[Pkg-golang-commits] [golang] 01/02: Imported Upstream version 1.5.1

Tianon Gravi tianon at debian.org
Fri Sep 25 20:38:07 UTC 2015


This is an automated email from the git hooks/post-receive script.

tianon pushed a commit to branch debian-experimental
in repository golang.

commit e37de337e22f1283f9fb3ac81c2791f099f33e15
Author: Tianon Gravi <tianon at debian.org>
Date:   Fri Sep 25 13:36:58 2015 -0700

    Imported Upstream version 1.5.1
---
 AUTHORS                                            |  100 +-
 CONTRIBUTING.md                                    |   33 +
 CONTRIBUTORS                                       |  123 +-
 README                                             |   32 -
 README.md                                          |   45 +
 VERSION                                            |    2 +-
 api/except.txt                                     |    1 +
 api/go1.5.txt                                      |  975 ++++
 api/next.txt                                       |  141 -
 doc/articles/go_command.html                       |   13 +-
 doc/articles/wiki/final-test.patch                 |   36 +
 doc/articles/wiki/final.go                         |   22 -
 doc/articles/wiki/test.bash                        |   20 +-
 doc/asm.html                                       |  375 +-
 doc/code.html                                      |   16 +-
 doc/contrib.html                                   |    7 +
 doc/contribute.html                                |  172 +-
 doc/devel/pre_go1.html                             |  455 ++
 doc/devel/release.html                             |  471 +-
 doc/devel/weekly.html                              |    2 +-
 doc/effective_go.html                              |   58 +-
 doc/gccgo_contribute.html                          |   24 +-
 doc/gccgo_install.html                             |   51 +-
 doc/go1.1.html                                     |    2 +-
 doc/go1.4.html                                     |    2 +-
 doc/go1.5.html                                     | 1310 +++++
 doc/go1compat.html                                 |   12 +
 doc/go_faq.html                                    |  211 +-
 doc/go_mem.html                                    |    8 +-
 doc/go_spec.html                                   |  266 +-
 doc/gopher/README                                  |    2 +-
 doc/install-source.html                            |  111 +-
 doc/install.html                                   |  103 +-
 doc/logo-153x55.png                                |  Bin 3382 -> 0 bytes
 doc/play/peano.go                                  |    6 +-
 doc/progs/cgo1.go                                  |    3 +-
 doc/progs/cgo2.go                                  |    3 +-
 doc/progs/cgo3.go                                  |    3 +-
 doc/progs/cgo4.go                                  |    3 +-
 doc/progs/defer.go                                 |    2 -
 doc/progs/defer.out                                |    3 -
 doc/progs/defer2.go                                |    2 -
 doc/progs/defer2.out                               |   12 -
 doc/progs/eff_bytesize.go                          |    2 -
 doc/progs/eff_bytesize.out                         |    1 -
 doc/progs/eff_qr.go                                |    2 -
 doc/progs/eff_sequence.go                          |    2 -
 doc/progs/eff_sequence.out                         |    1 -
 doc/progs/eff_unused1.go                           |    2 -
 doc/progs/eff_unused2.go                           |    2 -
 doc/progs/error.go                                 |    2 -
 doc/progs/error2.go                                |    2 -
 doc/progs/error3.go                                |    2 -
 doc/progs/error4.go                                |    2 -
 doc/progs/go1.go                                   |    3 -
 doc/progs/gobs1.go                                 |    2 -
 doc/progs/gobs2.go                                 |    2 -
 doc/progs/image_draw.go                            |    2 -
 doc/progs/image_package1.go                        |    2 -
 doc/progs/image_package1.out                       |    1 -
 doc/progs/image_package2.go                        |    2 -
 doc/progs/image_package2.out                       |    1 -
 doc/progs/image_package3.go                        |    2 -
 doc/progs/image_package3.out                       |    1 -
 doc/progs/image_package4.go                        |    2 -
 doc/progs/image_package4.out                       |    1 -
 doc/progs/image_package5.go                        |    2 -
 doc/progs/image_package5.out                       |    1 -
 doc/progs/image_package6.go                        |    2 -
 doc/progs/image_package6.out                       |    2 -
 doc/progs/interface.go                             |    2 -
 doc/progs/interface2.go                            |    2 -
 doc/progs/interface2.out                           |    1 -
 doc/progs/json1.go                                 |    2 -
 doc/progs/json2.go                                 |    2 -
 doc/progs/json2.out                                |    2 -
 doc/progs/json3.go                                 |    2 -
 doc/progs/json4.go                                 |    2 -
 doc/progs/json5.go                                 |    2 -
 doc/progs/run                                      |  125 -
 doc/progs/run.go                                   |  230 +
 doc/progs/slices.go                                |    2 -
 doc/progs/timeout1.go                              |    3 +-
 doc/progs/timeout2.go                              |    3 +-
 doc/progs/update.bash                              |   15 -
 doc/root.html                                      |    7 +-
 doc/security.html                                  |  174 +
 doc/sieve.gif                                      |  Bin 11019 -> 0 bytes
 include/README                                     |    6 -
 include/ar.h                                       |   47 -
 include/bio.h                                      |  144 -
 include/fmt.h                                      |  116 -
 include/libc.h                                     |  405 --
 include/link.h                                     |  631 ---
 include/plan9/386/u.h                              |   17 -
 include/plan9/amd64/u.h                            |   17 -
 include/plan9/arm/u.h                              |   15 -
 include/plan9/bio.h                                |    8 -
 include/plan9/errno.h                              |    7 -
 include/plan9/fmt.h                                |   64 -
 include/plan9/libc.h                               |   33 -
 include/plan9/link.h                               |    5 -
 include/plan9/mklibc.rc                            |    8 -
 include/plan9/stdarg.h                             |    3 -
 include/plan9/utf.h                                |    5 -
 include/u.h                                        |  233 -
 include/utf.h                                      |    1 -
 lib/codereview/codereview.cfg                      |    1 -
 lib/codereview/codereview.py                       | 3692 --------------
 lib/codereview/test.sh                             |  199 -
 lib/time/update.bash                               |    4 +-
 lib/time/zoneinfo.zip                              |  Bin 360713 -> 359824 bytes
 misc/android/README                                |    4 +-
 misc/android/cleaner.go                            |   39 +
 misc/android/go_android_exec.go                    |   82 +-
 misc/cgo/errors/test.bash                          |    2 +
 misc/cgo/gmp/gmp.go                                |    2 +-
 misc/cgo/test/backdoor.go                          |   11 +
 misc/cgo/test/backdoor/backdoor.go                 |    7 -
 misc/cgo/test/backdoor/runtime_gccgo.c             |   18 -
 misc/cgo/test/backdoor/thunk.s                     |   16 -
 misc/cgo/test/callback.go                          |   17 +-
 misc/cgo/test/callback_c_gc.c                      |   55 -
 misc/cgo/test/callback_c_gccgo.c                   |   49 -
 misc/cgo/test/cflags.go                            |    2 +-
 misc/cgo/test/cgo_linux_test.go                    |    8 +-
 misc/cgo/test/cgo_test.go                          |    4 +-
 misc/cgo/test/cthread_unix.c                       |    2 +-
 misc/cgo/test/issue10303.go                        |   70 +
 misc/cgo/test/issue11925.go                        |   37 +
 misc/cgo/test/issue3261.go                         |    6 +
 misc/cgo/test/issue3945.go                         |    2 +-
 misc/cgo/test/issue6997_linux.go                   |    2 +-
 misc/cgo/test/issue7234_test.go                    |    4 +-
 misc/cgo/test/issue7978.go                         |   25 +-
 misc/cgo/test/issue8428.go                         |    7 +-
 misc/cgo/test/issue8945.go                         |   16 +
 misc/cgo/test/issue9400/asm_386.s                  |   26 +
 misc/cgo/test/issue9400/asm_amd64x.s               |   27 +
 misc/cgo/test/issue9400/asm_arm.s                  |   39 +
 misc/cgo/test/issue9400/asm_arm64.s                |   39 +
 misc/cgo/test/issue9400/asm_ppc64x.s               |   32 +
 misc/cgo/test/issue9400/gccgo.go                   |   24 +
 misc/cgo/test/issue9400/stubs.go                   |    9 +
 misc/cgo/test/issue9400_linux.go                   |   58 +
 misc/cgo/test/issue9557.go                         |   36 +
 misc/cgo/test/setgid_linux.go                      |    2 +-
 misc/cgo/test/sigprocmask_linux.c                  |   36 +
 misc/cgo/test/sigprocmask_linux.go                 |   38 +
 misc/cgo/testcarchive/main.c                       |   34 +
 misc/cgo/testcarchive/src/libgo/libgo.go           |   53 +
 misc/cgo/testcarchive/src/p/p.go                   |   10 +
 misc/cgo/testcarchive/test.bash                    |   44 +
 misc/cgo/testcdefs/cdefstest.c                     |    9 -
 misc/cgo/testcdefs/cdefstest.go                    |   60 -
 misc/cgo/testcdefs/main.c                          |   76 -
 misc/cgo/testcdefs/main.go                         |   13 -
 misc/cgo/testcdefs/test.bash                       |   16 -
 misc/cgo/testcshared/main0.c                       |   36 +
 misc/cgo/testcshared/main1.c                       |   69 +
 misc/cgo/testcshared/main2.c                       |   56 +
 misc/cgo/testcshared/main3.c                       |   29 +
 misc/cgo/testcshared/src/libgo/libgo.go            |   46 +
 misc/cgo/testcshared/src/libgo2/libgo2.go          |   52 +
 misc/cgo/testcshared/src/p/p.go                    |   10 +
 misc/cgo/testcshared/test.bash                     |  129 +
 misc/cgo/testgodefs/test.bash                      |    2 +
 misc/cgo/testshared/shared_test.go                 |  674 +++
 misc/cgo/testshared/src/dep/asm.s                  |   10 +
 misc/cgo/testshared/src/dep/dep.go                 |   13 +
 misc/cgo/testshared/src/dep/gccgo.go               |    5 +
 misc/cgo/testshared/src/dep/stubs.go               |    5 +
 misc/cgo/testshared/src/dep2/dep2.go               |   11 +
 misc/cgo/testshared/src/exe/exe.go                 |   12 +
 misc/cgo/testshared/src/exe2/exe2.go               |    7 +
 misc/cgo/testshared/src/execgo/exe.go              |    8 +
 misc/cgo/testshared/src/trivial/trivial.go         |    4 +
 misc/cgo/testsigfwd/main.go                        |   58 +
 misc/cgo/testso/cgoso.go                           |    1 +
 misc/cgo/testso/cgoso_unix.go                      |    2 +-
 misc/cgo/testso/test.bash                          |   22 -
 misc/cgo/testso/test.bat                           |   18 -
 misc/cgo/testsovar/cgoso.go                        |   43 +
 misc/cgo/testsovar/cgoso_c.c                       |    7 +
 misc/cgo/testsovar/cgoso_c.h                       |   17 +
 misc/cgo/testsovar/main.go                         |   13 +
 misc/chrome/gophertool/gopher.js                   |   19 +-
 misc/chrome/gophertool/popup.html                  |   12 +-
 misc/editors                                       |    2 +-
 misc/ios/README                                    |   44 +
 misc/ios/clangwrap.sh                              |   20 +
 misc/ios/detect.go                                 |  135 +
 misc/ios/go_darwin_arm_exec.go                     |  665 +++
 misc/nacl/README                                   |   21 +-
 misc/nacl/testzip.proto                            |   23 +
 misc/swig/callback/callback_test.go                |   13 +-
 misc/swig/stdio/file_test.go                       |    2 +-
 misc/trace/README.md                               |   38 +
 misc/trace/trace_viewer_lean.html                  | 4043 +++++++++++++++
 src/androidtest.bash                               |   45 +-
 src/archive/tar/common.go                          |   28 +-
 src/archive/tar/example_test.go                    |    1 +
 src/archive/tar/reader.go                          |   17 +-
 src/archive/tar/reader_test.go                     |   61 +-
 src/archive/tar/tar_test.go                        |   63 +-
 src/archive/tar/testdata/hardlink.tar              |  Bin 0 -> 2560 bytes
 src/archive/tar/testdata/issue10968.tar            |  Bin 0 -> 512 bytes
 src/archive/tar/testdata/issue11169.tar            |  Bin 0 -> 602 bytes
 src/archive/tar/testdata/neg-size.tar              |  Bin 0 -> 512 bytes
 src/archive/tar/writer.go                          |    2 +-
 src/archive/tar/writer_test.go                     |   55 +
 src/archive/zip/reader.go                          |   32 +-
 src/archive/zip/reader_test.go                     |   74 +
 src/archive/zip/struct.go                          |    6 +-
 src/archive/zip/testdata/readme.notzip             |  Bin 1905 -> 1906 bytes
 src/archive/zip/testdata/readme.zip                |  Bin 1885 -> 1886 bytes
 src/archive/zip/writer.go                          |   37 +-
 src/archive/zip/writer_test.go                     |   35 +
 src/archive/zip/zip_test.go                        |   36 +-
 src/bootstrap.bash                                 |   73 +
 src/bufio/bufio.go                                 |   34 +-
 src/bufio/bufio_test.go                            |  146 +
 src/bufio/scan.go                                  |    2 +-
 src/buildall.bash                                  |   70 +
 src/builtin/builtin.go                             |    8 +-
 src/bytes/buffer.go                                |    4 +
 src/bytes/buffer_test.go                           |   17 +
 src/bytes/bytes.go                                 |   15 +-
 src/bytes/bytes_decl.go                            |    2 +-
 src/bytes/bytes_test.go                            |   17 +
 src/bytes/compare_test.go                          |    3 +
 src/bytes/export_test.go                           |    4 -
 src/bytes/reader.go                                |    6 +
 src/bytes/reader_test.go                           |   12 +
 src/clean.bash                                     |   16 +-
 src/clean.bat                                      |    5 +-
 src/clean.rc                                       |    3 +-
 src/cmd/5a/Makefile                                |   10 -
 src/cmd/5a/a.h                                     |  169 -
 src/cmd/5a/a.y                                     |  747 ---
 src/cmd/5a/doc.go                                  |   20 -
 src/cmd/5a/lex.c                                   |  538 --
 src/cmd/5a/y.tab.c                                 | 2936 -----------
 src/cmd/5a/y.tab.h                                 |  188 -
 src/cmd/5c/Makefile                                |    5 -
 src/cmd/5c/cgen.c                                  | 1213 -----
 src/cmd/5c/doc.go                                  |   16 -
 src/cmd/5c/gc.h                                    |  333 --
 src/cmd/5c/list.c                                  |   39 -
 src/cmd/5c/mul.c                                   |  640 ---
 src/cmd/5c/peep.c                                  | 1478 ------
 src/cmd/5c/reg.c                                   | 1210 -----
 src/cmd/5c/sgen.c                                  |  265 -
 src/cmd/5c/swt.c                                   |  461 --
 src/cmd/5c/txt.c                                   | 1361 ------
 src/cmd/5g/Makefile                                |    5 -
 src/cmd/5g/cgen.c                                  | 1846 -------
 src/cmd/5g/cgen64.c                                |  760 ---
 src/cmd/5g/doc.go                                  |   15 -
 src/cmd/5g/galign.c                                |   49 -
 src/cmd/5g/gg.h                                    |  123 -
 src/cmd/5g/ggen.c                                  |  956 ----
 src/cmd/5g/gobj.c                                  |  252 -
 src/cmd/5g/gsubr.c                                 | 2082 --------
 src/cmd/5g/opt.h                                   |  221 -
 src/cmd/5g/peep.c                                  | 1629 -------
 src/cmd/5g/prog.c                                  |  151 -
 src/cmd/5g/reg.c                                   | 1453 ------
 src/cmd/5l/5.out.h                                 |  347 --
 src/cmd/5l/Makefile                                |    5 -
 src/cmd/5l/asm.c                                   |  692 ---
 src/cmd/5l/doc.go                                  |   15 -
 src/cmd/5l/l.h                                     |  103 -
 src/cmd/5l/list.c                                  |   70 -
 src/cmd/5l/obj.c                                   |  116 -
 src/cmd/6a/Makefile                                |   10 -
 src/cmd/6a/a.h                                     |  184 -
 src/cmd/6a/a.y                                     |  691 ---
 src/cmd/6a/doc.go                                  |   20 -
 src/cmd/6a/lex.c                                   | 1136 -----
 src/cmd/6a/y.tab.c                                 | 2801 -----------
 src/cmd/6a/y.tab.h                                 |  139 -
 src/cmd/6c/Makefile                                |    5 -
 src/cmd/6c/cgen.c                                  | 2046 --------
 src/cmd/6c/div.c                                   |  236 -
 src/cmd/6c/doc.go                                  |   16 -
 src/cmd/6c/gc.h                                    |  359 --
 src/cmd/6c/list.c                                  |   38 -
 src/cmd/6c/machcap.c                               |  107 -
 src/cmd/6c/mul.c                                   |  458 --
 src/cmd/6c/peep.c                                  |  902 ----
 src/cmd/6c/reg.c                                   | 1523 ------
 src/cmd/6c/sgen.c                                  |  483 --
 src/cmd/6c/swt.c                                   |  353 --
 src/cmd/6c/txt.c                                   | 1674 -------
 src/cmd/6g/Makefile                                |    5 -
 src/cmd/6g/cgen.c                                  | 1732 -------
 src/cmd/6g/doc.go                                  |   15 -
 src/cmd/6g/galign.c                                |   66 -
 src/cmd/6g/gg.h                                    |  122 -
 src/cmd/6g/ggen.c                                  | 1228 -----
 src/cmd/6g/gobj.c                                  |  235 -
 src/cmd/6g/gsubr.c                                 | 2296 ---------
 src/cmd/6g/opt.h                                   |  220 -
 src/cmd/6g/peep.c                                  |  990 ----
 src/cmd/6g/prog.c                                  |  318 --
 src/cmd/6g/reg.c                                   | 1315 -----
 src/cmd/6l/6.out.h                                 |  890 ----
 src/cmd/6l/Makefile                                |    5 -
 src/cmd/6l/asm.c                                   |  817 ----
 src/cmd/6l/doc.go                                  |   15 -
 src/cmd/6l/l.h                                     |  109 -
 src/cmd/6l/list.c                                  |   67 -
 src/cmd/6l/obj.c                                   |  157 -
 src/cmd/8a/Makefile                                |   10 -
 src/cmd/8a/a.h                                     |  182 -
 src/cmd/8a/a.y                                     |  687 ---
 src/cmd/8a/doc.go                                  |   21 -
 src/cmd/8a/lex.c                                   |  910 ----
 src/cmd/8a/y.tab.c                                 | 2779 -----------
 src/cmd/8a/y.tab.h                                 |  139 -
 src/cmd/8c/Makefile                                |    5 -
 src/cmd/8c/cgen.c                                  | 1939 --------
 src/cmd/8c/cgen64.c                                | 2657 ----------
 src/cmd/8c/div.c                                   |  236 -
 src/cmd/8c/doc.go                                  |   16 -
 src/cmd/8c/gc.h                                    |  364 --
 src/cmd/8c/list.c                                  |   38 -
 src/cmd/8c/machcap.c                               |  116 -
 src/cmd/8c/mul.c                                   |  458 --
 src/cmd/8c/peep.c                                  |  807 ---
 src/cmd/8c/reg.c                                   | 1438 ------
 src/cmd/8c/sgen.c                                  |  483 --
 src/cmd/8c/swt.c                                   |  341 --
 src/cmd/8c/txt.c                                   | 1537 ------
 src/cmd/8g/Makefile                                |    5 -
 src/cmd/8g/cgen.c                                  | 1579 ------
 src/cmd/8g/cgen64.c                                |  549 ---
 src/cmd/8g/doc.go                                  |   15 -
 src/cmd/8g/galign.c                                |   47 -
 src/cmd/8g/gg.h                                    |  135 -
 src/cmd/8g/ggen.c                                  | 1342 -----
 src/cmd/8g/gobj.c                                  |  246 -
 src/cmd/8g/gsubr.c                                 | 2401 ---------
 src/cmd/8g/opt.h                                   |  238 -
 src/cmd/8g/peep.c                                  |  779 ---
 src/cmd/8g/prog.c                                  |  349 --
 src/cmd/8g/reg.c                                   | 1284 -----
 src/cmd/8l/8.out.h                                 |  676 ---
 src/cmd/8l/Makefile                                |    5 -
 src/cmd/8l/asm.c                                   |  745 ---
 src/cmd/8l/doc.go                                  |   15 -
 src/cmd/8l/l.h                                     |   95 -
 src/cmd/8l/list.c                                  |   67 -
 src/cmd/8l/obj.c                                   |  138 -
 src/cmd/addr2line/addr2line_test.go                |   24 +-
 src/cmd/api/goapi.go                               |  211 +-
 src/cmd/api/goapi_test.go                          |   15 +-
 src/cmd/api/run.go                                 |  148 +-
 src/cmd/asm/internal/arch/arch.go                  |  363 ++
 src/cmd/asm/internal/arch/arm.go                   |  248 +
 src/cmd/asm/internal/arch/arm64.go                 |  115 +
 src/cmd/asm/internal/arch/ppc64.go                 |   87 +
 src/cmd/asm/internal/asm/asm.go                    |  662 +++
 src/cmd/asm/internal/asm/endtoend_test.go          |   91 +
 src/cmd/asm/internal/asm/expr_test.go              |  131 +
 src/cmd/asm/internal/asm/operand_test.go           |  430 ++
 src/cmd/asm/internal/asm/parse.go                  |  988 ++++
 src/cmd/asm/internal/asm/testdata/386.out          |   49 +
 src/cmd/asm/internal/asm/testdata/386.s            |   86 +
 src/cmd/asm/internal/asm/testdata/amd64.out        |   57 +
 src/cmd/asm/internal/asm/testdata/amd64.s          |  101 +
 src/cmd/asm/internal/asm/testdata/arm.out          |   61 +
 src/cmd/asm/internal/asm/testdata/arm.s            |  296 ++
 src/cmd/asm/internal/asm/testdata/arm64.out        |   55 +
 src/cmd/asm/internal/asm/testdata/arm64.s          |  266 +
 src/cmd/asm/internal/asm/testdata/ppc64.out        |  114 +
 src/cmd/asm/internal/asm/testdata/ppc64.s          |  720 +++
 src/cmd/asm/internal/flags/flags.go                |   69 +
 src/cmd/asm/internal/lex/input.go                  |  464 ++
 src/cmd/asm/internal/lex/lex.go                    |  157 +
 src/cmd/asm/internal/lex/lex_test.go               |  154 +
 src/cmd/asm/internal/lex/slice.go                  |   59 +
 src/cmd/asm/internal/lex/stack.go                  |   53 +
 src/cmd/asm/internal/lex/tokenizer.go              |  152 +
 src/cmd/asm/main.go                                |   67 +
 src/cmd/cc/Makefile                                |   10 -
 src/cmd/cc/acid.c                                  |  344 --
 src/cmd/cc/bits.c                                  |  120 -
 src/cmd/cc/cc.h                                    |  835 ----
 src/cmd/cc/cc.y                                    | 1220 -----
 src/cmd/cc/com.c                                   | 1384 ------
 src/cmd/cc/com64.c                                 |  644 ---
 src/cmd/cc/dcl.c                                   | 1707 -------
 src/cmd/cc/doc.go                                  |   13 -
 src/cmd/cc/dpchk.c                                 |  793 ---
 src/cmd/cc/funct.c                                 |  431 --
 src/cmd/cc/godefs.c                                |  367 --
 src/cmd/cc/lex.c                                   | 1593 ------
 src/cmd/cc/lexbody                                 |  709 ---
 src/cmd/cc/mac.c                                   |   34 -
 src/cmd/cc/macbody                                 |  800 ---
 src/cmd/cc/omachcap.c                              |   40 -
 src/cmd/cc/pgen.c                                  |  622 ---
 src/cmd/cc/pswt.c                                  |  140 -
 src/cmd/cc/scon.c                                  |  640 ---
 src/cmd/cc/sub.c                                   | 2068 --------
 src/cmd/cc/y.tab.c                                 | 3822 ---------------
 src/cmd/cc/y.tab.h                                 |  230 -
 src/cmd/cgo/ast.go                                 |    8 +
 src/cmd/cgo/doc.go                                 |  241 +-
 src/cmd/cgo/gcc.go                                 |   96 +-
 src/cmd/cgo/godefs.go                              |  167 -
 src/cmd/cgo/main.go                                |   52 +-
 src/cmd/cgo/out.go                                 |  331 +-
 src/cmd/cgo/util.go                                |    2 +-
 src/cmd/compile/doc.go                             |  127 +
 src/cmd/compile/internal/amd64/cgen.go             |  151 +
 src/cmd/compile/internal/amd64/galign.go           |  129 +
 src/cmd/compile/internal/amd64/ggen.go             |  743 +++
 src/cmd/compile/internal/amd64/gsubr.go            | 1380 ++++++
 src/cmd/compile/internal/amd64/peep.go             | 1038 ++++
 src/cmd/compile/internal/amd64/prog.go             |  308 ++
 src/cmd/compile/internal/amd64/reg.go              |  152 +
 src/cmd/compile/internal/arm/cgen.go               |  229 +
 src/cmd/compile/internal/arm/cgen64.go             |  859 ++++
 src/cmd/compile/internal/arm/galign.go             |   94 +
 src/cmd/compile/internal/arm/ggen.go               |  529 ++
 src/cmd/compile/internal/arm/gsubr.go              | 1209 +++++
 src/cmd/compile/internal/arm/peep.go               | 1748 +++++++
 src/cmd/compile/internal/arm/prog.go               |  165 +
 src/cmd/compile/internal/arm/reg.go                |  136 +
 src/cmd/compile/internal/arm64/cgen.go             |  157 +
 src/cmd/compile/internal/arm64/galign.go           |   93 +
 src/cmd/compile/internal/arm64/ggen.go             |  534 ++
 src/cmd/compile/internal/arm64/gsubr.go            |  983 ++++
 src/cmd/compile/internal/arm64/peep.go             |  809 +++
 src/cmd/compile/internal/arm64/prog.go             |  174 +
 src/cmd/compile/internal/arm64/reg.go              |  169 +
 src/cmd/compile/internal/big/accuracy_string.go    |   17 +
 src/cmd/compile/internal/big/arith.go              |  305 ++
 src/cmd/compile/internal/big/arith_decl.go         |   53 +
 src/cmd/compile/internal/big/arith_test.go         |  457 ++
 src/cmd/compile/internal/big/bits_test.go          |  224 +
 src/cmd/compile/internal/big/calibrate_test.go     |   88 +
 src/cmd/compile/internal/big/decimal.go            |  264 +
 src/cmd/compile/internal/big/decimal_test.go       |  106 +
 src/cmd/compile/internal/big/example_test.go       |   51 +
 src/cmd/compile/internal/big/float.go              | 1693 +++++++
 src/cmd/compile/internal/big/float_test.go         | 1694 +++++++
 src/cmd/compile/internal/big/floatconv.go          |  239 +
 src/cmd/compile/internal/big/floatconv_test.go     |  573 +++
 src/cmd/compile/internal/big/floatexample_test.go  |  111 +
 src/cmd/compile/internal/big/ftoa.go               |  393 ++
 src/cmd/compile/internal/big/gcd_test.go           |   47 +
 src/cmd/compile/internal/big/hilbert_test.go       |  160 +
 src/cmd/compile/internal/big/int.go                |  966 ++++
 src/cmd/compile/internal/big/int_test.go           | 1525 ++++++
 src/cmd/compile/internal/big/intconv.go            |  228 +
 src/cmd/compile/internal/big/intconv_test.go       |  342 ++
 src/cmd/compile/internal/big/nat.go                | 1274 +++++
 src/cmd/compile/internal/big/nat_test.go           |  579 +++
 src/cmd/compile/internal/big/natconv.go            |  495 ++
 src/cmd/compile/internal/big/natconv_test.go       |  425 ++
 src/cmd/compile/internal/big/rat.go                |  570 +++
 src/cmd/compile/internal/big/rat_test.go           |  736 +++
 src/cmd/compile/internal/big/ratconv.go            |  251 +
 src/cmd/compile/internal/big/ratconv_test.go       |  451 ++
 .../compile/internal/big/roundingmode_string.go    |   16 +
 src/cmd/compile/internal/big/vendor.bash           |   31 +
 src/cmd/compile/internal/gc/align.go               |  713 +++
 src/cmd/compile/internal/gc/builtin.go             |  169 +
 src/cmd/compile/internal/gc/builtin/runtime.go     |  195 +
 src/cmd/compile/internal/gc/builtin/unsafe.go      |   18 +
 src/cmd/compile/internal/gc/bv.go                  |  195 +
 src/cmd/compile/internal/gc/cgen.go                | 3566 ++++++++++++++
 src/cmd/compile/internal/gc/closure.go             |  690 +++
 src/cmd/compile/internal/gc/const.go               | 1715 +++++++
 src/cmd/compile/internal/gc/cplx.go                |  479 ++
 src/cmd/compile/internal/gc/dcl.go                 | 1513 ++++++
 src/cmd/compile/internal/gc/esc.go                 | 1821 +++++++
 src/cmd/compile/internal/gc/export.go              |  561 +++
 src/cmd/compile/internal/gc/fmt.go                 | 1724 +++++++
 src/cmd/compile/internal/gc/gen.go                 | 1276 +++++
 src/cmd/compile/internal/gc/go.go                  |  870 ++++
 src/cmd/compile/internal/gc/go.y                   | 2316 +++++++++
 src/cmd/compile/internal/gc/gsubr.go               |  836 ++++
 src/cmd/compile/internal/gc/init.go                |  189 +
 src/cmd/compile/internal/gc/inl.go                 |  995 ++++
 src/cmd/compile/internal/gc/lex.go                 | 2653 ++++++++++
 src/cmd/compile/internal/gc/mkbuiltin.go           |   97 +
 src/cmd/compile/internal/gc/mparith2.go            |  300 ++
 src/cmd/compile/internal/gc/mparith3.go            |  250 +
 src/cmd/compile/internal/gc/obj.go                 |  450 ++
 src/cmd/compile/internal/gc/opnames.go             |  163 +
 src/cmd/compile/internal/gc/order.go               | 1179 +++++
 src/cmd/compile/internal/gc/pgen.go                |  544 +++
 src/cmd/compile/internal/gc/plive.go               | 1830 +++++++
 src/cmd/compile/internal/gc/popt.go                | 1086 +++++
 src/cmd/compile/internal/gc/racewalk.go            |  622 +++
 src/cmd/compile/internal/gc/range.go               |  406 ++
 src/cmd/compile/internal/gc/reflect.go             | 1607 ++++++
 src/cmd/compile/internal/gc/reg.go                 | 1559 ++++++
 src/cmd/compile/internal/gc/select.go              |  369 ++
 src/cmd/compile/internal/gc/sinit.go               | 1551 ++++++
 src/cmd/compile/internal/gc/subr.go                | 3589 ++++++++++++++
 src/cmd/compile/internal/gc/swt.go                 |  848 ++++
 src/cmd/compile/internal/gc/syntax.go              |  484 ++
 src/cmd/compile/internal/gc/typecheck.go           | 4035 +++++++++++++++
 src/cmd/compile/internal/gc/unsafe.go              |  165 +
 src/cmd/compile/internal/gc/util.go                |  103 +
 src/cmd/compile/internal/gc/walk.go                | 4074 ++++++++++++++++
 src/cmd/compile/internal/gc/y.go                   | 3526 ++++++++++++++
 src/cmd/compile/internal/ppc64/cgen.go             |  149 +
 src/cmd/compile/internal/ppc64/galign.go           |  100 +
 src/cmd/compile/internal/ppc64/ggen.go             |  564 +++
 src/cmd/compile/internal/ppc64/gsubr.go            | 1031 ++++
 src/cmd/compile/internal/ppc64/opt.go              |   12 +
 src/cmd/compile/internal/ppc64/peep.go             | 1051 ++++
 src/cmd/compile/internal/ppc64/prog.go             |  314 ++
 src/cmd/compile/internal/ppc64/reg.go              |  162 +
 src/cmd/compile/internal/x86/cgen.go               |  159 +
 src/cmd/compile/internal/x86/cgen64.go             |  598 +++
 src/cmd/compile/internal/x86/galign.go             |  110 +
 src/cmd/compile/internal/x86/ggen.go               |  940 ++++
 src/cmd/compile/internal/x86/gsubr.go              | 1801 +++++++
 src/cmd/compile/internal/x86/peep.go               |  814 ++++
 src/cmd/compile/internal/x86/prog.go               |  292 ++
 src/cmd/compile/internal/x86/reg.go                |  110 +
 src/cmd/compile/main.go                            |   34 +
 src/cmd/cover/cover.go                             |  722 +++
 src/cmd/cover/cover_test.go                        |   92 +
 src/cmd/cover/doc.go                               |   21 +
 src/cmd/cover/func.go                              |  164 +
 src/cmd/cover/html.go                              |  279 ++
 src/cmd/cover/profile.go                           |  192 +
 src/cmd/cover/testdata/main.go                     |  112 +
 src/cmd/cover/testdata/test.go                     |  218 +
 src/cmd/dist/README                                |   62 +-
 src/cmd/dist/a.h                                   |  165 -
 src/cmd/dist/arg.h                                 |   49 -
 src/cmd/dist/arm.c                                 |   72 -
 src/cmd/dist/buf.c                                 |  279 --
 src/cmd/dist/build.c                               | 1803 -------
 src/cmd/dist/build.go                              | 1202 +++++
 src/cmd/dist/buildgc.c                             |  137 -
 src/cmd/dist/buildgo.c                             |   49 -
 src/cmd/dist/buildgo.go                            |   39 +
 src/cmd/dist/buildruntime.c                        |  468 --
 src/cmd/dist/buildruntime.go                       |   96 +
 src/cmd/dist/buildtool.go                          |  144 +
 src/cmd/dist/cpuid_386.s                           |   16 +
 src/cmd/dist/cpuid_amd64.s                         |   16 +
 src/cmd/dist/cpuid_default.s                       |   10 +
 src/cmd/dist/main.c                                |   42 -
 src/cmd/dist/main.go                               |   86 +
 src/cmd/dist/plan9.c                               |  764 ---
 src/cmd/dist/sys_default.go                        |   10 +
 src/cmd/dist/sys_windows.go                        |   49 +
 src/cmd/dist/test.go                               |  866 ++++
 src/cmd/dist/unix.c                                |  843 ----
 src/cmd/dist/util.go                               |  559 +++
 src/cmd/dist/util_gc.go                            |   19 +
 src/cmd/dist/util_gccgo.go                         |   20 +
 src/cmd/dist/windows.c                             |  989 ----
 src/cmd/doc/doc_test.go                            |  348 ++
 src/cmd/doc/main.go                                |  354 ++
 src/cmd/doc/pkg.go                                 |  552 +++
 src/cmd/doc/testdata/pkg.go                        |   96 +
 src/cmd/fix/fix.go                                 |   20 +-
 src/cmd/fix/gotypes.go                             |   75 +
 src/cmd/fix/gotypes_test.go                        |   89 +
 src/cmd/gc/Makefile                                |   17 -
 src/cmd/gc/align.c                                 |  680 ---
 src/cmd/gc/array.c                                 |  115 -
 src/cmd/gc/bisonerrors                             |  156 -
 src/cmd/gc/bits.c                                  |  163 -
 src/cmd/gc/builtin.c                               |  137 -
 src/cmd/gc/bv.c                                    |  213 -
 src/cmd/gc/closure.c                               |  467 --
 src/cmd/gc/const.c                                 | 1674 -------
 src/cmd/gc/cplx.c                                  |  486 --
 src/cmd/gc/dcl.c                                   | 1494 ------
 src/cmd/gc/doc.go                                  |   95 -
 src/cmd/gc/esc.c                                   | 1281 -----
 src/cmd/gc/export.c                                |  521 --
 src/cmd/gc/fmt.c                                   | 1691 -------
 src/cmd/gc/gen.c                                   |  991 ----
 src/cmd/gc/go.errors                               |   79 -
 src/cmd/gc/go.h                                    | 1555 ------
 src/cmd/gc/go.y                                    | 2223 ---------
 src/cmd/gc/init.c                                  |  195 -
 src/cmd/gc/inl.c                                   |  986 ----
 src/cmd/gc/lex.c                                   | 2414 ---------
 src/cmd/gc/md5.c                                   |  302 --
 src/cmd/gc/md5.h                                   |   16 -
 src/cmd/gc/mkbuiltin                               |   32 -
 src/cmd/gc/mkbuiltin1.c                            |  102 -
 src/cmd/gc/mkopnames                               |   24 -
 src/cmd/gc/mparith1.c                              |  641 ---
 src/cmd/gc/mparith2.c                              |  716 ---
 src/cmd/gc/mparith3.c                              |  346 --
 src/cmd/gc/obj.c                                   |  284 --
 src/cmd/gc/order.c                                 | 1101 -----
 src/cmd/gc/pgen.c                                  |  539 --
 src/cmd/gc/plive.c                                 | 2017 --------
 src/cmd/gc/popt.c                                  | 1005 ----
 src/cmd/gc/popt.h                                  |   46 -
 src/cmd/gc/racewalk.c                              |  664 ---
 src/cmd/gc/range.c                                 |  296 --
 src/cmd/gc/reflect.c                               | 1577 ------
 src/cmd/gc/runtime.go                              |  164 -
 src/cmd/gc/select.c                                |  377 --
 src/cmd/gc/sinit.c                                 | 1505 ------
 src/cmd/gc/subr.c                                  | 3849 ---------------
 src/cmd/gc/swt.c                                   |  948 ----
 src/cmd/gc/typecheck.c                             | 3582 --------------
 src/cmd/gc/unsafe.c                                |  148 -
 src/cmd/gc/unsafe.go                               |   18 -
 src/cmd/gc/walk.c                                  | 3937 ---------------
 src/cmd/gc/y.tab.c                                 | 5132 --------------------
 src/cmd/gc/y.tab.h                                 |  167 -
 src/cmd/gc/yerr.h                                  |   79 -
 src/cmd/go/alldocs.go                              | 1481 ++++++
 src/cmd/go/bootstrap.go                            |   10 +-
 src/cmd/go/build.go                                | 1408 ++++--
 src/cmd/go/doc.go                                  | 1224 +----
 src/cmd/go/env.go                                  |    2 +-
 src/cmd/go/fix.go                                  |    4 +-
 src/cmd/go/fmt.go                                  |   30 +-
 src/cmd/go/generate.go                             |   85 +-
 src/cmd/go/generate_test.go                        |    1 +
 src/cmd/go/get.go                                  |  117 +-
 src/cmd/go/go_test.go                              | 2389 +++++++++
 src/cmd/go/help.go                                 |  246 +-
 src/cmd/go/http.go                                 |   30 +-
 src/cmd/go/list.go                                 |   13 +-
 src/cmd/go/main.go                                 |  148 +-
 src/cmd/go/mkalldocs.sh                            |   12 +
 src/cmd/go/mkdoc.sh                                |    9 -
 src/cmd/go/note.go                                 |  116 +
 src/cmd/go/note_test.go                            |   49 +
 src/cmd/go/pkg.go                                  |  999 +++-
 src/cmd/go/run.go                                  |    5 +-
 src/cmd/go/script                                  |   23 -
 src/cmd/go/script.txt                              |  352 --
 src/cmd/go/test.bash                               | 1123 -----
 src/cmd/go/test.go                                 |  134 +-
 src/cmd/go/testdata/failssh/ssh                    |    2 +
 src/cmd/go/testdata/generate/test3.go              |    2 +-
 src/cmd/go/testdata/generate/test4.go              |   10 +
 src/cmd/go/testdata/rundir/sub/sub.go              |    1 +
 src/cmd/go/testdata/rundir/x.go                    |    1 +
 src/cmd/go/testdata/src/testcycle/q1/q1.go         |    1 +
 src/cmd/go/testdata/src/testcycle/q1/q1_test.go    |    6 +
 src/cmd/go/testdata/src/testdep/p1/p1.go           |    1 +
 src/cmd/go/testdata/src/testdep/p1/p1_test.go      |    3 +
 src/cmd/go/testdata/src/testdep/p2/p2.go           |    3 +
 src/cmd/go/testdata/src/testdep/p3/p3.go           |    3 +
 src/cmd/go/testdata/src/vend/bad.go                |    3 +
 src/cmd/go/testdata/src/vend/good.go               |    3 +
 src/cmd/go/testdata/src/vend/hello/hello.go        |   10 +
 src/cmd/go/testdata/src/vend/hello/hello_test.go   |   12 +
 src/cmd/go/testdata/src/vend/hello/hellox_test.go  |   12 +
 src/cmd/go/testdata/src/vend/subdir/bad.go         |    3 +
 src/cmd/go/testdata/src/vend/subdir/good.go        |    3 +
 src/cmd/go/testdata/src/vend/vendor/p/p.go         |    1 +
 src/cmd/go/testdata/src/vend/vendor/q/q.go         |    1 +
 src/cmd/go/testdata/src/vend/vendor/strings/msg.go |    3 +
 src/cmd/go/testdata/src/vend/x/invalid/invalid.go  |    3 +
 src/cmd/go/testdata/src/vend/x/vendor/p/p.go       |    1 +
 src/cmd/go/testdata/src/vend/x/vendor/p/p/p.go     |    3 +
 src/cmd/go/testdata/src/vend/x/vendor/r/r.go       |    1 +
 src/cmd/go/testdata/src/vend/x/x.go                |    5 +
 src/cmd/go/testdata/src/vetpkg/c.go                |    9 +
 src/cmd/go/testdata/testinternal3/t.go             |    3 +
 src/cmd/go/testdata/testinternal4/src/p/p.go       |    6 +
 .../testdata/testinternal4/src/q/internal/x/x.go   |    1 +
 src/cmd/go/testdata/testinternal4/src/q/j/j.go     |    3 +
 src/cmd/go/testdata/testvendor/src/p/p.go          |    6 +
 src/cmd/go/testdata/testvendor/src/q/vendor/x/x.go |    1 +
 src/cmd/go/testdata/testvendor/src/q/y/y.go        |    3 +
 src/cmd/go/testdata/testvendor/src/q/z/z.go        |    3 +
 src/cmd/go/testdata/testvendor2/src/p/p.go         |    3 +
 src/cmd/go/testdata/testvendor2/vendor/x/x.go      |    1 +
 src/cmd/go/testflag.go                             |  200 +-
 src/cmd/go/tool.go                                 |   15 +-
 src/cmd/go/vcs.go                                  |  378 +-
 src/cmd/go/vcs_test.go                             |   69 +-
 src/cmd/go/vendor_test.go                          |  258 +
 src/cmd/go/vet.go                                  |   10 +-
 src/cmd/gofmt/doc.go                               |    7 +
 src/cmd/gofmt/gofmt.go                             |  156 +-
 src/cmd/gofmt/long_test.go                         |    5 +-
 src/cmd/gofmt/rewrite.go                           |    2 +-
 src/cmd/internal/gcprog/gcprog.go                  |  298 ++
 src/cmd/internal/goobj/read.go                     |   68 +-
 src/cmd/internal/obj/ar.go                         |   45 +
 src/cmd/internal/obj/arm/a.out.go                  |  328 ++
 src/cmd/internal/obj/arm/anames.go                 |  108 +
 src/cmd/internal/obj/arm/anames5.go                |   70 +
 src/cmd/internal/obj/arm/asm5.go                   | 2855 +++++++++++
 src/cmd/internal/obj/arm/list5.go                  |   83 +
 src/cmd/internal/obj/arm/obj5.go                   | 1020 ++++
 src/cmd/internal/obj/arm64/a.out.go                |  711 +++
 src/cmd/internal/obj/arm64/anames.go               |  379 ++
 src/cmd/internal/obj/arm64/anames7.go              |   62 +
 src/cmd/internal/obj/arm64/asm7.go                 | 4158 ++++++++++++++++
 src/cmd/internal/obj/arm64/list7.go                |  114 +
 src/cmd/internal/obj/arm64/obj7.go                 |  836 ++++
 src/cmd/internal/obj/data.go                       |  268 +
 src/cmd/internal/obj/flag.go                       |  120 +
 src/cmd/internal/obj/fmt.go                        |   34 +
 src/cmd/internal/obj/funcdata.go                   |   79 +
 src/cmd/internal/obj/go.go                         |   83 +
 src/cmd/internal/obj/ld.go                         |   92 +
 src/cmd/internal/obj/libc.go                       |   12 +
 src/cmd/internal/obj/line_test.go                  |   51 +
 src/cmd/internal/obj/link.go                       |  569 +++
 src/cmd/internal/obj/mgc0.go                       |   30 +
 src/cmd/internal/obj/obj.go                        |  283 ++
 src/cmd/internal/obj/objfile.go                    |  523 ++
 src/cmd/internal/obj/pass.go                       |  216 +
 src/cmd/internal/obj/pcln.go                       |  338 ++
 src/cmd/internal/obj/ppc64/a.out.go                |  538 ++
 src/cmd/internal/obj/ppc64/anames.go               |  300 ++
 src/cmd/internal/obj/ppc64/anames9.go              |   40 +
 src/cmd/internal/obj/ppc64/asm9.go                 | 3247 +++++++++++++
 src/cmd/internal/obj/ppc64/list9.go                |   98 +
 src/cmd/internal/obj/ppc64/obj9.go                 |  968 ++++
 src/cmd/internal/obj/stack.go                      |   51 +
 src/cmd/internal/obj/stringer.go                   |  104 +
 src/cmd/internal/obj/sym.go                        |  213 +
 src/cmd/internal/obj/textflag.go                   |   38 +
 src/cmd/internal/obj/typekind.go                   |   41 +
 src/cmd/internal/obj/util.go                       |  645 +++
 src/cmd/internal/obj/x86/a.out.go                  |  910 ++++
 src/cmd/internal/obj/x86/anames.go                 |  696 +++
 src/cmd/internal/obj/x86/asm6.go                   | 4380 +++++++++++++++++
 src/cmd/internal/obj/x86/list6.go                  |  164 +
 src/cmd/internal/obj/x86/obj6.go                   | 1330 +++++
 src/cmd/internal/obj/x86/obj6_test.go              |  170 +
 src/cmd/internal/objfile/disasm.go                 |   10 +-
 src/cmd/internal/objfile/elf.go                    |    2 +-
 src/cmd/internal/objfile/macho.go                  |   13 +-
 src/cmd/internal/rsc.io/arm/armasm/ext_test.go     |    2 +-
 src/cmd/internal/rsc.io/x86/x86asm/ext_test.go     |    2 +-
 src/cmd/ld/data.c                                  | 1397 ------
 src/cmd/ld/decodesym.c                             |  248 -
 src/cmd/ld/doc.go                                  |  100 -
 src/cmd/ld/dwarf.c                                 | 2466 ----------
 src/cmd/ld/dwarf.h                                 |   24 -
 src/cmd/ld/dwarf_defs.h                            |  504 --
 src/cmd/ld/elf.c                                   | 1526 ------
 src/cmd/ld/elf.h                                   | 1027 ----
 src/cmd/ld/go.c                                    |  861 ----
 src/cmd/ld/ldelf.c                                 |  905 ----
 src/cmd/ld/ldmacho.c                               |  850 ----
 src/cmd/ld/ldpe.c                                  |  499 --
 src/cmd/ld/lib.c                                   | 1617 ------
 src/cmd/ld/lib.h                                   |  289 --
 src/cmd/ld/macho.c                                 |  769 ---
 src/cmd/ld/macho.h                                 |   91 -
 src/cmd/ld/pcln.c                                  |  244 -
 src/cmd/ld/pe.c                                    |  712 ---
 src/cmd/ld/pe.h                                    |  179 -
 src/cmd/ld/pobj.c                                  |  207 -
 src/cmd/ld/symtab.c                                |  441 --
 src/cmd/ld/textflag.h                              |   36 -
 src/cmd/link/doc.go                                |   93 +
 src/cmd/link/internal/amd64/asm.go                 |  817 ++++
 src/cmd/link/internal/amd64/l.go                   |   47 +
 src/cmd/link/internal/amd64/obj.go                 |  214 +
 src/cmd/link/internal/amd64/z.go                   |    1 +
 src/cmd/link/internal/arm/asm.go                   |  651 +++
 src/cmd/link/internal/arm/l.go                     |   79 +
 src/cmd/link/internal/arm/obj.go                   |  178 +
 src/cmd/link/internal/arm64/asm.go                 |  435 ++
 src/cmd/link/internal/arm64/l.go                   |   78 +
 src/cmd/link/internal/arm64/obj.go                 |  169 +
 src/cmd/link/internal/ld/ar.go                     |   52 +
 src/cmd/link/internal/ld/arch.go                   |   70 +
 src/cmd/link/internal/ld/data.go                   | 1764 +++++++
 src/cmd/link/internal/ld/decodesym.go              |  226 +
 src/cmd/link/internal/ld/dwarf.go                  | 2624 ++++++++++
 src/cmd/link/internal/ld/dwarf_defs.go             |  516 ++
 src/cmd/link/internal/ld/elf.go                    | 2595 ++++++++++
 src/cmd/link/internal/ld/go.go                     |  869 ++++
 src/cmd/link/internal/ld/ld.go                     |  130 +
 src/cmd/link/internal/ld/ldelf.go                  | 1019 ++++
 src/cmd/link/internal/ld/ldmacho.go                |  893 ++++
 src/cmd/link/internal/ld/ldpe.go                   |  534 ++
 src/cmd/link/internal/ld/lib.go                    | 2049 ++++++++
 src/cmd/link/internal/ld/link.go                   |  227 +
 src/cmd/link/internal/ld/macho.go                  |  860 ++++
 src/cmd/link/internal/ld/macho_combine_dwarf.go    |  370 ++
 src/cmd/link/internal/ld/objfile.go                |  482 ++
 src/cmd/link/internal/ld/pcln.go                   |  471 ++
 src/cmd/link/internal/ld/pe.go                     | 1259 +++++
 src/cmd/link/internal/ld/pobj.go                   |  259 +
 src/cmd/link/internal/ld/sym.go                    |  227 +
 src/cmd/link/internal/ld/symtab.go                 |  541 +++
 src/cmd/link/internal/ld/textflag.go               |   29 +
 src/cmd/link/internal/ld/util.go                   |  172 +
 src/cmd/link/internal/ppc64/asm.go                 |  737 +++
 src/cmd/link/internal/ppc64/l.go                   |   78 +
 src/cmd/link/internal/ppc64/obj.go                 |  162 +
 src/cmd/link/internal/x86/asm.go                   |  643 +++
 src/cmd/link/internal/x86/l.go                     |   47 +
 src/cmd/link/internal/x86/obj.go                   |  187 +
 src/cmd/link/main.go                               |   34 +
 src/cmd/nm/nm_test.go                              |    6 +-
 src/cmd/objdump/main.go                            |    2 +-
 src/cmd/objdump/objdump_test.go                    |   26 +-
 src/cmd/pack/pack.go                               |    4 +-
 src/cmd/pack/pack_test.go                          |   47 +-
 src/cmd/pprof/doc.go                               |    2 +-
 src/cmd/pprof/internal/commands/commands.go        |   42 +-
 src/cmd/pprof/internal/driver/driver.go            |   19 +-
 src/cmd/pprof/internal/profile/encode.go           |    2 +-
 src/cmd/pprof/internal/profile/filter.go           |    1 +
 src/cmd/pprof/internal/profile/legacy_profile.go   |    3 +-
 src/cmd/pprof/internal/profile/profile.go          |   13 +-
 src/cmd/pprof/internal/profile/profile_test.go     |   24 +
 src/cmd/pprof/internal/report/report.go            |    2 +-
 src/cmd/pprof/internal/report/source.go            |    6 +-
 src/cmd/pprof/internal/svg/svg.go                  |   14 +-
 src/cmd/pprof/internal/svg/svgpan.go               |  291 ++
 src/cmd/trace/goroutines.go                        |  168 +
 src/cmd/trace/main.go                              |  156 +
 src/cmd/trace/pprof.go                             |  166 +
 src/cmd/trace/trace.go                             |  445 ++
 src/cmd/vet/asmdecl.go                             |  662 +++
 src/cmd/vet/assign.go                              |   49 +
 src/cmd/vet/atomic.go                              |   66 +
 src/cmd/vet/bool.go                                |  186 +
 src/cmd/vet/buildtag.go                            |   91 +
 src/cmd/vet/composite.go                           |  124 +
 src/cmd/vet/copylock.go                            |  156 +
 src/cmd/vet/deadcode.go                            |  296 ++
 src/cmd/vet/doc.go                                 |  191 +
 src/cmd/vet/main.go                                |  486 ++
 src/cmd/vet/method.go                              |  182 +
 src/cmd/vet/nilfunc.go                             |   67 +
 src/cmd/vet/print.go                               |  586 +++
 src/cmd/vet/rangeloop.go                           |   70 +
 src/cmd/vet/shadow.go                              |  244 +
 src/cmd/vet/shift.go                               |   82 +
 src/cmd/vet/structtag.go                           |  122 +
 src/cmd/vet/testdata/asm.go                        |   33 +
 src/cmd/vet/testdata/asm1.s                        |  254 +
 src/cmd/vet/testdata/asm2.s                        |  257 +
 src/cmd/vet/testdata/asm3.s                        |  178 +
 src/cmd/vet/testdata/asm4.s                        |   26 +
 src/cmd/vet/testdata/assign.go                     |   18 +
 src/cmd/vet/testdata/atomic.go                     |   43 +
 src/cmd/vet/testdata/bool.go                       |  113 +
 src/cmd/vet/testdata/buildtag.go                   |   14 +
 src/cmd/vet/testdata/buildtag_bad.go               |   15 +
 src/cmd/vet/testdata/composite.go                  |   63 +
 src/cmd/vet/testdata/copylock_func.go              |   95 +
 src/cmd/vet/testdata/copylock_range.go             |   67 +
 src/cmd/vet/testdata/deadcode.go                   | 2125 ++++++++
 src/cmd/vet/testdata/method.go                     |   22 +
 src/cmd/vet/testdata/nilfunc.go                    |   35 +
 src/cmd/vet/testdata/print.go                      |  342 ++
 src/cmd/vet/testdata/rangeloop.go                  |   59 +
 src/cmd/vet/testdata/shadow.go                     |   54 +
 src/cmd/vet/testdata/shift.go                      |   78 +
 src/cmd/vet/testdata/structtag.go                  |   36 +
 src/cmd/vet/testdata/tagtest/file1.go              |   10 +
 src/cmd/vet/testdata/tagtest/file2.go              |   10 +
 src/cmd/vet/testdata/unsafeptr.go                  |   61 +
 src/cmd/vet/testdata/unused.go                     |   29 +
 src/cmd/vet/types.go                               |  370 ++
 src/cmd/vet/unsafeptr.go                           |   97 +
 src/cmd/vet/unused.go                              |   93 +
 src/cmd/vet/vet_test.go                            |  107 +
 src/cmd/vet/whitelist/whitelist.go                 |   53 +
 src/cmd/yacc/doc.go                                |   29 +-
 src/cmd/yacc/testdata/expr/expr.y                  |   10 +-
 src/cmd/yacc/testdata/expr/main.go                 |    2 +-
 src/cmd/yacc/yacc.go                               |  343 +-
 src/compress/bzip2/bzip2.go                        |    8 +-
 src/compress/bzip2/bzip2_test.go                   |    4 +-
 src/compress/flate/deflate.go                      |    2 +-
 src/compress/flate/deflate_test.go                 |    2 +-
 src/compress/flate/flate_test.go                   |  236 +-
 src/compress/flate/gen.go                          |  125 +-
 src/compress/flate/huffman_bit_writer.go           |    6 +-
 src/compress/flate/huffman_code.go                 |    4 +-
 src/compress/flate/inflate.go                      |  164 +-
 src/compress/lzw/reader.go                         |    7 +-
 src/compress/lzw/reader_test.go                    |    9 +-
 src/compress/lzw/writer.go                         |   15 +-
 src/compress/lzw/writer_test.go                    |   10 +
 src/crypto/cipher/cipher.go                        |    3 +
 src/crypto/cipher/gcm.go                           |   70 +-
 src/crypto/cipher/gcm_test.go                      |   31 +-
 src/crypto/crypto.go                               |   72 +-
 src/crypto/ecdsa/ecdsa.go                          |   61 +-
 src/crypto/ecdsa/ecdsa_test.go                     |   72 +
 src/crypto/elliptic/elliptic.go                    |   13 +-
 src/crypto/elliptic/elliptic_test.go               |   13 +
 src/crypto/elliptic/p224.go                        |    2 +-
 src/crypto/elliptic/p256.go                        |    2 +-
 src/crypto/hmac/hmac.go                            |    2 +-
 src/crypto/md5/md5block_arm.s                      |  348 +-
 src/crypto/rand/eagain.go                          |   27 +
 src/crypto/rand/rand.go                            |    2 +
 src/crypto/rand/rand_linux.go                      |    6 +-
 src/crypto/rand/rand_unix.go                       |   18 +-
 src/crypto/rand/util_test.go                       |    2 +-
 src/crypto/rc4/rc4_arm.s                           |   78 +-
 src/crypto/rsa/pkcs1v15.go                         |   10 +
 src/crypto/rsa/pkcs1v15_test.go                    |   43 +-
 src/crypto/rsa/pss.go                              |    2 +-
 src/crypto/rsa/pss_test.go                         |    9 +
 src/crypto/rsa/rsa.go                              |   57 +-
 src/crypto/sha1/sha1block_arm.s                    |  274 +-
 src/crypto/sha512/sha512.go                        |  162 +-
 src/crypto/sha512/sha512_test.go                   |  372 +-
 src/crypto/tls/cipher_suites.go                    |   16 +-
 src/crypto/tls/common.go                           |  175 +-
 src/crypto/tls/conn.go                             |   22 +-
 src/crypto/tls/handshake_client.go                 |   60 +-
 src/crypto/tls/handshake_client_test.go            |  130 +-
 src/crypto/tls/handshake_messages.go               |   98 +-
 src/crypto/tls/handshake_messages_test.go          |   13 +-
 src/crypto/tls/handshake_server.go                 |  181 +-
 src/crypto/tls/handshake_server_test.go            |  285 +-
 src/crypto/tls/key_agreement.go                    |  108 +-
 src/crypto/tls/prf.go                              |  178 +-
 src/crypto/tls/prf_test.go                         |   18 +-
 .../testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA  |  105 +-
 .../testdata/Client-TLSv10-ClientCert-ECDSA-RSA    |   65 +-
 .../testdata/Client-TLSv10-ClientCert-RSA-ECDSA    |  103 +-
 .../tls/testdata/Client-TLSv10-ClientCert-RSA-RSA  |   63 +-
 .../tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES     |   83 +-
 .../tls/testdata/Client-TLSv10-ECDHE-RSA-AES       |   83 +-
 src/crypto/tls/testdata/Client-TLSv10-RSA-RC4      |   45 +-
 .../tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES     |   85 +-
 .../tls/testdata/Client-TLSv11-ECDHE-RSA-AES       |   83 +-
 src/crypto/tls/testdata/Client-TLSv11-RSA-RC4      |   45 +-
 src/crypto/tls/testdata/Client-TLSv12-ALPN         |   78 +-
 src/crypto/tls/testdata/Client-TLSv12-ALPN-NoMatch |   79 +-
 .../testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA  |  108 +-
 .../testdata/Client-TLSv12-ClientCert-ECDSA-RSA    |   69 +-
 .../Client-TLSv12-ClientCert-RSA-AES256-GCM-SHA384 |  139 +
 .../testdata/Client-TLSv12-ClientCert-RSA-ECDSA    |  108 +-
 .../tls/testdata/Client-TLSv12-ClientCert-RSA-RSA  |   69 +-
 .../tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES     |   85 +-
 .../tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM |   79 +-
 .../Client-TLSv12-ECDHE-ECDSA-AES256-GCM-SHA384    |   85 +
 .../tls/testdata/Client-TLSv12-ECDHE-RSA-AES       |   83 +-
 src/crypto/tls/testdata/Client-TLSv12-RSA-RC4      |   45 +-
 src/crypto/tls/testdata/Client-TLSv12-SCT          |  118 +
 src/crypto/tls/testdata/Server-SSLv3-RSA-3DES      |  145 +-
 src/crypto/tls/testdata/Server-SSLv3-RSA-AES       |  147 +-
 src/crypto/tls/testdata/Server-SSLv3-RSA-RC4       |  137 +-
 .../tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES     |   79 +-
 src/crypto/tls/testdata/Server-TLSv10-RSA-3DES     |  137 +-
 src/crypto/tls/testdata/Server-TLSv10-RSA-AES      |  143 +-
 src/crypto/tls/testdata/Server-TLSv10-RSA-RC4      |  131 +-
 src/crypto/tls/testdata/Server-TLSv11-RSA-RC4      |  131 +-
 src/crypto/tls/testdata/Server-TLSv12-ALPN         |  217 +-
 src/crypto/tls/testdata/Server-TLSv12-ALPN-NoMatch |  217 +-
 .../Server-TLSv12-CipherSuiteCertPreferenceECDSA   |  173 +-
 .../Server-TLSv12-CipherSuiteCertPreferenceRSA     |  189 +-
 .../Server-TLSv12-ClientAuthRequestedAndECDSAGiven |  157 +-
 .../Server-TLSv12-ClientAuthRequestedAndGiven      |  157 +-
 .../Server-TLSv12-ClientAuthRequestedNotGiven      |  139 +-
 .../tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES     |   82 +-
 src/crypto/tls/testdata/Server-TLSv12-IssueTicket  |  154 +-
 .../testdata/Server-TLSv12-IssueTicketPreDisable   |  154 +-
 src/crypto/tls/testdata/Server-TLSv12-RSA-3DES     |  142 +-
 src/crypto/tls/testdata/Server-TLSv12-RSA-AES      |  146 +-
 src/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM  |  156 +-
 .../testdata/Server-TLSv12-RSA-AES256-GCM-SHA384   |   87 +
 src/crypto/tls/testdata/Server-TLSv12-RSA-RC4      |  136 +-
 src/crypto/tls/testdata/Server-TLSv12-Resume       |   59 +-
 .../tls/testdata/Server-TLSv12-ResumeDisabled      |  156 +-
 src/crypto/tls/testdata/Server-TLSv12-SNI          |   56 +-
 .../tls/testdata/Server-TLSv12-SNI-GetCertificate  |   64 +
 .../Server-TLSv12-SNI-GetCertificateNotFound       |   64 +
 src/crypto/tls/ticket.go                           |   43 +-
 src/crypto/tls/tls.go                              |   38 +-
 src/crypto/tls/tls_test.go                         |   54 +-
 src/crypto/x509/cert_pool.go                       |    2 +-
 src/crypto/x509/pem_decrypt.go                     |    9 +-
 src/crypto/x509/pem_decrypt_test.go                |   24 +
 src/crypto/x509/pkix/pkix.go                       |   45 +-
 src/crypto/x509/root_bsd.go                        |   14 +
 src/crypto/x509/root_cgo_darwin.go                 |    2 +-
 src/crypto/x509/root_darwin.go                     |    2 +
 src/crypto/x509/root_darwin_arm_gen.go             |  191 +
 src/crypto/x509/root_darwin_armx.go                | 4907 +++++++++++++++++++
 src/crypto/x509/root_darwin_test.go                |   14 +-
 src/crypto/x509/root_linux.go                      |   13 +
 src/crypto/x509/root_nacl.go                       |    8 +
 src/crypto/x509/root_solaris.go                    |   12 +
 src/crypto/x509/root_unix.go                       |   12 -
 src/crypto/x509/sec1.go                            |    2 +-
 src/crypto/x509/sha2_windows_test.go               |   19 +
 src/crypto/x509/verify.go                          |    9 +-
 src/crypto/x509/verify_test.go                     |   11 +
 src/crypto/x509/x509.go                            |  396 +-
 src/crypto/x509/x509_test.go                       |  219 +-
 src/database/sql/fakedb_test.go                    |   23 +-
 src/database/sql/sql.go                            |  241 +-
 src/database/sql/sql_test.go                       |  226 +-
 src/debug/dwarf/buf.go                             |   11 +
 src/debug/dwarf/class_string.go                    |   17 +
 src/debug/dwarf/const.go                           |   28 +
 src/debug/dwarf/entry.go                           |  270 +-
 src/debug/dwarf/line.go                            |  590 +++
 src/debug/dwarf/line_test.go                       |  229 +
 src/debug/dwarf/testdata/line-clang.elf            |  Bin 0 -> 10271 bytes
 src/debug/dwarf/testdata/line-gcc.elf              |  Bin 0 -> 10113 bytes
 src/debug/dwarf/testdata/line1.c                   |    9 +
 src/debug/dwarf/testdata/line1.h                   |    7 +
 src/debug/dwarf/testdata/line2.c                   |    6 +
 src/debug/dwarf/type.go                            |   10 +
 src/debug/dwarf/typeunit.go                        |   27 +-
 src/debug/dwarf/unit.go                            |   43 +-
 src/debug/elf/elf.go                               |  180 +-
 src/debug/elf/file.go                              |  227 +-
 src/debug/elf/file_test.go                         |   38 +-
 .../elf/testdata/go-relocation-test-clang-arm.obj  |  Bin 0 -> 3092 bytes
 .../testdata/go-relocation-test-gcc482-ppc64le.obj |  Bin 0 -> 3016 bytes
 .../elf/testdata/go-relocation-test-gcc492-arm.obj |  Bin 0 -> 2648 bytes
 .../elf/testdata/go-relocation-test-gcc5-ppc.obj   |  Bin 0 -> 2356 bytes
 src/debug/gosym/pclntab_test.go                    |   22 +-
 src/debug/gosym/symtab.go                          |    2 +-
 src/debug/macho/file.go                            |   10 +-
 src/debug/pe/file.go                               |   13 +-
 src/debug/pe/file_test.go                          |  116 +-
 src/encoding/asn1/asn1.go                          |   50 +-
 src/encoding/asn1/asn1_test.go                     |   79 +-
 src/encoding/asn1/common.go                        |    5 +
 src/encoding/asn1/marshal.go                       |   12 +-
 src/encoding/asn1/marshal_test.go                  |   11 +
 src/encoding/base64/base64.go                      |  225 +-
 src/encoding/base64/base64_test.go                 |   74 +-
 src/encoding/binary/binary.go                      |   26 +-
 src/encoding/csv/example_test.go                   |  131 +
 src/encoding/csv/reader.go                         |    7 +-
 src/encoding/csv/reader_test.go                    |   31 +
 src/encoding/csv/writer.go                         |    4 +-
 src/encoding/gob/codec_test.go                     |   19 +
 src/encoding/gob/decode.go                         |  107 +-
 src/encoding/gob/doc.go                            |   18 +-
 src/encoding/gob/encoder.go                        |    6 +
 src/encoding/gob/encoder_test.go                   |  104 +-
 src/encoding/json/bench_test.go                    |   34 +
 src/encoding/json/decode.go                        |   51 +-
 src/encoding/json/decode_test.go                   |   86 +-
 src/encoding/json/encode.go                        |   27 +-
 src/encoding/json/example_test.go                  |   91 +
 src/encoding/json/fold.go                          |    2 +-
 src/encoding/json/scanner.go                       |    9 +-
 src/encoding/json/scanner_test.go                  |    1 +
 src/encoding/json/stream.go                        |  326 +-
 src/encoding/json/stream_test.go                   |  148 +
 src/encoding/json/tagkey_test.go                   |    4 +-
 src/encoding/pem/pem.go                            |   35 +-
 src/encoding/pem/pem_test.go                       |  112 +-
 src/encoding/xml/marshal.go                        |   59 +-
 src/encoding/xml/marshal_test.go                   |  552 ++-
 src/encoding/xml/read_test.go                      |    2 +-
 src/encoding/xml/xml.go                            |   44 +-
 src/encoding/xml/xml_test.go                       |   21 +-
 src/expvar/expvar.go                               |   41 +-
 src/expvar/expvar_test.go                          |  235 +-
 src/flag/flag.go                                   |  151 +-
 src/flag/flag_test.go                              |   38 +
 src/fmt/doc.go                                     |   77 +-
 src/fmt/fmt_test.go                                |  116 +-
 src/fmt/format.go                                  |   25 +-
 src/fmt/norace_test.go                             |    9 +
 src/fmt/print.go                                   |   40 +-
 src/fmt/race_test.go                               |    9 +
 src/fmt/scan.go                                    |  114 +-
 src/fmt/scan_test.go                               |  179 +-
 src/go/ast/ast.go                                  |   14 +-
 src/go/ast/filter.go                               |   21 +-
 src/go/ast/scope.go                                |    2 +-
 src/go/ast/walk.go                                 |    6 +-
 src/go/build/build.go                              |   82 +-
 src/go/build/build_test.go                         |   55 +-
 src/go/build/deps_test.go                          |  259 +-
 src/go/build/doc.go                                |    3 +-
 src/go/build/read.go                               |   20 +-
 src/go/build/read_test.go                          |    6 +-
 src/go/build/syslist.go                            |    2 +-
 src/go/constant/go13.go                            |   24 +
 src/go/constant/go14.go                            |   13 +
 src/go/constant/value.go                           |  925 ++++
 src/go/constant/value_test.go                      |  375 ++
 src/go/doc/doc.go                                  |    3 +-
 src/go/doc/exports.go                              |   65 +-
 src/go/doc/testdata/blank.0.golden                 |   28 +-
 src/go/doc/testdata/blank.1.golden                 |   31 +-
 src/go/doc/testdata/blank.2.golden                 |   28 +-
 src/go/doc/testdata/blank.go                       |   31 +-
 src/go/format/format.go                            |  157 +-
 src/go/format/format_test.go                       |    6 +-
 src/go/importer/importer.go                        |   69 +
 src/go/internal/gccgoimporter/gccgoinstallation.go |   94 +
 .../gccgoimporter/gccgoinstallation_test.go        |  193 +
 src/go/internal/gccgoimporter/importer.go          |  212 +
 src/go/internal/gccgoimporter/importer_test.go     |  171 +
 src/go/internal/gccgoimporter/parser.go            |  855 ++++
 src/go/internal/gccgoimporter/parser_test.go       |   72 +
 .../internal/gccgoimporter/testdata/complexnums.go |    6 +
 .../gccgoimporter/testdata/complexnums.gox         |    8 +
 src/go/internal/gccgoimporter/testdata/imports.go  |    5 +
 src/go/internal/gccgoimporter/testdata/imports.gox |    7 +
 src/go/internal/gccgoimporter/testdata/pointer.go  |    3 +
 src/go/internal/gccgoimporter/testdata/pointer.gox |    4 +
 src/go/internal/gcimporter/exportdata.go           |  108 +
 src/go/internal/gcimporter/gcimporter.go           |  991 ++++
 src/go/internal/gcimporter/gcimporter_test.go      |  225 +
 src/go/internal/gcimporter/testdata/exports.go     |   89 +
 src/go/parser/error_test.go                        |   27 +-
 src/go/parser/interface.go                         |   40 +-
 src/go/parser/parser.go                            |   82 +-
 src/go/parser/parser_test.go                       |  106 +-
 src/go/parser/short_test.go                        |   15 +-
 src/go/parser/testdata/issue3106.src               |    2 +-
 src/go/printer/nodes.go                            |   48 +-
 src/go/printer/printer.go                          |   32 +-
 src/go/printer/testdata/comments.golden            |   62 +
 src/go/printer/testdata/comments.input             |   62 +
 src/go/printer/testdata/declarations.golden        |    9 +
 src/go/printer/testdata/declarations.input         |    9 +
 src/go/printer/testdata/parser.go                  |    4 +-
 src/go/scanner/errors.go                           |   18 +-
 src/go/scanner/scanner.go                          |    3 +-
 src/go/scanner/scanner_test.go                     |   35 +
 src/go/token/position.go                           |   12 +-
 src/go/types/api.go                                |  336 ++
 src/go/types/api_test.go                           | 1044 ++++
 src/go/types/assignments.go                        |  328 ++
 src/go/types/builtins.go                           |  627 +++
 src/go/types/builtins_test.go                      |  204 +
 src/go/types/call.go                               |  441 ++
 src/go/types/check.go                              |  358 ++
 src/go/types/check_test.go                         |  298 ++
 src/go/types/conversions.go                        |  146 +
 src/go/types/decl.go                               |  430 ++
 src/go/types/errors.go                             |  103 +
 src/go/types/eval.go                               |   83 +
 src/go/types/eval_test.go                          |  188 +
 src/go/types/example_test.go                       |  312 ++
 src/go/types/expr.go                               | 1496 ++++++
 src/go/types/exprstring.go                         |  220 +
 src/go/types/exprstring_test.go                    |   94 +
 src/go/types/go11.go                               |   17 +
 src/go/types/go12.go                               |   17 +
 src/go/types/hilbert_test.go                       |  234 +
 src/go/types/initorder.go                          |  222 +
 src/go/types/issues_test.go                        |  206 +
 src/go/types/labels.go                             |  268 +
 src/go/types/lookup.go                             |  341 ++
 src/go/types/methodset.go                          |  268 +
 src/go/types/object.go                             |  360 ++
 src/go/types/objset.go                             |   31 +
 src/go/types/operand.go                            |  287 ++
 src/go/types/ordering.go                           |  127 +
 src/go/types/package.go                            |   65 +
 src/go/types/predicates.go                         |  309 ++
 src/go/types/resolver.go                           |  445 ++
 src/go/types/resolver_test.go                      |  209 +
 src/go/types/return.go                             |  185 +
 src/go/types/scope.go                              |  190 +
 src/go/types/selection.go                          |  143 +
 src/go/types/self_test.go                          |  102 +
 src/go/types/sizes.go                              |  211 +
 src/go/types/stdlib_test.go                        |  279 ++
 src/go/types/stmt.go                               |  744 +++
 src/go/types/testdata/blank.src                    |    5 +
 src/go/types/testdata/builtins.src                 |  881 ++++
 src/go/types/testdata/const0.src                   |  282 ++
 src/go/types/testdata/const1.src                   |  314 ++
 src/go/types/testdata/constdecl.src                |   97 +
 src/go/types/testdata/conversions.src              |   93 +
 src/go/types/testdata/cycles.src                   |  143 +
 src/go/types/testdata/cycles1.src                  |   77 +
 src/go/types/testdata/cycles2.src                  |  118 +
 src/go/types/testdata/cycles3.src                  |   60 +
 src/go/types/testdata/cycles4.src                  |  110 +
 src/go/types/testdata/decls0.src                   |  207 +
 src/go/types/testdata/decls1.src                   |  144 +
 src/go/types/testdata/decls2a.src                  |  111 +
 src/go/types/testdata/decls2b.src                  |   65 +
 src/go/types/testdata/decls3.src                   |  309 ++
 src/go/types/testdata/errors.src                   |   55 +
 src/go/types/testdata/expr0.src                    |  174 +
 src/go/types/testdata/expr1.src                    |    7 +
 src/go/types/testdata/expr2.src                    |  247 +
 src/go/types/testdata/expr3.src                    |  534 ++
 src/go/types/testdata/gotos.src                    |  560 +++
 src/go/types/testdata/importdecl0a.src             |   53 +
 src/go/types/testdata/importdecl0b.src             |   33 +
 src/go/types/testdata/importdecl1a.src             |   11 +
 src/go/types/testdata/importdecl1b.src             |    7 +
 src/go/types/testdata/init0.src                    |  106 +
 src/go/types/testdata/init1.src                    |   97 +
 src/go/types/testdata/init2.src                    |  139 +
 src/go/types/testdata/issues.src                   |   97 +
 src/go/types/testdata/labels.src                   |  207 +
 src/go/types/testdata/methodsets.src               |  214 +
 src/go/types/testdata/shifts.src                   |  341 ++
 src/go/types/testdata/stmt0.src                    |  833 ++++
 src/go/types/testdata/stmt1.src                    |  165 +
 src/go/types/testdata/vardecl.src                  |  186 +
 src/go/types/token_test.go                         |   47 +
 src/go/types/type.go                               |  454 ++
 src/go/types/typestring.go                         |  296 ++
 src/go/types/typestring_test.go                    |  168 +
 src/go/types/typexpr.go                            |  712 +++
 src/go/types/universe.go                           |  223 +
 src/hash/crc32/crc32.go                            |   49 +-
 src/hash/crc32/crc32_generic.go                    |    2 +-
 src/hash/crc32/crc32_test.go                       |   36 +-
 src/hash/crc32/example_test.go                     |   28 +
 src/html/escape.go                                 |   57 +-
 src/html/escape_test.go                            |   40 +-
 src/html/example_test.go                           |   22 +
 src/html/template/clone_test.go                    |    4 +-
 src/html/template/content_test.go                  |    2 +-
 src/html/template/css.go                           |   76 +-
 src/html/template/doc.go                           |    2 +-
 src/html/template/escape.go                        |   12 +-
 src/html/template/escape_test.go                   |   59 +
 src/html/template/example_test.go                  |  122 +
 src/html/template/html.go                          |   13 +-
 src/html/template/html_test.go                     |    9 +-
 src/html/template/js.go                            |    8 +-
 src/html/template/template.go                      |   26 +
 src/html/template/transition.go                    |   42 +-
 src/html/template/transition_test.go               |   60 +
 src/image/color/color.go                           |   58 +-
 src/image/color/ycbcr.go                           |  140 +-
 src/image/color/ycbcr_test.go                      |  130 +-
 src/image/decode_example_test.go                   |   32 +-
 src/image/decode_test.go                           |   14 +-
 src/image/draw/bench_test.go                       |   55 +-
 src/image/draw/clip_test.go                        |   30 +-
 src/image/draw/draw.go                             |  219 +-
 src/image/draw/draw_test.go                        |   40 +
 src/image/geom.go                                  |   44 +-
 src/image/geom_test.go                             |  115 +
 src/image/gif/reader.go                            |  159 +-
 src/image/gif/reader_test.go                       |   49 +-
 src/image/gif/writer.go                            |  127 +-
 src/image/gif/writer_test.go                       |  280 +-
 src/image/image.go                                 |   94 +-
 src/image/internal/imageutil/gen.go                |  154 +
 src/image/internal/imageutil/imageutil.go          |    8 +
 src/image/internal/imageutil/impl.go               |  196 +
 src/image/jpeg/huffman.go                          |    4 +-
 src/image/jpeg/reader.go                           |  451 +-
 src/image/jpeg/reader_test.go                      |   78 +
 src/image/jpeg/scan.go                             |   86 +-
 src/image/png/reader.go                            |   40 +-
 src/image/png/reader_test.go                       |   89 +
 .../png/testdata/gray-gradient.interlaced.png      |  Bin 0 -> 247 bytes
 src/image/png/testdata/gray-gradient.png           |  Bin 0 -> 77 bytes
 src/image/testdata/video-001.221212.jpeg           |  Bin 0 -> 19263 bytes
 src/image/testdata/video-001.221212.png            |  Bin 0 -> 29820 bytes
 src/image/testdata/video-001.cmyk.jpeg             |  Bin 0 -> 19477 bytes
 src/image/testdata/video-001.cmyk.png              |  Bin 0 -> 25439 bytes
 src/image/testdata/video-001.q50.410.jpeg          |  Bin 0 -> 3259 bytes
 .../testdata/video-001.q50.410.progressive.jpeg    |  Bin 0 -> 3125 bytes
 src/image/testdata/video-001.q50.411.jpeg          |  Bin 0 -> 3362 bytes
 .../testdata/video-001.q50.411.progressive.jpeg    |  Bin 0 -> 3251 bytes
 src/image/testdata/video-001.rgb.jpeg              |  Bin 0 -> 6237 bytes
 src/image/testdata/video-001.rgb.png               |  Bin 0 -> 20414 bytes
 src/image/ycbcr.go                                 |   29 +-
 src/image/ycbcr_test.go                            |   26 +
 src/internal/format/format.go                      |  163 +
 src/internal/singleflight/singleflight.go          |  111 +
 src/internal/singleflight/singleflight_test.go     |   87 +
 src/internal/syscall/getrandom_linux.go            |   56 -
 src/internal/syscall/unix/getrandom_linux.go       |   58 +
 .../syscall/windows/registry/export_test.go        |   11 +
 src/internal/syscall/windows/registry/key.go       |  175 +
 .../syscall/windows/registry/registry_test.go      |  678 +++
 src/internal/syscall/windows/registry/syscall.go   |   28 +
 src/internal/syscall/windows/registry/value.go     |  329 ++
 .../syscall/windows/registry/zsyscall_windows.go   |   73 +
 src/internal/syscall/windows/syscall_windows.go    |  130 +
 src/internal/syscall/windows/zsyscall_windows.go   |   49 +
 src/internal/testenv/testenv.go                    |  101 +
 src/internal/trace/goroutines.go                   |  180 +
 src/internal/trace/parser.go                       |  786 +++
 src/internal/trace/parser_test.go                  |   30 +
 src/io/io.go                                       |   27 +-
 src/io/io_test.go                                  |   50 +-
 src/io/ioutil/tempfile.go                          |    4 +
 src/io/pipe.go                                     |    5 +-
 src/iostest.bash                                   |   69 +
 src/lib9/Makefile                                  |    5 -
 src/lib9/_exits.c                                  |   37 -
 src/lib9/_p9dir.c                                  |  184 -
 src/lib9/atoi.c                                    |   47 -
 src/lib9/await.c                                   |  182 -
 src/lib9/cleanname.c                               |   80 -
 src/lib9/create.c                                  |   85 -
 src/lib9/ctime.c                                   |   30 -
 src/lib9/dirfstat.c                                |   56 -
 src/lib9/dirfwstat.c                               |   84 -
 src/lib9/dirstat.c                                 |   65 -
 src/lib9/dirwstat.c                                |   45 -
 src/lib9/dup.c                                     |   38 -
 src/lib9/errstr.c                                  |  107 -
 src/lib9/exec.c                                    |   35 -
 src/lib9/execl.c                                   |   55 -
 src/lib9/exitcode.c                                |   37 -
 src/lib9/exits.c                                   |   36 -
 src/lib9/flag.c                                    |  307 --
 src/lib9/fmt/charstod.c                            |   88 -
 src/lib9/fmt/dofmt.c                               |  624 ---
 src/lib9/fmt/dorfmt.c                              |   64 -
 src/lib9/fmt/errfmt.c                              |   32 -
 src/lib9/fmt/fltfmt.c                              |  683 ---
 src/lib9/fmt/fmt.c                                 |  235 -
 src/lib9/fmt/fmtdef.h                              |  119 -
 src/lib9/fmt/fmtfd.c                               |   51 -
 src/lib9/fmt/fmtfdflush.c                          |   37 -
 src/lib9/fmt/fmtlocale.c                           |   69 -
 src/lib9/fmt/fmtlock.c                             |   31 -
 src/lib9/fmt/fmtnull.c                             |   48 -
 src/lib9/fmt/fmtprint.c                            |   39 -
 src/lib9/fmt/fmtquote.c                            |  274 --
 src/lib9/fmt/fmtrune.c                             |   43 -
 src/lib9/fmt/fmtstr.c                              |   31 -
 src/lib9/fmt/fmtvprint.c                           |   52 -
 src/lib9/fmt/fprint.c                              |   33 -
 src/lib9/fmt/nan64.c                               |   93 -
 src/lib9/fmt/pow10.c                               |   60 -
 src/lib9/fmt/print.c                               |   33 -
 src/lib9/fmt/seprint.c                             |   33 -
 src/lib9/fmt/smprint.c                             |   33 -
 src/lib9/fmt/snprint.c                             |   34 -
 src/lib9/fmt/sprint.c                              |   45 -
 src/lib9/fmt/strtod.c                              |  533 --
 src/lib9/fmt/test.c                                |   67 -
 src/lib9/fmt/vfprint.c                             |   37 -
 src/lib9/fmt/vseprint.c                            |   44 -
 src/lib9/fmt/vsmprint.c                            |   87 -
 src/lib9/fmt/vsnprint.c                            |   43 -
 src/lib9/fmtlock2.c                                |   40 -
 src/lib9/getenv.c                                  |   52 -
 src/lib9/getfields.c                               |   63 -
 src/lib9/getwd.c                                   |   56 -
 src/lib9/goos.c                                    |   59 -
 src/lib9/jmp.c                                     |   45 -
 src/lib9/main.c                                    |   60 -
 src/lib9/nan.c                                     |   54 -
 src/lib9/notify.c                                  |  300 --
 src/lib9/nulldir.c                                 |   37 -
 src/lib9/open.c                                    |   70 -
 src/lib9/readn.c                                   |   50 -
 src/lib9/rfork.c                                   |  156 -
 src/lib9/run_plan9.c                               |   40 -
 src/lib9/run_unix.c                                |   43 -
 src/lib9/run_windows.c                             |   83 -
 src/lib9/seek.c                                    |   35 -
 src/lib9/strecpy.c                                 |   45 -
 src/lib9/sysfatal.c                                |   49 -
 src/lib9/tempdir_plan9.c                           |   56 -
 src/lib9/tempdir_unix.c                            |   52 -
 src/lib9/tempdir_windows.c                         |  113 -
 src/lib9/time.c                                    |   68 -
 src/lib9/tokenize.c                                |  135 -
 src/lib9/utf/Makefile                              |   30 -
 src/lib9/utf/mkrunetype.c                          |  734 ---
 src/lib9/utf/rune.c                                |  358 --
 src/lib9/utf/runetype.c                            |   38 -
 src/lib9/utf/runetypebody-6.3.0.h                  | 1638 -------
 src/lib9/utf/utf.h                                 |  240 -
 src/lib9/utf/utfdef.h                              |   27 -
 src/lib9/utf/utfecpy.c                             |   36 -
 src/lib9/utf/utflen.c                              |   35 -
 src/lib9/utf/utfnlen.c                             |   39 -
 src/lib9/utf/utfrrune.c                            |   46 -
 src/lib9/utf/utfrune.c                             |   45 -
 src/lib9/utf/utfutf.c                              |   43 -
 src/lib9/win.h                                     |    8 -
 src/lib9/windows.c                                 |   31 -
 src/libbio/Makefile                                |    5 -
 src/libbio/bbuffered.c                             |   46 -
 src/libbio/bfildes.c                               |   35 -
 src/libbio/bflush.c                                |   59 -
 src/libbio/bgetc.c                                 |   99 -
 src/libbio/bgetd.c                                 |   62 -
 src/libbio/bgetrune.c                              |   72 -
 src/libbio/binit.c                                 |  179 -
 src/libbio/boffset.c                               |   51 -
 src/libbio/bprint.c                                |   82 -
 src/libbio/bputc.c                                 |   60 -
 src/libbio/bputrune.c                              |   49 -
 src/libbio/brdline.c                               |  120 -
 src/libbio/brdstr.c                                |   60 -
 src/libbio/bread.c                                 |   71 -
 src/libbio/bseek.c                                 |   93 -
 src/libbio/bwrite.c                                |   64 -
 src/liblink/Makefile                               |    5 -
 src/liblink/asm5.c                                 | 2696 ----------
 src/liblink/asm6.c                                 | 3611 --------------
 src/liblink/asm8.c                                 | 2785 -----------
 src/liblink/data.c                                 |  372 --
 src/liblink/go.c                                   |   74 -
 src/liblink/ld.c                                   |  276 --
 src/liblink/list5.c                                |  373 --
 src/liblink/list6.c                                |  406 --
 src/liblink/list8.c                                |  354 --
 src/liblink/obj.c                                  |  296 --
 src/liblink/obj5.c                                 | 1094 -----
 src/liblink/obj6.c                                 | 1094 -----
 src/liblink/obj8.c                                 |  882 ----
 src/liblink/objfile.c                              |  790 ---
 src/liblink/pass.c                                 |  115 -
 src/liblink/pcln.c                                 |  365 --
 src/liblink/sym.c                                  |  268 -
 src/log/log.go                                     |   60 +-
 src/log/log_test.go                                |   67 +-
 src/log/syslog/doc.go                              |   18 +
 src/log/syslog/syslog.go                           |    7 -
 src/log/syslog/syslog_plan9.go                     |    8 -
 src/log/syslog/syslog_test.go                      |   25 +-
 src/log/syslog/syslog_windows.go                   |    8 -
 src/make.bash                                      |   43 +-
 src/make.bat                                       |   51 +-
 src/make.rc                                        |   41 +-
 src/math/abs_arm64.s                               |   11 +
 src/math/abs_ppc64x.s                              |   14 +
 src/math/all_test.go                               |   90 +-
 src/math/big/accuracy_string.go                    |   17 +
 src/math/big/arith.go                              |   89 +-
 src/math/big/arith_386.s                           |   22 +-
 src/math/big/arith_amd64.s                         |   87 +-
 src/math/big/arith_amd64p32.s                      |    2 +
 src/math/big/arith_arm.s                           |    2 +
 src/math/big/arith_arm64.s                         |  177 +
 src/math/big/arith_decl.go                         |    2 +
 src/math/big/arith_decl_pure.go                    |   55 +
 src/math/big/arith_ppc64x.s                        |   46 +
 src/math/big/arith_test.go                         |    3 +-
 src/math/big/bits_test.go                          |  224 +
 src/math/big/decimal.go                            |  264 +
 src/math/big/decimal_test.go                       |  106 +
 src/math/big/example_test.go                       |   77 +
 src/math/big/float.go                              | 1693 +++++++
 src/math/big/float_test.go                         | 1694 +++++++
 src/math/big/floatconv.go                          |  239 +
 src/math/big/floatconv_test.go                     |  573 +++
 src/math/big/floatexample_test.go                  |  111 +
 src/math/big/ftoa.go                               |  393 ++
 src/math/big/int.go                                |  331 +-
 src/math/big/int_test.go                           |  574 +--
 src/math/big/intconv.go                            |  228 +
 src/math/big/intconv_test.go                       |  342 ++
 src/math/big/nat.go                                |  590 +--
 src/math/big/nat_test.go                           |  608 +--
 src/math/big/natconv.go                            |  495 ++
 src/math/big/natconv_test.go                       |  425 ++
 src/math/big/rat.go                                |  164 +-
 src/math/big/rat_test.go                           |  424 --
 src/math/big/ratconv.go                            |  252 +
 src/math/big/ratconv_test.go                       |  453 ++
 src/math/big/roundingmode_string.go                |   16 +
 src/math/cbrt.go                                   |   91 +-
 src/math/const.go                                  |   19 +-
 src/math/dim_amd64.s                               |   32 +-
 src/math/expm1.go                                  |    8 +-
 src/math/log10.go                                  |    5 +
 src/math/nextafter.go                              |   16 +-
 src/math/rand/example_test.go                      |    4 +-
 src/math/rand/rand.go                              |    3 +
 src/math/rand/rand_test.go                         |   13 +-
 src/math/rand/zipf.go                              |    6 +-
 src/math/sqrt.go                                   |    5 +
 src/math/sqrt_arm64.s                              |   12 +
 src/math/stubs_arm64.s                             |   88 +
 src/math/stubs_ppc64x.s                            |   91 +
 src/mime/encodedword.go                            |  329 ++
 src/mime/encodedword_test.go                       |  287 ++
 src/mime/grammar.go                                |    6 +-
 src/mime/multipart/multipart.go                    |   38 +-
 src/mime/multipart/multipart_test.go               |   54 +-
 src/mime/multipart/quotedprintable.go              |  118 -
 src/mime/multipart/quotedprintable_test.go         |  204 -
 src/mime/multipart/writer.go                       |    3 +-
 src/mime/quotedprintable/reader.go                 |  124 +
 src/mime/quotedprintable/reader_test.go            |  204 +
 src/mime/quotedprintable/writer.go                 |  172 +
 src/mime/quotedprintable/writer_test.go            |  158 +
 src/mime/type.go                                   |  104 +-
 src/mime/type_dragonfly.go                         |    9 +
 src/mime/type_freebsd.go                           |    9 +
 src/mime/type_openbsd.go                           |    9 +
 src/mime/type_plan9.go                             |   34 +-
 src/mime/type_test.go                              |  110 +-
 src/mime/type_unix.go                              |    6 +-
 src/mime/type_windows.go                           |   54 +-
 src/nacltest.bash                                  |   14 +-
 src/net/addrselect.go                              |  388 ++
 src/net/addrselect_test.go                         |  219 +
 src/net/cgo_android.go                             |    4 +-
 src/net/cgo_bsd.go                                 |    8 +-
 src/net/cgo_linux.go                               |   16 +-
 src/net/cgo_netbsd.go                              |    4 +-
 src/net/cgo_openbsd.go                             |    4 +-
 src/net/cgo_resnew.go                              |   23 +
 src/net/cgo_resold.go                              |   23 +
 src/net/cgo_socknew.go                             |   33 +
 src/net/cgo_sockold.go                             |   33 +
 src/net/cgo_solaris.go                             |   15 +
 src/net/cgo_stub.go                                |   16 +-
 src/net/cgo_unix.go                                |  180 +-
 src/net/cgo_unix_test.go                           |    6 +-
 src/net/cgo_windows.go                             |   13 +
 src/net/conf.go                                    |  308 ++
 src/net/conf_netcgo.go                             |   18 +
 src/net/conf_test.go                               |  301 ++
 src/net/conn_test.go                               |  107 +-
 src/net/dial.go                                    |  279 +-
 src/net/dial_gen.go                                |   20 +-
 src/net/dial_gen_test.go                           |   11 -
 src/net/dial_test.go                               |  867 ++--
 src/net/dialgoogle_test.go                         |  209 -
 src/net/dnsclient.go                               |   67 +-
 src/net/dnsclient_test.go                          |    2 +-
 src/net/dnsclient_unix.go                          |  403 +-
 src/net/dnsclient_unix_test.go                     |  375 +-
 src/net/dnsconfig_unix.go                          |   54 +-
 src/net/dnsconfig_unix_test.go                     |   63 +-
 src/net/dnsmsg.go                                  |   18 +-
 src/net/dnsmsg_test.go                             |  175 +-
 src/net/dnsname_test.go                            |   31 +-
 src/net/error_plan9_test.go                        |   17 +
 src/net/error_posix_test.go                        |   44 +
 src/net/error_test.go                              |  673 +++
 src/net/external_test.go                           |  167 +
 src/net/fd_plan9.go                                |   18 +-
 src/net/fd_poll_nacl.go                            |    9 +-
 src/net/fd_poll_runtime.go                         |   15 +-
 src/net/fd_posix.go                                |   21 +
 src/net/fd_posix_test.go                           |   57 +
 src/net/fd_unix.go                                 |  126 +-
 src/net/fd_unix_test.go                            |   58 -
 src/net/fd_windows.go                              |  114 +-
 src/net/file.go                                    |   48 +
 src/net/file_plan9.go                              |   26 +-
 src/net/file_stub.go                               |   28 +-
 src/net/file_test.go                               |  130 +-
 src/net/file_unix.go                               |   88 +-
 src/net/file_windows.go                            |   24 +-
 src/net/hook.go                                    |   12 +
 src/net/hook_cloexec.go                            |   14 +
 src/net/hook_plan9.go                              |    9 +
 src/net/hook_unix.go                               |   21 +
 src/net/hook_windows.go                            |   21 +
 src/net/hosts.go                                   |   35 +-
 src/net/hosts_test.go                              |  151 +-
 src/net/http/cgi/child.go                          |    6 +-
 src/net/http/cgi/child_test.go                     |   21 +-
 src/net/http/cgi/host.go                           |   10 +-
 src/net/http/cgi/host_test.go                      |   43 +-
 src/net/http/cgi/matryoshka_test.go                |   15 +-
 src/net/http/cgi/testdata/test.cgi                 |    2 +-
 src/net/http/client.go                             |   82 +-
 src/net/http/client_test.go                        |  126 +-
 src/net/http/cookie.go                             |   36 +-
 src/net/http/cookie_test.go                        |   18 +-
 src/net/http/example_test.go                       |   23 +
 src/net/http/export_test.go                        |   24 +
 src/net/http/fcgi/child.go                         |   25 +-
 src/net/http/fcgi/fcgi_test.go                     |  106 +
 src/net/http/fs.go                                 |   53 +-
 src/net/http/fs_test.go                            |   51 +-
 src/net/http/http_test.go                          |   58 +
 src/net/http/httptest/server.go                    |   42 +-
 src/net/http/httputil/dump.go                      |   17 +-
 src/net/http/httputil/dump_test.go                 |    8 +-
 src/net/http/httputil/reverseproxy.go              |   70 +-
 src/net/http/httputil/reverseproxy_test.go         |  109 +
 src/net/http/internal/chunked.go                   |   17 +-
 src/net/http/lex.go                                |   73 +
 src/net/http/lex_test.go                           |   70 +
 src/net/http/main_test.go                          |   26 +-
 src/net/http/npn_test.go                           |   22 +-
 src/net/http/pprof/pprof.go                        |   38 +-
 src/net/http/proxy_test.go                         |    2 +-
 src/net/http/readrequest_test.go                   |   35 +-
 src/net/http/request.go                            |  139 +-
 src/net/http/request_test.go                       |  109 +-
 src/net/http/requestwrite_test.go                  |   69 +-
 src/net/http/response.go                           |   15 +-
 src/net/http/response_test.go                      |   51 +
 src/net/http/responsewrite_test.go                 |   15 +
 src/net/http/serve_test.go                         |  452 +-
 src/net/http/server.go                             |  279 +-
 src/net/http/sniff.go                              |   10 +-
 src/net/http/transfer.go                           |  109 +-
 src/net/http/transport.go                          |  360 +-
 src/net/http/transport_test.go                     |  528 +-
 src/net/interface.go                               |   44 +-
 src/net/interface_bsd.go                           |   93 +-
 src/net/interface_bsd_test.go                      |    4 +-
 src/net/interface_darwin.go                        |   43 +-
 src/net/interface_freebsd.go                       |   43 +-
 src/net/interface_linux.go                         |   34 +-
 src/net/interface_linux_test.go                    |   34 +-
 src/net/interface_test.go                          |  200 +-
 src/net/interface_unix_test.go                     |   74 +-
 src/net/interface_windows.go                       |  250 +-
 src/net/internal/socktest/main_test.go             |   56 +
 src/net/internal/socktest/main_unix_test.go        |   24 +
 src/net/internal/socktest/main_windows_test.go     |   22 +
 src/net/internal/socktest/switch.go                |  169 +
 src/net/internal/socktest/switch_posix.go          |   58 +
 src/net/internal/socktest/switch_stub.go           |   16 +
 src/net/internal/socktest/switch_unix.go           |   29 +
 src/net/internal/socktest/switch_windows.go        |   29 +
 src/net/internal/socktest/sys_cloexec.go           |   42 +
 src/net/internal/socktest/sys_unix.go              |  193 +
 src/net/internal/socktest/sys_windows.go           |  156 +
 src/net/ip.go                                      |   77 +-
 src/net/ip_test.go                                 |   91 +-
 src/net/ipraw_test.go                              |  244 +-
 src/net/iprawsock.go                               |   18 +-
 src/net/iprawsock_plan9.go                         |   16 +-
 src/net/iprawsock_posix.go                         |   82 +-
 src/net/ipsock.go                                  |  201 +-
 src/net/ipsock_plan9.go                            |   67 +-
 src/net/ipsock_posix.go                            |   43 +-
 src/net/ipsock_test.go                             |  235 +-
 src/net/listen_test.go                             |  685 +++
 src/net/lookup.go                                  |   62 +-
 src/net/lookup_plan9.go                            |   21 +-
 src/net/lookup_stub.go                             |    2 +-
 src/net/lookup_test.go                             |  444 +-
 src/net/lookup_unix.go                             |  151 +-
 src/net/lookup_windows.go                          |  122 +-
 src/net/lookup_windows_test.go                     |   14 +-
 src/net/mac.go                                     |    6 +-
 src/net/mac_test.go                                |   19 +-
 src/net/mail/example_test.go                       |   77 +
 src/net/mail/message.go                            |  260 +-
 src/net/mail/message_test.go                       |  274 ++
 src/net/main_cloexec_test.go                       |   25 +
 src/net/main_plan9_test.go                         |   15 +
 src/net/main_posix_test.go                         |   50 +
 src/net/main_test.go                               |  204 +
 src/net/main_unix_test.go                          |   52 +
 src/net/main_windows_test.go                       |   36 +
 src/net/mockicmp_test.go                           |  116 -
 src/net/mockserver_test.go                         |  464 +-
 src/net/multicast_test.go                          |  188 -
 src/net/net.go                                     |  241 +-
 src/net/net_test.go                                |  403 +-
 src/net/net_windows_test.go                        |   49 +-
 src/net/netgo_unix_test.go                         |    4 +-
 src/net/non_unix_test.go                           |   11 +
 src/net/nss.go                                     |  159 +
 src/net/nss_test.go                                |  169 +
 src/net/packetconn_test.go                         |  119 +-
 src/net/parse.go                                   |  207 +-
 src/net/parse_test.go                              |   36 +-
 src/net/pipe.go                                    |    6 +-
 src/net/pipe_test.go                               |   25 +-
 src/net/platform_test.go                           |  159 +
 src/net/port.go                                    |    2 +-
 src/net/port_test.go                               |   26 +-
 src/net/port_unix.go                               |    2 +-
 src/net/protoconn_test.go                          |  178 +-
 src/net/rpc/client_test.go                         |    2 +-
 src/net/rpc/server.go                              |    3 +-
 src/net/sendfile_dragonfly.go                      |    7 +-
 src/net/sendfile_freebsd.go                        |    7 +-
 src/net/sendfile_linux.go                          |    7 +-
 src/net/sendfile_solaris.go                        |  110 +
 src/net/sendfile_stub.go                           |    2 +-
 src/net/sendfile_windows.go                        |    2 +-
 src/net/server_test.go                             |  661 ++-
 src/net/singleflight.go                            |  109 -
 src/net/smtp/example_test.go                       |   24 +-
 src/net/smtp/smtp.go                               |   35 +-
 src/net/smtp/smtp_test.go                          |   44 +
 src/net/sock_cloexec.go                            |   39 +-
 src/net/sock_posix.go                              |   10 +-
 src/net/sock_windows.go                            |   14 +-
 src/net/sockopt_bsd.go                             |    2 +-
 src/net/sys_cloexec.go                             |   21 +-
 src/net/tcp_test.go                                |  187 +-
 src/net/tcpsock.go                                 |   13 +-
 src/net/tcpsock_plan9.go                           |   61 +-
 src/net/tcpsock_posix.go                           |   99 +-
 src/net/tcpsockopt_plan9.go                        |    3 +-
 src/net/tcpsockopt_solaris.go                      |   35 +
 src/net/tcpsockopt_unix.go                         |    2 +-
 src/net/tcpsockopt_windows.go                      |    2 +-
 src/net/testdata/ipv4-hosts                        |   12 +
 src/net/testdata/ipv6-hosts                        |   11 +
 src/net/testdata/openbsd-resolv.conf               |    5 +
 .../{hosts_singleline => singleline-hosts}         |    0
 src/net/textproto/reader.go                        |   15 +-
 src/net/textproto/reader_test.go                   |    9 +
 src/net/timeout_test.go                            | 1237 +++--
 src/net/udp_test.go                                |  330 +-
 src/net/udpsock.go                                 |   13 +-
 src/net/udpsock_plan9.go                           |   52 +-
 src/net/udpsock_posix.go                           |  103 +-
 src/net/unicast_posix_test.go                      |  469 --
 src/net/unix_test.go                               |  264 +-
 src/net/unixsock.go                                |    6 +-
 src/net/unixsock_plan9.go                          |   38 +-
 src/net/unixsock_posix.go                          |  108 +-
 src/net/url/example_test.go                        |   31 +-
 src/net/url/url.go                                 |  200 +-
 src/net/url/url_test.go                            |  286 +-
 src/net/z_last_test.go                             |   99 -
 src/os/env.go                                      |   13 +-
 src/os/env_test.go                                 |   17 +
 src/os/error_windows_test.go                       |   47 -
 src/os/exec.go                                     |    4 +-
 src/os/exec/exec.go                                |   20 +-
 src/os/exec/exec_posix.go                          |   24 +
 src/os/exec/exec_test.go                           |  123 +-
 src/os/exec/lp_windows_test.go                     |    2 +-
 src/os/exec_posix.go                               |   31 +-
 src/os/exec_windows.go                             |   18 +-
 src/os/file.go                                     |   18 +-
 src/os/file_plan9.go                               |    8 +-
 src/os/file_posix.go                               |   10 +-
 src/os/file_unix.go                                |   34 +-
 src/os/file_windows.go                             |   38 +-
 src/os/os_test.go                                  |  399 +-
 src/os/os_unix_test.go                             |  114 +-
 src/os/os_windows_test.go                          |   59 +-
 src/os/path_plan9.go                               |    2 +-
 src/os/path_test.go                                |   16 +-
 src/os/path_unix.go                                |    2 +-
 src/os/path_windows.go                             |    2 +-
 src/os/proc.go                                     |   14 +-
 src/os/signal/sig.s                                |   11 +-
 src/os/signal/signal.go                            |   59 +-
 src/os/signal/signal_plan9.go                      |   60 +
 src/os/signal/signal_plan9_test.go                 |  181 +
 src/os/signal/signal_stub.go                       |   17 -
 src/os/signal/signal_test.go                       |   66 +
 src/os/signal/signal_unix.go                       |    5 +
 src/os/stat_plan9.go                               |   40 +-
 src/os/stat_windows.go                             |   15 +-
 src/os/sticky_bsd.go                               |   11 +
 src/os/sticky_notbsd.go                            |   14 +
 src/os/str.go                                      |   25 +-
 src/os/sys_windows.go                              |   28 +-
 src/os/types.go                                    |    2 +-
 src/os/user/lookup_unix.go                         |   14 +-
 src/path/filepath/example_unix_test.go             |   28 +
 src/path/filepath/match.go                         |    4 +-
 src/path/filepath/path.go                          |   28 +-
 src/path/filepath/path_plan9.go                    |   12 +-
 src/path/filepath/path_test.go                     |   92 +-
 src/path/filepath/path_unix.go                     |   12 +-
 src/path/filepath/path_windows.go                  |   39 +-
 src/path/filepath/symlink_windows.go               |   27 +-
 src/path/match.go                                  |    2 +-
 src/path/path.go                                   |    4 +-
 src/race.bash                                      |   13 +-
 src/race.bat                                       |   17 +-
 src/reflect/all_test.go                            |  669 ++-
 src/reflect/asm_arm64.s                            |   30 +
 src/reflect/asm_ppc64x.s                           |   32 +
 src/reflect/example_test.go                        |   15 +
 src/reflect/export_test.go                         |   50 +-
 src/reflect/makefunc.go                            |    8 +-
 src/reflect/type.go                                |  762 ++-
 src/reflect/value.go                               |  200 +-
 src/regexp/all_test.go                             |   11 +
 src/regexp/backtrack.go                            |  366 ++
 src/regexp/exec.go                                 |   30 +-
 src/regexp/exec_test.go                            |   24 +-
 src/regexp/regexp.go                               |    6 +-
 src/regexp/syntax/prog.go                          |    4 +-
 src/regexp/testdata/README                         |    3 +-
 src/run.bash                                       |  233 +-
 src/run.bat                                        |  105 +-
 src/run.rc                                         |   50 +-
 src/runtime/alg.go                                 |  213 +-
 src/runtime/arch1_386.go                           |   15 +
 src/runtime/arch1_amd64.go                         |   15 +
 src/runtime/arch1_amd64p32.go                      |   15 +
 src/runtime/arch1_arm.go                           |   15 +
 src/runtime/arch1_arm64.go                         |   15 +
 src/runtime/arch1_ppc64.go                         |   15 +
 src/runtime/arch1_ppc64le.go                       |   15 +
 src/runtime/arch_386.h                             |   17 -
 src/runtime/arch_amd64.h                           |   25 -
 src/runtime/arch_amd64p32.h                        |   17 -
 src/runtime/arch_arm.h                             |   17 -
 src/runtime/arch_arm64.go                          |    8 +
 src/runtime/arch_ppc64.go                          |    8 +
 src/runtime/arch_ppc64le.go                        |    8 +
 src/runtime/asm.s                                  |    5 +
 src/runtime/asm_386.s                              | 1458 ++----
 src/runtime/asm_amd64.s                            | 1631 +++----
 src/runtime/asm_amd64p32.s                         |  316 +-
 src/runtime/asm_arm.s                              |  850 ++--
 src/runtime/asm_arm64.s                            | 1029 ++++
 src/runtime/asm_ppc64x.s                           | 1172 +++++
 src/runtime/atomic.go                              |   51 -
 src/runtime/atomic_386.c                           |   46 -
 src/runtime/atomic_386.go                          |   82 +
 src/runtime/atomic_amd64x.c                        |   29 -
 src/runtime/atomic_amd64x.go                       |   72 +
 src/runtime/atomic_arm.go                          |   40 +-
 src/runtime/atomic_arm64.go                        |   82 +
 src/runtime/atomic_arm64.s                         |  117 +
 src/runtime/atomic_pointer.go                      |   78 +
 src/runtime/atomic_ppc64x.go                       |   60 +
 src/runtime/atomic_ppc64x.s                        |   47 +
 src/runtime/atomic_test.go                         |   66 +
 src/runtime/cgo.go                                 |   50 +
 src/runtime/cgo/asm_arm.s                          |    8 +-
 src/runtime/cgo/asm_arm64.s                        |   57 +
 src/runtime/cgo/asm_ppc64x.s                       |  124 +
 src/runtime/cgo/callbacks.c                        |   83 -
 src/runtime/cgo/callbacks.go                       |   96 +
 src/runtime/cgo/cgo.go                             |    6 +-
 src/runtime/cgo/dragonfly.c                        |   19 -
 src/runtime/cgo/dragonfly.go                       |   19 +
 src/runtime/cgo/freebsd.c                          |   19 -
 src/runtime/cgo/freebsd.go                         |   22 +
 src/runtime/cgo/gcc_android_arm.c                  |    4 +-
 src/runtime/cgo/gcc_arm.S                          |    4 +
 src/runtime/cgo/gcc_arm64.S                        |   57 +
 src/runtime/cgo/gcc_darwin_arm.c                   |  153 +
 src/runtime/cgo/gcc_darwin_arm64.c                 |  157 +
 src/runtime/cgo/gcc_dragonfly_386.c                |   70 -
 src/runtime/cgo/gcc_libinit.c                      |   42 +
 src/runtime/cgo/gcc_libinit_linux_ppc64x.c         |   26 +
 src/runtime/cgo/gcc_libinit_openbsd.c              |   22 +
 src/runtime/cgo/gcc_libinit_windows.c              |   22 +
 src/runtime/cgo/gcc_linux_arm64.c                  |   73 +
 src/runtime/cgo/gcc_linux_ppc64x.c                 |   70 +
 src/runtime/cgo/gcc_ppc64x.S                       |  140 +
 src/runtime/cgo/gcc_setenv.c                       |    2 +-
 src/runtime/cgo/gcc_signal_darwin_armx.c           |  205 +
 src/runtime/cgo/gcc_signal_darwin_lldb.c           |   14 +
 src/runtime/cgo/gcc_solaris_amd64.c                |   75 +
 src/runtime/cgo/iscgo.c                            |   15 -
 src/runtime/cgo/iscgo.go                           |   17 +
 src/runtime/cgo/libcgo.h                           |   21 +
 src/runtime/cgo/netbsd.c                           |   19 -
 src/runtime/cgo/netbsd.go                          |   19 +
 src/runtime/cgo/openbsd.c                          |   27 -
 src/runtime/cgo/openbsd.go                         |   31 +
 src/runtime/cgo/setenv.c                           |   13 -
 src/runtime/cgo/setenv.go                          |   21 +
 src/runtime/cgo/signal_darwin_arm.s                |   49 +
 src/runtime/cgo/signal_darwin_arm64.s              |   56 +
 src/runtime/cgo/signal_darwin_armx.go              |   31 +
 src/runtime/cgocall.go                             |   91 +-
 src/runtime/cgocall.h                              |   13 -
 src/runtime/cgocallback.go                         |   29 +-
 src/runtime/chan.go                                |  130 +-
 src/runtime/chan.h                                 |   68 -
 src/runtime/chan_test.go                           |  104 +-
 src/runtime/chanbarrier_test.go                    |   83 +
 src/runtime/compiler.go                            |    2 +-
 src/runtime/complex.go                             |   39 +-
 src/runtime/cpuprof.go                             |   53 +-
 src/runtime/cputicks.go                            |   12 +
 src/runtime/crash_cgo_test.go                      |  237 +-
 src/runtime/crash_test.go                          |  104 +-
 src/runtime/crash_unix_test.go                     |  135 +
 src/runtime/debug.go                               |   27 +-
 src/runtime/debug/garbage.go                       |    2 +-
 src/runtime/debug/garbage_test.go                  |    4 +
 src/runtime/debug/heapdump_test.go                 |   36 +
 src/runtime/debug/stack.go                         |    2 +-
 src/runtime/debug/stubs.go                         |    1 -
 src/runtime/debug/stubs.s                          |    9 +
 src/runtime/defs.c                                 |   15 -
 src/runtime/defs1_linux.go                         |    6 +-
 src/runtime/defs1_netbsd_386.go                    |  183 +
 src/runtime/defs1_netbsd_amd64.go                  |  195 +
 src/runtime/defs1_netbsd_arm.go                    |  183 +
 src/runtime/defs1_solaris_amd64.go                 |  245 +
 src/runtime/defs3_linux.go                         |   43 +
 src/runtime/defs_android_arm.h                     |    3 -
 src/runtime/defs_darwin_386.go                     |  382 ++
 src/runtime/defs_darwin_386.h                      |  392 --
 src/runtime/defs_darwin_amd64.go                   |  385 ++
 src/runtime/defs_darwin_amd64.h                    |  395 --
 src/runtime/defs_darwin_arm.go                     |  245 +
 src/runtime/defs_darwin_arm64.go                   |  248 +
 src/runtime/defs_dragonfly.go                      |    1 -
 src/runtime/defs_dragonfly_386.h                   |  198 -
 src/runtime/defs_dragonfly_amd64.go                |  208 +
 src/runtime/defs_dragonfly_amd64.h                 |  208 -
 src/runtime/defs_freebsd_386.go                    |  213 +
 src/runtime/defs_freebsd_386.h                     |  213 -
 src/runtime/defs_freebsd_amd64.go                  |  224 +
 src/runtime/defs_freebsd_amd64.h                   |  224 -
 src/runtime/defs_freebsd_arm.go                    |  186 +
 src/runtime/defs_freebsd_arm.h                     |  186 -
 src/runtime/defs_linux.go                          |   11 +-
 src/runtime/defs_linux_386.go                      |  220 +
 src/runtime/defs_linux_386.h                       |  211 -
 src/runtime/defs_linux_amd64.go                    |  255 +
 src/runtime/defs_linux_amd64.h                     |  254 -
 src/runtime/defs_linux_arm.go                      |  182 +
 src/runtime/defs_linux_arm.h                       |  168 -
 src/runtime/defs_linux_arm64.go                    |  178 +
 src/runtime/defs_linux_ppc64.go                    |  200 +
 src/runtime/defs_linux_ppc64le.go                  |  200 +
 src/runtime/defs_nacl_386.go                       |   43 +
 src/runtime/defs_nacl_386.h                        |   63 -
 src/runtime/defs_nacl_amd64p32.go                  |   64 +
 src/runtime/defs_nacl_amd64p32.h                   |   90 -
 src/runtime/defs_nacl_arm.go                       |   50 +
 src/runtime/defs_nacl_arm.h                        |   70 -
 src/runtime/defs_netbsd_386.h                      |  182 -
 src/runtime/defs_netbsd_amd64.h                    |  194 -
 src/runtime/defs_netbsd_arm.h                      |  184 -
 src/runtime/defs_openbsd_386.go                    |  170 +
 src/runtime/defs_openbsd_386.h                     |  168 -
 src/runtime/defs_openbsd_amd64.go                  |  181 +
 src/runtime/defs_openbsd_amd64.h                   |  179 -
 src/runtime/defs_openbsd_arm.go                    |  170 +
 src/runtime/defs_plan9_386.go                      |   51 +
 src/runtime/defs_plan9_386.h                       |   26 -
 src/runtime/defs_plan9_amd64.go                    |   68 +
 src/runtime/defs_plan9_amd64.h                     |   34 -
 src/runtime/defs_solaris_amd64.h                   |  254 -
 src/runtime/defs_windows.go                        |    1 -
 src/runtime/defs_windows_386.go                    |  131 +
 src/runtime/defs_windows_386.h                     |  116 -
 src/runtime/defs_windows_amd64.go                  |  153 +
 src/runtime/defs_windows_amd64.h                   |  131 -
 src/runtime/duff_386.s                             |  779 +++
 src/runtime/duff_amd64.s                           |  841 ++++
 src/runtime/duff_arm.s                             |  523 ++
 src/runtime/duff_arm64.s                           |  138 +
 src/runtime/duff_ppc64x.s                          |  140 +
 src/runtime/env_plan9.go                           |   16 +-
 src/runtime/env_posix.go                           |   23 +-
 src/runtime/env_test.go                            |   47 +
 src/runtime/error.go                               |   23 +-
 src/runtime/export_arm_test.go                     |    9 +
 src/runtime/export_linux_test.go                   |    9 +
 src/runtime/export_test.go                         |  166 +-
 src/runtime/export_windows_test.go                 |    9 +
 src/runtime/extern.go                              |   71 +-
 src/runtime/float.c                                |   10 -
 src/runtime/funcdata.h                             |   10 +-
 src/runtime/futex_test.go                          |    4 +-
 src/runtime/gc_test.go                             |  268 +-
 src/runtime/gcinfo_test.go                         |  153 +-
 src/runtime/gengoos.go                             |   84 +
 src/runtime/go_tls.h                               |   22 +
 src/runtime/hash32.go                              |   89 +
 src/runtime/hash64.go                              |   89 +
 src/runtime/hash_test.go                           |    9 -
 src/runtime/hashmap.go                             |  292 +-
 src/runtime/hashmap_fast.go                        |   12 +-
 src/runtime/heapdump.c                             |  864 ----
 src/runtime/heapdump.go                            |  735 +++
 src/runtime/iface.go                               |  249 +-
 src/runtime/iface_test.go                          |  125 +
 src/runtime/lfstack.c                              |   87 -
 src/runtime/lfstack.go                             |   40 +
 src/runtime/lfstack_32bit.go                       |   21 +
 src/runtime/lfstack_amd64.go                       |   24 +
 src/runtime/lfstack_darwin_arm64.go                |   25 +
 src/runtime/lfstack_linux_arm64.go                 |   25 +
 src/runtime/lfstack_linux_ppc64x.go                |   32 +
 src/runtime/lfstack_test.go                        |    8 +-
 src/runtime/lock_futex.go                          |   27 +-
 src/runtime/lock_sema.go                           |   36 +-
 src/runtime/malloc.c                               |  396 --
 src/runtime/malloc.go                              | 1273 ++---
 src/runtime/malloc.h                               |  621 ---
 src/runtime/malloc_test.go                         |   38 +-
 src/runtime/map_test.go                            |   65 +
 src/runtime/mapspeed_test.go                       |   28 +
 src/runtime/mbarrier.go                            |  298 ++
 src/runtime/mbitmap.go                             | 1710 +++++++
 src/runtime/mcache.c                               |  115 -
 src/runtime/mcache.go                              |  139 +
 src/runtime/mcentral.c                             |  214 -
 src/runtime/mcentral.go                            |  212 +
 src/runtime/mem.go                                 |  108 -
 src/runtime/mem_bsd.go                             |   93 +
 src/runtime/mem_darwin.c                           |   82 -
 src/runtime/mem_darwin.go                          |   63 +
 src/runtime/mem_dragonfly.c                        |  105 -
 src/runtime/mem_freebsd.c                          |  100 -
 src/runtime/mem_linux.c                            |  162 -
 src/runtime/mem_linux.go                           |  159 +
 src/runtime/mem_nacl.c                             |  120 -
 src/runtime/mem_netbsd.c                           |  100 -
 src/runtime/mem_openbsd.c                          |  100 -
 src/runtime/mem_plan9.c                            |  121 -
 src/runtime/mem_plan9.go                           |  174 +
 src/runtime/mem_solaris.c                          |  101 -
 src/runtime/mem_windows.c                          |  132 -
 src/runtime/mem_windows.go                         |  114 +
 src/runtime/memclr_386.s                           |   46 +-
 src/runtime/memclr_amd64.s                         |   44 +-
 src/runtime/memclr_arm.s                           |   40 +-
 src/runtime/memclr_arm64.s                         |   18 +
 src/runtime/memclr_plan9_386.s                     |   24 +-
 src/runtime/memclr_ppc64x.s                        |   20 +
 src/runtime/memmove_arm.s                          |  252 +-
 src/runtime/memmove_arm64.s                        |   36 +
 src/runtime/memmove_ppc64x.s                       |   40 +
 src/runtime/memmove_test.go                        |   32 +
 src/runtime/mfinal.go                              |  412 ++
 src/runtime/mfinal_test.go                         |    3 -
 src/runtime/mfixalloc.c                            |   64 -
 src/runtime/mfixalloc.go                           |   87 +
 src/runtime/mgc.go                                 | 1765 +++++++
 src/runtime/mgc0.c                                 | 2013 --------
 src/runtime/mgc0.go                                |  152 -
 src/runtime/mgc0.h                                 |   78 -
 src/runtime/mgcmark.go                             | 1035 ++++
 src/runtime/mgcsweep.go                            |  370 ++
 src/runtime/mgcwork.go                             |  458 ++
 src/runtime/mheap.c                                |  889 ----
 src/runtime/mheap.go                               | 1090 +++++
 src/runtime/mkduff.go                              |  188 +
 src/runtime/mprof.go                               |   57 +-
 src/runtime/msize.c                                |  184 -
 src/runtime/msize.go                               |  254 +
 src/runtime/mstats.go                              |  391 ++
 src/runtime/netpoll.go                             |  139 +-
 src/runtime/netpoll_epoll.go                       |   16 +-
 src/runtime/netpoll_kqueue.go                      |   15 +-
 src/runtime/netpoll_solaris.c                      |  264 -
 src/runtime/netpoll_solaris.go                     |  243 +
 src/runtime/netpoll_stub.c                         |   18 -
 src/runtime/netpoll_stub.go                        |   19 +
 src/runtime/netpoll_windows.c                      |  163 -
 src/runtime/netpoll_windows.go                     |  145 +
 src/runtime/noasm.go                               |   58 +
 src/runtime/noasm_arm.go                           |   54 -
 src/runtime/norace_linux_test.go                   |   41 +
 src/runtime/norace_test.go                         |    4 +-
 src/runtime/os1_darwin.go                          |  481 ++
 src/runtime/os1_dragonfly.go                       |  247 +
 src/runtime/os1_freebsd.go                         |  249 +
 src/runtime/os1_linux.go                           |  350 ++
 src/runtime/os1_nacl.go                            |  203 +
 src/runtime/os1_netbsd.go                          |  238 +
 src/runtime/os1_netbsd_386.go                      |   16 +
 src/runtime/os1_netbsd_amd64.go                    |   16 +
 src/runtime/os1_openbsd.go                         |  246 +
 src/runtime/os1_plan9.go                           |  268 +
 src/runtime/os1_windows.go                         |  540 ++
 src/runtime/os2_darwin.go                          |   14 +
 src/runtime/os2_dragonfly.go                       |   15 +
 src/runtime/os2_freebsd.go                         |   15 +
 src/runtime/os2_linux.go                           |   25 +
 src/runtime/os2_nacl.go                            |  154 +
 src/runtime/os2_netbsd.go                          |   18 +
 src/runtime/os2_openbsd.go                         |   14 +
 src/runtime/os2_plan9.go                           |   74 +
 src/runtime/os2_solaris.go                         |   14 +
 src/runtime/os2_windows.go                         |   19 +
 src/runtime/os3_plan9.go                           |  128 +
 src/runtime/os3_solaris.go                         |  529 ++
 src/runtime/os_android.c                           |   16 -
 src/runtime/os_android.h                           |    1 -
 src/runtime/os_android_arm.go                      |   15 +
 src/runtime/os_darwin.c                            |  567 ---
 src/runtime/os_darwin.go                           |   31 +-
 src/runtime/os_darwin.h                            |   43 -
 src/runtime/os_darwin_arm.go                       |   24 +
 src/runtime/os_darwin_arm64.go                     |   13 +
 src/runtime/os_dragonfly.c                         |  312 --
 src/runtime/os_dragonfly.go                        |   38 +-
 src/runtime/os_dragonfly.h                         |   30 -
 src/runtime/os_freebsd.c                           |  320 --
 src/runtime/os_freebsd.go                          |   33 +-
 src/runtime/os_freebsd.h                           |   29 -
 src/runtime/os_freebsd_arm.c                       |   24 -
 src/runtime/os_freebsd_arm.go                      |   24 +
 src/runtime/os_linux.c                             |  342 --
 src/runtime/os_linux.go                            |   28 +-
 src/runtime/os_linux.h                             |   41 -
 src/runtime/os_linux_386.c                         |   38 -
 src/runtime/os_linux_386.go                        |   35 +
 src/runtime/os_linux_arm.c                         |   80 -
 src/runtime/os_linux_arm.go                        |   72 +
 src/runtime/os_linux_arm64.go                      |   20 +
 src/runtime/os_nacl.c                              |  312 --
 src/runtime/os_nacl.go                             |   38 +-
 src/runtime/os_nacl.h                              |  162 -
 src/runtime/os_nacl_arm.c                          |   24 -
 src/runtime/os_nacl_arm.go                         |   23 +
 src/runtime/os_netbsd.c                            |  368 --
 src/runtime/os_netbsd.go                           |   37 +-
 src/runtime/os_netbsd.h                            |   31 -
 src/runtime/os_netbsd_386.c                        |   17 -
 src/runtime/os_netbsd_amd64.c                      |   18 -
 src/runtime/os_netbsd_arm.c                        |   34 -
 src/runtime/os_netbsd_arm.go                       |   35 +
 src/runtime/os_openbsd.c                           |  309 --
 src/runtime/os_openbsd.go                          |   34 +-
 src/runtime/os_openbsd.h                           |   26 -
 src/runtime/os_openbsd_arm.go                      |   24 +
 src/runtime/os_plan9.c                             |  362 --
 src/runtime/os_plan9.go                            |   43 +-
 src/runtime/os_plan9.h                             |   93 -
 src/runtime/os_plan9_386.c                         |  150 -
 src/runtime/os_plan9_amd64.c                       |  158 -
 src/runtime/os_solaris.c                           |  557 ---
 src/runtime/os_solaris.go                          |   27 +-
 src/runtime/os_solaris.h                           |   55 -
 src/runtime/os_windows.c                           |  636 ---
 src/runtime/os_windows.go                          |   58 +-
 src/runtime/os_windows.h                           |   42 -
 src/runtime/os_windows_386.c                       |  128 -
 src/runtime/os_windows_386.go                      |   11 -
 src/runtime/os_windows_amd64.c                     |  150 -
 src/runtime/os_windows_amd64.go                    |   11 -
 src/runtime/panic.c                                |  200 -
 src/runtime/panic.go                               |  184 +-
 src/runtime/panic1.go                              |  150 +
 src/runtime/parfor.c                               |  226 -
 src/runtime/parfor.go                              |  212 +
 src/runtime/parfor_test.go                         |   21 +-
 src/runtime/pprof/pprof.go                         |   65 +-
 src/runtime/pprof/pprof_test.go                    |   54 +-
 src/runtime/print1.go                              |  146 +-
 src/runtime/print1_write.go                        |   13 +
 src/runtime/print1_write_android.go                |  160 +
 src/runtime/proc.c                                 | 3521 --------------
 src/runtime/proc.go                                |  195 +-
 src/runtime/proc1.go                               | 3725 ++++++++++++++
 src/runtime/proc_test.go                           |  133 +-
 src/runtime/race.c                                 |  347 --
 src/runtime/race.go                                |   47 +-
 src/runtime/race.h                                 |   34 -
 src/runtime/race/README                            |    2 +-
 src/runtime/race/doc.go                            |    2 +-
 src/runtime/race/output_test.go                    |   36 +-
 src/runtime/race/race_darwin_amd64.syso            |  Bin 278328 -> 314000 bytes
 src/runtime/race/race_freebsd_amd64.syso           |  Bin 294224 -> 316816 bytes
 src/runtime/race/race_linux_amd64.syso             |  Bin 298064 -> 330232 bytes
 src/runtime/race/race_test.go                      |   16 +-
 src/runtime/race/race_windows_amd64.syso           |  Bin 292311 -> 331489 bytes
 src/runtime/race/sched_test.go                     |   48 +
 src/runtime/race/testdata/io_test.go               |    2 +-
 src/runtime/race/testdata/mop_test.go              |  110 +
 src/runtime/race/testdata/rwmutex_test.go          |   22 +-
 src/runtime/race/testdata/select_test.go           |    2 +-
 src/runtime/race/testdata/slice_test.go            |  107 +
 src/runtime/race/testdata/sync_test.go             |   74 +-
 src/runtime/race0.go                               |   38 +-
 src/runtime/race1.go                               |  315 ++
 src/runtime/race_amd64.s                           |   40 +-
 src/runtime/rdebug.go                              |   18 -
 src/runtime/rt0_android_arm.s                      |   24 +
 src/runtime/rt0_darwin_amd64.s                     |   34 +
 src/runtime/rt0_darwin_arm.s                       |   59 +
 src/runtime/rt0_darwin_arm64.s                     |   55 +
 src/runtime/rt0_dragonfly_386.s                    |   16 -
 src/runtime/rt0_freebsd_arm.s                      |    6 +-
 src/runtime/rt0_linux_386.s                        |   56 +-
 src/runtime/rt0_linux_amd64.s                      |   49 +
 src/runtime/rt0_linux_arm.s                        |   57 +-
 src/runtime/rt0_linux_arm64.s                      |   19 +
 src/runtime/rt0_linux_ppc64.s                      |   23 +
 src/runtime/rt0_linux_ppc64le.s                    |   34 +
 src/runtime/rt0_netbsd_arm.s                       |    4 +-
 src/runtime/rt0_openbsd_arm.s                      |   11 +
 src/runtime/rt0_windows_386.s                      |    4 +-
 src/runtime/rt0_windows_amd64.s                    |    3 +-
 src/runtime/rune.go                                |    2 +-
 src/runtime/runtime-gdb.py                         |   58 +-
 src/runtime/runtime-gdb_test.go                    |  164 +
 src/runtime/runtime.c                              |  399 --
 src/runtime/runtime.go                             |   26 +-
 src/runtime/runtime.h                              | 1132 -----
 src/runtime/runtime1.go                            |  450 ++
 src/runtime/runtime2.go                            |  699 +++
 src/runtime/runtime_test.go                        |  160 +-
 src/runtime/runtime_unix_test.go                   |    2 +-
 src/runtime/select.go                              |  221 +-
 src/runtime/sema.go                                |   40 +-
 src/runtime/signal.c                               |   25 -
 src/runtime/signal1_unix.go                        |  241 +
 src/runtime/signal_386.c                           |  122 -
 src/runtime/signal_386.go                          |  193 +
 src/runtime/signal_amd64x.c                        |  156 -
 src/runtime/signal_amd64x.go                       |  204 +
 src/runtime/signal_android_386.h                   |    1 -
 src/runtime/signal_android_arm.h                   |    1 -
 src/runtime/signal_arm.c                           |  121 -
 src/runtime/signal_arm.go                          |  165 +
 src/runtime/signal_arm64.go                        |  178 +
 src/runtime/signal_darwin.go                       |   71 +
 src/runtime/signal_darwin_386.go                   |   34 +
 src/runtime/signal_darwin_386.h                    |   23 -
 src/runtime/signal_darwin_amd64.go                 |   42 +
 src/runtime/signal_darwin_amd64.h                  |   31 -
 src/runtime/signal_darwin_arm.go                   |   44 +
 src/runtime/signal_darwin_arm64.go                 |   60 +
 src/runtime/signal_dragonfly.go                    |   46 +
 src/runtime/signal_dragonfly_386.h                 |   23 -
 src/runtime/signal_dragonfly_amd64.go              |   44 +
 src/runtime/signal_dragonfly_amd64.h               |   31 -
 src/runtime/signal_freebsd.go                      |   46 +
 src/runtime/signal_freebsd_386.go                  |   34 +
 src/runtime/signal_freebsd_386.h                   |   23 -
 src/runtime/signal_freebsd_amd64.go                |   44 +
 src/runtime/signal_freebsd_amd64.h                 |   31 -
 src/runtime/signal_freebsd_arm.go                  |   48 +
 src/runtime/signal_freebsd_arm.h                   |   28 -
 src/runtime/signal_linux.go                        |   96 +
 src/runtime/signal_linux_386.go                    |   36 +
 src/runtime/signal_linux_386.h                     |   24 -
 src/runtime/signal_linux_amd64.go                  |   46 +
 src/runtime/signal_linux_amd64.h                   |   32 -
 src/runtime/signal_linux_arm.go                    |   48 +
 src/runtime/signal_linux_arm.h                     |   28 -
 src/runtime/signal_linux_arm64.go                  |   61 +
 src/runtime/signal_linux_ppc64x.go                 |   71 +
 src/runtime/signal_nacl.go                         |   45 +
 src/runtime/signal_nacl_386.go                     |   34 +
 src/runtime/signal_nacl_386.h                      |   23 -
 src/runtime/signal_nacl_amd64p32.go                |   44 +
 src/runtime/signal_nacl_amd64p32.h                 |   31 -
 src/runtime/signal_nacl_arm.go                     |   47 +
 src/runtime/signal_nacl_arm.h                      |   28 -
 src/runtime/signal_netbsd.go                       |   46 +
 src/runtime/signal_netbsd_386.go                   |   38 +
 src/runtime/signal_netbsd_386.h                    |   23 -
 src/runtime/signal_netbsd_amd64.go                 |   48 +
 src/runtime/signal_netbsd_amd64.h                  |   31 -
 src/runtime/signal_netbsd_arm.go                   |   48 +
 src/runtime/signal_netbsd_arm.h                    |   30 -
 src/runtime/signal_openbsd.go                      |   46 +
 src/runtime/signal_openbsd_386.go                  |   41 +
 src/runtime/signal_openbsd_386.h                   |   23 -
 src/runtime/signal_openbsd_amd64.go                |   49 +
 src/runtime/signal_openbsd_amd64.h                 |   31 -
 src/runtime/signal_openbsd_arm.go                  |   53 +
 src/runtime/signal_plan9.go                        |   54 +
 src/runtime/signal_ppc64x.go                       |  183 +
 src/runtime/signal_solaris.go                      |   88 +
 src/runtime/signal_solaris_amd64.go                |   46 +
 src/runtime/signal_solaris_amd64.h                 |   31 -
 src/runtime/signal_unix.c                          |  119 -
 src/runtime/signal_unix.go                         |   39 +-
 src/runtime/signal_unix.h                          |   14 -
 src/runtime/signal_windows.go                      |  221 +
 src/runtime/signals_android.h                      |    1 -
 src/runtime/signals_darwin.h                       |   53 -
 src/runtime/signals_dragonfly.h                    |   54 -
 src/runtime/signals_freebsd.h                      |   54 -
 src/runtime/signals_linux.h                        |   86 -
 src/runtime/signals_nacl.h                         |   53 -
 src/runtime/signals_netbsd.h                       |   54 -
 src/runtime/signals_openbsd.h                      |   54 -
 src/runtime/signals_plan9.h                        |   63 -
 src/runtime/signals_solaris.h                      |   97 -
 src/runtime/signals_windows.h                      |    3 -
 src/runtime/sigpanic_unix.go                       |   25 +-
 src/runtime/sigqueue.go                            |   50 +-
 src/runtime/sigqueue_plan9.go                      |  128 +
 src/runtime/slice.go                               |   56 +-
 src/runtime/softfloat64.go                         |   15 +-
 src/runtime/softfloat64_test.go                    |    2 +-
 src/runtime/softfloat_arm.c                        |  687 ---
 src/runtime/softfloat_arm.go                       |  608 +++
 src/runtime/sqrt.go                                |   63 +-
 src/runtime/sqrt_test.go                           |   85 +
 src/runtime/stack.c                                |  892 ----
 src/runtime/stack.go                               |   13 -
 src/runtime/stack.h                                |  118 -
 src/runtime/stack1.go                              |  917 ++++
 src/runtime/stack2.go                              |  106 +
 src/runtime/stack_test.go                          |   54 +-
 src/runtime/string.c                               |  226 -
 src/runtime/string.go                              |  164 +-
 src/runtime/string1.go                             |   67 +
 src/runtime/string_test.go                         |   77 +
 src/runtime/stubs.go                               |  276 +-
 src/runtime/stubs2.go                              |   30 +
 src/runtime/stubs32.go                             |   14 +
 src/runtime/stubs_android.go                       |   10 +
 src/runtime/symtab.go                              |  273 +-
 src/runtime/symtab_test.go                         |  105 +
 src/runtime/sys_arm.c                              |   35 -
 src/runtime/sys_arm.go                             |   38 +
 src/runtime/sys_arm64.go                           |   36 +
 src/runtime/sys_darwin_386.s                       |   61 +-
 src/runtime/sys_darwin_amd64.s                     |  133 +-
 src/runtime/sys_darwin_arm.s                       |  490 ++
 src/runtime/sys_darwin_arm64.s                     |  455 ++
 src/runtime/sys_dragonfly_386.s                    |  381 --
 src/runtime/sys_dragonfly_amd64.s                  |   40 +-
 src/runtime/sys_freebsd_386.s                      |   38 +-
 src/runtime/sys_freebsd_amd64.s                    |   63 +-
 src/runtime/sys_freebsd_arm.s                      |  139 +-
 src/runtime/sys_linux_386.s                        |  105 +-
 src/runtime/sys_linux_amd64.s                      |  102 +-
 src/runtime/sys_linux_arm.s                        |  275 +-
 src/runtime/sys_linux_arm64.s                      |  447 ++
 src/runtime/sys_linux_ppc64x.s                     |  407 ++
 src/runtime/sys_nacl_386.s                         |   20 +-
 src/runtime/sys_nacl_amd64p32.s                    |   17 +-
 src/runtime/sys_nacl_arm.s                         |   19 +-
 src/runtime/sys_netbsd_386.s                       |   28 +-
 src/runtime/sys_netbsd_amd64.s                     |   32 +-
 src/runtime/sys_netbsd_arm.s                       |  140 +-
 src/runtime/sys_openbsd_386.s                      |   32 +-
 src/runtime/sys_openbsd_amd64.s                    |   30 +-
 src/runtime/sys_openbsd_arm.s                      |  390 ++
 src/runtime/sys_plan9_386.s                        |    5 +-
 src/runtime/sys_plan9_amd64.s                      |    5 +-
 src/runtime/sys_ppc64x.go                          |   37 +
 src/runtime/sys_solaris_amd64.s                    |   27 +-
 src/runtime/sys_windows_386.s                      |   45 +-
 src/runtime/sys_windows_amd64.s                    |   43 +-
 src/runtime/sys_x86.c                              |   57 -
 src/runtime/sys_x86.go                             |   54 +
 src/runtime/syscall2_solaris.go                    |   49 +
 src/runtime/syscall_nacl.h                         |   15 +-
 src/runtime/syscall_solaris.c                      |   23 -
 src/runtime/syscall_solaris.go                     |   80 +-
 src/runtime/syscall_windows.go                     |   78 +-
 src/runtime/syscall_windows_test.go                |  125 +-
 src/runtime/textflag.h                             |   23 +
 src/runtime/thunk.s                                |  183 -
 src/runtime/thunk_solaris_amd64.s                  |   88 -
 src/runtime/thunk_windows.s                        |   30 -
 src/runtime/time.go                                |   26 +-
 src/runtime/tls_arm.s                              |   52 +-
 src/runtime/tls_arm64.h                            |   20 +
 src/runtime/tls_arm64.s                            |   60 +
 src/runtime/tls_ppc64x.s                           |   60 +
 src/runtime/trace.go                               |  859 ++++
 src/runtime/trace/trace.go                         |   42 +
 src/runtime/trace/trace_stack_test.go              |  285 ++
 src/runtime/trace/trace_test.go                    |  434 ++
 src/runtime/traceback.go                           |  212 +-
 src/runtime/type.go                                |   94 +
 src/runtime/type.h                                 |  113 -
 src/runtime/typekind.h                             |   38 -
 src/runtime/typekind1.go                           |   39 +
 src/runtime/unaligned1.go                          |   17 +
 src/runtime/unaligned2.go                          |   20 +
 src/runtime/vdso_linux_amd64.c                     |  371 --
 src/runtime/vdso_linux_amd64.go                    |  327 ++
 src/runtime/vdso_none.go                           |   12 +
 src/runtime/vlop_arm.s                             |  254 +-
 src/runtime/vlop_arm_test.go                       |   16 +-
 src/runtime/vlrt.c                                 |  914 ----
 src/runtime/wbfat.go                               |  190 +
 src/runtime/wbfat_gen.go                           |   41 +
 src/runtime/wincallback.go                         |   64 +
 src/runtime/zcallback_windows.go                   |    5 +
 src/runtime/zcallback_windows.s                    | 2010 ++++++++
 src/runtime/zgoarch_386.go                         |   13 +
 src/runtime/zgoarch_amd64.go                       |   13 +
 src/runtime/zgoarch_amd64p32.go                    |   13 +
 src/runtime/zgoarch_arm.go                         |   13 +
 src/runtime/zgoarch_arm64.go                       |   13 +
 src/runtime/zgoarch_ppc64.go                       |   13 +
 src/runtime/zgoarch_ppc64le.go                     |   13 +
 src/runtime/zgoos_android.go                       |   17 +
 src/runtime/zgoos_darwin.go                        |   17 +
 src/runtime/zgoos_dragonfly.go                     |   17 +
 src/runtime/zgoos_freebsd.go                       |   17 +
 src/runtime/zgoos_linux.go                         |   19 +
 src/runtime/zgoos_nacl.go                          |   17 +
 src/runtime/zgoos_netbsd.go                        |   17 +
 src/runtime/zgoos_openbsd.go                       |   17 +
 src/runtime/zgoos_plan9.go                         |   17 +
 src/runtime/zgoos_solaris.go                       |   17 +
 src/runtime/zgoos_windows.go                       |   17 +
 src/sort/sort.go                                   |  140 +-
 src/strconv/atof.go                                |    2 -
 src/strconv/atoi.go                                |   40 +-
 src/strconv/atoi_test.go                           |   83 +-
 src/strconv/decimal.go                             |  117 +-
 src/strconv/doc.go                                 |   57 +
 src/strconv/example_test.go                        |  338 ++
 src/strconv/extfloat.go                            |    2 +-
 src/strconv/ftoa.go                                |  108 +-
 src/strconv/ftoa_test.go                           |    1 +
 src/strconv/isprint.go                             |   89 +-
 src/strconv/itoa.go                                |   58 +-
 src/strconv/itoa_test.go                           |    1 +
 src/strconv/quote_example_test.go                  |   35 -
 src/strings/compare.go                             |   28 +
 src/strings/compare_test.go                        |   98 +
 src/strings/reader.go                              |    6 +
 src/strings/reader_test.go                         |   13 +
 src/strings/strings.go                             |   32 +-
 src/strings/strings_test.go                        |   46 +
 src/sudo.bash                                      |   41 -
 src/sync/atomic/asm_386.s                          |    9 -
 src/sync/atomic/asm_amd64.s                        |   14 +-
 src/sync/atomic/asm_amd64p32.s                     |   14 +-
 src/sync/atomic/asm_arm.s                          |   28 +
 src/sync/atomic/asm_arm64.s                        |  149 +
 src/sync/atomic/asm_darwin_arm.s                   |   99 +
 src/sync/atomic/asm_freebsd_arm.s                  |    9 -
 src/sync/atomic/asm_linux_arm.s                    |   27 +-
 src/sync/atomic/asm_nacl_arm.s                     |    9 -
 src/sync/atomic/asm_netbsd_arm.s                   |    9 -
 src/sync/atomic/asm_openbsd_arm.s                  |  100 +
 src/sync/atomic/asm_ppc64x.s                       |  175 +
 src/sync/atomic/atomic_test.go                     |   71 +-
 src/sync/export_test.go                            |    2 +
 src/sync/mutex.go                                  |   17 +
 src/sync/mutex_test.go                             |   55 +
 src/sync/runtime.go                                |    7 +
 src/sync/waitgroup.go                              |  134 +-
 src/sync/waitgroup_test.go                         |  123 +
 src/syscall/asm_darwin_386.s                       |   93 +-
 src/syscall/asm_darwin_amd64.s                     |  135 +-
 src/syscall/asm_darwin_arm.s                       |  134 +
 src/syscall/asm_darwin_arm64.s                     |  127 +
 src/syscall/asm_dragonfly_386.s                    |  140 -
 src/syscall/asm_freebsd_amd64.s                    |    5 -
 src/syscall/asm_freebsd_arm.s                      |  112 +-
 src/syscall/asm_linux_386.s                        |  143 +-
 src/syscall/asm_linux_amd64.s                      |  105 +-
 src/syscall/asm_linux_arm.s                        |  112 +-
 src/syscall/asm_linux_arm64.s                      |  105 +
 src/syscall/asm_linux_ppc64x.s                     |  104 +
 src/syscall/asm_nacl_386.s                         |    3 +-
 src/syscall/asm_nacl_amd64p32.s                    |    2 +-
 src/syscall/asm_nacl_arm.s                         |    2 +-
 src/syscall/asm_netbsd_arm.s                       |  106 +-
 src/syscall/asm_openbsd_arm.s                      |  132 +
 src/syscall/asm_solaris_amd64.s                    |    3 +
 src/syscall/const_plan9.go                         |   59 +
 src/syscall/creds_test.go                          |    8 +-
 src/syscall/dll_windows.go                         |    2 +-
 src/syscall/env_plan9.go                           |    6 +-
 src/syscall/env_windows.go                         |   20 +-
 .../{zerrors_plan9_386.go => errors_plan9.go}      |    0
 src/syscall/exec_bsd.go                            |   34 +-
 src/syscall/exec_linux.go                          |  115 +-
 src/syscall/exec_linux_test.go                     |  111 +
 src/syscall/exec_plan9.go                          |   20 +-
 src/syscall/exec_solaris.go                        |   37 +-
 src/syscall/exec_solaris_test.go                   |   37 +
 src/syscall/exec_unix.go                           |   10 +-
 src/syscall/exec_unix_test.go                      |  215 +
 src/syscall/exec_windows.go                        |   19 +-
 src/syscall/export_unix_test.go                    |   12 +
 src/syscall/fs_nacl.go                             |   25 +-
 src/syscall/mkall.sh                               |   73 +-
 src/syscall/mkall_windows.bat                      |   15 -
 src/syscall/mkerrors.sh                            |   11 +
 src/syscall/mksyscall.pl                           |    2 +-
 src/syscall/mksyscall_solaris.pl                   |   30 +-
 src/syscall/mksyscall_windows.go                   |   43 +-
 src/syscall/mksysnum_linux.pl                      |   17 +-
 src/syscall/pwd_plan9.go                           |   83 +
 src/syscall/route_bsd.go                           |  313 +-
 src/syscall/route_bsd_test.go                      |  225 +
 src/syscall/route_darwin.go                        |   46 +-
 src/syscall/route_dragonfly.go                     |   50 +-
 src/syscall/route_freebsd.go                       |   70 +-
 src/syscall/route_freebsd_32bit.go                 |   13 +-
 src/syscall/route_freebsd_64bit.go                 |    7 +-
 src/syscall/route_ifma_test.go                     |   74 +
 src/syscall/route_netbsd.go                        |    6 +-
 src/syscall/route_noifma_test.go                   |   63 +
 src/syscall/route_openbsd.go                       |    6 +-
 src/syscall/security_windows.go                    |   98 +-
 src/syscall/so_solaris.go                          |  262 -
 src/syscall/syscall.go                             |   14 +-
 src/syscall/syscall_bsd.go                         |   35 +-
 src/syscall/syscall_darwin.go                      |    4 +-
 src/syscall/syscall_darwin_amd64.go                |    2 +-
 src/syscall/syscall_darwin_arm.go                  |   70 +
 src/syscall/syscall_darwin_arm64.go                |   70 +
 src/syscall/syscall_dragonfly.go                   |    6 +-
 src/syscall/syscall_dragonfly_386.go               |   58 -
 src/syscall/syscall_freebsd.go                     |    4 +-
 src/syscall/syscall_linux.go                       |  101 +-
 src/syscall/syscall_linux_386.go                   |   31 +-
 src/syscall/syscall_linux_amd64.go                 |   35 +-
 src/syscall/syscall_linux_arm.go                   |   29 +-
 src/syscall/syscall_linux_arm64.go                 |  148 +
 src/syscall/syscall_linux_ppc64x.go                |  124 +
 src/syscall/syscall_linux_test.go                  |  140 +
 src/syscall/syscall_nacl.go                        |    1 +
 src/syscall/syscall_netbsd.go                      |    4 +-
 src/syscall/syscall_openbsd.go                     |    4 +-
 src/syscall/syscall_openbsd_arm.go                 |   42 +
 src/syscall/syscall_plan9.go                       |   67 +-
 src/syscall/syscall_solaris.go                     |   11 +-
 src/syscall/syscall_solaris_amd64.go               |    5 -
 src/syscall/syscall_unix.go                        |   24 +
 src/syscall/syscall_unix_test.go                   |   66 +-
 src/syscall/syscall_windows.go                     |   50 +-
 src/syscall/tables_nacl.go                         |   39 +-
 src/syscall/types_linux.go                         |  116 +-
 src/syscall/types_plan9.c                          |  115 -
 src/syscall/zerrors_darwin_386.go                  |    2 +
 src/syscall/zerrors_darwin_amd64.go                |    2 +
 src/syscall/zerrors_darwin_arm.go                  | 1351 ++++++
 src/syscall/zerrors_darwin_arm64.go                | 1436 ++++++
 src/syscall/zerrors_dragonfly_386.go               | 1526 ------
 src/syscall/zerrors_dragonfly_amd64.go             |    2 +
 src/syscall/zerrors_freebsd_386.go                 |    2 +
 src/syscall/zerrors_freebsd_amd64.go               |    2 +
 src/syscall/zerrors_freebsd_arm.go                 |    2 +
 src/syscall/zerrors_linux_386.go                   |    2 +
 src/syscall/zerrors_linux_amd64.go                 |    2 +
 src/syscall/zerrors_linux_arm.go                   |    2 +
 src/syscall/zerrors_linux_arm64.go                 | 1824 +++++++
 src/syscall/zerrors_linux_ppc64.go                 | 1880 +++++++
 src/syscall/zerrors_linux_ppc64le.go               | 1904 ++++++++
 src/syscall/zerrors_netbsd_386.go                  |    2 +
 src/syscall/zerrors_netbsd_amd64.go                |    2 +
 src/syscall/zerrors_netbsd_arm.go                  |    2 +
 src/syscall/zerrors_openbsd_386.go                 |    2 +
 src/syscall/zerrors_openbsd_amd64.go               |    2 +
 src/syscall/zerrors_openbsd_arm.go                 | 1584 ++++++
 src/syscall/zerrors_plan9_amd64.go                 |   48 -
 src/syscall/zerrors_solaris_amd64.go               |    2 +
 src/syscall/zsyscall_darwin_386.go                 |  212 +-
 src/syscall/zsyscall_darwin_amd64.go               |  212 +-
 src/syscall/zsyscall_darwin_arm.go                 | 1421 ++++++
 src/syscall/zsyscall_darwin_arm64.go               | 1421 ++++++
 src/syscall/zsyscall_dragonfly_386.go              | 1317 -----
 src/syscall/zsyscall_dragonfly_amd64.go            |  198 +-
 src/syscall/zsyscall_freebsd_386.go                |  200 +-
 src/syscall/zsyscall_freebsd_amd64.go              |  200 +-
 src/syscall/zsyscall_freebsd_arm.go                |  200 +-
 src/syscall/zsyscall_linux_386.go                  |  572 +--
 src/syscall/zsyscall_linux_amd64.go                |  608 +--
 src/syscall/zsyscall_linux_arm.go                  |  590 +--
 src/syscall/zsyscall_linux_arm64.go                | 1725 +++++++
 src/syscall/zsyscall_linux_ppc64.go                | 1798 +++++++
 src/syscall/zsyscall_linux_ppc64le.go              | 1798 +++++++
 src/syscall/zsyscall_nacl_386.go                   |   28 +-
 src/syscall/zsyscall_nacl_amd64p32.go              |   28 +-
 src/syscall/zsyscall_nacl_arm.go                   |   28 +-
 src/syscall/zsyscall_netbsd_386.go                 |  190 +-
 src/syscall/zsyscall_netbsd_amd64.go               |  190 +-
 src/syscall/zsyscall_netbsd_arm.go                 |  190 +-
 src/syscall/zsyscall_openbsd_386.go                |  196 +-
 src/syscall/zsyscall_openbsd_amd64.go              |  196 +-
 src/syscall/zsyscall_openbsd_arm.go                | 1293 +++++
 src/syscall/zsyscall_plan9_386.go                  |  160 +-
 src/syscall/zsyscall_plan9_amd64.go                |  160 +-
 src/syscall/zsyscall_solaris_amd64.go              |  645 ++-
 src/syscall/zsyscall_windows.go                    |    7 +-
 src/syscall/zsysnum_darwin_386.go                  |    2 +
 src/syscall/zsysnum_darwin_amd64.go                |    2 +
 src/syscall/zsysnum_darwin_arm.go                  |  347 ++
 src/syscall/zsysnum_darwin_arm64.go                |  358 ++
 src/syscall/zsysnum_dragonfly_386.go               |  302 --
 src/syscall/zsysnum_dragonfly_amd64.go             |    2 +
 src/syscall/zsysnum_freebsd_386.go                 |    2 +
 src/syscall/zsysnum_freebsd_amd64.go               |    2 +
 src/syscall/zsysnum_freebsd_arm.go                 |    2 +
 src/syscall/zsysnum_linux_386.go                   |    2 +
 src/syscall/zsysnum_linux_amd64.go                 |    2 +
 src/syscall/zsysnum_linux_arm.go                   |    2 +
 src/syscall/zsysnum_linux_arm64.go                 |  277 ++
 src/syscall/zsysnum_linux_ppc64.go                 |  353 ++
 src/syscall/zsysnum_linux_ppc64le.go               |  353 ++
 src/syscall/zsysnum_netbsd_386.go                  |    2 +
 src/syscall/zsysnum_netbsd_amd64.go                |    2 +
 src/syscall/zsysnum_netbsd_arm.go                  |    2 +
 src/syscall/zsysnum_openbsd_386.go                 |    2 +
 src/syscall/zsysnum_openbsd_amd64.go               |    2 +
 src/syscall/zsysnum_openbsd_arm.go                 |  213 +
 .../{zsysnum_plan9_386.go => zsysnum_plan9.go}     |    0
 src/syscall/zsysnum_plan9_amd64.go                 |   49 -
 src/syscall/zsysnum_solaris_amd64.go               |    2 +
 src/syscall/ztypes_darwin_386.go                   |    2 +
 src/syscall/ztypes_darwin_amd64.go                 |    2 +
 src/syscall/ztypes_darwin_arm.go                   |  449 ++
 src/syscall/ztypes_darwin_arm64.go                 |  458 ++
 src/syscall/ztypes_dragonfly_386.go                |  435 --
 src/syscall/ztypes_dragonfly_amd64.go              |    2 +
 src/syscall/ztypes_freebsd_386.go                  |    2 +
 src/syscall/ztypes_freebsd_amd64.go                |    2 +
 src/syscall/ztypes_freebsd_arm.go                  |    2 +
 src/syscall/ztypes_linux_386.go                    |    6 +-
 src/syscall/ztypes_linux_amd64.go                  |    6 +-
 src/syscall/ztypes_linux_arm.go                    |    6 +-
 src/syscall/ztypes_linux_arm64.go                  |  596 +++
 src/syscall/ztypes_linux_ppc64.go                  |  606 +++
 src/syscall/ztypes_linux_ppc64le.go                |  606 +++
 src/syscall/ztypes_netbsd_386.go                   |    2 +
 src/syscall/ztypes_netbsd_amd64.go                 |    2 +
 src/syscall/ztypes_netbsd_arm.go                   |    2 +
 src/syscall/ztypes_openbsd_386.go                  |    2 +
 src/syscall/ztypes_openbsd_amd64.go                |    2 +
 src/syscall/ztypes_openbsd_arm.go                  |  434 ++
 src/syscall/ztypes_plan9_386.go                    |   75 -
 src/syscall/ztypes_plan9_amd64.go                  |   75 -
 src/syscall/ztypes_solaris_amd64.go                |    2 +
 src/syscall/ztypes_windows.go                      |   25 +-
 src/testing/benchmark.go                           |   34 +-
 src/testing/example.go                             |    6 +-
 src/testing/iotest/logger.go                       |    2 +-
 src/testing/quick/quick.go                         |   26 +-
 src/testing/quick/quick_test.go                    |   47 +-
 src/testing/testing.go                             |   58 +-
 src/text/scanner/example_test.go                   |   38 +
 src/text/scanner/scanner.go                        |   23 +-
 src/text/scanner/scanner_test.go                   |   49 +
 src/text/template/doc.go                           |    4 +-
 src/text/template/exec.go                          |   77 +-
 src/text/template/exec_test.go                     |  101 +-
 src/text/template/funcs.go                         |    4 +-
 src/text/template/helper.go                        |   11 +-
 src/text/template/multi_test.go                    |   73 +
 src/text/template/option.go                        |   74 +
 src/text/template/parse/lex.go                     |   13 +-
 src/text/template/parse/lex_test.go                |   57 +-
 src/text/template/parse/node.go                    |   15 +-
 src/text/template/parse/parse.go                   |   35 +-
 src/text/template/parse/parse_test.go              |   31 +-
 src/text/template/template.go                      |   84 +-
 src/time/example_test.go                           |  124 +-
 src/time/export_windows_test.go                    |    4 +
 src/time/format.go                                 |  225 +-
 src/time/sleep_test.go                             |   41 +-
 src/time/sys_unix.go                               |    2 +
 src/time/tick.go                                   |    4 +-
 src/time/time.go                                   |    2 +
 src/time/time_test.go                              |   25 +-
 src/time/zoneinfo_ios.go                           |   51 +
 src/time/zoneinfo_plan9.go                         |   10 +-
 src/time/zoneinfo_unix.go                          |    8 +-
 src/time/zoneinfo_windows.go                       |   63 +-
 src/time/zoneinfo_windows_test.go                  |   25 +
 src/unicode/graphic.go                             |    2 +-
 src/unicode/letter_test.go                         |   14 +
 src/unicode/maketables.go                          |    7 +-
 src/unicode/script_test.go                         |   10 +-
 src/unicode/tables.go                              |  524 +-
 src/unicode/utf16/utf16.go                         |    2 +-
 src/unsafe/unsafe.go                               |   22 +-
 .../shootout/{fasta-1000.out => fasta-1000.txt}    |    0
 test/bench/shootout/timing.sh                      |   68 +-
 test/bugs/bug395.go                                |    7 +-
 test/chan/select5.go                               |    2 +-
 test/chanlinear.go                                 |   94 +
 test/clearfat.go                                   |   68 +
 test/closure1.go                                   |   19 +
 test/closure2.go                                   |  118 +
 test/cmp.go                                        |    2 +-
 test/cmplxdivide.c                                 |   13 +-
 test/cmplxdivide.go                                |    1 +
 test/complit1.go                                   |   14 +
 test/const4.go                                     |    2 +-
 test/const5.go                                     |    2 +-
 test/convlit.go                                    |    7 +
 test/errchk                                        |    2 +-
 test/escape2.go                                    | 1048 ++--
 test/escape2n.go                                   | 1048 ++--
 test/escape4.go                                    |    8 +-
 test/escape5.go                                    |   10 +-
 test/escape_array.go                               |  122 +
 test/escape_calls.go                               |   54 +
 test/escape_closure.go                             |  147 +
 test/escape_field.go                               |  174 +
 test/escape_iface.go                               |  227 +
 test/escape_indir.go                               |  160 +
 test/escape_level.go                               |  108 +
 test/escape_map.go                                 |  107 +
 test/escape_param.go                               |  353 ++
 test/escape_slice.go                               |  165 +
 test/escape_struct_param1.go                       |  298 ++
 test/escape_struct_param2.go                       |  298 ++
 test/escape_struct_return.go                       |   74 +
 test/fibo.go                                       |  310 ++
 test/fixedbugs/bug121.go                           |    1 -
 test/fixedbugs/bug214.go                           |    2 +-
 test/fixedbugs/bug215.go                           |    2 +-
 test/fixedbugs/bug216.go                           |    2 +-
 test/fixedbugs/bug217.go                           |    2 +-
 test/fixedbugs/bug218.go                           |    2 +-
 test/fixedbugs/bug221.go                           |    2 +-
 test/fixedbugs/bug248.go                           |   58 +-
 test/fixedbugs/bug264.go                           |    2 +-
 test/fixedbugs/bug265.go                           |    2 +-
 test/fixedbugs/bug269.go                           |    2 +-
 test/fixedbugs/bug271.go                           |    2 +-
 test/fixedbugs/bug272.go                           |    2 +-
 test/fixedbugs/bug273.go                           |    2 +-
 test/fixedbugs/bug274.go                           |    2 +-
 test/fixedbugs/bug279.go                           |    2 +-
 test/fixedbugs/bug280.go                           |    2 +-
 test/fixedbugs/bug281.go                           |    2 +-
 test/fixedbugs/bug283.go                           |    2 +-
 test/fixedbugs/bug285.go                           |    2 +-
 test/fixedbugs/bug290.go                           |    2 +-
 test/fixedbugs/bug291.go                           |    2 +-
 test/fixedbugs/bug292.go                           |    2 +-
 test/fixedbugs/bug293.go                           |    2 +-
 test/fixedbugs/bug294.go                           |    2 +-
 test/fixedbugs/bug301.go                           |    2 +-
 test/fixedbugs/bug302.dir/main.go                  |    4 +-
 test/fixedbugs/bug302.go                           |   32 +-
 test/fixedbugs/bug345.go                           |   45 +-
 test/fixedbugs/bug346.go                           |   27 +-
 test/fixedbugs/bug369.dir/main.go                  |   54 +
 test/fixedbugs/bug369.go                           |   70 +-
 test/fixedbugs/bug425.go                           |    2 +-
 test/fixedbugs/bug427.go                           |    2 +-
 test/fixedbugs/bug429.go                           |    6 +-
 test/fixedbugs/bug429_run.go                       |   34 +
 test/fixedbugs/bug435.go                           |    2 +-
 test/fixedbugs/bug492.dir/a.go                     |   16 +
 test/fixedbugs/bug492.dir/b.go                     |   11 +
 test/fixedbugs/bug492.go                           |    9 +
 test/fixedbugs/bug493.go                           |   15 +
 test/fixedbugs/bug494.go                           |   51 +
 test/fixedbugs/bug495.go                           |   20 +
 test/fixedbugs/gcc61204.go                         |   17 +
 test/fixedbugs/gcc61244.go                         |   19 +
 test/fixedbugs/gcc61246.go                         |   17 +
 test/fixedbugs/gcc61248.go                         |   14 +
 test/fixedbugs/gcc61253.go                         |   20 +
 test/fixedbugs/gcc61254.go                         |   13 +
 test/fixedbugs/gcc61255.go                         |   13 +
 test/fixedbugs/gcc61258.go                         |   13 +
 test/fixedbugs/gcc61264.go                         |   13 +
 test/fixedbugs/gcc61265.go                         |   16 +
 test/fixedbugs/gcc61273.go                         |   16 +
 test/fixedbugs/gcc65755.go                         |   37 +
 test/fixedbugs/issue10047.go                       |   19 +
 test/fixedbugs/issue10066.dir/a.go                 |   11 +
 test/fixedbugs/issue10066.dir/b.go                 |    7 +
 test/fixedbugs/issue10066.go                       |   10 +
 test/fixedbugs/issue10219.dir/a.go                 |   24 +
 test/fixedbugs/issue10219.dir/b.go                 |   11 +
 test/fixedbugs/issue10219.dir/c.go                 |   12 +
 test/fixedbugs/issue10219.go                       |   10 +
 test/fixedbugs/issue10253.go                       |   26 +
 test/fixedbugs/issue10284.go                       |   16 +
 test/fixedbugs/issue10320.go                       |   55 +
 test/fixedbugs/issue10332.go                       |   25 +
 test/fixedbugs/issue10353.go                       |   49 +
 test/fixedbugs/issue10407.go                       |   16 +
 test/fixedbugs/issue10441.go                       |   17 +
 test/fixedbugs/issue10486.go                       |   31 +
 test/fixedbugs/issue10607.go                       |   31 +
 test/fixedbugs/issue10607a.go                      |   81 +
 test/fixedbugs/issue10654.go                       |   17 +
 test/fixedbugs/issue10700.dir/other.go             |   10 +
 test/fixedbugs/issue10700.dir/test.go              |   49 +
 test/fixedbugs/issue10700.go                       |    7 +
 test/fixedbugs/issue10925.go                       |   23 +
 test/fixedbugs/issue10977.go                       |   20 +
 test/fixedbugs/issue11053.dir/p.go                 |    9 +
 test/fixedbugs/issue11053.dir/p_test.go            |   51 +
 test/fixedbugs/issue11053.go                       |   10 +
 test/fixedbugs/issue11053.out                      |    3 +
 test/fixedbugs/issue11256.go                       |   53 +
 test/fixedbugs/issue11286.go                       |   34 +
 test/fixedbugs/issue11326.go                       |   28 +
 test/fixedbugs/issue11326b.go                      |   44 +
 test/fixedbugs/issue11369.go                       |   27 +
 test/fixedbugs/issue11656.go                       |   62 +
 test/fixedbugs/issue11750.go                       |   20 +
 test/fixedbugs/issue11771.go                       |   64 +
 test/fixedbugs/issue11790.go                       |   36 +
 test/fixedbugs/issue12133.go                       |   26 +
 test/fixedbugs/issue12226.go                       |   15 +
 test/fixedbugs/issue3924.go                        |   13 -
 test/fixedbugs/issue4365.go                        |   27 +
 test/fixedbugs/issue5373.go                        |   71 +
 test/fixedbugs/issue6671.go                        |   28 +
 test/fixedbugs/issue6866.go                        |   80 +
 test/fixedbugs/issue6889.go                        |   10 +-
 test/fixedbugs/issue6964.go                        |    2 +-
 test/fixedbugs/issue7740.go                        |   35 +
 test/fixedbugs/issue7746.go                        |  133 +
 test/fixedbugs/issue8154.go                        |   14 +
 test/fixedbugs/issue8183.go                        |   23 +
 test/fixedbugs/issue8385.go                        |   42 +
 test/fixedbugs/issue8501.go                        |   18 +
 test/fixedbugs/issue8620.go                        |   30 +
 test/fixedbugs/issue8745.go                        |   13 +
 test/fixedbugs/issue8836.go                        |   24 +
 test/fixedbugs/issue9017.go                        |   57 +
 test/fixedbugs/issue9036.go                        |   29 +
 test/fixedbugs/issue9076.go                        |   15 +
 test/fixedbugs/issue9083.go                        |   22 +
 test/fixedbugs/issue9110.go                        |    1 +
 test/fixedbugs/issue9321.go                        |    6 +-
 test/fixedbugs/issue9355.dir/a.go                  |   16 +
 test/fixedbugs/issue9355.go                        |   59 +
 test/fixedbugs/issue9370.go                        |  127 +
 test/fixedbugs/issue9521.go                        |   18 +
 test/fixedbugs/issue9604b.go                       |  177 +
 test/fixedbugs/issue9608.dir/issue9608.go          |   73 +
 test/fixedbugs/issue9608.go                        |   14 +
 test/fixedbugs/issue9691.go                        |   21 +
 test/fixedbugs/issue9731.go                        |   21 +
 test/fixedbugs/issue9738.go                        |   20 +
 test/fixedbugs/issue9862.go                        |   15 +
 test/fixedbugs/issue9862_run.go                    |   27 +
 test/func6.go                                      |    2 +-
 test/func7.go                                      |    2 +-
 test/gc2.go                                        |    3 +-
 test/golden.out                                    |   24 -
 test/index.go                                      |    2 +-
 test/init1.go                                      |   26 +-
 test/inline.go                                     |   24 +
 test/interface/assertinline.go                     |   53 +
 test/interface/embed2.go                           |   23 +-
 test/linkx.go                                      |    9 +-
 test/linkx_run.go                                  |   45 +-
 test/live.go                                       |  203 +-
 test/live2.go                                      |   10 +-
 test/nilcheck.go                                   |    5 +
 test/nilptr3.go                                    |    3 +
 test/nosplit.go                                    |   51 +-
 test/recover4.go                                   |   73 +
 test/run                                           |  138 -
 test/run.go                                        |  185 +-
 test/sinit.go                                      |    5 +
 test/sinit_run.go                                  |   11 +-
 test/sliceopt.go                                   |   59 +
 test/testlib                                       |  170 -
 test/writebarrier.go                               |  146 +
 2846 files changed, 355095 insertions(+), 260409 deletions(-)

diff --git a/AUTHORS b/AUTHORS
index 46fd9fd..54a10ad 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -8,12 +8,15 @@
 
 # Please keep the list sorted.
 
+A Medium Corporation
+Aamir Khan <syst3m.w0rm at gmail.com>
 Aaron France <aaron.l.france at gmail.com>
 Abhinav Gupta <abhinav.g90 at gmail.com>
 Adrian Nos <nos.adrian at gmail.com>
 Adrian O'Grady <elpollouk at gmail.com>
 Adrien Bustany <adrien-xx-google at bustany.org>
 Ahmed Waheed Moanes <oneofone at gmail.com>
+Ainar Garipov <gugl.zadolbal at gmail.com>
 Akshat Kumar <seed at mail.nanosouffle.net>
 Alan Shreve <alan at inconshreveable.com>
 Albert Strasheim <fullung at gmail.com>
@@ -23,21 +26,29 @@ Aleksandar Dezelin <dezelin at gmail.com>
 Alex A Skinner <alex at lx.lc>
 Alex Brainman <alex.brainman at gmail.com>
 Alex Jin <toalexjin at gmail.com>
+Alex Plugaru <alex at plugaru.org> <alexandru.plugaru at gmail.com>
+Alex Schroeder <alex at gnu.org>
+Alex Sergeyev <abc at alexsergeyev.com>
 Alexander Larsson <alexander.larsson at gmail.com>
+Alexander Morozov <lk4d4math at gmail.com>
 Alexander Orlov <alexander.orlov at loxal.net>
 Alexander Reece <awreece at gmail.com>
 Alexander Surma <surma at surmair.de>
 Alexander Zhavnerchik <alex.vizor at gmail.com>
+Alexander Zolotov <goldifit at gmail.com>
+Alexandre Cesaro <alexandre.cesaro at gmail.com>
 Alexandre Normand <alexandre.normand at gmail.com>
 Alexei Sholik <alcosholik at gmail.com>
 Alexey Borzenkov <snaury at gmail.com>
 Alexey Palazhchenko <alexey.palazhchenko at gmail.com>
 Amir Mohammad Saied <amir at gluegadget.com>
 Amrut Joshi <amrut.joshi at gmail.com>
+Andrei Korzhevskii <a.korzhevskiy at gmail.com>
 Andrei Vieru <euvieru at gmail.com>
 Andrew Balholm <andybalholm at gmail.com>
 Andrew Bonventre <andybons at chromium.org>
 Andrew Bursavich <abursavich at gmail.com>
+Andrew Ekstedt <andrew.ekstedt at gmail.com>
 Andrew Harding <andrew at spacemonkey.com>
 Andrew Lutomirski <andy at luto.us>
 Andrew Pritchard <awpritchard at gmail.com>
@@ -45,9 +56,12 @@ Andrew Radev <andrey.radev at gmail.com>
 Andrew Skiba <skibaa at gmail.com>
 Andrew Szeto <andrew at jabagawee.com>
 Andrew Wilkins <axwalk at gmail.com>
+Andrew Williams <williams.andrew at gmail.com>
 Andrey Mirtchovski <mirtchovski at gmail.com>
+Andrey Petrov <andrey.petrov at shazow.net>
 Andriy Lytvynov <lytvynov.a.v at gmail.com>
 Andy Davis <andy at bigandian.com>
+Andy Maloney <asmaloney at gmail.com>
 Anfernee Yongkun Gui <anfernee.gui at gmail.com>
 Anh Hai Trinh <anh.hai.trinh at gmail.com>
 Anschel Schaffer-Cohen <anschelsc at gmail.com>
@@ -56,12 +70,16 @@ Anthony Martin <ality at pbrane.org>
 Anthony Starks <ajstarks at gmail.com>
 Apisak Darakananda <pongad at gmail.com>
 Aram Hăvărneanu <aram at mgk.ro>
+Areski Belaid <areski at gmail.com>
 Arnaud Ysmal <arnaud.ysmal at gmail.com>
 Arne Hormann <arnehormann at gmail.com>
 Aron Nopanen <aron.nopanen at gmail.com>
 Arvindh Rajesh Tamilmani <art at a-30.net>
 Ato Araki <ato.araki at gmail.com>
 Aulus Egnatius Varialus <varialus at gmail.com>
+awaw fumin <awawfumin at gmail.com>
+Aymerick Jéhanne <aymerick at jehanne.org>
+Ben Burkert <ben at benburkert.com>
 Ben Olive <sionide21 at gmail.com>
 Benjamin Black <b at b3k.us>
 Benny Siegert <bsiegert at gmail.com>
@@ -70,17 +88,22 @@ Berengar Lehr <berengar.lehr at gmx.de>
 Billie Harold Cleek <bhcleek at gmail.com>
 Bjorn Tillenius <bjorn at tillenius.me>
 Bjorn Tipling <bjorn.tipling at gmail.com>
+Blake Gentry <blakesgentry at gmail.com>
 Blake Mizerany <blake.mizerany at gmail.com>
 Bobby Powers <bobbypowers at gmail.com>
 Brendan Daniel Tracey <tracey.brendan at gmail.com>
+Brett Cannon <bcannon at gmail.com>
 Brian Dellisanti <briandellisanti at gmail.com>
 Brian G. Merrell <bgmerrell at gmail.com>
-Brian Gitonga Marete <marete at toshnix.com>
+Brian Gitonga Marete <marete at toshnix.com> <bgmarete at gmail.com>
 Brian Ketelsen <bketelsen at gmail.com>
+Brian Smith <ohohvi at gmail.com>
+Bryan Ford <brynosaurus at gmail.com>
 Caine Tighe <arctanofyourface at gmail.com>
 Caleb Spare <cespare at gmail.com>
 Carl Chatfield <carlchatfield at gmail.com>
 Carlos Castillo <cookieo9 at gmail.com>
+Carlos Cirello <uldericofilho at gmail.com>
 Case Nelson <case.nelson at gmail.com>
 Casey Marshall <casey.marshall at gmail.com>
 Cezar Sá Espinola <cezarsa at gmail.com>
@@ -91,6 +114,7 @@ Chris Dollin <ehog.hedge at gmail.com>
 Chris Farmiloe <chrisfarms at gmail.com>
 Chris Howey <howeyc at gmail.com>
 Chris Jones <chris at cjones.org>
+Chris Kastorff <encryptio at gmail.com>
 Chris Lennert <calennert at gmail.com>
 Chris McGee <sirnewton_01 at yahoo.ca> <newton688 at gmail.com>
 Christian Himpel <chressie at googlemail.com>
@@ -98,10 +122,13 @@ Christine Hansmann <chhansmann at gmail.com>
 Christoffer Buchholz <christoffer.buchholz at gmail.com>
 Christoph Hack <christoph at tux21b.org>
 Christopher Cahoon <chris.cahoon at gmail.com>
+Christopher Guiney <chris at guiney.net>
 Christopher Nielsen <m4dh4tt3r at gmail.com>
 Christopher Redden <christopher.redden at gmail.com>
 Christopher Wedgwood <cw at f00f.org>
 Clement Skau <clementskau at gmail.com>
+CloudFlare Inc.
+Colin Kennedy <moshen.colin at gmail.com>
 Conrad Meyer <cemeyer at cs.washington.edu>
 Corey Thomasson <cthom.lists at gmail.com>
 Cristian Staretu <unclejacksons at gmail.com>
@@ -125,21 +152,26 @@ David Jakob Fritz <david.jakob.fritz at gmail.com>
 David Leon Gil <coruus at gmail.com>
 David Thomas <davidthomas426 at gmail.com>
 David Titarenco <david.titarenco at gmail.com>
+Davies Liu <davies.liu at gmail.com>
 Dean Prichard <dean.prichard at gmail.com>
 Denis Brandolini <denis.brandolini at gmail.com>
+Derek Buitenhuis <derek.buitenhuis at gmail.com>
 Derek Parker <parkerderek86 at gmail.com>
 Devon H. O'Dell <devon.odell at gmail.com>
 Dhiru Kholia <dhiru.kholia at gmail.com>
+Didier Spezia <didier.06 at gmail.com>
 Dimitri Tcaciuc <dtcaciuc at gmail.com>
 Dmitri Shuralyov <shurcooL at gmail.com>
 Dmitriy Shelenin <deemok at googlemail.com> <deemok at gmail.com>
 Dmitry Chestnykh <dchest at gmail.com>
+Dmitry Savintsev <dsavints at gmail.com>
 Dominik Honnef <dominik.honnef at gmail.com>
 Donovan Hide <donovanhide at gmail.com>
 Dropbox, Inc.
 Duncan Holm <mail at frou.org>
 Dustin Sallings <dsallings at gmail.com>
 Dustin Shields-Cloues <dcloues at gmail.com>
+Dvir Volk <dvir at everything.me> <dvirsky at gmail.com>
 Eden Li <eden.li at gmail.com>
 Egon Elbre <egonelbre at gmail.com>
 Ehren Kret <ehren.kret at gmail.com>
@@ -150,9 +182,11 @@ Eoghan Sherry <ejsherry at gmail.com>
 Eric Clark <zerohp at gmail.com>
 Eric Milliken <emilliken at gmail.com>
 Eric Roshan-Eisner <eric.d.eisner at gmail.com>
+Erik Aigner <aigner.erik at gmail.com>
 Erik St. Martin <alakriti at gmail.com>
 Erik Westrup <erik.westrup at gmail.com>
 Esko Luontola <esko.luontola at gmail.com>
+Evan Phoenix <evan at phx.io>
 Evan Shaw <chickencha at gmail.com>
 Ewan Chou <coocood at gmail.com>
 Fabrizio Milo <mistobaan at gmail.com>
@@ -164,6 +198,7 @@ Felix Geisendörfer <haimuiba at gmail.com>
 Firmansyah Adiputra <frm.adiputra at gmail.com>
 Florian Uekermann <florian at uekermann-online.de>
 Florian Weimer <fw at deneb.enyo.de>
+Florin Patan <florinpatan at gmail.com>
 Francisco Souza <franciscossouza at gmail.com>
 Frederick Kelly Mayle III <frederickmayle at gmail.com>
 Fredrik Enestad <fredrik.enestad at soundtrackyourbrand.com>
@@ -171,29 +206,44 @@ Frithjof Schulze <schulze at math.uni-hannover.de> <sfrithjof at gmail.com>
 Gabriel Aszalos <gabriel.aszalos at gmail.com>
 Gary Burd <gary at beagledreams.com>
 Gautham Thambidorai <gautham.dorai at gmail.com>
+Geert-Johan Riemer <gjr19912 at gmail.com>
 Georg Reinke <guelfey at gmail.com>
+George Shammas <george at shamm.as> <georgyo at gmail.com>
 Gerasimos Dimitriadis <gedimitr at gmail.com>
 Gideon Jan-Wessel Redelinghuys <gjredelinghuys at gmail.com>
 Giles Lean <giles.lean at pobox.com>
+Giulio Iotti <dullgiulio at gmail.com>
 Google Inc.
 Gordon Klaus <gordon.klaus at gmail.com>
 Graham King <graham4king at gmail.com>
 Graham Miller <graham.miller at gmail.com>
 Greg Ward <greg at gerg.ca>
 Guillaume J. Charmes <guillaume at charmes.net>
+Guobiao Mei <meiguobiao at gmail.com>
 Gustav Paul <gustav.paul at gmail.com>
 Gustavo Niemeyer <gustavo at niemeyer.net>
 Gwenael Treguier <gwenn.kahz at gmail.com>
+Hajime Hoshi <hajimehoshi at gmail.com>
+Hari haran <hariharan.uno at gmail.com>
+Hariharan Srinath <srinathh at gmail.com>
 Harley Laue <losinggeneration at gmail.com>
+Håvard Haugen <havard.haugen at gmail.com>
 Hector Chu <hectorchu at gmail.com>
 Hector Martin Cantero <hector at marcansoft.com>
 Henning Schmiedehausen <henning at schmiedehausen.org>
 Henrik Edwards <henrik.edwards at gmail.com>
 Herbert Georg Fischer <herbert.fischer at gmail.com>
 Hong Ruiqi <hongruiqi at gmail.com>
+IBM
 Icarus Sparry <golang at icarus.freeuk.com>
+Igneous Systems, Inc.
+Igor Dolzhikov <bluesriverz at gmail.com>
+INADA Naoki <songofacandy at gmail.com>
+Ingo Krabbe <ikrabbe.ask at gmail.com>
 Ingo Oeser <nightlyone at googlemail.com>
 Isaac Wagner <ibw at isaacwagner.me>
+Ivan Ukhov <ivan.ukhov at gmail.com>
+Jae Kwon <jae at tendermint.com>
 Jakob Borg <jakob at nym.se>
 Jakub Ryszard Czarnowicz <j.czarnowicz at gmail.com>
 James David Chalfant <james.chalfant at gmail.com>
@@ -222,14 +272,18 @@ Jeremy Jackins <jeremyjackins at gmail.com>
 Jim McGrath <jimmc2 at gmail.com>
 Jimmy Zelinskie <jimmyzelinskie at gmail.com>
 Jingcheng Zhang <diogin at gmail.com>
+Jiong Du <londevil at gmail.com>
 Joakim Sernbrant <serbaut at gmail.com>
+Joe Harrison <joehazzers at gmail.com>
 Joe Poirier <jdpoirier at gmail.com>
 Joe Shaw <joe at joeshaw.org>
+Joe Tsai <joetsai at digital-static.net>
 Joel Stemmer <stemmertech at gmail.com>
 John Asmuth <jasmuth at gmail.com>
 John C Barstow <jbowtie at amathaine.com>
 John Graham-Cumming <jgc at jgc.org> <jgrahamc at gmail.com>
 John Howard Palevich <jack.palevich at gmail.com>
+John Potocny <johnp at vividcortex.com>
 John Shahid <jvshahid at gmail.com>
 John Tuley <john at tuley.org>
 Jonathan Gold <jgold.bg at gmail.com>
@@ -247,8 +301,11 @@ JT Olds <jtolds at xnet5.com>
 Jukka-Pekka Kekkonen <karatepekka at gmail.com>
 Julian Phillips <julian at quantumfyre.co.uk>
 Julien Schmidt <google at julienschmidt.com>
+Justin Nuß <nuss.justin at gmail.com>
 Kai Backman <kaib at golang.org>
 Kamil Kisiel <kamil at kamilkisiel.net> <kamil.kisiel at gmail.com>
+Kang Hu <hukangustc at gmail.com>
+Kato Kazuyoshi <kato.kazuyoshi at gmail.com>
 Katrina Owen <katrina.owen at gmail.com>
 Kei Son <hey.calmdown at gmail.com>
 Keith Rarick <kr at xph.us>
@@ -257,12 +314,16 @@ Kelvin Foo Chuan Lyi <vmirage at gmail.com>
 Ken Friedenbach <kenliz at cruzio.com>
 Ken Rockot <ken at oz.gs>
 Kevin Ballard <kevin at sb.org>
+Konstantin Shaposhnikov <k.shaposhnikov at gmail.com>
 Kyle Consalus <consalus at gmail.com>
 Kyle Isom <kyle at gokyle.net>
 Kyle Lemons <kyle at kylelemons.net>
 L Campbell <unpantsu at gmail.com>
 Lai Jiangshan <eag0628 at gmail.com>
+Larz Conwell <larzconwell at gmail.com>
+Lee Packham <lpackham at gmail.com>
 Linaro Limited
+Lloyd Dewolf <foolswisdom at gmail.com>
 Lorenzo Stoakes <lstoakes at gmail.com>
 Luca Greco <luca.greco at alcacoop.it>
 Lucio De Re <lucio.dere at gmail.com>
@@ -272,6 +333,7 @@ Luke Curley <qpingu at gmail.com>
 Manuel Mendez <mmendez534 at gmail.com>
 Marc Weistroff <marc at weistroff.net>
 Marco Hennings <marco.hennings at freiheit.com>
+Mark Bucciarelli <mkbucc at gmail.com>
 Mark Theunissen <mark.theunissen at gmail.com>
 Marko Juhani Silokunnas <marko.silokunnas at gmail.com>
 Marko Tiikkaja <marko at joh.to>
@@ -279,29 +341,41 @@ Markover Inc. DBA Poptip
 Markus Duft <markus.duft at salomon.at>
 Markus Sonderegger <marraison at gmail.com>
 Markus Zimmermann <zimmski at gmail.com>
+Martin Möhrmann <martisch at uos.de>
 Martin Neubauer <m.ne at gmx.net>
 Martin Olsson <martin at minimum.se>
 Mateusz Czapliński <czapkofan at gmail.com>
+Mathias Beke <git at denbeke.be>
 Mathieu Lonjaret <mathieu.lonjaret at gmail.com>
 Mats Lidell <mats.lidell at cag.se>
 Matt Aimonetti <mattaimonetti at gmail.com>
+Matt Bostock <matt at mattbostock.com>
 Matt Jibson <matt.jibson at gmail.com>
 Matt Joiner <anacrolix at gmail.com>
+Matt Layher <mdlayher at gmail.com>
 Matt Reiferson <mreiferson at gmail.com>
+Matt T. Proud <matt.proud at gmail.com>
+Matt Williams <gh at mattyw.net>
+Matthew Brennan <matty.brennan at gmail.com>
 Matthew Cottingham <mattcottingham at gmail.com>
+Matthew Holt <Matthew.Holt+git at gmail.com>
 Matthew Horsnell <matthew.horsnell at gmail.com>
 Maxim Khitrov <max at mxcrypt.com>
+Meir Fischer <meirfischer at gmail.com>
 Micah Stetson <micah.stetson at gmail.com>
 Michael Chaten <mchaten at gmail.com>
 Michael Elkins <michael.elkins at gmail.com>
 Michael Fraenkel <michael.fraenkel at gmail.com>
 Michael Gehring <mg at ebfe.org> <gnirheg.leahcim at gmail.com>
 Michael Hoisie <hoisie at gmail.com>
+Michael Käufl <golang at c.michael-kaeufl.de>
 Michael Lewis <mikelikespie at gmail.com>
 Michael MacInnis <Michael.P.MacInnis at gmail.com>
 Michael Pearson <mipearson at gmail.com>
+Michael Schaller <michael at 5challer.de>
 Michael Stapelberg <michael at stapelberg.de>
 Michael Teichgräber <mteichgraeber at gmx.de>
+Michael Vetter <g.bluehut at gmail.com>
 Michał Derkacz <ziutek at lnet.pl>
 Miek Gieben <miek at miek.nl>
 Mihai Borobocea <MihaiBorobocea at gmail.com>
@@ -319,6 +393,8 @@ Môshe van der Sterre <moshevds at gmail.com>
 Nan Deng <monnand at gmail.com>
 Nathan John Youngman <nj at nathany.com>
 Nathan P Finch <nate.finch at gmail.com>
+Nathan Youngman <git at nathany.com>
+Nevins Bartolomeo <nevins.bartolomeo at gmail.com>
 ngmoco, LLC
 Nicholas Katsaros <nick at nickkatsaros.com>
 Nicholas Presta <nick at nickpresta.ca> <nick1presta at gmail.com>
@@ -327,6 +403,7 @@ Nicholas Waples <nwaples at gmail.com>
 Nick Craig-Wood <nick at craig-wood.com> <nickcw at gmail.com>
 Nicolas Kaiser <nikai at nikai.net>
 Nicolas Owens <mischief at offblast.org>
+Nicolas S. Dade <nic.dade at gmail.com>
 Nigel Kerr <nigel.kerr at gmail.com>
 Noah Campbell <noahcampbell at gmail.com>
 Oling Cat <olingcat at gmail.com>
@@ -334,8 +411,11 @@ Oliver Hookins <ohookins at gmail.com>
 Olivier Antoine <olivier.antoine at gmail.com>
 Olivier Duperray <duperray.olivier at gmail.com>
 Olivier Saingre <osaingre at gmail.com>
+Oracle
 Padraig Kitterick <padraigkitterick at gmail.com>
+Palm Stone Games
 Paolo Giarrusso <p.giarrusso at gmail.com>
+Paolo Martini <mrtnpaolo at gmail.com>
 Pascal S. de Kloe <pascal at quies.net>
 Patrick Crosby <patrick at stathat.com>
 Patrick Gavlin <pgavlin at gmail.com>
@@ -347,6 +427,7 @@ Paul A Querna <paul.querna at gmail.com>
 Paul Hammond <paul at paulhammond.org>
 Paul Lalonde <paul.a.lalonde at gmail.com>
 Paul Sbarra <Sbarra.Paul at gmail.com>
+Paul Smith <paulsmith at pobox.com> <paulsmith at gmail.com>
 Paul van Brouwershaven <paul at vanbrouwershaven.com>
 Pavel Zinovkin <pavel.zinovkin at gmail.com>
 Percy Wegmann <ox.to.a.cart at gmail.com>
@@ -354,9 +435,11 @@ Petar Maymounkov <petarm at gmail.com>
 Peter Armitage <peter.armitage at gmail.com>
 Peter Froehlich <peter.hans.froehlich at gmail.com>
 Peter Kleiweg <pkleiweg at xs4all.nl>
+Peter Moody <pmoody at uber.com>
 Peter Mundy <go.peter.90 at gmail.com>
 Péter Surányi <speter.go1 at gmail.com>
 Péter Szilágyi <peterke at gmail.com>
+Peter Waldschmidt <peter at waldschmidt.com>
 Peter Waller <peter.waller at gmail.com>
 Peter Williams <pwil3058 at gmail.com>
 Philip K. Warren <pkwarren at gmail.com>
@@ -364,9 +447,12 @@ Pieter Droogendijk <pieter at binky.org.uk>
 Pietro Gagliardi <pietro10 at mac.com>
 Preetam Jinka <pj at preet.am>
 Quan Yong Zhai <qyzhai at gmail.com>
+Quoc-Viet Nguyen <afelion at gmail.com>
 Raif S. Naffah <go at naffah-raif.name>
+Rajat Goel <rajat.goel2010 at gmail.com>
 Red Hat, Inc.
 Rémy Oudompheng <oudomphe at phare.normalesup.org>
+Richard Barnes <rlb at ipv.sx>
 Richard Crowley <r at rcrowley.org>
 Richard Eric Gavaletz <gavaletz at gmail.com>
 Richard Musiol <mail at richard-musiol.de>
@@ -387,9 +473,11 @@ Ron Minnich <rminnich at gmail.com>
 Ross Light <rlight2 at gmail.com>
 Rowan Worth <sqweek at gmail.com>
 Ryan Hitchman <hitchmanr at gmail.com>
+Ryan Seys <ryan at ryanseys.com>
 Ryan Slade <ryanslade at gmail.com>
 S.Çağlar Onur <caglar at 10ur.org>
 Sanjay Menakuru <balasanjay at gmail.com>
+Scott Barron <scott.barron at github.com>
 Scott Ferguson <scottwferg at gmail.com>
 Scott Lawrence <bytbox at gmail.com>
 Sebastien Binet	<seb.binet at gmail.com>
@@ -401,21 +489,26 @@ Shane Hansen <shanemhansen at gmail.com>
 Shawn Smith <shawn.p.smith at gmail.com>
 Shenghou Ma <minux.ma at gmail.com>
 Shivakumar GN <shivakumar.gn at gmail.com>
+Silvan Jegen <s.jegen at gmail.com>
 Simon Whitehead <chemnova at gmail.com>
 Sokolov Yura <funny.falcon at gmail.com>
 Spring Mc <heresy.mc at gmail.com>
 StalkR <stalkr at stalkr.net>
+Stan Schwertly <stan at schwertly.com>
 Stefan Nilsson <snilsson at nada.kth.se> <trolleriprofessorn at gmail.com>
 Stéphane Travostino <stephane.travostino at gmail.com>
 Stephen McQuay <stephen at mcquay.me>
 Stephen Weinberg <stephen at q5comm.com>
 Steve McCoy <mccoyst at gmail.com>
+Steve Streeting <steve at stevestreeting.com>
 Steven Elliot Harris <seharris at gmail.com>
 Steven Hartland <steven.hartland at multiplay.co.uk>
+Stripe, Inc.
 Sven Almgren <sven at tras.se>
 Szabolcs Nagy <nsz at port70.net>
 Tad Glines <tad.glines at gmail.com>
 Taj Khattra <taj.khattra at gmail.com>
+Tamir Duberstein <tamird at gmail.com>
 Tarmigan Casebolt <tarmigan at gmail.com>
 Taru Karttunen <taruti at taruti.net>
 Tetsuo Kiso <tetsuokiso9 at gmail.com>
@@ -425,7 +518,10 @@ Thomas Kappler <tkappler at gmail.com>
 Timo Savola <timo.savola at gmail.com>
 Timo Truyts <alkaloid.btx at gmail.com>
 Tobias Columbus <tobias.columbus at gmail.com>
+Todd Neal <todd at tneal.org>
+Tom Heng <zhm20070928 at gmail.com>
 Tom Linford <tomlinford at gmail.com>
+Tommy Schaefer <tommy.schaefer at teecom.com>
 Tor Andersson <tor.andersson at gmail.com>
 Travis Cline <travis.cline at gmail.com>
 Tudor Golubenco <tudor.g at gmail.com>
@@ -436,6 +532,7 @@ Ulf Holm Nielsen <doktor at dyregod.dk>
 Uriel Mangado <uriel at berlinblue.org>
 Vadim Vygonets <unixdj at gmail.com>
 Vincent Ambo <tazjin at googlemail.com>
+Vincent Batts <vbatts at hashbangbash.com> <vbatts at gmail.com>
 Vincent Vanackere <vincent.vanackere at gmail.com>
 Vinu Rajashekhar <vinutheraj at gmail.com>
 Vladimir Nikishenko <vova616 at gmail.com>
@@ -448,6 +545,7 @@ Xia Bin <snyh at snyh.org>
 Xing Xing <mikespook at gmail.com>
 Yasuhiro Matsumoto <mattn.jp at gmail.com>
 Yissakhar Z. Beck <yissakhar.beck at gmail.com>
+Yo-An Lin <yoanlin93 at gmail.com>
 Yongjian Xu <i3dmaster at gmail.com>
 Yoshiyuki Kanno <nekotaroh at gmail.com> <yoshiyuki.kanno at stoic.co.jp>
 Yusuke Kagiwada <block.rxckin.beats at gmail.com>
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..712431c
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,33 @@
+# Contributing to Go
+
+Go is an open source project.
+
+It is the work of hundreds of contributors. We appreciate your help!
+
+
+## Filing issues
+
+When filing an issue, make sure to answer these five questions:
+
+1. What version of Go are you using (`go version`)?
+2. What operating system and processor architecture are you using?
+3. What did you do?
+4. What did you expect to see?
+5. What did you see instead?
+
+General questions should go to the [golang-nuts mailing list](https://groups.google.com/group/golang-nuts) instead of the issue tracker.
+The gophers there will answer or ask you to file an issue if you've tripped over a bug.
+
+Sensitive security-related issues should be reported to [security at golang.org](mailto:security at golang.org).
+
+## Contributing code
+
+Please read the [Contribution Guidelines](https://golang.org/doc/contribute.html)
+before sending patches.
+
+**We do not accept GitHub pull requests**
+(we use [Gerrit](https://code.google.com/p/gerrit/) instead for code review).
+
+Unless otherwise noted, the Go source files are distributed under
+the BSD-style license found in the LICENSE file.
+
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index b5e709e..d974f36 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -31,7 +31,9 @@
 
 # Please keep the list sorted.
 
+Aamir Khan <syst3m.w0rm at gmail.com>
 Aaron France <aaron.l.france at gmail.com>
+Aaron Jacobs <jacobsa at google.com>
 Aaron Kemp <kemp.aaron at gmail.com>
 Abhinav Gupta <abhinav.g90 at gmail.com>
 Adam Langley <agl at golang.org>
@@ -39,6 +41,7 @@ Adrian Nos <nos.adrian at gmail.com>
 Adrian O'Grady <elpollouk at gmail.com>
 Adrien Bustany <adrien-xx-google at bustany.org>
 Ahmed Waheed Moanes <oneofone at gmail.com>
+Ainar Garipov <gugl.zadolbal at gmail.com>
 Akshat Kumar <seed at mail.nanosouffle.net>
 Alan Donovan <adonovan at google.com>
 Alan Shreve <alan at inconshreveable.com>
@@ -50,11 +53,17 @@ Alex A Skinner <alex at lx.lc>
 Alex Brainman <alex.brainman at gmail.com>
 Alex Bramley <abramley at google.com>
 Alex Jin <toalexjin at gmail.com>
+Alex Plugaru <alex at plugaru.org> <alexandru.plugaru at gmail.com>
+Alex Schroeder <alex at gnu.org>
+Alex Sergeyev <abc at alexsergeyev.com>
 Alexander Larsson <alexander.larsson at gmail.com>
+Alexander Morozov <lk4d4math at gmail.com>
 Alexander Orlov <alexander.orlov at loxal.net>
 Alexander Reece <awreece at gmail.com>
 Alexander Surma <surma at surmair.de>
 Alexander Zhavnerchik <alex.vizor at gmail.com>
+Alexander Zolotov <goldifit at gmail.com>
+Alexandre Cesaro <alexandre.cesaro at gmail.com>
 Alexandre Normand <alexandre.normand at gmail.com>
 Alexandru Moșoi <brtzsnr at gmail.com>
 Alexei Sholik <alcosholik at gmail.com>
@@ -65,22 +74,28 @@ Amir Mohammad Saied <amir at gluegadget.com>
 Amrut Joshi <amrut.joshi at gmail.com>
 Andrea Spadaccini <spadaccio at google.com>
 Andreas Jellinghaus <andreas at ionisiert.de> <anj at google.com>
+Andrei Korzhevskii <a.korzhevskiy at gmail.com>
 Andrei Vieru <euvieru at gmail.com>
 Andres Erbsen <andreser at google.com>
 Andrew Balholm <andybalholm at gmail.com>
 Andrew Bonventre <andybons at chromium.org>
 Andrew Bursavich <abursavich at gmail.com>
+Andrew Ekstedt <andrew.ekstedt at gmail.com>
 Andrew Gerrand <adg at golang.org>
 Andrew Harding <andrew at spacemonkey.com>
 Andrew Lutomirski <andy at luto.us>
+Andrew Pilloud <andrewpilloud at igneoussystems.com>
 Andrew Pritchard <awpritchard at gmail.com>
 Andrew Radev <andrey.radev at gmail.com>
 Andrew Skiba <skibaa at gmail.com>
 Andrew Szeto <andrew at jabagawee.com>
 Andrew Wilkins <axwalk at gmail.com>
+Andrew Williams <williams.andrew at gmail.com>
 Andrey Mirtchovski <mirtchovski at gmail.com>
+Andrey Petrov <andrey.petrov at shazow.net>
 Andriy Lytvynov <lytvynov.a.v at gmail.com>
 Andy Davis <andy at bigandian.com>
+Andy Maloney <asmaloney at gmail.com>
 Anfernee Yongkun Gui <anfernee.gui at gmail.com>
 Anh Hai Trinh <anh.hai.trinh at gmail.com>
 Anschel Schaffer-Cohen <anschelsc at gmail.com>
@@ -89,6 +104,7 @@ Anthony Martin <ality at pbrane.org>
 Anthony Starks <ajstarks at gmail.com>
 Apisak Darakananda <pongad at gmail.com>
 Aram Hăvărneanu <aram at mgk.ro>
+Areski Belaid <areski at gmail.com>
 Arnaud Ysmal <arnaud.ysmal at gmail.com>
 Arne Hormann <arnehormann at gmail.com>
 Aron Nopanen <aron.nopanen at gmail.com>
@@ -97,7 +113,10 @@ Asim Shankar <asimshankar at gmail.com>
 Ato Araki <ato.araki at gmail.com>
 Aulus Egnatius Varialus <varialus at gmail.com>
 Austin Clements <austin at google.com> <aclements at csail.mit.edu>
+awaw fumin <awawfumin at gmail.com>
+Aymerick Jéhanne <aymerick at jehanne.org>
 Balazs Lecz <leczb at google.com>
+Ben Burkert <ben at benburkert.com>
 Ben Eitzen <eitzenb at golang.org>
 Ben Fried <ben.fried at gmail.com>
 Ben Lynn <benlynn at gmail.com>
@@ -111,24 +130,31 @@ Bill Thiede <couchmoney at gmail.com>
 Billie Harold Cleek <bhcleek at gmail.com>
 Bjorn Tillenius <bjorn at tillenius.me>
 Bjorn Tipling <bjorn.tipling at gmail.com>
+Blake Gentry <blakesgentry at gmail.com>
 Blake Mizerany <blake.mizerany at gmail.com>
 Bobby Powers <bobbypowers at gmail.com>
 Brad Fitzpatrick <bradfitz at golang.org> <bradfitz at gmail.com>
 Brad Garcia <bgarcia at golang.org>
+Brandon Gilmore <varz at google.com>
 Brendan Daniel Tracey <tracey.brendan at gmail.com>
 Brendan O'Dea <bod at golang.org>
+Brett Cannon <bcannon at gmail.com>
 Brian Dellisanti <briandellisanti at gmail.com>
 Brian G. Merrell <bgmerrell at gmail.com>
-Brian Gitonga Marete <marete at toshnix.com>
+Brian Gitonga Marete <marete at toshnix.com> <bgmarete at gmail.com>
 Brian Ketelsen <bketelsen at gmail.com>
 Brian Slesinsky <skybrian at google.com>
-Burcu Dogan <jbd at google.com>
+Brian Smith <ohohvi at gmail.com>
+Bryan Ford <brynosaurus at gmail.com>
+Burcu Dogan <jbd at google.com> <burcujdogan at gmail.com>
 Caine Tighe <arctanofyourface at gmail.com>
 Caleb Spare <cespare at gmail.com>
 Carl Chatfield <carlchatfield at gmail.com>
+Carl Jackson <carl at stripe.com>
 Carl Mastrangelo <notcarl at google.com>
 Carl Shapiro <cshapiro at google.com> <cshapiro at golang.org>
 Carlos Castillo <cookieo9 at gmail.com>
+Carlos Cirello <uldericofilho at gmail.com>
 Cary Hull <chull at google.com>
 Case Nelson <case.nelson at gmail.com>
 Casey Marshall <casey.marshall at gmail.com>
@@ -137,11 +163,13 @@ Cezar Sá Espinola <cezarsa at gmail.com>
 ChaiShushan <chaishushan at gmail.com>
 Charles L. Dorian <cldorian at gmail.com>
 Charles Lee <zombie.fml at gmail.com>
+Chris Broadfoot <cbro at golang.org>
 Chris Dollin <ehog.hedge at gmail.com>
 Chris Farmiloe <chrisfarms at gmail.com>
 Chris Howey <howeyc at gmail.com>
 Chris Hundt <hundt at google.com>
 Chris Jones <chris at cjones.org> <chris.jones.yar at gmail.com>
+Chris Kastorff <encryptio at gmail.com>
 Chris Lennert <calennert at gmail.com>
 Chris Manghane <cmang at golang.org>
 Chris McGee <sirnewton_01 at yahoo.ca> <newton688 at gmail.com>
@@ -150,12 +178,14 @@ Christine Hansmann <chhansmann at gmail.com>
 Christoffer Buchholz <christoffer.buchholz at gmail.com>
 Christoph Hack <christoph at tux21b.org>
 Christopher Cahoon <chris.cahoon at gmail.com>
+Christopher Guiney <chris at guiney.net>
 Christopher Nielsen <m4dh4tt3r at gmail.com>
 Christopher Redden <christopher.redden at gmail.com>
 Christopher Swenson <cswenson at google.com>
 Christopher Wedgwood <cw at f00f.org>
 Clement Skau <clementskau at gmail.com>
 Colby Ranger <cranger at google.com>
+Colin Kennedy <moshen.colin at gmail.com>
 Conrad Meyer <cemeyer at cs.washington.edu>
 Corey Thomasson <cthom.lists at gmail.com>
 Cosmos Nicolaou <cnicolaou at google.com>
@@ -164,6 +194,7 @@ Damian Gryski <dgryski at gmail.com>
 Damien Neil <dneil at google.com>
 Dan Callahan <dan.callahan at gmail.com>
 Dan Peterson <dpiddy at gmail.com>
+Dan Pupius <dan at medium.com>
 Dan Sinclair <dan.sinclair at gmail.com>
 Daniel Fleischman <danielfleischman at gmail.com>
 Daniel Krech <eikeon at eikeon.com>
@@ -180,6 +211,7 @@ David Anderson <danderson at google.com>
 David Barnett <dbarnett at google.com>
 David Bürgin <676c7473 at gmail.com>
 David Calavera <david.calavera at gmail.com>
+David Chase <drchase at google.com>
 David Covert <davidhcovert at gmail.com>
 David Crawshaw <david.crawshaw at zentus.com> <crawshaw at google.com> <crawshaw at golang.org>
 David du Colombier <0intro at gmail.com>
@@ -192,23 +224,29 @@ David Presotto <presotto at gmail.com>
 David Symonds <dsymonds at golang.org>
 David Thomas <davidthomas426 at gmail.com>
 David Titarenco <david.titarenco at gmail.com>
+Davies Liu <davies.liu at gmail.com>
 Dean Prichard <dean.prichard at gmail.com>
 Denis Brandolini <denis.brandolini at gmail.com>
+Derek Buitenhuis <derek.buitenhuis at gmail.com>
 Derek Parker <parkerderek86 at gmail.com>
 Devon H. O'Dell <devon.odell at gmail.com>
 Dhiru Kholia <dhiru.kholia at gmail.com>
+Didier Spezia <didier.06 at gmail.com>
 Dimitri Tcaciuc <dtcaciuc at gmail.com>
 Dmitri Shuralyov <shurcooL at gmail.com>
 Dmitriy Shelenin <deemok at googlemail.com> <deemok at gmail.com>
 Dmitriy Vyukov <dvyukov at google.com>
 Dmitry Chestnykh <dchest at gmail.com>
+Dmitry Savintsev <dsavints at gmail.com>
 Dominik Honnef <dominik.honnef at gmail.com>
+Dominik Vogt <vogt at linux.vnet.ibm.com>
 Donovan Hide <donovanhide at gmail.com>
 Drew Hintz <adhintz at google.com>
 Duncan Holm <mail at frou.org>
 Dustin Long <dustmop at gmail.com>
 Dustin Sallings <dsallings at gmail.com>
 Dustin Shields-Cloues <dcloues at gmail.com>
+Dvir Volk <dvir at everything.me> <dvirsky at gmail.com>
 Eden Li <eden.li at gmail.com>
 Egon Elbre <egonelbre at gmail.com>
 Ehren Kret <ehren.kret at gmail.com>
@@ -219,11 +257,13 @@ Eoghan Sherry <ejsherry at gmail.com>
 Eric Clark <zerohp at gmail.com>
 Eric Milliken <emilliken at gmail.com>
 Eric Roshan-Eisner <eric.d.eisner at gmail.com>
+Erik Aigner <aigner.erik at gmail.com>
 Erik St. Martin <alakriti at gmail.com>
 Erik Westrup <erik.westrup at gmail.com>
 Esko Luontola <esko.luontola at gmail.com>
 Evan Kroske <evankroske at google.com>
 Evan Martin <evan.martin at gmail.com>
+Evan Phoenix <evan at phx.io>
 Evan Shaw <chickencha at gmail.com>
 Ewan Chou <coocood at gmail.com>
 Fabrizio Milo <mistobaan at gmail.com>
@@ -234,6 +274,7 @@ Felix Geisendörfer <haimuiba at gmail.com>
 Firmansyah Adiputra <frm.adiputra at gmail.com>
 Florian Uekermann <florian at uekermann-online.de> <f1 at uekermann-online.de>
 Florian Weimer <fw at deneb.enyo.de>
+Florin Patan <florinpatan at gmail.com>
 Folke Behrens <folke at google.com>
 Francesc Campoy <campoy at golang.org>
 Francisco Souza <franciscossouza at gmail.com>
@@ -245,23 +286,30 @@ Gaal Yahas <gaal at google.com>
 Gabriel Aszalos <gabriel.aszalos at gmail.com>
 Gary Burd <gary at beagledreams.com> <gary.burd at gmail.com>
 Gautham Thambidorai <gautham.dorai at gmail.com>
+Geert-Johan Riemer <gjr19912 at gmail.com>
 Georg Reinke <guelfey at gmail.com>
+George Shammas <george at shamm.as> <georgyo at gmail.com>
 Gerasimos Dimitriadis <gedimitr at gmail.com>
 Gideon Jan-Wessel Redelinghuys <gjredelinghuys at gmail.com>
 Giles Lean <giles.lean at pobox.com>
+Giulio Iotti <dullgiulio at gmail.com>
 Glenn Lewis <gmlewis at google.com>
 Gordon Klaus <gordon.klaus at gmail.com>
 Graham King <graham4king at gmail.com>
 Graham Miller <graham.miller at gmail.com>
 Greg Ward <greg at gerg.ca>
 Guillaume J. Charmes <guillaume at charmes.net>
+Guobiao Mei <meiguobiao at gmail.com>
 Gustav Paul <gustav.paul at gmail.com>
 Gustavo Franco <gustavorfranco at gmail.com>
 Gustavo Niemeyer <gustavo at niemeyer.net> <n13m3y3r at gmail.com>
 Gwenael Treguier <gwenn.kahz at gmail.com>
-Hana Kim <hyangah at gmail.com>
+Hajime Hoshi <hajimehoshi at gmail.com>
 Han-Wen Nienhuys <hanwen at google.com>
+Hari haran <hariharan.uno at gmail.com>
+Hariharan Srinath <srinathh at gmail.com>
 Harley Laue <losinggeneration at gmail.com>
+Håvard Haugen <havard.haugen at gmail.com>
 Hector Chu <hectorchu at gmail.com>
 Hector Martin Cantero <hector at marcansoft.com>
 Henning Schmiedehausen <henning at schmiedehausen.org>
@@ -269,12 +317,19 @@ Henrik Edwards <henrik.edwards at gmail.com>
 Herbert Georg Fischer <herbert.fischer at gmail.com>
 Hong Ruiqi <hongruiqi at gmail.com>
 Hossein Sheikh Attar <hattar at google.com>
+Hyang-Ah Hana Kim <hakim at google.com> <hyangah at gmail.com>
 Ian Lance Taylor <iant at golang.org>
 Icarus Sparry <golang at icarus.freeuk.com>
+Igor Dolzhikov <bluesriverz at gmail.com>
+INADA Naoki <songofacandy at gmail.com>
+Ingo Krabbe <ikrabbe.ask at gmail.com>
 Ingo Oeser <nightlyone at googlemail.com> <nightlyone at gmail.com>
 Isaac Wagner <ibw at isaacwagner.me>
 Ivan Krasin <krasin at golang.org>
+Ivan Ukhov <ivan.ukhov at gmail.com>
 Jacob Baskin <jbaskin at google.com>
+Jacob H. Haven <jacob at cloudflare.com>
+Jae Kwon <jae at tendermint.com>
 Jakob Borg <jakob at nym.se>
 Jakub Ryszard Czarnowicz <j.czarnowicz at gmail.com>
 James Aguilar <jaguilar at google.com>
@@ -291,6 +346,7 @@ Jamie Gennis <jgennis at google.com> <jgennis at gmail.com>
 Jamie Turner <jamwt at dropbox.com>
 Jamie Wilkinson <jaq at spacepants.org>
 Jan H. Hosang <jan.hosang at gmail.com>
+Jan Kratochvil <jan.kratochvil at redhat.com>
 Jan Mercl <0xjnml at gmail.com>
 Jan Mercl <befelemepeseveze at gmail.com>
 Jan Newmarch <jan.newmarch at gmail.com>
@@ -313,9 +369,12 @@ Jeremy Schlatter <jeremy.schlatter at gmail.com>
 Jim McGrath <jimmc2 at gmail.com>
 Jimmy Zelinskie <jimmyzelinskie at gmail.com>
 Jingcheng Zhang <diogin at gmail.com>
+Jiong Du <londevil at gmail.com>
 Joakim Sernbrant <serbaut at gmail.com>
+Joe Harrison <joehazzers at gmail.com>
 Joe Poirier <jdpoirier at gmail.com>
 Joe Shaw <joe at joeshaw.org>
+Joe Tsai <joetsai at digital-static.net>
 Joel Sing <jsing at google.com>
 Joel Stemmer <stemmertech at gmail.com>
 Johan Euphrosine <proppy at google.com>
@@ -323,9 +382,11 @@ John Asmuth <jasmuth at gmail.com>
 John Beisley <huin at google.com>
 John C Barstow <jbowtie at amathaine.com>
 John DeNero <denero at google.com>
+John Dethridge <jcd at golang.org>
 John Graham-Cumming <jgc at jgc.org> <jgrahamc at gmail.com>
 John Howard Palevich <jack.palevich at gmail.com>
 John Newlin <jnewlin at google.com>
+John Potocny <johnp at vividcortex.com>
 John Shahid <jvshahid at gmail.com>
 John Tuley <john at tuley.org>
 Jonathan Allie <jonallie at google.com>
@@ -352,8 +413,11 @@ JT Olds <jtolds at xnet5.com>
 Jukka-Pekka Kekkonen <karatepekka at gmail.com>
 Julian Phillips <julian at quantumfyre.co.uk>
 Julien Schmidt <google at julienschmidt.com>
+Justin Nuß <nuss.justin at gmail.com>
 Kai Backman <kaib at golang.org>
 Kamil Kisiel <kamil at kamilkisiel.net> <kamil.kisiel at gmail.com>
+Kang Hu <hukangustc at gmail.com>
+Kato Kazuyoshi <kato.kazuyoshi at gmail.com>
 Katrina Owen <katrina.owen at gmail.com>
 Kay Zhu <kayzhu at google.com>
 Kei Son <hey.calmdown at gmail.com>
@@ -367,12 +431,16 @@ Ken Thompson <ken at golang.org>
 Kevin Ballard <kevin at sb.org>
 Kevin Klues <klueska at gmail.com> <klueska at google.com>
 Kirklin McDonald <kirklin.mcdonald at gmail.com>
+Konstantin Shaposhnikov <k.shaposhnikov at gmail.com>
 Kyle Consalus <consalus at gmail.com>
 Kyle Isom <kyle at gokyle.net>
 Kyle Lemons <kyle at kylelemons.net> <kevlar at google.com>
 L Campbell <unpantsu at gmail.com>
 Lai Jiangshan <eag0628 at gmail.com>
 Larry Hosken <lahosken at golang.org>
+Larz Conwell <larzconwell at gmail.com>
+Lee Packham <lpackham at gmail.com>
+Lloyd Dewolf <foolswisdom at gmail.com>
 Lorenzo Stoakes <lstoakes at gmail.com>
 Louis Kruger <louisk at google.com>
 Luca Greco <luca.greco at alcacoop.it>
@@ -380,13 +448,17 @@ Lucio De Re <lucio.dere at gmail.com>
 Luit van Drongelen <luitvd at gmail.com>
 Luka Zakrajšek <tr00.g33k at gmail.com>
 Luke Curley <qpingu at gmail.com>
+Luna Duclos <luna.duclos at palmstonegames.com>
 Luuk van Dijk <lvd at golang.org> <lvd at google.com>
+Lynn Boger <laboger at linux.vnet.ibm.com>
 Manoj Dayaram <platform-dev at moovweb.com> <manoj.dayaram at moovweb.com>
 Manu Garg <manugarg at google.com>
 Manuel Mendez <mmendez534 at gmail.com>
 Marc Weistroff <marc at weistroff.net>
 Marcel van Lohuizen <mpvl at golang.org>
 Marco Hennings <marco.hennings at freiheit.com>
+Marius Nuennerich <mnu at google.com>
+Mark Bucciarelli <mkbucc at gmail.com>
 Mark Theunissen <mark.theunissen at gmail.com>
 Mark Zavislak <zavislak at google.com>
 Marko Juhani Silokunnas <marko.silokunnas at gmail.com>
@@ -395,23 +467,32 @@ Marko Tiikkaja <marko at joh.to>
 Markus Duft <markus.duft at salomon.at>
 Markus Sonderegger <marraison at gmail.com>
 Markus Zimmermann <zimmski at gmail.com>
+Martin Möhrmann <martisch at uos.de>
 Martin Neubauer <m.ne at gmx.net>
 Martin Olsson <martin at minimum.se>
 Mateusz Czapliński <czapkofan at gmail.com>
+Mathias Beke <git at denbeke.be>
 Mathieu Lonjaret <mathieu.lonjaret at gmail.com>
 Mats Lidell <mats.lidell at cag.se> <mats.lidell at gmail.com>
 Matt Aimonetti <mattaimonetti at gmail.com>
+Matt Bostock <matt at mattbostock.com>
 Matt Brown <mdbrown at google.com>
 Matt Jibson <matt.jibson at gmail.com>
 Matt Joiner <anacrolix at gmail.com>
 Matt Jones <mrjones at google.com>
+Matt Layher <mdlayher at gmail.com>
 Matt Reiferson <mreiferson at gmail.com>
+Matt T. Proud <matt.proud at gmail.com>
+Matt Williams <gh at mattyw.net> <mattyjwilliams at gmail.com>
+Matthew Brennan <matty.brennan at gmail.com>
 Matthew Cottingham <mattcottingham at gmail.com>
 Matthew Dempsky <mdempsky at google.com>
+Matthew Holt <Matthew.Holt+git at gmail.com>
 Matthew Horsnell <matthew.horsnell at gmail.com>
 Maxim Khitrov <max at mxcrypt.com>
 Maxim Pimenov <mpimenov at google.com>
 Maxim Ushakov <ushakov at google.com>
+Meir Fischer <meirfischer at gmail.com>
 Micah Stetson <micah.stetson at gmail.com>
 Michael Chaten <mchaten at gmail.com>
 Michael Elkins <michael.elkins at gmail.com>
@@ -419,17 +500,23 @@ Michael Fraenkel <michael.fraenkel at gmail.com>
 Michael Gehring <mg at ebfe.org> <gnirheg.leahcim at gmail.com>
 Michael Hoisie <hoisie at gmail.com>
 Michael Hudson-Doyle <michael.hudson at linaro.org>
+Michael Käufl <golang at c.michael-kaeufl.de>
 Michael Kelly <mjk at google.com>
 Michael Lewis <mikelikespie at gmail.com>
 Michael MacInnis <Michael.P.MacInnis at gmail.com>
 Michael Matloob <matloob at google.com>
+Michael McGreevy <mcgreevy at golang.org>
 Michael Pearson <mipearson at gmail.com>
 Michael Piatek <piatek at google.com>
+Michael Schaller <michael at 5challer.de>
 Michael Shields <mshields at google.com>
 Michael Stapelberg <michael at stapelberg.de> <mstplbrg at googlemail.com>
 Michael T. Jones <mtj at google.com> <michael.jones at gmail.com>
 Michael Teichgräber <mteichgraeber at gmx.de> <mt4swm at googlemail.com>
+Michael Vetter <g.bluehut at gmail.com>
+Michal Cierniak <cierniak at google.com>
 Michał Derkacz <ziutek at lnet.pl>
+Michalis Kargakis <michaliskargakis at gmail.com>
 Miek Gieben <miek at miek.nl> <remigius.gieben at gmail.com>
 Mihai Borobocea <MihaiBorobocea at gmail.com>
 Mikael Tillenius <mikti42 at gmail.com>
@@ -448,6 +535,8 @@ Mrunal Patel <mrunalp at gmail.com>
 Nan Deng <monnand at gmail.com>
 Nathan John Youngman <nj at nathany.com>
 Nathan P Finch <nate.finch at gmail.com>
+Nathan Youngman <git at nathany.com>
+Nevins Bartolomeo <nevins.bartolomeo at gmail.com>
 Nicholas Katsaros <nick at nickkatsaros.com>
 Nicholas Presta <nick at nickpresta.ca> <nick1presta at gmail.com>
 Nicholas Sullivan <nicholas.sullivan at gmail.com>
@@ -456,6 +545,7 @@ Nick Cooper <nmvc at google.com>
 Nick Craig-Wood <nick at craig-wood.com> <nickcw at gmail.com>
 Nicolas Kaiser <nikai at nikai.net>
 Nicolas Owens <mischief at offblast.org>
+Nicolas S. Dade <nic.dade at gmail.com>
 Nigel Kerr <nigel.kerr at gmail.com>
 Nigel Tao <nigeltao at golang.org>
 Noah Campbell <noahcampbell at gmail.com>
@@ -466,6 +556,7 @@ Olivier Duperray <duperray.olivier at gmail.com>
 Olivier Saingre <osaingre at gmail.com>
 Padraig Kitterick <padraigkitterick at gmail.com>
 Paolo Giarrusso <p.giarrusso at gmail.com>
+Paolo Martini <mrtnpaolo at gmail.com>
 Pascal S. de Kloe <pascal at quies.net>
 Patrick Crosby <patrick at stathat.com>
 Patrick Gavlin <pgavlin at gmail.com>
@@ -479,8 +570,10 @@ Paul Borman <borman at google.com>
 Paul Chang <paulchang at google.com>
 Paul Hammond <paul at paulhammond.org>
 Paul Lalonde <paul.a.lalonde at gmail.com>
+Paul Marks <pmarks at google.com>
 Paul Nasrat <pnasrat at google.com>
 Paul Sbarra <Sbarra.Paul at gmail.com>
+Paul Smith <paulsmith at pobox.com> <paulsmith at gmail.com>
 Paul van Brouwershaven <paul at vanbrouwershaven.com>
 Pavel Zinovkin <pavel.zinovkin at gmail.com>
 Pawel Szczur <filemon at google.com>
@@ -491,10 +584,12 @@ Peter Collingbourne <pcc at google.com>
 Peter Froehlich <peter.hans.froehlich at gmail.com>
 Peter Kleiweg <pkleiweg at xs4all.nl>
 Peter McKenzie <petermck at google.com>
+Peter Moody <pmoody at uber.com>
 Peter Mundy <go.peter.90 at gmail.com>
 Péter Surányi <speter.go1 at gmail.com>
 Péter Szabó <pts at google.com>
 Péter Szilágyi <peterke at gmail.com>
+Peter Waldschmidt <peter at waldschmidt.com>
 Peter Waller <peter.waller at gmail.com>
 Peter Weinberger <pjw at golang.org>
 Peter Williams <pwil3058 at gmail.com>
@@ -504,10 +599,14 @@ Pieter Droogendijk <pieter at binky.org.uk>
 Pietro Gagliardi <pietro10 at mac.com>
 Preetam Jinka <pj at preet.am>
 Quan Yong Zhai <qyzhai at gmail.com>
+Quoc-Viet Nguyen <afelion at gmail.com>
+Rahul Chaudhry <rahulchaudhry at chromium.org>
 Raif S. Naffah <go at naffah-raif.name>
+Rajat Goel <rajat.goel2010 at gmail.com>
 Raph Levien <raph at google.com>
 Raul Silvera <rsilvera at google.com>
 Rémy Oudompheng <oudomphe at phare.normalesup.org> <remyoudompheng at gmail.com>
+Richard Barnes <rlb at ipv.sx>
 Richard Crowley <r at rcrowley.org>
 Richard Eric Gavaletz <gavaletz at gmail.com>
 Richard Musiol <mail at richard-musiol.de> <neelance at gmail.com>
@@ -530,22 +629,25 @@ Roger Pau Monné <royger at gmail.com>
 Roger Peppe <rogpeppe at gmail.com>
 Ron Hashimoto <mail at h2so5.net>
 Ron Minnich <rminnich at gmail.com>
-Ross Light <rlight2 at gmail.com>
+Ross Light <light at google.com> <rlight2 at gmail.com>
 Rowan Worth <sqweek at gmail.com>
 Rui Ueyama <ruiu at google.com>
 Russ Cox <rsc at golang.org>
 Ryan Barrett <ryanb at google.com>
+Ryan Brown <ribrdb at google.com>
 Ryan Hitchman <hitchmanr at gmail.com>
+Ryan Seys <ryan at ryanseys.com>
 Ryan Slade <ryanslade at gmail.com>
 S.Çağlar Onur <caglar at 10ur.org>
 Sam Thorogood <thorogood at google.com> <sam.thorogood at gmail.com>
 Sameer Ajmani <sameer at golang.org> <ajmani at gmail.com>
 Sanjay Menakuru <balasanjay at gmail.com>
+Scott Barron <scott.barron at github.com>
 Scott Ferguson <scottwferg at gmail.com>
 Scott Lawrence <bytbox at gmail.com>
 Scott Schwartz <scotts at golang.org>
 Sean Burford <sburford at google.com>
-Sebastien Binet	<seb.binet at gmail.com>
+Sebastien Binet <seb.binet at gmail.com>
 Sébastien Paolacci <sebastien.paolacci at gmail.com>
 Sergei Skorobogatov <skorobo at rambler.ru>
 Sergey 'SnakE' Gromov <snake.scaly at gmail.com>
@@ -555,16 +657,20 @@ Shawn Ledbetter <sledbetter at google.com>
 Shawn Smith <shawn.p.smith at gmail.com>
 Shenghou Ma <minux at golang.org> <minux.ma at gmail.com>
 Shivakumar GN <shivakumar.gn at gmail.com>
+Silvan Jegen <s.jegen at gmail.com>
 Simon Whitehead <chemnova at gmail.com>
 Sokolov Yura <funny.falcon at gmail.com>
 Spring Mc <heresy.mc at gmail.com>
+Srdjan Petrovic <spetrovic at google.com>
 StalkR <stalkr at stalkr.net>
+Stan Schwertly <stan at schwertly.com>
 Stefan Nilsson <snilsson at nada.kth.se> <trolleriprofessorn at gmail.com>
 Stéphane Travostino <stephane.travostino at gmail.com>
 Stephen Ma <stephenm at golang.org>
 Stephen McQuay <stephen at mcquay.me>
 Stephen Weinberg <stephen at q5comm.com>
 Steve McCoy <mccoyst at gmail.com>
+Steve Streeting <steve at stevestreeting.com>
 Steven Elliot Harris <seharris at gmail.com>
 Steven Hartland <steven.hartland at multiplay.co.uk>
 Sugu Sougoumarane <ssougou at gmail.com>
@@ -572,6 +678,7 @@ Sven Almgren <sven at tras.se>
 Szabolcs Nagy <nsz at port70.net>
 Tad Glines <tad.glines at gmail.com>
 Taj Khattra <taj.khattra at gmail.com>
+Tamir Duberstein <tamird at gmail.com>
 Tarmigan Casebolt <tarmigan at gmail.com>
 Taru Karttunen <taruti at taruti.net>
 Tetsuo Kiso <tetsuokiso9 at gmail.com>
@@ -582,9 +689,12 @@ Thomas Kappler <tkappler at gmail.com>
 Timo Savola <timo.savola at gmail.com>
 Timo Truyts <alkaloid.btx at gmail.com>
 Tobias Columbus <tobias.columbus at gmail.com> <tobias.columbus at googlemail.com>
+Todd Neal <todd at tneal.org>
 Todd Wang <toddwang at gmail.com>
+Tom Heng <zhm20070928 at gmail.com>
 Tom Linford <tomlinford at gmail.com>
 Tom Szymanski <tgs at google.com>
+Tommy Schaefer <tommy.schaefer at teecom.com>
 Tor Andersson <tor.andersson at gmail.com>
 Travis Cline <travis.cline at gmail.com>
 Trevor Strohman <trevor.strohman at gmail.com>
@@ -597,9 +707,11 @@ Uriel Mangado <uriel at berlinblue.org>
 Vadim Vygonets <unixdj at gmail.com>
 Vega Garcia Luis Alfonso <vegacom at gmail.com>
 Vincent Ambo <tazjin at googlemail.com>
+Vincent Batts <vbatts at hashbangbash.com> <vbatts at gmail.com>
 Vincent Vanackere <vincent.vanackere at gmail.com>
 Vinu Rajashekhar <vinutheraj at gmail.com>
 Vish Subramanian <vish at google.com>
+Vlad Krasnov <vlad at cloudflare.com>
 Vladimir Nikishenko <vova616 at gmail.com>
 Volker Dobler <dr.volker.dobler at gmail.com>
 Wei Guangjing <vcc.163 at gmail.com>
@@ -613,6 +725,7 @@ Xing Xing <mikespook at gmail.com>
 Yan Zou <yzou at google.com>
 Yasuhiro Matsumoto <mattn.jp at gmail.com>
 Yissakhar Z. Beck <yissakhar.beck at gmail.com>
+Yo-An Lin <yoanlin93 at gmail.com>
 Yongjian Xu <i3dmaster at gmail.com>
 Yoshiyuki Kanno <nekotaroh at gmail.com> <yoshiyuki.kanno at stoic.co.jp>
 Yusuke Kagiwada <block.rxckin.beats at gmail.com>
diff --git a/README b/README
deleted file mode 100644
index a557fe9..0000000
--- a/README
+++ /dev/null
@@ -1,32 +0,0 @@
-This is the source code repository for the Go programming language.  
-
-For documentation about how to install and use Go,
-visit http://golang.org/ or load doc/install-source.html
-in your web browser.
-
-After installing Go, you can view a nicely formatted
-doc/install-source.html by running godoc --http=:6060
-and then visiting http://localhost:6060/doc/install/source.
-
-Unless otherwise noted, the Go source files are distributed
-under the BSD-style license found in the LICENSE file.
-
---
-
-Binary Distribution Notes
-
-If you have just untarred a binary Go distribution, you need to set
-the environment variable $GOROOT to the full path of the go
-directory (the one containing this README).  You can omit the
-variable if you unpack it into /usr/local/go, or if you rebuild
-from sources by running all.bash (see doc/install.html).
-You should also add the Go binary directory $GOROOT/bin
-to your shell's path.
-
-For example, if you extracted the tar file into $HOME/go, you might
-put the following in your .profile:
-
-    export GOROOT=$HOME/go
-    export PATH=$PATH:$GOROOT/bin
-
-See doc/install.html for more details.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..4e6d7bd
--- /dev/null
+++ b/README.md
@@ -0,0 +1,45 @@
+# The Go Programming Language
+
+Go is an open source programming language that makes it easy to build simple,
+reliable, and efficient software.
+
+![Gopher image](doc/gopher/fiveyears.jpg)
+
+For documentation about how to install and use Go,
+visit https://golang.org/ or load doc/install-source.html
+in your web browser.
+
+Our canonical Git repository is located at https://go.googlesource.com/go.
+There is a mirror of the repository at https://github.com/golang/go.
+
+Please report issues here: https://golang.org/issue/new
+
+Go is the work of hundreds of contributors. We appreciate your help!
+
+To contribute, please read the contribution guidelines:
+	https://golang.org/doc/contribute.html
+
+##### Please note that we do not use pull requests.
+
+Unless otherwise noted, the Go source files are distributed
+under the BSD-style license found in the LICENSE file.
+
+--
+
+## Binary Distribution Notes
+
+If you have just untarred a binary Go distribution, you need to set
+the environment variable $GOROOT to the full path of the go
+directory (the one containing this file).  You can omit the
+variable if you unpack it into /usr/local/go, or if you rebuild
+from sources by running all.bash (see doc/install-source.html).
+You should also add the Go binary directory $GOROOT/bin
+to your shell's path.
+
+For example, if you extracted the tar file into $HOME/go, you might
+put the following in your .profile:
+
+	export GOROOT=$HOME/go
+	export PATH=$PATH:$GOROOT/bin
+
+See https://golang.org/doc/install or doc/install.html for more details.
diff --git a/VERSION b/VERSION
index 107be89..77af434 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-go1.4.3
\ No newline at end of file
+go1.5.1
\ No newline at end of file
diff --git a/api/except.txt b/api/except.txt
index 6e40e18..59ef942 100644
--- a/api/except.txt
+++ b/api/except.txt
@@ -328,3 +328,4 @@ pkg syscall (netbsd-arm), type IfMsghdr struct, Pad_cgo_1 [4]uint8
 pkg syscall (netbsd-arm-cgo), const SizeofIfData = 132
 pkg syscall (netbsd-arm-cgo), type IfMsghdr struct, Pad_cgo_1 [4]uint8
 pkg unicode, const Version = "6.3.0"
+pkg unicode, const Version = "7.0.0"
diff --git a/api/go1.5.txt b/api/go1.5.txt
new file mode 100644
index 0000000..d9cf797
--- /dev/null
+++ b/api/go1.5.txt
@@ -0,0 +1,975 @@
+pkg archive/zip, method (*Writer) SetOffset(int64)
+pkg bufio, method (*Reader) Discard(int) (int, error)
+pkg bufio, method (ReadWriter) Discard(int) (int, error)
+pkg bytes, func LastIndexByte([]uint8, uint8) int
+pkg bytes, method (*Buffer) Cap() int
+pkg bytes, method (*Reader) Size() int64
+pkg crypto, const SHA512_224 = 14
+pkg crypto, const SHA512_224 Hash
+pkg crypto, const SHA512_256 = 15
+pkg crypto, const SHA512_256 Hash
+pkg crypto, type Decrypter interface { Decrypt, Public }
+pkg crypto, type Decrypter interface, Decrypt(io.Reader, []uint8, DecrypterOpts) ([]uint8, error)
+pkg crypto, type Decrypter interface, Public() PublicKey
+pkg crypto, type DecrypterOpts interface {}
+pkg crypto/cipher, func NewGCMWithNonceSize(Block, int) (AEAD, error)
+pkg crypto/elliptic, type CurveParams struct, Name string
+pkg crypto/rsa, method (*PrivateKey) Decrypt(io.Reader, []uint8, crypto.DecrypterOpts) ([]uint8, error)
+pkg crypto/rsa, type OAEPOptions struct
+pkg crypto/rsa, type OAEPOptions struct, Hash crypto.Hash
+pkg crypto/rsa, type OAEPOptions struct, Label []uint8
+pkg crypto/rsa, type PKCS1v15DecryptOptions struct
+pkg crypto/rsa, type PKCS1v15DecryptOptions struct, SessionKeyLen int
+pkg crypto/sha512, const Size224 = 28
+pkg crypto/sha512, const Size224 ideal-int
+pkg crypto/sha512, const Size256 = 32
+pkg crypto/sha512, const Size256 ideal-int
+pkg crypto/sha512, func New512_224() hash.Hash
+pkg crypto/sha512, func New512_256() hash.Hash
+pkg crypto/sha512, func Sum512_224([]uint8) [28]uint8
+pkg crypto/sha512, func Sum512_256([]uint8) [32]uint8
+pkg crypto/tls, const TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 = 49196
+pkg crypto/tls, const TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 uint16
+pkg crypto/tls, const TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 = 49200
+pkg crypto/tls, const TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 uint16
+pkg crypto/tls, method (*Config) SetSessionTicketKeys([][32]uint8)
+pkg crypto/tls, type Certificate struct, SignedCertificateTimestamps [][]uint8
+pkg crypto/tls, type ConnectionState struct, OCSPResponse []uint8
+pkg crypto/tls, type ConnectionState struct, SignedCertificateTimestamps [][]uint8
+pkg crypto/x509, method (*CertificateRequest) CheckSignature() error
+pkg crypto/x509, type Certificate struct, UnhandledCriticalExtensions []asn1.ObjectIdentifier
+pkg crypto/x509/pkix, type Name struct, ExtraNames []AttributeTypeAndValue
+pkg database/sql, method (*DB) Stats() DBStats
+pkg database/sql, type DBStats struct
+pkg database/sql, type DBStats struct, OpenConnections int
+pkg debug/dwarf, const ClassAddress = 1
+pkg debug/dwarf, const ClassAddress Class
+pkg debug/dwarf, const ClassBlock = 2
+pkg debug/dwarf, const ClassBlock Class
+pkg debug/dwarf, const ClassConstant = 3
+pkg debug/dwarf, const ClassConstant Class
+pkg debug/dwarf, const ClassExprLoc = 4
+pkg debug/dwarf, const ClassExprLoc Class
+pkg debug/dwarf, const ClassFlag = 5
+pkg debug/dwarf, const ClassFlag Class
+pkg debug/dwarf, const ClassLinePtr = 6
+pkg debug/dwarf, const ClassLinePtr Class
+pkg debug/dwarf, const ClassLocListPtr = 7
+pkg debug/dwarf, const ClassLocListPtr Class
+pkg debug/dwarf, const ClassMacPtr = 8
+pkg debug/dwarf, const ClassMacPtr Class
+pkg debug/dwarf, const ClassRangeListPtr = 9
+pkg debug/dwarf, const ClassRangeListPtr Class
+pkg debug/dwarf, const ClassReference = 10
+pkg debug/dwarf, const ClassReference Class
+pkg debug/dwarf, const ClassReferenceAlt = 13
+pkg debug/dwarf, const ClassReferenceAlt Class
+pkg debug/dwarf, const ClassReferenceSig = 11
+pkg debug/dwarf, const ClassReferenceSig Class
+pkg debug/dwarf, const ClassString = 12
+pkg debug/dwarf, const ClassString Class
+pkg debug/dwarf, const ClassStringAlt = 14
+pkg debug/dwarf, const ClassStringAlt Class
+pkg debug/dwarf, method (*Data) LineReader(*Entry) (*LineReader, error)
+pkg debug/dwarf, method (*Entry) AttrField(Attr) *Field
+pkg debug/dwarf, method (*LineReader) Next(*LineEntry) error
+pkg debug/dwarf, method (*LineReader) Reset()
+pkg debug/dwarf, method (*LineReader) Seek(LineReaderPos)
+pkg debug/dwarf, method (*LineReader) SeekPC(uint64, *LineEntry) error
+pkg debug/dwarf, method (*LineReader) Tell() LineReaderPos
+pkg debug/dwarf, method (*Reader) AddressSize() int
+pkg debug/dwarf, method (Class) GoString() string
+pkg debug/dwarf, method (Class) String() string
+pkg debug/dwarf, type Class int
+pkg debug/dwarf, type Field struct, Class Class
+pkg debug/dwarf, type LineEntry struct
+pkg debug/dwarf, type LineEntry struct, Address uint64
+pkg debug/dwarf, type LineEntry struct, BasicBlock bool
+pkg debug/dwarf, type LineEntry struct, Column int
+pkg debug/dwarf, type LineEntry struct, Discriminator int
+pkg debug/dwarf, type LineEntry struct, EndSequence bool
+pkg debug/dwarf, type LineEntry struct, EpilogueBegin bool
+pkg debug/dwarf, type LineEntry struct, File *LineFile
+pkg debug/dwarf, type LineEntry struct, ISA int
+pkg debug/dwarf, type LineEntry struct, IsStmt bool
+pkg debug/dwarf, type LineEntry struct, Line int
+pkg debug/dwarf, type LineEntry struct, OpIndex int
+pkg debug/dwarf, type LineEntry struct, PrologueEnd bool
+pkg debug/dwarf, type LineFile struct
+pkg debug/dwarf, type LineFile struct, Length int
+pkg debug/dwarf, type LineFile struct, Mtime uint64
+pkg debug/dwarf, type LineFile struct, Name string
+pkg debug/dwarf, type LineReader struct
+pkg debug/dwarf, type LineReaderPos struct
+pkg debug/dwarf, var ErrUnknownPC error
+pkg debug/elf, const R_PPC64_ADDR14 = 7
+pkg debug/elf, const R_PPC64_ADDR14 R_PPC64
+pkg debug/elf, const R_PPC64_ADDR14_BRNTAKEN = 9
+pkg debug/elf, const R_PPC64_ADDR14_BRNTAKEN R_PPC64
+pkg debug/elf, const R_PPC64_ADDR14_BRTAKEN = 8
+pkg debug/elf, const R_PPC64_ADDR14_BRTAKEN R_PPC64
+pkg debug/elf, const R_PPC64_ADDR16 = 3
+pkg debug/elf, const R_PPC64_ADDR16 R_PPC64
+pkg debug/elf, const R_PPC64_ADDR16_DS = 56
+pkg debug/elf, const R_PPC64_ADDR16_DS R_PPC64
+pkg debug/elf, const R_PPC64_ADDR16_HA = 6
+pkg debug/elf, const R_PPC64_ADDR16_HA R_PPC64
+pkg debug/elf, const R_PPC64_ADDR16_HI = 5
+pkg debug/elf, const R_PPC64_ADDR16_HI R_PPC64
+pkg debug/elf, const R_PPC64_ADDR16_HIGHER = 39
+pkg debug/elf, const R_PPC64_ADDR16_HIGHER R_PPC64
+pkg debug/elf, const R_PPC64_ADDR16_HIGHERA = 40
+pkg debug/elf, const R_PPC64_ADDR16_HIGHERA R_PPC64
+pkg debug/elf, const R_PPC64_ADDR16_HIGHEST = 41
+pkg debug/elf, const R_PPC64_ADDR16_HIGHEST R_PPC64
+pkg debug/elf, const R_PPC64_ADDR16_HIGHESTA = 42
+pkg debug/elf, const R_PPC64_ADDR16_HIGHESTA R_PPC64
+pkg debug/elf, const R_PPC64_ADDR16_LO = 4
+pkg debug/elf, const R_PPC64_ADDR16_LO R_PPC64
+pkg debug/elf, const R_PPC64_ADDR16_LO_DS = 57
+pkg debug/elf, const R_PPC64_ADDR16_LO_DS R_PPC64
+pkg debug/elf, const R_PPC64_ADDR24 = 2
+pkg debug/elf, const R_PPC64_ADDR24 R_PPC64
+pkg debug/elf, const R_PPC64_ADDR32 = 1
+pkg debug/elf, const R_PPC64_ADDR32 R_PPC64
+pkg debug/elf, const R_PPC64_ADDR64 = 38
+pkg debug/elf, const R_PPC64_ADDR64 R_PPC64
+pkg debug/elf, const R_PPC64_DTPMOD64 = 68
+pkg debug/elf, const R_PPC64_DTPMOD64 R_PPC64
+pkg debug/elf, const R_PPC64_DTPREL16 = 74
+pkg debug/elf, const R_PPC64_DTPREL16 R_PPC64
+pkg debug/elf, const R_PPC64_DTPREL16_DS = 101
+pkg debug/elf, const R_PPC64_DTPREL16_DS R_PPC64
+pkg debug/elf, const R_PPC64_DTPREL16_HA = 77
+pkg debug/elf, const R_PPC64_DTPREL16_HA R_PPC64
+pkg debug/elf, const R_PPC64_DTPREL16_HI = 76
+pkg debug/elf, const R_PPC64_DTPREL16_HI R_PPC64
+pkg debug/elf, const R_PPC64_DTPREL16_HIGHER = 103
+pkg debug/elf, const R_PPC64_DTPREL16_HIGHER R_PPC64
+pkg debug/elf, const R_PPC64_DTPREL16_HIGHERA = 104
+pkg debug/elf, const R_PPC64_DTPREL16_HIGHERA R_PPC64
+pkg debug/elf, const R_PPC64_DTPREL16_HIGHEST = 105
+pkg debug/elf, const R_PPC64_DTPREL16_HIGHEST R_PPC64
+pkg debug/elf, const R_PPC64_DTPREL16_HIGHESTA = 106
+pkg debug/elf, const R_PPC64_DTPREL16_HIGHESTA R_PPC64
+pkg debug/elf, const R_PPC64_DTPREL16_LO = 75
+pkg debug/elf, const R_PPC64_DTPREL16_LO R_PPC64
+pkg debug/elf, const R_PPC64_DTPREL16_LO_DS = 102
+pkg debug/elf, const R_PPC64_DTPREL16_LO_DS R_PPC64
+pkg debug/elf, const R_PPC64_DTPREL64 = 78
+pkg debug/elf, const R_PPC64_DTPREL64 R_PPC64
+pkg debug/elf, const R_PPC64_GOT16 = 14
+pkg debug/elf, const R_PPC64_GOT16 R_PPC64
+pkg debug/elf, const R_PPC64_GOT16_DS = 58
+pkg debug/elf, const R_PPC64_GOT16_DS R_PPC64
+pkg debug/elf, const R_PPC64_GOT16_HA = 17
+pkg debug/elf, const R_PPC64_GOT16_HA R_PPC64
+pkg debug/elf, const R_PPC64_GOT16_HI = 16
+pkg debug/elf, const R_PPC64_GOT16_HI R_PPC64
+pkg debug/elf, const R_PPC64_GOT16_LO = 15
+pkg debug/elf, const R_PPC64_GOT16_LO R_PPC64
+pkg debug/elf, const R_PPC64_GOT16_LO_DS = 59
+pkg debug/elf, const R_PPC64_GOT16_LO_DS R_PPC64
+pkg debug/elf, const R_PPC64_GOT_DTPREL16_DS = 91
+pkg debug/elf, const R_PPC64_GOT_DTPREL16_DS R_PPC64
+pkg debug/elf, const R_PPC64_GOT_DTPREL16_HA = 94
+pkg debug/elf, const R_PPC64_GOT_DTPREL16_HA R_PPC64
+pkg debug/elf, const R_PPC64_GOT_DTPREL16_HI = 93
+pkg debug/elf, const R_PPC64_GOT_DTPREL16_HI R_PPC64
+pkg debug/elf, const R_PPC64_GOT_DTPREL16_LO_DS = 92
+pkg debug/elf, const R_PPC64_GOT_DTPREL16_LO_DS R_PPC64
+pkg debug/elf, const R_PPC64_GOT_TLSGD16 = 79
+pkg debug/elf, const R_PPC64_GOT_TLSGD16 R_PPC64
+pkg debug/elf, const R_PPC64_GOT_TLSGD16_HA = 82
+pkg debug/elf, const R_PPC64_GOT_TLSGD16_HA R_PPC64
+pkg debug/elf, const R_PPC64_GOT_TLSGD16_HI = 81
+pkg debug/elf, const R_PPC64_GOT_TLSGD16_HI R_PPC64
+pkg debug/elf, const R_PPC64_GOT_TLSGD16_LO = 80
+pkg debug/elf, const R_PPC64_GOT_TLSGD16_LO R_PPC64
+pkg debug/elf, const R_PPC64_GOT_TLSLD16 = 83
+pkg debug/elf, const R_PPC64_GOT_TLSLD16 R_PPC64
+pkg debug/elf, const R_PPC64_GOT_TLSLD16_HA = 86
+pkg debug/elf, const R_PPC64_GOT_TLSLD16_HA R_PPC64
+pkg debug/elf, const R_PPC64_GOT_TLSLD16_HI = 85
+pkg debug/elf, const R_PPC64_GOT_TLSLD16_HI R_PPC64
+pkg debug/elf, const R_PPC64_GOT_TLSLD16_LO = 84
+pkg debug/elf, const R_PPC64_GOT_TLSLD16_LO R_PPC64
+pkg debug/elf, const R_PPC64_GOT_TPREL16_DS = 87
+pkg debug/elf, const R_PPC64_GOT_TPREL16_DS R_PPC64
+pkg debug/elf, const R_PPC64_GOT_TPREL16_HA = 90
+pkg debug/elf, const R_PPC64_GOT_TPREL16_HA R_PPC64
+pkg debug/elf, const R_PPC64_GOT_TPREL16_HI = 89
+pkg debug/elf, const R_PPC64_GOT_TPREL16_HI R_PPC64
+pkg debug/elf, const R_PPC64_GOT_TPREL16_LO_DS = 88
+pkg debug/elf, const R_PPC64_GOT_TPREL16_LO_DS R_PPC64
+pkg debug/elf, const R_PPC64_JMP_SLOT = 21
+pkg debug/elf, const R_PPC64_JMP_SLOT R_PPC64
+pkg debug/elf, const R_PPC64_NONE = 0
+pkg debug/elf, const R_PPC64_NONE R_PPC64
+pkg debug/elf, const R_PPC64_REL14 = 11
+pkg debug/elf, const R_PPC64_REL14 R_PPC64
+pkg debug/elf, const R_PPC64_REL14_BRNTAKEN = 13
+pkg debug/elf, const R_PPC64_REL14_BRNTAKEN R_PPC64
+pkg debug/elf, const R_PPC64_REL14_BRTAKEN = 12
+pkg debug/elf, const R_PPC64_REL14_BRTAKEN R_PPC64
+pkg debug/elf, const R_PPC64_REL16 = 249
+pkg debug/elf, const R_PPC64_REL16 R_PPC64
+pkg debug/elf, const R_PPC64_REL16_HA = 252
+pkg debug/elf, const R_PPC64_REL16_HA R_PPC64
+pkg debug/elf, const R_PPC64_REL16_HI = 251
+pkg debug/elf, const R_PPC64_REL16_HI R_PPC64
+pkg debug/elf, const R_PPC64_REL16_LO = 250
+pkg debug/elf, const R_PPC64_REL16_LO R_PPC64
+pkg debug/elf, const R_PPC64_REL24 = 10
+pkg debug/elf, const R_PPC64_REL24 R_PPC64
+pkg debug/elf, const R_PPC64_REL32 = 26
+pkg debug/elf, const R_PPC64_REL32 R_PPC64
+pkg debug/elf, const R_PPC64_REL64 = 44
+pkg debug/elf, const R_PPC64_REL64 R_PPC64
+pkg debug/elf, const R_PPC64_TLS = 67
+pkg debug/elf, const R_PPC64_TLS R_PPC64
+pkg debug/elf, const R_PPC64_TLSGD = 107
+pkg debug/elf, const R_PPC64_TLSGD R_PPC64
+pkg debug/elf, const R_PPC64_TLSLD = 108
+pkg debug/elf, const R_PPC64_TLSLD R_PPC64
+pkg debug/elf, const R_PPC64_TOC = 51
+pkg debug/elf, const R_PPC64_TOC R_PPC64
+pkg debug/elf, const R_PPC64_TOC16 = 47
+pkg debug/elf, const R_PPC64_TOC16 R_PPC64
+pkg debug/elf, const R_PPC64_TOC16_DS = 63
+pkg debug/elf, const R_PPC64_TOC16_DS R_PPC64
+pkg debug/elf, const R_PPC64_TOC16_HA = 50
+pkg debug/elf, const R_PPC64_TOC16_HA R_PPC64
+pkg debug/elf, const R_PPC64_TOC16_HI = 49
+pkg debug/elf, const R_PPC64_TOC16_HI R_PPC64
+pkg debug/elf, const R_PPC64_TOC16_LO = 48
+pkg debug/elf, const R_PPC64_TOC16_LO R_PPC64
+pkg debug/elf, const R_PPC64_TOC16_LO_DS = 64
+pkg debug/elf, const R_PPC64_TOC16_LO_DS R_PPC64
+pkg debug/elf, const R_PPC64_TPREL16 = 69
+pkg debug/elf, const R_PPC64_TPREL16 R_PPC64
+pkg debug/elf, const R_PPC64_TPREL16_DS = 95
+pkg debug/elf, const R_PPC64_TPREL16_DS R_PPC64
+pkg debug/elf, const R_PPC64_TPREL16_HA = 72
+pkg debug/elf, const R_PPC64_TPREL16_HA R_PPC64
+pkg debug/elf, const R_PPC64_TPREL16_HI = 71
+pkg debug/elf, const R_PPC64_TPREL16_HI R_PPC64
+pkg debug/elf, const R_PPC64_TPREL16_HIGHER = 97
+pkg debug/elf, const R_PPC64_TPREL16_HIGHER R_PPC64
+pkg debug/elf, const R_PPC64_TPREL16_HIGHERA = 98
+pkg debug/elf, const R_PPC64_TPREL16_HIGHERA R_PPC64
+pkg debug/elf, const R_PPC64_TPREL16_HIGHEST = 99
+pkg debug/elf, const R_PPC64_TPREL16_HIGHEST R_PPC64
+pkg debug/elf, const R_PPC64_TPREL16_HIGHESTA = 100
+pkg debug/elf, const R_PPC64_TPREL16_HIGHESTA R_PPC64
+pkg debug/elf, const R_PPC64_TPREL16_LO = 70
+pkg debug/elf, const R_PPC64_TPREL16_LO R_PPC64
+pkg debug/elf, const R_PPC64_TPREL16_LO_DS = 96
+pkg debug/elf, const R_PPC64_TPREL16_LO_DS R_PPC64
+pkg debug/elf, const R_PPC64_TPREL64 = 73
+pkg debug/elf, const R_PPC64_TPREL64 R_PPC64
+pkg debug/elf, method (R_PPC64) GoString() string
+pkg debug/elf, method (R_PPC64) String() string
+pkg debug/elf, type R_PPC64 int
+pkg encoding/base64, const NoPadding = -1
+pkg encoding/base64, const NoPadding int32
+pkg encoding/base64, const StdPadding = 61
+pkg encoding/base64, const StdPadding int32
+pkg encoding/base64, method (Encoding) WithPadding(int32) *Encoding
+pkg encoding/base64, var RawStdEncoding *Encoding
+pkg encoding/base64, var RawURLEncoding *Encoding
+pkg encoding/json, method (*Decoder) More() bool
+pkg encoding/json, method (*Decoder) Token() (Token, error)
+pkg encoding/json, method (Delim) String() string
+pkg encoding/json, type Delim int32
+pkg encoding/json, type Token interface {}
+pkg encoding/json, type UnmarshalTypeError struct, Offset int64
+pkg flag, func UnquoteUsage(*Flag) (string, string)
+pkg go/ast, type EmptyStmt struct, Implicit bool
+pkg go/build, type Package struct, PkgTargetRoot string
+pkg go/constant, const Bool = 1
+pkg go/constant, const Bool Kind
+pkg go/constant, const Complex = 5
+pkg go/constant, const Complex Kind
+pkg go/constant, const Float = 4
+pkg go/constant, const Float Kind
+pkg go/constant, const Int = 3
+pkg go/constant, const Int Kind
+pkg go/constant, const String = 2
+pkg go/constant, const String Kind
+pkg go/constant, const Unknown = 0
+pkg go/constant, const Unknown Kind
+pkg go/constant, func BinaryOp(Value, token.Token, Value) Value
+pkg go/constant, func BitLen(Value) int
+pkg go/constant, func BoolVal(Value) bool
+pkg go/constant, func Bytes(Value) []uint8
+pkg go/constant, func Compare(Value, token.Token, Value) bool
+pkg go/constant, func Denom(Value) Value
+pkg go/constant, func Float32Val(Value) (float32, bool)
+pkg go/constant, func Float64Val(Value) (float64, bool)
+pkg go/constant, func Imag(Value) Value
+pkg go/constant, func Int64Val(Value) (int64, bool)
+pkg go/constant, func MakeBool(bool) Value
+pkg go/constant, func MakeFloat64(float64) Value
+pkg go/constant, func MakeFromBytes([]uint8) Value
+pkg go/constant, func MakeFromLiteral(string, token.Token, uint) Value
+pkg go/constant, func MakeImag(Value) Value
+pkg go/constant, func MakeInt64(int64) Value
+pkg go/constant, func MakeString(string) Value
+pkg go/constant, func MakeUint64(uint64) Value
+pkg go/constant, func MakeUnknown() Value
+pkg go/constant, func Num(Value) Value
+pkg go/constant, func Real(Value) Value
+pkg go/constant, func Shift(Value, token.Token, uint) Value
+pkg go/constant, func Sign(Value) int
+pkg go/constant, func StringVal(Value) string
+pkg go/constant, func Uint64Val(Value) (uint64, bool)
+pkg go/constant, func UnaryOp(token.Token, Value, uint) Value
+pkg go/constant, type Kind int
+pkg go/constant, type Value interface, Kind() Kind
+pkg go/constant, type Value interface, String() string
+pkg go/constant, type Value interface, unexported methods
+pkg go/importer, func Default() types.Importer
+pkg go/importer, func For(string, Lookup) types.Importer
+pkg go/importer, type Lookup func(string) (io.ReadCloser, error)
+pkg go/parser, func ParseExprFrom(*token.FileSet, string, interface{}, Mode) (ast.Expr, error)
+pkg go/types, const Bool = 1
+pkg go/types, const Bool BasicKind
+pkg go/types, const Byte = 8
+pkg go/types, const Byte BasicKind
+pkg go/types, const Complex128 = 16
+pkg go/types, const Complex128 BasicKind
+pkg go/types, const Complex64 = 15
+pkg go/types, const Complex64 BasicKind
+pkg go/types, const FieldVal = 0
+pkg go/types, const FieldVal SelectionKind
+pkg go/types, const Float32 = 13
+pkg go/types, const Float32 BasicKind
+pkg go/types, const Float64 = 14
+pkg go/types, const Float64 BasicKind
+pkg go/types, const Int = 2
+pkg go/types, const Int BasicKind
+pkg go/types, const Int16 = 4
+pkg go/types, const Int16 BasicKind
+pkg go/types, const Int32 = 5
+pkg go/types, const Int32 BasicKind
+pkg go/types, const Int64 = 6
+pkg go/types, const Int64 BasicKind
+pkg go/types, const Int8 = 3
+pkg go/types, const Int8 BasicKind
+pkg go/types, const Invalid = 0
+pkg go/types, const Invalid BasicKind
+pkg go/types, const IsBoolean = 1
+pkg go/types, const IsBoolean BasicInfo
+pkg go/types, const IsComplex = 16
+pkg go/types, const IsComplex BasicInfo
+pkg go/types, const IsConstType = 59
+pkg go/types, const IsConstType BasicInfo
+pkg go/types, const IsFloat = 8
+pkg go/types, const IsFloat BasicInfo
+pkg go/types, const IsInteger = 2
+pkg go/types, const IsInteger BasicInfo
+pkg go/types, const IsNumeric = 26
+pkg go/types, const IsNumeric BasicInfo
+pkg go/types, const IsOrdered = 42
+pkg go/types, const IsOrdered BasicInfo
+pkg go/types, const IsString = 32
+pkg go/types, const IsString BasicInfo
+pkg go/types, const IsUnsigned = 4
+pkg go/types, const IsUnsigned BasicInfo
+pkg go/types, const IsUntyped = 64
+pkg go/types, const IsUntyped BasicInfo
+pkg go/types, const MethodExpr = 2
+pkg go/types, const MethodExpr SelectionKind
+pkg go/types, const MethodVal = 1
+pkg go/types, const MethodVal SelectionKind
+pkg go/types, const RecvOnly = 2
+pkg go/types, const RecvOnly ChanDir
+pkg go/types, const Rune = 5
+pkg go/types, const Rune BasicKind
+pkg go/types, const SendOnly = 1
+pkg go/types, const SendOnly ChanDir
+pkg go/types, const SendRecv = 0
+pkg go/types, const SendRecv ChanDir
+pkg go/types, const String = 17
+pkg go/types, const String BasicKind
+pkg go/types, const Uint = 7
+pkg go/types, const Uint BasicKind
+pkg go/types, const Uint16 = 9
+pkg go/types, const Uint16 BasicKind
+pkg go/types, const Uint32 = 10
+pkg go/types, const Uint32 BasicKind
+pkg go/types, const Uint64 = 11
+pkg go/types, const Uint64 BasicKind
+pkg go/types, const Uint8 = 8
+pkg go/types, const Uint8 BasicKind
+pkg go/types, const Uintptr = 12
+pkg go/types, const Uintptr BasicKind
+pkg go/types, const UnsafePointer = 18
+pkg go/types, const UnsafePointer BasicKind
+pkg go/types, const UntypedBool = 19
+pkg go/types, const UntypedBool BasicKind
+pkg go/types, const UntypedComplex = 23
+pkg go/types, const UntypedComplex BasicKind
+pkg go/types, const UntypedFloat = 22
+pkg go/types, const UntypedFloat BasicKind
+pkg go/types, const UntypedInt = 20
+pkg go/types, const UntypedInt BasicKind
+pkg go/types, const UntypedNil = 25
+pkg go/types, const UntypedNil BasicKind
+pkg go/types, const UntypedRune = 21
+pkg go/types, const UntypedRune BasicKind
+pkg go/types, const UntypedString = 24
+pkg go/types, const UntypedString BasicKind
+pkg go/types, func AssertableTo(*Interface, Type) bool
+pkg go/types, func AssignableTo(Type, Type) bool
+pkg go/types, func Comparable(Type) bool
+pkg go/types, func ConvertibleTo(Type, Type) bool
+pkg go/types, func DefPredeclaredTestFuncs()
+pkg go/types, func Eval(*token.FileSet, *Package, token.Pos, string) (TypeAndValue, error)
+pkg go/types, func ExprString(ast.Expr) string
+pkg go/types, func Id(*Package, string) string
+pkg go/types, func Identical(Type, Type) bool
+pkg go/types, func Implements(Type, *Interface) bool
+pkg go/types, func IsInterface(Type) bool
+pkg go/types, func LookupFieldOrMethod(Type, bool, *Package, string) (Object, []int, bool)
+pkg go/types, func MissingMethod(Type, *Interface, bool) (*Func, bool)
+pkg go/types, func NewArray(Type, int64) *Array
+pkg go/types, func NewChan(ChanDir, Type) *Chan
+pkg go/types, func NewChecker(*Config, *token.FileSet, *Package, *Info) *Checker
+pkg go/types, func NewConst(token.Pos, *Package, string, Type, constant.Value) *Const
+pkg go/types, func NewField(token.Pos, *Package, string, Type, bool) *Var
+pkg go/types, func NewFunc(token.Pos, *Package, string, *Signature) *Func
+pkg go/types, func NewInterface([]*Func, []*Named) *Interface
+pkg go/types, func NewLabel(token.Pos, *Package, string) *Label
+pkg go/types, func NewMap(Type, Type) *Map
+pkg go/types, func NewMethodSet(Type) *MethodSet
+pkg go/types, func NewNamed(*TypeName, Type, []*Func) *Named
+pkg go/types, func NewPackage(string, string) *Package
+pkg go/types, func NewParam(token.Pos, *Package, string, Type) *Var
+pkg go/types, func NewPkgName(token.Pos, *Package, string, *Package) *PkgName
+pkg go/types, func NewPointer(Type) *Pointer
+pkg go/types, func NewScope(*Scope, token.Pos, token.Pos, string) *Scope
+pkg go/types, func NewSignature(*Var, *Tuple, *Tuple, bool) *Signature
+pkg go/types, func NewSlice(Type) *Slice
+pkg go/types, func NewStruct([]*Var, []string) *Struct
+pkg go/types, func NewTuple(...*Var) *Tuple
+pkg go/types, func NewTypeName(token.Pos, *Package, string, Type) *TypeName
+pkg go/types, func NewVar(token.Pos, *Package, string, Type) *Var
+pkg go/types, func ObjectString(Object, Qualifier) string
+pkg go/types, func RelativeTo(*Package) Qualifier
+pkg go/types, func SelectionString(*Selection, Qualifier) string
+pkg go/types, func TypeString(Type, Qualifier) string
+pkg go/types, func WriteExpr(*bytes.Buffer, ast.Expr)
+pkg go/types, func WriteSignature(*bytes.Buffer, *Signature, Qualifier)
+pkg go/types, func WriteType(*bytes.Buffer, Type, Qualifier)
+pkg go/types, method (*Array) Elem() Type
+pkg go/types, method (*Array) Len() int64
+pkg go/types, method (*Array) String() string
+pkg go/types, method (*Array) Underlying() Type
+pkg go/types, method (*Basic) Info() BasicInfo
+pkg go/types, method (*Basic) Kind() BasicKind
+pkg go/types, method (*Basic) Name() string
+pkg go/types, method (*Basic) String() string
+pkg go/types, method (*Basic) Underlying() Type
+pkg go/types, method (*Builtin) Exported() bool
+pkg go/types, method (*Builtin) Id() string
+pkg go/types, method (*Builtin) Name() string
+pkg go/types, method (*Builtin) Parent() *Scope
+pkg go/types, method (*Builtin) Pkg() *Package
+pkg go/types, method (*Builtin) Pos() token.Pos
+pkg go/types, method (*Builtin) String() string
+pkg go/types, method (*Builtin) Type() Type
+pkg go/types, method (*Chan) Dir() ChanDir
+pkg go/types, method (*Chan) Elem() Type
+pkg go/types, method (*Chan) String() string
+pkg go/types, method (*Chan) Underlying() Type
+pkg go/types, method (*Checker) Files([]*ast.File) error
+pkg go/types, method (*Config) Check(string, *token.FileSet, []*ast.File, *Info) (*Package, error)
+pkg go/types, method (*Const) Exported() bool
+pkg go/types, method (*Const) Id() string
+pkg go/types, method (*Const) Name() string
+pkg go/types, method (*Const) Parent() *Scope
+pkg go/types, method (*Const) Pkg() *Package
+pkg go/types, method (*Const) Pos() token.Pos
+pkg go/types, method (*Const) String() string
+pkg go/types, method (*Const) Type() Type
+pkg go/types, method (*Const) Val() constant.Value
+pkg go/types, method (*Func) Exported() bool
+pkg go/types, method (*Func) FullName() string
+pkg go/types, method (*Func) Id() string
+pkg go/types, method (*Func) Name() string
+pkg go/types, method (*Func) Parent() *Scope
+pkg go/types, method (*Func) Pkg() *Package
+pkg go/types, method (*Func) Pos() token.Pos
+pkg go/types, method (*Func) Scope() *Scope
+pkg go/types, method (*Func) String() string
+pkg go/types, method (*Func) Type() Type
+pkg go/types, method (*Info) ObjectOf(*ast.Ident) Object
+pkg go/types, method (*Info) TypeOf(ast.Expr) Type
+pkg go/types, method (*Initializer) String() string
+pkg go/types, method (*Interface) Complete() *Interface
+pkg go/types, method (*Interface) Embedded(int) *Named
+pkg go/types, method (*Interface) Empty() bool
+pkg go/types, method (*Interface) ExplicitMethod(int) *Func
+pkg go/types, method (*Interface) Method(int) *Func
+pkg go/types, method (*Interface) NumEmbeddeds() int
+pkg go/types, method (*Interface) NumExplicitMethods() int
+pkg go/types, method (*Interface) NumMethods() int
+pkg go/types, method (*Interface) String() string
+pkg go/types, method (*Interface) Underlying() Type
+pkg go/types, method (*Label) Exported() bool
+pkg go/types, method (*Label) Id() string
+pkg go/types, method (*Label) Name() string
+pkg go/types, method (*Label) Parent() *Scope
+pkg go/types, method (*Label) Pkg() *Package
+pkg go/types, method (*Label) Pos() token.Pos
+pkg go/types, method (*Label) String() string
+pkg go/types, method (*Label) Type() Type
+pkg go/types, method (*Map) Elem() Type
+pkg go/types, method (*Map) Key() Type
+pkg go/types, method (*Map) String() string
+pkg go/types, method (*Map) Underlying() Type
+pkg go/types, method (*MethodSet) At(int) *Selection
+pkg go/types, method (*MethodSet) Len() int
+pkg go/types, method (*MethodSet) Lookup(*Package, string) *Selection
+pkg go/types, method (*MethodSet) String() string
+pkg go/types, method (*Named) AddMethod(*Func)
+pkg go/types, method (*Named) Method(int) *Func
+pkg go/types, method (*Named) NumMethods() int
+pkg go/types, method (*Named) Obj() *TypeName
+pkg go/types, method (*Named) SetUnderlying(Type)
+pkg go/types, method (*Named) String() string
+pkg go/types, method (*Named) Underlying() Type
+pkg go/types, method (*Nil) Exported() bool
+pkg go/types, method (*Nil) Id() string
+pkg go/types, method (*Nil) Name() string
+pkg go/types, method (*Nil) Parent() *Scope
+pkg go/types, method (*Nil) Pkg() *Package
+pkg go/types, method (*Nil) Pos() token.Pos
+pkg go/types, method (*Nil) String() string
+pkg go/types, method (*Nil) Type() Type
+pkg go/types, method (*Package) Complete() bool
+pkg go/types, method (*Package) Imports() []*Package
+pkg go/types, method (*Package) MarkComplete()
+pkg go/types, method (*Package) Name() string
+pkg go/types, method (*Package) Path() string
+pkg go/types, method (*Package) Scope() *Scope
+pkg go/types, method (*Package) SetImports([]*Package)
+pkg go/types, method (*Package) String() string
+pkg go/types, method (*PkgName) Exported() bool
+pkg go/types, method (*PkgName) Id() string
+pkg go/types, method (*PkgName) Imported() *Package
+pkg go/types, method (*PkgName) Name() string
+pkg go/types, method (*PkgName) Parent() *Scope
+pkg go/types, method (*PkgName) Pkg() *Package
+pkg go/types, method (*PkgName) Pos() token.Pos
+pkg go/types, method (*PkgName) String() string
+pkg go/types, method (*PkgName) Type() Type
+pkg go/types, method (*Pointer) Elem() Type
+pkg go/types, method (*Pointer) String() string
+pkg go/types, method (*Pointer) Underlying() Type
+pkg go/types, method (*Scope) Child(int) *Scope
+pkg go/types, method (*Scope) Contains(token.Pos) bool
+pkg go/types, method (*Scope) End() token.Pos
+pkg go/types, method (*Scope) Innermost(token.Pos) *Scope
+pkg go/types, method (*Scope) Insert(Object) Object
+pkg go/types, method (*Scope) Len() int
+pkg go/types, method (*Scope) Lookup(string) Object
+pkg go/types, method (*Scope) LookupParent(string, token.Pos) (*Scope, Object)
+pkg go/types, method (*Scope) Names() []string
+pkg go/types, method (*Scope) NumChildren() int
+pkg go/types, method (*Scope) Parent() *Scope
+pkg go/types, method (*Scope) Pos() token.Pos
+pkg go/types, method (*Scope) String() string
+pkg go/types, method (*Scope) WriteTo(io.Writer, int, bool)
+pkg go/types, method (*Selection) Index() []int
+pkg go/types, method (*Selection) Indirect() bool
+pkg go/types, method (*Selection) Kind() SelectionKind
+pkg go/types, method (*Selection) Obj() Object
+pkg go/types, method (*Selection) Recv() Type
+pkg go/types, method (*Selection) String() string
+pkg go/types, method (*Selection) Type() Type
+pkg go/types, method (*Signature) Params() *Tuple
+pkg go/types, method (*Signature) Recv() *Var
+pkg go/types, method (*Signature) Results() *Tuple
+pkg go/types, method (*Signature) String() string
+pkg go/types, method (*Signature) Underlying() Type
+pkg go/types, method (*Signature) Variadic() bool
+pkg go/types, method (*Slice) Elem() Type
+pkg go/types, method (*Slice) String() string
+pkg go/types, method (*Slice) Underlying() Type
+pkg go/types, method (*StdSizes) Alignof(Type) int64
+pkg go/types, method (*StdSizes) Offsetsof([]*Var) []int64
+pkg go/types, method (*StdSizes) Sizeof(Type) int64
+pkg go/types, method (*Struct) Field(int) *Var
+pkg go/types, method (*Struct) NumFields() int
+pkg go/types, method (*Struct) String() string
+pkg go/types, method (*Struct) Tag(int) string
+pkg go/types, method (*Struct) Underlying() Type
+pkg go/types, method (*Tuple) At(int) *Var
+pkg go/types, method (*Tuple) Len() int
+pkg go/types, method (*Tuple) String() string
+pkg go/types, method (*Tuple) Underlying() Type
+pkg go/types, method (*TypeName) Exported() bool
+pkg go/types, method (*TypeName) Id() string
+pkg go/types, method (*TypeName) Name() string
+pkg go/types, method (*TypeName) Parent() *Scope
+pkg go/types, method (*TypeName) Pkg() *Package
+pkg go/types, method (*TypeName) Pos() token.Pos
+pkg go/types, method (*TypeName) String() string
+pkg go/types, method (*TypeName) Type() Type
+pkg go/types, method (*Var) Anonymous() bool
+pkg go/types, method (*Var) Exported() bool
+pkg go/types, method (*Var) Id() string
+pkg go/types, method (*Var) IsField() bool
+pkg go/types, method (*Var) Name() string
+pkg go/types, method (*Var) Parent() *Scope
+pkg go/types, method (*Var) Pkg() *Package
+pkg go/types, method (*Var) Pos() token.Pos
+pkg go/types, method (*Var) String() string
+pkg go/types, method (*Var) Type() Type
+pkg go/types, method (Checker) ObjectOf(*ast.Ident) Object
+pkg go/types, method (Checker) TypeOf(ast.Expr) Type
+pkg go/types, method (Error) Error() string
+pkg go/types, method (TypeAndValue) Addressable() bool
+pkg go/types, method (TypeAndValue) Assignable() bool
+pkg go/types, method (TypeAndValue) HasOk() bool
+pkg go/types, method (TypeAndValue) IsBuiltin() bool
+pkg go/types, method (TypeAndValue) IsNil() bool
+pkg go/types, method (TypeAndValue) IsType() bool
+pkg go/types, method (TypeAndValue) IsValue() bool
+pkg go/types, method (TypeAndValue) IsVoid() bool
+pkg go/types, type Array struct
+pkg go/types, type Basic struct
+pkg go/types, type BasicInfo int
+pkg go/types, type BasicKind int
+pkg go/types, type Builtin struct
+pkg go/types, type Chan struct
+pkg go/types, type ChanDir int
+pkg go/types, type Checker struct
+pkg go/types, type Checker struct, embedded *Info
+pkg go/types, type Config struct
+pkg go/types, type Config struct, DisableUnusedImportCheck bool
+pkg go/types, type Config struct, Error func(error)
+pkg go/types, type Config struct, FakeImportC bool
+pkg go/types, type Config struct, IgnoreFuncBodies bool
+pkg go/types, type Config struct, Importer Importer
+pkg go/types, type Config struct, Sizes Sizes
+pkg go/types, type Const struct
+pkg go/types, type Error struct
+pkg go/types, type Error struct, Fset *token.FileSet
+pkg go/types, type Error struct, Msg string
+pkg go/types, type Error struct, Pos token.Pos
+pkg go/types, type Error struct, Soft bool
+pkg go/types, type Func struct
+pkg go/types, type Importer interface { Import }
+pkg go/types, type Importer interface, Import(string) (*Package, error)
+pkg go/types, type Info struct
+pkg go/types, type Info struct, Defs map[*ast.Ident]Object
+pkg go/types, type Info struct, Implicits map[ast.Node]Object
+pkg go/types, type Info struct, InitOrder []*Initializer
+pkg go/types, type Info struct, Scopes map[ast.Node]*Scope
+pkg go/types, type Info struct, Selections map[*ast.SelectorExpr]*Selection
+pkg go/types, type Info struct, Types map[ast.Expr]TypeAndValue
+pkg go/types, type Info struct, Uses map[*ast.Ident]Object
+pkg go/types, type Initializer struct
+pkg go/types, type Initializer struct, Lhs []*Var
+pkg go/types, type Initializer struct, Rhs ast.Expr
+pkg go/types, type Interface struct
+pkg go/types, type Label struct
+pkg go/types, type Map struct
+pkg go/types, type MethodSet struct
+pkg go/types, type Named struct
+pkg go/types, type Nil struct
+pkg go/types, type Object interface, Exported() bool
+pkg go/types, type Object interface, Id() string
+pkg go/types, type Object interface, Name() string
+pkg go/types, type Object interface, Parent() *Scope
+pkg go/types, type Object interface, Pkg() *Package
+pkg go/types, type Object interface, Pos() token.Pos
+pkg go/types, type Object interface, String() string
+pkg go/types, type Object interface, Type() Type
+pkg go/types, type Object interface, unexported methods
+pkg go/types, type Package struct
+pkg go/types, type PkgName struct
+pkg go/types, type Pointer struct
+pkg go/types, type Qualifier func(*Package) string
+pkg go/types, type Scope struct
+pkg go/types, type Selection struct
+pkg go/types, type SelectionKind int
+pkg go/types, type Signature struct
+pkg go/types, type Sizes interface { Alignof, Offsetsof, Sizeof }
+pkg go/types, type Sizes interface, Alignof(Type) int64
+pkg go/types, type Sizes interface, Offsetsof([]*Var) []int64
+pkg go/types, type Sizes interface, Sizeof(Type) int64
+pkg go/types, type Slice struct
+pkg go/types, type StdSizes struct
+pkg go/types, type StdSizes struct, MaxAlign int64
+pkg go/types, type StdSizes struct, WordSize int64
+pkg go/types, type Struct struct
+pkg go/types, type Tuple struct
+pkg go/types, type Type interface { String, Underlying }
+pkg go/types, type Type interface, String() string
+pkg go/types, type Type interface, Underlying() Type
+pkg go/types, type TypeAndValue struct
+pkg go/types, type TypeAndValue struct, Type Type
+pkg go/types, type TypeAndValue struct, Value constant.Value
+pkg go/types, type TypeName struct
+pkg go/types, type Var struct
+pkg go/types, var Typ []*Basic
+pkg go/types, var Universe *Scope
+pkg go/types, var Unsafe *Package
+pkg html/template, method (*Template) Option(...string) *Template
+pkg image, const YCbCrSubsampleRatio410 = 5
+pkg image, const YCbCrSubsampleRatio410 YCbCrSubsampleRatio
+pkg image, const YCbCrSubsampleRatio411 = 4
+pkg image, const YCbCrSubsampleRatio411 YCbCrSubsampleRatio
+pkg image, func NewCMYK(Rectangle) *CMYK
+pkg image, method (*CMYK) At(int, int) color.Color
+pkg image, method (*CMYK) Bounds() Rectangle
+pkg image, method (*CMYK) CMYKAt(int, int) color.CMYK
+pkg image, method (*CMYK) ColorModel() color.Model
+pkg image, method (*CMYK) Opaque() bool
+pkg image, method (*CMYK) PixOffset(int, int) int
+pkg image, method (*CMYK) Set(int, int, color.Color)
+pkg image, method (*CMYK) SetCMYK(int, int, color.CMYK)
+pkg image, method (*CMYK) SubImage(Rectangle) Image
+pkg image, method (Rectangle) At(int, int) color.Color
+pkg image, method (Rectangle) Bounds() Rectangle
+pkg image, method (Rectangle) ColorModel() color.Model
+pkg image, type CMYK struct
+pkg image, type CMYK struct, Pix []uint8
+pkg image, type CMYK struct, Rect Rectangle
+pkg image, type CMYK struct, Stride int
+pkg image/color, func CMYKToRGB(uint8, uint8, uint8, uint8) (uint8, uint8, uint8)
+pkg image/color, func RGBToCMYK(uint8, uint8, uint8) (uint8, uint8, uint8, uint8)
+pkg image/color, method (CMYK) RGBA() (uint32, uint32, uint32, uint32)
+pkg image/color, type CMYK struct
+pkg image/color, type CMYK struct, C uint8
+pkg image/color, type CMYK struct, K uint8
+pkg image/color, type CMYK struct, M uint8
+pkg image/color, type CMYK struct, Y uint8
+pkg image/color, var CMYKModel Model
+pkg image/gif, const DisposalBackground = 2
+pkg image/gif, const DisposalBackground ideal-int
+pkg image/gif, const DisposalNone = 1
+pkg image/gif, const DisposalNone ideal-int
+pkg image/gif, const DisposalPrevious = 3
+pkg image/gif, const DisposalPrevious ideal-int
+pkg image/gif, type GIF struct, BackgroundIndex uint8
+pkg image/gif, type GIF struct, Config image.Config
+pkg image/gif, type GIF struct, Disposal []uint8
+pkg io, func CopyBuffer(Writer, Reader, []uint8) (int64, error)
+pkg log, const LUTC = 32
+pkg log, const LUTC ideal-int
+pkg log, func Output(int, string) error
+pkg log, method (*Logger) SetOutput(io.Writer)
+pkg math/big, const Above = 1
+pkg math/big, const Above Accuracy
+pkg math/big, const AwayFromZero = 3
+pkg math/big, const AwayFromZero RoundingMode
+pkg math/big, const Below = -1
+pkg math/big, const Below Accuracy
+pkg math/big, const Exact = 0
+pkg math/big, const Exact Accuracy
+pkg math/big, const MaxExp = 2147483647
+pkg math/big, const MaxExp ideal-int
+pkg math/big, const MaxPrec = 4294967295
+pkg math/big, const MaxPrec ideal-int
+pkg math/big, const MinExp = -2147483648
+pkg math/big, const MinExp ideal-int
+pkg math/big, const ToNearestAway = 1
+pkg math/big, const ToNearestAway RoundingMode
+pkg math/big, const ToNearestEven = 0
+pkg math/big, const ToNearestEven RoundingMode
+pkg math/big, const ToNegativeInf = 4
+pkg math/big, const ToNegativeInf RoundingMode
+pkg math/big, const ToPositiveInf = 5
+pkg math/big, const ToPositiveInf RoundingMode
+pkg math/big, const ToZero = 2
+pkg math/big, const ToZero RoundingMode
+pkg math/big, func Jacobi(*Int, *Int) int
+pkg math/big, func NewFloat(float64) *Float
+pkg math/big, func ParseFloat(string, int, uint, RoundingMode) (*Float, int, error)
+pkg math/big, method (*Float) Abs(*Float) *Float
+pkg math/big, method (*Float) Acc() Accuracy
+pkg math/big, method (*Float) Add(*Float, *Float) *Float
+pkg math/big, method (*Float) Append([]uint8, uint8, int) []uint8
+pkg math/big, method (*Float) Cmp(*Float) int
+pkg math/big, method (*Float) Copy(*Float) *Float
+pkg math/big, method (*Float) Float32() (float32, Accuracy)
+pkg math/big, method (*Float) Float64() (float64, Accuracy)
+pkg math/big, method (*Float) Format(fmt.State, int32)
+pkg math/big, method (*Float) Int(*Int) (*Int, Accuracy)
+pkg math/big, method (*Float) Int64() (int64, Accuracy)
+pkg math/big, method (*Float) IsInf() bool
+pkg math/big, method (*Float) IsInt() bool
+pkg math/big, method (*Float) MantExp(*Float) int
+pkg math/big, method (*Float) MinPrec() uint
+pkg math/big, method (*Float) Mode() RoundingMode
+pkg math/big, method (*Float) Mul(*Float, *Float) *Float
+pkg math/big, method (*Float) Neg(*Float) *Float
+pkg math/big, method (*Float) Parse(string, int) (*Float, int, error)
+pkg math/big, method (*Float) Prec() uint
+pkg math/big, method (*Float) Quo(*Float, *Float) *Float
+pkg math/big, method (*Float) Rat(*Rat) (*Rat, Accuracy)
+pkg math/big, method (*Float) Set(*Float) *Float
+pkg math/big, method (*Float) SetFloat64(float64) *Float
+pkg math/big, method (*Float) SetInf(bool) *Float
+pkg math/big, method (*Float) SetInt(*Int) *Float
+pkg math/big, method (*Float) SetInt64(int64) *Float
+pkg math/big, method (*Float) SetMantExp(*Float, int) *Float
+pkg math/big, method (*Float) SetMode(RoundingMode) *Float
+pkg math/big, method (*Float) SetPrec(uint) *Float
+pkg math/big, method (*Float) SetRat(*Rat) *Float
+pkg math/big, method (*Float) SetString(string) (*Float, bool)
+pkg math/big, method (*Float) SetUint64(uint64) *Float
+pkg math/big, method (*Float) Sign() int
+pkg math/big, method (*Float) Signbit() bool
+pkg math/big, method (*Float) String() string
+pkg math/big, method (*Float) Sub(*Float, *Float) *Float
+pkg math/big, method (*Float) Text(uint8, int) string
+pkg math/big, method (*Float) Uint64() (uint64, Accuracy)
+pkg math/big, method (*Int) ModSqrt(*Int, *Int) *Int
+pkg math/big, method (Accuracy) String() string
+pkg math/big, method (ErrNaN) Error() string
+pkg math/big, method (RoundingMode) String() string
+pkg math/big, type Accuracy int8
+pkg math/big, type ErrNaN struct
+pkg math/big, type Float struct
+pkg math/big, type RoundingMode uint8
+pkg mime, const BEncoding = 98
+pkg mime, const BEncoding WordEncoder
+pkg mime, const QEncoding = 113
+pkg mime, const QEncoding WordEncoder
+pkg mime, func ExtensionsByType(string) ([]string, error)
+pkg mime, method (*WordDecoder) Decode(string) (string, error)
+pkg mime, method (*WordDecoder) DecodeHeader(string) (string, error)
+pkg mime, method (WordEncoder) Encode(string, string) string
+pkg mime, type WordDecoder struct
+pkg mime, type WordDecoder struct, CharsetReader func(string, io.Reader) (io.Reader, error)
+pkg mime, type WordEncoder uint8
+pkg mime/quotedprintable, func NewReader(io.Reader) *Reader
+pkg mime/quotedprintable, func NewWriter(io.Writer) *Writer
+pkg mime/quotedprintable, method (*Reader) Read([]uint8) (int, error)
+pkg mime/quotedprintable, method (*Writer) Close() error
+pkg mime/quotedprintable, method (*Writer) Write([]uint8) (int, error)
+pkg mime/quotedprintable, type Reader struct
+pkg mime/quotedprintable, type Writer struct
+pkg mime/quotedprintable, type Writer struct, Binary bool
+pkg net, type Dialer struct, FallbackDelay time.Duration
+pkg net, type OpError struct, Source Addr
+pkg net/http, type Request struct, Cancel <-chan struct
+pkg net/http/fcgi, var ErrConnClosed error
+pkg net/http/fcgi, var ErrRequestAborted error
+pkg net/http/pprof, func Trace(http.ResponseWriter, *http.Request)
+pkg net/mail, method (*AddressParser) Parse(string) (*Address, error)
+pkg net/mail, method (*AddressParser) ParseList(string) ([]*Address, error)
+pkg net/mail, type AddressParser struct
+pkg net/mail, type AddressParser struct, WordDecoder *mime.WordDecoder
+pkg net/smtp, method (*Client) TLSConnectionState() (tls.ConnectionState, bool)
+pkg net/url, method (*URL) EscapedPath() string
+pkg net/url, type URL struct, RawPath string
+pkg os, func LookupEnv(string) (string, bool)
+pkg os/signal, func Ignore(...os.Signal)
+pkg os/signal, func Reset(...os.Signal)
+pkg reflect, func ArrayOf(int, Type) Type
+pkg reflect, func FuncOf([]Type, []Type, bool) Type
+pkg runtime, func ReadTrace() []uint8
+pkg runtime, func StartTrace() error
+pkg runtime, func StopTrace()
+pkg runtime, type MemStats struct, GCCPUFraction float64
+pkg runtime/trace, func Start(io.Writer) error
+pkg runtime/trace, func Stop()
+pkg strings, func Compare(string, string) int
+pkg strings, func LastIndexByte(string, uint8) int
+pkg strings, method (*Reader) Size() int64
+pkg syscall (darwin-386), type SysProcAttr struct, Ctty int
+pkg syscall (darwin-386), type SysProcAttr struct, Foreground bool
+pkg syscall (darwin-386), type SysProcAttr struct, Pgid int
+pkg syscall (darwin-386-cgo), type SysProcAttr struct, Ctty int
+pkg syscall (darwin-386-cgo), type SysProcAttr struct, Foreground bool
+pkg syscall (darwin-386-cgo), type SysProcAttr struct, Pgid int
+pkg syscall (darwin-amd64), type SysProcAttr struct, Ctty int
+pkg syscall (darwin-amd64), type SysProcAttr struct, Foreground bool
+pkg syscall (darwin-amd64), type SysProcAttr struct, Pgid int
+pkg syscall (darwin-amd64-cgo), type SysProcAttr struct, Ctty int
+pkg syscall (darwin-amd64-cgo), type SysProcAttr struct, Foreground bool
+pkg syscall (darwin-amd64-cgo), type SysProcAttr struct, Pgid int
+pkg syscall (freebsd-386), type SysProcAttr struct, Ctty int
+pkg syscall (freebsd-386), type SysProcAttr struct, Foreground bool
+pkg syscall (freebsd-386), type SysProcAttr struct, Pgid int
+pkg syscall (freebsd-386-cgo), type SysProcAttr struct, Ctty int
+pkg syscall (freebsd-386-cgo), type SysProcAttr struct, Foreground bool
+pkg syscall (freebsd-386-cgo), type SysProcAttr struct, Pgid int
+pkg syscall (freebsd-amd64), type SysProcAttr struct, Ctty int
+pkg syscall (freebsd-amd64), type SysProcAttr struct, Foreground bool
+pkg syscall (freebsd-amd64), type SysProcAttr struct, Pgid int
+pkg syscall (freebsd-amd64-cgo), type SysProcAttr struct, Ctty int
+pkg syscall (freebsd-amd64-cgo), type SysProcAttr struct, Foreground bool
+pkg syscall (freebsd-amd64-cgo), type SysProcAttr struct, Pgid int
+pkg syscall (freebsd-arm), type SysProcAttr struct, Ctty int
+pkg syscall (freebsd-arm), type SysProcAttr struct, Foreground bool
+pkg syscall (freebsd-arm), type SysProcAttr struct, Pgid int
+pkg syscall (freebsd-arm-cgo), type SysProcAttr struct, Ctty int
+pkg syscall (freebsd-arm-cgo), type SysProcAttr struct, Foreground bool
+pkg syscall (freebsd-arm-cgo), type SysProcAttr struct, Pgid int
+pkg syscall (linux-386), type SysProcAttr struct, Foreground bool
+pkg syscall (linux-386), type SysProcAttr struct, GidMappingsEnableSetgroups bool
+pkg syscall (linux-386), type SysProcAttr struct, Pgid int
+pkg syscall (linux-386-cgo), type SysProcAttr struct, Foreground bool
+pkg syscall (linux-386-cgo), type SysProcAttr struct, GidMappingsEnableSetgroups bool
+pkg syscall (linux-386-cgo), type SysProcAttr struct, Pgid int
+pkg syscall (linux-amd64), type SysProcAttr struct, Foreground bool
+pkg syscall (linux-amd64), type SysProcAttr struct, GidMappingsEnableSetgroups bool
+pkg syscall (linux-amd64), type SysProcAttr struct, Pgid int
+pkg syscall (linux-amd64-cgo), type SysProcAttr struct, Foreground bool
+pkg syscall (linux-amd64-cgo), type SysProcAttr struct, GidMappingsEnableSetgroups bool
+pkg syscall (linux-amd64-cgo), type SysProcAttr struct, Pgid int
+pkg syscall (linux-arm), type SysProcAttr struct, Foreground bool
+pkg syscall (linux-arm), type SysProcAttr struct, GidMappingsEnableSetgroups bool
+pkg syscall (linux-arm), type SysProcAttr struct, Pgid int
+pkg syscall (linux-arm-cgo), type SysProcAttr struct, Foreground bool
+pkg syscall (linux-arm-cgo), type SysProcAttr struct, GidMappingsEnableSetgroups bool
+pkg syscall (linux-arm-cgo), type SysProcAttr struct, Pgid int
+pkg syscall (netbsd-386), type SysProcAttr struct, Ctty int
+pkg syscall (netbsd-386), type SysProcAttr struct, Foreground bool
+pkg syscall (netbsd-386), type SysProcAttr struct, Pgid int
+pkg syscall (netbsd-386-cgo), type SysProcAttr struct, Ctty int
+pkg syscall (netbsd-386-cgo), type SysProcAttr struct, Foreground bool
+pkg syscall (netbsd-386-cgo), type SysProcAttr struct, Pgid int
+pkg syscall (netbsd-amd64), type SysProcAttr struct, Ctty int
+pkg syscall (netbsd-amd64), type SysProcAttr struct, Foreground bool
+pkg syscall (netbsd-amd64), type SysProcAttr struct, Pgid int
+pkg syscall (netbsd-amd64-cgo), type SysProcAttr struct, Ctty int
+pkg syscall (netbsd-amd64-cgo), type SysProcAttr struct, Foreground bool
+pkg syscall (netbsd-amd64-cgo), type SysProcAttr struct, Pgid int
+pkg syscall (netbsd-arm), type SysProcAttr struct, Ctty int
+pkg syscall (netbsd-arm), type SysProcAttr struct, Foreground bool
+pkg syscall (netbsd-arm), type SysProcAttr struct, Pgid int
+pkg syscall (netbsd-arm-cgo), type SysProcAttr struct, Ctty int
+pkg syscall (netbsd-arm-cgo), type SysProcAttr struct, Foreground bool
+pkg syscall (netbsd-arm-cgo), type SysProcAttr struct, Pgid int
+pkg syscall (openbsd-386), type SysProcAttr struct, Ctty int
+pkg syscall (openbsd-386), type SysProcAttr struct, Foreground bool
+pkg syscall (openbsd-386), type SysProcAttr struct, Pgid int
+pkg syscall (openbsd-386-cgo), type SysProcAttr struct, Ctty int
+pkg syscall (openbsd-386-cgo), type SysProcAttr struct, Foreground bool
+pkg syscall (openbsd-386-cgo), type SysProcAttr struct, Pgid int
+pkg syscall (openbsd-amd64), type SysProcAttr struct, Ctty int
+pkg syscall (openbsd-amd64), type SysProcAttr struct, Foreground bool
+pkg syscall (openbsd-amd64), type SysProcAttr struct, Pgid int
+pkg syscall (openbsd-amd64-cgo), type SysProcAttr struct, Ctty int
+pkg syscall (openbsd-amd64-cgo), type SysProcAttr struct, Foreground bool
+pkg syscall (openbsd-amd64-cgo), type SysProcAttr struct, Pgid int
+pkg text/template, method (*Template) DefinedTemplates() string
+pkg text/template, method (*Template) Option(...string) *Template
+pkg time, method (Time) AppendFormat([]uint8, string) []uint8
+pkg unicode, const Version = "8.0.0"
+pkg unicode, var Ahom *RangeTable
+pkg unicode, var Anatolian_Hieroglyphs *RangeTable
+pkg unicode, var Hatran *RangeTable
+pkg unicode, var Multani *RangeTable
+pkg unicode, var Old_Hungarian *RangeTable
+pkg unicode, var SignWriting *RangeTable
diff --git a/api/next.txt b/api/next.txt
index e8570a6..e69de29 100644
--- a/api/next.txt
+++ b/api/next.txt
@@ -1,141 +0,0 @@
-pkg debug/goobj, const SBSS = 21
-pkg debug/goobj, const SBSS SymKind
-pkg debug/goobj, const SCONST = 31
-pkg debug/goobj, const SCONST SymKind
-pkg debug/goobj, const SDATA = 19
-pkg debug/goobj, const SDATA SymKind
-pkg debug/goobj, const SDYNIMPORT = 32
-pkg debug/goobj, const SDYNIMPORT SymKind
-pkg debug/goobj, const SELFROSECT = 12
-pkg debug/goobj, const SELFROSECT SymKind
-pkg debug/goobj, const SELFRXSECT = 2
-pkg debug/goobj, const SELFRXSECT SymKind
-pkg debug/goobj, const SELFSECT = 14
-pkg debug/goobj, const SELFSECT SymKind
-pkg debug/goobj, const SFILE = 29
-pkg debug/goobj, const SFILE SymKind
-pkg debug/goobj, const SFILEPATH = 30
-pkg debug/goobj, const SFILEPATH SymKind
-pkg debug/goobj, const SFUNCTAB = 8
-pkg debug/goobj, const SFUNCTAB SymKind
-pkg debug/goobj, const SGOFUNC = 6
-pkg debug/goobj, const SGOFUNC SymKind
-pkg debug/goobj, const SGOSTRING = 5
-pkg debug/goobj, const SGOSTRING SymKind
-pkg debug/goobj, const SHOSTOBJ = 33
-pkg debug/goobj, const SHOSTOBJ SymKind
-pkg debug/goobj, const SINITARR = 18
-pkg debug/goobj, const SINITARR SymKind
-pkg debug/goobj, const SMACHO = 15
-pkg debug/goobj, const SMACHO SymKind
-pkg debug/goobj, const SMACHOGOT = 16
-pkg debug/goobj, const SMACHOGOT SymKind
-pkg debug/goobj, const SMACHOINDIRECTGOT = 28
-pkg debug/goobj, const SMACHOINDIRECTGOT SymKind
-pkg debug/goobj, const SMACHOINDIRECTPLT = 27
-pkg debug/goobj, const SMACHOINDIRECTPLT SymKind
-pkg debug/goobj, const SMACHOPLT = 13
-pkg debug/goobj, const SMACHOPLT SymKind
-pkg debug/goobj, const SMACHOSYMSTR = 25
-pkg debug/goobj, const SMACHOSYMSTR SymKind
-pkg debug/goobj, const SMACHOSYMTAB = 26
-pkg debug/goobj, const SMACHOSYMTAB SymKind
-pkg debug/goobj, const SNOPTRBSS = 22
-pkg debug/goobj, const SNOPTRBSS SymKind
-pkg debug/goobj, const SNOPTRDATA = 17
-pkg debug/goobj, const SNOPTRDATA SymKind
-pkg debug/goobj, const SPCLNTAB = 11
-pkg debug/goobj, const SPCLNTAB SymKind
-pkg debug/goobj, const SRODATA = 7
-pkg debug/goobj, const SRODATA SymKind
-pkg debug/goobj, const SSTRING = 4
-pkg debug/goobj, const SSTRING SymKind
-pkg debug/goobj, const SSYMTAB = 10
-pkg debug/goobj, const SSYMTAB SymKind
-pkg debug/goobj, const STEXT = 1
-pkg debug/goobj, const STEXT SymKind
-pkg debug/goobj, const STLSBSS = 23
-pkg debug/goobj, const STLSBSS SymKind
-pkg debug/goobj, const STYPE = 3
-pkg debug/goobj, const STYPE SymKind
-pkg debug/goobj, const STYPELINK = 9
-pkg debug/goobj, const STYPELINK SymKind
-pkg debug/goobj, const SWINDOWS = 20
-pkg debug/goobj, const SWINDOWS SymKind
-pkg debug/goobj, const SXREF = 24
-pkg debug/goobj, const SXREF SymKind
-pkg debug/goobj, func Parse(io.ReadSeeker, string) (*Package, error)
-pkg debug/goobj, method (Sym) String() string
-pkg debug/goobj, method (SymID) String() string
-pkg debug/goobj, method (SymKind) String() string
-pkg debug/goobj, type Data struct
-pkg debug/goobj, type Data struct, Offset int64
-pkg debug/goobj, type Data struct, Size int64
-pkg debug/goobj, type Func struct
-pkg debug/goobj, type Func struct, Args int
-pkg debug/goobj, type Func struct, File []string
-pkg debug/goobj, type Func struct, Frame int
-pkg debug/goobj, type Func struct, FuncData []FuncData
-pkg debug/goobj, type Func struct, Leaf bool
-pkg debug/goobj, type Func struct, NoSplit bool
-pkg debug/goobj, type Func struct, PCData []Data
-pkg debug/goobj, type Func struct, PCFile Data
-pkg debug/goobj, type Func struct, PCLine Data
-pkg debug/goobj, type Func struct, PCSP Data
-pkg debug/goobj, type Func struct, Var []Var
-pkg debug/goobj, type FuncData struct
-pkg debug/goobj, type FuncData struct, Offset int64
-pkg debug/goobj, type FuncData struct, Sym SymID
-pkg debug/goobj, type Package struct
-pkg debug/goobj, type Package struct, ImportPath string
-pkg debug/goobj, type Package struct, Imports []string
-pkg debug/goobj, type Package struct, MaxVersion int
-pkg debug/goobj, type Package struct, Syms []*Sym
-pkg debug/goobj, type Reloc struct
-pkg debug/goobj, type Reloc struct, Add int
-pkg debug/goobj, type Reloc struct, Offset int
-pkg debug/goobj, type Reloc struct, Size int
-pkg debug/goobj, type Reloc struct, Sym SymID
-pkg debug/goobj, type Reloc struct, Type int
-pkg debug/goobj, type Sym struct
-pkg debug/goobj, type Sym struct, Data Data
-pkg debug/goobj, type Sym struct, DupOK bool
-pkg debug/goobj, type Sym struct, Func *Func
-pkg debug/goobj, type Sym struct, Kind SymKind
-pkg debug/goobj, type Sym struct, Reloc []Reloc
-pkg debug/goobj, type Sym struct, Size int
-pkg debug/goobj, type Sym struct, Type SymID
-pkg debug/goobj, type Sym struct, embedded SymID
-pkg debug/goobj, type SymID struct
-pkg debug/goobj, type SymID struct, Name string
-pkg debug/goobj, type SymID struct, Version int
-pkg debug/goobj, type SymKind int
-pkg debug/goobj, type Var struct
-pkg debug/goobj, type Var struct, Kind int
-pkg debug/goobj, type Var struct, Name string
-pkg debug/goobj, type Var struct, Offset int
-pkg debug/goobj, type Var struct, Type SymID
-pkg unicode, const Version = "7.0.0"
-pkg unicode, var Bassa_Vah *RangeTable
-pkg unicode, var Caucasian_Albanian *RangeTable
-pkg unicode, var Duployan *RangeTable
-pkg unicode, var Elbasan *RangeTable
-pkg unicode, var Grantha *RangeTable
-pkg unicode, var Khojki *RangeTable
-pkg unicode, var Khudawadi *RangeTable
-pkg unicode, var Linear_A *RangeTable
-pkg unicode, var Mahajani *RangeTable
-pkg unicode, var Manichaean *RangeTable
-pkg unicode, var Mende_Kikakui *RangeTable
-pkg unicode, var Modi *RangeTable
-pkg unicode, var Mro *RangeTable
-pkg unicode, var Nabataean *RangeTable
-pkg unicode, var Old_North_Arabian *RangeTable
-pkg unicode, var Old_Permic *RangeTable
-pkg unicode, var Pahawh_Hmong *RangeTable
-pkg unicode, var Palmyrene *RangeTable
-pkg unicode, var Pau_Cin_Hau *RangeTable
-pkg unicode, var Psalter_Pahlavi *RangeTable
-pkg unicode, var Siddham *RangeTable
-pkg unicode, var Tirhuta *RangeTable
-pkg unicode, var Warang_Citi *RangeTable
diff --git a/doc/articles/go_command.html b/doc/articles/go_command.html
index 2978628..cc1d86a 100644
--- a/doc/articles/go_command.html
+++ b/doc/articles/go_command.html
@@ -250,11 +250,16 @@ projects at once within a single <code>$GOPATH</code> root directory.</p>
 <h2>Limitations</h2>
 
 <p>As mentioned above, the go command is not a general-purpose build
-tool. In particular, it does not have any facility for generating Go
-source files during a build.  Instead, if you want to use a tool like
-yacc or the protocol buffer compiler, you will need to write a
+tool.
+In particular, it does not have any facility for generating Go
+source files <em>during</em> a build, although it does provide
+<a href="/cmd/go/#hdr-Generate_Go_files_by_processing_source"><code>go</code>
+<code>generate</code></a>,
+which can automate the creation of Go files <em>before</em>
+the build, such as by running <code>yacc</code>.
+For more advanced build setups, you may need to write a
 makefile (or a configuration file for the build tool of your choice)
-to generate the Go files and then check those generated source files
+to run whatever tool creates the Go files and then check those generated source files
 into your repository. This is more work for you, the package author,
 but it is significantly less work for your users, who can use
 "<code>go get</code>" without needing to obtain and build
diff --git a/doc/articles/wiki/final-test.patch b/doc/articles/wiki/final-test.patch
new file mode 100644
index 0000000..499ad78
--- /dev/null
+++ b/doc/articles/wiki/final-test.patch
@@ -0,0 +1,36 @@
+*** final.go	2015-06-14 23:59:22.000000000 +0200
+--- final-test.go	2015-06-15 00:15:41.000000000 +0200
+***************
+*** 7,12 ****
+--- 7,14 ----
+  import (
+  	"html/template"
+  	"io/ioutil"
++ 	"log"
++ 	"net"
+  	"net/http"
+  	"regexp"
+  )
+***************
+*** 85,89 ****
+  	http.HandleFunc("/edit/", makeHandler(editHandler))
+  	http.HandleFunc("/save/", makeHandler(saveHandler))
+  
+! 	http.ListenAndServe(":8080", nil)
+  }
+--- 87,101 ----
+  	http.HandleFunc("/edit/", makeHandler(editHandler))
+  	http.HandleFunc("/save/", makeHandler(saveHandler))
+  
+! 	l, err := net.Listen("tcp", "127.0.0.1:0")
+! 	if err != nil {
+! 		log.Fatal(err)
+! 	}
+! 	err = ioutil.WriteFile("final-test-port.txt", []byte(l.Addr().String()), 0644)
+! 	if err != nil {
+! 		log.Fatal(err)
+! 	}
+! 	s := &http.Server{}
+! 	s.Serve(l)
+! 	return
+  }
diff --git a/doc/articles/wiki/final.go b/doc/articles/wiki/final.go
index d84c1ff..139a323 100644
--- a/doc/articles/wiki/final.go
+++ b/doc/articles/wiki/final.go
@@ -5,19 +5,12 @@
 package main
 
 import (
-	"flag"
 	"html/template"
 	"io/ioutil"
-	"log"
-	"net"
 	"net/http"
 	"regexp"
 )
 
-var (
-	addr = flag.Bool("addr", false, "find open address and print to final-port.txt")
-)
-
 type Page struct {
 	Title string
 	Body  []byte
@@ -88,24 +81,9 @@ func makeHandler(fn func(http.ResponseWriter, *http.Request, string)) http.Handl
 }
 
 func main() {
-	flag.Parse()
 	http.HandleFunc("/view/", makeHandler(viewHandler))
 	http.HandleFunc("/edit/", makeHandler(editHandler))
 	http.HandleFunc("/save/", makeHandler(saveHandler))
 
-	if *addr {
-		l, err := net.Listen("tcp", "127.0.0.1:0")
-		if err != nil {
-			log.Fatal(err)
-		}
-		err = ioutil.WriteFile("final-port.txt", []byte(l.Addr().String()), 0644)
-		if err != nil {
-			log.Fatal(err)
-		}
-		s := &http.Server{}
-		s.Serve(l)
-		return
-	}
-
 	http.ListenAndServe(":8080", nil)
 }
diff --git a/doc/articles/wiki/test.bash b/doc/articles/wiki/test.bash
index 2997f16..8bbb734 100755
--- a/doc/articles/wiki/test.bash
+++ b/doc/articles/wiki/test.bash
@@ -4,14 +4,20 @@
 # license that can be found in the LICENSE file.
 
 set -e
+
+if ! which patch > /dev/null; then
+	echo "Skipping test; patch command not found."
+	exit 0
+fi
+
 wiki_pid=
 cleanup() {
 	kill $wiki_pid
-	rm -f test_*.out Test.txt final.bin final-port.txt a.out get.bin
+	rm -f test_*.out Test.txt final-test.go final-test.bin final-test-port.txt a.out get.bin
 }
 trap cleanup 0 INT
 
-rm -f get.bin final.bin a.out
+rm -f get.bin final-test.bin a.out
 
 # If called with -all, check that all code snippets compile.
 if [ "$1" == "-all" ]; then
@@ -21,12 +27,14 @@ if [ "$1" == "-all" ]; then
 fi
 
 go build -o get.bin get.go
-go build -o final.bin final.go
-(./final.bin --addr) &
+cp final.go final-test.go
+patch final-test.go final-test.patch > /dev/null
+go build -o final-test.bin final-test.go
+./final-test.bin &
 wiki_pid=$!
 
 l=0
-while [ ! -f ./final-port.txt ]
+while [ ! -f ./final-test-port.txt ]
 do
 	l=$(($l+1))
 	if [ "$l" -gt 5 ]
@@ -38,7 +46,7 @@ do
 	sleep 1
 done
 
-addr=$(cat final-port.txt)
+addr=$(cat final-test-port.txt)
 ./get.bin http://$addr/edit/Test > test_edit.out
 diff -u test_edit.out test_edit.good
 ./get.bin -post=body=some%20content http://$addr/save/Test > test_save.out
diff --git a/doc/asm.html b/doc/asm.html
index 771c493..c992e14 100644
--- a/doc/asm.html
+++ b/doc/asm.html
@@ -6,16 +6,16 @@
 <h2 id="introduction">A Quick Guide to Go's Assembler</h2>
 
 <p>
-This document is a quick outline of the unusual form of assembly language used by the <code>gc</code>
-suite of Go compilers (<code>6g</code>, <code>8g</code>, etc.).
+This document is a quick outline of the unusual form of assembly language used by the <code>gc</code> Go compiler.
 The document is not comprehensive.
 </p>
 
 <p>
-The assembler is based on the input to the Plan 9 assemblers, which is documented in detail
-<a href="http://plan9.bell-labs.com/sys/doc/asm.html">on the Plan 9 site</a>.
+The assembler is based on the input style of the Plan 9 assemblers, which is documented in detail
+<a href="http://plan9.bell-labs.com/sys/doc/asm.html">elsewhere</a>.
 If you plan to write assembly language, you should read that document although much of it is Plan 9-specific.
-This document provides a summary of the syntax and
+The current document provides a summary of the syntax and the differences with
+what is explained in that document, and
 describes the peculiarities that apply when writing assembly code to interact with Go.
 </p>
 
@@ -25,10 +25,12 @@ Some of the details map precisely to the machine, but some do not.
 This is because the compiler suite (see
 <a href="http://plan9.bell-labs.com/sys/doc/compiler.html">this description</a>)
 needs no assembler pass in the usual pipeline.
-Instead, the compiler emits a kind of incompletely defined instruction set, in binary form, which the linker
-then completes.
-In particular, the linker does instruction selection, so when you see an instruction like <code>MOV</code>
-what the linker actually generates for that operation might not be a move instruction at all, perhaps a clear or load.
+Instead, the compiler operates on a kind of semi-abstract instruction set,
+and instruction selection occurs partly after code generation.
+The assembler works on the semi-abstract form, so
+when you see an instruction like <code>MOV</code>
+what the tool chain actually generates for that operation might
+not be a move instruction at all, perhaps a clear or load.
 Or it might correspond exactly to the machine instruction with that name.
 In general, machine-specific operations tend to appear as themselves, while more general concepts like
 memory move and subroutine call and return are more abstract.
@@ -36,13 +38,15 @@ The details vary with architecture, and we apologize for the imprecision; the si
 </p>
 
 <p>
-The assembler program is a way to generate that intermediate, incompletely defined instruction sequence
-as input for the linker.
+The assembler program is a way to parse a description of that
+semi-abstract instruction set and turn it into instructions to be
+input to the linker.
 If you want to see what the instructions look like in assembly for a given architecture, say amd64, there
 are many examples in the sources of the standard library, in packages such as
 <a href="/pkg/runtime/"><code>runtime</code></a> and
 <a href="/pkg/math/big/"><code>math/big</code></a>.
-You can also examine what the compiler emits as assembly code:
+You can also examine what the compiler emits as assembly code
+(the actual output may differ from what you see here):
 </p>
 
 <pre>
@@ -52,7 +56,7 @@ package main
 func main() {
 	println(3)
 }
-$ go tool 6g -S x.go        # or: go build -gcflags -S x.go
+$ GOOS=linux GOARCH=amd64 go tool compile -S x.go        # or: go build -gcflags -S x.go
 
 --- prog list "main" ---
 0000 (x.go:3) TEXT    main+0(SB),$8-0
@@ -106,20 +110,73 @@ codeblk [0x2000,0x1d059) at offset 0x1000
 
 -->
 
+<h3 id="constants">Constants</h3>
+
+<p>
+Although the assembler takes its guidance from the Plan 9 assemblers,
+it is a distinct program, so there are some differences.
+One is in constant evaluation.
+Constant expressions in the assembler are parsed using Go's operator
+precedence, not the C-like precedence of the original.
+Thus <code>3&1<<2</code> is 4, not 0—it parses as <code>(3&1)<<2</code>
+not <code>3&(1<<2)</code>.
+Also, constants are always evaluated as 64-bit unsigned integers.
+Thus <code>-2</code> is not the integer value minus two,
+but the unsigned 64-bit integer with the same bit pattern.
+The distinction rarely matters but
+to avoid ambiguity, division or right shift where the right operand's
+high bit is set is rejected.
+</p>
+
 <h3 id="symbols">Symbols</h3>
 
 <p>
-Some symbols, such as <code>PC</code>, <code>R0</code> and <code>SP</code>, are predeclared and refer to registers.
-There are two other predeclared symbols, <code>SB</code> (static base) and <code>FP</code> (frame pointer).
-All user-defined symbols other than jump labels are written as offsets to these pseudo-registers.
+Some symbols, such as <code>R1</code> or <code>LR</code>,
+are predefined and refer to registers.
+The exact set depends on the architecture.
+</p>
+
+<p>
+There are four predeclared symbols that refer to pseudo-registers.
+These are not real registers, but rather virtual registers maintained by
+the tool chain, such as a frame pointer.
+The set of pseudo-registers is the same for all architectures:
+</p>
+
+<ul>
+
+<li>
+<code>FP</code>: Frame pointer: arguments and locals.
+</li>
+
+<li>
+<code>PC</code>: Program counter:
+jumps and branches.
+</li>
+
+<li>
+<code>SB</code>: Static base pointer: global symbols.
+</li>
+
+<li>
+<code>SP</code>: Stack pointer: top of stack.
+</li>
+
+</ul>
+
+<p>
+All user-defined symbols are written as offsets to the pseudo-registers
+<code>FP</code> (arguments and locals) and <code>SB</code> (globals).
 </p>
 
 <p>
 The <code>SB</code> pseudo-register can be thought of as the origin of memory, so the symbol <code>foo(SB)</code>
 is the name <code>foo</code> as an address in memory.
 This form is used to name global functions and data.
-Adding <code><></code> to the name, as in <code>foo<>(SB)</code>, makes the name
+Adding <code><></code> to the name, as in <span style="white-space: nowrap"><code>foo<>(SB)</code></span>, makes the name
 visible only in the current source file, like a top-level <code>static</code> declaration in a C file.
+Adding an offset to the name refers to that offset from the symbol's address, so
+<code>a+4(SB)</code> is four bytes past the start of <code>foo</code>.
 </p>
 
 <p>
@@ -128,9 +185,19 @@ used to refer to function arguments.
 The compilers maintain a virtual frame pointer and refer to the arguments on the stack as offsets from that pseudo-register.
 Thus <code>0(FP)</code> is the first argument to the function,
 <code>8(FP)</code> is the second (on a 64-bit machine), and so on.
-When referring to a function argument this way, it is conventional to place the name
+However, when referring to a function argument this way, it is necessary to place a name
 at the beginning, as in <code>first_arg+0(FP)</code> and <code>second_arg+8(FP)</code>.
-Some of the assemblers enforce this convention, rejecting plain <code>0(FP)</code> and <code>8(FP)</code>.
+(The meaning of the offset—offset from the frame pointer—distinct
+from its use with <code>SB</code>, where it is an offset from the symbol.)
+The assembler enforces this convention, rejecting plain <code>0(FP)</code> and <code>8(FP)</code>.
+The actual name is semantically irrelevant but should be used to document
+the argument's name.
+It is worth stressing that <code>FP</code> is always a
+pseudo-register, not a hardware
+register, even on architectures with a hardware frame pointer.
+</p>
+
+<p>
 For assembly functions with Go prototypes, <code>go</code> <code>vet</code> will check that the argument names
 and offsets match.
 On 32-bit systems, the low and high 32 bits of a 64-bit value are distinguished by adding
@@ -145,14 +212,54 @@ prepared for function calls.
 It points to the top of the local stack frame, so references should use negative offsets
 in the range [−framesize, 0):
 <code>x-8(SP)</code>, <code>y-4(SP)</code>, and so on.
-On architectures with a real register named <code>SP</code>, the name prefix distinguishes
-references to the virtual stack pointer from references to the architectural <code>SP</code> register.
-That is, <code>x-8(SP)</code> and <code>-8(SP)</code> are different memory locations:
-the first refers to the virtual stack pointer pseudo-register, while the second refers to the
+</p>
+
+<p>
+On architectures with a hardware register named <code>SP</code>,
+the name prefix distinguishes
+references to the virtual stack pointer from references to the architectural
+<code>SP</code> register.
+That is, <code>x-8(SP)</code> and <code>-8(SP)</code>
+are different memory locations:
+the first refers to the virtual stack pointer pseudo-register,
+while the second refers to the
 hardware's <code>SP</code> register.
 </p>
 
 <p>
+On machines where <code>SP</code> and <code>PC</code> are
+traditionally aliases for a physical, numbered register,
+in the Go assembler the names <code>SP</code> and <code>PC</code>
+are still treated specially;
+for instance, references to <code>SP</code> require a symbol,
+much like <code>FP</code>.
+To access the actual hardware register use the true <code>R</code> name.
+For example, on the ARM architecture the hardware
+<code>SP</code> and <code>PC</code> are accessible as
+<code>R13</code> and <code>R15</code>.
+</p>
+
+<p>
+Branches and direct jumps are always written as offsets to the PC, or as
+jumps to labels:
+</p>
+
+<pre>
+label:
+	MOVW $0, R1
+	JMP label
+</pre>
+
+<p>
+Each label is visible only within the function in which it is defined.
+It is therefore permitted for multiple functions in a file to define
+and use the same label names.
+Direct jumps and call instructions can target text symbols,
+such as <code>name(SB)</code>, but not offsets from symbols,
+such as <code>name+4(SB)</code>.
+</p>
+
+<p>
 Instructions, registers, and assembler directives are always in UPPER CASE to remind you
 that assembly programming is a fraught endeavor.
 (Exception: the <code>g</code> register renaming on ARM.)
@@ -312,11 +419,17 @@ This data contains no pointers and therefore does not need to be
 scanned by the garbage collector.
 </li>
 <li>
-<code>WRAPPER</code>  = 32
+<code>WRAPPER</code> = 32
 <br>
 (For <code>TEXT</code> items.)
 This is a wrapper function and should not count as disabling <code>recover</code>.
 </li>
+<li>
+<code>NEEDCTXT</code> = 64
+<br>
+(For <code>TEXT</code> items.)
+This function is a closure so it uses its incoming context register.
+</li>
 </ul>
 
 <h3 id="runtime">Runtime Coordination</h3>
@@ -350,7 +463,11 @@ live pointers in its arguments, results, and local stack frame.
 For an assembly function with no pointer results and
 either no local stack frame or no function calls,
 the only requirement is to define a Go prototype for the function
-in a Go source file in the same package.
+in a Go source file in the same package. The name of the assembly
+function must not contain the package name component (for example,
+function <code>Syscall</code> in package <code>syscall</code> should
+use the name <code>·Syscall</code> instead of the equivalent name
+<code>syscall·Syscall</code> in its <code>TEXT</code> directive).
 For more complex situations, explicit annotation is needed.
 These annotations use pseudo-instructions defined in the standard
 <code>#include</code> file <code>funcdata.h</code>.
@@ -397,42 +514,61 @@ even pointers to stack data must not be kept in local variables.
 
 <p>
 It is impractical to list all the instructions and other details for each machine.
-To see what instructions are defined for a given machine, say 32-bit Intel x86,
-look in the top-level header file for the corresponding linker, in this case <code>8l</code>.
-That is, the file <code>$GOROOT/src/cmd/8l/8.out.h</code> contains a C enumeration, called <code>as</code>,
-of the instructions and their spellings as known to the assembler and linker for that architecture.
-In that file you'll find a declaration that begins
+To see what instructions are defined for a given machine, say ARM,
+look in the source for the <code>obj</code> support library for
+that architecture, located in the directory <code>src/cmd/internal/obj/arm</code>.
+In that directory is a file <code>a.out.go</code>; it contains
+a long list of constants starting with <code>A</code>, like this:
 </p>
 
 <pre>
-enum	as
-{
-	AXXX,
-	AAAA,
-	AAAD,
-	AAAM,
-	AAAS,
-	AADCB,
+const (
+	AAND = obj.ABaseARM + obj.A_ARCHSPECIFIC + iota
+	AEOR
+	ASUB
+	ARSB
+	AADD
 	...
 </pre>
 
 <p>
-Each instruction begins with a  initial capital <code>A</code> in this list, so <code>AADCB</code>
-represents the <code>ADCB</code> (add carry byte) instruction.
-The enumeration is in alphabetical order, plus some late additions (<code>AXXX</code> occupies
-the zero slot as an invalid instruction).
-The sequence has nothing to do with the actual encoding of the machine instructions.
-Again, the linker takes care of that detail.
+This is the list of instructions and their spellings as known to the assembler and linker for that architecture.
+Each instruction begins with an initial capital <code>A</code> in this list, so <code>AAND</code>
+represents the bitwise and instruction,
+<code>AND</code> (without the leading <code>A</code>),
+and is written in assembly source as <code>AND</code>.
+The enumeration is mostly in alphabetical order.
+(The architecture-independent <code>AXXX</code>, defined in the
+<code>cmd/internal/obj</code> package,
+represents an invalid instruction).
+The sequence of the <code>A</code> names has nothing to do with the actual
+encoding of the machine instructions.
+The <code>cmd/internal/obj</code> package takes care of that detail.
+</p>
+
+<p>
+The instructions for both the 386 and AMD64 architectures are listed in
+<code>cmd/internal/obj/x86/a.out.go</code>.
+</p>
+
+<p>
+The architectures share syntax for common addressing modes such as
+<code>(R1)</code> (register indirect),
+<code>4(R1)</code> (register indirect with offset), and
+<code>$foo(SB)</code> (absolute address).
+The assembler also supports some (not necessarily all) addressing modes
+specific to each architecture.
+The sections below list these.
 </p>
 
 <p>
 One detail evident in the examples from the previous sections is that data in the instructions flows from left to right:
 <code>MOVQ</code> <code>$0,</code> <code>CX</code> clears <code>CX</code>.
-This convention applies even on architectures where the usual mode is the opposite direction.
+This rule applies even on architectures where the conventional notation uses the opposite direction.
 </p>
 
 <p>
-Here follows some descriptions of key Go-specific details for the supported architectures.
+Here follow some descriptions of key Go-specific details for the supported architectures.
 </p>
 
 <h3 id="x86">32-bit Intel 386</h3>
@@ -441,11 +577,11 @@ Here follows some descriptions of key Go-specific details for the supported arch
 The runtime pointer to the <code>g</code> structure is maintained
 through the value of an otherwise unused (as far as Go is concerned) register in the MMU.
 A OS-dependent macro <code>get_tls</code> is defined for the assembler if the source includes
-an architecture-dependent header file, like this:
+a special header, <code>go_asm.h</code>:
 </p>
 
 <pre>
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
 </pre>
 
 <p>
@@ -458,21 +594,39 @@ The sequence to load <code>g</code> and <code>m</code> using <code>CX</code> loo
 <pre>
 get_tls(CX)
 MOVL	g(CX), AX     // Move g into AX.
-MOVL	g_m(AX), BX   // Move g->m into BX.
+MOVL	g_m(AX), BX   // Move g.m into BX.
 </pre>
 
+<p>
+Addressing modes:
+</p>
+
+<ul>
+
+<li>
+<code>(DI)(BX*2)</code>: The location at address <code>DI</code> plus <code>BX*2</code>.
+</li>
+
+<li>
+<code>64(DI)(BX*2)</code>: The location at address <code>DI</code> plus <code>BX*2</code> plus 64.
+These modes accept only 1, 2, 4, and 8 as scale factors.
+</li>
+
+</ul>
+
 <h3 id="amd64">64-bit Intel 386 (a.k.a. amd64)</h3>
 
 <p>
-The assembly code to access the <code>m</code> and <code>g</code>
-pointers is the same as on the 386, except it uses <code>MOVQ</code> rather than
-<code>MOVL</code>:
+The two architectures behave largely the same at the assembler level.
+Assembly code to access the <code>m</code> and <code>g</code>
+pointers on the 64-bit version is the same as on the 32-bit 386,
+except it uses <code>MOVQ</code> rather than <code>MOVL</code>:
 </p>
 
 <pre>
 get_tls(CX)
 MOVQ	g(CX), AX     // Move g into AX.
-MOVQ	g_m(AX), BX   // Move g->m into BX.
+MOVQ	g_m(AX), BX   // Move g.m into BX.
 </pre>
 
 <h3 id="arm">ARM</h3>
@@ -509,6 +663,107 @@ The name <code>SP</code> always refers to the virtual stack pointer described ea
 For the hardware register, use <code>R13</code>.
 </p>
 
+<p>
+Condition code syntax is to append a period and the one- or two-letter code to the instruction,
+as in <code>MOVW.EQ</code>.
+Multiple codes may be appended: <code>MOVM.IA.W</code>.
+The order of the code modifiers is irrelevant.
+</p>
+
+<p>
+Addressing modes:
+</p>
+
+<ul>
+
+<li>
+<code>R0->16</code>
+<br>
+<code>R0>>16</code>
+<br>
+<code>R0<<16</code>
+<br>
+<code>R0@>16</code>:
+For <code><<</code>, left shift <code>R0</code> by 16 bits.
+The other codes are <code>-></code> (arithmetic right shift),
+<code>>></code> (logical right shift), and
+<code>@></code> (rotate right).
+</li>
+
+<li>
+<code>R0->R1</code>
+<br>
+<code>R0>>R1</code>
+<br>
+<code>R0<<R1</code>
+<br>
+<code>R0@>R1</code>:
+For <code><<</code>, left shift <code>R0</code> by the count in <code>R1</code>.
+The other codes are <code>-></code> (arithmetic right shift),
+<code>>></code> (logical right shift), and
+<code>@></code> (rotate right).
+
+</li>
+
+<li>
+<code>[R0,g,R12-R15]</code>: For multi-register instructions, the set comprising
+<code>R0</code>, <code>g</code>, and <code>R12</code> through <code>R15</code> inclusive.
+</li>
+
+<li>
+<code>(R5, R6)</code>: Destination register pair.
+</li>
+
+</ul>
+
+<h3 id="arm64">ARM64</h3>
+
+<p>
+The ARM64 port is in an experimental state.
+</p>
+
+<p>
+Instruction modifiers are appended to the instruction following a period.
+The only modifiers are <code>P</code> (postincrement) and <code>W</code>
+(preincrement):
+<code>MOVW.P</code>, <code>MOVW.W</code>
+</p>
+
+<p>
+Addressing modes:
+</p>
+
+<ul>
+
+<li>
+<code>(R5, R6)</code>: Register pair for <code>LDP</code>/<code>STP</code>.
+</li>
+
+</ul>
+
+<h3 id="ppc64">64-bit PowerPC, a.k.a. ppc64</h3>
+
+<p>
+The 64-bit PowerPC port is in an experimental state.
+</p>
+
+<p>
+Addressing modes:
+</p>
+
+<ul>
+
+<li>
+<code>(R5)(R6*1)</code>: The location at <code>R5</code> plus <code>R6</code>. It is a scaled
+mode as on the x86, but the only scale allowed is <code>1</code>.
+</li>
+
+<li>
+<code>(R5+R6)</code>: Alias for (R5)(R6*1)
+</li>
+
+</ul>
+
 <h3 id="unsupported_opcodes">Unsupported opcodes</h3>
 
 <p>
@@ -527,11 +782,17 @@ Here's how the 386 runtime defines the 64-bit atomic load function.
 // uint64 atomicload64(uint64 volatile* addr);
 // so actually
 // void atomicload64(uint64 *res, uint64 volatile *addr);
-TEXT runtime·atomicload64(SB), NOSPLIT, $0-8
+TEXT runtime·atomicload64(SB), NOSPLIT, $0-12
 	MOVL	ptr+0(FP), AX
+	TESTL	$7, AX
+	JZ	2(PC)
+	MOVL	0, AX // crash with nil ptr deref
 	LEAL	ret_lo+4(FP), BX
-	BYTE $0x0f; BYTE $0x6f; BYTE $0x00	// MOVQ (%EAX), %MM0
-	BYTE $0x0f; BYTE $0x7f; BYTE $0x03	// MOVQ %MM0, 0(%EBX)
-	BYTE $0x0F; BYTE $0x77			// EMMS
+	// MOVQ (%EAX), %MM0
+	BYTE $0x0f; BYTE $0x6f; BYTE $0x00
+	// MOVQ %MM0, 0(%EBX)
+	BYTE $0x0f; BYTE $0x7f; BYTE $0x03
+	// EMMS
+	BYTE $0x0F; BYTE $0x77
 	RET
 </pre>
diff --git a/doc/code.html b/doc/code.html
index a4638f9..8cbfba0 100644
--- a/doc/code.html
+++ b/doc/code.html
@@ -108,13 +108,14 @@ when developing Go code.
 <p>
 To get started, create a workspace directory and set <code>GOPATH</code>
 accordingly. Your workspace can be located wherever you like, but we'll use
-<code>$HOME/go</code> in this document. Note that this must <b>not</b> be the
+<code>$HOME/work</code> in this document. Note that this must <b>not</b> be the
 same path as your Go installation.
+(Another common setup is to set <code>GOPATH=$HOME</code>.)
 </p>
 
 <pre>
-$ <b>mkdir $HOME/go</b>
-$ <b>export GOPATH=$HOME/go</b>
+$ <b>mkdir $HOME/work</b>
+$ <b>export GOPATH=$HOME/work</b>
 </pre>
 
 <p>
@@ -126,6 +127,11 @@ to your <code>PATH</code>:
 $ <b>export PATH=$PATH:$GOPATH/bin</b>
 </pre>
 
+<p>
+To learn more about setting up the <code>GOPATH</code> environment variable,
+please see
+<a href="/cmd/go/#hdr-GOPATH_environment_variable"><code>go help gopath</code></a>
+</p>
 
 <h3 id="PackagePaths">Package paths</h3>
 
@@ -218,7 +224,7 @@ This command builds the <code>hello</code> command, producing an executable
 binary. It then installs that binary to the workspace's <code>bin</code>
 directory as <code>hello</code> (or, under Windows, <code>hello.exe</code>).
 In our example, that will be <code>$GOPATH/bin/hello</code>, which is
-<code>$HOME/go/bin/hello</code>.
+<code>$HOME/work/bin/hello</code>.
 </p>
 
 <p>
@@ -254,7 +260,7 @@ optional: you do not need to use source control to write Go code.
 <pre>
 $ <b>cd $GOPATH/src/github.com/user/hello</b>
 $ <b>git init</b>
-Initialized empty Git repository in /home/user/go/src/github.com/user/hello/.git/
+Initialized empty Git repository in /home/user/work/src/github.com/user/hello/.git/
 $ <b>git add hello.go</b>
 $ <b>git commit -m "initial commit"</b>
 [master (root-commit) 0b4507d] initial commit
diff --git a/doc/contrib.html b/doc/contrib.html
index 93a609f..f5f6f68 100644
--- a/doc/contrib.html
+++ b/doc/contrib.html
@@ -34,6 +34,7 @@ We encourage all Go users to subscribe to
 <p>A <a href="/doc/devel/release.html">summary</a> of the changes between Go releases. Notes for the major releases:</p>
 
 <ul>
+	<li><a href="/doc/go1.5">Go 1.5</a> <small>(August 2015)</small></li>
 	<li><a href="/doc/go1.4">Go 1.4</a> <small>(December 2014)</small></li>
 	<li><a href="/doc/go1.3">Go 1.3</a> <small>(June 2014)</small></li>
 	<li><a href="/doc/go1.2">Go 1.2</a> <small>(December 2013)</small></li>
@@ -91,6 +92,12 @@ a new one.)
 We pride ourselves on being meticulous; no issue is too small.
 </p>
 
+<p>
+Security-related issues should be reported to
+<a href="mailto:security at golang.org">security at golang.org</a>.
+See the <a href="/security">security policy</a> for more details.
+</p>
+
 <h3><a href="/doc/contribute.html">Contributing code</a></h3>
 
 <p>
diff --git a/doc/contribute.html b/doc/contribute.html
index 63d4774..45ed8f1 100644
--- a/doc/contribute.html
+++ b/doc/contribute.html
@@ -20,23 +20,32 @@ see <a href="gccgo_contribute.html">Contributing to gccgo</a>.)
 
 <p>
 The project welcomes submissions but please let everyone know what
-you're working on if you want it to become part of the main repository.
+you're working on if you want to change or add to the Go repositories.
 </p>
 
 <p>
-Before undertaking to write something new for the Go project, send
-mail to the <a href="https://groups.google.com/group/golang-nuts">mailing
-list</a> to discuss what you plan to do.  This gives everyone a
-chance to validate the design, helps prevent duplication of effort,
-and ensures that the idea fits inside the goals for the language
-and tools.  It also guarantees that the design is sound before code
-is written; the code review tool is not the place for high-level
-discussions.
+Before undertaking to write something new for the Go project,
+please <a href="https://golang.org/issue/new">file an issue</a>
+(or claim an <a href="https://golang.org/issues">existing issue</a>).
+Significant changes must go through the
+<a href="https://golang.org/s/proposal-process">change proposal process</a>
+before they can be accepted.
 </p>
 
 <p>
-In short, send mail before you code.
-And don't start the discussion by mailing a change list!
+This process gives everyone a chance to validate the design,
+helps prevent duplication of effort,
+and ensures that the idea fits inside the goals for the language and tools.
+It also checks that the design is sound before code is written;
+the code review tool is not the place for high-level discussions.
+</p>
+
+<p>
+When planning work, please note that the Go project follows a
+<a href="https://golang.org/wiki/Go-Release-Cycle">six-month
+development cycle</a>. The latter half of each cycle is a three-month
+feature freeze during which only bug fixes and doc updates are accepted.
+New work cannot be submitted during a feature freeze.
 </p>
 
 <h2 id="Testing">Testing redux</h2>
@@ -64,10 +73,8 @@ After running for a while, the command should print
 <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,52 +84,89 @@ system called <a href="https://code.google.com/p/gerrit/">Gerrit</a>.
 <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>
 
+<h3>Contributor License Agreement</h3>
+
+<p>Gerrit serves as the gatekeeper and uses your e-mail address as the key.
+To send your first change to the Go project from a given address,
+you must have completed one of the contributor license agreements:
+<ul>
+<li>
+If you are the copyright holder, you will need to agree to the
+<a href="https://developers.google.com/open-source/cla/individual">individual
+contributor license agreement</a>, which can be completed online.
+</li>
+<li>
+If your organization is the copyright holder, the organization
+will need to agree to the
+<a href="https://developers.google.com/open-source/cla/corporate">corporate
+contributor license agreement</a>.
+(If the copyright holder for your code has already completed the
+agreement in connection with another Google open source project,
+it does not need to be completed again.)
+</li>
+</ul>
+
+<p>
+You can use the links above to create and sign the contributor license agreement
+or you can show your current agreements and create new ones through the Gerrit
+interface.  <a href="https://go-review.googlesource.com/login/">Log into Gerrit</a>,
+click your name in the upper-right, choose "Settings", then select "Agreements"
+from the topics on the left. If you do not have a signed agreement listed here,
+you can create one by clicking "New Contributor Agreement" and following the steps.
+</p>
+
+<p>
+This rigmarole only needs to be done for your first submission for each email address.
+</p>
+
 <h3>Install the git-codereview command</h3>
 
 <p>
@@ -130,7 +174,7 @@ Now install the <code>git-codereview</code> command by running,
 </p>
 
 <pre>
-go get -u golang.org/x/review/git-codereview
+$ go get -u golang.org/x/review/git-codereview
 </pre>
 
 <p>
@@ -386,7 +430,8 @@ Unless explicitly told otherwise, such as in the discussion leading
 up to sending in the change list, it's better not to specify a reviewer.
 All changes are automatically CC'ed to the
 <a href="https://groups.google.com/group/golang-codereviews">golang-codereviews at googlegroups.com</a>
-mailing list.
+mailing list. If this is your first ever change, there may be a moderation
+delay before it appears on the mailing list, to prevent spam.
 </p>
 
 <p>
@@ -482,7 +527,7 @@ $ git sync
 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 +550,15 @@ The output will look something like this:
 <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 <file>..." to unstage)
-  (use "git add <file>..." to mark resolution)
+  (use "git reset HEAD <file>..." to unstage)
+  (use "git add <file>..." to mark resolution)
 
-	<i>both modified:   sin.go</i>
+	<i>both modified: sin.go</i>
 </pre>
 
 <p>
@@ -530,9 +575,9 @@ might turn up:
 <pre>
 	arg = scale(arg)
 <<<<<<< HEAD
-	if arg > 1e9 {
+	if arg < 1e9 {
 =======
-	if arg > 1e10 {
+	if arg &lh; 1e10 {
 >>>>>>> mcgillicutty
 		largeReduce(arg)
 </pre>
@@ -546,7 +591,7 @@ to remove the markers and leave the correct code:
 
 <pre>
 	arg = scale(arg)
-	if arg > 1e10 {
+	if arg < 1e10 {
 		largeReduce(arg)
 </pre>
 
@@ -577,7 +622,7 @@ It should look something like this:
 </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 && git checkout FETCH_HEAD
 </pre>
 
 <p>
@@ -624,30 +669,7 @@ and perhaps the <a href="/AUTHORS"><code>AUTHORS</code></a> file.
 defines who the Go contributors—the people—are;
 the <a href="/AUTHORS"><code>AUTHORS</code></a> file defines
 who “The Go Authors”—the copyright holders—are.
-The Go developers at Google will update these files when submitting
-your first change.
-In order for them to do that, you need to have completed one of the
-contributor license agreements:
-<ul>
-<li>
-If you are the copyright holder, you will need to agree to the
-<a href="https://developers.google.com/open-source/cla/individual">individual
-contributor license agreement</a>, which can be completed online.
-</li>
-<li>
-If your organization is the copyright holder, the organization
-will need to agree to the
-<a href="https://developers.google.com/open-source/cla/corporate">corporate
-contributor license agreement</a>.
-(If the copyright holder for your code has already completed the
-agreement in connection with another Google open source project,
-it does not need to be completed again.)
-</li>
-</ul>
-
-<p>
-This rigmarole needs to be done only for your first submission.
-</p>
+These files will be periodically updated based on the commit logs.
 
 <p>Code that you contribute should use the standard copyright header:</p>
 
diff --git a/doc/devel/pre_go1.html b/doc/devel/pre_go1.html
new file mode 100644
index 0000000..813e23c
--- /dev/null
+++ b/doc/devel/pre_go1.html
@@ -0,0 +1,455 @@
+<!--{
+	"Title": "Pre-Go 1 Release History"
+}-->
+
+<p>
+This page summarizes the changes between stable releases of Go prior to Go 1.
+See the <a href="release.html">Release History</a> page for notes on recent releases.
+</p>
+
+<h2 id="r60">r60 (released 2011/09/07)</h2>
+
+<p>
+The r60 release corresponds to 
+<code><a href="weekly.html#2011-08-17">weekly.2011-08-17</a></code>.
+This section highlights the most significant changes in this release.
+For a more detailed summary, see the
+<a href="weekly.html#2011-08-17">weekly release notes</a>.
+For complete information, see the
+<a href="//code.google.com/p/go/source/list?r=release-branch.r60">Mercurial change list</a>.
+</p>
+
+<h3 id="r60.lang">Language</h3>
+
+<p>
+An "else" block is now required to have braces except if the body of the "else"
+is another "if". Since gofmt always puts those braces in anyway,
+gofmt-formatted programs will not be affected.
+To fix other programs, run gofmt.
+</p>
+
+<h3 id="r60.pkg">Packages</h3>
+
+<p>
+<a href="/pkg/http/">Package http</a>'s URL parsing and query escaping code
+(such as <code>ParseURL</code> and <code>URLEscape</code>) has been moved to
+the new <a href="/pkg/url/">url package</a>, with several simplifications to
+the names. Client code can be updated automatically with gofix.
+</p>
+
+<p>
+<a href="/pkg/image/">Package image</a> has had significant changes made to the
+<code>Pix</code> field of struct types such as
+<a href="/pkg/image/#RGBA">image.RGBA</a> and
+<a href="/pkg/image/#NRGBA">image.NRGBA</a>.
+The <a href="/pkg/image/#Image">image.Image</a> interface type has not changed,
+though, and you should not need to change your code if you don't explicitly
+refer to <code>Pix</code> fields. For example, if you decode a number of images
+using the <a href="/pkg/image/jpeg/">image/jpeg</a> package, compose them using
+<a href="/pkg/image/draw/">image/draw</a>, and then encode the result using
+<a href="/pkg/img/png">image/png</a>, then your code should still work as
+before.
+If your code <i>does</i> refer to <code>Pix</code> fields see the 
+<a href="/doc/devel/weekly.html#2011-07-19">weekly.2011-07-19</a>
+snapshot notes for how to update your code.
+</p>
+
+<p>
+<a href="/pkg/template/">Package template</a> has been replaced with a new
+templating package (formerly <code>exp/template</code>). The original template
+package is still available as <a href="/pkg/old/template/">old/template</a>.
+The <code>old/template</code> package is deprecated and will be removed.
+The Go tree has been updated to use the new template package. We encourage
+users of the old template package to switch to the new one. Code that uses
+<code>template</code> or <code>exp/template</code> will need to change its
+import lines to <code>"old/template"</code> or <code>"template"</code>,
+respectively.
+</p>
+
+<h3 id="r60.cmd">Tools</h3>
+
+<p>
+<a href="/cmd/goinstall/">Goinstall</a> now uses a new tag selection scheme.
+When downloading or updating, goinstall looks for a tag or branch with the
+<code>"go."</code> prefix that corresponds to the local Go version. For Go
+<code>release.r58</code> it looks for <code>go.r58</code>. For
+<code>weekly.2011-06-03</code> it looks for <code>go.weekly.2011-06-03</code>.
+If the specific <code>go.X</code> tag or branch is not found, it chooses the
+closest earlier version. If an appropriate tag or branch is found, goinstall
+uses that version of the code. Otherwise it uses the default version selected
+by the version control system. Library authors are encouraged to use the
+appropriate tag or branch names in their repositories to make their libraries
+more accessible.
+</p>
+
+<h3 id="r60.minor">Minor revisions</h3>
+
+<p>
+r60.1 includes a 
+<a href="//golang.org/change/1824581bf62d">linker
+fix</a>, a pair of
+<a href="//golang.org/change/9ef4429c2c64">goplay</a>
+<a href="//golang.org/change/d42ed8c3098e">fixes</a>,
+and a <code>json</code> package
+<a href="//golang.org/change/d5e97874fe84">fix</a> and
+a new
+<a href="//golang.org/change/4f0e6269213f">struct tag
+option</a>.
+</p>
+
+<p>
+r60.2
+<a href="//golang.org/change/ff19536042ac">fixes</a>
+a memory leak involving maps.
+</p>
+
+<p>
+r60.3 fixes a
+<a href="//golang.org/change/01fa62f5e4e5">reflect bug</a>.
+</p>
+
+<h2 id="r59">r59 (released 2011/08/01)</h2>
+
+<p>
+The r59 release corresponds to 
+<code><a href="weekly.html#2011-07-07">weekly.2011-07-07</a></code>.
+This section highlights the most significant changes in this release.
+For a more detailed summary, see the
+<a href="weekly.html#2011-07-07">weekly release notes</a>.
+For complete information, see the
+<a href="//code.google.com/p/go/source/list?r=release-branch.r59">Mercurial change list</a>.
+</p>
+
+<h3 id="r59.lang">Language</h3>
+
+<p>
+This release includes a language change that restricts the use of
+<code>goto</code>.  In essence, a <code>goto</code> statement outside a block
+cannot jump to a label inside that block. Your code may require changes if it
+uses <code>goto</code>.
+See <a href="//golang.org/change/dc6d3cf9279d">this
+changeset</a> for how the new rule affected the Go tree.
+</p>
+
+<h3 id="r59.pkg">Packages</h3>
+
+<p>
+As usual, <a href="/cmd/gofix/">gofix</a> will handle the bulk of the rewrites
+necessary for these changes to package APIs.
+</p>
+
+<p>
+<a href="/pkg/http">Package http</a> has a new
+<a href="/pkg/http/#FileSystem">FileSystem</a> interface that provides access
+to files. The <a href="/pkg/http/#FileServer">FileServer</a> helper now takes a
+<code>FileSystem</code> argument instead of an explicit file system root. By
+implementing your own <code>FileSystem</code> you can use the
+<code>FileServer</code> to serve arbitrary data.
+</p>
+
+<p>
+<a href="/pkg/os/">Package os</a>'s <code>ErrorString</code> type has been
+hidden. Most uses of <code>os.ErrorString</code> can be replaced with
+<a href="/pkg/os/#NewError">os.NewError</a>.
+</p>
+
+<p>
+<a href="/pkg/reflect/">Package reflect</a> supports a new struct tag scheme
+that enables sharing of struct tags between multiple packages.
+In this scheme, the tags must be of the form:
+</p>
+<pre>
+	`key:"value" key2:"value2"`
+</pre>
+<p>
+The <a href="/pkg/reflect/#StructField">StructField</a> type's Tag field now
+has type <a href="/pkg/reflect/#StructTag">StructTag</a>, which has a
+<code>Get</code> method. Clients of <a href="/pkg/json">json</a> and
+<a href="/pkg/xml">xml</a> will need to be updated. Code that says
+</p>
+<pre>
+	type T struct {
+		X int "name"
+	}
+</pre>
+<p>
+should become
+</p>
+<pre>
+	type T struct {
+		X int `json:"name"`  // or `xml:"name"`
+	}
+</pre>
+<p>
+Use <a href="/cmd/govet/">govet</a> to identify struct tags that need to be
+changed to use the new syntax.
+</p>
+
+<p>
+<a href="/pkg/sort/">Package sort</a>'s <code>IntArray</code> type has been
+renamed to <a href="/pkg/sort/#IntSlice">IntSlice</a>, and similarly for
+<a href="/pkg/sort/#Float64Slice">Float64Slice</a> and
+<a href="/pkg/sort/#StringSlice">StringSlice</a>.
+</p>
+
+<p>
+<a href="/pkg/strings/">Package strings</a>'s <code>Split</code> function has
+itself been split into <a href="/pkg/strings/#Split">Split</a> and
+<a href="/pkg/strings/#SplitN">SplitN</a>.
+<code>SplitN</code> is the same as the old <code>Split</code>.
+The new <code>Split</code> is equivalent to <code>SplitN</code> with a final
+argument of -1.
+</p>
+
+<a href="/pkg/image/draw/">Package image/draw</a>'s
+<a href="/pkg/image/draw/#Draw">Draw</a> function now takes an additional
+argument, a compositing operator.
+If in doubt, use <a href="/pkg/image/draw/#Op">draw.Over</a>.
+</p>
+
+<h3 id="r59.cmd">Tools</h3>
+
+<p>
+<a href="/cmd/goinstall/">Goinstall</a> now installs packages and commands from
+arbitrary remote repositories (not just Google Code, Github, and so on).
+See the <a href="/cmd/goinstall/">goinstall documentation</a> for details.
+</p>
+
+<h2 id="r58">r58 (released 2011/06/29)</h2>
+
+<p>
+The r58 release corresponds to 
+<code><a href="weekly.html#2011-06-09">weekly.2011-06-09</a></code>
+with additional bug fixes.
+This section highlights the most significant changes in this release.
+For a more detailed summary, see the
+<a href="weekly.html#2011-06-09">weekly release notes</a>.
+For complete information, see the
+<a href="//code.google.com/p/go/source/list?r=release-branch.r58">Mercurial change list</a>.
+</p>
+
+<h3 id="r58.lang">Language</h3>
+
+<p>
+This release fixes a <a href="//golang.org/change/b720749486e1">use of uninitialized memory in programs that misuse <code>goto</code></a>.
+</p>
+
+<h3 id="r58.pkg">Packages</h3>
+
+<p>
+As usual, <a href="/cmd/gofix/">gofix</a> will handle the bulk of the rewrites
+necessary for these changes to package APIs.
+</p>
+
+<p>
+<a href="/pkg/http/">Package http</a> drops the <code>finalURL</code> return
+value from the <a href="/pkg/http/#Client.Get">Client.Get</a> method. The value
+is now available via the new <code>Request</code> field on <a
+href="/pkg/http/#Response">http.Response</a>.
+Most instances of the type map[string][]string in have been
+replaced with the new <a href="/pkg/http/#Values">Values</a> type.
+</p>
+
+<p>
+<a href="/pkg/exec/">Package exec</a> has been redesigned with a more
+convenient and succinct API.
+</p>
+
+<p>
+<a href="/pkg/strconv/">Package strconv</a>'s <a href="/pkg/strconv/#Quote">Quote</a>
+function now escapes only those Unicode code points not classified as printable
+by <a href="/pkg/unicode/#IsPrint">unicode.IsPrint</a>.
+Previously Quote would escape all non-ASCII characters.
+This also affects the <a href="/pkg/fmt/">fmt</a> package's <code>"%q"</code>
+formatting directive. The previous quoting behavior is still available via
+strconv's new <a href="/pkg/strconv/#QuoteToASCII">QuoteToASCII</a> function.   
+</p>
+
+<p>
+<a href="/pkg/os/signal/">Package os/signal</a>'s
+<a href="/pkg/os/#Signal">Signal</a> and 
+<a href="/pkg/os/#UnixSignal">UnixSignal</a> types have been moved to the
+<a href="/pkg/os/">os</a> package.
+</p>
+
+<p>
+<a href="/pkg/image/draw/">Package image/draw</a> is the new name for
+<code>exp/draw</code>. The GUI-related code from <code>exp/draw</code> is now
+located in the <a href="/pkg/exp/gui/">exp/gui</a> package.
+</p>
+
+<h3 id="r58.cmd">Tools</h3>
+
+<p>
+<a href="/cmd/goinstall/">Goinstall</a> now observes the GOPATH environment
+variable to build and install your own code and external libraries outside of
+the Go tree (and avoid writing Makefiles).
+</p>
+
+
+<h3 id="r58.minor">Minor revisions</h3>
+
+<p>r58.1 adds 
+<a href="//golang.org/change/293c25943586">build</a> and
+<a href="//golang.org/change/bf17e96b6582">runtime</a>
+changes to make Go run on OS X 10.7 Lion.
+</p>
+
+<h2 id="r57">r57 (released 2011/05/03)</h2>
+
+<p>
+The r57 release corresponds to 
+<code><a href="weekly.html#2011-04-27">weekly.2011-04-27</a></code>
+with additional bug fixes.
+This section highlights the most significant changes in this release.
+For a more detailed summary, see the
+<a href="weekly.html#2011-04-27">weekly release notes</a>.
+For complete information, see the
+<a href="//code.google.com/p/go/source/list?r=release-branch.r57">Mercurial change list</a>.
+</p>
+
+<p>The new <a href="/cmd/gofix">gofix</a> tool finds Go programs that use old APIs and rewrites them to use
+newer ones.  After you update to a new Go release, gofix helps make the
+necessary changes to your programs. Gofix will handle the http, os, and syscall
+package changes described below, and we will update the program to keep up with
+future changes to the libraries. 
+Gofix can’t
+handle all situations perfectly, so read and test the changes it makes before
+committing them.
+See <a href="//blog.golang.org/2011/04/introducing-gofix.html">the gofix blog post</a> for more
+information.</p>
+
+<h3 id="r57.lang">Language</h3>
+
+<p>
+<a href="/doc/go_spec.html#Receive_operator">Multiple assignment syntax</a> replaces the <code>closed</code> function.
+The syntax for channel
+receives allows an optional second assigned value, a boolean value
+indicating whether the channel is closed. This code:
+</p>
+
+<pre>
+	v := <-ch
+	if closed(ch) {
+		// channel is closed
+	}
+</pre>
+
+<p>should now be written as:</p>
+
+<pre>
+	v, ok := <-ch
+	if !ok {
+		// channel is closed
+	}
+</pre>
+
+<p><a href="/doc/go_spec.html#Label_scopes">Unused labels are now illegal</a>, just as unused local variables are.</p>
+
+<h3 id="r57.pkg">Packages</h3>
+
+<p>
+<a href="/pkg/gob/">Package gob</a> will now encode and decode values of types that implement the
+<a href="/pkg/gob/#GobEncoder">GobEncoder</a> and
+<a href="/pkg/gob/#GobDecoder">GobDecoder</a> interfaces. This allows types with unexported
+fields to transmit self-consistent descriptions; examples include 
+<a href="/pkg/big/#Int.GobDecode">big.Int</a> and <a href="/pkg/big/#Rat.GobDecode">big.Rat</a>.
+</p>
+
+<p>
+<a href="/pkg/http/">Package http</a> has been redesigned.
+For clients, there are new
+<a href="/pkg/http/#Client">Client</a> and <a href="/pkg/http/#Transport">Transport</a>
+abstractions that give more control over HTTP details such as headers sent
+and redirections followed.  These abstractions make it easy to implement
+custom clients that add functionality such as <a href="//code.google.com/p/goauth2/source/browse/oauth/oauth.go">OAuth2</a>.
+For servers, <a href="/pkg/http/#ResponseWriter">ResponseWriter</a>
+has dropped its non-essential methods.
+The Hijack and Flush methods are no longer required;
+code can test for them by checking whether a specific value implements
+<a href="/pkg/http/#Hijacker">Hijacker</a> or <a href="/pkg/http/#Flusher">Flusher</a>.
+The RemoteAddr and UsingTLS methods are replaced by <a href="/pkg/http/#Request">Request</a>'s
+RemoteAddr and TLS fields.
+The SetHeader method is replaced by a Header method;
+its result, of type <a href="/pkg/http/#Header">Header</a>,
+implements Set and other methods.
+</p>
+
+<p>
+<a href="/pkg/net/">Package net</a>
+drops the <code>laddr</code> argument from <a href="/pkg/net/#Conn.Dial">Dial</a>
+and drops the <code>cname</code> return value
+from <a href="/pkg/net/#LookupHost">LookupHost</a>.
+The implementation now uses <a href="/cmd/cgo/">cgo</a> to implement
+network name lookups using the C library getaddrinfo(3)
+function when possible.  This ensures that Go and C programs
+resolve names the same way and also avoids the OS X 
+application-level firewall.
+</p>
+
+<p>
+<a href="/pkg/os/">Package os</a>
+introduces simplified <a href="/pkg/os/#File.Open">Open</a>
+and <a href="/pkg/os/#File.Create">Create</a> functions.
+The original Open is now available as <a href="/pkg/os/#File.OpenFile">OpenFile</a>.
+The final three arguments to <a href="/pkg/os/#Process.StartProcess">StartProcess</a>
+have been replaced by a pointer to a <a href="/pkg/os/#ProcAttr">ProcAttr</a>.
+</p>
+
+<p>
+<a href="/pkg/reflect/">Package reflect</a> has been redesigned.
+<a href="/pkg/reflect/#Type">Type</a> is now an interface that implements
+all the possible type methods.
+Instead of a type switch on a Type <code>t</code>, switch on <code>t.Kind()</code>.
+<a href="/pkg/reflect/#Value">Value</a> is now a struct value that
+implements all the possible value methods.
+Instead of a type switch on a Value <code>v</code>, switch on <code>v.Kind()</code>.
+Typeof and NewValue are now called <a href="/pkg/reflect/#Type.TypeOf">TypeOf</a> and <a href="/pkg/reflect/#Value.ValueOf">ValueOf</a>
+To create a writable Value, use <code>New(t).Elem()</code> instead of <code>Zero(t)</code>.
+See <a href="//golang.org/change/843855f3c026">the change description</a>
+for the full details.
+The new API allows a more efficient implementation of Value
+that avoids many of the allocations required by the previous API.
+</p>
+
+<p>
+Remember that gofix will handle the bulk of the rewrites
+necessary for these changes to package APIs.
+</p>
+
+<h3 id="r57.cmd">Tools</h3>
+
+<p><a href="/cmd/gofix/">Gofix</a>, a new command, is described above.</p>
+
+<p>
+<a href="/cmd/gotest/">Gotest</a> is now a Go program instead of a shell script.
+The new <code>-test.short</code> flag in combination with package testing's Short function
+allows you to write tests that can be run in normal or “short” mode;
+all.bash runs tests in short mode to reduce installation time.
+The Makefiles know about the flag: use <code>make testshort</code>.
+</p>
+
+<p>
+The run-time support now implements CPU and memory profiling.
+Gotest's new 
+<a href="/cmd/gotest/"><code>-test.cpuprofile</code> and
+<code>-test.memprofile</code> flags</a> make it easy to
+profile tests.
+To add profiling to your web server, see the <a href="/pkg/http/pprof/">http/pprof</a>
+documentation.
+For other uses, see the <a href="/pkg/runtime/pprof/">runtime/pprof</a> documentation.
+</p>
+
+<h3 id="r57.minor">Minor revisions</h3>
+
+<p>r57.1 fixes a <a href="//golang.org/change/ff2bc62726e7145eb2ecc1e0f076998e4a8f86f0">nil pointer dereference in http.FormFile</a>.</p>
+<p>r57.2 fixes a <a href="//golang.org/change/063b0ff67d8277df03c956208abc068076818dae">use of uninitialized memory in programs that misuse <code>goto</code></a>.</p>
+
+<h2 id="r56">r56 (released 2011/03/16)</h2>
+
+<p>
+The r56 release was the first stable release and corresponds to
+<code><a href="weekly.html#2011-03-07">weekly.2011-03-07.1</a></code>.
+The numbering starts at 56 because before this release,
+what we now consider weekly snapshots were called releases.
+</p>
diff --git a/doc/devel/release.html b/doc/devel/release.html
index 0ce2b2e..43ead08 100644
--- a/doc/devel/release.html
+++ b/doc/devel/release.html
@@ -8,10 +8,27 @@ The <a href="//golang.org/change">change log</a> has the full details.</p>
 <p>To update to a specific release, use:</p>
 
 <pre>
-hg pull
-hg update <i>tag</i>
+git pull
+git checkout <i>release-branch</i>
 </pre>
 
+<h2 id="go1.5">go1.5 (released 2015/08/19)</h2>
+
+<p>
+Go 1.5 is a major release of Go.
+Read the <a href="/doc/go1.5">Go 1.5 Release Notes</a> for more information.
+</p>
+
+<h3 id="go1.5.minor">Minor revisions</h3>
+
+<p>
+go1.5.1 (released 2015/09/08) includes bug fixes to the compiler, assembler, and
+the <code>fmt</code>, <code>net/textproto</code>, <code>net/http</code>, and
+<code>runtime</code> packages.
+See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.5.1">Go
+1.5.1 milestone</a> on our issue tracker for details.
+</p>
+
 <h2 id="go1.4">go1.4 (released 2014/12/10)</h2>
 
 <p>
@@ -31,11 +48,6 @@ go1.4.2 (released 2015/02/17) includes bug fixes to the <code>go</code> command,
 See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.4.2">Go 1.4.2 milestone on our issue tracker</a> for details.
 </p>
 
-<p>
-go1.4.3 (released 2015/09/22) includes security fixes to the <code>net/http</code> package and bug fixes to the <code>runtime</code> package.
-See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.4.3">Go 1.4.3 milestone on our issue tracker</a> for details.
-</p>
-
 <h2 id="go1.3">go1.3 (released 2014/06/18)</h2>
 
 <p>
@@ -150,449 +162,10 @@ go1.0.3 (released 2012/09/21) includes minor code and documentation fixes.
 See the <a href="//code.google.com/p/go/source/list?name=release-branch.go1">go1 release branch history</a> for the complete list of changes.
 </p>
 
-<h2 id="r60">r60 (released 2011/09/07)</h2>
-
-<p>
-The r60 release corresponds to 
-<code><a href="weekly.html#2011-08-17">weekly.2011-08-17</a></code>.
-This section highlights the most significant changes in this release.
-For a more detailed summary, see the
-<a href="weekly.html#2011-08-17">weekly release notes</a>.
-For complete information, see the
-<a href="//code.google.com/p/go/source/list?r=release-branch.r60">Mercurial change list</a>.
-</p>
-
-<h3 id="r60.lang">Language</h3>
-
-<p>
-An "else" block is now required to have braces except if the body of the "else"
-is another "if". Since gofmt always puts those braces in anyway,
-gofmt-formatted programs will not be affected.
-To fix other programs, run gofmt.
-</p>
-
-<h3 id="r60.pkg">Packages</h3>
-
-<p>
-<a href="/pkg/http/">Package http</a>'s URL parsing and query escaping code
-(such as <code>ParseURL</code> and <code>URLEscape</code>) has been moved to
-the new <a href="/pkg/url/">url package</a>, with several simplifications to
-the names. Client code can be updated automatically with gofix.
-</p>
-
-<p>
-<a href="/pkg/image/">Package image</a> has had significant changes made to the
-<code>Pix</code> field of struct types such as
-<a href="/pkg/image/#RGBA">image.RGBA</a> and
-<a href="/pkg/image/#NRGBA">image.NRGBA</a>.
-The <a href="/pkg/image/#Image">image.Image</a> interface type has not changed,
-though, and you should not need to change your code if you don't explicitly
-refer to <code>Pix</code> fields. For example, if you decode a number of images
-using the <a href="/pkg/image/jpeg/">image/jpeg</a> package, compose them using
-<a href="/pkg/image/draw/">image/draw</a>, and then encode the result using
-<a href="/pkg/img/png">image/png</a>, then your code should still work as
-before.
-If your code <i>does</i> refer to <code>Pix</code> fields see the 
-<a href="/doc/devel/weekly.html#2011-07-19">weekly.2011-07-19</a>
-snapshot notes for how to update your code.
-</p>
-
-<p>
-<a href="/pkg/template/">Package template</a> has been replaced with a new
-templating package (formerly <code>exp/template</code>). The original template
-package is still available as <a href="/pkg/old/template/">old/template</a>.
-The <code>old/template</code> package is deprecated and will be removed.
-The Go tree has been updated to use the new template package. We encourage
-users of the old template package to switch to the new one. Code that uses
-<code>template</code> or <code>exp/template</code> will need to change its
-import lines to <code>"old/template"</code> or <code>"template"</code>,
-respectively.
-</p>
-
-<h3 id="r60.cmd">Tools</h3>
-
-<p>
-<a href="/cmd/goinstall/">Goinstall</a> now uses a new tag selection scheme.
-When downloading or updating, goinstall looks for a tag or branch with the
-<code>"go."</code> prefix that corresponds to the local Go version. For Go
-<code>release.r58</code> it looks for <code>go.r58</code>. For
-<code>weekly.2011-06-03</code> it looks for <code>go.weekly.2011-06-03</code>.
-If the specific <code>go.X</code> tag or branch is not found, it chooses the
-closest earlier version. If an appropriate tag or branch is found, goinstall
-uses that version of the code. Otherwise it uses the default version selected
-by the version control system. Library authors are encouraged to use the
-appropriate tag or branch names in their repositories to make their libraries
-more accessible.
-</p>
-
-<h3 id="r60.minor">Minor revisions</h3>
-
-<p>
-r60.1 includes a 
-<a href="//golang.org/change/1824581bf62d">linker
-fix</a>, a pair of
-<a href="//golang.org/change/9ef4429c2c64">goplay</a>
-<a href="//golang.org/change/d42ed8c3098e">fixes</a>,
-and a <code>json</code> package
-<a href="//golang.org/change/d5e97874fe84">fix</a> and
-a new
-<a href="//golang.org/change/4f0e6269213f">struct tag
-option</a>.
-</p>
-
-<p>
-r60.2
-<a href="//golang.org/change/ff19536042ac">fixes</a>
-a memory leak involving maps.
-</p>
-
-<p>
-r60.3 fixes a
-<a href="//golang.org/change/01fa62f5e4e5">reflect bug</a>.
-</p>
-
-<h2 id="r59">r59 (released 2011/08/01)</h2>
-
-<p>
-The r59 release corresponds to 
-<code><a href="weekly.html#2011-07-07">weekly.2011-07-07</a></code>.
-This section highlights the most significant changes in this release.
-For a more detailed summary, see the
-<a href="weekly.html#2011-07-07">weekly release notes</a>.
-For complete information, see the
-<a href="//code.google.com/p/go/source/list?r=release-branch.r59">Mercurial change list</a>.
-</p>
-
-<h3 id="r59.lang">Language</h3>
-
-<p>
-This release includes a language change that restricts the use of
-<code>goto</code>.  In essence, a <code>goto</code> statement outside a block
-cannot jump to a label inside that block. Your code may require changes if it
-uses <code>goto</code>.
-See <a href="//golang.org/change/dc6d3cf9279d">this
-changeset</a> for how the new rule affected the Go tree.
-</p>
-
-<h3 id="r59.pkg">Packages</h3>
-
-<p>
-As usual, <a href="/cmd/gofix/">gofix</a> will handle the bulk of the rewrites
-necessary for these changes to package APIs.
-</p>
-
-<p>
-<a href="/pkg/http">Package http</a> has a new
-<a href="/pkg/http/#FileSystem">FileSystem</a> interface that provides access
-to files. The <a href="/pkg/http/#FileServer">FileServer</a> helper now takes a
-<code>FileSystem</code> argument instead of an explicit file system root. By
-implementing your own <code>FileSystem</code> you can use the
-<code>FileServer</code> to serve arbitrary data.
-</p>
-
-<p>
-<a href="/pkg/os/">Package os</a>'s <code>ErrorString</code> type has been
-hidden. Most uses of <code>os.ErrorString</code> can be replaced with
-<a href="/pkg/os/#NewError">os.NewError</a>.
-</p>
-
-<p>
-<a href="/pkg/reflect/">Package reflect</a> supports a new struct tag scheme
-that enables sharing of struct tags between multiple packages.
-In this scheme, the tags must be of the form:
-</p>
-<pre>
-	`key:"value" key2:"value2"`
-</pre>
-<p>
-The <a href="/pkg/reflect/#StructField">StructField</a> type's Tag field now
-has type <a href="/pkg/reflect/#StructTag">StructTag</a>, which has a
-<code>Get</code> method. Clients of <a href="/pkg/json">json</a> and
-<a href="/pkg/xml">xml</a> will need to be updated. Code that says
-</p>
-<pre>
-	type T struct {
-		X int "name"
-	}
-</pre>
-<p>
-should become
-</p>
-<pre>
-	type T struct {
-		X int `json:"name"`  // or `xml:"name"`
-	}
-</pre>
-<p>
-Use <a href="/cmd/govet/">govet</a> to identify struct tags that need to be
-changed to use the new syntax.
-</p>
-
-<p>
-<a href="/pkg/sort/">Package sort</a>'s <code>IntArray</code> type has been
-renamed to <a href="/pkg/sort/#IntSlice">IntSlice</a>, and similarly for
-<a href="/pkg/sort/#Float64Slice">Float64Slice</a> and
-<a href="/pkg/sort/#StringSlice">StringSlice</a>.
-</p>
-
-<p>
-<a href="/pkg/strings/">Package strings</a>'s <code>Split</code> function has
-itself been split into <a href="/pkg/strings/#Split">Split</a> and
-<a href="/pkg/strings/#SplitN">SplitN</a>.
-<code>SplitN</code> is the same as the old <code>Split</code>.
-The new <code>Split</code> is equivalent to <code>SplitN</code> with a final
-argument of -1.
-</p>
-
-<a href="/pkg/image/draw/">Package image/draw</a>'s
-<a href="/pkg/image/draw/#Draw">Draw</a> function now takes an additional
-argument, a compositing operator.
-If in doubt, use <a href="/pkg/image/draw/#Op">draw.Over</a>.
-</p>
-
-<h3 id="r59.cmd">Tools</h3>
+<h2 id="pre.go1">Older releases</h2>
 
 <p>
-<a href="/cmd/goinstall/">Goinstall</a> now installs packages and commands from
-arbitrary remote repositories (not just Google Code, Github, and so on).
-See the <a href="/cmd/goinstall/">goinstall documentation</a> for details.
+See the <a href="pre_go1.html">Pre-Go 1 Release History</a> page for notes
+on earlier releases.
 </p>
 
-<h2 id="r58">r58 (released 2011/06/29)</h2>
-
-<p>
-The r58 release corresponds to 
-<code><a href="weekly.html#2011-06-09">weekly.2011-06-09</a></code>
-with additional bug fixes.
-This section highlights the most significant changes in this release.
-For a more detailed summary, see the
-<a href="weekly.html#2011-06-09">weekly release notes</a>.
-For complete information, see the
-<a href="//code.google.com/p/go/source/list?r=release-branch.r58">Mercurial change list</a>.
-</p>
-
-<h3 id="r58.lang">Language</h3>
-
-<p>
-This release fixes a <a href="//golang.org/change/b720749486e1">use of uninitialized memory in programs that misuse <code>goto</code></a>.
-</p>
-
-<h3 id="r58.pkg">Packages</h3>
-
-<p>
-As usual, <a href="/cmd/gofix/">gofix</a> will handle the bulk of the rewrites
-necessary for these changes to package APIs.
-</p>
-
-<p>
-<a href="/pkg/http/">Package http</a> drops the <code>finalURL</code> return
-value from the <a href="/pkg/http/#Client.Get">Client.Get</a> method. The value
-is now available via the new <code>Request</code> field on <a
-href="/pkg/http/#Response">http.Response</a>.
-Most instances of the type map[string][]string in have been
-replaced with the new <a href="/pkg/http/#Values">Values</a> type.
-</p>
-
-<p>
-<a href="/pkg/exec/">Package exec</a> has been redesigned with a more
-convenient and succinct API.
-</p>
-
-<p>
-<a href="/pkg/strconv/">Package strconv</a>'s <a href="/pkg/strconv/#Quote">Quote</a>
-function now escapes only those Unicode code points not classified as printable
-by <a href="/pkg/unicode/#IsPrint">unicode.IsPrint</a>.
-Previously Quote would escape all non-ASCII characters.
-This also affects the <a href="/pkg/fmt/">fmt</a> package's <code>"%q"</code>
-formatting directive. The previous quoting behavior is still available via
-strconv's new <a href="/pkg/strconv/#QuoteToASCII">QuoteToASCII</a> function.   
-</p>
-
-<p>
-<a href="/pkg/os/signal/">Package os/signal</a>'s
-<a href="/pkg/os/#Signal">Signal</a> and 
-<a href="/pkg/os/#UnixSignal">UnixSignal</a> types have been moved to the
-<a href="/pkg/os/">os</a> package.
-</p>
-
-<p>
-<a href="/pkg/image/draw/">Package image/draw</a> is the new name for
-<code>exp/draw</code>. The GUI-related code from <code>exp/draw</code> is now
-located in the <a href="/pkg/exp/gui/">exp/gui</a> package.
-</p>
-
-<h3 id="r58.cmd">Tools</h3>
-
-<p>
-<a href="/cmd/goinstall/">Goinstall</a> now observes the GOPATH environment
-variable to build and install your own code and external libraries outside of
-the Go tree (and avoid writing Makefiles).
-</p>
-
-
-<h3 id="r58.minor">Minor revisions</h3>
-
-<p>r58.1 adds 
-<a href="//golang.org/change/293c25943586">build</a> and
-<a href="//golang.org/change/bf17e96b6582">runtime</a>
-changes to make Go run on OS X 10.7 Lion.
-</p>
-
-<h2 id="r57">r57 (released 2011/05/03)</h2>
-
-<p>
-The r57 release corresponds to 
-<code><a href="weekly.html#2011-04-27">weekly.2011-04-27</a></code>
-with additional bug fixes.
-This section highlights the most significant changes in this release.
-For a more detailed summary, see the
-<a href="weekly.html#2011-04-27">weekly release notes</a>.
-For complete information, see the
-<a href="//code.google.com/p/go/source/list?r=release-branch.r57">Mercurial change list</a>.
-</p>
-
-<p>The new <a href="/cmd/gofix">gofix</a> tool finds Go programs that use old APIs and rewrites them to use
-newer ones.  After you update to a new Go release, gofix helps make the
-necessary changes to your programs. Gofix will handle the http, os, and syscall
-package changes described below, and we will update the program to keep up with
-future changes to the libraries. 
-Gofix can’t
-handle all situations perfectly, so read and test the changes it makes before
-committing them.
-See <a href="//blog.golang.org/2011/04/introducing-gofix.html">the gofix blog post</a> for more
-information.</p>
-
-<h3 id="r57.lang">Language</h3>
-
-<p>
-<a href="/doc/go_spec.html#Receive_operator">Multiple assignment syntax</a> replaces the <code>closed</code> function.
-The syntax for channel
-receives allows an optional second assigned value, a boolean value
-indicating whether the channel is closed. This code:
-</p>
-
-<pre>
-	v := <-ch
-	if closed(ch) {
-		// channel is closed
-	}
-</pre>
-
-<p>should now be written as:</p>
-
-<pre>
-	v, ok := <-ch
-	if !ok {
-		// channel is closed
-	}
-</pre>
-
-<p><a href="/doc/go_spec.html#Label_scopes">Unused labels are now illegal</a>, just as unused local variables are.</p>
-
-<h3 id="r57.pkg">Packages</h3>
-
-<p>
-<a href="/pkg/gob/">Package gob</a> will now encode and decode values of types that implement the
-<a href="/pkg/gob/#GobEncoder">GobEncoder</a> and
-<a href="/pkg/gob/#GobDecoder">GobDecoder</a> interfaces. This allows types with unexported
-fields to transmit self-consistent descriptions; examples include 
-<a href="/pkg/big/#Int.GobDecode">big.Int</a> and <a href="/pkg/big/#Rat.GobDecode">big.Rat</a>.
-</p>
-
-<p>
-<a href="/pkg/http/">Package http</a> has been redesigned.
-For clients, there are new
-<a href="/pkg/http/#Client">Client</a> and <a href="/pkg/http/#Transport">Transport</a>
-abstractions that give more control over HTTP details such as headers sent
-and redirections followed.  These abstractions make it easy to implement
-custom clients that add functionality such as <a href="//code.google.com/p/goauth2/source/browse/oauth/oauth.go">OAuth2</a>.
-For servers, <a href="/pkg/http/#ResponseWriter">ResponseWriter</a>
-has dropped its non-essential methods.
-The Hijack and Flush methods are no longer required;
-code can test for them by checking whether a specific value implements
-<a href="/pkg/http/#Hijacker">Hijacker</a> or <a href="/pkg/http/#Flusher">Flusher</a>.
-The RemoteAddr and UsingTLS methods are replaced by <a href="/pkg/http/#Request">Request</a>'s
-RemoteAddr and TLS fields.
-The SetHeader method is replaced by a Header method;
-its result, of type <a href="/pkg/http/#Header">Header</a>,
-implements Set and other methods.
-</p>
-
-<p>
-<a href="/pkg/net/">Package net</a>
-drops the <code>laddr</code> argument from <a href="/pkg/net/#Conn.Dial">Dial</a>
-and drops the <code>cname</code> return value
-from <a href="/pkg/net/#LookupHost">LookupHost</a>.
-The implementation now uses <a href="/cmd/cgo/">cgo</a> to implement
-network name lookups using the C library getaddrinfo(3)
-function when possible.  This ensures that Go and C programs
-resolve names the same way and also avoids the OS X 
-application-level firewall.
-</p>
-
-<p>
-<a href="/pkg/os/">Package os</a>
-introduces simplified <a href="/pkg/os/#File.Open">Open</a>
-and <a href="/pkg/os/#File.Create">Create</a> functions.
-The original Open is now available as <a href="/pkg/os/#File.OpenFile">OpenFile</a>.
-The final three arguments to <a href="/pkg/os/#Process.StartProcess">StartProcess</a>
-have been replaced by a pointer to a <a href="/pkg/os/#ProcAttr">ProcAttr</a>.
-</p>
-
-<p>
-<a href="/pkg/reflect/">Package reflect</a> has been redesigned.
-<a href="/pkg/reflect/#Type">Type</a> is now an interface that implements
-all the possible type methods.
-Instead of a type switch on a Type <code>t</code>, switch on <code>t.Kind()</code>.
-<a href="/pkg/reflect/#Value">Value</a> is now a struct value that
-implements all the possible value methods.
-Instead of a type switch on a Value <code>v</code>, switch on <code>v.Kind()</code>.
-Typeof and NewValue are now called <a href="/pkg/reflect/#Type.TypeOf">TypeOf</a> and <a href="/pkg/reflect/#Value.ValueOf">ValueOf</a>
-To create a writable Value, use <code>New(t).Elem()</code> instead of <code>Zero(t)</code>.
-See <a href="//golang.org/change/843855f3c026">the change description</a>
-for the full details.
-The new API allows a more efficient implementation of Value
-that avoids many of the allocations required by the previous API.
-</p>
-
-<p>
-Remember that gofix will handle the bulk of the rewrites
-necessary for these changes to package APIs.
-</p>
-
-<h3 id="r57.cmd">Tools</h3>
-
-<p><a href="/cmd/gofix/">Gofix</a>, a new command, is described above.</p>
-
-<p>
-<a href="/cmd/gotest/">Gotest</a> is now a Go program instead of a shell script.
-The new <code>-test.short</code> flag in combination with package testing's Short function
-allows you to write tests that can be run in normal or “short” mode;
-all.bash runs tests in short mode to reduce installation time.
-The Makefiles know about the flag: use <code>make testshort</code>.
-</p>
-
-<p>
-The run-time support now implements CPU and memory profiling.
-Gotest's new 
-<a href="/cmd/gotest/"><code>-test.cpuprofile</code> and
-<code>-test.memprofile</code> flags</a> make it easy to
-profile tests.
-To add profiling to your web server, see the <a href="/pkg/http/pprof/">http/pprof</a>
-documentation.
-For other uses, see the <a href="/pkg/runtime/pprof/">runtime/pprof</a> documentation.
-</p>
-
-<h3 id="r57.minor">Minor revisions</h3>
-
-<p>r57.1 fixes a <a href="//golang.org/change/ff2bc62726e7145eb2ecc1e0f076998e4a8f86f0">nil pointer dereference in http.FormFile</a>.</p>
-<p>r57.2 fixes a <a href="//golang.org/change/063b0ff67d8277df03c956208abc068076818dae">use of uninitialized memory in programs that misuse <code>goto</code></a>.</p>
-
-<h2 id="r56">r56 (released 2011/03/16)</h2>
-
-<p>
-The r56 release was the first stable release and corresponds to
-<code><a href="weekly.html#2011-03-07">weekly.2011-03-07.1</a></code>.
-The numbering starts at 56 because before this release,
-what we now consider weekly snapshots were called releases.
-</p>
diff --git a/doc/devel/weekly.html b/doc/devel/weekly.html
index 5a9c51e..143727f 100644
--- a/doc/devel/weekly.html
+++ b/doc/devel/weekly.html
@@ -5971,7 +5971,7 @@ You can now check build status on various platforms at the Go Dashboard:
 * runtime: add SetFinalizer
 * time: Sleep through interruptions (thanks Chris Wedgwood)
 	add RFC822 formats
-	experimental implemenation of Ticker using two goroutines for all tickers
+	experimental implementation of Ticker using two goroutines for all tickers
 * xml: allow underscores in XML element names (thanks Michael Hoisie)
 	allow any scalar type in xml.Unmarshal
 </pre>
diff --git a/doc/effective_go.html b/doc/effective_go.html
index 4dd1a3e..5a522f6 100644
--- a/doc/effective_go.html
+++ b/doc/effective_go.html
@@ -866,7 +866,7 @@ var t interface{}
 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:
@@ -1382,7 +1382,7 @@ limit of how much data to read.  Here is the signature of the
 <code>os</code>:
 </p>
 <pre>
-func (file *File) Read(buf []byte) (n int, err error)
+func (f *File) Read(buf []byte) (n int, err error)
 </pre>
 <p>
 The method returns the number of bytes read and an error value, if
@@ -1421,7 +1421,7 @@ resulting slice is returned.  The function uses the fact that
 <code>nil</code> slice, and return 0.
 </p>
 <pre>
-func Append(slice, data[]byte) []byte {
+func Append(slice, data []byte) []byte {
     l := len(slice)
     if l + len(data) > cap(slice) {  // reallocate
         // Allocate double what's needed, for future growth.
@@ -3054,7 +3054,7 @@ req := req
 </pre>
 
 <p>
-but it's a legal and idiomatic in Go to do this.
+but it's legal and idiomatic in Go to do this.
 You get a fresh version of the variable with the same name, deliberately
 shadowing the loop variable locally but unique to each goroutine.
 </p>
@@ -3172,40 +3172,44 @@ count the completion signals by draining the channel after
 launching all the goroutines.
 </p>
 <pre>
-const NCPU = 4  // number of CPU cores
+const numCPU = 4 // number of CPU cores
 
 func (v Vector) DoAll(u Vector) {
-    c := make(chan int, NCPU)  // Buffering optional but sensible.
-    for i := 0; i < NCPU; i++ {
-        go v.DoSome(i*len(v)/NCPU, (i+1)*len(v)/NCPU, u, c)
+    c := make(chan int, numCPU)  // Buffering optional but sensible.
+    for i := 0; i < numCPU; i++ {
+        go v.DoSome(i*len(v)/numCPU, (i+1)*len(v)/numCPU, u, c)
     }
     // Drain the channel.
-    for i := 0; i < NCPU; i++ {
+    for i := 0; i < numCPU; i++ {
         <-c    // wait for one task to complete
     }
     // All done.
 }
-
 </pre>
-
 <p>
-The current implementation of the Go runtime
-will not parallelize this code by default.
-It dedicates only a single core to user-level processing.  An
-arbitrary number of goroutines can be blocked in system calls, but
-by default only one can be executing user-level code at any time.
-It should be smarter and one day it will be smarter, but until it
-is if you want CPU parallelism you must tell the run-time
-how many goroutines you want executing code simultaneously.  There
-are two related ways to do this.  Either run your job with environment
-variable <code>GOMAXPROCS</code> set to the number of cores to use
-or import the <code>runtime</code> package and call
-<code>runtime.GOMAXPROCS(NCPU)</code>.
-A helpful value might be <code>runtime.NumCPU()</code>, which reports the number
-of logical CPUs on the local machine.
-Again, this requirement is expected to be retired as the scheduling and run-time improve.
+Rather than create a constant value for numCPU, we can ask the runtime what
+value is appropriate.
+The function <code><a href="/pkg/runtime#NumCPU">runtime.NumCPU</a></code>
+returns the number of hardware CPU cores in the machine, so we could write
 </p>
-
+<pre>
+var numCPU = runtime.NumCPU()
+</pre>
+<p>
+There is also a function
+<code><a href="/pkg/runtime#GOMAXPROCS">runtime.GOMAXPROCS</a></code>,
+which reports (or sets)
+the user-specified number of cores that a Go program can have running
+simultaneously.
+It defaults to the value of <code>runtime.NumCPU</code> but can be
+overridden by setting the similarly named shell environment variable
+or by calling the function with a positive number.  Calling it with
+zero just queries the value.
+Therefore if we want to honor the user's resource request, we should write
+</p>
+<pre>
+var numCPU = runtime.GOMAXPROCS(0)
+</pre>
 <p>
 Be sure not to confuse the ideas of concurrency—structuring a program
 as independently executing components—and parallelism—executing
diff --git a/doc/gccgo_contribute.html b/doc/gccgo_contribute.html
index db7d1ab..dd1327a 100644
--- a/doc/gccgo_contribute.html
+++ b/doc/gccgo_contribute.html
@@ -30,7 +30,9 @@ contribution rules</a>.
 
 <p>
 The master sources for the gccgo frontend may be found at
-<a href="//code.google.com/p/gofrontend">http://code.google.com/p/gofrontend</a>.
+<a href="http://go.googlesource.com/gofrontend">http://go.googlesource.com/gofrontend</a>.
+They are mirrored
+at <a href="http://github.com/golang/gofrontend">http://github.com/golang/gofrontend</a>.
 The master sources are not buildable by themselves, but only in
 conjunction with GCC (in the future, other compilers may be
 supported).  Changes made to the gccgo frontend are also applied to
@@ -40,7 +42,7 @@ is mirrored to the <code>gcc/go/gofrontend</code> directory in the GCC
 repository, and the <code>gofrontend</code> <code>libgo</code>
 directory is mirrored to the GCC <code>libgo</code> directory.  In
 addition, the <code>test</code> directory
-from <a href="//code.google.com/p/go">the main Go repository</a>
+from <a href="//go.googlesource.com/go">the main Go repository</a>
 is mirrored to the <code>gcc/testsuite/go.test/test</code> directory
 in the GCC repository.
 </p>
@@ -53,19 +55,17 @@ them.
 </p>
 
 <p>
-The gccgo frontend is written in C++.  It follows the GNU coding
-standards to the extent that they apply to C++.  In writing code for
-the frontend, follow the formatting of the surrounding code.  Although
-the frontend is currently tied to the rest of the GCC codebase, we
-plan to make it more independent.  Eventually all GCC-specific code
-will migrate out of the frontend proper and into GCC proper.  In the
-GCC sources this will generally mean moving code
-from <code>gcc/go/gofrontend</code> to <code>gcc/go</code>.
+The gccgo frontend is written in C++.
+It follows the GNU and GCC coding standards for C++.
+In writing code for the frontend, follow the formatting of the
+surrounding code.
+Almost all GCC-specific code is not in the frontend proper and is
+instead in the GCC sources in the <code>gcc/go</code> directory.
 </p>
 
 <p>
 The run-time library for gccgo is mostly the same as the library
-in <a href="//code.google.com/p/go">the main Go repository</a>.
+in <a href="//go.googlesource.com/go">the main Go repository</a>.
 The library code in the Go repository is periodically merged into
 the <code>libgo/go</code> directory of the <code>gofrontend</code> and
 then the GCC repositories, using the shell
@@ -105,7 +105,7 @@ or <code>gcc/testsuite/go.dg</code> directories in the GCC repository.
 <p>
 Changes to the Go frontend should follow the same process as for the
 main Go repository, only for the <code>gofrontend</code> project and
-the<code>gofrontend-dev at googlegroups.com</code> mailing list 
+the <code>gofrontend-dev at googlegroups.com</code> mailing list 
 rather than the <code>go</code> project and the
 <code>golang-dev at googlegroups.com</code> mailing list.  Those changes
 will then be merged into the GCC sources.
diff --git a/doc/gccgo_install.html b/doc/gccgo_install.html
index acb315a..ef27fd1 100644
--- a/doc/gccgo_install.html
+++ b/doc/gccgo_install.html
@@ -46,6 +46,12 @@ identical to Go 1.1.  The GCC 4.8.2 release includes a complete Go
 The GCC 4.9 releases include a complete Go 1.2 implementation.
 </p>
 
+<p>
+The GCC 5 releases include a complete implementation of the Go 1.4
+user libraries.  The Go 1.4 runtime is not fully merged, but that
+should not be visible to Go programs.
+</p>
+
 <h2 id="Source_code">Source code</h2>
 
 <p>
@@ -174,13 +180,10 @@ export LIBRARY_PATH C_INCLUDE_PATH CPLUS_INCLUDE_PATH
 <h2 id="Using_gccgo">Using gccgo</h2>
 
 <p>
-The gccgo compiler works like other gcc frontends.  The gccgo
-installation does not currently include a version of
-the <code>go</code> command.  However if you have the <code>go</code>
-command from an installation of the <code>gc</code> compiler, you can
-use it with gccgo by passing the option <code>-compiler gccgo</code>
-to <code>go build</code> or <code>go install</code> or <code>go
-test</code>.
+The gccgo compiler works like other gcc frontends.  As of GCC 5 the gccgo
+installation also includes a version of the <code>go</code> command,
+which may be used to build Go programs as described at
+<a href="https://golang.org/cmd/go">https://golang.org/cmd/go</a>.
 </p>
 
 <p>
@@ -232,13 +235,14 @@ name the directory where <code>libgo.so</code> is found.
 
 <li>
 <p>
-Passing a <code>-Wl,-R</code> option when you link:
+Passing a <code>-Wl,-R</code> option when you link (replace lib with
+lib64 if appropriate for your system):
 </p>
 
 <pre>
-gccgo -o file file.o -Wl,-R,${prefix}/lib/gcc/MACHINE/VERSION
+go build -gccgoflags -Wl,-R,${prefix}/lib/gcc/MACHINE/VERSION
 [or]
-gccgo -o file file.o -Wl,-R,${prefix}/lib64/gcc/MACHINE/VERSION
+gccgo -o file file.o -Wl,-R,${prefix}/lib/gcc/MACHINE/VERSION
 </pre>
 </li>
 
@@ -266,27 +270,33 @@ and <code>-g</code> options.
 </p>
 
 <p>
-The <code>-fgo-prefix=PREFIX</code> option may be used to set a unique
-prefix for the package being compiled.  This option is intended for
-use with large programs that contain many packages, in order to allow
-multiple packages to use the same identifier as the package name.
-The <code>PREFIX</code> may be any string; a good choice for the
-string is the directory where the package will be installed.
+The <code>-fgo-pkgpath=PKGPATH</code> option may be used to set a
+unique prefix for the package being compiled.
+This option is automatically used by the go command, but you may want
+to use it if you invoke gccgo directly.
+This option is intended for use with large
+programs that contain many packages, in order to allow multiple
+packages to use the same identifier as the package name.
+The <code>PKGPATH</code> may be any string; a good choice for the
+string is the path used to import the package.
 </p>
 
 <p>
 The <code>-I</code> and <code>-L</code> options, which are synonyms
 for the compiler, may be used to set the search path for finding
 imports.
+These options are not needed if you build with the go command.
 </p>
 
 <h2 id="Imports">Imports</h2>
 
 <p>
 When you compile a file that exports something, the export
-information will be stored directly in the object file.  When
-you import a package, you must tell gccgo how to
-find the file.
+information will be stored directly in the object file.
+If you build with gccgo directly, rather than with the go command,
+then when you import a package, you must tell gccgo how to find the
+file.
+</p>
 
 <p>
 When you import the package <var>FILE</var> with gccgo,
@@ -319,9 +329,10 @@ gccgo.  Both options take directories to search. The
 </p>
 
 <p>
-The gccgo compiler does not currently (2013-06-20) record
+The gccgo compiler does not currently (2015-06-15) record
 the file name of imported packages in the object file. You must
 arrange for the imported data to be linked into the program.
+Again, this is not necessary when building with the go command.
 </p>
 
 <pre>
diff --git a/doc/go1.1.html b/doc/go1.1.html
index 825867f..f059fd7 100644
--- a/doc/go1.1.html
+++ b/doc/go1.1.html
@@ -160,7 +160,7 @@ The GCC release schedule does not coincide with the Go release schedule, so some
 The 4.8.0 version of GCC shipped in March, 2013 and includes a nearly-Go 1.1 version of <code>gccgo</code>.
 Its library is a little behind the release, but the biggest difference is that method values are not implemented.
 Sometime around July 2013, we expect 4.8.2 of GCC to ship with a <code>gccgo</code>
-providing a complete Go 1.1 implementaiton.
+providing a complete Go 1.1 implementation.
 </p>
 
 <h3 id="gc_flag">Command-line flag parsing</h3>
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 @@ now supports ALPN as defined in <a href="http://tools.ietf.org/html/rfc7301">RFC
 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.html b/doc/go1.5.html
new file mode 100644
index 0000000..693a185
--- /dev/null
+++ b/doc/go1.5.html
@@ -0,0 +1,1310 @@
+<!--{
+	"Title": "Go 1.5 Release Notes",
+	"Path":  "/doc/go1.5",
+	"Template": true
+}-->
+
+
+<h2 id="introduction">Introduction to Go 1.5</h2>
+
+<p>
+The latest Go release, version 1.5,
+is a significant release, including major architectural changes to the implementation.
+Despite that, we expect almost all Go programs to continue to compile and run as before,
+because the release still maintains the Go 1 <a href="/doc/go1compat.html">promise
+of compatibility</a>.
+</p>
+
+<p>
+The biggest developments in the implementation are:
+</p>
+
+<ul>
+
+<li>
+The compiler and runtime are now written entirely in Go (with a little assembler).
+C is no longer involved in the implementation, and so the C compiler that was
+once necessary for building the distribution is gone.
+</li>
+
+<li>
+The garbage collector is now <a href="https://golang.org/s/go14gc">concurrent</a> and provides dramatically lower
+pause times by running, when possible, in parallel with other goroutines.
+</li>
+
+<li>
+By default, Go programs run with <code>GOMAXPROCS</code> set to the
+number of cores available; in prior releases it defaulted to 1.
+</li>
+
+<li>
+Support for <a href="https://golang.org/s/go14internal">internal packages</a>
+is now provided for all repositories, not just the Go core.
+</li>
+
+<li>
+The <code>go</code> command now provides <a href="https://golang.org/s/go15vendor">experimental
+support</a> for "vendoring" external dependencies.
+</li>
+
+<li>
+A new <code>go tool trace</code> command supports fine-grained
+tracing of program execution.
+</li>
+
+<li>
+A new <code>go doc</code> command (distinct from <code>godoc</code>)
+is customized for command-line use.
+</li>
+
+</ul>
+
+<p>
+These and a number of other changes to the implementation and tools
+are discussed below.
+</p>
+
+<p>
+The release also contains one small language change involving map literals.
+</p>
+
+<p>
+Finally, the timing of the <a href="https://golang.org/s/releasesched">release</a>
+strays from the usual six-month interval,
+both to provide more time to prepare this major release and to shift the schedule thereafter to
+time the release dates more conveniently.
+</p>
+
+<h2 id="language">Changes to the language</h2>
+
+<h3 id="map_literals">Map literals</h3>
+
+<p>
+Due to an oversight, the rule that allowed the element type to be elided from slice literals was not
+applied to map keys.
+This has been <a href="/cl/2591">corrected</a> in Go 1.5.
+An example will make this clear.
+As of Go 1.5, this map literal,
+</p>
+
+<pre>
+m := map[Point]string{
+    Point{29.935523, 52.891566}:   "Persepolis",
+    Point{-25.352594, 131.034361}: "Uluru",
+    Point{37.422455, -122.084306}: "Googleplex",
+}
+</pre>
+
+<p>
+may be written as follows, without the <code>Point</code> type listed explicitly:
+</p>
+
+<pre>
+m := map[Point]string{
+    {29.935523, 52.891566}:   "Persepolis",
+    {-25.352594, 131.034361}: "Uluru",
+    {37.422455, -122.084306}: "Googleplex",
+}
+</pre>
+
+<h2 id="implementation">The Implementation</h2>
+
+<h3 id="c">No more C</h3>
+
+<p>
+The compiler and runtime are now implemented in Go and assembler, without C.
+The only C source left in the tree is related to testing or to <code>cgo</code>.
+There was a C compiler in the tree in 1.4 and earlier.
+It was used to build the runtime; a custom compiler was necessary in part to
+guarantee the C code would work with the stack management of goroutines.
+Since the runtime is in Go now, there is no need for this C compiler and it is gone.
+Details of the process to eliminate C are discussed <a href="https://golang.org/s/go13compiler">elsewhere</a>.
+</p>
+
+<p>
+The conversion from C was done with the help of custom tools created for the job.
+Most important, the compiler was actually moved by automatic translation of
+the C code into Go.
+It is in effect the same program in a different language.
+It is not a new implementation
+of the compiler so we expect the process will not have introduced new compiler
+bugs.
+An overview of this process is available in the slides for
+<a href="https://talks.golang.org/2015/gogo.slide">this presentation</a>.
+</p>
+
+<h3 id="compiler_and_tools">Compiler and tools</h3>
+
+<p>
+Independent of but encouraged by the move to Go, the names of the tools have changed.
+The old names <code>6g</code>, <code>8g</code> and so on are gone; instead there
+is just one binary, accessible as <code>go</code> <code>tool</code> <code>compile</code>,
+that compiles Go source into binaries suitable for the architecture and operating system
+specified by <code>$GOARCH</code> and <code>$GOOS</code>.
+Similarly, there is now one linker (<code>go</code> <code>tool</code> <code>link</code>)
+and one assembler (<code>go</code> <code>tool</code> <code>asm</code>).
+The linker was translated automatically from the old C implementation,
+but the assembler is a new native Go implementation discussed
+in more detail below.
+</p>
+
+<p>
+Similar to the drop of the names <code>6g</code>, <code>8g</code>, and so on,
+the output of the compiler and assembler are now given a plain <code>.o</code> suffix
+rather than <code>.8</code>, <code>.6</code>, etc.
+</p>
+
+
+<h3 id="gc">Garbage collector</h3>
+
+<p>
+The garbage collector has been re-engineered for 1.5 as part of the development
+outlined in the <a href="https://golang.org/s/go14gc">design document</a>.
+Expected latencies are much lower than with the collector
+in prior releases, through a combination of advanced algorithms,
+better <a href="https://golang.org/s/go15gcpacing">scheduling</a> of the collector,
+and running more of the collection in parallel with the user program.
+The "stop the world" phase of the collector
+will almost always be under 10 milliseconds and usually much less.
+</p>
+
+<p>
+For systems that benefit from low latency, such as user-responsive web sites,
+the drop in expected latency with the new collector may be important.
+</p>
+
+<p>
+Details of the new collector were presented in a
+<a href="https://talks.golang.org/2015/go-gc.pdf">talk</a> at GopherCon 2015.
+</p>
+
+<h3 id="runtime">Runtime</h3>
+
+<p>
+In Go 1.5, the order in which goroutines are scheduled has been changed.
+The properties of the scheduler were never defined by the language,
+but programs that depend on the scheduling order may be broken
+by this change.
+We have seen a few (erroneous) programs affected by this change.
+If you have programs that implicitly depend on the scheduling
+order, you will need to update them.
+</p>
+
+<p>
+Another potentially breaking change is that the runtime now
+sets the default number of threads to run simultaneously,
+defined by <code>GOMAXPROCS</code>, to the number
+of cores available on the CPU.
+In prior releases the default was 1.
+Programs that do not expect to run with multiple cores may
+break inadvertently.
+They can be updated by removing the restriction or by setting
+<code>GOMAXPROCS</code> explicitly.
+For a more detailed discussion of this change, see
+the <a href="https://golang.org/s/go15gomaxprocs">design document</a>.
+</p>
+
+<h3 id="build">Build</h3>
+
+<p>
+Now that the Go compiler and runtime are implemented in Go, a Go compiler
+must be available to compile the distribution from source.
+Thus, to build the Go core, a working Go distribution must already be in place.
+(Go programmers who do not work on the core are unaffected by this change.)
+Any Go 1.4 or later distribution (including <code>gccgo</code>) will serve.
+For details, see the <a href="https://golang.org/s/go15bootstrap">design document</a>.
+</p>
+
+<h2 id="ports">Ports</h2>
+
+<p>
+Due mostly to the industry's move away from the 32-bit x86 architecture,
+the set of binary downloads provided is reduced in 1.5.
+A distribution for the OS X operating system is provided only for the
+<code>amd64</code> architecture, not <code>386</code>.
+Similarly, the ports for Snow Leopard (Apple OS X 10.6) still work but are no
+longer released as a download or maintained since Apple no longer maintains that version
+of the operating system.
+Also, the <code>dragonfly/386</code> port is no longer supported at all
+because DragonflyBSD itself no longer supports the 32-bit 386 architecture.
+</p>
+
+<p>
+There are however several new ports available to be built from source.
+These include <code>darwin/arm</code> and <code>darwin/arm64</code>.
+The new port <code>linux/arm64</code> is mostly in place, but <code>cgo</code>
+is only supported using external linking.
+</p>
+
+<p>
+Also available as experiments are <code>ppc64</code>
+and <code>ppc64le</code> (64-bit PowerPC, big- and little-endian).
+Both these ports support <code>cgo</code> but
+only with internal linking.
+</p>
+
+<p>
+On FreeBSD, Go 1.5 requires FreeBSD 8-STABLE+ because of its new use of the <code>SYSCALL</code> instruction.
+</p>
+
+<p>
+On NaCl, Go 1.5 requires SDK version pepper-41. Later pepper versions are not
+compatible due to the removal of the sRPC subsystem from the NaCl runtime.
+</p>
+
+<p>
+On Darwin, the use of the system X.509 certificate interface can be disabled
+with the <code>ios</code> build tag.
+</p>
+
+<p>
+The Solaris port now has full support for cgo and the packages
+<a href="/pkg/net/"><code>net</code></a> and
+<a href="/pkg/crypto/x509/"><code>crypto/x509</code></a>,
+as well as a number of other fixes and improvements.
+</p>
+
+<h2 id="tools">Tools</h2>
+
+<h3 id="translate">Translating</h3>
+
+<p>
+As part of the process to eliminate C from the tree, the compiler and
+linker were translated from C to Go.
+It was a genuine (machine assisted) translation, so the new programs are essentially
+the old programs translated rather than new ones with new bugs.
+We are confident the translation process has introduced few if any new bugs,
+and in fact uncovered a number of previously unknown bugs, now fixed.
+</p>
+
+<p>
+The assembler is a new program, however; it is described below.
+</p>
+
+<h3 id="rename">Renaming</h3>
+
+<p>
+The suites of programs that were the compilers (<code>6g</code>, <code>8g</code>, etc.),
+the assemblers (<code>6a</code>, <code>8a</code>, etc.),
+and the linkers (<code>6l</code>, <code>8l</code>, etc.)
+have each been consolidated into a single tool that is configured
+by the environment variables <code>GOOS</code> and <code>GOARCH</code>.
+The old names are gone; the new tools are available through the <code>go</code> <code>tool</code>
+mechanism as <code>go tool compile</code>,
+<code>go tool asm</code>,
+<code>and go tool link</code>.
+Also, the file suffixes <code>.6</code>, <code>.8</code>, etc. for the
+intermediate object files are also gone; now they are just plain <code>.o</code> files.
+</p>
+
+<p>
+For example, to build and link a program on amd64 for Darwin
+using the tools directly, rather than through <code>go build</code>,
+one would run:
+</p>
+
+<pre>
+$ export GOOS=darwin GOARCH=amd64
+$ go tool compile program.go
+$ go tool link program.o
+</pre>
+
+<h3 id="moving">Moving</h3>
+
+<p>
+Because the <a href="/pkg/go/types/"><code>go/types</code></a> package
+has now moved into the main repository (see below),
+the <a href="/cmd/vet"><code>vet</code></a> and
+<a href="/cmd/cover"><code>cover</code></a>
+tools have also been moved.
+They are no longer maintained in the external <code>golang.org/x/tools</code> repository,
+although (deprecated) source still resides there for compatibility with old releases.
+</p>
+
+<h3 id="compiler">Compiler</h3>
+
+<p>
+As described above, the compiler in Go 1.5 is a single Go program,
+translated from the old C source, that replaces <code>6g</code>, <code>8g</code>,
+and so on.
+Its target is configured by the environment variables <code>GOOS</code> and <code>GOARCH</code>.
+</p>
+
+<p>
+The 1.5 compiler is mostly equivalent to the old,
+but some internal details have changed.
+One significant change is that evaluation of constants now uses
+the <a href="/pkg/math/big/"><code>math/big</code></a> package
+rather than a custom (and less well tested) implementation of high precision
+arithmetic.
+We do not expect this to affect the results.
+</p>
+
+<p>
+For the amd64 architecture only, the compiler has a new option, <code>-dynlink</code>,
+that assists dynamic linking by supporting references to Go symbols
+defined in external shared libraries.
+</p>
+
+<h3 id="assembler">Assembler</h3>
+
+<p>
+Like the compiler and linker, the assembler in Go 1.5 is a single program
+that replaces the suite of assemblers (<code>6a</code>,
+<code>8a</code>, etc.) and the environment variables
+<code>GOARCH</code> and <code>GOOS</code>
+configure the architecture and operating system.
+Unlike the other programs, the assembler is a wholly new program
+written in Go.
+</p>
+
+ <p>
+The new assembler is very nearly compatible with the previous
+ones, but there are a few changes that may affect some
+assembler source files.
+See the updated <a href="/doc/asm">assembler guide</a>
+for more specific information about these changes. In summary:
+
+</p>
+
+<p>
+First, the expression evaluation used for constants is a little
+different.
+It now uses unsigned 64-bit arithmetic and the precedence
+of operators (<code>+</code>, <code>-</code>, <code><<</code>, etc.)
+comes from Go, not C.
+We expect these changes to affect very few programs but
+manual verification may be required.
+</p>
+
+<p>
+Perhaps more important is that on machines where
+<code>SP</code> or <code>PC</code> is only an alias
+for a numbered register,
+such as <code>R13</code> for the stack pointer and
+<code>R15</code> for the hardware program counter
+on ARM,
+a reference to such a register that does not include a symbol
+is now illegal.
+For example, <code>SP</code> and <code>4(SP)</code> are
+illegal but <code>sym+4(SP)</code> is fine.
+On such machines, to refer to the hardware register use its
+true <code>R</code> name.
+</p>
+
+<p>
+One minor change is that some of the old assemblers
+permitted the notation
+</p>
+
+<pre>
+constant=value
+</pre>
+
+<p>
+to define a named constant.
+Since this is always possible to do with the traditional
+C-like <code>#define</code> notation, which is still
+supported (the assembler includes an implementation
+of a simplified C preprocessor), the feature was removed.
+</p>
+
+<h3 id="link">Linker</h3>
+
+<p>
+The linker in Go 1.5 is now one Go program,
+that replaces <code>6l</code>, <code>8l</code>, etc.
+Its operating system and instruction set are specified
+by the environment variables <code>GOOS</code> and <code>GOARCH</code>.
+</p>
+
+<p>
+There are several other changes.
+The most significant is the addition of a <code>-buildmode</code> option that
+expands the style of linking; it now supports
+situations such as building shared libraries and allowing other languages
+to call into Go libraries.
+Some of these were outlined in a <a href="https://golang.org/s/execmodes">design document</a>.
+For a list of the available build modes and their use, run
+</p>
+
+<pre>
+$ go help buildmode
+</pre>
+
+<p>
+Another minor change is that the linker no longer records build time stamps in
+the header of Windows executables.
+Also, although this may be fixed, Windows cgo executables are missing some
+DWARF information.
+</p>
+
+<p>
+Finally, the <code>-X</code> flag, which takes two arguments,
+as in
+</p>
+
+<pre>
+-X importpath.name value
+</pre>
+
+<p>
+now also accepts a more common Go flag style with a single argument
+that is itself a <code>name=value</code> pair:
+</p>
+
+<pre>
+-X importpath.name=value
+</pre>
+
+<p>
+Although the old syntax still works, it is recommended that uses of this
+flag in scripts and the like be updated to the new form.
+</p>
+
+<h3 id="go_command">Go command</h3>
+
+<p>
+The <a href="/cmd/go"><code>go</code></a> command's basic operation
+is unchanged, but there are a number of changes worth noting.
+</p>
+
+<p>
+The previous release introduced the idea of a directory internal to a package
+being unimportable through the <code>go</code> command.
+In 1.4, it was tested with the introduction of some internal elements
+in the core repository.
+As suggested in the <a href="https://golang.org/s/go14internal">design document</a>,
+that change is now being made available to all repositories.
+The rules are explained in the design document, but in summary any
+package in or under a directory named <code>internal</code> may
+be imported by packages rooted in the same subtree.
+Existing packages with directory elements named <code>internal</code> may be
+inadvertently broken by this change, which was why it was advertised
+in the last release.
+</p>
+
+<p>
+Another change in how packages are handled is the experimental
+addition of support for "vendoring".
+For details, see the documentation for the <a href="/cmd/go/#hdr-Vendor_Directories"><code>go</code> command</a>
+and the <a href="https://golang.org/s/go15vendor">design document</a>.
+</p>
+
+<p>
+There have also been several minor changes.
+Read the <a href="/cmd/go">documentation</a> for full details.
+</p>
+
+<ul>
+
+<li>
+SWIG support has been updated such that
+<code>.swig</code> and <code>.swigcxx</code>
+now require SWIG 3.0.6 or later.
+</li>
+
+<li>
+The <code>install</code> subcommand now removes the
+binary created by the <code>build</code> subcommand
+in the source directory, if present,
+to avoid problems having two binaries present in the tree.
+</li>
+
+<li>
+The <code>std</code> (standard library) wildcard package name
+now excludes commands.
+A new <code>cmd</code> wildcard covers the commands.
+</li>
+
+<li>
+A new <code>-asmflags</code> build option
+sets flags to pass to the assembler.
+However,
+the <code>-ccflags</code> build option has been dropped;
+it was specific to the old, now deleted C compiler .
+</li>
+
+<li>
+A new <code>-buildmode</code> build option
+sets the build mode, described above.
+</li>
+
+<li>
+A new <code>-pkgdir</code> build option
+sets the location of installed package archives,
+to help isolate custom builds.
+</li>
+
+<li>
+A new <code>-toolexec</code> build option
+allows substitution of a different command to invoke
+the compiler and so on.
+This acts as a custom replacement for <code>go tool</code>.
+</li>
+
+<li>
+The <code>test</code> subcommand now has a <code>-count</code>
+flag to specify how many times to run each test and benchmark.
+The <a href="/pkg/testing/"><code>testing</code></a> package
+does the work here, through by the <code>-test.count</code> flag.
+</li>
+
+<li>
+The <code>generate</code> subcommand has a couple of new features.
+The <code>-run</code> option specifies a regular expression to select which directives
+to execute; this was proposed but never implemented in 1.4.
+The executing pattern now has access to two new environment variables:
+<code>$GOLINE</code> returns the source line number of the directive
+and <code>$DOLLAR</code> expands to a dollar sign.
+</li>
+
+<li>
+The <code>get</code> subcommand now has a <code>-insecure</code>
+flag that must be enabled if fetching from an insecure repository, one that
+does not encrypt the connection.
+</li>
+
+</ul>
+
+<h3 id="vet_command">Go vet command</h3>
+
+<p>
+The <a href="/cmd/vet"><code>go tool vet</code></a> command now does
+more thorough validation of struct tags.
+</p>
+
+<h3 id="trace_command">Trace command</h3>
+
+<p>
+A new tool is available for dynamic execution tracing of Go programs.
+The usage is analogous to how the test coverage tool works.
+Generation of traces is integrated into <code>go test</code>,
+and then a separate execution of the tracing tool itself analyzes the results:
+</p>
+
+<pre>
+$ go test -trace=trace.out path/to/package
+$ go tool trace [flags] pkg.test trace.out
+</pre>
+
+<p>
+The flags enable the output to be displayed in a browser window.
+For details, run <code>go tool trace -help</code>.
+There is also a description of the tracing facility in this
+<a href="https://talks.golang.org/2015/dynamic-tools.slide">talk</a>
+from GopherCon 2015.
+</p>
+
+<h3 id="doc_command">Go doc command</h3>
+
+<p>
+A few releases back, the <code>go doc</code>
+command was deleted as being unnecessary.
+One could always run "<code>godoc .</code>" instead.
+The 1.5 release introduces a new <a href="/cmd/doc"><code>go doc</code></a>
+command with a more convenient command-line interface than
+<code>godoc</code>'s.
+It is designed for command-line usage specifically, and provides a more
+compact and focused presentation of the documentation for a package
+or its elements, according to the invocation.
+It also provides case-insensitive matching and
+support for showing the documentation for unexported symbols.
+For details run "<code>go help doc</code>".
+</p>
+
+<h3 id="cgo">Cgo</h3>
+
+<p>
+When parsing <code>#cgo</code> lines,
+the invocation <code>${SRCDIR}</code> is now
+expanded into the path to the source directory.
+This allows options to be passed to the
+compiler and linker that involve file paths relative to the
+source code directory. Without the expansion the paths would be
+invalid when the current working directory changes.
+</p>
+
+<p>
+Solaris now has full cgo support.
+</p>
+
+<p>
+On Windows, cgo now uses external linking by default.
+</p>
+
+<p>
+When a C struct ends with a zero-sized field, but the struct itself is
+not zero-sized, Go code can no longer refer to the zero-sized field.
+Any such references will have to be rewritten.
+</p>
+
+<h2 id="performance">Performance</h2>
+
+<p>
+As always, the changes are so general and varied that precise statements
+about performance are difficult to make.
+The changes are even broader ranging than usual in this release, which
+includes a new garbage collector and a conversion of the runtime to Go.
+Some programs may run faster, some slower.
+On average the programs in the Go 1 benchmark suite run a few percent faster in Go 1.5
+than they did in Go 1.4,
+while as mentioned above the garbage collector's pauses are
+dramatically shorter, and almost always under 10 milliseconds.
+</p>
+
+<p>
+Builds in Go 1.5 will be slower by a factor of about two.
+The automatic translation of the compiler and linker from C to Go resulted in
+unidiomatic Go code that performs poorly compared to well-written Go.
+Analysis tools and refactoring helped to improve the code, but much remains to be done.
+Further profiling and optimization will continue in Go 1.6 and future releases.
+For more details, see these <a href="https://talks.golang.org/2015/gogo.slide">slides</a>
+and associated <a href="https://www.youtube.com/watch?v=cF1zJYkBW4A">video</a>.
+</p>
+
+<h2 id="library">Core library</h2>
+
+<h3 id="flag">Flag</h3>
+
+<p>
+The flag package's
+<a href="/pkg/flag/#PrintDefaults"><code>PrintDefaults</code></a>
+function, and method on <a href="/pkg/flag/#FlagSet"><code>FlagSet</code></a>,
+have been modified to create nicer usage messages.
+The format has been changed to be more human-friendly and in the usage
+messages a word quoted with `backquotes` is taken to be the name of the
+flag's operand to display in the usage message.
+For instance, a flag created with the invocation,
+</p>
+
+<pre>
+cpuFlag = flag.Int("cpu", 1, "run `N` processes in parallel")
+</pre>
+
+<p>
+will show the help message,
+</p>
+
+<pre>
+-cpu N
+    	run N processes in parallel (default 1)
+</pre>
+
+<p>
+Also, the default is now listed only when it is not the zero value for the type.
+</p>
+
+<h3 id="math_big">Floats in math/big</h3>
+
+<p>
+The <a href="/pkg/math/big/"><code>math/big</code></a> package
+has a new, fundamental data type,
+<a href="/pkg/math/big/#Float"><code>Float</code></a>,
+which implements arbitrary-precision floating-point numbers.
+A <code>Float</code> value is represented by a boolean sign,
+a variable-length mantissa, and a 32-bit fixed-size signed exponent.
+The precision of a <code>Float</code> (the mantissa size in bits)
+can be specified explicitly or is otherwise determined by the first
+operation that creates the value.
+Once created, the size of a <code>Float</code>'s mantissa may be modified with the
+<a href="/pkg/math/big/#Float.SetPrec"><code>SetPrec</code></a> method.
+<code>Floats</code> support the concept of infinities, such as are created by
+overflow, but values that would lead to the equivalent of IEEE 754 NaNs
+trigger a panic.
+<code>Float</code> operations support all IEEE-754 rounding modes.
+When the precision is set to 24 (53) bits,
+operations that stay within the range of normalized <code>float32</code>
+(<code>float64</code>)
+values produce the same results as the corresponding IEEE-754
+arithmetic on those values.
+</p>
+
+<h3 id="go_types">Go types</h3>
+
+<p>
+The <a href="/pkg/go/types/"><code>go/types</code></a> package
+up to now has been maintained in the <code>golang.org/x</code>
+repository; as of Go 1.5 it has been relocated to the main repository.
+The code at the old location is now deprecated.
+There is also a modest API change in the package, discussed below.
+</p>
+
+<p>
+Associated with this move, the
+<a href="/pkg/go/constant/"><code>go/constant</code></a>
+package also moved to the main repository;
+it was <code>golang.org/x/tools/exact</code> before.
+The <a href="/pkg/go/importer/"><code>go/importer</code></a> package
+also moved to the main repository,
+as well as some tools described above.
+</p>
+
+<h3 id="net">Net</h3>
+
+<p>
+The DNS resolver in the net package has almost always used <code>cgo</code> to access
+the system interface.
+A change in Go 1.5 means that on most Unix systems DNS resolution
+will no longer require <code>cgo</code>, which simplifies execution
+on those platforms.
+Now, if the system's networking configuration permits, the native Go resolver
+will suffice.
+The important effect of this change is that each DNS resolution occupies a goroutine
+rather than a thread,
+so a program with multiple outstanding DNS requests will consume fewer operating
+system resources.
+</p>
+
+<p>
+The decision of how to run the resolver applies at run time, not build time.
+The <code>netgo</code> build tag that has been used to enforce the use
+of the Go resolver is no longer necessary, although it still works.
+A new <code>netcgo</code> build tag forces the use of the <code>cgo</code> resolver at
+build time.
+To force <code>cgo</code> resolution at run time set
+<code>GODEBUG=netdns=cgo</code> in the environment.
+More debug options are documented <a href="https://golang.org/cl/11584">here</a>.
+</p>
+
+<p>
+This change applies to Unix systems only.
+Windows, Mac OS X, and Plan 9 systems behave as before.
+</p>
+
+<h3 id="reflect">Reflect</h3>
+
+<p>
+The <a href="/pkg/reflect/"><code>reflect</code></a> package
+has two new functions: <a href="/pkg/reflect/#ArrayOf"><code>ArrayOf</code></a>
+and <a href="/pkg/reflect/#FuncOf"><code>FuncOf</code></a>.
+These functions, analogous to the extant
+<a href="/pkg/reflect/#SliceOf"><code>SliceOf</code></a> function,
+create new types at runtime to describe arrays and functions.
+</p>
+
+<h3 id="hardening">Hardening</h3>
+
+<p>
+Several dozen bugs were found in the standard library
+through randomized testing with the
+<a href="https://github.com/dvyukov/go-fuzz"><code>go-fuzz</code></a> tool.
+Bugs were fixed in the
+<a href="/pkg/archive/tar/"><code>archive/tar</code></a>,
+<a href="/pkg/archive/zip/"><code>archive/zip</code></a>,
+<a href="/pkg/compress/flate/"><code>compress/flate</code></a>,
+<a href="/pkg/encoding/gob/"><code>encoding/gob</code></a>,
+<a href="/pkg/fmt/"><code>fmt</code></a>,
+<a href="/pkg/html/template/"><code>html/template</code></a>,
+<a href="/pkg/image/gif/"><code>image/gif</code></a>,
+<a href="/pkg/image/jpeg/"><code>image/jpeg</code></a>,
+<a href="/pkg/image/png/"><code>image/png</code></a>, and
+<a href="/pkg/text/template/"><code>text/template</code></a>,
+packages.
+The fixes harden the implementation against incorrect and malicious inputs.
+</p>
+
+<h3 id="minor_library_changes">Minor changes to the library</h3>
+
+<ul>
+
+<li>
+The <a href="/pkg/archive/zip/"><code>archive/zip</code></a> package's
+<a href="/pkg/archive/zip/#Writer"><code>Writer</code></a> type now has a
+<a href="/pkg/archive/zip/#Writer.SetOffset"><code>SetOffset</code></a>
+method to specify the location within the output stream at which to write the archive.
+</li>
+
+<li>
+The <a href="/pkg/bufio/#Reader"><code>Reader</code></a> in the
+<a href="/pkg/bufio/"><code>bufio</code></a> package now has a
+<a href="/pkg/bufio/#Reader.Discard"><code>Discard</code></a>
+method to discard data from the input.
+</li>
+
+<li>
+In the <a href="/pkg/bytes/"><code>bytes</code></a> package,
+the <a href="/pkg/bytes/#Buffer"><code>Buffer</code></a> type
+now has a <a href="/pkg/bytes/#Buffer.Cap"><code>Cap</code></a> method
+that reports the number of bytes allocated within the buffer.
+Similarly, in both the <a href="/pkg/bytes/"><code>bytes</code></a>
+and <a href="/pkg/strings/"><code>strings</code></a> packages,
+the <a href="/pkg/bytes/#Reader"><code>Reader</code></a>
+type now has a <a href="/pkg/bytes/#Reader.Size"><code>Size</code></a>
+method that reports the original length of the underlying slice or string.
+</li>
+
+<li>
+Both the <a href="/pkg/bytes/"><code>bytes</code></a> and
+<a href="/pkg/strings/"><code>strings</code></a> packages
+also now have a <a href="/pkg/bytes/#LastIndexByte"><code>LastIndexByte</code></a>
+function that locates the rightmost byte with that value in the argument.
+</li>
+
+<li>
+The <a href="/pkg/crypto/"><code>crypto</code></a> package
+has a new interface, <a href="/pkg/crypto/#Decrypter"><code>Decrypter</code></a>,
+that abstracts the behavior of a private key used in asymmetric decryption.
+</li>
+
+<li>
+In the <a href="/pkg/crypto/cipher/"><code>crypto/cipher</code></a> package,
+the documentation for the <a href="/pkg/crypto/cipher/#Stream"><code>Stream</code></a>
+interface has been clarified regarding the behavior when the source and destination are
+different lengths.
+If the destination is shorter than the source, the method will panic.
+This is not a change in the implementation, only the documentation.
+</li>
+
+<li>
+Also in the <a href="/pkg/crypto/cipher/"><code>crypto/cipher</code></a> package,
+there is now support for nonce lengths other than 96 bytes in AES's Galois/Counter mode (GCM),
+which some protocols require.
+</li>
+
+<li>
+In the <a href="/pkg/crypto/elliptic/"><code>crypto/elliptic</code></a> package,
+there is now a <code>Name</code> field in the
+<a href="/pkg/crypto/elliptic/#CurveParams"><code>CurveParams</code></a> struct,
+and the curves implemented in the package have been given names.
+These names provide a safer way to select a curve, as opposed to
+selecting its bit size, for cryptographic systems that are curve-dependent.
+</li>
+
+<li>
+Also in the <a href="/pkg/crypto/elliptic/"><code>crypto/elliptic</code></a> package,
+the <a href="/pkg/crypto/elliptic/#Unmarshal"><code>Unmarshal</code></a> function
+now verifies that the point is actually on the curve.
+(If it is not, the function returns nils).
+This change guards against certain attacks.
+</li>
+
+<li>
+The <a href="/pkg/crypto/sha512/"><code>crypto/sha512</code></a>
+package now has support for the two truncated versions of
+the SHA-512 hash algorithm, SHA-512/224 and SHA-512/256.
+</li>
+
+<li>
+The <a href="/pkg/crypto/tls/"><code>crypto/tls</code></a> package
+minimum protocol version now defaults to TLS 1.0.
+The old default, SSLv3, is still available through <a href="/pkg/crypto/tls/#Config"><code>Config</code></a> if needed.
+</li>
+
+<li>
+The <a href="/pkg/crypto/tls/"><code>crypto/tls</code></a> package
+now supports Signed Certificate Timestamps (SCTs) as specified in RFC 6962.
+The server serves them if they are listed in the
+<a href="/pkg/crypto/tls/#Certificate"><code>Certificate</code></a> struct,
+and the client requests them and exposes them, if present,
+in its <a href="/pkg/crypto/tls/#ConnectionState"><code>ConnectionState</code></a> struct.
+
+<li>
+The stapled OCSP response to a <a href="/pkg/crypto/tls/"><code>crypto/tls</code></a> client connection,
+previously only available via the
+<a href="/pkg/crypto/tls/#Conn.OCSPResponse"><code>OCSPResponse</code></a> method,
+is now exposed in the <a href="/pkg/crypto/tls/#ConnectionState"><code>ConnectionState</code></a> struct.
+</li>
+
+<li>
+The <a href="/pkg/crypto/tls/"><code>crypto/tls</code></a> server implementation
+will now always call the
+<code>GetCertificate</code> function in
+the <a href="/pkg/crypto/tls/#Config"><code>Config</code></a> struct
+to select a certificate for the connection when none is supplied.
+</li>
+
+<li>
+Finally, the session ticket keys in the
+<a href="/pkg/crypto/tls/"><code>crypto/tls</code></a> package
+can now be changed while the server is running.
+This is done through the new
+<a href="/pkg/crypto/tls/#Config.SetSessionTicketKeys"><code>SetSessionTicketKeys</code></a>
+method of the
+<a href="/pkg/crypto/tls/#Config"><code>Config</code></a> type.
+</li>
+
+<li>
+In the <a href="/pkg/crypto/x509/"><code>crypto/x509</code></a> package,
+wildcards are now accepted only in the leftmost label as defined in
+<a href="https://tools.ietf.org/html/rfc6125#section-6.4.3">the specification</a>.
+</li>
+
+<li>
+Also in the <a href="/pkg/crypto/x509/"><code>crypto/x509</code></a> package,
+the handling of unknown critical extensions has been changed.
+They used to cause parse errors but now they are parsed and caused errors only
+in <a href="/pkg/crypto/x509/#Certificate.Verify"><code>Verify</code></a>.
+The new field <code>UnhandledCriticalExtensions</code> of
+<a href="/pkg/crypto/x509/#Certificate"><code>Certificate</code></a> records these extensions.
+</li>
+
+<li>
+The <a href="/pkg/database/sql/#DB"><code>DB</code></a> type of the
+<a href="/pkg/database/sql/"><code>database/sql</code></a> package
+now has a <a href="/pkg/database/sql/#DB.Stats"><code>Stats</code></a> method
+to retrieve database statistics.
+</li>
+
+<li>
+The <a href="/pkg/debug/dwarf/"><code>debug/dwarf</code></a>
+package has extensive additions to better support DWARF version 4.
+See for example the definition of the new type
+<a href="/pkg/debug/dwarf/#Class"><code>Class</code></a>.
+</li>
+
+<li>
+The <a href="/pkg/debug/dwarf/"><code>debug/dwarf</code></a> package
+also now supports decoding of DWARF line tables.
+</li>
+
+<li>
+The <a href="/pkg/debug/elf/"><code>debug/elf</code></a>
+package now has support for the 64-bit PowerPC architecture.
+</li>
+
+<li>
+The <a href="/pkg/encoding/base64/"><code>encoding/base64</code></a> package
+now supports unpadded encodings through two new encoding variables,
+<a href="/pkg/encoding/base64/#RawStdEncoding"><code>RawStdEncoding</code></a> and
+<a href="/pkg/encoding/base64/#RawURLEncoding"><code>RawURLEncoding</code></a>.
+</li>
+
+<li>
+The <a href="/pkg/encoding/json/"><code>encoding/json</code></a> package
+now returns an <a href="/pkg/encoding/json/#UnmarshalTypeError"><code>UnmarshalTypeError</code></a>
+if a JSON value is not appropriate for the target variable or component
+to which it is being unmarshaled.
+</li>
+
+<li>
+The <code>encoding/json</code>'s
+<a href="/pkg/encoding/json/#Decoder"><code>Decoder</code></a>
+type has a new method that provides a streaming interface for decoding
+a JSON document:
+<a href="/pkg/encoding/json/#Decoder.Token"><code>Token</code></a>.
+It also interoperates with the existing functionality of <code>Decode</code>,
+which will continue a decode operation already started with <code>Decoder.Token</code>.
+</li>
+
+<li>
+The <a href="/pkg/flag/"><code>flag</code></a> package
+has a new function, <a href="/pkg/flag/#UnquoteUsage"><code>UnquoteUsage</code></a>,
+to assist in the creation of usage messages using the new convention
+described above.
+</li>
+
+<li>
+In the <a href="/pkg/fmt/"><code>fmt</code></a> package,
+a value of type <a href="/pkg/reflect/#Value"><code>Value</code></a> now
+prints what it holds, rather than use the <code>reflect.Value</code>'s <code>Stringer</code>
+method, which produces things like <code><int Value></code>.
+</li>
+
+<li>
+The <a href="/pkg/ast/#EmptyStmt"><code>EmptyStmt</code></a> type
+in the <a href="/pkg/go/ast/"><code>go/ast</code></a> package now
+has a boolean <code>Implicit</code> field that records whether the
+semicolon was implicitly added or was present in the source.
+</li>
+
+<li>
+For forward compatibility the <a href="/pkg/go/build/"><code>go/build</code></a> package
+reserves <code>GOARCH</code> values for  a number of architectures that Go might support one day.
+This is not a promise that it will.
+Also, the <a href="/pkg/go/build/#Package"><code>Package</code></a> struct
+now has a <code>PkgTargetRoot</code> field that stores the
+architecture-dependent root directory in which to install, if known.
+</li>
+
+<li>
+The (newly migrated) <a href="/pkg/go/types/"><code>go/types</code></a>
+package allows one to control the prefix attached to package-level names using
+the new <a href="/pkg/go/types/#Qualifier"><code>Qualifier</code></a>
+function type as an argument to several functions. This is an API change for
+the package, but since it is new to the core, it is not breaking the Go 1 compatibility
+rules since code that uses the package must explicitly ask for it at its new location.
+To update, run
+<a href="https://golang.org/cmd/go/#hdr-Run_go_tool_fix_on_packages"><code>go fix</code></a> on your package.
+</li>
+
+<li>
+In the <a href="/pkg/image/"><code>image</code></a> package,
+the <a href="/pkg/image/#Rectangle"><code>Rectangle</code></a> type
+now implements the <a href="/pkg/image/#Image"><code>Image</code></a> interface,
+so a <code>Rectangle</code> can serve as a mask when drawing.
+</li>
+
+<li>
+Also in the <a href="/pkg/image/"><code>image</code></a> package,
+to assist in the handling of some JPEG images,
+there is now support for 4:1:1 and 4:1:0 YCbCr subsampling and basic
+CMYK support, represented by the new <code>image.CMYK</code> struct.
+</li>
+
+<li>
+The <a href="/pkg/image/color/"><code>image/color</code></a> package
+adds basic CMYK support, through the new
+<a href="/pkg/image/color/#CMYK"><code>CMYK</code></a> struct,
+the <a href="/pkg/image/color/#CMYKModel"><code>CMYKModel</code></a> color model, and the
+<a href="/pkg/image/color/#CMYKToRGB"><code>CMYKToRGB</code></a> function, as
+needed by some JPEG images.
+</li>
+
+<li>
+Also in the <a href="/pkg/image/color/"><code>image/color</code></a> package,
+the conversion of a <a href="/pkg/image/color/#YCbCr"><code>YCbCr</code></a>
+value to <code>RGBA</code> has become more precise.
+Previously, the low 8 bits were just an echo of the high 8 bits;
+now they contain more accurate information.
+Because of the echo property of the old code, the operation
+<code>uint8(r)</code> to extract an 8-bit red value worked, but is incorrect.
+In Go 1.5, that operation may yield a different value.
+The correct code is, and always was, to select the high 8 bits:
+<code>uint8(r>>8)</code>.
+Incidentally, the <code>image/draw</code> package
+provides better support for such conversions; see
+<a href="https://blog.golang.org/go-imagedraw-package">this blog post</a>
+for more information.
+</li>
+
+<li>
+Finally, as of Go 1.5 the closest match check in
+<a href="/pkg/image/color/#Palette.Index"><code>Index</code></a>
+now honors the alpha channel.
+</li>
+
+<li>
+The <a href="/pkg/image/gif/"><code>image/gif</code></a> package
+includes a couple of generalizations.
+A multiple-frame GIF file can now have an overall bounds different
+from all the contained single frames' bounds.
+Also, the <a href="/pkg/image/gif/#GIF"><code>GIF</code></a> struct
+now has a <code>Disposal</code> field
+that specifies the disposal method for each frame.
+</li>
+
+<li>
+The <a href="/pkg/io/"><code>io</code></a> package
+adds a <a href="/pkg/io/#CopyBuffer"><code>CopyBuffer</code></a> function
+that is like <a href="/pkg/io/#Copy"><code>Copy</code></a> but
+uses a caller-provided buffer, permitting control of allocation and buffer size.
+</li>
+
+<li>
+The <a href="/pkg/log/"><code>log</code></a> package
+has a new <a href="/pkg/log/#LUTC"><code>LUTC</code></a> flag
+that causes time stamps to be printed in the UTC time zone.
+It also adds a <a href="/pkg/log/#Logger.SetOutput"><code>SetOutput</code></a> method
+for user-created loggers.
+</li>
+
+<li>
+In Go 1.4, <a href="/pkg/math/#Max"><code>Max</code></a> was not detecting all possible NaN bit patterns.
+This is fixed in Go 1.5, so programs that use <code>math.Max</code> on data including NaNs may behave differently,
+but now correctly according to the IEEE754 definition of NaNs.
+</li>
+
+<li>
+The <a href="/pkg/math/big/"><code>math/big</code></a> package
+adds a new <a href="/pkg/math/big/#Jacobi"><code>Jacobi</code></a>
+function for integers and a new
+<a href="/pkg/math/big/#Int.ModSqrt"><code>ModSqrt</code></a>
+method for the <a href="/pkg/math/big/#Int"><code>Int</code></a> type.
+</li>
+
+<li>
+The mime package
+adds a new <a href="/pkg/mime/#WordDecoder"><code>WordDecoder</code></a> type
+to decode MIME headers containing RFC 204-encoded words.
+It also provides <a href="/pkg/mime/#BEncoding"><code>BEncoding</code></a> and
+<a href="/pkg/mime/#QEncoding"><code>QEncoding</code></a>
+as implementations of the encoding schemes of RFC 2045 and RFC 2047.
+</li>
+
+<li>
+The <a href="/pkg/mime/"><code>mime</code></a> package also adds an
+<a href="/pkg/mime/#ExtensionsByType"><code>ExtensionsByType</code></a>
+function that returns the MIME extensions know to be associated with a given MIME type.
+</li>
+
+<li>
+There is a new <a href="/pkg/mime/quotedprintable/"><code>mime/quotedprintable</code></a>
+package that implements the quoted-printable encoding defined by RFC 2045.
+</li>
+
+<li>
+The <a href="/pkg/net/"><code>net</code></a> package will now
+<a href="/pkg/net/#Dial"><code>Dial</code></a> hostnames by trying each
+IP address in order until one succeeds.
+The <code><a href="/pkg/net/#Dialer">Dialer</a>.DualStack</code>
+mode now implements Happy Eyeballs
+(<a href="https://tools.ietf.org/html/rfc6555">RFC 6555</a>) by giving the
+first address family a 300ms head start; this value can be overridden by
+the new <code>Dialer.FallbackDelay</code>.
+</li>
+
+<li>
+A number of inconsistencies in the types returned by errors in the
+<a href="/pkg/net/"><code>net</code></a> package have been
+tidied up.
+Most now return an
+<a href="/pkg/net/#OpError"><code>OpError</code></a> value
+with more information than before.
+Also, the <a href="/pkg/net/#OpError"><code>OpError</code></a>
+type now includes a <code>Source</code> field that holds the local
+network address.
+</li>
+
+<li>
+The <a href="/pkg/net/http/"><code>net/http</code></a> package now
+has support for setting trailers from a server <a href="/pkg/net/http/#Handler"><code>Handler</code></a>.
+For details, see the documentation for
+<a href="/pkg/net/http/#ResponseWriter"><code>ResponseWriter</code></a>.
+</li>
+
+<li>
+There is a new method to cancel a <a href="/pkg/net/http/"><code>net/http</code></a>
+<code>Request</code> by setting the new
+<a href="/pkg/net/http/#Request"><code>Request.Cancel</code></a>
+field.
+It is supported by <code>http.Transport</code>.
+The <code>Cancel</code> field's type is compatible with the
+<a href="https://godoc.org/golang.org/x/net/context"><code>context.Context.Done</code></a>
+return value.
+</li>
+
+<li>
+Also in the <a href="/pkg/net/http/"><code>net/http</code></a> package,
+there is code to ignore the zero <a href="/pkg/time/#Time"><code>Time</code></a> value
+in the <a href="/pkg/net/#ServeContent"><code>ServeContent</code></a> function.
+As of Go 1.5, it now also ignores a time value equal to the Unix epoch.
+</li>
+
+<li>
+The <a href="/pkg/net/http/fcgi/"><code>net/http/fcgi</code></a> package
+exports two new errors,
+<a href="/pkg/net/http/fcgi/#ErrConnClosed"><code>ErrConnClosed</code></a> and
+<a href="/pkg/net/http/fcgi/#ErrRequestAborted"><code>ErrRequestAborted</code></a>,
+to report the corresponding error conditions.
+</li>
+
+<li>
+The <a href="/pkg/net/http/cgi/"><code>net/http/cgi</code></a> package
+had a bug that mishandled the values of the environment variables
+<code>REMOTE_ADDR</code> and <code>REMOTE_HOST</code>.
+This has been fixed.
+Also, starting with Go 1.5 the package sets the <code>REMOTE_PORT</code>
+variable.
+</li>
+
+<li>
+The <a href="/pkg/net/mail/"><code>net/mail</code></a> package
+adds an <a href="/pkg/net/mail/#AddressParser"><code>AddressParser</code></a>
+type that can parse mail addresses.
+</li>
+
+<li>
+The <a href="/pkg/net/smtp/"><code>net/smtp</code></a> package
+now has a <a href="/pkg/net/smtp/#Client.TLSConnectionState"><code>TLSConnectionState</code></a>
+accessor to the <a href="/pkg/net/smtp/#Client"><code>Client</code></a>
+type that returns the client's TLS state.
+</li>
+
+<li>
+The <a href="/pkg/os/"><code>os</code></a> package
+has a new <a href="/pkg/os/#LookupEnv"><code>LookupEnv</code></a> function
+that is similar to <a href="/pkg/os/#Getenv"><code>Getenv</code></a>
+but can distinguish between an empty environment variable and a missing one.
+</li>
+
+<li>
+The <a href="/pkg/os/signal/"><code>os/signal</code></a> package
+adds new <a href="/pkg/os/signal/#Ignore"><code>Ignore</code></a> and
+<a href="/pkg/os/signal/#Reset"><code>Reset</code></a> functions.
+</li>
+
+<li>
+The <a href="/pkg/runtime/"><code>runtime</code></a>,
+<a href="/pkg/runtime/trace/"><code>runtime/trace</code></a>,
+and <a href="/pkg/net/http/pprof/"><code>net/http/pprof</code></a> packages
+each have new functions to support the tracing facilities described above:
+<a href="/pkg/runtime/#ReadTrace"><code>ReadTrace</code></a>,
+<a href="/pkg/runtime/#StartTrace"><code>StartTrace</code></a>,
+<a href="/pkg/runtime/#StopTrace"><code>StopTrace</code></a>,
+<a href="/pkg/runtime/trace/#Start"><code>Start</code></a>,
+<a href="/pkg/runtime/trace/#Stop"><code>Stop</code></a>, and
+<a href="/pkg/net/http/pprof/#Trace"><code>Trace</code></a>.
+See the respective documentation for details.
+</li>
+
+<li>
+The <a href="/pkg/runtime/pprof/"><code>runtime/pprof</code></a> package
+by default now includes overall memory statistics in all memory profiles.
+</li>
+
+<li>
+The <a href="/pkg/strings/"><code>strings</code></a> package
+has a new <a href="/pkg/strings/#Compare"><code>Compare</code></a> function.
+This is present to provide symmetry with the <a href="/pkg/bytes/"><code>bytes</code></a> package
+but is otherwise unnecessary as strings support comparison natively.
+</li>
+
+<li>
+The <a href="/pkg/sync/#WaitGroup"><code>WaitGroup</code></a> implementation in
+package <a href="/pkg/sync/"><code>sync</code></a>
+now diagnoses code that races a call to <a href="/pkg/sync/#WaitGroup.Add"><code>Add</code></a>
+against a return from <a href="/pkg/sync/#WaitGroup.Wait"><code>Wait</code></a>.
+If it detects this condition, the implementation panics.
+</li>
+
+<li>
+In the <a href="/pkg/syscall/"><code>syscall</code></a> package,
+the Linux <code>SysProcAttr</code> struct now has a
+<code>GidMappingsEnableSetgroups</code> field, made necessary
+by security changes in Linux 3.19.
+On all Unix systems, the struct also has new <code>Foreground</code> and <code>Pgid</code> fields
+to provide more control when exec'ing.
+On Darwin, there is now a <code>Syscall9</code> function
+to support calls with too many arguments.
+</li>
+
+<li>
+The <a href="/pkg/testing/quick/"><code>testing/quick</code></a> will now
+generate <code>nil</code> values for pointer types,
+making it possible to use with recursive data structures.
+Also, the package now supports generation of array types.
+</li>
+
+<li>
+In the <a href="/pkg/text/template/"><code>text/template</code></a> and
+<a href="/pkg/html/template/"><code>html/template</code></a> packages,
+integer constants too large to be represented as a Go integer now trigger a
+parse error. Before, they were silently converted to floating point, losing
+precision.
+</li>
+
+<li>
+Also in the <a href="/pkg/text/template/"><code>text/template</code></a> and
+<a href="/pkg/html/template/"><code>html/template</code></a> packages,
+a new <a href="/pkg/text/template/#Template.Option"><code>Option</code></a> method
+allows customization of the behavior of the template during execution.
+The sole implemented option allows control over how a missing key is
+handled when indexing a map.
+The default, which can now be overridden, is as before: to continue with an invalid value.
+</li>
+
+<li>
+The <a href="/pkg/time/"><code>time</code></a> package's
+<code>Time</code> type has a new method
+<a href="/pkg/time/#Time.AppendFormat"><code>AppendFormat</code></a>,
+which can be used to avoid allocation when printing a time value.
+</li>
+
+<li>
+The <a href="/pkg/unicode/"><code>unicode</code></a> package and associated
+support throughout the system has been upgraded from version 7.0 to
+<a href="http://www.unicode.org/versions/Unicode8.0.0/">Unicode 8.0</a>.
+</li>
+
+</ul>
diff --git a/doc/go1compat.html b/doc/go1compat.html
index d800dec..607d354 100644
--- a/doc/go1compat.html
+++ b/doc/go1compat.html
@@ -96,6 +96,18 @@ in a separate package should use the keyed notation.
 </li>
 
 <li>
+Methods. As with struct fields, it may be necessary to add methods
+to types.
+Under some circumstances, such as when the type is embedded in
+a struct along with another type,
+the addition of the new method may break
+the struct by creating a conflict with an existing method of the other
+embedded type.
+We cannot protect against this rare case and do not guarantee compatibility
+should it arise.
+</li>
+
+<li>
 Dot imports. If a program imports a standard package
 using <code>import . "path"</code>, additional names defined in the
 imported package in future releases may conflict with other names
diff --git a/doc/go_faq.html b/doc/go_faq.html
index 6b77f1c..33636fc 100644
--- a/doc/go_faq.html
+++ b/doc/go_faq.html
@@ -92,13 +92,6 @@ portability and the addition of new functionality such as improved support for i
 There may well be a Go 2 one day, but not for a few years and it will be influenced by what we learn using Go 1 as it is today.
 </p>
 
-<h3 id="What_is_the_origin_of_the_name">
-What is the origin of the name?</h3>
-
-<p>
-“Ogle” would be a good name for a Go debugger.
-</p>
-
 <h3 id="Whats_the_origin_of_the_mascot">
 What's the origin of the mascot?</h3>
 
@@ -107,7 +100,8 @@ The mascot and logo were designed by
 <a href="http://reneefrench.blogspot.com">Renée French</a>, who also designed
 <a href="http://plan9.bell-labs.com/plan9/glenda.html">Glenda</a>,
 the Plan 9 bunny.
-The gopher is derived from one she used for an <a href="http://wfmu.org/">WFMU</a>
+The <a href="https://blog.golang.org/gopher">gopher</a>
+is derived from one she used for an <a href="http://wfmu.org/">WFMU</a>
 T-shirt design some years ago.
 The logo and mascot are covered by the
 <a href="http://creativecommons.org/licenses/by/3.0/">Creative Commons Attribution 3.0</a>
@@ -153,7 +147,7 @@ Go is an attempt to combine the ease of programming of an interpreted,
 dynamically typed
 language with the efficiency and safety of a statically typed, compiled language.
 It also aims to be modern, with support for networked and multicore
-computing.  Finally, it is intended to be <i>fast</i>: it should take
+computing.  Finally, working with Go is intended to be <i>fast</i>: it should take
 at most a few seconds to build a large executable on a single computer.
 To meet these goals required addressing a number of
 linguistic issues: an expressive but lightweight type system;
@@ -228,7 +222,7 @@ document server running in a production configuration on
 </p>
 
 <p>
-Other examples include the <a href="//code.google.com/p/vitess/">Vitess</a>
+Other examples include the <a href="//github.com/youtube/vitess/">Vitess</a>
 system for large-scale SQL installations and Google's download server, <code>dl.google.com</code>,
 which delivers Chrome binaries and other large installables such as <code>apt-get</code>
 packages.
@@ -239,7 +233,7 @@ Do Go programs link with C/C++ programs?</h3>
 
 <p>
 There are two Go compiler implementations, <code>gc</code>
-(the <code>6g</code> program and friends) and <code>gccgo</code>.
+and <code>gccgo</code>.
 <code>Gc</code> uses a different calling convention and linker and can
 therefore only be linked with C programs using the same convention.
 There is such a C compiler but no C++ compiler.
@@ -260,7 +254,7 @@ Does Go support Google's protocol buffers?</h3>
 <p>
 A separate open source project provides the necessary compiler plugin and library.
 It is available at
-<a href="//code.google.com/p/goprotobuf/">code.google.com/p/goprotobuf/</a>
+<a href="//github.com/golang/protobuf">github.com/golang/protobuf/</a>
 </p>
 
 
@@ -508,7 +502,7 @@ They are not restricted to structs (classes).
 </p>
 
 <p>
-Also, the lack of type hierarchy makes “objects” in Go feel much more
+Also, the lack of a type hierarchy makes “objects” in Go feel much more
 lightweight than in languages such as C++ or Java.
 </p>
 
@@ -608,17 +602,19 @@ How can I guarantee my type satisfies an interface?</h3>
 
 <p>
 You can ask the compiler to check that the type <code>T</code> implements the
-interface <code>I</code> by attempting an assignment:
+interface <code>I</code> by attempting an assignment using the zero value for
+<code>T</code> or pointer to <code>T</code>, as appropriate:
 </p>
 
 <pre>
 type T struct{}
-var _ I = T{}   // Verify that T implements I.
+var _ I = T{}       // Verify that T implements I.
+var _ I = (*T)(nil) // Verify that *T implements I.
 </pre>
 
 <p>
-If <code>T</code> doesn't implement <code>I</code>, the mistake will be caught
-at compile time.
+If <code>T</code> (or <code>*T</code>, accordingly) doesn't implement
+<code>I</code>, the mistake will be caught at compile time.
 </p>
 
 <p>
@@ -726,7 +722,7 @@ interface satisfaction very easy to state: are the function's names
 and signatures exactly those of the interface?
 Go's rule is also easy to implement efficiently.
 We feel these benefits offset the lack of
-automatic type promotion. Should Go one day adopt some form of generic
+automatic type promotion. Should Go one day adopt some form of polymorphic
 typing, we expect there would be a way to express the idea of these
 examples and also have them be statically checked.
 </p>
@@ -765,7 +761,7 @@ schematically, (<code>int</code>, <code>3</code>).
 An interface value is <code>nil</code> only if the inner value and type are both unset,
 (<code>nil</code>, <code>nil</code>).
 In particular, a <code>nil</code> interface will always hold a <code>nil</code> type.
-If we store a pointer of type <code>*int</code> inside
+If we store a <code>nil</code> pointer of type <code>*int</code> inside
 an interface value, the inner type will be <code>*int</code> regardless of the value of the pointer:
 (<code>*int</code>, <code>nil</code>).
 Such an interface value will therefore be non-<code>nil</code>
@@ -773,7 +769,7 @@ Such an interface value will therefore be non-<code>nil</code>
 </p>
 
 <p>
-This situation can be confusing, and often arises when a <code>nil</code> value is
+This situation can be confusing, and arises when a <code>nil</code> value is
 stored inside an interface value such as an <code>error</code> return:
 </p>
 
@@ -890,7 +886,7 @@ encourages you to be explicit.
 </p>
 
 <p>
-A blog post, title <a href="http://blog.golang.org/constants">Constants</a>,
+A blog post titled <a href="https://blog.golang.org/constants">Constants</a>
 explores this topic in more detail.
 </p>
 
@@ -950,6 +946,19 @@ In fact, <code>godoc</code> implements the full site at
 <a href="/">golang.org/</a>.
 </p>
 
+<p>
+A <code>godoc</code> instance may be configured to provide rich,
+interactive static analyses of symbols in the programs it displays; details are
+listed <a href="https://golang.org/lib/godoc/analysis/help.html">here</a>.
+</p>
+
+<p>
+For access to documentation from the command line, the
+<a href="https://golang.org/pkg/cmd/go/">go</a> tool has a
+<a href="https://golang.org/pkg/cmd/go/#hdr-Show_documentation_for_package_or_symbol">doc</a>
+subcommand that provides a textual interface to the same information.
+</p>
+
 <h3 id="Is_there_a_Go_programming_style_guide">
 Is there a Go programming style guide?</h3>
 
@@ -1046,7 +1055,17 @@ unexpected ways, the simplest solution is to copy it to your local repository.
 (This is the approach Google takes internally.)
 Store the copy under a new import path that identifies it as a local copy.
 For example, you might copy "original.com/pkg" to "you.com/external/original.com/pkg".
-Keith Rarick's <a href="https://github.com/kr/goven">goven</a> is one tool to help automate this process.
+The <a href="https://godoc.org/golang.org/x/tools/cmd/gomvpkg">gomvpkg</a>
+program is one tool to help automate this process.
+</p>
+
+<p>
+The Go 1.5 release includes an experimental facility to the
+<a href="https://golang.org/cmd/go">go</a> command
+that makes it easier to manage external dependencies by "vendoring"
+them into a special directory near the package that depends upon them.
+See the <a href="https://golang.org/s/go15vendor">design
+document</a> for details.
 </p>
 
 <h2 id="Pointers">Pointers and Allocation</h2>
@@ -1061,7 +1080,8 @@ thing being passed, as if there were an assignment statement assigning the
 value to the parameter.  For instance, passing an <code>int</code> value
 to a function makes a copy of the <code>int</code>, and passing a pointer
 value makes a copy of the pointer, but not the data it points to.
-(See the next section for a discussion of how this affects method receivers.)
+(See a <a href="/doc/faq#methods_on_values_or_pointers">later
+section</a> for a discussion of how this affects method receivers.)
 </p>
 
 <p>
@@ -1290,14 +1310,20 @@ See the <a href="/doc/codewalk/sharemem/">Share Memory By Communicating</a> code
 Why doesn't my multi-goroutine program use multiple CPUs?</h3>
 
 <p>
-You must set the <code>GOMAXPROCS</code> shell environment variable
-or use the similarly-named <a href="/pkg/runtime/#GOMAXPROCS"><code>function</code></a>
-of the runtime package to allow the
-run-time support to utilize more than one OS thread.
+The number of CPUs available simultaneously to executing goroutines is
+controlled by the <code>GOMAXPROCS</code> shell environment variable.
+In earlier releases of Go, the default value was 1, but as of Go 1.5 the default
+value is the number of cores available.
+Therefore programs compiled after 1.5 should demonstrate parallel execution
+of multiple goroutines.
+To change the behavior, set the environment variable or use the similarly-named
+<a href="/pkg/runtime/#GOMAXPROCS">function</a>
+of the runtime package to configure the
+run-time support to utilize a different number of threads.
 </p>
 
 <p>
-Programs that perform parallel computation should benefit from an increase in
+Programs that perform parallel computation might benefit from a further increase in
 <code>GOMAXPROCS</code>.
 However, be aware that
 <a href="//blog.golang.org/2013/01/concurrency-is-not-parallelism.html">concurrency
@@ -1319,7 +1345,7 @@ intrinsically parallel.
 <p>
 In practical terms, programs that spend more time
 communicating on channels than doing computation
-will experience performance degradation when using
+may experience performance degradation when using
 multiple OS threads.
 This is because sending data between threads involves switching
 contexts, which has significant cost.
@@ -1330,9 +1356,11 @@ to speed it up.
 </p>
 
 <p>
-Go's goroutine scheduler is not as good as it needs to be. In the future, it
-should recognize such cases and optimize its use of OS threads. For now,
-<code>GOMAXPROCS</code> should be set on a per-application basis.
+Go's goroutine scheduler is not as good as it needs to be, although it
+has improved in recent releases.
+In the future, it may better optimize its use of OS threads.
+For now, if there are performance issues,
+setting <code>GOMAXPROCS</code> on a per-application basis may help.
 </p>
 
 <p>
@@ -1367,7 +1395,10 @@ there is no useful way for a method call to obtain a pointer.
 Even in cases where the compiler could take the address of a value
 to pass to the method, if the method modifies the value the changes
 will be lost in the caller.
-As a common example, this code:
+As an example, if the <code>Write</code> method of
+<a href="/pkg/bytes/#Buffer"><code>bytes.Buffer</code></a>
+used a value receiver rather than a pointer,
+this code:
 </p>
 
 <pre>
@@ -1461,7 +1492,7 @@ seem odd but works fine in Go:
 Does Go have the <code>?:</code> operator?</h3>
 
 <p>
-There is no ternary form in Go. You may use the following to achieve the same
+There is no ternary testing operation in Go. You may use the following to achieve the same
 result:
 </p>
 
@@ -1553,6 +1584,51 @@ test cases. The standard Go library is full of illustrative examples, such as in
 <a href="/src/fmt/fmt_test.go">the formatting tests for the <code>fmt</code> package</a>.
 </p>
 
+<h3 id="x_in_std">
+Why isn't <i>X</i> in the standard library?</h3>
+
+<p>
+The standard library's purpose is to support the runtime, connect to
+the operating system, and provide key functionality that many Go
+programs require, such as formatted I/O and networking.
+It also contains elements important for web programming, including
+cryptography and support for standards like HTTP, JSON, and XML.
+</p>
+
+<p>
+There is no clear criterion that defines what is included because for
+a long time, this was the <i>only</i> Go library.
+There are criteria that define what gets added today, however.
+</p>
+
+<p>
+New additions to the standard library are rare and the bar for
+inclusion is high.
+Code included in the standard library bears a large ongoing maintenance cost
+(often borne by those other than the original author),
+is subject to the <a href="/doc/go1compat.html">Go 1 compatibility promise</a>
+(blocking fixes to any flaws in the API),
+and is subject to the Go
+<a href="https://golang.org/s/releasesched">release schedule</a>,
+preventing bug fixes from being available to users quickly.
+</p>
+
+<p>
+Most new code should live outside of the standard library and be accessible
+via the <a href="/cmd/go/"><code>go</code> tool</a>'s
+<code>go get</code> command.
+Such code can have its own maintainers, release cycle,
+and compatibility guarantees.
+Users can find packages and read their documentation at
+<a href="https://godoc.org/">godoc.org</a>.
+</p>
+
+<p>
+Although there are pieces in the standard library that don't really belong,
+such as <code>log/syslog</code>, we continue to maintain everything in the
+library because of the Go 1 compatibility promise.
+But we encourage most new code to live elsewhere.
+</p>
 
 <h2 id="Implementation">Implementation</h2>
 
@@ -1561,11 +1637,10 @@ What compiler technology is used to build the compilers?</h3>
 
 <p>
 <code>Gccgo</code> has a front end written in C++, with a recursive descent parser coupled to the
-standard GCC back end. <code>Gc</code> is written in C using
-<code>yacc</code>/<code>bison</code> for the parser.
-Although it's a new program, it fits in the Plan 9 C compiler suite
-(<a href="http://plan9.bell-labs.com/sys/doc/compiler.html">http://plan9.bell-labs.com/sys/doc/compiler.html</a>)
-and uses a variant of the Plan 9 loader to generate ELF/Mach-O/PE binaries.
+standard GCC back end. <code>Gc</code> is written in Go using
+<code>yacc</code>/<code>bison</code> for the parser
+and uses a custom loader, also written in Go but
+based on the Plan 9 loader, to generate ELF/Mach-O/PE binaries.
 </p>
 
 <p>
@@ -1574,24 +1649,26 @@ slow to meet our performance goals.
 </p>
 
 <p>
-We also considered writing <code>gc</code>, the original Go compiler, in Go itself but
-elected not to do so because of the difficulties of bootstrapping and
-especially of open source distribution—you'd need a Go compiler to
-set up a Go environment. <code>Gccgo</code>, which came later, makes it possible to
-consider writing a compiler in Go.
-A plan to do that by machine translation of the existing compiler is under development.
-<a href="http://golang.org/s/go13compiler">A separate document</a>
-explains the reason for this approach.
+The original <code>gc</code>, the Go compiler, was written in C
+because of the difficulties of bootstrapping—you'd need a Go compiler to
+set up a Go environment.
+But things have advanced and as of Go 1.5 the compiler is written in Go.
+It was converted from C to Go using automatic translation tools, as
+described in <a href="/s/go13compiler">this design document</a>
+and <a href="https://talks.golang.org/2015/gogo.slide#1">a recent talk</a>.
+Thus the compiler is now "self-hosting", which means we must face
+the bootstrapping problem.
+The solution, naturally, is to have a working Go installation already,
+just as one normally has a working C installation in place.
+The story of how to bring up a new Go installation from source
+is described <a href="/s/go15bootstrap">separately</a>.
 </p>
 
 <p>
-That plan aside,
-Go is a
-fine language in which to implement a self-hosting compiler: a native lexer and
-parser are already available in the <a href="/pkg/go/"><code>go</code></a> package
-and a separate type checking
-<a href="http://godoc.org/golang.org/x/tools/go/types">package</a>
-has also been written.
+Go is a fine language in which to implement a Go compiler.
+Although <code>gc</code> does not use them (yet?), a native lexer and
+parser are available in the <a href="/pkg/go/"><code>go</code></a> package
+and there is also a <a href="/pkg/go/types">type checker</a>.
 </p>
 
 <h3 id="How_is_the_run_time_support_implemented">
@@ -1599,15 +1676,11 @@ How is the run-time support implemented?</h3>
 
 <p>
 Again due to bootstrapping issues, the run-time code was originally written mostly in C (with a
-tiny bit of assembler) although much of it has been translated to Go since then
-and one day all of it might be (except for the assembler bits).
+tiny bit of assembler) but it has since been translated to Go
+(except for some assembler bits).
 <code>Gccgo</code>'s run-time support uses <code>glibc</code>.
-<code>Gc</code> uses a custom C library to keep the footprint under
-control; it is
-compiled with a version of the Plan 9 C compiler that supports
-resizable stacks for goroutines.
-The <code>gccgo</code> compiler implements these on Linux only,
-using a technique called segmented stacks,
+The <code>gccgo</code> compiler implements goroutines using
+a technique called segmented stacks,
 supported by recent modifications to the gold linker.
 </p>
 
@@ -1615,8 +1688,8 @@ supported by recent modifications to the gold linker.
 Why is my trivial program such a large binary?</h3>
 
 <p>
-The linkers in the gc tool chain (<code>5l</code>, <code>6l</code>, and <code>8l</code>)
-do static linking.  All Go binaries therefore include the Go
+The linker in the <code>gc</code> tool chain
+creates statically-linked binaries by default.  All Go binaries therefore include the Go
 run-time, along with the run-time type information necessary to support dynamic
 type checks, reflection, and even panic-time stack traces.
 </p>
@@ -1626,7 +1699,7 @@ A simple C "hello, world" program compiled and linked statically using gcc
 on Linux is around 750 kB,
 including an implementation of <code>printf</code>.
 An equivalent Go program using <code>fmt.Printf</code>
-is around 1.9 MB, but
+is around 2.3 MB, but
 that includes more powerful run-time support and type information.
 </p>
 
@@ -1885,8 +1958,12 @@ simpler because they don't need to specify how memory is managed across them.
 </p>
 
 <p>
-The current implementation is a parallel mark-and-sweep
-collector but a future version might take a different approach.
+The current implementation is a parallel mark-and-sweep collector.
+Recent improvements, documented in
+<a href="/s/go14gc">this design document</a>,
+have introduced bounded pause times and improved the
+parallelism.
+Future versions might attempt new approaches.
 </p>
 
 <p>
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 @@ var limit = make(chan int, 3)
 
 func main() {
 	for _, w := range work {
-		go func() {
-			limit <- 1
+		go func(w func()) {
+			limit <- 1
 			w()
-			<-limit
-		}()
+			<-limit
+		}(w)
 	}
 	select{}
 }
diff --git a/doc/go_spec.html b/doc/go_spec.html
index ca0deb5..22f9701 100644
--- a/doc/go_spec.html
+++ b/doc/go_spec.html
@@ -1,24 +1,9 @@
 <!--{
 	"Title": "The Go Programming Language Specification",
-	"Subtitle": "Version of November 11, 2014",
+	"Subtitle": "Version of August 5, 2015",
 	"Path": "/ref/spec"
 }-->
 
-<!--
-TODO
-[ ] need language about function/method calls and parameter passing rules
-[ ] last paragraph of #Assignments (constant promotion) should be elsewhere
-    and mention assignment to empty interface.
-[ ] need to say something about "scope" of selectors?
-[ ] clarify what a field name is in struct declarations
-    (struct{T} vs struct {T T} vs struct {t T})
-[ ] need explicit language about the result type of operations
-[ ] should probably write something about evaluation order of statements even
-	though obvious
-[ ] in Selectors section, clarify what receiver value is passed in method invocations
--->
-
-
 <h2 id="Introduction">Introduction</h2>
 
 <p>
@@ -144,27 +129,27 @@ hex_digit     = "0" … "9" | "A" … "F" | "a" … "f" .
 <h3 id="Comments">Comments</h3>
 
 <p>
-There are two forms of comments:
+Comments serve as program documentation. There are two forms:
 </p>
 
 <ol>
 <li>
 <i>Line comments</i> start with the character sequence <code>//</code>
-and stop at the end of the line. A line comment acts like a newline.
+and stop at the end of the line.
 </li>
 <li>
 <i>General comments</i> start with the character sequence <code>/*</code>
-and continue through the character sequence <code>*/</code>. A general
-comment containing one or more newlines acts like a newline, otherwise it acts
-like a space.
+and stop with the first subsequent character sequence <code>*/</code>.
 </li>
 </ol>
 
 <p>
-Comments do not nest.
+A comment cannot start inside a <a href="#Rune_literals">rune</a> or
+<a href="#String_literals">string literal</a>, or inside a comment.
+A general comment containing no newlines acts like a space.
+Any other comment acts like a newline.
 </p>
 
-
 <h3 id="Tokens">Tokens</h3>
 
 <p>
@@ -191,11 +176,8 @@ using the following two rules:
 
 <ol>
 <li>
-<p>
 When the input is broken into tokens, a semicolon is automatically inserted
-into the token stream at the end of a non-blank line if the line's final
-token is
-</p>
+into the token stream immediately after a line's final token if that token is
 <ul>
 	<li>an
 	    <a href="#Identifiers">identifier</a>
@@ -372,9 +354,10 @@ imaginary_lit = (decimals | float_lit) "i" .
 <p>
 A rune literal represents a <a href="#Constants">rune constant</a>,
 an integer value identifying a Unicode code point.
-A rune literal is expressed as one or more characters enclosed in single quotes.
-Within the quotes, any character may appear except single
-quote and newline. A single quoted character represents the Unicode value
+A rune literal is expressed as one or more characters enclosed in single quotes,
+as in <code>'x'</code> or <code>'\n'</code>.
+Within the quotes, any character may appear except newline and unescaped single
+quote. A single quoted character represents the Unicode value
 of the character itself,
 while multi-character sequences beginning with a backslash encode
 values in various formats.
@@ -448,6 +431,7 @@ escaped_char     = `\` ( "a" | "b" | "f" | "n" | "r" | "t" | "v" | `\` | "'" | `
 '\xff'
 '\u12e4'
 '\U00101234'
+'\''         // rune literal containing single quote character
 'aa'         // illegal: too many characters
 '\xa'        // illegal: too few hexadecimal digits
 '\0'         // illegal: too few octal digits
@@ -464,8 +448,8 @@ obtained from concatenating a sequence of characters. There are two forms:
 raw string literals and interpreted string literals.
 </p>
 <p>
-Raw string literals are character sequences between back quotes
-<code>``</code>.  Within the quotes, any character is legal except
+Raw string literals are character sequences between back quotes, as in
+<code>`foo`</code>.  Within the quotes, any character may appear except
 back quote. The value of a raw string literal is the
 string composed of the uninterpreted (implicitly UTF-8-encoded) characters
 between the quotes;
@@ -476,8 +460,9 @@ are discarded from the raw string value.
 </p>
 <p>
 Interpreted string literals are character sequences between double
-quotes <code>""</code>. The text between the quotes,
-which may not contain newlines, forms the
+quotes, as in <code>"bar"</code>.
+Within the quotes, any character may appear except newline and unescaped double quote.
+The text between the quotes forms the
 value of the literal, with backslash escapes interpreted as they
 are in <a href="#Rune_literals">rune literals</a> (except that <code>\'</code> is illegal and
 <code>\"</code> is legal), with the same restrictions.
@@ -499,17 +484,17 @@ interpreted_string_lit = `"` { unicode_value | byte_value } `"` .
 </pre>
 
 <pre>
-`abc`  // same as "abc"
+`abc`                // same as "abc"
 `\n
-\n`    // same as "\\n\n\\n"
+\n`                  // same as "\\n\n\\n"
 "\n"
-""
+"\""                 // same as `"`
 "Hello, world!\n"
 "日本語"
 "\u65e5本\U00008a9e"
 "\xff\u00FF"
-"\uD800"       // illegal: surrogate half
-"\U00110000"   // illegal: invalid Unicode code point
+"\uD800"             // illegal: surrogate half
+"\U00110000"         // illegal: invalid Unicode code point
 </pre>
 
 <p>
@@ -677,7 +662,7 @@ acts like a variable.
 </p>
 
 <p>
-The <i>static type</i> (or just <i>type</i>) of a variable is the	
+The <i>static type</i> (or just <i>type</i>) of a variable is the
 type given in its declaration, the type provided in the
 <code>new</code> call or composite literal, or the type of
 an element of a structured variable.
@@ -687,8 +672,8 @@ which is the concrete type of the value assigned to the variable at run time
 which has no type).
 The dynamic type may vary during execution but values stored in interface
 variables are always <a href="#Assignability">assignable</a>
-to the static type of the variable.	
-</p>	
+to the static type of the variable.
+</p>
 
 <pre>
 var x interface{}  // x is nil and has static type interface{}
@@ -1933,7 +1918,7 @@ const (
 )
 
 func (tz TimeZone) String() string {
-	return fmt.Sprintf("GMT+%dh", tz)
+	return fmt.Sprintf("GMT%+dh", tz)
 }
 </pre>
 
@@ -1981,7 +1966,7 @@ with no explicit type.
 </p>
 
 <pre>
-var d = math.Sin(0.5)  // d is int64
+var d = math.Sin(0.5)  // d is float64
 var i = 42             // i is int
 var t, ok = x.(T)      // t is T, ok is bool
 var n = nil            // illegal
@@ -2021,12 +2006,12 @@ _, y, _ := coord(p)  // coord() returns three values; only interested in y coord
 </pre>
 
 <p>
-Unlike regular variable declarations, a short variable declaration may redeclare variables provided they
-were originally declared earlier in the same block with the same type, and at
-least one of the non-<a href="#Blank_identifier">blank</a> variables is new.  As a consequence, redeclaration
-can only appear in a multi-variable short declaration.
-Redeclaration does not introduce a new
-variable; it just assigns a new value to the original.
+Unlike regular variable declarations, a short variable declaration may <i>redeclare</i>
+variables provided they were originally declared earlier in the same block
+(or the parameter lists if the block is the function body) with the same type, 
+and at least one of the non-<a href="#Blank_identifier">blank</a> variables is new.
+As a consequence, redeclaration can only appear in a multi-variable short declaration.
+Redeclaration does not introduce a new variable; it just assigns a new value to the original.
 </p>
 
 <pre>
@@ -2065,13 +2050,13 @@ a <a href="#Terminating_statements">terminating statement</a>.
 </p>
 
 <pre>
-func findMarker(c <-chan int) int {
-	for i := range c {
-		if x := <-c; isMarker(x) {
-			return x
+func IndexRune(s string, r rune) int {
+	for i, c := range s {
+		if c == r {
+			return i
 		}
 	}
-	// invalid: missing return statement.
+	// invalid: missing return statement
 }
 </pre>
 
@@ -2105,14 +2090,15 @@ Receiver     = Parameters .
 </pre>
 
 <p>
-The receiver is specified via an extra parameter section preceeding the method
+The receiver is specified via an extra parameter section preceding the method
 name. That parameter section must declare a single parameter, the receiver.
 Its type must be of the form <code>T</code> or <code>*T</code> (possibly using
 parentheses) where <code>T</code> is a type name. The type denoted by <code>T</code> is called
 the receiver <i>base type</i>; it must not be a pointer or interface type and
 it must be declared in the same package as the method.
 The method is said to be <i>bound</i> to the base type and the method name
-is visible only within selectors for that type.
+is visible only within <a href="#Selectors">selectors</a> for type <code>T</code>
+or <code>*T</code>.
 </p>
 
 <p>
@@ -2236,9 +2222,8 @@ LiteralType   = StructType | ArrayType | "[" "..." "]" ElementType |
 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 +2342,21 @@ tmp[0 : n]
 
 <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>&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>&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{&Point{1.5, -3.5}, &Point{0, 0}}
 
-[...]*Point{{1.5, -3.5}, {0, 0}}  // same as [...]*Point{&Point{1.5, -3.5}, &Point{0, 0}}
+map[Point]string{{0, 0}: "orig"}    // same as map[Point]string{Point{0, 0}: "orig"}
 </pre>
 
 <p>
@@ -2602,7 +2591,7 @@ one may write:
 <pre>
 t.z          // t.z
 t.y          // t.T1.y
-t.x          // (*t.TO).x
+t.x          // (*t.T0).x
 
 p.z          // (*p).z
 p.y          // (*p).T1.y
@@ -2610,9 +2599,10 @@ p.x          // (*(*p).T0).x
 
 q.x          // (*(*q).T0).x        (*q).x is a valid field selector
 
-p.M2()       // p.M2()              M2 expects *T2 receiver
+p.M0()       // ((*p).T0).M0()      M0 expects *T0 receiver
 p.M1()       // ((*p).T1).M1()      M1 expects T1 receiver
-p.M0()       // ((&(*p).T0)).M0()   M0 expects *T0 receiver, see section on Calls
+p.M2()       // p.M2()              M2 expects *T2 receiver
+t.M2()       // (&t).M2()           M2 expects *T2 receiver, see section on Calls
 </pre>
 
 <p>
@@ -3302,7 +3292,7 @@ Operators combine operands into expressions.
 </p>
 
 <pre class="ebnf">
-Expression = UnaryExpr | Expression binary_op UnaryExpr .
+Expression = UnaryExpr | Expression binary_op Expression .
 UnaryExpr  = PrimaryExpr | unary_op UnaryExpr .
 
 binary_op  = "||" | "&&" | rel_op | add_op | mul_op .
@@ -3331,7 +3321,7 @@ to the type of the other operand.
 The right operand in a shift expression must have unsigned integer type
 or be an untyped constant that can be converted to unsigned integer type.
 If the left operand of a non-constant shift expression is an untyped constant,
-the type of the constant is what it would be if the shift expression were
+it is first converted to the type it would assume if the shift expression were
 replaced by its left operand alone.
 </p>
 
@@ -3351,7 +3341,8 @@ var v float32 = 1<<s   // illegal: 1 has type float32, cannot shift
 var w int64 = 1.0<<33  // 1.0<<33 is a constant shift expression
 </pre>
 
-<h3 id="Operator_precedence">Operator precedence</h3>
+
+<h4 id="Operator_precedence">Operator precedence</h4>
 <p>
 Unary operators have the highest precedence.
 As the  <code>++</code> and <code>--</code> operators form
@@ -3393,9 +3384,9 @@ x == y+1 && <-chanPtr > 0
 <p>
 Arithmetic operators apply to numeric values and yield a result of the same
 type as the first operand. The four standard arithmetic operators (<code>+</code>,
-<code>-</code>,  <code>*</code>, <code>/</code>) apply to integer,
-floating-point, and complex types; <code>+</code> also applies
-to strings. All other arithmetic operators apply to integers only.
+<code>-</code>, <code>*</code>, <code>/</code>) apply to integer,
+floating-point, and complex types; <code>+</code> also applies to strings.
+The bitwise logical and shift operators apply to integers only.
 </p>
 
 <pre class="grammar">
@@ -3414,20 +3405,10 @@ to strings. All other arithmetic operators apply to integers only.
 >>   right shift            integer >> unsigned integer
 </pre>
 
-<p>
-Strings can be concatenated using the <code>+</code> operator
-or the <code>+=</code> assignment operator:
-</p>
 
-<pre>
-s := "hi" + string(c)
-s += " and good bye"
-</pre>
+<h4 id="Integer_operators">Integer operators</h4>
 
 <p>
-String addition creates a new string by concatenating the operands.
-</p>
-<p>
 For two integer values <code>x</code> and <code>y</code>, the integer quotient
 <code>q = x / y</code> and remainder <code>r = x % y</code> satisfy the following
 relationships:
@@ -3503,16 +3484,8 @@ follows:
                                       and  m = -1 for signed x
 </pre>
 
-<p>
-For floating-point and complex numbers,
-<code>+x</code> is the same as <code>x</code>,
-while <code>-x</code> is the negation of <code>x</code>.
-The result of a floating-point or complex division by zero is not specified beyond the
-IEEE-754 standard; whether a <a href="#Run_time_panics">run-time panic</a>
-occurs is implementation-specific.
-</p>
 
-<h3 id="Integer_overflow">Integer overflow</h3>
+<h4 id="Integer_overflow">Integer overflow</h4>
 
 <p>
 For unsigned integer values, the operations <code>+</code>,
@@ -3533,6 +3506,35 @@ not occur. For instance, it may not assume that <code>x < x + 1</code> is alw
 </p>
 
 
+<h4 id="Floating_point_operators">Floating-point operators</h4>
+
+<p>
+For floating-point and complex numbers,
+<code>+x</code> is the same as <code>x</code>,
+while <code>-x</code> is the negation of <code>x</code>.
+The result of a floating-point or complex division by zero is not specified beyond the
+IEEE-754 standard; whether a <a href="#Run_time_panics">run-time panic</a>
+occurs is implementation-specific.
+</p>
+
+
+<h4 id="String_concatenation">String concatenation</h4>
+
+<p>
+Strings can be concatenated using the <code>+</code> operator
+or the <code>+=</code> assignment operator:
+</p>
+
+<pre>
+s := "hi" + string(c)
+s += " and good bye"
+</pre>
+
+<p>
+String addition creates a new string by concatenating the operands.
+</p>
+
+
 <h3 id="Comparison_operators">Comparison operators</h3>
 
 <p>
@@ -4095,7 +4097,7 @@ the implementation restriction in the section
 on <a href="#Constants">constants</a>.  This rounding may cause a
 floating-point constant expression to be invalid in an integer
 context, even if it would be integral when calculated using infinite
-precision.
+precision, and vice versa.
 </p>
 
 
@@ -4400,7 +4402,7 @@ a[i] = 23
 An <i>assignment operation</i> <code>x</code> <i>op</i><code>=</code>
 <code>y</code> where <i>op</i> is a binary arithmetic operation is equivalent
 to <code>x</code> <code>=</code> <code>x</code> <i>op</i>
-<code>y</code> but evaluates <code>x</code>
+<code>(y)</code> but evaluates <code>x</code>
 only once.  The <i>op</i><code>=</code> construct is a single token.
 In assignment operations, both the left- and right-hand expression lists
 must contain exactly one single-valued expression, and the left-hand
@@ -4562,6 +4564,7 @@ In an expression switch, the cases contain expressions that are compared
 against the value of the switch expression.
 In a type switch, the cases contain types that are compared against the
 type of a specially annotated switch expression.
+The switch expression is evaluated exactly once in a switch statement.
 </p>
 
 <h4 id="Expression_switches">Expression switches</h4>
@@ -4589,6 +4592,27 @@ ExprSwitchCase = "case" ExpressionList | "default" .
 </pre>
 
 <p>
+If the switch expression evaluates to an untyped constant, it is first
+<a href="#Conversions">converted</a> to its <a href="#Constants">default type</a>;
+if it is an untyped boolean value, it is first converted to type <code>bool</code>.
+The predeclared untyped value <code>nil</code> cannot be used as a switch expression.
+</p>
+
+<p>
+If a case expression is untyped, it is first <a href="#Conversions">converted</a>
+to the type of the switch expression.
+For each (possibly converted) case expression <code>x</code> and the value <code>t</code>
+of the switch expression, <code>x == t</code> must be a valid <a href="#Comparison_operators">comparison</a>.
+</p>
+
+<p>
+In other words, the switch expression is treated as if it were used to declare and
+initialize a temporary variable <code>t</code> without explicit type; it is that
+value of <code>t</code> against which each case expression <code>x</code> is tested
+for equality.
+</p>
+
+<p>
 In a case or default clause, the last non-empty statement
 may be a (possibly <a href="#Labeled_statements">labeled</a>)
 <a href="#Fallthrough_statements">"fallthrough" statement</a> to
@@ -4600,7 +4624,7 @@ but the last clause of an expression switch.
 </p>
 
 <p>
-The expression may be preceded by a simple statement, which
+The switch expression may be preceded by a simple statement, which
 executes before the expression is evaluated.
 </p>
 
@@ -4623,6 +4647,13 @@ case x == 4: f3()
 }
 </pre>
 
+<p>
+Implementation restriction: A compiler may disallow multiple case
+expressions evaluating to the same constant.
+For instance, the current compilers disallow duplicate integer,
+floating point, or string constants in case expressions.
+</p>
+
 <h4 id="Type_switches">Type switches</h4>
 
 <p>
@@ -5455,7 +5486,7 @@ const (
 	c2 = len([10]float64{2})         // [10]float64{2} contains no function calls
 	c3 = len([10]float64{c1})        // [10]float64{c1} contains no function calls
 	c4 = len([10]float64{imag(2i)})  // imag(2i) is a constant and no function call is issued
-	c5 = len([10]float64{imag(z)})   // invalid: imag(x) is a (non-constant) function call
+	c5 = len([10]float64{imag(z)})   // invalid: imag(z) is a (non-constant) function call
 )
 var z complex128
 </pre>
@@ -5579,7 +5610,7 @@ s3 := append(s2, s0...)            // append a slice              s3 == []int{0,
 s4 := append(s3[3:6], s3[2:]...)   // append overlapping slice    s4 == []int{3, 5, 7, 2, 3, 5, 7, 0, 0}
 
 var t []interface{}
-t = append(t, 42, 3.1415, "foo")                                  t == []interface{}{42, 3.1415, "foo"}
+t = append(t, 42, 3.1415, "foo")   //                             t == []interface{}{42, 3.1415, "foo"}
 
 var b []byte
 b = append(b, "bar"...)            // append string contents      b == []byte{'b', 'a', 'r' }
@@ -5657,11 +5688,28 @@ The type of the arguments and return value correspond.
 For <code>complex</code>, the two arguments must be of the same
 floating-point type and the return type is the complex type
 with the corresponding floating-point constituents:
-<code>complex64</code> for <code>float32</code>,
-<code>complex128</code> for <code>float64</code>.
-The <code>real</code> and <code>imag</code> functions
-together form the inverse, so for a complex value <code>z</code>,
-<code>z</code> <code>==</code> <code>complex(real(z),</code> <code>imag(z))</code>.
+<code>complex64</code> for <code>float32</code> arguments, and
+<code>complex128</code> for <code>float64</code> arguments.
+If one of the arguments evaluates to an untyped constant, it is first
+<a href="#Conversions">converted</a> to the type of the other argument.
+If both arguments evaluate to untyped constants, they must be non-complex
+numbers or their imaginary parts must be zero, and the return value of
+the function is an untyped complex constant.
+</p>
+
+<p>
+For <code>real</code> and <code>imag</code>, the argument must be
+of complex type, and the return type is the corresponding floating-point
+type: <code>float32</code> for a <code>complex64</code> argument, and
+<code>float64</code> for a <code>complex128</code> argument.
+If the argument evaluates to an untyped constant, it must be a number,
+and the return value of the function is an untyped floating-point constant.
+</p>
+
+<p>
+The <code>real</code> and <code>imag</code> functions together form the inverse of
+<code>complex</code>, so for a value <code>z</code> of a complex type <code>Z</code>,
+<code>z == Z(complex(real(z), imag(z)))</code>.
 </p>
 
 <p>
@@ -5671,11 +5719,15 @@ value is a constant.
 
 <pre>
 var a = complex(2, -2)             // complex128
-var b = complex(1.0, -1.4)         // complex128
+const b = complex(1.0, -1.4)       // untyped complex constant 1 - 1.4i
 x := float32(math.Cos(math.Pi/2))  // float32
 var c64 = complex(5, -x)           // complex64
-var im = imag(b)                   // float64
+const s uint = complex(1, 0)       // untyped complex constant 1 + 0i can be converted to uint
+_ = complex(1, 2<<s)               // illegal: 2 has floating-point type, cannot shift
 var rl = real(c64)                 // float32
+var im = imag(a)                   // float64
+const c = imag(b)                  // untyped constant -1.4
+_ = imag(3 << s)                   // illegal: 3 has complex type, cannot shift
 </pre>
 
 <h3 id="Handling_panics">Handling panics</h3>
diff --git a/doc/gopher/README b/doc/gopher/README
index 936a24c..d4ca8a1 100644
--- a/doc/gopher/README
+++ b/doc/gopher/README
@@ -1,3 +1,3 @@
 The Go gopher was designed by Renee French. (http://reneefrench.blogspot.com/)
 The design is licensed under the Creative Commons 3.0 Attributions license.
-Read this article for more details: http://blog.golang.org/gopher
+Read this article for more details: https://blog.golang.org/gopher
diff --git a/doc/install-source.html b/doc/install-source.html
index 7daf360..e71fff7 100644
--- a/doc/install-source.html
+++ b/doc/install-source.html
@@ -26,21 +26,21 @@ packages, though, read on.
 <p>
 There are two official Go compiler tool chains.
 This document focuses on the <code>gc</code> Go
-compiler and tools (<code>6g</code>, <code>8g</code> etc.).
+compiler and tools.
 For information on how to work on <code>gccgo</code>, a more traditional
 compiler using the GCC back end, see
 <a href="/doc/install/gccgo">Setting up and using gccgo</a>.
 </p>
 
 <p>
-The Go compilers support three instruction sets.
+The Go compilers support five instruction sets.
 There are important differences in the quality of the compilers for the different
 architectures.
 </p>
 
 <dl>
 <dt>
-	<code>amd64</code> (a.k.a. <code>x86-64</code>); <code>6g,6l,6c,6a</code>
+	<code>amd64</code> (also known as <code>x86-64</code>)
 </dt>
 <dd>
 	A mature implementation. The compiler has an effective
@@ -48,16 +48,28 @@ architectures.
 	<code>gccgo</code> can do noticeably better sometimes).
 </dd>
 <dt>
-	<code>386</code> (a.k.a. <code>x86</code> or <code>x86-32</code>); <code>8g,8l,8c,8a</code>
+	<code>386</code> (<code>x86</code> or <code>x86-32</code>)
 </dt>
 <dd>
 	Comparable to the <code>amd64</code> port.
 </dd>
 <dt>
-	<code>arm</code> (a.k.a. <code>ARM</code>); <code>5g,5l,5c,5a</code>
+	<code>arm</code> (<code>ARM</code>)
 </dt>
 <dd>
-	Supports Linux, FreeBSD and NetBSD binaries. Less widely used than the other ports.
+	Supports Linux, FreeBSD, NetBSD and Darwin binaries. Less widely used than the other ports.
+</dd>
+<dt>
+	<code>arm64</code> (<code>AArch64</code>)
+</dt>
+<dd>
+	Supports Linux and Darwin binaries. New in 1.5 and not as well excercised as other ports.
+</dd>
+<dt>
+	<code>ppc64, ppc64le</code> (64-bit PowerPC big- and little-endian)
+</dt>
+<dd>
+	Supports Linux binaries. New in 1.5 and not as well excercised as other ports.
 </dd>
 </dl>
 
@@ -77,14 +89,60 @@ The full set of supported combinations is listed in the discussion of
 
 </div>
 
-<h2 id="ctools">Install C tools, if needed</h2>
+<h2 id="go14">Install Go compiler binaries</h2>
+
+<p>
+The Go tool chain is written in Go. To build it, you need a Go compiler installed.
+The scripts that do the initial build of the tools look for an existing Go tool
+chain in <code>$HOME/go1.4</code>.
+(This path may be overridden by setting the <code>GOROOT_BOOTSTRAP</code>
+environment variable.)
+</p>
+
+<p>
+Build the tools with Go version 1.4 or a point release (1.4.1, 1.4.2 etc.).
+Go 1.4 binaries can be found at <a href="/dl/">the downloads page</a>.
+</p>
+
+<p>
+Download the zip or tarball of Go 1.4 for your platform and extract it to
+<code>$HOME/go1.4</code> (or your nominated <code>GOROOT_BOOTSTRAP</code>
+location).
+</p>
 
 <p>
-The Go tool chain is written in C. To build it, you need a C compiler installed. 
-Please refer to the <a href="//golang.org/wiki/InstallFromSource#install-c-tools">InstallFromSource</a>
-page on the Go community Wiki for operating system specific instructions.
+If you want to install Go 1.5 on a system that is not supported by Go 1.4 (such
+as <code>linux/ppc64</code>) you can either use
+<a href="/src/bootstrap.bash">bootstrap.bash</a> on a system that can bootstrap Go
+1.5 normally, or bootstrap with gccgo 5.
 </p>
 
+<p>
+When run as (for example)
+</p>
+
+<pre>
+$ GOOS=linux GOARCH=ppc64 ./bootstrap.bash
+</pre>
+
+<p>
+<code>bootstrap.bash</code> cross-compiles a toolchain for that <code>GOOS/GOARCH</code>
+combination, leaving the resulting tree in <code>../../go-${GOOS}-${GOARCH}-bootstrap</code>.
+That tree can be copied to a machine of the given target type
+and used as <code>GOROOT_BOOTSTRAP</code> to bootstrap a local build.
+</p>
+
+<p>
+To use gccgo, you need to arrange for <code>$GOROOT_BOOSTRAP/bin/go</code> to be
+the go tool that comes as part of gccgo 5. For example on Ubuntu Vivid:
+</p>
+
+<pre>
+$ sudo apt-get install gccgo-5
+$ sudo update-alternatives --set go /usr/bin/go-5
+$ GOROOT_BOOTSTRAP=/usr ./make.bash
+</pre>
+
 <h2 id="git">Install Git, if needed</h2>
 
 <p>
@@ -109,7 +167,7 @@ Then clone the repository and check out the latest release tag:</p>
 <pre>
 $ git clone https://go.googlesource.com/go
 $ cd go
-$ git checkout go1.4.1
+$ git checkout go1.5
 </pre>
 
 <h2 id="head">(Optional) Switch to the master branch</h2>
@@ -131,7 +189,7 @@ To build the Go distribution, run
 </p>
 
 <pre>
-$ cd go/src
+$ cd src
 $ ./all.bash
 </pre>
 
@@ -288,7 +346,7 @@ New releases are announced on the
 <a href="//groups.google.com/group/golang-announce">golang-announce</a>
 mailing list.
 Each announcement mentions the latest release tag, for instance,
-<code>go1.4</code>.
+<code>go1.5</code>.
 </p>
 
 <p>
@@ -341,12 +399,13 @@ These default to the values of <code>$GOHOSTOS</code> and
 
 <p>
 Choices for <code>$GOOS</code> are
-<code>darwin</code> (Mac OS X 10.6 and above), <code>dragonfly</code>, <code>freebsd</code>,
-<code>linux</code>, <code>netbsd</code>, <code>openbsd</code>, 
+<code>darwin</code> (Mac OS X 10.7 and above and iOS), <code>dragonfly</code>, <code>freebsd</code>,
+<code>linux</code>, <code>netbsd</code>, <code>openbsd</code>,
 <code>plan9</code>, <code>solaris</code> and <code>windows</code>.
 Choices for <code>$GOARCH</code> are
 <code>amd64</code> (64-bit x86, the most mature port),
-<code>386</code> (32-bit x86), and <code>arm</code> (32-bit ARM).
+<code>386</code> (32-bit x86), <code>arm</code> (32-bit ARM), <code>arm64</code> (64-bit ARM),
+<code>ppc64le</code> (PowerPC 64-bit, little-endian), and <code>ppc64</code> (PowerPC 64-bit, big-endian).
 The valid combinations of <code>$GOOS</code> and <code>$GOARCH</code> are:
 <table cellpadding="0">
 <tr>
@@ -359,7 +418,10 @@ The valid combinations of <code>$GOOS</code> and <code>$GOARCH</code> are:
 <td></td><td><code>darwin</code></td> <td><code>amd64</code></td>
 </tr>
 <tr>
-<td></td><td><code>dragonfly</code></td> <td><code>386</code></td>
+<td></td><td><code>darwin</code></td> <td><code>arm</code></td>
+</tr>
+<tr>
+<td></td><td><code>darwin</code></td> <td><code>arm64</code></td>
 </tr>
 <tr>
 <td></td><td><code>dragonfly</code></td> <td><code>amd64</code></td>
@@ -383,6 +445,15 @@ The valid combinations of <code>$GOOS</code> and <code>$GOARCH</code> are:
 <td></td><td><code>linux</code></td> <td><code>arm</code></td>
 </tr>
 <tr>
+<td></td><td><code>linux</code></td> <td><code>arm64</code></td>
+</tr>
+<tr>
+<td></td><td><code>linux</code></td> <td><code>ppc64</code></td>
+</tr>
+<tr>
+<td></td><td><code>linux</code></td> <td><code>ppc64le</code></td>
+</tr>
+<tr>
 <td></td><td><code>netbsd</code></td> <td><code>386</code></td>
 </tr>
 <tr>
@@ -398,6 +469,9 @@ The valid combinations of <code>$GOOS</code> and <code>$GOARCH</code> are:
 <td></td><td><code>openbsd</code></td> <td><code>amd64</code></td>
 </tr>
 <tr>
+<td></td><td><code>openbsd</code></td> <td><code>arm</code></td>
+</tr>
+<tr>
 <td></td><td><code>plan9</code></td> <td><code>386</code></td>
 </tr>
 <tr>
@@ -413,6 +487,7 @@ The valid combinations of <code>$GOOS</code> and <code>$GOARCH</code> are:
 <td></td><td><code>windows</code></td> <td><code>amd64</code></td>
 </tr>
 </table>
+<br>
 
 <li><code>$GOHOSTOS</code> and <code>$GOHOSTARCH</code>
 <p>
@@ -442,7 +517,7 @@ installs all commands there.
 <li><code>$GO386</code> (for <code>386</code> only, default is auto-detected
 if built on either <code>386</code> or <code>amd64</code>, <code>387</code> otherwise)
 <p>
-This controls the code generated by 8g to use either the 387 floating-point unit
+This controls the code generated by gc to use either the 387 floating-point unit
 (set to <code>387</code>) or SSE2 instructions (set to <code>sse2</code>) for
 floating point computations.
 </p>
diff --git a/doc/install.html b/doc/install.html
index 9561fdd..e9f0f0d 100644
--- a/doc/install.html
+++ b/doc/install.html
@@ -3,10 +3,12 @@
 	"Path":  "/doc/install"
 }-->
 
+<div class="hideFromDownload">
+
 <h2 id="download">Download the Go distribution</h2>
 
 <p>
-<a href="https://golang.org/dl/" id="start" class="download" target="_blank">
+<a href="https://golang.org/dl/" id="start" class="download">
 <span class="big">Download Go</span>
 <span class="desc">Click here to visit the downloads page</span>
 </a>
@@ -14,9 +16,10 @@
 
 <p>
 <a href="https://golang.org/dl/" target="_blank">Official binary
-distributions</a> are available for the FreeBSD (release 8 and above), Linux, Mac OS X (Snow Leopard
-and above), and Windows operating systems and the 32-bit (<code>386</code>) and
-64-bit (<code>amd64</code>) x86 processor architectures.
+distributions</a> are available for the FreeBSD (release 8-STABLE and above),
+Linux, Mac OS X (10.7 and above), and Windows operating systems and
+the 32-bit (<code>386</code>) and 64-bit (<code>amd64</code>) x86 processor
+architectures.
 </p>
 
 <p>
@@ -30,11 +33,11 @@ system and architecture, try
 <h2 id="requirements">System requirements</h2>
 
 <p>
-The <code>gc</code> compiler supports the following operating systems and
-architectures. Please ensure your system meets these requirements before
-proceeding. If your OS or architecture is not on the list, it's possible that
-<code>gccgo</code> might support your setup; see
-<a href="/doc/install/gccgo">Setting up and using gccgo</a> for details.
+Go binary distributions are available for these supported operating systems and architectures.
+Please ensure your system meets these requirements before proceeding.
+If your OS or architecture is not on the list, you may be able to
+<a href="/doc/install/source">install from source</a> or
+<a href="/doc/install/gccgo">use gccgo instead</a>.
 </p>
 
 <table class="codetable" frame="border" summary="requirements">
@@ -44,9 +47,9 @@ proceeding. If your OS or architecture is not on the list, it's possible that
 <th align="center">Notes</th>
 </tr>
 <tr><td colspan="3"><hr></td></tr>
-<tr><td>FreeBSD 8 or later</td> <td>amd64, 386, arm</td> <td>Debian GNU/kFreeBSD not supported; FreeBSD/ARM needs FreeBSD 10 or later</td></tr>
-<tr><td>Linux 2.6.23 or later with glibc</td> <td>amd64, 386, arm</td> <td>CentOS/RHEL 5.x not supported; no binary distribution for ARM yet</td></tr>
-<tr><td>Mac OS X 10.6 or later</td> <td>amd64, 386</td> <td>use the gcc<sup>†</sup> that comes with Xcode<sup>‡</sup></td></tr>
+<tr><td>FreeBSD 8-STABLE or later</td> <td>amd64</td> <td>Debian GNU/kFreeBSD not supported</td></tr>
+<tr><td>Linux 2.6.23 or later with glibc</td> <td>amd64, 386, arm</td> <td>CentOS/RHEL 5.x not supported; install from source for ARM</td></tr>
+<tr><td>Mac OS X 10.7 or later</td> <td>amd64</td> <td>use the clang or gcc<sup>†</sup> that comes with Xcode<sup>‡</sup></td></tr>
 <tr><td>Windows XP or later</td> <td>amd64, 386</td> <td>use MinGW gcc<sup>†</sup>. No need for cygwin or msys.</td></tr>
 </table>
 
@@ -59,6 +62,8 @@ installed Xcode 4.3+, you can install it from the Components tab of the
 Downloads preferences panel.
 </p>
 
+</div><!-- hideFromDownload -->
+
 
 <h2 id="install">Install the Go tools</h2>
 
@@ -67,6 +72,8 @@ If you are upgrading from an older version of Go you must
 first <a href="#uninstall">remove the existing version</a>.
 </p>
 
+<div id="tarballInstructions">
+
 <h3 id="tarball">Linux, Mac OS X, and FreeBSD tarballs</h3>
 
 <p>
@@ -76,10 +83,10 @@ and extract it into <code>/usr/local</code>, creating a Go tree in
 </p>
 
 <pre>
-tar -C /usr/local -xzf go$VERSION.$OS-$ARCH.tar.gz
+tar -C /usr/local -xzf <span class="downloadFilename">go$VERSION.$OS-$ARCH.tar.gz</span>
 </pre>
 
-<p>
+<p class="hideFromDownload">
 Choose the archive file appropriate for your installation.
 For instance, if you are installing Go version 1.2.1 for 64-bit x86 on Linux,
 the archive you want is called <code>go1.2.1.linux-amd64.tar.gz</code>.
@@ -124,6 +131,10 @@ export PATH=$PATH:$GOROOT/bin
 location.
 </p>
 
+</div><!-- tarballInstructions -->
+
+<div id="darwinPackageInstructions">
+
 <h3 id="osx">Mac OS X package installer</h3>
 
 <p>
@@ -138,15 +149,21 @@ The package should put the <code>/usr/local/go/bin</code> directory in your
 Terminal sessions for the change to take effect.
 </p>
 
+</div><!-- darwinPackageInstructions -->
+
+<div id="windowsInstructions">
+
 <h3 id="windows">Windows</h3>
 
-<p>
+<p class="hideFromDownload">
 The Go project provides two installation options for Windows users
 (besides <a href="/doc/install/source">installing from source</a>):
 a zip archive that requires you to set some environment variables and an
 MSI installer that configures your installation automatically.
 </p>
 
+<div id="windowsInstallerInstructions">
+
 <h4 id="windows_msi">MSI installer</h4>
 
 <p>
@@ -161,6 +178,10 @@ The installer should put the <code>c:\Go\bin</code> directory in your
 command prompts for the change to take effect.
 </p>
 
+</div><!-- windowsInstallerInstructions -->
+
+<div id="windowsZipInstructions">
+
 <h4 id="windows_zip">Zip archive</h4>
 
 <p>
@@ -176,6 +197,8 @@ you must set the <code>GOROOT</code> environment variable to your chosen path.
 Add the <code>bin</code> subdirectory of your Go root (for example, <code>c:\Go\bin</code>) to your <code>PATH</code> environment variable.
 </p>
 
+</div><!-- windowsZipInstructions -->
+
 <h4 id="windows_env">Setting environment variables under Windows</h4>
 
 <p>
@@ -185,15 +208,38 @@ versions of Windows provide this control panel through the "Advanced System
 Settings" option inside the "System" control panel.
 </p>
 
+</div><!-- windowsInstructions -->
+
 
 <h2 id="testing">Test your installation</h2>
 
 <p>
-Check that Go is installed correctly by building a simple program, as follows.
+Check that Go is installed correctly by setting up a workspace
+and building a simple program, as follows.
+</p>
+
+<p>
+Create a directory to contain your <a href="code.html#Workspaces">workspace</a>,
+<code>$HOME/work</code> for example, and set the <code>GOPATH</code> environment
+variable to point to that location.
+</p>
+
+<pre>
+$ <b>export GOPATH=$HOME/work</b>
+</pre>
+
+<p>
+You should put the above command in your shell startup script
+(<code>$HOME/.profile</code> for example) or, if you use Windows,
+follow the <a href="#windows_env">instructions above</a> to set the
+<code>GOPATH</code> environment variable on your system.
 </p>
 
 <p>
-Create a file named <code>hello.go</code> and put the following program in it:
+Next, make the directories <code>src/github.com/user/hello</code> inside your
+workspace (if you use GitHub, substitute your user name for <code>user</code>),
+and inside the <code>hello</code> directory create a file named <code>hello.go</code>
+with the following contents:
 </p>
 
 <pre>
@@ -207,29 +253,32 @@ func main() {
 </pre>
 
 <p>
-Then run it with the <code>go</code> tool:
+Then compile it with the <code>go</code> tool:
 </p>
 
 <pre>
-$ go run hello.go
-hello, world
+$ <b>go install github.com/user/hello</b>
 </pre>
 
 <p>
-If you see the "hello, world" message then your Go installation is working.
+The above command will put an executable command named <code>hello</code> 
+(or <code>hello.exe</code>) inside the <code>bin</code> directory of your workspace.
+Execute the command to see the greeting:
 </p>
 
-
-<h2 id="gopath">Set up your work environment</h2>
+<pre>
+$ <b>$GOPATH/bin/hello</b>
+hello, world
+</pre>
 
 <p>
-You're almost done.
-You just need to set up your environment.
+If you see the "hello, world" message then your Go installation is working.
 </p>
 
 <p>
-Read the <a href="/doc/code.html">How to Write Go Code</a> document,
-which provides <b>essential setup instructions</b> for using the Go tools.
+Before rushing off to write Go code please read the
+<a href="/doc/code.html">How to Write Go Code</a> document,
+which describes some essential concepts about using the Go tools.
 </p>
 
 
diff --git a/doc/logo-153x55.png b/doc/logo-153x55.png
deleted file mode 100644
index 8ec22aa..0000000
Binary files a/doc/logo-153x55.png and /dev/null differ
diff --git a/doc/play/peano.go b/doc/play/peano.go
index c1ee5ad..214fe1b 100644
--- a/doc/play/peano.go
+++ b/doc/play/peano.go
@@ -3,9 +3,9 @@
 // (the nodes are the data).
 // http://en.wikipedia.org/wiki/Peano_axioms
 
-// This program demonstrates the power of Go's
-// segmented stacks when doing massively
-// recursive computations.
+// This program demonstrates that Go's automatic
+// stack management can handle heavily recursive
+// computations.
 
 package main
 
diff --git a/doc/progs/cgo1.go b/doc/progs/cgo1.go
index 805fe3c..d559e13 100644
--- a/doc/progs/cgo1.go
+++ b/doc/progs/cgo1.go
@@ -1,8 +1,7 @@
-// skip
-
 // 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.
+
 package rand
 
 /*
diff --git a/doc/progs/cgo2.go b/doc/progs/cgo2.go
index b9e9f7d..da07aa4 100644
--- a/doc/progs/cgo2.go
+++ b/doc/progs/cgo2.go
@@ -1,8 +1,7 @@
-// skip
-
 // 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.
+
 package rand2
 
 /*
diff --git a/doc/progs/cgo3.go b/doc/progs/cgo3.go
index c4f4791..d5cedf4 100644
--- a/doc/progs/cgo3.go
+++ b/doc/progs/cgo3.go
@@ -1,8 +1,7 @@
-// skip
-
 // 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.
+
 package print
 
 // #include <stdio.h>
diff --git a/doc/progs/cgo4.go b/doc/progs/cgo4.go
index 30b8935..dbb07e8 100644
--- a/doc/progs/cgo4.go
+++ b/doc/progs/cgo4.go
@@ -1,8 +1,7 @@
-// skip
-
 // 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.
+
 package print
 
 // #include <stdio.h>
diff --git a/doc/progs/defer.go b/doc/progs/defer.go
index 006a474..2e11020 100644
--- a/doc/progs/defer.go
+++ b/doc/progs/defer.go
@@ -1,5 +1,3 @@
-// cmpout
-
 // 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.
diff --git a/doc/progs/defer.out b/doc/progs/defer.out
deleted file mode 100644
index 0cdf53a..0000000
--- a/doc/progs/defer.out
+++ /dev/null
@@ -1,3 +0,0 @@
-0
-3210
-2
diff --git a/doc/progs/defer2.go b/doc/progs/defer2.go
index ff7eaf9..cad66b0 100644
--- a/doc/progs/defer2.go
+++ b/doc/progs/defer2.go
@@ -1,5 +1,3 @@
-// cmpout
-
 // 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.
diff --git a/doc/progs/defer2.out b/doc/progs/defer2.out
deleted file mode 100644
index 6110685..0000000
--- a/doc/progs/defer2.out
+++ /dev/null
@@ -1,12 +0,0 @@
-Calling g.
-Printing in g 0
-Printing in g 1
-Printing in g 2
-Printing in g 3
-Panicking!
-Defer in g 3
-Defer in g 2
-Defer in g 1
-Defer in g 0
-Recovered in f 4
-Returned normally from f.
diff --git a/doc/progs/eff_bytesize.go b/doc/progs/eff_bytesize.go
index a0c3d50..b459611 100644
--- a/doc/progs/eff_bytesize.go
+++ b/doc/progs/eff_bytesize.go
@@ -1,5 +1,3 @@
-// cmpout
-
 // 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.
diff --git a/doc/progs/eff_bytesize.out b/doc/progs/eff_bytesize.out
deleted file mode 100644
index df763f3..0000000
--- a/doc/progs/eff_bytesize.out
+++ /dev/null
@@ -1 +0,0 @@
-1.00YB 9.09TB
diff --git a/doc/progs/eff_qr.go b/doc/progs/eff_qr.go
index 861131d..89de459 100644
--- a/doc/progs/eff_qr.go
+++ b/doc/progs/eff_qr.go
@@ -1,5 +1,3 @@
-// compile
-
 // 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.
diff --git a/doc/progs/eff_sequence.go b/doc/progs/eff_sequence.go
index c9b18ba..11c885a 100644
--- a/doc/progs/eff_sequence.go
+++ b/doc/progs/eff_sequence.go
@@ -1,5 +1,3 @@
-// cmpout
-
 // 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.
diff --git a/doc/progs/eff_sequence.out b/doc/progs/eff_sequence.out
deleted file mode 100644
index fd01a7d..0000000
--- a/doc/progs/eff_sequence.out
+++ /dev/null
@@ -1 +0,0 @@
-[-1 2 6 16 44]
diff --git a/doc/progs/eff_unused1.go b/doc/progs/eff_unused1.go
index f990a19..285d55e 100644
--- a/doc/progs/eff_unused1.go
+++ b/doc/progs/eff_unused1.go
@@ -1,5 +1,3 @@
-// skip
-
 package main
 
 import (
diff --git a/doc/progs/eff_unused2.go b/doc/progs/eff_unused2.go
index 3e6e041..92eb74e 100644
--- a/doc/progs/eff_unused2.go
+++ b/doc/progs/eff_unused2.go
@@ -1,5 +1,3 @@
-// compile
-
 package main
 
 import (
diff --git a/doc/progs/error.go b/doc/progs/error.go
index 57854c5..e776cdb 100644
--- a/doc/progs/error.go
+++ b/doc/progs/error.go
@@ -1,5 +1,3 @@
-// compile
-
 // 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.
diff --git a/doc/progs/error2.go b/doc/progs/error2.go
index aad1dc8..2b0e0c3 100644
--- a/doc/progs/error2.go
+++ b/doc/progs/error2.go
@@ -1,5 +1,3 @@
-// compile
-
 // 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.
diff --git a/doc/progs/error3.go b/doc/progs/error3.go
index 9f1b300..e4e57e0 100644
--- a/doc/progs/error3.go
+++ b/doc/progs/error3.go
@@ -1,5 +1,3 @@
-// compile
-
 // 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.
diff --git a/doc/progs/error4.go b/doc/progs/error4.go
index d40fc6e..8b2f304 100644
--- a/doc/progs/error4.go
+++ b/doc/progs/error4.go
@@ -1,5 +1,3 @@
-// compile
-
 // 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.
diff --git a/doc/progs/go1.go b/doc/progs/go1.go
index a4dc64d..50fd934 100644
--- a/doc/progs/go1.go
+++ b/doc/progs/go1.go
@@ -1,6 +1,3 @@
-// compile
-// this file will output a list of filenames in cwd, not suitable for cmpout
-
 // 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.
diff --git a/doc/progs/gobs1.go b/doc/progs/gobs1.go
index d95f765..7077ca1 100644
--- a/doc/progs/gobs1.go
+++ b/doc/progs/gobs1.go
@@ -1,5 +1,3 @@
-// compile
-
 // 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.
diff --git a/doc/progs/gobs2.go b/doc/progs/gobs2.go
index acd1838..85bb41c 100644
--- a/doc/progs/gobs2.go
+++ b/doc/progs/gobs2.go
@@ -1,5 +1,3 @@
-// compile
-
 // 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.
diff --git a/doc/progs/image_draw.go b/doc/progs/image_draw.go
index 0a1f7ac..bb73c8a 100644
--- a/doc/progs/image_draw.go
+++ b/doc/progs/image_draw.go
@@ -1,5 +1,3 @@
-// compile
-
 // 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.
diff --git a/doc/progs/image_package1.go b/doc/progs/image_package1.go
index d331834..c4c401e 100644
--- a/doc/progs/image_package1.go
+++ b/doc/progs/image_package1.go
@@ -1,5 +1,3 @@
-// cmpout
-
 // 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.
diff --git a/doc/progs/image_package1.out b/doc/progs/image_package1.out
deleted file mode 100644
index 809b31b..0000000
--- a/doc/progs/image_package1.out
+++ /dev/null
@@ -1 +0,0 @@
-X is 2 Y is 1
diff --git a/doc/progs/image_package2.go b/doc/progs/image_package2.go
index e5b78b4..fcb5d9f 100644
--- a/doc/progs/image_package2.go
+++ b/doc/progs/image_package2.go
@@ -1,5 +1,3 @@
-// cmpout
-
 // 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.
diff --git a/doc/progs/image_package2.out b/doc/progs/image_package2.out
deleted file mode 100644
index 616d307..0000000
--- a/doc/progs/image_package2.out
+++ /dev/null
@@ -1 +0,0 @@
-3 4 false
diff --git a/doc/progs/image_package3.go b/doc/progs/image_package3.go
index 95d72a0..13d0f08 100644
--- a/doc/progs/image_package3.go
+++ b/doc/progs/image_package3.go
@@ -1,5 +1,3 @@
-// cmpout
-
 // 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.
diff --git a/doc/progs/image_package3.out b/doc/progs/image_package3.out
deleted file mode 100644
index 3fe35de..0000000
--- a/doc/progs/image_package3.out
+++ /dev/null
@@ -1 +0,0 @@
-3 4 true
diff --git a/doc/progs/image_package4.go b/doc/progs/image_package4.go
index ec0e461..c46fddf 100644
--- a/doc/progs/image_package4.go
+++ b/doc/progs/image_package4.go
@@ -1,5 +1,3 @@
-// cmpout
-
 // 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.
diff --git a/doc/progs/image_package4.out b/doc/progs/image_package4.out
deleted file mode 100644
index cb1b777..0000000
--- a/doc/progs/image_package4.out
+++ /dev/null
@@ -1 +0,0 @@
-image.Point{X:2, Y:1}
diff --git a/doc/progs/image_package5.go b/doc/progs/image_package5.go
index b9e27d6..0bb5c76 100644
--- a/doc/progs/image_package5.go
+++ b/doc/progs/image_package5.go
@@ -1,5 +1,3 @@
-// cmpout
-
 // 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.
diff --git a/doc/progs/image_package5.out b/doc/progs/image_package5.out
deleted file mode 100644
index 2da80c1..0000000
--- a/doc/progs/image_package5.out
+++ /dev/null
@@ -1 +0,0 @@
-{255 0 0 255}
diff --git a/doc/progs/image_package6.go b/doc/progs/image_package6.go
index 5e6eefa..62eeecd 100644
--- a/doc/progs/image_package6.go
+++ b/doc/progs/image_package6.go
@@ -1,5 +1,3 @@
-// cmpout
-
 // 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.
diff --git a/doc/progs/image_package6.out b/doc/progs/image_package6.out
deleted file mode 100644
index fcd13c0..0000000
--- a/doc/progs/image_package6.out
+++ /dev/null
@@ -1,2 +0,0 @@
-8 4
-true
diff --git a/doc/progs/interface.go b/doc/progs/interface.go
index 6972b72..c2925d5 100644
--- a/doc/progs/interface.go
+++ b/doc/progs/interface.go
@@ -1,5 +1,3 @@
-// compile
-
 // 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.
diff --git a/doc/progs/interface2.go b/doc/progs/interface2.go
index 85e7d51..a541d94 100644
--- a/doc/progs/interface2.go
+++ b/doc/progs/interface2.go
@@ -1,5 +1,3 @@
-// cmpout
-
 // 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.
diff --git a/doc/progs/interface2.out b/doc/progs/interface2.out
deleted file mode 100644
index 085bd01..0000000
--- a/doc/progs/interface2.out
+++ /dev/null
@@ -1 +0,0 @@
-type: float64
diff --git a/doc/progs/json1.go b/doc/progs/json1.go
index 887d7d1..9e10f47 100644
--- a/doc/progs/json1.go
+++ b/doc/progs/json1.go
@@ -1,5 +1,3 @@
-// run
-
 // 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.
diff --git a/doc/progs/json2.go b/doc/progs/json2.go
index f358fea..6089ae6 100644
--- a/doc/progs/json2.go
+++ b/doc/progs/json2.go
@@ -1,5 +1,3 @@
-// cmpout
-
 // 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.
diff --git a/doc/progs/json2.out b/doc/progs/json2.out
deleted file mode 100644
index 8f2dea5..0000000
--- a/doc/progs/json2.out
+++ /dev/null
@@ -1,2 +0,0 @@
-the circle's area 24.227111172875365
-the reciprocal of i is 0.3601008282319049
diff --git a/doc/progs/json3.go b/doc/progs/json3.go
index 41eb373..a04fdfa 100644
--- a/doc/progs/json3.go
+++ b/doc/progs/json3.go
@@ -1,5 +1,3 @@
-// compile
-
 // 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.
diff --git a/doc/progs/json4.go b/doc/progs/json4.go
index ee38f31..4926302 100644
--- a/doc/progs/json4.go
+++ b/doc/progs/json4.go
@@ -1,5 +1,3 @@
-// run
-
 // 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.
diff --git a/doc/progs/json5.go b/doc/progs/json5.go
index 9ab972d..6d7a4ca 100644
--- a/doc/progs/json5.go
+++ b/doc/progs/json5.go
@@ -1,5 +1,3 @@
-// compile
-
 // 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.
diff --git a/doc/progs/run b/doc/progs/run
deleted file mode 100755
index 6e680b8..0000000
--- a/doc/progs/run
+++ /dev/null
@@ -1,125 +0,0 @@
-#!/usr/bin/env bash
-# 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.
-
-set -e
-
-goos=$(go env GOOS)
-
-defer_panic_recover="
-	defer
-	defer2
-"
-
-effective_go="
-	eff_bytesize
-	eff_qr
-	eff_sequence
-	eff_unused2
-"
-
-error_handling="
-	error
-	error2
-	error3
-	error4
-"
-
-law_of_reflection="
-	interface
-	interface2
-"
-
-c_go_cgo="
-	cgo1
-	cgo2
-	cgo3
-	cgo4
-"
-# cgo1 and cgo2 don't run on freebsd, srandom has a different signature
-if [ "$goos" == "freebsd" ]; then
-	c_go_cgo="cgo3 cgo4"
-fi
-# cgo1 and cgo2 don't run on netbsd, srandom has a different signature
-# cgo3 and cgo4 don't run on netbsd, since cgo cannot handle stdout correctly
-if [ "$goos" == "netbsd" ]; then
-	c_go_cgo=""
-fi
-# cgo3 and cgo4 don't run on openbsd, since cgo cannot handle stdout correctly
-if [ "$goos" == "openbsd" ]; then
-	c_go_cgo="cgo1 cgo2"
-fi
-if [ "$CGO_ENABLED" != 1 ]; then
-	c_go_cgo=""
-fi
-
-timeout="
-	timeout1
-	timeout2
-"
-
-gobs="
-	gobs1
-	gobs2
-"
-
-json="
-	json1
-	json2
-	json3
-	json4
-	json5
-"
-
-image_package="
-	image_package1
-	image_package2
-	image_package3
-	image_package4
-	image_package5
-	image_package6
-"
-
-all=$(echo $defer_panic_recover $effective_go $error_handling $law_of_reflection $c_go_cgo $timeout $gobs $json $image_package slices go1)
-
-for i in $all; do
-	go build $i.go
-done
-
-# Write to temporary file to avoid mingw bash bug.
-TMPFILE="${TMPDIR:-/tmp}/gotest3.$USER"
-
-function testit {
-	./$1 >"$TMPFILE" 2>&1 || true
-	x=$(echo $(cat "$TMPFILE")) # extra echo canonicalizes
-	if ! echo "$x" | grep "$2" > /dev/null
-	then
-		echo $1 failed: '"'$x'"' is not '"'$2'"'
-	fi
-}
-
-
-testit defer '^0 3210 2$'
-testit defer2 '^Calling g. Printing in g 0 Printing in g 1 Printing in g 2 Printing in g 3 Panicking! Defer in g 3 Defer in g 2 Defer in g 1 Defer in g 0 Recovered in f 4 Returned normally from f.$'
-
-testit eff_bytesize '^1.00YB 9.09TB$'
-testit eff_sequence '^\[-1 2 6 16 44\]$'
-
-testit go1 '^Christmas is a holiday: true Sleeping for 0.123s.*go1.go already exists$'
-
-testit interface2 "^type: float64$"
-
-testit json1 "^$"
-testit json2 "the reciprocal of i is"
-testit json3 "Age is int 6"
-testit json4 "^$"
-
-testit image_package1 "^X is 2 Y is 1$"
-testit image_package2 "^3 4 false$"
-testit image_package3 "^3 4 true$"
-testit image_package4 "^image.Point{X:2, Y:1}$"
-testit image_package5 "^{255 0 0 255}$"
-testit image_package6 "^8 4 true$"
-
-rm -f $all "$TMPFILE"
diff --git a/doc/progs/run.go b/doc/progs/run.go
new file mode 100755
index 0000000..8479a66
--- /dev/null
+++ b/doc/progs/run.go
@@ -0,0 +1,230 @@
+// 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.
+
+// run runs the docs tests found in this directory.
+package main
+
+import (
+	"bytes"
+	"flag"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"regexp"
+	"runtime"
+	"strings"
+)
+
+const usage = `go run run.go [tests]
+
+run.go runs the docs tests in this directory.
+If no tests are provided, it runs all tests.
+Tests may be specified without their .go suffix.
+`
+
+func main() {
+	flag.Usage = func() {
+		fmt.Fprintf(os.Stderr, usage)
+		flag.PrintDefaults()
+		os.Exit(2)
+	}
+
+	flag.Parse()
+	if flag.NArg() == 0 {
+		// run all tests
+		fixcgo()
+	} else {
+		// run specified tests
+		onlyTest(flag.Args()...)
+	}
+
+	tmpdir, err := ioutil.TempDir("", "go-progs")
+	if err != nil {
+		fmt.Fprintln(os.Stderr, err)
+		os.Exit(1)
+	}
+
+	// ratec limits the number of tests running concurrently.
+	// None of the tests are intensive, so don't bother
+	// trying to manually adjust for slow builders.
+	ratec := make(chan bool, runtime.NumCPU())
+	errc := make(chan error, len(tests))
+
+	for _, tt := range tests {
+		tt := tt
+		ratec <- true
+		go func() {
+			errc <- test(tmpdir, tt.file, tt.want)
+			<-ratec
+		}()
+	}
+
+	var rc int
+	for range tests {
+		if err := <-errc; err != nil {
+			fmt.Fprintln(os.Stderr, err)
+			rc = 1
+		}
+	}
+	os.Remove(tmpdir)
+	os.Exit(rc)
+}
+
+// test builds the test in the given file.
+// If want is non-empty, test also runs the test
+// and checks that the output matches the regexp want.
+func test(tmpdir, file, want string) error {
+	// Build the program.
+	prog := filepath.Join(tmpdir, file)
+	cmd := exec.Command("go", "build", "-o", prog, file+".go")
+	out, err := cmd.CombinedOutput()
+	if err != nil {
+		return fmt.Errorf("go build %s.go failed: %v\nOutput:\n%s", file, err, out)
+	}
+	defer os.Remove(prog)
+
+	// Only run the test if we have output to check.
+	if want == "" {
+		return nil
+	}
+
+	cmd = exec.Command(prog)
+	out, err = cmd.CombinedOutput()
+	if err != nil {
+		return fmt.Errorf("%s failed: %v\nOutput:\n%s", file, err, out)
+	}
+
+	// Canonicalize output.
+	out = bytes.TrimRight(out, "\n")
+	out = bytes.Replace(out, []byte{'\n'}, []byte{' '}, -1)
+
+	// Check the result.
+	match, err := regexp.Match(want, out)
+	if err != nil {
+		return fmt.Errorf("failed to parse regexp %q: %v", want, err)
+	}
+	if !match {
+		return fmt.Errorf("%s.go:\n%q\ndoes not match %s", file, out, want)
+	}
+
+	return nil
+}
+
+type testcase struct {
+	file string
+	want string
+}
+
+var tests = []testcase{
+	// defer_panic_recover
+	{"defer", `^0 3210 2$`},
+	{"defer2", `^Calling g. Printing in g 0 Printing in g 1 Printing in g 2 Printing in g 3 Panicking! Defer in g 3 Defer in g 2 Defer in g 1 Defer in g 0 Recovered in f 4 Returned normally from f.$`},
+
+	// effective_go
+	{"eff_bytesize", `^1.00YB 9.09TB$`},
+	{"eff_qr", ""},
+	{"eff_sequence", `^\[-1 2 6 16 44\]$`},
+	{"eff_unused2", ""},
+
+	// error_handling
+	{"error", ""},
+	{"error2", ""},
+	{"error3", ""},
+	{"error4", ""},
+
+	// law_of_reflection
+	{"interface", ""},
+	{"interface2", `^type: float64$`},
+
+	// c_go_cgo
+	{"cgo1", ""},
+	{"cgo2", ""},
+	{"cgo3", ""},
+	{"cgo4", ""},
+
+	// timeout
+	{"timeout1", ""},
+	{"timeout2", ""},
+
+	// gobs
+	{"gobs1", ""},
+	{"gobs2", ""},
+
+	// json
+	{"json1", `^$`},
+	{"json2", `the reciprocal of i is`},
+	{"json3", `Age is int 6`},
+	{"json4", `^$`},
+	{"json5", ""},
+
+	// image_package
+	{"image_package1", `^X is 2 Y is 1$`},
+	{"image_package2", `^3 4 false$`},
+	{"image_package3", `^3 4 true$`},
+	{"image_package4", `^image.Point{X:2, Y:1}$`},
+	{"image_package5", `^{255 0 0 255}$`},
+	{"image_package6", `^8 4 true$`},
+
+	// other
+	{"go1", `^Christmas is a holiday: true .*go1.go already exists$`},
+	{"slices", ""},
+}
+
+func onlyTest(files ...string) {
+	var new []testcase
+NextFile:
+	for _, file := range files {
+		file = strings.TrimSuffix(file, ".go")
+		for _, tt := range tests {
+			if tt.file == file {
+				new = append(new, tt)
+				continue NextFile
+			}
+		}
+		fmt.Fprintf(os.Stderr, "test %s.go not found\n", file)
+		os.Exit(1)
+	}
+	tests = new
+}
+
+func skipTest(file string) {
+	for i, tt := range tests {
+		if tt.file == file {
+			copy(tests[i:], tests[i+1:])
+			tests = tests[:len(tests)-1]
+			return
+		}
+	}
+	panic("delete(" + file + "): not found")
+}
+
+func fixcgo() {
+	if os.Getenv("CGO_ENABLED") != "1" {
+		skipTest("cgo1")
+		skipTest("cgo2")
+		skipTest("cgo3")
+		skipTest("cgo4")
+		return
+	}
+
+	switch runtime.GOOS {
+	case "freebsd":
+		// cgo1 and cgo2 don't run on freebsd, srandom has a different signature
+		skipTest("cgo1")
+		skipTest("cgo2")
+	case "netbsd":
+		// cgo1 and cgo2 don't run on netbsd, srandom has a different signature
+		skipTest("cgo1")
+		skipTest("cgo2")
+		// cgo3 and cgo4 don't run on netbsd, since cgo cannot handle stdout correctly, see issue #10715.
+		skipTest("cgo3")
+		skipTest("cgo4")
+	case "openbsd", "solaris":
+		// cgo3 and cgo4 don't run on openbsd and solaris, since cgo cannot handle stdout correctly, see issue #10715.
+		skipTest("cgo3")
+		skipTest("cgo4")
+	}
+}
diff --git a/doc/progs/slices.go b/doc/progs/slices.go
index f9af5fe..967a3e7 100644
--- a/doc/progs/slices.go
+++ b/doc/progs/slices.go
@@ -1,5 +1,3 @@
-// compile
-
 // 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.
diff --git a/doc/progs/timeout1.go b/doc/progs/timeout1.go
index fbc39ca..353ba69 100644
--- a/doc/progs/timeout1.go
+++ b/doc/progs/timeout1.go
@@ -1,8 +1,7 @@
-// compile
-
 // 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.
+
 package timeout
 
 import (
diff --git a/doc/progs/timeout2.go b/doc/progs/timeout2.go
index a12bc2a..b0d34ea 100644
--- a/doc/progs/timeout2.go
+++ b/doc/progs/timeout2.go
@@ -1,8 +1,7 @@
-// compile
-
 // 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.
+
 package query
 
 type Conn string
diff --git a/doc/progs/update.bash b/doc/progs/update.bash
deleted file mode 100755
index d4ecfbe..0000000
--- a/doc/progs/update.bash
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/usr/bin/env bash
-# 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.
-
-set -e
-
-rm -f *.out *.rej *.orig [568].out
-
-for i in *.go; do
-	if grep -q '^// cmpout$' $i; then
-		echo $i
-		go run $i &> ${i/.go/.out}
-	fi
-done
diff --git a/doc/root.html b/doc/root.html
index 3c6de2e..27dbc74 100644
--- a/doc/root.html
+++ b/doc/root.html
@@ -1,5 +1,6 @@
 <!--{
-	"Path": "/"
+	"Path": "/",
+	"Template": true
 }-->
 
 <div class="left">
@@ -25,7 +26,9 @@ Hello, 世界
 </div>
 <div class="buttons">
 <a class="run" href="#" title="Run this code [shift-enter]">Run</a>
+{{if $.Share}}
 <a class="share" href="#" title="Share this code">Share</a>
+{{end}}
 <a class="tour" href="//tour.golang.org/" title="Learn Go from your browser">Tour</a>
 </div>
 <div class="toys">
@@ -53,7 +56,7 @@ simple, reliable, and efficient software.
 
 <div id="gopher"></div>
 
-<a href="/doc/install" id="start">
+<a href="https://golang.org/dl/" id="start">
 <span class="big">Download Go</span>
 <span class="desc">
 Binary distributions available for<br>
diff --git a/doc/security.html b/doc/security.html
new file mode 100644
index 0000000..1879ccf
--- /dev/null
+++ b/doc/security.html
@@ -0,0 +1,174 @@
+<!--{
+	"Title": "Go Security Policy",
+	"Path":  "/security",
+	"Template": true
+}-->
+
+<h2>Implementation</h2>
+
+<h3>Reporting a Security Bug</h3>
+
+<p>
+Please report to us any issues you find.
+This document explains how to do that and what to expect in return.
+</p>
+
+<p>
+All security bugs in the Go distribution should be reported by email to
+<a href="mailto:security at golang.org">security at golang.org</a>.
+This mail is delivered to a small security team.
+Your email will be acknowledged within 24 hours, and you'll receive a more
+detailed response to your email within 72 hours indicating the next steps in
+handling your report.
+If you would like, you can encrypt your report using our PGP key (listed below).
+</p>
+
+<p>
+Please use a descriptive subject line for your report email.
+After the initial reply to your report, the security team will endeavor to keep
+you informed of the progress being made towards a fix and full announcement.
+These updates will be sent at least every five days.
+In reality, this is more likely to be every 24-48 hours.
+</p>
+
+<p>
+If you have not received a reply to your email within 48 hours or you have not
+heard from the security team for the past five days please contact the Go
+security team directly:
+</p>
+
+<ul>
+<li>Primary security coordinator: <a href="mailto:adg at golang.org">Andrew Gerrand</a>  (<a href="https://drive.google.com/a/google.com/file/d/0B42ZAZN5yFufRldybEVNandRN2c/view">public key</a>).</li>
+<li>Secondary coordinator: <a href="mailto:agl at golang.org">Adam Langley</a> (<a href="https://www.imperialviolet.org/key.asc">public key</a>).</li>
+<li>If you receive no response, mail <a href="mailto:golang-dev at googlegroups.com">golang-dev at googlegroups.com</a> or use the <a href="https://groups.google.com/forum/#!forum/golang-dev">golang-dev web interface</a>.</li>
+</ul>
+
+<p>
+Please note that golang-dev is a public discussion forum.
+When escalating on this list, please do not disclose the details of the issue.
+Simply state that you're trying to reach a member of the security team.
+</p>
+
+<h3>Flagging Existing Issues as Security-related</h3>
+
+<p>
+If you believe that an <a href="https://golang.org/issue">existing issue</a>
+is security-related, we ask that you send an email to
+<a href="mailto:security at golang.org">security at golang.org</a>.
+The email should include the issue ID and a short description of why it should
+be handled according to this security policy.
+</p>
+
+<h3>Disclosure Process</h3>
+
+<p>The Go project uses the following disclosure process:</p>
+
+<ol>
+<li>Once the security report is received it is assigned a primary handler.
+This person coordinates the fix and release process.</li>
+<li>The issue is confirmed and a list of affected software is determined.</li>
+<li>Code is audited to find any potential similar problems.</li>
+<li>If it is determined, in consultation with the submitter, that a CVE-ID is
+required, the primary handler obtains one via email to
+<a href="http://oss-security.openwall.org/wiki/mailing-lists/distros">oss-distros</a>.</li>
+<li>Fixes are prepared for the current stable release and the head/master
+revision. These fixes are not yet committed to the public repository.</li>
+<li>A notification is sent to the
+<a href="https://groups.google.com/group/golang-announce">golang-announce</a>
+mailing list to give users time to prepare their systems for the update.</li>
+<li>Three working days following this notification, the fixes are applied to
+the <a href="https://go.googlesource.com/go">public repository</a> and a new
+Go release is issued.</li>
+<li>On the date that the fixes are applied, announcements are sent to
+<a href="https://groups.google.com/group/golang-announce">golang-announce</a>,
+<a href="https://groups.google.com/group/golang-dev">golang-dev</a>, and
+<a href="https://groups.google.com/group/golang-nuts">golang-nuts</a>.
+</ol>
+
+<p>
+This process can take some time, especially when coordination is required with
+maintainers of other projects. Every effort will be made to handle the bug in
+as timely a manner as possible, however it's important that we follow the
+process described above to ensure that disclosures are handled consistently.
+</p>
+
+<p>
+For security issues that include the assignment of a CVE-ID,
+the issue is listed publicly under the
+<a href="https://www.cvedetails.com/vulnerability-list/vendor_id-14185/Golang.html">"Golang" product on the CVEDetails website</a>
+as well as the
+<a href="https://web.nvd.nist.gov/view/vuln/search">National Vulnerability Disclosure site</a>.
+</p>
+
+<h3>Receiving Security Updates</h3>
+
+<p>
+The best way to receive security announcements is to subscribe to the
+<a href="https://groups.google.com/forum/#!forum/golang-announce">golang-announce</a>
+mailing list. Any messages pertaining to a security issue will be prefixed
+with <code>[security]</code>.
+</p>
+
+<h3>Comments on This Policy</h3>
+
+<p>
+If you have any suggestions to improve this policy, please send an email to
+<a href="mailto:golang-dev at golang.org">golang-dev at golang.org</a> for discussion.
+</p>
+
+<h3>PGP Key for <a href="mailto:security at golang.org">security at golang.org</a></h3>
+
+<pre>
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+Comment: GPGTools - https://gpgtools.org
+
+mQINBFXI1h0BEADZdm05GDFWvjmQKutUVb0cJKS+VR+6XU3g/YQZGC8tnIL6i7te
++fPJHfQc2uIw0xeBgZX4Ni/S8yIqsbIjqYeaToX7QFUufJDQwrmlQRDVAvvT5HBT
+J80JEs7yHRreFoLzB6dnWehWXzWle4gFKeIy+hvLrYquZVvbeEYTnX7fNzZg0+5L
+ksvj7lnQlJIy1l3sL/7uPr9qsm45/hzd0WjTQS85Ry6Na3tMwRpqGENDh25Blz75
+8JgK9JmtTJa00my1zzeCXU04CKKEMRbkMLozzudOH4ZLiLWcFiKRpeCn860wC8l3
+oJcyyObuTSbr9o05ra3On+epjCEFkknGX1WxPv+TV34i0a23AtuVyTCloKb7RYXc
+7mUaskZpU2rFBqIkzZ4MQJ7RDtGlm5oBy36j2QL63jAZ1cKoT/yvjJNp2ObmWaVF
+X3tk/nYw2H0YDjTkTCgGtyAOj3Cfqrtsa5L0jG5K2p4RY8mtVgQ5EOh7QxuS+rmN
+JiA39SWh7O6uFCwkz/OCXzqeh6/nP10HAb9S9IC34QQxm7Fhd0ZXzEv9IlBTIRzk
+xddSdACPnLE1gJcFHxBd2LTqS/lmAFShCsf8S252kagKJfHRebQJZHCIs6kT9PfE
+0muq6KRKeDXv01afAUvoB4QW/3chUrtgL2HryyO8ugMu7leVGmoZhFkIrQARAQAB
+tCZHbyBTZWN1cml0eSBUZWFtIDxzZWN1cml0eUBnb2xhbmcub3JnPokCPQQTAQoA
+JwUCVcjWHQIbAwUJB4YfgAULCQgHAwUVCgkICwUWAgMBAAIeAQIXgAAKCRA6RtGR
+eVpYOLnDD/9YVTd6DTwdJq6irVfM/ICPlPTXB0JLERqCI1Veptcp56eQoJ0XWGQp
+tkGlgbvmCzFo0B+65Te7YA4R3oyBCXd6JgyWQQPy5p60FHyuuCPVAReclSWyt9f2
+Yj/u4DjghKhELOvPiI96egcU3g9jrEEcPjm7JYkc9M2gVSNOnnJvcD7wpQJNCzon
+51eMZ1ZyfA5UCBTa0SaT9eXg5zwNlYQnB6ZF6TjXezkhLqlTsBuHxoNVf+9vCC0o
+ZKIM2ovptMx9eEguTDKWaQ7tero7Zs/q5fwk/MDzM/LGJ9aXy2RCtqBxv46vDS7G
+fCNq+aPD/wyFd6hxQkvkua6hgZwYT+cJWHYA2Yv0LO3BYOJdjfc+j2hjv+mC9lF0
+UpWhCVJv3hHoFaxnz62GdROzf2wXz6aR9Saj1rYSvqT9jC20VInxqMufXNN2sbpo
+Kyk6MTbAeepphQpfAWQv+ltWgBiEjuFxYdwv/vmw20996JV7O8nqkeCUW84B6su+
+Y3bbdP9o3DBtOT0j9LTB/FucmdNCNHoO+EnNBKJd6FoYTGLWi3Rq9DLx2V9tdJHo
+Bn67dymcl+iyp337HJNY+qS+KCgoqAWlxkzXRiXKb/yluhXdIkqhg4kL8JPAJvfS
+cs7Zn67Mx04ixJnRMYCDmxtD4xPsFMzM7g8m3PQp+nE7WhujM/ImM7kCDQRVyNYd
+ARAAlw9H/1ybQs4K3XKA1joII16rta9KS7ew76+agXo0jeSRwMEQfItOxYvfhmo8
++ydn5TWsTbifGU8L3+EBTMRRyzWhbaGO0Wizw7BTVJ7n5JW+ndPrcUpp/ilUk6AU
+VxaO/8/R+9+VJZpoeoLHXYloFGNuX58GLIy1jSBvLsLl/Ki5IOrHvD1GK6TftOl5
+j8IPC1LSBrwGJO803x7wUdQP/tsKN/QPR8pnBntrEgrQFSI+Q3qrCvVMmXnBlYum
+jfOBt8pKMgB9/ix+HWN8piQNQiJxD+XjEM6XwUmQqIR7y5GINKWgundCmtYIzVgY
+9p2Br6UPrTJi12LfKv5s2R6NnxFHv/ad29CpPTeLJRsSqFfqBL969BCpj/isXmQE
+m4FtziZidARXo12KiGAnPF9otirNHp4+8hwNB3scf7cI53y8nZivO9cwI7BoClY6
+ZIabjDcJxjK+24emoz3mJ5SHpZpQLSb9o8GbLLfXOq+4uzEX2A30fhrtsQb/x0GM
+4v3EU1aP2mjuksyYbgldtY64tD35wqAA9mVl5Ux+g1HoUBvLw0h+lzwh370NJw//
+ITvBQVUtDMB96rfIP4fL5pYl5pmRz+vsuJ0iXzm05qBgKfSqO7To9SWxQPdX89R4
+u0/XVAlw0Ak9Zceq3W96vseEUTR3aoZCMIPiwfcDaq60rWUAEQEAAYkCJQQYAQoA
+DwUCVcjWHQIbDAUJB4YfgAAKCRA6RtGReVpYOEg/EADZcIYw4q1jAbDkDy3LQG07
+AR8QmLp/RDp72RKbCSIYyvyXEnmrhUg98lUG676qTH+Y7dlEX107dLhFuKEYyV8D
+ZalrFQO/3WpLWdIAmWrj/wq14qii1rgmy96Nh3EqG3CS50HEMGkW1llRx2rgBvGl
+pgoTcwOfT+h8s0HlZdIS/cv2wXqwPgMWr1PIk3as1fu1OH8n/BjeGQQnNJEaoBV7
+El2C/hz3oqf2uYQ1QvpU23F1NrstekxukO8o2Y/fqsgMJqAiNJApUCl/dNhK+W57
+iicjvPirUQk8MUVEHXKhWIzYxon6aEUTx+xyNMBpRJIZlJ61FxtnZhoPiAFtXVPb
++95BRJA9npidlVFjqz9QDK/4NSnJ3KaERR9tTDcvq4zqT22Z1Ai5gWQKqogTz5Mk
+F+nZwVizW0yi33id9qDpAuApp8o6AiyH5Ql1Bo23bvqS2lMrXPIS/QmPPsA76CBs
+lYjQwwz8abUD1pPdzyYtMKZUMwhicSFOHFDM4oQN16k2KJuntuih8BKVDCzIOq+E
+KHyeh1BqWplUtFh1ckxZlXW9p9F7TsWjtfcKaY8hkX0Cr4uVjwAFIjLcAxk67ROe
+huEb3Gt+lwJz6aNnZUU87ukMAxRVR2LL0btdxgc6z8spl66GXro/LUkXmAdyOEMV
+UDrmjf9pr7o00hC7lCHFzw==
+=WE0r
+-----END PGP PUBLIC KEY BLOCK-----
+</pre>
diff --git a/doc/sieve.gif b/doc/sieve.gif
deleted file mode 100644
index 8018ae2..0000000
Binary files a/doc/sieve.gif and /dev/null differ
diff --git a/include/README b/include/README
deleted file mode 100644
index b8fb523..0000000
--- a/include/README
+++ /dev/null
@@ -1,6 +0,0 @@
-The header files under this directory are strictly internal to the gc
-toolchain, so please don't copy them to the system include file
-directory (/usr/include, /usr/local/include, etc.)
-
-Also note that they must be kept as is in $GOROOT/include, or cmd/dist
-will malfunction.
diff --git a/include/ar.h b/include/ar.h
deleted file mode 100644
index d5636b3..0000000
--- a/include/ar.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// Inferno utils/include/ar.h
-// http://code.google.com/p/inferno-os/source/browse/utils/include/ar.h
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#define	ARMAG	"!<arch>\n"
-#define	SARMAG	8
-
-#define	ARFMAG	"`\n"
-#define	SARNAME	16
-
-struct	ar_hdr
-{
-	char	name[SARNAME];
-	char	date[12];
-	char	uid[6];
-	char	gid[6];
-	char	mode[8];
-	char	size[10];
-	char	fmag[2];
-};
-#define	SAR_HDR	(SARNAME+44)
diff --git a/include/bio.h b/include/bio.h
deleted file mode 100644
index 982b881..0000000
--- a/include/bio.h
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
-http://code.google.com/p/inferno-os/source/browse/include/bio.h
-
-	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  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.
-*/
-
-#ifndef _BIO_H_
-#define _BIO_H_ 1
-#if defined(__cplusplus)
-extern "C" {
-#endif
-
-#ifdef AUTOLIB
-AUTOLIB(bio)
-#endif
-
-typedef	struct	Biobuf	Biobuf;
-
-enum
-{
-	Bsize		= 8*1024,
-	Bungetsize	= 4,		/* space for ungetc */
-	Bmagic		= 0x314159,
-	Beof		= -1,
-	Bbad		= -2,
-
-	Binactive	= 0,		/* states */
-	Bractive,
-	Bwactive,
-	Bracteof,
-
-	Bend
-};
-
-struct	Biobuf
-{
-	int	icount;		/* neg num of bytes at eob */
-	int	ocount;		/* num of bytes at bob */
-	int	rdline;		/* num of bytes after rdline */
-	int	runesize;	/* num of bytes of last getrune */
-	int	state;		/* r/w/inactive */
-	int	fid;		/* open file */
-	int	flag;		/* magic if malloc'ed */
-	vlong	offset;		/* offset of buffer in file */
-	int	bsize;		/* size of buffer */
-	unsigned char*	bbuf;		/* pointer to beginning of buffer */
-	unsigned char*	ebuf;		/* pointer to end of buffer */
-	unsigned char*	gbuf;		/* pointer to good data in buf */
-	unsigned char	b[Bungetsize+Bsize];
-};
-
-/*
- * These macros get 1-, 2-, and 4-byte integer values by reading the
- * next few bytes in little-endian order.
- */
-#define	BGETC(bp)\
-	((bp)->icount?(int)((bp)->ebuf[(bp)->icount++]):Bgetc((bp)))
-#define	BGETLE2(bp)\
-	((bp)->icount<=-2?((bp)->icount+=2,((bp)->ebuf[(bp)->icount-2])|((bp)->ebuf[(bp)->icount-1]<<8)):Bgetle2((bp)))
-#define	BGETLE4(bp)\
-	(int)((bp)->icount<=-4?((bp)->icount+=4,((bp)->ebuf[(bp)->icount-4])|((bp)->ebuf[(bp)->icount-3]<<8)|((bp)->ebuf[(bp)->icount-2]<<16)|((uint32)(bp)->ebuf[(bp)->icount-1]<<24)):Bgetle4((bp)))
-
-/*
- * These macros put 1-, 2-, and 4-byte integer values by writing the
- * next few bytes in little-endian order.
- */
-#define	BPUTC(bp,c)\
-	((bp)->ocount?(bp)->ebuf[(bp)->ocount++]=(unsigned char)(c),0:Bputc((bp),(c)))
-#define	BPUTLE2(bp,c)\
-	((bp)->ocount<=-2?(bp)->ocount+=2,(bp)->ebuf[(bp)->ocount-2]=(unsigned char)(c),(bp)->ebuf[(bp)->ocount-1]=(unsigned char)(c>>8),0:Bputle2((bp),(c)))
-#define	BPUTLE4(bp,c)\
-	((bp)->ocount<=-4?(bp)->ocount+=4,(bp)->ebuf[(bp)->ocount-4]=(unsigned char)(c),(bp)->ebuf[(bp)->ocount-3]=(unsigned char)(c>>8),(bp)->ebuf[(bp)->ocount-2]=(unsigned char)(c>>16),(bp)->ebuf[(bp)->ocount-1]=(unsigned char)(c>>24),0:Bputle4((bp),(c)))
-
-#define	BOFFSET(bp)\
-	(((bp)->state==Bractive)?\
-		(bp)->offset + (bp)->icount:\
-	(((bp)->state==Bwactive)?\
-		(bp)->offset + ((bp)->bsize + (bp)->ocount):\
-		-1))
-#define	BLINELEN(bp)\
-	(bp)->rdline
-#define	BFILDES(bp)\
-	(bp)->fid
-
-int	Bbuffered(Biobuf*);
-Biobuf*	Bfdopen(int, int);
-int	Bfildes(Biobuf*);
-int	Bflush(Biobuf*);
-int	Bgetc(Biobuf*);
-int	Bgetle2(Biobuf*);
-int	Bgetle4(Biobuf*);
-int	Bgetd(Biobuf*, double*);
-long	Bgetrune(Biobuf*);
-int	Binit(Biobuf*, int, int);
-int	Binits(Biobuf*, int, int, unsigned char*, int);
-int	Blinelen(Biobuf*);
-vlong	Boffset(Biobuf*);
-Biobuf*	Bopen(char*, int);
-int	Bprint(Biobuf*, char*, ...);
-int	Bputc(Biobuf*, int);
-int	Bputle2(Biobuf*, int);
-int	Bputle4(Biobuf*, int);
-int	Bputrune(Biobuf*, long);
-void*	Brdline(Biobuf*, int);
-char*	Brdstr(Biobuf*, int, int);
-long	Bread(Biobuf*, void*, long);
-vlong	Bseek(Biobuf*, vlong, int);
-int	Bterm(Biobuf*);
-int	Bungetc(Biobuf*);
-int	Bungetrune(Biobuf*);
-long	Bwrite(Biobuf*, void*, long);
-int	Bvprint(Biobuf*, char*, va_list);
-/*c2go
-int	BGETC(Biobuf*);
-int	BGETLE2(Biobuf*);
-int	BGETLE4(Biobuf*);
-int	BPUTC(Biobuf*, int);
-int	BPUTLE2(Biobuf*, int);
-int	BPUTLE4(Biobuf*, int);
-*/
-
-#if defined(__cplusplus)
-}
-#endif
-#endif
diff --git a/include/fmt.h b/include/fmt.h
deleted file mode 100644
index 2280f25..0000000
--- a/include/fmt.h
+++ /dev/null
@@ -1,116 +0,0 @@
-#ifndef _FMT_H_
-#define _FMT_H_ 1
-#if defined(__cplusplus)
-extern "C" {
-#endif
-/*
- * 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.
- */
-
-#include <stdarg.h>
-#include <utf.h>
-
-typedef struct Fmt	Fmt;
-struct Fmt{
-	unsigned char	runes;		/* output buffer is runes or chars? */
-	void	*start;			/* of buffer */
-	void	*to;			/* current place in the buffer */
-	void	*stop;			/* end of the buffer; overwritten if flush fails */
-	int	(*flush)(Fmt *);	/* called when to == stop */
-	void	*farg;			/* to make flush a closure */
-	int	nfmt;			/* num chars formatted so far */
-	va_list	args;			/* args passed to dofmt */
-	Rune	r;			/* % format Rune */
-	int	width;
-	int	prec;
-	unsigned long	flags;
-	char	*decimal;	/* decimal point; cannot be "" */
-
-	/* For %'d */
-	char *thousands;	/* separator for thousands */
-
-	/*
-	 * Each char is an integer indicating #digits before next separator. Values:
-	 *	\xFF: no more grouping (or \x7F; defined to be CHAR_MAX in POSIX)
-	 *	\x00: repeat previous indefinitely
-	 *	\x**: count that many
-	 */
-	char	*grouping;		/* descriptor of separator placement */
-};
-
-enum{
-	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
-};
-
-extern	int	(*fmtdoquote)(int);
-
-/* Edit .+1,/^$/ | cfn $PLAN9/src/lib9/fmt/?*.c | grep -v static |grep -v __ */
-int		dofmt(Fmt *f, char *fmt);
-int		dorfmt(Fmt *f, const Rune *fmt);
-double		fmtcharstod(int(*f)(void*), void *vp);
-int		fmtfdflush(Fmt *f);
-int		fmtfdinit(Fmt *f, int fd, char *buf, int size);
-int		fmtinstall(int c, int (*f)(Fmt*));
-int		fmtnullinit(Fmt*);
-void		fmtlocaleinit(Fmt*, char*, char*, char*);
-int		fmtprint(Fmt *f, char *fmt, ...);
-int		fmtrune(Fmt *f, int r);
-int		fmtrunestrcpy(Fmt *f, Rune *s);
-int		fmtstrcpy(Fmt *f, char *s);
-char*		fmtstrflush(Fmt *f);
-int		fmtstrinit(Fmt *f);
-double		fmtstrtod(const char *as, char **aas);
-int		fmtvprint(Fmt *f, char *fmt, va_list args);
-int		fprint(int fd, char *fmt, ...);
-int		print(char *fmt, ...);
-void		quotefmtinstall(void);
-int		quoterunestrfmt(Fmt *f);
-int		quotestrfmt(Fmt *f);
-Rune*		runefmtstrflush(Fmt *f);
-int		runefmtstrinit(Fmt *f);
-Rune*		runeseprint(Rune *buf, Rune *e, char *fmt, ...);
-Rune*		runesmprint(char *fmt, ...);
-int		runesnprint(Rune *buf, int len, char *fmt, ...);
-int		runesprint(Rune *buf, char *fmt, ...);
-Rune*		runevseprint(Rune *buf, Rune *e, char *fmt, va_list args);
-Rune*		runevsmprint(char *fmt, va_list args);
-int		runevsnprint(Rune *buf, int len, char *fmt, va_list args);
-char*		seprint(char *buf, char *e, char *fmt, ...);
-char*		smprint(char *fmt, ...);
-int		snprint(char *buf, int len, char *fmt, ...);
-int		sprint(char *buf, char *fmt, ...);
-int		vfprint(int fd, char *fmt, va_list args);
-char*		vseprint(char *buf, char *e, char *fmt, va_list args);
-char*		vsmprint(char *fmt, va_list args);
-int		vsnprint(char *buf, int len, char *fmt, va_list args);
-
-#if defined(__cplusplus)
-}
-#endif
-#endif
diff --git a/include/libc.h b/include/libc.h
deleted file mode 100644
index e10dde3..0000000
--- a/include/libc.h
+++ /dev/null
@@ -1,405 +0,0 @@
-/*
-Derived from Inferno include/kern.h and
-Plan 9 from User Space include/libc.h
-
-http://code.google.com/p/inferno-os/source/browse/include/kern.h
-http://code.swtch.com/plan9port/src/tip/include/libc.h
-
-	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  All rights reserved.
-	Portions Copyright © 2001-2007 Russ Cox.  All rights reserved.
-	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.
-*/
-
-/*
- * Lib9 is miscellany from the Plan 9 C library that doesn't
- * fit into libutf or into libfmt, but is still missing from traditional
- * Unix C libraries.
- */
-#ifndef _LIBC_H_
-#define _LIBC_H_ 1
-#if defined(__cplusplus)
-extern "C" {
-#endif
-
-#include <utf.h>
-#include <fmt.h>
-
-/*
- * Begin trimmed down usual libc.h
- */
-
-#ifndef nil
-#define	nil	((void*)0)
-#endif
-#define	nelem(x)	(sizeof(x)/sizeof((x)[0]))
-
-#ifndef offsetof
-#define offsetof(s, m)	(ulong)(&(((s*)0)->m))
-#endif
-
-extern	char*	strecpy(char*, char*, char*);
-extern  int tokenize(char*, char**, int);
-
-extern  double  p9cputime(void);
-#ifndef NOPLAN9DEFINES
-#define cputime     p9cputime
-#endif
-/*
- * one-of-a-kind
- */
-enum
-{
-	PNPROC		= 1,
-	PNGROUP		= 2
-};
-int isInf(double, int);
-
-extern	int	p9atoi(char*);
-extern	long	p9atol(char*);
-extern	vlong	p9atoll(char*);
-extern	double	fmtcharstod(int(*)(void*), void*);
-extern	char*	cleanname(char*);
-extern	int	exitcode(char*);
-extern	void	exits(char*);
-extern	double	frexp(double, int*);
-extern	char*	p9getenv(char*);
-extern	int	p9putenv(char*, char*);
-extern	int	getfields(char*, char**, int, int, char*);
-extern	int	gettokens(char *, char **, int, char *);
-extern	char*	p9getwd(char*, int);
-extern	void	p9longjmp(p9jmp_buf, int);
-extern	void	p9notejmp(void*, p9jmp_buf, int);
-extern	void	perror(const char*);
-extern	int	postnote(int, int, char *);
-extern	double	p9pow10(int);
-extern	char*	p9ctime(long);
-#define p9setjmp(b)	sigsetjmp((void*)(b), 1)
-
-extern	void	sysfatal(char*, ...);
-
-#ifndef NOPLAN9DEFINES
-#define atoi		p9atoi
-#define atol		p9atol
-#define atoll		p9atoll
-#define getenv		p9getenv
-#define	getwd		p9getwd
-#define	longjmp		p9longjmp
-#undef  setjmp
-#define setjmp		p9setjmp
-#define putenv		p9putenv
-#define notejmp		p9notejmp
-#define jmp_buf		p9jmp_buf
-#define pow10		p9pow10
-#undef  strtod
-#define strtod		fmtstrtod
-#define charstod	fmtcharstod
-#define ctime	p9ctime
-#endif
-
-/*
- * system calls
- *
- */
-#define	STATMAX	65535U	/* max length of machine-independent stat structure */
-#define	DIRMAX	(sizeof(Dir)+STATMAX)	/* max length of Dir structure */
-#define	ERRMAX	128	/* max length of error string */
-
-#define	MORDER	0x0003	/* mask for bits defining order of mounting */
-#define	MREPL	0x0000	/* mount replaces object */
-#define	MBEFORE	0x0001	/* mount goes before others in union directory */
-#define	MAFTER	0x0002	/* mount goes after others in union directory */
-#define	MCREATE	0x0004	/* permit creation in mounted directory */
-#define	MCACHE	0x0010	/* cache some data */
-#define	MMASK	0x0017	/* all bits on */
-
-#define	OREAD	0	/* open for read */
-#define	OWRITE	1	/* write */
-#define	ORDWR	2	/* read and write */
-#define	OEXEC	3	/* execute, == read but check execute permission */
-#define	OTRUNC	16	/* or'ed in (except for exec), truncate file first */
-#define	ORCLOSE	64	/* or'ed in, remove on close */
-#define	ODIRECT	128	/* or'ed in, direct access */
-#define	OEXCL	0x1000	/* or'ed in, exclusive use (create only) */
-#define	OAPPEND	0x4000	/* or'ed in, append only */
-
-#define	AEXIST	0	/* accessible: exists */
-#define	AEXEC	1	/* execute access */
-#define	AWRITE	2	/* write access */
-#define	AREAD	4	/* read access */
-
-/* Segattch */
-#define	SG_RONLY	0040	/* read only */
-#define	SG_CEXEC	0100	/* detach on exec */
-
-#define	NCONT	0	/* continue after note */
-#define	NDFLT	1	/* terminate after note */
-#define	NSAVE	2	/* clear note but hold state */
-#define	NRSTR	3	/* restore saved state */
-
-/* bits in Qid.type */
-#define QTDIR		0x80		/* type bit for directories */
-#define QTAPPEND	0x40		/* type bit for append only files */
-#define QTEXCL		0x20		/* type bit for exclusive use files */
-#define QTMOUNT		0x10		/* type bit for mounted channel */
-#define QTAUTH		0x08		/* type bit for authentication file */
-#define QTTMP		0x04		/* type bit for non-backed-up file */
-#define QTSYMLINK	0x02		/* type bit for symbolic link */
-#define QTFILE		0x00		/* type bits for plain file */
-
-/* bits in Dir.mode */
-#define DMDIR		0x80000000	/* mode bit for directories */
-#define DMAPPEND	0x40000000	/* mode bit for append only files */
-#define DMEXCL		0x20000000	/* mode bit for exclusive use files */
-#define DMMOUNT		0x10000000	/* mode bit for mounted channel */
-#define DMAUTH		0x08000000	/* mode bit for authentication file */
-#define DMTMP		0x04000000	/* mode bit for non-backed-up file */
-#define DMSYMLINK	0x02000000	/* mode bit for symbolic link (Unix, 9P2000.u) */
-#define DMDEVICE	0x00800000	/* mode bit for device file (Unix, 9P2000.u) */
-#define DMNAMEDPIPE	0x00200000	/* mode bit for named pipe (Unix, 9P2000.u) */
-#define DMSOCKET	0x00100000	/* mode bit for socket (Unix, 9P2000.u) */
-#define DMSETUID	0x00080000	/* mode bit for setuid (Unix, 9P2000.u) */
-#define DMSETGID	0x00040000	/* mode bit for setgid (Unix, 9P2000.u) */
-
-#define DMREAD		0x4		/* mode bit for read permission */
-#define DMWRITE		0x2		/* mode bit for write permission */
-#define DMEXEC		0x1		/* mode bit for execute permission */
-
-#ifdef RFMEM	/* FreeBSD, OpenBSD, NetBSD */
-#undef RFFDG
-#undef RFNOTEG
-#undef RFPROC
-#undef RFMEM
-#undef RFNOWAIT
-#undef RFCFDG
-#undef RFNAMEG
-#undef RFENVG
-#undef RFCENVG
-#undef RFCFDG
-#undef RFCNAMEG
-#endif
-
-enum
-{
-	RFNAMEG		= (1<<0),
-	RFENVG		= (1<<1),
-	RFFDG		= (1<<2),
-	RFNOTEG		= (1<<3),
-	RFPROC		= (1<<4),
-	RFMEM		= (1<<5),
-	RFNOWAIT	= (1<<6),
-	RFCNAMEG	= (1<<10),
-	RFCENVG		= (1<<11),
-	RFCFDG		= (1<<12)
-/*	RFREND		= (1<<13), */
-/*	RFNOMNT		= (1<<14) */
-};
-
-typedef
-struct Qid
-{
-	uvlong	path;
-	ulong	vers;
-	uchar	type;
-} Qid;
-
-typedef
-struct Dir {
-	/* system-modified data */
-	ushort	type;	/* server type */
-	uint	dev;	/* server subtype */
-	/* file data */
-	Qid	qid;	/* unique id from server */
-	ulong	mode;	/* permissions */
-	ulong	atime;	/* last read time */
-	ulong	mtime;	/* last write time */
-	vlong	length;	/* file length */
-	char	*name;	/* last element of path */
-	char	*uid;	/* owner name */
-	char	*gid;	/* group name */
-	char	*muid;	/* last modifier name */
-
-	/* 9P2000.u extensions */
-	uint	uidnum;		/* numeric uid */
-	uint	gidnum;		/* numeric gid */
-	uint	muidnum;	/* numeric muid */
-	char	*ext;		/* extended info */
-} Dir;
-
-typedef
-struct Waitmsg
-{
-	int pid;	/* of loved one */
-	ulong time[3];	/* of loved one & descendants */
-	char	*msg;
-} Waitmsg;
-
-extern	void	_exits(char*);
-
-extern	void	abort(void);
-extern	long	p9alarm(ulong);
-extern	int	await(char*, int);
-extern	int	awaitfor(int, char*, int);
-extern	int	awaitnohang(char*, int);
-extern	int	p9chdir(char*);
-extern	int	close(int);
-extern	int	p9create(char*, int, ulong);
-extern	int	p9dup(int, int);
-extern	int	errstr(char*, uint);
-extern	int	p9exec(char*, char*[]);
-extern	int	p9execl(char*, ...);
-extern	int	p9rfork(int);
-extern	int	noted(int);
-extern	int	notify(void(*)(void*, char*));
-extern	int	noteenable(char*);
-extern	int	notedisable(char*);
-extern	int	notifyon(char*);
-extern	int	notifyoff(char*);
-extern	int	p9open(char*, int);
-extern	int	fd2path(int, char*, int);
-extern	long	readn(int, void*, long);
-extern	int	remove(const char*);
-extern	vlong	p9seek(int, vlong, int);
-extern	int	p9sleep(long);
-extern	Waitmsg*	p9wait(void);
-extern	Waitmsg*	p9waitfor(int);
-extern	Waitmsg*	waitnohang(void);
-extern	int	p9waitpid(void);
-extern	ulong	rendezvous(ulong, ulong);
-
-extern	char*	getgoos(void);
-extern	char*	getgoarch(void);
-extern	char*	getgoroot(void);
-extern	char*	getgoversion(void);
-extern	char*	getgoarm(void);
-extern	char*	getgo386(void);
-extern	char*	getgoextlinkenabled(void);
-
-extern	char*	mktempdir(void);
-extern	void	removeall(char*);
-extern	int	runcmd(char**);
-
-extern	void	flagcount(char*, char*, int*);
-extern	void	flagint32(char*, char*, int32*);
-extern	void	flagint64(char*, char*, int64*);
-extern	void	flagstr(char*, char*, char**);
-extern	void	flagparse(int*, char***, void (*usage)(void));
-extern	void	flagfn0(char*, char*, void(*fn)(void));
-extern	void	flagfn1(char*, char*, void(*fn)(char*));
-extern	void	flagfn2(char*, char*, void(*fn)(char*, char*));
-extern	void	flagprint(int);
-
-#ifdef _WIN32
-
-#if !defined(_WIN64) && !defined(__MINGW64_VERSION_MAJOR)
-struct timespec {
-	int tv_sec;
-	long tv_nsec;
-};
-#define execv(prog, argv) execv(prog, (const char* const*)(argv))
-#define execvp(prog, argv) execvp(prog, (const char**)(argv))
-#endif
-
-extern int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
-extern int fork(void);
-extern int pread(int fd, void *buf, int n, int off);
-extern int pwrite(int fd, void *buf, int n, int off);
-#undef  getwd
-#define getwd(s, ns) getcwd(s, ns)
-#undef  lseek
-#define lseek(fd, n, base) _lseeki64(fd, n, base)
-#define mkdir(path, perm) mkdir(path)
-#define pipe(fd) _pipe(fd, 512, O_BINARY)
-#else
-#define O_BINARY 0
-#endif
-
-#ifndef NOPLAN9DEFINES
-#define alarm		p9alarm
-#define	dup		p9dup
-#define	exec		p9exec
-#define	execl	p9execl
-#define	seek		p9seek
-#define sleep		p9sleep
-#define wait		p9wait
-#define waitpid		p9waitpid
-#define rfork		p9rfork
-#define create		p9create
-#undef open
-#define open		p9open
-#define	waitfor		p9waitfor
-#endif
-
-extern	Dir*	dirstat(char*);
-extern	Dir*	dirfstat(int);
-extern	int	dirwstat(char*, Dir*);
-extern	int	dirfwstat(int, Dir*);
-extern	void	nulldir(Dir*);
-extern	long	dirreadall(int, Dir**);
-extern	void	rerrstr(char*, uint);
-extern	char*	sysname(void);
-extern	void	werrstr(char*, ...);
-extern	char*	getns(void);
-extern	char*	get9root(void);
-extern	char*	unsharp(char*);
-
-/* external names that we don't want to step on */
-#ifndef NOPLAN9DEFINES
-#define main	p9main
-#endif
-
-/* compiler directives on plan 9 */
-#define	SET(x)	((x)=0)
-#define	USED(x)	if(x){}else{}
-#ifdef __GNUC__
-#	if __GNUC__ >= 3
-#		undef USED
-#		define USED(x) ((void)(x))
-#	endif
-#endif
-
-/* command line */
-extern char	*argv0;
-extern void __fixargv0(void);
-#define	ARGBEGIN	for((void)(argv0?0:(argv0=(__fixargv0(),*argv))),argv++,argc--;\
-			    argv[0] && argv[0][0]=='-' && argv[0][1];\
-			    argc--, argv++) {\
-				char *_args, *_argt;\
-				Rune _argc;\
-				_args = &argv[0][1];\
-				if(_args[0]=='-' && _args[1]==0){\
-					argc--; argv++; break;\
-				}\
-				_argc = 0;\
-				while(*_args && (_args += chartorune(&_argc, _args)))\
-				switch(_argc)
-#define	ARGEND		SET(_argt);USED(_argt);USED(_argc);USED(_args);}USED(argv);USED(argc);
-#define	ARGF()		(_argt=_args, _args="",\
-				(*_argt? _argt: argv[1]? (argc--, *++argv): 0))
-#define	EARGF(x)	(_argt=_args, _args="",\
-				(*_argt? _argt: argv[1]? (argc--, *++argv): ((x), abort(), (char*)0)))
-
-#define	ARGC()		_argc
-
-#if defined(__cplusplus)
-}
-#endif
-#endif	/* _LIB9_H_ */
diff --git a/include/link.h b/include/link.h
deleted file mode 100644
index 05e117c..0000000
--- a/include/link.h
+++ /dev/null
@@ -1,631 +0,0 @@
-// Derived from Inferno utils/6l/l.h and related files.
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/l.h
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-typedef	struct	Addr	Addr;
-typedef	struct	Prog	Prog;
-typedef	struct	LSym	LSym;
-typedef	struct	Reloc	Reloc;
-typedef	struct	Auto	Auto;
-typedef	struct	Hist	Hist;
-typedef	struct	Link	Link;
-typedef	struct	Plist	Plist;
-typedef	struct	LinkArch	LinkArch;
-typedef	struct	Library	Library;
-
-typedef	struct	Pcln	Pcln;
-typedef	struct	Pcdata	Pcdata;
-typedef	struct	Pciter	Pciter;
-
-// prevent incompatible type signatures between liblink and 8l on Plan 9
-#pragma incomplete struct Node
-
-struct	Addr
-{
-	vlong	offset;
-
-	union
-	{
-		char	sval[8];
-		float64	dval;
-		Prog*	branch;	// for 5g, 6g, 8g
-	} u;
-
-	LSym*	sym;
-	LSym*	gotype;
-	short	type;
-	uint8	index;
-	int8	scale;
-	int8	reg;	// for 5l
-	int8	name; // for 5l
-	int8	class;	// for 5l
-	uint8	etype; // for 5g, 6g, 8g
-	int32	offset2;	// for 5l, 8l
-	struct Node*	node; // for 5g, 6g, 8g
-	int64	width; // for 5g, 6g, 8g
-};
-
-struct	Reloc
-{
-	int32	off;
-	uchar	siz;
-	uchar	done;
-	int32	type;
-	int64	add;
-	int64	xadd;
-	LSym*	sym;
-	LSym*	xsym;
-};
-
-struct	Prog
-{
-	vlong	pc;
-	int32	lineno;
-	Prog*	link;
-	short	as;
-	uchar	reg; // arm only
-	uchar	scond; // arm only
-	Addr	from;
-	Addr	to;
-	
-	// for 5g, 6g, 8g internal use
-	void*	opt;
-
-	// for 5l, 6l, 8l internal use
-	Prog*	forwd;
-	Prog*	pcond;
-	Prog*	comefrom;	// 6l, 8l
-	Prog*	pcrel;	// 5l
-	int32	spadj;
-	uchar	mark;
-	uchar	back;	// 6l, 8l
-	uchar	ft;	/* 6l, 8l oclass cache */
-	uchar	tt;	// 6l, 8l
-	uint16	optab;	// 5l
-	uchar	isize;	// 6l, 8l
-
-	char	width;	/* fake for DATA */
-	char	mode;	/* 16, 32, or 64 in 6l, 8l; internal use in 5g, 6g, 8g */
-	
-	/*c2go uchar TEXTFLAG; */
-};
-
-// prevent incompatible type signatures between liblink and 8l on Plan 9
-#pragma incomplete struct Section
-
-struct	LSym
-{
-	char*	name;
-	char*	extname;	// name used in external object files
-	short	type;
-	short	version;
-	uchar	dupok;
-	uchar	cfunc;
-	uchar	external;
-	uchar	nosplit;
-	uchar	reachable;
-	uchar	cgoexport;
-	uchar	special;
-	uchar	stkcheck;
-	uchar	hide;
-	uchar	leaf;	// arm only
-	uchar	fnptr;	// arm only
-	uchar	seenglobl;
-	uchar	onlist;	// on the textp or datap lists
-	int16	symid;	// for writing .5/.6/.8 files
-	int32	dynid;
-	int32	sig;
-	int32	plt;
-	int32	got;
-	int32	align;	// if non-zero, required alignment in bytes
-	int32	elfsym;
-	int32	args;	// size of stack frame incoming arguments area
-	int32	locals;	// size of stack frame locals area (arm only?)
-	vlong	value;
-	vlong	size;
-	LSym*	hash;	// in hash table
-	LSym*	allsym;	// in all symbol list
-	LSym*	next;	// in text or data list
-	LSym*	sub;	// in SSUB list
-	LSym*	outer;	// container of sub
-	LSym*	gotype;
-	LSym*	reachparent;
-	LSym*	queue;
-	char*	file;
-	char*	dynimplib;
-	char*	dynimpvers;
-	struct Section*	sect;
-	
-	// STEXT
-	Auto*	autom;
-	Prog*	text;
-	Prog*	etext;
-	Pcln*	pcln;
-
-	// SDATA, SBSS
-	uchar*	p;
-	int	np;
-	int32	maxp;
-	Reloc*	r;
-	int32	nr;
-	int32	maxr;
-};
-
-// LSym.type
-enum
-{
-	Sxxx,
-
-	/* order here is order in output file */
-	/* readonly, executable */
-	STEXT,
-	SELFRXSECT,
-	
-	/* readonly, non-executable */
-	STYPE,
-	SSTRING,
-	SGOSTRING,
-	SGOFUNC,
-	SRODATA,
-	SFUNCTAB,
-	STYPELINK,
-	SSYMTAB, // TODO: move to unmapped section
-	SPCLNTAB,
-	SELFROSECT,
-	
-	/* writable, non-executable */
-	SMACHOPLT,
-	SELFSECT,
-	SMACHO,	/* Mach-O __nl_symbol_ptr */
-	SMACHOGOT,
-	SWINDOWS,
-	SNOPTRDATA,
-	SINITARR,
-	SDATA,
-	SBSS,
-	SNOPTRBSS,
-	STLSBSS,
-
-	/* not mapped */
-	SXREF,
-	SMACHOSYMSTR,
-	SMACHOSYMTAB,
-	SMACHOINDIRECTPLT,
-	SMACHOINDIRECTGOT,
-	SFILE,
-	SFILEPATH,
-	SCONST,
-	SDYNIMPORT,
-	SHOSTOBJ,
-
-	SSUB = 1<<8,	/* sub-symbol, linked from parent via ->sub list */
-	SMASK = SSUB - 1,
-	SHIDDEN = 1<<9, // hidden or local symbol
-};
-
-// Reloc.type
-enum
-{
-	R_ADDR = 1,
-	R_SIZE,
-	R_CALL, // relocation for direct PC-relative call
-	R_CALLARM, // relocation for ARM direct call
-	R_CALLIND, // marker for indirect call (no actual relocating necessary)
-	R_CONST,
-	R_PCREL,
-	R_TLS,
-	R_TLS_LE, // TLS local exec offset from TLS segment register
-	R_TLS_IE, // TLS initial exec offset from TLS base pointer
-	R_GOTOFF,
-	R_PLT0,
-	R_PLT1,
-	R_PLT2,
-	R_USEFIELD,
-};
-
-// Auto.type
-enum
-{
-	A_AUTO = 1,
-	A_PARAM,
-};
-
-struct	Auto
-{
-	LSym*	asym;
-	Auto*	link;
-	int32	aoffset;
-	int16	type;
-	LSym*	gotype;
-};
-
-enum
-{
-	LINKHASH = 100003,
-};
-
-struct	Hist
-{
-	Hist*	link;
-	char*	name;
-	int32	line;
-	int32	offset;
-};
-
-struct	Plist
-{
-	LSym*	name;
-	Prog*	firstpc;
-	int	recur;
-	Plist*	link;
-};
-
-struct	Library
-{
-	char *objref;	// object where we found the reference
-	char *srcref;	// src file where we found the reference
-	char *file;	// object file
-	char *pkg;	// import path
-};
-
-struct Pcdata
-{
-	uchar *p;
-	int n;
-	int m;
-};
-
-struct Pcln
-{
-	Pcdata pcsp;
-	Pcdata pcfile;
-	Pcdata pcline;
-	Pcdata *pcdata;
-	int npcdata;
-	LSym **funcdata;
-	int64 *funcdataoff;
-	int nfuncdata;
-	
-	LSym **file;
-	int nfile;
-	int mfile;
-
-	LSym *lastfile;
-	int lastindex;
-};
-
-// Pcdata iterator.
-//	for(pciterinit(ctxt, &it, &pcd); !it.done; pciternext(&it)) { it.value holds in [it.pc, it.nextpc) }
-struct Pciter
-{
-	Pcdata d;
-	uchar *p;
-	uint32 pc;
-	uint32 nextpc;
-	uint32 pcscale;
-	int32 value;
-	int start;
-	int done;
-};
-
-void	pciterinit(Link*, Pciter*, Pcdata*);
-void	pciternext(Pciter*);
-
-// symbol version, incremented each time a file is loaded.
-// version==1 is reserved for savehist.
-enum
-{
-	HistVersion = 1,
-};
-
-// Link holds the context for writing object code from a compiler
-// to be linker input or for reading that input into the linker.
-struct	Link
-{
-	int32	thechar; // '5' (arm), '6' (amd64), etc.
-	char*	thestring; // full name of architecture ("arm", "amd64", ..)
-	int32	goarm; // for arm only, GOARM setting
-	int	headtype;
-
-	LinkArch*	arch;
-	int32	(*ignore)(char*);	// do not emit names satisfying this function
-	int32	debugasm;	// -S flag in compiler
-	int32	debugline;	// -L flag in compiler
-	int32	debughist;	// -O flag in linker
-	int32	debugread;	// -W flag in linker
-	int32	debugvlog;	// -v flag in linker
-	int32	debugstack;	// -K flag in linker
-	int32	debugzerostack;	// -Z flag in linker
-	int32	debugdivmod;	// -M flag in 5l
-	int32	debugfloat;	// -F flag in 5l
-	int32	debugpcln;	// -O flag in linker
-	int32	flag_shared;	// -shared flag in linker
-	int32	iself;
-	Biobuf*	bso;	// for -v flag
-	char*	pathname;
-	int32	windows;
-	char*	trimpath;
-	char*	goroot;
-	char*	goroot_final;
-	int32	enforce_data_order;	// for use by assembler
-
-	// hash table of all symbols
-	LSym*	hash[LINKHASH];
-	LSym*	allsym;
-	int32	nsymbol;
-
-	// file-line history
-	Hist*	hist;
-	Hist*	ehist;
-	
-	// all programs
-	Plist*	plist;
-	Plist*	plast;
-	
-	// code generation
-	LSym*	sym_div;
-	LSym*	sym_divu;
-	LSym*	sym_mod;
-	LSym*	sym_modu;
-	LSym*	symmorestack[2];
-	LSym*	tlsg;
-	LSym*	plan9privates;
-	Prog*	curp;
-	Prog*	printp;
-	Prog*	blitrl;
-	Prog*	elitrl;
-	int	rexflag;
-	int	rep; // for nacl
-	int	repn; // for nacl
-	int	lock; // for nacl
-	int	asmode;
-	uchar*	andptr;
-	uchar	and[100];
-	int64	instoffset;
-	int32	autosize;
-	int32	armsize;
-
-	// for reading input files (during linker)
-	vlong	pc;
-	char**	libdir;
-	int32	nlibdir;
-	int32	maxlibdir;
-	Library*	library;
-	int	libraryp;
-	int	nlibrary;
-	int	tlsoffset;
-	void	(*diag)(char*, ...);
-	int	mode;
-	Auto*	curauto;
-	Auto*	curhist;
-	LSym*	cursym;
-	int	version;
-	LSym*	textp;
-	LSym*	etextp;
-	int32	histdepth;
-	int32	nhistfile;
-	LSym*	filesyms;
-};
-
-enum {
-	LittleEndian = 0x04030201,
-	BigEndian = 0x01020304,
-};
-
-// LinkArch is the definition of a single architecture.
-struct LinkArch
-{
-	char*	name; // "arm", "amd64", and so on
-	int	thechar;	// '5', '6', and so on
-	int32	endian; // LittleEndian or BigEndian
-
-	void	(*addstacksplit)(Link*, LSym*);
-	void	(*assemble)(Link*, LSym*);
-	int	(*datasize)(Prog*);
-	void	(*follow)(Link*, LSym*);
-	int	(*iscall)(Prog*);
-	int	(*isdata)(Prog*);
-	Prog*	(*prg)(void);
-	void	(*progedit)(Link*, Prog*);
-	void	(*settextflag)(Prog*, int);
-	int	(*symtype)(Addr*);
-	int	(*textflag)(Prog*);
-
-	int	minlc;
-	int	ptrsize;
-	int	regsize;
-	
-	// TODO: Give these the same values on all systems.
-	int	D_ADDR;
-	int	D_AUTO;
-	int	D_BRANCH;
-	int	D_CONST;
-	int	D_EXTERN;
-	int	D_FCONST;
-	int	D_NONE;
-	int	D_PARAM;
-	int	D_SCONST;
-	int	D_STATIC;
-	int	D_OREG;
-
-	int	ACALL;
-	int	ADATA;
-	int	AEND;
-	int	AFUNCDATA;
-	int	AGLOBL;
-	int	AJMP;
-	int	ANOP;
-	int	APCDATA;
-	int	ARET;
-	int	ATEXT;
-	int	ATYPE;
-	int	AUSEFIELD;
-};
-
-/* executable header types */
-enum {
-	Hunknown = 0,
-	Hdarwin,
-	Hdragonfly,
-	Helf,
-	Hfreebsd,
-	Hlinux,
-	Hnacl,
-	Hnetbsd,
-	Hopenbsd,
-	Hplan9,
-	Hsolaris,
-	Hwindows,
-};
-
-enum
-{
-	LinkAuto = 0,
-	LinkInternal,
-	LinkExternal,
-};
-
-extern	uchar	fnuxi8[8];
-extern	uchar	fnuxi4[4];
-extern	uchar	inuxi1[1];
-extern	uchar	inuxi2[2];
-extern	uchar	inuxi4[4];
-extern	uchar	inuxi8[8];
-
-// asm5.c
-void	span5(Link *ctxt, LSym *s);
-int	chipfloat5(Link *ctxt, float64 e);
-int	chipzero5(Link *ctxt, float64 e);
-
-// asm6.c
-void	span6(Link *ctxt, LSym *s);
-
-// asm8.c
-void	span8(Link *ctxt, LSym *s);
-
-// data.c
-vlong	addaddr(Link *ctxt, LSym *s, LSym *t);
-vlong	addaddrplus(Link *ctxt, LSym *s, LSym *t, vlong add);
-vlong	addaddrplus4(Link *ctxt, LSym *s, LSym *t, vlong add);
-vlong	addpcrelplus(Link *ctxt, LSym *s, LSym *t, vlong add);
-Reloc*	addrel(LSym *s);
-vlong	addsize(Link *ctxt, LSym *s, LSym *t);
-vlong	adduint16(Link *ctxt, LSym *s, uint16 v);
-vlong	adduint32(Link *ctxt, LSym *s, uint32 v);
-vlong	adduint64(Link *ctxt, LSym *s, uint64 v);
-vlong	adduint8(Link *ctxt, LSym *s, uint8 v);
-vlong	adduintxx(Link *ctxt, LSym *s, uint64 v, int wid);
-void	mangle(char *file);
-void	savedata(Link *ctxt, LSym *s, Prog *p, char *pn);
-void	savedata1(Link *ctxt, LSym *s, Prog *p, char *pn, int enforce_order);
-vlong	setaddr(Link *ctxt, LSym *s, vlong off, LSym *t);
-vlong	setaddrplus(Link *ctxt, LSym *s, vlong off, LSym *t, vlong add);
-vlong	setuint16(Link *ctxt, LSym *s, vlong r, uint16 v);
-vlong	setuint32(Link *ctxt, LSym *s, vlong r, uint32 v);
-vlong	setuint64(Link *ctxt, LSym *s, vlong r, uint64 v);
-vlong	setuint8(Link *ctxt, LSym *s, vlong r, uint8 v);
-vlong	setuintxx(Link *ctxt, LSym *s, vlong off, uint64 v, vlong wid);
-void	symgrow(Link *ctxt, LSym *s, vlong siz);
-
-// go.c
-void	double2ieee(uint64 *ieee, double native);
-void*	emallocz(long n);
-void*	erealloc(void *p, long n);
-char*	estrdup(char *p);
-char*	expandpkg(char *t0, char *pkg);
-
-// ld.c
-void	addhist(Link *ctxt, int32 line, int type);
-void	addlib(Link *ctxt, char *src, char *obj, char *path);
-void	addlibpath(Link *ctxt, char *srcref, char *objref, char *file, char *pkg);
-void	collapsefrog(Link *ctxt, LSym *s);
-void	copyhistfrog(Link *ctxt, char *buf, int nbuf);
-int	find1(int32 l, int c);
-void	linkgetline(Link *ctxt, int32 line, LSym **f, int32 *l);
-void	histtoauto(Link *ctxt);
-void	mkfwd(LSym*);
-void	nuxiinit(LinkArch*);
-void	savehist(Link *ctxt, int32 line, int32 off);
-Prog*	copyp(Link*, Prog*);
-Prog*	appendp(Link*, Prog*);
-vlong	atolwhex(char*);
-
-// list[568].c
-void	listinit5(void);
-void	listinit6(void);
-void	listinit8(void);
-
-// obj.c
-int	linklinefmt(Link *ctxt, Fmt *fp);
-void	linklinehist(Link *ctxt, int lineno, char *f, int offset);
-Plist*	linknewplist(Link *ctxt);
-void	linkprfile(Link *ctxt, int32 l);
-
-// objfile.c
-void	ldobjfile(Link *ctxt, Biobuf *b, char *pkg, int64 len, char *path);
-void	writeobj(Link *ctxt, Biobuf *b);
-
-// pass.c
-Prog*	brchain(Link *ctxt, Prog *p);
-Prog*	brloop(Link *ctxt, Prog *p);
-void	linkpatch(Link *ctxt, LSym *sym);
-
-// pcln.c
-void	linkpcln(Link*, LSym*);
-
-// sym.c
-LSym*	linklookup(Link *ctxt, char *name, int v);
-Link*	linknew(LinkArch*);
-LSym*	linknewsym(Link *ctxt, char *symb, int v);
-LSym*	linkrlookup(Link *ctxt, char *name, int v);
-int	linksymfmt(Fmt *f);
-int	headtype(char*);
-char*	headstr(int);
-
-extern	char*	anames5[];
-extern	char*	anames6[];
-extern	char*	anames8[];
-
-extern	char*	cnames5[];
-
-extern	LinkArch	link386;
-extern	LinkArch	linkamd64;
-extern	LinkArch	linkamd64p32;
-extern	LinkArch	linkarm;
-
-#pragma	varargck	type	"A"	int
-#pragma	varargck	type	"D"	Addr*
-#pragma	varargck	type	"lD"	Addr*
-#pragma	varargck	type	"P"	Prog*
-#pragma	varargck	type	"R"	int
-#pragma varargck	type	"^"	int
-
-// TODO(ality): remove this workaround.
-//   It's here because Pconv in liblink/list?.c references %L.
-#pragma	varargck	type	"L"	int32
diff --git a/include/plan9/386/u.h b/include/plan9/386/u.h
deleted file mode 100644
index 1c4076b..0000000
--- a/include/plan9/386/u.h
+++ /dev/null
@@ -1,17 +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.
-
-#include "/386/include/u.h"
-
-typedef	char	int8;
-typedef	uchar	uint8;
-typedef	short	int16;
-typedef	ushort	uint16;
-typedef	int	int32;
-typedef	uint	uint32;
-typedef	vlong	int64;
-typedef	uvlong	uint64;
-typedef	int	intptr;
-typedef	float	float32;
-typedef	double	float64;
diff --git a/include/plan9/amd64/u.h b/include/plan9/amd64/u.h
deleted file mode 100644
index c2d4999..0000000
--- a/include/plan9/amd64/u.h
+++ /dev/null
@@ -1,17 +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.
-
-#include "/amd64/include/u.h"
-
-typedef	char	int8;
-typedef	uchar	uint8;
-typedef	short	int16;
-typedef	ushort	uint16;
-typedef	int	int32;
-typedef	uint	uint32;
-typedef	vlong	int64;
-typedef	uvlong	uint64;
-typedef	vlong	intptr;
-typedef	float	float32;
-typedef	double	float64;
diff --git a/include/plan9/arm/u.h b/include/plan9/arm/u.h
deleted file mode 100644
index 19249aa..0000000
--- a/include/plan9/arm/u.h
+++ /dev/null
@@ -1,15 +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.
-
-#include "/arm/include/u.h"
-
-typedef	char	int8;
-typedef	uchar	uint8;
-typedef	short	int16;
-typedef	ushort	uint16;
-typedef	int	int32;
-typedef	uint	uint32;
-typedef	vlong	int64;
-typedef	uvlong	uint64;
-typedef	int	intptr;
diff --git a/include/plan9/bio.h b/include/plan9/bio.h
deleted file mode 100644
index 13d5e0e..0000000
--- a/include/plan9/bio.h
+++ /dev/null
@@ -1,8 +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.
-
-#include "../bio.h"
-
-#define fmtcharstod charstod
-#define lseek seek
diff --git a/include/plan9/errno.h b/include/plan9/errno.h
deleted file mode 100644
index 1ed572a..0000000
--- a/include/plan9/errno.h
+++ /dev/null
@@ -1,7 +0,0 @@
-// 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.
-
-int errno;
-
-#define ERANGE 1001
diff --git a/include/plan9/fmt.h b/include/plan9/fmt.h
deleted file mode 100644
index b4a4fe7..0000000
--- a/include/plan9/fmt.h
+++ /dev/null
@@ -1,64 +0,0 @@
-// 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 "../fmt.h"
-
-#pragma	varargck	argpos	fmtprint	2
-#pragma	varargck	argpos	fprint		2
-#pragma	varargck	argpos	print		1
-#pragma	varargck	argpos	runeseprint	3
-#pragma	varargck	argpos	runesmprint	1
-#pragma	varargck	argpos	runesnprint	3
-#pragma	varargck	argpos	runesprint	2
-#pragma	varargck	argpos	seprint		3
-#pragma	varargck	argpos	smprint		1
-#pragma	varargck	argpos	snprint		3
-#pragma	varargck	argpos	sprint		2
-
-#pragma	varargck	type	"lld"	vlong
-#pragma	varargck	type	"llo"	vlong
-#pragma	varargck	type	"llx"	vlong
-#pragma	varargck	type	"llb"	vlong
-#pragma	varargck	type	"lld"	uvlong
-#pragma	varargck	type	"llo"	uvlong
-#pragma	varargck	type	"llx"	uvlong
-#pragma	varargck	type	"llb"	uvlong
-#pragma	varargck	type	"ld"	long
-#pragma	varargck	type	"lo"	long
-#pragma	varargck	type	"lx"	long
-#pragma	varargck	type	"lb"	long
-#pragma	varargck	type	"ld"	ulong
-#pragma	varargck	type	"lo"	ulong
-#pragma	varargck	type	"lx"	ulong
-#pragma	varargck	type	"lb"	ulong
-#pragma	varargck	type	"d"	int
-#pragma	varargck	type	"o"	int
-#pragma	varargck	type	"x"	int
-#pragma	varargck	type	"c"	int
-#pragma	varargck	type	"C"	int
-#pragma	varargck	type	"b"	int
-#pragma	varargck	type	"d"	uint
-#pragma	varargck	type	"x"	uint
-#pragma	varargck	type	"c"	uint
-#pragma	varargck	type	"C"	uint
-#pragma	varargck	type	"b"	uint
-#pragma	varargck	type	"f"	double
-#pragma	varargck	type	"e"	double
-#pragma	varargck	type	"g"	double
-#pragma	varargck	type	"s"	char*
-#pragma	varargck	type	"q"	char*
-#pragma	varargck	type	"S"	Rune*
-#pragma	varargck	type	"Q"	Rune*
-#pragma	varargck	type	"r"	void
-#pragma	varargck	type	"%"	void
-#pragma	varargck	type	"n"	int*
-#pragma	varargck	type	"p"	uintptr
-#pragma	varargck	type	"p"	void*
-#pragma	varargck	flag	','
-#pragma	varargck	flag	' '
-#pragma	varargck	flag	'h'
-#pragma	varargck	type	"<"	void*
-#pragma	varargck	type	"["	void*
-#pragma	varargck	type	"H"	void*
-#pragma	varargck	type	"lH"	void*
diff --git a/include/plan9/libc.h b/include/plan9/libc.h
deleted file mode 100644
index 773edee..0000000
--- a/include/plan9/libc.h
+++ /dev/null
@@ -1,33 +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.
-
-#include "/sys/include/ctype.h"
-#include "fmt.h"
-#include "utf.h"
-#include "libc_plan9.h"
-
-char*	getgoos(void);
-char*	getgoarch(void);
-char*	getgoroot(void);
-char*	getgoversion(void);
-char*	getgoarm(void);
-char*	getgo386(void);
-char*	getgoextlinkenabled(void);
-
-void	flagcount(char*, char*, int*);
-void	flagint32(char*, char*, int32*);
-void	flagint64(char*, char*, int64*);
-void	flagstr(char*, char*, char**);
-void	flagparse(int*, char***, void (*usage)(void));
-void	flagfn0(char*, char*, void(*fn)(void));
-void	flagfn1(char*, char*, void(*fn)(char*));
-void	flagfn2(char*, char*, void(*fn)(char*, char*));
-void	flagprint(int);
-
-// The libraries use size_t to avoid -Wconversion warnings from GCC
-// when calling standard library functions like memcpy.
-typedef unsigned long size_t;
-
-// math.h
-#define HUGE_VAL 1.79769313486231e+308
diff --git a/include/plan9/link.h b/include/plan9/link.h
deleted file mode 100644
index f65971e..0000000
--- a/include/plan9/link.h
+++ /dev/null
@@ -1,5 +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.
-
-#include "../link.h"
diff --git a/include/plan9/mklibc.rc b/include/plan9/mklibc.rc
deleted file mode 100755
index 449e15f..0000000
--- a/include/plan9/mklibc.rc
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/bin/rc
-
-pattern='/umuldiv/d
-	/rune routines/,/^\/\*/d
-	/print routines/,/^\/\*/d
-	/error string for/,/^\/\*/d'
-
-sed -e $pattern /sys/include/libc.h | awk '/^enum/ && !n++, /^};/ {next}1'
diff --git a/include/plan9/stdarg.h b/include/plan9/stdarg.h
deleted file mode 100644
index b562a3a..0000000
--- a/include/plan9/stdarg.h
+++ /dev/null
@@ -1,3 +0,0 @@
-// 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/include/plan9/utf.h b/include/plan9/utf.h
deleted file mode 100644
index 03c26d6..0000000
--- a/include/plan9/utf.h
+++ /dev/null
@@ -1,5 +0,0 @@
-// 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 "../utf.h"
diff --git a/include/u.h b/include/u.h
deleted file mode 100644
index 489b2a3..0000000
--- a/include/u.h
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
-Plan 9 from User Space include/u.h
-http://code.swtch.com/plan9port/src/tip/include/u.h
-
-Copyright 2001-2007 Russ Cox.  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.
-*/
-
-#ifndef _U_H_
-#define _U_H_ 1
-#if defined(__cplusplus)
-extern "C" {
-#endif
-
-#define __BSD_VISIBLE 1 /* FreeBSD 5.x */
-#if defined(__sun__)
-#	define __EXTENSIONS__ 1 /* SunOS */
-#	if defined(__SunOS5_6__) || defined(__SunOS5_7__) || defined(__SunOS5_8__)
-		/* NOT USING #define __MAKECONTEXT_V2_SOURCE 1 / * SunOS */
-#	else
-#		define __MAKECONTEXT_V2_SOURCE 1
-#	endif
-#endif
-#define _BSD_SOURCE 1
-#define _NETBSD_SOURCE 1	/* NetBSD */
-#define _DEFAULT_SOURCE 1	/* glibc > 2.19 */
-#define _SVID_SOURCE 1
-#if !defined(__APPLE__) && !defined(__OpenBSD__)
-#	define _XOPEN_SOURCE 1000
-#	define _XOPEN_SOURCE_EXTENDED 1
-#endif
-#if defined(__FreeBSD__)
-#	include <sys/cdefs.h>
-	/* for strtoll */
-#	undef __ISO_C_VISIBLE
-#	define __ISO_C_VISIBLE 1999
-#	undef __LONG_LONG_SUPPORTED
-#	define __LONG_LONG_SUPPORTED
-#endif
-#define _LARGEFILE64_SOURCE 1
-#define _FILE_OFFSET_BITS 64
-
-#include <inttypes.h>
-
-#include <unistd.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <fcntl.h>
-#include <assert.h>
-#include <setjmp.h>
-#include <stddef.h>
-#include <math.h>
-#include <ctype.h>	/* for tolower */
-#include <signal.h>
-#include <time.h>
-
-/*
- * OS-specific crap
- */
-#define _NEEDUCHAR 1
-#define _NEEDUSHORT 1
-#define _NEEDUINT 1
-#define _NEEDULONG 1
-
-#ifdef _WIN32
-typedef jmp_buf sigjmp_buf;
-#endif
-typedef long p9jmp_buf[sizeof(sigjmp_buf)/sizeof(long)];
-
-#if defined(__linux__)
-#	include <sys/types.h>
-#	if defined(__Linux26__)
-#		include <pthread.h>
-#		define PLAN9PORT_USING_PTHREADS 1
-#	endif
-#	if defined(__USE_MISC)
-#		undef _NEEDUSHORT
-#		undef _NEEDUINT
-#		undef _NEEDULONG
-#	endif
-#elif defined(__sun__)
-#	include <sys/types.h>
-#	include <pthread.h>
-#	define PLAN9PORT_USING_PTHREADS 1
-#	undef _NEEDUSHORT
-#	undef _NEEDUINT
-#	undef _NEEDULONG
-#	define nil 0	/* no cast to void* */
-#elif defined(__FreeBSD__)
-#	include <sys/types.h>
-#	include <osreldate.h>
-#	if __FreeBSD_version >= 500000
-#		define PLAN9PORT_USING_PTHREADS 1
-#		include <pthread.h>
-#	endif
-#	if !defined(_POSIX_SOURCE)
-#		undef _NEEDUSHORT
-#		undef _NEEDUINT
-#	endif
-#elif defined(__APPLE__)
-#	include <sys/types.h>
-#	include <pthread.h>
-#	define PLAN9PORT_USING_PTHREADS 1
-#	if __GNUC__ < 4
-#		undef _NEEDUSHORT
-#		undef _NEEDUINT
-#	endif
-#	undef _ANSI_SOURCE
-#	undef _POSIX_C_SOURCE
-#	undef _XOPEN_SOURCE
-#	if !defined(NSIG)
-#		define NSIG 32
-#	endif
-#	define _NEEDLL 1
-#elif defined(__NetBSD__)
-#	include <sched.h>
-#	include <sys/types.h>
-#	undef _NEEDUSHORT
-#	undef _NEEDUINT
-#	undef _NEEDULONG
-#elif defined(__OpenBSD__)
-#	include <sys/types.h>
-#	undef _NEEDUSHORT
-#	undef _NEEDUINT
-#	undef _NEEDULONG
-#elif defined(_WIN32)
-#else
-	/* No idea what system this is -- try some defaults */
-#	include <pthread.h>
-#	define PLAN9PORT_USING_PTHREADS 1
-#endif
-
-#ifndef O_DIRECT
-#define O_DIRECT 0
-#endif
-
-typedef signed char schar;
-
-#ifdef _NEEDUCHAR
-	typedef unsigned char uchar;
-#endif
-#ifdef _NEEDUSHORT
-	typedef unsigned short ushort;
-#endif
-#ifdef _NEEDUINT
-	typedef unsigned int uint;
-#endif
-#ifdef _NEEDULONG
-	typedef unsigned long ulong;
-#endif
-typedef unsigned long long uvlong;
-typedef long long vlong;
-
-typedef uint64_t u64int;
-typedef int64_t s64int;
-typedef uint8_t u8int;
-typedef int8_t s8int;
-typedef uint16_t u16int;
-typedef int16_t s16int;
-typedef uintptr_t uintptr;
-typedef intptr_t intptr;
-typedef uint32_t u32int;
-typedef int32_t s32int;
-
-typedef s8int int8;
-typedef u8int uint8;
-typedef s16int int16;
-typedef u16int uint16;
-typedef s32int int32;
-typedef u32int uint32;
-typedef s64int int64;
-typedef u64int uint64;
-
-typedef float float32;
-typedef double float64;
-
-#undef _NEEDUCHAR
-#undef _NEEDUSHORT
-#undef _NEEDUINT
-#undef _NEEDULONG
-
-#define getcallerpc(x)	__builtin_return_address(0)
-
-#ifndef SIGBUS
-#define SIGBUS SIGSEGV /* close enough */
-#endif
-
-/*
- * Funny-named symbols to tip off 9l to autolink.
- */
-#define AUTOLIB(x)	static int __p9l_autolib_ ## x = 1;
-#define AUTOFRAMEWORK(x) static int __p9l_autoframework_ ## x = 1;
-
-/*
- * Gcc is too smart for its own good.
- */
-#if defined(__GNUC__)
-#	undef strcmp	/* causes way too many warnings */
-#	if __GNUC__ >= 4 || (__GNUC__==3 && !defined(__APPLE_CC__) && !defined(_WIN32))
-#		undef AUTOLIB
-#		define AUTOLIB(x) int __p9l_autolib_ ## x __attribute__ ((weak));
-#		undef AUTOFRAMEWORK
-#		define AUTOFRAMEWORK(x) int __p9l_autoframework_ ## x __attribute__ ((weak));
-#	else
-#		undef AUTOLIB
-#		define AUTOLIB(x) static int __p9l_autolib_ ## x __attribute__ ((unused));
-#		undef AUTOFRAMEWORK
-#		define AUTOFRAMEWORK(x) static int __p9l_autoframework_ ## x __attribute__ ((unused));
-#	endif
-#endif
-
-#if defined(__cplusplus)
-}
-#endif
-#endif
diff --git a/include/utf.h b/include/utf.h
deleted file mode 100644
index be1c46e..0000000
--- a/include/utf.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "../src/lib9/utf/utf.h"
diff --git a/lib/codereview/codereview.cfg b/lib/codereview/codereview.cfg
deleted file mode 100644
index 2801ebf..0000000
--- a/lib/codereview/codereview.cfg
+++ /dev/null
@@ -1 +0,0 @@
-defaultcc: golang-codereviews at googlegroups.com
diff --git a/lib/codereview/codereview.py b/lib/codereview/codereview.py
deleted file mode 100644
index 07c6d2b..0000000
--- a/lib/codereview/codereview.py
+++ /dev/null
@@ -1,3692 +0,0 @@
-# coding=utf-8
-# (The line above is necessary so that I can use 世界 in the
-# *comment* below without Python getting all bent out of shape.)
-
-# Copyright 2007-2009 Google Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#	http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-'''Mercurial interface to codereview.appspot.com.
-
-To configure, set the following options in
-your repository's .hg/hgrc file.
-
-	[extensions]
-	codereview = /path/to/codereview.py
-
-	[codereview]
-	server = codereview.appspot.com
-
-The server should be running Rietveld; see http://code.google.com/p/rietveld/.
-
-In addition to the new commands, this extension introduces
-the file pattern syntax @nnnnnn, where nnnnnn is a change list
-number, to mean the files included in that change list, which
-must be associated with the current client.
-
-For example, if change 123456 contains the files x.go and y.go,
-"hg diff @123456" is equivalent to"hg diff x.go y.go".
-'''
-
-import sys
-
-if __name__ == "__main__":
-	print >>sys.stderr, "This is a Mercurial extension and should not be invoked directly."
-	sys.exit(2)
-
-# We require Python 2.6 for the json package.
-if sys.version < '2.6':
-	print >>sys.stderr, "The codereview extension requires Python 2.6 or newer."
-	print >>sys.stderr, "You are running Python " + sys.version
-	sys.exit(2)
-
-import json
-import os
-import re
-import stat
-import subprocess
-import threading
-import time
-
-from mercurial import commands as hg_commands
-from mercurial import util as hg_util
-
-# bind Plan 9 preferred dotfile location
-if os.sys.platform == 'plan9':
-	try:
-		import plan9
-		n = plan9.bind(os.path.expanduser("~/lib"), os.path.expanduser("~"), plan9.MBEFORE|plan9.MCREATE)
-	except ImportError:
-		pass
-
-defaultcc = None
-codereview_disabled = None
-real_rollback = None
-releaseBranch = None
-server = "codereview.appspot.com"
-server_url_base = None
-testing = None
-
-#######################################################################
-# Normally I would split this into multiple files, but it simplifies
-# import path headaches to keep it all in one file.  Sorry.
-# The different parts of the file are separated by banners like this one.
-
-#######################################################################
-# Helpers
-
-def RelativePath(path, cwd):
-	n = len(cwd)
-	if path.startswith(cwd) and path[n] == '/':
-		return path[n+1:]
-	return path
-
-def Sub(l1, l2):
-	return [l for l in l1 if l not in l2]
-
-def Add(l1, l2):
-	l = l1 + Sub(l2, l1)
-	l.sort()
-	return l
-
-def Intersect(l1, l2):
-	return [l for l in l1 if l in l2]
-
-#######################################################################
-# RE: UNICODE STRING HANDLING
-#
-# Python distinguishes between the str (string of bytes)
-# and unicode (string of code points) types.  Most operations
-# work on either one just fine, but some (like regexp matching)
-# require unicode, and others (like write) require str.
-#
-# As befits the language, Python hides the distinction between
-# unicode and str by converting between them silently, but
-# *only* if all the bytes/code points involved are 7-bit ASCII.
-# This means that if you're not careful, your program works
-# fine on "hello, world" and fails on "hello, 世界".  And of course,
-# the obvious way to be careful - use static types - is unavailable.
-# So the only way is trial and error to find where to put explicit
-# conversions.
-#
-# Because more functions do implicit conversion to str (string of bytes)
-# than do implicit conversion to unicode (string of code points),
-# the convention in this module is to represent all text as str,
-# converting to unicode only when calling a unicode-only function
-# and then converting back to str as soon as possible.
-
-def typecheck(s, t):
-	if type(s) != t:
-		raise hg_util.Abort("type check failed: %s has type %s != %s" % (repr(s), type(s), t))
-
-# If we have to pass unicode instead of str, ustr does that conversion clearly.
-def ustr(s):
-	typecheck(s, str)
-	return s.decode("utf-8")
-
-# Even with those, Mercurial still sometimes turns unicode into str
-# and then tries to use it as ascii.  Change Mercurial's default.
-def set_mercurial_encoding_to_utf8():
-	from mercurial import encoding
-	encoding.encoding = 'utf-8'
-
-set_mercurial_encoding_to_utf8()
-
-# Even with those we still run into problems.
-# I tried to do things by the book but could not convince
-# Mercurial to let me check in a change with UTF-8 in the
-# CL description or author field, no matter how many conversions
-# between str and unicode I inserted and despite changing the
-# default encoding.  I'm tired of this game, so set the default
-# encoding for all of Python to 'utf-8', not 'ascii'.
-def default_to_utf8():
-	import sys
-	stdout, __stdout__ = sys.stdout, sys.__stdout__
-	reload(sys)  # site.py deleted setdefaultencoding; get it back
-	sys.stdout, sys.__stdout__ = stdout, __stdout__
-	sys.setdefaultencoding('utf-8')
-
-default_to_utf8()
-
-#######################################################################
-# Status printer for long-running commands
-
-global_status = None
-
-def set_status(s):
-	if verbosity > 0:
-		print >>sys.stderr, time.asctime(), s
-	global global_status
-	global_status = s
-
-class StatusThread(threading.Thread):
-	def __init__(self):
-		threading.Thread.__init__(self)
-	def run(self):
-		# pause a reasonable amount of time before
-		# starting to display status messages, so that
-		# most hg commands won't ever see them.
-		time.sleep(30)
-
-		# now show status every 15 seconds
-		while True:
-			time.sleep(15 - time.time() % 15)
-			s = global_status
-			if s is None:
-				continue
-			if s == "":
-				s = "(unknown status)"
-			print >>sys.stderr, time.asctime(), s
-
-def start_status_thread():
-	t = StatusThread()
-	t.setDaemon(True)  # allowed to exit if t is still running
-	t.start()
-
-#######################################################################
-# Change list parsing.
-#
-# Change lists are stored in .hg/codereview/cl.nnnnnn
-# where nnnnnn is the number assigned by the code review server.
-# Most data about a change list is stored on the code review server
-# too: the description, reviewer, and cc list are all stored there.
-# The only thing in the cl.nnnnnn file is the list of relevant files.
-# Also, the existence of the cl.nnnnnn file marks this repository
-# as the one where the change list lives.
-
-emptydiff = """Index: ~rietveld~placeholder~
-===================================================================
-diff --git a/~rietveld~placeholder~ b/~rietveld~placeholder~
-new file mode 100644
-"""
-
-class CL(object):
-	def __init__(self, name):
-		typecheck(name, str)
-		self.name = name
-		self.desc = ''
-		self.files = []
-		self.reviewer = []
-		self.cc = []
-		self.url = ''
-		self.local = False
-		self.web = False
-		self.copied_from = None	# None means current user
-		self.mailed = False
-		self.private = False
-		self.lgtm = []
-
-	def DiskText(self):
-		cl = self
-		s = ""
-		if cl.copied_from:
-			s += "Author: " + cl.copied_from + "\n\n"
-		if cl.private:
-			s += "Private: " + str(self.private) + "\n"
-		s += "Mailed: " + str(self.mailed) + "\n"
-		s += "Description:\n"
-		s += Indent(cl.desc, "\t")
-		s += "Files:\n"
-		for f in cl.files:
-			s += "\t" + f + "\n"
-		typecheck(s, str)
-		return s
-
-	def EditorText(self):
-		cl = self
-		s = _change_prolog
-		s += "\n"
-		if cl.copied_from:
-			s += "Author: " + cl.copied_from + "\n"
-		if cl.url != '':
-			s += 'URL: ' + cl.url + '	# cannot edit\n\n'
-		if cl.private:
-			s += "Private: True\n"
-		s += "Reviewer: " + JoinComma(cl.reviewer) + "\n"
-		s += "CC: " + JoinComma(cl.cc) + "\n"
-		s += "\n"
-		s += "Description:\n"
-		if cl.desc == '':
-			s += "\t<enter description here>\n"
-		else:
-			s += Indent(cl.desc, "\t")
-		s += "\n"
-		if cl.local or cl.name == "new":
-			s += "Files:\n"
-			for f in cl.files:
-				s += "\t" + f + "\n"
-			s += "\n"
-		typecheck(s, str)
-		return s
-
-	def PendingText(self, quick=False):
-		cl = self
-		s = cl.name + ":" + "\n"
-		s += Indent(cl.desc, "\t")
-		s += "\n"
-		if cl.copied_from:
-			s += "\tAuthor: " + cl.copied_from + "\n"
-		if not quick:
-			s += "\tReviewer: " + JoinComma(cl.reviewer) + "\n"
-			for (who, line, _) in cl.lgtm:
-				s += "\t\t" + who + ": " + line + "\n"
-			s += "\tCC: " + JoinComma(cl.cc) + "\n"
-		s += "\tFiles:\n"
-		for f in cl.files:
-			s += "\t\t" + f + "\n"
-		typecheck(s, str)
-		return s
-
-	def Flush(self, ui, repo):
-		if self.name == "new":
-			self.Upload(ui, repo, gofmt_just_warn=True, creating=True)
-		dir = CodeReviewDir(ui, repo)
-		path = dir + '/cl.' + self.name
-		f = open(path+'!', "w")
-		f.write(self.DiskText())
-		f.close()
-		if sys.platform == "win32" and os.path.isfile(path):
-			os.remove(path)
-		os.rename(path+'!', path)
-		if self.web and not self.copied_from:
-			EditDesc(self.name, desc=self.desc,
-				reviewers=JoinComma(self.reviewer), cc=JoinComma(self.cc),
-				private=self.private)
-
-	def Delete(self, ui, repo):
-		dir = CodeReviewDir(ui, repo)
-		os.unlink(dir + "/cl." + self.name)
-
-	def Subject(self, ui, repo):
-		s = line1(self.desc)
-		if len(s) > 60:
-			s = s[0:55] + "..."
-		if self.name != "new":
-			s = "code review %s: %s" % (self.name, s)
-		typecheck(s, str)
-		s = branch_prefix(ui, repo) + s
-		# Rietveld does a hard reject on any subject > 100 chars. Be sure.
-		if len(s) >= 100:
-			s = s[0:95] + "..."
-		return s
-
-	def Upload(self, ui, repo, send_mail=False, gofmt=True, gofmt_just_warn=False, creating=False, quiet=False):
-		if not self.files and not creating:
-			ui.warn("no files in change list\n")
-		if ui.configbool("codereview", "force_gofmt", True) and gofmt:
-			CheckFormat(ui, repo, self.files, just_warn=gofmt_just_warn)
-		set_status("uploading CL metadata + diffs")
-		os.chdir(repo.root)
-
-		form_fields = [
-			("content_upload", "1"),
-			("reviewers", JoinComma(self.reviewer)),
-			("cc", JoinComma(self.cc)),
-			("description", self.desc),
-			("base_hashes", ""),
-		]
-
-		if self.name != "new":
-			form_fields.append(("issue", self.name))
-		vcs = None
-		# We do not include files when creating the issue,
-		# because we want the patch sets to record the repository
-		# and base revision they are diffs against.  We use the patch
-		# set message for that purpose, but there is no message with
-		# the first patch set.  Instead the message gets used as the
-		# new CL's overall subject.  So omit the diffs when creating
-		# and then we'll run an immediate upload.
-		# This has the effect that every CL begins with an empty "Patch set 1".
-		if self.files and not creating:
-			vcs = MercurialVCS(upload_options, ui, repo)
-			data = vcs.GenerateDiff(self.files)
-			files = vcs.GetBaseFiles(data)
-			if len(data) > MAX_UPLOAD_SIZE:
-				uploaded_diff_file = []
-				form_fields.append(("separate_patches", "1"))
-			else:
-				uploaded_diff_file = [("data", "data.diff", data)]
-		else:
-			uploaded_diff_file = [("data", "data.diff", emptydiff)]
-		
-		if vcs and self.name != "new":
-			form_fields.append(("subject", "diff -r " + vcs.base_rev + " " + ui.expandpath("default")))
-		else:
-			# First upload sets the subject for the CL itself.
-			form_fields.append(("subject", self.Subject(ui, repo)))
-		
-		ctype, body = EncodeMultipartFormData(form_fields, uploaded_diff_file)
-		response_body = MySend("/upload", body, content_type=ctype)
-		patchset = None
-		msg = response_body
-		lines = msg.splitlines()
-		if len(lines) >= 2:
-			msg = lines[0]
-			patchset = lines[1].strip()
-			patches = [x.split(" ", 1) for x in lines[2:]]
-		else:
-			print >>sys.stderr, "Server says there is nothing to upload (probably wrong):\n" + msg
-		if response_body.startswith("Issue updated.") and quiet:
-			pass
-		else:
-			ui.status(msg + "\n")
-		set_status("uploaded CL metadata + diffs")
-		if not response_body.startswith("Issue created.") and not response_body.startswith("Issue updated."):
-			raise hg_util.Abort("failed to update issue: " + response_body)
-		issue = msg[msg.rfind("/")+1:]
-		self.name = issue
-		if not self.url:
-			self.url = server_url_base + self.name
-		if not uploaded_diff_file:
-			set_status("uploading patches")
-			patches = UploadSeparatePatches(issue, rpc, patchset, data, upload_options)
-		if vcs:
-			set_status("uploading base files")
-			vcs.UploadBaseFiles(issue, rpc, patches, patchset, upload_options, files)
-		if patchset != "1":
-			MySend("/" + issue + "/upload_complete/" + patchset, payload="")
-		if send_mail:
-			set_status("sending mail")
-			MySend("/" + issue + "/mail", payload="")
-		self.web = True
-		set_status("flushing changes to disk")
-		self.Flush(ui, repo)
-		return
-
-	def Mail(self, ui, repo):
-		pmsg = "Hello " + JoinComma(self.reviewer)
-		if self.cc:
-			pmsg += " (cc: %s)" % (', '.join(self.cc),)
-		pmsg += ",\n"
-		pmsg += "\n"
-		repourl = ui.expandpath("default")
-		if not self.mailed:
-			pmsg += "I'd like you to review this change to"
-			branch = repo[None].branch()
-			if workbranch(branch) and branch != "default":
-				pmsg += " the " + branch + " branch of"
-			pmsg += "\n" + repourl + "\n"
-		else:
-			pmsg += "Please take another look.\n"
-		typecheck(pmsg, str)
-		PostMessage(ui, self.name, pmsg, subject=self.Subject(ui, repo))
-		self.mailed = True
-		self.Flush(ui, repo)
-
-def GoodCLName(name):
-	typecheck(name, str)
-	return re.match("^[0-9]+$", name)
-
-def ParseCL(text, name):
-	typecheck(text, str)
-	typecheck(name, str)
-	sname = None
-	lineno = 0
-	sections = {
-		'Author': '',
-		'Description': '',
-		'Files': '',
-		'URL': '',
-		'Reviewer': '',
-		'CC': '',
-		'Mailed': '',
-		'Private': '',
-	}
-	for line in text.split('\n'):
-		lineno += 1
-		line = line.rstrip()
-		if line != '' and line[0] == '#':
-			continue
-		if line == '' or line[0] == ' ' or line[0] == '\t':
-			if sname == None and line != '':
-				return None, lineno, 'text outside section'
-			if sname != None:
-				sections[sname] += line + '\n'
-			continue
-		p = line.find(':')
-		if p >= 0:
-			s, val = line[:p].strip(), line[p+1:].strip()
-			if s in sections:
-				sname = s
-				if val != '':
-					sections[sname] += val + '\n'
-				continue
-		return None, lineno, 'malformed section header'
-
-	for k in sections:
-		sections[k] = StripCommon(sections[k]).rstrip()
-
-	cl = CL(name)
-	if sections['Author']:
-		cl.copied_from = sections['Author']
-	cl.desc = sections['Description']
-	for line in sections['Files'].split('\n'):
-		i = line.find('#')
-		if i >= 0:
-			line = line[0:i].rstrip()
-		line = line.strip()
-		if line == '':
-			continue
-		cl.files.append(line)
-	cl.reviewer = SplitCommaSpace(sections['Reviewer'])
-	cl.cc = SplitCommaSpace(sections['CC'])
-	cl.url = sections['URL']
-	if sections['Mailed'] != 'False':
-		# Odd default, but avoids spurious mailings when
-		# reading old CLs that do not have a Mailed: line.
-		# CLs created with this update will always have 
-		# Mailed: False on disk.
-		cl.mailed = True
-	if sections['Private'] in ('True', 'true', 'Yes', 'yes'):
-		cl.private = True
-	if cl.desc == '<enter description here>':
-		cl.desc = ''
-	return cl, 0, ''
-
-def SplitCommaSpace(s):
-	typecheck(s, str)
-	s = s.strip()
-	if s == "":
-		return []
-	return re.split(", *", s)
-
-def CutDomain(s):
-	typecheck(s, str)
-	i = s.find('@')
-	if i >= 0:
-		s = s[0:i]
-	return s
-
-def JoinComma(l):
-	seen = {}
-	uniq = []
-	for s in l:
-		typecheck(s, str)
-		if s not in seen:
-			seen[s] = True
-			uniq.append(s)
-			
-	return ", ".join(uniq)
-
-def ExceptionDetail():
-	s = str(sys.exc_info()[0])
-	if s.startswith("<type '") and s.endswith("'>"):
-		s = s[7:-2]
-	elif s.startswith("<class '") and s.endswith("'>"):
-		s = s[8:-2]
-	arg = str(sys.exc_info()[1])
-	if len(arg) > 0:
-		s += ": " + arg
-	return s
-
-def IsLocalCL(ui, repo, name):
-	return GoodCLName(name) and os.access(CodeReviewDir(ui, repo) + "/cl." + name, 0)
-
-# Load CL from disk and/or the web.
-def LoadCL(ui, repo, name, web=True):
-	typecheck(name, str)
-	set_status("loading CL " + name)
-	if not GoodCLName(name):
-		return None, "invalid CL name"
-	dir = CodeReviewDir(ui, repo)
-	path = dir + "cl." + name
-	if os.access(path, 0):
-		ff = open(path)
-		text = ff.read()
-		ff.close()
-		cl, lineno, err = ParseCL(text, name)
-		if err != "":
-			return None, "malformed CL data: "+err
-		cl.local = True
-	else:
-		cl = CL(name)
-	if web:
-		set_status("getting issue metadata from web")
-		d = JSONGet(ui, "/api/" + name + "?messages=true")
-		set_status(None)
-		if d is None:
-			return None, "cannot load CL %s from server" % (name,)
-		if 'owner_email' not in d or 'issue' not in d or str(d['issue']) != name:
-			return None, "malformed response loading CL data from code review server"
-		cl.dict = d
-		cl.reviewer = d.get('reviewers', [])
-		cl.cc = d.get('cc', [])
-		if cl.local and cl.copied_from and cl.desc:
-			# local copy of CL written by someone else
-			# and we saved a description.  use that one,
-			# so that committers can edit the description
-			# before doing hg submit.
-			pass
-		else:
-			cl.desc = d.get('description', "")
-		cl.url = server_url_base + name
-		cl.web = True
-		cl.private = d.get('private', False) != False
-		cl.lgtm = []
-		for m in d.get('messages', []):
-			if m.get('approval', False) == True or m.get('disapproval', False) == True:
-				who = re.sub('@.*', '', m.get('sender', ''))
-				text = re.sub("\n(.|\n)*", '', m.get('text', ''))
-				cl.lgtm.append((who, text, m.get('approval', False)))
-
-	set_status("loaded CL " + name)
-	return cl, ''
-
-class LoadCLThread(threading.Thread):
-	def __init__(self, ui, repo, dir, f, web):
-		threading.Thread.__init__(self)
-		self.ui = ui
-		self.repo = repo
-		self.dir = dir
-		self.f = f
-		self.web = web
-		self.cl = None
-	def run(self):
-		cl, err = LoadCL(self.ui, self.repo, self.f[3:], web=self.web)
-		if err != '':
-			self.ui.warn("loading "+self.dir+self.f+": " + err + "\n")
-			return
-		self.cl = cl
-
-# Load all the CLs from this repository.
-def LoadAllCL(ui, repo, web=True):
-	dir = CodeReviewDir(ui, repo)
-	m = {}
-	files = [f for f in os.listdir(dir) if f.startswith('cl.')]
-	if not files:
-		return m
-	active = []
-	first = True
-	for f in files:
-		t = LoadCLThread(ui, repo, dir, f, web)
-		t.start()
-		if web and first:
-			# first request: wait in case it needs to authenticate
-			# otherwise we get lots of user/password prompts
-			# running in parallel.
-			t.join()
-			if t.cl:
-				m[t.cl.name] = t.cl
-			first = False
-		else:
-			active.append(t)
-	for t in active:
-		t.join()
-		if t.cl:
-			m[t.cl.name] = t.cl
-	return m
-
-# Find repository root.  On error, ui.warn and return None
-def RepoDir(ui, repo):
-	url = repo.url();
-	if not url.startswith('file:'):
-		ui.warn("repository %s is not in local file system\n" % (url,))
-		return None
-	url = url[5:]
-	if url.endswith('/'):
-		url = url[:-1]
-	typecheck(url, str)
-	return url
-
-# Find (or make) code review directory.  On error, ui.warn and return None
-def CodeReviewDir(ui, repo):
-	dir = RepoDir(ui, repo)
-	if dir == None:
-		return None
-	dir += '/.hg/codereview/'
-	if not os.path.isdir(dir):
-		try:
-			os.mkdir(dir, 0700)
-		except:
-			ui.warn('cannot mkdir %s: %s\n' % (dir, ExceptionDetail()))
-			return None
-	typecheck(dir, str)
-	return dir
-
-# Turn leading tabs into spaces, so that the common white space
-# prefix doesn't get confused when people's editors write out 
-# some lines with spaces, some with tabs.  Only a heuristic
-# (some editors don't use 8 spaces either) but a useful one.
-def TabsToSpaces(line):
-	i = 0
-	while i < len(line) and line[i] == '\t':
-		i += 1
-	return ' '*(8*i) + line[i:]
-
-# Strip maximal common leading white space prefix from text
-def StripCommon(text):
-	typecheck(text, str)
-	ws = None
-	for line in text.split('\n'):
-		line = line.rstrip()
-		if line == '':
-			continue
-		line = TabsToSpaces(line)
-		white = line[:len(line)-len(line.lstrip())]
-		if ws == None:
-			ws = white
-		else:
-			common = ''
-			for i in range(min(len(white), len(ws))+1):
-				if white[0:i] == ws[0:i]:
-					common = white[0:i]
-			ws = common
-		if ws == '':
-			break
-	if ws == None:
-		return text
-	t = ''
-	for line in text.split('\n'):
-		line = line.rstrip()
-		line = TabsToSpaces(line)
-		if line.startswith(ws):
-			line = line[len(ws):]
-		if line == '' and t == '':
-			continue
-		t += line + '\n'
-	while len(t) >= 2 and t[-2:] == '\n\n':
-		t = t[:-1]
-	typecheck(t, str)
-	return t
-
-# Indent text with indent.
-def Indent(text, indent):
-	typecheck(text, str)
-	typecheck(indent, str)
-	t = ''
-	for line in text.split('\n'):
-		t += indent + line + '\n'
-	typecheck(t, str)
-	return t
-
-# Return the first line of l
-def line1(text):
-	typecheck(text, str)
-	return text.split('\n')[0]
-
-_change_prolog = """# Change list.
-# Lines beginning with # are ignored.
-# Multi-line values should be indented.
-"""
-
-desc_re = '^(.+: |(tag )?(release|weekly)\.|fix build|undo CL)'
-
-desc_msg = '''Your CL description appears not to use the standard form.
-
-The first line of your change description is conventionally a
-one-line summary of the change, prefixed by the primary affected package,
-and is used as the subject for code review mail; the rest of the description
-elaborates.
-
-Examples:
-
-	encoding/rot13: new package
-
-	math: add IsInf, IsNaN
-	
-	net: fix cname in LookupHost
-
-	unicode: update to Unicode 5.0.2
-
-'''
-
-def promptyesno(ui, msg):
-	if hgversion >= "2.7":
-		return ui.promptchoice(msg + " $$ &yes $$ &no", 0) == 0
-	else:
-		return ui.promptchoice(msg, ["&yes", "&no"], 0) == 0
-
-def promptremove(ui, repo, f):
-	if promptyesno(ui, "hg remove %s (y/n)?" % (f,)):
-		if hg_commands.remove(ui, repo, 'path:'+f) != 0:
-			ui.warn("error removing %s" % (f,))
-
-def promptadd(ui, repo, f):
-	if promptyesno(ui, "hg add %s (y/n)?" % (f,)):
-		if hg_commands.add(ui, repo, 'path:'+f) != 0:
-			ui.warn("error adding %s" % (f,))
-
-def EditCL(ui, repo, cl):
-	set_status(None)	# do not show status
-	s = cl.EditorText()
-	while True:
-		s = ui.edit(s, ui.username())
-		
-		# We can't trust Mercurial + Python not to die before making the change,
-		# so, by popular demand, just scribble the most recent CL edit into
-		# $(hg root)/last-change so that if Mercurial does die, people
-		# can look there for their work.
-		try:
-			f = open(repo.root+"/last-change", "w")
-			f.write(s)
-			f.close()
-		except:
-			pass
-
-		clx, line, err = ParseCL(s, cl.name)
-		if err != '':
-			if not promptyesno(ui, "error parsing change list: line %d: %s\nre-edit (y/n)?" % (line, err)):
-				return "change list not modified"
-			continue
-		
-		# Check description.
-		if clx.desc == '':
-			if promptyesno(ui, "change list should have a description\nre-edit (y/n)?"):
-				continue
-		elif re.search('<enter reason for undo>', clx.desc):
-			if promptyesno(ui, "change list description omits reason for undo\nre-edit (y/n)?"):
-				continue
-		elif not re.match(desc_re, clx.desc.split('\n')[0]):
-			if promptyesno(ui, desc_msg + "re-edit (y/n)?"):
-				continue
-
-		# Check file list for files that need to be hg added or hg removed
-		# or simply aren't understood.
-		pats = ['path:'+f for f in clx.files]
-		changed = hg_matchPattern(ui, repo, *pats, modified=True, added=True, removed=True)
-		deleted = hg_matchPattern(ui, repo, *pats, deleted=True)
-		unknown = hg_matchPattern(ui, repo, *pats, unknown=True)
-		ignored = hg_matchPattern(ui, repo, *pats, ignored=True)
-		clean = hg_matchPattern(ui, repo, *pats, clean=True)
-		files = []
-		for f in clx.files:
-			if f in changed:
-				files.append(f)
-				continue
-			if f in deleted:
-				promptremove(ui, repo, f)
-				files.append(f)
-				continue
-			if f in unknown:
-				promptadd(ui, repo, f)
-				files.append(f)
-				continue
-			if f in ignored:
-				ui.warn("error: %s is excluded by .hgignore; omitting\n" % (f,))
-				continue
-			if f in clean:
-				ui.warn("warning: %s is listed in the CL but unchanged\n" % (f,))
-				files.append(f)
-				continue
-			p = repo.root + '/' + f
-			if os.path.isfile(p):
-				ui.warn("warning: %s is a file but not known to hg\n" % (f,))
-				files.append(f)
-				continue
-			if os.path.isdir(p):
-				ui.warn("error: %s is a directory, not a file; omitting\n" % (f,))
-				continue
-			ui.warn("error: %s does not exist; omitting\n" % (f,))
-		clx.files = files
-
-		cl.desc = clx.desc
-		cl.reviewer = clx.reviewer
-		cl.cc = clx.cc
-		cl.files = clx.files
-		cl.private = clx.private
-		break
-	return ""
-
-# For use by submit, etc. (NOT by change)
-# Get change list number or list of files from command line.
-# If files are given, make a new change list.
-def CommandLineCL(ui, repo, pats, opts, op="verb", defaultcc=None):
-	if len(pats) > 0 and GoodCLName(pats[0]):
-		if len(pats) != 1:
-			return None, "cannot specify change number and file names"
-		if opts.get('message'):
-			return None, "cannot use -m with existing CL"
-		cl, err = LoadCL(ui, repo, pats[0], web=True)
-		if err != "":
-			return None, err
-	else:
-		cl = CL("new")
-		cl.local = True
-		cl.files = ChangedFiles(ui, repo, pats, taken=Taken(ui, repo))
-		if not cl.files:
-			return None, "no files changed (use hg %s <number> to use existing CL)" % op
-	if opts.get('reviewer'):
-		cl.reviewer = Add(cl.reviewer, SplitCommaSpace(opts.get('reviewer')))
-	if opts.get('cc'):
-		cl.cc = Add(cl.cc, SplitCommaSpace(opts.get('cc')))
-	if defaultcc and not cl.private:
-		cl.cc = Add(cl.cc, defaultcc)
-	if cl.name == "new":
-		if opts.get('message'):
-			cl.desc = opts.get('message')
-		else:
-			err = EditCL(ui, repo, cl)
-			if err != '':
-				return None, err
-	return cl, ""
-
-#######################################################################
-# Change list file management
-
-# Return list of changed files in repository that match pats.
-# The patterns came from the command line, so we warn
-# if they have no effect or cannot be understood.
-def ChangedFiles(ui, repo, pats, taken=None):
-	taken = taken or {}
-	# Run each pattern separately so that we can warn about
-	# patterns that didn't do anything useful.
-	for p in pats:
-		for f in hg_matchPattern(ui, repo, p, unknown=True):
-			promptadd(ui, repo, f)
-		for f in hg_matchPattern(ui, repo, p, removed=True):
-			promptremove(ui, repo, f)
-		files = hg_matchPattern(ui, repo, p, modified=True, added=True, removed=True)
-		for f in files:
-			if f in taken:
-				ui.warn("warning: %s already in CL %s\n" % (f, taken[f].name))
-		if not files:
-			ui.warn("warning: %s did not match any modified files\n" % (p,))
-
-	# Again, all at once (eliminates duplicates)
-	l = hg_matchPattern(ui, repo, *pats, modified=True, added=True, removed=True)
-	l.sort()
-	if taken:
-		l = Sub(l, taken.keys())
-	return l
-
-# Return list of changed files in repository that match pats and still exist.
-def ChangedExistingFiles(ui, repo, pats, opts):
-	l = hg_matchPattern(ui, repo, *pats, modified=True, added=True)
-	l.sort()
-	return l
-
-# Return list of files claimed by existing CLs
-def Taken(ui, repo):
-	all = LoadAllCL(ui, repo, web=False)
-	taken = {}
-	for _, cl in all.items():
-		for f in cl.files:
-			taken[f] = cl
-	return taken
-
-# Return list of changed files that are not claimed by other CLs
-def DefaultFiles(ui, repo, pats):
-	return ChangedFiles(ui, repo, pats, taken=Taken(ui, repo))
-
-#######################################################################
-# File format checking.
-
-def CheckFormat(ui, repo, files, just_warn=False):
-	set_status("running gofmt")
-	CheckGofmt(ui, repo, files, just_warn)
-	CheckTabfmt(ui, repo, files, just_warn)
-
-# Check that gofmt run on the list of files does not change them
-def CheckGofmt(ui, repo, files, just_warn):
-	files = gofmt_required(files)
-	if not files:
-		return
-	cwd = os.getcwd()
-	files = [RelativePath(repo.root + '/' + f, cwd) for f in files]
-	files = [f for f in files if os.access(f, 0)]
-	if not files:
-		return
-	try:
-		cmd = subprocess.Popen(["gofmt", "-l"] + files, shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=sys.platform != "win32")
-		cmd.stdin.close()
-	except:
-		raise hg_util.Abort("gofmt: " + ExceptionDetail())
-	data = cmd.stdout.read()
-	errors = cmd.stderr.read()
-	cmd.wait()
-	set_status("done with gofmt")
-	if len(errors) > 0:
-		ui.warn("gofmt errors:\n" + errors.rstrip() + "\n")
-		return
-	if len(data) > 0:
-		msg = "gofmt needs to format these files (run hg gofmt):\n" + Indent(data, "\t").rstrip()
-		if just_warn:
-			ui.warn("warning: " + msg + "\n")
-		else:
-			raise hg_util.Abort(msg)
-	return
-
-# Check that *.[chys] files indent using tabs.
-def CheckTabfmt(ui, repo, files, just_warn):
-	files = [f for f in files if f.startswith('src/') and re.search(r"\.[chys]$", f) and not re.search(r"\.tab\.[ch]$", f)]
-	if not files:
-		return
-	cwd = os.getcwd()
-	files = [RelativePath(repo.root + '/' + f, cwd) for f in files]
-	files = [f for f in files if os.access(f, 0)]
-	badfiles = []
-	for f in files:
-		try:
-			for line in open(f, 'r'):
-				# Four leading spaces is enough to complain about,
-				# except that some Plan 9 code uses four spaces as the label indent,
-				# so allow that.
-				if line.startswith('    ') and not re.match('    [A-Za-z0-9_]+:', line):
-					badfiles.append(f)
-					break
-		except:
-			# ignore cannot open file, etc.
-			pass
-	if len(badfiles) > 0:
-		msg = "these files use spaces for indentation (use tabs instead):\n\t" + "\n\t".join(badfiles)
-		if just_warn:
-			ui.warn("warning: " + msg + "\n")
-		else:
-			raise hg_util.Abort(msg)
-	return
-
-#######################################################################
-# CONTRIBUTORS file parsing
-
-contributorsCache = None
-contributorsURL = None
-
-def ReadContributors(ui, repo):
-	global contributorsCache
-	if contributorsCache is not None:
-		return contributorsCache
-
-	try:
-		if contributorsURL is not None:
-			opening = contributorsURL
-			f = urllib2.urlopen(contributorsURL)
-		else:
-			opening = repo.root + '/CONTRIBUTORS'
-			f = open(repo.root + '/CONTRIBUTORS', 'r')
-	except:
-		ui.write("warning: cannot open %s: %s\n" % (opening, ExceptionDetail()))
-		return {}
-
-	contributors = {}
-	for line in f:
-		# CONTRIBUTORS is a list of lines like:
-		#	Person <email>
-		#	Person <email> <alt-email>
-		# The first email address is the one used in commit logs.
-		if line.startswith('#'):
-			continue
-		m = re.match(r"([^<>]+\S)\s+(<[^<>\s]+>)((\s+<[^<>\s]+>)*)\s*$", line)
-		if m:
-			name = m.group(1)
-			email = m.group(2)[1:-1]
-			contributors[email.lower()] = (name, email)
-			for extra in m.group(3).split():
-				contributors[extra[1:-1].lower()] = (name, email)
-
-	contributorsCache = contributors
-	return contributors
-
-def CheckContributor(ui, repo, user=None):
-	set_status("checking CONTRIBUTORS file")
-	user, userline = FindContributor(ui, repo, user, warn=False)
-	if not userline:
-		raise hg_util.Abort("cannot find %s in CONTRIBUTORS" % (user,))
-	return userline
-
-def FindContributor(ui, repo, user=None, warn=True):
-	if not user:
-		user = ui.config("ui", "username")
-		if not user:
-			raise hg_util.Abort("[ui] username is not configured in .hgrc")
-	user = user.lower()
-	m = re.match(r".*<(.*)>", user)
-	if m:
-		user = m.group(1)
-
-	contributors = ReadContributors(ui, repo)
-	if user not in contributors:
-		if warn:
-			ui.warn("warning: cannot find %s in CONTRIBUTORS\n" % (user,))
-		return user, None
-	
-	user, email = contributors[user]
-	return email, "%s <%s>" % (user, email)
-
-#######################################################################
-# Mercurial helper functions.
-# Read http://mercurial.selenic.com/wiki/MercurialApi before writing any of these.
-# We use the ui.pushbuffer/ui.popbuffer + hg_commands.xxx tricks for all interaction
-# with Mercurial.  It has proved the most stable as they make changes.
-
-hgversion = hg_util.version()
-
-# We require Mercurial 1.9 and suggest Mercurial 2.1.
-# The details of the scmutil package changed then,
-# so allowing earlier versions would require extra band-aids below.
-# Ubuntu 11.10 ships with Mercurial 1.9.1 as the default version.
-hg_required = "1.9"
-hg_suggested = "2.1"
-
-old_message = """
-
-The code review extension requires Mercurial """+hg_required+""" or newer.
-You are using Mercurial """+hgversion+""".
-
-To install a new Mercurial, visit http://mercurial.selenic.com/downloads/.
-"""
-
-linux_message = """
-You may need to clear your current Mercurial installation by running:
-
-	sudo apt-get remove mercurial mercurial-common
-	sudo rm -rf /etc/mercurial
-"""
-
-if hgversion < hg_required:
-	msg = old_message
-	if os.access("/etc/mercurial", 0):
-		msg += linux_message
-	raise hg_util.Abort(msg)
-
-from mercurial.hg import clean as hg_clean
-from mercurial import cmdutil as hg_cmdutil
-from mercurial import error as hg_error
-from mercurial import match as hg_match
-from mercurial import node as hg_node
-
-class uiwrap(object):
-	def __init__(self, ui):
-		self.ui = ui
-		ui.pushbuffer()
-		self.oldQuiet = ui.quiet
-		ui.quiet = True
-		self.oldVerbose = ui.verbose
-		ui.verbose = False
-	def output(self):
-		ui = self.ui
-		ui.quiet = self.oldQuiet
-		ui.verbose = self.oldVerbose
-		return ui.popbuffer()
-
-def to_slash(path):
-	if sys.platform == "win32":
-		return path.replace('\\', '/')
-	return path
-
-def hg_matchPattern(ui, repo, *pats, **opts):
-	w = uiwrap(ui)
-	hg_commands.status(ui, repo, *pats, **opts)
-	text = w.output()
-	ret = []
-	prefix = to_slash(os.path.realpath(repo.root))+'/'
-	for line in text.split('\n'):
-		f = line.split()
-		if len(f) > 1:
-			if len(pats) > 0:
-				# Given patterns, Mercurial shows relative to cwd
-				p = to_slash(os.path.realpath(f[1]))
-				if not p.startswith(prefix):
-					print >>sys.stderr, "File %s not in repo root %s.\n" % (p, prefix)
-				else:
-					ret.append(p[len(prefix):])
-			else:
-				# Without patterns, Mercurial shows relative to root (what we want)
-				ret.append(to_slash(f[1]))
-	return ret
-
-def hg_heads(ui, repo):
-	w = uiwrap(ui)
-	hg_commands.heads(ui, repo)
-	return w.output()
-
-noise = [
-	"",
-	"resolving manifests",
-	"searching for changes",
-	"couldn't find merge tool hgmerge",
-	"adding changesets",
-	"adding manifests",
-	"adding file changes",
-	"all local heads known remotely",
-]
-
-def isNoise(line):
-	line = str(line)
-	for x in noise:
-		if line == x:
-			return True
-	return False
-
-def hg_incoming(ui, repo):
-	w = uiwrap(ui)
-	ret = hg_commands.incoming(ui, repo, force=False, bundle="")
-	if ret and ret != 1:
-		raise hg_util.Abort(ret)
-	return w.output()
-
-def hg_log(ui, repo, **opts):
-	for k in ['date', 'keyword', 'rev', 'user']:
-		if not opts.has_key(k):
-			opts[k] = ""
-	w = uiwrap(ui)
-	ret = hg_commands.log(ui, repo, **opts)
-	if ret:
-		raise hg_util.Abort(ret)
-	return w.output()
-
-def hg_outgoing(ui, repo, **opts):
-	w = uiwrap(ui)
-	ret = hg_commands.outgoing(ui, repo, **opts)
-	if ret and ret != 1:
-		raise hg_util.Abort(ret)
-	return w.output()
-
-def hg_pull(ui, repo, **opts):
-	w = uiwrap(ui)
-	ui.quiet = False
-	ui.verbose = True  # for file list
-	err = hg_commands.pull(ui, repo, **opts)
-	for line in w.output().split('\n'):
-		if isNoise(line):
-			continue
-		if line.startswith('moving '):
-			line = 'mv ' + line[len('moving '):]
-		if line.startswith('getting ') and line.find(' to ') >= 0:
-			line = 'mv ' + line[len('getting '):]
-		if line.startswith('getting '):
-			line = '+ ' + line[len('getting '):]
-		if line.startswith('removing '):
-			line = '- ' + line[len('removing '):]
-		ui.write(line + '\n')
-	return err
-
-def hg_update(ui, repo, **opts):
-	w = uiwrap(ui)
-	ui.quiet = False
-	ui.verbose = True  # for file list
-	err = hg_commands.update(ui, repo, **opts)
-	for line in w.output().split('\n'):
-		if isNoise(line):
-			continue
-		if line.startswith('moving '):
-			line = 'mv ' + line[len('moving '):]
-		if line.startswith('getting ') and line.find(' to ') >= 0:
-			line = 'mv ' + line[len('getting '):]
-		if line.startswith('getting '):
-			line = '+ ' + line[len('getting '):]
-		if line.startswith('removing '):
-			line = '- ' + line[len('removing '):]
-		ui.write(line + '\n')
-	return err
-
-def hg_push(ui, repo, **opts):
-	w = uiwrap(ui)
-	ui.quiet = False
-	ui.verbose = True
-	err = hg_commands.push(ui, repo, **opts)
-	for line in w.output().split('\n'):
-		if not isNoise(line):
-			ui.write(line + '\n')
-	return err
-
-def hg_commit(ui, repo, *pats, **opts):
-	return hg_commands.commit(ui, repo, *pats, **opts)
-
-#######################################################################
-# Mercurial precommit hook to disable commit except through this interface.
-
-commit_okay = False
-
-def precommithook(ui, repo, **opts):
-	if hgversion >= "2.1":
-		from mercurial import phases
-		if repo.ui.config('phases', 'new-commit') >= phases.secret:
-			return False
-	if commit_okay:
-		return False  # False means okay.
-	ui.write("\ncodereview extension enabled; use mail, upload, or submit instead of commit\n\n")
-	return True
-
-#######################################################################
-# @clnumber file pattern support
-
-# We replace scmutil.match with the MatchAt wrapper to add the @clnumber pattern.
-
-match_repo = None
-match_ui = None
-match_orig = None
-
-def InstallMatch(ui, repo):
-	global match_repo
-	global match_ui
-	global match_orig
-
-	match_ui = ui
-	match_repo = repo
-
-	from mercurial import scmutil
-	match_orig = scmutil.match
-	scmutil.match = MatchAt
-
-def MatchAt(ctx, pats=None, opts=None, globbed=False, default='relpath'):
-	taken = []
-	files = []
-	pats = pats or []
-	opts = opts or {}
-	
-	for p in pats:
-		if p.startswith('@'):
-			taken.append(p)
-			clname = p[1:]
-			if clname == "default":
-				files = DefaultFiles(match_ui, match_repo, [])
-			else:
-				if not GoodCLName(clname):
-					raise hg_util.Abort("invalid CL name " + clname)
-				cl, err = LoadCL(match_repo.ui, match_repo, clname, web=False)
-				if err != '':
-					raise hg_util.Abort("loading CL " + clname + ": " + err)
-				if not cl.files:
-					raise hg_util.Abort("no files in CL " + clname)
-				files = Add(files, cl.files)
-	pats = Sub(pats, taken) + ['path:'+f for f in files]
-
-	# work-around for http://selenic.com/hg/rev/785bbc8634f8
-	if not hasattr(ctx, 'match'):
-		ctx = ctx[None]
-	return match_orig(ctx, pats=pats, opts=opts, globbed=globbed, default=default)
-
-#######################################################################
-# Commands added by code review extension.
-
-def hgcommand(f):
-	return f
-
-#######################################################################
-# hg change
-
- at hgcommand
-def change(ui, repo, *pats, **opts):
-	"""create, edit or delete a change list
-
-	Create, edit or delete a change list.
-	A change list is a group of files to be reviewed and submitted together,
-	plus a textual description of the change.
-	Change lists are referred to by simple alphanumeric names.
-
-	Changes must be reviewed before they can be submitted.
-
-	In the absence of options, the change command opens the
-	change list for editing in the default editor.
-
-	Deleting a change with the -d or -D flag does not affect
-	the contents of the files listed in that change.  To revert
-	the files listed in a change, use
-
-		hg revert @123456
-
-	before running hg change -d 123456.
-	"""
-
-	if codereview_disabled:
-		raise hg_util.Abort(codereview_disabled)
-	
-	dirty = {}
-	if len(pats) > 0 and GoodCLName(pats[0]):
-		name = pats[0]
-		if len(pats) != 1:
-			raise hg_util.Abort("cannot specify CL name and file patterns")
-		pats = pats[1:]
-		cl, err = LoadCL(ui, repo, name, web=True)
-		if err != '':
-			raise hg_util.Abort(err)
-		if not cl.local and (opts["stdin"] or not opts["stdout"]):
-			raise hg_util.Abort("cannot change non-local CL " + name)
-	else:
-		name = "new"
-		cl = CL("new")
-		if not workbranch(repo[None].branch()):
-			raise hg_util.Abort("cannot create CL outside default branch; switch with 'hg update default'")
-		dirty[cl] = True
-		files = ChangedFiles(ui, repo, pats, taken=Taken(ui, repo))
-
-	if opts["delete"] or opts["deletelocal"]:
-		if opts["delete"] and opts["deletelocal"]:
-			raise hg_util.Abort("cannot use -d and -D together")
-		flag = "-d"
-		if opts["deletelocal"]:
-			flag = "-D"
-		if name == "new":
-			raise hg_util.Abort("cannot use "+flag+" with file patterns")
-		if opts["stdin"] or opts["stdout"]:
-			raise hg_util.Abort("cannot use "+flag+" with -i or -o")
-		if not cl.local:
-			raise hg_util.Abort("cannot change non-local CL " + name)
-		if opts["delete"]:
-			if cl.copied_from:
-				raise hg_util.Abort("original author must delete CL; hg change -D will remove locally")
-			PostMessage(ui, cl.name, "*** Abandoned ***", send_mail=cl.mailed)
-			EditDesc(cl.name, closed=True, private=cl.private)
-		cl.Delete(ui, repo)
-		return
-
-	if opts["stdin"]:
-		s = sys.stdin.read()
-		clx, line, err = ParseCL(s, name)
-		if err != '':
-			raise hg_util.Abort("error parsing change list: line %d: %s" % (line, err))
-		if clx.desc is not None:
-			cl.desc = clx.desc;
-			dirty[cl] = True
-		if clx.reviewer is not None:
-			cl.reviewer = clx.reviewer
-			dirty[cl] = True
-		if clx.cc is not None:
-			cl.cc = clx.cc
-			dirty[cl] = True
-		if clx.files is not None:
-			cl.files = clx.files
-			dirty[cl] = True
-		if clx.private != cl.private:
-			cl.private = clx.private
-			dirty[cl] = True
-
-	if not opts["stdin"] and not opts["stdout"]:
-		if name == "new":
-			cl.files = files
-		err = EditCL(ui, repo, cl)
-		if err != "":
-			raise hg_util.Abort(err)
-		dirty[cl] = True
-
-	for d, _ in dirty.items():
-		name = d.name
-		d.Flush(ui, repo)
-		if name == "new":
-			d.Upload(ui, repo, quiet=True)
-
-	if opts["stdout"]:
-		ui.write(cl.EditorText())
-	elif opts["pending"]:
-		ui.write(cl.PendingText())
-	elif name == "new":
-		if ui.quiet:
-			ui.write(cl.name)
-		else:
-			ui.write("CL created: " + cl.url + "\n")
-	return
-
-#######################################################################
-# hg code-login (broken?)
-
- at hgcommand
-def code_login(ui, repo, **opts):
-	"""log in to code review server
-
-	Logs in to the code review server, saving a cookie in
-	a file in your home directory.
-	"""
-	if codereview_disabled:
-		raise hg_util.Abort(codereview_disabled)
-
-	MySend(None)
-
-#######################################################################
-# hg clpatch / undo / release-apply / download
-# All concerned with applying or unapplying patches to the repository.
-
- at hgcommand
-def clpatch(ui, repo, clname, **opts):
-	"""import a patch from the code review server
-
-	Imports a patch from the code review server into the local client.
-	If the local client has already modified any of the files that the
-	patch modifies, this command will refuse to apply the patch.
-
-	Submitting an imported patch will keep the original author's
-	name as the Author: line but add your own name to a Committer: line.
-	"""
-	if not workbranch(repo[None].branch()):
-		raise hg_util.Abort("cannot run hg clpatch outside default branch")
-	err = clpatch_or_undo(ui, repo, clname, opts, mode="clpatch")
-	if err:
-		raise hg_util.Abort(err)
-
- at hgcommand
-def undo(ui, repo, clname, **opts):
-	"""undo the effect of a CL
-	
-	Creates a new CL that undoes an earlier CL.
-	After creating the CL, opens the CL text for editing so that
-	you can add the reason for the undo to the description.
-	"""
-	if not workbranch(repo[None].branch()):
-		raise hg_util.Abort("cannot run hg undo outside default branch")
-	err = clpatch_or_undo(ui, repo, clname, opts, mode="undo")
-	if err:
-		raise hg_util.Abort(err)
-
- at hgcommand
-def release_apply(ui, repo, clname, **opts):
-	"""apply a CL to the release branch
-
-	Creates a new CL copying a previously committed change
-	from the main branch to the release branch.
-	The current client must either be clean or already be in
-	the release branch.
-	
-	The release branch must be created by starting with a
-	clean client, disabling the code review plugin, and running:
-	
-		hg update weekly.YYYY-MM-DD
-		hg branch release-branch.rNN
-		hg commit -m 'create release-branch.rNN'
-		hg push --new-branch
-	
-	Then re-enable the code review plugin.
-	
-	People can test the release branch by running
-	
-		hg update release-branch.rNN
-	
-	in a clean client.  To return to the normal tree,
-	
-		hg update default
-	
-	Move changes since the weekly into the release branch 
-	using hg release-apply followed by the usual code review
-	process and hg submit.
-
-	When it comes time to tag the release, record the
-	final long-form tag of the release-branch.rNN
-	in the *default* branch's .hgtags file.  That is, run
-	
-		hg update default
-	
-	and then edit .hgtags as you would for a weekly.
-		
-	"""
-	c = repo[None]
-	if not releaseBranch:
-		raise hg_util.Abort("no active release branches")
-	if c.branch() != releaseBranch:
-		if c.modified() or c.added() or c.removed():
-			raise hg_util.Abort("uncommitted local changes - cannot switch branches")
-		err = hg_clean(repo, releaseBranch)
-		if err:
-			raise hg_util.Abort(err)
-	try:
-		err = clpatch_or_undo(ui, repo, clname, opts, mode="backport")
-		if err:
-			raise hg_util.Abort(err)
-	except Exception, e:
-		hg_clean(repo, "default")
-		raise e
-
-def rev2clname(rev):
-	# Extract CL name from revision description.
-	# The last line in the description that is a codereview URL is the real one.
-	# Earlier lines might be part of the user-written description.
-	all = re.findall('(?m)^https?://codereview.appspot.com/([0-9]+)$', rev.description())
-	if len(all) > 0:
-		return all[-1]
-	return ""
-
-undoHeader = """undo CL %s / %s
-
-<enter reason for undo>
-
-««« original CL description
-"""
-
-undoFooter = """
-»»»
-"""
-
-backportHeader = """[%s] %s
-
-««« CL %s / %s
-"""
-
-backportFooter = """
-»»»
-"""
-
-# Implementation of clpatch/undo.
-def clpatch_or_undo(ui, repo, clname, opts, mode):
-	if codereview_disabled:
-		return codereview_disabled
-
-	if mode == "undo" or mode == "backport":
-		# Find revision in Mercurial repository.
-		# Assume CL number is 7+ decimal digits.
-		# Otherwise is either change log sequence number (fewer decimal digits),
-		# hexadecimal hash, or tag name.
-		# Mercurial will fall over long before the change log
-		# sequence numbers get to be 7 digits long.
-		if re.match('^[0-9]{7,}$', clname):
-			found = False
-			for r in hg_log(ui, repo, keyword="codereview.appspot.com/"+clname, limit=100, template="{node}\n").split():
-				rev = repo[r]
-				# Last line with a code review URL is the actual review URL.
-				# Earlier ones might be part of the CL description.
-				n = rev2clname(rev)
-				if n == clname:
-					found = True
-					break
-			if not found:
-				return "cannot find CL %s in local repository" % clname
-		else:
-			rev = repo[clname]
-			if not rev:
-				return "unknown revision %s" % clname
-			clname = rev2clname(rev)
-			if clname == "":
-				return "cannot find CL name in revision description"
-		
-		# Create fresh CL and start with patch that would reverse the change.
-		vers = hg_node.short(rev.node())
-		cl = CL("new")
-		desc = str(rev.description())
-		if mode == "undo":
-			cl.desc = (undoHeader % (clname, vers)) + desc + undoFooter
-		else:
-			cl.desc = (backportHeader % (releaseBranch, line1(desc), clname, vers)) + desc + undoFooter
-		v1 = vers
-		v0 = hg_node.short(rev.parents()[0].node())
-		if mode == "undo":
-			arg = v1 + ":" + v0
-		else:
-			vers = v0
-			arg = v0 + ":" + v1
-		patch = RunShell(["hg", "diff", "--git", "-r", arg])
-
-	else:  # clpatch
-		cl, vers, patch, err = DownloadCL(ui, repo, clname)
-		if err != "":
-			return err
-		if patch == emptydiff:
-			return "codereview issue %s has no diff" % clname
-
-	# find current hg version (hg identify)
-	ctx = repo[None]
-	parents = ctx.parents()
-	id = '+'.join([hg_node.short(p.node()) for p in parents])
-
-	# if version does not match the patch version,
-	# try to update the patch line numbers.
-	if vers != "" and id != vers:
-		# "vers in repo" gives the wrong answer
-		# on some versions of Mercurial.  Instead, do the actual
-		# lookup and catch the exception.
-		try:
-			repo[vers].description()
-		except:
-			return "local repository is out of date; sync to get %s" % (vers)
-		patch1, err = portPatch(repo, patch, vers, id)
-		if err != "":
-			if not opts["ignore_hgapplydiff_failure"]:
-				return "codereview issue %s is out of date: %s (%s->%s)" % (clname, err, vers, id)
-		else:
-			patch = patch1
-	argv = ["hgapplydiff"]
-	if opts["no_incoming"] or mode == "backport":
-		argv += ["--checksync=false"]
-	try:
-		cmd = subprocess.Popen(argv, shell=False, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=None, close_fds=sys.platform != "win32")
-	except:
-		return "hgapplydiff: " + ExceptionDetail() + "\nInstall hgapplydiff with:\n$ go get golang.org/x/codereview/cmd/hgapplydiff\n"
-
-	out, err = cmd.communicate(patch)
-	if cmd.returncode != 0 and not opts["ignore_hgapplydiff_failure"]:
-		return "hgapplydiff failed"
-	cl.local = True
-	cl.files = out.strip().split()
-	if not cl.files and not opts["ignore_hgapplydiff_failure"]:
-		return "codereview issue %s has no changed files" % clname
-	files = ChangedFiles(ui, repo, [])
-	extra = Sub(cl.files, files)
-	if extra:
-		ui.warn("warning: these files were listed in the patch but not changed:\n\t" + "\n\t".join(extra) + "\n")
-	cl.Flush(ui, repo)
-	if mode == "undo":
-		err = EditCL(ui, repo, cl)
-		if err != "":
-			return "CL created, but error editing: " + err
-		cl.Flush(ui, repo)
-	else:
-		ui.write(cl.PendingText() + "\n")
-
-# portPatch rewrites patch from being a patch against
-# oldver to being a patch against newver.
-def portPatch(repo, patch, oldver, newver):
-	lines = patch.splitlines(True) # True = keep \n
-	delta = None
-	for i in range(len(lines)):
-		line = lines[i]
-		if line.startswith('--- a/'):
-			file = line[6:-1]
-			delta = fileDeltas(repo, file, oldver, newver)
-		if not delta or not line.startswith('@@ '):
-			continue
-		# @@ -x,y +z,w @@ means the patch chunk replaces
-		# the original file's line numbers x up to x+y with the
-		# line numbers z up to z+w in the new file.
-		# Find the delta from x in the original to the same
-		# line in the current version and add that delta to both
-		# x and z.
-		m = re.match('@@ -([0-9]+),([0-9]+) \+([0-9]+),([0-9]+) @@', line)
-		if not m:
-			return None, "error parsing patch line numbers"
-		n1, len1, n2, len2 = int(m.group(1)), int(m.group(2)), int(m.group(3)), int(m.group(4))
-		d, err = lineDelta(delta, n1, len1)
-		if err != "":
-			return "", err
-		n1 += d
-		n2 += d
-		lines[i] = "@@ -%d,%d +%d,%d @@\n" % (n1, len1, n2, len2)
-		
-	newpatch = ''.join(lines)
-	return newpatch, ""
-
-# fileDelta returns the line number deltas for the given file's
-# changes from oldver to newver.
-# The deltas are a list of (n, len, newdelta) triples that say
-# lines [n, n+len) were modified, and after that range the
-# line numbers are +newdelta from what they were before.
-def fileDeltas(repo, file, oldver, newver):
-	cmd = ["hg", "diff", "--git", "-r", oldver + ":" + newver, "path:" + file]
-	data = RunShell(cmd, silent_ok=True)
-	deltas = []
-	for line in data.splitlines():
-		m = re.match('@@ -([0-9]+),([0-9]+) \+([0-9]+),([0-9]+) @@', line)
-		if not m:
-			continue
-		n1, len1, n2, len2 = int(m.group(1)), int(m.group(2)), int(m.group(3)), int(m.group(4))
-		deltas.append((n1, len1, n2+len2-(n1+len1)))
-	return deltas
-
-# lineDelta finds the appropriate line number delta to apply to the lines [n, n+len).
-# It returns an error if those lines were rewritten by the patch.
-def lineDelta(deltas, n, len):
-	d = 0
-	for (old, oldlen, newdelta) in deltas:
-		if old >= n+len:
-			break
-		if old+len > n:
-			return 0, "patch and recent changes conflict"
-		d = newdelta
-	return d, ""
-
- at hgcommand
-def download(ui, repo, clname, **opts):
-	"""download a change from the code review server
-
-	Download prints a description of the given change list
-	followed by its diff, downloaded from the code review server.
-	"""
-	if codereview_disabled:
-		raise hg_util.Abort(codereview_disabled)
-
-	cl, vers, patch, err = DownloadCL(ui, repo, clname)
-	if err != "":
-		return err
-	ui.write(cl.EditorText() + "\n")
-	ui.write(patch + "\n")
-	return
-
-#######################################################################
-# hg file
-
- at hgcommand
-def file(ui, repo, clname, pat, *pats, **opts):
-	"""assign files to or remove files from a change list
-
-	Assign files to or (with -d) remove files from a change list.
-
-	The -d option only removes files from the change list.
-	It does not edit them or remove them from the repository.
-	"""
-	if codereview_disabled:
-		raise hg_util.Abort(codereview_disabled)
-
-	pats = tuple([pat] + list(pats))
-	if not GoodCLName(clname):
-		return "invalid CL name " + clname
-
-	dirty = {}
-	cl, err = LoadCL(ui, repo, clname, web=False)
-	if err != '':
-		return err
-	if not cl.local:
-		return "cannot change non-local CL " + clname
-
-	files = ChangedFiles(ui, repo, pats)
-
-	if opts["delete"]:
-		oldfiles = Intersect(files, cl.files)
-		if oldfiles:
-			if not ui.quiet:
-				ui.status("# Removing files from CL.  To undo:\n")
-				ui.status("#	cd %s\n" % (repo.root))
-				for f in oldfiles:
-					ui.status("#	hg file %s %s\n" % (cl.name, f))
-			cl.files = Sub(cl.files, oldfiles)
-			cl.Flush(ui, repo)
-		else:
-			ui.status("no such files in CL")
-		return
-
-	if not files:
-		return "no such modified files"
-
-	files = Sub(files, cl.files)
-	taken = Taken(ui, repo)
-	warned = False
-	for f in files:
-		if f in taken:
-			if not warned and not ui.quiet:
-				ui.status("# Taking files from other CLs.  To undo:\n")
-				ui.status("#	cd %s\n" % (repo.root))
-				warned = True
-			ocl = taken[f]
-			if not ui.quiet:
-				ui.status("#	hg file %s %s\n" % (ocl.name, f))
-			if ocl not in dirty:
-				ocl.files = Sub(ocl.files, files)
-				dirty[ocl] = True
-	cl.files = Add(cl.files, files)
-	dirty[cl] = True
-	for d, _ in dirty.items():
-		d.Flush(ui, repo)
-	return
-
-#######################################################################
-# hg gofmt
-
- at hgcommand
-def gofmt(ui, repo, *pats, **opts):
-	"""apply gofmt to modified files
-
-	Applies gofmt to the modified files in the repository that match
-	the given patterns.
-	"""
-	if codereview_disabled:
-		raise hg_util.Abort(codereview_disabled)
-
-	files = ChangedExistingFiles(ui, repo, pats, opts)
-	files = gofmt_required(files)
-	if not files:
-		ui.status("no modified go files\n")
-		return
-	cwd = os.getcwd()
-	files = [RelativePath(repo.root + '/' + f, cwd) for f in files]
-	try:
-		cmd = ["gofmt", "-l"]
-		if not opts["list"]:
-			cmd += ["-w"]
-		if subprocess.call(cmd + files) != 0:
-			raise hg_util.Abort("gofmt did not exit cleanly")
-	except hg_error.Abort, e:
-		raise
-	except:
-		raise hg_util.Abort("gofmt: " + ExceptionDetail())
-	return
-
-def gofmt_required(files):
-	return [f for f in files if (not f.startswith('test/') or f.startswith('test/bench/')) and f.endswith('.go')]
-
-#######################################################################
-# hg mail
-
- at hgcommand
-def mail(ui, repo, *pats, **opts):
-	"""mail a change for review
-
-	Uploads a patch to the code review server and then sends mail
-	to the reviewer and CC list asking for a review.
-	"""
-	if codereview_disabled:
-		raise hg_util.Abort(codereview_disabled)
-
-	cl, err = CommandLineCL(ui, repo, pats, opts, op="mail", defaultcc=defaultcc)
-	if err != "":
-		raise hg_util.Abort(err)
-	cl.Upload(ui, repo, gofmt_just_warn=True)
-	if not cl.reviewer:
-		# If no reviewer is listed, assign the review to defaultcc.
-		# This makes sure that it appears in the 
-		# codereview.appspot.com/user/defaultcc
-		# page, so that it doesn't get dropped on the floor.
-		if not defaultcc or cl.private:
-			raise hg_util.Abort("no reviewers listed in CL")
-		cl.cc = Sub(cl.cc, defaultcc)
-		cl.reviewer = defaultcc
-		cl.Flush(ui, repo)
-
-	if cl.files == []:
-			raise hg_util.Abort("no changed files, not sending mail")
-
-	cl.Mail(ui, repo)
-
-#######################################################################
-# hg p / hg pq / hg ps / hg pending
-
- at hgcommand
-def ps(ui, repo, *pats, **opts):
-	"""alias for hg p --short
-	"""
-	opts['short'] = True
-	return pending(ui, repo, *pats, **opts)
-
- at hgcommand
-def pq(ui, repo, *pats, **opts):
-	"""alias for hg p --quick
-	"""
-	opts['quick'] = True
-	return pending(ui, repo, *pats, **opts)
-
- at hgcommand
-def pending(ui, repo, *pats, **opts):
-	"""show pending changes
-
-	Lists pending changes followed by a list of unassigned but modified files.
-	"""
-	if codereview_disabled:
-		raise hg_util.Abort(codereview_disabled)
-
-	quick = opts.get('quick', False)
-	short = opts.get('short', False)
-	m = LoadAllCL(ui, repo, web=not quick and not short)
-	names = m.keys()
-	names.sort()
-	for name in names:
-		cl = m[name]
-		if short:
-			ui.write(name + "\t" + line1(cl.desc) + "\n")
-		else:
-			ui.write(cl.PendingText(quick=quick) + "\n")
-
-	if short:
-		return 0
-	files = DefaultFiles(ui, repo, [])
-	if len(files) > 0:
-		s = "Changed files not in any CL:\n"
-		for f in files:
-			s += "\t" + f + "\n"
-		ui.write(s)
-
-#######################################################################
-# hg submit
-
-def need_sync():
-	raise hg_util.Abort("local repository out of date; must sync before submit")
-
-def branch_prefix(ui, repo):
-	prefix = ""
-	branch = repo[None].branch()
-	if workbranch(branch) and branch != "default":
-		prefix = "[" + branch + "] "
-	return prefix
-
- at hgcommand
-def submit(ui, repo, *pats, **opts):
-	"""submit change to remote repository
-
-	Submits change to remote repository.
-	Bails out if the local repository is not in sync with the remote one.
-	"""
-	if codereview_disabled:
-		raise hg_util.Abort(codereview_disabled)
-
-	# We already called this on startup but sometimes Mercurial forgets.
-	set_mercurial_encoding_to_utf8()
-
-	if not opts["no_incoming"] and hg_incoming(ui, repo):
-		need_sync()
-
-	cl, err = CommandLineCL(ui, repo, pats, opts, op="submit", defaultcc=defaultcc)
-	if err != "":
-		raise hg_util.Abort(err)
-
-	user = None
-	if cl.copied_from:
-		user = cl.copied_from
-	userline = CheckContributor(ui, repo, user)
-	typecheck(userline, str)
-
-	about = ""
-
-	if not cl.lgtm and not opts.get('tbr') and needLGTM(cl):
-		raise hg_util.Abort("this CL has not been LGTM'ed")
-	if cl.lgtm:
-		about += "LGTM=" + JoinComma([CutDomain(who) for (who, line, approval) in cl.lgtm if approval]) + "\n"
-	reviewer = cl.reviewer
-	if opts.get('tbr'):
-		tbr = SplitCommaSpace(opts.get('tbr'))
-		for name in tbr:
-			if name.startswith('golang-'):
-				raise hg_util.Abort("--tbr requires a person, not a mailing list")
-		cl.reviewer = Add(cl.reviewer, tbr)
-		about += "TBR=" + JoinComma([CutDomain(s) for s in tbr]) + "\n"
-	if reviewer:
-		about += "R=" + JoinComma([CutDomain(s) for s in reviewer]) + "\n"
-	if cl.cc:
-		about += "CC=" + JoinComma([CutDomain(s) for s in cl.cc]) + "\n"
-
-	if not cl.reviewer and needLGTM(cl):
-		raise hg_util.Abort("no reviewers listed in CL")
-
-	if not cl.local:
-		raise hg_util.Abort("cannot submit non-local CL")
-
-	# upload, to sync current patch and also get change number if CL is new.
-	if not cl.copied_from:
-		cl.Upload(ui, repo, gofmt_just_warn=True)
-
-	# check gofmt for real; allowed upload to warn in order to save CL.
-	cl.Flush(ui, repo)
-	CheckFormat(ui, repo, cl.files)
-
-	about += "%s%s\n" % (server_url_base, cl.name)
-
-	if cl.copied_from:
-		about += "\nCommitter: " + CheckContributor(ui, repo, None) + "\n"
-	typecheck(about, str)
-
-	if not cl.mailed and not cl.copied_from:		# in case this is TBR
-		cl.Mail(ui, repo)
-
-	# submit changes locally
-	message = branch_prefix(ui, repo) + cl.desc.rstrip() + "\n\n" + about
-	typecheck(message, str)
-
-	set_status("pushing " + cl.name + " to remote server")
-
-	if hg_outgoing(ui, repo):
-		raise hg_util.Abort("local repository corrupt or out-of-phase with remote: found outgoing changes")
-	
-	old_heads = len(hg_heads(ui, repo).split())
-
-	# Normally we commit listing the specific files in the CL.
-	# If there are no changed files other than those in the CL, however,
-	# let hg build the list, because then committing a merge works.
-	# (You cannot name files for a merge commit, even if you name
-	# all the files that would be committed by not naming any.)
-	files = ['path:'+f for f in cl.files]
-	if ChangedFiles(ui, repo, []) == cl.files:
-		files = []
-
-	global commit_okay
-	commit_okay = True
-	ret = hg_commit(ui, repo, *files, message=message, user=userline)
-	commit_okay = False
-	if ret:
-		raise hg_util.Abort("nothing changed")
-
-	node = repo["-1"].node()
-	# push to remote; if it fails for any reason, roll back
-	try:
-		new_heads = len(hg_heads(ui, repo).split())
-		if old_heads != new_heads and not (old_heads == 0 and new_heads == 1):
-			# Created new head, so we weren't up to date.
-			need_sync()
-
-		# Push changes to remote.  If it works, we're committed.  If not, roll back.
-		try:
-			if hg_push(ui, repo):
-				raise hg_util.Abort("push error")
-		except hg_error.Abort, e:
-			if e.message.find("push creates new heads") >= 0:
-				# Remote repository had changes we missed.
-				need_sync()
-			raise
-		except urllib2.HTTPError, e:
-			print >>sys.stderr, "pushing to remote server failed; do you have commit permissions?"
-			raise
-	except:
-		real_rollback()
-		raise
-
-	# We're committed. Upload final patch, close review, add commit message.
-	changeURL = hg_node.short(node)
-	url = ui.expandpath("default")
-	m = re.match("(^https?://([^@/]+@)?([^.]+)\.googlecode\.com/hg/?)" + "|" +
-		"(^https?://([^@/]+@)?code\.google\.com/p/([^/.]+)(\.[^./]+)?/?)", url)
-	if m:
-		if m.group(1): # prj.googlecode.com/hg/ case
-			changeURL = "https://code.google.com/p/%s/source/detail?r=%s" % (m.group(3), changeURL)
-		elif m.group(4) and m.group(7): # code.google.com/p/prj.subrepo/ case
-			changeURL = "https://code.google.com/p/%s/source/detail?r=%s&repo=%s" % (m.group(6), changeURL, m.group(7)[1:])
-		elif m.group(4): # code.google.com/p/prj/ case
-			changeURL = "https://code.google.com/p/%s/source/detail?r=%s" % (m.group(6), changeURL)
-		else:
-			print >>sys.stderr, "URL: ", url
-	else:
-		print >>sys.stderr, "URL: ", url
-	pmsg = "*** Submitted as " + changeURL + " ***\n\n" + message
-
-	# When posting, move reviewers to CC line,
-	# so that the issue stops showing up in their "My Issues" page.
-	PostMessage(ui, cl.name, pmsg, reviewers="", cc=JoinComma(cl.reviewer+cl.cc))
-
-	if not cl.copied_from:
-		EditDesc(cl.name, closed=True, private=cl.private)
-	cl.Delete(ui, repo)
-
-	c = repo[None]
-	if c.branch() == releaseBranch and not c.modified() and not c.added() and not c.removed():
-		ui.write("switching from %s to default branch.\n" % releaseBranch)
-		err = hg_clean(repo, "default")
-		if err:
-			return err
-	return 0
-
-def needLGTM(cl):
-	rev = cl.reviewer
-	isGobot = 'gobot' in rev or 'gobot at swtch.com' in rev or 'gobot at golang.org' in rev
-	
-	# A+C CLs generated by addca do not need LGTM
-	if cl.desc.startswith('A+C:') and 'Generated by a+c.' in cl.desc and isGobot:
-		return False
-	
-	# CLs modifying only go1.x.txt do not need LGTM
-	if len(cl.files) == 1 and cl.files[0].startswith('doc/go1.') and cl.files[0].endswith('.txt'):
-		return False
-	
-	# Other CLs need LGTM
-	return True
-
-#######################################################################
-# hg sync
-
- at hgcommand
-def sync(ui, repo, **opts):
-	"""synchronize with remote repository
-
-	Incorporates recent changes from the remote repository
-	into the local repository.
-	"""
-	if codereview_disabled:
-		raise hg_util.Abort(codereview_disabled)
-
-	if not opts["local"]:
-		# If there are incoming CLs, pull -u will do the update.
-		# If there are no incoming CLs, do hg update to make sure
-		# that an update always happens regardless. This is less
-		# surprising than update depending on incoming CLs.
-		# It is important not to do both hg pull -u and hg update
-		# in the same command, because the hg update will end
-		# up marking resolve conflicts from the hg pull -u as resolved,
-		# causing files with <<< >>> markers to not show up in 
-		# hg resolve -l. Yay Mercurial.
-		if hg_incoming(ui, repo):
-			err = hg_pull(ui, repo, update=True)
-		else:
-			err = hg_update(ui, repo)
-		if err:
-			return err
-	sync_changes(ui, repo)
-
-def sync_changes(ui, repo):
-	# Look through recent change log descriptions to find
-	# potential references to http://.*/our-CL-number.
-	# Double-check them by looking at the Rietveld log.
-	for rev in hg_log(ui, repo, limit=100, template="{node}\n").split():
-		desc = repo[rev].description().strip()
-		for clname in re.findall('(?m)^https?://(?:[^\n]+)/([0-9]+)$', desc):
-			if IsLocalCL(ui, repo, clname) and IsRietveldSubmitted(ui, clname, repo[rev].hex()):
-				ui.warn("CL %s submitted as %s; closing\n" % (clname, repo[rev]))
-				cl, err = LoadCL(ui, repo, clname, web=False)
-				if err != "":
-					ui.warn("loading CL %s: %s\n" % (clname, err))
-					continue
-				if not cl.copied_from:
-					EditDesc(cl.name, closed=True, private=cl.private)
-				cl.Delete(ui, repo)
-
-	# Remove files that are not modified from the CLs in which they appear.
-	all = LoadAllCL(ui, repo, web=False)
-	changed = ChangedFiles(ui, repo, [])
-	for cl in all.values():
-		extra = Sub(cl.files, changed)
-		if extra:
-			ui.warn("Removing unmodified files from CL %s:\n" % (cl.name,))
-			for f in extra:
-				ui.warn("\t%s\n" % (f,))
-			cl.files = Sub(cl.files, extra)
-			cl.Flush(ui, repo)
-		if not cl.files:
-			if not cl.copied_from:
-				ui.warn("CL %s has no files; delete (abandon) with hg change -d %s\n" % (cl.name, cl.name))
-			else:
-				ui.warn("CL %s has no files; delete locally with hg change -D %s\n" % (cl.name, cl.name))
-	return 0
-
-#######################################################################
-# hg upload
-
- at hgcommand
-def upload(ui, repo, name, **opts):
-	"""upload diffs to the code review server
-
-	Uploads the current modifications for a given change to the server.
-	"""
-	if codereview_disabled:
-		raise hg_util.Abort(codereview_disabled)
-
-	repo.ui.quiet = True
-	cl, err = LoadCL(ui, repo, name, web=True)
-	if err != "":
-		raise hg_util.Abort(err)
-	if not cl.local:
-		raise hg_util.Abort("cannot upload non-local change")
-	cl.Upload(ui, repo)
-	print "%s%s\n" % (server_url_base, cl.name)
-	return 0
-
-#######################################################################
-# Table of commands, supplied to Mercurial for installation.
-
-review_opts = [
-	('r', 'reviewer', '', 'add reviewer'),
-	('', 'cc', '', 'add cc'),
-	('', 'tbr', '', 'add future reviewer'),
-	('m', 'message', '', 'change description (for new change)'),
-]
-
-cmdtable = {
-	# The ^ means to show this command in the help text that
-	# is printed when running hg with no arguments.
-	"^change": (
-		change,
-		[
-			('d', 'delete', None, 'delete existing change list'),
-			('D', 'deletelocal', None, 'delete locally, but do not change CL on server'),
-			('i', 'stdin', None, 'read change list from standard input'),
-			('o', 'stdout', None, 'print change list to standard output'),
-			('p', 'pending', None, 'print pending summary to standard output'),
-		],
-		"[-d | -D] [-i] [-o] change# or FILE ..."
-	),
-	"^clpatch": (
-		clpatch,
-		[
-			('', 'ignore_hgapplydiff_failure', None, 'create CL metadata even if hgapplydiff fails'),
-			('', 'no_incoming', None, 'disable check for incoming changes'),
-		],
-		"change#"
-	),
-	# Would prefer to call this codereview-login, but then
-	# hg help codereview prints the help for this command
-	# instead of the help for the extension.
-	"code-login": (
-		code_login,
-		[],
-		"",
-	),
-	"^download": (
-		download,
-		[],
-		"change#"
-	),
-	"^file": (
-		file,
-		[
-			('d', 'delete', None, 'delete files from change list (but not repository)'),
-		],
-		"[-d] change# FILE ..."
-	),
-	"^gofmt": (
-		gofmt,
-		[
-			('l', 'list', None, 'list files that would change, but do not edit them'),
-		],
-		"FILE ..."
-	),
-	"^pending|p": (
-		pending,
-		[
-			('s', 'short', False, 'show short result form'),
-			('', 'quick', False, 'do not consult codereview server'),
-		],
-		"[FILE ...]"
-	),
-	"^ps": (
-		ps,
-		[],
-		"[FILE ...]"
-	),
-	"^pq": (
-		pq,
-		[],
-		"[FILE ...]"
-	),
-	"^mail": (
-		mail,
-		review_opts + [
-		] + hg_commands.walkopts,
-		"[-r reviewer] [--cc cc] [change# | file ...]"
-	),
-	"^release-apply": (
-		release_apply,
-		[
-			('', 'ignore_hgapplydiff_failure', None, 'create CL metadata even if hgapplydiff fails'),
-			('', 'no_incoming', None, 'disable check for incoming changes'),
-		],
-		"change#"
-	),
-	# TODO: release-start, release-tag, weekly-tag
-	"^submit": (
-		submit,
-		review_opts + [
-			('', 'no_incoming', None, 'disable initial incoming check (for testing)'),
-		] + hg_commands.walkopts + hg_commands.commitopts + hg_commands.commitopts2,
-		"[-r reviewer] [--cc cc] [change# | file ...]"
-	),
-	"^sync": (
-		sync,
-		[
-			('', 'local', None, 'do not pull changes from remote repository')
-		],
-		"[--local]",
-	),
-	"^undo": (
-		undo,
-		[
-			('', 'ignore_hgapplydiff_failure', None, 'create CL metadata even if hgapplydiff fails'),
-			('', 'no_incoming', None, 'disable check for incoming changes'),
-		],
-		"change#"
-	),
-	"^upload": (
-		upload,
-		[],
-		"change#"
-	),
-}
-
-#######################################################################
-# Mercurial extension initialization
-
-def norollback(*pats, **opts):
-	"""(disabled when using this extension)"""
-	raise hg_util.Abort("codereview extension enabled; use undo instead of rollback")
-
-codereview_init = False
-
-def uisetup(ui):
-	global testing
-	testing = ui.config("codereview", "testing")
-	# Disable the Mercurial commands that might change the repository.
-	# Only commands in this extension are supposed to do that.
-	ui.setconfig("hooks", "pre-commit.codereview", precommithook) # runs before 'hg commit'
-	ui.setconfig("hooks", "precommit.codereview", precommithook) # catches all cases
-
-def reposetup(ui, repo):
-	global codereview_disabled
-	global defaultcc
-	
-	# reposetup gets called both for the local repository
-	# and also for any repository we are pulling or pushing to.
-	# Only initialize the first time.
-	global codereview_init
-	if codereview_init:
-		return
-	codereview_init = True
-	start_status_thread()
-
-	# Read repository-specific options from lib/codereview/codereview.cfg or codereview.cfg.
-	root = ''
-	try:
-		root = repo.root
-	except:
-		# Yes, repo might not have root; see issue 959.
-		codereview_disabled = 'codereview disabled: repository has no root'
-		return
-	
-	repo_config_path = ''
-	p1 = root + '/lib/codereview/codereview.cfg'
-	p2 = root + '/codereview.cfg'
-	if os.access(p1, os.F_OK):
-		repo_config_path = p1
-	else:
-		repo_config_path = p2
-	try:
-		f = open(repo_config_path)
-		for line in f:
-			if line.startswith('defaultcc:'):
-				defaultcc = SplitCommaSpace(line[len('defaultcc:'):])
-			if line.startswith('contributors:'):
-				global contributorsURL
-				contributorsURL = line[len('contributors:'):].strip()
-	except:
-		codereview_disabled = 'codereview disabled: cannot open ' + repo_config_path
-		return
-
-	remote = ui.config("paths", "default", "")
-	if remote.find("://") < 0 and not testing:
-		raise hg_util.Abort("codereview: default path '%s' is not a URL" % (remote,))
-
-	InstallMatch(ui, repo)
-	RietveldSetup(ui, repo)
-
-	# Rollback removes an existing commit.  Don't do that either.
-	global real_rollback
-	real_rollback = repo.rollback
-	repo.rollback = norollback
-	
-
-#######################################################################
-# Wrappers around upload.py for interacting with Rietveld
-
-from HTMLParser import HTMLParser
-
-# HTML form parser
-class FormParser(HTMLParser):
-	def __init__(self):
-		self.map = {}
-		self.curtag = None
-		self.curdata = None
-		HTMLParser.__init__(self)
-	def handle_starttag(self, tag, attrs):
-		if tag == "input":
-			key = None
-			value = ''
-			for a in attrs:
-				if a[0] == 'name':
-					key = a[1]
-				if a[0] == 'value':
-					value = a[1]
-			if key is not None:
-				self.map[key] = value
-		if tag == "textarea":
-			key = None
-			for a in attrs:
-				if a[0] == 'name':
-					key = a[1]
-			if key is not None:
-				self.curtag = key
-				self.curdata = ''
-	def handle_endtag(self, tag):
-		if tag == "textarea" and self.curtag is not None:
-			self.map[self.curtag] = self.curdata
-			self.curtag = None
-			self.curdata = None
-	def handle_charref(self, name):
-		self.handle_data(unichr(int(name)))
-	def handle_entityref(self, name):
-		import htmlentitydefs
-		if name in htmlentitydefs.entitydefs:
-			self.handle_data(htmlentitydefs.entitydefs[name])
-		else:
-			self.handle_data("&" + name + ";")
-	def handle_data(self, data):
-		if self.curdata is not None:
-			self.curdata += data
-
-def JSONGet(ui, path):
-	try:
-		data = MySend(path, force_auth=False)
-		typecheck(data, str)
-		d = fix_json(json.loads(data))
-	except:
-		ui.warn("JSONGet %s: %s\n" % (path, ExceptionDetail()))
-		return None
-	return d
-
-# Clean up json parser output to match our expectations:
-#   * all strings are UTF-8-encoded str, not unicode.
-#   * missing fields are missing, not None,
-#     so that d.get("foo", defaultvalue) works.
-def fix_json(x):
-	if type(x) in [str, int, float, bool, type(None)]:
-		pass
-	elif type(x) is unicode:
-		x = x.encode("utf-8")
-	elif type(x) is list:
-		for i in range(len(x)):
-			x[i] = fix_json(x[i])
-	elif type(x) is dict:
-		todel = []
-		for k in x:
-			if x[k] is None:
-				todel.append(k)
-			else:
-				x[k] = fix_json(x[k])
-		for k in todel:
-			del x[k]
-	else:
-		raise hg_util.Abort("unknown type " + str(type(x)) + " in fix_json")
-	if type(x) is str:
-		x = x.replace('\r\n', '\n')
-	return x
-
-def IsRietveldSubmitted(ui, clname, hex):
-	dict = JSONGet(ui, "/api/" + clname + "?messages=true")
-	if dict is None:
-		return False
-	for msg in dict.get("messages", []):
-		text = msg.get("text", "")
-		regex = '\*\*\* Submitted as [^*]*?r=([0-9a-f]+)[^ ]* \*\*\*'
-		if testing:
-			regex = '\*\*\* Submitted as ([0-9a-f]+) \*\*\*'
-		m = re.match(regex, text)
-		if m is not None and len(m.group(1)) >= 8 and hex.startswith(m.group(1)):
-			return True
-	return False
-
-def IsRietveldMailed(cl):
-	for msg in cl.dict.get("messages", []):
-		if msg.get("text", "").find("I'd like you to review this change") >= 0:
-			return True
-	return False
-
-def DownloadCL(ui, repo, clname):
-	set_status("downloading CL " + clname)
-	cl, err = LoadCL(ui, repo, clname, web=True)
-	if err != "":
-		return None, None, None, "error loading CL %s: %s" % (clname, err)
-
-	# Find most recent diff
-	diffs = cl.dict.get("patchsets", [])
-	if not diffs:
-		return None, None, None, "CL has no patch sets"
-	patchid = diffs[-1]
-
-	patchset = JSONGet(ui, "/api/" + clname + "/" + str(patchid))
-	if patchset is None:
-		return None, None, None, "error loading CL patchset %s/%d" % (clname, patchid)
-	if patchset.get("patchset", 0) != patchid:
-		return None, None, None, "malformed patchset information"
-	
-	vers = ""
-	msg = patchset.get("message", "").split()
-	if len(msg) >= 3 and msg[0] == "diff" and msg[1] == "-r":
-		vers = msg[2]
-	diff = "/download/issue" + clname + "_" + str(patchid) + ".diff"
-
-	diffdata = MySend(diff, force_auth=False)
-	
-	# Print warning if email is not in CONTRIBUTORS file.
-	email = cl.dict.get("owner_email", "")
-	if not email:
-		return None, None, None, "cannot find owner for %s" % (clname)
-	him = FindContributor(ui, repo, email)
-	me = FindContributor(ui, repo, None)
-	if him == me:
-		cl.mailed = IsRietveldMailed(cl)
-	else:
-		cl.copied_from = email
-
-	return cl, vers, diffdata, ""
-
-def MySend(request_path, payload=None,
-		content_type="application/octet-stream",
-		timeout=None, force_auth=True,
-		**kwargs):
-	"""Run MySend1 maybe twice, because Rietveld is unreliable."""
-	try:
-		return MySend1(request_path, payload, content_type, timeout, force_auth, **kwargs)
-	except Exception, e:
-		if type(e) != urllib2.HTTPError or e.code != 500:	# only retry on HTTP 500 error
-			raise
-		print >>sys.stderr, "Loading "+request_path+": "+ExceptionDetail()+"; trying again in 2 seconds."
-		time.sleep(2)
-		return MySend1(request_path, payload, content_type, timeout, force_auth, **kwargs)
-
-# Like upload.py Send but only authenticates when the
-# redirect is to www.google.com/accounts.  This keeps
-# unnecessary redirects from happening during testing.
-def MySend1(request_path, payload=None,
-				content_type="application/octet-stream",
-				timeout=None, force_auth=True,
-				**kwargs):
-	"""Sends an RPC and returns the response.
-
-	Args:
-		request_path: The path to send the request to, eg /api/appversion/create.
-		payload: The body of the request, or None to send an empty request.
-		content_type: The Content-Type header to use.
-		timeout: timeout in seconds; default None i.e. no timeout.
-			(Note: for large requests on OS X, the timeout doesn't work right.)
-		kwargs: Any keyword arguments are converted into query string parameters.
-
-	Returns:
-		The response body, as a string.
-	"""
-	# TODO: Don't require authentication.  Let the server say
-	# whether it is necessary.
-	global rpc
-	if rpc == None:
-		rpc = GetRpcServer(upload_options)
-	self = rpc
-	if not self.authenticated and force_auth:
-		self._Authenticate()
-	if request_path is None:
-		return
-	if timeout is None:
-		timeout = 30 # seconds
-
-	old_timeout = socket.getdefaulttimeout()
-	socket.setdefaulttimeout(timeout)
-	try:
-		tries = 0
-		while True:
-			tries += 1
-			args = dict(kwargs)
-			url = "https://%s%s" % (self.host, request_path)
-			if testing:
-				url = url.replace("https://", "http://")
-			if args:
-				url += "?" + urllib.urlencode(args)
-			req = self._CreateRequest(url=url, data=payload)
-			req.add_header("Content-Type", content_type)
-			try:
-				f = self.opener.open(req)
-				response = f.read()
-				f.close()
-				# Translate \r\n into \n, because Rietveld doesn't.
-				response = response.replace('\r\n', '\n')
-				# who knows what urllib will give us
-				if type(response) == unicode:
-					response = response.encode("utf-8")
-				typecheck(response, str)
-				return response
-			except urllib2.HTTPError, e:
-				if tries > 3:
-					raise
-				elif e.code == 401:
-					self._Authenticate()
-				elif e.code == 302:
-					loc = e.info()["location"]
-					if not loc.startswith('https://www.google.com/a') or loc.find('/ServiceLogin') < 0:
-						return ''
-					self._Authenticate()
-				else:
-					raise
-	finally:
-		socket.setdefaulttimeout(old_timeout)
-
-def GetForm(url):
-	f = FormParser()
-	f.feed(ustr(MySend(url)))	# f.feed wants unicode
-	f.close()
-	# convert back to utf-8 to restore sanity
-	m = {}
-	for k,v in f.map.items():
-		m[k.encode("utf-8")] = v.replace("\r\n", "\n").encode("utf-8")
-	return m
-
-def EditDesc(issue, subject=None, desc=None, reviewers=None, cc=None, closed=False, private=False):
-	set_status("uploading change to description")
-	form_fields = GetForm("/" + issue + "/edit")
-	if subject is not None:
-		form_fields['subject'] = subject
-	if desc is not None:
-		form_fields['description'] = desc
-	if reviewers is not None:
-		form_fields['reviewers'] = reviewers
-	if cc is not None:
-		form_fields['cc'] = cc
-	if closed:
-		form_fields['closed'] = "checked"
-	if private:
-		form_fields['private'] = "checked"
-	ctype, body = EncodeMultipartFormData(form_fields.items(), [])
-	response = MySend("/" + issue + "/edit", body, content_type=ctype)
-	if response != "":
-		print >>sys.stderr, "Error editing description:\n" + "Sent form: \n", form_fields, "\n", response
-		sys.exit(2)
-
-def PostMessage(ui, issue, message, reviewers=None, cc=None, send_mail=True, subject=None):
-	set_status("uploading message")
-	form_fields = GetForm("/" + issue + "/publish")
-	if reviewers is not None:
-		form_fields['reviewers'] = reviewers
-	if cc is not None:
-		form_fields['cc'] = cc
-	if send_mail:
-		form_fields['send_mail'] = "checked"
-	else:
-		del form_fields['send_mail']
-	if subject is not None:
-		form_fields['subject'] = subject
-	form_fields['message'] = message
-	
-	form_fields['message_only'] = '1'	# Don't include draft comments
-	if reviewers is not None or cc is not None:
-		form_fields['message_only'] = ''	# Must set '' in order to override cc/reviewer
-	ctype = "applications/x-www-form-urlencoded"
-	body = urllib.urlencode(form_fields)
-	response = MySend("/" + issue + "/publish", body, content_type=ctype)
-	if response != "":
-		print response
-		sys.exit(2)
-
-class opt(object):
-	pass
-
-def RietveldSetup(ui, repo):
-	global force_google_account
-	global rpc
-	global server
-	global server_url_base
-	global upload_options
-	global verbosity
-
-	if not ui.verbose:
-		verbosity = 0
-
-	# Config options.
-	x = ui.config("codereview", "server")
-	if x is not None:
-		server = x
-
-	# TODO(rsc): Take from ui.username?
-	email = None
-	x = ui.config("codereview", "email")
-	if x is not None:
-		email = x
-
-	server_url_base = "https://" + server + "/"
-	if testing:
-		server_url_base = server_url_base.replace("https://", "http://")
-
-	force_google_account = ui.configbool("codereview", "force_google_account", False)
-
-	upload_options = opt()
-	upload_options.email = email
-	upload_options.host = None
-	upload_options.verbose = 0
-	upload_options.description = None
-	upload_options.description_file = None
-	upload_options.reviewers = None
-	upload_options.cc = None
-	upload_options.message = None
-	upload_options.issue = None
-	upload_options.download_base = False
-	upload_options.send_mail = False
-	upload_options.vcs = None
-	upload_options.server = server
-	upload_options.save_cookies = True
-
-	if testing:
-		upload_options.save_cookies = False
-		upload_options.email = "test at example.com"
-
-	rpc = None
-	
-	global releaseBranch
-	tags = repo.branchmap().keys()
-	if 'release-branch.go10' in tags:
-		# NOTE(rsc): This tags.sort is going to get the wrong
-		# answer when comparing release-branch.go9 with
-		# release-branch.go10.  It will be a while before we care.
-		raise hg_util.Abort('tags.sort needs to be fixed for release-branch.go10')
-	tags.sort()
-	for t in tags:
-		if t.startswith('release-branch.go'):
-			releaseBranch = t			
-
-def workbranch(name):
-	return name == "default" or name.startswith('dev.') or name == 'release-branch.go1.4'
-
-#######################################################################
-# http://codereview.appspot.com/static/upload.py, heavily edited.
-
-#!/usr/bin/env python
-#
-# Copyright 2007 Google Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#	http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""Tool for uploading diffs from a version control system to the codereview app.
-
-Usage summary: upload.py [options] [-- diff_options]
-
-Diff options are passed to the diff command of the underlying system.
-
-Supported version control systems:
-	Git
-	Mercurial
-	Subversion
-
-It is important for Git/Mercurial users to specify a tree/node/branch to diff
-against by using the '--rev' option.
-"""
-# This code is derived from appcfg.py in the App Engine SDK (open source),
-# and from ASPN recipe #146306.
-
-import cookielib
-import getpass
-import logging
-import mimetypes
-import optparse
-import os
-import re
-import socket
-import subprocess
-import sys
-import urllib
-import urllib2
-import urlparse
-
-# The md5 module was deprecated in Python 2.5.
-try:
-	from hashlib import md5
-except ImportError:
-	from md5 import md5
-
-try:
-	import readline
-except ImportError:
-	pass
-
-# The logging verbosity:
-#  0: Errors only.
-#  1: Status messages.
-#  2: Info logs.
-#  3: Debug logs.
-verbosity = 1
-
-# Max size of patch or base file.
-MAX_UPLOAD_SIZE = 900 * 1024
-
-# whitelist for non-binary filetypes which do not start with "text/"
-# .mm (Objective-C) shows up as application/x-freemind on my Linux box.
-TEXT_MIMETYPES = [
-	'application/javascript',
-	'application/x-javascript',
-	'application/x-freemind'
-]
-
-def GetEmail(prompt):
-	"""Prompts the user for their email address and returns it.
-
-	The last used email address is saved to a file and offered up as a suggestion
-	to the user. If the user presses enter without typing in anything the last
-	used email address is used. If the user enters a new address, it is saved
-	for next time we prompt.
-
-	"""
-	last_email_file_name = os.path.expanduser("~/.last_codereview_email_address")
-	last_email = ""
-	if os.path.exists(last_email_file_name):
-		try:
-			last_email_file = open(last_email_file_name, "r")
-			last_email = last_email_file.readline().strip("\n")
-			last_email_file.close()
-			prompt += " [%s]" % last_email
-		except IOError, e:
-			pass
-	email = raw_input(prompt + ": ").strip()
-	if email:
-		try:
-			last_email_file = open(last_email_file_name, "w")
-			last_email_file.write(email)
-			last_email_file.close()
-		except IOError, e:
-			pass
-	else:
-		email = last_email
-	return email
-
-
-def StatusUpdate(msg):
-	"""Print a status message to stdout.
-
-	If 'verbosity' is greater than 0, print the message.
-
-	Args:
-		msg: The string to print.
-	"""
-	if verbosity > 0:
-		print msg
-
-
-def ErrorExit(msg):
-	"""Print an error message to stderr and exit."""
-	print >>sys.stderr, msg
-	sys.exit(1)
-
-
-class ClientLoginError(urllib2.HTTPError):
-	"""Raised to indicate there was an error authenticating with ClientLogin."""
-
-	def __init__(self, url, code, msg, headers, args):
-		urllib2.HTTPError.__init__(self, url, code, msg, headers, None)
-		self.args = args
-		# .reason is now a read-only property based on .msg
-		# this means we ignore 'msg', but that seems to work fine.
-		self.msg = args["Error"] 
-
-
-class AbstractRpcServer(object):
-	"""Provides a common interface for a simple RPC server."""
-
-	def __init__(self, host, auth_function, host_override=None, extra_headers={}, save_cookies=False):
-		"""Creates a new HttpRpcServer.
-
-		Args:
-			host: The host to send requests to.
-			auth_function: A function that takes no arguments and returns an
-				(email, password) tuple when called. Will be called if authentication
-				is required.
-			host_override: The host header to send to the server (defaults to host).
-			extra_headers: A dict of extra headers to append to every request.
-			save_cookies: If True, save the authentication cookies to local disk.
-				If False, use an in-memory cookiejar instead.  Subclasses must
-				implement this functionality.  Defaults to False.
-		"""
-		self.host = host
-		self.host_override = host_override
-		self.auth_function = auth_function
-		self.authenticated = False
-		self.extra_headers = extra_headers
-		self.save_cookies = save_cookies
-		self.opener = self._GetOpener()
-		if self.host_override:
-			logging.info("Server: %s; Host: %s", self.host, self.host_override)
-		else:
-			logging.info("Server: %s", self.host)
-
-	def _GetOpener(self):
-		"""Returns an OpenerDirector for making HTTP requests.
-
-		Returns:
-			A urllib2.OpenerDirector object.
-		"""
-		raise NotImplementedError()
-
-	def _CreateRequest(self, url, data=None):
-		"""Creates a new urllib request."""
-		logging.debug("Creating request for: '%s' with payload:\n%s", url, data)
-		req = urllib2.Request(url, data=data)
-		if self.host_override:
-			req.add_header("Host", self.host_override)
-		for key, value in self.extra_headers.iteritems():
-			req.add_header(key, value)
-		return req
-
-	def _GetAuthToken(self, email, password):
-		"""Uses ClientLogin to authenticate the user, returning an auth token.
-
-		Args:
-			email:    The user's email address
-			password: The user's password
-
-		Raises:
-			ClientLoginError: If there was an error authenticating with ClientLogin.
-			HTTPError: If there was some other form of HTTP error.
-
-		Returns:
-			The authentication token returned by ClientLogin.
-		"""
-		account_type = "GOOGLE"
-		if self.host.endswith(".google.com") and not force_google_account:
-			# Needed for use inside Google.
-			account_type = "HOSTED"
-		req = self._CreateRequest(
-				url="https://www.google.com/accounts/ClientLogin",
-				data=urllib.urlencode({
-						"Email": email,
-						"Passwd": password,
-						"service": "ah",
-						"source": "rietveld-codereview-upload",
-						"accountType": account_type,
-				}),
-		)
-		try:
-			response = self.opener.open(req)
-			response_body = response.read()
-			response_dict = dict(x.split("=") for x in response_body.split("\n") if x)
-			return response_dict["Auth"]
-		except urllib2.HTTPError, e:
-			if e.code == 403:
-				body = e.read()
-				response_dict = dict(x.split("=", 1) for x in body.split("\n") if x)
-				raise ClientLoginError(req.get_full_url(), e.code, e.msg, e.headers, response_dict)
-			else:
-				raise
-
-	def _GetAuthCookie(self, auth_token):
-		"""Fetches authentication cookies for an authentication token.
-
-		Args:
-			auth_token: The authentication token returned by ClientLogin.
-
-		Raises:
-			HTTPError: If there was an error fetching the authentication cookies.
-		"""
-		# This is a dummy value to allow us to identify when we're successful.
-		continue_location = "http://localhost/"
-		args = {"continue": continue_location, "auth": auth_token}
-		reqUrl = "https://%s/_ah/login?%s" % (self.host, urllib.urlencode(args))
-		if testing:
-			reqUrl = reqUrl.replace("https://", "http://")
-		req = self._CreateRequest(reqUrl)
-		try:
-			response = self.opener.open(req)
-		except urllib2.HTTPError, e:
-			response = e
-		if (response.code != 302 or
-				response.info()["location"] != continue_location):
-			raise urllib2.HTTPError(req.get_full_url(), response.code, response.msg, response.headers, response.fp)
-		self.authenticated = True
-
-	def _Authenticate(self):
-		"""Authenticates the user.
-
-		The authentication process works as follows:
-		1) We get a username and password from the user
-		2) We use ClientLogin to obtain an AUTH token for the user
-				(see http://code.google.com/apis/accounts/AuthForInstalledApps.html).
-		3) We pass the auth token to /_ah/login on the server to obtain an
-				authentication cookie. If login was successful, it tries to redirect
-				us to the URL we provided.
-
-		If we attempt to access the upload API without first obtaining an
-		authentication cookie, it returns a 401 response (or a 302) and
-		directs us to authenticate ourselves with ClientLogin.
-		"""
-		for i in range(3):
-			credentials = self.auth_function()
-			try:
-				auth_token = self._GetAuthToken(credentials[0], credentials[1])
-			except ClientLoginError, e:
-				if e.msg == "BadAuthentication":
-					print >>sys.stderr, "Invalid username or password."
-					continue
-				if e.msg == "CaptchaRequired":
-					print >>sys.stderr, (
-						"Please go to\n"
-						"https://www.google.com/accounts/DisplayUnlockCaptcha\n"
-						"and verify you are a human.  Then try again.")
-					break
-				if e.msg == "NotVerified":
-					print >>sys.stderr, "Account not verified."
-					break
-				if e.msg == "TermsNotAgreed":
-					print >>sys.stderr, "User has not agreed to TOS."
-					break
-				if e.msg == "AccountDeleted":
-					print >>sys.stderr, "The user account has been deleted."
-					break
-				if e.msg == "AccountDisabled":
-					print >>sys.stderr, "The user account has been disabled."
-					break
-				if e.msg == "ServiceDisabled":
-					print >>sys.stderr, "The user's access to the service has been disabled."
-					break
-				if e.msg == "ServiceUnavailable":
-					print >>sys.stderr, "The service is not available; try again later."
-					break
-				raise
-			self._GetAuthCookie(auth_token)
-			return
-
-	def Send(self, request_path, payload=None,
-					content_type="application/octet-stream",
-					timeout=None,
-					**kwargs):
-		"""Sends an RPC and returns the response.
-
-		Args:
-			request_path: The path to send the request to, eg /api/appversion/create.
-			payload: The body of the request, or None to send an empty request.
-			content_type: The Content-Type header to use.
-			timeout: timeout in seconds; default None i.e. no timeout.
-				(Note: for large requests on OS X, the timeout doesn't work right.)
-			kwargs: Any keyword arguments are converted into query string parameters.
-
-		Returns:
-			The response body, as a string.
-		"""
-		# TODO: Don't require authentication.  Let the server say
-		# whether it is necessary.
-		if not self.authenticated:
-			self._Authenticate()
-
-		old_timeout = socket.getdefaulttimeout()
-		socket.setdefaulttimeout(timeout)
-		try:
-			tries = 0
-			while True:
-				tries += 1
-				args = dict(kwargs)
-				url = "https://%s%s" % (self.host, request_path)
-				if testing:
-					url = url.replace("https://", "http://")
-				if args:
-					url += "?" + urllib.urlencode(args)
-				req = self._CreateRequest(url=url, data=payload)
-				req.add_header("Content-Type", content_type)
-				try:
-					f = self.opener.open(req)
-					response = f.read()
-					f.close()
-					return response
-				except urllib2.HTTPError, e:
-					if tries > 3:
-						raise
-					elif e.code == 401 or e.code == 302:
-						self._Authenticate()
-					else:
-						raise
-		finally:
-			socket.setdefaulttimeout(old_timeout)
-
-
-class HttpRpcServer(AbstractRpcServer):
-	"""Provides a simplified RPC-style interface for HTTP requests."""
-
-	def _Authenticate(self):
-		"""Save the cookie jar after authentication."""
-		super(HttpRpcServer, self)._Authenticate()
-		if self.save_cookies:
-			StatusUpdate("Saving authentication cookies to %s" % self.cookie_file)
-			self.cookie_jar.save()
-
-	def _GetOpener(self):
-		"""Returns an OpenerDirector that supports cookies and ignores redirects.
-
-		Returns:
-			A urllib2.OpenerDirector object.
-		"""
-		opener = urllib2.OpenerDirector()
-		opener.add_handler(urllib2.ProxyHandler())
-		opener.add_handler(urllib2.UnknownHandler())
-		opener.add_handler(urllib2.HTTPHandler())
-		opener.add_handler(urllib2.HTTPDefaultErrorHandler())
-		opener.add_handler(urllib2.HTTPSHandler())
-		opener.add_handler(urllib2.HTTPErrorProcessor())
-		if self.save_cookies:
-			self.cookie_file = os.path.expanduser("~/.codereview_upload_cookies_" + server)
-			self.cookie_jar = cookielib.MozillaCookieJar(self.cookie_file)
-			if os.path.exists(self.cookie_file):
-				try:
-					self.cookie_jar.load()
-					self.authenticated = True
-					StatusUpdate("Loaded authentication cookies from %s" % self.cookie_file)
-				except (cookielib.LoadError, IOError):
-					# Failed to load cookies - just ignore them.
-					pass
-			else:
-				# Create an empty cookie file with mode 600
-				fd = os.open(self.cookie_file, os.O_CREAT, 0600)
-				os.close(fd)
-			# Always chmod the cookie file
-			os.chmod(self.cookie_file, 0600)
-		else:
-			# Don't save cookies across runs of update.py.
-			self.cookie_jar = cookielib.CookieJar()
-		opener.add_handler(urllib2.HTTPCookieProcessor(self.cookie_jar))
-		return opener
-
-
-def GetRpcServer(options):
-	"""Returns an instance of an AbstractRpcServer.
-
-	Returns:
-		A new AbstractRpcServer, on which RPC calls can be made.
-	"""
-
-	rpc_server_class = HttpRpcServer
-
-	def GetUserCredentials():
-		"""Prompts the user for a username and password."""
-		# Disable status prints so they don't obscure the password prompt.
-		global global_status
-		st = global_status
-		global_status = None
-
-		email = options.email
-		if email is None:
-			email = GetEmail("Email (login for uploading to %s)" % options.server)
-		password = getpass.getpass("Password for %s: " % email)
-
-		# Put status back.
-		global_status = st
-		return (email, password)
-
-	# If this is the dev_appserver, use fake authentication.
-	host = (options.host or options.server).lower()
-	if host == "localhost" or host.startswith("localhost:"):
-		email = options.email
-		if email is None:
-			email = "test at example.com"
-			logging.info("Using debug user %s.  Override with --email" % email)
-		server = rpc_server_class(
-				options.server,
-				lambda: (email, "password"),
-				host_override=options.host,
-				extra_headers={"Cookie": 'dev_appserver_login="%s:False"' % email},
-				save_cookies=options.save_cookies)
-		# Don't try to talk to ClientLogin.
-		server.authenticated = True
-		return server
-
-	return rpc_server_class(options.server, GetUserCredentials,
-		host_override=options.host, save_cookies=options.save_cookies)
-
-
-def EncodeMultipartFormData(fields, files):
-	"""Encode form fields for multipart/form-data.
-
-	Args:
-		fields: A sequence of (name, value) elements for regular form fields.
-		files: A sequence of (name, filename, value) elements for data to be
-					uploaded as files.
-	Returns:
-		(content_type, body) ready for httplib.HTTP instance.
-
-	Source:
-		http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/146306
-	"""
-	BOUNDARY = '-M-A-G-I-C---B-O-U-N-D-A-R-Y-'
-	CRLF = '\r\n'
-	lines = []
-	for (key, value) in fields:
-		typecheck(key, str)
-		typecheck(value, str)
-		lines.append('--' + BOUNDARY)
-		lines.append('Content-Disposition: form-data; name="%s"' % key)
-		lines.append('')
-		lines.append(value)
-	for (key, filename, value) in files:
-		typecheck(key, str)
-		typecheck(filename, str)
-		typecheck(value, str)
-		lines.append('--' + BOUNDARY)
-		lines.append('Content-Disposition: form-data; name="%s"; filename="%s"' % (key, filename))
-		lines.append('Content-Type: %s' % GetContentType(filename))
-		lines.append('')
-		lines.append(value)
-	lines.append('--' + BOUNDARY + '--')
-	lines.append('')
-	body = CRLF.join(lines)
-	content_type = 'multipart/form-data; boundary=%s' % BOUNDARY
-	return content_type, body
-
-
-def GetContentType(filename):
-	"""Helper to guess the content-type from the filename."""
-	return mimetypes.guess_type(filename)[0] or 'application/octet-stream'
-
-
-# Use a shell for subcommands on Windows to get a PATH search.
-use_shell = sys.platform.startswith("win")
-
-def RunShellWithReturnCode(command, print_output=False,
-		universal_newlines=True, env=os.environ):
-	"""Executes a command and returns the output from stdout and the return code.
-
-	Args:
-		command: Command to execute.
-		print_output: If True, the output is printed to stdout.
-			If False, both stdout and stderr are ignored.
-		universal_newlines: Use universal_newlines flag (default: True).
-
-	Returns:
-		Tuple (output, return code)
-	"""
-	logging.info("Running %s", command)
-	p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
-		shell=use_shell, universal_newlines=universal_newlines, env=env)
-	if print_output:
-		output_array = []
-		while True:
-			line = p.stdout.readline()
-			if not line:
-				break
-			print line.strip("\n")
-			output_array.append(line)
-		output = "".join(output_array)
-	else:
-		output = p.stdout.read()
-	p.wait()
-	errout = p.stderr.read()
-	if print_output and errout:
-		print >>sys.stderr, errout
-	p.stdout.close()
-	p.stderr.close()
-	return output, p.returncode
-
-
-def RunShell(command, silent_ok=False, universal_newlines=True,
-		print_output=False, env=os.environ):
-	data, retcode = RunShellWithReturnCode(command, print_output, universal_newlines, env)
-	if retcode:
-		ErrorExit("Got error status from %s:\n%s" % (command, data))
-	if not silent_ok and not data:
-		ErrorExit("No output from %s" % command)
-	return data
-
-
-class VersionControlSystem(object):
-	"""Abstract base class providing an interface to the VCS."""
-
-	def __init__(self, options):
-		"""Constructor.
-
-		Args:
-			options: Command line options.
-		"""
-		self.options = options
-
-	def GenerateDiff(self, args):
-		"""Return the current diff as a string.
-
-		Args:
-			args: Extra arguments to pass to the diff command.
-		"""
-		raise NotImplementedError(
-				"abstract method -- subclass %s must override" % self.__class__)
-
-	def GetUnknownFiles(self):
-		"""Return a list of files unknown to the VCS."""
-		raise NotImplementedError(
-				"abstract method -- subclass %s must override" % self.__class__)
-
-	def CheckForUnknownFiles(self):
-		"""Show an "are you sure?" prompt if there are unknown files."""
-		unknown_files = self.GetUnknownFiles()
-		if unknown_files:
-			print "The following files are not added to version control:"
-			for line in unknown_files:
-				print line
-			prompt = "Are you sure to continue?(y/N) "
-			answer = raw_input(prompt).strip()
-			if answer != "y":
-				ErrorExit("User aborted")
-
-	def GetBaseFile(self, filename):
-		"""Get the content of the upstream version of a file.
-
-		Returns:
-			A tuple (base_content, new_content, is_binary, status)
-				base_content: The contents of the base file.
-				new_content: For text files, this is empty.  For binary files, this is
-					the contents of the new file, since the diff output won't contain
-					information to reconstruct the current file.
-				is_binary: True iff the file is binary.
-				status: The status of the file.
-		"""
-
-		raise NotImplementedError(
-				"abstract method -- subclass %s must override" % self.__class__)
-
-
-	def GetBaseFiles(self, diff):
-		"""Helper that calls GetBase file for each file in the patch.
-
-		Returns:
-			A dictionary that maps from filename to GetBaseFile's tuple.  Filenames
-			are retrieved based on lines that start with "Index:" or
-			"Property changes on:".
-		"""
-		files = {}
-		for line in diff.splitlines(True):
-			if line.startswith('Index:') or line.startswith('Property changes on:'):
-				unused, filename = line.split(':', 1)
-				# On Windows if a file has property changes its filename uses '\'
-				# instead of '/'.
-				filename = to_slash(filename.strip())
-				files[filename] = self.GetBaseFile(filename)
-		return files
-
-
-	def UploadBaseFiles(self, issue, rpc_server, patch_list, patchset, options,
-											files):
-		"""Uploads the base files (and if necessary, the current ones as well)."""
-
-		def UploadFile(filename, file_id, content, is_binary, status, is_base):
-			"""Uploads a file to the server."""
-			set_status("uploading " + filename)
-			file_too_large = False
-			if is_base:
-				type = "base"
-			else:
-				type = "current"
-			if len(content) > MAX_UPLOAD_SIZE:
-				print ("Not uploading the %s file for %s because it's too large." %
-							(type, filename))
-				file_too_large = True
-				content = ""
-			checksum = md5(content).hexdigest()
-			if options.verbose > 0 and not file_too_large:
-				print "Uploading %s file for %s" % (type, filename)
-			url = "/%d/upload_content/%d/%d" % (int(issue), int(patchset), file_id)
-			form_fields = [
-				("filename", filename),
-				("status", status),
-				("checksum", checksum),
-				("is_binary", str(is_binary)),
-				("is_current", str(not is_base)),
-			]
-			if file_too_large:
-				form_fields.append(("file_too_large", "1"))
-			if options.email:
-				form_fields.append(("user", options.email))
-			ctype, body = EncodeMultipartFormData(form_fields, [("data", filename, content)])
-			response_body = rpc_server.Send(url, body, content_type=ctype)
-			if not response_body.startswith("OK"):
-				StatusUpdate("  --> %s" % response_body)
-				sys.exit(1)
-
-		# Don't want to spawn too many threads, nor do we want to
-		# hit Rietveld too hard, or it will start serving 500 errors.
-		# When 8 works, it's no better than 4, and sometimes 8 is
-		# too many for Rietveld to handle.
-		MAX_PARALLEL_UPLOADS = 4
-
-		sema = threading.BoundedSemaphore(MAX_PARALLEL_UPLOADS)
-		upload_threads = []
-		finished_upload_threads = []
-		
-		class UploadFileThread(threading.Thread):
-			def __init__(self, args):
-				threading.Thread.__init__(self)
-				self.args = args
-			def run(self):
-				UploadFile(*self.args)
-				finished_upload_threads.append(self)
-				sema.release()
-
-		def StartUploadFile(*args):
-			sema.acquire()
-			while len(finished_upload_threads) > 0:
-				t = finished_upload_threads.pop()
-				upload_threads.remove(t)
-				t.join()
-			t = UploadFileThread(args)
-			upload_threads.append(t)
-			t.start()
-
-		def WaitForUploads():			
-			for t in upload_threads:
-				t.join()
-
-		patches = dict()
-		[patches.setdefault(v, k) for k, v in patch_list]
-		for filename in patches.keys():
-			base_content, new_content, is_binary, status = files[filename]
-			file_id_str = patches.get(filename)
-			if file_id_str.find("nobase") != -1:
-				base_content = None
-				file_id_str = file_id_str[file_id_str.rfind("_") + 1:]
-			file_id = int(file_id_str)
-			if base_content != None:
-				StartUploadFile(filename, file_id, base_content, is_binary, status, True)
-			if new_content != None:
-				StartUploadFile(filename, file_id, new_content, is_binary, status, False)
-		WaitForUploads()
-
-	def IsImage(self, filename):
-		"""Returns true if the filename has an image extension."""
-		mimetype =  mimetypes.guess_type(filename)[0]
-		if not mimetype:
-			return False
-		return mimetype.startswith("image/")
-
-	def IsBinary(self, filename):
-		"""Returns true if the guessed mimetyped isnt't in text group."""
-		mimetype = mimetypes.guess_type(filename)[0]
-		if not mimetype:
-			return False  # e.g. README, "real" binaries usually have an extension
-		# special case for text files which don't start with text/
-		if mimetype in TEXT_MIMETYPES:
-			return False
-		return not mimetype.startswith("text/")
-
-
-class FakeMercurialUI(object):
-	def __init__(self):
-		self.quiet = True
-		self.output = ''
-		self.debugflag = False
-	
-	def write(self, *args, **opts):
-		self.output += ' '.join(args)
-	def copy(self):
-		return self
-	def status(self, *args, **opts):
-		pass
-
-	def formatter(self, topic, opts):
-		from mercurial.formatter import plainformatter
-		return plainformatter(self, topic, opts)
-	
-	def readconfig(self, *args, **opts):
-		pass
-	def expandpath(self, *args, **opts):
-		return global_ui.expandpath(*args, **opts)
-	def configitems(self, *args, **opts):
-		return global_ui.configitems(*args, **opts)
-	def config(self, *args, **opts):
-		return global_ui.config(*args, **opts)
-
-use_hg_shell = False	# set to True to shell out to hg always; slower
-
-class MercurialVCS(VersionControlSystem):
-	"""Implementation of the VersionControlSystem interface for Mercurial."""
-
-	def __init__(self, options, ui, repo):
-		super(MercurialVCS, self).__init__(options)
-		self.ui = ui
-		self.repo = repo
-		self.status = None
-		# Absolute path to repository (we can be in a subdir)
-		self.repo_dir = os.path.normpath(repo.root)
-		# Compute the subdir
-		cwd = os.path.normpath(os.getcwd())
-		assert cwd.startswith(self.repo_dir)
-		self.subdir = cwd[len(self.repo_dir):].lstrip(r"\/")
-		mqparent, err = RunShellWithReturnCode(['hg', 'log', '--rev', 'qparent', '--template={node}'])
-		if not err and mqparent != "":
-			self.base_rev = mqparent
-		else:
-			out = RunShell(["hg", "parents", "-q", "--template={node} {branch}"], silent_ok=True).strip()
-			if not out:
-				# No revisions; use 0 to mean a repository with nothing.
-				out = "0:0 default"
-			
-			# Find parent along current branch.
-			branch = repo[None].branch()
-			base = ""
-			for line in out.splitlines():
-				fields = line.strip().split(' ')
-				if fields[1] == branch:
-					base = fields[0]
-					break
-			if base == "":
-				# Use the first parent
-				base = out.strip().split(' ')[0]
-			self.base_rev = base
-
-	def _GetRelPath(self, filename):
-		"""Get relative path of a file according to the current directory,
-		given its logical path in the repo."""
-		assert filename.startswith(self.subdir), (filename, self.subdir)
-		return filename[len(self.subdir):].lstrip(r"\/")
-
-	def GenerateDiff(self, extra_args):
-		# If no file specified, restrict to the current subdir
-		extra_args = extra_args or ["."]
-		cmd = ["hg", "diff", "--git", "-r", self.base_rev] + extra_args
-		data = RunShell(cmd, silent_ok=True)
-		svndiff = []
-		filecount = 0
-		for line in data.splitlines():
-			m = re.match("diff --git a/(\S+) b/(\S+)", line)
-			if m:
-				# Modify line to make it look like as it comes from svn diff.
-				# With this modification no changes on the server side are required
-				# to make upload.py work with Mercurial repos.
-				# NOTE: for proper handling of moved/copied files, we have to use
-				# the second filename.
-				filename = m.group(2)
-				svndiff.append("Index: %s" % filename)
-				svndiff.append("=" * 67)
-				filecount += 1
-				logging.info(line)
-			else:
-				svndiff.append(line)
-		if not filecount:
-			ErrorExit("No valid patches found in output from hg diff")
-		return "\n".join(svndiff) + "\n"
-
-	def GetUnknownFiles(self):
-		"""Return a list of files unknown to the VCS."""
-		args = []
-		status = RunShell(["hg", "status", "--rev", self.base_rev, "-u", "."],
-				silent_ok=True)
-		unknown_files = []
-		for line in status.splitlines():
-			st, fn = line.split(" ", 1)
-			if st == "?":
-				unknown_files.append(fn)
-		return unknown_files
-
-	def get_hg_status(self, rev, path):
-		# We'd like to use 'hg status -C path', but that is buggy
-		# (see http://mercurial.selenic.com/bts/issue3023).
-		# Instead, run 'hg status -C' without a path
-		# and skim the output for the path we want.
-		if self.status is None:
-			if use_hg_shell:
-				out = RunShell(["hg", "status", "-C", "--rev", rev])
-			else:
-				fui = FakeMercurialUI()
-				ret = hg_commands.status(fui, self.repo, *[], **{'rev': [rev], 'copies': True})
-				if ret:
-					raise hg_util.Abort(ret)
-				out = fui.output
-			self.status = out.splitlines()
-		for i in range(len(self.status)):
-			# line is
-			#	A path
-			#	M path
-			# etc
-			line = to_slash(self.status[i])
-			if line[2:] == path:
-				if i+1 < len(self.status) and self.status[i+1][:2] == '  ':
-					return self.status[i:i+2]
-				return self.status[i:i+1]
-		raise hg_util.Abort("no status for " + path)
-	
-	def GetBaseFile(self, filename):
-		set_status("inspecting " + filename)
-		# "hg status" and "hg cat" both take a path relative to the current subdir
-		# rather than to the repo root, but "hg diff" has given us the full path
-		# to the repo root.
-		base_content = ""
-		new_content = None
-		is_binary = False
-		oldrelpath = relpath = self._GetRelPath(filename)
-		out = self.get_hg_status(self.base_rev, relpath)
-		status, what = out[0].split(' ', 1)
-		if len(out) > 1 and status == "A" and what == relpath:
-			oldrelpath = out[1].strip()
-			status = "M"
-		if ":" in self.base_rev:
-			base_rev = self.base_rev.split(":", 1)[0]
-		else:
-			base_rev = self.base_rev
-		if status != "A":
-			if use_hg_shell:
-				base_content = RunShell(["hg", "cat", "-r", base_rev, oldrelpath], silent_ok=True)
-			else:
-				base_content = str(self.repo[base_rev][oldrelpath].data())
-			is_binary = "\0" in base_content  # Mercurial's heuristic
-		if status != "R":
-			new_content = open(relpath, "rb").read()
-			is_binary = is_binary or "\0" in new_content
-		if is_binary and base_content and use_hg_shell:
-			# Fetch again without converting newlines
-			base_content = RunShell(["hg", "cat", "-r", base_rev, oldrelpath],
-				silent_ok=True, universal_newlines=False)
-		if not is_binary or not self.IsImage(relpath):
-			new_content = None
-		return base_content, new_content, is_binary, status
-
-
-# NOTE: The SplitPatch function is duplicated in engine.py, keep them in sync.
-def SplitPatch(data):
-	"""Splits a patch into separate pieces for each file.
-
-	Args:
-		data: A string containing the output of svn diff.
-
-	Returns:
-		A list of 2-tuple (filename, text) where text is the svn diff output
-			pertaining to filename.
-	"""
-	patches = []
-	filename = None
-	diff = []
-	for line in data.splitlines(True):
-		new_filename = None
-		if line.startswith('Index:'):
-			unused, new_filename = line.split(':', 1)
-			new_filename = new_filename.strip()
-		elif line.startswith('Property changes on:'):
-			unused, temp_filename = line.split(':', 1)
-			# When a file is modified, paths use '/' between directories, however
-			# when a property is modified '\' is used on Windows.  Make them the same
-			# otherwise the file shows up twice.
-			temp_filename = to_slash(temp_filename.strip())
-			if temp_filename != filename:
-				# File has property changes but no modifications, create a new diff.
-				new_filename = temp_filename
-		if new_filename:
-			if filename and diff:
-				patches.append((filename, ''.join(diff)))
-			filename = new_filename
-			diff = [line]
-			continue
-		if diff is not None:
-			diff.append(line)
-	if filename and diff:
-		patches.append((filename, ''.join(diff)))
-	return patches
-
-
-def UploadSeparatePatches(issue, rpc_server, patchset, data, options):
-	"""Uploads a separate patch for each file in the diff output.
-
-	Returns a list of [patch_key, filename] for each file.
-	"""
-	patches = SplitPatch(data)
-	rv = []
-	for patch in patches:
-		set_status("uploading patch for " + patch[0])
-		if len(patch[1]) > MAX_UPLOAD_SIZE:
-			print ("Not uploading the patch for " + patch[0] +
-				" because the file is too large.")
-			continue
-		form_fields = [("filename", patch[0])]
-		if not options.download_base:
-			form_fields.append(("content_upload", "1"))
-		files = [("data", "data.diff", patch[1])]
-		ctype, body = EncodeMultipartFormData(form_fields, files)
-		url = "/%d/upload_patch/%d" % (int(issue), int(patchset))
-		print "Uploading patch for " + patch[0]
-		response_body = rpc_server.Send(url, body, content_type=ctype)
-		lines = response_body.splitlines()
-		if not lines or lines[0] != "OK":
-			StatusUpdate("  --> %s" % response_body)
-			sys.exit(1)
-		rv.append([lines[1], patch[0]])
-	return rv
diff --git a/lib/codereview/test.sh b/lib/codereview/test.sh
deleted file mode 100755
index 4bef9b6..0000000
--- a/lib/codereview/test.sh
+++ /dev/null
@@ -1,199 +0,0 @@
-#!/bin/bash
-# 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.
-
-# Test the code review plugin.
-# Assumes a local Rietveld is running using the App Engine SDK
-# at http://localhost:7777/
-#
-# dev_appserver.py --port 7777 $HOME/pub/rietveld
-
-codereview_script=$(pwd)/codereview.py
-server=localhost:7777
-master=/tmp/go.test
-clone1=/tmp/go.test1
-clone2=/tmp/go.test2
-export HGEDITOR=true
-
-must() {
-	if ! "$@"; then
-		echo "$@" failed >&2
-		exit 1
-	fi
-}
-
-not() {
-	if "$@"; then
-		false
-	else
-		true
-	fi
-}
-
-status() {
-	echo '+++' "$@" >&2
-}
-
-firstcl() {
-	hg pending | sed 1q | tr -d ':'
-}
-
-# Initial setup.
-status Create repositories.
-rm -rf $master $clone1 $clone2
-mkdir $master
-cd $master
-must hg init .
-echo Initial state >file
-must hg add file
-must hg ci -m 'first commit' file
-must hg clone $master $clone1
-must hg clone $master $clone2
-
-echo "
-[ui]
-username=Grace R Emlin <gre at golang.org>
-[extensions]
-codereview=$codereview_script
-[codereview]
-testing=true
-server=$server
-" >>$clone1/.hg/hgrc
-cp $clone1/.hg/hgrc $clone2/.hg/hgrc
-
-status Codereview should be disabled.
-cd $clone1
-must hg status
-must not hg pending
-
-status Enabling code review.
-must mkdir lib lib/codereview
-must touch lib/codereview/codereview.cfg
-
-status Code review should work even without CONTRIBUTORS.
-must hg pending
-
-status Add CONTRIBUTORS.
-echo 'Grace R Emlin <gre at golang.org>' >CONTRIBUTORS
-must hg add lib/codereview/codereview.cfg CONTRIBUTORS
-
-status First submit.
-must hg submit --tbr gre at golang.org -m codereview \
-	lib/codereview/codereview.cfg CONTRIBUTORS
-
-status Should see change in other client.
-cd $clone2
-must hg pull -u
-must test -f lib/codereview/codereview.cfg
-must test -f CONTRIBUTORS
-
-test_clpatch() {
-	# The email address must be test at example.com to match
-	# the test code review server's default user.
-	# Clpatch will check.
-	
-	cd $clone1
-	# dev_appserver.py used to crash with UTF-8 input.
-	if true; then
-		status Using UTF-8.
-		name="Grácè T Emlïn <test at example.com>"
-	else
-		status Using ASCII.
-		name="Grace T Emlin <test at example.com>"
-	fi
-	echo "$name" >>CONTRIBUTORS
-	cat .hg/hgrc | sed "s/Grace.*/$name/" >/tmp/x && mv /tmp/x .hg/hgrc
-	echo "
-Reviewer: gre at golang.org
-Description:
-	CONTRIBUTORS: add $name
-Files:
-	CONTRIBUTORS
-"	| must hg change -i
-	num=$(hg pending | sed 1q | tr -d :)
-	
-	status Patch CL.
-	cd $clone2
-	must hg clpatch $num
-	must [ "$num" = "$(firstcl)" ]
-	must hg submit --tbr gre at golang.org $num
-	
-	status Issue should be open with no reviewers.
-	must curl http://$server/api/$num >/tmp/x
-	must not grep '"closed":true' /tmp/x
-	must grep '"reviewers":\[\]' /tmp/x
-	
-	status Sync should close issue.
-	cd $clone1
-	must hg sync
-	must curl http://$server/api/$num >/tmp/x
-	must grep '"closed":true' /tmp/x
-	must grep '"reviewers":\[\]' /tmp/x
-	must [ "$(firstcl)" = "" ]
-}
-
-test_reviewer() {
-	status Submit without reviewer should fail.
-	cd $clone1
-	echo dummy >dummy
-	must hg add dummy
-	echo '
-Description:
-	no reviewer
-Files:
-	dummy
-'	| must hg change -i
-	num=$(firstcl)
-	must not hg submit $num
-	must hg revert dummy
-	must rm dummy
-	must hg change -d $num
-}
-
-test_linearity() {
-	status Linearity of changes.
-	cd $clone1
-	echo file1 >file1
-	must hg add file1
-	echo '
-Reviewer: gre at golang.org
-Description: file1
-Files: file1
-	' | must hg change -i
-	must hg submit --tbr gre at golang.org $(firstcl)
-	
-	cd $clone2
-	echo file2 >file2
-	must hg add file2
-	echo '
-Reviewer: gre at golang.org
-Description: file2
-Files: file2
-	' | must hg change -i
-	must not hg submit --tbr gre at golang.org $(firstcl)
-	must hg sync
-	must hg submit --tbr gre at golang.org $(firstcl)
-}
-
-test_restrict() {
-	status Cannot use hg ci.
-	cd $clone1
-	echo file1a >file1a
-	hg add file1a
-	must not hg ci -m commit file1a
-	must rm file1a
-	must hg revert file1a
-	
-	status Cannot use hg rollback.
-	must not hg rollback
-	
-	status Cannot use hg backout
-	must not hg backout -r -1
-}
-
-test_reviewer
-test_clpatch
-test_linearity
-test_restrict
-status ALL TESTS PASSED.
diff --git a/lib/time/update.bash b/lib/time/update.bash
index caa8450..3ef1df5 100755
--- a/lib/time/update.bash
+++ b/lib/time/update.bash
@@ -7,8 +7,8 @@
 # downloaded from the ICANN/IANA distribution.
 
 # Versions to use.
-CODE=2014j
-DATA=2014j
+CODE=2015e
+DATA=2015e
 
 set -e
 rm -rf work
diff --git a/lib/time/zoneinfo.zip b/lib/time/zoneinfo.zip
index 425d7c9..73c30b4 100644
Binary files a/lib/time/zoneinfo.zip and b/lib/time/zoneinfo.zip differ
diff --git a/misc/android/README b/misc/android/README
index 5f24faf..7b17d87 100644
--- a/misc/android/README
+++ b/misc/android/README
@@ -2,9 +2,9 @@ Android
 =======
 
 For details on developing Go for Android, see the documentation in the
-go.mobile subrepository:
+mobile subrepository:
 
-	https://code.google.com/p/go/source/browse/README?repo=mobile
+	https://github.com/golang/mobile
 
 To run the standard library tests, see androidtest.bash. Run it as
 
diff --git a/misc/android/cleaner.go b/misc/android/cleaner.go
new file mode 100644
index 0000000..dafb162
--- /dev/null
+++ b/misc/android/cleaner.go
@@ -0,0 +1,39 @@
+// 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.
+
+// Cleaner removes anything from /data/local/tmp/goroot not on a builtin list.
+// Used by androidtest.bash.
+package main
+
+import (
+	"log"
+	"os"
+	"path/filepath"
+	"strings"
+)
+
+func main() {
+	const goroot = "/data/local/tmp/goroot"
+	expect := make(map[string]bool)
+	for _, f := range strings.Split(files, "\n") {
+		expect[filepath.Join(goroot, f)] = true
+	}
+
+	err := filepath.Walk(goroot, func(path string, info os.FileInfo, err error) error {
+		if expect[path] {
+			return nil
+		}
+		log.Printf("removing %s", path)
+		if err := os.RemoveAll(path); err != nil {
+			return err
+		}
+		if info.IsDir() {
+			return filepath.SkipDir
+		}
+		return nil
+	})
+	if err != nil {
+		log.Fatal(err)
+	}
+}
diff --git a/misc/android/go_android_exec.go b/misc/android/go_android_exec.go
index e32a805..a67e990 100644
--- a/misc/android/go_android_exec.go
+++ b/misc/android/go_android_exec.go
@@ -9,6 +9,7 @@ package main
 import (
 	"bytes"
 	"fmt"
+	"go/build"
 	"io"
 	"log"
 	"os"
@@ -32,33 +33,36 @@ func run(args ...string) string {
 	return buf.String()
 }
 
+const (
+	// Directory structure on the target device androidtest.bash assumes.
+	deviceGoroot = "/data/local/tmp/goroot"
+	deviceGopath = "/data/local/tmp/gopath"
+)
+
 func main() {
 	log.SetFlags(0)
 	log.SetPrefix("go_android_exec: ")
 
-	// Determine thepackage by examining the current working
+	// Prepare a temporary directory that will be cleaned up at the end.
+	deviceGotmp := fmt.Sprintf("/data/local/tmp/%s-%d",
+		filepath.Base(os.Args[1]), os.Getpid())
+	run("shell", "mkdir", "-p", deviceGotmp)
+
+	// Determine the package by examining the current working
 	// directory, which will look something like
-	// "$GOROOT/src/mime/multipart". We extract everything
-	// after the $GOROOT to run on the same relative directory
-	// on the target device.
-	//
-	// TODO(crawshaw): Pick useful subdir when we are not
-	// inside a GOROOT, e.g. we are in a GOPATH.
-	cwd, err := os.Getwd()
-	if err != nil {
-		log.Fatal(err)
+	// "$GOROOT/src/mime/multipart" or "$GOPATH/src/golang.org/x/mobile".
+	// We extract everything after the $GOROOT or $GOPATH to run on the
+	// same relative directory on the target device.
+	subdir, inGoRoot := subdir()
+	deviceCwd := filepath.Join(deviceGoroot, subdir)
+	if !inGoRoot {
+		deviceCwd = filepath.Join(deviceGopath, subdir)
 	}
-	subdir, err := filepath.Rel(runtime.GOROOT(), cwd)
-	if err != nil {
-		log.Fatal(err)
-	}
-	subdir = filepath.ToSlash(subdir)
 
 	// Binary names can conflict.
 	// E.g. template.test from the {html,text}/template packages.
 	binName := filepath.Base(os.Args[1])
-	deviceGoroot := "/data/local/tmp/goroot"
-	deviceBin := fmt.Sprintf("%s/%s-%d", deviceGoroot, binName, os.Getpid())
+	deviceBin := fmt.Sprintf("%s/%s-%d", deviceGotmp, binName, os.Getpid())
 
 	// The push of the binary happens in parallel with other tests.
 	// Unfortunately, a simultaneous call to adb shell hold open
@@ -71,19 +75,22 @@ func main() {
 
 	// The adb shell command will return an exit code of 0 regardless
 	// of the command run. E.g.
-	//	$ adb shell false
-	//	$ echo $?
-	//	0
+	//      $ adb shell false
+	//      $ echo $?
+	//      0
 	// https://code.google.com/p/android/issues/detail?id=3254
 	// So we append the exitcode to the output and parse it from there.
 	const exitstr = "exitcode="
-	cmd := `export TMPDIR="/data/local/tmp"` +
+	cmd := `export TMPDIR="` + deviceGotmp + `"` +
 		`; export GOROOT="` + deviceGoroot + `"` +
-		`; cd "$GOROOT/` + subdir + `"` +
+		`; export GOPATH="` + deviceGopath + `"` +
+		`; cd "` + deviceCwd + `"` +
 		"; '" + deviceBin + "' " + strings.Join(os.Args[2:], " ") +
 		"; echo -n " + exitstr + "$?"
 	output := run("shell", cmd)
-	run("shell", "rm '"+deviceBin+"'") // cleanup
+
+	run("shell", "rm", "-rf", deviceGotmp) // Clean up.
+
 	output = output[strings.LastIndex(output, "\n")+1:]
 	if !strings.HasPrefix(output, exitstr) {
 		log.Fatalf("no exit code: %q", output)
@@ -94,3 +101,32 @@ func main() {
 	}
 	os.Exit(code)
 }
+
+// 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) {
+	cwd, err := os.Getwd()
+	if err != nil {
+		log.Fatal(err)
+	}
+	if root := runtime.GOROOT(); strings.HasPrefix(cwd, root) {
+		subdir, err := filepath.Rel(root, cwd)
+		if err != nil {
+			log.Fatal(err)
+		}
+		return subdir, true
+	}
+
+	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
+		}
+	}
+	log.Fatalf("the current path %q is not in either GOROOT(%q) or GOPATH(%q)",
+		cwd, runtime.GOROOT(), build.Default.GOPATH)
+	return "", false
+}
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/gmp/gmp.go b/misc/cgo/gmp/gmp.go
index 7b7a9b3..d39bfe6 100644
--- a/misc/cgo/gmp/gmp.go
+++ b/misc/cgo/gmp/gmp.go
@@ -8,7 +8,7 @@ multiprecision library gmp's integer type mpz_t wrapped to look like
 the Go package big's integer type Int.
 
 This is a syntactically valid Go program—it can be parsed with the Go
-parser and processed by godoc—but it is not compiled directly by 6g.
+parser and processed by godoc—but it is not compiled directly by gc.
 Instead, a separate tool, cgo, processes it to produce three output
 files.  The first two, 6g.go and 6c.c, are a Go source file for 6g and
 a C source file for 6c; both compile as part of the named package
diff --git a/misc/cgo/test/backdoor.go b/misc/cgo/test/backdoor.go
new file mode 100644
index 0000000..6fb33d6
--- /dev/null
+++ b/misc/cgo/test/backdoor.go
@@ -0,0 +1,11 @@
+// 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 cgotest
+
+import _ "unsafe"
+
+//go:linkname lockedOSThread runtime.lockedOSThread
+//extern runtime_lockedOSThread
+func lockedOSThread() bool
diff --git a/misc/cgo/test/backdoor/backdoor.go b/misc/cgo/test/backdoor/backdoor.go
deleted file mode 100644
index 3a97349..0000000
--- a/misc/cgo/test/backdoor/backdoor.go
+++ /dev/null
@@ -1,7 +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.
-
-package backdoor
-
-func LockedOSThread() bool // in thunk.s
diff --git a/misc/cgo/test/backdoor/runtime_gccgo.c b/misc/cgo/test/backdoor/runtime_gccgo.c
deleted file mode 100644
index 218b2c3..0000000
--- a/misc/cgo/test/backdoor/runtime_gccgo.c
+++ /dev/null
@@ -1,18 +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.
-
-// Expose some runtime functions for testing.
-// This is the gccgo version of runtime.c.
-
-// +build gccgo
-
-_Bool runtime_lockedOSThread(void);
-
-_Bool LockedOSThread(void) asm(GOPKGPATH ".LockedOSThread");
-
-_Bool
-LockedOSThread(void)
-{
-	return runtime_lockedOSThread();
-}
diff --git a/misc/cgo/test/backdoor/thunk.s b/misc/cgo/test/backdoor/thunk.s
deleted file mode 100644
index ae735c8..0000000
--- a/misc/cgo/test/backdoor/thunk.s
+++ /dev/null
@@ -1,16 +0,0 @@
-// 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.
-
-// Assembly to get into package runtime without using exported symbols.
-
-// +build amd64 amd64p32 arm 386
-
-#include "textflag.h"
-
-#ifdef GOARCH_arm
-#define JMP B
-#endif
-
-TEXT ·LockedOSThread(SB),NOSPLIT,$0-0
-	JMP	runtime·lockedOSThread(SB)
diff --git a/misc/cgo/test/callback.go b/misc/cgo/test/callback.go
index 44167e6..bff770f 100644
--- a/misc/cgo/test/callback.go
+++ b/misc/cgo/test/callback.go
@@ -9,7 +9,6 @@ void callback(void *f);
 void callGoFoo(void);
 void callGoStackCheck(void);
 void callPanic(void);
-void callCgoAllocate(void);
 int callGoReturnVal(void);
 int returnAfterGrow(void);
 int returnAfterGrowFromGo(void);
@@ -22,8 +21,6 @@ import (
 	"strings"
 	"testing"
 	"unsafe"
-
-	"./backdoor"
 )
 
 // nestedCall calls into C, back into Go, and finally to f.
@@ -50,8 +47,6 @@ func testCallbackGC(t *testing.T) {
 	nestedCall(runtime.GC)
 }
 
-var lockedOSThread = backdoor.LockedOSThread
-
 func testCallbackPanic(t *testing.T) {
 	// Make sure panic during callback unwinds properly.
 	if lockedOSThread() {
@@ -161,9 +156,8 @@ func testCallbackCallers(t *testing.T) {
 		"runtime.cgocallbackg1",
 		"runtime.cgocallbackg",
 		"runtime.cgocallback_gofunc",
-		"asmcgocall",
-		"runtime.asmcgocall_errno",
-		"runtime.cgocall_errno",
+		"runtime.asmcgocall",
+		"runtime.cgocall",
 		"test._Cfunc_callback",
 		"test.nestedCall",
 		"test.testCallbackCallers",
@@ -171,6 +165,9 @@ func testCallbackCallers(t *testing.T) {
 		"testing.tRunner",
 		"runtime.goexit",
 	}
+	if unsafe.Sizeof((*byte)(nil)) == 8 {
+		name[1] = "runtime.call32"
+	}
 	nestedCall(func() {
 		n = runtime.Callers(2, pc)
 	})
@@ -211,10 +208,6 @@ func testPanicFromC(t *testing.T) {
 	C.callPanic()
 }
 
-func testAllocateFromC(t *testing.T) {
-	C.callCgoAllocate() // crashes or exits on failure
-}
-
 // Test that C code can return a value if it calls a Go function that
 // causes a stack copy.
 func testReturnAfterGrow(t *testing.T) {
diff --git a/misc/cgo/test/callback_c_gc.c b/misc/cgo/test/callback_c_gc.c
index 28a62c6..c6ea3c5 100644
--- a/misc/cgo/test/callback_c_gc.c
+++ b/misc/cgo/test/callback_c_gc.c
@@ -23,58 +23,3 @@ callPanic(void)
 	crosscall2(_cgo_panic, &a, sizeof a);
 	*(int*)1 = 1;
 }
-
-/* Test calling cgo_allocate from C. This is what SWIG does. */
-
-typedef struct List List;
-struct List
-{
-	List *next;
-	int x;
-};
-
-void
-callCgoAllocate(void)
-{
-	int i;
-	struct { size_t n; void *ret; } a;
-	List *l, *head, **tail;
-
-	// Make sure this doesn't crash.
-	// And make sure it returns non-nil.
-	a.n = 0;
-	a.ret = 0;
-	crosscall2(_cgo_allocate, &a, sizeof a);
-	if(a.ret == 0) {
-		fprintf(stderr, "callCgoAllocate: alloc 0 returned nil\n");
-		exit(2);
-	}
-	
-	head = 0;
-	tail = &head;
-	for(i=0; i<100; i++) {
-		a.n = sizeof *l;
-		crosscall2(_cgo_allocate, &a, sizeof a);
-		l = a.ret;
-		l->x = i;
-		l->next = 0;
-		*tail = l;
-		tail = &l->next;
-	}
-	
-	gc();
-	
-	l = head;
-	for(i=0; i<100; i++) {
-		if(l->x != i) {
-			fprintf(stderr, "callCgoAllocate: lost memory\n");
-			exit(2);
-		}
-		l = l->next;
-	}
-	if(l != 0) {
-		fprintf(stderr, "callCgoAllocate: lost memory\n");
-		exit(2);
-	}
-}
-
diff --git a/misc/cgo/test/callback_c_gccgo.c b/misc/cgo/test/callback_c_gccgo.c
index d367b7b..ff5dbbb 100644
--- a/misc/cgo/test/callback_c_gccgo.c
+++ b/misc/cgo/test/callback_c_gccgo.c
@@ -19,52 +19,3 @@ callPanic(void)
 {
 	_cgo_panic("panic from C");
 }
-
-/* Test calling cgo_allocate from C. This is what SWIG does. */
-
-typedef struct List List;
-struct List
-{
-	List *next;
-	int x;
-};
-
-void
-callCgoAllocate(void)
-{
-	int i;
-	List *l, *head, **tail;
-	
-	// Make sure this doesn't crash.
-	// And make sure it returns non-nil.
-	if(_cgo_allocate(0) == 0) {
-		fprintf(stderr, "callCgoAllocate: alloc 0 returned nil\n");
-		exit(2);
-	}
-
-	head = 0;
-	tail = &head;
-	for(i=0; i<100; i++) {
-		l = _cgo_allocate(sizeof *l);
-		l->x = i;
-		l->next = 0;
-		*tail = l;
-		tail = &l->next;
-	}
-	
-	gc();
-	
-	l = head;
-	for(i=0; i<100; i++) {
-		if(l->x != i) {
-			fprintf(stderr, "callCgoAllocate: lost memory\n");
-			exit(2);
-		}
-		l = l->next;
-	}
-	if(l != 0) {
-		fprintf(stderr, "callCgoAllocate: lost memory\n");
-		exit(2);
-	}
-}
-
diff --git a/misc/cgo/test/cflags.go b/misc/cgo/test/cflags.go
index 24caab4..6571fe0 100644
--- a/misc/cgo/test/cflags.go
+++ b/misc/cgo/test/cflags.go
@@ -4,7 +4,7 @@
 
 // Test that the #cgo CFLAGS directive works,
 // with and without platform filters.
-// See http://code.google.com/p/go/issues/detail?id=5224 for details.
+// See https://golang.org/issue/5224 for details.
 package cgotest
 
 /*
diff --git a/misc/cgo/test/cgo_linux_test.go b/misc/cgo/test/cgo_linux_test.go
index 4fe0db1..3cc2af5 100644
--- a/misc/cgo/test/cgo_linux_test.go
+++ b/misc/cgo/test/cgo_linux_test.go
@@ -6,6 +6,8 @@ package cgotest
 
 import "testing"
 
-func TestSetgid(t *testing.T)  { testSetgid(t) }
-func Test6997(t *testing.T)    { test6997(t) }
-func TestBuildID(t *testing.T) { testBuildID(t) }
+func TestSetgid(t *testing.T)      { testSetgid(t) }
+func Test6997(t *testing.T)        { test6997(t) }
+func TestBuildID(t *testing.T)     { testBuildID(t) }
+func Test9400(t *testing.T)        { test9400(t) }
+func TestSigProcMask(t *testing.T) { testSigProcMask(t) }
diff --git a/misc/cgo/test/cgo_test.go b/misc/cgo/test/cgo_test.go
index fbdfac8..9af31e8 100644
--- a/misc/cgo/test/cgo_test.go
+++ b/misc/cgo/test/cgo_test.go
@@ -23,7 +23,6 @@ func TestCallbackPanic(t *testing.T)         { testCallbackPanic(t) }
 func TestCallbackPanicLoop(t *testing.T)     { testCallbackPanicLoop(t) }
 func TestCallbackPanicLocked(t *testing.T)   { testCallbackPanicLocked(t) }
 func TestPanicFromC(t *testing.T)            { testPanicFromC(t) }
-func TestAllocateFromC(t *testing.T)         { testAllocateFromC(t) }
 func TestZeroArgCallback(t *testing.T)       { testZeroArgCallback(t) }
 func TestBlocking(t *testing.T)              { testBlocking(t) }
 func Test1328(t *testing.T)                  { test1328(t) }
@@ -63,5 +62,8 @@ func Test8811(t *testing.T)                  { test8811(t) }
 func TestReturnAfterGrow(t *testing.T)       { testReturnAfterGrow(t) }
 func TestReturnAfterGrowFromGo(t *testing.T) { testReturnAfterGrowFromGo(t) }
 func Test9026(t *testing.T)                  { test9026(t) }
+func Test9557(t *testing.T)                  { test9557(t) }
+func Test10303(t *testing.T)                 { test10303(t, 10) }
+func Test11925(t *testing.T)                 { test11925(t) }
 
 func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) }
diff --git a/misc/cgo/test/cthread_unix.c b/misc/cgo/test/cthread_unix.c
index 3f39c15..d29f2fc 100644
--- a/misc/cgo/test/cthread_unix.c
+++ b/misc/cgo/test/cthread_unix.c
@@ -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 netbsd openbsd
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
 
 #include <pthread.h>
 #include "_cgo_export.h"
diff --git a/misc/cgo/test/issue10303.go b/misc/cgo/test/issue10303.go
new file mode 100644
index 0000000..ea623d7
--- /dev/null
+++ b/misc/cgo/test/issue10303.go
@@ -0,0 +1,70 @@
+// 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 10303. Pointers passed to C were not marked as escaping (bug in cgo).
+
+package cgotest
+
+/*
+typedef int *intptr;
+
+void setintstar(int *x) {
+	*x = 1;
+}
+
+void setintptr(intptr x) {
+	*x = 1;
+}
+
+void setvoidptr(void *x) {
+	*(int*)x = 1;
+}
+
+typedef struct Struct Struct;
+struct Struct {
+	int *P;
+};
+
+void setstruct(Struct s) {
+	*s.P = 1;
+}
+
+*/
+import "C"
+
+import (
+	"testing"
+	"unsafe"
+)
+
+func test10303(t *testing.T, n int) {
+	// Run at a few different stack depths just to avoid an unlucky pass
+	// due to variables ending up on different pages.
+	if n > 0 {
+		test10303(t, n-1)
+	}
+	if t.Failed() {
+		return
+	}
+	var x, y, z, v, si C.int
+	var s C.Struct
+	C.setintstar(&x)
+	C.setintptr(&y)
+	C.setvoidptr(unsafe.Pointer(&v))
+	s.P = &si
+	C.setstruct(s)
+
+	if uintptr(unsafe.Pointer(&x))&^0xfff == uintptr(unsafe.Pointer(&z))&^0xfff {
+		t.Error("C int* argument on stack")
+	}
+	if uintptr(unsafe.Pointer(&y))&^0xfff == uintptr(unsafe.Pointer(&z))&^0xfff {
+		t.Error("C intptr argument on stack")
+	}
+	if uintptr(unsafe.Pointer(&v))&^0xfff == uintptr(unsafe.Pointer(&z))&^0xfff {
+		t.Error("C void* argument on stack")
+	}
+	if uintptr(unsafe.Pointer(&si))&^0xfff == uintptr(unsafe.Pointer(&z))&^0xfff {
+		t.Error("C struct field pointer on stack")
+	}
+}
diff --git a/misc/cgo/test/issue11925.go b/misc/cgo/test/issue11925.go
new file mode 100644
index 0000000..9e50fb7
--- /dev/null
+++ b/misc/cgo/test/issue11925.go
@@ -0,0 +1,37 @@
+// 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 11925.  Structs with zero-length trailing fields are now
+// padded by the Go compiler.
+
+package cgotest
+
+/*
+struct a11925 {
+	int i;
+	char a[0];
+	char b[0];
+};
+
+struct b11925 {
+	int i;
+	char a[0];
+	char b[];
+};
+*/
+import "C"
+
+import (
+	"testing"
+	"unsafe"
+)
+
+func test11925(t *testing.T) {
+	if C.sizeof_struct_a11925 != unsafe.Sizeof(C.struct_a11925{}) {
+		t.Errorf("size of a changed: C %d, Go %d", C.sizeof_struct_a11925, unsafe.Sizeof(C.struct_a11925{}))
+	}
+	if C.sizeof_struct_b11925 != unsafe.Sizeof(C.struct_b11925{}) {
+		t.Errorf("size of b changed: C %d, Go %d", C.sizeof_struct_b11925, unsafe.Sizeof(C.struct_b11925{}))
+	}
+}
diff --git a/misc/cgo/test/issue3261.go b/misc/cgo/test/issue3261.go
index 0411be8..32cb06b 100644
--- a/misc/cgo/test/issue3261.go
+++ b/misc/cgo/test/issue3261.go
@@ -13,6 +13,12 @@ int vabs(int x) {
 	puts("testLibgcc is disabled on ARM because 5l cannot handle thumb library.");
 	return (x < 0) ? -x : x;
 }
+#elif defined(__arm64__) && defined(__clang__)
+#include <stdio.h>
+int vabs(int x) {
+	puts("testLibgcc is disabled on ARM64 with clang due to lack of libgcc.");
+	return (x < 0) ? -x : x;
+}
 #else
 int __absvsi2(int); // dummy prototype for libgcc function
 // we shouldn't name the function abs, as gcc might use
diff --git a/misc/cgo/test/issue3945.go b/misc/cgo/test/issue3945.go
index 331cd0b..7e6863f 100644
--- a/misc/cgo/test/issue3945.go
+++ b/misc/cgo/test/issue3945.go
@@ -5,7 +5,7 @@
 package cgotest
 
 // Test that cgo reserves enough stack space during cgo call.
-// See http://golang.org/issue/3945 for details.
+// See https://golang.org/issue/3945 for details.
 
 // #include <stdio.h>
 //
diff --git a/misc/cgo/test/issue6997_linux.go b/misc/cgo/test/issue6997_linux.go
index 5455f0c..07fd58e 100644
--- a/misc/cgo/test/issue6997_linux.go
+++ b/misc/cgo/test/issue6997_linux.go
@@ -4,7 +4,7 @@
 
 // Test that pthread_cancel works as expected
 // (NPTL uses SIGRTMIN to implement thread cancellation)
-// See http://golang.org/issue/6997
+// See https://golang.org/issue/6997
 package cgotest
 
 /*
diff --git a/misc/cgo/test/issue7234_test.go b/misc/cgo/test/issue7234_test.go
index 713dade..a020b6a 100644
--- a/misc/cgo/test/issue7234_test.go
+++ b/misc/cgo/test/issue7234_test.go
@@ -7,14 +7,14 @@ package cgotest
 import "testing"
 
 // This test actually doesn't have anything to do with cgo.  It is a
-// test of http://golang.org/issue/7234, a compiler/linker bug in
+// test of https://golang.org/issue/7234, a compiler/linker bug in
 // handling string constants when using -linkmode=external.  The test
 // is in this directory because we routinely test -linkmode=external
 // here.
 
 var v7234 = [...]string{"runtime/cgo"}
 
-func TestIssue7234(t *testing.T) {
+func Test7234(t *testing.T) {
 	if v7234[0] != "runtime/cgo" {
 		t.Errorf("bad string constant %q", v7234[0])
 	}
diff --git a/misc/cgo/test/issue7978.go b/misc/cgo/test/issue7978.go
index 5feed07..094ccc1 100644
--- a/misc/cgo/test/issue7978.go
+++ b/misc/cgo/test/issue7978.go
@@ -12,9 +12,23 @@ package cgotest
 
 void issue7978cb(void);
 
+#if defined(__APPLE__) && defined(__arm__)
+// on Darwin/ARM, libSystem doesn't provide implementation of the __sync_fetch_and_add
+// primitive, and although gcc supports it, it doesn't inline its definition.
+// Clang could inline its definition, so we require clang on Darwin/ARM.
+#if defined(__clang__)
+#define HAS_SYNC_FETCH_AND_ADD 1
+#else
+#define HAS_SYNC_FETCH_AND_ADD 0
+#endif
+#else
+#define HAS_SYNC_FETCH_AND_ADD 1
+#endif
+
 // use ugly atomic variable sync since that doesn't require calling back into
 // Go code or OS dependencies
 static void issue7978c(uint32_t *sync) {
+#if HAS_SYNC_FETCH_AND_ADD
 	while(__sync_fetch_and_add(sync, 0) != 0)
 		;
 	__sync_fetch_and_add(sync, 1);
@@ -24,6 +38,7 @@ static void issue7978c(uint32_t *sync) {
 	__sync_fetch_and_add(sync, 1);
 	while(__sync_fetch_and_add(sync, 0) != 6)
 		;
+#endif
 }
 */
 import "C"
@@ -82,6 +97,12 @@ func issue7978go() {
 }
 
 func test7978(t *testing.T) {
+	if runtime.Compiler == "gccgo" {
+		t.Skip("gccgo can not do stack traces of C code")
+	}
+	if C.HAS_SYNC_FETCH_AND_ADD == 0 {
+		t.Skip("clang required for __sync_fetch_and_add support on darwin/arm")
+	}
 	if os.Getenv("GOTRACEBACK") != "2" {
 		t.Fatalf("GOTRACEBACK must be 2")
 	}
@@ -89,13 +110,13 @@ func test7978(t *testing.T) {
 	go issue7978go()
 	// test in c code, before callback
 	issue7978wait(0, 1)
-	issue7978check(t, "runtime.cgocall_errno(", "", 1)
+	issue7978check(t, "runtime.cgocall(", "", 1)
 	// test in go code, during callback
 	issue7978wait(2, 3)
 	issue7978check(t, "test.issue7978cb(", "test.issue7978go", 3)
 	// test in c code, after callback
 	issue7978wait(4, 5)
-	issue7978check(t, "runtime.cgocall_errno(", "runtime.cgocallback", 1)
+	issue7978check(t, "runtime.cgocall(", "runtime.cgocallback", 1)
 	// test in go code, after return from cgo
 	issue7978wait(6, 7)
 	issue7978check(t, "test.issue7978go(", "", 3)
diff --git a/misc/cgo/test/issue8428.go b/misc/cgo/test/issue8428.go
index a3dc575..16fa7cc 100644
--- a/misc/cgo/test/issue8428.go
+++ b/misc/cgo/test/issue8428.go
@@ -20,6 +20,7 @@ struct issue8428two {
 	void *p;
 	char b;
 	char rest[0];
+	char pad;
 };
 
 struct issue8428three {
@@ -34,8 +35,10 @@ import "C"
 import "unsafe"
 
 var _ = C.struct_issue8428one{
-	b:    C.char(0),
-	rest: [0]C.char{},
+	b: C.char(0),
+	// The trailing rest field is not available in cgo.
+	// See issue 11925.
+	// rest: [0]C.char{},
 }
 
 var _ = C.struct_issue8428two{
diff --git a/misc/cgo/test/issue8945.go b/misc/cgo/test/issue8945.go
new file mode 100644
index 0000000..572b815
--- /dev/null
+++ b/misc/cgo/test/issue8945.go
@@ -0,0 +1,16 @@
+// 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 gccgo
+
+package cgotest
+
+//typedef void (*PFunc)();
+//PFunc success_cb;
+import "C"
+
+//export Test
+func Test() {
+	_ = C.success_cb
+}
diff --git a/misc/cgo/test/issue9400/asm_386.s b/misc/cgo/test/issue9400/asm_386.s
new file mode 100644
index 0000000..e37a54f
--- /dev/null
+++ b/misc/cgo/test/issue9400/asm_386.s
@@ -0,0 +1,26 @@
+// 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 !gccgo
+
+#include "textflag.h"
+
+TEXT ·RewindAndSetgid(SB),NOSPLIT,$0-0
+	// Rewind stack pointer so anything that happens on the stack
+	// will clobber the test pattern created by the caller
+	ADDL	$(1024 * 8), SP
+
+	// Ask signaller to setgid
+	MOVL	$1, ·Baton(SB)
+
+	// Wait for setgid completion
+loop:
+	PAUSE
+	MOVL	·Baton(SB), AX
+	CMPL	AX, $0
+	JNE	loop
+
+	// Restore stack
+	SUBL	$(1024 * 8), SP
+	RET
diff --git a/misc/cgo/test/issue9400/asm_amd64x.s b/misc/cgo/test/issue9400/asm_amd64x.s
new file mode 100644
index 0000000..f09e95d
--- /dev/null
+++ b/misc/cgo/test/issue9400/asm_amd64x.s
@@ -0,0 +1,27 @@
+// 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 amd64 amd64p32
+// +build !gccgo
+
+#include "textflag.h"
+
+TEXT ·RewindAndSetgid(SB),NOSPLIT,$0-0
+	// Rewind stack pointer so anything that happens on the stack
+	// will clobber the test pattern created by the caller
+	ADDQ	$(1024 * 8), SP
+
+	// Ask signaller to setgid
+	MOVL	$1, ·Baton(SB)
+
+	// Wait for setgid completion
+loop:
+	PAUSE
+	MOVL	·Baton(SB), AX
+	CMPL	AX, $0
+	JNE	loop
+
+	// Restore stack
+	SUBQ	$(1024 * 8), SP
+	RET
diff --git a/misc/cgo/test/issue9400/asm_arm.s b/misc/cgo/test/issue9400/asm_arm.s
new file mode 100644
index 0000000..5c5983d
--- /dev/null
+++ b/misc/cgo/test/issue9400/asm_arm.s
@@ -0,0 +1,39 @@
+// 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 !gccgo
+
+#include "textflag.h"
+
+TEXT cas<>(SB),NOSPLIT,$0
+	MOVW	$0xffff0fc0, R15 // R15 is PC
+
+TEXT ·RewindAndSetgid(SB),NOSPLIT,$-4-0
+	// Save link register
+	MOVW	R14, R4
+
+	// Rewind stack pointer so anything that happens on the stack
+	// will clobber the test pattern created by the caller
+	ADD	$(1024 * 8), R13
+
+	// Ask signaller to setgid
+	MOVW	$·Baton(SB), R2
+storeloop:
+	MOVW	0(R2), R0
+	MOVW	$1, R1
+	BL	cas<>(SB)
+	BCC	storeloop
+
+	// Wait for setgid completion
+loop:
+	MOVW	$0, R0
+	MOVW	$0, R1
+	BL	cas<>(SB)
+	BCC	loop
+
+	// Restore stack
+	SUB	$(1024 * 8), R13
+
+	MOVW	R4, R14
+	RET
diff --git a/misc/cgo/test/issue9400/asm_arm64.s b/misc/cgo/test/issue9400/asm_arm64.s
new file mode 100644
index 0000000..cba525f
--- /dev/null
+++ b/misc/cgo/test/issue9400/asm_arm64.s
@@ -0,0 +1,39 @@
+// 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 !gccgo
+
+#include "textflag.h"
+
+TEXT ·RewindAndSetgid(SB),NOSPLIT,$-8-0
+	// Save link register
+	MOVD	R30, R9
+
+	// Rewind stack pointer so anything that happens on the stack
+	// will clobber the test pattern created by the caller
+	ADD	$(1024 * 8), RSP
+
+	// Ask signaller to setgid
+	MOVD	$·Baton(SB), R0
+	MOVD	$1, R1
+storeloop:
+	LDAXRW	(R0), R2
+	STLXRW	R1, (R0), R3
+	CBNZ	R3, storeloop
+
+	// Wait for setgid completion
+	MOVW	$0, R1
+	MOVW	$0, R2
+loop:
+	LDAXRW	(R0), R3
+	CMPW	R1, R3
+	BNE	loop
+	STLXRW	R2, (R0), R3
+	CBNZ	R3, loop
+
+	// Restore stack
+	SUB	$(1024 * 8), RSP
+
+	MOVD	R9, R30
+	RET
diff --git a/misc/cgo/test/issue9400/asm_ppc64x.s b/misc/cgo/test/issue9400/asm_ppc64x.s
new file mode 100644
index 0000000..7dfe37e
--- /dev/null
+++ b/misc/cgo/test/issue9400/asm_ppc64x.s
@@ -0,0 +1,32 @@
+// 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 ppc64 ppc64le
+// +build !gccgo
+
+#include "textflag.h"
+
+TEXT ·RewindAndSetgid(SB),NOSPLIT,$-8-0
+	// Rewind stack pointer so anything that happens on the stack
+	// will clobber the test pattern created by the caller
+	ADD	$(1024 * 8), R1
+
+	// Ask signaller to setgid
+	MOVW	$1, R3
+	SYNC
+	MOVW	R3, ·Baton(SB)
+
+	// Wait for setgid completion
+loop:
+	SYNC
+	MOVW	·Baton(SB), R3
+	CMP	R3, $0
+	// Hint that we're in a spin loop
+	OR	R1, R1, R1
+	BNE	loop
+	ISYNC
+
+	// Restore stack
+	SUB	$(1024 * 8), R1
+	RET
diff --git a/misc/cgo/test/issue9400/gccgo.go b/misc/cgo/test/issue9400/gccgo.go
new file mode 100644
index 0000000..6b9d5fa
--- /dev/null
+++ b/misc/cgo/test/issue9400/gccgo.go
@@ -0,0 +1,24 @@
+// 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 gccgo
+
+package issue9400
+
+import (
+	"runtime"
+	"sync/atomic"
+)
+
+// The test for the gc compiler resets the stack pointer so that the
+// stack gets modified.  We don't have a way to do that for gccgo
+// without writing more assembly code, which we haven't bothered to
+// do.  So this is not much of a test.
+
+func RewindAndSetgid() {
+	atomic.StoreInt32(&Baton, 1)
+	for atomic.LoadInt32(&Baton) != 0 {
+		runtime.Gosched()
+	}
+}
diff --git a/misc/cgo/test/issue9400/stubs.go b/misc/cgo/test/issue9400/stubs.go
new file mode 100644
index 0000000..1dd8ccd
--- /dev/null
+++ b/misc/cgo/test/issue9400/stubs.go
@@ -0,0 +1,9 @@
+// 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 issue9400
+
+var Baton int32
+
+func RewindAndSetgid()
diff --git a/misc/cgo/test/issue9400_linux.go b/misc/cgo/test/issue9400_linux.go
new file mode 100644
index 0000000..b3b4b79
--- /dev/null
+++ b/misc/cgo/test/issue9400_linux.go
@@ -0,0 +1,58 @@
+// 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.
+
+// Test that SIGSETXID runs on signal stack, since it's likely to
+// overflow if it runs on the Go stack.
+
+package cgotest
+
+/*
+#include <sys/types.h>
+#include <unistd.h>
+*/
+import "C"
+
+import (
+	"runtime"
+	"sync/atomic"
+	"testing"
+
+	"./issue9400"
+)
+
+func test9400(t *testing.T) {
+	// We synchronize through a shared variable, so we need two procs
+	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(2))
+
+	// Start signaller
+	atomic.StoreInt32(&issue9400.Baton, 0)
+	go func() {
+		// Wait for RewindAndSetgid
+		for atomic.LoadInt32(&issue9400.Baton) == 0 {
+			runtime.Gosched()
+		}
+		// Broadcast SIGSETXID
+		runtime.LockOSThread()
+		C.setgid(0)
+		// Indicate that signalling is done
+		atomic.StoreInt32(&issue9400.Baton, 0)
+	}()
+
+	// Grow the stack and put down a test pattern
+	const pattern = 0x123456789abcdef
+	var big [1024]uint64 // len must match assmebly
+	for i := range big {
+		big[i] = pattern
+	}
+
+	// Temporarily rewind the stack and trigger SIGSETXID
+	issue9400.RewindAndSetgid()
+
+	// Check test pattern
+	for i := range big {
+		if big[i] != pattern {
+			t.Fatalf("entry %d of test pattern is wrong; %#x != %#x", i, big[i], uint64(pattern))
+		}
+	}
+}
diff --git a/misc/cgo/test/issue9557.go b/misc/cgo/test/issue9557.go
new file mode 100644
index 0000000..b29bacd
--- /dev/null
+++ b/misc/cgo/test/issue9557.go
@@ -0,0 +1,36 @@
+// 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.
+
+// cgo rewrote C.var to *_Cvar_var, but left
+// C.var.field as _Cvar.var.field.  It now rewrites
+// the latter as (*_Cvar_var).field.
+// See https://golang.org/issue/9557.
+
+package cgotest
+
+// struct issue9557_t {
+//   int a;
+// } test9557bar = { 42 };
+//
+// struct issue9557_t *issue9557foo = &test9557bar;
+import "C"
+import "testing"
+
+func test9557(t *testing.T) {
+	// implicitly dereference a Go variable
+	foo := C.issue9557foo
+	if v := foo.a; v != 42 {
+		t.Fatalf("foo.a expected 42, but got %d", v)
+	}
+
+	// explicitly dereference a C variable
+	if v := (*C.issue9557foo).a; v != 42 {
+		t.Fatalf("(*C.issue9557foo).a expected 42, but is %d", v)
+	}
+
+	// implicitly dereference a C variable
+	if v := C.issue9557foo.a; v != 42 {
+		t.Fatalf("C.issue9557foo.a expected 42, but is %d", v)
+	}
+}
diff --git a/misc/cgo/test/setgid_linux.go b/misc/cgo/test/setgid_linux.go
index 829afce..197f01f 100644
--- a/misc/cgo/test/setgid_linux.go
+++ b/misc/cgo/test/setgid_linux.go
@@ -3,7 +3,7 @@
 // license that can be found in the LICENSE file.
 
 // Test that setgid does not hang on GNU/Linux.
-// See http://code.google.com/p/go/issues/detail?id=3871 for details.
+// See https://golang.org/issue/3871 for details.
 
 package cgotest
 
diff --git a/misc/cgo/test/sigprocmask_linux.c b/misc/cgo/test/sigprocmask_linux.c
new file mode 100644
index 0000000..518c533
--- /dev/null
+++ b/misc/cgo/test/sigprocmask_linux.c
@@ -0,0 +1,36 @@
+// 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 <signal.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <unistd.h>
+
+extern void IntoGoAndBack();
+
+int CheckBlocked() {
+	sigset_t mask;
+	sigprocmask(SIG_BLOCK, NULL, &mask);
+	return sigismember(&mask, SIGIO);
+}
+
+static void* sigthreadfunc(void* unused) {
+	sigset_t mask;
+	sigemptyset(&mask);
+	sigaddset(&mask, SIGIO);
+	sigprocmask(SIG_BLOCK, &mask, NULL);
+	IntoGoAndBack();
+	return NULL;
+}
+
+int RunSigThread() {
+	pthread_t thread;
+	int r;
+
+	r = pthread_create(&thread, NULL, &sigthreadfunc, NULL);
+	if (r != 0)
+		return r;
+	return pthread_join(thread, NULL);
+}
diff --git a/misc/cgo/test/sigprocmask_linux.go b/misc/cgo/test/sigprocmask_linux.go
new file mode 100644
index 0000000..7d343e9
--- /dev/null
+++ b/misc/cgo/test/sigprocmask_linux.go
@@ -0,0 +1,38 @@
+// 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 cgotest
+
+/*
+#cgo CFLAGS: -pthread
+#cgo LDFLAGS: -pthread
+extern int RunSigThread();
+extern int CheckBlocked();
+*/
+import "C"
+import (
+	"os"
+	"os/signal"
+	"syscall"
+	"testing"
+)
+
+var blocked bool
+
+//export IntoGoAndBack
+func IntoGoAndBack() {
+	// Verify that SIGIO stays blocked on the C thread
+	// even when unblocked for signal.Notify().
+	signal.Notify(make(chan os.Signal), syscall.SIGIO)
+	blocked = C.CheckBlocked() != 0
+}
+
+func testSigProcMask(t *testing.T) {
+	if r := C.RunSigThread(); r != 0 {
+		t.Error("pthread_create/pthread_join failed")
+	}
+	if !blocked {
+		t.Error("Go runtime unblocked SIGIO")
+	}
+}
diff --git a/misc/cgo/testcarchive/main.c b/misc/cgo/testcarchive/main.c
new file mode 100644
index 0000000..cc3170d
--- /dev/null
+++ b/misc/cgo/testcarchive/main.c
@@ -0,0 +1,34 @@
+// 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 <stdint.h>
+#include <stdio.h>
+
+#include "p.h"
+#include "libgo.h"
+
+int main(void) {
+	int32_t res;
+
+	if (!DidInitRun()) {
+		fprintf(stderr, "ERROR: buildmode=c-archive init should run\n");
+		return 2;
+	}
+
+	if (DidMainRun()) {
+		fprintf(stderr, "ERROR: buildmode=c-archive should not run main\n");
+		return 2;
+	}
+
+	res = FromPkg();
+	if (res != 1024) {
+		fprintf(stderr, "ERROR: FromPkg()=%d, want 1024\n", res);
+		return 2;
+	}
+
+	CheckArgs();
+
+	fprintf(stderr, "PASS\n");
+	return 0;
+}
diff --git a/misc/cgo/testcarchive/src/libgo/libgo.go b/misc/cgo/testcarchive/src/libgo/libgo.go
new file mode 100644
index 0000000..45958a5
--- /dev/null
+++ b/misc/cgo/testcarchive/src/libgo/libgo.go
@@ -0,0 +1,53 @@
+// 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 (
+	"fmt"
+	"os"
+	"syscall"
+	"time"
+
+	_ "p"
+)
+
+import "C"
+
+var initCh = make(chan int, 1)
+var ranMain bool
+
+func init() {
+	// emulate an exceedingly slow package initialization function
+	time.Sleep(100 * time.Millisecond)
+	initCh <- 42
+}
+
+func main() { ranMain = true }
+
+//export DidInitRun
+func DidInitRun() bool {
+	select {
+	case x := <-initCh:
+		if x != 42 {
+			// Just in case initCh was not correctly made.
+			println("want init value of 42, got: ", x)
+			syscall.Exit(2)
+		}
+		return true
+	default:
+		return false
+	}
+}
+
+//export DidMainRun
+func DidMainRun() bool { return ranMain }
+
+//export CheckArgs
+func CheckArgs() {
+	if len(os.Args) != 3 || os.Args[1] != "arg1" || os.Args[2] != "arg2" {
+		fmt.Printf("CheckArgs: want [_, arg1, arg2], got: %v\n", os.Args)
+		os.Exit(2)
+	}
+}
diff --git a/misc/cgo/testcarchive/src/p/p.go b/misc/cgo/testcarchive/src/p/p.go
new file mode 100644
index 0000000..82b445c
--- /dev/null
+++ b/misc/cgo/testcarchive/src/p/p.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.
+
+package p
+
+import "C"
+
+//export FromPkg
+func FromPkg() int32 { return 1024 }
diff --git a/misc/cgo/testcarchive/test.bash b/misc/cgo/testcarchive/test.bash
new file mode 100755
index 0000000..89b761b
--- /dev/null
+++ b/misc/cgo/testcarchive/test.bash
@@ -0,0 +1,44 @@
+#!/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.
+
+set -e
+
+ccargs=
+if [ "$(go env GOOS)" == "darwin" ]; then
+	ccargs="-Wl,-no_pie"
+	# For darwin/arm.
+	# TODO(crawshaw): Can we do better?
+	ccargs="$ccargs -framework CoreFoundation -framework Foundation"
+fi
+ccargs="$ccargs -I pkg/$(go env GOOS)_$(go env GOARCH)"
+
+# TODO(crawshaw): Consider a go env for exec script name.
+bin=./testp
+exec_script=go_$(go env GOOS)_$(go env GOARCH)_exec
+if [ "$(which $exec_script)" != "" ]; then
+	bin="$exec_script ./testp"
+fi
+
+rm -rf libgo.a libgo.h testp pkg
+
+# Installing first will create the header files we want.
+
+GOPATH=$(pwd) go install -buildmode=c-archive libgo
+$(go env CC) $(go env GOGCCFLAGS) $ccargs -o testp main.c pkg/$(go env GOOS)_$(go env GOARCH)/libgo.a
+$bin arg1 arg2
+rm -f libgo.a libgo.h testp
+
+# Test building libgo other than installing it.
+# Header files are now present.
+
+GOPATH=$(pwd) go build -buildmode=c-archive src/libgo/libgo.go
+$(go env CC) $(go env GOGCCFLAGS) $ccargs -o testp main.c libgo.a
+$bin arg1 arg2
+rm -f libgo.a libgo.h testp
+
+GOPATH=$(pwd) go build -buildmode=c-archive -o libgo.a libgo
+$(go env CC) $(go env GOGCCFLAGS) $ccargs -o testp main.c libgo.a
+$bin arg1 arg2
+rm -rf libgo.a libgo.h testp pkg
diff --git a/misc/cgo/testcdefs/cdefstest.c b/misc/cgo/testcdefs/cdefstest.c
deleted file mode 100644
index ce670e7..0000000
--- a/misc/cgo/testcdefs/cdefstest.c
+++ /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.
-
-#include "runtime.h"
-#include "cdefstest.h"
-
-struct CdefsTest test;
-struct PackedTest packed;
diff --git a/misc/cgo/testcdefs/cdefstest.go b/misc/cgo/testcdefs/cdefstest.go
deleted file mode 100644
index 5e613c7..0000000
--- a/misc/cgo/testcdefs/cdefstest.go
+++ /dev/null
@@ -1,60 +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.
-//
-// +build ignore
-
-package cgotest
-
-/*
-// This file tests a bug found in the cgo -cdefs tool that incorrectly
-// translated Go pointer arrays generated by the cgo godefs tool back into C
-// pointer arrays.
-//
-// The comments below show how the type is translated from gcc-style C into Go
-// and back into C for both the buggy version and the correct version
-
-struct cdefsTest {
-	// This was already being handled correctly
-	// Correct: -> Array [20]int8 -> int8 array[20]
-	char array1[20];
-
-	// Buggy:   -> Array [20][20]int8 -> [20]int8 array[20]
-	// Correct: -> Array [20][20]int8 -> int8 array[20][20]
-	char array2[20][20];
-
-	// Buggy:   -> Array [20]*int8 -> *int8 array[20]
-	// Correct: -> Array [20]*int8 -> int8 *array[20]
-	char *array3[20];
-
-	// Buggy:   -> Array [20][20]*int8 -> [20]*int8 array[20]
-	// Correct: -> Array [20]**int8 -> int8 *array[20][20]
-	char *array4[20][20];
-
-	// Buggy:   -> Array [20][20]**int8 -> [20]**int8 array[20]
-	// Correct: -> Array [20][20]**int8 -> int8 **array[20][20]
-	char **array5[20][20];
-};
-
-// Test that packed structures can be translated to C correctly too.
-// See issue 8477.
-
-struct packedTest {
-	char first;
-	int second;
-	long long third;
-} __attribute__((packed));
-
-// Test that conflicting type definitions don't cause problems with cgo.
-// See issue 8477.
-
-typedef struct timespec {
-	double bogus;
-} pid_t;
-
-*/
-import "C"
-
-type CdefsTest C.struct_cdefsTest
-
-//type PackedTest C.struct_packedTest
diff --git a/misc/cgo/testcdefs/main.c b/misc/cgo/testcdefs/main.c
deleted file mode 100644
index 594a431..0000000
--- a/misc/cgo/testcdefs/main.c
+++ /dev/null
@@ -1,76 +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.
-
-#include "runtime.h"
-#include "cdefstest.h"
-
-void runtime·printf(int8*, ...);
-
-// From cdefstest.go.
-typedef struct CdefsOrig CdefsOrig;
-struct CdefsOrig {
-	int8 array1[20];
-	int8 array2[20][20];
-	int8 *array3[20];
-	int8 *array4[20][20];
-	int8 **array5[20][20];
-};
-
-// Packed structs are no longer supported for -cdefs.
-/*
-typedef struct PackedOrig PackedOrig;
-#pragma pack on
-struct PackedOrig {
-	int8 first;
-	int32 second;
-	int64 third;
-};
-#pragma pack off
-*/
-
-void
-main·test(int32 ret)
-{
-	CdefsOrig o;
-	CdefsTest t;
-	// PackedOrig po;
-	// PackedTest pt;
-	
-	ret = 0;
-	if(sizeof(t.array1) != sizeof(o.array1) || offsetof(CdefsTest, array1[0]) != offsetof(CdefsOrig, array1[0])) {
-		runtime·printf("array1: size, offset = %d, %d, want %d, %d\n", sizeof(t.array1), offsetof(CdefsTest, array1[0]), sizeof(o.array1), offsetof(CdefsOrig, array1[0]));
-		ret = 1;
-	}
-	if(sizeof(t.array2) != sizeof(o.array2) || offsetof(CdefsTest, array2[0][0]) != offsetof(CdefsOrig, array2[0][0])) {
-		runtime·printf("array2: size, offset = %d, %d, want %d, %d\n", sizeof(t.array2), offsetof(CdefsTest, array2[0][0]), sizeof(o.array2), offsetof(CdefsOrig, array2[0][0]));
-		ret = 1;
-	}
-	if(sizeof(t.array3) != sizeof(o.array3) || offsetof(CdefsTest, array3[0]) != offsetof(CdefsOrig, array3[0])) {
-		runtime·printf("array3: size, offset = %d, %d, want %d, %d\n", sizeof(t.array3), offsetof(CdefsTest, array3[0]), sizeof(o.array3), offsetof(CdefsOrig, array3[0]));
-		ret = 1;
-	}
-	if(sizeof(t.array4) != sizeof(o.array4) || offsetof(CdefsTest, array4[0][0]) != offsetof(CdefsOrig, array4[0][0])) {
-		runtime·printf("array4: size, offset = %d, %d, want %d, %d\n", sizeof(t.array4), offsetof(CdefsTest, array4[0][0]), sizeof(o.array4), offsetof(CdefsOrig, array4[0][0]));
-		ret = 1;
-	}
-	if(sizeof(t.array5) != sizeof(o.array5) || offsetof(CdefsTest, array5[0][0]) != offsetof(CdefsOrig, array5[0][0])) {
-		runtime·printf("array5: size, offset = %d, %d, want %d, %d\n", sizeof(t.array5), offsetof(CdefsTest, array5[0][0]), sizeof(o.array5), offsetof(CdefsOrig, array5[0][0]));
-		ret = 1;
-	}
-/*
-	if(sizeof(pt.first) != sizeof(po.first) || offsetof(PackedTest, first) != offsetof(PackedOrig, first)) {
-		runtime·printf("first: size, offset = %d, %d, want %d, %d\n", sizeof(pt.first), offsetof(PackedTest, first), sizeof(po.first), offsetof(PackedOrig, first));
-		ret = 1;
-	}
-	if(sizeof(pt.second) != sizeof(po.second) || offsetof(PackedTest, second) != offsetof(PackedOrig, second)) {
-		runtime·printf("second: size, offset = %d, %d, want %d, %d\n", sizeof(pt.second), offsetof(PackedTest, second), sizeof(po.second), offsetof(PackedOrig, second));
-		ret = 1;
-	}
-	if(sizeof(pt.third) != sizeof(po.third) || offsetof(PackedTest, third) != offsetof(PackedOrig, third)) {
-		runtime·printf("third: size, offset = %d, %d, want %d, %d\n", sizeof(pt.third), offsetof(PackedTest, third), sizeof(po.third), offsetof(PackedOrig, third));
-		ret = 1;
-	}
-*/
-	FLUSH(&ret); // flush return value
-}
diff --git a/misc/cgo/testcdefs/main.go b/misc/cgo/testcdefs/main.go
deleted file mode 100644
index 9231741..0000000
--- a/misc/cgo/testcdefs/main.go
+++ /dev/null
@@ -1,13 +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 main
-
-import "os"
-
-func test() int32 // in main.c
-
-func main() {
-	os.Exit(int(test()))
-}
diff --git a/misc/cgo/testcdefs/test.bash b/misc/cgo/testcdefs/test.bash
deleted file mode 100755
index 01621a4..0000000
--- a/misc/cgo/testcdefs/test.bash
+++ /dev/null
@@ -1,16 +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.
-
-# Just add issue file prefixes to this list if more issues come up
-FILE_PREFIXES="cdefstest"
-
-for FP in $FILE_PREFIXES
-do 
-  go tool cgo -cdefs ${FP}.go > ${FP}.h
-done
-
-go build . && ./testcdefs
-EXIT=$?
-rm -rf _obj testcdefs *.h
-exit $EXIT
diff --git a/misc/cgo/testcshared/main0.c b/misc/cgo/testcshared/main0.c
new file mode 100644
index 0000000..1274b89
--- /dev/null
+++ b/misc/cgo/testcshared/main0.c
@@ -0,0 +1,36 @@
+// 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 <stdint.h>
+#include <stdio.h>
+
+#include "p.h"
+#include "libgo.h"
+
+// Tests libgo.so to export the following functions.
+//   int8_t DidInitRun();
+//   int8_t DidMainRun();
+//   int32_t FromPkg();
+int main(void) {
+  int8_t ran_init = DidInitRun();
+  if (!ran_init) {
+    fprintf(stderr, "ERROR: DidInitRun returned unexpected results: %d\n",
+            ran_init);
+    return 1;
+  }
+  int8_t ran_main = DidMainRun();
+  if (ran_main) {
+    fprintf(stderr, "ERROR: DidMainRun returned unexpected results: %d\n",
+            ran_main);
+    return 1;
+  }
+  int32_t from_pkg = FromPkg();
+  if (from_pkg != 1024) {
+    fprintf(stderr, "ERROR: FromPkg=%d, want %d\n", from_pkg, 1024);
+    return 1;
+  }
+  // test.bash looks for "PASS" to ensure this program has reached the end. 
+  printf("PASS\n");
+  return 0;
+}
diff --git a/misc/cgo/testcshared/main1.c b/misc/cgo/testcshared/main1.c
new file mode 100644
index 0000000..420dd1e
--- /dev/null
+++ b/misc/cgo/testcshared/main1.c
@@ -0,0 +1,69 @@
+// 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 <stdint.h>
+#include <stdio.h>
+#include <dlfcn.h>
+
+int check_int8(void* handle, const char* fname, int8_t want) {
+  int8_t (*fn)();
+  fn = (int8_t (*)())dlsym(handle, fname);
+  if (!fn) {
+    fprintf(stderr, "ERROR: missing %s: %s\n", fname, dlerror());
+    return 1;
+  }
+  signed char ret = fn();
+  if (ret != want) {
+    fprintf(stderr, "ERROR: %s=%d, want %d\n", fname, ret, want);
+    return 1;
+  }
+  return 0;
+}
+
+int check_int32(void* handle, const char* fname, int32_t want) {
+  int32_t (*fn)();
+  fn = (int32_t (*)())dlsym(handle, fname);
+  if (!fn) {
+    fprintf(stderr, "ERROR: missing %s: %s\n", fname, dlerror());
+    return 1;
+  }
+  int32_t ret = fn();
+  if (ret != want) {
+    fprintf(stderr, "ERROR: %s=%d, want %d\n", fname, ret, want);
+    return 1;
+  }
+  return 0;
+}
+
+// Tests libgo.so to export the following functions.
+//   int8_t DidInitRun() // returns true
+//   int8_t DidMainRun() // returns true
+//   int32_t FromPkg() // returns 1024
+int main(int argc, char** argv) {
+  void* handle = dlopen(argv[1], RTLD_LAZY | RTLD_GLOBAL);
+  if (!handle) {
+    fprintf(stderr, "ERROR: failed to open the shared library: %s\n",
+		    dlerror());
+    return 2;
+  }
+
+  int ret = 0;
+  ret = check_int8(handle, "DidInitRun", 1);
+  if (ret != 0) {
+    return ret;
+  }
+
+  ret = check_int8(handle, "DidMainRun", 0);
+  if (ret != 0) {
+    return ret;
+  }
+
+  ret = check_int32(handle, "FromPkg", 1024);
+  if (ret != 0) {
+   return ret;
+  }
+  // test.bash looks for "PASS" to ensure this program has reached the end. 
+  printf("PASS\n");
+  return 0;
+}
diff --git a/misc/cgo/testcshared/main2.c b/misc/cgo/testcshared/main2.c
new file mode 100644
index 0000000..4023383
--- /dev/null
+++ b/misc/cgo/testcshared/main2.c
@@ -0,0 +1,56 @@
+// 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 <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#define fd (10)
+
+// Tests libgo2.so, which does not export any functions.
+// Read a string from the file descriptor and print it.
+int main(void) {
+  int i;
+  ssize_t n;
+  char buf[20];
+  struct timespec ts;
+
+  // The descriptor will be initialized in a thread, so we have to
+  // give a chance to get opened.
+  for (i = 0; i < 100; i++) {
+    n = read(fd, buf, sizeof buf);
+    if (n >= 0)
+      break;
+    if (errno != EBADF) {
+      fprintf(stderr, "BUG: read: %s\n", strerror(errno));
+      return 2;
+    }
+
+    // An EBADF error means that the shared library has not opened the
+    // descriptor yet.
+    ts.tv_sec = 0;
+    ts.tv_nsec = 1000000;
+    nanosleep(&ts, NULL);
+  }
+
+  if (n < 0) {
+    fprintf(stderr, "BUG: failed to read any data from pipe\n");
+    return 2;
+  }
+
+  if (n == 0) {
+    fprintf(stderr, "BUG: unexpected EOF\n");
+    return 2;
+  }
+
+  if (n == sizeof buf) {
+    n--;
+  }
+  buf[n] = '\0';
+  printf("%s\n", buf);
+  return 0;
+}
diff --git a/misc/cgo/testcshared/main3.c b/misc/cgo/testcshared/main3.c
new file mode 100644
index 0000000..49cc055
--- /dev/null
+++ b/misc/cgo/testcshared/main3.c
@@ -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.
+
+#include <stdint.h>
+#include <stdio.h>
+#include <dlfcn.h>
+
+// Tests "main.main" is exported on android/arm,
+// which golang.org/x/mobile/app depends on.
+int main(int argc, char** argv) {
+  void* handle = dlopen(argv[1], RTLD_LAZY | RTLD_GLOBAL);
+  if (!handle) {
+    fprintf(stderr, "ERROR: failed to open the shared library: %s\n",
+            dlerror());
+    return 2;
+  }
+
+  uintptr_t main_fn = (uintptr_t)dlsym(handle, "main.main");
+  if (!main_fn) {
+    fprintf(stderr, "ERROR: missing main.main: %s\n", dlerror());
+    return 2;
+  }
+
+  // TODO(hyangah): check that main.main can run.
+
+  printf("PASS\n");
+  return 0;
+}
diff --git a/misc/cgo/testcshared/src/libgo/libgo.go b/misc/cgo/testcshared/src/libgo/libgo.go
new file mode 100644
index 0000000..8a4bf79
--- /dev/null
+++ b/misc/cgo/testcshared/src/libgo/libgo.go
@@ -0,0 +1,46 @@
+// 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 (
+	_ "p"
+	"syscall"
+	"time"
+)
+
+import "C"
+
+var initCh = make(chan int, 1)
+var ranMain bool
+
+func init() {
+	// emulate an exceedingly slow package initialization function
+	time.Sleep(100 * time.Millisecond)
+	initCh <- 42
+}
+
+func main() {
+	ranMain = true
+}
+
+//export DidInitRun
+func DidInitRun() bool {
+	select {
+	case x := <-initCh:
+		if x != 42 {
+			// Just in case initCh was not correctly made.
+			println("want init value of 42, got: ", x)
+			syscall.Exit(2)
+		}
+		return true
+	default:
+		return false
+	}
+}
+
+//export DidMainRun
+func DidMainRun() bool {
+	return ranMain
+}
diff --git a/misc/cgo/testcshared/src/libgo2/libgo2.go b/misc/cgo/testcshared/src/libgo2/libgo2.go
new file mode 100644
index 0000000..6096860
--- /dev/null
+++ b/misc/cgo/testcshared/src/libgo2/libgo2.go
@@ -0,0 +1,52 @@
+// 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 main
+
+// Test a shared library created by -buildmode=c-shared that does not
+// export anything.
+
+import (
+	"fmt"
+	"os"
+	"syscall"
+)
+
+// To test this we want to communicate between the main program and
+// the shared library without using any exported symbols.  The init
+// function creates a pipe and Dups the read end to a known number
+// that the C code can also use.
+
+const (
+	fd = 10
+)
+
+func init() {
+	var p [2]int
+	if e := syscall.Pipe(p[0:]); e != nil {
+		fmt.Fprintf(os.Stderr, "pipe: %v\n", e)
+		os.Exit(2)
+	}
+
+	if e := syscall.Dup2(p[0], fd); e != nil {
+		fmt.Fprintf(os.Stderr, "dup2: %v\n", e)
+		os.Exit(2)
+	}
+
+	const str = "PASS"
+	if n, e := syscall.Write(p[1], []byte(str)); e != nil || n != len(str) {
+		fmt.Fprintf(os.Stderr, "write: %d %v\n", n, e)
+		os.Exit(2)
+	}
+
+	if e := syscall.Close(p[1]); e != nil {
+		fmt.Fprintf(os.Stderr, "close: %v\n", e)
+		os.Exit(2)
+	}
+}
+
+func main() {
+}
diff --git a/misc/cgo/testcshared/src/p/p.go b/misc/cgo/testcshared/src/p/p.go
new file mode 100644
index 0000000..82b445c
--- /dev/null
+++ b/misc/cgo/testcshared/src/p/p.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.
+
+package p
+
+import "C"
+
+//export FromPkg
+func FromPkg() int32 { return 1024 }
diff --git a/misc/cgo/testcshared/test.bash b/misc/cgo/testcshared/test.bash
new file mode 100755
index 0000000..57221bc
--- /dev/null
+++ b/misc/cgo/testcshared/test.bash
@@ -0,0 +1,129 @@
+#!/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 Android, this script requires adb to push and run compiled
+# binaries on a target device.
+
+set -e
+
+if [ ! -f src/libgo/libgo.go ]; then
+	cwd=$(pwd)
+	echo 'misc/cgo/testcshared/test.bash is running in $cwd' 1>&2
+	exit 1
+fi
+
+goos=$(go env GOOS)
+goarch=$(go env GOARCH)
+
+# Directory where cgo headers and outputs will be installed.
+# The installation directory format varies depending on the platform.
+installdir=pkg/${goos}_${goarch}_testcshared_shared
+if [ "${goos}/${goarch}" == "android/arm" ] || [ "${goos}/${goarch}" == "darwin/amd64" ]; then
+	installdir=pkg/${goos}_${goarch}_testcshared
+fi
+
+# Temporary directory on the android device.
+androidpath=/data/local/tmp/testcshared-$$
+
+function cleanup() {
+	rm -rf libgo.$libext libgo2.$libext libgo.h testp testp2 testp3 pkg
+
+	rm -rf $(go env GOROOT)/${installdir}
+
+	if [ "$goos" == "android" ]; then
+		adb shell rm -rf $androidpath
+	fi
+}
+trap cleanup EXIT
+
+if [ "$goos" == "android" ]; then
+	adb shell mkdir -p "$androidpath"
+fi
+
+function run() {
+	case "$goos" in
+	"android")
+		local args=$@
+		output=$(adb shell "cd ${androidpath}; $@")
+		output=$(echo $output|tr -d '\r')
+		case $output in
+			*PASS) echo "PASS";; 
+			*) echo "$output";;
+		esac
+		;;
+	*)
+		echo $(env $@)
+		;;
+	esac
+}
+
+function binpush() {
+	bin=${1}
+	if [ "$goos" == "android" ]; then
+		adb push "$bin"  "${androidpath}/${bin}" 2>/dev/null
+	fi
+}
+
+rm -rf pkg
+
+suffix="-installsuffix testcshared"
+
+libext="so"
+if [ "$goos" == "darwin" ]; then
+	libext="dylib"
+fi
+
+# Create the header files.
+GOPATH=$(pwd) go install -buildmode=c-shared $suffix libgo
+
+GOPATH=$(pwd) go build -buildmode=c-shared $suffix -o libgo.$libext src/libgo/libgo.go
+binpush libgo.$libext
+
+# test0: exported symbols in shared lib are accessible.
+# TODO(iant): using _shared here shouldn't really be necessary.
+$(go env CC) $(go env GOGCCFLAGS) -I ${installdir} -o testp main0.c libgo.$libext
+binpush testp
+
+output=$(run LD_LIBRARY_PATH=. ./testp)
+if [ "$output" != "PASS" ]; then
+	echo "FAIL test0 got ${output}"
+	exit 1
+fi
+
+# test1: shared library can be dynamically loaded and exported symbols are accessible.
+$(go env CC) $(go env GOGCCFLAGS) -o testp main1.c -ldl
+binpush testp
+output=$(run ./testp ./libgo.$libext)
+if [ "$output" != "PASS" ]; then
+	echo "FAIL test1 got ${output}"
+	exit 1
+fi
+
+# test2: tests libgo2 which does not export any functions.
+GOPATH=$(pwd) go build -buildmode=c-shared $suffix -o libgo2.$libext src/libgo2/libgo2.go
+binpush libgo2.$libext
+linkflags="-Wl,--no-as-needed"
+if [ "$goos" == "darwin" ]; then
+	linkflags=""
+fi
+$(go env CC) $(go env GOGCCFLAGS) -o testp2 main2.c $linkflags libgo2.$libext
+binpush testp2
+output=$(run LD_LIBRARY_PATH=. ./testp2)
+if [ "$output" != "PASS" ]; then
+	echo "FAIL test2 got ${output}"
+	exit 1
+fi
+
+# test3: tests main.main is exported on android.
+if [ "$goos" == "android" ]; then
+	$(go env CC) $(go env GOGCCFLAGS) -o testp3 main3.c -ldl
+	binpush testp3
+	output=$(run ./testp ./libgo.so)
+	if [ "$output" != "PASS" ]; then
+		echo "FAIL test3 got ${output}"
+		exit 1
+	fi
+fi
+echo "ok"
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/testshared/shared_test.go b/misc/cgo/testshared/shared_test.go
new file mode 100644
index 0000000..6ef448c
--- /dev/null
+++ b/misc/cgo/testshared/shared_test.go
@@ -0,0 +1,674 @@
+// 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 shared_test
+
+import (
+	"bufio"
+	"bytes"
+	"debug/elf"
+	"encoding/binary"
+	"errors"
+	"flag"
+	"fmt"
+	"go/build"
+	"io"
+	"io/ioutil"
+	"log"
+	"math/rand"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"regexp"
+	"strings"
+	"testing"
+	"time"
+)
+
+var gopathInstallDir, gorootInstallDir, suffix string
+
+// This is the smallest set of packages we can link into a shared
+// library (runtime/cgo is built implicitly).
+var minpkgs = []string{"runtime", "sync/atomic"}
+var soname = "libruntime,sync-atomic.so"
+
+// run runs a command and calls t.Errorf if it fails.
+func run(t *testing.T, msg string, args ...string) {
+	c := exec.Command(args[0], args[1:]...)
+	if output, err := c.CombinedOutput(); err != nil {
+		t.Errorf("executing %s (%s) failed %s:\n%s", strings.Join(args, " "), msg, err, output)
+	}
+}
+
+// goCmd invokes the go tool with the installsuffix set up by TestMain. It calls
+// t.Errorf if the command fails.
+func goCmd(t *testing.T, args ...string) {
+	newargs := []string{args[0], "-installsuffix=" + suffix}
+	if testing.Verbose() {
+		newargs = append(newargs, "-v")
+	}
+	newargs = append(newargs, args[1:]...)
+	c := exec.Command("go", newargs...)
+	var output []byte
+	var err error
+	if testing.Verbose() {
+		fmt.Printf("+ go %s\n", strings.Join(newargs, " "))
+		c.Stdout = os.Stdout
+		c.Stderr = os.Stderr
+		err = c.Run()
+	} else {
+		output, err = c.CombinedOutput()
+	}
+	if err != nil {
+		if t != nil {
+			t.Errorf("executing %s failed %v:\n%s", strings.Join(c.Args, " "), err, output)
+		} else {
+			log.Fatalf("executing %s failed %v:\n%s", strings.Join(c.Args, " "), err, output)
+		}
+	}
+}
+
+// TestMain calls testMain so that the latter can use defer (TestMain exits with os.Exit).
+func testMain(m *testing.M) (int, error) {
+	// Because go install -buildmode=shared $standard_library_package always
+	// installs into $GOROOT, here are some gymnastics to come up with a unique
+	// installsuffix to use in this test that we can clean up afterwards.
+	myContext := build.Default
+	runtimeP, err := myContext.Import("runtime", ".", build.ImportComment)
+	if err != nil {
+		return 0, fmt.Errorf("import failed: %v", err)
+	}
+	for i := 0; i < 10000; i++ {
+		try := fmt.Sprintf("%s_%d_dynlink", runtimeP.PkgTargetRoot, rand.Int63())
+		err = os.Mkdir(try, 0700)
+		if os.IsExist(err) {
+			continue
+		}
+		if err == nil {
+			gorootInstallDir = try
+		}
+		break
+	}
+	if err != nil {
+		return 0, fmt.Errorf("can't create temporary directory: %v", err)
+	}
+	if gorootInstallDir == "" {
+		return 0, errors.New("could not create temporary directory after 10000 tries")
+	}
+	defer os.RemoveAll(gorootInstallDir)
+
+	// Some tests need to edit the source in GOPATH, so copy this directory to a
+	// temporary directory and chdir to that.
+	scratchDir, err := ioutil.TempDir("", "testshared")
+	if err != nil {
+		return 0, fmt.Errorf("TempDir failed: %v", err)
+	}
+	defer os.RemoveAll(scratchDir)
+	err = filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
+		scratchPath := filepath.Join(scratchDir, path)
+		if info.IsDir() {
+			if path == "." {
+				return nil
+			}
+			return os.Mkdir(scratchPath, info.Mode())
+		} else {
+			fromBytes, err := ioutil.ReadFile(path)
+			if err != nil {
+				return err
+			}
+			return ioutil.WriteFile(scratchPath, fromBytes, info.Mode())
+		}
+	})
+	if err != nil {
+		return 0, fmt.Errorf("walk failed: %v", err)
+	}
+	os.Setenv("GOPATH", scratchDir)
+	myContext.GOPATH = scratchDir
+	os.Chdir(scratchDir)
+
+	// All tests depend on runtime being built into a shared library. Because
+	// that takes a few seconds, do it here and have all tests use the version
+	// built here.
+	suffix = strings.Split(filepath.Base(gorootInstallDir), "_")[2]
+	goCmd(nil, append([]string{"install", "-buildmode=shared"}, minpkgs...)...)
+
+	myContext.InstallSuffix = suffix + "_dynlink"
+	depP, err := myContext.Import("dep", ".", build.ImportComment)
+	if err != nil {
+		return 0, fmt.Errorf("import failed: %v", err)
+	}
+	gopathInstallDir = depP.PkgTargetRoot
+	return m.Run(), nil
+}
+
+func TestMain(m *testing.M) {
+	// Some of the tests install binaries into a custom GOPATH.
+	// That won't work if GOBIN is set.
+	os.Unsetenv("GOBIN")
+
+	flag.Parse()
+	exitCode, err := testMain(m)
+	if err != nil {
+		log.Fatal(err)
+	}
+	os.Exit(exitCode)
+}
+
+// The shared library was built at the expected location.
+func TestSOBuilt(t *testing.T) {
+	_, err := os.Stat(filepath.Join(gorootInstallDir, soname))
+	if err != nil {
+		t.Error(err)
+	}
+}
+
+// The install command should have created a "shlibname" file for the
+// listed packages (and runtime/cgo) indicating the name of the shared
+// library containing it.
+func TestShlibnameFiles(t *testing.T) {
+	pkgs := append([]string{}, minpkgs...)
+	pkgs = append(pkgs, "runtime/cgo")
+	for _, pkg := range pkgs {
+		shlibnamefile := filepath.Join(gorootInstallDir, pkg+".shlibname")
+		contentsb, err := ioutil.ReadFile(shlibnamefile)
+		if err != nil {
+			t.Errorf("error reading shlibnamefile for %s: %v", pkg, err)
+			continue
+		}
+		contents := strings.TrimSpace(string(contentsb))
+		if contents != soname {
+			t.Errorf("shlibnamefile for %s has wrong contents: %q", pkg, contents)
+		}
+	}
+}
+
+// Is a given offset into the file contained in a loaded segment?
+func isOffsetLoaded(f *elf.File, offset uint64) bool {
+	for _, prog := range f.Progs {
+		if prog.Type == elf.PT_LOAD {
+			if prog.Off <= offset && offset < prog.Off+prog.Filesz {
+				return true
+			}
+		}
+	}
+	return false
+}
+
+func rnd(v int32, r int32) int32 {
+	if r <= 0 {
+		return v
+	}
+	v += r - 1
+	c := v % r
+	if c < 0 {
+		c += r
+	}
+	v -= c
+	return v
+}
+
+func readwithpad(r io.Reader, sz int32) ([]byte, error) {
+	data := make([]byte, rnd(sz, 4))
+	_, err := io.ReadFull(r, data)
+	if err != nil {
+		return nil, err
+	}
+	data = data[:sz]
+	return data, nil
+}
+
+type note struct {
+	name    string
+	tag     int32
+	desc    string
+	section *elf.Section
+}
+
+// Read all notes from f. As ELF section names are not supposed to be special, one
+// looks for a particular note by scanning all SHT_NOTE sections looking for a note
+// with a particular "name" and "tag".
+func readNotes(f *elf.File) ([]*note, error) {
+	var notes []*note
+	for _, sect := range f.Sections {
+		if sect.Type != elf.SHT_NOTE {
+			continue
+		}
+		r := sect.Open()
+		for {
+			var namesize, descsize, tag int32
+			err := binary.Read(r, f.ByteOrder, &namesize)
+			if err != nil {
+				if err == io.EOF {
+					break
+				}
+				return nil, fmt.Errorf("read namesize failed:", err)
+			}
+			err = binary.Read(r, f.ByteOrder, &descsize)
+			if err != nil {
+				return nil, fmt.Errorf("read descsize failed:", err)
+			}
+			err = binary.Read(r, f.ByteOrder, &tag)
+			if err != nil {
+				return nil, fmt.Errorf("read type failed:", err)
+			}
+			name, err := readwithpad(r, namesize)
+			if err != nil {
+				return nil, fmt.Errorf("read name failed:", err)
+			}
+			desc, err := readwithpad(r, descsize)
+			if err != nil {
+				return nil, fmt.Errorf("read desc failed:", err)
+			}
+			notes = append(notes, &note{name: string(name), tag: tag, desc: string(desc), section: sect})
+		}
+	}
+	return notes, nil
+}
+
+func dynStrings(path string, flag elf.DynTag) []string {
+	f, err := elf.Open(path)
+	defer f.Close()
+	if err != nil {
+		log.Fatal("elf.Open failed: ", err)
+	}
+	dynstrings, err := f.DynString(flag)
+	if err != nil {
+		log.Fatal("dynstring failed: ", err)
+	}
+	return dynstrings
+}
+
+func AssertIsLinkedToRegexp(t *testing.T, path string, re *regexp.Regexp) {
+	for _, dynstring := range dynStrings(path, elf.DT_NEEDED) {
+		if re.MatchString(dynstring) {
+			return
+		}
+	}
+	t.Errorf("%s is not linked to anything matching %v", path, re)
+}
+
+func AssertIsLinkedTo(t *testing.T, path, lib string) {
+	AssertIsLinkedToRegexp(t, path, regexp.MustCompile(regexp.QuoteMeta(lib)))
+}
+
+func AssertHasRPath(t *testing.T, path, dir string) {
+	for _, tag := range []elf.DynTag{elf.DT_RPATH, elf.DT_RUNPATH} {
+		for _, dynstring := range dynStrings(path, tag) {
+			for _, rpath := range strings.Split(dynstring, ":") {
+				if filepath.Clean(rpath) == filepath.Clean(dir) {
+					return
+				}
+			}
+		}
+	}
+	t.Errorf("%s does not have rpath %s", path, dir)
+}
+
+// Build a trivial program that links against the shared runtime and check it runs.
+func TestTrivialExecutable(t *testing.T) {
+	goCmd(t, "install", "-linkshared", "trivial")
+	run(t, "trivial executable", "./bin/trivial")
+	AssertIsLinkedTo(t, "./bin/trivial", soname)
+	AssertHasRPath(t, "./bin/trivial", gorootInstallDir)
+}
+
+// Build an executable that uses cgo linked against the shared runtime and check it
+// runs.
+func TestCgoExecutable(t *testing.T) {
+	goCmd(t, "install", "-linkshared", "execgo")
+	run(t, "cgo executable", "./bin/execgo")
+}
+
+// Build a GOPATH package into a shared library that links against the goroot runtime
+// and an executable that links against both.
+func TestGopathShlib(t *testing.T) {
+	goCmd(t, "install", "-buildmode=shared", "-linkshared", "dep")
+	AssertIsLinkedTo(t, filepath.Join(gopathInstallDir, "libdep.so"), soname)
+	goCmd(t, "install", "-linkshared", "exe")
+	AssertIsLinkedTo(t, "./bin/exe", soname)
+	AssertIsLinkedTo(t, "./bin/exe", "libdep.so")
+	AssertHasRPath(t, "./bin/exe", gorootInstallDir)
+	AssertHasRPath(t, "./bin/exe", gopathInstallDir)
+	// And check it runs.
+	run(t, "executable linked to GOPATH library", "./bin/exe")
+}
+
+// The shared library contains a note listing the packages it contains in a section
+// that is not mapped into memory.
+func testPkgListNote(t *testing.T, f *elf.File, note *note) {
+	if note.section.Flags != 0 {
+		t.Errorf("package list section has flags %v", note.section.Flags)
+	}
+	if isOffsetLoaded(f, note.section.Offset) {
+		t.Errorf("package list section contained in PT_LOAD segment")
+	}
+	if note.desc != "dep\n" {
+		t.Errorf("incorrect package list %q", note.desc)
+	}
+}
+
+// The shared library contains a note containing the ABI hash that is mapped into
+// memory and there is a local symbol called go.link.abihashbytes that points 16
+// bytes into it.
+func testABIHashNote(t *testing.T, f *elf.File, note *note) {
+	if note.section.Flags != elf.SHF_ALLOC {
+		t.Errorf("abi hash section has flags %v", note.section.Flags)
+	}
+	if !isOffsetLoaded(f, note.section.Offset) {
+		t.Errorf("abihash section not contained in PT_LOAD segment")
+	}
+	var hashbytes elf.Symbol
+	symbols, err := f.Symbols()
+	if err != nil {
+		t.Errorf("error reading symbols %v", err)
+		return
+	}
+	for _, sym := range symbols {
+		if sym.Name == "go.link.abihashbytes" {
+			hashbytes = sym
+		}
+	}
+	if hashbytes.Name == "" {
+		t.Errorf("no symbol called go.link.abihashbytes")
+		return
+	}
+	if elf.ST_BIND(hashbytes.Info) != elf.STB_LOCAL {
+		t.Errorf("%s has incorrect binding %v", hashbytes.Name, elf.ST_BIND(hashbytes.Info))
+	}
+	if f.Sections[hashbytes.Section] != note.section {
+		t.Errorf("%s has incorrect section %v", hashbytes.Name, f.Sections[hashbytes.Section].Name)
+	}
+	if hashbytes.Value-note.section.Addr != 16 {
+		t.Errorf("%s has incorrect offset into section %d", hashbytes.Name, hashbytes.Value-note.section.Addr)
+	}
+}
+
+// A Go shared library contains a note indicating which other Go shared libraries it
+// was linked against in an unmapped section.
+func testDepsNote(t *testing.T, f *elf.File, note *note) {
+	if note.section.Flags != 0 {
+		t.Errorf("package list section has flags %v", note.section.Flags)
+	}
+	if isOffsetLoaded(f, note.section.Offset) {
+		t.Errorf("package list section contained in PT_LOAD segment")
+	}
+	// libdep.so just links against the lib containing the runtime.
+	if note.desc != soname {
+		t.Errorf("incorrect dependency list %q", note.desc)
+	}
+}
+
+// The shared library contains notes with defined contents; see above.
+func TestNotes(t *testing.T) {
+	goCmd(t, "install", "-buildmode=shared", "-linkshared", "dep")
+	f, err := elf.Open(filepath.Join(gopathInstallDir, "libdep.so"))
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer f.Close()
+	notes, err := readNotes(f)
+	if err != nil {
+		t.Fatal(err)
+	}
+	pkgListNoteFound := false
+	abiHashNoteFound := false
+	depsNoteFound := false
+	for _, note := range notes {
+		if note.name != "Go\x00\x00" {
+			continue
+		}
+		switch note.tag {
+		case 1: // ELF_NOTE_GOPKGLIST_TAG
+			if pkgListNoteFound {
+				t.Error("multiple package list notes")
+			}
+			testPkgListNote(t, f, note)
+			pkgListNoteFound = true
+		case 2: // ELF_NOTE_GOABIHASH_TAG
+			if abiHashNoteFound {
+				t.Error("multiple abi hash notes")
+			}
+			testABIHashNote(t, f, note)
+			abiHashNoteFound = true
+		case 3: // ELF_NOTE_GODEPS_TAG
+			if depsNoteFound {
+				t.Error("multiple abi hash notes")
+			}
+			testDepsNote(t, f, note)
+			depsNoteFound = true
+		}
+	}
+	if !pkgListNoteFound {
+		t.Error("package list note not found")
+	}
+	if !abiHashNoteFound {
+		t.Error("abi hash note not found")
+	}
+	if !depsNoteFound {
+		t.Error("deps note not found")
+	}
+}
+
+// Build a GOPATH package (dep) into a shared library that links against the goroot
+// runtime, another package (dep2) that links against the first, and and an
+// executable that links against dep2.
+func TestTwoGopathShlibs(t *testing.T) {
+	goCmd(t, "install", "-buildmode=shared", "-linkshared", "dep")
+	goCmd(t, "install", "-buildmode=shared", "-linkshared", "dep2")
+	goCmd(t, "install", "-linkshared", "exe2")
+	run(t, "executable linked to GOPATH library", "./bin/exe2")
+}
+
+// Build a GOPATH package into a shared library with gccgo and an executable that
+// links against it.
+func TestGoPathShlibGccgo(t *testing.T) {
+	gccgoName := os.Getenv("GCCGO")
+	if gccgoName == "" {
+		gccgoName = "gccgo"
+	}
+	_, err := exec.LookPath(gccgoName)
+	if err != nil {
+		t.Skip("gccgo not found")
+	}
+
+	libgoRE := regexp.MustCompile("libgo.so.[0-9]+")
+
+	gccgoContext := build.Default
+	gccgoContext.InstallSuffix = suffix + "_fPIC"
+	gccgoContext.Compiler = "gccgo"
+	gccgoContext.GOPATH = os.Getenv("GOPATH")
+	depP, err := gccgoContext.Import("dep", ".", build.ImportComment)
+	if err != nil {
+		t.Fatalf("import failed: %v", err)
+	}
+	gccgoInstallDir := filepath.Join(depP.PkgTargetRoot, "shlibs")
+	goCmd(t, "install", "-compiler=gccgo", "-buildmode=shared", "-linkshared", "dep")
+	AssertIsLinkedToRegexp(t, filepath.Join(gccgoInstallDir, "libdep.so"), libgoRE)
+	goCmd(t, "install", "-compiler=gccgo", "-linkshared", "exe")
+	AssertIsLinkedToRegexp(t, "./bin/exe", libgoRE)
+	AssertIsLinkedTo(t, "./bin/exe", "libdep.so")
+	AssertHasRPath(t, "./bin/exe", gccgoInstallDir)
+	// And check it runs.
+	run(t, "gccgo-built", "./bin/exe")
+}
+
+// The gccgo version of TestTwoGopathShlibs: build a GOPATH package into a shared
+// library with gccgo, another GOPATH package that depends on the first and an
+// executable that links the second library.
+func TestTwoGopathShlibsGccgo(t *testing.T) {
+	gccgoName := os.Getenv("GCCGO")
+	if gccgoName == "" {
+		gccgoName = "gccgo"
+	}
+	_, err := exec.LookPath(gccgoName)
+	if err != nil {
+		t.Skip("gccgo not found")
+	}
+
+	libgoRE := regexp.MustCompile("libgo.so.[0-9]+")
+
+	gccgoContext := build.Default
+	gccgoContext.InstallSuffix = suffix + "_fPIC"
+	gccgoContext.Compiler = "gccgo"
+	gccgoContext.GOPATH = os.Getenv("GOPATH")
+	depP, err := gccgoContext.Import("dep", ".", build.ImportComment)
+	if err != nil {
+		t.Fatalf("import failed: %v", err)
+	}
+	gccgoInstallDir := filepath.Join(depP.PkgTargetRoot, "shlibs")
+	goCmd(t, "install", "-compiler=gccgo", "-buildmode=shared", "-linkshared", "dep")
+	goCmd(t, "install", "-compiler=gccgo", "-buildmode=shared", "-linkshared", "dep2")
+	goCmd(t, "install", "-compiler=gccgo", "-linkshared", "exe2")
+
+	AssertIsLinkedToRegexp(t, filepath.Join(gccgoInstallDir, "libdep.so"), libgoRE)
+	AssertIsLinkedToRegexp(t, filepath.Join(gccgoInstallDir, "libdep2.so"), libgoRE)
+	AssertIsLinkedTo(t, filepath.Join(gccgoInstallDir, "libdep2.so"), "libdep.so")
+	AssertIsLinkedToRegexp(t, "./bin/exe2", libgoRE)
+	AssertIsLinkedTo(t, "./bin/exe2", "libdep2")
+	AssertIsLinkedTo(t, "./bin/exe2", "libdep.so")
+
+	// And check it runs.
+	run(t, "gccgo-built", "./bin/exe2")
+}
+
+// Testing rebuilding of shared libraries when they are stale is a bit more
+// complicated that it seems like it should be. First, we make everything "old": but
+// only a few seconds old, or it might be older than gc (or the runtime source) and
+// everything will get rebuilt. Then define a timestamp slightly newer than this
+// time, which is what we set the mtime to of a file to cause it to be seen as new,
+// and finally another slightly even newer one that we can compare files against to
+// see if they have been rebuilt.
+var oldTime = time.Now().Add(-9 * time.Second)
+var nearlyNew = time.Now().Add(-6 * time.Second)
+var stampTime = time.Now().Add(-3 * time.Second)
+
+// resetFileStamps makes "everything" (bin, src, pkg from GOPATH and the
+// test-specific parts of GOROOT) appear old.
+func resetFileStamps() {
+	chtime := func(path string, info os.FileInfo, err error) error {
+		return os.Chtimes(path, oldTime, oldTime)
+	}
+	reset := func(path string) {
+		if err := filepath.Walk(path, chtime); err != nil {
+			log.Fatalf("resetFileStamps failed: %v", err)
+		}
+
+	}
+	reset("bin")
+	reset("pkg")
+	reset("src")
+	reset(gorootInstallDir)
+}
+
+// touch makes path newer than the "old" time stamp used by resetFileStamps.
+func touch(path string) {
+	if err := os.Chtimes(path, nearlyNew, nearlyNew); err != nil {
+		log.Fatalf("os.Chtimes failed: %v", err)
+	}
+}
+
+// isNew returns if the path is newer than the time stamp used by touch.
+func isNew(path string) bool {
+	fi, err := os.Stat(path)
+	if err != nil {
+		log.Fatalf("os.Stat failed: %v", err)
+	}
+	return fi.ModTime().After(stampTime)
+}
+
+// Fail unless path has been rebuilt (i.e. is newer than the time stamp used by
+// isNew)
+func AssertRebuilt(t *testing.T, msg, path string) {
+	if !isNew(path) {
+		t.Errorf("%s was not rebuilt (%s)", msg, path)
+	}
+}
+
+// Fail if path has been rebuilt (i.e. is newer than the time stamp used by isNew)
+func AssertNotRebuilt(t *testing.T, msg, path string) {
+	if isNew(path) {
+		t.Errorf("%s was rebuilt (%s)", msg, path)
+	}
+}
+
+func TestRebuilding(t *testing.T) {
+	goCmd(t, "install", "-buildmode=shared", "-linkshared", "dep")
+	goCmd(t, "install", "-linkshared", "exe")
+
+	// If the source is newer than both the .a file and the .so, both are rebuilt.
+	resetFileStamps()
+	touch("src/dep/dep.go")
+	goCmd(t, "install", "-linkshared", "exe")
+	AssertRebuilt(t, "new source", filepath.Join(gopathInstallDir, "dep.a"))
+	AssertRebuilt(t, "new source", filepath.Join(gopathInstallDir, "libdep.so"))
+
+	// If the .a file is newer than the .so, the .so is rebuilt (but not the .a)
+	resetFileStamps()
+	touch(filepath.Join(gopathInstallDir, "dep.a"))
+	goCmd(t, "install", "-linkshared", "exe")
+	AssertNotRebuilt(t, "new .a file", filepath.Join(gopathInstallDir, "dep.a"))
+	AssertRebuilt(t, "new .a file", filepath.Join(gopathInstallDir, "libdep.so"))
+}
+
+func appendFile(path, content string) {
+	f, err := os.OpenFile(path, os.O_WRONLY|os.O_APPEND, 0660)
+	if err != nil {
+		log.Fatalf("os.OpenFile failed: %v", err)
+	}
+	defer func() {
+		err := f.Close()
+		if err != nil {
+			log.Fatalf("f.Close failed: %v", err)
+		}
+	}()
+	_, err = f.WriteString(content)
+	if err != nil {
+		log.Fatalf("f.WriteString failed: %v", err)
+	}
+}
+
+func TestABIChecking(t *testing.T) {
+	goCmd(t, "install", "-buildmode=shared", "-linkshared", "dep")
+	goCmd(t, "install", "-linkshared", "exe")
+
+	// If we make an ABI-breaking change to dep and rebuild libp.so but not exe,
+	// exe will abort with a complaint on startup.
+	// This assumes adding an exported function breaks ABI, which is not true in
+	// some senses but suffices for the narrow definition of ABI compatiblity the
+	// toolchain uses today.
+	resetFileStamps()
+	appendFile("src/dep/dep.go", "func ABIBreak() {}\n")
+	goCmd(t, "install", "-buildmode=shared", "-linkshared", "dep")
+	c := exec.Command("./bin/exe")
+	output, err := c.CombinedOutput()
+	if err == nil {
+		t.Fatal("executing exe did not fail after ABI break")
+	}
+	scanner := bufio.NewScanner(bytes.NewReader(output))
+	foundMsg := false
+	const wantLine = "abi mismatch detected between the executable and libdep.so"
+	for scanner.Scan() {
+		if scanner.Text() == wantLine {
+			foundMsg = true
+			break
+		}
+	}
+	if err = scanner.Err(); err != nil {
+		t.Errorf("scanner encountered error: %v", err)
+	}
+	if !foundMsg {
+		t.Fatalf("exe failed, but without line %q; got output:\n%s", wantLine, output)
+	}
+
+	// Rebuilding exe makes it work again.
+	goCmd(t, "install", "-linkshared", "exe")
+	run(t, "rebuilt exe", "./bin/exe")
+
+	// If we make a change which does not break ABI (such as adding an unexported
+	// function) and rebuild libdep.so, exe still works.
+	resetFileStamps()
+	appendFile("src/dep/dep.go", "func noABIBreak() {}\n")
+	goCmd(t, "install", "-buildmode=shared", "-linkshared", "dep")
+	run(t, "after non-ABI breaking change", "./bin/exe")
+}
diff --git a/misc/cgo/testshared/src/dep/asm.s b/misc/cgo/testshared/src/dep/asm.s
new file mode 100644
index 0000000..8069ebb
--- /dev/null
+++ b/misc/cgo/testshared/src/dep/asm.s
@@ -0,0 +1,10 @@
+// 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 !gccgo
+
+#include "textflag.h"
+
+TEXT ·ImplementedInAsm(SB),NOSPLIT,$0-0
+       RET
diff --git a/misc/cgo/testshared/src/dep/dep.go b/misc/cgo/testshared/src/dep/dep.go
new file mode 100644
index 0000000..d3bed3f
--- /dev/null
+++ b/misc/cgo/testshared/src/dep/dep.go
@@ -0,0 +1,13 @@
+package dep
+
+var V int = 1
+
+var HasMask []string = []string{"hi"}
+
+type HasProg struct {
+	array [1024]*byte
+}
+
+func F() int {
+	return V
+}
diff --git a/misc/cgo/testshared/src/dep/gccgo.go b/misc/cgo/testshared/src/dep/gccgo.go
new file mode 100644
index 0000000..552ec30
--- /dev/null
+++ b/misc/cgo/testshared/src/dep/gccgo.go
@@ -0,0 +1,5 @@
+//+build gccgo
+
+package dep
+
+func ImplementedInAsm() {}
diff --git a/misc/cgo/testshared/src/dep/stubs.go b/misc/cgo/testshared/src/dep/stubs.go
new file mode 100644
index 0000000..036296a
--- /dev/null
+++ b/misc/cgo/testshared/src/dep/stubs.go
@@ -0,0 +1,5 @@
+//+build !gccgo
+
+package dep
+
+func ImplementedInAsm()
diff --git a/misc/cgo/testshared/src/dep2/dep2.go b/misc/cgo/testshared/src/dep2/dep2.go
new file mode 100644
index 0000000..bac1086
--- /dev/null
+++ b/misc/cgo/testshared/src/dep2/dep2.go
@@ -0,0 +1,11 @@
+package dep2
+
+import "dep"
+
+var W int = 1
+
+var hasProg dep.HasProg
+
+func G() int {
+	return dep.F() + 1
+}
diff --git a/misc/cgo/testshared/src/exe/exe.go b/misc/cgo/testshared/src/exe/exe.go
new file mode 100644
index 0000000..f644776
--- /dev/null
+++ b/misc/cgo/testshared/src/exe/exe.go
@@ -0,0 +1,12 @@
+package main
+
+import (
+	"dep"
+	"runtime"
+)
+
+func main() {
+	defer dep.ImplementedInAsm()
+	runtime.GC()
+	dep.V = dep.F() + 1
+}
diff --git a/misc/cgo/testshared/src/exe2/exe2.go b/misc/cgo/testshared/src/exe2/exe2.go
new file mode 100644
index 0000000..acdb4dd
--- /dev/null
+++ b/misc/cgo/testshared/src/exe2/exe2.go
@@ -0,0 +1,7 @@
+package main
+
+import "dep2"
+
+func main() {
+	dep2.W = dep2.G() + 1
+}
diff --git a/misc/cgo/testshared/src/execgo/exe.go b/misc/cgo/testshared/src/execgo/exe.go
new file mode 100644
index 0000000..0427be8
--- /dev/null
+++ b/misc/cgo/testshared/src/execgo/exe.go
@@ -0,0 +1,8 @@
+package main
+
+/*
+ */
+import "C"
+
+func main() {
+}
diff --git a/misc/cgo/testshared/src/trivial/trivial.go b/misc/cgo/testshared/src/trivial/trivial.go
new file mode 100644
index 0000000..da29a2c
--- /dev/null
+++ b/misc/cgo/testshared/src/trivial/trivial.go
@@ -0,0 +1,4 @@
+package main
+
+func main() {
+}
diff --git a/misc/cgo/testsigfwd/main.go b/misc/cgo/testsigfwd/main.go
new file mode 100644
index 0000000..6641c9d
--- /dev/null
+++ b/misc/cgo/testsigfwd/main.go
@@ -0,0 +1,58 @@
+// 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 "fmt"
+
+/*
+#include <signal.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+int *p;
+static void sigsegv() {
+	*p = 1;
+	fprintf(stderr, "ERROR: C SIGSEGV not thrown on caught?.\n");
+	exit(2);
+}
+
+static void sighandler(int signum) {
+	if (signum == SIGSEGV) {
+		exit(0);  // success
+	}
+}
+
+static void __attribute__ ((constructor)) sigsetup(void) {
+	struct sigaction act;
+	act.sa_handler = &sighandler;
+	sigaction(SIGSEGV, &act, 0);
+}
+*/
+import "C"
+
+var p *byte
+
+func f() (ret bool) {
+	defer func() {
+		if recover() == nil {
+			fmt.Errorf("ERROR: couldn't raise SIGSEGV in Go.")
+			C.exit(2)
+		}
+		ret = true
+	}()
+	*p = 1
+	return false
+}
+
+func main() {
+	// Test that the signal originating in Go is handled (and recovered) by Go.
+	if !f() {
+		fmt.Errorf("couldn't recover from SIGSEGV in Go.")
+		C.exit(2)
+	}
+
+	// Test that the signal originating in C is handled by C.
+	C.sigsegv()
+}
diff --git a/misc/cgo/testso/cgoso.go b/misc/cgo/testso/cgoso.go
index ba62183..29814fa 100644
--- a/misc/cgo/testso/cgoso.go
+++ b/misc/cgo/testso/cgoso.go
@@ -11,6 +11,7 @@ package cgosotest
 #cgo dragonfly LDFLAGS: -L. -l cgosotest
 #cgo freebsd LDFLAGS: -L. -l cgosotest
 #cgo openbsd LDFLAGS: -L. -l cgosotest
+#cgo solaris LDFLAGS: -L. -lcgosotest
 #cgo netbsd LDFLAGS: -L. libcgosotest.so
 #cgo darwin LDFLAGS: -L. libcgosotest.dylib
 #cgo windows LDFLAGS: -L. libcgosotest.dll
diff --git a/misc/cgo/testso/cgoso_unix.go b/misc/cgo/testso/cgoso_unix.go
index 7d5444c..49cdeaa 100644
--- a/misc/cgo/testso/cgoso_unix.go
+++ b/misc/cgo/testso/cgoso_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 dragonfly freebsd linux netbsd
+// +build dragonfly freebsd linux netbsd solaris
 
 package cgosotest
 
diff --git a/misc/cgo/testso/test.bash b/misc/cgo/testso/test.bash
deleted file mode 100755
index f4061c6..0000000
--- a/misc/cgo/testso/test.bash
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/usr/bin/env bash
-# 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.
-
-set -e
-
-args=
-dyld_envvar=LD_LIBRARY_PATH
-ext=so
-if [ "$(uname)" == "Darwin" ]; then
-	args="-undefined suppress -flat_namespace"
-	dyld_envvar=DYLD_LIBRARY_PATH
-	ext=dylib
-fi
-
-dylib=libcgosotest.$ext
-$(go env CC) $(go env GOGCCFLAGS) -shared $args -o $dylib cgoso_c.c
-go build main.go
-
-eval "$dyld_envvar"=. ./main
-rm -rf $dylib main *.dSYM
diff --git a/misc/cgo/testso/test.bat b/misc/cgo/testso/test.bat
deleted file mode 100644
index b8cc384..0000000
--- a/misc/cgo/testso/test.bat
+++ /dev/null
@@ -1,18 +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.
-
- at echo off
-
-gcc -c cgoso_c.c
-gcc -shared -o libcgosotest.dll cgoso_c.o
-if not exist libcgosotest.dll goto fail
-go build main.go
-if not exist main.exe goto fail
-main.exe
-goto :end
-
-:fail
-set FAIL=1
-:end
-del /F cgoso_c.o libcgosotest.dll main.exe 2>NUL
diff --git a/misc/cgo/testsovar/cgoso.go b/misc/cgo/testsovar/cgoso.go
new file mode 100644
index 0000000..88d44c2
--- /dev/null
+++ b/misc/cgo/testsovar/cgoso.go
@@ -0,0 +1,43 @@
+// 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 cgosotest
+
+// This test verifies that Go can access C variables
+// in shared object file via cgo.
+
+/*
+// intentionally write the same LDFLAGS differently
+// to test correct handling of LDFLAGS.
+#cgo windows CFLAGS: -DIMPORT_DLL
+#cgo linux LDFLAGS: -L. -lcgosotest
+#cgo dragonfly LDFLAGS: -L. -l cgosotest
+#cgo freebsd LDFLAGS: -L. -l cgosotest
+#cgo openbsd LDFLAGS: -L. -l cgosotest
+#cgo solaris LDFLAGS: -L. -lcgosotest
+#cgo netbsd LDFLAGS: -L. libcgosotest.so
+#cgo darwin LDFLAGS: -L. libcgosotest.dylib
+#cgo windows LDFLAGS: -L. libcgosotest.dll
+
+#include "cgoso_c.h"
+
+const char* getVar() {
+	    return exported_var;
+}
+*/
+import "C"
+
+import "fmt"
+
+func Test() {
+	const want = "Hello world"
+	got := C.GoString(C.getVar())
+	if got != want {
+		panic(fmt.Sprintf("testExportedVar: got %q, but want %q", got, want))
+	}
+	got = C.GoString(C.exported_var)
+	if got != want {
+		panic(fmt.Sprintf("testExportedVar: got %q, but want %q", got, want))
+	}
+}
diff --git a/misc/cgo/testsovar/cgoso_c.c b/misc/cgo/testsovar/cgoso_c.c
new file mode 100644
index 0000000..a448c01
--- /dev/null
+++ b/misc/cgo/testsovar/cgoso_c.c
@@ -0,0 +1,7 @@
+// 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
+
+const char *exported_var = "Hello world";
diff --git a/misc/cgo/testsovar/cgoso_c.h b/misc/cgo/testsovar/cgoso_c.h
new file mode 100644
index 0000000..640db7b
--- /dev/null
+++ b/misc/cgo/testsovar/cgoso_c.h
@@ -0,0 +1,17 @@
+// 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
+
+#ifdef WIN32
+#if defined(EXPORT_DLL)
+#    define VAR __declspec(dllexport)
+#elif defined(IMPORT_DLL)
+#    define VAR __declspec(dllimport)
+#endif
+#else
+#    define VAR extern
+#endif
+
+VAR const char *exported_var;
diff --git a/misc/cgo/testsovar/main.go b/misc/cgo/testsovar/main.go
new file mode 100644
index 0000000..9c8a1c4
--- /dev/null
+++ b/misc/cgo/testsovar/main.go
@@ -0,0 +1,13 @@
+// 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 "."
+
+func main() {
+	cgosotest.Test()
+}
diff --git a/misc/chrome/gophertool/gopher.js b/misc/chrome/gophertool/gopher.js
index 3238f0f..09edb29 100644
--- a/misc/chrome/gophertool/gopher.js
+++ b/misc/chrome/gophertool/gopher.js
@@ -3,7 +3,8 @@
 // license that can be found in the LICENSE file.
 
 var numericRE = /^\d+$/;
-var commitRE = /^(?:\d+:)?([0-9a-f]{6,20})$/; // e.g "8486:ab29d2698a47" or "ab29d2698a47"
+var commitRE = /^(?:\d+:)?([0-9a-f]{6,40})$/; // e.g "8486:ab29d2698a47" or "ab29d2698a47"
+var gerritChangeIdRE = /^I[0-9a-f]{4,40}$/; // e.g. Id69c00d908d18151486007ec03da5495b34b05f5
 var pkgRE = /^[a-z0-9_\/]+$/;
 
 function urlForInput(t) {
@@ -13,21 +14,27 @@ function urlForInput(t) {
 
     if (numericRE.test(t)) {
         if (t < 150000) {
-            return "http://code.google.com/p/go/issues/detail?id=" + t;
+            // We could use the golang.org/cl/ handler here, but
+            // avoid some redirect latency and go right there, since
+            // one is easy. (no server-side mapping)
+            return "https://github.com/golang/go/issues/" + t;
         }
-        return "http://codereview.appspot.com/" + t + "/";
+        return "https://golang.org/cl/" + t;
+    }
+
+    if (gerritChangeIdRE.test(t)) {
+        return "https://golang.org/cl/" + t;
     }
 
     var match = commitRE.exec(t);
     if (match) {
-        return "http://code.google.com/p/go/source/detail?r=" + match[1];
+        return "https://golang.org/change/" + match[1];
     }
 
     if (pkgRE.test(t)) {
         // TODO: make this smarter, using a list of packages + substring matches.
         // Get the list from godoc itself in JSON format?
-        // TODO: prefer localhost:6060 to golang.org if localhost:6060 is responding. 
-        return "http://golang.org/pkg/" + t;
+        return "https://golang.org/pkg/" + t;
     }
 
     return null;
diff --git a/misc/chrome/gophertool/popup.html b/misc/chrome/gophertool/popup.html
index 8bb7795..9740406 100644
--- a/misc/chrome/gophertool/popup.html
+++ b/misc/chrome/gophertool/popup.html
@@ -9,11 +9,13 @@
 <script src="popup.js"></script>
 </head>
 <body style='margin: 0.5em; font-family: sans;'>
-<small><a href="#" url="http://code.google.com/p/go/issues/list">issue</a>,
-<a href="#" url="http://codereview.appspot.com/">codereview</a>,
-<a href="#" url="http://code.google.com/p/go/source/list">commit</a>, or
-<a href="#" url="http://golang.org/pkg/">pkg</a> id/name:</small>
+<small><a href="#" url="https://golang.org/issue">issue</a>,
+<a href="#" url="https://golang.org/cl">codereview</a>,
+<a href="#" url="https://golang.org/change">commit</a>, or
+<a href="#" url="https://golang.org/pkg/">pkg</a> id/name:</small>
 <form style='margin: 0' id='navform'><nobr><input id="inputbox" size=10 tabindex=1 /><input type="submit" value="go" /></nobr></form>
-<small>Also: <a href="#" url="http://build.golang.org">buildbots</a></small>
+<small>Also: <a href="#" url="https://build.golang.org">buildbots</a>
+<a href="#" url="https://github.com/golang/go">Github</a>
+</small>
 </body>
 </html>
diff --git a/misc/editors b/misc/editors
index 850ec34..3a0f73f 100644
--- a/misc/editors
+++ b/misc/editors
@@ -1,5 +1,5 @@
 For information about plugins and other support for Go in editors and shells,
 see this page on the Go Wiki:
 
-https://code.google.com/p/go-wiki/wiki/IDEsAndTextEditorPlugins
+https://golang.org/wiki/IDEsAndTextEditorPlugins
 
diff --git a/misc/ios/README b/misc/ios/README
new file mode 100644
index 0000000..417a217
--- /dev/null
+++ b/misc/ios/README
@@ -0,0 +1,44 @@
+Go on iOS
+=========
+
+To build a cross compiling toolchain for iOS on OS X, first modify clangwrap.sh
+in misc/ios to match your setup. And then run:
+
+	GOARM=7 CGO_ENABLED=1 GOARCH=arm CC_FOR_TARGET=`pwd`/../misc/ios/clangwrap.sh \
+	CXX_FOR_TARGET=`pwd`/../misc/ios/clangwrap.sh ./make.bash
+
+To build a program, use the normal go build command:
+
+	CGO_ENABLED=1 GOARCH=arm go build import/path
+
+To run a program on an iDevice, first make sure you have a valid developer
+certificate and have setup your iDevice properly to run apps signed by your
+developer certificate. Then install https://github.com/phonegap/ios-deploy.
+At a first step, you can try building the famous hello world program to run
+on your test device.
+(The needed files are provided at https://github.com/minux/go-ios-examples.)
+
+	# assume your program binary is helloworld.go, build it into the
+	# example hello.app bundle.
+	CGO_ENABLED=1 GOARCH=arm go build -o hello.app/hello helloworld.go
+	# sign the executable using your developer certificate
+	codesign -f -s "iPhone Developer" --entitlements hello.app/Entitlements.plist hello.app/hello
+	# run the program inside lldb on iDevice, run `ios-deploy` for more
+	# command options
+	ios-deploy --debug --uninstall --bundle hello.app
+	# Depending on your ios-deploy version, you might need to enter "run"
+	# into lldb to run your program, and its output will be shown by lldb.
+
+Notes:
+ - A dummy hello.app bundle is provided in this directory to help you get started.
+ - Running the program on an iDevice requires code sign and thus external linking,
+   if your program uses cgo, then it will automatically use external linking.
+   However, if your program does not use cgo, please make sure to add
+	import _ "runtime/cgo"
+   so that external linking will be used.
+
+Known issues
+============
+ - crypto/x509 won't build, I don't yet know how to get system root on iOS.
+ - Because I still want to be able to do native build, CGO_ENABLED=1 is not the
+   default, yet.
diff --git a/misc/ios/clangwrap.sh b/misc/ios/clangwrap.sh
new file mode 100755
index 0000000..9cad49f
--- /dev/null
+++ b/misc/ios/clangwrap.sh
@@ -0,0 +1,20 @@
+#!/bin/sh
+# This uses the latest available iOS SDK, which is recommended.
+# To select a specific SDK, run 'xcodebuild -showsdks'
+# to see the available SDKs and replace iphoneos with one of them.
+SDK=iphoneos
+SDK_PATH=`xcrun --sdk $SDK --show-sdk-path`
+export IPHONEOS_DEPLOYMENT_TARGET=5.1
+# cmd/cgo doesn't support llvm-gcc-4.2, so we have to use clang.
+CLANG=`xcrun --sdk $SDK --find clang`
+
+if [ "$GOARCH" == "arm" ]; then
+	CLANGARCH="armv7"
+elif [ "$GOARCH" == "arm64" ]; then
+	CLANGARCH="arm64"
+else
+	echo "unknown GOARCH=$GOARCH" >&2
+	exit 1
+fi
+
+exec $CLANG -arch $CLANGARCH -isysroot $SDK_PATH "$@"
diff --git a/misc/ios/detect.go b/misc/ios/detect.go
new file mode 100644
index 0000000..d305458
--- /dev/null
+++ b/misc/ios/detect.go
@@ -0,0 +1,135 @@
+// 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
+
+// detect attempts to autodetect the correct
+// values of the environment variables
+// used by go_darwin_arm_exec.
+// detect shells out to ideviceinfo, a third party program that can
+// be obtained by following the instructions at
+// https://github.com/libimobiledevice/libimobiledevice.
+package main
+
+import (
+	"bytes"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"strings"
+)
+
+func main() {
+	devID := detectDevID()
+	fmt.Printf("export GOIOS_DEV_ID=%s\n", devID)
+
+	udid := detectUDID()
+	mp := detectMobileProvisionFile(udid)
+
+	f, err := ioutil.TempFile("", "go_ios_detect_")
+	check(err)
+	fname := f.Name()
+	defer os.Remove(fname)
+
+	out := combinedOutput(parseMobileProvision(mp))
+	_, err = f.Write(out)
+	check(err)
+	check(f.Close())
+
+	appID, err := plistExtract(fname, "ApplicationIdentifierPrefix:0")
+	check(err)
+	fmt.Printf("export GOIOS_APP_ID=%s\n", appID)
+
+	teamID, err := plistExtract(fname, "Entitlements:com.apple.developer.team-identifier")
+	check(err)
+	fmt.Printf("export GOIOS_TEAM_ID=%s\n", teamID)
+}
+
+func detectDevID() string {
+	cmd := exec.Command("security", "find-identity", "-p", "codesigning", "-v")
+	lines := getLines(cmd)
+
+	for _, line := range lines {
+		if !bytes.Contains(line, []byte("iPhone Developer")) {
+			continue
+		}
+		fields := bytes.Fields(line)
+		return string(fields[1])
+	}
+	fail("no code signing identity found")
+	panic("unreachable")
+}
+
+var udidPrefix = []byte("UniqueDeviceID: ")
+
+func detectUDID() []byte {
+	cmd := exec.Command("ideviceinfo")
+	lines := getLines(cmd)
+	for _, line := range lines {
+		if bytes.HasPrefix(line, udidPrefix) {
+			return bytes.TrimPrefix(line, udidPrefix)
+		}
+	}
+	fail("udid not found; is the device connected?")
+	panic("unreachable")
+}
+
+func detectMobileProvisionFile(udid []byte) string {
+	cmd := exec.Command("mdfind", "-name", ".mobileprovision")
+	lines := getLines(cmd)
+
+	for _, line := range lines {
+		if len(line) == 0 {
+			continue
+		}
+		xmlLines := getLines(parseMobileProvision(string(line)))
+		for _, xmlLine := range xmlLines {
+			if bytes.Contains(xmlLine, udid) {
+				return string(line)
+			}
+		}
+	}
+	fail("did not find mobile provision matching device udid %s", udid)
+	panic("ureachable")
+}
+
+func parseMobileProvision(fname string) *exec.Cmd {
+	return exec.Command("security", "cms", "-D", "-i", string(fname))
+}
+
+func plistExtract(fname string, path string) ([]byte, error) {
+	out, err := exec.Command("/usr/libexec/PlistBuddy", "-c", "Print "+path, fname).CombinedOutput()
+	if err != nil {
+		return nil, err
+	}
+	return bytes.TrimSpace(out), nil
+}
+
+func getLines(cmd *exec.Cmd) [][]byte {
+	out := combinedOutput(cmd)
+	return bytes.Split(out, []byte("\n"))
+}
+
+func combinedOutput(cmd *exec.Cmd) []byte {
+	out, err := cmd.CombinedOutput()
+	if err != nil {
+		fmt.Println(strings.Join(cmd.Args, "\n"))
+		fmt.Fprintln(os.Stderr, err)
+		os.Exit(1)
+	}
+	return out
+}
+
+func check(err error) {
+	if err != nil {
+		fail(err.Error())
+	}
+}
+
+func fail(msg string, v ...interface{}) {
+	fmt.Fprintf(os.Stderr, msg, v...)
+	fmt.Fprintln(os.Stderr)
+	os.Exit(1)
+}
diff --git a/misc/ios/go_darwin_arm_exec.go b/misc/ios/go_darwin_arm_exec.go
new file mode 100644
index 0000000..debd2cd
--- /dev/null
+++ b/misc/ios/go_darwin_arm_exec.go
@@ -0,0 +1,665 @@
+// 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
+//
+// This script supports an extra flag, -lldb, that pauses execution
+// just before the main program begins and allows the user to control
+// the remote lldb session. This flag is appended to the end of the
+// script's arguments and is not passed through to the underlying
+// binary.
+//
+// This script requires that three environment variables be set:
+// 	GOIOS_DEV_ID: The codesigning developer id or certificate identifier
+// 	GOIOS_APP_ID: The provisioning app id prefix. Must support wildcard app ids.
+// 	GOIOS_TEAM_ID: The team id that owns the app id prefix.
+// $GOROOT/misc/ios contains a script, detect.go, that attempts to autodetect these.
+package main
+
+import (
+	"bytes"
+	"errors"
+	"flag"
+	"fmt"
+	"go/build"
+	"io"
+	"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
+
+var (
+	devID  string
+	appID  string
+	teamID 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")
+	}
+
+	// e.g. B393DDEB490947F5A463FD074299B6C0AXXXXXXX
+	devID = getenv("GOIOS_DEV_ID")
+
+	// e.g. Z8B3JBXXXX.org.golang.sample, Z8B3JBXXXX prefix is available at
+	// https://developer.apple.com/membercenter/index.action#accountSummary as Team ID.
+	appID = getenv("GOIOS_APP_ID")
+
+	// e.g. Z8B3JBXXXX, available at
+	// https://developer.apple.com/membercenter/index.action#accountSummary as Team ID.
+	teamID = getenv("GOIOS_TEAM_ID")
+
+	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 getenv(envvar string) string {
+	s := os.Getenv(envvar)
+	if s == "" {
+		log.Fatalf("%s not set\nrun $GOROOT/misc/ios/detect.go to attempt to autodetect", s)
+	}
+	return s
+}
+
+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", devID,
+		"--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()
+
+	var opts options
+	opts, args = parseArgs(args)
+
+	// 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)
+	if opts.lldb {
+		mw := io.MultiWriter(w, os.Stderr)
+		cmd.Stdout = mw
+		cmd.Stderr = mw
+	} else {
+		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 opts.timeout > 1*time.Second {
+		timedout = make(chan struct{})
+		time.AfterFunc(opts.timeout-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)", 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
+
+	if opts.lldb {
+		_, err := io.Copy(lldb, os.Stdin)
+		if err != io.EOF {
+			return err
+		}
+		return nil
+	}
+
+	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.
+	if pkgpath != "src" {
+		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)`)
+	}
+
+	// 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 <-w.find("\nPASS", 0):
+		passed := w.isPass()
+		w.printBuf()
+		if passed {
+			return nil
+		}
+		return errors.New("test failure")
+	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)
+
+	if debug {
+		inTxt := strings.Replace(string(in), "\n", "\\n", -1)
+		findTxt := strings.Replace(string(w.findTxt), "\n", "\\n", -1)
+		fmt.Printf("debug --> %s <-- debug (findTxt='%s')\n", inTxt, findTxt)
+	}
+
+	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()
+	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"))
+}
+
+type options struct {
+	timeout time.Duration
+	lldb    bool
+}
+
+func parseArgs(binArgs []string) (opts options, remainingArgs []string) {
+	var flagArgs []string
+	for _, arg := range binArgs {
+		if strings.Contains(arg, "-test.timeout") {
+			flagArgs = append(flagArgs, arg)
+		}
+		if strings.Contains(arg, "-lldb") {
+			flagArgs = append(flagArgs, arg)
+			continue
+		}
+		remainingArgs = append(remainingArgs, arg)
+	}
+	f := flag.NewFlagSet("", flag.ContinueOnError)
+	f.DurationVar(&opts.timeout, "test.timeout", 0, "")
+	f.BoolVar(&opts.lldb, "lldb", false, "")
+	f.Parse(flagArgs)
+	return opts, remainingArgs
+
+}
+
+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>
+`
+
+func entitlementsPlist() string {
+	return `<?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>` + appID + `.golang.gotest</string></array>
+	<key>get-task-allow</key>
+	<true/>
+	<key>application-identifier</key>
+	<string>` + appID + `.golang.gotest</string>
+	<key>com.apple.developer.team-identifier</key>
+	<string>` + teamID + `</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>
+			<integer>10</integer>
+		</dict>
+		<key>ResourceRules.plist</key>
+		<dict>
+			<key>omit</key>
+			<true/>
+			<key>weight</key>
+			<integer>100</integer>
+		</dict>
+	</dict>
+</dict>
+</plist>
+`
diff --git a/misc/nacl/README b/misc/nacl/README
index 72d0e08..99b94dc 100644
--- a/misc/nacl/README
+++ b/misc/nacl/README
@@ -8,10 +8,10 @@ Go 1.3 supports three architectures
 
  * 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.
+For background it is recommended that you read https://golang.org/s/go13nacl.
 
 Prerequisites
 -------------
@@ -37,21 +37,20 @@ sdk. These are released every 6-8 weeks, in line with Chrome releases.
 	% 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 @@ Then, run the program as:
 
 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 @@ If you see that the program is stopped in _rt0_amd64p32_nacl, then symbols are
 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/nacl/testzip.proto b/misc/nacl/testzip.proto
index 07d4a1d..bc382d5 100644
--- a/misc/nacl/testzip.proto
+++ b/misc/nacl/testzip.proto
@@ -10,9 +10,32 @@ usr	src=../misc/nacl/testdata
 go	src=..
 	src
 		cmd
+			api
+				testdata
+					+
+			asm
+				internal
+					asm
+						testdata
+							+
+			doc
+				main.go
+				pkg.go
+				doc_test.go
+				testdata
+					+
 			internal
 				objfile
 					objfile.go
+				rsc.io
+					arm
+						armasm
+							testdata
+								+
+					x86
+						x86asm
+							testdata
+								+
 			gofmt
 				gofmt.go
 				gofmt_test.go
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 TestCall(t *testing.T) {
 }
 
 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/misc/swig/stdio/file_test.go b/misc/swig/stdio/file_test.go
index 6478a7c..38d0746 100644
--- a/misc/swig/stdio/file_test.go
+++ b/misc/swig/stdio/file_test.go
@@ -10,7 +10,7 @@ import "testing"
 // as expected.
 func TestRead(t *testing.T) {
 	f := Fopen("file_test.go", "r")
-	if f == nil {
+	if f.Swigcptr() == 0 {
 		t.Fatal("fopen failed")
 	}
 	if Fgetc(f) != '/' || Fgetc(f) != '/' || Fgetc(f) != ' ' || Fgetc(f) != 'C' {
diff --git a/misc/trace/README.md b/misc/trace/README.md
new file mode 100644
index 0000000..8561c79
--- /dev/null
+++ b/misc/trace/README.md
@@ -0,0 +1,38 @@
+This directory contains helper file for trace viewer (`go tool trace`).
+
+`trace_viewer_lean.html` was generated by following
+[instructions](https://github.com/google/trace-viewer/wiki/Embedding)
+on revision `280626ef607decf36291e290d5f0322b173e8a7f` using:
+```
+trace-viewer$ ./vulcanize_trace_viewer --config=lean
+trace-viewer$ cp bin/trace_viewer_lean.html $GOROOT/misc/trace/
+```
+
+The license for trace-viewer is as follows:
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//    * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//    * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//    * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/misc/trace/trace_viewer_lean.html b/misc/trace/trace_viewer_lean.html
new file mode 100644
index 0000000..5d40bc5
--- /dev/null
+++ b/misc/trace/trace_viewer_lean.html
@@ -0,0 +1,4043 @@
+<!DOCTYPE HTML>
+<html>
+  <head i18n-values="dir:textdirection;">
+  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+    <polymer-element name="tr-ui-b-toolbar-button" noscript="noscript">
+<template>
+<style>
+    :host {
+      background-color: #f8f8f8;
+      border: 1px solid rgba(0, 0, 0, 0.5);
+      color: rgba(0,0,0,0.8);
+      text-align: center;
+    }
+    :host(:hover) {
+      background-color: rgba(255, 255, 255, 1.0);
+      border-color: rgba(0, 0, 0, 0.8);
+      box-shadow: 0 0 .05em rgba(0, 0, 0, 0.4);
+      color: rgba(0, 0, 0, 1);
+    }
+    </style>
+<content></content>
+</template>
+</polymer-element><polymer-element name="tr-ui-a-tab-view" constructor="TracingAnalysisTabView">
+<template>
+<style>
+      :host {
+        display: flex;
+        flex-flow: column nowrap;
+        overflow: hidden;
+        box-sizing: border-box;
+      }
+
+      tab-strip[tabs-hidden] {
+        display: none;
+      }
+
+      tab-strip {
+        background-color: rgb(236, 236, 236);
+        border-bottom: 1px solid #8e8e8e;
+        display: flex;
+        flex: 0 0 auto;
+        flex-flow: row;
+        overflow-x: auto;
+        padding: 0 10px 0 10px;
+        font-size: 12px;
+      }
+
+      tab-button {
+        display: block;
+        flex: 0 0 auto;
+        padding: 4px 15px 1px 15px;
+        margin-top: 2px;
+      }
+
+      tab-button[selected=true] {
+        background-color: white;
+        border: 1px solid rgb(163, 163, 163);
+        border-bottom: none;
+        padding: 3px 14px 1px 14px;
+      }
+
+      tabs-content-container {
+        display: flex;
+        flex: 1 1 auto;
+        overflow: auto;
+        width: 100%;
+      }
+
+      ::content > * {
+        flex: 1 1 auto;
+      }
+
+      ::content > *:not([selected]) {
+        display: none;
+      }
+
+      button-label {
+        display: inline;
+      }
+
+      tab-strip-heading {
+        display: block;
+        flex: 0 0 auto;
+        padding: 4px 15px 1px 15px;
+        margin-top: 2px;
+        margin-before: 20px;
+        margin-after: 10px;
+      }
+      #tsh {
+        display: inline;
+        font-weight: bold;
+      }
+    </style>
+<tab-strip>
+<tab-strip-heading id="tshh">
+<span id="tsh"></span>
+</tab-strip-heading>
+<template repeat="{{tab in tabs_}}">
+<tab-button button-id="{{ tab.id }}" on-click="{{ tabButtonSelectHandler_ }}" selected="{{ selectedTab_.id === tab.id }}">
+<button-label>{{ tab.label ? tab.label : 'No Label'}}</button-label>
+</tab-button>
+</template>
+</tab-strip>
+<tabs-content-container id="content-container">
+<content></content>
+</tabs-content-container>
+</template>
+
+</polymer-element><template id="overlay-template">
+<style>
+    overlay-mask {
+      left: 0;
+      padding: 8px;
+      position: absolute;
+      top: 0;
+      z-index: 1000;
+      font-family: sans-serif;
+      -webkit-justify-content: center;
+      background: rgba(0, 0, 0, 0.8);
+      display: -webkit-flex;
+      height: 100%;
+      left: 0;
+      position: fixed;
+      top: 0;
+      width: 100%;
+    }
+    overlay-mask:focus {
+      outline: none;
+    }
+    overlay-vertical-centering-container {
+      -webkit-justify-content: center;
+      -webkit-flex-direction: column;
+      display: -webkit-flex;
+    }
+    overlay-frame {
+      z-index: 1100;
+      background: rgb(255, 255, 255);
+      border: 1px solid #ccc;
+      margin: 75px;
+      display: -webkit-flex;
+      -webkit-flex-direction: column;
+      min-height: 0;
+    }
+    title-bar {
+      -webkit-align-items: center;
+      -webkit-flex-direction: row;
+      border-bottom: 1px solid #ccc;
+      background-color: #ddd;
+      display: -webkit-flex;
+      padding: 5px;
+      -webkit-flex: 0 0 auto;
+    }
+    title {
+      display: inline;
+      font-weight: bold;
+      -webkit-box-flex: 1;
+      -webkit-flex: 1 1 auto;
+    }
+    close-button {
+      -webkit-align-self: flex-end;
+      border: 1px solid #eee;
+      background-color: #999;
+      font-size: 10pt;
+      font-weight: bold;
+      padding: 2px;
+      text-align: center;
+      width: 16px;
+    }
+    close-button:hover {
+      background-color: #ddd;
+      border-color: black;
+      cursor: pointer;
+    }
+    overlay-content {
+      display: -webkit-flex;
+      -webkit-flex: 1 1 auto;
+      -webkit-flex-direction: column;
+      overflow-y: auto;
+      padding: 10px;
+      min-width: 300px;
+      min-height: 0;
+    }
+    button-bar {
+      -webkit-align-items: baseline;
+      border-top: 1px solid #ccc;
+      display: -webkit-flex;
+      -webkit-flex: 0 0 auto;
+      -webkit-flex-direction: row-reverse;
+      padding: 4px;
+    }
+  </style>
+<overlay-mask>
+<overlay-vertical-centering-container>
+<overlay-frame>
+<title-bar>
+<title></title>
+<close-button>&#x2715</close-button>
+</title-bar>
+<overlay-content>
+<content></content>
+</overlay-content>
+<button-bar></button-bar>
+</overlay-frame>
+</overlay-vertical-centering-container>
+</overlay-mask>
+</template><polymer-element name="tr-ui-a-sub-view">
+
+</polymer-element><polymer-element name="tr-ui-a-analysis-link" is="a">
+<template>
+<style>
+    :host {
+      display: inline;
+      color: -webkit-link;
+      cursor: pointer;
+      text-decoration: underline;
+      /* TODO(nduca): Whitespace is forced to normal here because the
+         analysis_results.css forces everything under it to pre. This is insane.
+         When that horrible evil class dies, then we can rip this white-space
+         restriction out.
+       */
+      white-space: normal;
+      cursor: pointer;
+    }
+    </style>
+<content></content>
+</template>
+
+</polymer-element><style>
+* /deep/ .labeled-checkbox {
+  display: flex;
+  white-space: nowrap;
+}
+</style><polymer-element name="tr-ui-b-table">
+<template>
+<style>
+      :host {
+        display: flex;
+        flex-direction: column;
+      }
+
+      table {
+        font-size: 12px;
+
+        flex: 1 1 auto;
+        align-self: stretch;
+        border-collapse: separate;
+        border-spacing: 0;
+        border-width: 0;
+        -webkit-user-select: initial;
+      }
+
+      tr > td {
+        padding: 2px 4px 2px 4px;
+        vertical-align: text-top;
+      }
+
+      tr:focus,
+      td:focus {
+        outline: 1px dotted rgba(0,0,0,0.1);
+        outline-offset: 0;
+      }
+
+      button.toggle-button {
+        height: 15px;
+        line-height: 60%;
+        vertical-align: middle;
+        width: 100%;
+      }
+
+      button > * {
+        height: 15px;
+        vertical-align: middle;
+      }
+
+      td.button-column {
+        width: 30px;
+      }
+
+      table > thead > tr > td.sensitive:hover {
+        background-color: #fcfcfc;
+      }
+
+      table > thead > tr > td {
+        font-weight: bold;
+        text-align: left;
+
+        background-color: #eee;
+        white-space: nowrap;
+        overflow: hidden;
+        text-overflow: ellipsis;
+
+        border-top: 1px solid #ffffff;
+        border-bottom: 1px solid #aaa;
+      }
+
+      table > tfoot {
+        background-color: #eee;
+        font-weight: bold;
+      }
+
+      /* Selection. */
+      table > tbody.row-selection-mode > tr[selected],
+      table > tbody.cell-selection-mode > tr > td[selected] {
+        background-color: rgb(103, 199, 165);  /* turquoise */
+      }
+      table > tbody.cell-selection-mode.row-highlight-enabled >
+          tr.highlighted-row {
+        background-color: rgb(213, 236, 229);  /* light turquoise */
+      }
+
+      /* Hover. */
+      table > tbody.row-selection-mode >
+          tr:hover:not(.empty-row):not([selected]),
+      table > tbody.cell-selection-mode >
+          tr:not(.empty-row):not(.highlighted-row) >
+          td.supports-selection:hover:not([selected]),
+      table > tfoot > tr:hover {
+        background-color: #e6e6e6;  /* grey */
+      }
+      table > tbody.cell-selection-mode.row-highlight-enabled >
+          tr:hover:not(.empty-row):not(.highlighted-row) {
+        background-color: #f6f6f6;  /* light grey */
+      }
+
+      /* Hover on selected and highlighted elements. */
+      table > tbody.row-selection-mode > tr:hover[selected],
+      table > tbody.cell-selection-mode > tr > td:hover[selected],
+      table > tbody.cell-selection-mode > tr.highlighted-row > td:hover {
+        background-color: rgb(171, 217, 202);  /* semi-light turquoise */
+      }
+
+      table > tbody > tr.empty-row > td {
+        color: #666;
+        font-style: italic;
+        text-align: center;
+      }
+
+      table > tbody.has-footer > tr:last-child > td {
+        border-bottom: 1px solid #aaa;
+      }
+
+      table > tfoot > tr:first-child > td {
+        border-top: 1px solid #ffffff;
+      }
+
+      expand-button {
+        -webkit-user-select: none;
+        display: inline-block;
+        cursor: pointer;
+        font-size: 9px;
+        min-width: 8px;
+        max-width: 8px;
+      }
+
+      .button-expanded {
+        transform: rotate(90deg);
+      }
+    </style>
+<table>
+<thead id="head">
+</thead>
+<tbody id="body">
+</tbody>
+<tfoot id="foot">
+</tfoot>
+</table>
+</template>
+
+</polymer-element>
+<polymer-element name="tr-ui-b-table-header-cell" on-tap="onTap_">
+<template>
+<style>
+    :host {
+      -webkit-user-select: none;
+      display: flex;
+    }
+
+    span {
+      flex: 0 1 auto;
+    }
+
+    side-element {
+      -webkit-user-select: none;
+      flex: 1 0 auto;
+      padding-left: 4px;
+      vertical-align: top;
+      font-size: 15px;
+      font-family: sans-serif;
+      display: inline;
+      line-height: 85%;
+    }
+  </style>
+<span id="title"></span><side-element id="side"></side-element>
+</template>
+
+</polymer-element><polymer-element name="tr-ui-u-time-duration-span">
+<template>
+<style>
+    :host {
+      display: flex;
+      flex-direction: row;
+      align-items: center;
+    }
+    #warning {
+      margin-left: 4px;
+      font-size: 66%;
+    }
+    </style>
+<span id="content"></span>
+<span id="warning" style="display:none">⚠</span>
+</template>
+
+</polymer-element><polymer-element name="tr-ui-u-time-stamp-span">
+<template>
+</template>
+
+</polymer-element><polymer-element name="tr-ui-u-size-in-bytes-span">
+<template>
+<style>
+    :host {
+      display: flex;
+      flex-direction: row;
+      align-items: center;
+    }
+    </style>
+<span id="content"></span>
+</template>
+
+</polymer-element><polymer-element name="tr-ui-a-generic-object-view" is="HTMLUnknownElement">
+<template>
+<style>
+    :host {
+      display: block;
+      font-family: monospace;
+    }
+    </style>
+<div id="content">
+</div>
+</template>
+
+</polymer-element>
+<polymer-element name="tr-ui-a-generic-object-view-with-label" is="HTMLUnknownElement">
+<template>
+<style>
+    :host {
+      display: block;
+    }
+    </style>
+</template>
+
+</polymer-element><polymer-element name="tr-ui-a-stack-frame">
+<template>
+<style>
+    :host {
+      display: flex;
+      flex-direction: row;
+      align-items: center;
+    }
+    </style>
+<tr-ui-a-generic-object-view id="ov">
+</tr-ui-a-generic-object-view>
+</template>
+
+</polymer-element><polymer-element name="tr-ui-a-single-event-sub-view" extends="tr-ui-a-sub-view">
+<template>
+<style>
+    :host {
+      display: flex;
+      flex-direction: column;
+    }
+    #table {
+      flex: 1 1 auto;
+      align-self: stretch;
+    }
+    </style>
+<tr-ui-b-table id="table">
+</tr-ui-b-table>
+</template>
+
+</polymer-element><polymer-element name="tr-ui-a-related-events">
+<template>
+<style>
+    :host {
+      display: flex;
+      flex-direction: column;
+    }
+    #table {
+      flex: 1 1 auto;
+      align-self: stretch;
+    }
+    </style>
+<tr-ui-b-table id="table"></tr-ui-b-table>
+</template>
+
+</polymer-element><polymer-element name="tr-ui-a-single-thread-slice-sub-view" extends="tr-ui-a-sub-view">
+<template>
+<style>
+    :host {
+      display: flex;
+      flex-direction: row;
+    }
+    #events {
+      display: flex;
+      flex-direction: column;
+    }
+
+    </style>
+<tr-ui-a-single-event-sub-view id="content"></tr-ui-a-single-event-sub-view>
+<div id="events">
+<tr-ui-a-related-events id="relatedEvents">
+</tr-ui-a-related-events>
+</div>
+</template>
+
+</polymer-element><polymer-element name="tr-ui-a-selection-summary-table">
+<template>
+<style>
+    :host {
+      display: flex;
+    }
+    #table {
+      flex: 1 1 auto;
+      align-self: stretch;
+    }
+    </style>
+<tr-ui-b-table id="table">
+</tr-ui-b-table>
+</template>
+
+</polymer-element><polymer-element name="tr-ui-a-multi-event-summary-table">
+<template>
+<style>
+    :host {
+      display: flex;
+    }
+    #table {
+      flex: 1 1 auto;
+      align-self: stretch;
+    }
+    </style>
+<tr-ui-b-table id="table">
+</tr-ui-b-table>
+</template>
+
+</polymer-element><polymer-element name="tr-ui-a-multi-event-details-table">
+<template>
+<style>
+    :host {
+      display: flex;
+      flex-direction: column;
+    }
+    #table {
+      flex: 1 1 auto;
+      align-self: stretch;
+    }
+
+    #titletable {
+      font-weight: bold;
+    }
+
+    #title-info {
+      font-size: 12px;
+    }
+    </style>
+<tr-ui-b-table id="titletable">
+</tr-ui-b-table>
+<tr-ui-b-table id="table">
+</tr-ui-b-table>
+</template>
+
+</polymer-element><polymer-element name="tr-ui-a-multi-event-sub-view" extends="tr-ui-a-sub-view">
+<template>
+<style>
+    :host {
+      display: flex;
+      overflow: auto;
+    }
+    #content {
+      display: flex;
+      flex-direction: column;
+      flex: 0 1 auto;
+      align-self: stretch;
+    }
+    #content > * {
+      flex: 0 0 auto;
+      align-self: stretch;
+    }
+    tr-ui-a-multi-event-summary-table {
+      border-bottom: 1px solid #aaa;
+    }
+
+    tr-ui-a-selection-summary-table  {
+      margin-top: 1.25em;
+      border-top: 1px solid #aaa;
+      background-color: #eee;
+      font-weight: bold;
+      margin-bottom: 1.25em;
+      border-bottom: 1px solid #aaa;
+    }
+    </style>
+<div id="content"></div>
+</template>
+
+</polymer-element><polymer-element name="tr-ui-a-multi-thread-slice-sub-view" extends="tr-ui-a-sub-view">
+<template>
+<style>
+    :host {
+      display: flex;
+    }
+    #content {
+      display: flex;
+      flex: 1 1 auto;
+    }
+    #content > tr-ui-a-related-events {
+      margin-left: 8px;
+    }
+    </style>
+<div id="content"></div>
+</template>
+
+</polymer-element><polymer-element name="tr-ui-a-single-async-slice-sub-view" extends="tr-ui-a-single-event-sub-view">
+
+</polymer-element><polymer-element name="tr-ui-a-multi-async-slice-sub-view" extends="tr-ui-a-sub-view">
+<template>
+<style>
+    :host {
+      display: flex;
+    }
+    </style>
+<tr-ui-a-multi-event-sub-view id="content"></tr-ui-a-multi-event-sub-view>
+</template>
+
+</polymer-element><polymer-element name="tr-ui-a-single-cpu-slice-sub-view" extends="tr-ui-a-sub-view">
+<template>
+<style>
+    table {
+      border-collapse: collapse;
+      border-width: 0;
+      margin-bottom: 25px;
+      width: 100%;
+    }
+
+    table tr > td:first-child {
+      padding-left: 2px;
+    }
+
+    table tr > td {
+      padding: 2px 4px 2px 4px;
+      vertical-align: text-top;
+      width: 150px;
+    }
+
+    table td td {
+      padding: 0 0 0 0;
+      width: auto;
+    }
+    tr {
+      vertical-align: top;
+    }
+
+    tr:nth-child(2n+0) {
+      background-color: #e2e2e2;
+    }
+    </style>
+<table>
+<tr>
+<td>Running process:</td><td id="process-name"></td>
+</tr>
+<tr>
+<td>Running thread:</td><td id="thread-name"></td>
+</tr>
+<tr>
+<td>Start:</td><td id="start"></td>
+</tr>
+<tr>
+<td>Duration:</td><td id="duration"></td>
+</tr>
+<tr>
+<td>Active slices:</td><td id="running-thread"></td>
+</tr>
+<tr>
+<td>Args:</td>
+<td>
+<tr-ui-a-generic-object-view id="args">
+</tr-ui-a-generic-object-view>
+</td>
+</tr>
+</table>
+</template>
+
+</polymer-element><polymer-element name="tr-ui-a-multi-cpu-slice-sub-view" extends="tr-ui-a-sub-view">
+<template>
+<style>
+    :host {
+      display: flex;
+    }
+    #content {
+      flex: 1 1 auto;
+    }
+    </style>
+<tr-ui-a-multi-event-sub-view id="content"></tr-ui-a-multi-event-sub-view>
+</template>
+
+</polymer-element><polymer-element name="tr-ui-a-single-thread-time-slice-sub-view" extends="tr-ui-a-sub-view">
+<template>
+<style>
+    table {
+      border-collapse: collapse;
+      border-width: 0;
+      margin-bottom: 25px;
+      width: 100%;
+    }
+
+    table tr > td:first-child {
+      padding-left: 2px;
+    }
+
+    table tr > td {
+      padding: 2px 4px 2px 4px;
+      vertical-align: text-top;
+      width: 150px;
+    }
+
+    table td td {
+      padding: 0 0 0 0;
+      width: auto;
+    }
+    tr {
+      vertical-align: top;
+    }
+
+    tr:nth-child(2n+0) {
+      background-color: #e2e2e2;
+    }
+    </style>
+<table>
+<tr>
+<td>Running process:</td><td id="process-name"></td>
+</tr>
+<tr>
+<td>Running thread:</td><td id="thread-name"></td>
+</tr>
+<tr>
+<td>State:</td>
+<td><b><span id="state"></span></b></td>
+</tr>
+<tr>
+<td>Start:</td><td id="start"></td>
+</tr>
+<tr>
+<td>Duration:</td><td id="duration"></td>
+</tr>
+<tr>
+<td>On CPU:</td><td id="on-cpu"></td>
+</tr>
+<tr>
+<td>Running instead:</td><td id="running-instead"></td>
+</tr>
+<tr>
+<td>Args:</td><td id="args"></td>
+</tr>
+</table>
+</template>
+
+</polymer-element><polymer-element name="tr-ui-a-multi-thread-time-slice-sub-view" extends="tr-ui-a-sub-view">
+<template>
+<style>
+    :host {
+      display: flex;
+    }
+    #content {
+      flex: 1 1 auto;
+    }
+    </style>
+<tr-ui-a-multi-event-sub-view id="content"></tr-ui-a-multi-event-sub-view>
+</template>
+
+</polymer-element><polymer-element name="tr-ui-a-single-instant-event-sub-view" extends="tr-ui-a-sub-view">
+<template>
+<style>
+    :host {
+      display: block;
+    }
+    </style>
+<div id="content"></div>
+</template>
+
+</polymer-element><polymer-element name="tr-ui-a-multi-instant-event-sub-view" extends="tr-ui-a-sub-view">
+<template>
+<style>
+    :host {
+      display: block;
+    }
+    </style>
+<div id="content"></div>
+</template>
+
+</polymer-element><style>
+.analysis-header{font-weight:bold}.analysis-results{font-family:monospace;white-space:pre}.analysis-results *{-webkit-user-select:text!important;cursor:text}.analysis-table{border-collapse:collapse;border-width:0;margin-bottom:25px;width:100%}.analysis-table tr>td:first-child{padding-left:2px}.analysis-table tr>td{padding:2px 4px 2px 4px;vertical-align:text-top;width:150px}.analysis-table td td{padding:0 0 0 0;width:auto}.analysis-table-header{text-align:left}.analysis-table-row{vertical [...]
+</style><polymer-element name="tr-ui-a-counter-sample-sub-view" extends="tr-ui-a-sub-view">
+
+</polymer-element><polymer-element name="tr-ui-a-single-flow-event-sub-view" extends="tr-ui-a-single-event-sub-view">
+
+</polymer-element><polymer-element name="tr-ui-a-multi-flow-event-sub-view" extends="tr-ui-a-sub-view">
+<template>
+<style>
+    :host {
+      display: flex;
+    }
+    </style>
+<tr-ui-a-multi-event-sub-view id="content"></tr-ui-a-multi-event-sub-view>
+</template>
+
+</polymer-element><polymer-element name="tr-ui-a-single-object-instance-sub-view" extends="tr-ui-a-sub-view">
+<template>
+<style>
+    :host {
+      display: block;
+    }
+
+    #snapshots > * {
+      display: block;
+    }
+
+    :host {
+      overflow: auto;
+      display: block;
+    }
+
+    * {
+      -webkit-user-select: text;
+    }
+
+    .title {
+      border-bottom: 1px solid rgb(128, 128, 128);
+      font-size: 110%;
+      font-weight: bold;
+    }
+
+    td, th {
+      font-family: monospace;
+      vertical-align: top;
+    }
+    </style>
+<div id="content"></div>
+</template>
+
+</polymer-element><polymer-element name="tr-ui-a-single-object-snapshot-sub-view" extends="tr-ui-a-sub-view">
+<template>
+<style>
+    #args {
+      white-space: pre;
+    }
+
+    :host {
+      overflow: auto;
+      display: flex;
+    }
+
+    * {
+      -webkit-user-select: text;
+    }
+
+    .title {
+      border-bottom: 1px solid rgb(128, 128, 128);
+      font-size: 110%;
+      font-weight: bold;
+    }
+
+    td, th {
+      font-family: monospace;
+      vertical-align: top;
+    }
+    </style>
+<content></content>
+</template>
+
+</polymer-element><polymer-element name="tr-ui-a-multi-object-sub-view" extends="tr-ui-a-sub-view">
+<template>
+<style>
+    :host {
+      display: flex;
+    }
+    </style>
+<tr-ui-b-table id="content"></tr-ui-b-table>
+</template>
+
+</polymer-element><polymer-element name="tr-ui-a-single-sample-sub-view" extends="tr-ui-a-sub-view">
+<template>
+<style>
+    :host {
+      display: flex;
+    }
+    </style>
+<tr-ui-b-table id="content"></tr-ui-b-table>
+</template>
+
+</polymer-element><polymer-element name="tr-ui-a-multi-sample-sub-view" extends="tr-ui-a-sub-view">
+<template>
+<style>
+    :host {
+      display: block;
+    }
+    </style>
+<div id="content"></div>
+</template>
+
+</polymer-element><polymer-element name="tr-ui-a-single-interaction-record-sub-view" extends="tr-ui-a-sub-view">
+
+</polymer-element><polymer-element name="tr-ui-a-multi-interaction-record-sub-view" extends="tr-ui-a-sub-view">
+
+</polymer-element><polymer-element name="tr-ui-a-alert-sub-view" extends="tr-ui-a-sub-view">
+<template>
+<style>
+    :host {
+      display: flex;
+      flex-direction: column;
+    }
+    #table {
+      flex: 1 1 auto;
+      align-self: stretch;
+    }
+    </style>
+<tr-ui-b-table id="table">
+</tr-ui-b-table>
+</template>
+
+</polymer-element><polymer-element name="tr-ui-a-single-frame-sub-view" extends="tr-ui-a-sub-view">
+<template>
+<style>
+    :host {
+      display: flex;
+      flex-direction: column;
+    }
+    #asv {
+      flex: 0 0 auto;
+      align-self: stretch;
+    }
+    </style>
+<tr-ui-a-alert-sub-view id="asv">
+</tr-ui-a-alert-sub-view>
+</template>
+
+</polymer-element><polymer-element name="tr-ui-a-multi-frame-sub-view" extends="tr-ui-a-sub-view">
+
+</polymer-element><polymer-element name="tr-ui-b-color-legend">
+<template>
+<style>
+    :host {
+      display: inline-block;
+    }
+
+    #square {
+      font-size: 150%;  /* Make the square bigger. */
+      line-height: 0%;  /* Prevent the square from increasing legend height. */
+    }
+    </style>
+<span id="square"></span>
+<span id="label"></span>
+</template>
+
+</polymer-element><polymer-element name="tr-ui-a-memory-dump-allocator-details-pane">
+<template>
+<style>
+      :host {
+        display: flex;
+        flex-direction: column;
+      }
+
+      #label {
+        flex: 0 0 auto;
+        padding: 8px;
+
+        background-color: #eee;
+        border-bottom: 1px solid #8e8e8e;
+        border-top: 1px solid white;
+
+        font-size:  15px;
+        font-weight: bold;
+      }
+
+      #contents {
+        flex: 1 0 auto;
+        align-self: stretch;
+        font-size: 12px;
+      }
+
+      #contents .info-text {
+        padding: 8px;
+        color: #666;
+        font-style: italic;
+        text-align: center;
+      }
+    </style>
+<div id="label">Allocator details</div>
+<div id="contents"></div>
+</template>
+
+</polymer-element><polymer-element name="tr-ui-a-memory-dump-vm-regions-details-pane">
+<template>
+<style>
+      :host {
+        display: flex;
+        flex-direction: column;
+      }
+
+      #label {
+        flex: 0 0 auto;
+        padding: 8px;
+
+        background-color: #eee;
+        border-bottom: 1px solid #8e8e8e;
+        border-top: 1px solid white;
+
+        font-size:  15px;
+        font-weight: bold;
+      }
+
+      #contents {
+        flex: 1 0 auto;
+        align-self: stretch;
+        font-size: 12px;
+      }
+
+      #contents .info-text {
+        padding: 8px;
+        color: #666;
+        font-style: italic;
+        text-align: center;
+      }
+    </style>
+<div id="label">Memory maps</div>
+<div id="contents"></div>
+</template>
+
+</polymer-element><polymer-element name="tr-ui-a-memory-dump-overview-pane">
+<template>
+<style>
+      :host {
+        display: flex;
+        flex-direction: column;
+      }
+
+      #label {
+        flex: 0 0 auto;
+        padding: 8px;
+
+        background-color: #eee;
+        border-bottom: 1px solid #8e8e8e;
+        border-top: 1px solid white;
+
+        font-size:  15px;
+        font-weight: bold;
+      }
+
+      #table {
+        flex: 1 0 auto;
+        align-self: stretch;
+      }
+    </style>
+<div id="label">Overview</div>
+<tr-ui-b-table id="table">
+</tr-ui-b-table>
+</template>
+
+</polymer-element><polymer-element name="tr-ui-a-memory-dump-view">
+<template>
+<style>
+    :host {
+      display: flex;
+      flex-direction: column;
+    }
+
+    #overview_pane,
+    #details_pane_container {
+      flex: 0 0 auto;
+    }
+    </style>
+<tr-ui-a-memory-dump-overview-pane id="overview_pane">
+</tr-ui-a-memory-dump-overview-pane>
+<div id="details_pane_container">
+</div>
+</template>
+
+</polymer-element><polymer-element name="tr-ui-a-single-process-memory-dump-sub-view" extends="tr-ui-a-sub-view">
+<template>
+<tr-ui-a-memory-dump-view id="memory_dump_view">
+</tr-ui-a-memory-dump-view>
+</template>
+
+</polymer-element><polymer-element name="tr-ui-a-multi-process-memory-dump-sub-view" extends="tr-ui-a-sub-view">
+<template>
+<style>
+    :host {
+      display: flex;
+    }
+    </style>
+<tr-ui-b-table id="content"></tr-ui-b-table>
+</template>
+
+</polymer-element><polymer-element name="tr-ui-a-single-global-memory-dump-sub-view" extends="tr-ui-a-sub-view">
+<template>
+<tr-ui-a-memory-dump-view id="memory_dump_view">
+</tr-ui-a-memory-dump-view>
+</template>
+
+</polymer-element><polymer-element name="tr-ui-a-multi-global-memory-dump-sub-view" extends="tr-ui-a-sub-view">
+<template>
+<style>
+    :host {
+      display: flex;
+    }
+    </style>
+<tr-ui-b-table id="content"></tr-ui-b-table>
+</template>
+
+</polymer-element><polymer-element name="tr-ui-a-analysis-view">
+<template>
+<style>
+      :host {
+        background-color: white;
+        display: flex;
+        flex-direction: column;
+        height: 275px;
+        overflow: auto;
+      }
+
+      :host(.tall-mode) {
+        height: 525px;
+      }
+
+      ::content > * {
+        flex: 1 0 auto;
+      }
+    </style>
+<content></content>
+</template>
+
+</polymer-element><style>
+.track-button{background-color:rgba(255,255,255,0.5);border:1px solid rgba(0,0,0,0.1);color:rgba(0,0,0,0.2);font-size:10px;height:12px;text-align:center;width:12px}.track-button:hover{background-color:rgba(255,255,255,1.0);border:1px solid rgba(0,0,0,0.5);box-shadow:0 0 .05em rgba(0,0,0,0.4);color:rgba(0,0,0,1)}.track-close-button{left:2px;position:absolute;top:2px}.track-collapse-button{left:3px;position:absolute;top:2px}
+</style><style>
+.drawing-container{-webkit-box-flex:1;display:inline;overflow:auto;overflow-x:hidden;position:relative}.drawing-container-canvas{-webkit-box-flex:1;display:block;pointer-events:none;position:absolute;top:0}
+</style><style>
+.heading-track{-webkit-box-align:stretch;-webkit-box-orient:horizontal;display:-webkit-box;margin:0;padding:0 5px 0 0}.heading-track>heading{-webkit-box-sizing:border-box;background-color:rgb(243,245,247);border-right:1px solid #8e8e8e;box-sizing:border-box;display:-webkit-flex;-webkit-flex-direction:row;align-items:center;overflow-x:hidden;padding-right:5px;text-align:left;text-overflow:ellipsis;white-space:nowrap}.heading-track>heading>.heading-arrow{-webkit-flex:0 0 auto;margin-left:5 [...]
+</style><style>
+.chart-track {
+  height: 30px;
+  position: relative;
+}
+</style><style>
+.letter-dot-track {
+  height: 18px;
+}
+</style><style>
+.object-instance-track{height:18px}
+</style><style>
+.rect-track{height:18px}
+</style><style>
+.spacing-track{height:4px}
+</style><style>
+.thread-track{-webkit-box-orient:vertical;display:-webkit-box;position:relative}
+</style><style>
+.process-track-header{-webkit-flex:0 0 auto;background-image:-webkit-gradient(linear,0 0,100% 0,from(#E5E5E5),to(#D1D1D1));border-bottom:1px solid #8e8e8e;border-top:1px solid white;font-size:75%}.process-track-name:before{content:'\25B8';padding:0 5px}.process-track-base.expanded .process-track-name:before{content:'\25BE'}
+</style><style>
+.model-track {
+  -webkit-box-flex: 1;
+}
+</style><style>
+.ruler-track{height:12px}.ruler-track.tall-mode{height:30px}
+</style><style>
+* /deep/ .mouse-mode-selector{-webkit-user-drag:element;-webkit-user-select:none;background:#DDD;border:1px solid #BBB;border-radius:4px;box-shadow:0 1px 2px rgba(0,0,0,0.2);left:calc(100% - 120px);position:absolute;top:100px;user-select:none;width:29px;z-index:20}* /deep/ .mouse-mode-icon{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAAChCAYAAACbBNzvAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAABV0RVh0Q3JlYXRpb24gVGltZQA3LzE2LzEzRNEKUwAAABx0RVh0U29mdHdhcm [...]
+</style>
+<style>
+* /deep/ .tool-button{background-position:center center;background-repeat:no-repeat;border-bottom:1px solid #BCBCBC;border-top:1px solid #F1F1F1;cursor:pointer;height:30px}* /deep/ .tool-button.active{cursor:auto}
+</style>
+<template id="mouse-mode-selector-template">
+<div class="drag-handle"></div>
+<div class="buttons">
+</div>
+</template><style>
+body *{-webkit-user-select:none;box-sizing:border-box}
+</style>
+<style>
+.timeline-track-view *{-webkit-user-select:none;cursor:default}.timeline-track-view .tool-button{cursor:pointer}.timeline-track-view{-webkit-box-orient:vertical;display:-webkit-box;position:relative}.model-track-container{-webkit-box-flex:1;overflow:auto}.drag-box{background-color:rgba(0,0,255,0.25);border:1px solid rgb(0,0,96);font-size:75%;position:fixed}.timeline-track-view>.hint-text{position:absolute;bottom:6px;right:6px;font-size:8pt}
+</style><polymer-element name="tr-ui-find-control" constructor="TracingFindControl">
+<template>
+<style>
+      :host {
+        -webkit-user-select: none;
+        display: -webkit-flex;
+        position: relative;
+      }
+      input {
+        -webkit-user-select: auto;
+        background-color: #f8f8f8;
+        border: 1px solid rgba(0, 0, 0, 0.5);
+        box-sizing: border-box;
+        margin: 0;
+        padding: 0;
+        width: 170px;
+      }
+      input:focus {
+        background-color: white;
+      }
+      tr-ui-b-toolbar-button {
+        border-left: none;
+        font-size: 14px;
+        margin: 0;
+      }
+      #hitCount {
+        left: 0;
+        opacity: 0.25;
+        pointer-events: none;
+        position: absolute;
+        text-align: right;
+        top: 2px;
+        width: 167px;
+        z-index: 1;
+      }
+      #spinner {
+        visibility: hidden;
+        width: 8px;
+        height: 8px;
+        left: 154px;
+        pointer-events: none;
+        position: absolute;
+        top: 4px;
+        z-index: 1;
+
+        border: 2px solid transparent;
+        border-bottom: 2px solid rgba(0, 0, 0, 0.5);
+        border-right: 2px solid rgba(0, 0, 0, 0.5);
+        border-radius: 50%;
+
+        animation: spin 1s linear infinite;
+      }
+      @keyframes spin { 100% { transform: rotate(360deg); } }
+    </style>
+<input type="text" id="filter" on-input="{{ filterTextChanged }}" on-keypress="{{ filterKeyPress }}" on-keydown="{{ filterKeyDown }}" on-blur="{{ filterBlur }}" on-focus="{{ filterFocus }}" on-mouseup="{{ filterMouseUp }}" />
+<div id="spinner"></div>
+<tr-ui-b-toolbar-button on-click="{{ findPrevious }}">
+      ←
+    </tr-ui-b-toolbar-button>
+<tr-ui-b-toolbar-button on-click="{{ findNext }}">
+      →
+    </tr-ui-b-toolbar-button>
+<div id="hitCount">0 of 0</div>
+</template>
+
+</polymer-element><polymer-element name="tracing-scripting-control" constructor="TracingScriptingControl">
+<template>
+<style>
+      :host {
+        flex: 1 1 auto;
+      }
+      .root {
+        font-family: monospace;
+        cursor: text;
+
+        padding: 2px;
+        margin: 2px;
+        border: 1px solid rgba(0, 0, 0, 0.5);
+        background: white;
+
+        height: 100px;
+        overflow-y: auto;
+
+        transition-property: opacity, height, padding, margin;
+        transition-duration: .2s;
+        transition-timing-function: ease-out;
+      }
+      .hidden {
+        margin-top: 0px;
+        margin-bottom: 0px;
+        padding-top: 0px;
+        padding-bottom: 0px;
+        height: 0px;
+        opacity: 0;
+      }
+      .focused {
+        outline: auto 5px -webkit-focus-ring-color;
+      }
+      #history {
+        -webkit-user-select: text;
+        color: #777;
+      }
+      #prompt {
+        -webkit-user-select: text;
+        -webkit-user-modify: read-write-plaintext-only;
+        text-overflow: clip !important;
+        text-decoration: none !important;
+      }
+      #prompt:focus {
+        outline: none;
+      }
+      #prompt br {
+        display: none;
+      }
+      #prompt ::before {
+        content: ">";
+        color: #468;
+      }
+    </style>
+<div id="root" class="root hidden" tabindex="0" on-focus="{{ onConsoleFocus }}">
+<div id="history"></div>
+<div id="prompt" on-keypress="{{ promptKeyPress }}" on-keydown="{{ promptKeyDown }}" on-blur="{{ onConsoleBlur }}">
+</div></div></template>
+
+</polymer-element><polymer-element name="tr-ui-side-panel">
+
+</polymer-element><polymer-element name="tr-ui-side-panel-container" is="HTMLUnknownElement">
+<template>
+<style>
+    :host {
+      align-items: stretch;
+      display: -webkit-flex;
+    }
+
+    :host([expanded]) > active-panel-container {
+      -webkit-flex: 1 1 auto;
+      border-left: 1px solid black;
+      display: -webkit-flex;
+    }
+
+    :host(:not([expanded])) > active-panel-container {
+      display: none;
+    }
+
+    active-panel-container {
+      display: flex;
+    }
+
+    tab-strip {
+      -webkit-flex: 0 0 auto;
+      -webkit-flex-direction: column;
+      -webkit-user-select: none;
+      background-color: rgb(236, 236, 236);
+      border-left: 1px solid black;
+      cursor: default;
+      display: -webkit-flex;
+      min-width: 18px; /* workaround for flexbox and writing-mode mixing bug */
+      padding: 10px 0 10px 0;
+      font-size: 12px;
+    }
+
+    tab-strip > tab-strip-label {
+      -webkit-writing-mode: vertical-rl;
+      display: inline;
+      margin-right: 1px;
+      min-height: 20px;
+      padding: 15px 3px 15px 1px;
+    }
+
+    tab-strip >
+        tab-strip-label:not([enabled]) {
+      color: rgb(128, 128, 128);
+    }
+
+    tab-strip > tab-strip-label[selected] {
+      background-color: white;
+      border: 1px solid rgb(163, 163, 163);
+      border-left: none;
+      padding: 14px 2px 14px 1px;
+    }
+    </style>
+<active-panel-container id="active_panel_container">
+</active-panel-container>
+<tab-strip id="tab_strip"></tab-strip>
+</template>
+
+</polymer-element><polymer-element name="tr-ui-b-dropdown">
+<template>
+<style>
+    :host {
+      position: relative;
+      display: flex;
+    }
+    #outer {
+      display: flex;
+      flex: 0 0 auto;
+      padding: 1px 4px 1px 4px;
+      -webkit-user-select: none;
+      cursor: default;
+      font-size: 12px;
+    }
+
+    #state {
+      display: flex;
+      flex: 0 0 auto;
+      margin-left: 2px;
+      margin-right: 0px;
+      flex: 0 0 auto;
+    }
+
+    #icon {
+      display: flex;
+      flex: 0 0 auto;
+      flex: 0 0 auto;
+    }
+    dialog {
+      position: absolute;
+      padding: 0;
+      border: 0;
+      margin: 0;
+    }
+    dialog::backdrop {
+      background: rgba(0,0,0,.05);
+    }
+
+    #dialog-frame {
+      background-color: #fff;
+      display: flex;
+      flex-direction: column;
+      flex: 1 1 auto;
+      padding: 6px;
+      border: 1px solid black;
+      -webkit-user-select: none;
+      cursor: default;
+    }
+    </style>
+<tr-ui-b-toolbar-button id="outer">
+<div id="icon">⚙</div>
+<div id="state">▾</div>
+</tr-ui-b-toolbar-button>
+<dialog id="dialog">
+<div id="dialog-frame">
+<content></content>
+</div>
+</dialog>
+</template>
+
+</polymer-element><style>
+* /deep/ x-drag-handle{-webkit-user-select:none;box-sizing:border-box;display:block}* /deep/ x-drag-handle.horizontal-drag-handle{background-image:-webkit-gradient(linear,0 0,0 100%,from(#E5E5E5),to(#D1D1D1));border-bottom:1px solid #8e8e8e;border-top:1px solid white;cursor:ns-resize;height:7px;position:relative;z-index:10}* /deep/ x-drag-handle.vertical-drag-handle{background-image:-webkit-gradient(linear,0 0,100% 0,from(#E5E5E5),to(#D1D1D1));border-left:1px solid white;border-right:1px [...]
+</style><style>
+x-timeline-view{-webkit-flex-direction:column;cursor:default;display:-webkit-flex;font-family:sans-serif;padding:0}x-timeline-view>.control>.title{font-size:14px;height:22px;padding-left:2px;padding-right:8px;padding-top:2px;flex:1 0 auto}x-timeline-view>.control{background-color:#e6e6e6;background-image:-webkit-gradient(linear,0 0,0 100%,from(#E5E5E5),to(#D1D1D1));flex:0 0 auto;overflow-x:auto}x-timeline-view>.control>.bar{display:flex}x-timeline-view>.control::-webkit-scrollbar{height: [...]
+</style>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<template id="timeline-view-template">
+<div class="control">
+<div class="bar">
+<div id="left-controls" class="controls"></div>
+<div class="title">^_^</div>
+<div id="right-controls" class="controls"></div>
+</div>
+<div id="collapsing-controls" class="controls"></div>
+</div>
+<middle-container>
+<track-view-container></track-view-container>
+<tr-ui-side-panel-container></tr-ui-side-panel-container>
+</middle-container>
+<x-drag-handle></x-drag-handle>
+<tr-ui-a-analysis-view id="analysis"></tr-ui-a-analysis-view>
+</template>
+<template id="help-btn-template">
+<tr-ui-b-toolbar-button class="view-help-button">
+    ?
+  </tr-ui-b-toolbar-button>
+<div class="view-help-text">
+<div class="column left">
+<h2>Navigation</h2>
+<div class="pair">
+<div class="command">w/s</div>
+<div class="action">Zoom in/out (+shift: faster)</div>
+</div>
+<div class="pair">
+<div class="command">a/d</div>
+<div class="action">Pan left/right (+shift: faster)</div>
+</div>
+<div class="pair">
+<div class="command">→/shift-TAB</div>
+<div class="action">Select previous event</div>
+</div>
+<div class="pair">
+<div class="command">←/TAB</div>
+<div class="action">Select next event</div>
+</div>
+<h2>Mouse Controls</h2>
+<div class="pair">
+<div class="command">click</div>
+<div class="action">Select event</div>
+</div>
+<div class="pair">
+<div class="command">alt-mousewheel</div>
+<div class="action">Zoom in/out</div>
+</div>
+<h3>
+<span class="mouse-mode-icon select-mode"></span>
+        Select mode
+      </h3>
+<div class="pair">
+<div class="command">drag</div>
+<div class="action">Box select</div>
+</div>
+<div class="pair">
+<div class="command">double click</div>
+<div class="action">Select all events with same title</div>
+</div>
+<h3>
+<span class="mouse-mode-icon pan-mode"></span>
+        Pan mode
+      </h3>
+<div class="pair">
+<div class="command">drag</div>
+<div class="action">Pan the view</div>
+</div>
+<h3>
+<span class="mouse-mode-icon zoom-mode"></span>
+        Zoom mode
+      </h3>
+<div class="pair">
+<div class="command">drag</div>
+<div class="action">Zoom in/out by dragging up/down</div>
+</div>
+<h3>
+<span class="mouse-mode-icon timing-mode"></span>
+        Timing mode
+      </h3>
+<div class="pair">
+<div class="command">drag</div>
+<div class="action">Create or move markers</div>
+</div>
+<div class="pair">
+<div class="command">double click</div>
+<div class="action">Set marker range to slice</div>
+</div>
+</div>
+<div class="column right">
+<h2>General</h2>
+<div class="pair">
+<div class="command">1-4</div>
+<div class="action">Switch mouse mode</div>
+</div>
+<div class="pair">
+<div class="command">shift</div>
+<div class="action">Hold for temporary select</div>
+</div>
+<div class="pair">
+<div class="command">space</div>
+<div class="action">Hold for temporary pan</div>
+</div>
+<div class="pair">
+<div class="command"><span class="mod"></span></div>
+<div class="action">Hold for temporary zoom</div>
+</div>
+<div class="pair">
+<div class="command">/</div>
+<div class="action">Search</div>
+</div>
+<div class="pair">
+<div class="command">enter</div>
+<div class="action">Step through search results</div>
+</div>
+<div class="pair">
+<div class="command">f</div>
+<div class="action">Zoom into selection</div>
+</div>
+<div class="pair">
+<div class="command">z/0</div>
+<div class="action">Reset zoom and pan</div>
+</div>
+<div class="pair">
+<div class="command">g/G</div>
+<div class="action">Toggle 60hz grid</div>
+</div>
+<div class="pair">
+<div class="command">v</div>
+<div class="action">Highlight VSync</div>
+</div>
+<div class="pair">
+<div class="command">h</div>
+<div class="action">Toggle low/high details</div>
+</div>
+<div class="pair">
+<div class="command">m</div>
+<div class="action">Mark current selection</div>
+</div>
+<div class="pair">
+<div class="command">`</div>
+<div class="action">Show or hide the scripting console</div>
+</div>
+<div class="pair">
+<div class="command">?</div>
+<div class="action">Show help</div>
+</div>
+</div>
+</div>
+</template>
+<template id="metadata-btn-template">
+<div class="button view-metadata-button view-info-button">Metadata</div>
+<div class="info-button-text metadata-dialog-text"></div>
+</template>
+<template id="console-btn-template">
+<tr-ui-b-toolbar-button class="view-console-button">
+    »
+  </tr-ui-b-toolbar-button>
+</template><script>
+
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+/* WARNING: This file is auto generated.
+ *
+ * Do not edit directly.
+ */
+
+/**
+ * @license
+ * Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
+ * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+ * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+ * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+ * Code distributed by Google as part of the polymer project is also
+ * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+ */
+// @version 0.5.5
+window.PolymerGestures={},function(a){var b=!1,c=document.createElement("meta");if(c.createShadowRoot){var d=c.createShadowRoot(),e=document.createElement("span");d.appendChild(e),c.addEventListener("testpath",function(a){a.path&&(b=a.path[0]===e),a.stopPropagation()});var f=new CustomEvent("testpath",{bubbles:!0});document.head.appendChild(c),e.dispatchEvent(f),c.parentNode.removeChild(c),d=e=null}c=null;var g={shadow:function(a){return a?a.shadowRoot||a.webkitShadowRoot:void 0},canTarg [...]
+var ab=H,bb=L;a.esprima={parse:R}}(this),function(a){"use strict";function b(a,b,d,e){var f;try{if(f=c(a),f.scopeIdent&&(d.nodeType!==Node.ELEMENT_NODE||"TEMPLATE"!==d.tagName||"bind"!==b&&"repeat"!==b))throw Error("as and in can only be used within <template bind/repeat>")}catch(g){return void console.error("Invalid expression syntax: "+a,g)}return function(a,b,c){var d=f.getBinding(a,e,c);return f.scopeIdent&&d&&(b.polymerExpressionScopeIdent_=f.scopeIdent,f.indexIdent&&(b.polymerExpre [...]
+return q(this,d.open(r(this))),t(this,a,e)},HTMLSelectElement.prototype.bind=function(a,c,d){if("selectedindex"===a&&(a="selectedIndex"),"selectedIndex"!==a&&"value"!==a)return HTMLElement.prototype.bind.call(this,a,c,d);if(this.removeAttribute(a),d)return j(this,a,c);var e=c,f=m(this,a,e);return j(this,a,e.open(k(this,a))),b(this,a,f)}}(this),function(a){"use strict";function b(a){if(!a)throw new Error("Assertion failed")}function c(a){for(var b;b=a.parentNode;)a=b;return a}function d(a [...]
+b.events&&Object.keys(a).length>0&&console.log("[%s] addHostListeners:",this.localName,a);for(var c in a){var d=a[c];PolymerGestures.addEventListener(this,c,this.element.getEventHandler(this,this,d))}},dispatchMethod:function(a,c,d){if(a){b.events&&console.group("[%s] dispatch [%s]",a.localName,c);var e="function"==typeof c?c:a[c];e&&e[d?"apply":"call"](a,d),b.events&&console.groupEnd(),Polymer.flush()}}};a.api.instance.events=d,a.addEventListener=function(a,b,c,d){PolymerGestures.addEve [...]
+function exportPath(name){var parts=name.split('.');var cur=global;for(var part;parts.length&&(part=parts.shift());){if(part in cur){cur=cur[part];}else{cur=cur[part]={};}}
+return cur;};function isDefined(name){var parts=name.split('.');var curObject=global;for(var i=0;i<parts.length;i++){var partName=parts[i];var nextObject=curObject[partName];if(nextObject===undefined)
+return false;curObject=nextObject;}
+return true;}
+var panicElement=undefined;var rawPanicMessages=[];function showPanicElementIfNeeded(){if(panicElement)
+return;var panicOverlay=document.createElement('div');panicOverlay.style.backgroundColor='white';panicOverlay.style.border='3px solid red';panicOverlay.style.boxSizing='border-box';panicOverlay.style.color='black';panicOverlay.style.display='-webkit-flex';panicOverlay.style.height='100%';panicOverlay.style.left=0;panicOverlay.style.padding='8px';panicOverlay.style.position='fixed';panicOverlay.style.top=0;panicOverlay.style.webkitFlexDirection='column';panicOverlay.style.width='100%';pan [...]
+function showPanic(panicTitle,panicDetails){if(panicDetails instanceof Error)
+panicDetails=panicDetails.stack;showPanicElementIfNeeded();var panicMessageEl=document.createElement('div');panicMessageEl.innerHTML='<h2 id="message"></h2>'+'<pre id="details"></pre>';panicMessageEl.querySelector('#message').textContent=panicTitle;panicMessageEl.querySelector('#details').textContent=panicDetails;panicElement.appendChild(panicMessageEl);rawPanicMessages.push({title:panicTitle,details:panicDetails});}
+function hasPanic(){return rawPanicMessages.length!==0;}
+function getPanicText(){return rawPanicMessages.map(function(msg){return msg.title;}).join(', ');}
+function exportTo(namespace,fn){var obj=exportPath(namespace);var exports=fn();for(var propertyName in exports){var propertyDescriptor=Object.getOwnPropertyDescriptor(exports,propertyName);if(propertyDescriptor)
+Object.defineProperty(obj,propertyName,propertyDescriptor);}};function initialize(){tr.doc=document;tr.isMac=/Mac/.test(navigator.platform);tr.isWindows=/Win/.test(navigator.platform);tr.isChromeOS=/CrOS/.test(navigator.userAgent);tr.isLinux=/Linux/.test(navigator.userAgent);}
+return{initialize:initialize,exportTo:exportTo,isDefined:isDefined,showPanic:showPanic,hasPanic:hasPanic,getPanicText:getPanicText};})();tr.initialize();'use strict';tr.exportTo('tr.b',function(){function Settings(){return Settings;};document.head.addEventListener('tr-unittest-will-run',function(){Settings.setAlternativeStorageInstance(global.sessionStorage);});function SessionSettings(){return SessionSettings;}
+function AddStaticStorageFunctionsToClass_(input_class,storage){input_class.storage_=storage;input_class.get=function(key,opt_default,opt_namespace){key=input_class.namespace_(key,opt_namespace);var rawVal=input_class.storage_.getItem(key);if(rawVal===null||rawVal===undefined)
+return opt_default;try{return JSON.parse(rawVal).value;}catch(e){input_class.storage_.removeItem(input_class.namespace_(key,opt_namespace));return opt_default;}};input_class.set=function(key,value,opt_namespace){if(value===undefined)
+throw new Error('Settings.set: value must not be undefined');var v=JSON.stringify({value:value});input_class.storage_.setItem(input_class.namespace_(key,opt_namespace),v);};input_class.keys=function(opt_namespace){var result=[];opt_namespace=opt_namespace||'';for(var i=0;i<input_class.storage_.length;i++){var key=input_class.storage_.key(i);if(input_class.isnamespaced_(key,opt_namespace))
+result.push(input_class.unnamespace_(key,opt_namespace));}
+return result;};input_class.isnamespaced_=function(key,opt_namespace){return key.indexOf(input_class.normalize_(opt_namespace))==0;};input_class.namespace_=function(key,opt_namespace){return input_class.normalize_(opt_namespace)+key;};input_class.unnamespace_=function(key,opt_namespace){return key.replace(input_class.normalize_(opt_namespace),'');};input_class.normalize_=function(opt_namespace){return input_class.NAMESPACE+(opt_namespace?opt_namespace+'.':'');};input_class.setAlternative [...]
+return undefined;return input_class.storage_;};input_class.NAMESPACE='trace-viewer';};AddStaticStorageFunctionsToClass_(Settings,localStorage);AddStaticStorageFunctionsToClass_(SessionSettings,sessionStorage);return{Settings:Settings,SessionSettings:SessionSettings};});'use strict';tr.exportTo('tr.b',function(){function asArray(arrayish){var values=[];for(var i=0;i<arrayish.length;i++)
+values.push(arrayish[i]);return values;}
+function compareArrays(x,y,elementCmp){var minLength=Math.min(x.length,y.length);for(var i=0;i<minLength;i++){var tmp=elementCmp(x[i],y[i]);if(tmp)
+return tmp;}
+if(x.length==y.length)
+return 0;if(x[i]===undefined)
+return-1;return 1;}
+function comparePossiblyUndefinedValues(x,y,cmp,opt_this){if(x!==undefined&&y!==undefined)
+return cmp.call(opt_this,x,y);if(x!==undefined)
+return-1;if(y!==undefined)
+return 1;return 0;}
+function concatenateArrays(){var values=[];for(var i=0;i<arguments.length;i++){if(!(arguments[i]instanceof Array))
+throw new Error('Arguments '+i+'is not an array');values.push.apply(values,arguments[i]);}
+return values;}
+function concatenateObjects(){var result={};for(var i=0;i<arguments.length;i++){var object=arguments[i];for(var j in object){result[j]=object[j];}}
+return result;}
+function dictionaryKeys(dict){var keys=[];for(var key in dict)
+keys.push(key);return keys;}
+function dictionaryValues(dict){var values=[];for(var key in dict)
+values.push(dict[key]);return values;}
+function dictionaryLength(dict){var n=0;for(var key in dict)
+n++;return n;}
+function group(ary,fn){return ary.reduce(function(accumulator,curr){var key=fn(curr);if(key in accumulator)
+accumulator[key].push(curr);else
+accumulator[key]=[curr];return accumulator;},{});}
+function iterItems(dict,fn,opt_this){opt_this=opt_this||this;var keys=Object.keys(dict);for(var i=0;i<keys.length;i++){var key=keys[i];fn.call(opt_this,key,dict[key]);}}
+function mapItems(dict,fn,opt_this){opt_this=opt_this||this;var result={};var keys=Object.keys(dict);for(var i=0;i<keys.length;i++){var key=keys[i];result[key]=fn.call(opt_this,key,dict[key]);}
+return result;}
+function iterObjectFieldsRecursively(object,func){if(!(object instanceof Object))
+return;if(object instanceof Array){for(var i=0;i<object.length;i++){func(object,i,object[i]);iterObjectFieldsRecursively(object[i],func);}
+return;}
+for(var key in object){var value=object[key];func(object,key,value);iterObjectFieldsRecursively(value,func);}}
+function identity(d){return d;}
+function findFirstIndexInArray(ary,opt_func,opt_this){var func=opt_func||identity;for(var i=0;i<ary.length;i++){if(func.call(opt_this,ary[i],i))
+return i;}
+return-1;}
+function findFirstInArray(ary,opt_func,opt_this){var i=findFirstIndexInArray(ary,opt_func,opt_func);if(i===-1)
+return undefined;return ary[i];}
+return{asArray:asArray,concatenateArrays:concatenateArrays,concatenateObjects:concatenateObjects,compareArrays:compareArrays,comparePossiblyUndefinedValues:comparePossiblyUndefinedValues,dictionaryLength:dictionaryLength,dictionaryKeys:dictionaryKeys,dictionaryValues:dictionaryValues,group:group,iterItems:iterItems,mapItems:mapItems,iterObjectFieldsRecursively:iterObjectFieldsRecursively,identity:identity,findFirstIndexInArray:findFirstIndexInArray,findFirstInArray:findFirstInArray};});' [...]
+this.processAddedChild_(this.children[i]);this.childrenObserver_=new MutationObserver(this.childrenUpdated_.bind(this));this.childrenObserver_.observe(this,{childList:'true'});},get tabStripHeadingText(){return this.$.tsh.textContent;},set tabStripHeadingText(tabStripHeadingText){this.$.tsh.textContent=tabStripHeadingText;if(!!tabStripHeadingText)
+this.$.tshh.style.display='';else
+this.$.tshh.style.display='none';},get selectedTab(){this.childrenUpdated_(this.childrenObserver_.takeRecords(),this.childrenObserver_);if(this.selectedTab_)
+return this.selectedTab_.content;return undefined;},set selectedTab(content){this.childrenUpdated_(this.childrenObserver_.takeRecords(),this.childrenObserver_);if(content===undefined||content===null){this.changeSelectedTabById_(undefined);return;}
+var contentTabId=undefined;for(var i=0;i<this.tabs_.length;i++)
+if(this.tabs_[i].content===content){contentTabId=this.tabs_[i].id;break;}
+if(contentTabId===undefined){console.warn('Tab not in tabs list. Ignoring changed selection.');return;}
+this.changeSelectedTabById_(contentTabId);},get tabsHidden(){var ts=this.shadowRoot.querySelector('tab-strip');return ts.hasAttribute('tabs-hidden');},set tabsHidden(tabsHidden){tabsHidden=!!tabsHidden;var ts=this.shadowRoot.querySelector('tab-strip');if(tabsHidden)
+ts.setAttribute('tabs-hidden',true);else
+ts.removeAttribute('tabs-hidden');},processAddedChild_:function(child){var observerAttributeSelected=new MutationObserver(this.childAttributesChanged_.bind(this));var observerAttributeTabLabel=new MutationObserver(this.childAttributesChanged_.bind(this));var tabObject={id:this.tabs_.length,content:child,label:child.getAttribute('tab-label'),observers:{forAttributeSelected:observerAttributeSelected,forAttributeTabLabel:observerAttributeTabLabel},savedScrollTop:0,savedScrollLeft:0};this.ta [...]
+child.removeAttribute('selected');else
+this.setSelectedTabById_(tabObject.id);}
+var previousSelected=child.selected;var tabView=this;Object.defineProperty(child,'selected',{configurable:true,set:function(value){if(value){tabView.changeSelectedTabById_(tabObject.id);return;}
+var wasSelected=tabView.selectedTab_===tabObject;if(wasSelected)
+tabView.changeSelectedTabById_(undefined);},get:function(){return this.hasAttribute('selected');}});if(previousSelected)
+child.selected=previousSelected;observerAttributeSelected.observe(child,{attributeFilter:['selected']});observerAttributeTabLabel.observe(child,{attributeFilter:['tab-label']});},processRemovedChild_:function(child){for(var i=0;i<this.tabs_.length;i++){this.tabs_[i].id=i;if(this.tabs_[i].content===child){this.tabs_[i].observers.forAttributeSelected.disconnect();this.tabs_[i].observers.forAttributeTabLabel.disconnect();if(this.tabs_[i]===this.selectedTab_){this.clearSelectedTab_();this.fi [...]
+child.removeAttribute('selected');delete child.selected;this.tabs_.splice(i,1);i--;}}},childAttributesChanged_:function(mutations,observer){var tabObject=undefined;for(var i=0;i<this.tabs_.length;i++){var observers=this.tabs_[i].observers;if(observers.forAttributeSelected===observer||observers.forAttributeTabLabel===observer){tabObject=this.tabs_[i];break;}}
+if(!tabObject)
+return;for(var i=0;i<mutations.length;i++){var node=tabObject.content;if(mutations[i].attributeName==='tab-label')
+tabObject.label=node.getAttribute('tab-label');if(mutations[i].attributeName==='selected'){var nodeIsSelected=node.hasAttribute('selected');if(nodeIsSelected)
+this.changeSelectedTabById_(tabObject.id);else
+this.changeSelectedTabById_(undefined);}}},childrenUpdated_:function(mutations,observer){mutations.forEach(function(mutation){for(var i=0;i<mutation.removedNodes.length;i++)
+this.processRemovedChild_(mutation.removedNodes[i]);for(var i=0;i<mutation.addedNodes.length;i++)
+this.processAddedChild_(mutation.addedNodes[i]);},this);},tabButtonSelectHandler_:function(event,detail,sender){this.changeSelectedTabById_(sender.getAttribute('button-id'));},changeSelectedTabById_:function(id){var newTab=id!==undefined?this.tabs_[id]:undefined;var changed=this.selectedTab_!==newTab;this.saveCurrentTabScrollPosition_();this.clearSelectedTab_();if(id!==undefined){this.setSelectedTabById_(id);this.restoreCurrentTabScrollPosition_();}
+if(changed)
+this.fire('selected-tab-change');},setSelectedTabById_:function(id){this.selectedTab_=this.tabs_[id];this.selectedTab_.observers.forAttributeSelected.disconnect();this.selectedTab_.content.setAttribute('selected','selected');this.selectedTab_.observers.forAttributeSelected.observe(this.selectedTab_.content,{attributeFilter:['selected']});},saveCurrentTabScrollPosition_:function(){if(this.selectedTab_){this.selectedTab_.savedScrollTop=this.$['content-container'].scrollTop;this.selectedTab [...]
+EventTarget.decorate=function(target){for(var k in EventTarget.prototype){if(k=='decorate')
+continue;var v=EventTarget.prototype[k];if(typeof v!=='function')
+continue;target[k]=v;}};EventTarget.prototype={addEventListener:function(type,handler){if(!this.listeners_)
+this.listeners_=Object.create(null);if(!(type in this.listeners_)){this.listeners_[type]=[handler];}else{var handlers=this.listeners_[type];if(handlers.indexOf(handler)<0)
+handlers.push(handler);}},removeEventListener:function(type,handler){if(!this.listeners_)
+return;if(type in this.listeners_){var handlers=this.listeners_[type];var index=handlers.indexOf(handler);if(index>=0){if(handlers.length==1)
+delete this.listeners_[type];else
+handlers.splice(index,1);}}},dispatchEvent:function(event){if(!this.listeners_)
+return true;var self=this;event.__defineGetter__('target',function(){return self;});var realPreventDefault=event.preventDefault;event.preventDefault=function(){realPreventDefault.call(this);this.rawReturnValue=false;};var type=event.type;var prevented=0;if(type in this.listeners_){var handlers=this.listeners_[type].concat();for(var i=0,handler;handler=handlers[i];i++){if(handler.handleEvent)
+prevented|=handler.handleEvent.call(handler,event)===false;else
+prevented|=handler.call(this,event)===false;}}
+return!prevented&&event.rawReturnValue;},hasEventListener:function(type){return this.listeners_[type]!==undefined;}};var EventTargetHelper={decorate:function(target){for(var k in EventTargetHelper){if(k=='decorate')
+continue;var v=EventTargetHelper[k];if(typeof v!=='function')
+continue;target[k]=v;}
+target.listenerCounts_={};},addEventListener:function(type,listener,useCapture){this.__proto__.addEventListener.call(this,type,listener,useCapture);if(this.listenerCounts_[type]===undefined)
+this.listenerCounts_[type]=0;this.listenerCounts_[type]++;},removeEventListener:function(type,listener,useCapture){this.__proto__.removeEventListener.call(this,type,listener,useCapture);this.listenerCounts_[type]--;},hasEventListener:function(type){return this.listenerCounts_[type]>0;}};return{EventTarget:EventTarget,EventTargetHelper:EventTargetHelper};});'use strict';tr.exportTo('tr.b',function(){function Event(type,opt_bubbles,opt_preventable){var e=tr.doc.createEvent('Event');e.initE [...]
+return{Event:Event,dispatchSimpleEvent:dispatchSimpleEvent};});'use strict';tr.exportTo('tr.b',function(){var nextGUID=1;var GUID={allocate:function(){return nextGUID++;},getLastGuid:function(){return nextGUID-1;}};return{GUID:GUID};});'use strict';tr.exportTo('tr.b',function(){function Range(){this.isEmpty_=true;this.min_=undefined;this.max_=undefined;};Range.prototype={__proto__:Object.prototype,reset:function(){this.isEmpty_=true;this.min_=undefined;this.max_=undefined;},get isEmpty() [...]
+return;this.addValue(range.min);this.addValue(range.max);},addValue:function(value){if(this.isEmpty_){this.max_=value;this.min_=value;this.isEmpty_=false;return;}
+this.max_=Math.max(this.max_,value);this.min_=Math.min(this.min_,value);},set min(min){this.isEmpty_=false;this.min_=min;},get min(){if(this.isEmpty_)
+return undefined;return this.min_;},get max(){if(this.isEmpty_)
+return undefined;return this.max_;},set max(max){this.isEmpty_=false;this.max_=max;},get range(){if(this.isEmpty_)
+return undefined;return this.max_-this.min_;},get center(){return(this.min_+this.max_)*0.5;},equals:function(that){if(this.isEmpty&&that.isEmpty)
+return true;if(this.isEmpty!=that.isEmpty)
+return false;return this.min===that.min&&this.max===that.max;},containsRange:function(range){if(this.isEmpty||range.isEmpty)
+return false;return this.min<=range.min&&this.max>=range.max;},containsExplicitRange:function(min,max){if(this.isEmpty)
+return false;return this.min<=min&&this.max>=max;},intersectsRange:function(range){if(this.isEmpty||range.isEmpty)
+return false;return!(range.max<this.min||range.min>this.max);},intersectsExplicitRange:function(min,max){if(this.isEmpty)
+return false;return!(max<this.min||min>this.max);}};Range.fromExplicitRange=function(min,max){var range=new Range();range.min=min;range.max=max;return range;};Range.compareByMinTimes=function(a,b){if(!a.isEmpty&&!b.isEmpty)
+return a.min_-b.min_;if(a.isEmpty&&!b.isEmpty)
+return-1;if(!a.isEmpty&&b.isEmpty)
+return 1;return 0;};return{Range:Range};});'use strict';tr.exportTo('tr.b',function(){function max(a,b){if(a===undefined)
+return b;if(b===undefined)
+return a;return Math.max(a,b);}
+function IntervalTree(beginPositionCb,endPositionCb){this.beginPositionCb_=beginPositionCb;this.endPositionCb_=endPositionCb;this.root_=undefined;this.size_=0;}
+IntervalTree.prototype={insert:function(datum){var startPosition=this.beginPositionCb_(datum);var endPosition=this.endPositionCb_(datum);var node=new IntervalTreeNode(datum,startPosition,endPosition);this.size_++;this.root_=this.insertNode_(this.root_,node);this.root_.colour=Colour.BLACK;return datum;},insertNode_:function(root,node){if(root===undefined)
+return node;if(root.leftNode&&root.leftNode.isRed&&root.rightNode&&root.rightNode.isRed)
+this.flipNodeColour_(root);if(node.key<root.key)
+root.leftNode=this.insertNode_(root.leftNode,node);else if(node.key===root.key)
+root.merge(node);else
+root.rightNode=this.insertNode_(root.rightNode,node);if(root.rightNode&&root.rightNode.isRed&&(root.leftNode===undefined||!root.leftNode.isRed))
+root=this.rotateLeft_(root);if(root.leftNode&&root.leftNode.isRed&&root.leftNode.leftNode&&root.leftNode.leftNode.isRed)
+root=this.rotateRight_(root);return root;},rotateRight_:function(node){var sibling=node.leftNode;node.leftNode=sibling.rightNode;sibling.rightNode=node;sibling.colour=node.colour;node.colour=Colour.RED;return sibling;},rotateLeft_:function(node){var sibling=node.rightNode;node.rightNode=sibling.leftNode;sibling.leftNode=node;sibling.colour=node.colour;node.colour=Colour.RED;return sibling;},flipNodeColour_:function(node){node.colour=this.flipColour_(node.colour);node.leftNode.colour=this [...]
+return undefined;node.maxHighLeft=this.updateHighValues_(node.leftNode);node.maxHighRight=this.updateHighValues_(node.rightNode);return max(max(node.maxHighLeft,node.highValue),node.maxHighRight);},validateFindArguments_:function(queryLow,queryHigh){if(queryLow===undefined||queryHigh===undefined)
+throw new Error('queryLow and queryHigh must be defined');if((typeof queryLow!=='number')||(typeof queryHigh!=='number'))
+throw new Error('queryLow and queryHigh must be numbers');},findIntersection:function(queryLow,queryHigh){this.validateFindArguments_(queryLow,queryHigh);if(this.root_===undefined)
+return[];var ret=[];this.root_.appendIntersectionsInto_(ret,queryLow,queryHigh);return ret;},get size(){return this.size_;},get root(){return this.root_;},dump_:function(){if(this.root_===undefined)
+return[];return this.root_.dump();}};var Colour={RED:'red',BLACK:'black'};function IntervalTreeNode(datum,lowValue,highValue){this.lowValue_=lowValue;this.data_=[{datum:datum,high:highValue,low:lowValue}];this.colour_=Colour.RED;this.parentNode_=undefined;this.leftNode_=undefined;this.rightNode_=undefined;this.maxHighLeft_=undefined;this.maxHighRight_=undefined;}
+IntervalTreeNode.prototype={appendIntersectionsInto_:function(ret,queryLow,queryHigh){if(this.lowValue_>=queryHigh){if(!this.leftNode_)
+return;return this.leftNode_.appendIntersectionsInto_(ret,queryLow,queryHigh);}
+if(this.maxHighLeft_>queryLow){this.leftNode_.appendIntersectionsInto_(ret,queryLow,queryHigh);}
+if(this.highValue>queryLow){for(var i=(this.data.length-1);i>=0;--i){if(this.data[i].high<queryLow)
+break;ret.push(this.data[i].datum);}}
+if(this.rightNode_){this.rightNode_.appendIntersectionsInto_(ret,queryLow,queryHigh);}},get colour(){return this.colour_;},set colour(colour){this.colour_=colour;},get key(){return this.lowValue_;},get lowValue(){return this.lowValue_;},get highValue(){return this.data_[this.data_.length-1].high;},set leftNode(left){this.leftNode_=left;},get leftNode(){return this.leftNode_;},get hasLeftNode(){return this.leftNode_!==undefined;},set rightNode(right){this.rightNode_=right;},get rightNode( [...]
+this.data_.push(node.data[i]);this.data_.sort(function(a,b){return a.high-b.high;});},dump:function(){var ret={};if(this.leftNode_)
+ret['left']=this.leftNode_.dump();ret['data']=this.data_.map(function(d){return[d.low,d.high];});if(this.rightNode_)
+ret['right']=this.rightNode_.dump();return ret;}};return{IntervalTree:IntervalTree};});'use strict';tr.exportTo('tr.b',function(){function addSingletonGetter(ctor){ctor.getInstance=function(){return ctor.instance_||(ctor.instance_=new ctor());};}
+function normalizeException(e){if(typeof(e)=='string'){return{message:e,stack:['<unknown>']};}
+return{message:e.message,stack:e.stack?e.stack:['<unknown>']};}
+function stackTrace(){var stack=new Error().stack+'';stack=stack.split('\n');return stack.slice(2);}
+function getUsingPath(path,from_dict){var parts=path.split('.');var cur=from_dict;for(var part;parts.length&&(part=parts.shift());){if(!parts.length){return cur[part];}else if(part in cur){cur=cur[part];}else{return undefined;}}
+return undefined;}
+return{addSingletonGetter:addSingletonGetter,normalizeException:normalizeException,stackTrace:stackTrace,getUsingPath:getUsingPath};});'use strict';tr.exportTo('tr.b',function(){var recordRAFStacks=false;var pendingPreAFs=[];var pendingRAFs=[];var pendingIdleCallbacks=[];var currentRAFDispatchList=undefined;var rafScheduled=false;function scheduleRAF(){if(rafScheduled)
+return;rafScheduled=true;if(window.requestAnimationFrame){window.requestAnimationFrame(processRequests);}else{var delta=Date.now()-window.performance.now();window.webkitRequestAnimationFrame(function(domTimeStamp){processRequests(domTimeStamp-delta);});}}
+function onAnimationFrameError(e,opt_stack){if(opt_stack)
+console.log(opt_stack);if(e.message)
+console.error(e.message,e.stack);else
+console.error(e);}
+function runTask(task,frameBeginTime){try{task.callback.call(task.context,frameBeginTime);}catch(e){tr.b.onAnimationFrameError(e,task.stack);}}
+function processRequests(frameBeginTime){var rafCompletionDeadline=frameBeginTime+10;rafScheduled=false;var currentPreAFs=pendingPreAFs;currentRAFDispatchList=pendingRAFs;pendingPreAFs=[];pendingRAFs=[];var hasRAFTasks=currentPreAFs.length||currentRAFDispatchList.length;for(var i=0;i<currentPreAFs.length;i++)
+runTask(currentPreAFs[i],frameBeginTime);while(currentRAFDispatchList.length>0)
+runTask(currentRAFDispatchList.shift(),frameBeginTime);currentRAFDispatchList=undefined;if(!hasRAFTasks){while(pendingIdleCallbacks.length>0){runTask(pendingIdleCallbacks.shift());if(window.performance.now()>=rafCompletionDeadline)
+break;}}
+if(pendingIdleCallbacks.length>0)
+scheduleRAF();}
+function getStack_(){if(!recordRAFStacks)
+return'';var stackLines=tr.b.stackTrace();stackLines.shift();return stackLines.join('\n');}
+function requestPreAnimationFrame(callback,opt_this){pendingPreAFs.push({callback:callback,context:opt_this||window,stack:getStack_()});scheduleRAF();}
+function requestAnimationFrameInThisFrameIfPossible(callback,opt_this){if(!currentRAFDispatchList){requestAnimationFrame(callback,opt_this);return;}
+currentRAFDispatchList.push({callback:callback,context:opt_this||window,stack:getStack_()});return;}
+function requestAnimationFrame(callback,opt_this){pendingRAFs.push({callback:callback,context:opt_this||window,stack:getStack_()});scheduleRAF();}
+function requestIdleCallback(callback,opt_this){pendingIdleCallbacks.push({callback:callback,context:opt_this||window,stack:getStack_()});scheduleRAF();}
+function forcePendingRAFTasksToRun(frameBeginTime){if(!rafScheduled)
+return;processRequests(frameBeginTime);}
+return{onAnimationFrameError:onAnimationFrameError,requestPreAnimationFrame:requestPreAnimationFrame,requestAnimationFrame:requestAnimationFrame,requestAnimationFrameInThisFrameIfPossible:requestAnimationFrameInThisFrameIfPossible,requestIdleCallback:requestIdleCallback,forcePendingRAFTasksToRun:forcePendingRAFTasksToRun};});'use strict';tr.exportTo('tr.b',function(){function Task(runCb,thisArg){if(runCb!==undefined&&thisArg===undefined)
+throw new Error('Almost certainly, you meant to pass a thisArg.');this.runCb_=runCb;this.thisArg_=thisArg;this.afterTask_=undefined;this.subTasks_=[];}
+Task.prototype={subTask:function(cb,thisArg){if(cb instanceof Task)
+this.subTasks_.push(cb);else
+this.subTasks_.push(new Task(cb,thisArg));return this.subTasks_[this.subTasks_.length-1];},run:function(){if(this.runCb_!==undefined)
+this.runCb_.call(this.thisArg_,this);var subTasks=this.subTasks_;this.subTasks_=undefined;if(!subTasks.length)
+return this.afterTask_;for(var i=1;i<subTasks.length;i++)
+subTasks[i-1].afterTask_=subTasks[i];subTasks[subTasks.length-1].afterTask_=this.afterTask_;return subTasks[0];},after:function(cb,thisArg){if(this.afterTask_)
+throw new Error('Has an after task already');if(cb instanceof Task)
+this.afterTask_=cb;else
+this.afterTask_=new Task(cb,thisArg);return this.afterTask_;},enqueue:function(cb,thisArg){var lastTask=this;while(lastTask.afterTask_)
+lastTask=lastTask.afterTask_;return lastTask.after(cb,thisArg);}};Task.RunSynchronously=function(task){var curTask=task;while(curTask)
+curTask=curTask.run();}
+Task.RunWhenIdle=function(task){return new Promise(function(resolve,reject){var curTask=task;function runAnother(){try{curTask=curTask.run();}catch(e){reject(e);console.error(e.stack);return;}
+if(curTask){tr.b.requestIdleCallback(runAnother);return;}
+resolve();}
+tr.b.requestIdleCallback(runAnother);});}
+return{Task:Task};});'use strict';tr.exportTo('tr.b.units',function(){var ms={suffix:'ms',roundedLess:function(a,b){return Math.round(a*1000)<Math.round(b*1000);},format:function(ts){var tsRounded=Math.round(ts*1000.0)/1000.0;var n=new Number(tsRounded);return n.toLocaleString(undefined,{minimumFractionDigits:3})+' ms';}};var ns={suffix:'ns',roundedLess:function(a,b){return Math.round(a*1000000)<Math.round(b*1000000);},format:function(ts){var tsRounded=Math.round(ts*1000000.0);var n=new  [...]
+return;this.currentDisplayUnit_=value;this.dispatchEvent(new Event('display-unit-changed'));},timestampFromUs:function(us){return us/1000;},maybeTimestampFromUs:function(us){return us===undefined?undefined:us/1000;}};tr.b.EventTarget.decorate(Time);return{Time:Time};});'use strict';tr.exportTo('tr.b',function(){function dispatchPropertyChange(target,propertyName,newValue,oldValue,opt_bubbles,opt_cancelable){var e=new tr.b.Event(propertyName+'Change',opt_bubbles,opt_cancelable);e.property [...]
+throw error;}
+function setPropertyAndDispatchChange(obj,propertyName,newValue){var privateName=propertyName+'_';var oldValue=obj[propertyName];obj[privateName]=newValue;if(oldValue!==newValue)
+tr.b.dispatchPropertyChange(obj,propertyName,newValue,oldValue,true,false);}
+function getAttributeName(jsName){return jsName.replace(/([A-Z])/g,'-$1').toLowerCase();}
+function getPrivateName(name){return name+'_tr_';}
+var PropertyKind={JS:'js',ATTR:'attr',BOOL_ATTR:'boolAttr'};function getGetter(name,kind){switch(kind){case PropertyKind.JS:var privateName=getPrivateName(name);return function(){return this[privateName];};case PropertyKind.ATTR:var attributeName=getAttributeName(name);return function(){return this.getAttribute(attributeName);};case PropertyKind.BOOL_ATTR:var attributeName=getAttributeName(name);return function(){return this.hasAttribute(attributeName);};}}
+function getSetter(name,kind,opt_setHook,opt_bubbles,opt_cancelable){switch(kind){case PropertyKind.JS:var privateName=getPrivateName(name);return function(value){var oldValue=this[privateName];if(value!==oldValue){this[privateName]=value;if(opt_setHook)
+opt_setHook.call(this,value,oldValue);dispatchPropertyChange(this,name,value,oldValue,opt_bubbles,opt_cancelable);}};case PropertyKind.ATTR:var attributeName=getAttributeName(name);return function(value){var oldValue=this.getAttribute(attributeName);if(value!==oldValue){if(value==undefined)
+this.removeAttribute(attributeName);else
+this.setAttribute(attributeName,value);if(opt_setHook)
+opt_setHook.call(this,value,oldValue);dispatchPropertyChange(this,name,value,oldValue,opt_bubbles,opt_cancelable);}};case PropertyKind.BOOL_ATTR:var attributeName=getAttributeName(name);return function(value){var oldValue=(this.getAttribute(attributeName)===name);if(value!==oldValue){if(value)
+this.setAttribute(attributeName,name);else
+this.removeAttribute(attributeName);if(opt_setHook)
+opt_setHook.call(this,value,oldValue);dispatchPropertyChange(this,name,value,oldValue,opt_bubbles,opt_cancelable);}};}}
+function defineProperty(obj,name,opt_kind,opt_setHook,opt_bubbles,opt_cancelable){console.error("Don't use tr.b.defineProperty");if(typeof obj=='function')
+obj=obj.prototype;var kind=opt_kind||PropertyKind.JS;if(!obj.__lookupGetter__(name))
+obj.__defineGetter__(name,getGetter(name,kind));if(!obj.__lookupSetter__(name))
+obj.__defineSetter__(name,getSetter(name,kind,opt_setHook,opt_bubbles,opt_cancelable));}
+return{PropertyKind:PropertyKind,defineProperty:defineProperty,dispatchPropertyChange:dispatchPropertyChange,setPropertyAndDispatchChange:setPropertyAndDispatchChange};});'use strict';tr.exportTo('tr.ui.b',function(){function decorate(source,constr){var elements;if(typeof source=='string')
+elements=tr.doc.querySelectorAll(source);else
+elements=[source];for(var i=0,el;el=elements[i];i++){if(!(el instanceof constr))
+constr.decorate(el);}}
+function define(className,opt_parentConstructor,opt_tagNS){if(typeof className=='function'){throw new Error('Passing functions as className is deprecated. Please '+'use (className, opt_parentConstructor) to subclass');}
+var className=className.toLowerCase();if(opt_parentConstructor&&!opt_parentConstructor.tagName)
+throw new Error('opt_parentConstructor was not '+'created by tr.ui.b.define');var tagName=className;var tagNS=undefined;if(opt_parentConstructor){if(opt_tagNS)
+throw new Error('Must not specify tagNS if parentConstructor is given');var parent=opt_parentConstructor;while(parent&&parent.tagName){tagName=parent.tagName;tagNS=parent.tagNS;parent=parent.parentConstructor;}}else{tagNS=opt_tagNS;}
+function f(){if(opt_parentConstructor&&f.prototype.__proto__!=opt_parentConstructor.prototype){throw new Error(className+' prototye\'s __proto__ field is messed up. '+'It MUST be the prototype of '+opt_parentConstructor.tagName);}
+var el;if(tagNS===undefined)
+el=tr.doc.createElement(tagName);else
+el=tr.doc.createElementNS(tagNS,tagName);f.decorate.call(this,el,arguments);return el;}
+f.decorate=function(el){el.__proto__=f.prototype;el.decorate.apply(el,arguments[1]);el.constructor=f;};f.className=className;f.tagName=tagName;f.tagNS=tagNS;f.parentConstructor=(opt_parentConstructor?opt_parentConstructor:undefined);f.toString=function(){if(!f.parentConstructor)
+return f.tagName;return f.parentConstructor.toString()+'::'+f.className;};return f;}
+function elementIsChildOf(el,potentialParent){if(el==potentialParent)
+return false;var cur=el;while(cur.parentNode){if(cur==potentialParent)
+return true;cur=cur.parentNode;}
+return false;};return{decorate:decorate,define:define,elementIsChildOf:elementIsChildOf};});(function(){"use strict";var e={};typeof exports=="undefined"?typeof define=="function"&&typeof define.amd=="object"&&define.amd?(e.exports={},define(function(){return e.exports})):e.exports=window:e.exports=exports,function(e){if(!t)var t=1e-6;if(!n)var n=typeof Float32Array!="undefined"?Float32Array:Array;var r={};r.setMatrixArrayType=function(e){n=e},typeof e!="undefined"&&(e.glMatrix=r);var i= [...]
+function lerp(percentage,lo,hi){var range=hi-lo;return lo+percentage*range;}
+function normalize(value,lo,hi){return(value-lo)/(hi-lo);}
+function deg2rad(deg){return(Math.PI*deg)/180.0;}
+var tmp_vec2=vec2.create();var tmp_vec2b=vec2.create();var tmp_vec4=vec4.create();var tmp_mat2d=mat2d.create();vec2.createFromArray=function(arr){if(arr.length!=2)
+throw new Error('Should be length 2');var v=vec2.create();vec2.set(v,arr[0],arr[1]);return v;};vec2.createXY=function(x,y){var v=vec2.create();vec2.set(v,x,y);return v;};vec2.toString=function(a){return'['+a[0]+', '+a[1]+']';};vec2.addTwoScaledUnitVectors=function(out,u1,scale1,u2,scale2){vec2.scale(tmp_vec2,u1,scale1);vec2.scale(tmp_vec2b,u2,scale2);vec2.add(out,tmp_vec2,tmp_vec2b);};vec2.interpolatePiecewiseFunction=function(points,x){if(x<points[0][0])
+return points[0][1];for(var i=1;i<points.length;++i){if(x<points[i][0]){var percent=normalize(x,points[i-1][0],points[i][0]);return lerp(percent,points[i-1][1],points[i][1]);}}
+return points[points.length-1][1];};vec3.createXYZ=function(x,y,z){var v=vec3.create();vec3.set(v,x,y,z);return v;};vec3.toString=function(a){return'vec3('+a[0]+', '+a[1]+', '+a[2]+')';}
+mat2d.translateXY=function(out,x,y){vec2.set(tmp_vec2,x,y);mat2d.translate(out,out,tmp_vec2);}
+mat2d.scaleXY=function(out,x,y){vec2.set(tmp_vec2,x,y);mat2d.scale(out,out,tmp_vec2);}
+vec4.unitize=function(out,a){out[0]=a[0]/a[3];out[1]=a[1]/a[3];out[2]=a[2]/a[3];out[3]=1;return out;}
+vec2.copyFromVec4=function(out,a){vec4.unitize(tmp_vec4,a);vec2.copy(out,tmp_vec4);}
+return{clamp:clamp,lerp:lerp,normalize:normalize,deg2rad:deg2rad};});'use strict';tr.exportTo('tr.b',function(){function Rect(){this.x=0;this.y=0;this.width=0;this.height=0;};Rect.fromXYWH=function(x,y,w,h){var rect=new Rect();rect.x=x;rect.y=y;rect.width=w;rect.height=h;return rect;}
+Rect.fromArray=function(ary){if(ary.length!=4)
+throw new Error('ary.length must be 4');var rect=new Rect();rect.x=ary[0];rect.y=ary[1];rect.width=ary[2];rect.height=ary[3];return rect;}
+Rect.prototype={__proto__:Object.prototype,get left(){return this.x;},get top(){return this.y;},get right(){return this.x+this.width;},get bottom(){return this.y+this.height;},toString:function(){return'Rect('+this.x+', '+this.y+', '+
+this.width+', '+this.height+')';},toArray:function(){return[this.x,this.y,this.width,this.height];},clone:function(){var rect=new Rect();rect.x=this.x;rect.y=this.y;rect.width=this.width;rect.height=this.height;return rect;},enlarge:function(pad){var rect=new Rect();this.enlargeFast(rect,pad);return rect;},enlargeFast:function(out,pad){out.x=this.x-pad;out.y=this.y-pad;out.width=this.width+2*pad;out.height=this.height+2*pad;return out;},size:function(){return{width:this.width,height:this [...]
+throw new Error('Element not found');return el.createInstance();}
+function windowRectForElement(element){var position=[element.offsetLeft,element.offsetTop];var size=[element.offsetWidth,element.offsetHeight];var node=element.offsetParent;while(node){position[0]+=node.offsetLeft;position[1]+=node.offsetTop;node=node.offsetParent;}
+return tr.b.Rect.fromXYWH(position[0],position[1],size[0],size[1]);}
+function scrollIntoViewIfNeeded(el){var pr=el.parentElement.getBoundingClientRect();var cr=el.getBoundingClientRect();if(cr.top<pr.top){el.scrollIntoView(true);}else if(cr.bottom>pr.bottom){el.scrollIntoView(false);}}
+return{instantiateTemplate:instantiateTemplate,windowRectForElement:windowRectForElement,scrollIntoViewIfNeeded:scrollIntoViewIfNeeded};});'use strict';tr.exportTo('tr.ui.b',function(){var THIS_DOC=document.currentScript.ownerDocument;var Overlay=tr.ui.b.define('overlay');Overlay.prototype={__proto__:HTMLDivElement.prototype,decorate:function(){this.classList.add('overlay');this.parentEl_=this.ownerDocument.body;this.visible_=false;this.userCanClose_=true;this.onKeyDown_=this.onKeyDown_. [...]
+return;tr.b.setPropertyAndDispatchChange(this,'visible',newValue);},onVisibleChange_:function(){this.visible_?this.show_():this.hide_();},show_:function(){this.parentEl_.appendChild(this);if(this.userCanClose_){this.addEventListener('keydown',this.onKeyDown_.bind(this));this.addEventListener('click',this.onDocumentClick_.bind(this));}
+this.parentEl_.addEventListener('focusin',this.onFocusIn_);this.tabIndex=0;var focusEl=undefined;var elList=this.querySelectorAll('button, input, list, select, a');if(elList.length>0){if(elList[0]===this.closeBtn_){if(elList.length>1)
+focusEl=elList[1];}else{focusEl=elList[0];}}
+if(focusEl===undefined)
+focusEl=this;focusEl.focus();},hide_:function(){this.parentEl_.removeChild(this);this.parentEl_.removeEventListener('focusin',this.onFocusIn_);if(this.closeBtn_)
+this.closeBtn_.removeEventListener(this.onClose_);document.removeEventListener('keydown',this.onKeyDown_);document.removeEventListener('click',this.onDocumentClick_);},onClose_:function(e){this.visible=false;if((e.type!='keydown')||(e.type==='keydown'&&e.keyCode===27))
+e.stopPropagation();e.preventDefault();tr.b.dispatchSimpleEvent(this,'closeclick');},onFocusIn_:function(e){if(e.target===this)
+return;window.setTimeout(function(){this.focus();},0);e.preventDefault();e.stopPropagation();},didButtonBarMutate_:function(e){var hasButtons=this.buttons.children.length>0;if(hasButtons)
+this.shadow_.querySelector('button-bar').style.display=undefined;else
+this.shadow_.querySelector('button-bar').style.display='none';},onKeyDown_:function(e){if(e.keyCode===9&&e.shiftKey&&e.target===this){e.preventDefault();return;}
+if(e.keyCode!==27)
+return;this.onClose_(e);},onClick_:function(e){e.stopPropagation();},onDocumentClick_:function(e){if(!this.userCanClose_)
+return;this.onClose_(e);}};Overlay.showError=function(msg,opt_err){var o=new Overlay();o.title='Error';o.textContent=msg;if(opt_err){var e=tr.b.normalizeException(opt_err);var stackDiv=document.createElement('pre');stackDiv.textContent=e.stack;stackDiv.style.paddingLeft='8px';stackDiv.style.margin=0;o.appendChild(stackDiv);}
+var b=document.createElement('button');b.textContent='OK';b.addEventListener('click',function(){o.visible=false;});o.buttons.appendChild(b);o.visible=true;return o;}
+return{Overlay:Overlay};});'use strict';tr.exportTo('tr.c',function(){function matchLower(value,pattern){return value.toLowerCase().indexOf(pattern)!==-1;}
+function Filter(){}
+Filter.prototype={__proto__:Object.prototype,matchCounter:function(counter){return true;},matchCpu:function(cpu){return true;},matchProcess:function(process){return true;},matchSlice:function(slice){return true;},matchThread:function(thread){return true;}};function TitleOrCategoryFilter(text){Filter.call(this);this.text_=text.toLowerCase();if(!text.length)
+throw new Error('Filter text is empty.');}
+TitleOrCategoryFilter.prototype={__proto__:Filter.prototype,matchSlice:function(slice){if(slice.title===undefined&&slice.category===undefined)
+return false;return matchLower(slice.title,this.text_)||(!!slice.category&&matchLower(slice.category,this.text_));}};function ExactTitleFilter(text){Filter.call(this);this.text_=text;if(!text.length)
+throw new Error('Filter text is empty.');}
+ExactTitleFilter.prototype={__proto__:Filter.prototype,matchSlice:function(slice){return slice.title===this.text_;}};return{Filter:Filter,TitleOrCategoryFilter:TitleOrCategoryFilter,ExactTitleFilter:ExactTitleFilter};});'use strict';tr.exportTo('tr.b',function(){function RegisteredTypeInfo(constructor,metadata){this.constructor=constructor;this.metadata=metadata;};var BASIC_REGISTRY_MODE='BASIC_REGISTRY_MODE';var TYPE_BASED_REGISTRY_MODE='TYPE_BASED_REGISTRY_MODE';var ALL_MODES={BASIC_RE [...]
+throw new Error('Mode is required');if(!ALL_MODES[mode])
+throw new Error('Not a mode.');this.mode_=mode;this.defaultMetadata_={};this.defaultConstructor_=undefined;this.mandatoryBaseClass_=undefined;this.defaultTypeInfo_=undefined;this.frozen_=false;}
+ExtensionRegistryOptions.prototype={freeze:function(){if(this.frozen_)
+throw new Error('Frozen');this.frozen_=true;},get mode(){return this.mode_;},get defaultMetadata(){return this.defaultMetadata_;},set defaultMetadata(defaultMetadata){if(this.frozen_)
+throw new Error('Frozen');this.defaultMetadata_=defaultMetadata;this.defaultTypeInfo_=undefined;},get defaultConstructor(){return this.defaultConstructor_;},set defaultConstructor(defaultConstructor){if(this.frozen_)
+throw new Error('Frozen');this.defaultConstructor_=defaultConstructor;this.defaultTypeInfo_=undefined;},get defaultTypeInfo(){if(this.defaultTypeInfo_===undefined&&this.defaultConstructor_){this.defaultTypeInfo_=new RegisteredTypeInfo(this.defaultConstructor,this.defaultMetadata);}
+return this.defaultTypeInfo_;},validateConstructor:function(constructor){if(!this.mandatoryBaseClass)
+return;var curProto=constructor.prototype.__proto__;var ok=false;while(curProto){if(curProto===this.mandatoryBaseClass.prototype){ok=true;break;}
+curProto=curProto.__proto__;}
+if(!ok)
+throw new Error(constructor+'must be subclass of '+registry);}};return{BASIC_REGISTRY_MODE:BASIC_REGISTRY_MODE,TYPE_BASED_REGISTRY_MODE:TYPE_BASED_REGISTRY_MODE,ExtensionRegistryOptions:ExtensionRegistryOptions,RegisteredTypeInfo:RegisteredTypeInfo};});'use strict';tr.exportTo('tr.b',function(){var RegisteredTypeInfo=tr.b.RegisteredTypeInfo;var ExtensionRegistryOptions=tr.b.ExtensionRegistryOptions;function decorateBasicExtensionRegistry(registry,extensionRegistryOptions){var savedStateS [...]
+throw new Error('Handler already registered for '+constructor);extensionRegistryOptions.validateConstructor(constructor);var metadata={};for(var k in extensionRegistryOptions.defaultMetadata)
+metadata[k]=extensionRegistryOptions.defaultMetadata[k];if(opt_metadata){for(var k in opt_metadata)
+metadata[k]=opt_metadata[k];}
+var typeInfo=new RegisteredTypeInfo(constructor,metadata);var e=new tr.b.Event('will-register');e.typeInfo=typeInfo;registry.dispatchEvent(e);registry.registeredTypeInfos_.push(typeInfo);e=new tr.b.Event('registry-changed');registry.dispatchEvent(e);};registry.pushCleanStateBeforeTest=function(){savedStateStack.push(registry.registeredTypeInfos_);registry.registeredTypeInfos_=[];var e=new tr.b.Event('registry-changed');registry.dispatchEvent(e);};registry.popCleanStateAfterTest=function( [...]
+if(registry.registeredTypeInfos_[i].constructor==constructor)
+return i;return undefined;};registry.unregister=function(constructor){var foundIndex=registry.findIndexOfRegisteredConstructor(constructor);if(foundIndex===undefined)
+throw new Error(constructor+' not registered');registry.registeredTypeInfos_.splice(foundIndex,1);var e=new tr.b.Event('registry-changed');registry.dispatchEvent(e);};registry.getAllRegisteredTypeInfos=function(){return registry.registeredTypeInfos_;};registry.findTypeInfo=function(constructor){var foundIndex=this.findIndexOfRegisteredConstructor(constructor);if(foundIndex!==undefined)
+return this.registeredTypeInfos_[foundIndex];return undefined;};registry.findTypeInfoMatching=function(predicate,opt_this){opt_this=opt_this?opt_this:undefined;for(var i=0;i<registry.registeredTypeInfos_.length;++i){var typeInfo=registry.registeredTypeInfos_[i];if(predicate.call(opt_this,typeInfo))
+return typeInfo;}
+return extensionRegistryOptions.defaultTypeInfo;};}
+return{_decorateBasicExtensionRegistry:decorateBasicExtensionRegistry};});'use strict';tr.exportTo('tr.b',function(){var categoryPartsFor={};function getCategoryParts(category){var parts=categoryPartsFor[category];if(parts!==undefined)
+return parts;parts=category.split(',');categoryPartsFor[category]=parts;return parts;}
+return{getCategoryParts:getCategoryParts};});'use strict';tr.exportTo('tr.b',function(){var getCategoryParts=tr.b.getCategoryParts;var RegisteredTypeInfo=tr.b.RegisteredTypeInfo;var ExtensionRegistryOptions=tr.b.ExtensionRegistryOptions;function decorateTypeBasedExtensionRegistry(registry,extensionRegistryOptions){var savedStateStack=[];registry.registeredTypeInfos_=[];registry.categoryPartToTypeInfoMap_={};registry.typeNameToTypeInfoMap_={};registry.register=function(constructor,metadat [...]
+typeInfo.typeNames.push(metadata.typeName);if(metadata&&metadata.typeNames){typeInfo.typeNames.push.apply(typeInfo.typeNames,metadata.typeNames);}
+if(metadata&&metadata.categoryParts){typeInfo.categoryParts.push.apply(typeInfo.categoryParts,metadata.categoryParts);}
+if(typeInfo.typeNames.length===0&&typeInfo.categoryParts.length===0)
+throw new Error('typeName or typeNames must be provided');typeInfo.typeNames.forEach(function(typeName){if(registry.typeNameToTypeInfoMap_[typeName])
+throw new Error('typeName '+typeName+' already registered');});typeInfo.categoryParts.forEach(function(categoryPart){if(registry.categoryPartToTypeInfoMap_[categoryPart]){throw new Error('categoryPart '+categoryPart+' already registered');}});var e=new tr.b.Event('will-register');e.typeInfo=typeInfo;registry.dispatchEvent(e);typeInfo.typeNames.forEach(function(typeName){registry.typeNameToTypeInfoMap_[typeName]=typeInfo;});typeInfo.categoryParts.forEach(function(categoryPart){registry.ca [...]
+if(typeInfoIndex===-1)
+throw new Error(constructor+' not registered');var typeInfo=registry.registeredTypeInfos_[typeInfoIndex];registry.registeredTypeInfos_.splice(typeInfoIndex,1);typeInfo.typeNames.forEach(function(typeName){delete registry.typeNameToTypeInfoMap_[typeName];});typeInfo.categoryParts.forEach(function(categoryPart){delete registry.categoryPartToTypeInfoMap_[categoryPart];});var e=new tr.b.Event('registry-changed');registry.dispatchEvent(e);};registry.getTypeInfo=function(category,typeName){if( [...]
+return registry.categoryPartToTypeInfoMap_[categoryPart];}}
+if(registry.typeNameToTypeInfoMap_[typeName])
+return registry.typeNameToTypeInfoMap_[typeName];return extensionRegistryOptions.defaultTypeInfo;};registry.getConstructor=function(category,typeName){var typeInfo=registry.getTypeInfo(category,typeName);if(typeInfo)
+return typeInfo.constructor;return undefined;};}
+return{_decorateTypeBasedExtensionRegistry:decorateTypeBasedExtensionRegistry};});'use strict';tr.exportTo('tr.b',function(){function decorateExtensionRegistry(registry,registryOptions){if(registry.register)
+throw new Error('Already has registry');registryOptions.freeze();if(registryOptions.mode==tr.b.BASIC_REGISTRY_MODE){tr.b._decorateBasicExtensionRegistry(registry,registryOptions);}else if(registryOptions.mode==tr.b.TYPE_BASED_REGISTRY_MODE){tr.b._decorateTypeBasedExtensionRegistry(registry,registryOptions);}else{throw new Error('Unrecognized mode');}
+if(registry.addEventListener===undefined)
+tr.b.EventTarget.decorate(registry);}
+return{decorateExtensionRegistry:decorateExtensionRegistry};});'use strict';tr.exportTo('tr.c',function(){function Auditor(model){}
+Auditor.prototype={__proto__:Object.prototype,runAnnotate:function(){},runAudit:function(){}};var options=new tr.b.ExtensionRegistryOptions(tr.b.BASIC_REGISTRY_MODE);options.defaultMetadata={};options.mandatoryBaseClass=Auditor;tr.b.decorateExtensionRegistry(Auditor,options);return{Auditor:Auditor};});'use strict';tr.exportTo('tr.importer',function(){function Importer(){}
+Importer.prototype={__proto__:Object.prototype,isTraceDataContainer:function(){return false;},extractSubtraces:function(){return[];},importEvents:function(){},importSampleData:function(){},finalizeImport:function(){},joinRefs:function(){}};var options=new tr.b.ExtensionRegistryOptions(tr.b.BASIC_REGISTRY_MODE);options.defaultMetadata={};options.mandatoryBaseClass=Importer;tr.b.decorateExtensionRegistry(Importer,options);Importer.findImporterFor=function(eventData){var typeInfo=Importer.f [...]
+return typeInfo.constructor;return undefined;};return{Importer:Importer};});'use strict';tr.exportTo('tr.importer',function(){var Importer=tr.importer.Importer;function EmptyImporter(events){this.importPriority=0;};EmptyImporter.canImport=function(eventData){if(eventData instanceof Array&&eventData.length==0)
+return true;if(typeof(eventData)==='string'||eventData instanceof String){return eventData.length==0;}
+return false;};EmptyImporter.prototype={__proto__:Importer.prototype};Importer.register(EmptyImporter);return{EmptyImporter:EmptyImporter};});'use strict';tr.exportTo('tr.model',function(){function EventContainer(){this.important=true;this.bounds=undefined;}
+EventContainer.prototype={get stableId(){throw new Error('Not implemented');},updateBounds:function(){throw new Error('Not implemented');},shiftTimestampsForward:function(amount){throw new Error('Not implemented');},iterateAllEventsInThisContainer:function(eventTypePredicate,callback,opt_this){throw new Error('Not implemented');},iterateAllChildEventContainers:function(callback,opt_this){throw new Error('Not implemented');},iterateAllEvents:function(callback,opt_this){this.iterateAllEven [...]
+visit(this);}};return{EventContainer:EventContainer};});'use strict';tr.exportTo('tr.model',function(){function Device(model){if(!model)
+throw new Error('Must provide a model.');tr.model.EventContainer.call(this);this.bounds=new tr.b.Range();this.guid=tr.b.GUID.allocate();};Device.compare=function(x,y){return x.guid-y.guid;};Device.prototype={__proto__:tr.model.EventContainer.prototype,compareTo:function(that){return Device.compare(this,that);},get userFriendlyName(){return'Device';},get userFriendlyDetails(){return'Device';},get stableId(){return'Device';},getSettingsKey:function(){return'device';},get counters(){return{ [...]
+SelectableItem.prototype={get modelItem(){return this.modelItem_;},get selected(){return this.selectionState===SelectionState.SELECTED;},addToSelection:function(selection){var modelItem=this.modelItem_;if(!modelItem)
+return;selection.push(modelItem);},addToTrackMap:function(eventToTrackMap,track){var modelItem=this.modelItem_;if(!modelItem)
+return;eventToTrackMap.addEvent(modelItem,track);}};return{SelectableItem:SelectableItem};});'use strict';tr.exportTo('tr.model',function(){var SelectableItem=tr.model.SelectableItem;var SelectionState=tr.model.SelectionState;var categoryPartsFor={};function getCategoryParts(category){var parts=categoryPartsFor[category];if(parts!==undefined)
+return parts;parts=category.split(',');categoryPartsFor[category]=parts;return parts;}
+function Event(){SelectableItem.call(this,this);this.guid_=tr.b.GUID.allocate();this.selectionState=SelectionState.NONE;this.associatedAlerts=new tr.c.Selection();this.info=undefined;}
+Event.prototype={__proto__:SelectableItem.prototype,get guid(){return this.guid_;}};function EventRegistry(){}
+var options=new tr.b.ExtensionRegistryOptions(tr.b.BASIC_REGISTRY_MODE);options.mandatoryBaseType=Event;tr.b.decorateExtensionRegistry(EventRegistry,options);EventRegistry.addEventListener('will-register',function(e){var metadata=e.typeInfo.metadata;if(metadata.name===undefined)
+throw new Error('Registered events must provide name metadata');var i=tr.b.findFirstInArray(EventRegistry.getAllRegisteredTypeInfos(),function(x){return x.metadata.name===metadata.name;});if(i!==undefined)
+throw new Error('Event type with that name already registered');if(metadata.pluralName===undefined)
+throw new Error('Registered events must provide pluralName metadata');if(metadata.singleViewElementName===undefined){throw new Error('Registered events must provide '+'singleViewElementName metadata');}
+if(metadata.multiViewElementName===undefined){throw new Error('Registered events must provide '+'multiViewElementName metadata');}});var eventsByTypeName=undefined;EventRegistry.getEventTypeInfoByTypeName=function(typeName){if(eventsByTypeName===undefined){eventsByTypeName={};EventRegistry.getAllRegisteredTypeInfos().forEach(function(typeInfo){eventsByTypeName[typeInfo.metadata.name]=typeInfo;});}
+return eventsByTypeName[typeName];}
+EventRegistry.addEventListener('registry-changed',function(){eventsByTypeName=undefined;});function convertCamelCaseToTitleCase(name){var result=name.replace(/[A-Z]/g,' $&');result=result.charAt(0).toUpperCase()+result.slice(1);return result;}
+EventRegistry.getUserFriendlySingularName=function(typeName){var typeInfo=EventRegistry.getEventTypeInfoByTypeName(typeName);var str=typeInfo.metadata.name;return convertCamelCaseToTitleCase(str);};EventRegistry.getUserFriendlyPluralName=function(typeName){var typeInfo=EventRegistry.getEventTypeInfoByTypeName(typeName);var str=typeInfo.metadata.pluralName;return convertCamelCaseToTitleCase(str);};return{Event:Event,EventRegistry:EventRegistry};});'use strict';tr.exportTo('tr.b.units',fun [...]
+return{tsString:tsString};});'use strict';tr.exportTo('tr.b',function(){function findLowIndexInSortedArray(ary,mapFn,loVal){if(ary.length==0)
+return 1;var low=0;var high=ary.length-1;var i,comparison;var hitPos=-1;while(low<=high){i=Math.floor((low+high)/2);comparison=mapFn(ary[i])-loVal;if(comparison<0){low=i+1;continue;}else if(comparison>0){high=i-1;continue;}else{hitPos=i;high=i-1;}}
+return hitPos!=-1?hitPos:low;}
+function findIndexInSortedIntervals(ary,mapLoFn,mapWidthFn,loVal){var first=findLowIndexInSortedArray(ary,mapLoFn,loVal);if(first==0){if(loVal>=mapLoFn(ary[0])&&loVal<mapLoFn(ary[0])+mapWidthFn(ary[0],0)){return 0;}else{return-1;}}else if(first<ary.length){if(loVal>=mapLoFn(ary[first])&&loVal<mapLoFn(ary[first])+mapWidthFn(ary[first],first)){return first;}else if(loVal>=mapLoFn(ary[first-1])&&loVal<mapLoFn(ary[first-1])+
+mapWidthFn(ary[first-1],first-1)){return first-1;}else{return ary.length;}}else if(first==ary.length){if(loVal>=mapLoFn(ary[first-1])&&loVal<mapLoFn(ary[first-1])+
+mapWidthFn(ary[first-1],first-1)){return first-1;}else{return ary.length;}}else{return ary.length;}}
+function findIndexInSortedClosedIntervals(ary,mapLoFn,mapHiFn,val){var i=findLowIndexInSortedArray(ary,mapLoFn,val);if(i===0){if(val>=mapLoFn(ary[0],0)&&val<=mapHiFn(ary[0],0)){return 0;}else{return-1;}}else if(i<ary.length){if(val>=mapLoFn(ary[i-1],i-1)&&val<=mapHiFn(ary[i-1],i-1)){return i-1;}else if(val>=mapLoFn(ary[i],i)&&val<=mapHiFn(ary[i],i)){return i;}else{return ary.length;}}else if(i==ary.length){if(val>=mapLoFn(ary[i-1],i-1)&&val<=mapHiFn(ary[i-1],i-1)){return i-1;}else{return [...]
+function iterateOverIntersectingIntervals(ary,mapLoFn,mapWidthFn,loVal,hiVal,cb){if(ary.length==0)
+return;if(loVal>hiVal)return;var i=findLowIndexInSortedArray(ary,mapLoFn,loVal);if(i==-1){return;}
+if(i>0){var hi=mapLoFn(ary[i-1])+mapWidthFn(ary[i-1],i-1);if(hi>=loVal){cb(ary[i-1],i-1);}}
+if(i==ary.length){return;}
+for(var n=ary.length;i<n;i++){var lo=mapLoFn(ary[i]);if(lo>=hiVal)
+break;cb(ary[i],i);}}
+function getIntersectingIntervals(ary,mapLoFn,mapWidthFn,loVal,hiVal){var tmp=[];iterateOverIntersectingIntervals(ary,mapLoFn,mapWidthFn,loVal,hiVal,function(d){tmp.push(d);});return tmp;}
+function findClosestElementInSortedArray(ary,mapFn,val,maxDiff){if(ary.length===0)
+return null;var aftIdx=findLowIndexInSortedArray(ary,mapFn,val);var befIdx=aftIdx>0?aftIdx-1:0;if(aftIdx===ary.length)
+aftIdx-=1;var befDiff=Math.abs(val-mapFn(ary[befIdx]));var aftDiff=Math.abs(val-mapFn(ary[aftIdx]));if(befDiff>maxDiff&&aftDiff>maxDiff)
+return null;var idx=befDiff<aftDiff?befIdx:aftIdx;return ary[idx];}
+function findClosestIntervalInSortedIntervals(ary,mapLoFn,mapHiFn,val,maxDiff){if(ary.length===0)
+return null;var idx=findLowIndexInSortedArray(ary,mapLoFn,val);if(idx>0)
+idx-=1;var hiInt=ary[idx];var loInt=hiInt;if(val>mapHiFn(hiInt)&&idx+1<ary.length)
+loInt=ary[idx+1];var loDiff=Math.abs(val-mapLoFn(loInt));var hiDiff=Math.abs(val-mapHiFn(hiInt));if(loDiff>maxDiff&&hiDiff>maxDiff)
+return null;if(loDiff<hiDiff)
+return loInt;else
+return hiInt;}
+return{findLowIndexInSortedArray:findLowIndexInSortedArray,findIndexInSortedIntervals:findIndexInSortedIntervals,findIndexInSortedClosedIntervals:findIndexInSortedClosedIntervals,iterateOverIntersectingIntervals:iterateOverIntersectingIntervals,getIntersectingIntervals:getIntersectingIntervals,findClosestElementInSortedArray:findClosestElementInSortedArray,findClosestIntervalInSortedIntervals:findClosestIntervalInSortedIntervals};});'use strict';tr.exportTo('tr.model',function(){function [...]
+CounterSample.groupByTimestamp=function(samples){var samplesByTimestamp=tr.b.group(samples,function(sample){return sample.timestamp;});var timestamps=tr.b.dictionaryKeys(samplesByTimestamp);timestamps.sort();var groups=[];for(var i=0;i<timestamps.length;i++){var ts=timestamps[i];var group=samplesByTimestamp[ts];group.sort(function(x,y){return x.series.seriesIndex-y.series.seriesIndex;});groups.push(group);}
+return groups;}
+CounterSample.prototype={__proto__:tr.model.Event.prototype,get series(){return this.series_;},get timestamp(){return this.timestamp_;},get value(){return this.value_;},set timestamp(timestamp){this.timestamp_=timestamp;},addBoundsToRange:function(range){range.addValue(this.timestamp);},getSampleIndex:function(){return tr.b.findLowIndexInSortedArray(this.series.timestamps,function(x){return x;},this.timestamp_);},get userFriendlyName(){return'Counter sample from '+this.series_.title+' at '+
+tr.b.units.tsString(this.timestamp);}};tr.model.EventRegistry.register(CounterSample,{name:'counterSample',pluralName:'counterSamples',singleViewElementName:'tr-ui-a-counter-sample-sub-view',multiViewElementName:'tr-ui-a-counter-sample-sub-view'});return{CounterSample:CounterSample};});'use strict';tr.exportTo('tr.model',function(){var CounterSample=tr.model.CounterSample;function CounterSeries(name,color){tr.model.EventContainer.call(this);this.guid_=tr.b.GUID.allocate();this.name_=name [...]
+CounterSeries.prototype={__proto__:tr.model.EventContainer.prototype,get length(){return this.timestamps_.length;},get name(){return this.name_;},get color(){return this.color_;},get samples(){return this.samples_;},get timestamps(){return this.timestamps_;},getSample:function(idx){return this.samples_[idx];},getTimestamp:function(idx){return this.timestamps_[idx];},addCounterSample:function(ts,val){var sample=new CounterSample(this,ts,val);this.addSample(sample);return sample;},addSampl [...]
+return{min:min,max:max,avg:(sum/sampleIndices.length),start:this.getSample(sampleIndices[0]).value,end:this.getSample(sampleIndices.length-1).value};},shiftTimestampsForward:function(amount){for(var i=0;i<this.timestamps_.length;++i){this.timestamps_[i]+=amount;this.samples_[i].timestamp=this.timestamps_[i];}},iterateAllEventsInThisContainer:function(eventTypePredicate,callback,opt_this){if(eventTypePredicate.call(opt_this,tr.model.CounterSample)){this.samples_.forEach(callback,opt_this) [...]
+Counter.prototype={__proto__:tr.model.EventContainer.prototype,get guid(){return this.guid_;},get parent(){return this.parent_;},get id(){return this.id_;},get category(){return this.category_;},get name(){return this.name_;},iterateAllEventsInThisContainer:function(eventTypePredicate,callback,opt_this){},iterateAllChildEventContainers:function(callback,opt_this){for(var i=0;i<this.series_.length;i++)
+callback.call(opt_this,this.series_[i]);},set timestamps(arg){throw new Error('Bad counter API. No cookie.');},set seriesNames(arg){throw new Error('Bad counter API. No cookie.');},set seriesColors(arg){throw new Error('Bad counter API. No cookie.');},set samples(arg){throw new Error('Bad counter API. No cookie.');},addSeries:function(series){series.counter=this;series.seriesIndex=this.series_.length;this.series_.push(series);return series;},getSeries:function(idx){return this.series_[id [...]
+return 0;return this.series_[0].length;},get timestamps(){if(this.series_.length===0)
+return[];return this.series_[0].timestamps;},getSampleStatistics:function(sampleIndices){sampleIndices.sort();var ret=[];this.series_.forEach(function(series){ret.push(series.getStatistics(sampleIndices));});return ret;},shiftTimestampsForward:function(amount){for(var i=0;i<this.series_.length;++i)
+this.series_[i].shiftTimestampsForward(amount);},updateBounds:function(){this.totals=[];this.maxTotal=0;this.bounds.reset();if(this.series_.length===0)
+return;var firstSeries=this.series_[0];var lastSeries=this.series_[this.series_.length-1];this.bounds.addValue(firstSeries.getTimestamp(0));this.bounds.addValue(lastSeries.getTimestamp(lastSeries.length-1));var numSeries=this.numSeries;this.maxTotal=-Infinity;for(var i=0;i<firstSeries.length;++i){var total=0;this.series_.forEach(function(series){total+=series.getSample(i).value;this.totals.push(total);}.bind(this));this.maxTotal=Math.max(total,this.maxTotal);}}};Counter.compare=function( [...]
+return tmp;var tmp=x.name.localeCompare(y.name);if(tmp==0)
+return x.tid-y.tid;return tmp;};return{Counter:Counter};});'use strict';tr.exportTo('tr.model',function(){function TimedEvent(start){tr.model.Event.call(this);this.start=start;this.duration=0;this.cpuStart=undefined;this.cpuDuration=undefined;}
+TimedEvent.prototype={__proto__:tr.model.Event.prototype,get end(){return this.start+this.duration;},addBoundsToRange:function(range){range.addValue(this.start);range.addValue(this.end);},bounds:function(that,precisionUnit){if(precisionUnit===undefined){precisionUnit=tr.b.units.Time.supportedUnits.ms;}
+var startsBefore=precisionUnit.roundedLess(that.start,this.start);var endsAfter=precisionUnit.roundedLess(this.end,that.end);return!startsBefore&&!endsAfter;}};return{TimedEvent:TimedEvent};});'use strict';tr.exportTo('tr.model',function(){function Slice(category,title,colorId,start,args,opt_duration,opt_cpuStart,opt_cpuDuration,opt_argsStripped){tr.model.TimedEvent.call(this,start);this.category=category||'';this.title=title;this.colorId=colorId;this.args=args;this.startStackFrame=undef [...]
+this.duration=opt_duration;if(opt_cpuStart!==undefined)
+this.cpuStart=opt_cpuStart;if(opt_cpuDuration!==undefined)
+this.cpuDuration=opt_cpuDuration;if(opt_argsStripped!==undefined)
+this.argsStripped=true;}
+Slice.prototype={__proto__:tr.model.TimedEvent.prototype,get analysisTypeName(){return this.title;},get userFriendlyName(){return'Slice '+this.title+' at '+
+tr.b.units.tsString(this.start);},findDescendentSlice:function(targetTitle){if(!this.subSlices)
+return undefined;for(var i=0;i<this.subSlices.length;i++){if(this.subSlices[i].title==targetTitle)
+return this.subSlices[i];var slice=this.subSlices[i].findDescendentSlice(targetTitle);if(slice)return slice;}
+return undefined;},get mostTopLevelSlice(){var curSlice=this;while(curSlice.parentSlice)
+curSlice=curSlice.parentSlice;return curSlice;},iterateAllSubsequentSlices:function(callback,opt_this){var parentStack=[];var started=false;var topmostSlice=this.mostTopLevelSlice;parentStack.push(topmostSlice);while(parentStack.length!==0){var curSlice=parentStack.pop();if(started)
+callback.call(opt_this,curSlice);else
+started=(curSlice.guid===this.guid);for(var i=curSlice.subSlices.length-1;i>=0;i--){parentStack.push(curSlice.subSlices[i]);}}},get subsequentSlices(){var res=[];this.iterateAllSubsequentSlices(function(subseqSlice){res.push(subseqSlice);});return res;},iterateAllAncestors:function(callback,opt_this){var curSlice=this;while(curSlice.parentSlice){curSlice=curSlice.parentSlice;callback.call(opt_this,curSlice);}},get ancestorSlices(){var res=[];this.iterateAllAncestors(function(ancestor){re [...]
+ThreadTimeSlice.prototype={__proto__:Slice.prototype,getColorForState_:function(state){var getColorIdForReservedName=tr.ui.b.getColorIdForReservedName;switch(state){case SCHEDULING_STATE.RUNNABLE:return getColorIdForReservedName('thread_state_runnable');case SCHEDULING_STATE.RUNNING:return getColorIdForReservedName('thread_state_running');case SCHEDULING_STATE.SLEEPING:return getColorIdForReservedName('thread_state_sleeping');case SCHEDULING_STATE.DEBUG:case SCHEDULING_STATE.EXIT_DEAD:ca [...]
+return undefined;var cpuSlices=this.cpuOnWhichThreadWasRunning.slices;for(var i=0;i<cpuSlices.length;i++){var cpuSlice=cpuSlices[i];if(cpuSlice.start!==this.start)
+continue;if(cpuSlice.duration!==this.duration)
+continue;return cpuSlice;}
+return undefined;},getCpuSliceThatTookCpu:function(){if(this.cpuOnWhichThreadWasRunning)
+return undefined;var curIndex=this.thread.indexOfTimeSlice(this);var cpuSliceWhenLastRunning;while(curIndex>=0){var curSlice=this.thread.timeSlices[curIndex];if(!curSlice.cpuOnWhichThreadWasRunning){curIndex--;continue;}
+cpuSliceWhenLastRunning=curSlice.getAssociatedCpuSlice();break;}
+if(!cpuSliceWhenLastRunning)
+return undefined;var cpu=cpuSliceWhenLastRunning.cpu;var indexOfSliceOnCpuWhenLastRunning=cpu.indexOf(cpuSliceWhenLastRunning);var nextRunningSlice=cpu.slices[indexOfSliceOnCpuWhenLastRunning+1];if(!nextRunningSlice)
+return undefined;if(Math.abs(nextRunningSlice.start-cpuSliceWhenLastRunning.end)<0.00001)
+return nextRunningSlice;return undefined;}};tr.model.EventRegistry.register(ThreadTimeSlice,{name:'threadTimeSlice',pluralName:'threadTimeSlices',singleViewElementName:'tr-ui-a-single-thread-time-slice-sub-view',multiViewElementName:'tr-ui-a-multi-thread-time-slice-sub-view'});return{ThreadTimeSlice:ThreadTimeSlice,SCHEDULING_STATE:SCHEDULING_STATE};});'use strict';tr.exportTo('tr.model',function(){var Slice=tr.model.Slice;function CpuSlice(cat,title,colorId,start,args,opt_duration){Slic [...]
+CpuSlice.prototype={__proto__:Slice.prototype,get analysisTypeName(){return'tr.ui.analysis.CpuSlice';},getAssociatedTimeslice:function(){if(!this.threadThatWasRunning)
+return undefined;var timeSlices=this.threadThatWasRunning.timeSlices;for(var i=0;i<timeSlices.length;i++){var timeSlice=timeSlices[i];if(timeSlice.start!==this.start)
+continue;if(timeSlice.duration!==this.duration)
+continue;return timeSlice;}
+return undefined;}};tr.model.EventRegistry.register(CpuSlice,{name:'cpuSlice',pluralName:'cpuSlices',singleViewElementName:'tr-ui-a-single-cpu-slice-sub-view',multiViewElementName:'tr-ui-a-multi-cpu-slice-sub-view'});return{CpuSlice:CpuSlice};});'use strict';tr.exportTo('tr.model',function(){var Counter=tr.model.Counter;var Slice=tr.model.Slice;var CpuSlice=tr.model.CpuSlice;function Cpu(kernel,number){if(kernel===undefined||number===undefined)
+throw new Error('Missing arguments');this.kernel=kernel;this.cpuNumber=number;this.slices=[];this.counters={};this.bounds=new tr.b.Range();this.samples_=undefined;this.lastActiveTimestamp_=undefined;this.lastActiveThread_=undefined;this.lastActiveName_=undefined;this.lastActiveArgs_=undefined;};Cpu.prototype={iterateAllEventsInThisContainer:function(eventTypePredicate,callback,opt_this){if(eventTypePredicate.call(opt_this,tr.model.CpuSlice))
+this.slices.forEach(callback,opt_this);if(this.samples_){if(eventTypePredicate.call(opt_this,tr.model.Sample))
+this.samples_.forEach(callback,opt_this);}},iterateAllChildEventContainers:function(callback,opt_this){for(var id in this.counters)
+callback.call(opt_this,this.counters[id]);},getOrCreateCounter:function(cat,name){var id;if(cat.length)
+id=cat+'.'+name;else
+id=name;if(!this.counters[id])
+this.counters[id]=new Counter(this,id,cat,name);return this.counters[id];},shiftTimestampsForward:function(amount){for(var sI=0;sI<this.slices.length;sI++)
+this.slices[sI].start=(this.slices[sI].start+amount);for(var id in this.counters)
+this.counters[id].shiftTimestampsForward(amount);},updateBounds:function(){this.bounds.reset();if(this.slices.length){this.bounds.addValue(this.slices[0].start);this.bounds.addValue(this.slices[this.slices.length-1].end);}
+for(var id in this.counters){this.counters[id].updateBounds();this.bounds.addRange(this.counters[id].bounds);}
+if(this.samples_&&this.samples_.length){this.bounds.addValue(this.samples_[0].start);this.bounds.addValue(this.samples_[this.samples_.length-1].end);}},createSubSlices:function(){this.samples_=this.kernel.model.samples.filter(function(sample){return sample.cpu==this;},this);},addCategoriesToDict:function(categoriesDict){for(var i=0;i<this.slices.length;i++)
+categoriesDict[this.slices[i].category]=true;for(var id in this.counters)
+categoriesDict[this.counters[id].category]=true;for(var i=0;i<this.samples_.length;i++)
+categoriesDict[this.samples_[i].category]=true;},get userFriendlyName(){return'CPU '+this.cpuNumber;},indexOf:function(cpuSlice){var i=tr.b.findLowIndexInSortedArray(this.slices,function(slice){return slice.start;},cpuSlice.start);if(this.slices[i]!==cpuSlice)
+return undefined;return i;},closeActiveThread:function(end_timestamp,args){if(this.lastActiveThread_==undefined||this.lastActiveThread_==0)
+return;if(end_timestamp<this.lastActiveTimestamp_){throw new Error('The end timestamp of a thread running on CPU '+
+this.cpuNumber+' is before its start timestamp.');}
+for(var key in args){this.lastActiveArgs_[key]=args[key];}
+var duration=end_timestamp-this.lastActiveTimestamp_;var slice=new tr.model.CpuSlice('',this.lastActiveName_,tr.ui.b.getColorIdForGeneralPurposeString(this.lastActiveName_),this.lastActiveTimestamp_,this.lastActiveArgs_,duration);slice.cpu=this;this.slices.push(slice);this.lastActiveTimestamp_=undefined;this.lastActiveThread_=undefined;this.lastActiveName_=undefined;this.lastActiveArgs_=undefined;},switchActiveThread:function(timestamp,old_thread_args,new_thread_id,new_thread_name,new_th [...]
+ObjectSnapshot.prototype={__proto__:tr.model.Event.prototype,preInitialize:function(){},initialize:function(){},addBoundsToRange:function(range){range.addValue(this.ts);},get userFriendlyName(){return'Snapshot of '+
+this.objectInstance.typeName+' '+
+this.objectInstance.id+' @ '+
+tr.b.units.tsString(this.ts);}};tr.model.EventRegistry.register(ObjectSnapshot,{name:'objectSnapshot',pluralName:'objectSnapshots',singleViewElementName:'tr-ui-a-single-object-snapshot-sub-view',multiViewElementName:'tr-ui-a-multi-object-sub-view'});var options=new tr.b.ExtensionRegistryOptions(tr.b.TYPE_BASED_REGISTRY_MODE);options.mandatoryBaseClass=ObjectSnapshot;options.defaultConstructor=ObjectSnapshot;tr.b.decorateExtensionRegistry(ObjectSnapshot,options);return{ObjectSnapshot:Obje [...]
+ObjectInstance.prototype={__proto__:tr.model.Event.prototype,get typeName(){return this.name;},addBoundsToRange:function(range){range.addRange(this.bounds);},addSnapshot:function(ts,args,opt_name,opt_baseTypeName){if(ts<this.creationTs)
+throw new Error('Snapshots must be >= instance.creationTs');if(ts>=this.deletionTs)
+throw new Error('Snapshots cannot be added after '+'an objects deletion timestamp.');var lastSnapshot;if(this.snapshots.length>0){lastSnapshot=this.snapshots[this.snapshots.length-1];if(lastSnapshot.ts==ts)
+throw new Error('Snapshots already exists at this time!');if(ts<lastSnapshot.ts){throw new Error('Snapshots must be added in increasing timestamp order');}}
+if(opt_name&&(this.name!=opt_name)){if(!opt_baseTypeName)
+throw new Error('Must provide base type name for name update');if(this.baseTypeName!=opt_baseTypeName)
+throw new Error('Cannot update type name: base types dont match');this.name=opt_name;}
+var snapshotConstructor=tr.model.ObjectSnapshot.getConstructor(this.category,this.name);var snapshot=new snapshotConstructor(this,ts,args);this.snapshots.push(snapshot);return snapshot;},wasDeleted:function(ts){var lastSnapshot;if(this.snapshots.length>0){lastSnapshot=this.snapshots[this.snapshots.length-1];if(lastSnapshot.ts>ts)
+throw new Error('Instance cannot be deleted at ts='+
+ts+'. A snapshot exists that is older.');}
+this.deletionTs=ts;this.deletionTsWasExplicit=true;},preInitialize:function(){for(var i=0;i<this.snapshots.length;i++)
+this.snapshots[i].preInitialize();},initialize:function(){for(var i=0;i<this.snapshots.length;i++)
+this.snapshots[i].initialize();},getSnapshotAt:function(ts){if(ts<this.creationTs){if(this.creationTsWasExplicit)
+throw new Error('ts must be within lifetime of this instance');return this.snapshots[0];}
+if(ts>this.deletionTs)
+throw new Error('ts must be within lifetime of this instance');var snapshots=this.snapshots;var i=tr.b.findIndexInSortedIntervals(snapshots,function(snapshot){return snapshot.ts;},function(snapshot,i){if(i==snapshots.length-1)
+return snapshots[i].objectInstance.deletionTs;return snapshots[i+1].ts-snapshots[i].ts;},ts);if(i<0){return this.snapshots[0];}
+if(i>=this.snapshots.length)
+return this.snapshots[this.snapshots.length-1];return this.snapshots[i];},updateBounds:function(){this.bounds.reset();this.bounds.addValue(this.creationTs);if(this.deletionTs!=Number.MAX_VALUE)
+this.bounds.addValue(this.deletionTs);else if(this.snapshots.length>0)
+this.bounds.addValue(this.snapshots[this.snapshots.length-1].ts);},shiftTimestampsForward:function(amount){this.creationTs+=amount;if(this.deletionTs!=Number.MAX_VALUE)
+this.deletionTs+=amount;this.snapshots.forEach(function(snapshot){snapshot.ts+=amount;});},get userFriendlyName(){return this.typeName+' object '+this.id;}};tr.model.EventRegistry.register(ObjectInstance,{name:'objectInstance',pluralName:'objectInstances',singleViewElementName:'tr-ui-a-single-object-instance-sub-view',multiViewElementName:'tr-ui-a-multi-object-sub-view'});var options=new tr.b.ExtensionRegistryOptions(tr.b.TYPE_BASED_REGISTRY_MODE);options.mandatoryBaseClass=ObjectInstanc [...]
+TimeToObjectInstanceMap.prototype={idWasCreated:function(category,name,ts){if(this.instances.length==0){this.instances.push(this.createObjectInstanceFunction_(this.parent,this.id,category,name,ts));this.instances[0].creationTsWasExplicit=true;return this.instances[0];}
+var lastInstance=this.instances[this.instances.length-1];if(ts<lastInstance.deletionTs){throw new Error('Mutation of the TimeToObjectInstanceMap must be '+'done in ascending timestamp order.');}
+lastInstance=this.createObjectInstanceFunction_(this.parent,this.id,category,name,ts);lastInstance.creationTsWasExplicit=true;this.instances.push(lastInstance);return lastInstance;},addSnapshot:function(category,name,ts,args,opt_baseTypeName){if(this.instances.length==0){this.instances.push(this.createObjectInstanceFunction_(this.parent,this.id,category,name,ts,opt_baseTypeName));}
+var i=tr.b.findIndexInSortedIntervals(this.instances,function(inst){return inst.creationTs;},function(inst){return inst.deletionTs-inst.creationTs;},ts);var instance;if(i<0){instance=this.instances[0];if(ts>instance.deletionTs||instance.creationTsWasExplicit){throw new Error('At the provided timestamp, no instance was still alive');}
+if(instance.snapshots.length!=0){throw new Error('Cannot shift creationTs forward, '+'snapshots have been added. First snap was at ts='+
+instance.snapshots[0].ts+' and creationTs was '+
+instance.creationTs);}
+instance.creationTs=ts;}else if(i>=this.instances.length){instance=this.instances[this.instances.length-1];if(ts>=instance.deletionTs){instance=this.createObjectInstanceFunction_(this.parent,this.id,category,name,ts,opt_baseTypeName);this.instances.push(instance);}else{var lastValidIndex;for(var i=this.instances.length-1;i>=0;i--){var tmp=this.instances[i];if(ts>=tmp.deletionTs)
+break;if(tmp.creationTsWasExplicit==false&&tmp.snapshots.length==0)
+lastValidIndex=i;}
+if(lastValidIndex===undefined){throw new Error('Cannot add snapshot. No instance was alive that was mutable.');}
+instance=this.instances[lastValidIndex];instance.creationTs=ts;}}else{instance=this.instances[i];}
+return instance.addSnapshot(ts,args,name,opt_baseTypeName);},get lastInstance(){if(this.instances.length==0)
+return undefined;return this.instances[this.instances.length-1];},idWasDeleted:function(category,name,ts){if(this.instances.length==0){this.instances.push(this.createObjectInstanceFunction_(this.parent,this.id,category,name,ts));}
+var lastInstance=this.instances[this.instances.length-1];if(ts<lastInstance.creationTs)
+throw new Error('Cannot delete a id before it was crated');if(lastInstance.deletionTs==Number.MAX_VALUE){lastInstance.wasDeleted(ts);return lastInstance;}
+if(ts<lastInstance.deletionTs)
+throw new Error('id was already deleted earlier.');lastInstance=this.createObjectInstanceFunction_(this.parent,this.id,category,name,ts);this.instances.push(lastInstance);lastInstance.wasDeleted(ts);return lastInstance;},getInstanceAt:function(ts){var i=tr.b.findIndexInSortedIntervals(this.instances,function(inst){return inst.creationTs;},function(inst){return inst.deletionTs-inst.creationTs;},ts);if(i<0){if(this.instances[0].creationTsWasExplicit)
+return undefined;return this.instances[0];}else if(i>=this.instances.length){return undefined;}
+return this.instances[i];},logToConsole:function(){for(var i=0;i<this.instances.length;i++){var instance=this.instances[i];var cEF='';var dEF='';if(instance.creationTsWasExplicit)
+cEF='(explicitC)';if(instance.deletionTsWasExplicit)
+dEF='(explicit)';console.log(instance.creationTs,cEF,instance.deletionTs,dEF,instance.category,instance.name,instance.snapshots.length+' snapshots');}}};return{TimeToObjectInstanceMap:TimeToObjectInstanceMap};});'use strict';tr.exportTo('tr.model',function(){var ObjectInstance=tr.model.ObjectInstance;var ObjectSnapshot=tr.model.ObjectSnapshot;function ObjectCollection(parent){tr.model.EventContainer.call(this);this.parent=parent;this.bounds=new tr.b.Range();this.instanceMapsById_={};this [...]
+ObjectCollection.prototype={__proto__:tr.model.EventContainer.prototype,iterateAllChildEventContainers:function(callback,opt_this){},iterateAllEventsInThisContainer:function(eventTypePredicate,callback,opt_this){var bI=!!eventTypePredicate.call(opt_this,ObjectInstance);var bS=!!eventTypePredicate.call(opt_this,ObjectSnapshot);if(bI===false&&bS===false)
+return;this.iterObjectInstances(function(instance){if(bI)
+callback.call(opt_this,instance);if(bS)
+instance.snapshots.forEach(callback,opt_this);},opt_this);},createObjectInstance_:function(parent,id,category,name,creationTs,opt_baseTypeName){var constructor=tr.model.ObjectInstance.getConstructor(category,name);var instance=new constructor(parent,id,category,name,creationTs,opt_baseTypeName);var typeName=instance.typeName;var instancesOfTypeName=this.instancesByTypeName_[typeName];if(!instancesOfTypeName){instancesOfTypeName=[];this.instancesByTypeName_[typeName]=instancesOfTypeName;}
+instancesOfTypeName.push(instance);return instance;},getOrCreateInstanceMap_:function(id){var instanceMap=this.instanceMapsById_[id];if(instanceMap)
+return instanceMap;instanceMap=new tr.model.TimeToObjectInstanceMap(this.createObjectInstance_,this.parent,id);this.instanceMapsById_[id]=instanceMap;return instanceMap;},idWasCreated:function(id,category,name,ts){var instanceMap=this.getOrCreateInstanceMap_(id);return instanceMap.idWasCreated(category,name,ts);},addSnapshot:function(id,category,name,ts,args,opt_baseTypeName){var instanceMap=this.getOrCreateInstanceMap_(id);var snapshot=instanceMap.addSnapshot(category,name,ts,args,opt_b [...]
+snapshot.objectInstance.category+' name='+
+snapshot.objectInstance.name;throw new Error(msg);}
+if(opt_baseTypeName&&snapshot.objectInstance.baseTypeName!=opt_baseTypeName){throw new Error('Could not add snapshot with baseTypeName='+
+opt_baseTypeName+'. It '+'was previously created with name='+
+snapshot.objectInstance.baseTypeName);}
+if(snapshot.objectInstance.name!=name){throw new Error('Could not add snapshot with name='+name+'. It '+'was previously created with name='+
+snapshot.objectInstance.name);}
+return snapshot;},idWasDeleted:function(id,category,name,ts){var instanceMap=this.getOrCreateInstanceMap_(id);var deletedInstance=instanceMap.idWasDeleted(category,name,ts);if(!deletedInstance)
+return;if(deletedInstance.category!=category){var msg='Deleting object '+deletedInstance.name+' with a different category '+'than when it was created. It previous had cat='+
+deletedInstance.category+' but the delete command '+'had cat='+category;throw new Error(msg);}
+if(deletedInstance.baseTypeName!=name){throw new Error('Deletion requested for name='+
+name+' could not proceed: '+'An existing object with baseTypeName='+
+deletedInstance.baseTypeName+' existed.');}},autoDeleteObjects:function(maxTimestamp){tr.b.iterItems(this.instanceMapsById_,function(id,i2imap){var lastInstance=i2imap.lastInstance;if(lastInstance.deletionTs!=Number.MAX_VALUE)
+return;i2imap.idWasDeleted(lastInstance.category,lastInstance.name,maxTimestamp);lastInstance.deletionTsWasExplicit=false;});},getObjectInstanceAt:function(id,ts){var instanceMap=this.instanceMapsById_[id];if(!instanceMap)
+return undefined;return instanceMap.getInstanceAt(ts);},getSnapshotAt:function(id,ts){var instance=this.getObjectInstanceAt(id,ts);if(!instance)
+return undefined;return instance.getSnapshotAt(ts);},iterObjectInstances:function(iter,opt_this){opt_this=opt_this||this;tr.b.iterItems(this.instanceMapsById_,function(id,i2imap){i2imap.instances.forEach(iter,opt_this);});},getAllObjectInstances:function(){var instances=[];this.iterObjectInstances(function(i){instances.push(i);});return instances;},getAllInstancesNamed:function(name){return this.instancesByTypeName_[name];},getAllInstancesByTypeName:function(){return this.instancesByType [...]
+ThreadSlice.prototype={__proto__:Slice.prototype};tr.model.EventRegistry.register(ThreadSlice,{name:'slice',pluralName:'slices',singleViewElementName:'tr-ui-a-single-thread-slice-sub-view',multiViewElementName:'tr-ui-a-multi-thread-slice-sub-view'});return{ThreadSlice:ThreadSlice};});'use strict';tr.exportTo('tr.ui.b',function(){function boundChannel(v){return Math.min(255,Math.max(0,Math.floor(v)));}
+function brightenColor(c){var k;if(c.r>=240&&c.g>=240&&c.b>=240)
+k=0.80;else
+k=1.45;return{r:boundChannel(c.r*k),g:boundChannel(c.g*k),b:boundChannel(c.b*k)};}
+function desaturateColor(c){var value=boundChannel((c.r+c.g+c.b)/3);return{r:value,g:value,b:value};}
+function colorToRGBString(c){return'rgb('+c.r+','+c.g+','+c.b+')';}
+function colorToRGBAString(c,a){return'rgba('+c.r+','+c.g+','+c.b+','+a+')';}
+return{brightenColor:brightenColor,desaturateColor:desaturateColor,colorToRGBString:colorToRGBString,colorToRGBAString:colorToRGBAString};});'use strict';tr.exportTo('tr.ui.b',function(){var colorToRGBString=tr.ui.b.colorToRGBString;var colorToRGBAString=tr.ui.b.colorToRGBAString;var generalPurposeColors=[{r:138,g:113,b:152},{r:175,g:112,b:133},{r:127,g:135,b:225},{r:93,g:81,b:137},{r:116,g:143,b:119},{r:178,g:214,b:122},{r:87,g:109,b:147},{r:119,g:155,b:95},{r:114,g:180,b:160},{r:132,g: [...]
+hash=(hash+37*hash+11*name.charCodeAt(i))%0xFFFFFFFF;return hash;}
+function getColorPalette(){return palette;}
+function getRawColorPalette(){return paletteRaw;}
+function getColorPaletteHighlightIdBoost(){return highlightIdBoost;}
+function getColorPaletteDesaturateIdBoost(){return desaturateIdBoost;}
+function getColorIdForReservedName(name){var id=reservedColorNameToIdMap[name];if(id===undefined)
+throw new Error('Unrecognized color ')+name;return id;}
+var stringColorIdCache={};function getColorIdForGeneralPurposeString(string){if(stringColorIdCache[string]===undefined){var hash=getStringHash(string);stringColorIdCache[string]=hash%numGeneralPurposeColorIds;}
+return stringColorIdCache[string];}
+var paletteProperties={numGeneralPurposeColorIds:numGeneralPurposeColorIds,highlightIdBoost:highlightIdBoost,desaturateIdBoost:desaturateIdBoost};return{getRawColorPalette:getRawColorPalette,getColorPalette:getColorPalette,paletteProperties:paletteProperties,getColorPaletteHighlightIdBoost:getColorPaletteHighlightIdBoost,getColorPaletteDesaturateIdBoost:getColorPaletteDesaturateIdBoost,getColorIdForReservedName:getColorIdForReservedName,getStringHash:getStringHash,getColorIdForGeneralPur [...]
+function getSliceHi(s){return s.end;}
+function SliceGroup(parentContainer,opt_sliceConstructor,opt_name){this.guid_=tr.b.GUID.allocate();this.parentContainer_=parentContainer;var sliceConstructor=opt_sliceConstructor||Slice;this.sliceConstructor=sliceConstructor;this.openPartialSlices_=[];this.slices=[];this.bounds=new tr.b.Range();this.topLevelSlices=[];this.haveTopLevelSlicesBeenBuilt=false;this.name_=opt_name;if(this.model===undefined)
+throw new Error('SliceGroup must have model defined.');}
+SliceGroup.prototype={__proto__:tr.model.EventContainer.prototype,get guid(){return this.guid_;},get parentContainer(){return this.parentContainer_;},get model(){return this.parentContainer_.model;},get stableId(){return this.parentContainer_.stableId+'.SliceGroup';},getSettingsKey:function(){if(!this.name_)
+return undefined;var parentKey=this.parentContainer_.getSettingsKey();if(!parentKey)
+return undefined;return parentKey+'.'+this.name;},get length(){return this.slices.length;},pushSlice:function(slice){this.haveTopLevelSlicesBeenBuilt=false;slice.parentContainer=this.parentContainer_;this.slices.push(slice);return slice;},pushSlices:function(slices){this.haveTopLevelSlicesBeenBuilt=false;slices.forEach(function(slice){slice.parentContainer=this.parentContainer_;this.slices.push(slice);},this);},beginSlice:function(category,title,ts,opt_args,opt_tts,opt_argsStripped){if(t [...]
+throw new Error('Slices must be added in increasing timestamp order');}
+var colorId=tr.ui.b.getColorIdForGeneralPurposeString(title);var slice=new this.sliceConstructor(category,title,colorId,ts,opt_args?opt_args:{},null,opt_tts,undefined,opt_argsStripped);this.openPartialSlices_.push(slice);slice.didNotFinish=true;this.pushSlice(slice);return slice;},isTimestampValidForBeginOrEnd:function(ts){if(!this.openPartialSlices_.length)
+return true;var top=this.openPartialSlices_[this.openPartialSlices_.length-1];return ts>=top.start;},get openSliceCount(){return this.openPartialSlices_.length;},get mostRecentlyOpenedPartialSlice(){if(!this.openPartialSlices_.length)
+return undefined;return this.openPartialSlices_[this.openPartialSlices_.length-1];},endSlice:function(ts,opt_tts){if(!this.openSliceCount)
+throw new Error('endSlice called without an open slice');var slice=this.openPartialSlices_[this.openSliceCount-1];this.openPartialSlices_.splice(this.openSliceCount-1,1);if(ts<slice.start)
+throw new Error('Slice '+slice.title+' end time is before its start.');slice.duration=ts-slice.start;slice.didNotFinish=false;if(opt_tts&&slice.cpuStart!==undefined)
+slice.cpuDuration=opt_tts-slice.cpuStart;return slice;},pushCompleteSlice:function(category,title,ts,duration,tts,cpuDuration,opt_args,opt_argsStripped){var colorId=tr.ui.b.getColorIdForGeneralPurposeString(title);var slice=new this.sliceConstructor(category,title,colorId,ts,opt_args?opt_args:{},duration,tts,cpuDuration,opt_argsStripped);if(duration===undefined)
+slice.didNotFinish=true;this.pushSlice(slice);return slice;},autoCloseOpenSlices:function(opt_maxTimestamp){if(!opt_maxTimestamp){this.updateBounds();opt_maxTimestamp=this.bounds.max;}
+for(var sI=0;sI<this.slices.length;sI++){var slice=this.slices[sI];if(slice.didNotFinish)
+slice.duration=opt_maxTimestamp-slice.start;}
+this.openPartialSlices_=[];},shiftTimestampsForward:function(amount){for(var sI=0;sI<this.slices.length;sI++){var slice=this.slices[sI];slice.start=(slice.start+amount);}},updateBounds:function(){this.bounds.reset();for(var i=0;i<this.slices.length;i++){this.bounds.addValue(this.slices[i].start);this.bounds.addValue(this.slices[i].end);}},copySlice:function(slice){var newSlice=new this.sliceConstructor(slice.category,slice.title,slice.colorId,slice.start,slice.args,slice.duration,slice.c [...]
+this.slices.forEach(callback,opt_this);},iterateAllChildEventContainers:function(callback,opt_this){},getSlicesOfName:function(title){var slices=[];for(var i=0;i<this.slices.length;i++){if(this.slices[i].title==title){slices.push(this.slices[i]);}}
+return slices;},iterSlicesInTimeRange:function(callback,start,end){var ret=[];tr.b.iterateOverIntersectingIntervals(this.topLevelSlices,function(s){return s.start;},function(s){return s.duration;},start,end,function(topLevelSlice){callback(topLevelSlice);topLevelSlice.iterateAllDescendents(callback);});return ret;},findSliceAtTs:function(ts){if(!this.haveTopLevelSlicesBeenBuilt)
+throw new Error('Nope');var i=tr.b.findIndexInSortedClosedIntervals(this.topLevelSlices,getSliceLo,getSliceHi,ts);if(i==-1||i==this.topLevelSlices.length)
+return undefined;var curSlice=this.topLevelSlices[i];while(true){var i=tr.b.findIndexInSortedClosedIntervals(curSlice.subSlices,getSliceLo,getSliceHi,ts);if(i==-1||i==curSlice.subSlices.length)
+return curSlice;curSlice=curSlice.subSlices[i];}},findNextSliceAfter:function(ts,refGuid){var i=tr.b.findLowIndexInSortedArray(this.slices,getSliceLo,ts);if(i===this.slices.length)
+return undefined;for(;i<this.slices.length;i++){var slice=this.slices[i];if(slice.start>ts)
+return slice;if(slice.guid<=refGuid)
+continue;return slice;}
+return undefined;},createSubSlices:function(){this.haveTopLevelSlicesBeenBuilt=true;this.createSubSlicesImpl_();if(this.parentContainer.timeSlices)
+this.addCpuTimeToSubslices_(this.parentContainer.timeSlices);this.slices.forEach(function(slice){var selfTime=slice.duration;for(var i=0;i<slice.subSlices.length;i++)
+selfTime-=slice.subSlices[i].duration;slice.selfTime=selfTime;if(slice.cpuDuration===undefined)
+return;var cpuSelfTime=slice.cpuDuration;for(var i=0;i<slice.subSlices.length;i++){if(slice.subSlices[i].cpuDuration!==undefined)
+cpuSelfTime-=slice.subSlices[i].cpuDuration;}
+slice.cpuSelfTime=cpuSelfTime;});},createSubSlicesImpl_:function(){var precisionUnit=this.model.intrinsicTimeUnit;function addSliceIfBounds(root,child){if(root.bounds(child,precisionUnit)){if(root.subSlices&&root.subSlices.length>0){if(addSliceIfBounds(root.subSlices[root.subSlices.length-1],child))
+return true;}
+child.parentSlice=root;if(root.subSlices===undefined)
+root.subSlices=[];root.subSlices.push(child);return true;}
+return false;}
+if(!this.slices.length)
+return;var ops=[];for(var i=0;i<this.slices.length;i++){if(this.slices[i].subSlices)
+this.slices[i].subSlices.splice(0,this.slices[i].subSlices.length);ops.push(i);}
+var originalSlices=this.slices;ops.sort(function(ix,iy){var x=originalSlices[ix];var y=originalSlices[iy];if(x.start!=y.start)
+return x.start-y.start;return ix-iy;});var slices=new Array(this.slices.length);for(var i=0;i<ops.length;i++){slices[i]=originalSlices[ops[i]];}
+var rootSlice=slices[0];this.topLevelSlices=[];this.topLevelSlices.push(rootSlice);for(var i=1;i<slices.length;i++){var slice=slices[i];if(!addSliceIfBounds(rootSlice,slice)){rootSlice=slice;this.topLevelSlices.push(rootSlice);}}
+this.slices=slices;},addCpuTimeToSubslices_:function(timeSlices){var SCHEDULING_STATE=tr.model.SCHEDULING_STATE;var sliceIdx=0;timeSlices.forEach(function(timeSlice){if(timeSlice.schedulingState==SCHEDULING_STATE.RUNNING){while(sliceIdx<this.topLevelSlices.length){if(this.addCpuTimeToSubslice_(this.topLevelSlices[sliceIdx],timeSlice)){sliceIdx++;}else{break;}}}},this);},addCpuTimeToSubslice_:function(slice,timeSlice){if(slice.start>timeSlice.end||slice.end<timeSlice.start)
+return slice.end<=timeSlice.end;var duration=timeSlice.duration;if(slice.start>timeSlice.start)
+duration-=slice.start-timeSlice.start;if(timeSlice.end>slice.end)
+duration-=timeSlice.end-slice.end;if(slice.cpuDuration){slice.cpuDuration+=duration;}else{slice.cpuDuration=duration;}
+for(var i=0;i<slice.subSlices.length;i++){this.addCpuTimeToSubslice_(slice.subSlices[i],timeSlice);}
+return slice.end<=timeSlice.end;}};SliceGroup.merge=function(groupA,groupB){if(groupA.openPartialSlices_.length>0)
+throw new Error('groupA has open partial slices');if(groupB.openPartialSlices_.length>0)
+throw new Error('groupB has open partial slices');if(groupA.parentContainer!=groupB.parentContainer)
+throw new Error('Different parent threads. Cannot merge');if(groupA.sliceConstructor!=groupB.sliceConstructor)
+throw new Error('Different slice constructors. Cannot merge');var result=new SliceGroup(groupA.parentContainer,groupA.sliceConstructor,groupA.name_);var slicesA=groupA.slices;var slicesB=groupB.slices;var idxA=0;var idxB=0;var openA=[];var openB=[];var splitOpenSlices=function(when){for(var i=0;i<openB.length;i++){var oldSlice=openB[i];var oldEnd=oldSlice.end;if(when<oldSlice.start||oldEnd<when){throw new Error('slice should not be split');}
+var newSlice=result.copySlice(oldSlice);newSlice.start=when;newSlice.duration=oldEnd-when;if(newSlice.title.indexOf(' (cont.)')==-1)
+newSlice.title+=' (cont.)';oldSlice.duration=when-oldSlice.start;openB[i]=newSlice;result.pushSlice(newSlice);}};var closeOpenSlices=function(upTo){while(openA.length>0||openB.length>0){var nextA=openA[openA.length-1];var nextB=openB[openB.length-1];var endA=nextA&&nextA.end;var endB=nextB&&nextB.end;if((endA===undefined||endA>upTo)&&(endB===undefined||endB>upTo)){return;}
+if(endB===undefined||endA<endB){splitOpenSlices(endA);openA.pop();}else{openB.pop();}}};while(idxA<slicesA.length||idxB<slicesB.length){var sA=slicesA[idxA];var sB=slicesB[idxB];var nextSlice,isFromB;if(sA===undefined||(sB!==undefined&&sA.start>sB.start)){nextSlice=result.copySlice(sB);isFromB=true;idxB++;}else{nextSlice=result.copySlice(sA);isFromB=false;idxA++;}
+closeOpenSlices(nextSlice.start);result.pushSlice(nextSlice);if(isFromB){openB.push(nextSlice);}else{splitOpenSlices(nextSlice.start);openA.push(nextSlice);}}
+closeOpenSlices();return result;};return{SliceGroup:SliceGroup};});'use strict';tr.exportTo('tr.model',function(){function AsyncSlice(category,title,colorId,start,args,duration,opt_isTopLevel,opt_cpuStart,opt_cpuDuration,opt_argsStripped){tr.model.TimedEvent.call(this,start);this.category=category||'';this.title=title;this.colorId=colorId;this.args=args;this.startStackFrame=undefined;this.endStackFrame=undefined;this.didNotFinish=false;this.important=false;this.subSlices=[];this.parentCo [...]
+this.cpuStart=opt_cpuStart;if(opt_cpuDuration!==undefined)
+this.cpuDuration=opt_cpuDuration;if(opt_argsStripped!==undefined)
+this.argsStripped=opt_argsStripped;};AsyncSlice.prototype={__proto__:tr.model.TimedEvent.prototype,get analysisTypeName(){return this.title;},get viewSubGroupTitle(){return this.title;},get userFriendlyName(){return'Async slice '+this.title+' at '+
+tr.b.units.tsString(this.start);},findDescendentSlice:function(targetTitle){if(!this.subSlices)
+return undefined;for(var i=0;i<this.subSlices.length;i++){if(this.subSlices[i].title==targetTitle)
+return this.subSlices[i];var slice=this.subSlices[i].findDescendentSlice(targetTitle);if(slice)return slice;}
+return undefined;},iterateAllDescendents:function(callback,opt_this){this.subSlices.forEach(callback,opt_this);this.subSlices.forEach(function(subSlice){subSlice.iterateAllDescendents(callback,opt_this);},opt_this);},compareTo:function(that){return this.title.localeCompare(that.title);}};tr.model.EventRegistry.register(AsyncSlice,{name:'asyncSlice',pluralName:'asyncSlices',singleViewElementName:'tr-ui-a-single-async-slice-sub-view',multiViewElementName:'tr-ui-a-multi-async-slice-sub-view [...]
+AsyncSliceGroup.prototype={__proto__:tr.model.EventContainer.prototype,get guid(){return this.guid_;},get parentContainer(){return this.parentContainer_;},get model(){return this.parentContainer_.parent.model;},get stableId(){return this.parentContainer_.stableId+'.AsyncSliceGroup';},getSettingsKey:function(){if(!this.name_)
+return undefined;var parentKey=this.parentContainer_.getSettingsKey();if(!parentKey)
+return undefined;return parentKey+'.'+this.name_;},push:function(slice){slice.parentContainer=this.parentContainer;this.slices.push(slice);return slice;},get length(){return this.slices.length;},shiftTimestampsForward:function(amount){for(var sI=0;sI<this.slices.length;sI++){var slice=this.slices[sI];slice.start=(slice.start+amount);var shiftSubSlices=function(subSlices){if(subSlices===undefined||subSlices.length===0)
+return;for(var sJ=0;sJ<subSlices.length;sJ++){subSlices[sJ].start+=amount;shiftSubSlices(subSlices[sJ].subSlices);}};shiftSubSlices(slice.subSlices);}},updateBounds:function(){this.bounds.reset();for(var i=0;i<this.slices.length;i++){this.bounds.addValue(this.slices[i].start);this.bounds.addValue(this.slices[i].end);}},get viewSubGroups(){if(this.viewSubGroups_===undefined){var prefix='';if(this.name!==undefined)
+prefix=this.name+'.';else
+prefix='';var subGroupsByTitle={};for(var i=0;i<this.slices.length;++i){var slice=this.slices[i];var subGroupTitle=slice.viewSubGroupTitle;if(!subGroupsByTitle[subGroupTitle]){subGroupsByTitle[subGroupTitle]=new AsyncSliceGroup(this.parentContainer_,prefix+subGroupTitle);}
+subGroupsByTitle[subGroupTitle].push(slice);}
+this.viewSubGroups_=tr.b.dictionaryValues(subGroupsByTitle);this.viewSubGroups_.sort(function(a,b){return a.slices[0].compareTo(b.slices[0]);});}
+return this.viewSubGroups_;},iterateAllEventsInThisContainer:function(eventTypePredicate,callback,opt_this){if(eventTypePredicate.call(opt_this,tr.model.AsyncSlice)){for(var i=0;i<this.slices.length;i++){var slice=this.slices[i];callback.call(opt_this,slice);if(slice.subSlices)
+slice.subSlices.forEach(callback,opt_this);}}},iterateAllChildEventContainers:function(callback,opt_this){}};return{AsyncSliceGroup:AsyncSliceGroup};});'use strict';tr.exportTo('tr.model',function(){var Slice=tr.model.Slice;var SliceGroup=tr.model.SliceGroup;var AsyncSlice=tr.model.AsyncSlice;var AsyncSliceGroup=tr.model.AsyncSliceGroup;var ThreadSlice=tr.model.ThreadSlice;var ThreadTimeSlice=tr.model.ThreadTimeSlice;function Thread(parent,tid){this.guid_=tr.b.GUID.allocate();if(!parent)
+throw new Error('Parent must be provided.');this.parent=parent;this.sortIndex=0;this.tid=tid;this.name=undefined;this.samples_=undefined;var that=this;this.sliceGroup=new SliceGroup(this,ThreadSlice,'slices');this.timeSlices=undefined;this.kernelSliceGroup=new SliceGroup(this,ThreadSlice,'kernel-slices');this.asyncSliceGroup=new AsyncSliceGroup(this,'async-slices');this.bounds=new tr.b.Range();}
+Thread.prototype={__proto__:tr.model.EventContainer.prototype,get guid(){return this.guid_;},get model(){return this.parent.model;},get stableId(){return this.parent.stableId+'.'+this.tid;},compareTo:function(that){return Thread.compare(this,that);},iterateAllChildEventContainers:function(callback,opt_this){if(this.sliceGroup.length)
+callback.call(opt_this,this.sliceGroup);if(this.kernelSliceGroup.length)
+callback.call(opt_this,this.kernelSliceGroup);if(this.asyncSliceGroup.length)
+callback.call(opt_this,this.asyncSliceGroup);},iterateAllEventsInThisContainer:function(eventTypePredicate,callback,opt_this){if(this.timeSlices&&this.timeSlices.length){if(eventTypePredicate.call(opt_this,ThreadTimeSlice))
+this.timeSlices.forEach(callback,opt_this);}},iterateAllPersistableObjects:function(cb){cb(this);if(this.sliceGroup.length)
+cb(this.sliceGroup);this.asyncSliceGroup.viewSubGroups.forEach(cb);},shiftTimestampsForward:function(amount){this.sliceGroup.shiftTimestampsForward(amount);if(this.timeSlices){for(var i=0;i<this.timeSlices.length;i++){var slice=this.timeSlices[i];slice.start+=amount;}}
+this.kernelSliceGroup.shiftTimestampsForward(amount);this.asyncSliceGroup.shiftTimestampsForward(amount);},get isEmpty(){if(this.sliceGroup.length)
+return false;if(this.sliceGroup.openSliceCount)
+return false;if(this.timeSlices&&this.timeSlices.length)
+return false;if(this.kernelSliceGroup.length)
+return false;if(this.asyncSliceGroup.length)
+return false;if(this.samples_.length)
+return false;return true;},updateBounds:function(){this.bounds.reset();this.sliceGroup.updateBounds();this.bounds.addRange(this.sliceGroup.bounds);this.kernelSliceGroup.updateBounds();this.bounds.addRange(this.kernelSliceGroup.bounds);this.asyncSliceGroup.updateBounds();this.bounds.addRange(this.asyncSliceGroup.bounds);if(this.timeSlices&&this.timeSlices.length){this.bounds.addValue(this.timeSlices[0].start);this.bounds.addValue(this.timeSlices[this.timeSlices.length-1].end);}
+if(this.samples_&&this.samples_.length){this.bounds.addValue(this.samples_[0].start);this.bounds.addValue(this.samples_[this.samples_.length-1].end);}},addCategoriesToDict:function(categoriesDict){for(var i=0;i<this.sliceGroup.length;i++)
+categoriesDict[this.sliceGroup.slices[i].category]=true;for(var i=0;i<this.kernelSliceGroup.length;i++)
+categoriesDict[this.kernelSliceGroup.slices[i].category]=true;for(var i=0;i<this.asyncSliceGroup.length;i++)
+categoriesDict[this.asyncSliceGroup.slices[i].category]=true;if(this.samples_){for(var i=0;i<this.samples_.length;i++)
+categoriesDict[this.samples_[i].category]=true;}},autoCloseOpenSlices:function(opt_maxTimestamp){this.sliceGroup.autoCloseOpenSlices(opt_maxTimestamp);this.kernelSliceGroup.autoCloseOpenSlices(opt_maxTimestamp);},mergeKernelWithUserland:function(){if(this.kernelSliceGroup.length>0){var newSlices=SliceGroup.merge(this.sliceGroup,this.kernelSliceGroup);this.sliceGroup.slices=newSlices.slices;this.kernelSliceGroup=new SliceGroup(this);this.updateBounds();}},createSubSlices:function(){this.s [...]
+(this.name?', name: '+this.name:'');},getSettingsKey:function(){if(!this.name)
+return undefined;var parentKey=this.parent.getSettingsKey();if(!parentKey)
+return undefined;return parentKey+'.'+this.name;},indexOfTimeSlice:function(timeSlice){var i=tr.b.findLowIndexInSortedArray(this.timeSlices,function(slice){return slice.start;},timeSlice.start);if(this.timeSlices[i]!==timeSlice)
+return undefined;return i;},getSchedulingStatsForRange:function(start,end){var stats={};if(!this.timeSlices)return stats;function addStatsForSlice(threadTimeSlice){var overlapStart=Math.max(threadTimeSlice.start,start);var overlapEnd=Math.min(threadTimeSlice.end,end);var schedulingState=threadTimeSlice.schedulingState;if(!(schedulingState in stats))
+stats[schedulingState]=0;stats[schedulingState]+=overlapEnd-overlapStart;}
+tr.b.iterateOverIntersectingIntervals(this.timeSlices,function(x){return x.start;},function(x){return x.end;},start,end,addStatsForSlice);return stats;},get samples(){return this.samples_;}};Thread.compare=function(x,y){var tmp=x.parent.compareTo(y.parent);if(tmp)
+return tmp;tmp=x.sortIndex-y.sortIndex;if(tmp)
+return tmp;tmp=tr.b.comparePossiblyUndefinedValues(x.name,y.name,function(x,y){return x.localeCompare(y);});if(tmp)
+return tmp;return x.tid-y.tid;};return{Thread:Thread};});'use strict';tr.exportTo('tr.model',function(){var Thread=tr.model.Thread;var Counter=tr.model.Counter;function ProcessBase(model){if(!model)
+throw new Error('Must provide a model');tr.model.EventContainer.call(this);this.guid_=tr.b.GUID.allocate();this.model=model;this.threads={};this.counters={};this.objects=new tr.model.ObjectCollection(this);this.bounds=new tr.b.Range();this.sortIndex=0;};ProcessBase.compare=function(x,y){return x.sortIndex-y.sortIndex;};ProcessBase.prototype={__proto__:tr.model.EventContainer.prototype,get guid(){return this.guid_;},get stableId(){throw new Error('Not implemented');},iterateAllChildEventC [...]
+callback.call(opt_this,this.threads[tid]);for(var id in this.counters)
+callback.call(opt_this,this.counters[id]);callback.call(opt_this,this.objects);},iterateAllEventsInThisContainer:function(eventTypePredicate,callback,opt_this){},iterateAllPersistableObjects:function(cb){cb(this);for(var tid in this.threads)
+this.threads[tid].iterateAllPersistableObjects(cb);},get numThreads(){var n=0;for(var p in this.threads){n++;}
+return n;},shiftTimestampsForward:function(amount){for(var tid in this.threads)
+this.threads[tid].shiftTimestampsForward(amount);for(var id in this.counters)
+this.counters[id].shiftTimestampsForward(amount);this.objects.shiftTimestampsForward(amount);},autoCloseOpenSlices:function(opt_maxTimestamp){for(var tid in this.threads){var thread=this.threads[tid];thread.autoCloseOpenSlices(opt_maxTimestamp);}},autoDeleteObjects:function(maxTimestamp){this.objects.autoDeleteObjects(maxTimestamp);},preInitializeObjects:function(){this.objects.preInitializeAllObjects();},initializeObjects:function(){this.objects.initializeAllObjects();},mergeKernelWithU [...]
+for(var id in this.counters){this.counters[id].updateBounds();this.bounds.addRange(this.counters[id].bounds);}
+this.objects.updateBounds();this.bounds.addRange(this.objects.bounds);},addCategoriesToDict:function(categoriesDict){for(var tid in this.threads)
+this.threads[tid].addCategoriesToDict(categoriesDict);for(var id in this.counters)
+categoriesDict[this.counters[id].category]=true;this.objects.addCategoriesToDict(categoriesDict);},findAllThreadsMatching:function(predicate,opt_this){var threads=[];for(var tid in this.threads){var thread=this.threads[tid];if(predicate.call(opt_this,thread))
+threads.push(thread);}
+return threads;},findAllThreadsNamed:function(name){var threads=this.findAllThreadsMatching(function(thread){if(!thread.name)
+return false;return thread.name===name;});return threads;},findAtMostOneThreadNamed:function(name){var threads=this.findAllThreadsNamed(name);if(threads.length===0)
+return undefined;if(threads.length>1)
+throw new Error('Expected no more than one '+name);return threads[0];},pruneEmptyContainers:function(){var threadsToKeep={};for(var tid in this.threads){var thread=this.threads[tid];if(!thread.isEmpty)
+threadsToKeep[tid]=thread;}
+this.threads=threadsToKeep;},getThread:function(tid){return this.threads[tid];},getOrCreateThread:function(tid){if(!this.threads[tid])
+this.threads[tid]=new Thread(this,tid);return this.threads[tid];},getOrCreateCounter:function(cat,name){var id=cat+'.'+name;if(!this.counters[id])
+this.counters[id]=new Counter(this,id,cat,name);return this.counters[id];},getSettingsKey:function(){throw new Error('Not implemented');},createSubSlices:function(){for(var tid in this.threads)
+this.threads[tid].createSubSlices();}};return{ProcessBase:ProcessBase};});'use strict';tr.exportTo('tr.model',function(){var Cpu=tr.model.Cpu;var ProcessBase=tr.model.ProcessBase;function Kernel(model){ProcessBase.call(this,model);this.cpus={};this.softwareMeasuredCpuCount_=undefined;};Kernel.compare=function(x,y){return 0;};Kernel.prototype={__proto__:ProcessBase.prototype,compareTo:function(that){return Kernel.compare(this,that);},get userFriendlyName(){return'Kernel';},get userFriendl [...]
+this.cpus[cpuNumber]=new Cpu(this,cpuNumber);return this.cpus[cpuNumber];},get softwareMeasuredCpuCount(){return this.softwareMeasuredCpuCount_;},set softwareMeasuredCpuCount(softwareMeasuredCpuCount){if(this.softwareMeasuredCpuCount_!==undefined&&this.softwareMeasuredCpuCount_!==softwareMeasuredCpuCount){throw new Error('Cannot change the softwareMeasuredCpuCount once it is set');}
+this.softwareMeasuredCpuCount_=softwareMeasuredCpuCount;},get bestGuessAtCpuCount(){var realCpuCount=tr.b.dictionaryLength(this.cpus);if(realCpuCount!==0)
+return realCpuCount;return this.softwareMeasuredCpuCount;},shiftTimestampsForward:function(amount){ProcessBase.prototype.shiftTimestampsForward.call(this,amount);for(var cpuNumber in this.cpus)
+this.cpus[cpuNumber].shiftTimestampsForward(amount);},updateBounds:function(){ProcessBase.prototype.updateBounds.call(this);for(var cpuNumber in this.cpus){var cpu=this.cpus[cpuNumber];cpu.updateBounds();this.bounds.addRange(cpu.bounds);}},createSubSlices:function(){ProcessBase.prototype.createSubSlices.call(this);for(var cpuNumber in this.cpus){var cpu=this.cpus[cpuNumber];cpu.createSubSlices();}},addCategoriesToDict:function(categoriesDict){ProcessBase.prototype.addCategoriesToDict.cal [...]
+this.cpus[cpuNumber].addCategoriesToDict(categoriesDict);},getSettingsKey:function(){return'kernel';},iterateAllChildEventContainers:function(callback,opt_this){ProcessBase.prototype.iterateAllChildEventContainers.call(this,callback,opt_this);for(var cpuId in this.cpus)
+callback.call(opt_this,this.cpus[cpuId]);},iterateAllEventsInThisContainer:function(eventTypePredicate,callback,opt_this){ProcessBase.prototype.iterateAllEventsInThisContainer.call(this,eventTypePredicate,callback,opt_this);}};return{Kernel:Kernel};});'use strict';tr.exportTo('tr.model',function(){function Attribute(units){this.units=units;this.infos=[];}
+Attribute.fromDictIfPossible=function(dict,opt_model){var typeInfo=Attribute.findTypeInfoMatching(function(typeInfo){return typeInfo.metadata.type===dict.type;});if(typeInfo===undefined){if(opt_model){opt_model.importWarning({type:'attribute_parse_error',message:'Unknown attribute type \''+dict.type+'\'.'});}
+return UnknownAttribute.fromDict(dict,opt_model);}
+return typeInfo.constructor.fromDict(dict,opt_model);};Attribute.findCommonTraits=function(attributes,opt_model){var commonTraits;for(var i=0;i<attributes.length;i++){var attribute=attributes[i];if(attribute===undefined)
+continue;var attributeConstructor=attribute.constructor;var attributeUnits=attribute.units;if(commonTraits===undefined){commonTraits={constructor:attributeConstructor,units:attributeUnits};}else if(attributeConstructor!==commonTraits.constructor){if(opt_model){opt_model.importWarning({type:'attribute_parse_error',message:'Attribute with different types: '+
+commonTraits.constructor+' and '+attributeConstructor+'.'});}
+commonTraits={constructor:UnknownAttribute,units:undefined};break;}else if(attributeUnits!==commonTraits.units){if(opt_model){opt_model.importWarning({type:'attribute_parse_error',message:'Attribute with different units: '+commonTraits.units+' and '+attributeUnits+'.'});}
+commonTraits={constructor:UnknownAttribute,units:undefined};break;}}
+return commonTraits;};Attribute.aggregate=function(childAttributes,existingParentAttribute,opt_model){var definedChildAttributes=childAttributes.filter(function(childAttribute){return childAttribute!==undefined;});var traits=Attribute.findCommonTraits(definedChildAttributes,opt_model);if(traits===undefined)
+return existingParentAttribute;var constructor=traits.constructor;if(constructor.merge===undefined)
+return existingParentAttribute;var mergedAttribute=constructor.merge(definedChildAttributes,traits.units,opt_model);if(existingParentAttribute===undefined)
+return mergedAttribute;existingParentAttribute.useMergedAttribute(mergedAttribute,opt_model);return existingParentAttribute;}
+Attribute.fromTraceValue=function(dict,opt_model){throw new Error('Not implemented');};Attribute.prototype.useMergedAttribute=function(mergedAttribute,opt_model){if(mergedAttribute.constructor!==this.constructor){if(opt_model){opt_model.importWarning({type:'attribute_parse_error',message:'Attribute with different types: '+this.constructor+' and '+mergedAttribute.constructor+'.'});}}else if(mergedAttribute.units!==this.units){if(opt_model){opt_model.importWarning({type:'attribute_parse_er [...]
+throw new Error('Attributes must have fromDict method');if(!e.typeInfo.metadata.type)
+throw new Error('Attributes must provide type');if(e.typeInfo.constructor.prototype.constructor!==e.typeInfo.constructor)
+throw new Error('Attribute prototypes must provide constructor.');});function ScalarAttribute(units,value){Attribute.call(this,units);this.value=value;}
+ScalarAttribute.fromDict=function(dict){return new ScalarAttribute(dict.units,parseInt(dict.value,16));};ScalarAttribute.merge=function(childAttributes,units){var sum=0;childAttributes.forEach(function(childAttribute){sum+=childAttribute.value;});return new ScalarAttribute(units,sum);}
+ScalarAttribute.prototype.__proto__=Attribute.prototype;Attribute.register(ScalarAttribute,{type:'scalar'});function StringAttribute(units,value){Attribute.call(this,units);this.value=value;}
+StringAttribute.fromDict=function(dict){return new StringAttribute(dict.units,dict.value);};Attribute.register(StringAttribute,{type:'string'});function UnknownAttribute(units,opt_value){Attribute.call(this,units,opt_value);this.value=opt_value;}
+UnknownAttribute.fromDict=function(dict){return new UnknownAttribute(dict.units);};UnknownAttribute.prototype.__proto__=Attribute.prototype;function AttributeInfo(type,message){this.type=type;this.message=message;}
+var AttributeInfoType={INFORMATION:0,WARNING:1,LINK:2};return{Attribute:Attribute,ScalarAttribute:ScalarAttribute,StringAttribute:StringAttribute,UnknownAttribute:UnknownAttribute,AttributeInfo:AttributeInfo,AttributeInfoType:AttributeInfoType};});'use strict';tr.exportTo('tr.model',function(){function ContainerMemoryDump(start){tr.model.TimedEvent.call(this,start);this.memoryAllocatorDumps_=undefined;this.memoryAllocatorDumpsByFullName_=undefined;};ContainerMemoryDump.prototype={__proto [...]
+return undefined;if(this.memoryAllocatorDumpsByFullName_===undefined){var index={};function addDumpsToIndex(dumps){dumps.forEach(function(dump){index[dump.fullName]=dump;addDumpsToIndex(dump.children);});};addDumpsToIndex(this.memoryAllocatorDumps_);this.memoryAllocatorDumpsByFullName_=index;}
+return this.memoryAllocatorDumpsByFullName_[fullName];}};return{ContainerMemoryDump:ContainerMemoryDump};});'use strict';tr.exportTo('tr.model',function(){function MemoryAllocatorDump(containerMemoryDump,fullName,opt_guid){this.fullName=fullName;this.parent=undefined;this.children=[];this.attributes={};this.containerMemoryDump=containerMemoryDump;this.owns=undefined;this.ownedBy=[];this.retains=[];this.retainedBy=[];this.guid=opt_guid;};MemoryAllocatorDump.prototype={get name(){return th [...]
+return true;dump=dump.parent;}
+return false;},addAttribute:function(name,value){if(name in this.attributes)
+throw new Error('Duplicate attribute name: '+name+'.');this.attributes[name]=value;},aggregateAttributes:function(opt_model){var attributes={};this.children.forEach(function(child){child.aggregateAttributes(opt_model);tr.b.iterItems(child.attributes,function(name){attributes[name]=true;},this);},this);tr.b.iterItems(attributes,function(name){var childAttributes=this.children.map(function(child){return child.attributes[name];},this);var currentAttribute=this.attributes[name];this.attribut [...]
+return undefined;if(!(sizeAttr instanceof tr.model.ScalarAttribute)){if(opt_model!==undefined){opt_model.importWarning({type:'memory_dump_parse_error',message:'\''+sizeAttrName+'\' attribute of memory allocator '+'dump \''+memoryAllocatorDump.fullName+'\' is not a scalar.'});}
+return undefined;}
+return sizeAttr;}};function MemoryAllocatorDumpLink(source,target,opt_importance){this.source=source;this.target=target;this.importance=opt_importance;}
+return{MemoryAllocatorDump:MemoryAllocatorDump,MemoryAllocatorDumpLink:MemoryAllocatorDumpLink};});'use strict';tr.exportTo('tr.model',function(){var DISCOUNTED_ALLOCATOR_NAMES=['winheap','malloc'];function ProcessMemoryDump(globalMemoryDump,process,start){tr.model.ContainerMemoryDump.call(this,start);this.process=process;this.globalMemoryDump=globalMemoryDump;this.totalResidentBytes=undefined;this.vmRegions_=undefined;this.tracingMemoryDiscounted_=false;};ProcessMemoryDump.prototype={__ [...]
+return undefined;var total=0;this.mostRecentVmRegions.forEach(function(vmRegion){var statValue=vmRegion.byteStats[statName];if(statValue===undefined)
+return;total+=statValue;});return total;},discountTracingOverhead:function(opt_model){if(this.tracingMemoryDiscounted_)
+return;this.tracingMemoryDiscounted_=true;var tracingDump=this.getMemoryAllocatorDumpByFullName('tracing');if(tracingDump===undefined)
+return;var tracingResidentSizeAttr=tracingDump.getValidSizeAttributeOrUndefined('resident_size',opt_model);if(tracingResidentSizeAttr!==undefined){var tracingResidentSize=tracingResidentSizeAttr.value;if(this.totalResidentBytes!==undefined)
+this.totalResidentBytes-=tracingResidentSize;if(this.vmRegions_!==undefined){this.vmRegions_.push(VMRegion.fromDict({mappedFile:'[discounted tracing overhead]',byteStats:{privateDirtyResident:-tracingResidentSize,proportionalResident:-tracingResidentSize}}));}}
+var tracingSizeAttr=tracingDump.getValidSizeAttributeOrUndefined('size',opt_model);if(tracingSizeAttr!==undefined){var tracingSize=tracingSizeAttr.value;var hasDiscountedFromAllocatorDumps=DISCOUNTED_ALLOCATOR_NAMES.some(function(allocatorName){var dump=this.getMemoryAllocatorDumpByFullName(allocatorName);if(dump===undefined)
+return false;var overheadSizeAttribute=new tr.model.ScalarAttribute('bytes',-tracingSize);var overheadDump=new tr.model.MemoryAllocatorDump(this,allocatorName+'/discounted_tracing_overhead');overheadDump.parent=dump;overheadDump.addAttribute('size',overheadSizeAttribute);dump.children.push(overheadDump);var dumpSizeAttr=dump.getValidSizeAttributeOrUndefined('size',opt_model);if(dumpSizeAttr!==undefined)
+dumpSizeAttr.value-=tracingSize;return true;},this);if(hasDiscountedFromAllocatorDumps)
+this.memoryAllocatorDumps=this.memoryAllocatorDumps;}}};ProcessMemoryDump.hookUpMostRecentVmRegionsLinks=function(processDumps){var mostRecentVmRegions=undefined;processDumps.forEach(function(processDump){if(processDump.vmRegions_!==undefined)
+mostRecentVmRegions=processDump.vmRegions_;processDump.mostRecentVmRegions=mostRecentVmRegions;});};function VMRegion(startAddress,sizeInBytes,protectionFlags,mappedFile,byteStats){this.startAddress=startAddress;this.sizeInBytes=sizeInBytes;this.protectionFlags=protectionFlags;this.mappedFile=mappedFile;this.byteStats=byteStats;};VMRegion.PROTECTION_FLAG_READ=4;VMRegion.PROTECTION_FLAG_WRITE=2;VMRegion.PROTECTION_FLAG_EXECUTE=1;VMRegion.prototype={get protectionFlagsToString(){if(this.pr [...]
+return undefined;return((this.protectionFlags&VMRegion.PROTECTION_FLAG_READ?'r':'-')+
+(this.protectionFlags&VMRegion.PROTECTION_FLAG_WRITE?'w':'-')+
+(this.protectionFlags&VMRegion.PROTECTION_FLAG_EXECUTE?'x':'-'));}};VMRegion.fromDict=function(dict){return new VMRegion(dict.startAddress,dict.sizeInBytes,dict.protectionFlags,dict.mappedFile,VMRegionByteStats.fromDict(dict.byteStats));};function VMRegionByteStats(privateCleanResident,privateDirtyResident,sharedCleanResident,sharedDirtyResident,proportionalResident,swapped){this.privateCleanResident=privateCleanResident;this.privateDirtyResident=privateDirtyResident;this.sharedCleanResi [...]
+VMRegionByteStats.fromDict=function(dict){return new VMRegionByteStats(dict.privateCleanResident,dict.privateDirtyResident,dict.sharedCleanResident,dict.sharedDirtyResident,dict.proportionalResident,dict.swapped);}
+tr.model.EventRegistry.register(ProcessMemoryDump,{name:'processMemoryDump',pluralName:'processMemoryDumps',singleViewElementName:'tr-ui-a-single-process-memory-dump-sub-view',multiViewElementName:'tr-ui-a-multi-process-memory-dump-sub-view'});return{ProcessMemoryDump:ProcessMemoryDump,VMRegion:VMRegion,VMRegionByteStats:VMRegionByteStats};});'use strict';tr.exportTo('tr.model',function(){var ProcessBase=tr.model.ProcessBase;var ProcessInstantEvent=tr.model.ProcessInstantEvent;var Frame= [...]
+throw new Error('model must be provided');if(pid===undefined)
+throw new Error('pid must be provided');tr.model.ProcessBase.call(this,model);this.pid=pid;this.name=undefined;this.labels=[];this.instantEvents=[];this.memoryDumps=[];this.frames=[];};Process.compare=function(x,y){var tmp=tr.model.ProcessBase.compare(x,y);if(tmp)
+return tmp;tmp=tr.b.comparePossiblyUndefinedValues(x.name,y.name,function(x,y){return x.localeCompare(y);});if(tmp)
+return tmp;tmp=tr.b.compareArrays(x.labels,y.labels,function(x,y){return x.localeCompare(y);});if(tmp)
+return tmp;return x.pid-y.pid;};Process.prototype={__proto__:tr.model.ProcessBase.prototype,get stableId(){return this.pid;},compareTo:function(that){return Process.compare(this,that);},iterateAllChildEventContainers:function(callback,opt_this){ProcessBase.prototype.iterateAllChildEventContainers.call(this,callback,opt_this);},iterateAllEventsInThisContainer:function(eventTypePredicate,callback,opt_this){ProcessBase.prototype.iterateAllEventsInThisContainer.call(this,eventTypePredicate,c [...]
+this.instantEvents.forEach(callback,opt_this);if(eventTypePredicate.call(opt_this,Frame))
+this.frames.forEach(callback,opt_this);if(eventTypePredicate.call(opt_this,ProcessMemoryDump))
+this.memoryDumps.forEach(callback,opt_this);},pushInstantEvent:function(instantEvent){this.instantEvents.push(instantEvent);},addLabelIfNeeded:function(labelName){for(var i=0;i<this.labels.length;i++){if(this.labels[i]===labelName)
+return;}
+this.labels.push(labelName);},get userFriendlyName(){var res;if(this.name)
+res=this.name+' (pid '+this.pid+')';else
+res='Process '+this.pid;if(this.labels.length)
+res+=': '+this.labels.join(', ');return res;},get userFriendlyDetails(){if(this.name)
+return this.name+' (pid '+this.pid+')';return'pid: '+this.pid;},getSettingsKey:function(){if(!this.name)
+return undefined;if(!this.labels.length)
+return'processes.'+this.name;return'processes.'+this.name+'.'+this.labels.join('.');},shiftTimestampsForward:function(amount){for(var id in this.instantEvents)
+this.instantEvents[id].start+=amount;for(var i=0;i<this.frames.length;i++)
+this.frames[i].shiftTimestampsForward(amount);for(var i=0;i<this.memoryDumps.length;i++)
+this.memoryDumps[i].shiftTimestampsForward(amount);tr.model.ProcessBase.prototype.shiftTimestampsForward.apply(this,arguments);},updateBounds:function(){tr.model.ProcessBase.prototype.updateBounds.apply(this);for(var i=0;i<this.frames.length;i++)
+this.frames[i].addBoundsToRange(this.bounds);for(var i=0;i<this.memoryDumps.length;i++)
+this.memoryDumps[i].addBoundsToRange(this.bounds);},sortMemoryDumps:function(){this.memoryDumps.sort(function(x,y){return x.start-y.start;});tr.model.ProcessMemoryDump.hookUpMostRecentVmRegionsLinks(this.memoryDumps);}};return{Process:Process};});'use strict';tr.exportTo('tr.model',function(){function Sample(cpu,thread,title,start,leafStackFrame,opt_weight,opt_args){tr.model.TimedEvent.call(this,start);this.title=title;this.cpu=cpu;this.thread=thread;this.leafStackFrame=leafStackFrame;th [...]
+Sample.prototype={__proto__:tr.model.TimedEvent.prototype,get colorId(){return this.leafStackFrame.colorId;},get stackTrace(){return this.leafStackFrame.stackTrace;},getUserFriendlyStackTrace:function(){return this.leafStackFrame.getUserFriendlyStackTrace();},get userFriendlyName(){return'Sample '+' at '+
+tr.b.units.tsString(this.start);}};tr.model.EventRegistry.register(Sample,{name:'sample',pluralName:'samples',singleViewElementName:'tr-ui-a-single-sample-sub-view',multiViewElementName:'tr-ui-a-multi-sample-sub-view'});return{Sample:Sample};});'use strict';tr.exportTo('tr.model',function(){function StackFrame(parentFrame,id,category,title,colorId){if(id===undefined)
+throw new Error('id must be given');this.parentFrame_=parentFrame;this.id=id;this.category=category||'';this.title=title;this.colorId=colorId;this.children=[];if(this.parentFrame_)
+this.parentFrame_.addChild(this);}
+StackFrame.prototype={get parentFrame(){return this.parentFrame_;},set parentFrame(parentFrame){if(this.parentFrame_)
+this.parentFrame_.removeChild(this);this.parentFrame_=parentFrame;if(this.parentFrame_)
+this.parentFrame_.addChild(this);},addChild:function(child){this.children.push(child);},removeChild:function(child){var i=this.children.indexOf(child.id);if(i==-1)
+throw new Error('omg');this.children.splice(i,1);},removeAllChildren:function(){for(var i=0;i<this.children.length;i++)
+this.children[i].parentFrame_=undefined;this.children.splice(0,this.children.length);},get stackTrace(){var stack=[];var cur=this;while(cur){stack.push(cur);cur=cur.parentFrame;}
+stack.reverse();return stack;},getUserFriendlyStackTrace:function(){return this.stackTrace.map(function(x){return x.category+': '+x.title;});}};return{StackFrame:StackFrame};});'use strict';tr.exportTo('tr.model',function(){var InstantEventType={GLOBAL:1,PROCESS:2};function InstantEvent(category,title,colorId,start,args){tr.model.TimedEvent.call(this);this.category=category||'';this.title=title;this.colorId=colorId;this.start=start;this.args=args;this.type=undefined;};InstantEvent.protot [...]
+this.tsString(start);}};function ProcessInstantEvent(category,title,colorId,start,args){InstantEvent.apply(this,arguments);this.type=InstantEventType.PROCESS;};ProcessInstantEvent.prototype={__proto__:InstantEvent.prototype,get userFriendlyName(){return'Process-level instant event '+this.title+' @ '+
+this.tsString(start);}};tr.model.EventRegistry.register(InstantEvent,{name:'instantEvent',pluralName:'instantEvents',singleViewElementName:'tr-ui-a-single-instant-event-sub-view',multiViewElementName:'tr-ui-a-multi-instant-event-sub-view'});return{GlobalInstantEvent:GlobalInstantEvent,ProcessInstantEvent:ProcessInstantEvent,InstantEventType:InstantEventType,InstantEvent:InstantEvent};});'use strict';tr.exportTo('tr.model',function(){function FlowEvent(category,id,title,colorId,start,args [...]
+this.duration=opt_duration;}
+FlowEvent.prototype={__proto__:tr.model.TimedEvent.prototype,get userFriendlyName(){return'Flow event named '+this.title+' at '+
+tr.b.units.tsString(this.timestamp);}};tr.model.EventRegistry.register(FlowEvent,{name:'flowEvent',pluralName:'flowEvents',singleViewElementName:'tr-ui-a-single-flow-event-sub-view',multiViewElementName:'tr-ui-a-multi-flow-event-sub-view'});return{FlowEvent:FlowEvent};});'use strict';tr.exportTo('tr.b.units',function(){var UNIT_PREFIXES=['','Ki','Mi','Gi','Ti'];function SizeInBytes(numBytes){this.numBytes=numBytes;};SizeInBytes.prototype={toString:function(){return SizeInBytes.format(thi [...]
+var i=0;while(numBytes>=1024&&i<UNIT_PREFIXES.length-1){numBytes/=1024;i++;}
+return signPrefix+numBytes.toFixed(1)+' '+UNIT_PREFIXES[i]+'B';};return{SizeInBytes:SizeInBytes};});'use strict';tr.exportTo('tr.model',function(){function GlobalMemoryDump(model,start){tr.model.ContainerMemoryDump.call(this,start);this.model=model;this.processMemoryDumps={};}
+var SIZE_ATTRIBUTE_NAME='size';GlobalMemoryDump.prototype={__proto__:tr.model.ContainerMemoryDump.prototype,get userFriendlyName(){return'Global memory dump at '+tr.b.units.tsString(this.start);},calculateGraphAttributes:function(){this.calculateSizes();this.aggregateAttributes();this.discountTracingOverhead();},calculateSizes:function(){this.traverseAllocatorDumpsInDepthFirstPostOrder(this.calculateMemoryAllocatorDumpSize_);},calculateMemoryAllocatorDumpSize_:function(dump){var shouldDe [...]
+return 0;shouldDefineSize=true;return attr.value;}
+var sizeAttribute=dump.getValidSizeAttributeOrUndefined(SIZE_ATTRIBUTE_NAME,this.model);var size=0;var infos=[];var checkDependentSizeIsConsistent=function(){};if(sizeAttribute!==undefined){size=sizeAttribute.value;shouldDefineSize=true;checkDependentSizeIsConsistent=function(dependentSize,dependentName){if(size>=dependentSize)
+return;var messageSuffix=' ('+tr.b.units.SizeInBytes.format(size)+') is less than '+dependentName+' ('+
+tr.b.units.SizeInBytes.format(dependentSize)+').';this.model.importWarning({type:'memory_dump_parse_error',message:'Size provided by memory allocator dump \''+
+dump.fullName+'\''+messageSuffix});infos.push(new tr.model.AttributeInfo(tr.model.AttributeInfoType.WARNING,'Size provided by this memory allocator dump'+messageSuffix));}.bind(this);}
+var aggregatedChildrenSize=0;var allOverlaps={};dump.children.forEach(function(childDump){function aggregateDescendantDump(descendantDump){var ownedDumpLink=descendantDump.owns;if(ownedDumpLink!==undefined&&ownedDumpLink.target.isDescendantOf(dump)){var ownedDescendantDump=ownedDumpLink.target;var ownedChildDump=ownedDescendantDump;while(ownedChildDump.parent!==dump)
+ownedChildDump=ownedChildDump.parent;if(childDump!==ownedChildDump){var overlap=getDependencySize(descendantDump);if(overlap>0){var ownedChildOverlaps=allOverlaps[ownedChildDump.name];if(ownedChildOverlaps===undefined)
+allOverlaps[ownedChildDump.name]=ownedChildOverlaps={};var previousTotalOverlap=ownedChildOverlaps[childDump.name]||0;var updatedTotalOverlap=previousTotalOverlap+overlap;ownedChildOverlaps[childDump.name]=updatedTotalOverlap;}}
+return;}
+if(descendantDump.children.length===0){aggregatedChildrenSize+=getDependencySize(descendantDump);return;}
+descendantDump.children.forEach(aggregateDescendantDump);}
+aggregateDescendantDump(childDump);});dump.children.forEach(function(childDump){var childOverlaps=allOverlaps[childDump.name];if(childOverlaps===undefined)
+return;var message=tr.b.dictionaryValues(tr.b.mapItems(childOverlaps,function(ownerChildName,overlap){return'This memory allocator dump overlaps with its sibling \''+
+ownerChildName+'\' ('+
+tr.b.units.SizeInBytes.format(overlap)+').';})).join(' ');childDump.attributes[SIZE_ATTRIBUTE_NAME].infos.push(new tr.model.AttributeInfo(tr.model.AttributeInfoType.INFORMATION,message));});checkDependentSizeIsConsistent(aggregatedChildrenSize,'the aggregated size of its children');var largestOwnerSize=0;dump.ownedBy.forEach(function(ownershipLink){var owner=ownershipLink.source;var ownerSize=getDependencySize(owner);largestOwnerSize=Math.max(largestOwnerSize,ownerSize);});checkDependent [...]
+size=Math.max(size,aggregatedChildrenSize,largestOwnerSize);var sizeAttribute=new tr.model.ScalarAttribute('bytes',size);sizeAttribute.infos=infos;dump.attributes[SIZE_ATTRIBUTE_NAME]=sizeAttribute;if(aggregatedChildrenSize<size&&dump.children!==undefined&&dump.children.length>0){var virtualChild=new tr.model.MemoryAllocatorDump(dump.containerMemoryDump,dump.fullName+'/<unspecified>');virtualChild.parent=dump;dump.children.unshift(virtualChild);virtualChild.attributes[SIZE_ATTRIBUTE_NAME [...]
+return;memoryAllocatorDumps.forEach(fn,this);});},traverseAllocatorDumpsInDepthFirstPostOrder:function(fn){var visitedDumps=new WeakSet();var openDumps=new WeakSet();function visit(dump){if(visitedDumps.has(dump))
+return;if(openDumps.has(dump))
+throw new Error(dump.userFriendlyName+' contains a cycle');openDumps.add(dump);dump.ownedBy.forEach(function(ownershipLink){visit.call(this,ownershipLink.source);},this);dump.children.forEach(visit,this);fn.call(this,dump);openDumps.delete(dump);visitedDumps.add(dump);}
+this.iterateRootAllocatorDumps(visit);}};tr.model.EventRegistry.register(GlobalMemoryDump,{name:'globalMemoryDump',pluralName:'globalMemoryDumps',singleViewElementName:'tr-ui-a-single-global-memory-dump-sub-view',multiViewElementName:'tr-ui-a-multi-global-memory-dump-sub-view'});return{GlobalMemoryDump:GlobalMemoryDump};});'use strict';tr.exportTo('tr.model',function(){function EventInfo(title,description,docLinks){this.title=title;this.description=description;this.docLinks=docLinks;this [...]
+return{EventInfo:EventInfo};});'use strict';tr.exportTo('tr.model',function(){function Alert(info,start,opt_associatedEvents,opt_args){tr.model.TimedEvent.call(this,start);this.info=info;this.args=opt_args||{};this.associatedEvents=new tr.c.Selection(opt_associatedEvents);this.associatedEvents.forEach(function(event){event.associatedAlerts.push(this);},this);}
+Alert.prototype={__proto__:tr.model.TimedEvent.prototype,get title(){return this.info.title;},get colorId(){return this.info.colorId;},get userFriendlyName(){return'Alert '+this.title+' at '+
+tr.b.units.tsString(this.start);}};tr.model.EventRegistry.register(Alert,{name:'alert',pluralName:'alerts',singleViewElementName:'tr-ui-a-alert-sub-view',multiViewElementName:'tr-ui-a-alert-sub-view'});return{Alert:Alert};});'use strict';tr.exportTo('tr.model',function(){function InteractionRecord(title,colorId,start,duration){tr.model.TimedEvent.call(this,start);this.title=title;this.colorId=colorId;this.duration=duration;this.args={};this.associatedEvents=new tr.c.Selection();}
+InteractionRecord.prototype={__proto__:tr.model.TimedEvent.prototype,get subSlices(){return[];},get userFriendlyName(){return this.title+' interaction at '+
+tr.b.units.tsString(this.start);}};tr.model.EventRegistry.register(InteractionRecord,{name:'interaction',pluralName:'interactions',singleViewElementName:'tr-ui-a-single-interaction-record-sub-view',multiViewElementName:'tr-ui-a-multi-interaction-record-sub-view'});return{InteractionRecord:InteractionRecord};});'use strict';tr.exportTo('tr.model',function(){function ModelIndices(model){this.flowEventsById_={};model.flowEvents.forEach(function(fe){if(fe.id!==undefined){if(!this.flowEventsB [...]
+this.flowEventsById_[fe.id].push(fe);}},this);}
+ModelIndices.prototype={addEventWithId:function(id,event){if(!this.flowEventsById_.hasOwnProperty(id)){this.flowEventsById_[id]=new Array();}
+this.flowEventsById_[id].push(event);},getFlowEventsWithId:function(id){if(!this.flowEventsById_.hasOwnProperty(id))
+return[];return this.flowEventsById_[id];}};return{ModelIndices:ModelIndices};});'use strict';tr.exportTo('tr',function(){var Importer=tr.importer.Importer;var Process=tr.model.Process;var Device=tr.model.Device;var Kernel=tr.model.Kernel;var GlobalMemoryDump=tr.model.GlobalMemoryDump;var GlobalInstantEvent=tr.model.GlobalInstantEvent;var FlowEvent=tr.model.FlowEvent;var Alert=tr.model.Alert;var InteractionRecord=tr.model.InteractionRecord;var Sample=tr.model.Sample;function ImportOption [...]
+ImportOptions.fromArguments=function(args,argsStartIndex){var arg0=args[argsStartIndex+0];if(typeof arg0==='object'){if(!(arg0 instanceof ImportOptions))
+throw new Error('Unexpected');return arg0;}
+var options=new ImportOptions();if(args[argsStartIndex]!==undefined)
+options.shiftWorldToZero=args[argsStartIndex];if(args[argsStartIndex+1]!==undefined)
+options.pruneEmptyContainers=args[argsStartIndex+1];if(args[argsStartIndex+2])
+options.customizeModelCallback=args[argsStartIndex+2];return options;}
+function ClockSyncRecord(name,ts,args){this.name=name;this.ts=ts;this.args=args;}
+function Model(opt_eventData,opt_options){tr.model.EventContainer.call(this);tr.b.EventTarget.decorate(this);this.faviconHue='blue';this.device=new Device(this);this.kernel=new Kernel(this);this.processes={};this.metadata=[];this.categories=[];this.bounds=new tr.b.Range();this.instantEvents=[];this.flowEvents=[];this.clockSyncRecords=[];this.intrinsicTimeUnit_=undefined;this.stackFrames={};this.samples=[];this.alerts=[];this.interaction_records=[];this.flowIntervalTree=new tr.b.IntervalT [...]
+this.importTraces([opt_eventData],options);}
+Model.prototype={__proto__:tr.model.EventContainer.prototype,iterateAllEventsInThisContainer:function(eventTypePredicate,callback,opt_this){if(eventTypePredicate.call(opt_this,GlobalMemoryDump))
+this.globalMemoryDumps.forEach(callback,opt_this);if(eventTypePredicate.call(opt_this,GlobalInstantEvent))
+this.instantEvents.forEach(callback,opt_this);if(eventTypePredicate.call(opt_this,FlowEvent))
+this.flowEvents.forEach(callback,opt_this);if(eventTypePredicate.call(opt_this,Alert))
+this.alerts.forEach(callback,opt_this);if(eventTypePredicate.call(opt_this,InteractionRecord))
+this.interaction_records.forEach(callback,opt_this);if(eventTypePredicate.call(opt_this,Sample))
+this.samples.forEach(callback,opt_this);},iterateAllChildEventContainers:function(callback,opt_this){callback.call(opt_this,this.device);callback.call(opt_this,this.kernel);for(var pid in this.processes)
+callback.call(opt_this,this.processes[pid]);},iterateAllPersistableObjects:function(callback){this.kernel.iterateAllPersistableObjects(callback);for(var pid in this.processes)
+this.processes[pid].iterateAllPersistableObjects(callback);},updateBounds:function(){this.bounds.reset();var bounds=this.bounds;this.iterateAllChildEventContainers(function(ec){ec.updateBounds();bounds.addRange(ec.bounds);});this.iterateAllEventsInThisContainer(function(eventConstructor){return true;},function(event){event.addBoundsToRange(bounds);});},shiftWorldToZero:function(){var shiftAmount=-this.bounds.min;this.iterateAllChildEventContainers(function(ec){ec.shiftTimestampsForward(s [...]
+n++;return n;},getProcess:function(pid){return this.processes[pid];},getOrCreateProcess:function(pid){if(!this.processes[pid])
+this.processes[pid]=new Process(this,pid);return this.processes[pid];},pushInstantEvent:function(instantEvent){this.instantEvents.push(instantEvent);},addStackFrame:function(stackFrame){if(this.stackFrames[stackFrame.id])
+throw new Error('Stack frame already exists');this.stackFrames[stackFrame.id]=stackFrame;return stackFrame;},addInteractionRecord:function(ir1){this.interaction_records.push(ir1);},getClockSyncRecordsNamed:function(name){return this.clockSyncRecords.filter(function(x){return x.name===name;});},updateCategories_:function(){var categoriesDict={};this.device.addCategoriesToDict(categoriesDict);this.kernel.addCategoriesToDict(categoriesDict);for(var pid in this.processes)
+this.processes[pid].addCategoriesToDict(categoriesDict);this.categories=[];for(var category in categoriesDict)
+if(category!='')
+this.categories.push(category);},getAllThreads:function(){var threads=[];for(var tid in this.kernel.threads){threads.push(process.threads[tid]);}
+for(var pid in this.processes){var process=this.processes[pid];for(var tid in process.threads){threads.push(process.threads[tid]);}}
+return threads;},getAllProcesses:function(){var processes=[];for(var pid in this.processes)
+processes.push(this.processes[pid]);return processes;},getAllCounters:function(){var counters=[];counters.push.apply(counters,tr.b.dictionaryValues(this.device.counters));counters.push.apply(counters,tr.b.dictionaryValues(this.kernel.counters));for(var pid in this.processes){var process=this.processes[pid];for(var tid in process.counters){counters.push(process.counters[tid]);}}
+return counters;},getAnnotationByGUID:function(guid){return this.annotationsByGuid_[guid];},addAnnotation:function(annotation){if(!annotation.guid)
+throw new Error('Annotation with undefined guid given');this.annotationsByGuid_[annotation.guid]=annotation;tr.b.dispatchSimpleEvent(this,'annotationChange');},removeAnnotation:function(annotation){this.annotationsByGuid_[annotation.guid].onRemove();delete this.annotationsByGuid_[annotation.guid];tr.b.dispatchSimpleEvent(this,'annotationChange');},getAllAnnotations:function(){return tr.b.dictionaryValues(this.annotationsByGuid_);},findAllThreadsNamed:function(name){var namedThreads=[];na [...]
+return namedThreads;},createImporter_:function(eventData){var importerConstructor=tr.importer.Importer.findImporterFor(eventData);if(!importerConstructor)
+throw new Error('Could not find an importer for the provided eventData.');var importer=new importerConstructor(this,eventData);return importer;},importTraces:function(traces,opt_options){var progressMeter={update:function(msg){}};var options=ImportOptions.fromArguments(arguments,1);var task=this.createImportTracesTask(progressMeter,traces,options);tr.b.Task.RunSynchronously(task);},importTracesWithProgressDialog:function(traces,opt_options){var options=ImportOptions.fromArguments(argumen [...]
+overlay.visible=true;var task=this.createImportTracesTask(overlay,traces,options);var promise=tr.b.Task.RunWhenIdle(task);promise.then(function(){overlay.visible=false;},function(err){overlay.visible=false;});return promise;},hasEventDataDecoder_:function(importers){if(importers.length===0)
+return false;for(var i=0;i<importers.length;++i){if(!importers[i].isTraceDataContainer())
+return true;}
+return false;},createImportTracesTask:function(progressMeter,traces,opt_options){var options=ImportOptions.fromArguments(arguments,2);if(this.importing_)
+throw new Error('Already importing.');this.importing_=true;var importTask=new tr.b.Task(function(){progressMeter.update('I will now import your traces for you...');},this);var lastTask=importTask;var importers=[];lastTask=lastTask.after(function(){traces=traces.slice(0);progressMeter.update('Creating importers...');for(var i=0;i<traces.length;++i)
+importers.push(this.createImporter_(traces[i]));for(var i=0;i<importers.length;i++){var subtraces=importers[i].extractSubtraces();for(var j=0;j<subtraces.length;j++){try{traces.push(subtraces[j]);importers.push(this.createImporter_(subtraces[j]));}catch(error){console.warn(error.name+': '+error.message);continue;}}}
+if(traces.length&&!this.hasEventDataDecoder_(importers)){throw new Error('Could not find an importer for '+'the provided eventData.');}
+importers.sort(function(x,y){return x.importPriority-y.importPriority;});},this);lastTask=lastTask.after(function(task){importers.forEach(function(importer,index){task.subTask(function(){progressMeter.update('Importing '+(index+1)+' of '+importers.length);importer.importEvents();},this);},this);},this);if(options.customizeModelCallback){lastTask=lastTask.after(function(task){options.customizeModelCallback(this);},this);}
+lastTask=lastTask.after(function(task){importers.forEach(function(importer,index){progressMeter.update('Importing sample data '+(index+1)+'/'+importers.length);importer.importSampleData();},this);},this);lastTask=lastTask.after(function(){progressMeter.update('Autoclosing open slices...');this.samples.sort(function(x,y){return x.start-y.start;});this.updateBounds();this.kernel.autoCloseOpenSlices(this.bounds.max);for(var pid in this.processes)
+this.processes[pid].autoCloseOpenSlices(this.bounds.max);this.kernel.createSubSlices();for(var pid in this.processes)
+this.processes[pid].createSubSlices();},this);lastTask=lastTask.after(function(task){importers.forEach(function(importer,index){progressMeter.update('Finalizing import '+(index+1)+'/'+importers.length);importer.finalizeImport();},this);},this);lastTask=lastTask.after(function(){progressMeter.update('Initializing objects (step 1/2)...');for(var pid in this.processes)
+this.processes[pid].preInitializeObjects();},this);if(options.pruneEmptyContainers){lastTask=lastTask.after(function(){progressMeter.update('Pruning empty containers...');this.kernel.pruneEmptyContainers();for(var pid in this.processes){this.processes[pid].pruneEmptyContainers();}},this);}
+lastTask=lastTask.after(function(){progressMeter.update('Merging kernel with userland...');for(var pid in this.processes)
+this.processes[pid].mergeKernelWithUserland();},this);var auditors=[];lastTask=lastTask.after(function(){progressMeter.update('Adding arbitrary data to model...');auditors=options.auditorConstructors.map(function(auditorConstructor){return new auditorConstructor(this);},this);auditors.forEach(function(auditor){auditor.runAnnotate();});},this);lastTask=lastTask.after(function(){progressMeter.update('Computing final world bounds...');this.updateBounds();this.updateCategories_();if(options. [...]
+this.shiftWorldToZero();},this);lastTask=lastTask.after(function(){progressMeter.update('Building flow event map...');for(var i=0;i<this.flowEvents.length;++i){var flowEvent=this.flowEvents[i];this.flowIntervalTree.insert(flowEvent);}
+this.flowIntervalTree.updateHighValues();},this);lastTask=lastTask.after(function(){progressMeter.update('Joining object refs...');for(var i=0;i<importers.length;i++)
+importers[i].joinRefs();},this);lastTask=lastTask.after(function(){progressMeter.update('Cleaning up undeleted objects...');for(var pid in this.processes)
+this.processes[pid].autoDeleteObjects(this.bounds.max);},this);lastTask=lastTask.after(function(){progressMeter.update('Sorting memory dumps...');this.globalMemoryDumps.sort(function(x,y){return x.start-y.start;});for(var pid in this.processes)
+this.processes[pid].sortMemoryDumps();},this);lastTask=lastTask.after(function(){progressMeter.update('Calculating memory dump graph attributes...');this.globalMemoryDumps.forEach(function(dump){dump.calculateGraphAttributes();});},this);lastTask=lastTask.after(function(){progressMeter.update('Initializing objects (step 2/2)...');for(var pid in this.processes)
+this.processes[pid].initializeObjects();},this);lastTask=lastTask.after(function(){progressMeter.update('Building flow event indices...');this.modelIndices=new tr.model.ModelIndices(this);},this);lastTask=lastTask.after(function(){progressMeter.update('Running auditors...');auditors.forEach(function(auditor){auditor.runAudit();});this.interaction_records.sort(function(x,y){return x.start-y.start;});this.alerts.sort(function(x,y){return x.start-y.start;});this.updateBounds();},this);lastT [...]
+return;console.warn(data.message);this.reportedImportWarnings_[data.type]=true;},get intrinsicTimeUnit(){if(this.intrinsicTimeUnit_===undefined)
+return tr.b.units.Time.supportedUnits.ms;return this.intrinsicTimeUnit_;},set intrinsicTimeUnit(value){if(this.intrinsicTimeUnit_===value)
+return;if(this.intrinsicTimeUnit_!==undefined)
+throw new Error('Intrinsic time unit already set');this.intrinsicTimeUnit_=value;},get hasImportWarnings(){return(this.importWarnings_.length>0);},get importWarnings(){return this.importWarnings_;}};return{ImportOptions:ImportOptions,ClockSyncRecord:ClockSyncRecord,Model:Model};});'use strict';tr.exportTo('tr.c',function(){var EventRegistry=tr.model.EventRegistry;var RequestSelectionChangeEvent=tr.b.Event.bind(undefined,'requestSelectionChange',true,false);function Selection(opt_events){ [...]
+this.push(opt_events[i]);}else{this.push(opt_events);}}}
+Selection.prototype={__proto__:Object.prototype,get bounds(){if(this.bounds_dirty_){this.bounds_.reset();for(var i=0;i<this.length_;i++)
+this[i].addBoundsToRange(this.bounds_);this.bounds_dirty_=false;}
+return this.bounds_;},get duration(){if(this.bounds_.isEmpty)
+return 0;return this.bounds_.max-this.bounds_.min;},get length(){return this.length_;},get guid(){return this.guid_;},clear:function(){for(var i=0;i<this.length_;++i)
+delete this[i];this.length_=0;this.bounds_dirty_=true;},push:function(event){if(event.guid==undefined)
+throw new Error('Event must have a GUID');if(this.contains(event))
+return event;this.pushed_guids_[event.guid]=true;this[this.length_++]=event;this.bounds_dirty_=true;return event;},contains:function(event){return this.pushed_guids_[event.guid];},addSelection:function(selection){for(var i=0;i<selection.length;i++)
+this.push(selection[i]);},subSelection:function(index,count){count=count||1;var selection=new Selection();selection.bounds_dirty_=true;if(index<0||index+count>this.length_)
+throw new Error('Index out of bounds');for(var i=index;i<index+count;i++)
+selection.push(this[i]);return selection;},equals:function(that){if(this.length!==that.length)
+return false;for(var i=0;i<this.length;i++){var event=this[i];if(that.pushed_guids_[event.guid]===undefined)
+return false;}
+return true;},getEventsOrganizedByBaseType:function(opt_pruneEmpty){var events={};var allTypeInfos=EventRegistry.getAllRegisteredTypeInfos();allTypeInfos.forEach(function(eventTypeInfo){events[eventTypeInfo.metadata.name]=new Selection();if(this.sunburst_zoom_level!==undefined)
+events[eventTypeInfo.metadata.name].sunburst_zoom_level=this.sunburst_zoom_level;},this);this.forEach(function(event,i){var maxEventIndex=-1;var maxEventTypeInfo=undefined;allTypeInfos.forEach(function(eventTypeInfo,eventIndex){if(!(event instanceof eventTypeInfo.constructor))
+return;if(eventIndex>maxEventIndex){maxEventIndex=eventIndex;maxEventTypeInfo=eventTypeInfo;}});if(maxEventIndex==-1){console.log(event);throw new Error('Unrecognized event type');}
+events[maxEventTypeInfo.metadata.name].push(event);});if(opt_pruneEmpty){var prunedEvents={};for(var eventType in events){if(events[eventType].length>0)
+prunedEvents[eventType]=events[eventType];}
+return prunedEvents;}else{return events;}},getEventsOrganizedByTitle:function(){var eventsByTitle={};for(var i=0;i<this.length;i++){var event=this[i];if(event.title===undefined)
+throw new Error('An event didn\'t have a title!');if(eventsByTitle[event.title]==undefined){eventsByTitle[event.title]=[];}
+eventsByTitle[event.title].push(event);}
+return eventsByTitle;},enumEventsOfType:function(type,func){for(var i=0;i<this.length_;i++)
+if(this[i]instanceof type)
+func(this[i]);},get userFriendlyName(){if(this.length===0){throw new Error('Empty selection');}
+var eventsByBaseType=this.getEventsOrganizedByBaseType(true);var eventTypeName=tr.b.dictionaryKeys(eventsByBaseType)[0];if(this.length===1){var tmp=EventRegistry.getUserFriendlySingularName(eventTypeName);return this[0].userFriendlyName;}
+var numEventTypes=tr.b.dictionaryLength(eventsByBaseType);if(numEventTypes!==1){return this.length+' events of various types';}
+var tmp=EventRegistry.getUserFriendlyPluralName(eventTypeName);return this.length+' '+tmp;},getShiftedSelection:function(viewport,offset){var newSelection=new Selection();for(var i=0;i<this.length_;i++){var event=this[i];if(event instanceof tr.model.FlowEvent){if(offset>0){newSelection.push(event.endSlice);}else if(offset<0){newSelection.push(event.startSlice);}else{}
+continue;}
+var track=viewport.trackForEvent(event);track.addEventNearToProvidedEventToSelection(event,offset,newSelection);}
+if(newSelection.length==0)
+return undefined;return newSelection;},filter:function(fn,opt_this){var res=new Selection();this.forEach(function(slice){if(fn.call(this,slice))
+res.push(slice);},opt_this);return res;},forEach:function(fn,opt_this){for(var i=0;i<this.length;i++)
+fn.call(opt_this,this[i],i);},map:function(fn,opt_this){var res=[];for(var i=0;i<this.length;i++)
+res.push(fn.call(opt_this,this[i],i));return res;},every:function(fn,opt_this){for(var i=0;i<this.length;i++)
+if(!fn.call(opt_this,this[i],i))
+return false;return true;},some:function(fn,opt_this){for(var i=0;i<this.length;i++)
+if(fn.call(opt_this,this[i],i))
+return true;return false;}};return{Selection:Selection,RequestSelectionChangeEvent:RequestSelectionChangeEvent};});'use strict';Polymer('tr-ui-a-sub-view',{set tabLabel(label){return this.setAttribute('tab-label',label);},get tabLabel(){return this.getAttribute('tab-label');},get requiresTallView(){return false;},get relatedEventsToHighlight(){return undefined;},set selection(selection){throw new Error('Not implemented!');},get selection(){throw new Error('Not implemented!');}});'use str [...]
+this.textContent=opt_textContent;},onClicked_:function(){if(!this.selection_)
+return;var event=new tr.c.RequestSelectionChangeEvent();if(typeof this.selection_==='function')
+event.selection=this.selection_();else
+event.selection=this.selection_;this.dispatchEvent(event);}});'use strict';tr.exportTo('tr.b.units',function(){function TimeDuration(duration){this.duration=duration;};TimeDuration.prototype={toString:function(){return TimeDuration.format(this.duration);}};TimeDuration.format=function(duration){return tr.b.units.Time.currentDisplayUnit.format(duration);};return{TimeDuration:TimeDuration};});'use strict';tr.exportTo('tr.b.units',function(){function TimeStamp(timestamp){this.timestamp=time [...]
+spanEl.className=opt_dictionary.className;if(opt_dictionary.textContent)
+spanEl.textContent=opt_dictionary.textContent;if(opt_dictionary.parent)
+opt_dictionary.parent.appendChild(spanEl);if(opt_dictionary.bold)
+spanEl.style.fontWeight='bold';if(opt_dictionary.marginLeft)
+spanEl.style.marginLeft=opt_dictionary.marginLeft;if(opt_dictionary.marginRight)
+spanEl.style.marginRight=opt_dictionary.marginRight;if(opt_dictionary.backgroundColor)
+spanEl.style.backgroundColor=opt_dictionary.backgroundColor;if(opt_dictionary.color)
+spanEl.style.color=opt_dictionary.color;}
+return spanEl;};function createDiv(opt_dictionary){var divEl=document.createElement('div');if(opt_dictionary){if(opt_dictionary.className)
+divEl.className=opt_dictionary.className;if(opt_dictionary.parent)
+opt_dictionary.parent.appendChild(divEl);if(opt_dictionary.textContent)
+divEl.textContent=opt_dictionary.textContent;if(opt_dictionary.maxWidth)
+divEl.style.maxWidth=opt_dictionary.maxWidth;}
+return divEl;};function createScopedStyle(styleContent){var styleEl=document.createElement('style');styleEl.scoped=true;styleEl.innerHTML=styleContent;return styleEl;}
+function valuesEqual(a,b){if(a instanceof Array&&b instanceof Array)
+return a.length===b.length&&JSON.stringify(a)===JSON.stringify(b);return a===b;}
+function createSelector(targetEl,targetElProperty,settingsKey,defaultValue,items,opt_namespace){var defaultValueIndex;for(var i=0;i<items.length;i++){var item=items[i];if(valuesEqual(item.value,defaultValue)){defaultValueIndex=i;break;}}
+if(defaultValueIndex===undefined)
+throw new Error('defaultValue must be in the items list');var selectorEl=document.createElement('select');selectorEl.addEventListener('change',onChange);for(var i=0;i<items.length;i++){var item=items[i];var optionEl=document.createElement('option');optionEl.textContent=item.label;optionEl.targetPropertyValue=item.value;selectorEl.appendChild(optionEl);}
+function onChange(e){var value=selectorEl.selectedOptions[0].targetPropertyValue;tr.b.Settings.set(settingsKey,value,opt_namespace);targetEl[targetElProperty]=value;}
+var oldSetter=targetEl.__lookupSetter__('selectedIndex');selectorEl.__defineGetter__('selectedValue',function(v){return selectorEl.children[selectorEl.selectedIndex].targetPropertyValue;});selectorEl.__defineSetter__('selectedValue',function(v){for(var i=0;i<selectorEl.children.length;i++){var value=selectorEl.children[i].targetPropertyValue;if(valuesEqual(value,v)){var changed=selectorEl.selectedIndex!=i;if(changed){selectorEl.selectedIndex=i;onChange();}
+return;}}
+throw new Error('Not a valid value');});var initialValue=tr.b.Settings.get(settingsKey,defaultValue,opt_namespace);var didSet=false;for(var i=0;i<selectorEl.children.length;i++){if(valuesEqual(selectorEl.children[i].targetPropertyValue,initialValue)){didSet=true;targetEl[targetElProperty]=initialValue;selectorEl.selectedIndex=i;break;}}
+if(!didSet){selectorEl.selectedIndex=defaultValueIndex;targetEl[targetElProperty]=defaultValue;}
+return selectorEl;}
+function createEditCategorySpan(optionGroupEl,targetEl){var spanEl=createSpan({className:'edit-categories'});spanEl.textContent='Edit categories';spanEl.classList.add('labeled-option');spanEl.addEventListener('click',function(){targetEl.onClickEditCategories();});return spanEl;}
+function createOptionGroup(targetEl,targetElProperty,settingsKey,defaultValue,items){function onChange(){var value=[];if(this.value.length)
+value=this.value.split(',');tr.b.Settings.set(settingsKey,value);targetEl[targetElProperty]=value;}
+var optionGroupEl=createSpan({className:'labeled-option-group'});var initialValue=tr.b.Settings.get(settingsKey,defaultValue);for(var i=0;i<items.length;++i){var item=items[i];var id='category-preset-'+item.label.replace(/ /g,'-');var radioEl=document.createElement('input');radioEl.type='radio';radioEl.setAttribute('id',id);radioEl.setAttribute('name','category-presets-group');radioEl.setAttribute('value',item.value);radioEl.addEventListener('change',onChange.bind(radioEl,targetEl,target [...]
+radioEl.checked=true;var labelEl=document.createElement('label');labelEl.textContent=item.label;labelEl.setAttribute('for',id);var spanEl=createSpan({className:'labeled-option'});spanEl.appendChild(radioEl);spanEl.appendChild(labelEl);spanEl.__defineSetter__('checked',function(opt_bool){var changed=radioEl.checked!==(!!opt_bool);if(!changed)
+return;radioEl.checked=!!opt_bool;onChange();});spanEl.__defineGetter__('checked',function(){return radioEl.checked;});optionGroupEl.appendChild(spanEl);}
+optionGroupEl.appendChild(createEditCategorySpan(optionGroupEl,targetEl));if(!initialValue.length)
+optionGroupEl.classList.add('categories-expanded');targetEl[targetElProperty]=initialValue;return optionGroupEl;}
+var nextCheckboxId=1;function createCheckBox(targetEl,targetElProperty,settingsKey,defaultValue,label){var buttonEl=document.createElement('input');buttonEl.type='checkbox';var initialValue=tr.b.Settings.get(settingsKey,defaultValue);buttonEl.checked=!!initialValue;if(targetEl)
+targetEl[targetElProperty]=initialValue;function onChange(){tr.b.Settings.set(settingsKey,buttonEl.checked);if(targetEl)
+targetEl[targetElProperty]=buttonEl.checked;}
+buttonEl.addEventListener('change',onChange);var id='#checkbox-'+nextCheckboxId++;var spanEl=createSpan({className:'labeled-checkbox'});buttonEl.setAttribute('id',id);var labelEl=document.createElement('label');labelEl.textContent=label;labelEl.setAttribute('for',id);spanEl.appendChild(buttonEl);spanEl.appendChild(labelEl);spanEl.__defineSetter__('checked',function(opt_bool){var changed=buttonEl.checked!==(!!opt_bool);if(!changed)
+return;buttonEl.checked=!!opt_bool;onChange();});spanEl.__defineGetter__('checked',function(){return buttonEl.checked;});return spanEl;}
+function isElementAttachedToDocument(el){var cur=el;while(cur.parentNode)
+cur=cur.parentNode;return(cur===el.ownerDocument||cur.nodeName==='#document-fragment');}
+function asHTMLOrTextNode(value,opt_ownerDocument){if(value instanceof Node)
+return value;var ownerDocument=opt_ownerDocument||document;return ownerDocument.createTextNode(value);}
+return{createSpan:createSpan,createDiv:createDiv,createScopedStyle:createScopedStyle,createSelector:createSelector,createOptionGroup:createOptionGroup,createCheckBox:createCheckBox,isElementAttachedToDocument:isElementAttachedToDocument,asHTMLOrTextNode:asHTMLOrTextNode};});'use strict';(function(){var RIGHT_ARROW=String.fromCharCode(0x25b6);var UNSORTED_ARROW=String.fromCharCode(0x25BF);var ASCENDING_ARROW=String.fromCharCode(0x25BE);var DESCENDING_ARROW=String.fromCharCode(0x25B4);var  [...]
+this.scheduleRebuildBody_();},set tableColumns(columns){var columnsWithExpandButtons=[];for(var i=0;i<columns.length;i++){if(columns[i].showExpandButtons)
+columnsWithExpandButtons.push(i);}
+if(columnsWithExpandButtons.length===0){columnsWithExpandButtons=[0];}
+for(var i=0;i<columns.length;i++){var colInfo=columns[i];if(colInfo.width===undefined)
+continue;var hasExpandButton=columnsWithExpandButtons.indexOf(i)!==-1;var w=colInfo.width;if(w){if(/\d+px/.test(w)){continue;}else if(/\d+%/.test(w)){if(hasExpandButton){throw new Error('Columns cannot be %-sized and host '+' an expand button');}}else{throw new Error('Unrecognized width string');}}}
+this.tableColumns_=columns;this.headerCells_=[];this.columnsWithExpandButtons_=columnsWithExpandButtons;this.sortColumnIndex=undefined;this.scheduleRebuildHeaders_();this.tableRows=this.tableRows_;},get tableColumns(){return this.tableColumns_;},set tableRows(rows){this.selectedTableRowInfo_=undefined;this.selectedColumnIndex_=undefined;this.maybeUpdateSelectedRow_();this.tableRows_=rows;this.tableRowsInfo_=new WeakMap();this.scheduleRebuildBody_();},get tableRows(){return this.tableRows [...]
+if(this.tableColumns_.length<=number)
+throw new Error('Column number '+number+' is out of bounds.');if(!this.tableColumns_[number].cmp)
+throw new Error('Column '+number+' does not have a comparator.');this.sortColumnIndex_=number;this.updateHeaderArrows_();this.scheduleRebuildBody_();},get sortColumnIndex(){return this.sortColumnIndex_;},set sortDescending(value){var newValue=!!value;if(newValue!==this.sortDescending_){this.sortDescending_=newValue;this.updateHeaderArrows_();this.scheduleRebuildBody_();}},get sortDescending(){return this.sortDescending_;},updateHeaderArrows_:function(){for(var i=0;i<this.headerCells_.len [...]
+if(i!==this.sortColumnIndex_){this.headerCells_[i].sideContent=UNSORTED_ARROW;continue;}
+this.headerCells_[i].sideContent=this.sortDescending_?DESCENDING_ARROW:ASCENDING_ARROW;}},sortRows_:function(rows){rows.sort(function(rowA,rowB){if(this.sortDescending_)
+return this.tableColumns_[this.sortColumnIndex_].cmp(rowB.userRow,rowA.userRow);return this.tableColumns_[this.sortColumnIndex_].cmp(rowA.userRow,rowB.userRow);}.bind(this));for(var i=0;i<rows.length;i++){if(rows[i].isExpanded)
+this.sortRows_(rows[i][this.subRowsPropertyName_]);}},generateHeaderColumns_:function(){this.headerCells_=[];this.$.head.textContent='';if(!this.showHeader_)
+return;var tr=this.appendNewElement_(this.$.head,'tr');for(var i=0;i<this.tableColumns_.length;i++){var td=this.appendNewElement_(tr,'td');var headerCell=document.createElement('tr-ui-b-table-header-cell');if(this.showHeader)
+headerCell.cellTitle=this.tableColumns_[i].title;else
+headerCell.cellTitle='';if(this.tableColumns_[i].cmp){td.classList.add('sensitive');headerCell.tapCallback=this.createSortCallback_(i);if(this.sortColumnIndex_===i)
+headerCell.sideContent=this.sortDescending_?DESCENDING_ARROW:ASCENDING_ARROW;else
+headerCell.sideContent=UNSORTED_ARROW;}
+td.appendChild(headerCell);this.headerCells_.push(headerCell);}},applySizes_:function(){if(this.tableRows_.length===0&&!this.showHeader)
+return;var rowToRemoveSizing;var rowToSize;if(this.showHeader){rowToSize=this.$.head.children[0];rowToRemoveSizing=this.$.body.children[0];}else{rowToSize=this.$.body.children[0];rowToRemoveSizing=this.$.head.children[0];}
+for(var i=0;i<this.tableColumns_.length;i++){if(rowToRemoveSizing&&rowToRemoveSizing.children[i]){var tdToRemoveSizing=rowToRemoveSizing.children[i];tdToRemoveSizing.style.minWidth='';tdToRemoveSizing.style.width='';}
+var td=rowToSize.children[i];var delta;if(this.columnsWithExpandButtons_.indexOf(i)!==-1){td.style.paddingLeft=BASIC_INDENTATION+'px';delta=BASIC_INDENTATION+'px';}else{delta=undefined;}
+function calc(base,delta){if(delta)
+return'calc('+base+' - '+delta+')';else
+return base;}
+var w=this.tableColumns_[i].width;if(w){if(/\d+px/.test(w)){td.style.minWidth=calc(w,delta);}else if(/\d+%/.test(w)){td.style.width=w;}else{throw new Error('Unrecognized width string: '+w);}}}},createSortCallback_:function(columnNumber){return function(){var previousIndex=this.sortColumnIndex;this.sortColumnIndex=columnNumber;if(previousIndex!==columnNumber)
+this.sortDescending=false;else
+this.sortDescending=!this.sortDescending;}.bind(this);},generateTableRowNodes_:function(tableSection,userRows,rowInfoMap,indentation,lastAddedRow,parentRowInfo){if(this.sortColumnIndex_!==undefined&&tableSection===this.$.body){userRows=userRows.slice();userRows.sort(function(rowA,rowB){var c=this.tableColumns_[this.sortColumnIndex_].cmp(rowA,rowB);if(this.sortDescending_)
+c=-c;return c;}.bind(this));}
+for(var i=0;i<userRows.length;i++){var userRow=userRows[i];var rowInfo=this.getOrCreateRowInfoFor_(rowInfoMap,userRow,parentRowInfo);var htmlNode=this.getHTMLNodeForRowInfo_(tableSection,rowInfo,rowInfoMap,indentation);if(lastAddedRow===undefined){tableSection.insertBefore(htmlNode,tableSection.firstChild);}else{var nextSiblingOfLastAdded=lastAddedRow.nextSibling;tableSection.insertBefore(htmlNode,nextSiblingOfLastAdded);}
+this.updateTabIndexForTableRowNode_(htmlNode);lastAddedRow=htmlNode;if(!rowInfo.isExpanded)
+continue;lastAddedRow=this.generateTableRowNodes_(tableSection,userRow[this.subRowsPropertyName_],rowInfoMap,indentation+1,lastAddedRow,rowInfo);}
+return lastAddedRow;},getOrCreateRowInfoFor_:function(rowInfoMap,userRow,parentRowInfo){if(rowInfoMap.has(userRow))
+return rowInfoMap.get(userRow);var rowInfo={userRow:userRow,htmlNode:undefined,isExpanded:userRow.isExpanded||false,parentRowInfo:parentRowInfo};rowInfoMap.set(userRow,rowInfo);return rowInfo;},getHTMLNodeForRowInfo_:function(tableSection,rowInfo,rowInfoMap,indentation){if(rowInfo.htmlNode)
+return rowInfo.htmlNode;var INDENT_SPACE=indentation*16;var INDENT_SPACE_NO_BUTTON=indentation*16+BASIC_INDENTATION;var trElement=this.ownerDocument.createElement('tr');rowInfo.htmlNode=trElement;rowInfo.indentation=indentation;trElement.rowInfo=rowInfo;for(var i=0;i<this.tableColumns_.length;){var td=this.appendNewElement_(trElement,'td');td.columnIndex=i;var column=this.tableColumns_[i];var value=column.value(rowInfo.userRow);var colSpan=column.colSpan?column.colSpan:1;td.style.colSpan [...]
+if(this.doesColumnIndexSupportSelection(i))
+td.classList.add('supports-selection');if(this.columnsWithExpandButtons_.indexOf(i)!=-1){if(rowInfo.userRow[this.subRowsPropertyName_]&&rowInfo.userRow[this.subRowsPropertyName_].length>0){td.style.paddingLeft=INDENT_SPACE+'px';var expandButton=this.appendNewElement_(td,'expand-button');expandButton.textContent=RIGHT_ARROW;if(rowInfo.isExpanded)
+expandButton.classList.add('button-expanded');}else{td.style.paddingLeft=INDENT_SPACE_NO_BUTTON+'px';}}
+td.appendChild(tr.ui.b.asHTMLOrTextNode(value,this.ownerDocument));i+=colSpan;}
+var needsClickListener=false;if(this.columnsWithExpandButtons_.length)
+needsClickListener=true;else if(tableSection==this.$.body)
+needsClickListener=true;if(needsClickListener){trElement.addEventListener('click',function(e){e.stopPropagation();if(e.target.tagName=='EXPAND-BUTTON'){this.setExpandedForUserRow_(tableSection,rowInfoMap,rowInfo.userRow,!rowInfo.isExpanded);return;}
+function getTD(cur){if(cur===trElement)
+throw new Error('woah');if(cur.parentElement===trElement)
+return cur;return getTD(cur.parentElement);}
+if(this.supportsSelection_){var isAlreadySelected=false;var tdThatWasClicked=getTD(e.target);if(!this.cellSelectionMode_){isAlreadySelected=this.selectedTableRowInfo_===rowInfo;}else{isAlreadySelected=this.selectedTableRowInfo_===rowInfo;isAlreadySelected&=(this.selectedColumnIndex_===tdThatWasClicked.columnIndex);}
+if(isAlreadySelected){if(rowInfo.userRow[this.subRowsPropertyName_]&&rowInfo.userRow[this.subRowsPropertyName_].length){this.setExpandedForUserRow_(tableSection,rowInfoMap,rowInfo.userRow,!rowInfo.isExpanded);}}else{this.didTableRowInfoGetClicked_(rowInfo,tdThatWasClicked.columnIndex);}}else{if(rowInfo.userRow[this.subRowsPropertyName_]&&rowInfo.userRow[this.subRowsPropertyName_].length){this.setExpandedForUserRow_(tableSection,rowInfoMap,rowInfo.userRow,!rowInfo.isExpanded);}}}.bind(this));}
+return rowInfo.htmlNode;},removeSubNodes_:function(tableSection,rowInfo,rowInfoMap){if(rowInfo.userRow[this.subRowsPropertyName_]===undefined)
+return;for(var i=0;i<rowInfo.userRow[this.subRowsPropertyName_].length;i++){var subRow=rowInfo.userRow[this.subRowsPropertyName_][i];var subRowInfo=rowInfoMap.get(subRow);if(!subRowInfo)
+continue;var subNode=subRowInfo.htmlNode;if(subNode&&subNode.parentNode===tableSection){tableSection.removeChild(subNode);this.removeSubNodes_(tableSection,subRowInfo,rowInfoMap);}}},scheduleRebuildHeaders_:function(){this.headerDirty_=true;this.scheduleRebuild_();},scheduleRebuildBody_:function(){this.bodyDirty_=true;this.scheduleRebuild_();},scheduleRebuildFooter_:function(){this.footerDirty_=true;this.scheduleRebuild_();},scheduleRebuild_:function(){if(this.rebuildPending_)
+return;this.rebuildPending_=true;setTimeout(function(){this.rebuildPending_=false;this.rebuild();}.bind(this),0);},rebuildIfNeeded_:function(){this.rebuild();},rebuild:function(){var wasBodyOrHeaderDirty=this.headerDirty_||this.bodyDirty_;if(this.headerDirty_){this.generateHeaderColumns_();this.headerDirty_=false;}
+if(this.bodyDirty_){this.$.body.textContent='';this.generateTableRowNodes_(this.$.body,this.tableRows_,this.tableRowsInfo_,0,undefined,undefined);if(this.tableRows_.length===0&&this.emptyValue_!==undefined){var trElement=this.ownerDocument.createElement('tr');this.$.body.appendChild(trElement);trElement.classList.add('empty-row');var td=this.ownerDocument.createElement('td');trElement.appendChild(td);td.colSpan=this.tableColumns_.length;var emptyValue=this.emptyValue_;td.appendChild(tr.u [...]
+this.bodyDirty_=false;}
+if(wasBodyOrHeaderDirty)
+this.applySizes_();if(this.footerDirty_){this.$.foot.textContent='';this.generateTableRowNodes_(this.$.foot,this.tableFooterRows_,this.tableFooterRowsInfo_,0,undefined,undefined);if(this.tableFooterRowsInfo_.length){this.$.body.classList.add('has-footer');}else{this.$.body.classList.remove('has-footer');}
+this.footerDirty_=false;}},appendNewElement_:function(parent,tagName){var element=parent.ownerDocument.createElement(tagName);parent.appendChild(element);return element;},getExpandedForTableRow:function(userRow){this.rebuildIfNeeded_();var rowInfo=this.tableRowsInfo_.get(userRow);if(rowInfo===undefined)
+throw new Error('Row has not been seen, must expand its parents');return rowInfo.isExpanded;},setExpandedForTableRow:function(userRow,expanded){this.rebuildIfNeeded_();var rowInfo=this.tableRowsInfo_.get(userRow);if(rowInfo===undefined)
+throw new Error('Row has not been seen, must expand its parents');return this.setExpandedForUserRow_(this.$.body,this.tableRowsInfo_,userRow,expanded);},setExpandedForUserRow_:function(tableSection,rowInfoMap,userRow,expanded){this.rebuildIfNeeded_();var rowInfo=rowInfoMap.get(userRow);if(rowInfo===undefined)
+throw new Error('Row has not been seen, must expand its parents');rowInfo.isExpanded=!!expanded;if(rowInfo.htmlNode===undefined)
+return;if(rowInfo.htmlNode.parentElement!==tableSection)
+return;var expandButton=rowInfo.htmlNode.querySelector('expand-button');if(rowInfo.isExpanded){expandButton.classList.add('button-expanded');var lastAddedRow=rowInfo.htmlNode;if(rowInfo.userRow[this.subRowsPropertyName_]){this.generateTableRowNodes_(tableSection,rowInfo.userRow[this.subRowsPropertyName_],rowInfoMap,rowInfo.indentation+1,lastAddedRow,rowInfo);}}else{expandButton.classList.remove('button-expanded');this.removeSubNodes_(tableSection,rowInfo,rowInfoMap);}
+this.maybeUpdateSelectedRow_();},get supportsSelection(){return this.supportsSelection_;},set supportsSelection(supportsSelection){this.rebuildIfNeeded_();this.supportsSelection_=!!supportsSelection;this.didSelectionStateChange_();},get cellSelectionMode(){return this.cellSelectionMode_;},set cellSelectionMode(cellSelectionMode){this.rebuildIfNeeded_();this.cellSelectionMode_=!!cellSelectionMode;this.didSelectionStateChange_();},get rowHighlightEnabled(){return this.rowHighlightEnabled_; [...]
+this.$.body.classList.add('row-highlight-enabled');else
+this.$.body.classList.remove('row-highlight-enabled');}
+for(var i=0;i<this.$.body.children.length;i++)
+this.updateTabIndexForTableRowNode_(this.$.body.children[i]);this.maybeUpdateSelectedRow_();},maybeUpdateSelectedRow_:function(){if(this.selectedTableRowInfo_===undefined)
+return;if(!this.supportsSelection_){this.removeSelectedState_();this.selectedTableRowInfo_=undefined;return;}
+function isVisible(rowInfo){if(!rowInfo.htmlNode)
+return false;return!!rowInfo.htmlNode.parentElement;}
+if(isVisible(this.selectedTableRowInfo_)){this.updateSelectedState_();return;}
+this.removeSelectedState_();var curRowInfo=this.selectedTableRowInfo_;while(curRowInfo&&!isVisible(curRowInfo))
+curRowInfo=curRowInfo.parentRowInfo;this.selectedTableRowInfo_=curRowInfo;if(this.selectedTableRowInfo_)
+this.updateSelectedState_();},didTableRowInfoGetClicked_:function(rowInfo,columnIndex){if(!this.supportsSelection_)
+return;if(this.cellSelectionMode_){if(!this.doesColumnIndexSupportSelection(columnIndex))
+return;}
+if(this.selectedTableRowInfo_!==rowInfo)
+this.selectedTableRow=rowInfo.userRow;if(this.selectedColumnIndex!==columnIndex)
+this.selectedColumnIndex=columnIndex;},get selectedTableRow(){if(!this.selectedTableRowInfo_)
+return undefined;return this.selectedTableRowInfo_.userRow;},set selectedTableRow(userRow){this.rebuildIfNeeded_();if(!this.supportsSelection_)
+throw new Error('Selection is off. Set supportsSelection=true.');var rowInfo=this.tableRowsInfo_.get(userRow);if(rowInfo===undefined)
+throw new Error('Row has not been seen, must expand its parents');var e=this.prepareToChangeSelection_();this.selectedTableRowInfo_=rowInfo;if(this.cellSelectionMode_){if(this.selectedTableRowInfo_&&this.selectedColumnIndex_===undefined){var i=this.getFirstSelectableColumnIndex_();if(i==-1)
+throw new Error('nope');this.selectedColumnIndex_=i;}}else{this.selectedColumnIndex_=undefined;}
+this.updateSelectedState_();this.dispatchEvent(e);},updateTabIndexForTableRowNode_:function(row){if(this.supportsSelection_){if(!this.cellSelectionMode_){row.tabIndex=0;}else{for(var i=0;i<this.tableColumns_.length;i++){if(!this.doesColumnIndexSupportSelection(i))
+continue;row.children[i].tabIndex=0;}}}else{if(!this.cellSelectionMode_){row.removeAttribute('tabIndex');}else{for(var i=0;i<this.tableColumns_.length;i++){if(!this.doesColumnIndexSupportSelection(i))
+continue;row.children[i].removeAttribute('tabIndex');}}}},prepareToChangeSelection_:function(){var e=new Event('selection-changed');var previousSelectedRowInfo=this.selectedTableRowInfo_;if(previousSelectedRowInfo)
+e.previousSelectedTableRow=previousSelectedRowInfo.userRow;else
+e.previousSelectedTableRow=undefined;this.removeSelectedState_();return e;},removeSelectedState_:function(){this.setSelectedState_(false);},updateSelectedState_:function(){this.setSelectedState_(true);},setSelectedState_:function(select){if(this.selectedTableRowInfo_===undefined)
+return;var tableRowNode=this.selectedTableRowInfo_.htmlNode;if(this.cellSelectionMode_&&this.rowHighlightEnabled_){if(select)
+tableRowNode.classList.add('highlighted-row');else
+tableRowNode.classList.remove('highlighted-row');}
+var node=this.getSelectableNodeGivenTableRowNode_(tableRowNode);if(select)
+node.setAttribute('selected',true);else
+node.removeAttribute('selected');},doesColumnIndexSupportSelection:function(columnIndex){var columnInfo=this.tableColumns_[columnIndex];var scs=columnInfo.supportsCellSelection;if(scs===false)
+return false;return true;},getFirstSelectableColumnIndex_:function(){for(var i=0;i<this.tableColumns_.length;i++){if(this.doesColumnIndexSupportSelection(i))
+return i;}
+return-1;},getSelectableNodeGivenTableRowNode_:function(htmlNode){if(!this.cellSelectionMode_){return htmlNode;}else{return htmlNode.children[this.selectedColumnIndex_];}},get selectedColumnIndex(){if(!this.supportsSelection_)
+return undefined;if(!this.cellSelectionMode_)
+return undefined;return this.selectedColumnIndex_;},set selectedColumnIndex(selectedColumnIndex){this.rebuildIfNeeded_();if(!this.supportsSelection_)
+throw new Error('Selection is off. Set supportsSelection=true.');if(selectedColumnIndex<0||selectedColumnIndex>=this.tableColumns_.length)
+throw new Error('Invalid index');if(!this.doesColumnIndexSupportSelection(selectedColumnIndex))
+throw new Error('Selection is not supported on this column');var e=this.prepareToChangeSelection_();this.selectedColumnIndex_=selectedColumnIndex;if(this.selectedColumnIndex_===undefined)
+this.selectedTableRowInfo_=undefined;this.updateSelectedState_();this.dispatchEvent(e);},onKeyDown_:function(e){if(this.supportsSelection_===false)
+return;if(this.selectedTableRowInfo_===undefined)
+return;var code_to_command_names={37:'ARROW_LEFT',38:'ARROW_UP',39:'ARROW_RIGHT',40:'ARROW_DOWN'};var cmdName=code_to_command_names[e.keyCode];if(cmdName===undefined)
+return;e.stopPropagation();e.preventDefault();this.performKeyCommand_(cmdName);},performKeyCommand_:function(cmdName){this.rebuildIfNeeded_();var rowInfo=this.selectedTableRowInfo_;var htmlNode=rowInfo.htmlNode;if(cmdName==='ARROW_UP'){var prev=htmlNode.previousElementSibling;if(prev){tr.ui.b.scrollIntoViewIfNeeded(prev);this.selectedTableRow=prev.rowInfo.userRow;this.focusSelected_();return;}
+return;}
+if(cmdName==='ARROW_DOWN'){var next=htmlNode.nextElementSibling;if(next){tr.ui.b.scrollIntoViewIfNeeded(next);this.selectedTableRow=next.rowInfo.userRow;this.focusSelected_();return;}
+return;}
+if(cmdName==='ARROW_RIGHT'){if(this.cellSelectionMode_){var newIndex=this.selectedColumnIndex_+1;if(newIndex>=this.tableColumns_.length)
+return;if(!this.doesColumnIndexSupportSelection(newIndex))
+return;this.selectedColumnIndex=newIndex;this.focusSelected_();return;}else{if(rowInfo.userRow[this.subRowsPropertyName_]===undefined)
+return;if(rowInfo.userRow[this.subRowsPropertyName_].length===0)
+return;if(!rowInfo.isExpanded)
+this.setExpandedForTableRow(rowInfo.userRow,true);this.selectedTableRow=rowInfo.userRow[this.subRowsPropertyName_][0];this.focusSelected_();return;}}
+if(cmdName==='ARROW_LEFT'){if(this.cellSelectionMode_){var newIndex=this.selectedColumnIndex_-1;if(newIndex<0)
+return;if(!this.doesColumnIndexSupportSelection(newIndex))
+return;this.selectedColumnIndex=newIndex;this.focusSelected_();return;}else{if(rowInfo.isExpanded){this.setExpandedForTableRow(rowInfo.userRow,false);this.focusSelected_();return;}
+var parentRowInfo=rowInfo.parentRowInfo;if(parentRowInfo){this.selectedTableRow=parentRowInfo.userRow;this.focusSelected_();return;}
+return;}}
+throw new Error('Unrecognized command');},focusSelected_:function(){if(!this.selectedTableRowInfo_)
+return;var node=this.getSelectableNodeGivenTableRowNode_(this.selectedTableRowInfo_.htmlNode);node.focus();}});})();'use strict';Polymer('tr-ui-b-table-header-cell',{created:function(){this.tapCallback_=undefined;this.cellTitle_='';},set cellTitle(value){this.cellTitle_=value;var titleNode=tr.ui.b.asHTMLOrTextNode(this.cellTitle_,this.ownerDocument);this.$.title.innerText='';this.$.title.appendChild(titleNode);},get cellTitle(){return this.cellTitle_;},clearSideContent:function(){this.$. [...]
+this.tapCallback_();}});'use strict';tr.exportTo('tr.b',function(){function _iterateElementDeeplyImpl(element,cb,thisArg,includeElement){if(includeElement){if(cb.call(thisArg,element))
+return true;}
+if(element.shadowRoot){if(_iterateElementDeeplyImpl(element.shadowRoot,cb,thisArg,false))
+return true;}
+for(var i=0;i<element.children.length;i++){if(_iterateElementDeeplyImpl(element.children[i],cb,thisArg,true))
+return true;}}
+function iterateElementDeeply(element,cb,thisArg){_iterateElementDeeplyImpl(element,cb,thisArg,false);}
+function findDeepElementMatchingPredicate(element,predicate){var foundElement=undefined;function matches(element){var match=predicate(element);if(!match)
+return false;foundElement=element;return true;}
+iterateElementDeeply(element,matches);return foundElement;}
+function findDeepElementsMatchingPredicate(element,predicate){var foundElements=[];function matches(element){var match=predicate(element);if(match){foundElements.push(element);}
+return false;}
+iterateElementDeeply(element,matches);return foundElements;}
+function findDeepElementMatching(element,selector){return findDeepElementMatchingPredicate(element,function(element){return element.matches(selector);});}
+function findDeepElementsMatching(element,selector){return findDeepElementsMatchingPredicate(element,function(element){return element.matches(selector);});}
+function findDeepElementWithTextContent(element,re){return findDeepElementMatchingPredicate(element,function(element){if(element.children.length!==0)
+return false;return re.test(element.textContent);});}
+return{iterateElementDeeply:iterateElementDeeply,findDeepElementMatching:findDeepElementMatching,findDeepElementsMatching:findDeepElementsMatching,findDeepElementMatchingPredicate:findDeepElementMatchingPredicate,findDeepElementsMatchingPredicate:findDeepElementsMatchingPredicate,findDeepElementWithTextContent:findDeepElementWithTextContent};});'use strict';tr.exportTo('tr.ui.units',function(){function createTimeSpan(duration){if(duration===undefined)
+return'';var span=document.createElement('tr-ui-u-time-duration-span');span.duration=duration;return span;}
+tr.b.units.Time.addEventListener('display-unit-changed',function(e){tr.b.findDeepElementsMatching(document.body,'tr-ui-u-time-duration-span').forEach(function(el){el.updateContent_();});});return{createTimeSpan:createTimeSpan};});'use strict';Polymer('tr-ui-u-time-duration-span',{ready:function(){this.warning_=undefined;this.duration_=undefined;},get duration(){return this.duration_;},set duration(duration){if(duration instanceof tr.b.units.TimeDuration)
+this.duration_=duration.duration;else
+this.duration_=duration;this.updateContent_();},updateContent_:function(){var content=tr.b.units.TimeDuration.format(this.duration_);this.$.content.textContent=content;},get warning(){return this.warning_;},set warning(warning){this.warning_=warning;var warningEl=this.$.warning;if(this.warning_){warningEl.title=warning;warningEl.style.display='';}else{warningEl.title='';warningEl.style.display='none';}}});'use strict';tr.exportTo('tr.ui.units',function(){function createTimeStampSpan(time [...]
+return'';var span=document.createElement('tr-ui-u-time-stamp-span');span.timestamp=timestamp;return span;}
+tr.b.units.Time.addEventListener('display-unit-changed',function(e){tr.b.findDeepElementsMatching(document.body,'tr-ui-u-time-stamp-span').forEach(function(el){el.updateContent_();});});return{createTimeStampSpan:createTimeStampSpan};});'use strict';Polymer('tr-ui-u-time-stamp-span',{ready:function(){this.timestamp_=undefined;},get timestamp(){return this.timestamp_;},set timestamp(timestamp){if(timestamp instanceof tr.b.units.TimeStamp)
+this.timestamp_=timestamp.timestamp;else
+this.timestamp_=timestamp;this.updateContent_();},updateContent_:function(){var content=tr.b.units.TimeStamp.format(this.timestamp_);this.shadowRoot.textContent=content;}});'use strict';Polymer('tr-ui-u-size-in-bytes-span',{ready:function(){this.$.content.textContent=String.fromCharCode(9888);this.numBytes_=undefined;},get numBytes(){return this.numBytes_;},set numBytes(numBytesOrSizeInBytes){if(numBytesOrSizeInBytes instanceof tr.b.units.SizeInBytes)
+this.numBytes_=numBytesOrSizeInBytes.numBytes;else
+this.numBytes_=numBytesOrSizeInBytes;this.$.content.textContent=tr.b.units.SizeInBytes.format(this.numBytes_);},get stringContent(){return this.$.content.textContent;}});'use strict';function isTable(object){if(!(object instanceof Array)||(object.length<2))return false;for(var colName in object[0]){if(typeof colName!=='string')return false;}
+for(var i=0;i<object.length;++i){if(!(object[i]instanceof Object))return false;for(var colName in object[i]){if(i&&(object[0][colName]===undefined))return false;var cellType=typeof object[i][colName];if(cellType!=='string'&&cellType!='number')return false;}
+if(i){for(var colName in object[0]){if(object[i][colName]===undefined)return false;}}}
+return true;}
+Polymer('tr-ui-a-generic-object-view',{ready:function(){this.object_=undefined;},get object(){return this.object_;},set object(object){this.object_=object;this.updateContents_();},updateContents_:function(){this.$.content.textContent='';this.appendElementsForType_('',this.object_,0,0,5,'');},appendElementsForType_:function(label,object,indent,depth,maxDepth,suffix){if(depth>maxDepth){this.appendSimpleText_(label,indent,'<recursion limit reached>',suffix);return;}
+if(object===undefined){this.appendSimpleText_(label,indent,'undefined',suffix);return;}
+if(object===null){this.appendSimpleText_(label,indent,'null',suffix);return;}
+if(!(object instanceof Object)){var type=typeof object;if(type=='string'){var objectReplaced=false;if((object[0]=='{'&&object[object.length-1]=='}')||(object[0]=='['&&object[object.length-1]==']')){try{object=JSON.parse(object);objectReplaced=true;}catch(e){}}
+if(!objectReplaced){if(object.indexOf('\n')!==-1){var lines=object.split('\n');lines.forEach(function(line,i){var text,ioff,ll,ss;if(i==0){text='"'+line;ioff=0;ll=label;ss='';}else if(i<lines.length-1){text=line;ioff=1;ll='';ss='';}else{text=line+'"';ioff=1;ll='';ss=suffix;}
+var el=this.appendSimpleText_(ll,indent+ioff*label.length+ioff,text,ss);el.style.whiteSpace='pre';return el;},this);return;}else{this.appendSimpleText_(label,indent,'"'+object+'"',suffix);return;}}
+else{}}else{return this.appendSimpleText_(label,indent,object,suffix);}}
+if(object instanceof tr.model.ObjectSnapshot){var link=document.createElement('tr-ui-a-analysis-link');link.selection=new tr.c.Selection(object);this.appendElementWithLabel_(label,indent,link,suffix);return;}
+if(object instanceof tr.model.ObjectInstance){var link=document.createElement('tr-ui-a-analysis-link');link.selection=new tr.c.Selection(object);this.appendElementWithLabel_(label,indent,link,suffix);return;}
+if(object instanceof tr.b.Rect){this.appendSimpleText_(label,indent,object.toString(),suffix);return;}
+if(object instanceof tr.b.units.SizeInBytes){var el=this.ownerDocument.createElement('tr-ui-u-size-in-bytes-span');el.numBytes=object.numBytes;this.appendElementWithLabel_(label,indent,el,suffix);return;}
+if(object instanceof tr.b.units.TimeDuration){var el=this.ownerDocument.createElement('tr-ui-u-time-duration-span');el.duration=object.duration;this.appendElementWithLabel_(label,indent,el,suffix);return;}
+if(object instanceof tr.b.units.TimeStamp){var el=this.ownerDocument.createElement('tr-ui-u-time-stamp-span');el.timestamp=object.timestamp;this.appendElementWithLabel_(label,indent,el,suffix);return;}
+if(object instanceof Array){this.appendElementsForArray_(label,object,indent,depth,maxDepth,suffix);return;}
+this.appendElementsForObject_(label,object,indent,depth,maxDepth,suffix);},appendElementsForArray_:function(label,object,indent,depth,maxDepth,suffix){if(object.length==0){this.appendSimpleText_(label,indent,'[]',suffix);return;}
+if(isTable(object)){var table=document.createElement('tr-ui-b-table');var columns=[];tr.b.iterItems(object[0],function(colName){columns.push({title:colName,value:function(row){return row[colName];}});});table.tableColumns=columns;table.tableRows=object;this.appendElementWithLabel_(label,indent,table,suffix);table.rebuild();return;}
+this.appendElementsForType_(label+'[',object[0],indent,depth+1,maxDepth,object.length>1?',':']'+suffix);for(var i=1;i<object.length;i++){this.appendElementsForType_('',object[i],indent+label.length+1,depth+1,maxDepth,i<object.length-1?',':']'+suffix);}
+return;},appendElementsForObject_:function(label,object,indent,depth,maxDepth,suffix){var keys=tr.b.dictionaryKeys(object);if(keys.length==0){this.appendSimpleText_(label,indent,'{}',suffix);return;}
+this.appendElementsForType_(label+'{'+keys[0]+': ',object[keys[0]],indent,depth,maxDepth,keys.length>1?',':'}'+suffix);for(var i=1;i<keys.length;i++){this.appendElementsForType_(keys[i]+': ',object[keys[i]],indent+label.length+1,depth+1,maxDepth,i<keys.length-1?',':'}'+suffix);}},appendElementWithLabel_:function(label,indent,dataElement,suffix){var row=document.createElement('div');var indentSpan=document.createElement('span');indentSpan.style.whiteSpace='pre';for(var i=0;i<indent;i++)
+indentSpan.textContent+=' ';row.appendChild(indentSpan);var labelSpan=document.createElement('span');labelSpan.textContent=label;row.appendChild(labelSpan);row.appendChild(dataElement);var suffixSpan=document.createElement('span');suffixSpan.textContent=suffix;row.appendChild(suffixSpan);row.dataElement=dataElement;this.$.content.appendChild(row);},appendSimpleText_:function(label,indent,text,suffix){var el=this.ownerDocument.createElement('span');el.textContent=text;this.appendElementWi [...]
+throw new Error('Only supports single slices');this.setSelectionWithoutErrorChecks(selection);},setSelectionWithoutErrorChecks:function(selection){this.currentSelection_=selection;this.updateContents_();},getEventRows_:function(event){var rows=[];if(event.error)
+rows.push({name:'Error',value:event.error});if(event.title)
+rows.push({name:'Title',value:event.title});if(event.category)
+rows.push({name:'Category',value:event.category});var startEl=document.createElement('tr-ui-u-time-stamp-span');startEl.timestamp=event.start;rows.push({name:'Start',value:startEl});if(event.duration){var wallDurationEl=document.createElement('tr-ui-u-time-duration-span');wallDurationEl.duration=event.duration;rows.push({name:'Wall Duration',value:wallDurationEl});}
+if(event.cpuDuration){var cpuDurationEl=document.createElement('tr-ui-u-time-duration-span');cpuDurationEl.duration=event.cpuDuration;rows.push({name:'CPU Duration',value:cpuDurationEl});}
+if(event.subSlices!==undefined&&event.subSlices.length!==0){if(event.selfTime){var selfTimeEl=document.createElement('tr-ui-u-time-duration-span');selfTimeEl.duration=event.selfTime;rows.push({name:'Self Time',value:selfTimeEl});}
+if(event.cpuSelfTime){var cpuSelfTimeEl=document.createElement('tr-ui-u-time-duration-span');cpuSelfTimeEl.duration=event.cpuSelfTime;if(event.cpuSelfTime>event.selfTime){cpuSelfTimeEl.warning=' Note that CPU Self Time is larger than Self Time. '+'This is a known limitation of this system, which occurs '+'due to several subslices, rounding issues, and imprecise '+'time at which we get cpu- and real-time.';}
+rows.push({name:'CPU Self Time',value:cpuSelfTimeEl});}}
+if(event.durationInUserTime){var durationInUserTimeEl=document.createElement('tr-ui-u-time-duration-span');durationInUserTimeEl.duration=event.durationInUserTime;rows.push({name:'Duration (U)',value:durationInUserTimeEl});}
+function createStackFrameEl(sf){var sfEl=document.createElement('tr-ui-a-stack-frame');sfEl.stackFrame=sf;return sfEl;}
+if(event.startStackFrame&&event.endStackFrame){if(event.startStackFrame===event.endStackFrame){rows.push({name:'Start+End Stack Trace',value:createStackFrameEl(event.startStackFrame)});}else{rows.push({name:'Start Stack Trace',value:createStackFrameEl(event.startStackFrame)});rows.push({name:'End Stack Trace',value:createStackFrameEl(event.endStackFrame)});}}else if(event.startStackFrame){rows.push({name:'Start Stack Trace',value:createStackFrameEl(event.startStackFrame)});}else if(event [...]
+if(event.info){var descriptionEl=tr.ui.b.createDiv({textContent:event.info.description,maxWidth:'300px'});rows.push({name:'Description',value:descriptionEl});if(event.info.docLinks){event.info.docLinks.forEach(function(linkObject){var linkEl=document.createElement('a');linkEl.target='_blank';linkEl.href=linkObject.href;linkEl.textContent=linkObject.textContent;rows.push({name:linkObject.label,value:linkEl});});}}
+if(event.associatedAlerts.length){var alertSubRows=[];event.associatedAlerts.forEach(function(alert){var linkEl=document.createElement('tr-ui-a-analysis-link');linkEl.setSelectionAndContent(function(){return new tr.c.Selection(alert);},alert.info.description);alertSubRows.push({name:alert.title,value:linkEl});});rows.push({name:'Alerts',value:'',isExpanded:true,subRows:alertSubRows});}
+return rows;},addArgsToRows_:function(rows,args){var n=0;for(var argName in args){n+=1;}
+if(n>0){var subRows=[];for(var argName in args){var argView=document.createElement('tr-ui-a-generic-object-view');argView.object=args[argName];subRows.push({name:argName,value:argView});}
+rows.push({name:'Args',value:'',isExpanded:true,subRows:subRows});}
+return rows;},updateContents_:function(){if(this.currentSelection_===undefined){this.$.table.rows=[];this.$.table.rebuild();return;}
+var event=this.currentSelection_[0];var rows=this.getEventRows_(event);if(event.argsStripped)
+rows.push({name:'Args',value:'Stripped'});else
+this.addArgsToRows_(rows,event.args);this.$.table.tableRows=rows;this.$.table.rebuild();}});'use strict';tr.exportTo('tr.ui.analysis',function(){var FLOW_IN=0x1;var FLOW_OUT=0x2;var FLOW_IN_OUT=FLOW_IN|FLOW_OUT;function FlowClassifier(){this.numEvents_=0;this.eventsByGUID_={};}
+FlowClassifier.prototype={getFS_:function(event){var fs=this.eventsByGUID_[event.guid];if(fs===undefined){this.numEvents_++;fs={state:0,event:event};this.eventsByGUID_[event.guid]=fs;}
+return fs;},addInFlow:function(event){var fs=this.getFS_(event);fs.state|=FLOW_IN;return event;},addOutFlow:function(event){var fs=this.getFS_(event);fs.state|=FLOW_OUT;return event;},hasEvents:function(){return this.numEvents_>0;},get inFlowEvents(){var selection=new tr.c.Selection();for(var guid in this.eventsByGUID_){var fs=this.eventsByGUID_[guid];if(fs.state===FLOW_IN)
+selection.push(fs.event);}
+return selection;},get outFlowEvents(){var selection=new tr.c.Selection();for(var guid in this.eventsByGUID_){var fs=this.eventsByGUID_[guid];if(fs.state===FLOW_OUT)
+selection.push(fs.event);}
+return selection;},get internalFlowEvents(){var selection=new tr.c.Selection();for(var guid in this.eventsByGUID_){var fs=this.eventsByGUID_[guid];if(fs.state===FLOW_IN_OUT)
+selection.push(fs.event);}
+return selection;}};return{FlowClassifier:FlowClassifier};});'use strict';Polymer('tr-ui-a-related-events',{ready:function(){this.eventGroups_=[];this.$.table.tableColumns=[{title:'Event(s)',value:function(row){var typeEl=document.createElement('span');typeEl.innerText=row.type;if(row.tooltip)
+typeEl.title=row.tooltip;return typeEl;},width:'150px'},{title:'Link',width:'100%',value:function(row){var linkEl=document.createElement('tr-ui-a-analysis-link');if(row.name)
+linkEl.setSelectionAndContent(row.selection,row.name);else
+linkEl.selection=row.selection;return linkEl;}}];},hasRelatedEvents:function(){return(this.eventGroups_&&this.eventGroups_.length>0);},addRelatedEvents:function(selection){this.addConnectedFlows_(selection);this.addConnectedEvents_(selection);this.addAncestorsAndDescendents_(selection);this.updateContents_();},addConnectedFlows_:function(selection){var classifier=new tr.ui.analysis.FlowClassifier();selection.forEach(function(slice){if(slice.inFlowEvents){slice.inFlowEvents.forEach(functi [...]
+if(slice.outFlowEvents){slice.outFlowEvents.forEach(function(flow){classifier.addOutFlow(flow);});}});if(!classifier.hasEvents())
+return;var addToEventGroups=function(type,flowEvent){this.eventGroups_.push({type:type,selection:new tr.c.Selection(flowEvent),name:flowEvent.title});};classifier.inFlowEvents.forEach(addToEventGroups.bind(this,'Incoming flow'));classifier.outFlowEvents.forEach(addToEventGroups.bind(this,'Outgoing flow'));classifier.internalFlowEvents.forEach(addToEventGroups.bind(this,'Internal flow'));},addConnectedEvents_:function(selection){if(selection.length===1)
+this.addConnectedEventsForSlice_(selection[0]);else
+this.addConnectedEventsForSelection_(selection);},addAncestorsAndDescendents_:function(selection){if(selection.length===1)
+this.addAncestorsAndDescendentsForSlice_(selection[0]);else
+this.addAncestorsAndDescendentsForSelection_(selection);},addConnectedEventsForSlice_:function(slice){var precedingEventsSelection=undefined;var followingEventsSelection=undefined;if(slice.inFlowEvents&&slice.inFlowEvents.length!==0){precedingEventsSelection=new tr.c.Selection();this.recursivelyAddConnectedEvents_(precedingEventsSelection,slice,function(event){return event.inFlowEvents;});this.eventGroups_.push({type:'Preceding events',tooltip:'All preceding events connected to this one  [...]
+if(slice.outFlowEvents&&slice.outFlowEvents.length!==0){followingEventsSelection=new tr.c.Selection();this.recursivelyAddConnectedEvents_(followingEventsSelection,slice,function(event){return event.outFlowEvents;});this.eventGroups_.push({type:'Following events',tooltip:'All following events connected to this one by flow arrows.',selection:followingEventsSelection});}
+if(precedingEventsSelection&&followingEventsSelection){var allEventsSelection=new tr.c.Selection();for(var i=0;i<precedingEventsSelection.length;++i)
+allEventsSelection.push(precedingEventsSelection[i]);for(var i=0;i<followingEventsSelection.length;++i)
+allEventsSelection.push(followingEventsSelection[i]);this.eventGroups_.push({type:'All connected events',tooltip:'All events connected to this one by flow arrows.',selection:allEventsSelection});}},addConnectedEventsForSelection_:function(selection){var allEventsSelection=new tr.c.Selection();selection.forEach(function(slice){this.recursivelyAddConnectedEvents_(allEventsSelection,slice,function(event){var flows=[];if(event.inFlowEvents)
+flows=flows.concat(event.inFlowEvents);if(event.outFlowEvents)
+flows=flows.concat(event.outFlowEvents);return flows;});}.bind(this));if(allEventsSelection.length>selection.length){this.eventGroups_.push({type:'All connected events',tooltip:'All events connected to this selection by flow arrows.',selection:allEventsSelection});}},recursivelyAddConnectedEvents_:function(selection,event,getFlows){if(!event||selection.contains(event))
+return;selection.push(event);var flowEvents=getFlows(event);if(!flowEvents)
+return;for(var i=0;i<flowEvents.length;++i){selection.push(flowEvents[i]);this.recursivelyAddConnectedEvents_(selection,flowEvents[i].startSlice,getFlows);this.recursivelyAddConnectedEvents_(selection,flowEvents[i].endSlice,getFlows);}},addAncestorsAndDescendentsForSlice_:function(slice){if(!slice.iterateAllAncestors||!slice.iterateAllDescendents)
+return;var ancestorsSelection=new tr.c.Selection(slice);var descendentsSelection=new tr.c.Selection(slice);var allSlicesSelection=new tr.c.Selection(slice);slice.iterateAllAncestors(function(otherSlice){ancestorsSelection.push(otherSlice);});slice.iterateAllDescendents(function(otherSlice){descendentsSelection.push(otherSlice);});if(ancestorsSelection.length>1){this.eventGroups_.push({type:'Ancestors',tooltip:'All slices above this one on this thread.',selection:ancestorsSelection});}
+if(descendentsSelection.length>1){this.eventGroups_.push({type:'Descendents',tooltip:'All slices below this one on this thread.',selection:descendentsSelection});}
+if(ancestorsSelection.length>1&&descendentsSelection.length>1){for(var i=0;i<ancestorsSelection.length;++i)
+allSlicesSelection.push(ancestorsSelection[i]);for(var i=0;i<descendentsSelection.length;++i)
+allSlicesSelection.push(descendentsSelection[i]);this.eventGroups_.push({type:'Hierarchy',tooltip:'All slices above or below this one on this thread.',selection:allSlicesSelection});}},addAncestorsAndDescendentsForSelection_:function(selection){var allSlicesSelection=new tr.c.Selection();selection.forEach(function(slice){allSlicesSelection.push(slice);if(slice.iterateAllAncestors&&slice.iterateAllDescendents){slice.iterateAllAncestors(function(otherSlice){allSlicesSelection.push(otherSli [...]
+table.tableRows=[];else
+table.tableRows=this.eventGroups_.slice();table.rebuild();}});'use strict';Polymer('tr-ui-a-single-thread-slice-sub-view',{get selection(){return this.$.content.selection;},set selection(selection){this.$.content.selection=selection;this.$.relatedEvents.addRelatedEvents(selection);if(this.$.relatedEvents.hasRelatedEvents())
+this.$.relatedEvents.style.display='';else
+this.$.relatedEvents.style.display='none';}});'use strict';Polymer('tr-ui-a-selection-summary-table',{created:function(){this.selection_=new tr.b.Range();},ready:function(){this.$.table.showHeader=false;this.$.table.tableColumns=[{title:'Name',value:function(row){return row.title;},width:'350px'},{title:'Value',width:'100%',value:function(row){return row.value;}}];},get selection(){return this.selection_;},set selection(selection){this.selection_=selection;this.updateContents_();},update [...]
+hasRange=true;else
+hasRange=false;rows.push({title:'Selection start',value:hasRange?tr.ui.units.createTimeStampSpan(selection.bounds.min):'<empty>'});rows.push({title:'Selection extent',value:hasRange?tr.ui.units.createTimeSpan(selection.bounds.range):'<empty>'});this.$.table.tableRows=rows;this.$.table.rebuild();}});'use strict';tr.exportTo('tr.b',function(){function identity(d){return d;}
+function Statistics(){}
+Statistics.sum=function(ary,opt_func,opt_this){var func=opt_func||identity;var ret=0;for(var i=0;i<ary.length;i++)
+ret+=func.call(opt_this,ary[i],i);return ret;};Statistics.mean=function(ary,opt_func,opt_this){return Statistics.sum(ary,opt_func,opt_this)/ary.length;};Statistics.variance=function(ary,opt_func,opt_this){var func=opt_func||identity;var mean=Statistics.mean(ary,func,opt_this);var sumOfSquaredDistances=Statistics.sum(ary,function(d,i){var v=func.call(this,d,i)-mean;return v*v;},opt_this);return sumOfSquaredDistances/(ary.length-1);};Statistics.stddev=function(ary,opt_func,opt_this){return [...]
+ret=Math.max(ret,func.call(opt_this,ary[i],i));return ret;};Statistics.min=function(ary,opt_func,opt_this){var func=opt_func||identity;var ret=Infinity;for(var i=0;i<ary.length;i++)
+ret=Math.min(ret,func.call(opt_this,ary[i],i));return ret;};Statistics.range=function(ary,opt_func,opt_this){var func=opt_func||identity;var ret=new tr.b.Range();for(var i=0;i<ary.length;i++)
+ret.addValue(func.call(opt_this,ary[i],i));return ret;}
+Statistics.percentile=function(ary,percent,opt_func,opt_this){if(!(percent>=0&&percent<=1))
+throw new Error('percent must be [0,1]');var func=opt_func||identity;var tmp=new Array(ary.length);for(var i=0;i<ary.length;i++)
+tmp[i]=func.call(opt_this,ary[i],i);tmp.sort();var idx=Math.floor((ary.length-1)*percent);return tmp[idx];};return{Statistics:Statistics};});'use strict';tr.exportTo('tr.ui.analysis',function(){function MultiEventSummary(title,events){this.title=title;this.duration_=undefined;this.selfTime_=undefined;this.events_=events;this.cpuTimesComputed_=false;this.cpuSelfTime_=undefined;this.cpuDuration_=undefined;this.untotallableArgs_=[];this.totalledArgs_=undefined;};MultiEventSummary.prototype= [...]
+return this.duration_;},get cpuSelfTime(){this.computeCpuTimesIfNeeded_();return this.cpuSelfTime_;},get cpuDuration(){this.computeCpuTimesIfNeeded_();return this.cpuDuration_;},computeCpuTimesIfNeeded_:function(){if(this.cpuTimesComputed_)
+return;this.cpuTimesComputed_=true;var cpuSelfTime=0;var cpuDuration=0;var hasCpuData=false;for(var i=0;i<this.events_.length;i++){var event=this.events_[i];if(event.cpuDuration!==undefined){cpuDuration+=event.cpuDuration;hasCpuData=true;}
+if(event.cpuSelfTime!==undefined){cpuSelfTime+=event.cpuSelfTime;hasCpuData=true;}}
+if(hasCpuData){this.cpuDuration_=cpuDuration;this.cpuSelfTime_=cpuSelfTime;}},get selfTime(){if(this.selfTime_===undefined){this.selfTime_=0;for(var i=0;i<this.events_.length;i++){if(this.events_[i].selfTime!==undefined)
+this.selfTime_+=this.events[i].selfTime;}}
+return this.selfTime_;},get events(){return this.events_;},get numEvents(){return this.events_.length;},get numAlerts(){if(this.numAlerts_===undefined){this.numAlerts_=tr.b.Statistics.sum(this.events_,function(event){return event.associatedAlerts.length;});}
+return this.numAlerts_;},get untotallableArgs(){this.updateArgsIfNeeded_();return this.untotallableArgs_;},get totalledArgs(){this.updateArgsIfNeeded_();return this.totalledArgs_;},updateArgsIfNeeded_:function(){if(this.totalledArgs_!==undefined)
+return;var untotallableArgs={};var totalledArgs={};for(var i=0;i<this.events_.length;i++){var event=this.events_[i];for(var argName in event.args){var argVal=event.args[argName];var type=typeof argVal;if(type!=='number'){untotallableArgs[argName]=true;delete totalledArgs[argName];continue;}
+if(untotallableArgs[argName]){continue;}
+if(totalledArgs[argName]===undefined)
+totalledArgs[argName]=0;totalledArgs[argName]+=argVal;}}
+this.untotallableArgs_=tr.b.dictionaryKeys(untotallableArgs);this.totalledArgs_=totalledArgs;}};return{MultiEventSummary:MultiEventSummary};});'use strict';Polymer('tr-ui-a-multi-event-summary-table',{ready:function(){this.showTotals_=false;this.eventsHaveDuration_=true;this.eventsHaveSubRows_=true;this.eventsByTitle_=undefined;},updateTableColumns_:function(rows){var hasCpuData=false;var hasAlerts=false;rows.forEach(function(row){if(row.cpuDuration!==undefined)
+hasCpuData=true;if(row.cpuSelfTime!==undefined)
+hasCpuData=true;if(row.numAlerts)
+hasAlerts=true;});var columns=[];columns.push({title:'Name',value:function(row){if(row.title==='Totals')
+return'Totals';var linkEl=document.createElement('tr-ui-a-analysis-link');linkEl.setSelectionAndContent(function(){return new tr.c.Selection(row.events);},row.title);return linkEl;},width:'350px',cmp:function(rowA,rowB){return rowA.title.localeCompare(rowB.title);}});if(this.eventsHaveDuration_){columns.push({title:'Wall Duration (ms)',value:function(row){return tr.ui.units.createTimeSpan(row.duration);},width:'<upated further down>',cmp:function(rowA,rowB){return rowA.duration-rowB.dura [...]
+if(this.eventsHaveDuration_&&hasCpuData){columns.push({title:'CPU Duration (ms)',value:function(row){return tr.ui.units.createTimeSpan(row.cpuDuration);},width:'<upated further down>',cmp:function(rowA,rowB){return rowA.cpuDuration-rowB.cpuDuration;}});}
+if(this.eventsHaveSubRows_&&this.eventsHaveDuration_){columns.push({title:'Self time (ms)',value:function(row){return tr.ui.units.createTimeSpan(row.selfTime);},width:'<upated further down>',cmp:function(rowA,rowB){return rowA.selfTime-rowB.selfTime;}});}
+if(this.eventsHaveSubRows_&&this.eventsHaveDuration_&&hasCpuData){columns.push({title:'CPU Self Time (ms)',value:function(row){return tr.ui.units.createTimeSpan(row.cpuSelfTime);},width:'<upated further down>',cmp:function(rowA,rowB){return rowA.cpuSelfTime-rowB.cpuSelfTime;}});}
+columns.push({title:'Occurrences',value:function(row){return row.numEvents;},width:'<upated further down>',cmp:function(rowA,rowB){return rowA.numEvents-rowB.numEvents;}});var alertsColumnIndex;if(hasAlerts){columns.push({title:'Num Alerts',value:function(row){return row.numAlerts;},width:'<upated further down>',cmp:function(rowA,rowB){return rowA.numAlerts-rowB.numAlerts;}});alertsColumnIndex=columns.length-1;}
+var colWidthPercentage;if(columns.length==1)
+colWidthPercentage='100%';else
+colWidthPercentage=(100/(columns.length-1)).toFixed(3)+'%';for(var i=1;i<columns.length;i++)
+columns[i].width=colWidthPercentage;this.$.table.tableColumns=columns;if(hasAlerts){this.$.table.sortColumnIndex=alertsColumnIndex;this.$.table.sortDescending=true;}},configure:function(config){if(config.eventsByTitle===undefined)
+throw new Error('Required: eventsByTitle');if(config.showTotals!==undefined)
+this.showTotals_=config.showTotals;else
+this.showTotals_=true;if(config.eventsHaveDuration!==undefined)
+this.eventsHaveDuration_=config.eventsHaveDuration;else
+this.eventsHaveDuration_=true;if(config.eventsHaveSubRows!==undefined)
+this.eventsHaveSubRows_=config.eventsHaveSubRows;else
+this.eventsHaveSubRows_=true;this.eventsByTitle_=config.eventsByTitle;this.updateContents_();},get showTotals(){return this.showTotals_;},set showTotals(showTotals){this.showTotals_=showTotals;this.updateContents_();},get eventsHaveDuration(){return this.eventsHaveDuration_;},set eventsHaveDuration(eventsHaveDuration){this.eventsHaveDuration_=eventsHaveDuration;this.updateContents_();},get eventsHaveSubRows(){return this.eventsHaveSubRows_;},set eventsHaveSubRows(eventsHaveSubRows){this. [...]
+eventsByTitle=this.eventsByTitle_;else
+eventsByTitle=[];var allEvents=[];var rows=[];tr.b.iterItems(eventsByTitle,function(title,eventsOfSingleTitle){allEvents.push.apply(allEvents,eventsOfSingleTitle);var row=new tr.ui.analysis.MultiEventSummary(title,eventsOfSingleTitle);rows.push(row);});this.updateTableColumns_(rows);this.$.table.tableRows=rows;var footerRows=[];if(this.showTotals_){footerRows.push(new tr.ui.analysis.MultiEventSummary('Totals',allEvents));}
+this.$.table.footerRows=footerRows;this.$.table.rebuild();}});'use strict';Polymer('tr-ui-a-multi-event-details-table',{created:function(){this.selection_=undefined;this.eventsHaveDuration_=true;this.eventsHaveSubRows_=true;},ready:function(){this.initTitleTable_();},get eventsHaveDuration(){return this.eventsHaveDuration_;},set eventsHaveDuration(eventsHaveDuration){this.eventsHaveDuration_=eventsHaveDuration;this.updateContents_();},get eventsHaveSubRows(){return this.eventsHaveSubRows [...]
+var summary=new tr.ui.analysis.MultiEventSummary('Totals',this.selection_);this.updateColumns_(summary);this.updateRows_(summary);this.$.table.rebuild();},initTitleTable_:function(){var table=this.$.titletable;table.showHeader=false;table.tableColumns=[{title:'Title',value:function(row){return row.title;},width:'350px'},{title:'Value',width:'100%',value:function(row){return row.value;}}];},updateTitleTable_:function(){var title;if(this.selection_&&this.selection_.length)
+title=this.selection_[0].title;else
+title='<No selection>';var table=this.$.titletable;table.tableRows=[{title:'Title',value:title}];},updateColumns_:function(summary){var hasCpuData;if(summary.cpuDuration!==undefined)
+hasCpuData=true;if(summary.cpuSelfTime!==undefined)
+hasCpuData=true;var colWidthPercentage;if(hasCpuData)
+colWidthPercentage='20%';else
+colWidthPercentage='33.3333%';var columns=[];columns.push({title:'Start',value:function(row){if(row.__proto__===tr.ui.analysis.MultiEventSummary.prototype){return row.title;}
+var linkEl=document.createElement('tr-ui-a-analysis-link');linkEl.setSelectionAndContent(function(){return new tr.c.Selection(row.event);});linkEl.appendChild(tr.ui.units.createTimeStampSpan(row.start));return linkEl;},width:'350px',cmp:function(rowA,rowB){return rowA.start-rowB.start;}});if(this.eventsHaveDuration_){columns.push({title:'Wall Duration (ms)',value:function(row){return tr.ui.units.createTimeSpan(row.duration);},width:'<upated further down>',cmp:function(rowA,rowB){return r [...]
+if(this.eventsHaveDuration_&&hasCpuData){columns.push({title:'CPU Duration (ms)',value:function(row){return tr.ui.units.createTimeSpan(row.cpuDuration);},width:'<upated further down>',cmp:function(rowA,rowB){return rowA.cpuDuration-rowB.cpuDuration;}});}
+if(this.eventsHaveSubRows_&&this.eventsHaveDuration_){columns.push({title:'Self time (ms)',value:function(row){return tr.ui.units.createTimeSpan(row.selfTime);},width:'<upated further down>',cmp:function(rowA,rowB){return rowA.selfTime-rowB.selfTime;}});}
+if(this.eventsHaveSubRows_&&this.eventsHaveDuration_&&hasCpuData){columns.push({title:'CPU Self Time (ms)',value:function(row){return tr.ui.units.createTimeSpan(row.cpuSelfTime);},width:'<upated further down>',cmp:function(rowA,rowB){return rowA.cpuSelfTime-rowB.cpuSelfTime;}});}
+var argKeys=tr.b.dictionaryKeys(summary.totalledArgs);argKeys.sort();var otherKeys=summary.untotallableArgs.slice(0);otherKeys.sort();argKeys.push.apply(argKeys,otherKeys);var keysWithColumns=argKeys.slice(0,4);var keysInOtherColumn=argKeys.slice(4);keysWithColumns.forEach(function(argKey){var hasTotal=summary.totalledArgs[argKey];var colDesc={title:'Arg: '+argKey,value:function(row){if(row.__proto__!==tr.ui.analysis.MultiEventSummary.prototype){var argView=document.createElement('tr-ui- [...]
+if(hasTotal)
+return row.totalledArgs[argKey];return'';},width:'<upated further down>'};if(hasTotal){colDesc.cmp=function(rowA,rowB){return rowA.args[argKey]-rowB.args[argKey];}}
+columns.push(colDesc);});if(keysInOtherColumn.length){columns.push({title:'Other Args',value:function(row){if(row.__proto__===tr.ui.analysis.MultiEventSummary.prototype)
+return'';var argView=document.createElement('tr-ui-a-generic-object-view');var obj={};for(var i=0;i<keysInOtherColumn.length;i++)
+obj[keysInOtherColumn[i]]=row.args[keysInOtherColumn[i]];argView.object=obj;return argView;},width:'<upated further down>'});}
+var colWidthPercentage;if(columns.length==1)
+colWidthPercentage='100%';else
+colWidthPercentage=(100/(columns.length-1)).toFixed(3)+'%';for(var i=1;i<columns.length;i++)
+columns[i].width=colWidthPercentage;this.$.table.tableColumns=columns;},updateRows_:function(summary){this.$.table.sortColumnIndex=0;function Row(event){this.event=event;}
+Row.prototype={get start(){return this.event.start;},get duration(){return this.event.duration;},get cpuDuration(){return this.event.cpuDuration;},get selfTime(){return this.event.selfTime;},get cpuSelfTime(){return this.event.cpuSelfTime;},get args(){return this.event.args;}};this.$.table.tableRows=this.selection_.map(function(event){return new Row(event);});this.$.table.footerRows=[summary];}});'use strict';Polymer('tr-ui-a-multi-event-sub-view',{created:function(){this.currentSelectio [...]
+throw new Error('Only supports multiple items');this.setSelectionWithoutErrorChecks(selection);},get selection(){return this.currentSelection_;},setSelectionWithoutErrorChecks:function(selection){this.currentSelection_=selection;this.updateContents_();},get eventsHaveDuration(){return this.eventsHaveDuration_;},set eventsHaveDuration(eventsHaveDuration){this.eventsHaveDuration_=eventsHaveDuration;this.updateContents_();},get eventsHaveSubRows(){return this.eventsHaveSubRows_;},set events [...]
+return;var eventsByTitle=selection.getEventsOrganizedByTitle();var numTitles=tr.b.dictionaryLength(eventsByTitle);var summaryTableEl=document.createElement('tr-ui-a-multi-event-summary-table');summaryTableEl.configure({showTotals:numTitles>1,eventsByTitle:eventsByTitle,eventsHaveDuration:this.eventsHaveDuration_,eventsHaveSubRows:this.eventsHaveSubRows_});this.$.content.appendChild(summaryTableEl);var selectionSummaryTableEl=document.createElement('tr-ui-a-selection-summary-table');selec [...]
+this.$.content.textContent='';var mesv=document.createElement('tr-ui-a-multi-event-sub-view');mesv.selection=selection;this.$.content.appendChild(mesv);var relatedEvents=document.createElement('tr-ui-a-related-events');relatedEvents.addRelatedEvents(selection);if(relatedEvents.hasRelatedEvents()){this.$.content.appendChild(relatedEvents);}},get requiresTallView(){if(this.$.content.children.length===0)
+return false;var childTagName=this.$.content.children[0].tagName;if(childTagName==='TR-UI-A-MULTI-EVENT-SUB-VIEW')
+return false;return true;}});'use strict';Polymer('tr-ui-a-single-async-slice-sub-view',{getEventRows_:function(event){var rows=this.__proto__.__proto__.getEventRows_(event);rows.splice(0,0,{name:'ID',value:event.id});return rows;},get relatedEventsToHighlight(){if(!this.currentSelection_)
+return undefined;return this.currentSelection_[0].associatedEvents;}});'use strict';Polymer('tr-ui-a-multi-async-slice-sub-view',{get selection(){return this.$.content.selection;},set selection(selection){this.$.content.selection=selection;},get relatedEventsToHighlight(){if(!this.$.content.selection)
+return undefined;var selection=new tr.c.Selection();this.$.content.selection.forEach(function(asyncEvent){if(!asyncEvent.associatedEvents)
+return;asyncEvent.associatedEvents.forEach(function(event){selection.push(event);});});if(selection.length)
+return selection;return undefined;}});'use strict';Polymer('tr-ui-a-single-cpu-slice-sub-view',{created:function(){this.currentSelection_=undefined;},get selection(){return this.currentSelection_;},set selection(selection){if(selection.length!==1)
+throw new Error('Only supports single slices');if(!(selection[0]instanceof tr.model.CpuSlice))
+throw new Error('Only supports thread time slices');this.currentSelection_=selection;var cpuSlice=selection[0];var thread=cpuSlice.threadThatWasRunning;var shadowRoot=this.shadowRoot;if(thread){shadowRoot.querySelector('#process-name').textContent=thread.parent.userFriendlyName;shadowRoot.querySelector('#thread-name').textContent=thread.userFriendlyName;}else{shadowRoot.querySelector('#process-name').parentElement.style.display='none';shadowRoot.querySelector('#thread-name').textContent= [...]
+shadowRoot.querySelector('#start').textContent=tr.b.units.tsString(cpuSlice.start);shadowRoot.querySelector('#duration').textContent=tr.b.units.tsString(cpuSlice.duration);var runningThreadEl=shadowRoot.querySelector('#running-thread');var timeSlice=cpuSlice.getAssociatedTimeslice();if(!timeSlice){runningThreadEl.parentElement.style.display='none';}else{var threadLink=document.createElement('tr-ui-a-analysis-link');threadLink.selection=new tr.c.Selection(timeSlice);threadLink.textContent [...]
+shadowRoot.querySelector('#args').object=cpuSlice.args;}});'use strict';Polymer('tr-ui-a-multi-cpu-slice-sub-view',{ready:function(){this.$.content.eventsHaveSubRows=false;},get selection(){return this.$.content.selection;},set selection(selection){this.$.content.setSelectionWithoutErrorChecks(selection);}});'use strict';Polymer('tr-ui-a-single-thread-time-slice-sub-view',{created:function(){this.currentSelection_=undefined;},get selection(){return this.currentSelection_;},set selection( [...]
+throw new Error('Only supports single slices');if(!(selection[0]instanceof tr.model.ThreadTimeSlice))
+throw new Error('Only supports thread time slices');this.currentSelection_=selection;var timeSlice=selection[0];var thread=timeSlice.thread;var shadowRoot=this.shadowRoot;shadowRoot.querySelector('#state').textContent=timeSlice.title;var stateColor=tr.ui.b.getColorPalette()[timeSlice.colorId];shadowRoot.querySelector('#state').style.backgroundColor=stateColor;shadowRoot.querySelector('#process-name').textContent=thread.parent.userFriendlyName;shadowRoot.querySelector('#thread-name').text [...]
+cpuLink.textContent=cpuSliceThatTookCpu.thread.userFriendlyName;else
+cpuLink.textContent=cpuSliceThatTookCpu.title;runningInsteadEl.appendChild(cpuLink);}else{runningInsteadEl.parentElement.removeChild(runningInsteadEl);}}
+var argsEl=shadowRoot.querySelector('#args');if(tr.b.dictionaryKeys(timeSlice.args).length>0){var argsView=document.createElement('tr-ui-a-generic-object-view');argsView.object=timeSlice.args;argsEl.parentElement.style.display='';argsEl.textContent='';argsEl.appendChild(argsView);}else{argsEl.parentElement.style.display='none';}}});'use strict';Polymer('tr-ui-a-multi-thread-time-slice-sub-view',{ready:function(){this.$.content.eventsHaveSubRows=false;},get selection(){return this.$.conte [...]
+wrap.userFriendlyName=text;el.selection=wrap;if(opt_tooltip)
+el.title=opt_tooltip;return el;},appendElement_:function(parent,tagName,opt_text){var n=parent.ownerDocument.createElement(tagName);parent.appendChild(n);if(opt_text!=undefined)
+n.textContent=opt_text;return n;},appendText_:function(parent,text){var textElement=parent.ownerDocument.createTextNode(text);parent.appendChild(textNode);return textNode;},appendTableCell_:function(table,row,cellnum,text,opt_warning){var td=this.appendElement_(row,'td',text);td.className=table.className+'-col-'+cellnum;if(opt_warning){var span=document.createElement('span');span.textContent=' '+String.fromCharCode(9888);span.title=opt_warning;td.appendChild(span);}
+return td;},appendTableCell:function(table,row,text){return this.appendTableCell_(table,row,row.children.length,text);},appendTableCellWithTooltip_:function(table,row,cellnum,text,tooltip){if(tooltip){var td=this.appendElement_(row,'td');td.className=table.className+'-col-'+cellnum;var span=this.appendElement_(td,'span',text);span.className='tooltip';span.title=tooltip;return td;}else{return this.appendTableCell_(table,row,cellnum,text);}},appendHeader:function(label){var header=this.app [...]
+throw new Error('Only one header row allowed.');if(table.tbody||table.tfoot)
+throw new Error('Cannot add a header row after data rows have been added.');table.headerRow=this.appendElement_(this.appendElement_(table,'thead'),'tr');table.headerRow.className='analysis-table-header';return table.headerRow;},appendBodyRow:function(table){if(table.tfoot)
+throw new Error('Cannot add a tbody row after footer rows have been added.');if(!table.tbody)
+table.tbody=this.appendElement_(table,'tbody');var row=this.appendElement_(table.tbody,'tr');if(table.headerRow)
+row.className='analysis-table-row';else
+row.className='analysis-table-row-inverted';return row;},appendFootRow:function(table){if(!table.tfoot){table.tfoot=this.appendElement_(table,'tfoot');table.tfoot.rowsClassName=((table.headerRow?1:0)+
+(table.tbody?table.tbody.rows.length:0))%2?'analysis-table-row':'analysis-table-row-inverted';}
+var row=this.appendElement_(table.tfoot,'tr');row.className=table.tfoot.rowsClassName;return row;},appendSpacingRow:function(table,opt_inFoot){if(table.tfoot||opt_inFoot)
+var row=this.appendFootRow(table);else
+var row=this.appendBodyRow(table);for(var i=0;i<table.numColumns;i++)
+this.appendTableCell_(table,row,i,' ');},appendInfoRow:function(table,label,opt_value,opt_inFoot){if(table.tfoot||opt_inFoot)
+var row=this.appendFootRow(table);else
+var row=this.appendBodyRow(table);this.appendTableCell_(table,row,0,label);if(opt_value!==undefined){var objectView=document.createElement('tr-ui-a-generic-object-view');objectView.object=opt_value;objectView.classList.add('analysis-table-col-1');objectView.style.display='table-cell';row.appendChild(objectView);}else{this.appendTableCell_(table,row,1,'');}
+for(var i=2;i<table.numColumns;i++)
+this.appendTableCell_(table,row,i,'');},appendInfoRowTime:function(table,label,time,opt_inFoot,opt_warning){if(table.tfoot||opt_inFoot)
+var row=this.appendFootRow(table);else
+var row=this.appendBodyRow(table);this.appendTableCell_(table,row,0,label);this.appendTableCell_(table,row,1,tr.b.units.tsString(time),opt_warning);},appendDetailsRow:function(table,start,duration,selfTime,args,opt_selectionGenerator,opt_cpuDuration,opt_inFoot){if(opt_inFoot){var row=this.appendFootRow(table);this.appendTableCell(table,row,'Totals');}
+else{var row=this.appendBodyRow(table);if(opt_selectionGenerator){var labelEl=this.appendTableCell(table,row,tr.b.units.tsString(start));labelEl.textContent='';labelEl.appendChild(this.createSelectionChangingLink(tr.b.units.tsString(start),opt_selectionGenerator,''));}else{this.appendTableCell(table,row,tr.b.units.tsString(start));}}
+if(duration!==null)
+this.appendTableCell(table,row,tr.b.units.tsString(duration));if(opt_cpuDuration)
+this.appendTableCell(table,row,opt_cpuDuration!=''?tr.b.units.tsString(opt_cpuDuration):'');if(selfTime!==null)
+this.appendTableCell(table,row,tr.b.units.tsString(selfTime));var argsCell=this.appendTableCell(table,row,'');var n=0;for(var argName in args){n+=1;}
+if(n>0){for(var argName in args){var argVal=args[argName];var objectView=document.createElement('tr-ui-a-generic-object-view');objectView.object=argVal;var argsRow=this.appendElement_(this.appendElement_(argsCell,'table'),'tr');this.appendElement_(argsRow,'td',argName+':');this.appendElement_(argsRow,'td').appendChild(objectView);}}},appendDataRow:function(table,label,opt_duration,opt_cpuDuration,opt_selfTime,opt_cpuSelfTime,opt_occurrences,opt_percentage,opt_statistics,opt_selectionGene [...]
+tr.b.units.tsString(opt_statistics.min)+' \u000DMax Duration:\u0009'+
+tr.b.units.tsString(opt_statistics.max)+' \u000DAvg Duration:\u0009'+
+tr.b.units.tsString(opt_statistics.avg)+' (\u03C3 = '+stddevRounded+')';if(opt_statistics.start){tooltip+='\u000DStart Time:\u0009'+
+tr.b.units.tsString(opt_statistics.start);}
+if(opt_statistics.end){tooltip+='\u000DEnd Time:\u0009'+
+tr.b.units.tsString(opt_statistics.end);}
+if(opt_statistics.frequency&&opt_statistics.frequency_stddev){var fR=Math.round(opt_statistics.frequency*1000)/1000;var fSR=Math.round(opt_statistics.frequency_stddev*1000)/1000;tooltip+='\u000DFrequency:\u0009'+
+fR+' occurrences/s (\u03C3 = '+fSR+')';}}
+if(table.tfoot||opt_inFoot)
+var row=this.appendFootRow(table);else
+var row=this.appendBodyRow(table);var cellNum=0;if(!opt_selectionGenerator){this.appendTableCellWithTooltip_(table,row,cellNum,label,tooltip);}else{var labelEl=this.appendTableCellWithTooltip_(table,row,cellNum,label,tooltip);if(labelEl){labelEl.textContent='';labelEl.appendChild(this.createSelectionChangingLink(label,opt_selectionGenerator,tooltip));}}
+cellNum++;if(opt_duration!==null){if(opt_duration){if(opt_duration instanceof Array){this.appendTableCellWithTooltip_(table,row,cellNum,'['+opt_duration.join(', ')+']',tooltip);}else{this.appendTableCellWithTooltip_(table,row,cellNum,tr.b.units.tsString(opt_duration),tooltip);}}else{this.appendTableCell_(table,row,cellNum,'');}
+cellNum++;}
+if(opt_cpuDuration!==null){if(opt_cpuDuration!=''){this.appendTableCellWithTooltip_(table,row,cellNum,tr.b.units.tsString(opt_cpuDuration),tooltip);}else{this.appendTableCell_(table,row,cellNum,'');}
+cellNum++;}
+if(opt_selfTime!==null){if(opt_selfTime){this.appendTableCellWithTooltip_(table,row,cellNum,tr.b.units.tsString(opt_selfTime),tooltip);}else{this.appendTableCell_(table,row,cellNum,'');}
+cellNum++;}
+if(opt_cpuSelfTime!==null){if(opt_cpuSelfTime){this.appendTableCellWithTooltip_(table,row,cellNum,tr.b.units.tsString(opt_cpuSelfTime),tooltip);}else{this.appendTableCell_(table,row,cellNum,'');}
+cellNum++;}
+if(opt_percentage!==null){if(opt_percentage){this.appendTableCellWithTooltip_(table,row,cellNum,opt_percentage,tooltip);}else{this.appendTableCell_(table,row,cellNum,'');}
+cellNum++;}
+if(opt_occurrences){this.appendTableCellWithTooltip_(table,row,cellNum,String(opt_occurrences),tooltip);}else{this.appendTableCell_(table,row,cellNum,'');}
+cellNum++;}};return{AnalysisResults:AnalysisResults};});'use strict';(function(){var CounterSample=tr.model.CounterSample;Polymer('tr-ui-a-counter-sample-sub-view',{created:function(){this.currentSelection_=undefined;},get selection(){return this.currentSelection_;},set selection(selection){var results=new tr.ui.analysis.AnalysisResults();this.appendChild(results);this.analyzeCounterSamples_(results,selection);},analyzeCounterSamples_:function(results,allSamples){var samplesByCounter={}; [...]
+samplesByCounter[ctr.guid]=[];samplesByCounter[ctr.guid].push(allSamples[i]);}
+for(var guid in samplesByCounter){var samples=samplesByCounter[guid];var ctr=samples[0].series.counter;var timestampGroups=CounterSample.groupByTimestamp(samples);if(timestampGroups.length==1)
+this.analyzeSingleCounterTimestamp_(results,ctr,timestampGroups[0]);else
+this.analyzeMultipleCounterTimestamps_(results,ctr,timestampGroups);}},analyzeSingleCounterTimestamp_:function(results,ctr,samplesWithSameTimestamp){results.appendHeader('Selected counter:');var table=results.appendTable('analysis-counter-table',2);results.appendInfoRow(table,'Title',ctr.name);results.appendInfoRowTime(table,'Timestamp',samplesWithSameTimestamp[0].timestamp);for(var i=0;i<samplesWithSameTimestamp.length;i++){var sample=samplesWithSameTimestamp[i];results.appendInfoRow(ta [...]
+sampleIndices.push(samplesByTimestamp[i][0].getSampleIndex());var stats=ctr.getSampleStatistics(sampleIndices);for(var i=0;i<stats.length;i++){var samples=[];for(var k=0;k<sampleIndices.length;++k)
+samples.push(ctr.getSeries(i).getSample(sampleIndices[k]).value);results.appendDataRow(table,ctr.name+': series('+ctr.getSeries(i).name+')',samples,null,null,null,samples.length,null,stats[i]);}}});})();'use strict';Polymer('tr-ui-a-single-flow-event-sub-view',{getEventRows_:function(event){var rows=this.__proto__.__proto__.getEventRows_(event);rows.splice(0,0,{name:'ID',value:event.id});function createLinkTo(slice){var linkEl=document.createElement('tr-ui-a-analysis-link');linkEl.setSel [...]
+rows.push({name:'From',value:createLinkTo(event.startSlice)});rows.push({name:'To',value:createLinkTo(event.endSlice)});return rows;}});'use strict';Polymer('tr-ui-a-multi-flow-event-sub-view',{ready:function(){this.$.content.eventsHaveDuration=false;this.$.content.eventsHaveSubRows=false;},set selection(selection){this.$.content.selection=selection;},get selection(){return this.$.content.selection;}});'use strict';tr.exportTo('tr.ui.analysis',function(){var ObjectInstanceView=tr.ui.b.de [...]
+return false;if(this.$.content.children[0]instanceof
+tr.ui.analysis.ObjectInstanceView)
+return this.$.content.children[0].requiresTallView;},get selection(){return this.currentSelection_;},set selection(selection){if(selection.length!==1)
+throw new Error('Only supports single item selections');if(!(selection[0]instanceof tr.model.ObjectInstance))
+throw new Error('Only supports object instances');this.$.content.textContent='';this.currentSelection_=selection;var instance=selection[0];var typeInfo=tr.ui.analysis.ObjectInstanceView.getTypeInfo(instance.category,instance.typeName);if(typeInfo){var customView=new typeInfo.constructor();this.$.content.appendChild(customView);customView.modelEvent=instance;}else{this.appendGenericAnalysis_(instance);}},appendGenericAnalysis_:function(instance){var html='';html+='<div class="title">'+
+instance.typeName+' '+
+instance.id+'</div>\n';html+='<table>';html+='<tr>';html+='<tr><td>creationTs:</td><td>'+
+instance.creationTs+'</td></tr>\n';if(instance.deletionTs!=Number.MAX_VALUE){html+='<tr><td>deletionTs:</td><td>'+
+instance.deletionTs+'</td></tr>\n';}else{html+='<tr><td>deletionTs:</td><td>not deleted</td></tr>\n';}
+html+='<tr><td>snapshots:</td><td id="snapshots"></td></tr>\n';html+='</table>';this.$.content.innerHTML=html;var snapshotsEl=this.$.content.querySelector('#snapshots');instance.snapshots.forEach(function(snapshot){var snapshotLink=document.createElement('tr-ui-a-analysis-link');snapshotLink.selection=new tr.c.Selection(snapshot);snapshotsEl.appendChild(snapshotLink);});}});'use strict';tr.exportTo('tr.ui.analysis',function(){var ObjectSnapshotView=tr.ui.b.define('object-snapshot-view'); [...]
+return false;if(this.children[0]instanceof tr.ui.analysis.ObjectSnapshotView)
+return this.children[0].requiresTallView;},get selection(){return this.currentSelection_;},set selection(selection){if(selection.length!==1)
+throw new Error('Only supports single item selections');if(!(selection[0]instanceof tr.model.ObjectSnapshot))
+throw new Error('Only supports object instances');this.textContent='';this.currentSelection_=selection;var snapshot=selection[0];var typeInfo=tr.ui.analysis.ObjectSnapshotView.getTypeInfo(snapshot.objectInstance.category,snapshot.objectInstance.typeName);if(typeInfo){var customView=new typeInfo.constructor();this.appendChild(customView);customView.modelEvent=snapshot;}else{this.appendGenericAnalysis_(snapshot);}},appendGenericAnalysis_:function(snapshot){var instance=snapshot.objectInsta [...]
+tr.b.units.tsString(snapshot.ts)+'</div>\n';html+='<table>';html+='<tr>';html+='<tr><td>args:</td><td id="args"></td></tr>\n';html+='</table>';this.innerHTML=html;var instanceLinkEl=document.createElement('tr-ui-a-analysis-link');instanceLinkEl.selection=new tr.c.Selection(instance);var tmp=this.querySelector('#instance-link');tmp.parentElement.replaceChild(instanceLinkEl,tmp);var argsEl=this.querySelector('#args');argsEl.textContent='';var objectView=document.createElement('tr-ui-a-gene [...]
+return tr.ui.units.createTimeStampSpan(event.ts);var spanEl=document.createElement('span');spanEl.appendChild(tr.ui.units.createTimeStampSpan(event.creationTs));spanEl.appendChild(tr.ui.b.createSpan({textContent:'-',marginLeft:'4px',marginRight:'4px'}));if(event.deletionTs!=Number.MAX_VALUE){spanEl.appendChild(tr.ui.units.createTimeStampSpan(event.deletionTs));}
+return spanEl;},width:'200px'},{title:'Second',value:function(event){var linkEl=document.createElement('tr-ui-a-analysis-link');linkEl.setSelectionAndContent(function(){return new tr.c.Selection(event);},event.userFriendlyName);return linkEl;},width:'100%'}];table.tableRows=objectEvents;table.rebuild();}});'use strict';Polymer('tr-ui-a-single-sample-sub-view',{created:function(){this.currentSelection_=undefined;},ready:function(){this.$.content.tableColumns=[{title:'FirstColumn',value:fu [...]
+var sample=this.currentSelection_[0];var table=this.$.content;var rows=[];rows.push({title:'Title',value:sample.title});rows.push({title:'Sample time',value:tr.ui.units.createTimeStampSpan(sample.start)});var sfEl=document.createElement('tr-ui-a-stack-frame');sfEl.stackFrame=sample.leafStackFrame;rows.push({title:'Stack trace',value:sfEl});table.tableRows=rows;table.rebuild();}});'use strict';Polymer('tr-ui-a-multi-sample-sub-view',{created:function(){this.currentSelection_=undefined;},g [...]
+return undefined;return this.currentSelection_[0].associatedEvents;}});'use strict';Polymer('tr-ui-a-multi-interaction-record-sub-view',{created:function(){this.currentSelection_=undefined;},set selection(selection){this.currentSelection_=selection;this.textContent='';var realView=document.createElement('tr-ui-a-multi-event-sub-view');this.appendChild(realView);realView.setSelectionWithoutErrorChecks(selection);this.currentSelection_=selection;},get selection(){return this.currentSelecti [...]
+return undefined;var selection=new tr.c.Selection();this.currentSelection_.forEach(function(ir){ir.associatedEvents.forEach(function(event){selection.push(event);});});return selection;}});'use strict';Polymer('tr-ui-a-alert-sub-view',{ready:function(){this.currentSelection_=undefined;this.$.table.tableColumns=[{title:'Label',value:function(row){return row.name;},width:'150px'},{title:'Value',width:'100%',value:function(row){return row.value;}}];this.$.table.showHeader=false;},get select [...]
+if(alert.associatedEvents.length){alert.associatedEvents.forEach(function(event,i){var linkEl=document.createElement('tr-ui-a-analysis-link');linkEl.setSelectionAndContent(function(){return event;},event.title);var valueString='';if(event instanceof tr.model.TimedEvent)
+valueString='took '+event.duration.toFixed(2)+'ms';rows.push({name:linkEl,value:valueString});});}
+var descriptionEl=tr.ui.b.createDiv({textContent:alert.info.description,maxWidth:'300px'});rows.push({name:'Description',value:descriptionEl});if(alert.info.docLinks){alert.info.docLinks.forEach(function(linkObject){var linkEl=document.createElement('a');linkEl.target='_blank';linkEl.href=linkObject.href;linkEl.textContent=linkObject.textContent;rows.push({name:linkObject.label,value:linkEl});});}
+return rows;},getRowsForAlerts_:function(alerts){if(alerts.length==1){var rows=[{name:'Alert',value:alerts[0].title}];var detailRows=this.getRowsForSingleAlert_(alerts[0]);rows.push.apply(rows,detailRows);return rows;}else{return alerts.map(function(alert){return{name:'Alert',value:alert.title,isExpanded:alerts.size<10,subRows:this.getRowsForSingleAlert_(alert)};},this);}},updateContents_:function(){if(this.currentSelection_===undefined){this.$.table.rows=[];this.$.table.rebuild();return;}
+var alerts=this.currentSelection_;this.$.table.tableRows=this.getRowsForAlerts_(alerts);this.$.table.rebuild();}});'use strict';Polymer('tr-ui-a-single-frame-sub-view',{ready:function(){this.currentSelection_=undefined;},get selection(){return this.currentSelection_;},set selection(selection){if(selection.length!=1)
+throw new Error('Only supports single frame!');this.currentSelection_=selection;this.$.asv.selection=selection[0].associatedAlerts;},get relatedEventsToHighlight(){if(!this.currentSelection_)
+return undefined;return this.currentSelection_[0].associatedEvents;}});'use strict';Polymer('tr-ui-a-multi-frame-sub-view',{created:function(){this.currentSelection_=undefined;},set selection(selection){this.textContent='';var realView=document.createElement('tr-ui-a-multi-event-sub-view');realView.eventsHaveDuration=false;realView.eventsHaveSubRows=false;this.appendChild(realView);realView.setSelectionWithoutErrorChecks(selection);this.currentSelection_=selection;},get selection(){retur [...]
+return undefined;var selection=new tr.c.Selection();this.currentSelection_.forEach(function(frameEvent){frameEvent.associatedEvents.forEach(function(event){selection.push(event);});});return selection;}});'use strict';Polymer('tr-ui-b-color-legend',{ready:function(){var blackSquareCharCode=9632;this.$.square.innerText=String.fromCharCode(blackSquareCharCode);this.label_=undefined;},get label(){return this.label_;},set label(label){this.label_=label;if(this.label_===undefined){this.$.squa [...]
+var paletteRaw=tr.ui.b.getRawColorPalette();var colorId=tr.ui.b.getColorIdForGeneralPurposeString(this.label_);var color=tr.ui.b.colorToRGBString(paletteRaw[colorId]);this.$.square.style.color=color;this.$.label.innerText=this.label_;}});'use strict';tr.exportTo('tr.ui.analysis',function(){function MemoryColumn(name,title,units,cellGetter){this.name=name;this.title=title;this.units=units;this.cell=cellGetter;this.color=undefined;}
+MemoryColumn.fromRows=function(rows,cellKey,opt_titleBuilder){var columnTraits={};function gatherTraits(row){if(row===undefined)
+return;var attrCells=row[cellKey];tr.b.iterItems(attrCells,function(attrName,attrCell){if(attrCell===undefined)
+return;var attrValue=attrCell.attr;if(attrValue===undefined)
+return;var existingTraits=columnTraits[attrName];if(existingTraits===undefined){columnTraits[attrName]={constructor:attrValue.constructor,units:attrValue.units};return;}
+if(existingTraits.constructor!==attrValue.constructor||existingTraits.units!==attrValue.units){existingTraits.constructor=tr.model.UnknownAttribute;existingTraits.units=undefined;}});if(row.subRows!==undefined)
+row.subRows.forEach(gatherTraits);};rows.forEach(gatherTraits);var titleBuilder=opt_titleBuilder||tr.b.identity;var columns=[];tr.b.iterItems(columnTraits,function(columnName,columnTraits){var cellGetter=fieldGetter(cellKey,columnName);var title=titleBuilder(columnName);columns.push(MemoryColumn.fromAttributeTraits(columnName,title,columnTraits,cellGetter));});return columns;};MemoryColumn.fromAttributeTraits=function(name,title,traits,cellGetter){var constructor;if(traits.constructor=== [...]
+constructor=ScalarMemoryColumn;else
+constructor=MemoryColumn;return new constructor(name,title,traits.units,cellGetter);};MemoryColumn.spaceEqually=function(columns){var columnWidth=(100/columns.length).toFixed(3)+'%';columns.forEach(function(column){column.width=columnWidth;});};MemoryColumn.sortByImportance=function(columns,importanceRules){var positions=columns.map(function(column,srcIndex){return{importance:column.getImportance(importanceRules),srcIndex:srcIndex,column:column};});positions.sort(function(a,b){if(a.impor [...]
+return a.srcIndex-b.srcIndex;return b.importance-a.importance;});positions.forEach(function(position,dstIndex){columns[dstIndex]=position.column;});};MemoryColumn.iconFromAttributeInfoType=function(type){switch(type){case tr.model.AttributeInfoType.WARNING:return{symbol:String.fromCharCode(9888),color:'red'};case tr.model.AttributeInfoType.LINK:return{symbol:String.fromCharCode(9903)};default:return{symbol:String.fromCharCode(9432),color:'blue'};}
+throw new Error('Unreachable');};MemoryColumn.prototype={attr:function(row){var cell=this.cell(row);if(cell===undefined)
+return undefined;return cell.attr;},value:function(row){var attr=this.attr(row);if(attr===undefined)
+return'';return this.formatDefinedAttribute(attr);},formatDefinedAttribute:function(attr){var formattedValue=this.formatDefinedAttributeValue(attr);var color;if(typeof this.color==='function')
+color=this.color(attr);else
+color=this.color;if(color===undefined&&attr.infos.length===0)
+return formattedValue;var attrEl=document.createElement('span');attrEl.style.display='flex';attrEl.style.alignItems='center';attrEl.appendChild(tr.ui.b.asHTMLOrTextNode(formattedValue));attr.infos.forEach(function(info){var infoEl=document.createElement('span');infoEl.style.paddingLeft='4px';infoEl.style.cursor='help';infoEl.style.fontWeight='bold';var icon=MemoryColumn.iconFromAttributeInfoType(info.type);infoEl.textContent=icon.symbol;if(icon.color!==undefined)
+infoEl.style.color=icon.color;infoEl.title=info.message;attrEl.appendChild(infoEl);},this);if(color!==undefined)
+attrEl.style.color=color;return attrEl;},formatDefinedAttributeValue:function(attr){return String(attr.value);},cmp:function(rowA,rowB){var attrA=this.attr(rowA);var attrB=this.attr(rowB);if(attrA===undefined&&attrB===undefined)
+return 0;if(attrA===undefined)
+return-1;if(attrB===undefined)
+return 1;return this.compareDefinedAttributes(attrA,attrB);},compareDefinedAttributes:function(attrA,attrB){var strA=String(attrA.value);var strB=String(attrB.value);return strA.localeCompare(strB);},getImportance:function(importanceRules){if(importanceRules.length===0)
+return 0;for(var i=0;i<importanceRules.length;i++){var importanceRule=importanceRules[i];if(this.matchesNameCondition(importanceRule.condition))
+return importanceRule.importance;}
+var minImportance=importanceRules[0].importance;for(var i=1;i<importanceRules.length;i++){minImportance=Math.min(minImportance,importanceRules[i].importance);}
+return minImportance-1;},matchesNameCondition:function(condition){if(condition===undefined)
+return true;if(typeof(condition)==='string')
+return this.name===condition;return condition.test(this.name);}};function ScalarMemoryColumn(name,title,units,cellGetter){MemoryColumn.call(this,name,title,units,cellGetter);}
+ScalarMemoryColumn.prototype={__proto__:MemoryColumn.prototype,formatDefinedAttributeValue:function(attr){if(this.units==='bytes'){var sizeEl=document.createElement('tr-ui-u-size-in-bytes-span');sizeEl.numBytes=attr.value;return sizeEl;}
+return MemoryColumn.prototype.formatDefinedAttributeValue.call(this,attr);},compareDefinedAttributes:function(attrA,attrB){return attrA.value-attrB.value;}};function MemoryCell(attr){this.attr=attr;}
+MemoryCell.extractAttribute=function(cell){if(cell===undefined)
+return undefined;return cell.attr;};function fieldGetter(){var fields=tr.b.asArray(arguments);return function(row){var value=row;for(var i=0;i<fields.length;i++)
+value=value[fields[i]];return value;};}
+var RECURSIVE_EXPANSION_MAX_SUB_ROW_COUNT=10;function expandTableRowsRecursively(table){function expandRowRecursively(row){if(row.subRows===undefined||row.subRows.length===0)
+return;if(row.subRows.length>RECURSIVE_EXPANSION_MAX_SUB_ROW_COUNT)
+return;table.setExpandedForTableRow(row,true);row.subRows.forEach(expandRowRecursively);}
+table.tableRows.forEach(expandRowRecursively);}
+function aggregateTableRowCellsRecursively(row,cellKey){var subRows=row.subRows;if(subRows===undefined)
+return;subRows.forEach(function(subRow){aggregateTableRowCellsRecursively(subRow,cellKey);});aggregateTableRowCells(row,subRows,cellKey);}
+function aggregateTableRowCells(row,subRows,cellKey){var rowCells=row[cellKey];if(rowCells===undefined)
+row[cellKey]=rowCells={};var subRowCellNames={};subRows.forEach(function(subRow){var subRowCells=subRow[cellKey];if(subRowCells===undefined)
+return;tr.b.iterItems(subRowCells,function(columnName){subRowCellNames[columnName]=true;});});tr.b.iterItems(subRowCellNames,function(cellName){var subRowAttributes=subRows.map(function(subRow){var subRowCells=subRow[cellKey];if(subRowCells===undefined)
+return undefined;return MemoryCell.extractAttribute(subRowCells[cellName]);},this);var existingRowCell=rowCells[cellName];var existingRowAttribute=MemoryCell.extractAttribute(existingRowCell);var aggregatedAttribute=tr.model.Attribute.aggregate(subRowAttributes,existingRowAttribute);if(existingRowCell!==undefined){existingRowCell.attr=aggregatedAttribute;}else{rowCells[cellName]=new MemoryCell(aggregatedAttribute);}});}
+return{MemoryColumn:MemoryColumn,ScalarMemoryColumn:ScalarMemoryColumn,MemoryCell:MemoryCell,fieldGetter:fieldGetter,expandTableRowsRecursively:expandTableRowsRecursively,aggregateTableRowCellsRecursively:aggregateTableRowCellsRecursively,aggregateTableRowCells:aggregateTableRowCells};});'use strict';(function(){var IMPORTANCE_RULES=[{condition:'size',importance:10},{condition:'page_size',importance:0},{condition:/size/,importance:5},{importance:0}];Polymer('tr-ui-a-memory-dump-allocator [...]
+var rows=this.createRows_();var columns=this.createColumns_(rows);var table=this.ownerDocument.createElement('tr-ui-b-table');this.$.contents.appendChild(table);table.supportsSelection=true;table.tableRows=rows;table.tableColumns=columns;table.rebuild();tr.ui.analysis.expandTableRowsRecursively(table);},createRows_:function(){var createAllocatorRow=function(allocatorDump){var cells=tr.b.mapItems(allocatorDump.attributes,function(attrName,attrValue){return new tr.ui.analysis.MemoryCell(at [...]
+row.subRows=allocatorDump.children.map(createAllocatorRow);return row;};var rows=[createAllocatorRow(this.memoryAllocatorDump_)];return rows;},createColumns_:function(rows){var titleColumn={title:'Allocator',value:function(row){return row.title;},width:'200px',cmp:function(rowA,rowB){return rowA.title.localeCompare(rowB.title);}};var attributeColumns=tr.ui.analysis.MemoryColumn.fromRows(rows,'cells');tr.ui.analysis.MemoryColumn.spaceEqually(attributeColumns);tr.ui.analysis.MemoryColumn.s [...]
+row.subRows=rule.children.map(createEmptyRow);return row;}
+function hexString(address,is64BitAddress){var hexPadding=is64BitAddress?'0000000000000000':'00000000';if(address===undefined)
+return undefined;return(hexPadding+address.toString(16)).substr(-hexPadding.length);}
+function classifyVMRegion(row,vmRegion,is64BitAddress){var rule=row.rule;if(rule===undefined||rule.children===undefined||rule.children.length===0){var mappedFile=vmRegion.mappedFile||'';var cells={};function addCellIfValueDefined(columnName,attrClass,units,value){if(value===undefined)
+return;var attr=new attrClass(units,value);var cell=new tr.ui.analysis.MemoryCell(attr);cells[columnName]=cell;}
+function addBytesCellIfValueDefined(columnName,value){addCellIfValueDefined(columnName,tr.model.ScalarAttribute,'bytes',value);}
+addCellIfValueDefined('Start address',tr.model.StringAttribute,'',hexString(vmRegion.startAddress,is64BitAddress));addBytesCellIfValueDefined('Virtual size',vmRegion.sizeInBytes);addCellIfValueDefined('Protection flags',tr.model.StringAttribute,'',vmRegion.protectionFlagsToString);addBytesCellIfValueDefined('PSS',vmRegion.byteStats.proportionalResident);addBytesCellIfValueDefined('Private dirty',vmRegion.byteStats.privateDirtyResident);addBytesCellIfValueDefined('Private clean',vmRegion. [...]
+function vmRegionMatchesChildRule(childRule){var fileRegExp=childRule.file;if(fileRegExp===undefined)
+return true;return fileRegExp.test(vmRegion.mappedFile);}
+var matchedChildRuleIndex=tr.b.findFirstIndexInArray(rule.children,vmRegionMatchesChildRule);if(matchedChildRuleIndex===-1){matchedChildRuleIndex=rule.children.length;if(matchedChildRuleIndex>=row.subRows.length){row.subRows.push({title:'Other',cells:{},subRows:[]});}}
+classifyVMRegion(row.subRows[matchedChildRuleIndex],vmRegion,is64BitAddress);}
+Polymer('tr-ui-a-memory-dump-vm-regions-details-pane',{created:function(){this.vmRegions_=undefined;},ready:function(){this.updateContents_();},set vmRegions(vmRegions){this.vmRegions_=vmRegions;this.updateContents_();},get vmRegions(){return this.vmRegions_;},updateContents_:function(){this.$.contents.textContent='';if(this.vmRegions_===undefined){var infoText=this.ownerDocument.createElement('div');this.$.contents.appendChild(infoText);infoText.classList.add('info-text');infoText.inner [...]
+var rows=this.createRows_();var columns=this.createColumns_(rows);var table=this.ownerDocument.createElement('tr-ui-b-table');this.$.contents.appendChild(table);table.supportsSelection=true;table.tableRows=rows;table.tableColumns=columns;table.rebuild();tr.ui.analysis.expandTableRowsRecursively(table);},createRows_:function(){var is64BitAddress=this.vmRegions_.some(function(vmRegion){if(vmRegion.startAddress===undefined)
+return;return vmRegion.startAddress>=4294967296;});var rootRow=createEmptyRow(CLASSIFICATION_RULES);this.vmRegions_.map(function(vmRegion){classifyVMRegion(rootRow,vmRegion,is64BitAddress);});tr.ui.analysis.aggregateTableRowCellsRecursively(rootRow,'cells');return[rootRow];},createColumns_:function(rows){var titleColumn={title:'Mapped file',value:function(row){return row.title;},width:'200px',cmp:function(rowA,rowB){return rowA.title.localeCompare(rowB.title);}};var attributeColumns=tr.u [...]
+return undefined;var selectedColumnIndex=this.$.table.selectedColumnIndex;if(selectedColumnIndex===undefined)
+return undefined;var selectedColumn=this.$.table.tableColumns[selectedColumnIndex];var selectedMemoryCell=selectedColumn.cell(selectedTableRow);return selectedMemoryCell;},updateContents_:function(){var processMemoryDumps=this.processMemoryDumps_||[];var rows=processMemoryDumps.map(function(processMemoryDump){function buildVMRegionsPane(){var pane=document.createElement('tr-ui-a-memory-dump-vm-regions-details-pane');pane.vmRegions=processMemoryDump.mostRecentVmRegions;return pane;}
+var usedMemorySizes={};var totalResident=processMemoryDump.totalResidentBytes;if(totalResident!==undefined){var cell=new tr.ui.analysis.MemoryCell(new tr.model.ScalarAttribute('bytes',totalResident));cell.buildDetailsPane=buildVMRegionsPane;usedMemorySizes['Total resident']=cell;}
+function addByteStatCell(byteStatName,columnTitle){var byteStat=processMemoryDump.getMostRecentTotalVmRegionStat(byteStatName);if(byteStat!==undefined){var attr=new tr.model.ScalarAttribute('bytes',byteStat);if(!processMemoryDump.hasOwnVmRegions){attr.infos.push(new tr.model.AttributeInfo(tr.model.AttributeInfoType.LINK,'Older value (process did not dump memory maps).'));attr.isOlderValue=true;}
+var cell=new tr.ui.analysis.MemoryCell(attr);cell.buildDetailsPane=buildVMRegionsPane;usedMemorySizes[columnTitle]=cell;}}
+addByteStatCell('proportionalResident','PSS');addByteStatCell('privateDirtyResident','Private dirty');addByteStatCell('swapped','Swapped');var allocatorSizes={};if(processMemoryDump.memoryAllocatorDumps!==undefined){processMemoryDump.memoryAllocatorDumps.forEach(function(dump){var attr=dump.attributes['size'];var cell=new tr.ui.analysis.MemoryCell(attr);cell.buildDetailsPane=function(){var pane=document.createElement('tr-ui-a-memory-dump-allocator-details-pane');pane.memoryAllocatorDump= [...]
+return{title:processMemoryDump.process.userFriendlyName,usedMemorySizes:usedMemorySizes,allocatorSizes:allocatorSizes};},this);this.$.table.tableRows=rows;if(rows.length>1){var totalRow={title:'Total',noLegend:true};tr.ui.analysis.aggregateTableRowCells(totalRow,rows,'usedMemorySizes');tr.ui.analysis.aggregateTableRowCells(totalRow,rows,'allocatorSizes');this.$.table.footerRows=[totalRow];}
+this.updateColumns_(rows);this.$.table.rebuild();this.restoreSelection_();},updateColumns_:function(rows){var titleColumn={title:'Process',value:function(row){if(row.noLegend)
+return row.title;var titleEl=document.createElement('tr-ui-b-color-legend');titleEl.label=row.title;return titleEl;},width:'200px',cmp:function(rowA,rowB){return rowA.title.localeCompare(rowB.title);},supportsCellSelection:false};var usedMemorySizeColumns=tr.ui.analysis.MemoryColumn.fromRows(rows,'usedMemorySizes');var allocatorSizeColumns=tr.ui.analysis.MemoryColumn.fromRows(rows,'allocatorSizes',function(allocatorName){var titleEl=document.createElement('tr-ui-b-color-legend');titleEl. [...]
+usedMemorySizeColumns.forEach(function(column){var olderUsedMemoryColumnColor=tr.ui.b.getColorPalette()[tr.ui.b.getColorIdForReservedName('older_used_memory_column')];var usedMemoryColumnColor=tr.ui.b.getColorPalette()[tr.ui.b.getColorIdForReservedName('used_memory_column')];column.title=tr.ui.b.createSpan({textContent:column.title,color:usedMemoryColumnColor});column.color=function(attr){return attr.isOlderValue?olderUsedMemoryColumnColor:usedMemoryColumnColor;}});var sizeColumns=usedMe [...]
+selectedRowTitle=selectedRow.title;var selectedColumnName;var selectedColumnIndex=this.$.table.selectedColumnIndex;if(selectedColumnIndex!==undefined){var selectedColumn=this.$.table.tableColumns[selectedColumnIndex];selectedColumnName=selectedColumn.name;}
+tr.b.SessionSettings.set(SETTINGS_KEY,{rowTitle:selectedRowTitle,columnName:selectedColumnName},SETTINGS_NAMESPACE);},restoreSelection_:function(){var settings=tr.b.SessionSettings.get(SETTINGS_KEY,{},SETTINGS_NAMESPACE);if(settings.rowTitle===undefined||settings.columnName===undefined)
+return;var selectedColumnName=settings.columnName;var selectedColumnIndex=tr.b.findFirstIndexInArray(this.$.table.tableColumns,function(column){return column.name===selectedColumnName;});if(selectedColumnIndex<0)
+return;var selectedRowTitle=settings.rowTitle;var selectedRow=tr.b.findFirstInArray(this.$.table.tableRows,function(row){return row.title===selectedRowTitle;});if(selectedRow===undefined)
+return;this.$.table.selectedTableRow=selectedRow;this.$.table.selectedColumnIndex=selectedColumnIndex;}});})();'use strict';Polymer('tr-ui-a-memory-dump-view',{created:function(){this.processMemoryDumps_=undefined;},ready:function(){this.$.overview_pane.addEventListener('selected-memory-cell-changed',this.updateDetailsPane_.bind(this));},set processMemoryDumps(processMemoryDumps){this.processMemoryDumps_=processMemoryDumps;this.$.overview_pane.processMemoryDumps=this.processMemoryDumps_; [...]
+return;this.$.details_pane_container.appendChild(selectedMemoryCell.buildDetailsPane());}});'use strict';Polymer('tr-ui-a-single-process-memory-dump-sub-view',{set selection(selection){if(selection.length!==1)
+throw new Error('Only supports a single process memory dump');if(!(selection[0]instanceof tr.model.ProcessMemoryDump))
+throw new Error('Only supports process memory dumps');this.currentSelection_=selection;this.$.memory_dump_view.processMemoryDumps=[selection[0]];},get selection(){return this.currentSelection_;},get requiresTallView(){return true;}});'use strict';Polymer('tr-ui-a-multi-process-memory-dump-sub-view',{created:function(){this.currentSelection_=undefined;},get selection(){return this.currentSelection_;},set selection(selection){this.currentSelection_=selection;selection=tr.b.asArray(selectio [...]
+throw new Error('Only supports a single global memory dump');if(!(selection[0]instanceof tr.model.GlobalMemoryDump))
+throw new Error('Only supports global memory dumps');this.currentSelection_=selection;this.$.memory_dump_view.processMemoryDumps=tr.b.dictionaryValues(selection[0].processMemoryDumps);},get selection(){return this.currentSelection_;},get requiresTallView(){return true;}});'use strict';Polymer('tr-ui-a-multi-global-memory-dump-sub-view',{created:function(){this.currentSelection_=undefined;},get selection(){return this.currentSelection_;},set selection(selection){this.currentSelection_=sel [...]
+function buildElementMapsIfNeeded(){if(elementsThatExtend!==undefined&&elementsByName!==undefined)
+return;elementsByName={};elementsThatExtend={};Polymer.elements.forEach(function(element){if(elementsByName[element.name])
+throw new Error('Something is strange: dupe polymer element names');elementsByName[element.name]=element;if(element.extends){if(elementsThatExtend[element.extends]===undefined)
+elementsThatExtend[element.extends]=[];elementsThatExtend[element.extends].push(element.name);}});}
+function getPolymerElementNamed(tagName){buildElementMapsIfNeeded();return elementsByName[tagName];}
+function getPolymerElementsThatSubclass(tagName){if(Polymer.waitingFor().length){throw new Error('There are unresolved polymer elements. '+'Wait until Polymer.whenReady');}
+buildElementMapsIfNeeded();var element=getPolymerElementNamed(tagName);if(!element)
+throw new Error(tagName+' is not a polymer element');if(elementSubclasses===undefined)
+elementSubclasses={};if(elementSubclasses[tagName]===undefined){var immediateSubElements=elementsThatExtend[element.name];var allSubElements=[];if(immediateSubElements!==undefined&&immediateSubElements.length){immediateSubElements.forEach(function(subElement){allSubElements.push(subElement);allSubElements.push.apply(allSubElements,getPolymerElementsThatSubclass(subElement));});}
+elementSubclasses[tagName]=allSubElements;}
+return elementSubclasses[tagName];}
+return{getPolymerElementNamed:getPolymerElementNamed,getPolymerElementsThatSubclass:getPolymerElementsThatSubclass};});'use strict';(function(){var EventRegistry=tr.model.EventRegistry;Polymer('tr-ui-a-analysis-view',{ready:function(){this.tabView_=document.createElement('tr-ui-a-tab-view');this.tabView_.style.flex='1 1 auto';this.appendChild(this.tabView_);this.selectionController_=undefined;this.onSelectedTabChange_=this.onSelectedTabChange_.bind(this);this.onSelectionChanged_=this.onS [...]
+this.classList.add('tall-mode');else
+this.classList.remove('tall-mode');},get tallMode(){return this.classList.contains('tall-mode');},get tabView(){return this.tabView_;},get selectionController(){return this.selectionController_;},set selectionController(selectionController){if(this.selectionController){this.selectionController_.removeEventListener('change',this.onSelectionChanged_);}
+this.selectionController_=selectionController;if(this.selectionController){this.selectionController_.addEventListener('change',this.onSelectionChanged_);}
+this.onSelectionChanged_();},get selection(){return this.selectionController_.selection;},onSelectionChanged_:function(e){var selection=this.selectionController_.selection;var selectionHasSameValue=this.lastSeenSelection_.equals(selection);this.lastSeenSelection_=selection;if(selectionHasSameValue)
+return;var lastSelectedTabTagName;var lastSelectedTabTypeName;if(this.tabView_.selectedTab){lastSelectedTabTagName=this.tabView_.selectedTab.tagName;lastSelectedTabTypeName=this.tabView_.selectedTab._eventTypeName;}
+this.tallMode=false;var previouslySelectedTab=this.tabView_.selectedTab;this.tabView_.removeEventListener('selected-tab-change',this.onSelectedTabChange_);this.tabView_.textContent='';if(selection.length==0){this.tabView_.tabStripHeadingText='Nothing selected. Tap stuff.';}else if(selection.length==1){this.tabView_.tabStripHeadingText='1 item selected: ';}else{this.tabView_.tabStripHeadingText=selection.length+' items selected: ';}
+var eventsByBaseTypeName=selection.getEventsOrganizedByBaseType(true);var numBaseTypesToAnalyze=tr.b.dictionaryLength(eventsByBaseTypeName);for(var eventTypeName in eventsByBaseTypeName){var subSelection=eventsByBaseTypeName[eventTypeName];var subView=this.createSubViewForSelection_(eventTypeName,subSelection);subView._eventTypeName=eventTypeName;this.tabView_.appendChild(subView);subView.selection=subSelection;}
+var tab;if(lastSelectedTabTagName)
+tab=this.tabView_.querySelector(lastSelectedTabTagName);if(!tab&&lastSelectedTabTypeName){var tab=tr.b.findFirstInArray(this.tabView_.children,function(tab){return tab._eventTypeName===lastSelectedTabTypeName;});}
+if(!tab)
+tab=this.tabView_.firstChild;this.tabView_.selectedTab=tab;if(this.tabView_.selectedTab!==previouslySelectedTab)
+this.onSelectedTabChange_();this.tabView_.addEventListener('selected-tab-change',this.onSelectedTabChange_);},createSubViewForSelection_:function(eventTypeName,subSelection){var eventTypeInfo=EventRegistry.getEventTypeInfoByTypeName(eventTypeName);var singleMode=subSelection.length==1;var tagName;if(subSelection.length===1)
+tagName=eventTypeInfo.metadata.singleViewElementName;else
+tagName=eventTypeInfo.metadata.multiViewElementName;if(!tr.ui.b.getPolymerElementNamed(tagName))
+throw new Error('Element not registered: '+tagName);var subView=document.createElement(tagName);var camelLabel;if(subSelection.length===1)
+camelLabel=EventRegistry.getUserFriendlySingularName(eventTypeName);else
+camelLabel=EventRegistry.getUserFriendlyPluralName(eventTypeName);subView.tabLabel=camelLabel+' ('+subSelection.length+')';return subView;},onSelectedTabChange_:function(){var selectionController=this.selectionController_;if(this.tabView_.selectedTab){var selectedTab=this.tabView_.selectedTab;this.tallMode=selectedTab.requiresTallView;if(selectionController){var rlth=selectedTab.relatedEventsToHighlight;selectionController.changeAnalysisViewRelatedEvents(rlth);}}else{this.tallMode=false; [...]
+selectionController.changeAnalysisViewRelatedEvents(undefined);}}});})();'use strict';tr.exportTo('tr.ui.b',function(){var FaviconsByHue={blue:'data:image/vndmicrosofticon;base64,AAABAAIAEBAAAAEAIABoBAAAJgAAACAgAAABACAAqBAAAI4EAAAoAAAAEAAAACAAAAABACAAAAAAAAAEAAASCwAAEgsAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjj8xAGArIgqOPzE8nUY3dqJJOJeiSTiXnUY3do4/MTxhKyIKjkAxAAAAAAAAAAAAAAAAAAAAAABQJBwAAAAAAZJBMzSoSzqlsU8+6bRQP/21UT//tVE//7RQP/2wTz3ppko6pY9AMjQAAAABTyMbAAAAAAB7e3sAAP//AKFSRE+wTz3dtVE//7VRP/+1UT//t [...]
+task=operation;else
+task=new tr.b.Task(operation,this);if(this.activeTask_){this.activeTask_=this.activeTask_.enqueue(task);}else{this.activeTask_=task;this.activePromise_=Task.RunWhenIdle(this.activeTask_);this.activePromise_.then(function(){this.activePromise_=undefined;this.activeTask_=undefined;}.bind(this));}},startFiltering:function(filterText){var sc=this.selectionController_;if(!sc)
+return;this.enqueueOperation_(function(){this.filterHits_=new tr.c.Selection();this.currentHitIndex_=-1;}.bind(this));var stateFromString;try{stateFromString=sc.uiStateFromString(filterText);}catch(e){this.enqueueOperation_(function(){var overlay=new tr.ui.b.Overlay();overlay.textContent=e.message;overlay.title='UI State Navigation Error';overlay.visible=true;});return this.activePromise_;}
+if(stateFromString!==undefined){this.enqueueOperation_(sc.navToPosition.bind(this,stateFromString,true));}else{if(filterText.length===0){this.enqueueOperation_(sc.findTextCleared.bind(sc));}else{var filter=new tr.c.TitleOrCategoryFilter(filterText);var filterHits=new tr.c.Selection();this.enqueueOperation_(sc.addAllEventsMatchingFilterToSelectionAsTask(filter,filterHits));this.enqueueOperation_(function(){this.filterHits_=filterHits;sc.findTextChangedTo(filterHits);}.bind(this));}}
+return this.activePromise_;},get filterHits(){return this.filterHits_;},get currentHitIndex(){return this.currentHitIndex_;},find_:function(dir){var firstHit=this.currentHitIndex_===-1;if(firstHit&&dir<0)
+this.currentHitIndex_=0;var N=this.filterHits.length;this.currentHitIndex_=(this.currentHitIndex_+dir+N)%N;if(!this.selectionController_)
+return;this.selectionController_.findFocusChangedTo(this.filterHits.subSelection(this.currentHitIndex_,1));},findNext:function(){this.find_(1);},findPrevious:function(){this.find_(-1);}};return{FindController:FindController};});'use strict';tr.exportTo('tr.ui.b',function(){var paletteRaw=tr.ui.b.getRawColorPalette();var palette=tr.ui.b.getColorPalette();var SelectionState=tr.model.SelectionState;var EventPresenter={getSelectableItemColor:function(item){var colorId=item.colorId+this.getCo [...]
+return tr.ui.b.paletteProperties.highlightIdBoost;else if(event.selectionState===SelectionState.DIMMED)
+return tr.ui.b.paletteProperties.desaturateIdBoost;return 0;},getTextColor:function(event){if(event.selectionState===SelectionState.DIMMED)
+return'rgb(60,60,60)';return'rgb(0,0,0)';},getSliceColorId:function(slice){return slice.colorId+this.getColorIdOffset_(slice);},getSliceAlpha:function(slice,async){var alpha=1;if(async)
+alpha*=0.3;return alpha;},getInstantSliceColor:function(instant){var colorId=instant.colorId+this.getColorIdOffset_(instant);return tr.ui.b.colorToRGBAString(paletteRaw[colorId],1.0);},getObjectInstanceColor:function(instance){var colorId=instance.colorId+this.getColorIdOffset_(instance);return tr.ui.b.colorToRGBAString(paletteRaw[colorId],0.25);},getObjectSnapshotColor:function(snapshot){var colorId=snapshot.objectInstance.colorId+this.getColorIdOffset_(snapshot);return palette[colorId] [...]
+ElidedTitleCache.prototype={get:function(ctx,pixWidth,title,width,sliceDuration){var elidedDict=elidedTitleCacheDict[title];if(!elidedDict){elidedDict={};elidedTitleCacheDict[title]=elidedDict;}
+var elidedDictForPixWidth=elidedDict[pixWidth];if(!elidedDictForPixWidth){elidedDict[pixWidth]={};elidedDictForPixWidth=elidedDict[pixWidth];}
+var stringWidthPair=elidedDictForPixWidth[sliceDuration];if(stringWidthPair===undefined){var newtitle=title;var elided=false;while(this.labelWidthWorld(ctx,newtitle,pixWidth)>sliceDuration){if(newtitle.length*0.75<1)
+break;newtitle=newtitle.substring(0,newtitle.length*0.75);elided=true;}
+if(elided&&newtitle.length>3)
+newtitle=newtitle.substring(0,newtitle.length-3)+'...';stringWidthPair=new ElidedStringWidthPair(newtitle,this.labelWidth(ctx,newtitle));elidedDictForPixWidth[sliceDuration]=stringWidthPair;}
+return stringWidthPair;},quickMeasureText_:function(ctx,text){var w=this.textWidthMap[text];if(!w){w=ctx.measureText(text).width;this.textWidthMap[text]=w;}
+return w;},labelWidth:function(ctx,title){return this.quickMeasureText_(ctx,title)+2;},labelWidthWorld:function(ctx,title,pixWidth){return this.labelWidth(ctx,title)*pixWidth;}};function ElidedStringWidthPair(string,width){this.string=string;this.width=width;}
+return{ElidedTitleCache:ElidedTitleCache};});'use strict';tr.exportTo('tr.ui.b',function(){var elidedTitleCache=new tr.ui.b.ElidedTitleCache();var palette=tr.ui.b.getColorPalette();var EventPresenter=tr.ui.b.EventPresenter;var blackColorId=tr.ui.b.getColorIdForReservedName('black');var THIN_SLICE_HEIGHT=4;var SLICE_WAITING_WIDTH_DRAW_THRESHOLD=3;var SLICE_ACTIVE_WIDTH_DRAW_THRESHOLD=1;var SHOULD_ELIDE_TEXT=true;function drawLine(ctx,x1,y1,x2,y2){ctx.moveTo(x1,y1);ctx.lineTo(x2,y2);}
+function drawTriangle(ctx,x1,y1,x2,y2,x3,y3){ctx.beginPath();ctx.moveTo(x1,y1);ctx.lineTo(x2,y2);ctx.lineTo(x3,y3);ctx.closePath();}
+function drawArrow(ctx,x1,y1,x2,y2,arrowLength,arrowWidth){var dx=x2-x1;var dy=y2-y1;var len=Math.sqrt(dx*dx+dy*dy);var perc=(len-arrowLength)/len;var bx=x1+perc*dx;var by=y1+perc*dy;var ux=dx/len;var uy=dy/len;var ax=uy*arrowWidth;var ay=-ux*arrowWidth;ctx.beginPath();drawLine(ctx,x1,y1,x2,y2);ctx.stroke();drawTriangle(ctx,bx+ax,by+ay,x2,y2,bx-ax,by-ay);ctx.fill();}
+function drawSlices(ctx,dt,viewLWorld,viewRWorld,viewHeight,slices,async){var pixelRatio=window.devicePixelRatio||1;var pixWidth=dt.xViewVectorToWorld(1);var height=viewHeight*pixelRatio;var darkRectHeight=THIN_SLICE_HEIGHT*pixelRatio;if(height<darkRectHeight)
+darkRectHeight=0;var lightRectHeight=height-darkRectHeight;ctx.save();dt.applyTransformToCanvas(ctx);var rect=new tr.ui.b.FastRectRenderer(ctx,2*pixWidth,2*pixWidth,palette);rect.setYandH(0,height);var lowSlice=tr.b.findLowIndexInSortedArray(slices,function(slice){return slice.start+slice.duration;},viewLWorld);var hadTopLevel=false;for(var i=lowSlice;i<slices.length;++i){var slice=slices[i];var x=slice.start;if(x>viewRWorld)
+break;var w=pixWidth;if(slice.duration>0){w=Math.max(slice.duration,0.000001);if(w<pixWidth)
+w=pixWidth;}
+var colorId=EventPresenter.getSliceColorId(slice);var alpha=EventPresenter.getSliceAlpha(slice,async);var lightAlpha=alpha*0.70;if(slice.isTopLevel){rect.setYandH(3,height-3);hadTopLevel=true;}else{rect.setYandH(0,height);}
+if(!slice.cpuDuration){rect.fillRect(x,w,colorId,alpha);continue;}
+var activeWidth=w*(slice.cpuDuration/slice.duration);var waitingWidth=w-activeWidth;if(activeWidth<SLICE_ACTIVE_WIDTH_DRAW_THRESHOLD*pixWidth){activeWidth=0;waitingWidth=w;}
+if(waitingWidth<SLICE_WAITING_WIDTH_DRAW_THRESHOLD*pixWidth){activeWidth=w;waitingWidth=0;}
+if(activeWidth>0){rect.fillRect(x,activeWidth,colorId,alpha);}
+if(waitingWidth>0){rect.setYandH(0,lightRectHeight);rect.fillRect(x+activeWidth-pixWidth,waitingWidth+pixWidth,colorId,lightAlpha);rect.setYandH(lightRectHeight,darkRectHeight);rect.fillRect(x+activeWidth-pixWidth,waitingWidth+pixWidth,colorId,alpha);rect.setYandH(0,height);}}
+rect.flush();if(async&&hadTopLevel){rect.setYandH(2,1);for(var i=lowSlice;i<slices.length;++i){var slice=slices[i];var x=slice.start;if(x>viewRWorld)
+break;if(!slice.isTopLevel)
+continue;var w=pixWidth;if(slice.duration>0){w=Math.max(slice.duration,0.000001);if(w<pixWidth)
+w=pixWidth;}
+rect.fillRect(x,w,blackColorId,0.7);}
+rect.flush();}
+ctx.restore();}
+function drawInstantSlicesAsLines(ctx,dt,viewLWorld,viewRWorld,viewHeight,slices,lineWidthInPixels){var pixelRatio=window.devicePixelRatio||1;var height=viewHeight*pixelRatio;var pixWidth=dt.xViewVectorToWorld(1);ctx.save();ctx.lineWidth=pixWidth*lineWidthInPixels*pixelRatio;dt.applyTransformToCanvas(ctx);ctx.beginPath();var lowSlice=tr.b.findLowIndexInSortedArray(slices,function(slice){return slice.start;},viewLWorld);for(var i=lowSlice;i<slices.length;++i){var slice=slices[i];var x=sli [...]
+break;ctx.strokeStyle=EventPresenter.getInstantSliceColor(slice);ctx.beginPath();ctx.moveTo(x,0);ctx.lineTo(x,height);ctx.stroke();}
+ctx.restore();}
+function drawLabels(ctx,dt,viewLWorld,viewRWorld,slices,async,fontSize,yOffset){var pixelRatio=window.devicePixelRatio||1;var pixWidth=dt.xViewVectorToWorld(1);ctx.save();ctx.textAlign='center';ctx.textBaseline='top';ctx.font=(fontSize*pixelRatio)+'px sans-serif';if(async)
+ctx.font='italic '+ctx.font;var cY=yOffset*pixelRatio;var lowSlice=tr.b.findLowIndexInSortedArray(slices,function(slice){return slice.start+slice.duration;},viewLWorld);var quickDiscardThresshold=pixWidth*20;for(var i=lowSlice;i<slices.length;++i){var slice=slices[i];if(slice.start>viewRWorld)
+break;if(slice.duration<=quickDiscardThresshold)
+continue;var title=slice.title+
+(slice.didNotFinish?' (Did Not Finish)':'');var drawnTitle=title;var drawnWidth=elidedTitleCache.labelWidth(ctx,drawnTitle);var fullLabelWidth=elidedTitleCache.labelWidthWorld(ctx,drawnTitle,pixWidth);if(SHOULD_ELIDE_TEXT&&fullLabelWidth>slice.duration){var elidedValues=elidedTitleCache.get(ctx,pixWidth,drawnTitle,drawnWidth,slice.duration);drawnTitle=elidedValues.string;drawnWidth=elidedValues.width;}
+if(drawnWidth*pixWidth<slice.duration){ctx.fillStyle=EventPresenter.getTextColor(slice);var cX=dt.xWorldToView(slice.start+0.5*slice.duration);ctx.fillText(drawnTitle,cX,cY,drawnWidth);}}
+ctx.restore();}
+return{drawSlices:drawSlices,drawInstantSlicesAsLines:drawInstantSlicesAsLines,drawLabels:drawLabels,drawLine:drawLine,drawTriangle:drawTriangle,drawArrow:drawArrow,elidedTitleCache_:elidedTitleCache,THIN_SLICE_HEIGHT:THIN_SLICE_HEIGHT};});'use strict';tr.exportTo('tr.ui',function(){function SnapIndicator(y,height){this.y=y;this.height=height;}
+function TimelineInterestRange(vp){this.viewport_=vp;this.range_=new tr.b.Range();this.leftSelected_=false;this.rightSelected_=false;this.leftSnapIndicator_=undefined;this.rightSnapIndicator_=undefined;}
+TimelineInterestRange.prototype={get isEmpty(){return this.range_.isEmpty;},reset:function(){this.range_.reset();this.leftSelected_=false;this.rightSelected_=false;this.leftSnapIndicator_=undefined;this.rightSnapIndicator_=undefined;this.viewport_.dispatchChangeEvent();},get min(){return this.range_.min;},set min(min){this.range_.min=min;this.viewport_.dispatchChangeEvent();},get max(){return this.range_.max;},set max(max){this.range_.max=max;this.viewport_.dispatchChangeEvent();},set:fu [...]
+return;this.leftSelected_=leftSelected;this.viewport_.dispatchChangeEvent();},get rightSelected(){return this.rightSelected_;},set rightSelected(rightSelected){if(this.rightSelected_==rightSelected)
+return;this.rightSelected_=rightSelected;this.viewport_.dispatchChangeEvent();},get leftSnapIndicator(){return this.leftSnapIndicator_;},set leftSnapIndicator(leftSnapIndicator){this.leftSnapIndicator_=leftSnapIndicator;this.viewport_.dispatchChangeEvent();},get rightSnapIndicator(){return this.rightSnapIndicator_;},set rightSnapIndicator(rightSnapIndicator){this.rightSnapIndicator_=rightSnapIndicator;this.viewport_.dispatchChangeEvent();},draw:function(ctx,viewLWorld,viewRWorld){if(this [...]
+return;var dt=this.viewport_.currentDisplayTransform;var markerLWorld=this.min;var markerRWorld=this.max;var markerLView=Math.round(dt.xWorldToView(markerLWorld));var markerRView=Math.round(dt.xWorldToView(markerRWorld));ctx.fillStyle='rgba(0, 0, 0, 0.2)';if(markerLWorld>viewLWorld){ctx.fillRect(dt.xWorldToView(viewLWorld),0,markerLView,ctx.canvas.height);}
+if(markerRWorld<viewRWorld){ctx.fillRect(markerRView,0,dt.xWorldToView(viewRWorld),ctx.canvas.height);}
+var pixelRatio=window.devicePixelRatio||1;ctx.lineWidth=Math.round(pixelRatio);if(this.range_.range>0){this.drawLine_(ctx,viewLWorld,viewRWorld,ctx.canvas.height,this.min,this.leftSelected_);this.drawLine_(ctx,viewLWorld,viewRWorld,ctx.canvas.height,this.max,this.rightSelected_);}else{this.drawLine_(ctx,viewLWorld,viewRWorld,ctx.canvas.height,this.min,this.leftSelected_||this.rightSelected_);}
+ctx.lineWidth=1;},drawLine_:function(ctx,viewLWorld,viewRWorld,height,ts,selected){if(ts<viewLWorld||ts>=viewRWorld)
+return;var dt=this.viewport_.currentDisplayTransform;var viewX=Math.round(dt.xWorldToView(ts));ctx.save();ctx.translate((Math.round(ctx.lineWidth)%2)/2,0);ctx.beginPath();tr.ui.b.drawLine(ctx,viewX,0,viewX,height);if(selected)
+ctx.strokeStyle='rgb(255, 0, 0)';else
+ctx.strokeStyle='rgb(0, 0, 0)';ctx.stroke();ctx.restore();},drawIndicators:function(ctx,viewLWorld,viewRWorld){if(this.leftSnapIndicator_){this.drawIndicator_(ctx,viewLWorld,viewRWorld,this.range_.min,this.leftSnapIndicator_,this.leftSelected_);}
+if(this.rightSnapIndicator_){this.drawIndicator_(ctx,viewLWorld,viewRWorld,this.range_.max,this.rightSnapIndicator_,this.rightSelected_);}},drawIndicator_:function(ctx,viewLWorld,viewRWorld,xWorld,si,selected){var dt=this.viewport_.currentDisplayTransform;var viewX=Math.round(dt.xWorldToView(xWorld));ctx.save();ctx.translate((Math.round(ctx.lineWidth)%2)/2,0);var pixelRatio=window.devicePixelRatio||1;var viewY=si.y*devicePixelRatio;var viewHeight=si.height*devicePixelRatio;var arrowSize= [...]
+ctx.fillStyle='rgb(255, 0, 0)';else
+ctx.fillStyle='rgb(0, 0, 0)';tr.ui.b.drawTriangle(ctx,viewX-arrowSize*0.75,viewY,viewX+arrowSize*0.75,viewY,viewX,viewY+arrowSize);ctx.fill();tr.ui.b.drawTriangle(ctx,viewX-arrowSize*0.75,viewY+viewHeight,viewX+arrowSize*0.75,viewY+viewHeight,viewX,viewY+viewHeight-arrowSize);ctx.fill();ctx.restore();}};return{SnapIndicator:SnapIndicator,TimelineInterestRange:TimelineInterestRange};});'use strict';tr.exportTo('tr.ui',function(){function TimelineDisplayTransform(opt_that){if(opt_that){thi [...]
+this.scaleX=1;this.panX=0;this.panY=0;}
+TimelineDisplayTransform.prototype={set:function(that){this.scaleX=that.scaleX;this.panX=that.panX;this.panY=that.panY;},clone:function(){return new TimelineDisplayTransform(this);},equals:function(that){var eq=true;if(that===undefined||that===null)
+return false;eq&=this.panX===that.panX;eq&=this.panY===that.panY;eq&=this.scaleX===that.scaleX;return!!eq;},almostEquals:function(that){var eq=true;if(that===undefined||that===null)
+return false;eq&=Math.abs(this.panX-that.panX)<0.001;eq&=Math.abs(this.panY-that.panY)<0.001;eq&=Math.abs(this.scaleX-that.scaleX)<0.001;return!!eq;},incrementPanXInViewUnits:function(xDeltaView){this.panX+=this.xViewVectorToWorld(xDeltaView);},xPanWorldPosToViewPos:function(worldX,viewX,viewWidth){if(typeof viewX=='string'){if(viewX==='left'){viewX=0;}else if(viewX==='center'){viewX=viewWidth/2;}else if(viewX==='right'){viewX=viewWidth-1;}else{throw new Error('viewX must be left|center| [...]
+this.panX=(viewX/this.scaleX)-worldX;},xPanWorldBoundsIntoView:function(worldMin,worldMax,viewWidth){if(this.xWorldToView(worldMin)<0)
+this.xPanWorldPosToViewPos(worldMin,'left',viewWidth);else if(this.xWorldToView(worldMax)>viewWidth)
+this.xPanWorldPosToViewPos(worldMax,'right',viewWidth);},xSetWorldBounds:function(worldMin,worldMax,viewWidth){var worldWidth=worldMax-worldMin;var scaleX=viewWidth/worldWidth;var panX=-worldMin;this.setPanAndScale(panX,scaleX);},setPanAndScale:function(p,s){this.scaleX=s;this.panX=p;},xWorldToView:function(x){return(x+this.panX)*this.scaleX;},xWorldVectorToView:function(x){return x*this.scaleX;},xViewToWorld:function(x){return(x/this.scaleX)-this.panX;},xViewVectorToWorld:function(x){re [...]
+ContainerToTrackMap.prototype={addContainer:function(container,track){if(!track)
+throw new Error('Must provide a track.');this.stableIdToTrackMap_[container.stableId]=track;},clear:function(){this.stableIdToTrackMap_={};},getTrackByStableId:function(stableId){return this.stableIdToTrackMap_[stableId];}};return{ContainerToTrackMap:ContainerToTrackMap};});'use strict';tr.exportTo('tr.ui.tracks',function(){function EventToTrackMap(){}
+EventToTrackMap.prototype={addEvent:function(event,track){if(!track)
+throw new Error('Must provide a track.');this[event.guid]=track;}};return{EventToTrackMap:EventToTrackMap};});'use strict';tr.exportTo('tr.ui.b',function(){function Animation(){}
+Animation.prototype={canTakeOverFor:function(existingAnimation){throw new Error('Not implemented');},takeOverFor:function(existingAnimation,newStartTimestamp,target){throw new Error('Not implemented');},start:function(timestamp,target){throw new Error('Not implemented');},didStopEarly:function(timestamp,target,willBeTakenOverByAnotherAnimation){},tick:function(timestamp,target){throw new Error('Not implemented');}};return{Animation:Animation};});'use strict';tr.exportTo('tr.ui.b',functio [...]
+AnimationController.prototype={__proto__:tr.b.EventTarget.prototype,get target(){return this.target_;},set target(target){if(this.activeAnimation_)
+throw new Error('Cannot change target while animation is running.');if(target.cloneAnimationState===undefined||typeof target.cloneAnimationState!=='function')
+throw new Error('target must have a cloneAnimationState function');this.target_=target;},get activeAnimation(){return this.activeAnimation_;},get hasActiveAnimation(){return!!this.activeAnimation_;},queueAnimation:function(animation,opt_now){if(this.target_===undefined)
+throw new Error('Cannot queue animations without a target');var now;if(opt_now!==undefined)
+now=opt_now;else
+now=window.performance.now();if(this.activeAnimation_){var done=this.activeAnimation_.tick(now,this.target_);if(done)
+this.activeAnimation_=undefined;}
+if(this.activeAnimation_){if(animation.canTakeOverFor(this.activeAnimation_)){this.activeAnimation_.didStopEarly(now,this.target_,true);animation.takeOverFor(this.activeAnimation_,now,this.target_);}else{this.activeAnimation_.didStopEarly(now,this.target_,false);}}
+this.activeAnimation_=animation;this.activeAnimation_.start(now,this.target_);if(this.tickScheduled_)
+return;this.tickScheduled_=true;tr.b.requestAnimationFrame(this.tickActiveAnimation_,this);},cancelActiveAnimation:function(opt_now){if(!this.activeAnimation_)
+return;var now;if(opt_now!==undefined)
+now=opt_now;else
+now=window.performance.now();this.activeAnimation_.didStopEarly(now,this.target_,false);this.activeAnimation_=undefined;},tickActiveAnimation_:function(frameBeginTime){this.tickScheduled_=false;if(!this.activeAnimation_)
+return;if(this.target_===undefined){this.activeAnimation_.didStopEarly(frameBeginTime,this.target_,false);return;}
+var oldTargetState=this.target_.cloneAnimationState();var done=this.activeAnimation_.tick(frameBeginTime,this.target_);if(done)
+this.activeAnimation_=undefined;if(this.activeAnimation_){this.tickScheduled_=true;tr.b.requestAnimationFrame(this.tickActiveAnimation_,this);}
+if(oldTargetState){var e=new Event('didtick');e.oldTargetState=oldTargetState;this.dispatchEvent(e,false,false);}}};return{AnimationController:AnimationController};});'use strict';tr.exportTo('tr.ui',function(){var TimelineDisplayTransform=tr.ui.TimelineDisplayTransform;var TimelineInterestRange=tr.ui.TimelineInterestRange;function TimelineViewport(parentEl){this.parentEl_=parentEl;this.modelTrackContainer_=undefined;this.currentDisplayTransform_=new TimelineDisplayTransform();this.initA [...]
+TimelineViewport.prototype={__proto__:tr.b.EventTarget.prototype,setWhenPossible:function(fn){this.pendingSetFunction_=fn;},get isAttachedToDocumentOrInTestMode(){if(this.parentEl_===undefined)
+return;return tr.ui.b.isElementAttachedToDocument(this.parentEl_);},onResize_:function(){this.dispatchChangeEvent();},checkForAttach_:function(){if(!this.isAttachedToDocumentOrInTestMode||this.clientWidth==0)
+return;if(!this.iframe_){this.iframe_=document.createElement('iframe');this.iframe_.style.cssText='position:absolute;width:100%;height:0;border:0;visibility:hidden;';this.parentEl_.appendChild(this.iframe_);this.iframe_.contentWindow.addEventListener('resize',this.onResize_);}
+var curSize=this.parentEl_.clientWidth+'x'+
+this.parentEl_.clientHeight;if(this.pendingSetFunction_){this.lastSize_=curSize;try{this.pendingSetFunction_();}catch(ex){console.log('While running setWhenPossible:',ex.message?ex.message+'\n'+ex.stack:ex.stack);}
+this.pendingSetFunction_=undefined;}
+window.clearInterval(this.checkForAttachInterval_);this.checkForAttachInterval_=undefined;},dispatchChangeEvent:function(){tr.b.dispatchSimpleEvent(this,'change');},detach:function(){if(this.checkForAttachInterval_){window.clearInterval(this.checkForAttachInterval_);this.checkForAttachInterval_=undefined;}
+if(this.iframe_){this.iframe_.removeEventListener('resize',this.onResize_);this.parentEl_.removeChild(this.iframe_);}},initAnimationController_:function(){this.dtAnimationController_=new tr.ui.b.AnimationController();this.dtAnimationController_.addEventListener('didtick',function(e){this.onCurentDisplayTransformChange_(e.oldTargetState);}.bind(this));var that=this;this.dtAnimationController_.target={get panX(){return that.currentDisplayTransform_.panX;},set panX(panX){that.currentDisplay [...]
+throw new Error('animation must be instanceof tr.ui.b.Animation');this.dtAnimationController_.queueAnimation(animation);},onCurentDisplayTransformChange_:function(oldDisplayTransform){if(this.modelTrackContainer_){this.currentDisplayTransform.panY=tr.b.clamp(this.currentDisplayTransform.panY,0,this.modelTrackContainer_.scrollHeight-
+this.modelTrackContainer_.clientHeight);}
+var changed=!this.currentDisplayTransform.equals(oldDisplayTransform);var yChanged=this.currentDisplayTransform.panY!==oldDisplayTransform.panY;if(yChanged)
+this.modelTrackContainer_.scrollTop=this.currentDisplayTransform.panY;if(changed)
+this.dispatchChangeEvent();},onModelTrackControllerScroll_:function(e){if(this.dtAnimationController_.activeAnimation&&this.dtAnimationController_.activeAnimation.affectsPanY)
+this.dtAnimationController_.cancelActiveAnimation();var panY=this.modelTrackContainer_.scrollTop;this.currentDisplayTransform_.panY=panY;},get modelTrackContainer(){return this.modelTrackContainer_;},set modelTrackContainer(m){if(this.modelTrackContainer_)
+this.modelTrackContainer_.removeEventListener('scroll',this.onModelTrackControllerScroll_);this.modelTrackContainer_=m;this.modelTrackContainer_.addEventListener('scroll',this.onModelTrackControllerScroll_);},get showFlowEvents(){return this.showFlowEvents_;},set showFlowEvents(showFlowEvents){this.showFlowEvents_=showFlowEvents;this.dispatchChangeEvent();},get highlightVSync(){return this.highlightVSync_;},set highlightVSync(highlightVSync){this.highlightVSync_=highlightVSync;this.dispa [...]
+return;this.gridEnabled_=enabled&&true;this.dispatchChangeEvent();},get gridTimebase(){return this.gridTimebase_;},set gridTimebase(timebase){if(this.gridTimebase_==timebase)
+return;this.gridTimebase_=timebase;this.dispatchChangeEvent();},get gridStep(){return this.gridStep_;},get interestRange(){return this.interestRange_;},drawMajorMarkLines:function(ctx){ctx.save();ctx.translate((Math.round(ctx.lineWidth)%2)/2,0);ctx.beginPath();for(var idx in this.majorMarkPositions){var x=Math.floor(this.majorMarkPositions[idx]);tr.ui.b.drawLine(ctx,x,0,x,ctx.canvas.height);}
+ctx.strokeStyle='#ddd';ctx.stroke();ctx.restore();},drawGridLines:function(ctx,viewLWorld,viewRWorld){if(!this.gridEnabled)
+return;var dt=this.currentDisplayTransform;var x=this.gridTimebase;ctx.save();ctx.translate((Math.round(ctx.lineWidth)%2)/2,0);ctx.beginPath();while(x<viewRWorld){if(x>=viewLWorld){var vx=Math.floor(dt.xWorldToView(x));tr.ui.b.drawLine(ctx,vx,0,vx,ctx.canvas.height);}
+x+=this.gridStep;}
+ctx.strokeStyle='rgba(255, 0, 0, 0.25)';ctx.stroke();ctx.restore();},rebuildEventToTrackMap:function(){this.eventToTrackMap_=new tr.ui.tracks.EventToTrackMap();this.modelTrackContainer_.addEventsToTrackMap(this.eventToTrackMap_);},rebuildContainerToTrackMap:function(){this.containerToTrackMap.clear();this.modelTrackContainer_.addContainersToTrackMap(this.containerToTrackMap);},trackForEvent:function(event){return this.eventToTrackMap_[event.guid];}};return{TimelineViewport:TimelineViewpo [...]
+this.durationMs=kDefaultPanAnimatoinDurationMs;else
+this.durationMs=opt_durationMs;this.startPanX=undefined;this.startPanY=undefined;this.startTimeMs=undefined;}
+TimelineDisplayTransformPanAnimation.prototype={__proto__:tr.ui.b.Animation.prototype,get affectsPanY(){return this.deltaY!==0;},canTakeOverFor:function(existingAnimation){return existingAnimation instanceof TimelineDisplayTransformPanAnimation;},takeOverFor:function(existing,timestamp,target){var remainingDeltaXOnExisting=existing.goalPanX-target.panX;var remainingDeltaYOnExisting=existing.goalPanY-target.panY;var remainingTimeOnExisting=timestamp-(existing.startTimeMs+existing.duration [...]
+target.panY=tr.b.lerp(percentDone,this.startPanY,this.goalPanY);return timestamp>=this.startTimeMs+this.durationMs;},get goalPanX(){return this.startPanX+this.deltaX;},get goalPanY(){return this.startPanY+this.deltaY;}};function TimelineDisplayTransformZoomToAnimation(goalFocalPointXWorld,goalFocalPointXView,goalFocalPointY,zoomInRatioX,opt_durationMs){this.goalFocalPointXWorld=goalFocalPointXWorld;this.goalFocalPointXView=goalFocalPointXView;this.goalFocalPointY=goalFocalPointY;this.zoo [...]
+this.durationMs=kDefaultPanAnimatoinDurationMs;else
+this.durationMs=opt_durationMs;this.startTimeMs=undefined;this.startScaleX=undefined;this.goalScaleX=undefined;this.startPanY=undefined;}
+TimelineDisplayTransformZoomToAnimation.prototype={__proto__:tr.ui.b.Animation.prototype,get affectsPanY(){return this.startPanY!=this.goalFocalPointY;},canTakeOverFor:function(existingAnimation){return false;},takeOverFor:function(existingAnimation,timestamp,target){this.goalScaleX=target.scaleX*this.zoomInRatioX;},start:function(timestamp,target){this.startTimeMs=timestamp;this.startScaleX=target.scaleX;this.goalScaleX=this.zoomInRatioX*target.scaleX;this.startPanY=target.panY;},tick:f [...]
+target.xPanWorldPosToViewPos(this.goalFocalPointXWorld,this.goalFocalPointXView);return timestamp>=this.startTimeMs+this.durationMs;}};return{TimelineDisplayTransformPanAnimation:TimelineDisplayTransformPanAnimation,TimelineDisplayTransformZoomToAnimation:TimelineDisplayTransformZoomToAnimation};});'use strict';tr.exportTo('tr.c',function(){var constants={HEADING_WIDTH:250};return{constants:constants};});'use strict';tr.exportTo('tr.ui.b',function(){var constants=tr.c.constants;function  [...]
+return;var pt=this.getSnappedToEventPosition_(e);this.mouseDownAt_(pt.x,pt.y);this.updateSnapIndicators_(pt);},updateSnapIndicators_:function(pt){if(!pt.snapped)
+return;var ir=this.viewport_.interestRange;if(ir.min===pt.x)
+ir.leftSnapIndicator=new tr.ui.SnapIndicator(pt.y,pt.height);if(ir.max===pt.x)
+ir.rightSnapIndicator=new tr.ui.SnapIndicator(pt.y,pt.height);},onUpdateTiming:function(e){var pt=this.getSnappedToEventPosition_(e);this.mouseMoveAt_(pt.x,pt.y,true);this.updateSnapIndicators_(pt);},onEndTiming:function(e){this.mouseUp_();},onExitTiming:function(e){this.targetElement_.removeEventListener('mousemove',this.onMouseMove_);this.targetElement_.removeEventListener('dblclick',this.onDblClick_);},onMouseMove_:function(e){if(e.button)
+return;var worldX=this.getWorldXFromEvent_(e);this.mouseMoveAt_(worldX,e.clientY,false);},onDblClick_:function(e){console.error('not implemented');},isTouchPointInsideTrackBounds_:function(clientX,clientY){if(!this.viewport_||!this.viewport_.modelTrackContainer||!this.viewport_.modelTrackContainer.canvas)
+return false;var canvas=this.viewport_.modelTrackContainer.canvas;var canvasRect=canvas.getBoundingClientRect();if(clientX>=canvasRect.left&&clientX<=canvasRect.right&&clientY>=canvasRect.top&&clientY<=canvasRect.bottom)
+return true;return false;},mouseDownAt_:function(worldX,y){var ir=this.viewport_.interestRange;var dt=this.viewport_.currentDisplayTransform;var pixelRatio=window.devicePixelRatio||1;var nearnessThresholdWorld=dt.xViewVectorToWorld(6*pixelRatio);if(ir.isEmpty){ir.setMinAndMax(worldX,worldX);ir.rightSelected=true;this.isMovingLeftEdge_=false;return;}
+if(Math.abs(worldX-ir.min)<nearnessThresholdWorld){ir.leftSelected=true;ir.min=worldX;this.isMovingLeftEdge_=true;return;}
+if(Math.abs(worldX-ir.max)<nearnessThresholdWorld){ir.rightSelected=true;ir.max=worldX;this.isMovingLeftEdge_=false;return;}
+ir.setMinAndMax(worldX,worldX);ir.rightSelected=true;this.isMovingLeftEdge_=false;},mouseMoveAt_:function(worldX,y,mouseDown){var ir=this.viewport_.interestRange;if(mouseDown){this.updateMovingEdge_(worldX);return;}
+var ir=this.viewport_.interestRange;var dt=this.viewport_.currentDisplayTransform;var pixelRatio=window.devicePixelRatio||1;var nearnessThresholdWorld=dt.xViewVectorToWorld(6*pixelRatio);if(Math.abs(worldX-ir.min)<nearnessThresholdWorld){ir.leftSelected=true;ir.rightSelected=false;return;}
+if(Math.abs(worldX-ir.max)<nearnessThresholdWorld){ir.leftSelected=false;ir.rightSelected=true;return;}
+ir.leftSelected=false;ir.rightSelected=false;return;},updateMovingEdge_:function(newWorldX){var ir=this.viewport_.interestRange;var a=ir.min;var b=ir.max;if(this.isMovingLeftEdge_)
+a=newWorldX;else
+b=newWorldX;if(a<=b)
+ir.setMinAndMax(a,b);else
+ir.setMinAndMax(b,a);if(ir.min==newWorldX){this.isMovingLeftEdge_=true;ir.leftSelected=true;ir.rightSelected=false;}else{this.isMovingLeftEdge_=false;ir.leftSelected=false;ir.rightSelected=true;}},mouseUp_:function(){var dt=this.viewport_.currentDisplayTransform;var ir=this.viewport_.interestRange;ir.leftSelected=false;ir.rightSelected=false;var pixelRatio=window.devicePixelRatio||1;var minWidthValue=dt.xViewVectorToWorld(2*pixelRatio);if(ir.range<minWidthValue)
+ir.reset();},getWorldXFromEvent_:function(e){var pixelRatio=window.devicePixelRatio||1;var canvas=this.viewport_.modelTrackContainer.canvas;var worldOffset=canvas.getBoundingClientRect().left;var viewX=(e.clientX-worldOffset)*pixelRatio;return this.viewport_.currentDisplayTransform.xViewToWorld(viewX);},getSnappedToEventPosition_:function(e){var pixelRatio=window.devicePixelRatio||1;var EVENT_SNAP_RANGE=16*pixelRatio;var modelTrackContainer=this.viewport_.modelTrackContainer;var modelTra [...]
+var minDistX=worldMaxDist;var minDistY=Infinity;var pixWidth=dt.xViewVectorToWorld(1);var result={x:worldX,y:mouseY-modelTrackContainerRect.top,height:0,snapped:false};var eventBounds=new tr.b.Range();for(var i=0;i<selection.length;i++){var event=selection[i];var track=viewport.trackForEvent(event);var trackRect=track.getBoundingClientRect();eventBounds.reset();event.addBoundsToRange(eventBounds);var eventX;if(Math.abs(eventBounds.min-worldX)<Math.abs(eventBounds.max-worldX)){eventX=even [...]
+var distX=eventX-worldX;var eventY=trackRect.top;var eventHeight=trackRect.height;var distY=Math.abs(eventY+eventHeight/2-mouseY);if((distX<=minDistX||Math.abs(distX-minDistX)<pixWidth)&&distY<minDistY){minDistX=distX;minDistY=distY;result.x=eventX;result.y=eventY+
+modelTrackContainer.scrollTop-modelTrackContainerRect.top;result.height=eventHeight;result.snapped=true;}}
+return result;}};return{TimingTool:TimingTool};});'use strict';tr.exportTo('tr.ui.b',function(){var ContainerThatDecoratesItsChildren=tr.ui.b.define('div');ContainerThatDecoratesItsChildren.prototype={__proto__:HTMLUnknownElement.prototype,decorate:function(){this.observer_=new WebKitMutationObserver(this.didMutate_.bind(this));this.observer_.observe(this,{childList:true});Object.defineProperty(this,'textContent',{get:undefined,set:this.onSetTextContent_});},appendChild:function(x){HTMLU [...]
+throw new Error('textContent can only be set to \'\'.');this.clear();},clear:function(){while(this.lastChild)
+HTMLUnknownElement.prototype.removeChild.call(this,this.lastChild);this.didMutate_(this.observer_.takeRecords());},didMutate_:function(records){this.beginDecorating_();for(var i=0;i<records.length;i++){var addedNodes=records[i].addedNodes;if(addedNodes){for(var j=0;j<addedNodes.length;j++)
+this.decorateChild_(addedNodes[j]);}
+var removedNodes=records[i].removedNodes;if(removedNodes){for(var j=0;j<removedNodes.length;j++){this.undecorateChild_(removedNodes[j]);}}}
+this.doneDecoratingForNow_();},decorateChild_:function(child){throw new Error('Not implemented');},undecorateChild_:function(child){throw new Error('Not implemented');},beginDecorating_:function(){},doneDecoratingForNow_:function(){}};return{ContainerThatDecoratesItsChildren:ContainerThatDecoratesItsChildren};});'use strict';tr.exportTo('tr.ui.tracks',function(){var Track=tr.ui.b.define('track',tr.ui.b.ContainerThatDecoratesItsChildren);Track.prototype={__proto__:tr.ui.b.ContainerThatDec [...]
+throw new Error('viewport is required when creating a Track.');this.viewport_=viewport;this.classList.add('track');},get viewport(){return this.viewport_;},get drawingContainer(){var cur=this;while(cur){if(cur instanceof tr.ui.tracks.DrawingContainer)
+return cur;cur=cur.parentElement;}
+return undefined;},get eventContainer(){},invalidateDrawingContainer:function(){var dc=this.drawingContainer;if(dc)
+dc.invalidate();},context:function(){if(!this.parentNode)
+return undefined;if(!this.parentNode.context)
+throw new Error('Parent container does not support context() method.');return this.parentNode.context();},decorateChild_:function(childTrack){},undecorateChild_:function(childTrack){if(childTrack.detach)
+childTrack.detach();},updateContents_:function(){},drawTrack:function(type){var ctx=this.context();var pixelRatio=window.devicePixelRatio||1;var bounds=this.getBoundingClientRect();var canvasBounds=ctx.canvas.getBoundingClientRect();ctx.save();ctx.translate(0,pixelRatio*(bounds.top-canvasBounds.top));var dt=this.viewport.currentDisplayTransform;var viewLWorld=dt.xViewToWorld(0);var viewRWorld=dt.xViewToWorld(bounds.width*pixelRatio);this.draw(type,viewLWorld,viewRWorld);ctx.restore();},d [...]
+return;this.addIntersectingEventsInRangeToSelectionInWorldSpace(loWX,hiWX,viewPixWidthWorld,selection);},addIntersectingEventsInRangeToSelectionInWorldSpace:function(loWX,hiWX,viewPixWidthWorld,selection){},addClosestEventToSelection:function(worldX,worldMaxDist,loY,hiY,selection){},addClosestInstantEventToSelection:function(instantEvents,worldX,worldMaxDist,selection){var instantEvent=tr.b.findClosestElementInSortedArray(instantEvents,function(x){return x.start;},worldX,worldMaxDist);if [...]
+return;selection.push(instantEvent);}};return{Track:Track};});'use strict';tr.exportTo('tr.ui.tracks',function(){var DrawType={GENERAL_EVENT:1,INSTANT_EVENT:2,BACKGROUND:3,GRID:4,FLOW_ARROWS:5,MARKERS:6,HIGHLIGHTS:7,ANNOTATIONS:8};var DrawingContainer=tr.ui.b.define('drawing-container',tr.ui.tracks.Track);DrawingContainer.prototype={__proto__:tr.ui.tracks.Track.prototype,decorate:function(viewport){tr.ui.tracks.Track.prototype.decorate.call(this,viewport);this.classList.add('drawing-cont [...]
+return;this.rafPending_=true;tr.b.requestPreAnimationFrame(this.preDraw_,this);},preDraw_:function(){this.rafPending_=false;this.updateCanvasSizeIfNeeded_();tr.b.requestAnimationFrameInThisFrameIfPossible(this.draw_,this);},draw_:function(){this.ctx_.clearRect(0,0,this.canvas_.width,this.canvas_.height);var typesToDraw=[DrawType.BACKGROUND,DrawType.HIGHLIGHTS,DrawType.GRID,DrawType.INSTANT_EVENT,DrawType.GENERAL_EVENT,DrawType.MARKERS,DrawType.ANNOTATIONS,DrawType.FLOW_ARROWS];for(var id [...]
+continue;this.children[i].drawTrack(typesToDraw[idx]);}}
+var pixelRatio=window.devicePixelRatio||1;var bounds=this.canvas_.getBoundingClientRect();var dt=this.viewport.currentDisplayTransform;var viewLWorld=dt.xViewToWorld(0);var viewRWorld=dt.xViewToWorld(bounds.width*pixelRatio);this.viewport.drawGridLines(this.ctx_,viewLWorld,viewRWorld);},updateCanvasSizeIfNeeded_:function(){var visibleChildTracks=tr.b.asArray(this.children).filter(this.visibleFilter_);var thisBounds=this.getBoundingClientRect();var firstChildTrackBounds=visibleChildTracks [...]
+tr.c.constants.HEADING_WIDTH;var innerHeight=lastChildTrackBounds.bottom-firstChildTrackBounds.top;var pixelRatio=window.devicePixelRatio||1;if(this.canvas_.width!=innerWidth*pixelRatio){this.canvas_.width=innerWidth*pixelRatio;this.canvas_.style.width=innerWidth+'px';}
+if(this.canvas_.height!=innerHeight*pixelRatio){this.canvas_.height=innerHeight*pixelRatio;this.canvas_.style.height=innerHeight+'px';}},visibleFilter_:function(element){if(!(element instanceof tr.ui.tracks.Track))
+return false;return window.getComputedStyle(element).display!=='none';},addClosestEventToSelection:function(worldX,worldMaxDist,loY,hiY,selection){for(var i=0;i<this.children.length;++i){if(!(this.children[i]instanceof tr.ui.tracks.Track))
+continue;var trackClientRect=this.children[i].getBoundingClientRect();var a=Math.max(loY,trackClientRect.top);var b=Math.min(hiY,trackClientRect.bottom);if(a<=b){this.children[i].addClosestEventToSelection(worldX,worldMaxDist,loY,hiY,selection);}}
+tr.ui.tracks.Track.prototype.addClosestEventToSelection.apply(this,arguments);},addEventsToTrackMap:function(eventToTrackMap){for(var i=0;i<this.children.length;++i){if(!(this.children[i]instanceof tr.ui.tracks.Track))
+continue;this.children[i].addEventsToTrackMap(eventToTrackMap);}},addContainersToTrackMap:function(containerToTrackMap){for(var i=0;i<this.children.length;++i){if(!(this.children[i]instanceof tr.ui.tracks.Track))
+continue;this.children[i].addContainersToTrackMap(containerToTrackMap);}}};return{DrawingContainer:DrawingContainer,DrawType:DrawType};});'use strict';tr.exportTo('tr.ui.tracks',function(){function Highlighter(viewport){if(viewport===undefined){throw new Error('viewport must be provided');}
+this.viewport_=viewport;};Highlighter.prototype={__proto__:Object.prototype,processModel:function(model){throw new Error('processModel implementation missing');},drawHighlight:function(ctx,dt,viewLWorld,viewRWorld,viewHeight){throw new Error('drawHighlight implementation missing');}};var options=new tr.b.ExtensionRegistryOptions(tr.b.BASIC_REGISTRY_MODE);options.defaultMetadata={};options.mandatoryBaseClass=Highlighter;tr.b.decorateExtensionRegistry(Highlighter,options);return{Highlighte [...]
+tracks.push(this.children[i]);}
+return tracks;},drawTrack:function(type){for(var i=0;i<this.children.length;++i){if(!(this.children[i]instanceof tr.ui.tracks.Track))
+continue;this.children[i].drawTrack(type);}},addIntersectingEventsInRangeToSelection:function(loVX,hiVX,loY,hiY,selection){for(var i=0;i<this.tracks_.length;i++){var trackClientRect=this.tracks_[i].getBoundingClientRect();var a=Math.max(loY,trackClientRect.top);var b=Math.min(hiY,trackClientRect.bottom);if(a<=b)
+this.tracks_[i].addIntersectingEventsInRangeToSelection(loVX,hiVX,loY,hiY,selection);}
+tr.ui.tracks.Track.prototype.addIntersectingEventsInRangeToSelection.apply(this,arguments);},addEventsToTrackMap:function(eventToTrackMap){for(var i=0;i<this.children.length;++i)
+this.children[i].addEventsToTrackMap(eventToTrackMap);},addAllEventsMatchingFilterToSelection:function(filter,selection){for(var i=0;i<this.tracks_.length;i++)
+this.tracks_[i].addAllEventsMatchingFilterToSelection(filter,selection);},addAllEventsMatchingFilterToSelectionAsTask:function(filter,selection){var task=new Task();for(var i=0;i<this.tracks_.length;i++){task.subTask(function(i){return function(){this.tracks_[i].addAllEventsMatchingFilterToSelection(filter,selection);}}(i),this);}
+return task;},addClosestEventToSelection:function(worldX,worldMaxDist,loY,hiY,selection){for(var i=0;i<this.tracks_.length;i++){var trackClientRect=this.tracks_[i].getBoundingClientRect();var a=Math.max(loY,trackClientRect.top);var b=Math.min(hiY,trackClientRect.bottom);if(a<=b){this.tracks_[i].addClosestEventToSelection(worldX,worldMaxDist,loY,hiY,selection);}}
+tr.ui.tracks.Track.prototype.addClosestEventToSelection.apply(this,arguments);}};return{ContainerTrack:ContainerTrack};});'use strict';tr.exportTo('tr.ui.tracks',function(){function ChartAxis(opt_min,opt_max){this.guid_=tr.b.GUID.allocate();this.bounds=new tr.b.Range();if(opt_min!==undefined)
+this.bounds.addValue(opt_min);if(opt_max!==undefined)
+this.bounds.addValue(opt_max);};ChartAxis.prototype={get guid(){return this.guid_;},valueToUnitRange:function(value){if(this.bounds.isEmpty)
+throw new Error('Chart axis bounds are empty');var bounds=this.bounds;if(bounds.range===0)
+return 0;return(value-bounds.min)/bounds.range;},autoSetFromSeries:function(series,opt_config){var range=new tr.b.Range();series.forEach(function(s){range.addRange(s.range);},this);this.autoSetFromRange(range,opt_config);},autoSetFromRange:function(range,opt_config){if(range.isEmpty)
+return;var bounds=this.bounds;if(bounds.isEmpty){bounds.addRange(range);return;}
+if(!opt_config)
+return;var useRangeMin=(opt_config.expandMin&&range.min<bounds.min||opt_config.shrinkMin&&range.min>bounds.min);var useRangeMax=(opt_config.expandMax&&range.max>bounds.max||opt_config.shrinkMax&&range.max<bounds.max);if(!useRangeMin&&!useRangeMax)
+return;if(useRangeMin&&useRangeMax){bounds.min=range.min;bounds.max=range.max;return;}
+if(useRangeMin){bounds.min=Math.min(range.min,bounds.max);}else{bounds.max=Math.max(range.max,bounds.min);}}};return{ChartAxis:ChartAxis};});'use strict';tr.exportTo('tr.model',function(){var SelectableItem=tr.model.SelectableItem;var SelectionState=tr.model.SelectionState;function ProxySelectableItem(modelItem){SelectableItem.call(this,modelItem);};ProxySelectableItem.prototype={__proto__:SelectableItem.prototype,get selectionState(){var modelItem=this.modelItem_;if(modelItem===undefined)
+return SelectionState.NONE;return modelItem.selectionState;}};return{ProxySelectableItem:ProxySelectableItem};});'use strict';tr.exportTo('tr.ui.tracks',function(){function ChartPoint(modelItem,x,y,opt_yBase){tr.model.ProxySelectableItem.call(this,modelItem);this.x=x;this.y=y;this.yBase=opt_yBase;};ChartPoint.prototype={__proto__:tr.model.ProxySelectableItem.prototype};return{ChartPoint:ChartPoint};});'use strict';tr.exportTo('tr.ui.tracks',function(){var DOWN_ARROW=String.fromCharCode(0 [...]
+return;this.expanded_=expanded;this.expandedStateChanged_();},expandedStateChanged_:function(){this.updateHeadigDiv_();},onHeadingDivClicked_:function(){var e=new Event('heading-clicked',{'bubbles':true});this.dispatchEvent(e);},updateContents_:function(){this.updateHeadigDiv_();},updateHeadigDiv_:function(){this.headingDiv_.innerHTML='';var span=document.createElement('span');span.classList.add('heading-arrow');if(this.expanded===true)
+span.textContent=DOWN_ARROW;else if(this.expanded===false)
+span.textContent=RIGHT_ARROW;else
+span.textContent='';this.headingDiv_.appendChild(span);if(this.selectionGenerator_){this.headingLink_=document.createElement('tr-ui-a-analysis-link');this.headingLink_.selection=this.selectionGenerator_;this.headingLink_.textContent='';this.headingDiv_.appendChild(this.headingLink_);this.headingLink_.appendChild(document.createTextNode(this.heading_));}else{span=document.createElement('span');span.textContent=this.heading_;this.headingDiv_.appendChild(span);}
+this.appendChild(this.headingDiv_);},draw:function(type,viewLWorld,viewRWorld){throw new Error('draw implementation missing');}};return{HeadingTrack:HeadingTrack};});'use strict';tr.exportTo('tr.ui.tracks',function(){var EventPresenter=tr.ui.b.EventPresenter;var SelectionState=tr.model.SelectionState;var ChartSeriesType={LINE:0,AREA:1};var DEFAULT_RENDERING_CONFIG={chartType:ChartSeriesType.LINE,selectedPointSize:4,unselectedPointSize:3,colorId:0,lineWidth:1,skipDistance:1,unselectedPoin [...]
+ChartSeries.prototype={useRenderingConfig_:function(opt_renderingConfig){var config=opt_renderingConfig||{};tr.b.iterItems(DEFAULT_RENDERING_CONFIG,function(key,defaultValue){var value=config[key];if(value===undefined)
+value=defaultValue;this[key+'_']=value;},this);this.topPadding=this.bottomPadding=Math.max(this.selectedPointSize_,this.unselectedPointSize_)/2;},get range(){var range=new tr.b.Range();this.points.forEach(function(point){range.addValue(point.y);},this);return range;},draw:function(ctx,transform,highDetails){if(this.points===undefined||this.points.length===0)
+return;if(this.chartType_===ChartSeriesType.AREA){this.drawComponent_(ctx,transform,ChartSeriesComponent.BACKGROUND,highDetails);}
+if(this.chartType_===ChartSeriesType.LINE||highDetails){this.drawComponent_(ctx,transform,ChartSeriesComponent.LINE,highDetails);}
+this.drawComponent_(ctx,transform,ChartSeriesComponent.DOTS,highDetails);},drawComponent_:function(ctx,transform,component,highDetails){var extraPixels=0;if(component===ChartSeriesComponent.DOTS){extraPixels=Math.max(this.selectedPointSize_,this.unselectedPointSize_);}
+var leftViewX=transform.leftViewX-extraPixels*transform.pixelRatio;var rightViewX=transform.rightViewX+
+extraPixels*transform.pixelRatio;var leftTimestamp=transform.leftTimestamp-extraPixels;var rightTimestamp=transform.rightTimestamp+extraPixels;var firstVisibleIndex=tr.b.findLowIndexInSortedArray(this.points,function(point){return point.x;},leftTimestamp);var lastVisibleIndex=tr.b.findLowIndexInSortedArray(this.points,function(point){return point.x;},rightTimestamp);if(lastVisibleIndex>=this.points.length||this.points[lastVisibleIndex].x>rightTimestamp){lastVisibleIndex--;}
+var viewSkipDistance=this.skipDistance_*transform.pixelRatio;var circleRadius;var squareSize;var squareHalfSize;var squareOpacity;switch(component){case ChartSeriesComponent.DOTS:ctx.strokeStyle=EventPresenter.getCounterSeriesColor(this.colorId_,SelectionState.NONE);ctx.lineWidth=transform.pixelRatio;circleRadius=(this.selectedPointSize_/2)*transform.pixelRatio;squareSize=this.unselectedPointSize_*transform.pixelRatio;squareHalfSize=squareSize/2;if(!highDetails){squareOpacity=0;break;}
+var visibleIndexRange=lastVisibleIndex-firstVisibleIndex;if(visibleIndexRange<=0){squareOpacity=1;break;}
+var visibleViewXRange=transform.worldXToViewX(this.points[lastVisibleIndex].x)-
+transform.worldXToViewX(this.points[firstVisibleIndex].x);if(visibleViewXRange===0){squareOpacity=1;break;}
+var density=visibleIndexRange/visibleViewXRange;var clampedDensity=tr.b.clamp(density,this.unselectedPointDensityOpaque_,this.unselectedPointDensityTransparent_);var densityRange=this.unselectedPointDensityTransparent_-
+this.unselectedPointDensityOpaque_;squareOpacity=(this.unselectedPointDensityTransparent_-clampedDensity)/densityRange;break;case ChartSeriesComponent.LINE:ctx.strokeStyle=EventPresenter.getCounterSeriesColor(this.colorId_,SelectionState.NONE);ctx.lineWidth=this.lineWidth_*transform.pixelRatio;break;case ChartSeriesComponent.BACKGROUND:break;default:throw new Error('Invalid component: '+component);}
+var previousViewX=undefined;var previousViewY=undefined;var previousViewYBase=undefined;var lastSelectionState=undefined;var baseSteps=undefined;var startIndex=Math.max(firstVisibleIndex-1,0);for(var i=startIndex;i<this.points.length;i++){var currentPoint=this.points[i];var currentViewX=transform.worldXToViewX(currentPoint.x);if(currentViewX>rightViewX){if(previousViewX!==undefined){previousViewX=currentViewX=rightViewX;if(component===ChartSeriesComponent.BACKGROUND||component===ChartSer [...]
+break;}
+if(i+1<this.points.length){var nextPoint=this.points[i+1];var nextViewX=transform.worldXToViewX(nextPoint.x);if(previousViewX!==undefined&&nextViewX-previousViewX<=viewSkipDistance&&nextViewX<rightViewX){continue;}
+if(currentViewX<leftViewX){currentViewX=leftViewX;}}
+if(previousViewX!==undefined&&currentViewX-previousViewX<viewSkipDistance){currentViewX=previousViewX+viewSkipDistance;}
+var currentViewY=Math.round(transform.worldYToViewY(currentPoint.y));var currentViewYBase;if(currentPoint.yBase===undefined){currentViewYBase=transform.outerBottomViewY;}else{currentViewYBase=Math.round(transform.worldYToViewY(currentPoint.yBase));}
+var currentSelectionState=currentPoint.selectionState;switch(component){case ChartSeriesComponent.DOTS:if(currentSelectionState!==lastSelectionState){if(currentSelectionState===SelectionState.SELECTED){ctx.fillStyle=EventPresenter.getCounterSeriesColor(this.colorId_,currentSelectionState);}else if(squareOpacity>0){ctx.fillStyle=EventPresenter.getCounterSeriesColor(this.colorId_,currentSelectionState,squareOpacity);}}
+if(currentSelectionState===SelectionState.SELECTED){ctx.beginPath();ctx.arc(currentViewX,currentViewY,circleRadius,0,2*Math.PI);ctx.fill();ctx.stroke();}else if(squareOpacity>0){ctx.fillRect(currentViewX-squareHalfSize,currentViewY-squareHalfSize,squareSize,squareSize);}
+break;case ChartSeriesComponent.LINE:if(previousViewX===undefined){ctx.beginPath();ctx.moveTo(currentViewX,currentViewY);}else{ctx.lineTo(currentViewX,previousViewY);}
+ctx.lineTo(currentViewX,currentViewY);break;case ChartSeriesComponent.BACKGROUND:if(previousViewX!==undefined)
+ctx.lineTo(currentViewX,previousViewY);if(currentSelectionState!==lastSelectionState){if(previousViewX!==undefined){var previousBaseStepViewX=currentViewX;for(var j=baseSteps.length-1;j>=0;j--){var baseStep=baseSteps[j];var baseStepViewX=baseStep.viewX;var baseStepViewY=baseStep.viewY;ctx.lineTo(previousBaseStepViewX,baseStepViewY);ctx.lineTo(baseStepViewX,baseStepViewY);previousBaseStepViewX=baseStepViewX;}
+ctx.closePath();ctx.fill();}
+ctx.beginPath();ctx.fillStyle=EventPresenter.getCounterSeriesColor(this.colorId_,currentSelectionState,this.backgroundOpacity_);ctx.moveTo(currentViewX,currentViewYBase);baseSteps=[];}
+if(currentViewYBase!==previousViewYBase||currentSelectionState!==lastSelectionState){baseSteps.push({viewX:currentViewX,viewY:currentViewYBase});}
+ctx.lineTo(currentViewX,currentViewY);break;default:throw new Error('Not reachable');}
+previousViewX=currentViewX;previousViewY=currentViewY;previousViewYBase=currentViewYBase;lastSelectionState=currentSelectionState;}
+if(previousViewX!==undefined){switch(component){case ChartSeriesComponent.DOTS:break;case ChartSeriesComponent.LINE:ctx.stroke();break;case ChartSeriesComponent.BACKGROUND:var previousBaseStepViewX=currentViewX;for(var j=baseSteps.length-1;j>=0;j--){var baseStep=baseSteps[j];var baseStepViewX=baseStep.viewX;var baseStepViewY=baseStep.viewY;ctx.lineTo(previousBaseStepViewX,baseStepViewY);ctx.lineTo(baseStepViewX,baseStepViewY);previousBaseStepViewX=baseStepViewX;}
+ctx.closePath();ctx.fill();break;default:throw new Error('Not reachable');}}},addIntersectingEventsInRangeToSelectionInWorldSpace:function(loWX,hiWX,viewPixWidthWorld,selection){var points=this.points;function getPointWidth(point,i){if(i===points.length-1)
+return LAST_POINT_WIDTH*viewPixWidthWorld;var nextPoint=points[i+1];return nextPoint.x-point.x;}
+function selectPoint(point){point.addToSelection(selection);}
+tr.b.iterateOverIntersectingIntervals(this.points,function(point){return point.x},getPointWidth,loWX,hiWX,selectPoint);},addEventNearToProvidedEventToSelection:function(event,offset,selection){if(this.points===undefined)
+return false;var index=tr.b.findFirstIndexInArray(this.points,function(point){return point.modelItem===event;},this);if(index===-1)
+return false;var newIndex=index+offset;if(newIndex<0||newIndex>=this.points.length)
+return false;this.points[newIndex].addToSelection(selection);return true;},addClosestEventToSelection:function(worldX,worldMaxDist,loY,hiY,selection){if(this.points===undefined)
+return;var item=tr.b.findClosestElementInSortedArray(this.points,function(point){return point.x},worldX,worldMaxDist);if(!item)
+return;item.addToSelection(selection);}};return{ChartSeries:ChartSeries,ChartSeriesType:ChartSeriesType};});'use strict';tr.exportTo('tr.ui.tracks',function(){function ChartTransform(displayTransform,axis,trackWidth,trackHeight,topPadding,bottomPadding,pixelRatio){this.pixelRatio=pixelRatio;this.leftViewX=0;this.rightViewX=trackWidth;this.leftTimestamp=displayTransform.xViewToWorld(this.leftViewX);this.rightTimestamp=displayTransform.xViewToWorld(this.rightViewX);this.displayTransform_=d [...]
+var axisGuidToAxisData={};var topPadding=0;var bottomPadding=0;this.series_.forEach(function(series){var axis=series.axis;var axisGuid=axis.guid;if(!(axisGuid in axisGuidToAxisData)){axisGuidToAxisData[axisGuid]={axis:axis,series:[]};}
+axisGuidToAxisData[axisGuid].series.push(series);topPadding=Math.max(topPadding,series.topPadding);bottomPadding=Math.max(bottomPadding,series.bottomPadding);},this);this.axisGuidToAxisData_=axisGuidToAxisData;this.topPadding_=topPadding;this.bottomPadding_=bottomPadding;},draw:function(type,viewLWorld,viewRWorld){switch(type){case tr.ui.tracks.DrawType.GENERAL_EVENT:this.drawChart_(viewLWorld,viewRWorld);break;}},drawChart_:function(viewLWorld,viewRWorld){if(!this.series_)
+return;var ctx=this.context();var displayTransform=this.viewport.currentDisplayTransform;var pixelRatio=window.devicePixelRatio||1;var bounds=this.getBoundingClientRect();var highDetails=this.viewport.highDetails;var width=bounds.width*pixelRatio;var height=bounds.height*pixelRatio;var topPadding=this.topPadding_*pixelRatio;var bottomPadding=this.bottomPadding_*pixelRatio;ctx.save();ctx.beginPath();ctx.rect(0,0,width,height);ctx.clip();this.series_.forEach(function(series){var chartTrans [...]
+return;switch(type){case tr.ui.tracks.DrawType.GENERAL_EVENT:this.drawLetterDots_(viewLWorld,viewRWorld);break;}},drawLetterDots_:function(viewLWorld,viewRWorld){var ctx=this.context();var pixelRatio=window.devicePixelRatio||1;var bounds=this.getBoundingClientRect();var height=bounds.height*pixelRatio;var halfHeight=height*0.5;var twoPi=Math.PI*2;var palette=tr.ui.b.getColorPalette();var highlightIdBoost=tr.ui.b.paletteProperties.highlightIdBoost;var dt=this.viewport.currentDisplayTransf [...]
+break;if(item.selected!==selected)
+continue;var xView=dt.xWorldToView(x);ctx.fillStyle=EventPresenter.getSelectableItemColor(item);ctx.beginPath();ctx.arc(xView,halfHeight,dumpRadiusView+0.5,0,twoPi);ctx.fill();if(item.selected){ctx.lineWidth=3;ctx.strokeStyle='rgb(100,100,0)';ctx.stroke();ctx.beginPath();ctx.arc(xView,halfHeight,dumpRadiusView,0,twoPi);ctx.lineWidth=1.5;ctx.strokeStyle='rgb(255,255,0)';ctx.stroke();}else{ctx.lineWidth=1;ctx.strokeStyle='rgb(0,0,0)';ctx.stroke();}
+ctx.fillStyle='rgb(255, 255, 255)';ctx.fillText(item.dotLetter,xView,halfHeight);}};drawItems(false);drawItems(true);ctx.lineWidth=1;ctx.font=oldFont;},addEventsToTrackMap:function(eventToTrackMap){if(this.items_===undefined)
+return;this.items_.forEach(function(item){item.addToTrackMap(eventToTrackMap,this);},this);},addIntersectingEventsInRangeToSelectionInWorldSpace:function(loWX,hiWX,viewPixWidthWorld,selection){if(this.items_===undefined)
+return;var itemRadiusWorld=viewPixWidthWorld*this.dumpRadiusView;tr.b.iterateOverIntersectingIntervals(this.items_,function(x){return x.start-itemRadiusWorld;},function(x){return 2*itemRadiusWorld;},loWX,hiWX,function(item){item.addToSelection(selection);}.bind(this));},addEventNearToProvidedEventToSelection:function(event,offset,selection){if(this.items_===undefined)
+return;var items=this.items_;var index=tr.b.findFirstIndexInArray(items,function(item){return item.modelItem===event;});if(index===-1)
+return false;var newIndex=index+offset;if(newIndex>=0&&newIndex<items.length){items[newIndex].addToSelection(selection);return true;}
+return false;},addAllEventsMatchingFilterToSelection:function(filter,selection){},addClosestEventToSelection:function(worldX,worldMaxDist,loY,hiY,selection){if(this.items_===undefined)
+return;var item=tr.b.findClosestElementInSortedArray(this.items_,function(x){return x.start;},worldX,worldMaxDist);if(!item)
+return;item.addToSelection(selection);}};function LetterDot(modelItem,dotLetter,colorId,start){tr.model.ProxySelectableItem.call(this,modelItem);this.dotLetter=dotLetter;this.colorId=colorId;this.start=start;};LetterDot.prototype={__proto__:tr.model.ProxySelectableItem.prototype};return{LetterDotTrack:LetterDotTrack,LetterDot:LetterDot};});'use strict';tr.exportTo('tr.ui.tracks',function(){var palette=tr.ui.b.getColorPalette();var startCompare=function(x,y){return x.start-y.start;}
+var FrameTrack=tr.ui.b.define('frame-track',tr.ui.tracks.LetterDotTrack);FrameTrack.prototype={__proto__:tr.ui.tracks.LetterDotTrack.prototype,decorate:function(viewport){tr.ui.tracks.LetterDotTrack.prototype.decorate.call(this,viewport);this.heading='Frames';this.frames_=undefined;this.items=undefined;},get frames(){return this.frames_;},set frames(frames){this.frames_=frames;if(frames===undefined)
+return;this.frames_=this.frames_.slice();this.frames_.sort(startCompare);this.items=this.frames_.map(function(frame){return new FrameDot(frame);});}};function FrameDot(frame){tr.ui.tracks.LetterDot.call(this,frame,'F',frame.colorId,frame.start);}
+FrameDot.prototype={__proto__:tr.ui.tracks.LetterDot.prototype};return{FrameTrack:FrameTrack};});'use strict';tr.exportTo('tr.model',function(){var Settings=tr.b.Settings;function ModelSettings(model){this.model=model;this.objectsByKey_=[];this.nonuniqueKeys_=[];this.buildObjectsByKeyMap_();this.removeNonuniqueKeysFromSettings_();this.ephemeralSettingsByGUID_={};}
+ModelSettings.prototype={buildObjectsByKeyMap_:function(){var objects=[];this.model.iterateAllPersistableObjects(function(o){objects.push(o);});var objectsByKey={};var NONUNIQUE_KEY='nonuniqueKey';for(var i=0;i<objects.length;i++){var object=objects[i];var objectKey=object.getSettingsKey();if(!objectKey)
+continue;if(objectsByKey[objectKey]===undefined){objectsByKey[objectKey]=object;continue;}
+objectsByKey[objectKey]=NONUNIQUE_KEY;}
+var nonuniqueKeys={};tr.b.dictionaryKeys(objectsByKey).forEach(function(objectKey){if(objectsByKey[objectKey]!==NONUNIQUE_KEY)
+return;delete objectsByKey[objectKey];nonuniqueKeys[objectKey]=true;});this.nonuniqueKeys=nonuniqueKeys;this.objectsByKey_=objectsByKey;},removeNonuniqueKeysFromSettings_:function(){var settings=Settings.get('trace_model_settings',{});var settingsChanged=false;tr.b.dictionaryKeys(settings).forEach(function(objectKey){if(!this.nonuniqueKeys[objectKey])
+return;settingsChanged=true;delete settings[objectKey];},this);if(settingsChanged)
+Settings.set('trace_model_settings',settings);},hasUniqueSettingKey:function(object){var objectKey=object.getSettingsKey();if(!objectKey)
+return false;return this.objectsByKey_[objectKey]!==undefined;},getSettingFor:function(object,objectLevelKey,defaultValue){var objectKey=object.getSettingsKey();if(!objectKey||!this.objectsByKey_[objectKey]){var settings=this.getEphemeralSettingsFor_(object);var ephemeralValue=settings[objectLevelKey];if(ephemeralValue!==undefined)
+return ephemeralValue;return defaultValue;}
+var settings=Settings.get('trace_model_settings',{});if(!settings[objectKey])
+settings[objectKey]={};var value=settings[objectKey][objectLevelKey];if(value!==undefined)
+return value;return defaultValue;},setSettingFor:function(object,objectLevelKey,value){var objectKey=object.getSettingsKey();if(!objectKey||!this.objectsByKey_[objectKey]){this.getEphemeralSettingsFor_(object)[objectLevelKey]=value;return;}
+var settings=Settings.get('trace_model_settings',{});if(!settings[objectKey])
+settings[objectKey]={};if(settings[objectKey][objectLevelKey]===value)
+return;settings[objectKey][objectLevelKey]=value;Settings.set('trace_model_settings',settings);},getEphemeralSettingsFor_:function(object){if(object.guid===undefined)
+throw new Error('Only objects with GUIDs can be persisted');if(this.ephemeralSettingsByGUID_[object.guid]===undefined)
+this.ephemeralSettingsByGUID_[object.guid]={};return this.ephemeralSettingsByGUID_[object.guid];}};return{ModelSettings:ModelSettings};});'use strict';tr.exportTo('tr.ui.tracks',function(){var MultiRowTrack=tr.ui.b.define('multi-row-track',tr.ui.tracks.ContainerTrack);MultiRowTrack.prototype={__proto__:tr.ui.tracks.ContainerTrack.prototype,decorate:function(viewport){tr.ui.tracks.ContainerTrack.prototype.decorate.call(this,viewport);this.tooltip_='';this.heading_='';this.groupingSource_= [...]
+return;this.expanded_=expanded;this.expandedStateChanged_();},onHeadingClicked_:function(e){if(this.subRows.length<=1)
+return;this.expanded=!this.expanded;if(this.groupingSource_){var modelSettings=new tr.model.ModelSettings(this.groupingSource_.model);modelSettings.setSettingFor(this.groupingSource_,'expanded',this.expanded);}
+e.stopPropagation();},updateExpandedStateFromGroupingSource_:function(){if(this.groupingSource_){var numSubRows=this.subRows.length;var modelSettings=new tr.model.ModelSettings(this.groupingSource_.model);if(numSubRows>1){var defaultExpanded;if(numSubRows>this.defaultToCollapsedWhenSubRowCountMoreThan){defaultExpanded=false;}else{defaultExpanded=true;}
+this.expanded=modelSettings.getSettingFor(this.groupingSource_,'expanded',defaultExpanded);}else{this.expanded=undefined;}}},expandedStateChanged_:function(){var minH=Math.max(2,Math.ceil(18/this.children.length));var h=(this.expanded_?18:minH)+'px';for(var i=0;i<this.children.length;i++)
+this.children[i].height=h;if(this.children.length>0)
+this.children[0].expanded=this.expanded;},updateContents_:function(){tr.ui.tracks.ContainerTrack.prototype.updateContents_.call(this);if(!this.itemsToGroup_){this.updateHeadingAndTooltip_();this.currentSubRows_=[];return;}
+if(this.areArrayContentsSame_(this.itemsGroupedOnLastUpdateContents_,this.itemsToGroup_)){this.updateHeadingAndTooltip_();return;}
+this.itemsGroupedOnLastUpdateContents_=this.itemsToGroup_;this.detach();if(!this.itemsToGroup_.length){this.currentSubRows_=[];return;}
+var subRows=this.buildSubRows_(this.itemsToGroup_);this.currentSubRows_=subRows;for(var srI=0;srI<subRows.length;srI++){var subRow=subRows[srI];if(!subRow.length)
+continue;var track=this.addSubTrack_(subRow);track.addEventListener('heading-clicked',this.onHeadingClicked_.bind(this));}
+this.updateHeadingAndTooltip_();this.expandedStateChanged_();},updateHeadingAndTooltip_:function(){if(!this.firstChild)
+return;this.firstChild.heading=this.heading_;this.firstChild.tooltip=this.tooltip_;},buildSubRows_:function(itemsToGroup){throw new Error('Not implemented');},addSubTrack_:function(subRowItems){throw new Error('Not implemented');},areArrayContentsSame_:function(a,b){if(!a||!b)
+return false;if(!a.length||!b.length)
+return false;if(a.length!=b.length)
+return false;for(var i=0;i<a.length;++i){if(a[i]!=b[i])
+return false;}
+return true;}};return{MultiRowTrack:MultiRowTrack};});'use strict';tr.exportTo('tr.ui.tracks',function(){var SelectionState=tr.model.SelectionState;var EventPresenter=tr.ui.b.EventPresenter;var ObjectInstanceTrack=tr.ui.b.define('object-instance-track',tr.ui.tracks.HeadingTrack);ObjectInstanceTrack.prototype={__proto__:tr.ui.tracks.HeadingTrack.prototype,decorate:function(viewport){tr.ui.tracks.HeadingTrack.prototype.decorate.call(this,viewport);this.classList.add('object-instance-track' [...]
+this.heading=objectInstances[0].typeName;this.objectInstances_=objectInstances;this.objectSnapshots_=[];this.objectInstances_.forEach(function(instance){this.objectSnapshots_.push.apply(this.objectSnapshots_,instance.snapshots);},this);this.objectSnapshots_.sort(function(a,b){return a.ts-b.ts;});},get height(){return window.getComputedStyle(this).height;},set height(height){this.style.height=height;},get snapshotRadiusView(){return 7*(window.devicePixelRatio||1);},draw:function(type,view [...]
+break;var right=instance.deletionTs==Number.MAX_VALUE?viewRWorld:instance.deletionTs;ctx.fillStyle=EventPresenter.getObjectInstanceColor(instance);ctx.fillRect(x,pixelRatio,right-x,height-2*pixelRatio);}
+ctx.restore();var objectSnapshots=this.objectSnapshots_;loI=tr.b.findLowIndexInSortedArray(objectSnapshots,function(snapshot){return snapshot.ts+snapshotRadiusWorld;},viewLWorld);for(var i=loI;i<objectSnapshots.length;++i){var snapshot=objectSnapshots[i];var x=snapshot.ts;if(x-snapshotRadiusWorld>viewRWorld)
+break;var xView=dt.xWorldToView(x);ctx.fillStyle=EventPresenter.getObjectSnapshotColor(snapshot);ctx.beginPath();ctx.arc(xView,halfHeight,snapshotRadiusView,0,twoPi);ctx.fill();if(snapshot.selected){ctx.lineWidth=5;ctx.strokeStyle='rgb(100,100,0)';ctx.stroke();ctx.beginPath();ctx.arc(xView,halfHeight,snapshotRadiusView-1,0,twoPi);ctx.lineWidth=2;ctx.strokeStyle='rgb(255,255,0)';ctx.stroke();}else{ctx.lineWidth=1;ctx.strokeStyle='rgb(0,0,0)';ctx.stroke();}}
+ctx.lineWidth=1;var selectionState=SelectionState.NONE;if(objectInstances.length&&objectInstances[0].selectionState===SelectionState.DIMMED){selectionState=SelectionState.DIMMED;}
+if(selectionState===SelectionState.DIMMED){var width=bounds.width*pixelRatio;ctx.fillStyle='rgba(255,255,255,0.5)';ctx.fillRect(0,0,width,height);ctx.restore();}},addEventsToTrackMap:function(eventToTrackMap){if(this.objectInstance_!==undefined){this.objectInstance_.forEach(function(obj){eventToTrackMap.addEvent(obj,this);},this);}
+if(this.objectSnapshots_!==undefined){this.objectSnapshots_.forEach(function(obj){eventToTrackMap.addEvent(obj,this);},this);}},addIntersectingEventsInRangeToSelectionInWorldSpace:function(loWX,hiWX,viewPixWidthWorld,selection){var foundSnapshot=false;function onSnapshot(snapshot){selection.push(snapshot);foundSnapshot=true;}
+var snapshotRadiusView=this.snapshotRadiusView;var snapshotRadiusWorld=viewPixWidthWorld*snapshotRadiusView;tr.b.iterateOverIntersectingIntervals(this.objectSnapshots_,function(x){return x.ts-snapshotRadiusWorld;},function(x){return 2*snapshotRadiusWorld;},loWX,hiWX,onSnapshot);if(foundSnapshot)
+return;tr.b.iterateOverIntersectingIntervals(this.objectInstances_,function(x){return x.creationTs;},function(x){return x.deletionTs-x.creationTs;},loWX,hiWX,selection.push.bind(selection));},addEventNearToProvidedEventToSelection:function(event,offset,selection){var events;if(event instanceof tr.model.ObjectSnapshot)
+events=this.objectSnapshots_;else if(event instanceof tr.model.ObjectInstance)
+events=this.objectInstances_;else
+throw new Error('Unrecognized event');var index=events.indexOf(event);var newIndex=index+offset;if(newIndex>=0&&newIndex<events.length){selection.push(events[newIndex]);return true;}
+return false;},addAllEventsMatchingFilterToSelection:function(filter,selection){},addClosestEventToSelection:function(worldX,worldMaxDist,loY,hiY,selection){var snapshot=tr.b.findClosestElementInSortedArray(this.objectSnapshots_,function(x){return x.ts;},worldX,worldMaxDist);if(!snapshot)
+return;selection.push(snapshot);}};var options=new tr.b.ExtensionRegistryOptions(tr.b.TYPE_BASED_REGISTRY_MODE);tr.b.decorateExtensionRegistry(ObjectInstanceTrack,options);return{ObjectInstanceTrack:ObjectInstanceTrack};});'use strict';tr.exportTo('tr.ui.tracks',function(){var ObjectInstanceGroupTrack=tr.ui.b.define('object-instance-group-track',tr.ui.tracks.MultiRowTrack);ObjectInstanceGroupTrack.prototype={__proto__:tr.ui.tracks.MultiRowTrack.prototype,decorate:function(viewport){tr.ui [...]
+if(!found){var subRow=[objectInstance];subRows.push(subRow);}}
+return subRows;},updateHeadingAndTooltip_:function(){}};return{ObjectInstanceGroupTrack:ObjectInstanceGroupTrack};});'use strict';tr.exportTo('tr.ui.b',function(){function FastRectRenderer(ctx,minRectSize,maxMergeDist,pallette){this.ctx_=ctx;this.minRectSize_=minRectSize;this.maxMergeDist_=maxMergeDist;this.pallette_=pallette;}
+FastRectRenderer.prototype={y_:0,h_:0,merging_:false,mergeStartX_:0,mergeCurRight_:0,mergedColorId_:0,mergedAlpha_:0,setYandH:function(y,h){if(this.y_===y&&this.h_===h)
+return;this.flush();this.y_=y;this.h_=h;},fillRect:function(x,w,colorId,alpha){var r=x+w;if(w<this.minRectSize_){if(r-this.mergeStartX_>this.maxMergeDist_)
+this.flush();if(!this.merging_){this.merging_=true;this.mergeStartX_=x;this.mergeCurRight_=r;this.mergedColorId_=colorId;this.mergedAlpha_=alpha;}else{this.mergeCurRight_=r;if(this.mergedAlpha_<alpha||(this.mergedAlpha_===alpha&&this.mergedColorId_<colorId)){this.mergedAlpha_=alpha;this.mergedColorId_=colorId;}}}else{if(this.merging_)
+this.flush();this.ctx_.fillStyle=this.pallette_[colorId];this.ctx_.globalAlpha=alpha;this.ctx_.fillRect(x,this.y_,w,this.h_);}},flush:function(){if(this.merging_){this.ctx_.fillStyle=this.pallette_[this.mergedColorId_];this.ctx_.globalAlpha=this.mergedAlpha_;this.ctx_.fillRect(this.mergeStartX_,this.y_,this.mergeCurRight_-this.mergeStartX_,this.h_);this.merging_=false;}}};return{FastRectRenderer:FastRectRenderer};});'use strict';tr.exportTo('tr.ui.tracks',function(){var RectTrack=tr.ui.b [...]
+return;var fontSize,yOffset;if(bounds.height<15){fontSize=6;yOffset=1.0;}else{fontSize=10;yOffset=2.5;}
+tr.ui.b.drawLabels(ctx,this.viewport.currentDisplayTransform,viewLWorld,viewRWorld,this.rects_,this.asyncStyle_,fontSize,yOffset);},addEventsToTrackMap:function(eventToTrackMap){if(this.rects_===undefined||this.rects_===null)
+return;this.rects_.forEach(function(rect){rect.addToTrackMap(eventToTrackMap,this);},this);},addIntersectingEventsInRangeToSelectionInWorldSpace:function(loWX,hiWX,viewPixWidthWorld,selection){function onRect(rect){rect.addToSelection(selection);}
+onRect=onRect.bind(this);tr.b.iterateOverIntersectingIntervals(this.rects_,function(x){return x.start;},function(x){return x.duration;},loWX,hiWX,onRect);},addEventNearToProvidedEventToSelection:function(event,offset,selection){var index=tr.b.findFirstIndexInArray(this.rects_,function(rect){return rect.modelItem===event;});if(index===-1)
+return false;var newIndex=index+offset;if(newIndex<0||newIndex>=this.rects_.length)
+return false;this.rects_[newIndex].addToSelection(selection);return true;},addAllEventsMatchingFilterToSelection:function(filter,selection){for(var i=0;i<this.rects_.length;++i){var modelItem=this.rects_[i].modelItem;if(!modelItem)
+continue;if(filter.matchSlice(modelItem))
+selection.push(modelItem);}},addClosestEventToSelection:function(worldX,worldMaxDist,loY,hiY,selection){var rect=tr.b.findClosestIntervalInSortedIntervals(this.rects_,function(x){return x.start;},function(x){return x.end;},worldX,worldMaxDist);if(!rect)
+return;rect.addToSelection(selection);}};function Rect(modelItem,title,colorId,start,duration){tr.model.ProxySelectableItem.call(this,modelItem);this.title=title;this.colorId=colorId;this.start=start;this.duration=duration;this.end=start+duration;};Rect.prototype={__proto__:tr.model.ProxySelectableItem.prototype};return{RectTrack:RectTrack,Rect:Rect};});'use strict';tr.exportTo('tr.ui.tracks',function(){var ProcessSummaryTrack=tr.ui.b.define('process-summary-track',tr.ui.tracks.RectTrack [...]
+return[];var ops=[];var pushOp=function(isStart,time,slice){ops.push({isStart:isStart,time:time,slice:slice});};for(var tid in process.threads){var sliceGroup=process.threads[tid].sliceGroup;sliceGroup.topLevelSlices.forEach(function(slice){pushOp(true,slice.start,undefined);pushOp(false,slice.end,undefined);});sliceGroup.slices.forEach(function(slice){if(slice.important){pushOp(true,slice.start,slice);pushOp(false,slice.end,slice);}});}
+ops.sort(function(a,b){return a.time-b.time;});var rects=[];var genericColorId=tr.ui.b.getColorIdForReservedName('generic_work');var pushRect=function(start,end,slice){rects.push(new tr.ui.tracks.Rect(slice,slice?slice.title:'',slice?slice.colorId:genericColorId,start,end-start));}
+var depth=0;var currentSlice=undefined;var lastStart=undefined;ops.forEach(function(op){depth+=op.isStart?1:-1;if(currentSlice){if(!op.isStart&&op.slice==currentSlice){pushRect(lastStart,op.time,currentSlice);lastStart=depth>=1?op.time:undefined;currentSlice=undefined;}}else{if(op.isStart){if(depth==1){lastStart=op.time;currentSlice=op.slice;}else if(op.slice){if(op.time!=lastStart){pushRect(lastStart,op.time,undefined);lastStart=op.time;}
+currentSlice=op.slice;}}else{if(depth==0){pushRect(lastStart,op.time,undefined);lastStart=undefined;}}}});return rects;};ProcessSummaryTrack.prototype={__proto__:tr.ui.tracks.RectTrack.prototype,decorate:function(viewport){tr.ui.tracks.RectTrack.prototype.decorate.call(this,viewport);},get process(){return this.process_;},set process(process){this.process_=process;this.rects=ProcessSummaryTrack.buildRectsFromProcess(process);}};return{ProcessSummaryTrack:ProcessSummaryTrack};});'use stri [...]
+return[];var ops=[];for(var i=0;i<slices.length;i++){if(slices[i].subSlices)
+slices[i].subSlices.splice(0,slices[i].subSlices.length);ops.push(i);}
+ops.sort(function(ix,iy){var x=slices[ix];var y=slices[iy];if(x.start!=y.start)
+return x.start-y.start;return ix-iy;});var subRows=[[]];this.badSlices_=[];for(var i=0;i<ops.length;i++){var op=ops[i];var slice=slices[op];var inserted=false;for(var j=subRows.length-1;j>=0;j--){if(subRows[j].length==0)
+continue;var insertedSlice=subRows[j][subRows[j].length-1];if(slice.start<insertedSlice.start){this.badSlices_.push(slice);inserted=true;}
+if(insertedSlice.bounds(slice,precisionUnit)){while(subRows.length<=j+1)
+subRows.push([]);subRows[j+1].push(slice);if(insertedSlice.subSlices)
+insertedSlice.subSlices.push(slice);inserted=true;break;}}
+if(inserted)
+continue;subRows[0].push(slice);}
+return subRows;}};return{SliceGroupTrack:SliceGroupTrack};});'use strict';tr.exportTo('tr.ui.tracks',function(){var AsyncSliceGroupTrack=tr.ui.b.define('async-slice-group-track',tr.ui.tracks.MultiRowTrack);AsyncSliceGroupTrack.prototype={__proto__:tr.ui.tracks.MultiRowTrack.prototype,decorate:function(viewport){tr.ui.tracks.MultiRowTrack.prototype.decorate.call(this,viewport);this.classList.add('async-slice-group-track');this.group_=undefined;},addSubTrack_:function(slices){var track=new [...]
+var findLevel=function(sliceToPut,rows,n){if(n>=rows.length)
+return true;var subRow=rows[n];var lastSliceInSubRow=subRow[subRow.length-1];if(sliceToPut.start>=lastSliceInSubRow.end){if(sliceToPut.subSlices===undefined||sliceToPut.subSlices.length===0){return true;}
+for(var i=0;i<sliceToPut.subSlices.length;i++){if(!findLevel(sliceToPut.subSlices[i],rows,n+1))
+return false;}
+return true;}
+return false;}
+var subRows=[];for(var i=0;i<slices.length;i++){var slice=slices[i];var found=false;var index=subRows.length;for(var j=0;j<subRows.length;j++){if(findLevel(slice,subRows,j)){found=true;index=j;break;}}
+if(!found)
+subRows.push([]);subRows[index].push(slice);var fitSubSlicesRecursively=function(subSlices,level,rows){if(subSlices===undefined||subSlices.length===0)
+return;if(level===rows.length)
+rows.push([]);for(var h=0;h<subSlices.length;h++){rows[level].push(subSlices[h]);fitSubSlicesRecursively(subSlices[h].subSlices,level+1,rows);}}
+fitSubSlicesRecursively(slice.subSlices,index+1,subRows);}
+return subRows;}};return{AsyncSliceGroupTrack:AsyncSliceGroupTrack};});'use strict';tr.exportTo('tr.ui.tracks',function(){var ThreadTrack=tr.ui.b.define('thread-track',tr.ui.tracks.ContainerTrack);ThreadTrack.prototype={__proto__:tr.ui.tracks.ContainerTrack.prototype,decorate:function(viewport){tr.ui.tracks.ContainerTrack.prototype.decorate.call(this,viewport);this.classList.add('thread-track');},get thread(){return this.thread_;},set thread(thread){this.thread_=thread;this.updateContent [...]
+this.childNodes[i].addContainersToTrackMap(containerToTrackMap);},updateContents_:function(){this.detach();if(!this.thread_)
+return;this.heading=this.thread_.userFriendlyName+': ';this.tooltip=this.thread_.userFriendlyDetails;if(this.thread_.asyncSliceGroup.length)
+this.appendAsyncSliceTracks_();this.appendThreadSamplesTracks_();if(this.thread_.timeSlices){var timeSlicesTrack=new tr.ui.tracks.SliceTrack(this.viewport);timeSlicesTrack.heading='';timeSlicesTrack.height=tr.ui.b.THIN_SLICE_HEIGHT+'px';timeSlicesTrack.slices=this.thread_.timeSlices;if(timeSlicesTrack.hasVisibleContent)
+this.appendChild(timeSlicesTrack);}
+if(this.thread_.sliceGroup.length){var track=new tr.ui.tracks.SliceGroupTrack(this.viewport);track.heading=this.thread_.userFriendlyName;track.tooltip=this.thread_.userFriendlyDetails;track.group=this.thread_.sliceGroup;if(track.hasVisibleContent)
+this.appendChild(track);}},appendAsyncSliceTracks_:function(){var subGroups=this.thread_.asyncSliceGroup.viewSubGroups;subGroups.forEach(function(subGroup){var asyncTrack=new tr.ui.tracks.AsyncSliceGroupTrack(this.viewport);var title=subGroup.slices[0].viewSubGroupTitle;asyncTrack.group=subGroup;asyncTrack.heading=title;if(asyncTrack.hasVisibleContent)
+this.appendChild(asyncTrack);},this);},appendThreadSamplesTracks_:function(){var threadSamples=this.thread_.samples;if(threadSamples===undefined||threadSamples.length===0)
+return;var samplesByTitle={};threadSamples.forEach(function(sample){if(samplesByTitle[sample.title]===undefined)
+samplesByTitle[sample.title]=[];samplesByTitle[sample.title].push(sample);});var sampleTitles=tr.b.dictionaryKeys(samplesByTitle);sampleTitles.sort();sampleTitles.forEach(function(sampleTitle){var samples=samplesByTitle[sampleTitle];var samplesTrack=new tr.ui.tracks.SampleTrack(this.viewport);samplesTrack.group=this.thread_;samplesTrack.samples=samples;samplesTrack.heading=this.thread_.userFriendlyName+': '+
+sampleTitle;samplesTrack.tooltip=this.thread_.userFriendlyDetails;samplesTrack.selectionGenerator=function(){var selection=new tr.c.Selection();for(var i=0;i<samplesTrack.samples.length;i++){selection.push(samplesTrack.samples[i]);}
+return selection;};this.appendChild(samplesTrack);},this);},collapsedDidChange:function(collapsed){if(collapsed){var h=parseInt(this.tracks[0].height);for(var i=0;i<this.tracks.length;++i){if(h>2){this.tracks[i].height=Math.floor(h)+'px';}else{this.tracks[i].style.display='none';}
+h=h*0.5;}}else{for(var i=0;i<this.tracks.length;++i){this.tracks[i].height=this.tracks[0].height;this.tracks[i].style.display='';}}}};return{ThreadTrack:ThreadTrack};});'use strict';tr.exportTo('tr.ui.tracks',function(){var ObjectSnapshotView=tr.ui.analysis.ObjectSnapshotView;var ObjectInstanceView=tr.ui.analysis.ObjectInstanceView;var SpacingTrack=tr.ui.tracks.SpacingTrack;var ProcessTrackBase=tr.ui.b.define('process-track-base',tr.ui.tracks.ContainerTrack);ProcessTrackBase.prototype={_ [...]
+this.updateContents_();},get expanded(){return this.classList.contains('expanded');},set expanded(expanded){expanded=!!expanded;if(this.expanded===expanded)
+return;this.classList.toggle('expanded');this.viewport_.dispatchChangeEvent();if(!this.processBase_)
+return;var modelSettings=new tr.model.ModelSettings(this.processBase_.model);modelSettings.setSettingFor(this.processBase_,'expanded',expanded);this.updateContents_();this.viewport.rebuildEventToTrackMap();this.viewport.rebuildContainerToTrackMap();},get hasVisibleContent(){if(this.expanded)
+return this.children.length>1;return true;},onHeaderClick_:function(e){e.stopPropagation();e.preventDefault();this.expanded=!this.expanded;},updateContents_:function(){this.tracks_.forEach(function(track){this.removeChild(track);},this);if(!this.processBase_)
+return;this.processNameEl_.textContent=this.processBase_.userFriendlyName;this.headerEl_.title=this.processBase_.userFriendlyDetails;this.willAppendTracks_();if(this.expanded){this.appendMemoryDumpTrack_();this.appendObjectInstanceTracks_();this.appendCounterTracks_();this.appendFrameTrack_();this.appendThreadTracks_();}else{this.appendSummaryTrack_();}
+this.didAppendTracks_();},addEventsToTrackMap:function(eventToTrackMap){this.tracks_.forEach(function(track){track.addEventsToTrackMap(eventToTrackMap);});},willAppendTracks_:function(){},didAppendTracks_:function(){},appendMemoryDumpTrack_:function(){},appendSummaryTrack_:function(){var track=new tr.ui.tracks.ProcessSummaryTrack(this.viewport);track.process=this.process;if(!track.hasVisibleContent)
+return;this.appendChild(track);},appendFrameTrack_:function(){var frames=this.process?this.process.frames:undefined;if(!frames||!frames.length)
+return;var track=new tr.ui.tracks.FrameTrack(this.viewport);track.frames=frames;this.appendChild(track);this.backgroundProvider=track;},appendObjectInstanceTracks_:function(){var instancesByTypeName=this.processBase_.objects.getAllInstancesByTypeName();var instanceTypeNames=tr.b.dictionaryKeys(instancesByTypeName);instanceTypeNames.sort();var didAppendAtLeastOneTrack=false;instanceTypeNames.forEach(function(typeName){var allInstances=instancesByTypeName[typeName];var instanceViewInfo=Obj [...]
+instanceViewInfo=undefined;if(snapshotViewInfo&&!snapshotViewInfo.metadata.showInTrackView)
+snapshotViewInfo=undefined;var hasViewInfo=instanceViewInfo||snapshotViewInfo;var visibleInstances=[];for(var i=0;i<allInstances.length;i++){var instance=allInstances[i];if(instance.snapshots.length===0)
+continue;if(instance.hasImplicitSnapshots&&!hasViewInfo)
+continue;visibleInstances.push(instance);}
+if(visibleInstances.length===0)
+return;var trackConstructor=tr.ui.tracks.ObjectInstanceTrack.getConstructor(undefined,typeName);if(!trackConstructor){var snapshotViewInfo=ObjectSnapshotView.getTypeInfo(undefined,typeName);if(snapshotViewInfo&&snapshotViewInfo.metadata.showInstances){trackConstructor=tr.ui.tracks.ObjectInstanceGroupTrack;}else{trackConstructor=tr.ui.tracks.ObjectInstanceTrack;}}
+var track=new trackConstructor(this.viewport);track.objectInstances=visibleInstances;this.appendChild(track);didAppendAtLeastOneTrack=true;},this);if(didAppendAtLeastOneTrack)
+this.appendChild(new SpacingTrack(this.viewport));},appendCounterTracks_:function(){var counters=tr.b.dictionaryValues(this.processBase.counters);counters.sort(tr.model.Counter.compare);counters.forEach(function(counter){var track=new tr.ui.tracks.CounterTrack(this.viewport);track.counter=counter;this.appendChild(track);this.appendChild(new SpacingTrack(this.viewport));}.bind(this));},appendThreadTracks_:function(){var threads=tr.b.dictionaryValues(this.processBase.threads);threads.sort( [...]
+return;this.appendChild(track);this.appendChild(new SpacingTrack(this.viewport));}.bind(this));}};return{ProcessTrackBase:ProcessTrackBase};});'use strict';tr.exportTo('tr.ui.tracks',function(){var CpuTrack=tr.ui.b.define('cpu-track',tr.ui.tracks.ContainerTrack);CpuTrack.prototype={__proto__:tr.ui.tracks.ContainerTrack.prototype,decorate:function(viewport){tr.ui.tracks.ContainerTrack.prototype.decorate.call(this,viewport);this.classList.add('cpu-track');this.detailedMode_=true;},get cpu( [...]
+return false;var cpu=this.cpu_;if(cpu.slices.length)
+return true;if(cpu.samples&&cpu.samples.length)
+return true;if(tr.b.dictionaryLength(cpu.counters)>0)
+return true;return false;},updateContents_:function(){this.detach();if(!this.cpu_)
+return;var slices=this.cpu_.slices;if(slices.length){var track=new tr.ui.tracks.SliceTrack(this.viewport);track.slices=slices;track.heading=this.cpu_.userFriendlyName+':';this.appendChild(track);}
+if(this.detailedMode_){this.appendSamplesTracks_();for(var counterName in this.cpu_.counters){var counter=this.cpu_.counters[counterName];track=new tr.ui.tracks.CounterTrack(this.viewport);track.heading=this.cpu_.userFriendlyName+' '+
+counter.name+':';track.counter=counter;this.appendChild(track);}}},appendSamplesTracks_:function(){var samples=this.cpu_.samples;if(samples===undefined||samples.length===0)
+return;var samplesByTitle={};samples.forEach(function(sample){if(samplesByTitle[sample.title]===undefined)
+samplesByTitle[sample.title]=[];samplesByTitle[sample.title].push(sample);});var sampleTitles=tr.b.dictionaryKeys(samplesByTitle);sampleTitles.sort();sampleTitles.forEach(function(sampleTitle){var samples=samplesByTitle[sampleTitle];var samplesTrack=new tr.ui.tracks.SliceTrack(this.viewport);samplesTrack.group=this.cpu_;samplesTrack.slices=samples;samplesTrack.heading=this.cpu_.userFriendlyName+': '+
+sampleTitle;samplesTrack.tooltip=this.cpu_.userFriendlyDetails;samplesTrack.selectionGenerator=function(){var selection=new tr.c.Selection();for(var i=0;i<samplesTrack.slices.length;i++){selection.push(samplesTrack.slices[i]);}
+return selection;};this.appendChild(samplesTrack);},this);}};return{CpuTrack:CpuTrack};});'use strict';tr.exportTo('tr.ui.tracks',function(){var Cpu=tr.model.Cpu;var CpuTrack=tr.ui.tracks.cpu_track;var ProcessTrackBase=tr.ui.tracks.ProcessTrackBase;var SpacingTrack=tr.ui.tracks.SpacingTrack;var KernelTrack=tr.ui.b.define('kernel-track',ProcessTrackBase);KernelTrack.prototype={__proto__:ProcessTrackBase.prototype,decorate:function(viewport){ProcessTrackBase.prototype.decorate.call(this,vi [...]
+continue;this.appendChild(track);didAppendAtLeastOneTrack=true;}
+if(didAppendAtLeastOneTrack)
+this.appendChild(new SpacingTrack(this.viewport));}};return{KernelTrack:KernelTrack};});'use strict';tr.exportTo('tr.ui.tracks',function(){var AlertTrack=tr.ui.b.define('alert-track',tr.ui.tracks.LetterDotTrack);AlertTrack.prototype={__proto__:tr.ui.tracks.LetterDotTrack.prototype,decorate:function(viewport){tr.ui.tracks.LetterDotTrack.prototype.decorate.call(this,viewport);this.heading='Alerts';this.alerts_=undefined;},get alerts(){return this.alerts_;},set alerts(alerts){this.alerts_=a [...]
+this.items=this.alerts_.map(function(alert){return new tr.ui.tracks.LetterDot(alert,String.fromCharCode(9888),alert.colorId,alert.start);});}};return{AlertTrack:AlertTrack};});'use strict';tr.exportTo('tr.ui.tracks',function(){var ALLOCATOR_SIZE_ATTRIBUTE_NAME='size';function addDictionary(dstDict,srcDict){tr.b.iterItems(srcDict,function(key,value){var existingValue=dstDict[key];if(existingValue===undefined)
+existingValue=0;dstDict[key]=existingValue+value;});}
+function getProcessMemoryDumpAllocatorSizes(processMemoryDump){var allocatorDumps=processMemoryDump.memoryAllocatorDumps;if(allocatorDumps===undefined)
+return{};var allocatorSizes={};allocatorDumps.forEach(function(allocatorDump){if(allocatorDump.fullName==='tracing')
+return;var allocatorSize=allocatorDump.attributes[ALLOCATOR_SIZE_ATTRIBUTE_NAME];if(allocatorSize===undefined)
+return;var allocatorSizeValue=allocatorSize.value;if(allocatorSizeValue===undefined)
+return;allocatorSizes[allocatorDump.fullName]=allocatorSizeValue;});return allocatorSizes;};function getGlobalMemoryDumpAllocatorSizes(globalMemoryDump){var globalAllocatorSizes={};tr.b.iterItems(globalMemoryDump.processMemoryDumps,function(pid,processMemoryDump){addDictionary(globalAllocatorSizes,getProcessMemoryDumpAllocatorSizes(processMemoryDump));});return globalAllocatorSizes;}
+function buildAllocatedMemoryChartSeries(memoryDumps,memoryDumpToAllocatorSizesFn){var allocatorNameToPoints={};var dumpsData=memoryDumps.map(function(memoryDump){var allocatorSizes=memoryDumpToAllocatorSizesFn(memoryDump);tr.b.iterItems(allocatorSizes,function(allocatorName){allocatorNameToPoints[allocatorName]=[];});return{dump:memoryDump,sizes:allocatorSizes};});if(Object.keys(allocatorNameToPoints).length===0)
+return undefined;dumpsData.forEach(function(dumpData){var memoryDump=dumpData.dump;var allocatorSizes=dumpData.sizes;tr.b.iterItems(allocatorNameToPoints,function(allocatorName,points){var allocatorSize=allocatorSizes[allocatorName]||0;points.push(new tr.ui.tracks.ChartPoint(memoryDump,memoryDump.start,allocatorSize));});});var axis=new tr.ui.tracks.ChartAxis(0);var series=[];tr.b.iterItems(allocatorNameToPoints,function(allocatorName,points){var colorId=tr.ui.b.getColorIdForGeneralPurpo [...]
+function buildMemoryLetterDots(memoryDumps){var memoryColorId=tr.ui.b.getColorIdForReservedName('memory_dump');return memoryDumps.map(function(memoryDump){return new tr.ui.tracks.LetterDot(memoryDump,'M',memoryColorId,memoryDump.start);});}
+function buildGlobalUsedMemoryChartSeries(globalMemoryDumps){var containsVmRegions=globalMemoryDumps.some(function(globalDump){for(var pid in globalDump.processMemoryDumps)
+if(globalDump.processMemoryDumps[pid].mostRecentVmRegions)
+return true;return false;});if(!containsVmRegions)
+return undefined;var pidToProcess={};globalMemoryDumps.forEach(function(globalDump){tr.b.iterItems(globalDump.processMemoryDumps,function(pid,processDump){pidToProcess[pid]=processDump.process;});});var pidToPoints={};tr.b.iterItems(pidToProcess,function(pid,process){pidToPoints[pid]=[];});globalMemoryDumps.forEach(function(globalDump){var pssBase=0;tr.b.iterItems(pidToPoints,function(pid,points){var processMemoryDump=globalDump.processMemoryDumps[pid];var pss;if(processMemoryDump===unde [...]
+var cumulativePss=pssBase+pss;points.push(new tr.ui.tracks.ChartPoint(globalDump,globalDump.start,cumulativePss,pssBase));pssBase=cumulativePss;});});var axis=new tr.ui.tracks.ChartAxis(0);var series=[];tr.b.iterItems(pidToPoints,function(pid,points){var process=pidToProcess[pid];var colorId=tr.ui.b.getColorIdForGeneralPurposeString(process.userFriendlyName);var renderingConfig={chartType:tr.ui.tracks.ChartSeriesType.AREA,colorId:colorId,backgroundOpacity:0.8};series.push(new tr.ui.track [...]
+function buildProcessAllocatedMemoryChartSeries(processMemoryDumps){return buildAllocatedMemoryChartSeries(processMemoryDumps,getProcessMemoryDumpAllocatorSizes);}
+function buildGlobalAllocatedMemoryChartSeries(globalMemoryDumps){return buildAllocatedMemoryChartSeries(globalMemoryDumps,getGlobalMemoryDumpAllocatorSizes);}
+return{buildMemoryLetterDots:buildMemoryLetterDots,buildGlobalUsedMemoryChartSeries:buildGlobalUsedMemoryChartSeries,buildProcessAllocatedMemoryChartSeries:buildProcessAllocatedMemoryChartSeries,buildGlobalAllocatedMemoryChartSeries:buildGlobalAllocatedMemoryChartSeries};});'use strict';tr.exportTo('tr.ui.tracks',function(){var USED_MEMORY_TRACK_HEIGHT=50;var ALLOCATED_MEMORY_TRACK_HEIGHT=50;var GlobalMemoryDumpTrack=tr.ui.b.define('global-memory-dump-track',tr.ui.tracks.ContainerTrack); [...]
+return;this.appendDumpDotsTrack_();this.appendUsedMemoryTrack_();this.appendAllocatedMemoryTrack_();},appendDumpDotsTrack_:function(){var items=tr.ui.tracks.buildMemoryLetterDots(this.memoryDumps_);if(!items)
+return;var track=new tr.ui.tracks.LetterDotTrack(this.viewport);track.heading='Memory Dumps';track.items=items;this.appendChild(track);},appendUsedMemoryTrack_:function(){var series=tr.ui.tracks.buildGlobalUsedMemoryChartSeries(this.memoryDumps_);if(!series)
+return;var track=new tr.ui.tracks.ChartTrack(this.viewport);track.heading='Used memory (per process)';track.height=USED_MEMORY_TRACK_HEIGHT+'px';track.series=series;track.autoSetAllAxes({expandMax:true});this.appendChild(track);},appendAllocatedMemoryTrack_:function(){var series=tr.ui.tracks.buildGlobalAllocatedMemoryChartSeries(this.memoryDumps_);if(!series)
+return;var track=new tr.ui.tracks.ChartTrack(this.viewport);track.heading='Allocated memory (per allocator)';track.height=ALLOCATED_MEMORY_TRACK_HEIGHT+'px';track.series=series;track.autoSetAllAxes({expandMax:true});this.appendChild(track);}};return{GlobalMemoryDumpTrack:GlobalMemoryDumpTrack};});'use strict';tr.exportTo('tr.ui.tracks',function(){var ALLOCATED_MEMORY_TRACK_HEIGHT=50;var ProcessMemoryDumpTrack=tr.ui.b.define('process-memory-dump-track',tr.ui.tracks.ContainerTrack);Process [...]
+return;this.appendAllocatedMemoryTrack_();},appendAllocatedMemoryTrack_:function(){var series=tr.ui.tracks.buildProcessAllocatedMemoryChartSeries(this.memoryDumps_);if(!series)
+return;var track=new tr.ui.tracks.ChartTrack(this.viewport);track.heading='Allocated memory (per allocator)';track.height=ALLOCATED_MEMORY_TRACK_HEIGHT+'px';track.series=series;track.autoSetAllAxes({expandMax:true});this.appendChild(track);}};return{ProcessMemoryDumpTrack:ProcessMemoryDumpTrack};});'use strict';tr.exportTo('tr.ui.tracks',function(){var ProcessTrackBase=tr.ui.tracks.ProcessTrackBase;var ProcessTrack=tr.ui.b.define('process-track',ProcessTrackBase);ProcessTrack.prototype={ [...]
+break;var ctx=this.context();var pixelRatio=window.devicePixelRatio||1;var bounds=this.getBoundingClientRect();var canvasBounds=ctx.canvas.getBoundingClientRect();ctx.save();ctx.translate(0,pixelRatio*(bounds.top-canvasBounds.top));var dt=this.viewport.currentDisplayTransform;var viewLWorld=dt.xViewToWorld(0);var viewRWorld=dt.xViewToWorld(bounds.width*pixelRatio);tr.ui.b.drawInstantSlicesAsLines(ctx,this.viewport.currentDisplayTransform,viewLWorld,viewRWorld,bounds.height,this.processBa [...]
+tr.ui.tracks.ContainerTrack.prototype.drawTrack.call(this,type);},drawBackground_:function(){var ctx=this.context();var canvasBounds=ctx.canvas.getBoundingClientRect();var pixelRatio=window.devicePixelRatio||1;var draw=false;ctx.fillStyle='#eee';for(var i=0;i<this.children.length;++i){if(!(this.children[i]instanceof tr.ui.tracks.Track)||(this.children[i]instanceof tr.ui.tracks.SpacingTrack))
+continue;draw=!draw;if(!draw)
+continue;var bounds=this.children[i].getBoundingClientRect();ctx.fillRect(0,pixelRatio*(bounds.top-canvasBounds.top),ctx.canvas.width,pixelRatio*bounds.height);}},set process(process){this.processBase=process;},get process(){return this.processBase;},get eventContainer(){return this.process;},addContainersToTrackMap:function(containerToTrackMap){containerToTrackMap.addContainer(this.process,this);this.tracks_.forEach(function(track){track.addContainersToTrackMap(containerToTrackMap);});} [...]
+tr.b.iterateOverIntersectingIntervals(this.processBase.instantEvents,function(x){return x.start;},function(x){return x.duration;},loWX,hiWX,onPickHit.bind(this));tr.ui.tracks.ContainerTrack.prototype.addIntersectingEventsInRangeToSelectionInWorldSpace.apply(this,arguments);},addClosestEventToSelection:function(worldX,worldMaxDist,loY,hiY,selection){this.addClosestInstantEventToSelection(this.processBase.instantEvents,worldX,worldMaxDist,selection);tr.ui.tracks.ContainerTrack.prototype.ad [...]
+return r;return x.start-y.start;});return tr.ui.tracks.AsyncSliceGroupTrack.prototype.buildSubRows_.call({},slices,true);};mrt.addSubTrack_=function(slices){var track=new tr.ui.tracks.SliceTrack(this.viewport);track.slices=slices;this.appendChild(track);return track;};mrt.setItemsToGroup(model.interaction_records,{guid:tr.b.GUID.allocate(),model:model,getSettingsKey:function(){return undefined;}});return mrt;}
+var SelectionState=tr.model.SelectionState;var EventPresenter=tr.ui.b.EventPresenter;var ModelTrack=tr.ui.b.define('model-track',tr.ui.tracks.ContainerTrack);ModelTrack.prototype={__proto__:tr.ui.tracks.ContainerTrack.prototype,decorate:function(viewport){tr.ui.tracks.ContainerTrack.prototype.decorate.call(this,viewport);this.classList.add('model-track');var typeInfos=tr.ui.tracks.Highlighter.getAllRegisteredTypeInfos();this.highlighters_=typeInfos.map(function(typeInfo){return new typeI [...]
+return;if(this.upperMode_)
+this.updateContentsForUpperMode_();else
+this.updateContentsForLowerMode_();},updateContentsForUpperMode_:function(){},updateContentsForLowerMode_:function(){if(this.model_.interaction_records.length){var mrt=new HackyMultiRowTrack(this.viewport_,this.model_);this.appendChild(mrt);}
+if(this.model_.alerts.length){var at=new tr.ui.tracks.AlertTrack(this.viewport_);at.alerts=this.model_.alerts;this.appendChild(at);}
+if(this.model_.globalMemoryDumps.length){var gmdt=new tr.ui.tracks.GlobalMemoryDumpTrack(this.viewport_);gmdt.memoryDumps=this.model_.globalMemoryDumps;this.appendChild(gmdt);}
+this.appendKernelTrack_();var processes=this.model_.getAllProcesses();processes.sort(tr.model.Process.compare);for(var i=0;i<processes.length;++i){var process=processes[i];var track=new tr.ui.tracks.ProcessTrack(this.viewport);track.process=process;if(!track.hasVisibleContent)
+continue;this.appendChild(track);}
+this.viewport_.rebuildEventToTrackMap();this.viewport_.rebuildContainerToTrackMap();for(var i=0;i<this.highlighters_.length;i++){this.highlighters_[i].processModel(this.model_);}
+this.updateAnnotations_();},updateAnnotations_:function(){this.annotationViews_=[];var annotations=this.model_.getAllAnnotations();for(var i=0;i<annotations.length;i++){this.annotationViews_.push(annotations[i].getOrCreateView(this.viewport_));}
+this.invalidateDrawingContainer();},addEventsToTrackMap:function(eventToTrackMap){if(!this.model_)
+return;var tracks=this.children;for(var i=0;i<tracks.length;++i)
+tracks[i].addEventsToTrackMap(eventToTrackMap);if(this.instantEvents===undefined)
+return;var vp=this.viewport_;this.instantEvents.forEach(function(ev){eventToTrackMap.addEvent(ev,this);}.bind(this));},addContainersToTrackMap:function(containerToTrackMap){var tracks=this.children;for(var i=0;i<tracks.length;++i)
+tracks[i].addContainersToTrackMap(containerToTrackMap);},appendKernelTrack_:function(){var kernel=this.model.kernel;var track=new tr.ui.tracks.KernelTrack(this.viewport);track.kernel=this.model.kernel;if(!track.hasVisibleContent)
+return;this.appendChild(track);},drawTrack:function(type){var ctx=this.context();if(!this.model_)
+return;var pixelRatio=window.devicePixelRatio||1;var bounds=this.getBoundingClientRect();var canvasBounds=ctx.canvas.getBoundingClientRect();ctx.save();ctx.translate(0,pixelRatio*(bounds.top-canvasBounds.top));var dt=this.viewport.currentDisplayTransform;var viewLWorld=dt.xViewToWorld(0);var viewRWorld=dt.xViewToWorld(bounds.width*pixelRatio);switch(type){case tr.ui.tracks.DrawType.GRID:this.viewport.drawMajorMarkLines(ctx);ctx.restore();return;case tr.ui.tracks.DrawType.FLOW_ARROWS:if(t [...]
+this.drawFlowArrows_(viewLWorld,viewRWorld);ctx.restore();return;case tr.ui.tracks.DrawType.INSTANT_EVENT:if(!this.model_.instantEvents||this.model_.instantEvents.length===0)
+break;tr.ui.b.drawInstantSlicesAsLines(ctx,this.viewport.currentDisplayTransform,viewLWorld,viewRWorld,bounds.height,this.model_.instantEvents,4);break;case tr.ui.tracks.DrawType.MARKERS:if(!this.viewport.interestRange.isEmpty){this.viewport.interestRange.draw(ctx,viewLWorld,viewRWorld);this.viewport.interestRange.drawIndicators(ctx,viewLWorld,viewRWorld);}
+ctx.restore();return;case tr.ui.tracks.DrawType.HIGHLIGHTS:for(var i=0;i<this.highlighters_.length;i++){this.highlighters_[i].drawHighlight(ctx,dt,viewLWorld,viewRWorld,bounds.height);}
+ctx.restore();return;case tr.ui.tracks.DrawType.ANNOTATIONS:for(var i=0;i<this.annotationViews_.length;i++){this.annotationViews_[i].draw(ctx);}
+ctx.restore();return;}
+ctx.restore();tr.ui.tracks.ContainerTrack.prototype.drawTrack.call(this,type);},drawFlowArrows_:function(viewLWorld,viewRWorld){var ctx=this.context();var dt=this.viewport.currentDisplayTransform;dt.applyTransformToCanvas(ctx);var pixWidth=dt.xViewVectorToWorld(1);ctx.strokeStyle='rgba(0, 0, 0, 0.4)';ctx.fillStyle='rgba(0, 0, 0, 0.4)';ctx.lineWidth=pixWidth>1.0?1:pixWidth;var events=this.model_.flowIntervalTree.findIntersection(viewLWorld,viewRWorld);var onlyHighlighted=!this.viewport.sh [...]
+continue;this.drawFlowArrow_(ctx,events[i],canvasBounds,pixWidth);}},drawFlowArrow_:function(ctx,flowEvent,canvasBounds,pixWidth){var pixelRatio=window.devicePixelRatio||1;var startTrack=this.viewport.trackForEvent(flowEvent.startSlice);var endTrack=this.viewport.trackForEvent(flowEvent.endSlice);if(startTrack===undefined||endTrack===undefined)
+return;var startBounds=startTrack.getBoundingClientRect();var endBounds=endTrack.getBoundingClientRect();if(flowEvent.selectionState==SelectionState.SELECTED){ctx.shadowBlur=1;ctx.shadowColor='red';ctx.shadowOffsety=2;ctx.strokeStyle='red';}else if(flowEvent.selectionState==SelectionState.HIGHLIGHTED){ctx.shadowBlur=1;ctx.shadowColor='red';ctx.shadowOffsety=2;ctx.strokeStyle='red';}else if(flowEvent.selectionState==SelectionState.DIMMED){ctx.shadowBlur=0;ctx.shadowOffsetX=0;ctx.strokeSty [...]
+var startSize=startBounds.left+startBounds.top+
+startBounds.bottom+startBounds.right;var endSize=endBounds.left+endBounds.top+
+endBounds.bottom+endBounds.right;if(startSize===0&&endSize===0)
+return;var startY=this.calculateTrackY_(startTrack,canvasBounds);var endY=this.calculateTrackY_(endTrack,canvasBounds);var pixelStartY=pixelRatio*startY;var pixelEndY=pixelRatio*endY;var half=(flowEvent.end-flowEvent.start)/2;ctx.beginPath();ctx.moveTo(flowEvent.start,pixelStartY);ctx.bezierCurveTo(flowEvent.start+half,pixelStartY,flowEvent.start+half,pixelEndY,flowEvent.end,pixelEndY);ctx.stroke();var arrowWidth=5*pixWidth*pixelRatio;var distance=flowEvent.end-flowEvent.start;if(distanc [...]
+return;var tipX=flowEvent.end;var tipY=pixelEndY;var arrowHeight=(endBounds.height/4)*pixelRatio;tr.ui.b.drawTriangle(ctx,tipX,tipY,tipX-arrowWidth,tipY-arrowHeight,tipX-arrowWidth,tipY+arrowHeight);ctx.fill();},calculateTrackY_:function(track,canvasBounds){var bounds=track.getBoundingClientRect();var size=bounds.left+bounds.top+bounds.bottom+bounds.right;if(size===0)
+return this.calculateTrackY_(track.parentNode,canvasBounds);return bounds.top-canvasBounds.top+(bounds.height/2);},addIntersectingEventsInRangeToSelectionInWorldSpace:function(loWX,hiWX,viewPixWidthWorld,selection){function onPickHit(instantEvent){selection.push(instantEvent);}
+tr.b.iterateOverIntersectingIntervals(this.model_.instantEvents,function(x){return x.start;},function(x){return x.duration;},loWX,hiWX,onPickHit.bind(this));tr.ui.tracks.ContainerTrack.prototype.addIntersectingEventsInRangeToSelectionInWorldSpace.apply(this,arguments);},addClosestEventToSelection:function(worldX,worldMaxDist,loY,hiY,selection){this.addClosestInstantEventToSelection(this.model_.instantEvents,worldX,worldMaxDist,selection);tr.ui.tracks.ContainerTrack.prototype.addClosestEv [...]
+RulerTrack.prototype={__proto__:tr.ui.tracks.HeadingTrack.prototype,decorate:function(viewport){tr.ui.tracks.HeadingTrack.prototype.decorate.call(this,viewport);this.classList.add('ruler-track');this.strings_secs_=[];this.strings_msecs_=[];this.strings_usecs_=[];this.strings_nsecs_=[];this.viewportChange_=this.viewportChange_.bind(this);viewport.addEventListener('change',this.viewportChange_);},detach:function(){tr.ui.tracks.HeadingTrack.prototype.detach.call(this);this.viewport.removeEv [...]
+this.classList.remove('tall-mode');else
+this.classList.add('tall-mode');},draw:function(type,viewLWorld,viewRWorld){switch(type){case tr.ui.tracks.DrawType.GRID:this.drawGrid_(viewLWorld,viewRWorld);break;case tr.ui.tracks.DrawType.MARKERS:if(!this.viewport.interestRange.isEmpty)
+this.viewport.interestRange.draw(this.context(),viewLWorld,viewRWorld);break;}},drawGrid_:function(viewLWorld,viewRWorld){var ctx=this.context();var pixelRatio=window.devicePixelRatio||1;var canvasBounds=ctx.canvas.getBoundingClientRect();var trackBounds=this.getBoundingClientRect();var width=canvasBounds.width*pixelRatio;var height=trackBounds.height*pixelRatio;var hasInterestRange=!this.viewport.interestRange.isEmpty;var rulerHeight=hasInterestRange?(height*2)/5:height;var vp=this.view [...]
+continue;majorMarkDistanceWorld=conservativeGuess/divisors[i-1];break;}
+var unit;var unitDivisor;var tickLabels=undefined;if(majorMarkDistanceWorld<0.0001){unit='ns';unitDivisor=0.000001;tickLabels=this.strings_nsecs_;}else if(majorMarkDistanceWorld<0.1){unit='us';unitDivisor=0.001;tickLabels=this.strings_usecs_;}else if(majorMarkDistanceWorld<100){unit='ms';unitDivisor=1;tickLabels=this.strings_msecs_;}else{unit='s';unitDivisor=1000;tickLabels=this.strings_secs_;}
+var numTicksPerMajor=5;var minorMarkDistanceWorld=majorMarkDistanceWorld/numTicksPerMajor;var minorMarkDistancePx=dt.xWorldVectorToView(minorMarkDistanceWorld);var firstMajorMark=Math.floor(viewLWorld/majorMarkDistanceWorld)*majorMarkDistanceWorld;var minorTickH=Math.floor(rulerHeight*0.25);ctx.save();var pixelRatio=window.devicePixelRatio||1;ctx.lineWidth=Math.round(pixelRatio);var crispLineCorrection=(ctx.lineWidth%2)/2;ctx.translate(crispLineCorrection,-crispLineCorrection);ctx.fillSt [...]
+tickLabels[roundedUnitValue]=roundedUnitValue+' '+unit;ctx.fillText(tickLabels[roundedUnitValue],curXView+(2*pixelRatio),0);vp.majorMarkPositions.push(curXView);tr.ui.b.drawLine(ctx,curXView,0,curXView,rulerHeight);for(var i=1;i<numTicksPerMajor;++i){var xView=Math.floor(curXView+minorMarkDistancePx*i);tr.ui.b.drawLine(ctx,xView,rulerHeight-minorTickH,xView,rulerHeight);}}
+ctx.strokeStyle='rgb(0, 0, 0)';tr.ui.b.drawLine(ctx,0,height,width,height);ctx.stroke();if(!hasInterestRange)
+return;tr.ui.b.drawLine(ctx,0,rulerHeight,width,rulerHeight);ctx.stroke();var displayDistance;var displayTextColor='rgb(0,0,0)';var arrowSpacing=10*pixelRatio;var arrowColor='rgb(128,121,121)';var arrowPosY=rulerHeight*1.75;var arrowWidthView=3*pixelRatio;var arrowLengthView=10*pixelRatio;var spaceForArrowsView=2*(arrowWidthView+arrowSpacing);ctx.textBaseline='middle';ctx.font=(14*pixelRatio)+'px sans-serif';var textPosY=arrowPosY;var interestRange=vp.interestRange;if(interestRange.range [...]
+textLeftView=markerView-4*pixelRatio-textWidthView;ctx.fillStyle=displayTextColor;ctx.fillText(textToDraw,textLeftView,textPosY);return;}
+var leftMarker=interestRange.min;var rightMarker=interestRange.max;var leftMarkerView=dt.xWorldToView(leftMarker);var rightMarkerView=dt.xWorldToView(rightMarker);var distanceBetweenMarkers=interestRange.range;var distanceBetweenMarkersView=dt.xWorldVectorToView(distanceBetweenMarkers);var positionInMiddleOfMarkersView=leftMarkerView+(distanceBetweenMarkersView/2);if(distanceBetweenMarkers<0.0001){unit='ns';unitDivisor=0.000001;}else if(distanceBetweenMarkers<0.1){unit='us';unitDivisor=0 [...]
+displayDistance=distanceBetweenMarkers/unitDivisor;var roundedDisplayDistance=Math.abs((Math.round(displayDistance*1000)/1000));var textToDraw=roundedDisplayDistance+' '+unit;var textWidthView=ctx.measureText(textToDraw).width;var spaceForArrowsAndTextView=textWidthView+spaceForArrowsView+arrowSpacing;var textLeftView=positionInMiddleOfMarkersView-textWidthView/2;var textRightView=textLeftView+textWidthView;if(spaceForArrowsAndTextView>distanceBetweenMarkersView){textLeftView=rightMarker [...]
+textLeftView=leftMarkerView-2*arrowSpacing-textWidthView;ctx.fillStyle=displayTextColor;ctx.fillText(textToDraw,textLeftView,textPosY);ctx.strokeStyle=arrowColor;ctx.beginPath();tr.ui.b.drawLine(ctx,leftMarkerView,arrowPosY,rightMarkerView,arrowPosY);ctx.stroke();ctx.fillStyle=arrowColor;tr.ui.b.drawArrow(ctx,leftMarkerView-1.5*arrowSpacing,arrowPosY,leftMarkerView,arrowPosY,arrowLengthView,arrowWidthView);tr.ui.b.drawArrow(ctx,rightMarkerView+1.5*arrowSpacing,arrowPosY,rightMarkerView,a [...]
+ctx.strokeStyle=arrowColor;ctx.fillStyle=arrowColor;tr.ui.b.drawArrow(ctx,leftArrowStart,arrowPosY,leftMarkerView,arrowPosY,arrowLengthView,arrowWidthView);tr.ui.b.drawArrow(ctx,rightArrowStart,arrowPosY,rightMarkerView,arrowPosY,arrowLengthView,arrowWidthView);}
+ctx.restore();},addIntersectingEventsInRangeToSelection:function(loVX,hiVX,loY,hiY,selection){},addAllEventsMatchingFilterToSelection:function(filter,selection){}};return{RulerTrack:RulerTrack};});'use strict';tr.exportTo('tr.model',function(){function Annotation(){this.guid_=tr.b.GUID.allocate();this.view_=undefined;};Annotation.fromDictIfPossible=function(args){if(args.typeName===undefined)
+throw new Error('Missing typeName argument');var typeInfo=Annotation.findTypeInfoMatching(function(typeInfo){return typeInfo.metadata.typeName===args.typeName;});if(typeInfo===undefined)
+return undefined;return typeInfo.constructor.fromDict(args);};Annotation.fromDict=function(){throw new Error('Not implemented');}
+Annotation.prototype={get guid(){return this.guid_;},onRemove:function(){},toDict:function(){throw new Error('Not implemented');},getOrCreateView:function(viewport){if(!this.view_)
+this.view_=this.createView_(viewport);return this.view_;},createView_:function(){throw new Error('Not implemented');}};var options=new tr.b.ExtensionRegistryOptions(tr.b.BASIC_REGISTRY_MODE);options.mandatoryBaseType=Annotation;tr.b.decorateExtensionRegistry(Annotation,options);Annotation.addEventListener('will-register',function(e){if(!e.typeInfo.constructor.hasOwnProperty('fromDict'))
+throw new Error('Must have fromDict method');if(!e.typeInfo.metadata.typeName)
+throw new Error('Registered Annotations must provide typeName');});return{Annotation:Annotation};});'use strict';tr.exportTo('tr.ui.annotations',function(){function AnnotationView(viewport,annotation){}
+AnnotationView.prototype={draw:function(ctx){throw new Error('Not implemented');}};return{AnnotationView:AnnotationView};});'use strict';tr.exportTo('tr.ui.annotations',function(){function XMarkerAnnotationView(viewport,annotation){this.viewport_=viewport;this.annotation_=annotation;}
+XMarkerAnnotationView.prototype={__proto__:tr.ui.annotations.AnnotationView.prototype,draw:function(ctx){var dt=this.viewport_.currentDisplayTransform;var viewX=dt.xWorldToView(this.annotation_.timestamp);ctx.beginPath();tr.ui.b.drawLine(ctx,viewX,0,viewX,ctx.canvas.height);ctx.strokeStyle=this.annotation_.strokeStyle;ctx.stroke();}};return{XMarkerAnnotationView:XMarkerAnnotationView};});'use strict';tr.exportTo('tr.model',function(){function XMarkerAnnotation(timestamp){tr.model.Annotat [...]
+XMarkerAnnotation.fromDict=function(dict){return new XMarkerAnnotation(dict.args.timestamp);}
+XMarkerAnnotation.prototype={__proto__:tr.model.Annotation.prototype,toDict:function(){return{typeName:'xmarker',args:{timestamp:this.timestamp}};},createView_:function(viewport){return new tr.ui.annotations.XMarkerAnnotationView(viewport,this);}};tr.model.Annotation.register(XMarkerAnnotation,{typeName:'xmarker'});return{XMarkerAnnotation:XMarkerAnnotation};});'use strict';tr.exportTo('tr.ui.b',function(){function KeyEventManager(opt_document){this.document_=opt_document||document;if(Ke [...]
+throw new Error('KeyEventManager is a singleton.');this.onEvent_=this.onEvent_.bind(this);this.document_.addEventListener('keydown',this.onEvent_);this.document_.addEventListener('keypress',this.onEvent_);this.document_.addEventListener('keyup',this.onEvent_);this.listeners_=[];}
+KeyEventManager.instance=undefined;document.head.addEventListener('tr-unittest-will-run',function(){if(KeyEventManager.instance){KeyEventManager.instance.destroy();KeyEventManager.instance=undefined;}
+KeyEventManager.instance=new KeyEventManager();});KeyEventManager.prototype={addListener:function(type,handler,thisArg){if(!thisArg.keyEventManagerGuid_){thisArg.keyEventManagerGuid_=tr.b.GUID.allocate();thisArg.keyEventManagerRefCount_=0;}
+thisArg.classList.add('key-event-manager-target');thisArg.keyEventManagerRefCount_++;var guid=thisArg.keyEventManagerGuid_;this.listeners_.push({guid:guid,type:type,handler:handler});},onEvent_:function(event){var preventDefaultState=undefined;var stopPropagationCalled=false;var oldPreventDefault=event.preventDefault;event.preventDefault=function(){preventDefaultState=false;oldPreventDefault.call(this);};var oldStopPropagation=event.stopPropagation;event.stopPropagation=function(){stopPr [...]
+var listeners=this.listeners_.concat();var type=event.type;var prevented=0;for(var i=0;i<listeners.length;i++){var listener=listeners[i];if(listener.type!==type)
+continue;var thisArg=possibleThisArgsByGUID[listener.guid];if(!thisArg)
+continue;var handler=listener.handler;if(handler.handleEvent)
+prevented|=handler.handleEvent.call(handler,event)===false;else
+prevented|=handler.call(thisArg,event)===false;if(stopPropagationCalled)
+break;}
+return!prevented&&preventDefaultState;},removeListener:function(type,handler,thisArg){if(thisArg.keyEventManagerGuid_===undefined)
+throw new Error('Was not registered with KeyEventManager');if(thisArg.keyEventManagerRefCount_===0)
+throw new Error('No events were registered on the provided thisArg');for(var i=0;i<this.listeners_.length;i++){var listener=this.listeners_[i];if(listener.type==type&&listener.handler==handler&&listener.guid==thisArg.keyEventManagerGuid_){thisArg.keyEventManagerRefCount_--;if(thisArg.keyEventManagerRefCount_===0)
+thisArg.classList.remove('key-event-manager-target');this.listeners_.splice(i,1);return;}}
+throw new Error('Listener not found');},destroy:function(){this.listeners_.splice(0);this.document_.removeEventListener('keydown',this.onEvent_);this.document_.removeEventListener('keypress',this.onEvent_);this.document_.removeEventListener('keyup',this.onEvent_);},dispatchFakeEvent:function(type,args){var e=new KeyboardEvent(type,args);return KeyEventManager.instance.onEvent_.call(undefined,e);}};KeyEventManager.instance=new KeyEventManager();return{KeyEventManager:KeyEventManager};});' [...]
+MouseTracker.prototype={get targetElement(){return this.targetElement_;},set targetElement(targetElement){if(this.targetElement_)
+this.targetElement_.removeEventListener('mousedown',this.onMouseDown_);this.targetElement_=targetElement;if(this.targetElement_)
+this.targetElement_.addEventListener('mousedown',this.onMouseDown_);},onMouseDown_:function(e){if(e.button!==0)
+return true;e=this.remakeEvent_(e,'mouse-tracker-start');this.targetElement_.dispatchEvent(e);document.addEventListener('mousemove',this.onMouseMove_);document.addEventListener('mouseup',this.onMouseUp_);this.targetElement_.addEventListener('blur',this.onMouseUp_);this.savePreviousUserSelect_=document.body.style['-webkit-user-select'];document.body.style['-webkit-user-select']='none';e.preventDefault();return true;},onMouseMove_:function(e){e=this.remakeEvent_(e,'mouse-tracker-move');thi [...]
+opt_mouseUpHandler(e);}
+document.addEventListener('mousemove',mouseMoveHandler);document.addEventListener('mouseup',cleanupAndDispatchToMouseUp);}
+return{MouseTracker:MouseTracker,trackMouseMovesUntilMouseUp:trackMouseMovesUntilMouseUp};});'use strict';tr.exportTo('tr.ui.b',function(){var THIS_DOC=document.currentScript.ownerDocument;var MIN_MOUSE_SELECTION_DISTANCE=4;var MOUSE_SELECTOR_MODE={};MOUSE_SELECTOR_MODE.SELECTION=0x1;MOUSE_SELECTOR_MODE.PANSCAN=0x2;MOUSE_SELECTOR_MODE.ZOOM=0x4;MOUSE_SELECTOR_MODE.TIMING=0x8;MOUSE_SELECTOR_MODE.ROTATE=0x10;MOUSE_SELECTOR_MODE.ALL_MODES=0x1F;var allModeInfo={};allModeInfo[MOUSE_SELECTOR_MO [...]
+this.targetElement_.removeEventListener('mousedown',this.onMouseDown_);this.targetElement_=target;if(this.targetElement_)
+this.targetElement_.addEventListener('mousedown',this.onMouseDown_);},get defaultMode(){return this.defaultMode_;},set defaultMode(defaultMode){this.defaultMode_=defaultMode;},get settingsKey(){return this.settingsKey_;},set settingsKey(settingsKey){this.settingsKey_=settingsKey;if(!this.settingsKey_)
+return;var mode=tr.b.Settings.get(this.settingsKey_+'.mode',undefined);if(allModeInfo[mode]===undefined)
+mode=undefined;if((mode&this.supportedModeMask_)===0)
+mode=undefined;if(!mode)
+mode=this.defaultMode_;this.mode=mode;var pos=tr.b.Settings.get(this.settingsKey_+'.pos',undefined);if(pos)
+this.pos=pos;},get supportedModeMask(){return this.supportedModeMask_;},set supportedModeMask(supportedModeMask){if(this.mode&&(supportedModeMask&this.mode)===0)
+throw new Error('supportedModeMask must include current mode.');function createButtonForMode(mode){var button=document.createElement('div');button.mode=mode;button.title=allModeInfo[mode].title;button.classList.add('tool-button');button.classList.add(allModeInfo[mode].className);return button;}
+this.supportedModeMask_=supportedModeMask;this.buttonsEl_.textContent='';for(var modeName in MOUSE_SELECTOR_MODE){if(modeName=='ALL_MODES')
+continue;var mode=MOUSE_SELECTOR_MODE[modeName];if((this.supportedModeMask_&mode)===0)
+continue;this.buttonsEl_.appendChild(createButtonForMode(mode));}},get mode(){return this.currentMode_;},set mode(newMode){if(newMode!==undefined){if(typeof newMode!=='number')
+throw new Error('Mode must be a number');if((newMode&this.supportedModeMask_)===0)
+throw new Error('Cannot switch to this mode, it is not supported');if(allModeInfo[newMode]===undefined)
+throw new Error('Unrecognized mode');}
+var modeInfo;if(this.currentMode_===newMode)
+return;if(this.currentMode_){modeInfo=allModeInfo[this.currentMode_];var buttonEl=this.buttonsEl_.querySelector('.'+modeInfo.className);if(buttonEl)
+buttonEl.classList.remove('active');if(this.isInteracting_){var mouseEvent=this.createEvent_(allModeInfo[this.mode].eventNames.end);this.dispatchEvent(mouseEvent);}
+tr.b.dispatchSimpleEvent(this,modeInfo.eventNames.exit,true);}
+this.currentMode_=newMode;if(this.currentMode_){modeInfo=allModeInfo[this.currentMode_];var buttonEl=this.buttonsEl_.querySelector('.'+modeInfo.className);if(buttonEl)
+buttonEl.classList.add('active');this.mouseDownPos_.x=this.mousePos_.x;this.mouseDownPos_.y=this.mousePos_.y;if(!this.isInAlternativeMode_)
+tr.b.dispatchSimpleEvent(this,modeInfo.eventNames.enter,true);if(this.isInteracting_){var mouseEvent=this.createEvent_(allModeInfo[this.mode].eventNames.begin);this.dispatchEvent(mouseEvent);}}
+if(this.settingsKey_&&!this.isInAlternativeMode_)
+tr.b.Settings.set(this.settingsKey_+'.mode',this.mode);},setKeyCodeForMode:function(mode,keyCode){if((mode&this.supportedModeMask_)===0)
+throw new Error('Mode not supported');this.modeToKeyCodeMap_[mode]=keyCode;if(!this.buttonsEl_)
+return;var modeInfo=allModeInfo[mode];var buttonEl=this.buttonsEl_.querySelector('.'+modeInfo.className);if(buttonEl){buttonEl.title=modeInfo.title+' ('+String.fromCharCode(keyCode)+')';}},setKeyCodeCondition:function(callback){this.keyCodeCondition=callback;},setCurrentMousePosFromEvent_:function(e){this.mousePos_.x=e.clientX;this.mousePos_.y=e.clientY;},createEvent_:function(eventName,sourceEvent){var event=new tr.b.Event(eventName,true);event.clientX=this.mousePos_.x;event.clientY=thi [...]
+sourceEvent.preventDefault();};event.stopPropagation=function(){sourceEvent.stopPropagation();};event.stopImmediatePropagation=function(){throw new Error('Not implemented');};return event;},onMouseDown_:function(e){if(e.button!==0)
+return;this.setCurrentMousePosFromEvent_(e);var mouseEvent=this.createEvent_(allModeInfo[this.mode].eventNames.begin,e);this.dispatchEvent(mouseEvent);this.isInteracting_=true;this.isClick_=true;tr.ui.b.trackMouseMovesUntilMouseUp(this.onMouseMove_,this.onMouseUp_);},onMouseMove_:function(e){this.setCurrentMousePosFromEvent_(e);var mouseEvent=this.createEvent_(allModeInfo[this.mode].eventNames.update,e);this.dispatchEvent(mouseEvent);if(this.isInteracting_)
+this.checkIsClick_(e);},onMouseUp_:function(e){if(e.button!==0)
+return;var mouseEvent=this.createEvent_(allModeInfo[this.mode].eventNames.end,e);mouseEvent.isClick=this.isClick_;this.dispatchEvent(mouseEvent);if(this.isClick_&&!mouseEvent.didPreventDefault)
+this.dispatchClickEvents_(e);this.isInteracting_=false;this.updateAlternativeModeState_(e);},onButtonMouseDown_:function(e){e.preventDefault();e.stopImmediatePropagation();},onButtonMouseUp_:function(e){e.preventDefault();e.stopImmediatePropagation();},onButtonPress_:function(e){this.modeBeforeAlternativeModeActivated_=undefined;this.mode=e.target.mode;e.preventDefault();},onKeyDown_:function(e){if(e.keyCode===' '.charCodeAt(0))
+this.spacePressed_=true;this.updateAlternativeModeState_(e);},onKeyUp_:function(e){if(e.keyCode===' '.charCodeAt(0))
+this.spacePressed_=false;if(this.keyCodeCondition!=undefined&&!this.keyCodeCondition()){return;}
+var didHandleKey=false;tr.b.iterItems(this.modeToKeyCodeMap_,function(modeStr,keyCode){if(e.keyCode===keyCode){this.modeBeforeAlternativeModeActivated_=undefined;var mode=parseInt(modeStr);this.mode=mode;didHandleKey=true;}},this);if(didHandleKey){e.preventDefault();e.stopPropagation();return;}
+this.updateAlternativeModeState_(e);},updateAlternativeModeState_:function(e){var shiftPressed=e.shiftKey;var spacePressed=this.spacePressed_;var cmdOrCtrlPressed=(tr.isMac&&e.metaKey)||(!tr.isMac&&e.ctrlKey);var smm=this.supportedModeMask_;var newMode;var isNewModeAnAlternativeMode=false;if(shiftPressed&&(this.modifierToModeMap_[MODIFIER.SHIFT]&smm)!==0){newMode=this.modifierToModeMap_[MODIFIER.SHIFT];isNewModeAnAlternativeMode=true;}else if(spacePressed&&(this.modifierToModeMap_[MODIFI [...]
+if(this.mode===newMode||newMode===undefined)
+return;if(isNewModeAnAlternativeMode)
+this.modeBeforeAlternativeModeActivated_=this.mode;this.mode=newMode;},get isInAlternativeMode_(){return!!this.modeBeforeAlternativeModeActivated_;},setModifierForAlternateMode:function(mode,modifier){this.modifierToModeMap_[modifier]=mode;},get pos(){return{x:parseInt(this.style.left),y:parseInt(this.style.top)};},set pos(pos){pos=this.constrainPositionToBounds_(pos);this.style.left=pos.x+'px';this.style.top=pos.y+'px';if(this.settingsKey_)
+tr.b.Settings.set(this.settingsKey_+'.pos',this.pos);},constrainPositionToBounds_:function(pos){var parent=this.offsetParent||document.body;var parentRect=tr.ui.b.windowRectForElement(parent);var top=0;var bottom=parentRect.height-this.offsetHeight;var left=0;var right=parentRect.width-this.offsetWidth;var res={};res.x=Math.max(pos.x,left);res.x=Math.min(res.x,right);res.y=Math.max(pos.y,top);res.y=Math.min(res.y,bottom);return res;},onDragHandleMouseDown_:function(e){e.preventDefault(); [...]
+return;var deltaX=this.mousePos_.x-this.mouseDownPos_.x;var deltaY=this.mousePos_.y-this.mouseDownPos_.y;var minDist=MIN_MOUSE_SELECTION_DISTANCE;if(deltaX*deltaX+deltaY*deltaY>minDist*minDist)
+this.isClick_=false;},dispatchClickEvents_:function(e){if(!this.isClick_)
+return;var eventNames=allModeInfo[MOUSE_SELECTOR_MODE.SELECTION].eventNames;var mouseEvent=this.createEvent_(eventNames.begin);this.dispatchEvent(mouseEvent);mouseEvent=this.createEvent_(eventNames.end);this.dispatchEvent(mouseEvent);}};return{MIN_MOUSE_SELECTION_DISTANCE:MIN_MOUSE_SELECTION_DISTANCE,MouseModeSelector:MouseModeSelector,MOUSE_SELECTOR_MODE:MOUSE_SELECTOR_MODE,MODIFIER:MODIFIER};});'use strict';tr.exportTo('tr.ui',function(){var Selection=tr.c.Selection;var SelectionState= [...]
+results.left=Math.max(r1.left,r2.left);results.top=Math.max(r1.top,r2.top);results.right=Math.min(r1.right,r2.right);results.bottom=Math.min(r1.bottom,r2.bottom);results.width=(results.right-results.left);results.height=(results.bottom-results.top);return results;}
+var TimelineTrackView=tr.ui.b.define('div');TimelineTrackView.prototype={__proto__:HTMLDivElement.prototype,model_:null,decorate:function(timelineView){this.classList.add('timeline-track-view');this.timelineView_=timelineView;this.viewport_=new Viewport(this);this.viewportDisplayTransformAtMouseDown_=null;this.selectionController_=undefined;this.rulerTrackContainer_=new tr.ui.tracks.DrawingContainer(this.viewport_);this.appendChild(this.rulerTrackContainer_);this.rulerTrackContainer_.inv [...]
+this.boundListeners_=[];var boundFunc=func.bind(target);this.boundListeners_.push({object:object,event:event,boundFunc:boundFunc});object.addEventListener(event,boundFunc);},initMouseModeSelector:function(){this.mouseModeSelector_=new tr.ui.b.MouseModeSelector(this);this.appendChild(this.mouseModeSelector_);this.mouseModeSelector_.addEventListener('beginpan',this.onBeginPanScan_.bind(this));this.mouseModeSelector_.addEventListener('updatepan',this.onUpdatePanScan_.bind(this));this.mouseM [...]
+this.selectionController_=selectionController;if(this.selectionController_){this.selectionController_.addEventListener('change',this.onSelectionChanged_);}},onSelectionChanged_:function(){this.showHintText_('Press \'m\' to mark current selection');this.viewport_.dispatchChangeEvent();},set selection(selection){throw new Error('DO NOT CALL THIS');},set highlight(highlight){throw new Error('DO NOT CALL THIS');},detach:function(){this.modelTrack_.detach();this.upperModelTrack_.detach();for( [...]
+this.boundListeners_=undefined;this.viewport_.detach();},get viewport(){return this.viewport_;},get model(){return this.model_;},set model(model){if(!model)
+throw new Error('Model cannot be null');var modelInstanceChanged=this.model_!==model;this.model_=model;this.modelTrack_.model=model;this.upperModelTrack_.model=model;if(modelInstanceChanged)
+this.viewport_.setWhenPossible(this.setInitialViewport_.bind(this));tr.b.setPropertyAndDispatchChange(this,'model',model);},get hasVisibleContent(){return this.modelTrack_.hasVisibleContent||this.upperModelTrack_.hasVisibleContent;},setInitialViewport_:function(){this.modelTrackContainer_.updateCanvasSizeIfNeeded_();var w=this.modelTrackContainer_.canvas.width;var min;var range;if(this.model_.bounds.isEmpty){min=0;range=1000;}else if(this.model_.bounds.range===0){min=this.model_.bounds.m [...]
+var boost=range*0.15;tempDisplayTransform.set(this.viewport_.currentDisplayTransform);tempDisplayTransform.xSetWorldBounds(min-boost,min+range+boost,w);this.viewport_.setDisplayTransformImmediately(tempDisplayTransform);},addAllEventsMatchingFilterToSelectionAsTask:function(filter,selection){var modelTrack=this.modelTrack_;var firstT=modelTrack.addAllEventsMatchingFilterToSelectionAsTask(filter,selection);var lastT=firstT.after(function(){this.upperModelTrack_.addAllEventsMatchingFilterT [...]
+return this.focusElement_;return this.parentElement;},set focusElement(value){this.focusElement_=value;},get listenToKeys_(){if(!this.viewport_.isAttachedToDocumentOrInTestMode)
+return false;if(document.activeElement instanceof TracingFindControl)
+return false;if(document.activeElement instanceof TracingScriptingControl)
+return false;if(!this.focusElement_)
+return true;if(this.focusElement.tabIndex>=0){if(document.activeElement==this.focusElement)
+return true;return tr.ui.b.elementIsChildOf(document.activeElement,this.focusElement);}
+return true;},onMouseMove_:function(e){if(this.isZooming_)
+return;this.storeLastMousePos_(e);},onTouchStart_:function(e){this.storeLastTouchPositions_(e);this.focusElements_();},onTouchMove_:function(e){e.preventDefault();this.onUpdateTransformForTouch_(e);},onTouchEnd_:function(e){this.storeLastTouchPositions_(e);this.focusElements_();},onKeypress_:function(e){var vp=this.viewport_;if(!this.listenToKeys_)
+return;if(document.activeElement.nodeName=='INPUT')
+return;var viewWidth=this.modelTrackContainer_.canvas.clientWidth;var curMouseV,curCenterW;switch(e.keyCode){case 119:case 44:this.zoomBy_(1.5,true);break;case 115:case 111:this.zoomBy_(1/1.5,true);break;case 103:this.onGridToggle_(true);break;case 71:this.onGridToggle_(false);break;case 87:case 60:this.zoomBy_(10,true);break;case 83:case 79:this.zoomBy_(1/10,true);break;case 97:this.queueSmoothPan_(viewWidth*0.3,0);break;case 100:case 101:this.queueSmoothPan_(viewWidth*-0.3,0);break;cas [...]
+return;var sel;var vp=this.viewport_;var viewWidth=this.modelTrackContainer_.canvas.clientWidth;switch(e.keyCode){case 37:sel=this.selectionController_.selection.getShiftedSelection(this.viewport,-1);if(sel){this.selectionController.changeSelectionFromTimeline(sel);this.panToSelection();e.preventDefault();}else{this.queueSmoothPan_(viewWidth*0.3,0);}
+break;case 39:sel=this.selectionController_.selection.getShiftedSelection(this.viewport,1);if(sel){this.selectionController.changeSelectionFromTimeline(sel);this.panToSelection();e.preventDefault();}else{this.queueSmoothPan_(-viewWidth*0.3,0);}
+break;case 9:if(this.focusElement.tabIndex==-1){if(e.shiftKey)
+this.selectPrevious_(e);else
+this.selectNext_(e);e.preventDefault();}
+break;}},onKeyup_:function(e){if(!this.listenToKeys_)
+return;if(!e.shiftKey){if(this.dragBeginEvent_){this.setDragBoxPosition_(this.dragBoxXStart_,this.dragBoxYStart_,this.dragBoxXEnd_,this.dragBoxYEnd_);}}},onDblClick_:function(e){if(this.mouseModeSelector_.mode!==tr.ui.b.MOUSE_SELECTOR_MODE.SELECTION)
+return;var curSelection=this.selectionController_.selection;if(!curSelection.length||!curSelection[0].title)
+return;var selection=new Selection();var filter=new tr.c.ExactTitleFilter(curSelection[0].title);this.modelTrack_.addAllEventsMatchingFilterToSelection(filter,selection);this.selectionController.changeSelectionFromTimeline(selection);},onMouseWheel_:function(e){if(!e.altKey)
+return;var delta=e.wheelDelta/120;var zoomScale=Math.pow(1.5,delta);this.zoomBy_(zoomScale);e.preventDefault();},onMouseDown_:function(e){if(this.mouseModeSelector_.mode!==tr.ui.b.MOUSE_SELECTOR_MODE.SELECTION)
+return;if(e.target!==this.rulerTrack_)
+return;this.dragBeginEvent_=undefined;if(this.xNavStringMarker_){this.model.removeAnnotation(this.xNavStringMarker_);this.xNavStringMarker_=undefined;}
+var dt=this.viewport_.currentDisplayTransform;tr.ui.b.trackMouseMovesUntilMouseUp(function(e){if(e.target===this.rulerTrack_)
+return;var relativePosition=this.extractRelativeMousePosition_(e);var loc=tr.ui.b.Location.fromViewCoordinates(this.viewport_,relativePosition.x,relativePosition.y);if(!loc)
+return;if(this.guideLineAnnotation_===undefined){this.guideLineAnnotation_=new tr.model.XMarkerAnnotation(loc.xWorld);this.model.addAnnotation(this.guideLineAnnotation_);}else{this.guideLineAnnotation_.timestamp=loc.xWorld;this.modelTrackContainer_.invalidate();}
+var state=new tr.ui.b.UIState(loc,this.viewport_.currentDisplayTransform.scaleX);this.timelineView_.setFindCtlText(state.toUserFriendlyString(this.viewport_));}.bind(this));},queueSmoothPan_:function(viewDeltaX,deltaY){var deltaX=this.viewport_.currentDisplayTransform.xViewVectorToWorld(viewDeltaX);var animation=new tr.ui.TimelineDisplayTransformPanAnimation(deltaX,deltaY);this.viewport_.queueDisplayTransformAnimation(animation);},zoomBy_:function(scale,smooth){if(scale<=0){return;}
+smooth=!!smooth;var vp=this.viewport_;var viewWidth=this.modelTrackContainer_.canvas.clientWidth;var pixelRatio=window.devicePixelRatio||1;var goalFocalPointXView=this.lastMouseViewPos_.x*pixelRatio;var goalFocalPointXWorld=vp.currentDisplayTransform.xViewToWorld(goalFocalPointXView);if(smooth){var animation=new tr.ui.TimelineDisplayTransformZoomToAnimation(goalFocalPointXWorld,goalFocalPointXView,vp.currentDisplayTransform.panY,scale);vp.queueDisplayTransformAnimation(animation);}else{t [...]
+return;var bounds=this.selectionController.selectionOfInterest.bounds;if(!bounds.range)
+return;var worldCenter=bounds.center;var viewCenter=this.modelTrackContainer_.canvas.width/2;var adjustedWorldRange=bounds.range*1.25;var newScale=this.modelTrackContainer_.canvas.width/adjustedWorldRange;var zoomInRatio=newScale/this.viewport_.currentDisplayTransform.scaleX;var animation=new tr.ui.TimelineDisplayTransformZoomToAnimation(worldCenter,viewCenter,this.viewport_.currentDisplayTransform.panY,zoomInRatio);this.viewport_.queueDisplayTransformAnimation(animation);},panToSelectio [...]
+return;var bounds=this.selectionController.selectionOfInterest.bounds;var worldCenter=bounds.center;var viewWidth=this.modelTrackContainer_.canvas.width;var dt=this.viewport_.currentDisplayTransform;if(false&&!bounds.range){if(dt.xWorldToView(bounds.center)<0||dt.xWorldToView(bounds.center)>viewWidth){tempDisplayTransform.set(dt);tempDisplayTransform.xPanWorldPosToViewPos(worldCenter,'center',viewWidth);var deltaX=tempDisplayTransform.panX-dt.panX;var animation=new tr.ui.TimelineDisplayT [...]
+return;}
+tempDisplayTransform.set(dt);tempDisplayTransform.xPanWorldBoundsIntoView(bounds.min,bounds.max,viewWidth);var deltaX=tempDisplayTransform.panX-dt.panX;var animation=new tr.ui.TimelineDisplayTransformPanAnimation(deltaX,0);this.viewport_.queueDisplayTransformAnimation(animation);},navToPosition:function(uiState,showNavLine){var location=uiState.location;var scaleX=uiState.scaleX;var track=location.getContainingTrack(this.viewport_);var worldCenter=location.xWorld;var viewCenter=this.mode [...]
+return;if(this.xNavStringMarker_)
+this.model.removeAnnotation(this.xNavStringMarker_);this.xNavStringMarker_=new tr.model.XMarkerAnnotation(worldCenter);this.model.addAnnotation(this.xNavStringMarker_);},setCurrentSelectionAsInterestRange_:function(){var selectionBounds=this.selectionController_.selection.bounds;if(selectionBounds.empty){this.viewport_.interestRange.reset();return;}
+if(this.viewport_.interestRange.min==selectionBounds.min&&this.viewport_.interestRange.max==selectionBounds.max)
+this.viewport_.interestRange.reset();else
+this.viewport_.interestRange.set(selectionBounds);},toggleHighDetails_:function(){this.viewport_.highDetails=!this.viewport_.highDetails;},hideDragBox_:function(){this.dragBox_.style.left='-1000px';this.dragBox_.style.top='-1000px';this.dragBox_.style.width=0;this.dragBox_.style.height=0;},setDragBoxPosition_:function(xStart,yStart,xEnd,yEnd){var loY=Math.min(yStart,yEnd);var hiY=Math.max(yStart,yEnd);var loX=Math.min(xStart,xEnd);var hiX=Math.max(xStart,xEnd);var modelTrackRect=this.mod [...]
+var numIntervalsSinceStart=Math.ceil((tb-this.model_.bounds.min)/this.viewport_.gridStep_);this.viewport_.gridEnabled=true;this.viewport_.gridSide=left;this.viewport_.gridInitialTimebase=tb;this.viewport_.gridTimebase=tb-
+(numIntervalsSinceStart+1)*this.viewport_.gridStep_;},storeLastMousePos_:function(e){this.lastMouseViewPos_=this.extractRelativeMousePosition_(e);},storeLastTouchPositions_:function(e){this.lastTouchViewPositions_=this.extractRelativeTouchPositions_(e);},extractRelativeMousePosition_:function(e){var canv=this.modelTrackContainer_.canvas;return{x:e.clientX-canv.offsetLeft,y:e.clientY-canv.offsetTop};},extractRelativeTouchPositions_:function(e){var canv=this.modelTrackContainer_.canvas;var [...]
+return touches;},storeInitialMouseDownPos_:function(e){var position=this.extractRelativeMousePosition_(e);this.mouseViewPosAtMouseDown_.x=position.x;this.mouseViewPosAtMouseDown_.y=position.y;},focusElements_:function(){if(document.activeElement)
+document.activeElement.blur();if(this.focusElement.tabIndex>=0)
+this.focusElement.focus();},storeInitialInteractionPositionsAndFocus_:function(e){this.storeInitialMouseDownPos_(e);this.storeLastMousePos_(e);this.focusElements_();},onBeginPanScan_:function(e){var vp=this.viewport_;this.viewportDisplayTransformAtMouseDown_=vp.currentDisplayTransform.clone();this.isPanningAndScanning_=true;this.storeInitialInteractionPositionsAndFocus_(e);e.preventDefault();},onUpdatePanScan_:function(e){if(!this.isPanningAndScanning_)
+return;var viewWidth=this.modelTrackContainer_.canvas.clientWidth;var pixelRatio=window.devicePixelRatio||1;var xDeltaView=pixelRatio*(this.lastMouseViewPos_.x-
+this.mouseViewPosAtMouseDown_.x);var yDelta=this.lastMouseViewPos_.y-
+this.mouseViewPosAtMouseDown_.y;tempDisplayTransform.set(this.viewportDisplayTransformAtMouseDown_);tempDisplayTransform.incrementPanXInViewUnits(xDeltaView);tempDisplayTransform.panY-=yDelta;this.viewport_.setDisplayTransformImmediately(tempDisplayTransform);e.preventDefault();e.stopPropagation();this.storeLastMousePos_(e);},onEndPanScan_:function(e){this.isPanningAndScanning_=false;this.storeLastMousePos_(e);if(!e.isClick)
+e.preventDefault();},onBeginSelection_:function(e){var canv=this.modelTrackContainer_.canvas;var rect=this.modelTrack_.getBoundingClientRect();var canvRect=canv.getBoundingClientRect();var inside=rect&&e.clientX>=rect.left&&e.clientX<rect.right&&e.clientY>=rect.top&&e.clientY<rect.bottom&&e.clientX>=canvRect.left&&e.clientX<canvRect.right;if(!inside)
+return;this.dragBeginEvent_=e;this.storeInitialInteractionPositionsAndFocus_(e);e.preventDefault();},onUpdateSelection_:function(e){if(!this.dragBeginEvent_)
+return;this.dragBoxXStart_=this.dragBeginEvent_.clientX;this.dragBoxXEnd_=e.clientX;this.dragBoxYStart_=this.dragBeginEvent_.clientY;this.dragBoxYEnd_=e.clientY;this.setDragBoxPosition_(this.dragBoxXStart_,this.dragBoxYStart_,this.dragBoxXEnd_,this.dragBoxYEnd_);},onEndSelection_:function(e){e.preventDefault();if(!this.dragBeginEvent_)
+return;this.hideDragBox_();var eDown=this.dragBeginEvent_;this.dragBeginEvent_=null;var loY=Math.min(eDown.clientY,e.clientY);var hiY=Math.max(eDown.clientY,e.clientY);var loX=Math.min(eDown.clientX,e.clientX);var hiX=Math.max(eDown.clientX,e.clientX);var canv=this.modelTrackContainer_.canvas;var worldOffset=canv.getBoundingClientRect().left;var loVX=loX-worldOffset;var hiVX=hiX-worldOffset;var selection=new Selection();this.modelTrack_.addIntersectingEventsInRangeToSelection(loVX,hiVX,l [...]
+return;var newPosition=this.extractRelativeMousePosition_(e);var zoomScaleValue=1+(this.lastMouseViewPos_.y-
+newPosition.y)*0.01;this.zoomBy_(zoomScaleValue,false);this.storeLastMousePos_(e);},onEndZoom_:function(e){this.isZooming_=false;if(!e.isClick)
+e.preventDefault();},computeTouchCenter_:function(positions){var xSum=0;var ySum=0;for(var i=0;i<positions.length;++i){xSum+=positions[i].x;ySum+=positions[i].y;}
+return{x:xSum/positions.length,y:ySum/positions.length};},computeTouchSpan_:function(positions){var xMin=Number.MAX_VALUE;var yMin=Number.MAX_VALUE;var xMax=Number.MIN_VALUE;var yMax=Number.MIN_VALUE;for(var i=0;i<positions.length;++i){xMin=Math.min(xMin,positions[i].x);yMin=Math.min(yMin,positions[i].y);xMax=Math.max(xMax,positions[i].x);yMax=Math.max(yMax,positions[i].y);}
+return Math.sqrt((xMin-xMax)*(xMin-xMax)+
+(yMin-yMax)*(yMin-yMax));},onUpdateTransformForTouch_:function(e){var newPositions=this.extractRelativeTouchPositions_(e);var currentPositions=this.lastTouchViewPositions_;var newCenter=this.computeTouchCenter_(newPositions);var currentCenter=this.computeTouchCenter_(currentPositions);var newSpan=this.computeTouchSpan_(newPositions);var currentSpan=this.computeTouchSpan_(currentPositions);var vp=this.viewport_;var viewWidth=this.modelTrackContainer_.canvas.clientWidth;var pixelRatio=wind [...]
+this.pendingHintTextClearTimeout_=setTimeout(this.hideHintText_.bind(this),1000);this.hintTextBox_.textContent=text;this.hintTextBox_.style.display='';},hideHintText_:function(){this.pendingHintTextClearTimeout_=undefined;this.hintTextBox_.style.display='none';}};return{TimelineTrackView:TimelineTrackView};});'use strict';Polymer('tr-ui-find-control',{filterKeyDown:function(e){if(e.keyCode===27)
+return;e.stopPropagation();if(e.keyCode!==13)return;e.shiftKey?this.findPrevious():this.findNext();},filterKeyPress:function(e){if(e.keyCode===27)
+return;e.stopPropagation();},filterBlur:function(e){this.updateHitCountEl();},filterFocus:function(e){this.$.filter.select();},filterMouseUp:function(e){e.preventDefault();},get controller(){return this.controller_;},set controller(c){this.controller_=c;this.updateHitCountEl();},focus:function(){this.$.filter.focus();},get hasFocus(){return this===document.activeElement;},filterTextChanged:function(){this.$.hitCount.textContent='';this.$.spinner.style.visibility='visible';this.controller [...]
+this.controller.findNext();this.updateHitCountEl();},findPrevious:function(){if(this.controller)
+this.controller.findPrevious();this.updateHitCountEl();},updateHitCountEl:function(){if(!this.controller||!this.hasFocus){this.$.hitCount.textContent='';return;}
+var n=this.controller.filterHits.length;var i=n===0?-1:this.controller.currentHitIndex;this.$.hitCount.textContent=(i+1)+' of '+n;},setText:function(string){this.$.filter.value=string;}});'use strict';tr.exportTo('tr.ui.b',function(){var Selection=tr.c.Selection;var SelectionState=tr.model.SelectionState;function BrushingState(){this.guid_=tr.b.GUID.allocate();this.selection_=new Selection();this.findMatches_=new Selection();this.analysisViewRelatedEvents_=new Selection();this.appliedToM [...]
+BrushingState.prototype={get guid(){return this.guid_;},clone:function(){var that=new BrushingState();that.selection_=this.selection_;that.findMatches_=this.findMatches_;that.analysisViewRelatedEvents_=this.analysisViewRelatedEvents_;return that;},equals:function(that){if(!this.selection_.equals(that.selection_))
+return false;if(!this.findMatches_.equals(that.findMatches_))
+return false;if(!this.analysisViewRelatedEvents_.equals(that.analysisViewRelatedEvents_)){return false;}
+return true;},get selectionOfInterest(){if(this.selection_.length)
+return this.selection_;if(this.highlight_.length)
+return this.highlight_;if(this.analysisViewRelatedEvents_.length)
+return this.analysisViewRelatedEvents_;return this.selection_;},get selection(){return this.selection_;},set selection(selection){if(this.appliedToModel_)
+throw new Error('Cannot mutate this state right now');if(selection===undefined)
+selection=new Selection();this.selection_=selection;},get findMatches(){return this.findMatches_;},set findMatches(findMatches){if(this.appliedToModel_)
+throw new Error('Cannot mutate this state right now');if(findMatches===undefined)
+findMatches=new Selection();this.findMatches_=findMatches;},get analysisViewRelatedEvents(){return this.analysisViewRelatedEvents_;},set analysisViewRelatedEvents(analysisViewRelatedEvents){if(this.appliedToModel_)
+throw new Error('Cannot mutate this state right now');if(analysisViewRelatedEvents===undefined)
+analysisViewRelatedEvents=new Selection();this.analysisViewRelatedEvents_=analysisViewRelatedEvents;},get isAppliedToModel(){return this.appliedToModel_!==undefined;},get hasHighlight_(){return this.findMatches_.length>0||this.analysisViewRelatedEvents_.length>0;},applyToModelSelectionState:function(model){this.appliedToModel_=model;if(!this.hasHighlight_){this.selection_.forEach(function(e){e.selectionState=SelectionState.SELECTED;});return;}
+model.iterateAllEvents(function(e){var selectionState;if(this.selection_.contains(e)){selectionState=SelectionState.SELECTED;}else if(this.findMatches_.contains(e)){selectionState=SelectionState.HIGHLIGHTED;}else if(this.analysisViewRelatedEvents_.contains(e)){selectionState=SelectionState.HIGHLIGHTED;}else{selectionState=SelectionState.DIMMED;}
+e.selectionState=selectionState;}.bind(this));},transferModelOwnershipToClone:function(that){if(!this.appliedToModel_)
+throw new Error('Not applied');that.appliedToModel_=this.appliedToModel_;this.appliedToModel_=undefined;},unapplyFromModelSelectionState:function(){if(!this.appliedToModel_)
+throw new Error('Not applied');var model=this.appliedToModel_;this.appliedToModel_=undefined;if(!this.hasHighlight_){this.selection_.forEach(function(e){e.selectionState=SelectionState.NONE;});return;}
+model.iterateAllEvents(function(e){e.selectionState=SelectionState.NONE;});}};return{BrushingState:BrushingState};});'use strict';tr.exportTo('tr.ui.b',function(){function YComponent(stableId,yPercentOffset){this.stableId=stableId;this.yPercentOffset=yPercentOffset;}
+YComponent.prototype={toDict:function(){return{stableId:this.stableId,yPercentOffset:this.yPercentOffset};}};function Location(xWorld,yComponents){this.xWorld_=xWorld;this.yComponents_=yComponents;};Location.fromViewCoordinates=function(viewport,viewX,viewY){var dt=viewport.currentDisplayTransform;var xWorld=dt.xViewToWorld(viewX);var yComponents=[];var elem=document.elementFromPoint(viewX+viewport.modelTrackContainer.canvas.offsetLeft,viewY+viewport.modelTrackContainer.canvas.offsetTop) [...]
+elem=elem.parentElement;}
+if(yComponents.length==0)
+return;return new Location(xWorld,yComponents);}
+Location.fromStableIdAndTimestamp=function(viewport,stableId,ts){var xWorld=ts;var yComponents=[];var containerToTrack=viewport.containerToTrackMap;var elem=containerToTrack.getTrackByStableId(stableId);if(!elem)
+return;var firstY=elem.getBoundingClientRect().top;while(elem instanceof tr.ui.tracks.Track){if(elem.eventContainer){var boundRect=elem.getBoundingClientRect();var yPercentOffset=(firstY-boundRect.top)/boundRect.height;yComponents.push(new YComponent(elem.eventContainer.stableId,yPercentOffset));}
+elem=elem.parentElement;}
+if(yComponents.length==0)
+return;return new Location(xWorld,yComponents);}
+Location.prototype={get xWorld(){return this.xWorld_;},getContainingTrack:function(viewport){var containerToTrack=viewport.containerToTrackMap;for(var i in this.yComponents_){var yComponent=this.yComponents_[i];var track=containerToTrack.getTrackByStableId(yComponent.stableId);if(track!==undefined)
+return track;}},toViewCoordinates:function(viewport){var dt=viewport.currentDisplayTransform;var containerToTrack=viewport.containerToTrackMap;var viewX=dt.xWorldToView(this.xWorld_);var viewY=-1;for(var index in this.yComponents_){var yComponent=this.yComponents_[index];var track=containerToTrack.getTrackByStableId(yComponent.stableId);if(track!==undefined){var boundRect=track.getBoundingClientRect();viewY=yComponent.yPercentOffset*boundRect.height+boundRect.top;break;}}
+return{viewX:viewX,viewY:viewY};},toDict:function(){return{xWorld:this.xWorld_,yComponents:this.yComponents_};}};return{Location:Location};});'use strict';tr.exportTo('tr.ui.b',function(){var Location=tr.ui.b.Location;function UIState(location,scaleX){this.location_=location;this.scaleX_=scaleX;};UIState.fromUserFriendlyString=function(model,viewport,stateString){var navByFinderPattern=/^(-?\d+(\.\d+)?)@(.+)x(\d+(\.\d+)?)$/g;var match=navByFinderPattern.exec(stateString);if(!match)
+return;var timestamp=parseFloat(match[1]);var stableId=match[3];var scaleX=parseFloat(match[4]);if(scaleX<=0)
+throw new Error('Invalid ScaleX value in UI State string.');if(!viewport.containerToTrackMap.getTrackByStableId(stableId))
+throw new Error('Invalid StableID given in UI State String.');var loc=tr.ui.b.Location.fromStableIdAndTimestamp(viewport,stableId,timestamp);return new UIState(loc,scaleX);}
+UIState.prototype={get location(){return this.location_;},get scaleX(){return this.scaleX_;},toUserFriendlyString:function(viewport){var timestamp=this.location_.xWorld;var stableId=this.location_.getContainingTrack(viewport).eventContainer.stableId;var scaleX=this.scaleX_;return timestamp.toFixed(5)+'@'+stableId+'x'+scaleX.toFixed(5);},toDict:function(){return{location:this.location_.toDict(),scaleX:this.scaleX_};}};return{UIState:UIState};});'use strict';tr.exportTo('tr.c',function(){v [...]
+SelectionController.prototype={__proto__:tr.b.EventTarget.prototype,dispatchChangeEvent_:function(){var e=new tr.b.Event('change',false,false);this.dispatchEvent(e);},get model(){if(!this.timelineView_)
+return undefined;return this.timelineView_.model;},get trackView(){if(!this.timelineView_)
+return undefined;return this.timelineView_.trackView;},get viewport(){if(!this.timelineView_)
+return undefined;if(!this.timelineView_.trackView)
+return undefined;return this.timelineView_.trackView.viewport;},get historyEnabled(){return this.historyEnabled_;},set historyEnabled(historyEnabled){this.historyEnabled_=!!historyEnabled;if(historyEnabled)
+window.addEventListener('popstate',this.onPopState_);else
+window.removeEventListener('popstate',this.onPopState_);},modelWillChange:function(){if(this.currentBrushingState_.isAppliedToModel)
+this.currentBrushingState_.unapplyFromModelSelectionState();},modelDidChange:function(){this.selections_={};this.currentBrushingState_.applyToModelSelectionState(this.model);var e=new tr.b.Event('model-changed',false,false);this.dispatchEvent(e);},onUserInitiatedSelectionChange_:function(){var selection=this.selection;if(this.historyEnabled){this.selections_[selection.guid]=selection;var state={selection_guid:selection.guid};window.history.pushState(state,document.title);}},onPopState_:f [...]
+return;var selection=this.selections_[e.state.selection_guid];if(selection){var newState=this.currentBrushingState_.clone();newState.selection=selection;this.currentBrushingState=newState;}
+e.stopPropagation();},get selection(){return this.currentBrushingState_.selection;},get findMatches(){return this.currentBrushingState_.findMatches;},get selectionOfInterest(){return this.currentBrushingState_.selectionOfInterest;},get currentBrushingState(){return this.currentBrushingState_;},set currentBrushingState(newBrushingState){if(newBrushingState.isAppliedToModel)
+throw new Error('Cannot apply this state, it is applied');var hasValueChanged=!this.currentBrushingState_.equals(newBrushingState);if(newBrushingState!==this.currentBrushingState_&&!hasValueChanged){if(this.currentBrushingState_.isAppliedToModel){this.currentBrushingState_.transferModelOwnershipToClone(newBrushingState);}
+this.currentBrushingState_=newBrushingState;return;}
+if(this.currentBrushingState_.isAppliedToModel)
+this.currentBrushingState_.unapplyFromModelSelectionState();this.currentBrushingState_=newBrushingState;if(this.model)
+this.currentBrushingState_.applyToModelSelectionState(this.model);this.dispatchChangeEvent_();},addAllEventsMatchingFilterToSelectionAsTask:function(filter,selection){var timelineView=this.timelineView_.trackView;if(!timelineView)
+return new tr.b.Task();return timelineView.addAllEventsMatchingFilterToSelectionAsTask(filter,selection);},findTextChangedTo:function(allPossibleMatches){var newBrushingState=this.currentBrushingState_.clone();newBrushingState.findMatches=allPossibleMatches;this.currentBrushingState=newBrushingState;},findFocusChangedTo:function(currentFocus){var newBrushingState=this.currentBrushingState_.clone();newBrushingState.selection=currentFocus;this.currentBrushingState=newBrushingState;this.onU [...]
+if(this.guideLineAnnotation_!==undefined){this.model.removeAnnotation(this.guideLineAnnotation_);this.guideLineAnnotation_=undefined;}
+var newBrushingState=this.currentBrushingState_.clone();newBrushingState.selection=new Selection();newBrushingState.findMatches=new Selection();this.currentBrushingState=newBrushingState;this.onUserInitiatedSelectionChange_();},uiStateFromString:function(string){return tr.ui.b.UIState.fromUserFriendlyString(this.model,this.viewport,string);},navToPosition:function(uiState,showNavLine){this.trackView.navToPosition(uiState,showNavLine);},changeSelectionFromTimeline:function(selection){var  [...]
+ScriptingObject.prototype={onModelChanged:function(){}};return{ScriptingObject:ScriptingObject};});'use strict';tr.exportTo('tr.c',function(){function ScriptingController(selectionController){this.selectionController_=selectionController;this.scriptObjectNames_=[];this.scriptObjectValues_=[];this.selectionController.addEventListener('model-changed',this.onModelChanged_.bind(this));var typeInfos=ScriptingObjectRegistry.getAllRegisteredTypeInfos();typeInfos.forEach(function(typeInfo){this. [...]
+function ScriptingObjectRegistry(){}
+var options=new tr.b.ExtensionRegistryOptions(tr.b.BASIC_REGISTRY_MODE);tr.b.decorateExtensionRegistry(ScriptingObjectRegistry,options);ScriptingController.prototype={get selectionController(){return this.selectionController_;},onModelChanged_:function(){this.scriptObjectValues_.forEach(function(v){if(v.onModelChanged)
+v.onModelChanged();});},addScriptObject:function(name,value){this.scriptObjectNames_.push(name);this.scriptObjectValues_.push(value);},executeCommand:function(command){var f=new Function(this.scriptObjectNames_,'return eval('+command+')');return f.apply(null,this.scriptObjectValues_);}};return{ScriptingController:ScriptingController,ScriptingObjectRegistry:ScriptingObjectRegistry};});'use strict';tr.exportTo('tr.e.tquery',function(){function Context(){this.event=undefined;this.ancestors=[];}
+Context.prototype={push:function(event){var ctx=new Context();ctx.ancestors=this.ancestors.slice();ctx.ancestors.push(event);return ctx;},pop:function(event){var ctx=new Context();ctx.event=this.ancestors[this.ancestors.length-1];ctx.ancestors=this.ancestors.slice(0,this.ancestors.length-1);return ctx;}};return{Context:Context};});'use strict';tr.exportTo('tr.e.tquery',function(){function Filter(){tr.c.ScriptingObject.call(this);}
+Filter.normalizeFilterExpression=function(filterExpression){if(filterExpression instanceof String||typeof(filterExpression)=='string'||filterExpression instanceof RegExp){var filter=new tr.e.tquery.FilterHasTitle(filterExpression);return filter;}
+return filterExpression;};Filter.prototype={__proto__:tr.c.ScriptingObject.prototype,evaluate:function(context){throw new Error('Not implemented');},matchValue_:function(value,expected){if(expected instanceof RegExp)
+return expected.test(value);else if(expected instanceof Function)
+return expected(value);return value===expected;}};return{Filter:Filter};});'use strict';tr.exportTo('tr.e.tquery',function(){function FilterAllOf(opt_subExpressions){tr.e.tquery.Filter.call(this);this.subExpressions=opt_subExpressions||[];}
+FilterAllOf.prototype={__proto__:tr.e.tquery.Filter.prototype,set subExpressions(exprs){this.subExpressions_=[];for(var i=0;i<exprs.length;i++){this.subExpressions_.push(tr.e.tquery.Filter.normalizeFilterExpression(exprs[i]));}},get subExpressions(){return this.subExpressions_;},evaluate:function(context){if(!this.subExpressions.length)
+return true;for(var i=0;i<this.subExpressions.length;i++){if(!this.subExpressions[i].evaluate(context))
+return false;}
+return true;}};tr.c.ScriptingObjectRegistry.register(function(){var exprs=[];for(var i=0;i<arguments.length;i++){exprs.push(arguments[i]);}
+return new FilterAllOf(exprs);},{name:'allOf'});return{FilterAllOf:FilterAllOf};});'use strict';tr.exportTo('tr.e.tquery',function(){function FilterAnyOf(opt_subExpressions){tr.e.tquery.Filter.call(this);this.subExpressions=opt_subExpressions||[];};FilterAnyOf.prototype={__proto__:tr.e.tquery.Filter.prototype,set subExpressions(exprs){this.subExpressions_=[];for(var i=0;i<exprs.length;i++){this.subExpressions_.push(tr.e.tquery.Filter.normalizeFilterExpression(exprs[i]));}},get subExpress [...]
+return true;for(var i=0;i<this.subExpressions.length;i++){if(this.subExpressions[i].evaluate(context))
+return true;}
+return false;}};tr.c.ScriptingObjectRegistry.register(function(){var exprs=[];for(var i=0;i<arguments.length;i++){exprs.push(arguments[i]);}
+return new FilterAnyOf(exprs);},{name:'anyOf'});return{FilterAnyOf:FilterAnyOf};});'use strict';tr.exportTo('tr.e.tquery',function(){function FilterHasAncestor(opt_subExpression){this.subExpression=opt_subExpression;};FilterHasAncestor.prototype={__proto__:tr.e.tquery.Filter.prototype,set subExpression(expr){this.subExpression_=tr.e.tquery.Filter.normalizeFilterExpression(expr);},get subExpression(){return this.subExpression_;},evaluate:function(context){if(!this.subExpression)
+return context.ancestors.length>0;while(context.ancestors.length){context=context.pop();if(this.subExpression.evaluate(context))
+return true;}
+return false;}};tr.c.ScriptingObjectRegistry.register(function(subExpression){return new FilterHasAncestor(subExpression);},{name:'hasAncestor'});return{FilterHasAncestor:FilterHasAncestor};});'use strict';tr.exportTo('tr.e.tquery',function(){function FilterHasDuration(minValueOrExpected,opt_maxValue){if(minValueOrExpected!==undefined&&opt_maxValue!==undefined){this.minValue=minValueOrExpected;this.maxValue=opt_maxValue;}else{this.expected=minValueOrExpected;}};FilterHasDuration.prototyp [...]
+return false;if(this.minValue!==undefined&&this.maxValue!==undefined){return context.event.duration>=this.minValue&&context.event.duration<=this.maxValue;}
+return this.matchValue_(context.event.duration,this.expected);}};tr.c.ScriptingObjectRegistry.register(function(minValueOrExpected,opt_maxValue){return new FilterHasDuration(minValueOrExpected,opt_maxValue);},{name:'hasDuration'});return{FilterHasDuration:FilterHasDuration};});'use strict';tr.exportTo('tr.e.tquery',function(){function FilterHasTitle(expected){tr.e.tquery.Filter.call(this);this.expected=expected;}
+FilterHasTitle.prototype={__proto__:tr.e.tquery.Filter.prototype,evaluate:function(context){return this.matchValue_(context.event.title,this.expected);}};tr.c.ScriptingObjectRegistry.register(function(expected){var filter=new tr.e.tquery.FilterHasTitle(expected);return filter;},{name:'hasTitle'});return{FilterHasTitle:FilterHasTitle};});'use strict';tr.exportTo('tr.e.tquery',function(){function FilterIsTopLevel(opt_subExpression){this.subExpression=opt_subExpression;}
+FilterIsTopLevel.prototype={__proto__:tr.e.tquery.Filter.prototype,set subExpression(expr){this.subExpression_=tr.e.tquery.Filter.normalizeFilterExpression(expr);},get subExpression(){return this.subExpression_;},evaluate:function(context){if(context.ancestors.length>0)
+return false;if(!this.subExpression)
+return true;return this.subExpression.evaluate(context);}};tr.c.ScriptingObjectRegistry.register(function(subExpression){return new FilterIsTopLevel(subExpression);},{name:'isTopLevel'});return{FilterIsTopLevel:FilterIsTopLevel};});'use strict';tr.exportTo('tr.e.tquery',function(){function TQuery(selectionController){tr.c.ScriptingObject.call(this);this.selectionController_=selectionController;this.parent_=undefined;this.filterExpression_=undefined;this.selection_=undefined;};TQuery.prot [...]
+var rootTask=new tr.b.Task();var lastTask=rootTask;for(var i=nodes.length-1;i>=0;i--){var node=nodes[i];if(node.selection_!==undefined)
+continue;node.selection_=new tr.c.Selection();if(node.parent_===undefined){lastTask=lastTask.after(this.selectEverythingAsTask_(node.selection_));}else{var prevNode=nodes[i+1];lastTask=this.createFilterTaskForNode_(lastTask,node,prevNode);}}
+return{rootTask:rootTask,lastTask:lastTask,lastNode:node};},createFilterTaskForNode_:function(lastTask,node,prevNode){return lastTask.after(function(){node.evaluateFilterExpression_(prevNode.selection_,node.selection_);},this);},evaluateFilterExpression_:function(inputSelection,outputSelection){var seenEvents={};inputSelection.forEach(function(event){var context=new tr.e.tquery.Context();context.event=event;this.evaluateFilterExpressionForEvent_(context,inputSelection,outputSelection,see [...]
+outputSelection.push(event);}
+if(!event.subSlices)
+return;context=context.push(event);for(var i=0;i<event.subSlices.length;i++){context.event=event.subSlices[i];this.evaluateFilterExpressionForEvent_(context,inputSelection,outputSelection,seenEvents);}},show:function(){var graph=this.createFilterTaskGraph_();graph.lastTask=graph.lastTask.after(function(){this.selectionController.showScriptControlSelection(graph.lastNode.selection_);},this);return graph.rootTask;},selectEverythingAsTask_:function(selection){var passThroughFilter=new tr.c. [...]
+return this.selection_;}};tr.c.ScriptingObjectRegistry.register(new TQuery(),{name:'$t'});return{TQuery:TQuery};});'use strict';Polymer('tracing-scripting-control',{_isEnterKey:function(event){return event.keyCode!==229&&event.keyIdentifier==='Enter';},_setFocused:function(focused){var promptEl=this.$.prompt;if(focused){promptEl.focus();this.$.root.classList.add('focused');if(promptEl.innerText.length>0){var sel=window.getSelection();sel.collapse(promptEl.firstChild,promptEl.innerText.le [...]
+return;var promptEl=this.$.prompt;var command=promptEl.innerText;if(command.length===0)
+return;promptEl.innerText='';this.addLine_(String.fromCharCode(187)+' '+command);try{var result=this.controller_.executeCommand(command);}catch(e){result=e.stack||e.stackTrace;}
+if(result instanceof tr.b.Task){tr.b.Task.RunWhenIdle(result);}else{this.addLine_(result);}},addLine_:function(line){var historyEl=this.$.history;if(historyEl.innerText.length!==0)
+historyEl.innerText+='\n';historyEl.innerText+=line;},promptKeyPress:function(e){e.stopPropagation();},toggleVisibility:function(){var root=this.$.root;if(!this.visible){root.classList.remove('hidden');this._setFocused(true);}else{root.classList.add('hidden');this._setFocused(false);}},get hasFocus(){return this===document.activeElement;},get visible(){var root=this.$.root;return!root.classList.contains('hidden');},get controller(){return this.controller_;},set controller(c){this.control [...]
+this.selectionController_=selectionController;if(this.selectionController){this.selectionController_.addEventListener('change',this.onSelectionChanged_);this.selectionController_.addEventListener('model-changed',this.onModelChanged_);}},get selection(){return this.selectionController_.selection;},onSelectionChanged_:function(){if(this.activePanel)
+this.activePanel.selection=this.selection;},get model(){return this.selectionController_.model;},onModelChanged_:function(){this.activePanelType_=undefined;this.updateContents_();},get expanded(){this.hasAttribute('expanded');},get activePanel(){if(this.activePanelContainer_.children.length===0)
+return undefined;return this.activePanelContainer_.children[0];},get activePanelType(){return this.activePanelType_;},set activePanelType(panelType){if(this.model===undefined)
+throw new Error('Cannot activate panel without a model');var panel=undefined;if(panelType)
+panel=document.createElement(panelType);if(panel!==undefined&&!panel.supportsModel(this.model))
+throw new Error('Cannot activate panel: does not support this model');if(this.activePanelType){this.getLabelElementForPanelType_(this.activePanelType).removeAttribute('selected');}
+this.activePanelContainer_.textContent='';if(panelType===undefined){this.removeAttribute('expanded');this.activePanelType_=undefined;return;}
+this.getLabelElementForPanelType_(panelType).setAttribute('selected',true);this.setAttribute('expanded',true);this.activePanelContainer_.appendChild(panel);panel.rangeOfInterest=this.rangeOfInterest_;panel.selection=this.selection_;panel.model=this.model;this.activePanelType_=panelType;},getPanelTypeForConstructor_:function(constructor){for(var i=0;i<this.tabStrip_.children.length;i++){if(this.tabStrip_.children[i].panelType.constructor==constructor)
+return this.tabStrip_.children[i].panelType;}},getLabelElementForPanelType_:function(panelType){for(var i=0;i<this.tabStrip_.children.length;i++){if(this.tabStrip_.children[i].panelType==panelType)
+return this.tabStrip_.children[i];}
+return undefined;},updateContents_:function(){var previouslyActivePanelType=this.activePanelType;this.tabStrip_.textContent='';var supportedPanelTypes=[];var panelTypes=tr.ui.b.getPolymerElementsThatSubclass('tr-ui-side-panel');panelTypes.forEach(function(panelType){var labelEl=document.createElement('tab-strip-label');var panel=document.createElement(panelType);labelEl.textContent=panel.textLabel;labelEl.panelType=panelType;var supported=panel.supportsModel(this.model);if(this.model&&su [...]
+supported.reason;labelEl.style.display='none';}
+this.tabStrip_.appendChild(labelEl);},this);if(previouslyActivePanelType&&supportedPanelTypes.indexOf(previouslyActivePanelType)!=-1){this.activePanelType=previouslyActivePanelType;this.setAttribute('expanded',true);}else{this.activePanelContainer_.textContent='';this.removeAttribute('expanded');}},get rangeOfInterest(){return this.rangeOfInterest_;},set rangeOfInterest(range){if(range==undefined)
+throw new Error('Must not be undefined');this.rangeOfInterest_=range;if(this.activePanel)
+this.activePanel.rangeOfInterest=range;}});'use strict';Polymer('tr-ui-b-dropdown',{ready:function(){this.$.outer.addEventListener('click',this.onOuterClick_.bind(this));this.$.dialog.addEventListener('click',this.onDialogClick_.bind(this));this.$.dialog.addEventListener('cancel',this.onDialogCancel_.bind(this));},get iconElement(){return this.$.icon;},onOuterClick_:function(e){var or=this.$.outer.getBoundingClientRect();var inside=true;inside&=e.clientX>=or.left;inside&=e.clientX<or.rig [...]
+return;e.preventDefault();if(!this.isOpen)
+this.show();else
+this.close();},show:function(){if(this.isOpen)
+return;this.$.outer.classList.add('open');var ddr=this.$.outer.getBoundingClientRect();var rW=Math.max(ddr.width,150);this.$.dialog.style.minWidth=rW+'px';this.$.dialog.showModal();var ddw=this.$.outer.getBoundingClientRect().width;var w=this.$.dialog.getBoundingClientRect().width;this.$.dialog.style.top=ddr.bottom-1+'px';this.$.dialog.style.left=ddr.left+'px';},onDialogClick_:function(e){if(!this.isOpen)
+return;var dr=this.$.dialog.getBoundingClientRect();var inside=true;inside&=e.clientX>=dr.left;inside&=e.clientX<dr.right;inside&=e.clientY>=dr.top;inside&=e.clientY<dr.bottom;if(!inside){e.preventDefault();this.close();}},onDialogCancel_:function(e){e.preventDefault();this.close();},close:function(){if(!this.isOpen)
+return;this.$.dialog.close();this.$.outer.classList.remove('open');},get isOpen(){return this.$.dialog.hasAttribute('open');}});'use strict';tr.exportTo('tr.ui.b',function(){var DragHandle=tr.ui.b.define('x-drag-handle');DragHandle.prototype={__proto__:HTMLDivElement.prototype,decorate:function(){this.lastMousePos_=0;this.onMouseMove_=this.onMouseMove_.bind(this);this.onMouseUp_=this.onMouseUp_.bind(this);this.addEventListener('mousedown',this.onMouseDown_);this.target_=undefined;this.ho [...]
+return;this.observer_.observe(this.target_,{attributes:true,attributeFilter:['class']});},get horizontal(){return this.horizontal_;},set horizontal(h){this.horizontal_=h;if(this.horizontal_)
+this.className='horizontal-drag-handle';else
+this.className='vertical-drag-handle';},get vertical(){return!this.horizontal_;},set vertical(v){this.horizontal=!v;},forceMutationObserverFlush_:function(){var records=this.observer_.takeRecords();if(records.length)
+this.didTargetMutate_(records);},didTargetMutate_:function(e){var modeSize=this.targetSizesByModeKey_[this.modeKey_];if(modeSize!==undefined){this.setTargetSize_(modeSize);return;}
+this.target_.style[this.targetStyleKey_]='';},get targetStyleKey_(){return this.horizontal_?'height':'width';},getTargetSize_:function(){var targetStyleKey=this.targetStyleKey_;if(!this.target_.style[targetStyleKey]){this.target_.style[targetStyleKey]=window.getComputedStyle(this.target_)[targetStyleKey];}
+var size=parseInt(this.target_.style[targetStyleKey]);this.targetSizesByModeKey_[this.modeKey_]=size;return size;},setTargetSize_:function(s){this.target_.style[this.targetStyleKey_]=s+'px';this.targetSizesByModeKey_[this.modeKey_]=s;},applyDelta_:function(delta){var curSize=this.getTargetSize_();var newSize;if(this.target_===this.nextElementSibling){newSize=curSize+delta;}else{newSize=curSize-delta;}
+this.setTargetSize_(newSize);},onMouseMove_:function(e){var curMousePos=this.horizontal_?e.clientY:e.clientX;var delta=this.lastMousePos_-curMousePos;this.applyDelta_(delta);this.lastMousePos_=curMousePos;e.preventDefault();return true;},onMouseDown_:function(e){if(!this.target_)
+return;this.forceMutationObserverFlush_();this.lastMousePos_=this.horizontal_?e.clientY:e.clientX;document.addEventListener('mousemove',this.onMouseMove_);document.addEventListener('mouseup',this.onMouseUp_);e.preventDefault();return true;},onMouseUp_:function(e){document.removeEventListener('mousemove',this.onMouseMove_);document.removeEventListener('mouseup',this.onMouseUp_);e.preventDefault();}};return{DragHandle:DragHandle};});'use strict';tr.exportTo('tr.ui',function(){var THIS_DOC= [...]
+this.optionsDropdown_=document.createElement('tr-ui-b-dropdown');this.optionsDropdown_.iconElement.textContent='View Options';this.showFlowEvents_=false;this.optionsDropdown_.appendChild(tr.ui.b.createCheckBox(this,'showFlowEvents','tr.ui.TimelineView.showFlowEvents',false,'Flow events'));this.highlightVSync_=false;this.highlightVSyncCheckbox_=tr.ui.b.createCheckBox(this,'highlightVSync','tr.ui.TimelineView.highlightVSync',false,'Highlight VSync');this.optionsDropdown_.appendChild(this.h [...]
+hue='blue';else
+hue=this.model.faviconHue;var faviconData=tr.ui.b.FaviconsByHue[hue];if(faviconData===undefined)
+faviconData=tr.ui.b.FaviconsByHue['blue'];var link=document.head.querySelector('link[rel="shortcut icon"]');if(!link){link=document.createElement('link');link.rel='shortcut icon';document.head.appendChild(link);}
+link.href=faviconData;},get showFlowEvents(){return this.showFlowEvents_;},set showFlowEvents(showFlowEvents){this.showFlowEvents_=showFlowEvents;if(!this.trackView_)
+return;this.trackView_.viewport.showFlowEvents=showFlowEvents;},get highlightVSync(){return this.highlightVSync_;},set highlightVSync(highlightVSync){this.highlightVSync_=highlightVSync;if(!this.trackView_)
+return;this.trackView_.viewport.highlightVSync=highlightVSync;},createHelpButton_:function(){var node=tr.ui.b.instantiateTemplate('#help-btn-template',THIS_DOC);var showEl=node.querySelector('.view-help-button');var helpTextEl=node.querySelector('.view-help-text');var dlg=new tr.ui.b.Overlay();dlg.title='chrome://tracing Help';dlg.classList.add('view-help-overlay');dlg.appendChild(node);function onClick(e){dlg.visible=!dlg.visible;var mod=tr.isMac?'cmd ':'ctrl';var spans=helpTextEl.query [...]
+e.stopPropagation();return false;}
+showEl.addEventListener('click',onClick.bind(this));return showEl;},createConsoleButton_:function(){var node=tr.ui.b.instantiateTemplate('#console-btn-template',THIS_DOC);var toggleEl=node.querySelector('.view-console-button');function onClick(e){this.scriptingCtl_.toggleVisibility();e.stopPropagation();return false;}
+toggleEl.addEventListener('click',onClick.bind(this));return toggleEl;},createMetadataButton_:function(){var node=tr.ui.b.instantiateTemplate('#metadata-btn-template',THIS_DOC);var showEl=node.querySelector('.view-metadata-button');var textEl=node.querySelector('.info-button-text');var dlg=new tr.ui.b.Overlay();dlg.title='Metadata for trace';dlg.classList.add('view-metadata-overlay');dlg.appendChild(node);function onClick(e){dlg.visible=true;var metadataStrings=[];var model=this.model;fo [...]
+textEl.textContent=metadataStrings.join('\n');e.stopPropagation();return false;}
+showEl.addEventListener('click',onClick.bind(this));function updateVisibility(){showEl.style.display=(this.model&&this.model.metadata.length)?'':'none';}
+var updateVisibility_=updateVisibility.bind(this);updateVisibility_();this.addEventListener('modelChange',updateVisibility_);return showEl;},get leftControls(){return this.leftControlsEl_;},get rightControls(){return this.rightControlsEl_;},get collapsingControls(){return this.collapsingControlsEl_;},get viewTitle(){return this.titleEl_.textContent.substring(this.titleEl_.textContent.length-2);},set viewTitle(text){if(text===undefined){this.titleEl_.textContent='';this.titleEl_.hidden=tr [...]
+this.titleEl_.hidden=false;this.titleEl_.textContent=text;},get model(){if(this.trackView_)
+return this.trackView_.model;return undefined;},set model(model){var modelInstanceChanged=model!=this.model;var modelValid=model&&!model.bounds.isEmpty;if(modelInstanceChanged){if(this.railScoreSpan_)
+this.railScoreSpan_.railScore=undefined;this.trackViewContainer_.textContent='';if(this.trackView_){this.trackView_.viewport.removeEventListener('change',this.onViewportChanged_);this.trackView_.selectionController=undefined;this.trackView_.detach();this.trackView_=undefined;}
+this.selectionController_.modelWillChange();}
+if(modelValid&&!this.trackView_){this.trackView_=new tr.ui.TimelineTrackView(this);this.trackView.selectionController=this.selectionController_;this.trackView_.focusElement=this.focusElement_?this.focusElement_:this.parentElement;this.trackViewContainer_.appendChild(this.trackView_);this.trackView_.viewport.addEventListener('change',this.onViewportChanged_);}
+if(modelValid){this.trackView_.model=model;this.trackView_.viewport.showFlowEvents=this.showFlowEvents;this.trackView_.viewport.highlightVSync=this.highlightVSync;if(this.railScoreSpan_){var railScore=tr.e.rail.RAILScore.fromModel(model);this.railScoreSpan_.railScore=railScore;}}
+if(modelInstanceChanged){tr.b.dispatchSimpleEvent(this,'modelChange');this.selectionController_.modelDidChange();this.onViewportChanged_();}},get selectionController(){return this.selectionController_;},get trackView(){return this.trackView_;},get settings(){if(!this.settings_)
+this.settings_=new tr.b.Settings();return this.settings_;},set focusElement(value){this.focusElement_=value;if(this.trackView_)
+this.trackView_.focusElement=value;},get focusElement(){if(this.focusElement_)
+return this.focusElement_;return this.parentElement;},get listenToKeys_(){if(!tr.ui.b.isElementAttachedToDocument(this))
+return;if(document.activeElement.type==='textarea')
+return false;if(this.sidePanelContainer_.activePanel&&this.sidePanelContainer_.activePanel.listeningToKeys)
+return false;if(!this.focusElement_)
+return true;if(this.focusElement.tabIndex>=0)
+return document.activeElement==this.focusElement;return true;},onKeyDown_:function(e){if(!this.listenToKeys_)
+return;},onKeypress_:function(e){if(!this.listenToKeys_)
+return;switch(e.keyCode){case'`'.charCodeAt(0):this.scriptingCtl_.toggleVisibility();if(!this.scriptingCtl_.hasFocus)
+this.focus();e.preventDefault();break;}
+if(this.scriptingCtl_.hasFocus)
+return;switch(e.keyCode){case'/'.charCodeAt(0):if(this.findCtl_.hasFocus)
+this.focus();else
+this.findCtl_.focus();e.preventDefault();break;case'?'.charCodeAt(0):this.querySelector('.view-help-button').click();e.preventDefault();break;}
+if(this.findCtl_.hasFocus)
+return;switch(e.keyCode){case'v'.charCodeAt(0):this.toggleHighlightVSync_();e.preventDefault();break;}},onViewportChanged_:function(e){var spc=this.sidePanelContainer_;if(!this.trackView_){spc.rangeOfInterest.reset();return;}
+var vr=this.trackView_.viewport.interestRange.asRangeObject();if(!spc.rangeOfInterest.equals(vr))
+spc.rangeOfInterest=vr;},toggleHighlightVSync_:function(){this.highlightVSyncCheckbox_.checked=!this.highlightVSyncCheckbox_.checked;},setFindCtlText:function(string){this.findCtl_.setText(string);}};return{TimelineView:TimelineView};});'use strict';tr.exportTo('tr',function(){var TraceViewer=tr.ui.b.define('trace-viewer',tr.ui.TimelineView);TraceViewer.prototype={__proto__:tr.ui.TimelineView.prototype,decorate:function(opt_url){tr.ui.TimelineView.prototype.decorate.call(this);if(opt_url [...]
+return;var url=opt_url;var that=this;var req=new XMLHttpRequest();var is_binary=/[.]gz$/.test(url)||/[.]zip$/.test(url);req.overrideMimeType('text/plain; charset=x-user-defined');req.open('GET',url,true);if(is_binary)
+req.responseType='arraybuffer';req.onreadystatechange=function(aEvt){if(req.readyState==4){window.setTimeout(function(){if(req.status==200){onResult(is_binary?req.response:req.responseText);}else{onResultFail(req.status);}},0);}};req.send(null);function onResultFail(err){var overlay=new tr.ui.b.Overlay();overlay.textContent=err+': '+url+' could not be loaded';overlay.title='Failed to fetch data';overlay.visible=true;}
+var model;function onResult(result){model=new tr.Model();var p=model.importTracesWithProgressDialog([result],true);p.then(onModelLoaded,onImportFail);}
+function onModelLoaded(){that.model=model;that.viewTitle=url;if(that.timeline)
+that.timeline.focusElement=that;}
+function onImportFail(){var overlay=new tr.ui.b.Overlay();overlay.textContent=tr.b.normalizeException(err).message;overlay.title='Import error';overlay.visible=true;}}};return{TraceViewer:TraceViewer};});'use strict';tr.exportTo('tr.b',function(){var tmpVec2s=[];for(var i=0;i<8;i++)
+tmpVec2s[i]=vec2.create();var tmpVec2a=vec4.create();var tmpVec4a=vec4.create();var tmpVec4b=vec4.create();var tmpMat4=mat4.create();var tmpMat4b=mat4.create();var p00=vec2.createXY(0,0);var p10=vec2.createXY(1,0);var p01=vec2.createXY(0,1);var p11=vec2.createXY(1,1);var lerpingVecA=vec2.create();var lerpingVecB=vec2.create();function lerpVec2(out,a,b,amt){vec2.scale(lerpingVecA,a,amt);vec2.scale(lerpingVecB,b,1-amt);vec2.add(out,lerpingVecA,lerpingVecB);vec2.normalize(out,out);return out;}
+function Quad(){this.p1=vec2.create();this.p2=vec2.create();this.p3=vec2.create();this.p4=vec2.create();}
+Quad.fromXYWH=function(x,y,w,h){var q=new Quad();vec2.set(q.p1,x,y);vec2.set(q.p2,x+w,y);vec2.set(q.p3,x+w,y+h);vec2.set(q.p4,x,y+h);return q;}
+Quad.fromRect=function(r){return new Quad.fromXYWH(r.x,r.y,r.width,r.height);}
+Quad.from4Vecs=function(p1,p2,p3,p4){var q=new Quad();vec2.set(q.p1,p1[0],p1[1]);vec2.set(q.p2,p2[0],p2[1]);vec2.set(q.p3,p3[0],p3[1]);vec2.set(q.p4,p4[0],p4[1]);return q;}
+Quad.from8Array=function(arr){if(arr.length!=8)
+throw new Error('Array must be 8 long');var q=new Quad();q.p1[0]=arr[0];q.p1[1]=arr[1];q.p2[0]=arr[2];q.p2[1]=arr[3];q.p3[0]=arr[4];q.p3[1]=arr[5];q.p4[0]=arr[6];q.p4[1]=arr[7];return q;};Quad.prototype={pointInside:function(point){return pointInImplicitQuad(point,this.p1,this.p2,this.p3,this.p4);},boundingRect:function(){var x0=Math.min(this.p1[0],this.p2[0],this.p3[0],this.p4[0]);var y0=Math.min(this.p1[1],this.p2[1],this.p3[1],this.p4[1]);var x1=Math.max(this.p1[0],this.p2[0],this.p3[ [...]
+vec2.toString(this.p1)+', '+
+vec2.toString(this.p2)+', '+
+vec2.toString(this.p3)+', '+
+vec2.toString(this.p4)+')';}};function sign(p1,p2,p3){return(p1[0]-p3[0])*(p2[1]-p3[1])-
+(p2[0]-p3[0])*(p1[1]-p3[1]);}
+function pointInTriangle2(pt,p1,p2,p3){var b1=sign(pt,p1,p2)<0.0;var b2=sign(pt,p2,p3)<0.0;var b3=sign(pt,p3,p1)<0.0;return((b1==b2)&&(b2==b3));}
+function pointInImplicitQuad(point,p1,p2,p3,p4){return pointInTriangle2(point,p1,p2,p3)||pointInTriangle2(point,p1,p3,p4);}
+return{pointInTriangle2:pointInTriangle2,pointInImplicitQuad:pointInImplicitQuad,Quad:Quad};});'use strict';tr.exportTo('tr.ui.annotations',function(){function RectAnnotationView(viewport,annotation){this.viewport_=viewport;this.annotation_=annotation;}
+RectAnnotationView.prototype={__proto__:tr.ui.annotations.AnnotationView.prototype,draw:function(ctx){var dt=this.viewport_.currentDisplayTransform;var startCoords=this.annotation_.startLocation.toViewCoordinates(this.viewport_);var endCoords=this.annotation_.endLocation.toViewCoordinates(this.viewport_);var startY=startCoords.viewY-ctx.canvas.getBoundingClientRect().top;var sizeY=endCoords.viewY-startCoords.viewY;if(startY+sizeY<0){startY=sizeY;}else if(startY<0){startY=0;}
+ctx.fillStyle=this.annotation_.fillStyle;ctx.fillRect(startCoords.viewX,startY,endCoords.viewX-startCoords.viewX,sizeY);}};return{RectAnnotationView:RectAnnotationView};});'use strict';tr.exportTo('tr.model',function(){function RectAnnotation(start,end){tr.model.Annotation.apply(this,arguments);this.startLocation_=start;this.endLocation_=end;this.fillStyle='rgba(255, 180, 0, 0.3)';}
+RectAnnotation.fromDict=function(dict){var args=dict.args;var startLoc=new tr.ui.b.Location(args.start.xWorld,args.start.yComponents);var endLoc=new tr.ui.b.Location(args.end.xWorld,args.end.yComponents);return new tr.model.RectAnnotation(startLoc,endLoc);}
+RectAnnotation.prototype={__proto__:tr.model.Annotation.prototype,get startLocation(){return this.startLocation_;},get endLocation(){return this.endLocation_;},toDict:function(){return{typeName:'rect',args:{start:this.startLocation.toDict(),end:this.endLocation.toDict()}};},createView_:function(viewport){return new tr.ui.annotations.RectAnnotationView(viewport,this);}};tr.model.Annotation.register(RectAnnotation,{typeName:'rect'});return{RectAnnotation:RectAnnotation};});'use strict';tr. [...]
+CommentBoxAnnotationView.prototype={__proto__:tr.ui.annotations.AnnotationView.prototype,removeTextArea:function(){this.textArea_.parentNode.removeChild(this.textArea_);},draw:function(ctx){var coords=this.annotation_.location.toViewCoordinates(this.viewport_);if(coords.viewX<0){if(this.textArea_)
+this.textArea_.style.visibility='hidden';return;}
+if(!this.textArea_){this.textArea_=document.createElement('textarea');this.textArea_.style.position='absolute';this.textArea_.readOnly=true;this.textArea_.value=this.annotation_.text;this.textArea_.style.zIndex=1;ctx.canvas.parentNode.appendChild(this.textArea_);}
+this.textArea_.style.width=this.styleWidth+'px';this.textArea_.style.height=this.styleHeight+'px';this.textArea_.style.fontSize=this.fontSize+'px';this.textArea_.style.visibility='visible';this.textArea_.style.left=coords.viewX+ctx.canvas.getBoundingClientRect().left+
+this.rightOffset+'px';this.textArea_.style.top=coords.viewY-ctx.canvas.getBoundingClientRect().top-
+this.topOffset+'px';ctx.strokeStyle='rgb(0, 0, 0)';ctx.lineWidth=2;ctx.beginPath();tr.ui.b.drawLine(ctx,coords.viewX,coords.viewY-ctx.canvas.getBoundingClientRect().top,coords.viewX+this.rightOffset,coords.viewY-this.topOffset-
+ctx.canvas.getBoundingClientRect().top);ctx.stroke();}};return{CommentBoxAnnotationView:CommentBoxAnnotationView};});'use strict';tr.exportTo('tr.model',function(){function CommentBoxAnnotation(location,text){tr.model.Annotation.apply(this,arguments);this.location=location;this.text=text;}
+CommentBoxAnnotation.fromDict=function(dict){var args=dict.args;var location=new tr.ui.b.Location(args.location.xWorld,args.location.yComponents);return new tr.model.CommentBoxAnnotation(location,args.text);};CommentBoxAnnotation.prototype={__proto__:tr.model.Annotation.prototype,onRemove:function(){this.view_.removeTextArea();},toDict:function(){return{typeName:'comment_box',args:{text:this.text,location:this.location.toDict()}};},createView_:function(viewport){return new tr.ui.annotati [...]
+return value;if(typeof value=='string')
+return value.substring();if(typeof value=='boolean')
+return value;if(typeof value=='number')
+return value;throw new Error('Unrecognized: '+typeof value);}
+var object=value;if(object instanceof Array){var res=new Array(object.length);for(var i=0;i<object.length;i++)
+res[i]=deepCopy(object[i]);return res;}
+if(object.__proto__!=Object.prototype)
+throw new Error('Can only clone simple types');var res={};for(var key in object){res[key]=deepCopy(object[key]);}
+return res;}
+var timestampFromUs=tr.b.units.Time.timestampFromUs;var maybeTimestampFromUs=tr.b.units.Time.maybeTimestampFromUs;function TraceEventImporter(model,eventData){this.importPriority=1;this.model_=model;this.events_=undefined;this.sampleEvents_=undefined;this.stackFrameEvents_=undefined;this.systemTraceEvents_=undefined;this.eventsWereFromString_=false;this.softwareMeasuredCpuCount_=undefined;this.allAsyncEvents_=[];this.allFlowEvents_=[];this.allObjectEvents_=[];this.traceEventSampleStackFr [...]
+eventData=eventData+']';}
+this.events_=JSON.parse(eventData);this.eventsWereFromString_=true;}else{this.events_=eventData;}
+this.traceAnnotations_=this.events_.traceAnnotations;if(this.events_.traceEvents){var container=this.events_;this.events_=this.events_.traceEvents;this.systemTraceEvents_=container.systemTraceEvents;this.sampleEvents_=container.samples;this.stackFrameEvents_=container.stackFrames;if(container.displayTimeUnit){var unitName=container.displayTimeUnit;var unit=tr.b.units.Time.supportedUnits[unitName];if(unit===undefined){throw new Error('Unit '+unitName+' is not supported.');}
+this.model_.intrinsicTimeUnit=unit;}
+for(var fieldName in container){if(fieldName==='traceEvents'||fieldName==='systemTraceEvents'||fieldName==='samples'||fieldName==='stackFrames'||fieldName==='traceAnnotations')
+continue;this.model_.metadata.push({name:fieldName,value:container[fieldName]});}}}
+TraceEventImporter.canImport=function(eventData){if(typeof(eventData)==='string'||eventData instanceof String){eventData=eventData.trim();return eventData[0]=='{'||eventData[0]=='[';}
+if(eventData instanceof Array&&eventData.length&&eventData[0].ph)
+return true;if(eventData.traceEvents){if(eventData.traceEvents instanceof Array){if(eventData.traceEvents.length&&eventData.traceEvents[0].ph)
+return true;if(eventData.samples.length&&eventData.stackFrames!==undefined)
+return true;}}
+return false;};TraceEventImporter.prototype={__proto__:Importer.prototype,extractSubtraces:function(){var tmp=this.systemTraceEvents_;this.systemTraceEvents_=undefined;return tmp?[tmp]:[];},deepCopyIfNeeded_:function(obj){if(obj===undefined)
+obj={};if(this.eventsWereFromString_)
+return obj;return deepCopy(obj);},processAsyncEvent:function(event){var thread=this.model_.getOrCreateProcess(event.pid).getOrCreateThread(event.tid);this.allAsyncEvents_.push({sequenceNumber:this.allAsyncEvents_.length,event:event,thread:thread});},processFlowEvent:function(event){var thread=this.model_.getOrCreateProcess(event.pid).getOrCreateThread(event.tid);this.allFlowEvents_.push({refGuid:tr.b.GUID.getLastGuid(),sequenceNumber:this.allFlowEvents_.length,event:event,thread:thread}) [...]
+ctr_name=event.name+'['+event.id+']';else
+ctr_name=event.name;var ctr=this.model_.getOrCreateProcess(event.pid).getOrCreateCounter(event.cat,ctr_name);if(ctr.numSeries===0){for(var seriesName in event.args){ctr.addSeries(new tr.model.CounterSeries(seriesName,tr.ui.b.getColorIdForGeneralPurposeString(ctr.name+'.'+seriesName)));}
+if(ctr.numSeries===0){this.model_.importWarning({type:'counter_parse_error',message:'Expected counter '+event.name+' to have at least one argument to use as a value.'});delete ctr.parent.counters[ctr.name];return;}}
+var ts=timestampFromUs(event.ts);ctr.series.forEach(function(series){var val=event.args[series.name]?event.args[series.name]:0;series.addCounterSample(ts,val);});},processObjectEvent:function(event){var thread=this.model_.getOrCreateProcess(event.pid).getOrCreateThread(event.tid);this.allObjectEvents_.push({sequenceNumber:this.allObjectEvents_.length,event:event,thread:thread});},processDurationEvent:function(event){var thread=this.model_.getOrCreateProcess(event.pid).getOrCreateThread(e [...]
+if(event.ph=='B'){var slice=thread.sliceGroup.beginSlice(event.cat,event.name,timestampFromUs(event.ts),this.deepCopyIfNeeded_(event.args),timestampFromUs(event.tts),event.argsStripped);slice.startStackFrame=this.getStackFrameForEvent_(event);}else if(event.ph=='I'||event.ph=='i'){if(event.s!==undefined&&event.s!=='t')
+throw new Error('This should never happen');thread.sliceGroup.beginSlice(event.cat,event.name,timestampFromUs(event.ts),this.deepCopyIfNeeded_(event.args),timestampFromUs(event.tts));var slice=thread.sliceGroup.endSlice(timestampFromUs(event.ts),timestampFromUs(event.tts));slice.startStackFrame=this.getStackFrameForEvent_(event);slice.endStackFrame=undefined;}else{if(!thread.sliceGroup.openSliceCount){this.model_.importWarning({type:'duration_parse_error',message:'E phase event without a [...]
+var slice=thread.sliceGroup.endSlice(timestampFromUs(event.ts),timestampFromUs(event.tts));if(event.name&&slice.title!=event.name){this.model_.importWarning({type:'title_match_error',message:'Titles do not match. Title is '+
+slice.title+' in openSlice, and is '+
+event.name+' in endSlice'});}
+slice.endStackFrame=this.getStackFrameForEvent_(event);this.mergeArgsInto_(slice.args,event.args,slice.title);}},mergeArgsInto_:function(dstArgs,srcArgs,eventName){for(var arg in srcArgs){if(dstArgs[arg]!==undefined){this.model_.importWarning({type:'arg_merge_error',message:'Different phases of '+eventName+' provided values for argument '+arg+'.'+' The last provided value will be used.'});}
+dstArgs[arg]=this.deepCopyIfNeeded_(srcArgs[arg]);}},processCompleteEvent:function(event){var thread=this.model_.getOrCreateProcess(event.pid).getOrCreateThread(event.tid);var slice=thread.sliceGroup.pushCompleteSlice(event.cat,event.name,timestampFromUs(event.ts),maybeTimestampFromUs(event.dur),maybeTimestampFromUs(event.tts),maybeTimestampFromUs(event.tdur),this.deepCopyIfNeeded_(event.args),event.argsStripped);slice.startStackFrame=this.getStackFrameForEvent_(event);slice.endStackFram [...]
+return;if(event.name=='process_name'){var process=this.model_.getOrCreateProcess(event.pid);process.name=event.args.name;}else if(event.name=='process_labels'){var process=this.model_.getOrCreateProcess(event.pid);var labels=event.args.labels.split(',');for(var i=0;i<labels.length;i++)
+process.addLabelIfNeeded(labels[i]);}else if(event.name=='process_sort_index'){var process=this.model_.getOrCreateProcess(event.pid);process.sortIndex=event.args.sort_index;}else if(event.name=='thread_name'){var thread=this.model_.getOrCreateProcess(event.pid).getOrCreateThread(event.tid);thread.name=event.args.name;}else if(event.name=='thread_sort_index'){var thread=this.model_.getOrCreateProcess(event.pid).getOrCreateThread(event.tid);thread.sortIndex=event.args.sort_index;}else if(e [...]
+n=Math.max(n,this.softwareMeasuredCpuCount_);this.softwareMeasuredCpuCount_=n;}else{this.model_.importWarning({type:'metadata_parse_error',message:'Unrecognized metadata name: '+event.name});}},processInstantEvent:function(event){if(event.s=='t'||event.s===undefined){this.processDurationEvent(event);return;}
+var constructor;switch(event.s){case'g':constructor=tr.model.GlobalInstantEvent;break;case'p':constructor=tr.model.ProcessInstantEvent;break;default:this.model_.importWarning({type:'instant_parse_error',message:'I phase event with unknown "s" field value.'});return;}
+var colorId=tr.ui.b.getColorIdForGeneralPurposeString(event.name);var instantEvent=new constructor(event.cat,event.name,colorId,timestampFromUs(event.ts),this.deepCopyIfNeeded_(event.args));switch(instantEvent.type){case tr.model.InstantEventType.GLOBAL:this.model_.pushInstantEvent(instantEvent);break;case tr.model.InstantEventType.PROCESS:var process=this.model_.getOrCreateProcess(event.pid);process.pushInstantEvent(instantEvent);break;default:throw new Error('Unknown instant event type [...]
+if(stackFrame===undefined){var id='te-'+tr.b.GUID.allocate();stackFrame=new tr.model.StackFrame(undefined,id,event.cat,event.name,tr.ui.b.getColorIdForGeneralPurposeString(event.name));this.model_.addStackFrame(stackFrame);this.traceEventSampleStackFramesByName_[event.name]=stackFrame;}
+var sample=new tr.model.Sample(undefined,thread,'TRACE_EVENT_SAMPLE',timestampFromUs(event.ts),stackFrame,1,this.deepCopyIfNeeded_(event.args));this.model_.samples.push(sample);},getOrCreateMemoryDumpEvents_:function(dumpId){if(this.allMemoryDumpEvents_[dumpId]===undefined){this.allMemoryDumpEvents_[dumpId]={global:undefined,process:[]};}
+return this.allMemoryDumpEvents_[dumpId];},processMemoryDumpEvent:function(event){if(event.id===undefined){this.model_.importWarning({type:'memory_dump_parse_error',message:event.ph+' phase event without a dump ID.'});return;}
+var events=this.getOrCreateMemoryDumpEvents_(event.id);if(event.ph==='v'){events.process.push(event);}else if(event.ph==='V'){if(events.global!==undefined){this.model_.importWarning({type:'memory_dump_parse_error',message:'Multiple V phase events with the same dump ID.'});return;}
+events.global=event;}else{throw new Error('Invalid memory dump event phase "'+event.ph+'".');}},importEvents:function(){var csr=new tr.ClockSyncRecord('ftrace_importer',0,{});this.model_.clockSyncRecords.push(csr);if(this.stackFrameEvents_)
+this.importStackFrames_();if(this.traceAnnotations_)
+this.importAnnotations_();var events=this.events_;for(var eI=0;eI<events.length;eI++){var event=events[eI];if(event.args==='__stripped__'){event.argsStripped=true;event.args=undefined;}
+if(event.ph==='B'||event.ph==='E'){this.processDurationEvent(event);}else if(event.ph==='X'){this.processCompleteEvent(event);}else if(event.ph==='b'||event.ph==='e'||event.ph==='n'||event.ph==='S'||event.ph==='F'||event.ph==='T'||event.ph==='p'){this.processAsyncEvent(event);}else if(event.ph=='I'||event.ph=='i'){this.processInstantEvent(event);}else if(event.ph=='P'){this.processTraceSampleEvent(event);}else if(event.ph=='C'){this.processCounterEvent(event);}else if(event.ph=='M'){this [...]
+event.ph+' ('+event.name+')'});}}},importStackFrames_:function(){var m=this.model_;var events=this.stackFrameEvents_;for(var id in events){var event=events[id];var textForColor=event.category?event.category:event.name;var frame=new tr.model.StackFrame(undefined,'g'+id,event.category,event.name,tr.ui.b.getColorIdForGeneralPurposeString(textForColor));m.addStackFrame(frame);}
+for(var id in events){var event=events[id];if(event.parent===undefined)
+continue;var frame=m.stackFrames['g'+id];if(frame===undefined)
+throw new Error('omg');var parentFrame;if(event.parent===undefined){parentFrame=undefined;}else{parentFrame=m.stackFrames['g'+event.parent];if(parentFrame===undefined)
+throw new Error('omg');}
+frame.parentFrame=parentFrame;}},importAnnotations_:function(){for(var id in this.traceAnnotations_){var annotation=tr.model.Annotation.fromDictIfPossible(this.traceAnnotations_[id]);if(!annotation){this.model_.importWarning({type:'annotation_warning',message:'Unrecognized traceAnnotation typeName \"'+
+this.traceAnnotations_[id].typeName+'\"'});continue;}
+this.model_.addAnnotation(annotation);}},finalizeImport:function(){if(this.softwareMeasuredCpuCount_!==undefined){this.model_.kernel.softwareMeasuredCpuCount=this.softwareMeasuredCpuCount_;}
+this.createAsyncSlices_();this.createFlowSlices_();this.createExplicitObjects_();this.createImplicitObjects_();this.createMemoryDumps_();},getStackFrameForEvent_:function(event,opt_lookForEndEvent){var sf;var stack;if(opt_lookForEndEvent){sf=event.esf;stack=event.estack;}else{sf=event.sf;stack=event.stack;}
+if(stack!==undefined&&sf!==undefined){this.model_.importWarning({type:'stack_frame_and_stack_error',message:'Event at '+event.ts+' cannot have both a stack and a stackframe.'});return undefined;}
+if(stack!==undefined)
+return this.model_.resolveStackToStackFrame_(event.pid,stack);if(sf===undefined)
+return undefined;var stackFrame=this.model_.stackFrames['g'+sf];if(stackFrame===undefined){this.model_.importWarning({type:'sample_import_error',message:'No frame for '+sf});return;}
+return stackFrame;},resolveStackToStackFrame_:function(pid,stack){return undefined;},importSampleData:function(){if(!this.sampleEvents_)
+return;var m=this.model_;var events=this.sampleEvents_;if(this.events_.length===0){for(var i=0;i<events.length;i++){var event=events[i];m.getOrCreateProcess(event.tid).getOrCreateThread(event.tid);}}
+var threadsByTid={};m.getAllThreads().forEach(function(t){threadsByTid[t.tid]=t;});for(var i=0;i<events.length;i++){var event=events[i];var thread=threadsByTid[event.tid];if(thread===undefined){m.importWarning({type:'sample_import_error',message:'Thread '+events.tid+'not found'});continue;}
+var cpu;if(event.cpu!==undefined)
+cpu=m.kernel.getOrCreateCpu(event.cpu);var stackFrame=this.getStackFrameForEvent_(event);var sample=new tr.model.Sample(cpu,thread,event.name,timestampFromUs(event.ts),stackFrame,event.weight);m.samples.push(sample);}},joinRefs:function(){this.joinObjectRefs_();},createAsyncSlices_:function(){if(this.allAsyncEvents_.length===0)
+return;this.allAsyncEvents_.sort(function(x,y){var d=x.event.ts-y.event.ts;if(d!==0)
+return d;return x.sequenceNumber-y.sequenceNumber;});var legacyEvents=[];var nestableAsyncEventsByKey={};for(var i=0;i<this.allAsyncEvents_.length;i++){var asyncEventState=this.allAsyncEvents_[i];var event=asyncEventState.event;if(event.ph==='S'||event.ph==='F'||event.ph==='T'||event.ph==='p'){legacyEvents.push(asyncEventState);continue;}
+if(event.cat===undefined){this.model_.importWarning({type:'async_slice_parse_error',message:'Nestable async events (ph: b, e, or n) require a '+'cat parameter.'});continue;}
+if(event.name===undefined){this.model_.importWarning({type:'async_slice_parse_error',message:'Nestable async events (ph: b, e, or n) require a '+'name parameter.'});continue;}
+if(event.id===undefined){this.model_.importWarning({type:'async_slice_parse_error',message:'Nestable async events (ph: b, e, or n) require an '+'id parameter.'});continue;}
+var key=event.cat+':'+event.id;if(nestableAsyncEventsByKey[key]===undefined)
+nestableAsyncEventsByKey[key]=[];nestableAsyncEventsByKey[key].push(asyncEventState);}
+this.createLegacyAsyncSlices_(legacyEvents);for(var key in nestableAsyncEventsByKey){var eventStateEntries=nestableAsyncEventsByKey[key];var parentStack=[];for(var i=0;i<eventStateEntries.length;++i){var eventStateEntry=eventStateEntries[i];if(eventStateEntry.event.ph==='e'){var parentIndex=-1;for(var k=parentStack.length-1;k>=0;--k){if(parentStack[k].event.name===eventStateEntry.event.name){parentIndex=k;break;}}
+if(parentIndex===-1){eventStateEntry.finished=false;}else{parentStack[parentIndex].end=eventStateEntry;while(parentIndex<parentStack.length){parentStack.pop();}}}
+if(parentStack.length>0)
+eventStateEntry.parentEntry=parentStack[parentStack.length-1];if(eventStateEntry.event.ph==='b')
+parentStack.push(eventStateEntry);}
+var topLevelSlices=[];for(var i=0;i<eventStateEntries.length;++i){var eventStateEntry=eventStateEntries[i];if(eventStateEntry.event.ph==='e'&&eventStateEntry.finished===undefined){continue;}
+var startState=undefined;var endState=undefined;var sliceArgs=eventStateEntry.event.args||{};var sliceError=undefined;if(eventStateEntry.event.ph==='n'){startState=eventStateEntry;endState=eventStateEntry;}else if(eventStateEntry.event.ph==='b'){if(eventStateEntry.end===undefined){eventStateEntry.end=eventStateEntries[eventStateEntries.length-1];sliceError='Slice has no matching END. End time has been adjusted.';this.model_.importWarning({type:'async_slice_parse_error',message:'Nestable  [...]
+eventStateEntry.event.ts+' with name='+
+eventStateEntry.event.name+' and id='+eventStateEntry.event.id+' was unmatched.'});}else{var concatenateArguments=function(args1,args2){if(args1.params===undefined||args2.params===undefined)
+return tr.b.concatenateObjects(args1,args2);var args3={};args3.params=tr.b.concatenateObjects(args1.params,args2.params);return tr.b.concatenateObjects(args1,args2,args3);}
+var endArgs=eventStateEntry.end.event.args||{};sliceArgs=concatenateArguments(sliceArgs,endArgs);}
+startState=eventStateEntry;endState=eventStateEntry.end;}else{sliceError='Slice has no matching BEGIN. Start time has been adjusted.';this.model_.importWarning({type:'async_slice_parse_error',message:'Nestable async END event at '+
+eventStateEntry.event.ts+' with name='+
+eventStateEntry.event.name+' and id='+eventStateEntry.event.id+' was unmatched.'});startState=eventStateEntries[0];endState=eventStateEntry;}
+var isTopLevel=(eventStateEntry.parentEntry===undefined);var asyncSliceConstructor=tr.model.AsyncSlice.getConstructor(eventStateEntry.event.cat,eventStateEntry.event.name);var thread_start=undefined;var thread_duration=undefined;if(startState.event.tts&&startState.event.use_async_tts){thread_start=timestampFromUs(startState.event.tts);if(endState.event.tts){var thread_end=timestampFromUs(endState.event.tts);thread_duration=thread_end-thread_start;}}
+var slice=new asyncSliceConstructor(eventStateEntry.event.cat,eventStateEntry.event.name,tr.ui.b.getColorIdForGeneralPurposeString(eventStateEntry.event.name),timestampFromUs(startState.event.ts),sliceArgs,timestampFromUs(endState.event.ts-startState.event.ts),isTopLevel,thread_start,thread_duration,startState.event.argsStripped);slice.startThread=startState.thread;slice.endThread=endState.thread;slice.id=key;if(sliceError!==undefined)
+slice.error=sliceError;eventStateEntry.slice=slice;if(isTopLevel){topLevelSlices.push(slice);}else if(eventStateEntry.parentEntry.slice!==undefined){eventStateEntry.parentEntry.slice.subSlices.push(slice);}}
+for(var si=0;si<topLevelSlices.length;si++){topLevelSlices[si].startThread.asyncSliceGroup.push(topLevelSlices[si]);}}},createLegacyAsyncSlices_:function(legacyEvents){if(legacyEvents.length===0)
+return;legacyEvents.sort(function(x,y){var d=x.event.ts-y.event.ts;if(d!=0)
+return d;return x.sequenceNumber-y.sequenceNumber;});var asyncEventStatesByNameThenID={};for(var i=0;i<legacyEvents.length;i++){var asyncEventState=legacyEvents[i];var event=asyncEventState.event;var name=event.name;if(name===undefined){this.model_.importWarning({type:'async_slice_parse_error',message:'Async events (ph: S, T, p, or F) require a name '+' parameter.'});continue;}
+var id=event.id;if(id===undefined){this.model_.importWarning({type:'async_slice_parse_error',message:'Async events (ph: S, T, p, or F) require an id parameter.'});continue;}
+if(event.ph==='S'){if(asyncEventStatesByNameThenID[name]===undefined)
+asyncEventStatesByNameThenID[name]={};if(asyncEventStatesByNameThenID[name][id]){this.model_.importWarning({type:'async_slice_parse_error',message:'At '+event.ts+', a slice of the same id '+id+' was alrady open.'});continue;}
+asyncEventStatesByNameThenID[name][id]=[];asyncEventStatesByNameThenID[name][id].push(asyncEventState);}else{if(asyncEventStatesByNameThenID[name]===undefined){this.model_.importWarning({type:'async_slice_parse_error',message:'At '+event.ts+', no slice named '+name+' was open.'});continue;}
+if(asyncEventStatesByNameThenID[name][id]===undefined){this.model_.importWarning({type:'async_slice_parse_error',message:'At '+event.ts+', no slice named '+name+' with id='+id+' was open.'});continue;}
+var events=asyncEventStatesByNameThenID[name][id];events.push(asyncEventState);if(event.ph==='F'){var asyncSliceConstructor=tr.model.AsyncSlice.getConstructor(events[0].event.cat,name);var slice=new asyncSliceConstructor(events[0].event.cat,name,tr.ui.b.getColorIdForGeneralPurposeString(name),timestampFromUs(events[0].event.ts),tr.b.concatenateObjects(events[0].event.args,events[events.length-1].event.args),timestampFromUs(event.ts-events[0].event.ts),true,undefined,undefined,events[0].e [...]
+break;}
+if(events[j].event.ph==='S'){this.model_.importWarning({type:'async_slice_parse_error',message:'At '+event.event.ts+', a slice named '+
+event.event.name+' with id='+event.event.id+' had a step before the start event.'});continue;}
+if(events[j].event.ph==='F'){this.model_.importWarning({type:'async_slice_parse_error',message:'At '+event.event.ts+', a slice named '+
+event.event.name+' with id='+event.event.id+' had a step after the finish event.'});continue;}
+var startIndex=j+(stepType==='T'?0:-1);var endIndex=startIndex+1;var subName=events[j].event.name;if(!events[j].event.argsStripped&&(events[j].event.ph==='T'||events[j].event.ph==='p'))
+subName=subName+':'+events[j].event.args.step;var asyncSliceConstructor=tr.model.AsyncSlice.getConstructor(events[0].event.cat,subName);var subSlice=new asyncSliceConstructor(events[0].event.cat,subName,tr.ui.b.getColorIdForGeneralPurposeString(subName+j),timestampFromUs(events[startIndex].event.ts),this.deepCopyIfNeeded_(events[j].event.args),timestampFromUs(events[endIndex].event.ts-events[startIndex].event.ts),undefined,undefined,events[startIndex].event.argsStripped);subSlice.startTh [...]
+if(isValid){slice.startThread.asyncSliceGroup.push(slice);}
+delete asyncEventStatesByNameThenID[name][id];}}}},assertStepTypeMatches_:function(stepType,event){if(stepType!=event.event.ph){this.model_.importWarning({type:'async_slice_parse_error',message:'At '+event.event.ts+', a slice named '+
+event.event.name+' with id='+event.event.id+' had both begin and end steps, which is not allowed.'});return false;}
+return true;},createFlowSlices_:function(){if(this.allFlowEvents_.length===0)
+return;var that=this;function validateFlowEvent(){if(event.name===undefined){that.model_.importWarning({type:'flow_slice_parse_error',message:'Flow events (ph: s, t or f) require a name parameter.'});return false;}
+if(event.id===undefined){that.model_.importWarning({type:'flow_slice_parse_error',message:'Flow events (ph: s, t or f) require an id parameter.'});return false;}
+return true;}
+function createFlowEvent(thread,event,refGuid){var ts=timestampFromUs(event.ts);var startSlice=thread.sliceGroup.findSliceAtTs(ts);if(startSlice===undefined)
+return undefined;var flowEvent=new tr.model.FlowEvent(event.cat,event.id,event.name,tr.ui.b.getColorIdForGeneralPurposeString(event.name),timestampFromUs(event.ts),that.deepCopyIfNeeded_(event.args));flowEvent.startSlice=startSlice;startSlice.outFlowEvents.push(flowEvent);return flowEvent;}
+function finishFlowEventWith(flowEvent,thread,event,refGuid,bindToParent){var endSlice;var ts=timestampFromUs(event.ts);if(bindToParent){endSlice=thread.sliceGroup.findSliceAtTs(ts);}else{endSlice=thread.sliceGroup.findNextSliceAfter(ts,refGuid);}
+if(endSlice===undefined)
+return false;endSlice.inFlowEvents.push(flowEvent);flowEvent.endSlice=endSlice;flowEvent.duration=ts-flowEvent.start;that.mergeArgsInto_(flowEvent.args,event.args,flowEvent.title);return true;}
+this.allFlowEvents_.sort(function(x,y){var d=x.event.ts-y.event.ts;if(d!=0)
+return d;return x.sequenceNumber-y.sequenceNumber;});var flowIdToEvent={};for(var i=0;i<this.allFlowEvents_.length;++i){var data=this.allFlowEvents_[i];var refGuid=data.refGuid;var event=data.event;var thread=data.thread;if(!validateFlowEvent(event))
+continue;var flowEvent;if(event.ph==='s'){if(flowIdToEvent[event.id]){this.model_.importWarning({type:'flow_slice_start_error',message:'event id '+event.id+' already seen when '+'encountering start of flow event.'});continue;}
+flowEvent=createFlowEvent(thread,event,refGuid);if(!flowEvent){this.model_.importWarning({type:'flow_slice_start_error',message:'event id '+event.id+' does not start '+'at an actual slice, so cannot be created.'});continue;}
+flowIdToEvent[event.id]=flowEvent;}else if(event.ph==='t'||event.ph==='f'){flowEvent=flowIdToEvent[event.id];if(flowEvent===undefined){this.model_.importWarning({type:'flow_slice_ordering_error',message:'Found flow phase '+event.ph+' for id: '+event.id+' but no flow start found.'});continue;}
+var bindToParent=event.ph==='t';if(event.ph==='f'){if(event.bp===undefined){if(event.cat.indexOf('input')>-1)
+bindToParent=true;else if(event.cat.indexOf('ipc.flow')>-1)
+bindToParent=true;}else{if(event.bp!=='e'){this.model_.importWarning({type:'flow_slice_bind_point_error',message:'Flow event with invalid binding point (event.bp).'});continue;}
+bindToParent=true;}}
+var ok=finishFlowEventWith(flowEvent,thread,event,refGuid,bindToParent);if(ok){that.model_.flowEvents.push(flowEvent);}else{this.model_.importWarning({type:'flow_slice_start_error',message:'event id '+event.id+' does not end '+'at an actual slice, so cannot be created.'});}
+flowIdToEvent[event.id]=undefined;if(ok&&event.ph==='t'){flowEvent=createFlowEvent(thread,event);flowIdToEvent[event.id]=flowEvent;}}}},createExplicitObjects_:function(){if(this.allObjectEvents_.length==0)
+return;function processEvent(objectEventState){var event=objectEventState.event;var thread=objectEventState.thread;if(event.name===undefined){this.model_.importWarning({type:'object_parse_error',message:'While processing '+JSON.stringify(event)+': '+'Object events require an name parameter.'});}
+if(event.id===undefined){this.model_.importWarning({type:'object_parse_error',message:'While processing '+JSON.stringify(event)+': '+'Object events require an id parameter.'});}
+var process=thread.parent;var ts=timestampFromUs(event.ts);var instance;if(event.ph=='N'){try{instance=process.objects.idWasCreated(event.id,event.cat,event.name,ts);}catch(e){this.model_.importWarning({type:'object_parse_error',message:'While processing create of '+
+event.id+' at ts='+ts+': '+e});return;}}else if(event.ph=='O'){if(event.args.snapshot===undefined){this.model_.importWarning({type:'object_parse_error',message:'While processing '+event.id+' at ts='+ts+': '+'Snapshots must have args: {snapshot: ...}'});return;}
+var snapshot;try{var args=this.deepCopyIfNeeded_(event.args.snapshot);var cat;if(args.cat){cat=args.cat;delete args.cat;}else{cat=event.cat;}
+var baseTypename;if(args.base_type){baseTypename=args.base_type;delete args.base_type;}else{baseTypename=undefined;}
+snapshot=process.objects.addSnapshot(event.id,cat,event.name,ts,args,baseTypename);snapshot.snapshottedOnThread=thread;}catch(e){this.model_.importWarning({type:'object_parse_error',message:'While processing snapshot of '+
+event.id+' at ts='+ts+': '+e});return;}
+instance=snapshot.objectInstance;}else if(event.ph=='D'){try{instance=process.objects.idWasDeleted(event.id,event.cat,event.name,ts);}catch(e){this.model_.importWarning({type:'object_parse_error',message:'While processing delete of '+
+event.id+' at ts='+ts+': '+e});return;}}
+if(instance){instance.colorId=tr.ui.b.getColorIdForGeneralPurposeString(instance.typeName);}}
+this.allObjectEvents_.sort(function(x,y){var d=x.event.ts-y.event.ts;if(d!=0)
+return d;return x.sequenceNumber-y.sequenceNumber;});var allObjectEvents=this.allObjectEvents_;for(var i=0;i<allObjectEvents.length;i++){var objectEventState=allObjectEvents[i];try{processEvent.call(this,objectEventState);}catch(e){this.model_.importWarning({type:'object_parse_error',message:e.message});}}},createImplicitObjects_:function(){tr.b.iterItems(this.model_.processes,function(pid,process){this.createImplicitObjectsForProcess_(process);},this);},createImplicitObjectsForProcess_: [...]
+return;if(referencingObjectFieldValue instanceof
+tr.model.ObjectSnapshot)
+return null;if(referencingObjectFieldValue.id===undefined)
+return;var implicitSnapshot=referencingObjectFieldValue;var rawId=implicitSnapshot.id;var m=/(.+)\/(.+)/.exec(rawId);if(!m)
+throw new Error('Implicit snapshots must have names.');delete implicitSnapshot.id;var name=m[1];var id=m[2];var res;var cat;if(implicitSnapshot.cat!==undefined)
+cat=implicitSnapshot.cat;else
+cat=containingSnapshot.objectInstance.category;var baseTypename;if(implicitSnapshot.base_type)
+baseTypename=implicitSnapshot.base_type;else
+baseTypename=undefined;try{res=process.objects.addSnapshot(id,cat,name,containingSnapshot.ts,implicitSnapshot,baseTypename);}catch(e){this.model_.importWarning({type:'object_snapshot_parse_error',message:'While processing implicit snapshot of '+
+rawId+' at ts='+containingSnapshot.ts+': '+e});return;}
+res.objectInstance.hasImplicitSnapshots=true;res.containingSnapshot=containingSnapshot;res.snapshottedOnThread=containingSnapshot.snapshottedOnThread;referencingObject[referencingObjectFieldName]=res;if(!(res instanceof tr.model.ObjectSnapshot))
+throw new Error('Created object must be instanceof snapshot');return res.args;}
+function iterObject(object,func,containingSnapshot,thisArg){if(!(object instanceof Object))
+return;if(object instanceof Array){for(var i=0;i<object.length;i++){var res=func.call(thisArg,object,i,object[i],containingSnapshot);if(res===null)
+continue;if(res)
+iterObject(res,func,containingSnapshot,thisArg);else
+iterObject(object[i],func,containingSnapshot,thisArg);}
+return;}
+for(var key in object){var res=func.call(thisArg,object,key,object[key],containingSnapshot);if(res===null)
+continue;if(res)
+iterObject(res,func,containingSnapshot,thisArg);else
+iterObject(object[key],func,containingSnapshot,thisArg);}}
+process.objects.iterObjectInstances(function(instance){instance.snapshots.forEach(function(snapshot){if(snapshot.args.id!==undefined)
+throw new Error('args cannot have an id field inside it');iterObject(snapshot.args,processField,snapshot,this);},this);},this);},createMemoryDumps_:function(){tr.b.iterItems(this.allMemoryDumpEvents_,function(id,events){var range=new tr.b.Range();if(events.global!==undefined)
+range.addValue(timestampFromUs(events.global.ts));for(var i=0;i<events.process.length;i++)
+range.addValue(timestampFromUs(events.process[i].ts));var globalMemoryDump=new tr.model.GlobalMemoryDump(this.model_,range.min);globalMemoryDump.duration=range.range;this.model_.globalMemoryDumps.push(globalMemoryDump);if(events.process.length===0){this.model_.importWarning({type:'memory_dump_parse_error',message:'No process memory dumps associated with global memory'+' dump '+id+'.'});}
+var allMemoryAllocatorDumpsByGuid={};var globalMemoryAllocatorDumpsByFullName={};events.process.forEach(function(processEvent){var pid=processEvent.pid;if(pid in globalMemoryDump.processMemoryDumps){this.model_.importWarning({type:'memory_dump_parse_error',message:'Multiple process memory dumps with pid='+pid+' for dump id '+id+'.'});return;}
+var dumps=processEvent.args.dumps;if(dumps===undefined){this.model_.importWarning({type:'memory_dump_parse_error',message:'dumps not found in process memory dump for '+'pid='+pid+' and dump id='+id+'.'});return;}
+var process=this.model_.getOrCreateProcess(pid);var processMemoryDump=new tr.model.ProcessMemoryDump(globalMemoryDump,process,timestampFromUs(processEvent.ts));if(dumps.process_totals===undefined||dumps.process_totals.resident_set_bytes===undefined){this.model_.importWarning({type:'memory_dump_parse_error',message:'Mandatory field resident_set_bytes not found in'+' process memory dump for pid='+pid+' and dump id='+id+'.'});processMemoryDump.totalResidentBytes=undefined;}else{processMemor [...]
+if(dumps.process_mmaps&&dumps.process_mmaps.vm_regions){function parseByteStat(rawValue){if(rawValue===undefined)
+return undefined;return parseInt(rawValue,16);}
+processMemoryDump.vmRegions=dumps.process_mmaps.vm_regions.map(function(rawRegion){var byteStats=new tr.model.VMRegionByteStats(parseByteStat(rawRegion.bs.pc),parseByteStat(rawRegion.bs.pd),parseByteStat(rawRegion.bs.sc),parseByteStat(rawRegion.bs.sd),parseByteStat(rawRegion.bs.pss),parseByteStat(rawRegion.bs.sw));return new tr.model.VMRegion(parseInt(rawRegion.sa,16),parseInt(rawRegion.sz,16),rawRegion.pf,rawRegion.mf,byteStats);});}
+var processMemoryAllocatorDumpsByFullName={};if(dumps.allocators!==undefined){tr.b.iterItems(dumps.allocators,function(fullName,rawAllocatorDump){var guid=rawAllocatorDump.guid;if(guid===undefined){this.model_.importWarning({type:'memory_dump_parse_error',message:'Memory allocator dump '+fullName+' from pid='+pid+' does not have a GUID.'});}
+var GLOBAL_MEMORY_ALLOCATOR_DUMP_PREFIX='global/';var containerMemoryDump;var dstIndex;if(fullName.startsWith(GLOBAL_MEMORY_ALLOCATOR_DUMP_PREFIX)){fullName=fullName.substring(GLOBAL_MEMORY_ALLOCATOR_DUMP_PREFIX.length);containerMemoryDump=globalMemoryDump;dstIndex=globalMemoryAllocatorDumpsByFullName;}else{containerMemoryDump=processMemoryDump;dstIndex=processMemoryAllocatorDumpsByFullName;}
+var allocatorDump=allMemoryAllocatorDumpsByGuid[guid];if(allocatorDump===undefined){if(fullName in dstIndex){this.model_.importWarning({type:'memory_dump_parse_error',message:'Multiple GUIDs provided for'+' memory allocator dump '+fullName+': '+
+dstIndex[fullName].guid+', '+guid+' (ignored).'});return;}
+allocatorDump=new tr.model.MemoryAllocatorDump(containerMemoryDump,fullName,guid);dstIndex[fullName]=allocatorDump;if(guid!==undefined)
+allMemoryAllocatorDumpsByGuid[guid]=allocatorDump;}else{if(allocatorDump.containerMemoryDump!==containerMemoryDump){this.model_.importWarning({type:'memory_dump_parse_error',message:'Memory allocator dump '+fullName+' (GUID='+guid+') dumped in different contexts.'});return;}
+if(allocatorDump.fullName!==fullName){this.model_.importWarning({type:'memory_dump_parse_error',message:'Memory allocator dump with GUID='+guid+' has multiple names: '+allocatorDump.fullName+', '+fullName+' (ignored).'});return;}}
+var attributes=rawAllocatorDump.attrs;tr.b.iterItems(attributes,function(attrName,attrArgs){if(attrName in allocatorDump.attributes){this.model_.importWarning({type:'memory_dump_parse_error',message:'Multiple values provided for attribute '+
+attrName+' of memory allocator dump '+fullName+' (GUID='+guid+').'});return;}
+var attrValue=tr.model.Attribute.fromDictIfPossible(attrArgs);allocatorDump.addAttribute(attrName,attrValue);},this);},this);}
+processMemoryDump.memoryAllocatorDumps=this.inferMemoryAllocatorDumpTree_(processMemoryAllocatorDumpsByFullName);process.memoryDumps.push(processMemoryDump);globalMemoryDump.processMemoryDumps[pid]=processMemoryDump;},this);globalMemoryDump.memoryAllocatorDumps=this.inferMemoryAllocatorDumpTree_(globalMemoryAllocatorDumpsByFullName);events.process.forEach(function(processEvent){var dumps=processEvent.args.dumps;if(dumps===undefined)
+return;var edges=dumps.allocators_graph;if(edges===undefined)
+return;edges.forEach(function(rawEdge){var sourceGuid=rawEdge.source;var sourceDump=allMemoryAllocatorDumpsByGuid[sourceGuid];if(sourceDump===undefined){this.model_.importWarning({type:'memory_dump_parse_error',message:'Edge is missing source memory allocator dump (GUID='+
+sourceGuid+')'});return;}
+var targetGuid=rawEdge.target;var targetDump=allMemoryAllocatorDumpsByGuid[targetGuid];if(targetDump===undefined){this.model_.importWarning({type:'memory_dump_parse_error',message:'Edge is missing target memory allocator dump (GUID='+
+targetGuid+')'});return;}
+var importance=rawEdge.importance;var edge=new tr.model.MemoryAllocatorDumpLink(sourceDump,targetDump,importance);switch(rawEdge.type){case'ownership':if(sourceDump.owns!==undefined){this.model_.importWarning({type:'memory_dump_parse_error',message:'Memory allocator dump '+sourceDump.fullName+' (GUID='+sourceGuid+') already owns a memory'+' allocator dump ('+
+sourceDump.owns.target.fullName+').'});return;}
+sourceDump.owns=edge;targetDump.ownedBy.push(edge);break;case'retention':sourceDump.retains.push(edge);targetDump.retainedBy.push(edge);break;default:this.model_.importWarning({type:'memory_dump_parse_error',message:'Invalid edge type: '+rawEdge.type+' (source='+sourceGuid+', target='+targetGuid+', importance='+importance+').'});}},this);},this);},this);},inferMemoryAllocatorDumpTree_:function(memoryAllocatorDumpsByFullName){var rootAllocatorDumps=[];var fullNames=Object.keys(memoryAlloc [...]
+var parentFullName=fullName.substring(0,lastSlashIndex);var parentAllocatorDump=memoryAllocatorDumpsByFullName[parentFullName];var parentAlreadyExisted=true;if(parentAllocatorDump===undefined){parentAlreadyExisted=false;parentAllocatorDump=new tr.model.MemoryAllocatorDump(allocatorDump.containerMemoryDump,parentFullName);memoryAllocatorDumpsByFullName[parentFullName]=parentAllocatorDump;}
+allocatorDump.parent=parentAllocatorDump;parentAllocatorDump.children.push(allocatorDump);if(parentAlreadyExisted)
+break;fullName=parentFullName;allocatorDump=parentAllocatorDump;}},this);return rootAllocatorDumps;},joinObjectRefs_:function(){tr.b.iterItems(this.model_.processes,function(pid,process){this.joinObjectRefsForProcess_(process);},this);},joinObjectRefsForProcess_:function(process){var patchupsToApply=[];tr.b.iterItems(process.threads,function(tid,thread){thread.asyncSliceGroup.slices.forEach(function(item){this.searchItemForIDRefs_(patchupsToApply,process.objects,'start',item);},this);thr [...]
+throw new Error('item is missing its args');function handleField(object,fieldName,fieldValue){if(!fieldValue||(!fieldValue.id_ref&&!fieldValue.idRef))
+return;var id=fieldValue.id_ref||fieldValue.idRef;var ts=item[itemTimestampField];var snapshot=objectCollection.getSnapshotAt(id,ts);if(!snapshot)
+return;patchupsToApply.push({object:object,field:fieldName,value:snapshot});}
+function iterObjectFieldsRecursively(object){if(!(object instanceof Object))
+return;if((object instanceof tr.model.ObjectSnapshot)||(object instanceof Float32Array)||(object instanceof tr.b.Quad))
+return;if(object instanceof Array){for(var i=0;i<object.length;i++){handleField(object,i,object[i]);iterObjectFieldsRecursively(object[i]);}
+return;}
+for(var key in object){var value=object[key];handleField(object,key,value);iterObjectFieldsRecursively(value);}}
+iterObjectFieldsRecursively(item.args);}};tr.importer.Importer.register(TraceEventImporter);return{TraceEventImporter:TraceEventImporter};});'use strict';tr.exportTo('tr.ui.e.highlighter',function(){var Highlighter=tr.ui.tracks.Highlighter;function VSyncHighlighter(viewport){Highlighter.call(this,viewport);this.times_=[];}
+VSyncHighlighter.VSYNC_HIGHLIGHT_COLOR={r:0,g:0,b:255};VSyncHighlighter.VSYNC_HIGHLIGHT_ALPHA=0.1;VSyncHighlighter.VSYNC_DENSITY_TRANSPARENT=0.20;VSyncHighlighter.VSYNC_DENSITY_OPAQUE=0.10;VSyncHighlighter.VSYNC_DENSITY_RANGE=VSyncHighlighter.VSYNC_DENSITY_TRANSPARENT-
+VSyncHighlighter.VSYNC_DENSITY_OPAQUE;VSyncHighlighter.VSYNC_COUNTER_PRECISIONS={'android.VSYNC-app':15,'android.VSYNC':15};VSyncHighlighter.VSYNC_SLICE_PRECISIONS={'RenderWidgetHostViewAndroid::OnVSync':5,'VSYNC':10,'vblank':10,'DisplayLinkMac::GetVSyncParameters':5};VSyncHighlighter.findVSyncTimes=function(model){var times=[];var maxPrecision=Number.NEGATIVE_INFINITY;var maxTitle=undefined;var useInstead=function(title,precisions){if(title!=maxTitle){var precision=precisions[title];if( [...]
+maxTitle+', '+title+') with the same precision, '+'ignoring the newer one ('+title+')');}
+return false;}
+maxPrecision=precision;maxTitle=title;times=[];}
+return true;}
+for(var pid in model.processes){var process=model.processes[pid];for(var cid in process.counters){if(useInstead(cid,VSyncHighlighter.VSYNC_COUNTER_PRECISIONS)){var counter=process.counters[cid];for(var i=0;i<counter.series.length;i++){var series=counter.series[i];Array.prototype.push.apply(times,series.timestamps);}}}
+for(var tid in process.threads){var thread=process.threads[tid];for(var i=0;i<thread.sliceGroup.slices.length;i++){var slice=thread.sliceGroup.slices[i];if(useInstead(slice.title,VSyncHighlighter.VSYNC_SLICE_PRECISIONS)){times.push(slice.start);}}}}
+times.sort(function(x,y){return x-y;});return times;};VSyncHighlighter.generateStripes=function(times,minTime,maxTime){var stripes=[];var lowIndex=tr.b.findLowIndexInSortedArray(times,function(time){return time;},minTime);if(lowIndex>times.length){lowIndex=times.length;}
+var highIndex=lowIndex-1;while(times[highIndex+1]<=maxTime){highIndex++;}
+for(var i=lowIndex-(lowIndex%2);i<=highIndex;i+=2){var left=i<lowIndex?minTime:times[i];var right=i+1>highIndex?maxTime:times[i+1];stripes.push([left,right]);}
+return stripes;}
+VSyncHighlighter.prototype={__proto__:Highlighter.prototype,processModel:function(model){this.times_=VSyncHighlighter.findVSyncTimes(model);},drawHighlight:function(ctx,dt,viewLWorld,viewRWorld,viewHeight){if(!this.viewport_.highlightVSync){return;}
+var stripes=VSyncHighlighter.generateStripes(this.times_,viewLWorld,viewRWorld);if(stripes.length==0){return;}
+var stripeRange=stripes[stripes.length-1][1]-stripes[0][0];var stripeDensity=stripes.length/(dt.scaleX*stripeRange);var clampedStripeDensity=tr.b.clamp(stripeDensity,VSyncHighlighter.VSYNC_DENSITY_OPAQUE,VSyncHighlighter.VSYNC_DENSITY_TRANSPARENT);var opacity=(VSyncHighlighter.VSYNC_DENSITY_TRANSPARENT-clampedStripeDensity)/VSyncHighlighter.VSYNC_DENSITY_RANGE;if(opacity==0){return;}
+var pixelRatio=window.devicePixelRatio||1;var height=viewHeight*pixelRatio;ctx.fillStyle=tr.ui.b.colorToRGBAString(VSyncHighlighter.VSYNC_HIGHLIGHT_COLOR,VSyncHighlighter.VSYNC_HIGHLIGHT_ALPHA*opacity);for(var i=0;i<stripes.length;i++){var xLeftView=dt.xWorldToView(stripes[i][0]);var xRightView=dt.xWorldToView(stripes[i][1]);ctx.fillRect(xLeftView,0,xRightView-xLeftView,height);}}};tr.ui.tracks.Highlighter.register(VSyncHighlighter);return{VSyncHighlighter:VSyncHighlighter};});
+</script>
+</head>
+  <body>
+  </body>
+</html>
diff --git a/src/androidtest.bash b/src/androidtest.bash
index 504d276..0010738 100755
--- a/src/androidtest.bash
+++ b/src/androidtest.bash
@@ -11,7 +11,7 @@ set -e
 ulimit -c 0 # no core files
 
 if [ ! -f make.bash ]; then
-	echo 'nacl.bash must be run from $GOROOT/src' 1>&2
+	echo 'androidtest.bash must be run from $GOROOT/src' 1>&2
 	exit 1
 fi
 
@@ -24,32 +24,53 @@ if [ "$GOOS" != "android" ]; then
 fi
 
 export CGO_ENABLED=1
+unset GOBIN
 
-# Run the build for the host bootstrap, so we can build go_android_exec.
+# Do the build first, so we can build go_android_exec and cleaner.
 # Also lets us fail early before the (slow) adb push if the build is broken.
-./make.bash
+. ./make.bash --no-banner
 export GOROOT=$(dirname $(pwd))
 export PATH=$GOROOT/bin:$PATH
 GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH go build \
 	-o ../bin/go_android_${GOARCH}_exec \
 	../misc/android/go_android_exec.go
 
+export ANDROID_TEST_DIR=/tmp/androidtest-$$
+
+function cleanup() {
+	rm -rf ${ANDROID_TEST_DIR}
+}
+trap cleanup EXIT
+
 # Push GOROOT to target device.
 #
 # The adb sync command will sync either the /system or /data
 # directories of an android device from a similar directory
-# on the host. So we fake one with symlinks to push the GOROOT
-# into a subdirectory of /data.
-export ANDROID_PRODUCT_OUT=/tmp/androidtest-$$
+# on the host. We copy the files required for running tests under
+# /data/local/tmp/goroot. The adb sync command does not follow
+# symlinks so we have to copy.
+export ANDROID_PRODUCT_OUT="${ANDROID_TEST_DIR}/out"
 FAKE_GOROOT=$ANDROID_PRODUCT_OUT/data/local/tmp/goroot
 mkdir -p $FAKE_GOROOT
-ln -s $GOROOT/src $FAKE_GOROOT/src
-ln -s $GOROOT/test $FAKE_GOROOT/test
-ln -s $GOROOT/lib $FAKE_GOROOT/lib
+mkdir -p $FAKE_GOROOT/pkg
+cp -a "${GOROOT}/src" "${FAKE_GOROOT}/"
+cp -a "${GOROOT}/test" "${FAKE_GOROOT}/"
+cp -a "${GOROOT}/lib" "${FAKE_GOROOT}/"
+cp -a "${GOROOT}/pkg/android_$GOARCH" "${FAKE_GOROOT}/pkg/"
 echo '# Syncing test files to android device'
+adb shell mkdir -p /data/local/tmp/goroot
 time adb sync data &> /dev/null
+
+export CLEANER=${ANDROID_TEST_DIR}/androidcleaner-$$
+cp ../misc/android/cleaner.go $CLEANER.go
+echo 'var files = `' >> $CLEANER.go
+(cd $ANDROID_PRODUCT_OUT/data/local/tmp/goroot; find . >> $CLEANER.go)
+echo '`' >> $CLEANER.go
+go build -o $CLEANER $CLEANER.go
+adb push $CLEANER /data/local/tmp/cleaner
+adb shell /data/local/tmp/cleaner
+
 echo ''
-rm -rf "$ANDROID_PRODUCT_OUT"
 
-# Run standard build and tests.
-./all.bash --no-clean
+# Run standard tests.
+bash run.bash --no-rebuild
diff --git a/src/archive/tar/common.go b/src/archive/tar/common.go
index e363aa7..c31df06 100644
--- a/src/archive/tar/common.go
+++ b/src/archive/tar/common.go
@@ -139,8 +139,8 @@ func (fi headerFileInfo) Mode() (mode os.FileMode) {
 	}
 
 	switch fi.h.Typeflag {
-	case TypeLink, TypeSymlink:
-		// hard link, symbolic link
+	case TypeSymlink:
+		// symbolic link
 		mode |= os.ModeSymlink
 	case TypeChar:
 		// character device node
@@ -249,6 +249,30 @@ func FileInfoHeader(fi os.FileInfo, link string) (*Header, error) {
 	if fm&os.ModeSticky != 0 {
 		h.Mode |= c_ISVTX
 	}
+	// If possible, populate additional fields from OS-specific
+	// FileInfo fields.
+	if sys, ok := fi.Sys().(*Header); ok {
+		// This FileInfo came from a Header (not the OS). Use the
+		// original Header to populate all remaining fields.
+		h.Uid = sys.Uid
+		h.Gid = sys.Gid
+		h.Uname = sys.Uname
+		h.Gname = sys.Gname
+		h.AccessTime = sys.AccessTime
+		h.ChangeTime = sys.ChangeTime
+		if sys.Xattrs != nil {
+			h.Xattrs = make(map[string]string)
+			for k, v := range sys.Xattrs {
+				h.Xattrs[k] = v
+			}
+		}
+		if sys.Typeflag == TypeLink {
+			// hard link
+			h.Typeflag = TypeLink
+			h.Size = 0
+			h.Linkname = sys.Linkname
+		}
+	}
 	if sysStat != nil {
 		return h, sysStat(fi, h)
 	}
diff --git a/src/archive/tar/example_test.go b/src/archive/tar/example_test.go
index 351eaa0..2317f44 100644
--- a/src/archive/tar/example_test.go
+++ b/src/archive/tar/example_test.go
@@ -31,6 +31,7 @@ func Example() {
 	for _, file := range files {
 		hdr := &tar.Header{
 			Name: file.Name,
+			Mode: 0600,
 			Size: int64(len(file.Body)),
 		}
 		if err := tw.WriteHeader(hdr); err != nil {
diff --git a/src/archive/tar/reader.go b/src/archive/tar/reader.go
index a27559d..67daca2 100644
--- a/src/archive/tar/reader.go
+++ b/src/archive/tar/reader.go
@@ -85,6 +85,8 @@ const (
 func NewReader(r io.Reader) *Reader { return &Reader{r: r} }
 
 // Next advances to the next entry in the tar archive.
+//
+// io.EOF is returned at the end of the input.
 func (tr *Reader) Next() (*Header, error) {
 	var hdr *Header
 	if tr.err == nil {
@@ -108,7 +110,13 @@ func (tr *Reader) Next() (*Header, error) {
 		// We actually read the whole file,
 		// but this skips alignment padding
 		tr.skipUnread()
+		if tr.err != nil {
+			return nil, tr.err
+		}
 		hdr = tr.readHeader()
+		if hdr == nil {
+			return nil, tr.err
+		}
 		mergePAX(hdr, headers)
 
 		// Check for a PAX format sparse file
@@ -331,7 +339,7 @@ func parsePAX(r io.Reader) (map[string]string, error) {
 		}
 		// Parse the first token as a decimal integer.
 		n, err := strconv.ParseInt(string(buf[:sp]), 10, 0)
-		if err != nil {
+		if err != nil || n < 5 || int64(len(buf)) < n {
 			return nil, ErrHeader
 		}
 		// Extract everything between the decimal and the n -1 on the
@@ -461,6 +469,10 @@ func (tr *Reader) readHeader() *Header {
 	hdr.Uid = int(tr.octal(s.next(8)))
 	hdr.Gid = int(tr.octal(s.next(8)))
 	hdr.Size = tr.octal(s.next(12))
+	if hdr.Size < 0 {
+		tr.err = ErrHeader
+		return nil
+	}
 	hdr.ModTime = time.Unix(tr.octal(s.next(12)), 0)
 	s.next(8) // chksum
 	hdr.Typeflag = s.next(1)[0]
@@ -785,6 +797,9 @@ func (sfr *sparseFileReader) Read(b []byte) (n int, err error) {
 		// Otherwise, we're at the end of the file
 		return 0, io.EOF
 	}
+	if sfr.tot < sfr.sp[0].offset {
+		return 0, io.ErrUnexpectedEOF
+	}
 	if sfr.pos < sfr.sp[0].offset {
 		// We're in a hole
 		n = sfr.readHole(b, sfr.sp[0].offset)
diff --git a/src/archive/tar/reader_test.go b/src/archive/tar/reader_test.go
index 9601ffe..da01f26 100644
--- a/src/archive/tar/reader_test.go
+++ b/src/archive/tar/reader_test.go
@@ -462,9 +462,14 @@ func TestParsePAXHeader(t *testing.T) {
 			t.Error("Buffer wasn't consumed")
 		}
 	}
-	badHeader := bytes.NewReader([]byte("3 somelongkey="))
-	if _, err := parsePAX(badHeader); err != ErrHeader {
-		t.Fatal("Unexpected success when parsing bad header")
+	badHeaderTests := [][]byte{
+		[]byte("3 somelongkey=\n"),
+		[]byte("50 tooshort=\n"),
+	}
+	for _, test := range badHeaderTests {
+		if _, err := parsePAX(bytes.NewReader(test)); err != ErrHeader {
+			t.Fatal("Unexpected success when parsing bad header")
+		}
 	}
 }
 
@@ -741,3 +746,53 @@ func TestUninitializedRead(t *testing.T) {
 	}
 
 }
+
+// Negative header size should not cause panic.
+// Issues 10959 and 10960.
+func TestNegativeHdrSize(t *testing.T) {
+	f, err := os.Open("testdata/neg-size.tar")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer f.Close()
+	r := NewReader(f)
+	_, err = r.Next()
+	if err != ErrHeader {
+		t.Error("want ErrHeader, got", err)
+	}
+	io.Copy(ioutil.Discard, r)
+}
+
+// This used to hang in (*sparseFileReader).readHole due to missing
+// verification of sparse offsets against file size.
+func TestIssue10968(t *testing.T) {
+	f, err := os.Open("testdata/issue10968.tar")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer f.Close()
+	r := NewReader(f)
+	_, err = r.Next()
+	if err != nil {
+		t.Fatal(err)
+	}
+	_, err = io.Copy(ioutil.Discard, r)
+	if err != io.ErrUnexpectedEOF {
+		t.Fatalf("expected %q, got %q", io.ErrUnexpectedEOF, err)
+	}
+}
+
+// Do not panic if there are errors in header blocks after the pax header.
+// Issue 11169
+func TestIssue11169(t *testing.T) {
+	f, err := os.Open("testdata/issue11169.tar")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer f.Close()
+	r := NewReader(f)
+	_, err = r.Next()
+	if err == nil {
+		t.Fatal("Unexpected success")
+	}
+}
diff --git a/src/archive/tar/tar_test.go b/src/archive/tar/tar_test.go
index ed333f3..d63c072 100644
--- a/src/archive/tar/tar_test.go
+++ b/src/archive/tar/tar_test.go
@@ -147,17 +147,6 @@ func TestHeaderRoundTrip(t *testing.T) {
 			},
 			fm: 0644,
 		},
-		// hard link.
-		{
-			h: &Header{
-				Name:     "hard.txt",
-				Mode:     0644 | c_ISLNK,
-				Size:     0,
-				ModTime:  time.Unix(1360600916, 0),
-				Typeflag: TypeLink,
-			},
-			fm: 0644 | os.ModeSymlink,
-		},
 		// symbolic link.
 		{
 			h: &Header{
@@ -246,6 +235,33 @@ func TestHeaderRoundTrip(t *testing.T) {
 			},
 			fm: 0600 | os.ModeSticky,
 		},
+		// hard link.
+		{
+			h: &Header{
+				Name:     "hard.txt",
+				Mode:     0644 | c_ISREG,
+				Size:     0,
+				Linkname: "file.txt",
+				ModTime:  time.Unix(1360600916, 0),
+				Typeflag: TypeLink,
+			},
+			fm: 0644,
+		},
+		// More information.
+		{
+			h: &Header{
+				Name:     "info.txt",
+				Mode:     0600 | c_ISREG,
+				Size:     0,
+				Uid:      1000,
+				Gid:      1000,
+				ModTime:  time.Unix(1360602540, 0),
+				Uname:    "slartibartfast",
+				Gname:    "users",
+				Typeflag: TypeReg,
+			},
+			fm: 0600,
+		},
 	}
 
 	for i, g := range golden {
@@ -268,12 +284,37 @@ func TestHeaderRoundTrip(t *testing.T) {
 		if got, want := h2.Size, g.h.Size; got != want {
 			t.Errorf("i=%d: Size: got %v, want %v", i, got, want)
 		}
+		if got, want := h2.Uid, g.h.Uid; got != want {
+			t.Errorf("i=%d: Uid: got %d, want %d", i, got, want)
+		}
+		if got, want := h2.Gid, g.h.Gid; got != want {
+			t.Errorf("i=%d: Gid: got %d, want %d", i, got, want)
+		}
+		if got, want := h2.Uname, g.h.Uname; got != want {
+			t.Errorf("i=%d: Uname: got %q, want %q", i, got, want)
+		}
+		if got, want := h2.Gname, g.h.Gname; got != want {
+			t.Errorf("i=%d: Gname: got %q, want %q", i, got, want)
+		}
+		if got, want := h2.Linkname, g.h.Linkname; got != want {
+			t.Errorf("i=%d: Linkname: got %v, want %v", i, got, want)
+		}
+		if got, want := h2.Typeflag, g.h.Typeflag; got != want {
+			t.Logf("%#v %#v", g.h, fi.Sys())
+			t.Errorf("i=%d: Typeflag: got %q, want %q", i, got, want)
+		}
 		if got, want := h2.Mode, g.h.Mode; got != want {
 			t.Errorf("i=%d: Mode: got %o, want %o", i, got, want)
 		}
 		if got, want := fi.Mode(), g.fm; got != want {
 			t.Errorf("i=%d: fi.Mode: got %o, want %o", i, got, want)
 		}
+		if got, want := h2.AccessTime, g.h.AccessTime; got != want {
+			t.Errorf("i=%d: AccessTime: got %v, want %v", i, got, want)
+		}
+		if got, want := h2.ChangeTime, g.h.ChangeTime; got != want {
+			t.Errorf("i=%d: ChangeTime: got %v, want %v", i, got, want)
+		}
 		if got, want := h2.ModTime, g.h.ModTime; got != want {
 			t.Errorf("i=%d: ModTime: got %v, want %v", i, got, want)
 		}
diff --git a/src/archive/tar/testdata/hardlink.tar b/src/archive/tar/testdata/hardlink.tar
new file mode 100644
index 0000000..9cd1a26
Binary files /dev/null and b/src/archive/tar/testdata/hardlink.tar differ
diff --git a/src/archive/tar/testdata/issue10968.tar b/src/archive/tar/testdata/issue10968.tar
new file mode 100644
index 0000000..1cc837b
Binary files /dev/null and b/src/archive/tar/testdata/issue10968.tar differ
diff --git a/src/archive/tar/testdata/issue11169.tar b/src/archive/tar/testdata/issue11169.tar
new file mode 100644
index 0000000..4d71fa1
Binary files /dev/null and b/src/archive/tar/testdata/issue11169.tar differ
diff --git a/src/archive/tar/testdata/neg-size.tar b/src/archive/tar/testdata/neg-size.tar
new file mode 100644
index 0000000..5deea3d
Binary files /dev/null and b/src/archive/tar/testdata/neg-size.tar differ
diff --git a/src/archive/tar/writer.go b/src/archive/tar/writer.go
index dafb2ca..9dbc01a 100644
--- a/src/archive/tar/writer.go
+++ b/src/archive/tar/writer.go
@@ -355,7 +355,7 @@ func paxHeader(msg string) string {
 // hdr.Size bytes are written after WriteHeader.
 func (tw *Writer) Write(b []byte) (n int, err error) {
 	if tw.closed {
-		err = ErrWriteTooLong
+		err = ErrWriteAfterClose
 		return
 	}
 	overwrite := false
diff --git a/src/archive/tar/writer_test.go b/src/archive/tar/writer_test.go
index 5e42e32..fe46a67 100644
--- a/src/archive/tar/writer_test.go
+++ b/src/archive/tar/writer_test.go
@@ -147,6 +147,44 @@ var writerTests = []*writerTest{
 			},
 		},
 	},
+	// This file was produced using gnu tar 1.26
+	// echo "Slartibartfast" > file.txt
+	// ln file.txt hard.txt
+	// tar -b 1 --format=ustar -c -f hardlink.tar file.txt hard.txt
+	{
+		file: "testdata/hardlink.tar",
+		entries: []*writerTestEntry{
+			{
+				header: &Header{
+					Name:     "file.txt",
+					Mode:     0644,
+					Uid:      1000,
+					Gid:      100,
+					Size:     15,
+					ModTime:  time.Unix(1425484303, 0),
+					Typeflag: '0',
+					Uname:    "vbatts",
+					Gname:    "users",
+				},
+				contents: "Slartibartfast\n",
+			},
+			{
+				header: &Header{
+					Name:     "hard.txt",
+					Mode:     0644,
+					Uid:      1000,
+					Gid:      100,
+					Size:     0,
+					ModTime:  time.Unix(1425484303, 0),
+					Typeflag: '1',
+					Linkname: "file.txt",
+					Uname:    "vbatts",
+					Gname:    "users",
+				},
+				// no contents
+			},
+		},
+	},
 }
 
 // Render byte array in a two-character hexadecimal string, spaced for easy visual inspection.
@@ -489,3 +527,20 @@ func TestValidTypeflagWithPAXHeader(t *testing.T) {
 		}
 	}
 }
+
+func TestWriteAfterClose(t *testing.T) {
+	var buffer bytes.Buffer
+	tw := NewWriter(&buffer)
+
+	hdr := &Header{
+		Name: "small.txt",
+		Size: 5,
+	}
+	if err := tw.WriteHeader(hdr); err != nil {
+		t.Fatalf("Failed to write header: %s", err)
+	}
+	tw.Close()
+	if _, err := tw.Write([]byte("Kilts")); err != ErrWriteAfterClose {
+		t.Fatalf("Write: got %v; want ErrWriteAfterClose", err)
+	}
+}
diff --git a/src/archive/zip/reader.go b/src/archive/zip/reader.go
index 8136b84..519748b 100644
--- a/src/archive/zip/reader.go
+++ b/src/archive/zip/reader.go
@@ -8,6 +8,7 @@ import (
 	"bufio"
 	"encoding/binary"
 	"errors"
+	"fmt"
 	"hash"
 	"hash/crc32"
 	"io"
@@ -77,6 +78,9 @@ func (z *Reader) init(r io.ReaderAt, size int64) error {
 	if err != nil {
 		return err
 	}
+	if end.directoryRecords > uint64(size)/fileHeaderLen {
+		return fmt.Errorf("archive/zip: TOC declares impossible %d files in %d byte zip", end.directoryRecords, size)
+	}
 	z.r = r
 	z.File = make([]*File, 0, end.directoryRecords)
 	z.Comment = end.comment
@@ -146,16 +150,22 @@ func (f *File) Open() (rc io.ReadCloser, err error) {
 	if f.hasDataDescriptor() {
 		desr = io.NewSectionReader(f.zipr, f.headerOffset+bodyOffset+size, dataDescriptorLen)
 	}
-	rc = &checksumReader{rc, crc32.NewIEEE(), f, desr, nil}
+	rc = &checksumReader{
+		rc:   rc,
+		hash: crc32.NewIEEE(),
+		f:    f,
+		desr: desr,
+	}
 	return
 }
 
 type checksumReader struct {
-	rc   io.ReadCloser
-	hash hash.Hash32
-	f    *File
-	desr io.Reader // if non-nil, where to read the data descriptor
-	err  error     // sticky error
+	rc    io.ReadCloser
+	hash  hash.Hash32
+	nread uint64 // number of bytes read so far
+	f     *File
+	desr  io.Reader // if non-nil, where to read the data descriptor
+	err   error     // sticky error
 }
 
 func (r *checksumReader) Read(b []byte) (n int, err error) {
@@ -164,13 +174,21 @@ func (r *checksumReader) Read(b []byte) (n int, err error) {
 	}
 	n, err = r.rc.Read(b)
 	r.hash.Write(b[:n])
+	r.nread += uint64(n)
 	if err == nil {
 		return
 	}
 	if err == io.EOF {
+		if r.nread != r.f.UncompressedSize64 {
+			return 0, io.ErrUnexpectedEOF
+		}
 		if r.desr != nil {
 			if err1 := readDataDescriptor(r.desr, r.f); err1 != nil {
-				err = err1
+				if err1 == io.EOF {
+					err = io.ErrUnexpectedEOF
+				} else {
+					err = err1
+				}
 			} else if r.hash.Sum32() != r.f.CRC32 {
 				err = ErrChecksum
 			}
diff --git a/src/archive/zip/reader_test.go b/src/archive/zip/reader_test.go
index 29d0652..547dd39 100644
--- a/src/archive/zip/reader_test.go
+++ b/src/archive/zip/reader_test.go
@@ -531,3 +531,77 @@ func TestIssue8186(t *testing.T) {
 		}
 	}
 }
+
+// Verify we return ErrUnexpectedEOF when length is short.
+func TestIssue10957(t *testing.T) {
+	data := []byte("PK\x03\x040000000PK\x01\x0200000" +
+		"0000000000000000000\x00" +
+		"\x00\x00\x00\x00\x00000000000000PK\x01" +
+		"\x020000000000000000000" +
+		"00000\v\x00\x00\x00\x00\x00000000000" +
+		"00000000000000PK\x01\x0200" +
+		"00000000000000000000" +
+		"00\v\x00\x00\x00\x00\x00000000000000" +
+		"00000000000PK\x01\x020000<" +
+		"0\x00\x0000000000000000\v\x00\v" +
+		"\x00\x00\x00\x00\x0000000000\x00\x00\x00\x00000" +
+		"00000000PK\x01\x0200000000" +
+		"0000000000000000\v\x00\x00\x00" +
+		"\x00\x0000PK\x05\x06000000\x05\x000000" +
+		"\v\x00\x00\x00\x00\x00")
+	z, err := NewReader(bytes.NewReader(data), int64(len(data)))
+	if err != nil {
+		t.Fatal(err)
+	}
+	for i, f := range z.File {
+		r, err := f.Open()
+		if err != nil {
+			continue
+		}
+		if f.UncompressedSize64 < 1e6 {
+			n, err := io.Copy(ioutil.Discard, r)
+			if i == 3 && err != io.ErrUnexpectedEOF {
+				t.Errorf("File[3] error = %v; want io.ErrUnexpectedEOF", err)
+			}
+			if err == nil && uint64(n) != f.UncompressedSize64 {
+				t.Errorf("file %d: bad size: copied=%d; want=%d", i, n, f.UncompressedSize64)
+			}
+		}
+		r.Close()
+	}
+}
+
+// Verify the number of files is sane.
+func TestIssue10956(t *testing.T) {
+	data := []byte("PK\x06\x06PK\x06\a0000\x00\x00\x00\x00\x00\x00\x00\x00" +
+		"0000PK\x05\x06000000000000" +
+		"0000\v\x00000\x00\x00\x00\x00\x00\x00\x000")
+	_, err := NewReader(bytes.NewReader(data), int64(len(data)))
+	const want = "TOC declares impossible 3472328296227680304 files in 57 byte"
+	if err == nil && !strings.Contains(err.Error(), want) {
+		t.Errorf("error = %v; want %q", err, want)
+	}
+}
+
+// Verify we return ErrUnexpectedEOF when reading truncated data descriptor.
+func TestIssue11146(t *testing.T) {
+	data := []byte("PK\x03\x040000000000000000" +
+		"000000\x01\x00\x00\x000\x01\x00\x00\xff\xff0000" +
+		"0000000000000000PK\x01\x02" +
+		"0000\b0\b\x00000000000000" +
+		"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x000000PK\x05\x06\x00\x00" +
+		"\x00\x0000\x01\x0000008\x00\x00\x00\x00\x00")
+	z, err := NewReader(bytes.NewReader(data), int64(len(data)))
+	if err != nil {
+		t.Fatal(err)
+	}
+	r, err := z.File[0].Open()
+	if err != nil {
+		t.Fatal(err)
+	}
+	_, err = ioutil.ReadAll(r)
+	if err != io.ErrUnexpectedEOF {
+		t.Errorf("File[0] error = %v; want io.ErrUnexpectedEOF", err)
+	}
+	r.Close()
+}
diff --git a/src/archive/zip/struct.go b/src/archive/zip/struct.go
index cb28e83..137d049 100644
--- a/src/archive/zip/struct.go
+++ b/src/archive/zip/struct.go
@@ -81,8 +81,8 @@ type FileHeader struct {
 	ModifiedTime       uint16 // MS-DOS time
 	ModifiedDate       uint16 // MS-DOS date
 	CRC32              uint32
-	CompressedSize     uint32 // deprecated; use CompressedSize64
-	UncompressedSize   uint32 // deprecated; use UncompressedSize64
+	CompressedSize     uint32 // Deprecated: Use CompressedSize64 instead.
+	UncompressedSize   uint32 // Deprecated: Use UncompressedSize64 instead.
 	CompressedSize64   uint64
 	UncompressedSize64 uint64
 	Extra              []byte
@@ -233,7 +233,7 @@ func (h *FileHeader) SetMode(mode os.FileMode) {
 	}
 }
 
-// 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/testdata/readme.notzip b/src/archive/zip/testdata/readme.notzip
index 06668c4..8173727 100644
Binary files a/src/archive/zip/testdata/readme.notzip and b/src/archive/zip/testdata/readme.notzip differ
diff --git a/src/archive/zip/testdata/readme.zip b/src/archive/zip/testdata/readme.zip
index db3bb90..5642a67 100644
Binary files a/src/archive/zip/testdata/readme.zip and b/src/archive/zip/testdata/readme.zip differ
diff --git a/src/archive/zip/writer.go b/src/archive/zip/writer.go
index 170beec..3be2b5f 100644
--- a/src/archive/zip/writer.go
+++ b/src/archive/zip/writer.go
@@ -34,6 +34,17 @@ func NewWriter(w io.Writer) *Writer {
 	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 {
@@ -122,15 +133,15 @@ func (w *Writer) Close() error {
 
 		// zip64 end of central directory record
 		b.uint32(directory64EndSignature)
-		b.uint64(directory64EndLen)
-		b.uint16(zipVersion45) // version made by
-		b.uint16(zipVersion45) // version needed to extract
-		b.uint32(0)            // number of this disk
-		b.uint32(0)            // number of the disk with the start of the central directory
-		b.uint64(records)      // total number of entries in the central directory on this disk
-		b.uint64(records)      // total number of entries in the central directory
-		b.uint64(size)         // size of the central directory
-		b.uint64(offset)       // offset of start of central directory with respect to the starting disk number
+		b.uint64(directory64EndLen - 12) // length minus signature (uint32) and length fields (uint64)
+		b.uint16(zipVersion45)           // version made by
+		b.uint16(zipVersion45)           // version needed to extract
+		b.uint32(0)                      // number of this disk
+		b.uint32(0)                      // number of the disk with the start of the central directory
+		b.uint64(records)                // total number of entries in the central directory on this disk
+		b.uint64(records)                // total number of entries in the central directory
+		b.uint64(size)                   // size of the central directory
+		b.uint64(offset)                 // offset of start of central directory with respect to the starting disk number
 
 		// zip64 end of central directory locator
 		b.uint32(directory64LocSignature)
@@ -184,14 +195,20 @@ func (w *Writer) Create(name string) (io.Writer, error) {
 // CreateHeader adds a file to the zip file using the provided FileHeader
 // for the file metadata.
 // It returns a Writer to which the file contents should be written.
+//
 // The file's contents must be written to the io.Writer before the next
-// call to Create, CreateHeader, or Close.
+// call to Create, CreateHeader, or Close. The provided FileHeader fh
+// must not be modified after a call to CreateHeader.
 func (w *Writer) CreateHeader(fh *FileHeader) (io.Writer, error) {
 	if w.last != nil && !w.last.closed {
 		if err := w.last.close(); err != nil {
 			return nil, err
 		}
 	}
+	if len(w.dir) > 0 && w.dir[len(w.dir)-1].FileHeader == fh {
+		// See https://golang.org/issue/11144 confusion.
+		return nil, errors.New("archive/zip: invalid duplicate FileHeader")
+	}
 
 	fh.Flags |= 0x8 // we will write a data descriptor
 
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 TestWriter(t *testing.T) {
 	}
 }
 
+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/archive/zip/zip_test.go b/src/archive/zip/zip_test.go
index 32a16a7..f00ff47 100644
--- a/src/archive/zip/zip_test.go
+++ b/src/archive/zip/zip_test.go
@@ -229,10 +229,11 @@ func TestZip64(t *testing.T) {
 		t.Skip("slow test; skipping")
 	}
 	const size = 1 << 32 // before the "END\n" part
-	testZip64(t, size)
+	buf := testZip64(t, size)
+	testZip64DirectoryRecordLength(buf, t)
 }
 
-func testZip64(t testing.TB, size int64) {
+func testZip64(t testing.TB, size int64) *rleBuffer {
 	const chunkSize = 1024
 	chunks := int(size / chunkSize)
 	// write 2^32 bytes plus "END\n" to a zip file
@@ -302,6 +303,37 @@ func testZip64(t testing.TB, size int64) {
 	if got, want := f0.UncompressedSize64, uint64(size)+uint64(len(end)); got != want {
 		t.Errorf("UncompressedSize64 %d, want %d", got, want)
 	}
+
+	return buf
+}
+
+// Issue 9857
+func testZip64DirectoryRecordLength(buf *rleBuffer, t *testing.T) {
+	d := make([]byte, 1024)
+	if _, err := buf.ReadAt(d, buf.Size()-int64(len(d))); err != nil {
+		t.Fatal("read:", err)
+	}
+
+	sigOff := findSignatureInBlock(d)
+	dirOff, err := findDirectory64End(buf, buf.Size()-int64(len(d))+int64(sigOff))
+	if err != nil {
+		t.Fatal("findDirectory64End:", err)
+	}
+
+	d = make([]byte, directory64EndLen)
+	if _, err := buf.ReadAt(d, dirOff); err != nil {
+		t.Fatal("read:", err)
+	}
+
+	b := readBuf(d)
+	if sig := b.uint32(); sig != directory64EndSignature {
+		t.Fatalf("Expected directory64EndSignature (%d), got %d", directory64EndSignature, sig)
+	}
+
+	size := b.uint64()
+	if size != directory64EndLen-12 {
+		t.Fatalf("Expected length of %d, got %d", directory64EndLen-12, size)
+	}
 }
 
 func testInvalidHeader(h *FileHeader, t *testing.T) {
diff --git a/src/bootstrap.bash b/src/bootstrap.bash
new file mode 100755
index 0000000..1b5ba7c
--- /dev/null
+++ b/src/bootstrap.bash
@@ -0,0 +1,73 @@
+#!/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 -f .gitignore
+if [ -e .git ]; then
+	git clean -f -d
+fi
+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/bufio.go b/src/bufio/bufio.go
index d3c68fe..3bbb933 100644
--- a/src/bufio/bufio.go
+++ b/src/bufio/bufio.go
@@ -144,6 +144,39 @@ func (b *Reader) Peek(n int) ([]byte, error) {
 	return b.buf[b.r : b.r+n], err
 }
 
+// Discard skips the next n bytes, returning the number of bytes discarded.
+//
+// If Discard skips fewer than n bytes, it also returns an error.
+// If 0 <= n <= b.Buffered(), Discard is guaranteed to succeed without
+// reading from the underlying io.Reader.
+func (b *Reader) Discard(n int) (discarded int, err error) {
+	if n < 0 {
+		return 0, ErrNegativeCount
+	}
+	if n == 0 {
+		return
+	}
+	remain := n
+	for {
+		skip := b.Buffered()
+		if skip == 0 {
+			b.fill()
+			skip = b.Buffered()
+		}
+		if skip > remain {
+			skip = remain
+		}
+		b.r += skip
+		remain -= skip
+		if remain == 0 {
+			return n, nil
+		}
+		if b.err != nil {
+			return n - remain, b.readErr()
+		}
+	}
+}
+
 // Read reads data into p.
 // It returns the number of bytes read into p.
 // It calls Read at most once on the underlying Reader,
@@ -367,7 +400,6 @@ func (b *Reader) ReadBytes(delim byte) (line []byte, err error) {
 	// accumulating full buffers.
 	var frag []byte
 	var full [][]byte
-	err = nil
 
 	for {
 		var e error
diff --git a/src/bufio/bufio_test.go b/src/bufio/bufio_test.go
index 550dac9..666c44e 100644
--- a/src/bufio/bufio_test.go
+++ b/src/bufio/bufio_test.go
@@ -1268,6 +1268,135 @@ func TestWriterReset(t *testing.T) {
 	}
 }
 
+func TestReaderDiscard(t *testing.T) {
+	tests := []struct {
+		name     string
+		r        io.Reader
+		bufSize  int // 0 means 16
+		peekSize int
+
+		n int // input to Discard
+
+		want    int   // from Discard
+		wantErr error // from Discard
+
+		wantBuffered int
+	}{
+		{
+			name:         "normal case",
+			r:            strings.NewReader("abcdefghijklmnopqrstuvwxyz"),
+			peekSize:     16,
+			n:            6,
+			want:         6,
+			wantBuffered: 10,
+		},
+		{
+			name:         "discard causing read",
+			r:            strings.NewReader("abcdefghijklmnopqrstuvwxyz"),
+			n:            6,
+			want:         6,
+			wantBuffered: 10,
+		},
+		{
+			name:         "discard all without peek",
+			r:            strings.NewReader("abcdefghijklmnopqrstuvwxyz"),
+			n:            26,
+			want:         26,
+			wantBuffered: 0,
+		},
+		{
+			name:         "discard more than end",
+			r:            strings.NewReader("abcdefghijklmnopqrstuvwxyz"),
+			n:            27,
+			want:         26,
+			wantErr:      io.EOF,
+			wantBuffered: 0,
+		},
+		// Any error from filling shouldn't show up until we
+		// get past the valid bytes. Here we return we return 5 valid bytes at the same time
+		// as an error, but test that we don't see the error from Discard.
+		{
+			name: "fill error, discard less",
+			r: newScriptedReader(func(p []byte) (n int, err error) {
+				if len(p) < 5 {
+					panic("unexpected small read")
+				}
+				return 5, errors.New("5-then-error")
+			}),
+			n:            4,
+			want:         4,
+			wantErr:      nil,
+			wantBuffered: 1,
+		},
+		{
+			name: "fill error, discard equal",
+			r: newScriptedReader(func(p []byte) (n int, err error) {
+				if len(p) < 5 {
+					panic("unexpected small read")
+				}
+				return 5, errors.New("5-then-error")
+			}),
+			n:            5,
+			want:         5,
+			wantErr:      nil,
+			wantBuffered: 0,
+		},
+		{
+			name: "fill error, discard more",
+			r: newScriptedReader(func(p []byte) (n int, err error) {
+				if len(p) < 5 {
+					panic("unexpected small read")
+				}
+				return 5, errors.New("5-then-error")
+			}),
+			n:            6,
+			want:         5,
+			wantErr:      errors.New("5-then-error"),
+			wantBuffered: 0,
+		},
+		// Discard of 0 shouldn't cause a read:
+		{
+			name:         "discard zero",
+			r:            newScriptedReader(), // will panic on Read
+			n:            0,
+			want:         0,
+			wantErr:      nil,
+			wantBuffered: 0,
+		},
+		{
+			name:         "discard negative",
+			r:            newScriptedReader(), // will panic on Read
+			n:            -1,
+			want:         0,
+			wantErr:      ErrNegativeCount,
+			wantBuffered: 0,
+		},
+	}
+	for _, tt := range tests {
+		br := NewReaderSize(tt.r, tt.bufSize)
+		if tt.peekSize > 0 {
+			peekBuf, err := br.Peek(tt.peekSize)
+			if err != nil {
+				t.Errorf("%s: Peek(%d): %v", tt.name, tt.peekSize, err)
+				continue
+			}
+			if len(peekBuf) != tt.peekSize {
+				t.Errorf("%s: len(Peek(%d)) = %v; want %v", tt.name, tt.peekSize, len(peekBuf), tt.peekSize)
+				continue
+			}
+		}
+		discarded, err := br.Discard(tt.n)
+		if ge, we := fmt.Sprint(err), fmt.Sprint(tt.wantErr); discarded != tt.want || ge != we {
+			t.Errorf("%s: Discard(%d) = (%v, %v); want (%v, %v)", tt.name, tt.n, discarded, ge, tt.want, we)
+			continue
+		}
+		if bn := br.Buffered(); bn != tt.wantBuffered {
+			t.Errorf("%s: after Discard, Buffered = %d; want %d", tt.name, bn, tt.wantBuffered)
+		}
+	}
+
+}
+
 // An onlyReader only implements io.Reader, no matter what other methods the underlying implementation may have.
 type onlyReader struct {
 	io.Reader
@@ -1278,6 +1407,23 @@ type onlyWriter struct {
 	io.Writer
 }
 
+// A scriptedReader is an io.Reader that executes its steps sequentially.
+type scriptedReader []func(p []byte) (n int, err error)
+
+func (sr *scriptedReader) Read(p []byte) (n int, err error) {
+	if len(*sr) == 0 {
+		panic("too many Read calls on scripted Reader. No steps remain.")
+	}
+	step := (*sr)[0]
+	*sr = (*sr)[1:]
+	return step(p)
+}
+
+func newScriptedReader(steps ...func(p []byte) (n int, err error)) io.Reader {
+	sr := scriptedReader(steps)
+	return &sr
+}
+
 func BenchmarkReaderCopyOptimal(b *testing.B) {
 	// Optimal case is where the underlying reader implements io.WriterTo
 	srcBuf := bytes.NewBuffer(make([]byte, 8192))
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 @@ func (s *Scanner) Text() string {
 // 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/buildall.bash b/src/buildall.bash
new file mode 100755
index 0000000..ba23d31
--- /dev/null
+++ b/src/buildall.bash
@@ -0,0 +1,70 @@
+#!/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.
+
+# Usage: buildall.sh [-e] [pattern]
+#
+# buildall.bash builds the standard library for all Go-supported
+# architectures. It is used by the "all-compile" trybot builder,
+# as a smoke test to quickly flag portability issues.
+#
+# Options:
+#   -e: stop at first failure
+
+if [ ! -f run.bash ]; then
+	echo 'buildall.bash must be run from $GOROOT/src' 1>&2
+	exit 1
+fi
+
+sete=false
+if [ "$1" = "-e" ]; then
+    sete=true
+    shift
+fi
+
+if [ "$sete" = true ]; then
+    set -e
+fi
+
+pattern="$1"
+if [ "$pattern" = "" ]; then
+    pattern=.
+fi
+
+# put linux, nacl first in the target list to get all the architectures up front.
+targets="$((ls runtime | sed -n 's/^rt0_\(.*\)_\(.*\)\.s/\1-\2/p'; echo linux-386-387 linux-arm-arm5) | sort | egrep -v android-arm | egrep "$pattern" | egrep 'linux|nacl')
+$(ls runtime | sed -n 's/^rt0_\(.*\)_\(.*\)\.s/\1-\2/p' | egrep -v 'android-arm|darwin-arm' | egrep "$pattern" | egrep -v 'linux|nacl')"
+
+./make.bash || exit 1
+GOROOT="$(cd .. && pwd)"
+
+failed=false
+for target in $targets
+do
+    echo ""
+    echo "### Building $target"
+    export GOOS=$(echo $target | sed 's/-.*//')
+    export GOARCH=$(echo $target | sed 's/.*-//')
+    unset GO386 GOARM
+    if [ "$GOARCH" = "arm5" ]; then
+        export GOARCH=arm
+        export GOARM=5
+    fi
+    if [ "$GOARCH" = "387" ]; then
+        export GOARCH=386
+        export GO386=387
+    fi
+    if ! "$GOROOT/bin/go" build -a std cmd; then
+        failed=true
+        if $sete; then
+            exit 1
+        fi
+    fi
+done
+
+if [ "$failed" = "true" ]; then
+    echo "" 1>&2
+    echo "Build(s) failed." 1>&2
+    exit 1
+fi
diff --git a/src/builtin/builtin.go b/src/builtin/builtin.go
index 51550a4..d63ad22 100644
--- a/src/builtin/builtin.go
+++ b/src/builtin/builtin.go
@@ -236,14 +236,14 @@ func panic(v interface{})
 // panicking.
 func recover() interface{}
 
-// The print built-in function formats its arguments in an implementation-
-// specific way and writes the result to standard error.
+// The print built-in function formats its arguments in an
+// implementation-specific way and writes the result to standard error.
 // Print is useful for bootstrapping and debugging; it is not guaranteed
 // to stay in the language.
 func print(args ...Type)
 
-// The println built-in function formats its arguments in an implementation-
-// specific way and writes the result to standard error.
+// The println built-in function formats its arguments in an
+// implementation-specific way and writes the result to standard error.
 // Spaces are always added between arguments and a newline is appended.
 // Println is useful for bootstrapping and debugging; it is not guaranteed
 // to stay in the language.
diff --git a/src/bytes/buffer.go b/src/bytes/buffer.go
index 46ca1d5..4db9386 100644
--- a/src/bytes/buffer.go
+++ b/src/bytes/buffer.go
@@ -56,6 +56,10 @@ func (b *Buffer) String() string {
 // b.Len() == len(b.Bytes()).
 func (b *Buffer) Len() int { return len(b.buf) - b.off }
 
+// Cap returns the capacity of the buffer's underlying byte slice, that is, the
+// total space allocated for the buffer's data.
+func (b *Buffer) Cap() int { return cap(b.buf) }
+
 // Truncate discards all but the first n unread bytes from the buffer.
 // It panics if n is negative or greater than the length of the buffer.
 func (b *Buffer) Truncate(n int) {
diff --git a/src/bytes/buffer_test.go b/src/bytes/buffer_test.go
index 75145b0..7de17ae 100644
--- a/src/bytes/buffer_test.go
+++ b/src/bytes/buffer_test.go
@@ -231,6 +231,23 @@ func TestMixedReadsAndWrites(t *testing.T) {
 	empty(t, "TestMixedReadsAndWrites (2)", &buf, s, make([]byte, buf.Len()))
 }
 
+func TestCapWithPreallocatedSlice(t *testing.T) {
+	buf := NewBuffer(make([]byte, 10))
+	n := buf.Cap()
+	if n != 10 {
+		t.Errorf("expected 10, got %d", n)
+	}
+}
+
+func TestCapWithSliceAndWrittenData(t *testing.T) {
+	buf := NewBuffer(make([]byte, 0, 10))
+	buf.Write([]byte("test"))
+	n := buf.Cap()
+	if n != 10 {
+		t.Errorf("expected 10, got %d", n)
+	}
+}
+
 func TestNil(t *testing.T) {
 	var b *Buffer
 	if b.String() != "<nil>" {
diff --git a/src/bytes/bytes.go b/src/bytes/bytes.go
index 7634707..b868240 100644
--- a/src/bytes/bytes.go
+++ b/src/bytes/bytes.go
@@ -23,7 +23,7 @@ func equalPortable(a, b []byte) bool {
 	return true
 }
 
-// explode splits s into a slice of UTF-8 sequences, one per Unicode character (still slices of bytes),
+// explode splits s into a slice of UTF-8 sequences, one per Unicode code point (still slices of bytes),
 // up to a maximum of n byte slices. Invalid UTF-8 sequences are chopped into individual bytes.
 func explode(s []byte, n int) [][]byte {
 	if n <= 0 {
@@ -47,6 +47,7 @@ func explode(s []byte, n int) [][]byte {
 }
 
 // Count counts the number of non-overlapping instances of sep in s.
+// If sep is an empty slice, Count returns 1 + the number of Unicode code points in s.
 func Count(s, sep []byte) int {
 	n := len(sep)
 	if n == 0 {
@@ -137,6 +138,16 @@ func LastIndex(s, sep []byte) int {
 	return -1
 }
 
+// LastIndexByte returns the index of the last instance of c in s, or -1 if c is not present in s.
+func LastIndexByte(s []byte, c byte) int {
+	for i := len(s) - 1; i >= 0; i-- {
+		if s[i] == c {
+			return i
+		}
+	}
+	return -1
+}
+
 // IndexRune interprets s as a sequence of UTF-8-encoded Unicode code points.
 // It returns the byte index of the first occurrence in s of the given rune.
 // It returns -1 if rune is not present in s.
@@ -442,7 +453,7 @@ func isSeparator(r rune) bool {
 // 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/bytes_decl.go b/src/bytes/bytes_decl.go
index 617d748..b453f21 100644
--- a/src/bytes/bytes_decl.go
+++ b/src/bytes/bytes_decl.go
@@ -21,4 +21,4 @@ func Equal(a, b []byte) bool // ../runtime/asm_$GOARCH.s
 // Compare returns an integer comparing two byte slices lexicographically.
 // The result will be 0 if a==b, -1 if a < b, and +1 if a > b.
 // A nil argument is equivalent to an empty slice.
-func Compare(a, b []byte) int // ../runtime/noasm_arm.goc or ../runtime/asm_{386,amd64}.s
+func Compare(a, b []byte) int // ../runtime/noasm.go or ../runtime/asm_{386,amd64}.s
diff --git a/src/bytes/bytes_test.go b/src/bytes/bytes_test.go
index 980c41d..6245e48 100644
--- a/src/bytes/bytes_test.go
+++ b/src/bytes/bytes_test.go
@@ -265,6 +265,23 @@ func TestIndexByte(t *testing.T) {
 	}
 }
 
+func TestLastIndexByte(t *testing.T) {
+	testCases := []BinOpTest{
+		{"", "q", -1},
+		{"abcdef", "q", -1},
+		{"abcdefabcdef", "a", len("abcdef")},      // something in the middle
+		{"abcdefabcdef", "f", len("abcdefabcde")}, // last byte
+		{"zabcdefabcdef", "z", 0},                 // first byte
+		{"a☺b☻c☹d", "b", len("a☺")},               // non-ascii
+	}
+	for _, test := range testCases {
+		actual := LastIndexByte([]byte(test.a), test.b[0])
+		if actual != test.i {
+			t.Errorf("LastIndexByte(%q,%c) = %v; want %v", test.a, test.b[0], actual, test.i)
+		}
+	}
+}
+
 // test a larger buffer with different sizes and alignments
 func TestIndexByteBig(t *testing.T) {
 	var n = 1024
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 @@ var compareTests = []struct {
 	{[]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 @@ var compareTests = []struct {
 	{[]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/bytes/export_test.go b/src/bytes/export_test.go
index 3b915d5..f61523e 100644
--- a/src/bytes/export_test.go
+++ b/src/bytes/export_test.go
@@ -7,7 +7,3 @@ package bytes
 // Export func for testing
 var IndexBytePortable = indexBytePortable
 var EqualPortable = equalPortable
-
-func (b *Buffer) Cap() int {
-	return cap(b.buf)
-}
diff --git a/src/bytes/reader.go b/src/bytes/reader.go
index d2d40fa..b89d154 100644
--- a/src/bytes/reader.go
+++ b/src/bytes/reader.go
@@ -29,6 +29,12 @@ func (r *Reader) Len() int {
 	return int(int64(len(r.s)) - r.i)
 }
 
+// Size returns the original length of the underlying byte slice.
+// Size is the number of bytes available for reading via ReadAt.
+// The returned value is always the same and is not affected by calls
+// to any other method.
+func (r *Reader) Size() int64 { return int64(len(r.s)) }
+
 func (r *Reader) Read(b []byte) (n int, err error) {
 	if len(b) == 0 {
 		return 0, nil
diff --git a/src/bytes/reader_test.go b/src/bytes/reader_test.go
index d3dce53..b929a28 100644
--- a/src/bytes/reader_test.go
+++ b/src/bytes/reader_test.go
@@ -244,3 +244,15 @@ func TestReaderCopyNothing(t *testing.T) {
 		t.Errorf("behavior differs: with = %#v; without: %#v", with, withOut)
 	}
 }
+
+// tests that Len is affected by reads, but Size is not.
+func TestReaderLenSize(t *testing.T) {
+	r := NewReader([]byte("abc"))
+	io.CopyN(ioutil.Discard, r, 1)
+	if r.Len() != 2 {
+		t.Errorf("Len = %d; want 2", r.Len())
+	}
+	if r.Size() != 3 {
+		t.Errorf("Size = %d; want 3", r.Size())
+	}
+}
diff --git a/src/clean.bash b/src/clean.bash
index f362602..39fe36d 100755
--- a/src/clean.bash
+++ b/src/clean.bash
@@ -5,12 +5,18 @@
 
 set -e
 
-eval $(go tool dist env)
+if [ ! -f run.bash ]; then
+	echo 'clean.bash must be run from $GOROOT/src' 1>&2
+	exit 1
+fi
+export GOROOT="$(cd .. && pwd)"
 
-if [ ! -x $GOTOOLDIR/dist ]; then
-	echo 'cannot find $GOTOOLDIR/dist; nothing to clean' >&2
+gobin="${GOBIN:-../bin}"
+if ! "$gobin"/go help >/dev/null 2>&1; then
+	echo 'cannot find go command; nothing to clean' >&2
 	exit 1
 fi
 
-"$GOBIN/go" clean -i std
-$GOTOOLDIR/dist clean
+"$gobin/go" clean -i std
+"$gobin/go" tool dist clean
+"$gobin/go" clean -i cmd
diff --git a/src/clean.bat b/src/clean.bat
index dcf54ea..3cc6a68 100644
--- a/src/clean.bat
+++ b/src/clean.bat
@@ -7,7 +7,7 @@ setlocal
 
 set GOBUILDFAIL=0
 
-go tool dist env -wp >env.bat
+go tool dist env -w -p >env.bat
 if errorlevel 1 goto fail
 call env.bat
 del env.bat
@@ -19,7 +19,8 @@ goto fail
 :distok
 
 "%GOBIN%\go" clean -i std
-%GOTOOLDIR%\dist clean
+"%GOBIN%\go" tool dist clean
+"%GOBIN%\go" clean -i cmd
 
 goto end
 
diff --git a/src/clean.rc b/src/clean.rc
index 41cab61..23bbd60 100755
--- a/src/clean.rc
+++ b/src/clean.rc
@@ -11,4 +11,5 @@ if(! test -x $GOTOOLDIR/dist){
 }
 
 $GOBIN/go clean -i std
-$GOTOOLDIR/dist clean
+$GOBIN/go tool dist clean
+$GOBIN/go clean -i cmd
diff --git a/src/cmd/5a/Makefile b/src/cmd/5a/Makefile
deleted file mode 100644
index 27290dd..0000000
--- a/src/cmd/5a/Makefile
+++ /dev/null
@@ -1,10 +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.
-
-include ../../Make.dist
-
-install: y.tab.h
-
-y.tab.h: a.y
-	LANG=C LANGUAGE=en_US.UTF8 bison -d -v -y a.y
diff --git a/src/cmd/5a/a.h b/src/cmd/5a/a.h
deleted file mode 100644
index bb60fe7..0000000
--- a/src/cmd/5a/a.h
+++ /dev/null
@@ -1,169 +0,0 @@
-// Inferno utils/5a/a.h
-// http://code.google.com/p/inferno-os/source/browse/utils/5a/a.h
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.	All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include <bio.h>
-#include <link.h>
-#include "../5l/5.out.h"
-
-#ifndef	EXTERN
-#define	EXTERN	extern
-#endif
-
-#undef	getc
-#undef	ungetc
-#undef	BUFSIZ
-
-#define	getc	ccgetc
-#define	ungetc	ccungetc
-
-typedef	struct	Sym	Sym;
-typedef	struct	Io	Io;
-
-#define	MAXALIGN	7
-#define	FPCHIP		1
-#define	NSYMB		8192
-#define	BUFSIZ		8192
-#define	HISTSZ		20
-#ifndef	EOF
-#define	EOF		(-1)
-#endif
-#define	IGN		(-2)
-#define	GETC()		((--fi.c < 0)? filbuf(): *fi.p++ & 0xff)
-#define	NHASH		503
-#define	STRINGSZ	200
-#define	NMACRO		10
-
-struct	Sym
-{
-	Sym*	link;
-	char*	macro;
-	int32	value;
-	ushort	type;
-	char	*name;
-	char	sym;
-};
-#define	S	((Sym*)0)
-
-EXTERN	struct
-{
-	char*	p;
-	int	c;
-} fi;
-
-struct	Io
-{
-	Io*	link;
-	char	b[BUFSIZ];
-	char*	p;
-	short	c;
-	short	f;
-};
-#define	I	((Io*)0)
-
-enum
-{
-	CLAST,
-	CMACARG,
-	CMACRO,
-	CPREPROC,
-
-	Always	= 14,
-};
-
-EXTERN	int	debug[256];
-EXTERN	Sym*	hash[NHASH];
-EXTERN	char**	Dlist;
-EXTERN	int	nDlist;
-EXTERN	int	newflag;
-EXTERN	char*	hunk;
-EXTERN	char**	include;
-EXTERN	Io*	iofree;
-EXTERN	Io*	ionext;
-EXTERN	Io*	iostack;
-EXTERN	int32	lineno;
-EXTERN	int	nerrors;
-EXTERN	int32	nhunk;
-EXTERN	int	ninclude;
-EXTERN	int32	nsymb;
-EXTERN	Addr	nullgen;
-EXTERN	char*	outfile;
-EXTERN	int	pass;
-EXTERN	int32	pc;
-EXTERN	int	peekc;
-EXTERN	int32	stmtline;
-EXTERN	int	sym;
-EXTERN	char*	symb;
-EXTERN	int	thechar;
-EXTERN	char*	thestring;
-EXTERN	int32	thunk;
-EXTERN	Biobuf	obuf;
-EXTERN	Link*	ctxt;
-EXTERN	Biobuf	bstdout;
-
-void*	alloc(int32);
-void*	allocn(void*, int32, int32);
-void	ensuresymb(int32);
-void	errorexit(void);
-void	pushio(void);
-void	newio(void);
-void	newfile(char*, int);
-Sym*	slookup(char*);
-Sym*	lookup(void);
-void	syminit(Sym*);
-int32	yylex(void);
-int	getc(void);
-int	getnsc(void);
-void	unget(int);
-int	escchar(int);
-void	cinit(void);
-void	pinit(char*);
-void	cclean(void);
-int	isreg(Addr*);
-void	outcode(int, int, Addr*, int, Addr*);
-int	filbuf(void);
-Sym*	getsym(void);
-void	domacro(void);
-void	macund(void);
-void	macdef(void);
-void	macexpand(Sym*, char*);
-void	macinc(void);
-void	maclin(void);
-void	macprag(void);
-void	macif(int);
-void	macend(void);
-void	dodefine(char*);
-void	prfile(int32);
-void	linehist(char*, int);
-void	gethunk(void);
-void	yyerror(char*, ...);
-int	yyparse(void);
-void	setinclude(char*);
-int	assemble(char*);
-void	listinit(void);
diff --git a/src/cmd/5a/a.y b/src/cmd/5a/a.y
deleted file mode 100644
index ad64760..0000000
--- a/src/cmd/5a/a.y
+++ /dev/null
@@ -1,747 +0,0 @@
-// Inferno utils/5a/a.y
-// http://code.google.com/p/inferno-os/source/browse/utils/5a/a.y
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.	All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-%{
-#include <u.h>
-#include <stdio.h>	/* if we don't, bison will, and a.h re-#defines getc */
-#include <libc.h>
-#include "a.h"
-#include "../../runtime/funcdata.h"
-%}
-%union
-{
-	Sym	*sym;
-	int32	lval;
-	double	dval;
-	char	sval[8];
-	Addr	addr;
-}
-%left	'|'
-%left	'^'
-%left	'&'
-%left	'<' '>'
-%left	'+' '-'
-%left	'*' '/' '%'
-%token	<lval>	LTYPE1 LTYPE2 LTYPE3 LTYPE4 LTYPE5
-%token	<lval>	LTYPE6 LTYPE7 LTYPE8 LTYPE9 LTYPEA
-%token	<lval>	LTYPEB LTYPEC LTYPED LTYPEE
-%token	<lval>	LTYPEG LTYPEH LTYPEI LTYPEJ LTYPEK
-%token	<lval>	LTYPEL LTYPEM LTYPEN LTYPEBX LTYPEPLD
-%token	<lval>	LCONST LSP LSB LFP LPC
-%token	<lval>	LTYPEX LTYPEPC LTYPEF LR LREG LF LFREG LC LCREG LPSR LFCR
-%token	<lval>	LCOND LS LAT
-%token	<dval>	LFCONST
-%token	<sval>	LSCONST
-%token	<sym>	LNAME LLAB LVAR
-%type	<lval>	con expr oexpr pointer offset sreg spreg creg
-%type	<lval>	rcon cond reglist
-%type	<addr>	gen rel reg regreg freg shift fcon frcon
-%type	<addr>	imm ximm name oreg ireg nireg ioreg imsr
-%%
-prog:
-|	prog
-	{
-		stmtline = lineno;
-	}
-	line
-
-line:
-	LLAB ':'
-	{
-		if($1->value != pc)
-			yyerror("redeclaration of %s", $1->name);
-		$1->value = pc;
-	}
-	line
-|	LNAME ':'
-	{
-		$1->type = LLAB;
-		$1->value = pc;
-	}
-	line
-|	LNAME '=' expr ';'
-	{
-		$1->type = LVAR;
-		$1->value = $3;
-	}
-|	LVAR '=' expr ';'
-	{
-		if($1->value != $3)
-			yyerror("redeclaration of %s", $1->name);
-		$1->value = $3;
-	}
-|	';'
-|	inst ';'
-|	error ';'
-
-inst:
-/*
- * ADD
- */
-	LTYPE1 cond imsr ',' spreg ',' reg
-	{
-		outcode($1, $2, &$3, $5, &$7);
-	}
-|	LTYPE1 cond imsr ',' spreg ','
-	{
-		outcode($1, $2, &$3, $5, &nullgen);
-	}
-|	LTYPE1 cond imsr ',' reg
-	{
-		outcode($1, $2, &$3, NREG, &$5);
-	}
-/*
- * MVN
- */
-|	LTYPE2 cond imsr ',' reg
-	{
-		outcode($1, $2, &$3, NREG, &$5);
-	}
-/*
- * MOVW
- */
-|	LTYPE3 cond gen ',' gen
-	{
-		outcode($1, $2, &$3, NREG, &$5);
-	}
-/*
- * B/BL
- */
-|	LTYPE4 cond comma rel
-	{
-		outcode($1, $2, &nullgen, NREG, &$4);
-	}
-|	LTYPE4 cond comma nireg
-	{
-		outcode($1, $2, &nullgen, NREG, &$4);
-	}
-/*
- * BX
- */
-|	LTYPEBX comma ireg
-	{
-		outcode($1, Always, &nullgen, NREG, &$3);
-	}
-/*
- * BEQ
- */
-|	LTYPE5 comma rel
-	{
-		outcode($1, Always, &nullgen, NREG, &$3);
-	}
-/*
- * SWI
- */
-|	LTYPE6 cond comma gen
-	{
-		outcode($1, $2, &nullgen, NREG, &$4);
-	}
-/*
- * CMP
- */
-|	LTYPE7 cond imsr ',' spreg comma
-	{
-		outcode($1, $2, &$3, $5, &nullgen);
-	}
-/*
- * MOVM
- */
-|	LTYPE8 cond ioreg ',' '[' reglist ']'
-	{
-		Addr g;
-
-		g = nullgen;
-		g.type = D_CONST;
-		g.offset = $6;
-		outcode($1, $2, &$3, NREG, &g);
-	}
-|	LTYPE8 cond '[' reglist ']' ',' ioreg
-	{
-		Addr g;
-
-		g = nullgen;
-		g.type = D_CONST;
-		g.offset = $4;
-		outcode($1, $2, &g, NREG, &$7);
-	}
-/*
- * SWAP
- */
-|	LTYPE9 cond reg ',' ireg ',' reg
-	{
-		outcode($1, $2, &$5, $3.reg, &$7);
-	}
-|	LTYPE9 cond reg ',' ireg comma
-	{
-		outcode($1, $2, &$5, $3.reg, &$3);
-	}
-|	LTYPE9 cond comma ireg ',' reg
-	{
-		outcode($1, $2, &$4, $6.reg, &$6);
-	}
-/*
- * RET
- */
-|	LTYPEA cond comma
-	{
-		outcode($1, $2, &nullgen, NREG, &nullgen);
-	}
-/*
- * TEXT/GLOBL
- */
-|	LTYPEB name ',' imm
-	{
-		$4.type = D_CONST2;
-		$4.offset2 = ArgsSizeUnknown;
-		outcode($1, Always, &$2, 0, &$4);
-	}
-|	LTYPEB name ',' con ',' imm
-	{
-		$6.type = D_CONST2;
-		$6.offset2 = ArgsSizeUnknown;
-		outcode($1, Always, &$2, $4, &$6);
-	}
-|	LTYPEB name ',' con ',' imm '-' con
-	{
-		$6.type = D_CONST2;
-		$6.offset2 = $8;
-		outcode($1, Always, &$2, $4, &$6);
-	}
-/*
- * DATA
- */
-|	LTYPEC name '/' con ',' ximm
-	{
-		outcode($1, Always, &$2, $4, &$6);
-	}
-/*
- * CASE
- */
-|	LTYPED cond reg comma
-	{
-		outcode($1, $2, &$3, NREG, &nullgen);
-	}
-/*
- * word
- */
-|	LTYPEH comma ximm
-	{
-		outcode($1, Always, &nullgen, NREG, &$3);
-	}
-/*
- * floating-point coprocessor
- */
-|	LTYPEI cond freg ',' freg
-	{
-		outcode($1, $2, &$3, NREG, &$5);
-	}
-|	LTYPEK cond frcon ',' freg
-	{
-		outcode($1, $2, &$3, NREG, &$5);
-	}
-|	LTYPEK cond frcon ',' LFREG ',' freg
-	{
-		outcode($1, $2, &$3, $5, &$7);
-	}
-|	LTYPEL cond freg ',' freg comma
-	{
-		outcode($1, $2, &$3, $5.reg, &nullgen);
-	}
-/*
- * MCR MRC
- */
-|	LTYPEJ cond con ',' expr ',' spreg ',' creg ',' creg oexpr
-	{
-		Addr g;
-
-		g = nullgen;
-		g.type = D_CONST;
-		g.offset =
-			(0xe << 24) |		/* opcode */
-			($1 << 20) |		/* MCR/MRC */
-			($2 << 28) |		/* scond */
-			(($3 & 15) << 8) |	/* coprocessor number */
-			(($5 & 7) << 21) |	/* coprocessor operation */
-			(($7 & 15) << 12) |	/* arm register */
-			(($9 & 15) << 16) |	/* Crn */
-			(($11 & 15) << 0) |	/* Crm */
-			(($12 & 7) << 5) |	/* coprocessor information */
-			(1<<4);			/* must be set */
-		outcode(AMRC, Always, &nullgen, NREG, &g);
-	}
-/*
- * MULL r1,r2,(hi,lo)
- */
-|	LTYPEM cond reg ',' reg ',' regreg
-	{
-		outcode($1, $2, &$3, $5.reg, &$7);
-	}
-/*
- * MULA r1,r2,r3,r4: (r1*r2+r3) & 0xffffffff -> r4
- * MULAW{T,B} r1,r2,r3,r4
- */
-|	LTYPEN cond reg ',' reg ',' reg ',' spreg
-	{
-		$7.type = D_REGREG2;
-		$7.offset = $9;
-		outcode($1, $2, &$3, $5.reg, &$7);
-	}
-/*
- * PLD
- */
-|	LTYPEPLD oreg
-	{
-		outcode($1, Always, &$2, NREG, &nullgen);
-	}
-/*
- * PCDATA
- */
-|	LTYPEPC gen ',' gen
-	{
-		if($2.type != D_CONST || $4.type != D_CONST)
-			yyerror("arguments to PCDATA must be integer constants");
-		outcode($1, Always, &$2, NREG, &$4);
-	}
-/*
- * FUNCDATA
- */
-|	LTYPEF gen ',' gen
-	{
-		if($2.type != D_CONST)
-			yyerror("index for FUNCDATA must be integer constant");
-		if($4.type != D_EXTERN && $4.type != D_STATIC && $4.type != D_OREG)
-			yyerror("value for FUNCDATA must be symbol reference");
- 		outcode($1, Always, &$2, NREG, &$4);
-	}
-/*
- * END
- */
-|	LTYPEE comma
-	{
-		outcode($1, Always, &nullgen, NREG, &nullgen);
-	}
-
-cond:
-	{
-		$$ = Always;
-	}
-|	cond LCOND
-	{
-		$$ = ($1 & ~C_SCOND) | $2;
-	}
-|	cond LS
-	{
-		$$ = $1 | $2;
-	}
-
-comma:
-|	',' comma
-
-rel:
-	con '(' LPC ')'
-	{
-		$$ = nullgen;
-		$$.type = D_BRANCH;
-		$$.offset = $1 + pc;
-	}
-|	LNAME offset
-	{
-		$$ = nullgen;
-		if(pass == 2)
-			yyerror("undefined label: %s", $1->name);
-		$$.type = D_BRANCH;
-		$$.offset = $2;
-	}
-|	LLAB offset
-	{
-		$$ = nullgen;
-		$$.type = D_BRANCH;
-		$$.offset = $1->value + $2;
-	}
-
-ximm:	'$' con
-	{
-		$$ = nullgen;
-		$$.type = D_CONST;
-		$$.offset = $2;
-	}
-|	'$' oreg
-	{
-		$$ = $2;
-		$$.type = D_CONST;
-	}
-|	'$' '*' '$' oreg
-	{
-		$$ = $4;
-		$$.type = D_OCONST;
-	}
-|	'$' LSCONST
-	{
-		$$ = nullgen;
-		$$.type = D_SCONST;
-		memcpy($$.u.sval, $2, sizeof($$.u.sval));
-	}
-|	fcon
-
-fcon:
-	'$' LFCONST
-	{
-		$$ = nullgen;
-		$$.type = D_FCONST;
-		$$.u.dval = $2;
-	}
-|	'$' '-' LFCONST
-	{
-		$$ = nullgen;
-		$$.type = D_FCONST;
-		$$.u.dval = -$3;
-	}
-
-reglist:
-	spreg
-	{
-		$$ = 1 << $1;
-	}
-|	spreg '-' spreg
-	{
-		int i;
-		$$=0;
-		for(i=$1; i<=$3; i++)
-			$$ |= 1<<i;
-		for(i=$3; i<=$1; i++)
-			$$ |= 1<<i;
-	}
-|	spreg comma reglist
-	{
-		$$ = (1<<$1) | $3;
-	}
-
-gen:
-	reg
-|	ximm
-|	shift
-|	shift '(' spreg ')'
-	{
-		$$ = $1;
-		$$.reg = $3;
-	}
-|	LPSR
-	{
-		$$ = nullgen;
-		$$.type = D_PSR;
-		$$.reg = $1;
-	}
-|	LFCR
-	{
-		$$ = nullgen;
-		$$.type = D_FPCR;
-		$$.reg = $1;
-	}
-|	con
-	{
-		$$ = nullgen;
-		$$.type = D_OREG;
-		$$.offset = $1;
-	}
-|	oreg
-|	freg
-
-nireg:
-	ireg
-|	name
-	{
-		$$ = $1;
-		if($1.name != D_EXTERN && $1.name != D_STATIC) {
-		}
-	}
-
-ireg:
-	'(' spreg ')'
-	{
-		$$ = nullgen;
-		$$.type = D_OREG;
-		$$.reg = $2;
-		$$.offset = 0;
-	}
-
-ioreg:
-	ireg
-|	con '(' sreg ')'
-	{
-		$$ = nullgen;
-		$$.type = D_OREG;
-		$$.reg = $3;
-		$$.offset = $1;
-	}
-
-oreg:
-	name
-|	name '(' sreg ')'
-	{
-		$$ = $1;
-		$$.type = D_OREG;
-		$$.reg = $3;
-	}
-|	ioreg
-
-imsr:
-	reg
-|	imm
-|	shift
-
-imm:	'$' con
-	{
-		$$ = nullgen;
-		$$.type = D_CONST;
-		$$.offset = $2;
-	}
-
-reg:
-	spreg
-	{
-		$$ = nullgen;
-		$$.type = D_REG;
-		$$.reg = $1;
-	}
-
-regreg:
-	'(' spreg ',' spreg ')'
-	{
-		$$ = nullgen;
-		$$.type = D_REGREG;
-		$$.reg = $2;
-		$$.offset = $4;
-	}
-
-shift:
-	spreg '<' '<' rcon
-	{
-		$$ = nullgen;
-		$$.type = D_SHIFT;
-		$$.offset = $1 | $4 | (0 << 5);
-	}
-|	spreg '>' '>' rcon
-	{
-		$$ = nullgen;
-		$$.type = D_SHIFT;
-		$$.offset = $1 | $4 | (1 << 5);
-	}
-|	spreg '-' '>' rcon
-	{
-		$$ = nullgen;
-		$$.type = D_SHIFT;
-		$$.offset = $1 | $4 | (2 << 5);
-	}
-|	spreg LAT '>' rcon
-	{
-		$$ = nullgen;
-		$$.type = D_SHIFT;
-		$$.offset = $1 | $4 | (3 << 5);
-	}
-
-rcon:
-	spreg
-	{
-		if($$ < 0 || $$ >= 16)
-			print("register value out of range\n");
-		$$ = (($1&15) << 8) | (1 << 4);
-	}
-|	con
-	{
-		if($$ < 0 || $$ >= 32)
-			print("shift value out of range\n");
-		$$ = ($1&31) << 7;
-	}
-
-sreg:
-	LREG
-|	LPC
-	{
-		$$ = REGPC;
-	}
-|	LR '(' expr ')'
-	{
-		if($3 < 0 || $3 >= NREG)
-			print("register value out of range\n");
-		$$ = $3;
-	}
-
-spreg:
-	sreg
-|	LSP
-	{
-		$$ = REGSP;
-	}
-
-creg:
-	LCREG
-|	LC '(' expr ')'
-	{
-		if($3 < 0 || $3 >= NREG)
-			print("register value out of range\n");
-		$$ = $3;
-	}
-
-frcon:
-	freg
-|	fcon
-
-freg:
-	LFREG
-	{
-		$$ = nullgen;
-		$$.type = D_FREG;
-		$$.reg = $1;
-	}
-|	LF '(' con ')'
-	{
-		$$ = nullgen;
-		$$.type = D_FREG;
-		$$.reg = $3;
-	}
-
-name:
-	con '(' pointer ')'
-	{
-		$$ = nullgen;
-		$$.type = D_OREG;
-		$$.name = $3;
-		$$.sym = nil;
-		$$.offset = $1;
-	}
-|	LNAME offset '(' pointer ')'
-	{
-		$$ = nullgen;
-		$$.type = D_OREG;
-		$$.name = $4;
-		$$.sym = linklookup(ctxt, $1->name, 0);
-		$$.offset = $2;
-	}
-|	LNAME '<' '>' offset '(' LSB ')'
-	{
-		$$ = nullgen;
-		$$.type = D_OREG;
-		$$.name = D_STATIC;
-		$$.sym = linklookup(ctxt, $1->name, 1);
-		$$.offset = $4;
-	}
-
-offset:
-	{
-		$$ = 0;
-	}
-|	'+' con
-	{
-		$$ = $2;
-	}
-|	'-' con
-	{
-		$$ = -$2;
-	}
-
-pointer:
-	LSB
-|	LSP
-|	LFP
-
-con:
-	LCONST
-|	LVAR
-	{
-		$$ = $1->value;
-	}
-|	'-' con
-	{
-		$$ = -$2;
-	}
-|	'+' con
-	{
-		$$ = $2;
-	}
-|	'~' con
-	{
-		$$ = ~$2;
-	}
-|	'(' expr ')'
-	{
-		$$ = $2;
-	}
-
-oexpr:
-	{
-		$$ = 0;
-	}
-|	',' expr
-	{
-		$$ = $2;
-	}
-
-expr:
-	con
-|	expr '+' expr
-	{
-		$$ = $1 + $3;
-	}
-|	expr '-' expr
-	{
-		$$ = $1 - $3;
-	}
-|	expr '*' expr
-	{
-		$$ = $1 * $3;
-	}
-|	expr '/' expr
-	{
-		$$ = $1 / $3;
-	}
-|	expr '%' expr
-	{
-		$$ = $1 % $3;
-	}
-|	expr '<' '<' expr
-	{
-		$$ = $1 << $4;
-	}
-|	expr '>' '>' expr
-	{
-		$$ = $1 >> $4;
-	}
-|	expr '&' expr
-	{
-		$$ = $1 & $3;
-	}
-|	expr '^' expr
-	{
-		$$ = $1 ^ $3;
-	}
-|	expr '|' expr
-	{
-		$$ = $1 | $3;
-	}
diff --git a/src/cmd/5a/doc.go b/src/cmd/5a/doc.go
deleted file mode 100644
index 3e9e78f..0000000
--- a/src/cmd/5a/doc.go
+++ /dev/null
@@ -1,20 +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.
-
-// +build ignore
-
-/*
-
-5a is a version of the Plan 9 assembler.  The original is documented at
-
-	http://plan9.bell-labs.com/magic/man2html/1/8a
-
-Go-specific considerations are documented at
-
-	http://golang.org/doc/asm
-
-Its target architecture is the ARM, referred to by these tools as arm.
-
-*/
-package main
diff --git a/src/cmd/5a/lex.c b/src/cmd/5a/lex.c
deleted file mode 100644
index 9c69709..0000000
--- a/src/cmd/5a/lex.c
+++ /dev/null
@@ -1,538 +0,0 @@
-// Inferno utils/5a/lex.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5a/lex.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.	All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#define	EXTERN
-#include <u.h>
-#include <libc.h>
-#include "a.h"
-#include "y.tab.h"
-
-enum
-{
-	Plan9	= 1<<0,
-	Unix	= 1<<1,
-	Windows	= 1<<2,
-};
-
-int
-systemtype(int sys)
-{
-#ifdef _WIN32
-	return sys&Windows;
-#else
-	return sys&Plan9;
-#endif
-}
-
-int
-Lconv(Fmt *fp)
-{
-	return linklinefmt(ctxt, fp);
-}
-
-void
-dodef(char *p)
-{
-	if(nDlist%8 == 0)
-		Dlist = allocn(Dlist, nDlist*sizeof(char *),
-			8*sizeof(char *));
-	Dlist[nDlist++] = p;
-}
-
-void
-usage(void)
-{
-	print("usage: %ca [options] file.c...\n", thechar);
-	flagprint(1);
-	errorexit();
-}
-
-void
-main(int argc, char *argv[])
-{
-	char *p;
-
-	thechar = '5';
-	thestring = "arm";
-
-	ctxt = linknew(&linkarm);
-	ctxt->diag = yyerror;
-	ctxt->bso = &bstdout;
-	ctxt->enforce_data_order = 1;
-	Binit(&bstdout, 1, OWRITE);
-	listinit5();
-	fmtinstall('L', Lconv);
-
-	// Allow GOARCH=thestring or GOARCH=thestringsuffix,
-	// but not other values.	
-	p = getgoarch();
-	if(strncmp(p, thestring, strlen(thestring)) != 0)
-		sysfatal("cannot use %cc with GOARCH=%s", thechar, p);
-
-	ensuresymb(NSYMB);
-	memset(debug, 0, sizeof(debug));
-	cinit();
-	outfile = 0;
-	setinclude(".");
-	
-	flagfn1("D", "name[=value]: add #define", dodef);
-	flagfn1("I", "dir: add dir to include path", setinclude);
-	flagcount("S", "print assembly and machine code", &debug['S']);
-	flagcount("m", "debug preprocessor macros", &debug['m']);
-	flagstr("o", "file: set output file", &outfile);
-	flagstr("trimpath", "prefix: remove prefix from recorded source file paths", &ctxt->trimpath);
-
-	flagparse(&argc, &argv, usage);
-	ctxt->debugasm = debug['S'];
-
-	if(argc < 1)
-		usage();
-	if(argc > 1){
-		print("can't assemble multiple files\n");
-		errorexit();
-	}
-
-	if(assemble(argv[0]))
-		errorexit();
-	Bflush(&bstdout);
-	exits(0);
-}
-
-int
-assemble(char *file)
-{
-	char *ofile, *p;
-	int i, of;
-
-	ofile = alloc(strlen(file)+3); // +3 for .x\0 (x=thechar)
-	strcpy(ofile, file);
-	p = utfrrune(ofile, '/');
-	if(p) {
-		include[0] = ofile;
-		*p++ = 0;
-	} else
-		p = ofile;
-	if(outfile == 0) {
-		outfile = p;
-		if(outfile){
-			p = utfrrune(outfile, '.');
-			if(p)
-				if(p[1] == 's' && p[2] == 0)
-					p[0] = 0;
-			p = utfrune(outfile, 0);
-			p[0] = '.';
-			p[1] = thechar;
-			p[2] = 0;
-		} else
-			outfile = "/dev/null";
-	}
-
-	of = create(outfile, OWRITE, 0664);
-	if(of < 0) {
-		yyerror("%ca: cannot create %s", thechar, outfile);
-		errorexit();
-	}
-	Binit(&obuf, of, OWRITE);
-	Bprint(&obuf, "go object %s %s %s\n", getgoos(), getgoarch(), getgoversion());
-	Bprint(&obuf, "!\n");
-
-	for(pass = 1; pass <= 2; pass++) {
-		pinit(file);
-		for(i=0; i<nDlist; i++)
-			dodefine(Dlist[i]);
-		yyparse();
-		cclean();
-		if(nerrors)
-			return nerrors;
-	}
-
-	writeobj(ctxt, &obuf);
-	Bflush(&obuf);
-	return 0;
-}
-
-struct
-{
-	char	*name;
-	ushort	type;
-	ushort	value;
-} itab[] =
-{
-	"SP",		LSP,	D_AUTO,
-	"SB",		LSB,	D_EXTERN,
-	"FP",		LFP,	D_PARAM,
-	"PC",		LPC,	D_BRANCH,
-
-	"R",		LR,	0,
-	"R0",		LREG,	0,
-	"R1",		LREG,	1,
-	"R2",		LREG,	2,
-	"R3",		LREG,	3,
-	"R4",		LREG,	4,
-	"R5",		LREG,	5,
-	"R6",		LREG,	6,
-	"R7",		LREG,	7,
-	"R8",		LREG,	8,
-	"R9",		LREG,	9,
-	"g",		LREG,	10, // avoid unintentionally clobber g using R10
-	"R11",		LREG,	11,
-	"R12",		LREG,	12,
-	"R13",		LREG,	13,
-	"R14",		LREG,	14,
-	"R15",		LREG,	15,
-
-	"F",		LF,	0,
-
-	"F0",		LFREG,	0,
-	"F1",		LFREG,	1,
-	"F2",		LFREG,	2,
-	"F3",		LFREG,	3,
-	"F4",		LFREG,	4,
-	"F5",		LFREG,	5,
-	"F6",		LFREG,	6,
-	"F7",		LFREG,	7,
-	"F8",		LFREG,	8,
-	"F9",		LFREG,	9,
-	"F10",		LFREG,	10,
-	"F11",		LFREG,	11,
-	"F12",		LFREG,	12,
-	"F13",		LFREG,	13,
-	"F14",		LFREG,	14,
-	"F15",		LFREG,	15,
-
-	"C",		LC,	0,
-
-	"C0",		LCREG,	0,
-	"C1",		LCREG,	1,
-	"C2",		LCREG,	2,
-	"C3",		LCREG,	3,
-	"C4",		LCREG,	4,
-	"C5",		LCREG,	5,
-	"C6",		LCREG,	6,
-	"C7",		LCREG,	7,
-	"C8",		LCREG,	8,
-	"C9",		LCREG,	9,
-	"C10",		LCREG,	10,
-	"C11",		LCREG,	11,
-	"C12",		LCREG,	12,
-	"C13",		LCREG,	13,
-	"C14",		LCREG,	14,
-	"C15",		LCREG,	15,
-
-	"CPSR",		LPSR,	0,
-	"SPSR",		LPSR,	1,
-
-	"FPSR",		LFCR,	0,
-	"FPCR",		LFCR,	1,
-
-	".EQ",		LCOND,	0,
-	".NE",		LCOND,	1,
-	".CS",		LCOND,	2,
-	".HS",		LCOND,	2,
-	".CC",		LCOND,	3,
-	".LO",		LCOND,	3,
-	".MI",		LCOND,	4,
-	".PL",		LCOND,	5,
-	".VS",		LCOND,	6,
-	".VC",		LCOND,	7,
-	".HI",		LCOND,	8,
-	".LS",		LCOND,	9,
-	".GE",		LCOND,	10,
-	".LT",		LCOND,	11,
-	".GT",		LCOND,	12,
-	".LE",		LCOND,	13,
-	".AL",		LCOND,	Always,
-
-	".U",		LS,	C_UBIT,
-	".S",		LS,	C_SBIT,
-	".W",		LS,	C_WBIT,
-	".P",		LS,	C_PBIT,
-	".PW",		LS,	C_WBIT|C_PBIT,
-	".WP",		LS,	C_WBIT|C_PBIT,
-
-	".F",		LS,	C_FBIT,
-
-	".IBW",		LS,	C_WBIT|C_PBIT|C_UBIT,
-	".IAW",		LS,	C_WBIT|C_UBIT,
-	".DBW",		LS,	C_WBIT|C_PBIT,
-	".DAW",		LS,	C_WBIT,
-	".IB",		LS,	C_PBIT|C_UBIT,
-	".IA",		LS,	C_UBIT,
-	".DB",		LS,	C_PBIT,
-	".DA",		LS,	0,
-
-	"@",		LAT,	0,
-
-	"AND",		LTYPE1,	AAND,
-	"EOR",		LTYPE1,	AEOR,
-	"SUB",		LTYPE1,	ASUB,
-	"RSB",		LTYPE1,	ARSB,
-	"ADD",		LTYPE1,	AADD,
-	"ADC",		LTYPE1,	AADC,
-	"SBC",		LTYPE1,	ASBC,
-	"RSC",		LTYPE1,	ARSC,
-	"ORR",		LTYPE1,	AORR,
-	"BIC",		LTYPE1,	ABIC,
-
-	"SLL",		LTYPE1,	ASLL,
-	"SRL",		LTYPE1,	ASRL,
-	"SRA",		LTYPE1,	ASRA,
-
-	"MUL",		LTYPE1, AMUL,
-	"MULA",		LTYPEN, AMULA,
-	"DIV",		LTYPE1,	ADIV,
-	"MOD",		LTYPE1,	AMOD,
-
-	"MULL",		LTYPEM, AMULL,
-	"MULAL",	LTYPEM, AMULAL,
-	"MULLU",	LTYPEM, AMULLU,
-	"MULALU",	LTYPEM, AMULALU,
-
-	"MVN",		LTYPE2, AMVN,	/* op2 ignored */
-
-	"MOVB",		LTYPE3, AMOVB,
-	"MOVBU",	LTYPE3, AMOVBU,
-	"MOVH",		LTYPE3, AMOVH,
-	"MOVHU",	LTYPE3, AMOVHU,
-	"MOVW",		LTYPE3, AMOVW,
-
-	"MOVD",		LTYPE3, AMOVD,
-	"MOVDF",		LTYPE3, AMOVDF,
-	"MOVDW",	LTYPE3, AMOVDW,
-	"MOVF",		LTYPE3, AMOVF,
-	"MOVFD",		LTYPE3, AMOVFD,
-	"MOVFW",		LTYPE3, AMOVFW,
-	"MOVWD",	LTYPE3, AMOVWD,
-	"MOVWF",		LTYPE3, AMOVWF,
-
-	"LDREX",		LTYPE3, ALDREX,
-	"LDREXD",		LTYPE3, ALDREXD,
-	"STREX",		LTYPE9, ASTREX,
-	"STREXD",		LTYPE9, ASTREXD,
-
-/*
-	"NEGF",		LTYPEI, ANEGF,
-	"NEGD",		LTYPEI, ANEGD,
-	"SQTF",		LTYPEI,	ASQTF,
-	"SQTD",		LTYPEI,	ASQTD,
-	"RNDF",		LTYPEI,	ARNDF,
-	"RNDD",		LTYPEI,	ARNDD,
-	"URDF",		LTYPEI,	AURDF,
-	"URDD",		LTYPEI,	AURDD,
-	"NRMF",		LTYPEI,	ANRMF,
-	"NRMD",		LTYPEI,	ANRMD,
-*/
-
-	"ABSF",		LTYPEI, AABSF,
-	"ABSD",		LTYPEI, AABSD,
-	"SQRTF",	LTYPEI, ASQRTF,
-	"SQRTD",	LTYPEI, ASQRTD,
-	"CMPF",		LTYPEL, ACMPF,
-	"CMPD",		LTYPEL, ACMPD,
-	"ADDF",		LTYPEK,	AADDF,
-	"ADDD",		LTYPEK,	AADDD,
-	"SUBF",		LTYPEK,	ASUBF,
-	"SUBD",		LTYPEK,	ASUBD,
-	"MULF",		LTYPEK,	AMULF,
-	"MULD",		LTYPEK,	AMULD,
-	"DIVF",		LTYPEK,	ADIVF,
-	"DIVD",		LTYPEK,	ADIVD,
-
-	"B",		LTYPE4, AB,
-	"BL",		LTYPE4, ABL,
-	"BX",		LTYPEBX,	ABX,
-
-	"BEQ",		LTYPE5,	ABEQ,
-	"BNE",		LTYPE5,	ABNE,
-	"BCS",		LTYPE5,	ABCS,
-	"BHS",		LTYPE5,	ABHS,
-	"BCC",		LTYPE5,	ABCC,
-	"BLO",		LTYPE5,	ABLO,
-	"BMI",		LTYPE5,	ABMI,
-	"BPL",		LTYPE5,	ABPL,
-	"BVS",		LTYPE5,	ABVS,
-	"BVC",		LTYPE5,	ABVC,
-	"BHI",		LTYPE5,	ABHI,
-	"BLS",		LTYPE5,	ABLS,
-	"BGE",		LTYPE5,	ABGE,
-	"BLT",		LTYPE5,	ABLT,
-	"BGT",		LTYPE5,	ABGT,
-	"BLE",		LTYPE5,	ABLE,
-	"BCASE",	LTYPE5,	ABCASE,
-
-	"SWI",		LTYPE6, ASWI,
-
-	"CMP",		LTYPE7,	ACMP,
-	"TST",		LTYPE7,	ATST,
-	"TEQ",		LTYPE7,	ATEQ,
-	"CMN",		LTYPE7,	ACMN,
-
-	"MOVM",		LTYPE8, AMOVM,
-
-	"SWPBU",	LTYPE9, ASWPBU,
-	"SWPW",		LTYPE9, ASWPW,
-
-	"RET",		LTYPEA, ARET,
-	"RFE",		LTYPEA, ARFE,
-
-	"TEXT",		LTYPEB, ATEXT,
-	"GLOBL",	LTYPEB, AGLOBL,
-	"DATA",		LTYPEC, ADATA,
-	"CASE",		LTYPED, ACASE,
-	"END",		LTYPEE, AEND,
-	"WORD",		LTYPEH, AWORD,
-	"NOP",		LTYPEI, ANOP,
-
-	"MCR",		LTYPEJ, 0,
-	"MRC",		LTYPEJ, 1,
-
-	"PLD",		LTYPEPLD, APLD,
-	"UNDEF",	LTYPEE,	AUNDEF,
-	"CLZ",		LTYPE2, ACLZ,
-
-	"MULWT",	LTYPE1, AMULWT,
-	"MULWB",	LTYPE1, AMULWB,
-	"MULAWT",	LTYPEN, AMULAWT,
-	"MULAWB",	LTYPEN, AMULAWB,
-
-	"USEFIELD",	LTYPEN, AUSEFIELD,
-	"PCDATA",	LTYPEPC,	APCDATA,
-	"FUNCDATA",	LTYPEF,	AFUNCDATA,
-
-	0
-};
-
-void
-cinit(void)
-{
-	Sym *s;
-	int i;
-
-	nullgen.type = D_NONE;
-	nullgen.name = D_NONE;
-	nullgen.reg = NREG;
-
-	nerrors = 0;
-	iostack = I;
-	iofree = I;
-	peekc = IGN;
-	nhunk = 0;
-	for(i=0; i<NHASH; i++)
-		hash[i] = S;
-	for(i=0; itab[i].name; i++) {
-		s = slookup(itab[i].name);
-		s->type = itab[i].type;
-		s->value = itab[i].value;
-	}
-}
-
-void
-syminit(Sym *s)
-{
-
-	s->type = LNAME;
-	s->value = 0;
-}
-
-int
-isreg(Addr *g)
-{
-
-	USED(g);
-	return 1;
-}
-
-void
-cclean(void)
-{
-	outcode(AEND, Always, &nullgen, NREG, &nullgen);
-}
-
-static int bcode[] =
-{
-	ABEQ,
-	ABNE,
-	ABCS,
-	ABCC,
-	ABMI,
-	ABPL,
-	ABVS,
-	ABVC,
-	ABHI,
-	ABLS,
-	ABGE,
-	ABLT,
-	ABGT,
-	ABLE,
-	AB,
-	ANOP,
-};
-
-static Prog *lastpc;
-
-void
-outcode(int a, int scond, Addr *g1, int reg, Addr *g2)
-{
-	Prog *p;
-	Plist *pl;
-
-	/* hack to make B.NE etc. work: turn it into the corresponding conditional */
-	if(a == AB){
-		a = bcode[scond&0xf];
-		scond = (scond & ~0xf) | Always;
-	}
-
-	if(pass == 1)
-		goto out;
-	
-	p = malloc(sizeof *p);
-	memset(p, 0, sizeof *p);
-	p->as = a;
-	p->lineno = stmtline;
-	p->scond = scond;
-	p->from = *g1;
-	p->reg = reg;
-	p->to = *g2;
-	p->pc = pc;
-
-	if(lastpc == nil) {
-		pl = linknewplist(ctxt);
-		pl->firstpc = p;
-	} else
-		lastpc->link = p;
-	lastpc = p;	
-
-out:
-	if(a != AGLOBL && a != ADATA)
-		pc++;
-}
-
-#include "../cc/lexbody"
-#include "../cc/macbody"
diff --git a/src/cmd/5a/y.tab.c b/src/cmd/5a/y.tab.c
deleted file mode 100644
index a6251b8..0000000
--- a/src/cmd/5a/y.tab.c
+++ /dev/null
@@ -1,2936 +0,0 @@
-/* A Bison parser, made by GNU Bison 2.7.12-4996.  */
-
-/* Bison implementation for Yacc-like parsers in C
-   
-      Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
-   
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-   
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-   
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
-
-/* As a special exception, you may create a larger work that contains
-   part or all of the Bison parser skeleton and distribute that work
-   under terms of your choice, so long as that work isn't itself a
-   parser generator using the skeleton or a modified version thereof
-   as a parser skeleton.  Alternatively, if you modify or redistribute
-   the parser skeleton itself, you may (at your option) remove this
-   special exception, which will cause the skeleton and the resulting
-   Bison output files to be licensed under the GNU General Public
-   License without this special exception.
-   
-   This special exception was added by the Free Software Foundation in
-   version 2.2 of Bison.  */
-
-/* C LALR(1) parser skeleton written by Richard Stallman, by
-   simplifying the original so-called "semantic" parser.  */
-
-/* All symbols defined below should begin with yy or YY, to avoid
-   infringing on user name space.  This should be done even for local
-   variables, as they might otherwise be expanded by user macros.
-   There are some unavoidable exceptions within include files to
-   define necessary library symbols; they are noted "INFRINGES ON
-   USER NAME SPACE" below.  */
-
-/* Identify Bison output.  */
-#define YYBISON 1
-
-/* Bison version.  */
-#define YYBISON_VERSION "2.7.12-4996"
-
-/* Skeleton name.  */
-#define YYSKELETON_NAME "yacc.c"
-
-/* Pure parsers.  */
-#define YYPURE 0
-
-/* Push parsers.  */
-#define YYPUSH 0
-
-/* Pull parsers.  */
-#define YYPULL 1
-
-
-
-
-/* Copy the first part of user declarations.  */
-/* Line 371 of yacc.c  */
-#line 31 "a.y"
-
-#include <u.h>
-#include <stdio.h>	/* if we don't, bison will, and a.h re-#defines getc */
-#include <libc.h>
-#include "a.h"
-#include "../../runtime/funcdata.h"
-
-/* Line 371 of yacc.c  */
-#line 76 "y.tab.c"
-
-# ifndef YY_NULL
-#  if defined __cplusplus && 201103L <= __cplusplus
-#   define YY_NULL nullptr
-#  else
-#   define YY_NULL 0
-#  endif
-# endif
-
-/* Enabling verbose error messages.  */
-#ifdef YYERROR_VERBOSE
-# undef YYERROR_VERBOSE
-# define YYERROR_VERBOSE 1
-#else
-# define YYERROR_VERBOSE 0
-#endif
-
-/* In a future release of Bison, this section will be replaced
-   by #include "y.tab.h".  */
-#ifndef YY_YY_Y_TAB_H_INCLUDED
-# define YY_YY_Y_TAB_H_INCLUDED
-/* Enabling traces.  */
-#ifndef YYDEBUG
-# define YYDEBUG 0
-#endif
-#if YYDEBUG
-extern int yydebug;
-#endif
-
-/* Tokens.  */
-#ifndef YYTOKENTYPE
-# define YYTOKENTYPE
-   /* Put the tokens into the symbol table, so that GDB and other debuggers
-      know about them.  */
-   enum yytokentype {
-     LTYPE1 = 258,
-     LTYPE2 = 259,
-     LTYPE3 = 260,
-     LTYPE4 = 261,
-     LTYPE5 = 262,
-     LTYPE6 = 263,
-     LTYPE7 = 264,
-     LTYPE8 = 265,
-     LTYPE9 = 266,
-     LTYPEA = 267,
-     LTYPEB = 268,
-     LTYPEC = 269,
-     LTYPED = 270,
-     LTYPEE = 271,
-     LTYPEG = 272,
-     LTYPEH = 273,
-     LTYPEI = 274,
-     LTYPEJ = 275,
-     LTYPEK = 276,
-     LTYPEL = 277,
-     LTYPEM = 278,
-     LTYPEN = 279,
-     LTYPEBX = 280,
-     LTYPEPLD = 281,
-     LCONST = 282,
-     LSP = 283,
-     LSB = 284,
-     LFP = 285,
-     LPC = 286,
-     LTYPEX = 287,
-     LTYPEPC = 288,
-     LTYPEF = 289,
-     LR = 290,
-     LREG = 291,
-     LF = 292,
-     LFREG = 293,
-     LC = 294,
-     LCREG = 295,
-     LPSR = 296,
-     LFCR = 297,
-     LCOND = 298,
-     LS = 299,
-     LAT = 300,
-     LFCONST = 301,
-     LSCONST = 302,
-     LNAME = 303,
-     LLAB = 304,
-     LVAR = 305
-   };
-#endif
-/* Tokens.  */
-#define LTYPE1 258
-#define LTYPE2 259
-#define LTYPE3 260
-#define LTYPE4 261
-#define LTYPE5 262
-#define LTYPE6 263
-#define LTYPE7 264
-#define LTYPE8 265
-#define LTYPE9 266
-#define LTYPEA 267
-#define LTYPEB 268
-#define LTYPEC 269
-#define LTYPED 270
-#define LTYPEE 271
-#define LTYPEG 272
-#define LTYPEH 273
-#define LTYPEI 274
-#define LTYPEJ 275
-#define LTYPEK 276
-#define LTYPEL 277
-#define LTYPEM 278
-#define LTYPEN 279
-#define LTYPEBX 280
-#define LTYPEPLD 281
-#define LCONST 282
-#define LSP 283
-#define LSB 284
-#define LFP 285
-#define LPC 286
-#define LTYPEX 287
-#define LTYPEPC 288
-#define LTYPEF 289
-#define LR 290
-#define LREG 291
-#define LF 292
-#define LFREG 293
-#define LC 294
-#define LCREG 295
-#define LPSR 296
-#define LFCR 297
-#define LCOND 298
-#define LS 299
-#define LAT 300
-#define LFCONST 301
-#define LSCONST 302
-#define LNAME 303
-#define LLAB 304
-#define LVAR 305
-
-
-
-#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-typedef union YYSTYPE
-{
-/* Line 387 of yacc.c  */
-#line 39 "a.y"
-
-	Sym	*sym;
-	int32	lval;
-	double	dval;
-	char	sval[8];
-	Addr	addr;
-
-
-/* Line 387 of yacc.c  */
-#line 228 "y.tab.c"
-} YYSTYPE;
-# define YYSTYPE_IS_TRIVIAL 1
-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
-# define YYSTYPE_IS_DECLARED 1
-#endif
-
-extern YYSTYPE yylval;
-
-#ifdef YYPARSE_PARAM
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void *YYPARSE_PARAM);
-#else
-int yyparse ();
-#endif
-#else /* ! YYPARSE_PARAM */
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void);
-#else
-int yyparse ();
-#endif
-#endif /* ! YYPARSE_PARAM */
-
-#endif /* !YY_YY_Y_TAB_H_INCLUDED  */
-
-/* Copy the second part of user declarations.  */
-
-/* Line 390 of yacc.c  */
-#line 256 "y.tab.c"
-
-#ifdef short
-# undef short
-#endif
-
-#ifdef YYTYPE_UINT8
-typedef YYTYPE_UINT8 yytype_uint8;
-#else
-typedef unsigned char yytype_uint8;
-#endif
-
-#ifdef YYTYPE_INT8
-typedef YYTYPE_INT8 yytype_int8;
-#elif (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-typedef signed char yytype_int8;
-#else
-typedef short int yytype_int8;
-#endif
-
-#ifdef YYTYPE_UINT16
-typedef YYTYPE_UINT16 yytype_uint16;
-#else
-typedef unsigned short int yytype_uint16;
-#endif
-
-#ifdef YYTYPE_INT16
-typedef YYTYPE_INT16 yytype_int16;
-#else
-typedef short int yytype_int16;
-#endif
-
-#ifndef YYSIZE_T
-# ifdef __SIZE_TYPE__
-#  define YYSIZE_T __SIZE_TYPE__
-# elif defined size_t
-#  define YYSIZE_T size_t
-# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
-#  define YYSIZE_T size_t
-# else
-#  define YYSIZE_T unsigned int
-# endif
-#endif
-
-#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
-
-#ifndef YY_
-# if defined YYENABLE_NLS && YYENABLE_NLS
-#  if ENABLE_NLS
-#   include <libintl.h> /* INFRINGES ON USER NAME SPACE */
-#   define YY_(Msgid) dgettext ("bison-runtime", Msgid)
-#  endif
-# endif
-# ifndef YY_
-#  define YY_(Msgid) Msgid
-# endif
-#endif
-
-#ifndef __attribute__
-/* This feature is available in gcc versions 2.5 and later.  */
-# if (! defined __GNUC__ || __GNUC__ < 2 \
-      || (__GNUC__ == 2 && __GNUC_MINOR__ < 5))
-#  define __attribute__(Spec) /* empty */
-# endif
-#endif
-
-/* Suppress unused-variable warnings by "using" E.  */
-#if ! defined lint || defined __GNUC__
-# define YYUSE(E) ((void) (E))
-#else
-# define YYUSE(E) /* empty */
-#endif
-
-
-/* Identity function, used to suppress warnings about constant conditions.  */
-#ifndef lint
-# define YYID(N) (N)
-#else
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static int
-YYID (int yyi)
-#else
-static int
-YYID (yyi)
-    int yyi;
-#endif
-{
-  return yyi;
-}
-#endif
-
-#if ! defined yyoverflow || YYERROR_VERBOSE
-
-/* The parser invokes alloca or malloc; define the necessary symbols.  */
-
-# ifdef YYSTACK_USE_ALLOCA
-#  if YYSTACK_USE_ALLOCA
-#   ifdef __GNUC__
-#    define YYSTACK_ALLOC __builtin_alloca
-#   elif defined __BUILTIN_VA_ARG_INCR
-#    include <alloca.h> /* INFRINGES ON USER NAME SPACE */
-#   elif defined _AIX
-#    define YYSTACK_ALLOC __alloca
-#   elif defined _MSC_VER
-#    include <malloc.h> /* INFRINGES ON USER NAME SPACE */
-#    define alloca _alloca
-#   else
-#    define YYSTACK_ALLOC alloca
-#    if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-#     include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-      /* Use EXIT_SUCCESS as a witness for stdlib.h.  */
-#     ifndef EXIT_SUCCESS
-#      define EXIT_SUCCESS 0
-#     endif
-#    endif
-#   endif
-#  endif
-# endif
-
-# ifdef YYSTACK_ALLOC
-   /* Pacify GCC's `empty if-body' warning.  */
-#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
-#  ifndef YYSTACK_ALLOC_MAXIMUM
-    /* The OS might guarantee only one guard page at the bottom of the stack,
-       and a page size can be as small as 4096 bytes.  So we cannot safely
-       invoke alloca (N) if N exceeds 4096.  Use a slightly smaller number
-       to allow for a few compiler-allocated temporary stack slots.  */
-#   define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
-#  endif
-# else
-#  define YYSTACK_ALLOC YYMALLOC
-#  define YYSTACK_FREE YYFREE
-#  ifndef YYSTACK_ALLOC_MAXIMUM
-#   define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
-#  endif
-#  if (defined __cplusplus && ! defined EXIT_SUCCESS \
-       && ! ((defined YYMALLOC || defined malloc) \
-	     && (defined YYFREE || defined free)))
-#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-#   ifndef EXIT_SUCCESS
-#    define EXIT_SUCCESS 0
-#   endif
-#  endif
-#  ifndef YYMALLOC
-#   define YYMALLOC malloc
-#   if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
-#   endif
-#  endif
-#  ifndef YYFREE
-#   define YYFREE free
-#   if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-void free (void *); /* INFRINGES ON USER NAME SPACE */
-#   endif
-#  endif
-# endif
-#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
-
-
-#if (! defined yyoverflow \
-     && (! defined __cplusplus \
-	 || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
-
-/* A type that is properly aligned for any stack member.  */
-union yyalloc
-{
-  yytype_int16 yyss_alloc;
-  YYSTYPE yyvs_alloc;
-};
-
-/* The size of the maximum gap between one aligned stack and the next.  */
-# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
-
-/* The size of an array large to enough to hold all stacks, each with
-   N elements.  */
-# define YYSTACK_BYTES(N) \
-     ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
-      + YYSTACK_GAP_MAXIMUM)
-
-# define YYCOPY_NEEDED 1
-
-/* Relocate STACK from its old location to the new one.  The
-   local variables YYSIZE and YYSTACKSIZE give the old and new number of
-   elements in the stack, and YYPTR gives the new location of the
-   stack.  Advance YYPTR to a properly aligned location for the next
-   stack.  */
-# define YYSTACK_RELOCATE(Stack_alloc, Stack)				\
-    do									\
-      {									\
-	YYSIZE_T yynewbytes;						\
-	YYCOPY (&yyptr->Stack_alloc, Stack, yysize);			\
-	Stack = &yyptr->Stack_alloc;					\
-	yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
-	yyptr += yynewbytes / sizeof (*yyptr);				\
-      }									\
-    while (YYID (0))
-
-#endif
-
-#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
-/* Copy COUNT objects from SRC to DST.  The source and destination do
-   not overlap.  */
-# ifndef YYCOPY
-#  if defined __GNUC__ && 1 < __GNUC__
-#   define YYCOPY(Dst, Src, Count) \
-      __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src)))
-#  else
-#   define YYCOPY(Dst, Src, Count)              \
-      do                                        \
-        {                                       \
-          YYSIZE_T yyi;                         \
-          for (yyi = 0; yyi < (Count); yyi++)   \
-            (Dst)[yyi] = (Src)[yyi];            \
-        }                                       \
-      while (YYID (0))
-#  endif
-# endif
-#endif /* !YYCOPY_NEEDED */
-
-/* YYFINAL -- State number of the termination state.  */
-#define YYFINAL  2
-/* YYLAST -- Last index in YYTABLE.  */
-#define YYLAST   609
-
-/* YYNTOKENS -- Number of terminals.  */
-#define YYNTOKENS  71
-/* YYNNTS -- Number of nonterminals.  */
-#define YYNNTS  35
-/* YYNRULES -- Number of rules.  */
-#define YYNRULES  133
-/* YYNRULES -- Number of states.  */
-#define YYNSTATES  339
-
-/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
-#define YYUNDEFTOK  2
-#define YYMAXUTOK   305
-
-#define YYTRANSLATE(YYX)						\
-  ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
-
-/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX.  */
-static const yytype_uint8 yytranslate[] =
-{
-       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,    69,    12,     5,     2,
-      67,    68,    10,     8,    64,     9,     2,    11,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,    61,    63,
-       6,    62,     7,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,    65,     2,    66,     4,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     3,     2,    70,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     1,     2,    13,    14,
-      15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
-      25,    26,    27,    28,    29,    30,    31,    32,    33,    34,
-      35,    36,    37,    38,    39,    40,    41,    42,    43,    44,
-      45,    46,    47,    48,    49,    50,    51,    52,    53,    54,
-      55,    56,    57,    58,    59,    60
-};
-
-#if YYDEBUG
-/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
-   YYRHS.  */
-static const yytype_uint16 yyprhs[] =
-{
-       0,     0,     3,     4,     5,     9,    10,    15,    16,    21,
-      26,    31,    33,    36,    39,    47,    54,    60,    66,    72,
-      77,    82,    86,    90,    95,   102,   110,   118,   126,   133,
-     140,   144,   149,   156,   165,   172,   177,   181,   187,   193,
-     201,   208,   221,   229,   239,   242,   247,   252,   255,   256,
-     259,   262,   263,   266,   271,   274,   277,   280,   283,   288,
-     291,   293,   296,   300,   302,   306,   310,   312,   314,   316,
-     321,   323,   325,   327,   329,   331,   333,   335,   339,   341,
-     346,   348,   353,   355,   357,   359,   361,   364,   366,   372,
-     377,   382,   387,   392,   394,   396,   398,   400,   405,   407,
-     409,   411,   416,   418,   420,   422,   427,   432,   438,   446,
-     447,   450,   453,   455,   457,   459,   461,   463,   466,   469,
-     472,   476,   477,   480,   482,   486,   490,   494,   498,   502,
-     507,   512,   516,   520
-};
-
-/* YYRHS -- A `-1'-separated list of the rules' RHS.  */
-static const yytype_int8 yyrhs[] =
-{
-      72,     0,    -1,    -1,    -1,    72,    73,    74,    -1,    -1,
-      59,    61,    75,    74,    -1,    -1,    58,    61,    76,    74,
-      -1,    58,    62,   105,    63,    -1,    60,    62,   105,    63,
-      -1,    63,    -1,    77,    63,    -1,     1,    63,    -1,    13,
-      78,    89,    64,    96,    64,    91,    -1,    13,    78,    89,
-      64,    96,    64,    -1,    13,    78,    89,    64,    91,    -1,
-      14,    78,    89,    64,    91,    -1,    15,    78,    84,    64,
-      84,    -1,    16,    78,    79,    80,    -1,    16,    78,    79,
-      85,    -1,    35,    79,    86,    -1,    17,    79,    80,    -1,
-      18,    78,    79,    84,    -1,    19,    78,    89,    64,    96,
-      79,    -1,    20,    78,    87,    64,    65,    83,    66,    -1,
-      20,    78,    65,    83,    66,    64,    87,    -1,    21,    78,
-      91,    64,    86,    64,    91,    -1,    21,    78,    91,    64,
-      86,    79,    -1,    21,    78,    79,    86,    64,    91,    -1,
-      22,    78,    79,    -1,    23,   100,    64,    90,    -1,    23,
-     100,    64,   103,    64,    90,    -1,    23,   100,    64,   103,
-      64,    90,     9,   103,    -1,    24,   100,    11,   103,    64,
-      81,    -1,    25,    78,    91,    79,    -1,    28,    79,    81,
-      -1,    29,    78,    99,    64,    99,    -1,    31,    78,    98,
-      64,    99,    -1,    31,    78,    98,    64,    48,    64,    99,
-      -1,    32,    78,    99,    64,    99,    79,    -1,    30,    78,
-     103,    64,   105,    64,    96,    64,    97,    64,    97,   104,
-      -1,    33,    78,    91,    64,    91,    64,    92,    -1,    34,
-      78,    91,    64,    91,    64,    91,    64,    96,    -1,    36,
-      88,    -1,    43,    84,    64,    84,    -1,    44,    84,    64,
-      84,    -1,    26,    79,    -1,    -1,    78,    53,    -1,    78,
-      54,    -1,    -1,    64,    79,    -1,   103,    67,    41,    68,
-      -1,    58,   101,    -1,    59,   101,    -1,    69,   103,    -1,
-      69,    88,    -1,    69,    10,    69,    88,    -1,    69,    57,
-      -1,    82,    -1,    69,    56,    -1,    69,     9,    56,    -1,
-      96,    -1,    96,     9,    96,    -1,    96,    79,    83,    -1,
-      91,    -1,    81,    -1,    93,    -1,    93,    67,    96,    68,
-      -1,    51,    -1,    52,    -1,   103,    -1,    88,    -1,    99,
-      -1,    86,    -1,   100,    -1,    67,    96,    68,    -1,    86,
-      -1,   103,    67,    95,    68,    -1,   100,    -1,   100,    67,
-      95,    68,    -1,    87,    -1,    91,    -1,    90,    -1,    93,
-      -1,    69,   103,    -1,    96,    -1,    67,    96,    64,    96,
-      68,    -1,    96,     6,     6,    94,    -1,    96,     7,     7,
-      94,    -1,    96,     9,     7,    94,    -1,    96,    55,     7,
-      94,    -1,    96,    -1,   103,    -1,    46,    -1,    41,    -1,
-      45,    67,   105,    68,    -1,    95,    -1,    38,    -1,    50,
-      -1,    49,    67,   105,    68,    -1,    99,    -1,    82,    -1,
-      48,    -1,    47,    67,   103,    68,    -1,   103,    67,   102,
-      68,    -1,    58,   101,    67,   102,    68,    -1,    58,     6,
-       7,   101,    67,    39,    68,    -1,    -1,     8,   103,    -1,
-       9,   103,    -1,    39,    -1,    38,    -1,    40,    -1,    37,
-      -1,    60,    -1,     9,   103,    -1,     8,   103,    -1,    70,
-     103,    -1,    67,   105,    68,    -1,    -1,    64,   105,    -1,
-     103,    -1,   105,     8,   105,    -1,   105,     9,   105,    -1,
-     105,    10,   105,    -1,   105,    11,   105,    -1,   105,    12,
-     105,    -1,   105,     6,     6,   105,    -1,   105,     7,     7,
-     105,    -1,   105,     5,   105,    -1,   105,     4,   105,    -1,
-     105,     3,   105,    -1
-};
-
-/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
-static const yytype_uint16 yyrline[] =
-{
-       0,    68,    68,    70,    69,    77,    76,    84,    83,    89,
-      94,   100,   101,   102,   108,   112,   116,   123,   130,   137,
-     141,   148,   155,   162,   169,   176,   185,   197,   201,   205,
-     212,   219,   225,   231,   240,   247,   254,   261,   265,   269,
-     273,   280,   302,   310,   319,   326,   335,   346,   352,   355,
-     359,   364,   365,   368,   374,   382,   389,   395,   400,   405,
-     411,   414,   420,   428,   432,   441,   447,   448,   449,   450,
-     455,   461,   467,   473,   474,   477,   478,   486,   495,   496,
-     505,   506,   512,   515,   516,   517,   519,   527,   535,   544,
-     550,   556,   562,   570,   576,   584,   585,   589,   597,   598,
-     604,   605,   613,   614,   617,   623,   631,   639,   647,   657,
-     660,   664,   670,   671,   672,   675,   676,   680,   684,   688,
-     692,   698,   701,   707,   708,   712,   716,   720,   724,   728,
-     732,   736,   740,   744
-};
-#endif
-
-#if YYDEBUG || YYERROR_VERBOSE || 0
-/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
-   First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
-static const char *const yytname[] =
-{
-  "$end", "error", "$undefined", "'|'", "'^'", "'&'", "'<'", "'>'", "'+'",
-  "'-'", "'*'", "'/'", "'%'", "LTYPE1", "LTYPE2", "LTYPE3", "LTYPE4",
-  "LTYPE5", "LTYPE6", "LTYPE7", "LTYPE8", "LTYPE9", "LTYPEA", "LTYPEB",
-  "LTYPEC", "LTYPED", "LTYPEE", "LTYPEG", "LTYPEH", "LTYPEI", "LTYPEJ",
-  "LTYPEK", "LTYPEL", "LTYPEM", "LTYPEN", "LTYPEBX", "LTYPEPLD", "LCONST",
-  "LSP", "LSB", "LFP", "LPC", "LTYPEX", "LTYPEPC", "LTYPEF", "LR", "LREG",
-  "LF", "LFREG", "LC", "LCREG", "LPSR", "LFCR", "LCOND", "LS", "LAT",
-  "LFCONST", "LSCONST", "LNAME", "LLAB", "LVAR", "':'", "'='", "';'",
-  "','", "'['", "']'", "'('", "')'", "'$'", "'~'", "$accept", "prog",
-  "$@1", "line", "$@2", "$@3", "inst", "cond", "comma", "rel", "ximm",
-  "fcon", "reglist", "gen", "nireg", "ireg", "ioreg", "oreg", "imsr",
-  "imm", "reg", "regreg", "shift", "rcon", "sreg", "spreg", "creg",
-  "frcon", "freg", "name", "offset", "pointer", "con", "oexpr", "expr", YY_NULL
-};
-#endif
-
-# ifdef YYPRINT
-/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
-   token YYLEX-NUM.  */
-static const yytype_uint16 yytoknum[] =
-{
-       0,   256,   257,   124,    94,    38,    60,    62,    43,    45,
-      42,    47,    37,   258,   259,   260,   261,   262,   263,   264,
-     265,   266,   267,   268,   269,   270,   271,   272,   273,   274,
-     275,   276,   277,   278,   279,   280,   281,   282,   283,   284,
-     285,   286,   287,   288,   289,   290,   291,   292,   293,   294,
-     295,   296,   297,   298,   299,   300,   301,   302,   303,   304,
-     305,    58,    61,    59,    44,    91,    93,    40,    41,    36,
-     126
-};
-# endif
-
-/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
-static const yytype_uint8 yyr1[] =
-{
-       0,    71,    72,    73,    72,    75,    74,    76,    74,    74,
-      74,    74,    74,    74,    77,    77,    77,    77,    77,    77,
-      77,    77,    77,    77,    77,    77,    77,    77,    77,    77,
-      77,    77,    77,    77,    77,    77,    77,    77,    77,    77,
-      77,    77,    77,    77,    77,    77,    77,    77,    78,    78,
-      78,    79,    79,    80,    80,    80,    81,    81,    81,    81,
-      81,    82,    82,    83,    83,    83,    84,    84,    84,    84,
-      84,    84,    84,    84,    84,    85,    85,    86,    87,    87,
-      88,    88,    88,    89,    89,    89,    90,    91,    92,    93,
-      93,    93,    93,    94,    94,    95,    95,    95,    96,    96,
-      97,    97,    98,    98,    99,    99,   100,   100,   100,   101,
-     101,   101,   102,   102,   102,   103,   103,   103,   103,   103,
-     103,   104,   104,   105,   105,   105,   105,   105,   105,   105,
-     105,   105,   105,   105
-};
-
-/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
-static const yytype_uint8 yyr2[] =
-{
-       0,     2,     0,     0,     3,     0,     4,     0,     4,     4,
-       4,     1,     2,     2,     7,     6,     5,     5,     5,     4,
-       4,     3,     3,     4,     6,     7,     7,     7,     6,     6,
-       3,     4,     6,     8,     6,     4,     3,     5,     5,     7,
-       6,    12,     7,     9,     2,     4,     4,     2,     0,     2,
-       2,     0,     2,     4,     2,     2,     2,     2,     4,     2,
-       1,     2,     3,     1,     3,     3,     1,     1,     1,     4,
-       1,     1,     1,     1,     1,     1,     1,     3,     1,     4,
-       1,     4,     1,     1,     1,     1,     2,     1,     5,     4,
-       4,     4,     4,     1,     1,     1,     1,     4,     1,     1,
-       1,     4,     1,     1,     1,     4,     4,     5,     7,     0,
-       2,     2,     1,     1,     1,     1,     1,     2,     2,     2,
-       3,     0,     2,     1,     3,     3,     3,     3,     3,     4,
-       4,     3,     3,     3
-};
-
-/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM.
-   Performed when YYTABLE doesn't specify something else to do.  Zero
-   means the default is an error.  */
-static const yytype_uint8 yydefact[] =
-{
-       2,     3,     1,     0,     0,    48,    48,    48,    48,    51,
-      48,    48,    48,    48,    48,     0,     0,    48,    51,    51,
-      48,    48,    48,    48,    48,    48,    51,     0,     0,     0,
-       0,     0,     0,    11,     4,     0,    13,     0,     0,     0,
-      51,    51,     0,    51,     0,     0,    51,    51,     0,     0,
-     115,   109,   116,     0,     0,     0,     0,     0,     0,    47,
-       0,     0,     0,     0,     0,     0,     0,     0,     0,    78,
-      82,    44,    80,     0,    99,    96,     0,    95,     0,   104,
-      70,    71,     0,    67,    60,     0,    73,    66,    68,    98,
-      87,    74,    72,     0,     7,     0,     5,     0,    12,    49,
-      50,     0,     0,    84,    83,    85,     0,     0,     0,    52,
-     109,   109,    22,     0,     0,     0,     0,     0,     0,     0,
-       0,    87,    30,   118,   117,     0,     0,     0,     0,   123,
-       0,   119,     0,     0,     0,    51,    36,     0,     0,     0,
-     103,     0,   102,     0,     0,     0,     0,    21,     0,     0,
-       0,     0,     0,     0,     0,    61,    59,    57,    56,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-      86,     0,     0,     0,   109,    19,    20,    75,    76,     0,
-      54,    55,     0,    23,     0,     0,    51,     0,     0,     0,
-       0,   109,   110,   111,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,   120,    31,     0,   113,   112,
-     114,     0,     0,    35,     0,     0,     0,     0,     0,     0,
-       0,    77,     0,     0,     0,     0,    62,     0,    45,     0,
-       0,     0,     0,     0,    46,     8,     9,     6,    10,    16,
-      87,    17,    18,    54,     0,     0,    51,     0,     0,     0,
-       0,     0,    51,     0,     0,   133,   132,   131,     0,     0,
-     124,   125,   126,   127,   128,     0,   106,     0,    37,     0,
-     104,    38,    51,     0,     0,    81,    79,    97,   105,    58,
-      69,    89,    93,    94,    90,    91,    92,    15,    53,    24,
-       0,    64,    65,     0,    29,    51,    28,     0,   107,   129,
-     130,    32,    34,     0,     0,    40,     0,     0,    14,    26,
-      25,    27,     0,     0,     0,    39,     0,    42,     0,   108,
-      33,     0,     0,     0,     0,   100,     0,     0,    43,     0,
-       0,     0,     0,   121,    88,   101,     0,    41,   122
-};
-
-/* YYDEFGOTO[NTERM-NUM].  */
-static const yytype_int16 yydefgoto[] =
-{
-      -1,     1,     3,    34,   168,   166,    35,    37,   109,   112,
-      83,    84,   185,    85,   176,    69,    70,    86,   102,   103,
-      87,   317,    88,   281,    89,   121,   326,   141,    91,    72,
-     128,   211,   129,   337,   130
-};
-
-/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
-   STATE-NUM.  */
-#define YYPACT_NINF -128
-static const yytype_int16 yypact[] =
-{
-    -128,     4,  -128,   315,   -35,  -128,  -128,  -128,  -128,   -10,
-    -128,  -128,  -128,  -128,  -128,    44,    44,  -128,   -10,   -10,
-    -128,  -128,  -128,  -128,  -128,  -128,   -10,   416,   371,   371,
-     -49,     9,    32,  -128,  -128,    38,  -128,   487,   487,   344,
-      69,   -10,   391,    69,   487,   209,   489,    69,   317,   317,
-    -128,    49,  -128,   317,   317,    42,    48,   106,    67,  -128,
-      61,   191,    25,    93,   191,    67,    67,    68,   170,  -128,
-    -128,  -128,    72,    84,  -128,  -128,    86,  -128,   109,  -128,
-    -128,  -128,   233,  -128,  -128,    80,  -128,  -128,   115,  -128,
-     426,  -128,    84,   120,  -128,   317,  -128,   317,  -128,  -128,
-    -128,   317,   137,  -128,  -128,  -128,   148,   155,   397,  -128,
-      74,    74,  -128,   164,   371,   204,   240,   207,   206,    68,
-     223,  -128,  -128,  -128,  -128,   270,   317,   317,   227,  -128,
-     183,  -128,    90,   160,   317,   -10,  -128,   234,   237,    16,
-    -128,   254,  -128,   255,   256,   257,   240,  -128,   212,   168,
-     548,   317,   317,   428,   258,  -128,  -128,  -128,    84,   371,
-     240,   318,   316,   335,   348,   371,   315,   502,   315,   512,
-    -128,   240,   240,   371,    49,  -128,  -128,  -128,  -128,   289,
-    -128,  -128,   330,  -128,   240,   291,    11,   307,   168,   312,
-      68,    74,  -128,  -128,   160,   317,   317,   317,   377,   379,
-     317,   317,   317,   317,   317,  -128,  -128,   324,  -128,  -128,
-    -128,   325,   337,  -128,    77,   317,   338,   126,    77,   240,
-     240,  -128,   339,   342,   249,   347,  -128,   416,  -128,   352,
-     170,   170,   170,   170,  -128,  -128,  -128,  -128,  -128,  -128,
-     362,  -128,  -128,   227,    -2,   359,   -10,   366,   240,   240,
-     240,   240,   375,   336,   384,   562,   590,   597,   317,   317,
-     213,   213,  -128,  -128,  -128,   385,  -128,    61,  -128,   357,
-     395,  -128,   -10,   396,   398,  -128,  -128,  -128,  -128,  -128,
-    -128,  -128,  -128,  -128,  -128,  -128,  -128,   240,  -128,  -128,
-     434,  -128,  -128,   400,  -128,   432,  -128,   424,  -128,   436,
-     436,   459,  -128,   240,    77,  -128,   402,   240,  -128,  -128,
-    -128,  -128,   404,   317,   411,  -128,   240,  -128,   415,  -128,
-    -128,   216,   418,   240,   413,  -128,   421,   240,  -128,   317,
-     216,   419,   302,   425,  -128,  -128,   317,  -128,   573
-};
-
-/* YYPGOTO[NTERM-NUM].  */
-static const yytype_int16 yypgoto[] =
-{
-    -128,  -128,  -128,   -77,  -128,  -128,  -128,   538,    50,   382,
-     -57,   429,    33,    -7,  -128,   -48,   -43,   -21,    36,  -127,
-     -23,  -128,    29,    17,  -101,   -28,   161,  -128,   -37,    -8,
-     -65,   299,     2,  -128,   -32
-};
-
-/* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
-   positive, shift that token.  If negative, reduce the rule which
-   number is the opposite.  If YYTABLE_NINF, syntax error.  */
-#define YYTABLE_NINF -64
-static const yytype_int16 yytable[] =
-{
-      90,    90,   117,   136,     2,   206,    71,    55,    57,    90,
-      90,    90,    94,    95,   104,   104,    90,    56,    56,   147,
-     248,   104,    93,   120,   137,   216,   142,   143,    36,    73,
-      92,    92,   107,    48,    49,   135,   208,   209,   210,   245,
-     148,    92,   144,   145,   113,   180,   181,   118,   222,   223,
-     123,   124,    48,    49,    41,   125,   131,   126,   127,    42,
-     177,   157,    50,   167,   138,   169,   105,   105,    59,    60,
-      96,   189,   155,   105,   106,    41,    67,   -63,    99,   100,
-     115,    50,   126,   127,   158,    52,    90,   223,   186,   235,
-     108,   237,    53,   114,    97,    54,   119,   122,    48,    49,
-     178,    98,    51,   170,    52,    74,   132,   183,    75,   243,
-     179,    53,    76,    77,    54,   133,    92,   134,   148,   224,
-      99,   100,    99,   100,    78,    79,   253,    50,   192,   193,
-      82,    90,   229,    41,   207,   146,   212,    90,   301,   149,
-      78,    79,   252,   240,   159,    90,    99,   100,   239,   241,
-      52,   150,   228,   151,   225,   124,   246,    53,   234,   101,
-      54,    92,   139,   255,   256,   257,   242,    92,   260,   261,
-     262,   263,   264,    78,   270,    92,   152,   268,    48,    49,
-     271,   272,   160,   269,   165,   213,   195,   196,   197,   198,
-     199,   200,   201,   202,   203,   204,   273,   274,   208,   209,
-     210,   171,   282,   282,   282,   282,   279,    50,    74,    75,
-     302,    75,   172,    76,    77,    76,    77,    48,    49,   173,
-     291,   186,   186,   202,   203,   204,   299,   300,   294,    73,
-      52,   182,   283,   283,   283,   283,   249,    53,    78,    79,
-      54,    48,   153,   154,    99,   100,    50,   309,   284,   285,
-     286,   205,   195,   196,   197,   198,   199,   200,   201,   202,
-     203,   204,    99,   100,   308,   324,   325,   315,   184,    52,
-      50,   187,   311,   188,   116,   314,    68,   191,    74,    54,
-     221,    75,   292,   293,   318,    76,    77,   190,   322,   155,
-     156,    51,   118,    52,   194,   328,   289,   332,   214,   331,
-      68,   215,   296,    54,   338,   195,   196,   197,   198,   199,
-     200,   201,   202,   203,   204,   320,     4,   277,   217,   218,
-     219,   220,   305,   231,   230,    48,    49,   227,     5,     6,
-       7,     8,     9,    10,    11,    12,    13,    14,    15,    16,
-      17,    18,   232,    19,    20,    21,    22,    23,    24,    25,
-      26,    27,    48,    49,    50,   233,   244,   247,    28,    29,
-     195,   196,   197,   198,   199,   200,   201,   202,   203,   204,
-     335,   245,   250,    30,    31,    32,   251,    52,    33,    48,
-      49,    50,    74,   258,    53,    75,   259,    54,   265,    76,
-      77,    78,    79,   266,   226,    80,    81,    99,   100,    48,
-      49,   267,    51,   297,    52,    48,    49,   275,    50,    74,
-     276,    68,    75,    82,    54,   278,    76,    77,    78,    79,
-     280,   303,    80,    81,    48,    49,   287,   288,    50,    51,
-     290,    52,   161,   162,    50,   163,    48,    49,    68,   295,
-      82,    54,    48,    49,   200,   201,   202,   203,   204,   110,
-     111,    52,   298,    50,   101,   174,   111,    52,    53,   304,
-     306,    54,   307,   312,    68,    50,   310,    54,   313,   316,
-      74,    50,   319,    75,    51,   321,    52,    76,    77,   323,
-     329,   164,   327,    68,   226,   330,    54,   334,    52,   336,
-     175,   333,   140,   254,    52,    53,    41,     0,    54,     0,
-       0,    68,     0,     0,    54,   195,   196,   197,   198,   199,
-     200,   201,   202,   203,   204,   195,   196,   197,   198,   199,
-     200,   201,   202,   203,   204,    74,     0,    74,    75,     0,
-      75,     0,    76,    77,    76,    77,     0,     0,     0,     0,
-      99,   100,    99,   100,    38,    39,    40,     0,    43,    44,
-      45,    46,    47,    41,     0,    58,   101,     0,    61,    62,
-      63,    64,    65,    66,     0,   236,   196,   197,   198,   199,
-     200,   201,   202,   203,   204,   238,   195,   196,   197,   198,
-     199,   200,   201,   202,   203,   204,   208,   209,   210,    75,
-       0,     0,     0,    76,    77,   197,   198,   199,   200,   201,
-     202,   203,   204,   198,   199,   200,   201,   202,   203,   204
-};
-
-#define yypact_value_is_default(Yystate) \
-  (!!((Yystate) == (-128)))
-
-#define yytable_value_is_error(Yytable_value) \
-  YYID (0)
-
-static const yytype_int16 yycheck[] =
-{
-      28,    29,    45,    60,     0,   132,    27,    15,    16,    37,
-      38,    39,    61,    62,    37,    38,    44,    15,    16,    67,
-       9,    44,    29,    46,    61,     9,    63,    64,    63,    27,
-      28,    29,    39,     8,     9,    58,    38,    39,    40,    41,
-      68,    39,    65,    66,    42,   110,   111,    45,   149,   150,
-      48,    49,     8,     9,    64,     6,    54,     8,     9,     9,
-     108,    82,    37,    95,    62,    97,    37,    38,    18,    19,
-      61,   119,    56,    44,    38,    64,    26,    66,    53,    54,
-      44,    37,     8,     9,    82,    60,   114,   188,   116,   166,
-      40,   168,    67,    43,    62,    70,    46,    47,     8,     9,
-     108,    63,    58,   101,    60,    38,    64,   114,    41,   174,
-     108,    67,    45,    46,    70,    67,   114,    11,   146,   151,
-      53,    54,    53,    54,    47,    48,   191,    37,   126,   127,
-      69,   159,   160,    64,   132,    67,   134,   165,   265,    67,
-      47,    48,   190,   171,    64,   173,    53,    54,   171,   172,
-      60,    67,   159,    67,   152,   153,   184,    67,   165,    69,
-      70,   159,    69,   195,   196,   197,   173,   165,   200,   201,
-     202,   203,   204,    47,    48,   173,    67,   214,     8,     9,
-     217,   218,    67,   215,    64,   135,     3,     4,     5,     6,
-       7,     8,     9,    10,    11,    12,   219,   220,    38,    39,
-      40,    64,   230,   231,   232,   233,   227,    37,    38,    41,
-     267,    41,    64,    45,    46,    45,    46,     8,     9,    64,
-     248,   249,   250,    10,    11,    12,   258,   259,   251,   227,
-      60,    67,   230,   231,   232,   233,   186,    67,    47,    48,
-      70,     8,     9,    10,    53,    54,    37,   290,   231,   232,
-     233,    68,     3,     4,     5,     6,     7,     8,     9,    10,
-      11,    12,    53,    54,   287,    49,    50,   304,    64,    60,
-      37,    64,   295,    67,    65,   303,    67,     7,    38,    70,
-      68,    41,   249,   250,   307,    45,    46,    64,   316,    56,
-      57,    58,   290,    60,    67,   323,   246,   329,    64,   327,
-      67,    64,   252,    70,   336,     3,     4,     5,     6,     7,
-       8,     9,    10,    11,    12,   313,     1,    68,    64,    64,
-      64,    64,   272,     7,     6,     8,     9,    69,    13,    14,
-      15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
-      25,    26,     7,    28,    29,    30,    31,    32,    33,    34,
-      35,    36,     8,     9,    37,     7,    67,    66,    43,    44,
-       3,     4,     5,     6,     7,     8,     9,    10,    11,    12,
-      68,    41,    65,    58,    59,    60,    64,    60,    63,     8,
-       9,    37,    38,     6,    67,    41,     7,    70,    64,    45,
-      46,    47,    48,    68,    56,    51,    52,    53,    54,     8,
-       9,    64,    58,    67,    60,     8,     9,    68,    37,    38,
-      68,    67,    41,    69,    70,    68,    45,    46,    47,    48,
-      68,    64,    51,    52,     8,     9,    64,    68,    37,    58,
-      64,    60,     6,     7,    37,     9,     8,     9,    67,    64,
-      69,    70,     8,     9,     8,     9,    10,    11,    12,    58,
-      59,    60,    68,    37,    69,    58,    59,    60,    67,    64,
-      64,    70,    64,    39,    67,    37,    66,    70,     9,    67,
-      38,    37,    68,    41,    58,    64,    60,    45,    46,    64,
-      67,    55,    64,    67,    56,    64,    70,    68,    60,    64,
-     108,   330,    63,   194,    60,    67,    64,    -1,    70,    -1,
-      -1,    67,    -1,    -1,    70,     3,     4,     5,     6,     7,
-       8,     9,    10,    11,    12,     3,     4,     5,     6,     7,
-       8,     9,    10,    11,    12,    38,    -1,    38,    41,    -1,
-      41,    -1,    45,    46,    45,    46,    -1,    -1,    -1,    -1,
-      53,    54,    53,    54,     6,     7,     8,    -1,    10,    11,
-      12,    13,    14,    64,    -1,    17,    69,    -1,    20,    21,
-      22,    23,    24,    25,    -1,    63,     4,     5,     6,     7,
-       8,     9,    10,    11,    12,    63,     3,     4,     5,     6,
-       7,     8,     9,    10,    11,    12,    38,    39,    40,    41,
-      -1,    -1,    -1,    45,    46,     5,     6,     7,     8,     9,
-      10,    11,    12,     6,     7,     8,     9,    10,    11,    12
-};
-
-/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
-   symbol of state STATE-NUM.  */
-static const yytype_uint8 yystos[] =
-{
-       0,    72,     0,    73,     1,    13,    14,    15,    16,    17,
-      18,    19,    20,    21,    22,    23,    24,    25,    26,    28,
-      29,    30,    31,    32,    33,    34,    35,    36,    43,    44,
-      58,    59,    60,    63,    74,    77,    63,    78,    78,    78,
-      78,    64,    79,    78,    78,    78,    78,    78,     8,     9,
-      37,    58,    60,    67,    70,   100,   103,   100,    78,    79,
-      79,    78,    78,    78,    78,    78,    78,    79,    67,    86,
-      87,    88,   100,   103,    38,    41,    45,    46,    47,    48,
-      51,    52,    69,    81,    82,    84,    88,    91,    93,    95,
-      96,    99,   103,    84,    61,    62,    61,    62,    63,    53,
-      54,    69,    89,    90,    91,    93,    89,    84,    79,    79,
-      58,    59,    80,   103,    79,    89,    65,    87,   103,    79,
-      91,    96,    79,   103,   103,     6,     8,     9,   101,   103,
-     105,   103,    64,    67,    11,    91,    81,    99,   103,    69,
-      82,    98,    99,    99,    91,    91,    67,    86,    96,    67,
-      67,    67,    67,     9,    10,    56,    57,    88,   103,    64,
-      67,     6,     7,     9,    55,    64,    76,   105,    75,   105,
-     103,    64,    64,    64,    58,    80,    85,    86,   100,   103,
-     101,   101,    67,    84,    64,    83,    96,    64,    67,    86,
-      64,     7,   103,   103,    67,     3,     4,     5,     6,     7,
-       8,     9,    10,    11,    12,    68,    90,   103,    38,    39,
-      40,   102,   103,    79,    64,    64,     9,    64,    64,    64,
-      64,    68,    95,    95,   105,   103,    56,    69,    84,    96,
-       6,     7,     7,     7,    84,    74,    63,    74,    63,    91,
-      96,    91,    84,   101,    67,    41,    96,    66,     9,    79,
-      65,    64,    86,   101,   102,   105,   105,   105,     6,     7,
-     105,   105,   105,   105,   105,    64,    68,    64,    99,   105,
-      48,    99,    99,    91,    91,    68,    68,    68,    68,    88,
-      68,    94,    96,   103,    94,    94,    94,    64,    68,    79,
-      64,    96,    83,    83,    91,    64,    79,    67,    68,   105,
-     105,    90,    81,    64,    64,    79,    64,    64,    91,    87,
-      66,    91,    39,     9,    96,    99,    67,    92,    91,    68,
-     103,    64,    96,    64,    49,    50,    97,    64,    96,    67,
-      64,    96,   105,    97,    68,    68,    64,   104,   105
-};
-
-#define yyerrok		(yyerrstatus = 0)
-#define yyclearin	(yychar = YYEMPTY)
-#define YYEMPTY		(-2)
-#define YYEOF		0
-
-#define YYACCEPT	goto yyacceptlab
-#define YYABORT		goto yyabortlab
-#define YYERROR		goto yyerrorlab
-
-
-/* Like YYERROR except do call yyerror.  This remains here temporarily
-   to ease the transition to the new meaning of YYERROR, for GCC.
-   Once GCC version 2 has supplanted version 1, this can go.  However,
-   YYFAIL appears to be in use.  Nevertheless, it is formally deprecated
-   in Bison 2.4.2's NEWS entry, where a plan to phase it out is
-   discussed.  */
-
-#define YYFAIL		goto yyerrlab
-#if defined YYFAIL
-  /* This is here to suppress warnings from the GCC cpp's
-     -Wunused-macros.  Normally we don't worry about that warning, but
-     some users do, and we want to make it easy for users to remove
-     YYFAIL uses, which will produce warnings from Bison 2.5.  */
-#endif
-
-#define YYRECOVERING()  (!!yyerrstatus)
-
-#define YYBACKUP(Token, Value)                                  \
-do                                                              \
-  if (yychar == YYEMPTY)                                        \
-    {                                                           \
-      yychar = (Token);                                         \
-      yylval = (Value);                                         \
-      YYPOPSTACK (yylen);                                       \
-      yystate = *yyssp;                                         \
-      goto yybackup;                                            \
-    }                                                           \
-  else                                                          \
-    {                                                           \
-      yyerror (YY_("syntax error: cannot back up")); \
-      YYERROR;							\
-    }								\
-while (YYID (0))
-
-/* Error token number */
-#define YYTERROR	1
-#define YYERRCODE	256
-
-
-/* This macro is provided for backward compatibility. */
-#ifndef YY_LOCATION_PRINT
-# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
-#endif
-
-
-/* YYLEX -- calling `yylex' with the right arguments.  */
-#ifdef YYLEX_PARAM
-# define YYLEX yylex (YYLEX_PARAM)
-#else
-# define YYLEX yylex ()
-#endif
-
-/* Enable debugging if requested.  */
-#if YYDEBUG
-
-# ifndef YYFPRINTF
-#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
-#  define YYFPRINTF fprintf
-# endif
-
-# define YYDPRINTF(Args)			\
-do {						\
-  if (yydebug)					\
-    YYFPRINTF Args;				\
-} while (YYID (0))
-
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location)			  \
-do {									  \
-  if (yydebug)								  \
-    {									  \
-      YYFPRINTF (stderr, "%s ", Title);					  \
-      yy_symbol_print (stderr,						  \
-		  Type, Value); \
-      YYFPRINTF (stderr, "\n");						  \
-    }									  \
-} while (YYID (0))
-
-
-/*--------------------------------.
-| Print this symbol on YYOUTPUT.  |
-`--------------------------------*/
-
-/*ARGSUSED*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static void
-yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
-#else
-static void
-yy_symbol_value_print (yyoutput, yytype, yyvaluep)
-    FILE *yyoutput;
-    int yytype;
-    YYSTYPE const * const yyvaluep;
-#endif
-{
-  FILE *yyo = yyoutput;
-  YYUSE (yyo);
-  if (!yyvaluep)
-    return;
-# ifdef YYPRINT
-  if (yytype < YYNTOKENS)
-    YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
-# else
-  YYUSE (yyoutput);
-# endif
-  YYUSE (yytype);
-}
-
-
-/*--------------------------------.
-| Print this symbol on YYOUTPUT.  |
-`--------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static void
-yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
-#else
-static void
-yy_symbol_print (yyoutput, yytype, yyvaluep)
-    FILE *yyoutput;
-    int yytype;
-    YYSTYPE const * const yyvaluep;
-#endif
-{
-  if (yytype < YYNTOKENS)
-    YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
-  else
-    YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
-
-  yy_symbol_value_print (yyoutput, yytype, yyvaluep);
-  YYFPRINTF (yyoutput, ")");
-}
-
-/*------------------------------------------------------------------.
-| yy_stack_print -- Print the state stack from its BOTTOM up to its |
-| TOP (included).                                                   |
-`------------------------------------------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static void
-yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
-#else
-static void
-yy_stack_print (yybottom, yytop)
-    yytype_int16 *yybottom;
-    yytype_int16 *yytop;
-#endif
-{
-  YYFPRINTF (stderr, "Stack now");
-  for (; yybottom <= yytop; yybottom++)
-    {
-      int yybot = *yybottom;
-      YYFPRINTF (stderr, " %d", yybot);
-    }
-  YYFPRINTF (stderr, "\n");
-}
-
-# define YY_STACK_PRINT(Bottom, Top)				\
-do {								\
-  if (yydebug)							\
-    yy_stack_print ((Bottom), (Top));				\
-} while (YYID (0))
-
-
-/*------------------------------------------------.
-| Report that the YYRULE is going to be reduced.  |
-`------------------------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static void
-yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
-#else
-static void
-yy_reduce_print (yyvsp, yyrule)
-    YYSTYPE *yyvsp;
-    int yyrule;
-#endif
-{
-  int yynrhs = yyr2[yyrule];
-  int yyi;
-  unsigned long int yylno = yyrline[yyrule];
-  YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
-	     yyrule - 1, yylno);
-  /* The symbols being reduced.  */
-  for (yyi = 0; yyi < yynrhs; yyi++)
-    {
-      YYFPRINTF (stderr, "   $%d = ", yyi + 1);
-      yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
-		       &(yyvsp[(yyi + 1) - (yynrhs)])
-		       		       );
-      YYFPRINTF (stderr, "\n");
-    }
-}
-
-# define YY_REDUCE_PRINT(Rule)		\
-do {					\
-  if (yydebug)				\
-    yy_reduce_print (yyvsp, Rule); \
-} while (YYID (0))
-
-/* Nonzero means print parse trace.  It is left uninitialized so that
-   multiple parsers can coexist.  */
-int yydebug;
-#else /* !YYDEBUG */
-# define YYDPRINTF(Args)
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
-# define YY_STACK_PRINT(Bottom, Top)
-# define YY_REDUCE_PRINT(Rule)
-#endif /* !YYDEBUG */
-
-
-/* YYINITDEPTH -- initial size of the parser's stacks.  */
-#ifndef	YYINITDEPTH
-# define YYINITDEPTH 200
-#endif
-
-/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
-   if the built-in stack extension method is used).
-
-   Do not make this value too large; the results are undefined if
-   YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
-   evaluated with infinite-precision integer arithmetic.  */
-
-#ifndef YYMAXDEPTH
-# define YYMAXDEPTH 10000
-#endif
-
-
-#if YYERROR_VERBOSE
-
-# ifndef yystrlen
-#  if defined __GLIBC__ && defined _STRING_H
-#   define yystrlen strlen
-#  else
-/* Return the length of YYSTR.  */
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static YYSIZE_T
-yystrlen (const char *yystr)
-#else
-static YYSIZE_T
-yystrlen (yystr)
-    const char *yystr;
-#endif
-{
-  YYSIZE_T yylen;
-  for (yylen = 0; yystr[yylen]; yylen++)
-    continue;
-  return yylen;
-}
-#  endif
-# endif
-
-# ifndef yystpcpy
-#  if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
-#   define yystpcpy stpcpy
-#  else
-/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
-   YYDEST.  */
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static char *
-yystpcpy (char *yydest, const char *yysrc)
-#else
-static char *
-yystpcpy (yydest, yysrc)
-    char *yydest;
-    const char *yysrc;
-#endif
-{
-  char *yyd = yydest;
-  const char *yys = yysrc;
-
-  while ((*yyd++ = *yys++) != '\0')
-    continue;
-
-  return yyd - 1;
-}
-#  endif
-# endif
-
-# ifndef yytnamerr
-/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
-   quotes and backslashes, so that it's suitable for yyerror.  The
-   heuristic is that double-quoting is unnecessary unless the string
-   contains an apostrophe, a comma, or backslash (other than
-   backslash-backslash).  YYSTR is taken from yytname.  If YYRES is
-   null, do not copy; instead, return the length of what the result
-   would have been.  */
-static YYSIZE_T
-yytnamerr (char *yyres, const char *yystr)
-{
-  if (*yystr == '"')
-    {
-      YYSIZE_T yyn = 0;
-      char const *yyp = yystr;
-
-      for (;;)
-	switch (*++yyp)
-	  {
-	  case '\'':
-	  case ',':
-	    goto do_not_strip_quotes;
-
-	  case '\\':
-	    if (*++yyp != '\\')
-	      goto do_not_strip_quotes;
-	    /* Fall through.  */
-	  default:
-	    if (yyres)
-	      yyres[yyn] = *yyp;
-	    yyn++;
-	    break;
-
-	  case '"':
-	    if (yyres)
-	      yyres[yyn] = '\0';
-	    return yyn;
-	  }
-    do_not_strip_quotes: ;
-    }
-
-  if (! yyres)
-    return yystrlen (yystr);
-
-  return yystpcpy (yyres, yystr) - yyres;
-}
-# endif
-
-/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
-   about the unexpected token YYTOKEN for the state stack whose top is
-   YYSSP.
-
-   Return 0 if *YYMSG was successfully written.  Return 1 if *YYMSG is
-   not large enough to hold the message.  In that case, also set
-   *YYMSG_ALLOC to the required number of bytes.  Return 2 if the
-   required number of bytes is too large to store.  */
-static int
-yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
-                yytype_int16 *yyssp, int yytoken)
-{
-  YYSIZE_T yysize0 = yytnamerr (YY_NULL, yytname[yytoken]);
-  YYSIZE_T yysize = yysize0;
-  enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
-  /* Internationalized format string. */
-  const char *yyformat = YY_NULL;
-  /* Arguments of yyformat. */
-  char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
-  /* Number of reported tokens (one for the "unexpected", one per
-     "expected"). */
-  int yycount = 0;
-
-  /* There are many possibilities here to consider:
-     - Assume YYFAIL is not used.  It's too flawed to consider.  See
-       <http://lists.gnu.org/archive/html/bison-patches/2009-12/msg00024.html>
-       for details.  YYERROR is fine as it does not invoke this
-       function.
-     - If this state is a consistent state with a default action, then
-       the only way this function was invoked is if the default action
-       is an error action.  In that case, don't check for expected
-       tokens because there are none.
-     - The only way there can be no lookahead present (in yychar) is if
-       this state is a consistent state with a default action.  Thus,
-       detecting the absence of a lookahead is sufficient to determine
-       that there is no unexpected or expected token to report.  In that
-       case, just report a simple "syntax error".
-     - Don't assume there isn't a lookahead just because this state is a
-       consistent state with a default action.  There might have been a
-       previous inconsistent state, consistent state with a non-default
-       action, or user semantic action that manipulated yychar.
-     - Of course, the expected token list depends on states to have
-       correct lookahead information, and it depends on the parser not
-       to perform extra reductions after fetching a lookahead from the
-       scanner and before detecting a syntax error.  Thus, state merging
-       (from LALR or IELR) and default reductions corrupt the expected
-       token list.  However, the list is correct for canonical LR with
-       one exception: it will still contain any token that will not be
-       accepted due to an error action in a later state.
-  */
-  if (yytoken != YYEMPTY)
-    {
-      int yyn = yypact[*yyssp];
-      yyarg[yycount++] = yytname[yytoken];
-      if (!yypact_value_is_default (yyn))
-        {
-          /* Start YYX at -YYN if negative to avoid negative indexes in
-             YYCHECK.  In other words, skip the first -YYN actions for
-             this state because they are default actions.  */
-          int yyxbegin = yyn < 0 ? -yyn : 0;
-          /* Stay within bounds of both yycheck and yytname.  */
-          int yychecklim = YYLAST - yyn + 1;
-          int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
-          int yyx;
-
-          for (yyx = yyxbegin; yyx < yyxend; ++yyx)
-            if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
-                && !yytable_value_is_error (yytable[yyx + yyn]))
-              {
-                if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
-                  {
-                    yycount = 1;
-                    yysize = yysize0;
-                    break;
-                  }
-                yyarg[yycount++] = yytname[yyx];
-                {
-                  YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULL, yytname[yyx]);
-                  if (! (yysize <= yysize1
-                         && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
-                    return 2;
-                  yysize = yysize1;
-                }
-              }
-        }
-    }
-
-  switch (yycount)
-    {
-# define YYCASE_(N, S)                      \
-      case N:                               \
-        yyformat = S;                       \
-      break
-      YYCASE_(0, YY_("syntax error"));
-      YYCASE_(1, YY_("syntax error, unexpected %s"));
-      YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
-      YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
-      YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
-      YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
-# undef YYCASE_
-    }
-
-  {
-    YYSIZE_T yysize1 = yysize + yystrlen (yyformat);
-    if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
-      return 2;
-    yysize = yysize1;
-  }
-
-  if (*yymsg_alloc < yysize)
-    {
-      *yymsg_alloc = 2 * yysize;
-      if (! (yysize <= *yymsg_alloc
-             && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
-        *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
-      return 1;
-    }
-
-  /* Avoid sprintf, as that infringes on the user's name space.
-     Don't have undefined behavior even if the translation
-     produced a string with the wrong number of "%s"s.  */
-  {
-    char *yyp = *yymsg;
-    int yyi = 0;
-    while ((*yyp = *yyformat) != '\0')
-      if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
-        {
-          yyp += yytnamerr (yyp, yyarg[yyi++]);
-          yyformat += 2;
-        }
-      else
-        {
-          yyp++;
-          yyformat++;
-        }
-  }
-  return 0;
-}
-#endif /* YYERROR_VERBOSE */
-
-/*-----------------------------------------------.
-| Release the memory associated to this symbol.  |
-`-----------------------------------------------*/
-
-/*ARGSUSED*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static void
-yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
-#else
-static void
-yydestruct (yymsg, yytype, yyvaluep)
-    const char *yymsg;
-    int yytype;
-    YYSTYPE *yyvaluep;
-#endif
-{
-  YYUSE (yyvaluep);
-
-  if (!yymsg)
-    yymsg = "Deleting";
-  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
-
-  YYUSE (yytype);
-}
-
-
-
-
-/* The lookahead symbol.  */
-int yychar;
-
-
-#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
-# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
-# define YY_IGNORE_MAYBE_UNINITIALIZED_END
-#endif
-#ifndef YY_INITIAL_VALUE
-# define YY_INITIAL_VALUE(Value) /* Nothing. */
-#endif
-
-/* The semantic value of the lookahead symbol.  */
-YYSTYPE yylval YY_INITIAL_VALUE(yyval_default);
-
-/* Number of syntax errors so far.  */
-int yynerrs;
-
-
-/*----------.
-| yyparse.  |
-`----------*/
-
-#ifdef YYPARSE_PARAM
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-int
-yyparse (void *YYPARSE_PARAM)
-#else
-int
-yyparse (YYPARSE_PARAM)
-    void *YYPARSE_PARAM;
-#endif
-#else /* ! YYPARSE_PARAM */
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-int
-yyparse (void)
-#else
-int
-yyparse ()
-
-#endif
-#endif
-{
-    int yystate;
-    /* Number of tokens to shift before error messages enabled.  */
-    int yyerrstatus;
-
-    /* The stacks and their tools:
-       `yyss': related to states.
-       `yyvs': related to semantic values.
-
-       Refer to the stacks through separate pointers, to allow yyoverflow
-       to reallocate them elsewhere.  */
-
-    /* The state stack.  */
-    yytype_int16 yyssa[YYINITDEPTH];
-    yytype_int16 *yyss;
-    yytype_int16 *yyssp;
-
-    /* The semantic value stack.  */
-    YYSTYPE yyvsa[YYINITDEPTH];
-    YYSTYPE *yyvs;
-    YYSTYPE *yyvsp;
-
-    YYSIZE_T yystacksize;
-
-  int yyn;
-  int yyresult;
-  /* Lookahead token as an internal (translated) token number.  */
-  int yytoken = 0;
-  /* The variables used to return semantic value and location from the
-     action routines.  */
-  YYSTYPE yyval;
-
-#if YYERROR_VERBOSE
-  /* Buffer for error messages, and its allocated size.  */
-  char yymsgbuf[128];
-  char *yymsg = yymsgbuf;
-  YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
-#endif
-
-#define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N))
-
-  /* The number of symbols on the RHS of the reduced rule.
-     Keep to zero when no symbol should be popped.  */
-  int yylen = 0;
-
-  yyssp = yyss = yyssa;
-  yyvsp = yyvs = yyvsa;
-  yystacksize = YYINITDEPTH;
-
-  YYDPRINTF ((stderr, "Starting parse\n"));
-
-  yystate = 0;
-  yyerrstatus = 0;
-  yynerrs = 0;
-  yychar = YYEMPTY; /* Cause a token to be read.  */
-  goto yysetstate;
-
-/*------------------------------------------------------------.
-| yynewstate -- Push a new state, which is found in yystate.  |
-`------------------------------------------------------------*/
- yynewstate:
-  /* In all cases, when you get here, the value and location stacks
-     have just been pushed.  So pushing a state here evens the stacks.  */
-  yyssp++;
-
- yysetstate:
-  *yyssp = yystate;
-
-  if (yyss + yystacksize - 1 <= yyssp)
-    {
-      /* Get the current used size of the three stacks, in elements.  */
-      YYSIZE_T yysize = yyssp - yyss + 1;
-
-#ifdef yyoverflow
-      {
-	/* Give user a chance to reallocate the stack.  Use copies of
-	   these so that the &'s don't force the real ones into
-	   memory.  */
-	YYSTYPE *yyvs1 = yyvs;
-	yytype_int16 *yyss1 = yyss;
-
-	/* Each stack pointer address is followed by the size of the
-	   data in use in that stack, in bytes.  This used to be a
-	   conditional around just the two extra args, but that might
-	   be undefined if yyoverflow is a macro.  */
-	yyoverflow (YY_("memory exhausted"),
-		    &yyss1, yysize * sizeof (*yyssp),
-		    &yyvs1, yysize * sizeof (*yyvsp),
-		    &yystacksize);
-
-	yyss = yyss1;
-	yyvs = yyvs1;
-      }
-#else /* no yyoverflow */
-# ifndef YYSTACK_RELOCATE
-      goto yyexhaustedlab;
-# else
-      /* Extend the stack our own way.  */
-      if (YYMAXDEPTH <= yystacksize)
-	goto yyexhaustedlab;
-      yystacksize *= 2;
-      if (YYMAXDEPTH < yystacksize)
-	yystacksize = YYMAXDEPTH;
-
-      {
-	yytype_int16 *yyss1 = yyss;
-	union yyalloc *yyptr =
-	  (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
-	if (! yyptr)
-	  goto yyexhaustedlab;
-	YYSTACK_RELOCATE (yyss_alloc, yyss);
-	YYSTACK_RELOCATE (yyvs_alloc, yyvs);
-#  undef YYSTACK_RELOCATE
-	if (yyss1 != yyssa)
-	  YYSTACK_FREE (yyss1);
-      }
-# endif
-#endif /* no yyoverflow */
-
-      yyssp = yyss + yysize - 1;
-      yyvsp = yyvs + yysize - 1;
-
-      YYDPRINTF ((stderr, "Stack size increased to %lu\n",
-		  (unsigned long int) yystacksize));
-
-      if (yyss + yystacksize - 1 <= yyssp)
-	YYABORT;
-    }
-
-  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
-
-  if (yystate == YYFINAL)
-    YYACCEPT;
-
-  goto yybackup;
-
-/*-----------.
-| yybackup.  |
-`-----------*/
-yybackup:
-
-  /* Do appropriate processing given the current state.  Read a
-     lookahead token if we need one and don't already have one.  */
-
-  /* First try to decide what to do without reference to lookahead token.  */
-  yyn = yypact[yystate];
-  if (yypact_value_is_default (yyn))
-    goto yydefault;
-
-  /* Not known => get a lookahead token if don't already have one.  */
-
-  /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol.  */
-  if (yychar == YYEMPTY)
-    {
-      YYDPRINTF ((stderr, "Reading a token: "));
-      yychar = YYLEX;
-    }
-
-  if (yychar <= YYEOF)
-    {
-      yychar = yytoken = YYEOF;
-      YYDPRINTF ((stderr, "Now at end of input.\n"));
-    }
-  else
-    {
-      yytoken = YYTRANSLATE (yychar);
-      YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
-    }
-
-  /* If the proper action on seeing token YYTOKEN is to reduce or to
-     detect an error, take that action.  */
-  yyn += yytoken;
-  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
-    goto yydefault;
-  yyn = yytable[yyn];
-  if (yyn <= 0)
-    {
-      if (yytable_value_is_error (yyn))
-        goto yyerrlab;
-      yyn = -yyn;
-      goto yyreduce;
-    }
-
-  /* Count tokens shifted since error; after three, turn off error
-     status.  */
-  if (yyerrstatus)
-    yyerrstatus--;
-
-  /* Shift the lookahead token.  */
-  YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
-
-  /* Discard the shifted token.  */
-  yychar = YYEMPTY;
-
-  yystate = yyn;
-  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
-  *++yyvsp = yylval;
-  YY_IGNORE_MAYBE_UNINITIALIZED_END
-
-  goto yynewstate;
-
-
-/*-----------------------------------------------------------.
-| yydefault -- do the default action for the current state.  |
-`-----------------------------------------------------------*/
-yydefault:
-  yyn = yydefact[yystate];
-  if (yyn == 0)
-    goto yyerrlab;
-  goto yyreduce;
-
-
-/*-----------------------------.
-| yyreduce -- Do a reduction.  |
-`-----------------------------*/
-yyreduce:
-  /* yyn is the number of a rule to reduce with.  */
-  yylen = yyr2[yyn];
-
-  /* If YYLEN is nonzero, implement the default value of the action:
-     `$$ = $1'.
-
-     Otherwise, the following line sets YYVAL to garbage.
-     This behavior is undocumented and Bison
-     users should not rely upon it.  Assigning to YYVAL
-     unconditionally makes the parser a bit smaller, and it avoids a
-     GCC warning that YYVAL may be used uninitialized.  */
-  yyval = yyvsp[1-yylen];
-
-
-  YY_REDUCE_PRINT (yyn);
-  switch (yyn)
-    {
-        case 3:
-/* Line 1787 of yacc.c  */
-#line 70 "a.y"
-    {
-		stmtline = lineno;
-	}
-    break;
-
-  case 5:
-/* Line 1787 of yacc.c  */
-#line 77 "a.y"
-    {
-		if((yyvsp[(1) - (2)].sym)->value != pc)
-			yyerror("redeclaration of %s", (yyvsp[(1) - (2)].sym)->name);
-		(yyvsp[(1) - (2)].sym)->value = pc;
-	}
-    break;
-
-  case 7:
-/* Line 1787 of yacc.c  */
-#line 84 "a.y"
-    {
-		(yyvsp[(1) - (2)].sym)->type = LLAB;
-		(yyvsp[(1) - (2)].sym)->value = pc;
-	}
-    break;
-
-  case 9:
-/* Line 1787 of yacc.c  */
-#line 90 "a.y"
-    {
-		(yyvsp[(1) - (4)].sym)->type = LVAR;
-		(yyvsp[(1) - (4)].sym)->value = (yyvsp[(3) - (4)].lval);
-	}
-    break;
-
-  case 10:
-/* Line 1787 of yacc.c  */
-#line 95 "a.y"
-    {
-		if((yyvsp[(1) - (4)].sym)->value != (yyvsp[(3) - (4)].lval))
-			yyerror("redeclaration of %s", (yyvsp[(1) - (4)].sym)->name);
-		(yyvsp[(1) - (4)].sym)->value = (yyvsp[(3) - (4)].lval);
-	}
-    break;
-
-  case 14:
-/* Line 1787 of yacc.c  */
-#line 109 "a.y"
-    {
-		outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &(yyvsp[(3) - (7)].addr), (yyvsp[(5) - (7)].lval), &(yyvsp[(7) - (7)].addr));
-	}
-    break;
-
-  case 15:
-/* Line 1787 of yacc.c  */
-#line 113 "a.y"
-    {
-		outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(3) - (6)].addr), (yyvsp[(5) - (6)].lval), &nullgen);
-	}
-    break;
-
-  case 16:
-/* Line 1787 of yacc.c  */
-#line 117 "a.y"
-    {
-		outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].addr), NREG, &(yyvsp[(5) - (5)].addr));
-	}
-    break;
-
-  case 17:
-/* Line 1787 of yacc.c  */
-#line 124 "a.y"
-    {
-		outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].addr), NREG, &(yyvsp[(5) - (5)].addr));
-	}
-    break;
-
-  case 18:
-/* Line 1787 of yacc.c  */
-#line 131 "a.y"
-    {
-		outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].addr), NREG, &(yyvsp[(5) - (5)].addr));
-	}
-    break;
-
-  case 19:
-/* Line 1787 of yacc.c  */
-#line 138 "a.y"
-    {
-		outcode((yyvsp[(1) - (4)].lval), (yyvsp[(2) - (4)].lval), &nullgen, NREG, &(yyvsp[(4) - (4)].addr));
-	}
-    break;
-
-  case 20:
-/* Line 1787 of yacc.c  */
-#line 142 "a.y"
-    {
-		outcode((yyvsp[(1) - (4)].lval), (yyvsp[(2) - (4)].lval), &nullgen, NREG, &(yyvsp[(4) - (4)].addr));
-	}
-    break;
-
-  case 21:
-/* Line 1787 of yacc.c  */
-#line 149 "a.y"
-    {
-		outcode((yyvsp[(1) - (3)].lval), Always, &nullgen, NREG, &(yyvsp[(3) - (3)].addr));
-	}
-    break;
-
-  case 22:
-/* Line 1787 of yacc.c  */
-#line 156 "a.y"
-    {
-		outcode((yyvsp[(1) - (3)].lval), Always, &nullgen, NREG, &(yyvsp[(3) - (3)].addr));
-	}
-    break;
-
-  case 23:
-/* Line 1787 of yacc.c  */
-#line 163 "a.y"
-    {
-		outcode((yyvsp[(1) - (4)].lval), (yyvsp[(2) - (4)].lval), &nullgen, NREG, &(yyvsp[(4) - (4)].addr));
-	}
-    break;
-
-  case 24:
-/* Line 1787 of yacc.c  */
-#line 170 "a.y"
-    {
-		outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(3) - (6)].addr), (yyvsp[(5) - (6)].lval), &nullgen);
-	}
-    break;
-
-  case 25:
-/* Line 1787 of yacc.c  */
-#line 177 "a.y"
-    {
-		Addr g;
-
-		g = nullgen;
-		g.type = D_CONST;
-		g.offset = (yyvsp[(6) - (7)].lval);
-		outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &(yyvsp[(3) - (7)].addr), NREG, &g);
-	}
-    break;
-
-  case 26:
-/* Line 1787 of yacc.c  */
-#line 186 "a.y"
-    {
-		Addr g;
-
-		g = nullgen;
-		g.type = D_CONST;
-		g.offset = (yyvsp[(4) - (7)].lval);
-		outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &g, NREG, &(yyvsp[(7) - (7)].addr));
-	}
-    break;
-
-  case 27:
-/* Line 1787 of yacc.c  */
-#line 198 "a.y"
-    {
-		outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &(yyvsp[(5) - (7)].addr), (yyvsp[(3) - (7)].addr).reg, &(yyvsp[(7) - (7)].addr));
-	}
-    break;
-
-  case 28:
-/* Line 1787 of yacc.c  */
-#line 202 "a.y"
-    {
-		outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(5) - (6)].addr), (yyvsp[(3) - (6)].addr).reg, &(yyvsp[(3) - (6)].addr));
-	}
-    break;
-
-  case 29:
-/* Line 1787 of yacc.c  */
-#line 206 "a.y"
-    {
-		outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(4) - (6)].addr), (yyvsp[(6) - (6)].addr).reg, &(yyvsp[(6) - (6)].addr));
-	}
-    break;
-
-  case 30:
-/* Line 1787 of yacc.c  */
-#line 213 "a.y"
-    {
-		outcode((yyvsp[(1) - (3)].lval), (yyvsp[(2) - (3)].lval), &nullgen, NREG, &nullgen);
-	}
-    break;
-
-  case 31:
-/* Line 1787 of yacc.c  */
-#line 220 "a.y"
-    {
-		(yyvsp[(4) - (4)].addr).type = D_CONST2;
-		(yyvsp[(4) - (4)].addr).offset2 = ArgsSizeUnknown;
-		outcode((yyvsp[(1) - (4)].lval), Always, &(yyvsp[(2) - (4)].addr), 0, &(yyvsp[(4) - (4)].addr));
-	}
-    break;
-
-  case 32:
-/* Line 1787 of yacc.c  */
-#line 226 "a.y"
-    {
-		(yyvsp[(6) - (6)].addr).type = D_CONST2;
-		(yyvsp[(6) - (6)].addr).offset2 = ArgsSizeUnknown;
-		outcode((yyvsp[(1) - (6)].lval), Always, &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
-	}
-    break;
-
-  case 33:
-/* Line 1787 of yacc.c  */
-#line 232 "a.y"
-    {
-		(yyvsp[(6) - (8)].addr).type = D_CONST2;
-		(yyvsp[(6) - (8)].addr).offset2 = (yyvsp[(8) - (8)].lval);
-		outcode((yyvsp[(1) - (8)].lval), Always, &(yyvsp[(2) - (8)].addr), (yyvsp[(4) - (8)].lval), &(yyvsp[(6) - (8)].addr));
-	}
-    break;
-
-  case 34:
-/* Line 1787 of yacc.c  */
-#line 241 "a.y"
-    {
-		outcode((yyvsp[(1) - (6)].lval), Always, &(yyvsp[(2) - (6)].addr), (yyvsp[(4) - (6)].lval), &(yyvsp[(6) - (6)].addr));
-	}
-    break;
-
-  case 35:
-/* Line 1787 of yacc.c  */
-#line 248 "a.y"
-    {
-		outcode((yyvsp[(1) - (4)].lval), (yyvsp[(2) - (4)].lval), &(yyvsp[(3) - (4)].addr), NREG, &nullgen);
-	}
-    break;
-
-  case 36:
-/* Line 1787 of yacc.c  */
-#line 255 "a.y"
-    {
-		outcode((yyvsp[(1) - (3)].lval), Always, &nullgen, NREG, &(yyvsp[(3) - (3)].addr));
-	}
-    break;
-
-  case 37:
-/* Line 1787 of yacc.c  */
-#line 262 "a.y"
-    {
-		outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].addr), NREG, &(yyvsp[(5) - (5)].addr));
-	}
-    break;
-
-  case 38:
-/* Line 1787 of yacc.c  */
-#line 266 "a.y"
-    {
-		outcode((yyvsp[(1) - (5)].lval), (yyvsp[(2) - (5)].lval), &(yyvsp[(3) - (5)].addr), NREG, &(yyvsp[(5) - (5)].addr));
-	}
-    break;
-
-  case 39:
-/* Line 1787 of yacc.c  */
-#line 270 "a.y"
-    {
-		outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &(yyvsp[(3) - (7)].addr), (yyvsp[(5) - (7)].lval), &(yyvsp[(7) - (7)].addr));
-	}
-    break;
-
-  case 40:
-/* Line 1787 of yacc.c  */
-#line 274 "a.y"
-    {
-		outcode((yyvsp[(1) - (6)].lval), (yyvsp[(2) - (6)].lval), &(yyvsp[(3) - (6)].addr), (yyvsp[(5) - (6)].addr).reg, &nullgen);
-	}
-    break;
-
-  case 41:
-/* Line 1787 of yacc.c  */
-#line 281 "a.y"
-    {
-		Addr g;
-
-		g = nullgen;
-		g.type = D_CONST;
-		g.offset =
-			(0xe << 24) |		/* opcode */
-			((yyvsp[(1) - (12)].lval) << 20) |		/* MCR/MRC */
-			((yyvsp[(2) - (12)].lval) << 28) |		/* scond */
-			(((yyvsp[(3) - (12)].lval) & 15) << 8) |	/* coprocessor number */
-			(((yyvsp[(5) - (12)].lval) & 7) << 21) |	/* coprocessor operation */
-			(((yyvsp[(7) - (12)].lval) & 15) << 12) |	/* arm register */
-			(((yyvsp[(9) - (12)].lval) & 15) << 16) |	/* Crn */
-			(((yyvsp[(11) - (12)].lval) & 15) << 0) |	/* Crm */
-			(((yyvsp[(12) - (12)].lval) & 7) << 5) |	/* coprocessor information */
-			(1<<4);			/* must be set */
-		outcode(AMRC, Always, &nullgen, NREG, &g);
-	}
-    break;
-
-  case 42:
-/* Line 1787 of yacc.c  */
-#line 303 "a.y"
-    {
-		outcode((yyvsp[(1) - (7)].lval), (yyvsp[(2) - (7)].lval), &(yyvsp[(3) - (7)].addr), (yyvsp[(5) - (7)].addr).reg, &(yyvsp[(7) - (7)].addr));
-	}
-    break;
-
-  case 43:
-/* Line 1787 of yacc.c  */
-#line 311 "a.y"
-    {
-		(yyvsp[(7) - (9)].addr).type = D_REGREG2;
-		(yyvsp[(7) - (9)].addr).offset = (yyvsp[(9) - (9)].lval);
-		outcode((yyvsp[(1) - (9)].lval), (yyvsp[(2) - (9)].lval), &(yyvsp[(3) - (9)].addr), (yyvsp[(5) - (9)].addr).reg, &(yyvsp[(7) - (9)].addr));
-	}
-    break;
-
-  case 44:
-/* Line 1787 of yacc.c  */
-#line 320 "a.y"
-    {
-		outcode((yyvsp[(1) - (2)].lval), Always, &(yyvsp[(2) - (2)].addr), NREG, &nullgen);
-	}
-    break;
-
-  case 45:
-/* Line 1787 of yacc.c  */
-#line 327 "a.y"
-    {
-		if((yyvsp[(2) - (4)].addr).type != D_CONST || (yyvsp[(4) - (4)].addr).type != D_CONST)
-			yyerror("arguments to PCDATA must be integer constants");
-		outcode((yyvsp[(1) - (4)].lval), Always, &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
-	}
-    break;
-
-  case 46:
-/* Line 1787 of yacc.c  */
-#line 336 "a.y"
-    {
-		if((yyvsp[(2) - (4)].addr).type != D_CONST)
-			yyerror("index for FUNCDATA must be integer constant");
-		if((yyvsp[(4) - (4)].addr).type != D_EXTERN && (yyvsp[(4) - (4)].addr).type != D_STATIC && (yyvsp[(4) - (4)].addr).type != D_OREG)
-			yyerror("value for FUNCDATA must be symbol reference");
- 		outcode((yyvsp[(1) - (4)].lval), Always, &(yyvsp[(2) - (4)].addr), NREG, &(yyvsp[(4) - (4)].addr));
-	}
-    break;
-
-  case 47:
-/* Line 1787 of yacc.c  */
-#line 347 "a.y"
-    {
-		outcode((yyvsp[(1) - (2)].lval), Always, &nullgen, NREG, &nullgen);
-	}
-    break;
-
-  case 48:
-/* Line 1787 of yacc.c  */
-#line 352 "a.y"
-    {
-		(yyval.lval) = Always;
-	}
-    break;
-
-  case 49:
-/* Line 1787 of yacc.c  */
-#line 356 "a.y"
-    {
-		(yyval.lval) = ((yyvsp[(1) - (2)].lval) & ~C_SCOND) | (yyvsp[(2) - (2)].lval);
-	}
-    break;
-
-  case 50:
-/* Line 1787 of yacc.c  */
-#line 360 "a.y"
-    {
-		(yyval.lval) = (yyvsp[(1) - (2)].lval) | (yyvsp[(2) - (2)].lval);
-	}
-    break;
-
-  case 53:
-/* Line 1787 of yacc.c  */
-#line 369 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_BRANCH;
-		(yyval.addr).offset = (yyvsp[(1) - (4)].lval) + pc;
-	}
-    break;
-
-  case 54:
-/* Line 1787 of yacc.c  */
-#line 375 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		if(pass == 2)
-			yyerror("undefined label: %s", (yyvsp[(1) - (2)].sym)->name);
-		(yyval.addr).type = D_BRANCH;
-		(yyval.addr).offset = (yyvsp[(2) - (2)].lval);
-	}
-    break;
-
-  case 55:
-/* Line 1787 of yacc.c  */
-#line 383 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_BRANCH;
-		(yyval.addr).offset = (yyvsp[(1) - (2)].sym)->value + (yyvsp[(2) - (2)].lval);
-	}
-    break;
-
-  case 56:
-/* Line 1787 of yacc.c  */
-#line 390 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_CONST;
-		(yyval.addr).offset = (yyvsp[(2) - (2)].lval);
-	}
-    break;
-
-  case 57:
-/* Line 1787 of yacc.c  */
-#line 396 "a.y"
-    {
-		(yyval.addr) = (yyvsp[(2) - (2)].addr);
-		(yyval.addr).type = D_CONST;
-	}
-    break;
-
-  case 58:
-/* Line 1787 of yacc.c  */
-#line 401 "a.y"
-    {
-		(yyval.addr) = (yyvsp[(4) - (4)].addr);
-		(yyval.addr).type = D_OCONST;
-	}
-    break;
-
-  case 59:
-/* Line 1787 of yacc.c  */
-#line 406 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_SCONST;
-		memcpy((yyval.addr).u.sval, (yyvsp[(2) - (2)].sval), sizeof((yyval.addr).u.sval));
-	}
-    break;
-
-  case 61:
-/* Line 1787 of yacc.c  */
-#line 415 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_FCONST;
-		(yyval.addr).u.dval = (yyvsp[(2) - (2)].dval);
-	}
-    break;
-
-  case 62:
-/* Line 1787 of yacc.c  */
-#line 421 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_FCONST;
-		(yyval.addr).u.dval = -(yyvsp[(3) - (3)].dval);
-	}
-    break;
-
-  case 63:
-/* Line 1787 of yacc.c  */
-#line 429 "a.y"
-    {
-		(yyval.lval) = 1 << (yyvsp[(1) - (1)].lval);
-	}
-    break;
-
-  case 64:
-/* Line 1787 of yacc.c  */
-#line 433 "a.y"
-    {
-		int i;
-		(yyval.lval)=0;
-		for(i=(yyvsp[(1) - (3)].lval); i<=(yyvsp[(3) - (3)].lval); i++)
-			(yyval.lval) |= 1<<i;
-		for(i=(yyvsp[(3) - (3)].lval); i<=(yyvsp[(1) - (3)].lval); i++)
-			(yyval.lval) |= 1<<i;
-	}
-    break;
-
-  case 65:
-/* Line 1787 of yacc.c  */
-#line 442 "a.y"
-    {
-		(yyval.lval) = (1<<(yyvsp[(1) - (3)].lval)) | (yyvsp[(3) - (3)].lval);
-	}
-    break;
-
-  case 69:
-/* Line 1787 of yacc.c  */
-#line 451 "a.y"
-    {
-		(yyval.addr) = (yyvsp[(1) - (4)].addr);
-		(yyval.addr).reg = (yyvsp[(3) - (4)].lval);
-	}
-    break;
-
-  case 70:
-/* Line 1787 of yacc.c  */
-#line 456 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_PSR;
-		(yyval.addr).reg = (yyvsp[(1) - (1)].lval);
-	}
-    break;
-
-  case 71:
-/* Line 1787 of yacc.c  */
-#line 462 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_FPCR;
-		(yyval.addr).reg = (yyvsp[(1) - (1)].lval);
-	}
-    break;
-
-  case 72:
-/* Line 1787 of yacc.c  */
-#line 468 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_OREG;
-		(yyval.addr).offset = (yyvsp[(1) - (1)].lval);
-	}
-    break;
-
-  case 76:
-/* Line 1787 of yacc.c  */
-#line 479 "a.y"
-    {
-		(yyval.addr) = (yyvsp[(1) - (1)].addr);
-		if((yyvsp[(1) - (1)].addr).name != D_EXTERN && (yyvsp[(1) - (1)].addr).name != D_STATIC) {
-		}
-	}
-    break;
-
-  case 77:
-/* Line 1787 of yacc.c  */
-#line 487 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_OREG;
-		(yyval.addr).reg = (yyvsp[(2) - (3)].lval);
-		(yyval.addr).offset = 0;
-	}
-    break;
-
-  case 79:
-/* Line 1787 of yacc.c  */
-#line 497 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_OREG;
-		(yyval.addr).reg = (yyvsp[(3) - (4)].lval);
-		(yyval.addr).offset = (yyvsp[(1) - (4)].lval);
-	}
-    break;
-
-  case 81:
-/* Line 1787 of yacc.c  */
-#line 507 "a.y"
-    {
-		(yyval.addr) = (yyvsp[(1) - (4)].addr);
-		(yyval.addr).type = D_OREG;
-		(yyval.addr).reg = (yyvsp[(3) - (4)].lval);
-	}
-    break;
-
-  case 86:
-/* Line 1787 of yacc.c  */
-#line 520 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_CONST;
-		(yyval.addr).offset = (yyvsp[(2) - (2)].lval);
-	}
-    break;
-
-  case 87:
-/* Line 1787 of yacc.c  */
-#line 528 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_REG;
-		(yyval.addr).reg = (yyvsp[(1) - (1)].lval);
-	}
-    break;
-
-  case 88:
-/* Line 1787 of yacc.c  */
-#line 536 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_REGREG;
-		(yyval.addr).reg = (yyvsp[(2) - (5)].lval);
-		(yyval.addr).offset = (yyvsp[(4) - (5)].lval);
-	}
-    break;
-
-  case 89:
-/* Line 1787 of yacc.c  */
-#line 545 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_SHIFT;
-		(yyval.addr).offset = (yyvsp[(1) - (4)].lval) | (yyvsp[(4) - (4)].lval) | (0 << 5);
-	}
-    break;
-
-  case 90:
-/* Line 1787 of yacc.c  */
-#line 551 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_SHIFT;
-		(yyval.addr).offset = (yyvsp[(1) - (4)].lval) | (yyvsp[(4) - (4)].lval) | (1 << 5);
-	}
-    break;
-
-  case 91:
-/* Line 1787 of yacc.c  */
-#line 557 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_SHIFT;
-		(yyval.addr).offset = (yyvsp[(1) - (4)].lval) | (yyvsp[(4) - (4)].lval) | (2 << 5);
-	}
-    break;
-
-  case 92:
-/* Line 1787 of yacc.c  */
-#line 563 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_SHIFT;
-		(yyval.addr).offset = (yyvsp[(1) - (4)].lval) | (yyvsp[(4) - (4)].lval) | (3 << 5);
-	}
-    break;
-
-  case 93:
-/* Line 1787 of yacc.c  */
-#line 571 "a.y"
-    {
-		if((yyval.lval) < 0 || (yyval.lval) >= 16)
-			print("register value out of range\n");
-		(yyval.lval) = (((yyvsp[(1) - (1)].lval)&15) << 8) | (1 << 4);
-	}
-    break;
-
-  case 94:
-/* Line 1787 of yacc.c  */
-#line 577 "a.y"
-    {
-		if((yyval.lval) < 0 || (yyval.lval) >= 32)
-			print("shift value out of range\n");
-		(yyval.lval) = ((yyvsp[(1) - (1)].lval)&31) << 7;
-	}
-    break;
-
-  case 96:
-/* Line 1787 of yacc.c  */
-#line 586 "a.y"
-    {
-		(yyval.lval) = REGPC;
-	}
-    break;
-
-  case 97:
-/* Line 1787 of yacc.c  */
-#line 590 "a.y"
-    {
-		if((yyvsp[(3) - (4)].lval) < 0 || (yyvsp[(3) - (4)].lval) >= NREG)
-			print("register value out of range\n");
-		(yyval.lval) = (yyvsp[(3) - (4)].lval);
-	}
-    break;
-
-  case 99:
-/* Line 1787 of yacc.c  */
-#line 599 "a.y"
-    {
-		(yyval.lval) = REGSP;
-	}
-    break;
-
-  case 101:
-/* Line 1787 of yacc.c  */
-#line 606 "a.y"
-    {
-		if((yyvsp[(3) - (4)].lval) < 0 || (yyvsp[(3) - (4)].lval) >= NREG)
-			print("register value out of range\n");
-		(yyval.lval) = (yyvsp[(3) - (4)].lval);
-	}
-    break;
-
-  case 104:
-/* Line 1787 of yacc.c  */
-#line 618 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_FREG;
-		(yyval.addr).reg = (yyvsp[(1) - (1)].lval);
-	}
-    break;
-
-  case 105:
-/* Line 1787 of yacc.c  */
-#line 624 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_FREG;
-		(yyval.addr).reg = (yyvsp[(3) - (4)].lval);
-	}
-    break;
-
-  case 106:
-/* Line 1787 of yacc.c  */
-#line 632 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_OREG;
-		(yyval.addr).name = (yyvsp[(3) - (4)].lval);
-		(yyval.addr).sym = nil;
-		(yyval.addr).offset = (yyvsp[(1) - (4)].lval);
-	}
-    break;
-
-  case 107:
-/* Line 1787 of yacc.c  */
-#line 640 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_OREG;
-		(yyval.addr).name = (yyvsp[(4) - (5)].lval);
-		(yyval.addr).sym = linklookup(ctxt, (yyvsp[(1) - (5)].sym)->name, 0);
-		(yyval.addr).offset = (yyvsp[(2) - (5)].lval);
-	}
-    break;
-
-  case 108:
-/* Line 1787 of yacc.c  */
-#line 648 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_OREG;
-		(yyval.addr).name = D_STATIC;
-		(yyval.addr).sym = linklookup(ctxt, (yyvsp[(1) - (7)].sym)->name, 1);
-		(yyval.addr).offset = (yyvsp[(4) - (7)].lval);
-	}
-    break;
-
-  case 109:
-/* Line 1787 of yacc.c  */
-#line 657 "a.y"
-    {
-		(yyval.lval) = 0;
-	}
-    break;
-
-  case 110:
-/* Line 1787 of yacc.c  */
-#line 661 "a.y"
-    {
-		(yyval.lval) = (yyvsp[(2) - (2)].lval);
-	}
-    break;
-
-  case 111:
-/* Line 1787 of yacc.c  */
-#line 665 "a.y"
-    {
-		(yyval.lval) = -(yyvsp[(2) - (2)].lval);
-	}
-    break;
-
-  case 116:
-/* Line 1787 of yacc.c  */
-#line 677 "a.y"
-    {
-		(yyval.lval) = (yyvsp[(1) - (1)].sym)->value;
-	}
-    break;
-
-  case 117:
-/* Line 1787 of yacc.c  */
-#line 681 "a.y"
-    {
-		(yyval.lval) = -(yyvsp[(2) - (2)].lval);
-	}
-    break;
-
-  case 118:
-/* Line 1787 of yacc.c  */
-#line 685 "a.y"
-    {
-		(yyval.lval) = (yyvsp[(2) - (2)].lval);
-	}
-    break;
-
-  case 119:
-/* Line 1787 of yacc.c  */
-#line 689 "a.y"
-    {
-		(yyval.lval) = ~(yyvsp[(2) - (2)].lval);
-	}
-    break;
-
-  case 120:
-/* Line 1787 of yacc.c  */
-#line 693 "a.y"
-    {
-		(yyval.lval) = (yyvsp[(2) - (3)].lval);
-	}
-    break;
-
-  case 121:
-/* Line 1787 of yacc.c  */
-#line 698 "a.y"
-    {
-		(yyval.lval) = 0;
-	}
-    break;
-
-  case 122:
-/* Line 1787 of yacc.c  */
-#line 702 "a.y"
-    {
-		(yyval.lval) = (yyvsp[(2) - (2)].lval);
-	}
-    break;
-
-  case 124:
-/* Line 1787 of yacc.c  */
-#line 709 "a.y"
-    {
-		(yyval.lval) = (yyvsp[(1) - (3)].lval) + (yyvsp[(3) - (3)].lval);
-	}
-    break;
-
-  case 125:
-/* Line 1787 of yacc.c  */
-#line 713 "a.y"
-    {
-		(yyval.lval) = (yyvsp[(1) - (3)].lval) - (yyvsp[(3) - (3)].lval);
-	}
-    break;
-
-  case 126:
-/* Line 1787 of yacc.c  */
-#line 717 "a.y"
-    {
-		(yyval.lval) = (yyvsp[(1) - (3)].lval) * (yyvsp[(3) - (3)].lval);
-	}
-    break;
-
-  case 127:
-/* Line 1787 of yacc.c  */
-#line 721 "a.y"
-    {
-		(yyval.lval) = (yyvsp[(1) - (3)].lval) / (yyvsp[(3) - (3)].lval);
-	}
-    break;
-
-  case 128:
-/* Line 1787 of yacc.c  */
-#line 725 "a.y"
-    {
-		(yyval.lval) = (yyvsp[(1) - (3)].lval) % (yyvsp[(3) - (3)].lval);
-	}
-    break;
-
-  case 129:
-/* Line 1787 of yacc.c  */
-#line 729 "a.y"
-    {
-		(yyval.lval) = (yyvsp[(1) - (4)].lval) << (yyvsp[(4) - (4)].lval);
-	}
-    break;
-
-  case 130:
-/* Line 1787 of yacc.c  */
-#line 733 "a.y"
-    {
-		(yyval.lval) = (yyvsp[(1) - (4)].lval) >> (yyvsp[(4) - (4)].lval);
-	}
-    break;
-
-  case 131:
-/* Line 1787 of yacc.c  */
-#line 737 "a.y"
-    {
-		(yyval.lval) = (yyvsp[(1) - (3)].lval) & (yyvsp[(3) - (3)].lval);
-	}
-    break;
-
-  case 132:
-/* Line 1787 of yacc.c  */
-#line 741 "a.y"
-    {
-		(yyval.lval) = (yyvsp[(1) - (3)].lval) ^ (yyvsp[(3) - (3)].lval);
-	}
-    break;
-
-  case 133:
-/* Line 1787 of yacc.c  */
-#line 745 "a.y"
-    {
-		(yyval.lval) = (yyvsp[(1) - (3)].lval) | (yyvsp[(3) - (3)].lval);
-	}
-    break;
-
-
-/* Line 1787 of yacc.c  */
-#line 2707 "y.tab.c"
-      default: break;
-    }
-  /* User semantic actions sometimes alter yychar, and that requires
-     that yytoken be updated with the new translation.  We take the
-     approach of translating immediately before every use of yytoken.
-     One alternative is translating here after every semantic action,
-     but that translation would be missed if the semantic action invokes
-     YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
-     if it invokes YYBACKUP.  In the case of YYABORT or YYACCEPT, an
-     incorrect destructor might then be invoked immediately.  In the
-     case of YYERROR or YYBACKUP, subsequent parser actions might lead
-     to an incorrect destructor call or verbose syntax error message
-     before the lookahead is translated.  */
-  YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
-
-  YYPOPSTACK (yylen);
-  yylen = 0;
-  YY_STACK_PRINT (yyss, yyssp);
-
-  *++yyvsp = yyval;
-
-  /* Now `shift' the result of the reduction.  Determine what state
-     that goes to, based on the state we popped back to and the rule
-     number reduced by.  */
-
-  yyn = yyr1[yyn];
-
-  yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
-  if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
-    yystate = yytable[yystate];
-  else
-    yystate = yydefgoto[yyn - YYNTOKENS];
-
-  goto yynewstate;
-
-
-/*------------------------------------.
-| yyerrlab -- here on detecting error |
-`------------------------------------*/
-yyerrlab:
-  /* Make sure we have latest lookahead translation.  See comments at
-     user semantic actions for why this is necessary.  */
-  yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar);
-
-  /* If not already recovering from an error, report this error.  */
-  if (!yyerrstatus)
-    {
-      ++yynerrs;
-#if ! YYERROR_VERBOSE
-      yyerror (YY_("syntax error"));
-#else
-# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \
-                                        yyssp, yytoken)
-      {
-        char const *yymsgp = YY_("syntax error");
-        int yysyntax_error_status;
-        yysyntax_error_status = YYSYNTAX_ERROR;
-        if (yysyntax_error_status == 0)
-          yymsgp = yymsg;
-        else if (yysyntax_error_status == 1)
-          {
-            if (yymsg != yymsgbuf)
-              YYSTACK_FREE (yymsg);
-            yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc);
-            if (!yymsg)
-              {
-                yymsg = yymsgbuf;
-                yymsg_alloc = sizeof yymsgbuf;
-                yysyntax_error_status = 2;
-              }
-            else
-              {
-                yysyntax_error_status = YYSYNTAX_ERROR;
-                yymsgp = yymsg;
-              }
-          }
-        yyerror (yymsgp);
-        if (yysyntax_error_status == 2)
-          goto yyexhaustedlab;
-      }
-# undef YYSYNTAX_ERROR
-#endif
-    }
-
-
-
-  if (yyerrstatus == 3)
-    {
-      /* If just tried and failed to reuse lookahead token after an
-	 error, discard it.  */
-
-      if (yychar <= YYEOF)
-	{
-	  /* Return failure if at end of input.  */
-	  if (yychar == YYEOF)
-	    YYABORT;
-	}
-      else
-	{
-	  yydestruct ("Error: discarding",
-		      yytoken, &yylval);
-	  yychar = YYEMPTY;
-	}
-    }
-
-  /* Else will try to reuse lookahead token after shifting the error
-     token.  */
-  goto yyerrlab1;
-
-
-/*---------------------------------------------------.
-| yyerrorlab -- error raised explicitly by YYERROR.  |
-`---------------------------------------------------*/
-yyerrorlab:
-
-  /* Pacify compilers like GCC when the user code never invokes
-     YYERROR and the label yyerrorlab therefore never appears in user
-     code.  */
-  if (/*CONSTCOND*/ 0)
-     goto yyerrorlab;
-
-  /* Do not reclaim the symbols of the rule which action triggered
-     this YYERROR.  */
-  YYPOPSTACK (yylen);
-  yylen = 0;
-  YY_STACK_PRINT (yyss, yyssp);
-  yystate = *yyssp;
-  goto yyerrlab1;
-
-
-/*-------------------------------------------------------------.
-| yyerrlab1 -- common code for both syntax error and YYERROR.  |
-`-------------------------------------------------------------*/
-yyerrlab1:
-  yyerrstatus = 3;	/* Each real token shifted decrements this.  */
-
-  for (;;)
-    {
-      yyn = yypact[yystate];
-      if (!yypact_value_is_default (yyn))
-	{
-	  yyn += YYTERROR;
-	  if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
-	    {
-	      yyn = yytable[yyn];
-	      if (0 < yyn)
-		break;
-	    }
-	}
-
-      /* Pop the current state because it cannot handle the error token.  */
-      if (yyssp == yyss)
-	YYABORT;
-
-
-      yydestruct ("Error: popping",
-		  yystos[yystate], yyvsp);
-      YYPOPSTACK (1);
-      yystate = *yyssp;
-      YY_STACK_PRINT (yyss, yyssp);
-    }
-
-  YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
-  *++yyvsp = yylval;
-  YY_IGNORE_MAYBE_UNINITIALIZED_END
-
-
-  /* Shift the error token.  */
-  YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
-
-  yystate = yyn;
-  goto yynewstate;
-
-
-/*-------------------------------------.
-| yyacceptlab -- YYACCEPT comes here.  |
-`-------------------------------------*/
-yyacceptlab:
-  yyresult = 0;
-  goto yyreturn;
-
-/*-----------------------------------.
-| yyabortlab -- YYABORT comes here.  |
-`-----------------------------------*/
-yyabortlab:
-  yyresult = 1;
-  goto yyreturn;
-
-#if !defined yyoverflow || YYERROR_VERBOSE
-/*-------------------------------------------------.
-| yyexhaustedlab -- memory exhaustion comes here.  |
-`-------------------------------------------------*/
-yyexhaustedlab:
-  yyerror (YY_("memory exhausted"));
-  yyresult = 2;
-  /* Fall through.  */
-#endif
-
-yyreturn:
-  if (yychar != YYEMPTY)
-    {
-      /* Make sure we have latest lookahead translation.  See comments at
-         user semantic actions for why this is necessary.  */
-      yytoken = YYTRANSLATE (yychar);
-      yydestruct ("Cleanup: discarding lookahead",
-                  yytoken, &yylval);
-    }
-  /* Do not reclaim the symbols of the rule which action triggered
-     this YYABORT or YYACCEPT.  */
-  YYPOPSTACK (yylen);
-  YY_STACK_PRINT (yyss, yyssp);
-  while (yyssp != yyss)
-    {
-      yydestruct ("Cleanup: popping",
-		  yystos[*yyssp], yyvsp);
-      YYPOPSTACK (1);
-    }
-#ifndef yyoverflow
-  if (yyss != yyssa)
-    YYSTACK_FREE (yyss);
-#endif
-#if YYERROR_VERBOSE
-  if (yymsg != yymsgbuf)
-    YYSTACK_FREE (yymsg);
-#endif
-  /* Make sure YYID is used.  */
-  return YYID (yyresult);
-}
-
-
diff --git a/src/cmd/5a/y.tab.h b/src/cmd/5a/y.tab.h
deleted file mode 100644
index f11fb85..0000000
--- a/src/cmd/5a/y.tab.h
+++ /dev/null
@@ -1,188 +0,0 @@
-/* A Bison parser, made by GNU Bison 2.7.12-4996.  */
-
-/* Bison interface for Yacc-like parsers in C
-   
-      Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
-   
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 of the License, or
-   (at your option) any later version.
-   
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-   
-   You should have received a copy of the GNU General Public License
-   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
-
-/* As a special exception, you may create a larger work that contains
-   part or all of the Bison parser skeleton and distribute that work
-   under terms of your choice, so long as that work isn't itself a
-   parser generator using the skeleton or a modified version thereof
-   as a parser skeleton.  Alternatively, if you modify or redistribute
-   the parser skeleton itself, you may (at your option) remove this
-   special exception, which will cause the skeleton and the resulting
-   Bison output files to be licensed under the GNU General Public
-   License without this special exception.
-   
-   This special exception was added by the Free Software Foundation in
-   version 2.2 of Bison.  */
-
-#ifndef YY_YY_Y_TAB_H_INCLUDED
-# define YY_YY_Y_TAB_H_INCLUDED
-/* Enabling traces.  */
-#ifndef YYDEBUG
-# define YYDEBUG 0
-#endif
-#if YYDEBUG
-extern int yydebug;
-#endif
-
-/* Tokens.  */
-#ifndef YYTOKENTYPE
-# define YYTOKENTYPE
-   /* Put the tokens into the symbol table, so that GDB and other debuggers
-      know about them.  */
-   enum yytokentype {
-     LTYPE1 = 258,
-     LTYPE2 = 259,
-     LTYPE3 = 260,
-     LTYPE4 = 261,
-     LTYPE5 = 262,
-     LTYPE6 = 263,
-     LTYPE7 = 264,
-     LTYPE8 = 265,
-     LTYPE9 = 266,
-     LTYPEA = 267,
-     LTYPEB = 268,
-     LTYPEC = 269,
-     LTYPED = 270,
-     LTYPEE = 271,
-     LTYPEG = 272,
-     LTYPEH = 273,
-     LTYPEI = 274,
-     LTYPEJ = 275,
-     LTYPEK = 276,
-     LTYPEL = 277,
-     LTYPEM = 278,
-     LTYPEN = 279,
-     LTYPEBX = 280,
-     LTYPEPLD = 281,
-     LCONST = 282,
-     LSP = 283,
-     LSB = 284,
-     LFP = 285,
-     LPC = 286,
-     LTYPEX = 287,
-     LTYPEPC = 288,
-     LTYPEF = 289,
-     LR = 290,
-     LREG = 291,
-     LF = 292,
-     LFREG = 293,
-     LC = 294,
-     LCREG = 295,
-     LPSR = 296,
-     LFCR = 297,
-     LCOND = 298,
-     LS = 299,
-     LAT = 300,
-     LFCONST = 301,
-     LSCONST = 302,
-     LNAME = 303,
-     LLAB = 304,
-     LVAR = 305
-   };
-#endif
-/* Tokens.  */
-#define LTYPE1 258
-#define LTYPE2 259
-#define LTYPE3 260
-#define LTYPE4 261
-#define LTYPE5 262
-#define LTYPE6 263
-#define LTYPE7 264
-#define LTYPE8 265
-#define LTYPE9 266
-#define LTYPEA 267
-#define LTYPEB 268
-#define LTYPEC 269
-#define LTYPED 270
-#define LTYPEE 271
-#define LTYPEG 272
-#define LTYPEH 273
-#define LTYPEI 274
-#define LTYPEJ 275
-#define LTYPEK 276
-#define LTYPEL 277
-#define LTYPEM 278
-#define LTYPEN 279
-#define LTYPEBX 280
-#define LTYPEPLD 281
-#define LCONST 282
-#define LSP 283
-#define LSB 284
-#define LFP 285
-#define LPC 286
-#define LTYPEX 287
-#define LTYPEPC 288
-#define LTYPEF 289
-#define LR 290
-#define LREG 291
-#define LF 292
-#define LFREG 293
-#define LC 294
-#define LCREG 295
-#define LPSR 296
-#define LFCR 297
-#define LCOND 298
-#define LS 299
-#define LAT 300
-#define LFCONST 301
-#define LSCONST 302
-#define LNAME 303
-#define LLAB 304
-#define LVAR 305
-
-
-
-#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-typedef union YYSTYPE
-{
-/* Line 2053 of yacc.c  */
-#line 39 "a.y"
-
-	Sym	*sym;
-	int32	lval;
-	double	dval;
-	char	sval[8];
-	Addr	addr;
-
-
-/* Line 2053 of yacc.c  */
-#line 166 "y.tab.h"
-} YYSTYPE;
-# define YYSTYPE_IS_TRIVIAL 1
-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
-# define YYSTYPE_IS_DECLARED 1
-#endif
-
-extern YYSTYPE yylval;
-
-#ifdef YYPARSE_PARAM
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void *YYPARSE_PARAM);
-#else
-int yyparse ();
-#endif
-#else /* ! YYPARSE_PARAM */
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void);
-#else
-int yyparse ();
-#endif
-#endif /* ! YYPARSE_PARAM */
-
-#endif /* !YY_YY_Y_TAB_H_INCLUDED  */
diff --git a/src/cmd/5c/Makefile b/src/cmd/5c/Makefile
deleted file mode 100644
index 3f528d7..0000000
--- a/src/cmd/5c/Makefile
+++ /dev/null
@@ -1,5 +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.
-
-include ../../Make.dist
diff --git a/src/cmd/5c/cgen.c b/src/cmd/5c/cgen.c
deleted file mode 100644
index 5a049ae..0000000
--- a/src/cmd/5c/cgen.c
+++ /dev/null
@@ -1,1213 +0,0 @@
-// Inferno utils/5c/cgen.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5c/cgen.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include "gc.h"
-#include "../../runtime/funcdata.h"
-
-void
-_cgen(Node *n, Node *nn, int inrel)
-{
-	Node *l, *r;
-	Prog *p1;
-	Node nod, nod1, nod2, nod3, nod4;
-	int o, t;
-	int32 v, curs;
-
-	if(debug['g']) {
-		prtree(nn, "cgen lhs");
-		prtree(n, "cgen");
-	}
-	if(n == Z || n->type == T)
-		return;
-	if(typesuv[n->type->etype] && (n->op != OFUNC || nn != Z)) {
-		sugen(n, nn, n->type->width);
-		return;
-	}
-	l = n->left;
-	r = n->right;
-	o = n->op;
-	if(n->addable >= INDEXED) {
-		if(nn == Z) {
-			switch(o) {
-			default:
-				nullwarn(Z, Z);
-				break;
-			case OINDEX:
-				nullwarn(l, r);
-				break;
-			}
-			return;
-		}
-		gmove(n, nn);
-		return;
-	}
-	curs = cursafe;
-
-	if(n->complex >= FNX)
-	if(l->complex >= FNX)
-	if(r != Z && r->complex >= FNX)
-	switch(o) {
-	default:
-		regret(&nod, r, 0, 0);
-		cgen(r, &nod);
-
-		regsalloc(&nod1, r);
-		gopcode(OAS, &nod, Z, &nod1);
-
-		regfree(&nod);
-		nod = *n;
-		nod.right = &nod1;
-		cgen(&nod, nn);
-		return;
-
-	case OFUNC:
-	case OCOMMA:
-	case OANDAND:
-	case OOROR:
-	case OCOND:
-	case ODOT:
-		break;
-	}
-
-	switch(o) {
-	default:
-		diag(n, "unknown op in cgen: %O", o);
-		break;
-
-	case OAS:
-		if(l->op == OBIT)
-			goto bitas;
-		if(l->addable >= INDEXED && l->complex < FNX) {
-			if(nn != Z || r->addable < INDEXED) {
-				if(r->complex >= FNX && nn == Z)
-					regret(&nod, r, 0, 0);
-				else
-					regalloc(&nod, r, nn);
-				cgen(r, &nod);
-				gmove(&nod, l);
-				if(nn != Z)
-					gmove(&nod, nn);
-				regfree(&nod);
-			} else
-				gmove(r, l);
-			break;
-		}
-		if(l->complex >= r->complex) {
-			reglcgen(&nod1, l, Z);
-			if(r->addable >= INDEXED) {
-				gmove(r, &nod1);
-				if(nn != Z)
-					gmove(r, nn);
-				regfree(&nod1);
-				break;
-			}
-			regalloc(&nod, r, nn);
-			cgen(r, &nod);
-		} else {
-			regalloc(&nod, r, nn);
-			cgen(r, &nod);
-			reglcgen(&nod1, l, Z);
-		}
-		gmove(&nod, &nod1);
-		regfree(&nod);
-		regfree(&nod1);
-		break;
-
-	bitas:
-		n = l->left;
-		regalloc(&nod, r, nn);
-		if(l->complex >= r->complex) {
-			reglcgen(&nod1, n, Z);
-			cgen(r, &nod);
-		} else {
-			cgen(r, &nod);
-			reglcgen(&nod1, n, Z);
-		}
-		regalloc(&nod2, n, Z);
-		gopcode(OAS, &nod1, Z, &nod2);
-		bitstore(l, &nod, &nod1, &nod2, nn);
-		break;
-
-	case OBIT:
-		if(nn == Z) {
-			nullwarn(l, Z);
-			break;
-		}
-		bitload(n, &nod, Z, Z, nn);
-		gopcode(OAS, &nod, Z, nn);
-		regfree(&nod);
-		break;
-
-	case ODIV:
-	case OMOD:
-		if(nn != Z)
-		if((t = vlog(r)) >= 0) {
-			/* signed div/mod by constant power of 2 */
-			cgen(l, nn);
-			gopcode(OGE, nodconst(0), nn, Z);
-			p1 = p;
-			if(o == ODIV) {
-				gopcode(OADD, nodconst((1<<t)-1), Z, nn);
-				patch(p1, pc);
-				gopcode(OASHR, nodconst(t), Z, nn);
-			} else {
-				gopcode(OSUB, nn, nodconst(0), nn);
-				gopcode(OAND, nodconst((1<<t)-1), Z, nn);
-				gopcode(OSUB, nn, nodconst(0), nn);
-				gbranch(OGOTO);
-				patch(p1, pc);
-				p1 = p;
-				gopcode(OAND, nodconst((1<<t)-1), Z, nn);
-				patch(p1, pc);
-			}
-			break;
-		}
-		goto muldiv;
-
-	case OSUB:
-		if(nn != Z)
-		if(l->op == OCONST)
-		if(!typefd[n->type->etype]) {
-			cgen(r, nn);
-			gopcode(o, Z, l, nn);
-			break;
-		}
-	case OADD:
-	case OAND:
-	case OOR:
-	case OXOR:
-	case OLSHR:
-	case OASHL:
-	case OASHR:
-		/*
-		 * immediate operands
-		 */
-		if(nn != Z)
-		if(r->op == OCONST)
-		if(!typefd[n->type->etype]) {
-			cgen(l, nn);
-			if(r->vconst == 0)
-			if(o != OAND)
-				break;
-			if(nn != Z)
-				gopcode(o, r, Z, nn);
-			break;
-		}
-
-	case OLMUL:
-	case OLDIV:
-	case OLMOD:
-	case OMUL:
-	muldiv:
-		if(nn == Z) {
-			nullwarn(l, r);
-			break;
-		}
-		if(o == OMUL || o == OLMUL) {
-			if(mulcon(n, nn))
-				break;
-		}
-		if(l->complex >= r->complex) {
-			regalloc(&nod, l, nn);
-			cgen(l, &nod);
-			regalloc(&nod1, r, Z);
-			cgen(r, &nod1);
-			gopcode(o, &nod1, Z, &nod);
-		} else {
-			regalloc(&nod, r, nn);
-			cgen(r, &nod);
-			regalloc(&nod1, l, Z);
-			cgen(l, &nod1);
-			gopcode(o, &nod, &nod1, &nod);
-		}
-		gopcode(OAS, &nod, Z, nn);
-		regfree(&nod);
-		regfree(&nod1);
-		break;
-
-	case OASLSHR:
-	case OASASHL:
-	case OASASHR:
-	case OASAND:
-	case OASADD:
-	case OASSUB:
-	case OASXOR:
-	case OASOR:
-		if(l->op == OBIT)
-			goto asbitop;
-		if(r->op == OCONST)
-		if(!typefd[r->type->etype])
-		if(!typefd[n->type->etype]) {
-			if(l->addable < INDEXED)
-				reglcgen(&nod2, l, Z);
-			else
-				nod2 = *l;
-			regalloc(&nod, r, nn);
-			gopcode(OAS, &nod2, Z, &nod);
-			gopcode(o, r, Z, &nod);
-			gopcode(OAS, &nod, Z, &nod2);
-
-			regfree(&nod);
-			if(l->addable < INDEXED)
-				regfree(&nod2);
-			break;
-		}
-
-	case OASLMUL:
-	case OASLDIV:
-	case OASLMOD:
-	case OASMUL:
-	case OASDIV:
-	case OASMOD:
-		if(l->op == OBIT)
-			goto asbitop;
-		if(l->complex >= r->complex) {
-			if(l->addable < INDEXED)
-				reglcgen(&nod2, l, Z);
-			else
-				nod2 = *l;
-			regalloc(&nod1, r, Z);
-			cgen(r, &nod1);
-		} else {
-			regalloc(&nod1, r, Z);
-			cgen(r, &nod1);
-			if(l->addable < INDEXED)
-				reglcgen(&nod2, l, Z);
-			else
-				nod2 = *l;
-		}
-
-		regalloc(&nod, n, nn);
-		gmove(&nod2, &nod);
-		gopcode(o, &nod1, Z, &nod);
-		gmove(&nod, &nod2);
-		if(nn != Z)
-			gopcode(OAS, &nod, Z, nn);
-		regfree(&nod);
-		regfree(&nod1);
-		if(l->addable < INDEXED)
-			regfree(&nod2);
-		break;
-
-	asbitop:
-		regalloc(&nod4, n, nn);
-		if(l->complex >= r->complex) {
-			bitload(l, &nod, &nod1, &nod2, &nod4);
-			regalloc(&nod3, r, Z);
-			cgen(r, &nod3);
-		} else {
-			regalloc(&nod3, r, Z);
-			cgen(r, &nod3);
-			bitload(l, &nod, &nod1, &nod2, &nod4);
-		}
-		gmove(&nod, &nod4);
-		gopcode(o, &nod3, Z, &nod4);
-		regfree(&nod3);
-		gmove(&nod4, &nod);
-		regfree(&nod4);
-		bitstore(l, &nod, &nod1, &nod2, nn);
-		break;
-
-	case OADDR:
-		if(nn == Z) {
-			nullwarn(l, Z);
-			break;
-		}
-		lcgen(l, nn);
-		break;
-
-	case OFUNC:
-		if(l->complex >= FNX) {
-			if(l->op != OIND)
-				diag(n, "bad function call");
-
-			regret(&nod, l->left, 0, 0);
-			cgen(l->left, &nod);
-			regsalloc(&nod1, l->left);
-			gopcode(OAS, &nod, Z, &nod1);
-			regfree(&nod);
-
-			nod = *n;
-			nod.left = &nod2;
-			nod2 = *l;
-			nod2.left = &nod1;
-			nod2.complex = 1;
-			cgen(&nod, nn);
-
-			return;
-		}
-		if(REGARG >= 0)
-			o = reg[REGARG];
-		gargs(r, &nod, &nod1);
-		if(l->addable < INDEXED) {
-			reglcgen(&nod, l, Z);
-			gopcode(OFUNC, Z, Z, &nod);
-			regfree(&nod);
-		} else
-			gopcode(OFUNC, Z, Z, l);
-		if(REGARG >= 0)
-			if(o != reg[REGARG])
-				reg[REGARG]--;
-		regret(&nod, n, l->type, 1);
-		if(nn != Z)
-			gmove(&nod, nn);
-		if(nod.op == OREGISTER)
-			regfree(&nod);
-		break;
-
-	case OIND:
-		if(nn == Z) {
-			nullwarn(l, Z);
-			break;
-		}
-		regialloc(&nod, n, nn);
-		r = l;
-		while(r->op == OADD)
-			r = r->right;
-		if(sconst(r) && (v = r->vconst+nod.xoffset) > -4096 && v < 4096) {
-			v = r->vconst;
-			r->vconst = 0;
-			cgen(l, &nod);
-			nod.xoffset += v;
-			r->vconst = v;
-		} else
-			cgen(l, &nod);
-		regind(&nod, n);
-		gopcode(OAS, &nod, Z, nn);
-		regfree(&nod);
-		break;
-
-	case OEQ:
-	case ONE:
-	case OLE:
-	case OLT:
-	case OGE:
-	case OGT:
-	case OLO:
-	case OLS:
-	case OHI:
-	case OHS:
-		if(nn == Z) {
-			nullwarn(l, r);
-			break;
-		}
-		boolgen(n, 1, nn);
-		break;
-
-	case OANDAND:
-	case OOROR:
-		boolgen(n, 1, nn);
-		if(nn == Z)
-			patch(p, pc);
-		break;
-
-	case ONOT:
-		if(nn == Z) {
-			nullwarn(l, Z);
-			break;
-		}
-		boolgen(n, 1, nn);
-		break;
-
-	case OCOMMA:
-		cgen(l, Z);
-		cgen(r, nn);
-		break;
-
-	case OCAST:
-		if(nn == Z) {
-			nullwarn(l, Z);
-			break;
-		}
-		/*
-		 * convert from types l->n->nn
-		 */
-		if(nocast(l->type, n->type)) {
-			if(nocast(n->type, nn->type)) {
-				cgen(l, nn);
-				break;
-			}
-		}
-		regalloc(&nod, l, nn);
-		cgen(l, &nod);
-		regalloc(&nod1, n, &nod);
-		if(inrel)
-			gmover(&nod, &nod1);
-		else
-			gopcode(OAS, &nod, Z, &nod1);
-		gopcode(OAS, &nod1, Z, nn);
-		regfree(&nod1);
-		regfree(&nod);
-		break;
-
-	case ODOT:
-		sugen(l, nodrat, l->type->width);
-		if(nn != Z) {
-			warn(n, "non-interruptable temporary");
-			nod = *nodrat;
-			if(!r || r->op != OCONST) {
-				diag(n, "DOT and no offset");
-				break;
-			}
-			nod.xoffset += (int32)r->vconst;
-			nod.type = n->type;
-			cgen(&nod, nn);
-		}
-		break;
-
-	case OCOND:
-		bcgen(l, 1);
-		p1 = p;
-		cgen(r->left, nn);
-		gbranch(OGOTO);
-		patch(p1, pc);
-		p1 = p;
-		cgen(r->right, nn);
-		patch(p1, pc);
-		break;
-
-	case OPOSTINC:
-	case OPOSTDEC:
-		v = 1;
-		if(l->type->etype == TIND)
-			v = l->type->link->width;
-		if(o == OPOSTDEC)
-			v = -v;
-		if(l->op == OBIT)
-			goto bitinc;
-		if(nn == Z)
-			goto pre;
-
-		if(l->addable < INDEXED)
-			reglcgen(&nod2, l, Z);
-		else
-			nod2 = *l;
-
-		regalloc(&nod, l, nn);
-		gopcode(OAS, &nod2, Z, &nod);
-		regalloc(&nod1, l, Z);
-		if(typefd[l->type->etype]) {
-			regalloc(&nod3, l, Z);
-			if(v < 0) {
-				gopcode(OAS, nodfconst(-v), Z, &nod3);
-				gopcode(OSUB, &nod3, &nod, &nod1);
-			} else {
-				gopcode(OAS, nodfconst(v), Z, &nod3);
-				gopcode(OADD, &nod3, &nod, &nod1);
-			}
-			regfree(&nod3);
-		} else
-			gopcode(OADD, nodconst(v), &nod, &nod1);
-		gopcode(OAS, &nod1, Z, &nod2);
-
-		regfree(&nod);
-		regfree(&nod1);
-		if(l->addable < INDEXED)
-			regfree(&nod2);
-		break;
-
-	case OPREINC:
-	case OPREDEC:
-		v = 1;
-		if(l->type->etype == TIND)
-			v = l->type->link->width;
-		if(o == OPREDEC)
-			v = -v;
-		if(l->op == OBIT)
-			goto bitinc;
-
-	pre:
-		if(l->addable < INDEXED)
-			reglcgen(&nod2, l, Z);
-		else
-			nod2 = *l;
-
-		regalloc(&nod, l, nn);
-		gopcode(OAS, &nod2, Z, &nod);
-		if(typefd[l->type->etype]) {
-			regalloc(&nod3, l, Z);
-			if(v < 0) {
-				gopcode(OAS, nodfconst(-v), Z, &nod3);
-				gopcode(OSUB, &nod3, Z, &nod);
-			} else {
-				gopcode(OAS, nodfconst(v), Z, &nod3);
-				gopcode(OADD, &nod3, Z, &nod);
-			}
-			regfree(&nod3);
-		} else
-			gopcode(OADD, nodconst(v), Z, &nod);
-		gopcode(OAS, &nod, Z, &nod2);
-
-		regfree(&nod);
-		if(l->addable < INDEXED)
-			regfree(&nod2);
-		break;
-
-	bitinc:
-		if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) {
-			bitload(l, &nod, &nod1, &nod2, Z);
-			gopcode(OAS, &nod, Z, nn);
-			gopcode(OADD, nodconst(v), Z, &nod);
-			bitstore(l, &nod, &nod1, &nod2, Z);
-			break;
-		}
-		bitload(l, &nod, &nod1, &nod2, nn);
-		gopcode(OADD, nodconst(v), Z, &nod);
-		bitstore(l, &nod, &nod1, &nod2, nn);
-		break;
-	}
-	cursafe = curs;
-	return;
-}
-
-void
-cgen(Node *n, Node *nn)
-{
-	_cgen(n, nn, 0);
-}
-
-void
-cgenrel(Node *n, Node *nn)
-{
-	_cgen(n, nn, 1);
-}
-
-void
-reglcgen(Node *t, Node *n, Node *nn)
-{
-	Node *r;
-	int32 v;
-
-	regialloc(t, n, nn);
-	if(n->op == OIND) {
-		r = n->left;
-		while(r->op == OADD)
-			r = r->right;
-		if(sconst(r) && (v = r->vconst+t->xoffset) > -4096 && v < 4096) {
-			v = r->vconst;
-			r->vconst = 0;
-			lcgen(n, t);
-			t->xoffset += v;
-			r->vconst = v;
-			regind(t, n);
-			return;
-		}
-	} else if(n->op == OINDREG) {
-		if((v = n->xoffset) > -4096 && v < 4096) {
-			n->op = OREGISTER;
-			cgen(n, t);
-			t->xoffset += v;
-			n->op = OINDREG;
-			regind(t, n);
-			return;
-		}
-	}
-	lcgen(n, t);
-	regind(t, n);
-}
-
-void
-reglpcgen(Node *n, Node *nn, int f)
-{
-	Type *t;
-
-	t = nn->type;
-	nn->type = types[TLONG];
-	if(f)
-		reglcgen(n, nn, Z);
-	else {
-		regialloc(n, nn, Z);
-		lcgen(nn, n);
-		regind(n, nn);
-	}
-	nn->type = t;
-}
-
-void
-lcgen(Node *n, Node *nn)
-{
-	Prog *p1;
-	Node nod;
-
-	if(debug['g']) {
-		prtree(nn, "lcgen lhs");
-		prtree(n, "lcgen");
-	}
-	if(n == Z || n->type == T)
-		return;
-	if(nn == Z) {
-		nn = &nod;
-		regalloc(&nod, n, Z);
-	}
-	switch(n->op) {
-	default:
-		if(n->addable < INDEXED) {
-			diag(n, "unknown op in lcgen: %O", n->op);
-			break;
-		}
-		nod = *n;
-		nod.op = OADDR;
-		nod.left = n;
-		nod.right = Z;
-		nod.type = types[TIND];
-		gopcode(OAS, &nod, Z, nn);
-		break;
-
-	case OCOMMA:
-		cgen(n->left, n->left);
-		lcgen(n->right, nn);
-		break;
-
-	case OIND:
-		cgen(n->left, nn);
-		break;
-
-	case OCOND:
-		bcgen(n->left, 1);
-		p1 = p;
-		lcgen(n->right->left, nn);
-		gbranch(OGOTO);
-		patch(p1, pc);
-		p1 = p;
-		lcgen(n->right->right, nn);
-		patch(p1, pc);
-		break;
-	}
-}
-
-void
-bcgen(Node *n, int true)
-{
-
-	if(n->type == T)
-		gbranch(OGOTO);
-	else
-		boolgen(n, true, Z);
-}
-
-void
-boolgen(Node *n, int true, Node *nn)
-{
-	int o;
-	Prog *p1, *p2;
-	Node *l, *r, nod, nod1;
-	int32 curs;
-
-	if(debug['g']) {
-		prtree(nn, "boolgen lhs");
-		prtree(n, "boolgen");
-	}
-	curs = cursafe;
-	l = n->left;
-	r = n->right;
-	switch(n->op) {
-
-	default:
-		regalloc(&nod, n, nn);
-		cgen(n, &nod);
-		o = ONE;
-		if(true)
-			o = comrel[relindex(o)];
-		if(typefd[n->type->etype]) {
-			gopcode(o, nodfconst(0), &nod, Z);
-		} else
-			gopcode(o, nodconst(0), &nod, Z);
-		regfree(&nod);
-		goto com;
-
-	case OCONST:
-		o = vconst(n);
-		if(!true)
-			o = !o;
-		gbranch(OGOTO);
-		if(o) {
-			p1 = p;
-			gbranch(OGOTO);
-			patch(p1, pc);
-		}
-		goto com;
-
-	case OCOMMA:
-		cgen(l, Z);
-		boolgen(r, true, nn);
-		break;
-
-	case ONOT:
-		boolgen(l, !true, nn);
-		break;
-
-	case OCOND:
-		bcgen(l, 1);
-		p1 = p;
-		bcgen(r->left, true);
-		p2 = p;
-		gbranch(OGOTO);
-		patch(p1, pc);
-		p1 = p;
-		bcgen(r->right, !true);
-		patch(p2, pc);
-		p2 = p;
-		gbranch(OGOTO);
-		patch(p1, pc);
-		patch(p2, pc);
-		goto com;
-
-	case OANDAND:
-		if(!true)
-			goto caseor;
-
-	caseand:
-		bcgen(l, true);
-		p1 = p;
-		bcgen(r, !true);
-		p2 = p;
-		patch(p1, pc);
-		gbranch(OGOTO);
-		patch(p2, pc);
-		goto com;
-
-	case OOROR:
-		if(!true)
-			goto caseand;
-
-	caseor:
-		bcgen(l, !true);
-		p1 = p;
-		bcgen(r, !true);
-		p2 = p;
-		gbranch(OGOTO);
-		patch(p1, pc);
-		patch(p2, pc);
-		goto com;
-
-	case OEQ:
-	case ONE:
-	case OLE:
-	case OLT:
-	case OGE:
-	case OGT:
-	case OHI:
-	case OHS:
-	case OLO:
-	case OLS:
-		o = n->op;
-		if(true)
-			o = comrel[relindex(o)];
-		if(l->complex >= FNX && r->complex >= FNX) {
-			regret(&nod, r, 0, 0);
-			cgenrel(r, &nod);
-			regsalloc(&nod1, r);
-			gopcode(OAS, &nod, Z, &nod1);
-			regfree(&nod);
-			nod = *n;
-			nod.right = &nod1;
-			boolgen(&nod, true, nn);
-			break;
-		}
-		if(sconst(l)) {
-			regalloc(&nod, r, nn);
-			cgenrel(r, &nod);
-			o = invrel[relindex(o)];
-			gopcode(o, l, &nod, Z);
-			regfree(&nod);
-			goto com;
-		}
-		if(sconst(r)) {
-			regalloc(&nod, l, nn);
-			cgenrel(l, &nod);
-			gopcode(o, r, &nod, Z);
-			regfree(&nod);
-			goto com;
-		}
-		if(l->complex >= r->complex) {
-			regalloc(&nod1, l, nn);
-			cgenrel(l, &nod1);
-			regalloc(&nod, r, Z);
-			cgenrel(r, &nod);
-		} else {
-			regalloc(&nod, r, nn);
-			cgenrel(r, &nod);
-			regalloc(&nod1, l, Z);
-			cgenrel(l, &nod1);
-		}
-		gopcode(o, &nod, &nod1, Z);
-		regfree(&nod);
-		regfree(&nod1);
-
-	com:
-		if(nn != Z) {
-			p1 = p;
-			gopcode(OAS, nodconst(1), Z, nn);
-			gbranch(OGOTO);
-			p2 = p;
-			patch(p1, pc);
-			gopcode(OAS, nodconst(0), Z, nn);
-			patch(p2, pc);
-		}
-		break;
-	}
-	cursafe = curs;
-}
-
-void
-sugen(Node *n, Node *nn, int32 w)
-{
-	Prog *p1;
-	Node nod0, nod1, nod2, nod3, nod4, *l, *r;
-	Type *t;
-	int32 pc1;
-	int i, m, c;
-
-	if(n == Z || n->type == T)
-		return;
-	if(debug['g']) {
-		prtree(nn, "sugen lhs");
-		prtree(n, "sugen");
-	}
-	if(nn == nodrat)
-		if(w > nrathole)
-			nrathole = w;
-	switch(n->op) {
-	case OIND:
-		if(nn == Z) {
-			nullwarn(n->left, Z);
-			break;
-		}
-
-	default:
-		goto copy;
-
-	case OCONST:
-		if(n->type && typev[n->type->etype]) {
-			if(nn == Z) {
-				nullwarn(n->left, Z);
-				break;
-			}
-
-			t = nn->type;
-			nn->type = types[TLONG];
-			reglcgen(&nod1, nn, Z);
-			nn->type = t;
-
-			if(isbigendian)
-				gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1);
-			else
-				gopcode(OAS, nod32const(n->vconst), Z, &nod1);
-			nod1.xoffset += SZ_LONG;
-			if(isbigendian)
-				gopcode(OAS, nod32const(n->vconst), Z, &nod1);
-			else
-				gopcode(OAS, nod32const(n->vconst>>32), Z, &nod1);
-
-			regfree(&nod1);
-			break;
-		}
-		goto copy;
-
-	case ODOT:
-		l = n->left;
-		sugen(l, nodrat, l->type->width);
-		if(nn != Z) {
-			warn(n, "non-interruptable temporary");
-			nod1 = *nodrat;
-			r = n->right;
-			if(!r || r->op != OCONST) {
-				diag(n, "DOT and no offset");
-				break;
-			}
-			nod1.xoffset += (int32)r->vconst;
-			nod1.type = n->type;
-			sugen(&nod1, nn, w);
-		}
-		break;
-
-	case OSTRUCT:
-		/*
-		 * rewrite so lhs has no side effect.
-		 */
-		if(nn != Z && side(nn)) {
-			nod1 = *n;
-			nod1.type = typ(TIND, n->type);
-			regret(&nod2, &nod1, 0, 0);
-			lcgen(nn, &nod2);
-			regsalloc(&nod0, &nod1);
-			gopcode(OAS, &nod2, Z, &nod0);
-			regfree(&nod2);
-
-			nod1 = *n;
-			nod1.op = OIND;
-			nod1.left = &nod0;
-			nod1.right = Z;
-			nod1.complex = 1;
-
-			sugen(n, &nod1, w);
-			return;
-		}
-
-		r = n->left;
-		for(t = n->type->link; t != T; t = t->down) {
-			l = r;
-			if(r->op == OLIST) {
-				l = r->left;
-				r = r->right;
-			}
-			if(nn == Z) {
-				cgen(l, nn);
-				continue;
-			}
-			/*
-			 * hand craft *(&nn + o) = l
-			 */
-			nod0 = znode;
-			nod0.op = OAS;
-			nod0.type = t;
-			nod0.left = &nod1;
-			nod0.right = l;
-
-			nod1 = znode;
-			nod1.op = OIND;
-			nod1.type = t;
-			nod1.left = &nod2;
-
-			nod2 = znode;
-			nod2.op = OADD;
-			nod2.type = typ(TIND, t);
-			nod2.left = &nod3;
-			nod2.right = &nod4;
-
-			nod3 = znode;
-			nod3.op = OADDR;
-			nod3.type = nod2.type;
-			nod3.left = nn;
-
-			nod4 = znode;
-			nod4.op = OCONST;
-			nod4.type = nod2.type;
-			nod4.vconst = t->offset;
-
-			ccom(&nod0);
-			acom(&nod0);
-			xcom(&nod0);
-			nod0.addable = 0;
-
-			cgen(&nod0, Z);
-		}
-		break;
-
-	case OAS:
-		if(nn == Z) {
-			if(n->addable < INDEXED)
-				sugen(n->right, n->left, w);
-			break;
-		}
-		sugen(n->right, nodrat, w);
-		warn(n, "non-interruptable temporary");
-		sugen(nodrat, n->left, w);
-		sugen(nodrat, nn, w);
-		break;
-
-	case OFUNC:
-		if(!hasdotdotdot(n->left->type)) {
-			cgen(n, Z);
-			if(nn != Z) {
-				curarg -= n->type->width;
-				regret(&nod1, n, n->left->type, 1);
-				if(nn->complex >= FNX) {
-					regsalloc(&nod2, n);
-					cgen(&nod1, &nod2);
-					nod1 = nod2;
-				}
-				cgen(&nod1, nn);
-			}
-			break;
-		}
-		if(nn == Z) {
-			sugen(n, nodrat, w);
-			break;
-		}
-		if(nn->op != OIND) {
-			nn = new1(OADDR, nn, Z);
-			nn->type = types[TIND];
-			nn->addable = 0;
-		} else
-			nn = nn->left;
-		n = new(OFUNC, n->left, new(OLIST, nn, n->right));
-		n->type = types[TVOID];
-		n->left->type = types[TVOID];
-		cgen(n, Z);
-		break;
-
-	case OCOND:
-		bcgen(n->left, 1);
-		p1 = p;
-		sugen(n->right->left, nn, w);
-		gbranch(OGOTO);
-		patch(p1, pc);
-		p1 = p;
-		sugen(n->right->right, nn, w);
-		patch(p1, pc);
-		break;
-
-	case OCOMMA:
-		cgen(n->left, Z);
-		sugen(n->right, nn, w);
-		break;
-	}
-	return;
-
-copy:
-	if(nn == Z)
-		return;
-	if(n->complex >= FNX && nn->complex >= FNX) {
-		t = nn->type;
-		nn->type = types[TLONG];
-		regialloc(&nod1, nn, Z);
-		lcgen(nn, &nod1);
-		regsalloc(&nod2, nn);
-		nn->type = t;
-
-		gopcode(OAS, &nod1, Z, &nod2);
-		regfree(&nod1);
-
-		nod2.type = typ(TIND, t);
-
-		nod1 = nod2;
-		nod1.op = OIND;
-		nod1.left = &nod2;
-		nod1.right = Z;
-		nod1.complex = 1;
-		nod1.type = t;
-
-		sugen(n, &nod1, w);
-		return;
-	}
-
-	w /= SZ_LONG;
-	if(w <= 2) {
-		if(n->complex > nn->complex) {
-			reglpcgen(&nod1, n, 1);
-			reglpcgen(&nod2, nn, 1);
-		} else {
-			reglpcgen(&nod2, nn, 1);
-			reglpcgen(&nod1, n, 1);
-		}
-		regalloc(&nod3, &regnode, Z);
-		regalloc(&nod4, &regnode, Z);
-		nod0 = *nodconst((1<<nod3.reg)|(1<<nod4.reg));
-		if(w == 2 && nod1.xoffset == 0)
-			gmovm(&nod1, &nod0, 0);
-		else {
-			gmove(&nod1, &nod3);
-			if(w == 2) {
-				nod1.xoffset += SZ_LONG;
-				gmove(&nod1, &nod4);
-			}
-		}
-		if(w == 2 && nod2.xoffset == 0)
-			gmovm(&nod0, &nod2, 0);
-		else {
-			gmove(&nod3, &nod2);
-			if(w == 2) {
-				nod2.xoffset += SZ_LONG;
-				gmove(&nod4, &nod2);
-			}
-		}
-		regfree(&nod1);
-		regfree(&nod2);
-		regfree(&nod3);
-		regfree(&nod4);
-		return;
-	}
-
-	if(n->complex > nn->complex) {
-		reglpcgen(&nod1, n, 0);
-		reglpcgen(&nod2, nn, 0);
-	} else {
-		reglpcgen(&nod2, nn, 0);
-		reglpcgen(&nod1, n, 0);
-	}
-
-	m = 0;
-	for(c = 0; c < w && c < 4; c++) {
-		i = tmpreg();
-		if (i == 0)
-			break;
-		reg[i]++;
-		m |= 1<<i;
-	}
-	nod4 = *(nodconst(m));
-	if(w < 3*c) {
-		for (; w>c; w-=c) {
-			gmovm(&nod1, &nod4, 1);
-			gmovm(&nod4, &nod2, 1);
-		}
-		goto out;
-	}
-
-	regalloc(&nod3, &regnode, Z);
-	gopcode(OAS, nodconst(w/c), Z, &nod3);
-	w %= c;
-
-	pc1 = pc;
-	gmovm(&nod1, &nod4, 1);
-	gmovm(&nod4, &nod2, 1);
-
-	gopcode(OSUB, nodconst(1), Z, &nod3);
-	gopcode(OEQ, nodconst(0), &nod3, Z);
-	p->as = ABGT;
-	patch(p, pc1);
-	regfree(&nod3);
-
-out:
-	if (w) {
-		i = 0;
-		while (c>w) {
-			while ((m&(1<<i)) == 0)
-				i++;
-			m &= ~(1<<i);
-			reg[i] = 0;
-			c--;
-			i++;
-		}
-		nod4.vconst = m;
-		gmovm(&nod1, &nod4, 0);
-		gmovm(&nod4, &nod2, 0);
-	}
-	i = 0;
-	do {
-		while ((m&(1<<i)) == 0)
-			i++;
-		reg[i] = 0;
-		c--;
-		i++;
-	} while (c>0);
-	regfree(&nod1);
-	regfree(&nod2);
-}
diff --git a/src/cmd/5c/doc.go b/src/cmd/5c/doc.go
deleted file mode 100644
index 7291d45..0000000
--- a/src/cmd/5c/doc.go
+++ /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.
-
-// +build ignore
-
-/*
-
-5c is a version of the Plan 9 C compiler.  The original is documented at
-
-	http://plan9.bell-labs.com/magic/man2html/1/8c
-
-Its target architecture is the ARM, referred to by these tools as arm.
-
-*/
-package main
diff --git a/src/cmd/5c/gc.h b/src/cmd/5c/gc.h
deleted file mode 100644
index 7417b7d..0000000
--- a/src/cmd/5c/gc.h
+++ /dev/null
@@ -1,333 +0,0 @@
-// Inferno utils/5c/gc.h
-// http://code.google.com/p/inferno-os/source/browse/utils/5c/gc.h
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include	<u.h>
-#include	"../cc/cc.h"
-#include	"../5l/5.out.h"
-
-/*
- * 5c/arm
- * Arm 7500
- */
-#define	SZ_CHAR		1
-#define	SZ_SHORT	2
-#define	SZ_INT		4
-#define	SZ_LONG		4
-#define	SZ_IND		4
-#define	SZ_FLOAT	4
-#define	SZ_VLONG	8
-#define	SZ_DOUBLE	8
-#define	FNX		100
-
-typedef	struct	Case	Case;
-typedef	struct	C1	C1;
-typedef	struct	Multab	Multab;
-typedef	struct	Hintab	Hintab;
-typedef	struct	Reg	Reg;
-typedef	struct	Rgn	Rgn;
-
-
-#define	R0ISZERO	0
-
-#define	A	((Addr*)0)
-
-#define	INDEXED	9
-#define	P	((Prog*)0)
-
-struct	Case
-{
-	Case*	link;
-	int32	val;
-	int32	label;
-	char	def;
-	char	isv;
-};
-#define	C	((Case*)0)
-
-struct	C1
-{
-	int32	val;
-	int32	label;
-};
-
-struct	Multab
-{
-	int32	val;
-	char	code[20];
-};
-
-struct	Hintab
-{
-	ushort	val;
-	char	hint[10];
-};
-
-struct	Reg
-{
-	int32	pc;
-	int32	rpo;		/* reverse post ordering */
-
-	Bits	set;
-	Bits	use1;
-	Bits	use2;
-
-	Bits	refbehind;
-	Bits	refahead;
-	Bits	calbehind;
-	Bits	calahead;
-	Bits	regdiff;
-	Bits	act;
-
-	int32	regu;
-	int32	loop;		/* could be shorter */
-
-
-	Reg*	log5;
-	int32	active;
-
-	Reg*	p1;
-	Reg*	p2;
-	Reg*	p2link;
-	Reg*	s1;
-	Reg*	s2;
-	Reg*	link;
-	Prog*	prog;
-};
-#define	R	((Reg*)0)
-
-#define	NRGN	600
-struct	Rgn
-{
-	Reg*	enter;
-	short	cost;
-	short	varno;
-	short	regno;
-};
-
-EXTERN	int32	breakpc;
-EXTERN	int32	nbreak;
-EXTERN	Case*	cases;
-EXTERN	Node	constnode;
-EXTERN	Node	fconstnode;
-EXTERN	int32	continpc;
-EXTERN	int32	curarg;
-EXTERN	int32	cursafe;
-EXTERN	int32	isbigendian;
-EXTERN	Prog*	lastp;
-EXTERN	int32	maxargsafe;
-EXTERN	int	mnstring;
-EXTERN	Multab	multab[20];
-extern	int	hintabsize;
-EXTERN	Node*	nodrat;
-EXTERN	Node*	nodret;
-EXTERN	Node*	nodsafe;
-EXTERN	int32	nrathole;
-EXTERN	int32	nstring;
-EXTERN	Prog*	p;
-EXTERN	int32	pc;
-EXTERN	Node	regnode;
-EXTERN	char	string[NSNAME];
-EXTERN	Sym*	symrathole;
-EXTERN	Node	znode;
-EXTERN	Prog	zprog;
-EXTERN	char	reg[NREG+NFREG];
-EXTERN	int32	exregoffset;
-EXTERN	int32	exfregoffset;
-EXTERN	int	suppress;
-
-#define	BLOAD(r)	band(bnot(r->refbehind), r->refahead)
-#define	BSTORE(r)	band(bnot(r->calbehind), r->calahead)
-#define	LOAD(r)		(~r->refbehind.b[z] & r->refahead.b[z])
-#define	STORE(r)	(~r->calbehind.b[z] & r->calahead.b[z])
-
-#define	bset(a,n)	((a).b[(n)/32]&(1L<<(n)%32))
-
-#define	CLOAD	4
-#define	CREF	5
-#define	CINF	1000
-#define	LOOP	3
-
-EXTERN	Rgn	region[NRGN];
-EXTERN	Rgn*	rgp;
-EXTERN	int	nregion;
-EXTERN	int	nvar;
-
-EXTERN	Bits	externs;
-EXTERN	Bits	params;
-EXTERN	Bits	consts;
-EXTERN	Bits	addrs;
-
-EXTERN	int32	regbits;
-EXTERN	int32	exregbits;
-
-EXTERN	int	change;
-
-EXTERN	Reg*	firstr;
-EXTERN	Reg*	lastr;
-EXTERN	Reg	zreg;
-EXTERN	Reg*	freer;
-EXTERN	int32*	idom;
-EXTERN	Reg**	rpo2r;
-EXTERN	int32	maxnr;
-
-extern	char*	anames[];
-extern	Hintab	hintab[];
-
-/*
- * sgen.c
- */
-void	codgen(Node*, Node*);
-void	gen(Node*);
-void	noretval(int);
-void	usedset(Node*, int);
-void	xcom(Node*);
-int	bcomplex(Node*, Node*);
-Prog*	gtext(Sym*, int32);
-vlong	argsize(int);
-
-/*
- * cgen.c
- */
-void	cgen(Node*, Node*);
-void	reglcgen(Node*, Node*, Node*);
-void	lcgen(Node*, Node*);
-void	bcgen(Node*, int);
-void	boolgen(Node*, int, Node*);
-void	sugen(Node*, Node*, int32);
-void	layout(Node*, Node*, int, int, Node*);
-void	cgenrel(Node*, Node*);
-
-/*
- * txt.c
- */
-void	ginit(void);
-void	gclean(void);
-void	nextpc(void);
-void	gargs(Node*, Node*, Node*);
-void	garg1(Node*, Node*, Node*, int, Node**);
-Node*	nodconst(int32);
-Node*	nod32const(vlong);
-Node*	nodfconst(double);
-void	nodreg(Node*, Node*, int);
-void	regret(Node*, Node*, Type*, int);
-int	tmpreg(void);
-void	regalloc(Node*, Node*, Node*);
-void	regfree(Node*);
-void	regialloc(Node*, Node*, Node*);
-void	regsalloc(Node*, Node*);
-void	regaalloc1(Node*, Node*);
-void	regaalloc(Node*, Node*);
-void	regind(Node*, Node*);
-void	gprep(Node*, Node*);
-void	raddr(Node*, Prog*);
-void	naddr(Node*, Addr*);
-void	gmovm(Node*, Node*, int);
-void	gmove(Node*, Node*);
-void	gmover(Node*, Node*);
-void	gins(int a, Node*, Node*);
-void	gopcode(int, Node*, Node*, Node*);
-int	samaddr(Node*, Node*);
-void	gbranch(int);
-void	patch(Prog*, int32);
-int	sconst(Node*);
-int	sval(int32);
-void	gpseudo(int, Sym*, Node*);
-void	gprefetch(Node*);
-void	gpcdata(int, int);
-
-/*
- * swt.c
- */
-int	swcmp(const void*, const void*);
-void	doswit(Node*);
-void	swit1(C1*, int, int32, Node*);
-void	swit2(C1*, int, int32, Node*);
-void	newcase(void);
-void	bitload(Node*, Node*, Node*, Node*, Node*);
-void	bitstore(Node*, Node*, Node*, Node*, Node*);
-int	mulcon(Node*, Node*);
-Multab*	mulcon0(int32);
-void	nullwarn(Node*, Node*);
-void	outcode(void);
-
-/*
- * list
- */
-void	listinit(void);
-
-/*
- * reg.c
- */
-Reg*	rega(void);
-int	rcmp(const void*, const void*);
-void	regopt(Prog*);
-void	addmove(Reg*, int, int, int);
-Bits	mkvar(Addr*, int);
-void	prop(Reg*, Bits, Bits);
-void	loopit(Reg*, int32);
-void	synch(Reg*, Bits);
-uint32	allreg(uint32, Rgn*);
-void	paint1(Reg*, int);
-uint32	paint2(Reg*, int);
-void	paint3(Reg*, int, int32, int);
-void	addreg(Addr*, int);
-
-/*
- * peep.c
- */
-void	peep(void);
-void	excise(Reg*);
-Reg*	uniqp(Reg*);
-Reg*	uniqs(Reg*);
-int	regtyp(Addr*);
-int	regzer(Addr*);
-int	anyvar(Addr*);
-int	subprop(Reg*);
-int	copyprop(Reg*);
-int	shiftprop(Reg*);
-void	constprop(Addr*, Addr*, Reg*);
-int	copy1(Addr*, Addr*, Reg*, int);
-int	copyu(Prog*, Addr*, Addr*);
-
-int	copyas(Addr*, Addr*);
-int	copyau(Addr*, Addr*);
-int	copyau1(Prog*, Addr*);
-int	copysub(Addr*, Addr*, Addr*, int);
-int	copysub1(Prog*, Addr*, Addr*, int);
-
-int32	RtoB(int);
-int32	FtoB(int);
-int	BtoR(int32);
-int	BtoF(int32);
-
-void	predicate(void);
-int	isbranch(Prog *);
-int	predicable(Prog *p);
-int	modifiescpsr(Prog *p);
diff --git a/src/cmd/5c/list.c b/src/cmd/5c/list.c
deleted file mode 100644
index 98da424..0000000
--- a/src/cmd/5c/list.c
+++ /dev/null
@@ -1,39 +0,0 @@
-// Inferno utils/5c/list.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5c/list.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-
-#define	EXTERN
-#include "gc.h"
-
-void
-listinit(void)
-{
-	listinit5();
-}
diff --git a/src/cmd/5c/mul.c b/src/cmd/5c/mul.c
deleted file mode 100644
index ff50c48..0000000
--- a/src/cmd/5c/mul.c
+++ /dev/null
@@ -1,640 +0,0 @@
-// Inferno utils/5c/mul.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5c/mul.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-
-#include "gc.h"
-
-/*
- * code sequences for multiply by constant.
- * [a-l][0-3]
- *	lsl	$(A-'a'),r0,r1
- * [+][0-7]
- *	add	r0,r1,r2
- * [-][0-7]
- *	sub	r0,r1,r2
- */
-
-static  int	maxmulops = 3;	/* max # of ops to replace mul with */
-static	int	multabp;
-static	int32	mulval;
-static	char*	mulcp;
-static	int32	valmax;
-static	int	shmax;
-
-static int	docode(char *hp, char *cp, int r0, int r1);
-static int	gen1(int len);
-static int	gen2(int len, int32 r1);
-static int	gen3(int len, int32 r0, int32 r1, int flag);
-enum
-{
-	SR1	= 1<<0,		/* r1 has been shifted */
-	SR0	= 1<<1,		/* r0 has been shifted */
-	UR1	= 1<<2,		/* r1 has not been used */
-	UR0	= 1<<3,		/* r0 has not been used */
-};
-
-Multab*
-mulcon0(int32 v)
-{
-	int a1, a2, g;
-	Multab *m, *m1;
-	char hint[10];
-
-	if(v < 0)
-		v = -v;
-
-	/*
-	 * look in cache
-	 */
-	m = multab;
-	for(g=0; g<nelem(multab); g++) {
-		if(m->val == v) {
-			if(m->code[0] == 0)
-				return 0;
-			return m;
-		}
-		m++;
-	}
-
-	/*
-	 * select a spot in cache to overwrite
-	 */
-	multabp++;
-	if(multabp < 0 || multabp >= nelem(multab))
-		multabp = 0;
-	m = multab+multabp;
-	m->val = v;
-	mulval = v;
-
-	/*
-	 * look in execption hint table
-	 */
-	a1 = 0;
-	a2 = hintabsize;
-	for(;;) {
-		if(a1 >= a2)
-			goto no;
-		g = (a2 + a1)/2;
-		if(v < hintab[g].val) {
-			a2 = g;
-			continue;
-		}
-		if(v > hintab[g].val) {
-			a1 = g+1;
-			continue;
-		}
-		break;
-	}
-
-	if(docode(hintab[g].hint, m->code, 1, 0))
-		return m;
-	print("multiply table failure %d\n", v);
-	m->code[0] = 0;
-	return 0;
-
-no:
-	/*
-	 * try to search
-	 */
-	hint[0] = 0;
-	for(g=1; g<=maxmulops; g++) {
-		if(g >= maxmulops && v >= 65535)
-			break;
-		mulcp = hint+g;
-		*mulcp = 0;
-		if(gen1(g)) {
-			if(docode(hint, m->code, 1, 0))
-				return m;
-			print("multiply table failure %d\n", v);
-			break;
-		}
-	}
-
-	/*
-	 * try a recur followed by a shift
-	 */
-	g = 0;
-	while(!(v & 1)) {
-		g++;
-		v >>= 1;
-	}
-	if(g) {
-		m1 = mulcon0(v);
-		if(m1) {
-			strcpy(m->code, m1->code);
-			sprint(strchr(m->code, 0), "%c0", g+'a');
-			return m;
-		}
-	}
-	m->code[0] = 0;
-	return 0;
-}
-
-static int
-docode(char *hp, char *cp, int r0, int r1)
-{
-	int c, i;
-
-	c = *hp++;
-	*cp = c;
-	cp += 2;
-	switch(c) {
-	default:
-		c -= 'a';
-		if(c < 1 || c >= 30)
-			break;
-		for(i=0; i<4; i++) {
-			switch(i) {
-			case 0:
-				if(docode(hp, cp, r0<<c, r1))
-					goto out;
-				break;
-			case 1:
-				if(docode(hp, cp, r1<<c, r1))
-					goto out;
-				break;
-			case 2:
-				if(docode(hp, cp, r0, r0<<c))
-					goto out;
-				break;
-			case 3:
-				if(docode(hp, cp, r0, r1<<c))
-					goto out;
-				break;
-			}
-		}
-		break;
-
-	case '+':
-		for(i=0; i<8; i++) {
-			cp[-1] = i+'0';
-			switch(i) {
-			case 1:
-				if(docode(hp, cp, r0+r1, r1))
-					goto out;
-				break;
-			case 5:
-				if(docode(hp, cp, r0, r0+r1))
-					goto out;
-				break;
-			}
-		}
-		break;
-
-	case '-':
-		for(i=0; i<8; i++) {
-			cp[-1] = i+'0';
-			switch(i) {
-			case 1:
-				if(docode(hp, cp, r0-r1, r1))
-					goto out;
-				break;
-			case 2:
-				if(docode(hp, cp, r1-r0, r1))
-					goto out;
-				break;
-			case 5:
-				if(docode(hp, cp, r0, r0-r1))
-					goto out;
-				break;
-			case 6:
-				if(docode(hp, cp, r0, r1-r0))
-					goto out;
-				break;
-			}
-		}
-		break;
-
-	case 0:
-		if(r0 == mulval)
-			return 1;
-	}
-	return 0;
-
-out:
-	cp[-1] = i+'0';
-	return 1;
-}
-
-static int
-gen1(int len)
-{
-	int i;
-
-	for(shmax=1; shmax<30; shmax++) {
-		valmax = 1<<shmax;
-		if(valmax >= mulval)
-			break;
-	}
-	if(mulval == 1)
-		return 1;
-
-	len--;
-	for(i=1; i<=shmax; i++)
-		if(gen2(len, 1<<i)) {
-			*--mulcp = 'a'+i;
-			return 1;
-		}
-	return 0;
-}
-
-static int
-gen2(int len, int32 r1)
-{
-	int i;
-
-	if(len <= 0) {
-		if(r1 == mulval)
-			return 1;
-		return 0;
-	}
-
-	len--;
-	if(len == 0)
-		goto calcr0;
-
-	if(gen3(len, r1, r1+1, UR1)) {
-		i = '+';
-		goto out;
-	}
-	if(gen3(len, r1-1, r1, UR0)) {
-		i = '-';
-		goto out;
-	}
-	if(gen3(len, 1, r1+1, UR1)) {
-		i = '+';
-		goto out;
-	}
-	if(gen3(len, 1, r1-1, UR1)) {
-		i = '-';
-		goto out;
-	}
-
-	return 0;
-
-calcr0:
-	if(mulval == r1+1) {
-		i = '+';
-		goto out;
-	}
-	if(mulval == r1-1) {
-		i = '-';
-		goto out;
-	}
-	return 0;
-
-out:
-	*--mulcp = i;
-	return 1;
-}
-
-static int
-gen3(int len, int32 r0, int32 r1, int flag)
-{
-	int i, f1, f2;
-	int32 x;
-
-	if(r0 <= 0 ||
-	   r0 >= r1 ||
-	   r1 > valmax)
-		return 0;
-
-	len--;
-	if(len == 0)
-		goto calcr0;
-
-	if(!(flag & UR1)) {
-		f1 = UR1|SR1;
-		for(i=1; i<=shmax; i++) {
-			x = r0<<i;
-			if(x > valmax)
-				break;
-			if(gen3(len, r0, x, f1)) {
-				i += 'a';
-				goto out;
-			}
-		}
-	}
-
-	if(!(flag & UR0)) {
-		f1 = UR1|SR1;
-		for(i=1; i<=shmax; i++) {
-			x = r1<<i;
-			if(x > valmax)
-				break;
-			if(gen3(len, r1, x, f1)) {
-				i += 'a';
-				goto out;
-			}
-		}
-	}
-
-	if(!(flag & SR1)) {
-		f1 = UR1|SR1|(flag&UR0);
-		for(i=1; i<=shmax; i++) {
-			x = r1<<i;
-			if(x > valmax)
-				break;
-			if(gen3(len, r0, x, f1)) {
-				i += 'a';
-				goto out;
-			}
-		}
-	}
-
-	if(!(flag & SR0)) {
-		f1 = UR0|SR0|(flag&(SR1|UR1));
-
-		f2 = UR1|SR1;
-		if(flag & UR1)
-			f2 |= UR0;
-		if(flag & SR1)
-			f2 |= SR0;
-
-		for(i=1; i<=shmax; i++) {
-			x = r0<<i;
-			if(x > valmax)
-				break;
-			if(x > r1) {
-				if(gen3(len, r1, x, f2)) {
-					i += 'a';
-					goto out;
-				}
-			} else
-				if(gen3(len, x, r1, f1)) {
-					i += 'a';
-					goto out;
-				}
-		}
-	}
-
-	x = r1+r0;
-	if(gen3(len, r0, x, UR1)) {
-		i = '+';
-		goto out;
-	}
-
-	if(gen3(len, r1, x, UR1)) {
-		i = '+';
-		goto out;
-	}
-
-	x = r1-r0;
-	if(gen3(len, x, r1, UR0)) {
-		i = '-';
-		goto out;
-	}
-
-	if(x > r0) {
-		if(gen3(len, r0, x, UR1)) {
-			i = '-';
-			goto out;
-		}
-	} else
-		if(gen3(len, x, r0, UR0)) {
-			i = '-';
-			goto out;
-		}
-
-	return 0;
-
-calcr0:
-	f1 = flag & (UR0|UR1);
-	if(f1 == UR1) {
-		for(i=1; i<=shmax; i++) {
-			x = r1<<i;
-			if(x >= mulval) {
-				if(x == mulval) {
-					i += 'a';
-					goto out;
-				}
-				break;
-			}
-		}
-	}
-
-	if(mulval == r1+r0) {
-		i = '+';
-		goto out;
-	}
-	if(mulval == r1-r0) {
-		i = '-';
-		goto out;
-	}
-
-	return 0;
-
-out:
-	*--mulcp = i;
-	return 1;
-}
-
-/*
- * hint table has numbers that
- * the search algorithm fails on.
- * <1000:
- *	all numbers
- * <5000:
- * 	÷ by 5
- * <10000:
- * 	÷ by 50
- * <65536:
- * 	÷ by 250
- */
-Hintab	hintab[] =
-{
-	683,	"b++d+e+",
-	687,	"b+e++e-",
-	691,	"b++d+e+",
-	731,	"b++d+e+",
-	811,	"b++d+i+",
-	821,	"b++e+e+",
-	843,	"b+d++e+",
-	851,	"b+f-+e-",
-	853,	"b++e+e+",
-	877,	"c++++g-",
-	933,	"b+c++g-",
-	981,	"c-+e-d+",
-	1375,	"b+c+b+h-",
-	1675,	"d+b++h+",
-	2425,	"c++f-e+",
-	2675,	"c+d++f-",
-	2750,	"b+d-b+h-",
-	2775,	"c-+g-e-",
-	3125,	"b++e+g+",
-	3275,	"b+c+g+e+",
-	3350,	"c++++i+",
-	3475,	"c-+e-f-",
-	3525,	"c-+d+g-",
-	3625,	"c-+e-j+",
-	3675,	"b+d+d+e+",
-	3725,	"b+d-+h+",
-	3925,	"b+d+f-d-",
-	4275,	"b+g++e+",
-	4325,	"b+h-+d+",
-	4425,	"b+b+g-j-",
-	4525,	"b+d-d+f+",
-	4675,	"c++d-g+",
-	4775,	"b+d+b+g-",
-	4825,	"c+c-+i-",
-	4850,	"c++++i-",
-	4925,	"b++e-g-",
-	4975,	"c+f++e-",
-	5500,	"b+g-c+d+",
-	6700,	"d+b++i+",
-	9700,	"d++++j-",
-	11000,	"b+f-c-h-",
-	11750,	"b+d+g+j-",
-	12500,	"b+c+e-k+",
-	13250,	"b+d+e-f+",
-	13750,	"b+h-c-d+",
-	14250,	"b+g-c+e-",
-	14500,	"c+f+j-d-",
-	14750,	"d-g--f+",
-	16750,	"b+e-d-n+",
-	17750,	"c+h-b+e+",
-	18250,	"d+b+h-d+",
-	18750,	"b+g-++f+",
-	19250,	"b+e+b+h+",
-	19750,	"b++h--f-",
-	20250,	"b+e-l-c+",
-	20750,	"c++bi+e-",
-	21250,	"b+i+l+c+",
-	22000,	"b+e+d-g-",
-	22250,	"b+d-h+k-",
-	22750,	"b+d-e-g+",
-	23250,	"b+c+h+e-",
-	23500,	"b+g-c-g-",
-	23750,	"b+g-b+h-",
-	24250,	"c++g+m-",
-	24750,	"b+e+e+j-",
-	25000,	"b++dh+g+",
-	25250,	"b+e+d-g-",
-	25750,	"b+e+b+j+",
-	26250,	"b+h+c+e+",
-	26500,	"b+h+c+g+",
-	26750,	"b+d+e+g-",
-	27250,	"b+e+e+f+",
-	27500,	"c-i-c-d+",
-	27750,	"b+bd++j+",
-	28250,	"d-d-++i-",
-	28500,	"c+c-h-e-",
-	29000,	"b+g-d-f+",
-	29500,	"c+h+++e-",
-	29750,	"b+g+f-c+",
-	30250,	"b+f-g-c+",
-	33500,	"c-f-d-n+",
-	33750,	"b+d-b+j-",
-	34250,	"c+e+++i+",
-	35250,	"e+b+d+k+",
-	35500,	"c+e+d-g-",
-	35750,	"c+i-++e+",
-	36250,	"b+bh-d+e+",
-	36500,	"c+c-h-e-",
-	36750,	"d+e--i+",
-	37250,	"b+g+g+b+",
-	37500,	"b+h-b+f+",
-	37750,	"c+be++j-",
-	38500,	"b+e+b+i+",
-	38750,	"d+i-b+d+",
-	39250,	"b+g-l-+d+",
-	39500,	"b+g-c+g-",
-	39750,	"b+bh-c+f-",
-	40250,	"b+bf+d+g-",
-	40500,	"b+g-c+g+",
-	40750,	"c+b+i-e+",
-	41250,	"d++bf+h+",
-	41500,	"b+j+c+d-",
-	41750,	"c+f+b+h-",
-	42500,	"c+h++g+",
-	42750,	"b+g+d-f-",
-	43250,	"b+l-e+d-",
-	43750,	"c+bd+h+f-",
-	44000,	"b+f+g-d-",
-	44250,	"b+d-g--f+",
-	44500,	"c+e+c+h+",
-	44750,	"b+e+d-h-",
-	45250,	"b++g+j-g+",
-	45500,	"c+d+e-g+",
-	45750,	"b+d-h-e-",
-	46250,	"c+bd++j+",
-	46500,	"b+d-c-j-",
-	46750,	"e-e-b+g-",
-	47000,	"b+c+d-j-",
-	47250,	"b+e+e-g-",
-	47500,	"b+g-c-h-",
-	47750,	"b+f-c+h-",
-	48250,	"d--h+n-",
-	48500,	"b+c-g+m-",
-	48750,	"b+e+e-g+",
-	49500,	"c-f+e+j-",
-	49750,	"c+c+g++f-",
-	50000,	"b+e+e+k+",
-	50250,	"b++i++g+",
-	50500,	"c+g+f-i+",
-	50750,	"b+e+d+k-",
-	51500,	"b+i+c-f+",
-	51750,	"b+bd+g-e-",
-	52250,	"b+d+g-j+",
-	52500,	"c+c+f+g+",
-	52750,	"b+c+e+i+",
-	53000,	"b+i+c+g+",
-	53500,	"c+g+g-n+",
-	53750,	"b+j+d-c+",
-	54250,	"b+d-g-j-",
-	54500,	"c-f+e+f+",
-	54750,	"b+f-+c+g+",
-	55000,	"b+g-d-g-",
-	55250,	"b+e+e+g+",
-	55500,	"b+cd++j+",
-	55750,	"b+bh-d-f-",
-	56250,	"c+d-b+j-",
-	56500,	"c+d+c+i+",
-	56750,	"b+e+d++h-",
-	57000,	"b+d+g-f+",
-	57250,	"b+f-m+d-",
-	57750,	"b+i+c+e-",
-	58000,	"b+e+d+h+",
-	58250,	"c+b+g+g+",
-	58750,	"d-e-j--e+",
-	59000,	"d-i-+e+",
-	59250,	"e--h-m+",
-	59500,	"c+c-h+f-",
-	59750,	"b+bh-e+i-",
-	60250,	"b+bh-e-e-",
-	60500,	"c+c-g-g-",
-	60750,	"b+e-l-e-",
-	61250,	"b+g-g-c+",
-	61750,	"b+g-c+g+",
-	62250,	"f--+c-i-",
-	62750,	"e+f--+g+",
-	64750,	"b+f+d+p-",
-};
-int	hintabsize	= nelem(hintab);
diff --git a/src/cmd/5c/peep.c b/src/cmd/5c/peep.c
deleted file mode 100644
index 1de56b5..0000000
--- a/src/cmd/5c/peep.c
+++ /dev/null
@@ -1,1478 +0,0 @@
-// Inferno utils/5c/peep.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5c/peep.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-
-#include "gc.h"
-
-int xtramodes(Reg*, Addr*);
-
-void
-peep(void)
-{
-	Reg *r, *r1, *r2;
-	Prog *p, *p1;
-	int t;
-/*
- * complete R structure
- */
-	t = 0;
-	for(r=firstr; r!=R; r=r1) {
-		r1 = r->link;
-		if(r1 == R)
-			break;
-		p = r->prog->link;
-		while(p != r1->prog)
-		switch(p->as) {
-		default:
-			r2 = rega();
-			r->link = r2;
-			r2->link = r1;
-
-			r2->prog = p;
-			r2->p1 = r;
-			r->s1 = r2;
-			r2->s1 = r1;
-			r1->p1 = r2;
-
-			r = r2;
-			t++;
-
-		case ADATA:
-		case AGLOBL:
-		case ANAME:
-		case ASIGNAME:
-			p = p->link;
-		}
-	}
-
-loop1:
-	t = 0;
-	for(r=firstr; r!=R; r=r->link) {
-		p = r->prog;
-		if(p->as == ASLL || p->as == ASRL || p->as == ASRA) {
-			/*
-			 * elide shift into D_SHIFT operand of subsequent instruction
-			 */
-			if(shiftprop(r)) {
-				excise(r);
-				t++;
-			}
-		}
-		if(p->as == AMOVW || p->as == AMOVF || p->as == AMOVD)
-		if(regtyp(&p->to)) {
-			if(p->from.type == D_CONST)
-				constprop(&p->from, &p->to, r->s1);
-			else if(regtyp(&p->from))
-			if(p->from.type == p->to.type) {
-				if(copyprop(r)) {
-					excise(r);
-					t++;
-				} else
-				if(subprop(r) && copyprop(r)) {
-					excise(r);
-					t++;
-				}
-			}
-		}
-	}
-	if(t)
-		goto loop1;
-	/*
-	 * look for MOVB x,R; MOVB R,R
-	 */
-	for(r=firstr; r!=R; r=r->link) {
-		p = r->prog;
-		switch(p->as) {
-		default:
-			continue;
-		case AEOR:
-			/*
-			 * EOR -1,x,y => MVN x,y
-			 */
-			if(p->from.type == D_CONST && p->from.offset == -1) {
-				p->as = AMVN;
-				p->from.type = D_REG;
-				if(p->reg != NREG)
-					p->from.reg = p->reg;
-				else
-					p->from.reg = p->to.reg;
-				p->reg = NREG;
-			}
-			continue;
-		case AMOVH:
-		case AMOVHS:
-		case AMOVHU:
-		case AMOVB:
-		case AMOVBS:
-		case AMOVBU:
-			if(p->to.type != D_REG)
-				continue;
-			break;
-		}
-		r1 = r->link;
-		if(r1 == R)
-			continue;
-		p1 = r1->prog;
-		if(p1->as != p->as)
-			continue;
-		if(p1->from.type != D_REG || p1->from.reg != p->to.reg)
-			continue;
-		if(p1->to.type != D_REG || p1->to.reg != p->to.reg)
-			continue;
-		excise(r1);
-	}
-
-	for(r=firstr; r!=R; r=r->link) {
-		p = r->prog;
-		switch(p->as) {
-		case AMOVW:
-		case AMOVB:
-		case AMOVBS:
-		case AMOVBU:
-			if(p->from.type == D_OREG && p->from.offset == 0)
-				xtramodes(r, &p->from);
-			else if(p->to.type == D_OREG && p->to.offset == 0)
-				xtramodes(r, &p->to);
-			else
-				continue;
-			break;
-		case ACMP:
-			/*
-			 * elide CMP $0,x if calculation of x can set condition codes
-			 */
-			if(p->from.type != D_CONST || p->from.offset != 0)
-				continue;
-			r2 = r->s1;
-			if(r2 == R)
-				continue;
-			t = r2->prog->as;
-			switch(t) {
-			default:
-				continue;
-			case ABEQ:
-			case ABNE:
-			case ABMI:
-			case ABPL:
-				break;
-			case ABGE:
-				t = ABPL;
-				break;
-			case ABLT:
-				t = ABMI;
-				break;
-			case ABHI:
-				t = ABNE;
-				break;
-			case ABLS:
-				t = ABEQ;
-				break;
-			}
-			r1 = r;
-			do
-				r1 = uniqp(r1);
-			while (r1 != R && r1->prog->as == ANOP);
-			if(r1 == R)
-				continue;
-			p1 = r1->prog;
-			if(p1->to.type != D_REG)
-				continue;
-			if(p1->to.reg != p->reg)
-			if(!(p1->as == AMOVW && p1->from.type == D_REG && p1->from.reg == p->reg))
-				continue;
-			switch(p1->as) {
-			default:
-				continue;
-			case AMOVW:
-				if(p1->from.type != D_REG)
-					continue;
-			case AAND:
-			case AEOR:
-			case AORR:
-			case ABIC:
-			case AMVN:
-			case ASUB:
-			case ARSB:
-			case AADD:
-			case AADC:
-			case ASBC:
-			case ARSC:
-				break;
-			}
-			p1->scond |= C_SBIT;
-			r2->prog->as = t;
-			excise(r);
-			continue;
-		}
-	}
-
-	predicate();
-}
-
-void
-excise(Reg *r)
-{
-	Prog *p;
-
-	p = r->prog;
-	p->as = ANOP;
-	p->scond = zprog.scond;
-	p->from = zprog.from;
-	p->to = zprog.to;
-	p->reg = zprog.reg; /**/
-}
-
-Reg*
-uniqp(Reg *r)
-{
-	Reg *r1;
-
-	r1 = r->p1;
-	if(r1 == R) {
-		r1 = r->p2;
-		if(r1 == R || r1->p2link != R)
-			return R;
-	} else
-		if(r->p2 != R)
-			return R;
-	return r1;
-}
-
-Reg*
-uniqs(Reg *r)
-{
-	Reg *r1;
-
-	r1 = r->s1;
-	if(r1 == R) {
-		r1 = r->s2;
-		if(r1 == R)
-			return R;
-	} else
-		if(r->s2 != R)
-			return R;
-	return r1;
-}
-
-int
-regtyp(Addr *a)
-{
-
-	if(a->type == D_REG)
-		return 1;
-	if(a->type == D_FREG)
-		return 1;
-	return 0;
-}
-
-/*
- * the idea is to substitute
- * one register for another
- * from one MOV to another
- *	MOV	a, R0
- *	ADD	b, R0	/ no use of R1
- *	MOV	R0, R1
- * would be converted to
- *	MOV	a, R1
- *	ADD	b, R1
- *	MOV	R1, R0
- * hopefully, then the former or latter MOV
- * will be eliminated by copy propagation.
- */
-int
-subprop(Reg *r0)
-{
-	Prog *p;
-	Addr *v1, *v2;
-	Reg *r;
-	int t;
-
-	p = r0->prog;
-	v1 = &p->from;
-	if(!regtyp(v1))
-		return 0;
-	v2 = &p->to;
-	if(!regtyp(v2))
-		return 0;
-	for(r=uniqp(r0); r!=R; r=uniqp(r)) {
-		if(uniqs(r) == R)
-			break;
-		p = r->prog;
-		switch(p->as) {
-		case ABL:
-			return 0;
-
-		case ACMP:
-		case ACMN:
-		case AADD:
-		case ASUB:
-		case ARSB:
-		case ASLL:
-		case ASRL:
-		case ASRA:
-		case AORR:
-		case AAND:
-		case AEOR:
-		case AMUL:
-		case ADIV:
-		case ADIVU:
-
-		case ACMPF:
-		case ACMPD:
-		case AADDD:
-		case AADDF:
-		case ASUBD:
-		case ASUBF:
-		case AMULD:
-		case AMULF:
-		case ADIVD:
-		case ADIVF:
-			if(p->to.type == v1->type)
-			if(p->to.reg == v1->reg) {
-				if(p->reg == NREG)
-					p->reg = p->to.reg;
-				goto gotit;
-			}
-			break;
-
-		case AMOVF:
-		case AMOVD:
-		case AMOVW:
-			if(p->to.type == v1->type)
-			if(p->to.reg == v1->reg)
-				goto gotit;
-			break;
-
-		case AMOVM:
-			t = 1<<v2->reg;
-			if((p->from.type == D_CONST && (p->from.offset&t)) ||
-			   (p->to.type == D_CONST && (p->to.offset&t)))
-				return 0;
-			break;
-		}
-		if(copyau(&p->from, v2) ||
-		   copyau1(p, v2) ||
-		   copyau(&p->to, v2))
-			break;
-		if(copysub(&p->from, v1, v2, 0) ||
-		   copysub1(p, v1, v2, 0) ||
-		   copysub(&p->to, v1, v2, 0))
-			break;
-	}
-	return 0;
-
-gotit:
-	copysub(&p->to, v1, v2, 1);
-	if(debug['P']) {
-		print("gotit: %D->%D\n%P", v1, v2, r->prog);
-		if(p->from.type == v2->type)
-			print(" excise");
-		print("\n");
-	}
-	for(r=uniqs(r); r!=r0; r=uniqs(r)) {
-		p = r->prog;
-		copysub(&p->from, v1, v2, 1);
-		copysub1(p, v1, v2, 1);
-		copysub(&p->to, v1, v2, 1);
-		if(debug['P'])
-			print("%P\n", r->prog);
-	}
-	t = v1->reg;
-	v1->reg = v2->reg;
-	v2->reg = t;
-	if(debug['P'])
-		print("%P last\n", r->prog);
-	return 1;
-}
-
-/*
- * The idea is to remove redundant copies.
- *	v1->v2	F=0
- *	(use v2	s/v2/v1/)*
- *	set v1	F=1
- *	use v2	return fail
- *	-----------------
- *	v1->v2	F=0
- *	(use v2	s/v2/v1/)*
- *	set v1	F=1
- *	set v2	return success
- */
-int
-copyprop(Reg *r0)
-{
-	Prog *p;
-	Addr *v1, *v2;
-	Reg *r;
-
-	p = r0->prog;
-	v1 = &p->from;
-	v2 = &p->to;
-	if(copyas(v1, v2))
-		return 1;
-	for(r=firstr; r!=R; r=r->link)
-		r->active = 0;
-	return copy1(v1, v2, r0->s1, 0);
-}
-
-int
-copy1(Addr *v1, Addr *v2, Reg *r, int f)
-{
-	int t;
-	Prog *p;
-
-	if(r->active) {
-		if(debug['P'])
-			print("act set; return 1\n");
-		return 1;
-	}
-	r->active = 1;
-	if(debug['P'])
-		print("copy %D->%D f=%d\n", v1, v2, f);
-	for(; r != R; r = r->s1) {
-		p = r->prog;
-		if(debug['P'])
-			print("%P", p);
-		if(!f && uniqp(r) == R) {
-			f = 1;
-			if(debug['P'])
-				print("; merge; f=%d", f);
-		}
-		t = copyu(p, v2, A);
-		switch(t) {
-		case 2:	/* rar, can't split */
-			if(debug['P'])
-				print("; %Drar; return 0\n", v2);
-			return 0;
-
-		case 3:	/* set */
-			if(debug['P'])
-				print("; %Dset; return 1\n", v2);
-			return 1;
-
-		case 1:	/* used, substitute */
-		case 4:	/* use and set */
-			if(f) {
-				if(!debug['P'])
-					return 0;
-				if(t == 4)
-					print("; %Dused+set and f=%d; return 0\n", v2, f);
-				else
-					print("; %Dused and f=%d; return 0\n", v2, f);
-				return 0;
-			}
-			if(copyu(p, v2, v1)) {
-				if(debug['P'])
-					print("; sub fail; return 0\n");
-				return 0;
-			}
-			if(debug['P'])
-				print("; sub%D/%D", v2, v1);
-			if(t == 4) {
-				if(debug['P'])
-					print("; %Dused+set; return 1\n", v2);
-				return 1;
-			}
-			break;
-		}
-		if(!f) {
-			t = copyu(p, v1, A);
-			if(!f && (t == 2 || t == 3 || t == 4)) {
-				f = 1;
-				if(debug['P'])
-					print("; %Dset and !f; f=%d", v1, f);
-			}
-		}
-		if(debug['P'])
-			print("\n");
-		if(r->s2)
-			if(!copy1(v1, v2, r->s2, f))
-				return 0;
-	}
-	return 1;
-}
-
-/*
- * The idea is to remove redundant constants.
- *	$c1->v1
- *	($c1->v2 s/$c1/v1)*
- *	set v1  return
- * The v1->v2 should be eliminated by copy propagation.
- */
-void
-constprop(Addr *c1, Addr *v1, Reg *r)
-{
-	Prog *p;
-
-	if(debug['C'])
-		print("constprop %D->%D\n", c1, v1);
-	for(; r != R; r = r->s1) {
-		p = r->prog;
-		if(debug['C'])
-			print("%P", p);
-		if(uniqp(r) == R) {
-			if(debug['C'])
-				print("; merge; return\n");
-			return;
-		}
-		if(p->as == AMOVW && copyas(&p->from, c1)) {
-				if(debug['C'])
-					print("; sub%D/%D", &p->from, v1);
-				p->from = *v1;
-		} else if(copyu(p, v1, A) > 1) {
-			if(debug['C'])
-				print("; %Dset; return\n", v1);
-			return;
-		}
-		if(debug['C'])
-			print("\n");
-		if(r->s2)
-			constprop(c1, v1, r->s2);
-	}
-}
-
-/*
- * ASLL x,y,w
- * .. (not use w, not set x y w)
- * AXXX w,a,b (a != w)
- * .. (not use w)
- * (set w)
- * ----------- changed to
- * ..
- * AXXX (x<<y),a,b
- * ..
- */
-#define FAIL(msg) { if(debug['H']) print("\t%s; FAILURE\n", msg); return 0; }
-int
-shiftprop(Reg *r)
-{
-	Reg *r1;
-	Prog *p, *p1, *p2;
-	int n, o;
-	Addr a;
-
-	p = r->prog;
-	if(p->to.type != D_REG)
-		FAIL("BOTCH: result not reg");
-	n = p->to.reg;
-	a = zprog.from;
-	if(p->reg != NREG && p->reg != p->to.reg) {
-		a.type = D_REG;
-		a.reg = p->reg;
-	}
-	if(debug['H'])
-		print("shiftprop\n%P", p);
-	r1 = r;
-	for(;;) {
-		/* find first use of shift result; abort if shift operands or result are changed */
-		r1 = uniqs(r1);
-		if(r1 == R)
-			FAIL("branch");
-		if(uniqp(r1) == R)
-			FAIL("merge");
-		p1 = r1->prog;
-		if(debug['H'])
-			print("\n%P", p1);
-		switch(copyu(p1, &p->to, A)) {
-		case 0:	/* not used or set */
-			if((p->from.type == D_REG && copyu(p1, &p->from, A) > 1) ||
-			   (a.type == D_REG && copyu(p1, &a, A) > 1))
-				FAIL("args modified");
-			continue;
-		case 3:	/* set, not used */
-			FAIL("BOTCH: noref");
-		}
-		break;
-	}
-	/* check whether substitution can be done */
-	switch(p1->as) {
-	default:
-		FAIL("non-dpi");
-	case AAND:
-	case AEOR:
-	case AADD:
-	case AADC:
-	case AORR:
-	case ASUB:
-	case ARSB:
-	case ASBC:
-	case ARSC:
-		if(p1->reg == n || (p1->reg == NREG && p1->to.type == D_REG && p1->to.reg == n)) {
-			if(p1->from.type != D_REG)
-				FAIL("can't swap");
-			p1->reg = p1->from.reg;
-			p1->from.reg = n;
-			switch(p1->as) {
-			case ASUB:
-				p1->as = ARSB;
-				break;
-			case ARSB:
-				p1->as = ASUB;
-				break;
-			case ASBC:
-				p1->as = ARSC;
-				break;
-			case ARSC:
-				p1->as = ASBC;
-				break;
-			}
-			if(debug['H'])
-				print("\t=>%P", p1);
-		}
-	case ABIC:
-	case ACMP:
-	case ACMN:
-		if(p1->reg == n)
-			FAIL("can't swap");
-		if(p1->reg == NREG && p1->to.reg == n)
-			FAIL("shift result used twice");
-	case AMVN:
-		if(p1->from.type == D_SHIFT)
-			FAIL("shift result used in shift");
-		if(p1->from.type != D_REG || p1->from.reg != n)
-			FAIL("BOTCH: where is it used?");
-		break;
-	}
-	/* check whether shift result is used subsequently */
-	p2 = p1;
-	if(p1->to.reg != n)
-	for (;;) {
-		r1 = uniqs(r1);
-		if(r1 == R)
-			FAIL("inconclusive");
-		p1 = r1->prog;
-		if(debug['H'])
-			print("\n%P", p1);
-		switch(copyu(p1, &p->to, A)) {
-		case 0:	/* not used or set */
-			continue;
-		case 3: /* set, not used */
-			break;
-		default:/* used */
-			FAIL("reused");
-		}
-		break;
-	}
-	/* make the substitution */
-	p2->from.type = D_SHIFT;
-	p2->from.reg = NREG;
-	o = p->reg;
-	if(o == NREG)
-		o = p->to.reg;
-	switch(p->from.type){
-	case D_CONST:
-		o |= (p->from.offset&0x1f)<<7;
-		break;
-	case D_REG:
-		o |= (1<<4) | (p->from.reg<<8);
-		break;
-	}
-	switch(p->as){
-	case ASLL:
-		o |= 0<<5;
-		break;
-	case ASRL:
-		o |= 1<<5;
-		break;
-	case ASRA:
-		o |= 2<<5;
-		break;
-	}
-	p2->from.offset = o;
-	if(debug['H'])
-		print("\t=>%P\tSUCCEED\n", p2);
-	return 1;
-}
-
-Reg*
-findpre(Reg *r, Addr *v)
-{
-	Reg *r1;
-
-	for(r1=uniqp(r); r1!=R; r=r1,r1=uniqp(r)) {
-		if(uniqs(r1) != r)
-			return R;
-		switch(copyu(r1->prog, v, A)) {
-		case 1: /* used */
-		case 2: /* read-alter-rewrite */
-			return R;
-		case 3: /* set */
-		case 4: /* set and used */
-			return r1;
-		}
-	}
-	return R;
-}
-
-Reg*
-findinc(Reg *r, Reg *r2, Addr *v)
-{
-	Reg *r1;
-	Prog *p;
-
-
-	for(r1=uniqs(r); r1!=R && r1!=r2; r=r1,r1=uniqs(r)) {
-		if(uniqp(r1) != r)
-			return R;
-		switch(copyu(r1->prog, v, A)) {
-		case 0: /* not touched */
-			continue;
-		case 4: /* set and used */
-			p = r1->prog;
-			if(p->as == AADD)
-			if(p->from.type == D_CONST)
-			if(p->from.offset > -4096 && p->from.offset < 4096)
-				return r1;
-		default:
-			return R;
-		}
-	}
-	return R;
-}
-
-int
-nochange(Reg *r, Reg *r2, Prog *p)
-{
-	Addr a[3];
-	int i, n;
-
-	if(r == r2)
-		return 1;
-	n = 0;
-	if(p->reg != NREG && p->reg != p->to.reg) {
-		a[n].type = D_REG;
-		a[n++].reg = p->reg;
-	}
-	switch(p->from.type) {
-	case D_SHIFT:
-		a[n].type = D_REG;
-		a[n++].reg = p->from.offset&0xf;
-	case D_REG:
-		a[n].type = D_REG;
-		a[n++].reg = p->from.reg;
-	}
-	if(n == 0)
-		return 1;
-	for(; r!=R && r!=r2; r=uniqs(r)) {
-		p = r->prog;
-		for(i=0; i<n; i++)
-			if(copyu(p, &a[i], A) > 1)
-				return 0;
-	}
-	return 1;
-}
-
-int
-findu1(Reg *r, Addr *v)
-{
-	for(; r != R; r = r->s1) {
-		if(r->active)
-			return 0;
-		r->active = 1;
-		switch(copyu(r->prog, v, A)) {
-		case 1: /* used */
-		case 2: /* read-alter-rewrite */
-		case 4: /* set and used */
-			return 1;
-		case 3: /* set */
-			return 0;
-		}
-		if(r->s2)
-			if (findu1(r->s2, v))
-				return 1;
-	}
-	return 0;
-}
-
-int
-finduse(Reg *r, Addr *v)
-{
-	Reg *r1;
-
-	for(r1=firstr; r1!=R; r1=r1->link)
-		r1->active = 0;
-	return findu1(r, v);
-}
-
-int
-xtramodes(Reg *r, Addr *a)
-{
-	Reg *r1, *r2, *r3;
-	Prog *p, *p1;
-	Addr v;
-
-	p = r->prog;
-	if((p->as == AMOVB || p->as == AMOVBS) && p->from.type == D_OREG)	/* byte load */
-		return 0;
-	v = *a;
-	v.type = D_REG;
-	r1 = findpre(r, &v);
-	if(r1 != R) {
-		p1 = r1->prog;
-		if(p1->to.type == D_REG && p1->to.reg == v.reg)
-		switch(p1->as) {
-		case AADD:
-			if(p1->from.type == D_REG ||
-			   (p1->from.type == D_SHIFT && (p1->from.offset&(1<<4)) == 0 &&
-			    ((p->as != AMOVB && p->as != AMOVBS) || (a == &p->from && (p1->from.offset&~0xf) == 0))) ||
-			   (p1->from.type == D_CONST &&
-			    p1->from.offset > -4096 && p1->from.offset < 4096))
-			if(nochange(uniqs(r1), r, p1)) {
-				if(a != &p->from || v.reg != p->to.reg)
-				if (finduse(r->s1, &v)) {
-					if(p1->reg == NREG || p1->reg == v.reg)
-						/* pre-indexing */
-						p->scond |= C_WBIT;
-					else return 0;
-				}
-				switch (p1->from.type) {
-				case D_REG:
-					/* register offset */
-					if(nacl)
-						return 0;
-					a->type = D_SHIFT;
-					a->offset = p1->from.reg;
-					break;
-				case D_SHIFT:
-					/* scaled register offset */
-					if(nacl)
-						return 0;
-					a->type = D_SHIFT;
-				case D_CONST:
-					/* immediate offset */
-					a->offset = p1->from.offset;
-					break;
-				}
-				if(p1->reg != NREG)
-					a->reg = p1->reg;
-				excise(r1);
-				return 1;
-			}
-			break;
-		case AMOVW:
-			if(p1->from.type == D_REG)
-			if((r2 = findinc(r1, r, &p1->from)) != R) {
-			for(r3=uniqs(r2); r3->prog->as==ANOP; r3=uniqs(r3))
-				;
-			if(r3 == r) {
-				/* post-indexing */
-				p1 = r2->prog;
-				a->reg = p1->to.reg;
-				a->offset = p1->from.offset;
-				p->scond |= C_PBIT;
-				if(!finduse(r, &r1->prog->to))
-					excise(r1);
-				excise(r2);
-				return 1;
-			}
-			}
-			break;
-		}
-	}
-	if(a != &p->from || a->reg != p->to.reg)
-	if((r1 = findinc(r, R, &v)) != R) {
-		/* post-indexing */
-		p1 = r1->prog;
-		a->offset = p1->from.offset;
-		p->scond |= C_PBIT;
-		excise(r1);
-		return 1;
-	}
-	return 0;
-}
-
-/*
- * return
- * 1 if v only used (and substitute),
- * 2 if read-alter-rewrite
- * 3 if set
- * 4 if set and used
- * 0 otherwise (not touched)
- */
-int
-copyu(Prog *p, Addr *v, Addr *s)
-{
-
-	switch(p->as) {
-
-	default:
-		if(debug['P'])
-			print(" (?)");
-		return 2;
-
-	case AMOVM:
-		if(v->type != D_REG)
-			return 0;
-		if(p->from.type == D_CONST) {	/* read reglist, read/rar */
-			if(s != A) {
-				if(p->from.offset&(1<<v->reg))
-					return 1;
-				if(copysub(&p->to, v, s, 1))
-					return 1;
-				return 0;
-			}
-			if(copyau(&p->to, v)) {
-				if(p->scond&C_WBIT)
-					return 2;
-				return 1;
-			}
-			if(p->from.offset&(1<<v->reg))
-				return 1;
-		} else {			/* read/rar, write reglist */
-			if(s != A) {
-				if(p->to.offset&(1<<v->reg))
-					return 1;
-				if(copysub(&p->from, v, s, 1))
-					return 1;
-				return 0;
-			}
-			if(copyau(&p->from, v)) {
-				if(p->scond&C_WBIT)
-					return 2;
-				if(p->to.offset&(1<<v->reg))
-					return 4;
-				return 1;
-			}
-			if(p->to.offset&(1<<v->reg))
-				return 3;
-		}
-		return 0;
-
-	case ANOP:	/* read, write */
-	case AMOVW:
-	case AMOVF:
-	case AMOVD:
-	case AMOVH:
-	case AMOVHS:
-	case AMOVHU:
-	case AMOVB:
-	case AMOVBS:
-	case AMOVBU:
-	case AMOVDW:
-	case AMOVWD:
-	case AMOVFD:
-	case AMOVDF:
-		if(p->scond&(C_WBIT|C_PBIT))
-		if(v->type == D_REG) {
-			if(p->from.type == D_OREG || p->from.type == D_SHIFT) {
-				if(p->from.reg == v->reg)
-					return 2;
-			} else {
-		  		if(p->to.reg == v->reg)
-				return 2;
-			}
-		}
-		if(s != A) {
-			if(copysub(&p->from, v, s, 1))
-				return 1;
-			if(!copyas(&p->to, v))
-				if(copysub(&p->to, v, s, 1))
-					return 1;
-			return 0;
-		}
-		if(copyas(&p->to, v)) {
-			if(copyau(&p->from, v))
-				return 4;
-			return 3;
-		}
-		if(copyau(&p->from, v))
-			return 1;
-		if(copyau(&p->to, v))
-			return 1;
-		return 0;
-
-
-	case AADD:	/* read, read, write */
-	case ASUB:
-	case ARSB:
-	case ASLL:
-	case ASRL:
-	case ASRA:
-	case AORR:
-	case AAND:
-	case AEOR:
-	case AMUL:
-	case ADIV:
-	case ADIVU:
-	case AADDF:
-	case AADDD:
-	case ASUBF:
-	case ASUBD:
-	case AMULF:
-	case AMULD:
-	case ADIVF:
-	case ADIVD:
-
-	case ACMPF:
-	case ACMPD:
-	case ACMP:
-	case ACMN:
-	case ACASE:
-		if(s != A) {
-			if(copysub(&p->from, v, s, 1))
-				return 1;
-			if(copysub1(p, v, s, 1))
-				return 1;
-			if(!copyas(&p->to, v))
-				if(copysub(&p->to, v, s, 1))
-					return 1;
-			return 0;
-		}
-		if(copyas(&p->to, v)) {
-			if(p->reg == NREG)
-				p->reg = p->to.reg;
-			if(copyau(&p->from, v))
-				return 4;
-			if(copyau1(p, v))
-				return 4;
-			return 3;
-		}
-		if(copyau(&p->from, v))
-			return 1;
-		if(copyau1(p, v))
-			return 1;
-		if(copyau(&p->to, v))
-			return 1;
-		return 0;
-
-	case ABEQ:	/* read, read */
-	case ABNE:
-	case ABCS:
-	case ABHS:
-	case ABCC:
-	case ABLO:
-	case ABMI:
-	case ABPL:
-	case ABVS:
-	case ABVC:
-	case ABHI:
-	case ABLS:
-	case ABGE:
-	case ABLT:
-	case ABGT:
-	case ABLE:
-	case APLD:
-		if(s != A) {
-			if(copysub(&p->from, v, s, 1))
-				return 1;
-			return copysub1(p, v, s, 1);
-		}
-		if(copyau(&p->from, v))
-			return 1;
-		if(copyau1(p, v))
-			return 1;
-		return 0;
-
-	case AB:	/* funny */
-		if(s != A) {
-			if(copysub(&p->to, v, s, 1))
-				return 1;
-			return 0;
-		}
-		if(copyau(&p->to, v))
-			return 1;
-		return 0;
-
-	case ARET:	/* funny */
-		if(v->type == D_REG)
-		if(v->reg == REGRET)
-			return 2;
-		if(v->type == D_FREG)
-		if(v->reg == FREGRET)
-			return 2;
-
-	case ABL:	/* funny */
-		if(v->type == D_REG) {
-			if(v->reg <= REGEXT && v->reg > exregoffset)
-				return 2;
-			if(v->reg == REGARG)
-				return 2;
-		}
-		if(v->type == D_FREG)
-			if(v->reg <= FREGEXT && v->reg > exfregoffset)
-				return 2;
-
-		if(s != A) {
-			if(copysub(&p->to, v, s, 1))
-				return 1;
-			return 0;
-		}
-		if(copyau(&p->to, v))
-			return 4;
-		return 3;
-
-	case ATEXT:	/* funny */
-		if(v->type == D_REG)
-			if(v->reg == REGARG)
-				return 3;
-		return 0;
-	}
-}
-
-int
-a2type(Prog *p)
-{
-
-	switch(p->as) {
-
-	case ACMP:
-	case ACMN:
-
-	case AADD:
-	case ASUB:
-	case ARSB:
-	case ASLL:
-	case ASRL:
-	case ASRA:
-	case AORR:
-	case AAND:
-	case AEOR:
-	case AMUL:
-	case ADIV:
-	case ADIVU:
-		return D_REG;
-
-	case ACMPF:
-	case ACMPD:
-
-	case AADDF:
-	case AADDD:
-	case ASUBF:
-	case ASUBD:
-	case AMULF:
-	case AMULD:
-	case ADIVF:
-	case ADIVD:
-		return D_FREG;
-	}
-	return D_NONE;
-}
-
-/*
- * direct reference,
- * could be set/use depending on
- * semantics
- */
-int
-copyas(Addr *a, Addr *v)
-{
-
-	if(regtyp(v)) {
-		if(a->type == v->type)
-		if(a->reg == v->reg)
-			return 1;
-	} else if(v->type == D_CONST) {		/* for constprop */
-		if(a->type == v->type)
-		if(a->name == v->name)
-		if(a->sym == v->sym)
-		if(a->reg == v->reg)
-		if(a->offset == v->offset)
-			return 1;
-	}
-	return 0;
-}
-
-/*
- * either direct or indirect
- */
-int
-copyau(Addr *a, Addr *v)
-{
-
-	if(copyas(a, v))
-		return 1;
-	if(v->type == D_REG) {
-		if(a->type == D_OREG) {
-			if(v->reg == a->reg)
-				return 1;
-		} else if(a->type == D_SHIFT) {
-			if((a->offset&0xf) == v->reg)
-				return 1;
-			if((a->offset&(1<<4)) && (a->offset>>8) == v->reg)
-				return 1;
-		}
-	}
-	return 0;
-}
-
-int
-copyau1(Prog *p, Addr *v)
-{
-
-	if(regtyp(v)) {
-		if(a2type(p) == v->type)
-		if(p->reg == v->reg) {
-			if(a2type(p) != v->type)
-				print("botch a2type %P\n", p);
-			return 1;
-		}
-	}
-	return 0;
-}
-
-/*
- * substitute s for v in a
- * return failure to substitute
- */
-int
-copysub(Addr *a, Addr *v, Addr *s, int f)
-{
-
-	if(f)
-	if(copyau(a, v)) {
-		if(a->type == D_SHIFT) {
-			if((a->offset&0xf) == v->reg)
-				a->offset = (a->offset&~0xf)|s->reg;
-			if((a->offset&(1<<4)) && (a->offset>>8) == v->reg)
-				a->offset = (a->offset&~(0xf<<8))|(s->reg<<8);
-		} else
-			a->reg = s->reg;
-	}
-	return 0;
-}
-
-int
-copysub1(Prog *p1, Addr *v, Addr *s, int f)
-{
-
-	if(f)
-	if(copyau1(p1, v))
-		p1->reg = s->reg;
-	return 0;
-}
-
-struct {
-	int opcode;
-	int notopcode;
-	int scond;
-	int notscond;
-} predinfo[]  = {
-	{ ABEQ,	ABNE,	0x0,	0x1, },
-	{ ABNE,	ABEQ,	0x1,	0x0, },
-	{ ABCS,	ABCC,	0x2,	0x3, },
-	{ ABHS,	ABLO,	0x2,	0x3, },
-	{ ABCC,	ABCS,	0x3,	0x2, },
-	{ ABLO,	ABHS,	0x3,	0x2, },
-	{ ABMI,	ABPL,	0x4,	0x5, },
-	{ ABPL,	ABMI,	0x5,	0x4, },
-	{ ABVS,	ABVC,	0x6,	0x7, },
-	{ ABVC,	ABVS,	0x7,	0x6, },
-	{ ABHI,	ABLS,	0x8,	0x9, },
-	{ ABLS,	ABHI,	0x9,	0x8, },
-	{ ABGE,	ABLT,	0xA,	0xB, },
-	{ ABLT,	ABGE,	0xB,	0xA, },
-	{ ABGT,	ABLE,	0xC,	0xD, },
-	{ ABLE,	ABGT,	0xD,	0xC, },
-};
-
-typedef struct {
-	Reg *start;
-	Reg *last;
-	Reg *end;
-	int len;
-} Joininfo;
-
-enum {
-	Join,
-	Split,
-	End,
-	Branch,
-	Setcond,
-	Toolong
-};
-
-enum {
-	Falsecond,
-	Truecond,
-	Delbranch,
-	Keepbranch
-};
-
-int
-isbranch(Prog *p)
-{
-	return (ABEQ <= p->as) && (p->as <= ABLE);
-}
-
-int
-predicable(Prog *p)
-{
-	if (isbranch(p)
-		|| p->as == ANOP
-		|| p->as == AXXX
-		|| p->as == ADATA
-		|| p->as == AGLOBL
-		|| p->as == AGOK
-		|| p->as == AHISTORY
-		|| p->as == ANAME
-		|| p->as == ASIGNAME
-		|| p->as == ATEXT
-		|| p->as == AWORD
-		|| p->as == ABCASE
-		|| p->as == ACASE)
-		return 0;
-	return 1;
-}
-
-/*
- * Depends on an analysis of the encodings performed by 5l.
- * These seem to be all of the opcodes that lead to the "S" bit
- * being set in the instruction encodings.
- *
- * C_SBIT may also have been set explicitly in p->scond.
- */
-int
-modifiescpsr(Prog *p)
-{
-	return (p->scond&C_SBIT)
-		|| p->as == ATST
-		|| p->as == ATEQ
-		|| p->as == ACMN
-		|| p->as == ACMP
-		|| p->as == AMULU
-		|| p->as == ADIVU
-		|| p->as == AMUL
-		|| p->as == ADIV
-		|| p->as == AMOD
-		|| p->as == AMODU
-		|| p->as == ABL;
-}
-
-/*
- * Find the maximal chain of instructions starting with r which could
- * be executed conditionally
- */
-int
-joinsplit(Reg *r, Joininfo *j)
-{
-	j->start = r;
-	j->last = r;
-	j->len = 0;
-	do {
-		if (r->p2 && (r->p1 || r->p2->p2link)) {
-			j->end = r;
-			return Join;
-		}
-		if (r->s1 && r->s2) {
-			j->end = r;
-			return Split;
-		}
-		j->last = r;
-		if (r->prog->as != ANOP)
-			j->len++;
-		if (!r->s1 && !r->s2) {
-			j->end = r->link;
-			return End;
-		}
-		if (r->s2) {
-			j->end = r->s2;
-			return Branch;
-		}
-		if (modifiescpsr(r->prog)) {
-			j->end = r->s1;
-			return Setcond;
-		}
-		r = r->s1;
-	} while (j->len < 4);
-	j->end = r;
-	return Toolong;
-}
-
-Reg *
-successor(Reg *r)
-{
-	if (r->s1)
-		return r->s1;
-	else
-		return r->s2;
-}
-
-void
-applypred(Reg *rstart, Joininfo *j, int cond, int branch)
-{
-	int pred;
-	Reg *r;
-
-	if(j->len == 0)
-		return;
-	if (cond == Truecond)
-		pred = predinfo[rstart->prog->as - ABEQ].scond;
-	else
-		pred = predinfo[rstart->prog->as - ABEQ].notscond;
-
-	for (r = j->start; ; r = successor(r)) {
-		if (r->prog->as == AB) {
-			if (r != j->last || branch == Delbranch)
-				excise(r);
-			else {
-			  if (cond == Truecond)
-				r->prog->as = predinfo[rstart->prog->as - ABEQ].opcode;
-			  else
-				r->prog->as = predinfo[rstart->prog->as - ABEQ].notopcode;
-			}
-		}
-		else if (predicable(r->prog))
-			r->prog->scond = (r->prog->scond&~C_SCOND)|pred;
-		if (r->s1 != r->link) {
-			r->s1 = r->link;
-			r->link->p1 = r;
-		}
-		if (r == j->last)
-			break;
-	}
-}
-
-void
-predicate(void)
-{
-	Reg *r;
-	int t1, t2;
-	Joininfo j1, j2;
-
-	for(r=firstr; r!=R; r=r->link) {
-		if (isbranch(r->prog)) {
-			t1 = joinsplit(r->s1, &j1);
-			t2 = joinsplit(r->s2, &j2);
-			if(j1.last->link != j2.start)
-				continue;
-			if(j1.end == j2.end)
-			if((t1 == Branch && (t2 == Join || t2 == Setcond)) ||
-			   (t2 == Join && (t1 == Join || t1 == Setcond))) {
-				applypred(r, &j1, Falsecond, Delbranch);
-				applypred(r, &j2, Truecond, Delbranch);
-				excise(r);
-				continue;
-			}
-			if(t1 == End || t1 == Branch) {
-				applypred(r, &j1, Falsecond, Keepbranch);
-				excise(r);
-				continue;
-			}
-		}
-	}
-}
diff --git a/src/cmd/5c/reg.c b/src/cmd/5c/reg.c
deleted file mode 100644
index 9024d5f..0000000
--- a/src/cmd/5c/reg.c
+++ /dev/null
@@ -1,1210 +0,0 @@
-// Inferno utils/5c/reg.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5c/reg.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-
-#include "gc.h"
-
-void	addsplits(void);
-
-Reg*
-rega(void)
-{
-	Reg *r;
-
-	r = freer;
-	if(r == R) {
-		r = alloc(sizeof(*r));
-	} else
-		freer = r->link;
-
-	*r = zreg;
-	return r;
-}
-
-int
-rcmp(const void *a1, const void *a2)
-{
-	Rgn *p1, *p2;
-	int c1, c2;
-
-	p1 = (Rgn*)a1;
-	p2 = (Rgn*)a2;
-	c1 = p2->cost;
-	c2 = p1->cost;
-	if(c1 -= c2)
-		return c1;
-	return p2->varno - p1->varno;
-}
-
-void
-regopt(Prog *p)
-{
-	Reg *r, *r1, *r2;
-	Prog *p1;
-	int i, z;
-	int32 initpc, val, npc;
-	uint32 vreg;
-	Bits bit;
-	struct
-	{
-		int32	m;
-		int32	c;
-		Reg*	p;
-	} log5[6], *lp;
-
-	firstr = R;
-	lastr = R;
-	nvar = 0;
-	regbits = 0;
-	for(z=0; z<BITS; z++) {
-		externs.b[z] = 0;
-		params.b[z] = 0;
-		consts.b[z] = 0;
-		addrs.b[z] = 0;
-	}
-
-	/*
-	 * pass 1
-	 * build aux data structure
-	 * allocate pcs
-	 * find use and set of variables
-	 */
-	val = 5L * 5L * 5L * 5L * 5L;
-	lp = log5;
-	for(i=0; i<5; i++) {
-		lp->m = val;
-		lp->c = 0;
-		lp->p = R;
-		val /= 5L;
-		lp++;
-	}
-	val = 0;
-	for(; p != P; p = p->link) {
-		switch(p->as) {
-		case ADATA:
-		case AGLOBL:
-		case ANAME:
-		case ASIGNAME:
-		case AFUNCDATA:
-			continue;
-		}
-		r = rega();
-		if(firstr == R) {
-			firstr = r;
-			lastr = r;
-		} else {
-			lastr->link = r;
-			r->p1 = lastr;
-			lastr->s1 = r;
-			lastr = r;
-		}
-		r->prog = p;
-		r->pc = val;
-		val++;
-
-		lp = log5;
-		for(i=0; i<5; i++) {
-			lp->c--;
-			if(lp->c <= 0) {
-				lp->c = lp->m;
-				if(lp->p != R)
-					lp->p->log5 = r;
-				lp->p = r;
-				(lp+1)->c = 0;
-				break;
-			}
-			lp++;
-		}
-
-		r1 = r->p1;
-		if(r1 != R)
-		switch(r1->prog->as) {
-		case ARET:
-		case AB:
-		case ARFE:
-			r->p1 = R;
-			r1->s1 = R;
-		}
-
-		/*
-		 * left side always read
-		 */
-		bit = mkvar(&p->from, p->as==AMOVW);
-		for(z=0; z<BITS; z++)
-			r->use1.b[z] |= bit.b[z];
-
-		/*
-		 * right side depends on opcode
-		 */
-		bit = mkvar(&p->to, 0);
-		if(bany(&bit))
-		switch(p->as) {
-		default:
-			diag(Z, "reg: unknown asop: %A", p->as);
-			break;
-
-		/*
-		 * right side write
-		 */
-		case ANOP:
-		case AMOVB:
-		case AMOVBS:
-		case AMOVBU:
-		case AMOVH:
-		case AMOVHS:
-		case AMOVHU:
-		case AMOVW:
-		case AMOVF:
-		case AMOVD:
-			for(z=0; z<BITS; z++)
-				r->set.b[z] |= bit.b[z];
-			break;
-
-		/*
-		 * right side read
-		 */
-		case APLD:
-			for(z=0; z<BITS; z++)
-				r->use2.b[z] |= bit.b[z];
-			break;
-
-		/*
-		 * funny
-		 */
-		case ABL:
-			for(z=0; z<BITS; z++)
-				addrs.b[z] |= bit.b[z];
-			break;
-		}
-
-		/* the mod/div runtime routines smash R12 */
-		switch(p->as) {
-		case AMOD:
-		case AMODU:
-		case ADIV:
-		case ADIVU:
-			regbits |= RtoB(12);
-			break;
-		}
-
-		if(p->as == AMOVM) {
-			if(p->from.type == D_CONST)
-				z = p->from.offset;
-			else
-				z = p->to.offset;
-			for(i=0; z; i++) {
-				if(z&1)
-					regbits |= RtoB(i);
-				z >>= 1;
-			}
-		}
-	}
-	if(firstr == R)
-		return;
-	initpc = pc - val;
-	npc = val;
-
-	/*
-	 * pass 2
-	 * turn branch references to pointers
-	 * build back pointers
-	 */
-	for(r = firstr; r != R; r = r->link) {
-		p = r->prog;
-		if(p->to.type == D_BRANCH) {
-			val = p->to.offset - initpc;
-			r1 = firstr;
-			while(r1 != R) {
-				r2 = r1->log5;
-				if(r2 != R && val >= r2->pc) {
-					r1 = r2;
-					continue;
-				}
-				if(r1->pc == val)
-					break;
-				r1 = r1->link;
-			}
-			if(r1 == R) {
-				nearln = p->lineno;
-				diag(Z, "ref not found\n%P", p);
-				continue;
-			}
-			if(r1 == r) {
-				nearln = p->lineno;
-				diag(Z, "ref to self\n%P", p);
-				continue;
-			}
-			r->s2 = r1;
-			r->p2link = r1->p2;
-			r1->p2 = r;
-		}
-	}
-	if(debug['R']) {
-		p = firstr->prog;
-		print("\n%L %D\n", p->lineno, &p->from);
-	}
-
-	/*
-	 * pass 2.5
-	 * find looping structure
-	 */
-	for(r = firstr; r != R; r = r->link)
-		r->active = 0;
-	change = 0;
-	loopit(firstr, npc);
-
-	/*
-	 * pass 3
-	 * iterate propagating usage
-	 * 	back until flow graph is complete
-	 */
-loop1:
-	change = 0;
-	for(r = firstr; r != R; r = r->link)
-		r->active = 0;
-	for(r = firstr; r != R; r = r->link)
-		if(r->prog->as == ARET)
-			prop(r, zbits, zbits);
-loop11:
-	/* pick up unreachable code */
-	i = 0;
-	for(r = firstr; r != R; r = r1) {
-		r1 = r->link;
-		if(r1 && r1->active && !r->active) {
-			prop(r, zbits, zbits);
-			i = 1;
-		}
-	}
-	if(i)
-		goto loop11;
-	if(change)
-		goto loop1;
-
-
-	/*
-	 * pass 4
-	 * iterate propagating register/variable synchrony
-	 * 	forward until graph is complete
-	 */
-loop2:
-	change = 0;
-	for(r = firstr; r != R; r = r->link)
-		r->active = 0;
-	synch(firstr, zbits);
-	if(change)
-		goto loop2;
-
-	addsplits();
-
-	if(debug['R'] && debug['v']) {
-		print("\nprop structure:\n");
-		for(r = firstr; r != R; r = r->link) {
-			print("%d:%P", r->loop, r->prog);
-			for(z=0; z<BITS; z++)
-				bit.b[z] = r->set.b[z] |
-					r->refahead.b[z] | r->calahead.b[z] |
-					r->refbehind.b[z] | r->calbehind.b[z] |
-					r->use1.b[z] | r->use2.b[z];
-			if(bany(&bit)) {
-				print("\t");
-				if(bany(&r->use1))
-					print(" u1=%B", r->use1);
-				if(bany(&r->use2))
-					print(" u2=%B", r->use2);
-				if(bany(&r->set))
-					print(" st=%B", r->set);
-				if(bany(&r->refahead))
-					print(" ra=%B", r->refahead);
-				if(bany(&r->calahead))
-					print(" ca=%B", r->calahead);
-				if(bany(&r->refbehind))
-					print(" rb=%B", r->refbehind);
-				if(bany(&r->calbehind))
-					print(" cb=%B", r->calbehind);
-			}
-			print("\n");
-		}
-	}
-
-	/*
-	 * pass 5
-	 * isolate regions
-	 * calculate costs (paint1)
-	 */
-	r = firstr;
-	if(r) {
-		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]);
-		if(bany(&bit)) {
-			nearln = r->prog->lineno;
-			warn(Z, "used and not set: %B", bit);
-			if(debug['R'] && !debug['w'])
-				print("used and not set: %B\n", bit);
-		}
-	}
-
-	for(r = firstr; r != R; r = r->link)
-		r->act = zbits;
-	rgp = region;
-	nregion = 0;
-	for(r = firstr; r != R; r = r->link) {
-		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)) {
-			nearln = r->prog->lineno;
-			warn(Z, "set and not used: %B", bit);
-			if(debug['R'])
-				print("set and not used: %B\n", bit);
-			excise(r);
-		}
-		for(z=0; z<BITS; z++)
-			bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]);
-		while(bany(&bit)) {
-			i = bnum(bit);
-			rgp->enter = r;
-			rgp->varno = i;
-			change = 0;
-			if(debug['R'] && debug['v'])
-				print("\n");
-			paint1(r, i);
-			bit.b[i/32] &= ~(1L<<(i%32));
-			if(change <= 0) {
-				if(debug['R'])
-					print("%L $%d: %B\n",
-						r->prog->lineno, change, blsh(i));
-				continue;
-			}
-			rgp->cost = change;
-			nregion++;
-			if(nregion >= NRGN) {
-				fatal(Z, "too many regions");
-				goto brk;
-			}
-			rgp++;
-		}
-	}
-brk:
-	qsort(region, nregion, sizeof(region[0]), rcmp);
-
-	/*
-	 * pass 6
-	 * determine used registers (paint2)
-	 * replace code (paint3)
-	 */
-	rgp = region;
-	for(i=0; i<nregion; i++) {
-		bit = blsh(rgp->varno);
-		vreg = paint2(rgp->enter, rgp->varno);
-		vreg = allreg(vreg, rgp);
-		if(debug['R']) {
-			if(rgp->regno >= NREG)
-				print("%L $%d F%d: %B\n",
-					rgp->enter->prog->lineno,
-					rgp->cost,
-					rgp->regno-NREG,
-					bit);
-			else
-				print("%L $%d R%d: %B\n",
-					rgp->enter->prog->lineno,
-					rgp->cost,
-					rgp->regno,
-					bit);
-		}
-		if(rgp->regno != 0)
-			paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
-		rgp++;
-	}
-	/*
-	 * pass 7
-	 * peep-hole on basic block
-	 */
-	if(!debug['R'] || debug['P'])
-		peep();
-
-	/*
-	 * pass 8
-	 * recalculate pc
-	 */
-	val = initpc;
-	for(r = firstr; r != R; r = r1) {
-		r->pc = val;
-		p = r->prog;
-		p1 = P;
-		r1 = r->link;
-		if(r1 != R)
-			p1 = r1->prog;
-		for(; p != p1; p = p->link) {
-			switch(p->as) {
-			default:
-				val++;
-				break;
-
-			case ANOP:
-			case ADATA:
-			case AGLOBL:
-			case ANAME:
-			case ASIGNAME:
-			case AFUNCDATA:
-				break;
-			}
-		}
-	}
-	pc = val;
-
-	/*
-	 * fix up branches
-	 */
-	if(debug['R'])
-		if(bany(&addrs))
-			print("addrs: %B\n", addrs);
-
-	r1 = 0; /* set */
-	for(r = firstr; r != R; r = r->link) {
-		p = r->prog;
-		if(p->to.type == D_BRANCH) {
-			p->to.offset = r->s2->pc;
-			p->to.u.branch = r->s2->prog;
-		}
-		r1 = r;
-	}
-
-	/*
-	 * last pass
-	 * eliminate nops
-	 * free aux structures
-	 */
-	for(p = firstr->prog; p != P; p = p->link){
-		while(p->link && p->link->as == ANOP)
-			p->link = p->link->link;
-	}
-	if(r1 != R) {
-		r1->link = freer;
-		freer = firstr;
-	}
-}
-
-void
-addsplits(void)
-{
-	Reg *r, *r1;
-	int z, i;
-	Bits bit;
-
-	for(r = firstr; r != R; r = r->link) {
-		if(r->loop > 1)
-			continue;
-		if(r->prog->as == ABL)
-			continue;
-		for(r1 = r->p2; r1 != R; r1 = r1->p2link) {
-			if(r1->loop <= 1)
-				continue;
-			for(z=0; z<BITS; z++)
-				bit.b[z] = r1->calbehind.b[z] &
-					(r->refahead.b[z] | r->use1.b[z] | r->use2.b[z]) &
-					~(r->calahead.b[z] & addrs.b[z]);
-			while(bany(&bit)) {
-				i = bnum(bit);
-				bit.b[i/32] &= ~(1L << (i%32));
-			}
-		}
-	}
-}
-
-/*
- * add mov b,rn
- * just after r
- */
-void
-addmove(Reg *r, int bn, int rn, int f)
-{
-	Prog *p, *p1;
-	Addr *a;
-	Var *v;
-
-	p1 = alloc(sizeof(*p1));
-	*p1 = zprog;
-	p = r->prog;
-
-	p1->link = p->link;
-	p->link = p1;
-	p1->lineno = p->lineno;
-
-	v = var + bn;
-
-	a = &p1->to;
-	a->sym = v->sym;
-	a->name = v->name;
-	a->offset = v->offset;
-	a->etype = v->etype;
-	a->type = D_OREG;
-	if(a->etype == TARRAY || a->sym == nil)
-		a->type = D_CONST;
-
-	p1->as = AMOVW;
-	if(v->etype == TCHAR || v->etype == TUCHAR)
-		p1->as = AMOVBS;
-	if(v->etype == TSHORT || v->etype == TUSHORT)
-		p1->as = AMOVHS;
-	if(v->etype == TFLOAT)
-		p1->as = AMOVF;
-	if(v->etype == TDOUBLE)
-		p1->as = AMOVD;
-
-	p1->from.type = D_REG;
-	p1->from.reg = rn;
-	if(rn >= NREG) {
-		p1->from.type = D_FREG;
-		p1->from.reg = rn-NREG;
-	}
-	if(!f) {
-		p1->from = *a;
-		*a = zprog.from;
-		a->type = D_REG;
-		a->reg = rn;
-		if(rn >= NREG) {
-			a->type = D_FREG;
-			a->reg = rn-NREG;
-		}
-		if(v->etype == TUCHAR)
-			p1->as = AMOVBU;
-		if(v->etype == TUSHORT)
-			p1->as = AMOVHU;
-	}
-	if(debug['R'])
-		print("%P\t.a%P\n", p, p1);
-}
-
-Bits
-mkvar(Addr *a, int docon)
-{
-	Var *v;
-	int i, t, n, et, z;
-	int32 o;
-	Bits bit;
-	LSym *s;
-
-	t = a->type;
-	if(t == D_REG && a->reg != NREG)
-		regbits |= RtoB(a->reg);
-	if(t == D_FREG && a->reg != NREG)
-		regbits |= FtoB(a->reg);
-	s = a->sym;
-	o = a->offset;
-	et = a->etype;
-	if(s == nil) {
-		if(t != D_CONST || !docon || a->reg != NREG)
-			goto none;
-		et = TLONG;
-	}
-	if(t == D_CONST) {
-		if(s == nil && sval(o))
-			goto none;
-	}
-
-	n = a->name;
-	v = var;
-	for(i=0; i<nvar; i++) {
-		if(s == v->sym)
-		if(n == v->name)
-		if(o == v->offset)
-			goto out;
-		v++;
-	}
-	if(s)
-		if(s->name[0] == '.')
-			goto none;
-	if(nvar >= NVAR)
-		fatal(Z, "variable not optimized: %s", s->name);
-	i = nvar;
-	nvar++;
-	v = &var[i];
-	v->sym = s;
-	v->offset = o;
-	v->etype = et;
-	v->name = n;
-	if(debug['R'])
-		print("bit=%2d et=%2d %D\n", i, et, a);
-out:
-	bit = blsh(i);
-	if(n == D_EXTERN || n == D_STATIC)
-		for(z=0; z<BITS; z++)
-			externs.b[z] |= bit.b[z];
-	if(n == D_PARAM)
-		for(z=0; z<BITS; z++)
-			params.b[z] |= bit.b[z];
-	if(v->etype != et || !typechlpfd[et])	/* funny punning */
-		for(z=0; z<BITS; z++)
-			addrs.b[z] |= bit.b[z];
-	if(t == D_CONST) {
-		if(s == nil) {
-			for(z=0; z<BITS; z++)
-				consts.b[z] |= bit.b[z];
-			return bit;
-		}
-		if(et != TARRAY)
-			for(z=0; z<BITS; z++)
-				addrs.b[z] |= bit.b[z];
-		for(z=0; z<BITS; z++)
-			params.b[z] |= bit.b[z];
-		return bit;
-	}
-	if(t == D_OREG)
-		return bit;
-
-none:
-	return zbits;
-}
-
-void
-prop(Reg *r, Bits ref, Bits cal)
-{
-	Reg *r1, *r2;
-	int z;
-
-	for(r1 = r; r1 != R; r1 = r1->p1) {
-		for(z=0; z<BITS; z++) {
-			ref.b[z] |= r1->refahead.b[z];
-			if(ref.b[z] != r1->refahead.b[z]) {
-				r1->refahead.b[z] = ref.b[z];
-				change++;
-			}
-			cal.b[z] |= r1->calahead.b[z];
-			if(cal.b[z] != r1->calahead.b[z]) {
-				r1->calahead.b[z] = cal.b[z];
-				change++;
-			}
-		}
-		switch(r1->prog->as) {
-		case ABL:
-			for(z=0; z<BITS; z++) {
-				cal.b[z] |= ref.b[z] | externs.b[z];
-				ref.b[z] = 0;
-			}
-			break;
-
-		case ATEXT:
-			for(z=0; z<BITS; z++) {
-				cal.b[z] = 0;
-				ref.b[z] = 0;
-			}
-			break;
-
-		case ARET:
-			for(z=0; z<BITS; z++) {
-				cal.b[z] = externs.b[z];
-				ref.b[z] = 0;
-			}
-		}
-		for(z=0; z<BITS; z++) {
-			ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
-				r1->use1.b[z] | r1->use2.b[z];
-			cal.b[z] &= ~(r1->set.b[z] | r1->use1.b[z] | r1->use2.b[z]);
-			r1->refbehind.b[z] = ref.b[z];
-			r1->calbehind.b[z] = cal.b[z];
-		}
-		if(r1->active)
-			break;
-		r1->active = 1;
-	}
-	for(; r != r1; r = r->p1)
-		for(r2 = r->p2; r2 != R; r2 = r2->p2link)
-			prop(r2, r->refbehind, r->calbehind);
-}
-
-/*
- * find looping structure
- *
- * 1) find reverse postordering
- * 2) find approximate dominators,
- *	the actual dominators if the flow graph is reducible
- *	otherwise, dominators plus some other non-dominators.
- *	See Matthew S. Hecht and Jeffrey D. Ullman,
- *	"Analysis of a Simple Algorithm for Global Data Flow Problems",
- *	Conf.  Record of ACM Symp. on Principles of Prog. Langs, Boston, Massachusetts,
- *	Oct. 1-3, 1973, pp.  207-217.
- * 3) find all nodes with a predecessor dominated by the current node.
- *	such a node is a loop head.
- *	recursively, all preds with a greater rpo number are in the loop
- */
-int32
-postorder(Reg *r, Reg **rpo2r, int32 n)
-{
-	Reg *r1;
-
-	r->rpo = 1;
-	r1 = r->s1;
-	if(r1 && !r1->rpo)
-		n = postorder(r1, rpo2r, n);
-	r1 = r->s2;
-	if(r1 && !r1->rpo)
-		n = postorder(r1, rpo2r, n);
-	rpo2r[n] = r;
-	n++;
-	return n;
-}
-
-int32
-rpolca(int32 *idom, int32 rpo1, int32 rpo2)
-{
-	int32 t;
-
-	if(rpo1 == -1)
-		return rpo2;
-	while(rpo1 != rpo2){
-		if(rpo1 > rpo2){
-			t = rpo2;
-			rpo2 = rpo1;
-			rpo1 = t;
-		}
-		while(rpo1 < rpo2){
-			t = idom[rpo2];
-			if(t >= rpo2)
-				fatal(Z, "bad idom");
-			rpo2 = t;
-		}
-	}
-	return rpo1;
-}
-
-int
-doms(int32 *idom, int32 r, int32 s)
-{
-	while(s > r)
-		s = idom[s];
-	return s == r;
-}
-
-int
-loophead(int32 *idom, Reg *r)
-{
-	int32 src;
-
-	src = r->rpo;
-	if(r->p1 != R && doms(idom, src, r->p1->rpo))
-		return 1;
-	for(r = r->p2; r != R; r = r->p2link)
-		if(doms(idom, src, r->rpo))
-			return 1;
-	return 0;
-}
-
-void
-loopmark(Reg **rpo2r, int32 head, Reg *r)
-{
-	if(r->rpo < head || r->active == head)
-		return;
-	r->active = head;
-	r->loop += LOOP;
-	if(r->p1 != R)
-		loopmark(rpo2r, head, r->p1);
-	for(r = r->p2; r != R; r = r->p2link)
-		loopmark(rpo2r, head, r);
-}
-
-void
-loopit(Reg *r, int32 nr)
-{
-	Reg *r1;
-	int32 i, d, me;
-
-	if(nr > maxnr) {
-		rpo2r = alloc(nr * sizeof(Reg*));
-		idom = alloc(nr * sizeof(int32));
-		maxnr = nr;
-	}
-	d = postorder(r, rpo2r, 0);
-	if(d > nr)
-		fatal(Z, "too many reg nodes");
-	nr = d;
-	for(i = 0; i < nr / 2; i++){
-		r1 = rpo2r[i];
-		rpo2r[i] = rpo2r[nr - 1 - i];
-		rpo2r[nr - 1 - i] = r1;
-	}
-	for(i = 0; i < nr; i++)
-		rpo2r[i]->rpo = i;
-
-	idom[0] = 0;
-	for(i = 0; i < nr; i++){
-		r1 = rpo2r[i];
-		me = r1->rpo;
-		d = -1;
-		if(r1->p1 != R && r1->p1->rpo < me)
-			d = r1->p1->rpo;
-		for(r1 = r1->p2; r1 != nil; r1 = r1->p2link)
-			if(r1->rpo < me)
-				d = rpolca(idom, d, r1->rpo);
-		idom[i] = d;
-	}
-
-	for(i = 0; i < nr; i++){
-		r1 = rpo2r[i];
-		r1->loop++;
-		if(r1->p2 != R && loophead(idom, r1))
-			loopmark(rpo2r, i, r1);
-	}
-}
-
-void
-synch(Reg *r, Bits dif)
-{
-	Reg *r1;
-	int z;
-
-	for(r1 = r; r1 != R; r1 = r1->s1) {
-		for(z=0; z<BITS; z++) {
-			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++;
-			}
-		}
-		if(r1->active)
-			break;
-		r1->active = 1;
-		for(z=0; z<BITS; z++)
-			dif.b[z] &= ~(~r1->calbehind.b[z] & r1->calahead.b[z]);
-		if(r1->s2 != R)
-			synch(r1->s2, dif);
-	}
-}
-
-uint32
-allreg(uint32 b, Rgn *r)
-{
-	Var *v;
-	int i;
-
-	v = var + r->varno;
-	r->regno = 0;
-	switch(v->etype) {
-
-	default:
-		diag(Z, "unknown etype %d/%d", bitno(b), v->etype);
-		break;
-
-	case TCHAR:
-	case TUCHAR:
-	case TSHORT:
-	case TUSHORT:
-	case TINT:
-	case TUINT:
-	case TLONG:
-	case TULONG:
-	case TIND:
-	case TARRAY:
-		i = BtoR(~b);
-		if(i && r->cost >= 0) {
-			r->regno = i;
-			return RtoB(i);
-		}
-		break;
-
-	case TVLONG:
-	case TDOUBLE:
-	case TFLOAT:
-		i = BtoF(~b);
-		if(i && r->cost >= 0) {
-			r->regno = i+NREG;
-			return FtoB(i);
-		}
-		break;
-	}
-	return 0;
-}
-
-void
-paint1(Reg *r, int bn)
-{
-	Reg *r1;
-	Prog *p;
-	int z;
-	uint32 bb;
-
-	z = bn/32;
-	bb = 1L<<(bn%32);
-	if(r->act.b[z] & bb)
-		return;
-	for(;;) {
-		if(!(r->refbehind.b[z] & bb))
-			break;
-		r1 = r->p1;
-		if(r1 == R)
-			break;
-		if(!(r1->refahead.b[z] & bb))
-			break;
-		if(r1->act.b[z] & bb)
-			break;
-		r = r1;
-	}
-
-	if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb) {
-		change -= CLOAD * r->loop;
-		if(debug['R'] && debug['v'])
-			print("%d%P\td %B $%d\n", r->loop,
-				r->prog, blsh(bn), change);
-	}
-	for(;;) {
-		r->act.b[z] |= bb;
-		p = r->prog;
-
-		if(r->use1.b[z] & bb) {
-			change += CREF * r->loop;
-			if(debug['R'] && debug['v'])
-				print("%d%P\tu1 %B $%d\n", r->loop,
-					p, blsh(bn), change);
-		}
-
-		if((r->use2.b[z]|r->set.b[z]) & bb) {
-			change += CREF * r->loop;
-			if(debug['R'] && debug['v'])
-				print("%d%P\tu2 %B $%d\n", r->loop,
-					p, blsh(bn), change);
-		}
-
-		if(STORE(r) & r->regdiff.b[z] & bb) {
-			change -= CLOAD * r->loop;
-			if(debug['R'] && debug['v'])
-				print("%d%P\tst %B $%d\n", r->loop,
-					p, blsh(bn), change);
-		}
-
-		if(r->refbehind.b[z] & bb)
-			for(r1 = r->p2; r1 != R; r1 = r1->p2link)
-				if(r1->refahead.b[z] & bb)
-					paint1(r1, bn);
-
-		if(!(r->refahead.b[z] & bb))
-			break;
-		r1 = r->s2;
-		if(r1 != R)
-			if(r1->refbehind.b[z] & bb)
-				paint1(r1, bn);
-		r = r->s1;
-		if(r == R)
-			break;
-		if(r->act.b[z] & bb)
-			break;
-		if(!(r->refbehind.b[z] & bb))
-			break;
-	}
-}
-
-uint32
-paint2(Reg *r, int bn)
-{
-	Reg *r1;
-	int z;
-	uint32 bb, vreg;
-
-	z = bn/32;
-	bb = 1L << (bn%32);
-	vreg = regbits;
-	if(!(r->act.b[z] & bb))
-		return vreg;
-	for(;;) {
-		if(!(r->refbehind.b[z] & bb))
-			break;
-		r1 = r->p1;
-		if(r1 == R)
-			break;
-		if(!(r1->refahead.b[z] & bb))
-			break;
-		if(!(r1->act.b[z] & bb))
-			break;
-		r = r1;
-	}
-	for(;;) {
-		r->act.b[z] &= ~bb;
-
-		vreg |= r->regu;
-
-		if(r->refbehind.b[z] & bb)
-			for(r1 = r->p2; r1 != R; r1 = r1->p2link)
-				if(r1->refahead.b[z] & bb)
-					vreg |= paint2(r1, bn);
-
-		if(!(r->refahead.b[z] & bb))
-			break;
-		r1 = r->s2;
-		if(r1 != R)
-			if(r1->refbehind.b[z] & bb)
-				vreg |= paint2(r1, bn);
-		r = r->s1;
-		if(r == R)
-			break;
-		if(!(r->act.b[z] & bb))
-			break;
-		if(!(r->refbehind.b[z] & bb))
-			break;
-	}
-	return vreg;
-}
-
-void
-paint3(Reg *r, int bn, int32 rb, int rn)
-{
-	Reg *r1;
-	Prog *p;
-	int z;
-	uint32 bb;
-
-	z = bn/32;
-	bb = 1L << (bn%32);
-	if(r->act.b[z] & bb)
-		return;
-	for(;;) {
-		if(!(r->refbehind.b[z] & bb))
-			break;
-		r1 = r->p1;
-		if(r1 == R)
-			break;
-		if(!(r1->refahead.b[z] & bb))
-			break;
-		if(r1->act.b[z] & bb)
-			break;
-		r = r1;
-	}
-
-	if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb)
-		addmove(r, bn, rn, 0);
-	for(;;) {
-		r->act.b[z] |= bb;
-		p = r->prog;
-
-		if(r->use1.b[z] & bb) {
-			if(debug['R'])
-				print("%P", p);
-			addreg(&p->from, rn);
-			if(debug['R'])
-				print("\t.c%P\n", p);
-		}
-		if((r->use2.b[z]|r->set.b[z]) & bb) {
-			if(debug['R'])
-				print("%P", p);
-			addreg(&p->to, rn);
-			if(debug['R'])
-				print("\t.c%P\n", p);
-		}
-
-		if(STORE(r) & r->regdiff.b[z] & bb)
-			addmove(r, bn, rn, 1);
-		r->regu |= rb;
-
-		if(r->refbehind.b[z] & bb)
-			for(r1 = r->p2; r1 != R; r1 = r1->p2link)
-				if(r1->refahead.b[z] & bb)
-					paint3(r1, bn, rb, rn);
-
-		if(!(r->refahead.b[z] & bb))
-			break;
-		r1 = r->s2;
-		if(r1 != R)
-			if(r1->refbehind.b[z] & bb)
-				paint3(r1, bn, rb, rn);
-		r = r->s1;
-		if(r == R)
-			break;
-		if(r->act.b[z] & bb)
-			break;
-		if(!(r->refbehind.b[z] & bb))
-			break;
-	}
-}
-
-void
-addreg(Addr *a, int rn)
-{
-
-	a->sym = 0;
-	a->name = D_NONE;
-	a->type = D_REG;
-	a->reg = rn;
-	if(rn >= NREG) {
-		a->type = D_FREG;
-		a->reg = rn-NREG;
-	}
-}
-
-/*
- *	bit	reg
- *	0	R0
- *	1	R1
- *	...	...
- *	10	R10
- *	12  R12
- */
-int32
-RtoB(int r)
-{
-
-	if(r < 2 || (r >= REGTMP-2 && r != 12))	// excluded R9 and R10 for m and g, but not R12
-		return 0;
-	return 1L << r;
-}
-
-int
-BtoR(int32 b)
-{
-	b &= 0x11fcL;	// excluded R9 and R10 for m and g, but not R12
-	if(b == 0)
-		return 0;
-	return bitno(b);
-}
-
-/*
- *	bit	reg
- *	18	F2
- *	19	F3
- *	...	...
- *	31	F15
- */
-int32
-FtoB(int f)
-{
-
-	if(f < 2 || f > NFREG-1)
-		return 0;
-	return 1L << (f + 16);
-}
-
-int
-BtoF(int32 b)
-{
-
-	b &= 0xfffc0000L;
-	if(b == 0)
-		return 0;
-	return bitno(b) - 16;
-}
diff --git a/src/cmd/5c/sgen.c b/src/cmd/5c/sgen.c
deleted file mode 100644
index a36612c..0000000
--- a/src/cmd/5c/sgen.c
+++ /dev/null
@@ -1,265 +0,0 @@
-// Inferno utils/5c/sgen.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5c/sgen.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-
-#include "gc.h"
-
-Prog*
-gtext(Sym *s, int32 stkoff)
-{
-	int32 a;
-
-	a = argsize(1);
-	if((textflag & NOSPLIT) != 0 && stkoff >= 128)
-		yyerror("stack frame too large for NOSPLIT function");
-
-	gpseudo(ATEXT, s, nodconst(stkoff));
-	p->to.type = D_CONST2;
-	p->to.offset2 = a;
-	return p;
-}
-
-void
-noretval(int n)
-{
-
-	if(n & 1) {
-		gins(ANOP, Z, Z);
-		p->to.type = D_REG;
-		p->to.reg = REGRET;
-	}
-	if(n & 2) {
-		gins(ANOP, Z, Z);
-		p->to.type = D_FREG;
-		p->to.reg = FREGRET;
-	}
-}
-
-/*
- *	calculate addressability as follows
- *		CONST ==> 20		$value
- *		NAME ==> 10		name
- *		REGISTER ==> 11		register
- *		INDREG ==> 12		*[(reg)+offset]
- *		&10 ==> 2		$name
- *		ADD(2, 20) ==> 2	$name+offset
- *		ADD(3, 20) ==> 3	$(reg)+offset
- *		&12 ==> 3		$(reg)+offset
- *		*11 ==> 11		??
- *		*2 ==> 10		name
- *		*3 ==> 12		*(reg)+offset
- *	calculate complexity (number of registers)
- */
-void
-xcom(Node *n)
-{
-	Node *l, *r;
-	int t;
-
-	if(n == Z)
-		return;
-	l = n->left;
-	r = n->right;
-	n->addable = 0;
-	n->complex = 0;
-	switch(n->op) {
-	case OCONST:
-		n->addable = 20;
-		return;
-
-	case OREGISTER:
-		n->addable = 11;
-		return;
-
-	case OINDREG:
-		n->addable = 12;
-		return;
-
-	case ONAME:
-		n->addable = 10;
-		return;
-
-	case OADDR:
-		xcom(l);
-		if(l->addable == 10)
-			n->addable = 2;
-		if(l->addable == 12)
-			n->addable = 3;
-		break;
-
-	case OIND:
-		xcom(l);
-		if(l->addable == 11)
-			n->addable = 12;
-		if(l->addable == 3)
-			n->addable = 12;
-		if(l->addable == 2)
-			n->addable = 10;
-		break;
-
-	case OADD:
-		xcom(l);
-		xcom(r);
-		if(l->addable == 20) {
-			if(r->addable == 2)
-				n->addable = 2;
-			if(r->addable == 3)
-				n->addable = 3;
-		}
-		if(r->addable == 20) {
-			if(l->addable == 2)
-				n->addable = 2;
-			if(l->addable == 3)
-				n->addable = 3;
-		}
-		break;
-
-	case OASLMUL:
-	case OASMUL:
-		xcom(l);
-		xcom(r);
-		t = vlog(r);
-		if(t >= 0) {
-			n->op = OASASHL;
-			r->vconst = t;
-			r->type = types[TINT];
-		}
-		break;
-
-	case OMUL:
-	case OLMUL:
-		xcom(l);
-		xcom(r);
-		t = vlog(r);
-		if(t >= 0) {
-			n->op = OASHL;
-			r->vconst = t;
-			r->type = types[TINT];
-		}
-		t = vlog(l);
-		if(t >= 0) {
-			n->op = OASHL;
-			n->left = r;
-			n->right = l;
-			r = l;
-			l = n->left;
-			r->vconst = t;
-			r->type = types[TINT];
-		}
-		break;
-
-	case OASLDIV:
-		xcom(l);
-		xcom(r);
-		t = vlog(r);
-		if(t >= 0) {
-			n->op = OASLSHR;
-			r->vconst = t;
-			r->type = types[TINT];
-		}
-		break;
-
-	case OLDIV:
-		xcom(l);
-		xcom(r);
-		t = vlog(r);
-		if(t >= 0) {
-			n->op = OLSHR;
-			r->vconst = t;
-			r->type = types[TINT];
-		}
-		break;
-
-	case OASLMOD:
-		xcom(l);
-		xcom(r);
-		t = vlog(r);
-		if(t >= 0) {
-			n->op = OASAND;
-			r->vconst--;
-		}
-		break;
-
-	case OLMOD:
-		xcom(l);
-		xcom(r);
-		t = vlog(r);
-		if(t >= 0) {
-			n->op = OAND;
-			r->vconst--;
-		}
-		break;
-
-	default:
-		if(l != Z)
-			xcom(l);
-		if(r != Z)
-			xcom(r);
-		break;
-	}
-	if(n->addable >= 10)
-		return;
-
-	if(l != Z)
-		n->complex = l->complex;
-	if(r != Z) {
-		if(r->complex == n->complex)
-			n->complex = r->complex+1;
-		else
-		if(r->complex > n->complex)
-			n->complex = r->complex;
-	}
-	if(n->complex == 0)
-		n->complex++;
-
-	if(com64(n))
-		return;
-
-	switch(n->op) {
-	case OFUNC:
-		n->complex = FNX;
-		break;
-
-	case OADD:
-	case OXOR:
-	case OAND:
-	case OOR:
-	case OEQ:
-	case ONE:
-		/*
-		 * immediate operators, make const on right
-		 */
-		if(l->op == OCONST) {
-			n->left = r;
-			n->right = l;
-		}
-		break;
-	}
-}
diff --git a/src/cmd/5c/swt.c b/src/cmd/5c/swt.c
deleted file mode 100644
index f39963b..0000000
--- a/src/cmd/5c/swt.c
+++ /dev/null
@@ -1,461 +0,0 @@
-// Inferno utils/5c/swt.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5c/swt.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include "gc.h"
-
-void
-swit1(C1 *q, int nc, int32 def, Node *n)
-{
-	Node nreg;
-
-	if(typev[n->type->etype]) {
-		regsalloc(&nreg, n);
-		nreg.type = types[TVLONG];
-		cgen(n, &nreg);
-		swit2(q, nc, def, &nreg);
-		return;
-	}
-
-	regalloc(&nreg, n, Z);
-	nreg.type = types[TLONG];
-	cgen(n, &nreg);
-	swit2(q, nc, def, &nreg);
-	regfree(&nreg);
-}
-
-void
-swit2(C1 *q, int nc, int32 def, Node *n)
-{
-	C1 *r;
-	int i;
-	int32 v;
-	Prog *sp;
-
-	if(nc >= 3) {
-		i = (q+nc-1)->val - (q+0)->val;
-		if(!nacl && i > 0 && i < nc*2)
-			goto direct;
-	}
-	if(nc < 5) {
-		for(i=0; i<nc; i++) {
-			if(debug['W'])
-				print("case = %.8ux\n", q->val);
-			gopcode(OEQ, nodconst(q->val), n, Z);
-			patch(p, q->label);
-			q++;
-		}
-		gbranch(OGOTO);
-		patch(p, def);
-		return;
-	}
-
-	i = nc / 2;
-	r = q+i;
-	if(debug['W'])
-		print("case > %.8ux\n", r->val);
-	gopcode(OGT, nodconst(r->val), n, Z);
-	sp = p;
-	gopcode(OEQ, nodconst(r->val), n, Z);	/* just gen the B.EQ */
-	patch(p, r->label);
-	swit2(q, i, def, n);
-
-	if(debug['W'])
-		print("case < %.8ux\n", r->val);
-	patch(sp, pc);
-	swit2(r+1, nc-i-1, def, n);
-	return;
-
-direct:
-	v = q->val;
-	if(v != 0)
-		gopcode(OSUB, nodconst(v), Z, n);
-	gopcode(OCASE, nodconst((q+nc-1)->val - v), n, Z);
-	patch(p, def);
-	for(i=0; i<nc; i++) {
-		if(debug['W'])
-			print("case = %.8ux\n", q->val);
-		while(q->val != v) {
-			nextpc();
-			p->as = ABCASE;
-			patch(p, def);
-			v++;
-		}
-		nextpc();
-		p->as = ABCASE;
-		patch(p, q->label);
-		q++;
-		v++;
-	}
-	gbranch(OGOTO);		/* so that regopt() won't be confused */
-	patch(p, def);
-}
-
-void
-bitload(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
-{
-	int sh;
-	int32 v;
-	Node *l;
-
-	/*
-	 * n1 gets adjusted/masked value
-	 * n2 gets address of cell
-	 * n3 gets contents of cell
-	 */
-	l = b->left;
-	if(n2 != Z) {
-		regalloc(n1, l, nn);
-		reglcgen(n2, l, Z);
-		regalloc(n3, l, Z);
-		gopcode(OAS, n2, Z, n3);
-		gopcode(OAS, n3, Z, n1);
-	} else {
-		regalloc(n1, l, nn);
-		cgen(l, n1);
-	}
-	if(b->type->shift == 0 && typeu[b->type->etype]) {
-		v = ~0 + (1L << b->type->nbits);
-		gopcode(OAND, nodconst(v), Z, n1);
-	} else {
-		sh = 32 - b->type->shift - b->type->nbits;
-		if(sh > 0)
-			gopcode(OASHL, nodconst(sh), Z, n1);
-		sh += b->type->shift;
-		if(sh > 0)
-			if(typeu[b->type->etype])
-				gopcode(OLSHR, nodconst(sh), Z, n1);
-			else
-				gopcode(OASHR, nodconst(sh), Z, n1);
-	}
-}
-
-void
-bitstore(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
-{
-	int32 v;
-	Node nod, *l;
-	int sh;
-
-	/*
-	 * n1 has adjusted/masked value
-	 * n2 has address of cell
-	 * n3 has contents of cell
-	 */
-	l = b->left;
-	regalloc(&nod, l, Z);
-	v = ~0 + (1L << b->type->nbits);
-	gopcode(OAND, nodconst(v), Z, n1);
-	gopcode(OAS, n1, Z, &nod);
-	if(nn != Z)
-		gopcode(OAS, n1, Z, nn);
-	sh = b->type->shift;
-	if(sh > 0)
-		gopcode(OASHL, nodconst(sh), Z, &nod);
-	v <<= sh;
-	gopcode(OAND, nodconst(~v), Z, n3);
-	gopcode(OOR, n3, Z, &nod);
-	gopcode(OAS, &nod, Z, n2);
-
-	regfree(&nod);
-	regfree(n1);
-	regfree(n2);
-	regfree(n3);
-}
-
-int32
-outstring(char *s, int32 n)
-{
-	int32 r;
-
-	if(suppress)
-		return nstring;
-	r = nstring;
-	while(n) {
-		string[mnstring] = *s++;
-		mnstring++;
-		nstring++;
-		if(mnstring >= NSNAME) {
-			gpseudo(ADATA, symstring, nodconst(0L));
-			p->from.offset += nstring - NSNAME;
-			p->reg = NSNAME;
-			p->to.type = D_SCONST;
-			memmove(p->to.u.sval, string, NSNAME);
-			mnstring = 0;
-		}
-		n--;
-	}
-	return r;
-}
-
-int
-mulcon(Node *n, Node *nn)
-{
-	Node *l, *r, nod1, nod2;
-	Multab *m;
-	int32 v, vs;
-	int o;
-	char code[sizeof(m->code)+2], *p;
-
-	if(typefd[n->type->etype])
-		return 0;
-	l = n->left;
-	r = n->right;
-	if(l->op == OCONST) {
-		l = r;
-		r = n->left;
-	}
-	if(r->op != OCONST)
-		return 0;
-	v = convvtox(r->vconst, n->type->etype);
-	if(v != r->vconst) {
-		if(debug['M'])
-			print("%L multiply conv: %lld\n", n->lineno, r->vconst);
-		return 0;
-	}
-	m = mulcon0(v);
-	if(!m) {
-		if(debug['M'])
-			print("%L multiply table: %lld\n", n->lineno, r->vconst);
-		return 0;
-	}
-	if(debug['M'] && debug['v'])
-		print("%L multiply: %d\n", n->lineno, v);
-
-	memmove(code, m->code, sizeof(m->code));
-	code[sizeof(m->code)] = 0;
-
-	p = code;
-	if(p[1] == 'i')
-		p += 2;
-	regalloc(&nod1, n, nn);
-	cgen(l, &nod1);
-	vs = v;
-	regalloc(&nod2, n, Z);
-
-loop:
-	switch(*p) {
-	case 0:
-		regfree(&nod2);
-		if(vs < 0) {
-			gopcode(OAS, &nod1, Z, &nod1);
-			gopcode(OSUB, &nod1, nodconst(0), nn);
-		} else
-			gopcode(OAS, &nod1, Z, nn);
-		regfree(&nod1);
-		return 1;
-	case '+':
-		o = OADD;
-		goto addsub;
-	case '-':
-		o = OSUB;
-	addsub:	/* number is r,n,l */
-		v = p[1] - '0';
-		r = &nod1;
-		if(v&4)
-			r = &nod2;
-		n = &nod1;
-		if(v&2)
-			n = &nod2;
-		l = &nod1;
-		if(v&1)
-			l = &nod2;
-		gopcode(o, l, n, r);
-		break;
-	default: /* op is shiftcount, number is r,l */
-		v = p[1] - '0';
-		r = &nod1;
-		if(v&2)
-			r = &nod2;
-		l = &nod1;
-		if(v&1)
-			l = &nod2;
-		v = *p - 'a';
-		if(v < 0 || v >= 32) {
-			diag(n, "mulcon unknown op: %c%c", p[0], p[1]);
-			break;
-		}
-		gopcode(OASHL, nodconst(v), l, r);
-		break;
-	}
-	p += 2;
-	goto loop;
-}
-
-void
-sextern(Sym *s, Node *a, int32 o, int32 w)
-{
-	int32 e, lw;
-
-	for(e=0; e<w; e+=NSNAME) {
-		lw = NSNAME;
-		if(w-e < lw)
-			lw = w-e;
-		gpseudo(ADATA, s, nodconst(0));
-		p->from.offset += o+e;
-		p->reg = lw;
-		p->to.type = D_SCONST;
-		memmove(p->to.u.sval, a->cstring+e, lw);
-	}
-}
-
-void
-gextern(Sym *s, Node *a, int32 o, int32 w)
-{
-
-	if(a->op == OCONST && typev[a->type->etype]) {
-		if(isbigendian)
-			gpseudo(ADATA, s, nod32const(a->vconst>>32));
-		else
-			gpseudo(ADATA, s, nod32const(a->vconst));
-		p->from.offset += o;
-		p->reg = 4;
-		if(isbigendian)
-			gpseudo(ADATA, s, nod32const(a->vconst));
-		else
-			gpseudo(ADATA, s, nod32const(a->vconst>>32));
-		p->from.offset += o + 4;
-		p->reg = 4;
-		return;
-	}
-	gpseudo(ADATA, s, a);
-	p->from.offset += o;
-	p->reg = w;
-	if(p->to.type == D_OREG)
-		p->to.type = D_CONST;
-}
-
-void
-outcode(void)
-{
-	Bprint(&outbuf, "go object %s %s %s\n", getgoos(), getgoarch(), getgoversion());
-	if(pragcgobuf.to > pragcgobuf.start) {
-		Bprint(&outbuf, "\n");
-		Bprint(&outbuf, "$$  // exports\n\n");
-		Bprint(&outbuf, "$$  // local types\n\n");
-		Bprint(&outbuf, "$$  // cgo\n");
-		Bprint(&outbuf, "%s", fmtstrflush(&pragcgobuf));
-		Bprint(&outbuf, "\n$$\n\n");
-	}
-	Bprint(&outbuf, "!\n");
-
-	writeobj(ctxt, &outbuf);
-	lastp = P;
-}
-
-int32
-align(int32 i, Type *t, int op, int32 *maxalign)
-{
-	int32 o;
-	Type *v;
-	int w, packw;
-
-	o = i;
-	w = 1;
-	packw = 0;
-	switch(op) {
-	default:
-		diag(Z, "unknown align opcode %d", op);
-		break;
-
-	case Asu2:	/* padding at end of a struct */
-		w = *maxalign;
-		if(w < 1)
-			w = 1;
-		if(packflg)
-			packw = packflg;
-		break;
-
-	case Ael1:	/* initial align of struct element */
-		for(v=t; v->etype==TARRAY; v=v->link)
-			;
-		if(v->etype == TSTRUCT || v->etype == TUNION)
-			w = v->align;
-		else {
-			w = ewidth[v->etype];
-			if(w == 8)
-				w = 4;
-		}
-		if(w < 1 || w > SZ_LONG)
-			fatal(Z, "align");
-		if(packflg) 
-			packw = packflg;
-		break;
-
-	case Ael2:	/* width of a struct element */
-		o += t->width;
-		break;
-
-	case Aarg0:	/* initial passbyptr argument in arg list */
-		if(typesuv[t->etype]) {
-			o = align(o, types[TIND], Aarg1, nil);
-			o = align(o, types[TIND], Aarg2, nil);
-		}
-		break;
-
-	case Aarg1:	/* initial align of parameter */
-		w = ewidth[t->etype];
-		if(w <= 0 || w >= SZ_LONG) {
-			w = SZ_LONG;
-			break;
-		}
-		w = 1;		/* little endian no adjustment */
-		break;
-
-	case Aarg2:	/* width of a parameter */
-		o += t->width;
-		w = t->width;
-		if(w > SZ_LONG)
-			w = SZ_LONG;
-		break;
-
-	case Aaut3:	/* total align of automatic */
-		o = align(o, t, Ael2, nil);
-		o = align(o, t, Ael1, nil);
-		w = SZ_LONG;	/* because of a pun in cc/dcl.c:contig() */
-		break;
-	}
-	if(packw != 0 && xround(o, w) != xround(o, packw))
-		diag(Z, "#pragma pack changes offset of %T", t);
-	o = xround(o, w);
-	if(maxalign != nil && *maxalign < w)
-		*maxalign = w;
-	if(debug['A'])
-		print("align %s %d %T = %d\n", bnames[op], i, t, o);
-	return o;
-}
-
-int32
-maxround(int32 max, int32 v)
-{
-	v = xround(v, SZ_LONG);
-	if(v > max)
-		return v;
-	return max;
-}
diff --git a/src/cmd/5c/txt.c b/src/cmd/5c/txt.c
deleted file mode 100644
index af40220..0000000
--- a/src/cmd/5c/txt.c
+++ /dev/null
@@ -1,1361 +0,0 @@
-// Inferno utils/5c/txt.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5c/txt.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-
-#include "gc.h"
-
-
-int thechar = '5';
-char *thestring = "arm";
-
-LinkArch	*thelinkarch = &linkarm;
-
-void
-linkarchinit(void)
-{
-}
-
-void
-ginit(void)
-{
-	Type *t;
-
-	exregoffset = REGEXT;
-	exfregoffset = FREGEXT;
-	listinit();
-	nstring = 0;
-	mnstring = 0;
-	nrathole = 0;
-	pc = 0;
-	breakpc = -1;
-	continpc = -1;
-	cases = C;
-	lastp = P;
-	tfield = types[TLONG];
-
-	zprog.link = P;
-	zprog.as = AGOK;
-	zprog.reg = NREG;
-	zprog.from.type = D_NONE;
-	zprog.from.name = D_NONE;
-	zprog.from.reg = NREG;
-	zprog.to = zprog.from;
-	zprog.scond = 0xE;
-
-	regnode.op = OREGISTER;
-	regnode.class = CEXREG;
-	regnode.reg = REGTMP;
-	regnode.complex = 0;
-	regnode.addable = 11;
-	regnode.type = types[TLONG];
-
-	constnode.op = OCONST;
-	constnode.class = CXXX;
-	constnode.complex = 0;
-	constnode.addable = 20;
-	constnode.type = types[TLONG];
-
-	fconstnode.op = OCONST;
-	fconstnode.class = CXXX;
-	fconstnode.complex = 0;
-	fconstnode.addable = 20;
-	fconstnode.type = types[TDOUBLE];
-
-	nodsafe = new(ONAME, Z, Z);
-	nodsafe->sym = slookup(".safe");
-	nodsafe->type = types[TINT];
-	nodsafe->etype = types[TINT]->etype;
-	nodsafe->class = CAUTO;
-	complex(nodsafe);
-
-	t = typ(TARRAY, types[TCHAR]);
-	symrathole = slookup(".rathole");
-	symrathole->class = CGLOBL;
-	symrathole->type = t;
-
-	nodrat = new(ONAME, Z, Z);
-	nodrat->sym = symrathole;
-	nodrat->type = types[TIND];
-	nodrat->etype = TVOID;
-	nodrat->class = CGLOBL;
-	complex(nodrat);
-	nodrat->type = t;
-
-	nodret = new(ONAME, Z, Z);
-	nodret->sym = slookup(".ret");
-	nodret->type = types[TIND];
-	nodret->etype = TIND;
-	nodret->class = CPARAM;
-	nodret = new(OIND, nodret, Z);
-	complex(nodret);
-
-	com64init();
-
-	memset(reg, 0, sizeof(reg));
-}
-
-void
-gclean(void)
-{
-	int i;
-	Sym *s;
-
-	for(i=0; i<NREG; i++)
-		if(reg[i])
-			diag(Z, "reg %d left allocated", i);
-	for(i=NREG; i<NREG+NFREG; i++)
-		if(reg[i])
-			diag(Z, "freg %d left allocated", i-NREG);
-	while(mnstring)
-		outstring("", 1L);
-	symstring->type->width = nstring;
-	symrathole->type->width = nrathole;
-	for(i=0; i<NHASH; i++)
-	for(s = hash[i]; s != S; s = s->link) {
-		if(s->type == T)
-			continue;
-		if(s->type->width == 0)
-			continue;
-		if(s->class != CGLOBL && s->class != CSTATIC)
-			continue;
-		if(s->type == types[TENUM])
-			continue;
-		gpseudo(AGLOBL, s, nodconst(s->type->width));
-	}
-	nextpc();
-	p->as = AEND;
-	outcode();
-}
-
-void
-nextpc(void)
-{
-	Plist *pl;
-
-	p = alloc(sizeof(*p));
-	*p = zprog;
-	p->lineno = nearln;
-	pc++;
-	if(lastp == nil) {
-		pl = linknewplist(ctxt);
-		pl->firstpc = p;
-	} else
-		lastp->link = p;
-	lastp = p;
-}
-
-void
-gargs(Node *n, Node *tn1, Node *tn2)
-{
-	int32 regs;
-	Node fnxargs[20], *fnxp;
-
-	regs = cursafe;
-
-	fnxp = fnxargs;
-	garg1(n, tn1, tn2, 0, &fnxp);	/* compile fns to temps */
-
-	curarg = 0;
-	fnxp = fnxargs;
-	garg1(n, tn1, tn2, 1, &fnxp);	/* compile normal args and temps */
-
-	cursafe = regs;
-}
-
-void
-garg1(Node *n, Node *tn1, Node *tn2, int f, Node **fnxp)
-{
-	Node nod;
-
-	if(n == Z)
-		return;
-	if(n->op == OLIST) {
-		garg1(n->left, tn1, tn2, f, fnxp);
-		garg1(n->right, tn1, tn2, f, fnxp);
-		return;
-	}
-	if(f == 0) {
-		if(n->complex >= FNX) {
-			regsalloc(*fnxp, n);
-			nod = znode;
-			nod.op = OAS;
-			nod.left = *fnxp;
-			nod.right = n;
-			nod.type = n->type;
-			cgen(&nod, Z);
-			(*fnxp)++;
-		}
-		return;
-	}
-	if(typesuv[n->type->etype]) {
-		regaalloc(tn2, n);
-		if(n->complex >= FNX) {
-			sugen(*fnxp, tn2, n->type->width);
-			(*fnxp)++;
-		} else
-			sugen(n, tn2, n->type->width);
-		return;
-	}
-	if(REGARG >= 0 && curarg == 0 && typechlp[n->type->etype]) {
-		regaalloc1(tn1, n);
-		if(n->complex >= FNX) {
-			cgen(*fnxp, tn1);
-			(*fnxp)++;
-		} else
-			cgen(n, tn1);
-		return;
-	}
-	regalloc(tn1, n, Z);
-	if(n->complex >= FNX) {
-		cgen(*fnxp, tn1);
-		(*fnxp)++;
-	} else
-		cgen(n, tn1);
-	regaalloc(tn2, n);
-	gopcode(OAS, tn1, Z, tn2);
-	regfree(tn1);
-}
-
-Node*
-nodconst(int32 v)
-{
-	constnode.vconst = v;
-	return &constnode;
-}
-
-Node*
-nod32const(vlong v)
-{
-	constnode.vconst = v & MASK(32);
-	return &constnode;
-}
-
-Node*
-nodfconst(double d)
-{
-	fconstnode.fconst = d;
-	return &fconstnode;
-}
-
-void
-nodreg(Node *n, Node *nn, int reg)
-{
-	*n = regnode;
-	n->reg = reg;
-	n->type = nn->type;
-	n->lineno = nn->lineno;
-}
-
-void
-regret(Node *n, Node *nn, Type *t, int mode)
-{
-	int r;
-
-	if(mode == 0 || hasdotdotdot(t) || nn->type->width == 0) {
-		r = REGRET;
-		if(typefd[nn->type->etype])
-			r = FREGRET+NREG;
-		nodreg(n, nn, r);
-		reg[r]++;
-		return;
-	}
-	
-	if(mode == 1) {
-		// fetch returned value after call.
-		// already called gargs, so curarg is set.
-		curarg = (curarg+3) & ~3;
-		regaalloc(n, nn);
-		return;
-	}
-	
-	if(mode == 2) {
-		// store value to be returned.
-		// must compute arg offset.
-		if(t->etype != TFUNC)
-			fatal(Z, "bad regret func %T", t);
-		*n = *nn;
-		n->op = ONAME;
-		n->class = CPARAM;
-		n->sym = slookup(".ret");
-		n->complex = nodret->complex;
-		n->xoffset = argsize(0);
-		n->addable = 20;
-		return;
-	}
-	
-	fatal(Z, "bad regret");
-}
-
-int
-tmpreg(void)
-{
-	int i;
-
-	for(i=REGRET+1; i<NREG; i++)
-		if(reg[i] == 0)
-			return i;
-	diag(Z, "out of fixed registers");
-	return 0;
-}
-
-void
-regalloc(Node *n, Node *tn, Node *o)
-{
-	int i;
-
-	switch(tn->type->etype) {
-	case TCHAR:
-	case TUCHAR:
-	case TSHORT:
-	case TUSHORT:
-	case TINT:
-	case TUINT:
-	case TLONG:
-	case TULONG:
-	case TIND:
-		if(o != Z && o->op == OREGISTER) {
-			i = o->reg;
-			if(i >= 0 && i < NREG)
-				goto out;
-		}
-		for(i=REGRET+1; i<=REGEXT-2; i++)
-			if(reg[i] == 0)
-				goto out;
-		diag(tn, "out of fixed registers");
-		goto err;
-
-	case TFLOAT:
-	case TDOUBLE:
-	case TVLONG:
-		if(o != Z && o->op == OREGISTER) {
-			i = o->reg;
-			if(i >= NREG && i < NREG+NFREG)
-				goto out;
-		}
-		for(i=NREG; i<NREG+NFREG; i++)
-			if(reg[i] == 0)
-				goto out;
-		diag(tn, "out of float registers");
-		goto err;
-	}
-	diag(tn, "unknown type in regalloc: %T", tn->type);
-err:
-	nodreg(n, tn, 0);
-	return;
-out:
-	reg[i]++;
-	nodreg(n, tn, i);
-}
-
-void
-regialloc(Node *n, Node *tn, Node *o)
-{
-	Node nod;
-
-	nod = *tn;
-	nod.type = types[TIND];
-	regalloc(n, &nod, o);
-}
-
-void
-regfree(Node *n)
-{
-	int i;
-
-	i = 0;
-	if(n->op != OREGISTER && n->op != OINDREG)
-		goto err;
-	i = n->reg;
-	if(i < 0 || i >= nelem(reg))
-		goto err;
-	if(reg[i] <= 0)
-		goto err;
-	reg[i]--;
-	return;
-err:
-	diag(n, "error in regfree: %d", i);
-}
-
-void
-regsalloc(Node *n, Node *nn)
-{
-	cursafe = align(cursafe, nn->type, Aaut3, nil);
-	maxargsafe = maxround(maxargsafe, cursafe+curarg);
-	*n = *nodsafe;
-	n->xoffset = -(stkoff + cursafe);
-	n->type = nn->type;
-	n->etype = nn->type->etype;
-	n->lineno = nn->lineno;
-}
-
-void
-regaalloc1(Node *n, Node *nn)
-{
-	if(REGARG < 0) {
-		fatal(n, "regaalloc1 and REGARG<0");
-		return;
-	}
-	nodreg(n, nn, REGARG);
-	reg[REGARG]++;
-	curarg = align(curarg, nn->type, Aarg1, nil);
-	curarg = align(curarg, nn->type, Aarg2, nil);
-	maxargsafe = maxround(maxargsafe, cursafe+curarg);
-}
-
-void
-regaalloc(Node *n, Node *nn)
-{
-	curarg = align(curarg, nn->type, Aarg1, nil);
-	*n = *nn;
-	n->op = OINDREG;
-	n->reg = REGSP;
-	n->xoffset = curarg + SZ_LONG;
-	n->complex = 0;
-	n->addable = 20;
-	curarg = align(curarg, nn->type, Aarg2, nil);
-	maxargsafe = maxround(maxargsafe, cursafe+curarg);
-}
-
-void
-regind(Node *n, Node *nn)
-{
-
-	if(n->op != OREGISTER) {
-		diag(n, "regind not OREGISTER");
-		return;
-	}
-	n->op = OINDREG;
-	n->type = nn->type;
-}
-
-void
-raddr(Node *n, Prog *p)
-{
-	Addr a;
-
-	naddr(n, &a);
-	if(R0ISZERO && a.type == D_CONST && a.offset == 0) {
-		a.type = D_REG;
-		a.reg = 0;
-	}
-	if(a.type != D_REG && a.type != D_FREG) {
-		if(n)
-			diag(n, "bad in raddr: %O", n->op);
-		else
-			diag(n, "bad in raddr: <null>");
-		p->reg = NREG;
-	} else
-		p->reg = a.reg;
-}
-
-void
-naddr(Node *n, Addr *a)
-{
-	int32 v;
-
-	a->type = D_NONE;
-	if(n == Z)
-		return;
-	switch(n->op) {
-	default:
-	bad:
-		diag(n, "bad in naddr: %O", n->op);
-		break;
-
-	case OREGISTER:
-		a->type = D_REG;
-		a->sym = nil;
-		a->reg = n->reg;
-		if(a->reg >= NREG) {
-			a->type = D_FREG;
-			a->reg -= NREG;
-		}
-		break;
-
-	case OIND:
-		naddr(n->left, a);
-		if(a->type == D_REG) {
-			a->type = D_OREG;
-			break;
-		}
-		if(a->type == D_CONST) {
-			a->type = D_OREG;
-			break;
-		}
-		goto bad;
-
-	case OINDREG:
-		a->type = D_OREG;
-		a->sym = nil;
-		a->offset = n->xoffset;
-		a->reg = n->reg;
-		break;
-
-	case ONAME:
-		a->etype = n->etype;
-		a->type = D_OREG;
-		a->name = D_STATIC;
-		a->sym = linksym(n->sym);
-		a->offset = n->xoffset;
-		if(n->class == CSTATIC)
-			break;
-		if(n->class == CEXTERN || n->class == CGLOBL) {
-			a->name = D_EXTERN;
-			break;
-		}
-		if(n->class == CAUTO) {
-			a->name = D_AUTO;
-			break;
-		}
-		if(n->class == CPARAM) {
-			a->name = D_PARAM;
-			break;
-		}
-		goto bad;
-
-	case OCONST:
-		a->sym = nil;
-		a->reg = NREG;
-		if(typefd[n->type->etype]) {
-			a->type = D_FCONST;
-			a->u.dval = n->fconst;
-		} else {
-			a->type = D_CONST;
-			a->offset = n->vconst;
-		}
-		break;
-
-	case OADDR:
-		naddr(n->left, a);
-		if(a->type == D_OREG) {
-			a->type = D_CONST;
-			break;
-		}
-		goto bad;
-
-	case OADD:
-		if(n->left->op == OCONST) {
-			naddr(n->left, a);
-			v = a->offset;
-			naddr(n->right, a);
-		} else {
-			naddr(n->right, a);
-			v = a->offset;
-			naddr(n->left, a);
-		}
-		a->offset += v;
-		break;
-
-	}
-}
-
-void
-fop(int as, int f1, int f2, Node *t)
-{
-	Node nod1, nod2, nod3;
-
-	nodreg(&nod1, t, NREG+f1);
-	nodreg(&nod2, t, NREG+f2);
-	regalloc(&nod3, t, t);
-	gopcode(as, &nod1, &nod2, &nod3);
-	gmove(&nod3, t);
-	regfree(&nod3);
-}
-
-void
-gmovm(Node *f, Node *t, int w)
-{
-	gins(AMOVM, f, t);
-	p->scond |= C_UBIT;
-	if(w)
-		p->scond |= C_WBIT;
-}
-
-void
-gmove(Node *f, Node *t)
-{
-	int ft, tt, a;
-	Node nod, nod1;
-	Prog *p1;
-
-	ft = f->type->etype;
-	tt = t->type->etype;
-
-	if(ft == TDOUBLE && f->op == OCONST) {
-	}
-	if(ft == TFLOAT && f->op == OCONST) {
-	}
-
-	/*
-	 * a load --
-	 * put it into a register then
-	 * worry what to do with it.
-	 */
-	if(f->op == ONAME || f->op == OINDREG || f->op == OIND) {
-		switch(ft) {
-		default:
-			a = AMOVW;
-			break;
-		case TFLOAT:
-			a = AMOVF;
-			break;
-		case TDOUBLE:
-			a = AMOVD;
-			break;
-		case TCHAR:
-			a = AMOVBS;
-			break;
-		case TUCHAR:
-			a = AMOVBU;
-			break;
-		case TSHORT:
-			a = AMOVHS;
-			break;
-		case TUSHORT:
-			a = AMOVHU;
-			break;
-		}
-		if(typechlp[ft] && typeilp[tt])
-			regalloc(&nod, t, t);
-		else
-			regalloc(&nod, f, t);
-		gins(a, f, &nod);
-		gmove(&nod, t);
-		regfree(&nod);
-		return;
-	}
-
-	/*
-	 * a store --
-	 * put it into a register then
-	 * store it.
-	 */
-	if(t->op == ONAME || t->op == OINDREG || t->op == OIND) {
-		switch(tt) {
-		default:
-			a = AMOVW;
-			break;
-		case TUCHAR:
-			a = AMOVBU;
-			break;
-		case TCHAR:
-			a = AMOVBS;
-			break;
-		case TUSHORT:
-			a = AMOVHU;
-			break;
-		case TSHORT:
-			a = AMOVHS;
-			break;
-		case TFLOAT:
-			a = AMOVF;
-			break;
-		case TVLONG:
-		case TDOUBLE:
-			a = AMOVD;
-			break;
-		}
-		if(ft == tt)
-			regalloc(&nod, t, f);
-		else
-			regalloc(&nod, t, Z);
-		gmove(f, &nod);
-		gins(a, &nod, t);
-		regfree(&nod);
-		return;
-	}
-
-	/*
-	 * type x type cross table
-	 */
-	a = AGOK;
-	switch(ft) {
-	case TDOUBLE:
-	case TVLONG:
-	case TFLOAT:
-		switch(tt) {
-		case TDOUBLE:
-		case TVLONG:
-			a = AMOVD;
-			if(ft == TFLOAT)
-				a = AMOVFD;
-			break;
-		case TFLOAT:
-			a = AMOVDF;
-			if(ft == TFLOAT)
-				a = AMOVF;
-			break;
-		case TINT:
-		case TUINT:
-		case TLONG:
-		case TULONG:
-		case TIND:
-			a = AMOVDW;
-			if(ft == TFLOAT)
-				a = AMOVFW;
-			break;
-		case TSHORT:
-		case TUSHORT:
-		case TCHAR:
-		case TUCHAR:
-			a = AMOVDW;
-			if(ft == TFLOAT)
-				a = AMOVFW;
-			break;
-		}
-		break;
-	case TUINT:
-	case TULONG:
-		if(tt == TFLOAT || tt == TDOUBLE) {
-			// ugly and probably longer than necessary,
-			// but vfp has a single instruction for this,
-			// so hopefully it won't last long.
-			//
-			//	tmp = f
-			//	tmp1 = tmp & 0x80000000
-			//	tmp ^= tmp1
-			//	t = float(int32(tmp))
-			//	if(tmp1)
-			//		t += 2147483648.
-			//
-			regalloc(&nod, f, Z);
-			regalloc(&nod1, f, Z);
-			gins(AMOVW, f, &nod);
-			gins(AMOVW, &nod, &nod1);
-			gins(AAND, nodconst(0x80000000), &nod1);
-			gins(AEOR, &nod1, &nod);
-			if(tt == TFLOAT)
-				gins(AMOVWF, &nod, t);
-			else
-				gins(AMOVWD, &nod, t);
-			gins(ACMP, nodconst(0), Z);
-			raddr(&nod1, p);
-			gins(ABEQ, Z, Z);
-			regfree(&nod);
-			regfree(&nod1);
-			p1 = p;
-			regalloc(&nod, t, Z);
-			gins(AMOVF, nodfconst(2147483648.), &nod);
-			gins(AADDF, &nod, t);
-			regfree(&nod);
-			patch(p1, pc);
-			return;
-		}
-		// fall through
-	
-	case TINT:
-	case TLONG:
-	case TIND:
-		switch(tt) {
-		case TDOUBLE:
-			gins(AMOVWD, f, t);
-			return;
-		case TFLOAT:
-			gins(AMOVWF, f, t);
-			return;
-		case TINT:
-		case TUINT:
-		case TLONG:
-		case TULONG:
-		case TIND:
-		case TSHORT:
-		case TUSHORT:
-		case TCHAR:
-		case TUCHAR:
-			a = AMOVW;
-			break;
-		}
-		break;
-	case TSHORT:
-		switch(tt) {
-		case TDOUBLE:
-			regalloc(&nod, f, Z);
-			gins(AMOVHS, f, &nod);
-			gins(AMOVWD, &nod, t);
-			regfree(&nod);
-			return;
-		case TFLOAT:
-			regalloc(&nod, f, Z);
-			gins(AMOVHS, f, &nod);
-			gins(AMOVWF, &nod, t);
-			regfree(&nod);
-			return;
-		case TUINT:
-		case TINT:
-		case TULONG:
-		case TLONG:
-		case TIND:
-			a = AMOVHS;
-			break;
-		case TSHORT:
-		case TUSHORT:
-		case TCHAR:
-		case TUCHAR:
-			a = AMOVW;
-			break;
-		}
-		break;
-	case TUSHORT:
-		switch(tt) {
-		case TDOUBLE:
-			regalloc(&nod, f, Z);
-			gins(AMOVHU, f, &nod);
-			gins(AMOVWD, &nod, t);
-			regfree(&nod);
-			return;
-		case TFLOAT:
-			regalloc(&nod, f, Z);
-			gins(AMOVHU, f, &nod);
-			gins(AMOVWF, &nod, t);
-			regfree(&nod);
-			return;
-		case TINT:
-		case TUINT:
-		case TLONG:
-		case TULONG:
-		case TIND:
-			a = AMOVHU;
-			break;
-		case TSHORT:
-		case TUSHORT:
-		case TCHAR:
-		case TUCHAR:
-			a = AMOVW;
-			break;
-		}
-		break;
-	case TCHAR:
-		switch(tt) {
-		case TDOUBLE:
-			regalloc(&nod, f, Z);
-			gins(AMOVBS, f, &nod);
-			gins(AMOVWD, &nod, t);
-			regfree(&nod);
-			return;
-		case TFLOAT:
-			regalloc(&nod, f, Z);
-			gins(AMOVBS, f, &nod);
-			gins(AMOVWF, &nod, t);
-			regfree(&nod);
-			return;
-		case TINT:
-		case TUINT:
-		case TLONG:
-		case TULONG:
-		case TIND:
-		case TSHORT:
-		case TUSHORT:
-			a = AMOVBS;
-			break;
-		case TCHAR:
-		case TUCHAR:
-			a = AMOVW;
-			break;
-		}
-		break;
-	case TUCHAR:
-		switch(tt) {
-		case TDOUBLE:
-			regalloc(&nod, f, Z);
-			gins(AMOVBU, f, &nod);
-			gins(AMOVWD, &nod, t);
-			regfree(&nod);
-			return;
-		case TFLOAT:
-			regalloc(&nod, f, Z);
-			gins(AMOVBU, f, &nod);
-			gins(AMOVWF, &nod, t);
-			regfree(&nod);
-			return;
-		case TINT:
-		case TUINT:
-		case TLONG:
-		case TULONG:
-		case TIND:
-		case TSHORT:
-		case TUSHORT:
-			a = AMOVBU;
-			break;
-		case TCHAR:
-		case TUCHAR:
-			a = AMOVW;
-			break;
-		}
-		break;
-	}
-	if(a == AGOK)
-		diag(Z, "bad opcode in gmove %T -> %T", f->type, t->type);
-	if(a == AMOVW || a == AMOVF || a == AMOVD)
-	if(samaddr(f, t))
-		return;
-	gins(a, f, t);
-}
-
-void
-gmover(Node *f, Node *t)
-{
-	int ft, tt, a;
-
-	ft = f->type->etype;
-	tt = t->type->etype;
-	a = AGOK;
-	if(typechlp[ft] && typechlp[tt] && ewidth[ft] >= ewidth[tt]){
-		switch(tt){
-		case TSHORT:
-			a = AMOVHS;
-			break;
-		case TUSHORT:
-			a = AMOVHU;
-			break;
-		case TCHAR:
-			a = AMOVBS;
-			break;
-		case TUCHAR:
-			a = AMOVBU;
-			break;
-		}
-	}
-	if(a == AGOK)
-		gmove(f, t);
-	else
-		gins(a, f, t);
-}
-
-void
-gins(int a, Node *f, Node *t)
-{
-
-	nextpc();
-	p->as = a;
-	if(f != Z)
-		naddr(f, &p->from);
-	if(t != Z)
-		naddr(t, &p->to);
-	if(debug['g'])
-		print("%P\n", p);
-}
-
-void
-gopcode(int o, Node *f1, Node *f2, Node *t)
-{
-	int a, et;
-	Addr ta;
-
-	et = TLONG;
-	if(f1 != Z && f1->type != T)
-		et = f1->type->etype;
-	a = AGOK;
-	switch(o) {
-	case OAS:
-		gmove(f1, t);
-		return;
-
-	case OASADD:
-	case OADD:
-		a = AADD;
-		if(et == TFLOAT)
-			a = AADDF;
-		else
-		if(et == TDOUBLE || et == TVLONG)
-			a = AADDD;
-		break;
-
-	case OASSUB:
-	case OSUB:
-		if(f2 && f2->op == OCONST) {
-			Node *t = f1;
-			f1 = f2;
-			f2 = t;
-			a = ARSB;
-		} else
-			a = ASUB;
-		if(et == TFLOAT)
-			a = ASUBF;
-		else
-		if(et == TDOUBLE || et == TVLONG)
-			a = ASUBD;
-		break;
-
-	case OASOR:
-	case OOR:
-		a = AORR;
-		break;
-
-	case OASAND:
-	case OAND:
-		a = AAND;
-		break;
-
-	case OASXOR:
-	case OXOR:
-		a = AEOR;
-		break;
-
-	case OASLSHR:
-	case OLSHR:
-		a = ASRL;
-		break;
-
-	case OASASHR:
-	case OASHR:
-		a = ASRA;
-		break;
-
-	case OASASHL:
-	case OASHL:
-		a = ASLL;
-		break;
-
-	case OFUNC:
-		a = ABL;
-		break;
-
-	case OASMUL:
-	case OMUL:
-		a = AMUL;
-		if(et == TFLOAT)
-			a = AMULF;
-		else
-		if(et == TDOUBLE || et == TVLONG)
-			a = AMULD;
-		break;
-
-	case OASDIV:
-	case ODIV:
-		a = ADIV;
-		if(et == TFLOAT)
-			a = ADIVF;
-		else
-		if(et == TDOUBLE || et == TVLONG)
-			a = ADIVD;
-		break;
-
-	case OASMOD:
-	case OMOD:
-		a = AMOD;
-		break;
-
-	case OASLMUL:
-	case OLMUL:
-		a = AMULU;
-		break;
-
-	case OASLMOD:
-	case OLMOD:
-		a = AMODU;
-		break;
-
-	case OASLDIV:
-	case OLDIV:
-		a = ADIVU;
-		break;
-
-	case OCASE:
-	case OEQ:
-	case ONE:
-	case OLT:
-	case OLE:
-	case OGE:
-	case OGT:
-	case OLO:
-	case OLS:
-	case OHS:
-	case OHI:
-		a = ACMP;
-		if(et == TFLOAT)
-			a = ACMPF;
-		else
-		if(et == TDOUBLE || et == TVLONG)
-			a = ACMPD;
-		nextpc();
-		p->as = a;
-		naddr(f1, &p->from);
-		if(a == ACMP && f1->op == OCONST && p->from.offset < 0) {
-			p->as = ACMN;
-			p->from.offset = -p->from.offset;
-		}
-		raddr(f2, p);
-		switch(o) {
-		case OEQ:
-			a = ABEQ;
-			break;
-		case ONE:
-			a = ABNE;
-			break;
-		case OLT:
-			a = ABLT;
-			break;
-		case OLE:
-			a = ABLE;
-			break;
-		case OGE:
-			a = ABGE;
-			break;
-		case OGT:
-			a = ABGT;
-			break;
-		case OLO:
-			a = ABLO;
-			break;
-		case OLS:
-			a = ABLS;
-			break;
-		case OHS:
-			a = ABHS;
-			break;
-		case OHI:
-			a = ABHI;
-			break;
-		case OCASE:
-			nextpc();
-			p->as = ACASE;
-			p->scond = 0x9;
-			naddr(f2, &p->from);
-			a = ABHI;
-			break;
-		}
-		f1 = Z;
-		f2 = Z;
-		break;
-	}
-	if(a == AGOK)
-		diag(Z, "bad in gopcode %O", o);
-	nextpc();
-	p->as = a;
-	if(f1 != Z)
-		naddr(f1, &p->from);
-	if(f2 != Z) {
-		naddr(f2, &ta);
-		p->reg = ta.reg;
-	}
-	if(t != Z)
-		naddr(t, &p->to);
-	if(debug['g'])
-		print("%P\n", p);
-}
-
-int
-samaddr(Node *f, Node *t)
-{
-
-	if(f->op != t->op)
-		return 0;
-	switch(f->op) {
-
-	case OREGISTER:
-		if(f->reg != t->reg)
-			break;
-		return 1;
-	}
-	return 0;
-}
-
-void
-gbranch(int o)
-{
-	int a;
-
-	a = AGOK;
-	switch(o) {
-	case ORETURN:
-		a = ARET;
-		break;
-	case OGOTO:
-		a = AB;
-		break;
-	}
-	nextpc();
-	if(a == AGOK) {
-		diag(Z, "bad in gbranch %O",  o);
-		nextpc();
-	}
-	p->as = a;
-}
-
-void
-patch(Prog *op, int32 pc)
-{
-
-	op->to.offset = pc;
-	op->to.type = D_BRANCH;
-}
-
-void
-gpseudo(int a, Sym *s, Node *n)
-{
-	nextpc();
-	p->as = a;
-	p->from.type = D_OREG;
-	p->from.sym = linksym(s);
-	p->from.name = D_EXTERN;
-
-	switch(a) {
-	case ATEXT:
-		p->reg = textflag;
-		textflag = 0;
-		break;
-	case AGLOBL:
-		p->reg = s->dataflag;
-		break;
-	}
-
-	if(s->class == CSTATIC)
-		p->from.name = D_STATIC;
-	naddr(n, &p->to);
-	if(a == ADATA || a == AGLOBL)
-		pc--;
-}
-
-void
-gpcdata(int index, int value)
-{
-	Node n1;
-	
-	n1 = *nodconst(index);
-	gins(APCDATA, &n1, nodconst(value));
-}
-
-void
-gprefetch(Node *n)
-{
-	Node n1;
-
-	regalloc(&n1, n, Z);
-	gmove(n, &n1);
-	n1.op = OINDREG;
-	gins(APLD, &n1, Z);
-	regfree(&n1);
-}
-
-int
-sconst(Node *n)
-{
-	vlong vv;
-
-	if(n->op == OCONST) {
-		if(!typefd[n->type->etype]) {
-			vv = n->vconst;
-			if(vv >= (vlong)(-32766) && vv < (vlong)32766)
-				return 1;
-			/*
-			 * should be specialised for constant values which will
-			 * fit in different instructionsl; for now, let 5l
-			 * sort it out
-			 */
-			return 1;
-		}
-	}
-	return 0;
-}
-
-int
-sval(int32 v)
-{
-	int i;
-
-	for(i=0; i<16; i++) {
-		if((v & ~0xff) == 0)
-			return 1;
-		if((~v & ~0xff) == 0)
-			return 1;
-		v = (v<<2) | ((uint32)v>>30);
-	}
-	return 0;
-}
-
-int32
-exreg(Type *t)
-{
-	int32 o;
-
-	if(typechlp[t->etype]) {
-		if(exregoffset <= REGEXT-4)
-			return 0;
-		o = exregoffset;
-		exregoffset--;
-		return o;
-	}
-	if(typefd[t->etype]) {
-		if(exfregoffset <= NFREG-1)
-			return 0;
-		o = exfregoffset + NREG;
-		exfregoffset--;
-		return o;
-	}
-	return 0;
-}
-
-schar	ewidth[NTYPE] =
-{
-	-1,		/* [TXXX] */
-	SZ_CHAR,	/* [TCHAR] */
-	SZ_CHAR,	/* [TUCHAR] */
-	SZ_SHORT,	/* [TSHORT] */
-	SZ_SHORT,	/* [TUSHORT] */
-	SZ_INT,		/* [TINT] */
-	SZ_INT,		/* [TUINT] */
-	SZ_LONG,	/* [TLONG] */
-	SZ_LONG,	/* [TULONG] */
-	SZ_VLONG,	/* [TVLONG] */
-	SZ_VLONG,	/* [TUVLONG] */
-	SZ_FLOAT,	/* [TFLOAT] */
-	SZ_DOUBLE,	/* [TDOUBLE] */
-	SZ_IND,		/* [TIND] */
-	0,		/* [TFUNC] */
-	-1,		/* [TARRAY] */
-	0,		/* [TVOID] */
-	-1,		/* [TSTRUCT] */
-	-1,		/* [TUNION] */
-	SZ_INT,		/* [TENUM] */
-};
-
-int32	ncast[NTYPE] =
-{
-	0,				/* [TXXX] */
-	BCHAR|BUCHAR,			/* [TCHAR] */
-	BCHAR|BUCHAR,			/* [TUCHAR] */
-	BSHORT|BUSHORT,			/* [TSHORT] */
-	BSHORT|BUSHORT,			/* [TUSHORT] */
-	BINT|BUINT|BLONG|BULONG|BIND,	/* [TINT] */
-	BINT|BUINT|BLONG|BULONG|BIND,	/* [TUINT] */
-	BINT|BUINT|BLONG|BULONG|BIND,	/* [TLONG] */
-	BINT|BUINT|BLONG|BULONG|BIND,	/* [TULONG] */
-	BVLONG|BUVLONG,			/* [TVLONG] */
-	BVLONG|BUVLONG,			/* [TUVLONG] */
-	BFLOAT,				/* [TFLOAT] */
-	BDOUBLE,			/* [TDOUBLE] */
-	BLONG|BULONG|BIND,		/* [TIND] */
-	0,				/* [TFUNC] */
-	0,				/* [TARRAY] */
-	0,				/* [TVOID] */
-	BSTRUCT,			/* [TSTRUCT] */
-	BUNION,				/* [TUNION] */
-	0,				/* [TENUM] */
-};
diff --git a/src/cmd/5g/Makefile b/src/cmd/5g/Makefile
deleted file mode 100644
index 3f528d7..0000000
--- a/src/cmd/5g/Makefile
+++ /dev/null
@@ -1,5 +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.
-
-include ../../Make.dist
diff --git a/src/cmd/5g/cgen.c b/src/cmd/5g/cgen.c
deleted file mode 100644
index 87c64f6..0000000
--- a/src/cmd/5g/cgen.c
+++ /dev/null
@@ -1,1846 +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 <u.h>
-#include <libc.h>
-#include "gg.h"
-
-/*
- * generate:
- *	res = n;
- * simplifies and calls gmove.
- */
-void
-cgen(Node *n, Node *res)
-{
-	Node *nl, *nr, *r;
-	Node n1, n2, f0, f1;
-	int a, w, rg;
-	Prog *p1, *p2, *p3;
-	Addr addr;
-
-	if(debug['g']) {
-		dump("\ncgen-n", n);
-		dump("cgen-res", res);
-	}
-	if(n == N || n->type == T)
-		goto ret;
-
-	if(res == N || res->type == T)
-		fatal("cgen: res nil");
-
-	switch(n->op) {
-	case OSLICE:
-	case OSLICEARR:
-	case OSLICESTR:
-	case OSLICE3:
-	case OSLICE3ARR:
-		if (res->op != ONAME || !res->addable) {
-			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) {
-			tempname(&n1, n->type);
-			cgen_eface(n, &n1);
-			cgen(&n1, res);
-		} else
-			cgen_eface(n, res);
-		return;
-	}
-
-	while(n->op == OCONVNOP)
-		n = n->left;
-
-	if(n->ullman >= UINF) {
-		if(n->op == OINDREG)
-			fatal("cgen: this is going to misscompile");
-		if(res->ullman >= UINF) {
-			tempname(&n1, n->type);
-			cgen(n, &n1);
-			cgen(&n1, res);
-			goto ret;
-		}
-	}
-
-	if(isfat(n->type)) {
-		if(n->type->width < 0)
-			fatal("forgot to compute width for %T", n->type);
-		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 OSPTR:
-	case OLEN:
-		if(isslice(n->left->type) || istype(n->left->type, TSTRING))
-			n->addable = n->left->addable;
-		break;
-	case OCAP:
-		if(isslice(n->left->type))
-			n->addable = n->left->addable;
-		break;
-	case OITAB:
-		n->addable = n->left->addable;
-		break;
-	}
-
-	// if both are addressable, move
-	if(n->addable && res->addable) {
-		if(is64(n->type) || is64(res->type) ||
-		   n->op == OREGISTER || res->op == OREGISTER ||
-		   iscomplex[n->type->etype] || iscomplex[res->type->etype]) {
-			gmove(n, res);
-		} else {
-			regalloc(&n1, n->type, N);
-			gmove(n, &n1);
-			cgen(&n1, res);
-			regfree(&n1);
-		}
-		goto ret;
-	}
-
-	// if both are not addressable, use a temporary.
-	if(!n->addable && !res->addable) {
-		// could use regalloc here sometimes,
-		// but have to check for ullman >= UINF.
-		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) {
-		igen(res, &n1, N);
-		cgen(n, &n1);
-		regfree(&n1);
-		return;
-	}
-
-	if(complexop(n, res)) {
-		complexgen(n, res);
-		return;
-	}
-
-	// if n is sudoaddable generate addr and move
-	if (!is64(n->type) && !is64(res->type) && !iscomplex[n->type->etype] && !iscomplex[res->type->etype]) {
-		a = optoas(OAS, n->type);
-		if(sudoaddable(a, n, &addr, &w)) {
-			if (res->op != OREGISTER) {
-				regalloc(&n2, res->type, N);
-				p1 = gins(a, N, &n2);
-				p1->from = addr;
-				if(debug['g'])
-					print("%P [ignore previous line]\n", p1);
-				gmove(&n2, res);
-				regfree(&n2);
-			} else {
-				p1 = gins(a, N, res);
-				p1->from = addr;
-				if(debug['g'])
-					print("%P [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 != N && nl->ullman >= UINF)
-	if(nr != N && nr->ullman >= UINF) {
-		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(is64(n->type) || is64(res->type) || n->left != N && is64(n->left->type)) {
-		switch(n->op) {
-		// math goes to cgen64.
-		case OMINUS:
-		case OCOM:
-		case OADD:
-		case OSUB:
-		case OMUL:
-		case OLROT:
-		case OLSH:
-		case ORSH:
-		case OAND:
-		case OOR:
-		case OXOR:
-			cgen64(n, res);
-			return;
-		}
-	}
-
-	if(nl != N && isfloat[n->type->etype] && isfloat[nl->type->etype])
-		goto flt;
-	switch(n->op) {
-	default:
-		dump("cgen", n);
-		fatal("cgen: unknown op %+hN", n);
-		break;
-
-	case OREAL:
-	case OIMAG:
-	case OCOMPLEX:
-		fatal("unexpected complex");
-		break;
-
-	// these call bgen to get a bool value
-	case OOROR:
-	case OANDAND:
-	case OEQ:
-	case ONE:
-	case OLT:
-	case OLE:
-	case OGE:
-	case OGT:
-	case ONOT:
-		p1 = gbranch(AB, T, 0);
-		p2 = pc;
-		gmove(nodbool(1), res);
-		p3 = gbranch(AB, T, 0);
-		patch(p1, pc);
-		bgen(n, 1, 0, p2);
-		gmove(nodbool(0), res);
-		patch(p3, pc);
-		goto ret;
-
-	case OPLUS:
-		cgen(nl, res);
-		goto ret;
-
-	// unary
-	case OCOM:
-		a = optoas(OXOR, nl->type);
-		regalloc(&n1, nl->type, N);
-		cgen(nl, &n1);
-		nodconst(&n2, nl->type, -1);
-		gins(a, &n2, &n1);
-		goto norm;
-
-	case OMINUS:
-		regalloc(&n1, nl->type, N);
-		cgen(nl, &n1);
-		nodconst(&n2, nl->type, 0);
-		gins(optoas(OMINUS, nl->type), &n2, &n1);
-		goto norm;
-
-	// symmetric binary
-	case OAND:
-	case OOR:
-	case OXOR:
-	case OADD:
-	case OMUL:
-		a = optoas(n->op, nl->type);
-		goto sbop;
-
-	// asymmetric binary
-	case OSUB:
-		a = optoas(n->op, nl->type);
-		goto abop;
-
-	case OHMUL:
-		cgen_hmul(nl, nr, res);
-		break;
-
-	case OLROT:
-	case OLSH:
-	case ORSH:
-		cgen_shift(n->op, n->bounded, nl, nr, res);
-		break;
-
-	case OCONV:
-		if(eqtype(n->type, nl->type) || noconv(n->type, nl->type)) {
-			cgen(nl, res);
-			break;
-		}
-		if(nl->addable && !is64(nl->type)) {
-			regalloc(&n1, nl->type, res);
-			gmove(nl, &n1);
-		} else {
-			if(n->type->width > 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 > widthptr || is64(n->type) || isfloat[n->type->etype])
-			tempname(&n2, n->type);
-		else
-			regalloc(&n2, n->type, N);
-		gmove(&n1, &n2);
-		gmove(&n2, res);
-		if(n1.op == OREGISTER)
-			regfree(&n1);
-		if(n2.op == OREGISTER)
-			regfree(&n2);
-		break;
-
-	case ODOT:
-	case ODOTPTR:
-	case OINDEX:
-	case OIND:
-	case ONAME:	// PHEAP or PPARAMREF var
-		igen(n, &n1, res);
-		gmove(&n1, res);
-		regfree(&n1);
-		break;
-
-	case OITAB:
-		// interface table is first word of interface value
-		igen(nl, &n1, res);
-		n1.type = n->type;
-		gmove(&n1, res);
-		regfree(&n1);
-		break;
-
-	case OSPTR:
-		// pointer is the first word of string or slice.
-		if(isconst(nl, CTSTR)) {
-			regalloc(&n1, types[tptr], res);
-			p1 = gins(AMOVW, N, &n1);
-			datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from);
-			gmove(&n1, res);
-			regfree(&n1);
-			break;
-		}
-		igen(nl, &n1, res);
-		n1.type = n->type;
-		gmove(&n1, res);
-		regfree(&n1);
-		break;
-
-	case OLEN:
-		if(istype(nl->type, TMAP) || istype(nl->type, TCHAN)) {
-			// map has len in the first 32-bit word.
-			// a zero pointer means zero length
-			regalloc(&n1, types[tptr], res);
-			cgen(nl, &n1);
-
-			nodconst(&n2, types[tptr], 0);
-			gcmp(optoas(OCMP, types[tptr]), &n1, &n2);
-			p1 = gbranch(optoas(OEQ, types[tptr]), T, -1);
-
-			n2 = n1;
-			n2.op = OINDREG;
-			n2.type = types[TINT32];
-			gmove(&n2, &n1);
-
-			patch(p1, pc);
-
-			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.
-			igen(nl, &n1, res);
-			n1.type = types[TUINT32];
-			n1.xoffset += Array_nel;
-			gmove(&n1, res);
-			regfree(&n1);
-			break;
-		}
-		fatal("cgen: OLEN: unknown type %lT", nl->type);
-		break;
-
-	case OCAP:
-		if(istype(nl->type, TCHAN)) {
-			// chan has cap in the second 32-bit word.
-			// a zero pointer means zero length
-			regalloc(&n1, types[tptr], res);
-			cgen(nl, &n1);
-
-			nodconst(&n2, types[tptr], 0);
-			gcmp(optoas(OCMP, types[tptr]), &n1, &n2);
-			p1 = gbranch(optoas(OEQ, types[tptr]), T, -1);
-
-			n2 = n1;
-			n2.op = OINDREG;
-			n2.xoffset = 4;
-			n2.type = types[TINT32];
-			gmove(&n2, &n1);
-
-			patch(p1, pc);
-
-			gmove(&n1, res);
-			regfree(&n1);
-			break;
-		}
-		if(isslice(nl->type)) {
-			igen(nl, &n1, res);
-			n1.type = types[TUINT32];
-			n1.xoffset += Array_cap;
-			gmove(&n1, res);
-			regfree(&n1);
-			break;
-		}
-		fatal("cgen: OCAP: unknown type %lT", nl->type);
-		break;
-
-	case OADDR:
-		agen(nl, res);
-		break;
-
-	case OCALLMETH:
-	case OCALLFUNC:
-		// Release res so that it is available for cgen_call.
-		// Pick it up again after the call.
-		rg = -1;
-		if(n->ullman >= UINF) {
-			if(res != N && (res->op == OREGISTER || res->op == OINDREG)) {
-				rg = res->val.u.reg;
-				reg[rg]--;
-			}
-		}
-		if(n->op == OCALLMETH)
-			cgen_callmeth(n, 0);
-		else
-			cgen_call(n, 0);
-		if(rg >= 0)
-			reg[rg]++;
-		cgen_callret(n, res);
-		break;
-
-	case OCALLINTER:
-		cgen_callinter(n, res, 0);
-		cgen_callret(n, res);
-		break;
-
-	case OMOD:
-	case ODIV:
-		a = optoas(n->op, nl->type);
-		goto abop;
-	}
-	goto ret;
-
-sbop:	// symmetric binary
-	if(nl->ullman < nr->ullman) {
-		r = nl;
-		nl = nr;
-		nr = r;
-	}
-
-abop:	// asymmetric binary
-	// TODO(kaib): use fewer registers here.
-	if(nl->ullman >= nr->ullman) {
-		regalloc(&n1, nl->type, res);
-		cgen(nl, &n1);
-		switch(n->op) {
-		case OADD:
-		case OSUB:
-		case OAND:
-		case OOR:
-		case OXOR:
-			if(smallintconst(nr)) {
-				n2 = *nr;
-				break;
-			}
-		default:
-			regalloc(&n2, nr->type, N);
-			cgen(nr, &n2);
-		}
-	} else {
-		switch(n->op) {
-		case OADD:
-		case OSUB:
-		case OAND:
-		case OOR:
-		case OXOR:
-			if(smallintconst(nr)) {
-				n2 = *nr;
-				break;
-			}
-		default:
-			regalloc(&n2, nr->type, res);
-			cgen(nr, &n2);
-		}
-		regalloc(&n1, nl->type, N);
-		cgen(nl, &n1);
-	}
-	gins(a, &n2, &n1);
-norm:
-	// Normalize result for types smaller than word.
-	if(n->type->width < widthptr) {
-		switch(n->op) {
-		case OADD:
-		case OSUB:
-		case OMUL:
-		case OCOM:
-		case OMINUS:
-			gins(optoas(OAS, n->type), &n1, &n1);
-			break;
-		}
-	}
-	gmove(&n1, res);
-	regfree(&n1);
-	if(n2.op != OLITERAL)
-		regfree(&n2);
-	goto ret;
-
-flt:	// floating-point.
-	regalloc(&f0, nl->type, res);
-	if(nr != N)
-		goto flt2;
-
-	if(n->op == OMINUS) {
-		nr = nodintconst(-1);
-		convlit(&nr, n->type);
-		n->op = OMUL;
-		goto flt2;
-	}
-
-	// unary
-	cgen(nl, &f0);
-	if(n->op != OCONV && n->op != OPLUS)
-		gins(optoas(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, N);
-		gmove(&f0, &f1);
-		cgen(nr, &f0);
-		gins(optoas(n->op, n->type), &f0, &f1);
-	} else {
-		cgen(nr, &f0);
-		regalloc(&f1, n->type, N);
-		cgen(nl, &f1);
-		gins(optoas(n->op, n->type), &f0, &f1);
-	}
-	gmove(&f1, res);
-	regfree(&f0);
-	regfree(&f1);
-	goto ret;
-
-ret:
-	;
-}
-
-/*
- * generate array index into res.
- * n might be any size; res is 32-bit.
- * returns Prog* to patch to panic call.
- */
-Prog*
-cgenindex(Node *n, Node *res, int bounded)
-{
-	Node tmp, lo, hi, zero, n1, n2;
-
-	if(!is64(n->type)) {
-		cgen(n, res);
-		return nil;
-	}
-
-	tempname(&tmp, types[TINT64]);
-	cgen(n, &tmp);
-	split64(&tmp, &lo, &hi);
-	gmove(&lo, res);
-	if(bounded) {
-		splitclean();
-		return nil;
-	}
-	regalloc(&n1, types[TINT32], N);
-	regalloc(&n2, types[TINT32], N);
-	nodconst(&zero, types[TINT32], 0);
-	gmove(&hi, &n1);
-	gmove(&zero, &n2);
-	gcmp(ACMP, &n1, &n2);
-	regfree(&n2);
-	regfree(&n1);
-	splitclean();
-	return gbranch(ABNE, T, -1);
-}
-
-/*
- * generate:
- *	res = &n;
- * The generated code checks that the result is not nil.
- */
-void
-agen(Node *n, Node *res)
-{
-	Node *nl;
-	Node n1, n2, n3;
-	int r;
-
-	if(debug['g']) {
-		dump("\nagen-res", res);
-		dump("agen-r", n);
-	}
-	if(n == N || n->type == T || res == N || res->type == T)
-		fatal("agen");
-
-	while(n->op == OCONVNOP)
-		n = n->left;
-
-	if(isconst(n, CTNIL) && n->type->width > 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.
-		tempname(&n1, n->type);
-		gvardef(&n1);
-		clearfat(&n1);
-		regalloc(&n2, types[tptr], res);
-		gins(AMOVW, &n1, &n2);
-		gmove(&n2, res);
-		regfree(&n2);
-		goto ret;
-	}
-		
-
-	if(n->addable) {
-		memset(&n1, 0, sizeof n1);
-		n1.op = OADDR;
-		n1.left = n;
-		regalloc(&n2, types[tptr], res);
-		gins(AMOVW, &n1, &n2);
-		gmove(&n2, res);
-		regfree(&n2);
-		goto ret;
-	}
-
-	nl = n->left;
-
-	switch(n->op) {
-	default:
-		fatal("agen: unknown op %+hN", n);
-		break;
-
-	case OCALLMETH:
-	case OCALLFUNC:
-		// Release res so that it is available for cgen_call.
-		// Pick it up again after the call.
-		r = -1;
-		if(n->ullman >= UINF) {
-			if(res->op == OREGISTER || res->op == OINDREG) {
-				r = res->val.u.reg;
-				reg[r]--;
-			}
-		}
-		if(n->op == OCALLMETH)
-			cgen_callmeth(n, 0);
-		else
-			cgen_call(n, 0);
-		if(r >= 0)
-			reg[r]++;
-		cgen_aret(n, res);
-		break;
-
-	case OCALLINTER:
-		cgen_callinter(n, res, 0);
-		cgen_aret(n, res);
-		break;
-
-	case OSLICE:
-	case OSLICEARR:
-	case OSLICESTR:
-	case OSLICE3:
-	case OSLICE3ARR:
-		tempname(&n1, n->type);
-		cgen_slice(n, &n1);
-		agen(&n1, res);
-		break;
-
-	case OEFACE:
-		tempname(&n1, n->type);
-		cgen_eface(n, &n1);
-		agen(&n1, res);
-		break;
-
-	case OINDEX:
-		agenr(n, &n1, res);
-		gmove(&n1, res);
-		regfree(&n1);
-		break;
-
-	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) && n->class != PPARAMREF) {
-			dump("bad agen", n);
-			fatal("agen: bad ONAME class %#x", n->class);
-		}
-		cgen(n->heapaddr, res);
-		if(n->xoffset != 0) {
-			nodconst(&n1, types[TINT32], n->xoffset);
-			regalloc(&n2, n1.type, N);
-			regalloc(&n3, types[TINT32], N);
-			gmove(&n1, &n2);
-			gmove(res, &n3);
-			gins(optoas(OADD, types[tptr]), &n2, &n3);
-			gmove(&n3, res);
-			regfree(&n2);
-			regfree(&n3);
-		}
-		break;
-
-	case OIND:
-		cgen(nl, res);
-		cgen_checknil(res);
-		break;
-
-	case ODOT:
-		agen(nl, res);
-		if(n->xoffset != 0) {
-			nodconst(&n1, types[TINT32], n->xoffset);
-			regalloc(&n2, n1.type, N);
-			regalloc(&n3, types[TINT32], N);
-			gmove(&n1, &n2);
-			gmove(res, &n3);
-			gins(optoas(OADD, types[tptr]), &n2, &n3);
-			gmove(&n3, res);
-			regfree(&n2);
-			regfree(&n3);
-		}
-		break;
-
-	case ODOTPTR:
-		cgen(nl, res);
-		cgen_checknil(res);
-		if(n->xoffset != 0) {
-			nodconst(&n1, types[TINT32], n->xoffset);
-			regalloc(&n2, n1.type, N);
-			regalloc(&n3, types[tptr], N);
-			gmove(&n1, &n2);
-			gmove(res, &n3);
-			gins(optoas(OADD, types[tptr]), &n2, &n3);
-			gmove(&n3, res);
-			regfree(&n2);
-			regfree(&n3);
-		}
-		break;
-	}
-
-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.
- */
-void
-igen(Node *n, Node *a, Node *res)
-{
-	Node n1;
-	int r;
-
-	if(debug['g']) {
-		dump("\nigen-n", n);
-	}
-	switch(n->op) {
-	case ONAME:
-		if((n->class&PHEAP) || 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 != REGSP)
-			reg[n->val.u.reg]++;
-		*a = *n;
-		return;
-
-	case ODOT:
-		igen(n->left, a, res);
-		a->xoffset += n->xoffset;
-		a->type = n->type;
-		return;
-
-	case ODOTPTR:
-		if(n->left->addable
-			|| n->left->op == OCALLFUNC
-			|| n->left->op == OCALLMETH
-			|| n->left->op == OCALLINTER) {
-			// igen-able nodes.
-			igen(n->left, &n1, res);
-			regalloc(a, types[tptr], &n1);
-			gmove(&n1, a);
-			regfree(&n1);
-		} else {
-			regalloc(a, types[tptr], res);
-			cgen(n->left, a);
-		}
-		cgen_checknil(a);
-		a->op = OINDREG;
-		a->xoffset = n->xoffset;
-		a->type = n->type;
-		return;
-
-	case OCALLMETH:
-	case OCALLFUNC:
-	case OCALLINTER:
-		// Release res so that it is available for cgen_call.
-		// Pick it up again after the call.
-		r = -1;
-		if(n->ullman >= UINF) {
-			if(res != N && (res->op == OREGISTER || res->op == OINDREG)) {
-				r = res->val.u.reg;
-				reg[r]--;
-			}
-		}
-		switch(n->op) {
-		case OCALLMETH:
-			cgen_callmeth(n, 0);
-			break;
-		case OCALLFUNC:
-			cgen_call(n, 0);
-			break;
-		case OCALLINTER:
-			cgen_callinter(n, N, 0);
-			break;
-		}
-		if(r >= 0)
-			reg[r]++;
-		regalloc(a, types[tptr], res);
-		cgen_aret(n, a);
-		a->op = OINDREG;
-		a->type = n->type;
-		return;
-	}
-
-	agenr(n, a, res);
-	a->op = OINDREG;
-	a->type = n->type;
-}
-
-/*
- * allocate a register in res and generate
- *  newreg = &n
- * The caller must call regfree(a).
- */
-void
-cgenr(Node *n, Node *a, Node *res)
-{
-	Node n1;
-
-	if(debug['g'])
-		dump("cgenr-n", n);
-
-	if(isfat(n->type))
-		fatal("cgenr on fat node");
-
-	if(n->addable) {
-		regalloc(a, types[tptr], res);
-		gmove(n, a);
-		return;
-	}
-
-	switch(n->op) {
-	case ONAME:
-	case ODOT:
-	case ODOTPTR:
-	case OINDEX:
-	case OCALLFUNC:
-	case OCALLMETH:
-	case OCALLINTER:
-		igen(n, &n1, res);
-		regalloc(a, types[tptr], &n1);
-		gmove(&n1, a);
-		regfree(&n1);
-		break;
-	default:
-		regalloc(a, n->type, res);
-		cgen(n, a);
-		break;
-	}
-}
-
-/*
- * generate:
- *	newreg = &n;
- *
- * caller must regfree(a).
- * The generated code checks that the result is not nil.
- */
-void
-agenr(Node *n, Node *a, Node *res)
-{
-	Node *nl, *nr;
-	Node n1, n2, n3, n4, tmp;
-	Prog *p1, *p2;
-	uint32 w;
-	uint64 v;
-	int bounded;
-
-	if(debug['g'])
-		dump("agenr-n", n);
-
-	nl = n->left;
-	nr = n->right;
-
-	switch(n->op) {
-	case ODOT:
-	case ODOTPTR:
-	case OCALLFUNC:
-	case OCALLMETH:
-	case OCALLINTER:
-		igen(n, &n1, res);
-		regalloc(a, types[tptr], &n1);
-		agen(&n1, a);
-		regfree(&n1);
-		break;
-
-	case OIND:
-		cgenr(n->left, a, res);
-		cgen_checknil(a);
-		break;
-
-	case OINDEX:
-		p2 = nil;  // to be patched to panicindex.
-		w = n->type->width;
-		bounded = debug['B'] || n->bounded;
-		if(nr->addable) {
-			if(!isconst(nr, CTINT))
-				tempname(&tmp, types[TINT32]);
-			if(!isconst(nl, CTSTR))
-				agenr(nl, &n3, res);
-			if(!isconst(nr, CTINT)) {
-				p2 = cgenindex(nr, &tmp, bounded);
-				regalloc(&n1, tmp.type, N);
-				gmove(&tmp, &n1);
-			}
-		} else
-		if(nl->addable) {
-			if(!isconst(nr, CTINT)) {
-				tempname(&tmp, types[TINT32]);
-				p2 = cgenindex(nr, &tmp, bounded);
-				regalloc(&n1, tmp.type, N);
-				gmove(&tmp, &n1);
-			}
-			if(!isconst(nl, CTSTR)) {
-				agenr(nl, &n3, res);
-			}
-		} else {
-			tempname(&tmp, types[TINT32]);
-			p2 = cgenindex(nr, &tmp, bounded);
-			nr = &tmp;
-			if(!isconst(nl, CTSTR))
-				agenr(nl, &n3, res);
-			regalloc(&n1, tmp.type, N);
-			gins(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 = mpgetfix(nr->val.u.xval);
-			if(isslice(nl->type) || nl->type->etype == TSTRING) {
-				if(!debug['B'] && !n->bounded) {
-					n1 = n3;
-					n1.op = OINDREG;
-					n1.type = types[tptr];
-					n1.xoffset = Array_nel;
-					regalloc(&n4, n1.type, N);
-					gmove(&n1, &n4);
-					nodconst(&n2, types[TUINT32], v);
-					gcmp(optoas(OCMP, types[TUINT32]), &n4, &n2);
-					regfree(&n4);
-					p1 = gbranch(optoas(OGT, types[TUINT32]), T, +1);
-					ginscall(panicindex, 0);
-					patch(p1, pc);
-				}
-
-				n1 = n3;
-				n1.op = OINDREG;
-				n1.type = types[tptr];
-				n1.xoffset = Array_array;
-				gmove(&n1, &n3);
-			}
-
-			nodconst(&n2, types[tptr], v*w);
-			gins(optoas(OADD, types[tptr]), &n2, &n3);
-			*a = n3;
-			break;
-		}
-
-		regalloc(&n2, types[TINT32], &n1);			// i
-		gmove(&n1, &n2);
-		regfree(&n1);
-
-		if(!debug['B'] && !n->bounded) {
-			// check bounds
-			if(isconst(nl, CTSTR)) {
-				nodconst(&n4, types[TUINT32], nl->val.u.sval->len);
-			} else if(isslice(nl->type) || nl->type->etype == TSTRING) {
-				n1 = n3;
-				n1.op = OINDREG;
-				n1.type = types[tptr];
-				n1.xoffset = Array_nel;
-				regalloc(&n4, types[TUINT32], N);
-				gmove(&n1, &n4);
-			} else {
-				nodconst(&n4, types[TUINT32], nl->type->bound);
-			}
-			gcmp(optoas(OCMP, types[TUINT32]), &n2, &n4);
-			if(n4.op == OREGISTER)
-				regfree(&n4);
-			p1 = gbranch(optoas(OLT, types[TUINT32]), T, +1);
-			if(p2)
-				patch(p2, pc);
-			ginscall(panicindex, 0);
-			patch(p1, pc);
-		}
-		
-		if(isconst(nl, CTSTR)) {
-			regalloc(&n3, types[tptr], res);
-			p1 = gins(AMOVW, N, &n3);
-			datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from);
-			p1->from.type = D_CONST;
-		} else
-		if(isslice(nl->type) || nl->type->etype == TSTRING) {
-			n1 = n3;
-			n1.op = OINDREG;
-			n1.type = types[tptr];
-			n1.xoffset = Array_array;
-			gmove(&n1, &n3);
-		}
-
-		if(w == 0) {
-			// nothing to do
-		} else if(w == 1 || w == 2 || w == 4 || w == 8) {
-			memset(&n4, 0, sizeof n4);
-			n4.op = OADDR;
-			n4.left = &n2;
-			cgen(&n4, &n3);
-			if (w == 1)
-				gins(AADD, &n2, &n3);
-			else if(w == 2)
-				gshift(AADD, &n2, SHIFT_LL, 1, &n3);
-			else if(w == 4)
-				gshift(AADD, &n2, SHIFT_LL, 2, &n3);
-			else if(w == 8)
-				gshift(AADD, &n2, SHIFT_LL, 3, &n3);
-		} else {
-			regalloc(&n4, types[TUINT32], N);
-			nodconst(&n1, types[TUINT32], w);
-			gmove(&n1, &n4);
-			gins(optoas(OMUL, types[TUINT32]), &n4, &n2);
-			gins(optoas(OADD, types[tptr]), &n2, &n3);
-			regfree(&n4);
-		}
-
-		*a = n3;
-		regfree(&n2);
-		break;
-
-	default:
-		regalloc(a, types[tptr], res);
-		agen(n, a);
-		break;
-	}
-}
-
-void
-gencmp0(Node *n, Type *t, int o, int likely, Prog *to)
-{
-	Node n1, n2, n3;
-	int a;
-
-	regalloc(&n1, t, N);
-	cgen(n, &n1);
-	a = optoas(OCMP, t);
-	if(a != ACMP) {
-		nodconst(&n2, t, 0);
-		regalloc(&n3, t, N);
-		gmove(&n2, &n3);
-		gcmp(a, &n1, &n3);
-		regfree(&n3);
-	} else
-		gins(ATST, &n1, N);
-	a = optoas(o, t);
-	patch(gbranch(a, t, likely), to);
-	regfree(&n1);
-}
-
-/*
- * generate:
- *	if(n == true) goto to;
- */
-void
-bgen(Node *n, int true, int likely, Prog *to)
-{
-	int et, a;
-	Node *nl, *nr, *r;
-	Node n1, n2, n3, tmp;
-	NodeList *ll;
-	Prog *p1, *p2;
-
-	if(debug['g']) {
-		dump("\nbgen", n);
-	}
-
-	if(n == N)
-		n = nodbool(1);
-
-	if(n->ninit != nil)
-		genlist(n->ninit);
-
-	if(n->type == T) {
-		convlit(&n, types[TBOOL]);
-		if(n->type == T)
-			goto ret;
-	}
-
-	et = n->type->etype;
-	if(et != TBOOL) {
-		yyerror("cgen: bad type %T for %O", n->type, n->op);
-		patch(gins(AEND, N, N), to);
-		goto ret;
-	}
-	nr = N;
-
-	switch(n->op) {
-	default:
-		a = ONE;
-		if(!true)
-			a = OEQ;
-		gencmp0(n, n->type, a, likely, to);
-		goto ret;
-
-	case OLITERAL:
-		// need to ask if it is bool?
-		if(!true == !n->val.u.bval)
-			patch(gbranch(AB, T, 0), to);
-		goto ret;
-
-	case OANDAND:
-		if(!true)
-			goto caseor;
-
-	caseand:
-		p1 = gbranch(AB, T, 0);
-		p2 = gbranch(AB, T, 0);
-		patch(p1, pc);
-		bgen(n->left, !true, -likely, p2);
-		bgen(n->right, !true, -likely, p2);
-		p1 = gbranch(AB, T, 0);
-		patch(p1, to);
-		patch(p2, pc);
-		goto ret;
-
-	case OOROR:
-		if(!true)
-			goto caseand;
-
-	caseor:
-		bgen(n->left, true, likely, to);
-		bgen(n->right, true, likely, to);
-		goto ret;
-
-	case OEQ:
-	case ONE:
-	case OLT:
-	case OGT:
-	case OLE:
-	case OGE:
-		nr = n->right;
-		if(nr == N || nr->type == T)
-			goto ret;
-
-	case ONOT:	// unary
-		nl = n->left;
-		if(nl == N || nl->type == T)
-			goto ret;
-	}
-
-	switch(n->op) {
-
-	case ONOT:
-		bgen(nl, !true, likely, to);
-		goto ret;
-
-	case OEQ:
-	case ONE:
-	case OLT:
-	case OGT:
-	case OLE:
-	case OGE:
-		a = n->op;
-		if(!true) {
-			if(isfloat[nl->type->etype]) {
-				// brcom is not valid on floats when NaN is involved.
-				p1 = gbranch(AB, T, 0);
-				p2 = gbranch(AB, T, 0);
-				patch(p1, pc);
-				ll = n->ninit;
-				n->ninit = nil;
-				bgen(n, 1, -likely, p2);
-				n->ninit = ll;
-				patch(gbranch(AB, T, 0), to);
-				patch(p2, pc);
-				goto ret;
-			}				
-			a = brcom(a);
-			true = !true;
-		}
-
-		// make simplest on right
-		if(nl->op == OLITERAL || (nl->ullman < UINF && nl->ullman < nr->ullman)) {
-			a = brrev(a);
-			r = nl;
-			nl = nr;
-			nr = r;
-		}
-
-		if(isslice(nl->type)) {
-			// only valid to cmp darray to literal nil
-			if((a != OEQ && a != ONE) || nr->op != OLITERAL) {
-				yyerror("illegal array comparison");
-				break;
-			}
-
-			igen(nl, &n1, N);
-			n1.xoffset += Array_array;
-			n1.type = types[tptr];
-			gencmp0(&n1, types[tptr], a, likely, to);
-			regfree(&n1);
-			break;
-		}
-
-		if(isinter(nl->type)) {
-			// front end shold only leave cmp to literal nil
-			if((a != OEQ && a != ONE) || nr->op != OLITERAL) {
-				yyerror("illegal interface comparison");
-				break;
-			}
-
-			igen(nl, &n1, N);
-			n1.type = types[tptr];
-			n1.xoffset += 0;
-			gencmp0(&n1, types[tptr], a, likely, to);
-			regfree(&n1);
-			break;
-		}
-
-		if(iscomplex[nl->type->etype]) {
-			complexbool(a, nl, nr, true, likely, to);
-			break;
-		}
-
-		if(is64(nr->type)) {
-			if(!nl->addable) {
-				tempname(&n1, nl->type);
-				cgen(nl, &n1);
-				nl = &n1;
-			}
-			if(!nr->addable) {
-				tempname(&n2, nr->type);
-				cgen(nr, &n2);
-				nr = &n2;
-			}
-			cmp64(nl, nr, a, likely, to);
-			break;
-		}
-
-		if(nr->op == OLITERAL) {
-			if(isconst(nr, CTINT) &&  mpgetfix(nr->val.u.xval) == 0) {
-				gencmp0(nl, nl->type, a, likely, to);
-				break;
-			}
-			if(nr->val.ctype == CTNIL) {
-				gencmp0(nl, nl->type, a, likely, to);
-				break;
-			}
-		}
-
-		a = optoas(a, nr->type);
-
-		if(nr->ullman >= UINF) {
-			regalloc(&n1, nl->type, N);
-			cgen(nl, &n1);
-
-			tempname(&tmp, nl->type);
-			gmove(&n1, &tmp);
-			regfree(&n1);
-
-			regalloc(&n2, nr->type, N);
-			cgen(nr, &n2);
-
-			regalloc(&n1, nl->type, N);
-			cgen(&tmp, &n1);
-
-			gcmp(optoas(OCMP, nr->type), &n1, &n2);
-			patch(gbranch(a, nr->type, likely), to);
-
-			regfree(&n1);
-			regfree(&n2);
-			break;
-		}
-
-		tempname(&n3, nl->type);
-		cgen(nl, &n3);
-
-		tempname(&tmp, nr->type);
-		cgen(nr, &tmp);
-
-		regalloc(&n1, nl->type, N);
-		gmove(&n3, &n1);
-
-		regalloc(&n2, nr->type, N);
-		gmove(&tmp, &n2);
-
-		gcmp(optoas(OCMP, nr->type), &n1, &n2);
-		if(isfloat[nl->type->etype]) {
-			if(n->op == ONE) {
-				p1 = gbranch(ABVS, nr->type, likely);
-				patch(gbranch(a, nr->type, likely), to);
-				patch(p1, to);
-			} else {
-				p1 = gbranch(ABVS, nr->type, -likely);
-				patch(gbranch(a, nr->type, likely), to);
-				patch(p1, pc);
-			}
-		} else {
-			patch(gbranch(a, nr->type, likely), to);
-		}
-		regfree(&n1);
-		regfree(&n2);
-		break;
-	}
-	goto ret;
-
-ret:
-	;
-}
-
-/*
- * n is on stack, either local variable
- * or return value from function call.
- * return n's offset from SP.
- */
-int32
-stkof(Node *n)
-{
-	Type *t;
-	Iter flist;
-	int32 off;
-
-	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:
-	case OCALLINTER:
-	case OCALLFUNC:
-		t = n->left->type;
-		if(isptr[t->etype])
-			t = t->type;
-
-		t = structfirst(&flist, getoutarg(t));
-		if(t != T)
-			return t->width + 4;	// correct for LR
-		break;
-	}
-
-	// 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
- */
-void
-sgen(Node *n, Node *res, int64 w)
-{
-	Node dst, src, tmp, nend, r0, r1, r2, *f;
-	int32 c, odst, osrc;
-	int dir, align, op;
-	Prog *p, *ploop;
-	NodeList *l;
-
-	if(debug['g']) {
-		print("\nsgen w=%lld\n", w);
-		dump("r", n);
-		dump("res", res);
-	}
-
-	if(n->ullman >= UINF && res->ullman >= UINF)
-		fatal("sgen UINF");
-
-	if(w < 0 || (int32)w != w)
-		fatal("sgen copy %lld", w);
-
-	if(n->type == T)
-		fatal("sgen: missing type");
-
-	if(w == 0) {
-		// evaluate side effects only.
-		regalloc(&dst, types[tptr], N);
-		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 == ONAME && strcmp(res->sym->name, ".args") == 0)
-		for(l = curfn->dcl; l != nil; l = l->next)
-			if(l->n->class == PPARAMOUT)
-				gvardef(l->n);
-
-	// Avoid taking the address for simple enough types.
-	if(componentgen(n, res))
-		return;
-	
-	// 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 = n->type->align;
-	switch(align) {
-	default:
-		fatal("sgen: invalid alignment %d for %T", align, n->type);
-	case 1:
-		op = AMOVB;
-		break;
-	case 2:
-		op = AMOVH;
-		break;
-	case 4:
-		op = AMOVW;
-		break;
-	}
-	if(w%align)
-		fatal("sgen: unaligned size %lld (align=%d) for %T", w, align, n->type);
-	c = w / 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.
-		tempname(&tmp, n->type);
-		sgen(n, &tmp, w);
-		sgen(&tmp, res, w);
-		return;
-	}
-	if(osrc%align != 0 || odst%align != 0)
-		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 && odst < osrc+w)
-		dir = -dir;
-
-	if(op == AMOVW && !nacl && dir > 0 && c >= 4 && c <= 128) {
-		r0.op = OREGISTER;
-		r0.val.u.reg = REGALLOC_R0;
-		r1.op = OREGISTER;
-		r1.val.u.reg = REGALLOC_R0 + 1;
-		r2.op = OREGISTER;
-		r2.val.u.reg = REGALLOC_R0 + 2;
-
-		regalloc(&src, types[tptr], &r1);
-		regalloc(&dst, types[tptr], &r2);
-		if(n->ullman >= res->ullman) {
-			// eval n first
-			agen(n, &src);
-			if(res->op == ONAME)
-				gvardef(res);
-			agen(res, &dst);
-		} else {
-			// eval res first
-			if(res->op == ONAME)
-				gvardef(res);
-			agen(res, &dst);
-			agen(n, &src);
-		}
-		regalloc(&tmp, types[tptr], &r0);
-		f = sysfunc("duffcopy");
-		p = gins(ADUFFCOPY, N, f);
-		afunclit(&p->to, f);
-		// 8 and 128 = magic constants: see ../../runtime/asm_arm.s
-		p->to.offset = 8*(128-c);
-
-		regfree(&tmp);
-		regfree(&src);
-		regfree(&dst);
-		return;
-	}
-	
-	if(n->ullman >= res->ullman) {
-		agenr(n, &dst, res);	// temporarily use dst
-		regalloc(&src, types[tptr], N);
-		gins(AMOVW, &dst, &src);
-		if(res->op == ONAME)
-			gvardef(res);
-		agen(res, &dst);
-	} else {
-		if(res->op == ONAME)
-			gvardef(res);
-		agenr(res, &dst, res);
-		agenr(n, &src, N);
-	}
-
-	regalloc(&tmp, types[TUINT32], N);
-
-	// set up end marker
-	memset(&nend, 0, sizeof nend);
-	if(c >= 4) {
-		regalloc(&nend, types[TUINT32], N);
-
-		p = gins(AMOVW, &src, &nend);
-		p->from.type = D_CONST;
-		if(dir < 0)
-			p->from.offset = dir;
-		else
-			p->from.offset = w;
-	}
-
-	// move src and dest to the end of block if necessary
-	if(dir < 0) {
-		p = gins(AMOVW, &src, &src);
-		p->from.type = D_CONST;
-		p->from.offset = w + dir;
-
-		p = gins(AMOVW, &dst, &dst);
-		p->from.type = D_CONST;
-		p->from.offset = w + dir;
-	}
-	
-	// move
-	if(c >= 4) {
-		p = gins(op, &src, &tmp);
-		p->from.type = D_OREG;
-		p->from.offset = dir;
-		p->scond |= C_PBIT;
-		ploop = p;
-
-		p = gins(op, &tmp, &dst);
-		p->to.type = D_OREG;
-		p->to.offset = dir;
-		p->scond |= C_PBIT;
-
-		p = gins(ACMP, &src, N);
-		raddr(&nend, p);
-
-		patch(gbranch(ABNE, T, 0), ploop);
- 		regfree(&nend);
-	} else {
-		while(c-- > 0) {
-			p = gins(op, &src, &tmp);
-			p->from.type = D_OREG;
-			p->from.offset = dir;
-			p->scond |= C_PBIT;
-	
-			p = gins(op, &tmp, &dst);
-			p->to.type = D_OREG;
-			p->to.offset = dir;
-			p->scond |= C_PBIT;
-		}
-	}
-
-	regfree(&dst);
-	regfree(&src);
-	regfree(&tmp);
-}
-
-static int
-cadable(Node *n)
-{
-	if(!n->addable) {
-		// dont know how it happens,
-		// but it does
-		return 0;
-	}
-
-	switch(n->op) {
-	case ONAME:
-		return 1;
-	}
-	return 0;
-}
-
-/*
- * copy a composite value by moving its individual components.
- * Slices, strings and interfaces are supported.
- * nr is N when assigning a zero value.
- * return 1 if can do, 0 if cant.
- */
-int
-componentgen(Node *nr, Node *nl)
-{
-	Node nodl, nodr, tmp;
-	Type *t;
-	int freel, freer;
-	vlong fldcount;
-	vlong loffset, roffset;
-
-	freel = 0;
-	freer = 0;
-
-	switch(nl->type->etype) {
-	default:
-		goto no;
-
-	case TARRAY:
-		t = nl->type;
-
-		// Slices are ok.
-		if(isslice(t))
-			break;
-		// Small arrays are ok.
-		if(t->bound > 0 && t->bound <= 3 && !isfat(t->type))
-			break;
-
-		goto no;
-
-	case TSTRUCT:
-		// Small structs with non-fat types are ok.
-		// Zero-sized structs are treated separately elsewhere.
-		fldcount = 0;
-		for(t=nl->type->type; t; t=t->down) {
-			if(isfat(t->type))
-				goto no;
-			if(t->etype != TFIELD)
-				fatal("componentgen: not a TFIELD: %lT", t);
-			fldcount++;
-		}
-		if(fldcount == 0 || fldcount > 4)
-			goto no;
-
-		break;
-
-	case TSTRING:
-	case TINTER:
-		break;
-	}
-
-	nodl = *nl;
-	if(!cadable(nl)) {
-		if(nr == N || !cadable(nr))
-			goto no;
-		igen(nl, &nodl, N);
-		freel = 1;
-	}
-
-	if(nr != N) {
-		nodr = *nr;
-		if(!cadable(nr)) {
-			igen(nr, &nodr, N);
-			freer = 1;
-		}
-	} else {
-		// When zeroing, prepare a register containing zero.
-		nodconst(&tmp, nl->type, 0);
-		regalloc(&nodr, types[TUINT], N);
-		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 != N && nl->op == ONAME && nr->op == ONAME && nl == nr)
-		goto yes;
-
-	switch(nl->type->etype) {
-	case TARRAY:
-		// componentgen for arrays.
-		if(nl->op == ONAME)
-			gvardef(nl);
-		t = nl->type;
-		if(!isslice(t)) {
-			nodl.type = t->type;
-			nodr.type = nodl.type;
-			for(fldcount=0; fldcount < t->bound; fldcount++) {
-				if(nr == N)
-					clearslim(&nodl);
-				else
-					gmove(&nodr, &nodl);
-				nodl.xoffset += t->type->width;
-				nodr.xoffset += t->type->width;
-			}
-			goto yes;
-		}
-
-		// componentgen for slices.
-		nodl.xoffset += Array_array;
-		nodl.type = ptrto(nl->type->type);
-
-		if(nr != N) {
-			nodr.xoffset += Array_array;
-			nodr.type = nodl.type;
-		}
-		gmove(&nodr, &nodl);
-
-		nodl.xoffset += Array_nel-Array_array;
-		nodl.type = types[simtype[TUINT]];
-
-		if(nr != N) {
-			nodr.xoffset += Array_nel-Array_array;
-			nodr.type = nodl.type;
-		}
-		gmove(&nodr, &nodl);
-
-		nodl.xoffset += Array_cap-Array_nel;
-		nodl.type = types[simtype[TUINT]];
-
-		if(nr != N) {
-			nodr.xoffset += Array_cap-Array_nel;
-			nodr.type = nodl.type;
-		}
-		gmove(&nodr, &nodl);
-
-		goto yes;
-
-	case TSTRING:
-		if(nl->op == ONAME)
-			gvardef(nl);
-		nodl.xoffset += Array_array;
-		nodl.type = ptrto(types[TUINT8]);
-
-		if(nr != N) {
-			nodr.xoffset += Array_array;
-			nodr.type = nodl.type;
-		}
-		gmove(&nodr, &nodl);
-
-		nodl.xoffset += Array_nel-Array_array;
-		nodl.type = types[simtype[TUINT]];
-
-		if(nr != N) {
-			nodr.xoffset += Array_nel-Array_array;
-			nodr.type = nodl.type;
-		}
-		gmove(&nodr, &nodl);
-
-		goto yes;
-
-	case TINTER:
-		if(nl->op == ONAME)
-			gvardef(nl);
-		nodl.xoffset += Array_array;
-		nodl.type = ptrto(types[TUINT8]);
-
-		if(nr != N) {
-			nodr.xoffset += Array_array;
-			nodr.type = nodl.type;
-		}
-		gmove(&nodr, &nodl);
-
-		nodl.xoffset += Array_nel-Array_array;
-		nodl.type = ptrto(types[TUINT8]);
-
-		if(nr != N) {
-			nodr.xoffset += Array_nel-Array_array;
-			nodr.type = nodl.type;
-		}
-		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 && nl->type->type)
-			loffset -= nl->type->type->width;
-		if(nr != N && nr->type->etype == TSTRUCT && nr->type->funarg && nr->type->type)
-			roffset -= nr->type->type->width;
-
-		for(t=nl->type->type; t; t=t->down) {
-			nodl.xoffset = loffset + t->width;
-			nodl.type = t->type;
-
-			if(nr == N)
-				clearslim(&nodl);
-			else {
-				nodr.xoffset = roffset + t->width;
-				nodr.type = nodl.type;
-				gmove(&nodr, &nodl);
-			}
-		}
-		goto yes;
-	}
-
-no:
-	if(freer)
-		regfree(&nodr);
-	if(freel)
-		regfree(&nodl);
-	return 0;
-
-yes:
-	if(freer)
-		regfree(&nodr);
-	if(freel)
-		regfree(&nodl);
-	return 1;
-}
diff --git a/src/cmd/5g/cgen64.c b/src/cmd/5g/cgen64.c
deleted file mode 100644
index ef11e2a..0000000
--- a/src/cmd/5g/cgen64.c
+++ /dev/null
@@ -1,760 +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 <u.h>
-#include <libc.h>
-#include "gg.h"
-
-/*
- * attempt to generate 64-bit
- *	res = n
- * return 1 on success, 0 if op not handled.
- */
-void
-cgen64(Node *n, Node *res)
-{
-	Node t1, t2, *l, *r;
-	Node lo1, lo2, hi1, hi2;
-	Node al, ah, bl, bh, cl, ch, s, n1, creg;
-	Prog *p1, *p2, *p3, *p4, *p5, *p6;
-
-	uint64 v;
-
-	if(res->op != OINDREG && res->op != ONAME) {
-		dump("n", n);
-		dump("res", res);
-		fatal("cgen64 %O of %O", n->op, res->op);
-	}
-
-	l = n->left;
-	if(!l->addable) {
-		tempname(&t1, l->type);
-		cgen(l, &t1);
-		l = &t1;
-	}
-
-	split64(l, &lo1, &hi1);
-	switch(n->op) {
-	default:
-		fatal("cgen64 %O", n->op);
-
-	case OMINUS:
-		split64(res, &lo2, &hi2);
-
-		regalloc(&t1, lo1.type, N);
-		regalloc(&al, lo1.type, N);
-		regalloc(&ah, hi1.type, N);
-
-		gins(AMOVW, &lo1, &al);
-		gins(AMOVW, &hi1, &ah);
-
-		gmove(ncon(0), &t1);
-		p1 = gins(ASUB, &al, &t1);
-		p1->scond |= C_SBIT;
-		gins(AMOVW, &t1, &lo2);
-
-		gmove(ncon(0), &t1);
-		gins(ASBC, &ah, &t1);
-		gins(AMOVW, &t1, &hi2);
-
-		regfree(&t1);
-		regfree(&al);
-		regfree(&ah);
-		splitclean();
-		splitclean();
-		return;
-
-	case OCOM:
-		regalloc(&t1, lo1.type, N);
-		gmove(ncon(-1), &t1);
-
-		split64(res, &lo2, &hi2);
-		regalloc(&n1, lo1.type, N);
-
-		gins(AMOVW, &lo1, &n1);
-		gins(AEOR, &t1, &n1);
-		gins(AMOVW, &n1, &lo2);
-
-		gins(AMOVW, &hi1, &n1);
-		gins(AEOR, &t1, &n1);
-		gins(AMOVW, &n1, &hi2);
-
-		regfree(&t1);
-		regfree(&n1);
-		splitclean();
-		splitclean();
-		return;
-
-	case OADD:
-	case OSUB:
-	case OMUL:
-	case OLSH:
-	case ORSH:
-	case OAND:
-	case OOR:
-	case OXOR:
-	case OLROT:
-		// binary operators.
-		// common setup below.
-		break;
-	}
-
-	// setup for binary operators
-	r = n->right;
-	if(r != N && !r->addable) {
-		tempname(&t2, r->type);
-		cgen(r, &t2);
-		r = &t2;
-	}
-	if(is64(r->type))
-		split64(r, &lo2, &hi2);
-
-	regalloc(&al, lo1.type, N);
-	regalloc(&ah, hi1.type, N);
-
-	// Do op.  Leave result in ah:al.
-	switch(n->op) {
-	default:
-		fatal("cgen64: not implemented: %N\n", n);
-
-	case OADD:
-		// TODO: Constants
-		regalloc(&bl, types[TPTR32], N);
-		regalloc(&bh, types[TPTR32], N);
-		gins(AMOVW, &hi1, &ah);
-		gins(AMOVW, &lo1, &al);
-		gins(AMOVW, &hi2, &bh);
-		gins(AMOVW, &lo2, &bl);
-		p1 = gins(AADD, &bl, &al);
-		p1->scond |= C_SBIT;
-		gins(AADC, &bh, &ah);
-		regfree(&bl);
-		regfree(&bh);
-		break;
-
-	case OSUB:
-		// TODO: Constants.
-		regalloc(&bl, types[TPTR32], N);
-		regalloc(&bh, types[TPTR32], N);
-		gins(AMOVW, &lo1, &al);
-		gins(AMOVW, &hi1, &ah);
-		gins(AMOVW, &lo2, &bl);
-		gins(AMOVW, &hi2, &bh);
-		p1 = gins(ASUB, &bl, &al);
-		p1->scond |= C_SBIT;
-		gins(ASBC, &bh, &ah);
-		regfree(&bl);
-		regfree(&bh);
-		break;
-
-	case OMUL:
-		// TODO(kaib): this can be done with 4 regs and does not need 6
-		regalloc(&bl, types[TPTR32], N);
-		regalloc(&bh, types[TPTR32], N);
-		regalloc(&cl, types[TPTR32], N);
-		regalloc(&ch, types[TPTR32], N);
-
-		// load args into bh:bl and bh:bl.
-		gins(AMOVW, &hi1, &bh);
-		gins(AMOVW, &lo1, &bl);
-		gins(AMOVW, &hi2, &ch);
-		gins(AMOVW, &lo2, &cl);
-
-		// bl * cl -> ah al
-		p1 = gins(AMULLU, N, N);
-		p1->from.type = D_REG;
-		p1->from.reg = bl.val.u.reg;
-		p1->reg = cl.val.u.reg;
-		p1->to.type = D_REGREG;
-		p1->to.reg = ah.val.u.reg;
-		p1->to.offset = al.val.u.reg;
-//print("%P\n", p1);
-
-		// bl * ch + ah -> ah
-		p1 = gins(AMULA, N, N);
-		p1->from.type = D_REG;
-		p1->from.reg = bl.val.u.reg;
-		p1->reg = ch.val.u.reg;
-		p1->to.type = D_REGREG2;
-		p1->to.reg = ah.val.u.reg;
-		p1->to.offset = ah.val.u.reg;
-//print("%P\n", p1);
-
-		// bh * cl + ah -> ah
-		p1 = gins(AMULA, N, N);
-		p1->from.type = D_REG;
-		p1->from.reg = bh.val.u.reg;
-		p1->reg = cl.val.u.reg;
-		p1->to.type = D_REGREG2;
-		p1->to.reg = ah.val.u.reg;
-		p1->to.offset = ah.val.u.reg;
-//print("%P\n", p1);
-
-		regfree(&bh);
-		regfree(&bl);
-		regfree(&ch);
-		regfree(&cl);
-
-		break;
-
-	case OLROT:
-		// We only rotate by a constant c in [0,64).
-		// if c >= 32:
-		//	lo, hi = hi, lo
-		//	c -= 32
-		// if c == 0:
-		//	no-op
-		// else:
-		//	t = hi
-		//	shld hi:lo, c
-		//	shld lo:t, c
-		v = mpgetfix(r->val.u.xval);
-		regalloc(&bl, lo1.type, N);
-		regalloc(&bh, hi1.type, N);
-		if(v >= 32) {
-			// reverse during load to do the first 32 bits of rotate
-			v -= 32;
-			gins(AMOVW, &hi1, &bl);
-			gins(AMOVW, &lo1, &bh);
-		} else {
-			gins(AMOVW, &hi1, &bh);
-			gins(AMOVW, &lo1, &bl);
-		}
-		if(v == 0) {
-			gins(AMOVW, &bh, &ah);
-			gins(AMOVW, &bl, &al);
-		} else {
-			// rotate by 1 <= v <= 31
-			//	MOVW	bl<<v, al
-			//	MOVW	bh<<v, ah
-			//	OR		bl>>(32-v), ah
-			//	OR		bh>>(32-v), al
-			gshift(AMOVW, &bl, SHIFT_LL, v, &al);
-			gshift(AMOVW, &bh, SHIFT_LL, v, &ah);
-			gshift(AORR, &bl, SHIFT_LR, 32-v, &ah);
-			gshift(AORR, &bh, SHIFT_LR, 32-v, &al);
-		}
-		regfree(&bl);
-		regfree(&bh);
-		break;
-
-	case OLSH:
-		regalloc(&bl, lo1.type, N);
-		regalloc(&bh, hi1.type, N);
-		gins(AMOVW, &hi1, &bh);
-		gins(AMOVW, &lo1, &bl);
-
-		if(r->op == OLITERAL) {
-			v = mpgetfix(r->val.u.xval);
-			if(v >= 64) {
-				// TODO(kaib): replace with gins(AMOVW, nodintconst(0), &al)
-				// here and below (verify it optimizes to EOR)
-				gins(AEOR, &al, &al);
-				gins(AEOR, &ah, &ah);
-			} else
-			if(v > 32) {
-				gins(AEOR, &al, &al);
-				//	MOVW	bl<<(v-32), ah
-				gshift(AMOVW, &bl, SHIFT_LL, (v-32), &ah);
-			} else
-			if(v == 32) {
-				gins(AEOR, &al, &al);
-				gins(AMOVW, &bl, &ah);
-			} else
-			if(v > 0) {
-				//	MOVW	bl<<v, al
-				gshift(AMOVW, &bl, SHIFT_LL, v, &al);
-
-				//	MOVW	bh<<v, ah
-				gshift(AMOVW, &bh, SHIFT_LL, v, &ah);
-
-				//	OR		bl>>(32-v), ah
-				gshift(AORR, &bl, SHIFT_LR, 32-v, &ah);
-			} else {
-				gins(AMOVW, &bl, &al);
-				gins(AMOVW, &bh, &ah);
-			}
-			goto olsh_break;
-		}
-
-		regalloc(&s, types[TUINT32], N);
-		regalloc(&creg, types[TUINT32], N);
-		if (is64(r->type)) {
-			// shift is >= 1<<32
-			split64(r, &cl, &ch);
-			gmove(&ch, &s);
-			gins(ATST, &s, N);
-			p6 = gbranch(ABNE, T, 0);
-			gmove(&cl, &s);
-			splitclean();
-		} else {
-			gmove(r, &s);
-			p6 = P;
-		}
-		gins(ATST, &s, N);
-
-		// shift == 0
-		p1 = gins(AMOVW, &bl, &al);
-		p1->scond = C_SCOND_EQ;
-		p1 = gins(AMOVW, &bh, &ah);
-		p1->scond = C_SCOND_EQ;
-		p2 = gbranch(ABEQ, T, 0);
-
-		// shift is < 32
-		nodconst(&n1, types[TUINT32], 32);
-		gmove(&n1, &creg);
-		gcmp(ACMP, &s, &creg);
-
-		//	MOVW.LO		bl<<s, al
-		p1 = gregshift(AMOVW, &bl, SHIFT_LL, &s, &al);
-		p1->scond = C_SCOND_LO;
-
-		//	MOVW.LO		bh<<s, ah
-		p1 = gregshift(AMOVW, &bh, SHIFT_LL, &s, &ah);
-		p1->scond = C_SCOND_LO;
-
-		//	SUB.LO		s, creg
-		p1 = gins(ASUB, &s, &creg);
-		p1->scond = C_SCOND_LO;
-
-		//	OR.LO		bl>>creg, ah
-		p1 = gregshift(AORR, &bl, SHIFT_LR, &creg, &ah);
-		p1->scond = C_SCOND_LO;
-
-		//	BLO	end
-		p3 = gbranch(ABLO, T, 0);
-
-		// shift == 32
-		p1 = gins(AEOR, &al, &al);
-		p1->scond = C_SCOND_EQ;
-		p1 = gins(AMOVW, &bl, &ah);
-		p1->scond = C_SCOND_EQ;
-		p4 = gbranch(ABEQ, T, 0);
-
-		// shift is < 64
-		nodconst(&n1, types[TUINT32], 64);
-		gmove(&n1, &creg);
-		gcmp(ACMP, &s, &creg);
-
-		//	EOR.LO	al, al
-		p1 = gins(AEOR, &al, &al);
-		p1->scond = C_SCOND_LO;
-
-		//	MOVW.LO		creg>>1, creg
-		p1 = gshift(AMOVW, &creg, SHIFT_LR, 1, &creg);
-		p1->scond = C_SCOND_LO;
-
-		//	SUB.LO		creg, s
-		p1 = gins(ASUB, &creg, &s);
-		p1->scond = C_SCOND_LO;
-
-		//	MOVW	bl<<s, ah
-		p1 = gregshift(AMOVW, &bl, SHIFT_LL, &s, &ah);
-		p1->scond = C_SCOND_LO;
-
-		p5 = gbranch(ABLO, T, 0);
-
-		// shift >= 64
-		if (p6 != P) patch(p6, pc);
-		gins(AEOR, &al, &al);
-		gins(AEOR, &ah, &ah);
-
-		patch(p2, pc);
-		patch(p3, pc);
-		patch(p4, pc);
-		patch(p5, pc);
-		regfree(&s);
-		regfree(&creg);
-
-olsh_break:
-		regfree(&bl);
-		regfree(&bh);
-		break;
-
-
-	case ORSH:
-		regalloc(&bl, lo1.type, N);
-		regalloc(&bh, hi1.type, N);
-		gins(AMOVW, &hi1, &bh);
-		gins(AMOVW, &lo1, &bl);
-
-		if(r->op == OLITERAL) {
-			v = mpgetfix(r->val.u.xval);
-			if(v >= 64) {
-				if(bh.type->etype == TINT32) {
-					//	MOVW	bh->31, al
-					gshift(AMOVW, &bh, SHIFT_AR, 31, &al);
-
-					//	MOVW	bh->31, ah
-					gshift(AMOVW, &bh, SHIFT_AR, 31, &ah);
-				} else {
-					gins(AEOR, &al, &al);
-					gins(AEOR, &ah, &ah);
-				}
-			} else
-			if(v > 32) {
-				if(bh.type->etype == TINT32) {
-					//	MOVW	bh->(v-32), al
-					gshift(AMOVW, &bh, SHIFT_AR, v-32, &al);
-
-					//	MOVW	bh->31, ah
-					gshift(AMOVW, &bh, SHIFT_AR, 31, &ah);
-				} else {
-					//	MOVW	bh>>(v-32), al
-					gshift(AMOVW, &bh, SHIFT_LR, v-32, &al);
-					gins(AEOR, &ah, &ah);
-				}
-			} else
-			if(v == 32) {
-				gins(AMOVW, &bh, &al);
-				if(bh.type->etype == TINT32) {
-					//	MOVW	bh->31, ah
-					gshift(AMOVW, &bh, SHIFT_AR, 31, &ah);
-				} else {
-					gins(AEOR, &ah, &ah);
-				}
-			} else
-			if( v > 0) {
-				//	MOVW	bl>>v, al
-				gshift(AMOVW, &bl, SHIFT_LR, v, &al);
-	
-				//	OR		bh<<(32-v), al
-				gshift(AORR, &bh, SHIFT_LL, 32-v, &al);
-
-				if(bh.type->etype == TINT32) {
-					//	MOVW	bh->v, ah
-					gshift(AMOVW, &bh, SHIFT_AR, v, &ah);
-				} else {
-					//	MOVW	bh>>v, ah
-					gshift(AMOVW, &bh, SHIFT_LR, v, &ah);
-				}
-			} else {
-				gins(AMOVW, &bl, &al);
-				gins(AMOVW, &bh, &ah);
-			}
-			goto orsh_break;
-		}
-
-		regalloc(&s, types[TUINT32], N);
-		regalloc(&creg, types[TUINT32], N);
-		if(is64(r->type)) {
-			// shift is >= 1<<32
-			split64(r, &cl, &ch);
-			gmove(&ch, &s);
-			gins(ATST, &s, N);
-			if(bh.type->etype == TINT32)
-				p1 = gshift(AMOVW, &bh, SHIFT_AR, 31, &ah);
-			else
-				p1 = gins(AEOR, &ah, &ah);
-			p1->scond = C_SCOND_NE;
-			p6 = gbranch(ABNE, T, 0);
-			gmove(&cl, &s);
-			splitclean();
-		} else {
-			gmove(r, &s);
-			p6 = P;
-		}
-		gins(ATST, &s, N);
-
-		// shift == 0
-		p1 = gins(AMOVW, &bl, &al);
-		p1->scond = C_SCOND_EQ;
-		p1 = gins(AMOVW, &bh, &ah);
-		p1->scond = C_SCOND_EQ;
-		p2 = gbranch(ABEQ, T, 0);
-
-		// check if shift is < 32
-		nodconst(&n1, types[TUINT32], 32);
-		gmove(&n1, &creg);
-		gcmp(ACMP, &s, &creg);
-
-		//	MOVW.LO		bl>>s, al
-		p1 = gregshift(AMOVW, &bl, SHIFT_LR, &s, &al);
-		p1->scond = C_SCOND_LO;
-
-		//	SUB.LO		s,creg
-		p1 = gins(ASUB, &s, &creg);
-		p1->scond = C_SCOND_LO;
-
-		//	OR.LO		bh<<(32-s), al
-		p1 = gregshift(AORR, &bh, SHIFT_LL, &creg, &al);
-		p1->scond = C_SCOND_LO;
-
-		if(bh.type->etype == TINT32) {
-			//	MOVW	bh->s, ah
-			p1 = gregshift(AMOVW, &bh, SHIFT_AR, &s, &ah);
-		} else {
-			//	MOVW	bh>>s, ah
-			p1 = gregshift(AMOVW, &bh, SHIFT_LR, &s, &ah);
-		}
-		p1->scond = C_SCOND_LO;
-
-		//	BLO	end
-		p3 = gbranch(ABLO, T, 0);
-
-		// shift == 32
-		p1 = gins(AMOVW, &bh, &al);
-		p1->scond = C_SCOND_EQ;
-		if(bh.type->etype == TINT32)
-			gshift(AMOVW, &bh, SHIFT_AR, 31, &ah);
-		else
-			gins(AEOR, &ah, &ah);
-		p4 = gbranch(ABEQ, T, 0);
-
-		// check if shift is < 64
-		nodconst(&n1, types[TUINT32], 64);
-		gmove(&n1, &creg);
-		gcmp(ACMP, &s, &creg);
-
-		//	MOVW.LO		creg>>1, creg
-		p1 = gshift(AMOVW, &creg, SHIFT_LR, 1, &creg);
-		p1->scond = C_SCOND_LO;
-
-		//	SUB.LO		creg, s
-		p1 = gins(ASUB, &creg, &s);
-		p1->scond = C_SCOND_LO;
-
-		if(bh.type->etype == TINT32) {
-			//	MOVW	bh->(s-32), al
-			p1 = gregshift(AMOVW, &bh, SHIFT_AR, &s, &al);
-			p1->scond = C_SCOND_LO;
-		} else {
-			//	MOVW	bh>>(v-32), al
-			p1 = gregshift(AMOVW, &bh, SHIFT_LR, &s, &al);
-			p1->scond = C_SCOND_LO;
-		}
-
-		//	BLO	end
-		p5 = gbranch(ABLO, T, 0);
-
-		// s >= 64
-		if(p6 != P)
-			patch(p6, pc);
-		if(bh.type->etype == TINT32) {
-			//	MOVW	bh->31, al
-			gshift(AMOVW, &bh, SHIFT_AR, 31, &al);
-		} else {
-			gins(AEOR, &al, &al);
-		}
-
-		patch(p2, pc);
-		patch(p3, pc);
-		patch(p4, pc);
-		patch(p5, pc);
-		regfree(&s);
-		regfree(&creg);
-
-
-orsh_break:
-		regfree(&bl);
-		regfree(&bh);
-		break;
-
-	case OXOR:
-	case OAND:
-	case OOR:
-		// TODO(kaib): literal optimizations
-		// make constant the right side (it usually is anyway).
-//		if(lo1.op == OLITERAL) {
-//			nswap(&lo1, &lo2);
-//			nswap(&hi1, &hi2);
-//		}
-//		if(lo2.op == OLITERAL) {
-//			// special cases for constants.
-//			lv = mpgetfix(lo2.val.u.xval);
-//			hv = mpgetfix(hi2.val.u.xval);
-//			splitclean();	// right side
-//			split64(res, &lo2, &hi2);
-//			switch(n->op) {
-//			case OXOR:
-//				gmove(&lo1, &lo2);
-//				gmove(&hi1, &hi2);
-//				switch(lv) {
-//				case 0:
-//					break;
-//				case 0xffffffffu:
-//					gins(ANOTL, N, &lo2);
-//					break;
-//				default:
-//					gins(AXORL, ncon(lv), &lo2);
-//					break;
-//				}
-//				switch(hv) {
-//				case 0:
-//					break;
-//				case 0xffffffffu:
-//					gins(ANOTL, N, &hi2);
-//					break;
-//				default:
-//					gins(AXORL, ncon(hv), &hi2);
-//					break;
-//				}
-//				break;
-
-//			case OAND:
-//				switch(lv) {
-//				case 0:
-//					gins(AMOVL, ncon(0), &lo2);
-//					break;
-//				default:
-//					gmove(&lo1, &lo2);
-//					if(lv != 0xffffffffu)
-//						gins(AANDL, ncon(lv), &lo2);
-//					break;
-//				}
-//				switch(hv) {
-//				case 0:
-//					gins(AMOVL, ncon(0), &hi2);
-//					break;
-//				default:
-//					gmove(&hi1, &hi2);
-//					if(hv != 0xffffffffu)
-//						gins(AANDL, ncon(hv), &hi2);
-//					break;
-//				}
-//				break;
-
-//			case OOR:
-//				switch(lv) {
-//				case 0:
-//					gmove(&lo1, &lo2);
-//					break;
-//				case 0xffffffffu:
-//					gins(AMOVL, ncon(0xffffffffu), &lo2);
-//					break;
-//				default:
-//					gmove(&lo1, &lo2);
-//					gins(AORL, ncon(lv), &lo2);
-//					break;
-//				}
-//				switch(hv) {
-//				case 0:
-//					gmove(&hi1, &hi2);
-//					break;
-//				case 0xffffffffu:
-//					gins(AMOVL, ncon(0xffffffffu), &hi2);
-//					break;
-//				default:
-//					gmove(&hi1, &hi2);
-//					gins(AORL, ncon(hv), &hi2);
-//					break;
-//				}
-//				break;
-//			}
-//			splitclean();
-//			splitclean();
-//			goto out;
-//		}
-		regalloc(&n1, lo1.type, N);
-		gins(AMOVW, &lo1, &al);
-		gins(AMOVW, &hi1, &ah);
-		gins(AMOVW, &lo2, &n1);
-		gins(optoas(n->op, lo1.type), &n1, &al);
-		gins(AMOVW, &hi2, &n1);
-		gins(optoas(n->op, lo1.type), &n1, &ah);
-		regfree(&n1);
-		break;
-	}
-	if(is64(r->type))
-		splitclean();
-	splitclean();
-
-	split64(res, &lo1, &hi1);
-	gins(AMOVW, &al, &lo1);
-	gins(AMOVW, &ah, &hi1);
-	splitclean();
-
-//out:
-	regfree(&al);
-	regfree(&ah);
-}
-
-/*
- * generate comparison of nl, nr, both 64-bit.
- * nl is memory; nr is constant or memory.
- */
-void
-cmp64(Node *nl, Node *nr, int op, int likely, Prog *to)
-{
-	Node lo1, hi1, lo2, hi2, r1, r2;
-	Prog *br;
-	Type *t;
-
-	split64(nl, &lo1, &hi1);
-	split64(nr, &lo2, &hi2);
-
-	// compare most significant word;
-	// if they differ, we're done.
-	t = hi1.type;
-	regalloc(&r1, types[TINT32], N);
-	regalloc(&r2, types[TINT32], N);
-	gins(AMOVW, &hi1, &r1);
-	gins(AMOVW, &hi2, &r2);
-	gcmp(ACMP, &r1, &r2);
-	regfree(&r1);
-	regfree(&r2);
-
-	br = P;
-	switch(op) {
-	default:
-		fatal("cmp64 %O %T", op, t);
-	case OEQ:
-		// cmp hi
-		// bne L
-		// cmp lo
-		// beq to
-		// L:
-		br = gbranch(ABNE, T, -likely);
-		break;
-	case ONE:
-		// cmp hi
-		// bne to
-		// cmp lo
-		// bne to
-		patch(gbranch(ABNE, T, likely), to);
-		break;
-	case OGE:
-	case OGT:
-		// cmp hi
-		// bgt to
-		// blt L
-		// cmp lo
-		// bge to (or bgt to)
-		// L:
-		patch(gbranch(optoas(OGT, t), T, likely), to);
-		br = gbranch(optoas(OLT, t), T, -likely);
-		break;
-	case OLE:
-	case OLT:
-		// cmp hi
-		// blt to
-		// bgt L
-		// cmp lo
-		// ble to (or jlt to)
-		// L:
-		patch(gbranch(optoas(OLT, t), T, likely), to);
-		br = gbranch(optoas(OGT, t), T, -likely);
-		break;
-	}
-
-	// compare least significant word
-	t = lo1.type;
-	regalloc(&r1, types[TINT32], N);
-	regalloc(&r2, types[TINT32], N);
-	gins(AMOVW, &lo1, &r1);
-	gins(AMOVW, &lo2, &r2);
-	gcmp(ACMP, &r1, &r2);
-	regfree(&r1);
-	regfree(&r2);
-
-	// jump again
-	patch(gbranch(optoas(op, t), T, likely), to);
-
-	// point first branch down here if appropriate
-	if(br != P)
-		patch(br, pc);
-
-	splitclean();
-	splitclean();
-}
diff --git a/src/cmd/5g/doc.go b/src/cmd/5g/doc.go
deleted file mode 100644
index aebdcab..0000000
--- a/src/cmd/5g/doc.go
+++ /dev/null
@@ -1,15 +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.
-
-// +build ignore
-
-/*
-
-5g is the version of the gc compiler for the ARM.
-The $GOARCH for these tools is arm.
-
-It reads .go files and outputs .5 files. The flags are documented in ../gc/doc.go.
-
-*/
-package main
diff --git a/src/cmd/5g/galign.c b/src/cmd/5g/galign.c
deleted file mode 100644
index b4c45da..0000000
--- a/src/cmd/5g/galign.c
+++ /dev/null
@@ -1,49 +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 <u.h>
-#include <libc.h>
-#include "gg.h"
-
-int	thechar	= '5';
-char*	thestring	= "arm";
-LinkArch*	thelinkarch = &linkarm;
-
-void
-linkarchinit(void)
-{
-}
-
-vlong MAXWIDTH = (1LL<<32) - 1;
-
-/*
- * go declares several platform-specific type aliases:
- * int, uint, float, and uintptr
- */
-Typedef	typedefs[] =
-{
-	{"int",		TINT,		TINT32},
-	{"uint",		TUINT,		TUINT32},
-	{"uintptr",	TUINTPTR,	TUINT32},
-	{0}
-};
-
-void
-betypeinit(void)
-{
-	widthptr = 4;
-	widthint = 4;
-	widthreg = 4;
-
-	zprog.link = P;
-	zprog.as = AGOK;
-	zprog.scond = C_SCOND_NONE;
-	zprog.reg = NREG;
-	zprog.from.type = D_NONE;
-	zprog.from.name = D_NONE;
-	zprog.from.reg = NREG;
-	zprog.to = zprog.from;
-
-	listinit5();
-}
diff --git a/src/cmd/5g/gg.h b/src/cmd/5g/gg.h
deleted file mode 100644
index 00914bf..0000000
--- a/src/cmd/5g/gg.h
+++ /dev/null
@@ -1,123 +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.
-
-#ifndef	EXTERN
-#define	EXTERN	extern
-#endif
-
-#include "../gc/go.h"
-#include "../5l/5.out.h"
-
-#define TEXTFLAG reg
-
-enum
-{
-	REGALLOC_R0 = 0,
-	REGALLOC_RMAX = REGEXT,
-	REGALLOC_F0 = NREG,
-	REGALLOC_FMAX = REGALLOC_F0 + FREGEXT,
-};
-
-EXTERN	int32	dynloc;
-EXTERN	uchar	reg[REGALLOC_FMAX+1];
-EXTERN	int32	pcloc;		// instruction counter
-EXTERN	Strlit	emptystring;
-EXTERN	Prog	zprog;
-EXTERN	Node*	newproc;
-EXTERN	Node*	deferproc;
-EXTERN	Node*	deferreturn;
-EXTERN	Node*	panicindex;
-EXTERN	Node*	panicslice;
-EXTERN	Node*	throwreturn;
-extern	long	unmappedzero;
-
-/*
- * gen.c
- */
-void	compile(Node*);
-void	gen(Node*);
-Node*	lookdot(Node*, Node*, int);
-void	cgen_as(Node*, Node*);
-void	cgen_callmeth(Node*, int);
-void	cgen_callinter(Node*, Node*, int);
-void	cgen_proc(Node*, int);
-void	cgen_callret(Node*, Node*);
-void	cgen_dcl(Node*);
-int	needconvert(Type*, Type*);
-void	genconv(Type*, Type*);
-void	allocparams(void);
-void	checklabels(void);
-void	ginscall(Node*, int);
-
-/*
- * cgen
- */
-void	agen(Node*, Node*);
-Prog* cgenindex(Node *, Node *, int);
-void	igen(Node*, Node*, Node*);
-void agenr(Node *n, Node *a, Node *res);
-vlong	fieldoffset(Type*, Node*);
-void	sgen(Node*, Node*, int64);
-void	gmove(Node*, Node*);
-Prog*	gins(int, Node*, Node*);
-int	samaddr(Node*, Node*);
-void	raddr(Node *n, Prog *p);
-Prog*	gcmp(int, Node*, Node*);
-Prog*	gshift(int as, Node *lhs, int32 stype, int32 sval, Node *rhs);
-Prog *	gregshift(int as, Node *lhs, int32 stype, Node *reg, Node *rhs);
-void	naddr(Node*, Addr*, int);
-void	cgen_aret(Node*, Node*);
-void	cgen_hmul(Node*, Node*, Node*);
-void	cgen_shift(int, int, Node*, Node*, Node*);
-int	componentgen(Node*, Node*);
-
-/*
- * cgen64.c
- */
-void	cmp64(Node*, Node*, int, int, Prog*);
-void	cgen64(Node*, Node*);
-
-/*
- * gsubr.c
- */
-void	clearp(Prog*);
-Prog*	gbranch(int, Type*, int);
-Prog*	prog(int);
-void	gconv(int, int);
-int	conv2pt(Type*);
-vlong	convvtox(vlong, int);
-void	fnparam(Type*, int, int);
-Prog*	gop(int, Node*, Node*, Node*);
-int	optoas(int, Type*);
-void	ginit(void);
-void	gclean(void);
-void	regalloc(Node*, Type*, Node*);
-void	regfree(Node*);
-Node*	nodarg(Type*, int);
-void	nodreg(Node*, Type*, int);
-void	nodindreg(Node*, Type*, int);
-void	buildtxt(void);
-Plist*	newplist(void);
-int	isfat(Type*);
-int	dotaddable(Node*, Node*);
-void	sudoclean(void);
-int	sudoaddable(int, Node*, Addr*, int*);
-void	afunclit(Addr*, Node*);
-void	datagostring(Strlit*, Addr*);
-void	split64(Node*, Node*, Node*);
-void	splitclean(void);
-Node*	ncon(uint32 i);
-void	gtrack(Sym*);
-
-/*
- * obj.c
- */
-void	datastring(char*, int, Addr*);
-
-/*
- * list.c
- */
-void	listinit(void);
-
-void	zaddr(Biobuf*, Addr*, int, int);
diff --git a/src/cmd/5g/ggen.c b/src/cmd/5g/ggen.c
deleted file mode 100644
index 53cddb7..0000000
--- a/src/cmd/5g/ggen.c
+++ /dev/null
@@ -1,956 +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.
-
-#undef	EXTERN
-#define	EXTERN
-#include <u.h>
-#include <libc.h>
-#include "gg.h"
-#include "opt.h"
-
-static Prog* appendpp(Prog*, int, int, int, int32, int, int, int32);
-static Prog *zerorange(Prog *p, vlong frame, vlong lo, vlong hi, uint32 *r0);
-
-void
-defframe(Prog *ptxt)
-{
-	uint32 frame, r0;
-	Prog *p;
-	vlong hi, lo;
-	NodeList *l;
-	Node *n;
-
-	// fill in argument size
-	ptxt->to.type = D_CONST2;
-	ptxt->to.offset2 = rnd(curfn->type->argwid, widthptr);
-
-	// fill in final stack size
-	frame = rnd(stksize+maxarg, widthptr);
-	ptxt->to.offset = frame;
-	
-	// insert code to contain ambiguously live variables
-	// so that garbage collector only sees initialized values
-	// when it looks for pointers.
-	p = ptxt;
-	lo = hi = 0;
-	r0 = 0;
-	for(l=curfn->dcl; l != nil; l = l->next) {
-		n = l->n;
-		if(!n->needzero)
-			continue;
-		if(n->class != PAUTO)
-			fatal("needzero class %d", n->class);
-		if(n->type->width % widthptr != 0 || n->xoffset % widthptr != 0 || n->type->width == 0)
-			fatal("var %lN has size %d offset %d", n, (int)n->type->width, (int)n->xoffset);
-		if(lo != hi && n->xoffset + n->type->width >= lo - 2*widthptr) {
-			// merge with range we already have
-			lo = rnd(n->xoffset, widthptr);
-			continue;
-		}
-		// zero old range
-		p = zerorange(p, frame, lo, hi, &r0);
-
-		// set new range
-		hi = n->xoffset + n->type->width;
-		lo = n->xoffset;
-	}
-	// zero final range
-	zerorange(p, frame, lo, hi, &r0);
-}
-
-static Prog*
-zerorange(Prog *p, vlong frame, vlong lo, vlong hi, uint32 *r0)
-{
-	vlong cnt, i;
-	Prog *p1;
-	Node *f;
-
-	cnt = hi - lo;
-	if(cnt == 0)
-		return p;
-	if(*r0 == 0) {
-		p = appendpp(p, AMOVW, D_CONST, NREG, 0, D_REG, 0, 0);
-		*r0 = 1;
-	}
-	if(cnt < 4*widthptr) {
-		for(i = 0; i < cnt; i += widthptr) 
-			p = appendpp(p, AMOVW, D_REG, 0, 0, D_OREG, REGSP, 4+frame+lo+i);
-	} else if(!nacl && (cnt <= 128*widthptr)) {
-		p = appendpp(p, AADD, D_CONST, NREG, 4+frame+lo, D_REG, 1, 0);
-		p->reg = REGSP;
-		p = appendpp(p, ADUFFZERO, D_NONE, NREG, 0, D_OREG, NREG, 0);
-		f = sysfunc("duffzero");
-		naddr(f, &p->to, 1);
-		afunclit(&p->to, f);
-		p->to.offset = 4*(128-cnt/widthptr);
-	} else {
-		p = appendpp(p, AADD, D_CONST, NREG, 4+frame+lo, D_REG, 1, 0);
-		p->reg = REGSP;
-		p = appendpp(p, AADD, D_CONST, NREG, cnt, D_REG, 2, 0);
-		p->reg = 1;
-		p1 = p = appendpp(p, AMOVW, D_REG, 0, 0, D_OREG, 1, 4);
-		p->scond |= C_PBIT;
-		p = appendpp(p, ACMP, D_REG, 1, 0, D_NONE, 0, 0);
-		p->reg = 2;
-		p = appendpp(p, ABNE, D_NONE, NREG, 0, D_BRANCH, NREG, 0);
-		patch(p, p1);
-	}
-	return p;
-}
-
-static Prog*	
-appendpp(Prog *p, int as, int ftype, int freg, int32 foffset, int ttype, int treg, int32 toffset)	
-{	
-	Prog *q;	
-		
-	q = mal(sizeof(*q));	
-	clearp(q);	
-	q->as = as;	
-	q->lineno = p->lineno;	
-	q->from.type = ftype;	
-	q->from.reg = freg;	
-	q->from.offset = foffset;	
-	q->to.type = ttype;	
-	q->to.reg = treg;	
-	q->to.offset = toffset;	
-	q->link = p->link;	
-	p->link = q;	
-	return q;	
-}
-
-// Sweep the prog list to mark any used nodes.
-void
-markautoused(Prog* p)
-{
-	for (; p; p = p->link) {
-		if (p->as == ATYPE || p->as == AVARDEF || p->as == AVARKILL)
-			continue;
-
-		if (p->from.node)
-			p->from.node->used = 1;
-
-		if (p->to.node)
-			p->to.node->used = 1;
-	}
-}
-
-// Fixup instructions after allocauto (formerly compactframe) has moved all autos around.
-void
-fixautoused(Prog* p)
-{
-	Prog **lp;
-
-	for (lp=&p; (p=*lp) != P; ) {
-		if (p->as == ATYPE && p->from.node && p->from.name == D_AUTO && !p->from.node->used) {
-			*lp = p->link;
-			continue;
-		}
-		if ((p->as == AVARDEF || p->as == AVARKILL) && p->to.node && !p->to.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
-			// the no-ops.
-			p->to.type = D_NONE;
-			p->to.node = N;
-			p->as = ANOP;
-			continue;
-		}
-
-		if (p->from.name == D_AUTO && p->from.node)
-			p->from.offset += p->from.node->stkdelta;
-
-		if (p->to.name == D_AUTO && p->to.node)
-			p->to.offset += p->to.node->stkdelta;
-
-		lp = &p->link;
-	}
-}
-
-/*
- * 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)
- */
-void
-ginscall(Node *f, int proc)
-{
-	Prog *p;
-	Node n1, r, r1, con;
-
-	if(f->type != T)
-		setmaxarg(f->type);
-
-	switch(proc) {
-	default:
-		fatal("ginscall: bad proc %d", proc);
-		break;
-
-	case 0:	// normal call
-	case -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 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.
-				nodreg(&r, types[TINT], 0);
-				p = gins(AAND, &r, &r);
-				p->scond = C_SCOND_EQ;
-			}
-			p = gins(ABL, N, f);
-			afunclit(&p->to, f);
-			if(proc == -1 || noreturn(p))
-				gins(AUNDEF, N, N);
-			break;
-		}
-		nodreg(&r, types[tptr], 7);
-		nodreg(&r1, types[tptr], 1);
-		gmove(f, &r);
-		r.op = OINDREG;
-		gmove(&r, &r1);
-		r.op = OREGISTER;
-		r1.op = OINDREG;
-		gins(ABL, &r, &r1);
-		break;
-
-	case 3:	// normal call of c function pointer
-		gins(ABL, N, f);
-		break;
-
-	case 1:	// call in new proc (go)
-	case 2:	// deferred call (defer)
-		regalloc(&r, types[tptr], N);
-		p = gins(AMOVW, N, &r);
-		p->from.type = D_OREG;
-		p->from.reg = REGSP;
-		
-		p = gins(AMOVW, &r, N);
-		p->to.type = D_OREG;
-		p->to.reg = REGSP;
-		p->to.offset = -12;
-		p->scond |= C_WBIT;
-
-		memset(&n1, 0, sizeof n1);
-		n1.op = OADDR;
-		n1.left = f;
-		gins(AMOVW, &n1, &r);
-
-		p = gins(AMOVW, &r, N);
-		p->to.type = D_OREG;
-		p->to.reg = REGSP;
-		p->to.offset = 8;
-
-		nodconst(&con, types[TINT32], argsize(f->type));
-		gins(AMOVW, &con, &r);
-		p = gins(AMOVW, &r, N);
-		p->to.type = D_OREG;
-		p->to.reg = REGSP;
-		p->to.offset = 4;
-		regfree(&r);
-
-		if(proc == 1)
-			ginscall(newproc, 0);
-		else
-			ginscall(deferproc, 0);
-
-		nodreg(&r, types[tptr], 1);
-		p = gins(AMOVW, N, N);
-		p->from.type = D_CONST;
-		p->from.reg = REGSP;
-		p->from.offset = 12;
-		p->to.reg = REGSP;
-		p->to.type = D_REG;
-
-		if(proc == 2) {
-			nodconst(&con, types[TINT32], 0);
-			p = gins(ACMP, &con, N);
-			p->reg = 0;
-			p = gbranch(ABEQ, T, +1);
-			cgen_ret(N);
-			patch(p, pc);
-		}
-		break;
-	}
-}
-
-/*
- * n is call to interface method.
- * generate res = n.
- */
-void
-cgen_callinter(Node *n, Node *res, int proc)
-{
-	int r;
-	Node *i, *f;
-	Node tmpi, nodo, nodr, nodsp;
-	Prog *p;
-
-	i = n->left;
-	if(i->op != ODOTINTER)
-		fatal("cgen_callinter: not ODOTINTER %O", i->op);
-
-	f = i->right;		// field
-	if(f->op != ONAME)
-		fatal("cgen_callinter: not ONAME %O", f->op);
-
-	i = i->left;		// interface
-
-	// Release res register during genlist and cgen,
-	// which might have their own function calls.
-	r = -1;
-	if(res != N && (res->op == OREGISTER || res->op == OINDREG)) {
-		r = res->val.u.reg;
-		reg[r]--;
-	}
-
-	if(!i->addable) {
-		tempname(&tmpi, i->type);
-		cgen(i, &tmpi);
-		i = &tmpi;
-	}
-
-	genlist(n->list);			// args
-	if(r >= 0)
-		reg[r]++;
-
-	regalloc(&nodr, types[tptr], res);
-	regalloc(&nodo, types[tptr], &nodr);
-	nodo.op = OINDREG;
-
-	agen(i, &nodr);		// REG = &inter
-
-	nodindreg(&nodsp, types[tptr], REGSP);
-	nodsp.xoffset = 4;
-	nodo.xoffset += widthptr;
-	cgen(&nodo, &nodsp);	// 4(SP) = 4(REG) -- i.data
-
-	nodo.xoffset -= widthptr;
-	cgen(&nodo, &nodr);	// REG = 0(REG) -- i.tab
-	cgen_checknil(&nodr); // in case offset is huge
-
-	nodo.xoffset = n->left->xoffset + 3*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 = OINDREG;
-		proc = 3;
-	} else {
-		// go/defer. generate go func value.
-		p = gins(AMOVW, &nodo, &nodr);
-		p->from.type = D_CONST;	// 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
- */
-void
-cgen_call(Node *n, int proc)
-{
-	Type *t;
-	Node nod, afun;
-
-	if(n == N)
-		return;
-
-	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) {
-		regalloc(&nod, types[tptr], N);
-		cgen_as(&nod, &afun);
-		nod.type = t;
-		ginscall(&nod, proc);
-		regfree(&nod);
-		goto ret;
-	}
-
-	// call pointer
-	if(n->left->op != ONAME || n->left->class != PFUNC) {
-		regalloc(&nod, types[tptr], N);
-		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.
- */
-void
-cgen_callret(Node *n, Node *res)
-{
-	Node nod;
-	Type *fp, *t;
-	Iter flist;
-
-	t = n->left->type;
-	if(t->etype == TPTR32 || t->etype == TPTR64)
-		t = t->type;
-
-	fp = structfirst(&flist, getoutarg(t));
-	if(fp == T)
-		fatal("cgen_callret: nil");
-
-	memset(&nod, 0, sizeof(nod));
-	nod.op = OINDREG;
-	nod.val.u.reg = REGSP;
-	nod.addable = 1;
-
-	nod.xoffset = fp->width + 4; // +4: saved lr at 0(SP)
-	nod.type = fp->type;
-	cgen_as(res, &nod);
-}
-
-/*
- * call to n has already been generated.
- * generate:
- *	res = &return value from call.
- */
-void
-cgen_aret(Node *n, Node *res)
-{
-	Node nod1, nod2;
-	Type *fp, *t;
-	Iter flist;
-
-	t = n->left->type;
-	if(isptr[t->etype])
-		t = t->type;
-
-	fp = structfirst(&flist, getoutarg(t));
-	if(fp == T)
-		fatal("cgen_aret: nil");
-
-	memset(&nod1, 0, sizeof(nod1));
-	nod1.op = OINDREG;
-	nod1.val.u.reg = REGSP;
-	nod1.addable = 1;
-
-	nod1.xoffset = fp->width + 4; // +4: saved lr at 0(SP)
-	nod1.type = fp->type;
-
-	if(res->op != OREGISTER) {
-		regalloc(&nod2, types[tptr], res);
-		agen(&nod1, &nod2);
-		gins(AMOVW, &nod2, res);
-		regfree(&nod2);
-	} else
-		agen(&nod1, res);
-}
-
-/*
- * generate return.
- * n->left is assignments to return values.
- */
-void
-cgen_ret(Node *n)
-{
-	Prog *p;
-
-	if(n != N)
-		genlist(n->list);		// copy out args
-	if(hasdefer)
-		ginscall(deferreturn, 0);
-	genlist(curfn->exit);
-	p = gins(ARET, N, N);
-	if(n != N && n->op == ORETJMP) {
-		p->to.name = D_EXTERN;
-		p->to.type = D_CONST;
-		p->to.sym = linksym(n->left->sym);
-	}
-}
-
-/*
- * generate += *= etc.
- */
-void
-cgen_asop(Node *n)
-{
-	Node n1, n2, n3, n4;
-	Node *nl, *nr;
-	Prog *p1;
-	Addr addr;
-	int a, w;
-
-	nl = n->left;
-	nr = n->right;
-
-	if(nr->ullman >= UINF && nl->ullman >= UINF) {
-		tempname(&n1, nr->type);
-		cgen(nr, &n1);
-		n2 = *n;
-		n2.right = &n1;
-		cgen_asop(&n2);
-		goto ret;
-	}
-
-	if(!isint[nl->type->etype])
-		goto hard;
-	if(!isint[nr->type->etype])
-		goto hard;
-	if(is64(nl->type) || is64(nr->type))
-		goto hard64;
-
-	switch(n->etype) {
-	case OADD:
-	case OSUB:
-	case OXOR:
-	case OAND:
-	case OOR:
-		a = optoas(n->etype, nl->type);
-		if(nl->addable) {
-			if(smallintconst(nr))
-				n3 = *nr;
-			else {
-				regalloc(&n3, nr->type, N);
-				cgen(nr, &n3);
-			}
-			regalloc(&n2, nl->type, N);
-			cgen(nl, &n2);
-			gins(a, &n3, &n2);
-			cgen(&n2, nl);
-			regfree(&n2);
-			if(n3.op != OLITERAL)
-				regfree(&n3);
-			goto ret;
-		}
-		if(nr->ullman < UINF)
-		if(sudoaddable(a, nl, &addr, &w)) {
-			w = optoas(OAS, nl->type);
-			regalloc(&n2, nl->type, N);
-			p1 = gins(w, N, &n2);
-			p1->from = addr;
-			regalloc(&n3, nr->type, N);
-			cgen(nr, &n3);
-			gins(a, &n3, &n2);
-			p1 = gins(w, &n2, N);
-			p1->to = addr;
-			regfree(&n2);
-			regfree(&n3);
-			sudoclean();
-			goto ret;
-		}
-	}
-
-hard:
-	n2.op = 0;
-	n1.op = 0;
-	if(nr->op == OLITERAL) {
-		// don't allocate a register for literals.
-	} else if(nr->ullman >= nl->ullman || nl->addable) {
-		regalloc(&n2, nr->type, N);
-		cgen(nr, &n2);
-		nr = &n2;
-	} else {
-		tempname(&n2, nr->type);
-		cgen(nr, &n2);
-		nr = &n2;
-	}
-	if(!nl->addable) {
-		igen(nl, &n1, N);
-		nl = &n1;
-	}
-
-	n3 = *n;
-	n3.left = nl;
-	n3.right = nr;
-	n3.op = n->etype;
-
-	regalloc(&n4, nl->type, N);
-	cgen(&n3, &n4);
-	gmove(&n4, nl);
-
-	if(n1.op)
-		regfree(&n1);
-	if(n2.op == OREGISTER)
-		regfree(&n2);
-	regfree(&n4);
-	goto ret;
-
-hard64:
-	if(nr->ullman > nl->ullman) {
-		tempname(&n2, nr->type);
-		cgen(nr, &n2);
-		igen(nl, &n1, N);
-	} else {
-		igen(nl, &n1, N);
-		tempname(&n2, nr->type);
-		cgen(nr, &n2);
-	}
-
-	n3 = *n;
-	n3.left = &n1;
-	n3.right = &n2;
-	n3.op = n->etype;
-
-	cgen(&n3, &n1);
-
-ret:
-	;
-}
-
-int
-samereg(Node *a, Node *b)
-{
-	if(a->op != OREGISTER)
-		return 0;
-	if(b->op != OREGISTER)
-		return 0;
-	if(a->val.u.reg != b->val.u.reg)
-		return 0;
-	return 1;
-}
-
-/*
- * generate high multiply
- *  res = (nl * nr) >> wordsize
- */
-void
-cgen_hmul(Node *nl, Node *nr, Node *res)
-{
-	int w;
-	Node n1, n2, *tmp;
-	Type *t;
-	Prog *p;
-
-	if(nl->ullman < nr->ullman) {
-		tmp = nl;
-		nl = nr;
-		nr = tmp;
-	}
-	t = nl->type;
-	w = t->width * 8;
-	regalloc(&n1, t, res);
-	cgen(nl, &n1);
-	regalloc(&n2, t, N);
-	cgen(nr, &n2);
-	switch(simtype[t->etype]) {
-	case TINT8:
-	case TINT16:
-		gins(optoas(OMUL, t), &n2, &n1);
-		gshift(AMOVW, &n1, SHIFT_AR, w, &n1);
-		break;
-	case TUINT8:
-	case TUINT16:
-		gins(optoas(OMUL, t), &n2, &n1);
-		gshift(AMOVW, &n1, SHIFT_LR, w, &n1);
-		break;
-	case TINT32:
-	case TUINT32:
-		// perform a long multiplication.
-		if(issigned[t->etype])
-			p = gins(AMULL, &n2, N);
-		else
-			p = gins(AMULLU, &n2, N);
-		// n2 * n1 -> (n1 n2)
-		p->reg = n1.val.u.reg;
-		p->to.type = D_REGREG;
-		p->to.reg = n1.val.u.reg;
-		p->to.offset = n2.val.u.reg;
-		break;
-	default:
-		fatal("cgen_hmul %T", t);
-		break;
-	}
-	cgen(&n1, res);
-	regfree(&n1);
-	regfree(&n2);
-}
-
-/*
- * generate shift according to op, one of:
- *	res = nl << nr
- *	res = nl >> nr
- */
-void
-cgen_shift(int op, int bounded, Node *nl, Node *nr, Node *res)
-{
-	Node n1, n2, n3, nt, t, lo, hi;
-	int w, v;
-	Prog *p1, *p2, *p3;
-	Type *tr;
-	uvlong sc;
-
-	USED(bounded);
-	if(nl->type->width > 4)
-		fatal("cgen_shift %T", nl->type);
-
-	w = nl->type->width * 8;
-
-	if(op == OLROT) {
-		v = mpgetfix(nr->val.u.xval);
-		regalloc(&n1, nl->type, res);
-		if(w == 32) {
-			cgen(nl, &n1);
-			gshift(AMOVW, &n1, SHIFT_RR, w-v, &n1);
-		} else {
-			regalloc(&n2, nl->type, N);
-			cgen(nl, &n2);
-			gshift(AMOVW, &n2, SHIFT_LL, v, &n1);
-			gshift(AORR, &n2, SHIFT_LR, w-v, &n1);
-			regfree(&n2);
-			// Ensure sign/zero-extended result.
-			gins(optoas(OAS, nl->type), &n1, &n1);
-		}
-		gmove(&n1, res);
-		regfree(&n1);
-		return;
-	}
-
-	if(nr->op == OLITERAL) {
-		regalloc(&n1, nl->type, res);
-		cgen(nl, &n1);
-		sc = mpgetfix(nr->val.u.xval);
-		if(sc == 0) {
-			// nothing to do
-		} else if(sc >= nl->type->width*8) {
-			if(op == ORSH && issigned[nl->type->etype])
-				gshift(AMOVW, &n1, SHIFT_AR, w, &n1);
-			else
-				gins(AEOR, &n1, &n1);
-		} else {
-			if(op == ORSH && issigned[nl->type->etype])
-				gshift(AMOVW, &n1, SHIFT_AR, sc, &n1);
-			else if(op == ORSH)
-				gshift(AMOVW, &n1, SHIFT_LR, sc, &n1);
-			else // OLSH
-				gshift(AMOVW, &n1, SHIFT_LL, sc, &n1);
-		}
-		if(w < 32 && op == OLSH)
-			gins(optoas(OAS, nl->type), &n1, &n1);
-		gmove(&n1, res);
-		regfree(&n1);
-		return;
-	}
-
-	tr = nr->type;
-	if(tr->width > 4) {
-		tempname(&nt, nr->type);
-		if(nl->ullman >= nr->ullman) {
-			regalloc(&n2, nl->type, res);
-			cgen(nl, &n2);
-			cgen(nr, &nt);
-			n1 = nt;
-		} else {
-			cgen(nr, &nt);
-			regalloc(&n2, nl->type, res);
-			cgen(nl, &n2);
-		}
-		split64(&nt, &lo, &hi);
-		regalloc(&n1, types[TUINT32], N);
-		regalloc(&n3, types[TUINT32], N);
-		gmove(&lo, &n1);
-		gmove(&hi, &n3);
-		splitclean();
-		gins(ATST, &n3, N);
-		nodconst(&t, types[TUINT32], w);
-		p1 = gins(AMOVW, &t, &n1);
-		p1->scond = C_SCOND_NE;
-		tr = types[TUINT32];
-		regfree(&n3);
-	} else {
-		if(nl->ullman >= nr->ullman) {
-			regalloc(&n2, nl->type, res);
-			cgen(nl, &n2);
-			regalloc(&n1, nr->type, N);
-			cgen(nr, &n1);
-		} else {
-			regalloc(&n1, nr->type, N);
-			cgen(nr, &n1);
-			regalloc(&n2, nl->type, res);
-			cgen(nl, &n2);
-		}
-	}
-
-	// test for shift being 0
-	gins(ATST, &n1, N);
-	p3 = gbranch(ABEQ, T, -1);
-
-	// test and fix up large shifts
-	// TODO: if(!bounded), don't emit some of this.
-	regalloc(&n3, tr, N);
-	nodconst(&t, types[TUINT32], w);
-	gmove(&t, &n3);
-	gcmp(ACMP, &n1, &n3);
-	if(op == ORSH) {
-		if(issigned[nl->type->etype]) {
-			p1 = gshift(AMOVW, &n2, SHIFT_AR, w-1, &n2);
-			p2 = gregshift(AMOVW, &n2, SHIFT_AR, &n1, &n2);
-		} else {
-			p1 = gins(AEOR, &n2, &n2);
-			p2 = gregshift(AMOVW, &n2, SHIFT_LR, &n1, &n2);
-		}
-		p1->scond = C_SCOND_HS;
-		p2->scond = C_SCOND_LO;
-	} else {
-		p1 = gins(AEOR, &n2, &n2);
-		p2 = gregshift(AMOVW, &n2, SHIFT_LL, &n1, &n2);
-		p1->scond = C_SCOND_HS;
-		p2->scond = C_SCOND_LO;
-	}
-	regfree(&n3);
-
-	patch(p3, pc);
-	// Left-shift of smaller word must be sign/zero-extended.
-	if(w < 32 && op == OLSH)
-		gins(optoas(OAS, nl->type), &n2, &n2);
-	gmove(&n2, res);
-
-	regfree(&n1);
-	regfree(&n2);
-}
-
-void
-clearfat(Node *nl)
-{
-	uint32 w, c, q;
-	Node dst, nc, nz, end, r0, r1, *f;
-	Prog *p, *pl;
-
-	/* clear a fat object */
-	if(debug['g'])
-		dump("\nclearfat", nl);
-
-	w = nl->type->width;
-	// Avoid taking the address for simple enough types.
-	if(componentgen(N, nl))
-		return;
-
-	c = w % 4;	// bytes
-	q = w / 4;	// quads
-
-	r0.op = OREGISTER;
-	r0.val.u.reg = REGALLOC_R0;
-	r1.op = OREGISTER;
-	r1.val.u.reg = REGALLOC_R0 + 1;
-	regalloc(&dst, types[tptr], &r1);
-	agen(nl, &dst);
-	nodconst(&nc, types[TUINT32], 0);
-	regalloc(&nz, types[TUINT32], &r0);
-	cgen(&nc, &nz);
-
-	if(q > 128) {
-		regalloc(&end, types[tptr], N);
-		p = gins(AMOVW, &dst, &end);
-		p->from.type = D_CONST;
-		p->from.offset = q*4;
-
-		p = gins(AMOVW, &nz, &dst);
-		p->to.type = D_OREG;
-		p->to.offset = 4;
-		p->scond |= C_PBIT;
-		pl = p;
-
-		p = gins(ACMP, &dst, N);
-		raddr(&end, p);
-		patch(gbranch(ABNE, T, 0), pl);
-
-		regfree(&end);
-	} else if(q >= 4 && !nacl) {
-		f = sysfunc("duffzero");
-		p = gins(ADUFFZERO, N, f);
-		afunclit(&p->to, f);
-		// 4 and 128 = magic constants: see ../../runtime/asm_arm.s
-		p->to.offset = 4*(128-q);
-	} else
-	while(q > 0) {
-		p = gins(AMOVW, &nz, &dst);
-		p->to.type = D_OREG;
-		p->to.offset = 4;
- 		p->scond |= C_PBIT;
-//print("1. %P\n", p);
-		q--;
-	}
-
-	while(c > 0) {
-		p = gins(AMOVB, &nz, &dst);
-		p->to.type = D_OREG;
-		p->to.offset = 1;
- 		p->scond |= C_PBIT;
-//print("2. %P\n", p);
-		c--;
-	}
-	regfree(&dst);
-	regfree(&nz);
-}
-
-// Called after regopt and peep have run.
-// Expand CHECKNIL pseudo-op into actual nil pointer check.
-void
-expandchecks(Prog *firstp)
-{
-	int reg;
-	Prog *p, *p1;
-
-	for(p = firstp; p != P; p = p->link) {
-		if(p->as != ACHECKNIL)
-			continue;
-		if(debug_checknil && p->lineno > 1) // p->lineno==1 in generated wrappers
-			warnl(p->lineno, "generated nil check");
-		if(p->from.type != D_REG)
-			fatal("invalid nil check %P", p);
-		reg = p->from.reg;
-		// check is
-		//	CMP arg, $0
-		//	MOV.EQ arg, 0(arg)
-		p1 = mal(sizeof *p1);
-		clearp(p1);
-		p1->link = p->link;
-		p->link = p1;
-		p1->lineno = p->lineno;
-		p1->pc = 9999;
-		p1->as = AMOVW;
-		p1->from.type = D_REG;
-		p1->from.reg = reg;
-		p1->to.type = D_OREG;
-		p1->to.reg = reg;
-		p1->to.offset = 0;
-		p1->scond = C_SCOND_EQ;
-		p->as = ACMP;
-		p->from.type = D_CONST;
-		p->from.reg = NREG;
-		p->from.offset = 0;
-		p->reg = reg;
-	}
-}
diff --git a/src/cmd/5g/gobj.c b/src/cmd/5g/gobj.c
deleted file mode 100644
index 5e98887..0000000
--- a/src/cmd/5g/gobj.c
+++ /dev/null
@@ -1,252 +0,0 @@
-// Derived from Inferno utils/5c/swt.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5c/swt.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include <u.h>
-#include <libc.h>
-#include "gg.h"
-
-int
-dsname(Sym *sym, int off, char *t, int n)
-{
-	Prog *p;
-
-	p = gins(ADATA, N, N);
-	p->from.type = D_OREG;
-	p->from.name = D_EXTERN;
-	p->from.etype = TINT32;
-	p->from.offset = off;
-	p->from.reg = NREG;
-	p->from.sym = linksym(sym);
-	
-	p->reg = n;
-	
-	p->to.type = D_SCONST;
-	p->to.name = D_NONE;
-	p->to.reg = NREG;
-	p->to.offset = 0;
-	memmove(p->to.u.sval, t, n);
-	return off + n;
-}
-
-/*
- * make a refer to the data s, s+len
- * emitting DATA if needed.
- */
-void
-datastring(char *s, int len, Addr *a)
-{
-	Sym *sym;
-	
-	sym = stringsym(s, len);
-	a->type = D_OREG;
-	a->name = D_EXTERN;
-	a->etype = TINT32;
-	a->offset = widthptr+4;  // skip header
-	a->reg = NREG;
-	a->sym = linksym(sym);
-	a->node = sym->def;
-}
-
-/*
- * make a refer to the string sval,
- * emitting DATA if needed.
- */
-void
-datagostring(Strlit *sval, Addr *a)
-{
-	Sym *sym;
-	
-	sym = stringsym(sval->s, sval->len);
-	a->type = D_OREG;
-	a->name = D_EXTERN;
-	a->etype = TINT32;
-	a->offset = 0;  // header
-	a->reg = NREG;
-	a->sym = linksym(sym);
-	a->node = sym->def;
-}
-
-void
-gdata(Node *nam, Node *nr, int wid)
-{
-	Prog *p;
-	vlong v;
-
-	if(nr->op == OLITERAL) {
-		switch(nr->val.ctype) {
-		case CTCPLX:
-			gdatacomplex(nam, nr->val.u.cval);
-			return;
-		case CTSTR:
-			gdatastring(nam, nr->val.u.sval);
-			return;
-		}
-	}
-
-	if(wid == 8 && is64(nr->type)) {
-		v = mpgetfix(nr->val.u.xval);
-		p = gins(ADATA, nam, nodintconst(v));
-		p->reg = 4;
-		p = gins(ADATA, nam, nodintconst(v>>32));
-		p->reg = 4;
-		p->from.offset += 4;
-		return;
-	}
-	p = gins(ADATA, nam, nr);
-	p->reg = wid;
-}
-
-void
-gdatacomplex(Node *nam, Mpcplx *cval)
-{
-	Prog *p;
-	int w;
-
-	w = cplxsubtype(nam->type->etype);
-	w = types[w]->width;
-
-	p = gins(ADATA, nam, N);
-	p->reg = w;
-	p->to.type = D_FCONST;
-	p->to.u.dval = mpgetflt(&cval->real);
-
-	p = gins(ADATA, nam, N);
-	p->reg = w;
-	p->from.offset += w;
-	p->to.type = D_FCONST;
-	p->to.u.dval = mpgetflt(&cval->imag);
-}
-
-void
-gdatastring(Node *nam, Strlit *sval)
-{
-	Prog *p;
-	Node nod1;
-
-	p = gins(ADATA, nam, N);
-	datastring(sval->s, sval->len, &p->to);
-	p->reg = types[tptr]->width;
-	p->to.type = D_CONST;
-	p->to.etype = TINT32;
-//print("%P\n", p);
-
-	nodconst(&nod1, types[TINT32], sval->len);
-	p = gins(ADATA, nam, &nod1);
-	p->reg = types[TINT32]->width;
-	p->from.offset += types[tptr]->width;
-}
-
-int
-dstringptr(Sym *s, int off, char *str)
-{
-	Prog *p;
-
-	off = rnd(off, widthptr);
-	p = gins(ADATA, N, N);
-	p->from.type = D_OREG;
-	p->from.name = D_EXTERN;
-	p->from.sym = linksym(s);
-	p->from.offset = off;
-	p->reg = widthptr;
-
-	datastring(str, strlen(str)+1, &p->to);
-	p->to.type = D_CONST;
-	p->to.etype = TINT32;
-	off += widthptr;
-
-	return off;
-}
-
-int
-dgostrlitptr(Sym *s, int off, Strlit *lit)
-{
-	Prog *p;
-
-	if(lit == nil)
-		return duintptr(s, off, 0);
-
-	off = rnd(off, widthptr);
-	p = gins(ADATA, N, N);
-	p->from.type = D_OREG;
-	p->from.name = D_EXTERN;
-	p->from.sym = linksym(s);
-	p->from.offset = off;
-	p->reg = widthptr;
-	datagostring(lit, &p->to);
-	p->to.type = D_CONST;
-	p->to.etype = TINT32;
-	off += widthptr;
-
-	return off;
-}
-
-int
-dgostringptr(Sym *s, int off, char *str)
-{
-	int n;
-	Strlit *lit;
-
-	if(str == nil)
-		return duintptr(s, off, 0);
-
-	n = strlen(str);
-	lit = mal(sizeof *lit + n);
-	strcpy(lit->s, str);
-	lit->len = n;
-	return dgostrlitptr(s, off, lit);
-}
-
-int
-dsymptr(Sym *s, int off, Sym *x, int xoff)
-{
-	Prog *p;
-
-	off = rnd(off, widthptr);
-
-	p = gins(ADATA, N, N);
-	p->from.type = D_OREG;
-	p->from.name = D_EXTERN;
-	p->from.sym = linksym(s);
-	p->from.offset = off;
-	p->reg = widthptr;
-	p->to.type = D_CONST;
-	p->to.name = D_EXTERN;
-	p->to.sym = linksym(x);
-	p->to.offset = xoff;
-	off += widthptr;
-
-	return off;
-}
-
-void
-nopout(Prog *p)
-{
-	p->as = ANOP;
-}
diff --git a/src/cmd/5g/gsubr.c b/src/cmd/5g/gsubr.c
deleted file mode 100644
index 06e274e..0000000
--- a/src/cmd/5g/gsubr.c
+++ /dev/null
@@ -1,2082 +0,0 @@
-// Derived from Inferno utils/5c/txt.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5c/txt.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include <u.h>
-#include <libc.h>
-#include "gg.h"
-#include "../../runtime/funcdata.h"
-
-// TODO(rsc): Can make this bigger if we move
-// the text segment up higher in 5l for all GOOS.
-// At the same time, can raise StackBig in ../../runtime/stack.h.
-long unmappedzero = 4096;
-
-void
-clearp(Prog *p)
-{
-	p->as = AEND;
-	p->reg = NREG;
-	p->scond = C_SCOND_NONE;
-	p->from.type = D_NONE;
-	p->from.name = D_NONE;
-	p->from.reg = NREG;
-	p->to.type = D_NONE;
-	p->to.name = D_NONE;
-	p->to.reg = NREG;
-	p->pc = pcloc;
-	pcloc++;
-}
-
-static int ddumped;
-static Prog *dfirst;
-static Prog *dpc;
-
-/*
- * generate and return proc with p->as = as,
- * linked into program.  pc is next instruction.
- */
-Prog*
-prog(int as)
-{
-	Prog *p;
-
-	if(as == ADATA || as == AGLOBL) {
-		if(ddumped)
-			fatal("already dumped data");
-		if(dpc == nil) {
-			dpc = mal(sizeof(*dpc));
-			dfirst = dpc;
-		}
-		p = dpc;
-		dpc = mal(sizeof(*dpc));
-		p->link = dpc;
-		p->reg = 0;  // used for flags
-	} else {
-		p = pc;
-		pc = mal(sizeof(*pc));
-		clearp(pc);
-		p->link = pc;
-	}
-
-	if(lineno == 0) {
-		if(debug['K'])
-			warn("prog: line 0");
-	}
-
-	p->as = as;
-	p->lineno = lineno;
-	return p;
-}
-
-void
-dumpdata(void)
-{
-	ddumped = 1;
-	if(dfirst == nil)
-		return;
-	newplist();
-	*pc = *dfirst;
-	pc = dpc;
-	clearp(pc);
-}
-
-/*
- * generate a branch.
- * t is ignored.
- * likely values are for branch prediction:
- *	-1 unlikely
- *	0 no opinion
- *	+1 likely
- */
-Prog*
-gbranch(int as, Type *t, int likely)
-{
-	Prog *p;
-
-	USED(t);
-	USED(likely);  // TODO: record this for linker
-
-	p = prog(as);
-	p->to.type = D_BRANCH;
-	p->to.u.branch = P;
-	return p;
-}
-
-/*
- * patch previous branch to jump to to.
- */
-void
-patch(Prog *p, Prog *to)
-{
-	if(p->to.type != D_BRANCH)
-		fatal("patch: not a branch");
-	p->to.u.branch = to;
-	p->to.offset = to->pc;
-}
-
-Prog*
-unpatch(Prog *p)
-{
-	Prog *q;
-
-	if(p->to.type != D_BRANCH)
-		fatal("unpatch: not a branch");
-	q = p->to.u.branch;
-	p->to.u.branch = P;
-	p->to.offset = 0;
-	return q;
-}
-
-/*
- * start a new Prog list.
- */
-Plist*
-newplist(void)
-{
-	Plist *pl;
-
-	pl = linknewplist(ctxt);
-
-	pc = mal(sizeof(*pc));
-	clearp(pc);
-	pl->firstpc = pc;
-
-	return pl;
-}
-
-void
-gused(Node *n)
-{
-	gins(ANOP, n, N);	// used
-}
-
-Prog*
-gjmp(Prog *to)
-{
-	Prog *p;
-
-	p = gbranch(AB, T, 0);
-	if(to != P)
-		patch(p, to);
-	return p;
-}
-
-void
-ggloblnod(Node *nam)
-{
-	Prog *p;
-
-	p = gins(AGLOBL, nam, N);
-	p->lineno = nam->lineno;
-	p->from.sym->gotype = linksym(ngotype(nam));
-	p->to.sym = nil;
-	p->to.type = D_CONST;
-	p->to.offset = nam->type->width;
-	if(nam->readonly)
-		p->reg = RODATA;
-	if(nam->type != T && !haspointers(nam->type))
-		p->reg |= NOPTR;
-}
-
-void
-ggloblsym(Sym *s, int32 width, int8 flags)
-{
-	Prog *p;
-
-	p = gins(AGLOBL, N, N);
-	p->from.type = D_OREG;
-	p->from.name = D_EXTERN;
-	p->from.sym = linksym(s);
-	p->to.type = D_CONST;
-	p->to.name = D_NONE;
-	p->to.offset = width;
-	p->reg = flags;
-}
-
-void
-gtrack(Sym *s)
-{
-	Prog *p;
-	
-	p = gins(AUSEFIELD, N, N);
-	p->from.type = D_OREG;
-	p->from.name = D_EXTERN;
-	p->from.sym = linksym(s);
-}
-
-int
-isfat(Type *t)
-{
-	if(t != T)
-	switch(t->etype) {
-	case TSTRUCT:
-	case TARRAY:
-	case TSTRING:
-	case TINTER:	// maybe remove later
-		return 1;
-	}
-	return 0;
-}
-
-/*
- * naddr of func generates code for address of func.
- * if using opcode that can take address implicitly,
- * call afunclit to fix up the argument.
- * also fix up direct register references to be D_OREG.
- */
-void
-afunclit(Addr *a, Node *n)
-{
-	if(a->type == D_CONST && a->name == D_EXTERN || a->type == D_REG) {
-		a->type = D_OREG;
-		if(n->op == ONAME)
-			a->sym = linksym(n->sym);
-	}
-}
-
-static	int	resvd[] =
-{
-	9,     // reserved for m
-	10,    // reserved for g
-	REGSP, // reserved for SP
-};
-
-void
-ginit(void)
-{
-	int i;
-
-	for(i=0; i<nelem(reg); i++)
-		reg[i] = 0;
-	for(i=0; i<nelem(resvd); i++)
-		reg[resvd[i]]++;
-}
-
-void
-gclean(void)
-{
-	int i;
-
-	for(i=0; i<nelem(resvd); i++)
-		reg[resvd[i]]--;
-
-	for(i=0; i<nelem(reg); i++)
-		if(reg[i])
-			yyerror("reg %R left allocated\n", i);
-}
-
-int32
-anyregalloc(void)
-{
-	int i, j;
-
-	for(i=0; i<nelem(reg); i++) {
-		if(reg[i] == 0)
-			goto ok;
-		for(j=0; j<nelem(resvd); j++)
-			if(resvd[j] == i)
-				goto ok;
-		return 1;
-	ok:;
-	}
-	return 0;
-}
-
-uintptr regpc[REGALLOC_FMAX+1];
-
-/*
- * allocate register of type t, leave in n.
- * if o != N, o is desired fixed register.
- * caller must regfree(n).
- */
-void
-regalloc(Node *n, Type *t, Node *o)
-{
-	int i, et, fixfree, floatfree;
-
-	if(0 && debug['r']) {
-		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++;
-		print("regalloc fix %d float %d\n", fixfree, floatfree);
-	}
-
-	if(t == T)
-		fatal("regalloc: t nil");
-	et = simtype[t->etype];
-	if(is64(t))
-		fatal("regalloc: 64 bit type %T");
-
-	switch(et) {
-	case TINT8:
-	case TUINT8:
-	case TINT16:
-	case TUINT16:
-	case TINT32:
-	case TUINT32:
-	case TPTR32:
-	case TBOOL:
-		if(o != N && o->op == OREGISTER) {
-			i = 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] = (uintptr)getcallerpc(&n);
-				goto out;
-			}
-		print("registers allocated at\n");
-		for(i=REGALLOC_R0; i<=REGALLOC_RMAX; i++)
-			print("%d %p\n", i, regpc[i]);
-		fatal("out of fixed registers");
-		goto err;
-
-	case TFLOAT32:
-	case TFLOAT64:
-		if(o != N && o->op == OREGISTER) {
-			i = 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;
-		fatal("out of floating point registers");
-		goto err;
-
-	case TCOMPLEX64:
-	case TCOMPLEX128:
-		tempname(n, t);
-		return;
-	}
-	yyerror("regalloc: unknown type %T", t);
-
-err:
-	nodreg(n, t, 0);
-	return;
-
-out:
-	reg[i]++;
-	nodreg(n, t, i);
-}
-
-void
-regfree(Node *n)
-{
-	int i, fixfree, floatfree;
-
-	if(0 && debug['r']) {
-		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++;
-		print("regalloc fix %d float %d\n", fixfree, floatfree);
-	}
-
-	if(n->op == ONAME)
-		return;
-	if(n->op != OREGISTER && n->op != OINDREG)
-		fatal("regfree: not a register");
-	i = n->val.u.reg;
-	if(i == REGSP)
-		return;
-	if(i < 0 || i >= nelem(reg) || i >= nelem(regpc))
-		fatal("regfree: reg out of range");
-	if(reg[i] <= 0)
-		fatal("regfree: reg %R not allocated", i);
-	reg[i]--;
-	if(reg[i] == 0)
-		regpc[i] = 0;
-}
-
-/*
- * initialize n to be register r of type t.
- */
-void
-nodreg(Node *n, Type *t, int r)
-{
-	if(t == T)
-		fatal("nodreg: t nil");
-
-	memset(n, 0, sizeof(*n));
-	n->op = OREGISTER;
-	n->addable = 1;
-	ullmancalc(n);
-	n->val.u.reg = r;
-	n->type = t;
-}
-
-/*
- * initialize n to be indirect of register r; n is type t.
- */
-void
-nodindreg(Node *n, Type *t, int r)
-{
-	nodreg(n, t, r);
-	n->op = OINDREG;
-}
-
-Node*
-nodarg(Type *t, int fp)
-{
-	Node *n;
-	NodeList *l;
-	Type *first;
-	Iter savet;
-
-	// entire argument struct, not just one arg
-	if(t->etype == TSTRUCT && t->funarg) {
-		n = nod(ONAME, N, N);
-		n->sym = lookup(".args");
-		n->type = t;
-		first = structfirst(&savet, &t);
-		if(first == nil)
-			fatal("nodarg: bad struct");
-		if(first->width == BADWIDTH)
-			fatal("nodarg: offset not computed for %T", t);
-		n->xoffset = first->width;
-		n->addable = 1;
-		goto fp;
-	}
-
-	if(t->etype != TFIELD)
-		fatal("nodarg: not field %T", t);
-
-	if(fp == 1) {
-		for(l=curfn->dcl; l; l=l->next) {
-			n = l->n;
-			if((n->class == PPARAM || n->class == PPARAMOUT) && !isblanksym(t->sym) && n->sym == t->sym)
-				return n;
-		}
-	}
-
-	n = nod(ONAME, N, N);
-	n->type = t->type;
-	n->sym = t->sym;
-	if(t->width == BADWIDTH)
-		fatal("nodarg: offset not computed for %T", t);
-	n->xoffset = t->width;
-	n->addable = 1;
-	n->orig = t->nname;
-
-fp:
-	// Rewrite argument named _ to __,
-	// or else the assignment to _ will be
-	// discarded during code generation.
-	if(isblank(n))
-		n->sym = lookup("__");
-
-	switch(fp) {
-	default:
-		fatal("nodarg %T %d", t, fp);
-
-	case 0:		// output arg for calling another function
-		n->op = OINDREG;
-		n->val.u.reg = REGSP;
-		n->xoffset += 4;
-		break;
-
-	case 1:		// input arg to current function
-		n->class = PPARAM;
-		break;
-	}
-	n->typecheck = 1;
-	return n;
-}
-
-/*
- * return constant i node.
- * overwritten by next call, but useful in calls to gins.
- */
-Node*
-ncon(uint32 i)
-{
-	static Node n;
-
-	if(n.type == T)
-		nodconst(&n, types[TUINT32], 0);
-	mpmovecfix(n.val.u.xval, i);
-	return &n;
-}
-
-/*
- * Is this node a memory operand?
- */
-int
-ismem(Node *n)
-{
-	switch(n->op) {
-	case OINDREG:
-	case ONAME:
-	case OPARAM:
-	case OCLOSUREVAR:
-		return 1;
-	}
-	return 0;
-}
-
-Node sclean[10];
-int nsclean;
-
-/*
- * n is a 64-bit value.  fill in lo and hi to refer to its 32-bit halves.
- */
-void
-split64(Node *n, Node *lo, Node *hi)
-{
-	Node n1;
-	int64 i;
-
-	if(!is64(n->type))
-		fatal("split64 %T", n->type);
-
-	if(nsclean >= nelem(sclean))
-		fatal("split64 clean");
-	sclean[nsclean].op = OEMPTY;
-	nsclean++;
-	switch(n->op) {
-	default:
-		if(!dotaddable(n, &n1)) {
-			igen(n, &n1, N);
-			sclean[nsclean-1] = n1;
-		}
-		n = &n1;
-		goto common;
-	case ONAME:
-		if(n->class == PPARAMREF) {
-			cgen(n->heapaddr, &n1);
-			sclean[nsclean-1] = n1;
-			// fall through.
-			n = &n1;
-		}
-		goto common;
-	case OINDREG:
-	common:
-		*lo = *n;
-		*hi = *n;
-		lo->type = types[TUINT32];
-		if(n->type->etype == TINT64)
-			hi->type = types[TINT32];
-		else
-			hi->type = types[TUINT32];
-		hi->xoffset += 4;
-		break;
-
-	case OLITERAL:
-		convconst(&n1, n->type, &n->val);
-		i = mpgetfix(n1.val.u.xval);
-		nodconst(lo, types[TUINT32], (uint32)i);
-		i >>= 32;
-		if(n->type->etype == TINT64)
-			nodconst(hi, types[TINT32], (int32)i);
-		else
-			nodconst(hi, types[TUINT32], (uint32)i);
-		break;
-	}
-}
-
-void
-splitclean(void)
-{
-	if(nsclean <= 0)
-		fatal("splitclean");
-	nsclean--;
-	if(sclean[nsclean].op != OEMPTY)
-		regfree(&sclean[nsclean]);
-}
-
-#define	CASE(a,b)	(((a)<<16)|((b)<<0))
-/*c2go int CASE(int, int); */
-
-void
-gmove(Node *f, Node *t)
-{
-	int a, ft, tt, fa, ta;
-	Type *cvt;
-	Node r1, r2, flo, fhi, tlo, thi, con;
-	Prog *p1;
-
-	if(debug['M'])
-		print("gmove %N -> %N\n", f, t);
-
-	ft = simsimtype(f->type);
-	tt = simsimtype(t->type);
-	cvt = t->type;
-
-	if(iscomplex[ft] || iscomplex[tt]) {
-		complexmove(f, t);
-		return;
-	}
-
-	// cannot have two memory operands;
-	// except 64-bit, which always copies via registers anyway.
-	if(!is64(f->type) && !is64(t->type) && ismem(f) && ismem(t))
-		goto hard;
-
-	// convert constant to desired type
-	if(f->op == OLITERAL) {
-		switch(tt) {
-		default:
-			convconst(&con, t->type, &f->val);
-			break;
-
-		case TINT16:
-		case TINT8:
-			convconst(&con, types[TINT32], &f->val);
-			regalloc(&r1, con.type, t);
-			gins(AMOVW, &con, &r1);
-			gmove(&r1, t);
-			regfree(&r1);
-			return;
-
-		case TUINT16:
-		case TUINT8:
-			convconst(&con, types[TUINT32], &f->val);
-			regalloc(&r1, con.type, t);
-			gins(AMOVW, &con, &r1);
-			gmove(&r1, t);
-			regfree(&r1);
-			return;
-		}
-
-		f = &con;
-		ft = simsimtype(con.type);
-
-		// constants can't move directly to memory
-		if(ismem(t) && !is64(t->type)) 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(CASE(ft, tt)) {
-	default:
-		goto fatal;
-
-	/*
-	 * integer copy and truncate
-	 */
-	case CASE(TINT8, TINT8):	// same size
-		if(!ismem(f)) {
-			a = AMOVB;
-			break;
-		}
-	case CASE(TUINT8, TINT8):
-	case CASE(TINT16, TINT8):	// truncate
-	case CASE(TUINT16, TINT8):
-	case CASE(TINT32, TINT8):
-	case CASE(TUINT32, TINT8):
-		a = AMOVBS;
-		break;
-
-	case CASE(TUINT8, TUINT8):
-		if(!ismem(f)) {
-			a = AMOVB;
-			break;
-		}
-	case CASE(TINT8, TUINT8):
-	case CASE(TINT16, TUINT8):
-	case CASE(TUINT16, TUINT8):
-	case CASE(TINT32, TUINT8):
-	case CASE(TUINT32, TUINT8):
-		a = AMOVBU;
-		break;
-
-	case CASE(TINT64, TINT8):	// truncate low word
-	case CASE(TUINT64, TINT8):
-		a = AMOVBS;
-		goto trunc64;
-
-	case CASE(TINT64, TUINT8):
-	case CASE(TUINT64, TUINT8):
-		a = AMOVBU;
-		goto trunc64;
-
-	case CASE(TINT16, TINT16):	// same size
-		if(!ismem(f)) {
-			a = AMOVH;
-			break;
-		}
-	case CASE(TUINT16, TINT16):
-	case CASE(TINT32, TINT16):	// truncate
-	case CASE(TUINT32, TINT16):
-		a = AMOVHS;
-		break;
-
-	case CASE(TUINT16, TUINT16):
-		if(!ismem(f)) {
-			a = AMOVH;
-			break;
-		}
-	case CASE(TINT16, TUINT16):
-	case CASE(TINT32, TUINT16):
-	case CASE(TUINT32, TUINT16):
-		a = AMOVHU;
-		break;
-
-	case CASE(TINT64, TINT16):	// truncate low word
-	case CASE(TUINT64, TINT16):
-		a = AMOVHS;
-		goto trunc64;
-
-	case CASE(TINT64, TUINT16):
-	case CASE(TUINT64, TUINT16):
-		a = AMOVHU;
-		goto trunc64;
-
-	case CASE(TINT32, TINT32):	// same size
-	case CASE(TINT32, TUINT32):
-	case CASE(TUINT32, TINT32):
-	case CASE(TUINT32, TUINT32):
-		a = AMOVW;
-		break;
-
-	case CASE(TINT64, TINT32):	// truncate
-	case CASE(TUINT64, TINT32):
-	case CASE(TINT64, TUINT32):
-	case CASE(TUINT64, TUINT32):
-		split64(f, &flo, &fhi);
-		regalloc(&r1, t->type, N);
-		gins(AMOVW, &flo, &r1);
-		gins(AMOVW, &r1, t);
-		regfree(&r1);
-		splitclean();
-		return;
-
-	case CASE(TINT64, TINT64):	// same size
-	case CASE(TINT64, TUINT64):
-	case CASE(TUINT64, TINT64):
-	case CASE(TUINT64, TUINT64):
-		split64(f, &flo, &fhi);
-		split64(t, &tlo, &thi);
-		regalloc(&r1, flo.type, N);
-		regalloc(&r2, fhi.type, N);
-		gins(AMOVW, &flo, &r1);
-		gins(AMOVW, &fhi, &r2);
-		gins(AMOVW, &r1, &tlo);
-		gins(AMOVW, &r2, &thi);
-		regfree(&r1);
-		regfree(&r2);
-		splitclean();
-		splitclean();
-		return;
-
-	/*
-	 * integer up-conversions
-	 */
-	case CASE(TINT8, TINT16):	// sign extend int8
-	case CASE(TINT8, TUINT16):
-	case CASE(TINT8, TINT32):
-	case CASE(TINT8, TUINT32):
-		a = AMOVBS;
-		goto rdst;
-	case CASE(TINT8, TINT64):	// convert via int32
-	case CASE(TINT8, TUINT64):
-		cvt = types[TINT32];
-		goto hard;
-
-	case CASE(TUINT8, TINT16):	// zero extend uint8
-	case CASE(TUINT8, TUINT16):
-	case CASE(TUINT8, TINT32):
-	case CASE(TUINT8, TUINT32):
-		a = AMOVBU;
-		goto rdst;
-	case CASE(TUINT8, TINT64):	// convert via uint32
-	case CASE(TUINT8, TUINT64):
-		cvt = types[TUINT32];
-		goto hard;
-
-	case CASE(TINT16, TINT32):	// sign extend int16
-	case CASE(TINT16, TUINT32):
-		a = AMOVHS;
-		goto rdst;
-	case CASE(TINT16, TINT64):	// convert via int32
-	case CASE(TINT16, TUINT64):
-		cvt = types[TINT32];
-		goto hard;
-
-	case CASE(TUINT16, TINT32):	// zero extend uint16
-	case CASE(TUINT16, TUINT32):
-		a = AMOVHU;
-		goto rdst;
-	case CASE(TUINT16, TINT64):	// convert via uint32
-	case CASE(TUINT16, TUINT64):
-		cvt = types[TUINT32];
-		goto hard;
-
-	case CASE(TINT32, TINT64):	// sign extend int32
-	case CASE(TINT32, TUINT64):
-		split64(t, &tlo, &thi);
-		regalloc(&r1, tlo.type, N);
-		regalloc(&r2, thi.type, N);
-		gmove(f, &r1);
-		p1 = gins(AMOVW, &r1, &r2);
-		p1->from.type = D_SHIFT;
-		p1->from.offset = 2 << 5 | 31 << 7 | r1.val.u.reg; // r1->31
-		p1->from.reg = NREG;
-//print("gmove: %P\n", p1);
-		gins(AMOVW, &r1, &tlo);
-		gins(AMOVW, &r2, &thi);
-		regfree(&r1);
-		regfree(&r2);
-		splitclean();
-		return;
-
-	case CASE(TUINT32, TINT64):	// zero extend uint32
-	case CASE(TUINT32, TUINT64):
-		split64(t, &tlo, &thi);
-		gmove(f, &tlo);
-		regalloc(&r1, thi.type, N);
-		gins(AMOVW, ncon(0), &r1);
-		gins(AMOVW, &r1, &thi);
-		regfree(&r1);
-		splitclean();
-		return;
-
-	/*
-	* float to integer
-	*/
-	case CASE(TFLOAT32, TINT8):
-	case CASE(TFLOAT32, TUINT8):
-	case CASE(TFLOAT32, TINT16):
-	case CASE(TFLOAT32, TUINT16):
-	case CASE(TFLOAT32, TINT32):
-	case CASE(TFLOAT32, TUINT32):
-//	case CASE(TFLOAT32, TUINT64):
-
-	case CASE(TFLOAT64, TINT8):
-	case CASE(TFLOAT64, TUINT8):
-	case CASE(TFLOAT64, TINT16):
-	case CASE(TFLOAT64, TUINT16):
-	case CASE(TFLOAT64, TINT32):
-	case CASE(TFLOAT64, TUINT32):
-//	case CASE(TFLOAT64, TUINT64):
-		fa = AMOVF;
-		a = AMOVFW;
-		if(ft == TFLOAT64) {
-			fa = AMOVD;
-			a = AMOVDW;
-		}
-		ta = AMOVW;
-		switch(tt) {
-		case TINT8:
-			ta = AMOVBS;
-			break;
-		case TUINT8:
-			ta = AMOVBU;
-			break;
-		case TINT16:
-			ta = AMOVHS;
-			break;
-		case TUINT16:
-			ta = AMOVHU;
-			break;
-		}
-
-		regalloc(&r1, types[ft], f);
-		regalloc(&r2, types[tt], t);
-		gins(fa, f, &r1);	// load to fpu
-		p1 = gins(a, &r1, &r1);	// convert to w
-		switch(tt) {
-		case TUINT8:
-		case TUINT16:
-		case TUINT32:
-			p1->scond |= C_UBIT;
-		}
-		gins(AMOVW, &r1, &r2);	// copy to cpu
-		gins(ta, &r2, t);	// store
-		regfree(&r1);
-		regfree(&r2);
-		return;
-
-	/*
-	 * integer to float
-	 */
-	case CASE(TINT8, TFLOAT32):
-	case CASE(TUINT8, TFLOAT32):
-	case CASE(TINT16, TFLOAT32):
-	case CASE(TUINT16, TFLOAT32):
-	case CASE(TINT32, TFLOAT32):
-	case CASE(TUINT32, TFLOAT32):
-	case CASE(TINT8, TFLOAT64):
-	case CASE(TUINT8, TFLOAT64):
-	case CASE(TINT16, TFLOAT64):
-	case CASE(TUINT16, TFLOAT64):
-	case CASE(TINT32, TFLOAT64):
-	case CASE(TUINT32, TFLOAT64):
-		fa = AMOVW;
-		switch(ft) {
-		case TINT8:
-			fa = AMOVBS;
-			break;
-		case TUINT8:
-			fa = AMOVBU;
-			break;
-		case TINT16:
-			fa = AMOVHS;
-			break;
-		case TUINT16:
-			fa = AMOVHU;
-			break;
-		}
-		a = AMOVWF;
-		ta = AMOVF;
-		if(tt == TFLOAT64) {
-			a = AMOVWD;
-			ta = AMOVD;
-		}
-		regalloc(&r1, types[ft], f);
-		regalloc(&r2, types[tt], t);
-		gins(fa, f, &r1);	// load to cpu
-		gins(AMOVW, &r1, &r2);	// copy to fpu
-		p1 = gins(a, &r2, &r2);	// convert
-		switch(ft) {
-		case TUINT8:
-		case TUINT16:
-		case TUINT32:
-			p1->scond |= C_UBIT;
-		}
-		gins(ta, &r2, t);	// store
-		regfree(&r1);
-		regfree(&r2);
-		return;
-
-	case CASE(TUINT64, TFLOAT32):
-	case CASE(TUINT64, TFLOAT64):
-		fatal("gmove UINT64, TFLOAT not implemented");
-		return;
-
-
-	/*
-	 * float to float
-	 */
-	case CASE(TFLOAT32, TFLOAT32):
-		a = AMOVF;
-		break;
-
-	case CASE(TFLOAT64, TFLOAT64):
-		a = AMOVD;
-		break;
-
-	case CASE(TFLOAT32, TFLOAT64):
-		regalloc(&r1, types[TFLOAT64], t);
-		gins(AMOVF, f, &r1);
-		gins(AMOVFD, &r1, &r1);
-		gins(AMOVD, &r1, t);
-		regfree(&r1);
-		return;
-
-	case CASE(TFLOAT64, TFLOAT32):
-		regalloc(&r1, types[TFLOAT64], t);
-		gins(AMOVD, f, &r1);
-		gins(AMOVDF, &r1, &r1);
-		gins(AMOVF, &r1, t);
-		regfree(&r1);
-		return;
-	}
-
-	gins(a, f, t);
-	return;
-
-rdst:
-	// TODO(kaib): we almost always require a register dest anyway, this can probably be
-	// removed.
-	// requires register destination
-	regalloc(&r1, t->type, t);
-	gins(a, f, &r1);
-	gmove(&r1, t);
-	regfree(&r1);
-	return;
-
-hard:
-	// requires register intermediate
-	regalloc(&r1, cvt, t);
-	gmove(f, &r1);
-	gmove(&r1, t);
-	regfree(&r1);
-	return;
-
-trunc64:
-	// truncate 64 bit integer
-	split64(f, &flo, &fhi);
-	regalloc(&r1, t->type, N);
-	gins(a, &flo, &r1);
-	gins(a, &r1, t);
-	regfree(&r1);
-	splitclean();
-	return;
-
-fatal:
-	// should not happen
-	fatal("gmove %N -> %N", f, t);
-}
-
-int
-samaddr(Node *f, Node *t)
-{
-
-	if(f->op != t->op)
-		return 0;
-
-	switch(f->op) {
-	case OREGISTER:
-		if(f->val.u.reg != t->val.u.reg)
-			break;
-		return 1;
-	}
-	return 0;
-}
-
-/*
- * generate one instruction:
- *	as f, t
- */
-Prog*
-gins(int as, Node *f, Node *t)
-{
-//	Node nod;
-//	int32 v;
-	Prog *p;
-	Addr af, at;
-
-	if(f != N && f->op == OINDEX) {
-		fatal("gins OINDEX not implemented");
-//		regalloc(&nod, &regnode, Z);
-//		v = constnode.vconst;
-//		cgen(f->right, &nod);
-//		constnode.vconst = v;
-//		idx.reg = nod.reg;
-//		regfree(&nod);
-	}
-	if(t != N && t->op == OINDEX) {
-		fatal("gins OINDEX not implemented");
-//		regalloc(&nod, &regnode, Z);
-//		v = constnode.vconst;
-//		cgen(t->right, &nod);
-//		constnode.vconst = v;
-//		idx.reg = nod.reg;
-//		regfree(&nod);
-	}
-
-	memset(&af, 0, sizeof af);
-	memset(&at, 0, sizeof at);
-	if(f != N)
-		naddr(f, &af, 1);
-	if(t != N)
-		naddr(t, &at, 1);
-	p = prog(as);
-	if(f != N)
-		p->from = af;
-	if(t != N)
-		p->to = at;
-	if(debug['g'])
-		print("%P\n", p);
-	return p;
-}
-
-/*
- * insert n into reg slot of p
- */
-void
-raddr(Node *n, Prog *p)
-{
-	Addr a;
-
-	naddr(n, &a, 1);
-	if(a.type != D_REG && a.type != D_FREG) {
-		if(n)
-			fatal("bad in raddr: %O", n->op);
-		else
-			fatal("bad in raddr: <null>");
-		p->reg = NREG;
-	} else
-		p->reg = a.reg;
-}
-
-/* generate a comparison
-TODO(kaib): one of the args can actually be a small constant. relax the constraint and fix call sites.
- */
-Prog*
-gcmp(int as, Node *lhs, Node *rhs)
-{
-	Prog *p;
-
-	if(lhs->op != OREGISTER)
-		fatal("bad operands to gcmp: %O %O", lhs->op, rhs->op);
-
-	p = gins(as, rhs, N);
-	raddr(lhs, p);
-	return p;
-}
-
-/* generate a constant shift
- * arm encodes a shift by 32 as 0, thus asking for 0 shift is illegal.
-*/
-Prog*
-gshift(int as, Node *lhs, int32 stype, int32 sval, Node *rhs)
-{
-	Prog *p;
-
-	if(sval <= 0 || sval > 32)
-		fatal("bad shift value: %d", sval);
-
-	sval = sval&0x1f;
-
-	p = gins(as, N, rhs);
-	p->from.type = D_SHIFT;
-	p->from.offset = stype | sval<<7 | lhs->val.u.reg;
-	return p;
-}
-
-/* generate a register shift
-*/
-Prog *
-gregshift(int as, Node *lhs, int32 stype, Node *reg, Node *rhs)
-{
-	Prog *p;
-	p = gins(as, N, rhs);
-	p->from.type = D_SHIFT;
-	p->from.offset = stype | reg->val.u.reg << 8 | 1<<4 | lhs->val.u.reg;
-	return p;
-}
-
-/*
- * generate code to compute n;
- * make a refer to result.
- */
-void
-naddr(Node *n, Addr *a, int canemitcode)
-{
-	Sym *s;
-
-	a->type = D_NONE;
-	a->name = D_NONE;
-	a->reg = NREG;
-	a->gotype = nil;
-	a->node = N;
-	a->etype = 0;
-	if(n == N)
-		return;
-
-	if(n->type != T && n->type->etype != TIDEAL) {
-		dowidth(n->type);
-		a->width = n->type->width;
-	}
-
-	switch(n->op) {
-	default:
-		fatal("naddr: bad %O %D", n->op, a);
-		break;
-
-	case OREGISTER:
-		if(n->val.u.reg <= REGALLOC_RMAX) {
-			a->type = D_REG;
-			a->reg = n->val.u.reg;
-		} else {
-			a->type = D_FREG;
-			a->reg = n->val.u.reg - REGALLOC_F0;
-		}
-		a->sym = nil;
-		break;
-
-	case OINDEX:
-	case OIND:
-		fatal("naddr: OINDEX");
-//		naddr(n->left, a);
-//		if(a->type >= D_AX && a->type <= D_DI)
-//			a->type += D_INDIR;
-//		else
-//		if(a->type == D_CONST)
-//			a->type = D_NONE+D_INDIR;
-//		else
-//		if(a->type == D_ADDR) {
-//			a->type = a->index;
-//			a->index = D_NONE;
-//		} else
-//			goto bad;
-//		if(n->op == OINDEX) {
-//			a->index = idx.reg;
-//			a->scale = n->scale;
-//		}
-//		break;
-
-	case OINDREG:
-		a->type = D_OREG;
-		a->reg = n->val.u.reg;
-		a->sym = linksym(n->sym);
-		a->offset = n->xoffset;
-		break;
-
-	case OPARAM:
-		// n->left is PHEAP ONAME for stack parameter.
-		// compute address of actual parameter on stack.
-		a->etype = simtype[n->left->type->etype];
-		a->width = n->left->type->width;
-		a->offset = n->xoffset;
-		a->sym = linksym(n->left->sym);
-		a->type = D_OREG;
-		a->name = D_PARAM;
-		a->node = n->left->orig;
-		break;
-	
-	case OCLOSUREVAR:
-		if(!curfn->needctxt)
-			fatal("closurevar without needctxt");
-		a->type = D_OREG;
-		a->reg = 7;
-		a->offset = n->xoffset;
-		a->sym = nil;
-		break;		
-
-	case OCFUNC:
-		naddr(n->left, a, canemitcode);
-		a->sym = linksym(n->left->sym);
-		break;
-
-	case ONAME:
-		a->etype = 0;
-		a->width = 0;
-		a->reg = NREG;
-		if(n->type != T) {
-			a->etype = simtype[n->type->etype];
-			a->width = n->type->width;
-		}
-		a->offset = n->xoffset;
-		s = n->sym;
-		a->node = n->orig;
-		//if(a->node >= (Node*)&n)
-		//	fatal("stack node");
-		if(s == S)
-			s = lookup(".noname");
-		if(n->method) {
-			if(n->type != T)
-			if(n->type->sym != S)
-			if(n->type->sym->pkg != nil)
-				s = pkglookup(s->name, n->type->sym->pkg);
-		}
-
-		a->type = D_OREG;
-		switch(n->class) {
-		default:
-			fatal("naddr: ONAME class %S %d\n", n->sym, n->class);
-		case PEXTERN:
-			a->name = D_EXTERN;
-			break;
-		case PAUTO:
-			a->name = D_AUTO;
-			break;
-		case PPARAM:
-		case PPARAMOUT:
-			a->name = D_PARAM;
-			break;
-		case PFUNC:
-			a->name = D_EXTERN;
-			a->type = D_CONST;
-			s = funcsym(s);
-			break;
-		}
-		a->sym = linksym(s);
-		break;
-
-	case OLITERAL:
-		switch(n->val.ctype) {
-		default:
-			fatal("naddr: const %lT", n->type);
-			break;
-		case CTFLT:
-			a->type = D_FCONST;
-			a->u.dval = mpgetflt(n->val.u.fval);
-			break;
-		case CTINT:
-		case CTRUNE:
-			a->sym = nil;
-			a->type = D_CONST;
-			a->offset = mpgetfix(n->val.u.xval);
-			break;
-		case CTSTR:
-			datagostring(n->val.u.sval, a);
-			break;
-		case CTBOOL:
-			a->sym = nil;
-			a->type = D_CONST;
-			a->offset = n->val.u.bval;
-			break;
-		case CTNIL:
-			a->sym = nil;
-			a->type = D_CONST;
-			a->offset = 0;
-			break;
-		}
-		break;
-
-	case OITAB:
-		// itable of interface value
-		naddr(n->left, a, canemitcode);
-		a->etype = TINT32;
-		if(a->type == D_CONST && a->offset == 0)
-			break;	// len(nil)
-		break;
-
-	case OSPTR:
-		// pointer in a string or slice
-		naddr(n->left, a, canemitcode);
-		if(a->type == D_CONST && a->offset == 0)
-			break;	// ptr(nil)
-		a->etype = simtype[tptr];
-		a->offset += Array_array;
-		a->width = widthptr;
-		break;
-
-	case OLEN:
-		// len of string or slice
-		naddr(n->left, a, canemitcode);
-		a->etype = TINT32;
-		if(a->type == D_CONST && a->offset == 0)
-			break;	// len(nil)
-		a->offset += Array_nel;
-		break;
-
-	case OCAP:
-		// cap of string or slice
-		naddr(n->left, a, canemitcode);
-		a->etype = TINT32;
-		if(a->type == D_CONST && a->offset == 0)
-			break;	// cap(nil)
-		a->offset += Array_cap;
-		break;
-
-	case OADDR:
-		naddr(n->left, a, canemitcode);
-		a->etype = tptr;
-		switch(a->type) {
-		case D_OREG:
-			a->type = D_CONST;
-			break;
-
-		case D_REG:
-		case D_CONST:
-			break;
-		
-		default:
-			fatal("naddr: OADDR %d\n", a->type);
-		}
-	}
-	
-	if(a->width < 0)
-		fatal("naddr: bad width for %N -> %D", n, a);
-}
-
-/*
- * return Axxx for Oxxx on type t.
- */
-int
-optoas(int op, Type *t)
-{
-	int a;
-
-	if(t == T)
-		fatal("optoas: t is nil");
-
-	a = AGOK;
-	switch(CASE(op, simtype[t->etype])) {
-	default:
-		fatal("optoas: no entry %O-%T etype %T simtype %T", op, t, types[t->etype], types[simtype[t->etype]]);
-		break;
-
-/*	case CASE(OADDR, TPTR32):
-		a = ALEAL;
-		break;
-
-	case CASE(OADDR, TPTR64):
-		a = ALEAQ;
-		break;
-*/
-	// TODO(kaib): make sure the conditional branches work on all edge cases
-	case CASE(OEQ, TBOOL):
-	case CASE(OEQ, TINT8):
-	case CASE(OEQ, TUINT8):
-	case CASE(OEQ, TINT16):
-	case CASE(OEQ, TUINT16):
-	case CASE(OEQ, TINT32):
-	case CASE(OEQ, TUINT32):
-	case CASE(OEQ, TINT64):
-	case CASE(OEQ, TUINT64):
-	case CASE(OEQ, TPTR32):
-	case CASE(OEQ, TPTR64):
-	case CASE(OEQ, TFLOAT32):
-	case CASE(OEQ, TFLOAT64):
-		a = ABEQ;
-		break;
-
-	case CASE(ONE, TBOOL):
-	case CASE(ONE, TINT8):
-	case CASE(ONE, TUINT8):
-	case CASE(ONE, TINT16):
-	case CASE(ONE, TUINT16):
-	case CASE(ONE, TINT32):
-	case CASE(ONE, TUINT32):
-	case CASE(ONE, TINT64):
-	case CASE(ONE, TUINT64):
-	case CASE(ONE, TPTR32):
-	case CASE(ONE, TPTR64):
-	case CASE(ONE, TFLOAT32):
-	case CASE(ONE, TFLOAT64):
-		a = ABNE;
-		break;
-
-	case CASE(OLT, TINT8):
-	case CASE(OLT, TINT16):
-	case CASE(OLT, TINT32):
-	case CASE(OLT, TINT64):
-	case CASE(OLT, TFLOAT32):
-	case CASE(OLT, TFLOAT64):
-		a = ABLT;
-		break;
-
-	case CASE(OLT, TUINT8):
-	case CASE(OLT, TUINT16):
-	case CASE(OLT, TUINT32):
-	case CASE(OLT, TUINT64):
-		a = ABLO;
-		break;
-
-	case CASE(OLE, TINT8):
-	case CASE(OLE, TINT16):
-	case CASE(OLE, TINT32):
-	case CASE(OLE, TINT64):
-	case CASE(OLE, TFLOAT32):
-	case CASE(OLE, TFLOAT64):
-		a = ABLE;
-		break;
-
-	case CASE(OLE, TUINT8):
-	case CASE(OLE, TUINT16):
-	case CASE(OLE, TUINT32):
-	case CASE(OLE, TUINT64):
-		a = ABLS;
-		break;
-
-	case CASE(OGT, TINT8):
-	case CASE(OGT, TINT16):
-	case CASE(OGT, TINT32):
-	case CASE(OGT, TINT64):
-	case CASE(OGT, TFLOAT32):
-	case CASE(OGT, TFLOAT64):
-		a = ABGT;
-		break;
-
-	case CASE(OGT, TUINT8):
-	case CASE(OGT, TUINT16):
-	case CASE(OGT, TUINT32):
-	case CASE(OGT, TUINT64):
-		a = ABHI;
-		break;
-
-	case CASE(OGE, TINT8):
-	case CASE(OGE, TINT16):
-	case CASE(OGE, TINT32):
-	case CASE(OGE, TINT64):
-	case CASE(OGE, TFLOAT32):
-	case CASE(OGE, TFLOAT64):
-		a = ABGE;
-		break;
-
-	case CASE(OGE, TUINT8):
-	case CASE(OGE, TUINT16):
-	case CASE(OGE, TUINT32):
-	case CASE(OGE, TUINT64):
-		a = ABHS;
-		break;
-
-	case CASE(OCMP, TBOOL):
-	case CASE(OCMP, TINT8):
-	case CASE(OCMP, TUINT8):
-	case CASE(OCMP, TINT16):
-	case CASE(OCMP, TUINT16):
-	case CASE(OCMP, TINT32):
-	case CASE(OCMP, TUINT32):
-	case CASE(OCMP, TPTR32):
-		a = ACMP;
-		break;
-
-	case CASE(OCMP, TFLOAT32):
-		a = ACMPF;
-		break;
-
-	case CASE(OCMP, TFLOAT64):
-		a = ACMPD;
-		break;
-
-	case CASE(OAS, TBOOL):
-		a = AMOVB;
-		break;
-
-	case CASE(OAS, TINT8):
-		a = AMOVBS;
-		break;
-
-	case CASE(OAS, TUINT8):
-		a = AMOVBU;
-		break;
-
-	case CASE(OAS, TINT16):
-		a = AMOVHS;
-		break;
-
-	case CASE(OAS, TUINT16):
-		a = AMOVHU;
-		break;
-
-	case CASE(OAS, TINT32):
-	case CASE(OAS, TUINT32):
-	case CASE(OAS, TPTR32):
-		a = AMOVW;
-		break;
-
-	case CASE(OAS, TFLOAT32):
-		a = AMOVF;
-		break;
-
-	case CASE(OAS, TFLOAT64):
-		a = AMOVD;
-		break;
-
-	case CASE(OADD, TINT8):
-	case CASE(OADD, TUINT8):
-	case CASE(OADD, TINT16):
-	case CASE(OADD, TUINT16):
-	case CASE(OADD, TINT32):
-	case CASE(OADD, TUINT32):
-	case CASE(OADD, TPTR32):
-		a = AADD;
-		break;
-
-	case CASE(OADD, TFLOAT32):
-		a = AADDF;
-		break;
-
-	case CASE(OADD, TFLOAT64):
-		a = AADDD;
-		break;
-
-	case CASE(OSUB, TINT8):
-	case CASE(OSUB, TUINT8):
-	case CASE(OSUB, TINT16):
-	case CASE(OSUB, TUINT16):
-	case CASE(OSUB, TINT32):
-	case CASE(OSUB, TUINT32):
-	case CASE(OSUB, TPTR32):
-		a = ASUB;
-		break;
-
-	case CASE(OSUB, TFLOAT32):
-		a = ASUBF;
-		break;
-
-	case CASE(OSUB, TFLOAT64):
-		a = ASUBD;
-		break;
-
-	case CASE(OMINUS, TINT8):
-	case CASE(OMINUS, TUINT8):
-	case CASE(OMINUS, TINT16):
-	case CASE(OMINUS, TUINT16):
-	case CASE(OMINUS, TINT32):
-	case CASE(OMINUS, TUINT32):
-	case CASE(OMINUS, TPTR32):
-		a = ARSB;
-		break;
-
-	case CASE(OAND, TINT8):
-	case CASE(OAND, TUINT8):
-	case CASE(OAND, TINT16):
-	case CASE(OAND, TUINT16):
-	case CASE(OAND, TINT32):
-	case CASE(OAND, TUINT32):
-	case CASE(OAND, TPTR32):
-		a = AAND;
-		break;
-
-	case CASE(OOR, TINT8):
-	case CASE(OOR, TUINT8):
-	case CASE(OOR, TINT16):
-	case CASE(OOR, TUINT16):
-	case CASE(OOR, TINT32):
-	case CASE(OOR, TUINT32):
-	case CASE(OOR, TPTR32):
-		a = AORR;
-		break;
-
-	case CASE(OXOR, TINT8):
-	case CASE(OXOR, TUINT8):
-	case CASE(OXOR, TINT16):
-	case CASE(OXOR, TUINT16):
-	case CASE(OXOR, TINT32):
-	case CASE(OXOR, TUINT32):
-	case CASE(OXOR, TPTR32):
-		a = AEOR;
-		break;
-
-	case CASE(OLSH, TINT8):
-	case CASE(OLSH, TUINT8):
-	case CASE(OLSH, TINT16):
-	case CASE(OLSH, TUINT16):
-	case CASE(OLSH, TINT32):
-	case CASE(OLSH, TUINT32):
-	case CASE(OLSH, TPTR32):
-		a = ASLL;
-		break;
-
-	case CASE(ORSH, TUINT8):
-	case CASE(ORSH, TUINT16):
-	case CASE(ORSH, TUINT32):
-	case CASE(ORSH, TPTR32):
-		a = ASRL;
-		break;
-
-	case CASE(ORSH, TINT8):
-	case CASE(ORSH, TINT16):
-	case CASE(ORSH, TINT32):
-		a = ASRA;
-		break;
-
-	case CASE(OMUL, TUINT8):
-	case CASE(OMUL, TUINT16):
-	case CASE(OMUL, TUINT32):
-	case CASE(OMUL, TPTR32):
-		a = AMULU;
-		break;
-
-	case CASE(OMUL, TINT8):
-	case CASE(OMUL, TINT16):
-	case CASE(OMUL, TINT32):
-		a = AMUL;
-		break;
-
-	case CASE(OMUL, TFLOAT32):
-		a = AMULF;
-		break;
-
-	case CASE(OMUL, TFLOAT64):
-		a = AMULD;
-		break;
-
-	case CASE(ODIV, TUINT8):
-	case CASE(ODIV, TUINT16):
-	case CASE(ODIV, TUINT32):
-	case CASE(ODIV, TPTR32):
-		a = ADIVU;
-		break;
-
-	case CASE(ODIV, TINT8):
-	case CASE(ODIV, TINT16):
-	case CASE(ODIV, TINT32):
-		a = ADIV;
-		break;
-
-	case CASE(OMOD, TUINT8):
-	case CASE(OMOD, TUINT16):
-	case CASE(OMOD, TUINT32):
-	case CASE(OMOD, TPTR32):
-		a = AMODU;
-		break;
-
-	case CASE(OMOD, TINT8):
-	case CASE(OMOD, TINT16):
-	case CASE(OMOD, TINT32):
-		a = AMOD;
-		break;
-
-//	case CASE(OEXTEND, TINT16):
-//		a = ACWD;
-//		break;
-
-//	case CASE(OEXTEND, TINT32):
-//		a = ACDQ;
-//		break;
-
-//	case CASE(OEXTEND, TINT64):
-//		a = ACQO;
-//		break;
-
-	case CASE(ODIV, TFLOAT32):
-		a = ADIVF;
-		break;
-
-	case CASE(ODIV, TFLOAT64):
-		a = ADIVD;
-		break;
-
-	}
-	return a;
-}
-
-enum
-{
-	ODynam	= 1<<0,
-	OPtrto	= 1<<1,
-};
-
-static	Node	clean[20];
-static	int	cleani = 0;
-
-void
-sudoclean(void)
-{
-	if(clean[cleani-1].op != OEMPTY)
-		regfree(&clean[cleani-1]);
-	if(clean[cleani-2].op != OEMPTY)
-		regfree(&clean[cleani-2]);
-	cleani -= 2;
-}
-
-int
-dotaddable(Node *n, Node *n1)
-{
-	int o;
-	int64 oary[10];
-	Node *nn;
-
-	if(n->op != ODOT)
-		return 0;
-
-	o = dotoffset(n, oary, &nn);
-	if(nn != N && nn->addable && o == 1 && oary[0] >= 0) {
-		*n1 = *nn;
-		n1->type = n->type;
-		n1->xoffset += oary[0];
-		return 1;
-	}
-	return 0;
-}
-
-/*
- * 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.
- */
-int
-sudoaddable(int as, Node *n, Addr *a, int *w)
-{
-	int o, i;
-	int64 oary[10];
-	int64 v;
-	Node n1, n2, n3, n4, *nn, *l, *r;
-	Node *reg, *reg1;
-	Prog *p1, *p2;
-	Type *t;
-
-	if(n->type == T)
-		return 0;
-
-	switch(n->op) {
-	case OLITERAL:
-		if(!isconst(n, CTINT))
-			break;
-		v = mpgetfix(n->val.u.xval);
-		if(v >= 32000 || v <= -32000)
-			break;
-		goto lit;
-
-	case ODOT:
-	case ODOTPTR:
-		cleani += 2;
-		reg = &clean[cleani-1];
-		reg1 = &clean[cleani-2];
-		reg->op = OEMPTY;
-		reg1->op = OEMPTY;
-		goto odot;
-
-	case OINDEX:
-		return 0;
-		// disabled: OINDEX case is now covered by agenr
-		// for a more suitable register allocation pattern.
-		if(n->left->type->etype == TSTRING)
-			return 0;
-		cleani += 2;
-		reg = &clean[cleani-1];
-		reg1 = &clean[cleani-2];
-		reg->op = OEMPTY;
-		reg1->op = OEMPTY;
-		goto oindex;
-	}
-	return 0;
-
-lit:
-	switch(as) {
-	default:
-		return 0;
-	case AADD: case ASUB: case AAND: case AORR: case AEOR:
-	case AMOVB: case AMOVBS: case AMOVBU:
-	case AMOVH: case AMOVHS: case AMOVHU:
-	case AMOVW:
-		break;
-	}
-
-	cleani += 2;
-	reg = &clean[cleani-1];
-	reg1 = &clean[cleani-2];
-	reg->op = OEMPTY;
-	reg1->op = OEMPTY;
-	naddr(n, a, 1);
-	goto yes;
-
-odot:
-	o = dotoffset(n, oary, &nn);
-	if(nn == N)
-		goto no;
-
-	if(nn->addable && o == 1 && oary[0] >= 0) {
-		// directly addressable set of DOTs
-		n1 = *nn;
-		n1.type = n->type;
-		n1.xoffset += oary[0];
-		naddr(&n1, a, 1);
-		goto yes;
-	}
-
-	regalloc(reg, types[tptr], N);
-	n1 = *reg;
-	n1.op = OINDREG;
-	if(oary[0] >= 0) {
-		agen(nn, reg);
-		n1.xoffset = oary[0];
-	} else {
-		cgen(nn, reg);
-		cgen_checknil(reg);
-		n1.xoffset = -(oary[0]+1);
-	}
-
-	for(i=1; i<o; i++) {
-		if(oary[i] >= 0)
-			fatal("can't happen");
-		gins(AMOVW, &n1, reg);
-		cgen_checknil(reg);
-		n1.xoffset = -(oary[i]+1);
-	}
-
-	a->type = D_NONE;
-	a->name = D_NONE;
-	n1.type = n->type;
-	naddr(&n1, a, 1);
-	goto yes;
-
-oindex:
-	l = n->left;
-	r = n->right;
-	if(l->ullman >= UINF && r->ullman >= UINF)
-		goto no;
-
-	// set o to type of array
-	o = 0;
-	if(isptr[l->type->etype]) {
-		o += OPtrto;
-		if(l->type->type->etype != TARRAY)
-			fatal("not ptr ary");
-		if(l->type->type->bound < 0)
-			o += ODynam;
-	} else {
-		if(l->type->etype != TARRAY)
-			fatal("not ary");
-		if(l->type->bound < 0)
-			o += ODynam;
-	}
-
-	*w = n->type->width;
-	if(isconst(r, CTINT))
-		goto oindex_const;
-
-	switch(*w) {
-	default:
-		goto no;
-	case 1:
-	case 2:
-	case 4:
-	case 8:
-		break;
-	}
-
-	// load the array (reg)
-	if(l->ullman > r->ullman) {
-		regalloc(reg, types[tptr], N);
-		if(o & OPtrto) {
-			cgen(l, reg);
-			cgen_checknil(reg);
-		} else
-			agen(l, reg);
-	}
-
-	// load the index (reg1)
-	t = types[TUINT32];
-	if(issigned[r->type->etype])
-		t = types[TINT32];
-	regalloc(reg1, t, N);
-	regalloc(&n3, types[TINT32], reg1);
-	p2 = cgenindex(r, &n3, debug['B'] || n->bounded);
-	gmove(&n3, reg1);
-	regfree(&n3);
-
-	// load the array (reg)
-	if(l->ullman <= r->ullman) {
-		regalloc(reg, types[tptr], N);
-		if(o & OPtrto) {
-			cgen(l, reg);
-			cgen_checknil(reg);
-		} else
-			agen(l, reg);
-	}
-
-	// check bounds
-	if(!debug['B']) {
-		if(o & ODynam) {
-			n2 = *reg;
-			n2.op = OINDREG;
-			n2.type = types[tptr];
-			n2.xoffset = Array_nel;
-		} else {
-			if(o & OPtrto)
-				nodconst(&n2, types[TUINT32], l->type->type->bound);
-			else
-				nodconst(&n2, types[TUINT32], l->type->bound);
-		}
-		regalloc(&n3, n2.type, N);
-		cgen(&n2, &n3);
-		gcmp(optoas(OCMP, types[TUINT32]), reg1, &n3);
-		regfree(&n3);
-		p1 = gbranch(optoas(OLT, types[TUINT32]), T, +1);
-		if(p2)
-			patch(p2, pc);
-		ginscall(panicindex, 0);
-		patch(p1, pc);
-	}
-
-	if(o & ODynam) {
-		n2 = *reg;
-		n2.op = OINDREG;
-		n2.type = types[tptr];
-		n2.xoffset = Array_array;
-		gmove(&n2, reg);
-	}
-
-	switch(*w) {
-	case 1:
-		gins(AADD, reg1, reg);
-		break;
-	case 2:
-		gshift(AADD, reg1, SHIFT_LL, 1, reg);
-		break;
-	case 4:
-		gshift(AADD, reg1, SHIFT_LL, 2, reg);
-		break;
-	case 8:
-		gshift(AADD, reg1, SHIFT_LL, 3, reg);
-		break;
-	}
-
-	naddr(reg1, a, 1);
-	a->type = D_OREG;
-	a->reg = reg->val.u.reg;
-	a->offset = 0;
-	goto yes;
-
-oindex_const:
-	// index is constant
-	// can check statically and
-	// can multiply by width statically
-
-	regalloc(reg, types[tptr], N);
-	if(o & OPtrto) {
-		cgen(l, reg);
-		cgen_checknil(reg);
-	} else
-		agen(l, reg);
-
-	v = mpgetfix(r->val.u.xval);
-	if(o & ODynam) {
-		if(!debug['B'] && !n->bounded) {
-			n1 = *reg;
-			n1.op = OINDREG;
-			n1.type = types[tptr];
-			n1.xoffset = Array_nel;
-			nodconst(&n2, types[TUINT32], v);
-			regalloc(&n3, types[TUINT32], N);
-			cgen(&n2, &n3);
-			regalloc(&n4, n1.type, N);
-			cgen(&n1, &n4);
-			gcmp(optoas(OCMP, types[TUINT32]), &n4, &n3);
-			regfree(&n4);
-			regfree(&n3);
-			p1 = gbranch(optoas(OGT, types[TUINT32]), T, +1);
-			ginscall(panicindex, 0);
-			patch(p1, pc);
-		}
-
-		n1 = *reg;
-		n1.op = OINDREG;
-		n1.type = types[tptr];
-		n1.xoffset = Array_array;
-		gmove(&n1, reg);
-	}
-
-	n2 = *reg;
-	n2.op = OINDREG;
-	n2.xoffset = v * (*w);
-	a->type = D_NONE;
-	a->name = D_NONE;
-	naddr(&n2, a, 1);
-	goto yes;
-
-yes:
-	return 1;
-
-no:
-	sudoclean();
-	return 0;
-}
diff --git a/src/cmd/5g/opt.h b/src/cmd/5g/opt.h
deleted file mode 100644
index 1946c1d..0000000
--- a/src/cmd/5g/opt.h
+++ /dev/null
@@ -1,221 +0,0 @@
-// Inferno utils/5c/gc.h
-// http://code.google.com/p/inferno-os/source/browse/utils/5c/gc.h
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include	"../gc/popt.h"
-
-#define	Z	N
-#define	Adr	Addr
-
-#define	D_HI	D_NONE
-#define	D_LO	D_NONE
-
-#define	BLOAD(r)	band(bnot(r->refbehind), r->refahead)
-#define	BSTORE(r)	band(bnot(r->calbehind), r->calahead)
-#define	LOAD(r)		(~r->refbehind.b[z] & r->refahead.b[z])
-#define	STORE(r)	(~r->calbehind.b[z] & r->calahead.b[z])
-
-#define	CLOAD	5
-#define	CREF	5
-#define	CINF	1000
-#define	LOOP	3
-
-typedef	struct	Reg	Reg;
-typedef	struct	Rgn	Rgn;
-
-/*c2go
-extern Node *Z;
-enum
-{
-	D_HI = D_NONE,
-	D_LO = D_NONE,
-	CLOAD = 5,
-	CREF = 5,
-	CINF = 1000,
-	LOOP = 3,
-};
-
-uint32 BLOAD(Reg*);
-uint32 BSTORE(Reg*);
-uint32 LOAD(Reg*);
-uint32 STORE(Reg*);
-*/
-
-// 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.
-// r->prog->opt points back to r.
-struct	Reg
-{
-	Flow	f;
-
-	Bits	set;  		// variables written by this instruction.
-	Bits	use1; 		// variables read by prog->from.
-	Bits	use2; 		// variables read by prog->to.
-
-	Bits	refbehind;
-	Bits	refahead;
-	Bits	calbehind;
-	Bits	calahead;
-	Bits	regdiff;
-	Bits	act;
-
-	int32	regu;		// register used bitmap
-};
-#define	R	((Reg*)0)
-/*c2go extern Reg *R; */
-
-#define	NRGN	600
-/*c2go enum { NRGN = 600 }; */
-struct	Rgn
-{
-	Reg*	enter;
-	short	cost;
-	short	varno;
-	short	regno;
-};
-
-EXTERN	int32	exregoffset;		// not set
-EXTERN	int32	exfregoffset;		// not set
-EXTERN	Reg	zreg;
-EXTERN	Reg*	freer;
-EXTERN	Reg**	rpo2r;
-EXTERN	Rgn	region[NRGN];
-EXTERN	Rgn*	rgp;
-EXTERN	int	nregion;
-EXTERN	int	nvar;
-EXTERN	int32	regbits;
-EXTERN	int32	exregbits;
-EXTERN	Bits	externs;
-EXTERN	Bits	params;
-EXTERN	Bits	consts;
-EXTERN	Bits	addrs;
-EXTERN	Bits	ivar;
-EXTERN	Bits	ovar;
-EXTERN	int	change;
-EXTERN	int32	maxnr;
-EXTERN	int32*	idom;
-
-EXTERN	struct
-{
-	int32	ncvtreg;
-	int32	nspill;
-	int32	nreload;
-	int32	ndelmov;
-	int32	nvar;
-	int32	naddr;
-} ostats;
-
-/*
- * reg.c
- */
-Reg*	rega(void);
-int	rcmp(const void*, const void*);
-void	regopt(Prog*);
-void	addmove(Reg*, int, int, int);
-Bits	mkvar(Reg *r, Adr *a);
-void	prop(Reg*, Bits, Bits);
-void	synch(Reg*, Bits);
-uint32	allreg(uint32, Rgn*);
-void	paint1(Reg*, int);
-uint32	paint2(Reg*, int);
-void	paint3(Reg*, int, int32, int);
-void	addreg(Adr*, int);
-void	dumpit(char *str, Flow *r0, int);
-
-/*
- * peep.c
- */
-void	peep(Prog*);
-void	excise(Flow*);
-int	copyu(Prog*, Adr*, Adr*);
-
-int32	RtoB(int);
-int32	FtoB(int);
-int	BtoR(int32);
-int	BtoF(int32);
-
-/*
- * prog.c
- */
-typedef struct ProgInfo ProgInfo;
-struct ProgInfo
-{
-	uint32 flags; // the bits below
-};
-
-enum
-{
-	// 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, // float aka float32
-	SizeD = 1<<8, // double aka float64
-
-	// Left side: address taken, read, write.
-	LeftAddr = 1<<9,
-	LeftRead = 1<<10,
-	LeftWrite = 1<<11,
-	
-	// Register in middle; never written.
-	RegRead = 1<<12,
-	CanRegRead = 1<<13,
-	
-	// Right side: address taken, read, write.
-	RightAddr = 1<<14,
-	RightRead = 1<<15,
-	RightWrite = 1<<16,
-
-	// 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
-};
-
-void proginfo(ProgInfo*, Prog*);
-
-// To allow use of AJMP and ACALL in ../gc/popt.c.
-enum
-{
-	AJMP = AB,
-	ACALL = ABL,
-};
diff --git a/src/cmd/5g/peep.c b/src/cmd/5g/peep.c
deleted file mode 100644
index 639f4c5..0000000
--- a/src/cmd/5g/peep.c
+++ /dev/null
@@ -1,1629 +0,0 @@
-// Inferno utils/5c/peep.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5c/peep.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-
-#include <u.h>
-#include <libc.h>
-#include "gg.h"
-#include "opt.h"
-
-static int	xtramodes(Graph*, Flow*, Adr*);
-static int	shortprop(Flow *r);
-static int	subprop(Flow*);
-static int	copyprop(Graph*, Flow*);
-static int	copy1(Adr*, Adr*, Flow*, int);
-static int	copyas(Adr*, Adr*);
-static int	copyau(Adr*, Adr*);
-static int	copysub(Adr*, Adr*, Adr*, int);
-static int	copysub1(Prog*, Adr*, Adr*, int);
-static Flow*	findpre(Flow *r, Adr *v);
-static int	copyau1(Prog *p, Adr *v);
-static int	isdconst(Addr *a);
-
-static uint32	gactive;
-
-// UNUSED
-int	shiftprop(Flow *r);
-void	constprop(Adr *c1, Adr *v1, Flow *r);
-void	predicate(Graph*);
-
-void
-peep(Prog *firstp)
-{
-	Flow *r;
-	Graph *g;
-	Prog *p;
-	int t;
-
-	g = flowstart(firstp, sizeof(Flow));
-	if(g == nil)
-		return;
-	gactive = 0;
-
-loop1:
-	if(debug['P'] && debug['v'])
-		dumpit("loop1", g->start, 0);
-
-	t = 0;
-	for(r=g->start; r!=nil; r=r->link) {
-		p = r->prog;
-		switch(p->as) {
-		case ASLL:
-		case ASRL:
-		case ASRA:
-			/*
-			 * elide shift into D_SHIFT operand of subsequent instruction
-			 */
-//			if(shiftprop(r)) {
-//				excise(r);
-//				t++;
-//				break;
-//			}
-			break;
-
-		case AMOVB:
-		case AMOVH:
-		case AMOVW:
-		case AMOVF:
-		case AMOVD:
-			if(regtyp(&p->from))
-			if(p->from.type == p->to.type)
-			if(p->scond == C_SCOND_NONE) {
-				if(copyprop(g, r)) {
-					excise(r);
-					t++;
-					break;
-				}
-				if(subprop(r) && copyprop(g, r)) {
-					excise(r);
-					t++;
-					break;
-				}
-			}
-			break;
-
-		case AMOVHS:
-		case AMOVHU:
-		case AMOVBS:
-		case AMOVBU:
-			if(p->from.type == D_REG) {
-				if(shortprop(r))
-					t++;
-			}
-			break;
-
-#ifdef NOTDEF
-			if(p->scond == C_SCOND_NONE)
-			if(regtyp(&p->to))
-			if(isdconst(&p->from)) {
-				constprop(&p->from, &p->to, r->s1);
-			}
-			break;
-#endif
-		}
-	}
-	if(t)
-		goto loop1;
-
-	for(r=g->start; r!=nil; r=r->link) {
-		p = r->prog;
-		switch(p->as) {
-		case AEOR:
-			/*
-			 * EOR -1,x,y => MVN x,y
-			 */
-			if(isdconst(&p->from) && p->from.offset == -1) {
-				p->as = AMVN;
-				p->from.type = D_REG;
-				if(p->reg != NREG)
-					p->from.reg = p->reg;
-				else
-					p->from.reg = p->to.reg;
-				p->reg = NREG;
-			}
-			break;
-		}
-	}
-
-	for(r=g->start; r!=nil; r=r->link) {
-		p = r->prog;
-		switch(p->as) {
-		case AMOVW:
-		case AMOVB:
-		case AMOVBS:
-		case AMOVBU:
-			if(p->from.type == D_OREG && p->from.offset == 0)
-				xtramodes(g, r, &p->from);
-			else
-			if(p->to.type == D_OREG && p->to.offset == 0)
-				xtramodes(g, r, &p->to);
-			else
-				continue;
-			break;
-//		case ACMP:
-//			/*
-//			 * elide CMP $0,x if calculation of x can set condition codes
-//			 */
-//			if(isdconst(&p->from) || p->from.offset != 0)
-//				continue;
-//			r2 = r->s1;
-//			if(r2 == nil)
-//				continue;
-//			t = r2->prog->as;
-//			switch(t) {
-//			default:
-//				continue;
-//			case ABEQ:
-//			case ABNE:
-//			case ABMI:
-//			case ABPL:
-//				break;
-//			case ABGE:
-//				t = ABPL;
-//				break;
-//			case ABLT:
-//				t = ABMI;
-//				break;
-//			case ABHI:
-//				t = ABNE;
-//				break;
-//			case ABLS:
-//				t = ABEQ;
-//				break;
-//			}
-//			r1 = r;
-//			do
-//				r1 = uniqp(r1);
-//			while (r1 != nil && r1->prog->as == ANOP);
-//			if(r1 == nil)
-//				continue;
-//			p1 = r1->prog;
-//			if(p1->to.type != D_REG)
-//				continue;
-//			if(p1->to.reg != p->reg)
-//			if(!(p1->as == AMOVW && p1->from.type == D_REG && p1->from.reg == p->reg))
-//				continue;
-//
-//			switch(p1->as) {
-//			default:
-//				continue;
-//			case AMOVW:
-//				if(p1->from.type != D_REG)
-//					continue;
-//			case AAND:
-//			case AEOR:
-//			case AORR:
-//			case ABIC:
-//			case AMVN:
-//			case ASUB:
-//			case ARSB:
-//			case AADD:
-//			case AADC:
-//			case ASBC:
-//			case ARSC:
-//				break;
-//			}
-//			p1->scond |= C_SBIT;
-//			r2->prog->as = t;
-//			excise(r);
-//			continue;
-		}
-	}
-
-//	predicate(g);
-
-	flowend(g);
-}
-
-int
-regtyp(Adr *a)
-{
-
-	if(a->type == D_REG)
-		return 1;
-	if(a->type == D_FREG)
-		return 1;
-	return 0;
-}
-
-/*
- * the idea is to substitute
- * one register for another
- * from one MOV to another
- *	MOV	a, R0
- *	ADD	b, R0	/ no use of R1
- *	MOV	R0, R1
- * would be converted to
- *	MOV	a, R1
- *	ADD	b, R1
- *	MOV	R1, R0
- * hopefully, then the former or latter MOV
- * will be eliminated by copy propagation.
- */
-static int
-subprop(Flow *r0)
-{
-	Prog *p;
-	Adr *v1, *v2;
-	Flow *r;
-	int t;
-	ProgInfo info;
-
-	p = r0->prog;
-	v1 = &p->from;
-	if(!regtyp(v1))
-		return 0;
-	v2 = &p->to;
-	if(!regtyp(v2))
-		return 0;
-	for(r=uniqp(r0); r!=nil; r=uniqp(r)) {
-		if(uniqs(r) == nil)
-			break;
-		p = r->prog;
-		if(p->as == AVARDEF || p->as == AVARKILL)
-			continue;
-		proginfo(&info, p);
-		if(info.flags & Call)
-			return 0;
-
-		if((info.flags & CanRegRead) && p->to.type == D_REG) {
-			info.flags |= RegRead;
-			info.flags &= ~(CanRegRead | RightRead);
-			p->reg = p->to.reg;
-		}
-
-		switch(p->as) {
-		case AMULLU:
-		case AMULA:
-		case AMVN:
-			return 0;
-		}
-		
-		if((info.flags & (RightRead|RightWrite)) == RightWrite) {
-			if(p->to.type == v1->type)
-			if(p->to.reg == v1->reg)
-			if(p->scond == C_SCOND_NONE)
-				goto gotit;
-		}
-
-		if(copyau(&p->from, v2) ||
-		   copyau1(p, v2) ||
-		   copyau(&p->to, v2))
-			break;
-		if(copysub(&p->from, v1, v2, 0) ||
-		   copysub1(p, v1, v2, 0) ||
-		   copysub(&p->to, v1, v2, 0))
-			break;
-	}
-	return 0;
-
-gotit:
-	copysub(&p->to, v1, v2, 1);
-	if(debug['P']) {
-		print("gotit: %D->%D\n%P", v1, v2, r->prog);
-		if(p->from.type == v2->type)
-			print(" excise");
-		print("\n");
-	}
-	for(r=uniqs(r); r!=r0; r=uniqs(r)) {
-		p = r->prog;
-		copysub(&p->from, v1, v2, 1);
-		copysub1(p, v1, v2, 1);
-		copysub(&p->to, v1, v2, 1);
-		if(debug['P'])
-			print("%P\n", r->prog);
-	}
-	t = v1->reg;
-	v1->reg = v2->reg;
-	v2->reg = t;
-	if(debug['P'])
-		print("%P last\n", r->prog);
-	return 1;
-}
-
-/*
- * The idea is to remove redundant copies.
- *	v1->v2	F=0
- *	(use v2	s/v2/v1/)*
- *	set v1	F=1
- *	use v2	return fail
- *	-----------------
- *	v1->v2	F=0
- *	(use v2	s/v2/v1/)*
- *	set v1	F=1
- *	set v2	return success
- */
-static int
-copyprop(Graph *g, Flow *r0)
-{
-	Prog *p;
-	Adr *v1, *v2;
-
-	USED(g);
-	p = r0->prog;
-	v1 = &p->from;
-	v2 = &p->to;
-	if(copyas(v1, v2))
-		return 1;
-	gactive++;
-	return copy1(v1, v2, r0->s1, 0);
-}
-
-static int
-copy1(Adr *v1, Adr *v2, Flow *r, int f)
-{
-	int t;
-	Prog *p;
-
-	if(r->active == gactive) {
-		if(debug['P'])
-			print("act set; return 1\n");
-		return 1;
-	}
-	r->active = gactive;
-	if(debug['P'])
-		print("copy %D->%D f=%d\n", v1, v2, f);
-	for(; r != nil; r = r->s1) {
-		p = r->prog;
-		if(debug['P'])
-			print("%P", p);
-		if(!f && uniqp(r) == nil) {
-			f = 1;
-			if(debug['P'])
-				print("; merge; f=%d", f);
-		}
-		t = copyu(p, v2, nil);
-		switch(t) {
-		case 2:	/* rar, can't split */
-			if(debug['P'])
-				print("; %Drar; return 0\n", v2);
-			return 0;
-
-		case 3:	/* set */
-			if(debug['P'])
-				print("; %Dset; return 1\n", v2);
-			return 1;
-
-		case 1:	/* used, substitute */
-		case 4:	/* use and set */
-			if(f) {
-				if(!debug['P'])
-					return 0;
-				if(t == 4)
-					print("; %Dused+set and f=%d; return 0\n", v2, f);
-				else
-					print("; %Dused and f=%d; return 0\n", v2, f);
-				return 0;
-			}
-			if(copyu(p, v2, v1)) {
-				if(debug['P'])
-					print("; sub fail; return 0\n");
-				return 0;
-			}
-			if(debug['P'])
-				print("; sub%D/%D", v2, v1);
-			if(t == 4) {
-				if(debug['P'])
-					print("; %Dused+set; return 1\n", v2);
-				return 1;
-			}
-			break;
-		}
-		if(!f) {
-			t = copyu(p, v1, nil);
-			if(!f && (t == 2 || t == 3 || t == 4)) {
-				f = 1;
-				if(debug['P'])
-					print("; %Dset and !f; f=%d", v1, f);
-			}
-		}
-		if(debug['P'])
-			print("\n");
-		if(r->s2)
-			if(!copy1(v1, v2, r->s2, f))
-				return 0;
-	}
-	return 1;
-}
-
-// UNUSED
-/*
- * The idea is to remove redundant constants.
- *	$c1->v1
- *	($c1->v2 s/$c1/v1)*
- *	set v1  return
- * The v1->v2 should be eliminated by copy propagation.
- */
-void
-constprop(Adr *c1, Adr *v1, Flow *r)
-{
-	Prog *p;
-
-	if(debug['P'])
-		print("constprop %D->%D\n", c1, v1);
-	for(; r != nil; r = r->s1) {
-		p = r->prog;
-		if(debug['P'])
-			print("%P", p);
-		if(uniqp(r) == nil) {
-			if(debug['P'])
-				print("; merge; return\n");
-			return;
-		}
-		if(p->as == AMOVW && copyas(&p->from, c1)) {
-				if(debug['P'])
-					print("; sub%D/%D", &p->from, v1);
-				p->from = *v1;
-		} else if(copyu(p, v1, nil) > 1) {
-			if(debug['P'])
-				print("; %Dset; return\n", v1);
-			return;
-		}
-		if(debug['P'])
-			print("\n");
-		if(r->s2)
-			constprop(c1, v1, r->s2);
-	}
-}
-
-/*
- * shortprop eliminates redundant zero/sign extensions.
- *
- *   MOVBS x, R
- *   <no use R>
- *   MOVBS R, R'
- *
- * changed to
- *
- *   MOVBS x, R
- *   ...
- *   MOVB  R, R' (compiled to mov)
- *
- * MOVBS above can be a MOVBS, MOVBU, MOVHS or MOVHU.
- */
-static int
-shortprop(Flow *r)
-{
-	Prog *p, *p1;
-	Flow *r1;
-
-	p = r->prog;
-	r1 = findpre(r, &p->from);
-	if(r1 == nil)
-		return 0;
-
-	p1 = r1->prog;
-	if(p1->as == p->as) {
-		// Two consecutive extensions.
-		goto gotit;
-	}
-
-	if(p1->as == AMOVW && isdconst(&p1->from)
-	   && p1->from.offset >= 0 && p1->from.offset < 128) {
-		// Loaded an immediate.
-		goto gotit;
-	}
-
-	return 0;
-
-gotit:
-	if(debug['P'])
-		print("shortprop\n%P\n%P", p1, p);
-	switch(p->as) {
-	case AMOVBS:
-	case AMOVBU:
-		p->as = AMOVB;
-		break;
-	case AMOVHS:
-	case AMOVHU:
-		p->as = AMOVH;
-		break;
-	}
-	if(debug['P'])
-		print(" => %A\n", p->as);
-	return 1;
-}
-
-// UNUSED
-/*
- * ASLL x,y,w
- * .. (not use w, not set x y w)
- * AXXX w,a,b (a != w)
- * .. (not use w)
- * (set w)
- * ----------- changed to
- * ..
- * AXXX (x<<y),a,b
- * ..
- */
-#define FAIL(msg) { if(debug['P']) print("\t%s; FAILURE\n", msg); return 0; }
-/*c2go void FAIL(char*); */
-
-int
-shiftprop(Flow *r)
-{
-	Flow *r1;
-	Prog *p, *p1, *p2;
-	int n, o;
-	Adr a;
-
-	p = r->prog;
-	if(p->to.type != D_REG)
-		FAIL("BOTCH: result not reg");
-	n = p->to.reg;
-	a = zprog.from;
-	if(p->reg != NREG && p->reg != p->to.reg) {
-		a.type = D_REG;
-		a.reg = p->reg;
-	}
-	if(debug['P'])
-		print("shiftprop\n%P", p);
-	r1 = r;
-	for(;;) {
-		/* find first use of shift result; abort if shift operands or result are changed */
-		r1 = uniqs(r1);
-		if(r1 == nil)
-			FAIL("branch");
-		if(uniqp(r1) == nil)
-			FAIL("merge");
-		p1 = r1->prog;
-		if(debug['P'])
-			print("\n%P", p1);
-		switch(copyu(p1, &p->to, nil)) {
-		case 0:	/* not used or set */
-			if((p->from.type == D_REG && copyu(p1, &p->from, nil) > 1) ||
-			   (a.type == D_REG && copyu(p1, &a, nil) > 1))
-				FAIL("args modified");
-			continue;
-		case 3:	/* set, not used */
-			FAIL("BOTCH: noref");
-		}
-		break;
-	}
-	/* check whether substitution can be done */
-	switch(p1->as) {
-	default:
-		FAIL("non-dpi");
-	case AAND:
-	case AEOR:
-	case AADD:
-	case AADC:
-	case AORR:
-	case ASUB:
-	case ASBC:
-	case ARSB:
-	case ARSC:
-		if(p1->reg == n || (p1->reg == NREG && p1->to.type == D_REG && p1->to.reg == n)) {
-			if(p1->from.type != D_REG)
-				FAIL("can't swap");
-			p1->reg = p1->from.reg;
-			p1->from.reg = n;
-			switch(p1->as) {
-			case ASUB:
-				p1->as = ARSB;
-				break;
-			case ARSB:
-				p1->as = ASUB;
-				break;
-			case ASBC:
-				p1->as = ARSC;
-				break;
-			case ARSC:
-				p1->as = ASBC;
-				break;
-			}
-			if(debug['P'])
-				print("\t=>%P", p1);
-		}
-	case ABIC:
-	case ATST:
-	case ACMP:
-	case ACMN:
-		if(p1->reg == n)
-			FAIL("can't swap");
-		if(p1->reg == NREG && p1->to.reg == n)
-			FAIL("shift result used twice");
-//	case AMVN:
-		if(p1->from.type == D_SHIFT)
-			FAIL("shift result used in shift");
-		if(p1->from.type != D_REG || p1->from.reg != n)
-			FAIL("BOTCH: where is it used?");
-		break;
-	}
-	/* check whether shift result is used subsequently */
-	p2 = p1;
-	if(p1->to.reg != n)
-	for (;;) {
-		r1 = uniqs(r1);
-		if(r1 == nil)
-			FAIL("inconclusive");
-		p1 = r1->prog;
-		if(debug['P'])
-			print("\n%P", p1);
-		switch(copyu(p1, &p->to, nil)) {
-		case 0:	/* not used or set */
-			continue;
-		case 3: /* set, not used */
-			break;
-		default:/* used */
-			FAIL("reused");
-		}
-		break;
-	}
-
-	/* make the substitution */
-	p2->from.type = D_SHIFT;
-	p2->from.reg = NREG;
-	o = p->reg;
-	if(o == NREG)
-		o = p->to.reg;
-
-	switch(p->from.type){
-	case D_CONST:
-		o |= (p->from.offset&0x1f)<<7;
-		break;
-	case D_REG:
-		o |= (1<<4) | (p->from.reg<<8);
-		break;
-	}
-	switch(p->as){
-	case ASLL:
-		o |= 0<<5;
-		break;
-	case ASRL:
-		o |= 1<<5;
-		break;
-	case ASRA:
-		o |= 2<<5;
-		break;
-	}
-	p2->from.offset = o;
-	if(debug['P'])
-		print("\t=>%P\tSUCCEED\n", p2);
-	return 1;
-}
-
-/*
- * findpre returns the last instruction mentioning v
- * before r. It must be a set, and there must be
- * a unique path from that instruction to r.
- */
-static Flow*
-findpre(Flow *r, Adr *v)
-{
-	Flow *r1;
-
-	for(r1=uniqp(r); r1!=nil; r=r1,r1=uniqp(r)) {
-		if(uniqs(r1) != r)
-			return nil;
-		switch(copyu(r1->prog, v, nil)) {
-		case 1: /* used */
-		case 2: /* read-alter-rewrite */
-			return nil;
-		case 3: /* set */
-		case 4: /* set and used */
-			return r1;
-		}
-	}
-	return nil;
-}
-
-/*
- * findinc finds ADD instructions with a constant
- * argument which falls within the immed_12 range.
- */
-static Flow*
-findinc(Flow *r, Flow *r2, Adr *v)
-{
-	Flow *r1;
-	Prog *p;
-
-
-	for(r1=uniqs(r); r1!=nil && r1!=r2; r=r1,r1=uniqs(r)) {
-		if(uniqp(r1) != r)
-			return nil;
-		switch(copyu(r1->prog, v, nil)) {
-		case 0: /* not touched */
-			continue;
-		case 4: /* set and used */
-			p = r1->prog;
-			if(p->as == AADD)
-			if(isdconst(&p->from))
-			if(p->from.offset > -4096 && p->from.offset < 4096)
-				return r1;
-		default:
-			return nil;
-		}
-	}
-	return nil;
-}
-
-static int
-nochange(Flow *r, Flow *r2, Prog *p)
-{
-	Adr a[3];
-	int i, n;
-
-	if(r == r2)
-		return 1;
-	n = 0;
-	if(p->reg != NREG && p->reg != p->to.reg) {
-		a[n].type = D_REG;
-		a[n++].reg = p->reg;
-	}
-	switch(p->from.type) {
-	case D_SHIFT:
-		a[n].type = D_REG;
-		a[n++].reg = p->from.offset&0xf;
-	case D_REG:
-		a[n].type = D_REG;
-		a[n++].reg = p->from.reg;
-	}
-	if(n == 0)
-		return 1;
-	for(; r!=nil && r!=r2; r=uniqs(r)) {
-		p = r->prog;
-		for(i=0; i<n; i++)
-			if(copyu(p, &a[i], nil) > 1)
-				return 0;
-	}
-	return 1;
-}
-
-static int
-findu1(Flow *r, Adr *v)
-{
-	for(; r != nil; r = r->s1) {
-		if(r->active)
-			return 0;
-		r->active = 1;
-		switch(copyu(r->prog, v, nil)) {
-		case 1: /* used */
-		case 2: /* read-alter-rewrite */
-		case 4: /* set and used */
-			return 1;
-		case 3: /* set */
-			return 0;
-		}
-		if(r->s2)
-			if (findu1(r->s2, v))
-				return 1;
-	}
-	return 0;
-}
-
-static int
-finduse(Graph *g, Flow *r, Adr *v)
-{
-	Flow *r1;
-
-	for(r1=g->start; r1!=nil; r1=r1->link)
-		r1->active = 0;
-	return findu1(r, v);
-}
-
-/*
- * xtramodes enables the ARM post increment and
- * shift offset addressing modes to transform
- *   MOVW   0(R3),R1
- *   ADD    $4,R3,R3
- * into
- *   MOVW.P 4(R3),R1
- * and 
- *   ADD    R0,R1
- *   MOVBU  0(R1),R0
- * into 
- *   MOVBU  R0<<0(R1),R0
- */
-static int
-xtramodes(Graph *g, Flow *r, Adr *a)
-{
-	Flow *r1, *r2, *r3;
-	Prog *p, *p1;
-	Adr v;
-
-	p = r->prog;
-	v = *a;
-	v.type = D_REG;
-	r1 = findpre(r, &v);
-	if(r1 != nil) {
-		p1 = r1->prog;
-		if(p1->to.type == D_REG && p1->to.reg == v.reg)
-		switch(p1->as) {
-		case AADD:
-			if(p1->scond & C_SBIT)
-				// avoid altering ADD.S/ADC sequences.
-				break;
-			if(p1->from.type == D_REG ||
-			   (p1->from.type == D_SHIFT && (p1->from.offset&(1<<4)) == 0 &&
-			    ((p->as != AMOVB && p->as != AMOVBS) || (a == &p->from && (p1->from.offset&~0xf) == 0))) ||
-			   (p1->from.type == D_CONST &&
-			    p1->from.offset > -4096 && p1->from.offset < 4096))
-			if(nochange(uniqs(r1), r, p1)) {
-				if(a != &p->from || v.reg != p->to.reg)
-				if (finduse(g, r->s1, &v)) {
-					if(p1->reg == NREG || p1->reg == v.reg)
-						/* pre-indexing */
-						p->scond |= C_WBIT;
-					else return 0;
-				}
-				switch (p1->from.type) {
-				case D_REG:
-					/* register offset */
-					if(nacl)
-						return 0;
-					a->type = D_SHIFT;
-					a->offset = p1->from.reg;
-					break;
-				case D_SHIFT:
-					/* scaled register offset */
-					if(nacl)
-						return 0;
-					a->type = D_SHIFT;
-				case D_CONST:
-					/* immediate offset */
-					a->offset = p1->from.offset;
-					break;
-				}
-				if(p1->reg != NREG)
-					a->reg = p1->reg;
-				excise(r1);
-				return 1;
-			}
-			break;
-		case AMOVW:
-			if(p1->from.type == D_REG)
-			if((r2 = findinc(r1, r, &p1->from)) != nil) {
-			for(r3=uniqs(r2); r3->prog->as==ANOP; r3=uniqs(r3))
-				;
-			if(r3 == r) {
-				/* post-indexing */
-				p1 = r2->prog;
-				a->reg = p1->to.reg;
-				a->offset = p1->from.offset;
-				p->scond |= C_PBIT;
-				if(!finduse(g, r, &r1->prog->to))
-					excise(r1);
-				excise(r2);
-				return 1;
-			}
-			}
-			break;
-		}
-	}
-	if(a != &p->from || a->reg != p->to.reg)
-	if((r1 = findinc(r, nil, &v)) != nil) {
-		/* post-indexing */
-		p1 = r1->prog;
-		a->offset = p1->from.offset;
-		p->scond |= C_PBIT;
-		excise(r1);
-		return 1;
-	}
-	return 0;
-}
-
-/*
- * return
- * 1 if v only used (and substitute),
- * 2 if read-alter-rewrite
- * 3 if set
- * 4 if set and used
- * 0 otherwise (not touched)
- */
-int
-copyu(Prog *p, Adr *v, Adr *s)
-{
-	switch(p->as) {
-
-	default:
-		print("copyu: can't find %A\n", p->as);
-		return 2;
-
-	case AMOVM:
-		if(v->type != D_REG)
-			return 0;
-		if(p->from.type == D_CONST) {	/* read reglist, read/rar */
-			if(s != nil) {
-				if(p->from.offset&(1<<v->reg))
-					return 1;
-				if(copysub(&p->to, v, s, 1))
-					return 1;
-				return 0;
-			}
-			if(copyau(&p->to, v)) {
-				if(p->scond&C_WBIT)
-					return 2;
-				return 1;
-			}
-			if(p->from.offset&(1<<v->reg))
-				return 1;
-		} else {			/* read/rar, write reglist */
-			if(s != nil) {
-				if(p->to.offset&(1<<v->reg))
-					return 1;
-				if(copysub(&p->from, v, s, 1))
-					return 1;
-				return 0;
-			}
-			if(copyau(&p->from, v)) {
-				if(p->scond&C_WBIT)
-					return 2;
-				if(p->to.offset&(1<<v->reg))
-					return 4;
-				return 1;
-			}
-			if(p->to.offset&(1<<v->reg))
-				return 3;
-		}
-		return 0;
-
-	case ANOP:	/* read,, write */
-	case AMOVW:
-	case AMOVF:
-	case AMOVD:
-	case AMOVH:
-	case AMOVHS:
-	case AMOVHU:
-	case AMOVB:
-	case AMOVBS:
-	case AMOVBU:
-	case AMOVFW:
-	case AMOVWF:
-	case AMOVDW:
-	case AMOVWD:
-	case AMOVFD:
-	case AMOVDF:
-		if(p->scond&(C_WBIT|C_PBIT))
-		if(v->type == D_REG) {
-			if(p->from.type == D_OREG || p->from.type == D_SHIFT) {
-				if(p->from.reg == v->reg)
-					return 2;
-			} else {
-		  		if(p->to.reg == v->reg)
-					return 2;
-			}
-		}
-		if(s != nil) {
-			if(copysub(&p->from, v, s, 1))
-				return 1;
-			if(!copyas(&p->to, v))
-				if(copysub(&p->to, v, s, 1))
-					return 1;
-			return 0;
-		}
-		if(copyas(&p->to, v)) {
-			if(p->scond != C_SCOND_NONE)
-				return 2;
-			if(copyau(&p->from, v))
-				return 4;
-			return 3;
-		}
-		if(copyau(&p->from, v))
-			return 1;
-		if(copyau(&p->to, v))
-			return 1;
-		return 0;
-
-	case AMULLU:	/* read, read, write, write */
-	case AMULL:
-	case AMULA:
-	case AMVN:
-		return 2;
-
-	case AADD:	/* read, read, write */
-	case AADC:
-	case ASUB:
-	case ASBC:
-	case ARSB:
-	case ASLL:
-	case ASRL:
-	case ASRA:
-	case AORR:
-	case AAND:
-	case AEOR:
-	case AMUL:
-	case AMULU:
-	case ADIV:
-	case ADIVU:
-	case AMOD:
-	case AMODU:
-	case AADDF:
-	case AADDD:
-	case ASUBF:
-	case ASUBD:
-	case AMULF:
-	case AMULD:
-	case ADIVF:
-	case ADIVD:
-
-	case ACHECKNIL: /* read */
-	case ACMPF:	/* read, read, */
-	case ACMPD:
-	case ACMP:
-	case ACMN:
-	case ACASE:
-	case ATST:	/* read,, */
-		if(s != nil) {
-			if(copysub(&p->from, v, s, 1))
-				return 1;
-			if(copysub1(p, v, s, 1))
-				return 1;
-			if(!copyas(&p->to, v))
-				if(copysub(&p->to, v, s, 1))
-					return 1;
-			return 0;
-		}
-		if(copyas(&p->to, v)) {
-			if(p->scond != C_SCOND_NONE)
-				return 2;
-			if(p->reg == NREG)
-				p->reg = p->to.reg;
-			if(copyau(&p->from, v))
-				return 4;
-			if(copyau1(p, v))
-				return 4;
-			return 3;
-		}
-		if(copyau(&p->from, v))
-			return 1;
-		if(copyau1(p, v))
-			return 1;
-		if(copyau(&p->to, v))
-			return 1;
-		return 0;
-
-	case ABEQ:	/* read, read */
-	case ABNE:
-	case ABCS:
-	case ABHS:
-	case ABCC:
-	case ABLO:
-	case ABMI:
-	case ABPL:
-	case ABVS:
-	case ABVC:
-	case ABHI:
-	case ABLS:
-	case ABGE:
-	case ABLT:
-	case ABGT:
-	case ABLE:
-		if(s != nil) {
-			if(copysub(&p->from, v, s, 1))
-				return 1;
-			return copysub1(p, v, s, 1);
-		}
-		if(copyau(&p->from, v))
-			return 1;
-		if(copyau1(p, v))
-			return 1;
-		return 0;
-
-	case AB:	/* funny */
-		if(s != nil) {
-			if(copysub(&p->to, v, s, 1))
-				return 1;
-			return 0;
-		}
-		if(copyau(&p->to, v))
-			return 1;
-		return 0;
-
-	case ARET:	/* funny */
-		if(s != nil)
-			return 1;
-		return 3;
-
-	case ABL:	/* funny */
-		if(v->type == D_REG) {
-			if(v->reg <= REGEXT && v->reg > exregoffset)
-				return 2;
-			if(v->reg == REGARG)
-				return 2;
-		}
-		if(v->type == D_FREG)
-			if(v->reg <= FREGEXT && v->reg > exfregoffset)
-				return 2;
-		if(p->from.type == D_REG && v->type == D_REG && p->from.reg == v->reg)
-			return 2;
-
-		if(s != nil) {
-			if(copysub(&p->to, v, s, 1))
-				return 1;
-			return 0;
-		}
-		if(copyau(&p->to, v))
-			return 4;
-		return 3;
-	case ADUFFZERO:
-		// R0 is zero, used by DUFFZERO, cannot be substituted.
-		// R1 is ptr to memory, used and set, cannot be substituted.
-		if(v->type == D_REG) {
-			if(v->reg == REGALLOC_R0)
-				return 1;
-			if(v->reg == REGALLOC_R0+1)
-				return 2;
-		}
-		return 0;
-	case ADUFFCOPY:
-		// R0 is scratch, set by DUFFCOPY, cannot be substituted.
-		// R1, R2 areptr to src, dst, used and set, cannot be substituted.
-		if(v->type == D_REG) {
-			if(v->reg == REGALLOC_R0)
-				return 3;
-			if(v->reg == REGALLOC_R0+1 || v->reg == REGALLOC_R0+2)
-				return 2;
-		}
-		return 0;
-			
-	case ATEXT:	/* funny */
-		if(v->type == D_REG)
-			if(v->reg == REGARG)
-				return 3;
-		return 0;
-
-	case APCDATA:
-	case AFUNCDATA:
-	case AVARDEF:
-	case AVARKILL:
-		return 0;
-	}
-}
-
-/*
- * direct reference,
- * could be set/use depending on
- * semantics
- */
-static int
-copyas(Adr *a, Adr *v)
-{
-
-	if(regtyp(v)) {
-		if(a->type == v->type)
-		if(a->reg == v->reg)
-			return 1;
-	} else
-	if(v->type == D_CONST) {		/* for constprop */
-		if(a->type == v->type)
-		if(a->name == v->name)
-		if(a->sym == v->sym)
-		if(a->reg == v->reg)
-		if(a->offset == v->offset)
-			return 1;
-	}
-	return 0;
-}
-
-int
-sameaddr(Adr *a, Adr *v)
-{
-	if(a->type != v->type)
-		return 0;
-	if(regtyp(v) && a->reg == v->reg)
-		return 1;
-	if(v->type == D_AUTO || v->type == D_PARAM) {
-		if(v->offset == a->offset)
-			return 1;
-	}
-	return 0;
-}
-
-/*
- * either direct or indirect
- */
-static int
-copyau(Adr *a, Adr *v)
-{
-
-	if(copyas(a, v))
-		return 1;
-	if(v->type == D_REG) {
-		if(a->type == D_CONST && a->reg != NREG) {
-			if(a->reg == v->reg)
-				return 1;
-		} else
-		if(a->type == D_OREG) {
-			if(a->reg == v->reg)
-				return 1;
-		} else
-		if(a->type == D_REGREG || a->type == D_REGREG2) {
-			if(a->reg == v->reg)
-				return 1;
-			if(a->offset == v->reg)
-				return 1;
-		} else
-		if(a->type == D_SHIFT) {
-			if((a->offset&0xf) == v->reg)
-				return 1;
-			if((a->offset&(1<<4)) && (a->offset>>8) == v->reg)
-				return 1;
-		}
-	}
-	return 0;
-}
-
-static int
-a2type(Prog *p)
-{
-	if(p->reg == NREG)
-		return D_NONE;
-
-	switch(p->as) {
-	default:
-		fatal("a2type: unhandled %P", p);
-
-	case AAND:
-	case AEOR:
-	case ASUB:
-	case ARSB:
-	case AADD:
-	case AADC:
-	case ASBC:
-	case ARSC:
-	case ATST:
-	case ATEQ:
-	case ACMP:
-	case ACMN:
-	case AORR:
-	case ABIC:
-	case AMVN:
-	case ASRL:
-	case ASRA:
-	case ASLL:
-	case AMULU:
-	case ADIVU:
-	case AMUL:
-	case ADIV:
-	case AMOD:
-	case AMODU:
-	case AMULA:
-	case AMULL:
-	case AMULAL:
-	case AMULLU:
-	case AMULALU:
-	case AMULWT:
-	case AMULWB:
-	case AMULAWT:
-	case AMULAWB:
-		return D_REG;
-
-	case ACMPF:
-	case ACMPD:
-	case AADDF:
-	case AADDD:
-	case ASUBF:
-	case ASUBD:
-	case AMULF:
-	case AMULD:
-	case ADIVF:
-	case ADIVD:
-	case ASQRTF:
-	case ASQRTD:
-	case AABSF:
-	case AABSD:
-		return D_FREG;
-	}
-}
-
-/*
- * compare v to the center
- * register in p (p->reg)
- */
-static int
-copyau1(Prog *p, Adr *v)
-{
-	if(v->type == D_REG && v->reg == NREG)
-		return 0;
-	return p->reg == v->reg && a2type(p) == v->type;
-}
-
-/*
- * substitute s for v in a
- * return failure to substitute
- */
-static int
-copysub(Adr *a, Adr *v, Adr *s, int f)
-{
-
-	if(f)
-	if(copyau(a, v)) {
-		if(a->type == D_SHIFT) {
-			if((a->offset&0xf) == v->reg)
-				a->offset = (a->offset&~0xf)|s->reg;
-			if((a->offset&(1<<4)) && (a->offset>>8) == v->reg)
-				a->offset = (a->offset&~(0xf<<8))|(s->reg<<8);
-		} else
-		if(a->type == D_REGREG || a->type == D_REGREG2) {
-			if(a->offset == v->reg)
-				a->offset = s->reg;
-			if(a->reg == v->reg)
-				a->reg = s->reg;
-		} else
-			a->reg = s->reg;
-	}
-	return 0;
-}
-
-static int
-copysub1(Prog *p1, Adr *v, Adr *s, int f)
-{
-
-	if(f)
-	if(copyau1(p1, v))
-		p1->reg = s->reg;
-	return 0;
-}
-
-struct {
-	int opcode;
-	int notopcode;
-	int scond;
-	int notscond;
-} predinfo[]  = {
-	{ ABEQ,	ABNE,	0x0,	0x1, },
-	{ ABNE,	ABEQ,	0x1,	0x0, },
-	{ ABCS,	ABCC,	0x2,	0x3, },
-	{ ABHS,	ABLO,	0x2,	0x3, },
-	{ ABCC,	ABCS,	0x3,	0x2, },
-	{ ABLO,	ABHS,	0x3,	0x2, },
-	{ ABMI,	ABPL,	0x4,	0x5, },
-	{ ABPL,	ABMI,	0x5,	0x4, },
-	{ ABVS,	ABVC,	0x6,	0x7, },
-	{ ABVC,	ABVS,	0x7,	0x6, },
-	{ ABHI,	ABLS,	0x8,	0x9, },
-	{ ABLS,	ABHI,	0x9,	0x8, },
-	{ ABGE,	ABLT,	0xA,	0xB, },
-	{ ABLT,	ABGE,	0xB,	0xA, },
-	{ ABGT,	ABLE,	0xC,	0xD, },
-	{ ABLE,	ABGT,	0xD,	0xC, },
-};
-
-typedef struct {
-	Flow *start;
-	Flow *last;
-	Flow *end;
-	int len;
-} Joininfo;
-
-enum {
-	Join,
-	Split,
-	End,
-	Branch,
-	Setcond,
-	Toolong
-};
-
-enum {
-	Falsecond,
-	Truecond,
-	Delbranch,
-	Keepbranch
-};
-
-static int
-isbranch(Prog *p)
-{
-	return (ABEQ <= p->as) && (p->as <= ABLE);
-}
-
-static int
-predicable(Prog *p)
-{
-	switch(p->as) {
-	case ANOP:
-	case AXXX:
-	case ADATA:
-	case AGLOBL:
-	case AGOK:
-	case AHISTORY:
-	case ANAME:
-	case ASIGNAME:
-	case ATEXT:
-	case AWORD:
-	case ABCASE:
-	case ACASE:
-		return 0;
-	}
-	if(isbranch(p))
-		return 0;
-	return 1;
-}
-
-/*
- * Depends on an analysis of the encodings performed by 5l.
- * These seem to be all of the opcodes that lead to the "S" bit
- * being set in the instruction encodings.
- *
- * C_SBIT may also have been set explicitly in p->scond.
- */
-static int
-modifiescpsr(Prog *p)
-{
-	switch(p->as) {
-	case AMULLU:
-	case AMULA:
-	case AMULU:
-	case ADIVU:
-
-	case ATEQ:
-	case ACMN:
-	case ATST:
-	case ACMP:
-	case AMUL:
-	case ADIV:
-	case AMOD:
-	case AMODU:
-	case ABL:
-		return 1;
-	}
-	if(p->scond & C_SBIT)
-		return 1;
-	return 0;
-}
-
-/*
- * Find the maximal chain of instructions starting with r which could
- * be executed conditionally
- */
-static int
-joinsplit(Flow *r, Joininfo *j)
-{
-	j->start = r;
-	j->last = r;
-	j->len = 0;
-	do {
-		if (r->p2 && (r->p1 || r->p2->p2link)) {
-			j->end = r;
-			return Join;
-		}
-		if (r->s1 && r->s2) {
-			j->end = r;
-			return Split;
-		}
-		j->last = r;
-		if (r->prog->as != ANOP)
-			j->len++;
-		if (!r->s1 && !r->s2) {
-			j->end = r->link;
-			return End;
-		}
-		if (r->s2) {
-			j->end = r->s2;
-			return Branch;
-		}
-		if (modifiescpsr(r->prog)) {
-			j->end = r->s1;
-			return Setcond;
-		}
-		r = r->s1;
-	} while (j->len < 4);
-	j->end = r;
-	return Toolong;
-}
-
-static Flow*
-successor(Flow *r)
-{
-	if(r->s1)
-		return r->s1;
-	else
-		return r->s2;
-}
-
-static void
-applypred(Flow *rstart, Joininfo *j, int cond, int branch)
-{
-	int pred;
-	Flow *r;
-
-	if(j->len == 0)
-		return;
-	if(cond == Truecond)
-		pred = predinfo[rstart->prog->as - ABEQ].scond;
-	else
-		pred = predinfo[rstart->prog->as - ABEQ].notscond;
-
-	for(r = j->start;; r = successor(r)) {
-		if(r->prog->as == AB) {
-			if(r != j->last || branch == Delbranch)
-				excise(r);
-			else {
-				if(cond == Truecond)
-					r->prog->as = predinfo[rstart->prog->as - ABEQ].opcode;
-				else
-					r->prog->as = predinfo[rstart->prog->as - ABEQ].notopcode;
-			}
-		}
-		else
-		if(predicable(r->prog))
-			r->prog->scond = (r->prog->scond&~C_SCOND)|pred;
-		if(r->s1 != r->link) {
-			r->s1 = r->link;
-			r->link->p1 = r;
-		}
-		if(r == j->last)
-			break;
-	}
-}
-
-void
-predicate(Graph *g)
-{
-	Flow *r;
-	int t1, t2;
-	Joininfo j1, j2;
-
-	for(r=g->start; r!=nil; r=r->link) {
-		if (isbranch(r->prog)) {
-			t1 = joinsplit(r->s1, &j1);
-			t2 = joinsplit(r->s2, &j2);
-			if(j1.last->link != j2.start)
-				continue;
-			if(j1.end == j2.end)
-			if((t1 == Branch && (t2 == Join || t2 == Setcond)) ||
-			   (t2 == Join && (t1 == Join || t1 == Setcond))) {
-				applypred(r, &j1, Falsecond, Delbranch);
-				applypred(r, &j2, Truecond, Delbranch);
-				excise(r);
-				continue;
-			}
-			if(t1 == End || t1 == Branch) {
-				applypred(r, &j1, Falsecond, Keepbranch);
-				excise(r);
-				continue;
-			}
-		}
-	}
-}
-
-static int
-isdconst(Addr *a)
-{
-	if(a->type == D_CONST && a->reg == NREG)
-		return 1;
-	return 0;
-}
-
-int
-stackaddr(Addr *a)
-{
-	return regtyp(a) && a->reg == REGSP;
-}
-
-int
-smallindir(Addr *a, Addr *reg)
-{
-	return reg->type == D_REG && a->type == D_OREG &&
-		a->reg == reg->reg &&
-		0 <= a->offset && a->offset < 4096;
-}
diff --git a/src/cmd/5g/prog.c b/src/cmd/5g/prog.c
deleted file mode 100644
index 797bc07..0000000
--- a/src/cmd/5g/prog.c
+++ /dev/null
@@ -1,151 +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.
-
-#include <u.h>
-#include <libc.h>
-#include "gg.h"
-#include "opt.h"
-
-enum
-{
-	RightRdwr = RightRead | 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.
-static ProgInfo progtable[ALAST] = {
-	[ATYPE]=	{Pseudo | Skip},
-	[ATEXT]=	{Pseudo},
-	[AFUNCDATA]=	{Pseudo},
-	[APCDATA]=	{Pseudo},
-	[AUNDEF]=	{Break},
-	[AUSEFIELD]=	{OK},
-	[ACHECKNIL]=	{LeftRead},
-	[AVARDEF]=	{Pseudo | RightWrite},
-	[AVARKILL]=	{Pseudo | RightWrite},
-
-	// NOP is an internal no-op that also stands
-	// for USED and SET annotations, not the Intel opcode.
-	[ANOP]=		{LeftRead | RightWrite},
-	
-	// Integer.
-	[AADC]=		{SizeL | LeftRead | RegRead | RightWrite},
-	[AADD]=		{SizeL | LeftRead | RegRead | RightWrite},
-	[AAND]=		{SizeL | LeftRead | RegRead | RightWrite},
-	[ABIC]=		{SizeL | LeftRead | RegRead | RightWrite},
-	[ACMN]=		{SizeL | LeftRead | RightRead},
-	[ACMP]=		{SizeL | LeftRead | RightRead},
-	[ADIVU]=	{SizeL | LeftRead | RegRead | RightWrite},
-	[ADIV]=		{SizeL | LeftRead | RegRead | RightWrite},
-	[AEOR]=		{SizeL | LeftRead | RegRead | RightWrite},
-	[AMODU]=	{SizeL | LeftRead | RegRead | RightWrite},
-	[AMOD]=		{SizeL | LeftRead | RegRead | RightWrite},
-	[AMULALU]=	{SizeL | LeftRead | RegRead | RightRdwr},
-	[AMULAL]=	{SizeL | LeftRead | RegRead | RightRdwr},
-	[AMULA]=	{SizeL | LeftRead | RegRead | RightRdwr},
-	[AMULU]=	{SizeL | LeftRead | RegRead | RightWrite},
-	[AMUL]=		{SizeL | LeftRead | RegRead | RightWrite},
-	[AMULL]=	{SizeL | LeftRead | RegRead | RightWrite},
-	[AMULLU]=	{SizeL | LeftRead | RegRead | RightWrite},
-	[AMVN]=		{SizeL | LeftRead | RightWrite},
-	[AORR]=		{SizeL | LeftRead | RegRead | RightWrite},
-	[ARSB]=		{SizeL | LeftRead | RegRead | RightWrite},
-	[ARSC]=		{SizeL | LeftRead | RegRead | RightWrite},
-	[ASBC]=		{SizeL | LeftRead | RegRead | RightWrite},
-	[ASLL]=		{SizeL | LeftRead | RegRead | RightWrite},
-	[ASRA]=		{SizeL | LeftRead | RegRead | RightWrite},
-	[ASRL]=		{SizeL | LeftRead | RegRead | RightWrite},
-	[ASUB]=		{SizeL | LeftRead | RegRead | RightWrite},
-	[ATEQ]=		{SizeL | LeftRead | RightRead},
-	[ATST]=		{SizeL | LeftRead | RightRead},
-
-	// Floating point.
-	[AADDD]=	{SizeD | LeftRead | RightRdwr},
-	[AADDF]=	{SizeF | LeftRead | RightRdwr},
-	[ACMPD]=	{SizeD | LeftRead | RightRead},
-	[ACMPF]=	{SizeF | LeftRead | RightRead},
-	[ADIVD]=	{SizeD | LeftRead | RightRdwr},
-	[ADIVF]=	{SizeF | LeftRead | RightRdwr},
-	[AMULD]=	{SizeD | LeftRead | RightRdwr},
-	[AMULF]=	{SizeF | LeftRead | RightRdwr},
-	[ASUBD]=	{SizeD | LeftRead | RightRdwr},
-	[ASUBF]=	{SizeF | LeftRead | RightRdwr},
-
-	// Conversions.
-	[AMOVWD]=		{SizeD | LeftRead | RightWrite | Conv},
-	[AMOVWF]=		{SizeF | LeftRead | RightWrite | Conv},
-	[AMOVDF]=		{SizeF | LeftRead | RightWrite | Conv},
-	[AMOVDW]=		{SizeL | LeftRead | RightWrite | Conv},
-	[AMOVFD]=		{SizeD | LeftRead | RightWrite | Conv},
-	[AMOVFW]=		{SizeL | LeftRead | RightWrite | Conv},
-
-	// Moves.
-	[AMOVB]=		{SizeB | LeftRead | RightWrite | Move},
-	[AMOVD]=		{SizeD | LeftRead | RightWrite | Move},
-	[AMOVF]=		{SizeF | LeftRead | RightWrite | Move},
-	[AMOVH]=		{SizeW | LeftRead | RightWrite | Move},
-	[AMOVW]=		{SizeL | LeftRead | RightWrite | Move},
-	// In addtion, duffzero reads R0,R1 and writes R1.  This fact is
-	// encoded in peep.c
-	[ADUFFZERO]=		{Call},
-	// In addtion, duffcopy reads R1,R2 and writes R0,R1,R2.  This fact is
-	// encoded in peep.c
-	[ADUFFCOPY]=		{Call},
-
-	// These should be split into the two different conversions instead
-	// of overloading the one.
-	[AMOVBS]=		{SizeB | LeftRead | RightWrite | Conv},
-	[AMOVBU]=		{SizeB | LeftRead | RightWrite | Conv},
-	[AMOVHS]=		{SizeW | LeftRead | RightWrite | Conv},
-	[AMOVHU]=		{SizeW | LeftRead | RightWrite | Conv},
-	
-	// Jumps.
-	[AB]=		{Jump | Break},
-	[ABL]=		{Call},
-	[ABEQ]=		{Cjmp},
-	[ABNE]=		{Cjmp},
-	[ABCS]=		{Cjmp},
-	[ABHS]=		{Cjmp},
-	[ABCC]=		{Cjmp},
-	[ABLO]=		{Cjmp},
-	[ABMI]=		{Cjmp},
-	[ABPL]=		{Cjmp},
-	[ABVS]=		{Cjmp},
-	[ABVC]=		{Cjmp},
-	[ABHI]=		{Cjmp},
-	[ABLS]=		{Cjmp},
-	[ABGE]=		{Cjmp},
-	[ABLT]=		{Cjmp},
-	[ABGT]=		{Cjmp},
-	[ABLE]=		{Cjmp},
-	[ARET]=		{Break},
-};
-
-void
-proginfo(ProgInfo *info, Prog *p)
-{
-	*info = progtable[p->as];
-	if(info->flags == 0)
-		fatal("unknown instruction %P", p);
-
-	if(p->from.type == D_CONST && p->from.sym != nil && (info->flags & LeftRead)) {
-		info->flags &= ~LeftRead;
-		info->flags |= LeftAddr;
-	}
-
-	if((info->flags & RegRead) && p->reg == NREG) {
-		info->flags &= ~RegRead;
-		info->flags |= CanRegRead | RightRead;
-	}
-	
-	if(((p->scond & C_SCOND) != C_SCOND_NONE) && (info->flags & RightWrite))
-		info->flags |= RightRead;
-}
diff --git a/src/cmd/5g/reg.c b/src/cmd/5g/reg.c
deleted file mode 100644
index b78c268..0000000
--- a/src/cmd/5g/reg.c
+++ /dev/null
@@ -1,1453 +0,0 @@
-// Inferno utils/5c/reg.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5c/reg.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-
-#include <u.h>
-#include <libc.h>
-#include "gg.h"
-#include "opt.h"
-
-#define	NREGVAR	32
-#define	REGBITS	((uint32)0xffffffff)
-/*c2go enum {
-	NREGVAR = 32,
-	REGBITS = 0xffffffff,
-};
-*/
-
-	void	addsplits(void);
-static	Reg*	firstr;
-static	int	first	= 1;
-
-int
-rcmp(const void *a1, const void *a2)
-{
-	Rgn *p1, *p2;
-	int c1, c2;
-
-	p1 = (Rgn*)a1;
-	p2 = (Rgn*)a2;
-	c1 = p2->cost;
-	c2 = p1->cost;
-	if(c1 -= c2)
-		return c1;
-	return p2->varno - p1->varno;
-}
-
-void
-excise(Flow *r)
-{
-	Prog *p;
-
-	p = r->prog;
-	p->as = ANOP;
-	p->scond = zprog.scond;
-	p->from = zprog.from;
-	p->to = zprog.to;
-	p->reg = zprog.reg;
-}
-
-static void
-setaddrs(Bits bit)
-{
-	int i, n;
-	Var *v;
-	Node *node;
-
-	while(bany(&bit)) {
-		// convert each bit to a variable
-		i = bnum(bit);
-		node = var[i].node;
-		n = var[i].name;
-		bit.b[i/32] &= ~(1L<<(i%32));
-
-		// disable all pieces of that variable
-		for(i=0; i<nvar; i++) {
-			v = var+i;
-			if(v->node == node && v->name == n)
-				v->addr = 2;
-		}
-	}
-}
-
-static char* regname[] = {
-	".R0",
-	".R1",
-	".R2",
-	".R3",
-	".R4",
-	".R5",
-	".R6",
-	".R7",
-	".R8",
-	".R9",
-	".R10",
-	".R11",
-	".R12",
-	".R13",
-	".R14",
-	".R15",
-	".F0",
-	".F1",
-	".F2",
-	".F3",
-	".F4",
-	".F5",
-	".F6",
-	".F7",
-	".F8",
-	".F9",
-	".F10",
-	".F11",
-	".F12",
-	".F13",
-	".F14",
-	".F15",
-};
-
-static Node* regnodes[NREGVAR];
-
-static void walkvardef(Node *n, Reg *r, int active);
-
-void
-regopt(Prog *firstp)
-{
-	Reg *r, *r1;
-	Prog *p;
-	Graph *g;
-	int i, z, active;
-	uint32 vreg;
-	Bits bit;
-	ProgInfo info;
-
-	if(first) {
-		fmtinstall('Q', Qconv);
-		first = 0;
-	}
-
-	mergetemp(firstp);
-
-	/*
-	 * control flow is more complicated in generated go code
-	 * than in generated c code.  define pseudo-variables for
-	 * registers, so we have complete register usage information.
-	 */
-	nvar = NREGVAR;
-	memset(var, 0, NREGVAR*sizeof var[0]);
-	for(i=0; i<NREGVAR; i++) {
-		if(regnodes[i] == N)
-			regnodes[i] = newname(lookup(regname[i]));
-		var[i].node = regnodes[i];
-	}
-
-	regbits = RtoB(REGSP)|RtoB(REGLINK)|RtoB(REGPC);
-	for(z=0; z<BITS; z++) {
-		externs.b[z] = 0;
-		params.b[z] = 0;
-		consts.b[z] = 0;
-		addrs.b[z] = 0;
-		ivar.b[z] = 0;
-		ovar.b[z] = 0;
-	}
-
-	/*
-	 * pass 1
-	 * build aux data structure
-	 * allocate pcs
-	 * find use and set of variables
-	 */
-	g = flowstart(firstp, sizeof(Reg));
-	if(g == nil) {
-		for(i=0; i<nvar; i++)
-			var[i].node->opt = nil;
-		return;
-	}
-
-	firstr = (Reg*)g->start;
-
-	for(r = firstr; r != R; r = (Reg*)r->f.link) {
-		p = r->f.prog;
-		if(p->as == AVARDEF || p->as == AVARKILL)
-			continue;
-		proginfo(&info, p);
-
-		// Avoid making variables for direct-called functions.
-		if(p->as == ABL && p->to.name == D_EXTERN)
-			continue;
-
-		bit = mkvar(r, &p->from);
-		if(info.flags & LeftRead)
-			for(z=0; z<BITS; z++)
-				r->use1.b[z] |= bit.b[z];
-		if(info.flags & LeftAddr)
-			setaddrs(bit);
-
-		if(info.flags & RegRead) {	
-			if(p->from.type != D_FREG)
-				r->use1.b[0] |= RtoB(p->reg);
-			else
-				r->use1.b[0] |= FtoB(p->reg);
-		}
-
-		if(info.flags & (RightAddr | RightRead | RightWrite)) {
-			bit = mkvar(r, &p->to);
-			if(info.flags & RightAddr)
-				setaddrs(bit);
-			if(info.flags & RightRead)
-				for(z=0; z<BITS; z++)
-					r->use2.b[z] |= bit.b[z];
-			if(info.flags & RightWrite)
-				for(z=0; z<BITS; z++)
-					r->set.b[z] |= bit.b[z];
-		}
-
-		/* the mod/div runtime routines smash R12 */
-		if(p->as == ADIV || p->as == ADIVU || p->as == AMOD || p->as == AMODU)
-			r->set.b[0] |= RtoB(12);
-	}
-	if(firstr == R)
-		return;
-
-	for(i=0; i<nvar; i++) {
-		Var *v = var+i;
-		if(v->addr) {
-			bit = blsh(i);
-			for(z=0; z<BITS; z++)
-				addrs.b[z] |= bit.b[z];
-		}
-
-		if(debug['R'] && debug['v'])
-			print("bit=%2d addr=%d et=%-6E w=%-2d s=%N + %lld\n",
-				i, v->addr, v->etype, v->width, v->node, v->offset);
-	}
-
-	if(debug['R'] && debug['v'])
-		dumpit("pass1", &firstr->f, 1);
-
-	/*
-	 * pass 2
-	 * find looping structure
-	 */
-	flowrpo(g);
-
-	if(debug['R'] && debug['v'])
-		dumpit("pass2", &firstr->f, 1);
-
-	/*
-	 * pass 2.5
-	 * iterate propagating fat vardef covering forward
-	 * r->act records vars with a VARDEF since the last CALL.
-	 * (r->act will be reused in pass 5 for something else,
-	 * but we'll be done with it by then.)
-	 */
-	active = 0;
-	for(r = firstr; r != R; r = (Reg*)r->f.link) {
-		r->f.active = 0;
-		r->act = zbits;
-	}
-	for(r = firstr; r != R; r = (Reg*)r->f.link) {
-		p = r->f.prog;
-		if(p->as == AVARDEF && isfat(p->to.node->type) && p->to.node->opt != nil) {
-			active++;
-			walkvardef(p->to.node, r, active);
-		}
-	}
-
-	/*
-	 * pass 3
-	 * iterate propagating usage
-	 * 	back until flow graph is complete
-	 */
-loop1:
-	change = 0;
-	for(r = firstr; r != R; r = (Reg*)r->f.link)
-		r->f.active = 0;
-	for(r = firstr; r != R; r = (Reg*)r->f.link)
-		if(r->f.prog->as == ARET)
-			prop(r, zbits, zbits);
-loop11:
-	/* pick up unreachable code */
-	i = 0;
-	for(r = firstr; r != R; r = r1) {
-		r1 = (Reg*)r->f.link;
-		if(r1 && r1->f.active && !r->f.active) {
-			prop(r, zbits, zbits);
-			i = 1;
-		}
-	}
-	if(i)
-		goto loop11;
-	if(change)
-		goto loop1;
-
-	if(debug['R'] && debug['v'])
-		dumpit("pass3", &firstr->f, 1);
-
-
-	/*
-	 * pass 4
-	 * iterate propagating register/variable synchrony
-	 * 	forward until graph is complete
-	 */
-loop2:
-	change = 0;
-	for(r = firstr; r != R; r = (Reg*)r->f.link)
-		r->f.active = 0;
-	synch(firstr, zbits);
-	if(change)
-		goto loop2;
-
-	addsplits();
-
-	if(debug['R'] && debug['v'])
-		dumpit("pass4", &firstr->f, 1);
-
-	if(debug['R'] > 1) {
-		print("\nprop structure:\n");
-		for(r = firstr; r != R; r = (Reg*)r->f.link) {
-			print("%d:%P", r->f.loop, r->f.prog);
-			for(z=0; z<BITS; z++) {
-				bit.b[z] = r->set.b[z] |
-					r->refahead.b[z] | r->calahead.b[z] |
-					r->refbehind.b[z] | r->calbehind.b[z] |
-					r->use1.b[z] | r->use2.b[z];
-				bit.b[z] &= ~addrs.b[z];
-			}
-
-			if(bany(&bit)) {
-				print("\t");
-				if(bany(&r->use1))
-					print(" u1=%Q", r->use1);
-				if(bany(&r->use2))
-					print(" u2=%Q", r->use2);
-				if(bany(&r->set))
-					print(" st=%Q", r->set);
-				if(bany(&r->refahead))
-					print(" ra=%Q", r->refahead);
-				if(bany(&r->calahead))
-					print(" ca=%Q", r->calahead);
-				if(bany(&r->refbehind))
-					print(" rb=%Q", r->refbehind);
-				if(bany(&r->calbehind))
-					print(" cb=%Q", r->calbehind);
-			}
-			print("\n");
-		}
-	}
-
-	/*
-	 * pass 4.5
-	 * move register pseudo-variables into regu.
-	 */
-	for(r = firstr; r != R; r = (Reg*)r->f.link) {
-		r->regu = (r->refbehind.b[0] | r->set.b[0]) & REGBITS;
-
-		r->set.b[0] &= ~REGBITS;
-		r->use1.b[0] &= ~REGBITS;
-		r->use2.b[0] &= ~REGBITS;
-		r->refbehind.b[0] &= ~REGBITS;
-		r->refahead.b[0] &= ~REGBITS;
-		r->calbehind.b[0] &= ~REGBITS;
-		r->calahead.b[0] &= ~REGBITS;
-		r->regdiff.b[0] &= ~REGBITS;
-		r->act.b[0] &= ~REGBITS;
-	}
-
-	if(debug['R'] && debug['v'])
-		dumpit("pass4.5", &firstr->f, 1);
-
-	/*
-	 * pass 5
-	 * isolate regions
-	 * calculate costs (paint1)
-	 */
-	r = firstr;
-	if(r) {
-		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]);
-		if(bany(&bit) & !r->f.refset) {
-			// should never happen - all variables are preset
-			if(debug['w'])
-				print("%L: used and not set: %Q\n", r->f.prog->lineno, bit);
-			r->f.refset = 1;
-		}
-	}
-
-	for(r = firstr; r != R; r = (Reg*)r->f.link)
-		r->act = zbits;
-	rgp = region;
-	nregion = 0;
-	for(r = firstr; r != R; r = (Reg*)r->f.link) {
-		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) && !r->f.refset) {
-			if(debug['w'])
-				print("%L: set and not used: %Q\n", r->f.prog->lineno, bit);
-			r->f.refset = 1;
-			excise(&r->f);
-		}
-		for(z=0; z<BITS; z++)
-			bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]);
-		while(bany(&bit)) {
-			i = bnum(bit);
-			rgp->enter = r;
-			rgp->varno = i;
-			change = 0;
-			if(debug['R'] > 1)
-				print("\n");
-			paint1(r, i);
-			bit.b[i/32] &= ~(1L<<(i%32));
-			if(change <= 0) {
-				if(debug['R'])
-					print("%L $%d: %Q\n",
-						r->f.prog->lineno, change, blsh(i));
-				continue;
-			}
-			rgp->cost = change;
-			nregion++;
-			if(nregion >= NRGN) {
-				if(debug['R'] > 1)
-					print("too many regions\n");
-				goto brk;
-			}
-			rgp++;
-		}
-	}
-brk:
-	qsort(region, nregion, sizeof(region[0]), rcmp);
-
-	if(debug['R'] && debug['v'])
-		dumpit("pass5", &firstr->f, 1);
-
-	/*
-	 * pass 6
-	 * determine used registers (paint2)
-	 * replace code (paint3)
-	 */
-	rgp = region;
-	for(i=0; i<nregion; i++) {
-		bit = blsh(rgp->varno);
-		vreg = paint2(rgp->enter, rgp->varno);
-		vreg = allreg(vreg, rgp);
-		if(debug['R']) {
-			if(rgp->regno >= NREG)
-				print("%L $%d F%d: %Q\n",
-					rgp->enter->f.prog->lineno,
-					rgp->cost,
-					rgp->regno-NREG,
-					bit);
-			else
-				print("%L $%d R%d: %Q\n",
-					rgp->enter->f.prog->lineno,
-					rgp->cost,
-					rgp->regno,
-					bit);
-		}
-		if(rgp->regno != 0)
-			paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
-		rgp++;
-	}
-
-	if(debug['R'] && debug['v'])
-		dumpit("pass6", &firstr->f, 1);
-
-	/*
-	 * free aux structures. peep allocates new ones.
-	 */
-	for(i=0; i<nvar; i++)
-		var[i].node->opt = nil;
-	flowend(g);
-	firstr = R;
-
-	/*
-	 * pass 7
-	 * peep-hole on basic block
-	 */
-	if(!debug['R'] || debug['P']) {
-		peep(firstp);
-	}
-
-	if(debug['R'] && debug['v'])
-		dumpit("pass7", &firstr->f, 1);
-
-	/*
-	 * last pass
-	 * eliminate nops
-	 * free aux structures
-	 * adjust the stack pointer
-	 *	MOVW.W 	R1,-12(R13)			<<- start
-	 *	MOVW   	R0,R1
-	 *	MOVW   	R1,8(R13)
-	 *	MOVW   	$0,R1
-	 *	MOVW   	R1,4(R13)
-	 *	BL     	,runtime.newproc+0(SB)
-	 *	MOVW   	&ft+-32(SP),R7			<<- adjust
-	 *	MOVW   	&j+-40(SP),R6			<<- adjust
-	 *	MOVW   	autotmp_0003+-24(SP),R5		<<- adjust
-	 *	MOVW   	$12(R13),R13			<<- finish
-	 */
-	vreg = 0;
-	for(p = firstp; p != P; p = p->link) {
-		while(p->link != P && p->link->as == ANOP)
-			p->link = p->link->link;
-		if(p->to.type == D_BRANCH)
-			while(p->to.u.branch != P && p->to.u.branch->as == ANOP)
-				p->to.u.branch = p->to.u.branch->link;
-		if(p->as == AMOVW && p->to.reg == 13) {
-			if(p->scond & C_WBIT) {
-				vreg = -p->to.offset;		// in adjust region
-//				print("%P adjusting %d\n", p, vreg);
-				continue;
-			}
-			if(p->from.type == D_CONST && p->to.type == D_REG) {
-				if(p->from.offset != vreg)
-					print("in and out different\n");
-//				print("%P finish %d\n", p, vreg);
-				vreg = 0;	// done adjust region
-				continue;
-			}
-
-//			print("%P %d %d from type\n", p, p->from.type, D_CONST);
-//			print("%P %d %d to type\n\n", p, p->to.type, D_REG);
-		}
-
-		if(p->as == AMOVW && vreg != 0) {
-			if(p->from.sym != nil)
-			if(p->from.name == D_AUTO || p->from.name == D_PARAM) {
-				p->from.offset += vreg;
-//				print("%P adjusting from %d %d\n", p, vreg, p->from.type);
-			}
-			if(p->to.sym != nil)
-			if(p->to.name == D_AUTO || p->to.name == D_PARAM) {
-				p->to.offset += vreg;
-//				print("%P adjusting to %d %d\n", p, vreg, p->from.type);
-			}
-		}
-	}
-}
-
-static void
-walkvardef(Node *n, Reg *r, int active)
-{
-	Reg *r1, *r2;
-	int bn;
-	Var *v;
-	
-	for(r1=r; r1!=R; r1=(Reg*)r1->f.s1) {
-		if(r1->f.active == active)
-			break;
-		r1->f.active = active;
-		if(r1->f.prog->as == AVARKILL && r1->f.prog->to.node == n)
-			break;
-		for(v=n->opt; v!=nil; v=v->nextinnode) {
-			bn = v - var;
-			r1->act.b[bn/32] |= 1L << (bn%32);
-		}
-		if(r1->f.prog->as == ABL)
-			break;
-	}
-
-	for(r2=r; r2!=r1; r2=(Reg*)r2->f.s1)
-		if(r2->f.s2 != nil)
-			walkvardef(n, (Reg*)r2->f.s2, active);
-}
-
-void
-addsplits(void)
-{
-	Reg *r, *r1;
-	int z, i;
-	Bits bit;
-
-	for(r = firstr; r != R; r = (Reg*)r->f.link) {
-		if(r->f.loop > 1)
-			continue;
-		if(r->f.prog->as == ABL)
-			continue;
-		if(r->f.prog->as == ADUFFZERO)
-			continue;
-		if(r->f.prog->as == ADUFFCOPY)
-			continue;
-		for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link) {
-			if(r1->f.loop <= 1)
-				continue;
-			for(z=0; z<BITS; z++)
-				bit.b[z] = r1->calbehind.b[z] &
-					(r->refahead.b[z] | r->use1.b[z] | r->use2.b[z]) &
-					~(r->calahead.b[z] & addrs.b[z]);
-			while(bany(&bit)) {
-				i = bnum(bit);
-				bit.b[i/32] &= ~(1L << (i%32));
-			}
-		}
-	}
-}
-
-/*
- * add mov b,rn
- * just after r
- */
-void
-addmove(Reg *r, int bn, int rn, int f)
-{
-	Prog *p, *p1, *p2;
-	Adr *a;
-	Var *v;
-
-	p1 = mal(sizeof(*p1));
-	*p1 = zprog;
-	p = r->f.prog;
-	
-	// If there's a stack fixup coming (after BL newproc or BL deferproc),
-	// delay the load until after the fixup.
-	p2 = p->link;
-	if(p2 && p2->as == AMOVW && p2->from.type == D_CONST && p2->from.reg == REGSP && p2->to.reg == REGSP && p2->to.type == D_REG)
-		p = p2;
-
-	p1->link = p->link;
-	p->link = p1;
-	p1->lineno = p->lineno;
-
-	v = var + bn;
-
-	a = &p1->to;
-	a->name = v->name;
-	a->node = v->node;
-	a->sym = linksym(v->node->sym);
-	a->offset = v->offset;
-	a->etype = v->etype;
-	a->type = D_OREG;
-	if(a->etype == TARRAY || a->sym == nil)
-		a->type = D_CONST;
-
-	if(v->addr)
-		fatal("addmove: shouldn't be doing this %A\n", a);
-
-	switch(v->etype) {
-	default:
-		print("What is this %E\n", v->etype);
-
-	case TINT8:
-		p1->as = AMOVBS;
-		break;
-	case TBOOL:
-	case TUINT8:
-//print("movbu %E %d %S\n", v->etype, bn, v->sym);
-		p1->as = AMOVBU;
-		break;
-	case TINT16:
-		p1->as = AMOVHS;
-		break;
-	case TUINT16:
-		p1->as = AMOVHU;
-		break;
-	case TINT32:
-	case TUINT32:
-	case TPTR32:
-		p1->as = AMOVW;
-		break;
-	case TFLOAT32:
-		p1->as = AMOVF;
-		break;
-	case TFLOAT64:
-		p1->as = AMOVD;
-		break;
-	}
-
-	p1->from.type = D_REG;
-	p1->from.reg = rn;
-	if(rn >= NREG) {
-		p1->from.type = D_FREG;
-		p1->from.reg = rn-NREG;
-	}
-	if(!f) {
-		p1->from = *a;
-		*a = zprog.from;
-		a->type = D_REG;
-		a->reg = rn;
-		if(rn >= NREG) {
-			a->type = D_FREG;
-			a->reg = rn-NREG;
-		}
-		if(v->etype == TUINT8 || v->etype == TBOOL)
-			p1->as = AMOVBU;
-		if(v->etype == TUINT16)
-			p1->as = AMOVHU;
-	}
-	if(debug['R'])
-		print("%P\t.a%P\n", p, p1);
-}
-
-static int
-overlap(int32 o1, int w1, int32 o2, int w2)
-{
-	int32 t1, t2;
-
-	t1 = o1+w1;
-	t2 = o2+w2;
-
-	if(!(t1 > o2 && t2 > o1))
-		return 0;
-
-	return 1;
-}
-
-Bits
-mkvar(Reg *r, Adr *a)
-{
-	Var *v;
-	int i, t, n, et, z, w, flag;
-	int32 o;
-	Bits bit;
-	Node *node;
-
-	// mark registers used
-	t = a->type;
-
-	flag = 0;
-	switch(t) {
-	default:
-		print("type %d %d %D\n", t, a->name, a);
-		goto none;
-
-	case D_NONE:
-	case D_FCONST:
-	case D_BRANCH:
-		break;
-
-
-	case D_REGREG:
-	case D_REGREG2:
-		bit = zbits;
-		if(a->offset != NREG)
-			bit.b[0] |= RtoB(a->offset);
-		if(a->reg != NREG)
-			bit.b[0] |= RtoB(a->reg);
-		return bit;
-
-	case D_CONST:
-	case D_REG:
-	case D_SHIFT:
-		if(a->reg != NREG) {
-			bit = zbits;
-			bit.b[0] = RtoB(a->reg);
-			return bit;
-		}
-		break;
-
-	case D_OREG:
-		if(a->reg != NREG) {
-			if(a == &r->f.prog->from)
-				r->use1.b[0] |= RtoB(a->reg);
-			else
-				r->use2.b[0] |= RtoB(a->reg);
-			if(r->f.prog->scond & (C_PBIT|C_WBIT))
-				r->set.b[0] |= RtoB(a->reg);
-		}
-		break;
-
-	case D_FREG:
-		if(a->reg != NREG) {
-			bit = zbits;
-			bit.b[0] = FtoB(a->reg);
-			return bit;
-		}
-		break;
-	}
-
-	switch(a->name) {
-	default:
-		goto none;
-
-	case D_EXTERN:
-	case D_STATIC:
-	case D_AUTO:
-	case D_PARAM:
-		n = a->name;
-		break;
-	}
-
-	node = a->node;
-	if(node == N || node->op != ONAME || node->orig == N)
-		goto none;
-	node = node->orig;
-	if(node->orig != node)
-		fatal("%D: bad node", a);
-	if(node->sym == S || node->sym->name[0] == '.')
-		goto none;
-	et = a->etype;
-	o = a->offset;
-	w = a->width;
-	if(w < 0)
-		fatal("bad width %d for %D", w, a);
-
-	for(i=0; i<nvar; i++) {
-		v = var+i;
-		if(v->node == node && v->name == n) {
-			if(v->offset == o)
-			if(v->etype == et)
-			if(v->width == w)
-				if(!flag)
-					return blsh(i);
-
-			// if they overlap, disable both
-			if(overlap(v->offset, v->width, o, w)) {
-				v->addr = 1;
-				flag = 1;
-			}
-		}
-	}
-
-	switch(et) {
-	case 0:
-	case TFUNC:
-		goto none;
-	}
-
-	if(nvar >= NVAR) {
-		if(debug['w'] > 1 && node)
-			fatal("variable not optimized: %D", a);
-		
-		// 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
-		// live at all calls. otherwise we might optimize away part of
-		// a variable but not all of it.
-		for(i=0; i<nvar; i++) {
-			v = var+i;
-			if(v->node == node)
-				v->addr = 1;
-		}
-		goto none;
-	}
-
-	i = nvar;
-	nvar++;
-//print("var %d %E %D %S\n", i, et, a, s);
-	v = var+i;
-	v->offset = o;
-	v->name = n;
-	v->etype = et;
-	v->width = w;
-	v->addr = flag;		// funny punning
-	v->node = node;
-	
-	// node->opt is the head of a linked list
-	// of Vars within the given Node, so that
-	// we can start at a Var and find all the other
-	// Vars in the same Go variable.
-	v->nextinnode = node->opt;
-	node->opt = v;
-	
-	bit = blsh(i);
-	if(n == D_EXTERN || n == D_STATIC)
-		for(z=0; z<BITS; z++)
-			externs.b[z] |= bit.b[z];
-	if(n == D_PARAM)
-		for(z=0; z<BITS; z++)
-			params.b[z] |= bit.b[z];
-
-	if(node->class == PPARAM)
-		for(z=0; z<BITS; z++)
-			ivar.b[z] |= bit.b[z];
-	if(node->class == PPARAMOUT)
-		for(z=0; z<BITS; z++)
-			ovar.b[z] |= bit.b[z];
-
-	// Treat values with their address taken as live at calls,
-	// because the garbage collector's liveness analysis in ../gc/plive.c does.
-	// These must be consistent or else we will elide stores and the garbage
-	// collector will see uninitialized data.
-	// The typical case where our own analysis is out of sync is when the
-	// node appears to have its address taken but that code doesn't actually
-	// get generated and therefore doesn't show up as an address being
-	// taken when we analyze the instruction stream.
-	// One instance of this case is when a closure uses the same name as
-	// an outer variable for one of its own variables declared with :=.
-	// The parser flags the outer variable as possibly shared, and therefore
-	// sets addrtaken, even though it ends up not being actually shared.
-	// 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)
-		v->addr = 1;
-
-	// Disable registerization for globals, because:
-	// (1) we might panic at any time and we want the recovery code
-	// to see the latest values (issue 1304).
-	// (2) we don't know what pointers might point at them and we want
-	// loads via those pointers to see updated values and vice versa (issue 7995).
-	//
-	// Disable registerization for results if using defer, because the deferred func
-	// might recover and return, causing the current values to be used.
-	if(node->class == PEXTERN || (hasdefer && node->class == PPARAMOUT))
-		v->addr = 1;
-
-	if(debug['R'])
-		print("bit=%2d et=%2E w=%d+%d %#N %D flag=%d\n", i, et, o, w, node, a, v->addr);
-
-	return bit;
-
-none:
-	return zbits;
-}
-
-void
-prop(Reg *r, Bits ref, Bits cal)
-{
-	Reg *r1, *r2;
-	int z, i, j;
-	Var *v, *v1;
-
-	for(r1 = r; r1 != R; r1 = (Reg*)r1->f.p1) {
-		for(z=0; z<BITS; z++) {
-			ref.b[z] |= r1->refahead.b[z];
-			if(ref.b[z] != r1->refahead.b[z]) {
-				r1->refahead.b[z] = ref.b[z];
-				change++;
-			}
-			cal.b[z] |= r1->calahead.b[z];
-			if(cal.b[z] != r1->calahead.b[z]) {
-				r1->calahead.b[z] = cal.b[z];
-				change++;
-			}
-		}
-		switch(r1->f.prog->as) {
-		case ABL:
-			if(noreturn(r1->f.prog))
-				break;
-
-			// Mark all input variables (ivar) as used, because that's what the
-			// liveness bitmaps say. The liveness bitmaps say that so that a
-			// panic will not show stale values in the parameter dump.
-			// Mark variables with a recent VARDEF (r1->act) as used,
-			// so that the optimizer flushes initializations to memory,
-			// so that if a garbage collection happens during this CALL,
-			// the collector will see initialized memory. Again this is to
-			// match what the liveness bitmaps say.
-			for(z=0; z<BITS; z++) {
-				cal.b[z] |= ref.b[z] | externs.b[z] | ivar.b[z] | r1->act.b[z];
-				ref.b[z] = 0;
-			}
-			
-			// cal.b is the current approximation of what's live across the call.
-			// Every bit in cal.b is a single stack word. For each such word,
-			// find all the other tracked stack words in the same Go variable
-			// (struct/slice/string/interface) and mark them live too.
-			// This is necessary because the liveness analysis for the garbage
-			// collector works at variable granularity, not at word granularity.
-			// It is fundamental for slice/string/interface: the garbage collector
-			// needs the whole value, not just some of the words, in order to
-			// interpret the other bits correctly. Specifically, slice needs a consistent
-			// ptr and cap, string needs a consistent ptr and len, and interface
-			// needs a consistent type word and data word.
-			for(z=0; z<BITS; z++) {
-				if(cal.b[z] == 0)
-					continue;
-				for(i=0; i<32; i++) {
-					if(z*32+i >= nvar || ((cal.b[z]>>i)&1) == 0)
-						continue;
-					v = var+z*32+i;
-					if(v->node->opt == nil) // v represents fixed register, not Go variable
-						continue;
-
-					// v->node->opt is the head of a linked list of Vars
-					// corresponding to tracked words from the Go variable v->node.
-					// Walk the list and set all the bits.
-					// For a large struct this could end up being quadratic:
-					// after the first setting, the outer loop (for z, i) would see a 1 bit
-					// for all of the remaining words in the struct, and for each such
-					// word would go through and turn on all the bits again.
-					// To avoid the quadratic behavior, we only turn on the bits if
-					// v is the head of the list or if the head's bit is not yet turned on.
-					// This will set the bits at most twice, keeping the overall loop linear.
-					v1 = v->node->opt;
-					j = v1 - var;
-					if(v == v1 || ((cal.b[j/32]>>(j&31))&1) == 0) {
-						for(; v1 != nil; v1 = v1->nextinnode) {
-							j = v1 - var;
-							cal.b[j/32] |= 1<<(j&31);
-						}
-					}
-				}
-			}
-			break;
-
-		case ATEXT:
-			for(z=0; z<BITS; z++) {
-				cal.b[z] = 0;
-				ref.b[z] = 0;
-			}
-			break;
-
-		case ARET:
-			for(z=0; z<BITS; z++) {
-				cal.b[z] = externs.b[z] | ovar.b[z];
-				ref.b[z] = 0;
-			}
-			break;
-		}
-		for(z=0; z<BITS; z++) {
-			ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
-				r1->use1.b[z] | r1->use2.b[z];
-			cal.b[z] &= ~(r1->set.b[z] | r1->use1.b[z] | r1->use2.b[z]);
-			r1->refbehind.b[z] = ref.b[z];
-			r1->calbehind.b[z] = cal.b[z];
-		}
-		if(r1->f.active)
-			break;
-		r1->f.active = 1;
-	}
-	for(; r != r1; r = (Reg*)r->f.p1)
-		for(r2 = (Reg*)r->f.p2; r2 != R; r2 = (Reg*)r2->f.p2link)
-			prop(r2, r->refbehind, r->calbehind);
-}
-
-void
-synch(Reg *r, Bits dif)
-{
-	Reg *r1;
-	int z;
-
-	for(r1 = r; r1 != R; r1 = (Reg*)r1->f.s1) {
-		for(z=0; z<BITS; z++) {
-			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++;
-			}
-		}
-		if(r1->f.active)
-			break;
-		r1->f.active = 1;
-		for(z=0; z<BITS; z++)
-			dif.b[z] &= ~(~r1->calbehind.b[z] & r1->calahead.b[z]);
-		if(r1->f.s2 != nil)
-			synch((Reg*)r1->f.s2, dif);
-	}
-}
-
-uint32
-allreg(uint32 b, Rgn *r)
-{
-	Var *v;
-	int i;
-
-	v = var + r->varno;
-	r->regno = 0;
-	switch(v->etype) {
-
-	default:
-		fatal("unknown etype %d/%E", bitno(b), v->etype);
-		break;
-
-	case TINT8:
-	case TUINT8:
-	case TINT16:
-	case TUINT16:
-	case TINT32:
-	case TUINT32:
-	case TINT:
-	case TUINT:
-	case TUINTPTR:
-	case TBOOL:
-	case TPTR32:
-		i = BtoR(~b);
-		if(i && r->cost >= 0) {
-			r->regno = i;
-			return RtoB(i);
-		}
-		break;
-
-	case TFLOAT32:
-	case TFLOAT64:
-		i = BtoF(~b);
-		if(i && r->cost >= 0) {
-			r->regno = i+NREG;
-			return FtoB(i);
-		}
-		break;
-
-	case TINT64:
-	case TUINT64:
-	case TPTR64:
-	case TINTER:
-	case TSTRUCT:
-	case TARRAY:
-		break;
-	}
-	return 0;
-}
-
-void
-paint1(Reg *r, int bn)
-{
-	Reg *r1;
-	Prog *p;
-	int z;
-	uint32 bb;
-
-	z = bn/32;
-	bb = 1L<<(bn%32);
-	if(r->act.b[z] & bb)
-		return;
-	for(;;) {
-		if(!(r->refbehind.b[z] & bb))
-			break;
-		r1 = (Reg*)r->f.p1;
-		if(r1 == R)
-			break;
-		if(!(r1->refahead.b[z] & bb))
-			break;
-		if(r1->act.b[z] & bb)
-			break;
-		r = r1;
-	}
-
-	if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb) {
-		change -= CLOAD * r->f.loop;
-		if(debug['R'] > 1)
-			print("%d%P\td %Q $%d\n", r->f.loop,
-				r->f.prog, blsh(bn), change);
-	}
-	for(;;) {
-		r->act.b[z] |= bb;
-		p = r->f.prog;
-
-
-		if(r->f.prog->as != ANOP) { // don't give credit for NOPs
-			if(r->use1.b[z] & bb) {
-				change += CREF * r->f.loop;
-				if(debug['R'] > 1)
-					print("%d%P\tu1 %Q $%d\n", r->f.loop,
-						p, blsh(bn), change);
-			}
-			if((r->use2.b[z]|r->set.b[z]) & bb) {
-				change += CREF * r->f.loop;
-				if(debug['R'] > 1)
-					print("%d%P\tu2 %Q $%d\n", r->f.loop,
-						p, blsh(bn), change);
-			}
-		}
-
-		if(STORE(r) & r->regdiff.b[z] & bb) {
-			change -= CLOAD * r->f.loop;
-			if(debug['R'] > 1)
-				print("%d%P\tst %Q $%d\n", r->f.loop,
-					p, blsh(bn), change);
-		}
-
-		if(r->refbehind.b[z] & bb)
-			for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link)
-				if(r1->refahead.b[z] & bb)
-					paint1(r1, bn);
-
-		if(!(r->refahead.b[z] & bb))
-			break;
-		r1 = (Reg*)r->f.s2;
-		if(r1 != R)
-			if(r1->refbehind.b[z] & bb)
-				paint1(r1, bn);
-		r = (Reg*)r->f.s1;
-		if(r == R)
-			break;
-		if(r->act.b[z] & bb)
-			break;
-		if(!(r->refbehind.b[z] & bb))
-			break;
-	}
-}
-
-uint32
-paint2(Reg *r, int bn)
-{
-	Reg *r1;
-	int z;
-	uint32 bb, vreg;
-
-	z = bn/32;
-	bb = 1L << (bn%32);
-	vreg = regbits;
-	if(!(r->act.b[z] & bb))
-		return vreg;
-	for(;;) {
-		if(!(r->refbehind.b[z] & bb))
-			break;
-		r1 = (Reg*)r->f.p1;
-		if(r1 == R)
-			break;
-		if(!(r1->refahead.b[z] & bb))
-			break;
-		if(!(r1->act.b[z] & bb))
-			break;
-		r = r1;
-	}
-	for(;;) {
-		r->act.b[z] &= ~bb;
-
-		vreg |= r->regu;
-
-		if(r->refbehind.b[z] & bb)
-			for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link)
-				if(r1->refahead.b[z] & bb)
-					vreg |= paint2(r1, bn);
-
-		if(!(r->refahead.b[z] & bb))
-			break;
-		r1 = (Reg*)r->f.s2;
-		if(r1 != R)
-			if(r1->refbehind.b[z] & bb)
-				vreg |= paint2(r1, bn);
-		r = (Reg*)r->f.s1;
-		if(r == R)
-			break;
-		if(!(r->act.b[z] & bb))
-			break;
-		if(!(r->refbehind.b[z] & bb))
-			break;
-	}
-	return vreg;
-}
-
-void
-paint3(Reg *r, int bn, int32 rb, int rn)
-{
-	Reg *r1;
-	Prog *p;
-	int z;
-	uint32 bb;
-
-	z = bn/32;
-	bb = 1L << (bn%32);
-	if(r->act.b[z] & bb)
-		return;
-	for(;;) {
-		if(!(r->refbehind.b[z] & bb))
-			break;
-		r1 = (Reg*)r->f.p1;
-		if(r1 == R)
-			break;
-		if(!(r1->refahead.b[z] & bb))
-			break;
-		if(r1->act.b[z] & bb)
-			break;
-		r = r1;
-	}
-
-	if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb)
-		addmove(r, bn, rn, 0);
-
-	for(;;) {
-		r->act.b[z] |= bb;
-		p = r->f.prog;
-
-		if(r->use1.b[z] & bb) {
-			if(debug['R'])
-				print("%P", p);
-			addreg(&p->from, rn);
-			if(debug['R'])
-				print("\t.c%P\n", p);
-		}
-		if((r->use2.b[z]|r->set.b[z]) & bb) {
-			if(debug['R'])
-				print("%P", p);
-			addreg(&p->to, rn);
-			if(debug['R'])
-				print("\t.c%P\n", p);
-		}
-
-		if(STORE(r) & r->regdiff.b[z] & bb)
-			addmove(r, bn, rn, 1);
-		r->regu |= rb;
-
-		if(r->refbehind.b[z] & bb)
-			for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link)
-				if(r1->refahead.b[z] & bb)
-					paint3(r1, bn, rb, rn);
-
-		if(!(r->refahead.b[z] & bb))
-			break;
-		r1 = (Reg*)r->f.s2;
-		if(r1 != R)
-			if(r1->refbehind.b[z] & bb)
-				paint3(r1, bn, rb, rn);
-		r = (Reg*)r->f.s1;
-		if(r == R)
-			break;
-		if(r->act.b[z] & bb)
-			break;
-		if(!(r->refbehind.b[z] & bb))
-			break;
-	}
-}
-
-void
-addreg(Adr *a, int rn)
-{
-	a->sym = nil;
-	a->node = nil;
-	a->name = D_NONE;
-	a->type = D_REG;
-	a->reg = rn;
-	if(rn >= NREG) {
-		a->type = D_FREG;
-		a->reg = rn-NREG;
-	}
-}
-
-/*
- *	bit	reg
- *	0	R0
- *	1	R1
- *	...	...
- *	10	R10
- *	12  R12
- */
-int32
-RtoB(int r)
-{
-	if(r >= REGTMP-2 && r != 12)	// excluded R9 and R10 for m and g, but not R12
-		return 0;
-	return 1L << r;
-}
-
-int
-BtoR(int32 b)
-{
-	b &= 0x11fcL;	// excluded R9 and R10 for m and g, but not R12
-	if(b == 0)
-		return 0;
-	return bitno(b);
-}
-
-/*
- *	bit	reg
- *	18	F2
- *	19	F3
- *	...	...
- *	31	F15
- */
-int32
-FtoB(int f)
-{
-
-	if(f < 2 || f > NFREG-1)
-		return 0;
-	return 1L << (f + 16);
-}
-
-int
-BtoF(int32 b)
-{
-
-	b &= 0xfffc0000L;
-	if(b == 0)
-		return 0;
-	return bitno(b) - 16;
-}
-
-void
-dumpone(Flow *f, int isreg)
-{
-	int z;
-	Bits bit;
-	Reg *r;
-
-	print("%d:%P", f->loop, f->prog);
-	if(isreg) {
-		r = (Reg*)f;
-		for(z=0; z<BITS; z++)
-			bit.b[z] =
-				r->set.b[z] |
-				r->use1.b[z] |
-				r->use2.b[z] |
-				r->refbehind.b[z] |
-				r->refahead.b[z] |
-				r->calbehind.b[z] |
-				r->calahead.b[z] |
-				r->regdiff.b[z] |
-				r->act.b[z] |
-					0;
-		if(bany(&bit)) {
-			print("\t");
-			if(bany(&r->set))
-				print(" s:%Q", r->set);
-			if(bany(&r->use1))
-				print(" u1:%Q", r->use1);
-			if(bany(&r->use2))
-				print(" u2:%Q", r->use2);
-			if(bany(&r->refbehind))
-				print(" rb:%Q ", r->refbehind);
-			if(bany(&r->refahead))
-				print(" ra:%Q ", r->refahead);
-			if(bany(&r->calbehind))
-				print(" cb:%Q ", r->calbehind);
-			if(bany(&r->calahead))
-				print(" ca:%Q ", r->calahead);
-			if(bany(&r->regdiff))
-				print(" d:%Q ", r->regdiff);
-			if(bany(&r->act))
-				print(" a:%Q ", r->act);
-		}
-	}
-	print("\n");
-}
-
-void
-dumpit(char *str, Flow *r0, int isreg)
-{
-	Flow *r, *r1;
-
-	print("\n%s\n", str);
-	for(r = r0; r != nil; r = r->link) {
-		dumpone(r, isreg);
-		r1 = r->p2;
-		if(r1 != nil) {
-			print("	pred:");
-			for(; r1 != nil; r1 = r1->p2link)
-				print(" %.4ud", (int)r1->prog->pc);
-			if(r->p1 != nil)
-				print(" (and %.4ud)", (int)r->p1->prog->pc);
-			else
-				print(" (only)");
-			print("\n");
-		}
-//		r1 = r->s1;
-//		if(r1 != nil) {
-//			print("	succ:");
-//			for(; r1 != R; r1 = r1->s1)
-//				print(" %.4ud", (int)r1->prog->pc);
-//			print("\n");
-//		}
-	}
-}
diff --git a/src/cmd/5l/5.out.h b/src/cmd/5l/5.out.h
deleted file mode 100644
index 7b16ac4..0000000
--- a/src/cmd/5l/5.out.h
+++ /dev/null
@@ -1,347 +0,0 @@
-// Inferno utils/5c/5.out.h
-// http://code.google.com/p/inferno-os/source/browse/utils/5c/5.out.h
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-enum
-{
-	NSNAME = 8,
-	NSYM = 50,
-	NREG = 16,
-};
-#include "../ld/textflag.h"
-
-/* -1 disables use of REGARG */
-#define	REGARG		-1
-/*c2go enum { REGARG = -1 }; */
-
-enum
-{
-	REGRET = 0,
-	/* compiler allocates R1 up as temps */
-	/* compiler allocates register variables R3 up */
-	/* compiler allocates external registers R10 down */
-	REGEXT = 10,
-	/* these two registers are declared in runtime.h */
-	REGG = REGEXT-0,
-	REGM = REGEXT-1,
-
-	REGTMP = 11,
-	REGSP = 13,
-	REGLINK = 14,
-	REGPC = 15,
-	
-	NFREG = 16,
-	FREGRET = 0,
-	FREGEXT = 7,
-	FREGTMP = 15,
-};
-/* compiler allocates register variables F0 up */
-/* compiler allocates external registers F7 down */
-
-enum
-{
-	C_NONE,
-	C_REG,
-	C_REGREG,
-	C_REGREG2,
-	C_SHIFT,
-	C_FREG,
-	C_PSR,
-	C_FCR,
-
-	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,	/* 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,	/* both nil and R */
-	C_LOREG,
-
-	C_PC,
-	C_SP,
-	C_HREG,
-
-	C_ADDR,		/* reference to relocatable address */
-
-	C_GOK,
-
-	C_NCLASS,	/* must be the last */
-};
-
-enum
-{
-	AXXX,
-
-	AAND,
-	AEOR,
-	ASUB,
-	ARSB,
-	AADD,
-	AADC,
-	ASBC,
-	ARSC,
-	ATST,
-	ATEQ,
-	ACMP,
-	ACMN,
-	AORR,
-	ABIC,
-
-	AMVN,
-
-	AB,
-	ABL,
-
-/*
- * Do not reorder or fragment the conditional branch
- * opcodes, or the predication code will break
- */
-	ABEQ,
-	ABNE,
-	ABCS,
-	ABHS,
-	ABCC,
-	ABLO,
-	ABMI,
-	ABPL,
-	ABVS,
-	ABVC,
-	ABHI,
-	ABLS,
-	ABGE,
-	ABLT,
-	ABGT,
-	ABLE,
-
-	AMOVWD,
-	AMOVWF,
-	AMOVDW,
-	AMOVFW,
-	AMOVFD,
-	AMOVDF,
-	AMOVF,
-	AMOVD,
-
-	ACMPF,
-	ACMPD,
-	AADDF,
-	AADDD,
-	ASUBF,
-	ASUBD,
-	AMULF,
-	AMULD,
-	ADIVF,
-	ADIVD,
-	ASQRTF,
-	ASQRTD,
-	AABSF,
-	AABSD,
-
-	ASRL,
-	ASRA,
-	ASLL,
-	AMULU,
-	ADIVU,
-	AMUL,
-	ADIV,
-	AMOD,
-	AMODU,
-
-	AMOVB,
-	AMOVBS,
-	AMOVBU,
-	AMOVH,
-	AMOVHS,
-	AMOVHU,
-	AMOVW,
-	AMOVM,
-	ASWPBU,
-	ASWPW,
-
-	ANOP,
-	ARFE,
-	ASWI,
-	AMULA,
-
-	ADATA,
-	AGLOBL,
-	AGOK,
-	AHISTORY,
-	ANAME,
-	ARET,
-	ATEXT,
-	AWORD,
-	ADYNT_,
-	AINIT_,
-	ABCASE,
-	ACASE,
-
-	AEND,
-
-	AMULL,
-	AMULAL,
-	AMULLU,
-	AMULALU,
-
-	ABX,
-	ABXRET,
-	ADWORD,
-
-	ASIGNAME,
-
-	ALDREX,
-	ASTREX,
-	
-	ALDREXD,
-	ASTREXD,
-
-	APLD,
-
-	AUNDEF,
-
-	ACLZ,
-
-	AMULWT,
-	AMULWB,
-	AMULAWT,
-	AMULAWB,
-	
-	AUSEFIELD,
-	ATYPE,
-	AFUNCDATA,
-	APCDATA,
-	ACHECKNIL,
-	AVARDEF,
-	AVARKILL,
-	ADUFFCOPY,
-	ADUFFZERO,
-	ADATABUNDLE,
-	ADATABUNDLEEND,
-
-	AMRC, // MRC/MCR
-
-	ALAST,
-};
-
-/* scond byte */
-enum
-{
-	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 */
-
-	C_SCOND_EQ = 0,
-	C_SCOND_NE = 1,
-	C_SCOND_HS = 2,
-	C_SCOND_LO = 3,
-	C_SCOND_MI = 4,
-	C_SCOND_PL = 5,
-	C_SCOND_VS = 6,
-	C_SCOND_VC = 7,
-	C_SCOND_HI = 8,
-	C_SCOND_LS = 9,
-	C_SCOND_GE = 10,
-	C_SCOND_LT = 11,
-	C_SCOND_GT = 12,
-	C_SCOND_LE = 13,
-	C_SCOND_NONE = 14,
-	C_SCOND_NV = 15,
-
-	/* D_SHIFT type */
-	SHIFT_LL = 0<<5,
-	SHIFT_LR = 1<<5,
-	SHIFT_AR = 2<<5,
-	SHIFT_RR = 3<<5,
-};
-
-enum
-{
-/* type/name */
-	D_GOK = 0,
-	D_NONE = 1,
-
-/* type */
-	D_BRANCH = (D_NONE+1),
-	D_OREG = (D_NONE+2),
-	D_CONST = (D_NONE+7),
-	D_FCONST = (D_NONE+8),
-	D_SCONST = (D_NONE+9),
-	D_PSR = (D_NONE+10),
-	D_REG = (D_NONE+12),
-	D_FREG = (D_NONE+13),
-	D_FILE = (D_NONE+16),
-	D_OCONST = (D_NONE+17),
-	D_FILE1 = (D_NONE+18),
-
-	D_SHIFT = (D_NONE+19),
-	D_FPCR = (D_NONE+20),
-	D_REGREG = (D_NONE+21), // (reg, reg)
-	D_ADDR = (D_NONE+22),
-
-	D_SBIG = (D_NONE+23),
-	D_CONST2 = (D_NONE+24),
-
-	D_REGREG2 = (D_NONE+25), // reg, reg
-
-/* name */
-	D_EXTERN = (D_NONE+3),
-	D_STATIC = (D_NONE+4),
-	D_AUTO = (D_NONE+5),
-	D_PARAM = (D_NONE+6),
-};
-
-/*
- * this is the ranlib header
- */
-#define	SYMDEF	"__.GOSYMDEF"
-/*c2go extern char SYMDEF[]; */
diff --git a/src/cmd/5l/Makefile b/src/cmd/5l/Makefile
deleted file mode 100644
index 3f528d7..0000000
--- a/src/cmd/5l/Makefile
+++ /dev/null
@@ -1,5 +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.
-
-include ../../Make.dist
diff --git a/src/cmd/5l/asm.c b/src/cmd/5l/asm.c
deleted file mode 100644
index 9c1c04e..0000000
--- a/src/cmd/5l/asm.c
+++ /dev/null
@@ -1,692 +0,0 @@
-// 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 at 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 at 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.
-
-// Writing object files.
-
-#include	"l.h"
-#include	"../ld/lib.h"
-#include	"../ld/elf.h"
-#include	"../ld/dwarf.h"
-
-
-char linuxdynld[] = "/lib/ld-linux.so.3"; // 2 for OABI, 3 for EABI
-char freebsddynld[] = "/usr/libexec/ld-elf.so.1";
-char openbsddynld[] = "XXX";
-char netbsddynld[] = "/libexec/ld.elf_so";
-char dragonflydynld[] = "XXX";
-char solarisdynld[] = "XXX";
-
-static int
-needlib(char *name)
-{
-	char *p;
-	LSym *s;
-
-	if(*name == '\0')
-		return 0;
-
-	/* reuse hash code in symbol table */
-	p = smprint(".dynlib.%s", name);
-	s = linklookup(ctxt, p, 0);
-	free(p);
-	if(s->type == 0) {
-		s->type = 100;	// avoid SDATA, etc.
-		return 1;
-	}
-	return 0;
-}
-
-int	nelfsym = 1;
-
-static void	addpltsym(Link*, LSym*);
-static void	addgotsym(Link*, LSym*);
-static void	addgotsyminternal(Link*, LSym*);
-
-// Preserve highest 8 bits of a, and do addition to lower 24-bit
-// of a and b; used to adjust ARM branch intruction's target
-static int32
-braddoff(int32 a, int32 b)
-{
-	return (((uint32)a) & 0xff000000U) | (0x00ffffffU & (uint32)(a + b));
-}
-
-void
-adddynrela(LSym *rel, LSym *s, Reloc *r)
-{
-	addaddrplus(ctxt, rel, s, r->off);
-	adduint32(ctxt, rel, R_ARM_RELATIVE);
-}
-
-void
-adddynrel(LSym *s, Reloc *r)
-{
-	LSym *targ, *rel;
-
-	targ = r->sym;
-	ctxt->cursym = s;
-
-	switch(r->type) {
-	default:
-		if(r->type >= 256) {
-			diag("unexpected relocation type %d", r->type);
-			return;
-		}
-		break;
-
-	// Handle relocations found in ELF object files.
-	case 256 + R_ARM_PLT32:
-		r->type = R_CALLARM;
-		if(targ->type == SDYNIMPORT) {
-			addpltsym(ctxt, targ);
-			r->sym = linklookup(ctxt, ".plt", 0);
-			r->add = braddoff(r->add, targ->plt / 4);
-		}
-		return;
-
-	case 256 + R_ARM_THM_PC22: // R_ARM_THM_CALL
-		diag("R_ARM_THM_CALL, are you using -marm?");
-		errorexit();
-		return;
-
-	case 256 + R_ARM_GOT32: // R_ARM_GOT_BREL
-		if(targ->type != SDYNIMPORT) {
-			addgotsyminternal(ctxt, targ);
-		} else {
-			addgotsym(ctxt, targ);
-		}
-		r->type = R_CONST;	// write r->add during relocsym
-		r->sym = S;
-		r->add += targ->got;
-		return;
-
-	case 256 + R_ARM_GOT_PREL: // GOT(S) + A - P
-		if(targ->type != SDYNIMPORT) {
-			addgotsyminternal(ctxt, targ);
-		} else {
-			addgotsym(ctxt, targ);
-		}
-		r->type = R_PCREL;
-		r->sym = linklookup(ctxt, ".got", 0);
-		r->add += targ->got + 4;
-		return;
-
-	case 256 + R_ARM_GOTOFF: // R_ARM_GOTOFF32
-		r->type = R_GOTOFF;
-		return;
-
-	case 256 + R_ARM_GOTPC: // R_ARM_BASE_PREL
-		r->type = R_PCREL;
-		r->sym = linklookup(ctxt, ".got", 0);
-		r->add += 4;
-		return;
-
-	case 256 + R_ARM_CALL:
-		r->type = R_CALLARM;
-		if(targ->type == SDYNIMPORT) {
-			addpltsym(ctxt, targ);
-			r->sym = linklookup(ctxt, ".plt", 0);
-			r->add = braddoff(r->add, targ->plt / 4);
-		}
-		return;
-
-	case 256 + R_ARM_REL32: // R_ARM_REL32
-		r->type = R_PCREL;
-		r->add += 4;
-		return;
-
-	case 256 + R_ARM_ABS32: 
-		if(targ->type == SDYNIMPORT)
-			diag("unexpected R_ARM_ABS32 relocation for dynamic symbol %s", targ->name);
-		r->type = R_ADDR;
-		return;
-
-	case 256 + R_ARM_V4BX:
-		// we can just ignore this, because we are targeting ARM V5+ anyway
-		if(r->sym) {
-			// R_ARM_V4BX is ABS relocation, so this symbol is a dummy symbol, ignore it
-			r->sym->type = 0;
-		}
-		r->sym = S;
-		return;
-
-	case 256 + R_ARM_PC24:
-	case 256 + R_ARM_JUMP24:
-		r->type = R_CALLARM;
-		if(targ->type == SDYNIMPORT) {
-			addpltsym(ctxt, targ);
-			r->sym = linklookup(ctxt, ".plt", 0);
-			r->add = braddoff(r->add, targ->plt / 4);
-		}
-		return;
-	}
-	
-	// Handle references to ELF symbols from our own object files.
-	if(targ->type != SDYNIMPORT)
-		return;
-
-	switch(r->type) {
-	case R_CALLARM:
-		addpltsym(ctxt, targ);
-		r->sym = linklookup(ctxt, ".plt", 0);
-		r->add = targ->plt;
-		return;
-	
-	case R_ADDR:
-		if(s->type != SDATA)
-			break;
-		if(iself) {
-			adddynsym(ctxt, targ);
-			rel = linklookup(ctxt, ".rel", 0);
-			addaddrplus(ctxt, rel, s, r->off);
-			adduint32(ctxt, rel, ELF32_R_INFO(targ->dynid, R_ARM_GLOB_DAT)); // we need a S + A dynmic reloc
-			r->type = R_CONST;	// write r->add during relocsym
-			r->sym = S;
-			return;
-		}
-		break;
-	}
-
-	ctxt->cursym = s;
-	diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type);
-}
-
-int
-elfreloc1(Reloc *r, vlong sectoff)
-{
-	int32 elfsym;
-	
-	LPUT(sectoff);
-
-	elfsym = r->xsym->elfsym;
-	switch(r->type) {
-	default:
-		return -1;
-
-	case R_ADDR:
-		if(r->siz == 4)
-			LPUT(R_ARM_ABS32 | elfsym<<8);
-		else
-			return -1;
-		break;
-
-	case R_PCREL:
-		if(r->siz == 4)
-			LPUT(R_ARM_REL32 | elfsym<<8);
-		else
-			return -1;
-		break;
-
-	case R_CALLARM:
-		if(r->siz == 4) {
-			if((r->add & 0xff000000) == 0xeb000000) // BL
-				LPUT(R_ARM_CALL | elfsym<<8);
-			else
-				LPUT(R_ARM_JUMP24 | elfsym<<8);
-		} else
-			return -1;
-		break;
-
-	case R_TLS:
-		if(r->siz == 4) {
-			if(flag_shared)
-				LPUT(R_ARM_TLS_IE32 | elfsym<<8);
-			else
-				LPUT(R_ARM_TLS_LE32 | elfsym<<8);
-		} else
-			return -1;
-		break;
-	}
-
-	return 0;
-}
-
-void
-elfsetupplt(void)
-{
-	LSym *plt, *got;
-	
-	plt = linklookup(ctxt, ".plt", 0);
-	got = linklookup(ctxt, ".got.plt", 0);
-	if(plt->size == 0) {
-		// str lr, [sp, #-4]!
-		adduint32(ctxt, plt, 0xe52de004);
-		// ldr lr, [pc, #4]
-		adduint32(ctxt, plt, 0xe59fe004);
-		// add lr, pc, lr
-		adduint32(ctxt, plt, 0xe08fe00e);
-		// ldr pc, [lr, #8]!
-		adduint32(ctxt, plt, 0xe5bef008);
-		// .word &GLOBAL_OFFSET_TABLE[0] - .
-		addpcrelplus(ctxt, plt, got, 4);
-
-		// the first .plt entry requires 3 .plt.got entries
-		adduint32(ctxt, got, 0);
-		adduint32(ctxt, got, 0);
-		adduint32(ctxt, got, 0);
-	}
-}
-
-int
-machoreloc1(Reloc *r, vlong sectoff)
-{
-	USED(r);
-	USED(sectoff);
-
-	return -1;
-}
-
-
-int
-archreloc(Reloc *r, LSym *s, vlong *val)
-{
-	LSym *rs;
-
-	if(linkmode == LinkExternal) {
-		switch(r->type) {
-		case R_CALLARM:
-			r->done = 0;
-
-			// set up addend for eventual relocation via outer symbol.
-			rs = r->sym;
-			r->xadd = r->add;
-			if(r->xadd & 0x800000)
-				r->xadd |= ~0xffffff;
-			r->xadd *= 4;
-			while(rs->outer != nil) {
-				r->xadd += symaddr(rs) - symaddr(rs->outer);
-				rs = rs->outer;
-			}
-
-			if(rs->type != SHOSTOBJ && rs->sect == nil)
-				diag("missing section for %s", rs->name);
-			r->xsym = rs;
-
-			*val = braddoff((0xff000000U & (uint32)r->add), 
-							(0xffffff & (uint32)(r->xadd / 4)));
-			return 0;
-		}
-		return -1;
-	}
-	switch(r->type) {
-	case R_CONST:
-		*val = r->add;
-		return 0;
-	case R_GOTOFF:
-		*val = symaddr(r->sym) + r->add - symaddr(linklookup(ctxt, ".got", 0));
-		return 0;
-	// The following three arch specific relocations are only for generation of 
-	// Linux/ARM ELF's PLT entry (3 assembler instruction)
-	case R_PLT0: // add ip, pc, #0xXX00000
-		if (symaddr(linklookup(ctxt, ".got.plt", 0)) < symaddr(linklookup(ctxt, ".plt", 0)))
-			diag(".got.plt should be placed after .plt section.");
-		*val = 0xe28fc600U +
-			(0xff & ((uint32)(symaddr(r->sym) - (symaddr(linklookup(ctxt, ".plt", 0)) + r->off) + r->add) >> 20));
-		return 0;
-	case R_PLT1: // add ip, ip, #0xYY000
-		*val = 0xe28cca00U +
-			(0xff & ((uint32)(symaddr(r->sym) - (symaddr(linklookup(ctxt, ".plt", 0)) + r->off) + r->add + 4) >> 12));
-		return 0;
-	case R_PLT2: // ldr pc, [ip, #0xZZZ]!
-		*val = 0xe5bcf000U +
-			(0xfff & (uint32)(symaddr(r->sym) - (symaddr(linklookup(ctxt, ".plt", 0)) + r->off) + r->add + 8));
-		return 0;
-	case R_CALLARM: // bl XXXXXX or b YYYYYY
-		*val = braddoff((0xff000000U & (uint32)r->add), 
-		                (0xffffff & (uint32)
-		                   ((symaddr(r->sym) + ((uint32)r->add) * 4 - (s->value + r->off)) / 4)));
-		return 0;
-	}
-	return -1;
-}
-
-static Reloc *
-addpltreloc(Link *ctxt, LSym *plt, LSym *got, LSym *sym, int typ)
-{
-	Reloc *r;
-
-	r = addrel(plt);
-	r->sym = got;
-	r->off = plt->size;
-	r->siz = 4;
-	r->type = typ;
-	r->add = sym->got - 8;
-
-	plt->reachable = 1;
-	plt->size += 4;
-	symgrow(ctxt, plt, plt->size);
-
-	return r;
-}
-
-static void
-addpltsym(Link *ctxt, LSym *s)
-{
-	LSym *plt, *got, *rel;
-	
-	if(s->plt >= 0)
-		return;
-
-	adddynsym(ctxt, s);
-	
-	if(iself) {
-		plt = linklookup(ctxt, ".plt", 0);
-		got = linklookup(ctxt, ".got.plt", 0);
-		rel = linklookup(ctxt, ".rel.plt", 0);
-		if(plt->size == 0)
-			elfsetupplt();
-		
-		// .got entry
-		s->got = got->size;
-		// In theory, all GOT should point to the first PLT entry,
-		// Linux/ARM's dynamic linker will do that for us, but FreeBSD/ARM's
-		// dynamic linker won't, so we'd better do it ourselves.
-		addaddrplus(ctxt, got, plt, 0);
-
-		// .plt entry, this depends on the .got entry
-		s->plt = plt->size;
-		addpltreloc(ctxt, plt, got, s, R_PLT0); // add lr, pc, #0xXX00000
-		addpltreloc(ctxt, plt, got, s, R_PLT1); // add lr, lr, #0xYY000
-		addpltreloc(ctxt, plt, got, s, R_PLT2); // ldr pc, [lr, #0xZZZ]!
-
-		// rel
-		addaddrplus(ctxt, rel, got, s->got);
-		adduint32(ctxt, rel, ELF32_R_INFO(s->dynid, R_ARM_JUMP_SLOT));
-	} else {
-		diag("addpltsym: unsupported binary format");
-	}
-}
-
-static void
-addgotsyminternal(Link *ctxt, LSym *s)
-{
-	LSym *got;
-	
-	if(s->got >= 0)
-		return;
-
-	got = linklookup(ctxt, ".got", 0);
-	s->got = got->size;
-
-	addaddrplus(ctxt, got, s, 0);
-
-	if(iself) {
-		;
-	} else {
-		diag("addgotsyminternal: unsupported binary format");
-	}
-}
-
-static void
-addgotsym(Link *ctxt, LSym *s)
-{
-	LSym *got, *rel;
-	
-	if(s->got >= 0)
-		return;
-	
-	adddynsym(ctxt, s);
-	got = linklookup(ctxt, ".got", 0);
-	s->got = got->size;
-	adduint32(ctxt, got, 0);
-	
-	if(iself) {
-		rel = linklookup(ctxt, ".rel", 0);
-		addaddrplus(ctxt, rel, got, s->got);
-		adduint32(ctxt, rel, ELF32_R_INFO(s->dynid, R_ARM_GLOB_DAT));
-	} else {
-		diag("addgotsym: unsupported binary format");
-	}
-}
-
-void
-adddynsym(Link *ctxt, LSym *s)
-{
-	LSym *d;
-	int t;
-	char *name;
-
-	if(s->dynid >= 0)
-		return;
-
-	if(iself) {
-		s->dynid = nelfsym++;
-
-		d = linklookup(ctxt, ".dynsym", 0);
-
-		/* name */
-		name = s->extname;
-		adduint32(ctxt, d, addstring(linklookup(ctxt, ".dynstr", 0), name));
-
-		/* value */
-		if(s->type == SDYNIMPORT)
-			adduint32(ctxt, d, 0);
-		else
-			addaddr(ctxt, d, s);
-
-		/* size */
-		adduint32(ctxt, d, 0);
-
-		/* type */
-		t = STB_GLOBAL << 4;
-		if((s->cgoexport & CgoExportDynamic) && (s->type&SMASK) == STEXT)
-			t |= STT_FUNC;
-		else
-			t |= STT_OBJECT;
-		adduint8(ctxt, d, t);
-		adduint8(ctxt, d, 0);
-
-		/* shndx */
-		if(s->type == SDYNIMPORT)
-			adduint16(ctxt, d, SHN_UNDEF);
-		else {
-			switch(s->type) {
-			default:
-			case STEXT:
-				t = 11;
-				break;
-			case SRODATA:
-				t = 12;
-				break;
-			case SDATA:
-				t = 13;
-				break;
-			case SBSS:
-				t = 14;
-				break;
-			}
-			adduint16(ctxt, d, t);
-		}
-	} else {
-		diag("adddynsym: unsupported binary format");
-	}
-}
-
-void
-adddynlib(char *lib)
-{
-	LSym *s;
-	
-	if(!needlib(lib))
-		return;
-	
-	if(iself) {
-		s = linklookup(ctxt, ".dynstr", 0);
-		if(s->size == 0)
-			addstring(s, "");
-		elfwritedynent(linklookup(ctxt, ".dynamic", 0), DT_NEEDED, addstring(s, lib));
-	} else {
-		diag("adddynlib: unsupported binary format");
-	}
-}
-
-void
-asmb(void)
-{
-	uint32 symo;
-	Section *sect;
-	LSym *sym;
-	int i;
-
-	if(debug['v'])
-		Bprint(&bso, "%5.2f asmb\n", cputime());
-	Bflush(&bso);
-
-	if(iself)
-		asmbelfsetup();
-
-	sect = segtext.sect;
-	cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);
-	codeblk(sect->vaddr, sect->len);
-	for(sect = sect->next; sect != nil; sect = sect->next) {
-		cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);
-		datblk(sect->vaddr, sect->len);
-	}
-
-	if(segrodata.filelen > 0) {
-		if(debug['v'])
-			Bprint(&bso, "%5.2f rodatblk\n", cputime());
-		Bflush(&bso);
-
-		cseek(segrodata.fileoff);
-		datblk(segrodata.vaddr, segrodata.filelen);
-	}
-
-	if(debug['v'])
-		Bprint(&bso, "%5.2f datblk\n", cputime());
-	Bflush(&bso);
-
-	cseek(segdata.fileoff);
-	datblk(segdata.vaddr, segdata.filelen);
-
-	/* output symbol table */
-	symsize = 0;
-	lcsize = 0;
-	symo = 0;
-	if(!debug['s']) {
-		// TODO: rationalize
-		if(debug['v'])
-			Bprint(&bso, "%5.2f sym\n", cputime());
-		Bflush(&bso);
-		switch(HEADTYPE) {
-		default:
-			if(iself)
-				goto ElfSym;
-		case Hplan9:
-			symo = segdata.fileoff+segdata.filelen;
-			break;
-		ElfSym:
-			symo = segdata.fileoff+segdata.filelen;
-			symo = rnd(symo, INITRND);
-			break;
-		}
-		cseek(symo);
-		switch(HEADTYPE) {
-		default:
-			if(iself) {
-				if(debug['v'])
-					Bprint(&bso, "%5.2f elfsym\n", cputime());
-				asmelfsym();
-				cflush();
-				cwrite(elfstrdat, elfstrsize);
-	
-				if(debug['v'])
-					Bprint(&bso, "%5.2f dwarf\n", cputime());
-				dwarfemitdebugsections();
-				
-				if(linkmode == LinkExternal)
-					elfemitreloc();
-			}
-			break;
-		case Hplan9:
-			asmplan9sym();
-			cflush();
-
-			sym = linklookup(ctxt, "pclntab", 0);
-			if(sym != nil) {
-				lcsize = sym->np;
-				for(i=0; i < lcsize; i++)
-					cput(sym->p[i]);
-
-				cflush();
-			}
-			break;
-		}
-	}
-
-	ctxt->cursym = nil;
-	if(debug['v'])
-		Bprint(&bso, "%5.2f header\n", cputime());
-	Bflush(&bso);
-	cseek(0L);
-	switch(HEADTYPE) {
-	default:
-	case Hplan9:	/* plan 9 */
-		LPUT(0x647);			/* magic */
-		LPUT(segtext.filelen);			/* sizes */
-		LPUT(segdata.filelen);
-		LPUT(segdata.len - segdata.filelen);
-		LPUT(symsize);			/* nsyms */
-		LPUT(entryvalue());		/* va of entry */
-		LPUT(0L);
-		LPUT(lcsize);
-		break;
-	case Hlinux:
-	case Hfreebsd:
-	case Hnetbsd:
-	case Hopenbsd:
-	case Hnacl:
-		asmbelf(symo);
-		break;
-	}
-	cflush();
-	if(debug['c']){
-		print("textsize=%ulld\n", segtext.filelen);
-		print("datsize=%ulld\n", segdata.filelen);
-		print("bsssize=%ulld\n", segdata.len - segdata.filelen);
-		print("symsize=%d\n", symsize);
-		print("lcsize=%d\n", lcsize);
-		print("total=%lld\n", segtext.filelen+segdata.len+symsize+lcsize);
-	}
-}
-
-int32
-rnd(int32 v, int32 r)
-{
-	int32 c;
-
-	if(r <= 0)
-		return v;
-	v += r - 1;
-	c = v % r;
-	if(c < 0)
-		c += r;
-	v -= c;
-	return v;
-}
diff --git a/src/cmd/5l/doc.go b/src/cmd/5l/doc.go
deleted file mode 100644
index a054a22..0000000
--- a/src/cmd/5l/doc.go
+++ /dev/null
@@ -1,15 +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.
-
-// +build ignore
-
-/*
-
-5l is the linker for the ARM.
-The $GOARCH for these tools is arm.
-
-The flags are documented in ../ld/doc.go.
-
-*/
-package main
diff --git a/src/cmd/5l/l.h b/src/cmd/5l/l.h
deleted file mode 100644
index c881a54..0000000
--- a/src/cmd/5l/l.h
+++ /dev/null
@@ -1,103 +0,0 @@
-// Inferno utils/5l/l.h
-// http://code.google.com/p/inferno-os/source/browse/utils/5l/l.h
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include	<u.h>
-#include	<libc.h>
-#include	<bio.h>
-#include	<link.h>
-#include	"5.out.h"
-
-enum
-{
-	thechar = '5',
-	PtrSize = 4,
-	IntSize = 4,
-	RegSize = 4,
-	MaxAlign = 8,	// max data alignment
-	FuncAlign = 4  // single-instruction alignment
-};
-
-#ifndef	EXTERN
-#define	EXTERN	extern
-#endif
-
-#define	P		((Prog*)0)
-#define	S		((LSym*)0)
-
-enum
-{
-/* mark flags */
-	FOLL		= 1<<0,
-	LABEL		= 1<<1,
-	LEAF		= 1<<2,
-
-	MINLC	= 4,
-};
-
-EXTERN	int32	autosize;
-EXTERN	LSym*	datap;
-EXTERN	int	debug[128];
-EXTERN	char*	noname;
-EXTERN	Prog*	lastp;
-EXTERN	int32	lcsize;
-EXTERN	char	literal[32];
-EXTERN	int	nerrors;
-EXTERN	int32	instoffset;
-EXTERN	char*	rpath;
-EXTERN	uint32	stroffset;
-EXTERN	int32	symsize;
-EXTERN	int	armsize;
-
-#pragma	varargck	type	"I"	uint32*
-
-int	Iconv(Fmt *fp);
-void	adddynlib(char *lib);
-void	adddynrel(LSym *s, Reloc *r);
-void	adddynrela(LSym *rel, LSym *s, Reloc *r);
-void	adddynsym(Link *ctxt, LSym *s);
-int	archreloc(Reloc *r, LSym *s, vlong *val);
-void	asmb(void);
-int	elfreloc1(Reloc *r, vlong sectoff);
-void	elfsetupplt(void);
-void	listinit(void);
-int	machoreloc1(Reloc *r, vlong sectoff);
-void	main(int argc, char *argv[]);
-int32	rnd(int32 v, int32 r);
-
-/* Native is little-endian */
-#define	LPUT(a)	lputl(a)
-#define	WPUT(a)	wputl(a)
-#define	VPUT(a)	abort()
-
-/* Used by ../ld/dwarf.c */
-enum
-{
-	DWARFREGSP = 13
-};
diff --git a/src/cmd/5l/list.c b/src/cmd/5l/list.c
deleted file mode 100644
index 875fc3e..0000000
--- a/src/cmd/5l/list.c
+++ /dev/null
@@ -1,70 +0,0 @@
-// Inferno utils/5l/list.h
-// http://code.google.com/p/inferno-os/source/browse/utils/5l/list.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-// Printing.
-
-#include "l.h"
-#include "../ld/lib.h"
-
-void
-listinit(void)
-{
-	listinit5();
-	fmtinstall('I', Iconv);
-}
-
-int
-Iconv(Fmt *fp)
-{
-	int i, n;
-	uint32 *p;
-	char *s;
-	Fmt fmt;
-	
-	n = fp->prec;
-	fp->prec = 0;
-	if(!(fp->flags&FmtPrec) || n < 0)
-		return fmtstrcpy(fp, "%I");
-	fp->flags &= ~FmtPrec;
-	p = va_arg(fp->args, uint32*);
-
-	// format into temporary buffer and
-	// call fmtstrcpy to handle padding.
-	fmtstrinit(&fmt);
-	for(i=0; i<n/4; i++) {
-		if(i > 0)
-			fmtprint(&fmt, " ");
-		fmtprint(&fmt, "%.8ux", *p++);
-	}
-	s = fmtstrflush(&fmt);
-	fmtstrcpy(fp, s);
-	free(s);
-	return 0;
-}
diff --git a/src/cmd/5l/obj.c b/src/cmd/5l/obj.c
deleted file mode 100644
index c6f60ee..0000000
--- a/src/cmd/5l/obj.c
+++ /dev/null
@@ -1,116 +0,0 @@
-// 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 at 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 at 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.
-
-// Reading object files.
-
-#include	"l.h"
-#include	"../ld/lib.h"
-#include	"../ld/elf.h"
-#include	"../ld/dwarf.h"
-#include	<ar.h>
-
-char *thestring = "arm";
-LinkArch *thelinkarch = &linkarm;
-
-void
-linkarchinit(void)
-{
-}
-
-void
-archinit(void)
-{
-	LSym *s;
-
-	// getgoextlinkenabled is based on GO_EXTLINK_ENABLED when
-	// Go was built; see ../../make.bash.
-	if(linkmode == LinkAuto && strcmp(getgoextlinkenabled(), "0") == 0)
-		linkmode = LinkInternal;
-
-	switch(HEADTYPE) {
-	default:
-		if(linkmode == LinkAuto)
-			linkmode = LinkInternal;
-		if(linkmode == LinkExternal && strcmp(getgoextlinkenabled(), "1") != 0)
-			sysfatal("cannot use -linkmode=external with -H %s", headstr(HEADTYPE));
-		break;
-	case Hlinux:
-	case Hfreebsd:
-	case Hnacl:
-		break;
-	}
-
-	switch(HEADTYPE) {
-	default:
-		diag("unknown -H option");
-		errorexit();
-	case Hplan9:	/* plan 9 */
-		HEADR = 32L;
-		if(INITTEXT == -1)
-			INITTEXT = 4128;
-		if(INITDAT == -1)
-			INITDAT = 0;
-		if(INITRND == -1)
-			INITRND = 4096;
-		break;
-	case Hlinux:	/* arm elf */
-	case Hfreebsd:
-	case Hnetbsd:
-		debug['d'] = 0;	// with dynamic linking
-		elfinit();
-		HEADR = ELFRESERVE;
-		if(INITTEXT == -1)
-			INITTEXT = 0x10000 + HEADR;
-		if(INITDAT == -1)
-			INITDAT = 0;
-		if(INITRND == -1)
-			INITRND = 4096;
-		break;
-	case Hnacl:
-		elfinit();
-		HEADR = 0x10000;
-		funcalign = 16;
-		if(INITTEXT == -1)
-			INITTEXT = 0x20000;
-		if(INITDAT == -1)
-			INITDAT = 0;
-		if(INITRND == -1)
-			INITRND = 0x10000;
-		break;
-	}
-	if(INITDAT != 0 && INITRND != 0)
-		print("warning: -D0x%ux is ignored because of -R0x%ux\n",
-			INITDAT, INITRND);
-
-	// embed goarm to runtime.goarm
-	s = linklookup(ctxt, "runtime.goarm", 0);
-	s->type = SRODATA;
-	adduint8(ctxt, s, ctxt->goarm);
-}
diff --git a/src/cmd/6a/Makefile b/src/cmd/6a/Makefile
deleted file mode 100644
index 27290dd..0000000
--- a/src/cmd/6a/Makefile
+++ /dev/null
@@ -1,10 +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.
-
-include ../../Make.dist
-
-install: y.tab.h
-
-y.tab.h: a.y
-	LANG=C LANGUAGE=en_US.UTF8 bison -d -v -y a.y
diff --git a/src/cmd/6a/a.h b/src/cmd/6a/a.h
deleted file mode 100644
index b3fb0bb..0000000
--- a/src/cmd/6a/a.h
+++ /dev/null
@@ -1,184 +0,0 @@
-// Inferno utils/6a/a.h
-// http://code.google.com/p/inferno-os/source/browse/utils/6a/a.h
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.	All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include <bio.h>
-#include <link.h>
-#include "../6l/6.out.h"
-
-#ifndef	EXTERN
-#define	EXTERN	extern
-#endif
-
-#undef	getc
-#undef	ungetc
-#undef	BUFSIZ
-
-#define	getc	ccgetc
-#define	ungetc	ccungetc
-
-typedef	struct	Sym	Sym;
-typedef	struct	Ref	Ref;
-typedef	struct	Io	Io;
-typedef	struct	Addr2	Addr2;
-
-#define	MAXALIGN	7
-#define	FPCHIP		1
-#define	NSYMB		500
-#define	BUFSIZ		8192
-#define	HISTSZ		20
-#ifndef	EOF
-#define	EOF		(-1)
-#endif
-#define	IGN		(-2)
-#define	GETC()		((--fi.c < 0)? filbuf(): *fi.p++ & 0xff)
-#define	NHASH		503
-#define	STRINGSZ	200
-#define	NMACRO		10
-
-struct	Sym
-{
-	Sym*	link;
-	Ref*	ref;
-	char*	macro;
-	vlong	value;
-	ushort	type;
-	char	*name;
-	char	sym;
-};
-#define	S	((Sym*)0)
-
-struct	Ref
-{
-	int	class;
-};
-
-EXTERN struct
-{
-	char*	p;
-	int	c;
-} fi;
-
-struct	Io
-{
-	Io*	link;
-	char	b[BUFSIZ];
-	char*	p;
-	short	c;
-	short	f;
-};
-#define	I	((Io*)0)
-
-struct	Addr2
-{
-	Addr	from;
-	Addr	to;
-};
-
-enum
-{
-	CLAST,
-	CMACARG,
-	CMACRO,
-	CPREPROC,
-};
-
-EXTERN	int	debug[256];
-EXTERN	Sym*	hash[NHASH];
-EXTERN	char**	Dlist;
-EXTERN	int	nDlist;
-EXTERN	int	newflag;
-EXTERN	char*	hunk;
-EXTERN	char**	include;
-EXTERN	Io*	iofree;
-EXTERN	Io*	ionext;
-EXTERN	Io*	iostack;
-EXTERN	int32	lineno;
-EXTERN	int	nerrors;
-EXTERN	int32	nhunk;
-EXTERN	int	ninclude;
-EXTERN	int32	nsymb;
-EXTERN	Addr	nullgen;
-EXTERN	char*	outfile;
-EXTERN	int	pass;
-EXTERN	int32	pc;
-EXTERN	int	peekc;
-EXTERN	int32	stmtline;
-EXTERN	int	sym;
-EXTERN	char*	symb;
-EXTERN	int	thechar;
-EXTERN	char*	thestring;
-EXTERN	int32	thunk;
-EXTERN	Biobuf	obuf;
-EXTERN	Link*	ctxt;
-EXTERN	Biobuf	bstdout;
-
-void*	alloc(int32);
-void*	allocn(void*, int32, int32);
-void	ensuresymb(int32);
-void	errorexit(void);
-void	pushio(void);
-void	newio(void);
-void	newfile(char*, int);
-Sym*	slookup(char*);
-Sym*	lookup(void);
-void	syminit(Sym*);
-int32	yylex(void);
-int	getc(void);
-int	getnsc(void);
-void	unget(int);
-int	escchar(int);
-void	cinit(void);
-void	checkscale(int);
-void	pinit(char*);
-void	cclean(void);
-int	isreg(Addr*);
-void	outcode(int, Addr2*);
-void	outhist(void);
-void	zaddr(Addr*, int);
-void	zname(char*, int, int);
-int	filbuf(void);
-Sym*	getsym(void);
-void	domacro(void);
-void	macund(void);
-void	macdef(void);
-void	macexpand(Sym*, char*);
-void	macinc(void);
-void	macprag(void);
-void	maclin(void);
-void	macif(int);
-void	macend(void);
-void	dodefine(char*);
-void	prfile(int32);
-void	linehist(char*, int);
-void	gethunk(void);
-void	yyerror(char*, ...);
-int	yyparse(void);
-void	setinclude(char*);
-int	assemble(char*);
diff --git a/src/cmd/6a/a.y b/src/cmd/6a/a.y
deleted file mode 100644
index 1089d40..0000000
--- a/src/cmd/6a/a.y
+++ /dev/null
@@ -1,691 +0,0 @@
-// Inferno utils/6a/a.y
-// http://code.google.com/p/inferno-os/source/browse/utils/6a/a.y
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.	All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-%{
-#include <u.h>
-#include <stdio.h>	/* if we don't, bison will, and a.h re-#defines getc */
-#include <libc.h>
-#include "a.h"
-#include "../../runtime/funcdata.h"
-%}
-%union	{
-	Sym	*sym;
-	vlong	lval;
-	double	dval;
-	char	sval[8];
-	Addr	addr;
-	Addr2	addr2;
-}
-%left	'|'
-%left	'^'
-%left	'&'
-%left	'<' '>'
-%left	'+' '-'
-%left	'*' '/' '%'
-%token	<lval>	LTYPE0 LTYPE1 LTYPE2 LTYPE3 LTYPE4
-%token	<lval>	LTYPEC LTYPED LTYPEN LTYPER LTYPET LTYPEG LTYPEPC
-%token	<lval>	LTYPES LTYPEM LTYPEI LTYPEXC LTYPEX LTYPERT LTYPEF
-%token	<lval>	LCONST LFP LPC LSB
-%token	<lval>	LBREG LLREG LSREG LFREG LMREG LXREG
-%token	<dval>	LFCONST
-%token	<sval>	LSCONST LSP
-%token	<sym>	LNAME LLAB LVAR
-%type	<lval>	con con2 expr pointer offset
-%type	<addr>	mem imm imm2 reg nam rel rem rim rom omem nmem
-%type	<addr2>	nonnon nonrel nonrem rimnon rimrem remrim
-%type	<addr2>	spec1 spec2 spec3 spec4 spec5 spec6 spec7 spec8 spec9
-%type	<addr2>	spec10 spec11 spec12 spec13
-%%
-prog:
-|	prog 
-	{
-		stmtline = lineno;
-	}
-	line
-
-line:
-	LLAB ':'
-	{
-		if($1->value != pc)
-			yyerror("redeclaration of %s", $1->name);
-		$1->value = pc;
-	}
-	line
-|	LNAME ':'
-	{
-		$1->type = LLAB;
-		$1->value = pc;
-	}
-	line
-|	';'
-|	inst ';'
-|	error ';'
-
-inst:
-	LNAME '=' expr
-	{
-		$1->type = LVAR;
-		$1->value = $3;
-	}
-|	LVAR '=' expr
-	{
-		if($1->value != $3)
-			yyerror("redeclaration of %s", $1->name);
-		$1->value = $3;
-	}
-|	LTYPE0 nonnon	{ outcode($1, &$2); }
-|	LTYPE1 nonrem	{ outcode($1, &$2); }
-|	LTYPE2 rimnon	{ outcode($1, &$2); }
-|	LTYPE3 rimrem	{ outcode($1, &$2); }
-|	LTYPE4 remrim	{ outcode($1, &$2); }
-|	LTYPER nonrel	{ outcode($1, &$2); }
-|	LTYPED spec1	{ outcode($1, &$2); }
-|	LTYPET spec2	{ outcode($1, &$2); }
-|	LTYPEC spec3	{ outcode($1, &$2); }
-|	LTYPEN spec4	{ outcode($1, &$2); }
-|	LTYPES spec5	{ outcode($1, &$2); }
-|	LTYPEM spec6	{ outcode($1, &$2); }
-|	LTYPEI spec7	{ outcode($1, &$2); }
-|	LTYPEXC spec8	{ outcode($1, &$2); }
-|	LTYPEX spec9	{ outcode($1, &$2); }
-|	LTYPERT spec10	{ outcode($1, &$2); }
-|	LTYPEG spec11	{ outcode($1, &$2); }
-|	LTYPEPC spec12	{ outcode($1, &$2); }
-|	LTYPEF spec13	{ outcode($1, &$2); }
-
-nonnon:
-	{
-		$$.from = nullgen;
-		$$.to = nullgen;
-	}
-|	','
-	{
-		$$.from = nullgen;
-		$$.to = nullgen;
-	}
-
-rimrem:
-	rim ',' rem
-	{
-		$$.from = $1;
-		$$.to = $3;
-	}
-
-remrim:
-	rem ',' rim
-	{
-		$$.from = $1;
-		$$.to = $3;
-	}
-
-rimnon:
-	rim ','
-	{
-		$$.from = $1;
-		$$.to = nullgen;
-	}
-|	rim
-	{
-		$$.from = $1;
-		$$.to = nullgen;
-	}
-
-nonrem:
-	',' rem
-	{
-		$$.from = nullgen;
-		$$.to = $2;
-	}
-|	rem
-	{
-		$$.from = nullgen;
-		$$.to = $1;
-	}
-
-nonrel:
-	',' rel
-	{
-		$$.from = nullgen;
-		$$.to = $2;
-	}
-|	rel
-	{
-		$$.from = nullgen;
-		$$.to = $1;
-	}
-|	imm ',' rel
-	{
-		$$.from = $1;
-		$$.to = $3;
-	}
-
-spec1:	/* DATA */
-	nam '/' con ',' imm
-	{
-		$$.from = $1;
-		$$.from.scale = $3;
-		$$.to = $5;
-	}
-
-spec2:	/* TEXT */
-	mem ',' imm2
-	{
-		$$.from = $1;
-		$$.to = $3;
-	}
-|	mem ',' con ',' imm2
-	{
-		$$.from = $1;
-		$$.from.scale = $3;
-		$$.to = $5;
-	}
-
-spec3:	/* JMP/CALL */
-	',' rom
-	{
-		$$.from = nullgen;
-		$$.to = $2;
-	}
-|	rom
-	{
-		$$.from = nullgen;
-		$$.to = $1;
-	}
-
-spec4:	/* NOP */
-	nonnon
-|	nonrem
-
-spec5:	/* SHL/SHR */
-	rim ',' rem
-	{
-		$$.from = $1;
-		$$.to = $3;
-	}
-|	rim ',' rem ':' LLREG
-	{
-		$$.from = $1;
-		$$.to = $3;
-		if($$.from.index != D_NONE)
-			yyerror("dp shift with lhs index");
-		$$.from.index = $5;
-	}
-
-spec6:	/* MOVW/MOVL */
-	rim ',' rem
-	{
-		$$.from = $1;
-		$$.to = $3;
-	}
-|	rim ',' rem ':' LSREG
-	{
-		$$.from = $1;
-		$$.to = $3;
-		if($$.to.index != D_NONE)
-			yyerror("dp move with lhs index");
-		$$.to.index = $5;
-	}
-
-spec7:
-	rim ','
-	{
-		$$.from = $1;
-		$$.to = nullgen;
-	}
-|	rim
-	{
-		$$.from = $1;
-		$$.to = nullgen;
-	}
-|	rim ',' rem
-	{
-		$$.from = $1;
-		$$.to = $3;
-	}
-
-spec8:	/* CMPPS/CMPPD */
-	reg ',' rem ',' con
-	{
-		$$.from = $1;
-		$$.to = $3;
-		$$.to.offset = $5;
-	}
-
-spec9:	/* shufl */
-	imm ',' rem ',' reg
-	{
-		$$.from = $3;
-		$$.to = $5;
-		if($1.type != D_CONST)
-			yyerror("illegal constant");
-		$$.to.offset = $1.offset;
-	}
-
-spec10:	/* RET/RETF */
-	{
-		$$.from = nullgen;
-		$$.to = nullgen;
-	}
-|	imm
-	{
-		$$.from = $1;
-		$$.to = nullgen;
-	}
-
-spec11:	/* GLOBL */
-	mem ',' imm
-	{
-		$$.from = $1;
-		$$.to = $3;
-	}
-|	mem ',' con ',' imm
-	{
-		$$.from = $1;
-		$$.from.scale = $3;
-		$$.to = $5;
-	}
-
-spec12:	/* PCDATA */
-	rim ',' rim
-	{
-		if($1.type != D_CONST || $3.type != D_CONST)
-			yyerror("arguments to PCDATA must be integer constants");
-		$$.from = $1;
-		$$.to = $3;
-	}
-
-spec13:	/* FUNCDATA */
-	rim ',' rim
-	{
-		if($1.type != D_CONST)
-			yyerror("index for FUNCDATA must be integer constant");
-		if($3.type != D_EXTERN && $3.type != D_STATIC)
-			yyerror("value for FUNCDATA must be symbol reference");
-		$$.from = $1;
-		$$.to = $3;
-	}
-
-rem:
-	reg
-|	mem
-
-rom:
-	rel
-|	nmem
-|	'*' reg
-	{
-		$$ = $2;
-	}
-|	'*' omem
-	{
-		$$ = $2;
-	}
-|	reg
-|	omem
-
-rim:
-	rem
-|	imm
-
-rel:
-	con '(' LPC ')'
-	{
-		$$ = nullgen;
-		$$.type = D_BRANCH;
-		$$.offset = $1 + pc;
-	}
-|	LNAME offset
-	{
-		$$ = nullgen;
-		if(pass == 2)
-			yyerror("undefined label: %s", $1->name);
-		$$.type = D_BRANCH;
-		$$.offset = $2;
-	}
-|	LLAB offset
-	{
-		$$ = nullgen;
-		$$.type = D_BRANCH;
-		$$.offset = $1->value + $2;
-	}
-
-reg:
-	LBREG
-	{
-		$$ = nullgen;
-		$$.type = $1;
-	}
-|	LFREG
-	{
-		$$ = nullgen;
-		$$.type = $1;
-	}
-|	LLREG
-	{
-		$$ = nullgen;
-		$$.type = $1;
-	}
-|	LMREG
-	{
-		$$ = nullgen;
-		$$.type = $1;
-	}
-|	LSP
-	{
-		$$ = nullgen;
-		$$.type = D_SP;
-	}
-|	LSREG
-	{
-		$$ = nullgen;
-		$$.type = $1;
-	}
-|	LXREG
-	{
-		$$ = nullgen;
-		$$.type = $1;
-	}
-imm2:
-	'$' con2
-	{
-		$$ = nullgen;
-		$$.type = D_CONST;
-		$$.offset = $2;
-	}
-
-imm:
-	'$' con
-	{
-		$$ = nullgen;
-		$$.type = D_CONST;
-		$$.offset = $2;
-	}
-|	'$' nam
-	{
-		$$ = $2;
-		$$.index = $2.type;
-		$$.type = D_ADDR;
-		/*
-		if($2.type == D_AUTO || $2.type == D_PARAM)
-			yyerror("constant cannot be automatic: %s",
-				$2.sym->name);
-		 */
-	}
-|	'$' LSCONST
-	{
-		$$ = nullgen;
-		$$.type = D_SCONST;
-		memcpy($$.u.sval, $2, sizeof($$.u.sval));
-	}
-|	'$' LFCONST
-	{
-		$$ = nullgen;
-		$$.type = D_FCONST;
-		$$.u.dval = $2;
-	}
-|	'$' '(' LFCONST ')'
-	{
-		$$ = nullgen;
-		$$.type = D_FCONST;
-		$$.u.dval = $3;
-	}
-|	'$' '(' '-' LFCONST ')'
-	{
-		$$ = nullgen;
-		$$.type = D_FCONST;
-		$$.u.dval = -$4;
-	}
-|	'$' '-' LFCONST
-	{
-		$$ = nullgen;
-		$$.type = D_FCONST;
-		$$.u.dval = -$3;
-	}
-
-mem:
-	omem
-|	nmem
-
-omem:
-	con
-	{
-		$$ = nullgen;
-		$$.type = D_INDIR+D_NONE;
-		$$.offset = $1;
-	}
-|	con '(' LLREG ')'
-	{
-		$$ = nullgen;
-		$$.type = D_INDIR+$3;
-		$$.offset = $1;
-	}
-|	con '(' LSP ')'
-	{
-		$$ = nullgen;
-		$$.type = D_INDIR+D_SP;
-		$$.offset = $1;
-	}
-|	con '(' LSREG ')'
-	{
-		$$ = nullgen;
-		$$.type = D_INDIR+$3;
-		$$.offset = $1;
-	}
-|	con '(' LLREG '*' con ')'
-	{
-		$$ = nullgen;
-		$$.type = D_INDIR+D_NONE;
-		$$.offset = $1;
-		$$.index = $3;
-		$$.scale = $5;
-		checkscale($$.scale);
-	}
-|	con '(' LLREG ')' '(' LLREG '*' con ')'
-	{
-		$$ = nullgen;
-		$$.type = D_INDIR+$3;
-		$$.offset = $1;
-		$$.index = $6;
-		$$.scale = $8;
-		checkscale($$.scale);
-	}
-|	con '(' LLREG ')' '(' LSREG '*' con ')'
-	{
-		$$ = nullgen;
-		$$.type = D_INDIR+$3;
-		$$.offset = $1;
-		$$.index = $6;
-		$$.scale = $8;
-		checkscale($$.scale);
-	}
-|	'(' LLREG ')'
-	{
-		$$ = nullgen;
-		$$.type = D_INDIR+$2;
-	}
-|	'(' LSP ')'
-	{
-		$$ = nullgen;
-		$$.type = D_INDIR+D_SP;
-	}
-|	'(' LLREG '*' con ')'
-	{
-		$$ = nullgen;
-		$$.type = D_INDIR+D_NONE;
-		$$.index = $2;
-		$$.scale = $4;
-		checkscale($$.scale);
-	}
-|	'(' LLREG ')' '(' LLREG '*' con ')'
-	{
-		$$ = nullgen;
-		$$.type = D_INDIR+$2;
-		$$.index = $5;
-		$$.scale = $7;
-		checkscale($$.scale);
-	}
-
-nmem:
-	nam
-	{
-		$$ = $1;
-	}
-|	nam '(' LLREG '*' con ')'
-	{
-		$$ = $1;
-		$$.index = $3;
-		$$.scale = $5;
-		checkscale($$.scale);
-	}
-
-nam:
-	LNAME offset '(' pointer ')'
-	{
-		$$ = nullgen;
-		$$.type = $4;
-		$$.sym = linklookup(ctxt, $1->name, 0);
-		$$.offset = $2;
-	}
-|	LNAME '<' '>' offset '(' LSB ')'
-	{
-		$$ = nullgen;
-		$$.type = D_STATIC;
-		$$.sym = linklookup(ctxt, $1->name, 1);
-		$$.offset = $4;
-	}
-
-offset:
-	{
-		$$ = 0;
-	}
-|	'+' con
-	{
-		$$ = $2;
-	}
-|	'-' con
-	{
-		$$ = -$2;
-	}
-
-pointer:
-	LSB
-|	LSP
-	{
-		$$ = D_AUTO;
-	}
-|	LFP
-
-con:
-	LCONST
-|	LVAR
-	{
-		$$ = $1->value;
-	}
-|	'-' con
-	{
-		$$ = -$2;
-	}
-|	'+' con
-	{
-		$$ = $2;
-	}
-|	'~' con
-	{
-		$$ = ~$2;
-	}
-|	'(' expr ')'
-	{
-		$$ = $2;
-	}
-
-con2:
-	LCONST
-	{
-		$$ = ($1 & 0xffffffffLL) +
-			((vlong)ArgsSizeUnknown << 32);
-	}
-|	'-' LCONST
-	{
-		$$ = (-$2 & 0xffffffffLL) +
-			((vlong)ArgsSizeUnknown << 32);
-	}
-|	LCONST '-' LCONST
-	{
-		$$ = ($1 & 0xffffffffLL) +
-			(($3 & 0xffffLL) << 32);
-	}
-|	'-' LCONST '-' LCONST
-	{
-		$$ = (-$2 & 0xffffffffLL) +
-			(($4 & 0xffffLL) << 32);
-	}
-
-expr:
-	con
-|	expr '+' expr
-	{
-		$$ = $1 + $3;
-	}
-|	expr '-' expr
-	{
-		$$ = $1 - $3;
-	}
-|	expr '*' expr
-	{
-		$$ = $1 * $3;
-	}
-|	expr '/' expr
-	{
-		$$ = $1 / $3;
-	}
-|	expr '%' expr
-	{
-		$$ = $1 % $3;
-	}
-|	expr '<' '<' expr
-	{
-		$$ = $1 << $4;
-	}
-|	expr '>' '>' expr
-	{
-		$$ = $1 >> $4;
-	}
-|	expr '&' expr
-	{
-		$$ = $1 & $3;
-	}
-|	expr '^' expr
-	{
-		$$ = $1 ^ $3;
-	}
-|	expr '|' expr
-	{
-		$$ = $1 | $3;
-	}
diff --git a/src/cmd/6a/doc.go b/src/cmd/6a/doc.go
deleted file mode 100644
index 9f14cc0..0000000
--- a/src/cmd/6a/doc.go
+++ /dev/null
@@ -1,20 +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.
-
-// +build ignore
-
-/*
-
-6a is a version of the Plan 9 assembler.  The original is documented at
-
-	http://plan9.bell-labs.com/magic/man2html/1/8a
-
-Go-specific considerations are documented at
-
-	http://golang.org/doc/asm
-
-Its target architecture is the x86-64, referred to by these tools as amd64.
-
-*/
-package main
diff --git a/src/cmd/6a/lex.c b/src/cmd/6a/lex.c
deleted file mode 100644
index 8973d69..0000000
--- a/src/cmd/6a/lex.c
+++ /dev/null
@@ -1,1136 +0,0 @@
-// Inferno utils/6a/lex.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6a/lex.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.	All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#define	EXTERN
-#include <u.h>
-#include <libc.h>
-#include "a.h"
-#include "y.tab.h"
-
-enum
-{
-	Plan9	= 1<<0,
-	Unix	= 1<<1,
-	Windows	= 1<<2,
-};
-
-int
-systemtype(int sys)
-{
-#ifdef _WIN32
-	return sys&Windows;
-#else
-	return sys&Plan9;
-#endif
-}
-
-int
-pathchar(void)
-{
-	return '/';
-}
-
-int
-Lconv(Fmt *fp)
-{
-	return linklinefmt(ctxt, fp);
-}
-
-void
-dodef(char *p)
-{
-	if(nDlist%8 == 0)
-		Dlist = allocn(Dlist, nDlist*sizeof(char *),
-			8*sizeof(char *));
-	Dlist[nDlist++] = p;
-}
-
-LinkArch*       thelinkarch = &linkamd64;
-
-void
-usage(void)
-{
-	print("usage: %ca [options] file.c...\n", thechar);
-	flagprint(1);
-	errorexit();
-}
-
-void
-main(int argc, char *argv[])
-{
-	char *p;
-
-	thechar = '6';
-	thestring = "amd64";
-
-	// Allow GOARCH=thestring or GOARCH=thestringsuffix,
-	// but not other values.	
-	p = getgoarch();
-	if(strncmp(p, thestring, strlen(thestring)) != 0)
-		sysfatal("cannot use %cc with GOARCH=%s", thechar, p);
-	if(strcmp(p, "amd64p32") == 0)
-		thelinkarch = &linkamd64p32;
-
-	ctxt = linknew(thelinkarch);
-	ctxt->diag = yyerror;
-	ctxt->bso = &bstdout;
-	ctxt->enforce_data_order = 1;
-	Binit(&bstdout, 1, OWRITE);
-	listinit6();
-	fmtinstall('L', Lconv);
-
-	ensuresymb(NSYMB);
-	memset(debug, 0, sizeof(debug));
-	cinit();
-	outfile = 0;
-	setinclude(".");
-	
-	flagfn1("D", "name[=value]: add #define", dodef);
-	flagfn1("I", "dir: add dir to include path", setinclude);
-	flagcount("S", "print assembly and machine code", &debug['S']);
-	flagcount("m", "debug preprocessor macros", &debug['m']);
-	flagstr("o", "file: set output file", &outfile);
-	flagstr("trimpath", "prefix: remove prefix from recorded source file paths", &ctxt->trimpath);
-
-	flagparse(&argc, &argv, usage);
-	ctxt->debugasm = debug['S'];
-
-	if(argc < 1)
-		usage();
-	if(argc > 1){
-		print("can't assemble multiple files\n");
-		errorexit();
-	}
-
-	if(assemble(argv[0]))
-		errorexit();
-	Bflush(&bstdout);
-	exits(0);
-}
-
-int
-assemble(char *file)
-{
-	char *ofile, *p;
-	int i, of;
-
-	ofile = alloc(strlen(file)+3); // +3 for .x\0 (x=thechar)
-	strcpy(ofile, file);
-	p = utfrrune(ofile, pathchar());
-	if(p) {
-		include[0] = ofile;
-		*p++ = 0;
-	} else
-		p = ofile;
-	if(outfile == 0) {
-		outfile = p;
-		if(outfile){
-			p = utfrrune(outfile, '.');
-			if(p)
-				if(p[1] == 's' && p[2] == 0)
-					p[0] = 0;
-			p = utfrune(outfile, 0);
-			p[0] = '.';
-			p[1] = thechar;
-			p[2] = 0;
-		} else
-			outfile = "/dev/null";
-	}
-
-	of = create(outfile, OWRITE, 0664);
-	if(of < 0) {
-		yyerror("%ca: cannot create %s", thechar, outfile);
-		errorexit();
-	}
-	Binit(&obuf, of, OWRITE);
-	Bprint(&obuf, "go object %s %s %s\n", getgoos(), getgoarch(), getgoversion());
-	Bprint(&obuf, "!\n");
-
-	for(pass = 1; pass <= 2; pass++) {
-		pinit(file);
-		for(i=0; i<nDlist; i++)
-			dodefine(Dlist[i]);
-		yyparse();
-		cclean();
-		if(nerrors)
-			return nerrors;
-	}
-
-	writeobj(ctxt, &obuf);
-	Bflush(&obuf);
-	return 0;
-}
-
-struct
-{
-	char	*name;
-	/*
-	 * type is the lexical type to return.  It dictates what kind of
-	 * operands 6a allows to follow it (in a.y) as the possible operand
-	 * types are handled by a grammar.  How do you know which LTYPE?
-	 * Either read a.y or think of an instruction that has the same
-	 * possible operands and look up what it takes.
-	 */
-	ushort	type;
-	ushort	value;
-} itab[] =
-{
-	"SP",		LSP,	D_AUTO,
-	"SB",		LSB,	D_EXTERN,
-	"FP",		LFP,	D_PARAM,
-	"PC",		LPC,	D_BRANCH,
-
-	"AL",		LBREG,	D_AL,
-	"CL",		LBREG,	D_CL,
-	"DL",		LBREG,	D_DL,
-	"BL",		LBREG,	D_BL,
-/*	"SPB",		LBREG,	D_SPB,	*/
-	"SIB",		LBREG,	D_SIB,
-	"DIB",		LBREG,	D_DIB,
-	"BPB",		LBREG,	D_BPB,
-	"R8B",		LBREG,	D_R8B,
-	"R9B",		LBREG,	D_R9B,
-	"R10B",		LBREG,	D_R10B,
-	"R11B",		LBREG,	D_R11B,
-	"R12B",		LBREG,	D_R12B,
-	"R13B",		LBREG,	D_R13B,
-	"R14B",		LBREG,	D_R14B,
-	"R15B",		LBREG,	D_R15B,
-
-	"AH",		LBREG,	D_AH,
-	"CH",		LBREG,	D_CH,
-	"DH",		LBREG,	D_DH,
-	"BH",		LBREG,	D_BH,
-
-	"AX",		LLREG,	D_AX,
-	"CX",		LLREG,	D_CX,
-	"DX",		LLREG,	D_DX,
-	"BX",		LLREG,	D_BX,
-/*	"SP",		LLREG,	D_SP,	*/
-	"BP",		LLREG,	D_BP,
-	"SI",		LLREG,	D_SI,
-	"DI",		LLREG,	D_DI,
-	"R8",		LLREG,	D_R8,
-	"R9",		LLREG,	D_R9,
-	"R10",		LLREG,	D_R10,
-	"R11",		LLREG,	D_R11,
-	"R12",		LLREG,	D_R12,
-	"R13",		LLREG,	D_R13,
-	"R14",		LLREG,	D_R14,
-	"R15",		LLREG,	D_R15,
-
-	"RARG",		LLREG,	REGARG,
-
-	"F0",		LFREG,	D_F0+0,
-	"F1",		LFREG,	D_F0+1,
-	"F2",		LFREG,	D_F0+2,
-	"F3",		LFREG,	D_F0+3,
-	"F4",		LFREG,	D_F0+4,
-	"F5",		LFREG,	D_F0+5,
-	"F6",		LFREG,	D_F0+6,
-	"F7",		LFREG,	D_F0+7,
-
-	"M0",		LMREG,	D_M0+0,
-	"M1",		LMREG,	D_M0+1,
-	"M2",		LMREG,	D_M0+2,
-	"M3",		LMREG,	D_M0+3,
-	"M4",		LMREG,	D_M0+4,
-	"M5",		LMREG,	D_M0+5,
-	"M6",		LMREG,	D_M0+6,
-	"M7",		LMREG,	D_M0+7,
-
-	"X0",		LXREG,	D_X0+0,
-	"X1",		LXREG,	D_X0+1,
-	"X2",		LXREG,	D_X0+2,
-	"X3",		LXREG,	D_X0+3,
-	"X4",		LXREG,	D_X0+4,
-	"X5",		LXREG,	D_X0+5,
-	"X6",		LXREG,	D_X0+6,
-	"X7",		LXREG,	D_X0+7,
-	"X8",		LXREG,	D_X0+8,
-	"X9",		LXREG,	D_X0+9,
-	"X10",		LXREG,	D_X0+10,
-	"X11",		LXREG,	D_X0+11,
-	"X12",		LXREG,	D_X0+12,
-	"X13",		LXREG,	D_X0+13,
-	"X14",		LXREG,	D_X0+14,
-	"X15",		LXREG,	D_X0+15,
-
-	"CS",		LSREG,	D_CS,
-	"SS",		LSREG,	D_SS,
-	"DS",		LSREG,	D_DS,
-	"ES",		LSREG,	D_ES,
-	"FS",		LSREG,	D_FS,
-	"GS",		LSREG,	D_GS,
-
-	"GDTR",		LBREG,	D_GDTR,
-	"IDTR",		LBREG,	D_IDTR,
-	"LDTR",		LBREG,	D_LDTR,
-	"MSW",		LBREG,	D_MSW,
-	"TASK",		LBREG,	D_TASK,
-
-	"CR0",		LBREG,	D_CR+0,
-	"CR1",		LBREG,	D_CR+1,
-	"CR2",		LBREG,	D_CR+2,
-	"CR3",		LBREG,	D_CR+3,
-	"CR4",		LBREG,	D_CR+4,
-	"CR5",		LBREG,	D_CR+5,
-	"CR6",		LBREG,	D_CR+6,
-	"CR7",		LBREG,	D_CR+7,
-	"CR8",		LBREG,	D_CR+8,
-	"CR9",		LBREG,	D_CR+9,
-	"CR10",		LBREG,	D_CR+10,
-	"CR11",		LBREG,	D_CR+11,
-	"CR12",		LBREG,	D_CR+12,
-	"CR13",		LBREG,	D_CR+13,
-	"CR14",		LBREG,	D_CR+14,
-	"CR15",		LBREG,	D_CR+15,
-
-	"DR0",		LBREG,	D_DR+0,
-	"DR1",		LBREG,	D_DR+1,
-	"DR2",		LBREG,	D_DR+2,
-	"DR3",		LBREG,	D_DR+3,
-	"DR4",		LBREG,	D_DR+4,
-	"DR5",		LBREG,	D_DR+5,
-	"DR6",		LBREG,	D_DR+6,
-	"DR7",		LBREG,	D_DR+7,
-
-	"TR0",		LBREG,	D_TR+0,
-	"TR1",		LBREG,	D_TR+1,
-	"TR2",		LBREG,	D_TR+2,
-	"TR3",		LBREG,	D_TR+3,
-	"TR4",		LBREG,	D_TR+4,
-	"TR5",		LBREG,	D_TR+5,
-	"TR6",		LBREG,	D_TR+6,
-	"TR7",		LBREG,	D_TR+7,
-	"TLS",		LSREG,	D_TLS,
-
-	"AAA",		LTYPE0,	AAAA,
-	"AAD",		LTYPE0,	AAAD,
-	"AAM",		LTYPE0,	AAAM,
-	"AAS",		LTYPE0,	AAAS,
-	"ADCB",		LTYPE3,	AADCB,
-	"ADCL",		LTYPE3,	AADCL,
-	"ADCQ",		LTYPE3,	AADCQ,
-	"ADCW",		LTYPE3,	AADCW,
-	"ADDB",		LTYPE3,	AADDB,
-	"ADDL",		LTYPE3,	AADDL,
-	"ADDQ",		LTYPE3,	AADDQ,
-	"ADDW",		LTYPE3,	AADDW,
-	"ADJSP",	LTYPE2,	AADJSP,
-	"ANDB",		LTYPE3,	AANDB,
-	"ANDL",		LTYPE3,	AANDL,
-	"ANDQ",		LTYPE3,	AANDQ,
-	"ANDW",		LTYPE3,	AANDW,
-	"ARPL",		LTYPE3,	AARPL,
-	"BOUNDL",	LTYPE3,	ABOUNDL,
-	"BOUNDW",	LTYPE3,	ABOUNDW,
-	"BSFL",		LTYPE3,	ABSFL,
-	"BSFQ",		LTYPE3,	ABSFQ,
-	"BSFW",		LTYPE3,	ABSFW,
-	"BSRL",		LTYPE3,	ABSRL,
-	"BSRQ",		LTYPE3,	ABSRQ,
-	"BSRW",		LTYPE3,	ABSRW,
-	"BSWAPL",	LTYPE1,	ABSWAPL,
-	"BSWAPQ",	LTYPE1,	ABSWAPQ,
-	"BTCL",		LTYPE3,	ABTCL,
-	"BTCQ",		LTYPE3,	ABTCQ,
-	"BTCW",		LTYPE3,	ABTCW,
-	"BTL",		LTYPE3,	ABTL,
-	"BTQ",		LTYPE3,	ABTQ,
-	"BTRL",		LTYPE3,	ABTRL,
-	"BTRQ",		LTYPE3,	ABTRQ,
-	"BTRW",		LTYPE3,	ABTRW,
-	"BTSL",		LTYPE3,	ABTSL,
-	"BTSQ",		LTYPE3,	ABTSQ,
-	"BTSW",		LTYPE3,	ABTSW,
-	"BTW",		LTYPE3,	ABTW,
-	"BYTE",		LTYPE2,	ABYTE,
-	"CALL",		LTYPEC,	ACALL,
-	"CLC",		LTYPE0,	ACLC,
-	"CLD",		LTYPE0,	ACLD,
-	"CLI",		LTYPE0,	ACLI,
-	"CLTS",		LTYPE0,	ACLTS,
-	"CMC",		LTYPE0,	ACMC,
-	"CMPB",		LTYPE4,	ACMPB,
-	"CMPL",		LTYPE4,	ACMPL,
-	"CMPQ",		LTYPE4,	ACMPQ,
-	"CMPW",		LTYPE4,	ACMPW,
-	"CMPSB",	LTYPE0,	ACMPSB,
-	"CMPSL",	LTYPE0,	ACMPSL,
-	"CMPSQ",	LTYPE0,	ACMPSQ,
-	"CMPSW",	LTYPE0,	ACMPSW,
-	"CMPXCHG8B",	LTYPE1,	ACMPXCHG8B,
-	"CMPXCHGB",	LTYPE3,	ACMPXCHGB,	/* LTYPE3? */
-	"CMPXCHGL",	LTYPE3,	ACMPXCHGL,
-	"CMPXCHGQ",	LTYPE3,	ACMPXCHGQ,
-	"CMPXCHGW",	LTYPE3,	ACMPXCHGW,
-	"CPUID",	LTYPE0,	ACPUID,
-	"DAA",		LTYPE0,	ADAA,
-	"DAS",		LTYPE0,	ADAS,
-	"DATA",		LTYPED,	ADATA,
-	"DECB",		LTYPE1,	ADECB,
-	"DECL",		LTYPE1,	ADECL,
-	"DECQ",		LTYPE1,	ADECQ,
-	"DECW",		LTYPE1,	ADECW,
-	"DIVB",		LTYPE2,	ADIVB,
-	"DIVL",		LTYPE2,	ADIVL,
-	"DIVQ",		LTYPE2,	ADIVQ,
-	"DIVW",		LTYPE2,	ADIVW,
-	"EMMS",		LTYPE0,	AEMMS,
-	"END",		LTYPE0,	AEND,
-	"ENTER",	LTYPE2,	AENTER,
-	"GLOBL",	LTYPEG,	AGLOBL,
-	"HLT",		LTYPE0,	AHLT,
-	"IDIVB",	LTYPE2,	AIDIVB,
-	"IDIVL",	LTYPE2,	AIDIVL,
-	"IDIVQ",	LTYPE2,	AIDIVQ,
-	"IDIVW",	LTYPE2,	AIDIVW,
-	"IMULB",	LTYPEI,	AIMULB,
-	"IMULL",	LTYPEI,	AIMULL,
-	"IMULQ",	LTYPEI,	AIMULQ,
-	"IMUL3Q",	LTYPEX,	AIMUL3Q,
-	"IMULW",	LTYPEI,	AIMULW,
-	"INB",		LTYPE0,	AINB,
-	"INL",		LTYPE0,	AINL,
-	"INW",		LTYPE0,	AINW,
-	"INCB",		LTYPE1,	AINCB,
-	"INCL",		LTYPE1,	AINCL,
-	"INCQ",		LTYPE1,	AINCQ,
-	"INCW",		LTYPE1,	AINCW,
-	"INSB",		LTYPE0,	AINSB,
-	"INSL",		LTYPE0,	AINSL,
-	"INSW",		LTYPE0,	AINSW,
-	"INT",		LTYPE2,	AINT,
-	"INTO",		LTYPE0,	AINTO,
-	"INVD",		LTYPE0,	AINVD,
-	"INVLPG",	LTYPE2,	AINVLPG,
-	"IRETL",	LTYPE0,	AIRETL,
-	"IRETQ",	LTYPE0,	AIRETQ,
-	"IRETW",	LTYPE0,	AIRETW,
-
-	"JOS",		LTYPER,	AJOS,	/* overflow set (OF = 1) */
-	"JO",		LTYPER,	AJOS,	/* alternate */
-	"JOC",		LTYPER,	AJOC,	/* overflow clear (OF = 0) */
-	"JNO",		LTYPER,	AJOC,	/* alternate */
-	"JCS",		LTYPER,	AJCS,	/* carry set (CF = 1) */
-	"JB",		LTYPER,	AJCS,	/* alternate */
-	"JC",		LTYPER,	AJCS,	/* alternate */
-	"JNAE",		LTYPER,	AJCS,	/* alternate */
-	"JLO",		LTYPER,	AJCS,	/* alternate */
-	"JCC",		LTYPER,	AJCC,	/* carry clear (CF = 0) */
-	"JAE",		LTYPER,	AJCC,	/* alternate */
-	"JNB",		LTYPER,	AJCC,	/* alternate */
-	"JNC",		LTYPER,	AJCC,	/* alternate */
-	"JHS",		LTYPER,	AJCC,	/* alternate */
-	"JEQ",		LTYPER,	AJEQ,	/* equal (ZF = 1) */
-	"JE",		LTYPER,	AJEQ,	/* alternate */
-	"JZ",		LTYPER,	AJEQ,	/* alternate */
-	"JNE",		LTYPER,	AJNE,	/* not equal (ZF = 0) */
-	"JNZ",		LTYPER,	AJNE,	/* alternate */
-	"JLS",		LTYPER,	AJLS,	/* lower or same (unsigned) (CF = 1 || ZF = 1) */
-	"JBE",		LTYPER,	AJLS,	/* alternate */
-	"JNA",		LTYPER,	AJLS,	/* alternate */
-	"JHI",		LTYPER,	AJHI,	/* higher (unsigned) (CF = 0 && ZF = 0) */
-	"JA",		LTYPER,	AJHI,	/* alternate */
-	"JNBE",		LTYPER,	AJHI,	/* alternate */
-	"JMI",		LTYPER,	AJMI,	/* negative (minus) (SF = 1) */
-	"JS",		LTYPER,	AJMI,	/* alternate */
-	"JPL",		LTYPER,	AJPL,	/* non-negative (plus) (SF = 0) */
-	"JNS",		LTYPER,	AJPL,	/* alternate */
-	"JPS",		LTYPER,	AJPS,	/* parity set (PF = 1) */
-	"JP",		LTYPER,	AJPS,	/* alternate */
-	"JPE",		LTYPER,	AJPS,	/* alternate */
-	"JPC",		LTYPER,	AJPC,	/* parity clear (PF = 0) */
-	"JNP",		LTYPER,	AJPC,	/* alternate */
-	"JPO",		LTYPER,	AJPC,	/* alternate */
-	"JLT",		LTYPER,	AJLT,	/* less than (signed) (SF != OF) */
-	"JL",		LTYPER,	AJLT,	/* alternate */
-	"JNGE",		LTYPER,	AJLT,	/* alternate */
-	"JGE",		LTYPER,	AJGE,	/* greater than or equal (signed) (SF = OF) */
-	"JNL",		LTYPER,	AJGE,	/* alternate */
-	"JLE",		LTYPER,	AJLE,	/* less than or equal (signed) (ZF = 1 || SF != OF) */
-	"JNG",		LTYPER,	AJLE,	/* alternate */
-	"JGT",		LTYPER,	AJGT,	/* greater than (signed) (ZF = 0 && SF = OF) */
-	"JG",		LTYPER,	AJGT,	/* alternate */
-	"JNLE",		LTYPER,	AJGT,	/* alternate */
-	"JCXZL",	LTYPER,	AJCXZL,
-	"JCXZQ",	LTYPER,	AJCXZQ,
-	"JMP",		LTYPEC,	AJMP,
-	"LAHF",		LTYPE0,	ALAHF,
-	"LARL",		LTYPE3,	ALARL,
-	"LARW",		LTYPE3,	ALARW,
-	"LEAL",		LTYPE3,	ALEAL,
-	"LEAQ",		LTYPE3,	ALEAQ,
-	"LEAW",		LTYPE3,	ALEAW,
-	"LEAVEL",	LTYPE0,	ALEAVEL,
-	"LEAVEQ",	LTYPE0,	ALEAVEQ,
-	"LEAVEW",	LTYPE0,	ALEAVEW,
-	"LFENCE",	LTYPE0,	ALFENCE,
-	"LOCK",		LTYPE0,	ALOCK,
-	"LODSB",	LTYPE0,	ALODSB,
-	"LODSL",	LTYPE0,	ALODSL,
-	"LODSQ",	LTYPE0,	ALODSQ,
-	"LODSW",	LTYPE0,	ALODSW,
-	"LONG",		LTYPE2,	ALONG,
-	"LOOP",		LTYPER,	ALOOP,
-	"LOOPEQ",	LTYPER,	ALOOPEQ,
-	"LOOPNE",	LTYPER,	ALOOPNE,
-	"LSLL",		LTYPE3,	ALSLL,
-	"LSLW",		LTYPE3,	ALSLW,
-	"MFENCE",	LTYPE0,	AMFENCE,
-	"MODE",		LTYPE2,	AMODE,
-	"MOVB",		LTYPE3,	AMOVB,
-	"MOVL",		LTYPEM,	AMOVL,
-	"MOVQ",		LTYPEM,	AMOVQ,
-	"MOVW",		LTYPEM,	AMOVW,
-	"MOVBLSX",	LTYPE3, AMOVBLSX,
-	"MOVBLZX",	LTYPE3, AMOVBLZX,
-	"MOVBQSX",	LTYPE3,	AMOVBQSX,
-	"MOVBQZX",	LTYPE3,	AMOVBQZX,
-	"MOVBWSX",	LTYPE3, AMOVBWSX,
-	"MOVBWZX",	LTYPE3, AMOVBWZX,
-	"MOVLQSX",	LTYPE3, AMOVLQSX,
-	"MOVLQZX",	LTYPE3, AMOVLQZX,
-	"MOVNTIL",	LTYPE3,	AMOVNTIL,
-	"MOVNTIQ",	LTYPE3,	AMOVNTIQ,
-	"MOVQL",	LTYPE3, AMOVQL,
-	"MOVWLSX",	LTYPE3, AMOVWLSX,
-	"MOVWLZX",	LTYPE3, AMOVWLZX,
-	"MOVWQSX",	LTYPE3,	AMOVWQSX,
-	"MOVWQZX",	LTYPE3,	AMOVWQZX,
-	"MOVSB",	LTYPE0,	AMOVSB,
-	"MOVSL",	LTYPE0,	AMOVSL,
-	"MOVSQ",	LTYPE0,	AMOVSQ,
-	"MOVSW",	LTYPE0,	AMOVSW,
-	"MULB",		LTYPE2,	AMULB,
-	"MULL",		LTYPE2,	AMULL,
-	"MULQ",		LTYPE2,	AMULQ,
-	"MULW",		LTYPE2,	AMULW,
-	"NEGB",		LTYPE1,	ANEGB,
-	"NEGL",		LTYPE1,	ANEGL,
-	"NEGQ",		LTYPE1,	ANEGQ,
-	"NEGW",		LTYPE1,	ANEGW,
-	"NOP",		LTYPEN,	ANOP,
-	"NOTB",		LTYPE1,	ANOTB,
-	"NOTL",		LTYPE1,	ANOTL,
-	"NOTQ",		LTYPE1,	ANOTQ,
-	"NOTW",		LTYPE1,	ANOTW,
-	"ORB",		LTYPE3,	AORB,
-	"ORL",		LTYPE3,	AORL,
-	"ORQ",		LTYPE3,	AORQ,
-	"ORW",		LTYPE3,	AORW,
-	"OUTB",		LTYPE0,	AOUTB,
-	"OUTL",		LTYPE0,	AOUTL,
-	"OUTW",		LTYPE0,	AOUTW,
-	"OUTSB",	LTYPE0,	AOUTSB,
-	"OUTSL",	LTYPE0,	AOUTSL,
-	"OUTSW",	LTYPE0,	AOUTSW,
-	"PAUSE",	LTYPEN,	APAUSE,
-	"POPAL",	LTYPE0,	APOPAL,
-	"POPAW",	LTYPE0,	APOPAW,
-	"POPFL",	LTYPE0,	APOPFL,
-	"POPFQ",	LTYPE0,	APOPFQ,
-	"POPFW",	LTYPE0,	APOPFW,
-	"POPL",		LTYPE1,	APOPL,
-	"POPQ",		LTYPE1,	APOPQ,
-	"POPW",		LTYPE1,	APOPW,
-	"PUSHAL",	LTYPE0,	APUSHAL,
-	"PUSHAW",	LTYPE0,	APUSHAW,
-	"PUSHFL",	LTYPE0,	APUSHFL,
-	"PUSHFQ",	LTYPE0,	APUSHFQ,
-	"PUSHFW",	LTYPE0,	APUSHFW,
-	"PUSHL",	LTYPE2,	APUSHL,
-	"PUSHQ",	LTYPE2,	APUSHQ,
-	"PUSHW",	LTYPE2,	APUSHW,
-	"RCLB",		LTYPE3,	ARCLB,
-	"RCLL",		LTYPE3,	ARCLL,
-	"RCLQ",		LTYPE3,	ARCLQ,
-	"RCLW",		LTYPE3,	ARCLW,
-	"RCRB",		LTYPE3,	ARCRB,
-	"RCRL",		LTYPE3,	ARCRL,
-	"RCRQ",		LTYPE3,	ARCRQ,
-	"RCRW",		LTYPE3,	ARCRW,
-	"RDMSR",	LTYPE0,	ARDMSR,
-	"RDPMC",	LTYPE0,	ARDPMC,
-	"RDTSC",	LTYPE0,	ARDTSC,
-	"REP",		LTYPE0,	AREP,
-	"REPN",		LTYPE0,	AREPN,
-	"RET",		LTYPE0,	ARET,
-	"RETFL",	LTYPERT,ARETFL,
-	"RETFW",	LTYPERT,ARETFW,
-	"RETFQ",	LTYPERT,ARETFQ,
-	"ROLB",		LTYPE3,	AROLB,
-	"ROLL",		LTYPE3,	AROLL,
-	"ROLQ",		LTYPE3,	AROLQ,
-	"ROLW",		LTYPE3,	AROLW,
-	"RORB",		LTYPE3,	ARORB,
-	"RORL",		LTYPE3,	ARORL,
-	"RORQ",		LTYPE3,	ARORQ,
-	"RORW",		LTYPE3,	ARORW,
-	"RSM",		LTYPE0,	ARSM,
-	"SAHF",		LTYPE0,	ASAHF,
-	"SALB",		LTYPE3,	ASALB,
-	"SALL",		LTYPE3,	ASALL,
-	"SALQ",		LTYPE3,	ASALQ,
-	"SALW",		LTYPE3,	ASALW,
-	"SARB",		LTYPE3,	ASARB,
-	"SARL",		LTYPE3,	ASARL,
-	"SARQ",		LTYPE3,	ASARQ,
-	"SARW",		LTYPE3,	ASARW,
-	"SBBB",		LTYPE3,	ASBBB,
-	"SBBL",		LTYPE3,	ASBBL,
-	"SBBQ",		LTYPE3,	ASBBQ,
-	"SBBW",		LTYPE3,	ASBBW,
-	"SCASB",	LTYPE0,	ASCASB,
-	"SCASL",	LTYPE0,	ASCASL,
-	"SCASQ",	LTYPE0,	ASCASQ,
-	"SCASW",	LTYPE0,	ASCASW,
-	"SETCC",	LTYPE1,	ASETCC,	/* see JCC etc above for condition codes */
-	"SETCS",	LTYPE1,	ASETCS,
-	"SETEQ",	LTYPE1,	ASETEQ,
-	"SETGE",	LTYPE1,	ASETGE,
-	"SETGT",	LTYPE1,	ASETGT,
-	"SETHI",	LTYPE1,	ASETHI,
-	"SETLE",	LTYPE1,	ASETLE,
-	"SETLS",	LTYPE1,	ASETLS,
-	"SETLT",	LTYPE1,	ASETLT,
-	"SETMI",	LTYPE1,	ASETMI,
-	"SETNE",	LTYPE1,	ASETNE,
-	"SETOC",	LTYPE1,	ASETOC,
-	"SETOS",	LTYPE1,	ASETOS,
-	"SETPC",	LTYPE1,	ASETPC,
-	"SETPL",	LTYPE1,	ASETPL,
-	"SETPS",	LTYPE1,	ASETPS,
-	"SFENCE",	LTYPE0,	ASFENCE,
-	"CDQ",		LTYPE0,	ACDQ,
-	"CWD",		LTYPE0,	ACWD,
-	"CQO",		LTYPE0,	ACQO,
-	"SHLB",		LTYPE3,	ASHLB,
-	"SHLL",		LTYPES,	ASHLL,
-	"SHLQ",		LTYPES,	ASHLQ,
-	"SHLW",		LTYPES,	ASHLW,
-	"SHRB",		LTYPE3,	ASHRB,
-	"SHRL",		LTYPES,	ASHRL,
-	"SHRQ",		LTYPES,	ASHRQ,
-	"SHRW",		LTYPES,	ASHRW,
-	"STC",		LTYPE0,	ASTC,
-	"STD",		LTYPE0,	ASTD,
-	"STI",		LTYPE0,	ASTI,
-	"STOSB",	LTYPE0,	ASTOSB,
-	"STOSL",	LTYPE0,	ASTOSL,
-	"STOSQ",	LTYPE0,	ASTOSQ,
-	"STOSW",	LTYPE0,	ASTOSW,
-	"SUBB",		LTYPE3,	ASUBB,
-	"SUBL",		LTYPE3,	ASUBL,
-	"SUBQ",		LTYPE3,	ASUBQ,
-	"SUBW",		LTYPE3,	ASUBW,
-	"SYSCALL",	LTYPE0,	ASYSCALL,
-	"SYSRET",	LTYPE0,	ASYSRET,
-	"SWAPGS",	LTYPE0,	ASWAPGS,
-	"TESTB",	LTYPE3,	ATESTB,
-	"TESTL",	LTYPE3,	ATESTL,
-	"TESTQ",	LTYPE3,	ATESTQ,
-	"TESTW",	LTYPE3,	ATESTW,
-	"TEXT",		LTYPET,	ATEXT,
-	"VERR",		LTYPE2,	AVERR,
-	"VERW",		LTYPE2,	AVERW,
-	"QUAD",		LTYPE2,	AQUAD,
-	"WAIT",		LTYPE0,	AWAIT,
-	"WBINVD",	LTYPE0,	AWBINVD,
-	"WRMSR",	LTYPE0,	AWRMSR,
-	"WORD",		LTYPE2,	AWORD,
-	"XADDB",	LTYPE3,	AXADDB,
-	"XADDL",	LTYPE3,	AXADDL,
-	"XADDQ",	LTYPE3,	AXADDQ,
-	"XADDW",	LTYPE3,	AXADDW,
-	"XCHGB",	LTYPE3,	AXCHGB,
-	"XCHGL",	LTYPE3,	AXCHGL,
-	"XCHGQ",	LTYPE3,	AXCHGQ,
-	"XCHGW",	LTYPE3,	AXCHGW,
-	"XLAT",		LTYPE2,	AXLAT,
-	"XORB",		LTYPE3,	AXORB,
-	"XORL",		LTYPE3,	AXORL,
-	"XORQ",		LTYPE3,	AXORQ,
-	"XORW",		LTYPE3,	AXORW,
-
-	"CMOVLCC",	LTYPE3,	ACMOVLCC,
-	"CMOVLCS",	LTYPE3,	ACMOVLCS,
-	"CMOVLEQ",	LTYPE3,	ACMOVLEQ,
-	"CMOVLGE",	LTYPE3,	ACMOVLGE,
-	"CMOVLGT",	LTYPE3,	ACMOVLGT,
-	"CMOVLHI",	LTYPE3,	ACMOVLHI,
-	"CMOVLLE",	LTYPE3,	ACMOVLLE,
-	"CMOVLLS",	LTYPE3,	ACMOVLLS,
-	"CMOVLLT",	LTYPE3,	ACMOVLLT,
-	"CMOVLMI",	LTYPE3,	ACMOVLMI,
-	"CMOVLNE",	LTYPE3,	ACMOVLNE,
-	"CMOVLOC",	LTYPE3,	ACMOVLOC,
-	"CMOVLOS",	LTYPE3,	ACMOVLOS,
-	"CMOVLPC",	LTYPE3,	ACMOVLPC,
-	"CMOVLPL",	LTYPE3,	ACMOVLPL,
-	"CMOVLPS",	LTYPE3,	ACMOVLPS,
-	"CMOVQCC",	LTYPE3,	ACMOVQCC,
-	"CMOVQCS",	LTYPE3,	ACMOVQCS,
-	"CMOVQEQ",	LTYPE3,	ACMOVQEQ,
-	"CMOVQGE",	LTYPE3,	ACMOVQGE,
-	"CMOVQGT",	LTYPE3,	ACMOVQGT,
-	"CMOVQHI",	LTYPE3,	ACMOVQHI,
-	"CMOVQLE",	LTYPE3,	ACMOVQLE,
-	"CMOVQLS",	LTYPE3,	ACMOVQLS,
-	"CMOVQLT",	LTYPE3,	ACMOVQLT,
-	"CMOVQMI",	LTYPE3,	ACMOVQMI,
-	"CMOVQNE",	LTYPE3,	ACMOVQNE,
-	"CMOVQOC",	LTYPE3,	ACMOVQOC,
-	"CMOVQOS",	LTYPE3,	ACMOVQOS,
-	"CMOVQPC",	LTYPE3,	ACMOVQPC,
-	"CMOVQPL",	LTYPE3,	ACMOVQPL,
-	"CMOVQPS",	LTYPE3,	ACMOVQPS,
-	"CMOVWCC",	LTYPE3,	ACMOVWCC,
-	"CMOVWCS",	LTYPE3,	ACMOVWCS,
-	"CMOVWEQ",	LTYPE3,	ACMOVWEQ,
-	"CMOVWGE",	LTYPE3,	ACMOVWGE,
-	"CMOVWGT",	LTYPE3,	ACMOVWGT,
-	"CMOVWHI",	LTYPE3,	ACMOVWHI,
-	"CMOVWLE",	LTYPE3,	ACMOVWLE,
-	"CMOVWLS",	LTYPE3,	ACMOVWLS,
-	"CMOVWLT",	LTYPE3,	ACMOVWLT,
-	"CMOVWMI",	LTYPE3,	ACMOVWMI,
-	"CMOVWNE",	LTYPE3,	ACMOVWNE,
-	"CMOVWOC",	LTYPE3,	ACMOVWOC,
-	"CMOVWOS",	LTYPE3,	ACMOVWOS,
-	"CMOVWPC",	LTYPE3,	ACMOVWPC,
-	"CMOVWPL",	LTYPE3,	ACMOVWPL,
-	"CMOVWPS",	LTYPE3,	ACMOVWPS,
-
-	"FMOVB",	LTYPE3, AFMOVB,
-	"FMOVBP",	LTYPE3, AFMOVBP,
-	"FMOVD",	LTYPE3, AFMOVD,
-	"FMOVDP",	LTYPE3, AFMOVDP,
-	"FMOVF",	LTYPE3, AFMOVF,
-	"FMOVFP",	LTYPE3, AFMOVFP,
-	"FMOVL",	LTYPE3, AFMOVL,
-	"FMOVLP",	LTYPE3, AFMOVLP,
-	"FMOVV",	LTYPE3, AFMOVV,
-	"FMOVVP",	LTYPE3, AFMOVVP,
-	"FMOVW",	LTYPE3, AFMOVW,
-	"FMOVWP",	LTYPE3, AFMOVWP,
-	"FMOVX",	LTYPE3, AFMOVX,
-	"FMOVXP",	LTYPE3, AFMOVXP,
-	"FCOMB",	LTYPE3, AFCOMB,
-	"FCOMBP",	LTYPE3, AFCOMBP,
-	"FCOMD",	LTYPE3, AFCOMD,
-	"FCOMDP",	LTYPE3, AFCOMDP,
-	"FCOMDPP",	LTYPE3, AFCOMDPP,
-	"FCOMF",	LTYPE3, AFCOMF,
-	"FCOMFP",	LTYPE3, AFCOMFP,
-	"FCOML",	LTYPE3, AFCOML,
-	"FCOMLP",	LTYPE3, AFCOMLP,
-	"FCOMW",	LTYPE3, AFCOMW,
-	"FCOMWP",	LTYPE3, AFCOMWP,
-	"FUCOM",	LTYPE3, AFUCOM,
-	"FUCOMP",	LTYPE3, AFUCOMP,
-	"FUCOMPP",	LTYPE3, AFUCOMPP,
-	"FADDW",	LTYPE3, AFADDW,
-	"FADDL",	LTYPE3, AFADDL,
-	"FADDF",	LTYPE3, AFADDF,
-	"FADDD",	LTYPE3, AFADDD,
-	"FADDDP",	LTYPE3, AFADDDP,
-	"FSUBDP",	LTYPE3, AFSUBDP,
-	"FSUBW",	LTYPE3, AFSUBW,
-	"FSUBL",	LTYPE3, AFSUBL,
-	"FSUBF",	LTYPE3, AFSUBF,
-	"FSUBD",	LTYPE3, AFSUBD,
-	"FSUBRDP",	LTYPE3, AFSUBRDP,
-	"FSUBRW",	LTYPE3, AFSUBRW,
-	"FSUBRL",	LTYPE3, AFSUBRL,
-	"FSUBRF",	LTYPE3, AFSUBRF,
-	"FSUBRD",	LTYPE3, AFSUBRD,
-	"FMULDP",	LTYPE3, AFMULDP,
-	"FMULW",	LTYPE3, AFMULW,
-	"FMULL",	LTYPE3, AFMULL,
-	"FMULF",	LTYPE3, AFMULF,
-	"FMULD",	LTYPE3, AFMULD,
-	"FDIVDP",	LTYPE3, AFDIVDP,
-	"FDIVW",	LTYPE3, AFDIVW,
-	"FDIVL",	LTYPE3, AFDIVL,
-	"FDIVF",	LTYPE3, AFDIVF,
-	"FDIVD",	LTYPE3, AFDIVD,
-	"FDIVRDP",	LTYPE3, AFDIVRDP,
-	"FDIVRW",	LTYPE3, AFDIVRW,
-	"FDIVRL",	LTYPE3, AFDIVRL,
-	"FDIVRF",	LTYPE3, AFDIVRF,
-	"FDIVRD",	LTYPE3, AFDIVRD,
-	"FXCHD",	LTYPE3, AFXCHD,
-	"FFREE",	LTYPE1, AFFREE,
-	"FLDCW",	LTYPE2, AFLDCW,
-	"FLDENV",	LTYPE1, AFLDENV,
-	"FRSTOR",	LTYPE2, AFRSTOR,
-	"FSAVE",	LTYPE1, AFSAVE,
-	"FSTCW",	LTYPE1, AFSTCW,
-	"FSTENV",	LTYPE1, AFSTENV,
-	"FSTSW",	LTYPE1, AFSTSW,
-	"F2XM1",	LTYPE0, AF2XM1,
-	"FABS",		LTYPE0, AFABS,
-	"FCHS",		LTYPE0, AFCHS,
-	"FCLEX",	LTYPE0, AFCLEX,
-	"FCOS",		LTYPE0, AFCOS,
-	"FDECSTP",	LTYPE0, AFDECSTP,
-	"FINCSTP",	LTYPE0, AFINCSTP,
-	"FINIT",	LTYPE0, AFINIT,
-	"FLD1",		LTYPE0, AFLD1,
-	"FLDL2E",	LTYPE0, AFLDL2E,
-	"FLDL2T",	LTYPE0, AFLDL2T,
-	"FLDLG2",	LTYPE0, AFLDLG2,
-	"FLDLN2",	LTYPE0, AFLDLN2,
-	"FLDPI",	LTYPE0, AFLDPI,
-	"FLDZ",		LTYPE0, AFLDZ,
-	"FNOP",		LTYPE0, AFNOP,
-	"FPATAN",	LTYPE0, AFPATAN,
-	"FPREM",	LTYPE0, AFPREM,
-	"FPREM1",	LTYPE0, AFPREM1,
-	"FPTAN",	LTYPE0, AFPTAN,
-	"FRNDINT",	LTYPE0, AFRNDINT,
-	"FSCALE",	LTYPE0, AFSCALE,
-	"FSIN",		LTYPE0, AFSIN,
-	"FSINCOS",	LTYPE0, AFSINCOS,
-	"FSQRT",	LTYPE0, AFSQRT,
-	"FTST",		LTYPE0, AFTST,
-	"FXAM",		LTYPE0, AFXAM,
-	"FXTRACT",	LTYPE0, AFXTRACT,
-	"FYL2X",	LTYPE0, AFYL2X,
-	"FYL2XP1",	LTYPE0, AFYL2XP1,
-
-	"ADDPD",	LTYPE3,	AADDPD,
-	"ADDPS",	LTYPE3,	AADDPS,
-	"ADDSD",	LTYPE3,	AADDSD,
-	"ADDSS",	LTYPE3,	AADDSS,
-	"ANDNPD",	LTYPE3,	AANDNPD,
-	"ANDNPS",	LTYPE3,	AANDNPS,
-	"ANDPD",	LTYPE3,	AANDPD,
-	"ANDPS",	LTYPE3,	AANDPS,
-	"CMPPD",	LTYPEXC,ACMPPD,
-	"CMPPS",	LTYPEXC,ACMPPS,
-	"CMPSD",	LTYPEXC,ACMPSD,
-	"CMPSS",	LTYPEXC,ACMPSS,
-	"COMISD",	LTYPE3,	ACOMISD,
-	"COMISS",	LTYPE3,	ACOMISS,
-	"CVTPL2PD",	LTYPE3,	ACVTPL2PD,
-	"CVTPL2PS",	LTYPE3,	ACVTPL2PS,
-	"CVTPD2PL",	LTYPE3,	ACVTPD2PL,
-	"CVTPD2PS",	LTYPE3,	ACVTPD2PS,
-	"CVTPS2PL",	LTYPE3,	ACVTPS2PL,
-	"PF2IW",	LTYPE3,	APF2IW,
-	"PF2IL",	LTYPE3,	APF2IL,
-	"PF2ID",	LTYPE3,	APF2IL,	/* syn */
-	"PI2FL",	LTYPE3,	API2FL,
-	"PI2FD",	LTYPE3,	API2FL,	/* syn */
-	"PI2FW",	LTYPE3,	API2FW,
-	"CVTPS2PD",	LTYPE3,	ACVTPS2PD,
-	"CVTSD2SL",	LTYPE3,	ACVTSD2SL,
-	"CVTSD2SQ",	LTYPE3,	ACVTSD2SQ,
-	"CVTSD2SS",	LTYPE3,	ACVTSD2SS,
-	"CVTSL2SD",	LTYPE3,	ACVTSL2SD,
-	"CVTSQ2SD",	LTYPE3,	ACVTSQ2SD,
-	"CVTSL2SS",	LTYPE3,	ACVTSL2SS,
-	"CVTSQ2SS",	LTYPE3,	ACVTSQ2SS,
-	"CVTSS2SD",	LTYPE3,	ACVTSS2SD,
-	"CVTSS2SL",	LTYPE3,	ACVTSS2SL,
-	"CVTSS2SQ",	LTYPE3,	ACVTSS2SQ,
-	"CVTTPD2PL",	LTYPE3,	ACVTTPD2PL,
-	"CVTTPS2PL",	LTYPE3,	ACVTTPS2PL,
-	"CVTTSD2SL",	LTYPE3,	ACVTTSD2SL,
-	"CVTTSD2SQ",	LTYPE3,	ACVTTSD2SQ,
-	"CVTTSS2SL",	LTYPE3,	ACVTTSS2SL,
-	"CVTTSS2SQ",	LTYPE3,	ACVTTSS2SQ,
-	"DIVPD",	LTYPE3,	ADIVPD,
-	"DIVPS",	LTYPE3,	ADIVPS,
-	"DIVSD",	LTYPE3,	ADIVSD,
-	"DIVSS",	LTYPE3,	ADIVSS,
-	"FXRSTOR",	LTYPE2,	AFXRSTOR,
-	"FXRSTOR64",	LTYPE2,	AFXRSTOR64,
-	"FXSAVE",	LTYPE1,	AFXSAVE,
-	"FXSAVE64",	LTYPE1,	AFXSAVE64,
-	"LDMXCSR",	LTYPE2,	ALDMXCSR,
-	"MASKMOVOU",	LTYPE3,	AMASKMOVOU,
-	"MASKMOVDQU",	LTYPE3,	AMASKMOVOU,	/* syn */
-	"MASKMOVQ",	LTYPE3,	AMASKMOVQ,
-	"MAXPD",	LTYPE3,	AMAXPD,
-	"MAXPS",	LTYPE3,	AMAXPS,
-	"MAXSD",	LTYPE3,	AMAXSD,
-	"MAXSS",	LTYPE3,	AMAXSS,
-	"MINPD",	LTYPE3,	AMINPD,
-	"MINPS",	LTYPE3,	AMINPS,
-	"MINSD",	LTYPE3,	AMINSD,
-	"MINSS",	LTYPE3,	AMINSS,
-	"MOVAPD",	LTYPE3,	AMOVAPD,
-	"MOVAPS",	LTYPE3,	AMOVAPS,
-	"MOVD",		LTYPE3,	AMOVQ,	/* syn */
-	"MOVDQ2Q",	LTYPE3,	AMOVQ,	/* syn */
-	"MOVO",		LTYPE3,	AMOVO,
-	"MOVOA",	LTYPE3,	AMOVO,	/* syn */
-	"MOVOU",	LTYPE3,	AMOVOU,
-	"MOVHLPS",	LTYPE3,	AMOVHLPS,
-	"MOVHPD",	LTYPE3,	AMOVHPD,
-	"MOVHPS",	LTYPE3,	AMOVHPS,
-	"MOVLHPS",	LTYPE3,	AMOVLHPS,
-	"MOVLPD",	LTYPE3,	AMOVLPD,
-	"MOVLPS",	LTYPE3,	AMOVLPS,
-	"MOVMSKPD",	LTYPE3,	AMOVMSKPD,
-	"MOVMSKPS",	LTYPE3,	AMOVMSKPS,
-	"MOVNTO",	LTYPE3,	AMOVNTO,
-	"MOVNTDQ",	LTYPE3,	AMOVNTO,	/* syn */
-	"MOVNTPD",	LTYPE3,	AMOVNTPD,
-	"MOVNTPS",	LTYPE3,	AMOVNTPS,
-	"MOVNTQ",	LTYPE3,	AMOVNTQ,
-	"MOVQOZX",	LTYPE3,	AMOVQOZX,
-	"MOVSD",	LTYPE3,	AMOVSD,
-	"MOVSS",	LTYPE3,	AMOVSS,
-	"MOVUPD",	LTYPE3,	AMOVUPD,
-	"MOVUPS",	LTYPE3,	AMOVUPS,
-	"MULPD",	LTYPE3,	AMULPD,
-	"MULPS",	LTYPE3,	AMULPS,
-	"MULSD",	LTYPE3,	AMULSD,
-	"MULSS",	LTYPE3,	AMULSS,
-	"ORPD",		LTYPE3,	AORPD,
-	"ORPS",		LTYPE3,	AORPS,
-	"PACKSSLW",	LTYPE3,	APACKSSLW,
-	"PACKSSWB",	LTYPE3,	APACKSSWB,
-	"PACKUSWB",	LTYPE3,	APACKUSWB,
-	"PADDB",	LTYPE3,	APADDB,
-	"PADDL",	LTYPE3,	APADDL,
-	"PADDQ",	LTYPE3,	APADDQ,
-	"PADDSB",	LTYPE3,	APADDSB,
-	"PADDSW",	LTYPE3,	APADDSW,
-	"PADDUSB",	LTYPE3,	APADDUSB,
-	"PADDUSW",	LTYPE3,	APADDUSW,
-	"PADDW",	LTYPE3,	APADDW,
-	"PAND",		LTYPE3, APAND,
-	"PANDB",	LTYPE3,	APANDB,
-	"PANDL",	LTYPE3,	APANDL,
-	"PANDSB",	LTYPE3,	APANDSB,
-	"PANDSW",	LTYPE3,	APANDSW,
-	"PANDUSB",	LTYPE3,	APANDUSB,
-	"PANDUSW",	LTYPE3,	APANDUSW,
-	"PANDW",	LTYPE3,	APANDW,
-	"PANDN",	LTYPE3, APANDN,
-	"PAVGB",	LTYPE3,	APAVGB,
-	"PAVGW",	LTYPE3,	APAVGW,
-	"PCMPEQB",	LTYPE3,	APCMPEQB,
-	"PCMPEQL",	LTYPE3,	APCMPEQL,
-	"PCMPEQW",	LTYPE3,	APCMPEQW,
-	"PCMPGTB",	LTYPE3,	APCMPGTB,
-	"PCMPGTL",	LTYPE3,	APCMPGTL,	
-	"PCMPGTW",	LTYPE3,	APCMPGTW,
-	"PEXTRW",	LTYPEX,	APEXTRW,
-	"PINSRW",	LTYPEX,	APINSRW,
-	"PINSRD",	LTYPEX,	APINSRD,
-	"PINSRQ",	LTYPEX,	APINSRQ,
-	"PMADDWL",	LTYPE3,	APMADDWL,
-	"PMAXSW",	LTYPE3,	APMAXSW,
-	"PMAXUB",	LTYPE3,	APMAXUB,
-	"PMINSW",	LTYPE3,	APMINSW,
-	"PMINUB",	LTYPE3,	APMINUB,
-	"PMOVMSKB",	LTYPE3,	APMOVMSKB,
-	"PMULHRW",	LTYPE3,	APMULHRW,
-	"PMULHUW",	LTYPE3,	APMULHUW,
-	"PMULHW",	LTYPE3,	APMULHW,
-	"PMULLW",	LTYPE3,	APMULLW,
-	"PMULULQ",	LTYPE3,	APMULULQ,
-	"POR",		LTYPE3,	APOR,
-	"PSADBW",	LTYPE3,	APSADBW,
-	"PSHUFHW",	LTYPEX,	APSHUFHW,
-	"PSHUFL",	LTYPEX,	APSHUFL,
-	"PSHUFLW",	LTYPEX,	APSHUFLW,
-	"PSHUFW",	LTYPEX, APSHUFW,
-	"PSHUFB",	LTYPEM, APSHUFB,
-	"PSLLO",	LTYPE3,	APSLLO,
-	"PSLLDQ",	LTYPE3,	APSLLO,	/* syn */
-	"PSLLL",	LTYPE3,	APSLLL,
-	"PSLLQ",	LTYPE3,	APSLLQ,
-	"PSLLW",	LTYPE3,	APSLLW,
-	"PSRAL",	LTYPE3,	APSRAL,
-	"PSRAW",	LTYPE3,	APSRAW,
-	"PSRLO",	LTYPE3,	APSRLO,
-	"PSRLDQ",	LTYPE3,	APSRLO,	/* syn */
-	"PSRLL",	LTYPE3,	APSRLL,
-	"PSRLQ",	LTYPE3,	APSRLQ,
-	"PSRLW",	LTYPE3,	APSRLW,
-	"PSUBB",	LTYPE3,	APSUBB,
-	"PSUBL",	LTYPE3,	APSUBL,
-	"PSUBQ",	LTYPE3,	APSUBQ,
-	"PSUBSB",	LTYPE3,	APSUBSB,
-	"PSUBSW",	LTYPE3,	APSUBSW,
-	"PSUBUSB",	LTYPE3,	APSUBUSB,
-	"PSUBUSW",	LTYPE3,	APSUBUSW,
-	"PSUBW",	LTYPE3,	APSUBW,
-	"PUNPCKHBW",	LTYPE3,	APUNPCKHBW,
-	"PUNPCKHLQ",	LTYPE3,	APUNPCKHLQ,
-	"PUNPCKHQDQ",	LTYPE3,	APUNPCKHQDQ,
-	"PUNPCKHWL",	LTYPE3,	APUNPCKHWL,
-	"PUNPCKLBW",	LTYPE3,	APUNPCKLBW,
-	"PUNPCKLLQ",	LTYPE3,	APUNPCKLLQ,
-	"PUNPCKLQDQ",	LTYPE3,	APUNPCKLQDQ,
-	"PUNPCKLWL",	LTYPE3,	APUNPCKLWL,
-	"PXOR",		LTYPE3,	APXOR,
-	"RCPPS",	LTYPE3,	ARCPPS,
-	"RCPSS",	LTYPE3,	ARCPSS,
-	"RSQRTPS",	LTYPE3,	ARSQRTPS,
-	"RSQRTSS",	LTYPE3,	ARSQRTSS,
-	"SHUFPD",	LTYPEX,	ASHUFPD,
-	"SHUFPS",	LTYPEX,	ASHUFPS,
-	"SQRTPD",	LTYPE3,	ASQRTPD,
-	"SQRTPS",	LTYPE3,	ASQRTPS,
-	"SQRTSD",	LTYPE3,	ASQRTSD,
-	"SQRTSS",	LTYPE3,	ASQRTSS,
-	"STMXCSR",	LTYPE1,	ASTMXCSR,
-	"SUBPD",	LTYPE3,	ASUBPD,
-	"SUBPS",	LTYPE3,	ASUBPS,
-	"SUBSD",	LTYPE3,	ASUBSD,
-	"SUBSS",	LTYPE3,	ASUBSS,
-	"UCOMISD",	LTYPE3,	AUCOMISD,
-	"UCOMISS",	LTYPE3,	AUCOMISS,
-	"UNPCKHPD",	LTYPE3,	AUNPCKHPD,
-	"UNPCKHPS",	LTYPE3,	AUNPCKHPS,
-	"UNPCKLPD",	LTYPE3,	AUNPCKLPD,
-	"UNPCKLPS",	LTYPE3,	AUNPCKLPS,
-	"XORPD",	LTYPE3,	AXORPD,
-	"XORPS",	LTYPE3,	AXORPS,
-	"CRC32B",	LTYPE4, ACRC32B,
-	"CRC32Q",	LTYPE4, ACRC32Q,
-	"PREFETCHT0",		LTYPE2,	APREFETCHT0,
-	"PREFETCHT1",		LTYPE2,	APREFETCHT1,
-	"PREFETCHT2",		LTYPE2,	APREFETCHT2,
-	"PREFETCHNTA",		LTYPE2,	APREFETCHNTA,
-	"UNDEF",	LTYPE0,	AUNDEF,
-	"AESENC",	LTYPE3,	AAESENC,
-	"AESENCLAST",	LTYPE3, AAESENCLAST,
-	"AESDEC",	LTYPE3, AAESDEC,
-	"AESDECLAST",	LTYPE3, AAESDECLAST,
-	"AESIMC",	LTYPE3, AAESIMC,
-	"AESKEYGENASSIST", LTYPEX, AAESKEYGENASSIST,
-	"PSHUFD",	LTYPEX, APSHUFD,
-	"USEFIELD",	LTYPEN, AUSEFIELD,
-	"PCLMULQDQ",	LTYPEX, APCLMULQDQ,
-	"PCDATA",	LTYPEPC,	APCDATA,
-	"FUNCDATA",	LTYPEF,	AFUNCDATA,
-	0
-};
-
-void
-cinit(void)
-{
-	Sym *s;
-	int i;
-
-	nullgen.type = D_NONE;
-	nullgen.index = D_NONE;
-
-	nerrors = 0;
-	iostack = I;
-	iofree = I;
-	peekc = IGN;
-	nhunk = 0;
-	for(i=0; i<NHASH; i++)
-		hash[i] = S;
-	for(i=0; itab[i].name; i++) {
-		s = slookup(itab[i].name);
-		if(s->type != LNAME)
-			yyerror("double initialization %s", itab[i].name);
-		s->type = itab[i].type;
-		s->value = itab[i].value;
-	}
-}
-
-void
-checkscale(int scale)
-{
-
-	switch(scale) {
-	case 1:
-	case 2:
-	case 4:
-	case 8:
-		return;
-	}
-	yyerror("scale must be 1248: %d", scale);
-}
-
-void
-syminit(Sym *s)
-{
-
-	s->type = LNAME;
-	s->value = 0;
-}
-
-void
-cclean(void)
-{
-	Addr2 g2;
-
-	g2.from = nullgen;
-	g2.to = nullgen;
-	outcode(AEND, &g2);
-}
-
-static Prog *lastpc;
-
-void
-outcode(int a, Addr2 *g2)
-{
-	Prog *p;
-	Plist *pl;
-	
-	if(pass == 1)
-		goto out;
-
-	p = malloc(sizeof *p);
-	memset(p, 0, sizeof *p);
-	p->as = a;
-	p->lineno = stmtline;
-	p->from = g2->from;
-	p->to = g2->to;
-	p->pc = pc;
-
-	if(lastpc == nil) {
-		pl = linknewplist(ctxt);
-		pl->firstpc = p;
-	} else
-		lastpc->link = p;
-	lastpc = p;	
-
-out:
-	if(a != AGLOBL && a != ADATA)
-		pc++;
-}
-
-#include "../cc/lexbody"
-#include "../cc/macbody"
diff --git a/src/cmd/6a/y.tab.c b/src/cmd/6a/y.tab.c
deleted file mode 100644
index b69fd95..0000000
--- a/src/cmd/6a/y.tab.c
+++ /dev/null
@@ -1,2801 +0,0 @@
-/* A Bison parser, made by GNU Bison 2.3.  */
-
-/* Skeleton implementation for Bison's Yacc-like parsers in C
-
-   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
-   Free Software Foundation, Inc.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
-   any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301, USA.  */
-
-/* As a special exception, you may create a larger work that contains
-   part or all of the Bison parser skeleton and distribute that work
-   under terms of your choice, so long as that work isn't itself a
-   parser generator using the skeleton or a modified version thereof
-   as a parser skeleton.  Alternatively, if you modify or redistribute
-   the parser skeleton itself, you may (at your option) remove this
-   special exception, which will cause the skeleton and the resulting
-   Bison output files to be licensed under the GNU General Public
-   License without this special exception.
-
-   This special exception was added by the Free Software Foundation in
-   version 2.2 of Bison.  */
-
-/* C LALR(1) parser skeleton written by Richard Stallman, by
-   simplifying the original so-called "semantic" parser.  */
-
-/* All symbols defined below should begin with yy or YY, to avoid
-   infringing on user name space.  This should be done even for local
-   variables, as they might otherwise be expanded by user macros.
-   There are some unavoidable exceptions within include files to
-   define necessary library symbols; they are noted "INFRINGES ON
-   USER NAME SPACE" below.  */
-
-/* Identify Bison output.  */
-#define YYBISON 1
-
-/* Bison version.  */
-#define YYBISON_VERSION "2.3"
-
-/* Skeleton name.  */
-#define YYSKELETON_NAME "yacc.c"
-
-/* Pure parsers.  */
-#define YYPURE 0
-
-/* Using locations.  */
-#define YYLSP_NEEDED 0
-
-
-
-/* Tokens.  */
-#ifndef YYTOKENTYPE
-# define YYTOKENTYPE
-   /* Put the tokens into the symbol table, so that GDB and other debuggers
-      know about them.  */
-   enum yytokentype {
-     LTYPE0 = 258,
-     LTYPE1 = 259,
-     LTYPE2 = 260,
-     LTYPE3 = 261,
-     LTYPE4 = 262,
-     LTYPEC = 263,
-     LTYPED = 264,
-     LTYPEN = 265,
-     LTYPER = 266,
-     LTYPET = 267,
-     LTYPEG = 268,
-     LTYPEPC = 269,
-     LTYPES = 270,
-     LTYPEM = 271,
-     LTYPEI = 272,
-     LTYPEXC = 273,
-     LTYPEX = 274,
-     LTYPERT = 275,
-     LTYPEF = 276,
-     LCONST = 277,
-     LFP = 278,
-     LPC = 279,
-     LSB = 280,
-     LBREG = 281,
-     LLREG = 282,
-     LSREG = 283,
-     LFREG = 284,
-     LMREG = 285,
-     LXREG = 286,
-     LFCONST = 287,
-     LSCONST = 288,
-     LSP = 289,
-     LNAME = 290,
-     LLAB = 291,
-     LVAR = 292
-   };
-#endif
-/* Tokens.  */
-#define LTYPE0 258
-#define LTYPE1 259
-#define LTYPE2 260
-#define LTYPE3 261
-#define LTYPE4 262
-#define LTYPEC 263
-#define LTYPED 264
-#define LTYPEN 265
-#define LTYPER 266
-#define LTYPET 267
-#define LTYPEG 268
-#define LTYPEPC 269
-#define LTYPES 270
-#define LTYPEM 271
-#define LTYPEI 272
-#define LTYPEXC 273
-#define LTYPEX 274
-#define LTYPERT 275
-#define LTYPEF 276
-#define LCONST 277
-#define LFP 278
-#define LPC 279
-#define LSB 280
-#define LBREG 281
-#define LLREG 282
-#define LSREG 283
-#define LFREG 284
-#define LMREG 285
-#define LXREG 286
-#define LFCONST 287
-#define LSCONST 288
-#define LSP 289
-#define LNAME 290
-#define LLAB 291
-#define LVAR 292
-
-
-
-
-/* Copy the first part of user declarations.  */
-#line 31 "a.y"
-
-#include <u.h>
-#include <stdio.h>	/* if we don't, bison will, and a.h re-#defines getc */
-#include <libc.h>
-#include "a.h"
-#include "../../runtime/funcdata.h"
-
-
-/* Enabling traces.  */
-#ifndef YYDEBUG
-# define YYDEBUG 0
-#endif
-
-/* Enabling verbose error messages.  */
-#ifdef YYERROR_VERBOSE
-# undef YYERROR_VERBOSE
-# define YYERROR_VERBOSE 1
-#else
-# define YYERROR_VERBOSE 0
-#endif
-
-/* Enabling the token table.  */
-#ifndef YYTOKEN_TABLE
-# define YYTOKEN_TABLE 0
-#endif
-
-#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-typedef union YYSTYPE
-#line 38 "a.y"
-{
-	Sym	*sym;
-	vlong	lval;
-	double	dval;
-	char	sval[8];
-	Addr	addr;
-	Addr2	addr2;
-}
-/* Line 193 of yacc.c.  */
-#line 187 "y.tab.c"
-	YYSTYPE;
-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
-# define YYSTYPE_IS_DECLARED 1
-# define YYSTYPE_IS_TRIVIAL 1
-#endif
-
-
-
-/* Copy the second part of user declarations.  */
-
-
-/* Line 216 of yacc.c.  */
-#line 200 "y.tab.c"
-
-#ifdef short
-# undef short
-#endif
-
-#ifdef YYTYPE_UINT8
-typedef YYTYPE_UINT8 yytype_uint8;
-#else
-typedef unsigned char yytype_uint8;
-#endif
-
-#ifdef YYTYPE_INT8
-typedef YYTYPE_INT8 yytype_int8;
-#elif (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-typedef signed char yytype_int8;
-#else
-typedef short int yytype_int8;
-#endif
-
-#ifdef YYTYPE_UINT16
-typedef YYTYPE_UINT16 yytype_uint16;
-#else
-typedef unsigned short int yytype_uint16;
-#endif
-
-#ifdef YYTYPE_INT16
-typedef YYTYPE_INT16 yytype_int16;
-#else
-typedef short int yytype_int16;
-#endif
-
-#ifndef YYSIZE_T
-# ifdef __SIZE_TYPE__
-#  define YYSIZE_T __SIZE_TYPE__
-# elif defined size_t
-#  define YYSIZE_T size_t
-# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
-#  define YYSIZE_T size_t
-# else
-#  define YYSIZE_T unsigned int
-# endif
-#endif
-
-#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
-
-#ifndef YY_
-# if defined YYENABLE_NLS && YYENABLE_NLS
-#  if ENABLE_NLS
-#   include <libintl.h> /* INFRINGES ON USER NAME SPACE */
-#   define YY_(msgid) dgettext ("bison-runtime", msgid)
-#  endif
-# endif
-# ifndef YY_
-#  define YY_(msgid) msgid
-# endif
-#endif
-
-/* Suppress unused-variable warnings by "using" E.  */
-#if ! defined lint || defined __GNUC__
-# define YYUSE(e) ((void) (e))
-#else
-# define YYUSE(e) /* empty */
-#endif
-
-/* Identity function, used to suppress warnings about constant conditions.  */
-#ifndef lint
-# define YYID(n) (n)
-#else
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static int
-YYID (int i)
-#else
-static int
-YYID (i)
-    int i;
-#endif
-{
-  return i;
-}
-#endif
-
-#if ! defined yyoverflow || YYERROR_VERBOSE
-
-/* The parser invokes alloca or malloc; define the necessary symbols.  */
-
-# ifdef YYSTACK_USE_ALLOCA
-#  if YYSTACK_USE_ALLOCA
-#   ifdef __GNUC__
-#    define YYSTACK_ALLOC __builtin_alloca
-#   elif defined __BUILTIN_VA_ARG_INCR
-#    include <alloca.h> /* INFRINGES ON USER NAME SPACE */
-#   elif defined _AIX
-#    define YYSTACK_ALLOC __alloca
-#   elif defined _MSC_VER
-#    include <malloc.h> /* INFRINGES ON USER NAME SPACE */
-#    define alloca _alloca
-#   else
-#    define YYSTACK_ALLOC alloca
-#    if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-#     include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-#     ifndef _STDLIB_H
-#      define _STDLIB_H 1
-#     endif
-#    endif
-#   endif
-#  endif
-# endif
-
-# ifdef YYSTACK_ALLOC
-   /* Pacify GCC's `empty if-body' warning.  */
-#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
-#  ifndef YYSTACK_ALLOC_MAXIMUM
-    /* The OS might guarantee only one guard page at the bottom of the stack,
-       and a page size can be as small as 4096 bytes.  So we cannot safely
-       invoke alloca (N) if N exceeds 4096.  Use a slightly smaller number
-       to allow for a few compiler-allocated temporary stack slots.  */
-#   define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
-#  endif
-# else
-#  define YYSTACK_ALLOC YYMALLOC
-#  define YYSTACK_FREE YYFREE
-#  ifndef YYSTACK_ALLOC_MAXIMUM
-#   define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
-#  endif
-#  if (defined __cplusplus && ! defined _STDLIB_H \
-       && ! ((defined YYMALLOC || defined malloc) \
-	     && (defined YYFREE || defined free)))
-#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-#   ifndef _STDLIB_H
-#    define _STDLIB_H 1
-#   endif
-#  endif
-#  ifndef YYMALLOC
-#   define YYMALLOC malloc
-#   if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
-#   endif
-#  endif
-#  ifndef YYFREE
-#   define YYFREE free
-#   if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-void free (void *); /* INFRINGES ON USER NAME SPACE */
-#   endif
-#  endif
-# endif
-#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
-
-
-#if (! defined yyoverflow \
-     && (! defined __cplusplus \
-	 || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
-
-/* A type that is properly aligned for any stack member.  */
-union yyalloc
-{
-  yytype_int16 yyss;
-  YYSTYPE yyvs;
-  };
-
-/* The size of the maximum gap between one aligned stack and the next.  */
-# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
-
-/* The size of an array large to enough to hold all stacks, each with
-   N elements.  */
-# define YYSTACK_BYTES(N) \
-     ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
-      + YYSTACK_GAP_MAXIMUM)
-
-/* Copy COUNT objects from FROM to TO.  The source and destination do
-   not overlap.  */
-# ifndef YYCOPY
-#  if defined __GNUC__ && 1 < __GNUC__
-#   define YYCOPY(To, From, Count) \
-      __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
-#  else
-#   define YYCOPY(To, From, Count)		\
-      do					\
-	{					\
-	  YYSIZE_T yyi;				\
-	  for (yyi = 0; yyi < (Count); yyi++)	\
-	    (To)[yyi] = (From)[yyi];		\
-	}					\
-      while (YYID (0))
-#  endif
-# endif
-
-/* Relocate STACK from its old location to the new one.  The
-   local variables YYSIZE and YYSTACKSIZE give the old and new number of
-   elements in the stack, and YYPTR gives the new location of the
-   stack.  Advance YYPTR to a properly aligned location for the next
-   stack.  */
-# define YYSTACK_RELOCATE(Stack)					\
-    do									\
-      {									\
-	YYSIZE_T yynewbytes;						\
-	YYCOPY (&yyptr->Stack, Stack, yysize);				\
-	Stack = &yyptr->Stack;						\
-	yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
-	yyptr += yynewbytes / sizeof (*yyptr);				\
-      }									\
-    while (YYID (0))
-
-#endif
-
-/* YYFINAL -- State number of the termination state.  */
-#define YYFINAL  2
-/* YYLAST -- Last index in YYTABLE.  */
-#define YYLAST   560
-
-/* YYNTOKENS -- Number of terminals.  */
-#define YYNTOKENS  56
-/* YYNNTS -- Number of nonterminals.  */
-#define YYNNTS  42
-/* YYNRULES -- Number of rules.  */
-#define YYNRULES  137
-/* YYNRULES -- Number of states.  */
-#define YYNSTATES  277
-
-/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
-#define YYUNDEFTOK  2
-#define YYMAXUTOK   292
-
-#define YYTRANSLATE(YYX)						\
-  ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
-
-/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX.  */
-static const yytype_uint8 yytranslate[] =
-{
-       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,    54,    12,     5,     2,
-      52,    53,    10,     8,    51,     9,     2,    11,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,    48,    49,
-       6,    50,     7,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     4,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     3,     2,    55,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     1,     2,    13,    14,
-      15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
-      25,    26,    27,    28,    29,    30,    31,    32,    33,    34,
-      35,    36,    37,    38,    39,    40,    41,    42,    43,    44,
-      45,    46,    47
-};
-
-#if YYDEBUG
-/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
-   YYRHS.  */
-static const yytype_uint16 yyprhs[] =
-{
-       0,     0,     3,     4,     5,     9,    10,    15,    16,    21,
-      23,    26,    29,    33,    37,    40,    43,    46,    49,    52,
-      55,    58,    61,    64,    67,    70,    73,    76,    79,    82,
-      85,    88,    91,    94,    95,    97,   101,   105,   108,   110,
-     113,   115,   118,   120,   124,   130,   134,   140,   143,   145,
-     147,   149,   153,   159,   163,   169,   172,   174,   178,   184,
-     190,   191,   193,   197,   203,   207,   211,   213,   215,   217,
-     219,   222,   225,   227,   229,   231,   233,   238,   241,   244,
-     246,   248,   250,   252,   254,   256,   258,   261,   264,   267,
-     270,   273,   278,   284,   288,   290,   292,   294,   299,   304,
-     309,   316,   326,   336,   340,   344,   350,   359,   361,   368,
-     374,   382,   383,   386,   389,   391,   393,   395,   397,   399,
-     402,   405,   408,   412,   414,   417,   421,   426,   428,   432,
-     436,   440,   444,   448,   453,   458,   462,   466
-};
-
-/* YYRHS -- A `-1'-separated list of the rules' RHS.  */
-static const yytype_int8 yyrhs[] =
-{
-      57,     0,    -1,    -1,    -1,    57,    58,    59,    -1,    -1,
-      46,    48,    60,    59,    -1,    -1,    45,    48,    61,    59,
-      -1,    49,    -1,    62,    49,    -1,     1,    49,    -1,    45,
-      50,    97,    -1,    47,    50,    97,    -1,    13,    63,    -1,
-      14,    67,    -1,    15,    66,    -1,    16,    64,    -1,    17,
-      65,    -1,    21,    68,    -1,    19,    69,    -1,    22,    70,
-      -1,    18,    71,    -1,    20,    72,    -1,    25,    73,    -1,
-      26,    74,    -1,    27,    75,    -1,    28,    76,    -1,    29,
-      77,    -1,    30,    78,    -1,    23,    79,    -1,    24,    80,
-      -1,    31,    81,    -1,    -1,    51,    -1,    84,    51,    82,
-      -1,    82,    51,    84,    -1,    84,    51,    -1,    84,    -1,
-      51,    82,    -1,    82,    -1,    51,    85,    -1,    85,    -1,
-      88,    51,    85,    -1,    92,    11,    95,    51,    88,    -1,
-      89,    51,    87,    -1,    89,    51,    95,    51,    87,    -1,
-      51,    83,    -1,    83,    -1,    63,    -1,    67,    -1,    84,
-      51,    82,    -1,    84,    51,    82,    48,    37,    -1,    84,
-      51,    82,    -1,    84,    51,    82,    48,    38,    -1,    84,
-      51,    -1,    84,    -1,    84,    51,    82,    -1,    86,    51,
-      82,    51,    95,    -1,    88,    51,    82,    51,    86,    -1,
-      -1,    88,    -1,    89,    51,    88,    -1,    89,    51,    95,
-      51,    88,    -1,    84,    51,    84,    -1,    84,    51,    84,
-      -1,    86,    -1,    89,    -1,    85,    -1,    91,    -1,    10,
-      86,    -1,    10,    90,    -1,    86,    -1,    90,    -1,    82,
-      -1,    88,    -1,    95,    52,    34,    53,    -1,    45,    93,
-      -1,    46,    93,    -1,    36,    -1,    39,    -1,    37,    -1,
-      40,    -1,    44,    -1,    38,    -1,    41,    -1,    54,    96,
-      -1,    54,    95,    -1,    54,    92,    -1,    54,    43,    -1,
-      54,    42,    -1,    54,    52,    42,    53,    -1,    54,    52,
-       9,    42,    53,    -1,    54,     9,    42,    -1,    90,    -1,
-      91,    -1,    95,    -1,    95,    52,    37,    53,    -1,    95,
-      52,    44,    53,    -1,    95,    52,    38,    53,    -1,    95,
-      52,    37,    10,    95,    53,    -1,    95,    52,    37,    53,
-      52,    37,    10,    95,    53,    -1,    95,    52,    37,    53,
-      52,    38,    10,    95,    53,    -1,    52,    37,    53,    -1,
-      52,    44,    53,    -1,    52,    37,    10,    95,    53,    -1,
-      52,    37,    53,    52,    37,    10,    95,    53,    -1,    92,
-      -1,    92,    52,    37,    10,    95,    53,    -1,    45,    93,
-      52,    94,    53,    -1,    45,     6,     7,    93,    52,    35,
-      53,    -1,    -1,     8,    95,    -1,     9,    95,    -1,    35,
-      -1,    44,    -1,    33,    -1,    32,    -1,    47,    -1,     9,
-      95,    -1,     8,    95,    -1,    55,    95,    -1,    52,    97,
-      53,    -1,    32,    -1,     9,    32,    -1,    32,     9,    32,
-      -1,     9,    32,     9,    32,    -1,    95,    -1,    97,     8,
-      97,    -1,    97,     9,    97,    -1,    97,    10,    97,    -1,
-      97,    11,    97,    -1,    97,    12,    97,    -1,    97,     6,
-       6,    97,    -1,    97,     7,     7,    97,    -1,    97,     5,
-      97,    -1,    97,     4,    97,    -1,    97,     3,    97,    -1
-};
-
-/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
-static const yytype_uint16 yyrline[] =
-{
-       0,    66,    66,    68,    67,    75,    74,    82,    81,    87,
-      88,    89,    92,    97,   103,   104,   105,   106,   107,   108,
-     109,   110,   111,   112,   113,   114,   115,   116,   117,   118,
-     119,   120,   121,   124,   128,   135,   142,   149,   154,   161,
-     166,   173,   178,   183,   190,   198,   203,   211,   216,   223,
-     224,   227,   232,   242,   247,   257,   262,   267,   274,   282,
-     292,   296,   303,   308,   316,   325,   336,   337,   340,   341,
-     342,   346,   350,   351,   354,   355,   358,   364,   372,   380,
-     385,   390,   395,   400,   405,   410,   416,   424,   430,   441,
-     447,   453,   459,   465,   473,   474,   477,   483,   489,   495,
-     501,   510,   519,   528,   533,   538,   546,   556,   560,   569,
-     576,   585,   588,   592,   598,   599,   603,   606,   607,   611,
-     615,   619,   623,   629,   634,   639,   644,   651,   652,   656,
-     660,   664,   668,   672,   676,   680,   684,   688
-};
-#endif
-
-#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
-/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
-   First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
-static const char *const yytname[] =
-{
-  "$end", "error", "$undefined", "'|'", "'^'", "'&'", "'<'", "'>'", "'+'",
-  "'-'", "'*'", "'/'", "'%'", "LTYPE0", "LTYPE1", "LTYPE2", "LTYPE3",
-  "LTYPE4", "LTYPEC", "LTYPED", "LTYPEN", "LTYPER", "LTYPET", "LTYPEG",
-  "LTYPEPC", "LTYPES", "LTYPEM", "LTYPEI", "LTYPEXC", "LTYPEX", "LTYPERT",
-  "LTYPEF", "LCONST", "LFP", "LPC", "LSB", "LBREG", "LLREG", "LSREG",
-  "LFREG", "LMREG", "LXREG", "LFCONST", "LSCONST", "LSP", "LNAME", "LLAB",
-  "LVAR", "':'", "';'", "'='", "','", "'('", "')'", "'$'", "'~'",
-  "$accept", "prog", "@1", "line", "@2", "@3", "inst", "nonnon", "rimrem",
-  "remrim", "rimnon", "nonrem", "nonrel", "spec1", "spec2", "spec3",
-  "spec4", "spec5", "spec6", "spec7", "spec8", "spec9", "spec10", "spec11",
-  "spec12", "spec13", "rem", "rom", "rim", "rel", "reg", "imm2", "imm",
-  "mem", "omem", "nmem", "nam", "offset", "pointer", "con", "con2", "expr", 0
-};
-#endif
-
-# ifdef YYPRINT
-/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
-   token YYLEX-NUM.  */
-static const yytype_uint16 yytoknum[] =
-{
-       0,   256,   257,   124,    94,    38,    60,    62,    43,    45,
-      42,    47,    37,   258,   259,   260,   261,   262,   263,   264,
-     265,   266,   267,   268,   269,   270,   271,   272,   273,   274,
-     275,   276,   277,   278,   279,   280,   281,   282,   283,   284,
-     285,   286,   287,   288,   289,   290,   291,   292,    58,    59,
-      61,    44,    40,    41,    36,   126
-};
-# endif
-
-/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
-static const yytype_uint8 yyr1[] =
-{
-       0,    56,    57,    58,    57,    60,    59,    61,    59,    59,
-      59,    59,    62,    62,    62,    62,    62,    62,    62,    62,
-      62,    62,    62,    62,    62,    62,    62,    62,    62,    62,
-      62,    62,    62,    63,    63,    64,    65,    66,    66,    67,
-      67,    68,    68,    68,    69,    70,    70,    71,    71,    72,
-      72,    73,    73,    74,    74,    75,    75,    75,    76,    77,
-      78,    78,    79,    79,    80,    81,    82,    82,    83,    83,
-      83,    83,    83,    83,    84,    84,    85,    85,    85,    86,
-      86,    86,    86,    86,    86,    86,    87,    88,    88,    88,
-      88,    88,    88,    88,    89,    89,    90,    90,    90,    90,
-      90,    90,    90,    90,    90,    90,    90,    91,    91,    92,
-      92,    93,    93,    93,    94,    94,    94,    95,    95,    95,
-      95,    95,    95,    96,    96,    96,    96,    97,    97,    97,
-      97,    97,    97,    97,    97,    97,    97,    97
-};
-
-/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
-static const yytype_uint8 yyr2[] =
-{
-       0,     2,     0,     0,     3,     0,     4,     0,     4,     1,
-       2,     2,     3,     3,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     0,     1,     3,     3,     2,     1,     2,
-       1,     2,     1,     3,     5,     3,     5,     2,     1,     1,
-       1,     3,     5,     3,     5,     2,     1,     3,     5,     5,
-       0,     1,     3,     5,     3,     3,     1,     1,     1,     1,
-       2,     2,     1,     1,     1,     1,     4,     2,     2,     1,
-       1,     1,     1,     1,     1,     1,     2,     2,     2,     2,
-       2,     4,     5,     3,     1,     1,     1,     4,     4,     4,
-       6,     9,     9,     3,     3,     5,     8,     1,     6,     5,
-       7,     0,     2,     2,     1,     1,     1,     1,     1,     2,
-       2,     2,     3,     1,     2,     3,     4,     1,     3,     3,
-       3,     3,     3,     4,     4,     3,     3,     3
-};
-
-/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
-   STATE-NUM when YYTABLE doesn't specify something else to do.  Zero
-   means the default is an error.  */
-static const yytype_uint8 yydefact[] =
-{
-       2,     3,     1,     0,     0,    33,     0,     0,     0,     0,
-       0,     0,    33,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,    60,     0,     0,     0,     0,     9,     4,     0,
-      11,    34,    14,     0,     0,   117,    79,    81,    84,    80,
-      82,    85,    83,   111,   118,     0,     0,     0,    15,    40,
-      66,    67,    94,    95,   107,    96,     0,    16,    74,    38,
-      75,    17,     0,    18,     0,     0,   111,   111,     0,    22,
-      48,    68,    72,    73,    69,    96,    20,     0,    34,    49,
-      50,    23,   111,     0,     0,    19,    42,     0,     0,    21,
-       0,    30,     0,    31,     0,    24,     0,    25,     0,    26,
-      56,    27,     0,    28,     0,    29,    61,    32,     0,     7,
-       0,     5,     0,    10,   120,   119,     0,     0,     0,     0,
-      39,     0,     0,   127,     0,   121,     0,     0,     0,    90,
-      89,     0,    88,    87,    37,     0,     0,    70,    71,    77,
-      78,    47,     0,     0,    77,    41,     0,     0,     0,     0,
-       0,     0,     0,    55,     0,     0,     0,     0,    12,     0,
-      13,   111,   112,   113,     0,     0,   103,   104,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,   122,     0,
-       0,     0,     0,    93,     0,     0,    35,    36,     0,     0,
-      43,     0,    45,     0,    62,     0,    64,    51,    53,    57,
-       0,     0,    65,     8,     6,     0,   116,   114,   115,     0,
-       0,     0,   137,   136,   135,     0,     0,   128,   129,   130,
-     131,   132,     0,     0,    97,    99,    98,     0,    91,    76,
-       0,     0,   123,    86,     0,     0,     0,     0,     0,     0,
-       0,   109,   105,     0,   133,   134,     0,     0,     0,    92,
-      44,   124,     0,    46,    63,    52,    54,    58,    59,     0,
-       0,   108,   100,     0,     0,     0,   125,   110,     0,     0,
-       0,   126,   106,     0,     0,   101,   102
-};
-
-/* YYDEFGOTO[NTERM-NUM].  */
-static const yytype_int16 yydefgoto[] =
-{
-      -1,     1,     3,    28,   159,   157,    29,    32,    61,    63,
-      57,    48,    85,    76,    89,    69,    81,    95,    97,    99,
-     101,   103,   105,    91,    93,   107,    58,    70,    59,    71,
-      50,   192,    60,    51,    52,    53,    54,   119,   209,    55,
-     233,   124
-};
-
-/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
-   STATE-NUM.  */
-#define YYPACT_NINF -94
-static const yytype_int16 yypact[] =
-{
-     -94,    15,   -94,   218,   -28,   -25,   264,   285,   285,   340,
-     163,     2,   319,    97,   415,   415,   285,   285,   285,   285,
-     306,   -24,   -24,   285,   -17,   -14,     4,   -94,   -94,    48,
-     -94,   -94,   -94,   481,   481,   -94,   -94,   -94,   -94,   -94,
-     -94,   -94,   -94,    19,   -94,   340,   399,   481,   -94,   -94,
-     -94,   -94,   -94,   -94,    46,    47,   385,   -94,   -94,    52,
-     -94,   -94,    59,   -94,    60,   374,    19,    56,   243,   -94,
-     -94,   -94,   -94,   -94,   -94,    63,   -94,   106,   340,   -94,
-     -94,   -94,    56,   138,   481,   -94,   -94,    69,    72,   -94,
-      74,   -94,    76,   -94,    77,   -94,    79,   -94,    80,   -94,
-      81,   -94,    83,   -94,    89,   -94,   -94,   -94,    94,   -94,
-     481,   -94,   481,   -94,   -94,   -94,   119,   481,   481,    98,
-     -94,    -1,   100,   -94,    84,   -94,   117,    23,   426,   -94,
-     -94,   433,   -94,   -94,   -94,   340,   285,   -94,   -94,    98,
-     -94,   -94,    75,   481,   -94,   -94,   138,   122,   440,   444,
-     285,   340,   340,   340,   340,   340,   285,   218,   393,   218,
-     393,    56,   -94,   -94,   -15,   481,   105,   -94,   481,   481,
-     481,   156,   162,   481,   481,   481,   481,   481,   -94,   165,
-       0,   123,   133,   -94,   474,   134,   -94,   -94,   136,   140,
-     -94,     7,   -94,   141,   -94,   143,   -94,   148,   149,   -94,
-     147,   160,   -94,   -94,   -94,   164,   -94,   -94,   -94,   167,
-     168,   180,   533,   541,   548,   481,   481,    58,    58,   -94,
-     -94,   -94,   481,   481,   171,   -94,   -94,   172,   -94,   -94,
-     -24,   192,   217,   -94,   175,   -24,   219,   216,   481,   306,
-     220,   -94,   -94,   247,    33,    33,   205,   208,    41,   -94,
-     -94,   253,   234,   -94,   -94,   -94,   -94,   -94,   -94,   215,
-     481,   -94,   -94,   259,   260,   239,   -94,   -94,   221,   481,
-     481,   -94,   -94,   223,   224,   -94,   -94
-};
-
-/* YYPGOTO[NTERM-NUM].  */
-static const yytype_int16 yypgoto[] =
-{
-     -94,   -94,   -94,   -43,   -94,   -94,   -94,   266,   -94,   -94,
-     -94,   273,   -94,   -94,   -94,   -94,   -94,   -94,   -94,   -94,
-     -94,   -94,   -94,   -94,   -94,   -94,    26,   229,    32,   -11,
-      -9,    57,    -8,    71,    -2,    -6,     1,   -60,   -94,   -10,
-     -94,   -93
-};
-
-/* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
-   positive, shift that token.  If negative, reduce the rule which
-   number is the opposite.  If zero, do what YYDEFACT says.
-   If YYTABLE_NINF, syntax error.  */
-#define YYTABLE_NINF -1
-static const yytype_uint16 yytable[] =
-{
-      75,    72,    86,    88,    74,    87,   139,   140,    73,   165,
-     223,   102,    77,   104,   106,     2,   231,   158,   206,   160,
-     207,    30,   144,   114,   115,   116,    31,   117,   118,   208,
-      56,   109,    49,   110,   111,    64,   123,   125,    49,   232,
-      62,   173,   174,   175,   176,   177,   133,    43,    94,    96,
-      98,   100,   166,   224,   112,   108,   137,   132,    75,    72,
-     180,   181,    74,   138,   117,   118,    73,   182,   175,   176,
-     177,   120,   145,    88,   123,   212,   213,   214,   263,   264,
-     217,   218,   219,   220,   221,    90,    92,   168,   169,   170,
-     171,   172,   173,   174,   175,   176,   177,   113,   126,   127,
-     123,   205,   123,   134,   120,    33,    34,   162,   163,   188,
-     135,   136,   180,   181,   203,   142,   204,   143,   115,   182,
-     146,   123,   244,   245,   147,   148,   161,   149,   150,    35,
-     151,   152,   153,   189,   154,   190,    88,   178,   193,   195,
-     155,   194,    82,    67,    44,   156,    33,    34,    83,    84,
-     164,    56,    47,   167,   179,   210,   188,   211,   123,   123,
-     123,   186,   215,   123,   123,   123,   123,   123,   187,   216,
-      35,    33,    34,    65,   115,   222,   225,   197,   198,   199,
-     200,   201,   196,    82,    67,    44,   226,   228,   202,   229,
-      84,   230,   234,    47,   235,    35,   236,   237,   238,    36,
-      37,    38,    39,    40,    41,   123,   123,    42,    66,    67,
-      44,   239,   246,   247,    68,    46,   240,   243,    47,     4,
-     241,   242,   250,   248,   251,   249,   252,   254,   257,   191,
-     258,     5,     6,     7,     8,     9,    10,    11,    12,    13,
-      14,    15,    16,    17,    18,    19,    20,    21,    22,    23,
-     268,    33,    34,    65,   256,   259,   255,   260,   261,   273,
-     274,   262,   265,    24,    25,    26,   266,    27,   267,   269,
-     270,   271,    33,    34,   272,    35,   275,   276,    79,    36,
-      37,    38,    39,    40,    41,    80,     0,    42,    66,    67,
-      44,   253,     0,    33,    34,    46,    35,   141,    47,     0,
-      36,    37,    38,    39,    40,    41,     0,     0,    42,    43,
-       0,    44,     0,     0,     0,    45,    46,    35,     0,    47,
-       0,    36,    37,    38,    39,    40,    41,    33,    34,    42,
-      43,     0,    44,     0,     0,     0,     0,    46,     0,    56,
-      47,     0,    36,    37,    38,    39,    40,    41,    33,    34,
-      42,    35,     0,     0,     0,    36,    37,    38,    39,    40,
-      41,     0,     0,    42,    43,     0,    44,     0,     0,     0,
-      78,    46,    35,     0,    47,     0,    36,    37,    38,    39,
-      40,    41,    33,    34,    42,    43,     0,    44,     0,     0,
-       0,     0,    46,    33,   128,    47,   168,   169,   170,   171,
-     172,   173,   174,   175,   176,   177,    35,    33,    34,     0,
-      36,    37,    38,    39,    40,    41,     0,    35,    42,     0,
-       0,    44,     0,    33,    34,     0,    46,   129,   130,    47,
-      43,    35,    44,     0,    33,    34,   121,   131,     0,     0,
-      47,    33,   184,   122,     0,     0,    44,    35,    33,    34,
-       0,    84,    33,    34,    47,     0,     0,     0,    35,     0,
-      43,     0,    44,     0,     0,    35,     0,    46,   183,     0,
-      47,     0,    35,    44,     0,   185,    35,     0,    84,     0,
-      44,    47,    33,    34,     0,    84,     0,    44,    47,    33,
-      34,    44,    84,     0,   191,    47,    84,     0,    56,    47,
-       0,     0,     0,     0,     0,     0,    35,     0,     0,     0,
-       0,     0,     0,    35,     0,     0,   227,     0,     0,     0,
-       0,    44,     0,     0,     0,     0,    84,     0,    44,    47,
-       0,     0,     0,    84,     0,     0,    47,   169,   170,   171,
-     172,   173,   174,   175,   176,   177,   170,   171,   172,   173,
-     174,   175,   176,   177,   171,   172,   173,   174,   175,   176,
-     177
-};
-
-static const yytype_int16 yycheck[] =
-{
-      10,    10,    13,    13,    10,    13,    66,    67,    10,    10,
-      10,    20,    11,    21,    22,     0,     9,   110,    33,   112,
-      35,    49,    82,    33,    34,     6,    51,     8,     9,    44,
-      54,    48,     6,    50,    48,     9,    46,    47,    12,    32,
-       8,     8,     9,    10,    11,    12,    56,    45,    16,    17,
-      18,    19,    53,    53,    50,    23,    65,    56,    68,    68,
-      37,    38,    68,    65,     8,     9,    68,    44,    10,    11,
-      12,    45,    83,    83,    84,   168,   169,   170,    37,    38,
-     173,   174,   175,   176,   177,    14,    15,     3,     4,     5,
-       6,     7,     8,     9,    10,    11,    12,    49,    52,    52,
-     110,   161,   112,    51,    78,     8,     9,   117,   118,    34,
-      51,    51,    37,    38,   157,    52,   159,    11,   128,    44,
-      51,   131,   215,   216,    52,    51,     7,    51,    51,    32,
-      51,    51,    51,   143,    51,   146,   146,    53,   148,   149,
-      51,   149,    45,    46,    47,    51,     8,     9,    51,    52,
-      52,    54,    55,    53,    37,   165,    34,    52,   168,   169,
-     170,   135,     6,   173,   174,   175,   176,   177,   136,     7,
-      32,     8,     9,    10,   184,    10,    53,   151,   152,   153,
-     154,   155,   150,    45,    46,    47,    53,    53,   156,    53,
-      52,    51,    51,    55,    51,    32,    48,    48,    51,    36,
-      37,    38,    39,    40,    41,   215,   216,    44,    45,    46,
-      47,    51,   222,   223,    51,    52,    52,    37,    55,     1,
-      53,    53,   230,    52,    32,    53,     9,   235,   238,    54,
-     239,    13,    14,    15,    16,    17,    18,    19,    20,    21,
-      22,    23,    24,    25,    26,    27,    28,    29,    30,    31,
-     260,     8,     9,    10,    38,    35,    37,    10,    53,   269,
-     270,    53,     9,    45,    46,    47,    32,    49,    53,    10,
-      10,    32,     8,     9,    53,    32,    53,    53,    12,    36,
-      37,    38,    39,    40,    41,    12,    -1,    44,    45,    46,
-      47,   234,    -1,     8,     9,    52,    32,    68,    55,    -1,
-      36,    37,    38,    39,    40,    41,    -1,    -1,    44,    45,
-      -1,    47,    -1,    -1,    -1,    51,    52,    32,    -1,    55,
-      -1,    36,    37,    38,    39,    40,    41,     8,     9,    44,
-      45,    -1,    47,    -1,    -1,    -1,    -1,    52,    -1,    54,
-      55,    -1,    36,    37,    38,    39,    40,    41,     8,     9,
-      44,    32,    -1,    -1,    -1,    36,    37,    38,    39,    40,
-      41,    -1,    -1,    44,    45,    -1,    47,    -1,    -1,    -1,
-      51,    52,    32,    -1,    55,    -1,    36,    37,    38,    39,
-      40,    41,     8,     9,    44,    45,    -1,    47,    -1,    -1,
-      -1,    -1,    52,     8,     9,    55,     3,     4,     5,     6,
-       7,     8,     9,    10,    11,    12,    32,     8,     9,    -1,
-      36,    37,    38,    39,    40,    41,    -1,    32,    44,    -1,
-      -1,    47,    -1,     8,     9,    -1,    52,    42,    43,    55,
-      45,    32,    47,    -1,     8,     9,    37,    52,    -1,    -1,
-      55,     8,     9,    44,    -1,    -1,    47,    32,     8,     9,
-      -1,    52,     8,     9,    55,    -1,    -1,    -1,    32,    -1,
-      45,    -1,    47,    -1,    -1,    32,    -1,    52,    42,    -1,
-      55,    -1,    32,    47,    -1,    42,    32,    -1,    52,    -1,
-      47,    55,     8,     9,    -1,    52,    -1,    47,    55,     8,
-       9,    47,    52,    -1,    54,    55,    52,    -1,    54,    55,
-      -1,    -1,    -1,    -1,    -1,    -1,    32,    -1,    -1,    -1,
-      -1,    -1,    -1,    32,    -1,    -1,    42,    -1,    -1,    -1,
-      -1,    47,    -1,    -1,    -1,    -1,    52,    -1,    47,    55,
-      -1,    -1,    -1,    52,    -1,    -1,    55,     4,     5,     6,
-       7,     8,     9,    10,    11,    12,     5,     6,     7,     8,
-       9,    10,    11,    12,     6,     7,     8,     9,    10,    11,
-      12
-};
-
-/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
-   symbol of state STATE-NUM.  */
-static const yytype_uint8 yystos[] =
-{
-       0,    57,     0,    58,     1,    13,    14,    15,    16,    17,
-      18,    19,    20,    21,    22,    23,    24,    25,    26,    27,
-      28,    29,    30,    31,    45,    46,    47,    49,    59,    62,
-      49,    51,    63,     8,     9,    32,    36,    37,    38,    39,
-      40,    41,    44,    45,    47,    51,    52,    55,    67,    82,
-      86,    89,    90,    91,    92,    95,    54,    66,    82,    84,
-      88,    64,    84,    65,    82,    10,    45,    46,    51,    71,
-      83,    85,    86,    90,    91,    95,    69,    92,    51,    63,
-      67,    72,    45,    51,    52,    68,    85,    88,    95,    70,
-      89,    79,    89,    80,    84,    73,    84,    74,    84,    75,
-      84,    76,    86,    77,    88,    78,    88,    81,    84,    48,
-      50,    48,    50,    49,    95,    95,     6,     8,     9,    93,
-      82,    37,    44,    95,    97,    95,    52,    52,     9,    42,
-      43,    52,    92,    95,    51,    51,    51,    86,    90,    93,
-      93,    83,    52,    11,    93,    85,    51,    52,    51,    51,
-      51,    51,    51,    51,    51,    51,    51,    61,    97,    60,
-      97,     7,    95,    95,    52,    10,    53,    53,     3,     4,
-       5,     6,     7,     8,     9,    10,    11,    12,    53,    37,
-      37,    38,    44,    42,     9,    42,    82,    84,    34,    95,
-      85,    54,    87,    95,    88,    95,    84,    82,    82,    82,
-      82,    82,    84,    59,    59,    93,    33,    35,    44,    94,
-      95,    52,    97,    97,    97,     6,     7,    97,    97,    97,
-      97,    97,    10,    10,    53,    53,    53,    42,    53,    53,
-      51,     9,    32,    96,    51,    51,    48,    48,    51,    51,
-      52,    53,    53,    37,    97,    97,    95,    95,    52,    53,
-      88,    32,     9,    87,    88,    37,    38,    95,    86,    35,
-      10,    53,    53,    37,    38,     9,    32,    53,    95,    10,
-      10,    32,    53,    95,    95,    53,    53
-};
-
-#define yyerrok		(yyerrstatus = 0)
-#define yyclearin	(yychar = YYEMPTY)
-#define YYEMPTY		(-2)
-#define YYEOF		0
-
-#define YYACCEPT	goto yyacceptlab
-#define YYABORT		goto yyabortlab
-#define YYERROR		goto yyerrorlab
-
-
-/* Like YYERROR except do call yyerror.  This remains here temporarily
-   to ease the transition to the new meaning of YYERROR, for GCC.
-   Once GCC version 2 has supplanted version 1, this can go.  */
-
-#define YYFAIL		goto yyerrlab
-
-#define YYRECOVERING()  (!!yyerrstatus)
-
-#define YYBACKUP(Token, Value)					\
-do								\
-  if (yychar == YYEMPTY && yylen == 1)				\
-    {								\
-      yychar = (Token);						\
-      yylval = (Value);						\
-      yytoken = YYTRANSLATE (yychar);				\
-      YYPOPSTACK (1);						\
-      goto yybackup;						\
-    }								\
-  else								\
-    {								\
-      yyerror (YY_("syntax error: cannot back up")); \
-      YYERROR;							\
-    }								\
-while (YYID (0))
-
-
-#define YYTERROR	1
-#define YYERRCODE	256
-
-
-/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
-   If N is 0, then set CURRENT to the empty location which ends
-   the previous symbol: RHS[0] (always defined).  */
-
-#define YYRHSLOC(Rhs, K) ((Rhs)[K])
-#ifndef YYLLOC_DEFAULT
-# define YYLLOC_DEFAULT(Current, Rhs, N)				\
-    do									\
-      if (YYID (N))                                                    \
-	{								\
-	  (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;	\
-	  (Current).first_column = YYRHSLOC (Rhs, 1).first_column;	\
-	  (Current).last_line    = YYRHSLOC (Rhs, N).last_line;		\
-	  (Current).last_column  = YYRHSLOC (Rhs, N).last_column;	\
-	}								\
-      else								\
-	{								\
-	  (Current).first_line   = (Current).last_line   =		\
-	    YYRHSLOC (Rhs, 0).last_line;				\
-	  (Current).first_column = (Current).last_column =		\
-	    YYRHSLOC (Rhs, 0).last_column;				\
-	}								\
-    while (YYID (0))
-#endif
-
-
-/* YY_LOCATION_PRINT -- Print the location on the stream.
-   This macro was not mandated originally: define only if we know
-   we won't break user code: when these are the locations we know.  */
-
-#ifndef YY_LOCATION_PRINT
-# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
-#  define YY_LOCATION_PRINT(File, Loc)			\
-     fprintf (File, "%d.%d-%d.%d",			\
-	      (Loc).first_line, (Loc).first_column,	\
-	      (Loc).last_line,  (Loc).last_column)
-# else
-#  define YY_LOCATION_PRINT(File, Loc) ((void) 0)
-# endif
-#endif
-
-
-/* YYLEX -- calling `yylex' with the right arguments.  */
-
-#ifdef YYLEX_PARAM
-# define YYLEX yylex (YYLEX_PARAM)
-#else
-# define YYLEX yylex ()
-#endif
-
-/* Enable debugging if requested.  */
-#if YYDEBUG
-
-# ifndef YYFPRINTF
-#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
-#  define YYFPRINTF fprintf
-# endif
-
-# define YYDPRINTF(Args)			\
-do {						\
-  if (yydebug)					\
-    YYFPRINTF Args;				\
-} while (YYID (0))
-
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location)			  \
-do {									  \
-  if (yydebug)								  \
-    {									  \
-      YYFPRINTF (stderr, "%s ", Title);					  \
-      yy_symbol_print (stderr,						  \
-		  Type, Value); \
-      YYFPRINTF (stderr, "\n");						  \
-    }									  \
-} while (YYID (0))
-
-
-/*--------------------------------.
-| Print this symbol on YYOUTPUT.  |
-`--------------------------------*/
-
-/*ARGSUSED*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static void
-yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
-#else
-static void
-yy_symbol_value_print (yyoutput, yytype, yyvaluep)
-    FILE *yyoutput;
-    int yytype;
-    YYSTYPE const * const yyvaluep;
-#endif
-{
-  if (!yyvaluep)
-    return;
-# ifdef YYPRINT
-  if (yytype < YYNTOKENS)
-    YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
-# else
-  YYUSE (yyoutput);
-# endif
-  switch (yytype)
-    {
-      default:
-	break;
-    }
-}
-
-
-/*--------------------------------.
-| Print this symbol on YYOUTPUT.  |
-`--------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static void
-yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
-#else
-static void
-yy_symbol_print (yyoutput, yytype, yyvaluep)
-    FILE *yyoutput;
-    int yytype;
-    YYSTYPE const * const yyvaluep;
-#endif
-{
-  if (yytype < YYNTOKENS)
-    YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
-  else
-    YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
-
-  yy_symbol_value_print (yyoutput, yytype, yyvaluep);
-  YYFPRINTF (yyoutput, ")");
-}
-
-/*------------------------------------------------------------------.
-| yy_stack_print -- Print the state stack from its BOTTOM up to its |
-| TOP (included).                                                   |
-`------------------------------------------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static void
-yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
-#else
-static void
-yy_stack_print (bottom, top)
-    yytype_int16 *bottom;
-    yytype_int16 *top;
-#endif
-{
-  YYFPRINTF (stderr, "Stack now");
-  for (; bottom <= top; ++bottom)
-    YYFPRINTF (stderr, " %d", *bottom);
-  YYFPRINTF (stderr, "\n");
-}
-
-# define YY_STACK_PRINT(Bottom, Top)				\
-do {								\
-  if (yydebug)							\
-    yy_stack_print ((Bottom), (Top));				\
-} while (YYID (0))
-
-
-/*------------------------------------------------.
-| Report that the YYRULE is going to be reduced.  |
-`------------------------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static void
-yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
-#else
-static void
-yy_reduce_print (yyvsp, yyrule)
-    YYSTYPE *yyvsp;
-    int yyrule;
-#endif
-{
-  int yynrhs = yyr2[yyrule];
-  int yyi;
-  unsigned long int yylno = yyrline[yyrule];
-  YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
-	     yyrule - 1, yylno);
-  /* The symbols being reduced.  */
-  for (yyi = 0; yyi < yynrhs; yyi++)
-    {
-      fprintf (stderr, "   $%d = ", yyi + 1);
-      yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
-		       &(yyvsp[(yyi + 1) - (yynrhs)])
-		       		       );
-      fprintf (stderr, "\n");
-    }
-}
-
-# define YY_REDUCE_PRINT(Rule)		\
-do {					\
-  if (yydebug)				\
-    yy_reduce_print (yyvsp, Rule); \
-} while (YYID (0))
-
-/* Nonzero means print parse trace.  It is left uninitialized so that
-   multiple parsers can coexist.  */
-int yydebug;
-#else /* !YYDEBUG */
-# define YYDPRINTF(Args)
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
-# define YY_STACK_PRINT(Bottom, Top)
-# define YY_REDUCE_PRINT(Rule)
-#endif /* !YYDEBUG */
-
-
-/* YYINITDEPTH -- initial size of the parser's stacks.  */
-#ifndef	YYINITDEPTH
-# define YYINITDEPTH 200
-#endif
-
-/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
-   if the built-in stack extension method is used).
-
-   Do not make this value too large; the results are undefined if
-   YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
-   evaluated with infinite-precision integer arithmetic.  */
-
-#ifndef YYMAXDEPTH
-# define YYMAXDEPTH 10000
-#endif
-
-

-
-#if YYERROR_VERBOSE
-
-# ifndef yystrlen
-#  if defined __GLIBC__ && defined _STRING_H
-#   define yystrlen strlen
-#  else
-/* Return the length of YYSTR.  */
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static YYSIZE_T
-yystrlen (const char *yystr)
-#else
-static YYSIZE_T
-yystrlen (yystr)
-    const char *yystr;
-#endif
-{
-  YYSIZE_T yylen;
-  for (yylen = 0; yystr[yylen]; yylen++)
-    continue;
-  return yylen;
-}
-#  endif
-# endif
-
-# ifndef yystpcpy
-#  if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
-#   define yystpcpy stpcpy
-#  else
-/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
-   YYDEST.  */
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static char *
-yystpcpy (char *yydest, const char *yysrc)
-#else
-static char *
-yystpcpy (yydest, yysrc)
-    char *yydest;
-    const char *yysrc;
-#endif
-{
-  char *yyd = yydest;
-  const char *yys = yysrc;
-
-  while ((*yyd++ = *yys++) != '\0')
-    continue;
-
-  return yyd - 1;
-}
-#  endif
-# endif
-
-# ifndef yytnamerr
-/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
-   quotes and backslashes, so that it's suitable for yyerror.  The
-   heuristic is that double-quoting is unnecessary unless the string
-   contains an apostrophe, a comma, or backslash (other than
-   backslash-backslash).  YYSTR is taken from yytname.  If YYRES is
-   null, do not copy; instead, return the length of what the result
-   would have been.  */
-static YYSIZE_T
-yytnamerr (char *yyres, const char *yystr)
-{
-  if (*yystr == '"')
-    {
-      YYSIZE_T yyn = 0;
-      char const *yyp = yystr;
-
-      for (;;)
-	switch (*++yyp)
-	  {
-	  case '\'':
-	  case ',':
-	    goto do_not_strip_quotes;
-
-	  case '\\':
-	    if (*++yyp != '\\')
-	      goto do_not_strip_quotes;
-	    /* Fall through.  */
-	  default:
-	    if (yyres)
-	      yyres[yyn] = *yyp;
-	    yyn++;
-	    break;
-
-	  case '"':
-	    if (yyres)
-	      yyres[yyn] = '\0';
-	    return yyn;
-	  }
-    do_not_strip_quotes: ;
-    }
-
-  if (! yyres)
-    return yystrlen (yystr);
-
-  return yystpcpy (yyres, yystr) - yyres;
-}
-# endif
-
-/* Copy into YYRESULT an error message about the unexpected token
-   YYCHAR while in state YYSTATE.  Return the number of bytes copied,
-   including the terminating null byte.  If YYRESULT is null, do not
-   copy anything; just return the number of bytes that would be
-   copied.  As a special case, return 0 if an ordinary "syntax error"
-   message will do.  Return YYSIZE_MAXIMUM if overflow occurs during
-   size calculation.  */
-static YYSIZE_T
-yysyntax_error (char *yyresult, int yystate, int yychar)
-{
-  int yyn = yypact[yystate];
-
-  if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
-    return 0;
-  else
-    {
-      int yytype = YYTRANSLATE (yychar);
-      YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
-      YYSIZE_T yysize = yysize0;
-      YYSIZE_T yysize1;
-      int yysize_overflow = 0;
-      enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
-      char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
-      int yyx;
-
-# if 0
-      /* This is so xgettext sees the translatable formats that are
-	 constructed on the fly.  */
-      YY_("syntax error, unexpected %s");
-      YY_("syntax error, unexpected %s, expecting %s");
-      YY_("syntax error, unexpected %s, expecting %s or %s");
-      YY_("syntax error, unexpected %s, expecting %s or %s or %s");
-      YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
-# endif
-      char *yyfmt;
-      char const *yyf;
-      static char const yyunexpected[] = "syntax error, unexpected %s";
-      static char const yyexpecting[] = ", expecting %s";
-      static char const yyor[] = " or %s";
-      char yyformat[sizeof yyunexpected
-		    + sizeof yyexpecting - 1
-		    + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
-		       * (sizeof yyor - 1))];
-      char const *yyprefix = yyexpecting;
-
-      /* Start YYX at -YYN if negative to avoid negative indexes in
-	 YYCHECK.  */
-      int yyxbegin = yyn < 0 ? -yyn : 0;
-
-      /* Stay within bounds of both yycheck and yytname.  */
-      int yychecklim = YYLAST - yyn + 1;
-      int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
-      int yycount = 1;
-
-      yyarg[0] = yytname[yytype];
-      yyfmt = yystpcpy (yyformat, yyunexpected);
-
-      for (yyx = yyxbegin; yyx < yyxend; ++yyx)
-	if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
-	  {
-	    if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
-	      {
-		yycount = 1;
-		yysize = yysize0;
-		yyformat[sizeof yyunexpected - 1] = '\0';
-		break;
-	      }
-	    yyarg[yycount++] = yytname[yyx];
-	    yysize1 = yysize + yytnamerr (0, yytname[yyx]);
-	    yysize_overflow |= (yysize1 < yysize);
-	    yysize = yysize1;
-	    yyfmt = yystpcpy (yyfmt, yyprefix);
-	    yyprefix = yyor;
-	  }
-
-      yyf = YY_(yyformat);
-      yysize1 = yysize + yystrlen (yyf);
-      yysize_overflow |= (yysize1 < yysize);
-      yysize = yysize1;
-
-      if (yysize_overflow)
-	return YYSIZE_MAXIMUM;
-
-      if (yyresult)
-	{
-	  /* Avoid sprintf, as that infringes on the user's name space.
-	     Don't have undefined behavior even if the translation
-	     produced a string with the wrong number of "%s"s.  */
-	  char *yyp = yyresult;
-	  int yyi = 0;
-	  while ((*yyp = *yyf) != '\0')
-	    {
-	      if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
-		{
-		  yyp += yytnamerr (yyp, yyarg[yyi++]);
-		  yyf += 2;
-		}
-	      else
-		{
-		  yyp++;
-		  yyf++;
-		}
-	    }
-	}
-      return yysize;
-    }
-}
-#endif /* YYERROR_VERBOSE */
-

-
-/*-----------------------------------------------.
-| Release the memory associated to this symbol.  |
-`-----------------------------------------------*/
-
-/*ARGSUSED*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static void
-yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
-#else
-static void
-yydestruct (yymsg, yytype, yyvaluep)
-    const char *yymsg;
-    int yytype;
-    YYSTYPE *yyvaluep;
-#endif
-{
-  YYUSE (yyvaluep);
-
-  if (!yymsg)
-    yymsg = "Deleting";
-  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
-
-  switch (yytype)
-    {
-
-      default:
-	break;
-    }
-}
-

-
-/* Prevent warnings from -Wmissing-prototypes.  */
-
-#ifdef YYPARSE_PARAM
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void *YYPARSE_PARAM);
-#else
-int yyparse ();
-#endif
-#else /* ! YYPARSE_PARAM */
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void);
-#else
-int yyparse ();
-#endif
-#endif /* ! YYPARSE_PARAM */
-
-
-
-/* The look-ahead symbol.  */
-int yychar;
-
-/* The semantic value of the look-ahead symbol.  */
-YYSTYPE yylval;
-
-/* Number of syntax errors so far.  */
-int yynerrs;
-
-
-
-/*----------.
-| yyparse.  |
-`----------*/
-
-#ifdef YYPARSE_PARAM
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-int
-yyparse (void *YYPARSE_PARAM)
-#else
-int
-yyparse (YYPARSE_PARAM)
-    void *YYPARSE_PARAM;
-#endif
-#else /* ! YYPARSE_PARAM */
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-int
-yyparse (void)
-#else
-int
-yyparse ()
-
-#endif
-#endif
-{
-  
-  int yystate;
-  int yyn;
-  int yyresult;
-  /* Number of tokens to shift before error messages enabled.  */
-  int yyerrstatus;
-  /* Look-ahead token as an internal (translated) token number.  */
-  int yytoken = 0;
-#if YYERROR_VERBOSE
-  /* Buffer for error messages, and its allocated size.  */
-  char yymsgbuf[128];
-  char *yymsg = yymsgbuf;
-  YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
-#endif
-
-  /* Three stacks and their tools:
-     `yyss': related to states,
-     `yyvs': related to semantic values,
-     `yyls': related to locations.
-
-     Refer to the stacks thru separate pointers, to allow yyoverflow
-     to reallocate them elsewhere.  */
-
-  /* The state stack.  */
-  yytype_int16 yyssa[YYINITDEPTH];
-  yytype_int16 *yyss = yyssa;
-  yytype_int16 *yyssp;
-
-  /* The semantic value stack.  */
-  YYSTYPE yyvsa[YYINITDEPTH];
-  YYSTYPE *yyvs = yyvsa;
-  YYSTYPE *yyvsp;
-
-
-
-#define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N))
-
-  YYSIZE_T yystacksize = YYINITDEPTH;
-
-  /* The variables used to return semantic value and location from the
-     action routines.  */
-  YYSTYPE yyval;
-
-
-  /* The number of symbols on the RHS of the reduced rule.
-     Keep to zero when no symbol should be popped.  */
-  int yylen = 0;
-
-  YYDPRINTF ((stderr, "Starting parse\n"));
-
-  yystate = 0;
-  yyerrstatus = 0;
-  yynerrs = 0;
-  yychar = YYEMPTY;		/* Cause a token to be read.  */
-
-  /* Initialize stack pointers.
-     Waste one element of value and location stack
-     so that they stay on the same level as the state stack.
-     The wasted elements are never initialized.  */
-
-  yyssp = yyss;
-  yyvsp = yyvs;
-
-  goto yysetstate;
-
-/*------------------------------------------------------------.
-| yynewstate -- Push a new state, which is found in yystate.  |
-`------------------------------------------------------------*/
- yynewstate:
-  /* In all cases, when you get here, the value and location stacks
-     have just been pushed.  So pushing a state here evens the stacks.  */
-  yyssp++;
-
- yysetstate:
-  *yyssp = yystate;
-
-  if (yyss + yystacksize - 1 <= yyssp)
-    {
-      /* Get the current used size of the three stacks, in elements.  */
-      YYSIZE_T yysize = yyssp - yyss + 1;
-
-#ifdef yyoverflow
-      {
-	/* Give user a chance to reallocate the stack.  Use copies of
-	   these so that the &'s don't force the real ones into
-	   memory.  */
-	YYSTYPE *yyvs1 = yyvs;
-	yytype_int16 *yyss1 = yyss;
-
-
-	/* Each stack pointer address is followed by the size of the
-	   data in use in that stack, in bytes.  This used to be a
-	   conditional around just the two extra args, but that might
-	   be undefined if yyoverflow is a macro.  */
-	yyoverflow (YY_("memory exhausted"),
-		    &yyss1, yysize * sizeof (*yyssp),
-		    &yyvs1, yysize * sizeof (*yyvsp),
-
-		    &yystacksize);
-
-	yyss = yyss1;
-	yyvs = yyvs1;
-      }
-#else /* no yyoverflow */
-# ifndef YYSTACK_RELOCATE
-      goto yyexhaustedlab;
-# else
-      /* Extend the stack our own way.  */
-      if (YYMAXDEPTH <= yystacksize)
-	goto yyexhaustedlab;
-      yystacksize *= 2;
-      if (YYMAXDEPTH < yystacksize)
-	yystacksize = YYMAXDEPTH;
-
-      {
-	yytype_int16 *yyss1 = yyss;
-	union yyalloc *yyptr =
-	  (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
-	if (! yyptr)
-	  goto yyexhaustedlab;
-	YYSTACK_RELOCATE (yyss);
-	YYSTACK_RELOCATE (yyvs);
-
-#  undef YYSTACK_RELOCATE
-	if (yyss1 != yyssa)
-	  YYSTACK_FREE (yyss1);
-      }
-# endif
-#endif /* no yyoverflow */
-
-      yyssp = yyss + yysize - 1;
-      yyvsp = yyvs + yysize - 1;
-
-
-      YYDPRINTF ((stderr, "Stack size increased to %lu\n",
-		  (unsigned long int) yystacksize));
-
-      if (yyss + yystacksize - 1 <= yyssp)
-	YYABORT;
-    }
-
-  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
-
-  goto yybackup;
-
-/*-----------.
-| yybackup.  |
-`-----------*/
-yybackup:
-
-  /* Do appropriate processing given the current state.  Read a
-     look-ahead token if we need one and don't already have one.  */
-
-  /* First try to decide what to do without reference to look-ahead token.  */
-  yyn = yypact[yystate];
-  if (yyn == YYPACT_NINF)
-    goto yydefault;
-
-  /* Not known => get a look-ahead token if don't already have one.  */
-
-  /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol.  */
-  if (yychar == YYEMPTY)
-    {
-      YYDPRINTF ((stderr, "Reading a token: "));
-      yychar = YYLEX;
-    }
-
-  if (yychar <= YYEOF)
-    {
-      yychar = yytoken = YYEOF;
-      YYDPRINTF ((stderr, "Now at end of input.\n"));
-    }
-  else
-    {
-      yytoken = YYTRANSLATE (yychar);
-      YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
-    }
-
-  /* If the proper action on seeing token YYTOKEN is to reduce or to
-     detect an error, take that action.  */
-  yyn += yytoken;
-  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
-    goto yydefault;
-  yyn = yytable[yyn];
-  if (yyn <= 0)
-    {
-      if (yyn == 0 || yyn == YYTABLE_NINF)
-	goto yyerrlab;
-      yyn = -yyn;
-      goto yyreduce;
-    }
-
-  if (yyn == YYFINAL)
-    YYACCEPT;
-
-  /* Count tokens shifted since error; after three, turn off error
-     status.  */
-  if (yyerrstatus)
-    yyerrstatus--;
-
-  /* Shift the look-ahead token.  */
-  YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
-
-  /* Discard the shifted token unless it is eof.  */
-  if (yychar != YYEOF)
-    yychar = YYEMPTY;
-
-  yystate = yyn;
-  *++yyvsp = yylval;
-
-  goto yynewstate;
-
-
-/*-----------------------------------------------------------.
-| yydefault -- do the default action for the current state.  |
-`-----------------------------------------------------------*/
-yydefault:
-  yyn = yydefact[yystate];
-  if (yyn == 0)
-    goto yyerrlab;
-  goto yyreduce;
-
-
-/*-----------------------------.
-| yyreduce -- Do a reduction.  |
-`-----------------------------*/
-yyreduce:
-  /* yyn is the number of a rule to reduce with.  */
-  yylen = yyr2[yyn];
-
-  /* If YYLEN is nonzero, implement the default value of the action:
-     `$$ = $1'.
-
-     Otherwise, the following line sets YYVAL to garbage.
-     This behavior is undocumented and Bison
-     users should not rely upon it.  Assigning to YYVAL
-     unconditionally makes the parser a bit smaller, and it avoids a
-     GCC warning that YYVAL may be used uninitialized.  */
-  yyval = yyvsp[1-yylen];
-
-
-  YY_REDUCE_PRINT (yyn);
-  switch (yyn)
-    {
-        case 3:
-#line 68 "a.y"
-    {
-		stmtline = lineno;
-	}
-    break;
-
-  case 5:
-#line 75 "a.y"
-    {
-		if((yyvsp[(1) - (2)].sym)->value != pc)
-			yyerror("redeclaration of %s", (yyvsp[(1) - (2)].sym)->name);
-		(yyvsp[(1) - (2)].sym)->value = pc;
-	}
-    break;
-
-  case 7:
-#line 82 "a.y"
-    {
-		(yyvsp[(1) - (2)].sym)->type = LLAB;
-		(yyvsp[(1) - (2)].sym)->value = pc;
-	}
-    break;
-
-  case 12:
-#line 93 "a.y"
-    {
-		(yyvsp[(1) - (3)].sym)->type = LVAR;
-		(yyvsp[(1) - (3)].sym)->value = (yyvsp[(3) - (3)].lval);
-	}
-    break;
-
-  case 13:
-#line 98 "a.y"
-    {
-		if((yyvsp[(1) - (3)].sym)->value != (yyvsp[(3) - (3)].lval))
-			yyerror("redeclaration of %s", (yyvsp[(1) - (3)].sym)->name);
-		(yyvsp[(1) - (3)].sym)->value = (yyvsp[(3) - (3)].lval);
-	}
-    break;
-
-  case 14:
-#line 103 "a.y"
-    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
-    break;
-
-  case 15:
-#line 104 "a.y"
-    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
-    break;
-
-  case 16:
-#line 105 "a.y"
-    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
-    break;
-
-  case 17:
-#line 106 "a.y"
-    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
-    break;
-
-  case 18:
-#line 107 "a.y"
-    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
-    break;
-
-  case 19:
-#line 108 "a.y"
-    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
-    break;
-
-  case 20:
-#line 109 "a.y"
-    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
-    break;
-
-  case 21:
-#line 110 "a.y"
-    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
-    break;
-
-  case 22:
-#line 111 "a.y"
-    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
-    break;
-
-  case 23:
-#line 112 "a.y"
-    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
-    break;
-
-  case 24:
-#line 113 "a.y"
-    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
-    break;
-
-  case 25:
-#line 114 "a.y"
-    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
-    break;
-
-  case 26:
-#line 115 "a.y"
-    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
-    break;
-
-  case 27:
-#line 116 "a.y"
-    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
-    break;
-
-  case 28:
-#line 117 "a.y"
-    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
-    break;
-
-  case 29:
-#line 118 "a.y"
-    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
-    break;
-
-  case 30:
-#line 119 "a.y"
-    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
-    break;
-
-  case 31:
-#line 120 "a.y"
-    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
-    break;
-
-  case 32:
-#line 121 "a.y"
-    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
-    break;
-
-  case 33:
-#line 124 "a.y"
-    {
-		(yyval.addr2).from = nullgen;
-		(yyval.addr2).to = nullgen;
-	}
-    break;
-
-  case 34:
-#line 129 "a.y"
-    {
-		(yyval.addr2).from = nullgen;
-		(yyval.addr2).to = nullgen;
-	}
-    break;
-
-  case 35:
-#line 136 "a.y"
-    {
-		(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
-		(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
-	}
-    break;
-
-  case 36:
-#line 143 "a.y"
-    {
-		(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
-		(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
-	}
-    break;
-
-  case 37:
-#line 150 "a.y"
-    {
-		(yyval.addr2).from = (yyvsp[(1) - (2)].addr);
-		(yyval.addr2).to = nullgen;
-	}
-    break;
-
-  case 38:
-#line 155 "a.y"
-    {
-		(yyval.addr2).from = (yyvsp[(1) - (1)].addr);
-		(yyval.addr2).to = nullgen;
-	}
-    break;
-
-  case 39:
-#line 162 "a.y"
-    {
-		(yyval.addr2).from = nullgen;
-		(yyval.addr2).to = (yyvsp[(2) - (2)].addr);
-	}
-    break;
-
-  case 40:
-#line 167 "a.y"
-    {
-		(yyval.addr2).from = nullgen;
-		(yyval.addr2).to = (yyvsp[(1) - (1)].addr);
-	}
-    break;
-
-  case 41:
-#line 174 "a.y"
-    {
-		(yyval.addr2).from = nullgen;
-		(yyval.addr2).to = (yyvsp[(2) - (2)].addr);
-	}
-    break;
-
-  case 42:
-#line 179 "a.y"
-    {
-		(yyval.addr2).from = nullgen;
-		(yyval.addr2).to = (yyvsp[(1) - (1)].addr);
-	}
-    break;
-
-  case 43:
-#line 184 "a.y"
-    {
-		(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
-		(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
-	}
-    break;
-
-  case 44:
-#line 191 "a.y"
-    {
-		(yyval.addr2).from = (yyvsp[(1) - (5)].addr);
-		(yyval.addr2).from.scale = (yyvsp[(3) - (5)].lval);
-		(yyval.addr2).to = (yyvsp[(5) - (5)].addr);
-	}
-    break;
-
-  case 45:
-#line 199 "a.y"
-    {
-		(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
-		(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
-	}
-    break;
-
-  case 46:
-#line 204 "a.y"
-    {
-		(yyval.addr2).from = (yyvsp[(1) - (5)].addr);
-		(yyval.addr2).from.scale = (yyvsp[(3) - (5)].lval);
-		(yyval.addr2).to = (yyvsp[(5) - (5)].addr);
-	}
-    break;
-
-  case 47:
-#line 212 "a.y"
-    {
-		(yyval.addr2).from = nullgen;
-		(yyval.addr2).to = (yyvsp[(2) - (2)].addr);
-	}
-    break;
-
-  case 48:
-#line 217 "a.y"
-    {
-		(yyval.addr2).from = nullgen;
-		(yyval.addr2).to = (yyvsp[(1) - (1)].addr);
-	}
-    break;
-
-  case 51:
-#line 228 "a.y"
-    {
-		(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
-		(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
-	}
-    break;
-
-  case 52:
-#line 233 "a.y"
-    {
-		(yyval.addr2).from = (yyvsp[(1) - (5)].addr);
-		(yyval.addr2).to = (yyvsp[(3) - (5)].addr);
-		if((yyval.addr2).from.index != D_NONE)
-			yyerror("dp shift with lhs index");
-		(yyval.addr2).from.index = (yyvsp[(5) - (5)].lval);
-	}
-    break;
-
-  case 53:
-#line 243 "a.y"
-    {
-		(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
-		(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
-	}
-    break;
-
-  case 54:
-#line 248 "a.y"
-    {
-		(yyval.addr2).from = (yyvsp[(1) - (5)].addr);
-		(yyval.addr2).to = (yyvsp[(3) - (5)].addr);
-		if((yyval.addr2).to.index != D_NONE)
-			yyerror("dp move with lhs index");
-		(yyval.addr2).to.index = (yyvsp[(5) - (5)].lval);
-	}
-    break;
-
-  case 55:
-#line 258 "a.y"
-    {
-		(yyval.addr2).from = (yyvsp[(1) - (2)].addr);
-		(yyval.addr2).to = nullgen;
-	}
-    break;
-
-  case 56:
-#line 263 "a.y"
-    {
-		(yyval.addr2).from = (yyvsp[(1) - (1)].addr);
-		(yyval.addr2).to = nullgen;
-	}
-    break;
-
-  case 57:
-#line 268 "a.y"
-    {
-		(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
-		(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
-	}
-    break;
-
-  case 58:
-#line 275 "a.y"
-    {
-		(yyval.addr2).from = (yyvsp[(1) - (5)].addr);
-		(yyval.addr2).to = (yyvsp[(3) - (5)].addr);
-		(yyval.addr2).to.offset = (yyvsp[(5) - (5)].lval);
-	}
-    break;
-
-  case 59:
-#line 283 "a.y"
-    {
-		(yyval.addr2).from = (yyvsp[(3) - (5)].addr);
-		(yyval.addr2).to = (yyvsp[(5) - (5)].addr);
-		if((yyvsp[(1) - (5)].addr).type != D_CONST)
-			yyerror("illegal constant");
-		(yyval.addr2).to.offset = (yyvsp[(1) - (5)].addr).offset;
-	}
-    break;
-
-  case 60:
-#line 292 "a.y"
-    {
-		(yyval.addr2).from = nullgen;
-		(yyval.addr2).to = nullgen;
-	}
-    break;
-
-  case 61:
-#line 297 "a.y"
-    {
-		(yyval.addr2).from = (yyvsp[(1) - (1)].addr);
-		(yyval.addr2).to = nullgen;
-	}
-    break;
-
-  case 62:
-#line 304 "a.y"
-    {
-		(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
-		(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
-	}
-    break;
-
-  case 63:
-#line 309 "a.y"
-    {
-		(yyval.addr2).from = (yyvsp[(1) - (5)].addr);
-		(yyval.addr2).from.scale = (yyvsp[(3) - (5)].lval);
-		(yyval.addr2).to = (yyvsp[(5) - (5)].addr);
-	}
-    break;
-
-  case 64:
-#line 317 "a.y"
-    {
-		if((yyvsp[(1) - (3)].addr).type != D_CONST || (yyvsp[(3) - (3)].addr).type != D_CONST)
-			yyerror("arguments to PCDATA must be integer constants");
-		(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
-		(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
-	}
-    break;
-
-  case 65:
-#line 326 "a.y"
-    {
-		if((yyvsp[(1) - (3)].addr).type != D_CONST)
-			yyerror("index for FUNCDATA must be integer constant");
-		if((yyvsp[(3) - (3)].addr).type != D_EXTERN && (yyvsp[(3) - (3)].addr).type != D_STATIC)
-			yyerror("value for FUNCDATA must be symbol reference");
-		(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
-		(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
-	}
-    break;
-
-  case 70:
-#line 343 "a.y"
-    {
-		(yyval.addr) = (yyvsp[(2) - (2)].addr);
-	}
-    break;
-
-  case 71:
-#line 347 "a.y"
-    {
-		(yyval.addr) = (yyvsp[(2) - (2)].addr);
-	}
-    break;
-
-  case 76:
-#line 359 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_BRANCH;
-		(yyval.addr).offset = (yyvsp[(1) - (4)].lval) + pc;
-	}
-    break;
-
-  case 77:
-#line 365 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		if(pass == 2)
-			yyerror("undefined label: %s", (yyvsp[(1) - (2)].sym)->name);
-		(yyval.addr).type = D_BRANCH;
-		(yyval.addr).offset = (yyvsp[(2) - (2)].lval);
-	}
-    break;
-
-  case 78:
-#line 373 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_BRANCH;
-		(yyval.addr).offset = (yyvsp[(1) - (2)].sym)->value + (yyvsp[(2) - (2)].lval);
-	}
-    break;
-
-  case 79:
-#line 381 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = (yyvsp[(1) - (1)].lval);
-	}
-    break;
-
-  case 80:
-#line 386 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = (yyvsp[(1) - (1)].lval);
-	}
-    break;
-
-  case 81:
-#line 391 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = (yyvsp[(1) - (1)].lval);
-	}
-    break;
-
-  case 82:
-#line 396 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = (yyvsp[(1) - (1)].lval);
-	}
-    break;
-
-  case 83:
-#line 401 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_SP;
-	}
-    break;
-
-  case 84:
-#line 406 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = (yyvsp[(1) - (1)].lval);
-	}
-    break;
-
-  case 85:
-#line 411 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = (yyvsp[(1) - (1)].lval);
-	}
-    break;
-
-  case 86:
-#line 417 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_CONST;
-		(yyval.addr).offset = (yyvsp[(2) - (2)].lval);
-	}
-    break;
-
-  case 87:
-#line 425 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_CONST;
-		(yyval.addr).offset = (yyvsp[(2) - (2)].lval);
-	}
-    break;
-
-  case 88:
-#line 431 "a.y"
-    {
-		(yyval.addr) = (yyvsp[(2) - (2)].addr);
-		(yyval.addr).index = (yyvsp[(2) - (2)].addr).type;
-		(yyval.addr).type = D_ADDR;
-		/*
-		if($2.type == D_AUTO || $2.type == D_PARAM)
-			yyerror("constant cannot be automatic: %s",
-				$2.sym->name);
-		 */
-	}
-    break;
-
-  case 89:
-#line 442 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_SCONST;
-		memcpy((yyval.addr).u.sval, (yyvsp[(2) - (2)].sval), sizeof((yyval.addr).u.sval));
-	}
-    break;
-
-  case 90:
-#line 448 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_FCONST;
-		(yyval.addr).u.dval = (yyvsp[(2) - (2)].dval);
-	}
-    break;
-
-  case 91:
-#line 454 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_FCONST;
-		(yyval.addr).u.dval = (yyvsp[(3) - (4)].dval);
-	}
-    break;
-
-  case 92:
-#line 460 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_FCONST;
-		(yyval.addr).u.dval = -(yyvsp[(4) - (5)].dval);
-	}
-    break;
-
-  case 93:
-#line 466 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_FCONST;
-		(yyval.addr).u.dval = -(yyvsp[(3) - (3)].dval);
-	}
-    break;
-
-  case 96:
-#line 478 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_INDIR+D_NONE;
-		(yyval.addr).offset = (yyvsp[(1) - (1)].lval);
-	}
-    break;
-
-  case 97:
-#line 484 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_INDIR+(yyvsp[(3) - (4)].lval);
-		(yyval.addr).offset = (yyvsp[(1) - (4)].lval);
-	}
-    break;
-
-  case 98:
-#line 490 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_INDIR+D_SP;
-		(yyval.addr).offset = (yyvsp[(1) - (4)].lval);
-	}
-    break;
-
-  case 99:
-#line 496 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_INDIR+(yyvsp[(3) - (4)].lval);
-		(yyval.addr).offset = (yyvsp[(1) - (4)].lval);
-	}
-    break;
-
-  case 100:
-#line 502 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_INDIR+D_NONE;
-		(yyval.addr).offset = (yyvsp[(1) - (6)].lval);
-		(yyval.addr).index = (yyvsp[(3) - (6)].lval);
-		(yyval.addr).scale = (yyvsp[(5) - (6)].lval);
-		checkscale((yyval.addr).scale);
-	}
-    break;
-
-  case 101:
-#line 511 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_INDIR+(yyvsp[(3) - (9)].lval);
-		(yyval.addr).offset = (yyvsp[(1) - (9)].lval);
-		(yyval.addr).index = (yyvsp[(6) - (9)].lval);
-		(yyval.addr).scale = (yyvsp[(8) - (9)].lval);
-		checkscale((yyval.addr).scale);
-	}
-    break;
-
-  case 102:
-#line 520 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_INDIR+(yyvsp[(3) - (9)].lval);
-		(yyval.addr).offset = (yyvsp[(1) - (9)].lval);
-		(yyval.addr).index = (yyvsp[(6) - (9)].lval);
-		(yyval.addr).scale = (yyvsp[(8) - (9)].lval);
-		checkscale((yyval.addr).scale);
-	}
-    break;
-
-  case 103:
-#line 529 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_INDIR+(yyvsp[(2) - (3)].lval);
-	}
-    break;
-
-  case 104:
-#line 534 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_INDIR+D_SP;
-	}
-    break;
-
-  case 105:
-#line 539 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_INDIR+D_NONE;
-		(yyval.addr).index = (yyvsp[(2) - (5)].lval);
-		(yyval.addr).scale = (yyvsp[(4) - (5)].lval);
-		checkscale((yyval.addr).scale);
-	}
-    break;
-
-  case 106:
-#line 547 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_INDIR+(yyvsp[(2) - (8)].lval);
-		(yyval.addr).index = (yyvsp[(5) - (8)].lval);
-		(yyval.addr).scale = (yyvsp[(7) - (8)].lval);
-		checkscale((yyval.addr).scale);
-	}
-    break;
-
-  case 107:
-#line 557 "a.y"
-    {
-		(yyval.addr) = (yyvsp[(1) - (1)].addr);
-	}
-    break;
-
-  case 108:
-#line 561 "a.y"
-    {
-		(yyval.addr) = (yyvsp[(1) - (6)].addr);
-		(yyval.addr).index = (yyvsp[(3) - (6)].lval);
-		(yyval.addr).scale = (yyvsp[(5) - (6)].lval);
-		checkscale((yyval.addr).scale);
-	}
-    break;
-
-  case 109:
-#line 570 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = (yyvsp[(4) - (5)].lval);
-		(yyval.addr).sym = linklookup(ctxt, (yyvsp[(1) - (5)].sym)->name, 0);
-		(yyval.addr).offset = (yyvsp[(2) - (5)].lval);
-	}
-    break;
-
-  case 110:
-#line 577 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_STATIC;
-		(yyval.addr).sym = linklookup(ctxt, (yyvsp[(1) - (7)].sym)->name, 1);
-		(yyval.addr).offset = (yyvsp[(4) - (7)].lval);
-	}
-    break;
-
-  case 111:
-#line 585 "a.y"
-    {
-		(yyval.lval) = 0;
-	}
-    break;
-
-  case 112:
-#line 589 "a.y"
-    {
-		(yyval.lval) = (yyvsp[(2) - (2)].lval);
-	}
-    break;
-
-  case 113:
-#line 593 "a.y"
-    {
-		(yyval.lval) = -(yyvsp[(2) - (2)].lval);
-	}
-    break;
-
-  case 115:
-#line 600 "a.y"
-    {
-		(yyval.lval) = D_AUTO;
-	}
-    break;
-
-  case 118:
-#line 608 "a.y"
-    {
-		(yyval.lval) = (yyvsp[(1) - (1)].sym)->value;
-	}
-    break;
-
-  case 119:
-#line 612 "a.y"
-    {
-		(yyval.lval) = -(yyvsp[(2) - (2)].lval);
-	}
-    break;
-
-  case 120:
-#line 616 "a.y"
-    {
-		(yyval.lval) = (yyvsp[(2) - (2)].lval);
-	}
-    break;
-
-  case 121:
-#line 620 "a.y"
-    {
-		(yyval.lval) = ~(yyvsp[(2) - (2)].lval);
-	}
-    break;
-
-  case 122:
-#line 624 "a.y"
-    {
-		(yyval.lval) = (yyvsp[(2) - (3)].lval);
-	}
-    break;
-
-  case 123:
-#line 630 "a.y"
-    {
-		(yyval.lval) = ((yyvsp[(1) - (1)].lval) & 0xffffffffLL) +
-			((vlong)ArgsSizeUnknown << 32);
-	}
-    break;
-
-  case 124:
-#line 635 "a.y"
-    {
-		(yyval.lval) = (-(yyvsp[(2) - (2)].lval) & 0xffffffffLL) +
-			((vlong)ArgsSizeUnknown << 32);
-	}
-    break;
-
-  case 125:
-#line 640 "a.y"
-    {
-		(yyval.lval) = ((yyvsp[(1) - (3)].lval) & 0xffffffffLL) +
-			(((yyvsp[(3) - (3)].lval) & 0xffffLL) << 32);
-	}
-    break;
-
-  case 126:
-#line 645 "a.y"
-    {
-		(yyval.lval) = (-(yyvsp[(2) - (4)].lval) & 0xffffffffLL) +
-			(((yyvsp[(4) - (4)].lval) & 0xffffLL) << 32);
-	}
-    break;
-
-  case 128:
-#line 653 "a.y"
-    {
-		(yyval.lval) = (yyvsp[(1) - (3)].lval) + (yyvsp[(3) - (3)].lval);
-	}
-    break;
-
-  case 129:
-#line 657 "a.y"
-    {
-		(yyval.lval) = (yyvsp[(1) - (3)].lval) - (yyvsp[(3) - (3)].lval);
-	}
-    break;
-
-  case 130:
-#line 661 "a.y"
-    {
-		(yyval.lval) = (yyvsp[(1) - (3)].lval) * (yyvsp[(3) - (3)].lval);
-	}
-    break;
-
-  case 131:
-#line 665 "a.y"
-    {
-		(yyval.lval) = (yyvsp[(1) - (3)].lval) / (yyvsp[(3) - (3)].lval);
-	}
-    break;
-
-  case 132:
-#line 669 "a.y"
-    {
-		(yyval.lval) = (yyvsp[(1) - (3)].lval) % (yyvsp[(3) - (3)].lval);
-	}
-    break;
-
-  case 133:
-#line 673 "a.y"
-    {
-		(yyval.lval) = (yyvsp[(1) - (4)].lval) << (yyvsp[(4) - (4)].lval);
-	}
-    break;
-
-  case 134:
-#line 677 "a.y"
-    {
-		(yyval.lval) = (yyvsp[(1) - (4)].lval) >> (yyvsp[(4) - (4)].lval);
-	}
-    break;
-
-  case 135:
-#line 681 "a.y"
-    {
-		(yyval.lval) = (yyvsp[(1) - (3)].lval) & (yyvsp[(3) - (3)].lval);
-	}
-    break;
-
-  case 136:
-#line 685 "a.y"
-    {
-		(yyval.lval) = (yyvsp[(1) - (3)].lval) ^ (yyvsp[(3) - (3)].lval);
-	}
-    break;
-
-  case 137:
-#line 689 "a.y"
-    {
-		(yyval.lval) = (yyvsp[(1) - (3)].lval) | (yyvsp[(3) - (3)].lval);
-	}
-    break;
-
-
-/* Line 1267 of yacc.c.  */
-#line 2588 "y.tab.c"
-      default: break;
-    }
-  YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
-
-  YYPOPSTACK (yylen);
-  yylen = 0;
-  YY_STACK_PRINT (yyss, yyssp);
-
-  *++yyvsp = yyval;
-
-
-  /* Now `shift' the result of the reduction.  Determine what state
-     that goes to, based on the state we popped back to and the rule
-     number reduced by.  */
-
-  yyn = yyr1[yyn];
-
-  yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
-  if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
-    yystate = yytable[yystate];
-  else
-    yystate = yydefgoto[yyn - YYNTOKENS];
-
-  goto yynewstate;
-
-
-/*------------------------------------.
-| yyerrlab -- here on detecting error |
-`------------------------------------*/
-yyerrlab:
-  /* If not already recovering from an error, report this error.  */
-  if (!yyerrstatus)
-    {
-      ++yynerrs;
-#if ! YYERROR_VERBOSE
-      yyerror (YY_("syntax error"));
-#else
-      {
-	YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
-	if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
-	  {
-	    YYSIZE_T yyalloc = 2 * yysize;
-	    if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
-	      yyalloc = YYSTACK_ALLOC_MAXIMUM;
-	    if (yymsg != yymsgbuf)
-	      YYSTACK_FREE (yymsg);
-	    yymsg = (char *) YYSTACK_ALLOC (yyalloc);
-	    if (yymsg)
-	      yymsg_alloc = yyalloc;
-	    else
-	      {
-		yymsg = yymsgbuf;
-		yymsg_alloc = sizeof yymsgbuf;
-	      }
-	  }
-
-	if (0 < yysize && yysize <= yymsg_alloc)
-	  {
-	    (void) yysyntax_error (yymsg, yystate, yychar);
-	    yyerror (yymsg);
-	  }
-	else
-	  {
-	    yyerror (YY_("syntax error"));
-	    if (yysize != 0)
-	      goto yyexhaustedlab;
-	  }
-      }
-#endif
-    }
-
-
-
-  if (yyerrstatus == 3)
-    {
-      /* If just tried and failed to reuse look-ahead token after an
-	 error, discard it.  */
-
-      if (yychar <= YYEOF)
-	{
-	  /* Return failure if at end of input.  */
-	  if (yychar == YYEOF)
-	    YYABORT;
-	}
-      else
-	{
-	  yydestruct ("Error: discarding",
-		      yytoken, &yylval);
-	  yychar = YYEMPTY;
-	}
-    }
-
-  /* Else will try to reuse look-ahead token after shifting the error
-     token.  */
-  goto yyerrlab1;
-
-
-/*---------------------------------------------------.
-| yyerrorlab -- error raised explicitly by YYERROR.  |
-`---------------------------------------------------*/
-yyerrorlab:
-
-  /* Pacify compilers like GCC when the user code never invokes
-     YYERROR and the label yyerrorlab therefore never appears in user
-     code.  */
-  if (/*CONSTCOND*/ 0)
-     goto yyerrorlab;
-
-  /* Do not reclaim the symbols of the rule which action triggered
-     this YYERROR.  */
-  YYPOPSTACK (yylen);
-  yylen = 0;
-  YY_STACK_PRINT (yyss, yyssp);
-  yystate = *yyssp;
-  goto yyerrlab1;
-
-
-/*-------------------------------------------------------------.
-| yyerrlab1 -- common code for both syntax error and YYERROR.  |
-`-------------------------------------------------------------*/
-yyerrlab1:
-  yyerrstatus = 3;	/* Each real token shifted decrements this.  */
-
-  for (;;)
-    {
-      yyn = yypact[yystate];
-      if (yyn != YYPACT_NINF)
-	{
-	  yyn += YYTERROR;
-	  if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
-	    {
-	      yyn = yytable[yyn];
-	      if (0 < yyn)
-		break;
-	    }
-	}
-
-      /* Pop the current state because it cannot handle the error token.  */
-      if (yyssp == yyss)
-	YYABORT;
-
-
-      yydestruct ("Error: popping",
-		  yystos[yystate], yyvsp);
-      YYPOPSTACK (1);
-      yystate = *yyssp;
-      YY_STACK_PRINT (yyss, yyssp);
-    }
-
-  if (yyn == YYFINAL)
-    YYACCEPT;
-
-  *++yyvsp = yylval;
-
-
-  /* Shift the error token.  */
-  YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
-
-  yystate = yyn;
-  goto yynewstate;
-
-
-/*-------------------------------------.
-| yyacceptlab -- YYACCEPT comes here.  |
-`-------------------------------------*/
-yyacceptlab:
-  yyresult = 0;
-  goto yyreturn;
-
-/*-----------------------------------.
-| yyabortlab -- YYABORT comes here.  |
-`-----------------------------------*/
-yyabortlab:
-  yyresult = 1;
-  goto yyreturn;
-
-#ifndef yyoverflow
-/*-------------------------------------------------.
-| yyexhaustedlab -- memory exhaustion comes here.  |
-`-------------------------------------------------*/
-yyexhaustedlab:
-  yyerror (YY_("memory exhausted"));
-  yyresult = 2;
-  /* Fall through.  */
-#endif
-
-yyreturn:
-  if (yychar != YYEOF && yychar != YYEMPTY)
-     yydestruct ("Cleanup: discarding lookahead",
-		 yytoken, &yylval);
-  /* Do not reclaim the symbols of the rule which action triggered
-     this YYABORT or YYACCEPT.  */
-  YYPOPSTACK (yylen);
-  YY_STACK_PRINT (yyss, yyssp);
-  while (yyssp != yyss)
-    {
-      yydestruct ("Cleanup: popping",
-		  yystos[*yyssp], yyvsp);
-      YYPOPSTACK (1);
-    }
-#ifndef yyoverflow
-  if (yyss != yyssa)
-    YYSTACK_FREE (yyss);
-#endif
-#if YYERROR_VERBOSE
-  if (yymsg != yymsgbuf)
-    YYSTACK_FREE (yymsg);
-#endif
-  /* Make sure YYID is used.  */
-  return YYID (yyresult);
-}
-
-
-
diff --git a/src/cmd/6a/y.tab.h b/src/cmd/6a/y.tab.h
deleted file mode 100644
index e0eb5e1..0000000
--- a/src/cmd/6a/y.tab.h
+++ /dev/null
@@ -1,139 +0,0 @@
-/* A Bison parser, made by GNU Bison 2.3.  */
-
-/* Skeleton interface for Bison's Yacc-like parsers in C
-
-   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
-   Free Software Foundation, Inc.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
-   any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301, USA.  */
-
-/* As a special exception, you may create a larger work that contains
-   part or all of the Bison parser skeleton and distribute that work
-   under terms of your choice, so long as that work isn't itself a
-   parser generator using the skeleton or a modified version thereof
-   as a parser skeleton.  Alternatively, if you modify or redistribute
-   the parser skeleton itself, you may (at your option) remove this
-   special exception, which will cause the skeleton and the resulting
-   Bison output files to be licensed under the GNU General Public
-   License without this special exception.
-
-   This special exception was added by the Free Software Foundation in
-   version 2.2 of Bison.  */
-
-/* Tokens.  */
-#ifndef YYTOKENTYPE
-# define YYTOKENTYPE
-   /* Put the tokens into the symbol table, so that GDB and other debuggers
-      know about them.  */
-   enum yytokentype {
-     LTYPE0 = 258,
-     LTYPE1 = 259,
-     LTYPE2 = 260,
-     LTYPE3 = 261,
-     LTYPE4 = 262,
-     LTYPEC = 263,
-     LTYPED = 264,
-     LTYPEN = 265,
-     LTYPER = 266,
-     LTYPET = 267,
-     LTYPEG = 268,
-     LTYPEPC = 269,
-     LTYPES = 270,
-     LTYPEM = 271,
-     LTYPEI = 272,
-     LTYPEXC = 273,
-     LTYPEX = 274,
-     LTYPERT = 275,
-     LTYPEF = 276,
-     LCONST = 277,
-     LFP = 278,
-     LPC = 279,
-     LSB = 280,
-     LBREG = 281,
-     LLREG = 282,
-     LSREG = 283,
-     LFREG = 284,
-     LMREG = 285,
-     LXREG = 286,
-     LFCONST = 287,
-     LSCONST = 288,
-     LSP = 289,
-     LNAME = 290,
-     LLAB = 291,
-     LVAR = 292
-   };
-#endif
-/* Tokens.  */
-#define LTYPE0 258
-#define LTYPE1 259
-#define LTYPE2 260
-#define LTYPE3 261
-#define LTYPE4 262
-#define LTYPEC 263
-#define LTYPED 264
-#define LTYPEN 265
-#define LTYPER 266
-#define LTYPET 267
-#define LTYPEG 268
-#define LTYPEPC 269
-#define LTYPES 270
-#define LTYPEM 271
-#define LTYPEI 272
-#define LTYPEXC 273
-#define LTYPEX 274
-#define LTYPERT 275
-#define LTYPEF 276
-#define LCONST 277
-#define LFP 278
-#define LPC 279
-#define LSB 280
-#define LBREG 281
-#define LLREG 282
-#define LSREG 283
-#define LFREG 284
-#define LMREG 285
-#define LXREG 286
-#define LFCONST 287
-#define LSCONST 288
-#define LSP 289
-#define LNAME 290
-#define LLAB 291
-#define LVAR 292
-
-
-
-
-#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-typedef union YYSTYPE
-#line 38 "a.y"
-{
-	Sym	*sym;
-	vlong	lval;
-	double	dval;
-	char	sval[8];
-	Addr	addr;
-	Addr2	addr2;
-}
-/* Line 1529 of yacc.c.  */
-#line 132 "y.tab.h"
-	YYSTYPE;
-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
-# define YYSTYPE_IS_DECLARED 1
-# define YYSTYPE_IS_TRIVIAL 1
-#endif
-
-extern YYSTYPE yylval;
-
diff --git a/src/cmd/6c/Makefile b/src/cmd/6c/Makefile
deleted file mode 100644
index 3f528d7..0000000
--- a/src/cmd/6c/Makefile
+++ /dev/null
@@ -1,5 +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.
-
-include ../../Make.dist
diff --git a/src/cmd/6c/cgen.c b/src/cmd/6c/cgen.c
deleted file mode 100644
index 68dd7bb..0000000
--- a/src/cmd/6c/cgen.c
+++ /dev/null
@@ -1,2046 +0,0 @@
-// Inferno utils/6c/cgen.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/cgen.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include "gc.h"
-#include "../../runtime/funcdata.h"
-
-/* ,x/^(print|prtree)\(/i/\/\/ */
-int castup(Type*, Type*);
-int vaddr(Node *n, int a);
-
-void
-cgen(Node *n, Node *nn)
-{
-	Node *l, *r, *t;
-	Prog *p1;
-	Node nod, nod1, nod2, nod3, nod4;
-	int o, hardleft;
-	int32 v, curs;
-	vlong c;
-
-	if(debug['g']) {
-		prtree(nn, "cgen lhs");
-		prtree(n, "cgen");
-	}
-	if(n == Z || n->type == T)
-		return;
-	if(typesu[n->type->etype] && (n->op != OFUNC || nn != Z)) {
-		sugen(n, nn, n->type->width);
-		return;
-	}
-	l = n->left;
-	r = n->right;
-	o = n->op;
-	
-	if(n->op == OEXREG || (nn != Z && nn->op == OEXREG)) {
-		gmove(n, nn);
-		return;
-	}
-
-	if(n->addable >= INDEXED) {
-		if(nn == Z) {
-			switch(o) {
-			default:
-				nullwarn(Z, Z);
-				break;
-			case OINDEX:
-				nullwarn(l, r);
-				break;
-			}
-			return;
-		}
-		gmove(n, nn);
-		return;
-	}
-	curs = cursafe;
-
-	if(l->complex >= FNX)
-	if(r != Z && r->complex >= FNX)
-	switch(o) {
-	default:
-		if(cond(o) && typesu[l->type->etype])
-			break;
-
-		regret(&nod, r, 0, 0);
-		cgen(r, &nod);
-
-		regsalloc(&nod1, r);
-		gmove(&nod, &nod1);
-
-		regfree(&nod);
-		nod = *n;
-		nod.right = &nod1;
-
-		cgen(&nod, nn);
-		return;
-
-	case OFUNC:
-	case OCOMMA:
-	case OANDAND:
-	case OOROR:
-	case OCOND:
-	case ODOT:
-		break;
-	}
-
-	hardleft = l->addable < INDEXED || l->complex >= FNX;
-	switch(o) {
-	default:
-		diag(n, "unknown op in cgen: %O", o);
-		break;
-
-	case ONEG:
-	case OCOM:
-		if(nn == Z) {
-			nullwarn(l, Z);
-			break;
-		}
-		regalloc(&nod, l, nn);
-		cgen(l, &nod);
-		gopcode(o, n->type, Z, &nod);
-		gmove(&nod, nn);
-		regfree(&nod);
-		break;
-
-	case OAS:
-		if(l->op == OBIT)
-			goto bitas;
-		if(!hardleft) {
-			if(nn != Z || r->addable < INDEXED || hardconst(r)) {
-				if(r->complex >= FNX && nn == Z)
-					regret(&nod, r, 0, 0);
-				else
-					regalloc(&nod, r, nn);
-				cgen(r, &nod);
-				gmove(&nod, l);
-				if(nn != Z)
-					gmove(&nod, nn);
-				regfree(&nod);
-			} else
-				gmove(r, l);
-			break;
-		}
-		if(l->complex >= r->complex) {
-			if(l->op == OINDEX && immconst(r)) {
-				gmove(r, l);
-				break;
-			}
-			reglcgen(&nod1, l, Z);
-			if(r->addable >= INDEXED && !hardconst(r)) {
-				gmove(r, &nod1);
-				if(nn != Z)
-					gmove(r, nn);
-				regfree(&nod1);
-				break;
-			}
-			regalloc(&nod, r, nn);
-			cgen(r, &nod);
-		} else {
-			regalloc(&nod, r, nn);
-			cgen(r, &nod);
-			reglcgen(&nod1, l, Z);
-		}
-		gmove(&nod, &nod1);
-		regfree(&nod);
-		regfree(&nod1);
-		break;
-
-	bitas:
-		n = l->left;
-		regalloc(&nod, r, nn);
-		if(l->complex >= r->complex) {
-			reglcgen(&nod1, n, Z);
-			cgen(r, &nod);
-		} else {
-			cgen(r, &nod);
-			reglcgen(&nod1, n, Z);
-		}
-		regalloc(&nod2, n, Z);
-		gmove(&nod1, &nod2);
-		bitstore(l, &nod, &nod1, &nod2, nn);
-		break;
-
-	case OBIT:
-		if(nn == Z) {
-			nullwarn(l, Z);
-			break;
-		}
-		bitload(n, &nod, Z, Z, nn);
-		gmove(&nod, nn);
-		regfree(&nod);
-		break;
-
-	case OLSHR:
-	case OASHL:
-	case OASHR:
-		if(nn == Z) {
-			nullwarn(l, r);
-			break;
-		}
-		if(r->op == OCONST) {
-			if(r->vconst == 0) {
-				cgen(l, nn);
-				break;
-			}
-			regalloc(&nod, l, nn);
-			cgen(l, &nod);
-			if(o == OASHL && r->vconst == 1)
-				gopcode(OADD, n->type, &nod, &nod);
-			else
-				gopcode(o, n->type, r, &nod);
-			gmove(&nod, nn);
-			regfree(&nod);
-			break;
-		}
-
-		/*
-		 * get nod to be D_CX
-		 */
-		if(nodreg(&nod, nn, D_CX)) {
-			regsalloc(&nod1, n);
-			gmove(&nod, &nod1);
-			cgen(n, &nod);		/* probably a bug */
-			gmove(&nod, nn);
-			gmove(&nod1, &nod);
-			break;
-		}
-		reg[D_CX]++;
-		if(nn->op == OREGISTER && nn->reg == D_CX)
-			regalloc(&nod1, l, Z);
-		else
-			regalloc(&nod1, l, nn);
-		if(r->complex >= l->complex) {
-			cgen(r, &nod);
-			cgen(l, &nod1);
-		} else {
-			cgen(l, &nod1);
-			cgen(r, &nod);
-		}
-		gopcode(o, n->type, &nod, &nod1);
-		gmove(&nod1, nn);
-		regfree(&nod);
-		regfree(&nod1);
-		break;
-
-	case OADD:
-	case OSUB:
-	case OOR:
-	case OXOR:
-	case OAND:
-		if(nn == Z) {
-			nullwarn(l, r);
-			break;
-		}
-		if(typefd[n->type->etype])
-			goto fop;
-		if(r->op == OCONST) {
-			if(r->vconst == 0 && o != OAND) {
-				cgen(l, nn);
-				break;
-			}
-		}
-		if(n->op == OOR && l->op == OASHL && r->op == OLSHR
-		&& l->right->op == OCONST && r->right->op == OCONST
-		&& l->left->op == ONAME && r->left->op == ONAME
-		&& l->left->sym == r->left->sym
-		&& l->right->vconst + r->right->vconst == 8 * l->left->type->width) {
-			regalloc(&nod, l->left, nn);
-			cgen(l->left, &nod);
-			gopcode(OROTL, n->type, l->right, &nod);
-			gmove(&nod, nn);
-			regfree(&nod);
-			break;
-		}
-		if(n->op == OADD && l->op == OASHL && l->right->op == OCONST
-		&& (r->op != OCONST || r->vconst < -128 || r->vconst > 127)) {
-			c = l->right->vconst;
-			if(c > 0 && c <= 3) {
-				if(l->left->complex >= r->complex) {
-					regalloc(&nod, l->left, nn);
-					cgen(l->left, &nod);
-					if(r->addable < INDEXED) {
-						regalloc(&nod1, r, Z);
-						cgen(r, &nod1);
-						genmuladd(&nod, &nod, 1 << c, &nod1);
-						regfree(&nod1);
-					}
-					else
-						genmuladd(&nod, &nod, 1 << c, r);
-				}
-				else {
-					regalloc(&nod, r, nn);
-					cgen(r, &nod);
-					regalloc(&nod1, l->left, Z);
-					cgen(l->left, &nod1);
-					genmuladd(&nod, &nod1, 1 << c, &nod);
-					regfree(&nod1);
-				}
-				gmove(&nod, nn);
-				regfree(&nod);
-				break;
-			}
-		}
-		if(r->addable >= INDEXED && !hardconst(r)) {
-			regalloc(&nod, l, nn);
-			cgen(l, &nod);
-			gopcode(o, n->type, r, &nod);
-			gmove(&nod, nn);
-			regfree(&nod);
-			break;
-		}
-		if(l->complex >= r->complex) {
-			regalloc(&nod, l, nn);
-			cgen(l, &nod);
-			regalloc(&nod1, r, Z);
-			cgen(r, &nod1);
-			gopcode(o, n->type, &nod1, &nod);
-		} else {
-			regalloc(&nod1, r, nn);
-			cgen(r, &nod1);
-			regalloc(&nod, l, Z);
-			cgen(l, &nod);
-			gopcode(o, n->type, &nod1, &nod);
-		}
-		gmove(&nod, nn);
-		regfree(&nod);
-		regfree(&nod1);
-		break;
-
-	case OLMOD:
-	case OMOD:
-	case OLMUL:
-	case OLDIV:
-	case OMUL:
-	case ODIV:
-		if(nn == Z) {
-			nullwarn(l, r);
-			break;
-		}
-		if(typefd[n->type->etype])
-			goto fop;
-		if(r->op == OCONST && typechl[n->type->etype]) {	/* TO DO */
-			SET(v);
-			switch(o) {
-			case ODIV:
-			case OMOD:
-				c = r->vconst;
-				if(c < 0)
-					c = -c;
-				v = xlog2(c);
-				if(v < 0)
-					break;
-				/* fall thru */
-			case OMUL:
-			case OLMUL:
-				regalloc(&nod, l, nn);
-				cgen(l, &nod);
-				switch(o) {
-				case OMUL:
-				case OLMUL:
-					mulgen(n->type, r, &nod);
-					break;
-				case ODIV:
-					sdiv2(r->vconst, v, l, &nod);
-					break;
-				case OMOD:
-					smod2(r->vconst, v, l, &nod);
-					break;
-				}
-				gmove(&nod, nn);
-				regfree(&nod);
-				goto done;
-			case OLDIV:
-				c = r->vconst;
-				if((c & 0x80000000) == 0)
-					break;
-				regalloc(&nod1, l, Z);
-				cgen(l, &nod1);
-				regalloc(&nod, l, nn);
-				zeroregm(&nod);
-				gins(ACMPL, &nod1, nodconst(c));
-				gins(ASBBL, nodconst(-1), &nod);
-				regfree(&nod1);
-				gmove(&nod, nn);
-				regfree(&nod);
-				goto done;
-			}
-		}
-
-		if(o == OMUL || o == OLMUL) {
-			if(l->addable >= INDEXED) {
-				t = l;
-				l = r;
-				r = t;
-			}
-			reg[D_DX]++; // for gopcode case OMUL
-			regalloc(&nod, l, nn);
-			cgen(l, &nod);
-			if(r->addable < INDEXED || hardconst(r)) {
-				regalloc(&nod1, r, Z);
-				cgen(r, &nod1);
-				gopcode(OMUL, n->type, &nod1, &nod);
-				regfree(&nod1);
-			}else
-				gopcode(OMUL, n->type, r, &nod);	/* addressible */
-			gmove(&nod, nn);
-			regfree(&nod);
-			reg[D_DX]--;
-			break;
-		}
-
-		/*
-		 * get nod to be D_AX
-		 * get nod1 to be D_DX
-		 */
-		if(nodreg(&nod, nn, D_AX)) {
-			regsalloc(&nod2, n);
-			gmove(&nod, &nod2);
-			v = reg[D_AX];
-			reg[D_AX] = 0;
-
-			if(isreg(l, D_AX)) {
-				nod3 = *n;
-				nod3.left = &nod2;
-				cgen(&nod3, nn);
-			} else
-			if(isreg(r, D_AX)) {
-				nod3 = *n;
-				nod3.right = &nod2;
-				cgen(&nod3, nn);
-			} else
-				cgen(n, nn);
-
-			gmove(&nod2, &nod);
-			reg[D_AX] = v;
-			break;
-		}
-		if(nodreg(&nod1, nn, D_DX)) {
-			regsalloc(&nod2, n);
-			gmove(&nod1, &nod2);
-			v = reg[D_DX];
-			reg[D_DX] = 0;
-
-			if(isreg(l, D_DX)) {
-				nod3 = *n;
-				nod3.left = &nod2;
-				cgen(&nod3, nn);
-			} else
-			if(isreg(r, D_DX)) {
-				nod3 = *n;
-				nod3.right = &nod2;
-				cgen(&nod3, nn);
-			} else
-				cgen(n, nn);
-
-			gmove(&nod2, &nod1);
-			reg[D_DX] = v;
-			break;
-		}
-		reg[D_AX]++;
-
-		if(r->op == OCONST && (o == ODIV || o == OLDIV) && immconst(r) && typechl[r->type->etype]) {
-			reg[D_DX]++;
-			if(l->addable < INDEXED) {
-				regalloc(&nod2, l, Z);
-				cgen(l, &nod2);
-				l = &nod2;
-			}
-			if(o == ODIV)
-				sdivgen(l, r, &nod, &nod1);
-			else
-				udivgen(l, r, &nod, &nod1);
-			gmove(&nod1, nn);
-			if(l == &nod2)
-				regfree(l);
-			goto freeaxdx;
-		}
-
-		if(l->complex >= r->complex) {
-			cgen(l, &nod);
-			reg[D_DX]++;
-			if(o == ODIV || o == OMOD)
-				gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z);
-			if(o == OLDIV || o == OLMOD)
-				zeroregm(&nod1);
-			if(r->addable < INDEXED || r->op == OCONST) {
-				regsalloc(&nod3, r);
-				cgen(r, &nod3);
-				gopcode(o, n->type, &nod3, Z);
-			} else
-				gopcode(o, n->type, r, Z);
-		} else {
-			regsalloc(&nod3, r);
-			cgen(r, &nod3);
-			cgen(l, &nod);
-			reg[D_DX]++;
-			if(o == ODIV || o == OMOD)
-				gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z);
-			if(o == OLDIV || o == OLMOD)
-				zeroregm(&nod1);
-			gopcode(o, n->type, &nod3, Z);
-		}
-		if(o == OMOD || o == OLMOD)
-			gmove(&nod1, nn);
-		else
-			gmove(&nod, nn);
-	freeaxdx:
-		regfree(&nod);
-		regfree(&nod1);
-		break;
-
-	case OASLSHR:
-	case OASASHL:
-	case OASASHR:
-		if(r->op == OCONST)
-			goto asand;
-		if(l->op == OBIT)
-			goto asbitop;
-		if(typefd[n->type->etype])
-			goto asand;	/* can this happen? */
-
-		/*
-		 * get nod to be D_CX
-		 */
-		if(nodreg(&nod, nn, D_CX)) {
-			regsalloc(&nod1, n);
-			gmove(&nod, &nod1);
-			cgen(n, &nod);
-			if(nn != Z)
-				gmove(&nod, nn);
-			gmove(&nod1, &nod);
-			break;
-		}
-		reg[D_CX]++;
-
-		if(r->complex >= l->complex) {
-			cgen(r, &nod);
-			if(hardleft)
-				reglcgen(&nod1, l, Z);
-			else
-				nod1 = *l;
-		} else {
-			if(hardleft)
-				reglcgen(&nod1, l, Z);
-			else
-				nod1 = *l;
-			cgen(r, &nod);
-		}
-
-		gopcode(o, l->type, &nod, &nod1);
-		regfree(&nod);
-		if(nn != Z)
-			gmove(&nod1, nn);
-		if(hardleft)
-			regfree(&nod1);
-		break;
-
-	case OASAND:
-	case OASADD:
-	case OASSUB:
-	case OASXOR:
-	case OASOR:
-	asand:
-		if(l->op == OBIT)
-			goto asbitop;
-		if(typefd[l->type->etype] || typefd[r->type->etype])
-			goto asfop;
-		if(l->complex >= r->complex) {
-			if(hardleft)
-				reglcgen(&nod, l, Z);
-			else
-				nod = *l;
-			if(!immconst(r)) {
-				regalloc(&nod1, r, nn);
-				cgen(r, &nod1);
-				gopcode(o, l->type, &nod1, &nod);
-				regfree(&nod1);
-			} else
-				gopcode(o, l->type, r, &nod);
-		} else {
-			regalloc(&nod1, r, nn);
-			cgen(r, &nod1);
-			if(hardleft)
-				reglcgen(&nod, l, Z);
-			else
-				nod = *l;
-			gopcode(o, l->type, &nod1, &nod);
-			regfree(&nod1);
-		}
-		if(nn != Z)
-			gmove(&nod, nn);
-		if(hardleft)
-			regfree(&nod);
-		break;
-
-	asfop:
-		if(l->complex >= r->complex) {
-			if(hardleft)
-				reglcgen(&nod, l, Z);
-			else
-				nod = *l;
-			if(r->addable < INDEXED){
-				regalloc(&nod1, r, nn);
-				cgen(r, &nod1);
-			}else
-				nod1 = *r;
-			regalloc(&nod2, r, Z);
-			gmove(&nod, &nod2);
-			gopcode(o, r->type, &nod1, &nod2);
-			gmove(&nod2, &nod);
-			regfree(&nod2);
-			if(r->addable < INDEXED)
-				regfree(&nod1);
-		} else {
-			regalloc(&nod1, r, nn);
-			cgen(r, &nod1);
-			if(hardleft)
-				reglcgen(&nod, l, Z);
-			else
-				nod = *l;
-			if(o != OASMUL && o != OASADD) {
-				regalloc(&nod2, r, Z);
-				gmove(&nod, &nod2);
-				gopcode(o, r->type, &nod1, &nod2);
-				regfree(&nod1);
-				gmove(&nod2, &nod);
-				regfree(&nod2);
-			} else {
-				gopcode(o, r->type, &nod, &nod1);
-				gmove(&nod1, &nod);
-				regfree(&nod1);
-			}
-		}
-		if(nn != Z)
-			gmove(&nod, nn);
-		if(hardleft)
-			regfree(&nod);
-		break;
-
-	case OASLMUL:
-	case OASLDIV:
-	case OASLMOD:
-	case OASMUL:
-	case OASDIV:
-	case OASMOD:
-		if(l->op == OBIT)
-			goto asbitop;
-		if(typefd[n->type->etype] || typefd[r->type->etype])
-			goto asfop;
-		if(r->op == OCONST && typechl[n->type->etype]) {
-			SET(v);
-			switch(o) {
-			case OASDIV:
-			case OASMOD:
-				c = r->vconst;
-				if(c < 0)
-					c = -c;
-				v = xlog2(c);
-				if(v < 0)
-					break;
-				/* fall thru */
-			case OASMUL:
-			case OASLMUL:
-				if(hardleft)
-					reglcgen(&nod2, l, Z);
-				else
-					nod2 = *l;
-				regalloc(&nod, l, nn);
-				cgen(&nod2, &nod);
-				switch(o) {
-				case OASMUL:
-				case OASLMUL:
-					mulgen(n->type, r, &nod);
-					break;
-				case OASDIV:
-					sdiv2(r->vconst, v, l, &nod);
-					break;
-				case OASMOD:
-					smod2(r->vconst, v, l, &nod);
-					break;
-				}
-			havev:
-				gmove(&nod, &nod2);
-				if(nn != Z)
-					gmove(&nod, nn);
-				if(hardleft)
-					regfree(&nod2);
-				regfree(&nod);
-				goto done;
-			case OASLDIV:
-				c = r->vconst;
-				if((c & 0x80000000) == 0)
-					break;
-				if(hardleft)
-					reglcgen(&nod2, l, Z);
-				else
-					nod2 = *l;
-				regalloc(&nod1, l, nn);
-				cgen(&nod2, &nod1);
-				regalloc(&nod, l, nn);
-				zeroregm(&nod);
-				gins(ACMPL, &nod1, nodconst(c));
-				gins(ASBBL, nodconst(-1), &nod);
-				regfree(&nod1);
-				goto havev;
-			}
-		}
-
-		if(o == OASMUL) {
-			/* should favour AX */
-			regalloc(&nod, l, nn);
-			if(r->complex >= FNX) {
-				regalloc(&nod1, r, Z);
-				cgen(r, &nod1);
-				r = &nod1;
-			}
-			if(hardleft)
-				reglcgen(&nod2, l, Z);
-			else
-				nod2 = *l;
-			cgen(&nod2, &nod);
-			if(r->addable < INDEXED || hardconst(r)) {
-				if(r->complex < FNX) {
-					regalloc(&nod1, r, Z);
-					cgen(r, &nod1);
-				}
-				gopcode(OASMUL, n->type, &nod1, &nod);
-				regfree(&nod1);
-			}
-			else
-				gopcode(OASMUL, n->type, r, &nod);
-			if(r == &nod1)
-				regfree(r);
-			gmove(&nod, &nod2);
-			if(nn != Z)
-				gmove(&nod, nn);
-			regfree(&nod);
-			if(hardleft)
-				regfree(&nod2);
-			break;
-		}
-
-		/*
-		 * get nod to be D_AX
-		 * get nod1 to be D_DX
-		 */
-		if(nodreg(&nod, nn, D_AX)) {
-			regsalloc(&nod2, n);
-			gmove(&nod, &nod2);
-			v = reg[D_AX];
-			reg[D_AX] = 0;
-
-			if(isreg(l, D_AX)) {
-				nod3 = *n;
-				nod3.left = &nod2;
-				cgen(&nod3, nn);
-			} else
-			if(isreg(r, D_AX)) {
-				nod3 = *n;
-				nod3.right = &nod2;
-				cgen(&nod3, nn);
-			} else
-				cgen(n, nn);
-
-			gmove(&nod2, &nod);
-			reg[D_AX] = v;
-			break;
-		}
-		if(nodreg(&nod1, nn, D_DX)) {
-			regsalloc(&nod2, n);
-			gmove(&nod1, &nod2);
-			v = reg[D_DX];
-			reg[D_DX] = 0;
-
-			if(isreg(l, D_DX)) {
-				nod3 = *n;
-				nod3.left = &nod2;
-				cgen(&nod3, nn);
-			} else
-			if(isreg(r, D_DX)) {
-				nod3 = *n;
-				nod3.right = &nod2;
-				cgen(&nod3, nn);
-			} else
-				cgen(n, nn);
-
-			gmove(&nod2, &nod1);
-			reg[D_DX] = v;
-			break;
-		}
-		reg[D_AX]++;
-		reg[D_DX]++;
-
-		if(l->complex >= r->complex) {
-			if(hardleft)
-				reglcgen(&nod2, l, Z);
-			else
-				nod2 = *l;
-			cgen(&nod2, &nod);
-			if(r->op == OCONST && typechl[r->type->etype]) {
-				switch(o) {
-				case OASDIV:
-					sdivgen(&nod2, r, &nod, &nod1);
-					goto divdone;
-				case OASLDIV:
-					udivgen(&nod2, r, &nod, &nod1);
-				divdone:
-					gmove(&nod1, &nod2);
-					if(nn != Z)
-						gmove(&nod1, nn);
-					goto freelxaxdx;
-				}
-			}
-			if(o == OASDIV || o == OASMOD)
-				gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z);
-			if(o == OASLDIV || o == OASLMOD)
-				zeroregm(&nod1);
-			if(r->addable < INDEXED || r->op == OCONST ||
-			   !typeil[r->type->etype]) {
-				regalloc(&nod3, r, Z);
-				cgen(r, &nod3);
-				gopcode(o, l->type, &nod3, Z);
-				regfree(&nod3);
-			} else
-				gopcode(o, n->type, r, Z);
-		} else {
-			regalloc(&nod3, r, Z);
-			cgen(r, &nod3);
-			if(hardleft)
-				reglcgen(&nod2, l, Z);
-			else
-				nod2 = *l;
-			cgen(&nod2, &nod);
-			if(o == OASDIV || o == OASMOD)
-				gins(typechl[l->type->etype]? ACDQ: ACQO, Z, Z);
-			if(o == OASLDIV || o == OASLMOD)
-				zeroregm(&nod1);
-			gopcode(o, l->type, &nod3, Z);
-			regfree(&nod3);
-		}
-		if(o == OASMOD || o == OASLMOD) {
-			gmove(&nod1, &nod2);
-			if(nn != Z)
-				gmove(&nod1, nn);
-		} else {
-			gmove(&nod, &nod2);
-			if(nn != Z)
-				gmove(&nod, nn);
-		}
-	freelxaxdx:
-		if(hardleft)
-			regfree(&nod2);
-		regfree(&nod);
-		regfree(&nod1);
-		break;
-
-	fop:
-		if(l->complex >= r->complex) {
-			regalloc(&nod, l, nn);
-			cgen(l, &nod);
-			if(r->addable < INDEXED) {
-				regalloc(&nod1, r, Z);
-				cgen(r, &nod1);
-				gopcode(o, n->type, &nod1, &nod);
-				regfree(&nod1);
-			} else
-				gopcode(o, n->type, r, &nod);
-		} else {
-			/* TO DO: could do better with r->addable >= INDEXED */
-			regalloc(&nod1, r, Z);
-			cgen(r, &nod1);
-			regalloc(&nod, l, nn);
-			cgen(l, &nod);
-			gopcode(o, n->type, &nod1, &nod);
-			regfree(&nod1);
-		}
-		gmove(&nod, nn);
-		regfree(&nod);
-		break;
-
-	asbitop:
-		regalloc(&nod4, n, nn);
-		if(l->complex >= r->complex) {
-			bitload(l, &nod, &nod1, &nod2, &nod4);
-			regalloc(&nod3, r, Z);
-			cgen(r, &nod3);
-		} else {
-			regalloc(&nod3, r, Z);
-			cgen(r, &nod3);
-			bitload(l, &nod, &nod1, &nod2, &nod4);
-		}
-		gmove(&nod, &nod4);
-
-		{	/* TO DO: check floating point source */
-			Node onod;
-
-			/* incredible grot ... */
-			onod = nod3;
-			onod.op = o;
-			onod.complex = 2;
-			onod.addable = 0;
-			onod.type = tfield;
-			onod.left = &nod4;
-			onod.right = &nod3;
-			cgen(&onod, Z);
-		}
-		regfree(&nod3);
-		gmove(&nod4, &nod);
-		regfree(&nod4);
-		bitstore(l, &nod, &nod1, &nod2, nn);
-		break;
-
-	case OADDR:
-		if(nn == Z) {
-			nullwarn(l, Z);
-			break;
-		}
-		lcgen(l, nn);
-		break;
-
-	case OFUNC:
-		if(l->complex >= FNX) {
-			if(l->op != OIND)
-				diag(n, "bad function call");
-
-			regret(&nod, l->left, 0, 0);
-			cgen(l->left, &nod);
-			regsalloc(&nod1, l->left);
-			gmove(&nod, &nod1);
-			regfree(&nod);
-
-			nod = *n;
-			nod.left = &nod2;
-			nod2 = *l;
-			nod2.left = &nod1;
-			nod2.complex = 1;
-			cgen(&nod, nn);
-
-			return;
-		}
-		gargs(r, &nod, &nod1);
-		if(l->addable < INDEXED) {
-			reglcgen(&nod, l, nn);
-			nod.op = OREGISTER;
-			gopcode(OFUNC, n->type, Z, &nod);
-			regfree(&nod);
-		} else
-			gopcode(OFUNC, n->type, Z, l);
-		if(REGARG >= 0 && reg[REGARG])
-			reg[REGARG]--;
-		regret(&nod, n, l->type, 1); // update maxarg if nothing else
-		if(nn != Z)
-			gmove(&nod, nn);
-		if(nod.op == OREGISTER)
-			regfree(&nod);
-		break;
-
-	case OIND:
-		if(nn == Z) {
-			nullwarn(l, Z);
-			break;
-		}
-		regialloc(&nod, n, nn);
-		r = l;
-		while(r->op == OADD)
-			r = r->right;
-		if(sconst(r)) {
-			v = r->vconst;
-			r->vconst = 0;
-			cgen(l, &nod);
-			nod.xoffset += v;
-			r->vconst = v;
-		} else
-			cgen(l, &nod);
-		regind(&nod, n);
-		gmove(&nod, nn);
-		regfree(&nod);
-		break;
-
-	case OEQ:
-	case ONE:
-	case OLE:
-	case OLT:
-	case OGE:
-	case OGT:
-	case OLO:
-	case OLS:
-	case OHI:
-	case OHS:
-		if(nn == Z) {
-			nullwarn(l, r);
-			break;
-		}
-		boolgen(n, 1, nn);
-		break;
-
-	case OANDAND:
-	case OOROR:
-		boolgen(n, 1, nn);
-		if(nn == Z)
-			patch(p, pc);
-		break;
-
-	case ONOT:
-		if(nn == Z) {
-			nullwarn(l, Z);
-			break;
-		}
-		boolgen(n, 1, nn);
-		break;
-
-	case OCOMMA:
-		cgen(l, Z);
-		cgen(r, nn);
-		break;
-
-	case OCAST:
-		if(nn == Z) {
-			nullwarn(l, Z);
-			break;
-		}
-		/*
-		 * convert from types l->n->nn
-		 */
-		if(nocast(l->type, n->type) && nocast(n->type, nn->type)) {
-			/* both null, gen l->nn */
-			cgen(l, nn);
-			break;
-		}
-		if(ewidth[n->type->etype] < ewidth[l->type->etype]){
-			if(l->type->etype == TIND && typechlp[n->type->etype])
-				warn(n, "conversion of pointer to shorter integer");
-		}else if(0){
-			if(nocast(n->type, nn->type) || castup(n->type, nn->type)){
-				if(typefd[l->type->etype] != typefd[nn->type->etype])
-					regalloc(&nod, l, nn);
-				else
-					regalloc(&nod, nn, nn);
-				cgen(l, &nod);
-				gmove(&nod, nn);
-				regfree(&nod);
-				break;
-			}
-		}
-		regalloc(&nod, l, nn);
-		cgen(l, &nod);
-		regalloc(&nod1, n, &nod);
-		gmove(&nod, &nod1);
-		gmove(&nod1, nn);
-		regfree(&nod1);
-		regfree(&nod);
-		break;
-
-	case ODOT:
-		sugen(l, nodrat, l->type->width);
-		if(nn == Z)
-			break;
-		warn(n, "non-interruptable temporary");
-		nod = *nodrat;
-		if(!r || r->op != OCONST) {
-			diag(n, "DOT and no offset");
-			break;
-		}
-		nod.xoffset += (int32)r->vconst;
-		nod.type = n->type;
-		cgen(&nod, nn);
-		break;
-
-	case OCOND:
-		bcgen(l, 1);
-		p1 = p;
-		cgen(r->left, nn);
-		gbranch(OGOTO);
-		patch(p1, pc);
-		p1 = p;
-		cgen(r->right, nn);
-		patch(p1, pc);
-		break;
-
-	case OPOSTINC:
-	case OPOSTDEC:
-		v = 1;
-		if(l->type->etype == TIND)
-			v = l->type->link->width;
-		if(o == OPOSTDEC)
-			v = -v;
-		if(l->op == OBIT)
-			goto bitinc;
-		if(nn == Z)
-			goto pre;
-
-		if(hardleft)
-			reglcgen(&nod, l, Z);
-		else
-			nod = *l;
-
-		gmove(&nod, nn);
-		if(typefd[n->type->etype]) {
-			regalloc(&nod1, l, Z);
-			gmove(&nod, &nod1);
-			if(v < 0)
-				gopcode(OSUB, n->type, nodfconst(-v), &nod1);
-			else
-				gopcode(OADD, n->type, nodfconst(v), &nod1);
-			gmove(&nod1, &nod);
-			regfree(&nod1);
-		} else
-			gopcode(OADD, n->type, nodconst(v), &nod);
-		if(hardleft)
-			regfree(&nod);
-		break;
-
-	case OPREINC:
-	case OPREDEC:
-		v = 1;
-		if(l->type->etype == TIND)
-			v = l->type->link->width;
-		if(o == OPREDEC)
-			v = -v;
-		if(l->op == OBIT)
-			goto bitinc;
-
-	pre:
-		if(hardleft)
-			reglcgen(&nod, l, Z);
-		else
-			nod = *l;
-		if(typefd[n->type->etype]) {
-			regalloc(&nod1, l, Z);
-			gmove(&nod, &nod1);
-			if(v < 0)
-				gopcode(OSUB, n->type, nodfconst(-v), &nod1);
-			else
-				gopcode(OADD, n->type, nodfconst(v), &nod1);
-			gmove(&nod1, &nod);
-			regfree(&nod1);
-		} else
-			gopcode(OADD, n->type, nodconst(v), &nod);
-		if(nn != Z)
-			gmove(&nod, nn);
-		if(hardleft)
-			regfree(&nod);
-		break;
-
-	bitinc:
-		if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) {
-			bitload(l, &nod, &nod1, &nod2, Z);
-			gmove(&nod, nn);
-			gopcode(OADD, tfield, nodconst(v), &nod);
-			bitstore(l, &nod, &nod1, &nod2, Z);
-			break;
-		}
-		bitload(l, &nod, &nod1, &nod2, nn);
-		gopcode(OADD, tfield, nodconst(v), &nod);
-		bitstore(l, &nod, &nod1, &nod2, nn);
-		break;
-	}
-done:
-	cursafe = curs;
-}
-
-void
-reglcgen(Node *t, Node *n, Node *nn)
-{
-	Node *r;
-	int32 v;
-
-	regialloc(t, n, nn);
-	if(n->op == OIND) {
-		r = n->left;
-		while(r->op == OADD)
-			r = r->right;
-		if(sconst(r)) {
-			v = r->vconst;
-			r->vconst = 0;
-			lcgen(n, t);
-			t->xoffset += v;
-			r->vconst = v;
-			regind(t, n);
-			return;
-		}
-	}
-	lcgen(n, t);
-	regind(t, n);
-}
-
-void
-lcgen(Node *n, Node *nn)
-{
-	Prog *p1;
-	Node nod;
-
-	if(debug['g']) {
-		prtree(nn, "lcgen lhs");
-		prtree(n, "lcgen");
-	}
-	if(n == Z || n->type == T)
-		return;
-	if(nn == Z) {
-		nn = &nod;
-		regalloc(&nod, n, Z);
-	}
-	switch(n->op) {
-	default:
-		if(n->addable < INDEXED) {
-			diag(n, "unknown op in lcgen: %O", n->op);
-			break;
-		}
-		gopcode(OADDR, n->type, n, nn);
-		break;
-
-	case OCOMMA:
-		cgen(n->left, n->left);
-		lcgen(n->right, nn);
-		break;
-
-	case OIND:
-		cgen(n->left, nn);
-		break;
-
-	case OCOND:
-		bcgen(n->left, 1);
-		p1 = p;
-		lcgen(n->right->left, nn);
-		gbranch(OGOTO);
-		patch(p1, pc);
-		p1 = p;
-		lcgen(n->right->right, nn);
-		patch(p1, pc);
-		break;
-	}
-}
-
-void
-bcgen(Node *n, int true)
-{
-
-	if(n->type == T)
-		gbranch(OGOTO);
-	else
-		boolgen(n, true, Z);
-}
-
-void
-boolgen(Node *n, int true, Node *nn)
-{
-	int o;
-	Prog *p1, *p2, *p3;
-	Node *l, *r, nod, nod1;
-	int32 curs;
-
-	if(debug['g']) {
-		print("boolgen %d\n", true);
-		prtree(nn, "boolgen lhs");
-		prtree(n, "boolgen");
-	}
-	curs = cursafe;
-	l = n->left;
-	r = n->right;
-	switch(n->op) {
-
-	default:
-		o = ONE;
-		if(true)
-			o = OEQ;
-		/* bad, 13 is address of external that becomes constant */
-		if(n->addable >= INDEXED && n->addable != 13) {
-			if(typefd[n->type->etype]) {
-				regalloc(&nod1, n, Z);
-				gmove(nodfconst(0.0), &nod1);	/* TO DO: FREGZERO */
-				gopcode(o, n->type, n, &nod1);
-				regfree(&nod1);
-			} else
-				gopcode(o, n->type, n, nodconst(0));
-			goto com;
-		}
-		regalloc(&nod, n, nn);
-		cgen(n, &nod);
-		if(typefd[n->type->etype]) {
-			regalloc(&nod1, n, Z);
-			gmove(nodfconst(0.0), &nod1);	/* TO DO: FREGZERO */
-			gopcode(o, n->type, &nod, &nod1);
-			regfree(&nod1);
-		} else
-			gopcode(o, n->type, &nod, nodconst(0));
-		regfree(&nod);
-		goto com;
-
-	case OCONST:
-		o = vconst(n);
-		if(!true)
-			o = !o;
-		gbranch(OGOTO);
-		if(o) {
-			p1 = p;
-			gbranch(OGOTO);
-			patch(p1, pc);
-		}
-		goto com;
-
-	case OCOMMA:
-		cgen(l, Z);
-		boolgen(r, true, nn);
-		break;
-
-	case ONOT:
-		boolgen(l, !true, nn);
-		break;
-
-	case OCOND:
-		bcgen(l, 1);
-		p1 = p;
-		bcgen(r->left, true);
-		p2 = p;
-		gbranch(OGOTO);
-		patch(p1, pc);
-		p1 = p;
-		bcgen(r->right, !true);
-		patch(p2, pc);
-		p2 = p;
-		gbranch(OGOTO);
-		patch(p1, pc);
-		patch(p2, pc);
-		goto com;
-
-	case OANDAND:
-		if(!true)
-			goto caseor;
-
-	caseand:
-		bcgen(l, true);
-		p1 = p;
-		bcgen(r, !true);
-		p2 = p;
-		patch(p1, pc);
-		gbranch(OGOTO);
-		patch(p2, pc);
-		goto com;
-
-	case OOROR:
-		if(!true)
-			goto caseand;
-
-	caseor:
-		bcgen(l, !true);
-		p1 = p;
-		bcgen(r, !true);
-		p2 = p;
-		gbranch(OGOTO);
-		patch(p1, pc);
-		patch(p2, pc);
-		goto com;
-
-	case OEQ:
-	case ONE:
-	case OLE:
-	case OLT:
-	case OGE:
-	case OGT:
-	case OHI:
-	case OHS:
-	case OLO:
-	case OLS:
-		o = n->op;
-		if(true && typefd[l->type->etype] && (o == OEQ || o == ONE)) {
-			// Cannot rewrite !(l == r) into l != r with float64; it breaks NaNs.
-			// Jump around instead.
-			boolgen(n, 0, Z);
-			p1 = p;
-			gbranch(OGOTO);
-			patch(p1, pc);
-			goto com;
-		}
-		if(true)
-			o = comrel[relindex(o)];
-		if(l->complex >= FNX && r->complex >= FNX) {
-			regret(&nod, r, 0, 0);
-			cgen(r, &nod);
-			regsalloc(&nod1, r);
-			gmove(&nod, &nod1);
-			regfree(&nod);
-			nod = *n;
-			nod.right = &nod1;
-			boolgen(&nod, true, nn);
-			break;
-		}
-		if(immconst(l)) {
-			// NOTE: Reversing the comparison here is wrong
-			// for floating point ordering comparisons involving NaN,
-			// but we don't have any of those yet so we don't
-			// bother worrying about it.
-			o = invrel[relindex(o)];
-			/* bad, 13 is address of external that becomes constant */
-			if(r->addable < INDEXED || r->addable == 13) {
-				regalloc(&nod, r, nn);
-				cgen(r, &nod);
-				gopcode(o, l->type, &nod, l);
-				regfree(&nod);
-			} else
-				gopcode(o, l->type, r, l);
-			goto com;
-		}
-		if(typefd[l->type->etype])
-			o = invrel[relindex(logrel[relindex(o)])];
-		if(l->complex >= r->complex) {
-			regalloc(&nod, l, nn);
-			cgen(l, &nod);
-			if(r->addable < INDEXED || hardconst(r) || typefd[l->type->etype]) {
-				regalloc(&nod1, r, Z);
-				cgen(r, &nod1);
-				gopcode(o, l->type, &nod, &nod1);
-				regfree(&nod1);
-			} else {
-				gopcode(o, l->type, &nod, r);
-			}
-			regfree(&nod);
-			goto fixfloat;
-		}
-		regalloc(&nod, r, nn);
-		cgen(r, &nod);
-		if(l->addable < INDEXED || l->addable == 13 || hardconst(l)) {
-			regalloc(&nod1, l, Z);
-			cgen(l, &nod1);
-			if(typechl[l->type->etype] && ewidth[l->type->etype] <= ewidth[TINT])
-				gopcode(o, types[TINT], &nod1, &nod);
-			else
-				gopcode(o, l->type, &nod1, &nod);
-			regfree(&nod1);
-		} else
-			gopcode(o, l->type, l, &nod);
-		regfree(&nod);
-	fixfloat:
-		if(typefd[l->type->etype]) {
-			switch(o) {
-			case OEQ:
-				// Already emitted AJEQ; want AJEQ and AJPC.
-				p1 = p;
-				gbranch(OGOTO);
-				p2 = p;
-				patch(p1, pc);
-				gins(AJPC, Z, Z);
-				patch(p2, pc);
-				break;
-
-			case ONE:
-				// Already emitted AJNE; want AJNE or AJPS.
-				p1 = p;
-				gins(AJPS, Z, Z);
-				p2 = p;
-				gbranch(OGOTO);
-				p3 = p;
-				patch(p1, pc);
-				patch(p2, pc);
-				gbranch(OGOTO);
-				patch(p3, pc);
-				break;
-			}
-		}
-
-	com:
-		if(nn != Z) {
-			p1 = p;
-			gmove(nodconst(1L), nn);
-			gbranch(OGOTO);
-			p2 = p;
-			patch(p1, pc);
-			gmove(nodconst(0L), nn);
-			patch(p2, pc);
-		}
-		break;
-	}
-	cursafe = curs;
-}
-
-void
-sugen(Node *n, Node *nn, int32 w)
-{
-	Prog *p1;
-	Node nod0, nod1, nod2, nod3, nod4, *l, *r;
-	Type *t;
-	int c, mt, mo;
-	vlong o0, o1;
-
-	if(n == Z || n->type == T)
-		return;
-	if(debug['g']) {
-		prtree(nn, "sugen lhs");
-		prtree(n, "sugen");
-	}
-	if(nn == nodrat)
-		if(w > nrathole)
-			nrathole = w;
-	switch(n->op) {
-	case OIND:
-		if(nn == Z) {
-			nullwarn(n->left, Z);
-			break;
-		}
-
-	default:
-		goto copy;
-
-	case OCONST:
-		goto copy;
-
-	case ODOT:
-		l = n->left;
-		sugen(l, nodrat, l->type->width);
-		if(nn == Z)
-			break;
-		warn(n, "non-interruptable temporary");
-		nod1 = *nodrat;
-		r = n->right;
-		if(!r || r->op != OCONST) {
-			diag(n, "DOT and no offset");
-			break;
-		}
-		nod1.xoffset += (int32)r->vconst;
-		nod1.type = n->type;
-		sugen(&nod1, nn, w);
-		break;
-
-	case OSTRUCT:
-		/*
-		 * rewrite so lhs has no fn call
-		 */
-		if(nn != Z && side(nn)) {
-			nod1 = *n;
-			nod1.type = typ(TIND, n->type);
-			regret(&nod2, &nod1, 0, 0);
-			lcgen(nn, &nod2);
-			regsalloc(&nod0, &nod1);
-			cgen(&nod2, &nod0);
-			regfree(&nod2);
-
-			nod1 = *n;
-			nod1.op = OIND;
-			nod1.left = &nod0;
-			nod1.right = Z;
-			nod1.complex = 1;
-
-			sugen(n, &nod1, w);
-			return;
-		}
-
-		r = n->left;
-		for(t = n->type->link; t != T; t = t->down) {
-			l = r;
-			if(r->op == OLIST) {
-				l = r->left;
-				r = r->right;
-			}
-			if(nn == Z) {
-				cgen(l, nn);
-				continue;
-			}
-			/*
-			 * hand craft *(&nn + o) = l
-			 */
-			nod0 = znode;
-			nod0.op = OAS;
-			nod0.type = t;
-			nod0.left = &nod1;
-			nod0.right = nil;
-
-			nod1 = znode;
-			nod1.op = OIND;
-			nod1.type = t;
-			nod1.left = &nod2;
-
-			nod2 = znode;
-			nod2.op = OADD;
-			nod2.type = typ(TIND, t);
-			nod2.left = &nod3;
-			nod2.right = &nod4;
-
-			nod3 = znode;
-			nod3.op = OADDR;
-			nod3.type = nod2.type;
-			nod3.left = nn;
-
-			nod4 = znode;
-			nod4.op = OCONST;
-			nod4.type = nod2.type;
-			nod4.vconst = t->offset;
-
-			ccom(&nod0);
-			acom(&nod0);
-			xcom(&nod0);
-			nod0.addable = 0;
-			nod0.right = l;
-
-			// prtree(&nod0, "hand craft");
-			cgen(&nod0, Z);
-		}
-		break;
-
-	case OAS:
-		if(nn == Z) {
-			if(n->addable < INDEXED)
-				sugen(n->right, n->left, w);
-			break;
-		}
-
-		sugen(n->right, nodrat, w);
-		warn(n, "non-interruptable temporary");
-		sugen(nodrat, n->left, w);
-		sugen(nodrat, nn, w);
-		break;
-
-	case OFUNC:
-		if(!hasdotdotdot(n->left->type)) {
-			cgen(n, Z);
-			if(nn != Z) {
-				curarg -= n->type->width;
-				regret(&nod1, n, n->left->type, 1);
-				if(nn->complex >= FNX) {
-					regsalloc(&nod2, n);
-					cgen(&nod1, &nod2);
-					nod1 = nod2;
-				}
-				cgen(&nod1, nn);
-			}
-			break;
-		}
-		if(nn == Z) {
-			sugen(n, nodrat, w);
-			break;
-		}
-		if(nn->op != OIND) {
-			nn = new1(OADDR, nn, Z);
-			nn->type = types[TIND];
-			nn->addable = 0;
-		} else
-			nn = nn->left;
-		n = new(OFUNC, n->left, new(OLIST, nn, n->right));
-		n->type = types[TVOID];
-		n->left->type = types[TVOID];
-		cgen(n, Z);
-		break;
-
-	case OCOND:
-		bcgen(n->left, 1);
-		p1 = p;
-		sugen(n->right->left, nn, w);
-		gbranch(OGOTO);
-		patch(p1, pc);
-		p1 = p;
-		sugen(n->right->right, nn, w);
-		patch(p1, pc);
-		break;
-
-	case OCOMMA:
-		cgen(n->left, Z);
-		sugen(n->right, nn, w);
-		break;
-	}
-	return;
-
-copy:
-	if(nn == Z) {
-		switch(n->op) {
-		case OASADD:
-		case OASSUB:
-		case OASAND:
-		case OASOR:
-		case OASXOR:
-
-		case OASMUL:
-		case OASLMUL:
-
-
-		case OASASHL:
-		case OASASHR:
-		case OASLSHR:
-			break;
-
-		case OPOSTINC:
-		case OPOSTDEC:
-		case OPREINC:
-		case OPREDEC:
-			break;
-
-		default:
-			return;
-		}
-	}
-
-	if(n->complex >= FNX && nn != nil && nn->complex >= FNX) {
-		t = nn->type;
-		nn->type = types[TIND];
-		regialloc(&nod1, nn, Z);
-		lcgen(nn, &nod1);
-		regsalloc(&nod2, nn);
-		nn->type = t;
-
-		gins(AMOVQ, &nod1, &nod2);
-		regfree(&nod1);
-
-		nod2.type = typ(TIND, t);
-
-		nod1 = nod2;
-		nod1.op = OIND;
-		nod1.left = &nod2;
-		nod1.right = Z;
-		nod1.complex = 1;
-		nod1.type = t;
-
-		sugen(n, &nod1, w);
-		return;
-	}
-
-	if(w <= 32) {
-		c = cursafe;
-		if(n->left != Z && n->left->complex >= FNX
-		&& n->right != Z && n->right->complex >= FNX) {
-			regsalloc(&nod1, n->right);
-			cgen(n->right, &nod1);
-			nod2 = *n;
-			nod2.right = &nod1;
-			cgen(&nod2, nn);
-			cursafe = c;
-			return;
-		}
-		if(w & 7) {
-			mt = TLONG;
-			mo = AMOVL;
-		} else {
-			mt = TVLONG;
-			mo = AMOVQ;
-		}
-		if(n->complex > nn->complex) {
-			t = n->type;
-			n->type = types[mt];
-			regalloc(&nod0, n, Z);
-			if(!vaddr(n, 0)) {
-				reglcgen(&nod1, n, Z);
-				n->type = t;
-				n = &nod1;
-			}
-			else
-				n->type = t;
-
-			t = nn->type;
-			nn->type = types[mt];
-			if(!vaddr(nn, 0)) {
-				reglcgen(&nod2, nn, Z);
-				nn->type = t;
-				nn = &nod2;
-			}
-			else
-				nn->type = t;
-		} else {
-			t = nn->type;
-			nn->type = types[mt];
-			regalloc(&nod0, nn, Z);
-			if(!vaddr(nn, 0)) {
-				reglcgen(&nod2, nn, Z);
-				nn->type = t;
-				nn = &nod2;
-			}
-			else
-				nn->type = t;
-
-			t = n->type;
-			n->type = types[mt];
-			if(!vaddr(n, 0)) {
-				reglcgen(&nod1, n, Z);
-				n->type = t;
-				n = &nod1;
-			}
-			else
-				n->type = t;
-		}
-		o0 = n->xoffset;
-		o1 = nn->xoffset;
-		w /= ewidth[mt];
-		while(--w >= 0) {
-			gins(mo, n, &nod0);
-			gins(mo, &nod0, nn);
-			n->xoffset += ewidth[mt];
-			nn->xoffset += ewidth[mt];
-		}
-		n->xoffset = o0;
-		nn->xoffset = o1;
-		if(nn == &nod2)
-			regfree(&nod2);
-		if(n == &nod1)
-			regfree(&nod1);
-		regfree(&nod0);
-		return;
-	}
-
-	/* botch, need to save in .safe */
-	c = 0;
-	if(n->complex > nn->complex) {
-		t = n->type;
-		n->type = types[TIND];
-		nodreg(&nod1, n, D_SI);
-		if(reg[D_SI]) {
-			gins(APUSHQ, &nod1, Z);
-			c |= 1;
-			reg[D_SI]++;
-		}
-		lcgen(n, &nod1);
-		n->type = t;
-
-		t = nn->type;
-		nn->type = types[TIND];
-		nodreg(&nod2, nn, D_DI);
-		if(reg[D_DI]) {
-warn(Z, "DI botch");
-			gins(APUSHQ, &nod2, Z);
-			c |= 2;
-			reg[D_DI]++;
-		}
-		lcgen(nn, &nod2);
-		nn->type = t;
-	} else {
-		t = nn->type;
-		nn->type = types[TIND];
-		nodreg(&nod2, nn, D_DI);
-		if(reg[D_DI]) {
-warn(Z, "DI botch");
-			gins(APUSHQ, &nod2, Z);
-			c |= 2;
-			reg[D_DI]++;
-		}
-		lcgen(nn, &nod2);
-		nn->type = t;
-
-		t = n->type;
-		n->type = types[TIND];
-		nodreg(&nod1, n, D_SI);
-		if(reg[D_SI]) {
-			gins(APUSHQ, &nod1, Z);
-			c |= 1;
-			reg[D_SI]++;
-		}
-		lcgen(n, &nod1);
-		n->type = t;
-	}
-	nodreg(&nod3, n, D_CX);
-	if(reg[D_CX]) {
-		gins(APUSHQ, &nod3, Z);
-		c |= 4;
-		reg[D_CX]++;
-	}
-	gins(AMOVL, nodconst(w/SZ_INT), &nod3);
-	gins(ACLD, Z, Z);
-	gins(AREP, Z, Z);
-	gins(AMOVSL, Z, Z);
-	if(c & 4) {
-		gins(APOPQ, Z, &nod3);
-		reg[D_CX]--;
-	}
-	if(c & 2) {
-		gins(APOPQ, Z, &nod2);
-		reg[nod2.reg]--;
-	}
-	if(c & 1) {
-		gins(APOPQ, Z, &nod1);
-		reg[nod1.reg]--;
-	}
-}
-
-/*
- * TO DO
- */
-void
-layout(Node *f, Node *t, int c, int cv, Node *cn)
-{
-	Node t1, t2;
-
-	while(c > 3) {
-		layout(f, t, 2, 0, Z);
-		c -= 2;
-	}
-
-	regalloc(&t1, &lregnode, Z);
-	regalloc(&t2, &lregnode, Z);
-	if(c > 0) {
-		gmove(f, &t1);
-		f->xoffset += SZ_INT;
-	}
-	if(cn != Z)
-		gmove(nodconst(cv), cn);
-	if(c > 1) {
-		gmove(f, &t2);
-		f->xoffset += SZ_INT;
-	}
-	if(c > 0) {
-		gmove(&t1, t);
-		t->xoffset += SZ_INT;
-	}
-	if(c > 2) {
-		gmove(f, &t1);
-		f->xoffset += SZ_INT;
-	}
-	if(c > 1) {
-		gmove(&t2, t);
-		t->xoffset += SZ_INT;
-	}
-	if(c > 2) {
-		gmove(&t1, t);
-		t->xoffset += SZ_INT;
-	}
-	regfree(&t1);
-	regfree(&t2);
-}
-
-/*
- * constant is not vlong or fits as 32-bit signed immediate
- */
-int
-immconst(Node *n)
-{
-	int32 v;
-
-	if(n->op != OCONST || !typechlpv[n->type->etype])
-		return 0;
-	if(typechl[n->type->etype])
-		return 1;
-	v = n->vconst;
-	return n->vconst == (vlong)v;
-}
-
-/*
- * if a constant and vlong, doesn't fit as 32-bit signed immediate
- */
-int
-hardconst(Node *n)
-{
-	return n->op == OCONST && !immconst(n);
-}
-
-/*
- * casting up to t2 covers an intermediate cast to t1
- */
-int
-castup(Type *t1, Type *t2)
-{
-	int ft;
-
-	if(!nilcast(t1, t2))
-		return 0;
-	/* known to be small to large */
-	ft = t1->etype;
-	switch(t2->etype){
-	case TINT:
-	case TLONG:
-		return ft == TLONG || ft == TINT || ft == TSHORT || ft == TCHAR;
-	case TUINT:
-	case TULONG:
-		return ft == TULONG || ft == TUINT || ft == TUSHORT || ft == TUCHAR;
-	case TVLONG:
-		return ft == TLONG || ft == TINT || ft == TSHORT;
-	case TUVLONG:
-		return ft == TULONG || ft == TUINT || ft == TUSHORT;
-	}
-	return 0;
-}
-
-void
-zeroregm(Node *n)
-{
-	gins(AMOVL, nodconst(0), n);
-}
-
-/* do we need to load the address of a vlong? */
-int
-vaddr(Node *n, int a)
-{
-	switch(n->op) {
-	case ONAME:
-		if(a)
-			return 1;
-		return !(n->class == CEXTERN || n->class == CGLOBL || n->class == CSTATIC);
-
-	case OCONST:
-	case OREGISTER:
-	case OINDREG:
-		return 1;
-	}
-	return 0;
-}
-
-int32
-hi64v(Node *n)
-{
-	if(align(0, types[TCHAR], Aarg1, nil))	/* isbigendian */
-		return (int32)(n->vconst) & ~0L;
-	else
-		return (int32)((uvlong)n->vconst>>32) & ~0L;
-}
-
-int32
-lo64v(Node *n)
-{
-	if(align(0, types[TCHAR], Aarg1, nil))	/* isbigendian */
-		return (int32)((uvlong)n->vconst>>32) & ~0L;
-	else
-		return (int32)(n->vconst) & ~0L;
-}
-
-Node *
-hi64(Node *n)
-{
-	return nodconst(hi64v(n));
-}
-
-Node *
-lo64(Node *n)
-{
-	return nodconst(lo64v(n));
-}
-
-int
-cond(int op)
-{
-	switch(op) {
-	case OANDAND:
-	case OOROR:
-	case ONOT:
-		return 1;
-
-	case OEQ:
-	case ONE:
-	case OLE:
-	case OLT:
-	case OGE:
-	case OGT:
-	case OHI:
-	case OHS:
-	case OLO:
-	case OLS:
-		return 1;
-	}
-	return 0;
-}
diff --git a/src/cmd/6c/div.c b/src/cmd/6c/div.c
deleted file mode 100644
index bad6c5e..0000000
--- a/src/cmd/6c/div.c
+++ /dev/null
@@ -1,236 +0,0 @@
-// Inferno utils/6c/div.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/div.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include "gc.h"
-
-/*
- * Based on: Granlund, T.; Montgomery, P.L.
- * "Division by Invariant Integers using Multiplication".
- * SIGPLAN Notices, Vol. 29, June 1994, page 61.
- */
-
-#define	TN(n)	((uvlong)1 << (n))
-#define	T31	TN(31)
-#define	T32	TN(32)
-
-int
-multiplier(uint32 d, int p, uvlong *mp)
-{
-	int l;
-	uvlong mlo, mhi, tlo, thi;
-
-	l = topbit(d - 1) + 1;
-	mlo = (((TN(l) - d) << 32) / d) + T32;
-	if(l + p == 64)
-		mhi = (((TN(l) + 1 - d) << 32) / d) + T32;
-	else
-		mhi = (TN(32 + l) + TN(32 + l - p)) / d;
-	/*assert(mlo < mhi);*/
-	while(l > 0) {
-		tlo = mlo >> 1;
-		thi = mhi >> 1;
-		if(tlo == thi)
-			break;
-		mlo = tlo;
-		mhi = thi;
-		l--;
-	}
-	*mp = mhi;
-	return l;
-}
-
-int
-sdiv(uint32 d, uint32 *mp, int *sp)
-{
-	int s;
-	uvlong m;
-
-	s = multiplier(d, 32 - 1, &m);
-	*mp = m;
-	*sp = s;
-	if(m >= T31)
-		return 1;
-	else
-		return 0;
-}
-
-int
-udiv(uint32 d, uint32 *mp, int *sp, int *pp)
-{
-	int p, s;
-	uvlong m;
-
-	s = multiplier(d, 32, &m);
-	p = 0;
-	if(m >= T32) {
-		while((d & 1) == 0) {
-			d >>= 1;
-			p++;
-		}
-		s = multiplier(d, 32 - p, &m);
-	}
-	*mp = m;
-	*pp = p;
-	if(m >= T32) {
-		/*assert(p == 0);*/
-		*sp = s - 1;
-		return 1;
-	}
-	else {
-		*sp = s;
-		return 0;
-	}
-}
-
-void
-sdivgen(Node *l, Node *r, Node *ax, Node *dx)
-{
-	int a, s;
-	uint32 m;
-	vlong c;
-
-	c = r->vconst;
-	if(c < 0)
-		c = -c;
-	a = sdiv(c, &m, &s);
-//print("a=%d i=%d s=%d m=%ux\n", a, (long)r->vconst, s, m);
-	gins(AMOVL, nodconst(m), ax);
-	gins(AIMULL, l, Z);
-	gins(AMOVL, l, ax);
-	if(a)
-		gins(AADDL, ax, dx);
-	gins(ASHRL, nodconst(31), ax);
-	gins(ASARL, nodconst(s), dx);
-	gins(AADDL, ax, dx);
-	if(r->vconst < 0)
-		gins(ANEGL, Z, dx);
-}
-
-void
-udivgen(Node *l, Node *r, Node *ax, Node *dx)
-{
-	int a, s, t;
-	uint32 m;
-	Node nod;
-
-	a = udiv(r->vconst, &m, &s, &t);
-//print("a=%ud i=%d p=%d s=%d m=%ux\n", a, (long)r->vconst, t, s, m);
-	if(t != 0) {
-		gins(AMOVL, l, ax);
-		gins(ASHRL, nodconst(t), ax);
-		gins(AMOVL, nodconst(m), dx);
-		gins(AMULL, dx, Z);
-	}
-	else if(a) {
-		if(l->op != OREGISTER) {
-			regalloc(&nod, l, Z);
-			gins(AMOVL, l, &nod);
-			l = &nod;
-		}
-		gins(AMOVL, nodconst(m), ax);
-		gins(AMULL, l, Z);
-		gins(AADDL, l, dx);
-		gins(ARCRL, nodconst(1), dx);
-		if(l == &nod)
-			regfree(l);
-	}
-	else {
-		gins(AMOVL, nodconst(m), ax);
-		gins(AMULL, l, Z);
-	}
-	if(s != 0)
-		gins(ASHRL, nodconst(s), dx);
-}
-
-void
-sext(Node *d, Node *s, Node *l)
-{
-	if(s->reg == D_AX && !nodreg(d, Z, D_DX)) {
-		reg[D_DX]++;
-		gins(ACDQ, Z, Z);
-	}
-	else {
-		regalloc(d, l, Z);
-		gins(AMOVL, s, d);
-		gins(ASARL, nodconst(31), d);
-	}
-}
-
-void
-sdiv2(int32 c, int v, Node *l, Node *n)
-{
-	Node nod;
-
-	if(v > 0) {
-		if(v > 1) {
-			sext(&nod, n, l);
-			gins(AANDL, nodconst((1 << v) - 1), &nod);
-			gins(AADDL, &nod, n);
-			regfree(&nod);
-		}
-		else {
-			gins(ACMPL, n, nodconst(0x80000000));
-			gins(ASBBL, nodconst(-1), n);
-		}
-		gins(ASARL, nodconst(v), n);
-	}
-	if(c < 0)
-		gins(ANEGL, Z, n);
-}
-
-void
-smod2(int32 c, int v, Node *l, Node *n)
-{
-	Node nod;
-
-	if(c == 1) {
-		zeroregm(n);
-		return;
-	}
-
-	sext(&nod, n, l);
-	if(v == 0) {
-		zeroregm(n);
-		gins(AXORL, &nod, n);
-		gins(ASUBL, &nod, n);
-	}
-	else if(v > 1) {
-		gins(AANDL, nodconst((1 << v) - 1), &nod);
-		gins(AADDL, &nod, n);
-		gins(AANDL, nodconst((1 << v) - 1), n);
-		gins(ASUBL, &nod, n);
-	}
-	else {
-		gins(AANDL, nodconst(1), n);
-		gins(AXORL, &nod, n);
-		gins(ASUBL, &nod, n);
-	}
-	regfree(&nod);
-}
diff --git a/src/cmd/6c/doc.go b/src/cmd/6c/doc.go
deleted file mode 100644
index e0a22e7..0000000
--- a/src/cmd/6c/doc.go
+++ /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.
-
-// +build ignore
-
-/*
-
-6c is a version of the Plan 9 C compiler.  The original is documented at
-
-	http://plan9.bell-labs.com/magic/man2html/1/8c
-
-Its target architecture is the x86-64, referred to by these tools as amd64.
-
-*/
-package main
diff --git a/src/cmd/6c/gc.h b/src/cmd/6c/gc.h
deleted file mode 100644
index aa9d95d..0000000
--- a/src/cmd/6c/gc.h
+++ /dev/null
@@ -1,359 +0,0 @@
-// Inferno utils/6c/gc.h
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/gc.h
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include	<u.h>
-#include	"../cc/cc.h"
-#include	"../6l/6.out.h"
-
-/*
- * 6c/amd64
- * Intel 386 with AMD64 extensions
- */
-#define	SZ_CHAR		1
-#define	SZ_SHORT	2
-#define	SZ_INT		4
-#define	SZ_LONG		4
-#define	SZ_IND		8
-#define	SZ_FLOAT	4
-#define	SZ_VLONG	8
-#define	SZ_DOUBLE	8
-#define	FNX		100
-
-typedef	struct	Case	Case;
-typedef	struct	C1	C1;
-typedef	struct	Reg	Reg;
-typedef	struct	Rgn	Rgn;
-typedef	struct	Renv	Renv;
-
-EXTERN	struct
-{
-	Node*	regtree;
-	Node*	basetree;
-	short	scale;
-	short	reg;
-	short	ptr;
-} idx;
-
-#define	INDEXED	9
-
-#define	A	((Addr*)0)
-#define	P	((Prog*)0)
-
-struct	Case
-{
-	Case*	link;
-	vlong	val;
-	int32	label;
-	char	def;
-	char	isv;
-};
-#define	C	((Case*)0)
-
-struct	C1
-{
-	vlong	val;
-	int32	label;
-};
-
-struct	Reg
-{
-	int32	pc;
-	int32	rpo;		/* reverse post ordering */
-
-	Bits	set;
-	Bits	use1;
-	Bits	use2;
-
-	Bits	refbehind;
-	Bits	refahead;
-	Bits	calbehind;
-	Bits	calahead;
-	Bits	regdiff;
-	Bits	act;
-
-	int32	regu;
-	int32	loop;		/* could be shorter */
-
-	Reg*	log5;
-	int32	active;
-
-	Reg*	p1;
-	Reg*	p2;
-	Reg*	p2link;
-	Reg*	s1;
-	Reg*	s2;
-	Reg*	link;
-	Prog*	prog;
-};
-#define	R	((Reg*)0)
-
-struct	Renv
-{
-	int	safe;
-	Node	base;
-	Node*	saved;
-	Node*	scope;
-};
-
-#define	NRGN	600
-struct	Rgn
-{
-	Reg*	enter;
-	short	cost;
-	short	varno;
-	short	regno;
-};
-
-EXTERN	int32	breakpc;
-EXTERN	int32	nbreak;
-EXTERN	Case*	cases;
-EXTERN	Node	constnode;
-EXTERN	Node	fconstnode;
-EXTERN	Node	vconstnode;
-EXTERN	int32	continpc;
-EXTERN	int32	curarg;
-EXTERN	int32	cursafe;
-EXTERN	Prog*	lastp;
-EXTERN	int32	maxargsafe;
-EXTERN	int	mnstring;
-EXTERN	Node*	nodrat;
-EXTERN	Node*	nodret;
-EXTERN	Node*	nodsafe;
-EXTERN	int32	nrathole;
-EXTERN	int32	nstring;
-EXTERN	Prog*	p;
-EXTERN	int32	pc;
-EXTERN	Node	lregnode;
-EXTERN	Node	qregnode;
-EXTERN	char	string[NSNAME];
-EXTERN	Sym*	symrathole;
-EXTERN	Node	znode;
-EXTERN	Prog	zprog;
-EXTERN	int	reg[D_NONE];
-EXTERN	int32	exregoffset;
-EXTERN	int32	exfregoffset;
-EXTERN	uchar	typechlpv[NTYPE];
-
-#define	BLOAD(r)	band(bnot(r->refbehind), r->refahead)
-#define	BSTORE(r)	band(bnot(r->calbehind), r->calahead)
-#define	LOAD(r)		(~r->refbehind.b[z] & r->refahead.b[z])
-#define	STORE(r)	(~r->calbehind.b[z] & r->calahead.b[z])
-
-#define	bset(a,n)	((a).b[(n)/32]&(1L<<(n)%32))
-
-#define	CLOAD	5
-#define	CREF	5
-#define	CINF	1000
-#define	LOOP	3
-
-EXTERN	Rgn	region[NRGN];
-EXTERN	Rgn*	rgp;
-EXTERN	int	nregion;
-EXTERN	int	nvar;
-
-EXTERN	Bits	externs;
-EXTERN	Bits	params;
-EXTERN	Bits	consts;
-EXTERN	Bits	addrs;
-
-EXTERN	int32	regbits;
-EXTERN	int32	exregbits;
-
-EXTERN	int	change;
-EXTERN	int	suppress;
-
-EXTERN	Reg*	firstr;
-EXTERN	Reg*	lastr;
-EXTERN	Reg	zreg;
-EXTERN	Reg*	freer;
-EXTERN	int32*	idom;
-EXTERN	Reg**	rpo2r;
-EXTERN	int32	maxnr;
-
-extern	char*	anames[];
-
-/*
- * sgen.c
- */
-void	codgen(Node*, Node*);
-void	gen(Node*);
-void	noretval(int);
-void	usedset(Node*, int);
-void	xcom(Node*);
-void	indx(Node*);
-int	bcomplex(Node*, Node*);
-Prog*	gtext(Sym*, int32);
-vlong	argsize(int);
-
-/*
- * cgen.c
- */
-void	zeroregm(Node*);
-void	cgen(Node*, Node*);
-void	reglcgen(Node*, Node*, Node*);
-void	lcgen(Node*, Node*);
-void	bcgen(Node*, int);
-void	boolgen(Node*, int, Node*);
-void	sugen(Node*, Node*, int32);
-int	needreg(Node*, int);
-int	hardconst(Node*);
-int	immconst(Node*);
-
-/*
- * txt.c
- */
-void	ginit(void);
-void	gclean(void);
-void	nextpc(void);
-void	gargs(Node*, Node*, Node*);
-void	garg1(Node*, Node*, Node*, int, Node**);
-Node*	nodconst(int32);
-Node*	nodfconst(double);
-Node*	nodgconst(vlong, Type*);
-int	nodreg(Node*, Node*, int);
-int	isreg(Node*, int);
-void	regret(Node*, Node*, Type*, int);
-void	regalloc(Node*, Node*, Node*);
-void	regfree(Node*);
-void	regialloc(Node*, Node*, Node*);
-void	regsalloc(Node*, Node*);
-void	regaalloc1(Node*, Node*);
-void	regaalloc(Node*, Node*);
-void	regind(Node*, Node*);
-void	gprep(Node*, Node*);
-void	naddr(Node*, Addr*);
-void	gcmp(int, Node*, vlong);
-void	gmove(Node*, Node*);
-void	gins(int a, Node*, Node*);
-void	gopcode(int, Type*, Node*, Node*);
-int	samaddr(Node*, Node*);
-void	gbranch(int);
-void	patch(Prog*, int32);
-int	sconst(Node*);
-void	gpseudo(int, Sym*, Node*);
-void	gprefetch(Node*);
-void	gpcdata(int, int);
-
-/*
- * swt.c
- */
-int	swcmp(const void*, const void*);
-void	doswit(Node*);
-void	swit1(C1*, int, int32, Node*);
-void	swit2(C1*, int, int32, Node*);
-void	newcase(void);
-void	bitload(Node*, Node*, Node*, Node*, Node*);
-void	bitstore(Node*, Node*, Node*, Node*, Node*);
-int32	outstring(char*, int32);
-void	nullwarn(Node*, Node*);
-void	sextern(Sym*, Node*, int32, int32);
-void	gextern(Sym*, Node*, int32, int32);
-void	outcode(void);
-
-/*
- * list
- */
-void	listinit(void);
-
-/*
- * reg.c
- */
-Reg*	rega(void);
-int	rcmp(const void*, const void*);
-void	regopt(Prog*);
-void	addmove(Reg*, int, int, int);
-Bits	mkvar(Reg*, Addr*);
-void	prop(Reg*, Bits, Bits);
-void	loopit(Reg*, int32);
-void	synch(Reg*, Bits);
-uint32	allreg(uint32, Rgn*);
-void	paint1(Reg*, int);
-uint32	paint2(Reg*, int);
-void	paint3(Reg*, int, int32, int);
-void	addreg(Addr*, int);
-
-/*
- * peep.c
- */
-void	peep(void);
-void	excise(Reg*);
-Reg*	uniqp(Reg*);
-Reg*	uniqs(Reg*);
-int	regtyp(Addr*);
-int	anyvar(Addr*);
-int	subprop(Reg*);
-int	copyprop(Reg*);
-int	copy1(Addr*, Addr*, Reg*, int);
-int	copyu(Prog*, Addr*, Addr*);
-
-int	copyas(Addr*, Addr*);
-int	copyau(Addr*, Addr*);
-int	copysub(Addr*, Addr*, Addr*, int);
-int	copysub1(Prog*, Addr*, Addr*, int);
-
-int32	RtoB(int);
-int32	FtoB(int);
-int	BtoR(int32);
-int	BtoF(int32);
-
-#define	D_HI	D_NONE
-#define	D_LO	D_NONE
-
-/*
- * bound
- */
-void	comtarg(void);
-
-/*
- * com64
- */
-int	cond(int);
-int	com64(Node*);
-void	com64init(void);
-void	bool64(Node*);
-int32	lo64v(Node*);
-int32	hi64v(Node*);
-Node*	lo64(Node*);
-Node*	hi64(Node*);
-
-/*
- * div/mul
- */
-void	sdivgen(Node*, Node*, Node*, Node*);
-void	udivgen(Node*, Node*, Node*, Node*);
-void	sdiv2(int32, int, Node*, Node*);
-void	smod2(int32, int, Node*, Node*);
-void	mulgen(Type*, Node*, Node*);
-void	genmuladd(Node*, Node*, int, Node*);
-void	shiftit(Type*, Node*, Node*);
-
-#define	D_X7	(D_X0+7)
-
-void	fgopcode(int, Node*, Node*, int, int);
diff --git a/src/cmd/6c/list.c b/src/cmd/6c/list.c
deleted file mode 100644
index 28f5b8d..0000000
--- a/src/cmd/6c/list.c
+++ /dev/null
@@ -1,38 +0,0 @@
-// Inferno utils/6c/list.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/list.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#define EXTERN
-#include "gc.h"
-
-void
-listinit(void)
-{
-	listinit6();
-}
diff --git a/src/cmd/6c/machcap.c b/src/cmd/6c/machcap.c
deleted file mode 100644
index 820d9a0..0000000
--- a/src/cmd/6c/machcap.c
+++ /dev/null
@@ -1,107 +0,0 @@
-// Inferno utils/6c/machcap.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/machcap.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include "gc.h"
-
-int
-machcap(Node *n)
-{
-
-	if(n == Z)
-		return 1;	/* test */
-
-	switch(n->op) {
-	case OMUL:
-	case OLMUL:
-	case OASMUL:
-	case OASLMUL:
-		if(typechl[n->type->etype])
-			return 1;
-		if(typev[n->type->etype])
-			return 1;
-		break;
-
-	case OCOM:
-	case ONEG:
-	case OADD:
-	case OAND:
-	case OOR:
-	case OSUB:
-	case OXOR:
-	case OASHL:
-	case OLSHR:
-	case OASHR:
-		if(typechlv[n->left->type->etype])
-			return 1;
-		break;
-
-	case OCAST:
-		return 1;
-
-	case OCOND:
-	case OCOMMA:
-	case OLIST:
-	case OANDAND:
-	case OOROR:
-	case ONOT:
-		return 1;
-
-	case OASADD:
-	case OASSUB:
-	case OASAND:
-	case OASOR:
-	case OASXOR:
-		return 1;
-
-	case OASASHL:
-	case OASASHR:
-	case OASLSHR:
-		return 1;
-
-	case OPOSTINC:
-	case OPOSTDEC:
-	case OPREINC:
-	case OPREDEC:
-		return 1;
-
-	case OEQ:
-	case ONE:
-	case OLE:
-	case OGT:
-	case OLT:
-	case OGE:
-	case OHI:
-	case OHS:
-	case OLO:
-	case OLS:
-		return 1;
-	}
-	return 0;
-}
diff --git a/src/cmd/6c/mul.c b/src/cmd/6c/mul.c
deleted file mode 100644
index 510edc0..0000000
--- a/src/cmd/6c/mul.c
+++ /dev/null
@@ -1,458 +0,0 @@
-// Inferno utils/6c/mul.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/mul.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include "gc.h"
-
-typedef struct	Malg	Malg;
-typedef struct	Mparam	Mparam;
-
-struct	Malg
-{
-	schar	vals[10];
-};
-
-struct	Mparam
-{
-	uint32	value;
-	schar	alg;
-	char	neg;
-	char	shift;
-	char	arg;
-	schar	off;
-};
-
-static	Mparam	multab[32];
-static	int	mulptr;
-
-static	Malg	malgs[]	=
-{
-	{0, 100},
-	{-1, 1, 100},
-	{-9, -5, -3, 3, 5, 9, 100},
-	{6, 10, 12, 18, 20, 24, 36, 40, 72, 100},
-	{-8, -4, -2, 2, 4, 8, 100},
-};
-
-/*
- * return position of lowest 1
- */
-int
-lowbit(uint32 v)
-{
-	int s, i;
-	uint32 m;
-
-	s = 0;
-	m = 0xFFFFFFFFUL;
-	for(i = 16; i > 0; i >>= 1) {
-		m >>= i;
-		if((v & m) == 0) {
-			v >>= i;
-			s += i;
-		}
-	}
-	return s;
-}
-
-void
-genmuladd(Node *d, Node *s, int m, Node *a)
-{
-	Node nod;
-
-	nod.op = OINDEX;
-	nod.left = a;
-	nod.right = s;
-	nod.scale = m;
-	nod.type = types[TIND];
-	nod.xoffset = 0;
-	xcom(&nod);
-	gopcode(OADDR, d->type, &nod, d);
-}
-
-void
-mulparam(uint32 m, Mparam *mp)
-{
-	int c, i, j, n, o, q, s;
-	int bc, bi, bn, bo, bq, bs, bt;
-	schar *p;
-	int32 u;
-	uint32 t;
-
-	bc = bq = 10;
-	bi = bn = bo = bs = bt = 0;
-	for(i = 0; i < nelem(malgs); i++) {
-		for(p = malgs[i].vals, j = 0; (o = p[j]) < 100; j++)
-		for(s = 0; s < 2; s++) {
-			c = 10;
-			q = 10;
-			u = m - o;
-			if(u == 0)
-				continue;
-			if(s) {
-				o = -o;
-				if(o > 0)
-					continue;
-				u = -u;
-			}
-			n = lowbit(u);
-			t = (uint32)u >> n;
-			switch(i) {
-			case 0:
-				if(t == 1) {
-					c = s + 1;
-					q = 0;
-					break;
-				}
-				switch(t) {
-				case 3:
-				case 5:
-				case 9:
-					c = s + 1;
-					if(n)
-						c++;
-					q = 0;
-					break;
-				}
-				if(s)
-					break;
-				switch(t) {
-				case 15:
-				case 25:
-				case 27:
-				case 45:
-				case 81:
-					c = 2;
-					if(n)
-						c++;
-					q = 1;
-					break;
-				}
-				break;
-			case 1:
-				if(t == 1) {
-					c = 3;
-					q = 3;
-					break;
-				}
-				switch(t) {
-				case 3:
-				case 5:
-				case 9:
-					c = 3;
-					q = 2;
-					break;
-				}
-				break;
-			case 2:
-				if(t == 1) {
-					c = 3;
-					q = 2;
-					break;
-				}
-				break;
-			case 3:
-				if(s)
-					break;
-				if(t == 1) {
-					c = 3;
-					q = 1;
-					break;
-				}
-				break;
-			case 4:
-				if(t == 1) {
-					c = 3;
-					q = 0;
-					break;
-				}
-				break;
-			}
-			if(c < bc || (c == bc && q > bq)) {
-				bc = c;
-				bi = i;
-				bn = n;
-				bo = o;
-				bq = q;
-				bs = s;
-				bt = t;
-			}
-		}
-	}
-	mp->value = m;
-	if(bc <= 3) {
-		mp->alg = bi;
-		mp->shift = bn;
-		mp->off = bo;
-		mp->neg = bs;
-		mp->arg = bt;
-	}
-	else
-		mp->alg = -1;
-}
-
-int
-m0(int a)
-{
-	switch(a) {
-	case -2:
-	case 2:
-		return 2;
-	case -3:
-	case 3:
-		return 2;
-	case -4:
-	case 4:
-		return 4;
-	case -5:
-	case 5:
-		return 4;
-	case 6:
-		return 2;
-	case -8:
-	case 8:
-		return 8;
-	case -9:
-	case 9:
-		return 8;
-	case 10:
-		return 4;
-	case 12:
-		return 2;
-	case 15:
-		return 2;
-	case 18:
-		return 8;
-	case 20:
-		return 4;
-	case 24:
-		return 2;
-	case 25:
-		return 4;
-	case 27:
-		return 2;
-	case 36:
-		return 8;
-	case 40:
-		return 4;
-	case 45:
-		return 4;
-	case 72:
-		return 8;
-	case 81:
-		return 8;
-	}
-	diag(Z, "bad m0");
-	return 0;
-}
-
-int
-m1(int a)
-{
-	switch(a) {
-	case 15:
-		return 4;
-	case 25:
-		return 4;
-	case 27:
-		return 8;
-	case 45:
-		return 8;
-	case 81:
-		return 8;
-	}
-	diag(Z, "bad m1");
-	return 0;
-}
-
-int
-m2(int a)
-{
-	switch(a) {
-	case 6:
-		return 2;
-	case 10:
-		return 2;
-	case 12:
-		return 4;
-	case 18:
-		return 2;
-	case 20:
-		return 4;
-	case 24:
-		return 8;
-	case 36:
-		return 4;
-	case 40:
-		return 8;
-	case 72:
-		return 8;
-	}
-	diag(Z, "bad m2");
-	return 0;
-}
-
-void
-shiftit(Type *t, Node *s, Node *d)
-{
-	int32 c;
-
-	c = (int32)s->vconst & 31;
-	switch(c) {
-	case 0:
-		break;
-	case 1:
-		gopcode(OADD, t, d, d);
-		break;
-	default:
-		gopcode(OASHL, t, s, d);
-	}
-}
-
-static int
-mulgen1(uint32 v, Node *n)
-{
-	int i, o;
-	Mparam *p;
-	Node nod, nods;
-
-	for(i = 0; i < nelem(multab); i++) {
-		p = &multab[i];
-		if(p->value == v)
-			goto found;
-	}
-
-	p = &multab[mulptr];
-	if(++mulptr == nelem(multab))
-		mulptr = 0;
-
-	mulparam(v, p);
-
-found:
-//	print("v=%.x a=%d n=%d s=%d g=%d o=%d \n", p->value, p->alg, p->neg, p->shift, p->arg, p->off);
-	if(p->alg < 0)
-		return 0;
-
-	nods = *nodconst(p->shift);
-
-	o = OADD;
-	if(p->alg > 0) {
-		regalloc(&nod, n, Z);
-		if(p->off < 0)
-			o = OSUB;
-	}
-
-	switch(p->alg) {
-	case 0:
-		switch(p->arg) {
-		case 1:
-			shiftit(n->type, &nods, n);
-			break;
-		case 15:
-		case 25:
-		case 27:
-		case 45:
-		case 81:
-			genmuladd(n, n, m1(p->arg), n);
-			/* fall thru */
-		case 3:
-		case 5:
-		case 9:
-			genmuladd(n, n, m0(p->arg), n);
-			shiftit(n->type, &nods, n);
-			break;
-		default:
-			goto bad;
-		}
-		if(p->neg == 1)
-			gins(ANEGL, Z, n);
-		break;
-	case 1:
-		switch(p->arg) {
-		case 1:
-			gmove(n, &nod);
-			shiftit(n->type, &nods, &nod);
-			break;
-		case 3:
-		case 5:
-		case 9:
-			genmuladd(&nod, n, m0(p->arg), n);
-			shiftit(n->type, &nods, &nod);
-			break;
-		default:
-			goto bad;
-		}
-		if(p->neg)
-			gopcode(o, n->type, &nod, n);
-		else {
-			gopcode(o, n->type, n, &nod);
-			gmove(&nod, n);
-		}
-		break;
-	case 2:
-		genmuladd(&nod, n, m0(p->off), n);
-		shiftit(n->type, &nods, n);
-		goto comop;
-	case 3:
-		genmuladd(&nod, n, m0(p->off), n);
-		shiftit(n->type, &nods, n);
-		genmuladd(n, &nod, m2(p->off), n);
-		break;
-	case 4:
-		genmuladd(&nod, n, m0(p->off), nodconst(0));
-		shiftit(n->type, &nods, n);
-		goto comop;
-	default:
-		diag(Z, "bad mul alg");
-		break;
-	comop:
-		if(p->neg) {
-			gopcode(o, n->type, n, &nod);
-			gmove(&nod, n);
-		}
-		else
-			gopcode(o, n->type, &nod, n);
-	}
-
-	if(p->alg > 0)
-		regfree(&nod);
-
-	return 1;
-
-bad:
-	diag(Z, "mulgen botch");
-	return 1;
-}
-
-void
-mulgen(Type *t, Node *r, Node *n)
-{
-	if(!mulgen1(r->vconst, n))
-		gopcode(OMUL, t, r, n);
-}
diff --git a/src/cmd/6c/peep.c b/src/cmd/6c/peep.c
deleted file mode 100644
index a11067c..0000000
--- a/src/cmd/6c/peep.c
+++ /dev/null
@@ -1,902 +0,0 @@
-// 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 at 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 at 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.
-
-#include "gc.h"
-
-static int
-needc(Prog *p)
-{
-	while(p != P) {
-		switch(p->as) {
-		case AADCL:
-		case AADCQ:
-		case ASBBL:
-		case ASBBQ:
-		case ARCRL:
-		case ARCRQ:
-			return 1;
-		case AADDL:
-		case AADDQ:
-		case ASUBL:
-		case ASUBQ:
-		case AJMP:
-		case ARET:
-		case ACALL:
-			return 0;
-		default:
-			if(p->to.type == D_BRANCH)
-				return 0;
-		}
-		p = p->link;
-	}
-	return 0;
-}
-
-static Reg*
-rnops(Reg *r)
-{
-	Prog *p;
-	Reg *r1;
-
-	if(r != R)
-	for(;;){
-		p = r->prog;
-		if(p->as != ANOP || p->from.type != D_NONE || p->to.type != D_NONE)
-			break;
-		r1 = uniqs(r);
-		if(r1 == R)
-			break;
-		r = r1;
-	}
-	return r;
-}
-
-void
-peep(void)
-{
-	Reg *r, *r1, *r2;
-	Prog *p, *p1;
-	int t;
-
-	/*
-	 * complete R structure
-	 */
-	t = 0;
-	for(r=firstr; r!=R; r=r1) {
-		r1 = r->link;
-		if(r1 == R)
-			break;
-		p = r->prog->link;
-		while(p != r1->prog)
-		switch(p->as) {
-		default:
-			r2 = rega();
-			r->link = r2;
-			r2->link = r1;
-
-			r2->prog = p;
-			r2->p1 = r;
-			r->s1 = r2;
-			r2->s1 = r1;
-			r1->p1 = r2;
-
-			r = r2;
-			t++;
-
-		case ADATA:
-		case AGLOBL:
-		case ANAME:
-		case ASIGNAME:
-			p = p->link;
-		}
-	}
-
-	pc = 0;	/* speculating it won't kill */
-
-loop1:
-
-	t = 0;
-	for(r=firstr; r!=R; r=r->link) {
-		p = r->prog;
-		switch(p->as) {
-		case AMOVL:
-		case AMOVQ:
-		case AMOVSS:
-		case AMOVSD:
-			if(regtyp(&p->to))
-			if(regtyp(&p->from)) {
-				if(copyprop(r)) {
-					excise(r);
-					t++;
-				} else
-				if(subprop(r) && copyprop(r)) {
-					excise(r);
-					t++;
-				}
-			}
-			break;
-
-		case AMOVBLZX:
-		case AMOVWLZX:
-		case AMOVBLSX:
-		case AMOVWLSX:
-			if(regtyp(&p->to)) {
-				r1 = rnops(uniqs(r));
-				if(r1 != R) {
-					p1 = r1->prog;
-					if(p->as == p1->as && p->to.type == p1->from.type){
-						p1->as = AMOVL;
-						t++;
-					}
-				}
-			}
-			break;
-
-		case AMOVBQSX:
-		case AMOVBQZX:
-		case AMOVWQSX:
-		case AMOVWQZX:
-		case AMOVLQSX:
-		case AMOVLQZX:
-			if(regtyp(&p->to)) {
-				r1 = rnops(uniqs(r));
-				if(r1 != R) {
-					p1 = r1->prog;
-					if(p->as == p1->as && p->to.type == p1->from.type){
-						p1->as = AMOVQ;
-						t++;
-					}
-				}
-			}
-			break;
-
-		case AADDL:
-		case AADDQ:
-		case AADDW:
-			if(p->from.type != D_CONST || needc(p->link))
-				break;
-			if(p->from.offset == -1){
-				if(p->as == AADDQ)
-					p->as = ADECQ;
-				else if(p->as == AADDL)
-					p->as = ADECL;
-				else
-					p->as = ADECW;
-				p->from = zprog.from;
-			}
-			else if(p->from.offset == 1){
-				if(p->as == AADDQ)
-					p->as = AINCQ;
-				else if(p->as == AADDL)
-					p->as = AINCL;
-				else
-					p->as = AINCW;
-				p->from = zprog.from;
-			}
-			break;
-
-		case ASUBL:
-		case ASUBQ:
-		case ASUBW:
-			if(p->from.type != D_CONST || needc(p->link))
-				break;
-			if(p->from.offset == -1) {
-				if(p->as == ASUBQ)
-					p->as = AINCQ;
-				else if(p->as == ASUBL)
-					p->as = AINCL;
-				else
-					p->as = AINCW;
-				p->from = zprog.from;
-			}
-			else if(p->from.offset == 1){
-				if(p->as == ASUBQ)
-					p->as = ADECQ;
-				else if(p->as == ASUBL)
-					p->as = ADECL;
-				else
-					p->as = ADECW;
-				p->from = zprog.from;
-			}
-			break;
-		}
-	}
-	if(t)
-		goto loop1;
-}
-
-void
-excise(Reg *r)
-{
-	Prog *p;
-
-	p = r->prog;
-	p->as = ANOP;
-	p->from = zprog.from;
-	p->to = zprog.to;
-}
-
-Reg*
-uniqp(Reg *r)
-{
-	Reg *r1;
-
-	r1 = r->p1;
-	if(r1 == R) {
-		r1 = r->p2;
-		if(r1 == R || r1->p2link != R)
-			return R;
-	} else
-		if(r->p2 != R)
-			return R;
-	return r1;
-}
-
-Reg*
-uniqs(Reg *r)
-{
-	Reg *r1;
-
-	r1 = r->s1;
-	if(r1 == R) {
-		r1 = r->s2;
-		if(r1 == R)
-			return R;
-	} else
-		if(r->s2 != R)
-			return R;
-	return r1;
-}
-
-int
-regtyp(Addr *a)
-{
-	int t;
-
-	t = a->type;
-	if(t >= D_AX && t <= D_R15)
-		return 1;
-	if(t >= D_X0 && t <= D_X0+15)
-		return 1;
-	return 0;
-}
-
-/*
- * the idea is to substitute
- * one register for another
- * from one MOV to another
- *	MOV	a, R0
- *	ADD	b, R0	/ no use of R1
- *	MOV	R0, R1
- * would be converted to
- *	MOV	a, R1
- *	ADD	b, R1
- *	MOV	R1, R0
- * hopefully, then the former or latter MOV
- * will be eliminated by copy propagation.
- */
-int
-subprop(Reg *r0)
-{
-	Prog *p;
-	Addr *v1, *v2;
-	Reg *r;
-	int t;
-
-	p = r0->prog;
-	v1 = &p->from;
-	if(!regtyp(v1))
-		return 0;
-	v2 = &p->to;
-	if(!regtyp(v2))
-		return 0;
-	for(r=uniqp(r0); r!=R; r=uniqp(r)) {
-		if(uniqs(r) == R)
-			break;
-		p = r->prog;
-		switch(p->as) {
-		case ACALL:
-			return 0;
-
-		case AIMULL:
-		case AIMULQ:
-		case AIMULW:
-			if(p->to.type != D_NONE)
-				break;
-			goto giveup;
-
-		case AROLB:
-		case AROLL:
-		case AROLQ:
-		case AROLW:
-		case ARORB:
-		case ARORL:
-		case ARORQ:
-		case ARORW:
-		case ASALB:
-		case ASALL:
-		case ASALQ:
-		case ASALW:
-		case ASARB:
-		case ASARL:
-		case ASARQ:
-		case ASARW:
-		case ASHLB:
-		case ASHLL:
-		case ASHLQ:
-		case ASHLW:
-		case ASHRB:
-		case ASHRL:
-		case ASHRQ:
-		case ASHRW:
-			if(p->from.type == D_CONST)
-				break;
-			goto giveup;
-
-		case ADIVB:
-		case ADIVL:
-		case ADIVQ:
-		case ADIVW:
-		case AIDIVB:
-		case AIDIVL:
-		case AIDIVQ:
-		case AIDIVW:
-		case AIMULB:
-		case AMULB:
-		case AMULL:
-		case AMULQ:
-		case AMULW:
-
-		case AREP:
-		case AREPN:
-
-		case ACWD:
-		case ACDQ:
-		case ACQO:
-
-		case ASTOSB:
-		case ASTOSL:
-		case ASTOSQ:
-		case AMOVSB:
-		case AMOVSL:
-		case AMOVSQ:
-		case AMOVQL:
-		giveup:
-			return 0;
-
-		case AMOVL:
-		case AMOVQ:
-			if(p->to.type == v1->type)
-				goto gotit;
-			break;
-		}
-		if(copyau(&p->from, v2) ||
-		   copyau(&p->to, v2))
-			break;
-		if(copysub(&p->from, v1, v2, 0) ||
-		   copysub(&p->to, v1, v2, 0))
-			break;
-	}
-	return 0;
-
-gotit:
-	copysub(&p->to, v1, v2, 1);
-	if(debug['P']) {
-		print("gotit: %D->%D\n%P", v1, v2, r->prog);
-		if(p->from.type == v2->type)
-			print(" excise");
-		print("\n");
-	}
-	for(r=uniqs(r); r!=r0; r=uniqs(r)) {
-		p = r->prog;
-		copysub(&p->from, v1, v2, 1);
-		copysub(&p->to, v1, v2, 1);
-		if(debug['P'])
-			print("%P\n", r->prog);
-	}
-	t = v1->type;
-	v1->type = v2->type;
-	v2->type = t;
-	if(debug['P'])
-		print("%P last\n", r->prog);
-	return 1;
-}
-
-/*
- * The idea is to remove redundant copies.
- *	v1->v2	F=0
- *	(use v2	s/v2/v1/)*
- *	set v1	F=1
- *	use v2	return fail
- *	-----------------
- *	v1->v2	F=0
- *	(use v2	s/v2/v1/)*
- *	set v1	F=1
- *	set v2	return success
- */
-int
-copyprop(Reg *r0)
-{
-	Prog *p;
-	Addr *v1, *v2;
-	Reg *r;
-
-	p = r0->prog;
-	v1 = &p->from;
-	v2 = &p->to;
-	if(copyas(v1, v2))
-		return 1;
-	for(r=firstr; r!=R; r=r->link)
-		r->active = 0;
-	return copy1(v1, v2, r0->s1, 0);
-}
-
-int
-copy1(Addr *v1, Addr *v2, Reg *r, int f)
-{
-	int t;
-	Prog *p;
-
-	if(r->active) {
-		if(debug['P'])
-			print("act set; return 1\n");
-		return 1;
-	}
-	r->active = 1;
-	if(debug['P'])
-		print("copy %D->%D f=%d\n", v1, v2, f);
-	for(; r != R; r = r->s1) {
-		p = r->prog;
-		if(debug['P'])
-			print("%P", p);
-		if(!f && uniqp(r) == R) {
-			f = 1;
-			if(debug['P'])
-				print("; merge; f=%d", f);
-		}
-		t = copyu(p, v2, A);
-		switch(t) {
-		case 2:	/* rar, can't split */
-			if(debug['P'])
-				print("; %D rar; return 0\n", v2);
-			return 0;
-
-		case 3:	/* set */
-			if(debug['P'])
-				print("; %D set; return 1\n", v2);
-			return 1;
-
-		case 1:	/* used, substitute */
-		case 4:	/* use and set */
-			if(f) {
-				if(!debug['P'])
-					return 0;
-				if(t == 4)
-					print("; %D used+set and f=%d; return 0\n", v2, f);
-				else
-					print("; %D used and f=%d; return 0\n", v2, f);
-				return 0;
-			}
-			if(copyu(p, v2, v1)) {
-				if(debug['P'])
-					print("; sub fail; return 0\n");
-				return 0;
-			}
-			if(debug['P'])
-				print("; sub %D/%D", v2, v1);
-			if(t == 4) {
-				if(debug['P'])
-					print("; %D used+set; return 1\n", v2);
-				return 1;
-			}
-			break;
-		}
-		if(!f) {
-			t = copyu(p, v1, A);
-			if(!f && (t == 2 || t == 3 || t == 4)) {
-				f = 1;
-				if(debug['P'])
-					print("; %D set and !f; f=%d", v1, f);
-			}
-		}
-		if(debug['P'])
-			print("\n");
-		if(r->s2)
-			if(!copy1(v1, v2, r->s2, f))
-				return 0;
-	}
-	return 1;
-}
-
-/*
- * return
- * 1 if v only used (and substitute),
- * 2 if read-alter-rewrite
- * 3 if set
- * 4 if set and used
- * 0 otherwise (not touched)
- */
-int
-copyu(Prog *p, Addr *v, Addr *s)
-{
-
-	switch(p->as) {
-
-	default:
-		if(debug['P'])
-			print("unknown op %A\n", p->as);
-		/* SBBL; ADCL; FLD1; SAHF */
-		return 2;
-
-
-	case ANEGB:
-	case ANEGW:
-	case ANEGL:
-	case ANEGQ:
-	case ANOTB:
-	case ANOTW:
-	case ANOTL:
-	case ANOTQ:
-		if(copyas(&p->to, v))
-			return 2;
-		break;
-
-	case ALEAL:	/* lhs addr, rhs store */
-	case ALEAQ:
-		if(copyas(&p->from, v))
-			return 2;
-
-
-	case ANOP:	/* rhs store */
-	case AMOVL:
-	case AMOVQ:
-	case AMOVBLSX:
-	case AMOVBLZX:
-	case AMOVBQSX:
-	case AMOVBQZX:
-	case AMOVLQSX:
-	case AMOVLQZX:
-	case AMOVWLSX:
-	case AMOVWLZX:
-	case AMOVWQSX:
-	case AMOVWQZX:
-	case AMOVQL:
-
-	case AMOVSS:
-	case AMOVSD:
-	case ACVTSD2SL:
-	case ACVTSD2SQ:
-	case ACVTSD2SS:
-	case ACVTSL2SD:
-	case ACVTSL2SS:
-	case ACVTSQ2SD:
-	case ACVTSQ2SS:
-	case ACVTSS2SD:
-	case ACVTSS2SL:
-	case ACVTSS2SQ:
-	case ACVTTSD2SL:
-	case ACVTTSD2SQ:
-	case ACVTTSS2SL:
-	case ACVTTSS2SQ:
-		if(copyas(&p->to, v)) {
-			if(s != A)
-				return copysub(&p->from, v, s, 1);
-			if(copyau(&p->from, v))
-				return 4;
-			return 3;
-		}
-		goto caseread;
-
-	case AROLB:
-	case AROLL:
-	case AROLQ:
-	case AROLW:
-	case ARORB:
-	case ARORL:
-	case ARORQ:
-	case ARORW:
-	case ASALB:
-	case ASALL:
-	case ASALQ:
-	case ASALW:
-	case ASARB:
-	case ASARL:
-	case ASARQ:
-	case ASARW:
-	case ASHLB:
-	case ASHLL:
-	case ASHLQ:
-	case ASHLW:
-	case ASHRB:
-	case ASHRL:
-	case ASHRQ:
-	case ASHRW:
-		if(copyas(&p->to, v))
-			return 2;
-		if(copyas(&p->from, v))
-			if(p->from.type == D_CX)
-				return 2;
-		goto caseread;
-
-	case AADDB:	/* rhs rar */
-	case AADDL:
-	case AADDQ:
-	case AADDW:
-	case AANDB:
-	case AANDL:
-	case AANDQ:
-	case AANDW:
-	case ADECL:
-	case ADECQ:
-	case ADECW:
-	case AINCL:
-	case AINCQ:
-	case AINCW:
-	case ASUBB:
-	case ASUBL:
-	case ASUBQ:
-	case ASUBW:
-	case AORB:
-	case AORL:
-	case AORQ:
-	case AORW:
-	case AXORB:
-	case AXORL:
-	case AXORQ:
-	case AXORW:
-	case AMOVB:
-	case AMOVW:
-
-	case AADDSD:
-	case AADDSS:
-	case ACMPSD:
-	case ACMPSS:
-	case ADIVSD:
-	case ADIVSS:
-	case AMAXSD:
-	case AMAXSS:
-	case AMINSD:
-	case AMINSS:
-	case AMULSD:
-	case AMULSS:
-	case ARCPSS:
-	case ARSQRTSS:
-	case ASQRTSD:
-	case ASQRTSS:
-	case ASUBSD:
-	case ASUBSS:
-	case AXORPD:
-		if(copyas(&p->to, v))
-			return 2;
-		goto caseread;
-
-	case ACMPL:	/* read only */
-	case ACMPW:
-	case ACMPB:
-	case ACMPQ:
-
-	case APREFETCHT0:
-	case APREFETCHT1:
-	case APREFETCHT2:
-	case APREFETCHNTA:
-
-	case ACOMISD:
-	case ACOMISS:
-	case AUCOMISD:
-	case AUCOMISS:
-	caseread:
-		if(s != A) {
-			if(copysub(&p->from, v, s, 1))
-				return 1;
-			return copysub(&p->to, v, s, 1);
-		}
-		if(copyau(&p->from, v))
-			return 1;
-		if(copyau(&p->to, v))
-			return 1;
-		break;
-
-	case AJGE:	/* no reference */
-	case AJNE:
-	case AJLE:
-	case AJEQ:
-	case AJHI:
-	case AJLS:
-	case AJMI:
-	case AJPL:
-	case AJGT:
-	case AJLT:
-	case AJCC:
-	case AJCS:
-
-	case AADJSP:
-	case AWAIT:
-	case ACLD:
-		break;
-
-	case AIMULL:
-	case AIMULQ:
-	case AIMULW:
-		if(p->to.type != D_NONE) {
-			if(copyas(&p->to, v))
-				return 2;
-			goto caseread;
-		}
-
-	case ADIVB:
-	case ADIVL:
-	case ADIVQ:
-	case ADIVW:
-	case AIDIVB:
-	case AIDIVL:
-	case AIDIVQ:
-	case AIDIVW:
-	case AIMULB:
-	case AMULB:
-	case AMULL:
-	case AMULQ:
-	case AMULW:
-
-	case ACWD:
-	case ACDQ:
-	case ACQO:
-		if(v->type == D_AX || v->type == D_DX)
-			return 2;
-		goto caseread;
-
-	case AREP:
-	case AREPN:
-		if(v->type == D_CX)
-			return 2;
-		goto caseread;
-
-	case AMOVSB:
-	case AMOVSL:
-	case AMOVSQ:
-		if(v->type == D_DI || v->type == D_SI)
-			return 2;
-		goto caseread;
-
-	case ASTOSB:
-	case ASTOSL:
-	case ASTOSQ:
-		if(v->type == D_AX || v->type == D_DI)
-			return 2;
-		goto caseread;
-
-	case AJMP:	/* funny */
-		if(s != A) {
-			if(copysub(&p->to, v, s, 1))
-				return 1;
-			return 0;
-		}
-		if(copyau(&p->to, v))
-			return 1;
-		return 0;
-
-	case ARET:	/* funny */
-		if(v->type == REGRET || v->type == FREGRET)
-			return 2;
-		if(s != A)
-			return 1;
-		return 3;
-
-	case ACALL:	/* funny */
-		if(REGARG >= 0 && v->type == (uchar)REGARG)
-			return 2;
-
-		if(s != A) {
-			if(copysub(&p->to, v, s, 1))
-				return 1;
-			return 0;
-		}
-		if(copyau(&p->to, v))
-			return 4;
-		return 3;
-
-	case ATEXT:	/* funny */
-		if(REGARG >= 0 && v->type == (uchar)REGARG)
-			return 3;
-		return 0;
-	}
-	return 0;
-}
-
-/*
- * direct reference,
- * could be set/use depending on
- * semantics
- */
-int
-copyas(Addr *a, Addr *v)
-{
-	if(a->type != v->type)
-		return 0;
-	if(regtyp(v))
-		return 1;
-	if(v->type == D_AUTO || v->type == D_PARAM)
-		if(v->offset == a->offset)
-			return 1;
-	return 0;
-}
-
-/*
- * either direct or indirect
- */
-int
-copyau(Addr *a, Addr *v)
-{
-
-	if(copyas(a, v))
-		return 1;
-	if(regtyp(v)) {
-		if(a->type-D_INDIR == v->type)
-			return 1;
-		if(a->index == v->type)
-			return 1;
-	}
-	return 0;
-}
-
-/*
- * substitute s for v in a
- * return failure to substitute
- */
-int
-copysub(Addr *a, Addr *v, Addr *s, int f)
-{
-	int t;
-
-	if(copyas(a, v)) {
-		t = s->type;
-		if(t >= D_AX && t <= D_R15 || t >= D_X0 && t <= D_X0+15) {
-			if(f)
-				a->type = t;
-		}
-		return 0;
-	}
-	if(regtyp(v)) {
-		t = v->type;
-		if(a->type == t+D_INDIR) {
-			if((s->type == D_BP || s->type == D_R13) && a->index != D_NONE)
-				return 1;	/* can't use BP-base with index */
-			if(f)
-				a->type = s->type+D_INDIR;
-//			return 0;
-		}
-		if(a->index == t) {
-			if(f)
-				a->index = s->type;
-			return 0;
-		}
-		return 0;
-	}
-	return 0;
-}
diff --git a/src/cmd/6c/reg.c b/src/cmd/6c/reg.c
deleted file mode 100644
index 6f8d3ce..0000000
--- a/src/cmd/6c/reg.c
+++ /dev/null
@@ -1,1523 +0,0 @@
-// 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 at 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 at 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.
-
-#include "gc.h"
-
-static	void	fixjmp(Reg*);
-
-Reg*
-rega(void)
-{
-	Reg *r;
-
-	r = freer;
-	if(r == R) {
-		r = alloc(sizeof(*r));
-	} else
-		freer = r->link;
-
-	*r = zreg;
-	return r;
-}
-
-int
-rcmp(const void *a1, const void *a2)
-{
-	Rgn *p1, *p2;
-	int c1, c2;
-
-	p1 = (Rgn*)a1;
-	p2 = (Rgn*)a2;
-	c1 = p2->cost;
-	c2 = p1->cost;
-	if(c1 -= c2)
-		return c1;
-	return p2->varno - p1->varno;
-}
-
-void
-regopt(Prog *p)
-{
-	Reg *r, *r1, *r2;
-	Prog *p1;
-	int i, z;
-	int32 initpc, val, npc;
-	uint32 vreg;
-	Bits bit;
-	struct
-	{
-		int32	m;
-		int32	c;
-		Reg*	p;
-	} log5[6], *lp;
-
-	firstr = R;
-	lastr = R;
-	nvar = 0;
-	regbits = RtoB(D_SP) | RtoB(D_AX) | RtoB(D_X0);
-	for(z=0; z<BITS; z++) {
-		externs.b[z] = 0;
-		params.b[z] = 0;
-		consts.b[z] = 0;
-		addrs.b[z] = 0;
-	}
-
-	/*
-	 * pass 1
-	 * build aux data structure
-	 * allocate pcs
-	 * find use and set of variables
-	 */
-	val = 5L * 5L * 5L * 5L * 5L;
-	lp = log5;
-	for(i=0; i<5; i++) {
-		lp->m = val;
-		lp->c = 0;
-		lp->p = R;
-		val /= 5L;
-		lp++;
-	}
-	val = 0;
-	for(; p != P; p = p->link) {
-		switch(p->as) {
-		case ADATA:
-		case AGLOBL:
-		case ANAME:
-		case ASIGNAME:
-		case AFUNCDATA:
-			continue;
-		}
-		r = rega();
-		if(firstr == R) {
-			firstr = r;
-			lastr = r;
-		} else {
-			lastr->link = r;
-			r->p1 = lastr;
-			lastr->s1 = r;
-			lastr = r;
-		}
-		r->prog = p;
-		r->pc = val;
-		val++;
-
-		lp = log5;
-		for(i=0; i<5; i++) {
-			lp->c--;
-			if(lp->c <= 0) {
-				lp->c = lp->m;
-				if(lp->p != R)
-					lp->p->log5 = r;
-				lp->p = r;
-				(lp+1)->c = 0;
-				break;
-			}
-			lp++;
-		}
-
-		r1 = r->p1;
-		if(r1 != R)
-		switch(r1->prog->as) {
-		case ARET:
-		case AJMP:
-		case AIRETL:
-		case AIRETQ:
-			r->p1 = R;
-			r1->s1 = R;
-		}
-
-		bit = mkvar(r, &p->from);
-		if(bany(&bit))
-		switch(p->as) {
-		/*
-		 * funny
-		 */
-		case ALEAL:
-		case ALEAQ:
-			for(z=0; z<BITS; z++)
-				addrs.b[z] |= bit.b[z];
-			break;
-
-		/*
-		 * left side read
-		 */
-		default:
-			for(z=0; z<BITS; z++)
-				r->use1.b[z] |= bit.b[z];
-			break;
-		}
-
-		bit = mkvar(r, &p->to);
-		if(bany(&bit))
-		switch(p->as) {
-		default:
-			diag(Z, "reg: unknown op: %A", p->as);
-			break;
-
-		/*
-		 * right side read
-		 */
-		case ACMPB:
-		case ACMPL:
-		case ACMPQ:
-		case ACMPW:
-		case APREFETCHT0:
-		case APREFETCHT1:
-		case APREFETCHT2:
-		case APREFETCHNTA:
-		case ACOMISS:
-		case ACOMISD:
-		case AUCOMISS:
-		case AUCOMISD:
-			for(z=0; z<BITS; z++)
-				r->use2.b[z] |= bit.b[z];
-			break;
-
-		/*
-		 * right side write
-		 */
-		case ANOP:
-		case AMOVL:
-		case AMOVQ:
-		case AMOVB:
-		case AMOVW:
-		case AMOVBLSX:
-		case AMOVBLZX:
-		case AMOVBQSX:
-		case AMOVBQZX:
-		case AMOVLQSX:
-		case AMOVLQZX:
-		case AMOVWLSX:
-		case AMOVWLZX:
-		case AMOVWQSX:
-		case AMOVWQZX:
-		case AMOVQL:
-
-		case AMOVSS:
-		case AMOVSD:
-		case ACVTSD2SL:
-		case ACVTSD2SQ:
-		case ACVTSD2SS:
-		case ACVTSL2SD:
-		case ACVTSL2SS:
-		case ACVTSQ2SD:
-		case ACVTSQ2SS:
-		case ACVTSS2SD:
-		case ACVTSS2SL:
-		case ACVTSS2SQ:
-		case ACVTTSD2SL:
-		case ACVTTSD2SQ:
-		case ACVTTSS2SL:
-		case ACVTTSS2SQ:
-			for(z=0; z<BITS; z++)
-				r->set.b[z] |= bit.b[z];
-			break;
-
-		/*
-		 * right side read+write
-		 */
-		case AADDB:
-		case AADDL:
-		case AADDQ:
-		case AADDW:
-		case AANDB:
-		case AANDL:
-		case AANDQ:
-		case AANDW:
-		case ASUBB:
-		case ASUBL:
-		case ASUBQ:
-		case ASUBW:
-		case AORB:
-		case AORL:
-		case AORQ:
-		case AORW:
-		case AXORB:
-		case AXORL:
-		case AXORQ:
-		case AXORW:
-		case ASALB:
-		case ASALL:
-		case ASALQ:
-		case ASALW:
-		case ASARB:
-		case ASARL:
-		case ASARQ:
-		case ASARW:
-		case AROLB:
-		case AROLL:
-		case AROLQ:
-		case AROLW:
-		case ARORB:
-		case ARORL:
-		case ARORQ:
-		case ARORW:
-		case ASHLB:
-		case ASHLL:
-		case ASHLQ:
-		case ASHLW:
-		case ASHRB:
-		case ASHRL:
-		case ASHRQ:
-		case ASHRW:
-		case AIMULL:
-		case AIMULQ:
-		case AIMULW:
-		case ANEGL:
-		case ANEGQ:
-		case ANOTL:
-		case ANOTQ:
-		case AADCL:
-		case AADCQ:
-		case ASBBL:
-		case ASBBQ:
-
-		case AADDSD:
-		case AADDSS:
-		case ACMPSD:
-		case ACMPSS:
-		case ADIVSD:
-		case ADIVSS:
-		case AMAXSD:
-		case AMAXSS:
-		case AMINSD:
-		case AMINSS:
-		case AMULSD:
-		case AMULSS:
-		case ARCPSS:
-		case ARSQRTSS:
-		case ASQRTSD:
-		case ASQRTSS:
-		case ASUBSD:
-		case ASUBSS:
-		case AXORPD:
-			for(z=0; z<BITS; z++) {
-				r->set.b[z] |= bit.b[z];
-				r->use2.b[z] |= bit.b[z];
-			}
-			break;
-
-		/*
-		 * funny
-		 */
-		case ACALL:
-			for(z=0; z<BITS; z++)
-				addrs.b[z] |= bit.b[z];
-			break;
-		}
-
-		switch(p->as) {
-		case AIMULL:
-		case AIMULQ:
-		case AIMULW:
-			if(p->to.type != D_NONE)
-				break;
-
-		case AIDIVB:
-		case AIDIVL:
-		case AIDIVQ:
-		case AIDIVW:
-		case AIMULB:
-		case ADIVB:
-		case ADIVL:
-		case ADIVQ:
-		case ADIVW:
-		case AMULB:
-		case AMULL:
-		case AMULQ:
-		case AMULW:
-
-		case ACWD:
-		case ACDQ:
-		case ACQO:
-			r->regu |= RtoB(D_AX) | RtoB(D_DX);
-			break;
-
-		case AREP:
-		case AREPN:
-		case ALOOP:
-		case ALOOPEQ:
-		case ALOOPNE:
-			r->regu |= RtoB(D_CX);
-			break;
-
-		case AMOVSB:
-		case AMOVSL:
-		case AMOVSQ:
-		case AMOVSW:
-		case ACMPSB:
-		case ACMPSL:
-		case ACMPSQ:
-		case ACMPSW:
-			r->regu |= RtoB(D_SI) | RtoB(D_DI);
-			break;
-
-		case ASTOSB:
-		case ASTOSL:
-		case ASTOSQ:
-		case ASTOSW:
-		case ASCASB:
-		case ASCASL:
-		case ASCASQ:
-		case ASCASW:
-			r->regu |= RtoB(D_AX) | RtoB(D_DI);
-			break;
-
-		case AINSB:
-		case AINSL:
-		case AINSW:
-		case AOUTSB:
-		case AOUTSL:
-		case AOUTSW:
-			r->regu |= RtoB(D_DI) | RtoB(D_DX);
-			break;
-		}
-	}
-	if(firstr == R)
-		return;
-	initpc = pc - val;
-	npc = val;
-
-	/*
-	 * pass 2
-	 * turn branch references to pointers
-	 * build back pointers
-	 */
-	for(r = firstr; r != R; r = r->link) {
-		p = r->prog;
-		if(p->to.type == D_BRANCH) {
-			val = p->to.offset - initpc;
-			r1 = firstr;
-			while(r1 != R) {
-				r2 = r1->log5;
-				if(r2 != R && val >= r2->pc) {
-					r1 = r2;
-					continue;
-				}
-				if(r1->pc == val)
-					break;
-				r1 = r1->link;
-			}
-			if(r1 == R) {
-				nearln = p->lineno;
-				diag(Z, "ref not found\n%P", p);
-				continue;
-			}
-			if(r1 == r) {
-				nearln = p->lineno;
-				diag(Z, "ref to self\n%P", p);
-				continue;
-			}
-			r->s2 = r1;
-			r->p2link = r1->p2;
-			r1->p2 = r;
-		}
-	}
-	if(debug['R']) {
-		p = firstr->prog;
-		print("\n%L %D\n", p->lineno, &p->from);
-	}
-
-	/*
-	 * pass 2.1
-	 * fix jumps
-	 */
-	fixjmp(firstr);
-
-	/*
-	 * pass 2.5
-	 * find looping structure
-	 */
-	for(r = firstr; r != R; r = r->link)
-		r->active = 0;
-	change = 0;
-	loopit(firstr, npc);
-	if(debug['R'] && debug['v']) {
-		print("\nlooping structure:\n");
-		for(r = firstr; r != R; r = r->link) {
-			print("%d:%P", r->loop, r->prog);
-			for(z=0; z<BITS; z++)
-				bit.b[z] = r->use1.b[z] |
-					   r->use2.b[z] |
-					   r->set.b[z];
-			if(bany(&bit)) {
-				print("\t");
-				if(bany(&r->use1))
-					print(" u1=%B", r->use1);
-				if(bany(&r->use2))
-					print(" u2=%B", r->use2);
-				if(bany(&r->set))
-					print(" st=%B", r->set);
-			}
-			print("\n");
-		}
-	}
-
-	/*
-	 * pass 3
-	 * iterate propagating usage
-	 * 	back until flow graph is complete
-	 */
-loop1:
-	change = 0;
-	for(r = firstr; r != R; r = r->link)
-		r->active = 0;
-	for(r = firstr; r != R; r = r->link)
-		if(r->prog->as == ARET)
-			prop(r, zbits, zbits);
-loop11:
-	/* pick up unreachable code */
-	i = 0;
-	for(r = firstr; r != R; r = r1) {
-		r1 = r->link;
-		if(r1 && r1->active && !r->active) {
-			prop(r, zbits, zbits);
-			i = 1;
-		}
-	}
-	if(i)
-		goto loop11;
-	if(change)
-		goto loop1;
-
-
-	/*
-	 * pass 4
-	 * iterate propagating register/variable synchrony
-	 * 	forward until graph is complete
-	 */
-loop2:
-	change = 0;
-	for(r = firstr; r != R; r = r->link)
-		r->active = 0;
-	synch(firstr, zbits);
-	if(change)
-		goto loop2;
-
-
-	/*
-	 * pass 5
-	 * isolate regions
-	 * calculate costs (paint1)
-	 */
-	r = firstr;
-	if(r) {
-		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]);
-		if(bany(&bit)) {
-			nearln = r->prog->lineno;
-			warn(Z, "used and not set: %B", bit);
-			if(debug['R'] && !debug['w'])
-				print("used and not set: %B\n", bit);
-		}
-	}
-	if(debug['R'] && debug['v'])
-		print("\nprop structure:\n");
-	for(r = firstr; r != R; r = r->link)
-		r->act = zbits;
-	rgp = region;
-	nregion = 0;
-	for(r = firstr; r != R; r = r->link) {
-		if(debug['R'] && debug['v']) {
-			print("%P\t", r->prog);
-			if(bany(&r->set))
-				print("s:%B ", r->set);
-			if(bany(&r->refahead))
-				print("ra:%B ", r->refahead);
-			if(bany(&r->calahead))
-				print("ca:%B ", r->calahead);
-			print("\n");
-		}
-		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)) {
-			nearln = r->prog->lineno;
-			warn(Z, "set and not used: %B", bit);
-			if(debug['R'])
-				print("set and not used: %B\n", bit);
-			excise(r);
-		}
-		for(z=0; z<BITS; z++)
-			bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]);
-		while(bany(&bit)) {
-			i = bnum(bit);
-			rgp->enter = r;
-			rgp->varno = i;
-			change = 0;
-			if(debug['R'] && debug['v'])
-				print("\n");
-			paint1(r, i);
-			bit.b[i/32] &= ~(1L<<(i%32));
-			if(change <= 0) {
-				if(debug['R'])
-					print("%L$%d: %B\n",
-						r->prog->lineno, change, blsh(i));
-				continue;
-			}
-			rgp->cost = change;
-			nregion++;
-			if(nregion >= NRGN)
-				fatal(Z, "too many regions");
-			rgp++;
-		}
-	}
-	qsort(region, nregion, sizeof(region[0]), rcmp);
-
-	/*
-	 * pass 6
-	 * determine used registers (paint2)
-	 * replace code (paint3)
-	 */
-	rgp = region;
-	for(i=0; i<nregion; i++) {
-		bit = blsh(rgp->varno);
-		vreg = paint2(rgp->enter, rgp->varno);
-		vreg = allreg(vreg, rgp);
-		if(debug['R']) {
-			print("%L$%d %R: %B\n",
-				rgp->enter->prog->lineno,
-				rgp->cost,
-				rgp->regno,
-				bit);
-		}
-		if(rgp->regno != 0)
-			paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
-		rgp++;
-	}
-	/*
-	 * pass 7
-	 * peep-hole on basic block
-	 */
-	if(!debug['R'] || debug['P'])
-		peep();
-
-	/*
-	 * pass 8
-	 * recalculate pc
-	 */
-	val = initpc;
-	for(r = firstr; r != R; r = r1) {
-		r->pc = val;
-		p = r->prog;
-		p1 = P;
-		r1 = r->link;
-		if(r1 != R)
-			p1 = r1->prog;
-		for(; p != p1; p = p->link) {
-			switch(p->as) {
-			default:
-				val++;
-				break;
-
-			case ANOP:
-			case ADATA:
-			case AGLOBL:
-			case ANAME:
-			case ASIGNAME:
-			case AFUNCDATA:
-				break;
-			}
-		}
-	}
-	pc = val;
-
-	/*
-	 * fix up branches
-	 */
-	if(debug['R'])
-		if(bany(&addrs))
-			print("addrs: %B\n", addrs);
-
-	r1 = 0; /* set */
-	for(r = firstr; r != R; r = r->link) {
-		p = r->prog;
-		if(p->to.type == D_BRANCH) {
-			p->to.offset = r->s2->pc;
-			p->to.u.branch = r->s2->prog;
-		}
-		r1 = r;
-	}
-
-	/*
-	 * last pass
-	 * eliminate nops
-	 * free aux structures
-	 */
-	for(p = firstr->prog; p != P; p = p->link){
-		while(p->link && p->link->as == ANOP)
-			p->link = p->link->link;
-	}
-	if(r1 != R) {
-		r1->link = freer;
-		freer = firstr;
-	}
-}
-
-/*
- * add mov b,rn
- * just after r
- */
-void
-addmove(Reg *r, int bn, int rn, int f)
-{
-	Prog *p, *p1;
-	Addr *a;
-	Var *v;
-
-	p1 = alloc(sizeof(*p1));
-	*p1 = zprog;
-	p = r->prog;
-
-	p1->link = p->link;
-	p->link = p1;
-	p1->lineno = p->lineno;
-
-	v = var + bn;
-
-	a = &p1->to;
-	a->sym = v->sym;
-	a->offset = v->offset;
-	a->etype = v->etype;
-	a->type = v->name;
-
-	p1->as = AMOVL;
-	if(v->etype == TCHAR || v->etype == TUCHAR)
-		p1->as = AMOVB;
-	if(v->etype == TSHORT || v->etype == TUSHORT)
-		p1->as = AMOVW;
-	if(v->etype == TVLONG || v->etype == TUVLONG || (v->etype == TIND && ewidth[TIND] == 8))
-		p1->as = AMOVQ;
-	if(v->etype == TFLOAT)
-		p1->as = AMOVSS;
-	if(v->etype == TDOUBLE)
-		p1->as = AMOVSD;
-
-	p1->from.type = rn;
-	if(!f) {
-		p1->from = *a;
-		*a = zprog.from;
-		a->type = rn;
-		if(v->etype == TUCHAR)
-			p1->as = AMOVB;
-		if(v->etype == TUSHORT)
-			p1->as = AMOVW;
-	}
-	if(debug['R'])
-		print("%P\t.a%P\n", p, p1);
-}
-
-uint32
-doregbits(int r)
-{
-	uint32 b;
-
-	b = 0;
-	if(r >= D_INDIR)
-		r -= D_INDIR;
-	if(r >= D_AX && r <= D_R15)
-		b |= RtoB(r);
-	else
-	if(r >= D_AL && r <= D_R15B)
-		b |= RtoB(r-D_AL+D_AX);
-	else
-	if(r >= D_AH && r <= D_BH)
-		b |= RtoB(r-D_AH+D_AX);
-	else
-	if(r >= D_X0 && r <= D_X0+15)
-		b |= FtoB(r);
-	return b;
-}
-
-Bits
-mkvar(Reg *r, Addr *a)
-{
-	Var *v;
-	int i, t, n, et, z;
-	int32 o;
-	Bits bit;
-	LSym *s;
-
-	/*
-	 * mark registers used
-	 */
-	t = a->type;
-	r->regu |= doregbits(t);
-	r->regu |= doregbits(a->index);
-
-	switch(t) {
-	default:
-		goto none;
-	case D_ADDR:
-		a->type = a->index;
-		bit = mkvar(r, a);
-		for(z=0; z<BITS; z++)
-			addrs.b[z] |= bit.b[z];
-		a->type = t;
-		goto none;
-	case D_EXTERN:
-	case D_STATIC:
-	case D_PARAM:
-	case D_AUTO:
-		n = t;
-		break;
-	}
-	s = a->sym;
-	if(s == nil)
-		goto none;
-	if(s->name[0] == '.')
-		goto none;
-	et = a->etype;
-	o = a->offset;
-	v = var;
-	for(i=0; i<nvar; i++) {
-		if(s == v->sym)
-		if(n == v->name)
-		if(o == v->offset)
-			goto out;
-		v++;
-	}
-	if(nvar >= NVAR)
-		fatal(Z, "variable not optimized: %s", s->name);
-	i = nvar;
-	nvar++;
-	v = &var[i];
-	v->sym = s;
-	v->offset = o;
-	v->name = n;
-	v->etype = et;
-	if(debug['R'])
-		print("bit=%2d et=%2d %D\n", i, et, a);
-
-out:
-	bit = blsh(i);
-	if(n == D_EXTERN || n == D_STATIC)
-		for(z=0; z<BITS; z++)
-			externs.b[z] |= bit.b[z];
-	if(n == D_PARAM)
-		for(z=0; z<BITS; z++)
-			params.b[z] |= bit.b[z];
-	if(v->etype != et || !(typechlpfd[et] || typev[et]))	/* funny punning */
-		for(z=0; z<BITS; z++)
-			addrs.b[z] |= bit.b[z];
-	return bit;
-
-none:
-	return zbits;
-}
-
-void
-prop(Reg *r, Bits ref, Bits cal)
-{
-	Reg *r1, *r2;
-	int z;
-
-	for(r1 = r; r1 != R; r1 = r1->p1) {
-		for(z=0; z<BITS; z++) {
-			ref.b[z] |= r1->refahead.b[z];
-			if(ref.b[z] != r1->refahead.b[z]) {
-				r1->refahead.b[z] = ref.b[z];
-				change++;
-			}
-			cal.b[z] |= r1->calahead.b[z];
-			if(cal.b[z] != r1->calahead.b[z]) {
-				r1->calahead.b[z] = cal.b[z];
-				change++;
-			}
-		}
-		switch(r1->prog->as) {
-		case ACALL:
-			for(z=0; z<BITS; z++) {
-				cal.b[z] |= ref.b[z] | externs.b[z];
-				ref.b[z] = 0;
-			}
-			break;
-
-		case ATEXT:
-			for(z=0; z<BITS; z++) {
-				cal.b[z] = 0;
-				ref.b[z] = 0;
-			}
-			break;
-
-		case ARET:
-			for(z=0; z<BITS; z++) {
-				cal.b[z] = externs.b[z];
-				ref.b[z] = 0;
-			}
-		}
-		for(z=0; z<BITS; z++) {
-			ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
-				r1->use1.b[z] | r1->use2.b[z];
-			cal.b[z] &= ~(r1->set.b[z] | r1->use1.b[z] | r1->use2.b[z]);
-			r1->refbehind.b[z] = ref.b[z];
-			r1->calbehind.b[z] = cal.b[z];
-		}
-		if(r1->active)
-			break;
-		r1->active = 1;
-	}
-	for(; r != r1; r = r->p1)
-		for(r2 = r->p2; r2 != R; r2 = r2->p2link)
-			prop(r2, r->refbehind, r->calbehind);
-}
-
-/*
- * find looping structure
- *
- * 1) find reverse postordering
- * 2) find approximate dominators,
- *	the actual dominators if the flow graph is reducible
- *	otherwise, dominators plus some other non-dominators.
- *	See Matthew S. Hecht and Jeffrey D. Ullman,
- *	"Analysis of a Simple Algorithm for Global Data Flow Problems",
- *	Conf.  Record of ACM Symp. on Principles of Prog. Langs, Boston, Massachusetts,
- *	Oct. 1-3, 1973, pp.  207-217.
- * 3) find all nodes with a predecessor dominated by the current node.
- *	such a node is a loop head.
- *	recursively, all preds with a greater rpo number are in the loop
- */
-int32
-postorder(Reg *r, Reg **rpo2r, int32 n)
-{
-	Reg *r1;
-
-	r->rpo = 1;
-	r1 = r->s1;
-	if(r1 && !r1->rpo)
-		n = postorder(r1, rpo2r, n);
-	r1 = r->s2;
-	if(r1 && !r1->rpo)
-		n = postorder(r1, rpo2r, n);
-	rpo2r[n] = r;
-	n++;
-	return n;
-}
-
-int32
-rpolca(int32 *idom, int32 rpo1, int32 rpo2)
-{
-	int32 t;
-
-	if(rpo1 == -1)
-		return rpo2;
-	while(rpo1 != rpo2){
-		if(rpo1 > rpo2){
-			t = rpo2;
-			rpo2 = rpo1;
-			rpo1 = t;
-		}
-		while(rpo1 < rpo2){
-			t = idom[rpo2];
-			if(t >= rpo2)
-				fatal(Z, "bad idom");
-			rpo2 = t;
-		}
-	}
-	return rpo1;
-}
-
-int
-doms(int32 *idom, int32 r, int32 s)
-{
-	while(s > r)
-		s = idom[s];
-	return s == r;
-}
-
-int
-loophead(int32 *idom, Reg *r)
-{
-	int32 src;
-
-	src = r->rpo;
-	if(r->p1 != R && doms(idom, src, r->p1->rpo))
-		return 1;
-	for(r = r->p2; r != R; r = r->p2link)
-		if(doms(idom, src, r->rpo))
-			return 1;
-	return 0;
-}
-
-void
-loopmark(Reg **rpo2r, int32 head, Reg *r)
-{
-	if(r->rpo < head || r->active == head)
-		return;
-	r->active = head;
-	r->loop += LOOP;
-	if(r->p1 != R)
-		loopmark(rpo2r, head, r->p1);
-	for(r = r->p2; r != R; r = r->p2link)
-		loopmark(rpo2r, head, r);
-}
-
-void
-loopit(Reg *r, int32 nr)
-{
-	Reg *r1;
-	int32 i, d, me;
-
-	if(nr > maxnr) {
-		rpo2r = alloc(nr * sizeof(Reg*));
-		idom = alloc(nr * sizeof(int32));
-		maxnr = nr;
-	}
-
-	d = postorder(r, rpo2r, 0);
-	if(d > nr)
-		fatal(Z, "too many reg nodes");
-	nr = d;
-	for(i = 0; i < nr / 2; i++){
-		r1 = rpo2r[i];
-		rpo2r[i] = rpo2r[nr - 1 - i];
-		rpo2r[nr - 1 - i] = r1;
-	}
-	for(i = 0; i < nr; i++)
-		rpo2r[i]->rpo = i;
-
-	idom[0] = 0;
-	for(i = 0; i < nr; i++){
-		r1 = rpo2r[i];
-		me = r1->rpo;
-		d = -1;
-		if(r1->p1 != R && r1->p1->rpo < me)
-			d = r1->p1->rpo;
-		for(r1 = r1->p2; r1 != nil; r1 = r1->p2link)
-			if(r1->rpo < me)
-				d = rpolca(idom, d, r1->rpo);
-		idom[i] = d;
-	}
-
-	for(i = 0; i < nr; i++){
-		r1 = rpo2r[i];
-		r1->loop++;
-		if(r1->p2 != R && loophead(idom, r1))
-			loopmark(rpo2r, i, r1);
-	}
-}
-
-void
-synch(Reg *r, Bits dif)
-{
-	Reg *r1;
-	int z;
-
-	for(r1 = r; r1 != R; r1 = r1->s1) {
-		for(z=0; z<BITS; z++) {
-			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++;
-			}
-		}
-		if(r1->active)
-			break;
-		r1->active = 1;
-		for(z=0; z<BITS; z++)
-			dif.b[z] &= ~(~r1->calbehind.b[z] & r1->calahead.b[z]);
-		if(r1->s2 != R)
-			synch(r1->s2, dif);
-	}
-}
-
-uint32
-allreg(uint32 b, Rgn *r)
-{
-	Var *v;
-	int i;
-
-	v = var + r->varno;
-	r->regno = 0;
-	switch(v->etype) {
-
-	default:
-		diag(Z, "unknown etype %d/%d", bitno(b), v->etype);
-		break;
-
-	case TCHAR:
-	case TUCHAR:
-	case TSHORT:
-	case TUSHORT:
-	case TINT:
-	case TUINT:
-	case TLONG:
-	case TULONG:
-	case TVLONG:
-	case TUVLONG:
-	case TIND:
-	case TARRAY:
-		i = BtoR(~b);
-		if(i && r->cost > 0) {
-			r->regno = i;
-			return RtoB(i);
-		}
-		break;
-
-	case TDOUBLE:
-	case TFLOAT:
-		i = BtoF(~b);
-		if(i && r->cost > 0) {
-			r->regno = i;
-			return FtoB(i);
-		}
-		break;
-	}
-	return 0;
-}
-
-void
-paint1(Reg *r, int bn)
-{
-	Reg *r1;
-	Prog *p;
-	int z;
-	uint32 bb;
-
-	z = bn/32;
-	bb = 1L<<(bn%32);
-	if(r->act.b[z] & bb)
-		return;
-	for(;;) {
-		if(!(r->refbehind.b[z] & bb))
-			break;
-		r1 = r->p1;
-		if(r1 == R)
-			break;
-		if(!(r1->refahead.b[z] & bb))
-			break;
-		if(r1->act.b[z] & bb)
-			break;
-		r = r1;
-	}
-
-	if(LOAD(r) & ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z])) & bb) {
-		change -= CLOAD * r->loop;
-		if(debug['R'] && debug['v'])
-			print("%d%P\td %B $%d\n", r->loop,
-				r->prog, blsh(bn), change);
-	}
-	for(;;) {
-		r->act.b[z] |= bb;
-		p = r->prog;
-
-		if(r->use1.b[z] & bb) {
-			change += CREF * r->loop;
-			if(debug['R'] && debug['v'])
-				print("%d%P\tu1 %B $%d\n", r->loop,
-					p, blsh(bn), change);
-		}
-
-		if((r->use2.b[z]|r->set.b[z]) & bb) {
-			change += CREF * r->loop;
-			if(debug['R'] && debug['v'])
-				print("%d%P\tu2 %B $%d\n", r->loop,
-					p, blsh(bn), change);
-		}
-
-		if(STORE(r) & r->regdiff.b[z] & bb) {
-			change -= CLOAD * r->loop;
-			if(debug['R'] && debug['v'])
-				print("%d%P\tst %B $%d\n", r->loop,
-					p, blsh(bn), change);
-		}
-
-		if(r->refbehind.b[z] & bb)
-			for(r1 = r->p2; r1 != R; r1 = r1->p2link)
-				if(r1->refahead.b[z] & bb)
-					paint1(r1, bn);
-
-		if(!(r->refahead.b[z] & bb))
-			break;
-		r1 = r->s2;
-		if(r1 != R)
-			if(r1->refbehind.b[z] & bb)
-				paint1(r1, bn);
-		r = r->s1;
-		if(r == R)
-			break;
-		if(r->act.b[z] & bb)
-			break;
-		if(!(r->refbehind.b[z] & bb))
-			break;
-	}
-}
-
-uint32
-regset(Reg *r, uint32 bb)
-{
-	uint32 b, set;
-	Addr v;
-	int c;
-
-	set = 0;
-	v = zprog.from;
-	while(b = bb & ~(bb-1)) {
-		v.type = b & 0xFFFF? BtoR(b): BtoF(b);
-		if(v.type == 0)
-			diag(Z, "zero v.type for %#ux", b);
-		c = copyu(r->prog, &v, A);
-		if(c == 3)
-			set |= b;
-		bb &= ~b;
-	}
-	return set;
-}
-
-uint32
-reguse(Reg *r, uint32 bb)
-{
-	uint32 b, set;
-	Addr v;
-	int c;
-
-	set = 0;
-	v = zprog.from;
-	while(b = bb & ~(bb-1)) {
-		v.type = b & 0xFFFF? BtoR(b): BtoF(b);
-		c = copyu(r->prog, &v, A);
-		if(c == 1 || c == 2 || c == 4)
-			set |= b;
-		bb &= ~b;
-	}
-	return set;
-}
-
-uint32
-paint2(Reg *r, int bn)
-{
-	Reg *r1;
-	int z;
-	uint32 bb, vreg, x;
-
-	z = bn/32;
-	bb = 1L << (bn%32);
-	vreg = regbits;
-	if(!(r->act.b[z] & bb))
-		return vreg;
-	for(;;) {
-		if(!(r->refbehind.b[z] & bb))
-			break;
-		r1 = r->p1;
-		if(r1 == R)
-			break;
-		if(!(r1->refahead.b[z] & bb))
-			break;
-		if(!(r1->act.b[z] & bb))
-			break;
-		r = r1;
-	}
-	for(;;) {
-		r->act.b[z] &= ~bb;
-
-		vreg |= r->regu;
-
-		if(r->refbehind.b[z] & bb)
-			for(r1 = r->p2; r1 != R; r1 = r1->p2link)
-				if(r1->refahead.b[z] & bb)
-					vreg |= paint2(r1, bn);
-
-		if(!(r->refahead.b[z] & bb))
-			break;
-		r1 = r->s2;
-		if(r1 != R)
-			if(r1->refbehind.b[z] & bb)
-				vreg |= paint2(r1, bn);
-		r = r->s1;
-		if(r == R)
-			break;
-		if(!(r->act.b[z] & bb))
-			break;
-		if(!(r->refbehind.b[z] & bb))
-			break;
-	}
-
-	bb = vreg;
-	for(; r; r=r->s1) {
-		x = r->regu & ~bb;
-		if(x) {
-			vreg |= reguse(r, x);
-			bb |= regset(r, x);
-		}
-	}
-	return vreg;
-}
-
-void
-paint3(Reg *r, int bn, int32 rb, int rn)
-{
-	Reg *r1;
-	Prog *p;
-	int z;
-	uint32 bb;
-
-	z = bn/32;
-	bb = 1L << (bn%32);
-	if(r->act.b[z] & bb)
-		return;
-	for(;;) {
-		if(!(r->refbehind.b[z] & bb))
-			break;
-		r1 = r->p1;
-		if(r1 == R)
-			break;
-		if(!(r1->refahead.b[z] & bb))
-			break;
-		if(r1->act.b[z] & bb)
-			break;
-		r = r1;
-	}
-
-	if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb)
-		addmove(r, bn, rn, 0);
-	for(;;) {
-		r->act.b[z] |= bb;
-		p = r->prog;
-
-		if(r->use1.b[z] & bb) {
-			if(debug['R'])
-				print("%P", p);
-			addreg(&p->from, rn);
-			if(debug['R'])
-				print("\t.c%P\n", p);
-		}
-		if((r->use2.b[z]|r->set.b[z]) & bb) {
-			if(debug['R'])
-				print("%P", p);
-			addreg(&p->to, rn);
-			if(debug['R'])
-				print("\t.c%P\n", p);
-		}
-
-		if(STORE(r) & r->regdiff.b[z] & bb)
-			addmove(r, bn, rn, 1);
-		r->regu |= rb;
-
-		if(r->refbehind.b[z] & bb)
-			for(r1 = r->p2; r1 != R; r1 = r1->p2link)
-				if(r1->refahead.b[z] & bb)
-					paint3(r1, bn, rb, rn);
-
-		if(!(r->refahead.b[z] & bb))
-			break;
-		r1 = r->s2;
-		if(r1 != R)
-			if(r1->refbehind.b[z] & bb)
-				paint3(r1, bn, rb, rn);
-		r = r->s1;
-		if(r == R)
-			break;
-		if(r->act.b[z] & bb)
-			break;
-		if(!(r->refbehind.b[z] & bb))
-			break;
-	}
-}
-
-void
-addreg(Addr *a, int rn)
-{
-
-	a->sym = 0;
-	a->offset = 0;
-	a->type = rn;
-}
-
-int32
-RtoB(int r)
-{
-
-	if(r < D_AX || r > D_R15)
-		return 0;
-	return 1L << (r-D_AX);
-}
-
-int
-BtoR(int32 b)
-{
-
-	b &= 0xffffL;
-	if(nacl)
-		b &= ~((1<<(D_BP-D_AX)) | (1<<(D_R15-D_AX)));
-	if(b == 0)
-		return 0;
-	return bitno(b) + D_AX;
-}
-
-/*
- *	bit	reg
- *	16	X5
- *	17	X6
- *	18	X7
- */
-int32
-FtoB(int f)
-{
-	if(f < FREGMIN || f > FREGEXT)
-		return 0;
-	return 1L << (f - FREGMIN + 16);
-}
-
-int
-BtoF(int32 b)
-{
-
-	b &= 0x70000L;
-	if(b == 0)
-		return 0;
-	return bitno(b) - 16 + FREGMIN;
-}
-
-/* what instruction does a JMP to p eventually land on? */
-static Reg*
-chasejmp(Reg *r, int *jmploop)
-{
-	int n;
-
-	n = 0;
-	for(; r; r=r->s2) {
-		if(r->prog->as != AJMP || r->prog->to.type != D_BRANCH)
-			break;
-		if(++n > 10) {
-			*jmploop = 1;
-			break;
-		}
-	}
-	return r;
-}
-
-/* mark all code reachable from firstp as alive */
-static void
-mark(Reg *firstr)
-{
-	Reg *r;
-	Prog *p;
-
-	for(r=firstr; r; r=r->link) {
-		if(r->active)
-			break;
-		r->active = 1;
-		p = r->prog;
-		if(p->as != ACALL && p->to.type == D_BRANCH)
-			mark(r->s2);
-		if(p->as == AJMP || p->as == ARET || p->as == AUNDEF)
-			break;
-	}
-}
-
-/*
- * the code generator depends on being able to write out JMP
- * instructions that it can jump to now but fill in later.
- * the linker will resolve them nicely, but they make the code
- * longer and more difficult to follow during debugging.
- * remove them.
- */
-static void
-fixjmp(Reg *firstr)
-{
-	int jmploop;
-	Reg *r;
-	Prog *p;
-
-	if(debug['R'] && debug['v'])
-		print("\nfixjmp\n");
-
-	// pass 1: resolve jump to AJMP, mark all code as dead.
-	jmploop = 0;
-	for(r=firstr; r; r=r->link) {
-		p = r->prog;
-		if(debug['R'] && debug['v'])
-			print("%04d %P\n", (int)r->pc, p);
-		if(p->as != ACALL && p->to.type == D_BRANCH && r->s2 && r->s2->prog->as == AJMP) {
-			r->s2 = chasejmp(r->s2, &jmploop);
-			p->to.offset = r->s2->pc;
-			p->to.u.branch = r->s2->prog;
-			if(debug['R'] && debug['v'])
-				print("->%P\n", p);
-		}
-		r->active = 0;
-	}
-	if(debug['R'] && debug['v'])
-		print("\n");
-
-	// pass 2: mark all reachable code alive
-	mark(firstr);
-
-	// pass 3: delete dead code (mostly JMPs).
-	for(r=firstr; r; r=r->link) {
-		if(!r->active) {
-			p = r->prog;
-			if(p->link == P && p->as == ARET && r->p1 && r->p1->prog->as != ARET) {
-				// This is the final ARET, and the code so far doesn't have one.
-				// Let it stay.
-			} else {
-				if(debug['R'] && debug['v'])
-					print("del %04d %P\n", (int)r->pc, p);
-				p->as = ANOP;
-			}
-		}
-	}
-
-	// pass 4: elide JMP to next instruction.
-	// only safe if there are no jumps to JMPs anymore.
-	if(!jmploop) {
-		for(r=firstr; r; r=r->link) {
-			p = r->prog;
-			if(p->as == AJMP && p->to.type == D_BRANCH && r->s2 == r->link) {
-				if(debug['R'] && debug['v'])
-					print("del %04d %P\n", (int)r->pc, p);
-				p->as = ANOP;
-			}
-		}
-	}
-
-	// fix back pointers.
-	for(r=firstr; r; r=r->link) {
-		r->p2 = R;
-		r->p2link = R;
-	}
-	for(r=firstr; r; r=r->link) {
-		if(r->s2) {
-			r->p2link = r->s2->p2;
-			r->s2->p2 = r;
-		}
-	}
-
-	if(debug['R'] && debug['v']) {
-		print("\n");
-		for(r=firstr; r; r=r->link)
-			print("%04d %P\n", (int)r->pc, r->prog);
-		print("\n");
-	}
-}
-
diff --git a/src/cmd/6c/sgen.c b/src/cmd/6c/sgen.c
deleted file mode 100644
index fceb332..0000000
--- a/src/cmd/6c/sgen.c
+++ /dev/null
@@ -1,483 +0,0 @@
-// Inferno utils/6c/sgen.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/sgen.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include "gc.h"
-#include "../../runtime/funcdata.h"
-
-Prog*
-gtext(Sym *s, int32 stkoff)
-{
-	vlong v;
-
-	v = ((uvlong)argsize(1) << 32) | (stkoff & 0xffffffff);
-	if((textflag & NOSPLIT) && stkoff >= 128)
-		yyerror("stack frame too large for NOSPLIT function");
-
-	gpseudo(ATEXT, s, nodgconst(v, types[TVLONG]));
-	return p;
-}
-
-void
-noretval(int n)
-{
-
-	if(n & 1) {
-		gins(ANOP, Z, Z);
-		p->to.type = REGRET;
-	}
-	if(n & 2) {
-		gins(ANOP, Z, Z);
-		p->to.type = FREGRET;
-	}
-}
-
-/* welcome to commute */
-static void
-commute(Node *n)
-{
-	Node *l, *r;
-
-	l = n->left;
-	r = n->right;
-	if(r->complex > l->complex) {
-		n->left = r;
-		n->right = l;
-	}
-}
-
-void
-indexshift(Node *n)
-{
-	int g;
-
-	if(!typechlpv[n->type->etype])
-		return;
-	simplifyshift(n);
-	if(n->op == OASHL && n->right->op == OCONST){
-		g = vconst(n->right);
-		if(g >= 0 && g <= 3)
-			n->addable = 7;
-	}
-}
-
-/*
- *	calculate addressability as follows
- *		NAME ==> 10/11		name+value(SB/SP)
- *		REGISTER ==> 12		register
- *		CONST ==> 20		$value
- *		*(20) ==> 21		value
- *		&(10) ==> 13		$name+value(SB)
- *		&(11) ==> 1		$name+value(SP)
- *		(13) + (20) ==> 13	fold constants
- *		(1) + (20) ==> 1	fold constants
- *		*(13) ==> 10		back to name
- *		*(1) ==> 11		back to name
- *
- *		(20) * (X) ==> 7	multiplier in indexing
- *		(X,7) + (13,1) ==> 8	adder in indexing (addresses)
- *		(8) ==> &9(OINDEX)	index, almost addressable
- *
- *	calculate complexity (number of registers)
- */
-void
-xcom(Node *n)
-{
-	Node *l, *r;
-	int g;
-
-	if(n == Z)
-		return;
-	l = n->left;
-	r = n->right;
-	n->complex = 0;
-	n->addable = 0;
-	switch(n->op) {
-	case OCONST:
-		n->addable = 20;
-		break;
-
-	case ONAME:
-		n->addable = 9;
-		if(n->class == CPARAM || n->class == CAUTO)
-			n->addable = 11;
-		break;
-
-	case OEXREG:
-		n->addable = 0;
-		break;
-
-	case OREGISTER:
-		n->addable = 12;
-		break;
-
-	case OINDREG:
-		n->addable = 12;
-		break;
-
-	case OADDR:
-		xcom(l);
-		if(l->addable == 10)
-			n->addable = 13;
-		else
-		if(l->addable == 11)
-			n->addable = 1;
-		break;
-
-	case OADD:
-		xcom(l);
-		xcom(r);
-		if(n->type->etype != TIND)
-			break;
-
-		switch(r->addable) {
-		case 20:
-			switch(l->addable) {
-			case 1:
-			case 13:
-			commadd:
-				l->type = n->type;
-				*n = *l;
-				l = new(0, Z, Z);
-				*l = *(n->left);
-				l->xoffset += r->vconst;
-				n->left = l;
-				r = n->right;
-				goto brk;
-			}
-			break;
-
-		case 1:
-		case 13:
-		case 10:
-		case 11:
-			/* l is the base, r is the index */
-			if(l->addable != 20)
-				n->addable = 8;
-			break;
-		}
-		switch(l->addable) {
-		case 20:
-			switch(r->addable) {
-			case 13:
-			case 1:
-				r = n->left;
-				l = n->right;
-				n->left = l;
-				n->right = r;
-				goto commadd;
-			}
-			break;
-
-		case 13:
-		case 1:
-		case 10:
-		case 11:
-			/* r is the base, l is the index */
-			if(r->addable != 20)
-				n->addable = 8;
-			break;
-		}
-		if(n->addable == 8 && !side(n) && !nacl) {
-			indx(n);
-			l = new1(OINDEX, idx.basetree, idx.regtree);
-			l->scale = idx.scale;
-			l->addable = 9;
-			l->complex = l->right->complex;
-			l->type = l->left->type;
-			n->op = OADDR;
-			n->left = l;
-			n->right = Z;
-			n->addable = 8;
-			break;
-		}
-		break;
-
-	case OINDEX:
-		xcom(l);
-		xcom(r);
-		n->addable = 9;
-		break;
-
-	case OIND:
-		xcom(l);
-		if(l->op == OADDR) {
-			l = l->left;
-			l->type = n->type;
-			*n = *l;
-			return;
-		}
-		switch(l->addable) {
-		case 20:
-			n->addable = 21;
-			break;
-		case 1:
-			n->addable = 11;
-			break;
-		case 13:
-			n->addable = 10;
-			break;
-		}
-		break;
-
-	case OASHL:
-		xcom(l);
-		xcom(r);
-		indexshift(n);
-		break;
-
-	case OMUL:
-	case OLMUL:
-		xcom(l);
-		xcom(r);
-		g = vlog(l);
-		if(g >= 0) {
-			n->left = r;
-			n->right = l;
-			l = r;
-			r = n->right;
-		}
-		g = vlog(r);
-		if(g >= 0) {
-			n->op = OASHL;
-			r->vconst = g;
-			r->type = types[TINT];
-			indexshift(n);
-			break;
-		}
-		commute(n);
-		break;
-
-	case OASLDIV:
-		xcom(l);
-		xcom(r);
-		g = vlog(r);
-		if(g >= 0) {
-			n->op = OASLSHR;
-			r->vconst = g;
-			r->type = types[TINT];
-		}
-		break;
-
-	case OLDIV:
-		xcom(l);
-		xcom(r);
-		g = vlog(r);
-		if(g >= 0) {
-			n->op = OLSHR;
-			r->vconst = g;
-			r->type = types[TINT];
-			indexshift(n);
-			break;
-		}
-		break;
-
-	case OASLMOD:
-		xcom(l);
-		xcom(r);
-		g = vlog(r);
-		if(g >= 0) {
-			n->op = OASAND;
-			r->vconst--;
-		}
-		break;
-
-	case OLMOD:
-		xcom(l);
-		xcom(r);
-		g = vlog(r);
-		if(g >= 0) {
-			n->op = OAND;
-			r->vconst--;
-		}
-		break;
-
-	case OASMUL:
-	case OASLMUL:
-		xcom(l);
-		xcom(r);
-		g = vlog(r);
-		if(g >= 0) {
-			n->op = OASASHL;
-			r->vconst = g;
-		}
-		break;
-
-	case OLSHR:
-	case OASHR:
-		xcom(l);
-		xcom(r);
-		indexshift(n);
-		break;
-
-	default:
-		if(l != Z)
-			xcom(l);
-		if(r != Z)
-			xcom(r);
-		break;
-	}
-brk:
-	if(n->addable >= 10)
-		return;
-	if(l != Z)
-		n->complex = l->complex;
-	if(r != Z) {
-		if(r->complex == n->complex)
-			n->complex = r->complex+1;
-		else
-		if(r->complex > n->complex)
-			n->complex = r->complex;
-	}
-	if(n->complex == 0)
-		n->complex++;
-
-	switch(n->op) {
-
-	case OFUNC:
-		n->complex = FNX;
-		break;
-
-	case OCAST:
-		if(l->type->etype == TUVLONG && typefd[n->type->etype])
-			n->complex += 2;
-		break;
-
-	case OLMOD:
-	case OMOD:
-	case OLMUL:
-	case OLDIV:
-	case OMUL:
-	case ODIV:
-	case OASLMUL:
-	case OASLDIV:
-	case OASLMOD:
-	case OASMUL:
-	case OASDIV:
-	case OASMOD:
-		if(r->complex >= l->complex) {
-			n->complex = l->complex + 3;
-			if(r->complex > n->complex)
-				n->complex = r->complex;
-		} else {
-			n->complex = r->complex + 3;
-			if(l->complex > n->complex)
-				n->complex = l->complex;
-		}
-		break;
-
-	case OLSHR:
-	case OASHL:
-	case OASHR:
-	case OASLSHR:
-	case OASASHL:
-	case OASASHR:
-		if(r->complex >= l->complex) {
-			n->complex = l->complex + 2;
-			if(r->complex > n->complex)
-				n->complex = r->complex;
-		} else {
-			n->complex = r->complex + 2;
-			if(l->complex > n->complex)
-				n->complex = l->complex;
-		}
-		break;
-
-	case OADD:
-	case OXOR:
-	case OAND:
-	case OOR:
-		/*
-		 * immediate operators, make const on right
-		 */
-		if(l->op == OCONST) {
-			n->left = r;
-			n->right = l;
-		}
-		break;
-
-	case OEQ:
-	case ONE:
-	case OLE:
-	case OLT:
-	case OGE:
-	case OGT:
-	case OHI:
-	case OHS:
-	case OLO:
-	case OLS:
-		/*
-		 * compare operators, make const on left
-		 */
-		if(r->op == OCONST) {
-			n->left = r;
-			n->right = l;
-			n->op = invrel[relindex(n->op)];
-		}
-		break;
-	}
-}
-
-void
-indx(Node *n)
-{
-	Node *l, *r;
-
-	if(debug['x'])
-		prtree(n, "indx");
-
-	l = n->left;
-	r = n->right;
-	if(l->addable == 1 || l->addable == 13 || r->complex > l->complex) {
-		n->right = l;
-		n->left = r;
-		l = r;
-		r = n->right;
-	}
-	if(l->addable != 7) {
-		idx.regtree = l;
-		idx.scale = 1;
-	} else
-	if(l->right->addable == 20) {
-		idx.regtree = l->left;
-		idx.scale = 1 << l->right->vconst;
-	} else
-	if(l->left->addable == 20) {
-		idx.regtree = l->right;
-		idx.scale = 1 << l->left->vconst;
-	} else
-		diag(n, "bad index");
-
-	idx.basetree = r;
-	if(debug['x']) {
-		print("scale = %d\n", idx.scale);
-		prtree(idx.regtree, "index");
-		prtree(idx.basetree, "base");
-	}
-}
diff --git a/src/cmd/6c/swt.c b/src/cmd/6c/swt.c
deleted file mode 100644
index 6e918eb..0000000
--- a/src/cmd/6c/swt.c
+++ /dev/null
@@ -1,353 +0,0 @@
-// Inferno utils/6c/swt.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/swt.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include "gc.h"
-
-void
-swit1(C1 *q, int nc, int32 def, Node *n)
-{
-	Node nreg;
-
-	regalloc(&nreg, n, Z);
-	if(typev[n->type->etype])
-		nreg.type = types[TVLONG];
-	else
-		nreg.type = types[TLONG];
-	cgen(n, &nreg);
-	swit2(q, nc, def, &nreg);
-	regfree(&nreg);
-}
-
-void
-swit2(C1 *q, int nc, int32 def, Node *n)
-{
-	C1 *r;
-	int i;
-	Prog *sp;
-
-	if(nc < 5) {
-		for(i=0; i<nc; i++) {
-			if(debug['W'])
-				print("case = %.8llux\n", q->val);
-			gcmp(OEQ, n, q->val);
-			patch(p, q->label);
-			q++;
-		}
-		gbranch(OGOTO);
-		patch(p, def);
-		return;
-	}
-	i = nc / 2;
-	r = q+i;
-	if(debug['W'])
-		print("case > %.8llux\n", r->val);
-	gcmp(OGT, n, r->val);
-	sp = p;
-	gbranch(OGOTO);
-	p->as = AJEQ;
-	patch(p, r->label);
-	swit2(q, i, def, n);
-
-	if(debug['W'])
-		print("case < %.8llux\n", r->val);
-	patch(sp, pc);
-	swit2(r+1, nc-i-1, def, n);
-}
-
-void
-bitload(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
-{
-	int sh;
-	int32 v;
-	Node *l;
-
-	/*
-	 * n1 gets adjusted/masked value
-	 * n2 gets address of cell
-	 * n3 gets contents of cell
-	 */
-	l = b->left;
-	if(n2 != Z) {
-		regalloc(n1, l, nn);
-		reglcgen(n2, l, Z);
-		regalloc(n3, l, Z);
-		gmove(n2, n3);
-		gmove(n3, n1);
-	} else {
-		regalloc(n1, l, nn);
-		cgen(l, n1);
-	}
-	if(b->type->shift == 0 && typeu[b->type->etype]) {
-		v = ~0 + (1L << b->type->nbits);
-		gopcode(OAND, tfield, nodconst(v), n1);
-	} else {
-		sh = 32 - b->type->shift - b->type->nbits;
-		if(sh > 0)
-			gopcode(OASHL, tfield, nodconst(sh), n1);
-		sh += b->type->shift;
-		if(sh > 0)
-			if(typeu[b->type->etype])
-				gopcode(OLSHR, tfield, nodconst(sh), n1);
-			else
-				gopcode(OASHR, tfield, nodconst(sh), n1);
-	}
-}
-
-void
-bitstore(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
-{
-	int32 v;
-	Node nod;
-	int sh;
-
-	regalloc(&nod, b->left, Z);
-	v = ~0 + (1L << b->type->nbits);
-	gopcode(OAND, types[TLONG], nodconst(v), n1);
-	gmove(n1, &nod);
-	if(nn != Z)
-		gmove(n1, nn);
-	sh = b->type->shift;
-	if(sh > 0)
-		gopcode(OASHL, types[TLONG], nodconst(sh), &nod);
-	v <<= sh;
-	gopcode(OAND, types[TLONG], nodconst(~v), n3);
-	gopcode(OOR, types[TLONG], n3, &nod);
-	gmove(&nod, n2);
-
-	regfree(&nod);
-	regfree(n1);
-	regfree(n2);
-	regfree(n3);
-}
-
-int32
-outstring(char *s, int32 n)
-{
-	int32 r;
-
-	if(suppress)
-		return nstring;
-	r = nstring;
-	while(n) {
-		string[mnstring] = *s++;
-		mnstring++;
-		nstring++;
-		if(mnstring >= NSNAME) {
-			gpseudo(ADATA, symstring, nodconst(0L));
-			p->from.offset += nstring - NSNAME;
-			p->from.scale = NSNAME;
-			p->to.type = D_SCONST;
-			memmove(p->to.u.sval, string, NSNAME);
-			mnstring = 0;
-		}
-		n--;
-	}
-	return r;
-}
-
-void
-sextern(Sym *s, Node *a, int32 o, int32 w)
-{
-	int32 e, lw;
-
-	for(e=0; e<w; e+=NSNAME) {
-		lw = NSNAME;
-		if(w-e < lw)
-			lw = w-e;
-		gpseudo(ADATA, s, nodconst(0L));
-		p->from.offset += o+e;
-		p->from.scale = lw;
-		p->to.type = D_SCONST;
-		memmove(p->to.u.sval, a->cstring+e, lw);
-	}
-}
-
-void
-gextern(Sym *s, Node *a, int32 o, int32 w)
-{
-	if(0 && a->op == OCONST && typev[a->type->etype]) {
-		gpseudo(ADATA, s, lo64(a));
-		p->from.offset += o;
-		p->from.scale = 4;
-		gpseudo(ADATA, s, hi64(a));
-		p->from.offset += o + 4;
-		p->from.scale = 4;
-		return;
-	}
-	gpseudo(ADATA, s, a);
-	p->from.offset += o;
-	p->from.scale = w;
-	switch(p->to.type) {
-	default:
-		p->to.index = p->to.type;
-		p->to.type = D_ADDR;
-	case D_CONST:
-	case D_FCONST:
-	case D_ADDR:
-		break;
-	}
-}
-
-void
-outcode(void)
-{
-	int f;
-	Biobuf b;
-
-	f = open(outfile, OWRITE);
-	if(f < 0) {
-		diag(Z, "cannot open %s", outfile);
-		return;
-	}
-	Binit(&b, f, OWRITE);
-
-	Bprint(&b, "go object %s %s %s\n", getgoos(), getgoarch(), getgoversion());
-	if(pragcgobuf.to > pragcgobuf.start) {
-		Bprint(&b, "\n");
-		Bprint(&b, "$$  // exports\n\n");
-		Bprint(&b, "$$  // local types\n\n");
-		Bprint(&b, "$$  // cgo\n");
-		Bprint(&b, "%s", fmtstrflush(&pragcgobuf));
-		Bprint(&b, "\n$$\n\n");
-	}
-	Bprint(&b, "!\n");
-
-	writeobj(ctxt, &b);
-	Bterm(&b);
-	close(f);
-	lastp = P;
-}
-
-int32
-align(int32 i, Type *t, int op, int32 *maxalign)
-{
-	int32 o;
-	Type *v;
-	int w, packw;
-
-	o = i;
-	w = 1;
-	packw = 0;
-	switch(op) {
-	default:
-		diag(Z, "unknown align opcode %d", op);
-		break;
-
-	case Asu2:	/* padding at end of a struct */
-		w = *maxalign;
-		if(w < 1)
-			w = 1;
-		if(packflg)
-			packw = packflg;
-		break;
-
-	case Ael1:	/* initial align of struct element */
-		for(v=t; v->etype==TARRAY; v=v->link)
-			;
-		if(v->etype == TSTRUCT || v->etype == TUNION)
-			w = v->align;
-		else
-			w = ewidth[v->etype];
-		if(w < 1 || w > SZ_VLONG)
-			fatal(Z, "align");
-		if(packflg) 
-			packw = packflg;
-		break;
-
-	case Ael2:	/* width of a struct element */
-		o += t->width;
-		break;
-
-	case Aarg0:	/* initial passbyptr argument in arg list */
-		if(typesu[t->etype]) {
-			o = align(o, types[TIND], Aarg1, nil);
-			o = align(o, types[TIND], Aarg2, nil);
-		}
-		break;
-
-	case Aarg1:	/* initial align of parameter */
-		if(ewidth[TIND] == 4) {
-			if(typesu[t->etype]) {
-				for(v = t->link; v != T; v = v->down)
-					o = align(o, v, Aarg1, maxalign);
-				goto out;
-			}
-			w = ewidth[t->etype];
-			if(typev[t->etype] || t->etype == TDOUBLE)
-				w = 8;
-			else if(w <= 0 || w >= 4)
-				w = 4;
-			else
-				w = 1;
-			break;
-		}
-		w = ewidth[t->etype];
-		if(w <= 0 || w >= SZ_VLONG) {
-			w = SZ_VLONG;
-			break;
-		}
-		w = 1;		/* little endian no adjustment */
-		break;
-
-	case Aarg2:	/* width of a parameter */
-		o += t->width;
-		if(ewidth[TIND] == 4) {
-			o = align(o, t, Aarg1, maxalign);
-			goto out;
-		}
-		w = t->width;
-		if(w > SZ_VLONG)
-			w = SZ_VLONG;
-		break;
-
-	case Aaut3:	/* total align of automatic */
-		o = align(o, t, Ael1, nil);
-		o = align(o, t, Ael2, nil);
-		break;
-	}
-	if(packw != 0 && xround(o, w) != xround(o, packw))
-		diag(Z, "#pragma pack changes offset of %T", t);
-	o = xround(o, w);
-	if(maxalign && *maxalign < w)
-		*maxalign = w;
-out:
-	if(debug['A'])
-		print("align %s %d %T = %d\n", bnames[op], i, t, o);
-	return o;
-}
-
-int32
-maxround(int32 max, int32 v)
-{
-	v = xround(v, SZ_VLONG);
-	if(v > max)
-		return v;
-	return max;
-}
diff --git a/src/cmd/6c/txt.c b/src/cmd/6c/txt.c
deleted file mode 100644
index 3bdbf41..0000000
--- a/src/cmd/6c/txt.c
+++ /dev/null
@@ -1,1674 +0,0 @@
-// 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 at 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 at 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.
-
-#include "gc.h"
-
-int thechar = '6';
-char *thestring = "amd64";
-
-LinkArch	*thelinkarch = &linkamd64;
-
-void
-linkarchinit(void)
-{
-	if(strcmp(getgoarch(), "amd64p32") == 0)
-		thelinkarch = &linkamd64p32;
-}
-
-void
-ginit(void)
-{
-	int i;
-	Type *t;
-
-	dodefine("_64BITREG");
-	if(ewidth[TIND] == 8)
-		dodefine("_64BIT");
-	listinit();
-	nstring = 0;
-	mnstring = 0;
-	nrathole = 0;
-	pc = 0;
-	breakpc = -1;
-	continpc = -1;
-	cases = C;
-	lastp = P;
-	tfield = types[TINT];
-
-	typeword = typechlvp;
-	typecmplx = typesu;
-
-	/* TO DO */
-	memmove(typechlpv, typechlp, sizeof(typechlpv));
-	typechlpv[TVLONG] = 1;
-	typechlpv[TUVLONG] = 1;
-
-	zprog.link = P;
-	zprog.as = AGOK;
-	zprog.from.type = D_NONE;
-	zprog.from.index = D_NONE;
-	zprog.from.scale = 0;
-	zprog.to = zprog.from;
-
-	lregnode.op = OREGISTER;
-	lregnode.class = CEXREG;
-	lregnode.reg = REGTMP;
-	lregnode.complex = 0;
-	lregnode.addable = 11;
-	lregnode.type = types[TLONG];
-
-	qregnode = lregnode;
-	qregnode.type = types[TVLONG];
-
-	constnode.op = OCONST;
-	constnode.class = CXXX;
-	constnode.complex = 0;
-	constnode.addable = 20;
-	constnode.type = types[TLONG];
-
-	vconstnode = constnode;
-	vconstnode.type = types[TVLONG];
-
-	fconstnode.op = OCONST;
-	fconstnode.class = CXXX;
-	fconstnode.complex = 0;
-	fconstnode.addable = 20;
-	fconstnode.type = types[TDOUBLE];
-
-	nodsafe = new(ONAME, Z, Z);
-	nodsafe->sym = slookup(".safe");
-	nodsafe->type = types[TINT];
-	nodsafe->etype = types[TINT]->etype;
-	nodsafe->class = CAUTO;
-	complex(nodsafe);
-
-	t = typ(TARRAY, types[TCHAR]);
-	symrathole = slookup(".rathole");
-	symrathole->class = CGLOBL;
-	symrathole->type = t;
-
-	nodrat = new(ONAME, Z, Z);
-	nodrat->sym = symrathole;
-	nodrat->type = types[TIND];
-	nodrat->etype = TVOID;
-	nodrat->class = CGLOBL;
-	complex(nodrat);
-	nodrat->type = t;
-
-	nodret = new(ONAME, Z, Z);
-	nodret->sym = slookup(".ret");
-	nodret->type = types[TIND];
-	nodret->etype = TIND;
-	nodret->class = CPARAM;
-	nodret = new(OIND, nodret, Z);
-	complex(nodret);
-
-	if(0)
-		com64init();
-
-	for(i=0; i<nelem(reg); i++) {
-		reg[i] = 1;
-		if(i >= D_AX && i <= D_R15 && i != D_SP)
-			reg[i] = 0;
-		if(i >= D_X0 && i <= D_X7)
-			reg[i] = 0;
-	}
-	if(nacl) {
-		reg[D_BP] = 1;
-		reg[D_R15] = 1;
-	}
-}
-
-void
-gclean(void)
-{
-	int i;
-	Sym *s;
-
-	reg[D_SP]--;
-	if(nacl) {
-		reg[D_BP]--;
-		reg[D_R15]--;
-	}
-	for(i=D_AX; i<=D_R15; i++)
-		if(reg[i])
-			diag(Z, "reg %R left allocated", i);
-	for(i=D_X0; i<=D_X7; i++)
-		if(reg[i])
-			diag(Z, "reg %R left allocated", i);
-	while(mnstring)
-		outstring("", 1L);
-	symstring->type->width = nstring;
-	symrathole->type->width = nrathole;
-	for(i=0; i<NHASH; i++)
-	for(s = hash[i]; s != S; s = s->link) {
-		if(s->type == T)
-			continue;
-		if(s->type->width == 0)
-			continue;
-		if(s->class != CGLOBL && s->class != CSTATIC)
-			continue;
-		if(s->type == types[TENUM])
-			continue;
-		gpseudo(AGLOBL, s, nodconst(s->type->width));
-	}
-	nextpc();
-	p->as = AEND;
-	outcode();
-}
-
-void
-nextpc(void)
-{
-	Plist *pl;
-
-	p = alloc(sizeof(*p));
-	*p = zprog;
-	p->lineno = nearln;
-	p->pc = pc;
-	pc++;
-	if(lastp == nil) {
-		pl = linknewplist(ctxt);
-		pl->firstpc = p;
-	} else
-		lastp->link = p;
-	lastp = p;
-}
-
-void
-gargs(Node *n, Node *tn1, Node *tn2)
-{
-	int32 regs;
-	Node fnxargs[20], *fnxp;
-
-	regs = cursafe;
-
-	fnxp = fnxargs;
-	garg1(n, tn1, tn2, 0, &fnxp);	/* compile fns to temps */
-
-	curarg = 0;
-	fnxp = fnxargs;
-	garg1(n, tn1, tn2, 1, &fnxp);	/* compile normal args and temps */
-
-	cursafe = regs;
-}
-
-int
-nareg(void)
-{
-	int i, n;
-
-	n = 0;
-	for(i=D_AX; i<=D_R15; i++)
-		if(reg[i] == 0)
-			n++;
-	return n;
-}
-
-void
-garg1(Node *n, Node *tn1, Node *tn2, int f, Node **fnxp)
-{
-	Node nod;
-
-	if(n == Z)
-		return;
-	if(n->op == OLIST) {
-		garg1(n->left, tn1, tn2, f, fnxp);
-		garg1(n->right, tn1, tn2, f, fnxp);
-		return;
-	}
-	if(f == 0) {
-		if(n->complex >= FNX) {
-			regsalloc(*fnxp, n);
-			nod = znode;
-			nod.op = OAS;
-			nod.left = *fnxp;
-			nod.right = n;
-			nod.type = n->type;
-			cgen(&nod, Z);
-			(*fnxp)++;
-		}
-		return;
-	}
-	if(typesu[n->type->etype]) {
-		regaalloc(tn2, n);
-		if(n->complex >= FNX) {
-			sugen(*fnxp, tn2, n->type->width);
-			(*fnxp)++;
-		} else
-			sugen(n, tn2, n->type->width);
-		return;
-	}
-	if(REGARG >= 0 && curarg == 0 && typechlpv[n->type->etype]) {
-		regaalloc1(tn1, n);
-		if(n->complex >= FNX) {
-			cgen(*fnxp, tn1);
-			(*fnxp)++;
-		} else
-			cgen(n, tn1);
-		return;
-	}
-	if(vconst(n) == 0) {
-		regaalloc(tn2, n);
-		gmove(n, tn2);
-		return;
-	}
-	regalloc(tn1, n, Z);
-	if(n->complex >= FNX) {
-		cgen(*fnxp, tn1);
-		(*fnxp)++;
-	} else
-		cgen(n, tn1);
-	regaalloc(tn2, n);
-	gmove(tn1, tn2);
-	regfree(tn1);
-}
-
-Node*
-nodgconst(vlong v, Type *t)
-{
-	if(!typev[t->etype])
-		return nodconst((int32)v);
-	vconstnode.vconst = v;
-	return &vconstnode;
-}
-
-Node*
-nodconst(int32 v)
-{
-	constnode.vconst = v;
-	return &constnode;
-}
-
-Node*
-nodfconst(double d)
-{
-	fconstnode.fconst = d;
-	return &fconstnode;
-}
-
-int
-isreg(Node *n, int r)
-{
-
-	if(n->op == OREGISTER)
-		if(n->reg == r)
-			return 1;
-	return 0;
-}
-
-int
-nodreg(Node *n, Node *nn, int r)
-{
-	int et;
-
-	*n = qregnode;
-	n->reg = r;
-	if(nn != Z){
-		et = nn->type->etype;
-		if(!typefd[et] && nn->type->width <= SZ_LONG && 0)
-			n->type = typeu[et]? types[TUINT]: types[TINT];
-		else
-			n->type = nn->type;
-//print("nodreg %s [%s]\n", tnames[et], tnames[n->type->etype]);
-		n->lineno = nn->lineno;
-	}
-	if(reg[r] == 0)
-		return 0;
-	if(nn != Z) {
-		if(nn->op == OREGISTER)
-		if(nn->reg == r)
-			return 0;
-	}
-	return 1;
-}
-
-void
-regret(Node *n, Node *nn, Type *t, int mode)
-{
-	int r;
-	
-	if(mode == 0 || hasdotdotdot(t) || nn->type->width == 0) {
-		r = REGRET;
-		if(typefd[nn->type->etype])
-			r = FREGRET;
-		nodreg(n, nn, r);
-		reg[r]++;
-		return;
-	}
-	
-	if(mode == 1) {
-		// fetch returned value after call.
-		// already called gargs, so curarg is set.
-		curarg = (curarg+7) & ~7;
-		regaalloc(n, nn);
-		return;
-	}
-
-	if(mode == 2) {
-		// store value to be returned.
-		// must compute arg offset.
-		if(t->etype != TFUNC)
-			fatal(Z, "bad regret func %T", t);
-		*n = *nn;
-		n->op = ONAME;
-		n->class = CPARAM;
-		n->sym = slookup(".ret");
-		n->complex = nodret->complex;
-		n->addable = 20;
-		n->xoffset = argsize(0);
-		return;
-	}
-	
-	fatal(Z, "bad regret");	
-}
-
-void
-regalloc(Node *n, Node *tn, Node *o)
-{
-	int i;
-
-	switch(tn->type->etype) {
-	case TCHAR:
-	case TUCHAR:
-	case TSHORT:
-	case TUSHORT:
-	case TINT:
-	case TUINT:
-	case TLONG:
-	case TULONG:
-	case TVLONG:
-	case TUVLONG:
-	case TIND:
-		if(o != Z && o->op == OREGISTER) {
-			i = o->reg;
-			if(i >= D_AX && i <= D_R15)
-				goto out;
-		}
-		for(i=D_AX; i<=D_R15; i++)
-			if(reg[i] == 0)
-				goto out;
-		diag(tn, "out of fixed registers");
-		goto err;
-
-	case TFLOAT:
-	case TDOUBLE:
-		if(o != Z && o->op == OREGISTER) {
-			i = o->reg;
-			if(i >= D_X0 && i <= D_X7)
-				goto out;
-		}
-		for(i=D_X0; i<=D_X7; i++)
-			if(reg[i] == 0)
-				goto out;
-		diag(tn, "out of float registers");
-		goto out;
-	}
-	diag(tn, "unknown type in regalloc: %T", tn->type);
-err:
-	i = 0;
-out:
-	if(i)
-		reg[i]++;
-	nodreg(n, tn, i);
-}
-
-void
-regialloc(Node *n, Node *tn, Node *o)
-{
-	Node nod;
-
-	nod = *tn;
-	nod.type = types[TIND];
-	regalloc(n, &nod, o);
-}
-
-void
-regfree(Node *n)
-{
-	int i;
-
-	i = 0;
-	if(n->op != OREGISTER && n->op != OINDREG)
-		goto err;
-	i = n->reg;
-	if(i < 0 || i >= nelem(reg))
-		goto err;
-	if(reg[i] <= 0)
-		goto err;
-	reg[i]--;
-	return;
-err:
-	diag(n, "error in regfree: %R", i);
-}
-
-void
-regsalloc(Node *n, Node *nn)
-{
-	cursafe = align(cursafe, nn->type, Aaut3, nil);
-	maxargsafe = maxround(maxargsafe, cursafe+curarg);
-	*n = *nodsafe;
-	n->xoffset = -(stkoff + cursafe);
-	n->type = nn->type;
-	n->etype = nn->type->etype;
-	n->lineno = nn->lineno;
-}
-
-void
-regaalloc1(Node *n, Node *nn)
-{
-	if(REGARG < 0) {
-		fatal(n, "regaalloc1 and REGARG<0");
-		return;
-	}
-	nodreg(n, nn, REGARG);
-	reg[(uchar)REGARG]++;
-	curarg = align(curarg, nn->type, Aarg1, nil);
-	curarg = align(curarg, nn->type, Aarg2, nil);
-	maxargsafe = maxround(maxargsafe, cursafe+curarg);
-}
-
-void
-regaalloc(Node *n, Node *nn)
-{
-	curarg = align(curarg, nn->type, Aarg1, nil);
-	*n = *nn;
-	n->op = OINDREG;
-	n->reg = REGSP;
-	n->xoffset = curarg;
-	n->complex = 0;
-	n->addable = 20;
-	curarg = align(curarg, nn->type, Aarg2, nil);
-	maxargsafe = maxround(maxargsafe, cursafe+curarg);
-}
-
-void
-regind(Node *n, Node *nn)
-{
-
-	if(n->op != OREGISTER) {
-		diag(n, "regind not OREGISTER");
-		return;
-	}
-	n->op = OINDREG;
-	n->type = nn->type;
-}
-
-void
-naddr(Node *n, Addr *a)
-{
-	int32 v;
-
-	a->type = D_NONE;
-	if(n == Z)
-		return;
-	switch(n->op) {
-	default:
-	bad:
-		diag(n, "bad in naddr: %O %D", n->op, a);
-		break;
-
-	case OREGISTER:
-		a->type = n->reg;
-		a->sym = nil;
-		break;
-
-	case OEXREG:
-		a->type = D_INDIR + D_TLS;
-		a->offset = n->reg - 1;
-		break;
-
-	case OIND:
-		naddr(n->left, a);
-		if(a->type >= D_AX && a->type <= D_R15)
-			a->type += D_INDIR;
-		else
-		if(a->type == D_CONST)
-			a->type = D_NONE+D_INDIR;
-		else
-		if(a->type == D_ADDR) {
-			a->type = a->index;
-			a->index = D_NONE;
-		} else
-			goto bad;
-		break;
-
-	case OINDEX:
-		a->type = idx.ptr;
-		if(n->left->op == OADDR || n->left->op == OCONST)
-			naddr(n->left, a);
-		if(a->type >= D_AX && a->type <= D_R15)
-			a->type += D_INDIR;
-		else
-		if(a->type == D_CONST)
-			a->type = D_NONE+D_INDIR;
-		else
-		if(a->type == D_ADDR) {
-			a->type = a->index;
-			a->index = D_NONE;
-		} else
-			goto bad;
-		a->index = idx.reg;
-		a->scale = n->scale;
-		a->offset += n->xoffset;
-		break;
-
-	case OINDREG:
-		a->type = n->reg+D_INDIR;
-		a->sym = nil;
-		a->offset = n->xoffset;
-		break;
-
-	case ONAME:
-		a->etype = n->etype;
-		a->type = D_STATIC;
-		a->sym = linksym(n->sym);
-		a->offset = n->xoffset;
-		if(n->class == CSTATIC)
-			break;
-		if(n->class == CEXTERN || n->class == CGLOBL) {
-			a->type = D_EXTERN;
-			break;
-		}
-		if(n->class == CAUTO) {
-			a->type = D_AUTO;
-			break;
-		}
-		if(n->class == CPARAM) {
-			a->type = D_PARAM;
-			break;
-		}
-		goto bad;
-
-	case OCONST:
-		if(typefd[n->type->etype]) {
-			a->type = D_FCONST;
-			a->u.dval = n->fconst;
-			break;
-		}
-		a->sym = nil;
-		a->type = D_CONST;
-		if(typev[n->type->etype] || (n->type->etype == TIND && ewidth[TIND] == 8))
-			a->offset = n->vconst;
-		else
-			a->offset = convvtox(n->vconst, typeu[n->type->etype]? TULONG: TLONG);
-		break;
-
-	case OADDR:
-		naddr(n->left, a);
-		if(a->type >= D_INDIR) {
-			a->type -= D_INDIR;
-			break;
-		}
-		if(a->type == D_EXTERN || a->type == D_STATIC ||
-		   a->type == D_AUTO || a->type == D_PARAM)
-			if(a->index == D_NONE) {
-				a->index = a->type;
-				a->type = D_ADDR;
-				break;
-			}
-		goto bad;
-
-	case OADD:
-		if(n->right->op == OCONST) {
-			v = n->right->vconst;
-			naddr(n->left, a);
-		} else
-		if(n->left->op == OCONST) {
-			v = n->left->vconst;
-			naddr(n->right, a);
-		} else
-			goto bad;
-		a->offset += v;
-		break;
-
-	}
-}
-
-void
-gcmp(int op, Node *n, vlong val)
-{
-	Node *cn, nod;
-
-	cn = nodgconst(val, n->type);
-	if(!immconst(cn)){
-		regalloc(&nod, n, Z);
-		gmove(cn, &nod);
-		gopcode(op, n->type, n, &nod);
-		regfree(&nod);
-	}else
-		gopcode(op, n->type, n, cn);
-}
-
-#define	CASE(a,b)	((a<<8)|(b<<0))
-
-void
-gmove(Node *f, Node *t)
-{
-	int ft, tt, t64, a;
-	Node nod, nod1, nod2, nod3;
-	Prog *p1, *p2;
-
-	ft = f->type->etype;
-	tt = t->type->etype;
-	if(ewidth[TIND] == 4) {
-		if(ft == TIND)
-			ft = TUINT;
-		if(tt == TIND)
-			tt = TUINT;
-	}
-	t64 = tt == TVLONG || tt == TUVLONG || tt == TIND;
-	if(debug['M'])
-		print("gop: %O %O[%s],%O[%s]\n", OAS,
-			f->op, tnames[ft], t->op, tnames[tt]);
-	if(typefd[ft] && f->op == OCONST) {
-		/* TO DO: pick up special constants, possibly preloaded */
-		if(f->fconst == 0.0){
-			regalloc(&nod, t, t);
-			gins(AXORPD, &nod, &nod);
-			gmove(&nod, t);
-			regfree(&nod);
-			return;
-		}
-	}
-/*
- * load
- */
-	if(ft == TVLONG || ft == TUVLONG)
-	if(f->op == OCONST)
-	if(f->vconst > 0x7fffffffLL || f->vconst < -0x7fffffffLL)
-	if(t->op != OREGISTER) {
-		regalloc(&nod, f, Z);
-		gmove(f, &nod);
-		gmove(&nod, t);
-		regfree(&nod);
-		return;
-	}
-
-	if(f->op == ONAME || f->op == OINDREG ||
-	   f->op == OIND || f->op == OINDEX)
-	switch(ft) {
-	case TCHAR:
-		a = AMOVBLSX;
-		if(t64)
-			a = AMOVBQSX;
-		goto ld;
-	case TUCHAR:
-		a = AMOVBLZX;
-		if(t64)
-			a = AMOVBQZX;
-		goto ld;
-	case TSHORT:
-		a = AMOVWLSX;
-		if(t64)
-			a = AMOVWQSX;
-		goto ld;
-	case TUSHORT:
-		a = AMOVWLZX;
-		if(t64)
-			a = AMOVWQZX;
-		goto ld;
-	case TINT:
-	case TLONG:
-		if(typefd[tt]) {
-			regalloc(&nod, t, t);
-			if(tt == TDOUBLE)
-				a = ACVTSL2SD;
-			else
-				a = ACVTSL2SS;
-			gins(a, f, &nod);
-			gmove(&nod, t);
-			regfree(&nod);
-			return;
-		}
-		a = AMOVL;
-		if(t64)
-			a = AMOVLQSX;
-		goto ld;
-	case TUINT:
-	case TULONG:
-		a = AMOVL;
-		if(t64)
-			a = AMOVLQZX;	/* could probably use plain MOVL */
-		goto ld;
-	case TVLONG:
-		if(typefd[tt]) {
-			regalloc(&nod, t, t);
-			if(tt == TDOUBLE)
-				a = ACVTSQ2SD;
-			else
-				a = ACVTSQ2SS;
-			gins(a, f, &nod);
-			gmove(&nod, t);
-			regfree(&nod);
-			return;
-		}
-	case TUVLONG:
-		a = AMOVQ;
-		goto ld;
-	case TIND:
-		a = AMOVQ;
-		if(ewidth[TIND] == 4)
-			a = AMOVL;
-
-	ld:
-		regalloc(&nod, f, t);
-		nod.type = t64? types[TVLONG]: types[TINT];
-		gins(a, f, &nod);
-		gmove(&nod, t);
-		regfree(&nod);
-		return;
-
-	case TFLOAT:
-		a = AMOVSS;
-		goto fld;
-	case TDOUBLE:
-		a = AMOVSD;
-	fld:
-		regalloc(&nod, f, t);
-		if(tt != TDOUBLE && tt != TFLOAT){	/* TO DO: why is this here */
-			prtree(f, "odd tree");
-			nod.type = t64? types[TVLONG]: types[TINT];
-		}
-		gins(a, f, &nod);
-		gmove(&nod, t);
-		regfree(&nod);
-		return;
-	}
-
-/*
- * store
- */
-	if(t->op == ONAME || t->op == OINDREG ||
-	   t->op == OIND || t->op == OINDEX)
-	switch(tt) {
-	case TCHAR:
-	case TUCHAR:
-		a = AMOVB;	goto st;
-	case TSHORT:
-	case TUSHORT:
-		a = AMOVW;	goto st;
-	case TINT:
-	case TUINT:
-	case TLONG:
-	case TULONG:
-		a = AMOVL;	goto st;
-	case TVLONG:
-	case TUVLONG:
-	case TIND:
-		a = AMOVQ;	goto st;
-
-	st:
-		if(f->op == OCONST) {
-			gins(a, f, t);
-			return;
-		}
-	fst:
-		regalloc(&nod, t, f);
-		gmove(f, &nod);
-		gins(a, &nod, t);
-		regfree(&nod);
-		return;
-
-	case TFLOAT:
-		a = AMOVSS;
-		goto fst;
-	case TDOUBLE:
-		a = AMOVSD;
-		goto fst;
-	}
-
-/*
- * convert
- */
-	switch(CASE(ft,tt)) {
-	default:
-/*
- * integer to integer
- ********
-		a = AGOK;	break;
-
-	case CASE(	TCHAR,	TCHAR):
-	case CASE(	TUCHAR,	TCHAR):
-	case CASE(	TSHORT,	TCHAR):
-	case CASE(	TUSHORT,TCHAR):
-	case CASE(	TINT,	TCHAR):
-	case CASE(	TUINT,	TCHAR):
-	case CASE(	TLONG,	TCHAR):
-	case CASE(	TULONG,	TCHAR):
-
-	case CASE(	TCHAR,	TUCHAR):
-	case CASE(	TUCHAR,	TUCHAR):
-	case CASE(	TSHORT,	TUCHAR):
-	case CASE(	TUSHORT,TUCHAR):
-	case CASE(	TINT,	TUCHAR):
-	case CASE(	TUINT,	TUCHAR):
-	case CASE(	TLONG,	TUCHAR):
-	case CASE(	TULONG,	TUCHAR):
-
-	case CASE(	TSHORT,	TSHORT):
-	case CASE(	TUSHORT,TSHORT):
-	case CASE(	TINT,	TSHORT):
-	case CASE(	TUINT,	TSHORT):
-	case CASE(	TLONG,	TSHORT):
-	case CASE(	TULONG,	TSHORT):
-
-	case CASE(	TSHORT,	TUSHORT):
-	case CASE(	TUSHORT,TUSHORT):
-	case CASE(	TINT,	TUSHORT):
-	case CASE(	TUINT,	TUSHORT):
-	case CASE(	TLONG,	TUSHORT):
-	case CASE(	TULONG,	TUSHORT):
-
-	case CASE(	TINT,	TINT):
-	case CASE(	TUINT,	TINT):
-	case CASE(	TLONG,	TINT):
-	case CASE(	TULONG,	TINT):
-
-	case CASE(	TINT,	TUINT):
-	case CASE(	TUINT,	TUINT):
-	case CASE(	TLONG,	TUINT):
-	case CASE(	TULONG,	TUINT):
- *****/
-		a = AMOVL;
-		break;
-
-	case CASE(	TINT,	TIND):
-	case CASE(	TINT,	TVLONG):
-	case CASE(	TINT,	TUVLONG):
-	case CASE(	TLONG,	TIND):
-	case CASE(	TLONG,	TVLONG):
-	case CASE(	TLONG,	TUVLONG):
-		a = AMOVLQSX;
-		if(f->op == OCONST) {
-			f->vconst &= (uvlong)0xffffffffU;
-			if(f->vconst & 0x80000000)
-				f->vconst |= (vlong)0xffffffff << 32;
-			a = AMOVQ;
-		}
-		break;
-
-	case CASE(	TUINT,	TIND):
-	case CASE(	TUINT,	TVLONG):
-	case CASE(	TUINT,	TUVLONG):
-	case CASE(	TULONG,	TVLONG):
-	case CASE(	TULONG,	TUVLONG):
-	case CASE(	TULONG,	TIND):
-		a = AMOVLQZX;
-		if(f->op == OCONST) {
-			f->vconst &= (uvlong)0xffffffffU;
-			a = AMOVQ;
-		}
-		break;
-	
-	case CASE(	TIND,	TCHAR):
-	case CASE(	TIND,	TUCHAR):
-	case CASE(	TIND,	TSHORT):
-	case CASE(	TIND,	TUSHORT):
-	case CASE(	TIND,	TINT):
-	case CASE(	TIND,	TUINT):
-	case CASE(	TIND,	TLONG):
-	case CASE(	TIND,	TULONG):
-	case CASE(	TVLONG,	TCHAR):
-	case CASE(	TVLONG,	TUCHAR):
-	case CASE(	TVLONG,	TSHORT):
-	case CASE(	TVLONG,	TUSHORT):
-	case CASE(	TVLONG,	TINT):
-	case CASE(	TVLONG,	TUINT):
-	case CASE(	TVLONG,	TLONG):
-	case CASE(	TVLONG,	TULONG):
-	case CASE(	TUVLONG,	TCHAR):
-	case CASE(	TUVLONG,	TUCHAR):
-	case CASE(	TUVLONG,	TSHORT):
-	case CASE(	TUVLONG,	TUSHORT):
-	case CASE(	TUVLONG,	TINT):
-	case CASE(	TUVLONG,	TUINT):
-	case CASE(	TUVLONG,	TLONG):
-	case CASE(	TUVLONG,	TULONG):
-		a = AMOVQL;
-		if(f->op == OCONST) {
-			f->vconst &= (int)0xffffffffU;
-			a = AMOVL;
-		}
-		break;	
-
-	case CASE(	TIND,	TIND):
-	case CASE(	TIND,	TVLONG):
-	case CASE(	TIND,	TUVLONG):
-	case CASE(	TVLONG,	TIND):
-	case CASE(	TVLONG,	TVLONG):
-	case CASE(	TVLONG,	TUVLONG):
-	case CASE(	TUVLONG,	TIND):
-	case CASE(	TUVLONG,	TVLONG):
-	case CASE(	TUVLONG,	TUVLONG):
-		a = AMOVQ;
-		break;
-
-	case CASE(	TSHORT,	TINT):
-	case CASE(	TSHORT,	TUINT):
-	case CASE(	TSHORT,	TLONG):
-	case CASE(	TSHORT,	TULONG):
-		a = AMOVWLSX;
-		if(f->op == OCONST) {
-			f->vconst &= 0xffff;
-			if(f->vconst & 0x8000)
-				f->vconst |= 0xffff0000;
-			a = AMOVL;
-		}
-		break;
-
-	case CASE(	TSHORT,	TVLONG):
-	case CASE(	TSHORT,	TUVLONG):
-	case CASE(	TSHORT,	TIND):
-		a = AMOVWQSX;
-		if(f->op == OCONST) {
-			f->vconst &= 0xffff;
-			if(f->vconst & 0x8000){
-				f->vconst |= 0xffff0000;
-				f->vconst |= (vlong)~0 << 32;
-			}
-			a = AMOVL;
-		}
-		break;
-
-	case CASE(	TUSHORT,TINT):
-	case CASE(	TUSHORT,TUINT):
-	case CASE(	TUSHORT,TLONG):
-	case CASE(	TUSHORT,TULONG):
-		a = AMOVWLZX;
-		if(f->op == OCONST) {
-			f->vconst &= 0xffff;
-			a = AMOVL;
-		}
-		break;
-
-	case CASE(	TUSHORT,TVLONG):
-	case CASE(	TUSHORT,TUVLONG):
-	case CASE(	TUSHORT,TIND):
-		a = AMOVWQZX;
-		if(f->op == OCONST) {
-			f->vconst &= 0xffff;
-			a = AMOVL;	/* MOVL also zero-extends to 64 bits */
-		}
-		break;
-
-	case CASE(	TCHAR,	TSHORT):
-	case CASE(	TCHAR,	TUSHORT):
-	case CASE(	TCHAR,	TINT):
-	case CASE(	TCHAR,	TUINT):
-	case CASE(	TCHAR,	TLONG):
-	case CASE(	TCHAR,	TULONG):
-		a = AMOVBLSX;
-		if(f->op == OCONST) {
-			f->vconst &= 0xff;
-			if(f->vconst & 0x80)
-				f->vconst |= 0xffffff00;
-			a = AMOVL;
-		}
-		break;
-
-	case CASE(	TCHAR,	TVLONG):
-	case CASE(	TCHAR,	TUVLONG):
-	case CASE(	TCHAR,	TIND):
-		a = AMOVBQSX;
-		if(f->op == OCONST) {
-			f->vconst &= 0xff;
-			if(f->vconst & 0x80){
-				f->vconst |= 0xffffff00;
-				f->vconst |= (vlong)~0 << 32;
-			}
-			a = AMOVQ;
-		}
-		break;
-
-	case CASE(	TUCHAR,	TSHORT):
-	case CASE(	TUCHAR,	TUSHORT):
-	case CASE(	TUCHAR,	TINT):
-	case CASE(	TUCHAR,	TUINT):
-	case CASE(	TUCHAR,	TLONG):
-	case CASE(	TUCHAR,	TULONG):
-		a = AMOVBLZX;
-		if(f->op == OCONST) {
-			f->vconst &= 0xff;
-			a = AMOVL;
-		}
-		break;
-
-	case CASE(	TUCHAR,	TVLONG):
-	case CASE(	TUCHAR,	TUVLONG):
-	case CASE(	TUCHAR,	TIND):
-		a = AMOVBQZX;
-		if(f->op == OCONST) {
-			f->vconst &= 0xff;
-			a = AMOVL;	/* zero-extends to 64-bits */
-		}
-		break;
-
-/*
- * float to fix
- */
-	case CASE(	TFLOAT,	TCHAR):
-	case CASE(	TFLOAT,	TUCHAR):
-	case CASE(	TFLOAT,	TSHORT):
-	case CASE(	TFLOAT,	TUSHORT):
-	case CASE(	TFLOAT,	TINT):
-	case CASE(	TFLOAT,	TUINT):
-	case CASE(	TFLOAT,	TLONG):
-	case CASE(	TFLOAT,	TULONG):
-	case CASE(	TFLOAT,	TVLONG):
-	case CASE(	TFLOAT,	TUVLONG):
-	case CASE(	TFLOAT,	TIND):
-
-	case CASE(	TDOUBLE,TCHAR):
-	case CASE(	TDOUBLE,TUCHAR):
-	case CASE(	TDOUBLE,TSHORT):
-	case CASE(	TDOUBLE,TUSHORT):
-	case CASE(	TDOUBLE,TINT):
-	case CASE(	TDOUBLE,TUINT):
-	case CASE(	TDOUBLE,TLONG):
-	case CASE(	TDOUBLE,TULONG):
-	case CASE(	TDOUBLE,TVLONG):
-	case CASE(	TDOUBLE,TUVLONG):
-	case CASE(	TDOUBLE,TIND):
-		regalloc(&nod, t, Z);
-		if(ewidth[tt] == SZ_VLONG || typeu[tt] && ewidth[tt] == SZ_INT){
-			if(ft == TFLOAT)
-				a = ACVTTSS2SQ;
-			else
-				a = ACVTTSD2SQ;
-		}else{
-			if(ft == TFLOAT)
-				a = ACVTTSS2SL;
-			else
-				a = ACVTTSD2SL;
-		}
-		gins(a, f, &nod);
-		gmove(&nod, t);
-		regfree(&nod);
-		return;
-
-/*
- * uvlong to float
- */
-	case CASE(	TUVLONG,	TDOUBLE):
-	case CASE(	TUVLONG,	TFLOAT):
-		a = ACVTSQ2SS;
-		if(tt == TDOUBLE)
-			a = ACVTSQ2SD;
-		regalloc(&nod, f, f);
-		gmove(f, &nod);
-		regalloc(&nod1, t, t);
-		gins(ACMPQ, &nod, nodconst(0));
-		gins(AJLT, Z, Z);
-		p1 = p;
-		gins(a, &nod, &nod1);
-		gins(AJMP, Z, Z);
-		p2 = p;
-		patch(p1, pc);
-		regalloc(&nod2, f, Z);
-		regalloc(&nod3, f, Z);
-		gmove(&nod, &nod2);
-		gins(ASHRQ, nodconst(1), &nod2);
-		gmove(&nod, &nod3);
-		gins(AANDL, nodconst(1), &nod3);
-		gins(AORQ, &nod3, &nod2);
-		gins(a, &nod2, &nod1);
-		gins(tt == TDOUBLE? AADDSD: AADDSS, &nod1, &nod1);
-		regfree(&nod2);
-		regfree(&nod3);
-		patch(p2, pc);
-		regfree(&nod);
-		regfree(&nod1);
-		return;
-
-	case CASE(	TULONG,	TDOUBLE):
-	case CASE(	TUINT,	TDOUBLE):
-	case CASE(	TULONG,	TFLOAT):
-	case CASE(	TUINT,	TFLOAT):
-		a = ACVTSQ2SS;
-		if(tt == TDOUBLE)
-			a = ACVTSQ2SD;
-		regalloc(&nod, f, f);
-		gins(AMOVLQZX, f, &nod);
-		regalloc(&nod1, t, t);
-		gins(a, &nod, &nod1);
-		gmove(&nod1, t);
-		regfree(&nod);
-		regfree(&nod1);
-		return;
-
-/*
- * fix to float
- */
-	case CASE(	TCHAR,	TFLOAT):
-	case CASE(	TUCHAR,	TFLOAT):
-	case CASE(	TSHORT,	TFLOAT):
-	case CASE(	TUSHORT,TFLOAT):
-	case CASE(	TINT,	TFLOAT):
-	case CASE(	TLONG,	TFLOAT):
-	case	CASE(	TVLONG,	TFLOAT):
-	case CASE(	TIND,	TFLOAT):
-
-	case CASE(	TCHAR,	TDOUBLE):
-	case CASE(	TUCHAR,	TDOUBLE):
-	case CASE(	TSHORT,	TDOUBLE):
-	case CASE(	TUSHORT,TDOUBLE):
-	case CASE(	TINT,	TDOUBLE):
-	case CASE(	TLONG,	TDOUBLE):
-	case CASE(	TVLONG,	TDOUBLE):
-	case CASE(	TIND,	TDOUBLE):
-		regalloc(&nod, t, t);
-		if(ewidth[ft] == SZ_VLONG){
-			if(tt == TFLOAT)
-				a = ACVTSQ2SS;
-			else
-				a = ACVTSQ2SD;
-		}else{
-			if(tt == TFLOAT)
-				a = ACVTSL2SS;
-			else
-				a = ACVTSL2SD;
-		}
-		gins(a, f, &nod);
-		gmove(&nod, t);
-		regfree(&nod);
-		return;
-
-/*
- * float to float
- */
-	case CASE(	TFLOAT,	TFLOAT):
-		a = AMOVSS;
-		break;
-	case CASE(	TDOUBLE,TFLOAT):
-		a = ACVTSD2SS;
-		break;
-	case CASE(	TFLOAT,	TDOUBLE):
-		a = ACVTSS2SD;
-		break;
-	case CASE(	TDOUBLE,TDOUBLE):
-		a = AMOVSD;
-		break;
-	}
-	if(a == AMOVQ || a == AMOVSD || a == AMOVSS || a == AMOVL && ewidth[ft] == ewidth[tt])	/* TO DO: check AMOVL */
-	if(samaddr(f, t))
-		return;
-	gins(a, f, t);
-}
-
-void
-doindex(Node *n)
-{
-	Node nod, nod1;
-	int32 v;
-
-if(debug['Y'])
-prtree(n, "index");
-
-if(n->left->complex >= FNX)
-print("botch in doindex\n");
-
-	regalloc(&nod, &qregnode, Z);
-	v = constnode.vconst;
-	cgen(n->right, &nod);
-	idx.ptr = D_NONE;
-	if(n->left->op == OCONST)
-		idx.ptr = D_CONST;
-	else if(n->left->op == OREGISTER)
-		idx.ptr = n->left->reg;
-	else if(n->left->op != OADDR) {
-		reg[D_BP]++;	// can't be used as a base
-		regalloc(&nod1, &qregnode, Z);
-		cgen(n->left, &nod1);
-		idx.ptr = nod1.reg;
-		regfree(&nod1);
-		reg[D_BP]--;
-	}
-	idx.reg = nod.reg;
-	regfree(&nod);
-	constnode.vconst = v;
-}
-
-void
-gins(int a, Node *f, Node *t)
-{
-
-	if(f != Z && f->op == OINDEX)
-		doindex(f);
-	if(t != Z && t->op == OINDEX)
-		doindex(t);
-	nextpc();
-	p->as = a;
-	if(f != Z)
-		naddr(f, &p->from);
-	if(t != Z)
-		naddr(t, &p->to);
-	if(debug['g'])
-		print("%P\n", p);
-}
-
-void
-gopcode(int o, Type *ty, Node *f, Node *t)
-{
-	int a, et;
-
-	et = TLONG;
-	if(ty != T)
-		et = ty->etype;
-	if(et == TIND && ewidth[TIND] == 4)
-		et = TUINT;
-	if(debug['M']) {
-		if(f != Z && f->type != T)
-			print("gop: %O %O[%s],", o, f->op, tnames[et]);
-		else
-			print("gop: %O Z,", o);
-		if(t != Z && t->type != T)
-			print("%O[%s]\n", t->op, tnames[t->type->etype]);
-		else
-			print("Z\n");
-	}
-	a = AGOK;
-	switch(o) {
-	case OCOM:
-		a = ANOTL;
-		if(et == TCHAR || et == TUCHAR)
-			a = ANOTB;
-		if(et == TSHORT || et == TUSHORT)
-			a = ANOTW;
-		if(et == TVLONG || et == TUVLONG || et == TIND)
-			a = ANOTQ;
-		break;
-
-	case ONEG:
-		a = ANEGL;
-		if(et == TCHAR || et == TUCHAR)
-			a = ANEGB;
-		if(et == TSHORT || et == TUSHORT)
-			a = ANEGW;
-		if(et == TVLONG || et == TUVLONG || et == TIND)
-			a = ANEGQ;
-		break;
-
-	case OADDR:
-		a = ALEAQ;
-		break;
-
-	case OASADD:
-	case OADD:
-		a = AADDL;
-		if(et == TCHAR || et == TUCHAR)
-			a = AADDB;
-		if(et == TSHORT || et == TUSHORT)
-			a = AADDW;
-		if(et == TVLONG || et == TUVLONG || et == TIND)
-			a = AADDQ;
-		if(et == TFLOAT)
-			a = AADDSS;
-		if(et == TDOUBLE)
-			a = AADDSD;
-		break;
-
-	case OASSUB:
-	case OSUB:
-		a = ASUBL;
-		if(et == TCHAR || et == TUCHAR)
-			a = ASUBB;
-		if(et == TSHORT || et == TUSHORT)
-			a = ASUBW;
-		if(et == TVLONG || et == TUVLONG || et == TIND)
-			a = ASUBQ;
-		if(et == TFLOAT)
-			a = ASUBSS;
-		if(et == TDOUBLE)
-			a = ASUBSD;
-		break;
-
-	case OASOR:
-	case OOR:
-		a = AORL;
-		if(et == TCHAR || et == TUCHAR)
-			a = AORB;
-		if(et == TSHORT || et == TUSHORT)
-			a = AORW;
-		if(et == TVLONG || et == TUVLONG || et == TIND)
-			a = AORQ;
-		break;
-
-	case OASAND:
-	case OAND:
-		a = AANDL;
-		if(et == TCHAR || et == TUCHAR)
-			a = AANDB;
-		if(et == TSHORT || et == TUSHORT)
-			a = AANDW;
-		if(et == TVLONG || et == TUVLONG || et == TIND)
-			a = AANDQ;
-		break;
-
-	case OASXOR:
-	case OXOR:
-		a = AXORL;
-		if(et == TCHAR || et == TUCHAR)
-			a = AXORB;
-		if(et == TSHORT || et == TUSHORT)
-			a = AXORW;
-		if(et == TVLONG || et == TUVLONG || et == TIND)
-			a = AXORQ;
-		break;
-
-	case OASLSHR:
-	case OLSHR:
-		a = ASHRL;
-		if(et == TCHAR || et == TUCHAR)
-			a = ASHRB;
-		if(et == TSHORT || et == TUSHORT)
-			a = ASHRW;
-		if(et == TVLONG || et == TUVLONG || et == TIND)
-			a = ASHRQ;
-		break;
-
-	case OASASHR:
-	case OASHR:
-		a = ASARL;
-		if(et == TCHAR || et == TUCHAR)
-			a = ASARB;
-		if(et == TSHORT || et == TUSHORT)
-			a = ASARW;
-		if(et == TVLONG || et == TUVLONG || et == TIND)
-			a = ASARQ;
-		break;
-
-	case OASASHL:
-	case OASHL:
-		a = ASALL;
-		if(et == TCHAR || et == TUCHAR)
-			a = ASALB;
-		if(et == TSHORT || et == TUSHORT)
-			a = ASALW;
-		if(et == TVLONG || et == TUVLONG || et == TIND)
-			a = ASALQ;
-		break;
-
-	case OROTL:
-		a = AROLL;
-		if(et == TCHAR || et == TUCHAR)
-			a = AROLB;
-		if(et == TSHORT || et == TUSHORT)
-			a = AROLW;
-		if(et == TVLONG || et == TUVLONG || et == TIND)
-			a = AROLQ;
-		break;
-
-	case OFUNC:
-		a = ACALL;
-		break;
-
-	case OASMUL:
-	case OMUL:
-		if(f->op == OREGISTER && t != Z && isreg(t, D_AX) && reg[D_DX] == 0)
-			t = Z;
-		a = AIMULL;
-		if(et == TVLONG || et == TUVLONG || et == TIND)
-			a = AIMULQ;
-		if(et == TFLOAT)
-			a = AMULSS;
-		if(et == TDOUBLE)
-			a = AMULSD;
-		break;
-
-	case OASMOD:
-	case OMOD:
-	case OASDIV:
-	case ODIV:
-		a = AIDIVL;
-		if(et == TVLONG || et == TUVLONG || et == TIND)
-			a = AIDIVQ;
-		if(et == TFLOAT)
-			a = ADIVSS;
-		if(et == TDOUBLE)
-			a = ADIVSD;
-		break;
-
-	case OASLMUL:
-	case OLMUL:
-		a = AMULL;
-		if(et == TVLONG || et == TUVLONG || et == TIND)
-			a = AMULQ;
-		break;
-
-	case OASLMOD:
-	case OLMOD:
-	case OASLDIV:
-	case OLDIV:
-		a = ADIVL;
-		if(et == TVLONG || et == TUVLONG || et == TIND)
-			a = ADIVQ;
-		break;
-
-	case OEQ:
-	case ONE:
-	case OLT:
-	case OLE:
-	case OGE:
-	case OGT:
-	case OLO:
-	case OLS:
-	case OHS:
-	case OHI:
-		a = ACMPL;
-		if(et == TCHAR || et == TUCHAR)
-			a = ACMPB;
-		if(et == TSHORT || et == TUSHORT)
-			a = ACMPW;
-		if(et == TVLONG || et == TUVLONG || et == TIND)
-			a = ACMPQ;
-		if(et == TFLOAT)
-			a = AUCOMISS;
-		if(et == TDOUBLE)
-			a = AUCOMISD;
-		gins(a, f, t);
-		switch(o) {
-		case OEQ:	a = AJEQ; break;
-		case ONE:	a = AJNE; break;
-		case OLT:	a = AJLT; break;
-		case OLE:	a = AJLE; break;
-		case OGE:	a = AJGE; break;
-		case OGT:	a = AJGT; break;
-		case OLO:	a = AJCS; break;
-		case OLS:	a = AJLS; break;
-		case OHS:	a = AJCC; break;
-		case OHI:	a = AJHI; break;
-		}
-		gins(a, Z, Z);
-		return;
-	}
-	if(a == AGOK)
-		diag(Z, "bad in gopcode %O", o);
-	gins(a, f, t);
-}
-
-int
-samaddr(Node *f, Node *t)
-{
-	return f->op == OREGISTER && t->op == OREGISTER && f->reg == t->reg;
-}
-
-void
-gbranch(int o)
-{
-	int a;
-
-	a = AGOK;
-	switch(o) {
-	case ORETURN:
-		a = ARET;
-		break;
-	case OGOTO:
-		a = AJMP;
-		break;
-	}
-	nextpc();
-	if(a == AGOK) {
-		diag(Z, "bad in gbranch %O",  o);
-		nextpc();
-	}
-	p->as = a;
-}
-
-void
-patch(Prog *op, int32 pc)
-{
-	op->to.offset = pc;
-	op->to.type = D_BRANCH;
-	op->to.u.branch = nil;
-	op->pcond = nil;
-}
-
-void
-gpseudo(int a, Sym *s, Node *n)
-{
-
-	nextpc();
-	p->as = a;
-	p->from.type = D_EXTERN;
-	p->from.sym = linksym(s);
-
-	switch(a) {
-	case ATEXT:
-		p->from.scale = textflag;
-		textflag = 0;
-		break;
-	case AGLOBL:
-		p->from.scale = s->dataflag;
-		break;
-	}
-
-	if(s->class == CSTATIC)
-		p->from.type = D_STATIC;
-	naddr(n, &p->to);
-	if(a == ADATA || a == AGLOBL)
-		pc--;
-}
-
-void
-gpcdata(int index, int value)
-{
-	Node n1;
-	
-	n1 = *nodconst(index);
-	gins(APCDATA, &n1, nodconst(value));
-}
-
-void
-gprefetch(Node *n)
-{
-	Node n1;
-	
-	regalloc(&n1, n, Z);
-	gmove(n, &n1);
-	n1.op = OINDREG;
-	gins(APREFETCHNTA, &n1, Z);
-	regfree(&n1);
-}
-
-int
-sconst(Node *n)
-{
-	int32 v;
-
-	if(n->op == OCONST && !typefd[n->type->etype]) {
-		v = n->vconst;
-		if(v >= -32766L && v < 32766L)
-			return 1;
-	}
-	return 0;
-}
-
-int32
-exreg(Type *t)
-{
-	int32 o;
-
-	if(typechlpv[t->etype]) {
-		if(exregoffset >= 64)
-			return 0;
-		o = exregoffset;
-		exregoffset += ewidth[TIND];
-		return o+1;	// +1 to avoid 0 == failure; naddr's case OEXREG will subtract 1.
-	}
-	return 0;
-}
-
-schar	ewidth[NTYPE] =
-{
-	-1,		/*[TXXX]*/
-	SZ_CHAR,	/*[TCHAR]*/
-	SZ_CHAR,	/*[TUCHAR]*/
-	SZ_SHORT,	/*[TSHORT]*/
-	SZ_SHORT,	/*[TUSHORT]*/
-	SZ_INT,		/*[TINT]*/
-	SZ_INT,		/*[TUINT]*/
-	SZ_LONG,	/*[TLONG]*/
-	SZ_LONG,	/*[TULONG]*/
-	SZ_VLONG,	/*[TVLONG]*/
-	SZ_VLONG,	/*[TUVLONG]*/
-	SZ_FLOAT,	/*[TFLOAT]*/
-	SZ_DOUBLE,	/*[TDOUBLE]*/
-	SZ_IND,		/*[TIND]*/
-	0,		/*[TFUNC]*/
-	-1,		/*[TARRAY]*/
-	0,		/*[TVOID]*/
-	-1,		/*[TSTRUCT]*/
-	-1,		/*[TUNION]*/
-	SZ_INT,		/*[TENUM]*/
-};
-int32	ncast[NTYPE] =
-{
-	0,				/*[TXXX]*/
-	BCHAR|BUCHAR,			/*[TCHAR]*/
-	BCHAR|BUCHAR,			/*[TUCHAR]*/
-	BSHORT|BUSHORT,			/*[TSHORT]*/
-	BSHORT|BUSHORT,			/*[TUSHORT]*/
-	BINT|BUINT|BLONG|BULONG,	/*[TINT]*/
-	BINT|BUINT|BLONG|BULONG,	/*[TUINT]*/
-	BINT|BUINT|BLONG|BULONG,	/*[TLONG]*/
-	BINT|BUINT|BLONG|BULONG,	/*[TULONG]*/
-	BVLONG|BUVLONG|BIND,			/*[TVLONG]*/
-	BVLONG|BUVLONG|BIND,			/*[TUVLONG]*/
-	BFLOAT,				/*[TFLOAT]*/
-	BDOUBLE,			/*[TDOUBLE]*/
-	BVLONG|BUVLONG|BIND,		/*[TIND]*/
-	0,				/*[TFUNC]*/
-	0,				/*[TARRAY]*/
-	0,				/*[TVOID]*/
-	BSTRUCT,			/*[TSTRUCT]*/
-	BUNION,				/*[TUNION]*/
-	0,				/*[TENUM]*/
-};
diff --git a/src/cmd/6g/Makefile b/src/cmd/6g/Makefile
deleted file mode 100644
index 3f528d7..0000000
--- a/src/cmd/6g/Makefile
+++ /dev/null
@@ -1,5 +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.
-
-include ../../Make.dist
diff --git a/src/cmd/6g/cgen.c b/src/cmd/6g/cgen.c
deleted file mode 100644
index d13c98d..0000000
--- a/src/cmd/6g/cgen.c
+++ /dev/null
@@ -1,1732 +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 <u.h>
-#include <libc.h>
-#include "gg.h"
-
-/*
- * generate:
- *	res = n;
- * simplifies and calls gmove.
- */
-void
-cgen(Node *n, Node *res)
-{
-	Node *nl, *nr, *r;
-	Node n1, n2;
-	int a, f;
-	Prog *p1, *p2, *p3;
-	Addr addr;
-
-	if(debug['g']) {
-		dump("\ncgen-n", n);
-		dump("cgen-res", res);
-	}
-	if(n == N || n->type == T)
-		goto ret;
-
-	if(res == N || res->type == T)
-		fatal("cgen: res nil");
-
-	while(n->op == OCONVNOP)
-		n = n->left;
-
-	switch(n->op) {
-	case OSLICE:
-	case OSLICEARR:
-	case OSLICESTR:
-	case OSLICE3:
-	case OSLICE3ARR:
-		if (res->op != ONAME || !res->addable) {
-			tempname(&n1, n->type);
-			cgen_slice(n, &n1);
-			cgen(&n1, res);
-		} else
-			cgen_slice(n, res);
-		goto ret;
-	case OEFACE:
-		if (res->op != ONAME || !res->addable) {
-			tempname(&n1, n->type);
-			cgen_eface(n, &n1);
-			cgen(&n1, res);
-		} else
-			cgen_eface(n, res);
-		goto ret;
-	}
-
-	if(n->ullman >= UINF) {
-		if(n->op == OINDREG)
-			fatal("cgen: this is going to misscompile");
-		if(res->ullman >= UINF) {
-			tempname(&n1, n->type);
-			cgen(n, &n1);
-			cgen(&n1, res);
-			goto ret;
-		}
-	}
-
-	if(isfat(n->type)) {
-		if(n->type->width < 0)
-			fatal("forgot to compute width for %T", n->type);
-		sgen(n, res, n->type->width);
-		goto ret;
-	}
-
-	if(!res->addable) {
-		if(n->ullman > res->ullman) {
-			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);
-			goto ret;
-		}
-
-		if(res->ullman >= UINF)
-			goto gen;
-
-		if(complexop(n, res)) {
-			complexgen(n, res);
-			goto ret;
-		}
-
-		f = 1;	// gen thru register
-		switch(n->op) {
-		case OLITERAL:
-			if(smallintconst(n))
-				f = 0;
-			break;
-		case OREGISTER:
-			f = 0;
-			break;
-		}
-
-		if(!iscomplex[n->type->etype]) {
-			a = optoas(OAS, res->type);
-			if(sudoaddable(a, res, &addr)) {
-				if(f) {
-					regalloc(&n2, res->type, N);
-					cgen(n, &n2);
-					p1 = gins(a, &n2, N);
-					regfree(&n2);
-				} else
-					p1 = gins(a, n, N);
-				p1->to = addr;
-				if(debug['g'])
-					print("%P [ignore previous line]\n", p1);
-				sudoclean();
-				goto ret;
-			}
-		}
-
-	gen:
-		igen(res, &n1, N);
-		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 OSPTR:
-	case OLEN:
-		if(isslice(n->left->type) || istype(n->left->type, TSTRING))
-			n->addable = n->left->addable;
-		break;
-	case OCAP:
-		if(isslice(n->left->type))
-			n->addable = n->left->addable;
-		break;
-	case OITAB:
-		n->addable = n->left->addable;
-		break;
-	}
-
-	if(complexop(n, res)) {
-		complexgen(n, res);
-		goto ret;
-	}
-
-	if(n->addable) {
-		gmove(n, res);
-		goto ret;
-	}
-
-	nl = n->left;
-	nr = n->right;
-
-	if(nl != N && nl->ullman >= UINF)
-	if(nr != N && nr->ullman >= UINF) {
-		tempname(&n1, nl->type);
-		cgen(nl, &n1);
-		n2 = *n;
-		n2.left = &n1;
-		cgen(&n2, res);
-		goto ret;
-	}
-
-	if(!iscomplex[n->type->etype]) {
-		a = optoas(OAS, n->type);
-		if(sudoaddable(a, n, &addr)) {
-			if(res->op == OREGISTER) {
-				p1 = gins(a, N, res);
-				p1->from = addr;
-			} else {
-				regalloc(&n2, n->type, N);
-				p1 = gins(a, N, &n2);
-				p1->from = addr;
-				gins(a, &n2, res);
-				regfree(&n2);
-			}
-			sudoclean();
-			goto ret;
-		}
-	}
-
-	switch(n->op) {
-	default:
-		dump("cgen", n);
-		fatal("cgen: unknown op %+hN", n);
-		break;
-
-	// these call bgen to get a bool value
-	case OOROR:
-	case OANDAND:
-	case OEQ:
-	case ONE:
-	case OLT:
-	case OLE:
-	case OGE:
-	case OGT:
-	case ONOT:
-		p1 = gbranch(AJMP, T, 0);
-		p2 = pc;
-		gmove(nodbool(1), res);
-		p3 = gbranch(AJMP, T, 0);
-		patch(p1, pc);
-		bgen(n, 1, 0, p2);
-		gmove(nodbool(0), res);
-		patch(p3, pc);
-		goto ret;
-
-	case OPLUS:
-		cgen(nl, res);
-		goto ret;
-
-	// unary
-	case OCOM:
-		a = optoas(OXOR, nl->type);
-		regalloc(&n1, nl->type, N);
-		cgen(nl, &n1);
-		nodconst(&n2, nl->type, -1);
-		gins(a, &n2, &n1);
-		gmove(&n1, res);
-		regfree(&n1);
-		goto ret;
-
-	case OMINUS:
-		if(isfloat[nl->type->etype]) {
-			nr = nodintconst(-1);
-			convlit(&nr, n->type);
-			a = optoas(OMUL, nl->type);
-			goto sbop;
-		}
-		a = optoas(n->op, nl->type);
-		goto uop;
-
-	// symmetric binary
-	case OAND:
-	case OOR:
-	case OXOR:
-	case OADD:
-	case OMUL:
-		a = optoas(n->op, nl->type);
-		if(a == AIMULB) {
-			cgen_bmul(n->op, nl, nr, res);
-			break;
-		}
-		goto sbop;
-
-	// asymmetric binary
-	case OSUB:
-		a = optoas(n->op, nl->type);
-		goto abop;
-
-	case OHMUL:
-		cgen_hmul(nl, nr, res);
-		break;
-
-	case 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 ODOT:
-			case ODOTPTR:
-			case OINDEX:
-			case OIND:
-			case ONAME:
-				igen(nl, &n1, res);
-				regalloc(&n2, n->type, res);
-				gmove(&n1, &n2);
-				gmove(&n2, res);
-				regfree(&n2);
-				regfree(&n1);
-				goto ret;
-			}
-		}
-
-		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.
-		gmove(&n1, &n2);
-		gmove(&n2, res);
-		regfree(&n2);
-		regfree(&n1);
-		break;
-
-	case ODOT:
-	case ODOTPTR:
-	case OINDEX:
-	case OIND:
-	case ONAME:	// PHEAP or PPARAMREF var
-		igen(n, &n1, res);
-		gmove(&n1, res);
-		regfree(&n1);
-		break;
-	
-	case OITAB:
-		// interface table is first word of interface value
-		igen(nl, &n1, res);
-		n1.type = n->type;
-		gmove(&n1, res);
-		regfree(&n1);
-		break;
-
-	case OSPTR:
-		// pointer is the first word of string or slice.
-		if(isconst(nl, CTSTR)) {
-			regalloc(&n1, types[tptr], res);
-			p1 = gins(ALEAQ, N, &n1);
-			datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from);
-			gmove(&n1, res);
-			regfree(&n1);
-			break;
-		}
-		igen(nl, &n1, res);
-		n1.type = n->type;
-		gmove(&n1, res);
-		regfree(&n1);
-		break;
-
-	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
-			regalloc(&n1, types[tptr], res);
-			cgen(nl, &n1);
-
-			nodconst(&n2, types[tptr], 0);
-			gins(optoas(OCMP, types[tptr]), &n1, &n2);
-			p1 = gbranch(optoas(OEQ, types[tptr]), T, 0);
-
-			n2 = n1;
-			n2.op = OINDREG;
-			n2.type = types[simtype[TINT]];
-			gmove(&n2, &n1);
-
-			patch(p1, pc);
-
-			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
-			igen(nl, &n1, res);
-			n1.type = types[simtype[TUINT]];
-			n1.xoffset += Array_nel;
-			gmove(&n1, res);
-			regfree(&n1);
-			break;
-		}
-		fatal("cgen: OLEN: unknown type %lT", nl->type);
-		break;
-
-	case OCAP:
-		if(istype(nl->type, TCHAN)) {
-			// chan has cap in the second int-sized word.
-			// a zero pointer means zero length
-			regalloc(&n1, types[tptr], res);
-			cgen(nl, &n1);
-
-			nodconst(&n2, types[tptr], 0);
-			gins(optoas(OCMP, types[tptr]), &n1, &n2);
-			p1 = gbranch(optoas(OEQ, types[tptr]), T, 0);
-
-			n2 = n1;
-			n2.op = OINDREG;
-			n2.xoffset = widthint;
-			n2.type = types[simtype[TINT]];
-			gmove(&n2, &n1);
-
-			patch(p1, pc);
-
-			gmove(&n1, res);
-			regfree(&n1);
-			break;
-		}
-		if(isslice(nl->type)) {
-			igen(nl, &n1, res);
-			n1.type = types[simtype[TUINT]];
-			n1.xoffset += Array_cap;
-			gmove(&n1, res);
-			regfree(&n1);
-			break;
-		}
-		fatal("cgen: OCAP: unknown type %lT", nl->type);
-		break;
-
-	case OADDR:
-		if(n->bounded) // let race detector avoid nil checks
-			disable_checknil++;
-		agen(nl, res);
-		if(n->bounded)
-			disable_checknil--;
-		break;
-
-	case OCALLMETH:
-		cgen_callmeth(n, 0);
-		cgen_callret(n, res);
-		break;
-
-	case OCALLINTER:
-		cgen_callinter(n, res, 0);
-		cgen_callret(n, res);
-		break;
-
-	case OCALLFUNC:
-		cgen_call(n, 0);
-		cgen_callret(n, res);
-		break;
-
-	case OMOD:
-	case ODIV:
-		if(isfloat[n->type->etype]) {
-			a = optoas(n->op, nl->type);
-			goto abop;
-		}
-
-		if(nl->ullman >= nr->ullman) {
-			regalloc(&n1, nl->type, res);
-			cgen(nl, &n1);
-			cgen_div(n->op, &n1, nr, res);
-			regfree(&n1);
-		} else {
-			if(!smallintconst(nr)) {
-				regalloc(&n2, nr->type, res);
-				cgen(nr, &n2);
-			} else {
-				n2 = *nr;
-			}
-			cgen_div(n->op, nl, &n2, res);
-			if(n2.op != OLITERAL)
-				regfree(&n2);
-		}
-		break;
-
-	case OLSH:
-	case ORSH:
-	case OLROT:
-		cgen_shift(n->op, n->bounded, nl, nr, res);
-		break;
-	}
-	goto ret;
-
-sbop:	// symmetric binary
-	/*
-	 * 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.
-	 */
-	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
-	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(smallintconst(nr))
-			n2 = *nr;
-		else {
-			regalloc(&n2, nr->type, N);
-			cgen(nr, &n2);
-		}
-	} else {
-		if(smallintconst(nr))
-			n2 = *nr;
-		else {
-			regalloc(&n2, nr->type, res);
-			cgen(nr, &n2);
-		}
-		regalloc(&n1, nl->type, N);
-		cgen(nl, &n1);
-	}
-	gins(a, &n2, &n1);
-	gmove(&n1, res);
-	regfree(&n1);
-	if(n2.op != OLITERAL)
-		regfree(&n2);
-	goto ret;
-
-uop:	// unary
-	regalloc(&n1, nl->type, res);
-	cgen(nl, &n1);
-	gins(a, N, &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).
- */
-void
-cgenr(Node *n, Node *a, Node *res)
-{
-	Node n1;
-
-	if(debug['g'])
-		dump("cgenr-n", n);
-
-	if(isfat(n->type))
-		fatal("cgenr on fat node");
-
-	if(n->addable) {
-		regalloc(a, n->type, res);
-		gmove(n, a);
-		return;
-	}
-
-	switch(n->op) {
-	case ONAME:
-	case ODOT:
-	case ODOTPTR:
-	case OINDEX:
-	case OCALLFUNC:
-	case OCALLMETH:
-	case OCALLINTER:
-		igen(n, &n1, res);
-		regalloc(a, types[tptr], &n1);
-		gmove(&n1, a);
-		regfree(&n1);
-		break;
-	default:
-		regalloc(a, n->type, res);
-		cgen(n, a);
-		break;
-	}
-}
-
-/*
- * 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.
- */
-void
-agenr(Node *n, Node *a, Node *res)
-{
-	Node *nl, *nr;
-	Node n1, n2, n3, n5, tmp, tmp2, nlen;
-	Prog *p1;
-	Type *t;
-	uint64 w;
-	uint64 v;
-	int freelen;
-
-	if(debug['g']) {
-		dump("\nagenr-n", n);
-	}
-
-	nl = n->left;
-	nr = n->right;
-
-	switch(n->op) {
-	case ODOT:
-	case ODOTPTR:
-	case OCALLFUNC:
-	case OCALLMETH:
-	case OCALLINTER:
-		igen(n, &n1, res);
-		regalloc(a, types[tptr], &n1);
-		agen(&n1, a);
-		regfree(&n1);
-		break;
-
-	case OIND:
-		cgenr(n->left, a, res);
-		cgen_checknil(a);
-		break;
-
-	case OINDEX:
-		freelen = 0;
-		w = n->type->width;
-		// Generate the non-addressable child first.
-		if(nr->addable)
-			goto irad;
-		if(nl->addable) {
-			cgenr(nr, &n1, N);
-			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 += Array_array;
-					regalloc(&n3, types[tptr], res);
-					gmove(&nlen, &n3);
-					nlen.type = types[simtype[TUINT]];
-					nlen.xoffset += Array_nel-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) {
-					// igen will need an addressable node.
-					tempname(&tmp2, nl->type);
-					cgen(nl, &tmp2);
-					nl = &tmp2;
-				}
-				igen(nl, &nlen, res);
-				freelen = 1;
-				nlen.type = types[tptr];
-				nlen.xoffset += Array_array;
-				regalloc(&n3, types[tptr], res);
-				gmove(&nlen, &n3);
-				nlen.type = types[simtype[TUINT]];
-				nlen.xoffset += Array_nel-Array_array;
-			}
-		}
-		if(!isconst(nr, CTINT)) {
-			cgenr(nr, &n1, N);
-		}
-		goto index;
-
-	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
-		if(isconst(nr, CTINT)) {
-			if(isconst(nl, CTSTR))
-				fatal("constant string constant index");	// front end should handle
-			v = mpgetfix(nr->val.u.xval);
-			if(isslice(nl->type) || nl->type->etype == TSTRING) {
-				if(!debug['B'] && !n->bounded) {
-					nodconst(&n2, types[simtype[TUINT]], v);
-					if(smallintconst(nr)) {
-						gins(optoas(OCMP, types[simtype[TUINT]]), &nlen, &n2);
-					} else {
-						regalloc(&tmp, types[simtype[TUINT]], N);
-						gmove(&n2, &tmp);
-						gins(optoas(OCMP, types[simtype[TUINT]]), &nlen, &tmp);
-						regfree(&tmp);
-					}
-					p1 = gbranch(optoas(OGT, types[simtype[TUINT]]), T, +1);
-					ginscall(panicindex, -1);
-					patch(p1, pc);
-				}
-				regfree(&nlen);
-			}
-
-			if (v*w != 0)
-				ginscon(optoas(OADD, types[tptr]), v*w, &n3);
-			*a = n3;
-			break;
-		}
-
-		// type of the index
-		t = types[TUINT64];
-		if(issigned[n1.type->etype])
-			t = types[TINT64];
-
-		regalloc(&n2, t, &n1);			// i
-		gmove(&n1, &n2);
-		regfree(&n1);
-
-		if(!debug['B'] && !n->bounded) {
-			// check bounds
-			t = types[simtype[TUINT]];
-			if(is64(nr->type))
-				t = types[TUINT64];
-			if(isconst(nl, CTSTR)) {
-				nodconst(&nlen, t, nl->val.u.sval->len);
-			} else if(isslice(nl->type) || nl->type->etype == TSTRING) {
-				if(is64(nr->type)) {
-					regalloc(&n5, t, N);
-					gmove(&nlen, &n5);
-					regfree(&nlen);
-					nlen = n5;
-				}
-			} else {
-				nodconst(&nlen, t, nl->type->bound);
-				if(!smallintconst(&nlen)) {
-					regalloc(&n5, t, N);
-					gmove(&nlen, &n5);
-					nlen = n5;
-					freelen = 1;
-				}
-			}
-			gins(optoas(OCMP, t), &n2, &nlen);
-			p1 = gbranch(optoas(OLT, t), T, +1);
-			ginscall(panicindex, -1);
-			patch(p1, pc);
-		}
-
-		if(isconst(nl, CTSTR)) {
-			regalloc(&n3, types[tptr], res);
-			p1 = gins(ALEAQ, N, &n3);
-			datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from);
-			gins(AADDQ, &n2, &n3);
-			goto indexdone;
-		}
-
-		if(w == 0) {
-			// nothing to do
-		} else if(w == 1 || w == 2 || w == 4 || w == 8) {
-			p1 = gins(ALEAQ, &n2, &n3);
-			p1->from.scale = w;
-			p1->from.index = p1->from.type;
-			p1->from.type = p1->to.type + D_INDIR;
-		} else {
-			ginscon(optoas(OMUL, t), w, &n2);
-			gins(optoas(OADD, types[tptr]), &n2, &n3);
-		}
-
-	indexdone:
-		*a = n3;
-		regfree(&n2);
-		if(freelen)
-			regfree(&nlen);
-		break;
-
-	default:
-		regalloc(a, types[tptr], res);
-		agen(n, a);
-		break;
-	}
-}
-
-/*
- * generate:
- *	res = &n;
- * The generated code checks that the result is not nil.
- */
-void
-agen(Node *n, Node *res)
-{
-	Node *nl, *nr;
-	Node n1, n2;
-
-	if(debug['g']) {
-		dump("\nagen-res", res);
-		dump("agen-r", n);
-	}
-	if(n == N || n->type == T)
-		return;
-
-	while(n->op == OCONVNOP)
-		n = n->left;
-
-	if(isconst(n, CTNIL) && n->type->width > 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.
-		tempname(&n1, n->type);
-		gvardef(&n1);
-		clearfat(&n1);
-		regalloc(&n2, types[tptr], res);
-		gins(ALEAQ, &n1, &n2);
-		gmove(&n2, res);
-		regfree(&n2);
-		goto ret;
-	}
-		
-	if(n->addable) {
-		regalloc(&n1, types[tptr], res);
-		gins(ALEAQ, n, &n1);
-		gmove(&n1, res);
-		regfree(&n1);
-		goto ret;
-	}
-
-	nl = n->left;
-	nr = n->right;
-	USED(nr);
-
-	switch(n->op) {
-	default:
-		fatal("agen: unknown op %+hN", n);
-		break;
-
-	case OCALLMETH:
-		cgen_callmeth(n, 0);
-		cgen_aret(n, res);
-		break;
-
-	case OCALLINTER:
-		cgen_callinter(n, res, 0);
-		cgen_aret(n, res);
-		break;
-
-	case OCALLFUNC:
-		cgen_call(n, 0);
-		cgen_aret(n, res);
-		break;
-
-	case OSLICE:
-	case OSLICEARR:
-	case OSLICESTR:
-	case OSLICE3:
-	case OSLICE3ARR:
-		tempname(&n1, n->type);
-		cgen_slice(n, &n1);
-		agen(&n1, res);
-		break;
-
-	case OEFACE:
-		tempname(&n1, n->type);
-		cgen_eface(n, &n1);
-		agen(&n1, res);
-		break;
-
-	case OINDEX:
-		agenr(n, &n1, res);
-		gmove(&n1, res);
-		regfree(&n1);
-		break;
-
-	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) && n->class != PPARAMREF) {
-			dump("bad agen", n);
-			fatal("agen: bad ONAME class %#x", n->class);
-		}
-		cgen(n->heapaddr, res);
-		if(n->xoffset != 0)
-			ginscon(optoas(OADD, types[tptr]), n->xoffset, res);
-		break;
-
-	case OIND:
-		cgen(nl, res);
-		cgen_checknil(res);
-		break;
-
-	case ODOT:
-		agen(nl, res);
-		if(n->xoffset != 0)
-			ginscon(optoas(OADD, types[tptr]), n->xoffset, res);
-		break;
-
-	case ODOTPTR:
-		cgen(nl, res);
-		cgen_checknil(res);
-		if(n->xoffset != 0)
-			ginscon(optoas(OADD, types[tptr]), n->xoffset, res);
-		break;
-	}
-
-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.
- */
-void
-igen(Node *n, Node *a, Node *res)
-{
-	Type *fp;
-	Iter flist;
-	Node n1;
-
-	if(debug['g']) {
-		dump("\nigen-n", n);
-	}
-	switch(n->op) {
-	case ONAME:
-		if((n->class&PHEAP) || 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 != D_SP)
-			reg[n->val.u.reg]++;
-		*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:
-	case OCALLMETH:
-	case OCALLINTER:
-		switch(n->op) {
-		case OCALLFUNC:
-			cgen_call(n, 0);
-			break;
-		case OCALLMETH:
-			cgen_callmeth(n, 0);
-			break;
-		case OCALLINTER:
-			cgen_callinter(n, N, 0);
-			break;
-		}
-		fp = structfirst(&flist, getoutarg(n->left->type));
-		memset(a, 0, sizeof *a);
-		a->op = OINDREG;
-		a->val.u.reg = D_SP;
-		a->addable = 1;
-		a->xoffset = fp->width;
-		a->type = n->type;
-		return;
-
-	case OINDEX:
-		// 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.
-		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 {
-				igen(n->left, &n1, res);
-				cgen_checknil(&n1);
-				regalloc(a, types[tptr], res);
-				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;
-		}
-		break;
-	}
-
-	agenr(n, a, res);
-	a->op = OINDREG;
-	a->type = n->type;
-}
-
-/*
- * generate:
- *	if(n == true) goto to;
- */
-void
-bgen(Node *n, int true, int likely, Prog *to)
-{
-	int et, a;
-	Node *nl, *nr, *l, *r;
-	Node n1, n2, tmp;
-	NodeList *ll;
-	Prog *p1, *p2;
-
-	if(debug['g']) {
-		dump("\nbgen", n);
-	}
-
-	if(n == N)
-		n = nodbool(1);
-
-	if(n->ninit != nil)
-		genlist(n->ninit);
-
-	if(n->type == T) {
-		convlit(&n, types[TBOOL]);
-		if(n->type == T)
-			goto ret;
-	}
-
-	et = n->type->etype;
-	if(et != TBOOL) {
-		yyerror("cgen: bad type %T for %O", n->type, n->op);
-		patch(gins(AEND, N, N), to);
-		goto ret;
-	}
-	nr = N;
-
-	while(n->op == OCONVNOP) {
-		n = n->left;
-		if(n->ninit != nil)
-			genlist(n->ninit);
-	}
-
-	switch(n->op) {
-	default:
-	def:
-		regalloc(&n1, n->type, N);
-		cgen(n, &n1);
-		nodconst(&n2, n->type, 0);
-		gins(optoas(OCMP, n->type), &n1, &n2);
-		a = AJNE;
-		if(!true)
-			a = AJEQ;
-		patch(gbranch(a, n->type, likely), to);
-		regfree(&n1);
-		goto ret;
-
-	case OLITERAL:
-		// need to ask if it is bool?
-		if(!true == !n->val.u.bval)
-			patch(gbranch(AJMP, T, likely), to);
-		goto ret;
-
-	case ONAME:
-		if(n->addable == 0)
-			goto def;
-		nodconst(&n1, n->type, 0);
-		gins(optoas(OCMP, n->type), n, &n1);
-		a = AJNE;
-		if(!true)
-			a = AJEQ;
-		patch(gbranch(a, n->type, likely), to);
-		goto ret;
-
-	case OANDAND:
-		if(!true)
-			goto caseor;
-
-	caseand:
-		p1 = gbranch(AJMP, T, 0);
-		p2 = gbranch(AJMP, T, 0);
-		patch(p1, pc);
-		bgen(n->left, !true, -likely, p2);
-		bgen(n->right, !true, -likely, p2);
-		p1 = gbranch(AJMP, T, 0);
-		patch(p1, to);
-		patch(p2, pc);
-		goto ret;
-
-	case OOROR:
-		if(!true)
-			goto caseand;
-
-	caseor:
-		bgen(n->left, true, likely, to);
-		bgen(n->right, true, likely, to);
-		goto ret;
-
-	case OEQ:
-	case ONE:
-	case OLT:
-	case OGT:
-	case OLE:
-	case OGE:
-		nr = n->right;
-		if(nr == N || nr->type == T)
-			goto ret;
-
-	case ONOT:	// unary
-		nl = n->left;
-		if(nl == N || nl->type == T)
-			goto ret;
-		break;
-	}
-
-	switch(n->op) {
-
-	case ONOT:
-		bgen(nl, !true, likely, to);
-		goto ret;
-
-	case OEQ:
-	case ONE:
-	case OLT:
-	case OGT:
-	case OLE:
-	case OGE:
-		a = n->op;
-		if(!true) {
-			if(isfloat[nr->type->etype]) {
-				// brcom is not valid on floats when NaN is involved.
-				p1 = gbranch(AJMP, T, 0);
-				p2 = gbranch(AJMP, T, 0);
-				patch(p1, pc);
-				ll = n->ninit;   // avoid re-genning ninit
-				n->ninit = nil;
-				bgen(n, 1, -likely, p2);
-				n->ninit = ll;
-				patch(gbranch(AJMP, T, 0), to);
-				patch(p2, pc);
-				goto ret;
-			}				
-			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 = optoas(a, types[tptr]);
-			igen(nl, &n1, N);
-			n1.xoffset += Array_array;
-			n1.type = types[tptr];
-			nodconst(&tmp, types[tptr], 0);
-			gins(optoas(OCMP, types[tptr]), &n1, &tmp);
-			patch(gbranch(a, types[tptr], likely), to);
-			regfree(&n1);
-			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 = optoas(a, types[tptr]);
-			igen(nl, &n1, N);
-			n1.type = types[tptr];
-			nodconst(&tmp, types[tptr], 0);
-			gins(optoas(OCMP, types[tptr]), &n1, &tmp);
-			patch(gbranch(a, types[tptr], likely), to);
-			regfree(&n1);
-			break;
-		}
-		if(iscomplex[nl->type->etype]) {
-			complexbool(a, nl, nr, true, likely, to);
-			break;
-		}
-
-		if(nr->ullman >= UINF) {
-			regalloc(&n1, nl->type, N);
-			cgen(nl, &n1);
-
-			tempname(&tmp, nl->type);
-			gmove(&n1, &tmp);
-			regfree(&n1);
-
-			regalloc(&n2, nr->type, N);
-			cgen(nr, &n2);
-
-			regalloc(&n1, nl->type, N);
-			cgen(&tmp, &n1);
-
-			goto cmp;
-		}
-
-		regalloc(&n1, nl->type, N);
-		cgen(nl, &n1);
-
-		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, N);
-		cgen(nr, &n2);
-	cmp:
-		// only < and <= work right with NaN; reverse if needed
-		l = &n1;
-		r = &n2;
-		if(isfloat[nl->type->etype] && (a == OGT || a == OGE)) {
-			l = &n2;
-			r = &n1;
-			a = brrev(a);
-		}
-
-		gins(optoas(OCMP, nr->type), l, r);
-
-		if(isfloat[nr->type->etype] && (n->op == OEQ || n->op == ONE)) {
-			if(n->op == OEQ) {
-				// neither NE nor P
-				p1 = gbranch(AJNE, T, -likely);
-				p2 = gbranch(AJPS, T, -likely);
-				patch(gbranch(AJMP, T, 0), to);
-				patch(p1, pc);
-				patch(p2, pc);
-			} else {
-				// either NE or P
-				patch(gbranch(AJNE, T, likely), to);
-				patch(gbranch(AJPS, T, likely), to);
-			}
-		} else
-			patch(gbranch(optoas(a, nr->type), nr->type, likely), to);
-		regfree(&n1);
-		regfree(&n2);
-		break;
-	}
-	goto ret;
-
-ret:
-	;
-}
-
-/*
- * n is on stack, either local variable
- * or return value from function call.
- * return n's offset from SP.
- */
-int64
-stkof(Node *n)
-{
-	Type *t;
-	Iter flist;
-	int64 off;
-
-	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:
-	case OCALLINTER:
-	case OCALLFUNC:
-		t = n->left->type;
-		if(isptr[t->etype])
-			t = t->type;
-
-		t = structfirst(&flist, getoutarg(t));
-		if(t != T)
-			return t->width;
-		break;
-	}
-
-	// botch - probably failing to recognize address
-	// arithmetic on the above. eg INDEX and DOT
-	return -1000;
-}
-
-/*
- * block copy:
- *	memmove(&ns, &n, w);
- */
-void
-sgen(Node *n, Node *ns, int64 w)
-{
-	Node nodl, nodr, nodsi, noddi, cx, oldcx, tmp;
-	vlong c, q, odst, osrc;
-	NodeList *l;
-	Prog *p;
-
-	if(debug['g']) {
-		print("\nsgen w=%lld\n", w);
-		dump("r", n);
-		dump("res", ns);
-	}
-
-	if(n->ullman >= UINF && ns->ullman >= UINF)
-		fatal("sgen UINF");
-
-	if(w < 0)
-		fatal("sgen copy %lld", w);
-	
-	// If copying .args, that's all the results, so record definition sites
-	// for them for the liveness analysis.
-	if(ns->op == ONAME && strcmp(ns->sym->name, ".args") == 0)
-		for(l = curfn->dcl; l != nil; l = l->next)
-			if(l->n->class == PPARAMOUT)
-				gvardef(l->n);
-
-	// Avoid taking the address for simple enough types.
-	if(componentgen(n, ns))
-		return;
-	
-	if(w == 0) {
-		// evaluate side effects only
-		regalloc(&nodr, types[tptr], N);
-		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.
-		tempname(&tmp, n->type);
-		sgen(n, &tmp, w);
-		sgen(&tmp, ns, w);
-		return;
-	}
-
-	if(n->ullman >= ns->ullman) {
-		agenr(n, &nodr, N);
-		if(ns->op == ONAME)
-			gvardef(ns);
-		agenr(ns, &nodl, N);
-	} else {
-		if(ns->op == ONAME)
-			gvardef(ns);
-		agenr(ns, &nodl, N);
-		agenr(n, &nodr, N);
-	}
-	
-	nodreg(&noddi, types[tptr], D_DI);
-	nodreg(&nodsi, types[tptr], D_SI);
-	gmove(&nodl, &noddi);
-	gmove(&nodr, &nodsi);
-	regfree(&nodl);
-	regfree(&nodr);
-
-	c = w % 8;	// bytes
-	q = w / 8;	// quads
-
-	savex(D_CX, &cx, &oldcx, N, types[TINT64]);
-
-	// if we are copying forward on the stack and
-	// the src and dst overlap, then reverse direction
-	if(osrc < odst && odst < osrc+w) {
-		// reverse direction
-		gins(ASTD, N, N);		// set direction flag
-		if(c > 0) {
-			gconreg(addptr, w-1, D_SI);
-			gconreg(addptr, w-1, D_DI);
-
-			gconreg(movptr, c, D_CX);
-			gins(AREP, N, N);	// repeat
-			gins(AMOVSB, N, N);	// MOVB *(SI)-,*(DI)-
-		}
-
-		if(q > 0) {
-			if(c > 0) {
-				gconreg(addptr, -7, D_SI);
-				gconreg(addptr, -7, D_DI);
-			} else {
-				gconreg(addptr, w-8, D_SI);
-				gconreg(addptr, w-8, D_DI);
-			}
-			gconreg(movptr, q, D_CX);
-			gins(AREP, N, N);	// repeat
-			gins(AMOVSQ, N, N);	// MOVQ *(SI)-,*(DI)-
-		}
-		// we leave with the flag clear
-		gins(ACLD, N, N);
-	} else {
-		// normal direction
-		if(q > 128 || (nacl && q >= 4)) {
-			gconreg(movptr, q, D_CX);
-			gins(AREP, N, N);	// repeat
-			gins(AMOVSQ, N, N);	// MOVQ *(SI)+,*(DI)+
-		} else if (q >= 4) {
-			p = gins(ADUFFCOPY, N, N);
-			p->to.type = D_ADDR;
-			p->to.sym = linksym(pkglookup("duffcopy", runtimepkg));
-			// 14 and 128 = magic constants: see ../../runtime/asm_amd64.s
-			p->to.offset = 14*(128-q);
-		} else
-		while(q > 0) {
-			gins(AMOVSQ, N, N);	// MOVQ *(SI)+,*(DI)+
-			q--;
-		}
-		// copy the remaining c bytes
-		if(w < 4 || c <= 1 || (odst < osrc && osrc < odst+w)) {
-			while(c > 0) {
-				gins(AMOVSB, N, N);	// MOVB *(SI)+,*(DI)+
-				c--;
-			}
-		} else if(w < 8 || c <= 4) {
-			nodsi.op = OINDREG;
-			noddi.op = OINDREG;
-			nodsi.type = types[TINT32];
-			noddi.type = types[TINT32];
-			if(c > 4) {
-				nodsi.xoffset = 0;
-				noddi.xoffset = 0;
-				gmove(&nodsi, &noddi);
-			}
-			nodsi.xoffset = c-4;
-			noddi.xoffset = c-4;
-			gmove(&nodsi, &noddi);
-		} else {
-			nodsi.op = OINDREG;
-			noddi.op = OINDREG;
-			nodsi.type = types[TINT64];
-			noddi.type = types[TINT64];
-			nodsi.xoffset = c-8;
-			noddi.xoffset = c-8;
-			gmove(&nodsi, &noddi);
-		}
-	}
-
-	restx(&cx, &oldcx);
-}
-
-static int
-cadable(Node *n)
-{
-	if(!n->addable) {
-		// dont know how it happens,
-		// but it does
-		return 0;
-	}
-
-	switch(n->op) {
-	case ONAME:
-		return 1;
-	}
-	return 0;
-}
-
-/*
- * 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.
- */
-int
-componentgen(Node *nr, Node *nl)
-{
-	Node nodl, nodr;
-	Type *t;
-	int freel, freer;
-	vlong fldcount;
-	vlong loffset, roffset;
-
-	freel = 0;
-	freer = 0;
-
-	switch(nl->type->etype) {
-	default:
-		goto no;
-
-	case TARRAY:
-		t = nl->type;
-
-		// Slices are ok.
-		if(isslice(t))
-			break;
-		// Small arrays are ok.
-		if(t->bound > 0 && t->bound <= 3 && !isfat(t->type))
-			break;
-
-		goto no;
-
-	case TSTRUCT:
-		// Small structs with non-fat types are ok.
-		// Zero-sized structs are treated separately elsewhere.
-		fldcount = 0;
-		for(t=nl->type->type; t; t=t->down) {
-			if(isfat(t->type))
-				goto no;
-			if(t->etype != TFIELD)
-				fatal("componentgen: not a TFIELD: %lT", t);
-			fldcount++;
-		}
-		if(fldcount == 0 || fldcount > 4)
-			goto no;
-
-		break;
-
-	case TSTRING:
-	case TINTER:
-		break;
-	}
-
-	nodl = *nl;
-	if(!cadable(nl)) {
-		if(nr == N || !cadable(nr))
-			goto no;
-		igen(nl, &nodl, N);
-		freel = 1;
-	}
-
-	if(nr != N) {
-		nodr = *nr;
-		if(!cadable(nr)) {
-			igen(nr, &nodr, N);
-			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 != N && nl->op == ONAME && nr->op == ONAME && nl == nr)
-		goto yes;
-
-	switch(nl->type->etype) {
-	case TARRAY:
-		// componentgen for arrays.
-		if(nl->op == ONAME)
-			gvardef(nl);
-		t = nl->type;
-		if(!isslice(t)) {
-			nodl.type = t->type;
-			nodr.type = nodl.type;
-			for(fldcount=0; fldcount < t->bound; fldcount++) {
-				if(nr == N)
-					clearslim(&nodl);
-				else
-					gmove(&nodr, &nodl);
-				nodl.xoffset += t->type->width;
-				nodr.xoffset += t->type->width;
-			}
-			goto yes;
-		}
-
-		// componentgen for slices.
-		nodl.xoffset += Array_array;
-		nodl.type = ptrto(nl->type->type);
-
-		if(nr != N) {
-			nodr.xoffset += Array_array;
-			nodr.type = nodl.type;
-		} else
-			nodconst(&nodr, nodl.type, 0);
-		gmove(&nodr, &nodl);
-
-		nodl.xoffset += Array_nel-Array_array;
-		nodl.type = types[simtype[TUINT]];
-
-		if(nr != N) {
-			nodr.xoffset += Array_nel-Array_array;
-			nodr.type = nodl.type;
-		} else
-			nodconst(&nodr, nodl.type, 0);
-		gmove(&nodr, &nodl);
-
-		nodl.xoffset += Array_cap-Array_nel;
-		nodl.type = types[simtype[TUINT]];
-
-		if(nr != N) {
-			nodr.xoffset += Array_cap-Array_nel;
-			nodr.type = nodl.type;
-		} else
-			nodconst(&nodr, nodl.type, 0);
-		gmove(&nodr, &nodl);
-
-		goto yes;
-
-	case TSTRING:
-		if(nl->op == ONAME)
-			gvardef(nl);
-		nodl.xoffset += Array_array;
-		nodl.type = ptrto(types[TUINT8]);
-
-		if(nr != N) {
-			nodr.xoffset += Array_array;
-			nodr.type = nodl.type;
-		} else
-			nodconst(&nodr, nodl.type, 0);
-		gmove(&nodr, &nodl);
-
-		nodl.xoffset += Array_nel-Array_array;
-		nodl.type = types[simtype[TUINT]];
-
-		if(nr != N) {
-			nodr.xoffset += Array_nel-Array_array;
-			nodr.type = nodl.type;
-		} else
-			nodconst(&nodr, nodl.type, 0);
-		gmove(&nodr, &nodl);
-
-		goto yes;
-
-	case TINTER:
-		if(nl->op == ONAME)
-			gvardef(nl);
-		nodl.xoffset += Array_array;
-		nodl.type = ptrto(types[TUINT8]);
-
-		if(nr != N) {
-			nodr.xoffset += Array_array;
-			nodr.type = nodl.type;
-		} else
-			nodconst(&nodr, nodl.type, 0);
-		gmove(&nodr, &nodl);
-
-		nodl.xoffset += Array_nel-Array_array;
-		nodl.type = ptrto(types[TUINT8]);
-
-		if(nr != N) {
-			nodr.xoffset += Array_nel-Array_array;
-			nodr.type = nodl.type;
-		} else
-			nodconst(&nodr, nodl.type, 0);
-		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 && nl->type->type)
-			loffset -= nl->type->type->width;
-		if(nr != N && nr->type->etype == TSTRUCT && nr->type->funarg && nr->type->type)
-			roffset -= nr->type->type->width;
-
-		for(t=nl->type->type; t; t=t->down) {
-			nodl.xoffset = loffset + t->width;
-			nodl.type = t->type;
-
-			if(nr == N)
-				clearslim(&nodl);
-			else {
-				nodr.xoffset = roffset + t->width;
-				nodr.type = nodl.type;
-				gmove(&nodr, &nodl);
-			}
-		}
-		goto yes;
-	}
-
-no:
-	if(freer)
-		regfree(&nodr);
-	if(freel)
-		regfree(&nodl);
-	return 0;
-
-yes:
-	if(freer)
-		regfree(&nodr);
-	if(freel)
-		regfree(&nodl);
-	return 1;
-}
diff --git a/src/cmd/6g/doc.go b/src/cmd/6g/doc.go
deleted file mode 100644
index 07b2818..0000000
--- a/src/cmd/6g/doc.go
+++ /dev/null
@@ -1,15 +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.
-
-// +build ignore
-
-/*
-
-6g is the version of the gc compiler for the x86-64.
-The $GOARCH for these tools is amd64.
-
-It reads .go files and outputs .6 files. The flags are documented in ../gc/doc.go.
-
-*/
-package main
diff --git a/src/cmd/6g/galign.c b/src/cmd/6g/galign.c
deleted file mode 100644
index 5670e6f..0000000
--- a/src/cmd/6g/galign.c
+++ /dev/null
@@ -1,66 +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 <u.h>
-#include <libc.h>
-#include "gg.h"
-
-int	thechar	= '6';
-char*	thestring	= "amd64";
-LinkArch*	thelinkarch = &linkamd64;
-
-void
-linkarchinit(void)
-{
-	if(strcmp(getgoarch(), "amd64p32") == 0)
-		thelinkarch = &linkamd64p32;
-}
-
-vlong MAXWIDTH = 1LL<<50;
-
-int	addptr = AADDQ;
-int	movptr = AMOVQ;
-int	leaptr = ALEAQ;
-int	cmpptr = ACMPQ;
-
-/*
- * go declares several platform-specific type aliases:
- * int, uint, float, and uintptr
- */
-Typedef	typedefs[] =
-{
-	{"int",		TINT,		TINT64},
-	{"uint",		TUINT,		TUINT64},
-	{"uintptr",	TUINTPTR,	TUINT64},
-	{0}
-};
-
-void
-betypeinit(void)
-{
-	widthptr = 8;
-	widthint = 8;
-	widthreg = 8;
-	if(strcmp(getgoarch(), "amd64p32") == 0) {
-		widthptr = 4;
-		widthint = 4;
-		addptr = AADDL;
-		movptr = AMOVL;
-		leaptr = ALEAL;
-		cmpptr = ACMPL;
-		typedefs[0].sameas = TINT32;
-		typedefs[1].sameas = TUINT32;
-		typedefs[2].sameas = TUINT32;
-		
-	}
-
-	zprog.link = P;
-	zprog.as = AGOK;
-	zprog.from.type = D_NONE;
-	zprog.from.index = D_NONE;
-	zprog.from.scale = 0;
-	zprog.to = zprog.from;
-
-	listinit6();
-}
diff --git a/src/cmd/6g/gg.h b/src/cmd/6g/gg.h
deleted file mode 100644
index fe69d5c..0000000
--- a/src/cmd/6g/gg.h
+++ /dev/null
@@ -1,122 +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.
-
-#ifndef	EXTERN
-#define	EXTERN	extern
-#endif
-
-#include "../gc/go.h"
-#include "../6l/6.out.h"
-
-#define TEXTFLAG from.scale
-
-EXTERN	int32	dynloc;
-EXTERN	uchar	reg[D_NONE];
-EXTERN	int32	pcloc;		// instruction counter
-EXTERN	Strlit	emptystring;
-EXTERN	Prog	zprog;
-EXTERN	Node*	newproc;
-EXTERN	Node*	deferproc;
-EXTERN	Node*	deferreturn;
-EXTERN	Node*	panicindex;
-EXTERN	Node*	panicslice;
-EXTERN	Node*	panicdiv;
-EXTERN	Node*	throwreturn;
-extern	vlong	unmappedzero;
-extern	int	addptr;
-extern	int	cmpptr;
-extern	int	movptr;
-extern	int	leaptr;
-
-/*
- * ggen.c
- */
-void	compile(Node*);
-void	gen(Node*);
-Node*	lookdot(Node*, Node*, int);
-void	cgen_as(Node*, Node*);
-void	cgen_callmeth(Node*, int);
-void	cgen_callinter(Node*, Node*, int);
-void	cgen_proc(Node*, int);
-void	cgen_callret(Node*, Node*);
-void	cgen_div(int, Node*, Node*, Node*);
-void	cgen_bmul(int, Node*, Node*, Node*);
-void	cgen_hmul(Node*, Node*, Node*);
-void	cgen_shift(int, int, Node*, Node*, Node*);
-void	cgen_dcl(Node*);
-int	needconvert(Type*, Type*);
-void	genconv(Type*, Type*);
-void	allocparams(void);
-void	checklabels(void);
-void	ginscall(Node*, int);
-int	gen_as_init(Node*);
-
-/*
- * cgen.c
- */
-void	agen(Node*, Node*);
-void	agenr(Node*, Node*, Node*);
-void	cgenr(Node*, Node*, Node*);
-void	igen(Node*, Node*, Node*);
-vlong	fieldoffset(Type*, Node*);
-void	sgen(Node*, Node*, int64);
-void	gmove(Node*, Node*);
-Prog*	gins(int, Node*, Node*);
-int	samaddr(Node*, Node*);
-void	naddr(Node*, Addr*, int);
-void	cgen_aret(Node*, Node*);
-void	restx(Node*, Node*);
-void	savex(int, Node*, Node*, Node*, Type*);
-int	componentgen(Node*, Node*);
-
-/*
- * gsubr.c
- */
-void	clearp(Prog*);
-Prog*	gbranch(int, Type*, int);
-Prog*	prog(int);
-void	gconv(int, int);
-int	conv2pt(Type*);
-vlong	convvtox(vlong, int);
-void	fnparam(Type*, int, int);
-Prog*	gop(int, Node*, Node*, Node*);
-int	optoas(int, Type*);
-void	ginit(void);
-void	gclean(void);
-void	regalloc(Node*, Type*, Node*);
-void	regfree(Node*);
-Node*	nodarg(Type*, int);
-void	nodreg(Node*, Type*, int);
-void	nodindreg(Node*, Type*, int);
-void	gconreg(int, vlong, int);
-void	ginscon(int, vlong, Node*);
-void	buildtxt(void);
-Plist*	newplist(void);
-int	isfat(Type*);
-void	sudoclean(void);
-int	sudoaddable(int, Node*, Addr*);
-void	afunclit(Addr*, Node*);
-void	nodfconst(Node*, Type*, Mpflt*);
-void	gtrack(Sym*);
-void	fixlargeoffset(Node *n);
-
-/*
- * cplx.c
- */
-int	complexop(Node*, Node*);
-void	complexmove(Node*, Node*);
-void	complexgen(Node*, Node*);
-
-/*
- * gobj.c
- */
-void	datastring(char*, int, Addr*);
-void	datagostring(Strlit*, Addr*);
-
-/*
- * list.c
- */
-void	listinit(void);
-
-void	zaddr(Biobuf*, Addr*, int, int);
diff --git a/src/cmd/6g/ggen.c b/src/cmd/6g/ggen.c
deleted file mode 100644
index 3636207..0000000
--- a/src/cmd/6g/ggen.c
+++ /dev/null
@@ -1,1228 +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.
-
-#undef	EXTERN
-#define	EXTERN
-#include <u.h>
-#include <libc.h>
-#include "gg.h"
-#include "opt.h"
-
-static Prog *appendpp(Prog*, int, int, vlong, int, vlong);
-static Prog *zerorange(Prog *p, vlong frame, vlong lo, vlong hi, uint32 *ax);
-
-void
-defframe(Prog *ptxt)
-{
-	uint32 frame, ax;
-	Prog *p;
-	vlong hi, lo;
-	NodeList *l;
-	Node *n;
-
-	// fill in argument size
-	ptxt->to.offset = rnd(curfn->type->argwid, widthptr);
-
-	// fill in final stack size
-	ptxt->to.offset <<= 32;
-	frame = rnd(stksize+maxarg, widthreg);
-	ptxt->to.offset |= frame;
-	
-	// insert code to zero ambiguously live variables
-	// so that the garbage collector only sees initialized values
-	// when it looks for pointers.
-	p = ptxt;
-	lo = hi = 0;
-	ax = 0;
-	// iterate through declarations - they are sorted in decreasing xoffset order.
-	for(l=curfn->dcl; l != nil; l = l->next) {
-		n = l->n;
-		if(!n->needzero)
-			continue;
-		if(n->class != PAUTO)
-			fatal("needzero class %d", n->class);
-		if(n->type->width % widthptr != 0 || n->xoffset % widthptr != 0 || n->type->width == 0)
-			fatal("var %lN has size %d offset %d", n, (int)n->type->width, (int)n->xoffset);
-
-		if(lo != hi && n->xoffset + n->type->width >= lo - 2*widthreg) {
-			// merge with range we already have
-			lo = n->xoffset;
-			continue;
-		}
-		// zero old range
-		p = zerorange(p, frame, lo, hi, &ax);
-
-		// set new range
-		hi = n->xoffset + n->type->width;
-		lo = n->xoffset;
-	}
-	// zero final range
-	zerorange(p, frame, lo, hi, &ax);
-}
-
-static Prog*
-zerorange(Prog *p, vlong frame, vlong lo, vlong hi, uint32 *ax)
-{
-	vlong cnt, i;
-
-	cnt = hi - lo;
-	if(cnt == 0)
-		return p;
-	if(*ax == 0) {
-		p = appendpp(p, AMOVQ, D_CONST, 0, D_AX, 0);
-		*ax = 1;
-	}
-	if(cnt % widthreg != 0) {
-		// should only happen with nacl
-		if(cnt % widthptr != 0)
-			fatal("zerorange count not a multiple of widthptr %d", cnt);
-		p = appendpp(p, AMOVL, D_AX, 0, D_SP+D_INDIR, frame+lo);
-		lo += widthptr;
-		cnt -= widthptr;
-	}
-	if(cnt <= 4*widthreg) {
-		for(i = 0; i < cnt; i += widthreg) {
-			p = appendpp(p, AMOVQ, D_AX, 0, D_SP+D_INDIR, frame+lo+i);
-		}
-	} else if(!nacl && (cnt <= 128*widthreg)) {
-		p = appendpp(p, leaptr, D_SP+D_INDIR, frame+lo, D_DI, 0);
-		p = appendpp(p, ADUFFZERO, D_NONE, 0, D_ADDR, 2*(128-cnt/widthreg));
-		p->to.sym = linksym(pkglookup("duffzero", runtimepkg));
-	} else {
-		p = appendpp(p, AMOVQ, D_CONST, cnt/widthreg, D_CX, 0);
-		p = appendpp(p, leaptr, D_SP+D_INDIR, frame+lo, D_DI, 0);
-		p = appendpp(p, AREP, D_NONE, 0, D_NONE, 0);
-		p = appendpp(p, ASTOSQ, D_NONE, 0, D_NONE, 0);
-	}
-	return p;
-}
-
-static Prog*	
-appendpp(Prog *p, int as, int ftype, vlong foffset, int ttype, vlong toffset)	
-{
-	Prog *q;
-	q = mal(sizeof(*q));	
-	clearp(q);	
-	q->as = as;	
-	q->lineno = p->lineno;	
-	q->from.type = ftype;	
-	q->from.offset = foffset;	
-	q->to.type = ttype;	
-	q->to.offset = toffset;	
-	q->link = p->link;	
-	p->link = q;	
-	return q;	
-}
-
-// Sweep the prog list to mark any used nodes.
-void
-markautoused(Prog* p)
-{
-	for (; p; p = p->link) {
-		if (p->as == ATYPE || p->as == AVARDEF || p->as == AVARKILL)
-			continue;
-
-		if (p->from.node)
-			p->from.node->used = 1;
-
-		if (p->to.node)
-			p->to.node->used = 1;
-	}
-}
-
-// Fixup instructions after allocauto (formerly compactframe) has moved all autos around.
-void
-fixautoused(Prog *p)
-{
-	Prog **lp;
-
-	for (lp=&p; (p=*lp) != P; ) {
-		if (p->as == ATYPE && p->from.node && p->from.type == D_AUTO && !p->from.node->used) {
-			*lp = p->link;
-			continue;
-		}
-		if ((p->as == AVARDEF || p->as == AVARKILL) && p->to.node && !p->to.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
-			// the no-ops.
-			p->to.type = D_NONE;
-			p->to.node = N;
-			p->as = ANOP;
-			continue;
-		}
-		if (p->from.type == D_AUTO && p->from.node)
-			p->from.offset += p->from.node->stkdelta;
-
-		if (p->to.type == D_AUTO && p->to.node)
-			p->to.offset += p->to.node->stkdelta;
-
-		lp = &p->link;
-	}
-}
-
-
-/*
- * 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)
- */
-void
-ginscall(Node *f, int proc)
-{
-	Prog *p;
-	Node reg, con;
-	Node r1;
-
-	if(f->type != T)
-		setmaxarg(f->type);
-
-	switch(proc) {
-	default:
-		fatal("ginscall: bad proc %d", proc);
-		break;
-
-	case 0:	// normal call
-	case -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 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.
-				nodreg(&reg, types[TINT], D_AX);
-				gins(AXCHGL, &reg, &reg);
-			}
-			p = gins(ACALL, N, f);
-			afunclit(&p->to, f);
-			if(proc == -1 || noreturn(p))
-				gins(AUNDEF, N, N);
-			break;
-		}
-		nodreg(&reg, types[tptr], D_DX);
-		nodreg(&r1, types[tptr], D_BX);
-		gmove(f, &reg);
-		reg.op = OINDREG;
-		gmove(&reg, &r1);
-		reg.op = OREGISTER;
-		gins(ACALL, &reg, &r1);
-		break;
-	
-	case 3:	// normal call of c function pointer
-		gins(ACALL, N, f);
-		break;
-
-	case 1:	// call in new proc (go)
-	case 2:	// deferred call (defer)
-		nodconst(&con, types[TINT64], argsize(f->type));
-		if(widthptr == 4) {
-			nodreg(&r1, types[TINT32], D_CX);
-			gmove(f, &r1);
-			nodreg(&reg, types[TINT64], D_CX);
-			nodconst(&r1, types[TINT64], 32);
-			gins(ASHLQ, &r1, &reg);
-			gins(AORQ, &con, &reg);
-			gins(APUSHQ, &reg, N);
-		} else {
-			nodreg(&reg, types[TINT64], D_CX);
-			gmove(f, &reg);
-			gins(APUSHQ, &reg, N);
-			gins(APUSHQ, &con, N);
-		}
-		if(proc == 1)
-			ginscall(newproc, 0);
-		else {
-			if(!hasdefer)
-				fatal("hasdefer=0 but has defer");
-			ginscall(deferproc, 0);
-		}
-		nodreg(&reg, types[TINT64], D_CX);
-		gins(APOPQ, N, &reg);
-		if(widthptr == 8)
-			gins(APOPQ, N, &reg);
-		if(proc == 2) {
-			nodreg(&reg, types[TINT64], D_AX);
-			gins(ATESTQ, &reg, &reg);
-			p = gbranch(AJEQ, T, +1);
-			cgen_ret(N);
-			patch(p, pc);
-		}
-		break;
-	}
-}
-
-/*
- * n is call to interface method.
- * generate res = n.
- */
-void
-cgen_callinter(Node *n, Node *res, int proc)
-{
-	Node *i, *f;
-	Node tmpi, nodi, nodo, nodr, nodsp;
-
-	i = n->left;
-	if(i->op != ODOTINTER)
-		fatal("cgen_callinter: not ODOTINTER %O", i->op);
-
-	f = i->right;		// field
-	if(f->op != ONAME)
-		fatal("cgen_callinter: not ONAME %O", f->op);
-
-	i = i->left;		// interface
-
-	if(!i->addable) {
-		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.
-	igen(i, &nodi, res);		// REG = &inter
-
-	nodindreg(&nodsp, types[tptr], D_SP);
-	nodi.type = types[tptr];
-	nodi.xoffset += widthptr;
-	cgen(&nodi, &nodsp);	// 0(SP) = 8(REG) -- i.data
-
-	regalloc(&nodo, types[tptr], res);
-	nodi.type = types[tptr];
-	nodi.xoffset -= widthptr;
-	cgen(&nodi, &nodo);	// REG = 0(REG) -- i.tab
-	regfree(&nodi);
-
-	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*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(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
- */
-void
-cgen_call(Node *n, int proc)
-{
-	Type *t;
-	Node nod, afun;
-
-	if(n == N)
-		return;
-
-	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) {
-		regalloc(&nod, types[tptr], N);
-		cgen_as(&nod, &afun);
-		nod.type = t;
-		ginscall(&nod, proc);
-		regfree(&nod);
-		return;
-	}
-
-	// call pointer
-	if(n->left->op != ONAME || n->left->class != PFUNC) {
-		regalloc(&nod, types[tptr], N);
-		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.
- */
-void
-cgen_callret(Node *n, Node *res)
-{
-	Node nod;
-	Type *fp, *t;
-	Iter flist;
-
-	t = n->left->type;
-	if(t->etype == TPTR32 || t->etype == TPTR64)
-		t = t->type;
-
-	fp = structfirst(&flist, getoutarg(t));
-	if(fp == T)
-		fatal("cgen_callret: nil");
-
-	memset(&nod, 0, sizeof(nod));
-	nod.op = OINDREG;
-	nod.val.u.reg = D_SP;
-	nod.addable = 1;
-
-	nod.xoffset = fp->width;
-	nod.type = fp->type;
-	cgen_as(res, &nod);
-}
-
-/*
- * call to n has already been generated.
- * generate:
- *	res = &return value from call.
- */
-void
-cgen_aret(Node *n, Node *res)
-{
-	Node nod1, nod2;
-	Type *fp, *t;
-	Iter flist;
-
-	t = n->left->type;
-	if(isptr[t->etype])
-		t = t->type;
-
-	fp = structfirst(&flist, getoutarg(t));
-	if(fp == T)
-		fatal("cgen_aret: nil");
-
-	memset(&nod1, 0, sizeof(nod1));
-	nod1.op = OINDREG;
-	nod1.val.u.reg = D_SP;
-	nod1.addable = 1;
-
-	nod1.xoffset = fp->width;
-	nod1.type = fp->type;
-
-	if(res->op != OREGISTER) {
-		regalloc(&nod2, types[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.
- */
-void
-cgen_ret(Node *n)
-{
-	Prog *p;
-
-	if(n != N)
-		genlist(n->list);		// copy out args
-	if(hasdefer)
-		ginscall(deferreturn, 0);
-	genlist(curfn->exit);
-	p = gins(ARET, N, N);
-	if(n != N && n->op == ORETJMP) {
-		p->to.type = D_EXTERN;
-		p->to.sym = linksym(n->left->sym);
-	}
-}
-
-/*
- * generate += *= etc.
- */
-void
-cgen_asop(Node *n)
-{
-	Node n1, n2, n3, n4;
-	Node *nl, *nr;
-	Prog *p1;
-	Addr addr;
-	int a;
-
-	nl = n->left;
-	nr = n->right;
-
-	if(nr->ullman >= UINF && nl->ullman >= UINF) {
-		tempname(&n1, nr->type);
-		cgen(nr, &n1);
-		n2 = *n;
-		n2.right = &n1;
-		cgen_asop(&n2);
-		goto ret;
-	}
-
-	if(!isint[nl->type->etype])
-		goto hard;
-	if(!isint[nr->type->etype])
-		goto hard;
-
-	switch(n->etype) {
-	case OADD:
-		if(smallintconst(nr))
-		if(mpgetfix(nr->val.u.xval) == 1) {
-			a = optoas(OINC, nl->type);
-			if(nl->addable) {
-				gins(a, N, nl);
-				goto ret;
-			}
-			if(sudoaddable(a, nl, &addr)) {
-				p1 = gins(a, N, N);
-				p1->to = addr;
-				sudoclean();
-				goto ret;
-			}
-		}
-		break;
-
-	case OSUB:
-		if(smallintconst(nr))
-		if(mpgetfix(nr->val.u.xval) == 1) {
-			a = optoas(ODEC, nl->type);
-			if(nl->addable) {
-				gins(a, N, nl);
-				goto ret;
-			}
-			if(sudoaddable(a, nl, &addr)) {
-				p1 = gins(a, N, N);
-				p1->to = addr;
-				sudoclean();
-				goto ret;
-			}
-		}
-		break;
-	}
-
-	switch(n->etype) {
-	case OADD:
-	case OSUB:
-	case OXOR:
-	case OAND:
-	case OOR:
-		a = optoas(n->etype, nl->type);
-		if(nl->addable) {
-			if(smallintconst(nr)) {
-				gins(a, nr, nl);
-				goto ret;
-			}
-			regalloc(&n2, nr->type, N);
-			cgen(nr, &n2);
-			gins(a, &n2, nl);
-			regfree(&n2);
-			goto ret;
-		}
-		if(nr->ullman < UINF)
-		if(sudoaddable(a, nl, &addr)) {
-			if(smallintconst(nr)) {
-				p1 = gins(a, nr, N);
-				p1->to = addr;
-				sudoclean();
-				goto ret;
-			}
-			regalloc(&n2, nr->type, N);
-			cgen(nr, &n2);
-			p1 = gins(a, &n2, N);
-			p1->to = addr;
-			regfree(&n2);
-			sudoclean();
-			goto ret;
-		}
-	}
-
-hard:
-	n2.op = 0;
-	n1.op = 0;
-	if(nr->op == OLITERAL) {
-		// don't allocate a register for literals.
-	} else if(nr->ullman >= nl->ullman || nl->addable) {
-		regalloc(&n2, nr->type, N);
-		cgen(nr, &n2);
-		nr = &n2;
-	} else {
-		tempname(&n2, nr->type);
-		cgen(nr, &n2);
-		nr = &n2;
-	}
-	if(!nl->addable) {
-		igen(nl, &n1, N);
-		nl = &n1;
-	}
-
-	n3 = *n;
-	n3.left = nl;
-	n3.right = nr;
-	n3.op = n->etype;
-
-	regalloc(&n4, nl->type, N);
-	cgen(&n3, &n4);
-	gmove(&n4, nl);
-
-	if(n1.op)
-		regfree(&n1);
-	if(n2.op == OREGISTER)
-		regfree(&n2);
-	regfree(&n4);
-
-ret:
-	;
-}
-
-int
-samereg(Node *a, Node *b)
-{
-	if(a == N || b == N)
-		return 0;
-	if(a->op != OREGISTER)
-		return 0;
-	if(b->op != OREGISTER)
-		return 0;
-	if(a->val.u.reg != b->val.u.reg)
-		return 0;
-	return 1;
-}
-
-/*
- * generate division.
- * generates one of:
- *	res = nl / nr
- *	res = nl % nr
- * according to op.
- */
-void
-dodiv(int op, Node *nl, Node *nr, Node *res)
-{
-	int a, check;
-	Node n3, n4;
-	Type *t, *t0;
-	Node ax, dx, ax1, n31, oldax, olddx;
-	Prog *p1, *p2;
-
-	// Have to be careful about handling
-	// most negative int divided by -1 correctly.
-	// The hardware will trap.
-	// Also the byte divide instruction needs AH,
-	// which we otherwise don't have to deal with.
-	// Easiest way to avoid for int8, int16: use int32.
-	// For int32 and int64, use explicit test.
-	// Could use int64 hw for int32.
-	t = nl->type;
-	t0 = t;
-	check = 0;
-	if(issigned[t->etype]) {
-		check = 1;
-		if(isconst(nl, CTINT) && mpgetfix(nl->val.u.xval) != -(1ULL<<(t->width*8-1)))
-			check = 0;
-		else if(isconst(nr, CTINT) && mpgetfix(nr->val.u.xval) != -1)
-			check = 0;
-	}
-	if(t->width < 4) {
-		if(issigned[t->etype])
-			t = types[TINT32];
-		else
-			t = types[TUINT32];
-		check = 0;
-	}
-	a = optoas(op, t);
-
-	regalloc(&n3, t0, N);
-	if(nl->ullman >= nr->ullman) {
-		savex(D_AX, &ax, &oldax, res, t0);
-		cgen(nl, &ax);
-		regalloc(&ax, t0, &ax);	// mark ax live during cgen
-		cgen(nr, &n3);
-		regfree(&ax);
-	} else {
-		cgen(nr, &n3);
-		savex(D_AX, &ax, &oldax, res, t0);
-		cgen(nl, &ax);
-	}
-	if(t != t0) {
-		// Convert
-		ax1 = ax;
-		n31 = n3;
-		ax.type = t;
-		n3.type = t;
-		gmove(&ax1, &ax);
-		gmove(&n31, &n3);
-	}
-
-	p2 = P;
-	if(nacl) {
-		// Native Client does not relay the divide-by-zero trap
-		// to the executing program, so we must insert a check
-		// for ourselves.
-		nodconst(&n4, t, 0);
-		gins(optoas(OCMP, t), &n3, &n4);
-		p1 = gbranch(optoas(ONE, t), T, +1);
-		if(panicdiv == N)
-			panicdiv = sysfunc("panicdivide");
-		ginscall(panicdiv, -1);
-		patch(p1, pc);
-	}
-	if(check) {
-		nodconst(&n4, t, -1);
-		gins(optoas(OCMP, t), &n3, &n4);
-		p1 = gbranch(optoas(ONE, t), T, +1);
-		if(op == ODIV) {
-			// a / (-1) is -a.
-			gins(optoas(OMINUS, t), N, &ax);
-			gmove(&ax, res);
-		} else {
-			// a % (-1) is 0.
-			nodconst(&n4, t, 0);
-			gmove(&n4, res);
-		}
-		p2 = gbranch(AJMP, T, 0);
-		patch(p1, pc);
-	}
-	savex(D_DX, &dx, &olddx, res, t);
-	if(!issigned[t->etype]) {
-		nodconst(&n4, t, 0);
-		gmove(&n4, &dx);
-	} else
-		gins(optoas(OEXTEND, t), N, N);
-	gins(a, &n3, N);
-	regfree(&n3);
-	if(op == ODIV)
-		gmove(&ax, res);
-	else
-		gmove(&dx, res);
-	restx(&dx, &olddx);
-	if(check)
-		patch(p2, pc);
-	restx(&ax, &oldax);
-}
-
-/*
- * register dr is one of the special ones (AX, CX, DI, SI, etc.).
- * we need to use it.  if it is already allocated as a temporary
- * (r > 1; can only happen if a routine like sgen passed a
- * special as cgen's res and then cgen used regalloc to reuse
- * it as its own temporary), then move it for now to another
- * register.  caller must call restx to move it back.
- * the move is not necessary if dr == res, because res is
- * known to be dead.
- */
-void
-savex(int dr, Node *x, Node *oldx, Node *res, Type *t)
-{
-	int r;
-
-	r = reg[dr];
-
-	// save current ax and dx if they are live
-	// and not the destination
-	memset(oldx, 0, sizeof *oldx);
-	nodreg(x, t, dr);
-	if(r > 1 && !samereg(x, res)) {
-		regalloc(oldx, types[TINT64], N);
-		x->type = types[TINT64];
-		gmove(x, oldx);
-		x->type = t;
-		oldx->ostk = r;	// squirrel away old r value
-		reg[dr] = 1;
-	}
-}
-
-void
-restx(Node *x, Node *oldx)
-{
-	if(oldx->op != 0) {
-		x->type = types[TINT64];
-		reg[x->val.u.reg] = oldx->ostk;
-		gmove(oldx, x);
-		regfree(oldx);
-	}
-}
-
-/*
- * generate division according to op, one of:
- *	res = nl / nr
- *	res = nl % nr
- */
-void
-cgen_div(int op, Node *nl, Node *nr, Node *res)
-{
-	Node n1, n2, n3;
-	int w, a;
-	Magic m;
-
-	if(nr->op != OLITERAL)
-		goto longdiv;
-	w = 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:
-		m.w = w;
-		m.ud = mpgetfix(nr->val.u.xval);
-		umagic(&m);
-		if(m.bad)
-			break;
-		if(op == OMOD)
-			goto longmod;
-
-		cgenr(nl, &n1, N);
-		nodconst(&n2, nl->type, m.um);
-		regalloc(&n3, nl->type, res);
-		cgen_hmul(&n1, &n2, &n3);
-
-		if(m.ua) {
-			// need to add numerator accounting for overflow
-			gins(optoas(OADD, nl->type), &n1, &n3);
-			nodconst(&n2, nl->type, 1);
-			gins(optoas(ORROTC, nl->type), &n2, &n3);
-			nodconst(&n2, nl->type, m.s-1);
-			gins(optoas(ORSH, nl->type), &n2, &n3);
-		} else {
-			nodconst(&n2, nl->type, m.s);
-			gins(optoas(ORSH, nl->type), &n2, &n3);	// shift dx
-		}
-
-		gmove(&n3, res);
-		regfree(&n1);
-		regfree(&n3);
-		return;
-
-	case TINT64:
-		m.w = w;
-		m.sd = mpgetfix(nr->val.u.xval);
-		smagic(&m);
-		if(m.bad)
-			break;
-		if(op == OMOD)
-			goto longmod;
-
-		cgenr(nl, &n1, res);
-		nodconst(&n2, nl->type, m.sm);
-		regalloc(&n3, nl->type, N);
-		cgen_hmul(&n1, &n2, &n3);
-
-		if(m.sm < 0) {
-			// need to add numerator
-			gins(optoas(OADD, nl->type), &n1, &n3);
-		}
-
-		nodconst(&n2, nl->type, m.s);
-		gins(optoas(ORSH, nl->type), &n2, &n3);	// shift n3
-
-		nodconst(&n2, nl->type, w-1);
-		gins(optoas(ORSH, nl->type), &n2, &n1);	// -1 iff num is neg
-		gins(optoas(OSUB, nl->type), &n1, &n3);	// added
-
-		if(m.sd < 0) {
-			// this could probably be removed
-			// by factoring it into the multiplier
-			gins(optoas(OMINUS, nl->type), N, &n3);
-		}
-
-		gmove(&n3, res);
-		regfree(&n1);
-		regfree(&n3);
-		return;
-	}
-	goto longdiv;
-
-longdiv:
-	// division and mod using (slow) hardware instruction
-	dodiv(op, nl, nr, res);
-	return;
-
-longmod:
-	// mod using formula A%B = A-(A/B*B) but
-	// we know that there is a fast algorithm for A/B
-	regalloc(&n1, nl->type, res);
-	cgen(nl, &n1);
-	regalloc(&n2, nl->type, N);
-	cgen_div(ODIV, &n1, nr, &n2);
-	a = optoas(OMUL, nl->type);
-	if(w == 8) {
-		// use 2-operand 16-bit multiply
-		// because there is no 2-operand 8-bit multiply
-		a = AIMULW;
-	}
-	if(!smallintconst(nr)) {
-		regalloc(&n3, nl->type, N);
-		cgen(nr, &n3);
-		gins(a, &n3, &n2);
-		regfree(&n3);
-	} else
-		gins(a, nr, &n2);
-	gins(optoas(OSUB, nl->type), &n2, &n1);
-	gmove(&n1, res);
-	regfree(&n1);
-	regfree(&n2);
-}
-
-/*
- * generate high multiply:
- *   res = (nl*nr) >> width
- */
-void
-cgen_hmul(Node *nl, Node *nr, Node *res)
-{
-	Type *t;
-	int a;
-	Node n1, n2, ax, dx, *tmp;
-
-	t = nl->type;
-	a = optoas(OHMUL, t);
-	if(nl->ullman < nr->ullman) {
-		tmp = nl;
-		nl = nr;
-		nr = tmp;
-	}
-	cgenr(nl, &n1, res);
-	cgenr(nr, &n2, N);
-	nodreg(&ax, t, D_AX);
-	gmove(&n1, &ax);
-	gins(a, &n2, N);
-	regfree(&n2);
-	regfree(&n1);
-
-	if(t->width == 1) {
-		// byte multiply behaves differently.
-		nodreg(&ax, t, D_AH);
-		nodreg(&dx, t, D_DX);
-		gmove(&ax, &dx);
-	}
-	nodreg(&dx, t, D_DX);
-	gmove(&dx, res);
-}
-
-/*
- * generate shift according to op, one of:
- *	res = nl << nr
- *	res = nl >> nr
- */
-void
-cgen_shift(int op, int bounded, Node *nl, Node *nr, Node *res)
-{
-	Node n1, n2, n3, n4, n5, cx, oldcx;
-	int a, rcx;
-	Prog *p1;
-	uvlong sc;
-	Type *tcount;
-
-	a = optoas(op, nl->type);
-
-	if(nr->op == OLITERAL) {
-		regalloc(&n1, nl->type, res);
-		cgen(nl, &n1);
-		sc = mpgetfix(nr->val.u.xval);
-		if(sc >= nl->type->width*8) {
-			// large shift gets 2 shifts by width-1
-			nodconst(&n3, types[TUINT32], nl->type->width*8-1);
-			gins(a, &n3, &n1);
-			gins(a, &n3, &n1);
-		} else
-			gins(a, nr, &n1);
-		gmove(&n1, res);
-		regfree(&n1);
-		goto ret;
-	}
-
-	if(nl->ullman >= UINF) {
-		tempname(&n4, nl->type);
-		cgen(nl, &n4);
-		nl = &n4;
-	}
-	if(nr->ullman >= UINF) {
-		tempname(&n5, nr->type);
-		cgen(nr, &n5);
-		nr = &n5;
-	}
-
-	rcx = reg[D_CX];
-	nodreg(&n1, types[TUINT32], D_CX);
-	
-	// Allow either uint32 or uint64 as shift type,
-	// to avoid unnecessary conversion from uint32 to uint64
-	// just to do the comparison.
-	tcount = types[simtype[nr->type->etype]];
-	if(tcount->etype < TUINT32)
-		tcount = types[TUINT32];
-
-	regalloc(&n1, nr->type, &n1);		// to hold the shift type in CX
-	regalloc(&n3, tcount, &n1);	// to clear high bits of CX
-
-	nodreg(&cx, types[TUINT64], D_CX);
-	memset(&oldcx, 0, sizeof oldcx);
-	if(rcx > 0 && !samereg(&cx, res)) {
-		regalloc(&oldcx, types[TUINT64], N);
-		gmove(&cx, &oldcx);
-	}
-	cx.type = tcount;
-
-	if(samereg(&cx, res))
-		regalloc(&n2, nl->type, N);
-	else
-		regalloc(&n2, nl->type, res);
-	if(nl->ullman >= nr->ullman) {
-		cgen(nl, &n2);
-		cgen(nr, &n1);
-		gmove(&n1, &n3);
-	} else {
-		cgen(nr, &n1);
-		gmove(&n1, &n3);
-		cgen(nl, &n2);
-	}
-	regfree(&n3);
-
-	// test and fix up large shifts
-	if(!bounded) {
-		nodconst(&n3, tcount, nl->type->width*8);
-		gins(optoas(OCMP, tcount), &n1, &n3);
-		p1 = gbranch(optoas(OLT, tcount), T, +1);
-		if(op == ORSH && issigned[nl->type->etype]) {
-			nodconst(&n3, types[TUINT32], nl->type->width*8-1);
-			gins(a, &n3, &n2);
-		} else {
-			nodconst(&n3, nl->type, 0);
-			gmove(&n3, &n2);
-		}
-		patch(p1, pc);
-	}
-
-	gins(a, &n1, &n2);
-
-	if(oldcx.op != 0) {
-		cx.type = types[TUINT64];
-		gmove(&oldcx, &cx);
-		regfree(&oldcx);
-	}
-
-	gmove(&n2, res);
-
-	regfree(&n1);
-	regfree(&n2);
-
-ret:
-	;
-}
-
-/*
- * generate byte multiply:
- *	res = nl * nr
- * there is no 2-operand byte multiply instruction so
- * we do a full-width multiplication and truncate afterwards.
- */
-void
-cgen_bmul(int op, Node *nl, Node *nr, Node *res)
-{
-	Node n1, n2, n1b, n2b, *tmp;
-	Type *t;
-	int a;
-
-	// largest ullman on left.
-	if(nl->ullman < nr->ullman) {
-		tmp = nl;
-		nl = nr;
-		nr = tmp;
-	}
-
-	// generate operands in "8-bit" registers.
-	regalloc(&n1b, nl->type, res);
-	cgen(nl, &n1b);
-	regalloc(&n2b, nr->type, N);
-	cgen(nr, &n2b);
-
-	// perform full-width multiplication.
-	t = types[TUINT64];
-	if(issigned[nl->type->etype])
-		t = types[TINT64];
-	nodreg(&n1, t, n1b.val.u.reg);
-	nodreg(&n2, t, n2b.val.u.reg);
-	a = optoas(op, t);
-	gins(a, &n2, &n1);
-
-	// truncate.
-	gmove(&n1, res);
-	regfree(&n1b);
-	regfree(&n2b);
-}
-
-void
-clearfat(Node *nl)
-{
-	int64 w, c, q;
-	Node n1, oldn1, ax, oldax, di, z;
-	Prog *p;
-
-	/* clear a fat object */
-	if(debug['g'])
-		dump("\nclearfat", nl);
-
-	w = nl->type->width;
-	// Avoid taking the address for simple enough types.
-	if(componentgen(N, nl))
-		return;
-
-	c = w % 8;	// bytes
-	q = w / 8;	// quads
-
-	if(q < 4) {
-		// Write sequence of MOV 0, off(base) instead of using STOSQ.
-		// The hope is that although the code will be slightly longer,
-		// the MOVs will have no dependencies and pipeline better
-		// than the unrolled STOSQ loop.
-		// NOTE: Must use agen, not igen, so that optimizer sees address
-		// being taken. We are not writing on field boundaries.
-		agenr(nl, &n1, N);
-		n1.op = OINDREG;
-		nodconst(&z, types[TUINT64], 0);
-		while(q-- > 0) {
-			n1.type = z.type;
-			gins(AMOVQ, &z, &n1);
-			n1.xoffset += 8;
-		}
-		if(c >= 4) {
-			nodconst(&z, types[TUINT32], 0);
-			n1.type = z.type;
-			gins(AMOVL, &z, &n1);
-			n1.xoffset += 4;
-			c -= 4;
-		}
-		nodconst(&z, types[TUINT8], 0);
-		while(c-- > 0) {
-			n1.type = z.type;
-			gins(AMOVB, &z, &n1);
-			n1.xoffset++;
-		}
-		regfree(&n1);
-		return;
-	}
-
-	savex(D_DI, &n1, &oldn1, N, types[tptr]);
-	agen(nl, &n1);
-
-	savex(D_AX, &ax, &oldax, N, types[tptr]);
-	gconreg(AMOVL, 0, D_AX);
-
-	if(q > 128 || nacl) {
-		gconreg(movptr, q, D_CX);
-		gins(AREP, N, N);	// repeat
-		gins(ASTOSQ, N, N);	// STOQ AL,*(DI)+
-	} else {
-		p = gins(ADUFFZERO, N, N);
-		p->to.type = D_ADDR;
-		p->to.sym = linksym(pkglookup("duffzero", runtimepkg));
-		// 2 and 128 = magic constants: see ../../runtime/asm_amd64.s
-		p->to.offset = 2*(128-q);
-	}
-
-	z = ax;
-	di = n1;
-	if(w >= 8 && c >= 4) {
-		di.op = OINDREG;
-		di.type = z.type = types[TINT64];
-		p = gins(AMOVQ, &z, &di);
-		p->to.scale = 1;
-		p->to.offset = c-8;
-	} else if(c >= 4) {
-		di.op = OINDREG;
-		di.type = z.type = types[TINT32];
-		p = gins(AMOVL, &z, &di);
-		if(c > 4) {
-			p = gins(AMOVL, &z, &di);
-			p->to.scale = 1;
-			p->to.offset = c-4;
-		}
-	} else
-	while(c > 0) {
-		gins(ASTOSB, N, N);	// STOB AL,*(DI)+
-		c--;
-	}
-
-	restx(&n1, &oldn1);
-	restx(&ax, &oldax);
-}
-
-// Called after regopt and peep have run.
-// Expand CHECKNIL pseudo-op into actual nil pointer check.
-void
-expandchecks(Prog *firstp)
-{
-	Prog *p, *p1, *p2;
-
-	for(p = firstp; p != P; p = p->link) {
-		if(p->as != ACHECKNIL)
-			continue;
-		if(debug_checknil && p->lineno > 1) // p->lineno==1 in generated wrappers
-			warnl(p->lineno, "generated nil check");
-		// check is
-		//	CMP arg, $0
-		//	JNE 2(PC) (likely)
-		//	MOV AX, 0
-		p1 = mal(sizeof *p1);
-		p2 = mal(sizeof *p2);
-		clearp(p1);
-		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 = cmpptr;
-		p->to.type = D_CONST;
-		p->to.offset = 0;
-		p1->as = AJNE;
-		p1->from.type = D_CONST;
-		p1->from.offset = 1; // likely
-		p1->to.type = D_BRANCH;
-		p1->to.u.branch = 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 = AMOVL;
-		p2->from.type = D_AX;
-		if(regtyp(&p->from))
-			p2->to.type = p->from.type + D_INDIR;
-		else
-			p2->to.type = D_INDIR+D_NONE;
-		p2->to.offset = 0;
-	}
-}
diff --git a/src/cmd/6g/gobj.c b/src/cmd/6g/gobj.c
deleted file mode 100644
index 04e837b..0000000
--- a/src/cmd/6g/gobj.c
+++ /dev/null
@@ -1,235 +0,0 @@
-// Derived from Inferno utils/6c/swt.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/swt.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include <u.h>
-#include <libc.h>
-#include "gg.h"
-
-int
-dsname(Sym *s, int off, char *t, int n)
-{
-	Prog *p;
-
-	p = gins(ADATA, N, N);
-	p->from.type = D_EXTERN;
-	p->from.index = D_NONE;
-	p->from.offset = off;
-	p->from.scale = n;
-	p->from.sym = linksym(s);
-	
-	p->to.type = D_SCONST;
-	p->to.index = D_NONE;
-	memmove(p->to.u.sval, t, n);
-	return off + n;
-}
-
-/*
- * make a refer to the data s, s+len
- * emitting DATA if needed.
- */
-void
-datastring(char *s, int len, Addr *a)
-{
-	Sym *sym;
-	
-	sym = stringsym(s, len);
-	a->type = D_EXTERN;
-	a->sym = linksym(sym);
-	a->node = sym->def;
-	a->offset = widthptr+widthint;  // skip header
-	a->etype = simtype[TINT];
-}
-
-/*
- * make a refer to the string sval,
- * emitting DATA if needed.
- */
-void
-datagostring(Strlit *sval, Addr *a)
-{
-	Sym *sym;
-
-	sym = stringsym(sval->s, sval->len);
-	a->type = D_EXTERN;
-	a->sym = linksym(sym);
-	a->node = sym->def;
-	a->offset = 0;  // header
-	a->etype = TINT32;
-}
-
-void
-gdata(Node *nam, Node *nr, int wid)
-{
-	Prog *p;
-
-	if(nr->op == OLITERAL) {
-		switch(nr->val.ctype) {
-		case CTCPLX:
-			gdatacomplex(nam, nr->val.u.cval);
-			return;
-		case CTSTR:
-			gdatastring(nam, nr->val.u.sval);
-			return;
-		}
-	}
-	p = gins(ADATA, nam, nr);
-	p->from.scale = wid;
-}
-
-void
-gdatacomplex(Node *nam, Mpcplx *cval)
-{
-	Prog *p;
-	int w;
-
-	w = cplxsubtype(nam->type->etype);
-	w = types[w]->width;
-
-	p = gins(ADATA, nam, N);
-	p->from.scale = w;
-	p->to.type = D_FCONST;
-	p->to.u.dval = mpgetflt(&cval->real);
-
-	p = gins(ADATA, nam, N);
-	p->from.scale = w;
-	p->from.offset += w;
-	p->to.type = D_FCONST;
-	p->to.u.dval = mpgetflt(&cval->imag);
-}
-
-void
-gdatastring(Node *nam, Strlit *sval)
-{
-	Prog *p;
-	Node nod1;
-
-	p = gins(ADATA, nam, N);
-	datastring(sval->s, sval->len, &p->to);
-	p->from.scale = types[tptr]->width;
-	p->to.index = p->to.type;
-	p->to.type = D_ADDR;
-//print("%P\n", p);
-
-	nodconst(&nod1, types[TINT], sval->len);
-	p = gins(ADATA, nam, &nod1);
-	p->from.scale = widthint;
-	p->from.offset += widthptr;
-}
-
-int
-dstringptr(Sym *s, int off, char *str)
-{
-	Prog *p;
-
-	off = rnd(off, widthptr);
-	p = gins(ADATA, N, N);
-	p->from.type = D_EXTERN;
-	p->from.index = D_NONE;
-	p->from.sym = linksym(s);
-	p->from.offset = off;
-	p->from.scale = widthptr;
-
-	datastring(str, strlen(str)+1, &p->to);
-	p->to.index = p->to.type;
-	p->to.type = D_ADDR;
-	p->to.etype = simtype[TINT];
-	off += widthptr;
-
-	return off;
-}
-
-int
-dgostrlitptr(Sym *s, int off, Strlit *lit)
-{
-	Prog *p;
-
-	if(lit == nil)
-		return duintptr(s, off, 0);
-
-	off = rnd(off, widthptr);
-	p = gins(ADATA, N, N);
-	p->from.type = D_EXTERN;
-	p->from.index = D_NONE;
-	p->from.sym = linksym(s);
-	p->from.offset = off;
-	p->from.scale = widthptr;
-	datagostring(lit, &p->to);
-	p->to.index = p->to.type;
-	p->to.type = D_ADDR;
-	p->to.etype = simtype[TINT];
-	off += widthptr;
-
-	return off;
-}
-
-int
-dgostringptr(Sym *s, int off, char *str)
-{
-	int n;
-	Strlit *lit;
-
-	if(str == nil)
-		return duintptr(s, off, 0);
-
-	n = strlen(str);
-	lit = mal(sizeof *lit + n);
-	strcpy(lit->s, str);
-	lit->len = n;
-	return dgostrlitptr(s, off, lit);
-}
-
-int
-dsymptr(Sym *s, int off, Sym *x, int xoff)
-{
-	Prog *p;
-
-	off = rnd(off, widthptr);
-
-	p = gins(ADATA, N, N);
-	p->from.type = D_EXTERN;
-	p->from.index = D_NONE;
-	p->from.sym = linksym(s);
-	p->from.offset = off;
-	p->from.scale = widthptr;
-	p->to.type = D_ADDR;
-	p->to.index = D_EXTERN;
-	p->to.sym = linksym(x);
-	p->to.offset = xoff;
-	off += widthptr;
-
-	return off;
-}
-
-void
-nopout(Prog *p)
-{
-	p->as = ANOP;
-}
-
diff --git a/src/cmd/6g/gsubr.c b/src/cmd/6g/gsubr.c
deleted file mode 100644
index 5bd9246..0000000
--- a/src/cmd/6g/gsubr.c
+++ /dev/null
@@ -1,2296 +0,0 @@
-// 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 at 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 at 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.
-
-#include <u.h>
-#include <libc.h>
-#include "gg.h"
-#include "../../runtime/funcdata.h"
-
-// 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.
-vlong unmappedzero = 4096;
-
-void
-clearp(Prog *p)
-{
-	p->as = AEND;
-	p->from.type = D_NONE;
-	p->from.index = D_NONE;
-	p->to.type = D_NONE;
-	p->to.index = D_NONE;
-	p->pc = pcloc;
-	pcloc++;
-}
-
-static int ddumped;
-static Prog *dfirst;
-static Prog *dpc;
-
-/*
- * generate and return proc with p->as = as,
- * linked into program. pc is next instruction.
- */
-Prog*
-prog(int as)
-{
-	Prog *p;
-
-	if(as == ADATA || as == AGLOBL) {
-		if(ddumped)
-			fatal("already dumped data");
-		if(dpc == nil) {
-			dpc = mal(sizeof(*dpc));
-			dfirst = dpc;
-		}
-		p = dpc;
-		dpc = mal(sizeof(*dpc));
-		p->link = dpc;
-	} else {
-		p = pc;
-		pc = mal(sizeof(*pc));
-		clearp(pc);
-		p->link = pc;
-	}
-
-	if(lineno == 0) {
-		if(debug['K'])
-			warn("prog: line 0");
-	}
-
-	p->as = as;
-	p->lineno = lineno;
-	return p;
-}
-
-void
-dumpdata(void)
-{
-	ddumped = 1;
-	if(dfirst == nil)
-		return;
-	newplist();
-	*pc = *dfirst;
-	pc = dpc;
-	clearp(pc);
-}
-
-/*
- * generate a branch.
- * t is ignored.
- * likely values are for branch prediction:
- *	-1 unlikely
- *	0 no opinion
- *	+1 likely
- */
-Prog*
-gbranch(int as, Type *t, int likely)
-{
-	Prog *p;
-	
-	USED(t);
-
-	p = prog(as);
-	p->to.type = D_BRANCH;
-	p->to.u.branch = P;
-	if(as != AJMP && likely != 0) {
-		p->from.type = D_CONST;
-		p->from.offset = likely > 0;
-	}
-	return p;
-}
-
-/*
- * patch previous branch to jump to to.
- */
-void
-patch(Prog *p, Prog *to)
-{
-	if(p->to.type != D_BRANCH)
-		fatal("patch: not a branch");
-	p->to.u.branch = to;
-	p->to.offset = to->pc;
-}
-
-Prog*
-unpatch(Prog *p)
-{
-	Prog *q;
-
-	if(p->to.type != D_BRANCH)
-		fatal("unpatch: not a branch");
-	q = p->to.u.branch;
-	p->to.u.branch = P;
-	p->to.offset = 0;
-	return q;
-}
-
-/*
- * start a new Prog list.
- */
-Plist*
-newplist(void)
-{
-	Plist *pl;
-
-	pl = linknewplist(ctxt);
-
-	pc = mal(sizeof(*pc));
-	clearp(pc);
-	pl->firstpc = pc;
-
-	return pl;
-}
-
-void
-gused(Node *n)
-{
-	gins(ANOP, n, N);	// used
-}
-
-Prog*
-gjmp(Prog *to)
-{
-	Prog *p;
-
-	p = gbranch(AJMP, T, 0);
-	if(to != P)
-		patch(p, to);
-	return p;
-}
-
-void
-ggloblnod(Node *nam)
-{
-	Prog *p;
-
-	p = gins(AGLOBL, nam, N);
-	p->lineno = nam->lineno;
-	p->from.sym->gotype = linksym(ngotype(nam));
-	p->to.sym = nil;
-	p->to.type = D_CONST;
-	p->to.offset = nam->type->width;
-	if(nam->readonly)
-		p->from.scale = RODATA;
-	if(nam->type != T && !haspointers(nam->type))
-		p->from.scale |= NOPTR;
-}
-
-void
-gtrack(Sym *s)
-{
-	Prog *p;
-	
-	p = gins(AUSEFIELD, N, N);
-	p->from.type = D_EXTERN;
-	p->from.index = D_NONE;
-	p->from.sym = linksym(s);
-}
-
-void
-ggloblsym(Sym *s, int32 width, int8 flags)
-{
-	Prog *p;
-
-	p = gins(AGLOBL, N, N);
-	p->from.type = D_EXTERN;
-	p->from.index = D_NONE;
-	p->from.sym = linksym(s);
-	p->to.type = D_CONST;
-	p->to.index = D_NONE;
-	p->to.offset = width;
-	p->from.scale = flags;
-}
-
-int
-isfat(Type *t)
-{
-	if(t != T)
-	switch(t->etype) {
-	case TSTRUCT:
-	case TARRAY:
-	case TSTRING:
-	case TINTER:	// maybe remove later
-		return 1;
-	}
-	return 0;
-}
-
-/*
- * naddr of func generates code for address of func.
- * if using opcode that can take address implicitly,
- * call afunclit to fix up the argument.
- */
-void
-afunclit(Addr *a, Node *n)
-{
-	if(a->type == D_ADDR && a->index == D_EXTERN) {
-		a->type = D_EXTERN;
-		a->index = D_NONE;
-		a->sym = linksym(n->sym);
-	}
-}
-
-static	int	resvd[] =
-{
-	D_DI,	// for movstring
-	D_SI,	// for movstring
-
-	D_AX,	// for divide
-	D_CX,	// for shift
-	D_DX,	// for divide
-	D_SP,	// for stack
-};
-
-void
-ginit(void)
-{
-	int i;
-
-	for(i=0; i<nelem(reg); i++)
-		reg[i] = 1;
-	for(i=D_AX; i<=D_R15; i++)
-		reg[i] = 0;
-	for(i=D_X0; i<=D_X15; i++)
-		reg[i] = 0;
-
-	for(i=0; i<nelem(resvd); i++)
-		reg[resvd[i]]++;
-	
-	if(nacl) {
-		reg[D_BP]++;
-		reg[D_R15]++;
-	}
-}
-
-void
-gclean(void)
-{
-	int i;
-
-	for(i=0; i<nelem(resvd); i++)
-		reg[resvd[i]]--;
-	if(nacl) {
-		reg[D_BP]--;
-		reg[D_R15]--;
-	}
-
-
-	for(i=D_AX; i<=D_R15; i++)
-		if(reg[i])
-			yyerror("reg %R left allocated\n", i);
-	for(i=D_X0; i<=D_X15; i++)
-		if(reg[i])
-			yyerror("reg %R left allocated\n", i);
-}
-
-int32
-anyregalloc(void)
-{
-	int i, j;
-
-	for(i=D_AX; i<=D_R15; i++) {
-		if(reg[i] == 0)
-			goto ok;
-		for(j=0; j<nelem(resvd); j++)
-			if(resvd[j] == i)
-				goto ok;
-		return 1;
-	ok:;
-	}
-	return 0;
-}
-
-static	uintptr	regpc[D_R15+1 - D_AX];
-
-/*
- * allocate register of type t, leave in n.
- * if o != N, o is desired fixed register.
- * caller must regfree(n).
- */
-void
-regalloc(Node *n, Type *t, Node *o)
-{
-	int i, et;
-
-	if(t == T)
-		fatal("regalloc: t nil");
-	et = simtype[t->etype];
-
-	switch(et) {
-	case TINT8:
-	case TUINT8:
-	case TINT16:
-	case TUINT16:
-	case TINT32:
-	case TUINT32:
-	case TINT64:
-	case TUINT64:
-	case TPTR32:
-	case TPTR64:
-	case TBOOL:
-		if(o != N && o->op == OREGISTER) {
-			i = o->val.u.reg;
-			if(i >= D_AX && i <= D_R15)
-				goto out;
-		}
-		for(i=D_AX; i<=D_R15; i++)
-			if(reg[i] == 0) {
-				regpc[i-D_AX] = (uintptr)getcallerpc(&n);
-				goto out;
-			}
-
-		flusherrors();
-		for(i=0; i+D_AX<=D_R15; i++)
-			print("%d %p\n", i, regpc[i]);
-		fatal("out of fixed registers");
-
-	case TFLOAT32:
-	case TFLOAT64:
-		if(o != N && o->op == OREGISTER) {
-			i = o->val.u.reg;
-			if(i >= D_X0 && i <= D_X15)
-				goto out;
-		}
-		for(i=D_X0; i<=D_X15; i++)
-			if(reg[i] == 0)
-				goto out;
-		fatal("out of floating registers");
-
-	case TCOMPLEX64:
-	case TCOMPLEX128:
-		tempname(n, t);
-		return;
-	}
-	fatal("regalloc: unknown type %T", t);
-	return;
-
-out:
-	reg[i]++;
-	nodreg(n, t, i);
-}
-
-void
-regfree(Node *n)
-{
-	int i;
-
-	if(n->op == ONAME)
-		return;
-	if(n->op != OREGISTER && n->op != OINDREG)
-		fatal("regfree: not a register");
-	i = n->val.u.reg;
-	if(i == D_SP)
-		return;
-	if(i < 0 || i >= nelem(reg))
-		fatal("regfree: reg out of range");
-	if(reg[i] <= 0)
-		fatal("regfree: reg not allocated");
-	reg[i]--;
-	if(reg[i] == 0 && D_AX <= i && i <= D_R15)
-		regpc[i - D_AX] = 0;
-}
-
-/*
- * initialize n to be register r of type t.
- */
-void
-nodreg(Node *n, Type *t, int r)
-{
-	if(t == T)
-		fatal("nodreg: t nil");
-
-	memset(n, 0, sizeof(*n));
-	n->op = OREGISTER;
-	n->addable = 1;
-	ullmancalc(n);
-	n->val.u.reg = r;
-	n->type = t;
-}
-
-/*
- * initialize n to be indirect of register r; n is type t.
- */
-void
-nodindreg(Node *n, Type *t, int r)
-{
-	nodreg(n, t, r);
-	n->op = OINDREG;
-}
-
-Node*
-nodarg(Type *t, int fp)
-{
-	Node *n;
-	NodeList *l;
-	Type *first;
-	Iter savet;
-
-	// entire argument struct, not just one arg
-	if(t->etype == TSTRUCT && t->funarg) {
-		n = nod(ONAME, N, N);
-		n->sym = lookup(".args");
-		n->type = t;
-		first = structfirst(&savet, &t);
-		if(first == nil)
-			fatal("nodarg: bad struct");
-		if(first->width == BADWIDTH)
-			fatal("nodarg: offset not computed for %T", t);
-		n->xoffset = first->width;
-		n->addable = 1;
-		goto fp;
-	}
-
-	if(t->etype != TFIELD)
-		fatal("nodarg: not field %T", t);
-	
-	if(fp == 1) {
-		for(l=curfn->dcl; l; l=l->next) {
-			n = l->n;
-			if((n->class == PPARAM || n->class == PPARAMOUT) && !isblanksym(t->sym) && n->sym == t->sym)
-				return n;
-		}
-	}
-
-	n = nod(ONAME, N, N);
-	n->type = t->type;
-	n->sym = t->sym;
-	
-	if(t->width == BADWIDTH)
-		fatal("nodarg: offset not computed for %T", t);
-	n->xoffset = t->width;
-	n->addable = 1;
-	n->orig = t->nname;
-
-fp:
-	// Rewrite argument named _ to __,
-	// or else the assignment to _ will be
-	// discarded during code generation.
-	if(isblank(n))
-		n->sym = lookup("__");
-
-	switch(fp) {
-	case 0:		// output arg
-		n->op = OINDREG;
-		n->val.u.reg = D_SP;
-		break;
-
-	case 1:		// input arg
-		n->class = PPARAM;
-		break;
-
-	case 2:		// offset output arg
-fatal("shouldn't be used");
-		n->op = OINDREG;
-		n->val.u.reg = D_SP;
-		n->xoffset += types[tptr]->width;
-		break;
-	}
-	n->typecheck = 1;
-	return n;
-}
-
-/*
- * generate
- *	as $c, reg
- */
-void
-gconreg(int as, vlong c, int reg)
-{
-	Node nr;
-
-	switch(as) {
-	case AADDL:
-	case AMOVL:
-	case ALEAL:
-		nodreg(&nr, types[TINT32], reg);
-		break;
-	default:
-		nodreg(&nr, types[TINT64], reg);
-	}
-
-	ginscon(as, c, &nr);
-}
-
-/*
- * generate
- *	as $c, n
- */
-void
-ginscon(int as, vlong c, Node *n2)
-{
-	Node n1, ntmp;
-
-	switch(as) {
-	case AADDL:
-	case AMOVL:
-	case ALEAL:
-		nodconst(&n1, types[TINT32], c);
-		break;
-	default:
-		nodconst(&n1, types[TINT64], c);
-	}
-
-	if(as != AMOVQ && (c < -(1LL<<31) || c >= 1LL<<31)) {
-		// cannot have 64-bit immediate in ADD, etc.
-		// instead, MOV into register first.
-		regalloc(&ntmp, types[TINT64], N);
-		gins(AMOVQ, &n1, &ntmp);
-		gins(as, &ntmp, n2);
-		regfree(&ntmp);
-		return;
-	}
-	gins(as, &n1, n2);
-}
-
-#define	CASE(a,b)	(((a)<<16)|((b)<<0))
-/*c2go int CASE(int, int); */
-
-/*
- * Is this node a memory operand?
- */
-int
-ismem(Node *n)
-{
-	switch(n->op) {
-	case OITAB:
-	case OSPTR:
-	case OLEN:
-	case OCAP:
-	case OINDREG:
-	case ONAME:
-	case OPARAM:
-	case OCLOSUREVAR:
-	case OADDR:
-		return 1;
-	}
-	return 0;
-}
-
-/*
- * set up nodes representing 2^63
- */
-Node bigi;
-Node bigf;
-
-void
-bignodes(void)
-{
-	static int did;
-
-	if(did)
-		return;
-	did = 1;
-
-	nodconst(&bigi, types[TUINT64], 1);
-	mpshiftfix(bigi.val.u.xval, 63);
-
-	bigf = bigi;
-	bigf.type = types[TFLOAT64];
-	bigf.val.ctype = CTFLT;
-	bigf.val.u.fval = mal(sizeof *bigf.val.u.fval);
-	mpmovefixflt(bigf.val.u.fval, bigi.val.u.xval);
-}
-
-/*
- * generate move:
- *	t = f
- * hard part is conversions.
- */
-// TODO: lost special constants for floating point.  XORPD for 0.0?
-void
-gmove(Node *f, Node *t)
-{
-	int a, ft, tt;
-	Type *cvt;
-	Node r1, r2, r3, r4, zero, one, con;
-	Prog *p1, *p2;
-
-	if(debug['M'])
-		print("gmove %lN -> %lN\n", f, t);
-
-	ft = simsimtype(f->type);
-	tt = simsimtype(t->type);
-	cvt = t->type;
-
-	if(iscomplex[ft] || iscomplex[tt]) {
-		complexmove(f, t);
-		return;
-	}
-
-	// cannot have two memory operands
-	if(ismem(f) && ismem(t))
-		goto hard;
-
-	// convert constant to desired type
-	if(f->op == OLITERAL) {
-		convconst(&con, t->type, &f->val);
-		f = &con;
-		ft = tt;	// so big switch will choose a simple mov
-
-		// some constants can't move directly to memory.
-		if(ismem(t)) {
-			// float constants come from memory.
-			if(isfloat[tt])
-				goto hard;
-
-			// 64-bit immediates are really 32-bit sign-extended
-			// unless moving into a register.
-			if(isint[tt]) {
-				if(mpcmpfixfix(con.val.u.xval, minintval[TINT32]) < 0)
-					goto hard;
-				if(mpcmpfixfix(con.val.u.xval, maxintval[TINT32]) > 0)
-					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(CASE(ft, tt)) {
-	default:
-		fatal("gmove %lT -> %lT", f->type, t->type);
-
-	/*
-	 * integer copy and truncate
-	 */
-	case CASE(TINT8, TINT8):	// same size
-	case CASE(TINT8, TUINT8):
-	case CASE(TUINT8, TINT8):
-	case CASE(TUINT8, TUINT8):
-	case CASE(TINT16, TINT8):	// truncate
-	case CASE(TUINT16, TINT8):
-	case CASE(TINT32, TINT8):
-	case CASE(TUINT32, TINT8):
-	case CASE(TINT64, TINT8):
-	case CASE(TUINT64, TINT8):
-	case CASE(TINT16, TUINT8):
-	case CASE(TUINT16, TUINT8):
-	case CASE(TINT32, TUINT8):
-	case CASE(TUINT32, TUINT8):
-	case CASE(TINT64, TUINT8):
-	case CASE(TUINT64, TUINT8):
-		a = AMOVB;
-		break;
-
-	case CASE(TINT16, TINT16):	// same size
-	case CASE(TINT16, TUINT16):
-	case CASE(TUINT16, TINT16):
-	case CASE(TUINT16, TUINT16):
-	case CASE(TINT32, TINT16):	// truncate
-	case CASE(TUINT32, TINT16):
-	case CASE(TINT64, TINT16):
-	case CASE(TUINT64, TINT16):
-	case CASE(TINT32, TUINT16):
-	case CASE(TUINT32, TUINT16):
-	case CASE(TINT64, TUINT16):
-	case CASE(TUINT64, TUINT16):
-		a = AMOVW;
-		break;
-
-	case CASE(TINT32, TINT32):	// same size
-	case CASE(TINT32, TUINT32):
-	case CASE(TUINT32, TINT32):
-	case CASE(TUINT32, TUINT32):
-		a = AMOVL;
-		break;
-
-	case CASE(TINT64, TINT32):	// truncate
-	case CASE(TUINT64, TINT32):
-	case CASE(TINT64, TUINT32):
-	case CASE(TUINT64, TUINT32):
-		a = AMOVQL;
-		break;
-
-	case CASE(TINT64, TINT64):	// same size
-	case CASE(TINT64, TUINT64):
-	case CASE(TUINT64, TINT64):
-	case CASE(TUINT64, TUINT64):
-		a = AMOVQ;
-		break;
-
-	/*
-	 * integer up-conversions
-	 */
-	case CASE(TINT8, TINT16):	// sign extend int8
-	case CASE(TINT8, TUINT16):
-		a = AMOVBWSX;
-		goto rdst;
-	case CASE(TINT8, TINT32):
-	case CASE(TINT8, TUINT32):
-		a = AMOVBLSX;
-		goto rdst;
-	case CASE(TINT8, TINT64):
-	case CASE(TINT8, TUINT64):
-		a = AMOVBQSX;
-		goto rdst;
-
-	case CASE(TUINT8, TINT16):	// zero extend uint8
-	case CASE(TUINT8, TUINT16):
-		a = AMOVBWZX;
-		goto rdst;
-	case CASE(TUINT8, TINT32):
-	case CASE(TUINT8, TUINT32):
-		a = AMOVBLZX;
-		goto rdst;
-	case CASE(TUINT8, TINT64):
-	case CASE(TUINT8, TUINT64):
-		a = AMOVBQZX;
-		goto rdst;
-
-	case CASE(TINT16, TINT32):	// sign extend int16
-	case CASE(TINT16, TUINT32):
-		a = AMOVWLSX;
-		goto rdst;
-	case CASE(TINT16, TINT64):
-	case CASE(TINT16, TUINT64):
-		a = AMOVWQSX;
-		goto rdst;
-
-	case CASE(TUINT16, TINT32):	// zero extend uint16
-	case CASE(TUINT16, TUINT32):
-		a = AMOVWLZX;
-		goto rdst;
-	case CASE(TUINT16, TINT64):
-	case CASE(TUINT16, TUINT64):
-		a = AMOVWQZX;
-		goto rdst;
-
-	case CASE(TINT32, TINT64):	// sign extend int32
-	case CASE(TINT32, TUINT64):
-		a = AMOVLQSX;
-		goto rdst;
-
-	case CASE(TUINT32, TINT64):	// zero extend uint32
-	case CASE(TUINT32, TUINT64):
-		// AMOVL into a register zeros the top of the register,
-		// so this is not always necessary, but if we rely on AMOVL
-		// the optimizer is almost certain to screw with us.
-		a = AMOVLQZX;
-		goto rdst;
-
-	/*
-	* float to integer
-	*/
-	case CASE(TFLOAT32, TINT32):
-		a = ACVTTSS2SL;
-		goto rdst;
-
-	case CASE(TFLOAT64, TINT32):
-		a = ACVTTSD2SL;
-		goto rdst;
-
-	case CASE(TFLOAT32, TINT64):
-		a = ACVTTSS2SQ;
-		goto rdst;
-
-	case CASE(TFLOAT64, TINT64):
-		a = ACVTTSD2SQ;
-		goto rdst;
-
-	case CASE(TFLOAT32, TINT16):
-	case CASE(TFLOAT32, TINT8):
-	case CASE(TFLOAT32, TUINT16):
-	case CASE(TFLOAT32, TUINT8):
-	case CASE(TFLOAT64, TINT16):
-	case CASE(TFLOAT64, TINT8):
-	case CASE(TFLOAT64, TUINT16):
-	case CASE(TFLOAT64, TUINT8):
-		// convert via int32.
-		cvt = types[TINT32];
-		goto hard;
-
-	case CASE(TFLOAT32, TUINT32):
-	case CASE(TFLOAT64, TUINT32):
-		// convert via int64.
-		cvt = types[TINT64];
-		goto hard;
-
-	case CASE(TFLOAT32, TUINT64):
-	case CASE(TFLOAT64, TUINT64):
-		// algorithm is:
-		//	if small enough, use native float64 -> int64 conversion.
-		//	otherwise, subtract 2^63, convert, and add it back.
-		a = ACVTTSS2SQ;
-		if(ft == TFLOAT64)
-			a = ACVTTSD2SQ;
-		bignodes();
-		regalloc(&r1, types[ft], N);
-		regalloc(&r2, types[tt], t);
-		regalloc(&r3, types[ft], N);
-		regalloc(&r4, types[tt], N);
-		gins(optoas(OAS, f->type), f, &r1);
-		gins(optoas(OCMP, f->type), &bigf, &r1);
-		p1 = gbranch(optoas(OLE, f->type), T, +1);
-		gins(a, &r1, &r2);
-		p2 = gbranch(AJMP, T, 0);
-		patch(p1, pc);
-		gins(optoas(OAS, f->type), &bigf, &r3);
-		gins(optoas(OSUB, f->type), &r3, &r1);
-		gins(a, &r1, &r2);
-		gins(AMOVQ, &bigi, &r4);
-		gins(AXORQ, &r4, &r2);
-		patch(p2, pc);
-		gmove(&r2, t);
-		regfree(&r4);
-		regfree(&r3);
-		regfree(&r2);
-		regfree(&r1);
-		return;
-
-	/*
-	 * integer to float
-	 */
-	case CASE(TINT32, TFLOAT32):
-		a = ACVTSL2SS;
-		goto rdst;
-
-
-	case CASE(TINT32, TFLOAT64):
-		a = ACVTSL2SD;
-		goto rdst;
-
-	case CASE(TINT64, TFLOAT32):
-		a = ACVTSQ2SS;
-		goto rdst;
-
-	case CASE(TINT64, TFLOAT64):
-		a = ACVTSQ2SD;
-		goto rdst;
-
-	case CASE(TINT16, TFLOAT32):
-	case CASE(TINT16, TFLOAT64):
-	case CASE(TINT8, TFLOAT32):
-	case CASE(TINT8, TFLOAT64):
-	case CASE(TUINT16, TFLOAT32):
-	case CASE(TUINT16, TFLOAT64):
-	case CASE(TUINT8, TFLOAT32):
-	case CASE(TUINT8, TFLOAT64):
-		// convert via int32
-		cvt = types[TINT32];
-		goto hard;
-
-	case CASE(TUINT32, TFLOAT32):
-	case CASE(TUINT32, TFLOAT64):
-		// convert via int64.
-		cvt = types[TINT64];
-		goto hard;
-
-	case CASE(TUINT64, TFLOAT32):
-	case CASE(TUINT64, TFLOAT64):
-		// algorithm is:
-		//	if small enough, use native int64 -> uint64 conversion.
-		//	otherwise, halve (rounding to odd?), convert, and double.
-		a = ACVTSQ2SS;
-		if(tt == TFLOAT64)
-			a = ACVTSQ2SD;
-		nodconst(&zero, types[TUINT64], 0);
-		nodconst(&one, types[TUINT64], 1);
-		regalloc(&r1, f->type, f);
-		regalloc(&r2, t->type, t);
-		regalloc(&r3, f->type, N);
-		regalloc(&r4, f->type, N);
-		gmove(f, &r1);
-		gins(ACMPQ, &r1, &zero);
-		p1 = gbranch(AJLT, T, +1);
-		gins(a, &r1, &r2);
-		p2 = gbranch(AJMP, T, 0);
-		patch(p1, pc);
-		gmove(&r1, &r3);
-		gins(ASHRQ, &one, &r3);
-		gmove(&r1, &r4);
-		gins(AANDL, &one, &r4);
-		gins(AORQ, &r4, &r3);
-		gins(a, &r3, &r2);
-		gins(optoas(OADD, t->type), &r2, &r2);
-		patch(p2, pc);
-		gmove(&r2, t);
-		regfree(&r4);
-		regfree(&r3);
-		regfree(&r2);
-		regfree(&r1);
-		return;
-
-	/*
-	 * float to float
-	 */
-	case CASE(TFLOAT32, TFLOAT32):
-		a = AMOVSS;
-		break;
-
-	case CASE(TFLOAT64, TFLOAT64):
-		a = AMOVSD;
-		break;
-
-	case CASE(TFLOAT32, TFLOAT64):
-		a = ACVTSS2SD;
-		goto rdst;
-
-	case CASE(TFLOAT64, TFLOAT32):
-		a = ACVTSD2SS;
-		goto rdst;
-	}
-
-	gins(a, f, t);
-	return;
-
-rdst:
-	// requires register destination
-	regalloc(&r1, t->type, t);
-	gins(a, f, &r1);
-	gmove(&r1, t);
-	regfree(&r1);
-	return;
-
-hard:
-	// requires register intermediate
-	regalloc(&r1, cvt, t);
-	gmove(f, &r1);
-	gmove(&r1, t);
-	regfree(&r1);
-	return;
-}
-
-int
-samaddr(Node *f, Node *t)
-{
-
-	if(f->op != t->op)
-		return 0;
-
-	switch(f->op) {
-	case OREGISTER:
-		if(f->val.u.reg != t->val.u.reg)
-			break;
-		return 1;
-	}
-	return 0;
-}
-
-/*
- * generate one instruction:
- *	as f, t
- */
-Prog*
-gins(int as, Node *f, Node *t)
-{
-//	Node nod;
-	int32 w;
-	Prog *p;
-	Addr af, at;
-
-//	if(f != N && f->op == OINDEX) {
-//		regalloc(&nod, &regnode, Z);
-//		v = constnode.vconst;
-//		cgen(f->right, &nod);
-//		constnode.vconst = v;
-//		idx.reg = nod.reg;
-//		regfree(&nod);
-//	}
-//	if(t != N && t->op == OINDEX) {
-//		regalloc(&nod, &regnode, Z);
-//		v = constnode.vconst;
-//		cgen(t->right, &nod);
-//		constnode.vconst = v;
-//		idx.reg = nod.reg;
-//		regfree(&nod);
-//	}
-
-	switch(as) {
-	case AMOVB:
-	case AMOVW:
-	case AMOVL:
-	case AMOVQ:
-	case AMOVSS:
-	case AMOVSD:
-		if(f != N && t != N && samaddr(f, t))
-			return nil;
-		break;
-	
-	case ALEAQ:
-		if(f != N && isconst(f, CTNIL)) {
-			fatal("gins LEAQ nil %T", f->type);
-		}
-		break;
-	}
-
-	memset(&af, 0, sizeof af);
-	memset(&at, 0, sizeof at);
-	if(f != N)
-		naddr(f, &af, 1);
-	if(t != N)
-		naddr(t, &at, 1);
-	p = prog(as);
-	if(f != N)
-		p->from = af;
-	if(t != N)
-		p->to = at;
-	if(debug['g'])
-		print("%P\n", p);
-
-	w = 0;
-	switch(as) {
-	case AMOVB:
-		w = 1;
-		break;
-	case AMOVW:
-		w = 2;
-		break;
-	case AMOVL:
-		w = 4;
-		break;
-	case AMOVQ:
-		w = 8;
-		break;
-	}
-	if(w != 0 && ((f != N && af.width < w) || (t != N && at.width > w))) {
-		dump("f", f);
-		dump("t", t);
-		fatal("bad width: %P (%d, %d)\n", p, af.width, at.width);
-	}
-
-	return p;
-}
-
-void
-fixlargeoffset(Node *n)
-{
-	Node a;
-
-	if(n == N)
-		return;
-	if(n->op != OINDREG)
-		return;
-	if(n->val.u.reg == D_SP) // stack offset cannot be large
-		return;
-	if(n->xoffset != (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);
-		ginscon(optoas(OADD, types[tptr]), n->xoffset, &a);
-		n->xoffset = 0;
-	}
-}
-
-/*
- * generate code to compute n;
- * make a refer to result.
- */
-void
-naddr(Node *n, Addr *a, int canemitcode)
-{
-	Sym *s;
-
-	a->scale = 0;
-	a->index = D_NONE;
-	a->type = D_NONE;
-	a->gotype = nil;
-	a->node = N;
-	a->width = 0;
-	if(n == N)
-		return;
-
-	if(n->type != T && n->type->etype != TIDEAL) {
-		dowidth(n->type);
-		a->width = n->type->width;
-	}
-
-	switch(n->op) {
-	default:
-		fatal("naddr: bad %O %D", n->op, a);
-		break;
-
-	case OREGISTER:
-		a->type = n->val.u.reg;
-		a->sym = nil;
-		break;
-
-//	case OINDEX:
-//	case OIND:
-//		naddr(n->left, a);
-//		if(a->type >= D_AX && a->type <= D_DI)
-//			a->type += D_INDIR;
-//		else
-//		if(a->type == D_CONST)
-//			a->type = D_NONE+D_INDIR;
-//		else
-//		if(a->type == D_ADDR) {
-//			a->type = a->index;
-//			a->index = D_NONE;
-//		} else
-//			goto bad;
-//		if(n->op == OINDEX) {
-//			a->index = idx.reg;
-//			a->scale = n->scale;
-//		}
-//		break;
-
-	case OINDREG:
-		a->type = n->val.u.reg+D_INDIR;
-		a->sym = linksym(n->sym);
-		a->offset = n->xoffset;
-		if(a->offset != (int32)a->offset)
-			yyerror("offset %lld too large for OINDREG", a->offset);
-		break;
-
-	case OPARAM:
-		// n->left is PHEAP ONAME for stack parameter.
-		// compute address of actual parameter on stack.
-		a->etype = simtype[n->left->type->etype];
-		a->width = n->left->type->width;
-		a->offset = n->xoffset;
-		a->sym = linksym(n->left->sym);
-		a->type = D_PARAM;
-		a->node = n->left->orig;
-		break;
-	
-	case OCLOSUREVAR:
-		if(!curfn->needctxt)
-			fatal("closurevar without needctxt");
-		a->type = D_DX+D_INDIR;
-		a->sym = nil;
-		a->offset = n->xoffset;
-		break;
-	
-	case OCFUNC:
-		naddr(n->left, a, canemitcode);
-		a->sym = linksym(n->left->sym);
-		break;
-
-	case ONAME:
-		a->etype = 0;
-		if(n->type != T)
-			a->etype = simtype[n->type->etype];
-		a->offset = n->xoffset;
-		s = n->sym;
-		a->node = n->orig;
-		//if(a->node >= (Node*)&n)
-		//	fatal("stack node");
-		if(s == S)
-			s = lookup(".noname");
-		if(n->method) {
-			if(n->type != T)
-			if(n->type->sym != S)
-			if(n->type->sym->pkg != nil)
-				s = pkglookup(s->name, n->type->sym->pkg);
-		}
-
-		switch(n->class) {
-		default:
-			fatal("naddr: ONAME class %S %d\n", n->sym, n->class);
-		case PEXTERN:
-			a->type = D_EXTERN;
-			break;
-		case PAUTO:
-			a->type = D_AUTO;
-			break;
-		case PPARAM:
-		case PPARAMOUT:
-			a->type = D_PARAM;
-			break;
-		case PFUNC:
-			a->index = D_EXTERN;
-			a->type = D_ADDR;
-			a->width = widthptr;
-			s = funcsym(s);			
-			break;
-		}
-		a->sym = linksym(s);
-		break;
-
-	case OLITERAL:
-		switch(n->val.ctype) {
-		default:
-			fatal("naddr: const %lT", n->type);
-			break;
-		case CTFLT:
-			a->type = D_FCONST;
-			a->u.dval = mpgetflt(n->val.u.fval);
-			break;
-		case CTINT:
-		case CTRUNE:
-			a->sym = nil;
-			a->type = D_CONST;
-			a->offset = mpgetfix(n->val.u.xval);
-			break;
-		case CTSTR:
-			datagostring(n->val.u.sval, a);
-			break;
-		case CTBOOL:
-			a->sym = nil;
-			a->type = D_CONST;
-			a->offset = n->val.u.bval;
-			break;
-		case CTNIL:
-			a->sym = nil;
-			a->type = D_CONST;
-			a->offset = 0;
-			break;
-		}
-		break;
-
-	case OADDR:
-		naddr(n->left, a, canemitcode);
-		a->width = widthptr;
-		if(a->type >= D_INDIR) {
-			a->type -= D_INDIR;
-			break;
-		}
-		if(a->type == D_EXTERN || a->type == D_STATIC ||
-		   a->type == D_AUTO || a->type == D_PARAM)
-			if(a->index == D_NONE) {
-				a->index = a->type;
-				a->type = D_ADDR;
-				break;
-			}
-		fatal("naddr: OADDR\n");
-	
-	case OITAB:
-		// itable of interface value
-		naddr(n->left, a, canemitcode);
-		if(a->type == D_CONST && a->offset == 0)
-			break;  // itab(nil)
-		a->etype = tptr;
-		a->width = widthptr;
-		break;
-
-	case OSPTR:
-		// pointer in a string or slice
-		naddr(n->left, a, canemitcode);
-		if(a->type == D_CONST && a->offset == 0)
-			break;	// ptr(nil)
-		a->etype = simtype[tptr];
-		a->offset += Array_array;
-		a->width = widthptr;
-		break;
-
-	case OLEN:
-		// len of string or slice
-		naddr(n->left, a, canemitcode);
-		if(a->type == D_CONST && a->offset == 0)
-			break;	// len(nil)
-		a->etype = simtype[TUINT];
-		a->offset += Array_nel;
-		a->width = widthint;
-		break;
-
-	case OCAP:
-		// cap of string or slice
-		naddr(n->left, a, canemitcode);
-		if(a->type == D_CONST && a->offset == 0)
-			break;	// cap(nil)
-		a->etype = simtype[TUINT];
-		a->offset += Array_cap;
-		a->width = widthint;
-		break;
-
-//	case OADD:
-//		if(n->right->op == OLITERAL) {
-//			v = n->right->vconst;
-//			naddr(n->left, a, canemitcode);
-//		} else
-//		if(n->left->op == OLITERAL) {
-//			v = n->left->vconst;
-//			naddr(n->right, a, canemitcode);
-//		} else
-//			goto bad;
-//		a->offset += v;
-//		break;
-
-	}
-}
-
-/*
- * return Axxx for Oxxx on type t.
- */
-int
-optoas(int op, Type *t)
-{
-	int a;
-
-	if(t == T)
-		fatal("optoas: t is nil");
-
-	a = AGOK;
-	switch(CASE(op, simtype[t->etype])) {
-	default:
-		fatal("optoas: no entry %O-%T", op, t);
-		break;
-
-	case CASE(OADDR, TPTR32):
-		a = ALEAL;
-		break;
-
-	case CASE(OADDR, TPTR64):
-		a = ALEAQ;
-		break;
-
-	case CASE(OEQ, TBOOL):
-	case CASE(OEQ, TINT8):
-	case CASE(OEQ, TUINT8):
-	case CASE(OEQ, TINT16):
-	case CASE(OEQ, TUINT16):
-	case CASE(OEQ, TINT32):
-	case CASE(OEQ, TUINT32):
-	case CASE(OEQ, TINT64):
-	case CASE(OEQ, TUINT64):
-	case CASE(OEQ, TPTR32):
-	case CASE(OEQ, TPTR64):
-	case CASE(OEQ, TFLOAT32):
-	case CASE(OEQ, TFLOAT64):
-		a = AJEQ;
-		break;
-
-	case CASE(ONE, TBOOL):
-	case CASE(ONE, TINT8):
-	case CASE(ONE, TUINT8):
-	case CASE(ONE, TINT16):
-	case CASE(ONE, TUINT16):
-	case CASE(ONE, TINT32):
-	case CASE(ONE, TUINT32):
-	case CASE(ONE, TINT64):
-	case CASE(ONE, TUINT64):
-	case CASE(ONE, TPTR32):
-	case CASE(ONE, TPTR64):
-	case CASE(ONE, TFLOAT32):
-	case CASE(ONE, TFLOAT64):
-		a = AJNE;
-		break;
-
-	case CASE(OLT, TINT8):
-	case CASE(OLT, TINT16):
-	case CASE(OLT, TINT32):
-	case CASE(OLT, TINT64):
-		a = AJLT;
-		break;
-
-	case CASE(OLT, TUINT8):
-	case CASE(OLT, TUINT16):
-	case CASE(OLT, TUINT32):
-	case CASE(OLT, TUINT64):
-		a = AJCS;
-		break;
-
-	case CASE(OLE, TINT8):
-	case CASE(OLE, TINT16):
-	case CASE(OLE, TINT32):
-	case CASE(OLE, TINT64):
-		a = AJLE;
-		break;
-
-	case CASE(OLE, TUINT8):
-	case CASE(OLE, TUINT16):
-	case CASE(OLE, TUINT32):
-	case CASE(OLE, TUINT64):
-		a = AJLS;
-		break;
-
-	case CASE(OGT, TINT8):
-	case CASE(OGT, TINT16):
-	case CASE(OGT, TINT32):
-	case CASE(OGT, TINT64):
-		a = AJGT;
-		break;
-
-	case CASE(OGT, TUINT8):
-	case CASE(OGT, TUINT16):
-	case CASE(OGT, TUINT32):
-	case CASE(OGT, TUINT64):
-	case CASE(OLT, TFLOAT32):
-	case CASE(OLT, TFLOAT64):
-		a = AJHI;
-		break;
-
-	case CASE(OGE, TINT8):
-	case CASE(OGE, TINT16):
-	case CASE(OGE, TINT32):
-	case CASE(OGE, TINT64):
-		a = AJGE;
-		break;
-
-	case CASE(OGE, TUINT8):
-	case CASE(OGE, TUINT16):
-	case CASE(OGE, TUINT32):
-	case CASE(OGE, TUINT64):
-	case CASE(OLE, TFLOAT32):
-	case CASE(OLE, TFLOAT64):
-		a = AJCC;
-		break;
-
-	case CASE(OCMP, TBOOL):
-	case CASE(OCMP, TINT8):
-	case CASE(OCMP, TUINT8):
-		a = ACMPB;
-		break;
-
-	case CASE(OCMP, TINT16):
-	case CASE(OCMP, TUINT16):
-		a = ACMPW;
-		break;
-
-	case CASE(OCMP, TINT32):
-	case CASE(OCMP, TUINT32):
-	case CASE(OCMP, TPTR32):
-		a = ACMPL;
-		break;
-
-	case CASE(OCMP, TINT64):
-	case CASE(OCMP, TUINT64):
-	case CASE(OCMP, TPTR64):
-		a = ACMPQ;
-		break;
-
-	case CASE(OCMP, TFLOAT32):
-		a = AUCOMISS;
-		break;
-
-	case CASE(OCMP, TFLOAT64):
-		a = AUCOMISD;
-		break;
-
-	case CASE(OAS, TBOOL):
-	case CASE(OAS, TINT8):
-	case CASE(OAS, TUINT8):
-		a = AMOVB;
-		break;
-
-	case CASE(OAS, TINT16):
-	case CASE(OAS, TUINT16):
-		a = AMOVW;
-		break;
-
-	case CASE(OAS, TINT32):
-	case CASE(OAS, TUINT32):
-	case CASE(OAS, TPTR32):
-		a = AMOVL;
-		break;
-
-	case CASE(OAS, TINT64):
-	case CASE(OAS, TUINT64):
-	case CASE(OAS, TPTR64):
-		a = AMOVQ;
-		break;
-
-	case CASE(OAS, TFLOAT32):
-		a = AMOVSS;
-		break;
-
-	case CASE(OAS, TFLOAT64):
-		a = AMOVSD;
-		break;
-
-	case CASE(OADD, TINT8):
-	case CASE(OADD, TUINT8):
-		a = AADDB;
-		break;
-
-	case CASE(OADD, TINT16):
-	case CASE(OADD, TUINT16):
-		a = AADDW;
-		break;
-
-	case CASE(OADD, TINT32):
-	case CASE(OADD, TUINT32):
-	case CASE(OADD, TPTR32):
-		a = AADDL;
-		break;
-
-	case CASE(OADD, TINT64):
-	case CASE(OADD, TUINT64):
-	case CASE(OADD, TPTR64):
-		a = AADDQ;
-		break;
-
-	case CASE(OADD, TFLOAT32):
-		a = AADDSS;
-		break;
-
-	case CASE(OADD, TFLOAT64):
-		a = AADDSD;
-		break;
-
-	case CASE(OSUB, TINT8):
-	case CASE(OSUB, TUINT8):
-		a = ASUBB;
-		break;
-
-	case CASE(OSUB, TINT16):
-	case CASE(OSUB, TUINT16):
-		a = ASUBW;
-		break;
-
-	case CASE(OSUB, TINT32):
-	case CASE(OSUB, TUINT32):
-	case CASE(OSUB, TPTR32):
-		a = ASUBL;
-		break;
-
-	case CASE(OSUB, TINT64):
-	case CASE(OSUB, TUINT64):
-	case CASE(OSUB, TPTR64):
-		a = ASUBQ;
-		break;
-
-	case CASE(OSUB, TFLOAT32):
-		a = ASUBSS;
-		break;
-
-	case CASE(OSUB, TFLOAT64):
-		a = ASUBSD;
-		break;
-
-	case CASE(OINC, TINT8):
-	case CASE(OINC, TUINT8):
-		a = AINCB;
-		break;
-
-	case CASE(OINC, TINT16):
-	case CASE(OINC, TUINT16):
-		a = AINCW;
-		break;
-
-	case CASE(OINC, TINT32):
-	case CASE(OINC, TUINT32):
-	case CASE(OINC, TPTR32):
-		a = AINCL;
-		break;
-
-	case CASE(OINC, TINT64):
-	case CASE(OINC, TUINT64):
-	case CASE(OINC, TPTR64):
-		a = AINCQ;
-		break;
-
-	case CASE(ODEC, TINT8):
-	case CASE(ODEC, TUINT8):
-		a = ADECB;
-		break;
-
-	case CASE(ODEC, TINT16):
-	case CASE(ODEC, TUINT16):
-		a = ADECW;
-		break;
-
-	case CASE(ODEC, TINT32):
-	case CASE(ODEC, TUINT32):
-	case CASE(ODEC, TPTR32):
-		a = ADECL;
-		break;
-
-	case CASE(ODEC, TINT64):
-	case CASE(ODEC, TUINT64):
-	case CASE(ODEC, TPTR64):
-		a = ADECQ;
-		break;
-
-	case CASE(OMINUS, TINT8):
-	case CASE(OMINUS, TUINT8):
-		a = ANEGB;
-		break;
-
-	case CASE(OMINUS, TINT16):
-	case CASE(OMINUS, TUINT16):
-		a = ANEGW;
-		break;
-
-	case CASE(OMINUS, TINT32):
-	case CASE(OMINUS, TUINT32):
-	case CASE(OMINUS, TPTR32):
-		a = ANEGL;
-		break;
-
-	case CASE(OMINUS, TINT64):
-	case CASE(OMINUS, TUINT64):
-	case CASE(OMINUS, TPTR64):
-		a = ANEGQ;
-		break;
-
-	case CASE(OAND, TINT8):
-	case CASE(OAND, TUINT8):
-		a = AANDB;
-		break;
-
-	case CASE(OAND, TINT16):
-	case CASE(OAND, TUINT16):
-		a = AANDW;
-		break;
-
-	case CASE(OAND, TINT32):
-	case CASE(OAND, TUINT32):
-	case CASE(OAND, TPTR32):
-		a = AANDL;
-		break;
-
-	case CASE(OAND, TINT64):
-	case CASE(OAND, TUINT64):
-	case CASE(OAND, TPTR64):
-		a = AANDQ;
-		break;
-
-	case CASE(OOR, TINT8):
-	case CASE(OOR, TUINT8):
-		a = AORB;
-		break;
-
-	case CASE(OOR, TINT16):
-	case CASE(OOR, TUINT16):
-		a = AORW;
-		break;
-
-	case CASE(OOR, TINT32):
-	case CASE(OOR, TUINT32):
-	case CASE(OOR, TPTR32):
-		a = AORL;
-		break;
-
-	case CASE(OOR, TINT64):
-	case CASE(OOR, TUINT64):
-	case CASE(OOR, TPTR64):
-		a = AORQ;
-		break;
-
-	case CASE(OXOR, TINT8):
-	case CASE(OXOR, TUINT8):
-		a = AXORB;
-		break;
-
-	case CASE(OXOR, TINT16):
-	case CASE(OXOR, TUINT16):
-		a = AXORW;
-		break;
-
-	case CASE(OXOR, TINT32):
-	case CASE(OXOR, TUINT32):
-	case CASE(OXOR, TPTR32):
-		a = AXORL;
-		break;
-
-	case CASE(OXOR, TINT64):
-	case CASE(OXOR, TUINT64):
-	case CASE(OXOR, TPTR64):
-		a = AXORQ;
-		break;
-
-	case CASE(OLROT, TINT8):
-	case CASE(OLROT, TUINT8):
-		a = AROLB;
-		break;
-
-	case CASE(OLROT, TINT16):
-	case CASE(OLROT, TUINT16):
-		a = AROLW;
-		break;
-
-	case CASE(OLROT, TINT32):
-	case CASE(OLROT, TUINT32):
-	case CASE(OLROT, TPTR32):
-		a = AROLL;
-		break;
-
-	case CASE(OLROT, TINT64):
-	case CASE(OLROT, TUINT64):
-	case CASE(OLROT, TPTR64):
-		a = AROLQ;
-		break;
-
-	case CASE(OLSH, TINT8):
-	case CASE(OLSH, TUINT8):
-		a = ASHLB;
-		break;
-
-	case CASE(OLSH, TINT16):
-	case CASE(OLSH, TUINT16):
-		a = ASHLW;
-		break;
-
-	case CASE(OLSH, TINT32):
-	case CASE(OLSH, TUINT32):
-	case CASE(OLSH, TPTR32):
-		a = ASHLL;
-		break;
-
-	case CASE(OLSH, TINT64):
-	case CASE(OLSH, TUINT64):
-	case CASE(OLSH, TPTR64):
-		a = ASHLQ;
-		break;
-
-	case CASE(ORSH, TUINT8):
-		a = ASHRB;
-		break;
-
-	case CASE(ORSH, TUINT16):
-		a = ASHRW;
-		break;
-
-	case CASE(ORSH, TUINT32):
-	case CASE(ORSH, TPTR32):
-		a = ASHRL;
-		break;
-
-	case CASE(ORSH, TUINT64):
-	case CASE(ORSH, TPTR64):
-		a = ASHRQ;
-		break;
-
-	case CASE(ORSH, TINT8):
-		a = ASARB;
-		break;
-
-	case CASE(ORSH, TINT16):
-		a = ASARW;
-		break;
-
-	case CASE(ORSH, TINT32):
-		a = ASARL;
-		break;
-
-	case CASE(ORSH, TINT64):
-		a = ASARQ;
-		break;
-
-	case CASE(ORROTC, TINT8):
-	case CASE(ORROTC, TUINT8):
-		a = ARCRB;
-		break;
-
-	case CASE(ORROTC, TINT16):
-	case CASE(ORROTC, TUINT16):
-		a = ARCRW;
-		break;
-
-	case CASE(ORROTC, TINT32):
-	case CASE(ORROTC, TUINT32):
-		a = ARCRL;
-		break;
-
-	case CASE(ORROTC, TINT64):
-	case CASE(ORROTC, TUINT64):
-		a = ARCRQ;
-		break;
-
-	case CASE(OHMUL, TINT8):
-	case CASE(OMUL, TINT8):
-	case CASE(OMUL, TUINT8):
-		a = AIMULB;
-		break;
-
-	case CASE(OHMUL, TINT16):
-	case CASE(OMUL, TINT16):
-	case CASE(OMUL, TUINT16):
-		a = AIMULW;
-		break;
-
-	case CASE(OHMUL, TINT32):
-	case CASE(OMUL, TINT32):
-	case CASE(OMUL, TUINT32):
-	case CASE(OMUL, TPTR32):
-		a = AIMULL;
-		break;
-
-	case CASE(OHMUL, TINT64):
-	case CASE(OMUL, TINT64):
-	case CASE(OMUL, TUINT64):
-	case CASE(OMUL, TPTR64):
-		a = AIMULQ;
-		break;
-
-	case CASE(OHMUL, TUINT8):
-		a = AMULB;
-		break;
-
-	case CASE(OHMUL, TUINT16):
-		a = AMULW;
-		break;
-
-	case CASE(OHMUL, TUINT32):
-	case CASE(OHMUL, TPTR32):
-		a = AMULL;
-		break;
-
-	case CASE(OHMUL, TUINT64):
-	case CASE(OHMUL, TPTR64):
-		a = AMULQ;
-		break;
-
-	case CASE(OMUL, TFLOAT32):
-		a = AMULSS;
-		break;
-
-	case CASE(OMUL, TFLOAT64):
-		a = AMULSD;
-		break;
-
-	case CASE(ODIV, TINT8):
-	case CASE(OMOD, TINT8):
-		a = AIDIVB;
-		break;
-
-	case CASE(ODIV, TUINT8):
-	case CASE(OMOD, TUINT8):
-		a = ADIVB;
-		break;
-
-	case CASE(ODIV, TINT16):
-	case CASE(OMOD, TINT16):
-		a = AIDIVW;
-		break;
-
-	case CASE(ODIV, TUINT16):
-	case CASE(OMOD, TUINT16):
-		a = ADIVW;
-		break;
-
-	case CASE(ODIV, TINT32):
-	case CASE(OMOD, TINT32):
-		a = AIDIVL;
-		break;
-
-	case CASE(ODIV, TUINT32):
-	case CASE(ODIV, TPTR32):
-	case CASE(OMOD, TUINT32):
-	case CASE(OMOD, TPTR32):
-		a = ADIVL;
-		break;
-
-	case CASE(ODIV, TINT64):
-	case CASE(OMOD, TINT64):
-		a = AIDIVQ;
-		break;
-
-	case CASE(ODIV, TUINT64):
-	case CASE(ODIV, TPTR64):
-	case CASE(OMOD, TUINT64):
-	case CASE(OMOD, TPTR64):
-		a = ADIVQ;
-		break;
-
-	case CASE(OEXTEND, TINT16):
-		a = ACWD;
-		break;
-
-	case CASE(OEXTEND, TINT32):
-		a = ACDQ;
-		break;
-
-	case CASE(OEXTEND, TINT64):
-		a = ACQO;
-		break;
-
-	case CASE(ODIV, TFLOAT32):
-		a = ADIVSS;
-		break;
-
-	case CASE(ODIV, TFLOAT64):
-		a = ADIVSD;
-		break;
-
-	}
-	return a;
-}
-
-enum
-{
-	ODynam		= 1<<0,
-	OAddable	= 1<<1,
-};
-
-static	Node	clean[20];
-static	int	cleani = 0;
-
-int
-xgen(Node *n, Node *a, int o)
-{
-	regalloc(a, types[tptr], N);
-
-	if(o & ODynam)
-	if(n->addable)
-	if(n->op != OINDREG)
-	if(n->op != OREGISTER)
-		return 1;
-
-	agen(n, a);
-	return 0;
-}
-
-void
-sudoclean(void)
-{
-	if(clean[cleani-1].op != OEMPTY)
-		regfree(&clean[cleani-1]);
-	if(clean[cleani-2].op != OEMPTY)
-		regfree(&clean[cleani-2]);
-	cleani -= 2;
-}
-
-/*
- * 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.
- */
-int
-sudoaddable(int as, Node *n, Addr *a)
-{
-	int o, i;
-	int64 oary[10];
-	int64 v, w;
-	Node n1, n2, n3, n4, *nn, *l, *r;
-	Node *reg, *reg1;
-	Prog *p1;
-	Type *t;
-
-	if(n->type == T)
-		return 0;
-
-	switch(n->op) {
-	case OLITERAL:
-		if(!isconst(n, CTINT))
-			break;
-		v = mpgetfix(n->val.u.xval);
-		if(v >= 32000 || v <= -32000)
-			break;
-		goto lit;
-
-	case ODOT:
-	case ODOTPTR:
-		cleani += 2;
-		reg = &clean[cleani-1];
-		reg1 = &clean[cleani-2];
-		reg->op = OEMPTY;
-		reg1->op = OEMPTY;
-		goto odot;
-
-	case OINDEX:
-		return 0;
-		// disabled: OINDEX case is now covered by agenr
-		// for a more suitable register allocation pattern.
-		if(n->left->type->etype == TSTRING)
-			return 0;
-		goto oindex;
-	}
-	return 0;
-
-lit:
-	switch(as) {
-	default:
-		return 0;
-	case AADDB: case AADDW: case AADDL: case AADDQ:
-	case ASUBB: case ASUBW: case ASUBL: case ASUBQ:
-	case AANDB: case AANDW: case AANDL: case AANDQ:
-	case AORB:  case AORW:  case AORL:  case AORQ:
-	case AXORB: case AXORW: case AXORL: case AXORQ:
-	case AINCB: case AINCW: case AINCL: case AINCQ:
-	case ADECB: case ADECW: case ADECL: case ADECQ:
-	case AMOVB: case AMOVW: case AMOVL: case AMOVQ:
-		break;
-	}
-
-	cleani += 2;
-	reg = &clean[cleani-1];
-	reg1 = &clean[cleani-2];
-	reg->op = OEMPTY;
-	reg1->op = OEMPTY;
-	naddr(n, a, 1);
-	goto yes;
-
-odot:
-	o = dotoffset(n, oary, &nn);
-	if(nn == N)
-		goto no;
-
-	if(nn->addable && o == 1 && oary[0] >= 0) {
-		// directly addressable set of DOTs
-		n1 = *nn;
-		n1.type = n->type;
-		n1.xoffset += oary[0];
-		naddr(&n1, a, 1);
-		goto yes;
-	}
-
-	regalloc(reg, types[tptr], N);
-	n1 = *reg;
-	n1.op = OINDREG;
-	if(oary[0] >= 0) {
-		agen(nn, reg);
-		n1.xoffset = oary[0];
-	} else {
-		cgen(nn, reg);
-		cgen_checknil(reg);
-		n1.xoffset = -(oary[0]+1);
-	}
-
-	for(i=1; i<o; i++) {
-		if(oary[i] >= 0)
-			fatal("can't happen");
-		gins(movptr, &n1, reg);
-		cgen_checknil(reg);
-		n1.xoffset = -(oary[i]+1);
-	}
-
-	a->type = D_NONE;
-	a->index = D_NONE;
-	fixlargeoffset(&n1);
-	naddr(&n1, a, 1);
-	goto yes;
-
-oindex:
-	l = n->left;
-	r = n->right;
-	if(l->ullman >= UINF && r->ullman >= UINF)
-		return 0;
-
-	// set o to type of array
-	o = 0;
-	if(isptr[l->type->etype])
-		fatal("ptr ary");
-	if(l->type->etype != TARRAY)
-		fatal("not ary");
-	if(l->type->bound < 0)
-		o |= ODynam;
-
-	w = n->type->width;
-	if(isconst(r, CTINT))
-		goto oindex_const;
-
-	switch(w) {
-	default:
-		return 0;
-	case 1:
-	case 2:
-	case 4:
-	case 8:
-		break;
-	}
-
-	cleani += 2;
-	reg = &clean[cleani-1];
-	reg1 = &clean[cleani-2];
-	reg->op = OEMPTY;
-	reg1->op = OEMPTY;
-
-	// load the array (reg)
-	if(l->ullman > r->ullman) {
-		if(xgen(l, reg, o))
-			o |= OAddable;
-	}
-
-	// load the index (reg1)
-	t = types[TUINT64];
-	if(issigned[r->type->etype])
-		t = types[TINT64];
-	regalloc(reg1, t, N);
-	regalloc(&n3, r->type, reg1);
-	cgen(r, &n3);
-	gmove(&n3, reg1);
-	regfree(&n3);
-
-	// load the array (reg)
-	if(l->ullman <= r->ullman) {
-		if(xgen(l, reg, o))
-			o |= OAddable;
-	}
-
-	// check bounds
-	if(!debug['B'] && !n->bounded) {
-		// check bounds
-		n4.op = OXXX;
-		t = types[simtype[TUINT]];
-		if(o & ODynam) {
-			if(o & OAddable) {
-				n2 = *l;
-				n2.xoffset += Array_nel;
-				n2.type = types[simtype[TUINT]];
-			} else {
-				n2 = *reg;
-				n2.xoffset = Array_nel;
-				n2.op = OINDREG;
-				n2.type = types[simtype[TUINT]];
-			}
-		} else {
-			if(is64(r->type))
-				t = types[TUINT64];
-			nodconst(&n2, types[TUINT64], l->type->bound);
-		}
-		gins(optoas(OCMP, t), reg1, &n2);
-		p1 = gbranch(optoas(OLT, t), T, +1);
-		if(n4.op != OXXX)
-			regfree(&n4);
-		ginscall(panicindex, -1);
-		patch(p1, pc);
-	}
-
-	if(o & ODynam) {
-		if(o & OAddable) {
-			n2 = *l;
-			n2.xoffset += Array_array;
-			n2.type = types[tptr];
-			gmove(&n2, reg);
-		} else {
-			n2 = *reg;
-			n2.op = OINDREG;
-			n2.xoffset = Array_array;
-			n2.type = types[tptr];
-			gmove(&n2, reg);
-		}
-	}
-
-	if(o & OAddable) {
-		naddr(reg1, a, 1);
-		a->offset = 0;
-		a->scale = w;
-		a->index = a->type;
-		a->type = reg->val.u.reg + D_INDIR;
-	} else {
-		naddr(reg1, a, 1);
-		a->offset = 0;
-		a->scale = w;
-		a->index = a->type;
-		a->type = reg->val.u.reg + D_INDIR;
-	}
-
-	goto yes;
-
-oindex_const:
-	// index is constant
-	// can check statically and
-	// can multiply by width statically
-
-	v = mpgetfix(r->val.u.xval);
-
-	if(sudoaddable(as, l, a))
-		goto oindex_const_sudo;
-
-	cleani += 2;
-	reg = &clean[cleani-1];
-	reg1 = &clean[cleani-2];
-	reg->op = OEMPTY;
-	reg1->op = OEMPTY;
-
-	if(o & ODynam) {
-		regalloc(reg, types[tptr], N);
-		agen(l, reg);
-	
-		if(!debug['B'] && !n->bounded) {
-			n1 = *reg;
-			n1.op = OINDREG;
-			n1.type = types[tptr];
-			n1.xoffset = Array_nel;
-			nodconst(&n2, types[TUINT64], v);
-			gins(optoas(OCMP, types[simtype[TUINT]]), &n1, &n2);
-			p1 = gbranch(optoas(OGT, types[simtype[TUINT]]), T, +1);
-			ginscall(panicindex, -1);
-			patch(p1, pc);
-		}
-
-		n1 = *reg;
-		n1.op = OINDREG;
-		n1.type = types[tptr];
-		n1.xoffset = Array_array;
-		gmove(&n1, reg);
-
-		n2 = *reg;
-		n2.op = OINDREG;
-		n2.xoffset = v*w;
-		fixlargeoffset(&n2);
-		a->type = D_NONE;
-		a->index = D_NONE;
-		naddr(&n2, a, 1);
-		goto yes;
-	}
-	
-	igen(l, &n1, N);
-	if(n1.op == OINDREG) {
-		*reg = n1;
-		reg->op = OREGISTER;
-	}
-	n1.xoffset += v*w;
-	fixlargeoffset(&n1);
-	a->type = D_NONE;
-	a->index= D_NONE;
-	naddr(&n1, a, 1);
-	goto yes;
-
-oindex_const_sudo:
-	if((o & ODynam) == 0) {
-		// array indexed by a constant
-		a->offset += v*w;
-		goto yes;
-	}
-
-	// slice indexed by a constant
-	if(!debug['B'] && !n->bounded) {
-		a->offset += Array_nel;
-		nodconst(&n2, types[TUINT64], v);
-		p1 = gins(optoas(OCMP, types[simtype[TUINT]]), N, &n2);
-		p1->from = *a;
-		p1 = gbranch(optoas(OGT, types[simtype[TUINT]]), T, +1);
-		ginscall(panicindex, -1);
-		patch(p1, pc);
-		a->offset -= Array_nel;
-	}
-
-	a->offset += Array_array;
-	reg = &clean[cleani-1];
-	if(reg->op == OEMPTY)
-		regalloc(reg, types[tptr], N);
-
-	p1 = gins(movptr, N, reg);
-	p1->from = *a;
-
-	n2 = *reg;
-	n2.op = OINDREG;
-	n2.xoffset = v*w;
-	fixlargeoffset(&n2);
-	a->type = D_NONE;
-	a->index = D_NONE;
-	naddr(&n2, a, 1);
-	goto yes;
-
-yes:
-	return 1;
-
-no:
-	sudoclean();
-	return 0;
-}
diff --git a/src/cmd/6g/opt.h b/src/cmd/6g/opt.h
deleted file mode 100644
index dbd039d..0000000
--- a/src/cmd/6g/opt.h
+++ /dev/null
@@ -1,220 +0,0 @@
-// Derived from Inferno utils/6c/gc.h
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/gc.h
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include	"../gc/popt.h"
-
-#define	Z	N
-#define	Adr	Addr
-
-#define	D_HI	D_NONE
-#define	D_LO	D_NONE
-
-#define	BLOAD(r)	band(bnot(r->refbehind), r->refahead)
-#define	BSTORE(r)	band(bnot(r->calbehind), r->calahead)
-#define	LOAD(r)		(~r->refbehind.b[z] & r->refahead.b[z])
-#define	STORE(r)	(~r->calbehind.b[z] & r->calahead.b[z])
-
-#define	CLOAD	5
-#define	CREF	5
-#define	CINF	1000
-#define	LOOP	3
-
-typedef	struct	Reg	Reg;
-typedef	struct	Rgn	Rgn;
-
-/*c2go
-extern Node *Z;
-enum
-{
-	D_HI = D_NONE,
-	D_LO = D_NONE,
-	CLOAD = 5,
-	CREF = 5,
-	CINF = 1000,
-	LOOP = 3,
-};
-
-uint32 BLOAD(Reg*);
-uint32 BSTORE(Reg*);
-uint32 LOAD(Reg*);
-uint32 STORE(Reg*);
-*/
-
-// 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.
-// r->prog->opt points back to r.
-struct	Reg
-{
-	Flow	f;
-
-	Bits	set;  		// variables written by this instruction.
-	Bits	use1; 		// variables read by prog->from.
-	Bits	use2; 		// variables read by prog->to.
-
-	Bits	refbehind;
-	Bits	refahead;
-	Bits	calbehind;
-	Bits	calahead;
-	Bits	regdiff;
-	Bits	act;
-
-	int32	regu;		// register used bitmap
-};
-#define	R	((Reg*)0)
-/*c2go extern Reg *R; */
-
-#define	NRGN	600
-/*c2go enum { NRGN = 600 }; */
-struct	Rgn
-{
-	Reg*	enter;
-	short	cost;
-	short	varno;
-	short	regno;
-};
-
-EXTERN	int32	exregoffset;		// not set
-EXTERN	int32	exfregoffset;		// not set
-EXTERN	Reg	zreg;
-EXTERN	Rgn	region[NRGN];
-EXTERN	Rgn*	rgp;
-EXTERN	int	nregion;
-EXTERN	int	nvar;
-EXTERN	int32	regbits;
-EXTERN	int32	exregbits;
-EXTERN	Bits	externs;
-EXTERN	Bits	params;
-EXTERN	Bits	consts;
-EXTERN	Bits	addrs;
-EXTERN	Bits	ivar;
-EXTERN	Bits	ovar;
-EXTERN	int	change;
-EXTERN	int32	maxnr;
-
-EXTERN	struct
-{
-	int32	ncvtreg;
-	int32	nspill;
-	int32	nreload;
-	int32	ndelmov;
-	int32	nvar;
-	int32	naddr;
-} ostats;
-
-/*
- * reg.c
- */
-int	rcmp(const void*, const void*);
-void	regopt(Prog*);
-void	addmove(Reg*, int, int, int);
-Bits	mkvar(Reg*, Adr*);
-void	prop(Reg*, Bits, Bits);
-void	synch(Reg*, Bits);
-uint32	allreg(uint32, Rgn*);
-void	paint1(Reg*, int);
-uint32	paint2(Reg*, int);
-void	paint3(Reg*, int, int32, int);
-void	addreg(Adr*, int);
-void	dumpone(Flow*, int);
-void	dumpit(char*, Flow*, int);
-
-/*
- * peep.c
- */
-void	peep(Prog*);
-void	excise(Flow*);
-int	copyu(Prog*, Adr*, Adr*);
-
-int32	RtoB(int);
-int32	FtoB(int);
-int	BtoR(int32);
-int	BtoF(int32);
-
-/*
- * prog.c
- */
-typedef struct ProgInfo ProgInfo;
-struct ProgInfo
-{
-	uint32 flags; // the bits below
-	uint32 reguse; // required registers used by this instruction
-	uint32 regset; // required registers set by this instruction
-	uint32 regindex; // registers used by addressing mode
-};
-
-enum
-{
-	// 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, // float aka float32
-	SizeD = 1<<8, // double aka float64
-
-	// Left side: address taken, read, write.
-	LeftAddr = 1<<9,
-	LeftRead = 1<<10,
-	LeftWrite = 1<<11,
-	
-	// Right side: address taken, read, write.
-	RightAddr = 1<<12,
-	RightRead = 1<<13,
-	RightWrite = 1<<14,
-
-	// Set, use, or kill of carry bit.
-	// Kill means we never look at the carry bit after this kind of instruction.
-	SetCarry = 1<<15,
-	UseCarry = 1<<16,
-	KillCarry = 1<<17,
-
-	// Instruction kinds
-	Move = 1<<18, // straight move
-	Conv = 1<<19, // size conversion
-	Cjmp = 1<<20, // conditional jump
-	Break = 1<<21, // breaks control flow (no fallthrough)
-	Call = 1<<22, // function call
-	Jump = 1<<23, // jump
-	Skip = 1<<24, // data instruction
-
-	// Special cases for register use.
-	ShiftCX = 1<<25, // possible shift by CX
-	ImulAXDX = 1<<26, // possible multiply into DX:AX
-};
-
-void proginfo(ProgInfo*, Prog*);
diff --git a/src/cmd/6g/peep.c b/src/cmd/6g/peep.c
deleted file mode 100644
index 2461783..0000000
--- a/src/cmd/6g/peep.c
+++ /dev/null
@@ -1,990 +0,0 @@
-// 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 at 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 at 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.
-
-#include <u.h>
-#include <libc.h>
-#include "gg.h"
-#include "opt.h"
-
-static void	conprop(Flow *r);
-static void	elimshortmov(Graph *g);
-static int	prevl(Flow *r, int reg);
-static void	pushback(Flow *r);
-static int	regconsttyp(Adr*);
-static int	subprop(Flow*);
-static int	copyprop(Graph*, Flow*);
-static int	copy1(Adr*, Adr*, Flow*, int);
-static int	copyas(Adr*, Adr*);
-static int	copyau(Adr*, Adr*);
-static int	copysub(Adr*, Adr*, Adr*, int);
-
-static uint32	gactive;
-
-// do we need the carry bit
-static int
-needc(Prog *p)
-{
-	ProgInfo info;
-
-	while(p != P) {
-		proginfo(&info, p);
-		if(info.flags & UseCarry)
-			return 1;
-		if(info.flags & (SetCarry|KillCarry))
-			return 0;
-		p = p->link;
-	}
-	return 0;
-}
-
-static Flow*
-rnops(Flow *r)
-{
-	Prog *p;
-	Flow *r1;
-
-	if(r != nil)
-	for(;;) {
-		p = r->prog;
-		if(p->as != ANOP || p->from.type != D_NONE || p->to.type != D_NONE)
-			break;
-		r1 = uniqs(r);
-		if(r1 == nil)
-			break;
-		r = r1;
-	}
-	return r;
-}
-
-void
-peep(Prog *firstp)
-{
-	Flow *r, *r1;
-	Graph *g;
-	Prog *p, *p1;
-	int t;
-
-	g = flowstart(firstp, sizeof(Flow));
-	if(g == nil)
-		return;
-	gactive = 0;
-
-	// byte, word arithmetic elimination.
-	elimshortmov(g);
-
-	// constant propagation
-	// find MOV $con,R followed by
-	// another MOV $con,R without
-	// setting R in the interim
-	for(r=g->start; r!=nil; r=r->link) {
-		p = r->prog;
-		switch(p->as) {
-		case ALEAL:
-		case ALEAQ:
-			if(regtyp(&p->to))
-			if(p->from.sym != nil)
-			if(p->from.index == D_NONE || p->from.index == D_CONST)
-				conprop(r);
-			break;
-
-		case AMOVB:
-		case AMOVW:
-		case AMOVL:
-		case AMOVQ:
-		case AMOVSS:
-		case AMOVSD:
-			if(regtyp(&p->to))
-			if(p->from.type == D_CONST)
-				conprop(r);
-			break;
-		}
-	}
-
-loop1:
-	if(debug['P'] && debug['v'])
-		dumpit("loop1", g->start, 0);
-
-	t = 0;
-	for(r=g->start; r!=nil; r=r->link) {
-		p = r->prog;
-		switch(p->as) {
-		case AMOVL:
-		case AMOVQ:
-		case AMOVSS:
-		case AMOVSD:
-			if(regtyp(&p->to))
-			if(regtyp(&p->from)) {
-				if(copyprop(g, r)) {
-					excise(r);
-					t++;
-				} else
-				if(subprop(r) && copyprop(g, r)) {
-					excise(r);
-					t++;
-				}
-			}
-			break;
-
-		case AMOVBLZX:
-		case AMOVWLZX:
-		case AMOVBLSX:
-		case AMOVWLSX:
-			if(regtyp(&p->to)) {
-				r1 = rnops(uniqs(r));
-				if(r1 != nil) {
-					p1 = r1->prog;
-					if(p->as == p1->as && p->to.type == p1->from.type){
-						p1->as = AMOVL;
-						t++;
-					}
-				}
-			}
-			break;
-
-		case AMOVBQSX:
-		case AMOVBQZX:
-		case AMOVWQSX:
-		case AMOVWQZX:
-		case AMOVLQSX:
-		case AMOVLQZX:
-		case AMOVQL:
-			if(regtyp(&p->to)) {
-				r1 = rnops(uniqs(r));
-				if(r1 != nil) {
-					p1 = r1->prog;
-					if(p->as == p1->as && p->to.type == p1->from.type){
-						p1->as = AMOVQ;
-						t++;
-					}
-				}
-			}
-			break;
-
-		case AADDL:
-		case AADDQ:
-		case AADDW:
-			if(p->from.type != D_CONST || needc(p->link))
-				break;
-			if(p->from.offset == -1){
-				if(p->as == AADDQ)
-					p->as = ADECQ;
-				else
-				if(p->as == AADDL)
-					p->as = ADECL;
-				else
-					p->as = ADECW;
-				p->from = zprog.from;
-				break;
-			}
-			if(p->from.offset == 1){
-				if(p->as == AADDQ)
-					p->as = AINCQ;
-				else if(p->as == AADDL)
-					p->as = AINCL;
-				else
-					p->as = AINCW;
-				p->from = zprog.from;
-				break;
-			}
-			break;
-
-		case ASUBL:
-		case ASUBQ:
-		case ASUBW:
-			if(p->from.type != D_CONST || needc(p->link))
-				break;
-			if(p->from.offset == -1) {
-				if(p->as == ASUBQ)
-					p->as = AINCQ;
-				else
-				if(p->as == ASUBL)
-					p->as = AINCL;
-				else
-					p->as = AINCW;
-				p->from = zprog.from;
-				break;
-			}
-			if(p->from.offset == 1){
-				if(p->as == ASUBQ)
-					p->as = ADECQ;
-				else
-				if(p->as == ASUBL)
-					p->as = ADECL;
-				else
-					p->as = ADECW;
-				p->from = zprog.from;
-				break;
-			}
-			break;
-		}
-	}
-	if(t)
-		goto loop1;
-
-	// MOVLQZX removal.
-	// The MOVLQZX exists to avoid being confused for a
-	// MOVL that is just copying 32-bit data around during
-	// copyprop.  Now that copyprop is done, remov MOVLQZX R1, R2
-	// if it is dominated by an earlier ADDL/MOVL/etc into R1 that
-	// will have already cleared the high bits.
-	//
-	// MOVSD removal.
-	// We never use packed registers, so a MOVSD between registers
-	// can be replaced by MOVAPD, which moves the pair of float64s
-	// instead of just the lower one.  We only use the lower one, but
-	// 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 == AMOVLQZX)
-		if(regtyp(&p->from))
-		if(p->from.type == p->to.type)
-		if(prevl(r, p->from.type))
-			excise(r);
-		
-		if(p->as == AMOVSD)
-		if(regtyp(&p->from))
-		if(regtyp(&p->to))
-			p->as = AMOVAPD;
-	}
-
-	// load pipelining
-	// push any load from memory as early as possible
-	// to give it time to complete before use.
-	for(r=g->start; r!=nil; r=r->link) {
-		p = r->prog;
-		switch(p->as) {
-		case AMOVB:
-		case AMOVW:
-		case AMOVL:
-		case AMOVQ:
-		case AMOVLQZX:
-			if(regtyp(&p->to) && !regconsttyp(&p->from))
-				pushback(r);
-		}
-	}
-	
-	flowend(g);
-}
-
-static void
-pushback(Flow *r0)
-{
-	Flow *r, *b;
-	Prog *p0, *p, t;
-	
-	b = nil;
-	p0 = r0->prog;
-	for(r=uniqp(r0); r!=nil && uniqs(r)!=nil; r=uniqp(r)) {
-		p = r->prog;
-		if(p->as != ANOP) {
-			if(!regconsttyp(&p->from) || !regtyp(&p->to))
-				break;
-			if(copyu(p, &p0->to, nil) || copyu(p0, &p->to, nil))
-				break;
-		}
-		if(p->as == ACALL)
-			break;
-		b = r;
-	}
-	
-	if(b == nil) {
-		if(debug['v']) {
-			print("no pushback: %P\n", r0->prog);
-			if(r)
-				print("\t%P [%d]\n", r->prog, uniqs(r)!=nil);
-		}
-		return;
-	}
-
-	if(debug['v']) {
-		print("pushback\n");
-		for(r=b;; r=r->link) {
-			print("\t%P\n", r->prog);
-			if(r == r0)
-				break;
-		}
-	}
-
-	t = *r0->prog;
-	for(r=uniqp(r0);; r=uniqp(r)) {
-		p0 = r->link->prog;
-		p = r->prog;
-		p0->as = p->as;
-		p0->lineno = p->lineno;
-		p0->from = p->from;
-		p0->to = p->to;
-
-		if(r == b)
-			break;
-	}
-	p0 = r->prog;
-	p0->as = t.as;
-	p0->lineno = t.lineno;
-	p0->from = t.from;
-	p0->to = t.to;
-
-	if(debug['v']) {
-		print("\tafter\n");
-		for(r=b;; r=r->link) {
-			print("\t%P\n", r->prog);
-			if(r == r0)
-				break;
-		}
-	}
-}
-
-void
-excise(Flow *r)
-{
-	Prog *p;
-
-	p = r->prog;
-	if(debug['P'] && debug['v'])
-		print("%P ===delete===\n", p);
-
-	p->as = ANOP;
-	p->from = zprog.from;
-	p->to = zprog.to;
-
-	ostats.ndelmov++;
-}
-
-int
-regtyp(Adr *a)
-{
-	int t;
-
-	t = a->type;
-	if(t >= D_AX && t <= D_R15)
-		return 1;
-	if(t >= D_X0 && t <= D_X0+15)
-		return 1;
-	return 0;
-}
-
-// movb elimination.
-// movb is simulated by the linker
-// when a register other than ax, bx, cx, dx
-// is used, so rewrite to other instructions
-// when possible.  a movb into a register
-// can smash the entire 32-bit register without
-// causing any trouble.
-//
-// TODO: Using the Q forms here instead of the L forms
-// seems unnecessary, and it makes the instructions longer.
-static void
-elimshortmov(Graph *g)
-{
-	Prog *p;
-	Flow *r;
-
-	for(r=g->start; r!=nil; r=r->link) {
-		p = r->prog;
-		if(regtyp(&p->to)) {
-			switch(p->as) {
-			case AINCB:
-			case AINCW:
-				p->as = AINCQ;
-				break;
-			case ADECB:
-			case ADECW:
-				p->as = ADECQ;
-				break;
-			case ANEGB:
-			case ANEGW:
-				p->as = ANEGQ;
-				break;
-			case ANOTB:
-			case ANOTW:
-				p->as = ANOTQ;
-				break;
-			}
-			if(regtyp(&p->from) || p->from.type == D_CONST) {
-				// move or artihmetic into partial register.
-				// from another register or constant can be movl.
-				// we don't switch to 64-bit arithmetic if it can
-				// change how the carry bit is set (and the carry bit is needed).
-				switch(p->as) {
-				case AMOVB:
-				case AMOVW:
-					p->as = AMOVQ;
-					break;
-				case AADDB:
-				case AADDW:
-					if(!needc(p->link))
-						p->as = AADDQ;
-					break;
-				case ASUBB:
-				case ASUBW:
-					if(!needc(p->link))
-						p->as = ASUBQ;
-					break;
-				case AMULB:
-				case AMULW:
-					p->as = AMULQ;
-					break;
-				case AIMULB:
-				case AIMULW:
-					p->as = AIMULQ;
-					break;
-				case AANDB:
-				case AANDW:
-					p->as = AANDQ;
-					break;
-				case AORB:
-				case AORW:
-					p->as = AORQ;
-					break;
-				case AXORB:
-				case AXORW:
-					p->as = AXORQ;
-					break;
-				case ASHLB:
-				case ASHLW:
-					p->as = ASHLQ;
-					break;
-				}
-			} else if(p->from.type >= D_NONE) {
-				// explicit zero extension, but don't
-				// do that if source is a byte register
-				// (only AH can occur and it's forbidden).
-				switch(p->as) {
-				case AMOVB:
-					p->as = AMOVBQZX;
-					break;
-				case AMOVW:
-					p->as = AMOVWQZX;
-					break;
-				}
-			}
-		}
-	}
-}
-
-// is 'a' a register or constant?
-static int
-regconsttyp(Adr *a)
-{
-	if(regtyp(a))
-		return 1;
-	switch(a->type) {
-	case D_CONST:
-	case D_FCONST:
-	case D_SCONST:
-	case D_ADDR:
-		return 1;
-	}
-	return 0;
-}
-
-// is reg guaranteed to be truncated by a previous L instruction?
-static int
-prevl(Flow *r0, int reg)
-{
-	Prog *p;
-	Flow *r;
-	ProgInfo info;
-
-	for(r=uniqp(r0); r!=nil; r=uniqp(r)) {
-		p = r->prog;
-		if(p->to.type == reg) {
-			proginfo(&info, p);
-			if(info.flags & RightWrite) {
-				if(info.flags & SizeL)
-					return 1;
-				return 0;
-			}
-		}
-	}
-	return 0;
-}
-
-/*
- * the idea is to substitute
- * one register for another
- * from one MOV to another
- *	MOV	a, R0
- *	ADD	b, R0	/ no use of R1
- *	MOV	R0, R1
- * would be converted to
- *	MOV	a, R1
- *	ADD	b, R1
- *	MOV	R1, R0
- * hopefully, then the former or latter MOV
- * will be eliminated by copy propagation.
- */
-static int
-subprop(Flow *r0)
-{
-	Prog *p;
-	ProgInfo info;
-	Adr *v1, *v2;
-	Flow *r;
-	int t;
-
-	if(debug['P'] && debug['v'])
-		print("subprop %P\n", r0->prog);
-	p = r0->prog;
-	v1 = &p->from;
-	if(!regtyp(v1)) {
-		if(debug['P'] && debug['v'])
-			print("\tnot regtype %D; return 0\n", v1);
-		return 0;
-	}
-	v2 = &p->to;
-	if(!regtyp(v2)) {
-		if(debug['P'] && debug['v'])
-			print("\tnot regtype %D; return 0\n", v2);
-		return 0;
-	}
-	for(r=uniqp(r0); r!=nil; r=uniqp(r)) {
-		if(debug['P'] && debug['v'])
-			print("\t? %P\n", r->prog);
-		if(uniqs(r) == nil) {
-			if(debug['P'] && debug['v'])
-				print("\tno unique successor\n");
-			break;
-		}
-		p = r->prog;
-		if(p->as == AVARDEF || p->as == AVARKILL)
-			continue;
-		proginfo(&info, p);
-		if(info.flags & Call) {
-			if(debug['P'] && debug['v'])
-				print("\tfound %P; return 0\n", p);
-			return 0;
-		}
-
-		if(info.reguse | info.regset) {
-			if(debug['P'] && debug['v'])
-				print("\tfound %P; return 0\n", p);
-			return 0;
-		}
-
-		if((info.flags & Move) && (info.flags & (SizeL|SizeQ|SizeF|SizeD)) && p->to.type == v1->type)
-			goto gotit;
-
-		if(copyau(&p->from, v2) ||
-		   copyau(&p->to, v2)) {
-		   	if(debug['P'] && debug['v'])
-		   		print("\tcopyau %D failed\n", v2);
-			break;
-		}
-		if(copysub(&p->from, v1, v2, 0) ||
-		   copysub(&p->to, v1, v2, 0)) {
-		   	if(debug['P'] && debug['v'])
-		   		print("\tcopysub failed\n");
-			break;
-		}
-	}
-	if(debug['P'] && debug['v'])
-		print("\tran off end; return 0\n");
-	return 0;
-
-gotit:
-	copysub(&p->to, v1, v2, 1);
-	if(debug['P']) {
-		print("gotit: %D->%D\n%P", v1, v2, r->prog);
-		if(p->from.type == v2->type)
-			print(" excise");
-		print("\n");
-	}
-	for(r=uniqs(r); r!=r0; r=uniqs(r)) {
-		p = r->prog;
-		copysub(&p->from, v1, v2, 1);
-		copysub(&p->to, v1, v2, 1);
-		if(debug['P'])
-			print("%P\n", r->prog);
-	}
-	t = v1->type;
-	v1->type = v2->type;
-	v2->type = t;
-	if(debug['P'])
-		print("%P last\n", r->prog);
-	return 1;
-}
-
-/*
- * The idea is to remove redundant copies.
- *	v1->v2	F=0
- *	(use v2	s/v2/v1/)*
- *	set v1	F=1
- *	use v2	return fail
- *	-----------------
- *	v1->v2	F=0
- *	(use v2	s/v2/v1/)*
- *	set v1	F=1
- *	set v2	return success
- */
-static int
-copyprop(Graph *g, Flow *r0)
-{
-	Prog *p;
-	Adr *v1, *v2;
-
-	USED(g);
-	if(debug['P'] && debug['v'])
-		print("copyprop %P\n", r0->prog);
-	p = r0->prog;
-	v1 = &p->from;
-	v2 = &p->to;
-	if(copyas(v1, v2))
-		return 1;
-	gactive++;
-	return copy1(v1, v2, r0->s1, 0);
-}
-
-static int
-copy1(Adr *v1, Adr *v2, Flow *r, int f)
-{
-	int t;
-	Prog *p;
-
-	if(r->active == gactive) {
-		if(debug['P'])
-			print("act set; return 1\n");
-		return 1;
-	}
-	r->active = gactive;
-	if(debug['P'])
-		print("copy %D->%D f=%d\n", v1, v2, f);
-	for(; r != nil; r = r->s1) {
-		p = r->prog;
-		if(debug['P'])
-			print("%P", p);
-		if(!f && uniqp(r) == nil) {
-			f = 1;
-			if(debug['P'])
-				print("; merge; f=%d", f);
-		}
-		t = copyu(p, v2, nil);
-		switch(t) {
-		case 2:	/* rar, can't split */
-			if(debug['P'])
-				print("; %D rar; return 0\n", v2);
-			return 0;
-
-		case 3:	/* set */
-			if(debug['P'])
-				print("; %D set; return 1\n", v2);
-			return 1;
-
-		case 1:	/* used, substitute */
-		case 4:	/* use and set */
-			if(f) {
-				if(!debug['P'])
-					return 0;
-				if(t == 4)
-					print("; %D used+set and f=%d; return 0\n", v2, f);
-				else
-					print("; %D used and f=%d; return 0\n", v2, f);
-				return 0;
-			}
-			if(copyu(p, v2, v1)) {
-				if(debug['P'])
-					print("; sub fail; return 0\n");
-				return 0;
-			}
-			if(debug['P'])
-				print("; sub %D/%D", v2, v1);
-			if(t == 4) {
-				if(debug['P'])
-					print("; %D used+set; return 1\n", v2);
-				return 1;
-			}
-			break;
-		}
-		if(!f) {
-			t = copyu(p, v1, nil);
-			if(!f && (t == 2 || t == 3 || t == 4)) {
-				f = 1;
-				if(debug['P'])
-					print("; %D set and !f; f=%d", v1, f);
-			}
-		}
-		if(debug['P'])
-			print("\n");
-		if(r->s2)
-			if(!copy1(v1, v2, r->s2, f))
-				return 0;
-	}
-	return 1;
-}
-
-/*
- * return
- * 1 if v only used (and substitute),
- * 2 if read-alter-rewrite
- * 3 if set
- * 4 if set and used
- * 0 otherwise (not touched)
- */
-int
-copyu(Prog *p, Adr *v, Adr *s)
-{
-	ProgInfo info;
-
-	switch(p->as) {
-	case AJMP:
-		if(s != nil) {
-			if(copysub(&p->to, v, s, 1))
-				return 1;
-			return 0;
-		}
-		if(copyau(&p->to, v))
-			return 1;
-		return 0;
-
-	case ARET:
-		if(s != nil)
-			return 1;
-		return 3;
-
-	case ACALL:
-		if(REGEXT && v->type <= REGEXT && v->type > exregoffset)
-			return 2;
-		if(REGARG >= 0 && v->type == (uchar)REGARG)
-			return 2;
-		if(v->type == p->from.type)
-			return 2;
-
-		if(s != nil) {
-			if(copysub(&p->to, v, s, 1))
-				return 1;
-			return 0;
-		}
-		if(copyau(&p->to, v))
-			return 4;
-		return 3;
-
-	case ATEXT:
-		if(REGARG >= 0 && v->type == (uchar)REGARG)
-			return 3;
-		return 0;
-	}
-
-	if(p->as == AVARDEF || p->as == AVARKILL)
-		return 0;
-	proginfo(&info, p);
-
-	if((info.reguse|info.regset) & RtoB(v->type))
-		return 2;
-		
-	if(info.flags & LeftAddr)
-		if(copyas(&p->from, v))
-			return 2;
-
-	if((info.flags & (RightRead|RightWrite)) == (RightRead|RightWrite))
-		if(copyas(&p->to, v))
-			return 2;
-	
-	if(info.flags & RightWrite) {
-		if(copyas(&p->to, v)) {
-			if(s != nil)
-				return copysub(&p->from, v, s, 1);
-			if(copyau(&p->from, v))
-				return 4;
-			return 3;
-		}
-	}
-	
-	if(info.flags & (LeftAddr|LeftRead|LeftWrite|RightAddr|RightRead|RightWrite)) {
-		if(s != nil) {
-			if(copysub(&p->from, v, s, 1))
-				return 1;
-			return copysub(&p->to, v, s, 1);
-		}
-		if(copyau(&p->from, v))
-			return 1;
-		if(copyau(&p->to, v))
-			return 1;
-	}
-
-	return 0;
-}
-
-/*
- * direct reference,
- * could be set/use depending on
- * semantics
- */
-static int
-copyas(Adr *a, Adr *v)
-{
-	if(D_AL <= a->type && a->type <= D_R15B)
-		fatal("use of byte register");
-	if(D_AL <= v->type && v->type <= D_R15B)
-		fatal("use of byte register");
-
-	if(a->type != v->type)
-		return 0;
-	if(regtyp(v))
-		return 1;
-	if(v->type == D_AUTO || v->type == D_PARAM)
-		if(v->offset == a->offset)
-			return 1;
-	return 0;
-}
-
-int
-sameaddr(Addr *a, Addr *v)
-{
-	if(a->type != v->type)
-		return 0;
-	if(regtyp(v))
-		return 1;
-	if(v->type == D_AUTO || v->type == D_PARAM)
-		if(v->offset == a->offset)
-			return 1;
-	return 0;
-}
-
-/*
- * either direct or indirect
- */
-static int
-copyau(Adr *a, Adr *v)
-{
-
-	if(copyas(a, v)) {
-		if(debug['P'] && debug['v'])
-			print("\tcopyau: copyas returned 1\n");
-		return 1;
-	}
-	if(regtyp(v)) {
-		if(a->type-D_INDIR == v->type) {
-			if(debug['P'] && debug['v'])
-				print("\tcopyau: found indir use - return 1\n");
-			return 1;
-		}
-		if(a->index == v->type) {
-			if(debug['P'] && debug['v'])
-				print("\tcopyau: found index use - return 1\n");
-			return 1;
-		}
-	}
-	return 0;
-}
-
-/*
- * substitute s for v in a
- * return failure to substitute
- */
-static int
-copysub(Adr *a, Adr *v, Adr *s, int f)
-{
-	int t;
-
-	if(copyas(a, v)) {
-		t = s->type;
-		if(t >= D_AX && t <= D_R15 || t >= D_X0 && t <= D_X0+15) {
-			if(f)
-				a->type = t;
-		}
-		return 0;
-	}
-	if(regtyp(v)) {
-		t = v->type;
-		if(a->type == t+D_INDIR) {
-			if((s->type == D_BP || s->type == D_R13) && a->index != D_NONE)
-				return 1;	/* can't use BP-base with index */
-			if(f)
-				a->type = s->type+D_INDIR;
-//			return 0;
-		}
-		if(a->index == t) {
-			if(f)
-				a->index = s->type;
-			return 0;
-		}
-		return 0;
-	}
-	return 0;
-}
-
-static void
-conprop(Flow *r0)
-{
-	Flow *r;
-	Prog *p, *p0;
-	int t;
-	Adr *v0;
-
-	p0 = r0->prog;
-	v0 = &p0->to;
-	r = r0;
-
-loop:
-	r = uniqs(r);
-	if(r == nil || r == r0)
-		return;
-	if(uniqp(r) == nil)
-		return;
-
-	p = r->prog;
-	t = copyu(p, v0, nil);
-	switch(t) {
-	case 0:	// miss
-	case 1:	// use
-		goto loop;
-
-	case 2:	// rar
-	case 4:	// use and set
-		break;
-
-	case 3:	// set
-		if(p->as == p0->as)
-		if(p->from.type == p0->from.type)
-		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 == D_FCONST && p->from.u.dval == p0->from.u.dval)
-		if(p->from.index == p0->from.index) {
-			excise(r);
-			goto loop;
-		}
-		break;
-	}
-}
-
-int
-smallindir(Addr *a, Addr *reg)
-{
-	return regtyp(reg) &&
-		a->type == D_INDIR + reg->type &&
-		a->index == D_NONE &&
-		0 <= a->offset && a->offset < 4096;
-}
-
-int
-stackaddr(Addr *a)
-{
-	return regtyp(a) && a->type == D_SP;
-}
diff --git a/src/cmd/6g/prog.c b/src/cmd/6g/prog.c
deleted file mode 100644
index ee68399..0000000
--- a/src/cmd/6g/prog.c
+++ /dev/null
@@ -1,318 +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.
-
-#include <u.h>
-#include <libc.h>
-#include "gg.h"
-#include "opt.h"
-
-// Matches real RtoB but can be used in global initializer.
-#define RtoB(r) (1<<((r)-D_AX))
-
-enum {
-	AX = RtoB(D_AX),
-	BX = RtoB(D_BX),
-	CX = RtoB(D_CX),
-	DX = RtoB(D_DX),
-	DI = RtoB(D_DI),
-	SI = RtoB(D_SI),
-	
-	LeftRdwr = LeftRead | LeftWrite,
-	RightRdwr = RightRead | RightWrite,
-};
-
-#undef RtoB
-
-// 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.
-static ProgInfo progtable[ALAST] = {
-	[ATYPE]=	{Pseudo | Skip},
-	[ATEXT]=	{Pseudo},
-	[AFUNCDATA]=	{Pseudo},
-	[APCDATA]=	{Pseudo},
-	[AUNDEF]=	{Break},
-	[AUSEFIELD]=	{OK},
-	[ACHECKNIL]=	{LeftRead},
-	[AVARDEF]=	{Pseudo | RightWrite},
-	[AVARKILL]=	{Pseudo | RightWrite},
-
-	// NOP is an internal no-op that also stands
-	// for USED and SET annotations, not the Intel opcode.
-	[ANOP]=		{LeftRead | RightWrite},
-
-	[AADCL]=	{SizeL | LeftRead | RightRdwr | SetCarry | UseCarry},
-	[AADCQ]=	{SizeQ | LeftRead | RightRdwr | SetCarry | UseCarry},
-	[AADCW]=	{SizeW | LeftRead | RightRdwr | SetCarry | UseCarry},
-
-	[AADDB]=	{SizeB | LeftRead | RightRdwr | SetCarry},
-	[AADDL]=	{SizeL | LeftRead | RightRdwr | SetCarry},
-	[AADDW]=	{SizeW | LeftRead | RightRdwr | SetCarry},
-	[AADDQ]=	{SizeQ | LeftRead | RightRdwr | SetCarry},
-	
-	[AADDSD]=	{SizeD | LeftRead | RightRdwr},
-	[AADDSS]=	{SizeF | LeftRead | RightRdwr},
-
-	[AANDB]=	{SizeB | LeftRead | RightRdwr | SetCarry},
-	[AANDL]=	{SizeL | LeftRead | RightRdwr | SetCarry},
-	[AANDQ]=	{SizeQ | LeftRead | RightRdwr | SetCarry},
-	[AANDW]=	{SizeW | LeftRead | RightRdwr | SetCarry},
-
-	[ACALL]=	{RightAddr | Call | KillCarry},
-
-	[ACDQ]=		{OK, AX, AX | DX},
-	[ACQO]=		{OK, AX, AX | DX},
-	[ACWD]=		{OK, AX, AX | DX},
-
-	[ACLD]=		{OK},
-	[ASTD]=		{OK},
-
-	[ACMPB]=	{SizeB | LeftRead | RightRead | SetCarry},
-	[ACMPL]=	{SizeL | LeftRead | RightRead | SetCarry},
-	[ACMPQ]=	{SizeQ | LeftRead | RightRead | SetCarry},
-	[ACMPW]=	{SizeW | LeftRead | RightRead | SetCarry},
-
-	[ACOMISD]=	{SizeD | LeftRead | RightRead | SetCarry},
-	[ACOMISS]=	{SizeF | LeftRead | RightRead | SetCarry},
-
-	[ACVTSD2SL]=	{SizeL | LeftRead | RightWrite | Conv},
-	[ACVTSD2SQ]=	{SizeQ | LeftRead | RightWrite | Conv},
-	[ACVTSD2SS]=	{SizeF | LeftRead | RightWrite | Conv},
-	[ACVTSL2SD]=	{SizeD | LeftRead | RightWrite | Conv},
-	[ACVTSL2SS]=	{SizeF | LeftRead | RightWrite | Conv},
-	[ACVTSQ2SD]=	{SizeD | LeftRead | RightWrite | Conv},
-	[ACVTSQ2SS]=	{SizeF | LeftRead | RightWrite | Conv},
-	[ACVTSS2SD]=	{SizeD | LeftRead | RightWrite | Conv},
-	[ACVTSS2SL]=	{SizeL | LeftRead | RightWrite | Conv},
-	[ACVTSS2SQ]=	{SizeQ | LeftRead | RightWrite | Conv},
-	[ACVTTSD2SL]=	{SizeL | LeftRead | RightWrite | Conv},
-	[ACVTTSD2SQ]=	{SizeQ | LeftRead | RightWrite | Conv},
-	[ACVTTSS2SL]=	{SizeL | LeftRead | RightWrite | Conv},
-	[ACVTTSS2SQ]=	{SizeQ | LeftRead | RightWrite | Conv},
-
-	[ADECB]=	{SizeB | RightRdwr},
-	[ADECL]=	{SizeL | RightRdwr},
-	[ADECQ]=	{SizeQ | RightRdwr},
-	[ADECW]=	{SizeW | RightRdwr},
-
-	[ADIVB]=	{SizeB | LeftRead | SetCarry, AX, AX},
-	[ADIVL]=	{SizeL | LeftRead | SetCarry, AX|DX, AX|DX},
-	[ADIVQ]=	{SizeQ | LeftRead | SetCarry, AX|DX, AX|DX},
-	[ADIVW]=	{SizeW | LeftRead | SetCarry, AX|DX, AX|DX},
-
-	[ADIVSD]=	{SizeD | LeftRead | RightRdwr},
-	[ADIVSS]=	{SizeF | LeftRead | RightRdwr},
-
-	[AIDIVB]=	{SizeB | LeftRead | SetCarry, AX, AX},
-	[AIDIVL]=	{SizeL | LeftRead | SetCarry, AX|DX, AX|DX},
-	[AIDIVQ]=	{SizeQ | LeftRead | SetCarry, AX|DX, AX|DX},
-	[AIDIVW]=	{SizeW | LeftRead | SetCarry, AX|DX, AX|DX},
-
-	[AIMULB]=	{SizeB | LeftRead | SetCarry, AX, AX},
-	[AIMULL]=	{SizeL | LeftRead | ImulAXDX | SetCarry},
-	[AIMULQ]=	{SizeQ | LeftRead | ImulAXDX | SetCarry},
-	[AIMULW]=	{SizeW | LeftRead | ImulAXDX | SetCarry},
-
-	[AINCB]=	{SizeB | RightRdwr},
-	[AINCL]=	{SizeL | RightRdwr},
-	[AINCQ]=	{SizeQ | RightRdwr},
-	[AINCW]=	{SizeW | RightRdwr},
-
-	[AJCC]=		{Cjmp | UseCarry},
-	[AJCS]=		{Cjmp | UseCarry},
-	[AJEQ]=		{Cjmp | UseCarry},
-	[AJGE]=		{Cjmp | UseCarry},
-	[AJGT]=		{Cjmp | UseCarry},
-	[AJHI]=		{Cjmp | UseCarry},
-	[AJLE]=		{Cjmp | UseCarry},
-	[AJLS]=		{Cjmp | UseCarry},
-	[AJLT]=		{Cjmp | UseCarry},
-	[AJMI]=		{Cjmp | UseCarry},
-	[AJNE]=		{Cjmp | UseCarry},
-	[AJOC]=		{Cjmp | UseCarry},
-	[AJOS]=		{Cjmp | UseCarry},
-	[AJPC]=		{Cjmp | UseCarry},
-	[AJPL]=		{Cjmp | UseCarry},
-	[AJPS]=		{Cjmp | UseCarry},
-
-	[AJMP]=		{Jump | Break | KillCarry},
-
-	[ALEAL]=	{LeftAddr | RightWrite},
-	[ALEAQ]=	{LeftAddr | RightWrite},
-
-	[AMOVBLSX]=	{SizeL | LeftRead | RightWrite | Conv},
-	[AMOVBLZX]=	{SizeL | LeftRead | RightWrite | Conv},
-	[AMOVBQSX]=	{SizeQ | LeftRead | RightWrite | Conv},
-	[AMOVBQZX]=	{SizeQ | LeftRead | RightWrite | Conv},
-	[AMOVBWSX]=	{SizeW | LeftRead | RightWrite | Conv},
-	[AMOVBWZX]=	{SizeW | LeftRead | RightWrite | Conv},
-	[AMOVLQSX]=	{SizeQ | LeftRead | RightWrite | Conv},
-	[AMOVLQZX]=	{SizeQ | LeftRead | RightWrite | Conv},
-	[AMOVWLSX]=	{SizeL | LeftRead | RightWrite | Conv},
-	[AMOVWLZX]=	{SizeL | LeftRead | RightWrite | Conv},
-	[AMOVWQSX]=	{SizeQ | LeftRead | RightWrite | Conv},
-	[AMOVWQZX]=	{SizeQ | LeftRead | RightWrite | Conv},
-	[AMOVQL]=	{SizeL | LeftRead | RightWrite | Conv},
-
-	[AMOVB]=	{SizeB | LeftRead | RightWrite | Move},
-	[AMOVL]=	{SizeL | LeftRead | RightWrite | Move},
-	[AMOVQ]=	{SizeQ | LeftRead | RightWrite | Move},
-	[AMOVW]=	{SizeW | LeftRead | RightWrite | Move},
-
-	[AMOVSB]=	{OK, DI|SI, DI|SI},
-	[AMOVSL]=	{OK, DI|SI, DI|SI},
-	[AMOVSQ]=	{OK, DI|SI, DI|SI},
-	[AMOVSW]=	{OK, DI|SI, DI|SI},
-	[ADUFFCOPY]=	{OK, DI|SI, DI|SI|CX},
-
-	[AMOVSD]=	{SizeD | LeftRead | RightWrite | Move},
-	[AMOVSS]=	{SizeF | LeftRead | RightWrite | Move},
-
-	// We use MOVAPD as a faster synonym for MOVSD.
-	[AMOVAPD]=	{SizeD | LeftRead | RightWrite | Move},
-
-	[AMULB]=	{SizeB | LeftRead | SetCarry, AX, AX},
-	[AMULL]=	{SizeL | LeftRead | SetCarry, AX, AX|DX},
-	[AMULQ]=	{SizeQ | LeftRead | SetCarry, AX, AX|DX},
-	[AMULW]=	{SizeW | LeftRead | SetCarry, AX, AX|DX},
-	
-	[AMULSD]=	{SizeD | LeftRead | RightRdwr},
-	[AMULSS]=	{SizeF | LeftRead | RightRdwr},
-
-	[ANEGB]=	{SizeB | RightRdwr | SetCarry},
-	[ANEGL]=	{SizeL | RightRdwr | SetCarry},
-	[ANEGQ]=	{SizeQ | RightRdwr | SetCarry},
-	[ANEGW]=	{SizeW | RightRdwr | SetCarry},
-
-	[ANOTB]=	{SizeB | RightRdwr},
-	[ANOTL]=	{SizeL | RightRdwr},
-	[ANOTQ]=	{SizeQ | RightRdwr},
-	[ANOTW]=	{SizeW | RightRdwr},
-
-	[AORB]=		{SizeB | LeftRead | RightRdwr | SetCarry},
-	[AORL]=		{SizeL | LeftRead | RightRdwr | SetCarry},
-	[AORQ]=		{SizeQ | LeftRead | RightRdwr | SetCarry},
-	[AORW]=		{SizeW | LeftRead | RightRdwr | SetCarry},
-
-	[APOPQ]=	{SizeQ | RightWrite},
-	[APUSHQ]=	{SizeQ | LeftRead},
-
-	[ARCLB]=	{SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
-	[ARCLL]=	{SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
-	[ARCLQ]=	{SizeQ | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
-	[ARCLW]=	{SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
-
-	[ARCRB]=	{SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
-	[ARCRL]=	{SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
-	[ARCRQ]=	{SizeQ | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
-	[ARCRW]=	{SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
-
-	[AREP]=		{OK, CX, CX},
-	[AREPN]=	{OK, CX, CX},
-
-	[ARET]=		{Break | KillCarry},
-
-	[AROLB]=	{SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry},
-	[AROLL]=	{SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry},
-	[AROLQ]=	{SizeQ | LeftRead | RightRdwr | ShiftCX | SetCarry},
-	[AROLW]=	{SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry},
-
-	[ARORB]=	{SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry},
-	[ARORL]=	{SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry},
-	[ARORQ]=	{SizeQ | LeftRead | RightRdwr | ShiftCX | SetCarry},
-	[ARORW]=	{SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry},
-
-	[ASALB]=	{SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry},
-	[ASALL]=	{SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry},
-	[ASALQ]=	{SizeQ | LeftRead | RightRdwr | ShiftCX | SetCarry},
-	[ASALW]=	{SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry},
-
-	[ASARB]=	{SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry},
-	[ASARL]=	{SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry},
-	[ASARQ]=	{SizeQ | LeftRead | RightRdwr | ShiftCX | SetCarry},
-	[ASARW]=	{SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry},
-
-	[ASBBB]=	{SizeB | LeftRead | RightRdwr | SetCarry | UseCarry},
-	[ASBBL]=	{SizeL | LeftRead | RightRdwr | SetCarry | UseCarry},
-	[ASBBQ]=	{SizeQ | LeftRead | RightRdwr | SetCarry | UseCarry},
-	[ASBBW]=	{SizeW | LeftRead | RightRdwr | SetCarry | UseCarry},
-
-	[ASHLB]=	{SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry},
-	[ASHLL]=	{SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry},
-	[ASHLQ]=	{SizeQ | LeftRead | RightRdwr | ShiftCX | SetCarry},
-	[ASHLW]=	{SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry},
-
-	[ASHRB]=	{SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry},
-	[ASHRL]=	{SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry},
-	[ASHRQ]=	{SizeQ | LeftRead | RightRdwr | ShiftCX | SetCarry},
-	[ASHRW]=	{SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry},
-
-	[ASTOSB]=	{OK, AX|DI, DI},
-	[ASTOSL]=	{OK, AX|DI, DI},
-	[ASTOSQ]=	{OK, AX|DI, DI},
-	[ASTOSW]=	{OK, AX|DI, DI},
-	[ADUFFZERO]=	{OK, AX|DI, DI},
-
-	[ASUBB]=	{SizeB | LeftRead | RightRdwr | SetCarry},
-	[ASUBL]=	{SizeL | LeftRead | RightRdwr | SetCarry},
-	[ASUBQ]=	{SizeQ | LeftRead | RightRdwr | SetCarry},
-	[ASUBW]=	{SizeW | LeftRead | RightRdwr | SetCarry},
-
-	[ASUBSD]=	{SizeD | LeftRead | RightRdwr},
-	[ASUBSS]=	{SizeF | LeftRead | RightRdwr},
-
-	[ATESTB]=	{SizeB | LeftRead | RightRead | SetCarry},
-	[ATESTL]=	{SizeL | LeftRead | RightRead | SetCarry},
-	[ATESTQ]=	{SizeQ | LeftRead | RightRead | SetCarry},
-	[ATESTW]=	{SizeW | LeftRead | RightRead | SetCarry},
-
-	[AUCOMISD]=	{SizeD | LeftRead | RightRead},
-	[AUCOMISS]=	{SizeF | LeftRead | RightRead},
-
-	[AXCHGB]=	{SizeB | LeftRdwr | RightRdwr},
-	[AXCHGL]=	{SizeL | LeftRdwr | RightRdwr},
-	[AXCHGQ]=	{SizeQ | LeftRdwr | RightRdwr},
-	[AXCHGW]=	{SizeW | LeftRdwr | RightRdwr},
-
-	[AXORB]=	{SizeB | LeftRead | RightRdwr | SetCarry},
-	[AXORL]=	{SizeL | LeftRead | RightRdwr | SetCarry},
-	[AXORQ]=	{SizeQ | LeftRead | RightRdwr | SetCarry},
-	[AXORW]=	{SizeW | LeftRead | RightRdwr | SetCarry},
-};
-
-void
-proginfo(ProgInfo *info, Prog *p)
-{
-	*info = progtable[p->as];
-	if(info->flags == 0)
-		fatal("unknown instruction %P", p);
-
-	if((info->flags & ShiftCX) && p->from.type != D_CONST)
-		info->reguse |= CX;
-
-	if(info->flags & ImulAXDX) {
-		if(p->to.type == D_NONE) {
-			info->reguse |= AX;
-			info->regset |= AX | DX;
-		} else {
-			info->flags |= RightRdwr;
-		}
-	}
-
-	// Addressing makes some registers used.
-	if(p->from.type >= D_INDIR)
-		info->regindex |= RtoB(p->from.type-D_INDIR);
-	if(p->from.index != D_NONE)
-		info->regindex |= RtoB(p->from.index);
-	if(p->to.type >= D_INDIR)
-		info->regindex |= RtoB(p->to.type-D_INDIR);
-	if(p->to.index != D_NONE)
-		info->regindex |= RtoB(p->to.index);
-}
diff --git a/src/cmd/6g/reg.c b/src/cmd/6g/reg.c
deleted file mode 100644
index 1f757e1..0000000
--- a/src/cmd/6g/reg.c
+++ /dev/null
@@ -1,1315 +0,0 @@
-// 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 at 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 at 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.
-
-#include <u.h>
-#include <libc.h>
-#include "gg.h"
-#include "opt.h"
-
-#define	NREGVAR	32	/* 16 general + 16 floating */
-#define	REGBITS	((uint32)0xffffffff)
-/*c2go enum {
-	NREGVAR = 32,
-	REGBITS = 0xffffffff,
-};
-*/
-
-static	Reg*	firstr;
-static	int	first	= 1;
-
-int
-rcmp(const void *a1, const void *a2)
-{
-	Rgn *p1, *p2;
-	int c1, c2;
-
-	p1 = (Rgn*)a1;
-	p2 = (Rgn*)a2;
-	c1 = p2->cost;
-	c2 = p1->cost;
-	if(c1 -= c2)
-		return c1;
-	return p2->varno - p1->varno;
-}
-
-static void
-setaddrs(Bits bit)
-{
-	int i, n;
-	Var *v;
-	Node *node;
-
-	while(bany(&bit)) {
-		// convert each bit to a variable
-		i = bnum(bit);
-		node = var[i].node;
-		n = var[i].name;
-		bit.b[i/32] &= ~(1L<<(i%32));
-
-		// disable all pieces of that variable
-		for(i=0; i<nvar; i++) {
-			v = var+i;
-			if(v->node == node && v->name == n)
-				v->addr = 2;
-		}
-	}
-}
-
-static char* regname[] = {
-	".AX",
-	".CX",
-	".DX",
-	".BX",
-	".SP",
-	".BP",
-	".SI",
-	".DI",
-	".R8",
-	".R9",
-	".R10",
-	".R11",
-	".R12",
-	".R13",
-	".R14",
-	".R15",
-	".X0",
-	".X1",
-	".X2",
-	".X3",
-	".X4",
-	".X5",
-	".X6",
-	".X7",
-	".X8",
-	".X9",
-	".X10",
-	".X11",
-	".X12",
-	".X13",
-	".X14",
-	".X15",
-};
-
-static Node* regnodes[NREGVAR];
-
-static void walkvardef(Node *n, Reg *r, int active);
-
-void
-regopt(Prog *firstp)
-{
-	Reg *r, *r1;
-	Prog *p;
-	Graph *g;
-	ProgInfo info;
-	int i, z, active;
-	uint32 vreg;
-	Bits bit;
-
-	if(first) {
-		fmtinstall('Q', Qconv);
-		exregoffset = D_R15;
-		first = 0;
-	}
-
-	mergetemp(firstp);
-
-	/*
-	 * control flow is more complicated in generated go code
-	 * than in generated c code.  define pseudo-variables for
-	 * registers, so we have complete register usage information.
-	 */
-	nvar = NREGVAR;
-	memset(var, 0, NREGVAR*sizeof var[0]);
-	for(i=0; i<NREGVAR; i++) {
-		if(regnodes[i] == N)
-			regnodes[i] = newname(lookup(regname[i]));
-		var[i].node = regnodes[i];
-	}
-
-	regbits = RtoB(D_SP);
-	for(z=0; z<BITS; z++) {
-		externs.b[z] = 0;
-		params.b[z] = 0;
-		consts.b[z] = 0;
-		addrs.b[z] = 0;
-		ivar.b[z] = 0;
-		ovar.b[z] = 0;
-	}
-
-	/*
-	 * pass 1
-	 * build aux data structure
-	 * allocate pcs
-	 * find use and set of variables
-	 */
-	g = flowstart(firstp, sizeof(Reg));
-	if(g == nil) {
-		for(i=0; i<nvar; i++)
-			var[i].node->opt = nil;
-		return;
-	}
-
-	firstr = (Reg*)g->start;
-
-	for(r = firstr; r != R; r = (Reg*)r->f.link) {
-		p = r->f.prog;
-		if(p->as == AVARDEF || p->as == AVARKILL)
-			continue;
-		proginfo(&info, p);
-
-		// Avoid making variables for direct-called functions.
-		if(p->as == ACALL && p->to.type == D_EXTERN)
-			continue;
-
-		r->use1.b[0] |= info.reguse | info.regindex;
-		r->set.b[0] |= info.regset;
-
-		bit = mkvar(r, &p->from);
-		if(bany(&bit)) {
-			if(info.flags & LeftAddr)
-				setaddrs(bit);
-			if(info.flags & LeftRead)
-				for(z=0; z<BITS; z++)
-					r->use1.b[z] |= bit.b[z];
-			if(info.flags & LeftWrite)
-				for(z=0; z<BITS; z++)
-					r->set.b[z] |= bit.b[z];
-		}
-
-		bit = mkvar(r, &p->to);
-		if(bany(&bit)) {	
-			if(info.flags & RightAddr)
-				setaddrs(bit);
-			if(info.flags & RightRead)
-				for(z=0; z<BITS; z++)
-					r->use2.b[z] |= bit.b[z];
-			if(info.flags & RightWrite)
-				for(z=0; z<BITS; z++)
-					r->set.b[z] |= bit.b[z];
-		}
-	}
-
-	for(i=0; i<nvar; i++) {
-		Var *v = var+i;
-		if(v->addr) {
-			bit = blsh(i);
-			for(z=0; z<BITS; z++)
-				addrs.b[z] |= bit.b[z];
-		}
-
-		if(debug['R'] && debug['v'])
-			print("bit=%2d addr=%d et=%-6E w=%-2d s=%N + %lld\n",
-				i, v->addr, v->etype, v->width, v->node, v->offset);
-	}
-
-	if(debug['R'] && debug['v'])
-		dumpit("pass1", &firstr->f, 1);
-
-	/*
-	 * pass 2
-	 * find looping structure
-	 */
-	flowrpo(g);
-
-	if(debug['R'] && debug['v'])
-		dumpit("pass2", &firstr->f, 1);
-
-	/*
-	 * pass 2.5
-	 * iterate propagating fat vardef covering forward
-	 * r->act records vars with a VARDEF since the last CALL.
-	 * (r->act will be reused in pass 5 for something else,
-	 * but we'll be done with it by then.)
-	 */
-	active = 0;
-	for(r = firstr; r != R; r = (Reg*)r->f.link) {
-		r->f.active = 0;
-		r->act = zbits;
-	}
-	for(r = firstr; r != R; r = (Reg*)r->f.link) {
-		p = r->f.prog;
-		if(p->as == AVARDEF && isfat(p->to.node->type) && p->to.node->opt != nil) {
-			active++;
-			walkvardef(p->to.node, r, active);
-		}
-	}
-
-	/*
-	 * pass 3
-	 * iterate propagating usage
-	 * 	back until flow graph is complete
-	 */
-loop1:
-	change = 0;
-	for(r = firstr; r != R; r = (Reg*)r->f.link)
-		r->f.active = 0;
-	for(r = firstr; r != R; r = (Reg*)r->f.link)
-		if(r->f.prog->as == ARET)
-			prop(r, zbits, zbits);
-loop11:
-	/* pick up unreachable code */
-	i = 0;
-	for(r = firstr; r != R; r = r1) {
-		r1 = (Reg*)r->f.link;
-		if(r1 && r1->f.active && !r->f.active) {
-			prop(r, zbits, zbits);
-			i = 1;
-		}
-	}
-	if(i)
-		goto loop11;
-	if(change)
-		goto loop1;
-
-	if(debug['R'] && debug['v'])
-		dumpit("pass3", &firstr->f, 1);
-
-	/*
-	 * pass 4
-	 * iterate propagating register/variable synchrony
-	 * 	forward until graph is complete
-	 */
-loop2:
-	change = 0;
-	for(r = firstr; r != R; r = (Reg*)r->f.link)
-		r->f.active = 0;
-	synch(firstr, zbits);
-	if(change)
-		goto loop2;
-
-	if(debug['R'] && debug['v'])
-		dumpit("pass4", &firstr->f, 1);
-
-	/*
-	 * pass 4.5
-	 * move register pseudo-variables into regu.
-	 */
-	for(r = firstr; r != R; r = (Reg*)r->f.link) {
-		r->regu = (r->refbehind.b[0] | r->set.b[0]) & REGBITS;
-
-		r->set.b[0] &= ~REGBITS;
-		r->use1.b[0] &= ~REGBITS;
-		r->use2.b[0] &= ~REGBITS;
-		r->refbehind.b[0] &= ~REGBITS;
-		r->refahead.b[0] &= ~REGBITS;
-		r->calbehind.b[0] &= ~REGBITS;
-		r->calahead.b[0] &= ~REGBITS;
-		r->regdiff.b[0] &= ~REGBITS;
-		r->act.b[0] &= ~REGBITS;
-	}
-
-	/*
-	 * pass 5
-	 * isolate regions
-	 * calculate costs (paint1)
-	 */
-	r = firstr;
-	if(r) {
-		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]);
-		if(bany(&bit) && !r->f.refset) {
-			// should never happen - all variables are preset
-			if(debug['w'])
-				print("%L: used and not set: %Q\n", r->f.prog->lineno, bit);
-			r->f.refset = 1;
-		}
-	}
-	for(r = firstr; r != R; r = (Reg*)r->f.link)
-		r->act = zbits;
-	rgp = region;
-	nregion = 0;
-	for(r = firstr; r != R; r = (Reg*)r->f.link) {
-		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) && !r->f.refset) {
-			if(debug['w'])
-				print("%L: set and not used: %Q\n", r->f.prog->lineno, bit);
-			r->f.refset = 1;
-			excise(&r->f);
-		}
-		for(z=0; z<BITS; z++)
-			bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]);
-		while(bany(&bit)) {
-			i = bnum(bit);
-			rgp->enter = r;
-			rgp->varno = i;
-			change = 0;
-			paint1(r, i);
-			bit.b[i/32] &= ~(1L<<(i%32));
-			if(change <= 0)
-				continue;
-			rgp->cost = change;
-			nregion++;
-			if(nregion >= NRGN) {
-				if(debug['R'] && debug['v'])
-					print("too many regions\n");
-				goto brk;
-			}
-			rgp++;
-		}
-	}
-brk:
-	qsort(region, nregion, sizeof(region[0]), rcmp);
-
-	if(debug['R'] && debug['v'])
-		dumpit("pass5", &firstr->f, 1);
-
-	/*
-	 * pass 6
-	 * determine used registers (paint2)
-	 * replace code (paint3)
-	 */
-	rgp = region;
-	for(i=0; i<nregion; i++) {
-		bit = blsh(rgp->varno);
-		vreg = paint2(rgp->enter, rgp->varno);
-		vreg = allreg(vreg, rgp);
-		if(rgp->regno != 0) {
-			if(debug['R'] && debug['v']) {
-				Var *v;
-
-				v = var + rgp->varno;
-				print("registerize %N+%lld (bit=%2d et=%2E) in %R\n",
-						v->node, v->offset, rgp->varno, v->etype, rgp->regno);
-			}
-			paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
-		}
-		rgp++;
-	}
-
-	if(debug['R'] && debug['v'])
-		dumpit("pass6", &firstr->f, 1);
-	
-	/*
-	 * free aux structures. peep allocates new ones.
-	 */
-	for(i=0; i<nvar; i++)
-		var[i].node->opt = nil;
-	flowend(g);
-	firstr = R;
-
-	/*
-	 * pass 7
-	 * peep-hole on basic block
-	 */
-	if(!debug['R'] || debug['P'])
-		peep(firstp);
-
-	/*
-	 * eliminate nops
-	 */
-	for(p=firstp; p!=P; p=p->link) {
-		while(p->link != P && p->link->as == ANOP)
-			p->link = p->link->link;
-		if(p->to.type == D_BRANCH)
-			while(p->to.u.branch != P && p->to.u.branch->as == ANOP)
-				p->to.u.branch = p->to.u.branch->link;
-	}
-
-	if(debug['R']) {
-		if(ostats.ncvtreg ||
-		   ostats.nspill ||
-		   ostats.nreload ||
-		   ostats.ndelmov ||
-		   ostats.nvar ||
-		   ostats.naddr ||
-		   0)
-			print("\nstats\n");
-
-		if(ostats.ncvtreg)
-			print("	%4d cvtreg\n", ostats.ncvtreg);
-		if(ostats.nspill)
-			print("	%4d spill\n", ostats.nspill);
-		if(ostats.nreload)
-			print("	%4d reload\n", ostats.nreload);
-		if(ostats.ndelmov)
-			print("	%4d delmov\n", ostats.ndelmov);
-		if(ostats.nvar)
-			print("	%4d var\n", ostats.nvar);
-		if(ostats.naddr)
-			print("	%4d addr\n", ostats.naddr);
-
-		memset(&ostats, 0, sizeof(ostats));
-	}
-}
-
-static void
-walkvardef(Node *n, Reg *r, int active)
-{
-	Reg *r1, *r2;
-	int bn;
-	Var *v;
-	
-	for(r1=r; r1!=R; r1=(Reg*)r1->f.s1) {
-		if(r1->f.active == active)
-			break;
-		r1->f.active = active;
-		if(r1->f.prog->as == AVARKILL && r1->f.prog->to.node == n)
-			break;
-		for(v=n->opt; v!=nil; v=v->nextinnode) {
-			bn = v - var;
-			r1->act.b[bn/32] |= 1L << (bn%32);
-		}
-		if(r1->f.prog->as == ACALL)
-			break;
-	}
-
-	for(r2=r; r2!=r1; r2=(Reg*)r2->f.s1)
-		if(r2->f.s2 != nil)
-			walkvardef(n, (Reg*)r2->f.s2, active);
-}
-
-/*
- * add mov b,rn
- * just after r
- */
-void
-addmove(Reg *r, int bn, int rn, int f)
-{
-	Prog *p, *p1;
-	Adr *a;
-	Var *v;
-
-	p1 = mal(sizeof(*p1));
-	clearp(p1);
-	p1->pc = 9999;
-
-	p = r->f.prog;
-	p1->link = p->link;
-	p->link = p1;
-	p1->lineno = p->lineno;
-
-	v = var + bn;
-
-	a = &p1->to;
-	a->offset = v->offset;
-	a->etype = v->etype;
-	a->type = v->name;
-	a->node = v->node;
-	a->sym = linksym(v->node->sym);
-
-	// need to clean this up with wptr and
-	// some of the defaults
-	p1->as = AMOVL;
-	switch(simtype[(uchar)v->etype]) {
-	default:
-		fatal("unknown type %E", v->etype);
-	case TINT8:
-	case TUINT8:
-	case TBOOL:
-		p1->as = AMOVB;
-		break;
-	case TINT16:
-	case TUINT16:
-		p1->as = AMOVW;
-		break;
-	case TINT64:
-	case TUINT64:
-	case TPTR64:
-		p1->as = AMOVQ;
-		break;
-	case TFLOAT32:
-		p1->as = AMOVSS;
-		break;
-	case TFLOAT64:
-		p1->as = AMOVSD;
-		break;
-	case TINT32:
-	case TUINT32:
-	case TPTR32:
-		break;
-	}
-
-	p1->from.type = rn;
-	if(!f) {
-		p1->from = *a;
-		*a = zprog.from;
-		a->type = rn;
-		if(v->etype == TUINT8)
-			p1->as = AMOVB;
-		if(v->etype == TUINT16)
-			p1->as = AMOVW;
-	}
-	if(debug['R'] && debug['v'])
-		print("%P ===add=== %P\n", p, p1);
-	ostats.nspill++;
-}
-
-uint32
-doregbits(int r)
-{
-	uint32 b;
-
-	b = 0;
-	if(r >= D_INDIR)
-		r -= D_INDIR;
-	if(r >= D_AX && r <= D_R15)
-		b |= RtoB(r);
-	else
-	if(r >= D_AL && r <= D_R15B)
-		b |= RtoB(r-D_AL+D_AX);
-	else
-	if(r >= D_AH && r <= D_BH)
-		b |= RtoB(r-D_AH+D_AX);
-	else
-	if(r >= D_X0 && r <= D_X0+15)
-		b |= FtoB(r);
-	return b;
-}
-
-static int
-overlap(int64 o1, int w1, int64 o2, int w2)
-{
-	int64 t1, t2;
-
-	t1 = o1+w1;
-	t2 = o2+w2;
-
-	if(!(t1 > o2 && t2 > o1))
-		return 0;
-
-	return 1;
-}
-
-Bits
-mkvar(Reg *r, Adr *a)
-{
-	Var *v;
-	int i, t, n, et, z, flag;
-	int64 w;
-	uint32 regu;
-	int64 o;
-	Bits bit;
-	Node *node;
-
-	/*
-	 * mark registers used
-	 */
-	t = a->type;
-	if(t == D_NONE)
-		goto none;
-
-	if(r != R)
-		r->use1.b[0] |= doregbits(a->index);
-
-	switch(t) {
-	default:
-		regu = doregbits(t);
-		if(regu == 0)
-			goto none;
-		bit = zbits;
-		bit.b[0] = regu;
-		return bit;
-
-	case D_ADDR:
-		a->type = a->index;
-		bit = mkvar(r, a);
-		setaddrs(bit);
-		a->type = t;
-		ostats.naddr++;
-		goto none;
-
-	case D_EXTERN:
-	case D_STATIC:
-	case D_PARAM:
-	case D_AUTO:
-		n = t;
-		break;
-	}
-
-	node = a->node;
-	if(node == N || node->op != ONAME || node->orig == N)
-		goto none;
-	node = node->orig;
-	if(node->orig != node)
-		fatal("%D: bad node", a);
-	if(node->sym == S || node->sym->name[0] == '.')
-		goto none;
-	et = a->etype;
-	o = a->offset;
-	w = a->width;
-	if(w < 0)
-		fatal("bad width %lld for %D", w, a);
-
-	flag = 0;
-	for(i=0; i<nvar; i++) {
-		v = var+i;
-		if(v->node == node && v->name == n) {
-			if(v->offset == o)
-			if(v->etype == et)
-			if(v->width == w)
-				return blsh(i);
-
-			// if they overlaps, disable both
-			if(overlap(v->offset, v->width, o, w)) {
-//				print("disable overlap %s %d %d %d %d, %E != %E\n", s->name, v->offset, v->width, o, w, v->etype, et);
-				v->addr = 1;
-				flag = 1;
-			}
-		}
-	}
-	switch(et) {
-	case 0:
-	case TFUNC:
-		goto none;
-	}
-
-	if(nvar >= NVAR) {
-		if(debug['w'] > 1 && node != N)
-			fatal("variable not optimized: %#N", node);
-		
-		// 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
-		// live at all calls. otherwise we might optimize away part of
-		// a variable but not all of it.
-		for(i=0; i<nvar; i++) {
-			v = var+i;
-			if(v->node == node)
-				v->addr = 1;
-		}
-		goto none;
-	}
-
-	i = nvar;
-	nvar++;
-	v = var+i;
-	v->offset = o;
-	v->name = n;
-	v->etype = et;
-	v->width = w;
-	v->addr = flag;		// funny punning
-	v->node = node;
-	
-	// node->opt is the head of a linked list
-	// of Vars within the given Node, so that
-	// we can start at a Var and find all the other
-	// Vars in the same Go variable.
-	v->nextinnode = node->opt;
-	node->opt = v;
-
-	bit = blsh(i);
-	if(n == D_EXTERN || n == D_STATIC)
-		for(z=0; z<BITS; z++)
-			externs.b[z] |= bit.b[z];
-	if(n == D_PARAM)
-		for(z=0; z<BITS; z++)
-			params.b[z] |= bit.b[z];
-
-	if(node->class == PPARAM)
-		for(z=0; z<BITS; z++)
-			ivar.b[z] |= bit.b[z];
-	if(node->class == PPARAMOUT)
-		for(z=0; z<BITS; z++)
-			ovar.b[z] |= bit.b[z];
-
-	// Treat values with their address taken as live at calls,
-	// because the garbage collector's liveness analysis in ../gc/plive.c does.
-	// These must be consistent or else we will elide stores and the garbage
-	// collector will see uninitialized data.
-	// The typical case where our own analysis is out of sync is when the
-	// node appears to have its address taken but that code doesn't actually
-	// get generated and therefore doesn't show up as an address being
-	// taken when we analyze the instruction stream.
-	// One instance of this case is when a closure uses the same name as
-	// an outer variable for one of its own variables declared with :=.
-	// The parser flags the outer variable as possibly shared, and therefore
-	// sets addrtaken, even though it ends up not being actually shared.
-	// 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)
-		v->addr = 1;
-
-	// Disable registerization for globals, because:
-	// (1) we might panic at any time and we want the recovery code
-	// to see the latest values (issue 1304).
-	// (2) we don't know what pointers might point at them and we want
-	// loads via those pointers to see updated values and vice versa (issue 7995).
-	//
-	// Disable registerization for results if using defer, because the deferred func
-	// might recover and return, causing the current values to be used.
-	if(node->class == PEXTERN || (hasdefer && node->class == PPARAMOUT))
-		v->addr = 1;
-
-	if(debug['R'])
-		print("bit=%2d et=%2E w=%lld+%lld %#N %D flag=%d\n", i, et, o, w, node, a, v->addr);
-	ostats.nvar++;
-
-	return bit;
-
-none:
-	return zbits;
-}
-
-void
-prop(Reg *r, Bits ref, Bits cal)
-{
-	Reg *r1, *r2;
-	int z, i, j;
-	Var *v, *v1;
-
-	for(r1 = r; r1 != R; r1 = (Reg*)r1->f.p1) {
-		for(z=0; z<BITS; z++) {
-			ref.b[z] |= r1->refahead.b[z];
-			if(ref.b[z] != r1->refahead.b[z]) {
-				r1->refahead.b[z] = ref.b[z];
-				change++;
-			}
-			cal.b[z] |= r1->calahead.b[z];
-			if(cal.b[z] != r1->calahead.b[z]) {
-				r1->calahead.b[z] = cal.b[z];
-				change++;
-			}
-		}
-		switch(r1->f.prog->as) {
-		case ACALL:
-			if(noreturn(r1->f.prog))
-				break;
-
-			// Mark all input variables (ivar) as used, because that's what the
-			// liveness bitmaps say. The liveness bitmaps say that so that a
-			// panic will not show stale values in the parameter dump.
-			// Mark variables with a recent VARDEF (r1->act) as used,
-			// so that the optimizer flushes initializations to memory,
-			// so that if a garbage collection happens during this CALL,
-			// the collector will see initialized memory. Again this is to
-			// match what the liveness bitmaps say.
-			for(z=0; z<BITS; z++) {
-				cal.b[z] |= ref.b[z] | externs.b[z] | ivar.b[z] | r1->act.b[z];
-				ref.b[z] = 0;
-			}
-			
-			// cal.b is the current approximation of what's live across the call.
-			// Every bit in cal.b is a single stack word. For each such word,
-			// find all the other tracked stack words in the same Go variable
-			// (struct/slice/string/interface) and mark them live too.
-			// This is necessary because the liveness analysis for the garbage
-			// collector works at variable granularity, not at word granularity.
-			// It is fundamental for slice/string/interface: the garbage collector
-			// needs the whole value, not just some of the words, in order to
-			// interpret the other bits correctly. Specifically, slice needs a consistent
-			// ptr and cap, string needs a consistent ptr and len, and interface
-			// needs a consistent type word and data word.
-			for(z=0; z<BITS; z++) {
-				if(cal.b[z] == 0)
-					continue;
-				for(i=0; i<32; i++) {
-					if(z*32+i >= nvar || ((cal.b[z]>>i)&1) == 0)
-						continue;
-					v = var+z*32+i;
-					if(v->node->opt == nil) // v represents fixed register, not Go variable
-						continue;
-
-					// v->node->opt is the head of a linked list of Vars
-					// corresponding to tracked words from the Go variable v->node.
-					// Walk the list and set all the bits.
-					// For a large struct this could end up being quadratic:
-					// after the first setting, the outer loop (for z, i) would see a 1 bit
-					// for all of the remaining words in the struct, and for each such
-					// word would go through and turn on all the bits again.
-					// To avoid the quadratic behavior, we only turn on the bits if
-					// v is the head of the list or if the head's bit is not yet turned on.
-					// This will set the bits at most twice, keeping the overall loop linear.
-					v1 = v->node->opt;
-					j = v1 - var;
-					if(v == v1 || ((cal.b[j/32]>>(j&31))&1) == 0) {
-						for(; v1 != nil; v1 = v1->nextinnode) {
-							j = v1 - var;
-							cal.b[j/32] |= 1UL<<(j&31);
-						}
-					}
-				}
-			}
-			break;
-
-		case ATEXT:
-			for(z=0; z<BITS; z++) {
-				cal.b[z] = 0;
-				ref.b[z] = 0;
-			}
-			break;
-
-		case ARET:
-			for(z=0; z<BITS; z++) {
-				cal.b[z] = externs.b[z] | ovar.b[z];
-				ref.b[z] = 0;
-			}
-			break;
-		}
-		for(z=0; z<BITS; z++) {
-			ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
-				r1->use1.b[z] | r1->use2.b[z];
-			cal.b[z] &= ~(r1->set.b[z] | r1->use1.b[z] | r1->use2.b[z]);
-			r1->refbehind.b[z] = ref.b[z];
-			r1->calbehind.b[z] = cal.b[z];
-		}
-		if(r1->f.active)
-			break;
-		r1->f.active = 1;
-	}
-	for(; r != r1; r = (Reg*)r->f.p1)
-		for(r2 = (Reg*)r->f.p2; r2 != R; r2 = (Reg*)r2->f.p2link)
-			prop(r2, r->refbehind, r->calbehind);
-}
-
-void
-synch(Reg *r, Bits dif)
-{
-	Reg *r1;
-	int z;
-
-	for(r1 = r; r1 != R; r1 = (Reg*)r1->f.s1) {
-		for(z=0; z<BITS; z++) {
-			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++;
-			}
-		}
-		if(r1->f.active)
-			break;
-		r1->f.active = 1;
-		for(z=0; z<BITS; z++)
-			dif.b[z] &= ~(~r1->calbehind.b[z] & r1->calahead.b[z]);
-		if(r1->f.s2 != nil)
-			synch((Reg*)r1->f.s2, dif);
-	}
-}
-
-uint32
-allreg(uint32 b, Rgn *r)
-{
-	Var *v;
-	int i;
-
-	v = var + r->varno;
-	r->regno = 0;
-	switch(v->etype) {
-
-	default:
-		fatal("unknown etype %d/%E", bitno(b), v->etype);
-		break;
-
-	case TINT8:
-	case TUINT8:
-	case TINT16:
-	case TUINT16:
-	case TINT32:
-	case TUINT32:
-	case TINT64:
-	case TUINT64:
-	case TINT:
-	case TUINT:
-	case TUINTPTR:
-	case TBOOL:
-	case TPTR32:
-	case TPTR64:
-		i = BtoR(~b);
-		if(i && r->cost > 0) {
-			r->regno = i;
-			return RtoB(i);
-		}
-		break;
-
-	case TFLOAT32:
-	case TFLOAT64:
-		i = BtoF(~b);
-		if(i && r->cost > 0) {
-			r->regno = i;
-			return FtoB(i);
-		}
-		break;
-	}
-	return 0;
-}
-
-void
-paint1(Reg *r, int bn)
-{
-	Reg *r1;
-	int z;
-	uint32 bb;
-
-	z = bn/32;
-	bb = 1L<<(bn%32);
-	if(r->act.b[z] & bb)
-		return;
-	for(;;) {
-		if(!(r->refbehind.b[z] & bb))
-			break;
-		r1 = (Reg*)r->f.p1;
-		if(r1 == R)
-			break;
-		if(!(r1->refahead.b[z] & bb))
-			break;
-		if(r1->act.b[z] & bb)
-			break;
-		r = r1;
-	}
-
-	if(LOAD(r) & ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z])) & bb) {
-		change -= CLOAD * r->f.loop;
-	}
-	for(;;) {
-		r->act.b[z] |= bb;
-
-		if(r->f.prog->as != ANOP) { // don't give credit for NOPs
-			if(r->use1.b[z] & bb)
-				change += CREF * r->f.loop;
-			if((r->use2.b[z]|r->set.b[z]) & bb)
-				change += CREF * r->f.loop;
-		}
-
-		if(STORE(r) & r->regdiff.b[z] & bb) {
-			change -= CLOAD * r->f.loop;
-		}
-
-		if(r->refbehind.b[z] & bb)
-			for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link)
-				if(r1->refahead.b[z] & bb)
-					paint1(r1, bn);
-
-		if(!(r->refahead.b[z] & bb))
-			break;
-		r1 = (Reg*)r->f.s2;
-		if(r1 != R)
-			if(r1->refbehind.b[z] & bb)
-				paint1(r1, bn);
-		r = (Reg*)r->f.s1;
-		if(r == R)
-			break;
-		if(r->act.b[z] & bb)
-			break;
-		if(!(r->refbehind.b[z] & bb))
-			break;
-	}
-}
-
-uint32
-regset(Reg *r, uint32 bb)
-{
-	uint32 b, set;
-	Adr v;
-	int c;
-
-	set = 0;
-	v = zprog.from;
-	while(b = bb & ~(bb-1)) {
-		v.type = b & 0xFFFF? BtoR(b): BtoF(b);
-		if(v.type == 0)
-			fatal("zero v.type for %#ux", b);
-		c = copyu(r->f.prog, &v, nil);
-		if(c == 3)
-			set |= b;
-		bb &= ~b;
-	}
-	return set;
-}
-
-uint32
-reguse(Reg *r, uint32 bb)
-{
-	uint32 b, set;
-	Adr v;
-	int c;
-
-	set = 0;
-	v = zprog.from;
-	while(b = bb & ~(bb-1)) {
-		v.type = b & 0xFFFF? BtoR(b): BtoF(b);
-		c = copyu(r->f.prog, &v, nil);
-		if(c == 1 || c == 2 || c == 4)
-			set |= b;
-		bb &= ~b;
-	}
-	return set;
-}
-
-uint32
-paint2(Reg *r, int bn)
-{
-	Reg *r1;
-	int z;
-	uint32 bb, vreg, x;
-
-	z = bn/32;
-	bb = 1L << (bn%32);
-	vreg = regbits;
-	if(!(r->act.b[z] & bb))
-		return vreg;
-	for(;;) {
-		if(!(r->refbehind.b[z] & bb))
-			break;
-		r1 = (Reg*)r->f.p1;
-		if(r1 == R)
-			break;
-		if(!(r1->refahead.b[z] & bb))
-			break;
-		if(!(r1->act.b[z] & bb))
-			break;
-		r = r1;
-	}
-	for(;;) {
-		r->act.b[z] &= ~bb;
-
-		vreg |= r->regu;
-
-		if(r->refbehind.b[z] & bb)
-			for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link)
-				if(r1->refahead.b[z] & bb)
-					vreg |= paint2(r1, bn);
-
-		if(!(r->refahead.b[z] & bb))
-			break;
-		r1 = (Reg*)r->f.s2;
-		if(r1 != R)
-			if(r1->refbehind.b[z] & bb)
-				vreg |= paint2(r1, bn);
-		r = (Reg*)r->f.s1;
-		if(r == R)
-			break;
-		if(!(r->act.b[z] & bb))
-			break;
-		if(!(r->refbehind.b[z] & bb))
-			break;
-	}
-
-	bb = vreg;
-	for(; r; r=(Reg*)r->f.s1) {
-		x = r->regu & ~bb;
-		if(x) {
-			vreg |= reguse(r, x);
-			bb |= regset(r, x);
-		}
-	}
-	return vreg;
-}
-
-void
-paint3(Reg *r, int bn, int32 rb, int rn)
-{
-	Reg *r1;
-	Prog *p;
-	int z;
-	uint32 bb;
-
-	z = bn/32;
-	bb = 1L << (bn%32);
-	if(r->act.b[z] & bb)
-		return;
-	for(;;) {
-		if(!(r->refbehind.b[z] & bb))
-			break;
-		r1 = (Reg*)r->f.p1;
-		if(r1 == R)
-			break;
-		if(!(r1->refahead.b[z] & bb))
-			break;
-		if(r1->act.b[z] & bb)
-			break;
-		r = r1;
-	}
-
-	if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb)
-		addmove(r, bn, rn, 0);
-	for(;;) {
-		r->act.b[z] |= bb;
-		p = r->f.prog;
-
-		if(r->use1.b[z] & bb) {
-			if(debug['R'] && debug['v'])
-				print("%P", p);
-			addreg(&p->from, rn);
-			if(debug['R'] && debug['v'])
-				print(" ===change== %P\n", p);
-		}
-		if((r->use2.b[z]|r->set.b[z]) & bb) {
-			if(debug['R'] && debug['v'])
-				print("%P", p);
-			addreg(&p->to, rn);
-			if(debug['R'] && debug['v'])
-				print(" ===change== %P\n", p);
-		}
-
-		if(STORE(r) & r->regdiff.b[z] & bb)
-			addmove(r, bn, rn, 1);
-		r->regu |= rb;
-
-		if(r->refbehind.b[z] & bb)
-			for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link)
-				if(r1->refahead.b[z] & bb)
-					paint3(r1, bn, rb, rn);
-
-		if(!(r->refahead.b[z] & bb))
-			break;
-		r1 = (Reg*)r->f.s2;
-		if(r1 != R)
-			if(r1->refbehind.b[z] & bb)
-				paint3(r1, bn, rb, rn);
-		r = (Reg*)r->f.s1;
-		if(r == R)
-			break;
-		if(r->act.b[z] & bb)
-			break;
-		if(!(r->refbehind.b[z] & bb))
-			break;
-	}
-}
-
-void
-addreg(Adr *a, int rn)
-{
-	a->sym = nil;
-	a->node = nil;
-	a->offset = 0;
-	a->type = rn;
-
-	ostats.ncvtreg++;
-}
-
-int32
-RtoB(int r)
-{
-
-	if(r < D_AX || r > D_R15)
-		return 0;
-	return 1L << (r-D_AX);
-}
-
-int
-BtoR(int32 b)
-{
-	b &= 0xffffL;
-	if(nacl)
-		b &= ~((1<<(D_BP-D_AX)) | (1<<(D_R15-D_AX)));
-	if(b == 0)
-		return 0;
-	return bitno(b) + D_AX;
-}
-
-/*
- *	bit	reg
- *	16	X0
- *	...
- *	31	X15
- */
-int32
-FtoB(int f)
-{
-	if(f < D_X0 || f > D_X15)
-		return 0;
-	return 1L << (f - D_X0 + 16);
-}
-
-int
-BtoF(int32 b)
-{
-
-	b &= 0xFFFF0000L;
-	if(b == 0)
-		return 0;
-	return bitno(b) - 16 + D_X0;
-}
-
-void
-dumpone(Flow *f, int isreg)
-{
-	int z;
-	Bits bit;
-	Reg *r;
-
-	print("%d:%P", f->loop, f->prog);
-	if(isreg) {	
-		r = (Reg*)f;
-		for(z=0; z<BITS; z++)
-			bit.b[z] =
-				r->set.b[z] |
-				r->use1.b[z] |
-				r->use2.b[z] |
-				r->refbehind.b[z] |
-				r->refahead.b[z] |
-				r->calbehind.b[z] |
-				r->calahead.b[z] |
-				r->regdiff.b[z] |
-				r->act.b[z] |
-					0;
-		if(bany(&bit)) {
-			print("\t");
-			if(bany(&r->set))
-				print(" s:%Q", r->set);
-			if(bany(&r->use1))
-				print(" u1:%Q", r->use1);
-			if(bany(&r->use2))
-				print(" u2:%Q", r->use2);
-			if(bany(&r->refbehind))
-				print(" rb:%Q ", r->refbehind);
-			if(bany(&r->refahead))
-				print(" ra:%Q ", r->refahead);
-			if(bany(&r->calbehind))
-				print(" cb:%Q ", r->calbehind);
-			if(bany(&r->calahead))
-				print(" ca:%Q ", r->calahead);
-			if(bany(&r->regdiff))
-				print(" d:%Q ", r->regdiff);
-			if(bany(&r->act))
-				print(" a:%Q ", r->act);
-		}
-	}
-	print("\n");
-}
-
-void
-dumpit(char *str, Flow *r0, int isreg)
-{
-	Flow *r, *r1;
-
-	print("\n%s\n", str);
-	for(r = r0; r != nil; r = r->link) {
-		dumpone(r, isreg);
-		r1 = r->p2;
-		if(r1 != nil) {
-			print("	pred:");
-			for(; r1 != nil; r1 = r1->p2link)
-				print(" %.4ud", (int)r1->prog->pc);
-			print("\n");
-		}
-//		r1 = r->s1;
-//		if(r1 != R) {
-//			print("	succ:");
-//			for(; r1 != R; r1 = r1->s1)
-//				print(" %.4ud", (int)r1->prog->pc);
-//			print("\n");
-//		}
-	}
-}
diff --git a/src/cmd/6l/6.out.h b/src/cmd/6l/6.out.h
deleted file mode 100644
index af72784..0000000
--- a/src/cmd/6l/6.out.h
+++ /dev/null
@@ -1,890 +0,0 @@
-// Inferno utils/6c/6.out.h
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/6.out.h
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#define	NSYM	50
-#define	NSNAME	8
-#include "../ld/textflag.h"
-
-/*
- *	amd64
- */
-
-enum
-{
-	AXXX,
-	AAAA,
-	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,
-	ACALL,
-	ACLC,
-	ACLD,
-	ACLI,
-	ACLTS,
-	ACMC,
-	ACMPB,
-	ACMPL,
-	ACMPW,
-	ACMPSB,
-	ACMPSL,
-	ACMPSW,
-	ADAA,
-	ADAS,
-	ADATA,
-	ADECB,
-	ADECL,
-	ADECQ,
-	ADECW,
-	ADIVB,
-	ADIVL,
-	ADIVW,
-	AENTER,
-	AGLOBL,
-	AGOK,
-	AHISTORY,
-	AHLT,
-	AIDIVB,
-	AIDIVL,
-	AIDIVW,
-	AIMULB,
-	AIMULL,
-	AIMULW,
-	AINB,
-	AINL,
-	AINW,
-	AINCB,
-	AINCL,
-	AINCQ,
-	AINCW,
-	AINSB,
-	AINSL,
-	AINSW,
-	AINT,
-	AINTO,
-	AIRETL,
-	AIRETW,
-	AJCC,
-	AJCS,
-	AJCXZL,
-	AJEQ,
-	AJGE,
-	AJGT,
-	AJHI,
-	AJLE,
-	AJLS,
-	AJLT,
-	AJMI,
-	AJMP,
-	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,
-	AMOVBLSX,
-	AMOVBLZX,
-	AMOVBQSX,
-	AMOVBQZX,
-	AMOVBWSX,
-	AMOVBWZX,
-	AMOVWLSX,
-	AMOVWLZX,
-	AMOVWQSX,
-	AMOVWQZX,
-	AMOVSB,
-	AMOVSL,
-	AMOVSW,
-	AMULB,
-	AMULL,
-	AMULW,
-	ANAME,
-	ANEGB,
-	ANEGL,
-	ANEGW,
-	ANOP,
-	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,
-	ARET,
-	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,
-	ATEXT,
-	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,
-	AFCOML,
-	AFCOMLP,
-	AFCOMW,
-	AFCOMWP,
-	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,
-	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,
-
-	AEND,
-
-	ADYNT_,
-	AINIT_,
-
-	ASIGNAME,
-
-	/* extra 32-bit operations */
-	ACMPXCHGB,
-	ACMPXCHGL,
-	ACMPXCHGW,
-	ACMPXCHG8B,
-	ACPUID,
-	AINVD,
-	AINVLPG,
-	ALFENCE,
-	AMFENCE,
-	AMOVNTIL,
-	ARDMSR,
-	ARDPMC,
-	ARDTSC,
-	ARSM,
-	ASFENCE,
-	ASYSRET,
-	AWBINVD,
-	AWRMSR,
-	AXADDB,
-	AXADDL,
-	AXADDW,
-
-	/* conditional move */
-	ACMOVLCC,
-	ACMOVLCS,
-	ACMOVLEQ,
-	ACMOVLGE,
-	ACMOVLGT,
-	ACMOVLHI,
-	ACMOVLLE,
-	ACMOVLLS,
-	ACMOVLLT,
-	ACMOVLMI,
-	ACMOVLNE,
-	ACMOVLOC,
-	ACMOVLOS,
-	ACMOVLPC,
-	ACMOVLPL,
-	ACMOVLPS,
-	ACMOVQCC,
-	ACMOVQCS,
-	ACMOVQEQ,
-	ACMOVQGE,
-	ACMOVQGT,
-	ACMOVQHI,
-	ACMOVQLE,
-	ACMOVQLS,
-	ACMOVQLT,
-	ACMOVQMI,
-	ACMOVQNE,
-	ACMOVQOC,
-	ACMOVQOS,
-	ACMOVQPC,
-	ACMOVQPL,
-	ACMOVQPS,
-	ACMOVWCC,
-	ACMOVWCS,
-	ACMOVWEQ,
-	ACMOVWGE,
-	ACMOVWGT,
-	ACMOVWHI,
-	ACMOVWLE,
-	ACMOVWLS,
-	ACMOVWLT,
-	ACMOVWMI,
-	ACMOVWNE,
-	ACMOVWOC,
-	ACMOVWOS,
-	ACMOVWPC,
-	ACMOVWPL,
-	ACMOVWPS,
-
-	/* 64-bit */
-	AADCQ,
-	AADDQ,
-	AANDQ,
-	ABSFQ,
-	ABSRQ,
-	ABTCQ,
-	ABTQ,
-	ABTRQ,
-	ABTSQ,
-	ACMPQ,
-	ACMPSQ,
-	ACMPXCHGQ,
-	ACQO,
-	ADIVQ,
-	AIDIVQ,
-	AIMULQ,
-	AIRETQ,
-	AJCXZQ,
-	ALEAQ,
-	ALEAVEQ,
-	ALODSQ,
-	AMOVQ,
-	AMOVLQSX,
-	AMOVLQZX,
-	AMOVNTIQ,
-	AMOVSQ,
-	AMULQ,
-	ANEGQ,
-	ANOTQ,
-	AORQ,
-	APOPFQ,
-	APOPQ,
-	APUSHFQ,
-	APUSHQ,
-	ARCLQ,
-	ARCRQ,
-	AROLQ,
-	ARORQ,
-	AQUAD,
-	ASALQ,
-	ASARQ,
-	ASBBQ,
-	ASCASQ,
-	ASHLQ,
-	ASHRQ,
-	ASTOSQ,
-	ASUBQ,
-	ATESTQ,
-	AXADDQ,
-	AXCHGQ,
-	AXORQ,
-
-	/* media */
-	AADDPD,
-	AADDPS,
-	AADDSD,
-	AADDSS,
-	AANDNPD,
-	AANDNPS,
-	AANDPD,
-	AANDPS,
-	ACMPPD,
-	ACMPPS,
-	ACMPSD,
-	ACMPSS,
-	ACOMISD,
-	ACOMISS,
-	ACVTPD2PL,
-	ACVTPD2PS,
-	ACVTPL2PD,
-	ACVTPL2PS,
-	ACVTPS2PD,
-	ACVTPS2PL,
-	ACVTSD2SL,
-	ACVTSD2SQ,
-	ACVTSD2SS,
-	ACVTSL2SD,
-	ACVTSL2SS,
-	ACVTSQ2SD,
-	ACVTSQ2SS,
-	ACVTSS2SD,
-	ACVTSS2SL,
-	ACVTSS2SQ,
-	ACVTTPD2PL,
-	ACVTTPS2PL,
-	ACVTTSD2SL,
-	ACVTTSD2SQ,
-	ACVTTSS2SL,
-	ACVTTSS2SQ,
-	ADIVPD,
-	ADIVPS,
-	ADIVSD,
-	ADIVSS,
-	AEMMS,
-	AFXRSTOR,
-	AFXRSTOR64,
-	AFXSAVE,
-	AFXSAVE64,
-	ALDMXCSR,
-	AMASKMOVOU,
-	AMASKMOVQ,
-	AMAXPD,
-	AMAXPS,
-	AMAXSD,
-	AMAXSS,
-	AMINPD,
-	AMINPS,
-	AMINSD,
-	AMINSS,
-	AMOVAPD,
-	AMOVAPS,
-	AMOVOU,
-	AMOVHLPS,
-	AMOVHPD,
-	AMOVHPS,
-	AMOVLHPS,
-	AMOVLPD,
-	AMOVLPS,
-	AMOVMSKPD,
-	AMOVMSKPS,
-	AMOVNTO,
-	AMOVNTPD,
-	AMOVNTPS,
-	AMOVNTQ,
-	AMOVO,
-	AMOVQOZX,
-	AMOVSD,
-	AMOVSS,
-	AMOVUPD,
-	AMOVUPS,
-	AMULPD,
-	AMULPS,
-	AMULSD,
-	AMULSS,
-	AORPD,
-	AORPS,
-	APACKSSLW,
-	APACKSSWB,
-	APACKUSWB,
-	APADDB,
-	APADDL,
-	APADDQ,
-	APADDSB,
-	APADDSW,
-	APADDUSB,
-	APADDUSW,
-	APADDW,
-	APANDB,
-	APANDL,
-	APANDSB,
-	APANDSW,
-	APANDUSB,
-	APANDUSW,
-	APANDW,
-	APAND,
-	APANDN,
-	APAVGB,
-	APAVGW,
-	APCMPEQB,
-	APCMPEQL,
-	APCMPEQW,
-	APCMPGTB,
-	APCMPGTL,
-	APCMPGTW,
-	APEXTRW,
-	APFACC,
-	APFADD,
-	APFCMPEQ,
-	APFCMPGE,
-	APFCMPGT,
-	APFMAX,
-	APFMIN,
-	APFMUL,
-	APFNACC,
-	APFPNACC,
-	APFRCP,
-	APFRCPIT1,
-	APFRCPI2T,
-	APFRSQIT1,
-	APFRSQRT,
-	APFSUB,
-	APFSUBR,
-	APINSRW,
-	APINSRD,
-	APINSRQ,
-	APMADDWL,
-	APMAXSW,
-	APMAXUB,
-	APMINSW,
-	APMINUB,
-	APMOVMSKB,
-	APMULHRW,
-	APMULHUW,
-	APMULHW,
-	APMULLW,
-	APMULULQ,
-	APOR,
-	APSADBW,
-	APSHUFHW,
-	APSHUFL,
-	APSHUFLW,
-	APSHUFW,
-	APSHUFB,
-	APSLLO,
-	APSLLL,
-	APSLLQ,
-	APSLLW,
-	APSRAL,
-	APSRAW,
-	APSRLO,
-	APSRLL,
-	APSRLQ,
-	APSRLW,
-	APSUBB,
-	APSUBL,
-	APSUBQ,
-	APSUBSB,
-	APSUBSW,
-	APSUBUSB,
-	APSUBUSW,
-	APSUBW,
-	APSWAPL,
-	APUNPCKHBW,
-	APUNPCKHLQ,
-	APUNPCKHQDQ,
-	APUNPCKHWL,
-	APUNPCKLBW,
-	APUNPCKLLQ,
-	APUNPCKLQDQ,
-	APUNPCKLWL,
-	APXOR,
-	ARCPPS,
-	ARCPSS,
-	ARSQRTPS,
-	ARSQRTSS,
-	ASHUFPD,
-	ASHUFPS,
-	ASQRTPD,
-	ASQRTPS,
-	ASQRTSD,
-	ASQRTSS,
-	ASTMXCSR,
-	ASUBPD,
-	ASUBPS,
-	ASUBSD,
-	ASUBSS,
-	AUCOMISD,
-	AUCOMISS,
-	AUNPCKHPD,
-	AUNPCKHPS,
-	AUNPCKLPD,
-	AUNPCKLPS,
-	AXORPD,
-	AXORPS,
-
-	APF2IW,
-	APF2IL,
-	API2FW,
-	API2FL,
-	ARETFW,
-	ARETFL,
-	ARETFQ,
-	ASWAPGS,
-
-	AMODE,
-	ACRC32B,
-	ACRC32Q,
-	AIMUL3Q,
-	
-	APREFETCHT0,
-	APREFETCHT1,
-	APREFETCHT2,
-	APREFETCHNTA,
-	
-	AMOVQL,
-	ABSWAPL,
-	ABSWAPQ,
-	
-	AUNDEF,
-
-	AAESENC,
-	AAESENCLAST,
-	AAESDEC,
-	AAESDECLAST,
-	AAESIMC,
-	AAESKEYGENASSIST,
-
-	APSHUFD,
-	APCLMULQDQ,
-	
-	AUSEFIELD,
-	ATYPE,
-	AFUNCDATA,
-	APCDATA,
-	ACHECKNIL,
-	AVARDEF,
-	AVARKILL,
-	ADUFFCOPY,
-	ADUFFZERO,
-	
-	ALAST
-};
-
-enum
-{
-
-	D_AL		= 0,
-	D_CL,
-	D_DL,
-	D_BL,
-	D_SPB,
-	D_BPB,
-	D_SIB,
-	D_DIB,
-	D_R8B,
-	D_R9B,
-	D_R10B,
-	D_R11B,
-	D_R12B,
-	D_R13B,
-	D_R14B,
-	D_R15B,
-
-	D_AX		= 16,
-	D_CX,
-	D_DX,
-	D_BX,
-	D_SP,
-	D_BP,
-	D_SI,
-	D_DI,
-	D_R8,
-	D_R9,
-	D_R10,
-	D_R11,
-	D_R12,
-	D_R13,
-	D_R14,
-	D_R15,
-
-	D_AH		= 32,
-	D_CH,
-	D_DH,
-	D_BH,
-
-	D_F0		= 36,
-
-	D_M0		= 44,
-
-	D_X0		= 52,
-	D_X1,
-	D_X2,
-	D_X3,
-	D_X4,
-	D_X5,
-	D_X6,
-	D_X7,
-	D_X8,
-	D_X9,
-	D_X10,
-	D_X11,
-	D_X12,
-	D_X13,
-	D_X14,
-	D_X15,
-
-	D_CS		= 68,
-	D_SS,
-	D_DS,
-	D_ES,
-	D_FS,
-	D_GS,
-
-	D_GDTR,		/* global descriptor table register */
-	D_IDTR,		/* interrupt descriptor table register */
-	D_LDTR,		/* local descriptor table register */
-	D_MSW,		/* machine status word */
-	D_TASK,		/* task register */
-
-	D_CR		= 79,
-	D_DR		= 95,
-	D_TR		= 103,
-
-	D_TLS		= 111,
-	D_NONE		= 112,
-
-	D_BRANCH	= 113,
-	D_EXTERN	= 114,
-	D_STATIC	= 115,
-	D_AUTO		= 116,
-	D_PARAM		= 117,
-	D_CONST		= 118,
-	D_FCONST	= 119,
-	D_SCONST	= 120,
-	D_ADDR		= 121,
-
-	D_INDIR,	/* additive */
-
-	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_64		= 1<<6,
-	T_GOTYPE	= 1<<7,
-
-	REGARG		= -1,
-	REGRET		= D_AX,
-	FREGRET		= D_X0,
-	REGSP		= D_SP,
-	REGTMP		= D_DI,
-	REGEXT		= D_R15,	/* compiler allocates external registers R15 down */
-	FREGMIN		= D_X0+5,	/* first register variable */
-	FREGEXT		= D_X0+15	/* first external register */
-};
-
-/*
- * this is the ranlib header
- */
-#define	SYMDEF	"__.GOSYMDEF"
diff --git a/src/cmd/6l/Makefile b/src/cmd/6l/Makefile
deleted file mode 100644
index 3f528d7..0000000
--- a/src/cmd/6l/Makefile
+++ /dev/null
@@ -1,5 +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.
-
-include ../../Make.dist
diff --git a/src/cmd/6l/asm.c b/src/cmd/6l/asm.c
deleted file mode 100644
index 18b5aa3..0000000
--- a/src/cmd/6l/asm.c
+++ /dev/null
@@ -1,817 +0,0 @@
-// 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 at 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 at 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.
-
-// Writing object files.
-
-#include	"l.h"
-#include	"../ld/lib.h"
-#include	"../ld/elf.h"
-#include	"../ld/dwarf.h"
-#include	"../ld/macho.h"
-#include	"../ld/pe.h"
-
-#define PADDR(a)	((uint32)(a) & ~0x80000000)
-
-char linuxdynld[] = "/lib64/ld-linux-x86-64.so.2";
-char freebsddynld[] = "/libexec/ld-elf.so.1";
-char openbsddynld[] = "/usr/libexec/ld.so";
-char netbsddynld[] = "/libexec/ld.elf_so";
-char dragonflydynld[] = "/usr/libexec/ld-elf.so.2";
-char solarisdynld[] = "/lib/amd64/ld.so.1";
-
-char	zeroes[32];
-
-static int
-needlib(char *name)
-{
-	char *p;
-	LSym *s;
-
-	if(*name == '\0')
-		return 0;
-
-	/* reuse hash code in symbol table */
-	p = smprint(".elfload.%s", name);
-	s = linklookup(ctxt, p, 0);
-	free(p);
-	if(s->type == 0) {
-		s->type = 100;	// avoid SDATA, etc.
-		return 1;
-	}
-	return 0;
-}
-
-int nelfsym = 1;
-
-static void addpltsym(LSym*);
-static void addgotsym(LSym*);
-
-void
-adddynrela(LSym *rela, LSym *s, Reloc *r)
-{
-	addaddrplus(ctxt, rela, s, r->off);
-	adduint64(ctxt, rela, R_X86_64_RELATIVE);
-	addaddrplus(ctxt, rela, r->sym, r->add); // Addend
-}
-
-void
-adddynrel(LSym *s, Reloc *r)
-{
-	LSym *targ, *rela, *got;
-	
-	targ = r->sym;
-	ctxt->cursym = s;
-
-	switch(r->type) {
-	default:
-		if(r->type >= 256) {
-			diag("unexpected relocation type %d", r->type);
-			return;
-		}
-		break;
-
-	// Handle relocations found in ELF object files.
-	case 256 + R_X86_64_PC32:
-		if(targ->type == SDYNIMPORT)
-			diag("unexpected R_X86_64_PC32 relocation for dynamic symbol %s", targ->name);
-		if(targ->type == 0 || targ->type == SXREF)
-			diag("unknown symbol %s in pcrel", targ->name);
-		r->type = R_PCREL;
-		r->add += 4;
-		return;
-	
-	case 256 + R_X86_64_PLT32:
-		r->type = R_PCREL;
-		r->add += 4;
-		if(targ->type == SDYNIMPORT) {
-			addpltsym(targ);
-			r->sym = linklookup(ctxt, ".plt", 0);
-			r->add += targ->plt;
-		}
-		return;
-	
-	case 256 + R_X86_64_GOTPCREL:
-		if(targ->type != SDYNIMPORT) {
-			// have symbol
-			if(r->off >= 2 && s->p[r->off-2] == 0x8b) {
-				// turn MOVQ of GOT entry into LEAQ of symbol itself
-				s->p[r->off-2] = 0x8d;
-				r->type = R_PCREL;
-				r->add += 4;
-				return;
-			}
-			// fall back to using GOT and hope for the best (CMOV*)
-			// TODO: just needs relocation, no need to put in .dynsym
-		}
-		addgotsym(targ);
-		r->type = R_PCREL;
-		r->sym = linklookup(ctxt, ".got", 0);
-		r->add += 4;
-		r->add += targ->got;
-		return;
-	
-	case 256 + R_X86_64_64:
-		if(targ->type == SDYNIMPORT)
-			diag("unexpected R_X86_64_64 relocation for dynamic symbol %s", targ->name);
-		r->type = R_ADDR;
-		return;
-	
-	// Handle relocations found in Mach-O object files.
-	case 512 + MACHO_X86_64_RELOC_UNSIGNED*2 + 0:
-	case 512 + MACHO_X86_64_RELOC_SIGNED*2 + 0:
-	case 512 + MACHO_X86_64_RELOC_BRANCH*2 + 0:
-		// TODO: What is the difference between all these?
-		r->type = R_ADDR;
-		if(targ->type == SDYNIMPORT)
-			diag("unexpected reloc for dynamic symbol %s", targ->name);
-		return;
-
-	case 512 + MACHO_X86_64_RELOC_BRANCH*2 + 1:
-		if(targ->type == SDYNIMPORT) {
-			addpltsym(targ);
-			r->sym = linklookup(ctxt, ".plt", 0);
-			r->add = targ->plt;
-			r->type = R_PCREL;
-			return;
-		}
-		// fall through
-	case 512 + MACHO_X86_64_RELOC_UNSIGNED*2 + 1:
-	case 512 + MACHO_X86_64_RELOC_SIGNED*2 + 1:
-	case 512 + MACHO_X86_64_RELOC_SIGNED_1*2 + 1:
-	case 512 + MACHO_X86_64_RELOC_SIGNED_2*2 + 1:
-	case 512 + MACHO_X86_64_RELOC_SIGNED_4*2 + 1:
-		r->type = R_PCREL;
-		if(targ->type == SDYNIMPORT)
-			diag("unexpected pc-relative reloc for dynamic symbol %s", targ->name);
-		return;
-
-	case 512 + MACHO_X86_64_RELOC_GOT_LOAD*2 + 1:
-		if(targ->type != SDYNIMPORT) {
-			// have symbol
-			// turn MOVQ of GOT entry into LEAQ of symbol itself
-			if(r->off < 2 || s->p[r->off-2] != 0x8b) {
-				diag("unexpected GOT_LOAD reloc for non-dynamic symbol %s", targ->name);
-				return;
-			}
-			s->p[r->off-2] = 0x8d;
-			r->type = R_PCREL;
-			return;
-		}
-		// fall through
-	case 512 + MACHO_X86_64_RELOC_GOT*2 + 1:
-		if(targ->type != SDYNIMPORT)
-			diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name);
-		addgotsym(targ);
-		r->type = R_PCREL;
-		r->sym = linklookup(ctxt, ".got", 0);
-		r->add += targ->got;
-		return;
-	}
-	
-	// Handle references to ELF symbols from our own object files.
-	if(targ->type != SDYNIMPORT)
-		return;
-
-	switch(r->type) {
-	case R_CALL:
-	case R_PCREL:
-		addpltsym(targ);
-		r->sym = linklookup(ctxt, ".plt", 0);
-		r->add = targ->plt;
-		return;
-	
-	case R_ADDR:
-		if(s->type == STEXT && iself) {
-			// The code is asking for the address of an external
-			// function.  We provide it with the address of the
-			// correspondent GOT symbol.
-			addgotsym(targ);
-			r->sym = linklookup(ctxt, ".got", 0);
-			r->add += targ->got;
-			return;
-		}
-		if(s->type != SDATA)
-			break;
-		if(iself) {
-			adddynsym(ctxt, targ);
-			rela = linklookup(ctxt, ".rela", 0);
-			addaddrplus(ctxt, rela, s, r->off);
-			if(r->siz == 8)
-				adduint64(ctxt, rela, ELF64_R_INFO(targ->dynid, R_X86_64_64));
-			else
-				adduint64(ctxt, rela, ELF64_R_INFO(targ->dynid, R_X86_64_32));
-			adduint64(ctxt, rela, r->add);
-			r->type = 256;	// ignore during relocsym
-			return;
-		}
-		if(HEADTYPE == Hdarwin && s->size == PtrSize && r->off == 0) {
-			// Mach-O relocations are a royal pain to lay out.
-			// They use a compact stateful bytecode representation
-			// that is too much bother to deal with.
-			// Instead, interpret the C declaration
-			//	void *_Cvar_stderr = &stderr;
-			// as making _Cvar_stderr the name of a GOT entry
-			// for stderr.  This is separate from the usual GOT entry,
-			// just in case the C code assigns to the variable,
-			// and of course it only works for single pointers,
-			// but we only need to support cgo and that's all it needs.
-			adddynsym(ctxt, targ);
-			got = linklookup(ctxt, ".got", 0);
-			s->type = got->type | SSUB;
-			s->outer = got;
-			s->sub = got->sub;
-			got->sub = s;
-			s->value = got->size;
-			adduint64(ctxt, got, 0);
-			adduint32(ctxt, linklookup(ctxt, ".linkedit.got", 0), targ->dynid);
-			r->type = 256;	// ignore during relocsym
-			return;
-		}
-		break;
-	}
-	
-	ctxt->cursym = s;
-	diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type);
-}
-
-int
-elfreloc1(Reloc *r, vlong sectoff)
-{
-	int32 elfsym;
-
-	VPUT(sectoff);
-
-	elfsym = r->xsym->elfsym;
-	switch(r->type) {
-	default:
-		return -1;
-
-	case R_ADDR:
-		if(r->siz == 4)
-			VPUT(R_X86_64_32 | (uint64)elfsym<<32);
-		else if(r->siz == 8)
-			VPUT(R_X86_64_64 | (uint64)elfsym<<32);
-		else
-			return -1;
-		break;
-
-	case R_TLS_LE:
-		if(r->siz == 4)
-			VPUT(R_X86_64_TPOFF32 | (uint64)elfsym<<32);
-		else
-			return -1;
-		break;
-		
-	case R_CALL:
-		if(r->siz == 4) {
-			if(r->xsym->type == SDYNIMPORT)
-				VPUT(R_X86_64_GOTPCREL | (uint64)elfsym<<32);
-			else
-				VPUT(R_X86_64_PC32 | (uint64)elfsym<<32);
-		} else
-			return -1;
-		break;
-
-	case R_PCREL:
-		if(r->siz == 4) {
-			VPUT(R_X86_64_PC32 | (uint64)elfsym<<32);
-		} else
-			return -1;
-		break;
-
-	case R_TLS:
-		if(r->siz == 4) {
-			if(flag_shared)
-				VPUT(R_X86_64_GOTTPOFF | (uint64)elfsym<<32);
-			else
-				VPUT(R_X86_64_TPOFF32 | (uint64)elfsym<<32);
-		} else
-			return -1;
-		break;		
-	}
-
-	VPUT(r->xadd);
-	return 0;
-}
-
-int
-machoreloc1(Reloc *r, vlong sectoff)
-{
-	uint32 v;
-	LSym *rs;
-	
-	rs = r->xsym;
-
-	if(rs->type == SHOSTOBJ || r->type == R_PCREL) {
-		if(rs->dynid < 0) {
-			diag("reloc %d to non-macho symbol %s type=%d", r->type, rs->name, rs->type);
-			return -1;
-		}
-		v = rs->dynid;			
-		v |= 1<<27; // external relocation
-	} else {
-		v = rs->sect->extnum;
-		if(v == 0) {
-			diag("reloc %d to symbol %s in non-macho section %s type=%d", r->type, rs->name, rs->sect->name, rs->type);
-			return -1;
-		}
-	}
-
-	switch(r->type) {
-	default:
-		return -1;
-	case R_ADDR:
-		v |= MACHO_X86_64_RELOC_UNSIGNED<<28;
-		break;
-	case R_CALL:
-		v |= 1<<24; // pc-relative bit
-		v |= MACHO_X86_64_RELOC_BRANCH<<28;
-		break;
-	case R_PCREL:
-		// NOTE: Only works with 'external' relocation. Forced above.
-		v |= 1<<24; // pc-relative bit
-		v |= MACHO_X86_64_RELOC_SIGNED<<28;
-	}
-	
-	switch(r->siz) {
-	default:
-		return -1;
-	case 1:
-		v |= 0<<25;
-		break;
-	case 2:
-		v |= 1<<25;
-		break;
-	case 4:
-		v |= 2<<25;
-		break;
-	case 8:
-		v |= 3<<25;
-		break;
-	}
-
-	LPUT(sectoff);
-	LPUT(v);
-	return 0;
-}
-
-int
-archreloc(Reloc *r, LSym *s, vlong *val)
-{
-	USED(r);
-	USED(s);
-	USED(val);
-	return -1;
-}
-
-void
-elfsetupplt(void)
-{
-	LSym *plt, *got;
-
-	plt = linklookup(ctxt, ".plt", 0);
-	got = linklookup(ctxt, ".got.plt", 0);
-	if(plt->size == 0) {
-		// pushq got+8(IP)
-		adduint8(ctxt, plt, 0xff);
-		adduint8(ctxt, plt, 0x35);
-		addpcrelplus(ctxt, plt, got, 8);
-		
-		// jmpq got+16(IP)
-		adduint8(ctxt, plt, 0xff);
-		adduint8(ctxt, plt, 0x25);
-		addpcrelplus(ctxt, plt, got, 16);
-		
-		// nopl 0(AX)
-		adduint32(ctxt, plt, 0x00401f0f);
-		
-		// assume got->size == 0 too
-		addaddrplus(ctxt, got, linklookup(ctxt, ".dynamic", 0), 0);
-		adduint64(ctxt, got, 0);
-		adduint64(ctxt, got, 0);
-	}
-}
-
-static void
-addpltsym(LSym *s)
-{
-	if(s->plt >= 0)
-		return;
-	
-	adddynsym(ctxt, s);
-	
-	if(iself) {
-		LSym *plt, *got, *rela;
-
-		plt = linklookup(ctxt, ".plt", 0);
-		got = linklookup(ctxt, ".got.plt", 0);
-		rela = linklookup(ctxt, ".rela.plt", 0);
-		if(plt->size == 0)
-			elfsetupplt();
-		
-		// jmpq *got+size(IP)
-		adduint8(ctxt, plt, 0xff);
-		adduint8(ctxt, plt, 0x25);
-		addpcrelplus(ctxt, plt, got, got->size);
-	
-		// add to got: pointer to current pos in plt
-		addaddrplus(ctxt, got, plt, plt->size);
-		
-		// pushq $x
-		adduint8(ctxt, plt, 0x68);
-		adduint32(ctxt, plt, (got->size-24-8)/8);
-		
-		// jmpq .plt
-		adduint8(ctxt, plt, 0xe9);
-		adduint32(ctxt, plt, -(plt->size+4));
-		
-		// rela
-		addaddrplus(ctxt, rela, got, got->size-8);
-		adduint64(ctxt, rela, ELF64_R_INFO(s->dynid, R_X86_64_JMP_SLOT));
-		adduint64(ctxt, rela, 0);
-		
-		s->plt = plt->size - 16;
-	} else if(HEADTYPE == Hdarwin) {
-		// To do lazy symbol lookup right, we're supposed
-		// to tell the dynamic loader which library each 
-		// symbol comes from and format the link info
-		// section just so.  I'm too lazy (ha!) to do that
-		// so for now we'll just use non-lazy pointers,
-		// which don't need to be told which library to use.
-		//
-		// http://networkpx.blogspot.com/2009/09/about-lcdyldinfoonly-command.html
-		// has details about what we're avoiding.
-
-		LSym *plt;
-		
-		addgotsym(s);
-		plt = linklookup(ctxt, ".plt", 0);
-
-		adduint32(ctxt, linklookup(ctxt, ".linkedit.plt", 0), s->dynid);
-
-		// jmpq *got+size(IP)
-		s->plt = plt->size;
-
-		adduint8(ctxt, plt, 0xff);
-		adduint8(ctxt, plt, 0x25);
-		addpcrelplus(ctxt, plt, linklookup(ctxt, ".got", 0), s->got);
-	} else {
-		diag("addpltsym: unsupported binary format");
-	}
-}
-
-static void
-addgotsym(LSym *s)
-{
-	LSym *got, *rela;
-
-	if(s->got >= 0)
-		return;
-
-	adddynsym(ctxt, s);
-	got = linklookup(ctxt, ".got", 0);
-	s->got = got->size;
-	adduint64(ctxt, got, 0);
-
-	if(iself) {
-		rela = linklookup(ctxt, ".rela", 0);
-		addaddrplus(ctxt, rela, got, s->got);
-		adduint64(ctxt, rela, ELF64_R_INFO(s->dynid, R_X86_64_GLOB_DAT));
-		adduint64(ctxt, rela, 0);
-	} else if(HEADTYPE == Hdarwin) {
-		adduint32(ctxt, linklookup(ctxt, ".linkedit.got", 0), s->dynid);
-	} else {
-		diag("addgotsym: unsupported binary format");
-	}
-}
-
-void
-adddynsym(Link *ctxt, LSym *s)
-{
-	LSym *d;
-	int t;
-	char *name;
-
-	if(s->dynid >= 0)
-		return;
-
-	if(iself) {
-		s->dynid = nelfsym++;
-
-		d = linklookup(ctxt, ".dynsym", 0);
-
-		name = s->extname;
-		adduint32(ctxt, d, addstring(linklookup(ctxt, ".dynstr", 0), name));
-		/* type */
-		t = STB_GLOBAL << 4;
-		if(s->cgoexport && (s->type&SMASK) == STEXT)
-			t |= STT_FUNC;
-		else
-			t |= STT_OBJECT;
-		adduint8(ctxt, d, t);
-	
-		/* reserved */
-		adduint8(ctxt, d, 0);
-	
-		/* section where symbol is defined */
-		if(s->type == SDYNIMPORT)
-			adduint16(ctxt, d, SHN_UNDEF);
-		else {
-			switch(s->type) {
-			default:
-			case STEXT:
-				t = 11;
-				break;
-			case SRODATA:
-				t = 12;
-				break;
-			case SDATA:
-				t = 13;
-				break;
-			case SBSS:
-				t = 14;
-				break;
-			}
-			adduint16(ctxt, d, t);
-		}
-	
-		/* value */
-		if(s->type == SDYNIMPORT)
-			adduint64(ctxt, d, 0);
-		else
-			addaddr(ctxt, d, s);
-	
-		/* size of object */
-		adduint64(ctxt, d, s->size);
-	
-		if(!(s->cgoexport & CgoExportDynamic) && s->dynimplib && needlib(s->dynimplib)) {
-			elfwritedynent(linklookup(ctxt, ".dynamic", 0), DT_NEEDED,
-				addstring(linklookup(ctxt, ".dynstr", 0), s->dynimplib));
-		}
-	} else if(HEADTYPE == Hdarwin) {
-		diag("adddynsym: missed symbol %s (%s)", s->name, s->extname);
-	} else if(HEADTYPE == Hwindows) {
-		// already taken care of
-	} else {
-		diag("adddynsym: unsupported binary format");
-	}
-}
-
-void
-adddynlib(char *lib)
-{
-	LSym *s;
-	
-	if(!needlib(lib))
-		return;
-	
-	if(iself) {
-		s = linklookup(ctxt, ".dynstr", 0);
-		if(s->size == 0)
-			addstring(s, "");
-		elfwritedynent(linklookup(ctxt, ".dynamic", 0), DT_NEEDED, addstring(s, lib));
-	} else if(HEADTYPE == Hdarwin) {
-		machoadddynlib(lib);
-	} else {
-		diag("adddynlib: unsupported binary format");
-	}
-}
-
-void
-asmb(void)
-{
-	int32 magic;
-	int i;
-	vlong vl, symo, dwarfoff, machlink;
-	Section *sect;
-	LSym *sym;
-
-	if(debug['v'])
-		Bprint(&bso, "%5.2f asmb\n", cputime());
-	Bflush(&bso);
-
-	if(debug['v'])
-		Bprint(&bso, "%5.2f codeblk\n", cputime());
-	Bflush(&bso);
-
-	if(iself)
-		asmbelfsetup();
-
-	sect = segtext.sect;
-	cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);
-	codeblk(sect->vaddr, sect->len);
-	for(sect = sect->next; sect != nil; sect = sect->next) {
-		cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);
-		datblk(sect->vaddr, sect->len);
-	}
-
-	if(segrodata.filelen > 0) {
-		if(debug['v'])
-			Bprint(&bso, "%5.2f rodatblk\n", cputime());
-		Bflush(&bso);
-
-		cseek(segrodata.fileoff);
-		datblk(segrodata.vaddr, segrodata.filelen);
-	}
-
-	if(debug['v'])
-		Bprint(&bso, "%5.2f datblk\n", cputime());
-	Bflush(&bso);
-
-	cseek(segdata.fileoff);
-	datblk(segdata.vaddr, segdata.filelen);
-
-	machlink = 0;
-	if(HEADTYPE == Hdarwin) {
-		if(debug['v'])
-			Bprint(&bso, "%5.2f dwarf\n", cputime());
-
-		dwarfoff = rnd(HEADR+segtext.len, INITRND) + rnd(segdata.filelen, INITRND);
-		cseek(dwarfoff);
-
-		segdwarf.fileoff = cpos();
-		dwarfemitdebugsections();
-		segdwarf.filelen = cpos() - segdwarf.fileoff;
-
-		machlink = domacholink();
-	}
-
-	switch(HEADTYPE) {
-	default:
-		diag("unknown header type %d", HEADTYPE);
-	case Hplan9:
-	case Helf:
-		break;
-	case Hdarwin:
-		debug['8'] = 1;	/* 64-bit addresses */
-		break;
-	case Hlinux:
-	case Hfreebsd:
-	case Hnetbsd:
-	case Hopenbsd:
-	case Hdragonfly:
-	case Hsolaris:
-		debug['8'] = 1;	/* 64-bit addresses */
-		break;
-	case Hnacl:
-	case Hwindows:
-		break;
-	}
-
-	symsize = 0;
-	spsize = 0;
-	lcsize = 0;
-	symo = 0;
-	if(!debug['s']) {
-		if(debug['v'])
-			Bprint(&bso, "%5.2f sym\n", cputime());
-		Bflush(&bso);
-		switch(HEADTYPE) {
-		default:
-		case Hplan9:
-		case Helf:
-			debug['s'] = 1;
-			symo = segdata.fileoff+segdata.filelen;
-			break;
-		case Hdarwin:
-			symo = segdata.fileoff+rnd(segdata.filelen, INITRND)+machlink;
-			break;
-		case Hlinux:
-		case Hfreebsd:
-		case Hnetbsd:
-		case Hopenbsd:
-		case Hdragonfly:
-		case Hsolaris:
-		case Hnacl:
-			symo = segdata.fileoff+segdata.filelen;
-			symo = rnd(symo, INITRND);
-			break;
-		case Hwindows:
-			symo = segdata.fileoff+segdata.filelen;
-			symo = rnd(symo, PEFILEALIGN);
-			break;
-		}
-		cseek(symo);
-		switch(HEADTYPE) {
-		default:
-			if(iself) {
-				cseek(symo);
-				asmelfsym();
-				cflush();
-				cwrite(elfstrdat, elfstrsize);
-
-				if(debug['v'])
-				       Bprint(&bso, "%5.2f dwarf\n", cputime());
-
-				dwarfemitdebugsections();
-				
-				if(linkmode == LinkExternal)
-					elfemitreloc();
-			}
-			break;
-		case Hplan9:
-			asmplan9sym();
-			cflush();
-
-			sym = linklookup(ctxt, "pclntab", 0);
-			if(sym != nil) {
-				lcsize = sym->np;
-				for(i=0; i < lcsize; i++)
-					cput(sym->p[i]);
-				
-				cflush();
-			}
-			break;
-		case Hwindows:
-			if(debug['v'])
-			       Bprint(&bso, "%5.2f dwarf\n", cputime());
-
-			dwarfemitdebugsections();
-			break;
-		case Hdarwin:
-			if(linkmode == LinkExternal)
-				machoemitreloc();
-			break;
-		}
-	}
-
-	if(debug['v'])
-		Bprint(&bso, "%5.2f headr\n", cputime());
-	Bflush(&bso);
-	cseek(0L);
-	switch(HEADTYPE) {
-	default:
-	case Hplan9:	/* plan9 */
-		magic = 4*26*26+7;
-		magic |= 0x00008000;		/* fat header */
-		lputb(magic);			/* magic */
-		lputb(segtext.filelen);			/* sizes */
-		lputb(segdata.filelen);
-		lputb(segdata.len - segdata.filelen);
-		lputb(symsize);			/* nsyms */
-		vl = entryvalue();
-		lputb(PADDR(vl));		/* va of entry */
-		lputb(spsize);			/* sp offsets */
-		lputb(lcsize);			/* line offsets */
-		vputb(vl);			/* va of entry */
-		break;
-	case Hdarwin:
-		asmbmacho();
-		break;
-	case Hlinux:
-	case Hfreebsd:
-	case Hnetbsd:
-	case Hopenbsd:
-	case Hdragonfly:
-	case Hsolaris:
-	case Hnacl:
-		asmbelf(symo);
-		break;
-	case Hwindows:
-		asmbpe();
-		break;
-	}
-	cflush();
-}
-
-vlong
-rnd(vlong v, vlong r)
-{
-	vlong c;
-
-	if(r <= 0)
-		return v;
-	v += r - 1;
-	c = v % r;
-	if(c < 0)
-		c += r;
-	v -= c;
-	return v;
-}
diff --git a/src/cmd/6l/doc.go b/src/cmd/6l/doc.go
deleted file mode 100644
index 6287dd9..0000000
--- a/src/cmd/6l/doc.go
+++ /dev/null
@@ -1,15 +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.
-
-// +build ignore
-
-/*
-
-6l is the linker for the x86-64.
-The $GOARCH for these tools is amd64.
-
-The flags are documented in ../ld/doc.go.
-
-*/
-package main
diff --git a/src/cmd/6l/l.h b/src/cmd/6l/l.h
deleted file mode 100644
index ff2e694..0000000
--- a/src/cmd/6l/l.h
+++ /dev/null
@@ -1,109 +0,0 @@
-// Inferno utils/6l/l.h
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/l.h
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include	<u.h>
-#include	<libc.h>
-#include	<bio.h>
-#include	<link.h>
-#include	"6.out.h"
-
-#ifndef	EXTERN
-#define	EXTERN	extern
-#endif
-
-enum
-{
-	thechar = '6',
-	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
-};
-
-EXTERN	int	PtrSize;
-EXTERN	int	IntSize;
-EXTERN	int	RegSize;
-
-#define	P		((Prog*)0)
-#define	S		((LSym*)0)
-enum
-{
-	MINLC		= 1,
-};
-
-#pragma	varargck	type	"I"	uchar*
-
-EXTERN	LSym*	datap;
-EXTERN	int	debug[128];
-EXTERN	char	literal[32];
-EXTERN	int32	lcsize;
-EXTERN	char*	rpath;
-EXTERN	int32	spsize;
-EXTERN	LSym*	symlist;
-EXTERN	int32	symsize;
-
-int	Iconv(Fmt *fp);
-void	adddynlib(char *lib);
-void	adddynrel(LSym *s, Reloc *r);
-void	adddynrela(LSym *rela, LSym *s, Reloc *r);
-void	adddynsym(Link *ctxt, LSym *s);
-int	archreloc(Reloc *r, LSym *s, vlong *val);
-void	asmb(void);
-int	elfreloc1(Reloc *r, vlong sectoff);
-void	elfsetupplt(void);
-void	listinit(void);
-int	machoreloc1(Reloc *r, vlong sectoff);
-vlong	rnd(vlong v, vlong r);
-
-/* Native is little-endian */
-#define	LPUT(a)	lputl(a)
-#define	WPUT(a)	wputl(a)
-#define	VPUT(a)	vputl(a)
-
-/* Used by ../ld/dwarf.c */
-enum
-{
-	DWARFREGSP = 7
-};
diff --git a/src/cmd/6l/list.c b/src/cmd/6l/list.c
deleted file mode 100644
index d960fcc..0000000
--- a/src/cmd/6l/list.c
+++ /dev/null
@@ -1,67 +0,0 @@
-// Inferno utils/6l/list.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/list.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-// Printing.
-
-#include	"l.h"
-#include	"../ld/lib.h"
-
-void
-listinit(void)
-{
-	listinit6();
-	fmtinstall('I', Iconv);
-}
-
-int
-Iconv(Fmt *fp)
-{
-	int i, n;
-	uchar *p;
-	char *s;
-	Fmt fmt;
-	
-	n = fp->prec;
-	fp->prec = 0;
-	if(!(fp->flags&FmtPrec) || n < 0)
-		return fmtstrcpy(fp, "%I");
-	fp->flags &= ~FmtPrec;
-	p = va_arg(fp->args, uchar*);
-
-	// format into temporary buffer and
-	// call fmtstrcpy to handle padding.
-	fmtstrinit(&fmt);
-	for(i=0; i<n; i++)
-		fmtprint(&fmt, "%.2ux", *p++);
-	s = fmtstrflush(&fmt);
-	fmtstrcpy(fp, s);
-	free(s);
-	return 0;
-}
diff --git a/src/cmd/6l/obj.c b/src/cmd/6l/obj.c
deleted file mode 100644
index 3b8e8f4..0000000
--- a/src/cmd/6l/obj.c
+++ /dev/null
@@ -1,157 +0,0 @@
-// Inferno utils/6l/obj.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-// Reading object files.
-
-#include	"l.h"
-#include	"../ld/lib.h"
-#include	"../ld/elf.h"
-#include	"../ld/macho.h"
-#include	"../ld/dwarf.h"
-#include	"../ld/pe.h"
-#include	<ar.h>
-
-char*	thestring 	= "amd64";
-LinkArch*	thelinkarch = &linkamd64;
-
-void
-linkarchinit(void)
-{
-	if(strcmp(getgoarch(), "amd64p32") == 0)
-		thelinkarch = &linkamd64p32;
-	PtrSize = thelinkarch->ptrsize;
-	IntSize = PtrSize;
-	RegSize = thelinkarch->regsize;
-}
-
-void
-archinit(void)
-{
-	// getgoextlinkenabled is based on GO_EXTLINK_ENABLED when
-	// Go was built; see ../../make.bash.
-	if(linkmode == LinkAuto && strcmp(getgoextlinkenabled(), "0") == 0)
-		linkmode = LinkInternal;
-
-	if(flag_shared)
-		linkmode = LinkExternal;
-
-	switch(HEADTYPE) {
-	default:
-		if(linkmode == LinkAuto)
-			linkmode = LinkInternal;
-		if(linkmode == LinkExternal && strcmp(getgoextlinkenabled(), "1") != 0)
-			sysfatal("cannot use -linkmode=external with -H %s", headstr(HEADTYPE));
-		break;
-	case Hdarwin:
-	case Hdragonfly:
-	case Hfreebsd:
-	case Hlinux:
-	case Hnacl:
-	case Hnetbsd:
-	case Hopenbsd:
-	case Hsolaris:
-		break;
-	}
-
-	switch(HEADTYPE) {
-	default:
-		diag("unknown -H option");
-		errorexit();
-	case Hplan9:		/* plan 9 */
-		HEADR = 32L + 8L;
-		if(INITTEXT == -1)
-			INITTEXT = 0x200000+HEADR;
-		if(INITDAT == -1)
-			INITDAT = 0;
-		if(INITRND == -1)
-			INITRND = 0x200000;
-		break;
-	case Helf:		/* elf32 executable */
-		HEADR = rnd(52L+3*32L, 16);
-		if(INITTEXT == -1)
-			INITTEXT = 0x80110000L;
-		if(INITDAT == -1)
-			INITDAT = 0;
-		if(INITRND == -1)
-			INITRND = 4096;
-		break;
-	case Hdarwin:		/* apple MACH */
-		machoinit();
-		HEADR = INITIAL_MACHO_HEADR;
-		if(INITRND == -1)
-			INITRND = 4096;
-		if(INITTEXT == -1)
-			INITTEXT = 4096+HEADR;
-		if(INITDAT == -1)
-			INITDAT = 0;
-		break;
-	case Hlinux:		/* elf64 executable */
-	case Hfreebsd:		/* freebsd */
-	case Hnetbsd:		/* netbsd */
-	case Hopenbsd:		/* openbsd */
-	case Hdragonfly:	/* dragonfly */
-	case Hsolaris:		/* solaris */
-		elfinit();
-		HEADR = ELFRESERVE;
-		if(INITTEXT == -1)
-			INITTEXT = (1<<22)+HEADR;
-		if(INITDAT == -1)
-			INITDAT = 0;
-		if(INITRND == -1)
-			INITRND = 4096;
-		break;
-	case Hnacl:
-		elfinit();
-		debug['w']++; // disable dwarf, which gets confused and is useless anyway
-		HEADR = 0x10000;
-		funcalign = 32;
-		if(INITTEXT == -1)
-			INITTEXT = 0x20000;
-		if(INITDAT == -1)
-			INITDAT = 0;
-		if(INITRND == -1)
-			INITRND = 0x10000;
-		break;
-	case Hwindows:		/* PE executable */
-		peinit();
-		HEADR = PEFILEHEADR;
-		if(INITTEXT == -1)
-			INITTEXT = PEBASE+PESECTHEADR;
-		if(INITDAT == -1)
-			INITDAT = 0;
-		if(INITRND == -1)
-			INITRND = PESECTALIGN;
-		break;
-	}
-
-	if(INITDAT != 0 && INITRND != 0)
-		print("warning: -D0x%llux is ignored because of -R0x%ux\n",
-			INITDAT, INITRND);
-}
diff --git a/src/cmd/8a/Makefile b/src/cmd/8a/Makefile
deleted file mode 100644
index 27290dd..0000000
--- a/src/cmd/8a/Makefile
+++ /dev/null
@@ -1,10 +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.
-
-include ../../Make.dist
-
-install: y.tab.h
-
-y.tab.h: a.y
-	LANG=C LANGUAGE=en_US.UTF8 bison -d -v -y a.y
diff --git a/src/cmd/8a/a.h b/src/cmd/8a/a.h
deleted file mode 100644
index adc388c..0000000
--- a/src/cmd/8a/a.h
+++ /dev/null
@@ -1,182 +0,0 @@
-// Inferno utils/8a/a.h
-// http://code.google.com/p/inferno-os/source/browse/utils/8a/a.h
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.	All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include <bio.h>
-#include <link.h>
-#include "../8l/8.out.h"
-
-#ifndef	EXTERN
-#define	EXTERN	extern
-#endif
-
-#undef	getc
-#undef	ungetc
-#undef	BUFSIZ
-
-#define	getc	ccgetc
-#define	ungetc	ccungetc
-
-typedef	struct	Sym	Sym;
-typedef	struct	Ref	Ref;
-typedef	struct	Io	Io;
-typedef	struct	Addr2	Addr2;
-
-#define	MAXALIGN	7
-#define	FPCHIP		1
-#define	NSYMB		500
-#define	BUFSIZ		8192
-#define	HISTSZ		20
-#ifndef	EOF
-#define	EOF		(-1)
-#endif
-#define	IGN		(-2)
-#define	GETC()		((--fi.c < 0)? filbuf(): *fi.p++ & 0xff)
-#define	NHASH		503
-#define	STRINGSZ	200
-#define	NMACRO		10
-
-struct	Sym
-{
-	Sym*	link;
-	Ref*	ref;
-	char*	macro;
-	int32	value;
-	ushort	type;
-	char	*name;
-	char	sym;
-};
-#define	S	((Sym*)0)
-
-struct	Ref
-{
-	int	class;
-};
-
-EXTERN struct
-{
-	char*	p;
-	int	c;
-} fi;
-
-struct	Io
-{
-	Io*	link;
-	char	b[BUFSIZ];
-	char*	p;
-	short	c;
-	short	f;
-};
-#define	I	((Io*)0)
-
-struct	Addr2
-{
-	Addr	from;
-	Addr	to;
-};
-
-enum
-{
-	CLAST,
-	CMACARG,
-	CMACRO,
-	CPREPROC,
-};
-
-EXTERN	int	debug[256];
-EXTERN	Sym*	hash[NHASH];
-EXTERN	char**	Dlist;
-EXTERN	int	nDlist;
-EXTERN	int	newflag;
-EXTERN	char*	hunk;
-EXTERN	char**	include;
-EXTERN	Io*	iofree;
-EXTERN	Io*	ionext;
-EXTERN	Io*	iostack;
-EXTERN	int32	lineno;
-EXTERN	int	nerrors;
-EXTERN	int32	nhunk;
-EXTERN	int	ninclude;
-EXTERN	int32	nsymb;
-EXTERN	Addr	nullgen;
-EXTERN	char*	outfile;
-EXTERN	int	pass;
-EXTERN	int32	pc;
-EXTERN	int	peekc;
-EXTERN	int32	stmtline;
-EXTERN	int	sym;
-EXTERN	char*	symb;
-EXTERN	int	thechar;
-EXTERN	char*	thestring;
-EXTERN	int32	thunk;
-EXTERN	Biobuf	obuf;
-EXTERN	Link*	ctxt;
-EXTERN	Biobuf	bstdout;
-
-void*	alloc(int32);
-void*	allocn(void*, int32, int32);
-void	ensuresymb(int32);
-void	errorexit(void);
-void	pushio(void);
-void	newio(void);
-void	newfile(char*, int);
-Sym*	slookup(char*);
-Sym*	lookup(void);
-void	syminit(Sym*);
-int32	yylex(void);
-int	getc(void);
-int	getnsc(void);
-void	unget(int);
-int	escchar(int);
-void	cinit(void);
-void	checkscale(int);
-void	pinit(char*);
-void	cclean(void);
-int	isreg(Addr*);
-void	outcode(int, Addr2*);
-void	outhist(void);
-int	filbuf(void);
-Sym*	getsym(void);
-void	domacro(void);
-void	macund(void);
-void	macdef(void);
-void	macexpand(Sym*, char*);
-void	macinc(void);
-void	macprag(void);
-void	maclin(void);
-void	macif(int);
-void	macend(void);
-void	dodefine(char*);
-void	prfile(int32);
-void	linehist(char*, int);
-void	gethunk(void);
-void	yyerror(char*, ...);
-int	yyparse(void);
-void	setinclude(char*);
-int	assemble(char*);
diff --git a/src/cmd/8a/a.y b/src/cmd/8a/a.y
deleted file mode 100644
index 6bcf131..0000000
--- a/src/cmd/8a/a.y
+++ /dev/null
@@ -1,687 +0,0 @@
-// Inferno utils/8a/a.y
-// http://code.google.com/p/inferno-os/source/browse/utils/8a/a.y
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.	All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-%{
-#include <u.h>
-#include <stdio.h>	/* if we don't, bison will, and a.h re-#defines getc */
-#include <libc.h>
-#include "a.h"
-#include "../../runtime/funcdata.h"
-%}
-%union	{
-	Sym	*sym;
-	int32	lval;
-	struct {
-		int32 v1;
-		int32 v2;
-	} con2;
-	double	dval;
-	char	sval[8];
-	Addr	addr;
-	Addr2	addr2;
-}
-%left	'|'
-%left	'^'
-%left	'&'
-%left	'<' '>'
-%left	'+' '-'
-%left	'*' '/' '%'
-%token	<lval>	LTYPE0 LTYPE1 LTYPE2 LTYPE3 LTYPE4
-%token	<lval>	LTYPEC LTYPED LTYPEN LTYPER LTYPET LTYPES LTYPEM LTYPEI LTYPEG LTYPEXC
-%token	<lval>	LTYPEX LTYPEPC LTYPEF LCONST LFP LPC LSB
-%token	<lval>	LBREG LLREG LSREG LFREG LXREG
-%token	<dval>	LFCONST
-%token	<sval>	LSCONST LSP
-%token	<sym>	LNAME LLAB LVAR
-%type	<lval>	con expr pointer offset
-%type	<con2>	con2
-%type	<addr>	mem imm imm2 reg nam rel rem rim rom omem nmem
-%type	<addr2>	nonnon nonrel nonrem rimnon rimrem remrim
-%type	<addr2>	spec1 spec2 spec3 spec4 spec5 spec6 spec7 spec8 spec9 spec10 spec11 spec12
-%%
-prog:
-|	prog
-	{
-		stmtline = lineno;
-	}
-	line
-
-line:
-	LLAB ':'
-	{
-		if($1->value != pc)
-			yyerror("redeclaration of %s", $1->name);
-		$1->value = pc;
-	}
-	line
-|	LNAME ':'
-	{
-		$1->type = LLAB;
-		$1->value = pc;
-	}
-	line
-|	';'
-|	inst ';'
-|	error ';'
-
-inst:
-	LNAME '=' expr
-	{
-		$1->type = LVAR;
-		$1->value = $3;
-	}
-|	LVAR '=' expr
-	{
-		if($1->value != $3)
-			yyerror("redeclaration of %s", $1->name);
-		$1->value = $3;
-	}
-|	LTYPE0 nonnon	{ outcode($1, &$2); }
-|	LTYPE1 nonrem	{ outcode($1, &$2); }
-|	LTYPE2 rimnon	{ outcode($1, &$2); }
-|	LTYPE3 rimrem	{ outcode($1, &$2); }
-|	LTYPE4 remrim	{ outcode($1, &$2); }
-|	LTYPER nonrel	{ outcode($1, &$2); }
-|	LTYPED spec1	{ outcode($1, &$2); }
-|	LTYPET spec2	{ outcode($1, &$2); }
-|	LTYPEC spec3	{ outcode($1, &$2); }
-|	LTYPEN spec4	{ outcode($1, &$2); }
-|	LTYPES spec5	{ outcode($1, &$2); }
-|	LTYPEM spec6	{ outcode($1, &$2); }
-|	LTYPEI spec7	{ outcode($1, &$2); }
-|	LTYPEG spec8	{ outcode($1, &$2); }
-|	LTYPEXC spec9	{ outcode($1, &$2); }
-|	LTYPEX spec10	{ outcode($1, &$2); }
-|	LTYPEPC spec11	{ outcode($1, &$2); }
-|	LTYPEF spec12	{ outcode($1, &$2); }
-
-nonnon:
-	{
-		$$.from = nullgen;
-		$$.to = nullgen;
-	}
-|	','
-	{
-		$$.from = nullgen;
-		$$.to = nullgen;
-	}
-
-rimrem:
-	rim ',' rem
-	{
-		$$.from = $1;
-		$$.to = $3;
-	}
-
-remrim:
-	rem ',' rim
-	{
-		$$.from = $1;
-		$$.to = $3;
-	}
-
-rimnon:
-	rim ','
-	{
-		$$.from = $1;
-		$$.to = nullgen;
-	}
-|	rim
-	{
-		$$.from = $1;
-		$$.to = nullgen;
-	}
-
-nonrem:
-	',' rem
-	{
-		$$.from = nullgen;
-		$$.to = $2;
-	}
-|	rem
-	{
-		$$.from = nullgen;
-		$$.to = $1;
-	}
-
-nonrel:
-	',' rel
-	{
-		$$.from = nullgen;
-		$$.to = $2;
-	}
-|	rel
-	{
-		$$.from = nullgen;
-		$$.to = $1;
-	}
-|	imm ',' rel
-	{
-		$$.from = $1;
-		$$.to = $3;
-	}
-
-spec1:	/* DATA */
-	nam '/' con ',' imm
-	{
-		$$.from = $1;
-		$$.from.scale = $3;
-		$$.to = $5;
-	}
-
-spec2:	/* TEXT */
-	mem ',' imm2
-	{
-		$$.from = $1;
-		$$.to = $3;
-	}
-|	mem ',' con ',' imm2
-	{
-		$$.from = $1;
-		$$.from.scale = $3;
-		$$.to = $5;
-	}
-
-spec3:	/* JMP/CALL */
-	',' rom
-	{
-		$$.from = nullgen;
-		$$.to = $2;
-	}
-|	rom
-	{
-		$$.from = nullgen;
-		$$.to = $1;
-	}
-|	'*' nam
-	{
-		$$.from = nullgen;
-		$$.to = $2;
-		$$.to.index = $2.type;
-		$$.to.type = D_INDIR+D_ADDR;
-	}
-
-spec4:	/* NOP */
-	nonnon
-|	nonrem
-
-spec5:	/* SHL/SHR */
-	rim ',' rem
-	{
-		$$.from = $1;
-		$$.to = $3;
-	}
-|	rim ',' rem ':' LLREG
-	{
-		$$.from = $1;
-		$$.to = $3;
-		if($$.from.index != D_NONE)
-			yyerror("dp shift with lhs index");
-		$$.from.index = $5;
-	}
-
-spec6:	/* MOVW/MOVL */
-	rim ',' rem
-	{
-		$$.from = $1;
-		$$.to = $3;
-	}
-|	rim ',' rem ':' LSREG
-	{
-		$$.from = $1;
-		$$.to = $3;
-		if($$.to.index != D_NONE)
-			yyerror("dp move with lhs index");
-		$$.to.index = $5;
-	}
-
-spec7:
-	rim ','
-	{
-		$$.from = $1;
-		$$.to = nullgen;
-	}
-|	rim
-	{
-		$$.from = $1;
-		$$.to = nullgen;
-	}
-|	rim ',' rem
-	{
-		$$.from = $1;
-		$$.to = $3;
-	}
-
-spec8:	/* GLOBL */
-	mem ',' imm
-	{
-		$$.from = $1;
-		$$.to = $3;
-	}
-|	mem ',' con ',' imm
-	{
-		$$.from = $1;
-		$$.from.scale = $3;
-		$$.to = $5;
-	}
-
-spec9:	/* CMPPS/CMPPD */
-	reg ',' rem ',' con
-	{
-		$$.from = $1;
-		$$.to = $3;
-		$$.to.offset = $5;
-	}
-
-spec10:	/* PINSRD */
-	imm ',' rem ',' reg
-	{
-		$$.from = $3;
-		$$.to = $5;
-		if($1.type != D_CONST)
-			yyerror("illegal constant");
-		$$.to.offset = $1.offset;
-	}
-
-spec11:	/* PCDATA */
-	rim ',' rim
-	{
-		if($1.type != D_CONST || $3.type != D_CONST)
-			yyerror("arguments to PCDATA must be integer constants");
-		$$.from = $1;
-		$$.to = $3;
-	}
-
-spec12:	/* FUNCDATA */
-	rim ',' rim
-	{
-		if($1.type != D_CONST)
-			yyerror("index for FUNCDATA must be integer constant");
-		if($3.type != D_EXTERN && $3.type != D_STATIC)
-			yyerror("value for FUNCDATA must be symbol reference");
- 		$$.from = $1;
- 		$$.to = $3;
- 	}
-
-rem:
-	reg
-|	mem
-
-rom:
-	rel
-|	nmem
-|	'*' reg
-	{
-		$$ = $2;
-	}
-|	'*' omem
-	{
-		$$ = $2;
-	}
-|	reg
-|	omem
-|	imm
-
-rim:
-	rem
-|	imm
-
-rel:
-	con '(' LPC ')'
-	{
-		$$ = nullgen;
-		$$.type = D_BRANCH;
-		$$.offset = $1 + pc;
-	}
-|	LNAME offset
-	{
-		$$ = nullgen;
-		if(pass == 2)
-			yyerror("undefined label: %s", $1->name);
-		$$.type = D_BRANCH;
-		$$.offset = $2;
-	}
-|	LLAB offset
-	{
-		$$ = nullgen;
-		$$.type = D_BRANCH;
-		$$.offset = $1->value + $2;
-	}
-
-reg:
-	LBREG
-	{
-		$$ = nullgen;
-		$$.type = $1;
-	}
-|	LFREG
-	{
-		$$ = nullgen;
-		$$.type = $1;
-	}
-|	LLREG
-	{
-		$$ = nullgen;
-		$$.type = $1;
-	}
-|	LXREG
-	{
-		$$ = nullgen;
-		$$.type = $1;
-	}
-|	LSP
-	{
-		$$ = nullgen;
-		$$.type = D_SP;
-	}
-|	LSREG
-	{
-		$$ = nullgen;
-		$$.type = $1;
-	}
-
-imm:
-	'$' con
-	{
-		$$ = nullgen;
-		$$.type = D_CONST;
-		$$.offset = $2;
-	}
-|	'$' nam
-	{
-		$$ = $2;
-		$$.index = $2.type;
-		$$.type = D_ADDR;
-		/*
-		if($2.type == D_AUTO || $2.type == D_PARAM)
-			yyerror("constant cannot be automatic: %s",
-				$2.sym->name);
-		 */
-	}
-|	'$' LSCONST
-	{
-		$$ = nullgen;
-		$$.type = D_SCONST;
-		memcpy($$.u.sval, $2, sizeof($$.u.sval));
-	}
-|	'$' LFCONST
-	{
-		$$ = nullgen;
-		$$.type = D_FCONST;
-		$$.u.dval = $2;
-	}
-|	'$' '(' LFCONST ')'
-	{
-		$$ = nullgen;
-		$$.type = D_FCONST;
-		$$.u.dval = $3;
-	}
-|	'$' '(' '-' LFCONST ')'
-	{
-		$$ = nullgen;
-		$$.type = D_FCONST;
-		$$.u.dval = -$4;
-	}
-|	'$' '-' LFCONST
-	{
-		$$ = nullgen;
-		$$.type = D_FCONST;
-		$$.u.dval = -$3;
-	}
-
-imm2:
-	'$' con2
-	{
-		$$ = nullgen;
-		$$.type = D_CONST2;
-		$$.offset = $2.v1;
-		$$.offset2 = $2.v2;
-	}
-
-con2:
-	LCONST
-	{
-		$$.v1 = $1;
-		$$.v2 = ArgsSizeUnknown;
-	}
-|	'-' LCONST
-	{
-		$$.v1 = -$2;
-		$$.v2 = ArgsSizeUnknown;
-	}
-|	LCONST '-' LCONST
-	{
-		$$.v1 = $1;
-		$$.v2 = $3;
-	}
-|	'-' LCONST '-' LCONST
-	{
-		$$.v1 = -$2;
-		$$.v2 = $4;
-	}
-
-mem:
-	omem
-|	nmem
-
-omem:
-	con
-	{
-		$$ = nullgen;
-		$$.type = D_INDIR+D_NONE;
-		$$.offset = $1;
-	}
-|	con '(' LLREG ')'
-	{
-		$$ = nullgen;
-		$$.type = D_INDIR+$3;
-		$$.offset = $1;
-	}
-|	con '(' LSP ')'
-	{
-		$$ = nullgen;
-		$$.type = D_INDIR+D_SP;
-		$$.offset = $1;
-	}
-|	con '(' LLREG '*' con ')'
-	{
-		$$ = nullgen;
-		$$.type = D_INDIR+D_NONE;
-		$$.offset = $1;
-		$$.index = $3;
-		$$.scale = $5;
-		checkscale($$.scale);
-	}
-|	con '(' LLREG ')' '(' LLREG '*' con ')'
-	{
-		$$ = nullgen;
-		$$.type = D_INDIR+$3;
-		$$.offset = $1;
-		$$.index = $6;
-		$$.scale = $8;
-		checkscale($$.scale);
-	}
-|	con '(' LLREG ')' '(' LSREG '*' con ')'
-	{
-		$$ = nullgen;
-		$$.type = D_INDIR+$3;
-		$$.offset = $1;
-		$$.index = $6;
-		$$.scale = $8;
-		checkscale($$.scale);
-	}
-|	'(' LLREG ')'
-	{
-		$$ = nullgen;
-		$$.type = D_INDIR+$2;
-	}
-|	'(' LSP ')'
-	{
-		$$ = nullgen;
-		$$.type = D_INDIR+D_SP;
-	}
-|	con '(' LSREG ')'
-	{
-		$$ = nullgen;
-		$$.type = D_INDIR+$3;
-		$$.offset = $1;
-	}
-|	'(' LLREG '*' con ')'
-	{
-		$$ = nullgen;
-		$$.type = D_INDIR+D_NONE;
-		$$.index = $2;
-		$$.scale = $4;
-		checkscale($$.scale);
-	}
-|	'(' LLREG ')' '(' LLREG '*' con ')'
-	{
-		$$ = nullgen;
-		$$.type = D_INDIR+$2;
-		$$.index = $5;
-		$$.scale = $7;
-		checkscale($$.scale);
-	}
-
-nmem:
-	nam
-	{
-		$$ = $1;
-	}
-|	nam '(' LLREG '*' con ')'
-	{
-		$$ = $1;
-		$$.index = $3;
-		$$.scale = $5;
-		checkscale($$.scale);
-	}
-
-nam:
-	LNAME offset '(' pointer ')'
-	{
-		$$ = nullgen;
-		$$.type = $4;
-		$$.sym = linklookup(ctxt, $1->name, 0);
-		$$.offset = $2;
-	}
-|	LNAME '<' '>' offset '(' LSB ')'
-	{
-		$$ = nullgen;
-		$$.type = D_STATIC;
-		$$.sym = linklookup(ctxt, $1->name, 1);
-		$$.offset = $4;
-	}
-
-offset:
-	{
-		$$ = 0;
-	}
-|	'+' con
-	{
-		$$ = $2;
-	}
-|	'-' con
-	{
-		$$ = -$2;
-	}
-
-pointer:
-	LSB
-|	LSP
-	{
-		$$ = D_AUTO;
-	}
-|	LFP
-
-con:
-	LCONST
-|	LVAR
-	{
-		$$ = $1->value;
-	}
-|	'-' con
-	{
-		$$ = -$2;
-	}
-|	'+' con
-	{
-		$$ = $2;
-	}
-|	'~' con
-	{
-		$$ = ~$2;
-	}
-|	'(' expr ')'
-	{
-		$$ = $2;
-	}
-
-expr:
-	con
-|	expr '+' expr
-	{
-		$$ = $1 + $3;
-	}
-|	expr '-' expr
-	{
-		$$ = $1 - $3;
-	}
-|	expr '*' expr
-	{
-		$$ = $1 * $3;
-	}
-|	expr '/' expr
-	{
-		$$ = $1 / $3;
-	}
-|	expr '%' expr
-	{
-		$$ = $1 % $3;
-	}
-|	expr '<' '<' expr
-	{
-		$$ = $1 << $4;
-	}
-|	expr '>' '>' expr
-	{
-		$$ = $1 >> $4;
-	}
-|	expr '&' expr
-	{
-		$$ = $1 & $3;
-	}
-|	expr '^' expr
-	{
-		$$ = $1 ^ $3;
-	}
-|	expr '|' expr
-	{
-		$$ = $1 | $3;
-	}
diff --git a/src/cmd/8a/doc.go b/src/cmd/8a/doc.go
deleted file mode 100644
index 84c7254..0000000
--- a/src/cmd/8a/doc.go
+++ /dev/null
@@ -1,21 +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.
-
-// +build ignore
-
-/*
-
-8a is a version of the Plan 9 assembler.  The original is documented at
-
-	http://plan9.bell-labs.com/magic/man2html/1/8a
-
-Go-specific considerations are documented at
-
-	http://golang.org/doc/asm
-
-I
-Its target architecture is the x86, referred to by these tools for historical reasons as 386.
-
-*/
-package main
diff --git a/src/cmd/8a/lex.c b/src/cmd/8a/lex.c
deleted file mode 100644
index 6ce6a18..0000000
--- a/src/cmd/8a/lex.c
+++ /dev/null
@@ -1,910 +0,0 @@
-// Inferno utils/8a/lex.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8a/lex.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.	All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#define	EXTERN
-#include <u.h>
-#include <libc.h>
-#include "a.h"
-#include "y.tab.h"
-
-enum
-{
-	Plan9	= 1<<0,
-	Unix	= 1<<1,
-	Windows	= 1<<2,
-};
-
-int
-systemtype(int sys)
-{
-#ifdef _WIN32
-	return sys&Windows;
-#else
-	return sys&Plan9;
-#endif
-}
-
-int
-pathchar(void)
-{
-	return '/';
-}
-
-int
-Lconv(Fmt *fp)
-{
-	return linklinefmt(ctxt, fp);
-}
-
-void
-dodef(char *p)
-{
-	if(nDlist%8 == 0)
-		Dlist = allocn(Dlist, nDlist*sizeof(char *),
-			8*sizeof(char *));
-	Dlist[nDlist++] = p;
-}
-
-void
-usage(void)
-{
-	print("usage: %ca [options] file.c...\n", thechar);
-	flagprint(1);
-	errorexit();
-}
-void
-main(int argc, char *argv[])
-{
-	char *p;
-
-	thechar = '8';
-	thestring = "386";
-
-	ctxt = linknew(&link386);
-	ctxt->diag = yyerror;
-	ctxt->bso = &bstdout;
-	ctxt->enforce_data_order = 1;
-	Binit(&bstdout, 1, OWRITE);
-	listinit8();
-	fmtinstall('L', Lconv);
-
-	// Allow GOARCH=thestring or GOARCH=thestringsuffix,
-	// but not other values.	
-	p = getgoarch();
-	if(strncmp(p, thestring, strlen(thestring)) != 0)
-		sysfatal("cannot use %cc with GOARCH=%s", thechar, p);
-
-	ensuresymb(NSYMB);
-	memset(debug, 0, sizeof(debug));
-	cinit();
-	outfile = 0;
-	setinclude(".");
-	
-	flagfn1("D", "name[=value]: add #define", dodef);
-	flagfn1("I", "dir: add dir to include path", setinclude);
-	flagcount("S", "print assembly and machine code", &debug['S']);
-	flagcount("m", "debug preprocessor macros", &debug['m']);
-	flagstr("o", "file: set output file", &outfile);
-	flagstr("trimpath", "prefix: remove prefix from recorded source file paths", &ctxt->trimpath);
-
-	flagparse(&argc, &argv, usage);
-	ctxt->debugasm = debug['S'];
-
-	if(argc < 1)
-		usage();
-	if(argc > 1){
-		print("can't assemble multiple files\n");
-		errorexit();
-	}
-
-	if(assemble(argv[0]))
-		errorexit();
-	Bflush(&bstdout);
-	exits(0);
-}
-
-int
-assemble(char *file)
-{
-	char *ofile, *p;
-	int i, of;
-
-	ofile = alloc(strlen(file)+3); // +3 for .x\0 (x=thechar)
-	strcpy(ofile, file);
-	p = utfrrune(ofile, pathchar());
-	if(p) {
-		include[0] = ofile;
-		*p++ = 0;
-	} else
-		p = ofile;
-	if(outfile == 0) {
-		outfile = p;
-		if(outfile){
-			p = utfrrune(outfile, '.');
-			if(p)
-				if(p[1] == 's' && p[2] == 0)
-					p[0] = 0;
-			p = utfrune(outfile, 0);
-			p[0] = '.';
-			p[1] = thechar;
-			p[2] = 0;
-		} else
-			outfile = "/dev/null";
-	}
-
-	of = create(outfile, OWRITE, 0664);
-	if(of < 0) {
-		yyerror("%ca: cannot create %s", thechar, outfile);
-		errorexit();
-	}
-	Binit(&obuf, of, OWRITE);
-	Bprint(&obuf, "go object %s %s %s\n", getgoos(), getgoarch(), getgoversion());
-	Bprint(&obuf, "!\n");
-
-	for(pass = 1; pass <= 2; pass++) {
-		pinit(file);
-		for(i=0; i<nDlist; i++)
-			dodefine(Dlist[i]);
-		yyparse();
-		cclean();
-		if(nerrors)
-			return nerrors;
-	}
-
-	writeobj(ctxt, &obuf);
-	Bflush(&obuf);
-	return 0;
-}
-
-struct
-{
-	char	*name;
-	ushort	type;
-	ushort	value;
-} itab[] =
-{
-	"SP",		LSP,	D_AUTO,
-	"SB",		LSB,	D_EXTERN,
-	"FP",		LFP,	D_PARAM,
-	"PC",		LPC,	D_BRANCH,
-
-	"AL",		LBREG,	D_AL,
-	"CL",		LBREG,	D_CL,
-	"DL",		LBREG,	D_DL,
-	"BL",		LBREG,	D_BL,
-	"AH",		LBREG,	D_AH,
-	"CH",		LBREG,	D_CH,
-	"DH",		LBREG,	D_DH,
-	"BH",		LBREG,	D_BH,
-
-	"AX",		LLREG,	D_AX,
-	"CX",		LLREG,	D_CX,
-	"DX",		LLREG,	D_DX,
-	"BX",		LLREG,	D_BX,
-/*	"SP",		LLREG,	D_SP,	*/
-	"BP",		LLREG,	D_BP,
-	"SI",		LLREG,	D_SI,
-	"DI",		LLREG,	D_DI,
-
-	"F0",		LFREG,	D_F0+0,
-	"F1",		LFREG,	D_F0+1,
-	"F2",		LFREG,	D_F0+2,
-	"F3",		LFREG,	D_F0+3,
-	"F4",		LFREG,	D_F0+4,
-	"F5",		LFREG,	D_F0+5,
-	"F6",		LFREG,	D_F0+6,
-	"F7",		LFREG,	D_F0+7,
-
-	"X0",		LXREG,	D_X0+0,
-	"X1",		LXREG,	D_X0+1,
-	"X2",		LXREG,	D_X0+2,
-	"X3",		LXREG,	D_X0+3,
-	"X4",		LXREG,	D_X0+4,
-	"X5",		LXREG,	D_X0+5,
-	"X6",		LXREG,	D_X0+6,
-	"X7",		LXREG,	D_X0+7,
-
-	"CS",		LSREG,	D_CS,
-	"SS",		LSREG,	D_SS,
-	"DS",		LSREG,	D_DS,
-	"ES",		LSREG,	D_ES,
-	"FS",		LSREG,	D_FS,
-	"GS",		LSREG,	D_GS,
-	"TLS",		LSREG,	D_TLS,
-
-	"GDTR",		LBREG,	D_GDTR,
-	"IDTR",		LBREG,	D_IDTR,
-	"LDTR",		LBREG,	D_LDTR,
-	"MSW",		LBREG,	D_MSW,
-	"TASK",		LBREG,	D_TASK,
-
-	"CR0",		LBREG,	D_CR+0,
-	"CR1",		LBREG,	D_CR+1,
-	"CR2",		LBREG,	D_CR+2,
-	"CR3",		LBREG,	D_CR+3,
-	"CR4",		LBREG,	D_CR+4,
-	"CR5",		LBREG,	D_CR+5,
-	"CR6",		LBREG,	D_CR+6,
-	"CR7",		LBREG,	D_CR+7,
-
-	"DR0",		LBREG,	D_DR+0,
-	"DR1",		LBREG,	D_DR+1,
-	"DR2",		LBREG,	D_DR+2,
-	"DR3",		LBREG,	D_DR+3,
-	"DR4",		LBREG,	D_DR+4,
-	"DR5",		LBREG,	D_DR+5,
-	"DR6",		LBREG,	D_DR+6,
-	"DR7",		LBREG,	D_DR+7,
-
-	"TR0",		LBREG,	D_TR+0,
-	"TR1",		LBREG,	D_TR+1,
-	"TR2",		LBREG,	D_TR+2,
-	"TR3",		LBREG,	D_TR+3,
-	"TR4",		LBREG,	D_TR+4,
-	"TR5",		LBREG,	D_TR+5,
-	"TR6",		LBREG,	D_TR+6,
-	"TR7",		LBREG,	D_TR+7,
-
-	"AAA",		LTYPE0,	AAAA,
-	"AAD",		LTYPE0,	AAAD,
-	"AAM",		LTYPE0,	AAAM,
-	"AAS",		LTYPE0,	AAAS,
-	"ADCB",		LTYPE3,	AADCB,
-	"ADCL",		LTYPE3,	AADCL,
-	"ADCW",		LTYPE3,	AADCW,
-	"ADDB",		LTYPE3,	AADDB,
-	"ADDL",		LTYPE3,	AADDL,
-	"ADDW",		LTYPE3,	AADDW,
-	"ADJSP",	LTYPE2,	AADJSP,
-	"ANDB",		LTYPE3,	AANDB,
-	"ANDL",		LTYPE3,	AANDL,
-	"ANDW",		LTYPE3,	AANDW,
-	"ARPL",		LTYPE3,	AARPL,
-	"BOUNDL",	LTYPE3,	ABOUNDL,
-	"BOUNDW",	LTYPE3,	ABOUNDW,
-	"BSFL",		LTYPE3,	ABSFL,
-	"BSFW",		LTYPE3,	ABSFW,
-	"BSRL",		LTYPE3,	ABSRL,
-	"BSRW",		LTYPE3,	ABSRW,
-	"BSWAPL",	LTYPE1,	ABSWAPL,
-	"BTCL",		LTYPE3,	ABTCL,
-	"BTCW",		LTYPE3,	ABTCW,
-	"BTL",		LTYPE3,	ABTL,
-	"BTRL",		LTYPE3,	ABTRL,
-	"BTRW",		LTYPE3,	ABTRW,
-	"BTSL",		LTYPE3,	ABTSL,
-	"BTSW",		LTYPE3,	ABTSW,
-	"BTW",		LTYPE3,	ABTW,
-	"BYTE",		LTYPE2,	ABYTE,
-	"CALL",		LTYPEC,	ACALL,
-	"CLC",		LTYPE0,	ACLC,
-	"CLD",		LTYPE0,	ACLD,
-	"CLI",		LTYPE0,	ACLI,
-	"CLTS",		LTYPE0,	ACLTS,
-	"CMC",		LTYPE0,	ACMC,
-	"CMPB",		LTYPE4,	ACMPB,
-	"CMPL",		LTYPE4,	ACMPL,
-	"CMPW",		LTYPE4,	ACMPW,
-	"CMPSB",	LTYPE0,	ACMPSB,
-	"CMPSL",	LTYPE0,	ACMPSL,
-	"CMPSW",	LTYPE0,	ACMPSW,
-	"CMPXCHG8B",	LTYPE1,	ACMPXCHG8B,
-	"CMPXCHGB",	LTYPE3,	ACMPXCHGB,
-	"CMPXCHGL",	LTYPE3,	ACMPXCHGL,
-	"CMPXCHGW",	LTYPE3,	ACMPXCHGW,
-	"CPUID",	LTYPE0,	ACPUID,
-	"DAA",		LTYPE0,	ADAA,
-	"DAS",		LTYPE0,	ADAS,
-	"DATA",		LTYPED,	ADATA,
-	"DECB",		LTYPE1,	ADECB,
-	"DECL",		LTYPE1,	ADECL,
-	"DECW",		LTYPE1,	ADECW,
-	"DIVB",		LTYPE2,	ADIVB,
-	"DIVL",		LTYPE2,	ADIVL,
-	"DIVW",		LTYPE2,	ADIVW,
-	"END",		LTYPE0,	AEND,
-	"ENTER",	LTYPE2,	AENTER,
-	"GLOBL",	LTYPEG,	AGLOBL,
-	"HLT",		LTYPE0,	AHLT,
-	"IDIVB",	LTYPE2,	AIDIVB,
-	"IDIVL",	LTYPE2,	AIDIVL,
-	"IDIVW",	LTYPE2,	AIDIVW,
-	"IMULB",	LTYPE2,	AIMULB,
-	"IMULL",	LTYPEI,	AIMULL,
-	"IMULW",	LTYPEI,	AIMULW,
-	"INB",		LTYPE0,	AINB,
-	"INL",		LTYPE0,	AINL,
-	"INW",		LTYPE0,	AINW,
-	"INCB",		LTYPE1,	AINCB,
-	"INCL",		LTYPE1,	AINCL,
-	"INCW",		LTYPE1,	AINCW,
-	"INSB",		LTYPE0,	AINSB,
-	"INSL",		LTYPE0,	AINSL,
-	"INSW",		LTYPE0,	AINSW,
-	"INT",		LTYPE2,	AINT,
-	"INTO",		LTYPE0,	AINTO,
-	"IRETL",	LTYPE0,	AIRETL,
-	"IRETW",	LTYPE0,	AIRETW,
-
-	"JOS",		LTYPER,	AJOS,	/* overflow set (OF = 1) */
-	"JO",		LTYPER,	AJOS,	/* alternate */
-	"JOC",		LTYPER,	AJOC,	/* overflow clear (OF = 0) */
-	"JNO",		LTYPER,	AJOC,	/* alternate */
-	"JCS",		LTYPER,	AJCS,	/* carry set (CF = 1) */
-	"JB",		LTYPER,	AJCS,	/* alternate */
-	"JC",		LTYPER,	AJCS,	/* alternate */
-	"JNAE",		LTYPER,	AJCS,	/* alternate */
-	"JLO",		LTYPER,	AJCS,	/* alternate */
-	"JCC",		LTYPER,	AJCC,	/* carry clear (CF = 0) */
-	"JAE",		LTYPER,	AJCC,	/* alternate */
-	"JNB",		LTYPER,	AJCC,	/* alternate */
-	"JNC",		LTYPER,	AJCC,	/* alternate */
-	"JHS",		LTYPER,	AJCC,	/* alternate */
-	"JEQ",		LTYPER,	AJEQ,	/* equal (ZF = 1) */
-	"JE",		LTYPER,	AJEQ,	/* alternate */
-	"JZ",		LTYPER,	AJEQ,	/* alternate */
-	"JNE",		LTYPER,	AJNE,	/* not equal (ZF = 0) */
-	"JNZ",		LTYPER,	AJNE,	/* alternate */
-	"JLS",		LTYPER,	AJLS,	/* lower or same (unsigned) (CF = 1 || ZF = 1) */
-	"JBE",		LTYPER,	AJLS,	/* alternate */
-	"JNA",		LTYPER,	AJLS,	/* alternate */
-	"JHI",		LTYPER,	AJHI,	/* higher (unsigned) (CF = 0 && ZF = 0) */
-	"JA",		LTYPER,	AJHI,	/* alternate */
-	"JNBE",		LTYPER,	AJHI,	/* alternate */
-	"JMI",		LTYPER,	AJMI,	/* negative (minus) (SF = 1) */
-	"JS",		LTYPER,	AJMI,	/* alternate */
-	"JPL",		LTYPER,	AJPL,	/* non-negative (plus) (SF = 0) */
-	"JNS",		LTYPER,	AJPL,	/* alternate */
-	"JPS",		LTYPER,	AJPS,	/* parity set (PF = 1) */
-	"JP",		LTYPER,	AJPS,	/* alternate */
-	"JPE",		LTYPER,	AJPS,	/* alternate */
-	"JPC",		LTYPER,	AJPC,	/* parity clear (PF = 0) */
-	"JNP",		LTYPER,	AJPC,	/* alternate */
-	"JPO",		LTYPER,	AJPC,	/* alternate */
-	"JLT",		LTYPER,	AJLT,	/* less than (signed) (SF != OF) */
-	"JL",		LTYPER,	AJLT,	/* alternate */
-	"JNGE",		LTYPER,	AJLT,	/* alternate */
-	"JGE",		LTYPER,	AJGE,	/* greater than or equal (signed) (SF = OF) */
-	"JNL",		LTYPER,	AJGE,	/* alternate */
-	"JLE",		LTYPER,	AJLE,	/* less than or equal (signed) (ZF = 1 || SF != OF) */
-	"JNG",		LTYPER,	AJLE,	/* alternate */
-	"JGT",		LTYPER,	AJGT,	/* greater than (signed) (ZF = 0 && SF = OF) */
-	"JG",		LTYPER,	AJGT,	/* alternate */
-	"JNLE",		LTYPER,	AJGT,	/* alternate */
-
-	"JCXZL",	LTYPER,	AJCXZL,
-	"JCXZW",	LTYPER,	AJCXZW,
-	"JMP",		LTYPEC,	AJMP,
-	"LAHF",		LTYPE0,	ALAHF,
-	"LARL",		LTYPE3,	ALARL,
-	"LARW",		LTYPE3,	ALARW,
-	"LEAL",		LTYPE3,	ALEAL,
-	"LEAW",		LTYPE3,	ALEAW,
-	"LEAVEL",	LTYPE0,	ALEAVEL,
-	"LEAVEW",	LTYPE0,	ALEAVEW,
-	"LOCK",		LTYPE0,	ALOCK,
-	"LODSB",	LTYPE0,	ALODSB,
-	"LODSL",	LTYPE0,	ALODSL,
-	"LODSW",	LTYPE0,	ALODSW,
-	"LONG",		LTYPE2,	ALONG,
-	"LOOP",		LTYPER,	ALOOP,
-	"LOOPEQ",	LTYPER,	ALOOPEQ,
-	"LOOPNE",	LTYPER,	ALOOPNE,
-	"LSLL",		LTYPE3,	ALSLL,
-	"LSLW",		LTYPE3,	ALSLW,
-	"MOVB",		LTYPE3,	AMOVB,
-	"MOVL",		LTYPEM,	AMOVL,
-	"MOVW",		LTYPEM,	AMOVW,
-	"MOVQ",		LTYPEM, AMOVQ,
-	"MOVBLSX",	LTYPE3, AMOVBLSX,
-	"MOVBLZX",	LTYPE3, AMOVBLZX,
-	"MOVBWSX",	LTYPE3, AMOVBWSX,
-	"MOVBWZX",	LTYPE3, AMOVBWZX,
-	"MOVWLSX",	LTYPE3, AMOVWLSX,
-	"MOVWLZX",	LTYPE3, AMOVWLZX,
-	"MOVSB",	LTYPE0,	AMOVSB,
-	"MOVSL",	LTYPE0,	AMOVSL,
-	"MOVSW",	LTYPE0,	AMOVSW,
-	"MULB",		LTYPE2,	AMULB,
-	"MULL",		LTYPE2,	AMULL,
-	"MULW",		LTYPE2,	AMULW,
-	"NEGB",		LTYPE1,	ANEGB,
-	"NEGL",		LTYPE1,	ANEGL,
-	"NEGW",		LTYPE1,	ANEGW,
-	"NOP",		LTYPEN,	ANOP,
-	"NOTB",		LTYPE1,	ANOTB,
-	"NOTL",		LTYPE1,	ANOTL,
-	"NOTW",		LTYPE1,	ANOTW,
-	"ORB",		LTYPE3,	AORB,
-	"ORL",		LTYPE3,	AORL,
-	"ORW",		LTYPE3,	AORW,
-	"OUTB",		LTYPE0,	AOUTB,
-	"OUTL",		LTYPE0,	AOUTL,
-	"OUTW",		LTYPE0,	AOUTW,
-	"OUTSB",	LTYPE0,	AOUTSB,
-	"OUTSL",	LTYPE0,	AOUTSL,
-	"OUTSW",	LTYPE0,	AOUTSW,
-	"PAUSE",	LTYPEN,	APAUSE,
-	"PINSRD",	LTYPEX,	APINSRD,
-	"POPAL",	LTYPE0,	APOPAL,
-	"POPAW",	LTYPE0,	APOPAW,
-	"POPFL",	LTYPE0,	APOPFL,
-	"POPFW",	LTYPE0,	APOPFW,
-	"POPL",		LTYPE1,	APOPL,
-	"POPW",		LTYPE1,	APOPW,
-	"PUSHAL",	LTYPE0,	APUSHAL,
-	"PUSHAW",	LTYPE0,	APUSHAW,
-	"PUSHFL",	LTYPE0,	APUSHFL,
-	"PUSHFW",	LTYPE0,	APUSHFW,
-	"PUSHL",	LTYPE2,	APUSHL,
-	"PUSHW",	LTYPE2,	APUSHW,
-	"RCLB",		LTYPE3,	ARCLB,
-	"RCLL",		LTYPE3,	ARCLL,
-	"RCLW",		LTYPE3,	ARCLW,
-	"RCRB",		LTYPE3,	ARCRB,
-	"RCRL",		LTYPE3,	ARCRL,
-	"RCRW",		LTYPE3,	ARCRW,
-	"RDTSC",	LTYPE0,	ARDTSC,
-	"REP",		LTYPE0,	AREP,
-	"REPN",		LTYPE0,	AREPN,
-	"RET",		LTYPE0,	ARET,
-	"ROLB",		LTYPE3,	AROLB,
-	"ROLL",		LTYPE3,	AROLL,
-	"ROLW",		LTYPE3,	AROLW,
-	"RORB",		LTYPE3,	ARORB,
-	"RORL",		LTYPE3,	ARORL,
-	"RORW",		LTYPE3,	ARORW,
-	"SAHF",		LTYPE0,	ASAHF,
-	"SALB",		LTYPE3,	ASALB,
-	"SALL",		LTYPE3,	ASALL,
-	"SALW",		LTYPE3,	ASALW,
-	"SARB",		LTYPE3,	ASARB,
-	"SARL",		LTYPE3,	ASARL,
-	"SARW",		LTYPE3,	ASARW,
-	"SBBB",		LTYPE3,	ASBBB,
-	"SBBL",		LTYPE3,	ASBBL,
-	"SBBW",		LTYPE3,	ASBBW,
-	"SCASB",	LTYPE0,	ASCASB,
-	"SCASL",	LTYPE0,	ASCASL,
-	"SCASW",	LTYPE0,	ASCASW,
-	"SETCC",	LTYPE1,	ASETCC,	/* see JCC etc above for condition codes */
-	"SETCS",	LTYPE1,	ASETCS,
-	"SETEQ",	LTYPE1,	ASETEQ,
-	"SETGE",	LTYPE1,	ASETGE,
-	"SETGT",	LTYPE1,	ASETGT,
-	"SETHI",	LTYPE1,	ASETHI,
-	"SETLE",	LTYPE1,	ASETLE,
-	"SETLS",	LTYPE1,	ASETLS,
-	"SETLT",	LTYPE1,	ASETLT,
-	"SETMI",	LTYPE1,	ASETMI,
-	"SETNE",	LTYPE1,	ASETNE,
-	"SETOC",	LTYPE1,	ASETOC,
-	"SETOS",	LTYPE1,	ASETOS,
-	"SETPC",	LTYPE1,	ASETPC,
-	"SETPL",	LTYPE1,	ASETPL,
-	"SETPS",	LTYPE1,	ASETPS,
-	"CDQ",		LTYPE0,	ACDQ,
-	"CWD",		LTYPE0,	ACWD,
-	"SHLB",		LTYPE3,	ASHLB,
-	"SHLL",		LTYPES,	ASHLL,
-	"SHLW",		LTYPES,	ASHLW,
-	"SHRB",		LTYPE3,	ASHRB,
-	"SHRL",		LTYPES,	ASHRL,
-	"SHRW",		LTYPES,	ASHRW,
-	"STC",		LTYPE0,	ASTC,
-	"STD",		LTYPE0,	ASTD,
-	"STI",		LTYPE0,	ASTI,
-	"STOSB",	LTYPE0,	ASTOSB,
-	"STOSL",	LTYPE0,	ASTOSL,
-	"STOSW",	LTYPE0,	ASTOSW,
-	"SUBB",		LTYPE3,	ASUBB,
-	"SUBL",		LTYPE3,	ASUBL,
-	"SUBW",		LTYPE3,	ASUBW,
-	"SYSCALL",	LTYPE0,	ASYSCALL,
-	"TESTB",	LTYPE3,	ATESTB,
-	"TESTL",	LTYPE3,	ATESTL,
-	"TESTW",	LTYPE3,	ATESTW,
-	"TEXT",		LTYPET,	ATEXT,
-	"VERR",		LTYPE2,	AVERR,
-	"VERW",		LTYPE2,	AVERW,
-	"WAIT",		LTYPE0,	AWAIT,
-	"WORD",		LTYPE2,	AWORD,
-	"XADDB",	LTYPE3,	AXADDB,
-	"XADDL",	LTYPE3,	AXADDL,
-	"XADDW",	LTYPE3,	AXADDW,
-	"XCHGB",	LTYPE3,	AXCHGB,
-	"XCHGL",	LTYPE3,	AXCHGL,
-	"XCHGW",	LTYPE3,	AXCHGW,
-	"XLAT",		LTYPE2,	AXLAT,
-	"XORB",		LTYPE3,	AXORB,
-	"XORL",		LTYPE3,	AXORL,
-	"XORW",		LTYPE3,	AXORW,
-
-	"CMOVLCC",	LTYPE3,	ACMOVLCC,
-	"CMOVLCS",	LTYPE3,	ACMOVLCS,
-	"CMOVLEQ",	LTYPE3,	ACMOVLEQ,
-	"CMOVLGE",	LTYPE3,	ACMOVLGE,
-	"CMOVLGT",	LTYPE3,	ACMOVLGT,
-	"CMOVLHI",	LTYPE3,	ACMOVLHI,
-	"CMOVLLE",	LTYPE3,	ACMOVLLE,
-	"CMOVLLS",	LTYPE3,	ACMOVLLS,
-	"CMOVLLT",	LTYPE3,	ACMOVLLT,
-	"CMOVLMI",	LTYPE3,	ACMOVLMI,
-	"CMOVLNE",	LTYPE3,	ACMOVLNE,
-	"CMOVLOC",	LTYPE3,	ACMOVLOC,
-	"CMOVLOS",	LTYPE3,	ACMOVLOS,
-	"CMOVLPC",	LTYPE3,	ACMOVLPC,
-	"CMOVLPL",	LTYPE3,	ACMOVLPL,
-	"CMOVLPS",	LTYPE3,	ACMOVLPS,
-	"CMOVWCC",	LTYPE3,	ACMOVWCC,
-	"CMOVWCS",	LTYPE3,	ACMOVWCS,
-	"CMOVWEQ",	LTYPE3,	ACMOVWEQ,
-	"CMOVWGE",	LTYPE3,	ACMOVWGE,
-	"CMOVWGT",	LTYPE3,	ACMOVWGT,
-	"CMOVWHI",	LTYPE3,	ACMOVWHI,
-	"CMOVWLE",	LTYPE3,	ACMOVWLE,
-	"CMOVWLS",	LTYPE3,	ACMOVWLS,
-	"CMOVWLT",	LTYPE3,	ACMOVWLT,
-	"CMOVWMI",	LTYPE3,	ACMOVWMI,
-	"CMOVWNE",	LTYPE3,	ACMOVWNE,
-	"CMOVWOC",	LTYPE3,	ACMOVWOC,
-	"CMOVWOS",	LTYPE3,	ACMOVWOS,
-	"CMOVWPC",	LTYPE3,	ACMOVWPC,
-	"CMOVWPL",	LTYPE3,	ACMOVWPL,
-	"CMOVWPS",	LTYPE3,	ACMOVWPS,
-
-	"FMOVB",	LTYPE3, AFMOVB,
-	"FMOVBP",	LTYPE3, AFMOVBP,
-	"FMOVD",	LTYPE3, AFMOVD,
-	"FMOVDP",	LTYPE3, AFMOVDP,
-	"FMOVF",	LTYPE3, AFMOVF,
-	"FMOVFP",	LTYPE3, AFMOVFP,
-	"FMOVL",	LTYPE3, AFMOVL,
-	"FMOVLP",	LTYPE3, AFMOVLP,
-	"FMOVV",	LTYPE3, AFMOVV,
-	"FMOVVP",	LTYPE3, AFMOVVP,
-	"FMOVW",	LTYPE3, AFMOVW,
-	"FMOVWP",	LTYPE3, AFMOVWP,
-	"FMOVX",	LTYPE3, AFMOVX,
-	"FMOVXP",	LTYPE3, AFMOVXP,
-	"FCMOVCC",	LTYPE3, AFCMOVCC,
-	"FCMOVCS",	LTYPE3, AFCMOVCS,
-	"FCMOVEQ",	LTYPE3, AFCMOVEQ,
-	"FCMOVHI",	LTYPE3, AFCMOVHI,
-	"FCMOVLS",	LTYPE3, AFCMOVLS,
-	"FCMOVNE",	LTYPE3, AFCMOVNE,
-	"FCMOVNU",	LTYPE3, AFCMOVNU,
-	"FCMOVUN",	LTYPE3, AFCMOVUN,
-	"FCOMB",	LTYPE3, AFCOMB,
-	"FCOMBP",	LTYPE3, AFCOMBP,
-	"FCOMD",	LTYPE3, AFCOMD,
-	"FCOMDP",	LTYPE3, AFCOMDP,
-	"FCOMDPP",	LTYPE3, AFCOMDPP,
-	"FCOMF",	LTYPE3, AFCOMF,
-	"FCOMFP",	LTYPE3, AFCOMFP,
-	"FCOMI",	LTYPE3, AFCOMI,
-	"FCOMIP",	LTYPE3, AFCOMIP,
-	"FCOML",	LTYPE3, AFCOML,
-	"FCOMLP",	LTYPE3, AFCOMLP,
-	"FCOMW",	LTYPE3, AFCOMW,
-	"FCOMWP",	LTYPE3, AFCOMWP,
-	"FUCOM",	LTYPE3, AFUCOM,
-	"FUCOMI",	LTYPE3, AFUCOMI,
-	"FUCOMIP",	LTYPE3, AFUCOMIP,
-	"FUCOMP",	LTYPE3, AFUCOMP,
-	"FUCOMPP",	LTYPE3, AFUCOMPP,
-	"FADDW",	LTYPE3, AFADDW,
-	"FADDL",	LTYPE3, AFADDL,
-	"FADDF",	LTYPE3, AFADDF,
-	"FADDD",	LTYPE3, AFADDD,
-	"FADDDP",	LTYPE3, AFADDDP,
-	"FSUBDP",	LTYPE3, AFSUBDP,
-	"FSUBW",	LTYPE3, AFSUBW,
-	"FSUBL",	LTYPE3, AFSUBL,
-	"FSUBF",	LTYPE3, AFSUBF,
-	"FSUBD",	LTYPE3, AFSUBD,
-	"FSUBRDP",	LTYPE3, AFSUBRDP,
-	"FSUBRW",	LTYPE3, AFSUBRW,
-	"FSUBRL",	LTYPE3, AFSUBRL,
-	"FSUBRF",	LTYPE3, AFSUBRF,
-	"FSUBRD",	LTYPE3, AFSUBRD,
-	"FMULDP",	LTYPE3, AFMULDP,
-	"FMULW",	LTYPE3, AFMULW,
-	"FMULL",	LTYPE3, AFMULL,
-	"FMULF",	LTYPE3, AFMULF,
-	"FMULD",	LTYPE3, AFMULD,
-	"FDIVDP",	LTYPE3, AFDIVDP,
-	"FDIVW",	LTYPE3, AFDIVW,
-	"FDIVL",	LTYPE3, AFDIVL,
-	"FDIVF",	LTYPE3, AFDIVF,
-	"FDIVD",	LTYPE3, AFDIVD,
-	"FDIVRDP",	LTYPE3, AFDIVRDP,
-	"FDIVRW",	LTYPE3, AFDIVRW,
-	"FDIVRL",	LTYPE3, AFDIVRL,
-	"FDIVRF",	LTYPE3, AFDIVRF,
-	"FDIVRD",	LTYPE3, AFDIVRD,
-	"FXCHD",	LTYPE3, AFXCHD,
-	"FFREE",	LTYPE1, AFFREE,
-	"FLDCW",	LTYPE2, AFLDCW,
-	"FLDENV",	LTYPE1, AFLDENV,
-	"FRSTOR",	LTYPE2, AFRSTOR,
-	"FSAVE",	LTYPE1, AFSAVE,
-	"FSTCW",	LTYPE1, AFSTCW,
-	"FSTENV",	LTYPE1, AFSTENV,
-	"FSTSW",	LTYPE1, AFSTSW,
-	"F2XM1",	LTYPE0, AF2XM1,
-	"FABS",		LTYPE0, AFABS,
-	"FCHS",		LTYPE0, AFCHS,
-	"FCLEX",	LTYPE0, AFCLEX,
-	"FCOS",		LTYPE0, AFCOS,
-	"FDECSTP",	LTYPE0, AFDECSTP,
-	"FINCSTP",	LTYPE0, AFINCSTP,
-	"FINIT",	LTYPE0, AFINIT,
-	"FLD1",		LTYPE0, AFLD1,
-	"FLDL2E",	LTYPE0, AFLDL2E,
-	"FLDL2T",	LTYPE0, AFLDL2T,
-	"FLDLG2",	LTYPE0, AFLDLG2,
-	"FLDLN2",	LTYPE0, AFLDLN2,
-	"FLDPI",	LTYPE0, AFLDPI,
-	"FLDZ",		LTYPE0, AFLDZ,
-	"FNOP",		LTYPE0, AFNOP,
-	"FPATAN",	LTYPE0, AFPATAN,
-	"FPREM",	LTYPE0, AFPREM,
-	"FPREM1",	LTYPE0, AFPREM1,
-	"FPTAN",	LTYPE0, AFPTAN,
-	"FRNDINT",	LTYPE0, AFRNDINT,
-	"FSCALE",	LTYPE0, AFSCALE,
-	"FSIN",		LTYPE0, AFSIN,
-	"FSINCOS",	LTYPE0, AFSINCOS,
-	"FSQRT",	LTYPE0, AFSQRT,
-	"FTST",		LTYPE0, AFTST,
-	"FXAM",		LTYPE0, AFXAM,
-	"FXTRACT",	LTYPE0, AFXTRACT,
-	"FYL2X",	LTYPE0, AFYL2X,
-	"FYL2XP1",	LTYPE0, AFYL2XP1,
-	"LFENCE",	LTYPE0, ALFENCE,
-	"MFENCE",	LTYPE0, AMFENCE,
-	"SFENCE",	LTYPE0, ASFENCE,
-	"EMMS",		LTYPE0, AEMMS,
-	"PREFETCHT0",		LTYPE2,	APREFETCHT0,
-	"PREFETCHT1",		LTYPE2,	APREFETCHT1,
-	"PREFETCHT2",		LTYPE2,	APREFETCHT2,
-	"PREFETCHNTA",		LTYPE2,	APREFETCHNTA,
-	"UNDEF",	LTYPE0,	AUNDEF,
-
-	"ADDPD",	LTYPE3,	AADDPD,
-	"ADDPS",	LTYPE3,	AADDPS,
-	"ADDSD",	LTYPE3,	AADDSD,
-	"ADDSS",	LTYPE3,	AADDSS,
-	"AESENC",	LTYPE3,	AAESENC,
-	"ANDNPD",	LTYPE3,	AANDNPD,
-	"ANDNPS",	LTYPE3,	AANDNPS,
-	"ANDPD",	LTYPE3,	AANDPD,
-	"ANDPS",	LTYPE3,	AANDPS,
-	"CMPPD",	LTYPEXC,ACMPPD,
-	"CMPPS",	LTYPEXC,ACMPPS,
-	"CMPSD",	LTYPEXC,ACMPSD,
-	"CMPSS",	LTYPEXC,ACMPSS,
-	"COMISD",	LTYPE3,	ACOMISD,
-	"COMISS",	LTYPE3,	ACOMISS,
-	"CVTPL2PD",	LTYPE3,	ACVTPL2PD,
-	"CVTPL2PS",	LTYPE3,	ACVTPL2PS,
-	"CVTPD2PL",	LTYPE3,	ACVTPD2PL,
-	"CVTPD2PS",	LTYPE3,	ACVTPD2PS,
-	"CVTPS2PL",	LTYPE3,	ACVTPS2PL,
-	"CVTPS2PD",	LTYPE3,	ACVTPS2PD,
-	"CVTSD2SL",	LTYPE3,	ACVTSD2SL,
-	"CVTSD2SS",	LTYPE3,	ACVTSD2SS,
-	"CVTSL2SD",	LTYPE3,	ACVTSL2SD,
-	"CVTSL2SS",	LTYPE3,	ACVTSL2SS,
-	"CVTSS2SD",	LTYPE3,	ACVTSS2SD,
-	"CVTSS2SL",	LTYPE3,	ACVTSS2SL,
-	"CVTTPD2PL",	LTYPE3,	ACVTTPD2PL,
-	"CVTTPS2PL",	LTYPE3,	ACVTTPS2PL,
-	"CVTTSD2SL",	LTYPE3,	ACVTTSD2SL,
-	"CVTTSS2SL",	LTYPE3,	ACVTTSS2SL,
-	"DIVPD",	LTYPE3,	ADIVPD,
-	"DIVPS",	LTYPE3,	ADIVPS,
-	"DIVSD",	LTYPE3,	ADIVSD,
-	"DIVSS",	LTYPE3,	ADIVSS,
-	"MASKMOVOU",	LTYPE3,	AMASKMOVOU,
-	"MASKMOVDQU",	LTYPE3,	AMASKMOVOU,	/* syn */
-	"MAXPD",	LTYPE3,	AMAXPD,
-	"MAXPS",	LTYPE3,	AMAXPS,
-	"MAXSD",	LTYPE3,	AMAXSD,
-	"MAXSS",	LTYPE3,	AMAXSS,
-	"MINPD",	LTYPE3,	AMINPD,
-	"MINPS",	LTYPE3,	AMINPS,
-	"MINSD",	LTYPE3,	AMINSD,
-	"MINSS",	LTYPE3,	AMINSS,
-	"MOVAPD",	LTYPE3,	AMOVAPD,
-	"MOVAPS",	LTYPE3,	AMOVAPS,
-	"MOVO",		LTYPE3,	AMOVO,
-	"MOVOA",	LTYPE3,	AMOVO,	/* syn */
-	"MOVOU",	LTYPE3,	AMOVOU,
-	"MOVHLPS",	LTYPE3,	AMOVHLPS,
-	"MOVHPD",	LTYPE3,	AMOVHPD,
-	"MOVHPS",	LTYPE3,	AMOVHPS,
-	"MOVLHPS",	LTYPE3,	AMOVLHPS,
-	"MOVLPD",	LTYPE3,	AMOVLPD,
-	"MOVLPS",	LTYPE3,	AMOVLPS,
-	"MOVMSKPD",	LTYPE3,	AMOVMSKPD,
-	"MOVMSKPS",	LTYPE3,	AMOVMSKPS,
-	"MOVNTO",	LTYPE3,	AMOVNTO,
-	"MOVNTDQ",	LTYPE3,	AMOVNTO,	/* syn */
-	"MOVNTPD",	LTYPE3,	AMOVNTPD,
-	"MOVNTPS",	LTYPE3,	AMOVNTPS,
-	"MOVSD",	LTYPE3,	AMOVSD,
-	"MOVSS",	LTYPE3,	AMOVSS,
-	"MOVUPD",	LTYPE3,	AMOVUPD,
-	"MOVUPS",	LTYPE3,	AMOVUPS,
-	"MULPD",	LTYPE3,	AMULPD,
-	"MULPS",	LTYPE3,	AMULPS,
-	"MULSD",	LTYPE3,	AMULSD,
-	"MULSS",	LTYPE3,	AMULSS,
-	"ORPD",		LTYPE3,	AORPD,
-	"ORPS",		LTYPE3,	AORPS,
-	"PADDQ",	LTYPE3,	APADDQ,
-	"PAND",		LTYPE3,	APAND,
-	"PCMPEQB",	LTYPE3,	APCMPEQB,
-	"PMAXSW",	LTYPE3,	APMAXSW,
-	"PMAXUB",	LTYPE3,	APMAXUB,
-	"PMINSW",	LTYPE3,	APMINSW,
-	"PMINUB",	LTYPE3,	APMINUB,
-	"PMOVMSKB",	LTYPE3,	APMOVMSKB,
-	"PSADBW",	LTYPE3,	APSADBW,
-	"PSHUFB",	LTYPE3, APSHUFB,
-	"PSUBB",	LTYPE3,	APSUBB,
-	"PSUBL",	LTYPE3,	APSUBL,
-	"PSUBQ",	LTYPE3,	APSUBQ,
-	"PSUBSB",	LTYPE3,	APSUBSB,
-	"PSUBSW",	LTYPE3,	APSUBSW,
-	"PSUBUSB",	LTYPE3,	APSUBUSB,
-	"PSUBUSW",	LTYPE3,	APSUBUSW,
-	"PSUBW",	LTYPE3,	APSUBW,
-	"PUNPCKHQDQ",	LTYPE3,	APUNPCKHQDQ,
-	"PUNPCKLQDQ",	LTYPE3,	APUNPCKLQDQ,
-	"PXOR",		LTYPE3, APXOR,
-	"RCPPS",	LTYPE3,	ARCPPS,
-	"RCPSS",	LTYPE3,	ARCPSS,
-	"RSQRTPS",	LTYPE3,	ARSQRTPS,
-	"RSQRTSS",	LTYPE3,	ARSQRTSS,
-	"SQRTPD",	LTYPE3,	ASQRTPD,
-	"SQRTPS",	LTYPE3,	ASQRTPS,
-	"SQRTSD",	LTYPE3,	ASQRTSD,
-	"SQRTSS",	LTYPE3,	ASQRTSS,
-	"SUBPD",	LTYPE3,	ASUBPD,
-	"SUBPS",	LTYPE3,	ASUBPS,
-	"SUBSD",	LTYPE3,	ASUBSD,
-	"SUBSS",	LTYPE3,	ASUBSS,
-	"UCOMISD",	LTYPE3,	AUCOMISD,
-	"UCOMISS",	LTYPE3,	AUCOMISS,
-	"UNPCKHPD",	LTYPE3,	AUNPCKHPD,
-	"UNPCKHPS",	LTYPE3,	AUNPCKHPS,
-	"UNPCKLPD",	LTYPE3,	AUNPCKLPD,
-	"UNPCKLPS",	LTYPE3,	AUNPCKLPS,
-	"XORPD",	LTYPE3,	AXORPD,
-	"XORPS",	LTYPE3,	AXORPS,
-	"USEFIELD",	LTYPEN, AUSEFIELD,
-	"PCDATA",	LTYPEPC,	APCDATA,
-	"FUNCDATA",	LTYPEF,	AFUNCDATA,
-	0
-};
-
-void
-cinit(void)
-{
-	Sym *s;
-	int i;
-
-	nullgen.type = D_NONE;
-	nullgen.index = D_NONE;
-
-	nerrors = 0;
-	iostack = I;
-	iofree = I;
-	peekc = IGN;
-	nhunk = 0;
-	for(i=0; i<NHASH; i++)
-		hash[i] = S;
-	for(i=0; itab[i].name; i++) {
-		s = slookup(itab[i].name);
-		if(s->type != LNAME)
-			yyerror("double initialization %s", itab[i].name);
-		s->type = itab[i].type;
-		s->value = itab[i].value;
-	}
-}
-
-void
-checkscale(int scale)
-{
-
-	switch(scale) {
-	case 1:
-	case 2:
-	case 4:
-	case 8:
-		return;
-	}
-	yyerror("scale must be 1248: %d", scale);
-}
-
-void
-syminit(Sym *s)
-{
-
-	s->type = LNAME;
-	s->value = 0;
-}
-
-void
-cclean(void)
-{
-	Addr2 g2;
-
-	g2.from = nullgen;
-	g2.to = nullgen;
-	outcode(AEND, &g2);
-}
-
-static Prog *lastpc;
-
-void
-outcode(int a, Addr2 *g2)
-{
-	Prog *p;
-	Plist *pl;
-	
-	if(pass == 1)
-		goto out;
-
-	p = malloc(sizeof *p);
-	memset(p, 0, sizeof *p);
-	p->as = a;
-	p->lineno = stmtline;
-	p->from = g2->from;
-	p->to = g2->to;
-	p->pc = pc;
-
-	if(lastpc == nil) {
-		pl = linknewplist(ctxt);
-		pl->firstpc = p;
-	} else
-		lastpc->link = p;
-	lastpc = p;	
-
-out:
-	if(a != AGLOBL && a != ADATA)
-		pc++;
-}
-
-#include "../cc/lexbody"
-#include "../cc/macbody"
diff --git a/src/cmd/8a/y.tab.c b/src/cmd/8a/y.tab.c
deleted file mode 100644
index 85279c2..0000000
--- a/src/cmd/8a/y.tab.c
+++ /dev/null
@@ -1,2779 +0,0 @@
-/* A Bison parser, made by GNU Bison 2.3.  */
-
-/* Skeleton implementation for Bison's Yacc-like parsers in C
-
-   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
-   Free Software Foundation, Inc.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
-   any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301, USA.  */
-
-/* As a special exception, you may create a larger work that contains
-   part or all of the Bison parser skeleton and distribute that work
-   under terms of your choice, so long as that work isn't itself a
-   parser generator using the skeleton or a modified version thereof
-   as a parser skeleton.  Alternatively, if you modify or redistribute
-   the parser skeleton itself, you may (at your option) remove this
-   special exception, which will cause the skeleton and the resulting
-   Bison output files to be licensed under the GNU General Public
-   License without this special exception.
-
-   This special exception was added by the Free Software Foundation in
-   version 2.2 of Bison.  */
-
-/* C LALR(1) parser skeleton written by Richard Stallman, by
-   simplifying the original so-called "semantic" parser.  */
-
-/* All symbols defined below should begin with yy or YY, to avoid
-   infringing on user name space.  This should be done even for local
-   variables, as they might otherwise be expanded by user macros.
-   There are some unavoidable exceptions within include files to
-   define necessary library symbols; they are noted "INFRINGES ON
-   USER NAME SPACE" below.  */
-
-/* Identify Bison output.  */
-#define YYBISON 1
-
-/* Bison version.  */
-#define YYBISON_VERSION "2.3"
-
-/* Skeleton name.  */
-#define YYSKELETON_NAME "yacc.c"
-
-/* Pure parsers.  */
-#define YYPURE 0
-
-/* Using locations.  */
-#define YYLSP_NEEDED 0
-
-
-
-/* Tokens.  */
-#ifndef YYTOKENTYPE
-# define YYTOKENTYPE
-   /* Put the tokens into the symbol table, so that GDB and other debuggers
-      know about them.  */
-   enum yytokentype {
-     LTYPE0 = 258,
-     LTYPE1 = 259,
-     LTYPE2 = 260,
-     LTYPE3 = 261,
-     LTYPE4 = 262,
-     LTYPEC = 263,
-     LTYPED = 264,
-     LTYPEN = 265,
-     LTYPER = 266,
-     LTYPET = 267,
-     LTYPES = 268,
-     LTYPEM = 269,
-     LTYPEI = 270,
-     LTYPEG = 271,
-     LTYPEXC = 272,
-     LTYPEX = 273,
-     LTYPEPC = 274,
-     LTYPEF = 275,
-     LCONST = 276,
-     LFP = 277,
-     LPC = 278,
-     LSB = 279,
-     LBREG = 280,
-     LLREG = 281,
-     LSREG = 282,
-     LFREG = 283,
-     LXREG = 284,
-     LFCONST = 285,
-     LSCONST = 286,
-     LSP = 287,
-     LNAME = 288,
-     LLAB = 289,
-     LVAR = 290
-   };
-#endif
-/* Tokens.  */
-#define LTYPE0 258
-#define LTYPE1 259
-#define LTYPE2 260
-#define LTYPE3 261
-#define LTYPE4 262
-#define LTYPEC 263
-#define LTYPED 264
-#define LTYPEN 265
-#define LTYPER 266
-#define LTYPET 267
-#define LTYPES 268
-#define LTYPEM 269
-#define LTYPEI 270
-#define LTYPEG 271
-#define LTYPEXC 272
-#define LTYPEX 273
-#define LTYPEPC 274
-#define LTYPEF 275
-#define LCONST 276
-#define LFP 277
-#define LPC 278
-#define LSB 279
-#define LBREG 280
-#define LLREG 281
-#define LSREG 282
-#define LFREG 283
-#define LXREG 284
-#define LFCONST 285
-#define LSCONST 286
-#define LSP 287
-#define LNAME 288
-#define LLAB 289
-#define LVAR 290
-
-
-
-
-/* Copy the first part of user declarations.  */
-#line 31 "a.y"
-
-#include <u.h>
-#include <stdio.h>	/* if we don't, bison will, and a.h re-#defines getc */
-#include <libc.h>
-#include "a.h"
-#include "../../runtime/funcdata.h"
-
-
-/* Enabling traces.  */
-#ifndef YYDEBUG
-# define YYDEBUG 0
-#endif
-
-/* Enabling verbose error messages.  */
-#ifdef YYERROR_VERBOSE
-# undef YYERROR_VERBOSE
-# define YYERROR_VERBOSE 1
-#else
-# define YYERROR_VERBOSE 0
-#endif
-
-/* Enabling the token table.  */
-#ifndef YYTOKEN_TABLE
-# define YYTOKEN_TABLE 0
-#endif
-
-#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-typedef union YYSTYPE
-#line 38 "a.y"
-{
-	Sym	*sym;
-	int32	lval;
-	struct {
-		int32 v1;
-		int32 v2;
-	} con2;
-	double	dval;
-	char	sval[8];
-	Addr	addr;
-	Addr2	addr2;
-}
-/* Line 193 of yacc.c.  */
-#line 187 "y.tab.c"
-	YYSTYPE;
-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
-# define YYSTYPE_IS_DECLARED 1
-# define YYSTYPE_IS_TRIVIAL 1
-#endif
-
-
-
-/* Copy the second part of user declarations.  */
-
-
-/* Line 216 of yacc.c.  */
-#line 200 "y.tab.c"
-
-#ifdef short
-# undef short
-#endif
-
-#ifdef YYTYPE_UINT8
-typedef YYTYPE_UINT8 yytype_uint8;
-#else
-typedef unsigned char yytype_uint8;
-#endif
-
-#ifdef YYTYPE_INT8
-typedef YYTYPE_INT8 yytype_int8;
-#elif (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-typedef signed char yytype_int8;
-#else
-typedef short int yytype_int8;
-#endif
-
-#ifdef YYTYPE_UINT16
-typedef YYTYPE_UINT16 yytype_uint16;
-#else
-typedef unsigned short int yytype_uint16;
-#endif
-
-#ifdef YYTYPE_INT16
-typedef YYTYPE_INT16 yytype_int16;
-#else
-typedef short int yytype_int16;
-#endif
-
-#ifndef YYSIZE_T
-# ifdef __SIZE_TYPE__
-#  define YYSIZE_T __SIZE_TYPE__
-# elif defined size_t
-#  define YYSIZE_T size_t
-# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
-#  define YYSIZE_T size_t
-# else
-#  define YYSIZE_T unsigned int
-# endif
-#endif
-
-#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
-
-#ifndef YY_
-# if defined YYENABLE_NLS && YYENABLE_NLS
-#  if ENABLE_NLS
-#   include <libintl.h> /* INFRINGES ON USER NAME SPACE */
-#   define YY_(msgid) dgettext ("bison-runtime", msgid)
-#  endif
-# endif
-# ifndef YY_
-#  define YY_(msgid) msgid
-# endif
-#endif
-
-/* Suppress unused-variable warnings by "using" E.  */
-#if ! defined lint || defined __GNUC__
-# define YYUSE(e) ((void) (e))
-#else
-# define YYUSE(e) /* empty */
-#endif
-
-/* Identity function, used to suppress warnings about constant conditions.  */
-#ifndef lint
-# define YYID(n) (n)
-#else
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static int
-YYID (int i)
-#else
-static int
-YYID (i)
-    int i;
-#endif
-{
-  return i;
-}
-#endif
-
-#if ! defined yyoverflow || YYERROR_VERBOSE
-
-/* The parser invokes alloca or malloc; define the necessary symbols.  */
-
-# ifdef YYSTACK_USE_ALLOCA
-#  if YYSTACK_USE_ALLOCA
-#   ifdef __GNUC__
-#    define YYSTACK_ALLOC __builtin_alloca
-#   elif defined __BUILTIN_VA_ARG_INCR
-#    include <alloca.h> /* INFRINGES ON USER NAME SPACE */
-#   elif defined _AIX
-#    define YYSTACK_ALLOC __alloca
-#   elif defined _MSC_VER
-#    include <malloc.h> /* INFRINGES ON USER NAME SPACE */
-#    define alloca _alloca
-#   else
-#    define YYSTACK_ALLOC alloca
-#    if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-#     include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-#     ifndef _STDLIB_H
-#      define _STDLIB_H 1
-#     endif
-#    endif
-#   endif
-#  endif
-# endif
-
-# ifdef YYSTACK_ALLOC
-   /* Pacify GCC's `empty if-body' warning.  */
-#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
-#  ifndef YYSTACK_ALLOC_MAXIMUM
-    /* The OS might guarantee only one guard page at the bottom of the stack,
-       and a page size can be as small as 4096 bytes.  So we cannot safely
-       invoke alloca (N) if N exceeds 4096.  Use a slightly smaller number
-       to allow for a few compiler-allocated temporary stack slots.  */
-#   define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
-#  endif
-# else
-#  define YYSTACK_ALLOC YYMALLOC
-#  define YYSTACK_FREE YYFREE
-#  ifndef YYSTACK_ALLOC_MAXIMUM
-#   define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
-#  endif
-#  if (defined __cplusplus && ! defined _STDLIB_H \
-       && ! ((defined YYMALLOC || defined malloc) \
-	     && (defined YYFREE || defined free)))
-#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-#   ifndef _STDLIB_H
-#    define _STDLIB_H 1
-#   endif
-#  endif
-#  ifndef YYMALLOC
-#   define YYMALLOC malloc
-#   if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
-#   endif
-#  endif
-#  ifndef YYFREE
-#   define YYFREE free
-#   if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-void free (void *); /* INFRINGES ON USER NAME SPACE */
-#   endif
-#  endif
-# endif
-#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
-
-
-#if (! defined yyoverflow \
-     && (! defined __cplusplus \
-	 || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
-
-/* A type that is properly aligned for any stack member.  */
-union yyalloc
-{
-  yytype_int16 yyss;
-  YYSTYPE yyvs;
-  };
-
-/* The size of the maximum gap between one aligned stack and the next.  */
-# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
-
-/* The size of an array large to enough to hold all stacks, each with
-   N elements.  */
-# define YYSTACK_BYTES(N) \
-     ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
-      + YYSTACK_GAP_MAXIMUM)
-
-/* Copy COUNT objects from FROM to TO.  The source and destination do
-   not overlap.  */
-# ifndef YYCOPY
-#  if defined __GNUC__ && 1 < __GNUC__
-#   define YYCOPY(To, From, Count) \
-      __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
-#  else
-#   define YYCOPY(To, From, Count)		\
-      do					\
-	{					\
-	  YYSIZE_T yyi;				\
-	  for (yyi = 0; yyi < (Count); yyi++)	\
-	    (To)[yyi] = (From)[yyi];		\
-	}					\
-      while (YYID (0))
-#  endif
-# endif
-
-/* Relocate STACK from its old location to the new one.  The
-   local variables YYSIZE and YYSTACKSIZE give the old and new number of
-   elements in the stack, and YYPTR gives the new location of the
-   stack.  Advance YYPTR to a properly aligned location for the next
-   stack.  */
-# define YYSTACK_RELOCATE(Stack)					\
-    do									\
-      {									\
-	YYSIZE_T yynewbytes;						\
-	YYCOPY (&yyptr->Stack, Stack, yysize);				\
-	Stack = &yyptr->Stack;						\
-	yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
-	yyptr += yynewbytes / sizeof (*yyptr);				\
-      }									\
-    while (YYID (0))
-
-#endif
-
-/* YYFINAL -- State number of the termination state.  */
-#define YYFINAL  2
-/* YYLAST -- Last index in YYTABLE.  */
-#define YYLAST   546
-
-/* YYNTOKENS -- Number of terminals.  */
-#define YYNTOKENS  54
-/* YYNNTS -- Number of nonterminals.  */
-#define YYNNTS  41
-/* YYNRULES -- Number of rules.  */
-#define YYNRULES  135
-/* YYNRULES -- Number of states.  */
-#define YYNSTATES  276
-
-/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
-#define YYUNDEFTOK  2
-#define YYMAXUTOK   290
-
-#define YYTRANSLATE(YYX)						\
-  ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
-
-/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX.  */
-static const yytype_uint8 yytranslate[] =
-{
-       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,    52,    12,     5,     2,
-      50,    51,    10,     8,    49,     9,     2,    11,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,    46,    47,
-       6,    48,     7,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     4,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     3,     2,    53,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     1,     2,    13,    14,
-      15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
-      25,    26,    27,    28,    29,    30,    31,    32,    33,    34,
-      35,    36,    37,    38,    39,    40,    41,    42,    43,    44,
-      45
-};
-
-#if YYDEBUG
-/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
-   YYRHS.  */
-static const yytype_uint16 yyprhs[] =
-{
-       0,     0,     3,     4,     5,     9,    10,    15,    16,    21,
-      23,    26,    29,    33,    37,    40,    43,    46,    49,    52,
-      55,    58,    61,    64,    67,    70,    73,    76,    79,    82,
-      85,    88,    91,    92,    94,    98,   102,   105,   107,   110,
-     112,   115,   117,   121,   127,   131,   137,   140,   142,   145,
-     147,   149,   153,   159,   163,   169,   172,   174,   178,   182,
-     188,   194,   200,   204,   208,   210,   212,   214,   216,   219,
-     222,   224,   226,   228,   230,   232,   237,   240,   243,   245,
-     247,   249,   251,   253,   255,   258,   261,   264,   267,   272,
-     278,   282,   285,   287,   290,   294,   299,   301,   303,   305,
-     310,   315,   322,   332,   342,   346,   350,   355,   361,   370,
-     372,   379,   385,   393,   394,   397,   400,   402,   404,   406,
-     408,   410,   413,   416,   419,   423,   425,   429,   433,   437,
-     441,   445,   450,   455,   459,   463
-};
-
-/* YYRHS -- A `-1'-separated list of the rules' RHS.  */
-static const yytype_int8 yyrhs[] =
-{
-      55,     0,    -1,    -1,    -1,    55,    56,    57,    -1,    -1,
-      44,    46,    58,    57,    -1,    -1,    43,    46,    59,    57,
-      -1,    47,    -1,    60,    47,    -1,     1,    47,    -1,    43,
-      48,    94,    -1,    45,    48,    94,    -1,    13,    61,    -1,
-      14,    65,    -1,    15,    64,    -1,    16,    62,    -1,    17,
-      63,    -1,    21,    66,    -1,    19,    67,    -1,    22,    68,
-      -1,    18,    69,    -1,    20,    70,    -1,    23,    71,    -1,
-      24,    72,    -1,    25,    73,    -1,    26,    74,    -1,    27,
-      75,    -1,    28,    76,    -1,    29,    77,    -1,    30,    78,
-      -1,    -1,    49,    -1,    81,    49,    79,    -1,    79,    49,
-      81,    -1,    81,    49,    -1,    81,    -1,    49,    79,    -1,
-      79,    -1,    49,    82,    -1,    82,    -1,    84,    49,    82,
-      -1,    90,    11,    93,    49,    84,    -1,    87,    49,    85,
-      -1,    87,    49,    93,    49,    85,    -1,    49,    80,    -1,
-      80,    -1,    10,    90,    -1,    61,    -1,    65,    -1,    81,
-      49,    79,    -1,    81,    49,    79,    46,    36,    -1,    81,
-      49,    79,    -1,    81,    49,    79,    46,    37,    -1,    81,
-      49,    -1,    81,    -1,    81,    49,    79,    -1,    87,    49,
-      84,    -1,    87,    49,    93,    49,    84,    -1,    83,    49,
-      79,    49,    93,    -1,    84,    49,    79,    49,    83,    -1,
-      81,    49,    81,    -1,    81,    49,    81,    -1,    83,    -1,
-      87,    -1,    82,    -1,    89,    -1,    10,    83,    -1,    10,
-      88,    -1,    83,    -1,    88,    -1,    84,    -1,    79,    -1,
-      84,    -1,    93,    50,    33,    51,    -1,    43,    91,    -1,
-      44,    91,    -1,    35,    -1,    38,    -1,    36,    -1,    39,
-      -1,    42,    -1,    37,    -1,    52,    93,    -1,    52,    90,
-      -1,    52,    41,    -1,    52,    40,    -1,    52,    50,    40,
-      51,    -1,    52,    50,     9,    40,    51,    -1,    52,     9,
-      40,    -1,    52,    86,    -1,    31,    -1,     9,    31,    -1,
-      31,     9,    31,    -1,     9,    31,     9,    31,    -1,    88,
-      -1,    89,    -1,    93,    -1,    93,    50,    36,    51,    -1,
-      93,    50,    42,    51,    -1,    93,    50,    36,    10,    93,
-      51,    -1,    93,    50,    36,    51,    50,    36,    10,    93,
-      51,    -1,    93,    50,    36,    51,    50,    37,    10,    93,
-      51,    -1,    50,    36,    51,    -1,    50,    42,    51,    -1,
-      93,    50,    37,    51,    -1,    50,    36,    10,    93,    51,
-      -1,    50,    36,    51,    50,    36,    10,    93,    51,    -1,
-      90,    -1,    90,    50,    36,    10,    93,    51,    -1,    43,
-      91,    50,    92,    51,    -1,    43,     6,     7,    91,    50,
-      34,    51,    -1,    -1,     8,    93,    -1,     9,    93,    -1,
-      34,    -1,    42,    -1,    32,    -1,    31,    -1,    45,    -1,
-       9,    93,    -1,     8,    93,    -1,    53,    93,    -1,    50,
-      94,    51,    -1,    93,    -1,    94,     8,    94,    -1,    94,
-       9,    94,    -1,    94,    10,    94,    -1,    94,    11,    94,
-      -1,    94,    12,    94,    -1,    94,     6,     6,    94,    -1,
-      94,     7,     7,    94,    -1,    94,     5,    94,    -1,    94,
-       4,    94,    -1,    94,     3,    94,    -1
-};
-
-/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
-static const yytype_uint16 yyrline[] =
-{
-       0,    69,    69,    71,    70,    78,    77,    85,    84,    90,
-      91,    92,    95,   100,   106,   107,   108,   109,   110,   111,
-     112,   113,   114,   115,   116,   117,   118,   119,   120,   121,
-     122,   123,   126,   130,   137,   144,   151,   156,   163,   168,
-     175,   180,   185,   192,   200,   205,   213,   218,   223,   232,
-     233,   236,   241,   251,   256,   266,   271,   276,   283,   288,
-     296,   304,   314,   323,   334,   335,   338,   339,   340,   344,
-     348,   349,   350,   353,   354,   357,   363,   371,   379,   384,
-     389,   394,   399,   404,   411,   417,   428,   434,   440,   446,
-     452,   460,   469,   474,   479,   484,   491,   492,   495,   501,
-     507,   513,   522,   531,   540,   545,   550,   556,   564,   574,
-     578,   587,   594,   603,   606,   610,   616,   617,   621,   624,
-     625,   629,   633,   637,   641,   647,   648,   652,   656,   660,
-     664,   668,   672,   676,   680,   684
-};
-#endif
-
-#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
-/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
-   First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
-static const char *const yytname[] =
-{
-  "$end", "error", "$undefined", "'|'", "'^'", "'&'", "'<'", "'>'", "'+'",
-  "'-'", "'*'", "'/'", "'%'", "LTYPE0", "LTYPE1", "LTYPE2", "LTYPE3",
-  "LTYPE4", "LTYPEC", "LTYPED", "LTYPEN", "LTYPER", "LTYPET", "LTYPES",
-  "LTYPEM", "LTYPEI", "LTYPEG", "LTYPEXC", "LTYPEX", "LTYPEPC", "LTYPEF",
-  "LCONST", "LFP", "LPC", "LSB", "LBREG", "LLREG", "LSREG", "LFREG",
-  "LXREG", "LFCONST", "LSCONST", "LSP", "LNAME", "LLAB", "LVAR", "':'",
-  "';'", "'='", "','", "'('", "')'", "'$'", "'~'", "$accept", "prog", "@1",
-  "line", "@2", "@3", "inst", "nonnon", "rimrem", "remrim", "rimnon",
-  "nonrem", "nonrel", "spec1", "spec2", "spec3", "spec4", "spec5", "spec6",
-  "spec7", "spec8", "spec9", "spec10", "spec11", "spec12", "rem", "rom",
-  "rim", "rel", "reg", "imm", "imm2", "con2", "mem", "omem", "nmem", "nam",
-  "offset", "pointer", "con", "expr", 0
-};
-#endif
-
-# ifdef YYPRINT
-/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
-   token YYLEX-NUM.  */
-static const yytype_uint16 yytoknum[] =
-{
-       0,   256,   257,   124,    94,    38,    60,    62,    43,    45,
-      42,    47,    37,   258,   259,   260,   261,   262,   263,   264,
-     265,   266,   267,   268,   269,   270,   271,   272,   273,   274,
-     275,   276,   277,   278,   279,   280,   281,   282,   283,   284,
-     285,   286,   287,   288,   289,   290,    58,    59,    61,    44,
-      40,    41,    36,   126
-};
-# endif
-
-/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
-static const yytype_uint8 yyr1[] =
-{
-       0,    54,    55,    56,    55,    58,    57,    59,    57,    57,
-      57,    57,    60,    60,    60,    60,    60,    60,    60,    60,
-      60,    60,    60,    60,    60,    60,    60,    60,    60,    60,
-      60,    60,    61,    61,    62,    63,    64,    64,    65,    65,
-      66,    66,    66,    67,    68,    68,    69,    69,    69,    70,
-      70,    71,    71,    72,    72,    73,    73,    73,    74,    74,
-      75,    76,    77,    78,    79,    79,    80,    80,    80,    80,
-      80,    80,    80,    81,    81,    82,    82,    82,    83,    83,
-      83,    83,    83,    83,    84,    84,    84,    84,    84,    84,
-      84,    85,    86,    86,    86,    86,    87,    87,    88,    88,
-      88,    88,    88,    88,    88,    88,    88,    88,    88,    89,
-      89,    90,    90,    91,    91,    91,    92,    92,    92,    93,
-      93,    93,    93,    93,    93,    94,    94,    94,    94,    94,
-      94,    94,    94,    94,    94,    94
-};
-
-/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
-static const yytype_uint8 yyr2[] =
-{
-       0,     2,     0,     0,     3,     0,     4,     0,     4,     1,
-       2,     2,     3,     3,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     0,     1,     3,     3,     2,     1,     2,     1,
-       2,     1,     3,     5,     3,     5,     2,     1,     2,     1,
-       1,     3,     5,     3,     5,     2,     1,     3,     3,     5,
-       5,     5,     3,     3,     1,     1,     1,     1,     2,     2,
-       1,     1,     1,     1,     1,     4,     2,     2,     1,     1,
-       1,     1,     1,     1,     2,     2,     2,     2,     4,     5,
-       3,     2,     1,     2,     3,     4,     1,     1,     1,     4,
-       4,     6,     9,     9,     3,     3,     4,     5,     8,     1,
-       6,     5,     7,     0,     2,     2,     1,     1,     1,     1,
-       1,     2,     2,     2,     3,     1,     3,     3,     3,     3,
-       3,     4,     4,     3,     3,     3
-};
-
-/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
-   STATE-NUM when YYTABLE doesn't specify something else to do.  Zero
-   means the default is an error.  */
-static const yytype_uint8 yydefact[] =
-{
-       2,     3,     1,     0,     0,    32,     0,     0,     0,     0,
-       0,     0,    32,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     9,     4,     0,    11,
-      33,    14,     0,     0,   119,    78,    80,    83,    79,    81,
-      82,   113,   120,     0,     0,     0,    15,    39,    64,    65,
-      96,    97,   109,    98,     0,    16,    73,    37,    74,    17,
-       0,    18,     0,     0,   113,   113,     0,    22,    47,    66,
-      70,    72,    71,    67,    98,    20,     0,    33,    49,    50,
-      23,   113,     0,     0,    19,    41,     0,     0,    21,     0,
-      24,     0,    25,     0,    26,    56,    27,     0,    28,     0,
-      29,     0,    30,     0,    31,     0,     7,     0,     5,     0,
-      10,   122,   121,     0,     0,     0,     0,    38,     0,     0,
-     125,     0,   123,     0,     0,     0,    87,    86,     0,    85,
-      84,    36,     0,     0,    68,    69,    48,    76,    77,     0,
-      46,     0,     0,    76,    40,     0,     0,     0,     0,     0,
-      55,     0,     0,     0,     0,     0,     0,    12,     0,    13,
-     113,   114,   115,     0,     0,   104,   105,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,   124,     0,     0,
-       0,     0,    90,     0,     0,    34,    35,     0,     0,    42,
-       0,    44,     0,    51,    53,    57,    58,     0,     0,     0,
-      62,    63,     8,     6,     0,   118,   116,   117,     0,     0,
-       0,   135,   134,   133,     0,     0,   126,   127,   128,   129,
-     130,     0,     0,    99,   106,   100,     0,    88,    75,     0,
-       0,    92,    91,     0,     0,     0,     0,     0,     0,     0,
-     111,   107,     0,   131,   132,     0,     0,     0,    89,    43,
-      93,     0,    45,    52,    54,    59,    60,    61,     0,     0,
-     110,   101,     0,     0,     0,    94,   112,     0,     0,     0,
-      95,   108,     0,     0,   102,   103
-};
-
-/* YYDEFGOTO[NTERM-NUM].  */
-static const yytype_int16 yydefgoto[] =
-{
-      -1,     1,     3,    27,   158,   156,    28,    31,    59,    61,
-      55,    46,    84,    75,    88,    67,    80,    90,    92,    94,
-      96,    98,   100,   102,   104,    56,    68,    57,    69,    48,
-      58,   191,   232,    49,    50,    51,    52,   116,   208,    53,
-     121
-};
-
-/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
-   STATE-NUM.  */
-#define YYPACT_NINF -104
-static const yytype_int16 yypact[] =
-{
-    -104,     4,  -104,   173,   -26,   -25,   277,   297,   297,   349,
-     225,   -14,   329,   396,    18,   297,   297,   297,    18,   171,
-     -20,   297,   297,     2,    -4,    26,  -104,  -104,    43,  -104,
-    -104,  -104,   478,   478,  -104,  -104,  -104,  -104,  -104,  -104,
-    -104,   111,  -104,   349,   402,   478,  -104,  -104,  -104,  -104,
-    -104,  -104,   -12,    -5,    83,  -104,  -104,    44,  -104,  -104,
-      46,  -104,    49,   349,   111,   113,   245,  -104,  -104,  -104,
-    -104,  -104,  -104,  -104,    50,  -104,   100,   349,  -104,  -104,
-    -104,   113,   420,   478,  -104,  -104,    64,    66,  -104,    78,
-    -104,    80,  -104,    85,  -104,    89,  -104,    93,  -104,    98,
-    -104,   101,  -104,   112,  -104,   121,  -104,   478,  -104,   478,
-    -104,  -104,  -104,   153,   478,   478,   135,  -104,     8,   163,
-    -104,    74,  -104,   179,    52,   427,  -104,  -104,   445,  -104,
-    -104,  -104,   349,   297,  -104,  -104,  -104,   135,  -104,   381,
-    -104,    33,   478,  -104,  -104,   420,   186,   451,   349,   349,
-     349,   460,   349,   349,   297,   297,   173,   172,   173,   172,
-     113,  -104,  -104,     5,   478,   180,  -104,   478,   478,   478,
-     226,   224,   478,   478,   478,   478,   478,  -104,   235,    36,
-     195,   196,  -104,   466,   197,  -104,  -104,   199,   202,  -104,
-      21,  -104,   203,   211,   219,  -104,  -104,   217,   222,   223,
-    -104,  -104,  -104,  -104,   229,  -104,  -104,  -104,   240,   241,
-     237,   232,   527,   534,   478,   478,   134,   134,  -104,  -104,
-    -104,   478,   478,   243,  -104,  -104,   248,  -104,  -104,   -20,
-     263,   287,  -104,   249,   264,   265,   -20,   478,   171,   269,
-    -104,  -104,   294,   214,   214,   256,   258,   119,  -104,  -104,
-     301,   280,  -104,  -104,  -104,  -104,  -104,  -104,   266,   478,
-    -104,  -104,   308,   311,   292,  -104,  -104,   273,   478,   478,
-    -104,  -104,   274,   278,  -104,  -104
-};
-
-/* YYPGOTO[NTERM-NUM].  */
-static const yytype_int16 yypgoto[] =
-{
-    -104,  -104,  -104,  -103,  -104,  -104,  -104,   319,  -104,  -104,
-    -104,   331,  -104,  -104,  -104,  -104,  -104,  -104,  -104,  -104,
-    -104,  -104,  -104,  -104,  -104,    19,   275,    -2,    -6,    -9,
-      -8,   115,  -104,    22,     1,    -1,    -3,   -48,  -104,   -10,
-     -66
-};
-
-/* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
-   positive, shift that token.  If negative, reduce the rule which
-   number is the opposite.  If zero, do what YYDEFACT says.
-   If YYTABLE_NINF, syntax error.  */
-#define YYTABLE_NINF -1
-static const yytype_uint16 yytable[] =
-{
-      74,    70,    71,    87,     2,    86,    60,    85,    76,    73,
-      99,    72,   101,    91,    93,    95,   137,   138,   164,   103,
-     105,    29,   111,   112,    30,    47,    32,    33,    62,    41,
-     230,    47,    54,   143,   120,   122,    89,   205,   123,   206,
-      97,   157,   108,   159,   130,   124,   222,   207,   106,    34,
-     107,   129,   231,   202,   134,   203,    74,    70,    71,   165,
-     136,    41,   117,    42,   135,    73,   187,    72,    44,   179,
-     180,    45,    87,   120,   109,   181,   144,   167,   168,   169,
-     170,   171,   172,   173,   174,   175,   176,   223,   179,   180,
-     110,    32,   125,   131,   181,   132,   117,   120,   133,   120,
-     141,   211,   212,   213,   161,   162,   216,   217,   218,   219,
-     220,   142,   204,   145,    34,   112,   146,   113,   120,   114,
-     115,   114,   115,   126,   127,   177,    41,   147,    42,   148,
-     134,   186,   188,   128,   149,    87,    45,   192,   150,   189,
-     135,   197,   151,   196,   174,   175,   176,   152,   243,   244,
-     153,   185,   200,   201,   209,   262,   263,   120,   120,   120,
-     160,   154,   120,   120,   120,   120,   120,   193,   194,   195,
-     155,   198,   199,   112,     4,   167,   168,   169,   170,   171,
-     172,   173,   174,   175,   176,   163,     5,     6,     7,     8,
-       9,    10,    11,    12,    13,    14,    15,    16,    17,    18,
-      19,    20,    21,    22,   120,   120,    35,    36,    37,    38,
-      39,   245,   246,    40,   166,   178,    23,    24,    25,   187,
-      26,   249,   172,   173,   174,   175,   176,   256,   255,   257,
-     210,   215,   214,    32,    33,    63,   168,   169,   170,   171,
-     172,   173,   174,   175,   176,   221,   224,   225,   227,   267,
-     228,   229,   233,    32,    33,   139,    34,   234,   272,   273,
-      35,    36,    37,    38,    39,   235,   236,    40,    64,    65,
-      42,   237,   238,   242,    66,    44,    34,    54,    45,   239,
-      35,    36,    37,    38,    39,    32,    33,    40,    64,    65,
-      42,   240,   241,   247,   250,    44,   251,    54,    45,   248,
-     253,   190,   254,   258,   259,    32,    33,   260,    34,   261,
-     264,   265,    35,    36,    37,    38,    39,   266,   268,    40,
-      41,   269,    42,   270,   271,   274,    43,    44,    34,   275,
-      45,    78,    35,    36,    37,    38,    39,    32,    33,    40,
-      41,   140,    42,    79,     0,     0,     0,    44,   252,    54,
-      45,     0,     0,     0,     0,     0,     0,    32,    33,     0,
-      34,     0,     0,     0,    35,    36,    37,    38,    39,     0,
-       0,    40,    41,     0,    42,     0,     0,     0,    77,    44,
-      34,     0,    45,     0,    35,    36,    37,    38,    39,    32,
-      33,    40,    41,     0,    42,     0,     0,     0,     0,    44,
-       0,     0,    45,     0,    32,    33,     0,     0,     0,     0,
-      32,    33,    34,     0,     0,     0,    35,    36,    37,    38,
-      39,     0,     0,    40,     0,     0,    42,    34,    32,    33,
-       0,    44,     0,    34,    45,    32,    33,     0,   118,    81,
-      65,    42,     0,     0,   119,    82,    83,    42,    54,    45,
-       0,    34,    83,    32,   183,    45,     0,     0,    34,    32,
-      33,     0,     0,    81,    65,    42,     0,   182,    32,    33,
-      83,     0,    42,    45,    32,    33,    34,    83,     0,     0,
-      45,     0,    34,     0,     0,   184,    32,    33,     0,     0,
-      42,    34,     0,     0,     0,    83,    42,    34,    45,     0,
-       0,    83,     0,   190,    45,    42,   226,     0,     0,    34,
-      83,    42,    54,    45,     0,     0,    83,     0,     0,    45,
-       0,     0,     0,    42,     0,     0,     0,     0,    83,     0,
-       0,    45,   169,   170,   171,   172,   173,   174,   175,   176,
-     170,   171,   172,   173,   174,   175,   176
-};
-
-static const yytype_int16 yycheck[] =
-{
-      10,    10,    10,    13,     0,    13,     8,    13,    11,    10,
-      19,    10,    20,    15,    16,    17,    64,    65,    10,    21,
-      22,    47,    32,    33,    49,     6,     8,     9,     9,    43,
-       9,    12,    52,    81,    44,    45,    14,    32,    50,    34,
-      18,   107,    46,   109,    54,    50,    10,    42,    46,    31,
-      48,    54,    31,   156,    63,   158,    66,    66,    66,    51,
-      63,    43,    43,    45,    63,    66,    33,    66,    50,    36,
-      37,    53,    82,    83,    48,    42,    82,     3,     4,     5,
-       6,     7,     8,     9,    10,    11,    12,    51,    36,    37,
-      47,     8,     9,    49,    42,    49,    77,   107,    49,   109,
-      50,   167,   168,   169,   114,   115,   172,   173,   174,   175,
-     176,    11,   160,    49,    31,   125,    50,     6,   128,     8,
-       9,     8,     9,    40,    41,    51,    43,    49,    45,    49,
-     139,   133,   142,    50,    49,   145,    53,   147,    49,   145,
-     139,   151,    49,   151,    10,    11,    12,    49,   214,   215,
-      49,   132,   154,   155,   164,    36,    37,   167,   168,   169,
-       7,    49,   172,   173,   174,   175,   176,   148,   149,   150,
-      49,   152,   153,   183,     1,     3,     4,     5,     6,     7,
-       8,     9,    10,    11,    12,    50,    13,    14,    15,    16,
-      17,    18,    19,    20,    21,    22,    23,    24,    25,    26,
-      27,    28,    29,    30,   214,   215,    35,    36,    37,    38,
-      39,   221,   222,    42,    51,    36,    43,    44,    45,    33,
-      47,   229,     8,     9,    10,    11,    12,   237,   236,   238,
-      50,     7,     6,     8,     9,    10,     4,     5,     6,     7,
-       8,     9,    10,    11,    12,    10,    51,    51,    51,   259,
-      51,    49,    49,     8,     9,    10,    31,    46,   268,   269,
-      35,    36,    37,    38,    39,    46,    49,    42,    43,    44,
-      45,    49,    49,    36,    49,    50,    31,    52,    53,    50,
-      35,    36,    37,    38,    39,     8,     9,    42,    43,    44,
-      45,    51,    51,    50,    31,    50,     9,    52,    53,    51,
-      36,    52,    37,    34,    10,     8,     9,    51,    31,    51,
-       9,    31,    35,    36,    37,    38,    39,    51,    10,    42,
-      43,    10,    45,    31,    51,    51,    49,    50,    31,    51,
-      53,    12,    35,    36,    37,    38,    39,     8,     9,    42,
-      43,    66,    45,    12,    -1,    -1,    -1,    50,   233,    52,
-      53,    -1,    -1,    -1,    -1,    -1,    -1,     8,     9,    -1,
-      31,    -1,    -1,    -1,    35,    36,    37,    38,    39,    -1,
-      -1,    42,    43,    -1,    45,    -1,    -1,    -1,    49,    50,
-      31,    -1,    53,    -1,    35,    36,    37,    38,    39,     8,
-       9,    42,    43,    -1,    45,    -1,    -1,    -1,    -1,    50,
-      -1,    -1,    53,    -1,     8,     9,    -1,    -1,    -1,    -1,
-       8,     9,    31,    -1,    -1,    -1,    35,    36,    37,    38,
-      39,    -1,    -1,    42,    -1,    -1,    45,    31,     8,     9,
-      -1,    50,    -1,    31,    53,     8,     9,    -1,    36,    43,
-      44,    45,    -1,    -1,    42,    49,    50,    45,    52,    53,
-      -1,    31,    50,     8,     9,    53,    -1,    -1,    31,     8,
-       9,    -1,    -1,    43,    44,    45,    -1,    40,     8,     9,
-      50,    -1,    45,    53,     8,     9,    31,    50,    -1,    -1,
-      53,    -1,    31,    -1,    -1,    40,     8,     9,    -1,    -1,
-      45,    31,    -1,    -1,    -1,    50,    45,    31,    53,    -1,
-      -1,    50,    -1,    52,    53,    45,    40,    -1,    -1,    31,
-      50,    45,    52,    53,    -1,    -1,    50,    -1,    -1,    53,
-      -1,    -1,    -1,    45,    -1,    -1,    -1,    -1,    50,    -1,
-      -1,    53,     5,     6,     7,     8,     9,    10,    11,    12,
-       6,     7,     8,     9,    10,    11,    12
-};
-
-/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
-   symbol of state STATE-NUM.  */
-static const yytype_uint8 yystos[] =
-{
-       0,    55,     0,    56,     1,    13,    14,    15,    16,    17,
-      18,    19,    20,    21,    22,    23,    24,    25,    26,    27,
-      28,    29,    30,    43,    44,    45,    47,    57,    60,    47,
-      49,    61,     8,     9,    31,    35,    36,    37,    38,    39,
-      42,    43,    45,    49,    50,    53,    65,    79,    83,    87,
-      88,    89,    90,    93,    52,    64,    79,    81,    84,    62,
-      81,    63,    79,    10,    43,    44,    49,    69,    80,    82,
-      83,    84,    88,    89,    93,    67,    90,    49,    61,    65,
-      70,    43,    49,    50,    66,    82,    84,    93,    68,    87,
-      71,    81,    72,    81,    73,    81,    74,    87,    75,    83,
-      76,    84,    77,    81,    78,    81,    46,    48,    46,    48,
-      47,    93,    93,     6,     8,     9,    91,    79,    36,    42,
-      93,    94,    93,    50,    50,     9,    40,    41,    50,    90,
-      93,    49,    49,    49,    83,    88,    90,    91,    91,    10,
-      80,    50,    11,    91,    82,    49,    50,    49,    49,    49,
-      49,    49,    49,    49,    49,    49,    59,    94,    58,    94,
-       7,    93,    93,    50,    10,    51,    51,     3,     4,     5,
-       6,     7,     8,     9,    10,    11,    12,    51,    36,    36,
-      37,    42,    40,     9,    40,    79,    81,    33,    93,    82,
-      52,    85,    93,    79,    79,    79,    84,    93,    79,    79,
-      81,    81,    57,    57,    91,    32,    34,    42,    92,    93,
-      50,    94,    94,    94,     6,     7,    94,    94,    94,    94,
-      94,    10,    10,    51,    51,    51,    40,    51,    51,    49,
-       9,    31,    86,    49,    46,    46,    49,    49,    49,    50,
-      51,    51,    36,    94,    94,    93,    93,    50,    51,    84,
-      31,     9,    85,    36,    37,    84,    93,    83,    34,    10,
-      51,    51,    36,    37,     9,    31,    51,    93,    10,    10,
-      31,    51,    93,    93,    51,    51
-};
-
-#define yyerrok		(yyerrstatus = 0)
-#define yyclearin	(yychar = YYEMPTY)
-#define YYEMPTY		(-2)
-#define YYEOF		0
-
-#define YYACCEPT	goto yyacceptlab
-#define YYABORT		goto yyabortlab
-#define YYERROR		goto yyerrorlab
-
-
-/* Like YYERROR except do call yyerror.  This remains here temporarily
-   to ease the transition to the new meaning of YYERROR, for GCC.
-   Once GCC version 2 has supplanted version 1, this can go.  */
-
-#define YYFAIL		goto yyerrlab
-
-#define YYRECOVERING()  (!!yyerrstatus)
-
-#define YYBACKUP(Token, Value)					\
-do								\
-  if (yychar == YYEMPTY && yylen == 1)				\
-    {								\
-      yychar = (Token);						\
-      yylval = (Value);						\
-      yytoken = YYTRANSLATE (yychar);				\
-      YYPOPSTACK (1);						\
-      goto yybackup;						\
-    }								\
-  else								\
-    {								\
-      yyerror (YY_("syntax error: cannot back up")); \
-      YYERROR;							\
-    }								\
-while (YYID (0))
-
-
-#define YYTERROR	1
-#define YYERRCODE	256
-
-
-/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
-   If N is 0, then set CURRENT to the empty location which ends
-   the previous symbol: RHS[0] (always defined).  */
-
-#define YYRHSLOC(Rhs, K) ((Rhs)[K])
-#ifndef YYLLOC_DEFAULT
-# define YYLLOC_DEFAULT(Current, Rhs, N)				\
-    do									\
-      if (YYID (N))                                                    \
-	{								\
-	  (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;	\
-	  (Current).first_column = YYRHSLOC (Rhs, 1).first_column;	\
-	  (Current).last_line    = YYRHSLOC (Rhs, N).last_line;		\
-	  (Current).last_column  = YYRHSLOC (Rhs, N).last_column;	\
-	}								\
-      else								\
-	{								\
-	  (Current).first_line   = (Current).last_line   =		\
-	    YYRHSLOC (Rhs, 0).last_line;				\
-	  (Current).first_column = (Current).last_column =		\
-	    YYRHSLOC (Rhs, 0).last_column;				\
-	}								\
-    while (YYID (0))
-#endif
-
-
-/* YY_LOCATION_PRINT -- Print the location on the stream.
-   This macro was not mandated originally: define only if we know
-   we won't break user code: when these are the locations we know.  */
-
-#ifndef YY_LOCATION_PRINT
-# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
-#  define YY_LOCATION_PRINT(File, Loc)			\
-     fprintf (File, "%d.%d-%d.%d",			\
-	      (Loc).first_line, (Loc).first_column,	\
-	      (Loc).last_line,  (Loc).last_column)
-# else
-#  define YY_LOCATION_PRINT(File, Loc) ((void) 0)
-# endif
-#endif
-
-
-/* YYLEX -- calling `yylex' with the right arguments.  */
-
-#ifdef YYLEX_PARAM
-# define YYLEX yylex (YYLEX_PARAM)
-#else
-# define YYLEX yylex ()
-#endif
-
-/* Enable debugging if requested.  */
-#if YYDEBUG
-
-# ifndef YYFPRINTF
-#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
-#  define YYFPRINTF fprintf
-# endif
-
-# define YYDPRINTF(Args)			\
-do {						\
-  if (yydebug)					\
-    YYFPRINTF Args;				\
-} while (YYID (0))
-
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location)			  \
-do {									  \
-  if (yydebug)								  \
-    {									  \
-      YYFPRINTF (stderr, "%s ", Title);					  \
-      yy_symbol_print (stderr,						  \
-		  Type, Value); \
-      YYFPRINTF (stderr, "\n");						  \
-    }									  \
-} while (YYID (0))
-
-
-/*--------------------------------.
-| Print this symbol on YYOUTPUT.  |
-`--------------------------------*/
-
-/*ARGSUSED*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static void
-yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
-#else
-static void
-yy_symbol_value_print (yyoutput, yytype, yyvaluep)
-    FILE *yyoutput;
-    int yytype;
-    YYSTYPE const * const yyvaluep;
-#endif
-{
-  if (!yyvaluep)
-    return;
-# ifdef YYPRINT
-  if (yytype < YYNTOKENS)
-    YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
-# else
-  YYUSE (yyoutput);
-# endif
-  switch (yytype)
-    {
-      default:
-	break;
-    }
-}
-
-
-/*--------------------------------.
-| Print this symbol on YYOUTPUT.  |
-`--------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static void
-yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
-#else
-static void
-yy_symbol_print (yyoutput, yytype, yyvaluep)
-    FILE *yyoutput;
-    int yytype;
-    YYSTYPE const * const yyvaluep;
-#endif
-{
-  if (yytype < YYNTOKENS)
-    YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
-  else
-    YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
-
-  yy_symbol_value_print (yyoutput, yytype, yyvaluep);
-  YYFPRINTF (yyoutput, ")");
-}
-
-/*------------------------------------------------------------------.
-| yy_stack_print -- Print the state stack from its BOTTOM up to its |
-| TOP (included).                                                   |
-`------------------------------------------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static void
-yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
-#else
-static void
-yy_stack_print (bottom, top)
-    yytype_int16 *bottom;
-    yytype_int16 *top;
-#endif
-{
-  YYFPRINTF (stderr, "Stack now");
-  for (; bottom <= top; ++bottom)
-    YYFPRINTF (stderr, " %d", *bottom);
-  YYFPRINTF (stderr, "\n");
-}
-
-# define YY_STACK_PRINT(Bottom, Top)				\
-do {								\
-  if (yydebug)							\
-    yy_stack_print ((Bottom), (Top));				\
-} while (YYID (0))
-
-
-/*------------------------------------------------.
-| Report that the YYRULE is going to be reduced.  |
-`------------------------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static void
-yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
-#else
-static void
-yy_reduce_print (yyvsp, yyrule)
-    YYSTYPE *yyvsp;
-    int yyrule;
-#endif
-{
-  int yynrhs = yyr2[yyrule];
-  int yyi;
-  unsigned long int yylno = yyrline[yyrule];
-  YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
-	     yyrule - 1, yylno);
-  /* The symbols being reduced.  */
-  for (yyi = 0; yyi < yynrhs; yyi++)
-    {
-      fprintf (stderr, "   $%d = ", yyi + 1);
-      yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
-		       &(yyvsp[(yyi + 1) - (yynrhs)])
-		       		       );
-      fprintf (stderr, "\n");
-    }
-}
-
-# define YY_REDUCE_PRINT(Rule)		\
-do {					\
-  if (yydebug)				\
-    yy_reduce_print (yyvsp, Rule); \
-} while (YYID (0))
-
-/* Nonzero means print parse trace.  It is left uninitialized so that
-   multiple parsers can coexist.  */
-int yydebug;
-#else /* !YYDEBUG */
-# define YYDPRINTF(Args)
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
-# define YY_STACK_PRINT(Bottom, Top)
-# define YY_REDUCE_PRINT(Rule)
-#endif /* !YYDEBUG */
-
-
-/* YYINITDEPTH -- initial size of the parser's stacks.  */
-#ifndef	YYINITDEPTH
-# define YYINITDEPTH 200
-#endif
-
-/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
-   if the built-in stack extension method is used).
-
-   Do not make this value too large; the results are undefined if
-   YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
-   evaluated with infinite-precision integer arithmetic.  */
-
-#ifndef YYMAXDEPTH
-# define YYMAXDEPTH 10000
-#endif
-
-

-
-#if YYERROR_VERBOSE
-
-# ifndef yystrlen
-#  if defined __GLIBC__ && defined _STRING_H
-#   define yystrlen strlen
-#  else
-/* Return the length of YYSTR.  */
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static YYSIZE_T
-yystrlen (const char *yystr)
-#else
-static YYSIZE_T
-yystrlen (yystr)
-    const char *yystr;
-#endif
-{
-  YYSIZE_T yylen;
-  for (yylen = 0; yystr[yylen]; yylen++)
-    continue;
-  return yylen;
-}
-#  endif
-# endif
-
-# ifndef yystpcpy
-#  if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
-#   define yystpcpy stpcpy
-#  else
-/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
-   YYDEST.  */
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static char *
-yystpcpy (char *yydest, const char *yysrc)
-#else
-static char *
-yystpcpy (yydest, yysrc)
-    char *yydest;
-    const char *yysrc;
-#endif
-{
-  char *yyd = yydest;
-  const char *yys = yysrc;
-
-  while ((*yyd++ = *yys++) != '\0')
-    continue;
-
-  return yyd - 1;
-}
-#  endif
-# endif
-
-# ifndef yytnamerr
-/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
-   quotes and backslashes, so that it's suitable for yyerror.  The
-   heuristic is that double-quoting is unnecessary unless the string
-   contains an apostrophe, a comma, or backslash (other than
-   backslash-backslash).  YYSTR is taken from yytname.  If YYRES is
-   null, do not copy; instead, return the length of what the result
-   would have been.  */
-static YYSIZE_T
-yytnamerr (char *yyres, const char *yystr)
-{
-  if (*yystr == '"')
-    {
-      YYSIZE_T yyn = 0;
-      char const *yyp = yystr;
-
-      for (;;)
-	switch (*++yyp)
-	  {
-	  case '\'':
-	  case ',':
-	    goto do_not_strip_quotes;
-
-	  case '\\':
-	    if (*++yyp != '\\')
-	      goto do_not_strip_quotes;
-	    /* Fall through.  */
-	  default:
-	    if (yyres)
-	      yyres[yyn] = *yyp;
-	    yyn++;
-	    break;
-
-	  case '"':
-	    if (yyres)
-	      yyres[yyn] = '\0';
-	    return yyn;
-	  }
-    do_not_strip_quotes: ;
-    }
-
-  if (! yyres)
-    return yystrlen (yystr);
-
-  return yystpcpy (yyres, yystr) - yyres;
-}
-# endif
-
-/* Copy into YYRESULT an error message about the unexpected token
-   YYCHAR while in state YYSTATE.  Return the number of bytes copied,
-   including the terminating null byte.  If YYRESULT is null, do not
-   copy anything; just return the number of bytes that would be
-   copied.  As a special case, return 0 if an ordinary "syntax error"
-   message will do.  Return YYSIZE_MAXIMUM if overflow occurs during
-   size calculation.  */
-static YYSIZE_T
-yysyntax_error (char *yyresult, int yystate, int yychar)
-{
-  int yyn = yypact[yystate];
-
-  if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
-    return 0;
-  else
-    {
-      int yytype = YYTRANSLATE (yychar);
-      YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
-      YYSIZE_T yysize = yysize0;
-      YYSIZE_T yysize1;
-      int yysize_overflow = 0;
-      enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
-      char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
-      int yyx;
-
-# if 0
-      /* This is so xgettext sees the translatable formats that are
-	 constructed on the fly.  */
-      YY_("syntax error, unexpected %s");
-      YY_("syntax error, unexpected %s, expecting %s");
-      YY_("syntax error, unexpected %s, expecting %s or %s");
-      YY_("syntax error, unexpected %s, expecting %s or %s or %s");
-      YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
-# endif
-      char *yyfmt;
-      char const *yyf;
-      static char const yyunexpected[] = "syntax error, unexpected %s";
-      static char const yyexpecting[] = ", expecting %s";
-      static char const yyor[] = " or %s";
-      char yyformat[sizeof yyunexpected
-		    + sizeof yyexpecting - 1
-		    + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
-		       * (sizeof yyor - 1))];
-      char const *yyprefix = yyexpecting;
-
-      /* Start YYX at -YYN if negative to avoid negative indexes in
-	 YYCHECK.  */
-      int yyxbegin = yyn < 0 ? -yyn : 0;
-
-      /* Stay within bounds of both yycheck and yytname.  */
-      int yychecklim = YYLAST - yyn + 1;
-      int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
-      int yycount = 1;
-
-      yyarg[0] = yytname[yytype];
-      yyfmt = yystpcpy (yyformat, yyunexpected);
-
-      for (yyx = yyxbegin; yyx < yyxend; ++yyx)
-	if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
-	  {
-	    if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
-	      {
-		yycount = 1;
-		yysize = yysize0;
-		yyformat[sizeof yyunexpected - 1] = '\0';
-		break;
-	      }
-	    yyarg[yycount++] = yytname[yyx];
-	    yysize1 = yysize + yytnamerr (0, yytname[yyx]);
-	    yysize_overflow |= (yysize1 < yysize);
-	    yysize = yysize1;
-	    yyfmt = yystpcpy (yyfmt, yyprefix);
-	    yyprefix = yyor;
-	  }
-
-      yyf = YY_(yyformat);
-      yysize1 = yysize + yystrlen (yyf);
-      yysize_overflow |= (yysize1 < yysize);
-      yysize = yysize1;
-
-      if (yysize_overflow)
-	return YYSIZE_MAXIMUM;
-
-      if (yyresult)
-	{
-	  /* Avoid sprintf, as that infringes on the user's name space.
-	     Don't have undefined behavior even if the translation
-	     produced a string with the wrong number of "%s"s.  */
-	  char *yyp = yyresult;
-	  int yyi = 0;
-	  while ((*yyp = *yyf) != '\0')
-	    {
-	      if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
-		{
-		  yyp += yytnamerr (yyp, yyarg[yyi++]);
-		  yyf += 2;
-		}
-	      else
-		{
-		  yyp++;
-		  yyf++;
-		}
-	    }
-	}
-      return yysize;
-    }
-}
-#endif /* YYERROR_VERBOSE */
-

-
-/*-----------------------------------------------.
-| Release the memory associated to this symbol.  |
-`-----------------------------------------------*/
-
-/*ARGSUSED*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static void
-yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
-#else
-static void
-yydestruct (yymsg, yytype, yyvaluep)
-    const char *yymsg;
-    int yytype;
-    YYSTYPE *yyvaluep;
-#endif
-{
-  YYUSE (yyvaluep);
-
-  if (!yymsg)
-    yymsg = "Deleting";
-  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
-
-  switch (yytype)
-    {
-
-      default:
-	break;
-    }
-}
-

-
-/* Prevent warnings from -Wmissing-prototypes.  */
-
-#ifdef YYPARSE_PARAM
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void *YYPARSE_PARAM);
-#else
-int yyparse ();
-#endif
-#else /* ! YYPARSE_PARAM */
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void);
-#else
-int yyparse ();
-#endif
-#endif /* ! YYPARSE_PARAM */
-
-
-
-/* The look-ahead symbol.  */
-int yychar;
-
-/* The semantic value of the look-ahead symbol.  */
-YYSTYPE yylval;
-
-/* Number of syntax errors so far.  */
-int yynerrs;
-
-
-
-/*----------.
-| yyparse.  |
-`----------*/
-
-#ifdef YYPARSE_PARAM
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-int
-yyparse (void *YYPARSE_PARAM)
-#else
-int
-yyparse (YYPARSE_PARAM)
-    void *YYPARSE_PARAM;
-#endif
-#else /* ! YYPARSE_PARAM */
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-int
-yyparse (void)
-#else
-int
-yyparse ()
-
-#endif
-#endif
-{
-  
-  int yystate;
-  int yyn;
-  int yyresult;
-  /* Number of tokens to shift before error messages enabled.  */
-  int yyerrstatus;
-  /* Look-ahead token as an internal (translated) token number.  */
-  int yytoken = 0;
-#if YYERROR_VERBOSE
-  /* Buffer for error messages, and its allocated size.  */
-  char yymsgbuf[128];
-  char *yymsg = yymsgbuf;
-  YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
-#endif
-
-  /* Three stacks and their tools:
-     `yyss': related to states,
-     `yyvs': related to semantic values,
-     `yyls': related to locations.
-
-     Refer to the stacks thru separate pointers, to allow yyoverflow
-     to reallocate them elsewhere.  */
-
-  /* The state stack.  */
-  yytype_int16 yyssa[YYINITDEPTH];
-  yytype_int16 *yyss = yyssa;
-  yytype_int16 *yyssp;
-
-  /* The semantic value stack.  */
-  YYSTYPE yyvsa[YYINITDEPTH];
-  YYSTYPE *yyvs = yyvsa;
-  YYSTYPE *yyvsp;
-
-
-
-#define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N))
-
-  YYSIZE_T yystacksize = YYINITDEPTH;
-
-  /* The variables used to return semantic value and location from the
-     action routines.  */
-  YYSTYPE yyval;
-
-
-  /* The number of symbols on the RHS of the reduced rule.
-     Keep to zero when no symbol should be popped.  */
-  int yylen = 0;
-
-  YYDPRINTF ((stderr, "Starting parse\n"));
-
-  yystate = 0;
-  yyerrstatus = 0;
-  yynerrs = 0;
-  yychar = YYEMPTY;		/* Cause a token to be read.  */
-
-  /* Initialize stack pointers.
-     Waste one element of value and location stack
-     so that they stay on the same level as the state stack.
-     The wasted elements are never initialized.  */
-
-  yyssp = yyss;
-  yyvsp = yyvs;
-
-  goto yysetstate;
-
-/*------------------------------------------------------------.
-| yynewstate -- Push a new state, which is found in yystate.  |
-`------------------------------------------------------------*/
- yynewstate:
-  /* In all cases, when you get here, the value and location stacks
-     have just been pushed.  So pushing a state here evens the stacks.  */
-  yyssp++;
-
- yysetstate:
-  *yyssp = yystate;
-
-  if (yyss + yystacksize - 1 <= yyssp)
-    {
-      /* Get the current used size of the three stacks, in elements.  */
-      YYSIZE_T yysize = yyssp - yyss + 1;
-
-#ifdef yyoverflow
-      {
-	/* Give user a chance to reallocate the stack.  Use copies of
-	   these so that the &'s don't force the real ones into
-	   memory.  */
-	YYSTYPE *yyvs1 = yyvs;
-	yytype_int16 *yyss1 = yyss;
-
-
-	/* Each stack pointer address is followed by the size of the
-	   data in use in that stack, in bytes.  This used to be a
-	   conditional around just the two extra args, but that might
-	   be undefined if yyoverflow is a macro.  */
-	yyoverflow (YY_("memory exhausted"),
-		    &yyss1, yysize * sizeof (*yyssp),
-		    &yyvs1, yysize * sizeof (*yyvsp),
-
-		    &yystacksize);
-
-	yyss = yyss1;
-	yyvs = yyvs1;
-      }
-#else /* no yyoverflow */
-# ifndef YYSTACK_RELOCATE
-      goto yyexhaustedlab;
-# else
-      /* Extend the stack our own way.  */
-      if (YYMAXDEPTH <= yystacksize)
-	goto yyexhaustedlab;
-      yystacksize *= 2;
-      if (YYMAXDEPTH < yystacksize)
-	yystacksize = YYMAXDEPTH;
-
-      {
-	yytype_int16 *yyss1 = yyss;
-	union yyalloc *yyptr =
-	  (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
-	if (! yyptr)
-	  goto yyexhaustedlab;
-	YYSTACK_RELOCATE (yyss);
-	YYSTACK_RELOCATE (yyvs);
-
-#  undef YYSTACK_RELOCATE
-	if (yyss1 != yyssa)
-	  YYSTACK_FREE (yyss1);
-      }
-# endif
-#endif /* no yyoverflow */
-
-      yyssp = yyss + yysize - 1;
-      yyvsp = yyvs + yysize - 1;
-
-
-      YYDPRINTF ((stderr, "Stack size increased to %lu\n",
-		  (unsigned long int) yystacksize));
-
-      if (yyss + yystacksize - 1 <= yyssp)
-	YYABORT;
-    }
-
-  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
-
-  goto yybackup;
-
-/*-----------.
-| yybackup.  |
-`-----------*/
-yybackup:
-
-  /* Do appropriate processing given the current state.  Read a
-     look-ahead token if we need one and don't already have one.  */
-
-  /* First try to decide what to do without reference to look-ahead token.  */
-  yyn = yypact[yystate];
-  if (yyn == YYPACT_NINF)
-    goto yydefault;
-
-  /* Not known => get a look-ahead token if don't already have one.  */
-
-  /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol.  */
-  if (yychar == YYEMPTY)
-    {
-      YYDPRINTF ((stderr, "Reading a token: "));
-      yychar = YYLEX;
-    }
-
-  if (yychar <= YYEOF)
-    {
-      yychar = yytoken = YYEOF;
-      YYDPRINTF ((stderr, "Now at end of input.\n"));
-    }
-  else
-    {
-      yytoken = YYTRANSLATE (yychar);
-      YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
-    }
-
-  /* If the proper action on seeing token YYTOKEN is to reduce or to
-     detect an error, take that action.  */
-  yyn += yytoken;
-  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
-    goto yydefault;
-  yyn = yytable[yyn];
-  if (yyn <= 0)
-    {
-      if (yyn == 0 || yyn == YYTABLE_NINF)
-	goto yyerrlab;
-      yyn = -yyn;
-      goto yyreduce;
-    }
-
-  if (yyn == YYFINAL)
-    YYACCEPT;
-
-  /* Count tokens shifted since error; after three, turn off error
-     status.  */
-  if (yyerrstatus)
-    yyerrstatus--;
-
-  /* Shift the look-ahead token.  */
-  YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
-
-  /* Discard the shifted token unless it is eof.  */
-  if (yychar != YYEOF)
-    yychar = YYEMPTY;
-
-  yystate = yyn;
-  *++yyvsp = yylval;
-
-  goto yynewstate;
-
-
-/*-----------------------------------------------------------.
-| yydefault -- do the default action for the current state.  |
-`-----------------------------------------------------------*/
-yydefault:
-  yyn = yydefact[yystate];
-  if (yyn == 0)
-    goto yyerrlab;
-  goto yyreduce;
-
-
-/*-----------------------------.
-| yyreduce -- Do a reduction.  |
-`-----------------------------*/
-yyreduce:
-  /* yyn is the number of a rule to reduce with.  */
-  yylen = yyr2[yyn];
-
-  /* If YYLEN is nonzero, implement the default value of the action:
-     `$$ = $1'.
-
-     Otherwise, the following line sets YYVAL to garbage.
-     This behavior is undocumented and Bison
-     users should not rely upon it.  Assigning to YYVAL
-     unconditionally makes the parser a bit smaller, and it avoids a
-     GCC warning that YYVAL may be used uninitialized.  */
-  yyval = yyvsp[1-yylen];
-
-
-  YY_REDUCE_PRINT (yyn);
-  switch (yyn)
-    {
-        case 3:
-#line 71 "a.y"
-    {
-		stmtline = lineno;
-	}
-    break;
-
-  case 5:
-#line 78 "a.y"
-    {
-		if((yyvsp[(1) - (2)].sym)->value != pc)
-			yyerror("redeclaration of %s", (yyvsp[(1) - (2)].sym)->name);
-		(yyvsp[(1) - (2)].sym)->value = pc;
-	}
-    break;
-
-  case 7:
-#line 85 "a.y"
-    {
-		(yyvsp[(1) - (2)].sym)->type = LLAB;
-		(yyvsp[(1) - (2)].sym)->value = pc;
-	}
-    break;
-
-  case 12:
-#line 96 "a.y"
-    {
-		(yyvsp[(1) - (3)].sym)->type = LVAR;
-		(yyvsp[(1) - (3)].sym)->value = (yyvsp[(3) - (3)].lval);
-	}
-    break;
-
-  case 13:
-#line 101 "a.y"
-    {
-		if((yyvsp[(1) - (3)].sym)->value != (yyvsp[(3) - (3)].lval))
-			yyerror("redeclaration of %s", (yyvsp[(1) - (3)].sym)->name);
-		(yyvsp[(1) - (3)].sym)->value = (yyvsp[(3) - (3)].lval);
-	}
-    break;
-
-  case 14:
-#line 106 "a.y"
-    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
-    break;
-
-  case 15:
-#line 107 "a.y"
-    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
-    break;
-
-  case 16:
-#line 108 "a.y"
-    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
-    break;
-
-  case 17:
-#line 109 "a.y"
-    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
-    break;
-
-  case 18:
-#line 110 "a.y"
-    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
-    break;
-
-  case 19:
-#line 111 "a.y"
-    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
-    break;
-
-  case 20:
-#line 112 "a.y"
-    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
-    break;
-
-  case 21:
-#line 113 "a.y"
-    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
-    break;
-
-  case 22:
-#line 114 "a.y"
-    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
-    break;
-
-  case 23:
-#line 115 "a.y"
-    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
-    break;
-
-  case 24:
-#line 116 "a.y"
-    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
-    break;
-
-  case 25:
-#line 117 "a.y"
-    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
-    break;
-
-  case 26:
-#line 118 "a.y"
-    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
-    break;
-
-  case 27:
-#line 119 "a.y"
-    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
-    break;
-
-  case 28:
-#line 120 "a.y"
-    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
-    break;
-
-  case 29:
-#line 121 "a.y"
-    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
-    break;
-
-  case 30:
-#line 122 "a.y"
-    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
-    break;
-
-  case 31:
-#line 123 "a.y"
-    { outcode((yyvsp[(1) - (2)].lval), &(yyvsp[(2) - (2)].addr2)); }
-    break;
-
-  case 32:
-#line 126 "a.y"
-    {
-		(yyval.addr2).from = nullgen;
-		(yyval.addr2).to = nullgen;
-	}
-    break;
-
-  case 33:
-#line 131 "a.y"
-    {
-		(yyval.addr2).from = nullgen;
-		(yyval.addr2).to = nullgen;
-	}
-    break;
-
-  case 34:
-#line 138 "a.y"
-    {
-		(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
-		(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
-	}
-    break;
-
-  case 35:
-#line 145 "a.y"
-    {
-		(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
-		(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
-	}
-    break;
-
-  case 36:
-#line 152 "a.y"
-    {
-		(yyval.addr2).from = (yyvsp[(1) - (2)].addr);
-		(yyval.addr2).to = nullgen;
-	}
-    break;
-
-  case 37:
-#line 157 "a.y"
-    {
-		(yyval.addr2).from = (yyvsp[(1) - (1)].addr);
-		(yyval.addr2).to = nullgen;
-	}
-    break;
-
-  case 38:
-#line 164 "a.y"
-    {
-		(yyval.addr2).from = nullgen;
-		(yyval.addr2).to = (yyvsp[(2) - (2)].addr);
-	}
-    break;
-
-  case 39:
-#line 169 "a.y"
-    {
-		(yyval.addr2).from = nullgen;
-		(yyval.addr2).to = (yyvsp[(1) - (1)].addr);
-	}
-    break;
-
-  case 40:
-#line 176 "a.y"
-    {
-		(yyval.addr2).from = nullgen;
-		(yyval.addr2).to = (yyvsp[(2) - (2)].addr);
-	}
-    break;
-
-  case 41:
-#line 181 "a.y"
-    {
-		(yyval.addr2).from = nullgen;
-		(yyval.addr2).to = (yyvsp[(1) - (1)].addr);
-	}
-    break;
-
-  case 42:
-#line 186 "a.y"
-    {
-		(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
-		(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
-	}
-    break;
-
-  case 43:
-#line 193 "a.y"
-    {
-		(yyval.addr2).from = (yyvsp[(1) - (5)].addr);
-		(yyval.addr2).from.scale = (yyvsp[(3) - (5)].lval);
-		(yyval.addr2).to = (yyvsp[(5) - (5)].addr);
-	}
-    break;
-
-  case 44:
-#line 201 "a.y"
-    {
-		(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
-		(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
-	}
-    break;
-
-  case 45:
-#line 206 "a.y"
-    {
-		(yyval.addr2).from = (yyvsp[(1) - (5)].addr);
-		(yyval.addr2).from.scale = (yyvsp[(3) - (5)].lval);
-		(yyval.addr2).to = (yyvsp[(5) - (5)].addr);
-	}
-    break;
-
-  case 46:
-#line 214 "a.y"
-    {
-		(yyval.addr2).from = nullgen;
-		(yyval.addr2).to = (yyvsp[(2) - (2)].addr);
-	}
-    break;
-
-  case 47:
-#line 219 "a.y"
-    {
-		(yyval.addr2).from = nullgen;
-		(yyval.addr2).to = (yyvsp[(1) - (1)].addr);
-	}
-    break;
-
-  case 48:
-#line 224 "a.y"
-    {
-		(yyval.addr2).from = nullgen;
-		(yyval.addr2).to = (yyvsp[(2) - (2)].addr);
-		(yyval.addr2).to.index = (yyvsp[(2) - (2)].addr).type;
-		(yyval.addr2).to.type = D_INDIR+D_ADDR;
-	}
-    break;
-
-  case 51:
-#line 237 "a.y"
-    {
-		(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
-		(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
-	}
-    break;
-
-  case 52:
-#line 242 "a.y"
-    {
-		(yyval.addr2).from = (yyvsp[(1) - (5)].addr);
-		(yyval.addr2).to = (yyvsp[(3) - (5)].addr);
-		if((yyval.addr2).from.index != D_NONE)
-			yyerror("dp shift with lhs index");
-		(yyval.addr2).from.index = (yyvsp[(5) - (5)].lval);
-	}
-    break;
-
-  case 53:
-#line 252 "a.y"
-    {
-		(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
-		(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
-	}
-    break;
-
-  case 54:
-#line 257 "a.y"
-    {
-		(yyval.addr2).from = (yyvsp[(1) - (5)].addr);
-		(yyval.addr2).to = (yyvsp[(3) - (5)].addr);
-		if((yyval.addr2).to.index != D_NONE)
-			yyerror("dp move with lhs index");
-		(yyval.addr2).to.index = (yyvsp[(5) - (5)].lval);
-	}
-    break;
-
-  case 55:
-#line 267 "a.y"
-    {
-		(yyval.addr2).from = (yyvsp[(1) - (2)].addr);
-		(yyval.addr2).to = nullgen;
-	}
-    break;
-
-  case 56:
-#line 272 "a.y"
-    {
-		(yyval.addr2).from = (yyvsp[(1) - (1)].addr);
-		(yyval.addr2).to = nullgen;
-	}
-    break;
-
-  case 57:
-#line 277 "a.y"
-    {
-		(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
-		(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
-	}
-    break;
-
-  case 58:
-#line 284 "a.y"
-    {
-		(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
-		(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
-	}
-    break;
-
-  case 59:
-#line 289 "a.y"
-    {
-		(yyval.addr2).from = (yyvsp[(1) - (5)].addr);
-		(yyval.addr2).from.scale = (yyvsp[(3) - (5)].lval);
-		(yyval.addr2).to = (yyvsp[(5) - (5)].addr);
-	}
-    break;
-
-  case 60:
-#line 297 "a.y"
-    {
-		(yyval.addr2).from = (yyvsp[(1) - (5)].addr);
-		(yyval.addr2).to = (yyvsp[(3) - (5)].addr);
-		(yyval.addr2).to.offset = (yyvsp[(5) - (5)].lval);
-	}
-    break;
-
-  case 61:
-#line 305 "a.y"
-    {
-		(yyval.addr2).from = (yyvsp[(3) - (5)].addr);
-		(yyval.addr2).to = (yyvsp[(5) - (5)].addr);
-		if((yyvsp[(1) - (5)].addr).type != D_CONST)
-			yyerror("illegal constant");
-		(yyval.addr2).to.offset = (yyvsp[(1) - (5)].addr).offset;
-	}
-    break;
-
-  case 62:
-#line 315 "a.y"
-    {
-		if((yyvsp[(1) - (3)].addr).type != D_CONST || (yyvsp[(3) - (3)].addr).type != D_CONST)
-			yyerror("arguments to PCDATA must be integer constants");
-		(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
-		(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
-	}
-    break;
-
-  case 63:
-#line 324 "a.y"
-    {
-		if((yyvsp[(1) - (3)].addr).type != D_CONST)
-			yyerror("index for FUNCDATA must be integer constant");
-		if((yyvsp[(3) - (3)].addr).type != D_EXTERN && (yyvsp[(3) - (3)].addr).type != D_STATIC)
-			yyerror("value for FUNCDATA must be symbol reference");
- 		(yyval.addr2).from = (yyvsp[(1) - (3)].addr);
- 		(yyval.addr2).to = (yyvsp[(3) - (3)].addr);
- 	}
-    break;
-
-  case 68:
-#line 341 "a.y"
-    {
-		(yyval.addr) = (yyvsp[(2) - (2)].addr);
-	}
-    break;
-
-  case 69:
-#line 345 "a.y"
-    {
-		(yyval.addr) = (yyvsp[(2) - (2)].addr);
-	}
-    break;
-
-  case 75:
-#line 358 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_BRANCH;
-		(yyval.addr).offset = (yyvsp[(1) - (4)].lval) + pc;
-	}
-    break;
-
-  case 76:
-#line 364 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		if(pass == 2)
-			yyerror("undefined label: %s", (yyvsp[(1) - (2)].sym)->name);
-		(yyval.addr).type = D_BRANCH;
-		(yyval.addr).offset = (yyvsp[(2) - (2)].lval);
-	}
-    break;
-
-  case 77:
-#line 372 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_BRANCH;
-		(yyval.addr).offset = (yyvsp[(1) - (2)].sym)->value + (yyvsp[(2) - (2)].lval);
-	}
-    break;
-
-  case 78:
-#line 380 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = (yyvsp[(1) - (1)].lval);
-	}
-    break;
-
-  case 79:
-#line 385 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = (yyvsp[(1) - (1)].lval);
-	}
-    break;
-
-  case 80:
-#line 390 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = (yyvsp[(1) - (1)].lval);
-	}
-    break;
-
-  case 81:
-#line 395 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = (yyvsp[(1) - (1)].lval);
-	}
-    break;
-
-  case 82:
-#line 400 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_SP;
-	}
-    break;
-
-  case 83:
-#line 405 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = (yyvsp[(1) - (1)].lval);
-	}
-    break;
-
-  case 84:
-#line 412 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_CONST;
-		(yyval.addr).offset = (yyvsp[(2) - (2)].lval);
-	}
-    break;
-
-  case 85:
-#line 418 "a.y"
-    {
-		(yyval.addr) = (yyvsp[(2) - (2)].addr);
-		(yyval.addr).index = (yyvsp[(2) - (2)].addr).type;
-		(yyval.addr).type = D_ADDR;
-		/*
-		if($2.type == D_AUTO || $2.type == D_PARAM)
-			yyerror("constant cannot be automatic: %s",
-				$2.sym->name);
-		 */
-	}
-    break;
-
-  case 86:
-#line 429 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_SCONST;
-		memcpy((yyval.addr).u.sval, (yyvsp[(2) - (2)].sval), sizeof((yyval.addr).u.sval));
-	}
-    break;
-
-  case 87:
-#line 435 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_FCONST;
-		(yyval.addr).u.dval = (yyvsp[(2) - (2)].dval);
-	}
-    break;
-
-  case 88:
-#line 441 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_FCONST;
-		(yyval.addr).u.dval = (yyvsp[(3) - (4)].dval);
-	}
-    break;
-
-  case 89:
-#line 447 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_FCONST;
-		(yyval.addr).u.dval = -(yyvsp[(4) - (5)].dval);
-	}
-    break;
-
-  case 90:
-#line 453 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_FCONST;
-		(yyval.addr).u.dval = -(yyvsp[(3) - (3)].dval);
-	}
-    break;
-
-  case 91:
-#line 461 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_CONST2;
-		(yyval.addr).offset = (yyvsp[(2) - (2)].con2).v1;
-		(yyval.addr).offset2 = (yyvsp[(2) - (2)].con2).v2;
-	}
-    break;
-
-  case 92:
-#line 470 "a.y"
-    {
-		(yyval.con2).v1 = (yyvsp[(1) - (1)].lval);
-		(yyval.con2).v2 = ArgsSizeUnknown;
-	}
-    break;
-
-  case 93:
-#line 475 "a.y"
-    {
-		(yyval.con2).v1 = -(yyvsp[(2) - (2)].lval);
-		(yyval.con2).v2 = ArgsSizeUnknown;
-	}
-    break;
-
-  case 94:
-#line 480 "a.y"
-    {
-		(yyval.con2).v1 = (yyvsp[(1) - (3)].lval);
-		(yyval.con2).v2 = (yyvsp[(3) - (3)].lval);
-	}
-    break;
-
-  case 95:
-#line 485 "a.y"
-    {
-		(yyval.con2).v1 = -(yyvsp[(2) - (4)].lval);
-		(yyval.con2).v2 = (yyvsp[(4) - (4)].lval);
-	}
-    break;
-
-  case 98:
-#line 496 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_INDIR+D_NONE;
-		(yyval.addr).offset = (yyvsp[(1) - (1)].lval);
-	}
-    break;
-
-  case 99:
-#line 502 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_INDIR+(yyvsp[(3) - (4)].lval);
-		(yyval.addr).offset = (yyvsp[(1) - (4)].lval);
-	}
-    break;
-
-  case 100:
-#line 508 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_INDIR+D_SP;
-		(yyval.addr).offset = (yyvsp[(1) - (4)].lval);
-	}
-    break;
-
-  case 101:
-#line 514 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_INDIR+D_NONE;
-		(yyval.addr).offset = (yyvsp[(1) - (6)].lval);
-		(yyval.addr).index = (yyvsp[(3) - (6)].lval);
-		(yyval.addr).scale = (yyvsp[(5) - (6)].lval);
-		checkscale((yyval.addr).scale);
-	}
-    break;
-
-  case 102:
-#line 523 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_INDIR+(yyvsp[(3) - (9)].lval);
-		(yyval.addr).offset = (yyvsp[(1) - (9)].lval);
-		(yyval.addr).index = (yyvsp[(6) - (9)].lval);
-		(yyval.addr).scale = (yyvsp[(8) - (9)].lval);
-		checkscale((yyval.addr).scale);
-	}
-    break;
-
-  case 103:
-#line 532 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_INDIR+(yyvsp[(3) - (9)].lval);
-		(yyval.addr).offset = (yyvsp[(1) - (9)].lval);
-		(yyval.addr).index = (yyvsp[(6) - (9)].lval);
-		(yyval.addr).scale = (yyvsp[(8) - (9)].lval);
-		checkscale((yyval.addr).scale);
-	}
-    break;
-
-  case 104:
-#line 541 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_INDIR+(yyvsp[(2) - (3)].lval);
-	}
-    break;
-
-  case 105:
-#line 546 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_INDIR+D_SP;
-	}
-    break;
-
-  case 106:
-#line 551 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_INDIR+(yyvsp[(3) - (4)].lval);
-		(yyval.addr).offset = (yyvsp[(1) - (4)].lval);
-	}
-    break;
-
-  case 107:
-#line 557 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_INDIR+D_NONE;
-		(yyval.addr).index = (yyvsp[(2) - (5)].lval);
-		(yyval.addr).scale = (yyvsp[(4) - (5)].lval);
-		checkscale((yyval.addr).scale);
-	}
-    break;
-
-  case 108:
-#line 565 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_INDIR+(yyvsp[(2) - (8)].lval);
-		(yyval.addr).index = (yyvsp[(5) - (8)].lval);
-		(yyval.addr).scale = (yyvsp[(7) - (8)].lval);
-		checkscale((yyval.addr).scale);
-	}
-    break;
-
-  case 109:
-#line 575 "a.y"
-    {
-		(yyval.addr) = (yyvsp[(1) - (1)].addr);
-	}
-    break;
-
-  case 110:
-#line 579 "a.y"
-    {
-		(yyval.addr) = (yyvsp[(1) - (6)].addr);
-		(yyval.addr).index = (yyvsp[(3) - (6)].lval);
-		(yyval.addr).scale = (yyvsp[(5) - (6)].lval);
-		checkscale((yyval.addr).scale);
-	}
-    break;
-
-  case 111:
-#line 588 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = (yyvsp[(4) - (5)].lval);
-		(yyval.addr).sym = linklookup(ctxt, (yyvsp[(1) - (5)].sym)->name, 0);
-		(yyval.addr).offset = (yyvsp[(2) - (5)].lval);
-	}
-    break;
-
-  case 112:
-#line 595 "a.y"
-    {
-		(yyval.addr) = nullgen;
-		(yyval.addr).type = D_STATIC;
-		(yyval.addr).sym = linklookup(ctxt, (yyvsp[(1) - (7)].sym)->name, 1);
-		(yyval.addr).offset = (yyvsp[(4) - (7)].lval);
-	}
-    break;
-
-  case 113:
-#line 603 "a.y"
-    {
-		(yyval.lval) = 0;
-	}
-    break;
-
-  case 114:
-#line 607 "a.y"
-    {
-		(yyval.lval) = (yyvsp[(2) - (2)].lval);
-	}
-    break;
-
-  case 115:
-#line 611 "a.y"
-    {
-		(yyval.lval) = -(yyvsp[(2) - (2)].lval);
-	}
-    break;
-
-  case 117:
-#line 618 "a.y"
-    {
-		(yyval.lval) = D_AUTO;
-	}
-    break;
-
-  case 120:
-#line 626 "a.y"
-    {
-		(yyval.lval) = (yyvsp[(1) - (1)].sym)->value;
-	}
-    break;
-
-  case 121:
-#line 630 "a.y"
-    {
-		(yyval.lval) = -(yyvsp[(2) - (2)].lval);
-	}
-    break;
-
-  case 122:
-#line 634 "a.y"
-    {
-		(yyval.lval) = (yyvsp[(2) - (2)].lval);
-	}
-    break;
-
-  case 123:
-#line 638 "a.y"
-    {
-		(yyval.lval) = ~(yyvsp[(2) - (2)].lval);
-	}
-    break;
-
-  case 124:
-#line 642 "a.y"
-    {
-		(yyval.lval) = (yyvsp[(2) - (3)].lval);
-	}
-    break;
-
-  case 126:
-#line 649 "a.y"
-    {
-		(yyval.lval) = (yyvsp[(1) - (3)].lval) + (yyvsp[(3) - (3)].lval);
-	}
-    break;
-
-  case 127:
-#line 653 "a.y"
-    {
-		(yyval.lval) = (yyvsp[(1) - (3)].lval) - (yyvsp[(3) - (3)].lval);
-	}
-    break;
-
-  case 128:
-#line 657 "a.y"
-    {
-		(yyval.lval) = (yyvsp[(1) - (3)].lval) * (yyvsp[(3) - (3)].lval);
-	}
-    break;
-
-  case 129:
-#line 661 "a.y"
-    {
-		(yyval.lval) = (yyvsp[(1) - (3)].lval) / (yyvsp[(3) - (3)].lval);
-	}
-    break;
-
-  case 130:
-#line 665 "a.y"
-    {
-		(yyval.lval) = (yyvsp[(1) - (3)].lval) % (yyvsp[(3) - (3)].lval);
-	}
-    break;
-
-  case 131:
-#line 669 "a.y"
-    {
-		(yyval.lval) = (yyvsp[(1) - (4)].lval) << (yyvsp[(4) - (4)].lval);
-	}
-    break;
-
-  case 132:
-#line 673 "a.y"
-    {
-		(yyval.lval) = (yyvsp[(1) - (4)].lval) >> (yyvsp[(4) - (4)].lval);
-	}
-    break;
-
-  case 133:
-#line 677 "a.y"
-    {
-		(yyval.lval) = (yyvsp[(1) - (3)].lval) & (yyvsp[(3) - (3)].lval);
-	}
-    break;
-
-  case 134:
-#line 681 "a.y"
-    {
-		(yyval.lval) = (yyvsp[(1) - (3)].lval) ^ (yyvsp[(3) - (3)].lval);
-	}
-    break;
-
-  case 135:
-#line 685 "a.y"
-    {
-		(yyval.lval) = (yyvsp[(1) - (3)].lval) | (yyvsp[(3) - (3)].lval);
-	}
-    break;
-
-
-/* Line 1267 of yacc.c.  */
-#line 2566 "y.tab.c"
-      default: break;
-    }
-  YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
-
-  YYPOPSTACK (yylen);
-  yylen = 0;
-  YY_STACK_PRINT (yyss, yyssp);
-
-  *++yyvsp = yyval;
-
-
-  /* Now `shift' the result of the reduction.  Determine what state
-     that goes to, based on the state we popped back to and the rule
-     number reduced by.  */
-
-  yyn = yyr1[yyn];
-
-  yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
-  if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
-    yystate = yytable[yystate];
-  else
-    yystate = yydefgoto[yyn - YYNTOKENS];
-
-  goto yynewstate;
-
-
-/*------------------------------------.
-| yyerrlab -- here on detecting error |
-`------------------------------------*/
-yyerrlab:
-  /* If not already recovering from an error, report this error.  */
-  if (!yyerrstatus)
-    {
-      ++yynerrs;
-#if ! YYERROR_VERBOSE
-      yyerror (YY_("syntax error"));
-#else
-      {
-	YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
-	if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
-	  {
-	    YYSIZE_T yyalloc = 2 * yysize;
-	    if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
-	      yyalloc = YYSTACK_ALLOC_MAXIMUM;
-	    if (yymsg != yymsgbuf)
-	      YYSTACK_FREE (yymsg);
-	    yymsg = (char *) YYSTACK_ALLOC (yyalloc);
-	    if (yymsg)
-	      yymsg_alloc = yyalloc;
-	    else
-	      {
-		yymsg = yymsgbuf;
-		yymsg_alloc = sizeof yymsgbuf;
-	      }
-	  }
-
-	if (0 < yysize && yysize <= yymsg_alloc)
-	  {
-	    (void) yysyntax_error (yymsg, yystate, yychar);
-	    yyerror (yymsg);
-	  }
-	else
-	  {
-	    yyerror (YY_("syntax error"));
-	    if (yysize != 0)
-	      goto yyexhaustedlab;
-	  }
-      }
-#endif
-    }
-
-
-
-  if (yyerrstatus == 3)
-    {
-      /* If just tried and failed to reuse look-ahead token after an
-	 error, discard it.  */
-
-      if (yychar <= YYEOF)
-	{
-	  /* Return failure if at end of input.  */
-	  if (yychar == YYEOF)
-	    YYABORT;
-	}
-      else
-	{
-	  yydestruct ("Error: discarding",
-		      yytoken, &yylval);
-	  yychar = YYEMPTY;
-	}
-    }
-
-  /* Else will try to reuse look-ahead token after shifting the error
-     token.  */
-  goto yyerrlab1;
-
-
-/*---------------------------------------------------.
-| yyerrorlab -- error raised explicitly by YYERROR.  |
-`---------------------------------------------------*/
-yyerrorlab:
-
-  /* Pacify compilers like GCC when the user code never invokes
-     YYERROR and the label yyerrorlab therefore never appears in user
-     code.  */
-  if (/*CONSTCOND*/ 0)
-     goto yyerrorlab;
-
-  /* Do not reclaim the symbols of the rule which action triggered
-     this YYERROR.  */
-  YYPOPSTACK (yylen);
-  yylen = 0;
-  YY_STACK_PRINT (yyss, yyssp);
-  yystate = *yyssp;
-  goto yyerrlab1;
-
-
-/*-------------------------------------------------------------.
-| yyerrlab1 -- common code for both syntax error and YYERROR.  |
-`-------------------------------------------------------------*/
-yyerrlab1:
-  yyerrstatus = 3;	/* Each real token shifted decrements this.  */
-
-  for (;;)
-    {
-      yyn = yypact[yystate];
-      if (yyn != YYPACT_NINF)
-	{
-	  yyn += YYTERROR;
-	  if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
-	    {
-	      yyn = yytable[yyn];
-	      if (0 < yyn)
-		break;
-	    }
-	}
-
-      /* Pop the current state because it cannot handle the error token.  */
-      if (yyssp == yyss)
-	YYABORT;
-
-
-      yydestruct ("Error: popping",
-		  yystos[yystate], yyvsp);
-      YYPOPSTACK (1);
-      yystate = *yyssp;
-      YY_STACK_PRINT (yyss, yyssp);
-    }
-
-  if (yyn == YYFINAL)
-    YYACCEPT;
-
-  *++yyvsp = yylval;
-
-
-  /* Shift the error token.  */
-  YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
-
-  yystate = yyn;
-  goto yynewstate;
-
-
-/*-------------------------------------.
-| yyacceptlab -- YYACCEPT comes here.  |
-`-------------------------------------*/
-yyacceptlab:
-  yyresult = 0;
-  goto yyreturn;
-
-/*-----------------------------------.
-| yyabortlab -- YYABORT comes here.  |
-`-----------------------------------*/
-yyabortlab:
-  yyresult = 1;
-  goto yyreturn;
-
-#ifndef yyoverflow
-/*-------------------------------------------------.
-| yyexhaustedlab -- memory exhaustion comes here.  |
-`-------------------------------------------------*/
-yyexhaustedlab:
-  yyerror (YY_("memory exhausted"));
-  yyresult = 2;
-  /* Fall through.  */
-#endif
-
-yyreturn:
-  if (yychar != YYEOF && yychar != YYEMPTY)
-     yydestruct ("Cleanup: discarding lookahead",
-		 yytoken, &yylval);
-  /* Do not reclaim the symbols of the rule which action triggered
-     this YYABORT or YYACCEPT.  */
-  YYPOPSTACK (yylen);
-  YY_STACK_PRINT (yyss, yyssp);
-  while (yyssp != yyss)
-    {
-      yydestruct ("Cleanup: popping",
-		  yystos[*yyssp], yyvsp);
-      YYPOPSTACK (1);
-    }
-#ifndef yyoverflow
-  if (yyss != yyssa)
-    YYSTACK_FREE (yyss);
-#endif
-#if YYERROR_VERBOSE
-  if (yymsg != yymsgbuf)
-    YYSTACK_FREE (yymsg);
-#endif
-  /* Make sure YYID is used.  */
-  return YYID (yyresult);
-}
-
-
-
diff --git a/src/cmd/8a/y.tab.h b/src/cmd/8a/y.tab.h
deleted file mode 100644
index d191455..0000000
--- a/src/cmd/8a/y.tab.h
+++ /dev/null
@@ -1,139 +0,0 @@
-/* A Bison parser, made by GNU Bison 2.3.  */
-
-/* Skeleton interface for Bison's Yacc-like parsers in C
-
-   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
-   Free Software Foundation, Inc.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
-   any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301, USA.  */
-
-/* As a special exception, you may create a larger work that contains
-   part or all of the Bison parser skeleton and distribute that work
-   under terms of your choice, so long as that work isn't itself a
-   parser generator using the skeleton or a modified version thereof
-   as a parser skeleton.  Alternatively, if you modify or redistribute
-   the parser skeleton itself, you may (at your option) remove this
-   special exception, which will cause the skeleton and the resulting
-   Bison output files to be licensed under the GNU General Public
-   License without this special exception.
-
-   This special exception was added by the Free Software Foundation in
-   version 2.2 of Bison.  */
-
-/* Tokens.  */
-#ifndef YYTOKENTYPE
-# define YYTOKENTYPE
-   /* Put the tokens into the symbol table, so that GDB and other debuggers
-      know about them.  */
-   enum yytokentype {
-     LTYPE0 = 258,
-     LTYPE1 = 259,
-     LTYPE2 = 260,
-     LTYPE3 = 261,
-     LTYPE4 = 262,
-     LTYPEC = 263,
-     LTYPED = 264,
-     LTYPEN = 265,
-     LTYPER = 266,
-     LTYPET = 267,
-     LTYPES = 268,
-     LTYPEM = 269,
-     LTYPEI = 270,
-     LTYPEG = 271,
-     LTYPEXC = 272,
-     LTYPEX = 273,
-     LTYPEPC = 274,
-     LTYPEF = 275,
-     LCONST = 276,
-     LFP = 277,
-     LPC = 278,
-     LSB = 279,
-     LBREG = 280,
-     LLREG = 281,
-     LSREG = 282,
-     LFREG = 283,
-     LXREG = 284,
-     LFCONST = 285,
-     LSCONST = 286,
-     LSP = 287,
-     LNAME = 288,
-     LLAB = 289,
-     LVAR = 290
-   };
-#endif
-/* Tokens.  */
-#define LTYPE0 258
-#define LTYPE1 259
-#define LTYPE2 260
-#define LTYPE3 261
-#define LTYPE4 262
-#define LTYPEC 263
-#define LTYPED 264
-#define LTYPEN 265
-#define LTYPER 266
-#define LTYPET 267
-#define LTYPES 268
-#define LTYPEM 269
-#define LTYPEI 270
-#define LTYPEG 271
-#define LTYPEXC 272
-#define LTYPEX 273
-#define LTYPEPC 274
-#define LTYPEF 275
-#define LCONST 276
-#define LFP 277
-#define LPC 278
-#define LSB 279
-#define LBREG 280
-#define LLREG 281
-#define LSREG 282
-#define LFREG 283
-#define LXREG 284
-#define LFCONST 285
-#define LSCONST 286
-#define LSP 287
-#define LNAME 288
-#define LLAB 289
-#define LVAR 290
-
-
-
-
-#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-typedef union YYSTYPE
-#line 38 "a.y"
-{
-	Sym	*sym;
-	int32	lval;
-	struct {
-		int32 v1;
-		int32 v2;
-	} con2;
-	double	dval;
-	char	sval[8];
-	Addr	addr;
-	Addr2	addr2;
-}
-/* Line 1529 of yacc.c.  */
-#line 132 "y.tab.h"
-	YYSTYPE;
-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
-# define YYSTYPE_IS_DECLARED 1
-# define YYSTYPE_IS_TRIVIAL 1
-#endif
-
-extern YYSTYPE yylval;
-
diff --git a/src/cmd/8c/Makefile b/src/cmd/8c/Makefile
deleted file mode 100644
index 3f528d7..0000000
--- a/src/cmd/8c/Makefile
+++ /dev/null
@@ -1,5 +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.
-
-include ../../Make.dist
diff --git a/src/cmd/8c/cgen.c b/src/cmd/8c/cgen.c
deleted file mode 100644
index 87e8fda..0000000
--- a/src/cmd/8c/cgen.c
+++ /dev/null
@@ -1,1939 +0,0 @@
-// Inferno utils/8c/cgen.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8c/cgen.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include "gc.h"
-#include "../../runtime/funcdata.h"
-
-/* ,x/^(print|prtree)\(/i/\/\/ */
-
-void
-cgen(Node *n, Node *nn)
-{
-	Node *l, *r, *t;
-	Prog *p1;
-	Node nod, nod1, nod2, nod3, nod4;
-	int o, hardleft;
-	int32 v, curs;
-	vlong c;
-
-	if(debug['g']) {
-		prtree(nn, "cgen lhs");
-		prtree(n, "cgen");
-	}
-	if(n == Z || n->type == T)
-		return;
-	if(typesuv[n->type->etype] && (n->op != OFUNC || nn != Z)) {
-		sugen(n, nn, n->type->width);
-		return;
-	}
-	l = n->left;
-	r = n->right;
-	o = n->op;
-
-	if(n->op == OEXREG || (nn != Z && nn->op == OEXREG)) {
-		gmove(n, nn);
-		return;
-	}
-
-	if(n->addable >= INDEXED) {
-		if(nn == Z) {
-			switch(o) {
-			default:
-				nullwarn(Z, Z);
-				break;
-			case OINDEX:
-				nullwarn(l, r);
-				break;
-			}
-			return;
-		}
-		gmove(n, nn);
-		return;
-	}
-	curs = cursafe;
-
-	if(l->complex >= FNX)
-	if(r != Z && r->complex >= FNX)
-	switch(o) {
-	default:
-		if(cond(o) && typesuv[l->type->etype])
-			break;
-
-		regret(&nod, r, 0, 0);
-		cgen(r, &nod);
-
-		regsalloc(&nod1, r);
-		gmove(&nod, &nod1);
-
-		regfree(&nod);
-		nod = *n;
-		nod.right = &nod1;
-
-		cgen(&nod, nn);
-		return;
-
-	case OFUNC:
-	case OCOMMA:
-	case OANDAND:
-	case OOROR:
-	case OCOND:
-	case ODOT:
-		break;
-	}
-
-	hardleft = l->addable < INDEXED || l->complex >= FNX;
-	switch(o) {
-	default:
-		diag(n, "unknown op in cgen: %O", o);
-		break;
-
-	case ONEG:
-	case OCOM:
-		if(nn == Z) {
-			nullwarn(l, Z);
-			break;
-		}
-		regalloc(&nod, l, nn);
-		cgen(l, &nod);
-		gopcode(o, n->type, Z, &nod);
-		gmove(&nod, nn);
-		regfree(&nod);
-		break;
-
-	case OAS:
-		if(typefd[n->type->etype]) {
-			cgen(r, &fregnode0);
-			if(nn != Z)
-				gins(AFMOVD, &fregnode0, &fregnode0);
-			if(l->addable < INDEXED) {
-				reglcgen(&nod, l, Z);
-				gmove(&fregnode0, &nod);
-				regfree(&nod);
-			} else
-				gmove(&fregnode0, l);
-			if(nn != Z)
-				gmove(&fregnode0, nn);
-			return;
-		}
-		if(l->op == OBIT)
-			goto bitas;
-		if(!hardleft) {
-			if(nn != Z || r->addable < INDEXED) {
-				if(r->complex >= FNX && nn == Z)
-					regret(&nod, r, 0, 0);
-				else
-					regalloc(&nod, r, nn);
-				cgen(r, &nod);
-				gmove(&nod, l);
-				if(nn != Z)
-					gmove(&nod, nn);
-				regfree(&nod);
-			} else
-				gmove(r, l);
-			break;
-		}
-		if(l->complex >= r->complex) {
-			if(l->op == OINDEX && r->op == OCONST) {
-				gmove(r, l);
-				break;
-			}
-			reglcgen(&nod1, l, Z);
-			if(r->addable >= INDEXED) {
-				gmove(r, &nod1);
-				if(nn != Z)
-					gmove(r, nn);
-				regfree(&nod1);
-				break;
-			}
-			regalloc(&nod, r, nn);
-			cgen(r, &nod);
-		} else {
-			regalloc(&nod, r, nn);
-			cgen(r, &nod);
-			reglcgen(&nod1, l, Z);
-		}
-		gmove(&nod, &nod1);
-		regfree(&nod);
-		regfree(&nod1);
-		break;
-
-	bitas:
-		n = l->left;
-		regalloc(&nod, r, nn);
-		if(l->complex >= r->complex) {
-			reglcgen(&nod1, n, Z);
-			cgen(r, &nod);
-		} else {
-			cgen(r, &nod);
-			reglcgen(&nod1, n, Z);
-		}
-		regalloc(&nod2, n, Z);
-		gmove(&nod1, &nod2);
-		bitstore(l, &nod, &nod1, &nod2, nn);
-		break;
-
-	case OBIT:
-		if(nn == Z) {
-			nullwarn(l, Z);
-			break;
-		}
-		bitload(n, &nod, Z, Z, nn);
-		gmove(&nod, nn);
-		regfree(&nod);
-		break;
-
-	case OLSHR:
-	case OASHL:
-	case OASHR:
-		if(nn == Z) {
-			nullwarn(l, r);
-			break;
-		}
-		if(r->op == OCONST) {
-			if(r->vconst == 0) {
-				cgen(l, nn);
-				break;
-			}
-			regalloc(&nod, l, nn);
-			cgen(l, &nod);
-			if(o == OASHL && r->vconst == 1)
-				gopcode(OADD, n->type, &nod, &nod);
-			else
-				gopcode(o, n->type, r, &nod);
-			gmove(&nod, nn);
-			regfree(&nod);
-			break;
-		}
-
-		/*
-		 * get nod to be D_CX
-		 */
-		if(nodreg(&nod, nn, D_CX)) {
-			regsalloc(&nod1, n);
-			gmove(&nod, &nod1);
-			cgen(n, &nod);		/* probably a bug */
-			gmove(&nod, nn);
-			gmove(&nod1, &nod);
-			break;
-		}
-		reg[D_CX]++;
-		if(nn->op == OREGISTER && nn->reg == D_CX)
-			regalloc(&nod1, l, Z);
-		else
-			regalloc(&nod1, l, nn);
-		if(r->complex >= l->complex) {
-			cgen(r, &nod);
-			cgen(l, &nod1);
-		} else {
-			cgen(l, &nod1);
-			cgen(r, &nod);
-		}
-		gopcode(o, n->type, &nod, &nod1);
-		gmove(&nod1, nn);
-		regfree(&nod);
-		regfree(&nod1);
-		break;
-
-	case OADD:
-	case OSUB:
-	case OOR:
-	case OXOR:
-	case OAND:
-		if(nn == Z) {
-			nullwarn(l, r);
-			break;
-		}
-		if(typefd[n->type->etype])
-			goto fop;
-		if(r->op == OCONST) {
-			if(r->vconst == 0 && o != OAND) {
-				cgen(l, nn);
-				break;
-			}
-		}
-		if(n->op == OOR && l->op == OASHL && r->op == OLSHR
-		&& l->right->op == OCONST && r->right->op == OCONST
-		&& l->left->op == ONAME && r->left->op == ONAME
-		&& l->left->sym == r->left->sym
-		&& l->right->vconst + r->right->vconst == 8 * l->left->type->width) {
-			regalloc(&nod, l->left, nn);
-			cgen(l->left, &nod);
-			gopcode(OROTL, n->type, l->right, &nod);
-			gmove(&nod, nn);
-			regfree(&nod);
-			break;
-		}
-		if(n->op == OADD && l->op == OASHL && l->right->op == OCONST
-		&& (r->op != OCONST || r->vconst < -128 || r->vconst > 127)) {
-			c = l->right->vconst;
-			if(c > 0 && c <= 3) {
-				if(l->left->complex >= r->complex) {
-					regalloc(&nod, l->left, nn);
-					cgen(l->left, &nod);
-					if(r->addable < INDEXED) {
-						regalloc(&nod1, r, Z);
-						cgen(r, &nod1);
-						genmuladd(&nod, &nod, 1 << c, &nod1);
-						regfree(&nod1);
-					}
-					else
-						genmuladd(&nod, &nod, 1 << c, r);
-				}
-				else {
-					regalloc(&nod, r, nn);
-					cgen(r, &nod);
-					regalloc(&nod1, l->left, Z);
-					cgen(l->left, &nod1);
-					genmuladd(&nod, &nod1, 1 << c, &nod);
-					regfree(&nod1);
-				}
-				gmove(&nod, nn);
-				regfree(&nod);
-				break;
-			}
-		}
-		if(r->addable >= INDEXED) {
-			regalloc(&nod, l, nn);
-			cgen(l, &nod);
-			gopcode(o, n->type, r, &nod);
-			gmove(&nod, nn);
-			regfree(&nod);
-			break;
-		}
-		if(l->complex >= r->complex) {
-			regalloc(&nod, l, nn);
-			cgen(l, &nod);
-			regalloc(&nod1, r, Z);
-			cgen(r, &nod1);
-			gopcode(o, n->type, &nod1, &nod);
-		} else {
-			regalloc(&nod1, r, nn);
-			cgen(r, &nod1);
-			regalloc(&nod, l, Z);
-			cgen(l, &nod);
-			gopcode(o, n->type, &nod1, &nod);
-		}
-		gmove(&nod, nn);
-		regfree(&nod);
-		regfree(&nod1);
-		break;
-
-	case OLMOD:
-	case OMOD:
-	case OLMUL:
-	case OLDIV:
-	case OMUL:
-	case ODIV:
-		if(nn == Z) {
-			nullwarn(l, r);
-			break;
-		}
-		if(typefd[n->type->etype])
-			goto fop;
-		if(r->op == OCONST) {
-			SET(v);
-			switch(o) {
-			case ODIV:
-			case OMOD:
-				c = r->vconst;
-				if(c < 0)
-					c = -c;
-				v = xlog2(c);
-				if(v < 0)
-					break;
-				/* fall thru */
-			case OMUL:
-			case OLMUL:
-				regalloc(&nod, l, nn);
-				cgen(l, &nod);
-				switch(o) {
-				case OMUL:
-				case OLMUL:
-					mulgen(n->type, r, &nod);
-					break;
-				case ODIV:
-					sdiv2(r->vconst, v, l, &nod);
-					break;
-				case OMOD:
-					smod2(r->vconst, v, l, &nod);
-					break;
-				}
-				gmove(&nod, nn);
-				regfree(&nod);
-				goto done;
-			case OLDIV:
-				c = r->vconst;
-				if((c & 0x80000000) == 0)
-					break;
-				regalloc(&nod1, l, Z);
-				cgen(l, &nod1);
-				regalloc(&nod, l, nn);
-				zeroregm(&nod);
-				gins(ACMPL, &nod1, nodconst(c));
-				gins(ASBBL, nodconst(-1), &nod);
-				regfree(&nod1);
-				gmove(&nod, nn);
-				regfree(&nod);
-				goto done;
-			}
-		}
-
-		if(o == OMUL || o == OLMUL) {
-			if(l->addable >= INDEXED) {
-				t = l;
-				l = r;
-				r = t;
-			}
-			reg[D_DX]++; // for gopcode case OMUL
-			regalloc(&nod, l, nn);
-			cgen(l, &nod);
-			if(r->addable < INDEXED) {
-				regalloc(&nod1, r, Z);
-				cgen(r, &nod1);
-				gopcode(OMUL, n->type, &nod1, &nod);
-				regfree(&nod1);
-			}else
-				gopcode(OMUL, n->type, r, &nod);	/* addressible */
-			gmove(&nod, nn);
-			regfree(&nod);
-			reg[D_DX]--;
-			break;
-		}
-
-		/*
-		 * get nod to be D_AX
-		 * get nod1 to be D_DX
-		 */
-		if(nodreg(&nod, nn, D_AX)) {
-			regsalloc(&nod2, n);
-			gmove(&nod, &nod2);
-			v = reg[D_AX];
-			reg[D_AX] = 0;
-
-			if(isreg(l, D_AX)) {
-				nod3 = *n;
-				nod3.left = &nod2;
-				cgen(&nod3, nn);
-			} else
-			if(isreg(r, D_AX)) {
-				nod3 = *n;
-				nod3.right = &nod2;
-				cgen(&nod3, nn);
-			} else
-				cgen(n, nn);
-
-			gmove(&nod2, &nod);
-			reg[D_AX] = v;
-			break;
-		}
-		if(nodreg(&nod1, nn, D_DX)) {
-			regsalloc(&nod2, n);
-			gmove(&nod1, &nod2);
-			v = reg[D_DX];
-			reg[D_DX] = 0;
-
-			if(isreg(l, D_DX)) {
-				nod3 = *n;
-				nod3.left = &nod2;
-				cgen(&nod3, nn);
-			} else
-			if(isreg(r, D_DX)) {
-				nod3 = *n;
-				nod3.right = &nod2;
-				cgen(&nod3, nn);
-			} else
-				cgen(n, nn);
-
-			gmove(&nod2, &nod1);
-			reg[D_DX] = v;
-			break;
-		}
-		reg[D_AX]++;
-
-		if(r->op == OCONST && (o == ODIV || o == OLDIV)) {
-			reg[D_DX]++;
-			if(l->addable < INDEXED) {
-				regalloc(&nod2, l, Z);
-				cgen(l, &nod2);
-				l = &nod2;
-			}
-			if(o == ODIV)
-				sdivgen(l, r, &nod, &nod1);
-			else
-				udivgen(l, r, &nod, &nod1);
-			gmove(&nod1, nn);
-			if(l == &nod2)
-				regfree(l);
-			goto freeaxdx;
-		}
-
-		if(l->complex >= r->complex) {
-			cgen(l, &nod);
-			reg[D_DX]++;
-			if(o == ODIV || o == OMOD)
-				gins(ACDQ, Z, Z);
-			if(o == OLDIV || o == OLMOD)
-				zeroregm(&nod1);
-			if(r->addable < INDEXED || r->op == OCONST) {
-				regsalloc(&nod3, r);
-				cgen(r, &nod3);
-				gopcode(o, n->type, &nod3, Z);
-			} else
-				gopcode(o, n->type, r, Z);
-		} else {
-			regsalloc(&nod3, r);
-			cgen(r, &nod3);
-			cgen(l, &nod);
-			reg[D_DX]++;
-			if(o == ODIV || o == OMOD)
-				gins(ACDQ, Z, Z);
-			if(o == OLDIV || o == OLMOD)
-				zeroregm(&nod1);
-			gopcode(o, n->type, &nod3, Z);
-		}
-		if(o == OMOD || o == OLMOD)
-			gmove(&nod1, nn);
-		else
-			gmove(&nod, nn);
-	freeaxdx:
-		regfree(&nod);
-		regfree(&nod1);
-		break;
-
-	case OASLSHR:
-	case OASASHL:
-	case OASASHR:
-		if(r->op == OCONST)
-			goto asand;
-		if(l->op == OBIT)
-			goto asbitop;
-		if(typefd[n->type->etype])
-			goto asfop;
-
-		/*
-		 * get nod to be D_CX
-		 */
-		if(nodreg(&nod, nn, D_CX)) {
-			regsalloc(&nod1, n);
-			gmove(&nod, &nod1);
-			cgen(n, &nod);
-			if(nn != Z)
-				gmove(&nod, nn);
-			gmove(&nod1, &nod);
-			break;
-		}
-		reg[D_CX]++;
-
-		if(r->complex >= l->complex) {
-			cgen(r, &nod);
-			if(hardleft)
-				reglcgen(&nod1, l, Z);
-			else
-				nod1 = *l;
-		} else {
-			if(hardleft)
-				reglcgen(&nod1, l, Z);
-			else
-				nod1 = *l;
-			cgen(r, &nod);
-		}
-
-		gopcode(o, l->type, &nod, &nod1);
-		regfree(&nod);
-		if(nn != Z)
-			gmove(&nod1, nn);
-		if(hardleft)
-			regfree(&nod1);
-		break;
-
-	case OASAND:
-	case OASADD:
-	case OASSUB:
-	case OASXOR:
-	case OASOR:
-	asand:
-		if(l->op == OBIT)
-			goto asbitop;
-		if(typefd[n->type->etype]||typefd[r->type->etype])
-			goto asfop;
-		if(l->complex >= r->complex) {
-			if(hardleft)
-				reglcgen(&nod, l, Z);
-			else
-				nod = *l;
-			if(r->op != OCONST) {
-				regalloc(&nod1, r, nn);
-				cgen(r, &nod1);
-				gopcode(o, l->type, &nod1, &nod);
-				regfree(&nod1);
-			} else
-				gopcode(o, l->type, r, &nod);
-		} else {
-			regalloc(&nod1, r, nn);
-			cgen(r, &nod1);
-			if(hardleft)
-				reglcgen(&nod, l, Z);
-			else
-				nod = *l;
-			gopcode(o, l->type, &nod1, &nod);
-			regfree(&nod1);
-		}
-		if(nn != Z)
-			gmove(&nod, nn);
-		if(hardleft)
-			regfree(&nod);
-		break;
-
-	case OASLMUL:
-	case OASLDIV:
-	case OASLMOD:
-	case OASMUL:
-	case OASDIV:
-	case OASMOD:
-		if(l->op == OBIT)
-			goto asbitop;
-		if(typefd[n->type->etype]||typefd[r->type->etype])
-			goto asfop;
-		if(r->op == OCONST) {
-			SET(v);
-			switch(o) {
-			case OASDIV:
-			case OASMOD:
-				c = r->vconst;
-				if(c < 0)
-					c = -c;
-				v = xlog2(c);
-				if(v < 0)
-					break;
-				/* fall thru */
-			case OASMUL:
-			case OASLMUL:
-				if(hardleft)
-					reglcgen(&nod2, l, Z);
-				else
-					nod2 = *l;
-				regalloc(&nod, l, nn);
-				cgen(&nod2, &nod);
-				switch(o) {
-				case OASMUL:
-				case OASLMUL:
-					mulgen(n->type, r, &nod);
-					break;
-				case OASDIV:
-					sdiv2(r->vconst, v, l, &nod);
-					break;
-				case OASMOD:
-					smod2(r->vconst, v, l, &nod);
-					break;
-				}
-			havev:
-				gmove(&nod, &nod2);
-				if(nn != Z)
-					gmove(&nod, nn);
-				if(hardleft)
-					regfree(&nod2);
-				regfree(&nod);
-				goto done;
-			case OASLDIV:
-				c = r->vconst;
-				if((c & 0x80000000) == 0)
-					break;
-				if(hardleft)
-					reglcgen(&nod2, l, Z);
-				else
-					nod2 = *l;
-				regalloc(&nod1, l, nn);
-				cgen(&nod2, &nod1);
-				regalloc(&nod, l, nn);
-				zeroregm(&nod);
-				gins(ACMPL, &nod1, nodconst(c));
-				gins(ASBBL, nodconst(-1), &nod);
-				regfree(&nod1);
-				goto havev;
-			}
-		}
-
-		if(o == OASMUL) {
-			/* should favour AX */
-			regalloc(&nod, l, nn);
-			if(r->complex >= FNX) {
-				regalloc(&nod1, r, Z);
-				cgen(r, &nod1);
-				r = &nod1;
-			}
-			if(hardleft)
-				reglcgen(&nod2, l, Z);
-			else
-				nod2 = *l;
-			cgen(&nod2, &nod);
-			if(r->addable < INDEXED) {
-				if(r->complex < FNX) {
-					regalloc(&nod1, r, Z);
-					cgen(r, &nod1);
-				}
-				gopcode(OASMUL, n->type, &nod1, &nod);
-				regfree(&nod1);
-			}
-			else
-				gopcode(OASMUL, n->type, r, &nod);
-			if(r == &nod1)
-				regfree(r);
-			gmove(&nod, &nod2);
-			if(nn != Z)
-				gmove(&nod, nn);
-			regfree(&nod);
-			if(hardleft)
-				regfree(&nod2);
-			break;
-		}
-
-		/*
-		 * get nod to be D_AX
-		 * get nod1 to be D_DX
-		 */
-		if(nodreg(&nod, nn, D_AX)) {
-			regsalloc(&nod2, n);
-			gmove(&nod, &nod2);
-			v = reg[D_AX];
-			reg[D_AX] = 0;
-
-			if(isreg(l, D_AX)) {
-				nod3 = *n;
-				nod3.left = &nod2;
-				cgen(&nod3, nn);
-			} else
-			if(isreg(r, D_AX)) {
-				nod3 = *n;
-				nod3.right = &nod2;
-				cgen(&nod3, nn);
-			} else
-				cgen(n, nn);
-
-			gmove(&nod2, &nod);
-			reg[D_AX] = v;
-			break;
-		}
-		if(nodreg(&nod1, nn, D_DX)) {
-			regsalloc(&nod2, n);
-			gmove(&nod1, &nod2);
-			v = reg[D_DX];
-			reg[D_DX] = 0;
-
-			if(isreg(l, D_DX)) {
-				nod3 = *n;
-				nod3.left = &nod2;
-				cgen(&nod3, nn);
-			} else
-			if(isreg(r, D_DX)) {
-				nod3 = *n;
-				nod3.right = &nod2;
-				cgen(&nod3, nn);
-			} else
-				cgen(n, nn);
-
-			gmove(&nod2, &nod1);
-			reg[D_DX] = v;
-			break;
-		}
-		reg[D_AX]++;
-		reg[D_DX]++;
-
-		if(l->complex >= r->complex) {
-			if(hardleft)
-				reglcgen(&nod2, l, Z);
-			else
-				nod2 = *l;
-			cgen(&nod2, &nod);
-			if(r->op == OCONST) {
-				switch(o) {
-				case OASDIV:
-					sdivgen(&nod2, r, &nod, &nod1);
-					goto divdone;
-				case OASLDIV:
-					udivgen(&nod2, r, &nod, &nod1);
-				divdone:
-					gmove(&nod1, &nod2);
-					if(nn != Z)
-						gmove(&nod1, nn);
-					goto freelxaxdx;
-				}
-			}
-			if(o == OASDIV || o == OASMOD)
-				gins(ACDQ, Z, Z);
-			if(o == OASLDIV || o == OASLMOD)
-				zeroregm(&nod1);
-			if(r->addable < INDEXED || r->op == OCONST ||
-			   !typeil[r->type->etype]) {
-				regalloc(&nod3, r, Z);
-				cgen(r, &nod3);
-				gopcode(o, l->type, &nod3, Z);
-				regfree(&nod3);
-			} else
-				gopcode(o, n->type, r, Z);
-		} else {
-			regalloc(&nod3, r, Z);
-			cgen(r, &nod3);
-			if(hardleft)
-				reglcgen(&nod2, l, Z);
-			else
-				nod2 = *l;
-			cgen(&nod2, &nod);
-			if(o == OASDIV || o == OASMOD)
-				gins(ACDQ, Z, Z);
-			if(o == OASLDIV || o == OASLMOD)
-				zeroregm(&nod1);
-			gopcode(o, l->type, &nod3, Z);
-			regfree(&nod3);
-		}
-		if(o == OASMOD || o == OASLMOD) {
-			gmove(&nod1, &nod2);
-			if(nn != Z)
-				gmove(&nod1, nn);
-		} else {
-			gmove(&nod, &nod2);
-			if(nn != Z)
-				gmove(&nod, nn);
-		}
-	freelxaxdx:
-		if(hardleft)
-			regfree(&nod2);
-		regfree(&nod);
-		regfree(&nod1);
-		break;
-
-	fop:
-		if(l->complex >= r->complex) {
-			cgen(l, &fregnode0);
-			if(r->addable < INDEXED) {
-				cgen(r, &fregnode0);
-				fgopcode(o, &fregnode0, &fregnode1, 1, 0);
-			} else
-				fgopcode(o, r, &fregnode0, 0, 0);
-		} else {
-			cgen(r, &fregnode0);
-			if(l->addable < INDEXED) {
-				cgen(l, &fregnode0);
-				fgopcode(o, &fregnode0, &fregnode1, 1, 1);
-			} else
-				fgopcode(o, l, &fregnode0, 0, 1);
-		}
-		gmove(&fregnode0, nn);
-		break;
-
-	asfop:
-		if(l->complex >= r->complex) {
-			if(hardleft)
-				reglcgen(&nod, l, Z);
-			else
-				nod = *l;
-			cgen(r, &fregnode0);
-		} else {
-			cgen(r, &fregnode0);
-			if(hardleft)
-				reglcgen(&nod, l, Z);
-			else
-				nod = *l;
-		}
-		if(!typefd[l->type->etype]) {
-			gmove(&nod, &fregnode0);
-			fgopcode(o, &fregnode0, &fregnode1, 1, 1);
-		} else
-			fgopcode(o, &nod, &fregnode0, 0, 1);
-		if(nn != Z)
-			gins(AFMOVD, &fregnode0, &fregnode0);
-		gmove(&fregnode0, &nod);
-		if(nn != Z)
-			gmove(&fregnode0, nn);
-		if(hardleft)
-			regfree(&nod);
-		break;
-
-	asbitop:
-		regalloc(&nod4, n, nn);
-		if(l->complex >= r->complex) {
-			bitload(l, &nod, &nod1, &nod2, &nod4);
-			regalloc(&nod3, r, Z);
-			cgen(r, &nod3);
-		} else {
-			regalloc(&nod3, r, Z);
-			cgen(r, &nod3);
-			bitload(l, &nod, &nod1, &nod2, &nod4);
-		}
-		gmove(&nod, &nod4);
-
-		if(typefd[nod3.type->etype])
-			fgopcode(o, &fregnode0, &fregnode1, 1, 1);
-		else {
-			Node onod;
-
-			/* incredible grot ... */
-			onod = nod3;
-			onod.op = o;
-			onod.complex = 2;
-			onod.addable = 0;
-			onod.type = tfield;
-			onod.left = &nod4;
-			onod.right = &nod3;
-			cgen(&onod, Z);
-		}
-		regfree(&nod3);
-		gmove(&nod4, &nod);
-		regfree(&nod4);
-		bitstore(l, &nod, &nod1, &nod2, nn);
-		break;
-
-	case OADDR:
-		if(nn == Z) {
-			nullwarn(l, Z);
-			break;
-		}
-		lcgen(l, nn);
-		break;
-
-	case OFUNC:
-		if(l->complex >= FNX) {
-			if(l->op != OIND)
-				diag(n, "bad function call");
-
-			regret(&nod, l->left, 0, 0);
-			cgen(l->left, &nod);
-			regsalloc(&nod1, l->left);
-			gmove(&nod, &nod1);
-			regfree(&nod);
-
-			nod = *n;
-			nod.left = &nod2;
-			nod2 = *l;
-			nod2.left = &nod1;
-			nod2.complex = 1;
-			cgen(&nod, nn);
-
-			return;
-		}
-		gargs(r, &nod, &nod1);
-		if(l->addable < INDEXED) {
-			reglcgen(&nod, l, nn);
-			nod.op = OREGISTER;
-			gopcode(OFUNC, n->type, Z, &nod);
-			regfree(&nod);
-		} else
-			gopcode(OFUNC, n->type, Z, l);
-		if(REGARG >= 0 && reg[REGARG])
-			reg[REGARG]--;
-		regret(&nod, n, l->type, 1); // update maxarg if nothing else
-		if(nn != Z)
-			gmove(&nod, nn);
-		if(nod.op == OREGISTER)
-			regfree(&nod);
-		if(nn == Z && hasdotdotdot(l->type) && typefd[n->type->etype])
-			gins(AFMOVDP, &fregnode0, &fregnode0);
-		break;
-
-	case OIND:
-		if(nn == Z) {
-			nullwarn(l, Z);
-			break;
-		}
-		regialloc(&nod, n, nn);
-		r = l;
-		while(r->op == OADD)
-			r = r->right;
-		if(sconst(r)) {
-			v = r->vconst;
-			r->vconst = 0;
-			cgen(l, &nod);
-			nod.xoffset += v;
-			r->vconst = v;
-		} else
-			cgen(l, &nod);
-		regind(&nod, n);
-		gmove(&nod, nn);
-		regfree(&nod);
-		break;
-
-	case OEQ:
-	case ONE:
-	case OLE:
-	case OLT:
-	case OGE:
-	case OGT:
-	case OLO:
-	case OLS:
-	case OHI:
-	case OHS:
-		if(nn == Z) {
-			nullwarn(l, r);
-			break;
-		}
-		boolgen(n, 1, nn);
-		break;
-
-	case OANDAND:
-	case OOROR:
-		boolgen(n, 1, nn);
-		if(nn == Z)
-			patch(p, pc);
-		break;
-
-	case ONOT:
-		if(nn == Z) {
-			nullwarn(l, Z);
-			break;
-		}
-		boolgen(n, 1, nn);
-		break;
-
-	case OCOMMA:
-		cgen(l, Z);
-		cgen(r, nn);
-		break;
-
-	case OCAST:
-		if(nn == Z) {
-			nullwarn(l, Z);
-			break;
-		}
-		/*
-		 * convert from types l->n->nn
-		 */
-		if(nocast(l->type, n->type) && nocast(n->type, nn->type)) {
-			/* both null, gen l->nn */
-			cgen(l, nn);
-			break;
-		}
-		if(typev[l->type->etype]) {
-			cgen64(n, nn);
-			break;
-		}
-		regalloc(&nod, l, nn);
-		cgen(l, &nod);
-		regalloc(&nod1, n, &nod);
-		gmove(&nod, &nod1);
-		gmove(&nod1, nn);
-		regfree(&nod1);
-		regfree(&nod);
-		break;
-
-	case ODOT:
-		sugen(l, nodrat, l->type->width);
-		if(nn == Z)
-			break;
-		warn(n, "non-interruptable temporary");
-		nod = *nodrat;
-		if(!r || r->op != OCONST) {
-			diag(n, "DOT and no offset");
-			break;
-		}
-		nod.xoffset += (int32)r->vconst;
-		nod.type = n->type;
-		cgen(&nod, nn);
-		break;
-
-	case OCOND:
-		bcgen(l, 1);
-		p1 = p;
-		cgen(r->left, nn);
-		gbranch(OGOTO);
-		patch(p1, pc);
-		p1 = p;
-		cgen(r->right, nn);
-		patch(p1, pc);
-		break;
-
-	case OPOSTINC:
-	case OPOSTDEC:
-		v = 1;
-		if(l->type->etype == TIND)
-			v = l->type->link->width;
-		if(o == OPOSTDEC)
-			v = -v;
-		if(l->op == OBIT)
-			goto bitinc;
-		if(nn == Z)
-			goto pre;
-
-		if(hardleft)
-			reglcgen(&nod, l, Z);
-		else
-			nod = *l;
-
-		if(typefd[n->type->etype])
-			goto fltinc;
-		gmove(&nod, nn);
-		gopcode(OADD, n->type, nodconst(v), &nod);
-		if(hardleft)
-			regfree(&nod);
-		break;
-
-	case OPREINC:
-	case OPREDEC:
-		v = 1;
-		if(l->type->etype == TIND)
-			v = l->type->link->width;
-		if(o == OPREDEC)
-			v = -v;
-		if(l->op == OBIT)
-			goto bitinc;
-
-	pre:
-		if(hardleft)
-			reglcgen(&nod, l, Z);
-		else
-			nod = *l;
-		if(typefd[n->type->etype])
-			goto fltinc;
-		gopcode(OADD, n->type, nodconst(v), &nod);
-		if(nn != Z)
-			gmove(&nod, nn);
-		if(hardleft)
-			regfree(&nod);
-		break;
-
-	fltinc:
-		gmove(&nod, &fregnode0);
-		if(nn != Z && (o == OPOSTINC || o == OPOSTDEC))
-			gins(AFMOVD, &fregnode0, &fregnode0);
-		gins(AFLD1, Z, Z);
-		if(v < 0)
-			fgopcode(OSUB, &fregnode0, &fregnode1, 1, 0);
-		else
-			fgopcode(OADD, &fregnode0, &fregnode1, 1, 0);
-		if(nn != Z && (o == OPREINC || o == OPREDEC))
-			gins(AFMOVD, &fregnode0, &fregnode0);
-		gmove(&fregnode0, &nod);
-		if(hardleft)
-			regfree(&nod);
-		break;
-
-	bitinc:
-		if(nn != Z && (o == OPOSTINC || o == OPOSTDEC)) {
-			bitload(l, &nod, &nod1, &nod2, Z);
-			gmove(&nod, nn);
-			gopcode(OADD, tfield, nodconst(v), &nod);
-			bitstore(l, &nod, &nod1, &nod2, Z);
-			break;
-		}
-		bitload(l, &nod, &nod1, &nod2, nn);
-		gopcode(OADD, tfield, nodconst(v), &nod);
-		bitstore(l, &nod, &nod1, &nod2, nn);
-		break;
-	}
-done:
-	cursafe = curs;
-}
-
-void
-reglcgen(Node *t, Node *n, Node *nn)
-{
-	Node *r;
-	int32 v;
-
-	regialloc(t, n, nn);
-	if(n->op == OIND) {
-		r = n->left;
-		while(r->op == OADD)
-			r = r->right;
-		if(sconst(r)) {
-			v = r->vconst;
-			r->vconst = 0;
-			lcgen(n, t);
-			t->xoffset += v;
-			r->vconst = v;
-			regind(t, n);
-			return;
-		}
-	}
-	lcgen(n, t);
-	regind(t, n);
-}
-
-void
-lcgen(Node *n, Node *nn)
-{
-	Prog *p1;
-	Node nod;
-
-	if(debug['g']) {
-		prtree(nn, "lcgen lhs");
-		prtree(n, "lcgen");
-	}
-	if(n == Z || n->type == T)
-		return;
-	if(nn == Z) {
-		nn = &nod;
-		regalloc(&nod, n, Z);
-	}
-	switch(n->op) {
-	default:
-		if(n->addable < INDEXED) {
-			diag(n, "unknown op in lcgen: %O", n->op);
-			break;
-		}
-		gopcode(OADDR, n->type, n, nn);
-		break;
-
-	case OCOMMA:
-		cgen(n->left, n->left);
-		lcgen(n->right, nn);
-		break;
-
-	case OIND:
-		cgen(n->left, nn);
-		break;
-
-	case OCOND:
-		bcgen(n->left, 1);
-		p1 = p;
-		lcgen(n->right->left, nn);
-		gbranch(OGOTO);
-		patch(p1, pc);
-		p1 = p;
-		lcgen(n->right->right, nn);
-		patch(p1, pc);
-		break;
-	}
-}
-
-void
-bcgen(Node *n, int true)
-{
-
-	if(n->type == T)
-		gbranch(OGOTO);
-	else
-		boolgen(n, true, Z);
-}
-
-void
-boolgen(Node *n, int true, Node *nn)
-{
-	int o;
-	Prog *p1, *p2, *p3;
-	Node *l, *r, nod, nod1;
-	int32 curs;
-
-	if(debug['g']) {
-		prtree(nn, "boolgen lhs");
-		prtree(n, "boolgen");
-	}
-	curs = cursafe;
-	l = n->left;
-	r = n->right;
-	switch(n->op) {
-
-	default:
-		if(typev[n->type->etype]) {
-			testv(n, true);
-			goto com;
-		}
-		o = ONE;
-		if(true)
-			o = OEQ;
-		if(typefd[n->type->etype]) {
-			if(n->addable < INDEXED) {
-				cgen(n, &fregnode0);
-				gins(AFLDZ, Z, Z);
-				fgopcode(o, &fregnode0, &fregnode1, 1, 1);
-			} else {
-				gins(AFLDZ, Z, Z);
-				fgopcode(o, n, &fregnode0, 0, 1);
-			}
-			goto com;
-		}
-		/* bad, 13 is address of external that becomes constant */
-		if(n->addable >= INDEXED && n->addable != 13) {
-			gopcode(o, n->type, n, nodconst(0));
-			goto com;
-		}
-		regalloc(&nod, n, nn);
-		cgen(n, &nod);
-		gopcode(o, n->type, &nod, nodconst(0));
-		regfree(&nod);
-		goto com;
-
-	case OCONST:
-		o = vconst(n);
-		if(!true)
-			o = !o;
-		gbranch(OGOTO);
-		if(o) {
-			p1 = p;
-			gbranch(OGOTO);
-			patch(p1, pc);
-		}
-		goto com;
-
-	case OCOMMA:
-		cgen(l, Z);
-		boolgen(r, true, nn);
-		break;
-
-	case ONOT:
-		boolgen(l, !true, nn);
-		break;
-
-	case OCOND:
-		bcgen(l, 1);
-		p1 = p;
-		bcgen(r->left, true);
-		p2 = p;
-		gbranch(OGOTO);
-		patch(p1, pc);
-		p1 = p;
-		bcgen(r->right, !true);
-		patch(p2, pc);
-		p2 = p;
-		gbranch(OGOTO);
-		patch(p1, pc);
-		patch(p2, pc);
-		goto com;
-
-	case OANDAND:
-		if(!true)
-			goto caseor;
-
-	caseand:
-		bcgen(l, true);
-		p1 = p;
-		bcgen(r, !true);
-		p2 = p;
-		patch(p1, pc);
-		gbranch(OGOTO);
-		patch(p2, pc);
-		goto com;
-
-	case OOROR:
-		if(!true)
-			goto caseand;
-
-	caseor:
-		bcgen(l, !true);
-		p1 = p;
-		bcgen(r, !true);
-		p2 = p;
-		gbranch(OGOTO);
-		patch(p1, pc);
-		patch(p2, pc);
-		goto com;
-
-	case OEQ:
-	case ONE:
-	case OLE:
-	case OLT:
-	case OGE:
-	case OGT:
-	case OHI:
-	case OHS:
-	case OLO:
-	case OLS:
-		o = n->op;
-		if(typev[l->type->etype]) {
-			if(!true)
-				n->op = comrel[relindex(o)];
-			cgen64(n, Z);
-			goto com;
-		}
-		if(true && typefd[l->type->etype] && (o == OEQ || o == ONE)) {
-			// Cannot rewrite !(l == r) into l != r with float64; it breaks NaNs.
-			// Jump around instead.
-			boolgen(n, 0, Z);
-			p1 = p;
-			gbranch(OGOTO);
-			patch(p1, pc);
-			goto com;
-		}
-		if(true)
-			o = comrel[relindex(o)];
-		if(l->complex >= FNX && r->complex >= FNX) {
-			regret(&nod, r, 0, 0);
-			cgen(r, &nod);
-			regsalloc(&nod1, r);
-			gmove(&nod, &nod1);
-			regfree(&nod);
-			nod = *n;
-			nod.right = &nod1;
-			boolgen(&nod, true, nn);
-			break;
-		}
-		if(typefd[l->type->etype]) {
-			if(l->complex >= r->complex) {
-				cgen(l, &fregnode0);
-				if(r->addable < INDEXED) {
-					cgen(r, &fregnode0);
-					o = invrel[relindex(o)];
-					fgopcode(o, &fregnode0, &fregnode1, 1, 1);
-				} else
-					fgopcode(o, r, &fregnode0, 0, 1);
-			} else {
-				o = invrel[relindex(o)];
-				cgen(r, &fregnode0);
-				if(l->addable < INDEXED) {
-					cgen(l, &fregnode0);
-					o = invrel[relindex(o)];
-					fgopcode(o, &fregnode0, &fregnode1, 1, 1);
-				} else
-					fgopcode(o, l, &fregnode0, 0, 1);
-			}
-			switch(o) {
-			case OEQ:
-				// Already emitted AJEQ; want AJEQ and AJPC.
-				p1 = p;
-				gbranch(OGOTO);
-				p2 = p;
-				patch(p1, pc);
-				gins(AJPC, Z, Z);
-				patch(p2, pc);
-				break;
-
-			case ONE:
-				// Already emitted AJNE; want AJNE or AJPS.
-				p1 = p;
-				gins(AJPS, Z, Z);
-				p2 = p;
-				gbranch(OGOTO);
-				p3 = p;
-				patch(p1, pc);
-				patch(p2, pc);
-				gbranch(OGOTO);
-				patch(p3, pc);
-				break;
-			}
-			goto com;
-		}
-		if(l->op == OCONST) {
-			o = invrel[relindex(o)];
-			/* bad, 13 is address of external that becomes constant */
-			if(r->addable < INDEXED || r->addable == 13) {
-				regalloc(&nod, r, nn);
-				cgen(r, &nod);
-				gopcode(o, l->type, &nod, l);
-				regfree(&nod);
-			} else
-				gopcode(o, l->type, r, l);
-			goto com;
-		}
-		if(l->complex >= r->complex) {
-			regalloc(&nod, l, nn);
-			cgen(l, &nod);
-			if(r->addable < INDEXED) {
-				regalloc(&nod1, r, Z);
-				cgen(r, &nod1);
-				gopcode(o, l->type, &nod, &nod1);
-				regfree(&nod1);
-			} else
-				gopcode(o, l->type, &nod, r);
-			regfree(&nod);
-			goto com;
-		}
-		regalloc(&nod, r, nn);
-		cgen(r, &nod);
-		if(l->addable < INDEXED || l->addable == 13) {
-			regalloc(&nod1, l, Z);
-			cgen(l, &nod1);
-			if(typechlp[l->type->etype])
-				gopcode(o, types[TINT], &nod1, &nod);
-			else
-				gopcode(o, l->type, &nod1, &nod);
-			regfree(&nod1);
-		} else
-			gopcode(o, l->type, l, &nod);
-		regfree(&nod);
-
-	com:
-		if(nn != Z) {
-			p1 = p;
-			gmove(nodconst(1L), nn);
-			gbranch(OGOTO);
-			p2 = p;
-			patch(p1, pc);
-			gmove(nodconst(0L), nn);
-			patch(p2, pc);
-		}
-		break;
-	}
-	cursafe = curs;
-}
-
-void
-sugen(Node *n, Node *nn, int32 w)
-{
-	Prog *p1;
-	Node nod0, nod1, nod2, nod3, nod4, *h, *l, *r;
-	Type *t;
-	int c, v, x;
-
-	if(n == Z || n->type == T)
-		return;
-	if(debug['g']) {
-		prtree(nn, "sugen lhs");
-		prtree(n, "sugen");
-	}
-	if(nn == nodrat)
-		if(w > nrathole)
-			nrathole = w;
-	switch(n->op) {
-	case OIND:
-		if(nn == Z) {
-			nullwarn(n->left, Z);
-			break;
-		}
-
-	default:
-		goto copy;
-
-	case OCONST:
-		if(n->type && typev[n->type->etype]) {
-			if(nn == Z) {
-				nullwarn(n->left, Z);
-				break;
-			}
-
-			if(nn->op == OREGPAIR) {
-				loadpair(n, nn);
-				break;
-			}
-			else if(!vaddr(nn, 0)) {
-				t = nn->type;
-				nn->type = types[TLONG];
-				reglcgen(&nod1, nn, Z);
-				nn->type = t;
-
-				gmove(lo64(n), &nod1);
-				nod1.xoffset += SZ_LONG;
-				gmove(hi64(n), &nod1);
-				regfree(&nod1);
-			}
-			else {
-				gins(AMOVL, lo64(n), nn);
-				nn->xoffset += SZ_LONG;
-				gins(AMOVL, hi64(n), nn);
-				nn->xoffset -= SZ_LONG;
-				break;
-			}
-			break;
-		}
-		goto copy;
-
-	case ODOT:
-		l = n->left;
-		sugen(l, nodrat, l->type->width);
-		if(nn == Z)
-			break;
-		warn(n, "non-interruptable temporary");
-		nod1 = *nodrat;
-		r = n->right;
-		if(!r || r->op != OCONST) {
-			diag(n, "DOT and no offset");
-			break;
-		}
-		nod1.xoffset += (int32)r->vconst;
-		nod1.type = n->type;
-		sugen(&nod1, nn, w);
-		break;
-
-	case OSTRUCT:
-		/*
-		 * rewrite so lhs has no fn call
-		 */
-		if(nn != Z && side(nn)) {
-			nod1 = *n;
-			nod1.type = typ(TIND, n->type);
-			regret(&nod2, &nod1, 0, 0);
-			lcgen(nn, &nod2);
-			regsalloc(&nod0, &nod1);
-			cgen(&nod2, &nod0);
-			regfree(&nod2);
-
-			nod1 = *n;
-			nod1.op = OIND;
-			nod1.left = &nod0;
-			nod1.right = Z;
-			nod1.complex = 1;
-
-			sugen(n, &nod1, w);
-			return;
-		}
-
-		r = n->left;
-		for(t = n->type->link; t != T; t = t->down) {
-			l = r;
-			if(r->op == OLIST) {
-				l = r->left;
-				r = r->right;
-			}
-			if(nn == Z) {
-				cgen(l, nn);
-				continue;
-			}
-			/*
-			 * hand craft *(&nn + o) = l
-			 */
-			nod0 = znode;
-			nod0.op = OAS;
-			nod0.type = t;
-			nod0.left = &nod1;
-			nod0.right = nil;
-
-			nod1 = znode;
-			nod1.op = OIND;
-			nod1.type = t;
-			nod1.left = &nod2;
-
-			nod2 = znode;
-			nod2.op = OADD;
-			nod2.type = typ(TIND, t);
-			nod2.left = &nod3;
-			nod2.right = &nod4;
-
-			nod3 = znode;
-			nod3.op = OADDR;
-			nod3.type = nod2.type;
-			nod3.left = nn;
-
-			nod4 = znode;
-			nod4.op = OCONST;
-			nod4.type = nod2.type;
-			nod4.vconst = t->offset;
-
-			ccom(&nod0);
-			acom(&nod0);
-			xcom(&nod0);
-			nod0.addable = 0;
-			nod0.right = l;
-
-			// prtree(&nod0, "hand craft");
-			cgen(&nod0, Z);
-		}
-		break;
-
-	case OAS:
-		if(nn == Z) {
-			if(n->addable < INDEXED)
-				sugen(n->right, n->left, w);
-			break;
-		}
-
-		sugen(n->right, nodrat, w);
-		warn(n, "non-interruptable temporary");
-		sugen(nodrat, n->left, w);
-		sugen(nodrat, nn, w);
-		break;
-
-	case OFUNC:
-		if(!hasdotdotdot(n->left->type)) {
-			cgen(n, Z);
-			if(nn != Z) {
-				curarg -= n->type->width;
-				regret(&nod1, n, n->left->type, 1);
-				if(nn->complex >= FNX) {
-					regsalloc(&nod2, n);
-					cgen(&nod1, &nod2);
-					nod1 = nod2;
-				}
-				cgen(&nod1, nn);
-			}
-			break;
-		}
-		if(nn == Z) {
-			sugen(n, nodrat, w);
-			break;
-		}
-		h = nn;
-		if(nn->op == OREGPAIR) {
-			regsalloc(&nod1, nn);
-			nn = &nod1;
-		}
-		if(nn->op != OIND) {
-			nn = new1(OADDR, nn, Z);
-			nn->type = types[TIND];
-			nn->addable = 0;
-		} else
-			nn = nn->left;
-		n = new(OFUNC, n->left, new(OLIST, nn, n->right));
-		n->type = types[TVOID];
-		n->left->type = types[TVOID];
-		cgen(n, Z);
-		if(h->op == OREGPAIR)
-			loadpair(nn->left, h);
-		break;
-
-	case OCOND:
-		bcgen(n->left, 1);
-		p1 = p;
-		sugen(n->right->left, nn, w);
-		gbranch(OGOTO);
-		patch(p1, pc);
-		p1 = p;
-		sugen(n->right->right, nn, w);
-		patch(p1, pc);
-		break;
-
-	case OCOMMA:
-		cgen(n->left, Z);
-		sugen(n->right, nn, w);
-		break;
-	}
-	return;
-
-copy:
-	if(nn == Z) {
-		switch(n->op) {
-		case OASADD:
-		case OASSUB:
-		case OASAND:
-		case OASOR:
-		case OASXOR:
-
-		case OASMUL:
-		case OASLMUL:
-
-
-		case OASASHL:
-		case OASASHR:
-		case OASLSHR:
-			break;
-
-		case OPOSTINC:
-		case OPOSTDEC:
-		case OPREINC:
-		case OPREDEC:
-			break;
-
-		default:
-			return;
-		}
-	}
-
-	v = w == 8;
-	if(n->complex >= FNX && nn != nil && nn->complex >= FNX) {
-		t = nn->type;
-		nn->type = types[TLONG];
-		regialloc(&nod1, nn, Z);
-		lcgen(nn, &nod1);
-		regsalloc(&nod2, nn);
-		nn->type = t;
-
-		gins(AMOVL, &nod1, &nod2);
-		regfree(&nod1);
-
-		nod2.type = typ(TIND, t);
-
-		nod1 = nod2;
-		nod1.op = OIND;
-		nod1.left = &nod2;
-		nod1.right = Z;
-		nod1.complex = 1;
-		nod1.type = t;
-
-		sugen(n, &nod1, w);
-		return;
-	}
-
-	x = 0;
-	if(v) {
-		if(nn != nil && nn->complex >= FNX) {
-			t = nn->type;
-			nn->type = types[TLONG];
-			regialloc(&nod2, nn, Z);
-			lcgen(nn, &nod2);
-			nn->type = t;
-			
-			nod2.type = typ(TIND, t);
-	
-			nod1 = nod2;
-			nod1.op = OIND;
-			nod1.left = &nod2;
-			nod1.right = Z;
-			nod1.complex = 1;
-			nod1.type = t;
-	
-			sugen(n, &nod1, w);
-			regfree(&nod2);
-			return;
-		}
-			
-		c = cursafe;
-		if(n->left != Z && n->left->complex >= FNX
-		&& n->right != Z && n->right->complex >= FNX) {
-//			warn(n, "toughie");
-			regsalloc(&nod1, n->right);
-			cgen(n->right, &nod1);
-			nod2 = *n;
-			nod2.right = &nod1;
-			cgen(&nod2, nn);
-			cursafe = c;
-			return;
-		}
-		if(cgen64(n, nn)) {
-			cursafe = c;
-			return;
-		}
-		if(n->op == OCOM) {
-			n = n->left;
-			x = 1;
-		}
-	}
-
-	/* botch, need to save in .safe */
-	c = 0;
-	if(n->complex > nn->complex) {
-		t = n->type;
-		n->type = types[TLONG];
-		if(v) {
-			regalloc(&nod0, n, Z);
-			if(!vaddr(n, 0)) {
-				reglcgen(&nod1, n, Z);
-				n->type = t;
-				n = &nod1;
-			}
-			else
-				n->type = t;
-		}
-		else {
-			nodreg(&nod1, n, D_SI);
-			if(reg[D_SI]) {
-				gins(APUSHL, &nod1, Z);
-				c |= 1;
-				reg[D_SI]++;
-			}
-			lcgen(n, &nod1);
-			n->type = t;
-		}
-
-		t = nn->type;
-		nn->type = types[TLONG];
-		if(v) {
-			if(!vaddr(nn, 0)) {
-				reglcgen(&nod2, nn, Z);
-				nn->type = t;
-				nn = &nod2;
-			}
-			else
-				nn->type = t;
-		}
-		else {
-			nodreg(&nod2, nn, D_DI);
-			if(reg[D_DI]) {
-				gins(APUSHL, &nod2, Z);
-				c |= 2;
-				reg[D_DI]++;
-			}
-			lcgen(nn, &nod2);
-			nn->type = t;
-		}
-	} else {
-		t = nn->type;
-		nn->type = types[TLONG];
-		if(v) {
-			regalloc(&nod0, nn, Z);
-			if(!vaddr(nn, 0)) {
-				reglcgen(&nod2, nn, Z);
-				nn->type = t;
-				nn = &nod2;
-			}
-			else
-				nn->type = t;
-		}
-		else {
-			nodreg(&nod2, nn, D_DI);
-			if(reg[D_DI]) {
-				gins(APUSHL, &nod2, Z);
-				c |= 2;
-				reg[D_DI]++;
-			}
-			lcgen(nn, &nod2);
-			nn->type = t;
-		}
-
-		t = n->type;
-		n->type = types[TLONG];
-		if(v) {
-			if(!vaddr(n, 0)) {
-				reglcgen(&nod1, n, Z);
-				n->type = t;
-				n = &nod1;
-			}
-			else
-				n->type = t;
-		}
-		else {
-			nodreg(&nod1, n, D_SI);
-			if(reg[D_SI]) {
-				gins(APUSHL, &nod1, Z);
-				c |= 1;
-				reg[D_SI]++;
-			}
-			lcgen(n, &nod1);
-			n->type = t;
-		}
-	}
-	if(v) {
-		gins(AMOVL, n, &nod0);
-		if(x)
-			gins(ANOTL, Z, &nod0);
-		gins(AMOVL, &nod0, nn);
-		n->xoffset += SZ_LONG;
-		nn->xoffset += SZ_LONG;
-		gins(AMOVL, n, &nod0);
-		if(x)
-			gins(ANOTL, Z, &nod0);
-		gins(AMOVL, &nod0, nn);
-		n->xoffset -= SZ_LONG;
-		nn->xoffset -= SZ_LONG;
-		if(nn == &nod2)
-			regfree(&nod2);
-		if(n == &nod1)
-			regfree(&nod1);
-		regfree(&nod0);
-		return;
-	}
-	nodreg(&nod3, n, D_CX);
-	if(reg[D_CX]) {
-		gins(APUSHL, &nod3, Z);
-		c |= 4;
-		reg[D_CX]++;
-	}
-	gins(AMOVL, nodconst(w/SZ_LONG), &nod3);
-	gins(ACLD, Z, Z);
-	gins(AREP, Z, Z);
-	gins(AMOVSL, Z, Z);
-	if(c & 4) {
-		gins(APOPL, Z, &nod3);
-		reg[D_CX]--;
-	}
-	if(c & 2) {
-		gins(APOPL, Z, &nod2);
-		reg[nod2.reg]--;
-	}
-	if(c & 1) {
-		gins(APOPL, Z, &nod1);
-		reg[nod1.reg]--;
-	}
-}
diff --git a/src/cmd/8c/cgen64.c b/src/cmd/8c/cgen64.c
deleted file mode 100644
index 3424f76..0000000
--- a/src/cmd/8c/cgen64.c
+++ /dev/null
@@ -1,2657 +0,0 @@
-// Inferno utils/8c/cgen64.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8c/cgen64.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include "gc.h"
-
-void
-zeroregm(Node *n)
-{
-	gins(AMOVL, nodconst(0), n);
-}
-
-/* do we need to load the address of a vlong? */
-int
-vaddr(Node *n, int a)
-{
-	switch(n->op) {
-	case ONAME:
-		if(a)
-			return 1;
-		return !(n->class == CEXTERN || n->class == CGLOBL || n->class == CSTATIC);
-
-	case OCONST:
-	case OREGISTER:
-	case OINDREG:
-		return 1;
-	}
-	return 0;
-}
-
-int32
-hi64v(Node *n)
-{
-	if(align(0, types[TCHAR], Aarg1, nil))	/* isbigendian */
-		return (int32)(n->vconst) & ~0L;
-	else
-		return (int32)((uvlong)n->vconst>>32) & ~0L;
-}
-
-int32
-lo64v(Node *n)
-{
-	if(align(0, types[TCHAR], Aarg1, nil))	/* isbigendian */
-		return (int32)((uvlong)n->vconst>>32) & ~0L;
-	else
-		return (int32)(n->vconst) & ~0L;
-}
-
-Node *
-hi64(Node *n)
-{
-	return nodconst(hi64v(n));
-}
-
-Node *
-lo64(Node *n)
-{
-	return nodconst(lo64v(n));
-}
-
-static Node *
-anonreg(void)
-{
-	Node *n;
-
-	n = new(OREGISTER, Z, Z);
-	n->reg = D_NONE;
-	n->type = types[TLONG];
-	return n;
-}
-
-static Node *
-regpair(Node *n, Node *t)
-{
-	Node *r;
-
-	if(n != Z && n->op == OREGPAIR)
-		return n;
-	r = new(OREGPAIR, anonreg(), anonreg());
-	if(n != Z)
-		r->type = n->type;
-	else
-		r->type = t->type;
-	return r;
-}
-
-static void
-evacaxdx(Node *r)
-{
-	Node nod1, nod2;
-
-	if(r->reg == D_AX || r->reg == D_DX) {
-		reg[D_AX]++;
-		reg[D_DX]++;
-		/*
-		 * this is just an optim that should
-		 * check for spill
-		 */
-		r->type = types[TULONG];
-		regalloc(&nod1, r, Z);
-		nodreg(&nod2, Z, r->reg);
-		gins(AMOVL, &nod2, &nod1);
-		regfree(r);
-		r->reg = nod1.reg;
-		reg[D_AX]--;
-		reg[D_DX]--;
-	}
-}
-
-/* lazy instantiation of register pair */
-static int
-instpair(Node *n, Node *l)
-{
-	int r;
-
-	r = 0;
-	if(n->left->reg == D_NONE) {
-		if(l != Z) {
-			n->left->reg = l->reg;
-			r = 1;
-		}
-		else
-			regalloc(n->left, n->left, Z);
-	}
-	if(n->right->reg == D_NONE)
-		regalloc(n->right, n->right, Z);
-	return r;
-}
-
-static void
-zapreg(Node *n)
-{
-	if(n->reg != D_NONE) {
-		regfree(n);
-		n->reg = D_NONE;
-	}
-}
-
-static void
-freepair(Node *n)
-{
-	regfree(n->left);
-	regfree(n->right);
-}
-
-/* n is not OREGPAIR, nn is */
-void
-loadpair(Node *n, Node *nn)
-{
-	Node nod;
-
-	instpair(nn, Z);
-	if(n->op == OCONST) {
-		gins(AMOVL, lo64(n), nn->left);
-		n->xoffset += SZ_LONG;
-		gins(AMOVL, hi64(n), nn->right);
-		n->xoffset -= SZ_LONG;
-		return;
-	}
-	if(!vaddr(n, 0)) {
-		/* steal the right register for the laddr */
-		nod = regnode;
-		nod.reg = nn->right->reg;
-		lcgen(n, &nod);
-		n = &nod;
-		regind(n, n);
-		n->xoffset = 0;
-	}
-	gins(AMOVL, n, nn->left);
-	n->xoffset += SZ_LONG;
-	gins(AMOVL, n, nn->right);
-	n->xoffset -= SZ_LONG;
-}
-
-/* n is OREGPAIR, nn is not */
-static void
-storepair(Node *n, Node *nn, int f)
-{
-	Node nod;
-
-	if(!vaddr(nn, 0)) {
-		reglcgen(&nod, nn, Z);
-		nn = &nod;
-	}
-	gins(AMOVL, n->left, nn);
-	nn->xoffset += SZ_LONG;
-	gins(AMOVL, n->right, nn);
-	nn->xoffset -= SZ_LONG;
-	if(nn == &nod)
-		regfree(&nod);
-	if(f)
-		freepair(n);
-}
-
-enum
-{
-/* 4 only, see WW */
-	WNONE	= 0,
-	WCONST,
-	WADDR,
-	WHARD,
-};
-
-static int
-whatof(Node *n, int a)
-{
-	if(n->op == OCONST)
-		return WCONST;
-	return !vaddr(n, a) ? WHARD : WADDR;
-}
-
-/* can upgrade an extern to addr for AND */
-static int
-reduxv(Node *n)
-{
-	return lo64v(n) == 0 || hi64v(n) == 0;
-}
-
-int
-cond(int op)
-{
-	switch(op) {
-	case OANDAND:
-	case OOROR:
-	case ONOT:
-		return 1;
-
-	case OEQ:
-	case ONE:
-	case OLE:
-	case OLT:
-	case OGE:
-	case OGT:
-	case OHI:
-	case OHS:
-	case OLO:
-	case OLS:
-		return 1;
-	}
-	return 0;
-}
-
-/*
- * for a func operand call it and then return
- * the safe node
- */
-static Node *
-vfunc(Node *n, Node *nn)
-{
-	Node *t;
-
-	if(n->op != OFUNC)
-		return n;
-	t = new(0, Z, Z);
-	if(nn == Z || nn == nodret)
-		nn = n;
-	regsalloc(t, nn);
-	sugen(n, t, 8);
-	return t;
-}
-
-/* try to steal a reg */
-static int
-getreg(Node **np, Node *t, int r)
-{
-	Node *n, *p;
-
-	n = *np;
-	if(n->reg == r) {
-		p = new(0, Z, Z);
-		regalloc(p, n, Z);
-		gins(AMOVL, n, p);
-		*t = *n;
-		*np = p;
-		return 1;
-	}
-	return 0;
-}
-
-static Node *
-snarfreg(Node *n, Node *t, int r, Node *d, Node *c)
-{
-	if(n == Z || n->op != OREGPAIR || (!getreg(&n->left, t, r) && !getreg(&n->right, t, r))) {
-		if(nodreg(t, Z, r)) {
-			regalloc(c, d, Z);
-			gins(AMOVL, t, c);
-			reg[r]++;
-			return c;
-		}
-		reg[r]++;
-	}
-	return Z;
-}
-
-enum
-{
-	Vstart	= OEND,
-
-	Vgo,
-	Vamv,
-	Vmv,
-	Vzero,
-	Vop,
-	Vopx,
-	Vins,
-	Vins0,
-	Vinsl,
-	Vinsr,
-	Vinsla,
-	Vinsra,
-	Vinsx,
-	Vmul,
-	Vshll,
-	VT,
-	VF,
-	V_l_lo_f,
-	V_l_hi_f,
-	V_l_lo_t,
-	V_l_hi_t,
-	V_l_lo_u,
-	V_l_hi_u,
-	V_r_lo_f,
-	V_r_hi_f,
-	V_r_lo_t,
-	V_r_hi_t,
-	V_r_lo_u,
-	V_r_hi_u,
-	Vspazz,
-	Vend,
-
-	V_T0,
-	V_T1,
-	V_F0,
-	V_F1,
-
-	V_a0,
-	V_a1,
-	V_f0,
-	V_f1,
-
-	V_p0,
-	V_p1,
-	V_p2,
-	V_p3,
-	V_p4,
-
-	V_s0,
-	V_s1,
-	V_s2,
-	V_s3,
-	V_s4,
-
-	C00,
-	C01,
-	C31,
-	C32,
-
-	O_l_lo,
-	O_l_hi,
-	O_r_lo,
-	O_r_hi,
-	O_t_lo,
-	O_t_hi,
-	O_l,
-	O_r,
-	O_l_rp,
-	O_r_rp,
-	O_t_rp,
-	O_r0,
-	O_r1,
-	O_Zop,
-
-	O_a0,
-	O_a1,
-
-	V_C0,
-	V_C1,
-
-	V_S0,
-	V_S1,
-
-	VOPS	= 5,
-	VLEN	= 5,
-	VARGS	= 2,
-
-	S00	= 0,
-	Sc0,
-	Sc1,
-	Sc2,
-	Sac3,
-	Sac4,
-	S10,
-
-	SAgen	= 0,
-	SAclo,
-	SAc32,
-	SAchi,
-	SAdgen,
-	SAdclo,
-	SAdc32,
-	SAdchi,
-
-	B0c	= 0,
-	Bca,
-	Bac,
-
-	T0i	= 0,
-	Tii,
-
-	Bop0	= 0,
-	Bop1,
-};
-
-/*
- * _testv:
- * 	CMPL	lo,$0
- * 	JNE	true
- * 	CMPL	hi,$0
- * 	JNE	true
- * 	GOTO	false
- * false:
- * 	GOTO	code
- * true:
- * 	GOTO	patchme
- * code:
- */
-
-static uchar	testi[][VLEN] =
-{
-	{Vop, ONE, O_l_lo, C00},
-	{V_s0, Vop, ONE, O_l_hi, C00},
-	{V_s1, Vgo, V_s2, Vgo, V_s3},
-	{VF, V_p0, V_p1, VT, V_p2},
-	{Vgo, V_p3},
-	{VT, V_p0, V_p1, VF, V_p2},
-	{Vend},
-};
-
-/* shift left general case */
-static uchar	shll00[][VLEN] =
-{
-	{Vop, OGE, O_r, C32},
-	{V_s0, Vinsl, ASHLL, O_r, O_l_rp},
-	{Vins, ASHLL, O_r, O_l_lo, Vgo},
-	{V_p0, V_s0},
-	{Vins, ASHLL, O_r, O_l_lo},
-	{Vins, AMOVL, O_l_lo, O_l_hi},
-	{Vzero, O_l_lo, V_p0, Vend},
-};
-
-/* shift left rp, const < 32 */
-static uchar	shllc0[][VLEN] =
-{
-	{Vinsl, ASHLL, O_r, O_l_rp},
-	{Vshll, O_r, O_l_lo, Vend},
-};
-
-/* shift left rp, const == 32 */
-static uchar	shllc1[][VLEN] =
-{
-	{Vins, AMOVL, O_l_lo, O_l_hi},
-	{Vzero, O_l_lo, Vend},
-};
-
-/* shift left rp, const > 32 */
-static uchar	shllc2[][VLEN] =
-{
-	{Vshll, O_r, O_l_lo},
-	{Vins, AMOVL, O_l_lo, O_l_hi},
-	{Vzero, O_l_lo, Vend},
-};
-
-/* shift left addr, const == 32 */
-static uchar	shllac3[][VLEN] =
-{
-	{Vins, AMOVL, O_l_lo, O_t_hi},
-	{Vzero, O_t_lo, Vend},
-};
-
-/* shift left addr, const > 32 */
-static uchar	shllac4[][VLEN] =
-{
-	{Vins, AMOVL, O_l_lo, O_t_hi},
-	{Vshll, O_r, O_t_hi},
-	{Vzero, O_t_lo, Vend},
-};
-
-/* shift left of constant */
-static uchar	shll10[][VLEN] =
-{
-	{Vop, OGE, O_r, C32},
-	{V_s0, Vins, AMOVL, O_l_lo, O_t_lo},
-	{Vins, AMOVL, O_l_hi, O_t_hi},
-	{Vinsl, ASHLL, O_r, O_t_rp},
-	{Vins, ASHLL, O_r, O_t_lo, Vgo},
-	{V_p0, V_s0},
-	{Vins, AMOVL, O_l_lo, O_t_hi},
-	{V_l_lo_t, Vins, ASHLL, O_r, O_t_hi},
-	{Vzero, O_t_lo, V_p0, Vend},
-};
-
-static uchar	(*shlltab[])[VLEN] =
-{
-	shll00,
-	shllc0,
-	shllc1,
-	shllc2,
-	shllac3,
-	shllac4,
-	shll10,
-};
-
-/* shift right general case */
-static uchar	shrl00[][VLEN] =
-{
-	{Vop, OGE, O_r, C32},
-	{V_s0, Vinsr, ASHRL, O_r, O_l_rp},
-	{Vins, O_a0, O_r, O_l_hi, Vgo},
-	{V_p0, V_s0},
-	{Vins, O_a0, O_r, O_l_hi},
-	{Vins, AMOVL, O_l_hi, O_l_lo},
-	{V_T1, Vzero, O_l_hi},
-	{V_F1, Vins, ASARL, C31, O_l_hi},
-	{V_p0, Vend},
-};
-
-/* shift right rp, const < 32 */
-static uchar	shrlc0[][VLEN] =
-{
-	{Vinsr, ASHRL, O_r, O_l_rp},
-	{Vins, O_a0, O_r, O_l_hi, Vend},
-};
-
-/* shift right rp, const == 32 */
-static uchar	shrlc1[][VLEN] =
-{
-	{Vins, AMOVL, O_l_hi, O_l_lo},
-	{V_T1, Vzero, O_l_hi},
-	{V_F1, Vins, ASARL, C31, O_l_hi},
-	{Vend},
-};
-
-/* shift right rp, const > 32 */
-static uchar	shrlc2[][VLEN] =
-{
-	{Vins, O_a0, O_r, O_l_hi},
-	{Vins, AMOVL, O_l_hi, O_l_lo},
-	{V_T1, Vzero, O_l_hi},
-	{V_F1, Vins, ASARL, C31, O_l_hi},
-	{Vend},
-};
-
-/* shift right addr, const == 32 */
-static uchar	shrlac3[][VLEN] =
-{
-	{Vins, AMOVL, O_l_hi, O_t_lo},
-	{V_T1, Vzero, O_t_hi},
-	{V_F1, Vins, AMOVL, O_t_lo, O_t_hi},
-	{V_F1, Vins, ASARL, C31, O_t_hi},
-	{Vend},
-};
-
-/* shift right addr, const > 32 */
-static uchar	shrlac4[][VLEN] =
-{
-	{Vins, AMOVL, O_l_hi, O_t_lo},
-	{Vins, O_a0, O_r, O_t_lo},
-	{V_T1, Vzero, O_t_hi},
-	{V_F1, Vins, AMOVL, O_t_lo, O_t_hi},
-	{V_F1, Vins, ASARL, C31, O_t_hi},
-	{Vend},
-};
-
-/* shift right of constant */
-static uchar	shrl10[][VLEN] =
-{
-	{Vop, OGE, O_r, C32},
-	{V_s0, Vins, AMOVL, O_l_lo, O_t_lo},
-	{Vins, AMOVL, O_l_hi, O_t_hi},
-	{Vinsr, ASHRL, O_r, O_t_rp},
-	{Vins, O_a0, O_r, O_t_hi, Vgo},
-	{V_p0, V_s0},
-	{Vins, AMOVL, O_l_hi, O_t_lo},
-	{V_l_hi_t, Vins, O_a0, O_r, O_t_lo},
-	{V_l_hi_u, V_S1},
-	{V_T1, Vzero, O_t_hi, V_p0},
-	{V_F1, Vins, AMOVL, O_t_lo, O_t_hi},
-	{V_F1, Vins, ASARL, C31, O_t_hi},
-	{Vend},
-};
-
-static uchar	(*shrltab[])[VLEN] =
-{
-	shrl00,
-	shrlc0,
-	shrlc1,
-	shrlc2,
-	shrlac3,
-	shrlac4,
-	shrl10,
-};
-
-/* shift asop left general case */
-static uchar	asshllgen[][VLEN] =
-{
-	{V_a0, V_a1},
-	{Vop, OGE, O_r, C32},
-	{V_s0, Vins, AMOVL, O_l_lo, O_r0},
-	{Vins, AMOVL, O_l_hi, O_r1},
-	{Vinsla, ASHLL, O_r, O_r0},
-	{Vins, ASHLL, O_r, O_r0},
-	{Vins, AMOVL, O_r1, O_l_hi},
-	{Vins, AMOVL, O_r0, O_l_lo, Vgo},
-	{V_p0, V_s0},
-	{Vins, AMOVL, O_l_lo, O_r0},
-	{Vzero, O_l_lo},
-	{Vins, ASHLL, O_r, O_r0},
-	{Vins, AMOVL, O_r0, O_l_hi, V_p0},
-	{V_f0, V_f1, Vend},
-};
-
-/* shift asop left, const < 32 */
-static uchar	asshllclo[][VLEN] =
-{
-	{V_a0, V_a1},
-	{Vins, AMOVL, O_l_lo, O_r0},
-	{Vins, AMOVL, O_l_hi, O_r1},
-	{Vinsla, ASHLL, O_r, O_r0},
-	{Vshll, O_r, O_r0},
-	{Vins, AMOVL, O_r1, O_l_hi},
-	{Vins, AMOVL, O_r0, O_l_lo},
-	{V_f0, V_f1, Vend},
-};
-
-/* shift asop left, const == 32 */
-static uchar	asshllc32[][VLEN] =
-{
-	{V_a0},
-	{Vins, AMOVL, O_l_lo, O_r0},
-	{Vzero, O_l_lo},
-	{Vins, AMOVL, O_r0, O_l_hi},
-	{V_f0, Vend},
-};
-
-/* shift asop left, const > 32 */
-static uchar	asshllchi[][VLEN] =
-{
-	{V_a0},
-	{Vins, AMOVL, O_l_lo, O_r0},
-	{Vzero, O_l_lo},
-	{Vshll, O_r, O_r0},
-	{Vins, AMOVL, O_r0, O_l_hi},
-	{V_f0, Vend},
-};
-
-/* shift asop dest left general case */
-static uchar	asdshllgen[][VLEN] =
-{
-	{Vop, OGE, O_r, C32},
-	{V_s0, Vins, AMOVL, O_l_lo, O_t_lo},
-	{Vins, AMOVL, O_l_hi, O_t_hi},
-	{Vinsl, ASHLL, O_r, O_t_rp},
-	{Vins, ASHLL, O_r, O_t_lo},
-	{Vins, AMOVL, O_t_hi, O_l_hi},
-	{Vins, AMOVL, O_t_lo, O_l_lo, Vgo},
-	{V_p0, V_s0},
-	{Vins, AMOVL, O_l_lo, O_t_hi},
-	{Vzero, O_l_lo},
-	{Vins, ASHLL, O_r, O_t_hi},
-	{Vzero, O_t_lo},
-	{Vins, AMOVL, O_t_hi, O_l_hi, V_p0},
-	{Vend},
-};
-
-/* shift asop dest left, const < 32 */
-static uchar	asdshllclo[][VLEN] =
-{
-	{Vins, AMOVL, O_l_lo, O_t_lo},
-	{Vins, AMOVL, O_l_hi, O_t_hi},
-	{Vinsl, ASHLL, O_r, O_t_rp},
-	{Vshll, O_r, O_t_lo},
-	{Vins, AMOVL, O_t_hi, O_l_hi},
-	{Vins, AMOVL, O_t_lo, O_l_lo},
-	{Vend},
-};
-
-/* shift asop dest left, const == 32 */
-static uchar	asdshllc32[][VLEN] =
-{
-	{Vins, AMOVL, O_l_lo, O_t_hi},
-	{Vzero, O_t_lo},
-	{Vins, AMOVL, O_t_hi, O_l_hi},
-	{Vins, AMOVL, O_t_lo, O_l_lo},
-	{Vend},
-};
-
-/* shift asop dest, const > 32 */
-static uchar	asdshllchi[][VLEN] =
-{
-	{Vins, AMOVL, O_l_lo, O_t_hi},
-	{Vzero, O_t_lo},
-	{Vshll, O_r, O_t_hi},
-	{Vins, AMOVL, O_t_lo, O_l_lo},
-	{Vins, AMOVL, O_t_hi, O_l_hi},
-	{Vend},
-};
-
-static uchar	(*asshlltab[])[VLEN] =
-{
-	asshllgen,
-	asshllclo,
-	asshllc32,
-	asshllchi,
-	asdshllgen,
-	asdshllclo,
-	asdshllc32,
-	asdshllchi,
-};
-
-/* shift asop right general case */
-static uchar	asshrlgen[][VLEN] =
-{
-	{V_a0, V_a1},
-	{Vop, OGE, O_r, C32},
-	{V_s0, Vins, AMOVL, O_l_lo, O_r0},
-	{Vins, AMOVL, O_l_hi, O_r1},
-	{Vinsra, ASHRL, O_r, O_r0},
-	{Vinsx, Bop0, O_r, O_r1},
-	{Vins, AMOVL, O_r0, O_l_lo},
-	{Vins, AMOVL, O_r1, O_l_hi, Vgo},
-	{V_p0, V_s0},
-	{Vins, AMOVL, O_l_hi, O_r0},
-	{Vinsx, Bop0, O_r, O_r0},
-	{V_T1, Vzero, O_l_hi},
-	{Vins, AMOVL, O_r0, O_l_lo},
-	{V_F1, Vins, ASARL, C31, O_r0},
-	{V_F1, Vins, AMOVL, O_r0, O_l_hi},
-	{V_p0, V_f0, V_f1, Vend},
-};
-
-/* shift asop right, const < 32 */
-static uchar	asshrlclo[][VLEN] =
-{
-	{V_a0, V_a1},
-	{Vins, AMOVL, O_l_lo, O_r0},
-	{Vins, AMOVL, O_l_hi, O_r1},
-	{Vinsra, ASHRL, O_r, O_r0},
-	{Vinsx, Bop0, O_r, O_r1},
-	{Vins, AMOVL, O_r0, O_l_lo},
-	{Vins, AMOVL, O_r1, O_l_hi},
-	{V_f0, V_f1, Vend},
-};
-
-/* shift asop right, const == 32 */
-static uchar	asshrlc32[][VLEN] =
-{
-	{V_a0},
-	{Vins, AMOVL, O_l_hi, O_r0},
-	{V_T1, Vzero, O_l_hi},
-	{Vins, AMOVL, O_r0, O_l_lo},
-	{V_F1, Vins, ASARL, C31, O_r0},
-	{V_F1, Vins, AMOVL, O_r0, O_l_hi},
-	{V_f0, Vend},
-};
-
-/* shift asop right, const > 32 */
-static uchar	asshrlchi[][VLEN] =
-{
-	{V_a0},
-	{Vins, AMOVL, O_l_hi, O_r0},
-	{V_T1, Vzero, O_l_hi},
-	{Vinsx, Bop0, O_r, O_r0},
-	{Vins, AMOVL, O_r0, O_l_lo},
-	{V_F1, Vins, ASARL, C31, O_r0},
-	{V_F1, Vins, AMOVL, O_r0, O_l_hi},
-	{V_f0, Vend},
-};
-
-/* shift asop dest right general case */
-static uchar	asdshrlgen[][VLEN] =
-{
-	{Vop, OGE, O_r, C32},
-	{V_s0, Vins, AMOVL, O_l_lo, O_t_lo},
-	{Vins, AMOVL, O_l_hi, O_t_hi},
-	{Vinsr, ASHRL, O_r, O_t_rp},
-	{Vinsx, Bop0, O_r, O_t_hi},
-	{Vins, AMOVL, O_t_lo, O_l_lo},
-	{Vins, AMOVL, O_t_hi, O_l_hi, Vgo},
-	{V_p0, V_s0},
-	{Vins, AMOVL, O_l_hi, O_t_lo},
-	{V_T1, Vzero, O_t_hi},
-	{Vinsx, Bop0, O_r, O_t_lo},
-	{V_F1, Vins, AMOVL, O_t_lo, O_t_hi},
-	{V_F1, Vins, ASARL, C31, O_t_hi},
-	{Vins, AMOVL, O_t_hi, O_l_hi, V_p0},
-	{Vend},
-};
-
-/* shift asop dest right, const < 32 */
-static uchar	asdshrlclo[][VLEN] =
-{
-	{Vins, AMOVL, O_l_lo, O_t_lo},
-	{Vins, AMOVL, O_l_hi, O_t_hi},
-	{Vinsr, ASHRL, O_r, O_t_rp},
-	{Vinsx, Bop0, O_r, O_t_hi},
-	{Vins, AMOVL, O_t_lo, O_l_lo},
-	{Vins, AMOVL, O_t_hi, O_l_hi},
-	{Vend},
-};
-
-/* shift asop dest right, const == 32 */
-static uchar	asdshrlc32[][VLEN] =
-{
-	{Vins, AMOVL, O_l_hi, O_t_lo},
-	{V_T1, Vzero, O_t_hi},
-	{V_F1, Vins, AMOVL, O_t_lo, O_t_hi},
-	{V_F1, Vins, ASARL, C31, O_t_hi},
-	{Vins, AMOVL, O_t_lo, O_l_lo},
-	{Vins, AMOVL, O_t_hi, O_l_hi},
-	{Vend},
-};
-
-/* shift asop dest, const > 32 */
-static uchar	asdshrlchi[][VLEN] =
-{
-	{Vins, AMOVL, O_l_hi, O_t_lo},
-	{V_T1, Vzero, O_t_hi},
-	{Vinsx, Bop0, O_r, O_t_lo},
-	{V_T1, Vins, AMOVL, O_t_hi, O_l_hi},
-	{V_T1, Vins, AMOVL, O_t_lo, O_l_lo},
-	{V_F1, Vins, AMOVL, O_t_lo, O_t_hi},
-	{V_F1, Vins, ASARL, C31, O_t_hi},
-	{V_F1, Vins, AMOVL, O_t_lo, O_l_lo},
-	{V_F1, Vins, AMOVL, O_t_hi, O_l_hi},
-	{Vend},
-};
-
-static uchar	(*asshrltab[])[VLEN] =
-{
-	asshrlgen,
-	asshrlclo,
-	asshrlc32,
-	asshrlchi,
-	asdshrlgen,
-	asdshrlclo,
-	asdshrlc32,
-	asdshrlchi,
-};
-
-static uchar	shrlargs[]	= { ASHRL, 1 };
-static uchar	sarlargs[]	= { ASARL, 0 };
-
-/* ++ -- */
-static uchar	incdec[][VLEN] =
-{
-	{Vinsx, Bop0, C01, O_l_lo},
-	{Vinsx, Bop1, C00, O_l_hi, Vend},
-};
-
-/* ++ -- *p */
-static uchar	incdecpre[][VLEN] =
-{
-	{Vins, AMOVL, O_l_lo, O_t_lo},
-	{Vins, AMOVL, O_l_hi, O_t_hi},
-	{Vinsx, Bop0, C01, O_t_lo},
-	{Vinsx, Bop1, C00, O_t_hi},
-	{Vins, AMOVL, O_t_lo, O_l_lo},
-	{Vins, AMOVL, O_t_hi, O_l_hi, Vend},
-};
-
-/* *p ++ -- */
-static uchar	incdecpost[][VLEN] =
-{
-	{Vins, AMOVL, O_l_lo, O_t_lo},
-	{Vins, AMOVL, O_l_hi, O_t_hi},
-	{Vinsx, Bop0, C01, O_l_lo},
-	{Vinsx, Bop1, C00, O_l_hi, Vend},
-};
-
-/* binop rp, rp */
-static uchar	binop00[][VLEN] =
-{
-	{Vinsx, Bop0, O_r_lo, O_l_lo},
-	{Vinsx, Bop1, O_r_hi, O_l_hi, Vend},
-	{Vend},
-};
-
-/* binop rp, addr */
-static uchar	binoptmp[][VLEN] =
-{
-	{V_a0, Vins, AMOVL, O_r_lo, O_r0},
-	{Vinsx, Bop0, O_r0, O_l_lo},
-	{Vins, AMOVL, O_r_hi, O_r0},
-	{Vinsx, Bop1, O_r0, O_l_hi},
-	{V_f0, Vend},
-};
-
-/* binop t = *a op *b */
-static uchar	binop11[][VLEN] =
-{
-	{Vins, AMOVL, O_l_lo, O_t_lo},
-	{Vinsx, Bop0, O_r_lo, O_t_lo},
-	{Vins, AMOVL, O_l_hi, O_t_hi},
-	{Vinsx, Bop1, O_r_hi, O_t_hi, Vend},
-};
-
-/* binop t = rp +- c */
-static uchar	add0c[][VLEN] =
-{
-	{V_r_lo_t, Vinsx, Bop0, O_r_lo, O_l_lo},
-	{V_r_lo_f, Vamv, Bop0, Bop1},
-	{Vinsx, Bop1, O_r_hi, O_l_hi},
-	{Vend},
-};
-
-/* binop t = rp & c */
-static uchar	and0c[][VLEN] =
-{
-	{V_r_lo_t, Vinsx, Bop0, O_r_lo, O_l_lo},
-	{V_r_lo_f, Vins, AMOVL, C00, O_l_lo},
-	{V_r_hi_t, Vinsx, Bop1, O_r_hi, O_l_hi},
-	{V_r_hi_f, Vins, AMOVL, C00, O_l_hi},
-	{Vend},
-};
-
-/* binop t = rp | c */
-static uchar	or0c[][VLEN] =
-{
-	{V_r_lo_t, Vinsx, Bop0, O_r_lo, O_l_lo},
-	{V_r_hi_t, Vinsx, Bop1, O_r_hi, O_l_hi},
-	{Vend},
-};
-
-/* binop t = c - rp */
-static uchar	sub10[][VLEN] =
-{
-	{V_a0, Vins, AMOVL, O_l_lo, O_r0},
-	{Vinsx, Bop0, O_r_lo, O_r0},
-	{Vins, AMOVL, O_l_hi, O_r_lo},
-	{Vinsx, Bop1, O_r_hi, O_r_lo},
-	{Vspazz, V_f0, Vend},
-};
-
-/* binop t = c + *b */
-static uchar	addca[][VLEN] =
-{
-	{Vins, AMOVL, O_r_lo, O_t_lo},
-	{V_l_lo_t, Vinsx, Bop0, O_l_lo, O_t_lo},
-	{V_l_lo_f, Vamv, Bop0, Bop1},
-	{Vins, AMOVL, O_r_hi, O_t_hi},
-	{Vinsx, Bop1, O_l_hi, O_t_hi},
-	{Vend},
-};
-
-/* binop t = c & *b */
-static uchar	andca[][VLEN] =
-{
-	{V_l_lo_t, Vins, AMOVL, O_r_lo, O_t_lo},
-	{V_l_lo_t, Vinsx, Bop0, O_l_lo, O_t_lo},
-	{V_l_lo_f, Vzero, O_t_lo},
-	{V_l_hi_t, Vins, AMOVL, O_r_hi, O_t_hi},
-	{V_l_hi_t, Vinsx, Bop1, O_l_hi, O_t_hi},
-	{V_l_hi_f, Vzero, O_t_hi},
-	{Vend},
-};
-
-/* binop t = c | *b */
-static uchar	orca[][VLEN] =
-{
-	{Vins, AMOVL, O_r_lo, O_t_lo},
-	{V_l_lo_t, Vinsx, Bop0, O_l_lo, O_t_lo},
-	{Vins, AMOVL, O_r_hi, O_t_hi},
-	{V_l_hi_t, Vinsx, Bop1, O_l_hi, O_t_hi},
-	{Vend},
-};
-
-/* binop t = c - *b */
-static uchar	subca[][VLEN] =
-{
-	{Vins, AMOVL, O_l_lo, O_t_lo},
-	{Vins, AMOVL, O_l_hi, O_t_hi},
-	{Vinsx, Bop0, O_r_lo, O_t_lo},
-	{Vinsx, Bop1, O_r_hi, O_t_hi},
-	{Vend},
-};
-
-/* binop t = *a +- c */
-static uchar	addac[][VLEN] =
-{
-	{Vins, AMOVL, O_l_lo, O_t_lo},
-	{V_r_lo_t, Vinsx, Bop0, O_r_lo, O_t_lo},
-	{V_r_lo_f, Vamv, Bop0, Bop1},
-	{Vins, AMOVL, O_l_hi, O_t_hi},
-	{Vinsx, Bop1, O_r_hi, O_t_hi},
-	{Vend},
-};
-
-/* binop t = *a | c */
-static uchar	orac[][VLEN] =
-{
-	{Vins, AMOVL, O_l_lo, O_t_lo},
-	{V_r_lo_t, Vinsx, Bop0, O_r_lo, O_t_lo},
-	{Vins, AMOVL, O_l_hi, O_t_hi},
-	{V_r_hi_t, Vinsx, Bop1, O_r_hi, O_t_hi},
-	{Vend},
-};
-
-/* binop t = *a & c */
-static uchar	andac[][VLEN] =
-{
-	{V_r_lo_t, Vins, AMOVL, O_l_lo, O_t_lo},
-	{V_r_lo_t, Vinsx, Bop0, O_r_lo, O_t_lo},
-	{V_r_lo_f, Vzero, O_t_lo},
-	{V_r_hi_t, Vins, AMOVL, O_l_hi, O_t_hi},
-	{V_r_hi_t, Vinsx, Bop0, O_r_hi, O_t_hi},
-	{V_r_hi_f, Vzero, O_t_hi},
-	{Vend},
-};
-
-static uchar	ADDargs[]	= { AADDL, AADCL };
-static uchar	ANDargs[]	= { AANDL, AANDL };
-static uchar	ORargs[]	= { AORL, AORL };
-static uchar	SUBargs[]	= { ASUBL, ASBBL };
-static uchar	XORargs[]	= { AXORL, AXORL };
-
-static uchar	(*ADDtab[])[VLEN] =
-{
-	add0c, addca, addac,
-};
-
-static uchar	(*ANDtab[])[VLEN] =
-{
-	and0c, andca, andac,
-};
-
-static uchar	(*ORtab[])[VLEN] =
-{
-	or0c, orca, orac,
-};
-
-static uchar	(*SUBtab[])[VLEN] =
-{
-	add0c, subca, addac,
-};
-
-/* mul of const32 */
-static uchar	mulc32[][VLEN] =
-{
-	{V_a0, Vop, ONE, O_l_hi, C00},
-	{V_s0, Vins, AMOVL, O_r_lo, O_r0},
-	{Vins, AMULL, O_r0, O_Zop},
-	{Vgo, V_p0, V_s0},
-	{Vins, AMOVL, O_l_hi, O_r0},
-	{Vmul, O_r_lo, O_r0},
-	{Vins, AMOVL, O_r_lo, O_l_hi},
-	{Vins, AMULL, O_l_hi, O_Zop},
-	{Vins, AADDL, O_r0, O_l_hi},
-	{V_f0, V_p0, Vend},
-};
-
-/* mul of const64 */
-static uchar	mulc64[][VLEN] =
-{
-	{V_a0, Vins, AMOVL, O_r_hi, O_r0},
-	{Vop, OOR, O_l_hi, O_r0},
-	{Vop, ONE, O_r0, C00},
-	{V_s0, Vins, AMOVL, O_r_lo, O_r0},
-	{Vins, AMULL, O_r0, O_Zop},
-	{Vgo, V_p0, V_s0},
-	{Vmul, O_r_lo, O_l_hi},
-	{Vins, AMOVL, O_l_lo, O_r0},
-	{Vmul, O_r_hi, O_r0},
-	{Vins, AADDL, O_l_hi, O_r0},
-	{Vins, AMOVL, O_r_lo, O_l_hi},
-	{Vins, AMULL, O_l_hi, O_Zop},
-	{Vins, AADDL, O_r0, O_l_hi},
-	{V_f0, V_p0, Vend},
-};
-
-/* mul general */
-static uchar	mull[][VLEN] =
-{
-	{V_a0, Vins, AMOVL, O_r_hi, O_r0},
-	{Vop, OOR, O_l_hi, O_r0},
-	{Vop, ONE, O_r0, C00},
-	{V_s0, Vins, AMOVL, O_r_lo, O_r0},
-	{Vins, AMULL, O_r0, O_Zop},
-	{Vgo, V_p0, V_s0},
-	{Vins, AIMULL, O_r_lo, O_l_hi},
-	{Vins, AMOVL, O_l_lo, O_r0},
-	{Vins, AIMULL, O_r_hi, O_r0},
-	{Vins, AADDL, O_l_hi, O_r0},
-	{Vins, AMOVL, O_r_lo, O_l_hi},
-	{Vins, AMULL, O_l_hi, O_Zop},
-	{Vins, AADDL, O_r0, O_l_hi},
-	{V_f0, V_p0, Vend},
-};
-
-/* cast rp l to rp t */
-static uchar	castrp[][VLEN] =
-{
-	{Vmv, O_l, O_t_lo},
-	{VT, Vins, AMOVL, O_t_lo, O_t_hi},
-	{VT, Vins, ASARL, C31, O_t_hi},
-	{VF, Vzero, O_t_hi},
-	{Vend},
-};
-
-/* cast rp l to addr t */
-static uchar	castrpa[][VLEN] =
-{
-	{VT, V_a0, Vmv, O_l, O_r0},
-	{VT, Vins, AMOVL, O_r0, O_t_lo},
-	{VT, Vins, ASARL, C31, O_r0},
-	{VT, Vins, AMOVL, O_r0, O_t_hi},
-	{VT, V_f0},
-	{VF, Vmv, O_l, O_t_lo},
-	{VF, Vzero, O_t_hi},
-	{Vend},
-};
-
-static uchar	netab0i[][VLEN] =
-{
-	{Vop, ONE, O_l_lo, O_r_lo},
-	{V_s0, Vop, ONE, O_l_hi, O_r_hi},
-	{V_s1, Vgo, V_s2, Vgo, V_s3},
-	{VF, V_p0, V_p1, VT, V_p2},
-	{Vgo, V_p3},
-	{VT, V_p0, V_p1, VF, V_p2},
-	{Vend},
-};
-
-static uchar	netabii[][VLEN] =
-{
-	{V_a0, Vins, AMOVL, O_l_lo, O_r0},
-	{Vop, ONE, O_r0, O_r_lo},
-	{V_s0, Vins, AMOVL, O_l_hi, O_r0},
-	{Vop, ONE, O_r0, O_r_hi},
-	{V_s1, Vgo, V_s2, Vgo, V_s3},
-	{VF, V_p0, V_p1, VT, V_p2},
-	{Vgo, V_p3},
-	{VT, V_p0, V_p1, VF, V_p2},
-	{V_f0, Vend},
-};
-
-static uchar	cmptab0i[][VLEN] =
-{
-	{Vopx, Bop0, O_l_hi, O_r_hi},
-	{V_s0, Vins0, AJNE},
-	{V_s1, Vopx, Bop1, O_l_lo, O_r_lo},
-	{V_s2, Vgo, V_s3, Vgo, V_s4},
-	{VT, V_p1, V_p3},
-	{VF, V_p0, V_p2},
-	{Vgo, V_p4},
-	{VT, V_p0, V_p2},
-	{VF, V_p1, V_p3},
-	{Vend},
-};
-
-static uchar	cmptabii[][VLEN] =
-{
-	{V_a0, Vins, AMOVL, O_l_hi, O_r0},
-	{Vopx, Bop0, O_r0, O_r_hi},
-	{V_s0, Vins0, AJNE},
-	{V_s1, Vins, AMOVL, O_l_lo, O_r0},
-	{Vopx, Bop1, O_r0, O_r_lo},
-	{V_s2, Vgo, V_s3, Vgo, V_s4},
-	{VT, V_p1, V_p3},
-	{VF, V_p0, V_p2},
-	{Vgo, V_p4},
-	{VT, V_p0, V_p2},
-	{VF, V_p1, V_p3},
-	{V_f0, Vend},
-};
-
-static uchar	(*NEtab[])[VLEN] =
-{
-	netab0i, netabii,
-};
-
-static uchar	(*cmptab[])[VLEN] =
-{
-	cmptab0i, cmptabii,
-};
-
-static uchar	GEargs[]	= { OGT, OHS };
-static uchar	GTargs[]	= { OGT, OHI };
-static uchar	HIargs[]	= { OHI, OHI };
-static uchar	HSargs[]	= { OHI, OHS };
-
-/* Big Generator */
-static void
-biggen(Node *l, Node *r, Node *t, int true, uchar code[][VLEN], uchar *a)
-{
-	int i, j, g, oc, op, lo, ro, to, xo, *xp;
-	Type *lt;
-	Prog *pr[VOPS];
-	Node *ot, *tl, *tr, tmps[2];
-	uchar *c, (*cp)[VLEN], args[VARGS];
-
-	if(a != nil)
-		memmove(args, a, VARGS);
-//print("biggen %d %d %d\n", args[0], args[1], args[2]);
-//if(l) prtree(l, "l");
-//if(r) prtree(r, "r");
-//if(t) prtree(t, "t");
-	lo = ro = to = 0;
-	cp = code;
-
-	for (;;) {
-		c = *cp++;
-		g = 1;
-		i = 0;
-//print("code %d %d %d %d %d\n", c[0], c[1], c[2], c[3], c[4]);
-		for(;;) {
-			switch(op = c[i]) {
-			case Vgo:
-				if(g)
-					gbranch(OGOTO);
-				i++;
-				break;
-
-			case Vamv:
-				i += 3;
-				if(i > VLEN) {
-					diag(l, "bad Vop");
-					return;
-				}
-				if(g)
-					args[c[i - 1]] = args[c[i - 2]];
-				break;
-
-			case Vzero:
-				i += 2;
-				if(i > VLEN) {
-					diag(l, "bad Vop");
-					return;
-				}
-				j = i - 1;
-				goto op;
-
-			case Vspazz:	// nasty hack to save a reg in SUB
-//print("spazz\n");
-				if(g) {
-//print("hi %R lo %R t %R\n", r->right->reg, r->left->reg, tmps[0].reg);
-					ot = r->right;
-					r->right = r->left;
-					tl = new(0, Z, Z);
-					*tl = tmps[0];
-					r->left = tl;
-					tmps[0] = *ot;
-//print("hi %R lo %R t %R\n", r->right->reg, r->left->reg, tmps[0].reg);
-				}
-				i++;
-				break;
-
-			case Vmv:
-			case Vmul:
-			case Vshll:
-				i += 3;
-				if(i > VLEN) {
-					diag(l, "bad Vop");
-					return;
-				}
-				j = i - 2;
-				goto op;
-
-			case Vins0:
-				i += 2;
-				if(i > VLEN) {
-					diag(l, "bad Vop");
-					return;
-				}
-				gins(c[i - 1], Z, Z);
-				break;
-
-			case Vop:
-			case Vopx:
-			case Vins:
-			case Vinsl:
-			case Vinsr:
-			case Vinsla:
-			case Vinsra:
-			case Vinsx:
-				i += 4;
-				if(i > VLEN) {
-					diag(l, "bad Vop");
-					return;
-				}
-				j = i - 2;
-				goto op;
-
-			op:
-				if(!g)
-					break;
-				tl = Z;
-				tr = Z;
-				for(; j < i; j++) {
-					switch(c[j]) {
-					case C00:
-						ot = nodconst(0);
-						break;
-					case C01:
-						ot = nodconst(1);
-						break;
-					case C31:
-						ot = nodconst(31);
-						break;
-					case C32:
-						ot = nodconst(32);
-						break;
-
-					case O_l:
-					case O_l_lo:
-						ot = l; xp = &lo; xo = 0;
-						goto op0;
-					case O_l_hi:
-						ot = l; xp = &lo; xo = SZ_LONG;
-						goto op0;
-					case O_r:
-					case O_r_lo:
-						ot = r; xp = &ro; xo = 0;
-						goto op0;
-					case O_r_hi:
-						ot = r; xp = &ro; xo = SZ_LONG;
-						goto op0;
-					case O_t_lo:
-						ot = t; xp = &to; xo = 0;
-						goto op0;
-					case O_t_hi:
-						ot = t; xp = &to; xo = SZ_LONG;
-						goto op0;
-					case O_l_rp:
-						ot = l;
-						break;
-					case O_r_rp:
-						ot = r;
-						break;
-					case O_t_rp:
-						ot = t;
-						break;
-					case O_r0:
-					case O_r1:
-						ot = &tmps[c[j] - O_r0];
-						break;
-					case O_Zop:
-						ot = Z;
-						break;
-
-					op0:
-						switch(ot->op) {
-						case OCONST:
-							if(xo)
-								ot = hi64(ot);
-							else
-								ot = lo64(ot);
-							break;
-						case OREGPAIR:
-							if(xo)
-								ot = ot->right;
-							else
-								ot = ot->left;
-							break;
-						case OREGISTER:
-							break;
-						default:
-							if(xo != *xp) {
-								ot->xoffset += xo - *xp;
-								*xp = xo;
-							}
-						}
-						break;
-					
-					default:
-						diag(l, "bad V_lop");
-						return;
-					}
-					if(tl == nil)
-						tl = ot;
-					else
-						tr = ot;
-				}
-				if(op == Vzero) {
-					zeroregm(tl);
-					break;
-				}
-				oc = c[i - 3];
-				if(op == Vinsx || op == Vopx) {
-//print("%d -> %d\n", oc, args[oc]);
-					oc = args[oc];
-				}
-				else {
-					switch(oc) {
-					case O_a0:
-					case O_a1:
-						oc = args[oc - O_a0];
-						break;
-					}
-				}
-				switch(op) {
-				case Vmul:
-					mulgen(tr->type, tl, tr);
-					break;
-				case Vmv:
-					gmove(tl, tr);
-					break;
-				case Vshll:
-					shiftit(tr->type, tl, tr);
-					break;
-				case Vop:
-				case Vopx:
-					gopcode(oc, types[TULONG], tl, tr);
-					break;
-				case Vins:
-				case Vinsx:
-					gins(oc, tl, tr);
-					break;
-				case Vinsl:
-					gins(oc, tl, tr->right);
-					p->from.index = tr->left->reg;
-					break;
-				case Vinsr:
-					gins(oc, tl, tr->left);
-					p->from.index = tr->right->reg;
-					break;
-				case Vinsla:
-					gins(oc, tl, tr + 1);
-					p->from.index = tr->reg;
-					break;
-				case Vinsra:
-					gins(oc, tl, tr);
-					p->from.index = (tr + 1)->reg;
-					break;
-				}
-				break;
-
-			case VT:
-				g = true;
-				i++;
-				break;
-			case VF:
-				g = !true;
-				i++;
-				break;
-
-			case V_T0: case V_T1:
-				g = args[op - V_T0];
-				i++;
-				break;
-
-			case V_F0: case V_F1:
-				g = !args[op - V_F0];
-				i++;
-				break;
-
-			case V_C0: case V_C1:
-				if(g)
-					args[op - V_C0] = 0;
-				i++;
-				break;
-
-			case V_S0: case V_S1:
-				if(g)
-					args[op - V_S0] = 1;
-				i++;
-				break;
-
-			case V_l_lo_f:
-				g = lo64v(l) == 0;
-				i++;
-				break;
-			case V_l_hi_f:
-				g = hi64v(l) == 0;
-				i++;
-				break;
-			case V_l_lo_t:
-				g = lo64v(l) != 0;
-				i++;
-				break;
-			case V_l_hi_t:
-				g = hi64v(l) != 0;
-				i++;
-				break;
-			case V_l_lo_u:
-				g = lo64v(l) >= 0;
-				i++;
-				break;
-			case V_l_hi_u:
-				g = hi64v(l) >= 0;
-				i++;
-				break;
-			case V_r_lo_f:
-				g = lo64v(r) == 0;
-				i++;
-				break;
-			case V_r_hi_f:
-				g = hi64v(r) == 0;
-				i++;
-				break;
-			case V_r_lo_t:
-				g = lo64v(r) != 0;
-				i++;
-				break;
-			case V_r_hi_t:
-				g = hi64v(r) != 0;
-				i++;
-				break;
-			case V_r_lo_u:
-				g = lo64v(r) >= 0;
-				i++;
-				break;
-			case V_r_hi_u:
-				g = hi64v(r) >= 0;
-				i++;
-				break;
-
-			case Vend:
-				goto out;
-
-			case V_a0: case V_a1:
-				if(g) {
-					lt = l->type;
-					l->type = types[TULONG];
-					regalloc(&tmps[op - V_a0], l, Z);
-					l->type = lt;
-				}
-				i++;
-				break;
-
-			case V_f0: case V_f1:
-				if(g)
-					regfree(&tmps[op - V_f0]);
-				i++;
-				break;
-
-			case V_p0: case V_p1: case V_p2: case V_p3: case V_p4:
-				if(g)
-					patch(pr[op - V_p0], pc);
-				i++;
-				break;
-
-			case V_s0: case V_s1: case V_s2: case V_s3: case V_s4:
-				if(g)
-					pr[op - V_s0] = p;
-				i++;
-				break;
-
-			default:
-				diag(l, "bad biggen: %d", op);
-				return;
-			}
-			if(i == VLEN || c[i] == 0)
-				break;
-		}
-	}
-out:
-	if(lo)
-		l->xoffset -= lo;
-	if(ro)
-		r->xoffset -= ro;
-	if(to)
-		t->xoffset -= to;
-}
-
-int
-cgen64(Node *n, Node *nn)
-{
-	Type *dt;
-	uchar *args, (*cp)[VLEN], (**optab)[VLEN];
-	int li, ri, lri, dr, si, m, op, sh, cmp, true;
-	Node *c, *d, *l, *r, *t, *s, nod1, nod2, nod3, nod4, nod5;
-
-	if(debug['g']) {
-		prtree(nn, "cgen64 lhs");
-		prtree(n, "cgen64");
-		print("AX = %d\n", reg[D_AX]);
-	}
-	cmp = 0;
-	sh = 0;
-
-	switch(n->op) {
-	case ONEG:
-		d = regpair(nn, n);
-		sugen(n->left, d, 8);
-		gins(ANOTL, Z, d->right);
-		gins(ANEGL, Z, d->left);
-		gins(ASBBL, nodconst(-1), d->right);
-		break;
-
-	case OCOM:
-		if(!vaddr(n->left, 0) || !vaddr(nn, 0))
-			d = regpair(nn, n);
-		else
-			return 0;
-		sugen(n->left, d, 8);
-		gins(ANOTL, Z, d->left);
-		gins(ANOTL, Z, d->right);
-		break;
-
-	case OADD:
-		optab = ADDtab;
-		args = ADDargs;
-		goto twoop;
-	case OAND:
-		optab = ANDtab;
-		args = ANDargs;
-		goto twoop;
-	case OOR:
-		optab = ORtab;
-		args = ORargs;
-		goto twoop;
-	case OSUB:
-		optab = SUBtab;
-		args = SUBargs;
-		goto twoop;
-	case OXOR:
-		optab = ORtab;
-		args = XORargs;
-		goto twoop;
-	case OASHL:
-		sh = 1;
-		args = nil;
-		optab = shlltab;
-		goto twoop;
-	case OLSHR:
-		sh = 1;
-		args = shrlargs;
-		optab = shrltab;
-		goto twoop;
-	case OASHR:
-		sh = 1;
-		args = sarlargs;
-		optab = shrltab;
-		goto twoop;
-	case OEQ:
-		cmp = 1;
-		args = nil;
-		optab = nil;
-		goto twoop;
-	case ONE:
-		cmp = 1;
-		args = nil;
-		optab = nil;
-		goto twoop;
-	case OLE:
-		cmp = 1;
-		args = nil;
-		optab = nil;
-		goto twoop;
-	case OLT:
-		cmp = 1;
-		args = nil;
-		optab = nil;
-		goto twoop;
-	case OGE:
-		cmp = 1;
-		args = nil;
-		optab = nil;
-		goto twoop;
-	case OGT:
-		cmp = 1;
-		args = nil;
-		optab = nil;
-		goto twoop;
-	case OHI:
-		cmp = 1;
-		args = nil;
-		optab = nil;
-		goto twoop;
-	case OHS:
-		cmp = 1;
-		args = nil;
-		optab = nil;
-		goto twoop;
-	case OLO:
-		cmp = 1;
-		args = nil;
-		optab = nil;
-		goto twoop;
-	case OLS:
-		cmp = 1;
-		args = nil;
-		optab = nil;
-		goto twoop;
-
-twoop:
-		dr = nn != Z && nn->op == OREGPAIR;
-		l = vfunc(n->left, nn);
-		if(sh)
-			r = n->right;
-		else
-			r = vfunc(n->right, nn);
-
-		li = l->op == ONAME || l->op == OINDREG || l->op == OCONST;
-		ri = r->op == ONAME || r->op == OINDREG || r->op == OCONST;
-
-#define	IMM(l, r)	((l) | ((r) << 1))
-
-		lri = IMM(li, ri);
-
-		/* find out what is so easy about some operands */
-		if(li)
-			li = whatof(l, sh | cmp);
-		if(ri)
-			ri = whatof(r, cmp);
-
-		if(sh)
-			goto shift;
-
-		if(cmp)
-			goto cmp;
-
-		/* evaluate hard subexps, stealing nn if possible. */
-		switch(lri) {
-		case IMM(0, 0):
-		bin00:
-			if(l->complex > r->complex) {
-				if(dr)
-					t = nn;
-				else
-					t = regpair(Z, n);
-				sugen(l, t, 8);
-				l = t;
-				t = regpair(Z, n);
-				sugen(r, t, 8);
-				r = t;
-			}
-			else {
-				t = regpair(Z, n);
-				sugen(r, t, 8);
-				r = t;
-				if(dr)
-					t = nn;
-				else
-					t = regpair(Z, n);
-				sugen(l, t, 8);
-				l = t;
-			}
-			break;
-		case IMM(0, 1):
-			if(dr)
-				t = nn;
-			else
-				t = regpair(Z, n);
-			sugen(l, t, 8);
-			l = t;
-			break;
-		case IMM(1, 0):
-			if(n->op == OSUB && l->op == OCONST && hi64v(l) == 0) {
-				lri = IMM(0, 0);
-				goto bin00;
-			}
-			if(dr)
-				t = nn;
-			else
-				t = regpair(Z, n);
-			sugen(r, t, 8);
-			r = t;
-			break;
-		case IMM(1, 1):
-			break;
-		}
-
-#define	WW(l, r)	((l) | ((r) << 2))
-		d = Z;
-		dt = nn->type;
-		nn->type = types[TLONG];
-
-		switch(lri) {
-		case IMM(0, 0):
-			biggen(l, r, Z, 0, binop00, args);
-			break;
-		case IMM(0, 1):
-			switch(ri) {
-			case WNONE:
-				diag(r, "bad whatof\n");
-				break;
-			case WCONST:
-				biggen(l, r, Z, 0, optab[B0c], args);
-				break;
-			case WHARD:
-				reglcgen(&nod2, r, Z);
-				r = &nod2;
-				/* fall thru */
-			case WADDR:
-				biggen(l, r, Z, 0, binoptmp, args);
-				if(ri == WHARD)
-					regfree(r);
-				break;
-			}
-			break;
-		case IMM(1, 0):
-			if(n->op == OSUB) {
-				switch(li) {
-				case WNONE:
-					diag(l, "bad whatof\n");
-					break;
-				case WHARD:
-					reglcgen(&nod2, l, Z);
-					l = &nod2;
-					/* fall thru */
-				case WADDR:
-				case WCONST:
-					biggen(l, r, Z, 0, sub10, args);
-					break;
-				}
-				if(li == WHARD)
-					regfree(l);
-			}
-			else {
-				switch(li) {
-				case WNONE:
-					diag(l, "bad whatof\n");
-					break;
-				case WCONST:
-					biggen(r, l, Z, 0, optab[B0c], args);
-					break;
-				case WHARD:
-					reglcgen(&nod2, l, Z);
-					l = &nod2;
-					/* fall thru */
-				case WADDR:
-					biggen(r, l, Z, 0, binoptmp, args);
-					if(li == WHARD)
-						regfree(l);
-					break;
-				}
-			}
-			break;
-		case IMM(1, 1):
-			switch(WW(li, ri)) {
-			case WW(WCONST, WHARD):
-				if(r->op == ONAME && n->op == OAND && reduxv(l))
-					ri = WADDR;
-				break;
-			case WW(WHARD, WCONST):
-				if(l->op == ONAME && n->op == OAND && reduxv(r))
-					li = WADDR;
-				break;
-			}
-			if(li == WHARD) {
-				reglcgen(&nod3, l, Z);
-				l = &nod3;
-			}
-			if(ri == WHARD) {
-				reglcgen(&nod2, r, Z);
-				r = &nod2;
-			}
-			d = regpair(nn, n);
-			instpair(d, Z);
-			switch(WW(li, ri)) {
-			case WW(WCONST, WADDR):
-			case WW(WCONST, WHARD):
-				biggen(l, r, d, 0, optab[Bca], args);
-				break;
-
-			case WW(WADDR, WCONST):
-			case WW(WHARD, WCONST):
-				biggen(l, r, d, 0, optab[Bac], args);
-				break;
-
-			case WW(WADDR, WADDR):
-			case WW(WADDR, WHARD):
-			case WW(WHARD, WADDR):
-			case WW(WHARD, WHARD):
-				biggen(l, r, d, 0, binop11, args);
-				break;
-
-			default:
-				diag(r, "bad whatof pair %d %d\n", li, ri);
-				break;
-			}
-			if(li == WHARD)
-				regfree(l);
-			if(ri == WHARD)
-				regfree(r);
-			break;
-		}
-
-		nn->type = dt;
-
-		if(d != Z)
-			goto finished;
-
-		switch(lri) {
-		case IMM(0, 0):
-			freepair(r);
-			/* fall thru */;
-		case IMM(0, 1):
-			if(!dr)
-				storepair(l, nn, 1);
-			break;
-		case IMM(1, 0):
-			if(!dr)
-				storepair(r, nn, 1);
-			break;
-		case IMM(1, 1):
-			break;
-		}
-		return 1;
-
-	shift:
-		c = Z;
-
-		/* evaluate hard subexps, stealing nn if possible. */
-		/* must also secure CX.  not as many optims as binop. */
-		switch(lri) {
-		case IMM(0, 0):
-		imm00:
-			if(l->complex + 1 > r->complex) {
-				if(dr)
-					t = nn;
-				else
-					t = regpair(Z, l);
-				sugen(l, t, 8);
-				l = t;
-				t = &nod1;
-				c = snarfreg(l, t, D_CX, r, &nod2);
-				cgen(r, t);
-				r = t;
-			}
-			else {
-				t = &nod1;
-				c = snarfreg(nn, t, D_CX, r, &nod2);
-				cgen(r, t);
-				r = t;
-				if(dr)
-					t = nn;
-				else
-					t = regpair(Z, l);
-				sugen(l, t, 8);
-				l = t;
-			}
-			break;
-		case IMM(0, 1):
-		imm01:
-			if(ri != WCONST) {
-				lri = IMM(0, 0);
-				goto imm00;
-			}
-			if(dr)
-				t = nn;
-			else
-				t = regpair(Z, n);
-			sugen(l, t, 8);
-			l = t;
-			break;
-		case IMM(1, 0):
-		imm10:
-			if(li != WCONST) {
-				lri = IMM(0, 0);
-				goto imm00;
-			}
-			t = &nod1;
-			c = snarfreg(nn, t, D_CX, r, &nod2);
-			cgen(r, t);
-			r = t;
-			break;
-		case IMM(1, 1):
-			if(ri != WCONST) {
-				lri = IMM(1, 0);
-				goto imm10;
-			}
-			if(li == WHARD) {
-				lri = IMM(0, 1);
-				goto imm01;
-			}
-			break;
-		}
-
-		d = Z;
-
-		switch(lri) {
-		case IMM(0, 0):
-			biggen(l, r, Z, 0, optab[S00], args);
-			break;
-		case IMM(0, 1):
-			switch(ri) {
-			case WNONE:
-			case WADDR:
-			case WHARD:
-				diag(r, "bad whatof\n");
-				break;
-			case WCONST:
-				m = r->vconst & 63;
-				s = nodconst(m);
-				if(m < 32)
-					cp = optab[Sc0];
-				else if(m == 32)
-					cp = optab[Sc1];
-				else
-					cp = optab[Sc2];
-				biggen(l, s, Z, 0, cp, args);
-				break;
-			}
-			break;
-		case IMM(1, 0):
-			/* left is const */
-			d = regpair(nn, n);
-			instpair(d, Z);
-			biggen(l, r, d, 0, optab[S10], args);
-			regfree(r);
-			break;
-		case IMM(1, 1):
-			d = regpair(nn, n);
-			instpair(d, Z);
-			switch(WW(li, ri)) {
-			case WW(WADDR, WCONST):
-				m = r->vconst & 63;
-				s = nodconst(m);
-				if(m < 32) {
-					loadpair(l, d);
-					l = d;
-					cp = optab[Sc0];
-				}
-				else if(m == 32)
-					cp = optab[Sac3];
-				else
-					cp = optab[Sac4];
-				biggen(l, s, d, 0, cp, args);
-				break;
-
-			default:
-				diag(r, "bad whatof pair %d %d\n", li, ri);
-				break;
-			}
-			break;
-		}
-
-		if(c != Z) {
-			gins(AMOVL, c, r);
-			regfree(c);
-		}
-
-		if(d != Z)
-			goto finished;
-
-		switch(lri) {
-		case IMM(0, 0):
-			regfree(r);
-			/* fall thru */
-		case IMM(0, 1):
-			if(!dr)
-				storepair(l, nn, 1);
-			break;
-		case IMM(1, 0):
-			regfree(r);
-			break;
-		case IMM(1, 1):
-			break;
-		}
-		return 1;
-
-	cmp:
-		op = n->op;
-		/* evaluate hard subexps */
-		switch(lri) {
-		case IMM(0, 0):
-			if(l->complex > r->complex) {
-				t = regpair(Z, l);
-				sugen(l, t, 8);
-				l = t;
-				t = regpair(Z, r);
-				sugen(r, t, 8);
-				r = t;
-			}
-			else {
-				t = regpair(Z, r);
-				sugen(r, t, 8);
-				r = t;
-				t = regpair(Z, l);
-				sugen(l, t, 8);
-				l = t;
-			}
-			break;
-		case IMM(1, 0):
-			t = r;
-			r = l;
-			l = t;
-			ri = li;
-			op = invrel[relindex(op)];
-			/* fall thru */
-		case IMM(0, 1):
-			t = regpair(Z, l);
-			sugen(l, t, 8);
-			l = t;
-			break;
-		case IMM(1, 1):
-			break;
-		}
-
-		true = 1;
-		optab = cmptab;
-		switch(op) {
-		case OEQ:
-			optab = NEtab;
-			true = 0;
-			break;
-		case ONE:
-			optab = NEtab;
-			break;
-		case OLE:
-			args = GTargs;
-			true = 0;
-			break;
-		case OGT:
-			args = GTargs;
-			break;
-		case OLS:
-			args = HIargs;
-			true = 0;
-			break;
-		case OHI:
-			args = HIargs;
-			break;
-		case OLT:
-			args = GEargs;
-			true = 0;
-			break;
-		case OGE:
-			args = GEargs;
-			break;
-		case OLO:
-			args = HSargs;
-			true = 0;
-			break;
-		case OHS:
-			args = HSargs;
-			break;
-		default:
-			diag(n, "bad cmp\n");
-			SET(optab);
-		}
-
-		switch(lri) {
-		case IMM(0, 0):
-			biggen(l, r, Z, true, optab[T0i], args);
-			break;
-		case IMM(0, 1):
-		case IMM(1, 0):
-			switch(ri) {
-			case WNONE:
-				diag(l, "bad whatof\n");
-				break;
-			case WCONST:
-				biggen(l, r, Z, true, optab[T0i], args);
-				break;
-			case WHARD:
-				reglcgen(&nod2, r, Z);
-				r = &nod2;
-				/* fall thru */
-			case WADDR:
-				biggen(l, r, Z, true, optab[T0i], args);
-				if(ri == WHARD)
-					regfree(r);
-				break;
-			}
-			break;
-		case IMM(1, 1):
-			if(li == WHARD) {
-				reglcgen(&nod3, l, Z);
-				l = &nod3;
-			}
-			if(ri == WHARD) {
-				reglcgen(&nod2, r, Z);
-				r = &nod2;
-			}
-			biggen(l, r, Z, true, optab[Tii], args);
-			if(li == WHARD)
-				regfree(l);
-			if(ri == WHARD)
-				regfree(r);
-			break;
-		}
-
-		switch(lri) {
-		case IMM(0, 0):
-			freepair(r);
-			/* fall thru */;
-		case IMM(0, 1):
-		case IMM(1, 0):
-			freepair(l);
-			break;
-		case IMM(1, 1):
-			break;
-		}
-		return 1;
-
-	case OASMUL:
-	case OASLMUL:
-		m = 0;
-		goto mulop;
-
-	case OMUL:
-	case OLMUL:
-		m = 1;
-		goto mulop;
-
-	mulop:
-		dr = nn != Z && nn->op == OREGPAIR;
-		l = vfunc(n->left, nn);
-		r = vfunc(n->right, nn);
-		if(r->op != OCONST) {
-			if(l->complex > r->complex) {
-				if(m) {
-					t = l;
-					l = r;
-					r = t;
-				}
-				else if(!vaddr(l, 1)) {
-					reglcgen(&nod5, l, Z);
-					l = &nod5;
-					evacaxdx(l);
-				}
-			}
-			t = regpair(Z, n);
-			sugen(r, t, 8);
-			r = t;
-			evacaxdx(r->left);
-			evacaxdx(r->right);
-			if(l->complex <= r->complex && !m && !vaddr(l, 1)) {
-				reglcgen(&nod5, l, Z);
-				l = &nod5;
-				evacaxdx(l);
-			}
-		}
-		if(dr)
-			t = nn;
-		else
-			t = regpair(Z, n);
-		c = Z;
-		d = Z;
-		if(!nodreg(&nod1, t->left, D_AX)) {
-			if(t->left->reg != D_AX){
-				t->left->reg = D_AX;
-				reg[D_AX]++;
-			}else if(reg[D_AX] == 0)
-				fatal(Z, "vlong mul AX botch");
-		}
-		if(!nodreg(&nod2, t->right, D_DX)) {
-			if(t->right->reg != D_DX){
-				t->right->reg = D_DX;
-				reg[D_DX]++;
-			}else if(reg[D_DX] == 0)
-				fatal(Z, "vlong mul DX botch");
-		}
-		if(m)
-			sugen(l, t, 8);
-		else
-			loadpair(l, t);
-		if(t->left->reg != D_AX) {
-			c = &nod3;
-			regsalloc(c, t->left);
-			gmove(&nod1, c);
-			gmove(t->left, &nod1);
-			zapreg(t->left);
-		}
-		if(t->right->reg != D_DX) {
-			d = &nod4;
-			regsalloc(d, t->right);
-			gmove(&nod2, d);
-			gmove(t->right, &nod2);
-			zapreg(t->right);
-		}
-		if(c != Z || d != Z) {
-			s = regpair(Z, n);
-			s->left = &nod1;
-			s->right = &nod2;
-		}
-		else
-			s = t;
-		if(r->op == OCONST) {
-			if(hi64v(r) == 0)
-				biggen(s, r, Z, 0, mulc32, nil);
-			else
-				biggen(s, r, Z, 0, mulc64, nil);
-		}
-		else
-			biggen(s, r, Z, 0, mull, nil);
-		instpair(t, Z);
-		if(c != Z) {
-			gmove(&nod1, t->left);
-			gmove(&nod3, &nod1);
-		}
-		if(d != Z) {
-			gmove(&nod2, t->right);
-			gmove(&nod4, &nod2);
-		}
-		if(r->op == OREGPAIR)
-			freepair(r);
-		if(!m)
-			storepair(t, l, 0);
-		if(l == &nod5)
-			regfree(l);
-		if(!dr) {
-			if(nn != Z)
-				storepair(t, nn, 1);
-			else
-				freepair(t);
-		}
-		return 1;
-
-	case OASADD:
-		args = ADDargs;
-		goto vasop;
-	case OASAND:
-		args = ANDargs;
-		goto vasop;
-	case OASOR:
-		args = ORargs;
-		goto vasop;
-	case OASSUB:
-		args = SUBargs;
-		goto vasop;
-	case OASXOR:
-		args = XORargs;
-		goto vasop;
-
-	vasop:
-		l = n->left;
-		r = n->right;
-		dr = nn != Z && nn->op == OREGPAIR;
-		m = 0;
-		if(l->complex > r->complex) {
-			if(!vaddr(l, 1)) {
-				reglcgen(&nod1, l, Z);
-				l = &nod1;
-			}
-			if(!vaddr(r, 1) || nn != Z || r->op == OCONST) {
-				if(dr)
-					t = nn;
-				else
-					t = regpair(Z, r);
-				sugen(r, t, 8);
-				r = t;
-				m = 1;
-			}
-		}
-		else {
-			if(!vaddr(r, 1) || nn != Z || r->op == OCONST) {
-				if(dr)
-					t = nn;
-				else
-					t = regpair(Z, r);
-				sugen(r, t, 8);
-				r = t;
-				m = 1;
-			}
-			if(!vaddr(l, 1)) {
-				reglcgen(&nod1, l, Z);
-				l = &nod1;
-			}
-		}
-		if(nn != Z) {
-			if(n->op == OASSUB)
-				biggen(l, r, Z, 0, sub10, args);
-			else
-				biggen(r, l, Z, 0, binoptmp, args);
-			storepair(r, l, 0);
-		}
-		else {
-			if(m)
-				biggen(l, r, Z, 0, binop00, args);
-			else
-				biggen(l, r, Z, 0, binoptmp, args);
-		}
-		if(l == &nod1)
-			regfree(&nod1);
-		if(m) {
-			if(nn == Z)
-				freepair(r);
-			else if(!dr)
-				storepair(r, nn, 1);
-		}
-		return 1;
-
-	case OASASHL:
-		args = nil;
-		optab = asshlltab;
-		goto assh;
-	case OASLSHR:
-		args = shrlargs;
-		optab = asshrltab;
-		goto assh;
-	case OASASHR:
-		args = sarlargs;
-		optab = asshrltab;
-		goto assh;
-
-	assh:
-		c = Z;
-		l = n->left;
-		r = n->right;
-		if(r->op == OCONST) {
-			m = r->vconst & 63;
-			if(m < 32)
-				m = SAclo;
-			else if(m == 32)
-				m = SAc32;
-			else
-				m = SAchi;
-		}
-		else
-			m = SAgen;
-		if(l->complex > r->complex) {
-			if(!vaddr(l, 0)) {
-				reglcgen(&nod1, l, Z);
-				l = &nod1;
-			}
-			if(m == SAgen) {
-				t = &nod2;
-				if(l->reg == D_CX) {
-					regalloc(t, r, Z);
-					gmove(l, t);
-					l->reg = t->reg;
-					t->reg = D_CX;
-				}
-				else
-					c = snarfreg(nn, t, D_CX, r, &nod3);
-				cgen(r, t);
-				r = t;
-			}
-		}
-		else {
-			if(m == SAgen) {
-				t = &nod2;
-				c = snarfreg(nn, t, D_CX, r, &nod3);
-				cgen(r, t);
-				r = t;
-			}
-			if(!vaddr(l, 0)) {
-				reglcgen(&nod1, l, Z);
-				l = &nod1;
-			}
-		}
-
-		if(nn != Z) {
-			m += SAdgen - SAgen;
-			d = regpair(nn, n);
-			instpair(d, Z);
-			biggen(l, r, d, 0, optab[m], args);
-			if(l == &nod1) {
-				regfree(&nod1);
-				l = Z;
-			}
-			if(r == &nod2 && c == Z) {
-				regfree(&nod2);
-				r = Z;
-			}
-			if(d != nn)
-				storepair(d, nn, 1);
-		}
-		else
-			biggen(l, r, Z, 0, optab[m], args);
-
-		if(c != Z) {
-			gins(AMOVL, c, r);
-			regfree(c);
-		}
-		if(l == &nod1)
-			regfree(&nod1);
-		if(r == &nod2)
-			regfree(&nod2);
-		return 1;
-
-	case OPOSTINC:
-		args = ADDargs;
-		cp = incdecpost;
-		goto vinc;
-	case OPOSTDEC:
-		args = SUBargs;
-		cp = incdecpost;
-		goto vinc;
-	case OPREINC:
-		args = ADDargs;
-		cp = incdecpre;
-		goto vinc;
-	case OPREDEC:
-		args = SUBargs;
-		cp = incdecpre;
-		goto vinc;
-
-	vinc:
-		l = n->left;
-		if(!vaddr(l, 1)) {
-			reglcgen(&nod1, l, Z);
-			l = &nod1;
-		}
-		
-		if(nn != Z) {
-			d = regpair(nn, n);
-			instpair(d, Z);
-			biggen(l, Z, d, 0, cp, args);
-			if(l == &nod1) {
-				regfree(&nod1);
-				l = Z;
-			}
-			if(d != nn)
-				storepair(d, nn, 1);
-		}
-		else
-			biggen(l, Z, Z, 0, incdec, args);
-
-		if(l == &nod1)
-			regfree(&nod1);
-		return 1;
-
-	case OCAST:
-		l = n->left;
-		if(typev[l->type->etype]) {
-			if(!vaddr(l, 1)) {
-				if(l->complex + 1 > nn->complex) {
-					d = regpair(Z, l);
-					sugen(l, d, 8);
-					if(!vaddr(nn, 1)) {
-						reglcgen(&nod1, nn, Z);
-						r = &nod1;
-					}
-					else
-						r = nn;
-				}
-				else {
-					if(!vaddr(nn, 1)) {
-						reglcgen(&nod1, nn, Z);
-						r = &nod1;
-					}
-					else
-						r = nn;
-					d = regpair(Z, l);
-					sugen(l, d, 8);
-				}
-//				d->left->type = r->type;
-				d->left->type = types[TLONG];
-				gmove(d->left, r);
-				freepair(d);
-			}
-			else {
-				if(nn->op != OREGISTER && !vaddr(nn, 1)) {
-					reglcgen(&nod1, nn, Z);
-					r = &nod1;
-				}
-				else
-					r = nn;
-//				l->type = r->type;
-				l->type = types[TLONG];
-				gmove(l, r);
-			}
-			if(r != nn)
-				regfree(r);
-		}
-		else {
-			if(typeu[l->type->etype] || cond(l->op))
-				si = TUNSIGNED;
-			else
-				si = TSIGNED;
-			regalloc(&nod1, l, Z);
-			cgen(l, &nod1);
-			if(nn->op == OREGPAIR) {
-				m = instpair(nn, &nod1);
-				biggen(&nod1, Z, nn, si == TSIGNED, castrp, nil);
-			}
-			else {
-				m = 0;
-				if(!vaddr(nn, si != TSIGNED)) {
-					dt = nn->type;
-					nn->type = types[TLONG];
-					reglcgen(&nod2, nn, Z);
-					nn->type = dt;
-					nn = &nod2;
-				}
-				dt = nn->type;
-				nn->type = types[TLONG];
-				biggen(&nod1, Z, nn, si == TSIGNED, castrpa, nil);
-				nn->type = dt;
-				if(nn == &nod2)
-					regfree(&nod2);
-			}
-			if(!m)
-				regfree(&nod1);
-		}
-		return 1;
-
-	default:
-		if(n->op == OREGPAIR) {
-			storepair(n, nn, 1);
-			return 1;
-		}
-		if(nn->op == OREGPAIR) {
-			loadpair(n, nn);
-			return 1;
-		}
-		return 0;
-	}
-finished:
-	if(d != nn)
-		storepair(d, nn, 1);
-	return 1;
-}
-
-void
-testv(Node *n, int true)
-{
-	Type *t;
-	Node *nn, nod;
-
-	switch(n->op) {
-	case OINDREG:
-	case ONAME:
-		biggen(n, Z, Z, true, testi, nil);
-		break;
-
-	default:
-		n = vfunc(n, n);
-		if(n->addable >= INDEXED) {
-			t = n->type;
-			n->type = types[TLONG];
-			reglcgen(&nod, n, Z);
-			n->type = t;
-			n = &nod;
-			biggen(n, Z, Z, true, testi, nil);
-			if(n == &nod)
-				regfree(n);
-		}
-		else {
-			nn = regpair(Z, n);
-			sugen(n, nn, 8);
-			biggen(nn, Z, Z, true, testi, nil);
-			freepair(nn);
-		}
-	}
-}
diff --git a/src/cmd/8c/div.c b/src/cmd/8c/div.c
deleted file mode 100644
index 1494505..0000000
--- a/src/cmd/8c/div.c
+++ /dev/null
@@ -1,236 +0,0 @@
-// Inferno utils/8c/div.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8c/div.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include "gc.h"
-
-/*
- * Based on: Granlund, T.; Montgomery, P.L.
- * "Division by Invariant Integers using Multiplication".
- * SIGPLAN Notices, Vol. 29, June 1994, page 61.
- */
-
-#define	TN(n)	((uvlong)1 << (n))
-#define	T31	TN(31)
-#define	T32	TN(32)
-
-int
-multiplier(uint32 d, int p, uvlong *mp)
-{
-	int l;
-	uvlong mlo, mhi, tlo, thi;
-
-	l = topbit(d - 1) + 1;
-	mlo = (((TN(l) - d) << 32) / d) + T32;
-	if(l + p == 64)
-		mhi = (((TN(l) + 1 - d) << 32) / d) + T32;
-	else
-		mhi = (TN(32 + l) + TN(32 + l - p)) / d;
-	/*assert(mlo < mhi);*/
-	while(l > 0) {
-		tlo = mlo >> 1;
-		thi = mhi >> 1;
-		if(tlo == thi)
-			break;
-		mlo = tlo;
-		mhi = thi;
-		l--;
-	}
-	*mp = mhi;
-	return l;
-}
-
-int
-sdiv(uint32 d, uint32 *mp, int *sp)
-{
-	int s;
-	uvlong m;
-
-	s = multiplier(d, 32 - 1, &m);
-	*mp = m;
-	*sp = s;
-	if(m >= T31)
-		return 1;
-	else
-		return 0;
-}
-
-int
-udiv(uint32 d, uint32 *mp, int *sp, int *pp)
-{
-	int p, s;
-	uvlong m;
-
-	s = multiplier(d, 32, &m);
-	p = 0;
-	if(m >= T32) {
-		while((d & 1) == 0) {
-			d >>= 1;
-			p++;
-		}
-		s = multiplier(d, 32 - p, &m);
-	}
-	*mp = m;
-	*pp = p;
-	if(m >= T32) {
-		/*assert(p == 0);*/
-		*sp = s - 1;
-		return 1;
-	}
-	else {
-		*sp = s;
-		return 0;
-	}
-}
-
-void
-sdivgen(Node *l, Node *r, Node *ax, Node *dx)
-{
-	int a, s;
-	uint32 m;
-	vlong c;
-
-	c = r->vconst;
-	if(c < 0)
-		c = -c;
-	a = sdiv(c, &m, &s);
-//print("a=%d i=%d s=%d m=%ux\n", a, (int32)r->vconst, s, m);
-	gins(AMOVL, nodconst(m), ax);
-	gins(AIMULL, l, Z);
-	gins(AMOVL, l, ax);
-	if(a)
-		gins(AADDL, ax, dx);
-	gins(ASHRL, nodconst(31), ax);
-	gins(ASARL, nodconst(s), dx);
-	gins(AADDL, ax, dx);
-	if(r->vconst < 0)
-		gins(ANEGL, Z, dx);
-}
-
-void
-udivgen(Node *l, Node *r, Node *ax, Node *dx)
-{
-	int a, s, t;
-	uint32 m;
-	Node nod;
-
-	a = udiv(r->vconst, &m, &s, &t);
-//print("a=%ud i=%d p=%d s=%d m=%ux\n", a, (int32)r->vconst, t, s, m);
-	if(t != 0) {
-		gins(AMOVL, l, ax);
-		gins(ASHRL, nodconst(t), ax);
-		gins(AMOVL, nodconst(m), dx);
-		gins(AMULL, dx, Z);
-	}
-	else if(a) {
-		if(l->op != OREGISTER) {
-			regalloc(&nod, l, Z);
-			gins(AMOVL, l, &nod);
-			l = &nod;
-		}
-		gins(AMOVL, nodconst(m), ax);
-		gins(AMULL, l, Z);
-		gins(AADDL, l, dx);
-		gins(ARCRL, nodconst(1), dx);
-		if(l == &nod)
-			regfree(l);
-	}
-	else {
-		gins(AMOVL, nodconst(m), ax);
-		gins(AMULL, l, Z);
-	}
-	if(s != 0)
-		gins(ASHRL, nodconst(s), dx);
-}
-
-void
-sext(Node *d, Node *s, Node *l)
-{
-	if(s->reg == D_AX && !nodreg(d, Z, D_DX)) {
-		reg[D_DX]++;
-		gins(ACDQ, Z, Z);
-	}
-	else {
-		regalloc(d, l, Z);
-		gins(AMOVL, s, d);
-		gins(ASARL, nodconst(31), d);
-	}
-}
-
-void
-sdiv2(int32 c, int v, Node *l, Node *n)
-{
-	Node nod;
-
-	if(v > 0) {
-		if(v > 1) {
-			sext(&nod, n, l);
-			gins(AANDL, nodconst((1 << v) - 1), &nod);
-			gins(AADDL, &nod, n);
-			regfree(&nod);
-		}
-		else {
-			gins(ACMPL, n, nodconst(0x80000000));
-			gins(ASBBL, nodconst(-1), n);
-		}
-		gins(ASARL, nodconst(v), n);
-	}
-	if(c < 0)
-		gins(ANEGL, Z, n);
-}
-
-void
-smod2(int32 c, int v, Node *l, Node *n)
-{
-	Node nod;
-
-	if(c == 1) {
-		zeroregm(n);
-		return;
-	}
-
-	sext(&nod, n, l);
-	if(v == 0) {
-		zeroregm(n);
-		gins(AXORL, &nod, n);
-		gins(ASUBL, &nod, n);
-	}
-	else if(v > 1) {
-		gins(AANDL, nodconst((1 << v) - 1), &nod);
-		gins(AADDL, &nod, n);
-		gins(AANDL, nodconst((1 << v) - 1), n);
-		gins(ASUBL, &nod, n);
-	}
-	else {
-		gins(AANDL, nodconst(1), n);
-		gins(AXORL, &nod, n);
-		gins(ASUBL, &nod, n);
-	}
-	regfree(&nod);
-}
diff --git a/src/cmd/8c/doc.go b/src/cmd/8c/doc.go
deleted file mode 100644
index 0d07db1..0000000
--- a/src/cmd/8c/doc.go
+++ /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.
-
-// +build ignore
-
-/*
-
-8c is a version of the Plan 9 C compiler.  The original is documented at
-
-	http://plan9.bell-labs.com/magic/man2html/1/8c
-
-Its target architecture is the x86, referred to by these tools for historical reasons as 386.
-
-*/
-package main
diff --git a/src/cmd/8c/gc.h b/src/cmd/8c/gc.h
deleted file mode 100644
index aa3888d..0000000
--- a/src/cmd/8c/gc.h
+++ /dev/null
@@ -1,364 +0,0 @@
-// Inferno utils/8c/gc.h
-// http://code.google.com/p/inferno-os/source/browse/utils/8c/gc.h
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include	<u.h>
-#include	"../cc/cc.h"
-#include	"../8l/8.out.h"
-
-/*
- * 8c/386
- * Intel 386
- */
-#define	SZ_CHAR		1
-#define	SZ_SHORT	2
-#define	SZ_INT		4
-#define	SZ_LONG		4
-#define	SZ_IND		4
-#define	SZ_FLOAT	4
-#define	SZ_VLONG	8
-#define	SZ_DOUBLE	8
-#define	FNX		100
-
-typedef	struct	Case	Case;
-typedef	struct	C1	C1;
-typedef	struct	Reg	Reg;
-typedef	struct	Rgn	Rgn;
-typedef	struct	Renv	Renv;
-
-EXTERN	struct
-{
-	Node*	regtree;
-	Node*	basetree;
-	short	scale;
-	short	reg;
-	short	ptr;
-} idx;
-
-#define	A	((Addr*)0)
-
-#define	INDEXED	9
-
-#define	P	((Prog*)0)
-
-struct	Case
-{
-	Case*	link;
-	int32	val;
-	int32	label;
-	char	def;
-	char	isv;
-};
-#define	C	((Case*)0)
-
-struct	C1
-{
-	int32	val;
-	int32	label;
-};
-
-struct	Reg
-{
-	int32	pc;
-	int32	rpo;		/* reverse post ordering */
-
-	Bits	set;
-	Bits	use1;
-	Bits	use2;
-
-	Bits	refbehind;
-	Bits	refahead;
-	Bits	calbehind;
-	Bits	calahead;
-	Bits	regdiff;
-	Bits	act;
-
-	int32	regu;
-	int32	loop;		/* could be shorter */
-
-	Reg*	log5;
-	int32	active;
-
-	Reg*	p1;
-	Reg*	p2;
-	Reg*	p2link;
-	Reg*	s1;
-	Reg*	s2;
-	Reg*	link;
-	Prog*	prog;
-};
-#define	R	((Reg*)0)
-
-struct	Renv
-{
-	int	safe;
-	Node	base;
-	Node*	saved;
-	Node*	scope;
-};
-
-#define	NRGN	600
-struct	Rgn
-{
-	Reg*	enter;
-	short	cost;
-	short	varno;
-	short	regno;
-};
-
-EXTERN	int32	breakpc;
-EXTERN	int32	nbreak;
-EXTERN	Case*	cases;
-EXTERN	Node	constnode;
-EXTERN	Node	fconstnode;
-EXTERN	int32	continpc;
-EXTERN	int32	curarg;
-EXTERN	int32	cursafe;
-EXTERN	Prog*	lastp;
-EXTERN	int32	maxargsafe;
-EXTERN	int	mnstring;
-EXTERN	Node*	nodrat;
-EXTERN	Node*	nodret;
-EXTERN	Node*	nodsafe;
-EXTERN	int32	nrathole;
-EXTERN	int32	nstring;
-EXTERN	Prog*	p;
-EXTERN	int32	pc;
-EXTERN	Node	regnode;
-EXTERN	Node	fregnode0;
-EXTERN	Node	fregnode1;
-EXTERN	char	string[NSNAME];
-EXTERN	Sym*	symrathole;
-EXTERN	Node	znode;
-EXTERN	Prog	zprog;
-EXTERN	int	reg[D_NONE];
-EXTERN	int32	exregoffset;
-EXTERN	int32	exfregoffset;
-
-#define	BLOAD(r)	band(bnot(r->refbehind), r->refahead)
-#define	BSTORE(r)	band(bnot(r->calbehind), r->calahead)
-#define	LOAD(r)		(~r->refbehind.b[z] & r->refahead.b[z])
-#define	STORE(r)	(~r->calbehind.b[z] & r->calahead.b[z])
-
-#define	bset(a,n)	((a).b[(n)/32]&(1L<<(n)%32))
-
-#define	CLOAD	5
-#define	CREF	5
-#define	CINF	1000
-#define	LOOP	3
-
-EXTERN	Rgn	region[NRGN];
-EXTERN	Rgn*	rgp;
-EXTERN	int	nregion;
-EXTERN	int	nvar;
-
-EXTERN	Bits	externs;
-EXTERN	Bits	params;
-EXTERN	Bits	consts;
-EXTERN	Bits	addrs;
-
-EXTERN	int32	regbits;
-EXTERN	int32	exregbits;
-
-EXTERN	int	change;
-EXTERN	int	suppress;
-
-EXTERN	Reg*	firstr;
-EXTERN	Reg*	lastr;
-EXTERN	Reg	zreg;
-EXTERN	Reg*	freer;
-EXTERN	int32*	idom;
-EXTERN	Reg**	rpo2r;
-EXTERN	int32	maxnr;
-
-extern	char*	anames[];
-
-/*
- * sgen.c
- */
-void	codgen(Node*, Node*);
-void	gen(Node*);
-void	noretval(int);
-void	usedset(Node*, int);
-void	xcom(Node*);
-void	indx(Node*);
-int	bcomplex(Node*, Node*);
-Prog*	gtext(Sym*, int32);
-vlong	argsize(int);
-
-/*
- * cgen.c
- */
-void	zeroregm(Node*);
-void	cgen(Node*, Node*);
-void	reglcgen(Node*, Node*, Node*);
-void	lcgen(Node*, Node*);
-void	bcgen(Node*, int);
-void	boolgen(Node*, int, Node*);
-void	sugen(Node*, Node*, int32);
-int	needreg(Node*, int);
-
-/*
- * cgen64.c
- */
-int	vaddr(Node*, int);
-void	loadpair(Node*, Node*);
-int	cgen64(Node*, Node*);
-void	testv(Node*, int);
-
-/*
- * txt.c
- */
-void	ginit(void);
-void	gclean(void);
-void	nextpc(void);
-void	gargs(Node*, Node*, Node*);
-void	garg1(Node*, Node*, Node*, int, Node**);
-Node*	nodconst(int32);
-Node*	nodfconst(double);
-int	nodreg(Node*, Node*, int);
-int	isreg(Node*, int);
-void	regret(Node*, Node*, Type*, int);
-void	regalloc(Node*, Node*, Node*);
-void	regfree(Node*);
-void	regialloc(Node*, Node*, Node*);
-void	regsalloc(Node*, Node*);
-void	regaalloc1(Node*, Node*);
-void	regaalloc(Node*, Node*);
-void	regind(Node*, Node*);
-void	gprep(Node*, Node*);
-void	naddr(Node*, Addr*);
-void	gmove(Node*, Node*);
-void	gins(int a, Node*, Node*);
-void	fgopcode(int, Node*, Node*, int, int);
-void	gopcode(int, Type*, Node*, Node*);
-int	samaddr(Node*, Node*);
-void	gbranch(int);
-void	patch(Prog*, int32);
-int	sconst(Node*);
-void	gpseudo(int, Sym*, Node*);
-void	gprefetch(Node*);
-void	gpcdata(int, int);
-
-/*
- * swt.c
- */
-int	swcmp(const void*, const void*);
-void	doswit(Node*);
-void	swit1(C1*, int, int32, Node*);
-void	swit2(C1*, int, int32, Node*);
-void	newcase(void);
-void	bitload(Node*, Node*, Node*, Node*, Node*);
-void	bitstore(Node*, Node*, Node*, Node*, Node*);
-int32	outstring(char*, int32);
-void	nullwarn(Node*, Node*);
-void	sextern(Sym*, Node*, int32, int32);
-void	gextern(Sym*, Node*, int32, int32);
-void	outcode(void);
-
-/*
- * list
- */
-void	listinit(void);
-
-/*
- * reg.c
- */
-Reg*	rega(void);
-int	rcmp(const void*, const void*);
-void	regopt(Prog*);
-void	addmove(Reg*, int, int, int);
-Bits	mkvar(Reg*, Addr*);
-void	prop(Reg*, Bits, Bits);
-void	loopit(Reg*, int32);
-void	synch(Reg*, Bits);
-uint32	allreg(uint32, Rgn*);
-void	paint1(Reg*, int);
-uint32	paint2(Reg*, int);
-void	paint3(Reg*, int, int32, int);
-void	addreg(Addr*, int);
-
-/*
- * peep.c
- */
-void	peep(void);
-void	excise(Reg*);
-Reg*	uniqp(Reg*);
-Reg*	uniqs(Reg*);
-int	regtyp(Addr*);
-int	anyvar(Addr*);
-int	subprop(Reg*);
-int	copyprop(Reg*);
-int	copy1(Addr*, Addr*, Reg*, int);
-int	copyu(Prog*, Addr*, Addr*);
-
-int	copyas(Addr*, Addr*);
-int	copyau(Addr*, Addr*);
-int	copysub(Addr*, Addr*, Addr*, int);
-int	copysub1(Prog*, Addr*, Addr*, int);
-
-int32	RtoB(int);
-int32	FtoB(int);
-int	BtoR(int32);
-int	BtoF(int32);
-
-#define	D_HI	D_NONE
-#define	D_LO	D_NONE
-
-/*
- * bound
- */
-void	comtarg(void);
-
-/*
- * com64
- */
-int	cond(int);
-int	com64(Node*);
-void	com64init(void);
-void	bool64(Node*);
-int32	lo64v(Node*);
-int32	hi64v(Node*);
-Node*	lo64(Node*);
-Node*	hi64(Node*);
-
-/*
- * div/mul
- */
-void	sdivgen(Node*, Node*, Node*, Node*);
-void	udivgen(Node*, Node*, Node*, Node*);
-void	sdiv2(int32, int, Node*, Node*);
-void	smod2(int32, int, Node*, Node*);
-void	mulgen(Type*, Node*, Node*);
-void	genmuladd(Node*, Node*, int, Node*);
-void	shiftit(Type*, Node*, Node*);
-
-/* wrecklessly steal a field */
-
-#define	rplink	label
diff --git a/src/cmd/8c/list.c b/src/cmd/8c/list.c
deleted file mode 100644
index 1730ecc..0000000
--- a/src/cmd/8c/list.c
+++ /dev/null
@@ -1,38 +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 at 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 at 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.
-
-#define EXTERN
-#include "gc.h"
-
-void
-listinit(void)
-{
-	listinit8();
-}
diff --git a/src/cmd/8c/machcap.c b/src/cmd/8c/machcap.c
deleted file mode 100644
index 61e5aad..0000000
--- a/src/cmd/8c/machcap.c
+++ /dev/null
@@ -1,116 +0,0 @@
-// Inferno utils/8c/machcap.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8c/machcap.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include "gc.h"
-
-int
-machcap(Node *n)
-{
-
-	if(n == Z)
-		return 1;	/* test */
-
-	switch(n->op) {
-	case OMUL:
-	case OLMUL:
-	case OASMUL:
-	case OASLMUL:
-		if(typechl[n->type->etype])
-			return 1;
-		if(typev[n->type->etype]) {
-				return 1;
-		}
-		break;
-
-	case OCOM:
-	case ONEG:
-	case OADD:
-	case OAND:
-	case OOR:
-	case OSUB:
-	case OXOR:
-	case OASHL:
-	case OLSHR:
-	case OASHR:
-		if(typechlv[n->left->type->etype])
-			return 1;
-		break;
-
-	case OCAST:
-		if(typev[n->type->etype]) {
-			if(typechlp[n->left->type->etype])
-				return 1;
-		}
-		else if(!typefd[n->type->etype]) {
-			if(typev[n->left->type->etype])
-				return 1;
-		}
-		break;
-
-	case OCOND:
-	case OCOMMA:
-	case OLIST:
-	case OANDAND:
-	case OOROR:
-	case ONOT:
-		return 1;
-
-	case OASADD:
-	case OASSUB:
-	case OASAND:
-	case OASOR:
-	case OASXOR:
-		return 1;
-
-	case OASASHL:
-	case OASASHR:
-	case OASLSHR:
-		return 1;
-
-	case OPOSTINC:
-	case OPOSTDEC:
-	case OPREINC:
-	case OPREDEC:
-		return 1;
-
-	case OEQ:
-	case ONE:
-	case OLE:
-	case OGT:
-	case OLT:
-	case OGE:
-	case OHI:
-	case OHS:
-	case OLO:
-	case OLS:
-		return 1;
-	}
-	return 0;
-}
diff --git a/src/cmd/8c/mul.c b/src/cmd/8c/mul.c
deleted file mode 100644
index 9955e76..0000000
--- a/src/cmd/8c/mul.c
+++ /dev/null
@@ -1,458 +0,0 @@
-// Inferno utils/8c/mul.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8c/mul.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include "gc.h"
-
-typedef struct	Malg	Malg;
-typedef struct	Mparam	Mparam;
-
-struct	Malg
-{
-	schar	vals[10];
-};
-
-struct	Mparam
-{
-	uint32	value;
-	schar	alg;
-	char	neg;
-	char	shift;
-	char	arg;
-	schar	off;
-};
-
-static	Mparam	multab[32];
-static	int	mulptr;
-
-static	Malg	malgs[]	=
-{
-	{0, 100},
-	{-1, 1, 100},
-	{-9, -5, -3, 3, 5, 9, 100},
-	{6, 10, 12, 18, 20, 24, 36, 40, 72, 100},
-	{-8, -4, -2, 2, 4, 8, 100},
-};
-
-/*
- * return position of lowest 1
- */
-int
-lowbit(uint32 v)
-{
-	int s, i;
-	uint32 m;
-
-	s = 0;
-	m = 0xFFFFFFFFUL;
-	for(i = 16; i > 0; i >>= 1) {
-		m >>= i;
-		if((v & m) == 0) {
-			v >>= i;
-			s += i;
-		}
-	}
-	return s;
-}
-
-void
-genmuladd(Node *d, Node *s, int m, Node *a)
-{
-	Node nod;
-
-	nod.op = OINDEX;
-	nod.left = a;
-	nod.right = s;
-	nod.scale = m;
-	nod.type = types[TIND];
-	nod.xoffset = 0;
-	xcom(&nod);
-	gopcode(OADDR, d->type, &nod, d);
-}
-
-void
-mulparam(uint32 m, Mparam *mp)
-{
-	int c, i, j, n, o, q, s;
-	int bc, bi, bn, bo, bq, bs, bt;
-	schar *p;
-	int32 u;
-	uint32 t;
-
-	bc = bq = 10;
-	bi = bn = bo = bs = bt = 0;
-	for(i = 0; i < nelem(malgs); i++) {
-		for(p = malgs[i].vals, j = 0; (o = p[j]) < 100; j++)
-		for(s = 0; s < 2; s++) {
-			c = 10;
-			q = 10;
-			u = m - o;
-			if(u == 0)
-				continue;
-			if(s) {
-				o = -o;
-				if(o > 0)
-					continue;
-				u = -u;
-			}
-			n = lowbit(u);
-			t = (uint32)u >> n;
-			switch(i) {
-			case 0:
-				if(t == 1) {
-					c = s + 1;
-					q = 0;
-					break;
-				}
-				switch(t) {
-				case 3:
-				case 5:
-				case 9:
-					c = s + 1;
-					if(n)
-						c++;
-					q = 0;
-					break;
-				}
-				if(s)
-					break;
-				switch(t) {
-				case 15:
-				case 25:
-				case 27:
-				case 45:
-				case 81:
-					c = 2;
-					if(n)
-						c++;
-					q = 1;
-					break;
-				}
-				break;
-			case 1:
-				if(t == 1) {
-					c = 3;
-					q = 3;
-					break;
-				}
-				switch(t) {
-				case 3:
-				case 5:
-				case 9:
-					c = 3;
-					q = 2;
-					break;
-				}
-				break;
-			case 2:
-				if(t == 1) {
-					c = 3;
-					q = 2;
-					break;
-				}
-				break;
-			case 3:
-				if(s)
-					break;
-				if(t == 1) {
-					c = 3;
-					q = 1;
-					break;
-				}
-				break;
-			case 4:
-				if(t == 1) {
-					c = 3;
-					q = 0;
-					break;
-				}
-				break;
-			}
-			if(c < bc || (c == bc && q > bq)) {
-				bc = c;
-				bi = i;
-				bn = n;
-				bo = o;
-				bq = q;
-				bs = s;
-				bt = t;
-			}
-		}
-	}
-	mp->value = m;
-	if(bc <= 3) {
-		mp->alg = bi;
-		mp->shift = bn;
-		mp->off = bo;
-		mp->neg = bs;
-		mp->arg = bt;
-	}
-	else
-		mp->alg = -1;
-}
-
-int
-m0(int a)
-{
-	switch(a) {
-	case -2:
-	case 2:
-		return 2;
-	case -3:
-	case 3:
-		return 2;
-	case -4:
-	case 4:
-		return 4;
-	case -5:
-	case 5:
-		return 4;
-	case 6:
-		return 2;
-	case -8:
-	case 8:
-		return 8;
-	case -9:
-	case 9:
-		return 8;
-	case 10:
-		return 4;
-	case 12:
-		return 2;
-	case 15:
-		return 2;
-	case 18:
-		return 8;
-	case 20:
-		return 4;
-	case 24:
-		return 2;
-	case 25:
-		return 4;
-	case 27:
-		return 2;
-	case 36:
-		return 8;
-	case 40:
-		return 4;
-	case 45:
-		return 4;
-	case 72:
-		return 8;
-	case 81:
-		return 8;
-	}
-	diag(Z, "bad m0");
-	return 0;
-}
-
-int
-m1(int a)
-{
-	switch(a) {
-	case 15:
-		return 4;
-	case 25:
-		return 4;
-	case 27:
-		return 8;
-	case 45:
-		return 8;
-	case 81:
-		return 8;
-	}
-	diag(Z, "bad m1");
-	return 0;
-}
-
-int
-m2(int a)
-{
-	switch(a) {
-	case 6:
-		return 2;
-	case 10:
-		return 2;
-	case 12:
-		return 4;
-	case 18:
-		return 2;
-	case 20:
-		return 4;
-	case 24:
-		return 8;
-	case 36:
-		return 4;
-	case 40:
-		return 8;
-	case 72:
-		return 8;
-	}
-	diag(Z, "bad m2");
-	return 0;
-}
-
-void
-shiftit(Type *t, Node *s, Node *d)
-{
-	int32 c;
-
-	c = (int32)s->vconst & 31;
-	switch(c) {
-	case 0:
-		break;
-	case 1:
-		gopcode(OADD, t, d, d);
-		break;
-	default:
-		gopcode(OASHL, t, s, d);
-	}
-}
-
-static int
-mulgen1(uint32 v, Node *n)
-{
-	int i, o;
-	Mparam *p;
-	Node nod, nods;
-
-	for(i = 0; i < nelem(multab); i++) {
-		p = &multab[i];
-		if(p->value == v)
-			goto found;
-	}
-
-	p = &multab[mulptr];
-	if(++mulptr == nelem(multab))
-		mulptr = 0;
-
-	mulparam(v, p);
-
-found:
-//	print("v=%.x a=%d n=%d s=%d g=%d o=%d \n", p->value, p->alg, p->neg, p->shift, p->arg, p->off);
-	if(p->alg < 0)
-		return 0;
-
-	nods = *nodconst(p->shift);
-
-	o = OADD;
-	if(p->alg > 0) {
-		regalloc(&nod, n, Z);
-		if(p->off < 0)
-			o = OSUB;
-	}
-
-	switch(p->alg) {
-	case 0:
-		switch(p->arg) {
-		case 1:
-			shiftit(n->type, &nods, n);
-			break;
-		case 15:
-		case 25:
-		case 27:
-		case 45:
-		case 81:
-			genmuladd(n, n, m1(p->arg), n);
-			/* fall thru */
-		case 3:
-		case 5:
-		case 9:
-			genmuladd(n, n, m0(p->arg), n);
-			shiftit(n->type, &nods, n);
-			break;
-		default:
-			goto bad;
-		}
-		if(p->neg == 1)
-			gins(ANEGL, Z, n);
-		break;
-	case 1:
-		switch(p->arg) {
-		case 1:
-			gmove(n, &nod);
-			shiftit(n->type, &nods, &nod);
-			break;
-		case 3:
-		case 5:
-		case 9:
-			genmuladd(&nod, n, m0(p->arg), n);
-			shiftit(n->type, &nods, &nod);
-			break;
-		default:
-			goto bad;
-		}
-		if(p->neg)
-			gopcode(o, n->type, &nod, n);
-		else {
-			gopcode(o, n->type, n, &nod);
-			gmove(&nod, n);
-		}
-		break;
-	case 2:
-		genmuladd(&nod, n, m0(p->off), n);
-		shiftit(n->type, &nods, n);
-		goto comop;
-	case 3:
-		genmuladd(&nod, n, m0(p->off), n);
-		shiftit(n->type, &nods, n);
-		genmuladd(n, &nod, m2(p->off), n);
-		break;
-	case 4:
-		genmuladd(&nod, n, m0(p->off), nodconst(0));
-		shiftit(n->type, &nods, n);
-		goto comop;
-	default:
-		diag(Z, "bad mul alg");
-		break;
-	comop:
-		if(p->neg) {
-			gopcode(o, n->type, n, &nod);
-			gmove(&nod, n);
-		}
-		else
-			gopcode(o, n->type, &nod, n);
-	}
-
-	if(p->alg > 0)
-		regfree(&nod);
-
-	return 1;
-
-bad:
-	diag(Z, "mulgen botch");
-	return 1;
-}
-
-void
-mulgen(Type *t, Node *r, Node *n)
-{
-	if(!mulgen1(r->vconst, n))
-		gopcode(OMUL, t, r, n);
-}
diff --git a/src/cmd/8c/peep.c b/src/cmd/8c/peep.c
deleted file mode 100644
index 4f58fc05..0000000
--- a/src/cmd/8c/peep.c
+++ /dev/null
@@ -1,807 +0,0 @@
-// Inferno utils/8c/peep.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8c/peep.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include "gc.h"
-
-static int
-needc(Prog *p)
-{
-	while(p != P) {
-		switch(p->as) {
-		case AADCL:
-		case ASBBL:
-		case ARCRL:
-			return 1;
-		case AADDL:
-		case ASUBL:
-		case AJMP:
-		case ARET:
-		case ACALL:
-			return 0;
-		default:
-			if(p->to.type == D_BRANCH)
-				return 0;
-		}
-		p = p->link;
-	}
-	return 0;
-}
-
-void
-peep(void)
-{
-	Reg *r, *r1, *r2;
-	Prog *p, *p1;
-	int t;
-
-	/*
-	 * complete R structure
-	 */
-	t = 0;
-	for(r=firstr; r!=R; r=r1) {
-		r1 = r->link;
-		if(r1 == R)
-			break;
-		p = r->prog->link;
-		while(p != r1->prog)
-		switch(p->as) {
-		default:
-			r2 = rega();
-			r->link = r2;
-			r2->link = r1;
-
-			r2->prog = p;
-			r2->p1 = r;
-			r->s1 = r2;
-			r2->s1 = r1;
-			r1->p1 = r2;
-
-			r = r2;
-			t++;
-
-		case ADATA:
-		case AGLOBL:
-		case ANAME:
-		case ASIGNAME:
-			p = p->link;
-		}
-	}
-
-	pc = 0;	/* speculating it won't kill */
-
-loop1:
-
-	t = 0;
-	for(r=firstr; r!=R; r=r->link) {
-		p = r->prog;
-		switch(p->as) {
-		case AMOVL:
-			if(regtyp(&p->to))
-			if(regtyp(&p->from)) {
-				if(copyprop(r)) {
-					excise(r);
-					t++;
-				}
-				if(subprop(r) && copyprop(r)) {
-					excise(r);
-					t++;
-				}
-			}
-			break;
-
-		case AMOVBLSX:
-		case AMOVBLZX:
-		case AMOVWLSX:
-		case AMOVWLZX:
-			if(regtyp(&p->to)) {
-				r1 = uniqs(r);
-				if(r1 != R) {
-					p1 = r1->prog;
-					if(p->as == p1->as && p->to.type == p1->from.type)
-						p1->as = AMOVL;
-				}
-			}
-			break;
-		case AADDL:
-		case AADDW:
-			if(p->from.type != D_CONST || needc(p->link))
-				break;
-			if(p->from.offset == -1){
-				if(p->as == AADDL)
-					p->as = ADECL;
-				else
-					p->as = ADECW;
-				p->from = zprog.from;
-			}
-			else if(p->from.offset == 1){
-				if(p->as == AADDL)
-					p->as = AINCL;
-				else
-					p->as = AINCW;
-				p->from = zprog.from;
-			}
-			break;
-		case ASUBL:
-		case ASUBW:
-			if(p->from.type != D_CONST || needc(p->link))
-				break;
-			if(p->from.offset == -1) {
-				if(p->as == ASUBL)
-					p->as = AINCL;
-				else
-					p->as = AINCW;
-				p->from = zprog.from;
-			}
-			else if(p->from.offset == 1){
-				if(p->as == ASUBL)
-					p->as = ADECL;
-				else
-					p->as = ADECW;
-				p->from = zprog.from;
-			}
-			break;
-		}
-	}
-	if(t)
-		goto loop1;
-}
-
-void
-excise(Reg *r)
-{
-	Prog *p;
-
-	p = r->prog;
-	p->as = ANOP;
-	p->from = zprog.from;
-	p->to = zprog.to;
-}
-
-Reg*
-uniqp(Reg *r)
-{
-	Reg *r1;
-
-	r1 = r->p1;
-	if(r1 == R) {
-		r1 = r->p2;
-		if(r1 == R || r1->p2link != R)
-			return R;
-	} else
-		if(r->p2 != R)
-			return R;
-	return r1;
-}
-
-Reg*
-uniqs(Reg *r)
-{
-	Reg *r1;
-
-	r1 = r->s1;
-	if(r1 == R) {
-		r1 = r->s2;
-		if(r1 == R)
-			return R;
-	} else
-		if(r->s2 != R)
-			return R;
-	return r1;
-}
-
-int
-regtyp(Addr *a)
-{
-	int t;
-
-	t = a->type;
-	if(t >= D_AX && t <= D_DI)
-		return 1;
-	return 0;
-}
-
-/*
- * the idea is to substitute
- * one register for another
- * from one MOV to another
- *	MOV	a, R0
- *	ADD	b, R0	/ no use of R1
- *	MOV	R0, R1
- * would be converted to
- *	MOV	a, R1
- *	ADD	b, R1
- *	MOV	R1, R0
- * hopefully, then the former or latter MOV
- * will be eliminated by copy propagation.
- */
-int
-subprop(Reg *r0)
-{
-	Prog *p;
-	Addr *v1, *v2;
-	Reg *r;
-	int t;
-
-	p = r0->prog;
-	v1 = &p->from;
-	if(!regtyp(v1))
-		return 0;
-	v2 = &p->to;
-	if(!regtyp(v2))
-		return 0;
-	for(r=uniqp(r0); r!=R; r=uniqp(r)) {
-		if(uniqs(r) == R)
-			break;
-		p = r->prog;
-		switch(p->as) {
-		case ACALL:
-			return 0;
-
-		case AIMULL:
-		case AIMULW:
-			if(p->to.type != D_NONE)
-				break;
-
-		case ADIVB:
-		case ADIVL:
-		case ADIVW:
-		case AIDIVB:
-		case AIDIVL:
-		case AIDIVW:
-		case AIMULB:
-		case AMULB:
-		case AMULL:
-		case AMULW:
-
-		case AROLB:
-		case AROLL:
-		case AROLW:
-		case ARORB:
-		case ARORL:
-		case ARORW:
-		case ASALB:
-		case ASALL:
-		case ASALW:
-		case ASARB:
-		case ASARL:
-		case ASARW:
-		case ASHLB:
-		case ASHLL:
-		case ASHLW:
-		case ASHRB:
-		case ASHRL:
-		case ASHRW:
-
-		case AREP:
-		case AREPN:
-
-		case ACWD:
-		case ACDQ:
-
-		case ASTOSB:
-		case ASTOSL:
-		case AMOVSB:
-		case AMOVSL:
-		case AFSTSW:
-			return 0;
-
-		case AMOVL:
-			if(p->to.type == v1->type)
-				goto gotit;
-			break;
-		}
-		if(copyau(&p->from, v2) ||
-		   copyau(&p->to, v2))
-			break;
-		if(copysub(&p->from, v1, v2, 0) ||
-		   copysub(&p->to, v1, v2, 0))
-			break;
-	}
-	return 0;
-
-gotit:
-	copysub(&p->to, v1, v2, 1);
-	if(debug['P']) {
-		print("gotit: %D->%D\n%P", v1, v2, r->prog);
-		if(p->from.type == v2->type)
-			print(" excise");
-		print("\n");
-	}
-	for(r=uniqs(r); r!=r0; r=uniqs(r)) {
-		p = r->prog;
-		copysub(&p->from, v1, v2, 1);
-		copysub(&p->to, v1, v2, 1);
-		if(debug['P'])
-			print("%P\n", r->prog);
-	}
-	t = v1->type;
-	v1->type = v2->type;
-	v2->type = t;
-	if(debug['P'])
-		print("%P last\n", r->prog);
-	return 1;
-}
-
-/*
- * The idea is to remove redundant copies.
- *	v1->v2	F=0
- *	(use v2	s/v2/v1/)*
- *	set v1	F=1
- *	use v2	return fail
- *	-----------------
- *	v1->v2	F=0
- *	(use v2	s/v2/v1/)*
- *	set v1	F=1
- *	set v2	return success
- */
-int
-copyprop(Reg *r0)
-{
-	Prog *p;
-	Addr *v1, *v2;
-	Reg *r;
-
-	p = r0->prog;
-	v1 = &p->from;
-	v2 = &p->to;
-	if(copyas(v1, v2))
-		return 1;
-	for(r=firstr; r!=R; r=r->link)
-		r->active = 0;
-	return copy1(v1, v2, r0->s1, 0);
-}
-
-int
-copy1(Addr *v1, Addr *v2, Reg *r, int f)
-{
-	int t;
-	Prog *p;
-
-	if(r->active) {
-		if(debug['P'])
-			print("act set; return 1\n");
-		return 1;
-	}
-	r->active = 1;
-	if(debug['P'])
-		print("copy %D->%D f=%d\n", v1, v2, f);
-	for(; r != R; r = r->s1) {
-		p = r->prog;
-		if(debug['P'])
-			print("%P", p);
-		if(!f && uniqp(r) == R) {
-			f = 1;
-			if(debug['P'])
-				print("; merge; f=%d", f);
-		}
-		t = copyu(p, v2, A);
-		switch(t) {
-		case 2:	/* rar, can't split */
-			if(debug['P'])
-				print("; %D rar; return 0\n", v2);
-			return 0;
-
-		case 3:	/* set */
-			if(debug['P'])
-				print("; %D set; return 1\n", v2);
-			return 1;
-
-		case 1:	/* used, substitute */
-		case 4:	/* use and set */
-			if(f) {
-				if(!debug['P'])
-					return 0;
-				if(t == 4)
-					print("; %D used+set and f=%d; return 0\n", v2, f);
-				else
-					print("; %D used and f=%d; return 0\n", v2, f);
-				return 0;
-			}
-			if(copyu(p, v2, v1)) {
-				if(debug['P'])
-					print("; sub fail; return 0\n");
-				return 0;
-			}
-			if(debug['P'])
-				print("; sub %D/%D", v2, v1);
-			if(t == 4) {
-				if(debug['P'])
-					print("; %D used+set; return 1\n", v2);
-				return 1;
-			}
-			break;
-		}
-		if(!f) {
-			t = copyu(p, v1, A);
-			if(!f && (t == 2 || t == 3 || t == 4)) {
-				f = 1;
-				if(debug['P'])
-					print("; %D set and !f; f=%d", v1, f);
-			}
-		}
-		if(debug['P'])
-			print("\n");
-		if(r->s2)
-			if(!copy1(v1, v2, r->s2, f))
-				return 0;
-	}
-	return 1;
-}
-
-/*
- * return
- * 1 if v only used (and substitute),
- * 2 if read-alter-rewrite
- * 3 if set
- * 4 if set and used
- * 0 otherwise (not touched)
- */
-int
-copyu(Prog *p, Addr *v, Addr *s)
-{
-
-	switch(p->as) {
-
-	default:
-		if(debug['P'])
-			print("unknown op %A\n", p->as);
-		return 2;
-
-	case ANEGB:
-	case ANEGW:
-	case ANEGL:
-	case ANOTB:
-	case ANOTW:
-	case ANOTL:
-		if(copyas(&p->to, v))
-			return 2;
-		break;
-
-	case ALEAL:	/* lhs addr, rhs store */
-		if(copyas(&p->from, v))
-			return 2;
-
-
-	case ANOP:	/* rhs store */
-	case AMOVL:
-	case AMOVBLSX:
-	case AMOVBLZX:
-	case AMOVWLSX:
-	case AMOVWLZX:
-		if(copyas(&p->to, v)) {
-			if(s != A)
-				return copysub(&p->from, v, s, 1);
-			if(copyau(&p->from, v))
-				return 4;
-			return 3;
-		}
-		goto caseread;
-
-	case AROLB:
-	case AROLL:
-	case AROLW:
-	case ARORB:
-	case ARORL:
-	case ARORW:
-	case ASALB:
-	case ASALL:
-	case ASALW:
-	case ASARB:
-	case ASARL:
-	case ASARW:
-	case ASHLB:
-	case ASHLL:
-	case ASHLW:
-	case ASHRB:
-	case ASHRL:
-	case ASHRW:
-		if(copyas(&p->to, v))
-			return 2;
-		if(copyas(&p->from, v))
-			if(p->from.type == D_CX)
-				return 2;
-		goto caseread;
-
-	case AADDB:	/* rhs rar */
-	case AADDL:
-	case AADDW:
-	case AANDB:
-	case AANDL:
-	case AANDW:
-	case ADECL:
-	case ADECW:
-	case AINCL:
-	case AINCW:
-	case ASUBB:
-	case ASUBL:
-	case ASUBW:
-	case AORB:
-	case AORL:
-	case AORW:
-	case AXORB:
-	case AXORL:
-	case AXORW:
-	case AMOVB:
-	case AMOVW:
-
-	case AFMOVB:
-	case AFMOVBP:
-	case AFMOVD:
-	case AFMOVDP:
-	case AFMOVF:
-	case AFMOVFP:
-	case AFMOVL:
-	case AFMOVLP:
-	case AFMOVV:
-	case AFMOVVP:
-	case AFMOVW:
-	case AFMOVWP:
-	case AFMOVX:
-	case AFMOVXP:
-	case AFADDDP:
-	case AFADDW:
-	case AFADDL:
-	case AFADDF:
-	case AFADDD:
-	case AFMULDP:
-	case AFMULW:
-	case AFMULL:
-	case AFMULF:
-	case AFMULD:
-	case AFSUBDP:
-	case AFSUBW:
-	case AFSUBL:
-	case AFSUBF:
-	case AFSUBD:
-	case AFSUBRDP:
-	case AFSUBRW:
-	case AFSUBRL:
-	case AFSUBRF:
-	case AFSUBRD:
-	case AFDIVDP:
-	case AFDIVW:
-	case AFDIVL:
-	case AFDIVF:
-	case AFDIVD:
-	case AFDIVRDP:
-	case AFDIVRW:
-	case AFDIVRL:
-	case AFDIVRF:
-	case AFDIVRD:
-		if(copyas(&p->to, v))
-			return 2;
-		goto caseread;
-
-	case ACMPL:	/* read only */
-	case ACMPW:
-	case ACMPB:
-	
-	case APREFETCHT0:
-	case APREFETCHT1:
-	case APREFETCHT2:
-	case APREFETCHNTA:
-
-
-	case AFCOMB:
-	case AFCOMBP:
-	case AFCOMD:
-	case AFCOMDP:
-	case AFCOMDPP:
-	case AFCOMF:
-	case AFCOMFP:
-	case AFCOML:
-	case AFCOMLP:
-	case AFCOMW:
-	case AFCOMWP:
-	case AFUCOM:
-	case AFUCOMP:
-	case AFUCOMPP:
-	caseread:
-		if(s != A) {
-			if(copysub(&p->from, v, s, 1))
-				return 1;
-			return copysub(&p->to, v, s, 1);
-		}
-		if(copyau(&p->from, v))
-			return 1;
-		if(copyau(&p->to, v))
-			return 1;
-		break;
-
-	case AJGE:	/* no reference */
-	case AJNE:
-	case AJLE:
-	case AJEQ:
-	case AJHI:
-	case AJLS:
-	case AJMI:
-	case AJPL:
-	case AJGT:
-	case AJLT:
-	case AJCC:
-	case AJCS:
-
-	case AADJSP:
-	case AFLDZ:
-	case AWAIT:
-		break;
-
-	case AIMULL:
-	case AIMULW:
-		if(p->to.type != D_NONE) {
-			if(copyas(&p->to, v))
-				return 2;
-			goto caseread;
-		}
-
-	case ADIVB:
-	case ADIVL:
-	case ADIVW:
-	case AIDIVB:
-	case AIDIVL:
-	case AIDIVW:
-	case AIMULB:
-	case AMULB:
-	case AMULL:
-	case AMULW:
-
-	case ACWD:
-	case ACDQ:
-		if(v->type == D_AX || v->type == D_DX)
-			return 2;
-		goto caseread;
-
-	case AREP:
-	case AREPN:
-		if(v->type == D_CX)
-			return 2;
-		goto caseread;
-
-	case AMOVSB:
-	case AMOVSL:
-		if(v->type == D_DI || v->type == D_SI)
-			return 2;
-		goto caseread;
-
-	case ASTOSB:
-	case ASTOSL:
-		if(v->type == D_AX || v->type == D_DI)
-			return 2;
-		goto caseread;
-
-	case AFSTSW:
-		if(v->type == D_AX)
-			return 2;
-		goto caseread;
-
-	case AJMP:	/* funny */
-		if(s != A) {
-			if(copysub(&p->to, v, s, 1))
-				return 1;
-			return 0;
-		}
-		if(copyau(&p->to, v))
-			return 1;
-		return 0;
-
-	case ARET:	/* funny */
-		if(v->type == REGRET)
-			return 2;
-		if(s != A)
-			return 1;
-		return 3;
-
-	case ACALL:	/* funny */
-		if(REGARG >= 0 && v->type == (uchar)REGARG)
-			return 2;
-
-		if(s != A) {
-			if(copysub(&p->to, v, s, 1))
-				return 1;
-			return 0;
-		}
-		if(copyau(&p->to, v))
-			return 4;
-		return 3;
-	}
-	return 0;
-}
-
-/*
- * direct reference,
- * could be set/use depending on
- * semantics
- */
-int
-copyas(Addr *a, Addr *v)
-{
-	if(a->type != v->type)
-		return 0;
-	if(regtyp(v))
-		return 1;
-	if(v->type == D_AUTO || v->type == D_PARAM)
-		if(v->offset == a->offset)
-			return 1;
-	return 0;
-}
-
-/*
- * either direct or indirect
- */
-int
-copyau(Addr *a, Addr *v)
-{
-
-	if(copyas(a, v))
-		return 1;
-	if(regtyp(v)) {
-		if(a->type-D_INDIR == v->type)
-			return 1;
-		if(a->index == v->type)
-			return 1;
-	}
-	return 0;
-}
-
-/*
- * substitute s for v in a
- * return failure to substitute
- */
-int
-copysub(Addr *a, Addr *v, Addr *s, int f)
-{
-	int t;
-
-	if(copyas(a, v)) {
-		t = s->type;
-		if(t >= D_AX && t <= D_DI) {
-			if(f)
-				a->type = t;
-		}
-		return 0;
-	}
-	if(regtyp(v)) {
-		t = v->type;
-		if(a->type == t+D_INDIR) {
-			if(s->type == D_BP && a->index != D_NONE)
-				return 1;	/* can't use BP-base with index */
-			if(f)
-				a->type = s->type+D_INDIR;
-//			return 0;
-		}
-		if(a->index == t) {
-			if(f)
-				a->index = s->type;
-			return 0;
-		}
-		return 0;
-	}
-	return 0;
-}
diff --git a/src/cmd/8c/reg.c b/src/cmd/8c/reg.c
deleted file mode 100644
index ea862f3..0000000
--- a/src/cmd/8c/reg.c
+++ /dev/null
@@ -1,1438 +0,0 @@
-// Inferno utils/8c/reg.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8c/reg.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include "gc.h"
-
-static	void	fixjmp(Reg*);
-
-Reg*
-rega(void)
-{
-	Reg *r;
-
-	r = freer;
-	if(r == R) {
-		r = alloc(sizeof(*r));
-	} else
-		freer = r->link;
-
-	*r = zreg;
-	return r;
-}
-
-int
-rcmp(const void *a1, const void *a2)
-{
-	Rgn *p1, *p2;
-	int c1, c2;
-
-	p1 = (Rgn*)a1;
-	p2 = (Rgn*)a2;
-	c1 = p2->cost;
-	c2 = p1->cost;
-	if(c1 -= c2)
-		return c1;
-	return p2->varno - p1->varno;
-}
-
-void
-regopt(Prog *p)
-{
-	Reg *r, *r1, *r2;
-	Prog *p1;
-	int i, z;
-	int32 initpc, val, npc;
-	uint32 vreg;
-	Bits bit;
-	struct
-	{
-		int32	m;
-		int32	c;
-		Reg*	p;
-	} log5[6], *lp;
-
-	firstr = R;
-	lastr = R;
-	nvar = 0;
-	regbits = RtoB(D_SP) | RtoB(D_AX);
-	for(z=0; z<BITS; z++) {
-		externs.b[z] = 0;
-		params.b[z] = 0;
-		consts.b[z] = 0;
-		addrs.b[z] = 0;
-	}
-
-	/*
-	 * pass 1
-	 * build aux data structure
-	 * allocate pcs
-	 * find use and set of variables
-	 */
-	val = 5L * 5L * 5L * 5L * 5L;
-	lp = log5;
-	for(i=0; i<5; i++) {
-		lp->m = val;
-		lp->c = 0;
-		lp->p = R;
-		val /= 5L;
-		lp++;
-	}
-	val = 0;
-	for(; p != P; p = p->link) {
-		switch(p->as) {
-		case ADATA:
-		case AGLOBL:
-		case ANAME:
-		case ASIGNAME:
-		case AFUNCDATA:
-			continue;
-		}
-		r = rega();
-		if(firstr == R) {
-			firstr = r;
-			lastr = r;
-		} else {
-			lastr->link = r;
-			r->p1 = lastr;
-			lastr->s1 = r;
-			lastr = r;
-		}
-		r->prog = p;
-		r->pc = val;
-		val++;
-
-		lp = log5;
-		for(i=0; i<5; i++) {
-			lp->c--;
-			if(lp->c <= 0) {
-				lp->c = lp->m;
-				if(lp->p != R)
-					lp->p->log5 = r;
-				lp->p = r;
-				(lp+1)->c = 0;
-				break;
-			}
-			lp++;
-		}
-
-		r1 = r->p1;
-		if(r1 != R)
-		switch(r1->prog->as) {
-		case ARET:
-		case AJMP:
-		case AIRETL:
-			r->p1 = R;
-			r1->s1 = R;
-		}
-		bit = mkvar(r, &p->from);
-		if(bany(&bit))
-		switch(p->as) {
-		/*
-		 * funny
-		 */
-		case ALEAL:
-			for(z=0; z<BITS; z++)
-				addrs.b[z] |= bit.b[z];
-			break;
-
-		/*
-		 * left side read
-		 */
-		default:
-			for(z=0; z<BITS; z++)
-				r->use1.b[z] |= bit.b[z];
-			break;
-		}
-
-		bit = mkvar(r, &p->to);
-		if(bany(&bit))
-		switch(p->as) {
-		default:
-			diag(Z, "reg: unknown op: %A", p->as);
-			break;
-
-		/*
-		 * right side read
-		 */
-		case ACMPB:
-		case ACMPL:
-		case ACMPW:
-		case APREFETCHT0:
-		case APREFETCHT1:
-		case APREFETCHT2:
-		case APREFETCHNTA:
-			for(z=0; z<BITS; z++)
-				r->use2.b[z] |= bit.b[z];
-			break;
-
-		/*
-		 * right side write
-		 */
-		case ANOP:
-		case AMOVL:
-		case AMOVB:
-		case AMOVW:
-		case AMOVBLSX:
-		case AMOVBLZX:
-		case AMOVWLSX:
-		case AMOVWLZX:
-			for(z=0; z<BITS; z++)
-				r->set.b[z] |= bit.b[z];
-			break;
-
-		/*
-		 * right side read+write
-		 */
-		case AADDB:
-		case AADDL:
-		case AADDW:
-		case AANDB:
-		case AANDL:
-		case AANDW:
-		case ASUBB:
-		case ASUBL:
-		case ASUBW:
-		case AORB:
-		case AORL:
-		case AORW:
-		case AXORB:
-		case AXORL:
-		case AXORW:
-		case ASALB:
-		case ASALL:
-		case ASALW:
-		case ASARB:
-		case ASARL:
-		case ASARW:
-		case AROLB:
-		case AROLL:
-		case AROLW:
-		case ARORB:
-		case ARORL:
-		case ARORW:
-		case ASHLB:
-		case ASHLL:
-		case ASHLW:
-		case ASHRB:
-		case ASHRL:
-		case ASHRW:
-		case AIMULL:
-		case AIMULW:
-		case ANEGL:
-		case ANOTL:
-		case AADCL:
-		case ASBBL:
-			for(z=0; z<BITS; z++) {
-				r->set.b[z] |= bit.b[z];
-				r->use2.b[z] |= bit.b[z];
-			}
-			break;
-
-		/*
-		 * funny
-		 */
-		case AFMOVDP:
-		case AFMOVFP:
-		case AFMOVLP:
-		case AFMOVVP:
-		case AFMOVWP:
-		case ACALL:
-			for(z=0; z<BITS; z++)
-				addrs.b[z] |= bit.b[z];
-			break;
-		}
-
-		switch(p->as) {
-		case AIMULL:
-		case AIMULW:
-			if(p->to.type != D_NONE)
-				break;
-
-		case AIDIVB:
-		case AIDIVL:
-		case AIDIVW:
-		case AIMULB:
-		case ADIVB:
-		case ADIVL:
-		case ADIVW:
-		case AMULB:
-		case AMULL:
-		case AMULW:
-
-		case ACWD:
-		case ACDQ:
-			r->regu |= RtoB(D_AX) | RtoB(D_DX);
-			break;
-
-		case AREP:
-		case AREPN:
-		case ALOOP:
-		case ALOOPEQ:
-		case ALOOPNE:
-			r->regu |= RtoB(D_CX);
-			break;
-
-		case AMOVSB:
-		case AMOVSL:
-		case AMOVSW:
-		case ACMPSB:
-		case ACMPSL:
-		case ACMPSW:
-			r->regu |= RtoB(D_SI) | RtoB(D_DI);
-			break;
-
-		case ASTOSB:
-		case ASTOSL:
-		case ASTOSW:
-		case ASCASB:
-		case ASCASL:
-		case ASCASW:
-			r->regu |= RtoB(D_AX) | RtoB(D_DI);
-			break;
-
-		case AINSB:
-		case AINSL:
-		case AINSW:
-		case AOUTSB:
-		case AOUTSL:
-		case AOUTSW:
-			r->regu |= RtoB(D_DI) | RtoB(D_DX);
-			break;
-
-		case AFSTSW:
-		case ASAHF:
-			r->regu |= RtoB(D_AX);
-			break;
-		}
-	}
-	if(firstr == R)
-		return;
-	initpc = pc - val;
-	npc = val;
-
-	/*
-	 * pass 2
-	 * turn branch references to pointers
-	 * build back pointers
-	 */
-	for(r = firstr; r != R; r = r->link) {
-		p = r->prog;
-		if(p->to.type == D_BRANCH) {
-			val = p->to.offset - initpc;
-			r1 = firstr;
-			while(r1 != R) {
-				r2 = r1->log5;
-				if(r2 != R && val >= r2->pc) {
-					r1 = r2;
-					continue;
-				}
-				if(r1->pc == val)
-					break;
-				r1 = r1->link;
-			}
-			if(r1 == R) {
-				nearln = p->lineno;
-				diag(Z, "ref not found\n%P", p);
-				continue;
-			}
-			if(r1 == r) {
-				nearln = p->lineno;
-				diag(Z, "ref to self\n%P", p);
-				continue;
-			}
-			r->s2 = r1;
-			r->p2link = r1->p2;
-			r1->p2 = r;
-		}
-	}
-	if(debug['R']) {
-		p = firstr->prog;
-		print("\n%L %D\n", p->lineno, &p->from);
-	}
-
-	/*
-	 * pass 2.1
-	 * fix jumps
-	 */
-	fixjmp(firstr);
-
-	/*
-	 * pass 2.5
-	 * find looping structure
-	 */
-	for(r = firstr; r != R; r = r->link)
-		r->active = 0;
-	change = 0;
-	loopit(firstr, npc);
-	if(debug['R'] && debug['v']) {
-		print("\nlooping structure:\n");
-		for(r = firstr; r != R; r = r->link) {
-			print("%d:%P", r->loop, r->prog);
-			for(z=0; z<BITS; z++)
-				bit.b[z] = r->use1.b[z] |
-					   r->use2.b[z] |
-					   r->set.b[z];
-			if(bany(&bit)) {
-				print("\t");
-				if(bany(&r->use1))
-					print(" u1=%B", r->use1);
-				if(bany(&r->use2))
-					print(" u2=%B", r->use2);
-				if(bany(&r->set))
-					print(" st=%B", r->set);
-			}
-			print("\n");
-		}
-	}
-
-	/*
-	 * pass 3
-	 * iterate propagating usage
-	 * 	back until flow graph is complete
-	 */
-loop1:
-	change = 0;
-	for(r = firstr; r != R; r = r->link)
-		r->active = 0;
-	for(r = firstr; r != R; r = r->link)
-		if(r->prog->as == ARET)
-			prop(r, zbits, zbits);
-loop11:
-	/* pick up unreachable code */
-	i = 0;
-	for(r = firstr; r != R; r = r1) {
-		r1 = r->link;
-		if(r1 && r1->active && !r->active) {
-			prop(r, zbits, zbits);
-			i = 1;
-		}
-	}
-	if(i)
-		goto loop11;
-	if(change)
-		goto loop1;
-
-
-	/*
-	 * pass 4
-	 * iterate propagating register/variable synchrony
-	 * 	forward until graph is complete
-	 */
-loop2:
-	change = 0;
-	for(r = firstr; r != R; r = r->link)
-		r->active = 0;
-	synch(firstr, zbits);
-	if(change)
-		goto loop2;
-
-
-	/*
-	 * pass 5
-	 * isolate regions
-	 * calculate costs (paint1)
-	 */
-	r = firstr;
-	if(r) {
-		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]);
-		if(bany(&bit)) {
-			nearln = r->prog->lineno;
-			warn(Z, "used and not set: %B", bit);
-			if(debug['R'] && !debug['w'])
-				print("used and not set: %B\n", bit);
-		}
-	}
-	if(debug['R'] && debug['v'])
-		print("\nprop structure:\n");
-	for(r = firstr; r != R; r = r->link)
-		r->act = zbits;
-	rgp = region;
-	nregion = 0;
-	for(r = firstr; r != R; r = r->link) {
-		if(debug['R'] && debug['v']) {
-			print("%P\t", r->prog);
-			if(bany(&r->set))
-				print("s:%B ", r->set);
-			if(bany(&r->refahead))
-				print("ra:%B ", r->refahead);
-			if(bany(&r->calahead))
-				print("ca:%B ", r->calahead);
-			print("\n");
-		}
-		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)) {
-			nearln = r->prog->lineno;
-			warn(Z, "set and not used: %B", bit);
-			if(debug['R'])
-				print("set and not used: %B\n", bit);
-			excise(r);
-		}
-		for(z=0; z<BITS; z++)
-			bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]);
-		while(bany(&bit)) {
-			i = bnum(bit);
-			rgp->enter = r;
-			rgp->varno = i;
-			change = 0;
-			if(debug['R'] && debug['v'])
-				print("\n");
-			paint1(r, i);
-			bit.b[i/32] &= ~(1L<<(i%32));
-			if(change <= 0) {
-				if(debug['R'])
-					print("%L$%d: %B\n",
-						r->prog->lineno, change, blsh(i));
-				continue;
-			}
-			rgp->cost = change;
-			nregion++;
-			if(nregion >= NRGN) {
-				fatal(Z, "too many regions");
-				goto brk;
-			}
-			rgp++;
-		}
-	}
-brk:
-	qsort(region, nregion, sizeof(region[0]), rcmp);
-
-	/*
-	 * pass 6
-	 * determine used registers (paint2)
-	 * replace code (paint3)
-	 */
-	rgp = region;
-	for(i=0; i<nregion; i++) {
-		bit = blsh(rgp->varno);
-		vreg = paint2(rgp->enter, rgp->varno);
-		vreg = allreg(vreg, rgp);
-		if(debug['R']) {
-			print("%L$%d %R: %B\n",
-				rgp->enter->prog->lineno,
-				rgp->cost,
-				rgp->regno,
-				bit);
-		}
-		if(rgp->regno != 0)
-			paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
-		rgp++;
-	}
-	/*
-	 * pass 7
-	 * peep-hole on basic block
-	 */
-	if(!debug['R'] || debug['P'])
-		peep();
-
-	if(debug['R'] && debug['v']) {
-		print("after pass 7 (peep)\n");
-		for(r=firstr; r; r=r->link)
-			print("%04d %P\n", (int)r->pc, r->prog);
-		print("\n");
-	}
-
-	/*
-	 * pass 8
-	 * recalculate pc
-	 */
-	val = initpc;
-	for(r = firstr; r != R; r = r1) {
-		r->pc = val;
-		p = r->prog;
-		p1 = P;
-		r1 = r->link;
-		if(r1 != R)
-			p1 = r1->prog;
-		for(; p != p1; p = p->link) {
-			switch(p->as) {
-			default:
-				val++;
-				break;
-
-			case ANOP:
-			case ADATA:
-			case AGLOBL:
-			case ANAME:
-			case ASIGNAME:
-			case AFUNCDATA:
-				break;
-			}
-		}
-	}
-	pc = val;
-
-	/*
-	 * fix up branches
-	 */
-	if(debug['R'])
-		if(bany(&addrs))
-			print("addrs: %B\n", addrs);
-
-	r1 = 0; /* set */
-	for(r = firstr; r != R; r = r->link) {
-		p = r->prog;
-		if(p->to.type == D_BRANCH) {
-			p->to.offset = r->s2->pc;
-			p->to.u.branch = r->s2->prog;
-		}
-		r1 = r;
-	}
-
-	/*
-	 * last pass
-	 * eliminate nops
-	 * free aux structures
-	 */
-	for(p = firstr->prog; p != P; p = p->link){
-		while(p->link && p->link->as == ANOP)
-			p->link = p->link->link;
-	}
-
-	if(debug['R'] && debug['v']) {
-		print("after pass 8 (fixup pc)\n");
-		for(p1=firstr->prog; p1!=P; p1=p1->link)
-			print("%P\n", p1);
-		print("\n");
-	}
-
-	if(r1 != R) {
-		r1->link = freer;
-		freer = firstr;
-	}
-}
-
-/*
- * add mov b,rn
- * just after r
- */
-void
-addmove(Reg *r, int bn, int rn, int f)
-{
-	Prog *p, *p1;
-	Addr *a;
-	Var *v;
-
-	p1 = alloc(sizeof(*p1));
-	*p1 = zprog;
-	p = r->prog;
-
-	p1->link = p->link;
-	p->link = p1;
-	p1->lineno = p->lineno;
-
-	v = var + bn;
-
-	a = &p1->to;
-	a->sym = v->sym;
-	a->offset = v->offset;
-	a->etype = v->etype;
-	a->type = v->name;
-
-	p1->as = AMOVL;
-	if(v->etype == TCHAR || v->etype == TUCHAR)
-		p1->as = AMOVB;
-	if(v->etype == TSHORT || v->etype == TUSHORT)
-		p1->as = AMOVW;
-
-	p1->from.type = rn;
-	if(!f) {
-		p1->from = *a;
-		*a = zprog.from;
-		a->type = rn;
-		if(v->etype == TUCHAR)
-			p1->as = AMOVB;
-		if(v->etype == TUSHORT)
-			p1->as = AMOVW;
-	}
-	if(debug['R'])
-		print("%P\t.a%P\n", p, p1);
-}
-
-uint32
-doregbits(int r)
-{
-	uint32 b;
-
-	b = 0;
-	if(r >= D_INDIR)
-		r -= D_INDIR;
-	if(r >= D_AX && r <= D_DI)
-		b |= RtoB(r);
-	else
-	if(r >= D_AL && r <= D_BL)
-		b |= RtoB(r-D_AL+D_AX);
-	else
-	if(r >= D_AH && r <= D_BH)
-		b |= RtoB(r-D_AH+D_AX);
-	return b;
-}
-
-Bits
-mkvar(Reg *r, Addr *a)
-{
-	Var *v;
-	int i, t, n, et, z;
-	int32 o;
-	Bits bit;
-	LSym *s;
-
-	/*
-	 * mark registers used
-	 */
-	t = a->type;
-	r->regu |= doregbits(t);
-	r->regu |= doregbits(a->index);
-
-	switch(t) {
-	default:
-		goto none;
-	case D_ADDR:
-		a->type = a->index;
-		bit = mkvar(r, a);
-		for(z=0; z<BITS; z++)
-			addrs.b[z] |= bit.b[z];
-		a->type = t;
-		goto none;
-	case D_EXTERN:
-	case D_STATIC:
-	case D_PARAM:
-	case D_AUTO:
-		n = t;
-		break;
-	}
-	s = a->sym;
-	if(s == nil)
-		goto none;
-	if(s->name[0] == '.')
-		goto none;
-	et = a->etype;
-	o = a->offset;
-	v = var;
-	for(i=0; i<nvar; i++) {
-		if(s == v->sym)
-		if(n == v->name)
-		if(o == v->offset)
-			goto out;
-		v++;
-	}
-	if(nvar >= NVAR)
-		fatal(Z, "variable not optimized: %s", s->name);
-	i = nvar;
-	nvar++;
-	v = &var[i];
-	v->sym = s;
-	v->offset = o;
-	v->name = n;
-	v->etype = et;
-	if(debug['R'])
-		print("bit=%2d et=%2d %D\n", i, et, a);
-
-out:
-	bit = blsh(i);
-	if(n == D_EXTERN || n == D_STATIC)
-		for(z=0; z<BITS; z++)
-			externs.b[z] |= bit.b[z];
-	if(n == D_PARAM)
-		for(z=0; z<BITS; z++)
-			params.b[z] |= bit.b[z];
-	if(v->etype != et || !typechlpfd[et])	/* funny punning */
-		for(z=0; z<BITS; z++)
-			addrs.b[z] |= bit.b[z];
-	return bit;
-
-none:
-	return zbits;
-}
-
-void
-prop(Reg *r, Bits ref, Bits cal)
-{
-	Reg *r1, *r2;
-	int z;
-
-	for(r1 = r; r1 != R; r1 = r1->p1) {
-		for(z=0; z<BITS; z++) {
-			ref.b[z] |= r1->refahead.b[z];
-			if(ref.b[z] != r1->refahead.b[z]) {
-				r1->refahead.b[z] = ref.b[z];
-				change++;
-			}
-			cal.b[z] |= r1->calahead.b[z];
-			if(cal.b[z] != r1->calahead.b[z]) {
-				r1->calahead.b[z] = cal.b[z];
-				change++;
-			}
-		}
-		switch(r1->prog->as) {
-		case ACALL:
-			for(z=0; z<BITS; z++) {
-				cal.b[z] |= ref.b[z] | externs.b[z];
-				ref.b[z] = 0;
-			}
-			break;
-
-		case ATEXT:
-			for(z=0; z<BITS; z++) {
-				cal.b[z] = 0;
-				ref.b[z] = 0;
-			}
-			break;
-
-		case ARET:
-			for(z=0; z<BITS; z++) {
-				cal.b[z] = externs.b[z];
-				ref.b[z] = 0;
-			}
-		}
-		for(z=0; z<BITS; z++) {
-			ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
-				r1->use1.b[z] | r1->use2.b[z];
-			cal.b[z] &= ~(r1->set.b[z] | r1->use1.b[z] | r1->use2.b[z]);
-			r1->refbehind.b[z] = ref.b[z];
-			r1->calbehind.b[z] = cal.b[z];
-		}
-		if(r1->active)
-			break;
-		r1->active = 1;
-	}
-	for(; r != r1; r = r->p1)
-		for(r2 = r->p2; r2 != R; r2 = r2->p2link)
-			prop(r2, r->refbehind, r->calbehind);
-}
-
-/*
- * find looping structure
- *
- * 1) find reverse postordering
- * 2) find approximate dominators,
- *	the actual dominators if the flow graph is reducible
- *	otherwise, dominators plus some other non-dominators.
- *	See Matthew S. Hecht and Jeffrey D. Ullman,
- *	"Analysis of a Simple Algorithm for Global Data Flow Problems",
- *	Conf.  Record of ACM Symp. on Principles of Prog. Langs, Boston, Massachusetts,
- *	Oct. 1-3, 1973, pp.  207-217.
- * 3) find all nodes with a predecessor dominated by the current node.
- *	such a node is a loop head.
- *	recursively, all preds with a greater rpo number are in the loop
- */
-int32
-postorder(Reg *r, Reg **rpo2r, int32 n)
-{
-	Reg *r1;
-
-	r->rpo = 1;
-	r1 = r->s1;
-	if(r1 && !r1->rpo)
-		n = postorder(r1, rpo2r, n);
-	r1 = r->s2;
-	if(r1 && !r1->rpo)
-		n = postorder(r1, rpo2r, n);
-	rpo2r[n] = r;
-	n++;
-	return n;
-}
-
-int32
-rpolca(int32 *idom, int32 rpo1, int32 rpo2)
-{
-	int32 t;
-
-	if(rpo1 == -1)
-		return rpo2;
-	while(rpo1 != rpo2){
-		if(rpo1 > rpo2){
-			t = rpo2;
-			rpo2 = rpo1;
-			rpo1 = t;
-		}
-		while(rpo1 < rpo2){
-			t = idom[rpo2];
-			if(t >= rpo2)
-				fatal(Z, "bad idom");
-			rpo2 = t;
-		}
-	}
-	return rpo1;
-}
-
-int
-doms(int32 *idom, int32 r, int32 s)
-{
-	while(s > r)
-		s = idom[s];
-	return s == r;
-}
-
-int
-loophead(int32 *idom, Reg *r)
-{
-	int32 src;
-
-	src = r->rpo;
-	if(r->p1 != R && doms(idom, src, r->p1->rpo))
-		return 1;
-	for(r = r->p2; r != R; r = r->p2link)
-		if(doms(idom, src, r->rpo))
-			return 1;
-	return 0;
-}
-
-void
-loopmark(Reg **rpo2r, int32 head, Reg *r)
-{
-	if(r->rpo < head || r->active == head)
-		return;
-	r->active = head;
-	r->loop += LOOP;
-	if(r->p1 != R)
-		loopmark(rpo2r, head, r->p1);
-	for(r = r->p2; r != R; r = r->p2link)
-		loopmark(rpo2r, head, r);
-}
-
-void
-loopit(Reg *r, int32 nr)
-{
-	Reg *r1;
-	int32 i, d, me;
-
-	if(nr > maxnr) {
-		rpo2r = alloc(nr * sizeof(Reg*));
-		idom = alloc(nr * sizeof(int32));
-		maxnr = nr;
-	}
-
-	d = postorder(r, rpo2r, 0);
-	if(d > nr)
-		fatal(Z, "too many reg nodes");
-	nr = d;
-	for(i = 0; i < nr / 2; i++){
-		r1 = rpo2r[i];
-		rpo2r[i] = rpo2r[nr - 1 - i];
-		rpo2r[nr - 1 - i] = r1;
-	}
-	for(i = 0; i < nr; i++)
-		rpo2r[i]->rpo = i;
-
-	idom[0] = 0;
-	for(i = 0; i < nr; i++){
-		r1 = rpo2r[i];
-		me = r1->rpo;
-		d = -1;
-		if(r1->p1 != R && r1->p1->rpo < me)
-			d = r1->p1->rpo;
-		for(r1 = r1->p2; r1 != nil; r1 = r1->p2link)
-			if(r1->rpo < me)
-				d = rpolca(idom, d, r1->rpo);
-		idom[i] = d;
-	}
-
-	for(i = 0; i < nr; i++){
-		r1 = rpo2r[i];
-		r1->loop++;
-		if(r1->p2 != R && loophead(idom, r1))
-			loopmark(rpo2r, i, r1);
-	}
-}
-
-void
-synch(Reg *r, Bits dif)
-{
-	Reg *r1;
-	int z;
-
-	for(r1 = r; r1 != R; r1 = r1->s1) {
-		for(z=0; z<BITS; z++) {
-			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++;
-			}
-		}
-		if(r1->active)
-			break;
-		r1->active = 1;
-		for(z=0; z<BITS; z++)
-			dif.b[z] &= ~(~r1->calbehind.b[z] & r1->calahead.b[z]);
-		if(r1->s2 != R)
-			synch(r1->s2, dif);
-	}
-}
-
-uint32
-allreg(uint32 b, Rgn *r)
-{
-	Var *v;
-	int i;
-
-	v = var + r->varno;
-	r->regno = 0;
-	switch(v->etype) {
-
-	default:
-		diag(Z, "unknown etype %d/%d", bitno(b), v->etype);
-		break;
-
-	case TCHAR:
-	case TUCHAR:
-	case TSHORT:
-	case TUSHORT:
-	case TINT:
-	case TUINT:
-	case TLONG:
-	case TULONG:
-	case TIND:
-	case TARRAY:
-		i = BtoR(~b);
-		if(i && r->cost > 0) {
-			r->regno = i;
-			return RtoB(i);
-		}
-		break;
-
-	case TDOUBLE:
-	case TFLOAT:
-		break;
-	}
-	return 0;
-}
-
-void
-paint1(Reg *r, int bn)
-{
-	Reg *r1;
-	Prog *p;
-	int z;
-	uint32 bb;
-
-	z = bn/32;
-	bb = 1L<<(bn%32);
-	if(r->act.b[z] & bb)
-		return;
-	for(;;) {
-		if(!(r->refbehind.b[z] & bb))
-			break;
-		r1 = r->p1;
-		if(r1 == R)
-			break;
-		if(!(r1->refahead.b[z] & bb))
-			break;
-		if(r1->act.b[z] & bb)
-			break;
-		r = r1;
-	}
-
-	if(LOAD(r) & ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z])) & bb) {
-		change -= CLOAD * r->loop;
-		if(debug['R'] && debug['v'])
-			print("%d%P\td %B $%d\n", r->loop,
-				r->prog, blsh(bn), change);
-	}
-	for(;;) {
-		r->act.b[z] |= bb;
-		p = r->prog;
-
-		if(r->use1.b[z] & bb) {
-			change += CREF * r->loop;
-			if(p->as == AFMOVL)
-				if(BtoR(bb) != D_F0)
-					change = -CINF;
-			if(debug['R'] && debug['v'])
-				print("%d%P\tu1 %B $%d\n", r->loop,
-					p, blsh(bn), change);
-		}
-
-		if((r->use2.b[z]|r->set.b[z]) & bb) {
-			change += CREF * r->loop;
-			if(p->as == AFMOVL)
-				if(BtoR(bb) != D_F0)
-					change = -CINF;
-			if(debug['R'] && debug['v'])
-				print("%d%P\tu2 %B $%d\n", r->loop,
-					p, blsh(bn), change);
-		}
-
-		if(STORE(r) & r->regdiff.b[z] & bb) {
-			change -= CLOAD * r->loop;
-			if(p->as == AFMOVL)
-				if(BtoR(bb) != D_F0)
-					change = -CINF;
-			if(debug['R'] && debug['v'])
-				print("%d%P\tst %B $%d\n", r->loop,
-					p, blsh(bn), change);
-		}
-
-		if(r->refbehind.b[z] & bb)
-			for(r1 = r->p2; r1 != R; r1 = r1->p2link)
-				if(r1->refahead.b[z] & bb)
-					paint1(r1, bn);
-
-		if(!(r->refahead.b[z] & bb))
-			break;
-		r1 = r->s2;
-		if(r1 != R)
-			if(r1->refbehind.b[z] & bb)
-				paint1(r1, bn);
-		r = r->s1;
-		if(r == R)
-			break;
-		if(r->act.b[z] & bb)
-			break;
-		if(!(r->refbehind.b[z] & bb))
-			break;
-	}
-}
-
-uint32
-regset(Reg *r, uint32 bb)
-{
-	uint32 b, set;
-	Addr v;
-	int c;
-
-	set = 0;
-	v = zprog.from;
-	while(b = bb & ~(bb-1)) {
-		v.type = BtoR(b);
-		c = copyu(r->prog, &v, A);
-		if(c == 3)
-			set |= b;
-		bb &= ~b;
-	}
-	return set;
-}
-
-uint32
-reguse(Reg *r, uint32 bb)
-{
-	uint32 b, set;
-	Addr v;
-	int c;
-
-	set = 0;
-	v = zprog.from;
-	while(b = bb & ~(bb-1)) {
-		v.type = BtoR(b);
-		c = copyu(r->prog, &v, A);
-		if(c == 1 || c == 2 || c == 4)
-			set |= b;
-		bb &= ~b;
-	}
-	return set;
-}
-
-uint32
-paint2(Reg *r, int bn)
-{
-	Reg *r1;
-	int z;
-	uint32 bb, vreg, x;
-
-	z = bn/32;
-	bb = 1L << (bn%32);
-	vreg = regbits;
-	if(!(r->act.b[z] & bb))
-		return vreg;
-	for(;;) {
-		if(!(r->refbehind.b[z] & bb))
-			break;
-		r1 = r->p1;
-		if(r1 == R)
-			break;
-		if(!(r1->refahead.b[z] & bb))
-			break;
-		if(!(r1->act.b[z] & bb))
-			break;
-		r = r1;
-	}
-	for(;;) {
-		r->act.b[z] &= ~bb;
-
-		vreg |= r->regu;
-
-		if(r->refbehind.b[z] & bb)
-			for(r1 = r->p2; r1 != R; r1 = r1->p2link)
-				if(r1->refahead.b[z] & bb)
-					vreg |= paint2(r1, bn);
-
-		if(!(r->refahead.b[z] & bb))
-			break;
-		r1 = r->s2;
-		if(r1 != R)
-			if(r1->refbehind.b[z] & bb)
-				vreg |= paint2(r1, bn);
-		r = r->s1;
-		if(r == R)
-			break;
-		if(!(r->act.b[z] & bb))
-			break;
-		if(!(r->refbehind.b[z] & bb))
-			break;
-	}
-
-	bb = vreg;
-	for(; r; r=r->s1) {
-		x = r->regu & ~bb;
-		if(x) {
-			vreg |= reguse(r, x);
-			bb |= regset(r, x);
-		}
-	}
-	return vreg;
-}
-
-void
-paint3(Reg *r, int bn, int32 rb, int rn)
-{
-	Reg *r1;
-	Prog *p;
-	int z;
-	uint32 bb;
-
-	z = bn/32;
-	bb = 1L << (bn%32);
-	if(r->act.b[z] & bb)
-		return;
-	for(;;) {
-		if(!(r->refbehind.b[z] & bb))
-			break;
-		r1 = r->p1;
-		if(r1 == R)
-			break;
-		if(!(r1->refahead.b[z] & bb))
-			break;
-		if(r1->act.b[z] & bb)
-			break;
-		r = r1;
-	}
-
-	if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb)
-		addmove(r, bn, rn, 0);
-	for(;;) {
-		r->act.b[z] |= bb;
-		p = r->prog;
-
-		if(r->use1.b[z] & bb) {
-			if(debug['R'])
-				print("%P", p);
-			addreg(&p->from, rn);
-			if(debug['R'])
-				print("\t.c%P\n", p);
-		}
-		if((r->use2.b[z]|r->set.b[z]) & bb) {
-			if(debug['R'])
-				print("%P", p);
-			addreg(&p->to, rn);
-			if(debug['R'])
-				print("\t.c%P\n", p);
-		}
-
-		if(STORE(r) & r->regdiff.b[z] & bb)
-			addmove(r, bn, rn, 1);
-		r->regu |= rb;
-
-		if(r->refbehind.b[z] & bb)
-			for(r1 = r->p2; r1 != R; r1 = r1->p2link)
-				if(r1->refahead.b[z] & bb)
-					paint3(r1, bn, rb, rn);
-
-		if(!(r->refahead.b[z] & bb))
-			break;
-		r1 = r->s2;
-		if(r1 != R)
-			if(r1->refbehind.b[z] & bb)
-				paint3(r1, bn, rb, rn);
-		r = r->s1;
-		if(r == R)
-			break;
-		if(r->act.b[z] & bb)
-			break;
-		if(!(r->refbehind.b[z] & bb))
-			break;
-	}
-}
-
-void
-addreg(Addr *a, int rn)
-{
-
-	a->sym = 0;
-	a->offset = 0;
-	a->type = rn;
-}
-
-int32
-RtoB(int r)
-{
-
-	if(r < D_AX || r > D_DI)
-		return 0;
-	return 1L << (r-D_AX);
-}
-
-int
-BtoR(int32 b)
-{
-
-	b &= 0xffL;
-	if(b == 0)
-		return 0;
-	return bitno(b) + D_AX;
-}
-
-/* what instruction does a JMP to p eventually land on? */
-static Reg*
-chasejmp(Reg *r, int *jmploop)
-{
-	int n;
-
-	n = 0;
-	for(; r; r=r->s2) {
-		if(r->prog->as != AJMP || r->prog->to.type != D_BRANCH)
-			break;
-		if(++n > 10) {
-			*jmploop = 1;
-			break;
-		}
-	}
-	return r;
-}
-
-/* mark all code reachable from firstp as alive */
-static void
-mark(Reg *firstr)
-{
-	Reg *r;
-	Prog *p;
-
-	for(r=firstr; r; r=r->link) {
-		if(r->active)
-			break;
-		r->active = 1;
-		p = r->prog;
-		if(p->as != ACALL && p->to.type == D_BRANCH)
-			mark(r->s2);
-		if(p->as == AJMP || p->as == ARET || p->as == AUNDEF)
-			break;
-	}
-}
-
-/*
- * the code generator depends on being able to write out JMP
- * instructions that it can jump to now but fill in later.
- * the linker will resolve them nicely, but they make the code
- * longer and more difficult to follow during debugging.
- * remove them.
- */
-static void
-fixjmp(Reg *firstr)
-{
-	int jmploop;
-	Reg *r;
-	Prog *p;
-
-	if(debug['R'] && debug['v'])
-		print("\nfixjmp\n");
-
-	// pass 1: resolve jump to AJMP, mark all code as dead.
-	jmploop = 0;
-	for(r=firstr; r; r=r->link) {
-		p = r->prog;
-		if(debug['R'] && debug['v'])
-			print("%04d %P\n", (int)r->pc, p);
-		if(p->as != ACALL && p->to.type == D_BRANCH && r->s2 && r->s2->prog->as == AJMP) {
-			r->s2 = chasejmp(r->s2, &jmploop);
-			p->to.offset = r->s2->pc;
-			p->to.u.branch = r->s2->prog;
-			if(debug['R'] && debug['v'])
-				print("->%P\n", p);
-		}
-		r->active = 0;
-	}
-	if(debug['R'] && debug['v'])
-		print("\n");
-
-	// pass 2: mark all reachable code alive
-	mark(firstr);
-
-	// pass 3: delete dead code (mostly JMPs).
-	for(r=firstr; r; r=r->link) {
-		if(!r->active) {
-			p = r->prog;
-			if(p->link == P && p->as == ARET && r->p1 && r->p1->prog->as != ARET) {
-				// This is the final ARET, and the code so far doesn't have one.
-				// Let it stay.
-			} else {
-				if(debug['R'] && debug['v'])
-					print("del %04d %P\n", (int)r->pc, p);
-				p->as = ANOP;
-			}
-		}
-	}
-
-	// pass 4: elide JMP to next instruction.
-	// only safe if there are no jumps to JMPs anymore.
-	if(!jmploop) {
-		for(r=firstr; r; r=r->link) {
-			p = r->prog;
-			if(p->as == AJMP && p->to.type == D_BRANCH && r->s2 == r->link) {
-				if(debug['R'] && debug['v'])
-					print("del %04d %P\n", (int)r->pc, p);
-				p->as = ANOP;
-			}
-		}
-	}
-
-	// fix back pointers.
-	for(r=firstr; r; r=r->link) {
-		r->p2 = R;
-		r->p2link = R;
-	}
-	for(r=firstr; r; r=r->link) {
-		if(r->s2) {
-			r->p2link = r->s2->p2;
-			r->s2->p2 = r;
-		}
-	}
-
-	if(debug['R'] && debug['v']) {
-		print("\n");
-		for(r=firstr; r; r=r->link)
-			print("%04d %P\n", (int)r->pc, r->prog);
-		print("\n");
-	}
-}
-
diff --git a/src/cmd/8c/sgen.c b/src/cmd/8c/sgen.c
deleted file mode 100644
index d647010..0000000
--- a/src/cmd/8c/sgen.c
+++ /dev/null
@@ -1,483 +0,0 @@
-// Inferno utils/8c/sgen.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8c/sgen.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include "gc.h"
-
-Prog*
-gtext(Sym *s, int32 stkoff)
-{
-	int32 a;
-
-	a = argsize(1);
-	if((textflag & NOSPLIT) != 0 && stkoff >= 128)
-		yyerror("stack frame too large for NOSPLIT function");
-
-	gpseudo(ATEXT, s, nodconst(stkoff));
-	p->to.type = D_CONST2;
-	p->to.offset2 = a;
-	return p;
-}
-
-void
-noretval(int n)
-{
-
-	if(n & 1) {
-		gins(ANOP, Z, Z);
-		p->to.type = REGRET;
-	}
-	if(n & 2) {
-		gins(ANOP, Z, Z);
-		p->to.type = FREGRET;
-	}
-}
-
-/* welcome to commute */
-static void
-commute(Node *n)
-{
-	Node *l, *r;
-
-	l = n->left;
-	r = n->right;
-	if(r->complex > l->complex) {
-		n->left = r;
-		n->right = l;
-	}
-}
-
-void
-indexshift(Node *n)
-{
-	int g;
-
-	if(!typechlp[n->type->etype])
-		return;
-	simplifyshift(n);
-	if(n->op == OASHL && n->right->op == OCONST){
-		g = vconst(n->right);
-		if(g >= 0 && g < 4)
-			n->addable = 7;
-	}
-}
-
-/*
- *	calculate addressability as follows
- *		NAME ==> 10/11		name+value(SB/SP)
- *		REGISTER ==> 12		register
- *		CONST ==> 20		$value
- *		*(20) ==> 21		value
- *		&(10) ==> 13		$name+value(SB)
- *		&(11) ==> 1		$name+value(SP)
- *		(13) + (20) ==> 13	fold constants
- *		(1) + (20) ==> 1	fold constants
- *		*(13) ==> 10		back to name
- *		*(1) ==> 11		back to name
- *
- *		(20) * (X) ==> 7	multiplier in indexing
- *		(X,7) + (13,1) ==> 8	adder in indexing (addresses)
- *		(8) ==> &9(OINDEX)	index, almost addressable
- *		100					extern register
- *
- *	calculate complexity (number of registers)
- */
-void
-xcom(Node *n)
-{
-	Node *l, *r;
-	int g;
-
-	if(n == Z)
-		return;
-	l = n->left;
-	r = n->right;
-	n->complex = 0;
-	n->addable = 0;
-	switch(n->op) {
-	case OCONST:
-		n->addable = 20;
-		break;
-
-	case ONAME:
-		n->addable = 10;
-		if(n->class == CPARAM || n->class == CAUTO)
-			n->addable = 11;
-		break;
-
-	case OEXREG:
-		n->addable = 0;
-		break;
-
-	case OREGISTER:
-		n->addable = 12;
-		break;
-
-	case OINDREG:
-		n->addable = 12;
-		break;
-
-	case OADDR:
-		xcom(l);
-		if(l->addable == 10)
-			n->addable = 13;
-		else
-		if(l->addable == 11)
-			n->addable = 1;
-		break;
-
-	case OADD:
-		xcom(l);
-		xcom(r);
-		if(n->type->etype != TIND)
-			break;
-
-		switch(r->addable) {
-		case 20:
-			switch(l->addable) {
-			case 1:
-			case 13:
-			commadd:
-				l->type = n->type;
-				*n = *l;
-				l = new(0, Z, Z);
-				*l = *(n->left);
-				l->xoffset += r->vconst;
-				n->left = l;
-				r = n->right;
-				goto brk;
-			}
-			break;
-
-		case 1:
-		case 13:
-		case 10:
-		case 11:
-			/* l is the base, r is the index */
-			if(l->addable != 20)
-				n->addable = 8;
-			break;
-		}
-		switch(l->addable) {
-		case 20:
-			switch(r->addable) {
-			case 13:
-			case 1:
-				r = n->left;
-				l = n->right;
-				n->left = l;
-				n->right = r;
-				goto commadd;
-			}
-			break;
-
-		case 13:
-		case 1:
-		case 10:
-		case 11:
-			/* r is the base, l is the index */
-			if(r->addable != 20)
-				n->addable = 8;
-			break;
-		}
-		if(n->addable == 8 && !side(n)) {
-			indx(n);
-			l = new1(OINDEX, idx.basetree, idx.regtree);
-			l->scale = idx.scale;
-			l->addable = 9;
-			l->complex = l->right->complex;
-			l->type = l->left->type;
-			n->op = OADDR;
-			n->left = l;
-			n->right = Z;
-			n->addable = 8;
-			break;
-		}
-		break;
-
-	case OINDEX:
-		xcom(l);
-		xcom(r);
-		n->addable = 9;
-		break;
-
-	case OIND:
-		xcom(l);
-		if(l->op == OADDR) {
-			l = l->left;
-			l->type = n->type;
-			*n = *l;
-			return;
-		}
-		switch(l->addable) {
-		case 20:
-			n->addable = 21;
-			break;
-		case 1:
-			n->addable = 11;
-			break;
-		case 13:
-			n->addable = 10;
-			break;
-		}
-		break;
-
-	case OASHL:
-		xcom(l);
-		xcom(r);
-		indexshift(n);
-		break;
-
-	case OMUL:
-	case OLMUL:
-		xcom(l);
-		xcom(r);
-		g = vlog(l);
-		if(g >= 0) {
-			n->left = r;
-			n->right = l;
-			l = r;
-			r = n->right;
-		}
-		g = vlog(r);
-		if(g >= 0) {
-			n->op = OASHL;
-			r->vconst = g;
-			r->type = types[TINT];
-			indexshift(n);
-			break;
-		}
-commute(n);
-		break;
-
-	case OASLDIV:
-		xcom(l);
-		xcom(r);
-		g = vlog(r);
-		if(g >= 0) {
-			n->op = OASLSHR;
-			r->vconst = g;
-			r->type = types[TINT];
-		}
-		break;
-
-	case OLDIV:
-		xcom(l);
-		xcom(r);
-		g = vlog(r);
-		if(g >= 0) {
-			n->op = OLSHR;
-			r->vconst = g;
-			r->type = types[TINT];
-			indexshift(n);
-			break;
-		}
-		break;
-
-	case OASLMOD:
-		xcom(l);
-		xcom(r);
-		g = vlog(r);
-		if(g >= 0) {
-			n->op = OASAND;
-			r->vconst--;
-		}
-		break;
-
-	case OLMOD:
-		xcom(l);
-		xcom(r);
-		g = vlog(r);
-		if(g >= 0) {
-			n->op = OAND;
-			r->vconst--;
-		}
-		break;
-
-	case OASMUL:
-	case OASLMUL:
-		xcom(l);
-		xcom(r);
-		g = vlog(r);
-		if(g >= 0) {
-			n->op = OASASHL;
-			r->vconst = g;
-		}
-		break;
-
-	case OLSHR:
-	case OASHR:
-		xcom(l);
-		xcom(r);
-		indexshift(n);
-		break;
-
-	default:
-		if(l != Z)
-			xcom(l);
-		if(r != Z)
-			xcom(r);
-		break;
-	}
-brk:
-	if(n->addable >= 10)
-		return;
-	if(l != Z)
-		n->complex = l->complex;
-	if(r != Z) {
-		if(r->complex == n->complex)
-			n->complex = r->complex+1;
-		else
-		if(r->complex > n->complex)
-			n->complex = r->complex;
-	}
-	if(n->complex == 0)
-		n->complex++;
-
-	if(com64(n))
-		return;
-
-	switch(n->op) {
-
-	case OFUNC:
-		n->complex = FNX;
-		break;
-
-	case OLMOD:
-	case OMOD:
-	case OLMUL:
-	case OLDIV:
-	case OMUL:
-	case ODIV:
-	case OASLMUL:
-	case OASLDIV:
-	case OASLMOD:
-	case OASMUL:
-	case OASDIV:
-	case OASMOD:
-		if(r->complex >= l->complex) {
-			n->complex = l->complex + 3;
-			if(r->complex > n->complex)
-				n->complex = r->complex;
-		} else {
-			n->complex = r->complex + 3;
-			if(l->complex > n->complex)
-				n->complex = l->complex;
-		}
-		break;
-
-	case OLSHR:
-	case OASHL:
-	case OASHR:
-	case OASLSHR:
-	case OASASHL:
-	case OASASHR:
-		if(r->complex >= l->complex) {
-			n->complex = l->complex + 2;
-			if(r->complex > n->complex)
-				n->complex = r->complex;
-		} else {
-			n->complex = r->complex + 2;
-			if(l->complex > n->complex)
-				n->complex = l->complex;
-		}
-		break;
-
-	case OADD:
-	case OXOR:
-	case OAND:
-	case OOR:
-		/*
-		 * immediate operators, make const on right
-		 */
-		if(l->op == OCONST) {
-			n->left = r;
-			n->right = l;
-		}
-		break;
-
-	case OEQ:
-	case ONE:
-	case OLE:
-	case OLT:
-	case OGE:
-	case OGT:
-	case OHI:
-	case OHS:
-	case OLO:
-	case OLS:
-		/*
-		 * compare operators, make const on left
-		 */
-		if(r->op == OCONST) {
-			n->left = r;
-			n->right = l;
-			n->op = invrel[relindex(n->op)];
-		}
-		break;
-	}
-}
-
-void
-indx(Node *n)
-{
-	Node *l, *r;
-
-	if(debug['x'])
-		prtree(n, "indx");
-
-	l = n->left;
-	r = n->right;
-	if(l->addable == 1 || l->addable == 13 || r->complex > l->complex) {
-		n->right = l;
-		n->left = r;
-		l = r;
-		r = n->right;
-	}
-	if(l->addable != 7) {
-		idx.regtree = l;
-		idx.scale = 1;
-	} else
-	if(l->right->addable == 20) {
-		idx.regtree = l->left;
-		idx.scale = 1 << l->right->vconst;
-	} else
-	if(l->left->addable == 20) {
-		idx.regtree = l->right;
-		idx.scale = 1 << l->left->vconst;
-	} else
-		diag(n, "bad index");
-
-	idx.basetree = r;
-	if(debug['x']) {
-		print("scale = %d\n", idx.scale);
-		prtree(idx.regtree, "index");
-		prtree(idx.basetree, "base");
-	}
-}
diff --git a/src/cmd/8c/swt.c b/src/cmd/8c/swt.c
deleted file mode 100644
index d960519..0000000
--- a/src/cmd/8c/swt.c
+++ /dev/null
@@ -1,341 +0,0 @@
-// Inferno utils/8c/swt.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8c/swt.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include "gc.h"
-
-void
-swit1(C1 *q, int nc, int32 def, Node *n)
-{
-	Node nreg;
-
-	if(typev[n->type->etype]) {
-		regsalloc(&nreg, n);
-		nreg.type = types[TVLONG];
-		cgen(n, &nreg);
-		swit2(q, nc, def, &nreg);
-		return;
-	}
-
-	regalloc(&nreg, n, Z);
-	nreg.type = types[TLONG];
-	cgen(n, &nreg);
-	swit2(q, nc, def, &nreg);
-	regfree(&nreg);
-}
-
-void
-swit2(C1 *q, int nc, int32 def, Node *n)
-{
-	C1 *r;
-	int i;
-	Prog *sp;
-
-	if(nc < 5) {
-		for(i=0; i<nc; i++) {
-			if(debug['W'])
-				print("case = %.8ux\n", q->val);
-			gopcode(OEQ, n->type, n, nodconst(q->val));
-			patch(p, q->label);
-			q++;
-		}
-		gbranch(OGOTO);
-		patch(p, def);
-		return;
-	}
-	i = nc / 2;
-	r = q+i;
-	if(debug['W'])
-		print("case > %.8ux\n", r->val);
-	gopcode(OGT, n->type, n, nodconst(r->val));
-	sp = p;
-	gbranch(OGOTO);
-	p->as = AJEQ;
-	patch(p, r->label);
-	swit2(q, i, def, n);
-
-	if(debug['W'])
-		print("case < %.8ux\n", r->val);
-	patch(sp, pc);
-	swit2(r+1, nc-i-1, def, n);
-}
-
-void
-bitload(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
-{
-	int sh;
-	int32 v;
-	Node *l;
-
-	/*
-	 * n1 gets adjusted/masked value
-	 * n2 gets address of cell
-	 * n3 gets contents of cell
-	 */
-	l = b->left;
-	if(n2 != Z) {
-		regalloc(n1, l, nn);
-		reglcgen(n2, l, Z);
-		regalloc(n3, l, Z);
-		gmove(n2, n3);
-		gmove(n3, n1);
-	} else {
-		regalloc(n1, l, nn);
-		cgen(l, n1);
-	}
-	if(b->type->shift == 0 && typeu[b->type->etype]) {
-		v = ~0 + (1L << b->type->nbits);
-		gopcode(OAND, types[TLONG], nodconst(v), n1);
-	} else {
-		sh = 32 - b->type->shift - b->type->nbits;
-		if(sh > 0)
-			gopcode(OASHL, types[TLONG], nodconst(sh), n1);
-		sh += b->type->shift;
-		if(sh > 0)
-			if(typeu[b->type->etype])
-				gopcode(OLSHR, types[TLONG], nodconst(sh), n1);
-			else
-				gopcode(OASHR, types[TLONG], nodconst(sh), n1);
-	}
-}
-
-void
-bitstore(Node *b, Node *n1, Node *n2, Node *n3, Node *nn)
-{
-	int32 v;
-	Node nod;
-	int sh;
-
-	regalloc(&nod, b->left, Z);
-	v = ~0 + (1L << b->type->nbits);
-	gopcode(OAND, types[TLONG], nodconst(v), n1);
-	gmove(n1, &nod);
-	if(nn != Z)
-		gmove(n1, nn);
-	sh = b->type->shift;
-	if(sh > 0)
-		gopcode(OASHL, types[TLONG], nodconst(sh), &nod);
-	v <<= sh;
-	gopcode(OAND, types[TLONG], nodconst(~v), n3);
-	gopcode(OOR, types[TLONG], n3, &nod);
-	gmove(&nod, n2);
-
-	regfree(&nod);
-	regfree(n1);
-	regfree(n2);
-	regfree(n3);
-}
-
-int32
-outstring(char *s, int32 n)
-{
-	int32 r;
-
-	if(suppress)
-		return nstring;
-	r = nstring;
-	while(n) {
-		string[mnstring] = *s++;
-		mnstring++;
-		nstring++;
-		if(mnstring >= NSNAME) {
-			gpseudo(ADATA, symstring, nodconst(0L));
-			p->from.offset += nstring - NSNAME;
-			p->from.scale = NSNAME;
-			p->to.type = D_SCONST;
-			memmove(p->to.u.sval, string, NSNAME);
-			mnstring = 0;
-		}
-		n--;
-	}
-	return r;
-}
-
-void
-sextern(Sym *s, Node *a, int32 o, int32 w)
-{
-	int32 e, lw;
-
-	for(e=0; e<w; e+=NSNAME) {
-		lw = NSNAME;
-		if(w-e < lw)
-			lw = w-e;
-		gpseudo(ADATA, s, nodconst(0L));
-		p->from.offset += o+e;
-		p->from.scale = lw;
-		p->to.type = D_SCONST;
-		memmove(p->to.u.sval, a->cstring+e, lw);
-	}
-}
-
-void
-gextern(Sym *s, Node *a, int32 o, int32 w)
-{
-	if(a->op == OCONST && typev[a->type->etype]) {
-		gpseudo(ADATA, s, lo64(a));
-		p->from.offset += o;
-		p->from.scale = 4;
-		gpseudo(ADATA, s, hi64(a));
-		p->from.offset += o + 4;
-		p->from.scale = 4;
-		return;
-	}
-	gpseudo(ADATA, s, a);
-	p->from.offset += o;
-	p->from.scale = w;
-	switch(p->to.type) {
-	default:
-		p->to.index = p->to.type;
-		p->to.type = D_ADDR;
-	case D_CONST:
-	case D_FCONST:
-	case D_ADDR:
-		break;
-	}
-}
-
-void
-outcode(void)
-{
-	int f;
-	Biobuf b;
-
-	f = open(outfile, OWRITE);
-	if(f < 0) {
-		diag(Z, "cannot open %s", outfile);
-		return;
-	}
-	Binit(&b, f, OWRITE);
-
-	Bprint(&b, "go object %s %s %s\n", getgoos(), getgoarch(), getgoversion());
-	if(pragcgobuf.to > pragcgobuf.start) {
-		Bprint(&b, "\n");
-		Bprint(&b, "$$  // exports\n\n");
-		Bprint(&b, "$$  // local types\n\n");
-		Bprint(&b, "$$  // cgo\n");
-		Bprint(&b, "%s", fmtstrflush(&pragcgobuf));
-		Bprint(&b, "\n$$\n\n");
-	}
-	Bprint(&b, "!\n");
-
-	writeobj(ctxt, &b);
-	Bterm(&b);
-	close(f);
-	lastp = P;
-}
-
-int32
-align(int32 i, Type *t, int op, int32 *maxalign)
-{
-	int32 o;
-	Type *v;
-	int w, packw;
-
-	o = i;
-	w = 1;
-	packw = 0;
-	switch(op) {
-	default:
-		diag(Z, "unknown align opcode %d", op);
-		break;
-
-	case Asu2:	/* padding at end of a struct */
-		w = *maxalign;
-		if(w < 1)
-			w = 1;
-		if(packflg)
-			packw = packflg;
-		break;
-
-	case Ael1:	/* initial align of struct element */
-		for(v=t; v->etype==TARRAY; v=v->link)
-			;
-		if(v->etype == TSTRUCT || v->etype == TUNION)
-			w = v->align;
-		else {
-			w = ewidth[v->etype];
-			if(w == 8)
-				w = 4;
-		}
-		if(w < 1 || w > SZ_LONG)
-			fatal(Z, "align");
-		if(packflg) 
-			packw = packflg;
-		break;
-
-	case Ael2:	/* width of a struct element */
-		o += t->width;
-		break;
-
-	case Aarg0:	/* initial passbyptr argument in arg list */
-		if(typesuv[t->etype]) {
-			o = align(o, types[TIND], Aarg1, nil);
-			o = align(o, types[TIND], Aarg2, nil);
-		}
-		break;
-
-	case Aarg1:	/* initial align of parameter */
-		w = ewidth[t->etype];
-		if(w <= 0 || w >= SZ_LONG) {
-			w = SZ_LONG;
-			break;
-		}
-		w = 1;		/* little endian no adjustment */
-		break;
-
-	case Aarg2:	/* width of a parameter */
-		o += t->width;
-		w = t->width;
-		if(w > SZ_LONG)
-			w = SZ_LONG;
-		break;
-
-	case Aaut3:	/* total align of automatic */
-		o = align(o, t, Ael1, nil);
-		o = align(o, t, Ael2, nil);
-		break;
-	}
-	if(packw != 0 && xround(o, w) != xround(o, packw))
-		diag(Z, "#pragma pack changes offset of %T", t);
-	o = xround(o, w);
-	if(maxalign && *maxalign < w)
-		*maxalign = w;
-	if(debug['A'])
-		print("align %s %d %T = %d\n", bnames[op], i, t, o);
-	return o;
-}
-
-int32
-maxround(int32 max, int32 v)
-{
-	v = xround(v, SZ_LONG);
-	if(v > max)
-		return v;
-	return max;
-}
diff --git a/src/cmd/8c/txt.c b/src/cmd/8c/txt.c
deleted file mode 100644
index 7f87a0a..0000000
--- a/src/cmd/8c/txt.c
+++ /dev/null
@@ -1,1537 +0,0 @@
-// Inferno utils/8c/txt.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8c/txt.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include "gc.h"
-
-
-int thechar = '8';
-char *thestring = "386";
-
-LinkArch	*thelinkarch = &link386;
-
-void
-linkarchinit(void)
-{
-}
-
-void
-ginit(void)
-{
-	int i;
-	Type *t;
-
-	exregoffset = 0;
-	exfregoffset = 0;
-	listinit();
-	nstring = 0;
-	mnstring = 0;
-	nrathole = 0;
-	pc = 0;
-	breakpc = -1;
-	continpc = -1;
-	cases = C;
-	lastp = P;
-	tfield = types[TLONG];
-
-	zprog.link = P;
-	zprog.as = AGOK;
-	zprog.from.type = D_NONE;
-	zprog.from.index = D_NONE;
-	zprog.from.scale = 0;
-	zprog.to = zprog.from;
-
-	regnode.op = OREGISTER;
-	regnode.class = CEXREG;
-	regnode.reg = REGTMP;
-	regnode.complex = 0;
-	regnode.addable = 11;
-	regnode.type = types[TLONG];
-
-	fregnode0 = regnode;
-	fregnode0.reg = D_F0;
-	fregnode0.type = types[TDOUBLE];
-
-	fregnode1 = fregnode0;
-	fregnode1.reg = D_F0+1;
-
-	constnode.op = OCONST;
-	constnode.class = CXXX;
-	constnode.complex = 0;
-	constnode.addable = 20;
-	constnode.type = types[TLONG];
-
-	fconstnode.op = OCONST;
-	fconstnode.class = CXXX;
-	fconstnode.complex = 0;
-	fconstnode.addable = 20;
-	fconstnode.type = types[TDOUBLE];
-
-	nodsafe = new(ONAME, Z, Z);
-	nodsafe->sym = slookup(".safe");
-	nodsafe->type = types[TINT];
-	nodsafe->etype = types[TINT]->etype;
-	nodsafe->class = CAUTO;
-	complex(nodsafe);
-
-	t = typ(TARRAY, types[TCHAR]);
-	symrathole = slookup(".rathole");
-	symrathole->class = CGLOBL;
-	symrathole->type = t;
-
-	nodrat = new(ONAME, Z, Z);
-	nodrat->sym = symrathole;
-	nodrat->type = types[TIND];
-	nodrat->etype = TVOID;
-	nodrat->class = CGLOBL;
-	complex(nodrat);
-	nodrat->type = t;
-
-	nodret = new(ONAME, Z, Z);
-	nodret->sym = slookup(".ret");
-	nodret->type = types[TIND];
-	nodret->etype = TIND;
-	nodret->class = CPARAM;
-	nodret = new(OIND, nodret, Z);
-	complex(nodret);
-
-	com64init();
-
-	for(i=0; i<nelem(reg); i++) {
-		reg[i] = 1;
-		if(i >= D_AX && i <= D_DI && i != D_SP)
-			reg[i] = 0;
-	}
-}
-
-void
-gclean(void)
-{
-	int i;
-	Sym *s;
-
-	reg[D_SP]--;
-	for(i=D_AX; i<=D_DI; i++)
-		if(reg[i])
-			diag(Z, "reg %R left allocated", i);
-	while(mnstring)
-		outstring("", 1L);
-	symstring->type->width = nstring;
-	symrathole->type->width = nrathole;
-	for(i=0; i<NHASH; i++)
-	for(s = hash[i]; s != S; s = s->link) {
-		if(s->type == T)
-			continue;
-		if(s->type->width == 0)
-			continue;
-		if(s->class != CGLOBL && s->class != CSTATIC)
-			continue;
-		if(s->type == types[TENUM])
-			continue;
-		gpseudo(AGLOBL, s, nodconst(s->type->width));
-	}
-	nextpc();
-	p->as = AEND;
-	outcode();
-}
-
-void
-nextpc(void)
-{
-	Plist *pl;
-
-	p = alloc(sizeof(*p));
-	*p = zprog;
-	p->lineno = nearln;
-	p->pc = pc;
-	pc++;
-	if(lastp == nil) {
-		pl = linknewplist(ctxt);
-		pl->firstpc = p;
-	} else
-		lastp->link = p;
-	lastp = p;
-}
-
-void
-gargs(Node *n, Node *tn1, Node *tn2)
-{
-	int32 regs;
-	Node fnxargs[20], *fnxp;
-
-	regs = cursafe;
-
-	fnxp = fnxargs;
-	garg1(n, tn1, tn2, 0, &fnxp);	/* compile fns to temps */
-
-	curarg = 0;
-	fnxp = fnxargs;
-	garg1(n, tn1, tn2, 1, &fnxp);	/* compile normal args and temps */
-
-	cursafe = regs;
-}
-
-int
-nareg(void)
-{
-	int i, n;
-
-	n = 0;
-	for(i=D_AX; i<=D_DI; i++)
-		if(reg[i] == 0)
-			n++;
-	return n;
-}
-
-void
-garg1(Node *n, Node *tn1, Node *tn2, int f, Node **fnxp)
-{
-	Node nod;
-
-	if(n == Z)
-		return;
-	if(n->op == OLIST) {
-		garg1(n->left, tn1, tn2, f, fnxp);
-		garg1(n->right, tn1, tn2, f, fnxp);
-		return;
-	}
-	if(f == 0) {
-		if(n->complex >= FNX) {
-			regsalloc(*fnxp, n);
-			nod = znode;
-			nod.op = OAS;
-			nod.left = *fnxp;
-			nod.right = n;
-			nod.type = n->type;
-			cgen(&nod, Z);
-			(*fnxp)++;
-		}
-		return;
-	}
-	if(typesu[n->type->etype] || typev[n->type->etype]) {
-		regaalloc(tn2, n);
-		if(n->complex >= FNX) {
-			sugen(*fnxp, tn2, n->type->width);
-			(*fnxp)++;
-		} else
-			sugen(n, tn2, n->type->width);
-		return;
-	}
-	if(REGARG >= 0 && curarg == 0 && typeilp[n->type->etype]) {
-		regaalloc1(tn1, n);
-		if(n->complex >= FNX) {
-			cgen(*fnxp, tn1);
-			(*fnxp)++;
-		} else
-			cgen(n, tn1);
-		return;
-	}
-	if(vconst(n) == 0) {
-		regaalloc(tn2, n);
-		gmove(n, tn2);
-		return;
-	}
-	regalloc(tn1, n, Z);
-	if(n->complex >= FNX) {
-		cgen(*fnxp, tn1);
-		(*fnxp)++;
-	} else
-		cgen(n, tn1);
-	regaalloc(tn2, n);
-	gmove(tn1, tn2);
-	regfree(tn1);
-}
-
-Node*
-nodconst(int32 v)
-{
-	constnode.vconst = v;
-	return &constnode;
-}
-
-Node*
-nodfconst(double d)
-{
-	fconstnode.fconst = d;
-	return &fconstnode;
-}
-
-int
-isreg(Node *n, int r)
-{
-
-	if(n->op == OREGISTER)
-		if(n->reg == r)
-			return 1;
-	return 0;
-}
-
-int
-nodreg(Node *n, Node *nn, int r)
-{
-
-	*n = regnode;
-	n->reg = r;
-	if(reg[r] == 0)
-		return 0;
-	if(nn != Z) {
-		n->type = nn->type;
-		n->lineno = nn->lineno;
-		if(nn->op == OREGISTER)
-		if(nn->reg == r)
-			return 0;
-	}
-	return 1;
-}
-
-void
-regret(Node *n, Node *nn, Type *t, int mode)
-{
-	int r;
-
-	if(mode == 0 || hasdotdotdot(t) || nn->type->width == 0) {
-		r = REGRET;
-		if(typefd[nn->type->etype])
-			r = FREGRET;
-		nodreg(n, nn, r);
-		reg[r]++;
-		return;
-	}
-	
-	if(mode == 1) {
-		// fetch returned value after call.
-		// already called gargs, so curarg is set.
-		curarg = (curarg+3) & ~3;
-		regaalloc(n, nn);
-		return;
-	}
-	
-	if(mode == 2) {
-		// store value to be returned.
-		// must compute arg offset.
-		if(t->etype != TFUNC)
-			fatal(Z, "bad regret func %T", t);
-		*n = *nn;
-		n->op = ONAME;
-		n->class = CPARAM;
-		n->sym = slookup(".retx");
-		n->complex = 0;
-		n->addable = 20;
-		n->xoffset = argsize(0);
-		return;
-	}
-	
-	fatal(Z, "bad regret");
-}
-
-void
-regalloc(Node *n, Node *tn, Node *o)
-{
-	int i;
-
-	switch(tn->type->etype) {
-	case TCHAR:
-	case TUCHAR:
-	case TSHORT:
-	case TUSHORT:
-	case TINT:
-	case TUINT:
-	case TLONG:
-	case TULONG:
-	case TIND:
-		if(o != Z && o->op == OREGISTER) {
-			i = o->reg;
-			if(i >= D_AX && i <= D_DI)
-				goto out;
-		}
-		for(i=D_AX; i<=D_DI; i++)
-			if(reg[i] == 0)
-				goto out;
-		diag(tn, "out of fixed registers");
-		goto err;
-
-	case TFLOAT:
-	case TDOUBLE:
-	case TVLONG:
-		i = D_F0;
-		goto out;
-	}
-	diag(tn, "unknown type in regalloc: %T", tn->type);
-err:
-	i = 0;
-out:
-	if(i)
-		reg[i]++;
-	nodreg(n, tn, i);
-}
-
-void
-regialloc(Node *n, Node *tn, Node *o)
-{
-	Node nod;
-
-	nod = *tn;
-	nod.type = types[TIND];
-	regalloc(n, &nod, o);
-}
-
-void
-regfree(Node *n)
-{
-	int i;
-
-	i = 0;
-	if(n->op != OREGISTER && n->op != OINDREG)
-		goto err;
-	i = n->reg;
-	if(i < 0 || i >= nelem(reg))
-		goto err;
-	if(reg[i] <= 0)
-		goto err;
-	reg[i]--;
-	return;
-err:
-	diag(n, "error in regfree: %R", i);
-}
-
-void
-regsalloc(Node *n, Node *nn)
-{
-	cursafe = align(cursafe, nn->type, Aaut3, nil);
-	maxargsafe = maxround(maxargsafe, cursafe+curarg);
-	*n = *nodsafe;
-	n->xoffset = -(stkoff + cursafe);
-	n->type = nn->type;
-	n->etype = nn->type->etype;
-	n->lineno = nn->lineno;
-}
-
-void
-regaalloc1(Node *n, Node *nn)
-{
-	if(REGARG < 0) {
-		fatal(n, "regaalloc1 and REGARG<0");
-		return;
-	}
-	nodreg(n, nn, REGARG);
-	reg[REGARG]++;
-	curarg = align(curarg, nn->type, Aarg1, nil);
-	curarg = align(curarg, nn->type, Aarg2, nil);
-	maxargsafe = maxround(maxargsafe, cursafe+curarg);
-}
-
-void
-regaalloc(Node *n, Node *nn)
-{
-	curarg = align(curarg, nn->type, Aarg1, nil);
-	*n = *nn;
-	n->op = OINDREG;
-	n->reg = REGSP;
-	n->xoffset = curarg;
-	n->complex = 0;
-	n->addable = 20;
-	curarg = align(curarg, nn->type, Aarg2, nil);
-	maxargsafe = maxround(maxargsafe, cursafe+curarg);
-}
-
-void
-regind(Node *n, Node *nn)
-{
-
-	if(n->op != OREGISTER) {
-		diag(n, "regind not OREGISTER");
-		return;
-	}
-	n->op = OINDREG;
-	n->type = nn->type;
-}
-
-void
-naddr(Node *n, Addr *a)
-{
-	int32 v;
-
-	a->type = D_NONE;
-	if(n == Z)
-		return;
-	switch(n->op) {
-	default:
-	bad:
-		diag(n, "bad in naddr: %O %D", n->op, a);
-		break;
-
-	case OREGISTER:
-		a->type = n->reg;
-		a->sym = nil;
-		break;
-
-	case OEXREG:
-		a->type = D_INDIR + D_TLS;
-		a->offset = n->reg - 1;
-		break;
-
-	case OIND:
-		naddr(n->left, a);
-		if(a->type >= D_AX && a->type <= D_DI)
-			a->type += D_INDIR;
-		else
-		if(a->type == D_CONST)
-			a->type = D_NONE+D_INDIR;
-		else
-		if(a->type == D_ADDR) {
-			a->type = a->index;
-			a->index = D_NONE;
-		} else
-			goto bad;
-		break;
-
-	case OINDEX:
-		a->type = idx.ptr;
-		if(n->left->op == OADDR || n->left->op == OCONST)
-			naddr(n->left, a);
-		if(a->type >= D_AX && a->type <= D_DI)
-			a->type += D_INDIR;
-		else
-		if(a->type == D_CONST)
-			a->type = D_NONE+D_INDIR;
-		else
-		if(a->type == D_ADDR) {
-			a->type = a->index;
-			a->index = D_NONE;
-		} else
-			goto bad;
-		a->index = idx.reg;
-		a->scale = n->scale;
-		a->offset += n->xoffset;
-		break;
-
-	case OINDREG:
-		a->type = n->reg+D_INDIR;
-		a->sym = nil;
-		a->offset = n->xoffset;
-		break;
-
-	case ONAME:
-		a->etype = n->etype;
-		a->type = D_STATIC;
-		a->sym = linksym(n->sym);
-		a->offset = n->xoffset;
-		if(n->class == CSTATIC)
-			break;
-		if(n->class == CEXTERN || n->class == CGLOBL) {
-			a->type = D_EXTERN;
-			break;
-		}
-		if(n->class == CAUTO) {
-			a->type = D_AUTO;
-			break;
-		}
-		if(n->class == CPARAM) {
-			a->type = D_PARAM;
-			break;
-		}
-		goto bad;
-
-	case OCONST:
-		if(typefd[n->type->etype]) {
-			a->type = D_FCONST;
-			a->u.dval = n->fconst;
-			break;
-		}
-		a->sym = nil;
-		a->type = D_CONST;
-		a->offset = n->vconst;
-		break;
-
-	case OADDR:
-		naddr(n->left, a);
-		if(a->type >= D_INDIR) {
-			a->type -= D_INDIR;
-			break;
-		}
-		if(a->type == D_EXTERN || a->type == D_STATIC ||
-		   a->type == D_AUTO || a->type == D_PARAM)
-			if(a->index == D_NONE) {
-				a->index = a->type;
-				a->type = D_ADDR;
-				break;
-			}
-		goto bad;
-
-	case OADD:
-		if(n->right->op == OCONST) {
-			v = n->right->vconst;
-			naddr(n->left, a);
-		} else
-		if(n->left->op == OCONST) {
-			v = n->left->vconst;
-			naddr(n->right, a);
-		} else
-			goto bad;
-		a->offset += v;
-		break;
-
-	}
-}
-
-#define	CASE(a,b)	((a<<8)|(b<<0))
-
-void
-gmove(Node *f, Node *t)
-{
-	int ft, tt, a;
-	Node nod, nod1;
-	Prog *p1;
-
-	ft = f->type->etype;
-	tt = t->type->etype;
-	if(debug['M'])
-		print("gop: %O %O[%s],%O[%s]\n", OAS,
-			f->op, tnames[ft], t->op, tnames[tt]);
-	if(typefd[ft] && f->op == OCONST) {
-		if(f->fconst == 0)
-			gins(AFLDZ, Z, Z);
-		else
-		if(f->fconst == 1)
-			gins(AFLD1, Z, Z);
-		else
-			gins(AFMOVD, f, &fregnode0);
-		gmove(&fregnode0, t);
-		return;
-	}
-/*
- * load
- */
-	if(f->op == ONAME || f->op == OINDREG ||
-	   f->op == OIND || f->op == OINDEX)
-	switch(ft) {
-	case TCHAR:
-		a = AMOVBLSX;
-		goto ld;
-	case TUCHAR:
-		a = AMOVBLZX;
-		goto ld;
-	case TSHORT:
-		if(typefd[tt]) {
-			gins(AFMOVW, f, &fregnode0);
-			gmove(&fregnode0, t);
-			return;
-		}
-		a = AMOVWLSX;
-		goto ld;
-	case TUSHORT:
-		a = AMOVWLZX;
-		goto ld;
-	case TINT:
-	case TUINT:
-	case TLONG:
-	case TULONG:
-	case TIND:
-		if(typefd[tt]) {
-			gins(AFMOVL, f, &fregnode0);
-			gmove(&fregnode0, t);
-			return;
-		}
-		a = AMOVL;
-
-	ld:
-		regalloc(&nod, f, t);
-		nod.type = types[TLONG];
-		gins(a, f, &nod);
-		gmove(&nod, t);
-		regfree(&nod);
-		return;
-
-	case TFLOAT:
-		gins(AFMOVF, f, t);
-		return;
-	case TDOUBLE:
-		gins(AFMOVD, f, t);
-		return;
-	case TVLONG:
-		gins(AFMOVV, f, t);
-		return;
-	}
-
-/*
- * store
- */
-	if(t->op == ONAME || t->op == OINDREG ||
-	   t->op == OIND || t->op == OINDEX)
-	switch(tt) {
-	case TCHAR:
-	case TUCHAR:
-		a = AMOVB;	goto st;
-	case TSHORT:
-	case TUSHORT:
-		a = AMOVW;	goto st;
-	case TINT:
-	case TUINT:
-	case TLONG:
-	case TULONG:
-	case TIND:
-		a = AMOVL;	goto st;
-
-	st:
-		if(f->op == OCONST) {
-			gins(a, f, t);
-			return;
-		}
-		regalloc(&nod, t, f);
-		gmove(f, &nod);
-		gins(a, &nod, t);
-		regfree(&nod);
-		return;
-
-	case TFLOAT:
-		gins(AFMOVFP, f, t);
-		return;
-	case TDOUBLE:
-		gins(AFMOVDP, f, t);
-		return;
-	case TVLONG:
-		gins(AFMOVVP, f, t);
-		return;
-	}
-
-/*
- * convert
- */
-	switch(CASE(ft,tt)) {
-	default:
-/*
- * integer to integer
- ********
-		a = AGOK;	break;
-
-	case CASE(	TCHAR,	TCHAR):
-	case CASE(	TUCHAR,	TCHAR):
-	case CASE(	TSHORT,	TCHAR):
-	case CASE(	TUSHORT,TCHAR):
-	case CASE(	TINT,	TCHAR):
-	case CASE(	TUINT,	TCHAR):
-	case CASE(	TLONG,	TCHAR):
-	case CASE(	TULONG,	TCHAR):
-	case CASE(	TIND,	TCHAR):
-
-	case CASE(	TCHAR,	TUCHAR):
-	case CASE(	TUCHAR,	TUCHAR):
-	case CASE(	TSHORT,	TUCHAR):
-	case CASE(	TUSHORT,TUCHAR):
-	case CASE(	TINT,	TUCHAR):
-	case CASE(	TUINT,	TUCHAR):
-	case CASE(	TLONG,	TUCHAR):
-	case CASE(	TULONG,	TUCHAR):
-	case CASE(	TIND,	TUCHAR):
-
-	case CASE(	TSHORT,	TSHORT):
-	case CASE(	TUSHORT,TSHORT):
-	case CASE(	TINT,	TSHORT):
-	case CASE(	TUINT,	TSHORT):
-	case CASE(	TLONG,	TSHORT):
-	case CASE(	TULONG,	TSHORT):
-	case CASE(	TIND,	TSHORT):
-
-	case CASE(	TSHORT,	TUSHORT):
-	case CASE(	TUSHORT,TUSHORT):
-	case CASE(	TINT,	TUSHORT):
-	case CASE(	TUINT,	TUSHORT):
-	case CASE(	TLONG,	TUSHORT):
-	case CASE(	TULONG,	TUSHORT):
-	case CASE(	TIND,	TUSHORT):
-
-	case CASE(	TINT,	TINT):
-	case CASE(	TUINT,	TINT):
-	case CASE(	TLONG,	TINT):
-	case CASE(	TULONG,	TINT):
-	case CASE(	TIND,	TINT):
-
-	case CASE(	TINT,	TUINT):
-	case CASE(	TUINT,	TUINT):
-	case CASE(	TLONG,	TUINT):
-	case CASE(	TULONG,	TUINT):
-	case CASE(	TIND,	TUINT):
-
-	case CASE(	TINT,	TLONG):
-	case CASE(	TUINT,	TLONG):
-	case CASE(	TLONG,	TLONG):
-	case CASE(	TULONG,	TLONG):
-	case CASE(	TIND,	TLONG):
-
-	case CASE(	TINT,	TULONG):
-	case CASE(	TUINT,	TULONG):
-	case CASE(	TLONG,	TULONG):
-	case CASE(	TULONG,	TULONG):
-	case CASE(	TIND,	TULONG):
-
-	case CASE(	TINT,	TIND):
-	case CASE(	TUINT,	TIND):
-	case CASE(	TLONG,	TIND):
-	case CASE(	TULONG,	TIND):
-	case CASE(	TIND,	TIND):
- *****/
-		a = AMOVL;
-		break;
-
-	case CASE(	TSHORT,	TINT):
-	case CASE(	TSHORT,	TUINT):
-	case CASE(	TSHORT,	TLONG):
-	case CASE(	TSHORT,	TULONG):
-	case CASE(	TSHORT,	TIND):
-		a = AMOVWLSX;
-		if(f->op == OCONST) {
-			f->vconst &= 0xffff;
-			if(f->vconst & 0x8000)
-				f->vconst |= 0xffff0000;
-			a = AMOVL;
-		}
-		break;
-
-	case CASE(	TUSHORT,TINT):
-	case CASE(	TUSHORT,TUINT):
-	case CASE(	TUSHORT,TLONG):
-	case CASE(	TUSHORT,TULONG):
-	case CASE(	TUSHORT,TIND):
-		a = AMOVWLZX;
-		if(f->op == OCONST) {
-			f->vconst &= 0xffff;
-			a = AMOVL;
-		}
-		break;
-
-	case CASE(	TCHAR,	TSHORT):
-	case CASE(	TCHAR,	TUSHORT):
-	case CASE(	TCHAR,	TINT):
-	case CASE(	TCHAR,	TUINT):
-	case CASE(	TCHAR,	TLONG):
-	case CASE(	TCHAR,	TULONG):
-	case CASE(	TCHAR,	TIND):
-		a = AMOVBLSX;
-		if(f->op == OCONST) {
-			f->vconst &= 0xff;
-			if(f->vconst & 0x80)
-				f->vconst |= 0xffffff00;
-			a = AMOVL;
-		}
-		break;
-
-	case CASE(	TUCHAR,	TSHORT):
-	case CASE(	TUCHAR,	TUSHORT):
-	case CASE(	TUCHAR,	TINT):
-	case CASE(	TUCHAR,	TUINT):
-	case CASE(	TUCHAR,	TLONG):
-	case CASE(	TUCHAR,	TULONG):
-	case CASE(	TUCHAR,	TIND):
-		a = AMOVBLZX;
-		if(f->op == OCONST) {
-			f->vconst &= 0xff;
-			a = AMOVL;
-		}
-		break;
-
-/*
- * float to fix
- */
-	case CASE(	TFLOAT,	TCHAR):
-	case CASE(	TFLOAT,	TUCHAR):
-	case CASE(	TFLOAT,	TSHORT):
-	case CASE(	TFLOAT,	TUSHORT):
-	case CASE(	TFLOAT,	TINT):
-	case CASE(	TFLOAT,	TUINT):
-	case CASE(	TFLOAT,	TLONG):
-	case CASE(	TFLOAT,	TULONG):
-	case CASE(	TFLOAT,	TIND):
-
-	case CASE(	TDOUBLE,TCHAR):
-	case CASE(	TDOUBLE,TUCHAR):
-	case CASE(	TDOUBLE,TSHORT):
-	case CASE(	TDOUBLE,TUSHORT):
-	case CASE(	TDOUBLE,TINT):
-	case CASE(	TDOUBLE,TUINT):
-	case CASE(	TDOUBLE,TLONG):
-	case CASE(	TDOUBLE,TULONG):
-	case CASE(	TDOUBLE,TIND):
-
-	case CASE(	TVLONG,	TCHAR):
-	case CASE(	TVLONG,	TUCHAR):
-	case CASE(	TVLONG,	TSHORT):
-	case CASE(	TVLONG,	TUSHORT):
-	case CASE(	TVLONG,	TINT):
-	case CASE(	TVLONG,	TUINT):
-	case CASE(	TVLONG,	TLONG):
-	case CASE(	TVLONG,	TULONG):
-	case CASE(	TVLONG,	TIND):
-		if(fproundflg) {
-			regsalloc(&nod, &regnode);
-			gins(AFMOVLP, f, &nod);
-			gmove(&nod, t);
-			return;
-		}
-		regsalloc(&nod, &regnode);
-		regsalloc(&nod1, &regnode);
-		gins(AFSTCW, Z, &nod1);
-		nod1.xoffset += 2;
-		gins(AMOVW, nodconst(0xf7f), &nod1);
-		gins(AFLDCW, &nod1, Z);
-		gins(AFMOVLP, f, &nod);
-		nod1.xoffset -= 2;
-		gins(AFLDCW, &nod1, Z);
-		gmove(&nod, t);
-		return;
-
-/*
- * ulong to float
- */
-	case CASE(	TULONG,	TDOUBLE):
-	case CASE(	TULONG,	TVLONG):
-	case CASE(	TULONG,	TFLOAT):
-	case CASE(	TUINT,	TDOUBLE):
-	case CASE(	TUINT,	TVLONG):
-	case CASE(	TUINT,	TFLOAT):
-		regalloc(&nod, f, f);
-		gmove(f, &nod);
-		regsalloc(&nod1, &regnode);
-		gmove(&nod, &nod1);
-		gins(AFMOVL, &nod1, &fregnode0);
-		gins(ACMPL, &nod, nodconst(0));
-		gins(AJGE, Z, Z);
-		p1 = p;
-		gins(AFADDD, nodfconst(4294967296.), &fregnode0);
-		patch(p1, pc);
-		regfree(&nod);
-		return;
-
-/*
- * fix to float
- */
-	case CASE(	TCHAR,	TFLOAT):
-	case CASE(	TUCHAR,	TFLOAT):
-	case CASE(	TSHORT,	TFLOAT):
-	case CASE(	TUSHORT,TFLOAT):
-	case CASE(	TINT,	TFLOAT):
-	case CASE(	TLONG,	TFLOAT):
-	case CASE(	TIND,	TFLOAT):
-
-	case CASE(	TCHAR,	TDOUBLE):
-	case CASE(	TUCHAR,	TDOUBLE):
-	case CASE(	TSHORT,	TDOUBLE):
-	case CASE(	TUSHORT,TDOUBLE):
-	case CASE(	TINT,	TDOUBLE):
-	case CASE(	TLONG,	TDOUBLE):
-	case CASE(	TIND,	TDOUBLE):
-
-	case CASE(	TCHAR,	TVLONG):
-	case CASE(	TUCHAR,	TVLONG):
-	case CASE(	TSHORT,	TVLONG):
-	case CASE(	TUSHORT,TVLONG):
-	case CASE(	TINT,	TVLONG):
-	case CASE(	TLONG,	TVLONG):
-	case CASE(	TIND,	TVLONG):
-		regsalloc(&nod, &regnode);
-		gmove(f, &nod);
-		gins(AFMOVL, &nod, &fregnode0);
-		return;
-
-/*
- * float to float
- */
-	case CASE(	TFLOAT,	TFLOAT):
-	case CASE(	TDOUBLE,TFLOAT):
-	case CASE(	TVLONG,	TFLOAT):
-
-	case CASE(	TFLOAT,	TDOUBLE):
-	case CASE(	TDOUBLE,TDOUBLE):
-	case CASE(	TVLONG,	TDOUBLE):
-
-	case CASE(	TFLOAT,	TVLONG):
-	case CASE(	TDOUBLE,TVLONG):
-	case CASE(	TVLONG,	TVLONG):
-		a = AFMOVD;	break;
-	}
-	if(a == AMOVL || a == AFMOVD)
-	if(samaddr(f, t))
-		return;
-	gins(a, f, t);
-}
-
-void
-doindex(Node *n)
-{
-	Node nod, nod1;
-	int32 v;
-
-if(debug['Y'])
-prtree(n, "index");
-
-if(n->left->complex >= FNX)
-print("botch in doindex\n");
-
-	regalloc(&nod, &regnode, Z);
-	v = constnode.vconst;
-	cgen(n->right, &nod);
-	idx.ptr = D_NONE;
-	if(n->left->op == OCONST)
-		idx.ptr = D_CONST;
-	else if(n->left->op == OREGISTER)
-		idx.ptr = n->left->reg;
-	else if(n->left->op != OADDR) {
-		reg[D_BP]++;	// can't be used as a base
-		regalloc(&nod1, &regnode, Z);
-		cgen(n->left, &nod1);
-		idx.ptr = nod1.reg;
-		regfree(&nod1);
-		reg[D_BP]--;
-	}
-	idx.reg = nod.reg;
-	regfree(&nod);
-	constnode.vconst = v;
-}
-
-void
-gins(int a, Node *f, Node *t)
-{
-
-	if(f != Z && f->op == OINDEX)
-		doindex(f);
-	if(t != Z && t->op == OINDEX)
-		doindex(t);
-	nextpc();
-	p->as = a;
-	if(f != Z)
-		naddr(f, &p->from);
-	if(t != Z)
-		naddr(t, &p->to);
-	if(debug['g'])
-		print("%P\n", p);
-}
-
-void
-fgopcode(int o, Node *f, Node *t, int pop, int rev)
-{
-	int a, et;
-	Node nod;
-
-	et = TLONG;
-	if(f != Z && f->type != T)
-		et = f->type->etype;
-	if(!typefd[et]) {
-		diag(f, "fop: integer %O", o);
-		return;
-	}
-	if(debug['M']) {
-		if(t != Z && t->type != T)
-			print("gop: %O %O-%s Z\n", o, f->op, tnames[et]);
-		else
-			print("gop: %O %O-%s %O-%s\n", o,
-				f->op, tnames[et], t->op, tnames[t->type->etype]);
-	}
-	a = AGOK;
-	switch(o) {
-
-	case OASADD:
-	case OADD:
-		if(et == TFLOAT)
-			a = AFADDF;
-		else
-		if(et == TDOUBLE || et == TVLONG) {
-			a = AFADDD;
-			if(pop)
-				a = AFADDDP;
-		}
-		break;
-
-	case OASSUB:
-	case OSUB:
-		if(et == TFLOAT) {
-			a = AFSUBF;
-			if(rev)
-				a = AFSUBRF;
-		} else
-		if(et == TDOUBLE || et == TVLONG) {
-			a = AFSUBD;
-			if(pop)
-				a = AFSUBDP;
-			if(rev) {
-				a = AFSUBRD;
-				if(pop)
-					a = AFSUBRDP;
-			}
-		}
-		break;
-
-	case OASMUL:
-	case OMUL:
-		if(et == TFLOAT)
-			a = AFMULF;
-		else
-		if(et == TDOUBLE || et == TVLONG) {
-			a = AFMULD;
-			if(pop)
-				a = AFMULDP;
-		}
-		break;
-
-	case OASMOD:
-	case OMOD:
-	case OASDIV:
-	case ODIV:
-		if(et == TFLOAT) {
-			a = AFDIVF;
-			if(rev)
-				a = AFDIVRF;
-		} else
-		if(et == TDOUBLE || et == TVLONG) {
-			a = AFDIVD;
-			if(pop)
-				a = AFDIVDP;
-			if(rev) {
-				a = AFDIVRD;
-				if(pop)
-					a = AFDIVRDP;
-			}
-		}
-		break;
-
-	case OEQ:
-	case ONE:
-	case OLT:
-	case OLE:
-	case OGE:
-	case OGT:
-		pop += rev;
-		if(et == TFLOAT) {
-			a = AFCOMF;
-			if(pop) {
-				a = AFCOMFP;
-				if(pop > 1)
-					a = AGOK;
-			}
-		} else
-		if(et == TDOUBLE || et == TVLONG) {
-			a = AFCOMF;
-			if(pop) {
-				a = AFCOMDP;
-				if(pop > 1)
-					a = AFCOMDPP;
-			}
-		}
-		gins(a, f, t);
-		regalloc(&nod, &regnode, Z);
-		if(nod.reg != D_AX) {
-			regfree(&nod);
-			nod.reg = D_AX;
-			gins(APUSHL, &nod, Z);
-			gins(AWAIT, Z, Z);
-			gins(AFSTSW, Z, &nod);
-			gins(ASAHF, Z, Z);
-			gins(APOPL, Z, &nod);
-		} else {
-			gins(AWAIT, Z, Z);
-			gins(AFSTSW, Z, &nod);
-			gins(ASAHF, Z, Z);
-			regfree(&nod);
-		}
-		switch(o) {
-		case OEQ:	a = AJEQ; break;
-		case ONE:	a = AJNE; break;
-		case OLT:	a = AJCS; break;
-		case OLE:	a = AJLS; break;
-		case OGE:	a = AJCC; break;
-		case OGT:	a = AJHI; break;
-		}
-		gins(a, Z, Z);
-		return;
-	}
-	if(a == AGOK)
-		diag(Z, "bad in gopcode %O", o);
-	gins(a, f, t);
-}
-
-void
-gopcode(int o, Type *ty, Node *f, Node *t)
-{
-	int a, et;
-
-	et = TLONG;
-	if(ty != T)
-		et = ty->etype;
-	if(typefd[et] && o != OADDR && o != OFUNC) {
-		diag(f, "gop: float %O", o);
-		return;
-	}
-	if(debug['M']) {
-		if(f != Z && f->type != T)
-			print("gop: %O %O[%s],", o, f->op, tnames[et]);
-		else
-			print("gop: %O Z,", o);
-		if(t != Z && t->type != T)
-			print("%O[%s]\n", t->op, tnames[t->type->etype]);
-		else
-			print("Z\n");
-	}
-	a = AGOK;
-	switch(o) {
-	case OCOM:
-		a = ANOTL;
-		if(et == TCHAR || et == TUCHAR)
-			a = ANOTB;
-		if(et == TSHORT || et == TUSHORT)
-			a = ANOTW;
-		break;
-
-	case ONEG:
-		a = ANEGL;
-		if(et == TCHAR || et == TUCHAR)
-			a = ANEGB;
-		if(et == TSHORT || et == TUSHORT)
-			a = ANEGW;
-		break;
-
-	case OADDR:
-		a = ALEAL;
-		break;
-
-	case OASADD:
-	case OADD:
-		a = AADDL;
-		if(et == TCHAR || et == TUCHAR)
-			a = AADDB;
-		if(et == TSHORT || et == TUSHORT)
-			a = AADDW;
-		break;
-
-	case OASSUB:
-	case OSUB:
-		a = ASUBL;
-		if(et == TCHAR || et == TUCHAR)
-			a = ASUBB;
-		if(et == TSHORT || et == TUSHORT)
-			a = ASUBW;
-		break;
-
-	case OASOR:
-	case OOR:
-		a = AORL;
-		if(et == TCHAR || et == TUCHAR)
-			a = AORB;
-		if(et == TSHORT || et == TUSHORT)
-			a = AORW;
-		break;
-
-	case OASAND:
-	case OAND:
-		a = AANDL;
-		if(et == TCHAR || et == TUCHAR)
-			a = AANDB;
-		if(et == TSHORT || et == TUSHORT)
-			a = AANDW;
-		break;
-
-	case OASXOR:
-	case OXOR:
-		a = AXORL;
-		if(et == TCHAR || et == TUCHAR)
-			a = AXORB;
-		if(et == TSHORT || et == TUSHORT)
-			a = AXORW;
-		break;
-
-	case OASLSHR:
-	case OLSHR:
-		a = ASHRL;
-		if(et == TCHAR || et == TUCHAR)
-			a = ASHRB;
-		if(et == TSHORT || et == TUSHORT)
-			a = ASHRW;
-		break;
-
-	case OASASHR:
-	case OASHR:
-		a = ASARL;
-		if(et == TCHAR || et == TUCHAR)
-			a = ASARB;
-		if(et == TSHORT || et == TUSHORT)
-			a = ASARW;
-		break;
-
-	case OASASHL:
-	case OASHL:
-		a = ASALL;
-		if(et == TCHAR || et == TUCHAR)
-			a = ASALB;
-		if(et == TSHORT || et == TUSHORT)
-			a = ASALW;
-		break;
-
-	case OROTL:
-		a = AROLL;
-		if(et == TCHAR || et == TUCHAR)
-			a = AROLB;
-		if(et == TSHORT || et == TUSHORT)
-			a = AROLW;
-		break;
-
-	case OFUNC:
-		a = ACALL;
-		break;
-
-	case OASMUL:
-	case OMUL:
-		if(f->op == OREGISTER && t != Z && isreg(t, D_AX) && reg[D_DX] == 0)
-			t = Z;
-		a = AIMULL;
-		break;
-
-	case OASMOD:
-	case OMOD:
-	case OASDIV:
-	case ODIV:
-		a = AIDIVL;
-		break;
-
-	case OASLMUL:
-	case OLMUL:
-		a = AMULL;
-		break;
-
-	case OASLMOD:
-	case OLMOD:
-	case OASLDIV:
-	case OLDIV:
-		a = ADIVL;
-		break;
-
-	case OEQ:
-	case ONE:
-	case OLT:
-	case OLE:
-	case OGE:
-	case OGT:
-	case OLO:
-	case OLS:
-	case OHS:
-	case OHI:
-		a = ACMPL;
-		if(et == TCHAR || et == TUCHAR)
-			a = ACMPB;
-		if(et == TSHORT || et == TUSHORT)
-			a = ACMPW;
-		gins(a, f, t);
-		switch(o) {
-		case OEQ:	a = AJEQ; break;
-		case ONE:	a = AJNE; break;
-		case OLT:	a = AJLT; break;
-		case OLE:	a = AJLE; break;
-		case OGE:	a = AJGE; break;
-		case OGT:	a = AJGT; break;
-		case OLO:	a = AJCS; break;
-		case OLS:	a = AJLS; break;
-		case OHS:	a = AJCC; break;
-		case OHI:	a = AJHI; break;
-		}
-		gins(a, Z, Z);
-		return;
-	}
-	if(a == AGOK)
-		diag(Z, "bad in gopcode %O", o);
-	gins(a, f, t);
-}
-
-int
-samaddr(Node *f, Node *t)
-{
-
-	if(f->op != t->op)
-		return 0;
-	switch(f->op) {
-
-	case OREGISTER:
-		if(f->reg != t->reg)
-			break;
-		return 1;
-	}
-	return 0;
-}
-
-void
-gbranch(int o)
-{
-	int a;
-
-	a = AGOK;
-	switch(o) {
-	case ORETURN:
-		a = ARET;
-		break;
-	case OGOTO:
-		a = AJMP;
-		break;
-	}
-	nextpc();
-	if(a == AGOK) {
-		diag(Z, "bad in gbranch %O",  o);
-		nextpc();
-	}
-	p->as = a;
-}
-
-void
-patch(Prog *op, int32 pc)
-{
-	op->to.offset = pc;
-	op->to.type = D_BRANCH;
-	op->to.u.branch = nil;
-	op->pcond = nil;
-}
-
-void
-gpseudo(int a, Sym *s, Node *n)
-{
-
-	nextpc();
-	p->as = a;
-	p->from.type = D_EXTERN;
-	p->from.sym = linksym(s);
-
-	switch(a) {
-	case ATEXT:
-		p->from.scale = textflag;
-		textflag = 0;
-		break;
-	case AGLOBL:
-		p->from.scale = s->dataflag;
-		break;
-	}
-
-	if(s->class == CSTATIC)
-		p->from.type = D_STATIC;
-	naddr(n, &p->to);
-	if(a == ADATA || a == AGLOBL)
-		pc--;
-}
-
-void
-gpcdata(int index, int value)
-{
-	Node n1;
-	
-	n1 = *nodconst(index);
-	gins(APCDATA, &n1, nodconst(value));
-}
-
-void
-gprefetch(Node *n)
-{
-	Node n1;
-	
-	if(strcmp(getgo386(), "sse2") != 0) // assume no prefetch on old machines
-		return;
-
-	regalloc(&n1, n, Z);
-	gmove(n, &n1);
-	n1.op = OINDREG;
-	gins(APREFETCHNTA, &n1, Z);
-	regfree(&n1);
-}
-
-int
-sconst(Node *n)
-{
-	int32 v;
-
-	if(n->op == OCONST && !typefd[n->type->etype]) {
-		v = n->vconst;
-		if(v >= -32766L && v < 32766L)
-			return 1;
-	}
-	return 0;
-}
-
-int32
-exreg(Type *t)
-{
-	int32 o;
-
-	if(typechlp[t->etype]){
-		if(exregoffset >= 32)
-			return 0;
-		o = exregoffset;
-		exregoffset += 4;
-		return o+1;	// +1 to avoid 0 == failure; naddr case OEXREG will -1.
-	}
-
-	return 0;
-}
-
-schar	ewidth[NTYPE] =
-{
-	-1,		/*[TXXX]*/
-	SZ_CHAR,	/*[TCHAR]*/
-	SZ_CHAR,	/*[TUCHAR]*/
-	SZ_SHORT,	/*[TSHORT]*/
-	SZ_SHORT,	/*[TUSHORT]*/
-	SZ_INT,		/*[TINT]*/
-	SZ_INT,		/*[TUINT]*/
-	SZ_LONG,	/*[TLONG]*/
-	SZ_LONG,	/*[TULONG]*/
-	SZ_VLONG,	/*[TVLONG]*/
-	SZ_VLONG,	/*[TUVLONG]*/
-	SZ_FLOAT,	/*[TFLOAT]*/
-	SZ_DOUBLE,	/*[TDOUBLE]*/
-	SZ_IND,		/*[TIND]*/
-	0,		/*[TFUNC]*/
-	-1,		/*[TARRAY]*/
-	0,		/*[TVOID]*/
-	-1,		/*[TSTRUCT]*/
-	-1,		/*[TUNION]*/
-	SZ_INT,		/*[TENUM]*/
-};
-int32	ncast[NTYPE] =
-{
-	0,				/*[TXXX]*/
-	BCHAR|BUCHAR,			/*[TCHAR]*/
-	BCHAR|BUCHAR,			/*[TUCHAR]*/
-	BSHORT|BUSHORT,			/*[TSHORT]*/
-	BSHORT|BUSHORT,			/*[TUSHORT]*/
-	BINT|BUINT|BLONG|BULONG|BIND,	/*[TINT]*/
-	BINT|BUINT|BLONG|BULONG|BIND,	/*[TUINT]*/
-	BINT|BUINT|BLONG|BULONG|BIND,	/*[TLONG]*/
-	BINT|BUINT|BLONG|BULONG|BIND,	/*[TULONG]*/
-	BVLONG|BUVLONG,			/*[TVLONG]*/
-	BVLONG|BUVLONG,			/*[TUVLONG]*/
-	BFLOAT,				/*[TFLOAT]*/
-	BDOUBLE,			/*[TDOUBLE]*/
-	BLONG|BULONG|BIND,		/*[TIND]*/
-	0,				/*[TFUNC]*/
-	0,				/*[TARRAY]*/
-	0,				/*[TVOID]*/
-	BSTRUCT,			/*[TSTRUCT]*/
-	BUNION,				/*[TUNION]*/
-	0,				/*[TENUM]*/
-};
diff --git a/src/cmd/8g/Makefile b/src/cmd/8g/Makefile
deleted file mode 100644
index 3f528d7..0000000
--- a/src/cmd/8g/Makefile
+++ /dev/null
@@ -1,5 +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.
-
-include ../../Make.dist
diff --git a/src/cmd/8g/cgen.c b/src/cmd/8g/cgen.c
deleted file mode 100644
index 2735fb6..0000000
--- a/src/cmd/8g/cgen.c
+++ /dev/null
@@ -1,1579 +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.
-
-// TODO(rsc):
-//	assume CLD?
-
-#include <u.h>
-#include <libc.h>
-#include "gg.h"
-
-void
-mgen(Node *n, Node *n1, Node *rg)
-{
-	Node n2;
-
-	n1->op = OEMPTY;
-
-	if(n->addable) {
-		*n1 = *n;
-		if(n1->op == OREGISTER || n1->op == OINDREG)
-			reg[n->val.u.reg]++;
-		return;
-	}
-	tempname(n1, n->type);
-	cgen(n, n1);
-	if(n->type->width <= widthptr || isfloat[n->type->etype]) {
-		n2 = *n1;
-		regalloc(n1, n->type, rg);
-		gmove(&n2, n1);
-	}
-}
-
-void
-mfree(Node *n)
-{
-	if(n->op == OREGISTER)
-		regfree(n);
-}
-
-/*
- * generate:
- *	res = n;
- * simplifies and calls gmove.
- *
- * TODO:
- *	sudoaddable
- */
-void
-cgen(Node *n, Node *res)
-{
-	Node *nl, *nr, *r, n1, n2, nt;
-	Prog *p1, *p2, *p3;
-	int a;
-
-	if(debug['g']) {
-		dump("\ncgen-n", n);
-		dump("cgen-res", res);
-	}
-
-	if(n == N || n->type == T)
-		fatal("cgen: n nil");
-	if(res == N || res->type == T)
-		fatal("cgen: res nil");
-
-	switch(n->op) {
-	case OSLICE:
-	case OSLICEARR:
-	case OSLICESTR:
-	case OSLICE3:
-	case OSLICE3ARR:
-		if (res->op != ONAME || !res->addable) {
-			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) {
-			tempname(&n1, n->type);
-			cgen_eface(n, &n1);
-			cgen(&n1, res);
-		} else
-			cgen_eface(n, res);
-		return;
-	}
-
-	while(n->op == OCONVNOP)
-		n = n->left;
-
-	// function calls on both sides?  introduce temporary
-	if(n->ullman >= UINF && res->ullman >= UINF) {
-		tempname(&n1, n->type);
-		cgen(n, &n1);
-		cgen(&n1, res);
-		return;
-	}
-
-	// structs etc get handled specially
-	if(isfat(n->type)) {
-		if(n->type->width < 0)
-			fatal("forgot to compute width for %T", n->type);
-		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 OSPTR:
-	case OLEN:
-		if(isslice(n->left->type) || istype(n->left->type, TSTRING))
-			n->addable = n->left->addable;
-		break;
-	case OCAP:
-		if(isslice(n->left->type))
-			n->addable = n->left->addable;
-		break;
-	case OITAB:
-		n->addable = n->left->addable;
-		break;
-	}
-
-	// if both are addressable, move
-	if(n->addable && res->addable) {
-		gmove(n, res);
-		return;
-	}
-
-	// if both are not addressable, use a temporary.
-	if(!n->addable && !res->addable) {
-		// could use regalloc here sometimes,
-		// but have to check for ullman >= UINF.
-		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) {
-		igen(res, &n1, N);
-		cgen(n, &n1);
-		regfree(&n1);
-		return;
-	}
-
-	// complex types
-	if(complexop(n, res)) {
-		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 != N && nl->ullman >= UINF)
-	if(nr != N && nr->ullman >= UINF) {
-		// both are hard
-		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(is64(n->type) || is64(res->type) || n->left != N && is64(n->left->type)) {
-		switch(n->op) {
-		// math goes to cgen64.
-		case OMINUS:
-		case OCOM:
-		case OADD:
-		case OSUB:
-		case OMUL:
-		case OLROT:
-		case OLSH:
-		case ORSH:
-		case OAND:
-		case OOR:
-		case OXOR:
-			cgen64(n, res);
-			return;
-		}
-	}
-
-	if(nl != N && isfloat[n->type->etype] && isfloat[nl->type->etype]) {
-		cgen_float(n, res);
-		return;
-	}
-
-	switch(n->op) {
-	default:
-		dump("cgen", n);
-		fatal("cgen %O", n->op);
-		break;
-
-	case OREAL:
-	case OIMAG:
-	case OCOMPLEX:
-		fatal("unexpected complex");
-		return;
-
-	// these call bgen to get a bool value
-	case OOROR:
-	case OANDAND:
-	case OEQ:
-	case ONE:
-	case OLT:
-	case OLE:
-	case OGE:
-	case OGT:
-	case ONOT:
-		p1 = gbranch(AJMP, T, 0);
-		p2 = pc;
-		gmove(nodbool(1), res);
-		p3 = gbranch(AJMP, T, 0);
-		patch(p1, pc);
-		bgen(n, 1, 0, p2);
-		gmove(nodbool(0), res);
-		patch(p3, pc);
-		return;
-
-	case OPLUS:
-		cgen(nl, res);
-		return;
-
-	case OMINUS:
-	case OCOM:
-		a = optoas(n->op, nl->type);
-		goto uop;
-
-	// symmetric binary
-	case OAND:
-	case OOR:
-	case OXOR:
-	case OADD:
-	case OMUL:
-		a = optoas(n->op, nl->type);
-		if(a == AIMULB) {
-			cgen_bmul(n->op, nl, nr, res);
-			break;
-		}
-		goto sbop;
-
-	// asymmetric binary
-	case OSUB:
-		a = optoas(n->op, nl->type);
-		goto abop;
-
-	case OHMUL:
-		cgen_hmul(nl, nr, res);
-		break;
-
-	case OCONV:
-		if(eqtype(n->type, nl->type) || noconv(n->type, nl->type)) {
-			cgen(nl, res);
-			break;
-		}
-
-		tempname(&n2, n->type);
-		mgen(nl, &n1, res);
-		gmove(&n1, &n2);
-		gmove(&n2, res);
-		mfree(&n1);
-		break;
-
-	case ODOT:
-	case ODOTPTR:
-	case OINDEX:
-	case OIND:
-	case ONAME:	// PHEAP or PPARAMREF var
-		igen(n, &n1, res);
-		gmove(&n1, res);
-		regfree(&n1);
-		break;
-
-	case OITAB:
-		igen(nl, &n1, res);
-		n1.type = ptrto(types[TUINTPTR]);
-		gmove(&n1, res);
-		regfree(&n1);
-		break;
-
-	case OSPTR:
-		// pointer is the first word of string or slice.
-		if(isconst(nl, CTSTR)) {
-			regalloc(&n1, types[tptr], res);
-			p1 = gins(ALEAL, N, &n1);
-			datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from);
-			gmove(&n1, res);
-			regfree(&n1);
-			break;
-		}
-		igen(nl, &n1, res);
-		n1.type = n->type;
-		gmove(&n1, res);
-		regfree(&n1);
-		break;
-
-	case OLEN:
-		if(istype(nl->type, TMAP) || istype(nl->type, TCHAN)) {
-			// map has len in the first 32-bit word.
-			// a zero pointer means zero length
-			tempname(&n1, types[tptr]);
-			cgen(nl, &n1);
-			regalloc(&n2, types[tptr], N);
-			gmove(&n1, &n2);
-			n1 = n2;
-
-			nodconst(&n2, types[tptr], 0);
-			gins(optoas(OCMP, types[tptr]), &n1, &n2);
-			p1 = gbranch(optoas(OEQ, types[tptr]), T, -1);
-
-			n2 = n1;
-			n2.op = OINDREG;
-			n2.type = types[TINT32];
-			gmove(&n2, &n1);
-
-			patch(p1, pc);
-
-			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.
-			igen(nl, &n1, res);
-			n1.type = types[TUINT32];
-			n1.xoffset += Array_nel;
-			gmove(&n1, res);
-			regfree(&n1);
-			break;
-		}
-		fatal("cgen: OLEN: unknown type %lT", nl->type);
-		break;
-
-	case OCAP:
-		if(istype(nl->type, TCHAN)) {
-			// chan has cap in the second 32-bit word.
-			// a zero pointer means zero length
-			tempname(&n1, types[tptr]);
-			cgen(nl, &n1);
-			regalloc(&n2, types[tptr], N);
-			gmove(&n1, &n2);
-			n1 = n2;
-
-			nodconst(&n2, types[tptr], 0);
-			gins(optoas(OCMP, types[tptr]), &n1, &n2);
-			p1 = gbranch(optoas(OEQ, types[tptr]), T, -1);
-
-			n2 = n1;
-			n2.op = OINDREG;
-			n2.xoffset = 4;
-			n2.type = types[TINT32];
-			gmove(&n2, &n1);
-
-			patch(p1, pc);
-
-			gmove(&n1, res);
-			regfree(&n1);
-			break;
-		}
-		if(isslice(nl->type)) {
-			igen(nl, &n1, res);
-			n1.type = types[TUINT32];
-			n1.xoffset += Array_cap;
-			gmove(&n1, res);
-			regfree(&n1);
-			break;
-		}
-		fatal("cgen: OCAP: unknown type %lT", nl->type);
-		break;
-
-	case OADDR:
-		agen(nl, res);
-		break;
-
-	case OCALLMETH:
-		cgen_callmeth(n, 0);
-		cgen_callret(n, res);
-		break;
-
-	case OCALLINTER:
-		cgen_callinter(n, res, 0);
-		cgen_callret(n, res);
-		break;
-
-	case OCALLFUNC:
-		cgen_call(n, 0);
-		cgen_callret(n, res);
-		break;
-
-	case OMOD:
-	case ODIV:
-		cgen_div(n->op, nl, nr, res);
-		break;
-
-	case OLSH:
-	case ORSH:
-	case OLROT:
-		cgen_shift(n->op, n->bounded, nl, nr, res);
-		break;
-	}
-	return;
-
-sbop:	// symmetric binary
-	if(nl->ullman < nr->ullman || nl->op == OLITERAL) {
-		r = nl;
-		nl = nr;
-		nr = r;
-	}
-
-abop:	// asymmetric binary
-	if(smallintconst(nr)) {
-		mgen(nl, &n1, res);
-		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) {
-		tempname(&nt, nl->type);
-		cgen(nl, &nt);
-		mgen(nr, &n2, N);
-		regalloc(&n1, nl->type, res);
-		gmove(&nt, &n1);
-		gins(a, &n2, &n1);
-		gmove(&n1, res);
-		regfree(&n1);
-		mfree(&n2);
-	} else {
-		regalloc(&n2, nr->type, res);
-		cgen(nr, &n2);
-		regalloc(&n1, nl->type, N);
-		cgen(nl, &n1);
-		gins(a, &n2, &n1);
-		regfree(&n2);
-		gmove(&n1, res);
-		regfree(&n1);
-	}
-	return;
-
-uop:	// unary
-	tempname(&n1, nl->type);
-	cgen(nl, &n1);
-	gins(a, N, &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.
- */
-static Prog*
-igenindex(Node *n, Node *res, int bounded)
-{
-	Node tmp, lo, hi, zero;
-
-	if(!is64(n->type)) {
-		if(n->addable) {
-			// nothing to do.
-			*res = *n;
-		} else {
-			tempname(res, types[TUINT32]);
-			cgen(n, res);
-		}
-		return nil;
-	}
-
-	tempname(&tmp, types[TINT64]);
-	cgen(n, &tmp);
-	split64(&tmp, &lo, &hi);
-	tempname(res, types[TUINT32]);
-	gmove(&lo, res);
-	if(bounded) {
-		splitclean();
-		return nil;
-	}
-	nodconst(&zero, types[TINT32], 0);
-	gins(ACMPL, &hi, &zero);
-	splitclean();
-	return gbranch(AJNE, T, +1);
-}
-		
-/*
- * address gen
- *	res = &n;
- * The generated code checks that the result is not nil.
- */
-void
-agen(Node *n, Node *res)
-{
-	Node *nl, *nr;
-	Node n1, n2, n3, tmp, nlen;
-	Type *t;
-	uint32 w;
-	uint64 v;
-	Prog *p1, *p2;
-	int bounded;
-
-	if(debug['g']) {
-		dump("\nagen-res", res);
-		dump("agen-r", n);
-	}
-	if(n == N || n->type == T || res == N || res->type == T)
-		fatal("agen");
-
-	while(n->op == OCONVNOP)
-		n = n->left;
-
-	if(isconst(n, CTNIL) && n->type->width > 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.
-		tempname(&n1, n->type);
-		gvardef(&n1);
-		clearfat(&n1);
-		regalloc(&n2, types[tptr], res);
-		gins(ALEAL, &n1, &n2);
-		gmove(&n2, res);
-		regfree(&n2);
-		return;
-	}
-		
-	// addressable var is easy
-	if(n->addable) {
-		if(n->op == OREGISTER)
-			fatal("agen OREGISTER");
-		regalloc(&n1, types[tptr], res);
-		gins(ALEAL, n, &n1);
-		gmove(&n1, res);
-		regfree(&n1);
-		return;
-	}
-
-	// let's compute
-	nl = n->left;
-	nr = n->right;
-
-	switch(n->op) {
-	default:
-		fatal("agen %O", n->op);
-
-	case OCALLMETH:
-		cgen_callmeth(n, 0);
-		cgen_aret(n, res);
-		break;
-
-	case OCALLINTER:
-		cgen_callinter(n, res, 0);
-		cgen_aret(n, res);
-		break;
-
-	case OCALLFUNC:
-		cgen_call(n, 0);
-		cgen_aret(n, res);
-		break;
-
-	case OSLICE:
-	case OSLICEARR:
-	case OSLICESTR:
-	case OSLICE3:
-	case OSLICE3ARR:
-		tempname(&n1, n->type);
-		cgen_slice(n, &n1);
-		agen(&n1, res);
-		break;
-
-	case OEFACE:
-		tempname(&n1, n->type);
-		cgen_eface(n, &n1);
-		agen(&n1, res);
-		break;
-
-	case OINDEX:
-		p2 = nil;  // to be patched to panicindex.
-		w = n->type->width;
-		bounded = debug['B'] || n->bounded;
-		if(nr->addable) {
-			// Generate &nl first, and move nr into register.
-			if(!isconst(nl, CTSTR))
-				igen(nl, &n3, res);
-			if(!isconst(nr, CTINT)) {
-				p2 = igenindex(nr, &tmp, bounded);
-				regalloc(&n1, tmp.type, N);
-				gmove(&tmp, &n1);
-			}
-		} else if(nl->addable) {
-			// Generate nr first, and move &nl into register.
-			if(!isconst(nr, CTINT)) {
-				p2 = igenindex(nr, &tmp, bounded);
-				regalloc(&n1, tmp.type, N);
-				gmove(&tmp, &n1);
-			}
-			if(!isconst(nl, CTSTR))
-				igen(nl, &n3, res);
-		} else {
-			p2 = igenindex(nr, &tmp, bounded);
-			nr = &tmp;
-			if(!isconst(nl, CTSTR))
-				igen(nl, &n3, res);
-			regalloc(&n1, tmp.type, N);
-			gins(optoas(OAS, tmp.type), &tmp, &n1);
-		}
-
-		// For fixed array we really want the pointer in n3.
-		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 = mpgetfix(nr->val.u.xval);
-			if(isslice(nl->type) || nl->type->etype == TSTRING) {
-				if(!debug['B'] && !n->bounded) {
-					nlen = n3;
-					nlen.type = types[TUINT32];
-					nlen.xoffset += Array_nel;
-					nodconst(&n2, types[TUINT32], v);
-					gins(optoas(OCMP, types[TUINT32]), &nlen, &n2);
-					p1 = gbranch(optoas(OGT, types[TUINT32]), T, +1);
-					ginscall(panicindex, -1);
-					patch(p1, pc);
-				}
-			}
-
-			// Load base pointer in n2 = n3.
-			regalloc(&n2, types[tptr], &n3);
-			n3.type = types[tptr];
-			n3.xoffset += Array_array;
-			gmove(&n3, &n2);
-			regfree(&n3);
-			if (v*w != 0) {
-				nodconst(&n1, types[tptr], v*w);
-				gins(optoas(OADD, types[tptr]), &n1, &n2);
-			}
-			gmove(&n2, res);
-			regfree(&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
-		gmove(&n1, &n2);
-		regfree(&n1);
-
-		if(!debug['B'] && !n->bounded) {
-			// check bounds
-			t = types[TUINT32];
-			if(isconst(nl, CTSTR)) {
-				nodconst(&nlen, t, nl->val.u.sval->len);
-			} else if(isslice(nl->type) || nl->type->etype == TSTRING) {
-				nlen = n3;
-				nlen.type = t;
-				nlen.xoffset += Array_nel;
-			} else {
-				nodconst(&nlen, t, nl->type->bound);
-			}
-			gins(optoas(OCMP, t), &n2, &nlen);
-			p1 = gbranch(optoas(OLT, t), T, +1);
-			if(p2)
-				patch(p2, pc);
-			ginscall(panicindex, -1);
-			patch(p1, pc);
-		}
-
-		if(isconst(nl, CTSTR)) {
-			regalloc(&n3, types[tptr], res);
-			p1 = gins(ALEAL, N, &n3);
-			datastring(nl->val.u.sval->s, nl->val.u.sval->len, &p1->from);
-			p1->from.scale = 1;
-			p1->from.index = n2.val.u.reg;
-			goto indexdone;
-		}
-
-		// Load base pointer in n3.
-		regalloc(&tmp, types[tptr], &n3);
-		if(isslice(nl->type) || nl->type->etype == TSTRING) {
-			n3.type = types[tptr];
-			n3.xoffset += Array_array;
-			gmove(&n3, &tmp);
-		}
-		regfree(&n3);
-		n3 = tmp;
-
-		if(w == 0) {
-			// nothing to do
-		} else if(w == 1 || w == 2 || w == 4 || w == 8) {
-			// LEAL (n3)(n2*w), n3
-			p1 = gins(ALEAL, &n2, &n3);
-			p1->from.scale = w;
-			p1->from.index = p1->from.type;
-			p1->from.type = p1->to.type + D_INDIR;
-		} else {
-			nodconst(&tmp, types[TUINT32], w);
-			gins(optoas(OMUL, types[TUINT32]), &tmp, &n2);
-			gins(optoas(OADD, types[tptr]), &n2, &n3);
-		}
-
-	indexdone:
-		gmove(&n3, res);
-		regfree(&n2);
-		regfree(&n3);
-		break;
-
-	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) && n->class != PPARAMREF) {
-			dump("bad agen", n);
-			fatal("agen: bad ONAME class %#x", n->class);
-		}
-		cgen(n->heapaddr, res);
-		if(n->xoffset != 0) {
-			nodconst(&n1, types[tptr], n->xoffset);
-			gins(optoas(OADD, types[tptr]), &n1, res);
-		}
-		break;
-
-	case OIND:
-		cgen(nl, res);
-		cgen_checknil(res);
-		break;
-
-	case ODOT:
-		agen(nl, res);
-		if(n->xoffset != 0) {
-			nodconst(&n1, types[tptr], n->xoffset);
-			gins(optoas(OADD, types[tptr]), &n1, res);
-		}
-		break;
-
-	case ODOTPTR:
-		t = nl->type;
-		if(!isptr[t->etype])
-			fatal("agen: not ptr %N", n);
-		cgen(nl, res);
-		cgen_checknil(res);
-		if(n->xoffset != 0) {
-			nodconst(&n1, types[tptr], n->xoffset);
-			gins(optoas(OADD, types[tptr]), &n1, res);
-		}
-		break;
-	}
-}
-
-/*
- * 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.
- */
-void
-igen(Node *n, Node *a, Node *res)
-{
-	Type *fp;
-	Iter flist;
-	Node n1;
-
-	if(debug['g']) {
-		dump("\nigen-n", n);
-	}
-	switch(n->op) {
-	case ONAME:
-		if((n->class&PHEAP) || 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 != D_SP)
-			reg[n->val.u.reg]++;
-		*a = *n;
-		return;
-
-	case ODOT:
-		igen(n->left, a, res);
-		a->xoffset += n->xoffset;
-		a->type = n->type;
-		return;
-
-	case ODOTPTR:
-		switch(n->left->op) {
-		case ODOT:
-		case ODOTPTR:
-		case OCALLFUNC:
-		case OCALLMETH:
-		case OCALLINTER:
-			// igen-able nodes.
-			igen(n->left, &n1, res);
-			regalloc(a, types[tptr], &n1);
-			gmove(&n1, a);
-			regfree(&n1);
-			break;
-		default:
-			regalloc(a, types[tptr], res);
-			cgen(n->left, a);
-		}
-		cgen_checknil(a);
-		a->op = OINDREG;
-		a->xoffset += n->xoffset;
-		a->type = n->type;
-		return;
-
-	case OCALLFUNC:
-	case OCALLMETH:
-	case OCALLINTER:
-		switch(n->op) {
-		case OCALLFUNC:
-			cgen_call(n, 0);
-			break;
-		case OCALLMETH:
-			cgen_callmeth(n, 0);
-			break;
-		case OCALLINTER:
-			cgen_callinter(n, N, 0);
-			break;
-		}
-		fp = structfirst(&flist, getoutarg(n->left->type));
-		memset(a, 0, sizeof *a);
-		a->op = OINDREG;
-		a->val.u.reg = D_SP;
-		a->addable = 1;
-		a->xoffset = fp->width;
-		a->type = n->type;
-		return;
-
-	case OINDEX:
-		// 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.
-		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 {
-				igen(n->left, &n1, res);
-				cgen_checknil(&n1);
-				regalloc(a, types[tptr], res);
-				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;
-			return;
-		}
-		break;
-	}
-
-	// release register for now, to avoid
-	// confusing tempname.
-	if(res != N && res->op == OREGISTER)
-		reg[res->val.u.reg]--;
-	tempname(&n1, types[tptr]);
-	agen(n, &n1);
-	if(res != N && res->op == OREGISTER)
-		reg[res->val.u.reg]++;
-	regalloc(a, types[tptr], res);
-	gmove(&n1, a);
-	a->op = OINDREG;
-	a->type = n->type;
-}
-
-/*
- * branch gen
- *	if(n == true) goto to;
- */
-void
-bgen(Node *n, int true, int likely, Prog *to)
-{
-	int et, a;
-	Node *nl, *nr, *r;
-	Node n1, n2, tmp;
-	Prog *p1, *p2;
-
-	if(debug['g']) {
-		dump("\nbgen", n);
-	}
-
-	if(n == N)
-		n = nodbool(1);
-
-	if(n->ninit != nil)
-		genlist(n->ninit);
-
-	if(n->type == T) {
-		convlit(&n, types[TBOOL]);
-		if(n->type == T)
-			return;
-	}
-
-	et = n->type->etype;
-	if(et != TBOOL) {
-		yyerror("cgen: bad type %T for %O", n->type, n->op);
-		patch(gins(AEND, N, N), to);
-		return;
-	}
-
-	while(n->op == OCONVNOP) {
-		n = n->left;
-		if(n->ninit != nil)
-			genlist(n->ninit);
-	}
-
-	nl = n->left;
-	nr = N;
-
-	if(nl != N && isfloat[nl->type->etype]) {
-		bgen_float(n, true, likely, to);
-		return;
-	}
-
-	switch(n->op) {
-	default:
-	def:
-		regalloc(&n1, n->type, N);
-		cgen(n, &n1);
-		nodconst(&n2, n->type, 0);
-		gins(optoas(OCMP, n->type), &n1, &n2);
-		a = AJNE;
-		if(!true)
-			a = AJEQ;
-		patch(gbranch(a, n->type, likely), to);
-		regfree(&n1);
-		return;
-
-	case OLITERAL:
-		// need to ask if it is bool?
-		if(!true == !n->val.u.bval)
-			patch(gbranch(AJMP, T, 0), to);
-		return;
-
-	case ONAME:
-		if(!n->addable)
-			goto def;
-		nodconst(&n1, n->type, 0);
-		gins(optoas(OCMP, n->type), n, &n1);
-		a = AJNE;
-		if(!true)
-			a = AJEQ;
-		patch(gbranch(a, n->type, likely), to);
-		return;
-
-	case OANDAND:
-		if(!true)
-			goto caseor;
-
-	caseand:
-		p1 = gbranch(AJMP, T, 0);
-		p2 = gbranch(AJMP, T, 0);
-		patch(p1, pc);
-		bgen(n->left, !true, -likely, p2);
-		bgen(n->right, !true, -likely, p2);
-		p1 = gbranch(AJMP, T, 0);
-		patch(p1, to);
-		patch(p2, pc);
-		return;
-
-	case OOROR:
-		if(!true)
-			goto caseand;
-
-	caseor:
-		bgen(n->left, true, likely, to);
-		bgen(n->right, true, likely, to);
-		return;
-
-	case OEQ:
-	case ONE:
-	case OLT:
-	case OGT:
-	case OLE:
-	case OGE:
-		nr = n->right;
-		if(nr == N || nr->type == T)
-			return;
-
-	case ONOT:	// unary
-		nl = n->left;
-		if(nl == N || nl->type == T)
-			return;
-	}
-
-	switch(n->op) {
-	case ONOT:
-		bgen(nl, !true, likely, to);
-		break;
-
-	case OEQ:
-	case ONE:
-	case OLT:
-	case OGT:
-	case OLE:
-	case OGE:
-		a = n->op;
-		if(!true) {
-			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 = optoas(a, types[tptr]);
-			igen(nl, &n1, N);
-			n1.xoffset += Array_array;
-			n1.type = types[tptr];
-			nodconst(&tmp, types[tptr], 0);
-			gins(optoas(OCMP, types[tptr]), &n1, &tmp);
-			patch(gbranch(a, types[tptr], likely), to);
-			regfree(&n1);
-			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 = optoas(a, types[tptr]);
-			igen(nl, &n1, N);
-			n1.type = types[tptr];
-			nodconst(&tmp, types[tptr], 0);
-			gins(optoas(OCMP, types[tptr]), &n1, &tmp);
-			patch(gbranch(a, types[tptr], likely), to);
-			regfree(&n1);
-			break;
-		}
-
-		if(iscomplex[nl->type->etype]) {
-			complexbool(a, nl, nr, true, likely, to);
-			break;
-		}
-
-		if(is64(nr->type)) {
-			if(!nl->addable || isconst(nl, CTINT)) {
-				tempname(&n1, nl->type);
-				cgen(nl, &n1);
-				nl = &n1;
-			}
-			if(!nr->addable) {
-				tempname(&n2, nr->type);
-				cgen(nr, &n2);
-				nr = &n2;
-			}
-			cmp64(nl, nr, a, likely, to);
-			break;
-		}
-
-		if(nr->ullman >= UINF) {
-			if(!nl->addable) {
-				tempname(&n1, nl->type);
-				cgen(nl, &n1);
-				nl = &n1;
-			}
-			if(!nr->addable) {
-				tempname(&tmp, nr->type);
-				cgen(nr, &tmp);
-				nr = &tmp;
-			}
-			regalloc(&n2, nr->type, N);
-			cgen(nr, &n2);
-			nr = &n2;
-			goto cmp;
-		}
-
-		if(!nl->addable) {
-			tempname(&n1, nl->type);
-			cgen(nl, &n1);
-			nl = &n1;
-		}
-
-		if(smallintconst(nr)) {
-			gins(optoas(OCMP, nr->type), nl, nr);
-			patch(gbranch(optoas(a, nr->type), nr->type, likely), to);
-			break;
-		}
-
-		if(!nr->addable) {
-			tempname(&tmp, nr->type);
-			cgen(nr, &tmp);
-			nr = &tmp;
-		}
-		regalloc(&n2, nr->type, N);
-		gmove(nr, &n2);
-		nr = &n2;
-
-cmp:
-		gins(optoas(OCMP, nr->type), nl, nr);
-		patch(gbranch(optoas(a, nr->type), nr->type, likely), to);
-
-		if(nl->op == OREGISTER)
-			regfree(nl);
-		regfree(nr);
-		break;
-	}
-}
-
-/*
- * n is on stack, either local variable
- * or return value from function call.
- * return n's offset from SP.
- */
-int32
-stkof(Node *n)
-{
-	Type *t;
-	Iter flist;
-	int32 off;
-
-	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:
-	case OCALLINTER:
-	case OCALLFUNC:
-		t = n->left->type;
-		if(isptr[t->etype])
-			t = t->type;
-
-		t = structfirst(&flist, getoutarg(t));
-		if(t != T)
-			return t->width;
-		break;
-	}
-
-	// botch - probably failing to recognize address
-	// arithmetic on the above. eg INDEX and DOT
-	return -1000;
-}
-
-/*
- * struct gen
- *	memmove(&res, &n, w);
- */
-void
-sgen(Node *n, Node *res, int64 w)
-{
-	Node dst, src, tdst, tsrc;
-	int32 c, q, odst, osrc;
-	NodeList *l;
-	Prog *p;
-
-	if(debug['g']) {
-		print("\nsgen w=%lld\n", w);
-		dump("r", n);
-		dump("res", res);
-	}
-	if(n->ullman >= UINF && res->ullman >= UINF)
-		fatal("sgen UINF");
-
-	if(w < 0 || (int32)w != w)
-		fatal("sgen copy %lld", w);
-
-	if(w == 0) {
-		// evaluate side effects only.
-		tempname(&tdst, types[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 == ONAME && strcmp(res->sym->name, ".args") == 0)
-		for(l = curfn->dcl; l != nil; l = l->next)
-			if(l->n->class == PPARAMOUT)
-				gvardef(l->n);
-
-	// Avoid taking the address for simple enough types.
-	if(componentgen(n, 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.
-		tempname(&tsrc, n->type);
-		sgen(n, &tsrc, w);
-		sgen(&tsrc, res, w);
-		return;
-	}
-
-	nodreg(&dst, types[tptr], D_DI);
-	nodreg(&src, types[tptr], D_SI);
-
-	tempname(&tsrc, types[tptr]);
-	tempname(&tdst, types[tptr]);
-	if(!n->addable)
-		agen(n, &tsrc);
-	if(!res->addable)
-		agen(res, &tdst);
-	if(n->addable)
-		agen(n, &src);
-	else
-		gmove(&tsrc, &src);
-
-	if(res->op == ONAME)
-		gvardef(res);
-
-	if(res->addable)
-		agen(res, &dst);
-	else
-		gmove(&tdst, &dst);
-
-	c = w % 4;	// bytes
-	q = w / 4;	// doublewords
-
-	// if we are copying forward on the stack and
-	// the src and dst overlap, then reverse direction
-	if(osrc < odst && odst < osrc+w) {
-		// reverse direction
-		gins(ASTD, N, N);		// set direction flag
-		if(c > 0) {
-			gconreg(AADDL, w-1, D_SI);
-			gconreg(AADDL, w-1, D_DI);
-
-			gconreg(AMOVL, c, D_CX);
-			gins(AREP, N, N);	// repeat
-			gins(AMOVSB, N, N);	// MOVB *(SI)-,*(DI)-
-		}
-
-		if(q > 0) {
-			if(c > 0) {
-				gconreg(AADDL, -3, D_SI);
-				gconreg(AADDL, -3, D_DI);
-			} else {
-				gconreg(AADDL, w-4, D_SI);
-				gconreg(AADDL, w-4, D_DI);
-			}
-			gconreg(AMOVL, q, D_CX);
-			gins(AREP, N, N);	// repeat
-			gins(AMOVSL, N, N);	// MOVL *(SI)-,*(DI)-
-		}
-		// we leave with the flag clear
-		gins(ACLD, N, N);
-	} else {
-		gins(ACLD, N, N);	// paranoia.  TODO(rsc): remove?
-		// normal direction
-		if(q > 128 || (q >= 4 && nacl)) {
-			gconreg(AMOVL, q, D_CX);
-			gins(AREP, N, N);	// repeat
-			gins(AMOVSL, N, N);	// MOVL *(SI)+,*(DI)+
-		} else if(q >= 4) {
-			p = gins(ADUFFCOPY, N, N);
-			p->to.type = D_ADDR;
-			p->to.sym = linksym(pkglookup("duffcopy", runtimepkg));
-			// 10 and 128 = magic constants: see ../../runtime/asm_386.s
-			p->to.offset = 10*(128-q);
-		} else
-		while(q > 0) {
-			gins(AMOVSL, N, N);	// MOVL *(SI)+,*(DI)+
-			q--;
-		}
-		while(c > 0) {
-			gins(AMOVSB, N, N);	// MOVB *(SI)+,*(DI)+
-			c--;
-		}
-	}
-}
-
-static int
-cadable(Node *n)
-{
-	if(!n->addable) {
-		// dont know how it happens,
-		// but it does
-		return 0;
-	}
-
-	switch(n->op) {
-	case ONAME:
-		return 1;
-	}
-	return 0;
-}
-
-/*
- * copy a composite value by moving its individual components.
- * Slices, strings and interfaces are supported.
- * nr is N when assigning a zero value.
- * return 1 if can do, 0 if can't.
- */
-int
-componentgen(Node *nr, Node *nl)
-{
-	Node nodl, nodr;
-	Type *t;
-	int freel, freer;
-	vlong fldcount;
-	vlong loffset, roffset;
-
-	freel = 0;
-	freer = 0;
-
-	switch(nl->type->etype) {
-	default:
-		goto no;
-
-	case TARRAY:
-		t = nl->type;
-
-		// Slices are ok.
-		if(isslice(t))
-			break;
-		// Small arrays are ok.
-		if(t->bound > 0 && t->bound <= 3 && !isfat(t->type))
-			break;
-
-		goto no;
-
-	case TSTRUCT:
-		// Small structs with non-fat types are ok.
-		// Zero-sized structs are treated separately elsewhere.
-		fldcount = 0;
-		for(t=nl->type->type; t; t=t->down) {
-			if(isfat(t->type))
-				goto no;
-			if(t->etype != TFIELD)
-				fatal("componentgen: not a TFIELD: %lT", t);
-			fldcount++;
-		}
-		if(fldcount == 0 || fldcount > 4)
-			goto no;
-
-		break;
-
-	case TSTRING:
-	case TINTER:
-		break;
-	}
-
-	nodl = *nl;
-	if(!cadable(nl)) {
-		if(nr == N || !cadable(nr))
-			goto no;
-		igen(nl, &nodl, N);
-		freel = 1;
-	}
-
-	if(nr != N) {
-		nodr = *nr;
-		if(!cadable(nr)) {
-			igen(nr, &nodr, N);
-			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 != N && nl->op == ONAME && nr->op == ONAME && nl == nr)
-		goto yes;
-
-	switch(nl->type->etype) {
-	case TARRAY:
-		// componentgen for arrays.
-		if(nl->op == ONAME)
-			gvardef(nl);
-		t = nl->type;
-		if(!isslice(t)) {
-			nodl.type = t->type;
-			nodr.type = nodl.type;
-			for(fldcount=0; fldcount < t->bound; fldcount++) {
-				if(nr == N)
-					clearslim(&nodl);
-				else
-					gmove(&nodr, &nodl);
-				nodl.xoffset += t->type->width;
-				nodr.xoffset += t->type->width;
-			}
-			goto yes;
-		}
-
-		// componentgen for slices.
-		nodl.xoffset += Array_array;
-		nodl.type = ptrto(nl->type->type);
-
-		if(nr != N) {
-			nodr.xoffset += Array_array;
-			nodr.type = nodl.type;
-		} else
-			nodconst(&nodr, nodl.type, 0);
-		gmove(&nodr, &nodl);
-
-		nodl.xoffset += Array_nel-Array_array;
-		nodl.type = types[simtype[TUINT]];
-
-		if(nr != N) {
-			nodr.xoffset += Array_nel-Array_array;
-			nodr.type = nodl.type;
-		} else
-			nodconst(&nodr, nodl.type, 0);
-		gmove(&nodr, &nodl);
-
-		nodl.xoffset += Array_cap-Array_nel;
-		nodl.type = types[simtype[TUINT]];
-
-		if(nr != N) {
-			nodr.xoffset += Array_cap-Array_nel;
-			nodr.type = nodl.type;
-		} else
-			nodconst(&nodr, nodl.type, 0);
-		gmove(&nodr, &nodl);
-
-		goto yes;
-
-	case TSTRING:
-		if(nl->op == ONAME)
-			gvardef(nl);
-		nodl.xoffset += Array_array;
-		nodl.type = ptrto(types[TUINT8]);
-
-		if(nr != N) {
-			nodr.xoffset += Array_array;
-			nodr.type = nodl.type;
-		} else
-			nodconst(&nodr, nodl.type, 0);
-		gmove(&nodr, &nodl);
-
-		nodl.xoffset += Array_nel-Array_array;
-		nodl.type = types[simtype[TUINT]];
-
-		if(nr != N) {
-			nodr.xoffset += Array_nel-Array_array;
-			nodr.type = nodl.type;
-		} else
-			nodconst(&nodr, nodl.type, 0);
-		gmove(&nodr, &nodl);
-
-		goto yes;
-
-	case TINTER:
-		if(nl->op == ONAME)
-			gvardef(nl);
-		nodl.xoffset += Array_array;
-		nodl.type = ptrto(types[TUINT8]);
-
-		if(nr != N) {
-			nodr.xoffset += Array_array;
-			nodr.type = nodl.type;
-		} else
-			nodconst(&nodr, nodl.type, 0);
-		gmove(&nodr, &nodl);
-
-		nodl.xoffset += Array_nel-Array_array;
-		nodl.type = ptrto(types[TUINT8]);
-
-		if(nr != N) {
-			nodr.xoffset += Array_nel-Array_array;
-			nodr.type = nodl.type;
-		} else
-			nodconst(&nodr, nodl.type, 0);
-		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 && nl->type->type)
-			loffset -= nl->type->type->width;
-		if(nr != N && nr->type->etype == TSTRUCT && nr->type->funarg && nr->type->type)
-			roffset -= nr->type->type->width;
-
-		for(t=nl->type->type; t; t=t->down) {
-			nodl.xoffset = loffset + t->width;
-			nodl.type = t->type;
-
-			if(nr == N)
-				clearslim(&nodl);
-			else {
-				nodr.xoffset = roffset + t->width;
-				nodr.type = nodl.type;
-				gmove(&nodr, &nodl);
-			}
-		}
-		goto yes;
-	}
-
-no:
-	if(freer)
-		regfree(&nodr);
-	if(freel)
-		regfree(&nodl);
-	return 0;
-
-yes:
-	if(freer)
-		regfree(&nodr);
-	if(freel)
-		regfree(&nodl);
-	return 1;
-}
diff --git a/src/cmd/8g/cgen64.c b/src/cmd/8g/cgen64.c
deleted file mode 100644
index dc50a40..0000000
--- a/src/cmd/8g/cgen64.c
+++ /dev/null
@@ -1,549 +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 <u.h>
-#include <libc.h>
-#include "gg.h"
-
-/*
- * attempt to generate 64-bit
- *	res = n
- * return 1 on success, 0 if op not handled.
- */
-void
-cgen64(Node *n, Node *res)
-{
-	Node t1, t2, ax, dx, cx, ex, fx, *l, *r;
-	Node lo1, lo2, hi1, hi2;
-	Prog *p1, *p2;
-	uint64 v;
-	uint32 lv, hv;
-
-	if(res->op != OINDREG && res->op != ONAME) {
-		dump("n", n);
-		dump("res", res);
-		fatal("cgen64 %O of %O", n->op, res->op);
-	}
-	switch(n->op) {
-	default:
-		fatal("cgen64 %O", n->op);
-
-	case OMINUS:
-		cgen(n->left, res);
-		split64(res, &lo1, &hi1);
-		gins(ANEGL, N, &lo1);
-		gins(AADCL, ncon(0), &hi1);
-		gins(ANEGL, N, &hi1);
-		splitclean();
-		return;
-
-	case OCOM:
-		cgen(n->left, res);
-		split64(res, &lo1, &hi1);
-		gins(ANOTL, N, &lo1);
-		gins(ANOTL, N, &hi1);
-		splitclean();
-		return;
-
-	case OADD:
-	case OSUB:
-	case OMUL:
-	case OLROT:
-	case OLSH:
-	case ORSH:
-	case OAND:
-	case OOR:
-	case OXOR:
-		// binary operators.
-		// common setup below.
-		break;
-	}
-
-	l = n->left;
-	r = n->right;
-	if(!l->addable) {
-		tempname(&t1, l->type);
-		cgen(l, &t1);
-		l = &t1;
-	}
-	if(r != N && !r->addable) {
-		tempname(&t2, r->type);
-		cgen(r, &t2);
-		r = &t2;
-	}
-
-	nodreg(&ax, types[TINT32], D_AX);
-	nodreg(&cx, types[TINT32], D_CX);
-	nodreg(&dx, types[TINT32], D_DX);
-
-	// Setup for binary operation.
-	split64(l, &lo1, &hi1);
-	if(is64(r->type))
-		split64(r, &lo2, &hi2);
-
-	// Do op.  Leave result in DX:AX.
-	switch(n->op) {
-	case OADD:
-		// TODO: Constants
-		gins(AMOVL, &lo1, &ax);
-		gins(AMOVL, &hi1, &dx);
-		gins(AADDL, &lo2, &ax);
-		gins(AADCL, &hi2, &dx);
-		break;
-
-	case OSUB:
-		// TODO: Constants.
-		gins(AMOVL, &lo1, &ax);
-		gins(AMOVL, &hi1, &dx);
-		gins(ASUBL, &lo2, &ax);
-		gins(ASBBL, &hi2, &dx);
-		break;
-
-	case OMUL:
-		// let's call the next two EX and FX.
-		regalloc(&ex, types[TPTR32], N);
-		regalloc(&fx, types[TPTR32], N);
-
-		// load args into DX:AX and EX:CX.
-		gins(AMOVL, &lo1, &ax);
-		gins(AMOVL, &hi1, &dx);
-		gins(AMOVL, &lo2, &cx);
-		gins(AMOVL, &hi2, &ex);
-
-		// if DX and EX are zero, use 32 x 32 -> 64 unsigned multiply.
-		gins(AMOVL, &dx, &fx);
-		gins(AORL, &ex, &fx);
-		p1 = gbranch(AJNE, T, 0);
-		gins(AMULL, &cx, N);	// implicit &ax
-		p2 = gbranch(AJMP, T, 0);
-		patch(p1, pc);
-
-		// full 64x64 -> 64, from 32x32 -> 64.
-		gins(AIMULL, &cx, &dx);
-		gins(AMOVL, &ax, &fx);
-		gins(AIMULL, &ex, &fx);
-		gins(AADDL, &dx, &fx);
-		gins(AMOVL, &cx, &dx);
-		gins(AMULL, &dx, N);	// implicit &ax
-		gins(AADDL, &fx, &dx);
-		patch(p2, pc);
-
-		regfree(&ex);
-		regfree(&fx);
-		break;
-	
-	case OLROT:
-		// We only rotate by a constant c in [0,64).
-		// if c >= 32:
-		//	lo, hi = hi, lo
-		//	c -= 32
-		// if c == 0:
-		//	no-op
-		// else:
-		//	t = hi
-		//	shld hi:lo, c
-		//	shld lo:t, c
-		v = mpgetfix(r->val.u.xval);
-		if(v >= 32) {
-			// reverse during load to do the first 32 bits of rotate
-			v -= 32;
-			gins(AMOVL, &lo1, &dx);
-			gins(AMOVL, &hi1, &ax);
-		} else {
-			gins(AMOVL, &lo1, &ax);
-			gins(AMOVL, &hi1, &dx);
-		}
-		if(v == 0) {
-			// done
-		} else {
-			gins(AMOVL, &dx, &cx);
-			p1 = gins(ASHLL, ncon(v), &dx);
-			p1->from.index = D_AX;	// double-width shift
-			p1->from.scale = 0;
-			p1 = gins(ASHLL, ncon(v), &ax);
-			p1->from.index = D_CX;	// double-width shift
-			p1->from.scale = 0;
-		}
-		break;
-
-	case OLSH:
-		if(r->op == OLITERAL) {
-			v = mpgetfix(r->val.u.xval);
-			if(v >= 64) {
-				if(is64(r->type))
-					splitclean();
-				splitclean();
-				split64(res, &lo2, &hi2);
-				gins(AMOVL, ncon(0), &lo2);
-				gins(AMOVL, ncon(0), &hi2);
-				splitclean();
-				goto out;
-			}
-			if(v >= 32) {
-				if(is64(r->type))
-					splitclean();
-				split64(res, &lo2, &hi2);
-				gmove(&lo1, &hi2);
-				if(v > 32) {
-					gins(ASHLL, ncon(v - 32), &hi2);
-				}
-				gins(AMOVL, ncon(0), &lo2);
-				splitclean();
-				splitclean();
-				goto out;
-			}
-
-			// general shift
-			gins(AMOVL, &lo1, &ax);
-			gins(AMOVL, &hi1, &dx);
-			p1 = gins(ASHLL, ncon(v), &dx);
-			p1->from.index = D_AX;	// double-width shift
-			p1->from.scale = 0;
-			gins(ASHLL, ncon(v), &ax);
-			break;
-		}
-
-		// load value into DX:AX.
-		gins(AMOVL, &lo1, &ax);
-		gins(AMOVL, &hi1, &dx);
-
-		// load shift value into register.
-		// if high bits are set, zero value.
-		p1 = P;
-		if(is64(r->type)) {
-			gins(ACMPL, &hi2, ncon(0));
-			p1 = gbranch(AJNE, T, +1);
-			gins(AMOVL, &lo2, &cx);
-		} else {
-			cx.type = types[TUINT32];
-			gmove(r, &cx);
-		}
-
-		// if shift count is >=64, zero value
-		gins(ACMPL, &cx, ncon(64));
-		p2 = gbranch(optoas(OLT, types[TUINT32]), T, +1);
-		if(p1 != P)
-			patch(p1, pc);
-		gins(AXORL, &dx, &dx);
-		gins(AXORL, &ax, &ax);
-		patch(p2, pc);
-
-		// if shift count is >= 32, zero low.
-		gins(ACMPL, &cx, ncon(32));
-		p1 = gbranch(optoas(OLT, types[TUINT32]), T, +1);
-		gins(AMOVL, &ax, &dx);
-		gins(ASHLL, &cx, &dx);	// SHLL only uses bottom 5 bits of count
-		gins(AXORL, &ax, &ax);
-		p2 = gbranch(AJMP, T, 0);
-		patch(p1, pc);
-
-		// general shift
-		p1 = gins(ASHLL, &cx, &dx);
-		p1->from.index = D_AX;	// double-width shift
-		p1->from.scale = 0;
-		gins(ASHLL, &cx, &ax);
-		patch(p2, pc);
-		break;
-
-	case ORSH:
-		if(r->op == OLITERAL) {
-			v = mpgetfix(r->val.u.xval);
-			if(v >= 64) {
-				if(is64(r->type))
-					splitclean();
-				splitclean();
-				split64(res, &lo2, &hi2);
-				if(hi1.type->etype == TINT32) {
-					gmove(&hi1, &lo2);
-					gins(ASARL, ncon(31), &lo2);
-					gmove(&hi1, &hi2);
-					gins(ASARL, ncon(31), &hi2);
-				} else {
-					gins(AMOVL, ncon(0), &lo2);
-					gins(AMOVL, ncon(0), &hi2);
-				}
-				splitclean();
-				goto out;
-			}
-			if(v >= 32) {
-				if(is64(r->type))
-					splitclean();
-				split64(res, &lo2, &hi2);
-				gmove(&hi1, &lo2);
-				if(v > 32)
-					gins(optoas(ORSH, hi1.type), ncon(v-32), &lo2);
-				if(hi1.type->etype == TINT32) {
-					gmove(&hi1, &hi2);
-					gins(ASARL, ncon(31), &hi2);
-				} else
-					gins(AMOVL, ncon(0), &hi2);
-				splitclean();
-				splitclean();
-				goto out;
-			}
-
-			// general shift
-			gins(AMOVL, &lo1, &ax);
-			gins(AMOVL, &hi1, &dx);
-			p1 = gins(ASHRL, ncon(v), &ax);
-			p1->from.index = D_DX;	// double-width shift
-			p1->from.scale = 0;
-			gins(optoas(ORSH, hi1.type), ncon(v), &dx);
-			break;
-		}
-
-		// load value into DX:AX.
-		gins(AMOVL, &lo1, &ax);
-		gins(AMOVL, &hi1, &dx);
-
-		// load shift value into register.
-		// if high bits are set, zero value.
-		p1 = P;
-		if(is64(r->type)) {
-			gins(ACMPL, &hi2, ncon(0));
-			p1 = gbranch(AJNE, T, +1);
-			gins(AMOVL, &lo2, &cx);
-		} else {
-			cx.type = types[TUINT32];
-			gmove(r, &cx);
-		}
-
-		// if shift count is >=64, zero or sign-extend value
-		gins(ACMPL, &cx, ncon(64));
-		p2 = gbranch(optoas(OLT, types[TUINT32]), T, +1);
-		if(p1 != P)
-			patch(p1, pc);
-		if(hi1.type->etype == TINT32) {
-			gins(ASARL, ncon(31), &dx);
-			gins(AMOVL, &dx, &ax);
-		} else {
-			gins(AXORL, &dx, &dx);
-			gins(AXORL, &ax, &ax);
-		}
-		patch(p2, pc);
-
-		// if shift count is >= 32, sign-extend hi.
-		gins(ACMPL, &cx, ncon(32));
-		p1 = gbranch(optoas(OLT, types[TUINT32]), T, +1);
-		gins(AMOVL, &dx, &ax);
-		if(hi1.type->etype == TINT32) {
-			gins(ASARL, &cx, &ax);	// SARL only uses bottom 5 bits of count
-			gins(ASARL, ncon(31), &dx);
-		} else {
-			gins(ASHRL, &cx, &ax);
-			gins(AXORL, &dx, &dx);
-		}
-		p2 = gbranch(AJMP, T, 0);
-		patch(p1, pc);
-
-		// general shift
-		p1 = gins(ASHRL, &cx, &ax);
-		p1->from.index = D_DX;	// double-width shift
-		p1->from.scale = 0;
-		gins(optoas(ORSH, hi1.type), &cx, &dx);
-		patch(p2, pc);
-		break;
-
-	case OXOR:
-	case OAND:
-	case OOR:
-		// make constant the right side (it usually is anyway).
-		if(lo1.op == OLITERAL) {
-			nswap(&lo1, &lo2);
-			nswap(&hi1, &hi2);
-		}
-		if(lo2.op == OLITERAL) {
-			// special cases for constants.
-			lv = mpgetfix(lo2.val.u.xval);
-			hv = mpgetfix(hi2.val.u.xval);
-			splitclean();	// right side
-			split64(res, &lo2, &hi2);
-			switch(n->op) {
-			case OXOR:
-				gmove(&lo1, &lo2);
-				gmove(&hi1, &hi2);
-				switch(lv) {
-				case 0:
-					break;
-				case 0xffffffffu:
-					gins(ANOTL, N, &lo2);
-					break;
-				default:
-					gins(AXORL, ncon(lv), &lo2);
-					break;
-				}
-				switch(hv) {
-				case 0:
-					break;
-				case 0xffffffffu:
-					gins(ANOTL, N, &hi2);
-					break;
-				default:
-					gins(AXORL, ncon(hv), &hi2);
-					break;
-				}
-				break;
-
-			case OAND:
-				switch(lv) {
-				case 0:
-					gins(AMOVL, ncon(0), &lo2);
-					break;
-				default:
-					gmove(&lo1, &lo2);
-					if(lv != 0xffffffffu)
-						gins(AANDL, ncon(lv), &lo2);
-					break;
-				}
-				switch(hv) {
-				case 0:
-					gins(AMOVL, ncon(0), &hi2);
-					break;
-				default:
-					gmove(&hi1, &hi2);
-					if(hv != 0xffffffffu)
-						gins(AANDL, ncon(hv), &hi2);
-					break;
-				}
-				break;
-
-			case OOR:
-				switch(lv) {
-				case 0:
-					gmove(&lo1, &lo2);
-					break;
-				case 0xffffffffu:
-					gins(AMOVL, ncon(0xffffffffu), &lo2);
-					break;
-				default:
-					gmove(&lo1, &lo2);
-					gins(AORL, ncon(lv), &lo2);
-					break;
-				}
-				switch(hv) {
-				case 0:
-					gmove(&hi1, &hi2);
-					break;
-				case 0xffffffffu:
-					gins(AMOVL, ncon(0xffffffffu), &hi2);
-					break;
-				default:
-					gmove(&hi1, &hi2);
-					gins(AORL, ncon(hv), &hi2);
-					break;
-				}
-				break;
-			}
-			splitclean();
-			splitclean();
-			goto out;
-		}
-		gins(AMOVL, &lo1, &ax);
-		gins(AMOVL, &hi1, &dx);
-		gins(optoas(n->op, lo1.type), &lo2, &ax);
-		gins(optoas(n->op, lo1.type), &hi2, &dx);
-		break;
-	}
-	if(is64(r->type))
-		splitclean();
-	splitclean();
-
-	split64(res, &lo1, &hi1);
-	gins(AMOVL, &ax, &lo1);
-	gins(AMOVL, &dx, &hi1);
-	splitclean();
-
-out:;
-}
-
-/*
- * generate comparison of nl, nr, both 64-bit.
- * nl is memory; nr is constant or memory.
- */
-void
-cmp64(Node *nl, Node *nr, int op, int likely, Prog *to)
-{
-	Node lo1, hi1, lo2, hi2, rr;
-	Prog *br;
-	Type *t;
-
-	split64(nl, &lo1, &hi1);
-	split64(nr, &lo2, &hi2);
-
-	// compare most significant word;
-	// if they differ, we're done.
-	t = hi1.type;
-	if(nl->op == OLITERAL || nr->op == OLITERAL)
-		gins(ACMPL, &hi1, &hi2);
-	else {
-		regalloc(&rr, types[TINT32], N);
-		gins(AMOVL, &hi1, &rr);
-		gins(ACMPL, &rr, &hi2);
-		regfree(&rr);
-	}
-	br = P;
-	switch(op) {
-	default:
-		fatal("cmp64 %O %T", op, t);
-	case OEQ:
-		// cmp hi
-		// jne L
-		// cmp lo
-		// jeq to
-		// L:
-		br = gbranch(AJNE, T, -likely);
-		break;
-	case ONE:
-		// cmp hi
-		// jne to
-		// cmp lo
-		// jne to
-		patch(gbranch(AJNE, T, likely), to);
-		break;
-	case OGE:
-	case OGT:
-		// cmp hi
-		// jgt to
-		// jlt L
-		// cmp lo
-		// jge to (or jgt to)
-		// L:
-		patch(gbranch(optoas(OGT, t), T, likely), to);
-		br = gbranch(optoas(OLT, t), T, -likely);
-		break;
-	case OLE:
-	case OLT:
-		// cmp hi
-		// jlt to
-		// jgt L
-		// cmp lo
-		// jle to (or jlt to)
-		// L:
-		patch(gbranch(optoas(OLT, t), T, likely), to);
-		br = gbranch(optoas(OGT, t), T, -likely);
-		break;
-	}
-
-	// compare least significant word
-	t = lo1.type;
-	if(nl->op == OLITERAL || nr->op == OLITERAL)
-		gins(ACMPL, &lo1, &lo2);
-	else {
-		regalloc(&rr, types[TINT32], N);
-		gins(AMOVL, &lo1, &rr);
-		gins(ACMPL, &rr, &lo2);
-		regfree(&rr);
-	}
-
-	// jump again
-	patch(gbranch(optoas(op, t), T, likely), to);
-
-	// point first branch down here if appropriate
-	if(br != P)
-		patch(br, pc);
-
-	splitclean();
-	splitclean();
-}
-
diff --git a/src/cmd/8g/doc.go b/src/cmd/8g/doc.go
deleted file mode 100644
index 9e46dca..0000000
--- a/src/cmd/8g/doc.go
+++ /dev/null
@@ -1,15 +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.
-
-// +build ignore
-
-/*
-
-8g is the version of the gc compiler for the x86.
-The $GOARCH for these tools is 386.
-
-It reads .go files and outputs .8 files. The flags are documented in ../gc/doc.go.
-
-*/
-package main
diff --git a/src/cmd/8g/galign.c b/src/cmd/8g/galign.c
deleted file mode 100644
index a0eb349..0000000
--- a/src/cmd/8g/galign.c
+++ /dev/null
@@ -1,47 +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 <u.h>
-#include <libc.h>
-#include "gg.h"
-
-int	thechar	= '8';
-char*	thestring	= "386";
-LinkArch*	thelinkarch = &link386;
-
-void
-linkarchinit(void)
-{
-}
-
-vlong MAXWIDTH = (1LL<<32) - 1;
-
-/*
- * go declares several platform-specific type aliases:
- * int, uint, float, and uintptr
- */
-Typedef	typedefs[] =
-{
-	{"int",		TINT,		TINT32},
-	{"uint",		TUINT,		TUINT32},
-	{"uintptr",	TUINTPTR,	TUINT32},
-	{0}
-};
-
-void
-betypeinit(void)
-{
-	widthptr = 4;
-	widthint = 4;
-	widthreg = 4;
-
-	zprog.link = P;
-	zprog.as = AGOK;
-	zprog.from.type = D_NONE;
-	zprog.from.index = D_NONE;
-	zprog.from.scale = 0;
-	zprog.to = zprog.from;
-
-	listinit8();
-}
diff --git a/src/cmd/8g/gg.h b/src/cmd/8g/gg.h
deleted file mode 100644
index 238f927..0000000
--- a/src/cmd/8g/gg.h
+++ /dev/null
@@ -1,135 +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.
-
-#ifndef	EXTERN
-#define	EXTERN	extern
-#endif
-
-#include "../gc/go.h"
-#include "../8l/8.out.h"
-
-#define TEXTFLAG from.scale
-
-// foptoas flags
-enum
-{
-	Frev = 1<<0,
-	Fpop = 1<<1,
-	Fpop2 = 1<<2,
-};
-
-EXTERN	int32	dynloc;
-EXTERN	uchar	reg[D_NONE];
-EXTERN	int32	pcloc;		// instruction counter
-EXTERN	Strlit	emptystring;
-EXTERN	Prog	zprog;
-EXTERN	Node*	newproc;
-EXTERN	Node*	deferproc;
-EXTERN	Node*	deferreturn;
-EXTERN	Node*	panicindex;
-EXTERN	Node*	panicslice;
-EXTERN	Node*	panicdiv;
-EXTERN	Node*	throwreturn;
-extern	uint32	unmappedzero;
-
-
-/*
- * ggen.c
- */
-void	compile(Node*);
-void	gen(Node*);
-Node*	lookdot(Node*, Node*, int);
-void	cgen_as(Node*, Node*);
-void	cgen_callmeth(Node*, int);
-void	cgen_callinter(Node*, Node*, int);
-void	cgen_proc(Node*, int);
-void	cgen_callret(Node*, Node*);
-void	cgen_div(int, Node*, Node*, Node*);
-void	cgen_bmul(int, Node*, Node*, Node*);
-void	cgen_hmul(Node*, Node*, Node*);
-void	cgen_shift(int, int, Node*, Node*, Node*);
-void	cgen_float(Node*, Node*);
-void	bgen_float(Node *n, int true, int likely, Prog *to);
-void	cgen_dcl(Node*);
-int	needconvert(Type*, Type*);
-void	genconv(Type*, Type*);
-void	allocparams(void);
-void	checklabels(void);
-void	ginscall(Node*, int);
-
-/*
- * cgen.c
- */
-void	agen(Node*, Node*);
-void	igen(Node*, Node*, Node*);
-vlong	fieldoffset(Type*, Node*);
-void	sgen(Node*, Node*, int64);
-void	gmove(Node*, Node*);
-Prog*	gins(int, Node*, Node*);
-int	samaddr(Node*, Node*);
-void	naddr(Node*, Addr*, int);
-void	cgen_aret(Node*, Node*);
-Node*	ncon(uint32);
-void	mgen(Node*, Node*, Node*);
-void	mfree(Node*);
-int	componentgen(Node*, Node*);
-
-/*
- * cgen64.c
- */
-void	cmp64(Node*, Node*, int, int, Prog*);
-void	cgen64(Node*, Node*);
-
-/*
- * gsubr.c
- */
-void	clearp(Prog*);
-Prog*	gbranch(int, Type*, int);
-Prog*	prog(int);
-void	gconv(int, int);
-int	conv2pt(Type*);
-vlong	convvtox(vlong, int);
-void	fnparam(Type*, int, int);
-Prog*	gop(int, Node*, Node*, Node*);
-int	optoas(int, Type*);
-int	foptoas(int, Type*, int);
-void	ginit(void);
-void	gclean(void);
-void	regalloc(Node*, Type*, Node*);
-void	regfree(Node*);
-Node*	nodarg(Type*, int);
-void	nodreg(Node*, Type*, int);
-void	nodindreg(Node*, Type*, int);
-void	nodconst(Node*, Type*, int64);
-void	gconreg(int, vlong, int);
-void	buildtxt(void);
-Plist*	newplist(void);
-int	isfat(Type*);
-void	sudoclean(void);
-int	sudoaddable(int, Node*, Addr*);
-int	dotaddable(Node*, Node*);
-void	afunclit(Addr*, Node*);
-void	split64(Node*, Node*, Node*);
-void	splitclean(void);
-void	nswap(Node*, Node*);
-void	gtrack(Sym*);
-/*
- * cplx.c
- */
-int	complexop(Node*, Node*);
-void	complexmove(Node*, Node*);
-void	complexgen(Node*, Node*);
-
-/*
- * gobj.c
- */
-void	datastring(char*, int, Addr*);
-void	datagostring(Strlit*, Addr*);
-
-/*
- * list.c
- */
-void	listinit(void);
-
-void	zaddr(Biobuf*, Addr*, int, int);
diff --git a/src/cmd/8g/ggen.c b/src/cmd/8g/ggen.c
deleted file mode 100644
index 6333a60..0000000
--- a/src/cmd/8g/ggen.c
+++ /dev/null
@@ -1,1342 +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.
-
-#undef	EXTERN
-#define	EXTERN
-#include <u.h>
-#include <libc.h>
-#include "gg.h"
-#include "opt.h"
-
-static Prog *appendpp(Prog*, int, int, vlong, int, vlong);
-static Prog *zerorange(Prog *p, vlong frame, vlong lo, vlong hi, uint32 *ax);
-
-void
-defframe(Prog *ptxt)
-{
-	uint32 frame, ax;
-	Prog *p;
-	vlong lo, hi;
-	NodeList *l;
-	Node *n;
-
-	// fill in argument size
-	ptxt->to.offset2 = rnd(curfn->type->argwid, widthptr);
-
-	// fill in final stack size
-	frame = rnd(stksize+maxarg, widthptr);
-	ptxt->to.offset = 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 = 0;
-	lo = hi;
-	ax = 0;
-	for(l=curfn->dcl; l != nil; l = l->next) {
-		n = l->n;
-		if(!n->needzero)
-			continue;
-		if(n->class != PAUTO)
-			fatal("needzero class %d", n->class);
-		if(n->type->width % widthptr != 0 || n->xoffset % widthptr != 0 || n->type->width == 0)
-			fatal("var %lN has size %d offset %d", n, (int)n->type->width, (int)n->xoffset);
-		if(lo != hi && n->xoffset + n->type->width == lo - 2*widthptr) {
-			// merge with range we already have
-			lo = n->xoffset;
-			continue;
-		}
-		// zero old range
-		p = zerorange(p, frame, lo, hi, &ax);
-
-		// set new range
-		hi = n->xoffset + n->type->width;
-		lo = n->xoffset;
-	}
-	// zero final range
-	zerorange(p, frame, lo, hi, &ax);
-}
-
-static Prog*
-zerorange(Prog *p, vlong frame, vlong lo, vlong hi, uint32 *ax)
-{
-	vlong cnt, i;
-
-	cnt = hi - lo;
-	if(cnt == 0)
-		return p;
-	if(*ax == 0) {
-		p = appendpp(p, AMOVL, D_CONST, 0, D_AX, 0);
-		*ax = 1;
-	}
-	if(cnt <= 4*widthreg) {
-		for(i = 0; i < cnt; i += widthreg) {
-			p = appendpp(p, AMOVL, D_AX, 0, D_SP+D_INDIR, frame+lo+i);
-		}
-	} else if(!nacl && cnt <= 128*widthreg) {
-		p = appendpp(p, ALEAL, D_SP+D_INDIR, frame+lo, D_DI, 0);
-		p = appendpp(p, ADUFFZERO, D_NONE, 0, D_ADDR, 1*(128-cnt/widthreg));
-		p->to.sym = linksym(pkglookup("duffzero", runtimepkg));
-	} else {
-		p = appendpp(p, AMOVL, D_CONST, cnt/widthreg, D_CX, 0);
-		p = appendpp(p, ALEAL, D_SP+D_INDIR, frame+lo, D_DI, 0);
-		p = appendpp(p, AREP, D_NONE, 0, D_NONE, 0);
-		p = appendpp(p, ASTOSL, D_NONE, 0, D_NONE, 0);
-	}
-	return p;
-}
-
-static Prog*	
-appendpp(Prog *p, int as, int ftype, vlong foffset, int ttype, vlong toffset)	
-{
-	Prog *q;
-	q = mal(sizeof(*q));	
-	clearp(q);	
-	q->as = as;	
-	q->lineno = p->lineno;	
-	q->from.type = ftype;	
-	q->from.offset = foffset;	
-	q->to.type = ttype;	
-	q->to.offset = toffset;	
-	q->link = p->link;	
-	p->link = q;	
-	return q;	
-}
-
-// Sweep the prog list to mark any used nodes.
-void
-markautoused(Prog* p)
-{
-	for (; p; p = p->link) {
-		if (p->as == ATYPE || p->as == AVARDEF || p->as == AVARKILL)
-			continue;
-
-		if (p->from.node)
-			p->from.node->used = 1;
-
-		if (p->to.node)
-			p->to.node->used = 1;
-	}
-}
-
-// Fixup instructions after allocauto (formerly compactframe) has moved all autos around.
-void
-fixautoused(Prog* p)
-{
-	Prog **lp;
-
-	for (lp=&p; (p=*lp) != P; ) {
-		if (p->as == ATYPE && p->from.node && p->from.type == D_AUTO && !p->from.node->used) {
-			*lp = p->link;
-			continue;
-		}
-		if ((p->as == AVARDEF || p->as == AVARKILL) && p->to.node && !p->to.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
-			// the no-ops.
-			p->to.type = D_NONE;
-			p->to.node = N;
-			p->as = ANOP;
-			continue;
-		}
-
-		if (p->from.type == D_AUTO && p->from.node)
-			p->from.offset += p->from.node->stkdelta;
-
-		if (p->to.type == D_AUTO && p->to.node)
-			p->to.offset += p->to.node->stkdelta;
-
-		lp = &p->link;
-	}
-}
-
-void
-clearfat(Node *nl)
-{
-	uint32 w, c, q;
-	Node n1, z;
-	Prog *p;
-
-	/* clear a fat object */
-	if(debug['g'])
-		dump("\nclearfat", nl);
-
-	w = nl->type->width;
-	// Avoid taking the address for simple enough types.
-	if(componentgen(N, nl))
-		return;
-
-	c = w % 4;	// bytes
-	q = w / 4;	// quads
-
-	if(q < 4) {
-		// Write sequence of MOV 0, off(base) instead of using STOSL.
-		// The hope is that although the code will be slightly longer,
-		// the MOVs will have no dependencies and pipeline better
-		// than the unrolled STOSL loop.
-		// NOTE: Must use agen, not igen, so that optimizer sees address
-		// being taken. We are not writing on field boundaries.
-		regalloc(&n1, types[tptr], N);
-		agen(nl, &n1);
-		n1.op = OINDREG;
-		nodconst(&z, types[TUINT64], 0);
-		while(q-- > 0) {
-			n1.type = z.type;
-			gins(AMOVL, &z, &n1);
-			n1.xoffset += 4;
-		}
-		nodconst(&z, types[TUINT8], 0);
-		while(c-- > 0) {
-			n1.type = z.type;
-			gins(AMOVB, &z, &n1);
-			n1.xoffset++;
-		}
-		regfree(&n1);
-		return;
-	}
-
-	nodreg(&n1, types[tptr], D_DI);
-	agen(nl, &n1);
-	gconreg(AMOVL, 0, D_AX);
-
-	if(q > 128 || (q >= 4 && nacl)) {
-		gconreg(AMOVL, q, D_CX);
-		gins(AREP, N, N);	// repeat
-		gins(ASTOSL, N, N);	// STOL AL,*(DI)+
-	} else if(q >= 4) {
-		p = gins(ADUFFZERO, N, N);
-		p->to.type = D_ADDR;
-		p->to.sym = linksym(pkglookup("duffzero", runtimepkg));
-		// 1 and 128 = magic constants: see ../../runtime/asm_386.s
-		p->to.offset = 1*(128-q);
-	} else
-	while(q > 0) {
-		gins(ASTOSL, N, N);	// STOL AL,*(DI)+
-		q--;
-	}
-
-	while(c > 0) {
-		gins(ASTOSB, N, N);	// 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)
- */
-void
-ginscall(Node *f, int proc)
-{
-	Prog *p;
-	Node reg, r1, con;
-
-	if(f->type != T)
-		setmaxarg(f->type);
-
-	switch(proc) {
-	default:
-		fatal("ginscall: bad proc %d", proc);
-		break;
-
-	case 0:	// normal call
-	case -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 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.
-				nodreg(&reg, types[TINT], D_AX);
-				gins(AXCHGL, &reg, &reg);
-			}
-			p = gins(ACALL, N, f);
-			afunclit(&p->to, f);
-			if(proc == -1 || noreturn(p))
-				gins(AUNDEF, N, N);
-			break;
-		}
-		nodreg(&reg, types[tptr], D_DX);
-		nodreg(&r1, types[tptr], D_BX);
-		gmove(f, &reg);
-		reg.op = OINDREG;
-		gmove(&reg, &r1);
-		reg.op = OREGISTER;
-		gins(ACALL, &reg, &r1);
-		break;
-	
-	case 3:	// normal call of c function pointer
-		gins(ACALL, N, f);
-		break;
-
-	case 1:	// call in new proc (go)
-	case 2:	// deferred call (defer)
-		nodreg(&reg, types[TINT32], D_CX);
-		gins(APUSHL, f, N);
-		nodconst(&con, types[TINT32], argsize(f->type));
-		gins(APUSHL, &con, N);
-		if(proc == 1)
-			ginscall(newproc, 0);
-		else
-			ginscall(deferproc, 0);
-		gins(APOPL, N, &reg);
-		gins(APOPL, N, &reg);
-		if(proc == 2) {
-			nodreg(&reg, types[TINT64], D_AX);
-			gins(ATESTL, &reg, &reg);
-			p = gbranch(AJEQ, T, +1);
-			cgen_ret(N);
-			patch(p, pc);
-		}
-		break;
-	}
-}
-
-/*
- * n is call to interface method.
- * generate res = n.
- */
-void
-cgen_callinter(Node *n, Node *res, int proc)
-{
-	Node *i, *f;
-	Node tmpi, nodi, nodo, nodr, nodsp;
-
-	i = n->left;
-	if(i->op != ODOTINTER)
-		fatal("cgen_callinter: not ODOTINTER %O", i->op);
-
-	f = i->right;		// field
-	if(f->op != ONAME)
-		fatal("cgen_callinter: not ONAME %O", f->op);
-
-	i = i->left;		// interface
-
-	if(!i->addable) {
-		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.
-	igen(i, &nodi, res);		// REG = &inter
-
-	nodindreg(&nodsp, types[tptr], D_SP);
-	nodi.type = types[tptr];
-	nodi.xoffset += widthptr;
-	cgen(&nodi, &nodsp);	// 0(SP) = 4(REG) -- i.data
-
-	regalloc(&nodo, types[tptr], res);
-	nodi.type = types[tptr];
-	nodi.xoffset -= widthptr;
-	cgen(&nodi, &nodo);	// REG = 0(REG) -- i.tab
-	regfree(&nodi);
-
-	regalloc(&nodr, types[tptr], &nodo);
-	if(n->left->xoffset == BADWIDTH)
-		fatal("cgen_callinter: badwidth");
-	cgen_checknil(&nodo);
-	nodo.op = OINDREG;
-	nodo.xoffset = n->left->xoffset + 3*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(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
- */
-void
-cgen_call(Node *n, int proc)
-{
-	Type *t;
-	Node nod, afun;
-
-	if(n == N)
-		return;
-
-	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) {
-		regalloc(&nod, types[tptr], N);
-		cgen_as(&nod, &afun);
-		nod.type = t;
-		ginscall(&nod, proc);
-		regfree(&nod);
-		return;
-	}
-
-	// call pointer
-	if(n->left->op != ONAME || n->left->class != PFUNC) {
-		regalloc(&nod, types[tptr], N);
-		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.
- */
-void
-cgen_callret(Node *n, Node *res)
-{
-	Node nod;
-	Type *fp, *t;
-	Iter flist;
-
-	t = n->left->type;
-	if(t->etype == TPTR32 || t->etype == TPTR64)
-		t = t->type;
-
-	fp = structfirst(&flist, getoutarg(t));
-	if(fp == T)
-		fatal("cgen_callret: nil");
-
-	memset(&nod, 0, sizeof(nod));
-	nod.op = OINDREG;
-	nod.val.u.reg = D_SP;
-	nod.addable = 1;
-
-	nod.xoffset = fp->width;
-	nod.type = fp->type;
-	cgen_as(res, &nod);
-}
-
-/*
- * call to n has already been generated.
- * generate:
- *	res = &return value from call.
- */
-void
-cgen_aret(Node *n, Node *res)
-{
-	Node nod1, nod2;
-	Type *fp, *t;
-	Iter flist;
-
-	t = n->left->type;
-	if(isptr[t->etype])
-		t = t->type;
-
-	fp = structfirst(&flist, getoutarg(t));
-	if(fp == T)
-		fatal("cgen_aret: nil");
-
-	memset(&nod1, 0, sizeof(nod1));
-	nod1.op = OINDREG;
-	nod1.val.u.reg = D_SP;
-	nod1.addable = 1;
-
-	nod1.xoffset = fp->width;
-	nod1.type = fp->type;
-
-	if(res->op != OREGISTER) {
-		regalloc(&nod2, types[tptr], res);
-		gins(ALEAL, &nod1, &nod2);
-		gins(AMOVL, &nod2, res);
-		regfree(&nod2);
-	} else
-		gins(ALEAL, &nod1, res);
-}
-
-/*
- * generate return.
- * n->left is assignments to return values.
- */
-void
-cgen_ret(Node *n)
-{
-	Prog *p;
-
-	if(n != N)
-		genlist(n->list);		// copy out args
-	if(hasdefer)
-		ginscall(deferreturn, 0);
-	genlist(curfn->exit);
-	p = gins(ARET, N, N);
-	if(n != N && n->op == ORETJMP) {
-		p->to.type = D_EXTERN;
-		p->to.sym = linksym(n->left->sym);
-	}
-}
-
-/*
- * generate += *= etc.
- */
-void
-cgen_asop(Node *n)
-{
-	Node n1, n2, n3, n4;
-	Node *nl, *nr;
-	Prog *p1;
-	Addr addr;
-	int a;
-
-	nl = n->left;
-	nr = n->right;
-
-	if(nr->ullman >= UINF && nl->ullman >= UINF) {
-		tempname(&n1, nr->type);
-		cgen(nr, &n1);
-		n2 = *n;
-		n2.right = &n1;
-		cgen_asop(&n2);
-		goto ret;
-	}
-
-	if(!isint[nl->type->etype])
-		goto hard;
-	if(!isint[nr->type->etype])
-		goto hard;
-	if(is64(nl->type) || is64(nr->type))
-		goto hard;
-
-	switch(n->etype) {
-	case OADD:
-		if(smallintconst(nr))
-		if(mpgetfix(nr->val.u.xval) == 1) {
-			a = optoas(OINC, nl->type);
-			if(nl->addable) {
-				gins(a, N, nl);
-				goto ret;
-			}
-			if(sudoaddable(a, nl, &addr)) {
-				p1 = gins(a, N, N);
-				p1->to = addr;
-				sudoclean();
-				goto ret;
-			}
-		}
-		break;
-
-	case OSUB:
-		if(smallintconst(nr))
-		if(mpgetfix(nr->val.u.xval) == 1) {
-			a = optoas(ODEC, nl->type);
-			if(nl->addable) {
-				gins(a, N, nl);
-				goto ret;
-			}
-			if(sudoaddable(a, nl, &addr)) {
-				p1 = gins(a, N, N);
-				p1->to = addr;
-				sudoclean();
-				goto ret;
-			}
-		}
-		break;
-	}
-
-	switch(n->etype) {
-	case OADD:
-	case OSUB:
-	case OXOR:
-	case OAND:
-	case OOR:
-		a = optoas(n->etype, nl->type);
-		if(nl->addable) {
-			if(smallintconst(nr)) {
-				gins(a, nr, nl);
-				goto ret;
-			}
-			regalloc(&n2, nr->type, N);
-			cgen(nr, &n2);
-			gins(a, &n2, nl);
-			regfree(&n2);
-			goto ret;
-		}
-		if(nr->ullman < UINF)
-		if(sudoaddable(a, nl, &addr)) {
-			if(smallintconst(nr)) {
-				p1 = gins(a, nr, N);
-				p1->to = addr;
-				sudoclean();
-				goto ret;
-			}
-			regalloc(&n2, nr->type, N);
-			cgen(nr, &n2);
-			p1 = gins(a, &n2, N);
-			p1->to = addr;
-			regfree(&n2);
-			sudoclean();
-			goto ret;
-		}
-	}
-
-hard:
-	n2.op = 0;
-	n1.op = 0;
-	if(nr->ullman >= nl->ullman || nl->addable) {
-		mgen(nr, &n2, N);
-		nr = &n2;
-	} else {
-		tempname(&n2, nr->type);
-		cgen(nr, &n2);
-		nr = &n2;
-	}
-	if(!nl->addable) {
-		igen(nl, &n1, N);
-		nl = &n1;
-	}
-
-	n3 = *n;
-	n3.left = nl;
-	n3.right = nr;
-	n3.op = n->etype;
-
-	mgen(&n3, &n4, N);
-	gmove(&n4, nl);
-
-	if(n1.op)
-		regfree(&n1);
-	mfree(&n2);
-	mfree(&n4);
-
-ret:
-	;
-}
-
-int
-samereg(Node *a, Node *b)
-{
-	if(a->op != OREGISTER)
-		return 0;
-	if(b->op != OREGISTER)
-		return 0;
-	if(a->val.u.reg != b->val.u.reg)
-		return 0;
-	return 1;
-}
-
-/*
- * generate division.
- * caller must set:
- *	ax = allocated AX register
- *	dx = allocated DX register
- * generates one of:
- *	res = nl / nr
- *	res = nl % nr
- * according to op.
- */
-void
-dodiv(int op, Node *nl, Node *nr, Node *res, Node *ax, Node *dx)
-{
-	int check;
-	Node n1, t1, t2, t3, t4, n4, nz;
-	Type *t, *t0;
-	Prog *p1, *p2;
-
-	// Have to be careful about handling
-	// most negative int divided by -1 correctly.
-	// The hardware will trap.
-	// Also the byte divide instruction needs AH,
-	// which we otherwise don't have to deal with.
-	// Easiest way to avoid for int8, int16: use int32.
-	// For int32 and int64, use explicit test.
-	// Could use int64 hw for int32.
-	t = nl->type;
-	t0 = t;
-	check = 0;
-	if(issigned[t->etype]) {
-		check = 1;
-		if(isconst(nl, CTINT) && mpgetfix(nl->val.u.xval) != -1LL<<(t->width*8-1))
-			check = 0;
-		else if(isconst(nr, CTINT) && mpgetfix(nr->val.u.xval) != -1)
-			check = 0;
-	}
-	if(t->width < 4) {
-		if(issigned[t->etype])
-			t = types[TINT32];
-		else
-			t = types[TUINT32];
-		check = 0;
-	}
-
-	tempname(&t1, t);
-	tempname(&t2, t);
-	if(t0 != t) {
-		tempname(&t3, t0);
-		tempname(&t4, t0);
-		cgen(nl, &t3);
-		cgen(nr, &t4);
-		// Convert.
-		gmove(&t3, &t1);
-		gmove(&t4, &t2);
-	} else {
-		cgen(nl, &t1);
-		cgen(nr, &t2);
-	}
-
-	if(!samereg(ax, res) && !samereg(dx, res))
-		regalloc(&n1, t, res);
-	else
-		regalloc(&n1, t, N);
-	gmove(&t2, &n1);
-	gmove(&t1, ax);
-	p2 = P;
-	if(nacl) {
-		// Native Client does not relay the divide-by-zero trap
-		// to the executing program, so we must insert a check
-		// for ourselves.
-		nodconst(&n4, t, 0);
-		gins(optoas(OCMP, t), &n1, &n4);
-		p1 = gbranch(optoas(ONE, t), T, +1);
-		if(panicdiv == N)
-			panicdiv = sysfunc("panicdivide");
-		ginscall(panicdiv, -1);
-		patch(p1, pc);
-	}
-	if(check) {
-		nodconst(&n4, t, -1);
-		gins(optoas(OCMP, t), &n1, &n4);
-		p1 = gbranch(optoas(ONE, t), T, +1);
-		if(op == ODIV) {
-			// a / (-1) is -a.
-			gins(optoas(OMINUS, t), N, ax);
-			gmove(ax, res);
-		} else {
-			// a % (-1) is 0.
-			nodconst(&n4, t, 0);
-			gmove(&n4, res);
-		}
-		p2 = gbranch(AJMP, T, 0);
-		patch(p1, pc);
-	}
-	if(!issigned[t->etype]) {
-		nodconst(&nz, t, 0);
-		gmove(&nz, dx);
-	} else
-		gins(optoas(OEXTEND, t), N, N);
-	gins(optoas(op, t), &n1, N);
-	regfree(&n1);
-
-	if(op == ODIV)
-		gmove(ax, res);
-	else
-		gmove(dx, res);
-	if(check)
-		patch(p2, pc);
-}
-
-static void
-savex(int dr, Node *x, Node *oldx, Node *res, Type *t)
-{
-	int r;
-
-	r = reg[dr];
-	nodreg(x, types[TINT32], dr);
-
-	// save current ax and dx if they are live
-	// and not the destination
-	memset(oldx, 0, sizeof *oldx);
-	if(r > 0 && !samereg(x, res)) {
-		tempname(oldx, types[TINT32]);
-		gmove(x, oldx);
-	}
-
-	regalloc(x, t, x);
-}
-
-static void
-restx(Node *x, Node *oldx)
-{
-	regfree(x);
-
-	if(oldx->op != 0) {
-		x->type = types[TINT32];
-		gmove(oldx, x);
-	}
-}
-
-/*
- * generate division according to op, one of:
- *	res = nl / nr
- *	res = nl % nr
- */
-void
-cgen_div(int op, Node *nl, Node *nr, Node *res)
-{
-	Node ax, dx, oldax, olddx;
-	Type *t;
-
-	if(is64(nl->type))
-		fatal("cgen_div %T", nl->type);
-
-	if(issigned[nl->type->etype])
-		t = types[TINT32];
-	else
-		t = types[TUINT32];
-	savex(D_AX, &ax, &oldax, res, t);
-	savex(D_DX, &dx, &olddx, res, t);
-	dodiv(op, nl, nr, res, &ax, &dx);
-	restx(&dx, &olddx);
-	restx(&ax, &oldax);
-}
-
-/*
- * generate shift according to op, one of:
- *	res = nl << nr
- *	res = nl >> nr
- */
-void
-cgen_shift(int op, int bounded, Node *nl, Node *nr, Node *res)
-{
-	Node n1, n2, nt, cx, oldcx, hi, lo;
-	int a, w;
-	Prog *p1, *p2;
-	uvlong sc;
-
-	if(nl->type->width > 4)
-		fatal("cgen_shift %T", nl->type);
-
-	w = nl->type->width * 8;
-
-	a = optoas(op, nl->type);
-
-	if(nr->op == OLITERAL) {
-		tempname(&n2, nl->type);
-		cgen(nl, &n2);
-		regalloc(&n1, nl->type, res);
-		gmove(&n2, &n1);
-		sc = mpgetfix(nr->val.u.xval);
-		if(sc >= nl->type->width*8) {
-			// large shift gets 2 shifts by width-1
-			gins(a, ncon(w-1), &n1);
-			gins(a, ncon(w-1), &n1);
-		} else
-			gins(a, nr, &n1);
-		gmove(&n1, res);
-		regfree(&n1);
-		return;
-	}
-
-	memset(&oldcx, 0, sizeof oldcx);
-	nodreg(&cx, types[TUINT32], D_CX);
-	if(reg[D_CX] > 1 && !samereg(&cx, res)) {
-		tempname(&oldcx, types[TUINT32]);
-		gmove(&cx, &oldcx);
-	}
-
-	if(nr->type->width > 4) {
-		tempname(&nt, nr->type);
-		n1 = nt;
-	} else {
-		nodreg(&n1, types[TUINT32], D_CX);
-		regalloc(&n1, nr->type, &n1);		// to hold the shift type in CX
-	}
-
-	if(samereg(&cx, res))
-		regalloc(&n2, nl->type, N);
-	else
-		regalloc(&n2, nl->type, res);
-	if(nl->ullman >= nr->ullman) {
-		cgen(nl, &n2);
-		cgen(nr, &n1);
-	} else {
-		cgen(nr, &n1);
-		cgen(nl, &n2);
-	}
-
-	// test and fix up large shifts
-	if(bounded) {
-		if(nr->type->width > 4) {
-			// delayed reg alloc
-			nodreg(&n1, types[TUINT32], D_CX);
-			regalloc(&n1, types[TUINT32], &n1);		// to hold the shift type in CX
-			split64(&nt, &lo, &hi);
-			gmove(&lo, &n1);
-			splitclean();
-		}
-	} else {
-		if(nr->type->width > 4) {
-			// delayed reg alloc
-			nodreg(&n1, types[TUINT32], D_CX);
-			regalloc(&n1, types[TUINT32], &n1);		// to hold the shift type in CX
-			split64(&nt, &lo, &hi);
-			gmove(&lo, &n1);
-			gins(optoas(OCMP, types[TUINT32]), &hi, ncon(0));
-			p2 = gbranch(optoas(ONE, types[TUINT32]), T, +1);
-			gins(optoas(OCMP, types[TUINT32]), &n1, ncon(w));
-			p1 = gbranch(optoas(OLT, types[TUINT32]), T, +1);
-			splitclean();
-			patch(p2, pc);
-		} else {
-			gins(optoas(OCMP, nr->type), &n1, ncon(w));
-			p1 = gbranch(optoas(OLT, types[TUINT32]), T, +1);
-		}
-		if(op == ORSH && issigned[nl->type->etype]) {
-			gins(a, ncon(w-1), &n2);
-		} else {
-			gmove(ncon(0), &n2);
-		}
-		patch(p1, pc);
-	}
-	gins(a, &n1, &n2);
-
-	if(oldcx.op != 0)
-		gmove(&oldcx, &cx);
-
-	gmove(&n2, res);
-
-	regfree(&n1);
-	regfree(&n2);
-}
-
-/*
- * generate byte multiply:
- *	res = nl * nr
- * there is no 2-operand byte multiply instruction so
- * we do a full-width multiplication and truncate afterwards.
- */
-void
-cgen_bmul(int op, Node *nl, Node *nr, Node *res)
-{
-	Node n1, n2, nt, *tmp;
-	Type *t;
-	int a;
-
-	// copy from byte to full registers
-	t = types[TUINT32];
-	if(issigned[nl->type->etype])
-		t = types[TINT32];
-
-	// largest ullman on left.
-	if(nl->ullman < nr->ullman) {
-		tmp = nl;
-		nl = nr;
-		nr = tmp;
-	}
-
-	tempname(&nt, nl->type);
-	cgen(nl, &nt);
-	regalloc(&n1, t, res);
-	cgen(nr, &n1);
-	regalloc(&n2, t, N);
-	gmove(&nt, &n2);
-	a = optoas(op, t);
-	gins(a, &n2, &n1);
-	regfree(&n2);
-	gmove(&n1, res);
-	regfree(&n1);
-}
-
-/*
- * generate high multiply:
- *   res = (nl*nr) >> width
- */
-void
-cgen_hmul(Node *nl, Node *nr, Node *res)
-{
-	Type *t;
-	int a;
-	Node n1, n2, ax, dx;
-
-	t = nl->type;
-	a = optoas(OHMUL, t);
-	// gen nl in n1.
-	tempname(&n1, t);
-	cgen(nl, &n1);
-	// gen nr in n2.
-	regalloc(&n2, t, res);
-	cgen(nr, &n2);
-
-	// multiply.
-	nodreg(&ax, t, D_AX);
-	gmove(&n2, &ax);
-	gins(a, &n1, N);
-	regfree(&n2);
-
-	if(t->width == 1) {
-		// byte multiply behaves differently.
-		nodreg(&ax, t, D_AH);
-		nodreg(&dx, t, D_DX);
-		gmove(&ax, &dx);
-	}
-	nodreg(&dx, t, D_DX);
-	gmove(&dx, res);
-}
-
-static void cgen_float387(Node *n, Node *res);
-static void cgen_floatsse(Node *n, Node *res);
-
-/*
- * generate floating-point operation.
- */
-void
-cgen_float(Node *n, Node *res)
-{
-	Node *nl;
-	Node n1, n2;
-	Prog *p1, *p2, *p3;
-
-	nl = n->left;
-	switch(n->op) {
-	case OEQ:
-	case ONE:
-	case OLT:
-	case OLE:
-	case OGE:
-		p1 = gbranch(AJMP, T, 0);
-		p2 = pc;
-		gmove(nodbool(1), res);
-		p3 = gbranch(AJMP, T, 0);
-		patch(p1, pc);
-		bgen(n, 1, 0, p2);
-		gmove(nodbool(0), res);
-		patch(p3, pc);
-		return;
-
-	case OPLUS:
-		cgen(nl, res);
-		return;
-
-	case OCONV:
-		if(eqtype(n->type, nl->type) || noconv(n->type, nl->type)) {
-			cgen(nl, res);
-			return;
-		}
-
-		tempname(&n2, n->type);
-		mgen(nl, &n1, res);
-		gmove(&n1, &n2);
-		gmove(&n2, res);
-		mfree(&n1);
-		return;
-	}
-
-	if(use_sse)
-		cgen_floatsse(n, res);
-	else
-		cgen_float387(n, res);
-}
-
-// floating-point.  387 (not SSE2)
-static void
-cgen_float387(Node *n, Node *res)
-{
-	Node f0, f1;
-	Node *nl, *nr;
-
-	nl = n->left;
-	nr = n->right;
-	nodreg(&f0, nl->type, D_F0);
-	nodreg(&f1, n->type, D_F0+1);
-	if(nr != N)
-		goto flt2;
-
-	// unary
-	cgen(nl, &f0);
-	if(n->op != OCONV && n->op != OPLUS)
-		gins(foptoas(n->op, n->type, 0), N, N);
-	gmove(&f0, res);
-	return;
-
-flt2:	// binary
-	if(nl->ullman >= nr->ullman) {
-		cgen(nl, &f0);
-		if(nr->addable)
-			gins(foptoas(n->op, n->type, 0), nr, &f0);
-		else {
-			cgen(nr, &f0);
-			gins(foptoas(n->op, n->type, Fpop), &f0, &f1);
-		}
-	} else {
-		cgen(nr, &f0);
-		if(nl->addable)
-			gins(foptoas(n->op, n->type, Frev), nl, &f0);
-		else {
-			cgen(nl, &f0);
-			gins(foptoas(n->op, n->type, Frev|Fpop), &f0, &f1);
-		}
-	}
-	gmove(&f0, res);
-	return;
-
-}
-
-static void
-cgen_floatsse(Node *n, Node *res)
-{
-	Node *nl, *nr, *r;
-	Node n1, n2, nt;
-	int a;
-
-	nl = n->left;
-	nr = n->right;
-	switch(n->op) {
-	default:
-		dump("cgen_floatsse", n);
-		fatal("cgen_floatsse %O", n->op);
-		return;
-
-	case OMINUS:
-	case OCOM:
-		nr = nodintconst(-1);
-		convlit(&nr, n->type);
-		a = foptoas(OMUL, nl->type, 0);
-		goto sbop;
-
-	// symmetric binary
-	case OADD:
-	case OMUL:
-		a = foptoas(n->op, nl->type, 0);
-		goto sbop;
-
-	// asymmetric binary
-	case OSUB:
-	case OMOD:
-	case ODIV:
-		a = foptoas(n->op, nl->type, 0);
-		goto abop;
-	}
-
-sbop:	// symmetric binary
-	if(nl->ullman < nr->ullman || nl->op == OLITERAL) {
-		r = nl;
-		nl = nr;
-		nr = r;
-	}
-
-abop:	// asymmetric binary
-	if(nl->ullman >= nr->ullman) {
-		tempname(&nt, nl->type);
-		cgen(nl, &nt);
-		mgen(nr, &n2, N);
-		regalloc(&n1, nl->type, res);
-		gmove(&nt, &n1);
-		gins(a, &n2, &n1);
-		gmove(&n1, res);
-		regfree(&n1);
-		mfree(&n2);
-	} else {
-		regalloc(&n2, nr->type, res);
-		cgen(nr, &n2);
-		regalloc(&n1, nl->type, N);
-		cgen(nl, &n1);
-		gins(a, &n2, &n1);
-		regfree(&n2);
-		gmove(&n1, res);
-		regfree(&n1);
-	}
-	return;
-}
-
-void
-bgen_float(Node *n, int true, int likely, Prog *to)
-{
-	int et, a;
-	Node *nl, *nr, *r;
-	Node n1, n2, n3, tmp, t1, t2, ax;
-	Prog *p1, *p2;
-
-	nl = n->left;
-	nr = n->right;
-	a = n->op;
-	if(!true) {
-		// brcom is not valid on floats when NaN is involved.
-		p1 = gbranch(AJMP, T, 0);
-		p2 = gbranch(AJMP, T, 0);
-		patch(p1, pc);
-		// No need to avoid re-genning ninit.
-		bgen_float(n, 1, -likely, p2);
-		patch(gbranch(AJMP, T, 0), to);
-		patch(p2, pc);
-		return;
-	}
-
-	if(use_sse)
-		goto sse;
-	else
-		goto x87;
-
-x87:
-	a = brrev(a);	// because the args are stacked
-	if(a == OGE || a == OGT) {
-		// only < and <= work right with NaN; reverse if needed
-		r = nr;
-		nr = nl;
-		nl = r;
-		a = brrev(a);
-	}
-
-	nodreg(&tmp, nr->type, D_F0);
-	nodreg(&n2, nr->type, D_F0 + 1);
-	nodreg(&ax, types[TUINT16], D_AX);
-	et = simsimtype(nr->type);
-	if(et == TFLOAT64) {
-		if(nl->ullman > nr->ullman) {
-			cgen(nl, &tmp);
-			cgen(nr, &tmp);
-			gins(AFXCHD, &tmp, &n2);
-		} else {
-			cgen(nr, &tmp);
-			cgen(nl, &tmp);
-		}
-		gins(AFUCOMIP, &tmp, &n2);
-		gins(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.
-		// This handles 32-bit comparison but presumably
-		// all the other ops have the same problem.
-		// We need to figure out what the right general
-		// solution is, besides telling people to use float64.
-		tempname(&t1, types[TFLOAT32]);
-		tempname(&t2, types[TFLOAT32]);
-		cgen(nr, &t1);
-		cgen(nl, &t2);
-		gmove(&t2, &tmp);
-		gins(AFCOMFP, &t1, &tmp);
-		gins(AFSTSW, N, &ax);
-		gins(ASAHF, N, N);
-	}
-
-	goto ret;
-
-sse:
-	if(!nl->addable) {
-		tempname(&n1, nl->type);
-		cgen(nl, &n1);
-		nl = &n1;
-	}
-	if(!nr->addable) {
-		tempname(&tmp, nr->type);
-		cgen(nr, &tmp);
-		nr = &tmp;
-	}
-	regalloc(&n2, nr->type, N);
-	gmove(nr, &n2);
-	nr = &n2;
-
-	if(nl->op != OREGISTER) {
-		regalloc(&n3, nl->type, N);
-		gmove(nl, &n3);
-		nl = &n3;
-	}
-
-	if(a == OGE || a == OGT) {
-		// only < and <= work right with NaN; reverse if needed
-		r = nr;
-		nr = nl;
-		nl = r;
-		a = brrev(a);
-	}
-
-	gins(foptoas(OCMP, nr->type, 0), nl, nr);
-	if(nl->op == OREGISTER)
-		regfree(nl);
-	regfree(nr);
-
-ret:
-	if(a == OEQ) {
-		// neither NE nor P
-		p1 = gbranch(AJNE, T, -likely);
-		p2 = gbranch(AJPS, T, -likely);
-		patch(gbranch(AJMP, T, 0), to);
-		patch(p1, pc);
-		patch(p2, pc);
-	} else if(a == ONE) {
-		// either NE or P
-		patch(gbranch(AJNE, T, likely), to);
-		patch(gbranch(AJPS, T, likely), to);
-	} else
-		patch(gbranch(optoas(a, nr->type), T, likely), to);
-
-}
-
-// Called after regopt and peep have run.
-// Expand CHECKNIL pseudo-op into actual nil pointer check.
-void
-expandchecks(Prog *firstp)
-{
-	Prog *p, *p1, *p2;
-
-	for(p = firstp; p != P; p = p->link) {
-		if(p->as != ACHECKNIL)
-			continue;
-		if(debug_checknil && p->lineno > 1) // p->lineno==1 in generated wrappers
-			warnl(p->lineno, "generated nil check");
-		// check is
-		//	CMP arg, $0
-		//	JNE 2(PC) (likely)
-		//	MOV AX, 0
-		p1 = mal(sizeof *p1);
-		p2 = mal(sizeof *p2);
-		clearp(p1);
-		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 = ACMPL;
-		p->to.type = D_CONST;
-		p->to.offset = 0;
-		p1->as = AJNE;
-		p1->from.type = D_CONST;
-		p1->from.offset = 1; // likely
-		p1->to.type = D_BRANCH;
-		p1->to.u.branch = 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 = AMOVL;
-		p2->from.type = D_AX;
-		if(regtyp(&p->from))
-			p2->to.type = p->from.type + D_INDIR;
-		else
-			p2->to.type = D_INDIR+D_NONE;
-		p2->to.offset = 0;
-	}
-}
diff --git a/src/cmd/8g/gobj.c b/src/cmd/8g/gobj.c
deleted file mode 100644
index fa0605e..0000000
--- a/src/cmd/8g/gobj.c
+++ /dev/null
@@ -1,246 +0,0 @@
-// Derived from Inferno utils/8c/swt.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8c/swt.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include <u.h>
-#include <libc.h>
-#include "gg.h"
-
-int
-dsname(Sym *s, int off, char *t, int n)
-{
-	Prog *p;
-
-	p = gins(ADATA, N, N);
-	p->from.type = D_EXTERN;
-	p->from.index = D_NONE;
-	p->from.offset = off;
-	p->from.scale = n;
-	p->from.sym = linksym(s);
-	
-	p->to.type = D_SCONST;
-	p->to.index = D_NONE;
-	memmove(p->to.u.sval, t, n);
-	return off + n;
-}
-
-/*
- * make a refer to the data s, s+len
- * emitting DATA if needed.
- */
-void
-datastring(char *s, int len, Addr *a)
-{
-	Sym *sym;
-	
-	sym = stringsym(s, len);
-	a->type = D_EXTERN;
-	a->sym = linksym(sym);
-	a->node = sym->def;
-	a->offset = widthptr+4;  // skip header
-	a->etype = TINT32;
-}
-
-/*
- * make a refer to the string sval,
- * emitting DATA if needed.
- */
-void
-datagostring(Strlit *sval, Addr *a)
-{
-	Sym *sym;
-	
-	sym = stringsym(sval->s, sval->len);
-	a->type = D_EXTERN;
-	a->sym = linksym(sym);
-	a->node = sym->def;
-	a->offset = 0;  // header
-	a->etype = TINT32;
-}
-
-void
-gdata(Node *nam, Node *nr, int wid)
-{
-	Prog *p;
-	vlong v;
-
-	if(nr->op == OLITERAL) {
-		switch(nr->val.ctype) {
-		case CTCPLX:
-			gdatacomplex(nam, nr->val.u.cval);
-			return;
-		case CTSTR:
-			gdatastring(nam, nr->val.u.sval);
-			return;
-		}
-	}
-
-	if(wid == 8 && is64(nr->type)) {
-		v = mpgetfix(nr->val.u.xval);
-		p = gins(ADATA, nam, nodintconst(v));
-		p->from.scale = 4;
-		p = gins(ADATA, nam, nodintconst(v>>32));
-		p->from.scale = 4;
-		p->from.offset += 4;
-		return;
-	}
-	p = gins(ADATA, nam, nr);
-	p->from.scale = wid;
-}
-
-void
-gdatacomplex(Node *nam, Mpcplx *cval)
-{
-	Prog *p;
-	int w;
-
-	w = cplxsubtype(nam->type->etype);
-	w = types[w]->width;
-
-	p = gins(ADATA, nam, N);
-	p->from.scale = w;
-	p->to.type = D_FCONST;
-	p->to.u.dval = mpgetflt(&cval->real);
-
-	p = gins(ADATA, nam, N);
-	p->from.scale = w;
-	p->from.offset += w;
-	p->to.type = D_FCONST;
-	p->to.u.dval = mpgetflt(&cval->imag);
-}
-
-void
-gdatastring(Node *nam, Strlit *sval)
-{
-	Prog *p;
-	Node nod1;
-
-	p = gins(ADATA, nam, N);
-	datastring(sval->s, sval->len, &p->to);
-	p->from.scale = types[tptr]->width;
-	p->to.index = p->to.type;
-	p->to.type = D_ADDR;
-//print("%P\n", p);
-
-	nodconst(&nod1, types[TINT32], sval->len);
-	p = gins(ADATA, nam, &nod1);
-	p->from.scale = types[TINT32]->width;
-	p->from.offset += types[tptr]->width;
-}
-
-int
-dstringptr(Sym *s, int off, char *str)
-{
-	Prog *p;
-
-	off = rnd(off, widthptr);
-	p = gins(ADATA, N, N);
-	p->from.type = D_EXTERN;
-	p->from.index = D_NONE;
-	p->from.sym = linksym(s);
-	p->from.offset = off;
-	p->from.scale = widthptr;
-
-	datastring(str, strlen(str)+1, &p->to);
-	p->to.index = p->to.type;
-	p->to.type = D_ADDR;
-	p->to.etype = TINT32;
-	off += widthptr;
-
-	return off;
-}
-
-int
-dgostrlitptr(Sym *s, int off, Strlit *lit)
-{
-	Prog *p;
-
-	if(lit == nil)
-		return duintptr(s, off, 0);
-
-	off = rnd(off, widthptr);
-	p = gins(ADATA, N, N);
-	p->from.type = D_EXTERN;
-	p->from.index = D_NONE;
-	p->from.sym = linksym(s);
-	p->from.offset = off;
-	p->from.scale = widthptr;
-	datagostring(lit, &p->to);
-	p->to.index = p->to.type;
-	p->to.type = D_ADDR;
-	p->to.etype = TINT32;
-	off += widthptr;
-
-	return off;
-}
-
-int
-dgostringptr(Sym *s, int off, char *str)
-{
-	int n;
-	Strlit *lit;
-
-	if(str == nil)
-		return duintptr(s, off, 0);
-
-	n = strlen(str);
-	lit = mal(sizeof *lit + n);
-	strcpy(lit->s, str);
-	lit->len = n;
-	return dgostrlitptr(s, off, lit);
-}
-
-int
-dsymptr(Sym *s, int off, Sym *x, int xoff)
-{
-	Prog *p;
-
-	off = rnd(off, widthptr);
-
-	p = gins(ADATA, N, N);
-	p->from.type = D_EXTERN;
-	p->from.index = D_NONE;
-	p->from.sym = linksym(s);
-	p->from.offset = off;
-	p->from.scale = widthptr;
-	p->to.type = D_ADDR;
-	p->to.index = D_EXTERN;
-	p->to.sym = linksym(x);
-	p->to.offset = xoff;
-	off += widthptr;
-
-	return off;
-}
-
-void
-nopout(Prog *p)
-{
-	p->as = ANOP;
-}
-
diff --git a/src/cmd/8g/gsubr.c b/src/cmd/8g/gsubr.c
deleted file mode 100644
index 3077e0a..0000000
--- a/src/cmd/8g/gsubr.c
+++ /dev/null
@@ -1,2401 +0,0 @@
-// Derived from Inferno utils/8c/txt.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8c/txt.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include <u.h>
-#include <libc.h>
-#include "gg.h"
-#include "../../runtime/funcdata.h"
-
-// TODO(rsc): Can make this bigger if we move
-// the text segment up higher in 8l for all GOOS.
-// At the same time, can raise StackBig in ../../runtime/stack.h.
-uint32 unmappedzero = 4096;
-
-#define	CASE(a,b)	(((a)<<16)|((b)<<0))
-/*c2go int CASE(int, int);*/
-
-void
-clearp(Prog *p)
-{
-	p->as = AEND;
-	p->from.type = D_NONE;
-	p->from.index = D_NONE;
-	p->to.type = D_NONE;
-	p->to.index = D_NONE;
-	p->pc = pcloc;
-	pcloc++;
-}
-
-static int ddumped;
-static Prog *dfirst;
-static Prog *dpc;
-
-/*
- * generate and return proc with p->as = as,
- * linked into program.  pc is next instruction.
- */
-Prog*
-prog(int as)
-{
-	Prog *p;
-
-	if(as == ADATA || as == AGLOBL) {
-		if(ddumped)
-			fatal("already dumped data");
-		if(dpc == nil) {
-			dpc = mal(sizeof(*dpc));
-			dfirst = dpc;
-		}
-		p = dpc;
-		dpc = mal(sizeof(*dpc));
-		p->link = dpc;
-	} else {
-		p = pc;
-		pc = mal(sizeof(*pc));
-		clearp(pc);
-		p->link = pc;
-	}
-
-	if(lineno == 0) {
-		if(debug['K'])
-			warn("prog: line 0");
-	}
-
-	p->as = as;
-	p->lineno = lineno;
-	return p;
-}
-
-void
-dumpdata(void)
-{
-	ddumped = 1;
-	if(dfirst == nil)
-		return;
-	newplist();
-	*pc = *dfirst;
-	pc = dpc;
-	clearp(pc);
-}
-
-/*
- * generate a branch.
- * t is ignored.
- * likely values are for branch prediction:
- *	-1 unlikely
- *	0 no opinion
- *	+1 likely
- */
-Prog*
-gbranch(int as, Type *t, int likely)
-{
-	Prog *p;
-
-	USED(t);
-	p = prog(as);
-	p->to.type = D_BRANCH;
-	p->to.u.branch = P;
-	if(likely != 0) {
-		p->from.type = D_CONST;
-		p->from.offset = likely > 0;
-	}
-	return p;
-}
-
-/*
- * patch previous branch to jump to to.
- */
-void
-patch(Prog *p, Prog *to)
-{
-	if(p->to.type != D_BRANCH)
-		fatal("patch: not a branch");
-	p->to.u.branch = to;
-	p->to.offset = to->pc;
-}
-
-Prog*
-unpatch(Prog *p)
-{
-	Prog *q;
-
-	if(p->to.type != D_BRANCH)
-		fatal("unpatch: not a branch");
-	q = p->to.u.branch;
-	p->to.u.branch = P;
-	p->to.offset = 0;
-	return q;
-}
-
-/*
- * start a new Prog list.
- */
-Plist*
-newplist(void)
-{
-	Plist *pl;
-
-	pl = linknewplist(ctxt);
-	
-	pc = mal(sizeof(*pc));
-	clearp(pc);
-	pl->firstpc = pc;
-
-	return pl;
-}
-
-void
-gused(Node *n)
-{
-	gins(ANOP, n, N);	// used
-}
-
-Prog*
-gjmp(Prog *to)
-{
-	Prog *p;
-
-	p = gbranch(AJMP, T, 0);
-	if(to != P)
-		patch(p, to);
-	return p;
-}
-
-void
-ggloblnod(Node *nam)
-{
-	Prog *p;
-
-	p = gins(AGLOBL, nam, N);
-	p->lineno = nam->lineno;
-	p->from.sym->gotype = linksym(ngotype(nam));
-	p->to.sym = nil;
-	p->to.type = D_CONST;
-	p->to.offset = nam->type->width;
-	if(nam->readonly)
-		p->from.scale = RODATA;
-	if(nam->type != T && !haspointers(nam->type))
-		p->from.scale |= NOPTR;
-}
-
-void
-ggloblsym(Sym *s, int32 width, int8 flags)
-{
-	Prog *p;
-
-	p = gins(AGLOBL, N, N);
-	p->from.type = D_EXTERN;
-	p->from.index = D_NONE;
-	p->from.sym = linksym(s);
-	p->to.type = D_CONST;
-	p->to.index = D_NONE;
-	p->to.offset = width;
-	p->from.scale = flags;
-}
-
-void
-gtrack(Sym *s)
-{
-	Prog *p;
-	
-	p = gins(AUSEFIELD, N, N);
-	p->from.type = D_EXTERN;
-	p->from.index = D_NONE;
-	p->from.sym = linksym(s);
-}
-
-int
-isfat(Type *t)
-{
-	if(t != T)
-	switch(t->etype) {
-	case TSTRUCT:
-	case TARRAY:
-	case TSTRING:
-	case TINTER:	// maybe remove later
-		return 1;
-	}
-	return 0;
-}
-
-/*
- * naddr of func generates code for address of func.
- * if using opcode that can take address implicitly,
- * call afunclit to fix up the argument.
- */
-void
-afunclit(Addr *a, Node *n)
-{
-	if(a->type == D_ADDR && a->index == D_EXTERN) {
-		a->type = D_EXTERN;
-		a->index = D_NONE;
-		a->sym = linksym(n->sym);
-	}
-}
-
-/*
- * return Axxx for Oxxx on type t.
- */
-int
-optoas(int op, Type *t)
-{
-	int a;
-
-	if(t == T)
-		fatal("optoas: t is nil");
-
-	a = AGOK;
-	switch(CASE(op, simtype[t->etype])) {
-	default:
-		fatal("optoas: no entry %O-%T", op, t);
-		break;
-
-	case CASE(OADDR, TPTR32):
-		a = ALEAL;
-		break;
-
-	case CASE(OEQ, TBOOL):
-	case CASE(OEQ, TINT8):
-	case CASE(OEQ, TUINT8):
-	case CASE(OEQ, TINT16):
-	case CASE(OEQ, TUINT16):
-	case CASE(OEQ, TINT32):
-	case CASE(OEQ, TUINT32):
-	case CASE(OEQ, TINT64):
-	case CASE(OEQ, TUINT64):
-	case CASE(OEQ, TPTR32):
-	case CASE(OEQ, TPTR64):
-	case CASE(OEQ, TFLOAT32):
-	case CASE(OEQ, TFLOAT64):
-		a = AJEQ;
-		break;
-
-	case CASE(ONE, TBOOL):
-	case CASE(ONE, TINT8):
-	case CASE(ONE, TUINT8):
-	case CASE(ONE, TINT16):
-	case CASE(ONE, TUINT16):
-	case CASE(ONE, TINT32):
-	case CASE(ONE, TUINT32):
-	case CASE(ONE, TINT64):
-	case CASE(ONE, TUINT64):
-	case CASE(ONE, TPTR32):
-	case CASE(ONE, TPTR64):
-	case CASE(ONE, TFLOAT32):
-	case CASE(ONE, TFLOAT64):
-		a = AJNE;
-		break;
-
-	case CASE(OLT, TINT8):
-	case CASE(OLT, TINT16):
-	case CASE(OLT, TINT32):
-	case CASE(OLT, TINT64):
-		a = AJLT;
-		break;
-
-	case CASE(OLT, TUINT8):
-	case CASE(OLT, TUINT16):
-	case CASE(OLT, TUINT32):
-	case CASE(OLT, TUINT64):
-		a = AJCS;
-		break;
-
-	case CASE(OLE, TINT8):
-	case CASE(OLE, TINT16):
-	case CASE(OLE, TINT32):
-	case CASE(OLE, TINT64):
-		a = AJLE;
-		break;
-
-	case CASE(OLE, TUINT8):
-	case CASE(OLE, TUINT16):
-	case CASE(OLE, TUINT32):
-	case CASE(OLE, TUINT64):
-		a = AJLS;
-		break;
-
-	case CASE(OGT, TINT8):
-	case CASE(OGT, TINT16):
-	case CASE(OGT, TINT32):
-	case CASE(OGT, TINT64):
-		a = AJGT;
-		break;
-
-	case CASE(OGT, TUINT8):
-	case CASE(OGT, TUINT16):
-	case CASE(OGT, TUINT32):
-	case CASE(OGT, TUINT64):
-	case CASE(OLT, TFLOAT32):
-	case CASE(OLT, TFLOAT64):
-		a = AJHI;
-		break;
-
-	case CASE(OGE, TINT8):
-	case CASE(OGE, TINT16):
-	case CASE(OGE, TINT32):
-	case CASE(OGE, TINT64):
-		a = AJGE;
-		break;
-
-	case CASE(OGE, TUINT8):
-	case CASE(OGE, TUINT16):
-	case CASE(OGE, TUINT32):
-	case CASE(OGE, TUINT64):
-	case CASE(OLE, TFLOAT32):
-	case CASE(OLE, TFLOAT64):
-		a = AJCC;
-		break;
-
-	case CASE(OCMP, TBOOL):
-	case CASE(OCMP, TINT8):
-	case CASE(OCMP, TUINT8):
-		a = ACMPB;
-		break;
-
-	case CASE(OCMP, TINT16):
-	case CASE(OCMP, TUINT16):
-		a = ACMPW;
-		break;
-
-	case CASE(OCMP, TINT32):
-	case CASE(OCMP, TUINT32):
-	case CASE(OCMP, TPTR32):
-		a = ACMPL;
-		break;
-
-	case CASE(OAS, TBOOL):
-	case CASE(OAS, TINT8):
-	case CASE(OAS, TUINT8):
-		a = AMOVB;
-		break;
-
-	case CASE(OAS, TINT16):
-	case CASE(OAS, TUINT16):
-		a = AMOVW;
-		break;
-
-	case CASE(OAS, TINT32):
-	case CASE(OAS, TUINT32):
-	case CASE(OAS, TPTR32):
-		a = AMOVL;
-		break;
-
-	case CASE(OADD, TINT8):
-	case CASE(OADD, TUINT8):
-		a = AADDB;
-		break;
-
-	case CASE(OADD, TINT16):
-	case CASE(OADD, TUINT16):
-		a = AADDW;
-		break;
-
-	case CASE(OADD, TINT32):
-	case CASE(OADD, TUINT32):
-	case CASE(OADD, TPTR32):
-		a = AADDL;
-		break;
-
-	case CASE(OSUB, TINT8):
-	case CASE(OSUB, TUINT8):
-		a = ASUBB;
-		break;
-
-	case CASE(OSUB, TINT16):
-	case CASE(OSUB, TUINT16):
-		a = ASUBW;
-		break;
-
-	case CASE(OSUB, TINT32):
-	case CASE(OSUB, TUINT32):
-	case CASE(OSUB, TPTR32):
-		a = ASUBL;
-		break;
-
-	case CASE(OINC, TINT8):
-	case CASE(OINC, TUINT8):
-		a = AINCB;
-		break;
-
-	case CASE(OINC, TINT16):
-	case CASE(OINC, TUINT16):
-		a = AINCW;
-		break;
-
-	case CASE(OINC, TINT32):
-	case CASE(OINC, TUINT32):
-	case CASE(OINC, TPTR32):
-		a = AINCL;
-		break;
-
-	case CASE(ODEC, TINT8):
-	case CASE(ODEC, TUINT8):
-		a = ADECB;
-		break;
-
-	case CASE(ODEC, TINT16):
-	case CASE(ODEC, TUINT16):
-		a = ADECW;
-		break;
-
-	case CASE(ODEC, TINT32):
-	case CASE(ODEC, TUINT32):
-	case CASE(ODEC, TPTR32):
-		a = ADECL;
-		break;
-
-	case CASE(OCOM, TINT8):
-	case CASE(OCOM, TUINT8):
-		a = ANOTB;
-		break;
-
-	case CASE(OCOM, TINT16):
-	case CASE(OCOM, TUINT16):
-		a = ANOTW;
-		break;
-
-	case CASE(OCOM, TINT32):
-	case CASE(OCOM, TUINT32):
-	case CASE(OCOM, TPTR32):
-		a = ANOTL;
-		break;
-
-	case CASE(OMINUS, TINT8):
-	case CASE(OMINUS, TUINT8):
-		a = ANEGB;
-		break;
-
-	case CASE(OMINUS, TINT16):
-	case CASE(OMINUS, TUINT16):
-		a = ANEGW;
-		break;
-
-	case CASE(OMINUS, TINT32):
-	case CASE(OMINUS, TUINT32):
-	case CASE(OMINUS, TPTR32):
-		a = ANEGL;
-		break;
-
-	case CASE(OAND, TINT8):
-	case CASE(OAND, TUINT8):
-		a = AANDB;
-		break;
-
-	case CASE(OAND, TINT16):
-	case CASE(OAND, TUINT16):
-		a = AANDW;
-		break;
-
-	case CASE(OAND, TINT32):
-	case CASE(OAND, TUINT32):
-	case CASE(OAND, TPTR32):
-		a = AANDL;
-		break;
-
-	case CASE(OOR, TINT8):
-	case CASE(OOR, TUINT8):
-		a = AORB;
-		break;
-
-	case CASE(OOR, TINT16):
-	case CASE(OOR, TUINT16):
-		a = AORW;
-		break;
-
-	case CASE(OOR, TINT32):
-	case CASE(OOR, TUINT32):
-	case CASE(OOR, TPTR32):
-		a = AORL;
-		break;
-
-	case CASE(OXOR, TINT8):
-	case CASE(OXOR, TUINT8):
-		a = AXORB;
-		break;
-
-	case CASE(OXOR, TINT16):
-	case CASE(OXOR, TUINT16):
-		a = AXORW;
-		break;
-
-	case CASE(OXOR, TINT32):
-	case CASE(OXOR, TUINT32):
-	case CASE(OXOR, TPTR32):
-		a = AXORL;
-		break;
-
-	case CASE(OLROT, TINT8):
-	case CASE(OLROT, TUINT8):
-		a = AROLB;
-		break;
-
-	case CASE(OLROT, TINT16):
-	case CASE(OLROT, TUINT16):
-		a = AROLW;
-		break;
-
-	case CASE(OLROT, TINT32):
-	case CASE(OLROT, TUINT32):
-	case CASE(OLROT, TPTR32):
-		a = AROLL;
-		break;
-
-	case CASE(OLSH, TINT8):
-	case CASE(OLSH, TUINT8):
-		a = ASHLB;
-		break;
-
-	case CASE(OLSH, TINT16):
-	case CASE(OLSH, TUINT16):
-		a = ASHLW;
-		break;
-
-	case CASE(OLSH, TINT32):
-	case CASE(OLSH, TUINT32):
-	case CASE(OLSH, TPTR32):
-		a = ASHLL;
-		break;
-
-	case CASE(ORSH, TUINT8):
-		a = ASHRB;
-		break;
-
-	case CASE(ORSH, TUINT16):
-		a = ASHRW;
-		break;
-
-	case CASE(ORSH, TUINT32):
-	case CASE(ORSH, TPTR32):
-		a = ASHRL;
-		break;
-
-	case CASE(ORSH, TINT8):
-		a = ASARB;
-		break;
-
-	case CASE(ORSH, TINT16):
-		a = ASARW;
-		break;
-
-	case CASE(ORSH, TINT32):
-		a = ASARL;
-		break;
-
-	case CASE(OHMUL, TINT8):
-	case CASE(OMUL, TINT8):
-	case CASE(OMUL, TUINT8):
-		a = AIMULB;
-		break;
-
-	case CASE(OHMUL, TINT16):
-	case CASE(OMUL, TINT16):
-	case CASE(OMUL, TUINT16):
-		a = AIMULW;
-		break;
-
-	case CASE(OHMUL, TINT32):
-	case CASE(OMUL, TINT32):
-	case CASE(OMUL, TUINT32):
-	case CASE(OMUL, TPTR32):
-		a = AIMULL;
-		break;
-
-	case CASE(OHMUL, TUINT8):
-		a = AMULB;
-		break;
-
-	case CASE(OHMUL, TUINT16):
-		a = AMULW;
-		break;
-
-	case CASE(OHMUL, TUINT32):
-	case CASE(OHMUL, TPTR32):
-		a = AMULL;
-		break;
-
-	case CASE(ODIV, TINT8):
-	case CASE(OMOD, TINT8):
-		a = AIDIVB;
-		break;
-
-	case CASE(ODIV, TUINT8):
-	case CASE(OMOD, TUINT8):
-		a = ADIVB;
-		break;
-
-	case CASE(ODIV, TINT16):
-	case CASE(OMOD, TINT16):
-		a = AIDIVW;
-		break;
-
-	case CASE(ODIV, TUINT16):
-	case CASE(OMOD, TUINT16):
-		a = ADIVW;
-		break;
-
-	case CASE(ODIV, TINT32):
-	case CASE(OMOD, TINT32):
-		a = AIDIVL;
-		break;
-
-	case CASE(ODIV, TUINT32):
-	case CASE(ODIV, TPTR32):
-	case CASE(OMOD, TUINT32):
-	case CASE(OMOD, TPTR32):
-		a = ADIVL;
-		break;
-
-	case CASE(OEXTEND, TINT16):
-		a = ACWD;
-		break;
-
-	case CASE(OEXTEND, TINT32):
-		a = ACDQ;
-		break;
-	}
-	return a;
-}
-
-#define FCASE(a, b, c)  (((a)<<16)|((b)<<8)|(c))
-/*c2go int FCASE(int, int, int); */
-int
-foptoas(int op, Type *t, int flg)
-{
-	int et, a;
-
-	a = AGOK;
-	et = simtype[t->etype];
-
-	if(use_sse)
-		goto sse;
-
-	// If we need Fpop, it means we're working on
-	// two different floating-point registers, not memory.
-	// There the instruction only has a float64 form.
-	if(flg & Fpop)
-		et = TFLOAT64;
-
-	// clear Frev if unneeded
-	switch(op) {
-	case OADD:
-	case OMUL:
-		flg &= ~Frev;
-		break;
-	}
-
-	switch(FCASE(op, et, flg)) {
-	case FCASE(OADD, TFLOAT32, 0):
-		return AFADDF;
-	case FCASE(OADD, TFLOAT64, 0):
-		return AFADDD;
-	case FCASE(OADD, TFLOAT64, Fpop):
-		return AFADDDP;
-
-	case FCASE(OSUB, TFLOAT32, 0):
-		return AFSUBF;
-	case FCASE(OSUB, TFLOAT32, Frev):
-		return AFSUBRF;
-
-	case FCASE(OSUB, TFLOAT64, 0):
-		return AFSUBD;
-	case FCASE(OSUB, TFLOAT64, Frev):
-		return AFSUBRD;
-	case FCASE(OSUB, TFLOAT64, Fpop):
-		return AFSUBDP;
-	case FCASE(OSUB, TFLOAT64, Fpop|Frev):
-		return AFSUBRDP;
-
-	case FCASE(OMUL, TFLOAT32, 0):
-		return AFMULF;
-	case FCASE(OMUL, TFLOAT64, 0):
-		return AFMULD;
-	case FCASE(OMUL, TFLOAT64, Fpop):
-		return AFMULDP;
-
-	case FCASE(ODIV, TFLOAT32, 0):
-		return AFDIVF;
-	case FCASE(ODIV, TFLOAT32, Frev):
-		return AFDIVRF;
-
-	case FCASE(ODIV, TFLOAT64, 0):
-		return AFDIVD;
-	case FCASE(ODIV, TFLOAT64, Frev):
-		return AFDIVRD;
-	case FCASE(ODIV, TFLOAT64, Fpop):
-		return AFDIVDP;
-	case FCASE(ODIV, TFLOAT64, Fpop|Frev):
-		return AFDIVRDP;
-
-	case FCASE(OCMP, TFLOAT32, 0):
-		return AFCOMF;
-	case FCASE(OCMP, TFLOAT32, Fpop):
-		return AFCOMFP;
-	case FCASE(OCMP, TFLOAT64, 0):
-		return AFCOMD;
-	case FCASE(OCMP, TFLOAT64, Fpop):
-		return AFCOMDP;
-	case FCASE(OCMP, TFLOAT64, Fpop2):
-		return AFCOMDPP;
-	
-	case FCASE(OMINUS, TFLOAT32, 0):
-		return AFCHS;
-	case FCASE(OMINUS, TFLOAT64, 0):
-		return AFCHS;
-	}
-
-	fatal("foptoas %O %T %#x", op, t, flg);
-	return 0;
-
-sse:
-	switch(CASE(op, et)) {
-	default:
-		fatal("foptoas-sse: no entry %O-%T", op, t);
-		break;
-
-	case CASE(OCMP, TFLOAT32):
-		a = AUCOMISS;
-		break;
-
-	case CASE(OCMP, TFLOAT64):
-		a = AUCOMISD;
-		break;
-
-	case CASE(OAS, TFLOAT32):
-		a = AMOVSS;
-		break;
-
-	case CASE(OAS, TFLOAT64):
-		a = AMOVSD;
-		break;
-
-	case CASE(OADD, TFLOAT32):
-		a = AADDSS;
-		break;
-
-	case CASE(OADD, TFLOAT64):
-		a = AADDSD;
-		break;
-
-	case CASE(OSUB, TFLOAT32):
-		a = ASUBSS;
-		break;
-
-	case CASE(OSUB, TFLOAT64):
-		a = ASUBSD;
-		break;
-
-	case CASE(OMUL, TFLOAT32):
-		a = AMULSS;
-		break;
-
-	case CASE(OMUL, TFLOAT64):
-		a = AMULSD;
-		break;
-
-	case CASE(ODIV, TFLOAT32):
-		a = ADIVSS;
-		break;
-
-	case CASE(ODIV, TFLOAT64):
-		a = ADIVSD;
-		break;
-	}
-	return a;
-}
-
-
-static	int	resvd[] =
-{
-//	D_DI,	// for movstring
-//	D_SI,	// for movstring
-
-	D_AX,	// for divide
-	D_CX,	// for shift
-	D_DX,	// for divide
-	D_SP,	// for stack
-
-	D_BL,	// because D_BX can be allocated
-	D_BH,
-};
-
-void
-ginit(void)
-{
-	int i;
-
-	for(i=0; i<nelem(reg); i++)
-		reg[i] = 1;
-	for(i=D_AX; i<=D_DI; i++)
-		reg[i] = 0;
-	for(i=D_X0; i<=D_X7; i++)
-		reg[i] = 0;
-	for(i=0; i<nelem(resvd); i++)
-		reg[resvd[i]]++;
-}
-
-uintptr regpc[D_NONE];
-
-void
-gclean(void)
-{
-	int i;
-
-	for(i=0; i<nelem(resvd); i++)
-		reg[resvd[i]]--;
-
-	for(i=D_AX; i<=D_DI; i++)
-		if(reg[i])
-			yyerror("reg %R left allocated at %ux", i, regpc[i]);
-	for(i=D_X0; i<=D_X7; i++)
-		if(reg[i])
-			yyerror("reg %R left allocated\n", i);
-}
-
-int32
-anyregalloc(void)
-{
-	int i, j;
-
-	for(i=D_AX; i<=D_DI; i++) {
-		if(reg[i] == 0)
-			goto ok;
-		for(j=0; j<nelem(resvd); j++)
-			if(resvd[j] == i)
-				goto ok;
-		return 1;
-	ok:;
-	}
-	for(i=D_X0; i<=D_X7; i++)
-		if(reg[i])
-			return 1;
-	return 0;
-}
-
-/*
- * allocate register of type t, leave in n.
- * if o != N, o is desired fixed register.
- * caller must regfree(n).
- */
-void
-regalloc(Node *n, Type *t, Node *o)
-{
-	int i, et;
-
-	if(t == T)
-		fatal("regalloc: t nil");
-	et = simtype[t->etype];
-
-	switch(et) {
-	case TINT64:
-	case TUINT64:
-		fatal("regalloc64");
-
-	case TINT8:
-	case TUINT8:
-	case TINT16:
-	case TUINT16:
-	case TINT32:
-	case TUINT32:
-	case TPTR32:
-	case TPTR64:
-	case TBOOL:
-		if(o != N && o->op == OREGISTER) {
-			i = o->val.u.reg;
-			if(i >= D_AX && i <= D_DI)
-				goto out;
-		}
-		for(i=D_AX; i<=D_DI; i++)
-			if(reg[i] == 0)
-				goto out;
-
-		fprint(2, "registers allocated at\n");
-		for(i=D_AX; i<=D_DI; i++)
-			fprint(2, "\t%R\t%#lux\n", i, regpc[i]);
-		fatal("out of fixed registers");
-		goto err;
-
-	case TFLOAT32:
-	case TFLOAT64:
-		if(!use_sse) {
-			i = D_F0;
-			goto out;
-		}
-		if(o != N && o->op == OREGISTER) {
-			i = o->val.u.reg;
-			if(i >= D_X0 && i <= D_X7)
-				goto out;
-		}
-		for(i=D_X0; i<=D_X7; i++)
-			if(reg[i] == 0)
-				goto out;
-		fprint(2, "registers allocated at\n");
-		for(i=D_X0; i<=D_X7; i++)
-			fprint(2, "\t%R\t%#lux\n", i, regpc[i]);
-		fatal("out of floating registers");
-	}
-	yyerror("regalloc: unknown type %T", t);
-
-err:
-	nodreg(n, t, 0);
-	return;
-
-out:
-	if (i == D_SP)
-		print("alloc SP\n");
-	if(reg[i] == 0) {
-		regpc[i] = (uintptr)getcallerpc(&n);
-		if(i == D_AX || i == D_CX || i == D_DX || i == D_SP) {
-			dump("regalloc-o", o);
-			fatal("regalloc %R", i);
-		}
-	}
-	reg[i]++;
-	nodreg(n, t, i);
-}
-
-void
-regfree(Node *n)
-{
-	int i;
-	
-	if(n->op == ONAME)
-		return;
-	if(n->op != OREGISTER && n->op != OINDREG)
-		fatal("regfree: not a register");
-	i = n->val.u.reg;
-	if(i == D_SP)
-		return;
-	if(i < 0 || i >= nelem(reg))
-		fatal("regfree: reg out of range");
-	if(reg[i] <= 0)
-		fatal("regfree: reg not allocated");
-	reg[i]--;
-	if(reg[i] == 0 && (i == D_AX || i == D_CX || i == D_DX || i == D_SP))
-		fatal("regfree %R", i);
-}
-
-/*
- * initialize n to be register r of type t.
- */
-void
-nodreg(Node *n, Type *t, int r)
-{
-	if(t == T)
-		fatal("nodreg: t nil");
-
-	memset(n, 0, sizeof(*n));
-	n->op = OREGISTER;
-	n->addable = 1;
-	ullmancalc(n);
-	n->val.u.reg = r;
-	n->type = t;
-}
-
-/*
- * initialize n to be indirect of register r; n is type t.
- */
-void
-nodindreg(Node *n, Type *t, int r)
-{
-	nodreg(n, t, r);
-	n->op = OINDREG;
-}
-
-Node*
-nodarg(Type *t, int fp)
-{
-	Node *n;
-	NodeList *l;
-	Type *first;
-	Iter savet;
-
-	// entire argument struct, not just one arg
-	switch(t->etype) {
-	default:
-		fatal("nodarg %T", t);
-
-	case TSTRUCT:
-		if(!t->funarg)
-			fatal("nodarg: TSTRUCT but not funarg");
-		n = nod(ONAME, N, N);
-		n->sym = lookup(".args");
-		n->type = t;
-		first = structfirst(&savet, &t);
-		if(first == nil)
-			fatal("nodarg: bad struct");
-		if(first->width == BADWIDTH)
-			fatal("nodarg: offset not computed for %T", t);
-		n->xoffset = first->width;
-		n->addable = 1;
-		break;
-
-	case TFIELD:
-		if(fp == 1 && t->sym != S && !isblanksym(t->sym)) {
-			for(l=curfn->dcl; l; l=l->next) {
-				n = l->n;
-				if((n->class == PPARAM || n->class == PPARAMOUT) && n->sym == t->sym)
-					return n;
-			}
-		}
-
-		n = nod(ONAME, N, N);
-		n->type = t->type;
-		n->sym = t->sym;
-		if(t->width == BADWIDTH)
-			fatal("nodarg: offset not computed for %T", t);
-		n->xoffset = t->width;
-		n->addable = 1;
-		n->orig = t->nname;
-		break;
-	}
-	
-	// Rewrite argument named _ to __,
-	// or else the assignment to _ will be
-	// discarded during code generation.
-	if(isblank(n))
-		n->sym = lookup("__");
-
-	switch(fp) {
-	default:
-		fatal("nodarg %T %d", t, fp);
-
-	case 0:		// output arg
-		n->op = OINDREG;
-		n->val.u.reg = D_SP;
-		break;
-
-	case 1:		// input arg
-		n->class = PPARAM;
-		break;
-	}
-
-	n->typecheck = 1;
-	return n;
-}
-
-/*
- * generate
- *	as $c, reg
- */
-void
-gconreg(int as, vlong c, int reg)
-{
-	Node n1, n2;
-
-	nodconst(&n1, types[TINT64], c);
-	nodreg(&n2, types[TINT64], reg);
-	gins(as, &n1, &n2);
-}
-
-/*
- * swap node contents
- */
-void
-nswap(Node *a, Node *b)
-{
-	Node t;
-
-	t = *a;
-	*a = *b;
-	*b = t;
-}
-
-/*
- * return constant i node.
- * overwritten by next call, but useful in calls to gins.
- */
-Node*
-ncon(uint32 i)
-{
-	static Node n;
-
-	if(n.type == T)
-		nodconst(&n, types[TUINT32], 0);
-	mpmovecfix(n.val.u.xval, i);
-	return &n;
-}
-
-/*
- * Is this node a memory operand?
- */
-int
-ismem(Node *n)
-{
-	switch(n->op) {
-	case OITAB:
-	case OSPTR:
-	case OLEN:
-	case OCAP:
-	case OINDREG:
-	case ONAME:
-	case OPARAM:
-	case OCLOSUREVAR:
-		return 1;
-	}
-	return 0;
-}
-
-Node sclean[10];
-int nsclean;
-
-/*
- * n is a 64-bit value.  fill in lo and hi to refer to its 32-bit halves.
- */
-void
-split64(Node *n, Node *lo, Node *hi)
-{
-	Node n1;
-	int64 i;
-
-	if(!is64(n->type))
-		fatal("split64 %T", n->type);
-
-	if(nsclean >= nelem(sclean))
-		fatal("split64 clean");
-	sclean[nsclean].op = OEMPTY;
-	nsclean++;
-	switch(n->op) {
-	default:
-		if(!dotaddable(n, &n1)) {
-			igen(n, &n1, N);
-			sclean[nsclean-1] = n1;
-		}
-		n = &n1;
-		goto common;
-	case ONAME:
-		if(n->class == PPARAMREF) {
-			cgen(n->heapaddr, &n1);
-			sclean[nsclean-1] = n1;
-			// fall through.
-			n = &n1;
-		}
-		goto common;
-	case OINDREG:
-	common:
-		*lo = *n;
-		*hi = *n;
-		lo->type = types[TUINT32];
-		if(n->type->etype == TINT64)
-			hi->type = types[TINT32];
-		else
-			hi->type = types[TUINT32];
-		hi->xoffset += 4;
-		break;
-
-	case OLITERAL:
-		convconst(&n1, n->type, &n->val);
-		i = mpgetfix(n1.val.u.xval);
-		nodconst(lo, types[TUINT32], (uint32)i);
-		i >>= 32;
-		if(n->type->etype == TINT64)
-			nodconst(hi, types[TINT32], (int32)i);
-		else
-			nodconst(hi, types[TUINT32], (uint32)i);
-		break;
-	}
-}
-
-void
-splitclean(void)
-{
-	if(nsclean <= 0)
-		fatal("splitclean");
-	nsclean--;
-	if(sclean[nsclean].op != OEMPTY)
-		regfree(&sclean[nsclean]);
-}
-
-/*
- * set up nodes representing fp constants
- */
-Node zerof;
-Node two64f;
-Node two63f;
-
-void
-bignodes(void)
-{
-	static int did;
-
-	if(did)
-		return;
-	did = 1;
-
-	two64f = *ncon(0);
-	two64f.type = types[TFLOAT64];
-	two64f.val.ctype = CTFLT;
-	two64f.val.u.fval = mal(sizeof *two64f.val.u.fval);
-	mpmovecflt(two64f.val.u.fval, 18446744073709551616.);
-
-	two63f = two64f;
-	two63f.val.u.fval = mal(sizeof *two63f.val.u.fval);
-	mpmovecflt(two63f.val.u.fval, 9223372036854775808.);
-
-	zerof = two64f;
-	zerof.val.u.fval = mal(sizeof *zerof.val.u.fval);
-	mpmovecflt(zerof.val.u.fval, 0);
-}
-
-void
-memname(Node *n, Type *t)
-{
-	tempname(n, t);
-	strcpy(namebuf, n->sym->name);
-	namebuf[0] = '.';	// keep optimizer from registerizing
-	n->sym = lookup(namebuf);
-	n->orig->sym = n->sym;
-}
-
-static void floatmove(Node *f, Node *t);
-static void floatmove_387(Node *f, Node *t);
-static void floatmove_sse(Node *f, Node *t);
-
-void
-gmove(Node *f, Node *t)
-{
-	int a, ft, tt;
-	Type *cvt;
-	Node r1, r2, flo, fhi, tlo, thi, con;
-
-	if(debug['M'])
-		print("gmove %N -> %N\n", f, t);
-
-	ft = simsimtype(f->type);
-	tt = simsimtype(t->type);
-	cvt = t->type;
-	
-	if(iscomplex[ft] || iscomplex[tt]) {
-		complexmove(f, t);
-		return;
-	}
-	if(isfloat[ft] || isfloat[tt]) {
-		floatmove(f, t);
-		return;
-	}
-
-	// cannot have two integer memory operands;
-	// except 64-bit, which always copies via registers anyway.
-	if(isint[ft] && isint[tt] && !is64(f->type) && !is64(t->type) && ismem(f) && ismem(t))
-		goto hard;
-
-	// convert constant to desired type
-	if(f->op == OLITERAL) {
-		convconst(&con, t->type, &f->val);
-		f = &con;
-		ft = simsimtype(con.type);
-	}
-
-	// 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(CASE(ft, tt)) {
-	default:
-		goto fatal;
-
-	/*
-	 * integer copy and truncate
-	 */
-	case CASE(TINT8, TINT8):	// same size
-	case CASE(TINT8, TUINT8):
-	case CASE(TUINT8, TINT8):
-	case CASE(TUINT8, TUINT8):
-		a = AMOVB;
-		break;
-
-	case CASE(TINT16, TINT8):	// truncate
-	case CASE(TUINT16, TINT8):
-	case CASE(TINT32, TINT8):
-	case CASE(TUINT32, TINT8):
-	case CASE(TINT16, TUINT8):
-	case CASE(TUINT16, TUINT8):
-	case CASE(TINT32, TUINT8):
-	case CASE(TUINT32, TUINT8):
-		a = AMOVB;
-		goto rsrc;
-
-	case CASE(TINT64, TINT8):	// truncate low word
-	case CASE(TUINT64, TINT8):
-	case CASE(TINT64, TUINT8):
-	case CASE(TUINT64, TUINT8):
-		split64(f, &flo, &fhi);
-		nodreg(&r1, t->type, D_AX);
-		gmove(&flo, &r1);
-		gins(AMOVB, &r1, t);
-		splitclean();
-		return;
-
-	case CASE(TINT16, TINT16):	// same size
-	case CASE(TINT16, TUINT16):
-	case CASE(TUINT16, TINT16):
-	case CASE(TUINT16, TUINT16):
-		a = AMOVW;
-		break;
-
-	case CASE(TINT32, TINT16):	// truncate
-	case CASE(TUINT32, TINT16):
-	case CASE(TINT32, TUINT16):
-	case CASE(TUINT32, TUINT16):
-		a = AMOVW;
-		goto rsrc;
-
-	case CASE(TINT64, TINT16):	// truncate low word
-	case CASE(TUINT64, TINT16):
-	case CASE(TINT64, TUINT16):
-	case CASE(TUINT64, TUINT16):
-		split64(f, &flo, &fhi);
-		nodreg(&r1, t->type, D_AX);
-		gmove(&flo, &r1);
-		gins(AMOVW, &r1, t);
-		splitclean();
-		return;
-
-	case CASE(TINT32, TINT32):	// same size
-	case CASE(TINT32, TUINT32):
-	case CASE(TUINT32, TINT32):
-	case CASE(TUINT32, TUINT32):
-		a = AMOVL;
-		break;
-
-	case CASE(TINT64, TINT32):	// truncate
-	case CASE(TUINT64, TINT32):
-	case CASE(TINT64, TUINT32):
-	case CASE(TUINT64, TUINT32):
-		split64(f, &flo, &fhi);
-		nodreg(&r1, t->type, D_AX);
-		gmove(&flo, &r1);
-		gins(AMOVL, &r1, t);
-		splitclean();
-		return;
-
-	case CASE(TINT64, TINT64):	// same size
-	case CASE(TINT64, TUINT64):
-	case CASE(TUINT64, TINT64):
-	case CASE(TUINT64, TUINT64):
-		split64(f, &flo, &fhi);
-		split64(t, &tlo, &thi);
-		if(f->op == OLITERAL) {
-			gins(AMOVL, &flo, &tlo);
-			gins(AMOVL, &fhi, &thi);
-		} else {
-			nodreg(&r1, t->type, D_AX);
-			nodreg(&r2, t->type, D_DX);
-			gins(AMOVL, &flo, &r1);
-			gins(AMOVL, &fhi, &r2);
-			gins(AMOVL, &r1, &tlo);
-			gins(AMOVL, &r2, &thi);
-		}
-		splitclean();
-		splitclean();
-		return;
-
-	/*
-	 * integer up-conversions
-	 */
-	case CASE(TINT8, TINT16):	// sign extend int8
-	case CASE(TINT8, TUINT16):
-		a = AMOVBWSX;
-		goto rdst;
-	case CASE(TINT8, TINT32):
-	case CASE(TINT8, TUINT32):
-		a = AMOVBLSX;
-		goto rdst;
-	case CASE(TINT8, TINT64):	// convert via int32
-	case CASE(TINT8, TUINT64):
-		cvt = types[TINT32];
-		goto hard;
-
-	case CASE(TUINT8, TINT16):	// zero extend uint8
-	case CASE(TUINT8, TUINT16):
-		a = AMOVBWZX;
-		goto rdst;
-	case CASE(TUINT8, TINT32):
-	case CASE(TUINT8, TUINT32):
-		a = AMOVBLZX;
-		goto rdst;
-	case CASE(TUINT8, TINT64):	// convert via uint32
-	case CASE(TUINT8, TUINT64):
-		cvt = types[TUINT32];
-		goto hard;
-
-	case CASE(TINT16, TINT32):	// sign extend int16
-	case CASE(TINT16, TUINT32):
-		a = AMOVWLSX;
-		goto rdst;
-	case CASE(TINT16, TINT64):	// convert via int32
-	case CASE(TINT16, TUINT64):
-		cvt = types[TINT32];
-		goto hard;
-
-	case CASE(TUINT16, TINT32):	// zero extend uint16
-	case CASE(TUINT16, TUINT32):
-		a = AMOVWLZX;
-		goto rdst;
-	case CASE(TUINT16, TINT64):	// convert via uint32
-	case CASE(TUINT16, TUINT64):
-		cvt = types[TUINT32];
-		goto hard;
-
-	case CASE(TINT32, TINT64):	// sign extend int32
-	case CASE(TINT32, TUINT64):
-		split64(t, &tlo, &thi);
-		nodreg(&flo, tlo.type, D_AX);
-		nodreg(&fhi, thi.type, D_DX);
-		gmove(f, &flo);
-		gins(ACDQ, N, N);
-		gins(AMOVL, &flo, &tlo);
-		gins(AMOVL, &fhi, &thi);
-		splitclean();
-		return;
-
-	case CASE(TUINT32, TINT64):	// zero extend uint32
-	case CASE(TUINT32, TUINT64):
-		split64(t, &tlo, &thi);
-		gmove(f, &tlo);
-		gins(AMOVL, ncon(0), &thi);
-		splitclean();
-		return;
-	}
-
-	gins(a, f, t);
-	return;
-
-rsrc:
-	// requires register source
-	regalloc(&r1, f->type, t);
-	gmove(f, &r1);
-	gins(a, &r1, t);
-	regfree(&r1);
-	return;
-
-rdst:
-	// requires register destination
-	regalloc(&r1, t->type, t);
-	gins(a, f, &r1);
-	gmove(&r1, t);
-	regfree(&r1);
-	return;
-
-hard:
-	// requires register intermediate
-	regalloc(&r1, cvt, t);
-	gmove(f, &r1);
-	gmove(&r1, t);
-	regfree(&r1);
-	return;
-
-fatal:
-	// should not happen
-	fatal("gmove %N -> %N", f, t);
-}
-
-static void
-floatmove(Node *f, Node *t)
-{
-	Node r1, r2, t1, t2, tlo, thi, con, f0, f1, ax, dx, cx;
-	Type *cvt;
-	int ft, tt;
-	Prog *p1, *p2, *p3;
-
-	ft = simsimtype(f->type);
-	tt = simsimtype(t->type);
-	cvt = t->type;
-
-	// cannot have two floating point memory operands.
-	if(isfloat[ft] && isfloat[tt] && ismem(f) && ismem(t))
-		goto hard;
-
-	// convert constant to desired type
-	if(f->op == OLITERAL) {
-		convconst(&con, t->type, &f->val);
-		f = &con;
-		ft = simsimtype(con.type);
-
-		// some constants can't move directly to memory.
-		if(ismem(t)) {
-			// float constants come from memory.
-			if(isfloat[tt])
-				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(CASE(ft, tt)) {
-	default:
-		if(use_sse)
-			floatmove_sse(f, t);
-		else
-			floatmove_387(f, t);
-		return;
-
-	// float to very long integer.
-	case CASE(TFLOAT32, TINT64):
-	case CASE(TFLOAT64, TINT64):
-		if(f->op == OREGISTER) {
-			cvt = f->type;
-			goto hardmem;
-		}
-		nodreg(&r1, types[ft], D_F0);
-		if(ft == TFLOAT32)
-			gins(AFMOVF, f, &r1);
-		else
-			gins(AFMOVD, f, &r1);
-
-		// set round to zero mode during conversion
-		memname(&t1, types[TUINT16]);
-		memname(&t2, types[TUINT16]);
-		gins(AFSTCW, N, &t1);
-		gins(AMOVW, ncon(0xf7f), &t2);
-		gins(AFLDCW, &t2, N);
-		if(tt == TINT16)
-			gins(AFMOVWP, &r1, t);
-		else if(tt == TINT32)
-			gins(AFMOVLP, &r1, t);
-		else
-			gins(AFMOVVP, &r1, t);
-		gins(AFLDCW, &t1, N);
-		return;
-
-	case CASE(TFLOAT32, TUINT64):
-	case CASE(TFLOAT64, TUINT64):
-		if(!ismem(f)) {
-			cvt = f->type;
-			goto hardmem;
-		}
-		bignodes();
-		nodreg(&f0, types[ft], D_F0);
-		nodreg(&f1, types[ft], D_F0 + 1);
-		nodreg(&ax, types[TUINT16], D_AX);
-
-		if(ft == TFLOAT32)
-			gins(AFMOVF, f, &f0);
-		else
-			gins(AFMOVD, f, &f0);
-
-		// if 0 > v { answer = 0 }
-		gins(AFMOVD, &zerof, &f0);
-		gins(AFUCOMIP, &f0, &f1);
-		p1 = gbranch(optoas(OGT, types[tt]), T, 0);
-		// if 1<<64 <= v { answer = 0 too }
-		gins(AFMOVD, &two64f, &f0);
-		gins(AFUCOMIP, &f0, &f1);
-		p2 = gbranch(optoas(OGT, types[tt]), T, 0);
-		patch(p1, pc);
-		gins(AFMOVVP, &f0, t);	// don't care about t, but will pop the stack
-		split64(t, &tlo, &thi);
-		gins(AMOVL, ncon(0), &tlo);
-		gins(AMOVL, ncon(0), &thi);
-		splitclean();
-		p1 = gbranch(AJMP, T, 0);
-		patch(p2, pc);
-
-		// in range; algorithm is:
-		//	if small enough, use native float64 -> int64 conversion.
-		//	otherwise, subtract 2^63, convert, and add it back.
-
-		// set round to zero mode during conversion
-		memname(&t1, types[TUINT16]);
-		memname(&t2, types[TUINT16]);
-		gins(AFSTCW, N, &t1);
-		gins(AMOVW, ncon(0xf7f), &t2);
-		gins(AFLDCW, &t2, N);
-
-		// actual work
-		gins(AFMOVD, &two63f, &f0);
-		gins(AFUCOMIP, &f0, &f1);
-		p2 = gbranch(optoas(OLE, types[tt]), T, 0);
-		gins(AFMOVVP, &f0, t);
-		p3 = gbranch(AJMP, T, 0);
-		patch(p2, pc);
-		gins(AFMOVD, &two63f, &f0);
-		gins(AFSUBDP, &f0, &f1);
-		gins(AFMOVVP, &f0, t);
-		split64(t, &tlo, &thi);
-		gins(AXORL, ncon(0x80000000), &thi);	// + 2^63
-		patch(p3, pc);
-		splitclean();
-		// restore rounding mode
-		gins(AFLDCW, &t1, N);
-
-		patch(p1, pc);
-		return;
-
-	/*
-	 * integer to float
-	 */
-	case CASE(TINT64, TFLOAT32):
-	case CASE(TINT64, TFLOAT64):
-		if(t->op == OREGISTER)
-			goto hardmem;
-		nodreg(&f0, t->type, D_F0);
-		gins(AFMOVV, f, &f0);
-		if(tt == TFLOAT32)
-			gins(AFMOVFP, &f0, t);
-		else
-			gins(AFMOVDP, &f0, t);
-		return;
-
-	case CASE(TUINT64, TFLOAT32):
-	case CASE(TUINT64, TFLOAT64):
-		// algorithm is:
-		//	if small enough, use native int64 -> float64 conversion.
-		//	otherwise, halve (rounding to odd?), convert, and double.
-		nodreg(&ax, types[TUINT32], D_AX);
-		nodreg(&dx, types[TUINT32], D_DX);
-		nodreg(&cx, types[TUINT32], D_CX);
-		tempname(&t1, f->type);
-		split64(&t1, &tlo, &thi);
-		gmove(f, &t1);
-		gins(ACMPL, &thi, ncon(0));
-		p1 = gbranch(AJLT, T, 0);
-		// native
-		nodreg(&r1, types[tt], D_F0);
-		gins(AFMOVV, &t1, &r1);
-		if(tt == TFLOAT32)
-			gins(AFMOVFP, &r1, t);
-		else
-			gins(AFMOVDP, &r1, t);
-		p2 = gbranch(AJMP, T, 0);
-		// simulated
-		patch(p1, pc);
-		gmove(&tlo, &ax);
-		gmove(&thi, &dx);
-		p1 = gins(ASHRL, ncon(1), &ax);
-		p1->from.index = D_DX;	// double-width shift DX -> AX
-		p1->from.scale = 0;
-		gins(AMOVL, ncon(0), &cx);
-		gins(ASETCC, N, &cx);
-		gins(AORL, &cx, &ax);
-		gins(ASHRL, ncon(1), &dx);
-		gmove(&dx, &thi);
-		gmove(&ax, &tlo);
-		nodreg(&r1, types[tt], D_F0);
-		nodreg(&r2, types[tt], D_F0 + 1);
-		gins(AFMOVV, &t1, &r1);
-		gins(AFMOVD, &r1, &r1);
-		gins(AFADDDP, &r1, &r2);
-		if(tt == TFLOAT32)
-			gins(AFMOVFP, &r1, t);
-		else
-			gins(AFMOVDP, &r1, t);
-		patch(p2, pc);
-		splitclean();
-		return;
-	}
-
-hard:
-	// requires register intermediate
-	regalloc(&r1, cvt, t);
-	gmove(f, &r1);
-	gmove(&r1, t);
-	regfree(&r1);
-	return;
-
-hardmem:
-	// requires memory intermediate
-	tempname(&r1, cvt);
-	gmove(f, &r1);
-	gmove(&r1, t);
-	return;
-}
-
-static void
-floatmove_387(Node *f, Node *t)
-{
-	Node r1, t1, t2;
-	Type *cvt;
-	Prog *p1, *p2, *p3;
-	int a, ft, tt;
-
-	ft = simsimtype(f->type);
-	tt = simsimtype(t->type);
-	cvt = t->type;
-
-	switch(CASE(ft, tt)) {
-	default:
-		goto fatal;
-
-	/*
-	* float to integer
-	*/
-	case CASE(TFLOAT32, TINT16):
-	case CASE(TFLOAT32, TINT32):
-	case CASE(TFLOAT32, TINT64):
-	case CASE(TFLOAT64, TINT16):
-	case CASE(TFLOAT64, TINT32):
-	case CASE(TFLOAT64, TINT64):
-		if(t->op == OREGISTER)
-			goto hardmem;
-		nodreg(&r1, types[ft], D_F0);
-		if(f->op != OREGISTER) {
-			if(ft == TFLOAT32)
-				gins(AFMOVF, f, &r1);
-			else
-				gins(AFMOVD, f, &r1);
-		}
-
-		// set round to zero mode during conversion
-		memname(&t1, types[TUINT16]);
-		memname(&t2, types[TUINT16]);
-		gins(AFSTCW, N, &t1);
-		gins(AMOVW, ncon(0xf7f), &t2);
-		gins(AFLDCW, &t2, N);
-		if(tt == TINT16)
-			gins(AFMOVWP, &r1, t);
-		else if(tt == TINT32)
-			gins(AFMOVLP, &r1, t);
-		else
-			gins(AFMOVVP, &r1, t);
-		gins(AFLDCW, &t1, N);
-		return;
-
-	case CASE(TFLOAT32, TINT8):
-	case CASE(TFLOAT32, TUINT16):
-	case CASE(TFLOAT32, TUINT8):
-	case CASE(TFLOAT64, TINT8):
-	case CASE(TFLOAT64, TUINT16):
-	case CASE(TFLOAT64, TUINT8):
-		// convert via int32.
-		tempname(&t1, types[TINT32]);
-		gmove(f, &t1);
-		switch(tt) {
-		default:
-			fatal("gmove %T", t);
-		case TINT8:
-			gins(ACMPL, &t1, ncon(-0x80));
-			p1 = gbranch(optoas(OLT, types[TINT32]), T, -1);
-			gins(ACMPL, &t1, ncon(0x7f));
-			p2 = gbranch(optoas(OGT, types[TINT32]), T, -1);
-			p3 = gbranch(AJMP, T, 0);
-			patch(p1, pc);
-			patch(p2, pc);
-			gmove(ncon(-0x80), &t1);
-			patch(p3, pc);
-			gmove(&t1, t);
-			break;
-		case TUINT8:
-			gins(ATESTL, ncon(0xffffff00), &t1);
-			p1 = gbranch(AJEQ, T, +1);
-			gins(AMOVL, ncon(0), &t1);
-			patch(p1, pc);
-			gmove(&t1, t);
-			break;
-		case TUINT16:
-			gins(ATESTL, ncon(0xffff0000), &t1);
-			p1 = gbranch(AJEQ, T, +1);
-			gins(AMOVL, ncon(0), &t1);
-			patch(p1, pc);
-			gmove(&t1, t);
-			break;
-		}
-		return;
-
-	case CASE(TFLOAT32, TUINT32):
-	case CASE(TFLOAT64, TUINT32):
-		// convert via int64.
-		cvt = types[TINT64];
-		goto hardmem;
-
-	/*
-	 * integer to float
-	 */
-	case CASE(TINT16, TFLOAT32):
-	case CASE(TINT16, TFLOAT64):
-	case CASE(TINT32, TFLOAT32):
-	case CASE(TINT32, TFLOAT64):
-	case CASE(TINT64, TFLOAT32):
-	case CASE(TINT64, TFLOAT64):
-		if(t->op != OREGISTER)
-			goto hard;
-		if(f->op == OREGISTER) {
-			cvt = f->type;
-			goto hardmem;
-		}
-		switch(ft) {
-		case TINT16:
-			a = AFMOVW;
-			break;
-		case TINT32:
-			a = AFMOVL;
-			break;
-		default:
-			a = AFMOVV;
-			break;
-		}
-		break;
-
-	case CASE(TINT8, TFLOAT32):
-	case CASE(TINT8, TFLOAT64):
-	case CASE(TUINT16, TFLOAT32):
-	case CASE(TUINT16, TFLOAT64):
-	case CASE(TUINT8, TFLOAT32):
-	case CASE(TUINT8, TFLOAT64):
-		// convert via int32 memory
-		cvt = types[TINT32];
-		goto hardmem;
-
-	case CASE(TUINT32, TFLOAT32):
-	case CASE(TUINT32, TFLOAT64):
-		// convert via int64 memory
-		cvt = types[TINT64];
-		goto hardmem;
-
-	/*
-	 * float to float
-	 */
-	case CASE(TFLOAT32, TFLOAT32):
-	case CASE(TFLOAT64, TFLOAT64):
-		// The way the code generator uses floating-point
-		// registers, a move from F0 to F0 is intended as a no-op.
-		// On the x86, it's not: it pushes a second copy of F0
-		// on the floating point stack.  So toss it away here.
-		// Also, F0 is the *only* register we ever evaluate
-		// into, so we should only see register/register as F0/F0.
-		if(ismem(f) && ismem(t))
-			goto hard;
-		if(f->op == OREGISTER && t->op == OREGISTER) {
-			if(f->val.u.reg != D_F0 || t->val.u.reg != D_F0)
-				goto fatal;
-			return;
-		}
-		a = AFMOVF;
-		if(ft == TFLOAT64)
-			a = AFMOVD;
-		if(ismem(t)) {
-			if(f->op != OREGISTER || f->val.u.reg != D_F0)
-				fatal("gmove %N", f);
-			a = AFMOVFP;
-			if(ft == TFLOAT64)
-				a = AFMOVDP;
-		}
-		break;
-
-	case CASE(TFLOAT32, TFLOAT64):
-		if(ismem(f) && ismem(t))
-			goto hard;
-		if(f->op == OREGISTER && t->op == OREGISTER) {
-			if(f->val.u.reg != D_F0 || t->val.u.reg != D_F0)
-				goto fatal;
-			return;
-		}
-		if(f->op == OREGISTER)
-			gins(AFMOVDP, f, t);
-		else
-			gins(AFMOVF, f, t);
-		return;
-
-	case CASE(TFLOAT64, TFLOAT32):
-		if(ismem(f) && ismem(t))
-			goto hard;
-		if(f->op == OREGISTER && t->op == OREGISTER) {
-			tempname(&r1, types[TFLOAT32]);
-			gins(AFMOVFP, f, &r1);
-			gins(AFMOVF, &r1, t);
-			return;
-		}
-		if(f->op == OREGISTER)
-			gins(AFMOVFP, f, t);
-		else
-			gins(AFMOVD, f, t);
-		return;
-	}
-
-	gins(a, f, t);
-	return;
-
-hard:
-	// requires register intermediate
-	regalloc(&r1, cvt, t);
-	gmove(f, &r1);
-	gmove(&r1, t);
-	regfree(&r1);
-	return;
-
-hardmem:
-	// requires memory intermediate
-	tempname(&r1, cvt);
-	gmove(f, &r1);
-	gmove(&r1, t);
-	return;
-
-fatal:
-	// should not happen
-	fatal("gmove %lN -> %lN", f, t);
-	return;
-}
-
-static void
-floatmove_sse(Node *f, Node *t)
-{
-	Node r1;
-	Type *cvt;
-	int a, ft, tt;
-
-	ft = simsimtype(f->type);
-	tt = simsimtype(t->type);
-
-	switch(CASE(ft, tt)) {
-	default:
-		// should not happen
-		fatal("gmove %N -> %N", f, t);
-		return;
-	/*
-	* float to integer
-	*/
-	case CASE(TFLOAT32, TINT16):
-	case CASE(TFLOAT32, TINT8):
-	case CASE(TFLOAT32, TUINT16):
-	case CASE(TFLOAT32, TUINT8):
-	case CASE(TFLOAT64, TINT16):
-	case CASE(TFLOAT64, TINT8):
-	case CASE(TFLOAT64, TUINT16):
-	case CASE(TFLOAT64, TUINT8):
-		// convert via int32.
-		cvt = types[TINT32];
-		goto hard;
-
-	case CASE(TFLOAT32, TUINT32):
-	case CASE(TFLOAT64, TUINT32):
-		// convert via int64.
-		cvt = types[TINT64];
-		goto hardmem;
-
-	case CASE(TFLOAT32, TINT32):
-		a = ACVTTSS2SL;
-		goto rdst;
-
-	case CASE(TFLOAT64, TINT32):
-		a = ACVTTSD2SL;
-		goto rdst;
-
-	/*
-	 * integer to float
-	 */
-	case CASE(TINT8, TFLOAT32):
-	case CASE(TINT8, TFLOAT64):
-	case CASE(TINT16, TFLOAT32):
-	case CASE(TINT16, TFLOAT64):
-	case CASE(TUINT16, TFLOAT32):
-	case CASE(TUINT16, TFLOAT64):
-	case CASE(TUINT8, TFLOAT32):
-	case CASE(TUINT8, TFLOAT64):
-		// convert via int32 memory
-		cvt = types[TINT32];
-		goto hard;
-
-	case CASE(TUINT32, TFLOAT32):
-	case CASE(TUINT32, TFLOAT64):
-		// convert via int64 memory
-		cvt = types[TINT64];
-		goto hardmem;
-
-	case CASE(TINT32, TFLOAT32):
-		a = ACVTSL2SS;
-		goto rdst;
-
-	case CASE(TINT32, TFLOAT64):
-		a = ACVTSL2SD;
-		goto rdst;
-
-	/*
-	 * float to float
-	 */
-	case CASE(TFLOAT32, TFLOAT32):
-		a = AMOVSS;
-		break;
-
-	case CASE(TFLOAT64, TFLOAT64):
-		a = AMOVSD;
-		break;
-
-	case CASE(TFLOAT32, TFLOAT64):
-		a = ACVTSS2SD;
-		goto rdst;
-
-	case CASE(TFLOAT64, TFLOAT32):
-		a = ACVTSD2SS;
-		goto rdst;
-	}
-
-	gins(a, f, t);
-	return;
-
-hard:
-	// requires register intermediate
-	regalloc(&r1, cvt, t);
-	gmove(f, &r1);
-	gmove(&r1, t);
-	regfree(&r1);
-	return;
-
-hardmem:
-	// requires memory intermediate
-	tempname(&r1, cvt);
-	gmove(f, &r1);
-	gmove(&r1, t);
-	return;
-
-rdst:
-	// requires register destination
-	regalloc(&r1, t->type, t);
-	gins(a, f, &r1);
-	gmove(&r1, t);
-	regfree(&r1);
-	return;
-}
-
-int
-samaddr(Node *f, Node *t)
-{
-
-	if(f->op != t->op)
-		return 0;
-
-	switch(f->op) {
-	case OREGISTER:
-		if(f->val.u.reg != t->val.u.reg)
-			break;
-		return 1;
-	}
-	return 0;
-}
-/*
- * generate one instruction:
- *	as f, t
- */
-Prog*
-gins(int as, Node *f, Node *t)
-{
-	Prog *p;
-	Addr af, at;
-	int w;
-
-	if(as == AFMOVF && f && f->op == OREGISTER && t && t->op == OREGISTER)
-		fatal("gins MOVF reg, reg");
-	if(as == ACVTSD2SS && f && f->op == OLITERAL)
-		fatal("gins CVTSD2SS const");
-	if(as == AMOVSD && t && t->op == OREGISTER && t->val.u.reg == D_F0)
-		fatal("gins MOVSD into F0");
-
-	switch(as) {
-	case AMOVB:
-	case AMOVW:
-	case AMOVL:
-		if(f != N && t != N && samaddr(f, t))
-			return nil;
-		break;
-	
-	case ALEAL:
-		if(f != N && isconst(f, CTNIL))
-			fatal("gins LEAL nil %T", f->type);
-		break;
-	}
-
-	memset(&af, 0, sizeof af);
-	memset(&at, 0, sizeof at);
-	if(f != N)
-		naddr(f, &af, 1);
-	if(t != N)
-		naddr(t, &at, 1);
-	p = prog(as);
-	if(f != N)
-		p->from = af;
-	if(t != N)
-		p->to = at;
-	if(debug['g'])
-		print("%P\n", p);
-
-	w = 0;
-	switch(as) {
-	case AMOVB:
-		w = 1;
-		break;
-	case AMOVW:
-		w = 2;
-		break;
-	case AMOVL:
-		w = 4;
-		break;
-	}
-
-	if(1 && w != 0 && f != N && (af.width > w || at.width > w)) {
-		dump("bad width from:", f);
-		dump("bad width to:", t);
-		fatal("bad width: %P (%d, %d)\n", p, af.width, at.width);
-	}
-
-	return p;
-}
-
-/*
- * generate code to compute n;
- * make a refer to result.
- */
-void
-naddr(Node *n, Addr *a, int canemitcode)
-{
-	Sym *s;
-
-	a->scale = 0;
-	a->index = D_NONE;
-	a->type = D_NONE;
-	a->gotype = nil;
-	a->node = N;
-	if(n == N)
-		return;
-
-	switch(n->op) {
-	default:
-		fatal("naddr: bad %O %D", n->op, a);
-		break;
-
-	case OREGISTER:
-		a->type = n->val.u.reg;
-		a->sym = nil;
-		break;
-
-	case OINDREG:
-		a->type = n->val.u.reg+D_INDIR;
-		a->sym = linksym(n->sym);
-		a->offset = n->xoffset;
-		break;
-
-	case OPARAM:
-		// n->left is PHEAP ONAME for stack parameter.
-		// compute address of actual parameter on stack.
-		a->etype = n->left->type->etype;
-		a->width = n->left->type->width;
-		a->offset = n->xoffset;
-		a->sym = linksym(n->left->sym);
-		a->type = D_PARAM;
-		a->node = n->left->orig;
-		break;
-
-	case OCLOSUREVAR:
-		if(!curfn->needctxt)
-			fatal("closurevar without needctxt");
-		a->type = D_DX+D_INDIR;
-		a->offset = n->xoffset;
-		a->sym = nil;
-		break;
-
-	case OCFUNC:
-		naddr(n->left, a, canemitcode);
-		a->sym = linksym(n->left->sym);
-		break;
-
-	case ONAME:
-		a->etype = 0;
-		a->width = 0;
-		if(n->type != T) {
-			a->etype = simtype[n->type->etype];
-			dowidth(n->type);
-			a->width = n->type->width;
-		}
-		a->offset = n->xoffset;
-		s = n->sym;
-		a->node = n->orig;
-		//if(a->node >= (Node*)&n)
-		//	fatal("stack node");
-		if(s == S)
-			s = lookup(".noname");
-		if(n->method) {
-			if(n->type != T)
-			if(n->type->sym != S)
-			if(n->type->sym->pkg != nil)
-				s = pkglookup(s->name, n->type->sym->pkg);
-		}
-
-		switch(n->class) {
-		default:
-			fatal("naddr: ONAME class %S %d\n", n->sym, n->class);
-		case PEXTERN:
-			a->type = D_EXTERN;
-			break;
-		case PAUTO:
-			a->type = D_AUTO;
-			break;
-		case PPARAM:
-		case PPARAMOUT:
-			a->type = D_PARAM;
-			break;
-		case PFUNC:
-			a->index = D_EXTERN;
-			a->type = D_ADDR;
-			s = funcsym(s);
-			break;
-		}
-		a->sym = linksym(s);
-		break;
-
-	case OLITERAL:
-		switch(n->val.ctype) {
-		default:
-			fatal("naddr: const %lT", n->type);
-			break;
-		case CTFLT:
-			a->type = D_FCONST;
-			a->u.dval = mpgetflt(n->val.u.fval);
-			break;
-		case CTINT:
-		case CTRUNE:
-			a->sym = nil;
-			a->type = D_CONST;
-			a->offset = mpgetfix(n->val.u.xval);
-			break;
-		case CTSTR:
-			datagostring(n->val.u.sval, a);
-			break;
-		case CTBOOL:
-			a->sym = nil;
-			a->type = D_CONST;
-			a->offset = n->val.u.bval;
-			break;
-		case CTNIL:
-			a->sym = nil;
-			a->type = D_CONST;
-			a->offset = 0;
-			break;
-		}
-		break;
-
-	case OADDR:
-		naddr(n->left, a, canemitcode);
-		if(a->type >= D_INDIR) {
-			a->type -= D_INDIR;
-			break;
-		}
-		if(a->type == D_EXTERN || a->type == D_STATIC ||
-		   a->type == D_AUTO || a->type == D_PARAM)
-			if(a->index == D_NONE) {
-				a->index = a->type;
-				a->type = D_ADDR;
-				break;
-			}
-		fatal("naddr: OADDR\n");
-	
-	case OITAB:
-		// itable of interface value
-		naddr(n->left, a, canemitcode);
-		if(a->type == D_CONST && a->offset == 0)
-			break;	// len(nil)
-		a->etype = tptr;
-		a->width = widthptr;
-		break;
-
-	case OSPTR:
-		// pointer in a string or slice
-		naddr(n->left, a, canemitcode);
-		if(a->type == D_CONST && a->offset == 0)
-			break;	// ptr(nil)
-		a->etype = simtype[tptr];
-		a->offset += Array_array;
-		a->width = widthptr;
-		break;
-
-	case OLEN:
-		// len of string or slice
-		naddr(n->left, a, canemitcode);
-		if(a->type == D_CONST && a->offset == 0)
-			break;	// len(nil)
-		a->etype = TUINT32;
-		a->offset += Array_nel;
-		a->width = 4;
-		break;
-
-	case OCAP:
-		// cap of string or slice
-		naddr(n->left, a, canemitcode);
-		if(a->type == D_CONST && a->offset == 0)
-			break;	// cap(nil)
-		a->etype = TUINT32;
-		a->offset += Array_cap;
-		a->width = 4;
-		break;
-
-//	case OADD:
-//		if(n->right->op == OLITERAL) {
-//			v = n->right->vconst;
-//			naddr(n->left, a, canemitcode);
-//		} else
-//		if(n->left->op == OLITERAL) {
-//			v = n->left->vconst;
-//			naddr(n->right, a, canemitcode);
-//		} else
-//			goto bad;
-//		a->offset += v;
-//		break;
-
-	}
-}
-
-int
-dotaddable(Node *n, Node *n1)
-{
-	int o;
-	int64 oary[10];
-	Node *nn;
-
-	if(n->op != ODOT)
-		return 0;
-
-	o = dotoffset(n, oary, &nn);
-	if(nn != N && nn->addable && o == 1 && oary[0] >= 0) {
-		*n1 = *nn;
-		n1->type = n->type;
-		n1->xoffset += oary[0];
-		return 1;
-	}
-	return 0;
-}
-
-void
-sudoclean(void)
-{
-}
-
-int
-sudoaddable(int as, Node *n, Addr *a)
-{
-	USED(as);
-	USED(n);
-	USED(a);
-
-	return 0;
-}
diff --git a/src/cmd/8g/opt.h b/src/cmd/8g/opt.h
deleted file mode 100644
index 09f58c4..0000000
--- a/src/cmd/8g/opt.h
+++ /dev/null
@@ -1,238 +0,0 @@
-// Derived from Inferno utils/6c/gc.h
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/gc.h
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include	"../gc/popt.h"
-
-#define	Z	N
-#define	Adr	Addr
-
-#define	D_HI	D_NONE
-#define	D_LO	D_NONE
-
-#define	BLOAD(r)	band(bnot(r->refbehind), r->refahead)
-#define	BSTORE(r)	band(bnot(r->calbehind), r->calahead)
-#define	LOAD(r)		(~r->refbehind.b[z] & r->refahead.b[z])
-#define	STORE(r)	(~r->calbehind.b[z] & r->calahead.b[z])
-
-#define	CLOAD	5
-#define	CREF	5
-#define	CINF	1000
-#define	LOOP	3
-
-typedef	struct	Reg	Reg;
-typedef	struct	Rgn	Rgn;
-
-/*c2go
-extern Node *Z;
-enum
-{
-	D_HI = D_NONE,
-	D_LO = D_NONE,
-	CLOAD = 5,
-	CREF = 5,
-	CINF = 1000,
-	LOOP = 3,
-};
-
-uint32 BLOAD(Reg*);
-uint32 BSTORE(Reg*);
-uint32 LOAD(Reg*);
-uint32 STORE(Reg*);
-*/
-
-// 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.
-// r->prog->opt points back to r.
-struct	Reg
-{
-	Flow	f;
-
-	Bits	set;  		// variables written by this instruction.
-	Bits	use1; 		// variables read by prog->from.
-	Bits	use2; 		// variables read by prog->to.
-
-	Bits	refbehind;
-	Bits	refahead;
-	Bits	calbehind;
-	Bits	calahead;
-	Bits	regdiff;
-	Bits	act;
-
-	int32	regu;		// register used bitmap
-	int32	rpo;		// reverse post ordering
-	int32	active;
-
-	uint16	loop;		// x5 for every loop
-	uchar	refset;		// diagnostic generated
-
-	Reg*	p1;     	// predecessors of this instruction: p1,
-	Reg*	p2;     	// and then p2 linked though p2link.
-	Reg*	p2link;
-	Reg*	s1;     	// successors of this instruction (at most two: s1 and s2).
-	Reg*	s2;
-	Reg*	link;   	// next instruction in function code
-	Prog*	prog;   	// actual instruction
-};
-#define	R	((Reg*)0)
-/*c2go extern Reg *R; */
-
-#define	NRGN	600
-/*c2go enum { NRGN = 600 }; */
-struct	Rgn
-{
-	Reg*	enter;
-	short	cost;
-	short	varno;
-	short	regno;
-};
-
-EXTERN	int32	exregoffset;		// not set
-EXTERN	int32	exfregoffset;		// not set
-EXTERN	Reg	zreg;
-EXTERN	Reg*	freer;
-EXTERN	Reg**	rpo2r;
-EXTERN	Rgn	region[NRGN];
-EXTERN	Rgn*	rgp;
-EXTERN	int	nregion;
-EXTERN	int	nvar;
-EXTERN	int32	regbits;
-EXTERN	int32	exregbits;
-EXTERN	Bits	externs;
-EXTERN	Bits	params;
-EXTERN	Bits	consts;
-EXTERN	Bits	addrs;
-EXTERN	Bits	ivar;
-EXTERN	Bits	ovar;
-EXTERN	int	change;
-EXTERN	int32	maxnr;
-EXTERN	int32*	idom;
-
-EXTERN	struct
-{
-	int32	ncvtreg;
-	int32	nspill;
-	int32	nreload;
-	int32	ndelmov;
-	int32	nvar;
-	int32	naddr;
-} ostats;
-
-/*
- * reg.c
- */
-Reg*	rega(void);
-int	rcmp(const void*, const void*);
-void	regopt(Prog*);
-void	addmove(Reg*, int, int, int);
-Bits	mkvar(Reg*, Adr*);
-void	prop(Reg*, Bits, Bits);
-void	loopit(Reg*, int32);
-void	synch(Reg*, Bits);
-uint32	allreg(uint32, Rgn*);
-void	paint1(Reg*, int);
-uint32	paint2(Reg*, int);
-void	paint3(Reg*, int, int32, int);
-void	addreg(Adr*, int);
-void	dumpone(Flow*, int);
-void	dumpit(char*, Flow*, int);
-
-/*
- * peep.c
- */
-void	peep(Prog*);
-void	excise(Flow*);
-int	copyu(Prog*, Adr*, Adr*);
-
-int32	RtoB(int);
-int32	FtoB(int);
-int	BtoR(int32);
-int	BtoF(int32);
-
-/*
- * prog.c
- */
-typedef struct ProgInfo ProgInfo;
-struct ProgInfo
-{
-	uint32 flags; // the bits below
-	uint32 reguse; // required registers used by this instruction
-	uint32 regset; // required registers set by this instruction
-	uint32 regindex; // registers used by addressing mode
-};
-
-enum
-{
-	// 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, // float aka float32
-	SizeD = 1<<8, // double aka float64
-
-	// Left side: address taken, read, write.
-	LeftAddr = 1<<9,
-	LeftRead = 1<<10,
-	LeftWrite = 1<<11,
-	
-	// Right side: address taken, read, write.
-	RightAddr = 1<<12,
-	RightRead = 1<<13,
-	RightWrite = 1<<14,
-
-	// Set, use, or kill of carry bit.
-	// Kill means we never look at the carry bit after this kind of instruction.
-	SetCarry = 1<<15,
-	UseCarry = 1<<16,
-	KillCarry = 1<<17,
-
-	// Instruction kinds
-	Move = 1<<18, // straight move
-	Conv = 1<<19, // size conversion
-	Cjmp = 1<<20, // conditional jump
-	Break = 1<<21, // breaks control flow (no fallthrough)
-	Call = 1<<22, // function call
-	Jump = 1<<23, // jump
-	Skip = 1<<24, // data instruction
-
-	// Special cases for register use.
-	ShiftCX = 1<<25, // possible shift by CX
-	ImulAXDX = 1<<26, // possible multiply into DX:AX
-};
-
-void proginfo(ProgInfo*, Prog*);
diff --git a/src/cmd/8g/peep.c b/src/cmd/8g/peep.c
deleted file mode 100644
index 91a91d2..0000000
--- a/src/cmd/8g/peep.c
+++ /dev/null
@@ -1,779 +0,0 @@
-// 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 at 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 at 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.
-
-#include <u.h>
-#include <libc.h>
-#include "gg.h"
-#include "opt.h"
-
-enum {
-	REGEXT = 0,
-};
-
-static void	conprop(Flow *r);
-static void	elimshortmov(Graph*);
-static int	subprop(Flow*);
-static int	copyprop(Graph*, Flow*);
-static int	copy1(Adr*, Adr*, Flow*, int);
-static int	copyas(Adr*, Adr*);
-static int	copyau(Adr*, Adr*);
-static int	copysub(Adr*, Adr*, Adr*, int);
-
-static uint32	gactive;
-
-// do we need the carry bit
-static int
-needc(Prog *p)
-{
-	ProgInfo info;
-
-	while(p != P) {
-		proginfo(&info, p);
-		if(info.flags & UseCarry)
-			return 1;
-		if(info.flags & (SetCarry|KillCarry))
-			return 0;
-		p = p->link;
-	}
-	return 0;
-}
-
-static Flow*
-rnops(Flow *r)
-{
-	Prog *p;
-	Flow *r1;
-
-	if(r != nil)
-	for(;;) {
-		p = r->prog;
-		if(p->as != ANOP || p->from.type != D_NONE || p->to.type != D_NONE)
-			break;
-		r1 = uniqs(r);
-		if(r1 == nil)
-			break;
-		r = r1;
-	}
-	return r;
-}
-
-void
-peep(Prog *firstp)
-{
-	Flow *r, *r1;
-	Graph *g;
-	Prog *p, *p1;
-	int t;
-
-	g = flowstart(firstp, sizeof(Flow));
-	if(g == nil)
-		return;
-	gactive = 0;
-
-	// byte, word arithmetic elimination.
-	elimshortmov(g);
-
-	// constant propagation
-	// find MOV $con,R followed by
-	// another MOV $con,R without
-	// setting R in the interim
-	for(r=g->start; r!=nil; r=r->link) {
-		p = r->prog;
-		switch(p->as) {
-		case ALEAL:
-			if(regtyp(&p->to))
-			if(p->from.sym != nil)
-			if(p->from.index == D_NONE || p->from.index == D_CONST)
-				conprop(r);
-			break;
-
-		case AMOVB:
-		case AMOVW:
-		case AMOVL:
-		case AMOVSS:
-		case AMOVSD:
-			if(regtyp(&p->to))
-			if(p->from.type == D_CONST)
-				conprop(r);
-			break;
-		}
-	}
-
-loop1:
-	if(debug['P'] && debug['v'])
-		dumpit("loop1", g->start, 0);
-
-	t = 0;
-	for(r=g->start; r!=nil; r=r->link) {
-		p = r->prog;
-		switch(p->as) {
-		case AMOVL:
-		case AMOVSS:
-		case AMOVSD:
-			if(regtyp(&p->to))
-			if(regtyp(&p->from)) {
-				if(copyprop(g, r)) {
-					excise(r);
-					t++;
-				} else
-				if(subprop(r) && copyprop(g, r)) {
-					excise(r);
-					t++;
-				}
-			}
-			break;
-
-		case AMOVBLZX:
-		case AMOVWLZX:
-		case AMOVBLSX:
-		case AMOVWLSX:
-			if(regtyp(&p->to)) {
-				r1 = rnops(uniqs(r));
-				if(r1 != nil) {
-					p1 = r1->prog;
-					if(p->as == p1->as && p->to.type == p1->from.type){
-						p1->as = AMOVL;
-						t++;
-					}
-				}
-			}
-			break;
-
-		case AADDL:
-		case AADDW:
-			if(p->from.type != D_CONST || needc(p->link))
-				break;
-			if(p->from.offset == -1){
-				if(p->as == AADDL)
-					p->as = ADECL;
-				else
-					p->as = ADECW;
-				p->from = zprog.from;
-				break;
-			}
-			if(p->from.offset == 1){
-				if(p->as == AADDL)
-					p->as = AINCL;
-				else
-					p->as = AINCW;
-				p->from = zprog.from;
-				break;
-			}
-			break;
-
-		case ASUBL:
-		case ASUBW:
-			if(p->from.type != D_CONST || needc(p->link))
-				break;
-			if(p->from.offset == -1) {
-				if(p->as == ASUBL)
-					p->as = AINCL;
-				else
-					p->as = AINCW;
-				p->from = zprog.from;
-				break;
-			}
-			if(p->from.offset == 1){
-				if(p->as == ASUBL)
-					p->as = ADECL;
-				else
-					p->as = ADECW;
-				p->from = zprog.from;
-				break;
-			}
-			break;
-		}
-	}
-	if(t)
-		goto loop1;
-
-	// MOVSD removal.
-	// We never use packed registers, so a MOVSD between registers
-	// can be replaced by MOVAPD, which moves the pair of float64s
-	// instead of just the lower one.  We only use the lower one, but
-	// 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 == AMOVSD)
-		if(regtyp(&p->from))
-		if(regtyp(&p->to))
-			p->as = AMOVAPD;
-	}
-	
-	flowend(g);
-}
-
-void
-excise(Flow *r)
-{
-	Prog *p;
-
-	p = r->prog;
-	if(debug['P'] && debug['v'])
-		print("%P ===delete===\n", p);
-
-	p->as = ANOP;
-	p->from = zprog.from;
-	p->to = zprog.to;
-
-	ostats.ndelmov++;
-}
-
-int
-regtyp(Adr *a)
-{
-	int t;
-
-	t = a->type;
-	if(t >= D_AX && t <= D_DI)
-		return 1;
-	if(t >= D_X0 && t <= D_X7)
-		return 1;
-	return 0;
-}
-
-// movb elimination.
-// movb is simulated by the linker
-// when a register other than ax, bx, cx, dx
-// is used, so rewrite to other instructions
-// when possible.  a movb into a register
-// can smash the entire 64-bit register without
-// causing any trouble.
-static void
-elimshortmov(Graph *g)
-{
-	Prog *p;
-	Flow *r;
-
-	for(r=g->start; r!=nil; r=r->link) {
-		p = r->prog;
-		if(regtyp(&p->to)) {
-			switch(p->as) {
-			case AINCB:
-			case AINCW:
-				p->as = AINCL;
-				break;
-			case ADECB:
-			case ADECW:
-				p->as = ADECL;
-				break;
-			case ANEGB:
-			case ANEGW:
-				p->as = ANEGL;
-				break;
-			case ANOTB:
-			case ANOTW:
-				p->as = ANOTL;
-				break;
-			}
-			if(regtyp(&p->from) || p->from.type == D_CONST) {
-				// move or artihmetic into partial register.
-				// from another register or constant can be movl.
-				// 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 AMOVB:
-				case AMOVW:
-					p->as = AMOVL;
-					break;
-				case AADDB:
-				case AADDW:
-					if(!needc(p->link))
-						p->as = AADDL;
-					break;
-				case ASUBB:
-				case ASUBW:
-					if(!needc(p->link))
-						p->as = ASUBL;
-					break;
-				case AMULB:
-				case AMULW:
-					p->as = AMULL;
-					break;
-				case AIMULB:
-				case AIMULW:
-					p->as = AIMULL;
-					break;
-				case AANDB:
-				case AANDW:
-					p->as = AANDL;
-					break;
-				case AORB:
-				case AORW:
-					p->as = AORL;
-					break;
-				case AXORB:
-				case AXORW:
-					p->as = AXORL;
-					break;
-				case ASHLB:
-				case ASHLW:
-					p->as = ASHLL;
-					break;
-				}
-			} else {
-				// explicit zero extension
-				switch(p->as) {
-				case AMOVB:
-					p->as = AMOVBLZX;
-					break;
-				case AMOVW:
-					p->as = AMOVWLZX;
-					break;
-				}
-			}
-		}
-	}
-}
-
-/*
- * the idea is to substitute
- * one register for another
- * from one MOV to another
- *	MOV	a, R0
- *	ADD	b, R0	/ no use of R1
- *	MOV	R0, R1
- * would be converted to
- *	MOV	a, R1
- *	ADD	b, R1
- *	MOV	R1, R0
- * hopefully, then the former or latter MOV
- * will be eliminated by copy propagation.
- */
-static int
-subprop(Flow *r0)
-{
-	Prog *p;
-	Adr *v1, *v2;
-	Flow *r;
-	int t;
-	ProgInfo info;
-
-	p = r0->prog;
-	v1 = &p->from;
-	if(!regtyp(v1))
-		return 0;
-	v2 = &p->to;
-	if(!regtyp(v2))
-		return 0;
-	for(r=uniqp(r0); r!=nil; r=uniqp(r)) {
-		if(debug['P'] && debug['v'])
-			print("\t? %P\n", r->prog);
-		if(uniqs(r) == nil)
-			break;
-		p = r->prog;
-		if(p->as == AVARDEF || p->as == AVARKILL)
-			continue;
-		proginfo(&info, p);
-		if(info.flags & Call)
-			return 0;
-
-		if(info.reguse | info.regset)
-			return 0;
-
-		if((info.flags & Move) && (info.flags & (SizeL|SizeQ|SizeF|SizeD)) && p->to.type == v1->type)
-			goto gotit;
-
-		if(copyau(&p->from, v2) || copyau(&p->to, v2))
-			break;
-		if(copysub(&p->from, v1, v2, 0) || copysub(&p->to, v1, v2, 0))
-			break;
-	}
-	return 0;
-
-gotit:
-	copysub(&p->to, v1, v2, 1);
-	if(debug['P']) {
-		print("gotit: %D->%D\n%P", v1, v2, r->prog);
-		if(p->from.type == v2->type)
-			print(" excise");
-		print("\n");
-	}
-	for(r=uniqs(r); r!=r0; r=uniqs(r)) {
-		p = r->prog;
-		copysub(&p->from, v1, v2, 1);
-		copysub(&p->to, v1, v2, 1);
-		if(debug['P'])
-			print("%P\n", r->prog);
-	}
-	t = v1->type;
-	v1->type = v2->type;
-	v2->type = t;
-	if(debug['P'])
-		print("%P last\n", r->prog);
-	return 1;
-}
-
-/*
- * The idea is to remove redundant copies.
- *	v1->v2	F=0
- *	(use v2	s/v2/v1/)*
- *	set v1	F=1
- *	use v2	return fail
- *	-----------------
- *	v1->v2	F=0
- *	(use v2	s/v2/v1/)*
- *	set v1	F=1
- *	set v2	return success
- */
-static int
-copyprop(Graph *g, Flow *r0)
-{
-	Prog *p;
-	Adr *v1, *v2;
-
-	USED(g);
-	p = r0->prog;
-	v1 = &p->from;
-	v2 = &p->to;
-	if(copyas(v1, v2))
-		return 1;
-	gactive++;
-	return copy1(v1, v2, r0->s1, 0);
-}
-
-static int
-copy1(Adr *v1, Adr *v2, Flow *r, int f)
-{
-	int t;
-	Prog *p;
-
-	if(r->active == gactive) {
-		if(debug['P'])
-			print("act set; return 1\n");
-		return 1;
-	}
-	r->active = gactive;
-	if(debug['P'])
-		print("copy %D->%D f=%d\n", v1, v2, f);
-	for(; r != nil; r = r->s1) {
-		p = r->prog;
-		if(debug['P'])
-			print("%P", p);
-		if(!f && uniqp(r) == nil) {
-			f = 1;
-			if(debug['P'])
-				print("; merge; f=%d", f);
-		}
-		t = copyu(p, v2, nil);
-		switch(t) {
-		case 2:	/* rar, can't split */
-			if(debug['P'])
-				print("; %D rar; return 0\n", v2);
-			return 0;
-
-		case 3:	/* set */
-			if(debug['P'])
-				print("; %D set; return 1\n", v2);
-			return 1;
-
-		case 1:	/* used, substitute */
-		case 4:	/* use and set */
-			if(f) {
-				if(!debug['P'])
-					return 0;
-				if(t == 4)
-					print("; %D used+set and f=%d; return 0\n", v2, f);
-				else
-					print("; %D used and f=%d; return 0\n", v2, f);
-				return 0;
-			}
-			if(copyu(p, v2, v1)) {
-				if(debug['P'])
-					print("; sub fail; return 0\n");
-				return 0;
-			}
-			if(debug['P'])
-				print("; sub %D/%D", v2, v1);
-			if(t == 4) {
-				if(debug['P'])
-					print("; %D used+set; return 1\n", v2);
-				return 1;
-			}
-			break;
-		}
-		if(!f) {
-			t = copyu(p, v1, nil);
-			if(!f && (t == 2 || t == 3 || t == 4)) {
-				f = 1;
-				if(debug['P'])
-					print("; %D set and !f; f=%d", v1, f);
-			}
-		}
-		if(debug['P'])
-			print("\n");
-		if(r->s2)
-			if(!copy1(v1, v2, r->s2, f))
-				return 0;
-	}
-	return 1;
-}
-
-/*
- * return
- * 1 if v only used (and substitute),
- * 2 if read-alter-rewrite
- * 3 if set
- * 4 if set and used
- * 0 otherwise (not touched)
- */
-int
-copyu(Prog *p, Adr *v, Adr *s)
-{
-	ProgInfo info;
-
-	switch(p->as) {
-	case AJMP:
-		if(s != nil) {
-			if(copysub(&p->to, v, s, 1))
-				return 1;
-			return 0;
-		}
-		if(copyau(&p->to, v))
-			return 1;
-		return 0;
-
-	case ARET:
-		if(s != nil)
-			return 1;
-		return 3;
-
-	case ACALL:
-		if(REGEXT && v->type <= REGEXT && v->type > exregoffset)
-			return 2;
-		if(REGARG >= 0 && v->type == (uchar)REGARG)
-			return 2;
-		if(v->type == p->from.type)
-			return 2;
-
-		if(s != nil) {
-			if(copysub(&p->to, v, s, 1))
-				return 1;
-			return 0;
-		}
-		if(copyau(&p->to, v))
-			return 4;
-		return 3;
-
-	case ATEXT:
-		if(REGARG >= 0 && v->type == (uchar)REGARG)
-			return 3;
-		return 0;
-	}
-
-	if(p->as == AVARDEF || p->as == AVARKILL)
-		return 0;
-	proginfo(&info, p);
-
-	if((info.reguse|info.regset) & RtoB(v->type))
-		return 2;
-		
-	if(info.flags & LeftAddr)
-		if(copyas(&p->from, v))
-			return 2;
-
-	if((info.flags & (RightRead|RightWrite)) == (RightRead|RightWrite))
-		if(copyas(&p->to, v))
-			return 2;
-	
-	if(info.flags & RightWrite) {
-		if(copyas(&p->to, v)) {
-			if(s != nil)
-				return copysub(&p->from, v, s, 1);
-			if(copyau(&p->from, v))
-				return 4;
-			return 3;
-		}
-	}
-	
-	if(info.flags & (LeftAddr|LeftRead|LeftWrite|RightAddr|RightRead|RightWrite)) {
-		if(s != nil) {
-			if(copysub(&p->from, v, s, 1))
-				return 1;
-			return copysub(&p->to, v, s, 1);
-		}
-		if(copyau(&p->from, v))
-			return 1;
-		if(copyau(&p->to, v))
-			return 1;
-	}
-
-	return 0;
-}
-
-/*
- * direct reference,
- * could be set/use depending on
- * semantics
- */
-static int
-copyas(Adr *a, Adr *v)
-{
-	if(D_AL <= a->type && a->type <= D_BL)
-		fatal("use of byte register");
-	if(D_AL <= v->type && v->type <= D_BL)
-		fatal("use of byte register");
-
-	if(a->type != v->type)
-		return 0;
-	if(regtyp(v))
-		return 1;
-	if(v->type == D_AUTO || v->type == D_PARAM)
-		if(v->offset == a->offset)
-			return 1;
-	return 0;
-}
-
-int
-sameaddr(Addr *a, Addr *v)
-{
-	if(a->type != v->type)
-		return 0;
-	if(regtyp(v))
-		return 1;
-	if(v->type == D_AUTO || v->type == D_PARAM)
-		if(v->offset == a->offset)
-			return 1;
-	return 0;
-}
-
-/*
- * either direct or indirect
- */
-static int
-copyau(Adr *a, Adr *v)
-{
-
-	if(copyas(a, v))
-		return 1;
-	if(regtyp(v)) {
-		if(a->type-D_INDIR == v->type)
-			return 1;
-		if(a->index == v->type)
-			return 1;
-	}
-	return 0;
-}
-
-/*
- * substitute s for v in a
- * return failure to substitute
- */
-static int
-copysub(Adr *a, Adr *v, Adr *s, int f)
-{
-	int t;
-
-	if(copyas(a, v)) {
-		t = s->type;
-		if(t >= D_AX && t <= D_DI || t >= D_X0 && t <= D_X7) {
-			if(f)
-				a->type = t;
-		}
-		return 0;
-	}
-	if(regtyp(v)) {
-		t = v->type;
-		if(a->type == t+D_INDIR) {
-			if((s->type == D_BP) && a->index != D_NONE)
-				return 1;	/* can't use BP-base with index */
-			if(f)
-				a->type = s->type+D_INDIR;
-//			return 0;
-		}
-		if(a->index == t) {
-			if(f)
-				a->index = s->type;
-			return 0;
-		}
-		return 0;
-	}
-	return 0;
-}
-
-static void
-conprop(Flow *r0)
-{
-	Flow *r;
-	Prog *p, *p0;
-	int t;
-	Adr *v0;
-
-	p0 = r0->prog;
-	v0 = &p0->to;
-	r = r0;
-
-loop:
-	r = uniqs(r);
-	if(r == nil || r == r0)
-		return;
-	if(uniqp(r) == nil)
-		return;
-
-	p = r->prog;
-	t = copyu(p, v0, nil);
-	switch(t) {
-	case 0:	// miss
-	case 1:	// use
-		goto loop;
-
-	case 2:	// rar
-	case 4:	// use and set
-		break;
-
-	case 3:	// set
-		if(p->as == p0->as)
-		if(p->from.type == p0->from.type)
-		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 == D_FCONST && p->from.u.dval == p0->from.u.dval)
-		if(p->from.index == p0->from.index) {
-			excise(r);
-			goto loop;
-		}
-		break;
-	}
-}
-
-int
-smallindir(Addr *a, Addr *reg)
-{
-	return regtyp(reg) &&
-		a->type == D_INDIR + reg->type &&
-		a->index == D_NONE &&
-		0 <= a->offset && a->offset < 4096;
-}
-
-int
-stackaddr(Addr *a)
-{
-	return regtyp(a) && a->type == D_SP;
-}
diff --git a/src/cmd/8g/prog.c b/src/cmd/8g/prog.c
deleted file mode 100644
index 8eed67f..0000000
--- a/src/cmd/8g/prog.c
+++ /dev/null
@@ -1,349 +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.
-
-#include <u.h>
-#include <libc.h>
-#include "gg.h"
-#include "opt.h"
-
-// Matches real RtoB but can be used in global initializer.
-#define RtoB(r) (1<<((r)-D_AX))
-
-enum {
-	AX = RtoB(D_AX),
-	BX = RtoB(D_BX),
-	CX = RtoB(D_CX),
-	DX = RtoB(D_DX),
-	DI = RtoB(D_DI),
-	SI = RtoB(D_SI),
-	
-	LeftRdwr = LeftRead | LeftWrite,
-	RightRdwr = RightRead | RightWrite,
-};
-
-#undef RtoB
-
-// 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.
-static ProgInfo progtable[ALAST] = {
-	[ATYPE]=	{Pseudo | Skip},
-	[ATEXT]=	{Pseudo},
-	[AFUNCDATA]=	{Pseudo},
-	[APCDATA]=	{Pseudo},
-	[AUNDEF]=	{Break},
-	[AUSEFIELD]=	{OK},
-	[ACHECKNIL]=	{LeftRead},
-	[AVARDEF]=	{Pseudo | RightWrite},
-	[AVARKILL]=	{Pseudo | RightWrite},
-
-	// NOP is an internal no-op that also stands
-	// for USED and SET annotations, not the Intel opcode.
-	[ANOP]=		{LeftRead | RightWrite},
-
-	[AADCL]=	{SizeL | LeftRead | RightRdwr | SetCarry | UseCarry},
-	[AADCW]=	{SizeW | LeftRead | RightRdwr | SetCarry | UseCarry},
-
-	[AADDB]=	{SizeB | LeftRead | RightRdwr | SetCarry},
-	[AADDL]=	{SizeL | LeftRead | RightRdwr | SetCarry},
-	[AADDW]=	{SizeW | LeftRead | RightRdwr | SetCarry},
-	
-	[AADDSD]=	{SizeD | LeftRead | RightRdwr},
-	[AADDSS]=	{SizeF | LeftRead | RightRdwr},
-
-	[AANDB]=	{SizeB | LeftRead | RightRdwr | SetCarry},
-	[AANDL]=	{SizeL | LeftRead | RightRdwr | SetCarry},
-	[AANDW]=	{SizeW | LeftRead | RightRdwr | SetCarry},
-
-	[ACALL]=	{RightAddr | Call | KillCarry},
-
-	[ACDQ]=		{OK, AX, AX | DX},
-	[ACWD]=		{OK, AX, AX | DX},
-
-	[ACLD]=		{OK},
-	[ASTD]=		{OK},
-
-	[ACMPB]=	{SizeB | LeftRead | RightRead | SetCarry},
-	[ACMPL]=	{SizeL | LeftRead | RightRead | SetCarry},
-	[ACMPW]=	{SizeW | LeftRead | RightRead | SetCarry},
-
-	[ACOMISD]=	{SizeD | LeftRead | RightRead | SetCarry},
-	[ACOMISS]=	{SizeF | LeftRead | RightRead | SetCarry},
-
-	[ACVTSD2SL]=	{SizeL | LeftRead | RightWrite | Conv},
-	[ACVTSD2SS]=	{SizeF | LeftRead | RightWrite | Conv},
-	[ACVTSL2SD]=	{SizeD | LeftRead | RightWrite | Conv},
-	[ACVTSL2SS]=	{SizeF | LeftRead | RightWrite | Conv},
-	[ACVTSS2SD]=	{SizeD | LeftRead | RightWrite | Conv},
-	[ACVTSS2SL]=	{SizeL | LeftRead | RightWrite | Conv},
-	[ACVTTSD2SL]=	{SizeL | LeftRead | RightWrite | Conv},
-	[ACVTTSS2SL]=	{SizeL | LeftRead | RightWrite | Conv},
-
-	[ADECB]=	{SizeB | RightRdwr},
-	[ADECL]=	{SizeL | RightRdwr},
-	[ADECW]=	{SizeW | RightRdwr},
-
-	[ADIVB]=	{SizeB | LeftRead | SetCarry, AX, AX},
-	[ADIVL]=	{SizeL | LeftRead | SetCarry, AX|DX, AX|DX},
-	[ADIVW]=	{SizeW | LeftRead | SetCarry, AX|DX, AX|DX},
-
-	[ADIVSD]=	{SizeD | LeftRead | RightRdwr},
-	[ADIVSS]=	{SizeF | LeftRead | RightRdwr},
-	
-	[AFLDCW]=	{SizeW | LeftAddr},
-	[AFSTCW]=	{SizeW | RightAddr},
-
-	[AFSTSW]=	{SizeW | RightAddr | RightWrite},
-
-	[AFADDD]=	{SizeD | LeftAddr | RightRdwr},
-	[AFADDDP]=	{SizeD | LeftAddr | RightRdwr},
-	[AFADDF]=	{SizeF | LeftAddr | RightRdwr},
-
-	[AFCOMD]=	{SizeD | LeftAddr | RightRead},
-	[AFCOMDP]=	{SizeD | LeftAddr | RightRead},
-	[AFCOMDPP]=	{SizeD | LeftAddr | RightRead},
-	[AFCOMF]=	{SizeF | LeftAddr | RightRead},
-	[AFCOMFP]=	{SizeF | LeftAddr | RightRead},
-	[AFUCOMIP]=	{SizeF | LeftAddr | RightRead},
-
-	[AFCHS]=	{SizeD | RightRdwr}, // also SizeF
-
-	[AFDIVDP]=	{SizeD | LeftAddr | RightRdwr},
-	[AFDIVF]=	{SizeF | LeftAddr | RightRdwr},
-	[AFDIVD]=	{SizeD | LeftAddr | RightRdwr},
-
-	[AFDIVRDP]=	{SizeD | LeftAddr | RightRdwr},
-	[AFDIVRF]=	{SizeF | LeftAddr | RightRdwr},
-	[AFDIVRD]=	{SizeD | LeftAddr | RightRdwr},
-
-	[AFXCHD]=	{SizeD | LeftRdwr | RightRdwr},
-
-	[AFSUBD]=	{SizeD | LeftAddr | RightRdwr},
-	[AFSUBDP]=	{SizeD | LeftAddr | RightRdwr},
-	[AFSUBF]=	{SizeF | LeftAddr | RightRdwr},
-	[AFSUBRD]=	{SizeD | LeftAddr | RightRdwr},
-	[AFSUBRDP]=	{SizeD | LeftAddr | RightRdwr},
-	[AFSUBRF]=	{SizeF | LeftAddr | RightRdwr},
-
-	[AFMOVD]=	{SizeD | LeftAddr | RightWrite},
-	[AFMOVF]=	{SizeF | LeftAddr | RightWrite},
-	[AFMOVL]=	{SizeL | LeftAddr | RightWrite},
-	[AFMOVW]=	{SizeW | LeftAddr | RightWrite},
-	[AFMOVV]=	{SizeQ | LeftAddr | RightWrite},
-
-	// 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.
-	[AFMOVDP]=	{SizeD | LeftRead | RightWrite | RightAddr},
-	[AFMOVFP]=	{SizeF | LeftRead | RightWrite | RightAddr},
-	[AFMOVLP]=	{SizeL | LeftRead | RightWrite | RightAddr},
-	[AFMOVWP]=	{SizeW | LeftRead | RightWrite | RightAddr},
-	[AFMOVVP]=	{SizeQ | LeftRead | RightWrite | RightAddr},
-
-	[AFMULD]=	{SizeD | LeftAddr | RightRdwr},
-	[AFMULDP]=	{SizeD | LeftAddr | RightRdwr},
-	[AFMULF]=	{SizeF | LeftAddr | RightRdwr},
-
-	[AIDIVB]=	{SizeB | LeftRead | SetCarry, AX, AX},
-	[AIDIVL]=	{SizeL | LeftRead | SetCarry, AX|DX, AX|DX},
-	[AIDIVW]=	{SizeW | LeftRead | SetCarry, AX|DX, AX|DX},
-
-	[AIMULB]=	{SizeB | LeftRead | SetCarry, AX, AX},
-	[AIMULL]=	{SizeL | LeftRead | ImulAXDX | SetCarry},
-	[AIMULW]=	{SizeW | LeftRead | ImulAXDX | SetCarry},
-
-	[AINCB]=	{SizeB | RightRdwr},
-	[AINCL]=	{SizeL | RightRdwr},
-	[AINCW]=	{SizeW | RightRdwr},
-
-	[AJCC]=		{Cjmp | UseCarry},
-	[AJCS]=		{Cjmp | UseCarry},
-	[AJEQ]=		{Cjmp | UseCarry},
-	[AJGE]=		{Cjmp | UseCarry},
-	[AJGT]=		{Cjmp | UseCarry},
-	[AJHI]=		{Cjmp | UseCarry},
-	[AJLE]=		{Cjmp | UseCarry},
-	[AJLS]=		{Cjmp | UseCarry},
-	[AJLT]=		{Cjmp | UseCarry},
-	[AJMI]=		{Cjmp | UseCarry},
-	[AJNE]=		{Cjmp | UseCarry},
-	[AJOC]=		{Cjmp | UseCarry},
-	[AJOS]=		{Cjmp | UseCarry},
-	[AJPC]=		{Cjmp | UseCarry},
-	[AJPL]=		{Cjmp | UseCarry},
-	[AJPS]=		{Cjmp | UseCarry},
-
-	[AJMP]=		{Jump | Break | KillCarry},
-
-	[ALEAL]=	{LeftAddr | RightWrite},
-
-	[AMOVBLSX]=	{SizeL | LeftRead | RightWrite | Conv},
-	[AMOVBLZX]=	{SizeL | LeftRead | RightWrite | Conv},
-	[AMOVBWSX]=	{SizeW | LeftRead | RightWrite | Conv},
-	[AMOVBWZX]=	{SizeW | LeftRead | RightWrite | Conv},
-	[AMOVWLSX]=	{SizeL | LeftRead | RightWrite | Conv},
-	[AMOVWLZX]=	{SizeL | LeftRead | RightWrite | Conv},
-
-	[AMOVB]=	{SizeB | LeftRead | RightWrite | Move},
-	[AMOVL]=	{SizeL | LeftRead | RightWrite | Move},
-	[AMOVW]=	{SizeW | LeftRead | RightWrite | Move},
-
-	[AMOVSB]=	{OK, DI|SI, DI|SI},
-	[AMOVSL]=	{OK, DI|SI, DI|SI},
-	[AMOVSW]=	{OK, DI|SI, DI|SI},
-	[ADUFFCOPY]=	{OK, DI|SI, DI|SI|CX},
-
-	[AMOVSD]=	{SizeD | LeftRead | RightWrite | Move},
-	[AMOVSS]=	{SizeF | LeftRead | RightWrite | Move},
-
-	// We use MOVAPD as a faster synonym for MOVSD.
-	[AMOVAPD]=	{SizeD | LeftRead | RightWrite | Move},
-
-	[AMULB]=	{SizeB | LeftRead | SetCarry, AX, AX},
-	[AMULL]=	{SizeL | LeftRead | SetCarry, AX, AX|DX},
-	[AMULW]=	{SizeW | LeftRead | SetCarry, AX, AX|DX},
-	
-	[AMULSD]=	{SizeD | LeftRead | RightRdwr},
-	[AMULSS]=	{SizeF | LeftRead | RightRdwr},
-
-	[ANEGB]=	{SizeB | RightRdwr | SetCarry},
-	[ANEGL]=	{SizeL | RightRdwr | SetCarry},
-	[ANEGW]=	{SizeW | RightRdwr | SetCarry},
-
-	[ANOTB]=	{SizeB | RightRdwr},
-	[ANOTL]=	{SizeL | RightRdwr},
-	[ANOTW]=	{SizeW | RightRdwr},
-
-	[AORB]=		{SizeB | LeftRead | RightRdwr | SetCarry},
-	[AORL]=		{SizeL | LeftRead | RightRdwr | SetCarry},
-	[AORW]=		{SizeW | LeftRead | RightRdwr | SetCarry},
-
-	[APOPL]=	{SizeL | RightWrite},
-	[APUSHL]=	{SizeL | LeftRead},
-
-	[ARCLB]=	{SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
-	[ARCLL]=	{SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
-	[ARCLW]=	{SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
-
-	[ARCRB]=	{SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
-	[ARCRL]=	{SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
-	[ARCRW]=	{SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry | UseCarry},
-
-	[AREP]=		{OK, CX, CX},
-	[AREPN]=	{OK, CX, CX},
-
-	[ARET]=		{Break | KillCarry},
-
-	[AROLB]=	{SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry},
-	[AROLL]=	{SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry},
-	[AROLW]=	{SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry},
-
-	[ARORB]=	{SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry},
-	[ARORL]=	{SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry},
-	[ARORW]=	{SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry},
-
-	[ASAHF]=	{OK, AX, AX},
-
-	[ASALB]=	{SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry},
-	[ASALL]=	{SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry},
-	[ASALW]=	{SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry},
-
-	[ASARB]=	{SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry},
-	[ASARL]=	{SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry},
-	[ASARW]=	{SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry},
-
-	[ASBBB]=	{SizeB | LeftRead | RightRdwr | SetCarry | UseCarry},
-	[ASBBL]=	{SizeL | LeftRead | RightRdwr | SetCarry | UseCarry},
-	[ASBBW]=	{SizeW | LeftRead | RightRdwr | SetCarry | UseCarry},
-
-	[ASETCC]=	{SizeB | RightRdwr | UseCarry},
-	[ASETCS]=	{SizeB | RightRdwr | UseCarry},
-	[ASETEQ]=	{SizeB | RightRdwr | UseCarry},
-	[ASETGE]=	{SizeB | RightRdwr | UseCarry},
-	[ASETGT]=	{SizeB | RightRdwr | UseCarry},
-	[ASETHI]=	{SizeB | RightRdwr | UseCarry},
-	[ASETLE]=	{SizeB | RightRdwr | UseCarry},
-	[ASETLS]=	{SizeB | RightRdwr | UseCarry},
-	[ASETLT]=	{SizeB | RightRdwr | UseCarry},
-	[ASETMI]=	{SizeB | RightRdwr | UseCarry},
-	[ASETNE]=	{SizeB | RightRdwr | UseCarry},
-	[ASETOC]=	{SizeB | RightRdwr | UseCarry},
-	[ASETOS]=	{SizeB | RightRdwr | UseCarry},
-	[ASETPC]=	{SizeB | RightRdwr | UseCarry},
-	[ASETPL]=	{SizeB | RightRdwr | UseCarry},
-	[ASETPS]=	{SizeB | RightRdwr | UseCarry},
-
-	[ASHLB]=	{SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry},
-	[ASHLL]=	{SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry},
-	[ASHLW]=	{SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry},
-
-	[ASHRB]=	{SizeB | LeftRead | RightRdwr | ShiftCX | SetCarry},
-	[ASHRL]=	{SizeL | LeftRead | RightRdwr | ShiftCX | SetCarry},
-	[ASHRW]=	{SizeW | LeftRead | RightRdwr | ShiftCX | SetCarry},
-
-	[ASTOSB]=	{OK, AX|DI, DI},
-	[ASTOSL]=	{OK, AX|DI, DI},
-	[ASTOSW]=	{OK, AX|DI, DI},
-	[ADUFFZERO]=	{OK, AX|DI, DI},
-
-	[ASUBB]=	{SizeB | LeftRead | RightRdwr | SetCarry},
-	[ASUBL]=	{SizeL | LeftRead | RightRdwr | SetCarry},
-	[ASUBW]=	{SizeW | LeftRead | RightRdwr | SetCarry},
-
-	[ASUBSD]=	{SizeD | LeftRead | RightRdwr},
-	[ASUBSS]=	{SizeF | LeftRead | RightRdwr},
-
-	[ATESTB]=	{SizeB | LeftRead | RightRead | SetCarry},
-	[ATESTL]=	{SizeL | LeftRead | RightRead | SetCarry},
-	[ATESTW]=	{SizeW | LeftRead | RightRead | SetCarry},
-
-	[AUCOMISD]=	{SizeD | LeftRead | RightRead},
-	[AUCOMISS]=	{SizeF | LeftRead | RightRead},
-
-	[AXCHGB]=	{SizeB | LeftRdwr | RightRdwr},
-	[AXCHGL]=	{SizeL | LeftRdwr | RightRdwr},
-	[AXCHGW]=	{SizeW | LeftRdwr | RightRdwr},
-
-	[AXORB]=	{SizeB | LeftRead | RightRdwr | SetCarry},
-	[AXORL]=	{SizeL | LeftRead | RightRdwr | SetCarry},
-	[AXORW]=	{SizeW | LeftRead | RightRdwr | SetCarry},
-};
-
-void
-proginfo(ProgInfo *info, Prog *p)
-{
-	*info = progtable[p->as];
-	if(info->flags == 0)
-		fatal("unknown instruction %P", p);
-
-	if((info->flags & ShiftCX) && p->from.type != D_CONST)
-		info->reguse |= CX;
-
-	if(info->flags & ImulAXDX) {
-		if(p->to.type == D_NONE) {
-			info->reguse |= AX;
-			info->regset |= AX | DX;
-		} else {
-			info->flags |= RightRdwr;
-		}
-	}
-
-	// Addressing makes some registers used.
-	if(p->from.type >= D_INDIR)
-		info->regindex |= RtoB(p->from.type-D_INDIR);
-	if(p->from.index != D_NONE)
-		info->regindex |= RtoB(p->from.index);
-	if(p->to.type >= D_INDIR)
-		info->regindex |= RtoB(p->to.type-D_INDIR);
-	if(p->to.index != D_NONE)
-		info->regindex |= RtoB(p->to.index);
-}
diff --git a/src/cmd/8g/reg.c b/src/cmd/8g/reg.c
deleted file mode 100644
index 302b273..0000000
--- a/src/cmd/8g/reg.c
+++ /dev/null
@@ -1,1284 +0,0 @@
-// 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 at 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 at 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.
-
-#include <u.h>
-#include <libc.h>
-#include "gg.h"
-#include "opt.h"
-
-#define	NREGVAR	16	/* 8 integer + 8 floating */
-#define	REGBITS	((uint32)0xffff)
-/*c2go enum {
-	NREGVAR = 16,
-	REGBITS = (1<<NREGVAR) - 1,
-};
-*/
-
-static	Reg*	firstr;
-static	int	first	= 1;
-
-int
-rcmp(const void *a1, const void *a2)
-{
-	Rgn *p1, *p2;
-	int c1, c2;
-
-	p1 = (Rgn*)a1;
-	p2 = (Rgn*)a2;
-	c1 = p2->cost;
-	c2 = p1->cost;
-	if(c1 -= c2)
-		return c1;
-	return p2->varno - p1->varno;
-}
-
-static void
-setaddrs(Bits bit)
-{
-	int i, n;
-	Var *v;
-	Node *node;
-
-	while(bany(&bit)) {
-		// convert each bit to a variable
-		i = bnum(bit);
-		node = var[i].node;
-		n = var[i].name;
-		bit.b[i/32] &= ~(1L<<(i%32));
-
-		// disable all pieces of that variable
-		for(i=0; i<nvar; i++) {
-			v = var+i;
-			if(v->node == node && v->name == n)
-				v->addr = 2;
-		}
-	}
-}
-
-static char* regname[] = {
-	".ax", ".cx", ".dx", ".bx", ".sp", ".bp", ".si", ".di",
-	".x0", ".x1", ".x2", ".x3", ".x4", ".x5", ".x6", ".x7",
-};
-
-static Node* regnodes[NREGVAR];
-
-static void walkvardef(Node *n, Reg *r, int active);
-
-void
-regopt(Prog *firstp)
-{
-	Reg *r, *r1;
-	Prog *p;
-	Graph *g;
-	ProgInfo info;
-	int i, z, active;
-	uint32 vreg;
-	Bits bit;
-
-	if(first) {
-		fmtinstall('Q', Qconv);
-		exregoffset = D_DI;	// no externals
-		first = 0;
-	}
-
-	mergetemp(firstp);
-
-	/*
-	 * control flow is more complicated in generated go code
-	 * than in generated c code.  define pseudo-variables for
-	 * registers, so we have complete register usage information.
-	 */
-	nvar = NREGVAR;
-	memset(var, 0, NREGVAR*sizeof var[0]);
-	for(i=0; i<NREGVAR; i++) {
-		if(regnodes[i] == N)
-			regnodes[i] = newname(lookup(regname[i]));
-		var[i].node = regnodes[i];
-	}
-
-	regbits = RtoB(D_SP);
-	for(z=0; z<BITS; z++) {
-		externs.b[z] = 0;
-		params.b[z] = 0;
-		consts.b[z] = 0;
-		addrs.b[z] = 0;
-		ivar.b[z] = 0;
-		ovar.b[z] = 0;
-	}
-
-	/*
-	 * pass 1
-	 * build aux data structure
-	 * allocate pcs
-	 * find use and set of variables
-	 */
-	g = flowstart(firstp, sizeof(Reg));
-	if(g == nil) {
-		for(i=0; i<nvar; i++)
-			var[i].node->opt = nil;
-		return;
-	}
-
-	firstr = (Reg*)g->start;
-
-	for(r = firstr; r != R; r = (Reg*)r->f.link) {
-		p = r->f.prog;
-		if(p->as == AVARDEF || p->as == AVARKILL)
-			continue;
-		proginfo(&info, p);
-
-		// Avoid making variables for direct-called functions.
-		if(p->as == ACALL && p->to.type == D_EXTERN)
-			continue;
-
-		r->use1.b[0] |= info.reguse | info.regindex;
-		r->set.b[0] |= info.regset;
-
-		bit = mkvar(r, &p->from);
-		if(bany(&bit)) {
-			if(info.flags & LeftAddr)
-				setaddrs(bit);
-			if(info.flags & LeftRead)
-				for(z=0; z<BITS; z++)
-					r->use1.b[z] |= bit.b[z];
-			if(info.flags & LeftWrite)
-				for(z=0; z<BITS; z++)
-					r->set.b[z] |= bit.b[z];
-		}
-
-		bit = mkvar(r, &p->to);
-		if(bany(&bit)) {	
-			if(info.flags & RightAddr)
-				setaddrs(bit);
-			if(info.flags & RightRead)
-				for(z=0; z<BITS; z++)
-					r->use2.b[z] |= bit.b[z];
-			if(info.flags & RightWrite)
-				for(z=0; z<BITS; z++)
-					r->set.b[z] |= bit.b[z];
-		}
-	}
-	if(firstr == R)
-		return;
-
-	for(i=0; i<nvar; i++) {
-		Var *v = var+i;
-		if(v->addr) {
-			bit = blsh(i);
-			for(z=0; z<BITS; z++)
-				addrs.b[z] |= bit.b[z];
-		}
-
-		if(debug['R'] && debug['v'])
-			print("bit=%2d addr=%d et=%-6E w=%-2d s=%N + %lld\n",
-				i, v->addr, v->etype, v->width, v->node, v->offset);
-	}
-
-	if(debug['R'] && debug['v'])
-		dumpit("pass1", &firstr->f, 1);
-
-	/*
-	 * pass 2
-	 * find looping structure
-	 */
-	flowrpo(g);
-
-	if(debug['R'] && debug['v'])
-		dumpit("pass2", &firstr->f, 1);
-
-	/*
-	 * pass 2.5
-	 * iterate propagating fat vardef covering forward
-	 * r->act records vars with a VARDEF since the last CALL.
-	 * (r->act will be reused in pass 5 for something else,
-	 * but we'll be done with it by then.)
-	 */
-	active = 0;
-	for(r = firstr; r != R; r = (Reg*)r->f.link) {
-		r->f.active = 0;
-		r->act = zbits;
-	}
-	for(r = firstr; r != R; r = (Reg*)r->f.link) {
-		p = r->f.prog;
-		if(p->as == AVARDEF && isfat(p->to.node->type) && p->to.node->opt != nil) {
-			active++;
-			walkvardef(p->to.node, r, active);
-		}
-	}
-
-	/*
-	 * pass 3
-	 * iterate propagating usage
-	 * 	back until flow graph is complete
-	 */
-loop1:
-	change = 0;
-	for(r = firstr; r != R; r = (Reg*)r->f.link)
-		r->f.active = 0;
-	for(r = firstr; r != R; r = (Reg*)r->f.link)
-		if(r->f.prog->as == ARET)
-			prop(r, zbits, zbits);
-loop11:
-	/* pick up unreachable code */
-	i = 0;
-	for(r = firstr; r != R; r = r1) {
-		r1 = (Reg*)r->f.link;
-		if(r1 && r1->f.active && !r->f.active) {
-			prop(r, zbits, zbits);
-			i = 1;
-		}
-	}
-	if(i)
-		goto loop11;
-	if(change)
-		goto loop1;
-
-	if(debug['R'] && debug['v'])
-		dumpit("pass3", &firstr->f, 1);
-
-	/*
-	 * pass 4
-	 * iterate propagating register/variable synchrony
-	 * 	forward until graph is complete
-	 */
-loop2:
-	change = 0;
-	for(r = firstr; r != R; r = (Reg*)r->f.link)
-		r->f.active = 0;
-	synch(firstr, zbits);
-	if(change)
-		goto loop2;
-
-	if(debug['R'] && debug['v'])
-		dumpit("pass4", &firstr->f, 1);
-
-	/*
-	 * pass 4.5
-	 * move register pseudo-variables into regu.
-	 */
-	for(r = firstr; r != R; r = (Reg*)r->f.link) {
-		r->regu = (r->refbehind.b[0] | r->set.b[0]) & REGBITS;
-
-		r->set.b[0] &= ~REGBITS;
-		r->use1.b[0] &= ~REGBITS;
-		r->use2.b[0] &= ~REGBITS;
-		r->refbehind.b[0] &= ~REGBITS;
-		r->refahead.b[0] &= ~REGBITS;
-		r->calbehind.b[0] &= ~REGBITS;
-		r->calahead.b[0] &= ~REGBITS;
-		r->regdiff.b[0] &= ~REGBITS;
-		r->act.b[0] &= ~REGBITS;
-	}
-
-	/*
-	 * pass 5
-	 * isolate regions
-	 * calculate costs (paint1)
-	 */
-	r = firstr;
-	if(r) {
-		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]);
-		if(bany(&bit) && !r->f.refset) {
-			// should never happen - all variables are preset
-			if(debug['w'])
-				print("%L: used and not set: %Q\n", r->f.prog->lineno, bit);
-			r->f.refset = 1;
-		}
-	}
-	for(r = firstr; r != R; r = (Reg*)r->f.link)
-		r->act = zbits;
-	rgp = region;
-	nregion = 0;
-	for(r = firstr; r != R; r = (Reg*)r->f.link) {
-		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) && !r->f.refset) {
-			if(debug['w'])
-				print("%L: set and not used: %Q\n", r->f.prog->lineno, bit);
-			r->f.refset = 1;
-			excise(&r->f);
-		}
-		for(z=0; z<BITS; z++)
-			bit.b[z] = LOAD(r) & ~(r->act.b[z] | addrs.b[z]);
-		while(bany(&bit)) {
-			i = bnum(bit);
-			rgp->enter = r;
-			rgp->varno = i;
-			change = 0;
-			paint1(r, i);
-			bit.b[i/32] &= ~(1L<<(i%32));
-			if(change <= 0)
-				continue;
-			rgp->cost = change;
-			nregion++;
-			if(nregion >= NRGN) {
-				if(debug['R'] && debug['v'])
-					print("too many regions\n");
-				goto brk;
-			}
-			rgp++;
-		}
-	}
-brk:
-	qsort(region, nregion, sizeof(region[0]), rcmp);
-
-	/*
-	 * pass 6
-	 * determine used registers (paint2)
-	 * replace code (paint3)
-	 */
-	rgp = region;
-	for(i=0; i<nregion; i++) {
-		bit = blsh(rgp->varno);
-		vreg = paint2(rgp->enter, rgp->varno);
-		vreg = allreg(vreg, rgp);
-		if(rgp->regno != 0)
-			paint3(rgp->enter, rgp->varno, vreg, rgp->regno);
-		rgp++;
-	}
-
-	if(debug['R'] && debug['v'])
-		dumpit("pass6", &firstr->f, 1);
-
-	/*
-	 * free aux structures. peep allocates new ones.
-	 */
-	for(i=0; i<nvar; i++)
-		var[i].node->opt = nil;
-	flowend(g);
-	firstr = R;
-
-	/*
-	 * pass 7
-	 * peep-hole on basic block
-	 */
-	if(!debug['R'] || debug['P'])
-		peep(firstp);
-
-	/*
-	 * eliminate nops
-	 */
-	for(p=firstp; p!=P; p=p->link) {
-		while(p->link != P && p->link->as == ANOP)
-			p->link = p->link->link;
-		if(p->to.type == D_BRANCH)
-			while(p->to.u.branch != P && p->to.u.branch->as == ANOP)
-				p->to.u.branch = p->to.u.branch->link;
-	}
-
-	if(!use_sse)
-	for(p=firstp; p!=P; p=p->link) {
-		if(p->from.type >= D_X0 && p->from.type <= D_X7)
-			fatal("invalid use of %R with GO386=387: %P", p->from.type, p);
-		if(p->to.type >= D_X0 && p->to.type <= D_X7)
-			fatal("invalid use of %R with GO386=387: %P", p->to.type, p);
-	}
-
-	if(debug['R']) {
-		if(ostats.ncvtreg ||
-		   ostats.nspill ||
-		   ostats.nreload ||
-		   ostats.ndelmov ||
-		   ostats.nvar ||
-		   ostats.naddr ||
-		   0)
-			print("\nstats\n");
-
-		if(ostats.ncvtreg)
-			print("	%4d cvtreg\n", ostats.ncvtreg);
-		if(ostats.nspill)
-			print("	%4d spill\n", ostats.nspill);
-		if(ostats.nreload)
-			print("	%4d reload\n", ostats.nreload);
-		if(ostats.ndelmov)
-			print("	%4d delmov\n", ostats.ndelmov);
-		if(ostats.nvar)
-			print("	%4d var\n", ostats.nvar);
-		if(ostats.naddr)
-			print("	%4d addr\n", ostats.naddr);
-
-		memset(&ostats, 0, sizeof(ostats));
-	}
-}
-
-static void
-walkvardef(Node *n, Reg *r, int active)
-{
-	Reg *r1, *r2;
-	int bn;
-	Var *v;
-	
-	for(r1=r; r1!=R; r1=(Reg*)r1->f.s1) {
-		if(r1->f.active == active)
-			break;
-		r1->f.active = active;
-		if(r1->f.prog->as == AVARKILL && r1->f.prog->to.node == n)
-			break;
-		for(v=n->opt; v!=nil; v=v->nextinnode) {
-			bn = v - var;
-			r1->act.b[bn/32] |= 1L << (bn%32);
-		}
-		if(r1->f.prog->as == ACALL)
-			break;
-	}
-
-	for(r2=r; r2!=r1; r2=(Reg*)r2->f.s1)
-		if(r2->f.s2 != nil)
-			walkvardef(n, (Reg*)r2->f.s2, active);
-}
-
-/*
- * add mov b,rn
- * just after r
- */
-void
-addmove(Reg *r, int bn, int rn, int f)
-{
-	Prog *p, *p1;
-	Adr *a;
-	Var *v;
-
-	p1 = mal(sizeof(*p1));
-	clearp(p1);
-	p1->pc = 9999;
-
-	p = r->f.prog;
-	p1->link = p->link;
-	p->link = p1;
-	p1->lineno = p->lineno;
-
-	v = var + bn;
-
-	a = &p1->to;
-	a->offset = v->offset;
-	a->etype = v->etype;
-	a->type = v->name;
-	a->node = v->node;
-	a->sym = linksym(v->node->sym);
-
-	// need to clean this up with wptr and
-	// some of the defaults
-	p1->as = AMOVL;
-	switch(v->etype) {
-	default:
-		fatal("unknown type %E", v->etype);
-	case TINT8:
-	case TUINT8:
-	case TBOOL:
-		p1->as = AMOVB;
-		break;
-	case TINT16:
-	case TUINT16:
-		p1->as = AMOVW;
-		break;
-	case TFLOAT32:
-		p1->as = AMOVSS;
-		break;
-	case TFLOAT64:
-		p1->as = AMOVSD;
-		break;
-	case TINT:
-	case TUINT:
-	case TINT32:
-	case TUINT32:
-	case TPTR32:
-		break;
-	}
-
-	p1->from.type = rn;
-	if(!f) {
-		p1->from = *a;
-		*a = zprog.from;
-		a->type = rn;
-		if(v->etype == TUINT8)
-			p1->as = AMOVB;
-		if(v->etype == TUINT16)
-			p1->as = AMOVW;
-	}
-	if(debug['R'] && debug['v'])
-		print("%P ===add=== %P\n", p, p1);
-	ostats.nspill++;
-}
-
-uint32
-doregbits(int r)
-{
-	uint32 b;
-
-	b = 0;
-	if(r >= D_INDIR)
-		r -= D_INDIR;
-	if(r >= D_AX && r <= D_DI)
-		b |= RtoB(r);
-	else
-	if(r >= D_AL && r <= D_BL)
-		b |= RtoB(r-D_AL+D_AX);
-	else
-	if(r >= D_AH && r <= D_BH)
-		b |= RtoB(r-D_AH+D_AX);
-	else
-	if(r >= D_X0 && r <= D_X0+7)
-		b |= FtoB(r);
-	return b;
-}
-
-static int
-overlap(int32 o1, int w1, int32 o2, int w2)
-{
-	int32 t1, t2;
-
-	t1 = o1+w1;
-	t2 = o2+w2;
-
-	if(!(t1 > o2 && t2 > o1))
-		return 0;
-
-	return 1;
-}
-
-Bits
-mkvar(Reg *r, Adr *a)
-{
-	Var *v;
-	int i, t, n, et, z, w, flag, regu;
-	int32 o;
-	Bits bit;
-	Node *node;
-
-	/*
-	 * mark registers used
-	 */
-	t = a->type;
-	if(t == D_NONE)
-		goto none;
-
-	if(r != R)
-		r->use1.b[0] |= doregbits(a->index);
-
-	switch(t) {
-	default:
-		regu = doregbits(t);
-		if(regu == 0)
-			goto none;
-		bit = zbits;
-		bit.b[0] = regu;
-		return bit;
-
-	case D_ADDR:
-		a->type = a->index;
-		bit = mkvar(r, a);
-		setaddrs(bit);
-		a->type = t;
-		ostats.naddr++;
-		goto none;
-
-	case D_EXTERN:
-	case D_STATIC:
-	case D_PARAM:
-	case D_AUTO:
-		n = t;
-		break;
-	}
-
-	node = a->node;
-	if(node == N || node->op != ONAME || node->orig == N)
-		goto none;
-	node = node->orig;
-	if(node->orig != node)
-		fatal("%D: bad node", a);
-	if(node->sym == S || node->sym->name[0] == '.')
-		goto none;
-	et = a->etype;
-	o = a->offset;
-	w = a->width;
-	if(w < 0)
-		fatal("bad width %d for %D", w, a);
-
-	flag = 0;
-	for(i=0; i<nvar; i++) {
-		v = var+i;
-		if(v->node == node && v->name == n) {
-			if(v->offset == o)
-			if(v->etype == et)
-			if(v->width == w)
-				return blsh(i);
-
-			// if they overlap, disable both
-			if(overlap(v->offset, v->width, o, w)) {
-				if(debug['R'])
-					print("disable %s\n", node->sym->name);
-				v->addr = 1;
-				flag = 1;
-			}
-		}
-	}
-
-	switch(et) {
-	case 0:
-	case TFUNC:
-		goto none;
-	}
-
-	if(nvar >= NVAR) {
-		if(debug['w'] > 1 && node != N)
-			fatal("variable not optimized: %D", a);
-		
-		// 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
-		// live at all calls. otherwise we might optimize away part of
-		// a variable but not all of it.
-		for(i=0; i<nvar; i++) {
-			v = var+i;
-			if(v->node == node)
-				v->addr = 1;
-		}
-		goto none;
-	}
-
-	i = nvar;
-	nvar++;
-	v = var+i;
-	v->offset = o;
-	v->name = n;
-	v->etype = et;
-	v->width = w;
-	v->addr = flag;		// funny punning
-	v->node = node;
-	
-	// node->opt is the head of a linked list
-	// of Vars within the given Node, so that
-	// we can start at a Var and find all the other
-	// Vars in the same Go variable.
-	v->nextinnode = node->opt;
-	node->opt = v;
-
-	bit = blsh(i);
-	if(n == D_EXTERN || n == D_STATIC)
-		for(z=0; z<BITS; z++)
-			externs.b[z] |= bit.b[z];
-	if(n == D_PARAM)
-		for(z=0; z<BITS; z++)
-			params.b[z] |= bit.b[z];
-		
-	if(node->class == PPARAM)
-		for(z=0; z<BITS; z++)
-			ivar.b[z] |= bit.b[z];
-	if(node->class == PPARAMOUT)
-		for(z=0; z<BITS; z++)
-			ovar.b[z] |= bit.b[z];
-
-	// Treat values with their address taken as live at calls,
-	// because the garbage collector's liveness analysis in ../gc/plive.c does.
-	// These must be consistent or else we will elide stores and the garbage
-	// collector will see uninitialized data.
-	// The typical case where our own analysis is out of sync is when the
-	// node appears to have its address taken but that code doesn't actually
-	// get generated and therefore doesn't show up as an address being
-	// taken when we analyze the instruction stream.
-	// One instance of this case is when a closure uses the same name as
-	// an outer variable for one of its own variables declared with :=.
-	// The parser flags the outer variable as possibly shared, and therefore
-	// sets addrtaken, even though it ends up not being actually shared.
-	// 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)
-		v->addr = 1;
-
-	// Disable registerization for globals, because:
-	// (1) we might panic at any time and we want the recovery code
-	// to see the latest values (issue 1304).
-	// (2) we don't know what pointers might point at them and we want
-	// loads via those pointers to see updated values and vice versa (issue 7995).
-	//
-	// Disable registerization for results if using defer, because the deferred func
-	// might recover and return, causing the current values to be used.
-	if(node->class == PEXTERN || (hasdefer && node->class == PPARAMOUT))
-		v->addr = 1;
-
-	if(debug['R'])
-		print("bit=%2d et=%2E w=%d+%d %#N %D flag=%d\n", i, et, o, w, node, a, v->addr);
-	ostats.nvar++;
-
-	return bit;
-
-none:
-	return zbits;
-}
-
-void
-prop(Reg *r, Bits ref, Bits cal)
-{
-	Reg *r1, *r2;
-	int z, i, j;
-	Var *v, *v1;
-
-	for(r1 = r; r1 != R; r1 = (Reg*)r1->f.p1) {
-		for(z=0; z<BITS; z++) {
-			ref.b[z] |= r1->refahead.b[z];
-			if(ref.b[z] != r1->refahead.b[z]) {
-				r1->refahead.b[z] = ref.b[z];
-				change++;
-			}
-			cal.b[z] |= r1->calahead.b[z];
-			if(cal.b[z] != r1->calahead.b[z]) {
-				r1->calahead.b[z] = cal.b[z];
-				change++;
-			}
-		}
-		switch(r1->f.prog->as) {
-		case ACALL:
-			if(noreturn(r1->f.prog))
-				break;
-
-			// Mark all input variables (ivar) as used, because that's what the
-			// liveness bitmaps say. The liveness bitmaps say that so that a
-			// panic will not show stale values in the parameter dump.
-			// Mark variables with a recent VARDEF (r1->act) as used,
-			// so that the optimizer flushes initializations to memory,
-			// so that if a garbage collection happens during this CALL,
-			// the collector will see initialized memory. Again this is to
-			// match what the liveness bitmaps say.
-			for(z=0; z<BITS; z++) {
-				cal.b[z] |= ref.b[z] | externs.b[z] | ivar.b[z] | r1->act.b[z];
-				ref.b[z] = 0;
-			}
-			
-			// cal.b is the current approximation of what's live across the call.
-			// Every bit in cal.b is a single stack word. For each such word,
-			// find all the other tracked stack words in the same Go variable
-			// (struct/slice/string/interface) and mark them live too.
-			// This is necessary because the liveness analysis for the garbage
-			// collector works at variable granularity, not at word granularity.
-			// It is fundamental for slice/string/interface: the garbage collector
-			// needs the whole value, not just some of the words, in order to
-			// interpret the other bits correctly. Specifically, slice needs a consistent
-			// ptr and cap, string needs a consistent ptr and len, and interface
-			// needs a consistent type word and data word.
-			for(z=0; z<BITS; z++) {
-				if(cal.b[z] == 0)
-					continue;
-				for(i=0; i<32; i++) {
-					if(z*32+i >= nvar || ((cal.b[z]>>i)&1) == 0)
-						continue;
-					v = var+z*32+i;
-					if(v->node->opt == nil) // v represents fixed register, not Go variable
-						continue;
-
-					// v->node->opt is the head of a linked list of Vars
-					// corresponding to tracked words from the Go variable v->node.
-					// Walk the list and set all the bits.
-					// For a large struct this could end up being quadratic:
-					// after the first setting, the outer loop (for z, i) would see a 1 bit
-					// for all of the remaining words in the struct, and for each such
-					// word would go through and turn on all the bits again.
-					// To avoid the quadratic behavior, we only turn on the bits if
-					// v is the head of the list or if the head's bit is not yet turned on.
-					// This will set the bits at most twice, keeping the overall loop linear.
-					v1 = v->node->opt;
-					j = v1 - var;
-					if(v == v1 || ((cal.b[j/32]>>(j&31))&1) == 0) {
-						for(; v1 != nil; v1 = v1->nextinnode) {
-							j = v1 - var;
-							cal.b[j/32] |= 1<<(j&31);
-						}
-					}
-				}
-			}
-			break;
-
-		case ATEXT:
-			for(z=0; z<BITS; z++) {
-				cal.b[z] = 0;
-				ref.b[z] = 0;
-			}
-			break;
-
-		case ARET:
-			for(z=0; z<BITS; z++) {
-				cal.b[z] = externs.b[z] | ovar.b[z];
-				ref.b[z] = 0;
-			}
-			break;
-		}
-		for(z=0; z<BITS; z++) {
-			ref.b[z] = (ref.b[z] & ~r1->set.b[z]) |
-				r1->use1.b[z] | r1->use2.b[z];
-			cal.b[z] &= ~(r1->set.b[z] | r1->use1.b[z] | r1->use2.b[z]);
-			r1->refbehind.b[z] = ref.b[z];
-			r1->calbehind.b[z] = cal.b[z];
-		}
-		if(r1->f.active)
-			break;
-		r1->f.active = 1;
-	}
-	for(; r != r1; r = (Reg*)r->f.p1)
-		for(r2 = (Reg*)r->f.p2; r2 != R; r2 = (Reg*)r2->f.p2link)
-			prop(r2, r->refbehind, r->calbehind);
-}
-
-void
-synch(Reg *r, Bits dif)
-{
-	Reg *r1;
-	int z;
-
-	for(r1 = r; r1 != R; r1 = (Reg*)r1->f.s1) {
-		for(z=0; z<BITS; z++) {
-			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++;
-			}
-		}
-		if(r1->f.active)
-			break;
-		r1->f.active = 1;
-		for(z=0; z<BITS; z++)
-			dif.b[z] &= ~(~r1->calbehind.b[z] & r1->calahead.b[z]);
-		if((Reg*)r1->f.s2 != R)
-			synch((Reg*)r1->f.s2, dif);
-	}
-}
-
-uint32
-allreg(uint32 b, Rgn *r)
-{
-	Var *v;
-	int i;
-
-	v = var + r->varno;
-	r->regno = 0;
-	switch(v->etype) {
-
-	default:
-		fatal("unknown etype %d/%E", bitno(b), v->etype);
-		break;
-
-	case TINT8:
-	case TUINT8:
-	case TINT16:
-	case TUINT16:
-	case TINT32:
-	case TUINT32:
-	case TINT64:
-	case TINT:
-	case TUINT:
-	case TUINTPTR:
-	case TBOOL:
-	case TPTR32:
-		i = BtoR(~b);
-		if(i && r->cost > 0) {
-			r->regno = i;
-			return RtoB(i);
-		}
-		break;
-
-	case TFLOAT32:
-	case TFLOAT64:
-		if(!use_sse)
-			break;
-		i = BtoF(~b);
-		if(i && r->cost > 0) {
-			r->regno = i;
-			return FtoB(i);
-		}
-		break;
-	}
-	return 0;
-}
-
-void
-paint1(Reg *r, int bn)
-{
-	Reg *r1;
-	Prog *p;
-	int z;
-	uint32 bb;
-
-	z = bn/32;
-	bb = 1L<<(bn%32);
-	if(r->act.b[z] & bb)
-		return;
-	for(;;) {
-		if(!(r->refbehind.b[z] & bb))
-			break;
-		r1 = (Reg*)r->f.p1;
-		if(r1 == R)
-			break;
-		if(!(r1->refahead.b[z] & bb))
-			break;
-		if(r1->act.b[z] & bb)
-			break;
-		r = r1;
-	}
-
-	if(LOAD(r) & ~(r->set.b[z]&~(r->use1.b[z]|r->use2.b[z])) & bb) {
-		change -= CLOAD * r->f.loop;
-	}
-	for(;;) {
-		r->act.b[z] |= bb;
-		p = r->f.prog;
-
-		if(r->f.prog->as != ANOP) { // don't give credit for NOPs
-			if(r->use1.b[z] & bb) {
-				change += CREF * r->f.loop;
-				if(p->as == AFMOVL || p->as == AFMOVW)
-					if(BtoR(bb) != D_F0)
-						change = -CINF;
-			}
-			if((r->use2.b[z]|r->set.b[z]) & bb) {
-				change += CREF * r->f.loop;
-				if(p->as == AFMOVL || p->as == AFMOVW)
-					if(BtoR(bb) != D_F0)
-						change = -CINF;
-			}
-		}
-
-		if(STORE(r) & r->regdiff.b[z] & bb) {
-			change -= CLOAD * r->f.loop;
-			if(p->as == AFMOVL || p->as == AFMOVW)
-				if(BtoR(bb) != D_F0)
-					change = -CINF;
-		}
-
-		if(r->refbehind.b[z] & bb)
-			for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link)
-				if(r1->refahead.b[z] & bb)
-					paint1(r1, bn);
-
-		if(!(r->refahead.b[z] & bb))
-			break;
-		r1 = (Reg*)r->f.s2;
-		if(r1 != R)
-			if(r1->refbehind.b[z] & bb)
-				paint1(r1, bn);
-		r = (Reg*)r->f.s1;
-		if(r == R)
-			break;
-		if(r->act.b[z] & bb)
-			break;
-		if(!(r->refbehind.b[z] & bb))
-			break;
-	}
-}
-
-uint32
-regset(Reg *r, uint32 bb)
-{
-	uint32 b, set;
-	Adr v;
-	int c;
-
-	set = 0;
-	v = zprog.from;
-	while(b = bb & ~(bb-1)) {
-		v.type = b & 0xFF ? BtoR(b): BtoF(b);
-		c = copyu(r->f.prog, &v, nil);
-		if(c == 3)
-			set |= b;
-		bb &= ~b;
-	}
-	return set;
-}
-
-uint32
-reguse(Reg *r, uint32 bb)
-{
-	uint32 b, set;
-	Adr v;
-	int c;
-
-	set = 0;
-	v = zprog.from;
-	while(b = bb & ~(bb-1)) {
-		v.type = b & 0xFF ? BtoR(b): BtoF(b);
-		c = copyu(r->f.prog, &v, nil);
-		if(c == 1 || c == 2 || c == 4)
-			set |= b;
-		bb &= ~b;
-	}
-	return set;
-}
-
-uint32
-paint2(Reg *r, int bn)
-{
-	Reg *r1;
-	int z;
-	uint32 bb, vreg, x;
-
-	z = bn/32;
-	bb = 1L << (bn%32);
-	vreg = regbits;
-	if(!(r->act.b[z] & bb))
-		return vreg;
-	for(;;) {
-		if(!(r->refbehind.b[z] & bb))
-			break;
-		r1 = (Reg*)r->f.p1;
-		if(r1 == R)
-			break;
-		if(!(r1->refahead.b[z] & bb))
-			break;
-		if(!(r1->act.b[z] & bb))
-			break;
-		r = r1;
-	}
-	for(;;) {
-		r->act.b[z] &= ~bb;
-
-		vreg |= r->regu;
-
-		if(r->refbehind.b[z] & bb)
-			for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link)
-				if(r1->refahead.b[z] & bb)
-					vreg |= paint2(r1, bn);
-
-		if(!(r->refahead.b[z] & bb))
-			break;
-		r1 = (Reg*)r->f.s2;
-		if(r1 != R)
-			if(r1->refbehind.b[z] & bb)
-				vreg |= paint2(r1, bn);
-		r = (Reg*)r->f.s1;
-		if(r == R)
-			break;
-		if(!(r->act.b[z] & bb))
-			break;
-		if(!(r->refbehind.b[z] & bb))
-			break;
-	}
-
-	bb = vreg;
-	for(; r; r=(Reg*)r->f.s1) {
-		x = r->regu & ~bb;
-		if(x) {
-			vreg |= reguse(r, x);
-			bb |= regset(r, x);
-		}
-	}
-	return vreg;
-}
-
-void
-paint3(Reg *r, int bn, int32 rb, int rn)
-{
-	Reg *r1;
-	Prog *p;
-	int z;
-	uint32 bb;
-
-	z = bn/32;
-	bb = 1L << (bn%32);
-	if(r->act.b[z] & bb)
-		return;
-	for(;;) {
-		if(!(r->refbehind.b[z] & bb))
-			break;
-		r1 = (Reg*)r->f.p1;
-		if(r1 == R)
-			break;
-		if(!(r1->refahead.b[z] & bb))
-			break;
-		if(r1->act.b[z] & bb)
-			break;
-		r = r1;
-	}
-
-	if(LOAD(r) & ~(r->set.b[z] & ~(r->use1.b[z]|r->use2.b[z])) & bb)
-		addmove(r, bn, rn, 0);
-	for(;;) {
-		r->act.b[z] |= bb;
-		p = r->f.prog;
-
-		if(r->use1.b[z] & bb) {
-			if(debug['R'] && debug['v'])
-				print("%P", p);
-			addreg(&p->from, rn);
-			if(debug['R'] && debug['v'])
-				print(" ===change== %P\n", p);
-		}
-		if((r->use2.b[z]|r->set.b[z]) & bb) {
-			if(debug['R'] && debug['v'])
-				print("%P", p);
-			addreg(&p->to, rn);
-			if(debug['R'] && debug['v'])
-				print(" ===change== %P\n", p);
-		}
-
-		if(STORE(r) & r->regdiff.b[z] & bb)
-			addmove(r, bn, rn, 1);
-		r->regu |= rb;
-
-		if(r->refbehind.b[z] & bb)
-			for(r1 = (Reg*)r->f.p2; r1 != R; r1 = (Reg*)r1->f.p2link)
-				if(r1->refahead.b[z] & bb)
-					paint3(r1, bn, rb, rn);
-
-		if(!(r->refahead.b[z] & bb))
-			break;
-		r1 = (Reg*)r->f.s2;
-		if(r1 != R)
-			if(r1->refbehind.b[z] & bb)
-				paint3(r1, bn, rb, rn);
-		r = (Reg*)r->f.s1;
-		if(r == R)
-			break;
-		if(r->act.b[z] & bb)
-			break;
-		if(!(r->refbehind.b[z] & bb))
-			break;
-	}
-}
-
-void
-addreg(Adr *a, int rn)
-{
-	a->sym = nil;
-	a->node = nil;
-	a->offset = 0;
-	a->type = rn;
-
-	ostats.ncvtreg++;
-}
-
-int32
-RtoB(int r)
-{
-
-	if(r < D_AX || r > D_DI)
-		return 0;
-	return 1L << (r-D_AX);
-}
-
-int
-BtoR(int32 b)
-{
-
-	b &= 0xffL;
-	if(b == 0)
-		return 0;
-	return bitno(b) + D_AX;
-}
-
-int32
-FtoB(int f)
-{
-	if(f < D_X0 || f > D_X7)
-		return 0;
-	return 1L << (f - D_X0 + 8);
-}
-
-int
-BtoF(int32 b)
-{
-	b &= 0xFF00L;
-	if(b == 0)
-		return 0;
-	return bitno(b) - 8 + D_X0;
-}
-
-void
-dumpone(Flow *f, int isreg)
-{
-	int z;
-	Bits bit;
-	Reg *r;
-
-	print("%d:%P", f->loop, f->prog);
-	if(isreg) {
-		r = (Reg*)f;
-		for(z=0; z<BITS; z++)
-			bit.b[z] =
-				r->set.b[z] |
-				r->use1.b[z] |
-				r->use2.b[z] |
-				r->refbehind.b[z] |
-				r->refahead.b[z] |
-				r->calbehind.b[z] |
-				r->calahead.b[z] |
-				r->regdiff.b[z] |
-				r->act.b[z] |
-					0;
-		if(bany(&bit)) {
-			print("\t");
-			if(bany(&r->set))
-				print(" s:%Q", r->set);
-			if(bany(&r->use1))
-				print(" u1:%Q", r->use1);
-			if(bany(&r->use2))
-				print(" u2:%Q", r->use2);
-			if(bany(&r->refbehind))
-				print(" rb:%Q ", r->refbehind);
-			if(bany(&r->refahead))
-				print(" ra:%Q ", r->refahead);
-			if(bany(&r->calbehind))
-				print(" cb:%Q ", r->calbehind);
-			if(bany(&r->calahead))
-				print(" ca:%Q ", r->calahead);
-			if(bany(&r->regdiff))
-				print(" d:%Q ", r->regdiff);
-			if(bany(&r->act))
-				print(" a:%Q ", r->act);
-		}
-	}
-	print("\n");
-}
-
-void
-dumpit(char *str, Flow *r0, int isreg)
-{
-	Flow *r, *r1;
-
-	print("\n%s\n", str);
-	for(r = r0; r != nil; r = r->link) {
-		dumpone(r, isreg);
-		r1 = r->p2;
-		if(r1 != nil) {
-			print("	pred:");
-			for(; r1 != nil; r1 = r1->p2link)
-				print(" %.4ud", (int)r1->prog->pc);
-			print("\n");
-		}
-//		r1 = r->s1;
-//		if(r1 != nil) {
-//			print("	succ:");
-//			for(; r1 != R; r1 = r1->s1)
-//				print(" %.4ud", (int)r1->prog->pc);
-//			print("\n");
-//		}
-	}
-}
diff --git a/src/cmd/8l/8.out.h b/src/cmd/8l/8.out.h
deleted file mode 100644
index ed54f67..0000000
--- a/src/cmd/8l/8.out.h
+++ /dev/null
@@ -1,676 +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 at 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 at 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.
-
-#define	NSYM	50
-#define	NSNAME	8
-#include "../ld/textflag.h"
-
-enum
-{
-	AXXX,
-	AAAA,
-	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,
-	ACALL,
-	ACLC,
-	ACLD,
-	ACLI,
-	ACLTS,
-	ACMC,
-	ACMPB,
-	ACMPL,
-	ACMPW,
-	ACMPSB,
-	ACMPSL,
-	ACMPSW,
-	ADAA,
-	ADAS,
-	ADATA,
-	ADECB,
-	ADECL,
-	ADECW,
-	ADIVB,
-	ADIVL,
-	ADIVW,
-	AENTER,
-	AGLOBL,
-	AGOK,
-	AHISTORY,
-	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,
-	AJMP,
-	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,
-	ANAME,
-	ANEGB,
-	ANEGL,
-	ANEGW,
-	ANOP,
-	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,
-	ARET,
-	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,
-	ATEXT,
-	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,
-
-	AEND,
-
-	ADYNT_,
-	AINIT_,
-
-	ASIGNAME,
-
-	ACMPXCHGB,
-	ACMPXCHGL,
-	ACMPXCHGW,
-	ACMPXCHG8B,
-
-	ACPUID,
-	ARDTSC,
-
-	AXADDB,
-	AXADDL,
-	AXADDW,
-
-	/* conditional move */
-	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,
-	
-	AUNDEF,
-
-	// SSE2
-	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,
-
-	/* SSE 3+ */
-	AAESENC,
-	APINSRD,
-	APSHUFB,
-
-	AUSEFIELD,
-	ATYPE,
-	AFUNCDATA,
-	APCDATA,
-	ACHECKNIL,
-	AVARDEF,
-	AVARKILL,
-	ADUFFCOPY,
-	ADUFFZERO,
-	
-	ALAST
-};
-
-enum
-{
-	D_AL		= 0,
-	D_CL,
-	D_DL,
-	D_BL,
-
-	D_AH		= 4,
-	D_CH,
-	D_DH,
-	D_BH,
-
-	D_AX		= 8,
-	D_CX,
-	D_DX,
-	D_BX,
-	D_SP,
-	D_BP,
-	D_SI,
-	D_DI,
-
-	D_F0		= 16,
-	D_F7		= D_F0 + 7,
-
-	D_CS		= 24,
-	D_SS,
-	D_DS,
-	D_ES,
-	D_FS,
-	D_GS,
-
-	D_GDTR,		/* global descriptor table register */
-	D_IDTR,		/* interrupt descriptor table register */
-	D_LDTR,		/* local descriptor table register */
-	D_MSW,		/* machine status word */
-	D_TASK,		/* task register */
-
-	D_CR		= 35,
-	D_DR		= 43,
-	D_TR		= 51,
-
-	D_X0		= 59,
-	D_X1,
-	D_X2,
-	D_X3,
-	D_X4,
-	D_X5,
-	D_X6,
-	D_X7,
-	
-	D_TLS		= 67,
-	D_NONE		= 68,
-
-	D_BRANCH	= 69,
-	D_EXTERN	= 70,
-	D_STATIC	= 71,
-	D_AUTO		= 72,
-	D_PARAM		= 73,
-	D_CONST		= 74,
-	D_FCONST	= 75,
-	D_SCONST	= 76,
-	D_ADDR		= 77,
-
-	D_INDIR,	/* additive */
-
-	D_CONST2 = D_INDIR+D_INDIR,
-
-	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		= D_AX,
-	FREGRET		= D_F0,
-	REGSP		= D_SP,
-	REGTMP		= D_DI,
-};
-
-/*
- * this is the ranlib header
- */
-#define	SYMDEF	"__.GOSYMDEF"
diff --git a/src/cmd/8l/Makefile b/src/cmd/8l/Makefile
deleted file mode 100644
index 3f528d7..0000000
--- a/src/cmd/8l/Makefile
+++ /dev/null
@@ -1,5 +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.
-
-include ../../Make.dist
diff --git a/src/cmd/8l/asm.c b/src/cmd/8l/asm.c
deleted file mode 100644
index 98c0424..0000000
--- a/src/cmd/8l/asm.c
+++ /dev/null
@@ -1,745 +0,0 @@
-// 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 at 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 at 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.
-
-// Writing object files.
-
-#include	"l.h"
-#include	"../ld/lib.h"
-#include	"../ld/elf.h"
-#include	"../ld/dwarf.h"
-#include	"../ld/macho.h"
-#include	"../ld/pe.h"
-
-char linuxdynld[] = "/lib/ld-linux.so.2";
-char freebsddynld[] = "/usr/libexec/ld-elf.so.1";
-char openbsddynld[] = "/usr/libexec/ld.so";
-char netbsddynld[] = "/usr/libexec/ld.elf_so";
-char dragonflydynld[] = "/usr/libexec/ld-elf.so.2";
-char solarisdynld[] = "/lib/ld.so.1";
-
-static int
-needlib(char *name)
-{
-	char *p;
-	LSym *s;
-
-	if(*name == '\0')
-		return 0;
-
-	/* reuse hash code in symbol table */
-	p = smprint(".dynlib.%s", name);
-	s = linklookup(ctxt, p, 0);
-	free(p);
-	if(s->type == 0) {
-		s->type = 100;	// avoid SDATA, etc.
-		return 1;
-	}
-	return 0;
-}
-
-int	nelfsym = 1;
-
-static void	addpltsym(Link*, LSym*);
-static void	addgotsym(Link*, LSym*);
-
-void
-adddynrela(LSym *rela, LSym *s, Reloc *r)
-{
-	USED(rela);
-	USED(s);
-	USED(r);
-	sysfatal("adddynrela not implemented");
-}
-
-void
-adddynrel(LSym *s, Reloc *r)
-{
-	LSym *targ, *rel, *got;
-
-	targ = r->sym;
-	ctxt->cursym = s;
-
-	switch(r->type) {
-	default:
-		if(r->type >= 256) {
-			diag("unexpected relocation type %d", r->type);
-			return;
-		}
-		break;
-
-	// Handle relocations found in ELF object files.
-	case 256 + R_386_PC32:
-		if(targ->type == SDYNIMPORT)
-			diag("unexpected R_386_PC32 relocation for dynamic symbol %s", targ->name);
-		if(targ->type == 0 || targ->type == SXREF)
-			diag("unknown symbol %s in pcrel", targ->name);
-		r->type = R_PCREL;
-		r->add += 4;
-		return;
-
-	case 256 + R_386_PLT32:
-		r->type = R_PCREL;
-		r->add += 4;
-		if(targ->type == SDYNIMPORT) {
-			addpltsym(ctxt, targ);
-			r->sym = linklookup(ctxt, ".plt", 0);
-			r->add += targ->plt;
-		}
-		return;		
-	
-	case 256 + R_386_GOT32:
-		if(targ->type != SDYNIMPORT) {
-			// have symbol
-			if(r->off >= 2 && s->p[r->off-2] == 0x8b) {
-				// turn MOVL of GOT entry into LEAL of symbol address, relative to GOT.
-				s->p[r->off-2] = 0x8d;
-				r->type = R_GOTOFF;
-				return;
-			}
-			if(r->off >= 2 && s->p[r->off-2] == 0xff && s->p[r->off-1] == 0xb3) {
-				// turn PUSHL of GOT entry into PUSHL of symbol itself.
-				// use unnecessary SS prefix to keep instruction same length.
-				s->p[r->off-2] = 0x36;
-				s->p[r->off-1] = 0x68;
-				r->type = R_ADDR;
-				return;
-			}
-			diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name);
-			return;
-		}
-		addgotsym(ctxt, targ);
-		r->type = R_CONST;	// write r->add during relocsym
-		r->sym = S;
-		r->add += targ->got;
-		return;
-	
-	case 256 + R_386_GOTOFF:
-		r->type = R_GOTOFF;
-		return;
-	
-	case 256 + R_386_GOTPC:
-		r->type = R_PCREL;
-		r->sym = linklookup(ctxt, ".got", 0);
-		r->add += 4;
-		return;
-
-	case 256 + R_386_32:
-		if(targ->type == SDYNIMPORT)
-			diag("unexpected R_386_32 relocation for dynamic symbol %s", targ->name);
-		r->type = R_ADDR;
-		return;
-	
-	case 512 + MACHO_GENERIC_RELOC_VANILLA*2 + 0:
-		r->type = R_ADDR;
-		if(targ->type == SDYNIMPORT)
-			diag("unexpected reloc for dynamic symbol %s", targ->name);
-		return;
-	
-	case 512 + MACHO_GENERIC_RELOC_VANILLA*2 + 1:
-		if(targ->type == SDYNIMPORT) {
-			addpltsym(ctxt, targ);
-			r->sym = linklookup(ctxt, ".plt", 0);
-			r->add = targ->plt;
-			r->type = R_PCREL;
-			return;
-		}
-		r->type = R_PCREL;
-		return;
-	
-	case 512 + MACHO_FAKE_GOTPCREL:
-		if(targ->type != SDYNIMPORT) {
-			// have symbol
-			// turn MOVL of GOT entry into LEAL of symbol itself
-			if(r->off < 2 || s->p[r->off-2] != 0x8b) {
-				diag("unexpected GOT reloc for non-dynamic symbol %s", targ->name);
-				return;
-			}
-			s->p[r->off-2] = 0x8d;
-			r->type = R_PCREL;
-			return;
-		}
-		addgotsym(ctxt, targ);
-		r->sym = linklookup(ctxt, ".got", 0);
-		r->add += targ->got;
-		r->type = R_PCREL;
-		return;
-	}
-	
-	// Handle references to ELF symbols from our own object files.
-	if(targ->type != SDYNIMPORT)
-		return;
-
-	switch(r->type) {
-	case R_CALL:
-	case R_PCREL:
-		addpltsym(ctxt, targ);
-		r->sym = linklookup(ctxt, ".plt", 0);
-		r->add = targ->plt;
-		return;
-	
-	case R_ADDR:
-		if(s->type != SDATA)
-			break;
-		if(iself) {
-			adddynsym(ctxt, targ);
-			rel = linklookup(ctxt, ".rel", 0);
-			addaddrplus(ctxt, rel, s, r->off);
-			adduint32(ctxt, rel, ELF32_R_INFO(targ->dynid, R_386_32));
-			r->type = R_CONST;	// write r->add during relocsym
-			r->sym = S;
-			return;
-		}
-		if(HEADTYPE == Hdarwin && s->size == PtrSize && r->off == 0) {
-			// Mach-O relocations are a royal pain to lay out.
-			// They use a compact stateful bytecode representation
-			// that is too much bother to deal with.
-			// Instead, interpret the C declaration
-			//	void *_Cvar_stderr = &stderr;
-			// as making _Cvar_stderr the name of a GOT entry
-			// for stderr.  This is separate from the usual GOT entry,
-			// just in case the C code assigns to the variable,
-			// and of course it only works for single pointers,
-			// but we only need to support cgo and that's all it needs.
-			adddynsym(ctxt, targ);
-			got = linklookup(ctxt, ".got", 0);
-			s->type = got->type | SSUB;
-			s->outer = got;
-			s->sub = got->sub;
-			got->sub = s;
-			s->value = got->size;
-			adduint32(ctxt, got, 0);
-			adduint32(ctxt, linklookup(ctxt, ".linkedit.got", 0), targ->dynid);
-			r->type = 256;	// ignore during relocsym
-			return;
-		}
-		break;
-	}
-	
-	ctxt->cursym = s;
-	diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ->name, r->type, targ->type);
-}
-
-int
-elfreloc1(Reloc *r, vlong sectoff)
-{
-	int32 elfsym;
-
-	LPUT(sectoff);
-
-	elfsym = r->xsym->elfsym;
-	switch(r->type) {
-	default:
-		return -1;
-
-	case R_ADDR:
-		if(r->siz == 4)
-			LPUT(R_386_32 | elfsym<<8);
-		else
-			return -1;
-		break;
-
-	case R_CALL:
-	case R_PCREL:
-		if(r->siz == 4)
-			LPUT(R_386_PC32 | elfsym<<8);
-		else
-			return -1;
-		break;
-	
-	case R_TLS_LE:
-	case R_TLS_IE:
-		if(r->siz == 4)
-			LPUT(R_386_TLS_LE | elfsym<<8);
-		else
-			return -1;
-	}
-
-	return 0;
-}
-
-int
-machoreloc1(Reloc *r, vlong sectoff)
-{
-	uint32 v;
-	LSym *rs;
-	
-	rs = r->xsym;
-
-	if(rs->type == SHOSTOBJ) {
-		if(rs->dynid < 0) {
-			diag("reloc %d to non-macho symbol %s type=%d", r->type, rs->name, rs->type);
-			return -1;
-		}
-		v = rs->dynid;			
-		v |= 1<<27; // external relocation
-	} else {
-		v = rs->sect->extnum;
-		if(v == 0) {
-			diag("reloc %d to symbol %s in non-macho section %s type=%d", r->type, rs->name, rs->sect->name, rs->type);
-			return -1;
-		}
-	}
-
-	switch(r->type) {
-	default:
-		return -1;
-	case R_ADDR:
-		v |= MACHO_GENERIC_RELOC_VANILLA<<28;
-		break;
-	case R_CALL:
-	case R_PCREL:
-		v |= 1<<24; // pc-relative bit
-		v |= MACHO_GENERIC_RELOC_VANILLA<<28;
-		break;
-	}
-	
-	switch(r->siz) {
-	default:
-		return -1;
-	case 1:
-		v |= 0<<25;
-		break;
-	case 2:
-		v |= 1<<25;
-		break;
-	case 4:
-		v |= 2<<25;
-		break;
-	case 8:
-		v |= 3<<25;
-		break;
-	}
-
-	LPUT(sectoff);
-	LPUT(v);
-	return 0;
-}
-
-int
-archreloc(Reloc *r, LSym *s, vlong *val)
-{
-	USED(s);
-	if(linkmode == LinkExternal)
-		return -1;
-	switch(r->type) {
-	case R_CONST:
-		*val = r->add;
-		return 0;
-	case R_GOTOFF:
-		*val = symaddr(r->sym) + r->add - symaddr(linklookup(ctxt, ".got", 0));
-		return 0;
-	}
-	return -1;
-}
-
-void
-elfsetupplt(void)
-{
-	LSym *plt, *got;
-	
-	plt = linklookup(ctxt, ".plt", 0);
-	got = linklookup(ctxt, ".got.plt", 0);
-	if(plt->size == 0) {
-		// pushl got+4
-		adduint8(ctxt, plt, 0xff);
-		adduint8(ctxt, plt, 0x35);
-		addaddrplus(ctxt, plt, got, 4);
-		
-		// jmp *got+8
-		adduint8(ctxt, plt, 0xff);
-		adduint8(ctxt, plt, 0x25);
-		addaddrplus(ctxt, plt, got, 8);
-
-		// zero pad
-		adduint32(ctxt, plt, 0);
-		
-		// assume got->size == 0 too
-		addaddrplus(ctxt, got, linklookup(ctxt, ".dynamic", 0), 0);
-		adduint32(ctxt, got, 0);
-		adduint32(ctxt, got, 0);
-	}
-}
-
-static void
-addpltsym(Link *ctxt, LSym *s)
-{
-	LSym *plt, *got, *rel;
-	
-	if(s->plt >= 0)
-		return;
-
-	adddynsym(ctxt, s);
-	
-	if(iself) {
-		plt = linklookup(ctxt, ".plt", 0);
-		got = linklookup(ctxt, ".got.plt", 0);
-		rel = linklookup(ctxt, ".rel.plt", 0);
-		if(plt->size == 0)
-			elfsetupplt();
-		
-		// jmpq *got+size
-		adduint8(ctxt, plt, 0xff);
-		adduint8(ctxt, plt, 0x25);
-		addaddrplus(ctxt, plt, got, got->size);
-		
-		// add to got: pointer to current pos in plt
-		addaddrplus(ctxt, got, plt, plt->size);
-		
-		// pushl $x
-		adduint8(ctxt, plt, 0x68);
-		adduint32(ctxt, plt, rel->size);
-		
-		// jmp .plt
-		adduint8(ctxt, plt, 0xe9);
-		adduint32(ctxt, plt, -(plt->size+4));
-		
-		// rel
-		addaddrplus(ctxt, rel, got, got->size-4);
-		adduint32(ctxt, rel, ELF32_R_INFO(s->dynid, R_386_JMP_SLOT));
-		
-		s->plt = plt->size - 16;
-	} else if(HEADTYPE == Hdarwin) {
-		// Same laziness as in 6l.
-		
-		LSym *plt;
-
-		plt = linklookup(ctxt, ".plt", 0);
-
-		addgotsym(ctxt, s);
-
-		adduint32(ctxt, linklookup(ctxt, ".linkedit.plt", 0), s->dynid);
-
-		// jmpq *got+size(IP)
-		s->plt = plt->size;
-
-		adduint8(ctxt, plt, 0xff);
-		adduint8(ctxt, plt, 0x25);
-		addaddrplus(ctxt, plt, linklookup(ctxt, ".got", 0), s->got);
-	} else {
-		diag("addpltsym: unsupported binary format");
-	}
-}
-
-static void
-addgotsym(Link *ctxt, LSym *s)
-{
-	LSym *got, *rel;
-	
-	if(s->got >= 0)
-		return;
-	
-	adddynsym(ctxt, s);
-	got = linklookup(ctxt, ".got", 0);
-	s->got = got->size;
-	adduint32(ctxt, got, 0);
-	
-	if(iself) {
-		rel = linklookup(ctxt, ".rel", 0);
-		addaddrplus(ctxt, rel, got, s->got);
-		adduint32(ctxt, rel, ELF32_R_INFO(s->dynid, R_386_GLOB_DAT));
-	} else if(HEADTYPE == Hdarwin) {
-		adduint32(ctxt, linklookup(ctxt, ".linkedit.got", 0), s->dynid);
-	} else {
-		diag("addgotsym: unsupported binary format");
-	}
-}
-
-void
-adddynsym(Link *ctxt, LSym *s)
-{
-	LSym *d;
-	int t;
-	char *name;
-	
-	if(s->dynid >= 0)
-		return;
-	
-	if(iself) {
-		s->dynid = nelfsym++;
-		
-		d = linklookup(ctxt, ".dynsym", 0);
-
-		/* name */
-		name = s->extname;
-		adduint32(ctxt, d, addstring(linklookup(ctxt, ".dynstr", 0), name));
-		
-		/* value */
-		if(s->type == SDYNIMPORT)
-			adduint32(ctxt, d, 0);
-		else
-			addaddr(ctxt, d, s);
-		
-		/* size */
-		adduint32(ctxt, d, 0);
-	
-		/* type */
-		t = STB_GLOBAL << 4;
-		if(s->cgoexport && (s->type&SMASK) == STEXT)
-			t |= STT_FUNC;
-		else
-			t |= STT_OBJECT;
-		adduint8(ctxt, d, t);
-		adduint8(ctxt, d, 0);
-	
-		/* shndx */
-		if(s->type == SDYNIMPORT)
-			adduint16(ctxt, d, SHN_UNDEF);
-		else {
-			switch(s->type) {
-			default:
-			case STEXT:
-				t = 11;
-				break;
-			case SRODATA:
-				t = 12;
-				break;
-			case SDATA:
-				t = 13;
-				break;
-			case SBSS:
-				t = 14;
-				break;
-			}
-			adduint16(ctxt, d, t);
-		}
-	} else if(HEADTYPE == Hdarwin) {
-		diag("adddynsym: missed symbol %s (%s)", s->name, s->extname);
-	} else if(HEADTYPE == Hwindows) {
-		// already taken care of
-	} else {
-		diag("adddynsym: unsupported binary format");
-	}
-}
-
-void
-adddynlib(char *lib)
-{
-	LSym *s;
-	
-	if(!needlib(lib))
-		return;
-	
-	if(iself) {
-		s = linklookup(ctxt, ".dynstr", 0);
-		if(s->size == 0)
-			addstring(s, "");
-		elfwritedynent(linklookup(ctxt, ".dynamic", 0), DT_NEEDED, addstring(s, lib));
-	} else if(HEADTYPE == Hdarwin) {
-		machoadddynlib(lib);
-	} else if(HEADTYPE != Hwindows) {
-		diag("adddynlib: unsupported binary format");
-	}
-}
-
-void
-asmb(void)
-{
-	int32 magic;
-	uint32 symo, dwarfoff, machlink;
-	Section *sect;
-	LSym *sym;
-	int i;
-
-	if(debug['v'])
-		Bprint(&bso, "%5.2f asmb\n", cputime());
-	Bflush(&bso);
-
-	if(iself)
-		asmbelfsetup();
-
-	sect = segtext.sect;
-	cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);
-	codeblk(sect->vaddr, sect->len);
-	for(sect = sect->next; sect != nil; sect = sect->next) {
-		cseek(sect->vaddr - segtext.vaddr + segtext.fileoff);
-		datblk(sect->vaddr, sect->len);
-	}
-	
-	if(segrodata.filelen > 0) {
-		if(debug['v'])
-			Bprint(&bso, "%5.2f rodatblk\n", cputime());
-		Bflush(&bso);
-
-		cseek(segrodata.fileoff);
-		datblk(segrodata.vaddr, segrodata.filelen);
-	}
-
-	if(debug['v'])
-		Bprint(&bso, "%5.2f datblk\n", cputime());
-	Bflush(&bso);
-
-	cseek(segdata.fileoff);
-	datblk(segdata.vaddr, segdata.filelen);
-
-	machlink = 0;
-	if(HEADTYPE == Hdarwin) {
-		if(debug['v'])
-			Bprint(&bso, "%5.2f dwarf\n", cputime());
-
-		dwarfoff = rnd(HEADR+segtext.len, INITRND) + rnd(segdata.filelen, INITRND);
-		cseek(dwarfoff);
-
-		segdwarf.fileoff = cpos();
-		dwarfemitdebugsections();
-		segdwarf.filelen = cpos() - segdwarf.fileoff;
-
-		machlink = domacholink();
-	}
-
-	symsize = 0;
-	spsize = 0;
-	lcsize = 0;
-	symo = 0;
-	if(!debug['s']) {
-		// TODO: rationalize
-		if(debug['v'])
-			Bprint(&bso, "%5.2f sym\n", cputime());
-		Bflush(&bso);
-		switch(HEADTYPE) {
-		default:
-			if(iself)
-				goto Elfsym;
-		case Hplan9:
-			symo = segdata.fileoff+segdata.filelen;
-			break;
-		case Hdarwin:
-			symo = segdata.fileoff+rnd(segdata.filelen, INITRND)+machlink;
-			break;
-		Elfsym:
-			symo = segdata.fileoff+segdata.filelen;
-			symo = rnd(symo, INITRND);
-			break;
-		case Hwindows:
-			symo = segdata.fileoff+segdata.filelen;
-			symo = rnd(symo, PEFILEALIGN);
-			break;
-		}
-		cseek(symo);
-		switch(HEADTYPE) {
-		default:
-			if(iself) {
-				if(debug['v'])
-					Bprint(&bso, "%5.2f elfsym\n", cputime());
-				asmelfsym();
-				cflush();
-				cwrite(elfstrdat, elfstrsize);
-
-				if(debug['v'])
-					Bprint(&bso, "%5.2f dwarf\n", cputime());
-				dwarfemitdebugsections();
-				
-				if(linkmode == LinkExternal)
-					elfemitreloc();
-			}
-			break;
-		case Hplan9:
-			asmplan9sym();
-			cflush();
-
-			sym = linklookup(ctxt, "pclntab", 0);
-			if(sym != nil) {
-				lcsize = sym->np;
-				for(i=0; i < lcsize; i++)
-					cput(sym->p[i]);
-				
-				cflush();
-			}
-			break;
-		case Hwindows:
-			if(debug['v'])
-				Bprint(&bso, "%5.2f dwarf\n", cputime());
-			dwarfemitdebugsections();
-			break;
-		case Hdarwin:
-			if(linkmode == LinkExternal)
-				machoemitreloc();
-			break;
-		}
-	}
-	if(debug['v'])
-		Bprint(&bso, "%5.2f headr\n", cputime());
-	Bflush(&bso);
-	cseek(0L);
-	switch(HEADTYPE) {
-	default:
-	case Hplan9:	/* plan9 */
-		magic = 4*11*11+7;
-		lputb(magic);		/* magic */
-		lputb(segtext.filelen);			/* sizes */
-		lputb(segdata.filelen);
-		lputb(segdata.len - segdata.filelen);
-		lputb(symsize);			/* nsyms */
-		lputb(entryvalue());		/* va of entry */
-		lputb(spsize);			/* sp offsets */
-		lputb(lcsize);			/* line offsets */
-		break;
-	case Hdarwin:
-		asmbmacho();
-		break;
-	case Hlinux:
-	case Hfreebsd:
-	case Hnetbsd:
-	case Hopenbsd:
-	case Hdragonfly:
-	case Hnacl:
-		asmbelf(symo);
-		break;
-	case Hwindows:
-		asmbpe();
-		break;
-	}
-	cflush();
-}
-
-void
-s8put(char *n)
-{
-	char name[8];
-	int i;
-
-	strncpy(name, n, sizeof(name));
-	for(i=0; i<sizeof(name); i++)
-		cput(name[i]);
-}
-
-int32
-rnd(int32 v, int32 r)
-{
-	int32 c;
-
-	if(r <= 0)
-		return v;
-	v += r - 1;
-	c = v % r;
-	if(c < 0)
-		c += r;
-	v -= c;
-	return v;
-}
diff --git a/src/cmd/8l/doc.go b/src/cmd/8l/doc.go
deleted file mode 100644
index ff06bc3..0000000
--- a/src/cmd/8l/doc.go
+++ /dev/null
@@ -1,15 +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.
-
-// +build ignore
-
-/*
-
-8l is the linker for the 32-bit x86.
-The $GOARCH for these tools is 386.
-
-The flags are documented in ../ld/doc.go.
-
-*/
-package main
diff --git a/src/cmd/8l/l.h b/src/cmd/8l/l.h
deleted file mode 100644
index 70d3a4b..0000000
--- a/src/cmd/8l/l.h
+++ /dev/null
@@ -1,95 +0,0 @@
-// Inferno utils/8l/l.h
-// http://code.google.com/p/inferno-os/source/browse/utils/8l/l.h
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include	<u.h>
-#include	<libc.h>
-#include	<bio.h>
-#include	<link.h>
-#include	"8.out.h"
-
-#ifndef	EXTERN
-#define	EXTERN	extern
-#endif
-
-enum
-{
-	thechar = '8',
-	PtrSize = 4,
-	IntSize = 4,
-	RegSize = 4,
-	MaxAlign = 32,	// max data alignment
-	FuncAlign = 16
-};
-
-#define	P		((Prog*)0)
-#define	S		((LSym*)0)
-
-enum
-{
-	MINLC		= 1,
-};
-
-#pragma	varargck	type	"I"	uchar*
-
-EXTERN	LSym*	datap;
-EXTERN	int	debug[128];
-EXTERN	char	literal[32];
-EXTERN	Prog*	firstp;
-EXTERN	int32	lcsize;
-EXTERN	char*	rpath;
-EXTERN	int32	spsize;
-EXTERN	LSym*	symlist;
-EXTERN	int32	symsize;
-
-int	Iconv(Fmt *fp);
-void	adddynlib(char *lib);
-void	adddynrel(LSym *s, Reloc *r);
-void	adddynrela(LSym *rela, LSym *s, Reloc *r);
-void	adddynsym(Link *ctxt, LSym *s);
-int	archreloc(Reloc *r, LSym *s, vlong *val);
-void	asmb(void);
-int	elfreloc1(Reloc *r, vlong sectoff);
-void	elfsetupplt(void);
-void	listinit(void);
-int	machoreloc1(Reloc *r, vlong sectoff);
-int32	rnd(int32 v, int32 r);
-void	s8put(char *n);
-char*	xsymname(LSym *s);
-
-/* Native is little-endian */
-#define	LPUT(a)	lputl(a)
-#define	WPUT(a)	wputl(a)
-#define	VPUT(a)	vputl(a)
-
-/* Used by ../ld/dwarf.c */
-enum
-{
-	DWARFREGSP = 4
-};
diff --git a/src/cmd/8l/list.c b/src/cmd/8l/list.c
deleted file mode 100644
index 0a75340..0000000
--- a/src/cmd/8l/list.c
+++ /dev/null
@@ -1,67 +0,0 @@
-// Inferno utils/8l/list.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8l/list.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-// Printing.
-
-#include	"l.h"
-#include	"../ld/lib.h"
-
-void
-listinit(void)
-{
-	listinit8();
-	fmtinstall('I', Iconv);
-}
-
-int
-Iconv(Fmt *fp)
-{
-	int i, n;
-	uchar *p;
-	char *s;
-	Fmt fmt;
-	
-	n = fp->prec;
-	fp->prec = 0;
-	if(!(fp->flags&FmtPrec) || n < 0)
-		return fmtstrcpy(fp, "%I");
-	fp->flags &= ~FmtPrec;
-	p = va_arg(fp->args, uchar*);
-
-	// format into temporary buffer and
-	// call fmtstrcpy to handle padding.
-	fmtstrinit(&fmt);
-	for(i=0; i<n; i++)
-		fmtprint(&fmt, "%.2ux", *p++);
-	s = fmtstrflush(&fmt);
-	fmtstrcpy(fp, s);
-	free(s);
-	return 0;
-}
diff --git a/src/cmd/8l/obj.c b/src/cmd/8l/obj.c
deleted file mode 100644
index 1b65c5e..0000000
--- a/src/cmd/8l/obj.c
+++ /dev/null
@@ -1,138 +0,0 @@
-// Inferno utils/8l/obj.c
-// http://code.google.com/p/inferno-os/source/browse/utils/8l/obj.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-// Reading object files.
-
-#include	"l.h"
-#include	"../ld/lib.h"
-#include	"../ld/elf.h"
-#include	"../ld/macho.h"
-#include	"../ld/dwarf.h"
-#include	"../ld/pe.h"
-#include	<ar.h>
-
-char*	thestring 	= "386";
-LinkArch*	thelinkarch = &link386;
-
-void
-linkarchinit(void)
-{
-}
-
-void
-archinit(void)
-{
-	// getgoextlinkenabled is based on GO_EXTLINK_ENABLED when
-	// Go was built; see ../../make.bash.
-	if(linkmode == LinkAuto && strcmp(getgoextlinkenabled(), "0") == 0)
-		linkmode = LinkInternal;
-
-	switch(HEADTYPE) {
-	default:
-		if(linkmode == LinkAuto)
-			linkmode = LinkInternal;
-		if(linkmode == LinkExternal && strcmp(getgoextlinkenabled(), "1") != 0)
-			sysfatal("cannot use -linkmode=external with -H %s", headstr(HEADTYPE));
-		break;
-	case Hdarwin:
-	case Hdragonfly:
-	case Hfreebsd:
-	case Hlinux:
-	case Hnetbsd:
-	case Hopenbsd:
-		break;
-	}
-
-	switch(HEADTYPE) {
-	default:
-		diag("unknown -H option");
-		errorexit();
-
-	case Hplan9:	/* plan 9 */
-		HEADR = 32L;
-		if(INITTEXT == -1)
-			INITTEXT = 4096+32;
-		if(INITDAT == -1)
-			INITDAT = 0;
-		if(INITRND == -1)
-			INITRND = 4096;
-		break;
-	case Hdarwin:	/* apple MACH */
-		machoinit();
-		HEADR = INITIAL_MACHO_HEADR;
-		if(INITTEXT == -1)
-			INITTEXT = 4096+HEADR;
-		if(INITDAT == -1)
-			INITDAT = 0;
-		if(INITRND == -1)
-			INITRND = 4096;
-		break;
-	case Hlinux:	/* elf32 executable */
-	case Hfreebsd:
-	case Hnetbsd:
-	case Hopenbsd:
-	case Hdragonfly:
-		elfinit();
-		HEADR = ELFRESERVE;
-		if(INITTEXT == -1)
-			INITTEXT = 0x08048000+HEADR;
-		if(INITDAT == -1)
-			INITDAT = 0;
-		if(INITRND == -1)
-			INITRND = 4096;
-		break;
-	
-	case Hnacl:
-		elfinit();
-		HEADR = 0x10000;
-		funcalign = 32;
-		if(INITTEXT == -1)
-			INITTEXT = 0x20000;
-		if(INITDAT == -1)
-			INITDAT = 0;
-		if(INITRND == -1)
-			INITRND = 0x10000;
-		break;
-	
-	case Hwindows: /* PE executable */
-		peinit();
-		HEADR = PEFILEHEADR;
-		if(INITTEXT == -1)
-			INITTEXT = PEBASE+PESECTHEADR;
-		if(INITDAT == -1)
-			INITDAT = 0;
-		if(INITRND == -1)
-			INITRND = PESECTALIGN;
-		break;
-	}
-	if(INITDAT != 0 && INITRND != 0)
-		print("warning: -D0x%llux is ignored because of -R0x%ux\n",
-			INITDAT, INITRND);
-}
diff --git a/src/cmd/addr2line/addr2line_test.go b/src/cmd/addr2line/addr2line_test.go
index 10d1dc9..620b416 100644
--- a/src/cmd/addr2line/addr2line_test.go
+++ b/src/cmd/addr2line/addr2line_test.go
@@ -7,6 +7,7 @@ package main
 import (
 	"bufio"
 	"bytes"
+	"internal/testenv"
 	"io/ioutil"
 	"os"
 	"os/exec"
@@ -51,15 +52,9 @@ func runAddr2Line(t *testing.T, exepath, addr string) (funcname, path, lineno st
 	funcname = f[0]
 	pathAndLineNo := f[1]
 	f = strings.Split(pathAndLineNo, ":")
-	if runtime.GOOS == "windows" {
-		switch len(f) {
-		case 2:
-			return funcname, f[0], f[1]
-		case 3:
-			return funcname, f[0] + ":" + f[1], f[2]
-		default:
-			t.Fatalf("no line number found in %q", pathAndLineNo)
-		}
+	if runtime.GOOS == "windows" && len(f) == 3 {
+		// Reattach drive letter.
+		f = []string{f[0] + ":" + f[1], f[2]}
 	}
 	if len(f) != 2 {
 		t.Fatalf("no line number found in %q", pathAndLineNo)
@@ -85,17 +80,14 @@ func testAddr2Line(t *testing.T, exepath, addr string) {
 	if !os.SameFile(fi1, fi2) {
 		t.Fatalf("addr2line_test.go and %s are not same file", srcPath)
 	}
-	if srcLineNo != "94" {
-		t.Fatalf("line number = %v; want 94", srcLineNo)
+	if srcLineNo != "89" {
+		t.Fatalf("line number = %v; want 89", srcLineNo)
 	}
 }
 
-// This is line 93. The test depends on that.
+// This is line 88. The test depends on that.
 func TestAddr2Line(t *testing.T) {
-	switch runtime.GOOS {
-	case "nacl", "android":
-		t.Skipf("skipping on %s", runtime.GOOS)
-	}
+	testenv.MustHaveGoBuild(t)
 
 	syms := loadSyms(t)
 
diff --git a/src/cmd/api/goapi.go b/src/cmd/api/goapi.go
index 4a63eac..01b6def 100644
--- a/src/cmd/api/goapi.go
+++ b/src/cmd/api/goapi.go
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build api_tool
-
 // Binary api computes the exported API of a set of Go packages.
 package main
 
@@ -16,6 +14,7 @@ import (
 	"go/build"
 	"go/parser"
 	"go/token"
+	"go/types"
 	"io"
 	"io/ioutil"
 	"log"
@@ -26,8 +25,6 @@ import (
 	"runtime"
 	"sort"
 	"strings"
-
-	"code.google.com/p/go.tools/go/types"
 )
 
 // Flags
@@ -155,7 +152,8 @@ func main() {
 					// w.Import(name) will return nil
 					continue
 				}
-				w.export(w.Import(name))
+				pkg, _ := w.Import(name)
+				w.export(pkg)
 			}
 		}
 
@@ -205,7 +203,8 @@ func main() {
 	}
 	optional := fileFeatures(*nextFile)
 	exception := fileFeatures(*exceptFile)
-	fail = !compareAPI(bw, features, required, optional, exception)
+	fail = !compareAPI(bw, features, required, optional, exception,
+		*allowNew && strings.Contains(runtime.Version(), "devel"))
 }
 
 // export emits the exported package features.
@@ -241,7 +240,7 @@ func featureWithoutContext(f string) string {
 	return spaceParensRx.ReplaceAllString(f, "")
 }
 
-func compareAPI(w io.Writer, features, required, optional, exception []string) (ok bool) {
+func compareAPI(w io.Writer, features, required, optional, exception []string, allowAdd bool) (ok bool) {
 	ok = true
 
 	optionalSet := set(optional)
@@ -283,7 +282,7 @@ func compareAPI(w io.Writer, features, required, optional, exception []string) (
 				delete(optionalSet, newFeature)
 			} else {
 				fmt.Fprintf(w, "+%s\n", newFeature)
-				if !*allowNew || !strings.Contains(runtime.Version(), "devel") {
+				if !allowAdd {
 					ok = false // we're in lock-down mode for next release
 				}
 			}
@@ -356,139 +355,16 @@ var parsedFileCache = make(map[string]*ast.File)
 
 func (w *Walker) parseFile(dir, file string) (*ast.File, error) {
 	filename := filepath.Join(dir, file)
-	f, _ := parsedFileCache[filename]
-	if f != nil {
+	if f := parsedFileCache[filename]; f != nil {
 		return f, nil
 	}
 
-	var err error
-
-	// generate missing context-dependent files.
-
-	if w.context != nil && file == fmt.Sprintf("zgoos_%s.go", w.context.GOOS) {
-		src := fmt.Sprintf("package runtime; const theGoos = `%s`", w.context.GOOS)
-		f, err = parser.ParseFile(fset, filename, src, 0)
-		if err != nil {
-			log.Fatalf("incorrect generated file: %s", err)
-		}
-	}
-
-	if w.context != nil && file == fmt.Sprintf("zgoarch_%s.go", w.context.GOARCH) {
-		src := fmt.Sprintf("package runtime; const theGoarch = `%s`", w.context.GOARCH)
-		f, err = parser.ParseFile(fset, filename, src, 0)
-		if err != nil {
-			log.Fatalf("incorrect generated file: %s", err)
-		}
-	}
-	if w.context != nil && file == fmt.Sprintf("zruntime_defs_%s_%s.go", w.context.GOOS, w.context.GOARCH) {
-		// Just enough to keep the api checker happy. Keep sorted.
-		src := "package runtime; type (" +
-			" _defer struct{};" +
-			" _func struct{};" +
-			" _panic struct{};" +
-			" _select struct{}; " +
-			" _type struct{};" +
-			" alg struct{};" +
-			" chantype struct{};" +
-			" context struct{};" + // windows
-			" eface struct{};" +
-			" epollevent struct{};" +
-			" funcval struct{};" +
-			" g struct{};" +
-			" gobuf struct{};" +
-			" hchan struct{};" +
-			" iface struct{};" +
-			" interfacetype struct{};" +
-			" itab struct{};" +
-			" keventt struct{};" +
-			" m struct{};" +
-			" maptype struct{};" +
-			" mcache struct{};" +
-			" mspan struct{};" +
-			" mutex struct{};" +
-			" note struct{};" +
-			" p struct{};" +
-			" parfor struct{};" +
-			" slicetype struct{};" +
-			" stkframe struct{};" +
-			" sudog struct{};" +
-			" timespec struct{};" +
-			" waitq struct{};" +
-			" wincallbackcontext struct{};" +
-			"); " +
-			"const (" +
-			" cb_max = 2000;" +
-			" _CacheLineSize = 64;" +
-			" _Gidle = 1;" +
-			" _Grunnable = 2;" +
-			" _Grunning = 3;" +
-			" _Gsyscall = 4;" +
-			" _Gwaiting = 5;" +
-			" _Gdead = 6;" +
-			" _Genqueue = 7;" +
-			" _Gcopystack = 8;" +
-			" _NSIG = 32;" +
-			" _FlagNoScan = iota;" +
-			" _FlagNoZero;" +
-			" _TinySize;" +
-			" _TinySizeClass;" +
-			" _MaxSmallSize;" +
-			" _PageShift;" +
-			" _PageSize;" +
-			" _PageMask;" +
-			" _BitsPerPointer;" +
-			" _BitsMask;" +
-			" _PointersPerByte;" +
-			" _MaxGCMask;" +
-			" _BitsDead;" +
-			" _BitsPointer;" +
-			" _MSpanInUse;" +
-			" _ConcurrentSweep;" +
-			" _KindBool;" +
-			" _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;" +
-			" _KindGCProg;" +
-			" _KindNoPointers;" +
-			" _KindMask;" +
-			")"
-		f, err = parser.ParseFile(fset, filename, src, 0)
-		if err != nil {
-			log.Fatalf("incorrect generated file: %s", err)
-		}
-	}
-
-	if f == nil {
-		f, err = parser.ParseFile(fset, filename, nil, 0)
-		if err != nil {
-			return nil, err
-		}
+	f, err := parser.ParseFile(fset, filename, nil, 0)
+	if err != nil {
+		return nil, err
 	}
-
 	parsedFileCache[filename] = f
+
 	return f, nil
 }
 
@@ -542,13 +418,13 @@ func tagKey(dir string, context *build.Context, tags []string) string {
 // for a package that is in the process of being imported.
 var importing types.Package
 
-func (w *Walker) Import(name string) (pkg *types.Package) {
-	pkg = w.imported[name]
+func (w *Walker) Import(name string) (*types.Package, error) {
+	pkg := w.imported[name]
 	if pkg != nil {
 		if pkg == &importing {
 			log.Fatalf("cycle importing package %q", name)
 		}
-		return pkg
+		return pkg, nil
 	}
 	w.imported[name] = &importing
 
@@ -572,7 +448,7 @@ func (w *Walker) Import(name string) (pkg *types.Package) {
 			key = tagKey(dir, context, tags)
 			if pkg := pkgCache[key]; pkg != nil {
 				w.imported[name] = pkg
-				return pkg
+				return pkg, nil
 			}
 		}
 	}
@@ -580,7 +456,7 @@ func (w *Walker) Import(name string) (pkg *types.Package) {
 	info, err := context.ImportDir(dir, 0)
 	if err != nil {
 		if _, nogo := err.(*build.NoGoError); nogo {
-			return
+			return nil, nil
 		}
 		log.Fatalf("pkg %q, dir %q: ScanDir: %v", name, dir, err)
 	}
@@ -595,25 +471,6 @@ func (w *Walker) Import(name string) (pkg *types.Package) {
 
 	filenames := append(append([]string{}, info.GoFiles...), info.CgoFiles...)
 
-	// Certain files only exist when building for the specified context.
-	// Add them manually.
-	if name == "runtime" {
-		n := fmt.Sprintf("zgoos_%s.go", w.context.GOOS)
-		if !contains(filenames, n) {
-			filenames = append(filenames, n)
-		}
-
-		n = fmt.Sprintf("zgoarch_%s.go", w.context.GOARCH)
-		if !contains(filenames, n) {
-			filenames = append(filenames, n)
-		}
-
-		n = fmt.Sprintf("zruntime_defs_%s_%s.go", w.context.GOOS, w.context.GOARCH)
-		if !contains(filenames, n) {
-			filenames = append(filenames, n)
-		}
-	}
-
 	// Parse package files.
 	var files []*ast.File
 	for _, file := range filenames {
@@ -628,11 +485,7 @@ func (w *Walker) Import(name string) (pkg *types.Package) {
 	conf := types.Config{
 		IgnoreFuncBodies: true,
 		FakeImportC:      true,
-		Import: func(imports map[string]*types.Package, name string) (*types.Package, error) {
-			pkg := w.Import(name)
-			imports[name] = pkg
-			return pkg, nil
-		},
+		Importer:         w,
 	}
 	pkg, err = conf.Check(name, fset, files, nil)
 	if err != nil {
@@ -648,7 +501,7 @@ func (w *Walker) Import(name string) (pkg *types.Package) {
 	}
 
 	w.imported[name] = pkg
-	return
+	return pkg, nil
 }
 
 // pushScope enters a new scope (walking a package, type, node, etc)
@@ -750,12 +603,14 @@ func (w *Walker) writeType(buf *bytes.Buffer, typ types.Type) {
 	case *types.Chan:
 		var s string
 		switch typ.Dir() {
-		case ast.SEND:
+		case types.SendOnly:
 			s = "chan<- "
-		case ast.RECV:
+		case types.RecvOnly:
 			s = "<-chan "
-		default:
+		case types.SendRecv:
 			s = "chan "
+		default:
+			panic("unreachable")
 		}
 		buf.WriteString(s)
 		w.writeType(buf, typ.Elem())
@@ -775,7 +630,7 @@ func (w *Walker) writeType(buf *bytes.Buffer, typ types.Type) {
 }
 
 func (w *Walker) writeSignature(buf *bytes.Buffer, sig *types.Signature) {
-	w.writeParams(buf, sig.Params(), sig.IsVariadic())
+	w.writeParams(buf, sig.Params(), sig.Variadic())
 	switch res := sig.Results(); res.Len() {
 	case 0:
 		// nothing to do
@@ -847,10 +702,10 @@ func (w *Walker) emitType(obj *types.TypeName) {
 
 	// emit methods with value receiver
 	var methodNames map[string]bool
-	vset := typ.MethodSet()
+	vset := types.NewMethodSet(typ)
 	for i, n := 0, vset.Len(); i < n; i++ {
 		m := vset.At(i)
-		if m.Obj().IsExported() {
+		if m.Obj().Exported() {
 			w.emitMethod(m)
 			if methodNames == nil {
 				methodNames = make(map[string]bool)
@@ -862,10 +717,10 @@ func (w *Walker) emitType(obj *types.TypeName) {
 	// emit methods with pointer receiver; exclude
 	// methods that we have emitted already
 	// (the method set of *T includes the methods of T)
-	pset := types.NewPointer(typ).MethodSet()
+	pset := types.NewMethodSet(types.NewPointer(typ))
 	for i, n := 0, pset.Len(); i < n; i++ {
 		m := pset.At(i)
-		if m.Obj().IsExported() && !methodNames[m.Obj().Name()] {
+		if m.Obj().Exported() && !methodNames[m.Obj().Name()] {
 			w.emitMethod(m)
 		}
 	}
@@ -878,7 +733,7 @@ func (w *Walker) emitStructType(name string, typ *types.Struct) {
 
 	for i := 0; i < typ.NumFields(); i++ {
 		f := typ.Field(i)
-		if !f.IsExported() {
+		if !f.Exported() {
 			continue
 		}
 		typ := f.Type()
@@ -895,10 +750,10 @@ func (w *Walker) emitIfaceType(name string, typ *types.Interface) {
 
 	var methodNames []string
 	complete := true
-	mset := typ.MethodSet()
+	mset := types.NewMethodSet(typ)
 	for i, n := 0, mset.Len(); i < n; i++ {
 		m := mset.At(i).Obj().(*types.Func)
-		if !m.IsExported() {
+		if !m.Exported() {
 			complete = false
 			continue
 		}
@@ -949,7 +804,7 @@ func (w *Walker) emitMethod(m *types.Selection) {
 		if p, _ := recv.(*types.Pointer); p != nil {
 			base = p.Elem()
 		}
-		if obj := base.(*types.Named).Obj(); !obj.IsExported() {
+		if obj := base.(*types.Named).Obj(); !obj.Exported() {
 			log.Fatalf("exported method with unexported receiver base type: %s", m)
 		}
 	}
diff --git a/src/cmd/api/goapi_test.go b/src/cmd/api/goapi_test.go
index f4fb7d3..1d2cc9a 100644
--- a/src/cmd/api/goapi_test.go
+++ b/src/cmd/api/goapi_test.go
@@ -1,5 +1,3 @@
-// +build api_tool
-
 // 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.
@@ -38,9 +36,11 @@ func TestGolden(t *testing.T) {
 			continue
 		}
 
-		goldenFile := filepath.Join("testdata", "src", fi.Name(), "golden.txt")
+		// TODO(gri) remove extra pkg directory eventually
+		goldenFile := filepath.Join("testdata", "src", "pkg", fi.Name(), "golden.txt")
 		w := NewWalker(nil, "testdata/src/pkg")
-		w.export(w.Import(fi.Name()))
+		pkg, _ := w.Import(fi.Name())
+		w.export(pkg)
 
 		if *updateGolden {
 			os.Remove(goldenFile)
@@ -115,7 +115,7 @@ func TestCompareAPI(t *testing.T) {
 			out:       "",
 		},
 		{
-			// http://golang.org/issue/4303
+			// https://golang.org/issue/4303
 			name: "contexts reconverging",
 			required: []string{
 				"A",
@@ -132,7 +132,7 @@ func TestCompareAPI(t *testing.T) {
 	}
 	for _, tt := range tests {
 		buf := new(bytes.Buffer)
-		gotok := compareAPI(buf, tt.features, tt.required, tt.optional, tt.exception)
+		gotok := compareAPI(buf, tt.features, tt.required, tt.optional, tt.exception, true)
 		if gotok != tt.ok {
 			t.Errorf("%s: ok = %v; want %v", tt.name, gotok, tt.ok)
 		}
@@ -179,7 +179,8 @@ func BenchmarkAll(b *testing.B) {
 			w := NewWalker(context, filepath.Join(build.Default.GOROOT, "src"))
 			for _, name := range pkgNames {
 				if name != "unsafe" && !strings.HasPrefix(name, "cmd/") {
-					w.export(w.Import(name))
+					pkg, _ := w.Import(name)
+					w.export(pkg)
 				}
 			}
 			w.Features()
diff --git a/src/cmd/api/run.go b/src/cmd/api/run.go
index ed5613e..eaffa0a 100644
--- a/src/cmd/api/run.go
+++ b/src/cmd/api/run.go
@@ -4,32 +4,18 @@
 
 // +build ignore
 
-// The run program is invoked via "go run" from src/run.bash or
-// src/run.bat conditionally builds and runs the cmd/api tool.
-//
-// TODO(bradfitz): the "conditional" condition is always true.
-// We should only do this if the user has the hg codereview extension
-// enabled and verifies that the go.tools subrepo is checked out with
-// a suitably recently version. In prep for the cmd/api rewrite.
+// The run program is invoked via the dist tool.
+// To invoke manually: go tool dist test -run api --no-rebuild
 package main
 
 import (
 	"fmt"
 	"log"
-	"net/http"
 	"os"
 	"os/exec"
-	"os/user"
 	"path/filepath"
-	"runtime"
-	"strings"
 )
 
-// goToolsVersion is the hg revision of the go.tools subrepo we need
-// to build cmd/api.  This only needs to be updated whenever a go/types
-// bug fix is needed by the cmd/api tool.
-const goToolsVersion = "6698ca2900e2"
-
 var goroot string
 
 func main() {
@@ -38,23 +24,9 @@ func main() {
 	if goroot == "" {
 		log.Fatal("No $GOROOT set.")
 	}
-	_, err := exec.LookPath("hg")
-	if err != nil {
-		fmt.Println("Skipping cmd/api checks; hg not available")
-		return
-	}
-
-	gopath := prepGoPath()
-
-	cmd := exec.Command("go", "install", "--tags=api_tool", "cmd/api")
-	cmd.Env = append(filterOut(os.Environ(), "GOARCH", "GOPATH"), "GOPATH="+gopath)
-	out, err := cmd.CombinedOutput()
-	if err != nil {
-		log.Fatalf("Error installing cmd/api: %v\n%s", err, out)
-	}
 
-	out, err = exec.Command("go", "tool", "api",
-		"-c", file("go1", "go1.1", "go1.2", "go1.3", "go1.4"),
+	out, err := exec.Command("go", "tool", "api",
+		"-c", file("go1", "go1.1", "go1.2", "go1.3", "go1.4", "go1.5"),
 		"-next", file("next"),
 		"-except", file("except")).CombinedOutput()
 	if err != nil {
@@ -63,22 +35,6 @@ func main() {
 	fmt.Print(string(out))
 }
 
-// filterOut returns a copy of the src environment without environment
-// variables from remove.
-// TODO: delete when issue 6201 is fixed.
-func filterOut(src []string, remove ...string) (out []string) {
-S:
-	for _, s := range src {
-		for _, r := range remove {
-			if strings.HasPrefix(s, r) && strings.HasPrefix(s, r+"=") {
-				continue S
-			}
-		}
-		out = append(out, s)
-	}
-	return
-}
-
 // file expands s to $GOROOT/api/s.txt.
 // If there are more than 1, they're comma-separated.
 func file(s ...string) string {
@@ -87,99 +43,3 @@ func file(s ...string) string {
 	}
 	return filepath.Join(goroot, "api", s[0]+".txt")
 }
-
-// prepGoPath returns a GOPATH for the "go" tool to compile the API tool with.
-// It tries to re-use a go.tools checkout from a previous run if possible,
-// else it hg clones it.
-func prepGoPath() string {
-	const tempBase = "go.tools.TMP"
-
-	username := ""
-	u, err := user.Current()
-	if err == nil {
-		username = u.Username
-	} else {
-		username = os.Getenv("USER")
-		if username == "" {
-			username = "nobody"
-		}
-	}
-
-	// The GOPATH we'll return
-	gopath := filepath.Join(os.TempDir(), "gopath-api-"+cleanUsername(username)+"-"+cleanUsername(strings.Fields(runtime.Version())[0]), goToolsVersion)
-
-	// cloneDir is where we run "hg clone".
-	cloneDir := filepath.Join(gopath, "src", "code.google.com", "p")
-
-	// The dir we clone into. We only atomically rename it to finalDir on
-	// clone success.
-	tmpDir := filepath.Join(cloneDir, tempBase)
-
-	// finalDir is where the checkout will live once it's complete.
-	finalDir := filepath.Join(cloneDir, "go.tools")
-
-	if goToolsCheckoutGood(finalDir) {
-		return gopath
-	}
-	os.RemoveAll(finalDir) // in case it's there but corrupt
-	os.RemoveAll(tmpDir)   // in case of aborted hg clone before
-
-	if err := os.MkdirAll(cloneDir, 0700); err != nil {
-		log.Fatal(err)
-	}
-	cmd := exec.Command("hg",
-		"clone", "--rev="+goToolsVersion,
-		"https://code.google.com/p/go.tools",
-		tempBase)
-	cmd.Dir = cloneDir
-	out, err := cmd.CombinedOutput()
-	if err != nil {
-		if _, err := http.Head("http://ip.appspot.com/"); err != nil {
-			log.Printf("# Skipping API check; network appears to be unavailable")
-			os.Exit(0)
-		}
-		log.Fatalf("Error running hg clone on go.tools: %v\n%s", err, out)
-	}
-	if err := os.Rename(tmpDir, finalDir); err != nil {
-		log.Fatal(err)
-	}
-	return gopath
-}
-
-func cleanUsername(n string) string {
-	b := make([]rune, len(n))
-	for i, r := range n {
-		if r == '\\' || r == '/' || r == ':' {
-			b[i] = '_'
-		} else {
-			b[i] = r
-		}
-	}
-	return string(b)
-}
-
-func goToolsCheckoutGood(dir string) bool {
-	if _, err := os.Stat(dir); err != nil {
-		return false
-	}
-
-	cmd := exec.Command("hg", "id", "--id")
-	cmd.Dir = dir
-	out, err := cmd.Output()
-	if err != nil {
-		return false
-	}
-	id := strings.TrimSpace(string(out))
-	if id != goToolsVersion {
-		return false
-	}
-
-	cmd = exec.Command("hg", "status")
-	cmd.Dir = dir
-	out, err = cmd.Output()
-	if err != nil || len(out) > 0 {
-		return false
-	}
-
-	return true
-}
diff --git a/src/cmd/asm/internal/arch/arch.go b/src/cmd/asm/internal/arch/arch.go
new file mode 100644
index 0000000..e6901eb
--- /dev/null
+++ b/src/cmd/asm/internal/arch/arch.go
@@ -0,0 +1,363 @@
+// 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 arch
+
+import (
+	"cmd/internal/obj"
+	"cmd/internal/obj/arm"
+	"cmd/internal/obj/arm64"
+	"cmd/internal/obj/ppc64"
+	"cmd/internal/obj/x86"
+	"fmt"
+	"strings"
+)
+
+// Pseudo-registers whose names are the constant name without the leading R.
+const (
+	RFP = -(iota + 1)
+	RSB
+	RSP
+	RPC
+)
+
+// Arch wraps the link architecture object with more architecture-specific information.
+type Arch struct {
+	*obj.LinkArch
+	// Map of instruction names to enumeration.
+	Instructions map[string]int
+	// Map of register names to enumeration.
+	Register map[string]int16
+	// Table of register prefix names. These are things like R for R(0) and SPR for SPR(268).
+	RegisterPrefix map[string]bool
+	// RegisterNumber converts R(10) into arm.REG_R10.
+	RegisterNumber func(string, int16) (int16, bool)
+	// Instruction is a jump.
+	IsJump func(word string) bool
+}
+
+// nilRegisterNumber is the register number function for architectures
+// that do not accept the R(N) notation. It always returns failure.
+func nilRegisterNumber(name string, n int16) (int16, bool) {
+	return 0, false
+}
+
+var Pseudos = map[string]int{
+	"DATA":     obj.ADATA,
+	"FUNCDATA": obj.AFUNCDATA,
+	"GLOBL":    obj.AGLOBL,
+	"PCDATA":   obj.APCDATA,
+	"TEXT":     obj.ATEXT,
+}
+
+// Set configures the architecture specified by GOARCH and returns its representation.
+// It returns nil if GOARCH is not recognized.
+func Set(GOARCH string) *Arch {
+	switch GOARCH {
+	case "386":
+		return archX86(&x86.Link386)
+	case "amd64":
+		return archX86(&x86.Linkamd64)
+	case "amd64p32":
+		return archX86(&x86.Linkamd64p32)
+	case "arm":
+		return archArm()
+	case "arm64":
+		return archArm64()
+	case "ppc64":
+		a := archPPC64()
+		a.LinkArch = &ppc64.Linkppc64
+		return a
+	case "ppc64le":
+		a := archPPC64()
+		a.LinkArch = &ppc64.Linkppc64le
+		return a
+	}
+	return nil
+}
+
+func jumpX86(word string) bool {
+	return word[0] == 'J' || word == "CALL" || strings.HasPrefix(word, "LOOP")
+}
+
+func archX86(linkArch *obj.LinkArch) *Arch {
+	register := make(map[string]int16)
+	// Create maps for easy lookup of instruction names etc.
+	for i, s := range x86.Register {
+		register[s] = int16(i + x86.REG_AL)
+	}
+	// Pseudo-registers.
+	register["SB"] = RSB
+	register["FP"] = RFP
+	register["PC"] = RPC
+	// Register prefix not used on this architecture.
+
+	instructions := make(map[string]int)
+	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   /* alternate */
+	instructions["JAE"] = x86.AJCC  /* alternate */
+	instructions["JB"] = x86.AJCS   /* alternate */
+	instructions["JBE"] = x86.AJLS  /* alternate */
+	instructions["JC"] = x86.AJCS   /* alternate */
+	instructions["JCC"] = x86.AJCC  /* carry clear (CF = 0) */
+	instructions["JCS"] = x86.AJCS  /* carry set (CF = 1) */
+	instructions["JE"] = x86.AJEQ   /* alternate */
+	instructions["JEQ"] = x86.AJEQ  /* equal (ZF = 1) */
+	instructions["JG"] = x86.AJGT   /* alternate */
+	instructions["JGE"] = x86.AJGE  /* greater than or equal (signed) (SF = OF) */
+	instructions["JGT"] = x86.AJGT  /* greater than (signed) (ZF = 0 && SF = OF) */
+	instructions["JHI"] = x86.AJHI  /* higher (unsigned) (CF = 0 && ZF = 0) */
+	instructions["JHS"] = x86.AJCC  /* alternate */
+	instructions["JL"] = x86.AJLT   /* alternate */
+	instructions["JLE"] = x86.AJLE  /* less than or equal (signed) (ZF = 1 || SF != OF) */
+	instructions["JLO"] = x86.AJCS  /* alternate */
+	instructions["JLS"] = x86.AJLS  /* lower or same (unsigned) (CF = 1 || ZF = 1) */
+	instructions["JLT"] = x86.AJLT  /* less than (signed) (SF != OF) */
+	instructions["JMI"] = x86.AJMI  /* negative (minus) (SF = 1) */
+	instructions["JNA"] = x86.AJLS  /* alternate */
+	instructions["JNAE"] = x86.AJCS /* alternate */
+	instructions["JNB"] = x86.AJCC  /* alternate */
+	instructions["JNBE"] = x86.AJHI /* alternate */
+	instructions["JNC"] = x86.AJCC  /* alternate */
+	instructions["JNE"] = x86.AJNE  /* not equal (ZF = 0) */
+	instructions["JNG"] = x86.AJLE  /* alternate */
+	instructions["JNGE"] = x86.AJLT /* alternate */
+	instructions["JNL"] = x86.AJGE  /* alternate */
+	instructions["JNLE"] = x86.AJGT /* alternate */
+	instructions["JNO"] = x86.AJOC  /* alternate */
+	instructions["JNP"] = x86.AJPC  /* alternate */
+	instructions["JNS"] = x86.AJPL  /* alternate */
+	instructions["JNZ"] = x86.AJNE  /* alternate */
+	instructions["JO"] = x86.AJOS   /* alternate */
+	instructions["JOC"] = x86.AJOC  /* overflow clear (OF = 0) */
+	instructions["JOS"] = x86.AJOS  /* overflow set (OF = 1) */
+	instructions["JP"] = x86.AJPS   /* alternate */
+	instructions["JPC"] = x86.AJPC  /* parity clear (PF = 0) */
+	instructions["JPE"] = x86.AJPS  /* alternate */
+	instructions["JPL"] = x86.AJPL  /* non-negative (plus) (SF = 0) */
+	instructions["JPO"] = x86.AJPC  /* alternate */
+	instructions["JPS"] = x86.AJPS  /* parity set (PF = 1) */
+	instructions["JS"] = x86.AJMI   /* alternate */
+	instructions["JZ"] = x86.AJEQ   /* alternate */
+	instructions["MASKMOVDQU"] = x86.AMASKMOVOU
+	instructions["MOVD"] = x86.AMOVQ
+	instructions["MOVDQ2Q"] = x86.AMOVQ
+	instructions["MOVNTDQ"] = x86.AMOVNTO
+	instructions["MOVOA"] = x86.AMOVO
+	instructions["MOVOA"] = x86.AMOVO
+	instructions["PF2ID"] = x86.APF2IL
+	instructions["PI2FD"] = x86.API2FL
+	instructions["PSLLDQ"] = x86.APSLLO
+	instructions["PSRLDQ"] = x86.APSRLO
+
+	return &Arch{
+		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.
+	// 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)
+	}
+	// Avoid unintentionally clobbering g using R10.
+	delete(register, "R10")
+	register["g"] = arm.REG_R10
+	for i := 0; i < 16; i++ {
+		register[fmt.Sprintf("C%d", i)] = int16(i)
+	}
+
+	// Pseudo-registers.
+	register["SB"] = RSB
+	register["FP"] = RFP
+	register["PC"] = RPC
+	register["SP"] = RSP
+	registerPrefix := map[string]bool{
+		"F": true,
+		"R": true,
+	}
+
+	instructions := make(map[string]int)
+	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
+	// 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,
+		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.
+	// 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)
+	}
+	for i := ppc64.REG_F0; i <= ppc64.REG_F31; i++ {
+		register[obj.Rconv(i)] = int16(i)
+	}
+	for i := ppc64.REG_CR0; i <= ppc64.REG_CR7; i++ {
+		register[obj.Rconv(i)] = int16(i)
+	}
+	for i := ppc64.REG_MSR; i <= ppc64.REG_CR; i++ {
+		register[obj.Rconv(i)] = int16(i)
+	}
+	register["CR"] = ppc64.REG_CR
+	register["XER"] = ppc64.REG_XER
+	register["LR"] = ppc64.REG_LR
+	register["CTR"] = ppc64.REG_CTR
+	register["FPSCR"] = ppc64.REG_FPSCR
+	register["MSR"] = ppc64.REG_MSR
+	// Pseudo-registers.
+	register["SB"] = RSB
+	register["FP"] = RFP
+	register["PC"] = RPC
+	// Avoid unintentionally clobbering g using R30.
+	delete(register, "R30")
+	register["g"] = ppc64.REG_R30
+	registerPrefix := map[string]bool{
+		"CR":  true,
+		"F":   true,
+		"R":   true,
+		"SPR": true,
+	}
+
+	instructions := make(map[string]int)
+	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
+
+	return &Arch{
+		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
new file mode 100644
index 0000000..8df994e
--- /dev/null
+++ b/src/cmd/asm/internal/arch/arm.go
@@ -0,0 +1,248 @@
+// 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 ARM
+// instruction set, to minimize its interaction with the core of the
+// assembler.
+
+package arch
+
+import (
+	"strings"
+
+	"cmd/internal/obj"
+	"cmd/internal/obj/arm"
+)
+
+var armLS = map[string]uint8{
+	"U":  arm.C_UBIT,
+	"S":  arm.C_SBIT,
+	"W":  arm.C_WBIT,
+	"P":  arm.C_PBIT,
+	"PW": arm.C_WBIT | arm.C_PBIT,
+	"WP": arm.C_WBIT | arm.C_PBIT,
+}
+
+var armSCOND = map[string]uint8{
+	"EQ":  arm.C_SCOND_EQ,
+	"NE":  arm.C_SCOND_NE,
+	"CS":  arm.C_SCOND_HS,
+	"HS":  arm.C_SCOND_HS,
+	"CC":  arm.C_SCOND_LO,
+	"LO":  arm.C_SCOND_LO,
+	"MI":  arm.C_SCOND_MI,
+	"PL":  arm.C_SCOND_PL,
+	"VS":  arm.C_SCOND_VS,
+	"VC":  arm.C_SCOND_VC,
+	"HI":  arm.C_SCOND_HI,
+	"LS":  arm.C_SCOND_LS,
+	"GE":  arm.C_SCOND_GE,
+	"LT":  arm.C_SCOND_LT,
+	"GT":  arm.C_SCOND_GT,
+	"LE":  arm.C_SCOND_LE,
+	"AL":  arm.C_SCOND_NONE,
+	"U":   arm.C_UBIT,
+	"S":   arm.C_SBIT,
+	"W":   arm.C_WBIT,
+	"P":   arm.C_PBIT,
+	"PW":  arm.C_WBIT | arm.C_PBIT,
+	"WP":  arm.C_WBIT | arm.C_PBIT,
+	"F":   arm.C_FBIT,
+	"IBW": arm.C_WBIT | arm.C_PBIT | arm.C_UBIT,
+	"IAW": arm.C_WBIT | arm.C_UBIT,
+	"DBW": arm.C_WBIT | arm.C_PBIT,
+	"DAW": arm.C_WBIT,
+	"IB":  arm.C_PBIT | arm.C_UBIT,
+	"IA":  arm.C_UBIT,
+	"DB":  arm.C_PBIT,
+	"DA":  0,
+}
+
+var armJump = 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,
+	"JMP":  true,
+}
+
+func jumpArm(word string) bool {
+	return armJump[word]
+}
+
+// IsARMCMP reports whether the op (as defined by an arm.A* constant) is
+// one of the comparison instructions that require special handling.
+func IsARMCMP(op int) bool {
+	switch op {
+	case arm.ACMN, arm.ACMP, arm.ATEQ, arm.ATST:
+		return true
+	}
+	return false
+}
+
+// IsARMSTREX reports whether the op (as defined by an arm.A* constant) is
+// one of the STREX-like instructions that require special handling.
+func IsARMSTREX(op int) bool {
+	switch op {
+	case arm.ASTREX, arm.ASTREXD, arm.ASWPW, arm.ASWPBU:
+		return true
+	}
+	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, aMCR: // Note: aMCR is defined in this package.
+		return true
+	}
+	return false
+}
+
+// IsARMFloatCmp reports whether the op is a floating comparison instruction.
+func IsARMFloatCmp(op int) bool {
+	switch op {
+	case arm.ACMPF, arm.ACMPD:
+		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 {
+	switch op {
+	case arm.AMULA, arm.AMULAWB, arm.AMULAWT:
+		return true
+	}
+	return false
+}
+
+var bcode = []int{
+	arm.ABEQ,
+	arm.ABNE,
+	arm.ABCS,
+	arm.ABCC,
+	arm.ABMI,
+	arm.ABPL,
+	arm.ABVS,
+	arm.ABVC,
+	arm.ABHI,
+	arm.ABLS,
+	arm.ABGE,
+	arm.ABLT,
+	arm.ABGT,
+	arm.ABLE,
+	arm.AB,
+	obj.ANOP,
+}
+
+// ARMConditionCodes handles the special condition code situation for the ARM.
+// It returns a boolean to indicate success; failure means cond was unrecognized.
+func ARMConditionCodes(prog *obj.Prog, cond string) bool {
+	if cond == "" {
+		return true
+	}
+	bits, ok := ParseARMCondition(cond)
+	if !ok {
+		return false
+	}
+	/* hack to make B.NE etc. work: turn it into the corresponding conditional */
+	if prog.As == arm.AB {
+		prog.As = int16(bcode[(bits^arm.C_SCOND_XOR)&0xf])
+		bits = (bits &^ 0xf) | arm.C_SCOND_NONE
+	}
+	prog.Scond = bits
+	return true
+}
+
+// ParseARMCondition parses the conditions attached to an ARM instruction.
+// 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:]
+	}
+	if cond == "" {
+		return arm.C_SCOND_NONE, true
+	}
+	names := strings.Split(cond, ".")
+	bits := uint8(0)
+	for _, name := range names {
+		if b, present := ls[name]; present {
+			bits |= b
+			continue
+		}
+		if b, present := scond[name]; present {
+			bits = (bits &^ arm.C_SCOND) | b
+			continue
+		}
+		return 0, false
+	}
+	return bits, true
+}
+
+func armRegisterNumber(name string, n int16) (int16, bool) {
+	if n < 0 || 15 < n {
+		return 0, false
+	}
+	switch name {
+	case "R":
+		return arm.REG_R0 + n, true
+	case "F":
+		return arm.REG_F0 + n, true
+	}
+	return 0, false
+}
diff --git a/src/cmd/asm/internal/arch/arm64.go b/src/cmd/asm/internal/arch/arm64.go
new file mode 100644
index 0000000..0f29e81
--- /dev/null
+++ b/src/cmd/asm/internal/arch/arm64.go
@@ -0,0 +1,115 @@
+// 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,
+	"JMP":   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/arch/ppc64.go b/src/cmd/asm/internal/arch/ppc64.go
new file mode 100644
index 0000000..6523fbf
--- /dev/null
+++ b/src/cmd/asm/internal/arch/ppc64.go
@@ -0,0 +1,87 @@
+// 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
+// 64-bit PowerPC (PPC64) instruction set, to minimize its interaction
+// with the core of the assembler.
+
+package arch
+
+import "cmd/internal/obj/ppc64"
+
+func jumpPPC64(word string) bool {
+	switch word {
+	case "BC", "BCL", "BEQ", "BGE", "BGT", "BL", "BLE", "BLT", "BNE", "BR", "BVC", "BVS", "CALL", "JMP":
+		return true
+	}
+	return false
+}
+
+// IsPPC64RLD reports whether the op (as defined by an ppc64.A* constant) is
+// one of the RLD-like instructions that require special handling.
+// The FMADD-like instructions behave similarly.
+func IsPPC64RLD(op int) bool {
+	switch op {
+	case ppc64.ARLDC, ppc64.ARLDCCC, ppc64.ARLDCL, ppc64.ARLDCLCC,
+		ppc64.ARLDCR, ppc64.ARLDCRCC, ppc64.ARLDMI, ppc64.ARLDMICC,
+		ppc64.ARLWMI, ppc64.ARLWMICC, ppc64.ARLWNM, ppc64.ARLWNMCC:
+		return true
+	case ppc64.AFMADD, ppc64.AFMADDCC, ppc64.AFMADDS, ppc64.AFMADDSCC,
+		ppc64.AFMSUB, ppc64.AFMSUBCC, ppc64.AFMSUBS, ppc64.AFMSUBSCC,
+		ppc64.AFNMADD, ppc64.AFNMADDCC, ppc64.AFNMADDS, ppc64.AFNMADDSCC,
+		ppc64.AFNMSUB, ppc64.AFNMSUBCC, ppc64.AFNMSUBS, ppc64.AFNMSUBSCC:
+		return true
+	}
+	return false
+}
+
+// IsPPC64CMP reports whether the op (as defined by an ppc64.A* constant) is
+// one of the CMP instructions that require special handling.
+func IsPPC64CMP(op int) bool {
+	switch op {
+	case ppc64.ACMP, ppc64.ACMPU, ppc64.ACMPW, ppc64.ACMPWU:
+		return true
+	}
+	return false
+}
+
+// IsPPC64NEG reports whether the op (as defined by an ppc64.A* constant) is
+// one of the NEG-like instructions that require special handling.
+func IsPPC64NEG(op int) bool {
+	switch op {
+	case ppc64.AADDMECC, ppc64.AADDMEVCC, ppc64.AADDMEV, ppc64.AADDME,
+		ppc64.AADDZECC, ppc64.AADDZEVCC, ppc64.AADDZEV, ppc64.AADDZE,
+		ppc64.ACNTLZDCC, ppc64.ACNTLZD, ppc64.ACNTLZWCC, ppc64.ACNTLZW,
+		ppc64.AEXTSBCC, ppc64.AEXTSB, ppc64.AEXTSHCC, ppc64.AEXTSH,
+		ppc64.AEXTSWCC, ppc64.AEXTSW, ppc64.ANEGCC, ppc64.ANEGVCC,
+		ppc64.ANEGV, ppc64.ANEG, ppc64.ASLBMFEE, ppc64.ASLBMFEV,
+		ppc64.ASLBMTE, ppc64.ASUBMECC, ppc64.ASUBMEVCC, ppc64.ASUBMEV,
+		ppc64.ASUBME, ppc64.ASUBZECC, ppc64.ASUBZEVCC, ppc64.ASUBZEV,
+		ppc64.ASUBZE:
+		return true
+	}
+	return false
+}
+
+func ppc64RegisterNumber(name string, n int16) (int16, bool) {
+	switch name {
+	case "CR":
+		if 0 <= n && n <= 7 {
+			return ppc64.REG_CR0 + n, true
+		}
+	case "F":
+		if 0 <= n && n <= 31 {
+			return ppc64.REG_F0 + n, true
+		}
+	case "R":
+		if 0 <= n && n <= 31 {
+			return ppc64.REG_R0 + n, true
+		}
+	case "SPR":
+		if 0 <= n && n <= 1024 {
+			return ppc64.REG_SPR0 + n, true
+		}
+	}
+	return 0, false
+}
diff --git a/src/cmd/asm/internal/asm/asm.go b/src/cmd/asm/internal/asm/asm.go
new file mode 100644
index 0000000..3563c1a
--- /dev/null
+++ b/src/cmd/asm/internal/asm/asm.go
@@ -0,0 +1,662 @@
+// 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 asm
+
+import (
+	"bytes"
+	"fmt"
+	"text/scanner"
+
+	"cmd/asm/internal/arch"
+	"cmd/asm/internal/flags"
+	"cmd/asm/internal/lex"
+	"cmd/internal/obj"
+)
+
+// TODO: configure the architecture
+
+var testOut *bytes.Buffer // Gathers output when testing.
+
+// 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 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 {
+		p.firstProg = prog
+	} else {
+		p.lastProg.Link = prog
+	}
+	p.lastProg = prog
+	if doLabel {
+		p.pc++
+		for _, label := range p.pendingLabels {
+			if p.labels[label] != nil {
+				p.errorf("label %q multiply defined", label)
+			}
+			p.labels[label] = prog
+		}
+		p.pendingLabels = p.pendingLabels[0:0]
+	}
+	prog.Pc = int64(p.pc)
+	if *flags.Debug {
+		fmt.Println(p.histLineNum, prog)
+	}
+	if testOut != nil {
+		fmt.Fprintln(testOut, p.histLineNum, prog)
+	}
+}
+
+// validateSymbol checks that addr represents a valid name for a pseudo-op.
+func (p *Parser) validateSymbol(pseudo string, addr *obj.Addr, offsetOk bool) {
+	if addr.Name != obj.NAME_EXTERN && addr.Name != obj.NAME_STATIC || addr.Scale != 0 || addr.Reg != 0 {
+		p.errorf("%s symbol %q must be a symbol(SB)", pseudo, addr.Sym.Name)
+	}
+	if !offsetOk && addr.Offset != 0 {
+		p.errorf("%s symbol %q must not be offset from SB", pseudo, addr.Sym.Name)
+	}
+}
+
+// evalInteger evaluates an integer constant for a pseudo-op.
+func (p *Parser) evalInteger(pseudo string, operands []lex.Token) int64 {
+	addr := p.address(operands)
+	return p.getConstantPseudo(pseudo, &addr)
+}
+
+// validateImmediate checks that addr represents an immediate constant.
+func (p *Parser) validateImmediate(pseudo string, addr *obj.Addr) {
+	if addr.Type != obj.TYPE_CONST || addr.Name != 0 || addr.Reg != 0 || addr.Index != 0 {
+		p.errorf("%s: expected immediate constant; found %s", pseudo, obj.Dconv(&emptyProg, addr))
+	}
+}
+
+// asmText assembles a TEXT pseudo-op.
+// TEXT runtime·sigtramp(SB),4,$0-0
+func (p *Parser) asmText(word string, operands [][]lex.Token) {
+	if len(operands) != 2 && len(operands) != 3 {
+		p.errorf("expect two or three operands for TEXT")
+	}
+
+	// Labels are function scoped. Patch existing labels and
+	// create a new label space for this TEXT.
+	p.patch()
+	p.labels = make(map[string]*obj.Prog)
+
+	// Operand 0 is the symbol name in the form foo(SB).
+	// That means symbol plus indirect on SB and no offset.
+	nameAddr := p.address(operands[0])
+	p.validateSymbol("TEXT", &nameAddr, false)
+	name := nameAddr.Sym.Name
+	next := 1
+
+	// Next operand is the optional text flag, a literal integer.
+	var flag = int64(0)
+	if len(operands) == 3 {
+		flag = p.evalInteger("TEXT", operands[1])
+		next++
+	}
+
+	// Next operand is the frame and arg size.
+	// Bizarre syntax: $frameSize-argSize is two words, not subtraction.
+	// Both frameSize and argSize must be simple integers; only frameSize
+	// can be negative.
+	// The "-argSize" may be missing; if so, set it to obj.ArgsSizeUnknown.
+	// Parse left to right.
+	op := operands[next]
+	if len(op) < 2 || op[0].ScanToken != '$' {
+		p.errorf("TEXT %s: frame size must be an immediate constant", name)
+		return
+	}
+	op = op[1:]
+	negative := false
+	if op[0].ScanToken == '-' {
+		negative = true
+		op = op[1:]
+	}
+	if len(op) == 0 || op[0].ScanToken != scanner.Int {
+		p.errorf("TEXT %s: frame size must be an immediate constant", name)
+		return
+	}
+	frameSize := p.positiveAtoi(op[0].String())
+	if negative {
+		frameSize = -frameSize
+	}
+	op = op[1:]
+	argSize := int64(obj.ArgsSizeUnknown)
+	if len(op) > 0 {
+		// There is an argument size. It must be a minus sign followed by a non-negative integer literal.
+		if len(op) != 2 || op[0].ScanToken != '-' || op[1].ScanToken != scanner.Int {
+			p.errorf("TEXT %s: argument size must be of form -integer", name)
+		}
+		argSize = p.positiveAtoi(op[1].String())
+	}
+	prog := &obj.Prog{
+		Ctxt:   p.ctxt,
+		As:     obj.ATEXT,
+		Lineno: p.histLineNum,
+		From:   nameAddr,
+		From3: &obj.Addr{
+			Type:   obj.TYPE_CONST,
+			Offset: flag,
+		},
+		To: obj.Addr{
+			Type:   obj.TYPE_TEXTSIZE,
+			Offset: frameSize,
+			// Argsize set below.
+		},
+	}
+	prog.To.Val = int32(argSize)
+
+	p.append(prog, "", true)
+}
+
+// asmData assembles a DATA pseudo-op.
+// DATA masks<>+0x00(SB)/4, $0x00000000
+func (p *Parser) asmData(word string, operands [][]lex.Token) {
+	if len(operands) != 2 {
+		p.errorf("expect two operands for DATA")
+	}
+
+	// Operand 0 has the general form foo<>+0x04(SB)/4.
+	op := operands[0]
+	n := len(op)
+	if n < 3 || op[n-2].ScanToken != '/' || op[n-1].ScanToken != scanner.Int {
+		p.errorf("expect /size for DATA argument")
+	}
+	scale := p.parseScale(op[n-1].String())
+	op = op[:n-2]
+	nameAddr := p.address(op)
+	p.validateSymbol("DATA", &nameAddr, true)
+	name := nameAddr.Sym.Name
+
+	// Operand 1 is an immediate constant or address.
+	valueAddr := p.address(operands[1])
+	switch valueAddr.Type {
+	case obj.TYPE_CONST, obj.TYPE_FCONST, obj.TYPE_SCONST, obj.TYPE_ADDR:
+		// OK
+	default:
+		p.errorf("DATA value must be an immediate constant or address")
+	}
+
+	// The addresses must not overlap. Easiest test: require monotonicity.
+	if lastAddr, ok := p.dataAddr[name]; ok && nameAddr.Offset < lastAddr {
+		p.errorf("overlapping DATA entry for %s", name)
+	}
+	p.dataAddr[name] = nameAddr.Offset + int64(scale)
+
+	prog := &obj.Prog{
+		Ctxt:   p.ctxt,
+		As:     obj.ADATA,
+		Lineno: p.histLineNum,
+		From:   nameAddr,
+		From3: &obj.Addr{
+			Offset: int64(scale),
+		},
+		To: valueAddr,
+	}
+
+	p.append(prog, "", false)
+}
+
+// asmGlobl assembles a GLOBL pseudo-op.
+// GLOBL shifts<>(SB),8,$256
+// GLOBL shifts<>(SB),$256
+func (p *Parser) asmGlobl(word string, operands [][]lex.Token) {
+	if len(operands) != 2 && len(operands) != 3 {
+		p.errorf("expect two or three operands for GLOBL")
+	}
+
+	// Operand 0 has the general form foo<>+0x04(SB).
+	nameAddr := p.address(operands[0])
+	p.validateSymbol("GLOBL", &nameAddr, false)
+	next := 1
+
+	// Next operand is the optional flag, a literal integer.
+	var flag = int64(0)
+	if len(operands) == 3 {
+		flag = p.evalInteger("GLOBL", operands[1])
+		next++
+	}
+
+	// Final operand is an immediate constant.
+	addr := p.address(operands[next])
+	p.validateImmediate("GLOBL", &addr)
+
+	// log.Printf("GLOBL %s %d, $%d", name, flag, size)
+	prog := &obj.Prog{
+		Ctxt:   p.ctxt,
+		As:     obj.AGLOBL,
+		Lineno: p.histLineNum,
+		From:   nameAddr,
+		From3: &obj.Addr{
+			Offset: flag,
+		},
+		To: addr,
+	}
+	p.append(prog, "", false)
+}
+
+// asmPCData assembles a PCDATA pseudo-op.
+// PCDATA $2, $705
+func (p *Parser) asmPCData(word string, operands [][]lex.Token) {
+	if len(operands) != 2 {
+		p.errorf("expect two operands for PCDATA")
+	}
+
+	// Operand 0 must be an immediate constant.
+	key := p.address(operands[0])
+	p.validateImmediate("PCDATA", &key)
+
+	// Operand 1 must be an immediate constant.
+	value := p.address(operands[1])
+	p.validateImmediate("PCDATA", &value)
+
+	// log.Printf("PCDATA $%d, $%d", key.Offset, value.Offset)
+	prog := &obj.Prog{
+		Ctxt:   p.ctxt,
+		As:     obj.APCDATA,
+		Lineno: p.histLineNum,
+		From:   key,
+		To:     value,
+	}
+	p.append(prog, "", true)
+}
+
+// asmFuncData assembles a FUNCDATA pseudo-op.
+// FUNCDATA $1, funcdata<>+4(SB)
+func (p *Parser) asmFuncData(word string, operands [][]lex.Token) {
+	if len(operands) != 2 {
+		p.errorf("expect two operands for FUNCDATA")
+	}
+
+	// Operand 0 must be an immediate constant.
+	valueAddr := p.address(operands[0])
+	p.validateImmediate("FUNCDATA", &valueAddr)
+
+	// Operand 1 is a symbol name in the form foo(SB).
+	nameAddr := p.address(operands[1])
+	p.validateSymbol("FUNCDATA", &nameAddr, true)
+
+	prog := &obj.Prog{
+		Ctxt:   p.ctxt,
+		As:     obj.AFUNCDATA,
+		Lineno: p.histLineNum,
+		From:   valueAddr,
+		To:     nameAddr,
+	}
+	p.append(prog, "", true)
+}
+
+// asmJump assembles a jump instruction.
+// JMP	R1
+// JMP	exit
+// JMP	3(PC)
+func (p *Parser) asmJump(op int, cond string, a []obj.Addr) {
+	var target *obj.Addr
+	prog := &obj.Prog{
+		Ctxt:   p.ctxt,
+		Lineno: p.histLineNum,
+		As:     int16(op),
+	}
+	switch len(a) {
+	case 1:
+		target = &a[0]
+	case 2:
+		// Special 2-operand jumps.
+		target = &a[1]
+		prog.From = a[0]
+	case 3:
+		if p.arch.Thechar == '9' {
+			// Special 3-operand jumps.
+			// First two must be constants; a[1] is a register number.
+			target = &a[2]
+			prog.From = obj.Addr{
+				Type:   obj.TYPE_CONST,
+				Offset: p.getConstant(prog, op, &a[0]),
+			}
+			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", obj.Aconv(op))
+		return
+	}
+	switch {
+	case target.Type == obj.TYPE_BRANCH:
+		// JMP 4(PC)
+		prog.To = obj.Addr{
+			Type:   obj.TYPE_BRANCH,
+			Offset: p.pc + 1 + target.Offset, // +1 because p.pc is incremented in append, below.
+		}
+	case target.Type == obj.TYPE_REG:
+		// JMP R1
+		prog.To = *target
+	case target.Type == obj.TYPE_MEM && (target.Name == obj.NAME_EXTERN || target.Name == obj.NAME_STATIC):
+		// JMP main·morestack(SB)
+		prog.To = *target
+	case target.Type == obj.TYPE_INDIR && (target.Name == obj.NAME_EXTERN || target.Name == obj.NAME_STATIC):
+		// JMP *main·morestack(SB)
+		prog.To = *target
+		prog.To.Type = obj.TYPE_INDIR
+	case target.Type == obj.TYPE_MEM && target.Reg == 0 && target.Offset == 0:
+		// JMP exit
+		if target.Sym == nil {
+			// Parse error left name unset.
+			return
+		}
+		targetProg := p.labels[target.Sym.Name]
+		if targetProg == nil {
+			p.toPatch = append(p.toPatch, Patch{prog, target.Sym.Name})
+		} else {
+			p.branch(prog, targetProg)
+		}
+	case target.Type == obj.TYPE_MEM && target.Name == obj.NAME_NONE:
+		// JMP 4(R0)
+		prog.To = *target
+		// On the ppc64, 9a encodes BR (CTR) as BR CTR. We do the same.
+		if p.arch.Thechar == '9' && target.Offset == 0 {
+			prog.To.Type = obj.TYPE_REG
+		}
+	case target.Type == obj.TYPE_CONST:
+		// JMP $4
+		prog.To = a[0]
+	default:
+		p.errorf("cannot assemble jump %+v", target)
+	}
+
+	p.append(prog, cond, true)
+}
+
+func (p *Parser) patch() {
+	for _, patch := range p.toPatch {
+		targetProg := p.labels[patch.label]
+		if targetProg == nil {
+			p.errorf("undefined label %s", patch.label)
+		} else {
+			p.branch(patch.prog, targetProg)
+		}
+	}
+	p.toPatch = p.toPatch[:0]
+}
+
+func (p *Parser) branch(jmp, target *obj.Prog) {
+	jmp.To = obj.Addr{
+		Type:  obj.TYPE_BRANCH,
+		Index: 0,
+	}
+	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", obj.Aconv(op), a)
+	prog := &obj.Prog{
+		Ctxt:   p.ctxt,
+		Lineno: p.histLineNum,
+		As:     int16(op),
+	}
+	switch len(a) {
+	case 0:
+		// Nothing to do.
+	case 1:
+		if p.arch.UnaryDst[op] {
+			// prog.From is no address.
+			prog.To = a[0]
+		} else {
+			prog.From = a[0]
+			// prog.To is no address.
+		}
+		if p.arch.Thechar == '9' && arch.IsPPC64NEG(op) {
+			// NEG: From and To are both a[0].
+			prog.To = a[0]
+			prog.From = a[0]
+			break
+		}
+	case 2:
+		if p.arch.Thechar == '5' {
+			if arch.IsARMCMP(op) {
+				prog.From = a[0]
+				prog.Reg = p.getRegister(prog, op, &a[1])
+				break
+			}
+			// Strange special cases.
+			if arch.IsARMSTREX(op) {
+				/*
+					STREX x, (y)
+						from=(y) reg=x to=x
+					STREX (x), y
+						from=(x) reg=y to=y
+				*/
+				if a[0].Type == obj.TYPE_REG && a[1].Type != obj.TYPE_REG {
+					prog.From = a[1]
+					prog.Reg = a[0].Reg
+					prog.To = a[0]
+					break
+				} else if a[0].Type != obj.TYPE_REG && a[1].Type == obj.TYPE_REG {
+					prog.From = a[0]
+					prog.Reg = a[1].Reg
+					prog.To = a[1]
+					break
+				}
+				p.errorf("unrecognized addressing for %s", obj.Aconv(op))
+			}
+			if arch.IsARMFloatCmp(op) {
+				prog.From = a[0]
+				prog.Reg = p.getRegister(prog, op, &a[1])
+				break
+			}
+		} 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]
+	case 3:
+		switch p.arch.Thechar {
+		case '5':
+			// Special cases.
+			if arch.IsARMSTREX(op) {
+				/*
+					STREX x, (y), z
+						from=(y) reg=x to=z
+				*/
+				prog.From = a[1]
+				prog.Reg = p.getRegister(prog, op, &a[0])
+				prog.To = a[2]
+				break
+			}
+			// Otherwise the 2nd operand (a[1]) must be a register.
+			prog.From = a[0]
+			prog.Reg = p.getRegister(prog, op, &a[1])
+			prog.To = a[2]
+		case '7':
+			// ARM64 instructions with one input and two outputs.
+			if arch.IsARM64STLXR(op) {
+				prog.From = a[0]
+				prog.To = a[1]
+				if a[2].Type != obj.TYPE_REG {
+					p.errorf("invalid addressing modes for third operand to %s instruction, must be register", obj.Aconv(op))
+				}
+				prog.RegTo2 = a[2].Reg
+				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 = newAddr(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.
+				prog.From = a[0]
+				prog.Reg = p.getRegister(prog, op, &a[2])
+				prog.To = a[1]
+				break
+			}
+			// Arithmetic. Choices are:
+			// reg reg reg
+			// imm reg reg
+			// reg imm reg
+			// If the immediate is the middle argument, use From3.
+			switch a[1].Type {
+			case obj.TYPE_REG:
+				prog.From = a[0]
+				prog.Reg = p.getRegister(prog, op, &a[1])
+				prog.To = a[2]
+			case obj.TYPE_CONST:
+				prog.From = a[0]
+				prog.From3 = newAddr(a[1])
+				prog.To = a[2]
+			default:
+				p.errorf("invalid addressing modes for %s instruction", obj.Aconv(op))
+			}
+		default:
+			p.errorf("TODO: implement three-operand instructions for this architecture")
+		}
+	case 4:
+		if p.arch.Thechar == '5' && arch.IsARMMULA(op) {
+			// All must be registers.
+			p.getRegister(prog, op, &a[0])
+			r1 := p.getRegister(prog, op, &a[1])
+			p.getRegister(prog, op, &a[2])
+			r3 := p.getRegister(prog, op, &a[3])
+			prog.From = a[0]
+			prog.To = a[2]
+			prog.To.Type = obj.TYPE_REGREG2
+			prog.To.Offset = int64(r3)
+			prog.Reg = r1
+			break
+		}
+		if p.arch.Thechar == '7' {
+			prog.From = a[0]
+			prog.Reg = p.getRegister(prog, op, &a[1])
+			prog.From3 = newAddr(a[2])
+			prog.To = a[3]
+			break
+		}
+		if p.arch.Thechar == '9' && arch.IsPPC64RLD(op) {
+			// 2nd operand must always be a register.
+			// TODO: Do we need to guard this with the instruction type?
+			// That is, are there 4-operand instructions without this property?
+			prog.From = a[0]
+			prog.Reg = p.getRegister(prog, op, &a[1])
+			prog.From3 = newAddr(a[2])
+			prog.To = a[3]
+			break
+		}
+		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').
+			prog.From = a[0]
+			prog.Reg = p.getRegister(prog, op, &a[1])
+			mask1 := p.getConstant(prog, op, &a[2])
+			mask2 := p.getConstant(prog, op, &a[3])
+			var mask uint32
+			if mask1 < mask2 {
+				mask = (^uint32(0) >> uint(mask1)) & (^uint32(0) << uint(31-mask2))
+			} else {
+				mask = (^uint32(0) >> uint(mask2+1)) & (^uint32(0) << uint(31-(mask1-1)))
+			}
+			prog.From3 = &obj.Addr{
+				Type:   obj.TYPE_CONST,
+				Offset: int64(mask),
+			}
+			prog.To = a[4]
+			break
+		}
+		p.errorf("can't handle %s instruction with 5 operands", obj.Aconv(op))
+	case 6:
+		if p.arch.Thechar == '5' && arch.IsARMMRC(op) {
+			// Strange special case: MCR, MRC.
+			prog.To.Type = obj.TYPE_CONST
+			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])
+			// 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 = offset
+			cond = ""
+			prog.As = MRC // Both instructions are coded as MRC.
+			break
+		}
+		fallthrough
+	default:
+		p.errorf("can't handle %s instruction with %d operands", obj.Aconv(op), len(a))
+	}
+
+	p.append(prog, cond, true)
+}
+
+// newAddr returns a new(Addr) initialized to x.
+func newAddr(x obj.Addr) *obj.Addr {
+	p := new(obj.Addr)
+	*p = x
+	return p
+}
+
+var emptyProg obj.Prog
+
+// getConstantPseudo checks that addr represents a plain constant and returns its value.
+func (p *Parser) getConstantPseudo(pseudo string, 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", pseudo, obj.Dconv(&emptyProg, addr))
+	}
+	return addr.Offset
+}
+
+// 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", obj.Aconv(op), obj.Dconv(prog, addr))
+	}
+	return addr.Offset
+}
+
+// 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", obj.Aconv(op), obj.Dconv(prog, addr))
+	}
+	return addr.Offset
+}
+
+// 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", 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
new file mode 100644
index 0000000..abe4e4e
--- /dev/null
+++ b/src/cmd/asm/internal/asm/endtoend_test.go
@@ -0,0 +1,91 @@
+// 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 asm
+
+import (
+	"bytes"
+	"fmt"
+	"io/ioutil"
+	"log"
+	"os"
+	"path/filepath"
+	"strings"
+	"testing"
+
+	"cmd/asm/internal/lex"
+	"cmd/internal/obj"
+)
+
+// An end-to-end test for the assembler: Do we print what we parse?
+// Output is generated by, in effect, turning on -S and comparing the
+// result against a golden file.
+
+func testEndToEnd(t *testing.T, goarch string) {
+	lex.InitHist()
+	input := filepath.Join("testdata", goarch+".s")
+	output := filepath.Join("testdata", goarch+".out")
+	architecture, ctxt := setArch(goarch)
+	lexer := lex.NewLexer(input, ctxt)
+	parser := NewParser(ctxt, architecture, lexer)
+	pList := obj.Linknewplist(ctxt)
+	var ok bool
+	testOut = new(bytes.Buffer) // The assembler writes -S output to this buffer.
+	ctxt.Bso = obj.Binitw(os.Stdout)
+	defer ctxt.Bso.Flush()
+	ctxt.Diag = log.Fatalf
+	obj.Binitw(ioutil.Discard)
+	pList.Firstpc, ok = parser.Parse()
+	if !ok {
+		t.Fatalf("asm: %s assembly failed", goarch)
+	}
+	result := string(testOut.Bytes())
+	expect, err := ioutil.ReadFile(output)
+	// For Windows.
+	result = strings.Replace(result, `testdata\`, `testdata/`, -1)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if result != string(expect) {
+		if false { // Enable to capture output.
+			fmt.Printf("%s", result)
+			os.Exit(1)
+		}
+		t.Errorf("%s failed: output differs", goarch)
+		r := strings.Split(result, "\n")
+		e := strings.Split(string(expect), "\n")
+		if len(r) != len(e) {
+			t.Errorf("%s: expected %d lines, got %d", goarch, len(e), len(r))
+		}
+		n := len(e)
+		if n > len(r) {
+			n = len(r)
+		}
+		for i := 0; i < n; i++ {
+			if r[i] != e[i] {
+				t.Errorf("%s:%d:\nexpected\n\t%s\ngot\n\t%s", output, i, e[i], r[i])
+			}
+		}
+	}
+}
+
+func TestPPC64EndToEnd(t *testing.T) {
+	testEndToEnd(t, "ppc64")
+}
+
+func TestARMEndToEnd(t *testing.T) {
+	testEndToEnd(t, "arm")
+}
+
+func TestARM64EndToEnd(t *testing.T) {
+	testEndToEnd(t, "arm64")
+}
+
+func TestAMD64EndToEnd(t *testing.T) {
+	testEndToEnd(t, "amd64")
+}
+
+func Test386EndToEnd(t *testing.T) {
+	testEndToEnd(t, "386")
+}
diff --git a/src/cmd/asm/internal/asm/expr_test.go b/src/cmd/asm/internal/asm/expr_test.go
new file mode 100644
index 0000000..eafbc5f
--- /dev/null
+++ b/src/cmd/asm/internal/asm/expr_test.go
@@ -0,0 +1,131 @@
+// 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 asm
+
+import (
+	"cmd/asm/internal/lex"
+	"strings"
+	"testing"
+	"text/scanner"
+)
+
+type exprTest struct {
+	input  string
+	output int64
+	atEOF  bool
+}
+
+var exprTests = []exprTest{
+	// Simple
+	{"0", 0, true},
+	{"3", 3, true},
+	{"070", 8 * 7, true},
+	{"0x0f", 15, true},
+	{"0xFF", 255, true},
+	{"9223372036854775807", 9223372036854775807, true}, // max int64
+	// Unary
+	{"-0", 0, true},
+	{"~0", -1, true},
+	{"~0*0", 0, true},
+	{"+3", 3, true},
+	{"-3", -3, true},
+	{"-9223372036854775808", -9223372036854775808, true}, // min int64
+	// Binary
+	{"3+4", 3 + 4, true},
+	{"3-4", 3 - 4, true},
+	{"2|5", 2 | 5, true},
+	{"3^4", 3 ^ 4, true},
+	{"3*4", 3 * 4, true},
+	{"14/4", 14 / 4, true},
+	{"3<<4", 3 << 4, true},
+	{"48>>3", 48 >> 3, true},
+	{"3&9", 3 & 9, true},
+	// General
+	{"3*2+3", 3*2 + 3, true},
+	{"3+2*3", 3 + 2*3, true},
+	{"3*(2+3)", 3 * (2 + 3), true},
+	{"3*-(2+3)", 3 * -(2 + 3), true},
+	{"3<<2+4", 3<<2 + 4, true},
+	{"3<<2+4", 3<<2 + 4, true},
+	{"3<<(2+4)", 3 << (2 + 4), true},
+	// Junk at EOF.
+	{"3 x", 3, false},
+	// Big number
+	{"4611686018427387904", 4611686018427387904, true},
+}
+
+func TestExpr(t *testing.T) {
+	p := NewParser(nil, nil, nil) // Expression evaluation uses none of these fields of the parser.
+	for i, test := range exprTests {
+		p.start(lex.Tokenize(test.input))
+		result := int64(p.expr())
+		if result != test.output {
+			t.Errorf("%d: %q evaluated to %d; expected %d", i, test.input, result, test.output)
+		}
+		tok := p.next()
+		if test.atEOF && tok.ScanToken != scanner.EOF {
+			t.Errorf("%d: %q: at EOF got %s", i, test.input, tok)
+		} else if !test.atEOF && tok.ScanToken == scanner.EOF {
+			t.Errorf("%d: %q: expected not EOF but at EOF", i, test.input)
+		}
+	}
+}
+
+type badExprTest struct {
+	input string
+	error string // Empty means no error.
+}
+
+var badExprTests = []badExprTest{
+	{"0/0", "division by zero"},
+	{"3/0", "division by zero"},
+	{"(1<<63)/0", "divide of value with high bit set"},
+	{"3%0", "modulo by zero"},
+	{"(1<<63)%0", "modulo of value with high bit set"},
+	{"3<<-4", "negative left shift count"},
+	{"3<<(1<<63)", "negative left shift count"},
+	{"3>>-4", "negative right shift count"},
+	{"3>>(1<<63)", "negative right shift count"},
+	{"(1<<63)>>2", "right shift of value with high bit set"},
+	{"(1<<62)>>2", ""},
+	{`'\x80'`, "illegal UTF-8 encoding for character constant"},
+	{"(23*4", "missing closing paren"},
+	{")23*4", "unexpected ) evaluating expression"},
+	{"18446744073709551616", "value out of range"},
+}
+
+func TestBadExpr(t *testing.T) {
+	panicOnError = true
+	defer func() {
+		panicOnError = false
+	}()
+	for i, test := range badExprTests {
+		err := runBadTest(i, test, t)
+		if err == nil {
+			if test.error != "" {
+				t.Errorf("#%d: %q: expected error %q; got none", i, test.input, test.error)
+			}
+			continue
+		}
+		if !strings.Contains(err.Error(), test.error) {
+			t.Errorf("#%d: expected error %q; got %q", i, test.error, err)
+			continue
+		}
+	}
+}
+
+func runBadTest(i int, test badExprTest, t *testing.T) (err error) {
+	p := NewParser(nil, nil, nil) // Expression evaluation uses none of these fields of the parser.
+	p.start(lex.Tokenize(test.input))
+	defer func() {
+		e := recover()
+		var ok bool
+		if err, ok = e.(error); e != nil && !ok {
+			t.Fatal(e)
+		}
+	}()
+	p.expr()
+	return nil
+}
diff --git a/src/cmd/asm/internal/asm/operand_test.go b/src/cmd/asm/internal/asm/operand_test.go
new file mode 100644
index 0000000..01335ed
--- /dev/null
+++ b/src/cmd/asm/internal/asm/operand_test.go
@@ -0,0 +1,430 @@
+// 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 asm
+
+import (
+	"os"
+	"testing"
+
+	"cmd/asm/internal/arch"
+	"cmd/asm/internal/lex"
+	"cmd/internal/obj"
+)
+
+// A simple in-out test: Do we print what we parse?
+
+func setArch(goarch string) (*arch.Arch, *obj.Link) {
+	os.Setenv("GOOS", "linux") // obj can handle this OS for all architectures.
+	architecture := arch.Set(goarch)
+	if architecture == nil {
+		panic("asm: unrecognized architecture " + goarch)
+	}
+	return architecture, obj.Linknew(architecture.LinkArch)
+}
+
+func newParser(goarch string) *Parser {
+	architecture, ctxt := setArch(goarch)
+	return NewParser(ctxt, architecture, nil)
+}
+
+func testOperandParser(t *testing.T, parser *Parser, tests []operandTest) {
+	for _, test := range tests {
+		parser.start(lex.Tokenize(test.input))
+		addr := obj.Addr{}
+		parser.operand(&addr)
+		result := obj.Dconv(&emptyProg, &addr)
+		if result != test.output {
+			t.Errorf("fail at %s: got %s; expected %s\n", test.input, result, test.output)
+		}
+	}
+}
+
+func TestAMD64OperandParser(t *testing.T) {
+	parser := newParser("amd64")
+	testOperandParser(t, parser, amd64OperandTests)
+}
+
+func Test386OperandParser(t *testing.T) {
+	parser := newParser("386")
+	testOperandParser(t, parser, x86OperandTests)
+}
+
+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)
+}
+
+type operandTest struct {
+	input, output string
+}
+
+// Examples collected by scanning all the assembly in the standard repo.
+
+var amd64OperandTests = []operandTest{
+	{"$(-1.0)", "$(-1.0)"},
+	{"$(0.0)", "$(0.0)"},
+	{"$(0x2000000+116)", "$33554548"},
+	{"$(0x3F<<7)", "$8064"},
+	{"$(112+8)", "$120"},
+	{"$(1<<63)", "$-9223372036854775808"},
+	{"$-1", "$-1"},
+	{"$0", "$0"},
+	{"$0-0", "$0"},
+	{"$0-16", "$-16"},
+	{"$0x000FFFFFFFFFFFFF", "$4503599627370495"},
+	{"$0x01", "$1"},
+	{"$0x02", "$2"},
+	{"$0x04", "$4"},
+	{"$0x3FE", "$1022"},
+	{"$0x7fffffe00000", "$140737486258176"},
+	{"$0xfffffffffffff001", "$-4095"},
+	{"$1", "$1"},
+	{"$1.0", "$(1.0)"},
+	{"$10", "$10"},
+	{"$1000", "$1000"},
+	{"$1000000", "$1000000"},
+	{"$1000000000", "$1000000000"},
+	{"$__tsan_func_enter(SB)", "$__tsan_func_enter(SB)"},
+	{"$main(SB)", "$main(SB)"},
+	{"$masks<>(SB)", "$masks<>(SB)"},
+	{"$setg_gcc<>(SB)", "$setg_gcc<>(SB)"},
+	{"$shifts<>(SB)", "$shifts<>(SB)"},
+	{"$~(1<<63)", "$9223372036854775807"},
+	{"$~0x3F", "$-64"},
+	{"$~15", "$-16"},
+	{"(((8)&0xf)*4)(SP)", "32(SP)"},
+	{"(((8-14)&0xf)*4)(SP)", "40(SP)"},
+	{"(6+8)(AX)", "14(AX)"},
+	{"(8*4)(BP)", "32(BP)"},
+	{"(AX)", "(AX)"},
+	{"(AX)(CX*8)", "(AX)(CX*8)"},
+	{"(BP)(CX*4)", "(BP)(CX*4)"},
+	{"(BP)(DX*4)", "(BP)(DX*4)"},
+	{"(BP)(R8*4)", "(BP)(R8*4)"},
+	{"(BX)", "(BX)"},
+	{"(DI)", "(DI)"},
+	{"(DI)(BX*1)", "(DI)(BX*1)"},
+	{"(DX)", "(DX)"},
+	{"(R9)", "(R9)"},
+	{"(R9)(BX*8)", "(R9)(BX*8)"},
+	{"(SI)", "(SI)"},
+	{"(SI)(BX*1)", "(SI)(BX*1)"},
+	{"(SI)(DX*1)", "(SI)(DX*1)"},
+	{"(SP)", "(SP)"},
+	{"+3(PC)", "3(PC)"},
+	{"-1(DI)(BX*1)", "-1(DI)(BX*1)"},
+	{"-3(PC)", "-3(PC)"},
+	{"-64(SI)(BX*1)", "-64(SI)(BX*1)"},
+	{"-96(SI)(BX*1)", "-96(SI)(BX*1)"},
+	{"AL", "AL"},
+	{"AX", "AX"},
+	{"BP", "BP"},
+	{"BX", "BX"},
+	{"CX", "CX"},
+	{"DI", "DI"},
+	{"DX", "DX"},
+	{"R10", "R10"},
+	{"R10", "R10"},
+	{"R11", "R11"},
+	{"R12", "R12"},
+	{"R13", "R13"},
+	{"R14", "R14"},
+	{"R15", "R15"},
+	{"R8", "R8"},
+	{"R9", "R9"},
+	{"SI", "SI"},
+	{"SP", "SP"},
+	{"X0", "X0"},
+	{"X1", "X1"},
+	{"X10", "X10"},
+	{"X11", "X11"},
+	{"X12", "X12"},
+	{"X13", "X13"},
+	{"X14", "X14"},
+	{"X15", "X15"},
+	{"X2", "X2"},
+	{"X3", "X3"},
+	{"X4", "X4"},
+	{"X5", "X5"},
+	{"X6", "X6"},
+	{"X7", "X7"},
+	{"X8", "X8"},
+	{"X9", "X9"},
+	{"_expand_key_128<>(SB)", "_expand_key_128<>(SB)"},
+	{"_seek<>(SB)", "_seek<>(SB)"},
+	{"a2+16(FP)", "a2+16(FP)"},
+	{"addr2+24(FP)", "addr2+24(FP)"},
+	{"asmcgocall<>(SB)", "asmcgocall<>(SB)"},
+	{"b+24(FP)", "b+24(FP)"},
+	{"b_len+32(FP)", "b_len+32(FP)"},
+	{"racecall<>(SB)", "racecall<>(SB)"},
+	{"rcv_name+20(FP)", "rcv_name+20(FP)"},
+	{"retoffset+28(FP)", "retoffset+28(FP)"},
+	{"runtime·_GetStdHandle(SB)", "runtime._GetStdHandle(SB)"},
+	{"sync\u2215atomic·AddInt64(SB)", "sync/atomic.AddInt64(SB)"},
+	{"timeout+20(FP)", "timeout+20(FP)"},
+	{"ts+16(FP)", "ts+16(FP)"},
+	{"x+24(FP)", "x+24(FP)"},
+	{"x·y(SB)", "x.y(SB)"},
+	{"x·y(SP)", "x.y(SP)"},
+	{"x·y+8(SB)", "x.y+8(SB)"},
+	{"x·y+8(SP)", "x.y+8(SP)"},
+	{"y+56(FP)", "y+56(FP)"},
+	{"·AddUint32(SB)", "\"\".AddUint32(SB)"},
+	{"·callReflect(SB)", "\"\".callReflect(SB)"},
+}
+
+var x86OperandTests = []operandTest{
+	{"$(2.928932188134524e-01)", "$(0.29289321881345243)"},
+	{"$-1", "$-1"},
+	{"$0", "$0"},
+	{"$0x00000000", "$0"},
+	{"$runtime·badmcall(SB)", "$runtime.badmcall(SB)"},
+	{"$setg_gcc<>(SB)", "$setg_gcc<>(SB)"},
+	{"$~15", "$-16"},
+	{"(-64*1024+104)(SP)", "-65432(SP)"},
+	{"(0*4)(BP)", "(BP)"},
+	{"(1*4)(DI)", "4(DI)"},
+	{"(4*4)(BP)", "16(BP)"},
+	{"(AX)", "(AX)"},
+	{"(BP)(CX*4)", "(BP)(CX*4)"},
+	{"(BP*8)", "0(BP*8)"},
+	{"(BX)", "(BX)"},
+	{"(SP)", "(SP)"},
+	{"*AX", "AX"}, // TODO: Should make * illegal here; a simple alias for JMP AX.
+	{"*runtime·_GetStdHandle(SB)", "*runtime._GetStdHandle(SB)"},
+	{"-(4+12)(DI)", "-16(DI)"},
+	{"-1(DI)(BX*1)", "-1(DI)(BX*1)"},
+	{"-96(DI)(BX*1)", "-96(DI)(BX*1)"},
+	{"0(AX)", "(AX)"},
+	{"0(BP)", "(BP)"},
+	{"0(BX)", "(BX)"},
+	{"4(AX)", "4(AX)"},
+	{"AL", "AL"},
+	{"AX", "AX"},
+	{"BP", "BP"},
+	{"BX", "BX"},
+	{"CX", "CX"},
+	{"DI", "DI"},
+	{"DX", "DX"},
+	{"F0", "F0"},
+	{"GS", "GS"},
+	{"SI", "SI"},
+	{"SP", "SP"},
+	{"X0", "X0"},
+	{"X1", "X1"},
+	{"X2", "X2"},
+	{"X3", "X3"},
+	{"X4", "X4"},
+	{"X5", "X5"},
+	{"X6", "X6"},
+	{"X7", "X7"},
+	{"asmcgocall<>(SB)", "asmcgocall<>(SB)"},
+	{"ax+4(FP)", "ax+4(FP)"},
+	{"ptime-12(SP)", "ptime-12(SP)"},
+	{"runtime·_NtWaitForSingleObject(SB)", "runtime._NtWaitForSingleObject(SB)"},
+	{"s(FP)", "s(FP)"},
+	{"sec+4(FP)", "sec+4(FP)"},
+	{"shifts<>(SB)(CX*8)", "shifts<>(SB)(CX*8)"},
+	{"x+4(FP)", "x+4(FP)"},
+	{"·AddUint32(SB)", "\"\".AddUint32(SB)"},
+	{"·reflectcall(SB)", "\"\".reflectcall(SB)"},
+}
+
+var armOperandTests = []operandTest{
+	{"$0", "$0"},
+	{"$256", "$256"},
+	{"(R0)", "(R0)"},
+	{"(R11)", "(R11)"},
+	{"(g)", "(g)"},
+	{"-12(R4)", "-12(R4)"},
+	{"0(PC)", "0(PC)"},
+	{"1024", "1024"},
+	{"12(R(1))", "12(R1)"},
+	{"12(R13)", "12(R13)"},
+	{"R0", "R0"},
+	{"R0->(32-1)", "R0->31"},
+	{"R0<<R1", "R0<<R1"},
+	{"R0>>R(1)", "R0>>R1"},
+	{"R0@>(32-1)", "R0@>31"},
+	{"R1", "R1"},
+	{"R11", "R11"},
+	{"R12", "R12"},
+	{"R13", "R13"},
+	{"R14", "R14"},
+	{"R15", "R15"},
+	{"R1<<2(R3)", "R1<<2(R3)"},
+	{"R(1)<<2(R(3))", "R1<<2(R3)"},
+	{"R2", "R2"},
+	{"R3", "R3"},
+	{"R4", "R4"},
+	{"R(4)", "R4"},
+	{"R5", "R5"},
+	{"R6", "R6"},
+	{"R7", "R7"},
+	{"R8", "R8"},
+	{"[R0,R1,g,R15]", "[R0,R1,g,R15]"},
+	{"[R0-R7]", "[R0,R1,R2,R3,R4,R5,R6,R7]"},
+	{"[R(0)-R(7)]", "[R0,R1,R2,R3,R4,R5,R6,R7]"},
+	{"[R0]", "[R0]"},
+	{"[R1-R12]", "[R1,R2,R3,R4,R5,R6,R7,R8,R9,g,R11,R12]"},
+	{"armCAS64(SB)", "armCAS64(SB)"},
+	{"asmcgocall<>(SB)", "asmcgocall<>(SB)"},
+	{"c+28(FP)", "c+28(FP)"},
+	{"g", "g"},
+	{"gosave<>(SB)", "gosave<>(SB)"},
+	{"retlo+12(FP)", "retlo+12(FP)"},
+	{"runtime·_sfloat2(SB)", "runtime._sfloat2(SB)"},
+	{"·AddUint32(SB)", "\"\".AddUint32(SB)"},
+	{"(R1, R3)", "(R1, R3)"},
+	{"[R0,R1,g,R15", ""}, // Issue 11764 - previously asm just hung parsing ']' missing register lists
+}
+
+var ppc64OperandTests = []operandTest{
+	{"$((1<<63)-1)", "$9223372036854775807"},
+	{"$(-64*1024)", "$-65536"},
+	{"$(1024 * 8)", "$8192"},
+	{"$-1", "$-1"},
+	{"$-24(R4)", "$-24(R4)"},
+	{"$0", "$0"},
+	{"$0(R1)", "$(R1)"},
+	{"$0.5", "$(0.5)"},
+	{"$0x7000", "$28672"},
+	{"$0x88888eef", "$2290650863"},
+	{"$1", "$1"},
+	{"$_main<>(SB)", "$_main<>(SB)"},
+	{"$argframe(FP)", "$argframe(FP)"},
+	{"$runtime·tlsg(SB)", "$runtime.tlsg(SB)"},
+	{"$~3", "$-4"},
+	{"(-288-3*8)(R1)", "-312(R1)"},
+	{"(16)(R7)", "16(R7)"},
+	{"(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)"},
+	{"CR7", "CR7"},
+	{"CTR", "CTR"},
+	{"F14", "F14"},
+	{"F15", "F15"},
+	{"F16", "F16"},
+	{"F17", "F17"},
+	{"F18", "F18"},
+	{"F19", "F19"},
+	{"F20", "F20"},
+	{"F21", "F21"},
+	{"F22", "F22"},
+	{"F23", "F23"},
+	{"F24", "F24"},
+	{"F25", "F25"},
+	{"F26", "F26"},
+	{"F27", "F27"},
+	{"F28", "F28"},
+	{"F29", "F29"},
+	{"F30", "F30"},
+	{"F31", "F31"},
+	{"LR", "LR"},
+	{"R0", "R0"},
+	{"R1", "R1"},
+	{"R11", "R11"},
+	{"R12", "R12"},
+	{"R13", "R13"},
+	{"R14", "R14"},
+	{"R15", "R15"},
+	{"R16", "R16"},
+	{"R17", "R17"},
+	{"R18", "R18"},
+	{"R19", "R19"},
+	{"R2", "R2"},
+	{"R20", "R20"},
+	{"R21", "R21"},
+	{"R22", "R22"},
+	{"R23", "R23"},
+	{"R24", "R24"},
+	{"R25", "R25"},
+	{"R26", "R26"},
+	{"R27", "R27"},
+	{"R28", "R28"},
+	{"R29", "R29"},
+	{"R3", "R3"},
+	{"R31", "R31"},
+	{"R4", "R4"},
+	{"R5", "R5"},
+	{"R6", "R6"},
+	{"R7", "R7"},
+	{"R8", "R8"},
+	{"R9", "R9"},
+	{"SPR(269)", "SPR(269)"},
+	{"a(FP)", "a(FP)"},
+	{"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)"},
+	{"(R29, RSP)", "(R29, RSP)"},
+}
diff --git a/src/cmd/asm/internal/asm/parse.go b/src/cmd/asm/internal/asm/parse.go
new file mode 100644
index 0000000..6cf50df
--- /dev/null
+++ b/src/cmd/asm/internal/asm/parse.go
@@ -0,0 +1,988 @@
+// 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 asm implements the parser and instruction generator for the assembler.
+// TODO: Split apart?
+package asm
+
+import (
+	"fmt"
+	"log"
+	"os"
+	"strconv"
+	"text/scanner"
+	"unicode/utf8"
+
+	"cmd/asm/internal/arch"
+	"cmd/asm/internal/lex"
+	"cmd/internal/obj"
+)
+
+type Parser struct {
+	lex           lex.TokenReader
+	lineNum       int   // Line number in source file.
+	histLineNum   int32 // Cumulative line number across source files.
+	errorLine     int32 // (Cumulative) line number of last error.
+	errorCount    int   // Number of errors.
+	pc            int64 // virtual PC; count of Progs; doesn't advance for GLOBL or DATA.
+	input         []lex.Token
+	inputPos      int
+	pendingLabels []string // Labels to attach to next instruction.
+	labels        map[string]*obj.Prog
+	toPatch       []Patch
+	addr          []obj.Addr
+	arch          *arch.Arch
+	ctxt          *obj.Link
+	firstProg     *obj.Prog
+	lastProg      *obj.Prog
+	dataAddr      map[string]int64 // Most recent address for DATA for this symbol.
+}
+
+type Patch struct {
+	prog  *obj.Prog
+	label string
+}
+
+func NewParser(ctxt *obj.Link, ar *arch.Arch, lexer lex.TokenReader) *Parser {
+	return &Parser{
+		ctxt:     ctxt,
+		arch:     ar,
+		lex:      lexer,
+		labels:   make(map[string]*obj.Prog),
+		dataAddr: make(map[string]int64),
+	}
+}
+
+// panicOnError is enable when testing to abort execution on the first error
+// and turn it into a recoverable panic.
+var panicOnError bool
+
+func (p *Parser) errorf(format string, args ...interface{}) {
+	if panicOnError {
+		panic(fmt.Errorf(format, args...))
+	}
+	if p.histLineNum == p.errorLine {
+		// Only one error per line.
+		return
+	}
+	p.errorLine = p.histLineNum
+	// Put file and line information on head of message.
+	format = "%s:%d: " + format + "\n"
+	args = append([]interface{}{p.lex.File(), p.lineNum}, args...)
+	fmt.Fprintf(os.Stderr, format, args...)
+	p.errorCount++
+	if p.errorCount > 10 {
+		log.Fatal("too many errors")
+	}
+}
+
+func (p *Parser) Parse() (*obj.Prog, bool) {
+	for p.line() {
+	}
+	if p.errorCount > 0 {
+		return nil, false
+	}
+	p.patch()
+	return p.firstProg, true
+}
+
+// WORD [ arg {, arg} ] (';' | '\n')
+func (p *Parser) line() bool {
+	// Skip newlines.
+	var tok lex.ScanToken
+	for {
+		tok = p.lex.Next()
+		// We save the line number here so error messages from this instruction
+		// are labeled with this line. Otherwise we complain after we've absorbed
+		// the terminating newline and the line numbers are off by one in errors.
+		p.lineNum = p.lex.Line()
+		p.histLineNum = lex.HistLine()
+		switch tok {
+		case '\n', ';':
+			continue
+		case scanner.EOF:
+			return false
+		}
+		break
+	}
+	// First item must be an identifier.
+	if tok != scanner.Ident {
+		p.errorf("expected identifier, found %q", p.lex.Text())
+		return false // Might as well stop now.
+	}
+	word := p.lex.Text()
+	var cond string
+	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' || p.arch.Thechar == '7') && tok == '.' {
+					// ARM conditionals.
+					tok = p.lex.Next()
+					str := p.lex.Text()
+					if tok != scanner.Ident {
+						p.errorf("ARM condition expected identifier, found %s", str)
+					}
+					cond = cond + "." + str
+					continue
+				}
+				if tok == ':' {
+					// Labels.
+					p.pendingLabels = append(p.pendingLabels, word)
+					return true
+				}
+			}
+			if tok == scanner.EOF {
+				p.errorf("unexpected EOF")
+				return false
+			}
+			// 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 == '[' {
+				nesting++
+			}
+			if tok == ')' || tok == ']' {
+				nesting--
+			}
+			items = append(items, lex.Make(tok, p.lex.Text()))
+		}
+		if len(items) > 0 {
+			operands = append(operands, items)
+			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")
+		}
+	}
+	i, present := arch.Pseudos[word]
+	if present {
+		p.pseudo(i, word, operands)
+		return true
+	}
+	i, present = p.arch.Instructions[word]
+	if present {
+		p.instruction(i, word, cond, operands)
+		return true
+	}
+	p.errorf("unrecognized instruction %q", word)
+	return true
+}
+
+func (p *Parser) instruction(op int, word, cond string, operands [][]lex.Token) {
+	p.addr = p.addr[0:0]
+	isJump := p.arch.IsJump(word)
+	for _, op := range operands {
+		addr := p.address(op)
+		if !isJump && addr.Reg < 0 { // Jumps refer to PC, a pseudo.
+			p.errorf("illegal use of pseudo-register in %s", word)
+		}
+		p.addr = append(p.addr, addr)
+	}
+	if isJump {
+		p.asmJump(op, cond, p.addr)
+		return
+	}
+	p.asmInstruction(op, cond, p.addr)
+}
+
+func (p *Parser) pseudo(op int, word string, operands [][]lex.Token) {
+	switch op {
+	case obj.ATEXT:
+		p.asmText(word, operands)
+	case obj.ADATA:
+		p.asmData(word, operands)
+	case obj.AGLOBL:
+		p.asmGlobl(word, operands)
+	case obj.APCDATA:
+		p.asmPCData(word, operands)
+	case obj.AFUNCDATA:
+		p.asmFuncData(word, operands)
+	default:
+		p.errorf("unimplemented: %s", word)
+	}
+}
+
+func (p *Parser) start(operand []lex.Token) {
+	p.input = operand
+	p.inputPos = 0
+}
+
+// address parses the operand into a link address structure.
+func (p *Parser) address(operand []lex.Token) obj.Addr {
+	p.start(operand)
+	addr := obj.Addr{}
+	p.operand(&addr)
+	return addr
+}
+
+// parseScale converts a decimal string into a valid scale factor.
+func (p *Parser) parseScale(s string) int8 {
+	switch s {
+	case "1", "2", "4", "8":
+		return int8(s[0] - '0')
+	}
+	p.errorf("bad scale: %s", s)
+	return 0
+}
+
+// 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)
+	if len(p.input) == 0 {
+		p.errorf("empty operand: cannot happen")
+		return false
+	}
+	// General address (with a few exceptions) looks like
+	//	$sym±offset(SB)(reg)(index*scale)
+	// Exceptions are:
+	//
+	//	R1
+	//	offset
+	//	$offset
+	// Every piece is optional, so we scan left to right and what
+	// we discover tells us where we are.
+
+	// Prefix: $.
+	var prefix rune
+	switch tok := p.peek(); tok {
+	case '$', '*':
+		prefix = rune(tok)
+		p.next()
+	}
+
+	// Symbol: sym±offset(SB)
+	tok := p.next()
+	name := tok.String()
+	if tok.ScanToken == scanner.Ident && !p.atStartOfRegister(name) {
+		// We have a symbol. Parse $sym±offset(symkind)
+		p.symbolReference(a, name, prefix)
+		// fmt.Printf("SYM %s\n", obj.Dconv(&emptyProg, 0, a))
+		if p.peek() == scanner.EOF {
+			return true
+		}
+	}
+
+	// Special register list syntax for arm: [R1,R3-R7]
+	if tok.ScanToken == '[' {
+		if prefix != 0 {
+			p.errorf("illegal use of register list")
+		}
+		p.registerList(a)
+		p.expect(scanner.EOF)
+		return true
+	}
+
+	// Register: R1
+	if tok.ScanToken == scanner.Ident && p.atStartOfRegister(name) {
+		if p.atRegisterShift() {
+			// ARM shifted register such as R1<<R2 or R1>>2.
+			a.Type = obj.TYPE_SHIFT
+			a.Offset = p.registerShift(tok.String(), prefix)
+			if p.peek() == '(' {
+				// Can only be a literal register here.
+				p.next()
+				tok := p.next()
+				name := tok.String()
+				if !p.atStartOfRegister(name) {
+					p.errorf("expected register; found %s", name)
+				}
+				a.Reg, _ = p.registerReference(name)
+				p.get(')')
+			}
+		} else if r1, r2, scale, ok := p.register(tok.String(), prefix); ok {
+			if scale != 0 {
+				p.errorf("expected simple register reference")
+			}
+			a.Type = obj.TYPE_REG
+			a.Reg = r1
+			if r2 != 0 {
+				// Form is R1:R2. It is on RHS and the second register
+				// needs to go into the LHS.
+				panic("cannot happen (Addr.Reg2)")
+			}
+		}
+		// fmt.Printf("REG %s\n", obj.Dconv(&emptyProg, 0, a))
+		p.expect(scanner.EOF)
+		return true
+	}
+
+	// Constant.
+	haveConstant := false
+	switch tok.ScanToken {
+	case scanner.Int, scanner.Float, scanner.String, scanner.Char, '+', '-', '~':
+		haveConstant = true
+	case '(':
+		// Could be parenthesized expression or (R).
+		rname := p.next().String()
+		p.back()
+		haveConstant = !p.atStartOfRegister(rname)
+		if !haveConstant {
+			p.back() // Put back the '('.
+		}
+	}
+	if haveConstant {
+		p.back()
+		if p.have(scanner.Float) {
+			if prefix != '$' {
+				p.errorf("floating-point constant must be an immediate")
+			}
+			a.Type = obj.TYPE_FCONST
+			a.Val = p.floatExpr()
+			// fmt.Printf("FCONST %s\n", obj.Dconv(&emptyProg, 0, a))
+			p.expect(scanner.EOF)
+			return true
+		}
+		if p.have(scanner.String) {
+			if prefix != '$' {
+				p.errorf("string constant must be an immediate")
+			}
+			str, err := strconv.Unquote(p.get(scanner.String).String())
+			if err != nil {
+				p.errorf("string parse error: %s", err)
+			}
+			a.Type = obj.TYPE_SCONST
+			a.Val = str
+			// fmt.Printf("SCONST %s\n", obj.Dconv(&emptyProg, 0, a))
+			p.expect(scanner.EOF)
+			return true
+		}
+		a.Offset = int64(p.expr())
+		if p.peek() != '(' {
+			switch prefix {
+			case '$':
+				a.Type = obj.TYPE_CONST
+			case '*':
+				a.Type = obj.TYPE_INDIR // Can appear but is illegal, will be rejected by the linker.
+			default:
+				a.Type = obj.TYPE_MEM
+			}
+			// fmt.Printf("CONST %d %s\n", a.Offset, obj.Dconv(&emptyProg, 0, a))
+			p.expect(scanner.EOF)
+			return true
+		}
+		// fmt.Printf("offset %d \n", a.Offset)
+	}
+
+	// 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)
+	return true
+}
+
+// atStartOfRegister reports whether the parser is at the start of a register definition.
+func (p *Parser) atStartOfRegister(name string) bool {
+	// Simple register: R10.
+	_, present := p.arch.Register[name]
+	if present {
+		return true
+	}
+	// Parenthesized register: R(10).
+	return p.arch.RegisterPrefix[name] && p.peek() == '('
+}
+
+// atRegisterShift reports whether we are at the start of an ARM shifted register.
+// We have consumed the register or R prefix.
+func (p *Parser) atRegisterShift() bool {
+	// ARM only.
+	if p.arch.Thechar != '5' {
+		return false
+	}
+	// R1<<...
+	if lex.IsRegisterShift(p.peek()) {
+		return true
+	}
+	// R(1)<<...   Ugly check. TODO: Rethink how we handle ARM register shifts to be
+	// less special.
+	if p.peek() != '(' || len(p.input)-p.inputPos < 4 {
+		return false
+	}
+	return p.at('(', scanner.Int, ')') && lex.IsRegisterShift(p.input[p.inputPos+3].ScanToken)
+}
+
+// registerReference parses a register given either the name, R10, or a parenthesized form, SPR(10).
+func (p *Parser) registerReference(name string) (int16, bool) {
+	r, present := p.arch.Register[name]
+	if present {
+		return r, true
+	}
+	if !p.arch.RegisterPrefix[name] {
+		p.errorf("expected register; found %s", name)
+		return 0, false
+	}
+	p.get('(')
+	tok := p.get(scanner.Int)
+	num, err := strconv.ParseInt(tok.String(), 10, 16)
+	p.get(')')
+	if err != nil {
+		p.errorf("parsing register list: %s", err)
+		return 0, false
+	}
+	r, ok := p.arch.RegisterNumber(name, int16(num))
+	if !ok {
+		p.errorf("illegal register %s(%d)", name, r)
+		return 0, false
+	}
+	return r, true
+}
+
+// register parses a full register reference where there is no symbol present (as in 4(R0) or R(10) but not sym(SB))
+// including forms involving multiple registers such as R1:R2.
+func (p *Parser) register(name string, prefix rune) (r1, r2 int16, scale int8, ok bool) {
+	// R1 or R(1) R1:R2 R1,R2 R1+R2, or R1*scale.
+	r1, ok = p.registerReference(name)
+	if !ok {
+		return
+	}
+	if prefix != 0 && prefix != '*' { // *AX is OK.
+		p.errorf("prefix %c not allowed for register: %c%s", prefix, prefix, name)
+	}
+	c := p.peek()
+	if c == ':' || c == ',' || c == '+' {
+		// 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 != '5' && char != '7' {
+				p.errorf("(register,register) not supported on this architecture")
+				return
+			}
+		case '+':
+			if char != '9' {
+				p.errorf("(register+register) not supported on this architecture")
+				return
+			}
+		}
+		name := p.next().String()
+		r2, ok = p.registerReference(name)
+		if !ok {
+			return
+		}
+	}
+	if p.peek() == '*' {
+		// Scale
+		p.next()
+		scale = p.parseScale(p.next().String())
+	}
+	return r1, r2, scale, true
+}
+
+// registerShift parses an ARM shifted register reference and returns the encoded representation.
+// There is known to be a register (current token) and a shift operator (peeked token).
+func (p *Parser) registerShift(name string, prefix rune) int64 {
+	if prefix != 0 {
+		p.errorf("prefix %c not allowed for shifted register: $%s", prefix, name)
+	}
+	// R1 op R2 or r1 op constant.
+	// op is:
+	//	"<<" == 0
+	//	">>" == 1
+	//	"->" == 2
+	//	"@>" == 3
+	r1, ok := p.registerReference(name)
+	if !ok {
+		return 0
+	}
+	var op int16
+	switch p.next().ScanToken {
+	case lex.LSH:
+		op = 0
+	case lex.RSH:
+		op = 1
+	case lex.ARR:
+		op = 2
+	case lex.ROT:
+		op = 3
+	}
+	tok := p.next()
+	str := tok.String()
+	var count int16
+	switch tok.ScanToken {
+	case scanner.Ident:
+		r2, ok := p.registerReference(str)
+		if !ok {
+			p.errorf("rhs of shift must be register or integer: %s", str)
+		}
+		count = (r2&15)<<8 | 1<<4
+	case scanner.Int, '(':
+		p.back()
+		x := int64(p.expr())
+		if x >= 32 {
+			p.errorf("register shift count too large: %s", str)
+		}
+		count = int16((x & 31) << 7)
+	default:
+		p.errorf("unexpected %s in register shift", tok.String())
+	}
+	return int64((r1 & 15) | op<<5 | count)
+}
+
+// symbolReference parses a symbol that is known not to be a register.
+func (p *Parser) symbolReference(a *obj.Addr, name string, prefix rune) {
+	// Identifier is a name.
+	switch prefix {
+	case 0:
+		a.Type = obj.TYPE_MEM
+	case '$':
+		a.Type = obj.TYPE_ADDR
+	case '*':
+		a.Type = obj.TYPE_INDIR
+	}
+	// Weirdness with statics: Might now have "<>".
+	isStatic := 0 // TODO: Really a boolean, but Linklookup wants a "version" integer.
+	if p.peek() == '<' {
+		isStatic = 1
+		p.next()
+		p.get('>')
+	}
+	if p.peek() == '+' || p.peek() == '-' {
+		a.Offset = int64(p.expr())
+	}
+	a.Sym = obj.Linklookup(p.ctxt, name, isStatic)
+	if p.peek() == scanner.EOF {
+		if prefix != 0 {
+			p.errorf("illegal addressing mode for symbol %s", name)
+		}
+		return
+	}
+	// Expect (SB) or (FP), (PC), (SB), or (SP)
+	p.get('(')
+	reg := p.get(scanner.Ident).String()
+	p.get(')')
+	p.setPseudoRegister(a, reg, isStatic != 0, prefix)
+}
+
+// setPseudoRegister sets the NAME field of addr for a pseudo-register reference such as (SB).
+func (p *Parser) setPseudoRegister(addr *obj.Addr, reg string, isStatic bool, prefix rune) {
+	if addr.Reg != 0 {
+		p.errorf("internal error: reg %s already set in pseudo", reg)
+	}
+	switch reg {
+	case "FP":
+		addr.Name = obj.NAME_PARAM
+	case "PC":
+		if prefix != 0 {
+			p.errorf("illegal addressing mode for PC")
+		}
+		addr.Type = obj.TYPE_BRANCH // We set the type and leave NAME untouched. See asmJump.
+	case "SB":
+		addr.Name = obj.NAME_EXTERN
+		if isStatic {
+			addr.Name = obj.NAME_STATIC
+		}
+	case "SP":
+		addr.Name = obj.NAME_AUTO // The pseudo-stack.
+	default:
+		p.errorf("expected pseudo-register; found %s", reg)
+	}
+	if prefix == '$' {
+		addr.Type = obj.TYPE_ADDR
+	}
+}
+
+// registerIndirect parses the general form of a register indirection.
+// It is can be (R1), (R2*scale), or (R1)(R2*scale) where R1 may be a simple
+// register or register pair R:R or (R, R) or (R+R).
+// Or it might be a pseudo-indirection like (FP).
+// We are sitting on the opening parenthesis.
+func (p *Parser) registerIndirect(a *obj.Addr, prefix rune) {
+	p.get('(')
+	tok := p.next()
+	name := tok.String()
+	r1, r2, scale, ok := p.register(name, 0)
+	if !ok {
+		p.errorf("indirect through non-register %s", tok)
+	}
+	p.get(')')
+	a.Type = obj.TYPE_MEM
+	if r1 < 0 {
+		// Pseudo-register reference.
+		if r2 != 0 {
+			p.errorf("cannot use pseudo-register in pair")
+			return
+		}
+		// For SB, SP, and FP, there must be a name here. 0(FP) is not legal.
+		if name != "PC" && a.Name == obj.NAME_NONE {
+			p.errorf("cannot reference %s without a symbol", name)
+		}
+		p.setPseudoRegister(a, name, false, prefix)
+		return
+	}
+	a.Reg = r1
+	if r2 != 0 {
+		// TODO: Consistency in the encoding would be nice here.
+		if p.arch.Thechar == '5' || p.arch.Thechar == '7' {
+			// Special form
+			// ARM: destination register pair (R1, R2).
+			// ARM64: register pair (R1, R2) for LDP/STP.
+			if prefix != 0 || scale != 0 {
+				p.errorf("illegal address mode for register pair")
+				return
+			}
+			a.Type = obj.TYPE_REGREG
+			a.Offset = int64(r2)
+			// Nothing may follow
+			return
+		}
+		if p.arch.Thechar == '9' {
+			// Special form for PPC64: (R1+R2); alias for (R1)(R2*1).
+			if prefix != 0 || scale != 0 {
+				p.errorf("illegal address mode for register+register")
+				return
+			}
+			a.Type = obj.TYPE_MEM
+			a.Scale = 1
+			a.Index = r2
+			// Nothing may follow.
+			return
+		}
+	}
+	if r2 != 0 {
+		p.errorf("indirect through register pair")
+	}
+	if prefix == '$' {
+		a.Type = obj.TYPE_ADDR
+	}
+	if r1 == arch.RPC && prefix != 0 {
+		p.errorf("illegal addressing mode for PC")
+	}
+	if scale == 0 && p.peek() == '(' {
+		// General form (R)(R*scale).
+		p.next()
+		tok := p.next()
+		r1, r2, scale, ok = p.register(tok.String(), 0)
+		if !ok {
+			p.errorf("indirect through non-register %s", tok)
+		}
+		if r2 != 0 {
+			p.errorf("unimplemented two-register form")
+		}
+		a.Index = r1
+		a.Scale = int16(scale)
+		p.get(')')
+	} else if scale != 0 {
+		// First (R) was missing, all we have is (R*scale).
+		a.Reg = 0
+		a.Index = r1
+		a.Scale = int16(scale)
+	}
+}
+
+// registerList parses an ARM register list expression, a list of registers in [].
+// There may be comma-separated ranges or individual registers, as in
+// [R1,R3-R5]. Only R0 through R15 may appear.
+// The opening bracket has been consumed.
+func (p *Parser) registerList(a *obj.Addr) {
+	// One range per loop.
+	var bits uint16
+ListLoop:
+	for {
+		tok := p.next()
+		switch tok.ScanToken {
+		case ']':
+			break ListLoop
+		case scanner.EOF:
+			p.errorf("missing ']' in register list")
+			return
+		}
+		lo := p.registerNumber(tok.String())
+		hi := lo
+		if p.peek() == '-' {
+			p.next()
+			hi = p.registerNumber(p.next().String())
+		}
+		if hi < lo {
+			lo, hi = hi, lo
+		}
+		for lo <= hi {
+			if bits&(1<<lo) != 0 {
+				p.errorf("register R%d already in list", lo)
+			}
+			bits |= 1 << lo
+			lo++
+		}
+		if p.peek() != ']' {
+			p.get(',')
+		}
+	}
+	a.Type = obj.TYPE_REGLIST
+	a.Offset = int64(bits)
+}
+
+// register number is ARM-specific. It returns the number of the specified register.
+func (p *Parser) registerNumber(name string) uint16 {
+	if p.arch.Thechar == '5' && name == "g" {
+		return 10
+	}
+	if name[0] != 'R' {
+		p.errorf("expected g or R0 through R15; found %s", name)
+	}
+	r, ok := p.registerReference(name)
+	if !ok {
+		return 0
+	}
+	return uint16(r - p.arch.Register["R0"])
+}
+
+// Note: There are two changes in the expression handling here
+// compared to the old yacc/C implementations. Neither has
+// much practical consequence because the expressions we
+// see in assembly code are simple, but for the record:
+//
+// 1) Evaluation uses uint64; the old one used int64.
+// 2) Precedence uses Go rules not C rules.
+
+// expr = term | term ('+' | '-' | '|' | '^') term.
+func (p *Parser) expr() uint64 {
+	value := p.term()
+	for {
+		switch p.peek() {
+		case '+':
+			p.next()
+			value += p.term()
+		case '-':
+			p.next()
+			value -= p.term()
+		case '|':
+			p.next()
+			value |= p.term()
+		case '^':
+			p.next()
+			value ^= p.term()
+		default:
+			return value
+		}
+	}
+}
+
+// floatExpr = fconst | '-' floatExpr | '+' floatExpr | '(' floatExpr ')'
+func (p *Parser) floatExpr() float64 {
+	tok := p.next()
+	switch tok.ScanToken {
+	case '(':
+		v := p.floatExpr()
+		if p.next().ScanToken != ')' {
+			p.errorf("missing closing paren")
+		}
+		return v
+	case '+':
+		return +p.floatExpr()
+	case '-':
+		return -p.floatExpr()
+	case scanner.Float:
+		return p.atof(tok.String())
+	}
+	p.errorf("unexpected %s evaluating float expression", tok)
+	return 0
+}
+
+// term = factor | factor ('*' | '/' | '%' | '>>' | '<<' | '&') factor
+func (p *Parser) term() uint64 {
+	value := p.factor()
+	for {
+		switch p.peek() {
+		case '*':
+			p.next()
+			value *= p.factor()
+		case '/':
+			p.next()
+			if int64(value) < 0 {
+				p.errorf("divide of value with high bit set")
+			}
+			divisor := p.factor()
+			if divisor == 0 {
+				p.errorf("division by zero")
+			} else {
+				value /= divisor
+			}
+		case '%':
+			p.next()
+			divisor := p.factor()
+			if int64(value) < 0 {
+				p.errorf("modulo of value with high bit set")
+			}
+			if divisor == 0 {
+				p.errorf("modulo by zero")
+			} else {
+				value %= divisor
+			}
+		case lex.LSH:
+			p.next()
+			shift := p.factor()
+			if int64(shift) < 0 {
+				p.errorf("negative left shift count")
+			}
+			return value << shift
+		case lex.RSH:
+			p.next()
+			shift := p.term()
+			if int64(shift) < 0 {
+				p.errorf("negative right shift count")
+			}
+			if int64(value) < 0 {
+				p.errorf("right shift of value with high bit set")
+			}
+			value >>= shift
+		case '&':
+			p.next()
+			value &= p.factor()
+		default:
+			return value
+		}
+	}
+}
+
+// factor = const | '+' factor | '-' factor | '~' factor | '(' expr ')'
+func (p *Parser) factor() uint64 {
+	tok := p.next()
+	switch tok.ScanToken {
+	case scanner.Int:
+		return p.atoi(tok.String())
+	case scanner.Char:
+		str, err := strconv.Unquote(tok.String())
+		if err != nil {
+			p.errorf("%s", err)
+		}
+		r, w := utf8.DecodeRuneInString(str)
+		if w == 1 && r == utf8.RuneError {
+			p.errorf("illegal UTF-8 encoding for character constant")
+		}
+		return uint64(r)
+	case '+':
+		return +p.factor()
+	case '-':
+		return -p.factor()
+	case '~':
+		return ^p.factor()
+	case '(':
+		v := p.expr()
+		if p.next().ScanToken != ')' {
+			p.errorf("missing closing paren")
+		}
+		return v
+	}
+	p.errorf("unexpected %s evaluating expression", tok)
+	return 0
+}
+
+// positiveAtoi returns an int64 that must be >= 0.
+func (p *Parser) positiveAtoi(str string) int64 {
+	value, err := strconv.ParseInt(str, 0, 64)
+	if err != nil {
+		p.errorf("%s", err)
+	}
+	if value < 0 {
+		p.errorf("%s overflows int64", str)
+	}
+	return value
+}
+
+func (p *Parser) atoi(str string) uint64 {
+	value, err := strconv.ParseUint(str, 0, 64)
+	if err != nil {
+		p.errorf("%s", err)
+	}
+	return value
+}
+
+func (p *Parser) atof(str string) float64 {
+	value, err := strconv.ParseFloat(str, 64)
+	if err != nil {
+		p.errorf("%s", err)
+	}
+	return value
+}
+
+func (p *Parser) atos(str string) string {
+	value, err := strconv.Unquote(str)
+	if err != nil {
+		p.errorf("%s", err)
+	}
+	return value
+}
+
+// EOF represents the end of input.
+var EOF = lex.Make(scanner.EOF, "EOF")
+
+func (p *Parser) next() lex.Token {
+	if !p.more() {
+		return EOF
+	}
+	tok := p.input[p.inputPos]
+	p.inputPos++
+	return tok
+}
+
+func (p *Parser) back() {
+	p.inputPos--
+}
+
+func (p *Parser) peek() lex.ScanToken {
+	if p.more() {
+		return p.input[p.inputPos].ScanToken
+	}
+	return scanner.EOF
+}
+
+func (p *Parser) more() bool {
+	return p.inputPos < len(p.input)
+}
+
+// get verifies that the next item has the expected type and returns it.
+func (p *Parser) get(expected lex.ScanToken) lex.Token {
+	p.expect(expected)
+	return p.next()
+}
+
+// expect verifies that the next item has the expected type. It does not consume it.
+func (p *Parser) expect(expected lex.ScanToken) {
+	if p.peek() != expected {
+		p.errorf("expected %s, found %s", expected, p.next())
+	}
+}
+
+// have reports whether the remaining tokens (including the current one) contain the specified token.
+func (p *Parser) have(token lex.ScanToken) bool {
+	for i := p.inputPos; i < len(p.input); i++ {
+		if p.input[i].ScanToken == token {
+			return true
+		}
+	}
+	return false
+}
+
+// at reports whether the next tokens are as requested.
+func (p *Parser) at(next ...lex.ScanToken) bool {
+	if len(p.input)-p.inputPos < len(next) {
+		return false
+	}
+	for i, r := range next {
+		if p.input[p.inputPos+i].ScanToken != r {
+			return false
+		}
+	}
+	return true
+}
diff --git a/src/cmd/asm/internal/asm/testdata/386.out b/src/cmd/asm/internal/asm/testdata/386.out
new file mode 100644
index 0000000..be43ccb
--- /dev/null
+++ b/src/cmd/asm/internal/asm/testdata/386.out
@@ -0,0 +1,49 @@
+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
new file mode 100644
index 0000000..6bee39f
--- /dev/null
+++ b/src/cmd/asm/internal/asm/testdata/386.s
@@ -0,0 +1,86 @@
+// This input was created by taking the instruction productions in
+// the old assembler's (8a's) grammar and hand-writing complete
+// instructions for each rule, to guarantee we cover the same space.
+
+TEXT foo(SB), 0, $0
+
+// LTYPE1 nonrem	{ outcode(int($1), &$2); }
+	SETCC	AX
+	SETCC	foo+4(SB)
+
+// LTYPE2 rimnon	{ outcode(int($1), &$2); }
+	DIVB	AX
+	DIVB	foo+4(SB)
+	PUSHL	$foo+4(SB)
+	POPL		AX // balance PUSHL
+
+// LTYPE3 rimrem	{ outcode(int($1), &$2); }
+	SUBB	$1, AX
+	SUBB	$1, foo+4(SB)
+	SUBB	BX, AX
+	SUBB	BX, foo+4(SB)
+
+// LTYPE4 remrim	{ outcode(int($1), &$2); }
+	CMPB	AX, $1
+	CMPB	foo+4(SB), $4
+	CMPB	BX, AX
+	CMPB	foo+4(SB), BX
+
+// LTYPER nonrel	{ outcode(int($1), &$2); }
+label:
+	JC	label
+	JC	-1(PC)
+
+// LTYPEC spec3	{ outcode(int($1), &$2); }
+	CALL	AX
+	JMP	*AX
+	CALL	*foo(SB)
+	JMP	$4
+	JMP	label
+	CALL	foo(SB)
+	CALL	(AX*4)
+	CALL	foo+4(SB)(AX*4)
+	CALL	*4(SP)
+	CALL	*(AX)
+	CALL	*(SP)
+	CALL	*(AX*4)
+	CALL	*(AX)(AX*4)
+	CALL	4(SP)
+	CALL	(AX)
+	CALL	(SP)
+	CALL	(AX*4)
+	JMP	(AX)(AX*4)
+
+// LTYPEN spec4	{ outcode(int($1), &$2); }
+	NOP
+	NOP	AX
+	NOP	foo+4(SB)
+
+// LTYPES spec5	{ outcode(int($1), &$2); }
+	SHLL	$4, BX
+	SHLL	$4, foo+4(SB)
+	SHLL	$4, foo+4(SB):AX
+
+// LTYPEM spec6	{ outcode(int($1), &$2); }
+	MOVL	AX, BX
+	MOVL	$4, BX
+	
+// LTYPEI spec7	{ outcode(int($1), &$2); }
+	IMULL	AX
+	IMULL	$4, CX
+	IMULL	AX, BX
+
+// LTYPEXC spec9	{ outcode(int($1), &$2); }
+	CMPPD	X0, X1, 4
+	CMPPD	X0, foo+4(SB), 4
+
+// LTYPEX spec10	{ outcode(int($1), &$2); }
+	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
new file mode 100644
index 0000000..850a78e
--- /dev/null
+++ b/src/cmd/asm/internal/asm/testdata/amd64.out
@@ -0,0 +1,57 @@
+9 00001 (testdata/amd64.s:9)	TEXT	foo(SB), 0, $0
+12 00002 (testdata/amd64.s:12)	NEGQ	R11
+13 00003 (testdata/amd64.s:13)	NEGQ	4(R11)
+14 00004 (testdata/amd64.s:14)	NEGQ	foo+4(SB)
+17 00005 (testdata/amd64.s:17)	INT	$4
+18 00006 (testdata/amd64.s:18)	DIVB	R11
+19 00007 (testdata/amd64.s:19)	DIVB	4(R11)
+20 00008 (testdata/amd64.s:20)	DIVB	foo+4(SB)
+23 00009 (testdata/amd64.s:23)	SUBQ	$4, DI
+24 00010 (testdata/amd64.s:24)	SUBQ	R11, DI
+25 00011 (testdata/amd64.s:25)	SUBQ	4(R11), DI
+26 00012 (testdata/amd64.s:26)	SUBQ	foo+4(SB), DI
+27 00013 (testdata/amd64.s:27)	SUBQ	$4, 8(R12)
+28 00014 (testdata/amd64.s:28)	SUBQ	R11, 8(R12)
+29 00015 (testdata/amd64.s:29)	SUBQ	R11, foo+4(SB)
+32 00016 (testdata/amd64.s:32)	CMPB	CX, $4
+36 00017 (testdata/amd64.s:36)	JCS	13(PC)
+37 00018 (testdata/amd64.s:37)	JCS	17
+40 00019 (testdata/amd64.s:40)	JMP	15(PC)
+41 00020 (testdata/amd64.s:41)	JMP	17
+42 00021 (testdata/amd64.s:42)	JMP	foo+4(SB)
+43 00022 (testdata/amd64.s:43)	JMP	bar<>+4(SB)
+44 00023 (testdata/amd64.s:44)	JMP	bar<>+4(SB)(R11*4)
+45 00024 (testdata/amd64.s:45)	JMP	4(SP)
+46 00025 (testdata/amd64.s:46)	JMP	(R12)
+48 00026 (testdata/amd64.s:48)	JMP	(R12)(R13*4)
+49 00027 (testdata/amd64.s:49)	JMP	(AX)
+50 00028 (testdata/amd64.s:50)	JMP	(SP)
+52 00029 (testdata/amd64.s:52)	JMP	(AX)(AX*4)
+53 00030 (testdata/amd64.s:53)	JMP	4(SP)
+54 00031 (testdata/amd64.s:54)	JMP	(R12)
+56 00032 (testdata/amd64.s:56)	JMP	(R12)(R13*4)
+57 00033 (testdata/amd64.s:57)	JMP	(AX)
+58 00034 (testdata/amd64.s:58)	JMP	(SP)
+60 00035 (testdata/amd64.s:60)	JMP	(AX)(AX*4)
+61 00036 (testdata/amd64.s:61)	JMP	R13
+64 00037 (testdata/amd64.s:64)	NOP
+65 00038 (testdata/amd64.s:65)	NOP	AX
+66 00039 (testdata/amd64.s:66)	NOP	foo+4(SB)
+69 00040 (testdata/amd64.s:69)	SHLL	R11, R12
+70 00041 (testdata/amd64.s:70)	SHLL	R11, foo+4(SB)
+71 00042 (testdata/amd64.s:71)	SHLL	R11, AX, R11
+74 00043 (testdata/amd64.s:74)	MOVL	AX, R11
+75 00044 (testdata/amd64.s:75)	MOVL	$4, R11
+76 00045 (testdata/amd64.s:76)	MOVL	AX, CS, AX
+79 00046 (testdata/amd64.s:79)	IMULB	$4
+80 00047 (testdata/amd64.s:80)	IMULB	R11
+81 00048 (testdata/amd64.s:81)	IMULB	$4, R11
+82 00049 (testdata/amd64.s:82)	IMULB	R11, R12
+83 00050 (testdata/amd64.s:83)	IMULB	R11, foo+4(SB)
+86 00051 (testdata/amd64.s:86)	CMPPD	R11, R12, 4
+87 00052 (testdata/amd64.s:87)	CMPPD	R11, foo+4(SB), 4
+90 00053 (testdata/amd64.s:90)	PINSRW	$4, R11, AX
+91 00054 (testdata/amd64.s:91)	PINSRW	$4, foo+4(SB), AX
+94 00055 (testdata/amd64.s:94)	RETFL	$4
+98 00056 (testdata/amd64.s:98)	LOOP
+101 00057 (testdata/amd64.s:101)	RET
diff --git a/src/cmd/asm/internal/asm/testdata/amd64.s b/src/cmd/asm/internal/asm/testdata/amd64.s
new file mode 100644
index 0000000..1b32ac4
--- /dev/null
+++ b/src/cmd/asm/internal/asm/testdata/amd64.s
@@ -0,0 +1,101 @@
+// 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 input was created by taking the instruction productions in
+// the old assembler's (6a's) grammar and hand-writing complete
+// instructions for each rule, to guarantee we cover the same space.
+
+TEXT	foo(SB), 0, $0
+
+// LTYPE1 nonrem	{ outcode($1, &$2); }
+	NEGQ	R11
+	NEGQ	4(R11)
+	NEGQ	foo+4(SB)
+
+// LTYPE2 rimnon	{ outcode($1, &$2); }
+	INT	$4
+	DIVB	R11
+	DIVB	4(R11)
+	DIVB	foo+4(SB)
+
+// LTYPE3 rimrem	{ outcode($1, &$2); }
+	SUBQ $4, DI
+	SUBQ R11, DI
+	SUBQ 4(R11), DI
+	SUBQ foo+4(SB), DI
+	SUBQ $4, 8(R12)
+	SUBQ R11, 8(R12)
+	SUBQ R11, foo+4(SB)
+
+// LTYPE4 remrim	{ outcode($1, &$2); }
+	CMPB	CX, $4
+
+// LTYPER nonrel	{ outcode($1, &$2); }
+label:
+	JB	-4(PC)
+	JB	label
+
+// LTYPEC spec3	{ outcode($1, &$2); }
+	JMP	-4(PC)
+	JMP	label
+	JMP	foo+4(SB)
+	JMP	bar<>+4(SB)
+	JMP	bar<>+4(SB)(R11*4)
+	JMP	*4(SP)
+	JMP	*(R12)
+	JMP	*(R12*4)
+	JMP	*(R12)(R13*4)
+	JMP	*(AX)
+	JMP	*(SP)
+	JMP	*(AX*4)
+	JMP	*(AX)(AX*4)
+	JMP	4(SP)
+	JMP	(R12)
+	JMP	(R12*4)
+	JMP	(R12)(R13*4)
+	JMP	(AX)
+	JMP	(SP)
+	JMP	(AX*4)
+	JMP	(AX)(AX*4)
+	JMP	R13
+
+// LTYPEN spec4	{ outcode($1, &$2); }
+	NOP
+	NOP	AX
+	NOP	foo+4(SB)
+
+// LTYPES spec5	{ outcode($1, &$2); }
+	SHLL	R11, R12
+	SHLL	R11, foo+4(SB)
+	SHLL	R11, R11:AX // Old syntax, still accepted.
+
+// LTYPEM spec6	{ outcode($1, &$2); }
+	MOVL	AX, R11
+	MOVL	$4, R11
+	MOVL	AX, AX:CS
+
+// LTYPEI spec7	{ outcode($1, &$2); }
+	IMULB	$4
+	IMULB	R11
+	IMULB	$4, R11
+	IMULB	R11, R12
+	IMULB	R11, foo+4(SB)
+
+// LTYPEXC spec8	{ outcode($1, &$2); }
+	CMPPD	R11, R12, 4
+	CMPPD	R11, foo+4(SB), 4
+
+// LTYPEX spec9	{ outcode($1, &$2); }
+	PINSRW	$4, R11, AX
+	PINSRW	$4, foo+4(SB), AX
+
+// 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
new file mode 100644
index 0000000..1af3999
--- /dev/null
+++ b/src/cmd/asm/internal/asm/testdata/arm.out
@@ -0,0 +1,61 @@
+9 00001 (testdata/arm.s:9)	TEXT	foo(SB), 0, $0
+18 00002 (testdata/arm.s:18)	ADD	$1, R2, R3
+19 00003 (testdata/arm.s:19)	ADD	R1<<R2, R3, R4
+20 00004 (testdata/arm.s:20)	ADD	R1>>R2, R3, R4
+21 00005 (testdata/arm.s:21)	ADD	R1@>R2, R3, R4
+22 00006 (testdata/arm.s:22)	ADD	R1->R2, R3, R4
+23 00007 (testdata/arm.s:23)	ADD	R1, R2, R3
+24 00008 (testdata/arm.s:24)	ADD	R1<<R2, R3, R4
+34 00009 (testdata/arm.s:34)	ADD	$1, R2
+35 00010 (testdata/arm.s:35)	ADD	R1<<R2, R3
+36 00011 (testdata/arm.s:36)	ADD	R1>>R2, R3
+37 00012 (testdata/arm.s:37)	ADD	R1@>R2, R3
+38 00013 (testdata/arm.s:38)	ADD	R1->R2, R3
+39 00014 (testdata/arm.s:39)	ADD	R1, R2
+48 00015 (testdata/arm.s:48)	CLZ.S	R1, R2
+57 00016 (testdata/arm.s:57)	MOVW.S	R1, R2
+58 00017 (testdata/arm.s:58)	MOVW.S	$1, R2
+59 00018 (testdata/arm.s:59)	MOVW.S	R1<<R2, R3
+68 00019 (testdata/arm.s:68)	JMP.S	20(PC)
+74 00020 (testdata/arm.s:74)	JMP.S	(R2)
+75 00021 (testdata/arm.s:75)	JMP.S	foo(SB)
+76 00022 (testdata/arm.s:76)	JMP.S	bar<>(SB)
+85 00023 (testdata/arm.s:85)	BX	(R2)
+94 00024 (testdata/arm.s:94)	BEQ	25(PC)
+103 00025 (testdata/arm.s:103)	SWI.S	R1
+104 00026 (testdata/arm.s:104)	SWI.S	(R1)
+105 00027 (testdata/arm.s:105)	SWI.S	foo(SB)
+114 00028 (testdata/arm.s:114)	CMP.S	$1, R2
+115 00029 (testdata/arm.s:115)	CMP.S	R1<<R2, R3
+116 00030 (testdata/arm.s:116)	CMP.S	R1, R2
+130 00031 (testdata/arm.s:130)	MOVM	(R1), [R2,R5,R8,g]
+131 00032 (testdata/arm.s:131)	MOVM	(R1), [R2,R3,R4,R5]
+132 00033 (testdata/arm.s:132)	MOVM.S	(R1), [R2]
+143 00034 (testdata/arm.s:143)	MOVM	[R2,R5,R8,g], (R1)
+144 00035 (testdata/arm.s:144)	MOVM	[R2,R3,R4,R5], (R1)
+145 00036 (testdata/arm.s:145)	MOVM.S	[R2], (R1)
+154 00037 (testdata/arm.s:154)	STREX.S	(R2), R1, R3
+160 00038 (testdata/arm.s:160)	STREX.S	(R2), R1, R1
+166 00039 (testdata/arm.s:166)	STREX.S	(R2), R3, R3
+174 00040 (testdata/arm.s:174)	CASE.S	R1
+183 00041 (testdata/arm.s:183)	WORD	$1234
+192 00042 (testdata/arm.s:192)	ABSF.S	F1, F2
+198 00043 (testdata/arm.s:198)	ADDD.S	F1, F2
+199 00044 (testdata/arm.s:199)	ADDD.S	$(0.5), F2
+205 00045 (testdata/arm.s:205)	ADDD.S	F1, F2, F3
+206 00046 (testdata/arm.s:206)	ADDD.S	$(0.5), F2, F3
+212 00047 (testdata/arm.s:212)	CMPD.S	F1, F2
+236 00048 (testdata/arm.s:236)	MRC	$8301712627
+237 00049 (testdata/arm.s:237)	MRC	$8300664051
+246 00050 (testdata/arm.s:246)	MULL	R1, R2, (R3, R4)
+258 00051 (testdata/arm.s:258)	MULAWT	R1, R2, R3, R4
+266 00052 (testdata/arm.s:266)	PLD	(R1)
+267 00053 (testdata/arm.s:267)	PLD	4(R1)
+276 00054 (testdata/arm.s:276)	RET
+280 00055 (testdata/arm.s:280)	JMP	foo(SB)
+281 00056 (testdata/arm.s:281)	CALL	foo(SB)
+282 00057 (testdata/arm.s:282)	JMP	foo(SB)
+283 00058 (testdata/arm.s:283)	CALL	foo(SB)
+286 00059 (testdata/arm.s:286)	CMPF	F1, F2
+287 00060 (testdata/arm.s:287)	CMPD	F1, F2
+296 00061 (testdata/arm.s:296)	END
diff --git a/src/cmd/asm/internal/asm/testdata/arm.s b/src/cmd/asm/internal/asm/testdata/arm.s
new file mode 100644
index 0000000..95fee50
--- /dev/null
+++ b/src/cmd/asm/internal/asm/testdata/arm.s
@@ -0,0 +1,296 @@
+// 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 input was created by taking the instruction productions in
+// the old assembler's (5a's) grammar and hand-writing complete
+// instructions for each rule, to guarantee we cover the same space.
+
+TEXT	foo(SB), 0, $0
+
+// ADD
+//
+//	LTYPE1 cond imsr ',' spreg ',' reg
+//	{
+//		outcode($1, $2, &$3, $5, &$7);
+//	}
+// Cover some operand space here too.
+	ADD	$1, R2, R3
+	ADD	R1<<R2, R3, R4
+	ADD	R1>>R2, R3, R4
+	ADD	R1@>R2, R3, R4
+	ADD	R1->R2, R3, R4
+	ADD	R1, R2, R3
+	ADD	R(1)<<R(2), R(3), R(4)
+
+//	LTYPE1 cond imsr ',' spreg ',' // asm doesn't support trailing comma.
+//	{
+//		outcode($1, $2, &$3, $5, &nullgen);
+//	}
+//	LTYPE1 cond imsr ',' reg
+//	{
+//		outcode($1, $2, &$3, 0, &$5);
+//	}
+	ADD	$1, R2
+	ADD	R1<<R2, R3
+	ADD	R1>>R2, R3
+	ADD	R1@>R2, R3
+	ADD	R1->R2, R3
+	ADD	R1, R2
+
+//
+// MVN
+//
+//	LTYPE2 cond imsr ',' reg
+//	{
+//		outcode($1, $2, &$3, 0, &$5);
+//	}
+	CLZ.S	R1, R2
+
+//
+// MOVW
+//
+//	LTYPE3 cond gen ',' gen
+//	{
+//		outcode($1, $2, &$3, 0, &$5);
+//	}
+	MOVW.S	R1, R2
+	MOVW.S	$1, R2
+	MOVW.S	R1<<R2, R3
+
+//
+// B/BL
+//
+//	LTYPE4 cond comma rel
+//	{
+//		outcode($1, $2, &nullgen, 0, &$4);
+//	}
+	B.S	1(PC)
+
+//	LTYPE4 cond comma nireg
+//	{
+//		outcode($1, $2, &nullgen, 0, &$4);
+//	}
+	B.S	(R2)
+	B.S	foo(SB)
+	B.S	bar<>(SB)
+
+//
+// BX
+//
+//	LTYPEBX comma ireg
+//	{
+//		outcode($1, Always, &nullgen, 0, &$3);
+//	}
+	BX	(R2)
+
+//
+// BEQ
+//
+//	LTYPE5 comma rel
+//	{
+//		outcode($1, Always, &nullgen, 0, &$3);
+//	}
+	BEQ	1(PC)
+
+//
+// SWI
+//
+//	LTYPE6 cond comma gen
+//	{
+//		outcode($1, $2, &nullgen, 0, &$4);
+//	}
+	SWI.S	R1
+	SWI.S	(R1)
+	SWI.S	foo(SB)
+
+//
+// CMP
+//
+//	LTYPE7 cond imsr ',' spreg
+//	{
+//		outcode($1, $2, &$3, $5, &nullgen);
+//	}
+	CMP.S	$1, R2
+	CMP.S	R1<<R2, R3
+	CMP.S	R1, R2
+
+//
+// MOVM
+//
+//	LTYPE8 cond ioreg ',' '[' reglist ']'
+//	{
+//		var g obj.Addr
+//
+//		g = nullgen;
+//		g.Type = obj.TYPE_CONST;
+//		g.Offset = int64($6);
+//		outcode($1, $2, &$3, 0, &g);
+//	}
+	MOVM	0(R1), [R2,R5,R8,g]
+	MOVM	0(R1), [R2-R5]
+	MOVM.S	(R1), [R2]
+
+//	LTYPE8 cond '[' reglist ']' ',' ioreg
+//	{
+//		var g obj.Addr
+//
+//		g = nullgen;
+//		g.Type = obj.TYPE_CONST;
+//		g.Offset = int64($4);
+//		outcode($1, $2, &g, 0, &$7);
+//	}
+	MOVM	[R2,R5,R8,g], 0(R1)
+	MOVM	[R2-R5], 0(R1)
+	MOVM.S	[R2], (R1)
+
+//
+// SWAP
+//
+//	LTYPE9 cond reg ',' ireg ',' reg
+//	{
+//		outcode($1, $2, &$5, int32($3.Reg), &$7);
+//	}
+	STREX.S	R1, (R2), R3
+
+//	LTYPE9 cond reg ',' ireg
+//	{
+//		outcode($1, $2, &$5, int32($3.Reg), &$3);
+//	}
+	STREX.S	R1, (R2)
+
+//	LTYPE9 cond comma ireg ',' reg
+//	{
+//		outcode($1, $2, &$4, int32($6.Reg), &$6);
+//	}
+	STREX.S	(R2), R3
+
+// CASE
+//
+//	LTYPED cond reg
+//	{
+//		outcode($1, $2, &$3, 0, &nullgen);
+//	}
+	CASE.S	R1
+
+//
+// word
+//
+//	LTYPEH comma ximm
+//	{
+//		outcode($1, Always, &nullgen, 0, &$3);
+//	}
+	WORD	$1234
+
+//
+// floating-point coprocessor
+//
+//	LTYPEI cond freg ',' freg
+//	{
+//		outcode($1, $2, &$3, 0, &$5);
+//	}
+	ABSF.S	F1, F2
+
+//	LTYPEK cond frcon ',' freg
+//	{
+//		outcode($1, $2, &$3, 0, &$5);
+//	}
+	ADDD.S	F1, F2
+	ADDD.S	$0.5, F2
+
+//	LTYPEK cond frcon ',' LFREG ',' freg
+//	{
+//		outcode($1, $2, &$3, $5, &$7);
+//	}
+	ADDD.S	F1, F2, F3
+	ADDD.S	$0.5, F2, F3
+
+//	LTYPEL cond freg ',' freg
+//	{
+//		outcode($1, $2, &$3, int32($5.Reg), &nullgen);
+//	}
+	CMPD.S	F1, F2
+
+//
+// MCR MRC
+//
+//	LTYPEJ cond con ',' expr ',' spreg ',' creg ',' creg oexpr
+//	{
+//		var g obj.Addr
+//
+//		g = nullgen;
+//		g.Type = obj.TYPE_CONST;
+//		g.Offset = int64(
+//			(0xe << 24) |		/* opcode */
+//			($1 << 20) |		/* MCR/MRC */
+//			(($2^C_SCOND_XOR) << 28) |		/* scond */
+//			(($3 & 15) << 8) |	/* coprocessor number */
+//			(($5 & 7) << 21) |	/* coprocessor operation */
+//			(($7 & 15) << 12) |	/* arm register */
+//			(($9 & 15) << 16) |	/* Crn */
+//			(($11 & 15) << 0) |	/* Crm */
+//			(($12 & 7) << 5) |	/* coprocessor information */
+//			(1<<4));			/* must be set */
+//		outcode(AMRC, Always, &nullgen, 0, &g);
+//	}
+	MRC.S	4, 6, R1, C2, C3, 7
+	MCR.S	4, 6, R1, C2, C3, 7
+
+//
+// MULL r1,r2,(hi,lo)
+//
+//	LTYPEM cond reg ',' reg ',' regreg
+//	{
+//		outcode($1, $2, &$3, int32($5.Reg), &$7);
+//	}
+	MULL	R1, R2, (R3,R4)
+
+//
+// MULA r1,r2,r3,r4: (r1*r2+r3) & 0xffffffff . r4
+// MULAW{T,B} r1,r2,r3,r4
+//
+//	LTYPEN cond reg ',' reg ',' reg ',' spreg
+//	{
+//		$7.Type = obj.TYPE_REGREG2;
+//		$7.Offset = int64($9);
+//		outcode($1, $2, &$3, int32($5.Reg), &$7);
+//	}
+	MULAWT	R1, R2, R3, R4
+//
+// PLD
+//
+//	LTYPEPLD oreg
+//	{
+//		outcode($1, Always, &$2, 0, &nullgen);
+//	}
+	PLD	(R1)
+	PLD	4(R1)
+
+//
+// RET
+//
+//	LTYPEA cond
+//	{
+//		outcode($1, $2, &nullgen, 0, &nullgen);
+//	}
+	RET
+
+// More B/BL cases, and canonical names JMP, CALL.
+
+	B	foo(SB)
+	BL	foo(SB)
+	JMP	foo(SB)
+	CALL	foo(SB)
+
+// CMPF and CMPD are special.
+	CMPF F1, F2
+	CMPD F1, F2
+
+//
+// END
+//
+//	LTYPEE
+//	{
+//		outcode($1, Always, &nullgen, 0, &nullgen);
+//	}
+	END
diff --git a/src/cmd/asm/internal/asm/testdata/arm64.out b/src/cmd/asm/internal/asm/testdata/arm64.out
new file mode 100644
index 0000000..0b7b430
--- /dev/null
+++ b/src/cmd/asm/internal/asm/testdata/arm64.out
@@ -0,0 +1,55 @@
+9 00001 (testdata/arm64.s:9)	TEXT	foo(SB), 7, $-8
+20 00002 (testdata/arm64.s:20)	ADDW	$1, R2, R3
+21 00003 (testdata/arm64.s:21)	ADDW	R1, R2, R3
+22 00004 (testdata/arm64.s:22)	ADDW	R1, ZR, R3
+23 00005 (testdata/arm64.s:23)	ADD	$1, R2, R3
+24 00006 (testdata/arm64.s:24)	ADD	R1, R2, R3
+25 00007 (testdata/arm64.s:25)	ADD	R1, ZR, R3
+26 00008 (testdata/arm64.s:26)	ADD	$1, R2, R3
+36 00009 (testdata/arm64.s:36)	ADDW	$1, R2
+37 00010 (testdata/arm64.s:37)	ADDW	R1, R2
+38 00011 (testdata/arm64.s:38)	ADD	$1, R2
+39 00012 (testdata/arm64.s:39)	ADD	R1, R2
+48 00013 (testdata/arm64.s:48)	CLSW	R1, R2
+49 00014 (testdata/arm64.s:49)	CLS	R1, R2
+58 00015 (testdata/arm64.s:58)	MOVW	R1, R2
+59 00016 (testdata/arm64.s:59)	MOVW	ZR, R1
+60 00017 (testdata/arm64.s:60)	MOVW	R1, ZR
+61 00018 (testdata/arm64.s:61)	MOVW	$1, ZR
+62 00019 (testdata/arm64.s:62)	MOVW	$1, R1
+63 00020 (testdata/arm64.s:63)	MOVW	ZR, (R1)
+64 00021 (testdata/arm64.s:64)	MOVD	R1, R2
+65 00022 (testdata/arm64.s:65)	MOVD	ZR, R1
+66 00023 (testdata/arm64.s:66)	MOVD	$1, ZR
+67 00024 (testdata/arm64.s:67)	MOVD	$1, R1
+68 00025 (testdata/arm64.s:68)	MOVD	ZR, (R1)
+77 00026 (testdata/arm64.s:77)	MOVK	$1, R1
+86 00027 (testdata/arm64.s:86)	CALL	28(PC)
+92 00028 (testdata/arm64.s:92)	CALL	(R2)
+93 00029 (testdata/arm64.s:93)	CALL	foo(SB)
+94 00030 (testdata/arm64.s:94)	CALL	bar<>(SB)
+102 00031 (testdata/arm64.s:102)	BEQ	32(PC)
+110 00032 (testdata/arm64.s:110)	SVC
+119 00033 (testdata/arm64.s:119)	CMP	$3, R2
+120 00034 (testdata/arm64.s:120)	CMP	R1, R2
+130 00035 (testdata/arm64.s:130)	CBZ	R1
+139 00036 (testdata/arm64.s:139)	CSET	GT, R1
+147 00037 (testdata/arm64.s:147)	CSEL	LT, R1, R2, ZR
+148 00038 (testdata/arm64.s:148)	CSINC	GT, R1, ZR, R3
+149 00039 (testdata/arm64.s:149)	CSNEG	MI, R1, R2, R3
+150 00040 (testdata/arm64.s:150)	CSINV	0, R1, R2, R3
+156 00041 (testdata/arm64.s:156)	CSEL	LT, R1, R2
+164 00042 (testdata/arm64.s:164)	CCMN	MI, ZR, R1, $4
+173 00043 (testdata/arm64.s:173)	FADDD	$(0.5), F1
+174 00044 (testdata/arm64.s:174)	FADDD	F1, F2
+180 00045 (testdata/arm64.s:180)	FADDD	$(0.69999999999999996), F1, F2
+181 00046 (testdata/arm64.s:181)	FADDD	F1, F2, F3
+233 00047 (testdata/arm64.s:233)	DMB	$1
+242 00048 (testdata/arm64.s:242)	LDAXRW	(R0), R2
+243 00049 (testdata/arm64.s:243)	STLXRW	R1, (R0), R3
+251 00050 (testdata/arm64.s:251)	RET
+255 00051 (testdata/arm64.s:255)	JMP	foo(SB)
+256 00052 (testdata/arm64.s:256)	CALL	foo(SB)
+257 00053 (testdata/arm64.s:257)	JMP	foo(SB)
+258 00054 (testdata/arm64.s:258)	CALL	foo(SB)
+266 00055 (testdata/arm64.s:266)	END
diff --git a/src/cmd/asm/internal/asm/testdata/arm64.s b/src/cmd/asm/internal/asm/testdata/arm64.s
new file mode 100644
index 0000000..2c8720b
--- /dev/null
+++ b/src/cmd/asm/internal/asm/testdata/arm64.s
@@ -0,0 +1,266 @@
+// 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 input was created by taking the instruction productions in
+// the old assembler's (7a's) grammar and hand-writing complete
+// instructions for each rule, to guarantee we cover the same space.
+
+TEXT	foo(SB), 7, $-8
+
+//
+// ADD
+//
+//	LTYPE1 imsr ',' spreg ',' reg
+//	{
+//		outcode($1, &$2, $4, &$6);
+//	}
+// imsr comes from the old 7a, we only support immediates and registers
+// at the moment, no shifted registers.
+	ADDW	$1, R2, R3
+	ADDW	R1, R2, R3
+	ADDW	R1, ZR, R3
+	ADD	$1, R2, R3
+	ADD	R1, R2, R3
+	ADD	R1, ZR, R3
+	ADD	$1, R2, R3
+
+//	LTYPE1 imsr ',' spreg ','
+//	{
+//		outcode($1, &$2, $4, &nullgen);
+//	}
+//	LTYPE1 imsr ',' reg
+//	{
+//		outcode($1, &$2, NREG, &$4);
+//	}
+	ADDW	$1, R2
+	ADDW	R1, R2
+	ADD	$1, R2
+	ADD	R1, R2
+
+//
+// CLS
+//
+//	LTYPE2 imsr ',' reg
+//	{
+//		outcode($1, &$2, NREG, &$4);
+//	}
+	CLSW	R1, R2
+	CLS	R1, R2
+
+//
+// MOV
+//
+//	LTYPE3 addr ',' addr
+//	{
+//		outcode($1, &$2, NREG, &$4);
+//	}
+	MOVW	R1, R2
+	MOVW	ZR, R1
+	MOVW	R1, ZR
+	MOVW	$1, ZR
+	MOVW	$1, R1
+	MOVW	ZR, (R1)
+	MOVD	R1, R2
+	MOVD	ZR, R1
+	MOVD	$1, ZR
+	MOVD	$1, R1
+	MOVD	ZR, (R1)
+
+//
+// MOVK
+//
+//		LMOVK imm ',' reg
+//	{
+//		outcode($1, &$2, NREG, &$4);
+//	}
+	MOVK	$1, R1
+
+//
+// B/BL
+//
+//		LTYPE4 comma rel
+//	{
+//		outcode($1, &nullgen, NREG, &$3);
+//	}
+	BL	1(PC)
+
+//		LTYPE4 comma nireg
+//	{
+//		outcode($1, &nullgen, NREG, &$3);
+//	}
+	BL	(R2)
+	BL	foo(SB)
+	BL	bar<>(SB)
+//
+// BEQ
+//
+//		LTYPE5 comma rel
+//	{
+//		outcode($1, &nullgen, NREG, &$3);
+//	}
+	BEQ	1(PC)
+//
+// SVC
+//
+//		LTYPE6
+//	{
+//		outcode($1, &nullgen, NREG, &nullgen);
+//	}
+	SVC
+
+//
+// CMP
+//
+//		LTYPE7 imsr ',' spreg comma
+//	{
+//		outcode($1, &$2, $4, &nullgen);
+//	}
+	CMP	$3, R2
+	CMP	R1, R2
+
+//
+// CBZ
+//
+//		LTYPE8 reg ',' rel
+//	{
+//		outcode($1, &$2, NREG, &$4);
+//	}
+again:
+	CBZ	R1, again
+
+//
+// CSET
+//
+//		LTYPER cond ',' reg
+//	{
+//		outcode($1, &$2, NREG, &$4);
+//	}
+	CSET	GT, R1
+//
+// CSEL/CSINC/CSNEG/CSINV
+//
+//		LTYPES cond ',' reg ',' reg ',' reg
+//	{
+//		outgcode($1, &$2, $6.reg, &$4, &$8);
+//	}
+	CSEL	LT, R1, R2, ZR
+	CSINC	GT, R1, ZR, R3
+	CSNEG	MI, R1, R2, R3
+	CSINV	CS, R1, R2, R3
+
+//		LTYPES cond ',' reg ',' reg
+//	{
+//		outcode($1, &$2, $4.reg, &$6);
+//	}
+	CSEL	LT, R1, R2
+//
+// CCMN
+//
+//		LTYPEU cond ',' imsr ',' reg ',' imm comma
+//	{
+//		outgcode($1, &$2, $6.reg, &$4, &$8);
+//	}
+	CCMN	MI, ZR, R1, $4
+
+//
+// FADDD
+//
+//		LTYPEK frcon ',' freg
+//	{
+//		outcode($1, &$2, NREG, &$4);
+//	}
+	FADDD	$0.5, F1
+	FADDD	F1, F2
+
+//		LTYPEK frcon ',' freg ',' freg
+//	{
+//		outcode($1, &$2, $4.reg, &$6);
+//	}
+	FADDD	$0.7, F1, F2
+	FADDD	F1, F2, F3
+
+//
+// FCMP
+//
+//		LTYPEL frcon ',' freg comma
+//	{
+//		outcode($1, &$2, $4.reg, &nullgen);
+//	}
+//	FCMP	$0.2, F1
+//	FCMP	F1, F2
+
+//
+// FCCMP
+//
+//		LTYPEF cond ',' freg ',' freg ',' imm comma
+//	{
+//		outgcode($1, &$2, $6.reg, &$4, &$8);
+//	}
+//	FCCMP	LT, F1, F2, $1
+
+//
+// FMULA
+//
+//		LTYPE9 freg ',' freg ',' freg ',' freg comma
+//	{
+//		outgcode($1, &$2, $4.reg, &$6, &$8);
+//	}
+//	FMULA	F1, F2, F3, F4
+
+//
+// FCSEL
+//
+//		LFCSEL cond ',' freg ',' freg ',' freg
+//	{
+//		outgcode($1, &$2, $6.reg, &$4, &$8);
+//	}
+//
+// MADD Rn,Rm,Ra,Rd
+//
+//		LTYPEM reg ',' reg ',' sreg ',' reg
+//	{
+//		outgcode($1, &$2, $6, &$4, &$8);
+//	}
+//	MADD	R1, R2, R3, R4
+
+// DMB, HINT
+//
+//		LDMB imm
+//	{
+//		outcode($1, &$2, NREG, &nullgen);
+//	}
+	DMB	$1
+
+//
+// STXR
+//
+//		LSTXR reg ',' addr ',' reg
+//	{
+//		outtcode($1, &$2, &$4, &$6);
+//	}
+	LDAXRW	(R0), R2
+	STLXRW	R1, (R0), R3
+
+// RET
+//
+//		LTYPEA comma
+//	{
+//		outcode($1, &nullgen, NREG, &nullgen);
+//	}
+	RET
+
+// More B/BL cases, and canonical names JMP, CALL.
+
+	B	foo(SB)
+	BL	foo(SB)
+	JMP	foo(SB)
+	CALL	foo(SB)
+
+// END
+//
+//	LTYPEE comma
+//	{
+//		outcode($1, &nullgen, NREG, &nullgen);
+//	}
+	END
diff --git a/src/cmd/asm/internal/asm/testdata/ppc64.out b/src/cmd/asm/internal/asm/testdata/ppc64.out
new file mode 100644
index 0000000..2a5d175
--- /dev/null
+++ b/src/cmd/asm/internal/asm/testdata/ppc64.out
@@ -0,0 +1,114 @@
+9 00001 (testdata/ppc64.s:9)	TEXT	foo(SB), 0, $0
+19 00002 (testdata/ppc64.s:19)	MOVW	R1, R2
+25 00003 (testdata/ppc64.s:25)	MOVW	foo<>+3(SB), R2
+26 00004 (testdata/ppc64.s:26)	MOVW	16(R1), R2
+32 00005 (testdata/ppc64.s:32)	MOVW	(R1), R2
+33 00006 (testdata/ppc64.s:33)	MOVW	(R1)(R2*1), R3
+39 00007 (testdata/ppc64.s:39)	MOVW	R1, R2
+45 00008 (testdata/ppc64.s:45)	MOVB	foo<>+3(SB), R2
+46 00009 (testdata/ppc64.s:46)	MOVB	16(R1), R2
+52 00010 (testdata/ppc64.s:52)	MOVB	(R1), R2
+53 00011 (testdata/ppc64.s:53)	MOVB	(R1)(R2*1), R3
+62 00012 (testdata/ppc64.s:62)	FMOVD	foo<>+3(SB), F2
+63 00013 (testdata/ppc64.s:63)	FMOVD	16(R1), F2
+69 00014 (testdata/ppc64.s:69)	FMOVD	(R1), F2
+75 00015 (testdata/ppc64.s:75)	FMOVD	$(0.10000000000000001), F2
+81 00016 (testdata/ppc64.s:81)	FMOVD	F1, F2
+87 00017 (testdata/ppc64.s:87)	FMOVD	F2, foo<>+3(SB)
+88 00018 (testdata/ppc64.s:88)	FMOVD	F2, 16(R1)
+94 00019 (testdata/ppc64.s:94)	FMOVD	F2, (R1)
+103 00020 (testdata/ppc64.s:103)	MOVW	R1, foo<>+3(SB)
+104 00021 (testdata/ppc64.s:104)	MOVW	R1, 16(R2)
+110 00022 (testdata/ppc64.s:110)	MOVW	R1, (R1)
+111 00023 (testdata/ppc64.s:111)	MOVW	R1, (R2)(R3*1)
+117 00024 (testdata/ppc64.s:117)	MOVB	R1, foo<>+3(SB)
+118 00025 (testdata/ppc64.s:118)	MOVB	R1, 16(R2)
+124 00026 (testdata/ppc64.s:124)	MOVB	R1, (R1)
+125 00027 (testdata/ppc64.s:125)	MOVB	R1, (R2)(R3*1)
+133 00028 (testdata/ppc64.s:133)	FMOVD	F1, foo<>+3(SB)
+134 00029 (testdata/ppc64.s:134)	FMOVD	F1, 16(R2)
+140 00030 (testdata/ppc64.s:140)	FMOVD	F1, (R1)
+149 00031 (testdata/ppc64.s:149)	MOVFL	FPSCR, F1
+155 00032 (testdata/ppc64.s:155)	MOVFL	F1, FPSCR
+161 00033 (testdata/ppc64.s:161)	MOVFL	F1, $4, FPSCR
+167 00034 (testdata/ppc64.s:167)	MOVFL	FPSCR, CR0
+188 00035 (testdata/ppc64.s:188)	MOVW	R1, CR1
+194 00036 (testdata/ppc64.s:194)	MOVW	R1, CR
+206 00037 (testdata/ppc64.s:206)	ADD	R1, R2, R3
+212 00038 (testdata/ppc64.s:212)	ADD	$1, R2, R3
+224 00039 (testdata/ppc64.s:224)	ADD	R1, R2
+230 00040 (testdata/ppc64.s:230)	ADD	$4, R1
+236 00041 (testdata/ppc64.s:236)	ADDE	R1, R2, R3
+242 00042 (testdata/ppc64.s:242)	ADDE	R1, R2
+248 00043 (testdata/ppc64.s:248)	SLW	R1, R2, R3
+254 00044 (testdata/ppc64.s:254)	SLW	R1, R2
+260 00045 (testdata/ppc64.s:260)	SLW	$4, R1, R2
+266 00046 (testdata/ppc64.s:266)	SLW	$4, R1
+272 00047 (testdata/ppc64.s:272)	SLW	$4, R1
+278 00048 (testdata/ppc64.s:278)	SUBME	R1, R1
+296 00049 (testdata/ppc64.s:296)	MOVW	$1, R1
+302 00050 (testdata/ppc64.s:302)	MOVW	$1, R1
+303 00051 (testdata/ppc64.s:303)	MOVW	$foo(SB), R1
+327 00052 (testdata/ppc64.s:327)	MOVFL	CR0, CR1
+339 00053 (testdata/ppc64.s:339)	MOVW	CR, R1
+345 00054 (testdata/ppc64.s:345)	MOVW	SPR(0), R1
+346 00055 (testdata/ppc64.s:346)	MOVW	SPR(7), R1
+352 00056 (testdata/ppc64.s:352)	MOVW	LR, R1
+353 00057 (testdata/ppc64.s:353)	MOVW	CTR, R1
+359 00058 (testdata/ppc64.s:359)	MOVW	R1, LR
+360 00059 (testdata/ppc64.s:360)	MOVW	R1, CTR
+372 00060 (testdata/ppc64.s:372)	MOVW	R1, SPR(7)
+384 00061 (testdata/ppc64.s:384)	JMP	62(PC)
+385 00062 (testdata/ppc64.s:385)	JMP	61
+391 00063 (testdata/ppc64.s:391)	JMP	4(R1)
+392 00064 (testdata/ppc64.s:392)	JMP	foo(SB)
+398 00065 (testdata/ppc64.s:398)	JMP	CTR
+417 00066 (testdata/ppc64.s:417)	BEQ	CR1, 67(PC)
+418 00067 (testdata/ppc64.s:418)	BEQ	CR1, 66
+444 00068 (testdata/ppc64.s:444)	BC	4, CTR
+454 00069 (testdata/ppc64.s:454)	BC	$3, R4, 66
+474 00070 (testdata/ppc64.s:474)	BC	$3, R3, LR
+504 00071 (testdata/ppc64.s:504)	FABS	F1, F2
+510 00072 (testdata/ppc64.s:510)	FADD	F1, F2
+516 00073 (testdata/ppc64.s:516)	FADD	F1, F2, F3
+522 00074 (testdata/ppc64.s:522)	FMADD	F1, F2, F3, F4
+528 00075 (testdata/ppc64.s:528)	FCMPU	F1, F2
+534 00076 (testdata/ppc64.s:534)	FCMPU	F1, F2, CR0
+543 00077 (testdata/ppc64.s:543)	CMP	R1, R2
+549 00078 (testdata/ppc64.s:549)	CMP	R1, $4
+555 00079 (testdata/ppc64.s:555)	CMP	R1, CR0, R2
+561 00080 (testdata/ppc64.s:561)	CMP	R1, CR0, $4
+570 00081 (testdata/ppc64.s:570)	RLDC	$4, R1, $5, R2
+576 00082 (testdata/ppc64.s:576)	RLDC	$26, R1, $201326592, R2
+582 00083 (testdata/ppc64.s:582)	RLDC	R1, R2, $4, R3
+588 00084 (testdata/ppc64.s:588)	RLWMI	R1, R2, $201326592, R3
+597 00085 (testdata/ppc64.s:597)	MOVMW	foo(SB), R2
+598 00086 (testdata/ppc64.s:598)	MOVMW	4(R1), R2
+604 00087 (testdata/ppc64.s:604)	MOVMW	R1, foo(SB)
+605 00088 (testdata/ppc64.s:605)	MOVMW	R1, 4(R2)
+615 00089 (testdata/ppc64.s:615)	LSW	(R1), R2
+616 00090 (testdata/ppc64.s:616)	LSW	(R1)(R2*1), R3
+622 00091 (testdata/ppc64.s:622)	LSW	(R1), $1, R2
+623 00092 (testdata/ppc64.s:623)	LSW	(R1)(R2*1), $1, R3
+629 00093 (testdata/ppc64.s:629)	STSW	R1, (R2)
+630 00094 (testdata/ppc64.s:630)	STSW	R1, (R2)(R3*1)
+636 00095 (testdata/ppc64.s:636)	STSW	R1, $1, (R2)
+637 00096 (testdata/ppc64.s:637)	STSW	R1, $1, (R2)(R3*1)
+643 00097 (testdata/ppc64.s:643)	MOVHBR	(R1), R2
+644 00098 (testdata/ppc64.s:644)	MOVHBR	(R1)(R2*1), R3
+650 00099 (testdata/ppc64.s:650)	MOVHBR	R1, (R2)
+651 00100 (testdata/ppc64.s:651)	MOVHBR	R1, (R2)(R3*1)
+657 00101 (testdata/ppc64.s:657)	DCBF	(R1)
+658 00102 (testdata/ppc64.s:658)	DCBF	(R1)(R2*1)
+667 00103 (testdata/ppc64.s:667)	NOP
+673 00104 (testdata/ppc64.s:673)	NOP	R2
+679 00105 (testdata/ppc64.s:679)	NOP	F2
+685 00106 (testdata/ppc64.s:685)	NOP	R2
+691 00107 (testdata/ppc64.s:691)	NOP	F2
+697 00108 (testdata/ppc64.s:697)	NOP	$4
+705 00109 (testdata/ppc64.s:705)	RET
+709 00110 (testdata/ppc64.s:709)	JMP	foo(SB)
+710 00111 (testdata/ppc64.s:710)	CALL	foo(SB)
+711 00112 (testdata/ppc64.s:711)	JMP	foo(SB)
+712 00113 (testdata/ppc64.s:712)	CALL	foo(SB)
+720 00114 (testdata/ppc64.s:720)	END
diff --git a/src/cmd/asm/internal/asm/testdata/ppc64.s b/src/cmd/asm/internal/asm/testdata/ppc64.s
new file mode 100644
index 0000000..46c1ee6
--- /dev/null
+++ b/src/cmd/asm/internal/asm/testdata/ppc64.s
@@ -0,0 +1,720 @@
+// 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 input was created by taking the instruction productions in
+// the old assembler's (9a's) grammar and hand-writing complete
+// instructions for each rule, to guarantee we cover the same space.
+
+TEXT foo(SB),0,$0
+
+//inst:
+//
+// load ints and bytes
+//
+//	LMOVW rreg ',' rreg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	MOVW	R1, R2
+
+//	LMOVW addr ',' rreg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	MOVW	foo<>+3(SB), R2
+	MOVW	16(R1), R2
+
+//	LMOVW regaddr ',' rreg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	MOVW	(R1), R2
+	MOVW	(R1+R2), R3
+
+//	LMOVB rreg ',' rreg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	MOVW	R1, R2
+
+//	LMOVB addr ',' rreg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	MOVB	foo<>+3(SB), R2
+	MOVB	16(R1), R2
+
+//	LMOVB regaddr ',' rreg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	MOVB	(R1), R2
+	MOVB	(R1+R2), R3
+
+//
+// load floats
+//
+//	LFMOV addr ',' freg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	FMOVD	foo<>+3(SB), F2
+	FMOVD	16(R1), F2
+
+//	LFMOV regaddr ',' freg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	FMOVD	(R1), F2
+
+//	LFMOV fimm ',' freg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	FMOVD	$0.1, F2
+
+//	LFMOV freg ',' freg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	FMOVD	F1, F2
+
+//	LFMOV freg ',' addr
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	FMOVD	F2, foo<>+3(SB)
+	FMOVD	F2, 16(R1)
+
+//	LFMOV freg ',' regaddr
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	FMOVD	F2, (R1)
+
+//
+// store ints and bytes
+//
+//	LMOVW rreg ',' addr
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	MOVW	R1, foo<>+3(SB)
+	MOVW	R1, 16(R2)
+
+//	LMOVW rreg ',' regaddr
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	MOVW	R1, (R1)
+	MOVW	R1, (R2+R3)
+
+//	LMOVB rreg ',' addr
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	MOVB	R1, foo<>+3(SB)
+	MOVB	R1, 16(R2)
+
+//	LMOVB rreg ',' regaddr
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	MOVB	R1, (R1)
+	MOVB	R1, (R2+R3)
+//
+// store floats
+//
+//	LMOVW freg ',' addr
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	FMOVD	F1, foo<>+3(SB)
+	FMOVD	F1, 16(R2)
+
+//	LMOVW freg ',' regaddr
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	FMOVD	F1, (R1)
+
+//
+// floating point status
+//
+//	LMOVW fpscr ',' freg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	MOVFL	FPSCR, F1
+
+//	LMOVW freg ','  fpscr
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	MOVFL	F1, FPSCR
+
+//	LMOVW freg ',' imm ',' fpscr
+//	{
+//		outgcode(int($1), &$2, 0, &$4, &$6);
+//	}
+	MOVFL	F1, $4, FPSCR
+
+//	LMOVW fpscr ',' creg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	MOVFL	FPSCR, CR0
+
+//	LMTFSB imm ',' con
+//	{
+//		outcode(int($1), &$2, int($4), &nullgen);
+//	}
+//TODO	9a doesn't work MTFSB0	$4, 4
+
+//
+// field moves (mtcrf)
+//
+//	LMOVW rreg ',' imm ',' lcr
+//	{
+//		outgcode(int($1), &$2, 0, &$4, &$6);
+//	}
+// TODO 9a doesn't work	MOVFL	R1,$4,CR
+
+//	LMOVW rreg ',' creg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+		MOVW	R1, CR1
+
+//	LMOVW rreg ',' lcr
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	MOVW	R1, CR
+
+//
+// integer operations
+// logical instructions
+// shift instructions
+// unary instructions
+//
+//	LADDW rreg ',' sreg ',' rreg
+//	{
+//		outcode(int($1), &$2, int($4), &$6);
+//	}
+	ADD	R1, R2, R3
+
+//	LADDW imm ',' sreg ',' rreg
+//	{
+//		outcode(int($1), &$2, int($4), &$6);
+//	}
+	ADD	$1, R2, R3
+
+//	LADDW rreg ',' imm ',' rreg
+//	{
+//		outgcode(int($1), &$2, 0, &$4, &$6);
+//	}
+//TODO 9a trouble	ADD	R1, $2, R3 maybe swap rreg and imm
+
+//	LADDW rreg ',' rreg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	ADD	R1, R2
+
+//	LADDW imm ',' rreg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	ADD	$4, R1
+
+//	LLOGW rreg ',' sreg ',' rreg
+//	{
+//		outcode(int($1), &$2, int($4), &$6);
+//	}
+	ADDE	R1, R2, R3
+
+//	LLOGW rreg ',' rreg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	ADDE	R1, R2
+
+//	LSHW rreg ',' sreg ',' rreg
+//	{
+//		outcode(int($1), &$2, int($4), &$6);
+//	}
+	SLW	R1, R2, R3
+
+//	LSHW rreg ',' rreg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	SLW	R1, R2
+
+//	LSHW imm ',' sreg ',' rreg
+//	{
+//		outcode(int($1), &$2, int($4), &$6);
+//	}
+	SLW	$4, R1, R2
+
+//	LSHW imm ',' rreg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	SLW	$4, R1
+
+//	LABS rreg ',' rreg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	SLW	$4, R1
+
+//	LABS rreg
+//	{
+//		outcode(int($1), &$2, 0, &$2);
+//	}
+	SUBME	R1
+
+//
+// multiply-accumulate
+//
+//	LMA rreg ',' sreg ',' rreg
+//	{
+//		outcode(int($1), &$2, int($4), &$6);
+//	}
+//TODO this instruction is undefined in lex.go	LMA R1, R2, R3 NOT SUPPORTED (called MAC)
+
+//
+// move immediate: macro for cau+or, addi, addis, and other combinations
+//
+//	LMOVW imm ',' rreg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	MOVW	$1, R1
+
+//	LMOVW ximm ',' rreg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	MOVW	$1, R1
+	MOVW	$foo(SB), R1
+
+// condition register operations
+//
+//	LCROP cbit ',' cbit
+//	{
+//		outcode(int($1), &$2, int($4.Reg), &$4);
+//	}
+//TODO 9a trouble	CREQV	1, 2 delete? liblink encodes like a divide (maybe wrong too)
+
+//	LCROP cbit ',' con ',' cbit
+//	{
+//		outcode(int($1), &$2, int($4), &$6);
+//	}
+//TODO 9a trouble	CREQV	1, 2, 3
+
+//
+// condition register moves
+// move from machine state register
+//
+//	LMOVW creg ',' creg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	MOVFL	CR0, CR1
+
+//	LMOVW psr ',' creg // TODO: should psr should be fpscr
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+//TODO 9a trouble	MOVW	FPSCR, CR1
+
+//	LMOVW lcr ',' rreg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	MOVW	CR, R1
+
+//	LMOVW psr ',' rreg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	MOVW	SPR(0), R1
+	MOVW	SPR(7), R1
+
+//	LMOVW xlreg ',' rreg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	MOVW	LR, R1
+	MOVW	CTR, R1
+
+//	LMOVW rreg ',' xlreg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	MOVW	R1, LR
+	MOVW	R1, CTR
+
+//	LMOVW creg ',' psr // TODO doesn't exist
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+//TODO 9a trouble	MOVW	CR1, SPR(7)
+
+//	LMOVW rreg ',' psr
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	MOVW	R1, SPR(7)
+
+//
+// branch, branch conditional
+// branch conditional register
+// branch conditional to count register
+//
+//	LBRA rel
+//	{
+//		outcode(int($1), &nullgen, 0, &$2);
+//	}
+label0:
+	BR	1(PC)
+	BR	label0+0
+
+//	LBRA addr
+//	{
+//		outcode(int($1), &nullgen, 0, &$2);
+//	}
+	BR	4(R1)
+	BR	foo+0(SB)
+
+//	LBRA '(' xlreg ')'
+//	{
+//		outcode(int($1), &nullgen, 0, &$3);
+//	}
+	BR	(CTR)
+
+//	LBRA ',' rel  // asm doesn't support the leading comma
+//	{
+//		outcode(int($1), &nullgen, 0, &$3);
+//	}
+//	LBRA ',' addr  // asm doesn't support the leading comma
+//	{
+//		outcode(int($1), &nullgen, 0, &$3);
+//	}
+//	LBRA ',' '(' xlreg ')'  // asm doesn't support the leading comma
+//	{
+//		outcode(int($1), &nullgen, 0, &$4);
+//	}
+//	LBRA creg ',' rel
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+label1:
+	BEQ	CR1, 1(PC)
+	BEQ	CR1, label1
+
+//	LBRA creg ',' addr // TODO DOES NOT WORK in 9a
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+
+//	LBRA creg ',' '(' xlreg ')' // TODO DOES NOT WORK in 9a
+//	{
+//		outcode(int($1), &$2, 0, &$5);
+//	}
+
+//	LBRA con ',' rel // TODO DOES NOT WORK in 9a
+//	{
+//		outcode(int($1), &nullgen, int($2), &$4);
+//	}
+
+//	LBRA con ',' addr // TODO DOES NOT WORK in 9a
+//	{
+//		outcode(int($1), &nullgen, int($2), &$4);
+//	}
+
+//	LBRA con ',' '(' xlreg ')'
+//	{
+//		outcode(int($1), &nullgen, int($2), &$5);
+//	}
+	BC	4, (CTR)
+
+//	LBRA con ',' con ',' rel
+//	{
+//		var g obj.Addr
+//		g = nullgen;
+//		g.Type = obj.TYPE_CONST;
+//		g.Offset = $2;
+//		outcode(int($1), &g, int(REG_R0+$4), &$6);
+//	}
+	BC	3, 4, label1
+
+//	LBRA con ',' con ',' addr // TODO mystery
+//	{
+//		var g obj.Addr
+//		g = nullgen;
+//		g.Type = obj.TYPE_CONST;
+//		g.Offset = $2;
+//		outcode(int($1), &g, int(REG_R0+$4), &$6);
+//	}
+//TODO 9a trouble	BC	3, 3, 4(R1)
+
+//	LBRA con ',' con ',' '(' xlreg ')'
+//	{
+//		var g obj.Addr
+//		g = nullgen;
+//		g.Type = obj.TYPE_CONST;
+//		g.Offset = $2;
+//		outcode(int($1), &g, int(REG_R0+$4), &$7);
+//	}
+	BC	3, 3, (LR)
+
+//
+// conditional trap // TODO NOT DEFINED
+// TODO these instructions are not in lex.go
+//
+//	LTRAP rreg ',' sreg
+//	{
+//		outcode(int($1), &$2, int($4), &nullgen);
+//	}
+//	LTRAP imm ',' sreg
+//	{
+//		outcode(int($1), &$2, int($4), &nullgen);
+//	}
+//	LTRAP rreg comma
+//	{
+//		outcode(int($1), &$2, 0, &nullgen);
+//	}
+//	LTRAP comma
+//	{
+//		outcode(int($1), &nullgen, 0, &nullgen);
+//	}
+
+//
+// floating point operate
+//
+//	LFCONV freg ',' freg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	FABS	F1, F2
+
+//	LFADD freg ',' freg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	FADD	F1, F2
+
+//	LFADD freg ',' freg ',' freg
+//	{
+//		outcode(int($1), &$2, int($4.Reg), &$6);
+//	}
+	FADD	F1, F2, F3
+
+//	LFMA freg ',' freg ',' freg ',' freg
+//	{
+//		outgcode(int($1), &$2, int($4.Reg), &$6, &$8);
+//	}
+	FMADD	F1, F2, F3, F4
+
+//	LFCMP freg ',' freg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	FCMPU	F1, F2
+
+//	LFCMP freg ',' freg ',' creg
+//	{
+//		outcode(int($1), &$2, int($6.Reg), &$4);
+//	}
+	FCMPU	F1, F2, CR0
+
+//
+// CMP
+//
+//	LCMP rreg ',' rreg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	CMP	R1, R2
+
+//	LCMP rreg ',' imm
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	CMP	R1, $4
+
+//	LCMP rreg ',' rreg ',' creg
+//	{
+//		outcode(int($1), &$2, int($6.Reg), &$4);
+//	}
+	CMP	R1, R2, CR0
+
+//	LCMP rreg ',' imm ',' creg
+//	{
+//		outcode(int($1), &$2, int($6.Reg), &$4);
+//	}
+	CMP	R1, $4, CR0
+
+//
+// rotate and mask
+//
+//	LRLWM  imm ',' rreg ',' imm ',' rreg
+//	{
+//		outgcode(int($1), &$2, int($4.Reg), &$6, &$8);
+//	}
+	RLDC $4, R1, $5, R2
+
+//	LRLWM  imm ',' rreg ',' mask ',' rreg
+//	{
+//		outgcode(int($1), &$2, int($4.Reg), &$6, &$8);
+//	}
+	RLDC $26, R1, 4, 5, R2
+
+//	LRLWM  rreg ',' rreg ',' imm ',' rreg
+//	{
+//		outgcode(int($1), &$2, int($4.Reg), &$6, &$8);
+//	}
+	RLDC	R1, R2, $4, R3
+
+//	LRLWM  rreg ',' rreg ',' mask ',' rreg
+//	{
+//		outgcode(int($1), &$2, int($4.Reg), &$6, &$8);
+//	}
+	RLWMI	R1, R2, 4, 5, R3
+
+//
+// load/store multiple
+//
+//	LMOVMW addr ',' rreg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	MOVMW	foo+0(SB), R2
+	MOVMW	4(R1), R2
+
+//	LMOVMW rreg ',' addr
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	MOVMW	R1, foo+0(SB)
+	MOVMW	R1, 4(R2)
+
+//
+// various indexed load/store
+// indexed unary (eg, cache clear)
+//
+//	LXLD regaddr ',' rreg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	LSW	(R1), R2
+	LSW	(R1+R2), R3
+
+//	LXLD regaddr ',' imm ',' rreg
+//	{
+//		outgcode(int($1), &$2, 0, &$4, &$6);
+//	}
+	LSW	(R1), $1, R2
+	LSW	(R1+R2), $1, R3
+
+//	LXST rreg ',' regaddr
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	STSW	R1, (R2)
+	STSW	R1, (R2+R3)
+
+//	LXST rreg ',' imm ',' regaddr
+//	{
+//		outgcode(int($1), &$2, 0, &$4, &$6);
+//	}
+	STSW	R1, $1, (R2)
+	STSW	R1, $1, (R2+R3)
+
+//	LXMV regaddr ',' rreg
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	MOVHBR	(R1), R2
+	MOVHBR	(R1+R2), R3
+
+//	LXMV rreg ',' regaddr
+//	{
+//		outcode(int($1), &$2, 0, &$4);
+//	}
+	MOVHBR	R1, (R2)
+	MOVHBR	R1, (R2+R3)
+
+//	LXOP regaddr
+//	{
+//		outcode(int($1), &$2, 0, &nullgen);
+//	}
+	DCBF	(R1)
+	DCBF	(R1+R2)
+
+//
+// NOP
+//
+//	LNOP comma // asm doesn't support the trailing comma.
+//	{
+//		outcode(int($1), &nullgen, 0, &nullgen);
+//	}
+	NOP
+
+//	LNOP rreg comma // asm doesn't support the trailing comma.
+//	{
+//		outcode(int($1), &$2, 0, &nullgen);
+//	}
+	NOP R2
+
+//	LNOP freg comma // asm doesn't support the trailing comma.
+//	{
+//		outcode(int($1), &$2, 0, &nullgen);
+//	}
+	NOP	F2
+
+//	LNOP ',' rreg // asm doesn't support the leading comma.
+//	{
+//		outcode(int($1), &nullgen, 0, &$3);
+//	}
+	NOP	R2
+
+//	LNOP ',' freg // asm doesn't support the leading comma.
+//	{
+//		outcode(int($1), &nullgen, 0, &$3);
+//	}
+	NOP	F2
+
+//	LNOP imm // SYSCALL $num: load $num to R0 before syscall and restore R0 to 0 afterwards.
+//	{
+//		outcode(int($1), &$2, 0, &nullgen);
+//	}
+	NOP	$4
+
+// RET
+//
+//	LRETRN	comma // asm doesn't support the trailing comma.
+//	{
+//		outcode(int($1), &nullgen, 0, &nullgen);
+//	}
+	RET
+
+// More BR/BL cases, and canonical names JMP, CALL.
+
+	BR	foo(SB)
+	BL	foo(SB)
+	JMP	foo(SB)
+	CALL	foo(SB)
+
+// END
+//
+//	LEND	comma // asm doesn't support the trailing comma.
+//	{
+//		outcode(int($1), &nullgen, 0, &nullgen);
+//	}
+	END
diff --git a/src/cmd/asm/internal/flags/flags.go b/src/cmd/asm/internal/flags/flags.go
new file mode 100644
index 0000000..bf5cb1e
--- /dev/null
+++ b/src/cmd/asm/internal/flags/flags.go
@@ -0,0 +1,69 @@
+// 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 flags implements top-level flags and the usage message for the assembler.
+package flags
+
+import (
+	"flag"
+	"fmt"
+	"os"
+	"path/filepath"
+	"strings"
+)
+
+var (
+	Debug      = flag.Bool("debug", false, "dump instructions as they are parsed")
+	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")
+	Dynlink    = flag.Bool("dynlink", false, "support references to Go symbols defined in other shared libraries")
+)
+
+var (
+	D MultiFlag
+	I MultiFlag
+)
+
+func init() {
+	flag.Var(&D, "D", "predefined symbol with optional simple value -D=identifer=value; can be set multiple times")
+	flag.Var(&I, "I", "include directory; can be set multiple times")
+}
+
+// MultiFlag allows setting a value multiple times to collect a list, as in -I=dir1 -I=dir2.
+type MultiFlag []string
+
+func (m *MultiFlag) String() string {
+	return fmt.Sprint(*m)
+}
+
+func (m *MultiFlag) Set(val string) error {
+	(*m) = append(*m, val)
+	return nil
+}
+
+func Usage() {
+	fmt.Fprintf(os.Stderr, "usage: asm [options] file.s\n")
+	fmt.Fprintf(os.Stderr, "Flags:\n")
+	flag.PrintDefaults()
+	os.Exit(2)
+}
+
+func Parse() {
+	flag.Usage = Usage
+	flag.Parse()
+	if flag.NArg() != 1 {
+		flag.Usage()
+	}
+
+	// Flag refinement.
+	if *OutputFile == "" {
+		input := filepath.Base(flag.Arg(0))
+		if strings.HasSuffix(input, ".s") {
+			input = input[:len(input)-2]
+		}
+		*OutputFile = fmt.Sprintf("%s.o", input)
+	}
+}
diff --git a/src/cmd/asm/internal/lex/input.go b/src/cmd/asm/internal/lex/input.go
new file mode 100644
index 0000000..7e495b8
--- /dev/null
+++ b/src/cmd/asm/internal/lex/input.go
@@ -0,0 +1,464 @@
+// 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 lex
+
+import (
+	"fmt"
+	"os"
+	"path/filepath"
+	"strconv"
+	"strings"
+	"text/scanner"
+
+	"cmd/asm/internal/flags"
+)
+
+// Input is the main input: a stack of readers and some macro definitions.
+// It also handles #include processing (by pushing onto the input stack)
+// and parses and instantiates macro definitions.
+type Input struct {
+	Stack
+	includes        []string
+	beginningOfLine bool
+	ifdefStack      []bool
+	macros          map[string]*Macro
+	text            string // Text of last token returned by Next.
+	peek            bool
+	peekToken       ScanToken
+	peekText        string
+}
+
+// NewInput returns a
+func NewInput(name string) *Input {
+	return &Input{
+		// include directories: look in source dir, then -I directories.
+		includes:        append([]string{filepath.Dir(name)}, flags.I...),
+		beginningOfLine: true,
+		macros:          predefine(flags.D),
+	}
+}
+
+// predefine installs the macros set by the -D flag on the command line.
+func predefine(defines flags.MultiFlag) map[string]*Macro {
+	macros := make(map[string]*Macro)
+	for _, name := range defines {
+		value := "1"
+		i := strings.IndexRune(name, '=')
+		if i > 0 {
+			name, value = name[:i], name[i+1:]
+		}
+		tokens := Tokenize(name)
+		if len(tokens) != 1 || tokens[0].ScanToken != scanner.Ident {
+			fmt.Fprintf(os.Stderr, "asm: parsing -D: %q is not a valid identifier name\n", tokens[0])
+			flags.Usage()
+		}
+		macros[name] = &Macro{
+			name:   name,
+			args:   nil,
+			tokens: Tokenize(value),
+		}
+	}
+	return macros
+}
+
+func (in *Input) Error(args ...interface{}) {
+	fmt.Fprintf(os.Stderr, "%s:%d: %s", in.File(), in.Line(), fmt.Sprintln(args...))
+	os.Exit(1)
+}
+
+// expectText is like Error but adds "got XXX" where XXX is a quoted representation of the most recent token.
+func (in *Input) expectText(args ...interface{}) {
+	in.Error(append(args, "; got", strconv.Quote(in.Stack.Text()))...)
+}
+
+// enabled reports whether the input is enabled by an ifdef, or is at the top level.
+func (in *Input) enabled() bool {
+	return len(in.ifdefStack) == 0 || in.ifdefStack[len(in.ifdefStack)-1]
+}
+
+func (in *Input) expectNewline(directive string) {
+	tok := in.Stack.Next()
+	if tok != '\n' {
+		in.expectText("expected newline after", directive)
+	}
+}
+
+func (in *Input) Next() ScanToken {
+	if in.peek {
+		in.peek = false
+		tok := in.peekToken
+		in.text = in.peekText
+		return tok
+	}
+	// If we cannot generate a token after 100 macro invocations, we're in trouble.
+	// The usual case is caught by Push, below, but be safe.
+	for nesting := 0; nesting < 100; {
+		tok := in.Stack.Next()
+		switch tok {
+		case '#':
+			if !in.beginningOfLine {
+				in.Error("'#' must be first item on line")
+			}
+			in.beginningOfLine = in.hash()
+		case scanner.Ident:
+			// Is it a macro name?
+			name := in.Stack.Text()
+			macro := in.macros[name]
+			if macro != nil {
+				nesting++
+				in.invokeMacro(macro)
+				continue
+			}
+			fallthrough
+		default:
+			in.beginningOfLine = tok == '\n'
+			if in.enabled() {
+				in.text = in.Stack.Text()
+				return tok
+			}
+		}
+	}
+	in.Error("recursive macro invocation")
+	return 0
+}
+
+func (in *Input) Text() string {
+	return in.text
+}
+
+// hash processes a # preprocessor directive. It returns true iff it completes.
+func (in *Input) hash() bool {
+	// We have a '#'; it must be followed by a known word (define, include, etc.).
+	tok := in.Stack.Next()
+	if tok != scanner.Ident {
+		in.expectText("expected identifier after '#'")
+	}
+	if !in.enabled() {
+		// Can only start including again if we are at #else or #endif.
+		// We let #line through because it might affect errors.
+		switch in.Stack.Text() {
+		case "else", "endif", "line":
+			// Press on.
+		default:
+			return false
+		}
+	}
+	switch in.Stack.Text() {
+	case "define":
+		in.define()
+	case "else":
+		in.else_()
+	case "endif":
+		in.endif()
+	case "ifdef":
+		in.ifdef(true)
+	case "ifndef":
+		in.ifdef(false)
+	case "include":
+		in.include()
+	case "line":
+		in.line()
+	case "undef":
+		in.undef()
+	default:
+		in.Error("unexpected token after '#':", in.Stack.Text())
+	}
+	return true
+}
+
+// macroName returns the name for the macro being referenced.
+func (in *Input) macroName() string {
+	// We use the Stack's input method; no macro processing at this stage.
+	tok := in.Stack.Next()
+	if tok != scanner.Ident {
+		in.expectText("expected identifier after # directive")
+	}
+	// Name is alphanumeric by definition.
+	return in.Stack.Text()
+}
+
+// #define processing.
+func (in *Input) define() {
+	name := in.macroName()
+	args, tokens := in.macroDefinition(name)
+	in.defineMacro(name, args, tokens)
+}
+
+// defineMacro stores the macro definition in the Input.
+func (in *Input) defineMacro(name string, args []string, tokens []Token) {
+	if in.macros[name] != nil {
+		in.Error("redefinition of macro:", name)
+	}
+	in.macros[name] = &Macro{
+		name:   name,
+		args:   args,
+		tokens: tokens,
+	}
+}
+
+// macroDefinition returns the list of formals and the tokens of the definition.
+// The argument list is nil for no parens on the definition; otherwise a list of
+// formal argument names.
+func (in *Input) macroDefinition(name string) ([]string, []Token) {
+	prevCol := in.Stack.Col()
+	tok := in.Stack.Next()
+	if tok == '\n' || tok == scanner.EOF {
+		return nil, nil // No definition for macro
+	}
+	var args []string
+	// The C preprocessor treats
+	//	#define A(x)
+	// and
+	//	#define A (x)
+	// distinctly: the first is a macro with arguments, the second without.
+	// Distinguish these cases using the column number, since we don't
+	// see the space itself. Note that text/scanner reports the position at the
+	// end of the token. It's where you are now, and you just read this token.
+	if tok == '(' && in.Stack.Col() == prevCol+1 {
+		// Macro has arguments. Scan list of formals.
+		acceptArg := true
+		args = []string{} // Zero length but not nil.
+	Loop:
+		for {
+			tok = in.Stack.Next()
+			switch tok {
+			case ')':
+				tok = in.Stack.Next() // First token of macro definition.
+				break Loop
+			case ',':
+				if acceptArg {
+					in.Error("bad syntax in definition for macro:", name)
+				}
+				acceptArg = true
+			case scanner.Ident:
+				if !acceptArg {
+					in.Error("bad syntax in definition for macro:", name)
+				}
+				arg := in.Stack.Text()
+				if i := lookup(args, arg); i >= 0 {
+					in.Error("duplicate argument", arg, "in definition for macro:", name)
+				}
+				args = append(args, arg)
+				acceptArg = false
+			default:
+				in.Error("bad definition for macro:", name)
+			}
+		}
+	}
+	var tokens []Token
+	// Scan to newline. Backslashes escape newlines.
+	for tok != '\n' {
+		if tok == '\\' {
+			tok = in.Stack.Next()
+			if tok != '\n' && tok != '\\' {
+				in.Error(`can only escape \ or \n in definition for macro:`, name)
+			}
+		}
+		tokens = append(tokens, Make(tok, in.Stack.Text()))
+		tok = in.Stack.Next()
+	}
+	return args, tokens
+}
+
+func lookup(args []string, arg string) int {
+	for i, a := range args {
+		if a == arg {
+			return i
+		}
+	}
+	return -1
+}
+
+// invokeMacro pushes onto the input Stack a Slice that holds the macro definition with the actual
+// parameters substituted for the formals.
+// Invoking a macro does not touch the PC/line history.
+func (in *Input) invokeMacro(macro *Macro) {
+	// If the macro has no arguments, just substitute the text.
+	if macro.args == nil {
+		in.Push(NewSlice(in.File(), in.Line(), macro.tokens))
+		return
+	}
+	tok := in.Stack.Next()
+	if tok != '(' {
+		// If the macro has arguments but is invoked without them, all we push is the macro name.
+		// First, put back the token.
+		in.peekToken = tok
+		in.peekText = in.text
+		in.peek = true
+		in.Push(NewSlice(in.File(), in.Line(), []Token{Make(macroName, macro.name)}))
+		return
+	}
+	actuals := in.argsFor(macro)
+	var tokens []Token
+	for _, tok := range macro.tokens {
+		if tok.ScanToken != scanner.Ident {
+			tokens = append(tokens, tok)
+			continue
+		}
+		substitution := actuals[tok.text]
+		if substitution == nil {
+			tokens = append(tokens, tok)
+			continue
+		}
+		tokens = append(tokens, substitution...)
+	}
+	in.Push(NewSlice(in.File(), in.Line(), tokens))
+}
+
+// argsFor returns a map from formal name to actual value for this argumented macro invocation.
+// The opening parenthesis has been absorbed.
+func (in *Input) argsFor(macro *Macro) map[string][]Token {
+	var args [][]Token
+	// One macro argument per iteration. Collect them all and check counts afterwards.
+	for argNum := 0; ; argNum++ {
+		tokens, tok := in.collectArgument(macro)
+		args = append(args, tokens)
+		if tok == ')' {
+			break
+		}
+	}
+	// Zero-argument macros are tricky.
+	if len(macro.args) == 0 && len(args) == 1 && args[0] == nil {
+		args = nil
+	} else if len(args) != len(macro.args) {
+		in.Error("wrong arg count for macro", macro.name)
+	}
+	argMap := make(map[string][]Token)
+	for i, arg := range args {
+		argMap[macro.args[i]] = arg
+	}
+	return argMap
+}
+
+// collectArgument returns the actual tokens for a single argument of a macro.
+// It also returns the token that terminated the argument, which will always
+// be either ',' or ')'. The starting '(' has been scanned.
+func (in *Input) collectArgument(macro *Macro) ([]Token, ScanToken) {
+	nesting := 0
+	var tokens []Token
+	for {
+		tok := in.Stack.Next()
+		if tok == scanner.EOF || tok == '\n' {
+			in.Error("unterminated arg list invoking macro:", macro.name)
+		}
+		if nesting == 0 && (tok == ')' || tok == ',') {
+			return tokens, tok
+		}
+		if tok == '(' {
+			nesting++
+		}
+		if tok == ')' {
+			nesting--
+		}
+		tokens = append(tokens, Make(tok, in.Stack.Text()))
+	}
+}
+
+// #ifdef and #ifndef processing.
+func (in *Input) ifdef(truth bool) {
+	name := in.macroName()
+	in.expectNewline("#if[n]def")
+	if _, defined := in.macros[name]; !defined {
+		truth = !truth
+	}
+	in.ifdefStack = append(in.ifdefStack, truth)
+}
+
+// #else processing
+func (in *Input) else_() {
+	in.expectNewline("#else")
+	if len(in.ifdefStack) == 0 {
+		in.Error("unmatched #else")
+	}
+	in.ifdefStack[len(in.ifdefStack)-1] = !in.ifdefStack[len(in.ifdefStack)-1]
+}
+
+// #endif processing.
+func (in *Input) endif() {
+	in.expectNewline("#endif")
+	if len(in.ifdefStack) == 0 {
+		in.Error("unmatched #endif")
+	}
+	in.ifdefStack = in.ifdefStack[:len(in.ifdefStack)-1]
+}
+
+// #include processing.
+func (in *Input) include() {
+	// Find and parse string.
+	tok := in.Stack.Next()
+	if tok != scanner.String {
+		in.expectText("expected string after #include")
+	}
+	name, err := strconv.Unquote(in.Stack.Text())
+	if err != nil {
+		in.Error("unquoting include file name: ", err)
+	}
+	in.expectNewline("#include")
+	// Push tokenizer for file onto stack.
+	fd, err := os.Open(name)
+	if err != nil {
+		for _, dir := range in.includes {
+			fd, err = os.Open(filepath.Join(dir, name))
+			if err == nil {
+				break
+			}
+		}
+		if err != nil {
+			in.Error("#include:", err)
+		}
+	}
+	in.Push(NewTokenizer(name, fd, fd))
+}
+
+// #line processing.
+func (in *Input) line() {
+	// Only need to handle Plan 9 format: #line 337 "filename"
+	tok := in.Stack.Next()
+	if tok != scanner.Int {
+		in.expectText("expected line number after #line")
+	}
+	line, err := strconv.Atoi(in.Stack.Text())
+	if err != nil {
+		in.Error("error parsing #line (cannot happen):", err)
+	}
+	tok = in.Stack.Next()
+	if tok != scanner.String {
+		in.expectText("expected file name in #line")
+	}
+	file, err := strconv.Unquote(in.Stack.Text())
+	if err != nil {
+		in.Error("unquoting #line file name: ", err)
+	}
+	tok = in.Stack.Next()
+	if tok != '\n' {
+		in.Error("unexpected token at end of #line: ", tok)
+	}
+	linkCtxt.LineHist.Update(histLine, file, line)
+	in.Stack.SetPos(line, file)
+}
+
+// #undef processing
+func (in *Input) undef() {
+	name := in.macroName()
+	if in.macros[name] == nil {
+		in.Error("#undef for undefined macro:", name)
+	}
+	// Newline must be next.
+	tok := in.Stack.Next()
+	if tok != '\n' {
+		in.Error("syntax error in #undef for macro:", name)
+	}
+	delete(in.macros, name)
+}
+
+func (in *Input) Push(r TokenReader) {
+	if len(in.tr) > 100 {
+		in.Error("input recursion")
+	}
+	in.Stack.Push(r)
+}
+
+func (in *Input) Close() {
+}
diff --git a/src/cmd/asm/internal/lex/lex.go b/src/cmd/asm/internal/lex/lex.go
new file mode 100644
index 0000000..6fce55f
--- /dev/null
+++ b/src/cmd/asm/internal/lex/lex.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.
+
+// Package lex implements lexical analysis for the assembler.
+package lex
+
+import (
+	"fmt"
+	"log"
+	"os"
+	"strings"
+	"text/scanner"
+
+	"cmd/internal/obj"
+)
+
+// A ScanToken represents an input item. It is a simple wrapping of rune, as
+// returned by text/scanner.Scanner, plus a couple of extra values.
+type ScanToken rune
+
+const (
+	// Asm defines some two-character lexemes. We make up
+	// a rune/ScanToken value for them - ugly but simple.
+	LSH       ScanToken = -1000 - iota // << Left shift.
+	RSH                                // >> Logical right shift.
+	ARR                                // -> Used on ARM for shift type 3, arithmetic right shift.
+	ROT                                // @> Used on ARM for shift type 4, rotate right.
+	macroName                          // name of macro that should not be expanded
+)
+
+// IsRegisterShift reports whether the token is one of the ARM register shift operators.
+func IsRegisterShift(r ScanToken) bool {
+	return ROT <= r && r <= LSH // Order looks backwards because these are negative.
+}
+
+func (t ScanToken) String() string {
+	switch t {
+	case scanner.EOF:
+		return "EOF"
+	case scanner.Ident:
+		return "identifier"
+	case scanner.Int:
+		return "integer constant"
+	case scanner.Float:
+		return "float constant"
+	case scanner.Char:
+		return "rune constant"
+	case scanner.String:
+		return "string constant"
+	case scanner.RawString:
+		return "raw string constant"
+	case scanner.Comment:
+		return "comment"
+	default:
+		return fmt.Sprintf("%q", rune(t))
+	}
+}
+
+var (
+	// It might be nice if these weren't global.
+	linkCtxt *obj.Link     // The link context for all instructions.
+	histLine int       = 1 // The cumulative count of lines processed.
+)
+
+// HistLine reports the cumulative source line number of the token,
+// for use in the Prog structure for the linker. (It's always handling the
+// instruction from the current lex line.)
+// It returns int32 because that's what type ../asm prefers.
+func HistLine() int32 {
+	return int32(histLine)
+}
+
+// NewLexer returns a lexer for the named file and the given link context.
+func NewLexer(name string, ctxt *obj.Link) TokenReader {
+	linkCtxt = ctxt
+	input := NewInput(name)
+	fd, err := os.Open(name)
+	if err != nil {
+		log.Fatalf("asm: %s\n", err)
+	}
+	input.Push(NewTokenizer(name, fd, fd))
+	return input
+}
+
+// InitHist sets the line count to 1, for reproducible testing.
+func InitHist() {
+	histLine = 1
+}
+
+// The other files in this directory each contain an implementation of TokenReader.
+
+// A TokenReader is like a reader, but returns lex tokens of type Token. It also can tell you what
+// the text of the most recently returned token is, and where it was found.
+// The underlying scanner elides all spaces except newline, so the input looks like a  stream of
+// Tokens; original spacing is lost but we don't need it.
+type TokenReader interface {
+	// Next returns the next token.
+	Next() ScanToken
+	// The following methods all refer to the most recent token returned by Next.
+	// Text returns the original string representation of the token.
+	Text() string
+	// File reports the source file name of the token.
+	File() string
+	// Line reports the source line number of the token.
+	Line() int
+	// Col reports the source column number of the token.
+	Col() int
+	// SetPos sets the file and line number.
+	SetPos(line int, file string)
+	// Close does any teardown required.
+	Close()
+}
+
+// A Token is a scan token plus its string value.
+// A macro is stored as a sequence of Tokens with spaces stripped.
+type Token struct {
+	ScanToken
+	text string
+}
+
+// Make returns a Token with the given rune (ScanToken) and text representation.
+func Make(token ScanToken, text string) Token {
+	// If the symbol starts with center dot, as in ·x, rewrite it as ""·x
+	if token == scanner.Ident && strings.HasPrefix(text, "\u00B7") {
+		text = `""` + text
+	}
+	// Substitute the substitutes for . and /.
+	text = strings.Replace(text, "\u00B7", ".", -1)
+	text = strings.Replace(text, "\u2215", "/", -1)
+	return Token{ScanToken: token, text: text}
+}
+
+func (l Token) String() string {
+	return l.text
+}
+
+// A Macro represents the definition of a #defined macro.
+type Macro struct {
+	name   string   // The #define name.
+	args   []string // Formal arguments.
+	tokens []Token  // Body of macro.
+}
+
+// Tokenize turns a string into a list of Tokens; used to parse the -D flag and in tests.
+func Tokenize(str string) []Token {
+	t := NewTokenizer("command line", strings.NewReader(str), nil)
+	var tokens []Token
+	for {
+		tok := t.Next()
+		if tok == scanner.EOF {
+			break
+		}
+		tokens = append(tokens, Make(tok, t.Text()))
+	}
+	return tokens
+}
diff --git a/src/cmd/asm/internal/lex/lex_test.go b/src/cmd/asm/internal/lex/lex_test.go
new file mode 100644
index 0000000..f034d69
--- /dev/null
+++ b/src/cmd/asm/internal/lex/lex_test.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.
+
+package lex
+
+import (
+	"bytes"
+	"strings"
+	"testing"
+	"text/scanner"
+)
+
+type lexTest struct {
+	name   string
+	input  string
+	output string
+}
+
+var lexTests = []lexTest{
+	{
+		"empty",
+		"",
+		"",
+	},
+	{
+		"simple",
+		"1 (a)",
+		"1.(.a.)",
+	},
+	{
+		"simple define",
+		lines(
+			"#define A 1234",
+			"A",
+		),
+		"1234.\n",
+	},
+	{
+		"define without value",
+		"#define A",
+		"",
+	},
+	{
+		"macro without arguments",
+		"#define A() 1234\n" + "A()\n",
+		"1234.\n",
+	},
+	{
+		"macro with just parens as body",
+		"#define A () \n" + "A\n",
+		"(.).\n",
+	},
+	{
+		"macro with parens but no arguments",
+		"#define A (x) \n" + "A\n",
+		"(.x.).\n",
+	},
+	{
+		"macro with arguments",
+		"#define A(x, y, z) x+z+y\n" + "A(1, 2, 3)\n",
+		"1.+.3.+.2.\n",
+	},
+	{
+		"argumented macro invoked without arguments",
+		lines(
+			"#define X() foo ",
+			"X()",
+			"X",
+		),
+		"foo.\n.X.\n",
+	},
+	{
+		"multiline macro without arguments",
+		lines(
+			"#define A 1\\",
+			"\t2\\",
+			"\t3",
+			"before",
+			"A",
+			"after",
+		),
+		"before.\n.1.\n.2.\n.3.\n.after.\n",
+	},
+	{
+		"multiline macro with arguments",
+		lines(
+			"#define A(a, b, c) a\\",
+			"\tb\\",
+			"\tc",
+			"before",
+			"A(1, 2, 3)",
+			"after",
+		),
+		"before.\n.1.\n.2.\n.3.\n.after.\n",
+	},
+	{
+		"LOAD macro",
+		lines(
+			"#define LOAD(off, reg) \\",
+			"\tMOVBLZX	(off*4)(R12),	reg \\",
+			"\tADDB	reg,		DX",
+			"",
+			"LOAD(8, AX)",
+		),
+		"\n.\n.MOVBLZX.(.8.*.4.).(.R12.).,.AX.\n.ADDB.AX.,.DX.\n",
+	},
+	{
+		"nested multiline macro",
+		lines(
+			"#define KEYROUND(xmm, load, off, r1, r2, index) \\",
+			"\tMOVBLZX	(BP)(DX*4),	R8 \\",
+			"\tload((off+1), r2) \\",
+			"\tMOVB	R8,		(off*4)(R12) \\",
+			"\tPINSRW	$index, (BP)(R8*4), xmm",
+			"#define LOAD(off, reg) \\",
+			"\tMOVBLZX	(off*4)(R12),	reg \\",
+			"\tADDB	reg,		DX",
+			"KEYROUND(X0, LOAD, 8, AX, BX, 0)",
+		),
+		"\n.MOVBLZX.(.BP.).(.DX.*.4.).,.R8.\n.\n.MOVBLZX.(.(.8.+.1.).*.4.).(.R12.).,.BX.\n.ADDB.BX.,.DX.\n.MOVB.R8.,.(.8.*.4.).(.R12.).\n.PINSRW.$.0.,.(.BP.).(.R8.*.4.).,.X0.\n",
+	},
+}
+
+func TestLex(t *testing.T) {
+	for _, test := range lexTests {
+		input := NewInput(test.name)
+		input.Push(NewTokenizer(test.name, strings.NewReader(test.input), nil))
+		result := drain(input)
+		if result != test.output {
+			t.Errorf("%s: got %q expected %q", test.name, result, test.output)
+		}
+	}
+}
+
+// lines joins the arguments together as complete lines.
+func lines(a ...string) string {
+	return strings.Join(a, "\n") + "\n"
+}
+
+// drain returns a single string representing the processed input tokens.
+func drain(input *Input) string {
+	var buf bytes.Buffer
+	for {
+		tok := input.Next()
+		if tok == scanner.EOF {
+			return buf.String()
+		}
+		if buf.Len() > 0 {
+			buf.WriteByte('.')
+		}
+		buf.WriteString(input.Text())
+	}
+}
diff --git a/src/cmd/asm/internal/lex/slice.go b/src/cmd/asm/internal/lex/slice.go
new file mode 100644
index 0000000..e94106b
--- /dev/null
+++ b/src/cmd/asm/internal/lex/slice.go
@@ -0,0 +1,59 @@
+// 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 lex
+
+import "text/scanner"
+
+// A Slice reads from a slice of Tokens.
+type Slice struct {
+	tokens   []Token
+	fileName string
+	line     int
+	pos      int
+}
+
+func NewSlice(fileName string, line int, tokens []Token) *Slice {
+	return &Slice{
+		tokens:   tokens,
+		fileName: fileName,
+		line:     line,
+		pos:      -1, // Next will advance to zero.
+	}
+}
+
+func (s *Slice) Next() ScanToken {
+	s.pos++
+	if s.pos >= len(s.tokens) {
+		return scanner.EOF
+	}
+	return s.tokens[s.pos].ScanToken
+}
+
+func (s *Slice) Text() string {
+	return s.tokens[s.pos].text
+}
+
+func (s *Slice) File() string {
+	return s.fileName
+}
+
+func (s *Slice) Line() int {
+	return s.line
+}
+
+func (s *Slice) Col() int {
+	// Col is only called when defining a macro, which can't reach here.
+	panic("cannot happen: slice col")
+}
+
+func (s *Slice) SetPos(line int, file string) {
+	// Cannot happen because we only have slices of already-scanned
+	// text, but be prepared.
+	s.line = line
+	s.fileName = file
+}
+
+func (s *Slice) Close() {
+}
diff --git a/src/cmd/asm/internal/lex/stack.go b/src/cmd/asm/internal/lex/stack.go
new file mode 100644
index 0000000..72d7f8a
--- /dev/null
+++ b/src/cmd/asm/internal/lex/stack.go
@@ -0,0 +1,53 @@
+// 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 lex
+
+import "text/scanner"
+
+// A Stack is a stack of TokenReaders. As the top TokenReader hits EOF,
+// it resumes reading the next one down.
+type Stack struct {
+	tr []TokenReader
+}
+
+// Push adds tr to the top (end) of the input stack. (Popping happens automatically.)
+func (s *Stack) Push(tr TokenReader) {
+	s.tr = append(s.tr, tr)
+}
+
+func (s *Stack) Next() ScanToken {
+	tos := s.tr[len(s.tr)-1]
+	tok := tos.Next()
+	for tok == scanner.EOF && len(s.tr) > 1 {
+		tos.Close()
+		// Pop the topmost item from the stack and resume with the next one down.
+		s.tr = s.tr[:len(s.tr)-1]
+		tok = s.Next()
+	}
+	return tok
+}
+
+func (s *Stack) Text() string {
+	return s.tr[len(s.tr)-1].Text()
+}
+
+func (s *Stack) File() string {
+	return s.tr[len(s.tr)-1].File()
+}
+
+func (s *Stack) Line() int {
+	return s.tr[len(s.tr)-1].Line()
+}
+
+func (s *Stack) Col() int {
+	return s.tr[len(s.tr)-1].Col()
+}
+
+func (s *Stack) SetPos(line int, file string) {
+	s.tr[len(s.tr)-1].SetPos(line, file)
+}
+
+func (s *Stack) Close() { // Unused.
+}
diff --git a/src/cmd/asm/internal/lex/tokenizer.go b/src/cmd/asm/internal/lex/tokenizer.go
new file mode 100644
index 0000000..6a4d954
--- /dev/null
+++ b/src/cmd/asm/internal/lex/tokenizer.go
@@ -0,0 +1,152 @@
+// 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 lex
+
+import (
+	"io"
+	"os"
+	"strings"
+	"text/scanner"
+	"unicode"
+)
+
+// A Tokenizer is a simple wrapping of text/scanner.Scanner, configured
+// for our purposes and made a TokenReader. It forms the lowest level,
+// turning text from readers into tokens.
+type Tokenizer struct {
+	tok      ScanToken
+	s        *scanner.Scanner
+	line     int
+	fileName string
+	file     *os.File // If non-nil, file descriptor to close.
+}
+
+func NewTokenizer(name string, r io.Reader, file *os.File) *Tokenizer {
+	var s scanner.Scanner
+	s.Init(r)
+	// Newline is like a semicolon; other space characters are fine.
+	s.Whitespace = 1<<'\t' | 1<<'\r' | 1<<' '
+	// Don't skip comments: we need to count newlines.
+	s.Mode = scanner.ScanChars |
+		scanner.ScanFloats |
+		scanner.ScanIdents |
+		scanner.ScanInts |
+		scanner.ScanStrings |
+		scanner.ScanComments
+	s.Position.Filename = name
+	s.IsIdentRune = isIdentRune
+	if file != nil {
+		linkCtxt.LineHist.Push(histLine, name)
+	}
+	return &Tokenizer{
+		s:        &s,
+		line:     1,
+		fileName: name,
+		file:     file,
+	}
+}
+
+// We want center dot (·) and division slash (∕) to work as identifier characters.
+func isIdentRune(ch rune, i int) bool {
+	if unicode.IsLetter(ch) {
+		return true
+	}
+	switch ch {
+	case '_': // Underscore; traditional.
+		return true
+	case '\u00B7': // Represents the period in runtime.exit. U+00B7 '·' middle dot
+		return true
+	case '\u2215': // Represents the slash in runtime/debug.setGCPercent. U+2215 '∕' division slash
+		return true
+	}
+	// Digits are OK only after the first character.
+	return i > 0 && unicode.IsDigit(ch)
+}
+
+func (t *Tokenizer) Text() string {
+	switch t.tok {
+	case LSH:
+		return "<<"
+	case RSH:
+		return ">>"
+	case ARR:
+		return "->"
+	case ROT:
+		return "@>"
+	}
+	return t.s.TokenText()
+}
+
+func (t *Tokenizer) File() string {
+	return t.fileName
+}
+
+func (t *Tokenizer) Line() int {
+	return t.line
+}
+
+func (t *Tokenizer) Col() int {
+	return t.s.Pos().Column
+}
+
+func (t *Tokenizer) SetPos(line int, file string) {
+	t.line = line
+	t.fileName = file
+}
+
+func (t *Tokenizer) Next() ScanToken {
+	s := t.s
+	for {
+		t.tok = ScanToken(s.Scan())
+		if t.tok != scanner.Comment {
+			break
+		}
+		length := strings.Count(s.TokenText(), "\n")
+		t.line += length
+		histLine += length
+		// TODO: If we ever have //go: comments in assembly, will need to keep them here.
+		// For now, just discard all comments.
+	}
+	switch t.tok {
+	case '\n':
+		if t.file != nil {
+			histLine++
+		}
+		t.line++
+	case '-':
+		if s.Peek() == '>' {
+			s.Next()
+			t.tok = ARR
+			return ARR
+		}
+	case '@':
+		if s.Peek() == '>' {
+			s.Next()
+			t.tok = ROT
+			return ROT
+		}
+	case '<':
+		if s.Peek() == '<' {
+			s.Next()
+			t.tok = LSH
+			return LSH
+		}
+	case '>':
+		if s.Peek() == '>' {
+			s.Next()
+			t.tok = RSH
+			return RSH
+		}
+	}
+	return t.tok
+}
+
+func (t *Tokenizer) Close() {
+	if t.file != nil {
+		t.file.Close()
+		// It's an open file, so pop the line history.
+		linkCtxt.LineHist.Pop(histLine)
+	}
+}
diff --git a/src/cmd/asm/main.go b/src/cmd/asm/main.go
new file mode 100644
index 0000000..db0e28e
--- /dev/null
+++ b/src/cmd/asm/main.go
@@ -0,0 +1,67 @@
+// 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 (
+	"flag"
+	"fmt"
+	"log"
+	"os"
+
+	"cmd/asm/internal/arch"
+	"cmd/asm/internal/asm"
+	"cmd/asm/internal/flags"
+	"cmd/asm/internal/lex"
+
+	"cmd/internal/obj"
+)
+
+func main() {
+	log.SetFlags(0)
+	log.SetPrefix("asm: ")
+
+	GOARCH := obj.Getgoarch()
+
+	architecture := arch.Set(GOARCH)
+	if architecture == nil {
+		log.Fatalf("asm: unrecognized architecture %s", GOARCH)
+	}
+
+	flags.Parse()
+
+	// Create object file, write header.
+	fd, err := os.Create(*flags.OutputFile)
+	if err != nil {
+		log.Fatal(err)
+	}
+	ctxt := obj.Linknew(architecture.LinkArch)
+	if *flags.PrintOut {
+		ctxt.Debugasm = 1
+	}
+	ctxt.LineHist.TrimPathPrefix = *flags.TrimPath
+	ctxt.Flag_dynlink = *flags.Dynlink
+	if *flags.Shared || *flags.Dynlink {
+		ctxt.Flag_shared = 1
+	}
+	ctxt.Bso = obj.Binitw(os.Stdout)
+	defer ctxt.Bso.Flush()
+	ctxt.Diag = log.Fatalf
+	output := obj.Binitw(fd)
+	fmt.Fprintf(output, "go object %s %s %s\n", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion())
+	fmt.Fprintf(output, "!\n")
+
+	lexer := lex.NewLexer(flag.Arg(0), ctxt)
+	parser := asm.NewParser(ctxt, architecture, lexer)
+	pList := obj.Linknewplist(ctxt)
+	var ok bool
+	pList.Firstpc, ok = parser.Parse()
+	if !ok {
+		log.Printf("asm: assembly of %s failed", flag.Arg(0))
+		os.Remove(*flags.OutputFile)
+		os.Exit(1)
+	}
+	obj.Writeobjdirect(ctxt, output)
+	output.Flush()
+}
diff --git a/src/cmd/cc/Makefile b/src/cmd/cc/Makefile
deleted file mode 100644
index 34df31d..0000000
--- a/src/cmd/cc/Makefile
+++ /dev/null
@@ -1,10 +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.
-
-include ../../Make.dist
-
-install: y.tab.h
-
-y.tab.h: cc.y
-	LANG=C LANGUAGE=en_US.UTF8 bison -d -v -y cc.y
diff --git a/src/cmd/cc/acid.c b/src/cmd/cc/acid.c
deleted file mode 100644
index 23147e5..0000000
--- a/src/cmd/cc/acid.c
+++ /dev/null
@@ -1,344 +0,0 @@
-// Inferno utils/cc/acid.c
-// http://code.google.com/p/inferno-os/source/browse/utils/cc/acid.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include <u.h>
-#include "cc.h"
-
-static char *kwd[] =
-{
-	"$adt", "$aggr", "$append", "$complex", "$defn",
-	"$delete", "$do", "$else", "$eval", "$head", "$if",
-	"$local", "$loop", "$return", "$tail", "$then",
-	"$union", "$whatis", "$while",
-};
-
-char*
-amap(char *s)
-{
-	int i, bot, top, new;
-
-	bot = 0;
-	top = bot + nelem(kwd) - 1;
-	while(bot <= top){
-		new = bot + (top - bot)/2;
-		i = strcmp(kwd[new]+1, s);
-		if(i == 0)
-			return kwd[new];
-
-		if(i < 0)
-			bot = new + 1;
-		else
-			top = new - 1;
-	}
-	return s;
-}
-
-Sym*
-acidsue(Type *t)
-{
-	int h;
-	Sym *s;
-
-	if(t != T)
-	for(h=0; h<nelem(hash); h++)
-		for(s = hash[h]; s != S; s = s->link)
-			if(s->suetag && s->suetag->link == t)
-				return s;
-	return 0;
-}
-
-Sym*
-acidfun(Type *t)
-{
-	int h;
-	Sym *s;
-
-	for(h=0; h<nelem(hash); h++)
-		for(s = hash[h]; s != S; s = s->link)
-			if(s->type == t)
-				return s;
-	return 0;
-}
-
-char	acidchar[NTYPE];
-Init	acidcinit[] =
-{
-	TCHAR,		'C',	0,
-	TUCHAR,		'b',	0,
-	TSHORT,		'd',	0,
-	TUSHORT,	'u',	0,
-	TLONG,		'D',	0,
-	TULONG,		'U',	0,
-	TVLONG,		'V',	0,
-	TUVLONG,	'W',	0,
-	TFLOAT,		'f',	0,
-	TDOUBLE,	'F',	0,
-	TARRAY,		'a',	0,
-	TIND,		'X',	0,
-	-1,		0,	0,
-};
-
-static void
-acidinit(void)
-{
-	Init *p;
-
-	for(p=acidcinit; p->code >= 0; p++)
-		acidchar[p->code] = p->value;
-
-	acidchar[TINT] = acidchar[TLONG];
-	acidchar[TUINT] = acidchar[TULONG];
-	if(types[TINT]->width != types[TLONG]->width) {
-		acidchar[TINT] = acidchar[TSHORT];
-		acidchar[TUINT] = acidchar[TUSHORT];
-		if(types[TINT]->width != types[TSHORT]->width)
-			warn(Z, "acidmember int not long or short");
-	}
-	if(types[TIND]->width == types[TUVLONG]->width)
-		acidchar[TIND] = 'Y';
-	
-}
-
-void
-acidmember(Type *t, int32 off, int flag)
-{
-	Sym *s, *s1;
-	Type *l;
-	static int acidcharinit = 0;
-
-	if(acidcharinit == 0) {
-		acidinit();
-		acidcharinit = 1;
-	}
-	s = t->sym;
-	switch(t->etype) {
-	default:
-		Bprint(&outbuf, "	T%d\n", t->etype);
-		break;
-
-	case TIND:
-		if(s == S)
-			break;
-		l = t->link;
-		if(flag) { 
-			if(typesu[l->etype]) {
-				s1 = acidsue(l->link);
-				if(s1 != S) {
-					Bprint(&outbuf, "	'A' %s %d %s;\n",
-						amap(s1->name),
-						t->offset+off, amap(s->name));
-					break;
-				}
-			}
-		} else {
-			l = t->link;
-			s1 = S;
-			if(typesu[l->etype])
-				s1 = acidsue(l->link);
-			if(s1 != S) {
-				Bprint(&outbuf,
-					"\tprint(indent, \"%s\t(%s)\", addr.%s\\X, \"\\n\");\n",
-					amap(s->name), amap(s1->name), amap(s->name));
-			} else {
-				Bprint(&outbuf,
-					"\tprint(indent, \"%s\t\", addr.%s\\X, \"\\n\");\n",
-					amap(s->name), amap(s->name));
-			}
-			break;
-		}
-
-	case TINT:
-	case TUINT:
-	case TCHAR:
-	case TUCHAR:
-	case TSHORT:
-	case TUSHORT:
-	case TLONG:
-	case TULONG:
-	case TVLONG:
-	case TUVLONG:
-	case TFLOAT:
-	case TDOUBLE:
-	case TARRAY:
-		if(s == S)
-			break;
-		if(flag) {
-			Bprint(&outbuf, "	'%c' %d %s;\n",
-			acidchar[t->etype], t->offset+off, amap(s->name));
-		} else {
-			Bprint(&outbuf, "\tprint(indent, \"%s\t\", addr.%s, \"\\n\");\n",
-				amap(s->name), amap(s->name));
-		}
-		break;
-
-	case TSTRUCT:
-	case TUNION:
-		s1 = acidsue(t->link);
-		if(s1 == S)
-			break;
-		if(flag) {
-			if(s == S) {
-				Bprint(&outbuf, "	{\n");
-				for(l = t->link; l != T; l = l->down)
-					acidmember(l, t->offset+off, flag);
-				Bprint(&outbuf, "	};\n");
-			} else {
-				Bprint(&outbuf, "	%s %d %s;\n",
-					amap(s1->name),
-					t->offset+off, amap(s->name));
-			}
-		} else {
-			if(s != S) {
-				Bprint(&outbuf, "\tprint(indent, \"%s %s {\\n\");\n",
-					amap(s1->name), amap(s->name));
-				Bprint(&outbuf, "\tindent_%s(addr.%s, indent+\"\\t\");\n",
-					amap(s1->name), amap(s->name));
-				Bprint(&outbuf, "\tprint(indent, \"}\\n\");\n");
-			} else {
-				Bprint(&outbuf, "\tprint(indent, \"%s {\\n\");\n",
-					amap(s1->name));
-				Bprint(&outbuf, "\tindent_%s(addr+%d, indent+\"\\t\");\n",
-					amap(s1->name), t->offset+off);
-				Bprint(&outbuf, "\tprint(indent, \"}\\n\");\n");
-			}
-		}
-		break;
-	}
-}
-
-void
-acidtype(Type *t)
-{
-	Sym *s;
-	Type *l;
-	Io *i;
-	int n;
-	char *an;
-
-	if(!debug['a'])
-		return;
-	if(debug['a'] > 1) {
-		n = 0;
-		for(i=iostack; i; i=i->link)
-			n++;
-		if(n > 1)
-			return;
-	}
-	s = acidsue(t->link);
-	if(s == S)
-		return;
-	switch(t->etype) {
-	default:
-		Bprint(&outbuf, "T%d\n", t->etype);
-		return;
-
-	case TUNION:
-	case TSTRUCT:
-		if(debug['s'])
-			goto asmstr;
-		an = amap(s->name);
-		Bprint(&outbuf, "sizeof%s = %d;\n", an, t->width);
-		Bprint(&outbuf, "aggr %s\n{\n", an);
-		for(l = t->link; l != T; l = l->down)
-			acidmember(l, 0, 1);
-		Bprint(&outbuf, "};\n\n");
-
-		Bprint(&outbuf, "defn\n%s(addr) {\n\tindent_%s(addr, \"\\t\");\n}\n", an, an);
-		Bprint(&outbuf, "defn\nindent_%s(addr, indent) {\n\tcomplex %s addr;\n", an, an);
-		for(l = t->link; l != T; l = l->down)
-			acidmember(l, 0, 0);
-		Bprint(&outbuf, "};\n\n");
-		break;
-	asmstr:
-		if(s == S)
-			break;
-		for(l = t->link; l != T; l = l->down)
-			if(l->sym != S)
-				Bprint(&outbuf, "#define\t%s.%s\t%d\n",
-					s->name,
-					l->sym->name,
-					l->offset);
-		break;
-	}
-}
-
-void
-acidvar(Sym *s)
-{
-	int n;
-	Io *i;
-	Type *t;
-	Sym *s1, *s2;
-
-	if(!debug['a'] || debug['s'])
-		return;
-	if(debug['a'] > 1) {
-		n = 0;
-		for(i=iostack; i; i=i->link)
-			n++;
-		if(n > 1)
-			return;
-	}
-	t = s->type;
-	while(t && t->etype == TIND)
-		t = t->link;
-	if(t == T)
-		return;
-	if(t->etype == TENUM) {
-		Bprint(&outbuf, "%s = ", amap(s->name));
-		if(!typefd[t->etype])
-			Bprint(&outbuf, "%lld;\n", s->vconst);
-		else
-			Bprint(&outbuf, "%f\n;", s->fconst);
-		return;
-	}
-	if(!typesu[t->etype])
-		return;
-	s1 = acidsue(t->link);
-	if(s1 == S)
-		return;
-	switch(s->class) {
-	case CAUTO:
-	case CPARAM:
-		s2 = acidfun(thisfn);
-		if(s2)
-			Bprint(&outbuf, "complex %s %s:%s;\n",
-				amap(s1->name), amap(s2->name), amap(s->name));
-		break;
-	
-	case CSTATIC:
-	case CEXTERN:
-	case CGLOBL:
-	case CLOCAL:
-		Bprint(&outbuf, "complex %s %s;\n",
-			amap(s1->name), amap(s->name));
-		break;
-	}
-}
diff --git a/src/cmd/cc/bits.c b/src/cmd/cc/bits.c
deleted file mode 100644
index 4496d65..0000000
--- a/src/cmd/cc/bits.c
+++ /dev/null
@@ -1,120 +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 at 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 at 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.
-
-#include	<u.h>
-#include	"cc.h"
-
-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;
-}
-*/
-
-int
-bany(Bits *a)
-{
-	int i;
-
-	for(i=0; i<BITS; i++)
-		if(a->b[i])
-			return 1;
-	return 0;
-}
-
-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;
-}
-
-int
-bnum(Bits a)
-{
-	int i;
-	int32 b;
-
-	for(i=0; i<BITS; i++)
-		if(b = a.b[i])
-			return 32*i + bitno(b);
-	diag(Z, "bad in bnum");
-	return 0;
-}
-
-Bits
-blsh(uint n)
-{
-	Bits c;
-
-	c = zbits;
-	c.b[n/32] = 1L << (n%32);
-	return c;
-}
-
-int
-bset(Bits a, uint n)
-{
-	if(a.b[n/32] & (1L << (n%32)))
-		return 1;
-	return 0;
-}
diff --git a/src/cmd/cc/cc.h b/src/cmd/cc/cc.h
deleted file mode 100644
index 9530f5c..0000000
--- a/src/cmd/cc/cc.h
+++ /dev/null
@@ -1,835 +0,0 @@
-// Inferno utils/cc/cc.h
-// http://code.google.com/p/inferno-os/source/browse/utils/cc/cc.h
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include <libc.h>
-#include <bio.h>
-#include <link.h>
-
-#ifndef	EXTERN
-#define EXTERN	extern
-#endif
-
-#undef	getc
-#undef	ungetc
-#undef	BUFSIZ
-
-#define	getc	ccgetc
-#define	ungetc	ccungetc
-
-typedef	struct	Node	Node;
-typedef	struct	Sym	Sym;
-typedef	struct	Type	Type;
-typedef	struct	Funct	Funct;
-typedef	struct	Decl	Decl;
-typedef	struct	Io	Io;
-typedef	struct	Term	Term;
-typedef	struct	Init	Init;
-typedef	struct	Bits	Bits;
-typedef	struct	Bvec	Bvec;
-typedef	struct	Dynimp	Dynimp;
-typedef	struct	Dynexp	Dynexp;
-typedef	struct	Var	Var;
-
-typedef	Rune	TRune;	/* target system type */
-
-#define	BUFSIZ		8192
-#define	NSYMB		500
-#define	NHASH		1024
-#define	STRINGSZ	200
-#define	HISTSZ		20
-#define YYMAXDEPTH	500
-#define	NTERM		10
-#define	MAXALIGN	7
-
-#define	SIGN(n)		((uvlong)1<<(n-1))
-#define	MASK(n)		(SIGN(n)|(SIGN(n)-1))
-
-#define	BITS	5
-#define	NVAR	(BITS*sizeof(uint32)*8)
-struct	Bits
-{
-	uint32	b[BITS];
-};
-
-struct Bvec
-{
-	int32	n;	// number of bits
-	uint32	b[];
-};
-
-struct	Var
-{
-	vlong	offset;
-	LSym*	sym;
-	char	name;
-	char	etype;
-};
-
-struct	Node
-{
-	Node*	left;
-	Node*	right;
-	void*	label;
-	int32	pc;
-	int	reg;
-	int32	xoffset;
-	double	fconst;		/* fp constant */
-	vlong	vconst;		/* non fp const */
-	char*	cstring;	/* character string */
-	TRune*	rstring;	/* rune string */
-
-	Sym*	sym;
-	Type*	type;
-	int32	lineno;
-	uchar	op;
-	uchar	oldop;
-	uchar	xcast;
-	uchar	class;
-	uchar	etype;
-	uchar	complex;
-	uchar	addable;
-	uchar	scale;
-	uchar	garb;
-};
-#define	Z	((Node*)0)
-
-struct	Sym
-{
-	Sym*	link;
-	LSym*	lsym;
-	Type*	type;
-	Type*	suetag;
-	Type*	tenum;
-	char*	macro;
-	int32	varlineno;
-	int32	offset;
-	vlong	vconst;
-	double	fconst;
-	Node*	label;
-	ushort	lexical;
-	char	*name;
-	ushort	block;
-	ushort	sueblock;
-	uchar	class;
-	uchar	sym;
-	uchar	aused;
-	uchar	sig;
-	uchar	dataflag;
-};
-#define	S	((Sym*)0)
-
-enum{
-	SIGNONE = 0,
-	SIGDONE = 1,
-	SIGINTERN = 2,
-
-	SIGNINTERN = 1729*325*1729,
-};
-
-struct	Decl
-{
-	Decl*	link;
-	Sym*	sym;
-	Type*	type;
-	int32	varlineno;
-	int32	offset;
-	short	val;
-	ushort	block;
-	uchar	class;
-	uchar	aused;
-};
-#define	D	((Decl*)0)
-
-struct	Type
-{
-	Sym*	sym;
-	Sym*	tag;
-	Funct*	funct;
-	Type*	link;
-	Type*	down;
-	int32	width;
-	int32	offset;
-	int32	lineno;
-	uchar	shift;
-	uchar	nbits;
-	uchar	etype;
-	uchar	garb;
-	uchar	align;
-};
-
-#define	T	((Type*)0)
-#define	NODECL	((void(*)(int, Type*, Sym*))0)
-
-struct	Init			/* general purpose initialization */
-{
-	int	code;
-	uint32	value;
-	char*	s;
-};
-
-EXTERN struct
-{
-	char*	p;
-	int	c;
-} fi;
-
-struct	Io
-{
-	Io*	link;
-	char*	p;
-	char	b[BUFSIZ];
-	short	c;
-	short	f;
-};
-#define	I	((Io*)0)
-
-struct	Term
-{
-	vlong	mult;
-	Node	*node;
-};
-
-enum
-{
-	Axxx,
-	Ael1,
-	Ael2,
-	Asu2,
-	Aarg0,
-	Aarg1,
-	Aarg2,
-	Aaut3,
-	NALIGN,
-};
-
-enum
-{
-	DMARK,
-	DAUTO,
-	DSUE,
-	DLABEL,
-};
-enum
-{
-	OXXX,
-	OADD,
-	OADDR,
-	OAND,
-	OANDAND,
-	OARRAY,
-	OAS,
-	OASI,
-	OASADD,
-	OASAND,
-	OASASHL,
-	OASASHR,
-	OASDIV,
-	OASHL,
-	OASHR,
-	OASLDIV,
-	OASLMOD,
-	OASLMUL,
-	OASLSHR,
-	OASMOD,
-	OASMUL,
-	OASOR,
-	OASSUB,
-	OASXOR,
-	OBIT,
-	OBREAK,
-	OCASE,
-	OCAST,
-	OCOMMA,
-	OCOND,
-	OCONST,
-	OCONTINUE,
-	ODIV,
-	ODOT,
-	ODOTDOT,
-	ODWHILE,
-	OENUM,
-	OEQ,
-	OEXREG,
-	OFOR,
-	OFUNC,
-	OGE,
-	OGOTO,
-	OGT,
-	OHI,
-	OHS,
-	OIF,
-	OIND,
-	OINDREG,
-	OINIT,
-	OLABEL,
-	OLDIV,
-	OLE,
-	OLIST,
-	OLMOD,
-	OLMUL,
-	OLO,
-	OLS,
-	OLSHR,
-	OLT,
-	OMOD,
-	OMUL,
-	ONAME,
-	ONE,
-	ONOT,
-	OOR,
-	OOROR,
-	OPOSTDEC,
-	OPOSTINC,
-	OPREDEC,
-	OPREINC,
-	OPREFETCH,
-	OPROTO,
-	OREGISTER,
-	ORETURN,
-	OSET,
-	OSIGN,
-	OSIZE,
-	OSTRING,
-	OLSTRING,
-	OSTRUCT,
-	OSUB,
-	OSWITCH,
-	OUNION,
-	OUSED,
-	OWHILE,
-	OXOR,
-	ONEG,
-	OCOM,
-	OPOS,
-	OELEM,
-
-	OTST,		/* used in some compilers */
-	OINDEX,
-	OFAS,
-	OREGPAIR,
-	OROTL,
-
-	OEND
-};
-enum
-{
-	TXXX,
-	TCHAR,
-	TUCHAR,
-	TSHORT,
-	TUSHORT,
-	TINT,
-	TUINT,
-	TLONG,
-	TULONG,
-	TVLONG,
-	TUVLONG,
-	TFLOAT,
-	TDOUBLE,
-	TIND,
-	TFUNC,
-	TARRAY,
-	TVOID,
-	TSTRUCT,
-	TUNION,
-	TENUM,
-	NTYPE,
-
-	TAUTO	= NTYPE,
-	TEXTERN,
-	TSTATIC,
-	TTYPEDEF,
-	TTYPESTR,
-	TREGISTER,
-	TCONSTNT,
-	TVOLATILE,
-	TUNSIGNED,
-	TSIGNED,
-	TDOT,
-	TFILE,
-	TOLD,
-	NALLTYPES,
-
-	/* adapt size of Rune to target system's size */
-	TRUNE = sizeof(TRune)==4? TUINT: TUSHORT,
-};
-enum
-{
-	CXXX,
-	CAUTO,
-	CEXTERN,
-	CGLOBL,
-	CSTATIC,
-	CLOCAL,
-	CTYPEDEF,
-	CTYPESTR,
-	CPARAM,
-	CSELEM,
-	CLABEL,
-	CEXREG,
-	NCTYPES,
-};
-enum
-{
-	GXXX		= 0,
-	GCONSTNT	= 1<<0,
-	GVOLATILE	= 1<<1,
-	NGTYPES		= 1<<2,
-
-	GINCOMPLETE	= 1<<2,
-};
-enum
-{
-	BCHAR		= 1L<<TCHAR,
-	BUCHAR		= 1L<<TUCHAR,
-	BSHORT		= 1L<<TSHORT,
-	BUSHORT		= 1L<<TUSHORT,
-	BINT		= 1L<<TINT,
-	BUINT		= 1L<<TUINT,
-	BLONG		= 1L<<TLONG,
-	BULONG		= 1L<<TULONG,
-	BVLONG		= 1L<<TVLONG,
-	BUVLONG		= 1L<<TUVLONG,
-	BFLOAT		= 1L<<TFLOAT,
-	BDOUBLE		= 1L<<TDOUBLE,
-	BIND		= 1L<<TIND,
-	BFUNC		= 1L<<TFUNC,
-	BARRAY		= 1L<<TARRAY,
-	BVOID		= 1L<<TVOID,
-	BSTRUCT		= 1L<<TSTRUCT,
-	BUNION		= 1L<<TUNION,
-	BENUM		= 1L<<TENUM,
-	BFILE		= 1L<<TFILE,
-	BDOT		= 1L<<TDOT,
-	BCONSTNT	= 1L<<TCONSTNT,
-	BVOLATILE	= 1L<<TVOLATILE,
-	BUNSIGNED	= 1L<<TUNSIGNED,
-	BSIGNED		= 1L<<TSIGNED,
-	BAUTO		= 1L<<TAUTO,
-	BEXTERN		= 1L<<TEXTERN,
-	BSTATIC		= 1L<<TSTATIC,
-	BTYPEDEF	= 1L<<TTYPEDEF,
-	BTYPESTR	= 1L<<TTYPESTR,
-	BREGISTER	= 1L<<TREGISTER,
-
-	BINTEGER	= BCHAR|BUCHAR|BSHORT|BUSHORT|BINT|BUINT|
-				BLONG|BULONG|BVLONG|BUVLONG,
-	BNUMBER		= BINTEGER|BFLOAT|BDOUBLE,
-
-/* these can be overloaded with complex types */
-
-	BCLASS		= BAUTO|BEXTERN|BSTATIC|BTYPEDEF|BTYPESTR|BREGISTER,
-	BGARB		= BCONSTNT|BVOLATILE,
-};
-
-struct	Funct
-{
-	Sym*	sym[OEND];
-	Sym*	castto[NTYPE];
-	Sym*	castfr[NTYPE];
-};
-
-EXTERN struct
-{
-	Type*	tenum;		/* type of entire enum */
-	Type*	cenum;		/* type of current enum run */
-	vlong	lastenum;	/* value of current enum */
-	double	floatenum;	/* value of current enum */
-} en;
-
-EXTERN	int	autobn;
-EXTERN	int32	autoffset;
-EXTERN	int	blockno;
-EXTERN	Decl*	dclstack;
-EXTERN	int	debug[256];
-EXTERN	int32	firstbit;
-EXTERN	Sym*	firstarg;
-EXTERN	Type*	firstargtype;
-EXTERN	Decl*	firstdcl;
-EXTERN	int	fperror;
-EXTERN	Sym*	hash[NHASH];
-EXTERN	char*	hunk;
-EXTERN	char**	include;
-EXTERN	Io*	iofree;
-EXTERN	Io*	ionext;
-EXTERN	Io*	iostack;
-EXTERN	int32	lastbit;
-EXTERN	char	lastclass;
-EXTERN	Type*	lastdcl;
-EXTERN	int32	lastfield;
-EXTERN	Type*	lasttype;
-EXTERN	int32	lineno;
-EXTERN	int32	nearln;
-EXTERN	int	nerrors;
-EXTERN	int	newflag;
-EXTERN	int32	nhunk;
-EXTERN	int	ninclude;
-EXTERN	Node*	nodproto;
-EXTERN	Node*	nodcast;
-EXTERN	int32	nsymb;
-EXTERN	Biobuf	outbuf;
-EXTERN	Biobuf	diagbuf;
-EXTERN	char*	outfile;
-EXTERN	int	peekc;
-EXTERN	int32	stkoff;
-EXTERN	Type*	strf;
-EXTERN	Type*	strl;
-EXTERN	char*	symb;
-EXTERN	Sym*	symstring;
-EXTERN	int	taggen;
-EXTERN	Type*	tfield;
-EXTERN	Type*	tufield;
-extern	int	thechar;
-extern	char*	thestring;
-extern	LinkArch*	thelinkarch;
-EXTERN	Type*	thisfn;
-EXTERN	int32	thunk;
-EXTERN	Type*	types[NALLTYPES];
-EXTERN	Type*	fntypes[NALLTYPES];
-EXTERN	Node*	initlist;
-EXTERN	Term	term[NTERM];
-EXTERN	int	nterm;
-EXTERN	int	packflg;
-EXTERN	int	fproundflg;
-EXTERN	int	textflag;
-EXTERN	int	dataflag;
-EXTERN	int	flag_largemodel;
-EXTERN	int	ncontin;
-EXTERN	int	canreach;
-EXTERN	int	warnreach;
-EXTERN	int	nacl;
-EXTERN	Bits	zbits;
-EXTERN	Fmt	pragcgobuf;
-EXTERN	Biobuf	bstdout;
-EXTERN	Var	var[NVAR];
-
-extern	char	*onames[], *tnames[], *gnames[];
-extern	char	*cnames[], *qnames[], *bnames[];
-extern	uchar	tab[NTYPE][NTYPE];
-extern	uchar	comrel[], invrel[], logrel[];
-extern	int32	ncast[], tadd[], tand[];
-extern	int32	targ[], tasadd[], tasign[], tcast[];
-extern	int32	tdot[], tfunct[], tindir[], tmul[];
-extern	int32	tnot[], trel[], tsub[];
-
-extern	uchar	typeaf[];
-extern	uchar	typefd[];
-extern	uchar	typei[];
-extern	uchar	typesu[];
-extern	uchar	typesuv[];
-extern	uchar	typeu[];
-extern	uchar	typev[];
-extern	uchar	typec[];
-extern	uchar	typeh[];
-extern	uchar	typeil[];
-extern	uchar	typeilp[];
-extern	uchar	typechl[];
-extern	uchar	typechlv[];
-extern	uchar	typechlvp[];
-extern	uchar	typechlp[];
-extern	uchar	typechlpfd[];
-
-EXTERN	uchar*	typeword;
-EXTERN	uchar*	typecmplx;
-EXTERN	Link*	ctxt;
-
-extern	uint32	thash1;
-extern	uint32	thash2;
-extern	uint32	thash3;
-extern	uint32	thash[];
-
-/*
- *	compat.c/unix.c/windows.c
- */
-int	systemtype(int);
-int	pathchar(void);
-
-/*
- *	parser
- */
-int	yyparse(void);
-int	mpatov(char*, vlong*);
-
-/*
- *	lex.c
- */
-void*	allocn(void*, int32, int32);
-void*	alloc(int32);
-void    ensuresymb(int32);
-void	cinit(void);
-int	compile(char*, char**, int);
-void	errorexit(void);
-int	filbuf(void);
-int	getc(void);
-int32	getr(void);
-int	getnsc(void);
-Sym*	lookup(void);
-void	main(int, char*[]);
-void	newfile(char*, int);
-void	newio(void);
-void	pushio(void);
-int32	escchar(int32, int, int);
-Sym*	slookup(char*);
-void	syminit(Sym*);
-void	unget(int);
-int32	yylex(void);
-int	Lconv(Fmt*);
-int	Tconv(Fmt*);
-int	FNconv(Fmt*);
-int	Oconv(Fmt*);
-int	Qconv(Fmt*);
-int	VBconv(Fmt*);
-int	Bconv(Fmt*);
-void	setinclude(char*);
-
-/*
- * mac.c
- */
-void	dodefine(char*);
-void	domacro(void);
-Sym*	getsym(void);
-int32	getnsn(void);
-void	macdef(void);
-void	macprag(void);
-void	macend(void);
-void	macexpand(Sym*, char*);
-void	macif(int);
-void	macinc(void);
-void	maclin(void);
-void	macund(void);
-
-/*
- * dcl.c
- */
-Node*	doinit(Sym*, Type*, int32, Node*);
-Type*	tcopy(Type*);
-Node*	init1(Sym*, Type*, int32, int);
-Node*	newlist(Node*, Node*);
-void	adecl(int, Type*, Sym*);
-int	anyproto(Node*);
-void	argmark(Node*, int);
-void	dbgdecl(Sym*);
-Node*	dcllabel(Sym*, int);
-Node*	dodecl(void(*)(int, Type*, Sym*), int, Type*, Node*);
-Sym*	mkstatic(Sym*);
-void	doenum(Sym*, Node*);
-void	snap(Type*);
-Type*	dotag(Sym*, int, int);
-void	edecl(int, Type*, Sym*);
-Type*	fnproto(Node*);
-Type*	fnproto1(Node*);
-void	markdcl(void);
-Type*	paramconv(Type*, int);
-void	pdecl(int, Type*, Sym*);
-Decl*	push(void);
-Decl*	push1(Sym*);
-Node*	revertdcl(void);
-int32	xround(int32, int);
-int	rsametype(Type*, Type*, int, int);
-int	sametype(Type*, Type*);
-uint32	sign(Sym*);
-uint32	signature(Type*);
-void	sualign(Type*);
-void	tmerge(Type*, Sym*);
-void	walkparam(Node*, int);
-void	xdecl(int, Type*, Sym*);
-Node*	contig(Sym*, Node*, int32);
-
-/*
- * com.c
- */
-void	ccom(Node*);
-void	complex(Node*);
-int	tcom(Node*);
-int	tcoma(Node*, Node*, Type*, int);
-int	tcomd(Node*);
-int	tcomo(Node*, int);
-int	tcomx(Node*);
-int	tlvalue(Node*);
-void	constas(Node*, Type*, Type*);
-
-/*
- * con.c
- */
-void	acom(Node*);
-void	acom1(vlong, Node*);
-void	acom2(Node*, Type*);
-int	acomcmp1(const void*, const void*);
-int	acomcmp2(const void*, const void*);
-int	addo(Node*);
-void	evconst(Node*);
-
-/*
- * funct.c
- */
-int	isfunct(Node*);
-void	dclfunct(Type*, Sym*);
-
-/*
- * sub.c
- */
-void	arith(Node*, int);
-int	deadheads(Node*);
-Type*	dotsearch(Sym*, Type*, Node*, int32*);
-int32	dotoffset(Type*, Type*, Node*);
-void	gethunk(void);
-Node*	invert(Node*);
-int	bitno(int32);
-void	makedot(Node*, Type*, int32);
-int	mixedasop(Type*, Type*);
-Node*	new(int, Node*, Node*);
-Node*	new1(int, Node*, Node*);
-int	nilcast(Type*, Type*);
-int	nocast(Type*, Type*);
-void	prtree(Node*, char*);
-void	prtree1(Node*, int, int);
-void	relcon(Node*, Node*);
-int	relindex(int);
-int	simpleg(int32);
-Type*	garbt(Type*, int32);
-int	simplec(int32);
-Type*	simplet(int32);
-int	stcompat(Node*, Type*, Type*, int32[]);
-int	tcompat(Node*, Type*, Type*, int32[]);
-void	tinit(void);
-Type*	typ(int, Type*);
-Type*	copytyp(Type*);
-void	typeext(Type*, Node*);
-void	typeext1(Type*, Node*);
-int	side(Node*);
-int	vconst(Node*);
-int	xlog2(uvlong);
-int	vlog(Node*);
-int	topbit(uint32);
-void	simplifyshift(Node*);
-int32	typebitor(int32, int32);
-void	diag(Node*, char*, ...);
-void	warn(Node*, char*, ...);
-void	yyerror(char*, ...);
-void	fatal(Node*, char*, ...);
-LSym*	linksym(Sym*);
-
-/*
- * acid.c
- */
-void	acidtype(Type*);
-void	acidvar(Sym*);
-
-/*
- * godefs.c
- */
-int	Uconv(Fmt*);
-void	godeftype(Type*);
-void	godefvar(Sym*);
-
-/*
- * bits.c
- */
-Bits	bor(Bits, Bits);
-Bits	band(Bits, Bits);
-Bits	bnot(Bits);
-int	bany(Bits*);
-int	bnum(Bits);
-Bits	blsh(uint);
-int	beq(Bits, Bits);
-int	bset(Bits, uint);
-
-/*
- * dpchk.c
- */
-void	dpcheck(Node*);
-void	arginit(void);
-void	pragvararg(void);
-void	pragpack(void);
-void	pragfpround(void);
-void	pragdataflag(void);
-void	pragtextflag(void);
-void	pragincomplete(void);
-void	pragcgo(char*);
-
-/*
- * calls to machine depend part
- */
-void	codgen(Node*, Node*);
-void	gclean(void);
-void	gextern(Sym*, Node*, int32, int32);
-void	ginit(void);
-int32	outstring(char*, int32);
-int32	outlstring(TRune*, int32);
-void	sextern(Sym*, Node*, int32, int32);
-void	xcom(Node*);
-int32	exreg(Type*);
-int32	align(int32, Type*, int, int32*);
-int32	maxround(int32, int32);
-int	hasdotdotdot(Type*);
-void    linkarchinit(void);
-
-extern	schar	ewidth[];
-
-/*
- * com64
- */
-int	com64(Node*);
-void	com64init(void);
-void	bool64(Node*);
-double	convvtof(vlong);
-vlong	convftov(double);
-double	convftox(double, int);
-vlong	convvtox(vlong, int);
-
-/*
- * machcap
- */
-int	machcap(Node*);
-
-#pragma	varargck	argpos	warn	2
-#pragma	varargck	argpos	diag	2
-#pragma	varargck	argpos	yyerror	1
-
-#pragma	varargck	type	"B"	Bits
-#pragma	varargck	type	"F"	Node*
-#pragma	varargck	type	"L"	int32
-#pragma	varargck	type	"Q"	int32
-#pragma	varargck	type	"O"	int
-#pragma	varargck	type	"O"	uint
-#pragma	varargck	type	"T"	Type*
-#pragma	varargck	type	"U"	char*
-#pragma	varargck	type	"|"	int
-
-enum
-{
-	Plan9	= 1<<0,
-	Unix	= 1<<1,
-	Windows	= 1<<2,
-};
-int	pathchar(void);
-int	systemtype(int);
-void*	alloc(int32 n);
-void*	allocn(void*, int32, int32);
diff --git a/src/cmd/cc/cc.y b/src/cmd/cc/cc.y
deleted file mode 100644
index 8d7cb14..0000000
--- a/src/cmd/cc/cc.y
+++ /dev/null
@@ -1,1220 +0,0 @@
-// Inferno utils/cc/cc.y
-// http://code.google.com/p/inferno-os/source/browse/utils/cc/cc.y
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-%{
-#include <u.h>
-#include <stdio.h>	/* if we don't, bison will, and cc.h re-#defines getc */
-#include "cc.h"
-%}
-%union	{
-	Node*	node;
-	Sym*	sym;
-	Type*	type;
-	struct
-	{
-		Type*	t;
-		uchar	c;
-	} tycl;
-	struct
-	{
-		Type*	t1;
-		Type*	t2;
-		Type*	t3;
-		uchar	c;
-	} tyty;
-	struct
-	{
-		char*	s;
-		int32	l;
-	} sval;
-	int32	lval;
-	double	dval;
-	vlong	vval;
-}
-%type	<sym>	ltag
-%type	<lval>	gctname gcname cname gname tname
-%type	<lval>	gctnlist gcnlist zgnlist
-%type	<type>	tlist sbody complex
-%type	<tycl>	types
-%type	<node>	zarglist arglist zcexpr
-%type	<node>	name block stmnt cexpr expr xuexpr pexpr
-%type	<node>	zelist elist adecl slist uexpr string lstring
-%type	<node>	xdecor xdecor2 labels label ulstmnt
-%type	<node>	adlist edecor tag qual qlist
-%type	<node>	abdecor abdecor1 abdecor2 abdecor3
-%type	<node>	zexpr lexpr init ilist forexpr
-
-%left	';'
-%left	','
-%right	'=' LPE LME LMLE LDVE LMDE LRSHE LLSHE LANDE LXORE LORE
-%right	'?' ':'
-%left	LOROR
-%left	LANDAND
-%left	'|'
-%left	'^'
-%left	'&'
-%left	LEQ LNE
-%left	'<' '>' LLE LGE
-%left	LLSH LRSH
-%left	'+' '-'
-%left	'*' '/' '%'
-%right	LMM LPP LMG '.' '[' '('
-
-%token	<sym>	LNAME LTYPE
-%token	<dval>	LFCONST LDCONST
-%token	<vval>	LCONST LLCONST LUCONST LULCONST LVLCONST LUVLCONST
-%token	<sval>	LSTRING LLSTRING
-%token		LAUTO LBREAK LCASE LCHAR LCONTINUE LDEFAULT LDO
-%token		LDOUBLE LELSE LEXTERN LFLOAT LFOR LGOTO
-%token	LIF LINT LLONG LPREFETCH LREGISTER LRETURN LSHORT LSIZEOF LUSED
-%token	LSTATIC LSTRUCT LSWITCH LTYPEDEF LTYPESTR LUNION LUNSIGNED
-%token	LWHILE LVOID LENUM LSIGNED LCONSTNT LVOLATILE LSET LSIGNOF
-%token	LRESTRICT LINLINE
-%%
-prog:
-|	prog xdecl
-
-/*
- * external declarator
- */
-xdecl:
-	zctlist ';'
-	{
-		dodecl(xdecl, lastclass, lasttype, Z);
-	}
-|	zctlist xdlist ';'
-|	zctlist xdecor
-	{
-		lastdcl = T;
-		firstarg = S;
-		dodecl(xdecl, lastclass, lasttype, $2);
-		if(lastdcl == T || lastdcl->etype != TFUNC) {
-			diag($2, "not a function");
-			lastdcl = types[TFUNC];
-		}
-		thisfn = lastdcl;
-		markdcl();
-		firstdcl = dclstack;
-		argmark($2, 0);
-	}
-	pdecl
-	{
-		argmark($2, 1);
-	}
-	block
-	{
-		Node *n;
-
-		n = revertdcl();
-		if(n)
-			$6 = new(OLIST, n, $6);
-		if(!debug['a'] && !debug['Z'])
-			codgen($6, $2);
-	}
-
-xdlist:
-	xdecor
-	{
-		dodecl(xdecl, lastclass, lasttype, $1);
-	}
-|	xdecor
-	{
-		$1 = dodecl(xdecl, lastclass, lasttype, $1);
-	}
-	'=' init
-	{
-		doinit($1->sym, $1->type, 0L, $4);
-	}
-|	xdlist ',' xdlist
-
-xdecor:
-	xdecor2
-|	'*' zgnlist xdecor
-	{
-		$$ = new(OIND, $3, Z);
-		$$->garb = simpleg($2);
-	}
-
-xdecor2:
-	tag
-|	'(' xdecor ')'
-	{
-		$$ = $2;
-	}
-|	xdecor2 '(' zarglist ')'
-	{
-		$$ = new(OFUNC, $1, $3);
-	}
-|	xdecor2 '[' zexpr ']'
-	{
-		$$ = new(OARRAY, $1, $3);
-	}
-
-/*
- * automatic declarator
- */
-adecl:
-	ctlist ';'
-	{
-		$$ = dodecl(adecl, lastclass, lasttype, Z);
-	}
-|	ctlist adlist ';'
-	{
-		$$ = $2;
-	}
-
-adlist:
-	xdecor
-	{
-		dodecl(adecl, lastclass, lasttype, $1);
-		$$ = Z;
-	}
-|	xdecor
-	{
-		$1 = dodecl(adecl, lastclass, lasttype, $1);
-	}
-	'=' init
-	{
-		int32 w;
-
-		w = $1->sym->type->width;
-		$$ = doinit($1->sym, $1->type, 0L, $4);
-		$$ = contig($1->sym, $$, w);
-	}
-|	adlist ',' adlist
-	{
-		$$ = $1;
-		if($3 != Z) {
-			$$ = $3;
-			if($1 != Z)
-				$$ = new(OLIST, $1, $3);
-		}
-	}
-
-/*
- * parameter declarator
- */
-pdecl:
-|	pdecl ctlist pdlist ';'
-
-pdlist:
-	xdecor
-	{
-		dodecl(pdecl, lastclass, lasttype, $1);
-	}
-|	pdlist ',' pdlist
-
-/*
- * structure element declarator
- */
-edecl:
-	tlist
-	{
-		lasttype = $1;
-	}
-	zedlist ';'
-|	edecl tlist
-	{
-		lasttype = $2;
-	}
-	zedlist ';'
-
-zedlist:					/* extension */
-	{
-		lastfield = 0;
-		edecl(CXXX, lasttype, S);
-	}
-|	edlist
-
-edlist:
-	edecor
-	{
-		dodecl(edecl, CXXX, lasttype, $1);
-	}
-|	edlist ',' edlist
-
-edecor:
-	xdecor
-	{
-		lastbit = 0;
-		firstbit = 1;
-	}
-|	tag ':' lexpr
-	{
-		$$ = new(OBIT, $1, $3);
-	}
-|	':' lexpr
-	{
-		$$ = new(OBIT, Z, $2);
-	}
-
-/*
- * abstract declarator
- */
-abdecor:
-	{
-		$$ = (Z);
-	}
-|	abdecor1
-
-abdecor1:
-	'*' zgnlist
-	{
-		$$ = new(OIND, (Z), Z);
-		$$->garb = simpleg($2);
-	}
-|	'*' zgnlist abdecor1
-	{
-		$$ = new(OIND, $3, Z);
-		$$->garb = simpleg($2);
-	}
-|	abdecor2
-
-abdecor2:
-	abdecor3
-|	abdecor2 '(' zarglist ')'
-	{
-		$$ = new(OFUNC, $1, $3);
-	}
-|	abdecor2 '[' zexpr ']'
-	{
-		$$ = new(OARRAY, $1, $3);
-	}
-
-abdecor3:
-	'(' ')'
-	{
-		$$ = new(OFUNC, (Z), Z);
-	}
-|	'[' zexpr ']'
-	{
-		$$ = new(OARRAY, (Z), $2);
-	}
-|	'(' abdecor1 ')'
-	{
-		$$ = $2;
-	}
-
-init:
-	expr
-|	'{' ilist '}'
-	{
-		$$ = new(OINIT, invert($2), Z);
-	}
-
-qual:
-	'[' lexpr ']'
-	{
-		$$ = new(OARRAY, $2, Z);
-	}
-|	'.' ltag
-	{
-		$$ = new(OELEM, Z, Z);
-		$$->sym = $2;
-	}
-|	qual '='
-
-qlist:
-	init ','
-|	qlist init ','
-	{
-		$$ = new(OLIST, $1, $2);
-	}
-|	qual
-|	qlist qual
-	{
-		$$ = new(OLIST, $1, $2);
-	}
-
-ilist:
-	qlist
-|	init
-|	qlist init
-	{
-		$$ = new(OLIST, $1, $2);
-	}
-
-zarglist:
-	{
-		$$ = Z;
-	}
-|	arglist
-	{
-		$$ = invert($1);
-	}
-
-
-arglist:
-	name
-|	tlist abdecor
-	{
-		$$ = new(OPROTO, $2, Z);
-		$$->type = $1;
-	}
-|	tlist xdecor
-	{
-		$$ = new(OPROTO, $2, Z);
-		$$->type = $1;
-	}
-|	'.' '.' '.'
-	{
-		$$ = new(ODOTDOT, Z, Z);
-	}
-|	arglist ',' arglist
-	{
-		$$ = new(OLIST, $1, $3);
-	}
-
-block:
-	'{' slist '}'
-	{
-		$$ = invert($2);
-	//	if($2 != Z)
-	//		$$ = new(OLIST, $2, $$);
-		if($$ == Z)
-			$$ = new(OLIST, Z, Z);
-	}
-
-slist:
-	{
-		$$ = Z;
-	}
-|	slist adecl
-	{
-		$$ = new(OLIST, $1, $2);
-	}
-|	slist stmnt
-	{
-		$$ = new(OLIST, $1, $2);
-	}
-
-labels:
-	label
-|	labels label
-	{
-		$$ = new(OLIST, $1, $2);
-	}
-
-label:
-	LCASE expr ':'
-	{
-		$$ = new(OCASE, $2, Z);
-	}
-|	LDEFAULT ':'
-	{
-		$$ = new(OCASE, Z, Z);
-	}
-|	LNAME ':'
-	{
-		$$ = new(OLABEL, dcllabel($1, 1), Z);
-	}
-
-stmnt:
-	error ';'
-	{
-		$$ = Z;
-	}
-|	ulstmnt
-|	labels ulstmnt
-	{
-		$$ = new(OLIST, $1, $2);
-	}
-
-forexpr:
-	zcexpr
-|	ctlist adlist
-	{
-		$$ = $2;
-	}
-
-ulstmnt:
-	zcexpr ';'
-|	{
-		markdcl();
-	}
-	block
-	{
-		$$ = revertdcl();
-		if($$)
-			$$ = new(OLIST, $$, $2);
-		else
-			$$ = $2;
-	}
-|	LIF '(' cexpr ')' stmnt
-	{
-		$$ = new(OIF, $3, new(OLIST, $5, Z));
-		if($5 == Z)
-			warn($3, "empty if body");
-	}
-|	LIF '(' cexpr ')' stmnt LELSE stmnt
-	{
-		$$ = new(OIF, $3, new(OLIST, $5, $7));
-		if($5 == Z)
-			warn($3, "empty if body");
-		if($7 == Z)
-			warn($3, "empty else body");
-	}
-|	{ markdcl(); } LFOR '(' forexpr ';' zcexpr ';' zcexpr ')' stmnt
-	{
-		$$ = revertdcl();
-		if($$){
-			if($4)
-				$4 = new(OLIST, $$, $4);
-			else
-				$4 = $$;
-		}
-		$$ = new(OFOR, new(OLIST, $6, new(OLIST, $4, $8)), $10);
-	}
-|	LWHILE '(' cexpr ')' stmnt
-	{
-		$$ = new(OWHILE, $3, $5);
-	}
-|	LDO stmnt LWHILE '(' cexpr ')' ';'
-	{
-		$$ = new(ODWHILE, $5, $2);
-	}
-|	LRETURN zcexpr ';'
-	{
-		$$ = new(ORETURN, $2, Z);
-		$$->type = thisfn->link;
-	}
-|	LSWITCH '(' cexpr ')' stmnt
-	{
-		$$ = new(OCONST, Z, Z);
-		$$->vconst = 0;
-		$$->type = types[TINT];
-		$3 = new(OSUB, $$, $3);
-
-		$$ = new(OCONST, Z, Z);
-		$$->vconst = 0;
-		$$->type = types[TINT];
-		$3 = new(OSUB, $$, $3);
-
-		$$ = new(OSWITCH, $3, $5);
-	}
-|	LBREAK ';'
-	{
-		$$ = new(OBREAK, Z, Z);
-	}
-|	LCONTINUE ';'
-	{
-		$$ = new(OCONTINUE, Z, Z);
-	}
-|	LGOTO ltag ';'
-	{
-		$$ = new(OGOTO, dcllabel($2, 0), Z);
-	}
-|	LUSED '(' zelist ')' ';'
-	{
-		$$ = new(OUSED, $3, Z);
-	}
-|	LPREFETCH '(' zelist ')' ';'
-	{
-		$$ = new(OPREFETCH, $3, Z);
-	}
-|	LSET '(' zelist ')' ';'
-	{
-		$$ = new(OSET, $3, Z);
-	}
-
-zcexpr:
-	{
-		$$ = Z;
-	}
-|	cexpr
-
-zexpr:
-	{
-		$$ = Z;
-	}
-|	lexpr
-
-lexpr:
-	expr
-	{
-		$$ = new(OCAST, $1, Z);
-		$$->type = types[TLONG];
-	}
-
-cexpr:
-	expr
-|	cexpr ',' cexpr
-	{
-		$$ = new(OCOMMA, $1, $3);
-	}
-
-expr:
-	xuexpr
-|	expr '*' expr
-	{
-		$$ = new(OMUL, $1, $3);
-	}
-|	expr '/' expr
-	{
-		$$ = new(ODIV, $1, $3);
-	}
-|	expr '%' expr
-	{
-		$$ = new(OMOD, $1, $3);
-	}
-|	expr '+' expr
-	{
-		$$ = new(OADD, $1, $3);
-	}
-|	expr '-' expr
-	{
-		$$ = new(OSUB, $1, $3);
-	}
-|	expr LRSH expr
-	{
-		$$ = new(OASHR, $1, $3);
-	}
-|	expr LLSH expr
-	{
-		$$ = new(OASHL, $1, $3);
-	}
-|	expr '<' expr
-	{
-		$$ = new(OLT, $1, $3);
-	}
-|	expr '>' expr
-	{
-		$$ = new(OGT, $1, $3);
-	}
-|	expr LLE expr
-	{
-		$$ = new(OLE, $1, $3);
-	}
-|	expr LGE expr
-	{
-		$$ = new(OGE, $1, $3);
-	}
-|	expr LEQ expr
-	{
-		$$ = new(OEQ, $1, $3);
-	}
-|	expr LNE expr
-	{
-		$$ = new(ONE, $1, $3);
-	}
-|	expr '&' expr
-	{
-		$$ = new(OAND, $1, $3);
-	}
-|	expr '^' expr
-	{
-		$$ = new(OXOR, $1, $3);
-	}
-|	expr '|' expr
-	{
-		$$ = new(OOR, $1, $3);
-	}
-|	expr LANDAND expr
-	{
-		$$ = new(OANDAND, $1, $3);
-	}
-|	expr LOROR expr
-	{
-		$$ = new(OOROR, $1, $3);
-	}
-|	expr '?' cexpr ':' expr
-	{
-		$$ = new(OCOND, $1, new(OLIST, $3, $5));
-	}
-|	expr '=' expr
-	{
-		$$ = new(OAS, $1, $3);
-	}
-|	expr LPE expr
-	{
-		$$ = new(OASADD, $1, $3);
-	}
-|	expr LME expr
-	{
-		$$ = new(OASSUB, $1, $3);
-	}
-|	expr LMLE expr
-	{
-		$$ = new(OASMUL, $1, $3);
-	}
-|	expr LDVE expr
-	{
-		$$ = new(OASDIV, $1, $3);
-	}
-|	expr LMDE expr
-	{
-		$$ = new(OASMOD, $1, $3);
-	}
-|	expr LLSHE expr
-	{
-		$$ = new(OASASHL, $1, $3);
-	}
-|	expr LRSHE expr
-	{
-		$$ = new(OASASHR, $1, $3);
-	}
-|	expr LANDE expr
-	{
-		$$ = new(OASAND, $1, $3);
-	}
-|	expr LXORE expr
-	{
-		$$ = new(OASXOR, $1, $3);
-	}
-|	expr LORE expr
-	{
-		$$ = new(OASOR, $1, $3);
-	}
-
-xuexpr:
-	uexpr
-|	'(' tlist abdecor ')' xuexpr
-	{
-		$$ = new(OCAST, $5, Z);
-		dodecl(NODECL, CXXX, $2, $3);
-		$$->type = lastdcl;
-		$$->xcast = 1;
-	}
-|	'(' tlist abdecor ')' '{' ilist '}'	/* extension */
-	{
-		$$ = new(OSTRUCT, $6, Z);
-		dodecl(NODECL, CXXX, $2, $3);
-		$$->type = lastdcl;
-	}
-
-uexpr:
-	pexpr
-|	'*' xuexpr
-	{
-		$$ = new(OIND, $2, Z);
-	}
-|	'&' xuexpr
-	{
-		$$ = new(OADDR, $2, Z);
-	}
-|	'+' xuexpr
-	{
-		$$ = new(OPOS, $2, Z);
-	}
-|	'-' xuexpr
-	{
-		$$ = new(ONEG, $2, Z);
-	}
-|	'!' xuexpr
-	{
-		$$ = new(ONOT, $2, Z);
-	}
-|	'~' xuexpr
-	{
-		$$ = new(OCOM, $2, Z);
-	}
-|	LPP xuexpr
-	{
-		$$ = new(OPREINC, $2, Z);
-	}
-|	LMM xuexpr
-	{
-		$$ = new(OPREDEC, $2, Z);
-	}
-|	LSIZEOF uexpr
-	{
-		$$ = new(OSIZE, $2, Z);
-	}
-|	LSIGNOF uexpr
-	{
-		$$ = new(OSIGN, $2, Z);
-	}
-
-pexpr:
-	'(' cexpr ')'
-	{
-		$$ = $2;
-	}
-|	LSIZEOF '(' tlist abdecor ')'
-	{
-		$$ = new(OSIZE, Z, Z);
-		dodecl(NODECL, CXXX, $3, $4);
-		$$->type = lastdcl;
-	}
-|	LSIGNOF '(' tlist abdecor ')'
-	{
-		$$ = new(OSIGN, Z, Z);
-		dodecl(NODECL, CXXX, $3, $4);
-		$$->type = lastdcl;
-	}
-|	pexpr '(' zelist ')'
-	{
-		$$ = new(OFUNC, $1, Z);
-		if($1->op == ONAME)
-		if($1->type == T)
-			dodecl(xdecl, CXXX, types[TINT], $$);
-		$$->right = invert($3);
-	}
-|	pexpr '[' cexpr ']'
-	{
-		$$ = new(OIND, new(OADD, $1, $3), Z);
-	}
-|	pexpr LMG ltag
-	{
-		$$ = new(ODOT, new(OIND, $1, Z), Z);
-		$$->sym = $3;
-	}
-|	pexpr '.' ltag
-	{
-		$$ = new(ODOT, $1, Z);
-		$$->sym = $3;
-	}
-|	pexpr LPP
-	{
-		$$ = new(OPOSTINC, $1, Z);
-	}
-|	pexpr LMM
-	{
-		$$ = new(OPOSTDEC, $1, Z);
-	}
-|	name
-|	LCONST
-	{
-		$$ = new(OCONST, Z, Z);
-		$$->type = types[TINT];
-		$$->vconst = $1;
-		$$->cstring = strdup(symb);
-	}
-|	LLCONST
-	{
-		$$ = new(OCONST, Z, Z);
-		$$->type = types[TLONG];
-		$$->vconst = $1;
-		$$->cstring = strdup(symb);
-	}
-|	LUCONST
-	{
-		$$ = new(OCONST, Z, Z);
-		$$->type = types[TUINT];
-		$$->vconst = $1;
-		$$->cstring = strdup(symb);
-	}
-|	LULCONST
-	{
-		$$ = new(OCONST, Z, Z);
-		$$->type = types[TULONG];
-		$$->vconst = $1;
-		$$->cstring = strdup(symb);
-	}
-|	LDCONST
-	{
-		$$ = new(OCONST, Z, Z);
-		$$->type = types[TDOUBLE];
-		$$->fconst = $1;
-		$$->cstring = strdup(symb);
-	}
-|	LFCONST
-	{
-		$$ = new(OCONST, Z, Z);
-		$$->type = types[TFLOAT];
-		$$->fconst = $1;
-		$$->cstring = strdup(symb);
-	}
-|	LVLCONST
-	{
-		$$ = new(OCONST, Z, Z);
-		$$->type = types[TVLONG];
-		$$->vconst = $1;
-		$$->cstring = strdup(symb);
-	}
-|	LUVLCONST
-	{
-		$$ = new(OCONST, Z, Z);
-		$$->type = types[TUVLONG];
-		$$->vconst = $1;
-		$$->cstring = strdup(symb);
-	}
-|	string
-|	lstring
-
-string:
-	LSTRING
-	{
-		$$ = new(OSTRING, Z, Z);
-		$$->type = typ(TARRAY, types[TCHAR]);
-		$$->type->width = $1.l + 1;
-		$$->cstring = $1.s;
-		$$->sym = symstring;
-		$$->etype = TARRAY;
-		$$->class = CSTATIC;
-	}
-|	string LSTRING
-	{
-		char *s;
-		int n;
-
-		n = $1->type->width - 1;
-		s = alloc(n+$2.l+MAXALIGN);
-
-		memcpy(s, $1->cstring, n);
-		memcpy(s+n, $2.s, $2.l);
-		s[n+$2.l] = 0;
-
-		$$ = $1;
-		$$->type->width += $2.l;
-		$$->cstring = s;
-	}
-
-lstring:
-	LLSTRING
-	{
-		$$ = new(OLSTRING, Z, Z);
-		$$->type = typ(TARRAY, types[TRUNE]);
-		$$->type->width = $1.l + sizeof(TRune);
-		$$->rstring = (TRune*)$1.s;
-		$$->sym = symstring;
-		$$->etype = TARRAY;
-		$$->class = CSTATIC;
-	}
-|	lstring LLSTRING
-	{
-		char *s;
-		int n;
-
-		n = $1->type->width - sizeof(TRune);
-		s = alloc(n+$2.l+MAXALIGN);
-
-		memcpy(s, $1->rstring, n);
-		memcpy(s+n, $2.s, $2.l);
-		*(TRune*)(s+n+$2.l) = 0;
-
-		$$ = $1;
-		$$->type->width += $2.l;
-		$$->rstring = (TRune*)s;
-	}
-
-zelist:
-	{
-		$$ = Z;
-	}
-|	elist
-
-elist:
-	expr
-|	elist ',' elist
-	{
-		$$ = new(OLIST, $1, $3);
-	}
-
-sbody:
-	'{'
-	{
-		$<tyty>$.t1 = strf;
-		$<tyty>$.t2 = strl;
-		$<tyty>$.t3 = lasttype;
-		$<tyty>$.c = lastclass;
-		strf = T;
-		strl = T;
-		lastbit = 0;
-		firstbit = 1;
-		lastclass = CXXX;
-		lasttype = T;
-	}
-	edecl '}'
-	{
-		$$ = strf;
-		strf = $<tyty>2.t1;
-		strl = $<tyty>2.t2;
-		lasttype = $<tyty>2.t3;
-		lastclass = $<tyty>2.c;
-	}
-
-zctlist:
-	{
-		lastclass = CXXX;
-		lasttype = types[TINT];
-	}
-|	ctlist
-
-types:
-	complex
-	{
-		$$.t = $1;
-		$$.c = CXXX;
-	}
-|	tname
-	{
-		$$.t = simplet($1);
-		$$.c = CXXX;
-	}
-|	gcnlist
-	{
-		$$.t = simplet($1);
-		$$.c = simplec($1);
-		$$.t = garbt($$.t, $1);
-	}
-|	complex gctnlist
-	{
-		$$.t = $1;
-		$$.c = simplec($2);
-		$$.t = garbt($$.t, $2);
-		if($2 & ~BCLASS & ~BGARB)
-			diag(Z, "duplicate types given: %T and %Q", $1, $2);
-	}
-|	tname gctnlist
-	{
-		$$.t = simplet(typebitor($1, $2));
-		$$.c = simplec($2);
-		$$.t = garbt($$.t, $2);
-	}
-|	gcnlist complex zgnlist
-	{
-		$$.t = $2;
-		$$.c = simplec($1);
-		$$.t = garbt($$.t, $1|$3);
-	}
-|	gcnlist tname
-	{
-		$$.t = simplet($2);
-		$$.c = simplec($1);
-		$$.t = garbt($$.t, $1);
-	}
-|	gcnlist tname gctnlist
-	{
-		$$.t = simplet(typebitor($2, $3));
-		$$.c = simplec($1|$3);
-		$$.t = garbt($$.t, $1|$3);
-	}
-
-tlist:
-	types
-	{
-		$$ = $1.t;
-		if($1.c != CXXX)
-			diag(Z, "illegal combination of class 4: %s", cnames[$1.c]);
-	}
-
-ctlist:
-	types
-	{
-		lasttype = $1.t;
-		lastclass = $1.c;
-	}
-
-complex:
-	LSTRUCT ltag
-	{
-		dotag($2, TSTRUCT, 0);
-		$$ = $2->suetag;
-	}
-|	LSTRUCT ltag
-	{
-		dotag($2, TSTRUCT, autobn);
-	}
-	sbody
-	{
-		$$ = $2->suetag;
-		if($$->link != T)
-			diag(Z, "redeclare tag: %s", $2->name);
-		$$->link = $4;
-		sualign($$);
-	}
-|	LSTRUCT sbody
-	{
-		diag(Z, "struct must have tag");
-		taggen++;
-		sprint(symb, "_%d_", taggen);
-		$$ = dotag(lookup(), TSTRUCT, autobn);
-		$$->link = $2;
-		sualign($$);
-	}
-|	LUNION ltag
-	{
-		dotag($2, TUNION, 0);
-		$$ = $2->suetag;
-	}
-|	LUNION ltag
-	{
-		dotag($2, TUNION, autobn);
-	}
-	sbody
-	{
-		$$ = $2->suetag;
-		if($$->link != T)
-			diag(Z, "redeclare tag: %s", $2->name);
-		$$->link = $4;
-		sualign($$);
-	}
-|	LUNION sbody
-	{
-		taggen++;
-		sprint(symb, "_%d_", taggen);
-		$$ = dotag(lookup(), TUNION, autobn);
-		$$->link = $2;
-		sualign($$);
-	}
-|	LENUM ltag
-	{
-		dotag($2, TENUM, 0);
-		$$ = $2->suetag;
-		if($$->link == T)
-			$$->link = types[TINT];
-		$$ = $$->link;
-	}
-|	LENUM ltag
-	{
-		dotag($2, TENUM, autobn);
-	}
-	'{'
-	{
-		en.tenum = T;
-		en.cenum = T;
-	}
-	enum '}'
-	{
-		$$ = $2->suetag;
-		if($$->link != T)
-			diag(Z, "redeclare tag: %s", $2->name);
-		if(en.tenum == T) {
-			diag(Z, "enum type ambiguous: %s", $2->name);
-			en.tenum = types[TINT];
-		}
-		$$->link = en.tenum;
-		$$ = en.tenum;
-	}
-|	LENUM '{'
-	{
-		en.tenum = T;
-		en.cenum = T;
-	}
-	enum '}'
-	{
-		$$ = en.tenum;
-	}
-|	LTYPE
-	{
-		$$ = tcopy($1->type);
-	}
-
-gctnlist:
-	gctname
-|	gctnlist gctname
-	{
-		$$ = typebitor($1, $2);
-	}
-
-zgnlist:
-	{
-		$$ = 0;
-	}
-|	zgnlist gname
-	{
-		$$ = typebitor($1, $2);
-	}
-
-gctname:
-	tname
-|	gname
-|	cname
-
-gcnlist:
-	gcname
-|	gcnlist gcname
-	{
-		$$ = typebitor($1, $2);
-	}
-
-gcname:
-	gname
-|	cname
-
-enum:
-	LNAME
-	{
-		doenum($1, Z);
-	}
-|	LNAME '=' expr
-	{
-		doenum($1, $3);
-	}
-|	enum ','
-|	enum ',' enum
-
-tname:	/* type words */
-	LCHAR { $$ = BCHAR; }
-|	LSHORT { $$ = BSHORT; }
-|	LINT { $$ = BINT; }
-|	LLONG { $$ = BLONG; }
-|	LSIGNED { $$ = BSIGNED; }
-|	LUNSIGNED { $$ = BUNSIGNED; }
-|	LFLOAT { $$ = BFLOAT; }
-|	LDOUBLE { $$ = BDOUBLE; }
-|	LVOID { $$ = BVOID; }
-
-cname:	/* class words */
-	LAUTO { $$ = BAUTO; }
-|	LSTATIC { $$ = BSTATIC; }
-|	LEXTERN { $$ = BEXTERN; }
-|	LTYPEDEF { $$ = BTYPEDEF; }
-|	LTYPESTR { $$ = BTYPESTR; }
-|	LREGISTER { $$ = BREGISTER; }
-|	LINLINE { $$ = 0; }
-
-gname:	/* garbage words */
-	LCONSTNT { $$ = BCONSTNT; }
-|	LVOLATILE { $$ = BVOLATILE; }
-|	LRESTRICT { $$ = 0; }
-
-name:
-	LNAME
-	{
-		$$ = new(ONAME, Z, Z);
-		if($1->class == CLOCAL)
-			$1 = mkstatic($1);
-		$$->sym = $1;
-		$$->type = $1->type;
-		$$->etype = TVOID;
-		if($$->type != T)
-			$$->etype = $$->type->etype;
-		$$->xoffset = $1->offset;
-		$$->class = $1->class;
-		$1->aused = 1;
-	}
-tag:
-	ltag
-	{
-		$$ = new(ONAME, Z, Z);
-		$$->sym = $1;
-		$$->type = $1->type;
-		$$->etype = TVOID;
-		if($$->type != T)
-			$$->etype = $$->type->etype;
-		$$->xoffset = $1->offset;
-		$$->class = $1->class;
-	}
-ltag:
-	LNAME
-|	LTYPE
-%%
diff --git a/src/cmd/cc/com.c b/src/cmd/cc/com.c
deleted file mode 100644
index 4886b73..0000000
--- a/src/cmd/cc/com.c
+++ /dev/null
@@ -1,1384 +0,0 @@
-// Inferno utils/cc/com.c
-// http://code.google.com/p/inferno-os/source/browse/utils/cc/com.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include <u.h>
-#include "cc.h"
-
-int compar(Node*, int);
-
-void
-complex(Node *n)
-{
-
-	if(n == Z)
-		return;
-
-	nearln = n->lineno;
-	if(debug['t'])
-		if(n->op != OCONST)
-			prtree(n, "pre complex");
-	if(tcom(n))
-		return;
-	if(debug['t'])
-		if(n->op != OCONST)
-			prtree(n, "t complex");
-	ccom(n);
-	if(debug['t'])
-		if(n->op != OCONST)
-			prtree(n, "c complex");
-	acom(n);
-	if(debug['t'])
-		if(n->op != OCONST)
-			prtree(n, "a complex");
-	xcom(n);
-	if(debug['t'])
-		if(n->op != OCONST)
-			prtree(n, "x complex");
-}
-
-/*
- * evaluate types
- * evaluate lvalues (addable == 1)
- */
-enum
-{
-	ADDROF	= 1<<0,
-	CASTOF	= 1<<1,
-	ADDROP	= 1<<2,
-};
-
-int
-tcom(Node *n)
-{
-
-	return tcomo(n, ADDROF);
-}
-
-int
-tcomo(Node *n, int f)
-{
-	Node *l, *r;
-	Type *t;
-	int o;
-	static TRune zer;
-
-	if(n == Z) {
-		diag(Z, "Z in tcom");
-		errorexit();
-	}
-	n->addable = 0;
-	l = n->left;
-	r = n->right;
-
-	switch(n->op) {
-	default:
-		diag(n, "unknown op in type complex: %O", n->op);
-		goto bad;
-
-	case ODOTDOT:
-		/*
-		 * tcom has already been called on this subtree
-		 */
-		*n = *n->left;
-		if(n->type == T)
-			goto bad;
-		break;
-
-	case OCAST:
-		if(n->type == T)
-			break;
-		if(n->type->width == types[TLONG]->width) {
-			if(tcomo(l, ADDROF|CASTOF))
-				goto bad;
-		} else
-			if(tcom(l))
-				goto bad;
-		if(isfunct(n))
-			break;
-		if(tcompat(n, l->type, n->type, tcast))
-			goto bad;
-		break;
-
-	case ORETURN:
-		if(l == Z) {
-			if(n->type->etype != TVOID)
-				diag(n, "null return of a typed function");
-			break;
-		}
-		if(tcom(l))
-			goto bad;
-		typeext(n->type, l);
-		if(tcompat(n, n->type, l->type, tasign))
-			break;
-		constas(n, n->type, l->type);
-		if(!sametype(n->type, l->type)) {
-			l = new1(OCAST, l, Z);
-			l->type = n->type;
-			n->left = l;
-		}
-		break;
-
-	case OASI:	/* same as as, but no test for const */
-		n->op = OAS;
-		o = tcom(l);
-		if(o | tcom(r))
-			goto bad;
-
-		typeext(l->type, r);
-		if(tlvalue(l) || tcompat(n, l->type, r->type, tasign))
-			goto bad;
-		if(!sametype(l->type, r->type)) {
-			r = new1(OCAST, r, Z);
-			r->type = l->type;
-			n->right = r;
-		}
-		n->type = l->type;
-		break;
-
-	case OAS:
-		o = tcom(l);
-		if(o | tcom(r))
-			goto bad;
-		if(tlvalue(l))
-			goto bad;
-		if(isfunct(n))
-			break;
-		typeext(l->type, r);
-		if(tcompat(n, l->type, r->type, tasign))
-			goto bad;
-		constas(n, l->type, r->type);
-		if(!sametype(l->type, r->type)) {
-			r = new1(OCAST, r, Z);
-			r->type = l->type;
-			n->right = r;
-		}
-		n->type = l->type;
-		break;
-
-	case OASADD:
-	case OASSUB:
-		o = tcom(l);
-		if(o | tcom(r))
-			goto bad;
-		if(tlvalue(l))
-			goto bad;
-		if(isfunct(n))
-			break;
-		typeext1(l->type, r);
-		if(tcompat(n, l->type, r->type, tasadd))
-			goto bad;
-		constas(n, l->type, r->type);
-		t = l->type;
-		arith(n, 0);
-		while(n->left->op == OCAST)
-			n->left = n->left->left;
-		if(!sametype(t, n->type) && !mixedasop(t, n->type)) {
-			r = new1(OCAST, n->right, Z);
-			r->type = t;
-			n->right = r;
-			n->type = t;
-		}
-		break;
-
-	case OASMUL:
-	case OASLMUL:
-	case OASDIV:
-	case OASLDIV:
-		o = tcom(l);
-		if(o | tcom(r))
-			goto bad;
-		if(tlvalue(l))
-			goto bad;
-		if(isfunct(n))
-			break;
-		typeext1(l->type, r);
-		if(tcompat(n, l->type, r->type, tmul))
-			goto bad;
-		constas(n, l->type, r->type);
-		t = l->type;
-		arith(n, 0);
-		while(n->left->op == OCAST)
-			n->left = n->left->left;
-		if(!sametype(t, n->type) && !mixedasop(t, n->type)) {
-			r = new1(OCAST, n->right, Z);
-			r->type = t;
-			n->right = r;
-			n->type = t;
-		}
-		if(typeu[n->type->etype]) {
-			if(n->op == OASDIV)
-				n->op = OASLDIV;
-			if(n->op == OASMUL)
-				n->op = OASLMUL;
-		}
-		break;
-
-	case OASLSHR:
-	case OASASHR:
-	case OASASHL:
-		o = tcom(l);
-		if(o | tcom(r))
-			goto bad;
-		if(tlvalue(l))
-			goto bad;
-		if(isfunct(n))
-			break;
-		if(tcompat(n, l->type, r->type, tand))
-			goto bad;
-		n->type = l->type;
-		if(typeu[n->type->etype]) {
-			if(n->op == OASASHR)
-				n->op = OASLSHR;
-		}
-		break;
-
-	case OASMOD:
-	case OASLMOD:
-	case OASOR:
-	case OASAND:
-	case OASXOR:
-		o = tcom(l);
-		if(o | tcom(r))
-			goto bad;
-		if(tlvalue(l))
-			goto bad;
-		if(isfunct(n))
-			break;
-		if(tcompat(n, l->type, r->type, tand))
-			goto bad;
-		t = l->type;
-		arith(n, 0);
-		while(n->left->op == OCAST)
-			n->left = n->left->left;
-		if(!sametype(t, n->type) && !mixedasop(t, n->type)) {
-			r = new1(OCAST, n->right, Z);
-			r->type = t;
-			n->right = r;
-			n->type = t;
-		}
-		if(typeu[n->type->etype]) {
-			if(n->op == OASMOD)
-				n->op = OASLMOD;
-		}
-		break;
-
-	case OPREINC:
-	case OPREDEC:
-	case OPOSTINC:
-	case OPOSTDEC:
-		if(tcom(l))
-			goto bad;
-		if(tlvalue(l))
-			goto bad;
-		if(isfunct(n))
-			break;
-		if(tcompat(n, l->type, types[TINT], tadd))
-			goto bad;
-		n->type = l->type;
-		if(n->type->etype == TIND)
-		if(n->type->link->width < 1)
-			diag(n, "inc/dec of a void pointer");
-		break;
-
-	case OEQ:
-	case ONE:
-		o = tcom(l);
-		if(o | tcom(r))
-			goto bad;
-		if(isfunct(n))
-			break;
-		typeext(l->type, r);
-		typeext(r->type, l);
-		if(tcompat(n, l->type, r->type, trel))
-			goto bad;
-		arith(n, 0);
-		n->type = types[TINT];
-		break;
-
-	case OLT:
-	case OGE:
-	case OGT:
-	case OLE:
-		o = tcom(l);
-		if(o | tcom(r))
-			goto bad;
-		if(isfunct(n))
-			break;
-		typeext1(l->type, r);
-		typeext1(r->type, l);
-		if(tcompat(n, l->type, r->type, trel))
-			goto bad;
-		arith(n, 0);
-		if(typeu[n->type->etype])
-			n->op = logrel[relindex(n->op)];
-		n->type = types[TINT];
-		break;
-
-	case OCOND:
-		o = tcom(l);
-		o |= tcom(r->left);
-		if(o | tcom(r->right))
-			goto bad;
-		if(r->right->type->etype == TIND && vconst(r->left) == 0) {
-			r->left->type = r->right->type;
-			r->left->vconst = 0;
-		}
-		if(r->left->type->etype == TIND && vconst(r->right) == 0) {
-			r->right->type = r->left->type;
-			r->right->vconst = 0;
-		}
-		if(sametype(r->right->type, r->left->type)) {
-			r->type = r->right->type;
-			n->type = r->type;
-			break;
-		}
-		if(tcompat(r, r->left->type, r->right->type, trel))
-			goto bad;
-		arith(r, 0);
-		n->type = r->type;
-		break;
-
-	case OADD:
-		o = tcom(l);
-		if(o | tcom(r))
-			goto bad;
-		if(isfunct(n))
-			break;
-		if(tcompat(n, l->type, r->type, tadd))
-			goto bad;
-		arith(n, 1);
-		break;
-
-	case OSUB:
-		o = tcom(l);
-		if(o | tcom(r))
-			goto bad;
-		if(isfunct(n))
-			break;
-		if(tcompat(n, l->type, r->type, tsub))
-			goto bad;
-		arith(n, 1);
-		break;
-
-	case OMUL:
-	case OLMUL:
-	case ODIV:
-	case OLDIV:
-		o = tcom(l);
-		if(o | tcom(r))
-			goto bad;
-		if(isfunct(n))
-			break;
-		if(tcompat(n, l->type, r->type, tmul))
-			goto bad;
-		arith(n, 1);
-		if(typeu[n->type->etype]) {
-			if(n->op == ODIV)
-				n->op = OLDIV;
-			if(n->op == OMUL)
-				n->op = OLMUL;
-		}
-		break;
-
-	case OLSHR:
-	case OASHL:
-	case OASHR:
-		o = tcom(l);
-		if(o | tcom(r))
-			goto bad;
-		if(isfunct(n))
-			break;
-		if(tcompat(n, l->type, r->type, tand))
-			goto bad;
-		n->right = Z;
-		arith(n, 1);
-		n->right = new1(OCAST, r, Z);
-		n->right->type = types[TINT];
-		if(typeu[n->type->etype])
-			if(n->op == OASHR)
-				n->op = OLSHR;
-		break;
-
-	case OAND:
-	case OOR:
-	case OXOR:
-		o = tcom(l);
-		if(o | tcom(r))
-			goto bad;
-		if(isfunct(n))
-			break;
-		if(tcompat(n, l->type, r->type, tand))
-			goto bad;
-		arith(n, 1);
-		break;
-
-	case OMOD:
-	case OLMOD:
-		o = tcom(l);
-		if(o | tcom(r))
-			goto bad;
-		if(isfunct(n))
-			break;
-		if(tcompat(n, l->type, r->type, tand))
-			goto bad;
-		arith(n, 1);
-		if(typeu[n->type->etype])
-			n->op = OLMOD;
-		break;
-
-	case OPOS:
-		if(tcom(l))
-			goto bad;
-		if(isfunct(n))
-			break;
-
-		r = l;
-		l = new(OCONST, Z, Z);
-		l->vconst = 0;
-		l->type = types[TINT];
-		n->op = OADD;
-		n->right = r;
-		n->left = l;
-
-		if(tcom(l))
-			goto bad;
-		if(tcompat(n, l->type, r->type, tsub))
-			goto bad;
-		arith(n, 1);
-		break;
-
-	case ONEG:
-		if(tcom(l))
-			goto bad;
-		if(isfunct(n))
-			break;
-
-		if(!machcap(n)) {
-			r = l;
-			l = new(OCONST, Z, Z);
-			l->vconst = 0;
-			l->type = types[TINT];
-			n->op = OSUB;
-			n->right = r;
-			n->left = l;
-
-			if(tcom(l))
-				goto bad;
-			if(tcompat(n, l->type, r->type, tsub))
-				goto bad;
-		}
-		arith(n, 1);
-		break;
-
-	case OCOM:
-		if(tcom(l))
-			goto bad;
-		if(isfunct(n))
-			break;
-
-		if(!machcap(n)) {
-			r = l;
-			l = new(OCONST, Z, Z);
-			l->vconst = -1;
-			l->type = types[TINT];
-			n->op = OXOR;
-			n->right = r;
-			n->left = l;
-
-			if(tcom(l))
-				goto bad;
-			if(tcompat(n, l->type, r->type, tand))
-				goto bad;
-		}
-		arith(n, 1);
-		break;
-
-	case ONOT:
-		if(tcom(l))
-			goto bad;
-		if(isfunct(n))
-			break;
-		if(tcompat(n, T, l->type, tnot))
-			goto bad;
-		n->type = types[TINT];
-		break;
-
-	case OANDAND:
-	case OOROR:
-		o = tcom(l);
-		if(o | tcom(r))
-			goto bad;
-		if(tcompat(n, T, l->type, tnot) |
-		   tcompat(n, T, r->type, tnot))
-			goto bad;
-		n->type = types[TINT];
-		break;
-
-	case OCOMMA:
-		o = tcom(l);
-		if(o | tcom(r))
-			goto bad;
-		n->type = r->type;
-		break;
-
-
-	case OSIGN:	/* extension signof(type) returns a hash */
-		if(l != Z) {
-			if(l->op != OSTRING && l->op != OLSTRING)
-				if(tcomo(l, 0))
-					goto bad;
-			if(l->op == OBIT) {
-				diag(n, "signof bitfield");
-				goto bad;
-			}
-			n->type = l->type;
-		}
-		if(n->type == T)
-			goto bad;
-		if(n->type->width < 0) {
-			diag(n, "signof undefined type");
-			goto bad;
-		}
-		n->op = OCONST;
-		n->left = Z;
-		n->right = Z;
-		n->vconst = convvtox(signature(n->type), TULONG);
-		n->type = types[TULONG];
-		break;
-
-	case OSIZE:
-		if(l != Z) {
-			if(l->op != OSTRING && l->op != OLSTRING)
-				if(tcomo(l, 0))
-					goto bad;
-			if(l->op == OBIT) {
-				diag(n, "sizeof bitfield");
-				goto bad;
-			}
-			n->type = l->type;
-		}
-		if(n->type == T)
-			goto bad;
-		if(n->type->width <= 0) {
-			diag(n, "sizeof undefined type");
-			goto bad;
-		}
-		if(n->type->etype == TFUNC) {
-			diag(n, "sizeof function");
-			goto bad;
-		}
-		n->op = OCONST;
-		n->left = Z;
-		n->right = Z;
-		n->vconst = convvtox(n->type->width, TINT);
-		n->type = types[TINT];
-		break;
-
-	case OFUNC:
-		o = tcomo(l, 0);
-		if(o)
-			goto bad;
-		if(l->type->etype == TIND && l->type->link->etype == TFUNC) {
-			l = new1(OIND, l, Z);
-			l->type = l->left->type->link;
-			n->left = l;
-		}
-		if(tcompat(n, T, l->type, tfunct))
-			goto bad;
-		if(o | tcoma(l, r, l->type->down, 1))
-			goto bad;
-		n->type = l->type->link;
-		if(!debug['B'])
-			if(l->type->down == T || l->type->down->etype == TOLD) {
-				nerrors--;
-				diag(n, "function args not checked: %F", l);
-			}
-		dpcheck(n);
-		break;
-
-	case ONAME:
-		if(n->type == T) {
-			diag(n, "name not declared: %F", n);
-			goto bad;
-		}
-		if(n->type->etype == TENUM) {
-			n->op = OCONST;
-			n->type = n->sym->tenum;
-			if(!typefd[n->type->etype])
-				n->vconst = n->sym->vconst;
-			else
-				n->fconst = n->sym->fconst;
-			break;
-		}
-		n->addable = 1;
-		if(n->class == CEXREG) {
-			n->op = OREGISTER;
-			// on 386 or amd64, "extern register" generates
-			// memory references relative to the
-			// gs or fs segment.
-			if(thechar == '8' || thechar == '6')	// [sic]
-				n->op = OEXREG;
-			n->reg = n->sym->offset;
-			n->xoffset = 0;
-			break;
-		}
-		break;
-
-	case OLSTRING:
-		if(n->type->link != types[TRUNE]) {
-			o = outstring(0, 0);
-			while(o & 3) {
-				outlstring(&zer, sizeof(TRune));
-				o = outlstring(0, 0);
-			}
-		}
-		n->op = ONAME;
-		n->xoffset = outlstring(n->rstring, n->type->width);
-		n->addable = 1;
-		break;
-
-	case OSTRING:
-		if(n->type->link != types[TCHAR]) {
-			o = outstring(0, 0);
-			while(o & 3) {
-				outstring("", 1);
-				o = outstring(0, 0);
-			}
-		}
-		n->op = ONAME;
-		n->xoffset = outstring(n->cstring, n->type->width);
-		n->addable = 1;
-		break;
-
-	case OCONST:
-		break;
-
-	case ODOT:
-		if(tcom(l))
-			goto bad;
-		if(tcompat(n, T, l->type, tdot))
-			goto bad;
-		if(tcomd(n))
-			goto bad;
-		break;
-
-	case OADDR:
-		if(tcomo(l, ADDROP))
-			goto bad;
-		if(tlvalue(l))
-			goto bad;
-		if(l->type->nbits) {
-			diag(n, "address of a bit field");
-			goto bad;
-		}
-		if(l->op == OREGISTER) {
-			diag(n, "address of a register");
-			goto bad;
-		}
-		n->type = typ(TIND, l->type);
-		n->type->width = types[TIND]->width;
-		break;
-
-	case OIND:
-		if(tcom(l))
-			goto bad;
-		if(tcompat(n, T, l->type, tindir))
-			goto bad;
-		n->type = l->type->link;
-		n->addable = 1;
-		break;
-
-	case OSTRUCT:
-		if(tcomx(n))
-			goto bad;
-		break;
-	}
-	t = n->type;
-	if(t == T)
-		goto bad;
-	if(t->width < 0) {
-		snap(t);
-		if(t->width < 0) {
-			if(typesu[t->etype] && t->tag)
-				diag(n, "structure not fully declared %s", t->tag->name);
-			else
-				diag(n, "structure not fully declared");
-			goto bad;
-		}
-	}
-	if(typeaf[t->etype]) {
-		if(f & ADDROF)
-			goto addaddr;
-		if(f & ADDROP)
-			warn(n, "address of array/func ignored");
-	}
-	return 0;
-
-addaddr:
-	if(tlvalue(n))
-		goto bad;
-	l = new1(OXXX, Z, Z);
-	*l = *n;
-	n->op = OADDR;
-	if(l->type->etype == TARRAY)
-		l->type = l->type->link;
-	n->left = l;
-	n->right = Z;
-	n->addable = 0;
-	n->type = typ(TIND, l->type);
-	n->type->width = types[TIND]->width;
-	return 0;
-
-bad:
-	n->type = T;
-	return 1;
-}
-
-int
-tcoma(Node *l, Node *n, Type *t, int f)
-{
-	Node *n1;
-	int o;
-
-	if(t != T)
-	if(t->etype == TOLD || t->etype == TDOT)	/* .../old in prototype */
-		t = T;
-	if(n == Z) {
-		if(t != T && !sametype(t, types[TVOID])) {
-			diag(n, "not enough function arguments: %F", l);
-			return 1;
-		}
-		return 0;
-	}
-	if(n->op == OLIST) {
-		o = tcoma(l, n->left, t, 0);
-		if(t != T) {
-			t = t->down;
-			if(t == T)
-				t = types[TVOID];
-		}
-		return o | tcoma(l, n->right, t, 1);
-	}
-	if(f && t != T)
-		tcoma(l, Z, t->down, 0);
-	if(tcom(n) || tcompat(n, T, n->type, targ))
-		return 1;
-	if(sametype(t, types[TVOID])) {
-		diag(n, "too many function arguments: %F", l);
-		return 1;
-	}
-	if(t != T) {
-		typeext(t, n);
-		if(stcompat(nodproto, t, n->type, tasign)) {
-			diag(l, "argument prototype mismatch \"%T\" for \"%T\": %F",
-				n->type, t, l);
-			return 1;
-		}
-//		switch(t->etype) {
-//		case TCHAR:
-//		case TSHORT:
-//			t = types[TINT];
-//			break;
-//
-//		case TUCHAR:
-//		case TUSHORT:
-//			t = types[TUINT];
-//			break;
-//		}
-	} else {
-		switch(n->type->etype) {
-		case TCHAR:
-		case TSHORT:
-			t = types[TINT];
-			break;
-
-		case TUCHAR:
-		case TUSHORT:
-			t = types[TUINT];
-			break;
-
-		case TFLOAT:
-			t = types[TDOUBLE];
-		}
-	}
-
-	if(t != T && !sametype(t, n->type)) {
-		n1 = new1(OXXX, Z, Z);
-		*n1 = *n;
-		n->op = OCAST;
-		n->left = n1;
-		n->right = Z;
-		n->type = t;
-		n->addable = 0;
-	}
-	return 0;
-}
-
-int
-tcomd(Node *n)
-{
-	Type *t;
-	int32 o;
-
-	o = 0;
-	t = dotsearch(n->sym, n->left->type->link, n, &o);
-	if(t == T) {
-		diag(n, "not a member of struct/union: %F", n);
-		return 1;
-	}
-	makedot(n, t, o);
-	return 0;
-}
-
-int
-tcomx(Node *n)
-{
-	Type *t;
-	Node *l, *r, **ar, **al;
-	int e;
-
-	e = 0;
-	if(n->type->etype != TSTRUCT) {
-		diag(n, "constructor must be a structure");
-		return 1;
-	}
-	l = invert(n->left);
-	n->left = l;
-	al = &n->left;
-	for(t = n->type->link; t != T; t = t->down) {
-		if(l == Z) {
-			diag(n, "constructor list too short");
-			return 1;
-		}
-		if(l->op == OLIST) {
-			r = l->left;
-			ar = &l->left;
-			al = &l->right;
-			l = l->right;
-		} else {
-			r = l;
-			ar = al;
-			l = Z;
-		}
-		if(tcom(r))
-			e++;
-		typeext(t, r);
-		if(tcompat(n, t, r->type, tasign))
-			e++;
-		constas(n, t, r->type);
-		if(!e && !sametype(t, r->type)) {
-			r = new1(OCAST, r, Z);
-			r->type = t;
-			*ar = r;
-		}
-	}
-	if(l != Z) {
-		diag(n, "constructor list too long");
-		return 1;
-	}
-	return e;
-}
-
-int
-tlvalue(Node *n)
-{
-
-	if(!n->addable) {
-		diag(n, "not an l-value");
-		return 1;
-	}
-	return 0;
-}
-
-/*
- *	general rewrite
- *	(IND(ADDR x)) ==> x
- *	(ADDR(IND x)) ==> x
- *	remove some zero operands
- *	remove no op casts
- *	evaluate constants
- */
-void
-ccom(Node *n)
-{
-	Node *l, *r;
-	int t;
-
-loop:
-	if(n == Z)
-		return;
-	l = n->left;
-	r = n->right;
-	switch(n->op) {
-
-	case OAS:
-	case OASXOR:
-	case OASAND:
-	case OASOR:
-	case OASMOD:
-	case OASLMOD:
-	case OASLSHR:
-	case OASASHR:
-	case OASASHL:
-	case OASDIV:
-	case OASLDIV:
-	case OASMUL:
-	case OASLMUL:
-	case OASSUB:
-	case OASADD:
-		ccom(l);
-		ccom(r);
-		if(n->op == OASLSHR || n->op == OASASHR || n->op == OASASHL)
-		if(r->op == OCONST) {
-			t = n->type->width * 8;	/* bits per byte */
-			if(r->vconst >= t || r->vconst < 0)
-				warn(n, "stupid shift: %lld", r->vconst);
-		}
-		break;
-
-	case OCAST:
-		ccom(l);
-		if(l->op == OCONST) {
-			evconst(n);
-			if(n->op == OCONST)
-				break;
-		}
-		if(nocast(l->type, n->type)) {
-			l->type = n->type;
-			*n = *l;
-		}
-		break;
-
-	case OCOND:
-		ccom(l);
-		ccom(r);
-		if(l->op == OCONST)
-			if(vconst(l) == 0)
-				*n = *r->right;
-			else
-				*n = *r->left;
-		break;
-
-	case OREGISTER:
-	case OINDREG:
-	case OCONST:
-	case ONAME:
-		break;
-
-	case OADDR:
-		ccom(l);
-		l->etype = TVOID;
-		if(l->op == OIND) {
-			l->left->type = n->type;
-			*n = *l->left;
-			break;
-		}
-		goto common;
-
-	case OIND:
-		ccom(l);
-		if(l->op == OADDR) {
-			l->left->type = n->type;
-			*n = *l->left;
-			break;
-		}
-		goto common;
-
-	case OEQ:
-	case ONE:
-
-	case OLE:
-	case OGE:
-	case OLT:
-	case OGT:
-
-	case OLS:
-	case OHS:
-	case OLO:
-	case OHI:
-		ccom(l);
-		ccom(r);
-		if(compar(n, 0) || compar(n, 1))
-			break;
-		relcon(l, r);
-		relcon(r, l);
-		goto common;
-
-	case OASHR:
-	case OASHL:
-	case OLSHR:
-		ccom(l);
-		if(vconst(l) == 0 && !side(r)) {
-			*n = *l;
-			break;
-		}
-		ccom(r);
-		if(vconst(r) == 0) {
-			*n = *l;
-			break;
-		}
-		if(r->op == OCONST) {
-			t = n->type->width * 8;	/* bits per byte */
-			if(r->vconst >= t || r->vconst <= -t)
-				warn(n, "stupid shift: %lld", r->vconst);
-		}
-		goto common;
-
-	case OMUL:
-	case OLMUL:
-		ccom(l);
-		t = vconst(l);
-		if(t == 0 && !side(r)) {
-			*n = *l;
-			break;
-		}
-		if(t == 1) {
-			*n = *r;
-			goto loop;
-		}
-		ccom(r);
-		t = vconst(r);
-		if(t == 0 && !side(l)) {
-			*n = *r;
-			break;
-		}
-		if(t == 1) {
-			*n = *l;
-			break;
-		}
-		goto common;
-
-	case ODIV:
-	case OLDIV:
-		ccom(l);
-		if(vconst(l) == 0 && !side(r)) {
-			*n = *l;
-			break;
-		}
-		ccom(r);
-		t = vconst(r);
-		if(t == 0) {
-			diag(n, "divide check");
-			*n = *r;
-			break;
-		}
-		if(t == 1) {
-			*n = *l;
-			break;
-		}
-		goto common;
-
-	case OSUB:
-		ccom(r);
-		if(r->op == OCONST) {
-			if(typefd[r->type->etype]) {
-				n->op = OADD;
-				r->fconst = -r->fconst;
-				goto loop;
-			} else {
-				n->op = OADD;
-				r->vconst = -r->vconst;
-				goto loop;
-			}
-		}
-		ccom(l);
-		goto common;
-
-	case OXOR:
-	case OOR:
-	case OADD:
-		ccom(l);
-		if(vconst(l) == 0) {
-			*n = *r;
-			goto loop;
-		}
-		ccom(r);
-		if(vconst(r) == 0) {
-			*n = *l;
-			break;
-		}
-		goto commute;
-
-	case OAND:
-		ccom(l);
-		ccom(r);
-		if(vconst(l) == 0 && !side(r)) {
-			*n = *l;
-			break;
-		}
-		if(vconst(r) == 0 && !side(l)) {
-			*n = *r;
-			break;
-		}
-
-	commute:
-		/* look for commutative constant */
-		if(r->op == OCONST) {
-			if(l->op == n->op) {
-				if(l->left->op == OCONST) {
-					n->right = l->right;
-					l->right = r;
-					goto loop;
-				}
-				if(l->right->op == OCONST) {
-					n->right = l->left;
-					l->left = r;
-					goto loop;
-				}
-			}
-		}
-		if(l->op == OCONST) {
-			if(r->op == n->op) {
-				if(r->left->op == OCONST) {
-					n->left = r->right;
-					r->right = l;
-					goto loop;
-				}
-				if(r->right->op == OCONST) {
-					n->left = r->left;
-					r->left = l;
-					goto loop;
-				}
-			}
-		}
-		goto common;
-
-	case OANDAND:
-		ccom(l);
-		if(vconst(l) == 0) {
-			*n = *l;
-			break;
-		}
-		ccom(r);
-		goto common;
-
-	case OOROR:
-		ccom(l);
-		if(l->op == OCONST && l->vconst != 0) {
-			*n = *l;
-			n->vconst = 1;
-			break;
-		}
-		ccom(r);
-		goto common;
-
-	default:
-		if(l != Z)
-			ccom(l);
-		if(r != Z)
-			ccom(r);
-	common:
-		if(l != Z)
-		if(l->op != OCONST)
-			break;
-		if(r != Z)
-		if(r->op != OCONST)
-			break;
-		evconst(n);
-	}
-}
-
-/*	OEQ, ONE, OLE, OLS, OLT, OLO, OGE, OHS, OGT, OHI */
-static char *cmps[12] = 
-{
-	"==", "!=", "<=", "<=", "<", "<", ">=", ">=", ">", ">",
-};
-
-/* 128-bit numbers */
-typedef struct Big Big;
-struct Big
-{
-	vlong a;
-	uvlong b;
-};
-static int
-cmp(Big x, Big y)
-{
-	if(x.a != y.a){
-		if(x.a < y.a)
-			return -1;
-		return 1;
-	}
-	if(x.b != y.b){
-		if(x.b < y.b)
-			return -1;
-		return 1;
-	}
-	return 0;
-}
-static Big
-add(Big x, int y)
-{
-	uvlong ob;
-	
-	ob = x.b;
-	x.b += y;
-	if(y > 0 && x.b < ob)
-		x.a++;
-	if(y < 0 && x.b > ob)
-		x.a--;
-	return x;
-} 
-
-Big
-big(vlong a, uvlong b)
-{
-	Big x;
-
-	x.a = a;
-	x.b = b;
-	return x;
-}
-
-int
-compar(Node *n, int reverse)
-{
-	Big lo, hi, x;
-	int op;
-	char xbuf[40], cmpbuf[50];
-	Node *l, *r;
-	Type *lt, *rt;
-
-	/*
-	 * The point of this function is to diagnose comparisons 
-	 * that can never be true or that look misleading because
-	 * of the `usual arithmetic conversions'.  As an example 
-	 * of the latter, if x is a ulong, then if(x <= -1) really means
-	 * if(x <= 0xFFFFFFFF), while if(x <= -1LL) really means
-	 * what it says (but 8c compiles it wrong anyway).
-	 */
-
-	if(reverse){
-		r = n->left;
-		l = n->right;
-		op = comrel[relindex(n->op)];
-	}else{
-		l = n->left;
-		r = n->right;
-		op = n->op;
-	}
-
-	/*
-	 * Skip over left casts to find out the original expression range.
-	 */
-	while(l->op == OCAST)
-		l = l->left;
-	if(l->op == OCONST)
-		return 0;
-	lt = l->type;
-	if(l->op == ONAME && l->sym->type){
-		lt = l->sym->type;
-		if(lt->etype == TARRAY)
-			lt = lt->link;
-	}
-	if(lt == T)
-		return 0;
-	if(lt->etype == TXXX || lt->etype > TUVLONG)
-		return 0;
-	
-	/*
-	 * Skip over the right casts to find the on-screen value.
-	 */
-	if(r->op != OCONST)
-		return 0;
-	while(r->oldop == OCAST && !r->xcast)
-		r = r->left;
-	rt = r->type;
-	if(rt == T)
-		return 0;
-
-	x.b = r->vconst;
-	x.a = 0;
-	if((rt->etype&1) && r->vconst < 0)	/* signed negative */
-		x.a = ~0ULL;
-
-	if((lt->etype&1)==0){
-		/* unsigned */
-		lo = big(0, 0);
-		if(lt->width == 8)
-			hi = big(0, ~0ULL);
-		else
-			hi = big(0, (1ULL<<(l->type->width*8))-1);
-	}else{
-		lo = big(~0ULL, -(1ULL<<(l->type->width*8-1)));
-		hi = big(0, (1ULL<<(l->type->width*8-1))-1);
-	}
-
-	switch(op){
-	case OLT:
-	case OLO:
-	case OGE:
-	case OHS:
-		if(cmp(x, lo) <= 0)
-			goto useless;
-		if(cmp(x, add(hi, 1)) >= 0)
-			goto useless;
-		break;
-	case OLE:
-	case OLS:
-	case OGT:
-	case OHI:
-		if(cmp(x, add(lo, -1)) <= 0)
-			goto useless;
-		if(cmp(x, hi) >= 0)
-			goto useless;
-		break;
-	case OEQ:
-	case ONE:
-		/*
-		 * Don't warn about comparisons if the expression
-		 * is as wide as the value: the compiler-supplied casts
-		 * will make both outcomes possible.
-		 */
-		if(lt->width >= rt->width && debug['w'] < 2)
-			return 0;
-		if(cmp(x, lo) < 0 || cmp(x, hi) > 0)
-			goto useless;
-		break;
-	}
-	return 0;
-
-useless:
-	if((x.a==0 && x.b<=9) || (x.a==~0LL && x.b >= -9ULL))
-		snprint(xbuf, sizeof xbuf, "%lld", x.b);
-	else if(x.a == 0)
-		snprint(xbuf, sizeof xbuf, "%#llux", x.b);
-	else
-		snprint(xbuf, sizeof xbuf, "%#llx", x.b);
-	if(reverse)
-		snprint(cmpbuf, sizeof cmpbuf, "%s %s %T",
-			xbuf, cmps[relindex(n->op)], lt);
-	else
-		snprint(cmpbuf, sizeof cmpbuf, "%T %s %s",
-			lt, cmps[relindex(n->op)], xbuf);
-	warn(n, "useless or misleading comparison: %s", cmpbuf);
-	return 0;
-}
-
diff --git a/src/cmd/cc/com64.c b/src/cmd/cc/com64.c
deleted file mode 100644
index f46fedc..0000000
--- a/src/cmd/cc/com64.c
+++ /dev/null
@@ -1,644 +0,0 @@
-// Inferno utils/cc/com64.c
-// http://code.google.com/p/inferno-os/source/browse/utils/cc/com64.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include <u.h>
-#include "cc.h"
-
-/*
- * this is machine depend, but it is totally
- * common on all of the 64-bit symulating machines.
- */
-
-#define	FNX	100	/* botch -- redefinition */
-
-Node*	nodaddv;
-Node*	nodsubv;
-Node*	nodmulv;
-Node*	noddivv;
-Node*	noddivvu;
-Node*	nodmodv;
-Node*	nodmodvu;
-Node*	nodlshv;
-Node*	nodrshav;
-Node*	nodrshlv;
-Node*	nodandv;
-Node*	nodorv;
-Node*	nodxorv;
-Node*	nodnegv;
-Node*	nodcomv;
-
-Node*	nodtestv;
-Node*	nodeqv;
-Node*	nodnev;
-Node*	nodlev;
-Node*	nodltv;
-Node*	nodgev;
-Node*	nodgtv;
-Node*	nodhiv;
-Node*	nodhsv;
-Node*	nodlov;
-Node*	nodlsv;
-
-Node*	nodf2v;
-Node*	nodd2v;
-Node*	nodp2v;
-Node*	nodsi2v;
-Node*	nodui2v;
-Node*	nodsl2v;
-Node*	nodul2v;
-Node*	nodsh2v;
-Node*	noduh2v;
-Node*	nodsc2v;
-Node*	noduc2v;
-
-Node*	nodv2f;
-Node*	nodv2d;
-Node*	nodv2ui;
-Node*	nodv2si;
-Node*	nodv2ul;
-Node*	nodv2sl;
-Node*	nodv2uh;
-Node*	nodv2sh;
-Node*	nodv2uc;
-Node*	nodv2sc;
-
-Node*	nodvpp;
-Node*	nodppv;
-Node*	nodvmm;
-Node*	nodmmv;
-
-Node*	nodvasop;
-
-char	etconv[NALLTYPES];	/* for _vasop */
-Init	initetconv[] =
-{
-	TCHAR,		1,	0,
-	TUCHAR,		2,	0,
-	TSHORT,		3,	0,
-	TUSHORT,	4,	0,
-	TLONG,		5,	0,
-	TULONG,		6,	0,
-	TVLONG,		7,	0,
-	TUVLONG,	8,	0,
-	TINT,		9,	0,
-	TUINT,		10,	0,
-	-1,		0,	0,
-};
-
-Node*
-fvn(char *name, int type)
-{
-	Node *n;
-
-	n = new(ONAME, Z, Z);
-	n->sym = slookup(name);
-	n->sym->sig = SIGINTERN;
-	if(fntypes[type] == 0)
-		fntypes[type] = typ(TFUNC, types[type]);
-	n->type = fntypes[type];
-	n->etype = type;
-	n->class = CGLOBL;
-	n->addable = 10;
-	n->complex = 0;
-	return n;
-}
-
-void
-com64init(void)
-{
-	Init *p;
-
-	nodaddv = fvn("_addv", TVLONG);
-	nodsubv = fvn("_subv", TVLONG);
-	nodmulv = fvn("_mulv", TVLONG);
-	noddivv = fvn("_divv", TVLONG);
-	noddivvu = fvn("_divvu", TVLONG);
-	nodmodv = fvn("_modv", TVLONG);
-	nodmodvu = fvn("_modvu", TVLONG);
-	nodlshv = fvn("_lshv", TVLONG);
-	nodrshav = fvn("_rshav", TVLONG);
-	nodrshlv = fvn("_rshlv", TVLONG);
-	nodandv = fvn("_andv", TVLONG);
-	nodorv = fvn("_orv", TVLONG);
-	nodxorv = fvn("_xorv", TVLONG);
-	nodnegv = fvn("_negv", TVLONG);
-	nodcomv = fvn("_comv", TVLONG);
-
-	nodtestv = fvn("_testv", TLONG);
-	nodeqv = fvn("_eqv", TLONG);
-	nodnev = fvn("_nev", TLONG);
-	nodlev = fvn("_lev", TLONG);
-	nodltv = fvn("_ltv", TLONG);
-	nodgev = fvn("_gev", TLONG);
-	nodgtv = fvn("_gtv", TLONG);
-	nodhiv = fvn("_hiv", TLONG);
-	nodhsv = fvn("_hsv", TLONG);
-	nodlov = fvn("_lov", TLONG);
-	nodlsv = fvn("_lsv", TLONG);
-
-	nodf2v = fvn("_f2v", TVLONG);
-	nodd2v = fvn("_d2v", TVLONG);
-	nodp2v = fvn("_p2v", TVLONG);
-	nodsi2v = fvn("_si2v", TVLONG);
-	nodui2v = fvn("_ui2v", TVLONG);
-	nodsl2v = fvn("_sl2v", TVLONG);
-	nodul2v = fvn("_ul2v", TVLONG);
-	nodsh2v = fvn("_sh2v", TVLONG);
-	noduh2v = fvn("_uh2v", TVLONG);
-	nodsc2v = fvn("_sc2v", TVLONG);
-	noduc2v = fvn("_uc2v", TVLONG);
-
-	nodv2f = fvn("_v2f", TFLOAT);
-	nodv2d = fvn("_v2d", TDOUBLE);
-	nodv2sl = fvn("_v2sl", TLONG);
-	nodv2ul = fvn("_v2ul", TULONG);
-	nodv2si = fvn("_v2si", TINT);
-	nodv2ui = fvn("_v2ui", TUINT);
-	nodv2sh = fvn("_v2sh", TSHORT);
-	nodv2uh = fvn("_v2ul", TUSHORT);
-	nodv2sc = fvn("_v2sc", TCHAR);
-	nodv2uc = fvn("_v2uc", TUCHAR);
-
-	nodvpp = fvn("_vpp", TVLONG);
-	nodppv = fvn("_ppv", TVLONG);
-	nodvmm = fvn("_vmm", TVLONG);
-	nodmmv = fvn("_mmv", TVLONG);
-
-	nodvasop = fvn("_vasop", TVLONG);
-
-	for(p = initetconv; p->code >= 0; p++)
-		etconv[p->code] = p->value;
-}
-
-int
-com64(Node *n)
-{
-	Node *l, *r, *a, *t;
-	int lv, rv;
-
-	if(n->type == 0)
-		return 0;
-
-	l = n->left;
-	r = n->right;
-
-	lv = 0;
-	if(l && l->type && typev[l->type->etype])
-		lv = 1;
-	rv = 0;
-	if(r && r->type && typev[r->type->etype])
-		rv = 1;
-
-	if(lv) {
-		switch(n->op) {
-		case OEQ:
-			a = nodeqv;
-			goto setbool;
-		case ONE:
-			a = nodnev;
-			goto setbool;
-		case OLE:
-			a = nodlev;
-			goto setbool;
-		case OLT:
-			a = nodltv;
-			goto setbool;
-		case OGE:
-			a = nodgev;
-			goto setbool;
-		case OGT:
-			a = nodgtv;
-			goto setbool;
-		case OHI:
-			a = nodhiv;
-			goto setbool;
-		case OHS:
-			a = nodhsv;
-			goto setbool;
-		case OLO:
-			a = nodlov;
-			goto setbool;
-		case OLS:
-			a = nodlsv;
-			goto setbool;
-
-		case OANDAND:
-		case OOROR:
-			if(machcap(n))
-				return 1;
-
-			if(rv) {
-				r = new(OFUNC, nodtestv, r);
-				n->right = r;
-				r->complex = FNX;
-				r->op = OFUNC;
-				r->type = types[TLONG];
-			}
-
-		case OCOND:
-		case ONOT:
-			if(machcap(n))
-				return 1;
-
-			l = new(OFUNC, nodtestv, l);
-			n->left = l;
-			l->complex = FNX;
-			l->op = OFUNC;
-			l->type = types[TLONG];
-			n->complex = FNX;
-			return 1;
-		}
-	}
-
-	if(rv) {
-		if(machcap(n))
-			return 1;
-		switch(n->op) {
-		case OANDAND:
-		case OOROR:
-			r = new(OFUNC, nodtestv, r);
-			n->right = r;
-			r->complex = FNX;
-			r->op = OFUNC;
-			r->type = types[TLONG];
-			return 1;
-		}
-	}
-
-	if(typev[n->type->etype]) {
-		if(machcap(n))
-			return 1;
-		switch(n->op) {
-		default:
-			diag(n, "unknown vlong %O", n->op);
-		case OFUNC:
-			n->complex = FNX;
-		case ORETURN:
-		case OAS:
-		case OIND:
-			return 1;
-		case OADD:
-			a = nodaddv;
-			goto setbop;
-		case OSUB:
-			a = nodsubv;
-			goto setbop;
-		case OMUL:
-		case OLMUL:
-			a = nodmulv;
-			goto setbop;
-		case ODIV:
-			a = noddivv;
-			goto setbop;
-		case OLDIV:
-			a = noddivvu;
-			goto setbop;
-		case OMOD:
-			a = nodmodv;
-			goto setbop;
-		case OLMOD:
-			a = nodmodvu;
-			goto setbop;
-		case OASHL:
-			a = nodlshv;
-			goto setbop;
-		case OASHR:
-			a = nodrshav;
-			goto setbop;
-		case OLSHR:
-			a = nodrshlv;
-			goto setbop;
-		case OAND:
-			a = nodandv;
-			goto setbop;
-		case OOR:
-			a = nodorv;
-			goto setbop;
-		case OXOR:
-			a = nodxorv;
-			goto setbop;
-		case OPOSTINC:
-			a = nodvpp;
-			goto setvinc;
-		case OPOSTDEC:
-			a = nodvmm;
-			goto setvinc;
-		case OPREINC:
-			a = nodppv;
-			goto setvinc;
-		case OPREDEC:
-			a = nodmmv;
-			goto setvinc;
-		case ONEG:
-			a = nodnegv;
-			goto setfnx;
-		case OCOM:
-			a = nodcomv;
-			goto setfnx;
-		case OCAST:
-			switch(l->type->etype) {
-			case TCHAR:
-				a = nodsc2v;
-				goto setfnxl;
-			case TUCHAR:
-				a = noduc2v;
-				goto setfnxl;
-			case TSHORT:
-				a = nodsh2v;
-				goto setfnxl;
-			case TUSHORT:
-				a = noduh2v;
-				goto setfnxl;
-			case TINT:
-				a = nodsi2v;
-				goto setfnx;
-			case TUINT:
-				a = nodui2v;
-				goto setfnx;
-			case TLONG:
-				a = nodsl2v;
-				goto setfnx;
-			case TULONG:
-				a = nodul2v;
-				goto setfnx;
-			case TFLOAT:
-				a = nodf2v;
-				goto setfnx;
-			case TDOUBLE:
-				a = nodd2v;
-				goto setfnx;
-			case TIND:
-				a = nodp2v;
-				goto setfnx;
-			}
-			diag(n, "unknown %T->vlong cast", l->type);
-			return 1;
-		case OASADD:
-			a = nodaddv;
-			goto setasop;
-		case OASSUB:
-			a = nodsubv;
-			goto setasop;
-		case OASMUL:
-		case OASLMUL:
-			a = nodmulv;
-			goto setasop;
-		case OASDIV:
-			a = noddivv;
-			goto setasop;
-		case OASLDIV:
-			a = noddivvu;
-			goto setasop;
-		case OASMOD:
-			a = nodmodv;
-			goto setasop;
-		case OASLMOD:
-			a = nodmodvu;
-			goto setasop;
-		case OASASHL:
-			a = nodlshv;
-			goto setasop;
-		case OASASHR:
-			a = nodrshav;
-			goto setasop;
-		case OASLSHR:
-			a = nodrshlv;
-			goto setasop;
-		case OASAND:
-			a = nodandv;
-			goto setasop;
-		case OASOR:
-			a = nodorv;
-			goto setasop;
-		case OASXOR:
-			a = nodxorv;
-			goto setasop;
-		}
-	}
-
-	if(typefd[n->type->etype] && l && l->op == OFUNC) {
-		switch(n->op) {
-		case OASADD:
-		case OASSUB:
-		case OASMUL:
-		case OASLMUL:
-		case OASDIV:
-		case OASLDIV:
-		case OASMOD:
-		case OASLMOD:
-		case OASASHL:
-		case OASASHR:
-		case OASLSHR:
-		case OASAND:
-		case OASOR:
-		case OASXOR:
-			if(l->right && typev[l->right->etype]) {
-				diag(n, "sorry float <asop> vlong not implemented\n");
-			}
-		}
-	}
-
-	if(n->op == OCAST) {
-		if(l->type && typev[l->type->etype]) {
-			if(machcap(n))
-				return 1;
-			switch(n->type->etype) {
-			case TDOUBLE:
-				a = nodv2d;
-				goto setfnx;
-			case TFLOAT:
-				a = nodv2f;
-				goto setfnx;
-			case TLONG:
-				a = nodv2sl;
-				goto setfnx;
-			case TULONG:
-				a = nodv2ul;
-				goto setfnx;
-			case TINT:
-				a = nodv2si;
-				goto setfnx;
-			case TUINT:
-				a = nodv2ui;
-				goto setfnx;
-			case TSHORT:
-				a = nodv2sh;
-				goto setfnx;
-			case TUSHORT:
-				a = nodv2uh;
-				goto setfnx;
-			case TCHAR:
-				a = nodv2sc;
-				goto setfnx;
-			case TUCHAR:
-				a = nodv2uc;
-				goto setfnx;
-			case TIND:	// small pun here
-				a = nodv2ul;
-				goto setfnx;
-			}
-			diag(n, "unknown vlong->%T cast", n->type);
-			return 1;
-		}
-	}
-
-	return 0;
-
-setbop:
-	n->left = a;
-	n->right = new(OLIST, l, r);
-	n->complex = FNX;
-	n->op = OFUNC;
-	return 1;
-
-setfnxl:
-	l = new(OCAST, l, 0);
-	l->type = types[TLONG];
-	l->complex = l->left->complex;
-
-setfnx:
-	n->left = a;
-	n->right = l;
-	n->complex = FNX;
-	n->op = OFUNC;
-	return 1;
-
-setvinc:
-	n->left = a;
-	l = new(OADDR, l, Z);
-	l->type = typ(TIND, l->left->type);
-	n->right = new(OLIST, l, r);
-	n->complex = FNX;
-	n->op = OFUNC;
-	return 1;
-
-setbool:
-	if(machcap(n))
-		return 1;
-	n->left = a;
-	n->right = new(OLIST, l, r);
-	n->complex = FNX;
-	n->op = OFUNC;
-	n->type = types[TLONG];
-	return 1;
-
-setasop:
-	if(l->op == OFUNC) {
-		l = l->right;
-		goto setasop;
-	}
-
-	t = new(OCONST, 0, 0);
-	t->vconst = etconv[l->type->etype];
-	t->type = types[TLONG];
-	t->addable = 20;
-	r = new(OLIST, t, r);
-
-	t = new(OADDR, a, 0);
-	t->type = typ(TIND, a->type);
-	r = new(OLIST, t, r);
-
-	t = new(OADDR, l, 0);
-	t->type = typ(TIND, l->type);
-	r = new(OLIST, t, r);
-
-	n->left = nodvasop;
-	n->right = r;
-	n->complex = FNX;
-	n->op = OFUNC;
-
-	return 1;
-}
-
-void
-bool64(Node *n)
-{
-	Node *n1;
-
-	if(machcap(Z))
-		return;
-	if(typev[n->type->etype]) {
-		n1 = new(OXXX, 0, 0);
-		*n1 = *n;
-
-		n->right = n1;
-		n->left = nodtestv;
-		n->complex = FNX;
-		n->addable = 0;
-		n->op = OFUNC;
-		n->type = types[TLONG];
-	}
-}
-
-/*
- * more machine depend stuff.
- * this is common for 8,16,32,64 bit machines.
- * this is common for ieee machines.
- */
-double
-convvtof(vlong v)
-{
-	double d;
-
-	d = v;		/* BOTCH */
-	return d;
-}
-
-vlong
-convftov(double d)
-{
-	vlong v;
-
-
-	v = d;		/* BOTCH */
-	return v;
-}
-
-double
-convftox(double d, int et)
-{
-
-	if(!typefd[et])
-		diag(Z, "bad type in castftox %s", tnames[et]);
-	return d;
-}
-
-vlong
-convvtox(vlong c, int et)
-{
-	int n;
-
-	n = 8 * ewidth[et];
-	c &= MASK(n);
-	if(!typeu[et])
-		if(c & SIGN(n))
-			c |= ~MASK(n);
-	return c;
-}
diff --git a/src/cmd/cc/dcl.c b/src/cmd/cc/dcl.c
deleted file mode 100644
index 117508f..0000000
--- a/src/cmd/cc/dcl.c
+++ /dev/null
@@ -1,1707 +0,0 @@
-// Inferno utils/cc/dcl.c
-// http://code.google.com/p/inferno-os/source/browse/utils/cc/dcl.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include <u.h>
-#include "cc.h"
-#include "../ld/textflag.h"
-
-static int haspointers(Type*);
-
-Node*
-dodecl(void (*f)(int,Type*,Sym*), int c, Type *t, Node *n)
-{
-	Sym *s;
-	Node *n1;
-	int32 v;
-
-	nearln = lineno;
-	lastfield = 0;
-
-loop:
-	if(n != Z)
-	switch(n->op) {
-	default:
-		diag(n, "unknown declarator: %O", n->op);
-		break;
-
-	case OARRAY:
-		t = typ(TARRAY, t);
-		t->width = 0;
-		n1 = n->right;
-		n = n->left;
-		if(n1 != Z) {
-			complex(n1);
-			v = -1;
-			if(n1->op == OCONST)
-				v = n1->vconst;
-			if(v <= 0) {
-				diag(n, "array size must be a positive constant");
-				v = 1;
-			}
-			t->width = v * t->link->width;
-		}
-		goto loop;
-
-	case OIND:
-		t = typ(TIND, t);
-		t->garb = n->garb;
-		n = n->left;
-		goto loop;
-
-	case OFUNC:
-		t = typ(TFUNC, t);
-		t->down = fnproto(n);
-		n = n->left;
-		goto loop;
-
-	case OBIT:
-		n1 = n->right;
-		complex(n1);
-		lastfield = -1;
-		if(n1->op == OCONST)
-			lastfield = n1->vconst;
-		if(lastfield < 0) {
-			diag(n, "field width must be non-negative constant");
-			lastfield = 1;
-		}
-		if(lastfield == 0) {
-			lastbit = 0;
-			firstbit = 1;
-			if(n->left != Z) {
-				diag(n, "zero width named field");
-				lastfield = 1;
-			}
-		}
-		if(!typei[t->etype]) {
-			diag(n, "field type must be int-like");
-			t = types[TINT];
-			lastfield = 1;
-		}
-		if(lastfield > tfield->width*8) {
-			diag(n, "field width larger than field unit");
-			lastfield = 1;
-		}
-		lastbit += lastfield;
-		if(lastbit > tfield->width*8) {
-			lastbit = lastfield;
-			firstbit = 1;
-		}
-		n = n->left;
-		goto loop;
-
-	case ONAME:
-		if(f == NODECL)
-			break;
-		s = n->sym;
-		(*f)(c, t, s);
-		if(s->class == CLOCAL)
-			s = mkstatic(s);
-		if(dataflag) {
-			s->dataflag = dataflag;
-			dataflag = 0;
-		} else if(s->type != T && !haspointers(s->type))
-			s->dataflag = NOPTR;
-		firstbit = 0;
-		n->sym = s;
-		n->type = s->type;
-		n->xoffset = s->offset;
-		n->class = s->class;
-		n->etype = TVOID;
-		if(n->type != T)
-			n->etype = n->type->etype;
-		if(debug['d'])
-			dbgdecl(s);
-		acidvar(s);
-		godefvar(s);
-		s->varlineno = lineno;
-		break;
-	}
-	lastdcl = t;
-	return n;
-}
-
-Sym*
-mkstatic(Sym *s)
-{
-	Sym *s1;
-
-	if(s->class != CLOCAL)
-		return s;
-	snprint(symb, NSYMB, "%s$%d", s->name, s->block);
-	s1 = lookup();
-	if(s1->class != CSTATIC) {
-		s1->type = s->type;
-		s1->offset = s->offset;
-		s1->block = s->block;
-		s1->class = CSTATIC;
-	}
-	return s1;
-}
-
-/*
- * make a copy of a typedef
- * the problem is to split out incomplete
- * arrays so that it is in the variable
- * rather than the typedef.
- */
-Type*
-tcopy(Type *t)
-{
-	Type *tl, *tx;
-	int et;
-
-	if(t == T)
-		return t;
-	et = t->etype;
-	if(typesu[et])
-		return t;
-	tl = tcopy(t->link);
-	if(tl != t->link ||
-	  (et == TARRAY && t->width == 0)) {
-		tx = copytyp(t);
-		tx->link = tl;
-		return tx;
-	}
-	return t;
-}
-
-Node*
-doinit(Sym *s, Type *t, int32 o, Node *a)
-{
-	Node *n;
-
-	if(t == T)
-		return Z;
-	if(s->class == CEXTERN) {
-		s->class = CGLOBL;
-		if(debug['d'])
-			dbgdecl(s);
-	}
-	if(debug['i']) {
-		print("t = %T; o = %d; n = %s\n", t, o, s->name);
-		prtree(a, "doinit value");
-	}
-
-
-	n = initlist;
-	if(a->op == OINIT)
-		a = a->left;
-	initlist = a;
-
-	a = init1(s, t, o, 0);
-	if(initlist != Z)
-		diag(initlist, "more initializers than structure: %s",
-			s->name);
-	initlist = n;
-
-	return a;
-}
-
-/*
- * get next major operator,
- * dont advance initlist.
- */
-Node*
-peekinit(void)
-{
-	Node *a;
-
-	a = initlist;
-
-loop:
-	if(a == Z)
-		return a;
-	if(a->op == OLIST) {
-		a = a->left;
-		goto loop;
-	}
-	return a;
-}
-
-/*
- * consume and return next element on
- * initlist. expand strings.
- */
-Node*
-nextinit(void)
-{
-	Node *a, *b, *n;
-
-	a = initlist;
-	n = Z;
-
-	if(a == Z)
-		return a;
-	if(a->op == OLIST) {
-		n = a->right;
-		a = a->left;
-	}
-	if(a->op == OUSED) {
-		a = a->left;
-		b = new(OCONST, Z, Z);
-		b->type = a->type->link;
-		if(a->op == OSTRING) {
-			b->vconst = convvtox(*a->cstring, TCHAR);
-			a->cstring++;
-		}
-		if(a->op == OLSTRING) {
-			b->vconst = convvtox(*a->rstring, TRUNE);
-			a->rstring++;
-		}
-		a->type->width -= b->type->width;
-		if(a->type->width <= 0)
-			initlist = n;
-		return b;
-	}
-	initlist = n;
-	return a;
-}
-
-int
-isstruct(Node *a, Type *t)
-{
-	Node *n;
-
-	switch(a->op) {
-	case ODOTDOT:
-		n = a->left;
-		if(n && n->type && sametype(n->type, t))
-			return 1;
-	case OSTRING:
-	case OLSTRING:
-	case OCONST:
-	case OINIT:
-	case OELEM:
-		return 0;
-	}
-
-	n = new(ODOTDOT, Z, Z);
-	*n = *a;
-
-	/*
-	 * ODOTDOT is a flag for tcom
-	 * a second tcom will not be performed
-	 */
-	a->op = ODOTDOT;
-	a->left = n;
-	a->right = Z;
-
-	if(tcom(n))
-		return 0;
-
-	if(sametype(n->type, t))
-		return 1;
-	return 0;
-}
-
-Node*
-init1(Sym *s, Type *t, int32 o, int exflag)
-{
-	Node *a, *l, *r, nod;
-	Type *t1;
-	int32 e, w, so, mw;
-
-	a = peekinit();
-	if(a == Z)
-		return Z;
-
-	if(debug['i']) {
-		print("t = %T; o = %d; n = %s\n", t, o, s->name);
-		prtree(a, "init1 value");
-	}
-
-	if(exflag && a->op == OINIT)
-		return doinit(s, t, o, nextinit());
-
-	switch(t->etype) {
-	default:
-		diag(Z, "unknown type in initialization: %T to: %s", t, s->name);
-		return Z;
-
-	case TCHAR:
-	case TUCHAR:
-	case TINT:
-	case TUINT:
-	case TSHORT:
-	case TUSHORT:
-	case TLONG:
-	case TULONG:
-	case TVLONG:
-	case TUVLONG:
-	case TFLOAT:
-	case TDOUBLE:
-	case TIND:
-	single:
-		if(a->op == OARRAY || a->op == OELEM)
-			return Z;
-
-		a = nextinit();
-		if(a == Z)
-			return Z;
-
-		if(t->nbits)
-			diag(Z, "cannot initialize bitfields");
-		if(s->class == CAUTO) {
-			l = new(ONAME, Z, Z);
-			l->sym = s;
-			l->type = t;
-			l->etype = TVOID;
-			if(s->type)
-				l->etype = s->type->etype;
-			l->xoffset = s->offset + o;
-			l->class = s->class;
-
-			l = new(OASI, l, a);
-			return l;
-		}
-
-		complex(a);
-		if(a->type == T)
-			return Z;
-
-		if(a->op == OCONST) {
-			if(vconst(a) && t->etype == TIND && a->type && a->type->etype != TIND){
-				diag(a, "initialize pointer to an integer: %s", s->name);
-				return Z;
-			}
-			if(!sametype(a->type, t)) {
-				/* hoop jumping to save malloc */
-				if(nodcast == Z)
-					nodcast = new(OCAST, Z, Z);
-				nod = *nodcast;
-				nod.left = a;
-				nod.type = t;
-				nod.lineno = a->lineno;
-				complex(&nod);
-				if(nod.type)
-					*a = nod;
-			}
-			if(a->op != OCONST) {
-				diag(a, "initializer is not a constant: %s",
-					s->name);
-				return Z;
-			}
-			if(vconst(a) == 0)
-				return Z;
-			goto gext;
-		}
-		if(t->etype == TIND) {
-			while(a->op == OCAST) {
-				warn(a, "CAST in initialization ignored");
-				a = a->left;
-			}
-			if(!sametype(t, a->type)) {
-				diag(a, "initialization of incompatible pointers: %s\n%T and %T",
-					s->name, t, a->type);
-			}
-			if(a->op == OADDR)
-				a = a->left;
-			goto gext;
-		}
-
-		while(a->op == OCAST)
-			a = a->left;
-		if(a->op == OADDR) {
-			warn(a, "initialize pointer to an integer: %s", s->name);
-			a = a->left;
-			goto gext;
-		}
-		diag(a, "initializer is not a constant: %s", s->name);
-		return Z;
-
-	gext:
-		gextern(s, a, o, t->width);
-
-		return Z;
-
-	case TARRAY:
-		w = t->link->width;
-		if(a->op == OSTRING || a->op == OLSTRING)
-		if(typei[t->link->etype]) {
-			/*
-			 * get rid of null if sizes match exactly
-			 */
-			a = nextinit();
-			mw = t->width/w;
-			so = a->type->width/a->type->link->width;
-			if(mw && so > mw) {
-				if(so != mw+1)
-					diag(a, "string initialization larger than array");
-				a->type->width -= a->type->link->width;
-			}
-
-			/*
-			 * arrange strings to be expanded
-			 * inside OINIT braces.
-			 */
-			a = new(OUSED, a, Z);
-			return doinit(s, t, o, a);
-		}
-
-		mw = -w;
-		l = Z;
-		for(e=0;;) {
-			/*
-			 * peek ahead for element initializer
-			 */
-			a = peekinit();
-			if(a == Z)
-				break;
-			if(a->op == OELEM && t->link->etype != TSTRUCT)
-				break;
-			if(a->op == OARRAY) {
-				if(e && exflag)
-					break;
-				a = nextinit();
-				r = a->left;
-				complex(r);
-				if(r->op != OCONST) {
-					diag(r, "initializer subscript must be constant");
-					return Z;
-				}
-				e = r->vconst;
-				if(t->width != 0)
-					if(e < 0 || e*w >= t->width) {
-						diag(a, "initialization index out of range: %d", e);
-						continue;
-					}
-			}
-
-			so = e*w;
-			if(so > mw)
-				mw = so;
-			if(t->width != 0)
-				if(mw >= t->width)
-					break;
-			r = init1(s, t->link, o+so, 1);
-			l = newlist(l, r);
-			e++;
-		}
-		if(t->width == 0)
-			t->width = mw+w;
-		return l;
-
-	case TUNION:
-	case TSTRUCT:
-		/*
-		 * peek ahead to find type of rhs.
-		 * if its a structure, then treat
-		 * this element as a variable
-		 * rather than an aggregate.
-		 */
-		if(isstruct(a, t))
-			goto single;
-
-		if(t->width <= 0) {
-			diag(Z, "incomplete structure: %s", s->name);
-			return Z;
-		}
-		l = Z;
-
-	again:
-		for(t1 = t->link; t1 != T; t1 = t1->down) {
-			if(a->op == OARRAY && t1->etype != TARRAY)
-				break;
-			if(a->op == OELEM) {
-				if(t1->sym != a->sym)
-					continue;
-				nextinit();
-			}
-			r = init1(s, t1, o+t1->offset, 1);
-			l = newlist(l, r);
-			a = peekinit();
-			if(a == Z)
-				break;
-			if(a->op == OELEM)
-				goto again;
-		}
-		if(a && a->op == OELEM)
-			diag(a, "structure element not found %F", a);
-		return l;
-	}
-}
-
-Node*
-newlist(Node *l, Node *r)
-{
-	if(r == Z)
-		return l;
-	if(l == Z)
-		return r;
-	return new(OLIST, l, r);
-}
-
-static int
-haspointers(Type *t)
-{
-	Type *fld;
-
-	switch(t->etype) {
-	case TSTRUCT:
-		for(fld = t->link; fld != T; fld = fld->down) {
-			if(haspointers(fld))
-				return 1;
-		}
-		return 0;
-	case TARRAY:
-		return haspointers(t->link);
-	case TIND:
-		return t->link->etype != TFUNC;
-	default:
-		return 0;
-	}
-}
-
-void
-sualign(Type *t)
-{
-	Type *l;
-	int32 o, w, maxal;
-
-	o = 0;
-	maxal = 0;
-	switch(t->etype) {
-
-	case TSTRUCT:
-		t->offset = 0;
-		w = 0;
-		for(l = t->link; l != T; l = l->down) {
-			if(l->nbits) {
-				if(l->shift <= 0) {
-					l->shift = -l->shift;
-					w = xround(w, tfield->width);
-					o = w;
-					w += tfield->width;
-				}
-				l->offset = o;
-			} else {
-				if(l->width <= 0)
-				if(l->down != T)
-					if(l->sym)
-						diag(Z, "incomplete structure element: %s",
-							l->sym->name);
-					else
-						diag(Z, "incomplete structure element");
-				w = align(w, l, Ael1, &maxal);
-				l->offset = w;
-				w = align(w, l, Ael2, &maxal);
-			}
-		}
-		w = align(w, t, Asu2, &maxal);
-		t->width = w;
-		t->align = maxal;
-		acidtype(t);
-		godeftype(t);
-		return;
-
-	case TUNION:
-		t->offset = 0;
-		w = 0;
-		for(l = t->link; l != T; l = l->down) {
-			if(l->width <= 0)
-				if(l->sym)
-					diag(Z, "incomplete union element: %s",
-						l->sym->name);
-				else
-					diag(Z, "incomplete union element");
-			l->offset = 0;
-			l->shift = 0;
-			if((debug['q'] || debug['Q']) && haspointers(l))
-				diag(Z, "precise garbage collector cannot handle unions with pointers");
-
-			o = align(align(0, l, Ael1, &maxal), l, Ael2, &maxal);
-			if(o > w)
-				w = o;
-		}
-		w = align(w, t, Asu2, &maxal);
-		t->width = w;
-		t->align = maxal;
-		acidtype(t);
-		godeftype(t);
-		return;
-
-	default:
-		diag(Z, "unknown type in sualign: %T", t);
-		break;
-	}
-}
-
-int32
-xround(int32 v, int w)
-{
-	int r;
-
-	if(w <= 0 || w > 8) {
-		diag(Z, "rounding by %d", w);
-		w = 1;
-	}
-	r = v%w;
-	if(r)
-		v += w-r;
-	return v;
-}
-
-Type*
-ofnproto(Node *n)
-{
-	Type *tl, *tr, *t;
-
-	if(n == Z)
-		return T;
-	switch(n->op) {
-	case OLIST:
-		tl = ofnproto(n->left);
-		tr = ofnproto(n->right);
-		if(tl == T)
-			return tr;
-		tl->down = tr;
-		return tl;
-
-	case ONAME:
-		t = copytyp(n->sym->type);
-		t->down = T;
-		return t;
-	}
-	return T;
-}
-
-#define	ANSIPROTO	1
-#define	OLDPROTO	2
-
-void
-argmark(Node *n, int pass)
-{
-	Type *t;
-
-	if(hasdotdotdot(thisfn->link))
-		autoffset = align(0, thisfn->link, Aarg0, nil);
-	stkoff = 0;
-	for(; n->left != Z; n = n->left) {
-		if(n->op != OFUNC || n->left->op != ONAME)
-			continue;
-		walkparam(n->right, pass);
-		if(pass != 0 && anyproto(n->right) == OLDPROTO) {
-			t = typ(TFUNC, n->left->sym->type->link);
-			t->down = typ(TOLD, T);
-			t->down->down = ofnproto(n->right);
-			tmerge(t, n->left->sym);
-			n->left->sym->type = t;
-		}
-		break;
-	}
-	autoffset = 0;
-	stkoff = 0;
-}
-
-void
-walkparam(Node *n, int pass)
-{
-	Sym *s;
-	Node *n1;
-
-	if(n != Z && n->op == OPROTO && n->left == Z && n->type == types[TVOID])
-		return;
-
-loop:
-	if(n == Z)
-		return;
-	switch(n->op) {
-	default:
-		diag(n, "argument not a name/prototype: %O", n->op);
-		break;
-
-	case OLIST:
-		walkparam(n->left, pass);
-		n = n->right;
-		goto loop;
-
-	case OPROTO:
-		for(n1 = n; n1 != Z; n1=n1->left)
-			if(n1->op == ONAME) {
-				if(pass == 0) {
-					s = n1->sym;
-					push1(s);
-					s->offset = -1;
-					break;
-				}
-				dodecl(pdecl, CPARAM, n->type, n->left);
-				break;
-			}
-		if(n1)
-			break;
-		if(pass == 0) {
-			/*
-			 * extension:
-			 *	allow no name in argument declaration
-			diag(Z, "no name in argument declaration");
-			 */
-			break;
-		}
-		dodecl(NODECL, CPARAM, n->type, n->left);
-		pdecl(CPARAM, lastdcl, S);
-		break;
-
-	case ODOTDOT:
-		break;
-	
-	case ONAME:
-		s = n->sym;
-		if(pass == 0) {
-			push1(s);
-			s->offset = -1;
-			break;
-		}
-		if(s->offset != -1) {
-			if(autoffset == 0) {
-				firstarg = s;
-				firstargtype = s->type;
-			}
-			autoffset = align(autoffset, s->type, Aarg1, nil);
-			s->offset = autoffset;
-			autoffset = align(autoffset, s->type, Aarg2, nil);
-		} else
-			dodecl(pdecl, CXXX, types[TINT], n);
-		break;
-	}
-}
-
-void
-markdcl(void)
-{
-	Decl *d;
-
-	blockno++;
-	d = push();
-	d->val = DMARK;
-	d->offset = autoffset;
-	d->block = autobn;
-	autobn = blockno;
-}
-
-Node*
-revertdcl(void)
-{
-	Decl *d;
-	Sym *s;
-	Node *n, *n1;
-
-	n = Z;
-	for(;;) {
-		d = dclstack;
-		if(d == D) {
-			diag(Z, "pop off dcl stack");
-			break;
-		}
-		dclstack = d->link;
-		s = d->sym;
-		switch(d->val) {
-		case DMARK:
-			autoffset = d->offset;
-			autobn = d->block;
-			return n;
-
-		case DAUTO:
-			if(debug['d'])
-				print("revert1 \"%s\"\n", s->name);
-			if(s->aused == 0) {
-				nearln = s->varlineno;
-				if(s->class == CAUTO)
-					warn(Z, "auto declared and not used: %s", s->name);
-				if(s->class == CPARAM)
-					warn(Z, "param declared and not used: %s", s->name);
-			}
-			if(s->type && (s->type->garb & GVOLATILE)) {
-				n1 = new(ONAME, Z, Z);
-				n1->sym = s;
-				n1->type = s->type;
-				n1->etype = TVOID;
-				if(n1->type != T)
-					n1->etype = n1->type->etype;
-				n1->xoffset = s->offset;
-				n1->class = s->class;
-
-				n1 = new(OADDR, n1, Z);
-				n1 = new(OUSED, n1, Z);
-				if(n == Z)
-					n = n1;
-				else
-					n = new(OLIST, n1, n);
-			}
-			s->type = d->type;
-			s->class = d->class;
-			s->offset = d->offset;
-			s->block = d->block;
-			s->varlineno = d->varlineno;
-			s->aused = d->aused;
-			break;
-
-		case DSUE:
-			if(debug['d'])
-				print("revert2 \"%s\"\n", s->name);
-			s->suetag = d->type;
-			s->sueblock = d->block;
-			break;
-
-		case DLABEL:
-			if(debug['d'])
-				print("revert3 \"%s\"\n", s->name);
-			if(s->label && s->label->addable == 0)
-				warn(s->label, "label declared and not used \"%s\"", s->name);
-			s->label = Z;
-			break;
-		}
-	}
-	return n;
-}
-
-Type*
-fnproto(Node *n)
-{
-	int r;
-
-	r = anyproto(n->right);
-	if(r == 0 || (r & OLDPROTO)) {
-		if(r & ANSIPROTO)
-			diag(n, "mixed ansi/old function declaration: %F", n->left);
-		return T;
-	}
-	return fnproto1(n->right);
-}
-
-int
-anyproto(Node *n)
-{
-	int r;
-
-	r = 0;
-
-loop:
-	if(n == Z)
-		return r;
-	switch(n->op) {
-	case OLIST:
-		r |= anyproto(n->left);
-		n = n->right;
-		goto loop;
-
-	case ODOTDOT:
-	case OPROTO:
-		return r | ANSIPROTO;
-	}
-	return r | OLDPROTO;
-}
-
-Type*
-fnproto1(Node *n)
-{
-	Type *t;
-
-	if(n == Z)
-		return T;
-	switch(n->op) {
-	case OLIST:
-		t = fnproto1(n->left);
-		if(t != T)
-			t->down = fnproto1(n->right);
-		return t;
-
-	case OPROTO:
-		lastdcl = T;
-		dodecl(NODECL, CXXX, n->type, n->left);
-		t = typ(TXXX, T);
-		if(lastdcl != T)
-			*t = *paramconv(lastdcl, 1);
-		return t;
-
-	case ONAME:
-		diag(n, "incomplete argument prototype");
-		return typ(TINT, T);
-
-	case ODOTDOT:
-		return typ(TDOT, T);
-	}
-	diag(n, "unknown op in fnproto");
-	return T;
-}
-
-void
-dbgdecl(Sym *s)
-{
-	print("decl \"%s\": C=%s [B=%d:O=%d] T=%T\n",
-		s->name, cnames[s->class], s->block, s->offset, s->type);
-}
-
-Decl*
-push(void)
-{
-	Decl *d;
-
-	d = alloc(sizeof(*d));
-	d->link = dclstack;
-	dclstack = d;
-	return d;
-}
-
-Decl*
-push1(Sym *s)
-{
-	Decl *d;
-
-	d = push();
-	d->sym = s;
-	d->val = DAUTO;
-	d->type = s->type;
-	d->class = s->class;
-	d->offset = s->offset;
-	d->block = s->block;
-	d->varlineno = s->varlineno;
-	d->aused = s->aused;
-	return d;
-}
-
-int
-sametype(Type *t1, Type *t2)
-{
-
-	if(t1 == t2)
-		return 1;
-	return rsametype(t1, t2, 5, 1);
-}
-
-int
-rsametype(Type *t1, Type *t2, int n, int f)
-{
-	int et;
-
-	n--;
-	for(;;) {
-		if(t1 == t2)
-			return 1;
-		if(t1 == T || t2 == T)
-			return 0;
-		if(n <= 0)
-			return 1;
-		et = t1->etype;
-		if(et != t2->etype)
-			return 0;
-		if(et == TFUNC) {
-			if(!rsametype(t1->link, t2->link, n, 0))
-				return 0;
-			t1 = t1->down;
-			t2 = t2->down;
-			while(t1 != T && t2 != T) {
-				if(t1->etype == TOLD) {
-					t1 = t1->down;
-					continue;
-				}
-				if(t2->etype == TOLD) {
-					t2 = t2->down;
-					continue;
-				}
-				while(t1 != T || t2 != T) {
-					if(!rsametype(t1, t2, n, 0))
-						return 0;
-					t1 = t1->down;
-					t2 = t2->down;
-				}
-				break;
-			}
-			return 1;
-		}
-		if(et == TARRAY)
-			if(t1->width != t2->width && t1->width != 0 && t2->width != 0)
-				return 0;
-		if(typesu[et]) {
-			if(t1->link == T)
-				snap(t1);
-			if(t2->link == T)
-				snap(t2);
-			t1 = t1->link;
-			t2 = t2->link;
-			for(;;) {
-				if(t1 == t2)
-					return 1;
-				if(!rsametype(t1, t2, n, 0))
-					return 0;
-				t1 = t1->down;
-				t2 = t2->down;
-			}
-		}
-		t1 = t1->link;
-		t2 = t2->link;
-		if((f || !debug['V']) && et == TIND) {
-			if(t1 != T && t1->etype == TVOID)
-				return 1;
-			if(t2 != T && t2->etype == TVOID)
-				return 1;
-		}
-	}
-}
-
-typedef struct Typetab Typetab;
-
-struct Typetab{
-	int n;
-	Type **a;
-};
-
-static int
-sigind(Type *t, Typetab *tt)
-{
-	int n;
-	Type **a, **na, **p, **e;
-
-	n = tt->n;
-	a = tt->a;
-	e = a+n;
-	/* linear search seems ok */
-	for(p = a ; p < e; p++)
-		if(sametype(*p, t))
-			return p-a;
-	if((n&15) == 0){
-		na = malloc((n+16)*sizeof(Type*));
-		if(na == nil) {
-			print("%s: out of memory", argv0);
-			errorexit();
-		}
-		memmove(na, a, n*sizeof(Type*));
-		free(a);
-		a = tt->a = na;
-	}
-	a[tt->n++] = t;
-	return -1;
-}
-
-static uint32
-signat(Type *t, Typetab *tt)
-{
-	int i;
-	Type *t1;
-	int32 s;
-
-	s = 0;
-	for(; t; t=t->link) {
-		s = s*thash1 + thash[t->etype];
-		if(t->garb&GINCOMPLETE)
-			return s;
-		switch(t->etype) {
-		default:
-			return s;
-		case TARRAY:
-			s = s*thash2 + 0;	/* was t->width */
-			break;
-		case TFUNC:
-			for(t1=t->down; t1; t1=t1->down)
-				s = s*thash3 + signat(t1, tt);
-			break;
-		case TSTRUCT:
-		case TUNION:
-			if((i = sigind(t, tt)) >= 0){
-				s = s*thash2 + i;
-				return s;
-			}
-			for(t1=t->link; t1; t1=t1->down)
-				s = s*thash3 + signat(t1, tt);
-			return s;
-		case TIND:
-			break;
-		}
-	}
-	return s;
-}
-
-uint32
-signature(Type *t)
-{
-	uint32 s;
-	Typetab tt;
-
-	tt.n = 0;
-	tt.a = nil;
-	s = signat(t, &tt);
-	free(tt.a);
-	return s;
-}
-
-uint32
-sign(Sym *s)
-{
-	uint32 v;
-	Type *t;
-
-	if(s->sig == SIGINTERN)
-		return SIGNINTERN;
-	if((t = s->type) == T)
-		return 0;
-	v = signature(t);
-	if(v == 0)
-		v = SIGNINTERN;
-	return v;
-}
-
-void
-snap(Type *t)
-{
-	if(typesu[t->etype])
-	if(t->link == T && t->tag && t->tag->suetag) {
-		t->link = t->tag->suetag->link;
-		t->width = t->tag->suetag->width;
-	}
-}
-
-Type*
-dotag(Sym *s, int et, int bn)
-{
-	Decl *d;
-
-	if(bn != 0 && bn != s->sueblock) {
-		d = push();
-		d->sym = s;
-		d->val = DSUE;
-		d->type = s->suetag;
-		d->block = s->sueblock;
-		s->suetag = T;
-	}
-	if(s->suetag == T) {
-		s->suetag = typ(et, T);
-		s->sueblock = autobn;
-	}
-	if(s->suetag->etype != et)
-		diag(Z, "tag used for more than one type: %s",
-			s->name);
-	if(s->suetag->tag == S)
-		s->suetag->tag = s;
-	return s->suetag;
-}
-
-Node*
-dcllabel(Sym *s, int f)
-{
-	Decl *d, d1;
-	Node *n;
-
-	n = s->label;
-	if(n != Z) {
-		if(f) {
-			if(n->complex)
-				diag(Z, "label reused: %s", s->name);
-			n->complex = 1;	// declared
-		} else
-			n->addable = 1;	// used
-		return n;
-	}
-
-	d = push();
-	d->sym = s;
-	d->val = DLABEL;
-	dclstack = d->link;
-
-	d1 = *firstdcl;
-	*firstdcl = *d;
-	*d = d1;
-
-	firstdcl->link = d;
-	firstdcl = d;
-
-	n = new(OXXX, Z, Z);
-	n->sym = s;
-	n->complex = f;
-	n->addable = !f;
-	s->label = n;
-
-	if(debug['d'])
-		dbgdecl(s);
-	return n;
-}
-
-Type*
-paramconv(Type *t, int f)
-{
-
-	switch(t->etype) {
-	case TUNION:
-	case TSTRUCT:
-		if(t->width <= 0)
-			diag(Z, "incomplete structure: %s", t->tag->name);
-		break;
-
-	case TARRAY:
-		t = typ(TIND, t->link);
-		t->width = types[TIND]->width;
-		break;
-
-	case TFUNC:
-		t = typ(TIND, t);
-		t->width = types[TIND]->width;
-		break;
-
-	case TFLOAT:
-		if(!f)
-			t = types[TDOUBLE];
-		break;
-
-	case TCHAR:
-	case TSHORT:
-		if(!f)
-			t = types[TINT];
-		break;
-
-	case TUCHAR:
-	case TUSHORT:
-		if(!f)
-			t = types[TUINT];
-		break;
-	}
-	return t;
-}
-
-void
-adecl(int c, Type *t, Sym *s)
-{
-
-	if(c == CSTATIC)
-		c = CLOCAL;
-	if(t->etype == TFUNC) {
-		if(c == CXXX)
-			c = CEXTERN;
-		if(c == CLOCAL)
-			c = CSTATIC;
-		if(c == CAUTO || c == CEXREG)
-			diag(Z, "function cannot be %s %s", cnames[c], s->name);
-	}
-	if(c == CXXX)
-		c = CAUTO;
-	if(s) {
-		if(s->class == CSTATIC)
-			if(c == CEXTERN || c == CGLOBL) {
-				warn(Z, "just say static: %s", s->name);
-				c = CSTATIC;
-			}
-		if(s->class == CAUTO || s->class == CPARAM || s->class == CLOCAL)
-		if(s->block == autobn)
-			diag(Z, "auto redeclaration of: %s", s->name);
-		if(c != CPARAM)
-			push1(s);
-		s->block = autobn;
-		s->offset = 0;
-		s->type = t;
-		s->class = c;
-		s->aused = 0;
-	}
-	switch(c) {
-	case CAUTO:
-		autoffset = align(autoffset, t, Aaut3, nil);
-		stkoff = maxround(stkoff, autoffset);
-		s->offset = -autoffset;
-		break;
-
-	case CPARAM:
-		if(autoffset == 0) {
-			firstarg = s;
-			firstargtype = t;
-		}
-		autoffset = align(autoffset, t, Aarg1, nil);
-		if(s)
-			s->offset = autoffset;
-		autoffset = align(autoffset, t, Aarg2, nil);
-		break;
-	}
-}
-
-void
-pdecl(int c, Type *t, Sym *s)
-{
-	if(s && s->offset != -1) {
-		diag(Z, "not a parameter: %s", s->name);
-		return;
-	}
-	t = paramconv(t, c==CPARAM);
-	if(c == CXXX)
-		c = CPARAM;
-	if(c != CPARAM) {
-		diag(Z, "parameter cannot have class: %s", s->name);
-		c = CPARAM;
-	}
-	adecl(c, t, s);
-}
-
-void
-xdecl(int c, Type *t, Sym *s)
-{
-	int32 o;
-
-	o = 0;
-	switch(c) {
-	case CEXREG:
-		o = exreg(t);
-		if(o == 0)
-			c = CEXTERN;
-		if(s->class == CGLOBL)
-			c = CGLOBL;
-		break;
-
-	case CEXTERN:
-		if(s->class == CGLOBL)
-			c = CGLOBL;
-		break;
-
-	case CXXX:
-		c = CGLOBL;
-		if(s->class == CEXTERN)
-			s->class = CGLOBL;
-		break;
-
-	case CAUTO:
-		diag(Z, "overspecified class: %s %s %s", s->name, cnames[c], cnames[s->class]);
-		c = CEXTERN;
-		break;
-
-	case CTYPESTR:
-		if(!typesuv[t->etype]) {
-			diag(Z, "typestr must be struct/union: %s", s->name);
-			break;
-		}
-		dclfunct(t, s);
-		break;
-	}
-
-	if(s->class == CSTATIC)
-		if(c == CEXTERN || c == CGLOBL) {
-			warn(Z, "overspecified class: %s %s %s", s->name, cnames[c], cnames[s->class]);
-			c = CSTATIC;
-		}
-	if(s->type != T)
-		if(s->class != c || !sametype(t, s->type) || t->etype == TENUM) {
-			diag(Z, "external redeclaration of: %s", s->name);
-			Bprint(&diagbuf, "	%s %T %L\n", cnames[c], t, nearln);
-			Bprint(&diagbuf, "	%s %T %L\n", cnames[s->class], s->type, s->varlineno);
-		}
-	tmerge(t, s);
-	s->type = t;
-	if(c == CTYPEDEF && (typechlv[t->etype] || typefd[t->etype])) {
-		s->type = copytyp(t);
-		s->type->tag = s;
-	}
-	s->class = c;
-	s->block = 0;
-	s->offset = o;
-}
-
-void
-tmerge(Type *t1, Sym *s)
-{
-	Type *ta, *tb, *t2;
-
-	t2 = s->type;
-	for(;;) {
-		if(t1 == T || t2 == T || t1 == t2)
-			break;
-		if(t1->etype != t2->etype)
-			break;
-		switch(t1->etype) {
-		case TFUNC:
-			ta = t1->down;
-			tb = t2->down;
-			if(ta == T) {
-				t1->down = tb;
-				break;
-			}
-			if(tb == T)
-				break;
-			while(ta != T && tb != T) {
-				if(ta == tb)
-					break;
-				/* ignore old-style flag */
-				if(ta->etype == TOLD) {
-					ta = ta->down;
-					continue;
-				}
-				if(tb->etype == TOLD) {
-					tb = tb->down;
-					continue;
-				}
-				/* checking terminated by ... */
-				if(ta->etype == TDOT && tb->etype == TDOT) {
-					ta = T;
-					tb = T;
-					break;
-				}
-				if(!sametype(ta, tb))
-					break;
-				ta = ta->down;
-				tb = tb->down;
-			}
-			if(ta != tb)
-				diag(Z, "function inconsistently declared: %s", s->name);
-
-			/* take new-style over old-style */
-			ta = t1->down;
-			tb = t2->down;
-			if(ta != T && ta->etype == TOLD)
-				if(tb != T && tb->etype != TOLD)
-					t1->down = tb;
-			break;
-
-		case TARRAY:
-			/* should we check array size change? */
-			if(t2->width > t1->width)
-				t1->width = t2->width;
-			break;
-
-		case TUNION:
-		case TSTRUCT:
-			return;
-		}
-		t1 = t1->link;
-		t2 = t2->link;
-	}
-}
-
-void
-edecl(int c, Type *t, Sym *s)
-{
-	Type *t1;
-
-	if(s == S)
-		diag(Z, "unnamed structure elements not supported");
-	else
-		if(c != CXXX)
-			diag(Z, "structure element cannot have class: %s", s->name);
-	t1 = t;
-	t = copytyp(t1);
-	t->sym = s;
-	t->down = T;
-	if(lastfield) {
-		t->shift = lastbit - lastfield;
-		t->nbits = lastfield;
-		if(firstbit)
-			t->shift = -t->shift;
-		if(typeu[t->etype])
-			t->etype = tufield->etype;
-		else
-			t->etype = tfield->etype;
-	}
-	if(strf == T)
-		strf = t;
-	else
-		strl->down = t;
-	strl = t;
-}
-
-/*
- * this routine is very suspect.
- * ansi requires the enum type to
- * be represented as an 'int'
- * this means that 0x81234567
- * would be illegal. this routine
- * makes signed and unsigned go
- * to unsigned.
- */
-Type*
-maxtype(Type *t1, Type *t2)
-{
-
-	if(t1 == T)
-		return t2;
-	if(t2 == T)
-		return t1;
-	if(t1->etype > t2->etype)
-		return t1;
-	return t2;
-}
-
-void
-doenum(Sym *s, Node *n)
-{
-
-	if(n) {
-		complex(n);
-		if(n->op != OCONST) {
-			diag(n, "enum not a constant: %s", s->name);
-			return;
-		}
-		en.cenum = n->type;
-		en.tenum = maxtype(en.cenum, en.tenum);
-
-		if(!typefd[en.cenum->etype])
-			en.lastenum = n->vconst;
-		else
-			en.floatenum = n->fconst;
-	}
-	if(dclstack)
-		push1(s);
-	xdecl(CXXX, types[TENUM], s);
-
-	if(en.cenum == T) {
-		en.tenum = types[TINT];
-		en.cenum = types[TINT];
-		en.lastenum = 0;
-	}
-	s->tenum = en.cenum;
-
-	if(!typefd[s->tenum->etype]) {
-		s->vconst = convvtox(en.lastenum, s->tenum->etype);
-		en.lastenum++;
-	} else {
-		s->fconst = en.floatenum;
-		en.floatenum++;
-	}
-
-	if(debug['d'])
-		dbgdecl(s);
-	acidvar(s);
-	godefvar(s);
-}
-
-void
-symadjust(Sym *s, Node *n, int32 del)
-{
-
-	switch(n->op) {
-	default:
-		if(n->left)
-			symadjust(s, n->left, del);
-		if(n->right)
-			symadjust(s, n->right, del);
-		return;
-
-	case ONAME:
-		if(n->sym == s)
-			n->xoffset -= del;
-		return;
-
-	case OCONST:
-	case OSTRING:
-	case OLSTRING:
-	case OINDREG:
-	case OREGISTER:
-		return;
-	}
-}
-
-Node*
-contig(Sym *s, Node *n, int32 v)
-{
-	Node *p, *r, *q, *m;
-	int32 w;
-	Type *zt;
-
-	if(debug['i']) {
-		print("contig v = %d; s = %s\n", v, s->name);
-		prtree(n, "doinit value");
-	}
-
-	if(n == Z)
-		goto no;
-	w = s->type->width;
-
-	/*
-	 * nightmare: an automatic array whose size
-	 * increases when it is initialized
-	 */
-	if(v != w) {
-		if(v != 0)
-			diag(n, "automatic adjustable array: %s", s->name);
-		v = s->offset;
-		autoffset = align(autoffset, s->type, Aaut3, nil);
-		s->offset = -autoffset;
-		stkoff = maxround(stkoff, autoffset);
-		symadjust(s, n, v - s->offset);
-	}
-	if(w <= ewidth[TIND])
-		goto no;
-	if(n->op == OAS)
-		diag(Z, "oops in contig");
-/*ZZZ this appears incorrect
-need to check if the list completely covers the data.
-if not, bail
- */
-	if(n->op == OLIST)
-		goto no;
-	if(n->op == OASI)
-		if(n->left->type)
-		if(n->left->type->width == w)
-			goto no;
-	while(w & (ewidth[TIND]-1))
-		w++;
-/*
- * insert the following code, where long becomes vlong if pointers are fat
- *
-	*(long**)&X = (long*)((char*)X + sizeof(X));
-	do {
-		*(long**)&X -= 1;
-		**(long**)&X = 0;
-	} while(*(long**)&X);
- */
-
-	for(q=n; q->op != ONAME; q=q->left)
-		;
-
-	zt = ewidth[TIND] > ewidth[TLONG]? types[TVLONG]: types[TLONG];
-
-	p = new(ONAME, Z, Z);
-	*p = *q;
-	p->type = typ(TIND, zt);
-	p->xoffset = s->offset;
-
-	r = new(ONAME, Z, Z);
-	*r = *p;
-	r = new(OPOSTDEC, r, Z);
-
-	q = new(ONAME, Z, Z);
-	*q = *p;
-	q = new(OIND, q, Z);
-
-	m = new(OCONST, Z, Z);
-	m->vconst = 0;
-	m->type = zt;
-
-	q = new(OAS, q, m);
-
-	r = new(OLIST, r, q);
-
-	q = new(ONAME, Z, Z);
-	*q = *p;
-	r = new(ODWHILE, q, r);
-
-	q = new(ONAME, Z, Z);
-	*q = *p;
-	q->type = q->type->link;
-	q->xoffset += w;
-	q = new(OADDR, q, 0);
-
-	q = new(OASI, p, q);
-	r = new(OLIST, q, r);
-
-	n = new(OLIST, r, n);
-
-no:
-	return n;
-}
diff --git a/src/cmd/cc/doc.go b/src/cmd/cc/doc.go
deleted file mode 100644
index 10901b4..0000000
--- a/src/cmd/cc/doc.go
+++ /dev/null
@@ -1,13 +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.
-
-// +build ignore
-
-/*
-
-This directory contains the portable section of the Plan 9 C compilers.
-See ../6c, ../8c, and ../5c for more information.
-
-*/
-package main
diff --git a/src/cmd/cc/dpchk.c b/src/cmd/cc/dpchk.c
deleted file mode 100644
index 606bf40..0000000
--- a/src/cmd/cc/dpchk.c
+++ /dev/null
@@ -1,793 +0,0 @@
-// Inferno utils/cc/dpchk.c
-// http://code.google.com/p/inferno-os/source/browse/utils/cc/dpchk.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include	<u.h>
-#include	"cc.h"
-#include	"y.tab.h"
-
-enum
-{
-	Fnone	= 0,
-	Fl,
-	Fvl,
-	Fignor,
-	Fstar,
-	Fadj,
-
-	Fverb	= 10,
-};
-
-typedef	struct	Tprot	Tprot;
-struct	Tprot
-{
-	Type*	type;
-	Bits	flag;
-	Tprot*	link;
-};
-
-typedef	struct	Tname	Tname;
-struct	Tname
-{
-	char*	name;
-	int	param;
-	int	count;
-	Tname*	link;
-	Tprot*	prot;
-};
-
-static	Type*	indchar;
-static	uchar	flagbits[512];
-static	char*	lastfmt;
-static	int	lastadj;
-static	int	lastverb;
-static	int	nstar;
-static	Tprot*	tprot;
-static	Tname*	tname;
-
-void
-argflag(int c, int v)
-{
-
-	switch(v) {
-	case Fignor:
-	case Fstar:
-	case Fl:
-	case Fvl:
-		flagbits[c] = v;
-		break;
-	case Fverb:
-		flagbits[c] = lastverb;
-/*print("flag-v %c %d\n", c, lastadj);*/
-		lastverb++;
-		break;
-	case Fadj:
-		flagbits[c] = lastadj;
-/*print("flag-l %c %d\n", c, lastadj);*/
-		lastadj++;
-		break;
-	}
-}
-
-Bits
-getflag(char *s)
-{
-	Bits flag;
-	int f;
-	Fmt fmt;
-	Rune c;
-
-	flag = zbits;
-	nstar = 0;
-	fmtstrinit(&fmt);
-	for(;;) {
-		s += chartorune(&c, s);
-		if(c == 0 || c >= nelem(flagbits))
-			break;
-		fmtrune(&fmt, c);
-		f = flagbits[c];
-		switch(f) {
-		case Fnone:
-			argflag(c, Fverb);
-			f = flagbits[c];
-			break;
-		case Fstar:
-			nstar++;
-		case Fignor:
-			continue;
-		case Fl:
-			if(bset(flag, Fl))
-				flag = bor(flag, blsh(Fvl));
-		}
-		flag = bor(flag, blsh(f));
-		if(f >= Fverb)
-			break;
-	}
-	free(lastfmt);
-	lastfmt = fmtstrflush(&fmt);
-	return flag;
-}
-
-static void
-newprot(Sym *m, Type *t, char *s, Tprot **prot)
-{
-	Bits flag;
-	Tprot *l;
-
-	if(t == T) {
-		warn(Z, "%s: newprot: type not defined", m->name);
-		return;
-	}
-	flag = getflag(s);
-	for(l=*prot; l; l=l->link)
-		if(beq(flag, l->flag) && sametype(t, l->type))
-			return;
-	l = alloc(sizeof(*l));
-	l->type = t;
-	l->flag = flag;
-	l->link = *prot;
-	*prot = l;
-}
-
-static Tname*
-newname(char *s, int p, int count)
-{
-	Tname *l;
-
-	for(l=tname; l; l=l->link)
-		if(strcmp(l->name, s) == 0) {
-			if(p >= 0 && l->param != p)
-				yyerror("vargck %s already defined\n", s);
-			return l;
-		}
-	if(p < 0)
-		return nil;
-
-	l = alloc(sizeof(*l));
-	l->name = s;
-	l->param = p;
-	l->link = tname;
-	l->count = count;
-	tname = l;
-	return l;
-}
-
-void
-arginit(void)
-{
-	int i;
-
-/* debug['F'] = 1;*/
-/* debug['w'] = 1;*/
-
-	lastadj = Fadj;
-	lastverb = Fverb;
-	indchar = typ(TIND, types[TCHAR]);
-
-	memset(flagbits, Fnone, sizeof(flagbits));
-
-	for(i='0'; i<='9'; i++)
-		argflag(i, Fignor);
-	argflag('.', Fignor);
-	argflag('#', Fignor);
-	argflag('u', Fignor);
-	argflag('h', Fignor);
-	argflag('+', Fignor);
-	argflag('-', Fignor);
-
-	argflag('*', Fstar);
-	argflag('l', Fl);
-
-	argflag('o', Fverb);
-	flagbits['x'] = flagbits['o'];
-	flagbits['X'] = flagbits['o'];
-}
-
-static char*
-getquoted(void)
-{
-	int c;
-	Rune r;
-	Fmt fmt;
-
-	c = getnsc();
-	if(c != '"')
-		return nil;
-	fmtstrinit(&fmt);
-	for(;;) {
-		r = getr();
-		if(r == '\n') {
-			free(fmtstrflush(&fmt));
-			return nil;
-		}
-		if(r == '"')
-			break;
-		fmtrune(&fmt, r);
-	}
-	free(lastfmt);
-	lastfmt = fmtstrflush(&fmt);
-	return strdup(lastfmt);
-}
-
-void
-pragvararg(void)
-{
-	Sym *s;
-	int n, c;
-	char *t;
-	Type *ty;
-	Tname *l;
-
-	if(!debug['F'])
-		goto out;
-	s = getsym();
-	if(s && strcmp(s->name, "argpos") == 0)
-		goto ckpos;
-	if(s && strcmp(s->name, "type") == 0)
-		goto cktype;
-	if(s && strcmp(s->name, "flag") == 0)
-		goto ckflag;
-	if(s && strcmp(s->name, "countpos") == 0)
-		goto ckcount;
-	yyerror("syntax in #pragma varargck");
-	goto out;
-
-ckpos:
-/*#pragma	varargck	argpos	warn	2*/
-	s = getsym();
-	if(s == S)
-		goto bad;
-	n = getnsn();
-	if(n < 0)
-		goto bad;
-	newname(s->name, n, 0);
-	goto out;
-
-ckcount:
-/*#pragma	varargck	countpos	name 2*/
-	s = getsym();
-	if(s == S)
-		goto bad;
-	n = getnsn();
-	if(n < 0)
-		goto bad;
-	newname(s->name, 0, n);
-	goto out;
-
-ckflag:
-/*#pragma	varargck	flag	'c'*/
-	c = getnsc();
-	if(c != '\'')
-		goto bad;
-	c = getr();
-	if(c == '\\')
-		c = getr();
-	else if(c == '\'')
-		goto bad;
-	if(c == '\n')
-		goto bad;
-	if(getc() != '\'')
-		goto bad;
-	argflag(c, Fignor);
-	goto out;
-
-cktype:
-	c = getnsc();
-	unget(c);
-	if(c != '"') {
-/*#pragma	varargck	type	name	int*/
-		s = getsym();
-		if(s == S)
-			goto bad;
-		l = newname(s->name, -1, -1);
-		s = getsym();
-		if(s == S)
-			goto bad;
-		ty = s->type;
-		while((c = getnsc()) == '*')
-			ty = typ(TIND, ty);
-		unget(c);
-		newprot(s, ty, "a", &l->prot);
-		goto out;
-	}
-
-/*#pragma	varargck	type	O	int*/
-	t = getquoted();
-	if(t == nil)
-		goto bad;
-	s = getsym();
-	if(s == S)
-		goto bad;
-	ty = s->type;
-	while((c = getnsc()) == '*')
-		ty = typ(TIND, ty);
-	unget(c);
-	newprot(s, ty, t, &tprot);
-	goto out;
-
-bad:
-	yyerror("syntax in #pragma varargck");
-
-out:
-	while(getnsc() != '\n')
-		;
-}
-
-Node*
-nextarg(Node *n, Node **a)
-{
-	if(n == Z) {
-		*a = Z;
-		return Z;
-	}
-	if(n->op == OLIST) {
-		*a = n->left;
-		return n->right;
-	}
-	*a = n;
-	return Z;
-}
-
-void
-checkargs(Node *nn, char *s, int pos)
-{
-	Node *a, *n;
-	Bits flag;
-	Tprot *l;
-
-	if(!debug['F'])
-		return;
-	n = nn;
-	for(;;) {
-		s = strchr(s, '%');
-		if(s == 0) {
-			nextarg(n, &a);
-			if(a != Z)
-				warn(nn, "more arguments than format %T",
-					a->type);
-			return;
-		}
-		s++;
-		flag = getflag(s);
-		while(nstar > 0) {
-			n = nextarg(n, &a);
-			pos++;
-			nstar--;
-			if(a == Z) {
-				warn(nn, "more format than arguments %s",
-					lastfmt);
-				return;
-			}
-			if(a->type == T)
-				continue;
-			if(!sametype(types[TINT], a->type) &&
-			   !sametype(types[TUINT], a->type))
-				warn(nn, "format mismatch '*' in %s %T, arg %d",
-					lastfmt, a->type, pos);
-		}
-		for(l=tprot; l; l=l->link)
-			if(sametype(types[TVOID], l->type)) {
-				if(beq(flag, l->flag)) {
-					s++;
-					goto loop;
-				}
-			}
-
-		n = nextarg(n, &a);
-		pos++;
-		if(a == Z) {
-			warn(nn, "more format than arguments %s",
-				lastfmt);
-			return;
-		}
-		if(a->type == 0)
-			continue;
-		for(l=tprot; l; l=l->link)
-			if(sametype(a->type, l->type)) {
-/*print("checking %T/%ux %T/%ux\n", a->type, flag.b[0], l->type, l->flag.b[0]);*/
-				if(beq(flag, l->flag))
-					goto loop;
-			}
-		warn(nn, "format mismatch %s %T, arg %d", lastfmt, a->type, pos);
-	loop:;
-	}
-}
-
-void
-dpcheck(Node *n)
-{
-	char *s;
-	Node *a, *b;
-	Tname *l;
-	Tprot *tl;
-	int i, j;
-
-	if(n == Z)
-		return;
-	b = n->left;
-	if(b == Z || b->op != ONAME)
-		return;
-	s = b->sym->name;
-	for(l=tname; l; l=l->link)
-		if(strcmp(s, l->name) == 0)
-			break;
-	if(l == 0)
-		return;
-
-	if(l->count > 0) {
-		// fetch count, then check remaining length
-		i = l->count;
-		a = nil;
-		b = n->right;
-		while(i > 0) {
-			b = nextarg(b, &a);
-			i--;
-		}
-		if(a == Z) {
-			diag(n, "can't find count arg");
-			return;
-		}
-		if(a->op != OCONST || !typechl[a->type->etype]) {
-			diag(n, "count is invalid constant");
-			return;
-		}
-		j = a->vconst;
-		i = 0;
-		while(b != Z) {
-			b = nextarg(b, &a);
-			i++;
-		}
-		if(i != j)
-			diag(n, "found %d argument%s after count %d", i, i == 1 ? "" : "s", j);
-	}
-
-	if(l->prot != nil) {
-		// check that all arguments after param or count
-		// are listed in type list.
-		i = l->count;
-		if(i == 0)
-			i = l->param;
-		if(i == 0)
-			return;
-		a = nil;
-		b = n->right;
-		while(i > 0) {
-			b = nextarg(b, &a);
-			i--;
-		}
-		if(a == Z) {
-			diag(n, "can't find count/param arg");
-			return;
-		}
-		while(b != Z) {
-			b = nextarg(b, &a);
-			for(tl=l->prot; tl; tl=tl->link)
-				if(sametype(a->type, tl->type))
-					break;
-			if(tl == nil)
-				diag(a, "invalid type %T in call to %s", a->type, s);
-		}
-	}
-
-	if(l->param <= 0)
-		return;
-	i = l->param;
-	a = nil;
-	b = n->right;
-	while(i > 0) {
-		b = nextarg(b, &a);
-		i--;
-	}
-	if(a == Z) {
-		diag(n, "can't find format arg");
-		return;
-	}
-	if(!sametype(indchar, a->type)) {
-		diag(n, "format arg type %T", a->type);
-		return;
-	}
-	if(a->op != OADDR || a->left->op != ONAME || a->left->sym != symstring) {
-/*		warn(n, "format arg not constant string");*/
-		return;
-	}
-	s = a->left->cstring;
-	checkargs(b, s, l->param);
-}
-
-void
-pragpack(void)
-{
-	Sym *s;
-
-	packflg = 0;
-	s = getsym();
-	if(s) {
-		packflg = atoi(s->name+1);
-		if(strcmp(s->name, "on") == 0 ||
-		   strcmp(s->name, "yes") == 0)
-			packflg = 1;
-	}
-	while(getnsc() != '\n')
-		;
-	if(debug['f'])
-		if(packflg)
-			print("%4d: pack %d\n", lineno, packflg);
-		else
-			print("%4d: pack off\n", lineno);
-}
-
-void
-pragfpround(void)
-{
-	Sym *s;
-
-	fproundflg = 0;
-	s = getsym();
-	if(s) {
-		fproundflg = atoi(s->name+1);
-		if(strcmp(s->name, "on") == 0 ||
-		   strcmp(s->name, "yes") == 0)
-			fproundflg = 1;
-	}
-	while(getnsc() != '\n')
-		;
-	if(debug['f'])
-		if(fproundflg)
-			print("%4d: fproundflg %d\n", lineno, fproundflg);
-		else
-			print("%4d: fproundflg off\n", lineno);
-}
-
-void
-pragtextflag(void)
-{
-	Sym *s;
-
-	s = getsym();
-	if(s == S) {
-		textflag = getnsn();
-	} else {
-		if(s->macro) {
-			macexpand(s, symb);
-		}
-		if(symb[0] < '0' || symb[0] > '9')
-			yyerror("pragma textflag not an integer");
-		textflag = atoi(symb);
-	}
-	while(getnsc() != '\n')
-		;
-	if(debug['f'])
-		print("%4d: textflag %d\n", lineno, textflag);
-}
-
-void
-pragdataflag(void)
-{
-	Sym *s;
-
-	s = getsym();
-	if(s == S) {
-		dataflag = getnsn();
-	} else {
-		if(s->macro) {
-			macexpand(s, symb);
-		}
-		if(symb[0] < '0' || symb[0] > '9')
-			yyerror("pragma dataflag not an integer");
-		dataflag = atoi(symb);
-	}
-	while(getnsc() != '\n')
-		;
-	if(debug['f'])
-		print("%4d: dataflag %d\n", lineno, dataflag);
-}
-
-void
-pragincomplete(void)
-{
-	Sym *s;
-	Type *t;
-	int istag, w, et;
-
-	istag = 0;
-	s = getsym();
-	if(s == nil)
-		goto out;
-	et = 0;
-	w = s->lexical;
-	if(w == LSTRUCT)
-		et = TSTRUCT;
-	else if(w == LUNION)
-		et = TUNION;
-	if(et != 0){
-		s = getsym();
-		if(s == nil){
-			yyerror("missing struct/union tag in pragma incomplete");
-			goto out;
-		}
-		if(s->lexical != LNAME && s->lexical != LTYPE){
-			yyerror("invalid struct/union tag: %s", s->name);
-			goto out;
-		}
-		dotag(s, et, 0);
-		istag = 1;
-	}else if(strcmp(s->name, "_off_") == 0){
-		debug['T'] = 0;
-		goto out;
-	}else if(strcmp(s->name, "_on_") == 0){
-		debug['T'] = 1;
-		goto out;
-	}
-	t = s->type;
-	if(istag)
-		t = s->suetag;
-	if(t == T)
-		yyerror("unknown type %s in pragma incomplete", s->name);
-	else if(!typesu[t->etype])
-		yyerror("not struct/union type in pragma incomplete: %s", s->name);
-	else
-		t->garb |= GINCOMPLETE;
-out:
-	while(getnsc() != '\n')
-		;
-	if(debug['f'])
-		print("%s incomplete\n", s->name);
-}
-
-Sym*
-getimpsym(void)
-{
-	int c;
-	char *cp;
-
-	c = getnsc();
-	if(isspace(c) || c == '"') {
-		unget(c);
-		return S;
-	}
-	for(cp = symb;;) {
-		if(cp <= symb+NSYMB-4)
-			*cp++ = c;
-		c = getc();
-		if(c > 0 && !isspace(c) && c != '"')
-			continue;
-		unget(c);
-		break;
-	}
-	*cp = 0;
-	if(cp > symb+NSYMB-4)
-		yyerror("symbol too large: %s", symb);
-	return lookup();
-}
-
-static int
-more(void)
-{
-	int c;
-	
-	do
-		c = getnsc();
-	while(c == ' ' || c == '\t');
-	unget(c);
-	return c != '\n';
-}
-
-void
-pragcgo(char *verb)
-{
-	Sym *local, *remote;
-	char *p;
-
-	if(strcmp(verb, "cgo_dynamic_linker") == 0 || strcmp(verb, "dynlinker") == 0) {
-		p = getquoted();
-		if(p == nil)
-			goto err1;
-		fmtprint(&pragcgobuf, "cgo_dynamic_linker %q\n", p);
-		goto out;
-	
-	err1:
-		yyerror("usage: #pragma cgo_dynamic_linker \"path\"");
-		goto out;
-	}	
-	
-	if(strcmp(verb, "dynexport") == 0)
-		verb = "cgo_export_dynamic";
-	if(strcmp(verb, "cgo_export_static") == 0 || strcmp(verb, "cgo_export_dynamic") == 0) {
-		local = getimpsym();
-		if(local == nil)
-			goto err2;
-		if(!more()) {
-			fmtprint(&pragcgobuf, "%s %q\n", verb, local->name);
-			goto out;
-		}
-		remote = getimpsym();
-		if(remote == nil)
-			goto err2;
-		fmtprint(&pragcgobuf, "%s %q %q\n", verb, local->name, remote->name);
-		goto out;
-	
-	err2:
-		yyerror("usage: #pragma %s local [remote]", verb);
-		goto out;
-	}
-	
-	if(strcmp(verb, "cgo_import_dynamic") == 0 || strcmp(verb, "dynimport") == 0) {
-		local = getimpsym();
-		if(local == nil)
-			goto err3;
-		if(!more()) {
-			fmtprint(&pragcgobuf, "cgo_import_dynamic %q\n", local->name);
-			goto out;
-		}
-		remote = getimpsym();
-		if(remote == nil)
-			goto err3;
-		if(!more()) {
-			fmtprint(&pragcgobuf, "cgo_import_dynamic %q %q\n", local->name, remote->name);
-			goto out;
-		}
-		p = getquoted();
-		if(p == nil)	
-			goto err3;
-		fmtprint(&pragcgobuf, "cgo_import_dynamic %q %q %q\n", local->name, remote->name, p);
-		goto out;
-	
-	err3:
-		yyerror("usage: #pragma cgo_import_dynamic local [remote [\"library\"]]");
-		goto out;
-	}
-	
-	if(strcmp(verb, "cgo_import_static") == 0) {
-		local = getimpsym();
-		if(local == nil)
-			goto err4;
-		fmtprint(&pragcgobuf, "cgo_import_static %q\n", local->name);
-		goto out;
-
-	err4:
-		yyerror("usage: #pragma cgo_import_static local [remote]");
-		goto out;
-	}
-	
-	if(strcmp(verb, "cgo_ldflag") == 0) {
-		p = getquoted();
-		if(p == nil)
-			goto err5;
-		fmtprint(&pragcgobuf, "cgo_ldflag %q\n", p);
-		goto out;
-
-	err5:
-		yyerror("usage: #pragma cgo_ldflag \"arg\"");
-		goto out;
-	}
-	
-out:
-	while(getnsc() != '\n')
-		;
-}
diff --git a/src/cmd/cc/funct.c b/src/cmd/cc/funct.c
deleted file mode 100644
index 92c067d..0000000
--- a/src/cmd/cc/funct.c
+++ /dev/null
@@ -1,431 +0,0 @@
-// Inferno utils/cc/funct.c
-// http://code.google.com/p/inferno-os/source/browse/utils/cc/funct.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include	<u.h>
-#include	"cc.h"
-
-typedef	struct	Ftab	Ftab;
-struct	Ftab
-{
-	char	op;
-	char*	name;
-	char	typ;
-};
-typedef	struct	Gtab	Gtab;
-struct	Gtab
-{
-	char	etype;
-	char*	name;
-};
-
-Ftab	ftabinit[OEND];
-Gtab	gtabinit[NALLTYPES];
-
-int
-isfunct(Node *n)
-{
-	Type *t, *t1;
-	Funct *f;
-	Node *l;
-	Sym *s;
-	int o;
-
-	o = n->op;
-	if(n->left == Z)
-		goto no;
-	t = n->left->type;
-	if(t == T)
-		goto no;
-	f = t->funct;
-
-	switch(o) {
-	case OAS:	// put cast on rhs
-	case OASI:
-	case OASADD:
-	case OASAND:
-	case OASASHL:
-	case OASASHR:
-	case OASDIV:
-	case OASLDIV:
-	case OASLMOD:
-	case OASLMUL:
-	case OASLSHR:
-	case OASMOD:
-	case OASMUL:
-	case OASOR:
-	case OASSUB:
-	case OASXOR:
-		if(n->right == Z)
-			goto no;
-		t1 = n->right->type;
-		if(t1 == T)
-			goto no;
-		if(t1->funct == f)
-			break;
-
-		l = new(OXXX, Z, Z);
-		*l = *n->right;
-
-		n->right->left = l;
-		n->right->right = Z;
-		n->right->type = t;
-		n->right->op = OCAST;
-
-		if(!isfunct(n->right))
-			prtree(n, "isfunc !");
-		break;
-
-	case OCAST:	// t f(T) or T f(t)
-		t1 = n->type;
-		if(t1 == T)
-			goto no;
-		if(f != nil) {
-			s = f->castfr[t1->etype];
-			if(s == S)
-				goto no;
-			n->right = n->left;
-			goto build;
-		}
-		f = t1->funct;
-		if(f != nil) {
-			s = f->castto[t->etype];
-			if(s == S)
-				goto no;
-			n->right = n->left;
-			goto build;
-		}
-		goto no;
-	}
-
-	if(f == nil)
-		goto no;
-	s = f->sym[o];
-	if(s == S)
-		goto no;
-
-	/*
-	 * the answer is yes,
-	 * now we rewrite the node
-	 * and give diagnostics
-	 */
-	switch(o) {
-	default:
-		diag(n, "isfunct op missing %O\n", o);
-		goto bad;
-
-	case OADD:	// T f(T, T)
-	case OAND:
-	case OASHL:
-	case OASHR:
-	case ODIV:
-	case OLDIV:
-	case OLMOD:
-	case OLMUL:
-	case OLSHR:
-	case OMOD:
-	case OMUL:
-	case OOR:
-	case OSUB:
-	case OXOR:
-
-	case OEQ:	// int f(T, T)
-	case OGE:
-	case OGT:
-	case OHI:
-	case OHS:
-	case OLE:
-	case OLO:
-	case OLS:
-	case OLT:
-	case ONE:
-		if(n->right == Z)
-			goto bad;
-		t1 = n->right->type;
-		if(t1 == T)
-			goto bad;
-		if(t1->funct != f)
-			goto bad;
-		n->right = new(OLIST, n->left, n->right);
-		break;
-
-	case OAS:	// structure copies done by the compiler
-	case OASI:
-		goto no;
-
-	case OASADD:	// T f(T*, T)
-	case OASAND:
-	case OASASHL:
-	case OASASHR:
-	case OASDIV:
-	case OASLDIV:
-	case OASLMOD:
-	case OASLMUL:
-	case OASLSHR:
-	case OASMOD:
-	case OASMUL:
-	case OASOR:
-	case OASSUB:
-	case OASXOR:
-		if(n->right == Z)
-			goto bad;
-		t1 = n->right->type;
-		if(t1 == T)
-			goto bad;
-		if(t1->funct != f)
-			goto bad;
-		n->right = new(OLIST, new(OADDR, n->left, Z), n->right);
-		break;
-
-	case OPOS:	// T f(T)
-	case ONEG:
-	case ONOT:
-	case OCOM:
-		n->right = n->left;
-		break;
-
-
-	}
-
-build:
-	l = new(ONAME, Z, Z);
-	l->sym = s;
-	l->type = s->type;
-	l->etype = s->type->etype;
-	l->xoffset = s->offset;
-	l->class = s->class;
-	tcomo(l, 0);
-
-	n->op = OFUNC;
-	n->left = l;
-	n->type = l->type->link;
-	if(tcompat(n, T, l->type, tfunct))
-		goto bad;
-	if(tcoma(n->left, n->right, l->type->down, 1))
-		goto bad;
-	return 1;
-
-no:
-	return 0;
-
-bad:
-	diag(n, "can't rewrite typestr for op %O\n", o);
-	prtree(n, "isfunct");
-	n->type = T;
-	return 1;
-}
-
-void
-dclfunct(Type *t, Sym *s)
-{
-	Funct *f;
-	Node *n;
-	Type *f1, *f2, *f3, *f4;
-	int o, i, c;
-	char str[100];
-
-	if(t->funct)
-		return;
-
-	// recognize generated tag of dorm _%d_
-	if(t->tag == S)
-		goto bad;
-	for(i=0; c = t->tag->name[i]; i++) {
-		if(c == '_') {
-			if(i == 0 || t->tag->name[i+1] == 0)
-				continue;
-			break;
-		}
-		if(c < '0' || c > '9')
-			break;
-	}
-	if(c == 0)
-		goto bad;
-
-	f = alloc(sizeof(*f));
-	for(o=0; o<nelem(f->sym); o++)
-		f->sym[o] = S;
-
-	t->funct = f;
-
-	f1 = typ(TFUNC, t);
-	f1->down = copytyp(t);
-	f1->down->down = t;
-
-	f2 = typ(TFUNC, types[TINT]);
-	f2->down = copytyp(t);
-	f2->down->down = t;
-
-	f3 = typ(TFUNC, t);
-	f3->down = typ(TIND, t);
-	f3->down->down = t;
-
-	f4 = typ(TFUNC, t);
-	f4->down = t;
-
-	for(i=0;; i++) {
-		o = ftabinit[i].op;
-		if(o == OXXX)
-			break;
-		sprint(str, "%s_%s_", t->tag->name, ftabinit[i].name);
-		n = new(ONAME, Z, Z);
-		n->sym = slookup(str);
-		f->sym[o] = n->sym;
-		switch(ftabinit[i].typ) {
-		default:
-			diag(Z, "dclfunct op missing %d\n", ftabinit[i].typ);
-			break;
-
-		case 1:	// T f(T,T)	+
-			dodecl(xdecl, CEXTERN, f1, n);
-			break;
-
-		case 2:	// int f(T,T)	==
-			dodecl(xdecl, CEXTERN, f2, n);
-			break;
-
-		case 3:	// void f(T*,T)	+=
-			dodecl(xdecl, CEXTERN, f3, n);
-			break;
-
-		case 4:	// T f(T)	~
-			dodecl(xdecl, CEXTERN, f4, n);
-			break;
-		}
-	}
-	for(i=0;; i++) {
-		o = gtabinit[i].etype;
-		if(o == TXXX)
-			break;
-
-		/*
-		 * OCAST types T1 _T2_T1_(T2)
-		 */
-		sprint(str, "_%s%s_", gtabinit[i].name, t->tag->name);
-		n = new(ONAME, Z, Z);
-		n->sym = slookup(str);
-		f->castto[o] = n->sym;
-
-		f1 = typ(TFUNC, t);
-		f1->down = types[o];
-		dodecl(xdecl, CEXTERN, f1, n);
-
-		sprint(str, "%s_%s_", t->tag->name, gtabinit[i].name);
-		n = new(ONAME, Z, Z);
-		n->sym = slookup(str);
-		f->castfr[o] = n->sym;
-
-		f1 = typ(TFUNC, types[o]);
-		f1->down = t;
-		dodecl(xdecl, CEXTERN, f1, n);
-	}
-	return;
-bad:
-	diag(Z, "dclfunct bad %T %s\n", t, s->name);
-}
-
-Gtab	gtabinit[NALLTYPES] =
-{
-	TCHAR,		"c",
-	TUCHAR,		"uc",
-	TSHORT,		"h",
-	TUSHORT,	"uh",
-	TINT,		"i",
-	TUINT,		"ui",
-	TLONG,		"l",
-	TULONG,		"ul",
-	TVLONG,		"v",
-	TUVLONG,	"uv",
-	TFLOAT,		"f",
-	TDOUBLE,	"d",
-	TXXX
-};
-
-Ftab	ftabinit[OEND] =
-{
-	OADD,		"add",		1,
-	OAND,		"and",		1,
-	OASHL,		"ashl",		1,
-	OASHR,		"ashr",		1,
-	ODIV,		"div",		1,
-	OLDIV,		"ldiv",		1,
-	OLMOD,		"lmod",		1,
-	OLMUL,		"lmul",		1,
-	OLSHR,		"lshr",		1,
-	OMOD,		"mod",		1,
-	OMUL,		"mul",		1,
-	OOR,		"or",		1,
-	OSUB,		"sub",		1,
-	OXOR,		"xor",		1,
-
-	OEQ,		"eq",		2,
-	OGE,		"ge",		2,
-	OGT,		"gt",		2,
-	OHI,		"hi",		2,
-	OHS,		"hs",		2,
-	OLE,		"le",		2,
-	OLO,		"lo",		2,
-	OLS,		"ls",		2,
-	OLT,		"lt",		2,
-	ONE,		"ne",		2,
-
-	OASADD,		"asadd",	3,
-	OASAND,		"asand",	3,
-	OASASHL,	"asashl",	3,
-	OASASHR,	"asashr",	3,
-	OASDIV,		"asdiv",	3,
-	OASLDIV,	"asldiv",	3,
-	OASLMOD,	"aslmod",	3,
-	OASLMUL,	"aslmul",	3,
-	OASLSHR,	"aslshr",	3,
-	OASMOD,		"asmod",	3,
-	OASMUL,		"asmul",	3,
-	OASOR,		"asor",		3,
-	OASSUB,		"assub",	3,
-	OASXOR,		"asxor",	3,
-
-	OPOS,		"pos",		4,
-	ONEG,		"neg",		4,
-	OCOM,		"com",		4,
-	ONOT,		"not",		4,
-
-//	OPOSTDEC,
-//	OPOSTINC,
-//	OPREDEC,
-//	OPREINC,
-
-	OXXX,
-};
-
-//	Node*	nodtestv;
-
-//	Node*	nodvpp;
-//	Node*	nodppv;
-//	Node*	nodvmm;
-//	Node*	nodmmv;
diff --git a/src/cmd/cc/godefs.c b/src/cmd/cc/godefs.c
deleted file mode 100644
index d9f67f0..0000000
--- a/src/cmd/cc/godefs.c
+++ /dev/null
@@ -1,367 +0,0 @@
-//   cmd/cc/godefs.cc
-//
-//   derived from pickle.cc which itself was derived from acid.cc.
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at terzarima.net)
-//	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
-//	Portions Copyright © 2009-2011 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.
-
-#include <u.h>
-#include "cc.h"
-
-static int upper;
-
-static char *kwd[] =
-{
-	"_bool",
-	"_break",
-	"_byte",
-	"_case",
-	"_chan",
-	"_complex128",
-	"_complex64",
-	"_const",
-	"_continue",
-	"_default",
-	"_defer",
-	"_else",
-	"_fallthrough",
-	"_false",
-	"_float32",
-	"_float64",
-	"_for",
-	"_func",
-	"_go",
-	"_goto",
-	"_if",
-	"_import",
-	"_int",
-	"_int16",
-	"_int32",
-	"_int64",
-	"_int8",
-	"_interface",
-	"_intptr",
-	"_map",
-	"_package",
-	"_panic",
-	"_range",
-	"_return",
-	"_select",
-	"_string",
-	"_struct",
-	"_switch",
-	"_true",
-	"_type",
-	"_uint",
-	"_uint16",
-	"_uint32",
-	"_uint64",
-	"_uint8",
-	"_uintptr",
-	"_var",
-};
-
-static char*
-pmap(char *s)
-{
-	int i, bot, top, mid;
-
-	bot = -1;
-	top = nelem(kwd);
-	while(top - bot > 1){
-		mid = (bot + top) / 2;
-		i = strcmp(kwd[mid]+1, s);
-		if(i == 0)
-			return kwd[mid];
-		if(i < 0)
-			bot = mid;
-		else
-			top = mid;
-	}
-
-	return s;
-}
-
-
-int
-Uconv(Fmt *fp)
-{
-	char str[STRINGSZ+1];
-	char *s, *n;
-	int i;
-
-	str[0] = 0;
-	s = va_arg(fp->args, char*);
-
-	// strip package name
-	n = strrchr(s, '.');
-	if(n != nil)
-		s = n + 1;
-
-	if(s && *s) {
-		if(upper)
-			str[0] = toupper((uchar)*s);
-		else
-			str[0] = tolower((uchar)*s);
-		for(i = 1; i < STRINGSZ && s[i] != 0; i++)
-			str[i] = tolower((uchar)s[i]);
-		str[i] = 0;
-	}
-
-	return fmtstrcpy(fp, pmap(str));
-}
-
-
-static Sym*
-findsue(Type *t)
-{
-	int h;
-	Sym *s;
-
-	if(t != T)
-	for(h=0; h<nelem(hash); h++)
-		for(s = hash[h]; s != S; s = s->link)
-			if(s->suetag && s->suetag->link == t)
-				return s;
-	return 0;
-}
-
-static void
-printtypename(Type *t)
-{
-	Sym *s;
-	int w;
-	char *n;
-
-	for( ; t != nil; t = t->link) {
-		switch(t->etype) {
-		case TIND:
-			// Special handling of *void.
-			if(t->link != nil && t->link->etype==TVOID) {
-				Bprint(&outbuf, "unsafe.Pointer");
-				return;
-			}
-			// *func == func
-			if(t->link != nil && t->link->etype==TFUNC)
-				continue;
-			Bprint(&outbuf, "*");
-			continue;
-		case TARRAY:
-			w = t->width;
-			if(t->link && t->link->width)
-				w /= t->link->width;
-			Bprint(&outbuf, "[%d]", w);
-			continue;
-		}
-		break;
-	}
-
-	if(t == nil) {
-		Bprint(&outbuf, "bad // should not happen");
-		return;
-	}
-
-	switch(t->etype) {
-	case TINT:
-	case TUINT:
-	case TCHAR:
-	case TUCHAR:
-	case TSHORT:
-	case TUSHORT:
-	case TLONG:
-	case TULONG:
-	case TVLONG:
-	case TUVLONG:
-	case TFLOAT:
-	case TDOUBLE:
-		// All names used in the runtime code should be typedefs.
-		if(t->tag != nil) {
-			if(strcmp(t->tag->name, "intgo") == 0)
-				Bprint(&outbuf, "int");
-			else if(strcmp(t->tag->name, "uintgo") == 0)
-				Bprint(&outbuf, "uint");
-			else
-				Bprint(&outbuf, "%s", t->tag->name);
-		} else	
-			Bprint(&outbuf, "C.%T", t);
-		break;
-	case TUNION:
-	case TSTRUCT:
-		s = findsue(t->link);
-		n = "bad";
-		if(s != S)
-			n = s->name;
-		else if(t->tag)
-			n = t->tag->name;
-		if(strcmp(n, "String") == 0)
-			Bprint(&outbuf, "string");
-		else if(strcmp(n, "Slice") == 0)
-			Bprint(&outbuf, "[]byte");
-		else if(strcmp(n, "Eface") == 0)
-			Bprint(&outbuf, "interface{}");
-		else
-			Bprint(&outbuf, "%U", n);
-		break;
-	case TFUNC:
-		// There's no equivalent to a C function in the Go world.
-		Bprint(&outbuf, "unsafe.Pointer");
-		break;
-	case TDOT:
-		Bprint(&outbuf, "...interface{}");
-		break;
-	default:
-		Bprint(&outbuf, " weird<%T>", t);
-	}
-}
-
-static int
-dontrun(void)
-{
-	Io *i;
-	int n;
-
-	if(!debug['q'] && !debug['Q'])
-		return 1;
-	if(debug['q'] + debug['Q'] > 1) {
-		n = 0;
-		for(i=iostack; i; i=i->link)
-			n++;
-		if(n > 1)
-			return 1;
-	}
-
-	upper = debug['Q'];
-	return 0;
-}
-
-void
-godeftype(Type *t)
-{
-	Sym *s;
-	Type *l;
-	int gotone;
-
-	if(dontrun())
-		return;
-
-	switch(t->etype) {
-	case TUNION:
-	case TSTRUCT:
-		s = findsue(t->link);
-		if(s == S) {
-			Bprint(&outbuf, "/* can't find %T */\n\n", t);
-			return;
-		}
-
-		gotone = 0; // for unions, take first member of size equal to union
-		Bprint(&outbuf, "type %U struct {\n", s->name);
-		for(l = t->link; l != T; l = l->down) {
-			Bprint(&outbuf, "\t");
-			if(t->etype == TUNION) {
-				if(!gotone && l->width == t->width)
-					gotone = 1;
-				else
-					Bprint(&outbuf, "// (union)\t");
-			}
-			if(l->sym != nil)  // not anonymous field
-				Bprint(&outbuf, "%U\t", l->sym->name);
-			printtypename(l);
-			Bprint(&outbuf, "\n");
-		}
-		Bprint(&outbuf, "}\n\n");
-		break;
-
-	default:
-		Bprint(&outbuf, "/* %T */\n\n", t);
-		break;
-	}
-}
-
-void
-godefvar(Sym *s)
-{
-	Type *t, *t1;
-	char n;
-
-	if(dontrun())
-		return;
-
-	t = s->type;
-	if(t == nil)
-		return;
-
-	switch(t->etype) {
-	case TENUM:
-		if(!typefd[t->etype])
-			Bprint(&outbuf, "const %s = %lld\n", s->name, s->vconst);
-		else
-			Bprint(&outbuf, "const %s = %f\n;", s->name, s->fconst);
-		break;
-
-	case TFUNC:
-		Bprint(&outbuf, "func %U(", s->name);
-		n = 'a';
-		for(t1 = t->down; t1 != T; t1 = t1->down) {
-			if(t1->etype == TVOID)
-				break;
-			if(t1 != t->down)
-				Bprint(&outbuf, ", ");
-			Bprint(&outbuf, "%c ", n++);
-			printtypename(t1);
-		}
-		Bprint(&outbuf, ")");
-		if(t->link && t->link->etype != TVOID) {
-			Bprint(&outbuf, " ");
-			printtypename(t->link);
-		}
-		Bprint(&outbuf, "\n");
-		break;
-
-	default:
-		switch(s->class) {
-		case CTYPEDEF:
-			if(!typesu[t->etype]) {
-				Bprint(&outbuf, "// type %U\t", s->name);
-				printtypename(t);
-				Bprint(&outbuf, "\n");
-			}
-			break;
-		case CSTATIC:
-		case CEXTERN:
-		case CGLOBL:
-			if(strchr(s->name, '$') != nil)
-				break;
-			if(strncmp(s->name, "go.weak.", 8) == 0)
-				break;
-			Bprint(&outbuf, "var %U\t", s->name);
-			printtypename(t);
-			Bprint(&outbuf, "\n");
-			break;
-		}
-		break;
-	}
-}
diff --git a/src/cmd/cc/lex.c b/src/cmd/cc/lex.c
deleted file mode 100644
index 7c9f718..0000000
--- a/src/cmd/cc/lex.c
+++ /dev/null
@@ -1,1593 +0,0 @@
-// Inferno utils/cc/lex.c
-// http://code.google.com/p/inferno-os/source/browse/utils/cc/lex.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include	<u.h>
-#include	"cc.h"
-#include	"y.tab.h"
-#include	"../ld/textflag.h"
-
-#ifndef	CPP
-#define	CPP	"cpp"
-#endif
-
-int
-systemtype(int sys)
-{
-#ifdef _WIN32
-	return sys&Windows;
-#else
-	return sys&Plan9;
-#endif
-}
-
-int
-pathchar(void)
-{
-	return '/';
-}
-
-/*
- * known debug flags
- *	-a		acid declaration output
- *	-A		!B
- *	-B		non ANSI
- *	-d		print declarations
- *	-D name		define
- *	-F		format specification check
- *	-G		print pgen stuff
- *	-g		print cgen trees
- *	-i		print initialization
- *	-I path		include
- *	-l		generate little-endian code
- *	-L		print every NAME symbol
- *	-M		constant multiplication
- *	-m		print add/sub/mul trees
- *	-n		print acid or godefs to file (%.c=%.acid) (with -a or -aa)
- *	-o file		output file
- *	-p		use standard cpp ANSI preprocessor (not on windows)
- *	-p		something with peepholes
- *	-q		print equivalent Go code for variables and types (lower-case identifiers)
- *	-Q		print equivalent Go code for variables and types (upper-case identifiers)
- *	-r		print registerization
- *	-s		print structure offsets (with -a or -aa)
- *	-S		print assembly
- *	-t		print type trees
- *	-V		enable void* conversion warnings
- *	-v		verbose printing
- *	-w		print warnings
- *	-X		abort on error
- *	-.		Inhibit search for includes in source directory
- */
-
-void
-usage(void)
-{
-	print("usage: %cc [options] file.c...\n", thechar);
-	flagprint(1);
-	errorexit();
-}
-
-void
-dospim(void)
-{
-	thechar = '0';
-	thestring = "spim";
-}
-
-char **defs;
-int ndef;
-
-void
-dodef(char *p)
-{
-	if(ndef%8 == 0)
-		defs = allocn(defs, ndef*sizeof(char *),
-			8*sizeof(char *));
-	defs[ndef++] = p;
-	dodefine(p);
-}
-
-void
-main(int argc, char *argv[])
-{
-	int c;
-	char *p;
-
-	// Allow GOARCH=thestring or GOARCH=thestringsuffix,
-	// but not other values.	
-	p = getgoarch();
-	if(strncmp(p, thestring, strlen(thestring)) != 0)
-		sysfatal("cannot use %cc with GOARCH=%s", thechar, p);
-	if(strcmp(p, "amd64p32") == 0) // must be before cinit
-		ewidth[TIND] = 4;
-		
-	nacl = strcmp(getgoos(), "nacl") == 0;
-	if(nacl)
-		flag_largemodel = 1;
-
-	quotefmtinstall(); // before cinit, which overrides %Q
-
-	linkarchinit();
-	ctxt = linknew(thelinkarch);
-	ctxt->diag = yyerror;
-	ctxt->bso = &bstdout;
-	Binit(&bstdout, 1, OWRITE);
-
-	ensuresymb(NSYMB);
-	memset(debug, 0, sizeof(debug));
-	tinit();
-	cinit();
-	ginit();
-	arginit();
-	
-	fmtstrinit(&pragcgobuf);
-
-	tufield = simplet((1L<<tfield->etype) | BUNSIGNED);
-	ndef = 0;
-	defs = nil;
-	outfile = 0;
-	setinclude(".");
-
-	flagcount("+", "pass -+ to preprocessor", &debug['+']);	
-	flagcount(".", "pass -. to preprocessor", &debug['.']);	
-	flagcount("<", "debug shift", &debug['<']);
-	flagcount("A", "debug alignment", &debug['A']);
-	flagcount("B", "allow pre-ANSI code", &debug['B']);
-	if(thechar == '5')
-		flagcount("C", "debug constant propagation", &debug['C']);
-	flagfn1("D", "name[=value]: add #define", dodef);
-	flagcount("F", "enable print format checks", &debug['F']);
-	if(thechar == '5')
-		flagcount("H", "debug shift propagation", &debug['H']);
-	flagfn1("I", "dir: add dir to include path", setinclude);
-	flagcount("L", "debug lexer", &debug['L']);
-	flagcount("M", "debug move generation", &debug['M']);
-	flagcount("N", "disable optimizations", &debug['N']);
-	flagcount("P", "debug peephole optimizer", &debug['P']);
-	flagcount("Q", "print exported Go definitions", &debug['Q']);
-	flagcount("R", "debug register optimizer", &debug['R']);
-	flagcount("S", "print assembly", &debug['S']);
-	flagcount("T", "enable type signatures", &debug['T']);
-	flagcount("V", "enable pointer type checks", &debug['V']);
-	flagcount("W", "debug switch generation", &debug['W']);
-	flagcount("X", "abort on error", &debug['X']);
-	flagcount("Y", "debug index generation", &debug['Y']);
-	flagcount("Z", "skip code generation", &debug['Z']);
-	flagcount("a", "print acid definitions", &debug['a']);
-	flagcount("c", "debug constant evaluation", &debug['c']);
-	flagcount("d", "debug declarations", &debug['d']);
-	flagcount("e", "debug macro expansion", &debug['e']);
-	flagcount("f", "debug pragmas", &debug['f']);
-	flagcount("g", "debug code generation", &debug['g']);
-	flagcount("i", "debug initialization", &debug['i']);
-	if(thechar == 'v')
-		flagfn0("l", "little-endian mips mode", dospim);
-	flagcount("m", "debug multiplication", &debug['m']);
-	flagcount("n", "print acid/Go to file, not stdout", &debug['n']);
-	flagstr("o", "file: set output file", &outfile);
-	flagcount("p", "invoke C preprocessor", &debug['p']);	
-	flagcount("q", "print Go definitions", &debug['q']);
-	flagcount("s", "print #define assembly offsets", &debug['s']);
-	flagcount("t", "debug code generation", &debug['t']);
-	flagstr("trimpath", "prefix: remove prefix from recorded source file paths", &ctxt->trimpath);
-	flagcount("w", "enable warnings", &debug['w']);
-	flagcount("v", "increase debug verbosity", &debug['v']);	
-	if(thechar == '6')
-		flagcount("largemodel", "generate code that assumes a large memory model", &flag_largemodel);
-	
-	flagparse(&argc, &argv, usage);
-	ctxt->debugasm = debug['S'];
-	ctxt->debugvlog = debug['v'];
-
-	if(argc < 1 && outfile == 0)
-		usage();
-
-	if(argc > 1){
-		print("can't compile multiple files\n");
-		errorexit();
-	}
-
-	if(argc == 0)
-		c = compile("stdin", defs, ndef);
-	else
-		c = compile(argv[0], defs, ndef);
-
-	Bflush(&bstdout);
-	if(c)
-		errorexit();
-	exits(0);
-}
-
-int
-compile(char *file, char **defs, int ndef)
-{
-	char *ofile;
-	char *p, **av, opt[256];
-	int i, c, fd[2];
-	static int first = 1;
-
-	ofile = alloc(strlen(file)+10);
-	strcpy(ofile, file);
-	p = utfrrune(ofile, pathchar());
-	if(p) {
-		*p++ = 0;
-		if(!debug['.'])
-			include[0] = strdup(ofile);
-	} else
-		p = ofile;
-
-	if(outfile == 0) {
-		outfile = p;
-		if(outfile) {
-			if(p = utfrrune(outfile, '.'))
-				if(p[1] == 'c' && p[2] == 0)
-					p[0] = 0;
-			p = utfrune(outfile, 0);
-			if(debug['a'] && debug['n'])
-				strcat(p, ".acid");
-			else if((debug['q'] || debug['Q']) && debug['n'])
-				strcat(p, ".go");
-			else {
-				p[0] = '.';
-				p[1] = thechar;
-				p[2] = 0;
-			}
-		} else
-			outfile = "/dev/null";
-	}
-
-	if (first)
-		Binit(&diagbuf, 1, OWRITE);
-	/*
-	 * if we're writing acid to standard output, don't keep scratching
-	 * outbuf.
-	 */
-	if((debug['a'] || debug['q'] || debug['Q']) && !debug['n']) {
-		if (first) {
-			outfile = 0;
-			Binit(&outbuf, dup(1, -1), OWRITE);
-			dup(2, 1);
-		}
-	} else {
-		c = create(outfile, OWRITE, 0664);
-		if(c < 0) {
-			diag(Z, "cannot open %s - %r", outfile);
-			outfile = 0;
-			errorexit();
-		}
-		Binit(&outbuf, c, OWRITE);
-		outfile = strdup(outfile);
-	}
-	newio();
-	first = 0;
-
-	/* Use an ANSI preprocessor */
-	if(debug['p']) {
-		if(systemtype(Windows)) {
-			diag(Z, "-p option not supported on windows");
-			errorexit();
-		}
-		if(access(file, AREAD) < 0) {
-			diag(Z, "%s does not exist", file);
-			errorexit();
-		}
-		if(pipe(fd) < 0) {
-			diag(Z, "pipe failed");
-			errorexit();
-		}
-		switch(fork()) {
-		case -1:
-			diag(Z, "fork failed");
-			errorexit();
-		case 0:
-			close(fd[0]);
-			dup(fd[1], 1);
-			close(fd[1]);
-			av = alloc((ndef+ninclude+5)*sizeof(char *));
-			av[0] = CPP;
-			i = 1;
-			if(debug['.']){
-				sprint(opt, "-.");
-				av[i++] = strdup(opt);
-			}
-			if(debug['+']) {
-				sprint(opt, "-+");
-				av[i++] = strdup(opt);
-			}
-			for(c = 0; c < ndef; c++)
-				av[i++] = smprint("-D%s", defs[c]);
-			for(c = 0; c < ninclude; c++)
-				av[i++] = smprint("-I%s", include[c]);
-			if(strcmp(file, "stdin") != 0)
-				av[i++] = file;
-			av[i] = 0;
-			if(debug['p'] > 1) {
-				for(c = 0; c < i; c++)
-					fprint(2, "%s ", av[c]);
-				fprint(2, "\n");
-			}
-			exec(av[0], av);
-			fprint(2, "can't exec C preprocessor %s: %r\n", CPP);
-			errorexit();
-		default:
-			close(fd[1]);
-			newfile(file, fd[0]);
-			break;
-		}
-	} else {
-		if(strcmp(file, "stdin") == 0)
-			newfile(file, 0);
-		else
-			newfile(file, -1);
-	}
-	yyparse();
-	if(!debug['a'] && !debug['q'] && !debug['Q'])
-		gclean();
-	return nerrors;
-}
-
-void
-errorexit(void)
-{
-	Bflush(&bstdout);
-	if(outfile)
-		remove(outfile);
-	exits("error");
-}
-
-void
-pushio(void)
-{
-	Io *i;
-
-	i = iostack;
-	if(i == I) {
-		yyerror("botch in pushio");
-		errorexit();
-	}
-	i->p = fi.p;
-	i->c = fi.c;
-}
-
-void
-newio(void)
-{
-	Io *i;
-	static int pushdepth = 0;
-
-	i = iofree;
-	if(i == I) {
-		pushdepth++;
-		if(pushdepth > 1000) {
-			yyerror("macro/io expansion too deep");
-			errorexit();
-		}
-		i = alloc(sizeof(*i));
-	} else
-		iofree = i->link;
-	i->c = 0;
-	i->f = -1;
-	ionext = i;
-}
-
-void
-newfile(char *s, int f)
-{
-	Io *i;
-
-	if(debug['e'])
-		print("%L: %s\n", lineno, s);
-
-	i = ionext;
-	i->link = iostack;
-	iostack = i;
-	i->f = f;
-	if(f < 0)
-		i->f = open(s, 0);
-	if(i->f < 0) {
-		yyerror("%cc: %r: %s", thechar, s);
-		errorexit();
-	}
-	fi.c = 0;
-	linklinehist(ctxt, lineno, s, 0);
-}
-
-Sym*
-slookup(char *s)
-{
-	ensuresymb(strlen(s));
-	strcpy(symb, s);
-	return lookup();
-}
-
-Sym*
-lookup(void)
-{
-	Sym *s;
-	uint32 h;
-	char *p;
-	int c, n;
-	char *r, *w;
-
-	if((uchar)symb[0] == 0xc2 && (uchar)symb[1] == 0xb7) {
-		// turn leading · into ""·
-		h = strlen(symb);
-		ensuresymb(h+2);
-		memmove(symb+2, symb, h+1);
-		symb[0] = '"';
-		symb[1] = '"';
-	}
-
-	for(r=w=symb; *r; r++) {
-		// turn · (U+00B7) into .
-		// turn ∕ (U+2215) into /
-		if((uchar)*r == 0xc2 && (uchar)*(r+1) == 0xb7) {
-			*w++ = '.';
-			r++;
-		}else if((uchar)*r == 0xe2 && (uchar)*(r+1) == 0x88 && (uchar)*(r+2) == 0x95) {
-			*w++ = '/';
-			r++;
-			r++;
-		}else
-			*w++ = *r;
-	}
-	*w = '\0';
-
-	h = 0;
-	for(p=symb; *p;) {
-		h = h * 3;
-		h += *p++;
-	}
-	n = (p - symb) + 1;
-	h &= 0xffffff;
-	h %= NHASH;
-	c = symb[0];
-	for(s = hash[h]; s != S; s = s->link) {
-		if(s->name[0] != c)
-			continue;
-		if(strcmp(s->name, symb) == 0)
-			return s;
-	}
-	s = alloc(sizeof(*s));
-	s->name = alloc(n);
-	memmove(s->name, symb, n);
-	s->link = hash[h];
-	hash[h] = s;
-	syminit(s);
-
-	return s;
-}
-
-void
-syminit(Sym *s)
-{
-	s->lexical = LNAME;
-	s->block = 0;
-	s->offset = 0;
-	s->type = T;
-	s->suetag = T;
-	s->class = CXXX;
-	s->aused = 0;
-	s->sig = SIGNONE;
-}
-
-#define	EOF	(-1)
-#define	IGN	(-2)
-#define	ESC	(1<<20)
-#define	GETC()	((--fi.c < 0)? filbuf(): (*fi.p++ & 0xff))
-
-enum
-{
-	Numdec		= 1<<0,
-	Numlong		= 1<<1,
-	Numuns		= 1<<2,
-	Numvlong	= 1<<3,
-	Numflt		= 1<<4,
-};
-
-int32
-yylex(void)
-{
-	vlong vv;
-	int32 c, c1, t;
-	char *cp;
-	Rune rune;
-	Sym *s;
-
-	if(peekc != IGN) {
-		c = peekc;
-		peekc = IGN;
-		goto l1;
-	}
-l0:
-	c = GETC();
-
-l1:
-	if(c >= Runeself) {
-		/*
-		 * extension --
-		 *	all multibyte runes are alpha
-		 */
-		cp = symb;
-		goto talph;
-	}
-	if(isspace(c)) {
-		if(c == '\n')
-			lineno++;
-		goto l0;
-	}
-	if(isalpha(c)) {
-		cp = symb;
-		if(c != 'L')
-			goto talph;
-		*cp++ = c;
-		c = GETC();
-		if(c == '\'') {
-			/* L'x' */
-			c = escchar('\'', 1, 0);
-			if(c == EOF)
-				c = '\'';
-			c1 = escchar('\'', 1, 0);
-			if(c1 != EOF) {
-				yyerror("missing '");
-				peekc = c1;
-			}
-			yylval.vval = convvtox(c, TRUNE);
-			return LUCONST;
-		}
-		if(c == '"') {
-			goto caselq;
-		}
-		goto talph;
-	}
-	if(isdigit(c))
-		goto tnum;
-	switch(c)
-	{
-
-	case EOF:
-		peekc = EOF;
-		return -1;
-
-	case '_':
-		cp = symb;
-		goto talph;
-
-	case '#':
-		domacro();
-		goto l0;
-
-	case '.':
-		c1 = GETC();
-		if(isdigit(c1)) {
-			cp = symb;
-			*cp++ = c;
-			c = c1;
-			c1 = 0;
-			goto casedot;
-		}
-		break;
-
-	case '"':
-		strcpy(symb, "\"<string>\"");
-		cp = alloc(0);
-		c1 = 0;
-
-		/* "..." */
-		for(;;) {
-			c = escchar('"', 0, 1);
-			if(c == EOF)
-				break;
-			if(c & ESC) {
-				cp = allocn(cp, c1, 1);
-				cp[c1++] = c;
-			} else {
-				rune = c;
-				c = runelen(rune);
-				cp = allocn(cp, c1, c);
-				runetochar(cp+c1, &rune);
-				c1 += c;
-			}
-		}
-		yylval.sval.l = c1;
-		do {
-			cp = allocn(cp, c1, 1);
-			cp[c1++] = 0;
-		} while(c1 & MAXALIGN);
-		yylval.sval.s = cp;
-		return LSTRING;
-
-	caselq:
-		/* L"..." */
-		strcpy(symb, "\"L<string>\"");
-		cp = alloc(0);
-		c1 = 0;
-		for(;;) {
-			c = escchar('"', 1, 0);
-			if(c == EOF)
-				break;
-			cp = allocn(cp, c1, sizeof(TRune));
-			*(TRune*)(cp + c1) = c;
-			c1 += sizeof(TRune);
-		}
-		yylval.sval.l = c1;
-		do {
-			cp = allocn(cp, c1, sizeof(TRune));
-			*(TRune*)(cp + c1) = 0;
-			c1 += sizeof(TRune);
-		} while(c1 & MAXALIGN);
-		yylval.sval.s = cp;
-		return LLSTRING;
-
-	case '\'':
-		/* '.' */
-		c = escchar('\'', 0, 0);
-		if(c == EOF)
-			c = '\'';
-		c1 = escchar('\'', 0, 0);
-		if(c1 != EOF) {
-			yyerror("missing '");
-			peekc = c1;
-		}
-		vv = c;
-		yylval.vval = convvtox(vv, TUCHAR);
-		if(yylval.vval != vv)
-			yyerror("overflow in character constant: 0x%x", c);
-		else
-		if(c & 0x80){
-			nearln = lineno;
-			warn(Z, "sign-extended character constant");
-		}
-		yylval.vval = convvtox(vv, TCHAR);
-		return LCONST;
-
-	case '/':
-		c1 = GETC();
-		if(c1 == '*') {
-			for(;;) {
-				c = getr();
-				while(c == '*') {
-					c = getr();
-					if(c == '/')
-						goto l0;
-				}
-				if(c == EOF) {
-					yyerror("eof in comment");
-					errorexit();
-				}
-			}
-		}
-		if(c1 == '/') {
-			for(;;) {
-				c = getr();
-				if(c == '\n')
-					goto l0;
-				if(c == EOF) {
-					yyerror("eof in comment");
-					errorexit();
-				}
-			}
-		}
-		if(c1 == '=')
-			return LDVE;
-		break;
-
-	case '*':
-		c1 = GETC();
-		if(c1 == '=')
-			return LMLE;
-		break;
-
-	case '%':
-		c1 = GETC();
-		if(c1 == '=')
-			return LMDE;
-		break;
-
-	case '+':
-		c1 = GETC();
-		if(c1 == '+')
-			return LPP;
-		if(c1 == '=')
-			return LPE;
-		break;
-
-	case '-':
-		c1 = GETC();
-		if(c1 == '-')
-			return LMM;
-		if(c1 == '=')
-			return LME;
-		if(c1 == '>')
-			return LMG;
-		break;
-
-	case '>':
-		c1 = GETC();
-		if(c1 == '>') {
-			c = LRSH;
-			c1 = GETC();
-			if(c1 == '=')
-				return LRSHE;
-			break;
-		}
-		if(c1 == '=')
-			return LGE;
-		break;
-
-	case '<':
-		c1 = GETC();
-		if(c1 == '<') {
-			c = LLSH;
-			c1 = GETC();
-			if(c1 == '=')
-				return LLSHE;
-			break;
-		}
-		if(c1 == '=')
-			return LLE;
-		break;
-
-	case '=':
-		c1 = GETC();
-		if(c1 == '=')
-			return LEQ;
-		break;
-
-	case '!':
-		c1 = GETC();
-		if(c1 == '=')
-			return LNE;
-		break;
-
-	case '&':
-		c1 = GETC();
-		if(c1 == '&')
-			return LANDAND;
-		if(c1 == '=')
-			return LANDE;
-		break;
-
-	case '|':
-		c1 = GETC();
-		if(c1 == '|')
-			return LOROR;
-		if(c1 == '=')
-			return LORE;
-		break;
-
-	case '^':
-		c1 = GETC();
-		if(c1 == '=')
-			return LXORE;
-		break;
-
-	default:
-		return c;
-	}
-	peekc = c1;
-	return c;
-
-talph:
-	/*
-	 * cp is set to symb and some
-	 * prefix has been stored
-	 */
-	for(;;) {
-		if(c >= Runeself) {
-			for(c1=0;;) {
-				cp[c1++] = c;
-				if(fullrune(cp, c1))
-					break;
-				c = GETC();
-			}
-			cp += c1;
-			c = GETC();
-			continue;
-		}
-		if(!isalnum(c) && c != '_')
-			break;
-		*cp++ = c;
-		c = GETC();
-	}
-	*cp = 0;
-	if(debug['L'])
-		print("%L: %s\n", lineno, symb);
-	peekc = c;
-	s = lookup();
-	if(s->macro) {
-		newio();
-		cp = ionext->b;
-		macexpand(s, cp);
-		pushio();
-		ionext->link = iostack;
-		iostack = ionext;
-		fi.p = cp;
-		fi.c = strlen(cp);
-		if(peekc != IGN) {
-			cp[fi.c++] = peekc;
-			cp[fi.c] = 0;
-			peekc = IGN;
-		}
-		goto l0;
-	}
-	yylval.sym = s;
-	if(s->class == CTYPEDEF || s->class == CTYPESTR)
-		return LTYPE;
-	return s->lexical;
-
-tnum:
-	c1 = 0;
-	cp = symb;
-	if(c != '0') {
-		c1 |= Numdec;
-		for(;;) {
-			*cp++ = c;
-			c = GETC();
-			if(isdigit(c))
-				continue;
-			goto dc;
-		}
-	}
-	*cp++ = c;
-	c = GETC();
-	if(c == 'x' || c == 'X')
-		for(;;) {
-			*cp++ = c;
-			c = GETC();
-			if(isdigit(c))
-				continue;
-			if(c >= 'a' && c <= 'f')
-				continue;
-			if(c >= 'A' && c <= 'F')
-				continue;
-			if(cp == symb+2)
-				yyerror("malformed hex constant");
-			goto ncu;
-		}
-	if(c < '0' || c > '7')
-		goto dc;
-	for(;;) {
-		if(c >= '0' && c <= '7') {
-			*cp++ = c;
-			c = GETC();
-			continue;
-		}
-		goto ncu;
-	}
-
-dc:
-	if(c == '.')
-		goto casedot;
-	if(c == 'e' || c == 'E')
-		goto casee;
-
-ncu:
-	if((c == 'U' || c == 'u') && !(c1 & Numuns)) {
-		c = GETC();
-		c1 |= Numuns;
-		goto ncu;
-	}
-	if((c == 'L' || c == 'l') && !(c1 & Numvlong)) {
-		c = GETC();
-		if(c1 & Numlong)
-			c1 |= Numvlong;
-		c1 |= Numlong;
-		goto ncu;
-	}
-	*cp = 0;
-	peekc = c;
-	if(mpatov(symb, &yylval.vval))
-		yyerror("overflow in constant");
-
-	vv = yylval.vval;
-	if(c1 & Numvlong) {
-		if((c1 & Numuns) || convvtox(vv, TVLONG) < 0) {
-			c = LUVLCONST;
-			t = TUVLONG;
-			goto nret;
-		}
-		c = LVLCONST;
-		t = TVLONG;
-		goto nret;
-	}
-	if(c1 & Numlong) {
-		if((c1 & Numuns) || convvtox(vv, TLONG) < 0) {
-			c = LULCONST;
-			t = TULONG;
-			goto nret;
-		}
-		c = LLCONST;
-		t = TLONG;
-		goto nret;
-	}
-	if((c1 & Numuns) || convvtox(vv, TINT) < 0) {
-		c = LUCONST;
-		t = TUINT;
-		goto nret;
-	}
-	c = LCONST;
-	t = TINT;
-	goto nret;
-
-nret:
-	yylval.vval = convvtox(vv, t);
-	if(yylval.vval != vv){
-		nearln = lineno;
-		warn(Z, "truncated constant: %T %s", types[t], symb);
-	}
-	return c;
-
-casedot:
-	for(;;) {
-		*cp++ = c;
-		c = GETC();
-		if(!isdigit(c))
-			break;
-	}
-	if(c != 'e' && c != 'E')
-		goto caseout;
-
-casee:
-	*cp++ = 'e';
-	c = GETC();
-	if(c == '+' || c == '-') {
-		*cp++ = c;
-		c = GETC();
-	}
-	if(!isdigit(c))
-		yyerror("malformed fp constant exponent");
-	while(isdigit(c)) {
-		*cp++ = c;
-		c = GETC();
-	}
-
-caseout:
-	if(c == 'L' || c == 'l') {
-		c = GETC();
-		c1 |= Numlong;
-	} else
-	if(c == 'F' || c == 'f') {
-		c = GETC();
-		c1 |= Numflt;
-	}
-	*cp = 0;
-	peekc = c;
-	yylval.dval = strtod(symb, nil);
-	if(isInf(yylval.dval, 1) || isInf(yylval.dval, -1)) {
-		yyerror("overflow in float constant");
-		yylval.dval = 0;
-	}
-	if(c1 & Numflt)
-		return LFCONST;
-	return LDCONST;
-}
-
-/*
- * convert a string, s, to vlong in *v
- * return conversion overflow.
- * required syntax is [0[x]]d*
- */
-int
-mpatov(char *s, vlong *v)
-{
-	vlong n, nn;
-	int c;
-
-	n = 0;
-	c = *s;
-	if(c == '0')
-		goto oct;
-	while(c = *s++) {
-		if(c >= '0' && c <= '9')
-			nn = n*10 + c-'0';
-		else
-			goto bad;
-		if(n < 0 && nn >= 0)
-			goto bad;
-		n = nn;
-	}
-	goto out;
-
-oct:
-	s++;
-	c = *s;
-	if(c == 'x' || c == 'X')
-		goto hex;
-	while(c = *s++) {
-		if(c >= '0' || c <= '7')
-			nn = n*8 + c-'0';
-		else
-			goto bad;
-		if(n < 0 && nn >= 0)
-			goto bad;
-		n = nn;
-	}
-	goto out;
-
-hex:
-	s++;
-	while(c = *s++) {
-		if(c >= '0' && c <= '9')
-			c += 0-'0';
-		else
-		if(c >= 'a' && c <= 'f')
-			c += 10-'a';
-		else
-		if(c >= 'A' && c <= 'F')
-			c += 10-'A';
-		else
-			goto bad;
-		nn = (uvlong)n*16 + c;
-		if(n < 0 && nn >= 0)
-			goto bad;
-		n = nn;
-	}
-out:
-	*v = n;
-	return 0;
-
-bad:
-	*v = ~0;
-	return 1;
-}
-
-int
-getc(void)
-{
-	int c;
-
-	if(peekc != IGN) {
-		c = peekc;
-		peekc = IGN;
-	} else
-		c = GETC();
-	if(c == '\n')
-		lineno++;
-	if(c == EOF) {
-		yyerror("End of file");
-		errorexit();
-	}
-	return c;
-}
-
-int32
-getr(void)
-{
-	int c, i;
-	char str[UTFmax+1];
-	Rune rune;
-
-
-	c = getc();
-	if(c < Runeself)
-		return c;
-	i = 0;
-	str[i++] = c;
-
-loop:
-	c = getc();
-	str[i++] = c;
-	if(!fullrune(str, i))
-		goto loop;
-	c = chartorune(&rune, str);
-	if(rune == Runeerror && c == 1) {
-		nearln = lineno;
-		diag(Z, "illegal rune in string");
-		for(c=0; c<i; c++)
-			print(" %.2x", *(uchar*)(str+c));
-		print("\n");
-	}
-	return rune;
-}
-
-int
-getnsc(void)
-{
-	int c;
-
-	if(peekc != IGN) {
-		c = peekc;
-		peekc = IGN;
-	} else
-		c = GETC();
-	for(;;) {
-		if(c >= Runeself || !isspace(c))
-			return c;
-		if(c == '\n') {
-			lineno++;
-			return c;
-		}
-		c = GETC();
-	}
-}
-
-void
-unget(int c)
-{
-
-	peekc = c;
-	if(c == '\n')
-		lineno--;
-}
-
-int32
-escchar(int32 e, int longflg, int escflg)
-{
-	int32 c, l;
-	int i;
-
-loop:
-	c = getr();
-	if(c == '\n') {
-		yyerror("newline in string");
-		return EOF;
-	}
-	if(c != '\\') {
-		if(c == e)
-			c = EOF;
-		return c;
-	}
-	c = getr();
-	if(c == 'x') {
-		/*
-		 * note this is not ansi,
-		 * supposed to only accept 2 hex
-		 */
-		i = 2;
-		if(longflg)
-			i = 6;
-		l = 0;
-		for(; i>0; i--) {
-			c = getc();
-			if(c >= '0' && c <= '9') {
-				l = l*16 + c-'0';
-				continue;
-			}
-			if(c >= 'a' && c <= 'f') {
-				l = l*16 + c-'a' + 10;
-				continue;
-			}
-			if(c >= 'A' && c <= 'F') {
-				l = l*16 + c-'A' + 10;
-				continue;
-			}
-			unget(c);
-			break;
-		}
-		if(escflg)
-			l |= ESC;
-		return l;
-	}
-	if(c >= '0' && c <= '7') {
-		/*
-		 * note this is not ansi,
-		 * supposed to only accept 3 oct
-		 */
-		i = 2;
-		if(longflg)
-			i = 8;
-		l = c - '0';
-		for(; i>0; i--) {
-			c = getc();
-			if(c >= '0' && c <= '7') {
-				l = l*8 + c-'0';
-				continue;
-			}
-			unget(c);
-		}
-		if(escflg)
-			l |= ESC;
-		return l;
-	}
-	switch(c)
-	{
-	case '\n':	goto loop;
-	case 'n':	return '\n';
-	case 't':	return '\t';
-	case 'b':	return '\b';
-	case 'r':	return '\r';
-	case 'f':	return '\f';
-	case 'a':	return '\a';
-	case 'v':	return '\v';
-	}
-	return c;
-}
-
-struct
-{
-	char	*name;
-	ushort	lexical;
-	ushort	type;
-} itab[] =
-{
-	"auto",		LAUTO,		0,
-	"break",	LBREAK,		0,
-	"case",		LCASE,		0,
-	"char",		LCHAR,		TCHAR,
-	"const",	LCONSTNT,	0,
-	"continue",	LCONTINUE,	0,
-	"default",	LDEFAULT,	0,
-	"do",		LDO,		0,
-	"double",	LDOUBLE,	TDOUBLE,
-	"else",		LELSE,		0,
-	"enum",		LENUM,		0,
-	"extern",	LEXTERN,	0,
-	"float",	LFLOAT,		TFLOAT,
-	"for",		LFOR,		0,
-	"goto",		LGOTO,		0,
-	"if",		LIF,		0,
-	"inline",	LINLINE,	0,
-	"int",		LINT,		TINT,
-	"long",		LLONG,		TLONG,
-	"PREFETCH",	LPREFETCH,	0,
-	"register",	LREGISTER,	0,
-	"restrict",	LRESTRICT,	0,
-	"return",	LRETURN,	0,
-	"SET",		LSET,		0,
-	"short",	LSHORT,		TSHORT,
-	"signed",	LSIGNED,	0,
-	"signof",	LSIGNOF,	0,
-	"sizeof",	LSIZEOF,	0,
-	"static",	LSTATIC,	0,
-	"struct",	LSTRUCT,	0,
-	"switch",	LSWITCH,	0,
-	"typedef",	LTYPEDEF,	0,
-	"typestr",	LTYPESTR,	0,
-	"union",	LUNION,		0,
-	"unsigned",	LUNSIGNED,	0,
-	"USED",		LUSED,		0,
-	"void",		LVOID,		TVOID,
-	"volatile",	LVOLATILE,	0,
-	"while",	LWHILE,		0,
-	0
-};
-
-void
-cinit(void)
-{
-	Sym *s;
-	int i;
-	Type *t;
-
-	nerrors = 0;
-	lineno = 1;
-	iostack = I;
-	iofree = I;
-	peekc = IGN;
-	nhunk = 0;
-
-	types[TXXX] = T;
-	types[TCHAR] = typ(TCHAR, T);
-	types[TUCHAR] = typ(TUCHAR, T);
-	types[TSHORT] = typ(TSHORT, T);
-	types[TUSHORT] = typ(TUSHORT, T);
-	types[TINT] = typ(TINT, T);
-	types[TUINT] = typ(TUINT, T);
-	types[TLONG] = typ(TLONG, T);
-	types[TULONG] = typ(TULONG, T);
-	types[TVLONG] = typ(TVLONG, T);
-	types[TUVLONG] = typ(TUVLONG, T);
-	types[TFLOAT] = typ(TFLOAT, T);
-	types[TDOUBLE] = typ(TDOUBLE, T);
-	types[TVOID] = typ(TVOID, T);
-	types[TENUM] = typ(TENUM, T);
-	types[TFUNC] = typ(TFUNC, types[TINT]);
-	types[TIND] = typ(TIND, types[TVOID]);
-
-	for(i=0; i<NHASH; i++)
-		hash[i] = S;
-	for(i=0; itab[i].name; i++) {
-		s = slookup(itab[i].name);
-		s->lexical = itab[i].lexical;
-		if(itab[i].type != 0)
-			s->type = types[itab[i].type];
-	}
-	blockno = 0;
-	autobn = 0;
-	autoffset = 0;
-
-	t = typ(TARRAY, types[TCHAR]);
-	t->width = 0;
-	symstring = slookup(".string");
-	symstring->class = CSTATIC;
-	symstring->dataflag = NOPTR;
-	symstring->type = t;
-
-	t = typ(TARRAY, types[TCHAR]);
-	t->width = 0;
-
-	nodproto = new(OPROTO, Z, Z);
-	dclstack = D;
-
-	fmtinstall('O', Oconv);
-	fmtinstall('T', Tconv);
-	fmtinstall('F', FNconv);
-	fmtinstall('L', Lconv);
-	fmtinstall('Q', Qconv);
-	fmtinstall('|', VBconv);
-	fmtinstall('U', Uconv);
-	fmtinstall('B', Bconv);
-}
-
-int
-filbuf(void)
-{
-	Io *i;
-
-loop:
-	i = iostack;
-	if(i == I)
-		return EOF;
-	if(i->f < 0)
-		goto pop;
-	fi.c = read(i->f, i->b, BUFSIZ) - 1;
-	if(fi.c < 0) {
-		close(i->f);
-		linklinehist(ctxt, lineno, nil, 0);
-		goto pop;
-	}
-	fi.p = i->b + 1;
-	return i->b[0] & 0xff;
-
-pop:
-	iostack = i->link;
-	i->link = iofree;
-	iofree = i;
-	i = iostack;
-	if(i == I)
-		return EOF;
-	fi.p = i->p;
-	fi.c = i->c;
-	if(--fi.c < 0)
-		goto loop;
-	return *fi.p++ & 0xff;
-}
-
-int
-Oconv(Fmt *fp)
-{
-	int a;
-
-	a = va_arg(fp->args, int);
-	if(a < OXXX || a > OEND)
-		return fmtprint(fp, "***badO %d***", a);
-
-	return fmtstrcpy(fp, onames[a]);
-}
-
-int
-Lconv(Fmt *fp)
-{
-	return linklinefmt(ctxt, fp);
-}
-
-int
-Tconv(Fmt *fp)
-{
-	char str[STRINGSZ+20], s[STRINGSZ+20];
-	Type *t, *t1;
-	int et;
-	int32 n;
-
-	str[0] = 0;
-	for(t = va_arg(fp->args, Type*); t != T; t = t->link) {
-		et = t->etype;
-		if(str[0])
-			strcat(str, " ");
-		if(t->garb&~GINCOMPLETE) {
-			sprint(s, "%s ", gnames[t->garb&~GINCOMPLETE]);
-			if(strlen(str) + strlen(s) < STRINGSZ)
-				strcat(str, s);
-		}
-		sprint(s, "%s", tnames[et]);
-		if(strlen(str) + strlen(s) < STRINGSZ)
-			strcat(str, s);
-		if(et == TFUNC && (t1 = t->down)) {
-			sprint(s, "(%T", t1);
-			if(strlen(str) + strlen(s) < STRINGSZ)
-				strcat(str, s);
-			while(t1 = t1->down) {
-				sprint(s, ", %T", t1);
-				if(strlen(str) + strlen(s) < STRINGSZ)
-					strcat(str, s);
-			}
-			if(strlen(str) + strlen(s) < STRINGSZ)
-				strcat(str, ")");
-		}
-		if(et == TARRAY) {
-			n = t->width;
-			if(t->link && t->link->width)
-				n /= t->link->width;
-			sprint(s, "[%d]", n);
-			if(strlen(str) + strlen(s) < STRINGSZ)
-				strcat(str, s);
-		}
-		if(t->nbits) {
-			sprint(s, " %d:%d", t->shift, t->nbits);
-			if(strlen(str) + strlen(s) < STRINGSZ)
-				strcat(str, s);
-		}
-		if(typesu[et]) {
-			if(t->tag) {
-				strcat(str, " ");
-				if(strlen(str) + strlen(t->tag->name) < STRINGSZ)
-					strcat(str, t->tag->name);
-			} else
-				strcat(str, " {}");
-			break;
-		}
-	}
-	return fmtstrcpy(fp, str);
-}
-
-int
-FNconv(Fmt *fp)
-{
-	char *str;
-	Node *n;
-
-	n = va_arg(fp->args, Node*);
-	str = "<indirect>";
-	if(n != Z && (n->op == ONAME || n->op == ODOT || n->op == OELEM))
-		str = n->sym->name;
-	return fmtstrcpy(fp, str);
-}
-
-int
-Qconv(Fmt *fp)
-{
-	char str[STRINGSZ+20], *s;
-	int32 b;
-	int i;
-
-	str[0] = 0;
-	for(b = va_arg(fp->args, int32); b;) {
-		i = bitno(b);
-		if(str[0])
-			strcat(str, " ");
-		s = qnames[i];
-		if(strlen(str) + strlen(s) >= STRINGSZ)
-			break;
-		strcat(str, s);
-		b &= ~(1L << i);
-	}
-	return fmtstrcpy(fp, str);
-}
-
-int
-VBconv(Fmt *fp)
-{
-	char str[STRINGSZ];
-	int i, n, t, pc;
-
-	n = va_arg(fp->args, int);
-	pc = 0;	/* BUG: was printcol */
-	i = 0;
-	while(pc < n) {
-		t = (pc+4) & ~3;
-		if(t <= n) {
-			str[i++] = '\t';
-			pc = t;
-			continue;
-		}
-		str[i++] = ' ';
-		pc++;
-	}
-	str[i] = 0;
-
-	return fmtstrcpy(fp, str);
-}
-
-int
-Bconv(Fmt *fp)
-{
-	char str[STRINGSZ], ss[STRINGSZ], *s;
-	Bits bits;
-	int i;
-
-	str[0] = 0;
-	bits = va_arg(fp->args, Bits);
-	while(bany(&bits)) {
-		i = bnum(bits);
-		if(str[0])
-			strcat(str, " ");
-		if(var[i].sym == nil) {
-			sprint(ss, "$%lld", var[i].offset);
-			s = ss;
-		} else
-			s = var[i].sym->name;
-		if(strlen(str) + strlen(s) + 1 >= STRINGSZ)
-			break;
-		strcat(str, s);
-		bits.b[i/32] &= ~(1L << (i%32));
-	}
-	return fmtstrcpy(fp, str);
-}
-
-void
-setinclude(char *p)
-{
-	int i;
-
-	if(*p != 0) {
-		for(i=1; i < ninclude; i++)
-			if(strcmp(p, include[i]) == 0)
-				return;
-
-		if(ninclude%8 == 0)
-			include = allocn(include, ninclude*sizeof(char *),
-				8*sizeof(char *));
-		include[ninclude++] = p;
-	}
-}
-
-void*
-alloc(int32 n)
-{
-	void *p;
-
-	p = malloc(n);
-	if(p == nil) {
-		print("alloc out of mem\n");
-		exits("alloc: out of mem");
-	}
-	memset(p, 0, n);
-	return p;
-}
-
-void*
-allocn(void *p, int32 n, int32 d)
-{
-	if(p == nil)
-		return alloc(n+d);
-	p = realloc(p, n+d);
-	if(p == nil) {
-		print("allocn out of mem\n");
-		exits("allocn: out of mem");
-	}
-	if(d > 0)
-		memset((char*)p+n, 0, d);
-	return p;
-}
-
-void
-ensuresymb(int32 n)
-{
-	if(symb == nil) {
-		symb = alloc(NSYMB+1);
-		nsymb = NSYMB;
-	}
-
-	if(n > nsymb) {
-		symb = allocn(symb, nsymb, n+1-nsymb);
-		nsymb = n;
-	}
-}
diff --git a/src/cmd/cc/lexbody b/src/cmd/cc/lexbody
deleted file mode 100644
index e24db1b..0000000
--- a/src/cmd/cc/lexbody
+++ /dev/null
@@ -1,709 +0,0 @@
-// Inferno utils/cc/lexbody
-// http://code.google.com/p/inferno-os/source/browse/utils/cc/lexbody
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-/*
- * common code for all the assemblers
- */
-
-void
-pragpack(void)
-{
-	while(getnsc() != '\n')
-		;
-}
-
-void
-pragvararg(void)
-{
-	while(getnsc() != '\n')
-		;
-}
-
-void
-pragcgo(char *name)
-{
-	USED(name);
-	while(getnsc() != '\n')
-		;
-}
-
-void
-pragfpround(void)
-{
-	while(getnsc() != '\n')
-		;
-}
-
-void
-pragtextflag(void)
-{
-	while(getnsc() != '\n')
-		;
-}
-
-void
-pragdataflag(void)
-{
-	while(getnsc() != '\n')
-		;
-}
-
-void
-pragprofile(void)
-{
-	while(getnsc() != '\n')
-		;
-}
-
-void
-pragincomplete(void)
-{
-	while(getnsc() != '\n')
-		;
-}
-
-void*
-alloc(int32 n)
-{
-	void *p;
-
-	p = malloc(n);
-	if(p == nil) {
-		print("alloc out of mem\n");
-		exits("alloc: out of mem");
-	}
-	memset(p, 0, n);
-	return p;
-}
-
-void*
-allocn(void *p, int32 n, int32 d)
-{
-	if(p == nil)
-		return alloc(n+d);
-	p = realloc(p, n+d);
-	if(p == nil) {
-		print("allocn out of mem\n");
-		exits("allocn: out of mem");
-	}
-	if(d > 0)
-		memset((char*)p+n, 0, d);
-	return p;
-}
-
-void
-ensuresymb(int32 n)
-{
-	if(symb == nil) {
-		symb = alloc(NSYMB+1);
-		nsymb = NSYMB;
-	}
-
-	if(n > nsymb) {
-		symb = allocn(symb, nsymb, n+1-nsymb);
-		nsymb = n;
-	}
-}
-
-void
-setinclude(char *p)
-{
-	int i;
-
-	if(p == 0)
-		return;
-	for(i=1; i < ninclude; i++)
-		if(strcmp(p, include[i]) == 0)
-			return;
-	
-	if(ninclude%8 == 0)
-		include = allocn(include, ninclude*sizeof(char *), 
-			8*sizeof(char *));
-	include[ninclude++] = p;
-}
-
-void
-errorexit(void)
-{
-	Bflush(&bstdout);
-	if(outfile)
-		remove(outfile);
-	exits("error");
-}
-
-void
-pushio(void)
-{
-	Io *i;
-
-	i = iostack;
-	if(i == I) {
-		yyerror("botch in pushio");
-		errorexit();
-	}
-	i->p = fi.p;
-	i->c = fi.c;
-}
-
-void
-newio(void)
-{
-	Io *i;
-	static int pushdepth = 0;
-
-	i = iofree;
-	if(i == I) {
-		pushdepth++;
-		if(pushdepth > 1000) {
-			yyerror("macro/io expansion too deep");
-			errorexit();
-		}
-		i = alloc(sizeof(*i));
-	} else
-		iofree = i->link;
-	i->c = 0;
-	i->f = -1;
-	ionext = i;
-}
-
-void
-newfile(char *s, int f)
-{
-	Io *i;
-
-	i = ionext;
-	i->link = iostack;
-	iostack = i;
-	i->f = f;
-	if(f < 0)
-		i->f = open(s, 0);
-	if(i->f < 0) {
-		yyerror("%ca: %r: %s", thechar, s);
-		errorexit();
-	}
-	fi.c = 0;
-	linklinehist(ctxt, lineno, s, 0);
-}
-
-Sym*
-slookup(char *s)
-{
-	ensuresymb(strlen(s));
-	strcpy(symb, s);
-	return lookup();
-}
-
-Sym*
-lookup(void)
-{
-	Sym *s;
-	uint32 h;
-	char *p;
-	int c, l;
-	char *r, *w;
-
-	if((uchar)symb[0] == 0xc2 && (uchar)symb[1] == 0xb7) {
-		// turn leading · into ""·
-		h = strlen(symb);
-		ensuresymb(h+2);
-		memmove(symb+2, symb, h+1);
-		symb[0] = '"';
-		symb[1] = '"';
-	}
-
-	for(r=w=symb; *r; r++) {
-		// turn · (U+00B7) into .
-		// turn ∕ (U+2215) into /
-		if((uchar)*r == 0xc2 && (uchar)*(r+1) == 0xb7) {
-			*w++ = '.';
-			r++;
-		}else if((uchar)*r == 0xe2 && (uchar)*(r+1) == 0x88 && (uchar)*(r+2) == 0x95) {
-			*w++ = '/';
-			r++;
-			r++;
-		}else
-			*w++ = *r;
-	}
-	*w = '\0';
-
-	h = 0;
-	for(p=symb; c = *p; p++)
-		h = h+h+h + c;
-	l = (p - symb) + 1;
-	h &= 0xffffff;
-	h %= NHASH;
-	c = symb[0];
-	for(s = hash[h]; s != S; s = s->link) {
-		if(s->name[0] != c)
-			continue;
-		if(strcmp(s->name, symb) == 0)
-			return s;
-	}
-	s = alloc(sizeof(*s));
-	s->name = alloc(l);
-	memmove(s->name, symb, l);
-
-	s->link = hash[h];
-	hash[h] = s;
-	syminit(s);
-	return s;
-}
-
-int
-ISALPHA(int c)
-{
-	if(isalpha(c))
-		return 1;
-	if(c >= Runeself)
-		return 1;
-	return 0;
-}
-
-int32
-yylex(void)
-{
-	int c, c1;
-	char *cp;
-	Sym *s;
-
-	c = peekc;
-	if(c != IGN) {
-		peekc = IGN;
-		goto l1;
-	}
-l0:
-	c = GETC();
-
-l1:
-	if(c == EOF) {
-		peekc = EOF;
-		return -1;
-	}
-	if(isspace(c)) {
-		if(c == '\n') {
-			lineno++;
-			return ';';
-		}
-		goto l0;
-	}
-	if(ISALPHA(c))
-		goto talph;
-	if(isdigit(c))
-		goto tnum;
-	switch(c)
-	{
-	case '\n':
-		lineno++;
-		return ';';
-
-	case '#':
-		domacro();
-		goto l0;
-
-	case '.':
-		c = GETC();
-		if(ISALPHA(c)) {
-			cp = symb;
-			*cp++ = '.';
-			goto aloop;
-		}
-		if(isdigit(c)) {
-			cp = symb;
-			*cp++ = '.';
-			goto casedot;
-		}
-		peekc = c;
-		return '.';
-
-	talph:
-	case '_':
-	case '@':
-		cp = symb;
-
-	aloop:
-		*cp++ = c;
-		c = GETC();
-		if(ISALPHA(c) || isdigit(c) || c == '_' || c == '$')
-			goto aloop;
-		*cp = 0;
-		peekc = c;
-		s = lookup();
-		if(s->macro) {
-			newio();
-			cp = ionext->b;
-			macexpand(s, cp);
-			pushio();
-			ionext->link = iostack;
-			iostack = ionext;
-			fi.p = cp;
-			fi.c = strlen(cp);
-			if(peekc != IGN) {
-				cp[fi.c++] = peekc;
-				cp[fi.c] = 0;
-				peekc = IGN;
-			}
-			goto l0;
-		}
-		if(s->type == 0)
-			s->type = LNAME;
-		if(s->type == LNAME ||
-		   s->type == LVAR ||
-		   s->type == LLAB) {
-			yylval.sym = s;
-			return s->type;
-		}
-		yylval.lval = s->value;
-		return s->type;
-
-	tnum:
-		cp = symb;
-		if(c != '0')
-			goto dc;
-		*cp++ = 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 = (uvlong)yylval.lval << c1;
-				yylval.lval += c - '0';
-				c = GETC();
-				continue;
-			}
-			if(c1 == 3)
-				break;
-			if(c >= 'A' && c <= 'F')
-				c += 'a' - 'A';
-			if(c >= 'a' && c <= 'f') {
-				yylval.lval = (uvlong)yylval.lval << c1;
-				yylval.lval += c - 'a' + 10;
-				c = GETC();
-				continue;
-			}
-			break;
-		}
-		goto ncu;
-
-	dc:
-		for(;;) {
-			if(!isdigit(c))
-				break;
-			*cp++ = c;
-			c = GETC();
-		}
-		if(c == '.')
-			goto casedot;
-		if(c == 'e' || c == 'E')
-			goto casee;
-		*cp = 0;
-		if(sizeof(yylval.lval) == sizeof(vlong))
-			yylval.lval = strtoll(symb, nil, 10);
-		else
-			yylval.lval = strtol(symb, nil, 10);
-
-	ncu:
-		while(c == 'U' || c == 'u' || c == 'l' || c == 'L')
-			c = GETC();
-		peekc = c;
-		return LCONST;
-
-	casedot:
-		for(;;) {
-			*cp++ = c;
-			c = GETC();
-			if(!isdigit(c))
-				break;
-		}
-		if(c == 'e' || c == 'E')
-			goto casee;
-		goto caseout;
-
-	casee:
-		*cp++ = 'e';
-		c = GETC();
-		if(c == '+' || c == '-') {
-			*cp++ = c;
-			c = GETC();
-		}
-		while(isdigit(c)) {
-			*cp++ = c;
-			c = GETC();
-		}
-
-	caseout:
-		*cp = 0;
-		peekc = c;
-		if(FPCHIP) {
-			yylval.dval = atof(symb);
-			return LFCONST;
-		}
-		yyerror("assembler cannot interpret fp constants");
-		yylval.lval = 1L;
-		return LCONST;
-
-	case '"':
-		memcpy(yylval.sval, nullgen.u.sval, sizeof(yylval.sval));
-		cp = yylval.sval;
-		c1 = 0;
-		for(;;) {
-			c = escchar('"');
-			if(c == EOF)
-				break;
-			if(c1 < sizeof(yylval.sval))
-				*cp++ = c;
-			c1++;
-		}
-		if(c1 > sizeof(yylval.sval))
-			yyerror("string constant too long");
-		return LSCONST;
-
-	case '\'':
-		c = escchar('\'');
-		if(c == EOF)
-			c = '\'';
-		if(escchar('\'') != EOF)
-			yyerror("missing '");
-		yylval.lval = c;
-		return LCONST;
-
-	case '/':
-		c1 = GETC();
-		if(c1 == '/') {
-			for(;;) {
-				c = GETC();
-				if(c == '\n')
-					goto l1;
-				if(c == EOF) {
-					yyerror("eof in comment");
-					errorexit();
-				}
-			}
-		}
-		if(c1 == '*') {
-			for(;;) {
-				c = GETC();
-				while(c == '*') {
-					c = GETC();
-					if(c == '/')
-						goto l0;
-				}
-				if(c == EOF) {
-					yyerror("eof in comment");
-					errorexit();
-				}
-				if(c == '\n')
-					lineno++;
-			}
-		}
-		break;
-
-	default:
-		return c;
-	}
-	peekc = c1;
-	return c;
-}
-
-int
-getc(void)
-{
-	int c;
-
-	c = peekc;
-	if(c != IGN) {
-		peekc = IGN;
-		return c;
-	}
-	c = GETC();
-	if(c == '\n')
-		lineno++;
-	if(c == EOF) {
-		yyerror("End of file");
-		errorexit();
-	}
-	return c;
-}
-
-int
-getnsc(void)
-{
-	int c;
-
-	for(;;) {
-		c = getc();
-		if(!isspace(c) || c == '\n')
-			return c;
-	}
-}
-
-void
-unget(int c)
-{
-
-	peekc = c;
-	if(c == '\n')
-		lineno--;
-}
-
-int
-escchar(int e)
-{
-	int c, l;
-
-loop:
-	c = getc();
-	if(c == '\n') {
-		yyerror("newline in string");
-		return EOF;
-	}
-	if(c != '\\') {
-		if(c == e)
-			return EOF;
-		return c;
-	}
-	c = getc();
-	if(c >= '0' && c <= '7') {
-		l = c - '0';
-		c = getc();
-		if(c >= '0' && c <= '7') {
-			l = l*8 + c-'0';
-			c = getc();
-			if(c >= '0' && c <= '7') {
-				l = l*8 + c-'0';
-				return l;
-			}
-		}
-		peekc = c;
-		return l;
-	}
-	switch(c)
-	{
-	case '\n':	goto loop;
-	case 'n':	return '\n';
-	case 't':	return '\t';
-	case 'b':	return '\b';
-	case 'r':	return '\r';
-	case 'f':	return '\f';
-	case 'a':	return 0x07;
-	case 'v':	return 0x0b;
-	case 'z':	return 0x00;
-	}
-	return c;
-}
-
-void
-pinit(char *f)
-{
-	int i;
-	Sym *s;
-
-	lineno = 1;
-	newio();
-	newfile(f, -1);
-	pc = 0;
-	peekc = IGN;
-	sym = 1;
-	for(i=0; i<NHASH; i++)
-		for(s = hash[i]; s != S; s = s->link)
-			s->macro = 0;
-}
-
-int
-filbuf(void)
-{
-	Io *i;
-
-loop:
-	i = iostack;
-	if(i == I)
-		return EOF;
-	if(i->f < 0)
-		goto pop;
-	fi.c = read(i->f, i->b, BUFSIZ) - 1;
-	if(fi.c < 0) {
-		close(i->f);
-		linklinehist(ctxt, lineno, 0, 0);
-		goto pop;
-	}
-	fi.p = i->b + 1;
-	return i->b[0] & 0xff;
-
-pop:
-	iostack = i->link;
-	i->link = iofree;
-	iofree = i;
-	i = iostack;
-	if(i == I)
-		return EOF;
-	fi.p = i->p;
-	fi.c = i->c;
-	if(--fi.c < 0)
-		goto loop;
-	return *fi.p++ & 0xff;
-}
-
-void
-yyerror(char *a, ...)
-{
-	char buf[200];
-	va_list arg;
-
-	/*
-	 * hack to intercept message from yaccpar
-	 */
-	if(strcmp(a, "syntax error") == 0) {
-		yyerror("syntax error, last name: %s", symb);
-		return;
-	}
-	prfile(lineno);
-	va_start(arg, a);
-	vseprint(buf, buf+sizeof(buf), a, arg);
-	va_end(arg);
-	print("%s\n", buf);
-	nerrors++;
-	if(nerrors > 10) {
-		print("too many errors\n");
-		errorexit();
-	}
-}
-
-void
-prfile(int32 l)
-{
-	linkprfile(ctxt, l);
-}
diff --git a/src/cmd/cc/mac.c b/src/cmd/cc/mac.c
deleted file mode 100644
index b969662..0000000
--- a/src/cmd/cc/mac.c
+++ /dev/null
@@ -1,34 +0,0 @@
-// Inferno utils/cc/mac.c
-// http://code.google.com/p/inferno-os/source/browse/utils/cc/mac.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include	<u.h>
-#include	"cc.h"
-
-#include	"macbody"
diff --git a/src/cmd/cc/macbody b/src/cmd/cc/macbody
deleted file mode 100644
index f6927b2..0000000
--- a/src/cmd/cc/macbody
+++ /dev/null
@@ -1,800 +0,0 @@
-// Inferno utils/cc/macbody
-// http://code.google.com/p/inferno-os/source/browse/utils/cc/macbody
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#define VARMAC 0x80
-
-int32
-getnsn(void)
-{
-	int32 n;
-	int c;
-
-	c = getnsc();
-	if(c < '0' || c > '9')
-		return -1;
-	n = 0;
-	while(c >= '0' && c <= '9') {
-		n = n*10 + c-'0';
-		c = getc();
-	}
-	unget(c);
-	return n;
-}
-
-Sym*
-getsym(void)
-{
-	int c;
-	char *cp;
-
-	c = getnsc();
-	if(!isalpha(c) && c != '_' && c < 0x80) {
-		unget(c);
-		return S;
-	}
-	for(cp = symb;;) {
-		if(cp <= symb+NSYMB-4)
-			*cp++ = c;
-		c = getc();
-		if(isalnum(c) || c == '_' || c >= 0x80)
-			continue;
-		unget(c);
-		break;
-	}
-	*cp = 0;
-	if(cp > symb+NSYMB-4)
-		yyerror("symbol too large: %s", symb);
-	return lookup();
-}
-
-Sym*
-getsymdots(int *dots)
-{
-	int c;
-	Sym *s;
-
-	s = getsym();
-	if(s != S)
-		return s;
-
-	c = getnsc();
-	if(c != '.'){
-		unget(c);
-		return S;
-	}
-	if(getc() != '.' || getc() != '.')
-		yyerror("bad dots in macro");
-	*dots = 1;
-	return slookup("__VA_ARGS__");
-}
-
-int
-getcom(void)
-{
-	int c;
-
-	for(;;) {
-		c = getnsc();
-		if(c != '/')
-			break;
-		c = getc();
-		if(c == '/') {
-			while(c != '\n')
-				c = getc();
-			break;
-		}
-		if(c != '*')
-			break;
-		c = getc();
-		for(;;) {
-			if(c == '*') {
-				c = getc();
-				if(c != '/')
-					continue;
-				c = getc();
-				break;
-			}
-			if(c == '\n') {
-				yyerror("comment across newline");
-				break;
-			}
-			c = getc();
-		}
-		if(c == '\n')
-			break;
-	}
-	return c;
-}
-
-void
-dodefine(char *cp)
-{
-	Sym *s;
-	char *p;
-	int32 l;
-
-	ensuresymb(strlen(cp));
-	strcpy(symb, cp);
-	p = strchr(symb, '=');
-	if(p) {
-		*p++ = 0;
-		s = lookup();
-		l = strlen(p) + 2;	/* +1 null, +1 nargs */
-		s->macro = alloc(l);
-		strcpy(s->macro+1, p);
-	} else {
-		s = lookup();
-		s->macro = "\0001";	/* \000 is nargs */
-	}
-	if(debug['m'])
-		print("#define (-D) %s %s\n", s->name, s->macro+1);
-}
-
-struct
-{
-	char	*macname;
-	void	(*macf)(void);
-} mactab[] =
-{
-	"ifdef",	0,	/* macif(0) */
-	"ifndef",	0,	/* macif(1) */
-	"else",		0,	/* macif(2) */
-
-	"line",		maclin,
-	"define",	macdef,
-	"include",	macinc,
-	"undef",	macund,
-
-	"pragma",	macprag,
-	"endif",	macend,
-	0
-};
-
-void
-domacro(void)
-{
-	int i;
-	Sym *s;
-
-	s = getsym();
-	if(s == S)
-		s = slookup("endif");
-	for(i=0; mactab[i].macname; i++)
-		if(strcmp(s->name, mactab[i].macname) == 0) {
-			if(mactab[i].macf)
-				(*mactab[i].macf)();
-			else
-				macif(i);
-			return;
-		}
-	yyerror("unknown #: %s", s->name);
-	macend();
-}
-
-void
-macund(void)
-{
-	Sym *s;
-
-	s = getsym();
-	macend();
-	if(s == S) {
-		yyerror("syntax in #undef");
-		return;
-	}
-	s->macro = 0;
-}
-
-#define	NARG	25
-void
-macdef(void)
-{
-	Sym *s, *a;
-	char *args[NARG], *np, *base;
-	int n, i, c, len, dots;
-	int ischr;
-
-	s = getsym();
-	if(s == S)
-		goto bad;
-	if(s->macro)
-		yyerror("macro redefined: %s", s->name);
-	c = getc();
-	n = -1;
-	dots = 0;
-	if(c == '(') {
-		n++;
-		c = getnsc();
-		if(c != ')') {
-			unget(c);
-			for(;;) {
-				a = getsymdots(&dots);
-				if(a == S)
-					goto bad;
-				if(n >= NARG) {
-					yyerror("too many arguments in #define: %s", s->name);
-					goto bad;
-				}
-				args[n++] = a->name;
-				c = getnsc();
-				if(c == ')')
-					break;
-				if(c != ',' || dots)
-					goto bad;
-			}
-		}
-		c = getc();
-	}
-	if(isspace(c))
-		if(c != '\n')
-			c = getnsc();
-	base = hunk;
-	len = 1;
-	ischr = 0;
-	for(;;) {
-		if(isalpha(c) || c == '_') {
-			np = symb;
-			*np++ = c;
-			c = getc();
-			while(isalnum(c) || c == '_') {
-				*np++ = c;
-				c = getc();
-			}
-			*np = 0;
-			for(i=0; i<n; i++)
-				if(strcmp(symb, args[i]) == 0)
-					break;
-			if(i >= n) {
-				i = strlen(symb);
-				base = allocn(base, len, i);
-				memcpy(base+len, symb, i);
-				len += i;
-				continue;
-			}
-			base = allocn(base, len, 2);
-			base[len++] = '#';
-			base[len++] = 'a' + i;
-			continue;
-		}
-		if(ischr){
-			if(c == '\\'){
-				base = allocn(base, len, 1);
-				base[len++] = c;
-				c = getc();
-			}else if(c == ischr)
-				ischr = 0;
-		}else{
-			if(c == '"' || c == '\''){
-				base = allocn(base, len, 1);
-				base[len++] = c;
-				ischr = c;
-				c = getc();
-				continue;
-			}
-			if(c == '/') {
-				c = getc();
-				if(c == '/'){
-					c = getc();
-					for(;;) {
-						if(c == '\n')
-							break;
-						c = getc();
-					}
-					continue;
-				}
-				if(c == '*'){
-					c = getc();
-					for(;;) {
-						if(c == '*') {
-							c = getc();
-							if(c != '/')
-								continue;
-							c = getc();
-							break;
-						}
-						if(c == '\n') {
-							yyerror("comment and newline in define: %s", s->name);
-							break;
-						}
-						c = getc();
-					}
-					continue;
-				}
-				base = allocn(base, len, 1);
-				base[len++] = '/';
-				continue;
-			}
-		}
-		if(c == '\\') {
-			c = getc();
-			if(c == '\n') {
-				c = getc();
-				continue;
-			}
-			else if(c == '\r') {
-				c = getc();
-				if(c == '\n') {
-					c = getc();
-					continue;
-				}
-			}
-			base = allocn(base, len, 1);
-			base[len++] = '\\';
-			continue;
-		}
-		if(c == '\n')
-			break;
-		if(c == '#')
-		if(n > 0) {
-			base = allocn(base, len, 1);
-			base[len++] = c;
-		}
-		base = allocn(base, len, 1);
-		base[len++] = c;
-		c = ((--fi.c < 0)? filbuf(): (*fi.p++ & 0xff));
-		if(c == '\n')
-			lineno++;
-		if(c == -1) {
-			yyerror("eof in a macro: %s", s->name);
-			break;
-		}
-	}
-	do {
-		base = allocn(base, len, 1);
-		base[len++] = 0;
-	} while(len & 3);
-
-	*base = n+1;
-	if(dots)
-		*base |= VARMAC;
-	s->macro = base;
-	if(debug['m'])
-		print("#define %s %s\n", s->name, s->macro+1);
-	return;
-
-bad:
-	if(s == S)
-		yyerror("syntax in #define");
-	else
-		yyerror("syntax in #define: %s", s->name);
-	macend();
-}
-
-void
-macexpand(Sym *s, char *b)
-{
-	char buf[2000];
-	int n, l, c, nargs;
-	char *arg[NARG], *cp, *ob, *ecp, dots;
-
-	ob = b;
-	if(*s->macro == 0) {
-		strcpy(b, s->macro+1);
-		if(debug['m'])
-			print("#expand %s %s\n", s->name, ob);
-		return;
-	}
-
-	nargs = (char)(*s->macro & ~VARMAC) - 1;
-	dots = *s->macro & VARMAC;
-
-	c = getnsc();
-	if(c != '(')
-		goto bad;
-	n = 0;
-	c = getc();
-	if(c != ')') {
-		unget(c);
-		l = 0;
-		cp = buf;
-		ecp = cp + sizeof(buf)-4;
-		arg[n++] = cp;
-		for(;;) {
-			if(cp >= ecp)
-				goto toobig;
-			c = getc();
-			if(c == '"')
-				for(;;) {
-					if(cp >= ecp)
-						goto toobig;
-					*cp++ = c;
-					c = getc();
-					if(c == '\\') {
-						*cp++ = c;
-						c = getc();
-						continue;
-					}
-					if(c == '\n')
-						goto bad;
-					if(c == '"')
-						break;
-				}
-			if(c == '\'')
-				for(;;) {
-					if(cp >= ecp)
-						goto toobig;
-					*cp++ = c;
-					c = getc();
-					if(c == '\\') {
-						*cp++ = c;
-						c = getc();
-						continue;
-					}
-					if(c == '\n')
-						goto bad;
-					if(c == '\'')
-						break;
-				}
-			if(c == '/') {
-				c = getc();
-				switch(c) {
-				case '*':
-					for(;;) {
-						c = getc();
-						if(c == '*') {
-							c = getc();
-							if(c == '/')
-								break;
-						}
-					}
-					*cp++ = ' ';
-					continue;
-				case '/':
-					while((c = getc()) != '\n')
-						;
-					break;
-				default:
-					unget(c);
-					c = '/';
-				}
-			}
-			if(l == 0) {
-				if(c == ',') {
-					if(n == nargs && dots) {
-						*cp++ = ',';
-						continue;
-					}
-					*cp++ = 0;
-					arg[n++] = cp;
-					if(n > nargs)
-						break;
-					continue;
-				}
-				if(c == ')')
-					break;
-			}
-			if(c == '\n')
-				c = ' ';
-			*cp++ = c;
-			if(c == '(')
-				l++;
-			if(c == ')')
-				l--;
-		}
-		*cp = 0;
-	}
-	if(n != nargs) {
-		yyerror("argument mismatch expanding: %s", s->name);
-		*b = 0;
-		return;
-	}
-	cp = s->macro+1;
-	for(;;) {
-		c = *cp++;
-		if(c == '\n')
-			c = ' ';
-		if(c != '#') {
-			*b++ = c;
-			if(c == 0)
-				break;
-			continue;
-		}
-		c = *cp++;
-		if(c == 0)
-			goto bad;
-		if(c == '#') {
-			*b++ = c;
-			continue;
-		}
-		c -= 'a';
-		if(c < 0 || c >= n)
-			continue;
-		strcpy(b, arg[c]);
-		b += strlen(arg[c]);
-	}
-	*b = 0;
-	if(debug['m'])
-		print("#expand %s %s\n", s->name, ob);
-	return;
-
-bad:
-	yyerror("syntax in macro expansion: %s", s->name);
-	*b = 0;
-	return;
-
-toobig:
-	yyerror("too much text in macro expansion: %s", s->name);
-	*b = 0;
-}
-
-void
-macinc(void)
-{
-	int c0, c, i, f;
-	char str[STRINGSZ], *hp;
-
-	c0 = getnsc();
-	if(c0 != '"') {
-		c = c0;
-		if(c0 != '<')
-			goto bad;
-		c0 = '>';
-	}
-	for(hp = str;;) {
-		c = getc();
-		if(c == c0)
-			break;
-		if(c == '\n')
-			goto bad;
-		*hp++ = c;
-	}
-	*hp = 0;
-
-	c = getcom();
-	if(c != '\n')
-		goto bad;
-
-	f = -1;
-	for(i=0; i<ninclude; i++) {
-		if(i == 0 && c0 == '>')
-			continue;
-		ensuresymb(strlen(include[i])+strlen(str)+2);
-		strcpy(symb, include[i]);
-		strcat(symb, "/");
-		if(strcmp(symb, "./") == 0)
-			symb[0] = 0;
-		strcat(symb, str);
-		f = open(symb, OREAD);
-		if(f >= 0)
-			break;
-	}
-	if(f < 0)
-		strcpy(symb, str);
-	c = strlen(symb) + 1;
-	hp = alloc(c);
-	memcpy(hp, symb, c);
-	newio();
-	pushio();
-	newfile(hp, f);
-	return;
-
-bad:
-	unget(c);
-	yyerror("syntax in #include");
-	macend();
-}
-
-void
-maclin(void)
-{
-	char *cp;
-	int c;
-	int32 n;
-
-	n = getnsn();
-	c = getc();
-	if(n < 0)
-		goto bad;
-
-	for(;;) {
-		if(c == ' ' || c == '\t') {
-			c = getc();
-			continue;
-		}
-		if(c == '"')
-			break;
-		if(c == '\n') {
-			strcpy(symb, "<noname>");
-			goto nn;
-		}
-		goto bad;
-	}
-	cp = symb;
-	for(;;) {
-		c = getc();
-		if(c == '"')
-			break;
-		*cp++ = c;
-	}
-	*cp = 0;
-	c = getcom();
-	if(c != '\n')
-		goto bad;
-
-nn:
-	c = strlen(symb) + 1;
-	cp = alloc(c);
-	memcpy(cp, symb, c);
-	linklinehist(ctxt, lineno, cp, n);
-	return;
-
-bad:
-	unget(c);
-	yyerror("syntax in #line");
-	macend();
-}
-
-void
-macif(int f)
-{
-	int c, l, bol;
-	Sym *s;
-
-	if(f == 2)
-		goto skip;
-	s = getsym();
-	if(s == S)
-		goto bad;
-	if(getcom() != '\n')
-		goto bad;
-	if((s->macro != 0) ^ f)
-		return;
-
-skip:
-	bol = 1;
-	l = 0;
-	for(;;) {
-		c = getc();
-		if(c != '#') {
-			if(!isspace(c))
-				bol = 0;
-			if(c == '\n')
-				bol = 1;
-			continue;
-		}
-		if(!bol)
-			continue;
-		s = getsym();
-		if(s == S)
-			continue;
-		if(strcmp(s->name, "endif") == 0) {
-			if(l) {
-				l--;
-				continue;
-			}
-			macend();
-			return;
-		}
-		if(strcmp(s->name, "ifdef") == 0 || strcmp(s->name, "ifndef") == 0) {
-			l++;
-			continue;
-		}
-		if(l == 0 && f != 2 && strcmp(s->name, "else") == 0) {
-			macend();
-			return;
-		}
-	}
-
-bad:
-	yyerror("syntax in #if(n)def");
-	macend();
-}
-
-void
-macprag(void)
-{
-	Sym *s;
-	int c0, c;
-	char *hp;
-
-	s = getsym();
-
-	if(s && strcmp(s->name, "lib") == 0)
-		goto praglib;
-	if(s && strcmp(s->name, "pack") == 0) {
-		pragpack();
-		return;
-	}
-	if(s && strcmp(s->name, "fpround") == 0) {
-		pragfpround();
-		return;
-	}
-	if(s && strcmp(s->name, "textflag") == 0) {
-		pragtextflag();
-		return;
-	}
-	if(s && strcmp(s->name, "dataflag") == 0) {
-		pragdataflag();
-		return;
-	}
-	if(s && strcmp(s->name, "varargck") == 0) {
-		pragvararg();
-		return;
-	}
-	if(s && strcmp(s->name, "incomplete") == 0) {
-		pragincomplete();
-		return;
-	}
-	if(s && (strncmp(s->name, "cgo_", 4) == 0 || strncmp(s->name, "dyn", 3) == 0)) {
-		pragcgo(s->name);
-		return;
-	}
-	while(getnsc() != '\n')
-		;
-	return;
-
-praglib:
-	c0 = getnsc();
-	if(c0 != '"') {
-		c = c0;
-		if(c0 != '<')
-			goto bad;
-		c0 = '>';
-	}
-	for(hp = symb;;) {
-		c = getc();
-		if(c == c0)
-			break;
-		if(c == '\n')
-			goto bad;
-		*hp++ = c;
-	}
-	*hp = 0;
-	c = getcom();
-	if(c != '\n')
-		goto bad;
-
-	/*
-	 * put pragma-line in as a funny history
-	 */
-	c = strlen(symb) + 1;
-	hp = alloc(c);
-	memcpy(hp, symb, c);
-
-	linklinehist(ctxt, lineno, hp, -1);
-	return;
-
-bad:
-	unget(c);
-	yyerror("syntax in #pragma lib");
-	macend();
-}
-
-void
-macend(void)
-{
-	int c;
-
-	for(;;) {
-		c = getnsc();
-		if(c < 0 || c == '\n')
-			return;
-	}
-}
diff --git a/src/cmd/cc/omachcap.c b/src/cmd/cc/omachcap.c
deleted file mode 100644
index f8fc1d8..0000000
--- a/src/cmd/cc/omachcap.c
+++ /dev/null
@@ -1,40 +0,0 @@
-// Inferno utils/cc/machcap.c
-// http://code.google.com/p/inferno-os/source/browse/utils/cc/machcap.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include	<u.h>
-#include	"cc.h"
-
-/* default, like old cc */
-int
-machcap(Node *n)
-{
-	USED(n);
-	return 0;
-}
diff --git a/src/cmd/cc/pgen.c b/src/cmd/cc/pgen.c
deleted file mode 100644
index db9aae9..0000000
--- a/src/cmd/cc/pgen.c
+++ /dev/null
@@ -1,622 +0,0 @@
-// Inferno utils/6c/sgen.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/sgen.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include "gc.h"
-#include "../../runtime/funcdata.h"
-
-int
-hasdotdotdot(Type *t)
-{
-	for(t=t->down; t!=T; t=t->down)
-		if(t->etype == TDOT)
-			return 1;
-	return 0;
-}
-
-vlong
-argsize(int doret)
-{
-	Type *t;
-	int32 s;
-
-//print("t=%T\n", thisfn);
-	s = 0;
-	if(hasdotdotdot(thisfn))
-		s = align(s, thisfn->link, Aarg0, nil);
-	for(t=thisfn->down; t!=T; t=t->down) {
-		switch(t->etype) {
-		case TVOID:
-			break;
-		case TDOT:
-			if((textflag & NOSPLIT) == 0)
-				yyerror("function takes ... without textflag NOSPLIT");
-			return ArgsSizeUnknown;
-		default:
-			s = align(s, t, Aarg1, nil);
-			s = align(s, t, Aarg2, nil);
-			break;
-		}
-//print("	%d %T\n", s, t);
-	}
-	if(thechar == '6')
-		s = (s+7) & ~7;
-	else
-		s = (s+3) & ~3;
-	if(doret && thisfn->link->etype != TVOID) {
-		s = align(s, thisfn->link, Aarg1, nil);
-		s = align(s, thisfn->link, Aarg2, nil);
-		if(thechar == '6')
-			s = (s+7) & ~7;
-		else
-			s = (s+3) & ~3;
-	}
-	return s;
-}
-
-void
-codgen(Node *n, Node *nn)
-{
-	Prog *sp;
-	Node *n1, nod, nod1;
-
-	cursafe = 0;
-	curarg = 0;
-	maxargsafe = 0;
-
-	/*
-	 * isolate name
-	 */
-	for(n1 = nn;; n1 = n1->left) {
-		if(n1 == Z) {
-			diag(nn, "can't find function name");
-			return;
-		}
-		if(n1->op == ONAME)
-			break;
-	}
-	nearln = nn->lineno;
-
-	p = gtext(n1->sym, stkoff);
-	p->from.sym->cfunc = 1;
-	sp = p;
-
-	/*
-	 * isolate first argument
-	 */
-	if(REGARG >= 0) {
-		if(typesuv[thisfn->link->etype]) {
-			nod1 = *nodret->left;
-			nodreg(&nod, &nod1, REGARG);
-			gmove(&nod, &nod1);
-		} else
-		if(firstarg && typechlp[firstargtype->etype]) {
-			nod1 = *nodret->left;
-			nod1.sym = firstarg;
-			nod1.type = firstargtype;
-			nod1.xoffset = align(0, firstargtype, Aarg1, nil);
-			nod1.etype = firstargtype->etype;
-			nodreg(&nod, &nod1, REGARG);
-			gmove(&nod, &nod1);
-		}
-	}
-
-	canreach = 1;
-	warnreach = 1;
-	gen(n);
-	if(canreach && thisfn->link->etype != TVOID)
-		diag(Z, "no return at end of function: %s", n1->sym->name);
-	noretval(3);
-	gbranch(ORETURN);
-
-	if(!debug['N'] || debug['R'] || debug['P'])
-		regopt(sp);
-
-	if(thechar=='6' || thechar=='7')	/* [sic] */
-		maxargsafe = xround(maxargsafe, 8);
-	sp->to.offset += maxargsafe;
-}
-
-void
-supgen(Node *n)
-{
-	int owarn;
-	long spc;
-	Prog *sp;
-
-	if(n == Z)
-		return;
-	suppress++;
-	owarn = warnreach;
-	warnreach = 0;
-	spc = pc;
-	sp = lastp;
-	gen(n);
-	lastp = sp;
-	pc = spc;
-	sp->link = nil;
-	suppress--;
-	warnreach = owarn;
-}
-
-void
-gen(Node *n)
-{
-	Node *l, nod, nod1;
-	Prog *sp, *spc, *spb;
-	Case *cn;
-	long sbc, scc;
-	int snbreak, sncontin;
-	int f, o, oldreach;
-
-loop:
-	if(n == Z)
-		return;
-	nearln = n->lineno;
-	o = n->op;
-	if(debug['G'])
-		if(o != OLIST)
-			print("%L %O\n", nearln, o);
-
-	if(!canreach) {
-		switch(o) {
-		case OLABEL:
-		case OCASE:
-		case OLIST:
-		case OBREAK:
-		case OFOR:
-		case OWHILE:
-		case ODWHILE:
-			/* all handled specially - see switch body below */
-			break;
-		default:
-			if(warnreach) {
-				warn(n, "unreachable code %O", o);
-				warnreach = 0;
-			}
-		}
-	}
-
-	switch(o) {
-
-	default:
-		complex(n);
-		cgen(n, Z);
-		break;
-
-	case OLIST:
-		gen(n->left);
-
-	rloop:
-		n = n->right;
-		goto loop;
-
-	case ORETURN:
-		canreach = 0;
-		warnreach = !suppress;
-		complex(n);
-		if(n->type == T)
-			break;
-		l = n->left;
-		if(l == Z) {
-			noretval(3);
-			gbranch(ORETURN);
-			break;
-		}
-		if(typecmplx[n->type->etype] && !hasdotdotdot(thisfn)) {
-			regret(&nod, n, thisfn, 2);
-			sugen(l, &nod, n->type->width);
-			noretval(3);
-			gbranch(ORETURN);
-			break;
-		}
-		if(typecmplx[n->type->etype]) {
-			sugen(l, nodret, n->type->width);
-			noretval(3);
-			gbranch(ORETURN);
-			break;
-		}
-		regret(&nod1, n, thisfn, 2);
-		nod = nod1;
-		if(nod.op != OREGISTER)
-			regalloc(&nod, n, Z);
-		cgen(l, &nod);
-		if(nod1.op != OREGISTER)
-			gmove(&nod, &nod1);
-		regfree(&nod);
-		if(typefd[n->type->etype])
-			noretval(1);
-		else
-			noretval(2);
-		gbranch(ORETURN);
-		break;
-
-	case OLABEL:
-		canreach = 1;
-		l = n->left;
-		if(l) {
-			l->pc = pc;
-			if(l->label)
-				patch(l->label, pc);
-		}
-		gbranch(OGOTO);	/* prevent self reference in reg */
-		patch(p, pc);
-		goto rloop;
-
-	case OGOTO:
-		canreach = 0;
-		warnreach = !suppress;
-		n = n->left;
-		if(n == Z)
-			return;
-		if(n->complex == 0) {
-			diag(Z, "label undefined: %s", n->sym->name);
-			return;
-		}
-		if(suppress)
-			return;
-		gbranch(OGOTO);
-		if(n->pc) {
-			patch(p, n->pc);
-			return;
-		}
-		if(n->label)
-			patch(n->label, pc-1);
-		n->label = p;
-		return;
-
-	case OCASE:
-		canreach = 1;
-		l = n->left;
-		if(cases == C)
-			diag(n, "case/default outside a switch");
-		if(l == Z) {
-			newcase();
-			cases->val = 0;
-			cases->def = 1;
-			cases->label = pc;
-			cases->isv = 0;
-			goto rloop;
-		}
-		complex(l);
-		if(l->type == T)
-			goto rloop;
-		if(l->op == OCONST)
-		if(typeword[l->type->etype] && l->type->etype != TIND) {
-			newcase();
-			cases->val = l->vconst;
-			cases->def = 0;
-			cases->label = pc;
-			cases->isv = typev[l->type->etype];
-			goto rloop;
-		}
-		diag(n, "case expression must be integer constant");
-		goto rloop;
-
-	case OSWITCH:
-		l = n->left;
-		complex(l);
-		if(l->type == T)
-			break;
-		if(!typechlvp[l->type->etype] || l->type->etype == TIND) {
-			diag(n, "switch expression must be integer");
-			break;
-		}
-
-		gbranch(OGOTO);		/* entry */
-		sp = p;
-
-		cn = cases;
-		cases = C;
-		newcase();
-
-		sbc = breakpc;
-		breakpc = pc;
-		snbreak = nbreak;
-		nbreak = 0;
-		gbranch(OGOTO);
-		spb = p;
-
-		gen(n->right);		/* body */
-		if(canreach){
-			gbranch(OGOTO);
-			patch(p, breakpc);
-			nbreak++;
-		}
-
-		patch(sp, pc);
-		doswit(l);
-		patch(spb, pc);
-
-		cases = cn;
-		breakpc = sbc;
-		canreach = nbreak!=0;
-		if(canreach == 0)
-			warnreach = !suppress;
-		nbreak = snbreak;
-		break;
-
-	case OWHILE:
-	case ODWHILE:
-		l = n->left;
-		gbranch(OGOTO);		/* entry */
-		sp = p;
-
-		scc = continpc;
-		continpc = pc;
-		gbranch(OGOTO);
-		spc = p;
-
-		sbc = breakpc;
-		breakpc = pc;
-		snbreak = nbreak;
-		nbreak = 0;
-		gbranch(OGOTO);
-		spb = p;
-
-		patch(spc, pc);
-		if(n->op == OWHILE)
-			patch(sp, pc);
-		bcomplex(l, Z);		/* test */
-		patch(p, breakpc);
-		if(l->op != OCONST || vconst(l) == 0)
-			nbreak++;
-
-		if(n->op == ODWHILE)
-			patch(sp, pc);
-		gen(n->right);		/* body */
-		gbranch(OGOTO);
-		patch(p, continpc);
-
-		patch(spb, pc);
-		continpc = scc;
-		breakpc = sbc;
-		canreach = nbreak!=0;
-		if(canreach == 0)
-			warnreach = !suppress;
-		nbreak = snbreak;
-		break;
-
-	case OFOR:
-		l = n->left;
-		if(!canreach && l->right->left && warnreach) {
-			warn(n, "unreachable code FOR");
-			warnreach = 0;
-		}
-		gen(l->right->left);	/* init */
-		gbranch(OGOTO);		/* entry */
-		sp = p;
-
-		/*
-		 * if there are no incoming labels in the
-		 * body and the top's not reachable, warn
-		 */
-		if(!canreach && warnreach && deadheads(n)) {
-			warn(n, "unreachable code %O", o);
-			warnreach = 0;
-		}
-
-		scc = continpc;
-		continpc = pc;
-		gbranch(OGOTO);
-		spc = p;
-
-		sbc = breakpc;
-		breakpc = pc;
-		snbreak = nbreak;
-		nbreak = 0;
-		sncontin = ncontin;
-		ncontin = 0;
-		gbranch(OGOTO);
-		spb = p;
-
-		patch(spc, pc);
-		gen(l->right->right);	/* inc */
-		patch(sp, pc);
-		if(l->left != Z) {	/* test */
-			bcomplex(l->left, Z);
-			patch(p, breakpc);
-			if(l->left->op != OCONST || vconst(l->left) == 0)
-				nbreak++;
-		}
-		canreach = 1;
-		gen(n->right);		/* body */
-		if(canreach){
-			gbranch(OGOTO);
-			patch(p, continpc);
-			ncontin++;
-		}
-		if(!ncontin && l->right->right && warnreach) {
-			warn(l->right->right, "unreachable FOR inc");
-			warnreach = 0;
-		}
-
-		patch(spb, pc);
-		continpc = scc;
-		breakpc = sbc;
-		canreach = nbreak!=0;
-		if(canreach == 0)
-			warnreach = !suppress;
-		nbreak = snbreak;
-		ncontin = sncontin;
-		break;
-
-	case OCONTINUE:
-		if(continpc < 0) {
-			diag(n, "continue not in a loop");
-			break;
-		}
-		gbranch(OGOTO);
-		patch(p, continpc);
-		ncontin++;
-		canreach = 0;
-		warnreach = !suppress;
-		break;
-
-	case OBREAK:
-		if(breakpc < 0) {
-			diag(n, "break not in a loop");
-			break;
-		}
-		/*
-		 * Don't complain about unreachable break statements.
-		 * There are breaks hidden in yacc's output and some people
-		 * write return; break; in their switch statements out of habit.
-		 * However, don't confuse the analysis by inserting an
-		 * unreachable reference to breakpc either.
-		 */
-		if(!canreach)
-			break;
-		gbranch(OGOTO);
-		patch(p, breakpc);
-		nbreak++;
-		canreach = 0;
-		warnreach = !suppress;
-		break;
-
-	case OIF:
-		l = n->left;
-		if(bcomplex(l, n->right)) {
-			if(typefd[l->type->etype])
-				f = !l->fconst;
-			else
-				f = !l->vconst;
-			if(debug['c'])
-				print("%L const if %s\n", nearln, f ? "false" : "true");
-			if(f) {
-				canreach = 1;
-				supgen(n->right->left);
-				oldreach = canreach;
-				canreach = 1;
-				gen(n->right->right);
-				/*
-				 * treat constant ifs as regular ifs for
-				 * reachability warnings.
-				 */
-				if(!canreach && oldreach && debug['w'] < 2)
-					warnreach = 0;
-			}
-			else {
-				canreach = 1;
-				gen(n->right->left);
-				oldreach = canreach;
-				canreach = 1;
-				supgen(n->right->right);
-				/*
-				 * treat constant ifs as regular ifs for
-				 * reachability warnings.
-				 */
-				if(!oldreach && canreach && debug['w'] < 2)
-					warnreach = 0;
-				canreach = oldreach;
-			}
-		}
-		else {
-			sp = p;
-			canreach = 1;
-			if(n->right->left != Z)
-				gen(n->right->left);
-			oldreach = canreach;
-			canreach = 1;
-			if(n->right->right != Z) {
-				gbranch(OGOTO);
-				patch(sp, pc);
-				sp = p;
-				gen(n->right->right);
-			}
-			patch(sp, pc);
-			canreach = canreach || oldreach;
-			if(canreach == 0)
-				warnreach = !suppress;
-		}
-		break;
-
-	case OSET:
-	case OUSED:
-	case OPREFETCH:
-		usedset(n->left, o);
-		break;
-	}
-}
-
-void
-usedset(Node *n, int o)
-{
-	if(n->op == OLIST) {
-		usedset(n->left, o);
-		usedset(n->right, o);
-		return;
-	}
-	complex(n);
-	if(o == OPREFETCH) {
-		gprefetch(n);
-		return;
-	}
-	switch(n->op) {
-	case OADDR:	/* volatile */
-		gins(ANOP, n, Z);
-		break;
-	case ONAME:
-		if(o == OSET)
-			gins(ANOP, Z, n);
-		else
-			gins(ANOP, n, Z);
-		break;
-	}
-}
-
-int
-bcomplex(Node *n, Node *c)
-{
-	Node *b, nod;
-
-	complex(n);
-	if(n->type != T)
-	if(tcompat(n, T, n->type, tnot))
-		n->type = T;
-	if(n->type == T) {
-		gbranch(OGOTO);
-		return 0;
-	}
-	if(c != Z && n->op == OCONST && deadheads(c))
-		return 1;
-	if(typev[n->type->etype] && machcap(Z)) {
-		b = &nod;
-		b->op = ONE;
-		b->left = n;
-		b->right = new(0, Z, Z);
-		*b->right = *nodconst(0);
-		b->right->type = n->type;
-		b->type = types[TLONG];
-		n = b;
-	}
-	bool64(n);
-	boolgen(n, 1, Z);
-	return 0;
-}
diff --git a/src/cmd/cc/pswt.c b/src/cmd/cc/pswt.c
deleted file mode 100644
index bae57c6..0000000
--- a/src/cmd/cc/pswt.c
+++ /dev/null
@@ -1,140 +0,0 @@
-// Inferno utils/6c/swt.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/swt.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include "gc.h"
-
-int
-swcmp(const void *a1, const void *a2)
-{
-	C1 *p1, *p2;
-
-	p1 = (C1*)a1;
-	p2 = (C1*)a2;
-	if(p1->val < p2->val)
-		return -1;
-	return p1->val > p2->val;
-}
-
-void
-doswit(Node *n)
-{
-	Case *c;
-	C1 *q, *iq;
-	int32 def, nc, i, isv;
-
-	def = 0;
-	nc = 0;
-	isv = 0;
-	for(c = cases; c->link != C; c = c->link) {
-		if(c->def) {
-			if(def)
-				diag(n, "more than one default in switch");
-			def = c->label;
-			continue;
-		}
-		isv |= c->isv;
-		nc++;
-	}
-	if(isv && !typev[n->type->etype])
-		warn(n, "32-bit switch expression with 64-bit case constant");
-
-	iq = alloc(nc*sizeof(C1));
-	q = iq;
-	for(c = cases; c->link != C; c = c->link) {
-		if(c->def)
-			continue;
-		q->label = c->label;
-		if(isv)
-			q->val = c->val;
-		else
-			q->val = (int32)c->val;	/* cast ensures correct value for 32-bit switch on 64-bit architecture */
-		q++;
-	}
-	qsort(iq, nc, sizeof(C1), swcmp);
-	if(debug['W'])
-	for(i=0; i<nc; i++)
-		print("case %2d: = %.8llux\n", i, (vlong)iq[i].val);
-	for(i=0; i<nc-1; i++)
-		if(iq[i].val == iq[i+1].val)
-			diag(n, "duplicate cases in switch %lld", (vlong)iq[i].val);
-	if(def == 0) {
-		def = breakpc;
-		nbreak++;
-	}
-	swit1(iq, nc, def, n);
-}
-
-void
-newcase(void)
-{
-	Case *c;
-
-	c = alloc(sizeof(*c));
-	c->link = cases;
-	cases = c;
-}
-
-int32
-outlstring(TRune *s, int32 n)
-{
-	char buf[sizeof(TRune)];
-	uint c;
-	int i;
-	int32 r;
-
-	if(suppress)
-		return nstring;
-	while(nstring & (sizeof(TRune)-1))
-		outstring("", 1);
-	r = nstring;
-	while(n > 0) {
-		c = *s++;
-		if(align(0, types[TCHAR], Aarg1, nil)) {
-			for(i = 0; i < sizeof(TRune); i++)
-				buf[i] = c>>(8*(sizeof(TRune) - i - 1));
-		} else {
-			for(i = 0; i < sizeof(TRune); i++)
-				buf[i] = c>>(8*i);
-		}
-		outstring(buf, sizeof(TRune));
-		n -= sizeof(TRune);
-	}
-	return r;
-}
-
-void
-nullwarn(Node *l, Node *r)
-{
-	warn(Z, "result of operation not used");
-	if(l != Z)
-		cgen(l, Z);
-	if(r != Z)
-		cgen(r, Z);
-}
diff --git a/src/cmd/cc/scon.c b/src/cmd/cc/scon.c
deleted file mode 100644
index b0b9097..0000000
--- a/src/cmd/cc/scon.c
+++ /dev/null
@@ -1,640 +0,0 @@
-// Inferno utils/cc/scon.c
-// http://code.google.com/p/inferno-os/source/browse/utils/cc/scon.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include <u.h>
-#include "cc.h"
-
-static Node*
-acast(Type *t, Node *n)
-{
-	if(n->type->etype != t->etype || n->op == OBIT) {
-		n = new1(OCAST, n, Z);
-		if(nocast(n->left->type, t))
-			*n = *n->left;
-		n->type = t;
-	}
-	return n;
-}
-
-
-void
-evconst(Node *n)
-{
-	Node *l, *r;
-	int et, isf;
-	vlong v;
-	double d;
-
-	if(n == Z || n->type == T)
-		return;
-
-	et = n->type->etype;
-	isf = typefd[et];
-
-	l = n->left;
-	r = n->right;
-
-	d = 0;
-	v = 0;
-
-	switch(n->op) {
-	default:
-		return;
-
-	case ONEG:
-		if(isf)
-			d = -l->fconst;
-		else
-			v = -l->vconst;
-		break;
-
-	case OCOM:
-		v = ~l->vconst;
-		break;
-
-	case OCAST:
-		if(et == TVOID)
-			return;
-		et = l->type->etype;
-		if(isf) {
-			if(typefd[et])
-				d = l->fconst;
-			else
-				d = l->vconst;
-		} else {
-			if(typefd[et])
-				v = l->fconst;
-			else
-				v = convvtox(l->vconst, n->type->etype);
-		}
-		break;
-
-	case OCONST:
-		break;
-
-	case OADD:
-		if(isf)
-			d = l->fconst + r->fconst;
-		else {
-			v = l->vconst + r->vconst;
-		}
-		break;
-
-	case OSUB:
-		if(isf)
-			d = l->fconst - r->fconst;
-		else
-			v = l->vconst - r->vconst;
-		break;
-
-	case OMUL:
-		if(isf)
-			d = l->fconst * r->fconst;
-		else {
-			v = l->vconst * r->vconst;
-		}
-		break;
-
-	case OLMUL:
-		v = (uvlong)l->vconst * (uvlong)r->vconst;
-		break;
-
-
-	case ODIV:
-		if(vconst(r) == 0) {
-			warn(n, "divide by zero");
-			return;
-		}
-		if(isf)
-			d = l->fconst / r->fconst;
-		else
-			v = l->vconst / r->vconst;
-		break;
-
-	case OLDIV:
-		if(vconst(r) == 0) {
-			warn(n, "divide by zero");
-			return;
-		}
-		v = (uvlong)l->vconst / (uvlong)r->vconst;
-		break;
-
-	case OMOD:
-		if(vconst(r) == 0) {
-			warn(n, "modulo by zero");
-			return;
-		}
-		v = l->vconst % r->vconst;
-		break;
-
-	case OLMOD:
-		if(vconst(r) == 0) {
-			warn(n, "modulo by zero");
-			return;
-		}
-		v = (uvlong)l->vconst % (uvlong)r->vconst;
-		break;
-
-	case OAND:
-		v = l->vconst & r->vconst;
-		break;
-
-	case OOR:
-		v = l->vconst | r->vconst;
-		break;
-
-	case OXOR:
-		v = l->vconst ^ r->vconst;
-		break;
-
-	case OLSHR:
-		if(l->type->width != sizeof(uvlong))
-			v = ((uvlong)l->vconst & 0xffffffffULL) >> r->vconst;
-		else
-			v = (uvlong)l->vconst >> r->vconst;
-		break;
-
-	case OASHR:
-		v = l->vconst >> r->vconst;
-		break;
-
-	case OASHL:
-		v = (uvlong)l->vconst << r->vconst;
-		break;
-
-	case OLO:
-		v = (uvlong)l->vconst < (uvlong)r->vconst;
-		break;
-
-	case OLT:
-		if(typefd[l->type->etype])
-			v = l->fconst < r->fconst;
-		else
-			v = l->vconst < r->vconst;
-		break;
-
-	case OHI:
-		v = (uvlong)l->vconst > (uvlong)r->vconst;
-		break;
-
-	case OGT:
-		if(typefd[l->type->etype])
-			v = l->fconst > r->fconst;
-		else
-			v = l->vconst > r->vconst;
-		break;
-
-	case OLS:
-		v = (uvlong)l->vconst <= (uvlong)r->vconst;
-		break;
-
-	case OLE:
-		if(typefd[l->type->etype])
-			v = l->fconst <= r->fconst;
-		else
-			v = l->vconst <= r->vconst;
-		break;
-
-	case OHS:
-		v = (uvlong)l->vconst >= (uvlong)r->vconst;
-		break;
-
-	case OGE:
-		if(typefd[l->type->etype])
-			v = l->fconst >= r->fconst;
-		else
-			v = l->vconst >= r->vconst;
-		break;
-
-	case OEQ:
-		if(typefd[l->type->etype])
-			v = l->fconst == r->fconst;
-		else
-			v = l->vconst == r->vconst;
-		break;
-
-	case ONE:
-		if(typefd[l->type->etype])
-			v = l->fconst != r->fconst;
-		else
-			v = l->vconst != r->vconst;
-		break;
-
-	case ONOT:
-		if(typefd[l->type->etype])
-			v = !l->fconst;
-		else
-			v = !l->vconst;
-		break;
-
-	case OANDAND:
-		if(typefd[l->type->etype])
-			v = l->fconst && r->fconst;
-		else
-			v = l->vconst && r->vconst;
-		break;
-
-	case OOROR:
-		if(typefd[l->type->etype])
-			v = l->fconst || r->fconst;
-		else
-			v = l->vconst || r->vconst;
-		break;
-	}
-	if(isf) {
-		n->fconst = d;
-	} else {
-		n->vconst = convvtox(v, n->type->etype);
-	}
-	n->oldop = n->op;
-	n->op = OCONST;
-}
-
-void
-acom(Node *n)
-{
-	Type *t;
-	Node *l, *r;
-	int i;
-
-	switch(n->op)
-	{
-
-	case ONAME:
-	case OCONST:
-	case OSTRING:
-	case OINDREG:
-	case OREGISTER:
-		return;
-
-	case ONEG:
-		l = n->left;
-		if(addo(n) && addo(l))
-			break;
-		acom(l);
-		return;
-
-	case OADD:
-	case OSUB:
-	case OMUL:
-		l = n->left;
-		r = n->right;
-		if(addo(n)) {
-			if(addo(r))
-				break;
-			if(addo(l))
-				break;
-		}
-		acom(l);
-		acom(r);
-		return;
-
-	default:
-		l = n->left;
-		r = n->right;
-		if(l != Z)
-			acom(l);
-		if(r != Z)
-			acom(r);
-		return;
-	}
-
-	/* bust terms out */
-	t = n->type;
-	term[0].mult = 0;
-	term[0].node = Z;
-	nterm = 1;
-	acom1(1, n);
-	if(debug['m'])
-	for(i=0; i<nterm; i++) {
-		print("%d %3lld ", i, term[i].mult);
-		prtree1(term[i].node, 1, 0);
-	}
-	if(nterm < NTERM)
-		acom2(n, t);
-	n->type = t;
-}
-
-int
-acomcmp1(const void *a1, const void *a2)
-{
-	vlong c1, c2;
-	Term *t1, *t2;
-
-	t1 = (Term*)a1;
-	t2 = (Term*)a2;
-	c1 = t1->mult;
-	if(c1 < 0)
-		c1 = -c1;
-	c2 = t2->mult;
-	if(c2 < 0)
-		c2 = -c2;
-	if(c1 > c2)
-		return 1;
-	if(c1 < c2)
-		return -1;
-	c1 = 1;
-	if(t1->mult < 0)
-		c1 = 0;
-	c2 = 1;
-	if(t2->mult < 0)
-		c2 = 0;
-	if(c2 -= c1)
-		return c2;
-	if(t2 > t1)
-		return 1;
-	return -1;
-}
-
-int
-acomcmp2(const void *a1, const void *a2)
-{
-	vlong c1, c2;
-	Term *t1, *t2;
-
-	t1 = (Term*)a1;
-	t2 = (Term*)a2;
-	c1 = t1->mult;
-	c2 = t2->mult;
-	if(c1 > c2)
-		return 1;
-	if(c1 < c2)
-		return -1;
-	if(t2 > t1)
-		return 1;
-	return -1;
-}
-
-void
-acom2(Node *n, Type *t)
-{
-	Node *l, *r;
-	Term trm[NTERM];
-	int et, nt, i, j;
-	vlong c1, c2;
-
-	/*
-	 * copy into automatic
-	 */
-	c2 = 0;
-	nt = nterm;
-	for(i=0; i<nt; i++)
-		trm[i] = term[i];
-	/*
-	 * recur on subtrees
-	 */
-	j = 0;
-	for(i=1; i<nt; i++) {
-		c1 = trm[i].mult;
-		if(c1 == 0)
-			continue;
-		l = trm[i].node;
-		if(l != Z) {
-			j = 1;
-			acom(l);
-		}
-	}
-	c1 = trm[0].mult;
-	if(j == 0) {
-		n->oldop = n->op;
-		n->op = OCONST;
-		n->vconst = c1;
-		return;
-	}
-	et = t->etype;
-
-	/*
-	 * prepare constant term,
-	 * combine it with an addressing term
-	 */
-	if(c1 != 0) {
-		l = new1(OCONST, Z, Z);
-		l->type = t;
-		l->vconst = c1;
-		trm[0].mult = 1;
-		for(i=1; i<nt; i++) {
-			if(trm[i].mult != 1)
-				continue;
-			r = trm[i].node;
-			if(r->op != OADDR)
-				continue;
-			r->type = t;
-			l = new1(OADD, r, l);
-			l->type = t;
-			trm[i].mult = 0;
-			break;
-		}
-		trm[0].node = l;
-	}
-	/*
-	 * look for factorable terms
-	 * c1*i + c1*c2*j -> c1*(i + c2*j)
-	 */
-	qsort(trm+1, nt-1, sizeof(trm[0]), acomcmp1);
-	for(i=nt-1; i>=0; i--) {
-		c1 = trm[i].mult;
-		if(c1 < 0)
-			c1 = -c1;
-		if(c1 <= 1)
-			continue;
-		for(j=i+1; j<nt; j++) {
-			c2 = trm[j].mult;
-			if(c2 < 0)
-				c2 = -c2;
-			if(c2 <= 1)
-				continue;
-			if(c2 % c1)
-				continue;
-			r = trm[j].node;
-			if(r->type->etype != et)
-				r = acast(t, r);
-			c2 = trm[j].mult/trm[i].mult;
-			if(c2 != 1 && c2 != -1) {
-				r = new1(OMUL, r, new(OCONST, Z, Z));
-				r->type = t;
-				r->right->type = t;
-				r->right->vconst = c2;
-			}
-			l = trm[i].node;
-			if(l->type->etype != et)
-				l = acast(t, l);
-			r = new1(OADD, l, r);
-			r->type = t;
-			if(c2 == -1)
-				r->op = OSUB;
-			trm[i].node = r;
-			trm[j].mult = 0;
-		}
-	}
-	if(debug['m']) {
-		print("\n");
-		for(i=0; i<nt; i++) {
-			print("%d %3lld ", i, trm[i].mult);
-			prtree1(trm[i].node, 1, 0);
-		}
-	}
-
-	/*
-	 * put it all back together
-	 */
-	qsort(trm+1, nt-1, sizeof(trm[0]), acomcmp2);
-	l = Z;
-	for(i=nt-1; i>=0; i--) {
-		c1 = trm[i].mult;
-		if(c1 == 0)
-			continue;
-		r = trm[i].node;
-		if(r->type->etype != et || r->op == OBIT)
-			r = acast(t, r);
-		if(c1 != 1 && c1 != -1) {
-			r = new1(OMUL, r, new(OCONST, Z, Z));
-			r->type = t;
-			r->right->type = t;
-			if(c1 < 0) {
-				r->right->vconst = -c1;
-				c1 = -1;
-			} else {
-				r->right->vconst = c1;
-				c1 = 1;
-			}
-		}
-		if(l == Z) {
-			l = r;
-			c2 = c1;
-			continue;
-		}
-		if(c1 < 0)
-			if(c2 < 0)
-				l = new1(OADD, l, r);
-			else
-				l = new1(OSUB, l, r);
-		else
-			if(c2 < 0) {
-				l = new1(OSUB, r, l);
-				c2 = 1;
-			} else
-				l = new1(OADD, l, r);
-		l->type = t;
-	}
-	if(c2 < 0) {
-		r = new1(OCONST, 0, 0);
-		r->vconst = 0;
-		r->type = t;
-		l = new1(OSUB, r, l);
-		l->type = t;
-	}
-	*n = *l;
-}
-
-void
-acom1(vlong v, Node *n)
-{
-	Node *l, *r;
-
-	if(v == 0 || nterm >= NTERM)
-		return;
-	if(!addo(n)) {
-		if(n->op == OCONST)
-		if(!typefd[n->type->etype]) {
-			term[0].mult += v*n->vconst;
-			return;
-		}
-		term[nterm].mult = v;
-		term[nterm].node = n;
-		nterm++;
-		return;
-	}
-	switch(n->op) {
-
-	case OCAST:
-		acom1(v, n->left);
-		break;
-
-	case ONEG:
-		acom1(-v, n->left);
-		break;
-
-	case OADD:
-		acom1(v, n->left);
-		acom1(v, n->right);
-		break;
-
-	case OSUB:
-		acom1(v, n->left);
-		acom1(-v, n->right);
-		break;
-
-	case OMUL:
-		l = n->left;
-		r = n->right;
-		if(l->op == OCONST)
-		if(!typefd[n->type->etype]) {
-			acom1(v*l->vconst, r);
-			break;
-		}
-		if(r->op == OCONST)
-		if(!typefd[n->type->etype]) {
-			acom1(v*r->vconst, l);
-			break;
-		}
-		break;
-
-	default:
-		diag(n, "not addo");
-	}
-}
-
-int
-addo(Node *n)
-{
-
-	if(n != Z)
-	if(!typefd[n->type->etype])
-	if(!typev[n->type->etype] || ewidth[TVLONG] == ewidth[TIND])
-	switch(n->op) {
-
-	case OCAST:
-		if(nilcast(n->left->type, n->type))
-			return 1;
-		break;
-
-	case ONEG:
-	case OADD:
-	case OSUB:
-		return 1;
-
-	case OMUL:
-		if(n->left->op == OCONST)
-			return 1;
-		if(n->right->op == OCONST)
-			return 1;
-	}
-	return 0;
-}
diff --git a/src/cmd/cc/sub.c b/src/cmd/cc/sub.c
deleted file mode 100644
index 94c11d0..0000000
--- a/src/cmd/cc/sub.c
+++ /dev/null
@@ -1,2068 +0,0 @@
-// Inferno utils/cc/sub.c
-// http://code.google.com/p/inferno-os/source/browse/utils/cc/sub.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include	<u.h>
-#include	"cc.h"
-
-Node*
-new(int t, Node *l, Node *r)
-{
-	Node *n;
-
-	n = alloc(sizeof(*n));
-	n->op = t;
-	n->left = l;
-	n->right = r;
-	if(l && t != OGOTO)
-		n->lineno = l->lineno;
-	else if(r)
-		n->lineno = r->lineno;
-	else
-		n->lineno = lineno;
-	newflag = 1;
-	return n;
-}
-
-Node*
-new1(int o, Node *l, Node *r)
-{
-	Node *n;
-
-	n = new(o, l, r);
-	n->lineno = nearln;
-	return n;
-}
-
-void
-prtree(Node *n, char *s)
-{
-
-	print(" == %s ==\n", s);
-	prtree1(n, 0, 0);
-	print("\n");
-}
-
-void
-prtree1(Node *n, int d, int f)
-{
-	int i;
-
-	if(f)
-	for(i=0; i<d; i++)
-		print("   ");
-	if(n == Z) {
-		print("Z\n");
-		return;
-	}
-	if(n->op == OLIST) {
-		prtree1(n->left, d, 0);
-		prtree1(n->right, d, 1);
-		return;
-	}
-	d++;
-	print("%O", n->op);
-	i = 3;
-	switch(n->op)
-	{
-	case ONAME:
-		print(" \"%F\"", n);
-		print(" %d", n->xoffset);
-		i = 0;
-		break;
-
-	case OINDREG:
-		print(" %d(R%d)", n->xoffset, n->reg);
-		i = 0;
-		break;
-
-	case OREGISTER:
-		if(n->xoffset)
-			print(" %d+R%d", n->xoffset, n->reg);
-		else
-			print(" R%d", n->reg);
-		i = 0;
-		break;
-
-	case OSTRING:
-		print(" \"%s\"", n->cstring);
-		i = 0;
-		break;
-
-	case OLSTRING:
-		if(sizeof(TRune) == sizeof(Rune))
-			print(" \"%S\"", (Rune*)n->rstring);
-		else
-			print(" \"...\"");
-		i = 0;
-		break;
-
-	case ODOT:
-	case OELEM:
-		print(" \"%F\"", n);
-		break;
-
-	case OCONST:
-		if(typefd[n->type->etype])
-			print(" \"%.8e\"", n->fconst);
-		else
-			print(" \"%lld\"", n->vconst);
-		i = 0;
-		break;
-	}
-	if(n->addable != 0)
-		print(" <%d>", n->addable);
-	if(n->type != T)
-		print(" %T", n->type);
-	if(n->complex != 0)
-		print(" (%d)", n->complex);
-	print(" %L\n", n->lineno);
-	if(i & 2)
-		prtree1(n->left, d, 1);
-	if(i & 1)
-		prtree1(n->right, d, 1);
-}
-
-Type*
-typ(int et, Type *d)
-{
-	Type *t;
-
-	t = alloc(sizeof(*t));
-	t->etype = et;
-	t->link = d;
-	t->down = T;
-	t->sym = S;
-	if(et < NTYPE)
-		t->width = ewidth[et];
-	else
-		t->width = -1; // for TDOT or TOLD in prototype
-	t->offset = 0;
-	t->shift = 0;
-	t->nbits = 0;
-	t->garb = 0;
-	return t;
-}
-
-Type*
-copytyp(Type *t)
-{
-	Type *nt;
-
-	nt = typ(TXXX, T);
-	*nt = *t;
-	return nt;
-}
-
-Type*
-garbt(Type *t, int32 b)
-{
-	Type *t1;
-
-	if(b & BGARB) {
-		t1 = copytyp(t);
-		t1->garb = simpleg(b);
-		return t1;
-	}
-	return t;
-}
-
-int
-simpleg(int32 b)
-{
-
-	b &= BGARB;
-	switch(b) {
-	case BCONSTNT:
-		return GCONSTNT;
-	case BVOLATILE:
-		return GVOLATILE;
-	case BVOLATILE|BCONSTNT:
-		return GCONSTNT|GVOLATILE;
-	}
-	return GXXX;
-}
-
-int
-simplec(int32 b)
-{
-
-	b &= BCLASS;
-	switch(b) {
-	case 0:
-	case BREGISTER:
-		return CXXX;
-	case BAUTO:
-	case BAUTO|BREGISTER:
-		return CAUTO;
-	case BEXTERN:
-		return CEXTERN;
-	case BEXTERN|BREGISTER:
-		return CEXREG;
-	case BSTATIC:
-		return CSTATIC;
-	case BTYPEDEF:
-		return CTYPEDEF;
-	case BTYPESTR:
-		return CTYPESTR;
-	}
-	diag(Z, "illegal combination of classes %Q", b);
-	return CXXX;
-}
-
-Type*
-simplet(int32 b)
-{
-
-	b &= ~BCLASS & ~BGARB;
-	switch(b) {
-	case BCHAR:
-	case BCHAR|BSIGNED:
-		return types[TCHAR];
-
-	case BCHAR|BUNSIGNED:
-		return types[TUCHAR];
-
-	case BSHORT:
-	case BSHORT|BINT:
-	case BSHORT|BSIGNED:
-	case BSHORT|BINT|BSIGNED:
-		return types[TSHORT];
-
-	case BUNSIGNED|BSHORT:
-	case BUNSIGNED|BSHORT|BINT:
-		return types[TUSHORT];
-
-	case 0:
-	case BINT:
-	case BINT|BSIGNED:
-	case BSIGNED:
-		return types[TINT];
-
-	case BUNSIGNED:
-	case BUNSIGNED|BINT:
-		return types[TUINT];
-
-	case BLONG:
-	case BLONG|BINT:
-	case BLONG|BSIGNED:
-	case BLONG|BINT|BSIGNED:
-		return types[TLONG];
-
-	case BUNSIGNED|BLONG:
-	case BUNSIGNED|BLONG|BINT:
-		return types[TULONG];
-
-	case BVLONG|BLONG:
-	case BVLONG|BLONG|BINT:
-	case BVLONG|BLONG|BSIGNED:
-	case BVLONG|BLONG|BINT|BSIGNED:
-		return types[TVLONG];
-
-	case BVLONG|BLONG|BUNSIGNED:
-	case BVLONG|BLONG|BINT|BUNSIGNED:
-		return types[TUVLONG];
-
-	case BFLOAT:
-		return types[TFLOAT];
-
-	case BDOUBLE:
-	case BDOUBLE|BLONG:
-	case BFLOAT|BLONG:
-		return types[TDOUBLE];
-
-	case BVOID:
-		return types[TVOID];
-	}
-
-	diag(Z, "illegal combination of types %Q", b);
-	return types[TINT];
-}
-
-int
-stcompat(Node *n, Type *t1, Type *t2, int32 ttab[])
-{
-	int i;
-	uint32 b;
-
-	i = 0;
-	if(t2 != T)
-		i = t2->etype;
-	b = 1L << i;
-	i = 0;
-	if(t1 != T)
-		i = t1->etype;
-	if(b & ttab[i]) {
-		if(ttab == tasign)
-			if(b == BSTRUCT || b == BUNION)
-				if(!sametype(t1, t2))
-					return 1;
-		if(n->op != OCAST)
-		 	if(b == BIND && i == TIND)
-				if(!sametype(t1, t2))
-					return 1;
-		return 0;
-	}
-	return 1;
-}
-
-int
-tcompat(Node *n, Type *t1, Type *t2, int32 ttab[])
-{
-
-	if(stcompat(n, t1, t2, ttab)) {
-		if(t1 == T)
-			diag(n, "incompatible type: \"%T\" for op \"%O\"",
-				t2, n->op);
-		else
-			diag(n, "incompatible types: \"%T\" and \"%T\" for op \"%O\"",
-				t1, t2, n->op);
-		return 1;
-	}
-	return 0;
-}
-
-void
-makedot(Node *n, Type *t, int32 o)
-{
-	Node *n1, *n2;
-
-	if(t->nbits) {
-		n1 = new(OXXX, Z, Z);
-		*n1 = *n;
-		n->op = OBIT;
-		n->left = n1;
-		n->right = Z;
-		n->type = t;
-		n->addable = n1->left->addable;
-		n = n1;
-	}
-	n->addable = n->left->addable;
-	if(n->addable == 0) {
-		n1 = new1(OCONST, Z, Z);
-		n1->vconst = o;
-		n1->type = types[TLONG];
-		n->right = n1;
-		n->type = t;
-		return;
-	}
-	n->left->type = t;
-	if(o == 0) {
-		*n = *n->left;
-		return;
-	}
-	n->type = t;
-	n1 = new1(OCONST, Z, Z);
-	n1->vconst = o;
-	t = typ(TIND, t);
-	t->width = types[TIND]->width;
-	n1->type = t;
-
-	n2 = new1(OADDR, n->left, Z);
-	n2->type = t;
-
-	n1 = new1(OADD, n1, n2);
-	n1->type = t;
-
-	n->op = OIND;
-	n->left = n1;
-	n->right = Z;
-}
-
-Type*
-dotsearch(Sym *s, Type *t, Node *n, int32 *off)
-{
-	Type *t1, *xt, *rt;
-
-	xt = T;
-
-	/*
-	 * look it up by name
-	 */
-	for(t1 = t; t1 != T; t1 = t1->down)
-		if(t1->sym == s) {
-			if(xt != T)
-				goto ambig;
-			xt = t1;
-		}
-
-	/*
-	 * look it up by type
-	 */
-	if(s->class == CTYPEDEF || s->class == CTYPESTR)
-		for(t1 = t; t1 != T; t1 = t1->down)
-			if(t1->sym == S && typesu[t1->etype])
-				if(sametype(s->type, t1)) {
-					if(xt != T)
-						goto ambig;
-					xt = t1;
-				}
-	if(xt != T) {
-		*off = xt->offset;
-		return xt;
-	}
-
-	/*
-	 * look it up in unnamed substructures
-	 */
-	for(t1 = t; t1 != T; t1 = t1->down)
-		if(t1->sym == S && typesu[t1->etype]){
-			rt = dotsearch(s, t1->link, n, off);
-			if(rt != T) {
-				if(xt != T)
-					goto ambig;
-				xt = rt;
-				*off += t1->offset;
-			}
-		}
-	return xt;
-
-ambig:
-	diag(n, "ambiguous structure element: %s", s->name);
-	return xt;
-}
-
-int32
-dotoffset(Type *st, Type *lt, Node *n)
-{
-	Type *t;
-	Sym *g;
-	int32 o, o1;
-
-	o = -1;
-	/*
-	 * first try matching at the top level
-	 * for matching tag names
-	 */
-	g = st->tag;
-	if(g != S)
-		for(t=lt->link; t!=T; t=t->down)
-			if(t->sym == S)
-				if(g == t->tag) {
-					if(o >= 0)
-						goto ambig;
-					o = t->offset;
-				}
-	if(o >= 0)
-		return o;
-
-	/*
-	 * second try matching at the top level
-	 * for similar types
-	 */
-	for(t=lt->link; t!=T; t=t->down)
-		if(t->sym == S)
-			if(sametype(st, t)) {
-				if(o >= 0)
-					goto ambig;
-				o = t->offset;
-			}
-	if(o >= 0)
-		return o;
-
-	/*
-	 * last try matching sub-levels
-	 */
-	for(t=lt->link; t!=T; t=t->down)
-		if(t->sym == S)
-		if(typesu[t->etype]) {
-			o1 = dotoffset(st, t, n);
-			if(o1 >= 0) {
-				if(o >= 0)
-					goto ambig;
-				o = o1 + t->offset;
-			}
-		}
-	return o;
-
-ambig:
-	diag(n, "ambiguous unnamed structure element");
-	return o;
-}
-
-/*
- * look into tree for floating point constant expressions
- */
-int
-allfloat(Node *n, int flag)
-{
-
-	if(n != Z) {
-		if(n->type->etype != TDOUBLE)
-			return 1;
-		switch(n->op) {
-		case OCONST:
-			if(flag)
-				n->type = types[TFLOAT];
-			return 1;
-		case OADD:	/* no need to get more exotic than this */
-		case OSUB:
-		case OMUL:
-		case ODIV:
-			if(!allfloat(n->right, flag))
-				break;
-		case OCAST:
-			if(!allfloat(n->left, flag))
-				break;
-			if(flag)
-				n->type = types[TFLOAT];
-			return 1;
-		}
-	}
-	return 0;
-}
-
-void
-constas(Node *n, Type *il, Type *ir)
-{
-	Type *l, *r;
-
-	l = il;
-	r = ir;
-
-	if(l == T)
-		return;
-	if(l->garb & GCONSTNT) {
-		warn(n, "assignment to a constant type (%T)", il);
-		return;
-	}
-	if(r == T)
-		return;
-	for(;;) {
-		if(l->etype != TIND || r->etype != TIND)
-			break;
-		l = l->link;
-		r = r->link;
-		if(l == T || r == T)
-			break;
-		if(r->garb & GCONSTNT)
-			if(!(l->garb & GCONSTNT)) {
-				warn(n, "assignment of a constant pointer type (%T)", ir);
-				break;
-			}
-	}
-}
-
-void
-typeext1(Type *st, Node *l)
-{
-	if(st->etype == TFLOAT && allfloat(l, 0))
-		allfloat(l, 1);
-}
-
-void
-typeext(Type *st, Node *l)
-{
-	Type *lt;
-	Node *n1, *n2;
-	int32 o;
-
-	lt = l->type;
-	if(lt == T)
-		return;
-	if(st->etype == TIND && vconst(l) == 0) {
-		l->type = st;
-		l->vconst = 0;
-		return;
-	}
-	typeext1(st, l);
-
-	/*
-	 * extension of C
-	 * if assign of struct containing unnamed sub-struct
-	 * to type of sub-struct, insert the DOT.
-	 * if assign of *struct containing unnamed substruct
-	 * to type of *sub-struct, insert the add-offset
-	 */
-	if(typesu[st->etype] && typesu[lt->etype]) {
-		o = dotoffset(st, lt, l);
-		if(o >= 0) {
-			n1 = new1(OXXX, Z, Z);
-			*n1 = *l;
-			l->op = ODOT;
-			l->left = n1;
-			l->right = Z;
-			makedot(l, st, o);
-		}
-		return;
-	}
-	if(st->etype == TIND && typesu[st->link->etype])
-	if(lt->etype == TIND && typesu[lt->link->etype]) {
-		o = dotoffset(st->link, lt->link, l);
-		if(o >= 0) {
-			l->type = st;
-			if(o == 0)
-				return;
-			n1 = new1(OXXX, Z, Z);
-			*n1 = *l;
-			n2 = new1(OCONST, Z, Z);
-			n2->vconst = o;
-			n2->type = st;
-			l->op = OADD;
-			l->left = n1;
-			l->right = n2;
-		}
-		return;
-	}
-}
-
-/*
- * a cast that generates no code
- * (same size move)
- */
-int
-nocast(Type *t1, Type *t2)
-{
-	int i, b;
-
-	if(t1->nbits)
-		return 0;
-	i = 0;
-	if(t2 != T)
-		i = t2->etype;
-	b = 1<<i;
-	i = 0;
-	if(t1 != T)
-		i = t1->etype;
-	if(b & ncast[i])
-		return 1;
-	return 0;
-}
-
-/*
- * a cast that has a noop semantic
- * (small to large, convert)
- */
-int
-nilcast(Type *t1, Type *t2)
-{
-	int et1, et2;
-
-	if(t1 == T)
-		return 0;
-	if(t1->nbits)
-		return 0;
-	if(t2 == T)
-		return 0;
-	et1 = t1->etype;
-	et2 = t2->etype;
-	if(et1 == et2)
-		return 1;
-	if(typefd[et1] && typefd[et2]) {
-		if(ewidth[et1] < ewidth[et2])
-			return 1;
-		return 0;
-	}
-	if(typechlp[et1] && typechlp[et2]) {
-		if(ewidth[et1] < ewidth[et2])
-			return 1;
-		return 0;
-	}
-	return 0;
-}
-
-/*
- * "the usual arithmetic conversions are performed"
- */
-void
-arith(Node *n, int f)
-{
-	Type *t1, *t2;
-	int i, j, k;
-	Node *n1;
-	int32 w;
-
-	t1 = n->left->type;
-	if(n->right == Z)
-		t2 = t1;
-	else
-		t2 = n->right->type;
-	i = TXXX;
-	if(t1 != T)
-		i = t1->etype;
-	j = TXXX;
-	if(t2 != T)
-		j = t2->etype;
-	k = tab[i][j];
-	if(k == TIND) {
-		if(i == TIND)
-			n->type = t1;
-		else
-		if(j == TIND)
-			n->type = t2;
-	} else {
-		/* convert up to at least int */
-		if(f == 1)
-		while(k < TINT)
-			k += 2;
-		n->type = types[k];
-	}
-	if(n->op == OSUB)
-	if(i == TIND && j == TIND) {
-		w = n->right->type->link->width;
-		if(w < 1 || n->left->type->link == T || n->left->type->link->width < 1)
-			goto bad;
-		n->type = types[ewidth[TIND] <= ewidth[TLONG]? TLONG: TVLONG];
-		if(0 && ewidth[TIND] > ewidth[TLONG]){
-			n1 = new1(OXXX, Z, Z);
-			*n1 = *n;
-			n->op = OCAST;
-			n->left = n1;
-			n->right = Z;
-			n->type = types[TLONG];
-		}
-		if(w > 1) {
-			n1 = new1(OXXX, Z, Z);
-			*n1 = *n;
-			n->op = ODIV;
-			n->left = n1;
-			n1 = new1(OCONST, Z, Z);
-			n1->vconst = w;
-			n1->type = n->type;
-			n->right = n1;
-			w = vlog(n1);
-			if(w >= 0) {
-				n->op = OASHR;
-				n1->vconst = w;
-			}
-		}
-		return;
-	}
-	if(!sametype(n->type, n->left->type)) {
-		n->left = new1(OCAST, n->left, Z);
-		n->left->type = n->type;
-		if(n->type->etype == TIND) {
-			w = n->type->link->width;
-			if(w < 1) {
-				snap(n->type->link);
-				w = n->type->link->width;
-				if(w < 1)
-					goto bad;
-			}
-			if(w > 1) {
-				n1 = new1(OCONST, Z, Z);
-				n1->vconst = w;
-				n1->type = n->type;
-				n->left = new1(OMUL, n->left, n1);
-				n->left->type = n->type;
-			}
-		}
-	}
-	if(n->right != Z)
-	if(!sametype(n->type, n->right->type)) {
-		n->right = new1(OCAST, n->right, Z);
-		n->right->type = n->type;
-		if(n->type->etype == TIND) {
-			w = n->type->link->width;
-			if(w < 1) {
-				snap(n->type->link);
-				w = n->type->link->width;
-				if(w < 1)
-					goto bad;
-			}
-			if(w != 1) {
-				n1 = new1(OCONST, Z, Z);
-				n1->vconst = w;
-				n1->type = n->type;
-				n->right = new1(OMUL, n->right, n1);
-				n->right->type = n->type;
-			}
-		}
-	}
-	return;
-bad:
-	diag(n, "pointer addition not fully declared: %T", n->type->link);
-}
-
-/*
- * try to rewrite shift & mask
- */
-void
-simplifyshift(Node *n)
-{
-	uint32 c3;
-	int o, s1, s2, c1, c2;
-
-	if(!typechlp[n->type->etype])
-		return;
-	switch(n->op) {
-	default:
-		return;
-	case OASHL:
-		s1 = 0;
-		break;
-	case OLSHR:
-		s1 = 1;
-		break;
-	case OASHR:
-		s1 = 2;
-		break;
-	}
-	if(n->right->op != OCONST)
-		return;
-	if(n->left->op != OAND)
-		return;
-	if(n->left->right->op != OCONST)
-		return;
-	switch(n->left->left->op) {
-	default:
-		return;
-	case OASHL:
-		s2 = 0;
-		break;
-	case OLSHR:
-		s2 = 1;
-		break;
-	case OASHR:
-		s2 = 2;
-		break;
-	}
-	if(n->left->left->right->op != OCONST)
-		return;
-
-	c1 = n->right->vconst;
-	c2 = n->left->left->right->vconst;
-	c3 = n->left->right->vconst;
-
-	o = n->op;
-	switch((s1<<3)|s2) {
-	case 000:	/* (((e <<u c2) & c3) <<u c1) */
-		c3 >>= c2;
-		c1 += c2;
-		if(c1 >= 32)
-			break;
-		goto rewrite1;
-
-	case 002:	/* (((e >>s c2) & c3) <<u c1) */
-		if(topbit(c3) >= (32-c2))
-			break;
-	case 001:	/* (((e >>u c2) & c3) <<u c1) */
-		if(c1 > c2) {
-			c3 <<= c2;
-			c1 -= c2;
-			o = OASHL;
-			goto rewrite1;
-		}
-		c3 <<= c1;
-		if(c1 == c2)
-			goto rewrite0;
-		c1 = c2-c1;
-		o = OLSHR;
-		goto rewrite2;
-
-	case 022:	/* (((e >>s c2) & c3) >>s c1) */
-		if(c2 <= 0)
-			break;
-	case 012:	/* (((e >>s c2) & c3) >>u c1) */
-		if(topbit(c3) >= (32-c2))
-			break;
-		goto s11;
-	case 021:	/* (((e >>u c2) & c3) >>s c1) */
-		if(topbit(c3) >= 31 && c2 <= 0)
-			break;
-		goto s11;
-	case 011:	/* (((e >>u c2) & c3) >>u c1) */
-	s11:
-		c3 <<= c2;
-		c1 += c2;
-		if(c1 >= 32)
-			break;
-		o = OLSHR;
-		goto rewrite1;
-
-	case 020:	/* (((e <<u c2) & c3) >>s c1) */
-		if(topbit(c3) >= 31)
-			break;
-	case 010:	/* (((e <<u c2) & c3) >>u c1) */
-		c3 >>= c1;
-		if(c1 == c2)
-			goto rewrite0;
-		if(c1 > c2) {
-			c1 -= c2;
-			goto rewrite2;
-		}
-		c1 = c2 - c1;
-		o = OASHL;
-		goto rewrite2;
-	}
-	return;
-
-rewrite0:	/* get rid of both shifts */
-if(debug['<'])prtree(n, "rewrite0");
-	*n = *n->left;
-	n->left = n->left->left;
-	n->right->vconst = c3;
-	return;
-rewrite1:	/* get rid of lower shift */
-if(debug['<'])prtree(n, "rewrite1");
-	n->left->left = n->left->left->left;
-	n->left->right->vconst = c3;
-	n->right->vconst = c1;
-	n->op = o;
-	return;
-rewrite2:	/* get rid of upper shift */
-if(debug['<'])prtree(n, "rewrite2");
-	*n = *n->left;
-	n->right->vconst = c3;
-	n->left->right->vconst = c1;
-	n->left->op = o;
-}
-
-int
-side(Node *n)
-{
-
-loop:
-	if(n != Z)
-	switch(n->op) {
-	case OCAST:
-	case ONOT:
-	case OADDR:
-	case OIND:
-		n = n->left;
-		goto loop;
-
-	case OCOND:
-		if(side(n->left))
-			break;
-		n = n->right;
-
-	case OEQ:
-	case ONE:
-	case OLT:
-	case OGE:
-	case OGT:
-	case OLE:
-	case OADD:
-	case OSUB:
-	case OMUL:
-	case OLMUL:
-	case ODIV:
-	case OLDIV:
-	case OLSHR:
-	case OASHL:
-	case OASHR:
-	case OAND:
-	case OOR:
-	case OXOR:
-	case OMOD:
-	case OLMOD:
-	case OANDAND:
-	case OOROR:
-	case OCOMMA:
-	case ODOT:
-		if(side(n->left))
-			break;
-		n = n->right;
-		goto loop;
-
-	case OSIGN:
-	case OSIZE:
-	case OCONST:
-	case OSTRING:
-	case OLSTRING:
-	case ONAME:
-		return 0;
-	}
-	return 1;
-}
-
-int
-vconst(Node *n)
-{
-	int i;
-
-	if(n == Z)
-		goto no;
-	if(n->op != OCONST)
-		goto no;
-	if(n->type == T)
-		goto no;
-	switch(n->type->etype)
-	{
-	case TFLOAT:
-	case TDOUBLE:
-		i = 100;
-		if(n->fconst > i || n->fconst < -i)
-			goto no;
-		i = n->fconst;
-		if(i != n->fconst)
-			goto no;
-		return i;
-
-	case TVLONG:
-	case TUVLONG:
-		i = n->vconst;
-		if(i != n->vconst)
-			goto no;
-		return i;
-
-	case TCHAR:
-	case TUCHAR:
-	case TSHORT:
-	case TUSHORT:
-	case TINT:
-	case TUINT:
-	case TLONG:
-	case TULONG:
-	case TIND:
-		i = n->vconst;
-		if(i != n->vconst)
-			goto no;
-		return i;
-	}
-no:
-	return -159;	/* first uninteresting constant */
-}
-
-/*
- * return log(n) if n is a power of 2 constant
- */
-int
-xlog2(uvlong v)
-{
-	int s, i;
-	uvlong m;
-
-	s = 0;
-	m = MASK(8*sizeof(uvlong));
-	for(i=32; i; i>>=1) {
-		m >>= i;
-		if(!(v & m)) {
-			v >>= i;
-			s += i;
-		}
-	}
-	if(v == 1)
-		return s;
-	return -1;
-}
-
-int
-vlog(Node *n)
-{
-	if(n->op != OCONST)
-		goto bad;
-	if(typefd[n->type->etype])
-		goto bad;
-
-	return xlog2(n->vconst);
-
-bad:
-	return -1;
-}
-
-int
-topbit(uint32 v)
-{
-	int i;
-
-	for(i = -1; v; i++)
-		v >>= 1;
-	return i;
-}
-
-/*
- * try to cast a constant down
- * rather than cast a variable up
- * example:
- *	if(c == 'a')
- */
-void
-relcon(Node *l, Node *r)
-{
-	vlong v;
-
-	if(l->op != OCONST)
-		return;
-	if(r->op != OCAST)
-		return;
-	if(!nilcast(r->left->type, r->type))
-		return;
-	switch(r->type->etype) {
-	default:
-		return;
-	case TCHAR:
-	case TUCHAR:
-	case TSHORT:
-	case TUSHORT:
-		v = convvtox(l->vconst, r->type->etype);
-		if(v != l->vconst)
-			return;
-		break;
-	}
-	l->type = r->left->type;
-	*r = *r->left;
-}
-
-int
-relindex(int o)
-{
-
-	switch(o) {
-	default:
-		diag(Z, "bad in relindex: %O", o);
-	case OEQ: return 0;
-	case ONE: return 1;
-	case OLE: return 2;
-	case OLS: return 3;
-	case OLT: return 4;
-	case OLO: return 5;
-	case OGE: return 6;
-	case OHS: return 7;
-	case OGT: return 8;
-	case OHI: return 9;
-	}
-}
-
-Node*
-invert(Node *n)
-{
-	Node *i;
-
-	if(n == Z || n->op != OLIST)
-		return n;
-	i = n;
-	for(n = n->left; n != Z; n = n->left) {
-		if(n->op != OLIST)
-			break;
-		i->left = n->right;
-		n->right = i;
-		i = n;
-	}
-	i->left = n;
-	return i;
-}
-
-int
-bitno(int32 b)
-{
-	int i;
-
-	for(i=0; i<32; i++)
-		if(b & (1L<<i))
-			return i;
-	diag(Z, "bad in bitno");
-	return 0;
-}
-
-int32
-typebitor(int32 a, int32 b)
-{
-	int32 c;
-
-	c = a | b;
-	if(a & b)
-		if((a & b) == BLONG)
-			c |= BVLONG;		/* long long => vlong */
-		else
-			warn(Z, "once is enough: %Q", a & b);
-	return c;
-}
-
-void
-diag(Node *n, char *fmt, ...)
-{
-	char buf[STRINGSZ];
-	va_list arg;
-
-	va_start(arg, fmt);
-	vseprint(buf, buf+sizeof(buf), fmt, arg);
-	va_end(arg);
-	Bprint(&diagbuf, "%L %s\n", (n==Z)? nearln: n->lineno, buf);
-
-	if(debug['X']){
-		Bflush(&diagbuf);
-		abort();
-	}
-	if(n != Z)
-	if(debug['v'])
-		prtree(n, "diagnostic");
-
-	nerrors++;
-	if(nerrors > 10) {
-		Bprint(&diagbuf, "too many errors\n");
-		errorexit();
-	}
-}
-
-void
-warn(Node *n, char *fmt, ...)
-{
-	char buf[STRINGSZ];
-	va_list arg;
-
-	if(debug['w']) {
-		Bprint(&diagbuf, "warning: ");
-		va_start(arg, fmt);
-		vseprint(buf, buf+sizeof(buf), fmt, arg);
-		va_end(arg);
-		Bprint(&diagbuf, "%L %s\n", (n==Z)? nearln: n->lineno, buf);
-
-		if(n != Z)
-		if(debug['v'])
-			prtree(n, "warning");
-	}
-}
-
-void
-yyerror(char *fmt, ...)
-{
-	char buf[STRINGSZ];
-	va_list arg;
-
-	/*
-	 * hack to intercept message from yaccpar
-	 */
-	if(strcmp(fmt, "syntax error") == 0) {
-		yyerror("syntax error, last name: %s", symb);
-		return;
-	}
-	va_start(arg, fmt);
-	vseprint(buf, buf+sizeof(buf), fmt, arg);
-	va_end(arg);
-	Bprint(&diagbuf, "%L %s\n", lineno, buf);
-	nerrors++;
-	if(nerrors > 10) {
-		Bprint(&diagbuf, "too many errors\n");
-		errorexit();
-	}
-}
-
-void
-fatal(Node *n, char *fmt, ...)
-{
-	char buf[STRINGSZ];
-	va_list arg;
-
-	va_start(arg, fmt);
-	vseprint(buf, buf+sizeof(buf), fmt, arg);
-	va_end(arg);
-	Bprint(&diagbuf, "%L %s\n", (n==Z)? nearln: n->lineno, buf);
-
-	if(debug['X']){
-		Bflush(&diagbuf);
-		abort();
-	}
-	if(n != Z)
-	if(debug['v'])
-		prtree(n, "diagnostic");
-
-	nerrors++;
-	errorexit();
-}
-
-uint32	thash1	= 0x2edab8c9;
-uint32	thash2	= 0x1dc74fb8;
-uint32	thash3	= 0x1f241331;
-uint32	thash[NALLTYPES];
-Init	thashinit[] =
-{
-	TXXX,		0x17527bbd,	0,
-	TCHAR,		0x5cedd32b,	0,
-	TUCHAR,		0x552c4454,	0,
-	TSHORT,		0x63040b4b,	0,
-	TUSHORT,	0x32a45878,	0,
-	TINT,		0x4151d5bd,	0,
-	TUINT,		0x5ae707d6,	0,
-	TLONG,		0x5ef20f47,	0,
-	TULONG,		0x36d8eb8f,	0,
-	TVLONG,		0x6e5e9590,	0,
-	TUVLONG,	0x75910105,	0,
-	TFLOAT,		0x25fd7af1,	0,
-	TDOUBLE,	0x7c40a1b2,	0,
-	TIND,		0x1b832357,	0,
-	TFUNC,		0x6babc9cb,	0,
-	TARRAY,		0x7c50986d,	0,
-	TVOID,		0x44112eff,	0,
-	TSTRUCT,	0x7c2da3bf,	0,
-	TUNION,		0x3eb25e98,	0,
-	TENUM,		0x44b54f61,	0,
-	TFILE,		0x19242ac3,	0,
-	TOLD,		0x22b15988,	0,
-	TDOT,		0x0204f6b3,	0,
-	-1,		0,		0,
-};
-
-char*	bnames[NALIGN];
-Init	bnamesinit[] =
-{
-	Axxx,	0,	"Axxx",
-	Ael1,	0,	"el1",
-	Ael2,	0,	"el2",
-	Asu2,	0,	"su2",
-	Aarg0,	0,	"arg0",
-	Aarg1,	0,	"arg1",
-	Aarg2,	0,	"arg2",
-	Aaut3,	0,	"aut3",
-	-1,	0,	0,
-};
-
-char*	tnames[NALLTYPES];
-Init	tnamesinit[] =
-{
-	TXXX,		0,	"TXXX",
-	TCHAR,		0,	"CHAR",
-	TUCHAR,		0,	"UCHAR",
-	TSHORT,		0,	"SHORT",
-	TUSHORT,	0,	"USHORT",
-	TINT,		0,	"INT",
-	TUINT,		0,	"UINT",
-	TLONG,		0,	"LONG",
-	TULONG,		0,	"ULONG",
-	TVLONG,		0,	"VLONG",
-	TUVLONG,	0,	"UVLONG",
-	TFLOAT,		0,	"FLOAT",
-	TDOUBLE,	0,	"DOUBLE",
-	TIND,		0,	"IND",
-	TFUNC,		0,	"FUNC",
-	TARRAY,		0,	"ARRAY",
-	TVOID,		0,	"VOID",
-	TSTRUCT,	0,	"STRUCT",
-	TUNION,		0,	"UNION",
-	TENUM,		0,	"ENUM",
-	TFILE,		0,	"FILE",
-	TOLD,		0,	"OLD",
-	TDOT,		0,	"DOT",
-	-1,		0,	0,
-};
-
-char*	gnames[NGTYPES];
-Init	gnamesinit[] =
-{
-	GXXX,			0,	"GXXX",
-	GCONSTNT,		0,	"CONST",
-	GVOLATILE,		0,	"VOLATILE",
-	GVOLATILE|GCONSTNT,	0,	"CONST-VOLATILE",
-	-1,			0,	0,
-};
-
-char*	qnames[NALLTYPES];
-Init	qnamesinit[] =
-{
-	TXXX,		0,	"TXXX",
-	TCHAR,		0,	"CHAR",
-	TUCHAR,		0,	"UCHAR",
-	TSHORT,		0,	"SHORT",
-	TUSHORT,	0,	"USHORT",
-	TINT,		0,	"INT",
-	TUINT,		0,	"UINT",
-	TLONG,		0,	"LONG",
-	TULONG,		0,	"ULONG",
-	TVLONG,		0,	"VLONG",
-	TUVLONG,	0,	"UVLONG",
-	TFLOAT,		0,	"FLOAT",
-	TDOUBLE,	0,	"DOUBLE",
-	TIND,		0,	"IND",
-	TFUNC,		0,	"FUNC",
-	TARRAY,		0,	"ARRAY",
-	TVOID,		0,	"VOID",
-	TSTRUCT,	0,	"STRUCT",
-	TUNION,		0,	"UNION",
-	TENUM,		0,	"ENUM",
-
-	TAUTO,		0,	"AUTO",
-	TEXTERN,	0,	"EXTERN",
-	TSTATIC,	0,	"STATIC",
-	TTYPEDEF,	0,	"TYPEDEF",
-	TTYPESTR,	0,	"TYPESTR",
-	TREGISTER,	0,	"REGISTER",
-	TCONSTNT,	0,	"CONSTNT",
-	TVOLATILE,	0,	"VOLATILE",
-	TUNSIGNED,	0,	"UNSIGNED",
-	TSIGNED,	0,	"SIGNED",
-	TDOT,		0,	"DOT",
-	TFILE,		0,	"FILE",
-	TOLD,		0,	"OLD",
-	-1,		0,	0,
-};
-char*	cnames[NCTYPES];
-Init	cnamesinit[] =
-{
-	CXXX,		0,	"CXXX",
-	CAUTO,		0,	"AUTO",
-	CEXTERN,	0,	"EXTERN",
-	CGLOBL,		0,	"GLOBL",
-	CSTATIC,	0,	"STATIC",
-	CLOCAL,		0,	"LOCAL",
-	CTYPEDEF,	0,	"TYPEDEF",
-	CTYPESTR,	0,	"TYPESTR",
-	CPARAM,		0,	"PARAM",
-	CSELEM,		0,	"SELEM",
-	CLABEL,		0,	"LABEL",
-	CEXREG,		0,	"EXREG",
-	-1,		0,	0,
-};
-
-char*	onames[OEND+1];
-Init	onamesinit[] =
-{
-	OXXX,		0,	"OXXX",
-	OADD,		0,	"ADD",
-	OADDR,		0,	"ADDR",
-	OAND,		0,	"AND",
-	OANDAND,	0,	"ANDAND",
-	OARRAY,		0,	"ARRAY",
-	OAS,		0,	"AS",
-	OASI,		0,	"ASI",
-	OASADD,		0,	"ASADD",
-	OASAND,		0,	"ASAND",
-	OASASHL,	0,	"ASASHL",
-	OASASHR,	0,	"ASASHR",
-	OASDIV,		0,	"ASDIV",
-	OASHL,		0,	"ASHL",
-	OASHR,		0,	"ASHR",
-	OASLDIV,	0,	"ASLDIV",
-	OASLMOD,	0,	"ASLMOD",
-	OASLMUL,	0,	"ASLMUL",
-	OASLSHR,	0,	"ASLSHR",
-	OASMOD,		0,	"ASMOD",
-	OASMUL,		0,	"ASMUL",
-	OASOR,		0,	"ASOR",
-	OASSUB,		0,	"ASSUB",
-	OASXOR,		0,	"ASXOR",
-	OBIT,		0,	"BIT",
-	OBREAK,		0,	"BREAK",
-	OCASE,		0,	"CASE",
-	OCAST,		0,	"CAST",
-	OCOMMA,		0,	"COMMA",
-	OCOND,		0,	"COND",
-	OCONST,		0,	"CONST",
-	OCONTINUE,	0,	"CONTINUE",
-	ODIV,		0,	"DIV",
-	ODOT,		0,	"DOT",
-	ODOTDOT,	0,	"DOTDOT",
-	ODWHILE,	0,	"DWHILE",
-	OENUM,		0,	"ENUM",
-	OEQ,		0,	"EQ",
-	OEXREG,	0,	"EXREG",
-	OFOR,		0,	"FOR",
-	OFUNC,		0,	"FUNC",
-	OGE,		0,	"GE",
-	OGOTO,		0,	"GOTO",
-	OGT,		0,	"GT",
-	OHI,		0,	"HI",
-	OHS,		0,	"HS",
-	OIF,		0,	"IF",
-	OIND,		0,	"IND",
-	OINDREG,	0,	"INDREG",
-	OINIT,		0,	"INIT",
-	OLABEL,		0,	"LABEL",
-	OLDIV,		0,	"LDIV",
-	OLE,		0,	"LE",
-	OLIST,		0,	"LIST",
-	OLMOD,		0,	"LMOD",
-	OLMUL,		0,	"LMUL",
-	OLO,		0,	"LO",
-	OLS,		0,	"LS",
-	OLSHR,		0,	"LSHR",
-	OLT,		0,	"LT",
-	OMOD,		0,	"MOD",
-	OMUL,		0,	"MUL",
-	ONAME,		0,	"NAME",
-	ONE,		0,	"NE",
-	ONOT,		0,	"NOT",
-	OOR,		0,	"OR",
-	OOROR,		0,	"OROR",
-	OPOSTDEC,	0,	"POSTDEC",
-	OPOSTINC,	0,	"POSTINC",
-	OPREDEC,	0,	"PREDEC",
-	OPREINC,	0,	"PREINC",
-	OPREFETCH,		0,	"PREFETCH",
-	OPROTO,		0,	"PROTO",
-	OREGISTER,	0,	"REGISTER",
-	ORETURN,	0,	"RETURN",
-	OSET,		0,	"SET",
-	OSIGN,		0,	"SIGN",
-	OSIZE,		0,	"SIZE",
-	OSTRING,	0,	"STRING",
-	OLSTRING,	0,	"LSTRING",
-	OSTRUCT,	0,	"STRUCT",
-	OSUB,		0,	"SUB",
-	OSWITCH,	0,	"SWITCH",
-	OUNION,		0,	"UNION",
-	OUSED,		0,	"USED",
-	OWHILE,		0,	"WHILE",
-	OXOR,		0,	"XOR",
-	OPOS,		0,	"POS",
-	ONEG,		0,	"NEG",
-	OCOM,		0,	"COM",
-	OELEM,		0,	"ELEM",
-	OTST,		0,	"TST",
-	OINDEX,		0,	"INDEX",
-	OFAS,		0,	"FAS",
-	OREGPAIR,	0,	"REGPAIR",
-	OROTL,		0,	"ROTL",
-	OEND,		0,	"END",
-	-1,		0,	0,
-};
-
-/*	OEQ, ONE, OLE, OLS, OLT, OLO, OGE, OHS, OGT, OHI */
-uchar	comrel[12] =
-{
-	ONE, OEQ, OGT, OHI, OGE, OHS, OLT, OLO, OLE, OLS,
-};
-uchar	invrel[12] =
-{
-	OEQ, ONE, OGE, OHS, OGT, OHI, OLE, OLS, OLT, OLO,
-};
-uchar	logrel[12] =
-{
-	OEQ, ONE, OLS, OLS, OLO, OLO, OHS, OHS, OHI, OHI,
-};
-
-uchar	typei[NALLTYPES];
-int	typeiinit[] =
-{
-	TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TVLONG, TUVLONG, -1,
-};
-uchar	typeu[NALLTYPES];
-int	typeuinit[] =
-{
-	TUCHAR, TUSHORT, TUINT, TULONG, TUVLONG, TIND, -1,
-};
-
-uchar	typesuv[NALLTYPES];
-int	typesuvinit[] =
-{
-	TVLONG, TUVLONG, TSTRUCT, TUNION, -1,
-};
-
-uchar	typeilp[NALLTYPES];
-int	typeilpinit[] =
-{
-	TINT, TUINT, TLONG, TULONG, TIND, -1
-};
-
-uchar	typechl[NALLTYPES];
-uchar	typechlv[NALLTYPES];
-uchar	typechlvp[NALLTYPES];
-int	typechlinit[] =
-{
-	TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, -1,
-};
-
-uchar	typechlp[NALLTYPES];
-int	typechlpinit[] =
-{
-	TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TIND, -1,
-};
-
-uchar	typechlpfd[NALLTYPES];
-int	typechlpfdinit[] =
-{
-	TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG, TULONG, TFLOAT, TDOUBLE, TIND, -1,
-};
-
-uchar	typec[NALLTYPES];
-int	typecinit[] =
-{
-	TCHAR, TUCHAR, -1
-};
-
-uchar	typeh[NALLTYPES];
-int	typehinit[] =
-{
-	TSHORT, TUSHORT, -1,
-};
-
-uchar	typeil[NALLTYPES];
-int	typeilinit[] =
-{
-	TINT, TUINT, TLONG, TULONG, -1,
-};
-
-uchar	typev[NALLTYPES];
-int	typevinit[] =
-{
-	TVLONG,	TUVLONG, -1,
-};
-
-uchar	typefd[NALLTYPES];
-int	typefdinit[] =
-{
-	TFLOAT, TDOUBLE, -1,
-};
-
-uchar	typeaf[NALLTYPES];
-int	typeafinit[] =
-{
-	TFUNC, TARRAY, -1,
-};
-
-uchar	typesu[NALLTYPES];
-int	typesuinit[] =
-{
-	TSTRUCT, TUNION, -1,
-};
-
-int32	tasign[NALLTYPES];
-Init	tasigninit[] =
-{
-	TCHAR,		BNUMBER,	0,
-	TUCHAR,		BNUMBER,	0,
-	TSHORT,		BNUMBER,	0,
-	TUSHORT,	BNUMBER,	0,
-	TINT,		BNUMBER,	0,
-	TUINT,		BNUMBER,	0,
-	TLONG,		BNUMBER,	0,
-	TULONG,		BNUMBER,	0,
-	TVLONG,		BNUMBER,	0,
-	TUVLONG,	BNUMBER,	0,
-	TFLOAT,		BNUMBER,	0,
-	TDOUBLE,	BNUMBER,	0,
-	TIND,		BIND,		0,
-	TSTRUCT,	BSTRUCT,	0,
-	TUNION,		BUNION,		0,
-	-1,		0,		0,
-};
-
-int32	tasadd[NALLTYPES];
-Init	tasaddinit[] =
-{
-	TCHAR,		BNUMBER,	0,
-	TUCHAR,		BNUMBER,	0,
-	TSHORT,		BNUMBER,	0,
-	TUSHORT,	BNUMBER,	0,
-	TINT,		BNUMBER,	0,
-	TUINT,		BNUMBER,	0,
-	TLONG,		BNUMBER,	0,
-	TULONG,		BNUMBER,	0,
-	TVLONG,		BNUMBER,	0,
-	TUVLONG,	BNUMBER,	0,
-	TFLOAT,		BNUMBER,	0,
-	TDOUBLE,	BNUMBER,	0,
-	TIND,		BINTEGER,	0,
-	-1,		0,		0,
-};
-
-int32	tcast[NALLTYPES];
-Init	tcastinit[] =
-{
-	TCHAR,		BNUMBER|BIND|BVOID,	0,
-	TUCHAR,		BNUMBER|BIND|BVOID,	0,
-	TSHORT,		BNUMBER|BIND|BVOID,	0,
-	TUSHORT,	BNUMBER|BIND|BVOID,	0,
-	TINT,		BNUMBER|BIND|BVOID,	0,
-	TUINT,		BNUMBER|BIND|BVOID,	0,
-	TLONG,		BNUMBER|BIND|BVOID,	0,
-	TULONG,		BNUMBER|BIND|BVOID,	0,
-	TVLONG,		BNUMBER|BIND|BVOID,	0,
-	TUVLONG,	BNUMBER|BIND|BVOID,	0,
-	TFLOAT,		BNUMBER|BVOID,		0,
-	TDOUBLE,	BNUMBER|BVOID,		0,
-	TIND,		BINTEGER|BIND|BVOID,	0,
-	TVOID,		BVOID,			0,
-	TSTRUCT,	BSTRUCT|BVOID,		0,
-	TUNION,		BUNION|BVOID,		0,
-	-1,		0,			0,
-};
-
-int32	tadd[NALLTYPES];
-Init	taddinit[] =
-{
-	TCHAR,		BNUMBER|BIND,	0,
-	TUCHAR,		BNUMBER|BIND,	0,
-	TSHORT,		BNUMBER|BIND,	0,
-	TUSHORT,	BNUMBER|BIND,	0,
-	TINT,		BNUMBER|BIND,	0,
-	TUINT,		BNUMBER|BIND,	0,
-	TLONG,		BNUMBER|BIND,	0,
-	TULONG,		BNUMBER|BIND,	0,
-	TVLONG,		BNUMBER|BIND,	0,
-	TUVLONG,	BNUMBER|BIND,	0,
-	TFLOAT,		BNUMBER,	0,
-	TDOUBLE,	BNUMBER,	0,
-	TIND,		BINTEGER,	0,
-	-1,		0,		0,
-};
-
-int32	tsub[NALLTYPES];
-Init	tsubinit[] =
-{
-	TCHAR,		BNUMBER,	0,
-	TUCHAR,		BNUMBER,	0,
-	TSHORT,		BNUMBER,	0,
-	TUSHORT,	BNUMBER,	0,
-	TINT,		BNUMBER,	0,
-	TUINT,		BNUMBER,	0,
-	TLONG,		BNUMBER,	0,
-	TULONG,		BNUMBER,	0,
-	TVLONG,		BNUMBER,	0,
-	TUVLONG,	BNUMBER,	0,
-	TFLOAT,		BNUMBER,	0,
-	TDOUBLE,	BNUMBER,	0,
-	TIND,		BINTEGER|BIND,	0,
-	-1,		0,		0,
-};
-
-int32	tmul[NALLTYPES];
-Init	tmulinit[] =
-{
-	TCHAR,		BNUMBER,	0,
-	TUCHAR,		BNUMBER,	0,
-	TSHORT,		BNUMBER,	0,
-	TUSHORT,	BNUMBER,	0,
-	TINT,		BNUMBER,	0,
-	TUINT,		BNUMBER,	0,
-	TLONG,		BNUMBER,	0,
-	TULONG,		BNUMBER,	0,
-	TVLONG,		BNUMBER,	0,
-	TUVLONG,	BNUMBER,	0,
-	TFLOAT,		BNUMBER,	0,
-	TDOUBLE,	BNUMBER,	0,
-	-1,		0,		0,
-};
-
-int32	tand[NALLTYPES];
-Init	tandinit[] =
-{
-	TCHAR,		BINTEGER,	0,
-	TUCHAR,		BINTEGER,	0,
-	TSHORT,		BINTEGER,	0,
-	TUSHORT,	BINTEGER,	0,
-	TINT,		BNUMBER,	0,
-	TUINT,		BNUMBER,	0,
-	TLONG,		BINTEGER,	0,
-	TULONG,		BINTEGER,	0,
-	TVLONG,		BINTEGER,	0,
-	TUVLONG,	BINTEGER,	0,
-	-1,		0,		0,
-};
-
-int32	trel[NALLTYPES];
-Init	trelinit[] =
-{
-	TCHAR,		BNUMBER,	0,
-	TUCHAR,		BNUMBER,	0,
-	TSHORT,		BNUMBER,	0,
-	TUSHORT,	BNUMBER,	0,
-	TINT,		BNUMBER,	0,
-	TUINT,		BNUMBER,	0,
-	TLONG,		BNUMBER,	0,
-	TULONG,		BNUMBER,	0,
-	TVLONG,		BNUMBER,	0,
-	TUVLONG,	BNUMBER,	0,
-	TFLOAT,		BNUMBER,	0,
-	TDOUBLE,	BNUMBER,	0,
-	TIND,		BIND,		0,
-	-1,		0,		0,
-};
-
-int32	tfunct[1] =
-{
-	BFUNC,
-};
-
-int32	tindir[1] =
-{
-	BIND,
-};
-
-int32	tdot[1] =
-{
-	BSTRUCT|BUNION,
-};
-
-int32	tnot[1] =
-{
-	BNUMBER|BIND,
-};
-
-int32	targ[1] =
-{
-	BNUMBER|BIND|BSTRUCT|BUNION,
-};
-
-uchar	tab[NTYPE][NTYPE] =
-{
-/*TXXX*/	{ 0,
-		},
-
-/*TCHAR*/	{ 0,	TCHAR, TUCHAR, TSHORT, TUSHORT, TINT, TUINT, TLONG,
-			TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
-		},
-/*TUCHAR*/	{ 0,	TUCHAR, TUCHAR, TUSHORT, TUSHORT, TUINT, TUINT, TULONG,
-			TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
-		},
-/*TSHORT*/	{ 0,	TSHORT, TUSHORT, TSHORT, TUSHORT, TINT, TUINT, TLONG,
-			TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
-		},
-/*TUSHORT*/	{ 0,	TUSHORT, TUSHORT, TUSHORT, TUSHORT, TUINT, TUINT, TULONG,
-			TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
-		},
-/*TINT*/	{ 0,	TINT, TUINT, TINT, TUINT, TINT, TUINT, TLONG,
-			TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
-		},
-/*TUINT*/	{ 0,	TUINT, TUINT, TUINT, TUINT, TUINT, TUINT, TULONG,
-			TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
-		},
-/*TLONG*/	{ 0,	TLONG, TULONG, TLONG, TULONG, TLONG, TULONG, TLONG,
-			TULONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
-		},
-/*TULONG*/	{ 0,	TULONG, TULONG, TULONG, TULONG, TULONG, TULONG, TULONG,
-			TULONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
-		},
-/*TVLONG*/	{ 0,	TVLONG, TUVLONG, TVLONG, TUVLONG, TVLONG, TUVLONG, TVLONG,
-			TUVLONG, TVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
-		},
-/*TUVLONG*/	{ 0,	TUVLONG, TUVLONG, TUVLONG, TUVLONG, TUVLONG, TUVLONG, TUVLONG,
-			TUVLONG, TUVLONG, TUVLONG, TFLOAT, TDOUBLE, TIND,
-		},
-/*TFLOAT*/	{ 0,	TFLOAT, TFLOAT, TFLOAT, TFLOAT, TFLOAT, TFLOAT, TFLOAT,
-			TFLOAT, TFLOAT, TFLOAT, TFLOAT, TDOUBLE, TIND,
-		},
-/*TDOUBLE*/	{ 0,	TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE, TDOUBLE,
-			TDOUBLE, TDOUBLE, TDOUBLE, TFLOAT, TDOUBLE, TIND,
-		},
-/*TIND*/	{ 0,	TIND, TIND, TIND, TIND, TIND, TIND, TIND,
-			 TIND, TIND, TIND, TIND, TIND, TIND,
-		},
-};
-
-void
-urk(char *name, int max, int i)
-{
-	if(i >= max) {
-		fprint(2, "bad tinit: %s %d>=%d\n", name, i, max);
-		exits("init");
-	}
-}
-
-void
-tinit(void)
-{
-	int *ip;
-	Init *p;
-
-	for(p=thashinit; p->code >= 0; p++) {
-		urk("thash", nelem(thash), p->code);
-		thash[p->code] = p->value;
-	}
-	for(p=bnamesinit; p->code >= 0; p++) {
-		urk("bnames", nelem(bnames), p->code);
-		bnames[p->code] = p->s;
-	}
-	for(p=tnamesinit; p->code >= 0; p++) {
-		urk("tnames", nelem(tnames), p->code);
-		tnames[p->code] = p->s;
-	}
-	for(p=gnamesinit; p->code >= 0; p++) {
-		urk("gnames", nelem(gnames), p->code);
-		gnames[p->code] = p->s;
-	}
-	for(p=qnamesinit; p->code >= 0; p++) {
-		urk("qnames", nelem(qnames), p->code);
-		qnames[p->code] = p->s;
-	}
-	for(p=cnamesinit; p->code >= 0; p++) {
-		urk("cnames", nelem(cnames), p->code);
-		cnames[p->code] = p->s;
-	}
-	for(p=onamesinit; p->code >= 0; p++) {
-		urk("onames", nelem(onames), p->code);
-		onames[p->code] = p->s;
-	}
-	for(ip=typeiinit; *ip>=0; ip++) {
-		urk("typei", nelem(typei), *ip);
-		typei[*ip] = 1;
-	}
-	for(ip=typeuinit; *ip>=0; ip++) {
-		urk("typeu", nelem(typeu), *ip);
-		typeu[*ip] = 1;
-	}
-	for(ip=typesuvinit; *ip>=0; ip++) {
-		urk("typesuv", nelem(typesuv), *ip);
-		typesuv[*ip] = 1;
-	}
-	for(ip=typeilpinit; *ip>=0; ip++) {
-		urk("typeilp", nelem(typeilp), *ip);
-		typeilp[*ip] = 1;
-	}
-	for(ip=typechlinit; *ip>=0; ip++) {
-		urk("typechl", nelem(typechl), *ip);
-		typechl[*ip] = 1;
-		typechlv[*ip] = 1;
-		typechlvp[*ip] = 1;
-	}
-	for(ip=typechlpinit; *ip>=0; ip++) {
-		urk("typechlp", nelem(typechlp), *ip);
-		typechlp[*ip] = 1;
-		typechlvp[*ip] = 1;
-	}
-	for(ip=typechlpfdinit; *ip>=0; ip++) {
-		urk("typechlpfd", nelem(typechlpfd), *ip);
-		typechlpfd[*ip] = 1;
-	}
-	for(ip=typecinit; *ip>=0; ip++) {
-		urk("typec", nelem(typec), *ip);
-		typec[*ip] = 1;
-	}
-	for(ip=typehinit; *ip>=0; ip++) {
-		urk("typeh", nelem(typeh), *ip);
-		typeh[*ip] = 1;
-	}
-	for(ip=typeilinit; *ip>=0; ip++) {
-		urk("typeil", nelem(typeil), *ip);
-		typeil[*ip] = 1;
-	}
-	for(ip=typevinit; *ip>=0; ip++) {
-		urk("typev", nelem(typev), *ip);
-		typev[*ip] = 1;
-		typechlv[*ip] = 1;
-		typechlvp[*ip] = 1;
-	}
-	for(ip=typefdinit; *ip>=0; ip++) {
-		urk("typefd", nelem(typefd), *ip);
-		typefd[*ip] = 1;
-	}
-	for(ip=typeafinit; *ip>=0; ip++) {
-		urk("typeaf", nelem(typeaf), *ip);
-		typeaf[*ip] = 1;
-	}
-	for(ip=typesuinit; *ip >= 0; ip++) {
-		urk("typesu", nelem(typesu), *ip);
-		typesu[*ip] = 1;
-	}
-	for(p=tasigninit; p->code >= 0; p++) {
-		urk("tasign", nelem(tasign), p->code);
-		tasign[p->code] = p->value;
-	}
-	for(p=tasaddinit; p->code >= 0; p++) {
-		urk("tasadd", nelem(tasadd), p->code);
-		tasadd[p->code] = p->value;
-	}
-	for(p=tcastinit; p->code >= 0; p++) {
-		urk("tcast", nelem(tcast), p->code);
-		tcast[p->code] = p->value;
-	}
-	for(p=taddinit; p->code >= 0; p++) {
-		urk("tadd", nelem(tadd), p->code);
-		tadd[p->code] = p->value;
-	}
-	for(p=tsubinit; p->code >= 0; p++) {
-		urk("tsub", nelem(tsub), p->code);
-		tsub[p->code] = p->value;
-	}
-	for(p=tmulinit; p->code >= 0; p++) {
-		urk("tmul", nelem(tmul), p->code);
-		tmul[p->code] = p->value;
-	}
-	for(p=tandinit; p->code >= 0; p++) {
-		urk("tand", nelem(tand), p->code);
-		tand[p->code] = p->value;
-	}
-	for(p=trelinit; p->code >= 0; p++) {
-		urk("trel", nelem(trel), p->code);
-		trel[p->code] = p->value;
-	}
-	
-	/* 32-bit defaults */
-	typeword = typechlp;
-	typecmplx = typesuv;
-}
-
-/*
- * return 1 if it is impossible to jump into the middle of n.
- */
-static int
-deadhead(Node *n, int caseok)
-{
-loop:
-	if(n == Z)
-		return 1;
-	switch(n->op) {
-	case OLIST:
-		if(!deadhead(n->left, caseok))
-			return 0;
-	rloop:
-		n = n->right;
-		goto loop;
-
-	case ORETURN:
-		break;
-
-	case OLABEL:
-		return 0;
-
-	case OGOTO:
-		break;
-
-	case OCASE:
-		if(!caseok)
-			return 0;
-		goto rloop;
-
-	case OSWITCH:
-		return deadhead(n->right, 1);
-
-	case OWHILE:
-	case ODWHILE:
-		goto rloop;
-
-	case OFOR:
-		goto rloop;
-
-	case OCONTINUE:
-		break;
-
-	case OBREAK:
-		break;
-
-	case OIF:
-		return deadhead(n->right->left, caseok) && deadhead(n->right->right, caseok);
-
-	case OSET:
-	case OUSED:
-		break;
-	}
-	return 1;
-}
-
-int
-deadheads(Node *c)
-{
-	return deadhead(c->left, 0) && deadhead(c->right, 0);
-}
-
-int
-mixedasop(Type *l, Type *r)
-{
-	return !typefd[l->etype] && typefd[r->etype];
-}
-
-LSym*
-linksym(Sym *s)
-{
-	if(s == nil)
-		return nil;
-	if(s->lsym != nil)
-		return s->lsym;
-	return linklookup(ctxt, s->name, s->class == CSTATIC);
-}
diff --git a/src/cmd/cc/y.tab.c b/src/cmd/cc/y.tab.c
deleted file mode 100644
index 94932ef..0000000
--- a/src/cmd/cc/y.tab.c
+++ /dev/null
@@ -1,3822 +0,0 @@
-/* A Bison parser, made by GNU Bison 2.3.  */
-
-/* Skeleton implementation for Bison's Yacc-like parsers in C
-
-   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
-   Free Software Foundation, Inc.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
-   any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301, USA.  */
-
-/* As a special exception, you may create a larger work that contains
-   part or all of the Bison parser skeleton and distribute that work
-   under terms of your choice, so long as that work isn't itself a
-   parser generator using the skeleton or a modified version thereof
-   as a parser skeleton.  Alternatively, if you modify or redistribute
-   the parser skeleton itself, you may (at your option) remove this
-   special exception, which will cause the skeleton and the resulting
-   Bison output files to be licensed under the GNU General Public
-   License without this special exception.
-
-   This special exception was added by the Free Software Foundation in
-   version 2.2 of Bison.  */
-
-/* C LALR(1) parser skeleton written by Richard Stallman, by
-   simplifying the original so-called "semantic" parser.  */
-
-/* All symbols defined below should begin with yy or YY, to avoid
-   infringing on user name space.  This should be done even for local
-   variables, as they might otherwise be expanded by user macros.
-   There are some unavoidable exceptions within include files to
-   define necessary library symbols; they are noted "INFRINGES ON
-   USER NAME SPACE" below.  */
-
-/* Identify Bison output.  */
-#define YYBISON 1
-
-/* Bison version.  */
-#define YYBISON_VERSION "2.3"
-
-/* Skeleton name.  */
-#define YYSKELETON_NAME "yacc.c"
-
-/* Pure parsers.  */
-#define YYPURE 0
-
-/* Using locations.  */
-#define YYLSP_NEEDED 0
-
-
-
-/* Tokens.  */
-#ifndef YYTOKENTYPE
-# define YYTOKENTYPE
-   /* Put the tokens into the symbol table, so that GDB and other debuggers
-      know about them.  */
-   enum yytokentype {
-     LORE = 258,
-     LXORE = 259,
-     LANDE = 260,
-     LLSHE = 261,
-     LRSHE = 262,
-     LMDE = 263,
-     LDVE = 264,
-     LMLE = 265,
-     LME = 266,
-     LPE = 267,
-     LOROR = 268,
-     LANDAND = 269,
-     LNE = 270,
-     LEQ = 271,
-     LGE = 272,
-     LLE = 273,
-     LRSH = 274,
-     LLSH = 275,
-     LMG = 276,
-     LPP = 277,
-     LMM = 278,
-     LNAME = 279,
-     LTYPE = 280,
-     LFCONST = 281,
-     LDCONST = 282,
-     LCONST = 283,
-     LLCONST = 284,
-     LUCONST = 285,
-     LULCONST = 286,
-     LVLCONST = 287,
-     LUVLCONST = 288,
-     LSTRING = 289,
-     LLSTRING = 290,
-     LAUTO = 291,
-     LBREAK = 292,
-     LCASE = 293,
-     LCHAR = 294,
-     LCONTINUE = 295,
-     LDEFAULT = 296,
-     LDO = 297,
-     LDOUBLE = 298,
-     LELSE = 299,
-     LEXTERN = 300,
-     LFLOAT = 301,
-     LFOR = 302,
-     LGOTO = 303,
-     LIF = 304,
-     LINT = 305,
-     LLONG = 306,
-     LPREFETCH = 307,
-     LREGISTER = 308,
-     LRETURN = 309,
-     LSHORT = 310,
-     LSIZEOF = 311,
-     LUSED = 312,
-     LSTATIC = 313,
-     LSTRUCT = 314,
-     LSWITCH = 315,
-     LTYPEDEF = 316,
-     LTYPESTR = 317,
-     LUNION = 318,
-     LUNSIGNED = 319,
-     LWHILE = 320,
-     LVOID = 321,
-     LENUM = 322,
-     LSIGNED = 323,
-     LCONSTNT = 324,
-     LVOLATILE = 325,
-     LSET = 326,
-     LSIGNOF = 327,
-     LRESTRICT = 328,
-     LINLINE = 329
-   };
-#endif
-/* Tokens.  */
-#define LORE 258
-#define LXORE 259
-#define LANDE 260
-#define LLSHE 261
-#define LRSHE 262
-#define LMDE 263
-#define LDVE 264
-#define LMLE 265
-#define LME 266
-#define LPE 267
-#define LOROR 268
-#define LANDAND 269
-#define LNE 270
-#define LEQ 271
-#define LGE 272
-#define LLE 273
-#define LRSH 274
-#define LLSH 275
-#define LMG 276
-#define LPP 277
-#define LMM 278
-#define LNAME 279
-#define LTYPE 280
-#define LFCONST 281
-#define LDCONST 282
-#define LCONST 283
-#define LLCONST 284
-#define LUCONST 285
-#define LULCONST 286
-#define LVLCONST 287
-#define LUVLCONST 288
-#define LSTRING 289
-#define LLSTRING 290
-#define LAUTO 291
-#define LBREAK 292
-#define LCASE 293
-#define LCHAR 294
-#define LCONTINUE 295
-#define LDEFAULT 296
-#define LDO 297
-#define LDOUBLE 298
-#define LELSE 299
-#define LEXTERN 300
-#define LFLOAT 301
-#define LFOR 302
-#define LGOTO 303
-#define LIF 304
-#define LINT 305
-#define LLONG 306
-#define LPREFETCH 307
-#define LREGISTER 308
-#define LRETURN 309
-#define LSHORT 310
-#define LSIZEOF 311
-#define LUSED 312
-#define LSTATIC 313
-#define LSTRUCT 314
-#define LSWITCH 315
-#define LTYPEDEF 316
-#define LTYPESTR 317
-#define LUNION 318
-#define LUNSIGNED 319
-#define LWHILE 320
-#define LVOID 321
-#define LENUM 322
-#define LSIGNED 323
-#define LCONSTNT 324
-#define LVOLATILE 325
-#define LSET 326
-#define LSIGNOF 327
-#define LRESTRICT 328
-#define LINLINE 329
-
-
-
-
-/* Copy the first part of user declarations.  */
-#line 31 "cc.y"
-
-#include <u.h>
-#include <stdio.h>	/* if we don't, bison will, and cc.h re-#defines getc */
-#include "cc.h"
-
-
-/* Enabling traces.  */
-#ifndef YYDEBUG
-# define YYDEBUG 0
-#endif
-
-/* Enabling verbose error messages.  */
-#ifdef YYERROR_VERBOSE
-# undef YYERROR_VERBOSE
-# define YYERROR_VERBOSE 1
-#else
-# define YYERROR_VERBOSE 0
-#endif
-
-/* Enabling the token table.  */
-#ifndef YYTOKEN_TABLE
-# define YYTOKEN_TABLE 0
-#endif
-
-#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-typedef union YYSTYPE
-#line 36 "cc.y"
-{
-	Node*	node;
-	Sym*	sym;
-	Type*	type;
-	struct
-	{
-		Type*	t;
-		uchar	c;
-	} tycl;
-	struct
-	{
-		Type*	t1;
-		Type*	t2;
-		Type*	t3;
-		uchar	c;
-	} tyty;
-	struct
-	{
-		char*	s;
-		int32	l;
-	} sval;
-	int32	lval;
-	double	dval;
-	vlong	vval;
-}
-/* Line 193 of yacc.c.  */
-#line 276 "y.tab.c"
-	YYSTYPE;
-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
-# define YYSTYPE_IS_DECLARED 1
-# define YYSTYPE_IS_TRIVIAL 1
-#endif
-
-
-
-/* Copy the second part of user declarations.  */
-
-
-/* Line 216 of yacc.c.  */
-#line 289 "y.tab.c"
-
-#ifdef short
-# undef short
-#endif
-
-#ifdef YYTYPE_UINT8
-typedef YYTYPE_UINT8 yytype_uint8;
-#else
-typedef unsigned char yytype_uint8;
-#endif
-
-#ifdef YYTYPE_INT8
-typedef YYTYPE_INT8 yytype_int8;
-#elif (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-typedef signed char yytype_int8;
-#else
-typedef short int yytype_int8;
-#endif
-
-#ifdef YYTYPE_UINT16
-typedef YYTYPE_UINT16 yytype_uint16;
-#else
-typedef unsigned short int yytype_uint16;
-#endif
-
-#ifdef YYTYPE_INT16
-typedef YYTYPE_INT16 yytype_int16;
-#else
-typedef short int yytype_int16;
-#endif
-
-#ifndef YYSIZE_T
-# ifdef __SIZE_TYPE__
-#  define YYSIZE_T __SIZE_TYPE__
-# elif defined size_t
-#  define YYSIZE_T size_t
-# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
-#  define YYSIZE_T size_t
-# else
-#  define YYSIZE_T unsigned int
-# endif
-#endif
-
-#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
-
-#ifndef YY_
-# if defined YYENABLE_NLS && YYENABLE_NLS
-#  if ENABLE_NLS
-#   include <libintl.h> /* INFRINGES ON USER NAME SPACE */
-#   define YY_(msgid) dgettext ("bison-runtime", msgid)
-#  endif
-# endif
-# ifndef YY_
-#  define YY_(msgid) msgid
-# endif
-#endif
-
-/* Suppress unused-variable warnings by "using" E.  */
-#if ! defined lint || defined __GNUC__
-# define YYUSE(e) ((void) (e))
-#else
-# define YYUSE(e) /* empty */
-#endif
-
-/* Identity function, used to suppress warnings about constant conditions.  */
-#ifndef lint
-# define YYID(n) (n)
-#else
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static int
-YYID (int i)
-#else
-static int
-YYID (i)
-    int i;
-#endif
-{
-  return i;
-}
-#endif
-
-#if ! defined yyoverflow || YYERROR_VERBOSE
-
-/* The parser invokes alloca or malloc; define the necessary symbols.  */
-
-# ifdef YYSTACK_USE_ALLOCA
-#  if YYSTACK_USE_ALLOCA
-#   ifdef __GNUC__
-#    define YYSTACK_ALLOC __builtin_alloca
-#   elif defined __BUILTIN_VA_ARG_INCR
-#    include <alloca.h> /* INFRINGES ON USER NAME SPACE */
-#   elif defined _AIX
-#    define YYSTACK_ALLOC __alloca
-#   elif defined _MSC_VER
-#    include <malloc.h> /* INFRINGES ON USER NAME SPACE */
-#    define alloca _alloca
-#   else
-#    define YYSTACK_ALLOC alloca
-#    if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-#     include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-#     ifndef _STDLIB_H
-#      define _STDLIB_H 1
-#     endif
-#    endif
-#   endif
-#  endif
-# endif
-
-# ifdef YYSTACK_ALLOC
-   /* Pacify GCC's `empty if-body' warning.  */
-#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
-#  ifndef YYSTACK_ALLOC_MAXIMUM
-    /* The OS might guarantee only one guard page at the bottom of the stack,
-       and a page size can be as small as 4096 bytes.  So we cannot safely
-       invoke alloca (N) if N exceeds 4096.  Use a slightly smaller number
-       to allow for a few compiler-allocated temporary stack slots.  */
-#   define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
-#  endif
-# else
-#  define YYSTACK_ALLOC YYMALLOC
-#  define YYSTACK_FREE YYFREE
-#  ifndef YYSTACK_ALLOC_MAXIMUM
-#   define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
-#  endif
-#  if (defined __cplusplus && ! defined _STDLIB_H \
-       && ! ((defined YYMALLOC || defined malloc) \
-	     && (defined YYFREE || defined free)))
-#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-#   ifndef _STDLIB_H
-#    define _STDLIB_H 1
-#   endif
-#  endif
-#  ifndef YYMALLOC
-#   define YYMALLOC malloc
-#   if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
-#   endif
-#  endif
-#  ifndef YYFREE
-#   define YYFREE free
-#   if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-void free (void *); /* INFRINGES ON USER NAME SPACE */
-#   endif
-#  endif
-# endif
-#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
-
-
-#if (! defined yyoverflow \
-     && (! defined __cplusplus \
-	 || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
-
-/* A type that is properly aligned for any stack member.  */
-union yyalloc
-{
-  yytype_int16 yyss;
-  YYSTYPE yyvs;
-  };
-
-/* The size of the maximum gap between one aligned stack and the next.  */
-# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
-
-/* The size of an array large to enough to hold all stacks, each with
-   N elements.  */
-# define YYSTACK_BYTES(N) \
-     ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
-      + YYSTACK_GAP_MAXIMUM)
-
-/* Copy COUNT objects from FROM to TO.  The source and destination do
-   not overlap.  */
-# ifndef YYCOPY
-#  if defined __GNUC__ && 1 < __GNUC__
-#   define YYCOPY(To, From, Count) \
-      __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
-#  else
-#   define YYCOPY(To, From, Count)		\
-      do					\
-	{					\
-	  YYSIZE_T yyi;				\
-	  for (yyi = 0; yyi < (Count); yyi++)	\
-	    (To)[yyi] = (From)[yyi];		\
-	}					\
-      while (YYID (0))
-#  endif
-# endif
-
-/* Relocate STACK from its old location to the new one.  The
-   local variables YYSIZE and YYSTACKSIZE give the old and new number of
-   elements in the stack, and YYPTR gives the new location of the
-   stack.  Advance YYPTR to a properly aligned location for the next
-   stack.  */
-# define YYSTACK_RELOCATE(Stack)					\
-    do									\
-      {									\
-	YYSIZE_T yynewbytes;						\
-	YYCOPY (&yyptr->Stack, Stack, yysize);				\
-	Stack = &yyptr->Stack;						\
-	yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
-	yyptr += yynewbytes / sizeof (*yyptr);				\
-      }									\
-    while (YYID (0))
-
-#endif
-
-/* YYFINAL -- State number of the termination state.  */
-#define YYFINAL  2
-/* YYLAST -- Last index in YYTABLE.  */
-#define YYLAST   1188
-
-/* YYNTOKENS -- Number of terminals.  */
-#define YYNTOKENS  99
-/* YYNNTS -- Number of nonterminals.  */
-#define YYNNTS  75
-/* YYNRULES -- Number of rules.  */
-#define YYNRULES  247
-/* YYNRULES -- Number of states.  */
-#define YYNSTATES  417
-
-/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
-#define YYUNDEFTOK  2
-#define YYMAXUTOK   329
-
-#define YYTRANSLATE(YYX)						\
-  ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
-
-/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX.  */
-static const yytype_uint8 yytranslate[] =
-{
-       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,    97,     2,     2,     2,    35,    22,     2,
-      38,    93,    33,    31,     4,    32,    36,    34,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,    17,     3,
-      25,     5,    26,    16,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,    37,     2,    94,    21,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,    95,    20,    96,    98,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     1,     2,     6,     7,
-       8,     9,    10,    11,    12,    13,    14,    15,    18,    19,
-      23,    24,    27,    28,    29,    30,    39,    40,    41,    42,
-      43,    44,    45,    46,    47,    48,    49,    50,    51,    52,
-      53,    54,    55,    56,    57,    58,    59,    60,    61,    62,
-      63,    64,    65,    66,    67,    68,    69,    70,    71,    72,
-      73,    74,    75,    76,    77,    78,    79,    80,    81,    82,
-      83,    84,    85,    86,    87,    88,    89,    90,    91,    92
-};
-
-#if YYDEBUG
-/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
-   YYRHS.  */
-static const yytype_uint16 yyprhs[] =
-{
-       0,     0,     3,     4,     7,    10,    14,    15,    16,    23,
-      25,    26,    31,    35,    37,    41,    43,    47,    52,    57,
-      60,    64,    66,    67,    72,    76,    77,    82,    84,    88,
-      89,    94,    95,   101,   102,   104,   106,   110,   112,   116,
-     119,   120,   122,   125,   129,   131,   133,   138,   143,   146,
-     150,   154,   156,   160,   164,   167,   170,   173,   177,   179,
-     182,   184,   186,   189,   190,   192,   194,   197,   200,   204,
-     208,   212,   213,   216,   219,   221,   224,   228,   231,   234,
-     237,   239,   242,   244,   247,   250,   251,   254,   260,   268,
-     269,   280,   286,   294,   298,   304,   307,   310,   314,   320,
-     326,   332,   333,   335,   336,   338,   340,   342,   346,   348,
-     352,   356,   360,   364,   368,   372,   376,   380,   384,   388,
-     392,   396,   400,   404,   408,   412,   416,   420,   426,   430,
-     434,   438,   442,   446,   450,   454,   458,   462,   466,   470,
-     472,   478,   486,   488,   491,   494,   497,   500,   503,   506,
-     509,   512,   515,   518,   522,   528,   534,   539,   544,   548,
-     552,   555,   558,   560,   562,   564,   566,   568,   570,   572,
-     574,   576,   578,   580,   582,   585,   587,   590,   591,   593,
-     595,   599,   600,   605,   606,   608,   610,   612,   614,   617,
-     620,   624,   627,   631,   633,   635,   638,   639,   644,   647,
-     650,   651,   656,   659,   662,   663,   664,   672,   673,   679,
-     681,   683,   686,   687,   690,   692,   694,   696,   698,   701,
-     703,   705,   707,   711,   714,   718,   720,   722,   724,   726,
-     728,   730,   732,   734,   736,   738,   740,   742,   744,   746,
-     748,   750,   752,   754,   756,   758,   760,   762
-};
-
-/* YYRHS -- A `-1'-separated list of the rules' RHS.  */
-static const yytype_int16 yyrhs[] =
-{
-     100,     0,    -1,    -1,   100,   101,    -1,   152,     3,    -1,
-     152,   104,     3,    -1,    -1,    -1,   152,   106,   102,   111,
-     103,   129,    -1,   106,    -1,    -1,   106,   105,     5,   123,
-      -1,   104,     4,   104,    -1,   107,    -1,    33,   163,   106,
-      -1,   172,    -1,    38,   106,    93,    -1,   107,    38,   127,
-      93,    -1,   107,    37,   139,    94,    -1,   155,     3,    -1,
-     155,   109,     3,    -1,   106,    -1,    -1,   106,   110,     5,
-     123,    -1,   109,     4,   109,    -1,    -1,   111,   155,   112,
-       3,    -1,   106,    -1,   112,     4,   112,    -1,    -1,   154,
-     114,   116,     3,    -1,    -1,   113,   154,   115,   116,     3,
-      -1,    -1,   117,    -1,   118,    -1,   117,     4,   117,    -1,
-     106,    -1,   172,    17,   140,    -1,    17,   140,    -1,    -1,
-     120,    -1,    33,   163,    -1,    33,   163,   120,    -1,   121,
-      -1,   122,    -1,   121,    38,   127,    93,    -1,   121,    37,
-     139,    94,    -1,    38,    93,    -1,    37,   139,    94,    -1,
-      38,   120,    93,    -1,   142,    -1,    95,   126,    96,    -1,
-      37,   140,    94,    -1,    36,   173,    -1,   124,     5,    -1,
-     123,     4,    -1,   125,   123,     4,    -1,   124,    -1,   125,
-     124,    -1,   125,    -1,   123,    -1,   125,   123,    -1,    -1,
-     128,    -1,   171,    -1,   154,   119,    -1,   154,   106,    -1,
-      36,    36,    36,    -1,   128,     4,   128,    -1,    95,   130,
-      96,    -1,    -1,   130,   108,    -1,   130,   133,    -1,   132,
-      -1,   131,   132,    -1,    56,   142,    17,    -1,    59,    17,
-      -1,    42,    17,    -1,     1,     3,    -1,   135,    -1,   131,
-     135,    -1,   138,    -1,   155,   109,    -1,   138,     3,    -1,
-      -1,   136,   129,    -1,    67,    38,   141,    93,   133,    -1,
-      67,    38,   141,    93,   133,    62,   133,    -1,    -1,   137,
-      65,    38,   134,     3,   138,     3,   138,    93,   133,    -1,
-      83,    38,   141,    93,   133,    -1,    60,   133,    83,    38,
-     141,    93,     3,    -1,    72,   138,     3,    -1,    78,    38,
-     141,    93,   133,    -1,    55,     3,    -1,    58,     3,    -1,
-      66,   173,     3,    -1,    75,    38,   148,    93,     3,    -1,
-      70,    38,   148,    93,     3,    -1,    89,    38,   148,    93,
-       3,    -1,    -1,   141,    -1,    -1,   140,    -1,   142,    -1,
-     142,    -1,   141,     4,   141,    -1,   143,    -1,   142,    33,
-     142,    -1,   142,    34,   142,    -1,   142,    35,   142,    -1,
-     142,    31,   142,    -1,   142,    32,   142,    -1,   142,    29,
-     142,    -1,   142,    30,   142,    -1,   142,    25,   142,    -1,
-     142,    26,   142,    -1,   142,    28,   142,    -1,   142,    27,
-     142,    -1,   142,    24,   142,    -1,   142,    23,   142,    -1,
-     142,    22,   142,    -1,   142,    21,   142,    -1,   142,    20,
-     142,    -1,   142,    19,   142,    -1,   142,    18,   142,    -1,
-     142,    16,   141,    17,   142,    -1,   142,     5,   142,    -1,
-     142,    15,   142,    -1,   142,    14,   142,    -1,   142,    13,
-     142,    -1,   142,    12,   142,    -1,   142,    11,   142,    -1,
-     142,     9,   142,    -1,   142,    10,   142,    -1,   142,     8,
-     142,    -1,   142,     7,   142,    -1,   142,     6,   142,    -1,
-     144,    -1,    38,   154,   119,    93,   143,    -1,    38,   154,
-     119,    93,    95,   126,    96,    -1,   145,    -1,    33,   143,
-      -1,    22,   143,    -1,    31,   143,    -1,    32,   143,    -1,
-      97,   143,    -1,    98,   143,    -1,    40,   143,    -1,    41,
-     143,    -1,    74,   144,    -1,    90,   144,    -1,    38,   141,
-      93,    -1,    74,    38,   154,   119,    93,    -1,    90,    38,
-     154,   119,    93,    -1,   145,    38,   148,    93,    -1,   145,
-      37,   141,    94,    -1,   145,    39,   173,    -1,   145,    36,
-     173,    -1,   145,    40,    -1,   145,    41,    -1,   171,    -1,
-      46,    -1,    47,    -1,    48,    -1,    49,    -1,    45,    -1,
-      44,    -1,    50,    -1,    51,    -1,   146,    -1,   147,    -1,
-      52,    -1,   146,    52,    -1,    53,    -1,   147,    53,    -1,
-      -1,   149,    -1,   142,    -1,   149,     4,   149,    -1,    -1,
-      95,   151,   113,    96,    -1,    -1,   155,    -1,   156,    -1,
-     168,    -1,   165,    -1,   156,   162,    -1,   168,   162,    -1,
-     165,   156,   163,    -1,   165,   168,    -1,   165,   168,   162,
-      -1,   153,    -1,   153,    -1,    77,   173,    -1,    -1,    77,
-     173,   157,   150,    -1,    77,   150,    -1,    81,   173,    -1,
-      -1,    81,   173,   158,   150,    -1,    81,   150,    -1,    85,
-     173,    -1,    -1,    -1,    85,   173,   159,    95,   160,   167,
-      96,    -1,    -1,    85,    95,   161,   167,    96,    -1,    43,
-      -1,   164,    -1,   162,   164,    -1,    -1,   163,   170,    -1,
-     168,    -1,   170,    -1,   169,    -1,   166,    -1,   165,   166,
-      -1,   170,    -1,   169,    -1,    42,    -1,    42,     5,   142,
-      -1,   167,     4,    -1,   167,     4,   167,    -1,    57,    -1,
-      73,    -1,    68,    -1,    69,    -1,    86,    -1,    82,    -1,
-      64,    -1,    61,    -1,    84,    -1,    54,    -1,    76,    -1,
-      63,    -1,    79,    -1,    80,    -1,    71,    -1,    92,    -1,
-      87,    -1,    88,    -1,    91,    -1,    42,    -1,   173,    -1,
-      42,    -1,    43,    -1
-};
-
-/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
-static const yytype_uint16 yyrline[] =
-{
-       0,   101,   101,   102,   108,   112,   114,   128,   113,   143,
-     148,   147,   155,   158,   159,   166,   167,   171,   175,   184,
-     188,   194,   200,   199,   211,   224,   225,   228,   232,   239,
-     238,   244,   243,   250,   254,   257,   261,   264,   269,   273,
-     282,   285,   288,   293,   298,   301,   302,   306,   312,   316,
-     320,   326,   327,   333,   337,   342,   345,   346,   350,   351,
-     357,   358,   359,   365,   368,   375,   376,   381,   386,   390,
-     396,   406,   409,   413,   419,   420,   426,   430,   434,   440,
-     444,   445,   451,   452,   458,   459,   459,   470,   476,   484,
-     484,   495,   499,   503,   508,   522,   526,   530,   534,   538,
-     542,   548,   551,   554,   557,   560,   567,   568,   574,   575,
-     579,   583,   587,   591,   595,   599,   603,   607,   611,   615,
-     619,   623,   627,   631,   635,   639,   643,   647,   651,   655,
-     659,   663,   667,   671,   675,   679,   683,   687,   691,   697,
-     698,   705,   713,   714,   718,   722,   726,   730,   734,   738,
-     742,   746,   750,   756,   760,   766,   772,   780,   784,   789,
-     794,   798,   802,   803,   810,   817,   824,   831,   838,   845,
-     852,   859,   860,   863,   873,   891,   901,   919,   922,   925,
-     926,   933,   932,   955,   959,   962,   967,   972,   978,   986,
-     992,   998,  1004,  1012,  1020,  1027,  1033,  1032,  1044,  1053,
-    1059,  1058,  1070,  1078,  1087,  1091,  1086,  1108,  1107,  1116,
-    1122,  1123,  1129,  1132,  1138,  1139,  1140,  1143,  1144,  1150,
-    1151,  1154,  1158,  1162,  1163,  1166,  1167,  1168,  1169,  1170,
-    1171,  1172,  1173,  1174,  1177,  1178,  1179,  1180,  1181,  1182,
-    1183,  1186,  1187,  1188,  1191,  1206,  1218,  1219
-};
-#endif
-
-#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
-/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
-   First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
-static const char *const yytname[] =
-{
-  "$end", "error", "$undefined", "';'", "','", "'='", "LORE", "LXORE",
-  "LANDE", "LLSHE", "LRSHE", "LMDE", "LDVE", "LMLE", "LME", "LPE", "'?'",
-  "':'", "LOROR", "LANDAND", "'|'", "'^'", "'&'", "LNE", "LEQ", "'<'",
-  "'>'", "LGE", "LLE", "LRSH", "LLSH", "'+'", "'-'", "'*'", "'/'", "'%'",
-  "'.'", "'['", "'('", "LMG", "LPP", "LMM", "LNAME", "LTYPE", "LFCONST",
-  "LDCONST", "LCONST", "LLCONST", "LUCONST", "LULCONST", "LVLCONST",
-  "LUVLCONST", "LSTRING", "LLSTRING", "LAUTO", "LBREAK", "LCASE", "LCHAR",
-  "LCONTINUE", "LDEFAULT", "LDO", "LDOUBLE", "LELSE", "LEXTERN", "LFLOAT",
-  "LFOR", "LGOTO", "LIF", "LINT", "LLONG", "LPREFETCH", "LREGISTER",
-  "LRETURN", "LSHORT", "LSIZEOF", "LUSED", "LSTATIC", "LSTRUCT", "LSWITCH",
-  "LTYPEDEF", "LTYPESTR", "LUNION", "LUNSIGNED", "LWHILE", "LVOID",
-  "LENUM", "LSIGNED", "LCONSTNT", "LVOLATILE", "LSET", "LSIGNOF",
-  "LRESTRICT", "LINLINE", "')'", "']'", "'{'", "'}'", "'!'", "'~'",
-  "$accept", "prog", "xdecl", "@1", "@2", "xdlist", "@3", "xdecor",
-  "xdecor2", "adecl", "adlist", "@4", "pdecl", "pdlist", "edecl", "@5",
-  "@6", "zedlist", "edlist", "edecor", "abdecor", "abdecor1", "abdecor2",
-  "abdecor3", "init", "qual", "qlist", "ilist", "zarglist", "arglist",
-  "block", "slist", "labels", "label", "stmnt", "forexpr", "ulstmnt", "@7",
-  "@8", "zcexpr", "zexpr", "lexpr", "cexpr", "expr", "xuexpr", "uexpr",
-  "pexpr", "string", "lstring", "zelist", "elist", "sbody", "@9",
-  "zctlist", "types", "tlist", "ctlist", "complex", "@10", "@11", "@12",
-  "@13", "@14", "gctnlist", "zgnlist", "gctname", "gcnlist", "gcname",
-  "enum", "tname", "cname", "gname", "name", "tag", "ltag", 0
-};
-#endif
-
-# ifdef YYPRINT
-/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
-   token YYLEX-NUM.  */
-static const yytype_uint16 yytoknum[] =
-{
-       0,   256,   257,    59,    44,    61,   258,   259,   260,   261,
-     262,   263,   264,   265,   266,   267,    63,    58,   268,   269,
-     124,    94,    38,   270,   271,    60,    62,   272,   273,   274,
-     275,    43,    45,    42,    47,    37,    46,    91,    40,   276,
-     277,   278,   279,   280,   281,   282,   283,   284,   285,   286,
-     287,   288,   289,   290,   291,   292,   293,   294,   295,   296,
-     297,   298,   299,   300,   301,   302,   303,   304,   305,   306,
-     307,   308,   309,   310,   311,   312,   313,   314,   315,   316,
-     317,   318,   319,   320,   321,   322,   323,   324,   325,   326,
-     327,   328,   329,    41,    93,   123,   125,    33,   126
-};
-# endif
-
-/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
-static const yytype_uint8 yyr1[] =
-{
-       0,    99,   100,   100,   101,   101,   102,   103,   101,   104,
-     105,   104,   104,   106,   106,   107,   107,   107,   107,   108,
-     108,   109,   110,   109,   109,   111,   111,   112,   112,   114,
-     113,   115,   113,   116,   116,   117,   117,   118,   118,   118,
-     119,   119,   120,   120,   120,   121,   121,   121,   122,   122,
-     122,   123,   123,   124,   124,   124,   125,   125,   125,   125,
-     126,   126,   126,   127,   127,   128,   128,   128,   128,   128,
-     129,   130,   130,   130,   131,   131,   132,   132,   132,   133,
-     133,   133,   134,   134,   135,   136,   135,   135,   135,   137,
-     135,   135,   135,   135,   135,   135,   135,   135,   135,   135,
-     135,   138,   138,   139,   139,   140,   141,   141,   142,   142,
-     142,   142,   142,   142,   142,   142,   142,   142,   142,   142,
-     142,   142,   142,   142,   142,   142,   142,   142,   142,   142,
-     142,   142,   142,   142,   142,   142,   142,   142,   142,   143,
-     143,   143,   144,   144,   144,   144,   144,   144,   144,   144,
-     144,   144,   144,   145,   145,   145,   145,   145,   145,   145,
-     145,   145,   145,   145,   145,   145,   145,   145,   145,   145,
-     145,   145,   145,   146,   146,   147,   147,   148,   148,   149,
-     149,   151,   150,   152,   152,   153,   153,   153,   153,   153,
-     153,   153,   153,   154,   155,   156,   157,   156,   156,   156,
-     158,   156,   156,   156,   159,   160,   156,   161,   156,   156,
-     162,   162,   163,   163,   164,   164,   164,   165,   165,   166,
-     166,   167,   167,   167,   167,   168,   168,   168,   168,   168,
-     168,   168,   168,   168,   169,   169,   169,   169,   169,   169,
-     169,   170,   170,   170,   171,   172,   173,   173
-};
-
-/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
-static const yytype_uint8 yyr2[] =
-{
-       0,     2,     0,     2,     2,     3,     0,     0,     6,     1,
-       0,     4,     3,     1,     3,     1,     3,     4,     4,     2,
-       3,     1,     0,     4,     3,     0,     4,     1,     3,     0,
-       4,     0,     5,     0,     1,     1,     3,     1,     3,     2,
-       0,     1,     2,     3,     1,     1,     4,     4,     2,     3,
-       3,     1,     3,     3,     2,     2,     2,     3,     1,     2,
-       1,     1,     2,     0,     1,     1,     2,     2,     3,     3,
-       3,     0,     2,     2,     1,     2,     3,     2,     2,     2,
-       1,     2,     1,     2,     2,     0,     2,     5,     7,     0,
-      10,     5,     7,     3,     5,     2,     2,     3,     5,     5,
-       5,     0,     1,     0,     1,     1,     1,     3,     1,     3,
-       3,     3,     3,     3,     3,     3,     3,     3,     3,     3,
-       3,     3,     3,     3,     3,     3,     3,     5,     3,     3,
-       3,     3,     3,     3,     3,     3,     3,     3,     3,     1,
-       5,     7,     1,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     3,     5,     5,     4,     4,     3,     3,
-       2,     2,     1,     1,     1,     1,     1,     1,     1,     1,
-       1,     1,     1,     1,     2,     1,     2,     0,     1,     1,
-       3,     0,     4,     0,     1,     1,     1,     1,     2,     2,
-       3,     2,     3,     1,     1,     2,     0,     4,     2,     2,
-       0,     4,     2,     2,     0,     0,     7,     0,     5,     1,
-       1,     2,     0,     2,     1,     1,     1,     1,     2,     1,
-       1,     1,     3,     2,     3,     1,     1,     1,     1,     1,
-       1,     1,     1,     1,     1,     1,     1,     1,     1,     1,
-       1,     1,     1,     1,     1,     1,     1,     1
-};
-
-/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
-   STATE-NUM when YYTABLE doesn't specify something else to do.  Zero
-   means the default is an error.  */
-static const yytype_uint8 yydefact[] =
-{
-       2,   183,     1,   209,   234,   225,   232,   236,   231,   227,
-     228,   239,   226,   235,     0,   237,   238,     0,   230,   233,
-       0,   229,   241,   242,   243,   240,     3,     0,   194,   184,
-     185,   187,   217,   186,   220,   219,   246,   247,   181,   198,
-     195,   202,   199,   207,   203,     4,   212,     0,     0,     6,
-      13,    15,   245,   188,   210,   214,   216,   215,   212,   218,
-     191,   189,     0,     0,     0,     0,     0,     0,     0,     5,
-       0,    25,     0,   103,    63,   211,   190,   192,     0,   193,
-      29,   197,   201,   221,     0,   205,    14,   213,    16,    12,
-       9,     7,     0,     0,     0,     0,     0,     0,     0,     0,
-     244,   168,   167,   163,   164,   165,   166,   169,   170,   173,
-     175,     0,     0,     0,     0,     0,   104,   105,   108,   139,
-     142,   171,   172,   162,     0,     0,    64,    40,    65,   182,
-      31,    33,     0,   223,   208,     0,     0,     0,     0,    11,
-      51,   144,   145,   146,   143,     0,   106,    40,   149,   150,
-       0,   151,     0,   152,   147,   148,    18,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,     0,   177,
-       0,   160,   161,   174,   176,     0,    17,     0,   212,   103,
-       0,    67,    66,    41,    44,    45,    33,     0,    37,     0,
-      34,    35,    15,   222,   224,     0,    71,     8,    27,     0,
-       0,     0,    61,    58,    60,     0,     0,   153,   212,     0,
-       0,    40,    40,   128,   138,   137,   136,   134,   135,   133,
-     132,   131,   130,   129,     0,   126,   125,   124,   123,   122,
-     121,   120,   116,   117,   119,   118,   114,   115,   112,   113,
-     109,   110,   111,   159,     0,   179,     0,   178,   158,    68,
-      69,    42,     0,    48,     0,   103,    63,     0,    39,    30,
-       0,     0,   206,     0,    26,     0,    54,     0,    56,    55,
-      62,    59,    52,   107,    42,     0,     0,     0,     0,   157,
-     156,     0,    43,    49,    50,     0,     0,    32,    36,    38,
-       0,   244,     0,     0,     0,     0,     0,     0,     0,     0,
-     101,     0,     0,     0,     0,    70,    72,    85,    74,    73,
-      80,     0,     0,     0,   102,     0,    28,    53,    57,     0,
-     140,   154,   155,   127,   180,    47,    46,    79,    78,    95,
-       0,    96,    77,     0,     0,     0,   177,     0,   177,     0,
-       0,   177,    75,    81,    86,     0,    84,    19,    21,     0,
-       0,    76,     0,    97,     0,     0,    93,     0,     0,     0,
-       0,   101,     0,    20,     0,   141,     0,     0,     0,     0,
-       0,     0,     0,     0,    82,     0,     0,    24,     0,    87,
-      99,    98,    94,    91,   100,   101,    83,    23,     0,     0,
-       0,    92,    88,   101,     0,     0,    90
-};
-
-/* YYDEFGOTO[NTERM-NUM].  */
-static const yytype_int16 yydefgoto[] =
-{
-      -1,     1,    26,    71,   136,    48,    72,   208,    50,   326,
-     369,   382,    91,   219,    78,   131,   206,   209,   210,   211,
-     202,   203,   204,   205,   222,   223,   224,   225,   125,   126,
-     217,   283,   327,   328,   329,   393,   330,   331,   332,   333,
-     115,   116,   334,   146,   118,   119,   120,   121,   122,   266,
-     267,    39,    62,    27,    79,   127,    29,    30,    63,    64,
-      66,   135,    65,    53,    67,    54,    31,    32,    84,    33,
-      34,    35,   123,    51,    52
-};
-
-/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
-   STATE-NUM.  */
-#define YYPACT_NINF -331
-static const yytype_int16 yypact[] =
-{
-    -331,   548,  -331,  -331,  -331,  -331,  -331,  -331,  -331,  -331,
-    -331,  -331,  -331,  -331,    -3,  -331,  -331,    -3,  -331,  -331,
-     149,  -331,  -331,  -331,  -331,  -331,  -331,   264,  -331,  -331,
-     965,   929,  -331,   965,  -331,  -331,  -331,  -331,  -331,  -331,
-     -75,  -331,   -72,  -331,   -60,  -331,  -331,   307,    60,   270,
-     156,  -331,  -331,   965,  -331,  -331,  -331,  -331,  -331,  -331,
-     965,   965,   929,   -44,   -44,    29,   -15,   199,   -10,  -331,
-     307,  -331,    83,   756,   849,  -331,   140,   965,   889,  -331,
-    -331,  -331,  -331,    86,    12,  -331,  -331,  -331,  -331,  -331,
-      90,   929,   686,   756,   756,   756,   756,   615,   756,   756,
-    -331,  -331,  -331,  -331,  -331,  -331,  -331,  -331,  -331,  -331,
-    -331,   791,   826,   756,   756,     9,  -331,  1084,  -331,  -331,
-     708,    54,    57,  -331,   110,    56,   152,   310,  -331,  -331,
-    -331,   279,   756,    29,  -331,    29,    63,   307,   165,  -331,
-    1084,  -331,  -331,  -331,  -331,    30,  1084,    44,  -331,  -331,
-     615,  -331,   615,  -331,  -331,  -331,  -331,   756,   756,   756,
-     756,   756,   756,   756,   756,   756,   756,   756,   756,   756,
-     756,   756,   756,   756,   756,   756,   756,   756,   756,   756,
-     756,   756,   756,   756,   756,   756,   756,   157,   756,   756,
-     157,  -331,  -331,  -331,  -331,   115,  -331,   849,  -331,   756,
-     128,  -331,  -331,  -331,   182,  -331,   279,   756,  -331,   164,
-     200,  -331,   208,  1084,  -331,    13,  -331,  -331,  -331,   262,
-     157,   756,   225,   228,   165,    73,   756,  -331,  -331,    -7,
-     150,    44,    44,  1084,  1084,  1084,  1084,  1084,  1084,  1084,
-    1084,  1084,  1084,  1084,    28,   304,  1100,  1115,  1129,  1142,
-    1153,  1153,   433,   433,   433,   433,   333,   333,   265,   265,
-    -331,  -331,  -331,  -331,     8,  1084,   153,   236,  -331,  -331,
-    -331,   147,   158,  -331,   161,   756,   849,   247,  -331,  -331,
-     279,   756,  -331,   341,  -331,   307,  -331,   175,  -331,  -331,
-     254,   228,  -331,  -331,   135,   721,   188,   190,   756,  -331,
-    -331,   756,  -331,  -331,  -331,   191,   211,  -331,  -331,  -331,
-     298,   301,   338,   756,   343,   339,   439,   157,   319,   321,
-     756,   322,   323,   324,   332,  -331,  -331,   509,  -331,  -331,
-    -331,    63,   306,   372,   373,   277,  -331,  -331,  -331,   165,
-    -331,  -331,  -331,   425,  -331,  -331,  -331,  -331,  -331,  -331,
-    1053,  -331,  -331,   293,   375,   756,   756,   400,   756,   756,
-     756,   756,  -331,  -331,  -331,   396,  -331,  -331,   430,   285,
-     377,  -331,   431,  -331,    55,   381,  -331,   382,    62,    64,
-     383,   615,   473,  -331,   307,  -331,   756,   439,   479,   490,
-     439,   439,   493,   497,  -331,   307,   686,  -331,    66,   440,
-    -331,  -331,  -331,  -331,  -331,   756,   499,  -331,   498,   439,
-     504,  -331,  -331,   756,   415,   439,  -331
-};
-
-/* YYPGOTO[NTERM-NUM].  */
-static const yytype_int16 yypgoto[] =
-{
-    -331,  -331,  -331,  -331,  -331,   445,  -331,   -26,  -331,  -331,
-    -330,  -331,  -331,   233,  -331,  -331,  -331,   313,   230,  -331,
-    -132,  -187,  -331,  -331,   -82,   292,  -331,   181,   245,   326,
-     193,  -331,  -331,   198,  -227,  -331,   203,  -331,  -331,  -309,
-    -181,  -183,   -83,   -45,   -38,   243,  -331,  -331,  -331,  -175,
-     226,    10,  -331,  -331,    -1,     0,   -88,   495,  -331,  -331,
-    -331,  -331,  -331,   -14,   -51,   -28,  -331,   501,   -85,   218,
-     231,   -24,   -52,  -127,   -12
-};
-
-/* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
-   positive, shift that token.  If negative, reduce the rule which
-   number is the opposite.  If zero, do what YYDEFACT says.
-   If YYTABLE_NINF, syntax error.  */
-#define YYTABLE_NINF -205
-static const yytype_int16 yytable[] =
-{
-      28,    49,    40,   137,   212,    42,    57,    76,    44,    57,
-     139,   357,   226,   274,   145,   230,   133,   133,   272,    61,
-    -196,    68,   128,  -200,   278,    75,   228,    41,   117,    57,
-     199,   229,   226,    75,   226,  -204,    57,    57,   287,    36,
-      37,    86,   274,    87,    90,   298,    77,   140,   214,    75,
-     215,    38,    87,    57,   397,   141,   142,   143,   144,   226,
-     148,   149,    80,    69,    70,   406,   226,   145,   226,   145,
-     226,    83,   394,    81,    82,   154,   155,   228,   130,   212,
-      85,   199,   229,    88,   302,   244,   273,   213,    92,   353,
-      28,   132,    38,   140,   305,   -10,   410,   147,   309,   296,
-     297,   201,   299,   156,   414,   264,   193,   302,   134,   282,
-     194,   218,   233,   234,   235,   236,   237,   238,   239,   240,
-     241,   242,   243,   227,   245,   246,   247,   248,   249,   250,
-     251,   252,   253,   254,   255,   256,   257,   258,   259,   260,
-     261,   262,   290,   293,   265,   128,   195,   271,   387,   196,
-     231,   269,   232,   212,   117,   390,   197,   391,   216,   408,
-     399,   198,   117,   402,   403,   199,   200,   279,   228,   292,
-      36,    37,   199,   229,    68,   263,   117,   294,   268,   140,
-     198,   375,   412,   377,   199,   200,   380,    93,   416,    36,
-      37,    36,    37,    73,    74,   335,    94,    95,    96,    36,
-      37,   220,   221,    97,   280,    98,    99,   100,   286,   101,
-     102,   103,   104,   105,   106,   107,   108,   109,   110,   275,
-     276,   273,    22,    23,   128,   281,    24,    22,    23,   288,
-     117,    24,    46,   289,    22,    23,   117,    47,    24,   111,
-     301,    36,    37,   295,    43,    86,   300,    87,    55,    60,
-     307,    55,   303,   343,   304,   112,   265,   340,   338,   218,
-     138,    56,   113,   114,    56,   284,   285,    45,   350,   337,
-      87,    55,   374,    -9,    -9,   -10,   378,   379,    55,    55,
-     367,   341,    28,   342,    56,   345,    22,    23,   383,   384,
-      24,    56,    56,   395,   140,    55,   207,    46,   184,   185,
-     186,   347,    47,   398,   346,   354,    36,    37,    56,   368,
-      46,   265,    46,   265,   407,    47,   265,    47,   348,    36,
-      37,    36,    37,   170,   171,   172,   173,   174,   175,   176,
-     177,   178,   179,   180,   181,   182,   183,   184,   185,   186,
-      46,   349,   310,   198,  -101,    47,   351,   199,   200,    36,
-      37,   140,    36,    37,   151,   153,   352,   355,   368,   356,
-     358,   359,   360,    93,   182,   183,   184,   185,   186,   368,
-     361,   365,    94,    95,    96,   366,   372,   226,   373,    97,
-      28,    98,    99,   311,     3,   101,   102,   103,   104,   105,
-     106,   107,   108,   109,   110,     4,   312,   313,     5,   314,
-     315,   316,     6,   376,     7,     8,   -89,   317,   318,     9,
-      10,   319,    11,   320,    12,   111,   321,    13,    14,   322,
-      15,    16,    17,    18,   323,    19,    20,    21,    22,    23,
-     324,   112,    24,    25,   381,   -22,   -85,   325,   113,   114,
-     310,   168,  -101,   169,   170,   171,   172,   173,   174,   175,
-     176,   177,   178,   179,   180,   181,   182,   183,   184,   185,
-     186,    93,   180,   181,   182,   183,   184,   185,   186,   386,
-      94,    95,    96,   385,   388,   389,   392,    97,   396,    98,
-      99,   311,   400,   101,   102,   103,   104,   105,   106,   107,
-     108,   109,   110,   401,   312,   313,   404,   314,   315,   316,
-     405,   411,   409,   384,   -89,   317,   318,   413,   415,   319,
-     308,   320,  -101,   111,   321,    89,   291,   322,   336,   277,
-     370,   306,   323,   270,   364,   362,    58,   344,   324,   112,
-     363,    93,    59,     0,   -85,     0,   113,   114,     0,     0,
-      94,    95,    96,     0,     0,     0,     0,    97,     2,    98,
-      99,   311,     0,   101,   102,   103,   104,   105,   106,   107,
-     108,   109,   110,     0,   312,   313,     0,   314,   315,   316,
-       0,     0,     0,     0,   -89,   317,   318,     0,     0,   319,
-       0,   320,     0,   111,   321,     0,     0,   322,     0,     0,
-       0,     3,   323,     0,     0,     0,     0,     0,   324,   112,
-       0,     0,     4,     0,     0,     5,   113,   114,     0,     6,
-       0,     7,     8,     0,     0,     0,     9,    10,     0,    11,
-       0,    12,     0,     0,    13,    14,     0,    15,    16,    17,
-      18,     0,    19,    20,    21,    22,    23,    93,     0,    24,
-      25,     0,     0,     0,     0,     0,    94,    95,    96,     0,
-       0,     0,     0,    97,     0,    98,    99,   100,     3,   101,
-     102,   103,   104,   105,   106,   107,   108,   109,   110,     4,
-       0,     0,     5,     0,     0,     0,     6,     0,     7,     8,
-       0,     0,     0,     9,    10,     0,    11,     0,    12,   111,
-       0,    13,    14,     0,    15,    16,    17,    18,     0,    19,
-      20,    21,    22,    23,     0,   112,    24,    25,    93,     0,
-       0,     0,   113,   114,     0,     0,     0,    94,    95,    96,
-       0,     0,     0,     0,    97,     0,    98,    99,   100,     0,
-     101,   102,   103,   104,   105,   106,   107,   108,   109,   110,
-       0,     0,     0,    93,   187,   188,   189,   190,   191,   192,
-       0,     0,    94,    95,    96,     0,     0,     0,     0,    97,
-     111,    98,    99,   100,     0,   101,   102,   103,   104,   105,
-     106,   107,   108,   109,   110,     0,   112,     0,    93,     0,
-       0,   138,     0,   113,   114,     0,     0,    94,    95,    96,
-       0,     0,     0,     0,    97,   111,    98,    99,   100,     0,
-     101,   102,   103,   104,   105,   106,   107,   108,   109,   110,
-       0,   112,     0,    93,     0,     0,   339,     0,   113,   114,
-       0,     0,    94,    95,    96,     0,     0,     0,     0,   150,
-     111,    98,    99,   100,     0,   101,   102,   103,   104,   105,
-     106,   107,   108,   109,   110,     0,   112,     0,    93,     0,
-       0,     0,     0,   113,   114,     0,     0,    94,    95,    96,
-       0,     0,     0,     0,   152,   111,    98,    99,   100,     0,
-     101,   102,   103,   104,   105,   106,   107,   108,   109,   110,
-       0,   112,     0,     0,     0,   124,     0,     0,   113,   114,
-       0,   100,     3,     0,     0,     0,     0,     0,     0,     0,
-     111,     0,     0,     4,     0,     0,     5,     0,     0,     0,
-       6,     0,     7,     8,     0,     0,   112,     9,    10,     0,
-      11,     0,    12,   113,   114,    13,    14,     0,    15,    16,
-      17,    18,     3,    19,    20,    21,    22,    23,     0,     0,
-      24,    25,     0,     4,     0,     0,     5,     0,     0,     0,
-       6,     0,     7,     8,     0,     0,     0,     9,    10,     0,
-      11,     0,    12,     0,     0,    13,    14,     0,    15,    16,
-      17,    18,     3,    19,    20,    21,    22,    23,     0,     0,
-      24,    25,     0,     4,     0,   129,     5,     0,     0,     0,
-       6,     0,     7,     8,     0,     0,     0,     9,    10,     0,
-      11,     0,    12,     0,     0,    13,    14,     0,    15,    16,
-      17,    18,     0,    19,    20,    21,    22,    23,     0,     4,
-      24,    25,     5,     0,     0,     0,     6,     0,     7,     8,
-       0,     0,     0,     9,    10,     0,    11,     0,    12,     0,
-       0,    13,     0,     0,    15,    16,     0,    18,     0,    19,
-       0,    21,    22,    23,     0,     0,    24,    25,   157,   158,
-     159,   160,   161,   162,   163,   164,   165,   166,   167,   168,
-     371,   169,   170,   171,   172,   173,   174,   175,   176,   177,
-     178,   179,   180,   181,   182,   183,   184,   185,   186,   157,
-     158,   159,   160,   161,   162,   163,   164,   165,   166,   167,
-     168,     0,   169,   170,   171,   172,   173,   174,   175,   176,
-     177,   178,   179,   180,   181,   182,   183,   184,   185,   186,
-     171,   172,   173,   174,   175,   176,   177,   178,   179,   180,
-     181,   182,   183,   184,   185,   186,   172,   173,   174,   175,
-     176,   177,   178,   179,   180,   181,   182,   183,   184,   185,
-     186,   173,   174,   175,   176,   177,   178,   179,   180,   181,
-     182,   183,   184,   185,   186,   174,   175,   176,   177,   178,
-     179,   180,   181,   182,   183,   184,   185,   186,   176,   177,
-     178,   179,   180,   181,   182,   183,   184,   185,   186
-};
-
-static const yytype_int16 yycheck[] =
-{
-       1,    27,    14,    91,   131,    17,    30,    58,    20,    33,
-      92,   320,     4,   200,    97,   147,     4,     4,   199,    33,
-      95,    47,    74,    95,   207,    53,    33,    17,    73,    53,
-      37,    38,     4,    61,     4,    95,    60,    61,   221,    42,
-      43,    67,   229,    67,    70,    17,    60,    92,   133,    77,
-     135,    95,    76,    77,   384,    93,    94,    95,    96,     4,
-      98,    99,    62,     3,     4,   395,     4,   150,     4,   152,
-       4,    42,   381,    63,    64,   113,   114,    33,    78,   206,
-      95,    37,    38,    93,   271,   168,    93,   132,     5,   316,
-      91,     5,    95,   138,   275,     5,   405,    97,   281,   231,
-     232,   127,    94,    94,   413,   188,    52,   294,    96,    96,
-      53,   137,   157,   158,   159,   160,   161,   162,   163,   164,
-     165,   166,   167,    93,   169,   170,   171,   172,   173,   174,
-     175,   176,   177,   178,   179,   180,   181,   182,   183,   184,
-     185,   186,   224,   226,   189,   197,    36,   198,    93,    93,
-     150,    36,   152,   280,   199,    93,     4,    93,    95,    93,
-     387,    33,   207,   390,   391,    37,    38,     3,    33,    96,
-      42,    43,    37,    38,   200,   187,   221,   228,   190,   224,
-      33,   356,   409,   358,    37,    38,   361,    22,   415,    42,
-      43,    42,    43,    37,    38,   283,    31,    32,    33,    42,
-      43,    36,    37,    38,     4,    40,    41,    42,   220,    44,
-      45,    46,    47,    48,    49,    50,    51,    52,    53,    37,
-      38,    93,    87,    88,   276,    17,    91,    87,    88,     4,
-     275,    91,    33,     5,    87,    88,   281,    38,    91,    74,
-       4,    42,    43,    93,    95,   271,    93,   271,    30,    31,
-       3,    33,    94,   298,    93,    90,   301,   295,     4,   285,
-      95,    30,    97,    98,    33,     3,     4,     3,   313,    94,
-     294,    53,   355,     3,     4,     5,   359,   360,    60,    61,
-       3,    93,   283,    93,    53,    94,    87,    88,     3,     4,
-      91,    60,    61,   381,   339,    77,    17,    33,    33,    34,
-      35,     3,    38,   386,    93,   317,    42,    43,    77,   335,
-      33,   356,    33,   358,   396,    38,   361,    38,    17,    42,
-      43,    42,    43,    19,    20,    21,    22,    23,    24,    25,
-      26,    27,    28,    29,    30,    31,    32,    33,    34,    35,
-      33,     3,     1,    33,     3,    38,     3,    37,    38,    42,
-      43,   396,    42,    43,   111,   112,    17,    38,   384,    38,
-      38,    38,    38,    22,    31,    32,    33,    34,    35,   395,
-      38,    65,    31,    32,    33,     3,    83,     4,     3,    38,
-     381,    40,    41,    42,    43,    44,    45,    46,    47,    48,
-      49,    50,    51,    52,    53,    54,    55,    56,    57,    58,
-      59,    60,    61,     3,    63,    64,    65,    66,    67,    68,
-      69,    70,    71,    72,    73,    74,    75,    76,    77,    78,
-      79,    80,    81,    82,    83,    84,    85,    86,    87,    88,
-      89,    90,    91,    92,    38,     5,    95,    96,    97,    98,
-       1,    16,     3,    18,    19,    20,    21,    22,    23,    24,
-      25,    26,    27,    28,    29,    30,    31,    32,    33,    34,
-      35,    22,    29,    30,    31,    32,    33,    34,    35,    38,
-      31,    32,    33,    96,    93,    93,    93,    38,     5,    40,
-      41,    42,     3,    44,    45,    46,    47,    48,    49,    50,
-      51,    52,    53,     3,    55,    56,     3,    58,    59,    60,
-       3,     3,    62,     4,    65,    66,    67,     3,    93,    70,
-     280,    72,     3,    74,    75,    70,   224,    78,   285,   206,
-     339,   276,    83,   197,   331,   327,    31,   301,    89,    90,
-     327,    22,    31,    -1,    95,    -1,    97,    98,    -1,    -1,
-      31,    32,    33,    -1,    -1,    -1,    -1,    38,     0,    40,
-      41,    42,    -1,    44,    45,    46,    47,    48,    49,    50,
-      51,    52,    53,    -1,    55,    56,    -1,    58,    59,    60,
-      -1,    -1,    -1,    -1,    65,    66,    67,    -1,    -1,    70,
-      -1,    72,    -1,    74,    75,    -1,    -1,    78,    -1,    -1,
-      -1,    43,    83,    -1,    -1,    -1,    -1,    -1,    89,    90,
-      -1,    -1,    54,    -1,    -1,    57,    97,    98,    -1,    61,
-      -1,    63,    64,    -1,    -1,    -1,    68,    69,    -1,    71,
-      -1,    73,    -1,    -1,    76,    77,    -1,    79,    80,    81,
-      82,    -1,    84,    85,    86,    87,    88,    22,    -1,    91,
-      92,    -1,    -1,    -1,    -1,    -1,    31,    32,    33,    -1,
-      -1,    -1,    -1,    38,    -1,    40,    41,    42,    43,    44,
-      45,    46,    47,    48,    49,    50,    51,    52,    53,    54,
-      -1,    -1,    57,    -1,    -1,    -1,    61,    -1,    63,    64,
-      -1,    -1,    -1,    68,    69,    -1,    71,    -1,    73,    74,
-      -1,    76,    77,    -1,    79,    80,    81,    82,    -1,    84,
-      85,    86,    87,    88,    -1,    90,    91,    92,    22,    -1,
-      -1,    -1,    97,    98,    -1,    -1,    -1,    31,    32,    33,
-      -1,    -1,    -1,    -1,    38,    -1,    40,    41,    42,    -1,
-      44,    45,    46,    47,    48,    49,    50,    51,    52,    53,
-      -1,    -1,    -1,    22,    36,    37,    38,    39,    40,    41,
-      -1,    -1,    31,    32,    33,    -1,    -1,    -1,    -1,    38,
-      74,    40,    41,    42,    -1,    44,    45,    46,    47,    48,
-      49,    50,    51,    52,    53,    -1,    90,    -1,    22,    -1,
-      -1,    95,    -1,    97,    98,    -1,    -1,    31,    32,    33,
-      -1,    -1,    -1,    -1,    38,    74,    40,    41,    42,    -1,
-      44,    45,    46,    47,    48,    49,    50,    51,    52,    53,
-      -1,    90,    -1,    22,    -1,    -1,    95,    -1,    97,    98,
-      -1,    -1,    31,    32,    33,    -1,    -1,    -1,    -1,    38,
-      74,    40,    41,    42,    -1,    44,    45,    46,    47,    48,
-      49,    50,    51,    52,    53,    -1,    90,    -1,    22,    -1,
-      -1,    -1,    -1,    97,    98,    -1,    -1,    31,    32,    33,
-      -1,    -1,    -1,    -1,    38,    74,    40,    41,    42,    -1,
-      44,    45,    46,    47,    48,    49,    50,    51,    52,    53,
-      -1,    90,    -1,    -1,    -1,    36,    -1,    -1,    97,    98,
-      -1,    42,    43,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      74,    -1,    -1,    54,    -1,    -1,    57,    -1,    -1,    -1,
-      61,    -1,    63,    64,    -1,    -1,    90,    68,    69,    -1,
-      71,    -1,    73,    97,    98,    76,    77,    -1,    79,    80,
-      81,    82,    43,    84,    85,    86,    87,    88,    -1,    -1,
-      91,    92,    -1,    54,    -1,    -1,    57,    -1,    -1,    -1,
-      61,    -1,    63,    64,    -1,    -1,    -1,    68,    69,    -1,
-      71,    -1,    73,    -1,    -1,    76,    77,    -1,    79,    80,
-      81,    82,    43,    84,    85,    86,    87,    88,    -1,    -1,
-      91,    92,    -1,    54,    -1,    96,    57,    -1,    -1,    -1,
-      61,    -1,    63,    64,    -1,    -1,    -1,    68,    69,    -1,
-      71,    -1,    73,    -1,    -1,    76,    77,    -1,    79,    80,
-      81,    82,    -1,    84,    85,    86,    87,    88,    -1,    54,
-      91,    92,    57,    -1,    -1,    -1,    61,    -1,    63,    64,
-      -1,    -1,    -1,    68,    69,    -1,    71,    -1,    73,    -1,
-      -1,    76,    -1,    -1,    79,    80,    -1,    82,    -1,    84,
-      -1,    86,    87,    88,    -1,    -1,    91,    92,     5,     6,
-       7,     8,     9,    10,    11,    12,    13,    14,    15,    16,
-      17,    18,    19,    20,    21,    22,    23,    24,    25,    26,
-      27,    28,    29,    30,    31,    32,    33,    34,    35,     5,
-       6,     7,     8,     9,    10,    11,    12,    13,    14,    15,
-      16,    -1,    18,    19,    20,    21,    22,    23,    24,    25,
-      26,    27,    28,    29,    30,    31,    32,    33,    34,    35,
-      20,    21,    22,    23,    24,    25,    26,    27,    28,    29,
-      30,    31,    32,    33,    34,    35,    21,    22,    23,    24,
-      25,    26,    27,    28,    29,    30,    31,    32,    33,    34,
-      35,    22,    23,    24,    25,    26,    27,    28,    29,    30,
-      31,    32,    33,    34,    35,    23,    24,    25,    26,    27,
-      28,    29,    30,    31,    32,    33,    34,    35,    25,    26,
-      27,    28,    29,    30,    31,    32,    33,    34,    35
-};
-
-/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
-   symbol of state STATE-NUM.  */
-static const yytype_uint8 yystos[] =
-{
-       0,   100,     0,    43,    54,    57,    61,    63,    64,    68,
-      69,    71,    73,    76,    77,    79,    80,    81,    82,    84,
-      85,    86,    87,    88,    91,    92,   101,   152,   153,   155,
-     156,   165,   166,   168,   169,   170,    42,    43,    95,   150,
-     173,   150,   173,    95,   173,     3,    33,    38,   104,   106,
-     107,   172,   173,   162,   164,   168,   169,   170,   156,   166,
-     168,   162,   151,   157,   158,   161,   159,   163,   106,     3,
-       4,   102,   105,    37,    38,   164,   163,   162,   113,   153,
-     154,   150,   150,    42,   167,    95,   106,   170,    93,   104,
-     106,   111,     5,    22,    31,    32,    33,    38,    40,    41,
-      42,    44,    45,    46,    47,    48,    49,    50,    51,    52,
-      53,    74,    90,    97,    98,   139,   140,   142,   143,   144,
-     145,   146,   147,   171,    36,   127,   128,   154,   171,    96,
-     154,   114,     5,     4,    96,   160,   103,   155,    95,   123,
-     142,   143,   143,   143,   143,   141,   142,   154,   143,   143,
-      38,   144,    38,   144,   143,   143,    94,     5,     6,     7,
-       8,     9,    10,    11,    12,    13,    14,    15,    16,    18,
-      19,    20,    21,    22,    23,    24,    25,    26,    27,    28,
-      29,    30,    31,    32,    33,    34,    35,    36,    37,    38,
-      39,    40,    41,    52,    53,    36,    93,     4,    33,    37,
-      38,   106,   119,   120,   121,   122,   115,    17,   106,   116,
-     117,   118,   172,   142,   167,   167,    95,   129,   106,   112,
-      36,    37,   123,   124,   125,   126,     4,    93,    33,    38,
-     119,   154,   154,   142,   142,   142,   142,   142,   142,   142,
-     142,   142,   142,   142,   141,   142,   142,   142,   142,   142,
-     142,   142,   142,   142,   142,   142,   142,   142,   142,   142,
-     142,   142,   142,   173,   141,   142,   148,   149,   173,    36,
-     128,   163,   139,    93,   120,    37,    38,   116,   140,     3,
-       4,    17,    96,   130,     3,     4,   173,   140,     4,     5,
-     123,   124,    96,   141,   163,    93,   119,   119,    17,    94,
-      93,     4,   120,    94,    93,   139,   127,     3,   117,   140,
-       1,    42,    55,    56,    58,    59,    60,    66,    67,    70,
-      72,    75,    78,    83,    89,    96,   108,   131,   132,   133,
-     135,   136,   137,   138,   141,   155,   112,    94,     4,    95,
-     143,    93,    93,   142,   149,    94,    93,     3,    17,     3,
-     142,     3,    17,   133,   173,    38,    38,   138,    38,    38,
-      38,    38,   132,   135,   129,    65,     3,     3,   106,   109,
-     126,    17,    83,     3,   141,   148,     3,   148,   141,   141,
-     148,    38,   110,     3,     4,    96,    38,    93,    93,    93,
-      93,    93,    93,   134,   138,   155,     5,   109,   141,   133,
-       3,     3,   133,   133,     3,     3,   109,   123,    93,    62,
-     138,     3,   133,     3,   138,    93,   133
-};
-
-#define yyerrok		(yyerrstatus = 0)
-#define yyclearin	(yychar = YYEMPTY)
-#define YYEMPTY		(-2)
-#define YYEOF		0
-
-#define YYACCEPT	goto yyacceptlab
-#define YYABORT		goto yyabortlab
-#define YYERROR		goto yyerrorlab
-
-
-/* Like YYERROR except do call yyerror.  This remains here temporarily
-   to ease the transition to the new meaning of YYERROR, for GCC.
-   Once GCC version 2 has supplanted version 1, this can go.  */
-
-#define YYFAIL		goto yyerrlab
-
-#define YYRECOVERING()  (!!yyerrstatus)
-
-#define YYBACKUP(Token, Value)					\
-do								\
-  if (yychar == YYEMPTY && yylen == 1)				\
-    {								\
-      yychar = (Token);						\
-      yylval = (Value);						\
-      yytoken = YYTRANSLATE (yychar);				\
-      YYPOPSTACK (1);						\
-      goto yybackup;						\
-    }								\
-  else								\
-    {								\
-      yyerror (YY_("syntax error: cannot back up")); \
-      YYERROR;							\
-    }								\
-while (YYID (0))
-
-
-#define YYTERROR	1
-#define YYERRCODE	256
-
-
-/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
-   If N is 0, then set CURRENT to the empty location which ends
-   the previous symbol: RHS[0] (always defined).  */
-
-#define YYRHSLOC(Rhs, K) ((Rhs)[K])
-#ifndef YYLLOC_DEFAULT
-# define YYLLOC_DEFAULT(Current, Rhs, N)				\
-    do									\
-      if (YYID (N))                                                    \
-	{								\
-	  (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;	\
-	  (Current).first_column = YYRHSLOC (Rhs, 1).first_column;	\
-	  (Current).last_line    = YYRHSLOC (Rhs, N).last_line;		\
-	  (Current).last_column  = YYRHSLOC (Rhs, N).last_column;	\
-	}								\
-      else								\
-	{								\
-	  (Current).first_line   = (Current).last_line   =		\
-	    YYRHSLOC (Rhs, 0).last_line;				\
-	  (Current).first_column = (Current).last_column =		\
-	    YYRHSLOC (Rhs, 0).last_column;				\
-	}								\
-    while (YYID (0))
-#endif
-
-
-/* YY_LOCATION_PRINT -- Print the location on the stream.
-   This macro was not mandated originally: define only if we know
-   we won't break user code: when these are the locations we know.  */
-
-#ifndef YY_LOCATION_PRINT
-# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
-#  define YY_LOCATION_PRINT(File, Loc)			\
-     fprintf (File, "%d.%d-%d.%d",			\
-	      (Loc).first_line, (Loc).first_column,	\
-	      (Loc).last_line,  (Loc).last_column)
-# else
-#  define YY_LOCATION_PRINT(File, Loc) ((void) 0)
-# endif
-#endif
-
-
-/* YYLEX -- calling `yylex' with the right arguments.  */
-
-#ifdef YYLEX_PARAM
-# define YYLEX yylex (YYLEX_PARAM)
-#else
-# define YYLEX yylex ()
-#endif
-
-/* Enable debugging if requested.  */
-#if YYDEBUG
-
-# ifndef YYFPRINTF
-#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
-#  define YYFPRINTF fprintf
-# endif
-
-# define YYDPRINTF(Args)			\
-do {						\
-  if (yydebug)					\
-    YYFPRINTF Args;				\
-} while (YYID (0))
-
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location)			  \
-do {									  \
-  if (yydebug)								  \
-    {									  \
-      YYFPRINTF (stderr, "%s ", Title);					  \
-      yy_symbol_print (stderr,						  \
-		  Type, Value); \
-      YYFPRINTF (stderr, "\n");						  \
-    }									  \
-} while (YYID (0))
-
-
-/*--------------------------------.
-| Print this symbol on YYOUTPUT.  |
-`--------------------------------*/
-
-/*ARGSUSED*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static void
-yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
-#else
-static void
-yy_symbol_value_print (yyoutput, yytype, yyvaluep)
-    FILE *yyoutput;
-    int yytype;
-    YYSTYPE const * const yyvaluep;
-#endif
-{
-  if (!yyvaluep)
-    return;
-# ifdef YYPRINT
-  if (yytype < YYNTOKENS)
-    YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
-# else
-  YYUSE (yyoutput);
-# endif
-  switch (yytype)
-    {
-      default:
-	break;
-    }
-}
-
-
-/*--------------------------------.
-| Print this symbol on YYOUTPUT.  |
-`--------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static void
-yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
-#else
-static void
-yy_symbol_print (yyoutput, yytype, yyvaluep)
-    FILE *yyoutput;
-    int yytype;
-    YYSTYPE const * const yyvaluep;
-#endif
-{
-  if (yytype < YYNTOKENS)
-    YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
-  else
-    YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
-
-  yy_symbol_value_print (yyoutput, yytype, yyvaluep);
-  YYFPRINTF (yyoutput, ")");
-}
-
-/*------------------------------------------------------------------.
-| yy_stack_print -- Print the state stack from its BOTTOM up to its |
-| TOP (included).                                                   |
-`------------------------------------------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static void
-yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
-#else
-static void
-yy_stack_print (bottom, top)
-    yytype_int16 *bottom;
-    yytype_int16 *top;
-#endif
-{
-  YYFPRINTF (stderr, "Stack now");
-  for (; bottom <= top; ++bottom)
-    YYFPRINTF (stderr, " %d", *bottom);
-  YYFPRINTF (stderr, "\n");
-}
-
-# define YY_STACK_PRINT(Bottom, Top)				\
-do {								\
-  if (yydebug)							\
-    yy_stack_print ((Bottom), (Top));				\
-} while (YYID (0))
-
-
-/*------------------------------------------------.
-| Report that the YYRULE is going to be reduced.  |
-`------------------------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static void
-yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
-#else
-static void
-yy_reduce_print (yyvsp, yyrule)
-    YYSTYPE *yyvsp;
-    int yyrule;
-#endif
-{
-  int yynrhs = yyr2[yyrule];
-  int yyi;
-  unsigned long int yylno = yyrline[yyrule];
-  YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
-	     yyrule - 1, yylno);
-  /* The symbols being reduced.  */
-  for (yyi = 0; yyi < yynrhs; yyi++)
-    {
-      fprintf (stderr, "   $%d = ", yyi + 1);
-      yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
-		       &(yyvsp[(yyi + 1) - (yynrhs)])
-		       		       );
-      fprintf (stderr, "\n");
-    }
-}
-
-# define YY_REDUCE_PRINT(Rule)		\
-do {					\
-  if (yydebug)				\
-    yy_reduce_print (yyvsp, Rule); \
-} while (YYID (0))
-
-/* Nonzero means print parse trace.  It is left uninitialized so that
-   multiple parsers can coexist.  */
-int yydebug;
-#else /* !YYDEBUG */
-# define YYDPRINTF(Args)
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
-# define YY_STACK_PRINT(Bottom, Top)
-# define YY_REDUCE_PRINT(Rule)
-#endif /* !YYDEBUG */
-
-
-/* YYINITDEPTH -- initial size of the parser's stacks.  */
-#ifndef	YYINITDEPTH
-# define YYINITDEPTH 200
-#endif
-
-/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
-   if the built-in stack extension method is used).
-
-   Do not make this value too large; the results are undefined if
-   YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
-   evaluated with infinite-precision integer arithmetic.  */
-
-#ifndef YYMAXDEPTH
-# define YYMAXDEPTH 10000
-#endif
-
-

-
-#if YYERROR_VERBOSE
-
-# ifndef yystrlen
-#  if defined __GLIBC__ && defined _STRING_H
-#   define yystrlen strlen
-#  else
-/* Return the length of YYSTR.  */
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static YYSIZE_T
-yystrlen (const char *yystr)
-#else
-static YYSIZE_T
-yystrlen (yystr)
-    const char *yystr;
-#endif
-{
-  YYSIZE_T yylen;
-  for (yylen = 0; yystr[yylen]; yylen++)
-    continue;
-  return yylen;
-}
-#  endif
-# endif
-
-# ifndef yystpcpy
-#  if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
-#   define yystpcpy stpcpy
-#  else
-/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
-   YYDEST.  */
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static char *
-yystpcpy (char *yydest, const char *yysrc)
-#else
-static char *
-yystpcpy (yydest, yysrc)
-    char *yydest;
-    const char *yysrc;
-#endif
-{
-  char *yyd = yydest;
-  const char *yys = yysrc;
-
-  while ((*yyd++ = *yys++) != '\0')
-    continue;
-
-  return yyd - 1;
-}
-#  endif
-# endif
-
-# ifndef yytnamerr
-/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
-   quotes and backslashes, so that it's suitable for yyerror.  The
-   heuristic is that double-quoting is unnecessary unless the string
-   contains an apostrophe, a comma, or backslash (other than
-   backslash-backslash).  YYSTR is taken from yytname.  If YYRES is
-   null, do not copy; instead, return the length of what the result
-   would have been.  */
-static YYSIZE_T
-yytnamerr (char *yyres, const char *yystr)
-{
-  if (*yystr == '"')
-    {
-      YYSIZE_T yyn = 0;
-      char const *yyp = yystr;
-
-      for (;;)
-	switch (*++yyp)
-	  {
-	  case '\'':
-	  case ',':
-	    goto do_not_strip_quotes;
-
-	  case '\\':
-	    if (*++yyp != '\\')
-	      goto do_not_strip_quotes;
-	    /* Fall through.  */
-	  default:
-	    if (yyres)
-	      yyres[yyn] = *yyp;
-	    yyn++;
-	    break;
-
-	  case '"':
-	    if (yyres)
-	      yyres[yyn] = '\0';
-	    return yyn;
-	  }
-    do_not_strip_quotes: ;
-    }
-
-  if (! yyres)
-    return yystrlen (yystr);
-
-  return yystpcpy (yyres, yystr) - yyres;
-}
-# endif
-
-/* Copy into YYRESULT an error message about the unexpected token
-   YYCHAR while in state YYSTATE.  Return the number of bytes copied,
-   including the terminating null byte.  If YYRESULT is null, do not
-   copy anything; just return the number of bytes that would be
-   copied.  As a special case, return 0 if an ordinary "syntax error"
-   message will do.  Return YYSIZE_MAXIMUM if overflow occurs during
-   size calculation.  */
-static YYSIZE_T
-yysyntax_error (char *yyresult, int yystate, int yychar)
-{
-  int yyn = yypact[yystate];
-
-  if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
-    return 0;
-  else
-    {
-      int yytype = YYTRANSLATE (yychar);
-      YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
-      YYSIZE_T yysize = yysize0;
-      YYSIZE_T yysize1;
-      int yysize_overflow = 0;
-      enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
-      char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
-      int yyx;
-
-# if 0
-      /* This is so xgettext sees the translatable formats that are
-	 constructed on the fly.  */
-      YY_("syntax error, unexpected %s");
-      YY_("syntax error, unexpected %s, expecting %s");
-      YY_("syntax error, unexpected %s, expecting %s or %s");
-      YY_("syntax error, unexpected %s, expecting %s or %s or %s");
-      YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
-# endif
-      char *yyfmt;
-      char const *yyf;
-      static char const yyunexpected[] = "syntax error, unexpected %s";
-      static char const yyexpecting[] = ", expecting %s";
-      static char const yyor[] = " or %s";
-      char yyformat[sizeof yyunexpected
-		    + sizeof yyexpecting - 1
-		    + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
-		       * (sizeof yyor - 1))];
-      char const *yyprefix = yyexpecting;
-
-      /* Start YYX at -YYN if negative to avoid negative indexes in
-	 YYCHECK.  */
-      int yyxbegin = yyn < 0 ? -yyn : 0;
-
-      /* Stay within bounds of both yycheck and yytname.  */
-      int yychecklim = YYLAST - yyn + 1;
-      int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
-      int yycount = 1;
-
-      yyarg[0] = yytname[yytype];
-      yyfmt = yystpcpy (yyformat, yyunexpected);
-
-      for (yyx = yyxbegin; yyx < yyxend; ++yyx)
-	if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
-	  {
-	    if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
-	      {
-		yycount = 1;
-		yysize = yysize0;
-		yyformat[sizeof yyunexpected - 1] = '\0';
-		break;
-	      }
-	    yyarg[yycount++] = yytname[yyx];
-	    yysize1 = yysize + yytnamerr (0, yytname[yyx]);
-	    yysize_overflow |= (yysize1 < yysize);
-	    yysize = yysize1;
-	    yyfmt = yystpcpy (yyfmt, yyprefix);
-	    yyprefix = yyor;
-	  }
-
-      yyf = YY_(yyformat);
-      yysize1 = yysize + yystrlen (yyf);
-      yysize_overflow |= (yysize1 < yysize);
-      yysize = yysize1;
-
-      if (yysize_overflow)
-	return YYSIZE_MAXIMUM;
-
-      if (yyresult)
-	{
-	  /* Avoid sprintf, as that infringes on the user's name space.
-	     Don't have undefined behavior even if the translation
-	     produced a string with the wrong number of "%s"s.  */
-	  char *yyp = yyresult;
-	  int yyi = 0;
-	  while ((*yyp = *yyf) != '\0')
-	    {
-	      if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
-		{
-		  yyp += yytnamerr (yyp, yyarg[yyi++]);
-		  yyf += 2;
-		}
-	      else
-		{
-		  yyp++;
-		  yyf++;
-		}
-	    }
-	}
-      return yysize;
-    }
-}
-#endif /* YYERROR_VERBOSE */
-

-
-/*-----------------------------------------------.
-| Release the memory associated to this symbol.  |
-`-----------------------------------------------*/
-
-/*ARGSUSED*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static void
-yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
-#else
-static void
-yydestruct (yymsg, yytype, yyvaluep)
-    const char *yymsg;
-    int yytype;
-    YYSTYPE *yyvaluep;
-#endif
-{
-  YYUSE (yyvaluep);
-
-  if (!yymsg)
-    yymsg = "Deleting";
-  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
-
-  switch (yytype)
-    {
-
-      default:
-	break;
-    }
-}
-

-
-/* Prevent warnings from -Wmissing-prototypes.  */
-
-#ifdef YYPARSE_PARAM
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void *YYPARSE_PARAM);
-#else
-int yyparse ();
-#endif
-#else /* ! YYPARSE_PARAM */
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void);
-#else
-int yyparse ();
-#endif
-#endif /* ! YYPARSE_PARAM */
-
-
-
-/* The look-ahead symbol.  */
-int yychar;
-
-/* The semantic value of the look-ahead symbol.  */
-YYSTYPE yylval;
-
-/* Number of syntax errors so far.  */
-int yynerrs;
-
-
-
-/*----------.
-| yyparse.  |
-`----------*/
-
-#ifdef YYPARSE_PARAM
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-int
-yyparse (void *YYPARSE_PARAM)
-#else
-int
-yyparse (YYPARSE_PARAM)
-    void *YYPARSE_PARAM;
-#endif
-#else /* ! YYPARSE_PARAM */
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-int
-yyparse (void)
-#else
-int
-yyparse ()
-
-#endif
-#endif
-{
-  
-  int yystate;
-  int yyn;
-  int yyresult;
-  /* Number of tokens to shift before error messages enabled.  */
-  int yyerrstatus;
-  /* Look-ahead token as an internal (translated) token number.  */
-  int yytoken = 0;
-#if YYERROR_VERBOSE
-  /* Buffer for error messages, and its allocated size.  */
-  char yymsgbuf[128];
-  char *yymsg = yymsgbuf;
-  YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
-#endif
-
-  /* Three stacks and their tools:
-     `yyss': related to states,
-     `yyvs': related to semantic values,
-     `yyls': related to locations.
-
-     Refer to the stacks thru separate pointers, to allow yyoverflow
-     to reallocate them elsewhere.  */
-
-  /* The state stack.  */
-  yytype_int16 yyssa[YYINITDEPTH];
-  yytype_int16 *yyss = yyssa;
-  yytype_int16 *yyssp;
-
-  /* The semantic value stack.  */
-  YYSTYPE yyvsa[YYINITDEPTH];
-  YYSTYPE *yyvs = yyvsa;
-  YYSTYPE *yyvsp;
-
-
-
-#define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N))
-
-  YYSIZE_T yystacksize = YYINITDEPTH;
-
-  /* The variables used to return semantic value and location from the
-     action routines.  */
-  YYSTYPE yyval;
-
-
-  /* The number of symbols on the RHS of the reduced rule.
-     Keep to zero when no symbol should be popped.  */
-  int yylen = 0;
-
-  YYDPRINTF ((stderr, "Starting parse\n"));
-
-  yystate = 0;
-  yyerrstatus = 0;
-  yynerrs = 0;
-  yychar = YYEMPTY;		/* Cause a token to be read.  */
-
-  /* Initialize stack pointers.
-     Waste one element of value and location stack
-     so that they stay on the same level as the state stack.
-     The wasted elements are never initialized.  */
-
-  yyssp = yyss;
-  yyvsp = yyvs;
-
-  goto yysetstate;
-
-/*------------------------------------------------------------.
-| yynewstate -- Push a new state, which is found in yystate.  |
-`------------------------------------------------------------*/
- yynewstate:
-  /* In all cases, when you get here, the value and location stacks
-     have just been pushed.  So pushing a state here evens the stacks.  */
-  yyssp++;
-
- yysetstate:
-  *yyssp = yystate;
-
-  if (yyss + yystacksize - 1 <= yyssp)
-    {
-      /* Get the current used size of the three stacks, in elements.  */
-      YYSIZE_T yysize = yyssp - yyss + 1;
-
-#ifdef yyoverflow
-      {
-	/* Give user a chance to reallocate the stack.  Use copies of
-	   these so that the &'s don't force the real ones into
-	   memory.  */
-	YYSTYPE *yyvs1 = yyvs;
-	yytype_int16 *yyss1 = yyss;
-
-
-	/* Each stack pointer address is followed by the size of the
-	   data in use in that stack, in bytes.  This used to be a
-	   conditional around just the two extra args, but that might
-	   be undefined if yyoverflow is a macro.  */
-	yyoverflow (YY_("memory exhausted"),
-		    &yyss1, yysize * sizeof (*yyssp),
-		    &yyvs1, yysize * sizeof (*yyvsp),
-
-		    &yystacksize);
-
-	yyss = yyss1;
-	yyvs = yyvs1;
-      }
-#else /* no yyoverflow */
-# ifndef YYSTACK_RELOCATE
-      goto yyexhaustedlab;
-# else
-      /* Extend the stack our own way.  */
-      if (YYMAXDEPTH <= yystacksize)
-	goto yyexhaustedlab;
-      yystacksize *= 2;
-      if (YYMAXDEPTH < yystacksize)
-	yystacksize = YYMAXDEPTH;
-
-      {
-	yytype_int16 *yyss1 = yyss;
-	union yyalloc *yyptr =
-	  (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
-	if (! yyptr)
-	  goto yyexhaustedlab;
-	YYSTACK_RELOCATE (yyss);
-	YYSTACK_RELOCATE (yyvs);
-
-#  undef YYSTACK_RELOCATE
-	if (yyss1 != yyssa)
-	  YYSTACK_FREE (yyss1);
-      }
-# endif
-#endif /* no yyoverflow */
-
-      yyssp = yyss + yysize - 1;
-      yyvsp = yyvs + yysize - 1;
-
-
-      YYDPRINTF ((stderr, "Stack size increased to %lu\n",
-		  (unsigned long int) yystacksize));
-
-      if (yyss + yystacksize - 1 <= yyssp)
-	YYABORT;
-    }
-
-  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
-
-  goto yybackup;
-
-/*-----------.
-| yybackup.  |
-`-----------*/
-yybackup:
-
-  /* Do appropriate processing given the current state.  Read a
-     look-ahead token if we need one and don't already have one.  */
-
-  /* First try to decide what to do without reference to look-ahead token.  */
-  yyn = yypact[yystate];
-  if (yyn == YYPACT_NINF)
-    goto yydefault;
-
-  /* Not known => get a look-ahead token if don't already have one.  */
-
-  /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol.  */
-  if (yychar == YYEMPTY)
-    {
-      YYDPRINTF ((stderr, "Reading a token: "));
-      yychar = YYLEX;
-    }
-
-  if (yychar <= YYEOF)
-    {
-      yychar = yytoken = YYEOF;
-      YYDPRINTF ((stderr, "Now at end of input.\n"));
-    }
-  else
-    {
-      yytoken = YYTRANSLATE (yychar);
-      YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
-    }
-
-  /* If the proper action on seeing token YYTOKEN is to reduce or to
-     detect an error, take that action.  */
-  yyn += yytoken;
-  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
-    goto yydefault;
-  yyn = yytable[yyn];
-  if (yyn <= 0)
-    {
-      if (yyn == 0 || yyn == YYTABLE_NINF)
-	goto yyerrlab;
-      yyn = -yyn;
-      goto yyreduce;
-    }
-
-  if (yyn == YYFINAL)
-    YYACCEPT;
-
-  /* Count tokens shifted since error; after three, turn off error
-     status.  */
-  if (yyerrstatus)
-    yyerrstatus--;
-
-  /* Shift the look-ahead token.  */
-  YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
-
-  /* Discard the shifted token unless it is eof.  */
-  if (yychar != YYEOF)
-    yychar = YYEMPTY;
-
-  yystate = yyn;
-  *++yyvsp = yylval;
-
-  goto yynewstate;
-
-
-/*-----------------------------------------------------------.
-| yydefault -- do the default action for the current state.  |
-`-----------------------------------------------------------*/
-yydefault:
-  yyn = yydefact[yystate];
-  if (yyn == 0)
-    goto yyerrlab;
-  goto yyreduce;
-
-
-/*-----------------------------.
-| yyreduce -- Do a reduction.  |
-`-----------------------------*/
-yyreduce:
-  /* yyn is the number of a rule to reduce with.  */
-  yylen = yyr2[yyn];
-
-  /* If YYLEN is nonzero, implement the default value of the action:
-     `$$ = $1'.
-
-     Otherwise, the following line sets YYVAL to garbage.
-     This behavior is undocumented and Bison
-     users should not rely upon it.  Assigning to YYVAL
-     unconditionally makes the parser a bit smaller, and it avoids a
-     GCC warning that YYVAL may be used uninitialized.  */
-  yyval = yyvsp[1-yylen];
-
-
-  YY_REDUCE_PRINT (yyn);
-  switch (yyn)
-    {
-        case 4:
-#line 109 "cc.y"
-    {
-		dodecl(xdecl, lastclass, lasttype, Z);
-	}
-    break;
-
-  case 6:
-#line 114 "cc.y"
-    {
-		lastdcl = T;
-		firstarg = S;
-		dodecl(xdecl, lastclass, lasttype, (yyvsp[(2) - (2)].node));
-		if(lastdcl == T || lastdcl->etype != TFUNC) {
-			diag((yyvsp[(2) - (2)].node), "not a function");
-			lastdcl = types[TFUNC];
-		}
-		thisfn = lastdcl;
-		markdcl();
-		firstdcl = dclstack;
-		argmark((yyvsp[(2) - (2)].node), 0);
-	}
-    break;
-
-  case 7:
-#line 128 "cc.y"
-    {
-		argmark((yyvsp[(2) - (4)].node), 1);
-	}
-    break;
-
-  case 8:
-#line 132 "cc.y"
-    {
-		Node *n;
-
-		n = revertdcl();
-		if(n)
-			(yyvsp[(6) - (6)].node) = new(OLIST, n, (yyvsp[(6) - (6)].node));
-		if(!debug['a'] && !debug['Z'])
-			codgen((yyvsp[(6) - (6)].node), (yyvsp[(2) - (6)].node));
-	}
-    break;
-
-  case 9:
-#line 144 "cc.y"
-    {
-		dodecl(xdecl, lastclass, lasttype, (yyvsp[(1) - (1)].node));
-	}
-    break;
-
-  case 10:
-#line 148 "cc.y"
-    {
-		(yyvsp[(1) - (1)].node) = dodecl(xdecl, lastclass, lasttype, (yyvsp[(1) - (1)].node));
-	}
-    break;
-
-  case 11:
-#line 152 "cc.y"
-    {
-		doinit((yyvsp[(1) - (4)].node)->sym, (yyvsp[(1) - (4)].node)->type, 0L, (yyvsp[(4) - (4)].node));
-	}
-    break;
-
-  case 14:
-#line 160 "cc.y"
-    {
-		(yyval.node) = new(OIND, (yyvsp[(3) - (3)].node), Z);
-		(yyval.node)->garb = simpleg((yyvsp[(2) - (3)].lval));
-	}
-    break;
-
-  case 16:
-#line 168 "cc.y"
-    {
-		(yyval.node) = (yyvsp[(2) - (3)].node);
-	}
-    break;
-
-  case 17:
-#line 172 "cc.y"
-    {
-		(yyval.node) = new(OFUNC, (yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].node));
-	}
-    break;
-
-  case 18:
-#line 176 "cc.y"
-    {
-		(yyval.node) = new(OARRAY, (yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].node));
-	}
-    break;
-
-  case 19:
-#line 185 "cc.y"
-    {
-		(yyval.node) = dodecl(adecl, lastclass, lasttype, Z);
-	}
-    break;
-
-  case 20:
-#line 189 "cc.y"
-    {
-		(yyval.node) = (yyvsp[(2) - (3)].node);
-	}
-    break;
-
-  case 21:
-#line 195 "cc.y"
-    {
-		dodecl(adecl, lastclass, lasttype, (yyvsp[(1) - (1)].node));
-		(yyval.node) = Z;
-	}
-    break;
-
-  case 22:
-#line 200 "cc.y"
-    {
-		(yyvsp[(1) - (1)].node) = dodecl(adecl, lastclass, lasttype, (yyvsp[(1) - (1)].node));
-	}
-    break;
-
-  case 23:
-#line 204 "cc.y"
-    {
-		int32 w;
-
-		w = (yyvsp[(1) - (4)].node)->sym->type->width;
-		(yyval.node) = doinit((yyvsp[(1) - (4)].node)->sym, (yyvsp[(1) - (4)].node)->type, 0L, (yyvsp[(4) - (4)].node));
-		(yyval.node) = contig((yyvsp[(1) - (4)].node)->sym, (yyval.node), w);
-	}
-    break;
-
-  case 24:
-#line 212 "cc.y"
-    {
-		(yyval.node) = (yyvsp[(1) - (3)].node);
-		if((yyvsp[(3) - (3)].node) != Z) {
-			(yyval.node) = (yyvsp[(3) - (3)].node);
-			if((yyvsp[(1) - (3)].node) != Z)
-				(yyval.node) = new(OLIST, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-		}
-	}
-    break;
-
-  case 27:
-#line 229 "cc.y"
-    {
-		dodecl(pdecl, lastclass, lasttype, (yyvsp[(1) - (1)].node));
-	}
-    break;
-
-  case 29:
-#line 239 "cc.y"
-    {
-		lasttype = (yyvsp[(1) - (1)].type);
-	}
-    break;
-
-  case 31:
-#line 244 "cc.y"
-    {
-		lasttype = (yyvsp[(2) - (2)].type);
-	}
-    break;
-
-  case 33:
-#line 250 "cc.y"
-    {
-		lastfield = 0;
-		edecl(CXXX, lasttype, S);
-	}
-    break;
-
-  case 35:
-#line 258 "cc.y"
-    {
-		dodecl(edecl, CXXX, lasttype, (yyvsp[(1) - (1)].node));
-	}
-    break;
-
-  case 37:
-#line 265 "cc.y"
-    {
-		lastbit = 0;
-		firstbit = 1;
-	}
-    break;
-
-  case 38:
-#line 270 "cc.y"
-    {
-		(yyval.node) = new(OBIT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 39:
-#line 274 "cc.y"
-    {
-		(yyval.node) = new(OBIT, Z, (yyvsp[(2) - (2)].node));
-	}
-    break;
-
-  case 40:
-#line 282 "cc.y"
-    {
-		(yyval.node) = (Z);
-	}
-    break;
-
-  case 42:
-#line 289 "cc.y"
-    {
-		(yyval.node) = new(OIND, (Z), Z);
-		(yyval.node)->garb = simpleg((yyvsp[(2) - (2)].lval));
-	}
-    break;
-
-  case 43:
-#line 294 "cc.y"
-    {
-		(yyval.node) = new(OIND, (yyvsp[(3) - (3)].node), Z);
-		(yyval.node)->garb = simpleg((yyvsp[(2) - (3)].lval));
-	}
-    break;
-
-  case 46:
-#line 303 "cc.y"
-    {
-		(yyval.node) = new(OFUNC, (yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].node));
-	}
-    break;
-
-  case 47:
-#line 307 "cc.y"
-    {
-		(yyval.node) = new(OARRAY, (yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].node));
-	}
-    break;
-
-  case 48:
-#line 313 "cc.y"
-    {
-		(yyval.node) = new(OFUNC, (Z), Z);
-	}
-    break;
-
-  case 49:
-#line 317 "cc.y"
-    {
-		(yyval.node) = new(OARRAY, (Z), (yyvsp[(2) - (3)].node));
-	}
-    break;
-
-  case 50:
-#line 321 "cc.y"
-    {
-		(yyval.node) = (yyvsp[(2) - (3)].node);
-	}
-    break;
-
-  case 52:
-#line 328 "cc.y"
-    {
-		(yyval.node) = new(OINIT, invert((yyvsp[(2) - (3)].node)), Z);
-	}
-    break;
-
-  case 53:
-#line 334 "cc.y"
-    {
-		(yyval.node) = new(OARRAY, (yyvsp[(2) - (3)].node), Z);
-	}
-    break;
-
-  case 54:
-#line 338 "cc.y"
-    {
-		(yyval.node) = new(OELEM, Z, Z);
-		(yyval.node)->sym = (yyvsp[(2) - (2)].sym);
-	}
-    break;
-
-  case 57:
-#line 347 "cc.y"
-    {
-		(yyval.node) = new(OLIST, (yyvsp[(1) - (3)].node), (yyvsp[(2) - (3)].node));
-	}
-    break;
-
-  case 59:
-#line 352 "cc.y"
-    {
-		(yyval.node) = new(OLIST, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node));
-	}
-    break;
-
-  case 62:
-#line 360 "cc.y"
-    {
-		(yyval.node) = new(OLIST, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node));
-	}
-    break;
-
-  case 63:
-#line 365 "cc.y"
-    {
-		(yyval.node) = Z;
-	}
-    break;
-
-  case 64:
-#line 369 "cc.y"
-    {
-		(yyval.node) = invert((yyvsp[(1) - (1)].node));
-	}
-    break;
-
-  case 66:
-#line 377 "cc.y"
-    {
-		(yyval.node) = new(OPROTO, (yyvsp[(2) - (2)].node), Z);
-		(yyval.node)->type = (yyvsp[(1) - (2)].type);
-	}
-    break;
-
-  case 67:
-#line 382 "cc.y"
-    {
-		(yyval.node) = new(OPROTO, (yyvsp[(2) - (2)].node), Z);
-		(yyval.node)->type = (yyvsp[(1) - (2)].type);
-	}
-    break;
-
-  case 68:
-#line 387 "cc.y"
-    {
-		(yyval.node) = new(ODOTDOT, Z, Z);
-	}
-    break;
-
-  case 69:
-#line 391 "cc.y"
-    {
-		(yyval.node) = new(OLIST, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 70:
-#line 397 "cc.y"
-    {
-		(yyval.node) = invert((yyvsp[(2) - (3)].node));
-	//	if($2 != Z)
-	//		$$ = new(OLIST, $2, $$);
-		if((yyval.node) == Z)
-			(yyval.node) = new(OLIST, Z, Z);
-	}
-    break;
-
-  case 71:
-#line 406 "cc.y"
-    {
-		(yyval.node) = Z;
-	}
-    break;
-
-  case 72:
-#line 410 "cc.y"
-    {
-		(yyval.node) = new(OLIST, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node));
-	}
-    break;
-
-  case 73:
-#line 414 "cc.y"
-    {
-		(yyval.node) = new(OLIST, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node));
-	}
-    break;
-
-  case 75:
-#line 421 "cc.y"
-    {
-		(yyval.node) = new(OLIST, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node));
-	}
-    break;
-
-  case 76:
-#line 427 "cc.y"
-    {
-		(yyval.node) = new(OCASE, (yyvsp[(2) - (3)].node), Z);
-	}
-    break;
-
-  case 77:
-#line 431 "cc.y"
-    {
-		(yyval.node) = new(OCASE, Z, Z);
-	}
-    break;
-
-  case 78:
-#line 435 "cc.y"
-    {
-		(yyval.node) = new(OLABEL, dcllabel((yyvsp[(1) - (2)].sym), 1), Z);
-	}
-    break;
-
-  case 79:
-#line 441 "cc.y"
-    {
-		(yyval.node) = Z;
-	}
-    break;
-
-  case 81:
-#line 446 "cc.y"
-    {
-		(yyval.node) = new(OLIST, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node));
-	}
-    break;
-
-  case 83:
-#line 453 "cc.y"
-    {
-		(yyval.node) = (yyvsp[(2) - (2)].node);
-	}
-    break;
-
-  case 85:
-#line 459 "cc.y"
-    {
-		markdcl();
-	}
-    break;
-
-  case 86:
-#line 463 "cc.y"
-    {
-		(yyval.node) = revertdcl();
-		if((yyval.node))
-			(yyval.node) = new(OLIST, (yyval.node), (yyvsp[(2) - (2)].node));
-		else
-			(yyval.node) = (yyvsp[(2) - (2)].node);
-	}
-    break;
-
-  case 87:
-#line 471 "cc.y"
-    {
-		(yyval.node) = new(OIF, (yyvsp[(3) - (5)].node), new(OLIST, (yyvsp[(5) - (5)].node), Z));
-		if((yyvsp[(5) - (5)].node) == Z)
-			warn((yyvsp[(3) - (5)].node), "empty if body");
-	}
-    break;
-
-  case 88:
-#line 477 "cc.y"
-    {
-		(yyval.node) = new(OIF, (yyvsp[(3) - (7)].node), new(OLIST, (yyvsp[(5) - (7)].node), (yyvsp[(7) - (7)].node)));
-		if((yyvsp[(5) - (7)].node) == Z)
-			warn((yyvsp[(3) - (7)].node), "empty if body");
-		if((yyvsp[(7) - (7)].node) == Z)
-			warn((yyvsp[(3) - (7)].node), "empty else body");
-	}
-    break;
-
-  case 89:
-#line 484 "cc.y"
-    { markdcl(); }
-    break;
-
-  case 90:
-#line 485 "cc.y"
-    {
-		(yyval.node) = revertdcl();
-		if((yyval.node)){
-			if((yyvsp[(4) - (10)].node))
-				(yyvsp[(4) - (10)].node) = new(OLIST, (yyval.node), (yyvsp[(4) - (10)].node));
-			else
-				(yyvsp[(4) - (10)].node) = (yyval.node);
-		}
-		(yyval.node) = new(OFOR, new(OLIST, (yyvsp[(6) - (10)].node), new(OLIST, (yyvsp[(4) - (10)].node), (yyvsp[(8) - (10)].node))), (yyvsp[(10) - (10)].node));
-	}
-    break;
-
-  case 91:
-#line 496 "cc.y"
-    {
-		(yyval.node) = new(OWHILE, (yyvsp[(3) - (5)].node), (yyvsp[(5) - (5)].node));
-	}
-    break;
-
-  case 92:
-#line 500 "cc.y"
-    {
-		(yyval.node) = new(ODWHILE, (yyvsp[(5) - (7)].node), (yyvsp[(2) - (7)].node));
-	}
-    break;
-
-  case 93:
-#line 504 "cc.y"
-    {
-		(yyval.node) = new(ORETURN, (yyvsp[(2) - (3)].node), Z);
-		(yyval.node)->type = thisfn->link;
-	}
-    break;
-
-  case 94:
-#line 509 "cc.y"
-    {
-		(yyval.node) = new(OCONST, Z, Z);
-		(yyval.node)->vconst = 0;
-		(yyval.node)->type = types[TINT];
-		(yyvsp[(3) - (5)].node) = new(OSUB, (yyval.node), (yyvsp[(3) - (5)].node));
-
-		(yyval.node) = new(OCONST, Z, Z);
-		(yyval.node)->vconst = 0;
-		(yyval.node)->type = types[TINT];
-		(yyvsp[(3) - (5)].node) = new(OSUB, (yyval.node), (yyvsp[(3) - (5)].node));
-
-		(yyval.node) = new(OSWITCH, (yyvsp[(3) - (5)].node), (yyvsp[(5) - (5)].node));
-	}
-    break;
-
-  case 95:
-#line 523 "cc.y"
-    {
-		(yyval.node) = new(OBREAK, Z, Z);
-	}
-    break;
-
-  case 96:
-#line 527 "cc.y"
-    {
-		(yyval.node) = new(OCONTINUE, Z, Z);
-	}
-    break;
-
-  case 97:
-#line 531 "cc.y"
-    {
-		(yyval.node) = new(OGOTO, dcllabel((yyvsp[(2) - (3)].sym), 0), Z);
-	}
-    break;
-
-  case 98:
-#line 535 "cc.y"
-    {
-		(yyval.node) = new(OUSED, (yyvsp[(3) - (5)].node), Z);
-	}
-    break;
-
-  case 99:
-#line 539 "cc.y"
-    {
-		(yyval.node) = new(OPREFETCH, (yyvsp[(3) - (5)].node), Z);
-	}
-    break;
-
-  case 100:
-#line 543 "cc.y"
-    {
-		(yyval.node) = new(OSET, (yyvsp[(3) - (5)].node), Z);
-	}
-    break;
-
-  case 101:
-#line 548 "cc.y"
-    {
-		(yyval.node) = Z;
-	}
-    break;
-
-  case 103:
-#line 554 "cc.y"
-    {
-		(yyval.node) = Z;
-	}
-    break;
-
-  case 105:
-#line 561 "cc.y"
-    {
-		(yyval.node) = new(OCAST, (yyvsp[(1) - (1)].node), Z);
-		(yyval.node)->type = types[TLONG];
-	}
-    break;
-
-  case 107:
-#line 569 "cc.y"
-    {
-		(yyval.node) = new(OCOMMA, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 109:
-#line 576 "cc.y"
-    {
-		(yyval.node) = new(OMUL, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 110:
-#line 580 "cc.y"
-    {
-		(yyval.node) = new(ODIV, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 111:
-#line 584 "cc.y"
-    {
-		(yyval.node) = new(OMOD, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 112:
-#line 588 "cc.y"
-    {
-		(yyval.node) = new(OADD, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 113:
-#line 592 "cc.y"
-    {
-		(yyval.node) = new(OSUB, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 114:
-#line 596 "cc.y"
-    {
-		(yyval.node) = new(OASHR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 115:
-#line 600 "cc.y"
-    {
-		(yyval.node) = new(OASHL, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 116:
-#line 604 "cc.y"
-    {
-		(yyval.node) = new(OLT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 117:
-#line 608 "cc.y"
-    {
-		(yyval.node) = new(OGT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 118:
-#line 612 "cc.y"
-    {
-		(yyval.node) = new(OLE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 119:
-#line 616 "cc.y"
-    {
-		(yyval.node) = new(OGE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 120:
-#line 620 "cc.y"
-    {
-		(yyval.node) = new(OEQ, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 121:
-#line 624 "cc.y"
-    {
-		(yyval.node) = new(ONE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 122:
-#line 628 "cc.y"
-    {
-		(yyval.node) = new(OAND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 123:
-#line 632 "cc.y"
-    {
-		(yyval.node) = new(OXOR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 124:
-#line 636 "cc.y"
-    {
-		(yyval.node) = new(OOR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 125:
-#line 640 "cc.y"
-    {
-		(yyval.node) = new(OANDAND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 126:
-#line 644 "cc.y"
-    {
-		(yyval.node) = new(OOROR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 127:
-#line 648 "cc.y"
-    {
-		(yyval.node) = new(OCOND, (yyvsp[(1) - (5)].node), new(OLIST, (yyvsp[(3) - (5)].node), (yyvsp[(5) - (5)].node)));
-	}
-    break;
-
-  case 128:
-#line 652 "cc.y"
-    {
-		(yyval.node) = new(OAS, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 129:
-#line 656 "cc.y"
-    {
-		(yyval.node) = new(OASADD, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 130:
-#line 660 "cc.y"
-    {
-		(yyval.node) = new(OASSUB, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 131:
-#line 664 "cc.y"
-    {
-		(yyval.node) = new(OASMUL, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 132:
-#line 668 "cc.y"
-    {
-		(yyval.node) = new(OASDIV, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 133:
-#line 672 "cc.y"
-    {
-		(yyval.node) = new(OASMOD, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 134:
-#line 676 "cc.y"
-    {
-		(yyval.node) = new(OASASHL, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 135:
-#line 680 "cc.y"
-    {
-		(yyval.node) = new(OASASHR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 136:
-#line 684 "cc.y"
-    {
-		(yyval.node) = new(OASAND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 137:
-#line 688 "cc.y"
-    {
-		(yyval.node) = new(OASXOR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 138:
-#line 692 "cc.y"
-    {
-		(yyval.node) = new(OASOR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 140:
-#line 699 "cc.y"
-    {
-		(yyval.node) = new(OCAST, (yyvsp[(5) - (5)].node), Z);
-		dodecl(NODECL, CXXX, (yyvsp[(2) - (5)].type), (yyvsp[(3) - (5)].node));
-		(yyval.node)->type = lastdcl;
-		(yyval.node)->xcast = 1;
-	}
-    break;
-
-  case 141:
-#line 706 "cc.y"
-    {
-		(yyval.node) = new(OSTRUCT, (yyvsp[(6) - (7)].node), Z);
-		dodecl(NODECL, CXXX, (yyvsp[(2) - (7)].type), (yyvsp[(3) - (7)].node));
-		(yyval.node)->type = lastdcl;
-	}
-    break;
-
-  case 143:
-#line 715 "cc.y"
-    {
-		(yyval.node) = new(OIND, (yyvsp[(2) - (2)].node), Z);
-	}
-    break;
-
-  case 144:
-#line 719 "cc.y"
-    {
-		(yyval.node) = new(OADDR, (yyvsp[(2) - (2)].node), Z);
-	}
-    break;
-
-  case 145:
-#line 723 "cc.y"
-    {
-		(yyval.node) = new(OPOS, (yyvsp[(2) - (2)].node), Z);
-	}
-    break;
-
-  case 146:
-#line 727 "cc.y"
-    {
-		(yyval.node) = new(ONEG, (yyvsp[(2) - (2)].node), Z);
-	}
-    break;
-
-  case 147:
-#line 731 "cc.y"
-    {
-		(yyval.node) = new(ONOT, (yyvsp[(2) - (2)].node), Z);
-	}
-    break;
-
-  case 148:
-#line 735 "cc.y"
-    {
-		(yyval.node) = new(OCOM, (yyvsp[(2) - (2)].node), Z);
-	}
-    break;
-
-  case 149:
-#line 739 "cc.y"
-    {
-		(yyval.node) = new(OPREINC, (yyvsp[(2) - (2)].node), Z);
-	}
-    break;
-
-  case 150:
-#line 743 "cc.y"
-    {
-		(yyval.node) = new(OPREDEC, (yyvsp[(2) - (2)].node), Z);
-	}
-    break;
-
-  case 151:
-#line 747 "cc.y"
-    {
-		(yyval.node) = new(OSIZE, (yyvsp[(2) - (2)].node), Z);
-	}
-    break;
-
-  case 152:
-#line 751 "cc.y"
-    {
-		(yyval.node) = new(OSIGN, (yyvsp[(2) - (2)].node), Z);
-	}
-    break;
-
-  case 153:
-#line 757 "cc.y"
-    {
-		(yyval.node) = (yyvsp[(2) - (3)].node);
-	}
-    break;
-
-  case 154:
-#line 761 "cc.y"
-    {
-		(yyval.node) = new(OSIZE, Z, Z);
-		dodecl(NODECL, CXXX, (yyvsp[(3) - (5)].type), (yyvsp[(4) - (5)].node));
-		(yyval.node)->type = lastdcl;
-	}
-    break;
-
-  case 155:
-#line 767 "cc.y"
-    {
-		(yyval.node) = new(OSIGN, Z, Z);
-		dodecl(NODECL, CXXX, (yyvsp[(3) - (5)].type), (yyvsp[(4) - (5)].node));
-		(yyval.node)->type = lastdcl;
-	}
-    break;
-
-  case 156:
-#line 773 "cc.y"
-    {
-		(yyval.node) = new(OFUNC, (yyvsp[(1) - (4)].node), Z);
-		if((yyvsp[(1) - (4)].node)->op == ONAME)
-		if((yyvsp[(1) - (4)].node)->type == T)
-			dodecl(xdecl, CXXX, types[TINT], (yyval.node));
-		(yyval.node)->right = invert((yyvsp[(3) - (4)].node));
-	}
-    break;
-
-  case 157:
-#line 781 "cc.y"
-    {
-		(yyval.node) = new(OIND, new(OADD, (yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].node)), Z);
-	}
-    break;
-
-  case 158:
-#line 785 "cc.y"
-    {
-		(yyval.node) = new(ODOT, new(OIND, (yyvsp[(1) - (3)].node), Z), Z);
-		(yyval.node)->sym = (yyvsp[(3) - (3)].sym);
-	}
-    break;
-
-  case 159:
-#line 790 "cc.y"
-    {
-		(yyval.node) = new(ODOT, (yyvsp[(1) - (3)].node), Z);
-		(yyval.node)->sym = (yyvsp[(3) - (3)].sym);
-	}
-    break;
-
-  case 160:
-#line 795 "cc.y"
-    {
-		(yyval.node) = new(OPOSTINC, (yyvsp[(1) - (2)].node), Z);
-	}
-    break;
-
-  case 161:
-#line 799 "cc.y"
-    {
-		(yyval.node) = new(OPOSTDEC, (yyvsp[(1) - (2)].node), Z);
-	}
-    break;
-
-  case 163:
-#line 804 "cc.y"
-    {
-		(yyval.node) = new(OCONST, Z, Z);
-		(yyval.node)->type = types[TINT];
-		(yyval.node)->vconst = (yyvsp[(1) - (1)].vval);
-		(yyval.node)->cstring = strdup(symb);
-	}
-    break;
-
-  case 164:
-#line 811 "cc.y"
-    {
-		(yyval.node) = new(OCONST, Z, Z);
-		(yyval.node)->type = types[TLONG];
-		(yyval.node)->vconst = (yyvsp[(1) - (1)].vval);
-		(yyval.node)->cstring = strdup(symb);
-	}
-    break;
-
-  case 165:
-#line 818 "cc.y"
-    {
-		(yyval.node) = new(OCONST, Z, Z);
-		(yyval.node)->type = types[TUINT];
-		(yyval.node)->vconst = (yyvsp[(1) - (1)].vval);
-		(yyval.node)->cstring = strdup(symb);
-	}
-    break;
-
-  case 166:
-#line 825 "cc.y"
-    {
-		(yyval.node) = new(OCONST, Z, Z);
-		(yyval.node)->type = types[TULONG];
-		(yyval.node)->vconst = (yyvsp[(1) - (1)].vval);
-		(yyval.node)->cstring = strdup(symb);
-	}
-    break;
-
-  case 167:
-#line 832 "cc.y"
-    {
-		(yyval.node) = new(OCONST, Z, Z);
-		(yyval.node)->type = types[TDOUBLE];
-		(yyval.node)->fconst = (yyvsp[(1) - (1)].dval);
-		(yyval.node)->cstring = strdup(symb);
-	}
-    break;
-
-  case 168:
-#line 839 "cc.y"
-    {
-		(yyval.node) = new(OCONST, Z, Z);
-		(yyval.node)->type = types[TFLOAT];
-		(yyval.node)->fconst = (yyvsp[(1) - (1)].dval);
-		(yyval.node)->cstring = strdup(symb);
-	}
-    break;
-
-  case 169:
-#line 846 "cc.y"
-    {
-		(yyval.node) = new(OCONST, Z, Z);
-		(yyval.node)->type = types[TVLONG];
-		(yyval.node)->vconst = (yyvsp[(1) - (1)].vval);
-		(yyval.node)->cstring = strdup(symb);
-	}
-    break;
-
-  case 170:
-#line 853 "cc.y"
-    {
-		(yyval.node) = new(OCONST, Z, Z);
-		(yyval.node)->type = types[TUVLONG];
-		(yyval.node)->vconst = (yyvsp[(1) - (1)].vval);
-		(yyval.node)->cstring = strdup(symb);
-	}
-    break;
-
-  case 173:
-#line 864 "cc.y"
-    {
-		(yyval.node) = new(OSTRING, Z, Z);
-		(yyval.node)->type = typ(TARRAY, types[TCHAR]);
-		(yyval.node)->type->width = (yyvsp[(1) - (1)].sval).l + 1;
-		(yyval.node)->cstring = (yyvsp[(1) - (1)].sval).s;
-		(yyval.node)->sym = symstring;
-		(yyval.node)->etype = TARRAY;
-		(yyval.node)->class = CSTATIC;
-	}
-    break;
-
-  case 174:
-#line 874 "cc.y"
-    {
-		char *s;
-		int n;
-
-		n = (yyvsp[(1) - (2)].node)->type->width - 1;
-		s = alloc(n+(yyvsp[(2) - (2)].sval).l+MAXALIGN);
-
-		memcpy(s, (yyvsp[(1) - (2)].node)->cstring, n);
-		memcpy(s+n, (yyvsp[(2) - (2)].sval).s, (yyvsp[(2) - (2)].sval).l);
-		s[n+(yyvsp[(2) - (2)].sval).l] = 0;
-
-		(yyval.node) = (yyvsp[(1) - (2)].node);
-		(yyval.node)->type->width += (yyvsp[(2) - (2)].sval).l;
-		(yyval.node)->cstring = s;
-	}
-    break;
-
-  case 175:
-#line 892 "cc.y"
-    {
-		(yyval.node) = new(OLSTRING, Z, Z);
-		(yyval.node)->type = typ(TARRAY, types[TRUNE]);
-		(yyval.node)->type->width = (yyvsp[(1) - (1)].sval).l + sizeof(TRune);
-		(yyval.node)->rstring = (TRune*)(yyvsp[(1) - (1)].sval).s;
-		(yyval.node)->sym = symstring;
-		(yyval.node)->etype = TARRAY;
-		(yyval.node)->class = CSTATIC;
-	}
-    break;
-
-  case 176:
-#line 902 "cc.y"
-    {
-		char *s;
-		int n;
-
-		n = (yyvsp[(1) - (2)].node)->type->width - sizeof(TRune);
-		s = alloc(n+(yyvsp[(2) - (2)].sval).l+MAXALIGN);
-
-		memcpy(s, (yyvsp[(1) - (2)].node)->rstring, n);
-		memcpy(s+n, (yyvsp[(2) - (2)].sval).s, (yyvsp[(2) - (2)].sval).l);
-		*(TRune*)(s+n+(yyvsp[(2) - (2)].sval).l) = 0;
-
-		(yyval.node) = (yyvsp[(1) - (2)].node);
-		(yyval.node)->type->width += (yyvsp[(2) - (2)].sval).l;
-		(yyval.node)->rstring = (TRune*)s;
-	}
-    break;
-
-  case 177:
-#line 919 "cc.y"
-    {
-		(yyval.node) = Z;
-	}
-    break;
-
-  case 180:
-#line 927 "cc.y"
-    {
-		(yyval.node) = new(OLIST, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 181:
-#line 933 "cc.y"
-    {
-		(yyval.tyty).t1 = strf;
-		(yyval.tyty).t2 = strl;
-		(yyval.tyty).t3 = lasttype;
-		(yyval.tyty).c = lastclass;
-		strf = T;
-		strl = T;
-		lastbit = 0;
-		firstbit = 1;
-		lastclass = CXXX;
-		lasttype = T;
-	}
-    break;
-
-  case 182:
-#line 946 "cc.y"
-    {
-		(yyval.type) = strf;
-		strf = (yyvsp[(2) - (4)].tyty).t1;
-		strl = (yyvsp[(2) - (4)].tyty).t2;
-		lasttype = (yyvsp[(2) - (4)].tyty).t3;
-		lastclass = (yyvsp[(2) - (4)].tyty).c;
-	}
-    break;
-
-  case 183:
-#line 955 "cc.y"
-    {
-		lastclass = CXXX;
-		lasttype = types[TINT];
-	}
-    break;
-
-  case 185:
-#line 963 "cc.y"
-    {
-		(yyval.tycl).t = (yyvsp[(1) - (1)].type);
-		(yyval.tycl).c = CXXX;
-	}
-    break;
-
-  case 186:
-#line 968 "cc.y"
-    {
-		(yyval.tycl).t = simplet((yyvsp[(1) - (1)].lval));
-		(yyval.tycl).c = CXXX;
-	}
-    break;
-
-  case 187:
-#line 973 "cc.y"
-    {
-		(yyval.tycl).t = simplet((yyvsp[(1) - (1)].lval));
-		(yyval.tycl).c = simplec((yyvsp[(1) - (1)].lval));
-		(yyval.tycl).t = garbt((yyval.tycl).t, (yyvsp[(1) - (1)].lval));
-	}
-    break;
-
-  case 188:
-#line 979 "cc.y"
-    {
-		(yyval.tycl).t = (yyvsp[(1) - (2)].type);
-		(yyval.tycl).c = simplec((yyvsp[(2) - (2)].lval));
-		(yyval.tycl).t = garbt((yyval.tycl).t, (yyvsp[(2) - (2)].lval));
-		if((yyvsp[(2) - (2)].lval) & ~BCLASS & ~BGARB)
-			diag(Z, "duplicate types given: %T and %Q", (yyvsp[(1) - (2)].type), (yyvsp[(2) - (2)].lval));
-	}
-    break;
-
-  case 189:
-#line 987 "cc.y"
-    {
-		(yyval.tycl).t = simplet(typebitor((yyvsp[(1) - (2)].lval), (yyvsp[(2) - (2)].lval)));
-		(yyval.tycl).c = simplec((yyvsp[(2) - (2)].lval));
-		(yyval.tycl).t = garbt((yyval.tycl).t, (yyvsp[(2) - (2)].lval));
-	}
-    break;
-
-  case 190:
-#line 993 "cc.y"
-    {
-		(yyval.tycl).t = (yyvsp[(2) - (3)].type);
-		(yyval.tycl).c = simplec((yyvsp[(1) - (3)].lval));
-		(yyval.tycl).t = garbt((yyval.tycl).t, (yyvsp[(1) - (3)].lval)|(yyvsp[(3) - (3)].lval));
-	}
-    break;
-
-  case 191:
-#line 999 "cc.y"
-    {
-		(yyval.tycl).t = simplet((yyvsp[(2) - (2)].lval));
-		(yyval.tycl).c = simplec((yyvsp[(1) - (2)].lval));
-		(yyval.tycl).t = garbt((yyval.tycl).t, (yyvsp[(1) - (2)].lval));
-	}
-    break;
-
-  case 192:
-#line 1005 "cc.y"
-    {
-		(yyval.tycl).t = simplet(typebitor((yyvsp[(2) - (3)].lval), (yyvsp[(3) - (3)].lval)));
-		(yyval.tycl).c = simplec((yyvsp[(1) - (3)].lval)|(yyvsp[(3) - (3)].lval));
-		(yyval.tycl).t = garbt((yyval.tycl).t, (yyvsp[(1) - (3)].lval)|(yyvsp[(3) - (3)].lval));
-	}
-    break;
-
-  case 193:
-#line 1013 "cc.y"
-    {
-		(yyval.type) = (yyvsp[(1) - (1)].tycl).t;
-		if((yyvsp[(1) - (1)].tycl).c != CXXX)
-			diag(Z, "illegal combination of class 4: %s", cnames[(yyvsp[(1) - (1)].tycl).c]);
-	}
-    break;
-
-  case 194:
-#line 1021 "cc.y"
-    {
-		lasttype = (yyvsp[(1) - (1)].tycl).t;
-		lastclass = (yyvsp[(1) - (1)].tycl).c;
-	}
-    break;
-
-  case 195:
-#line 1028 "cc.y"
-    {
-		dotag((yyvsp[(2) - (2)].sym), TSTRUCT, 0);
-		(yyval.type) = (yyvsp[(2) - (2)].sym)->suetag;
-	}
-    break;
-
-  case 196:
-#line 1033 "cc.y"
-    {
-		dotag((yyvsp[(2) - (2)].sym), TSTRUCT, autobn);
-	}
-    break;
-
-  case 197:
-#line 1037 "cc.y"
-    {
-		(yyval.type) = (yyvsp[(2) - (4)].sym)->suetag;
-		if((yyval.type)->link != T)
-			diag(Z, "redeclare tag: %s", (yyvsp[(2) - (4)].sym)->name);
-		(yyval.type)->link = (yyvsp[(4) - (4)].type);
-		sualign((yyval.type));
-	}
-    break;
-
-  case 198:
-#line 1045 "cc.y"
-    {
-		diag(Z, "struct must have tag");
-		taggen++;
-		sprint(symb, "_%d_", taggen);
-		(yyval.type) = dotag(lookup(), TSTRUCT, autobn);
-		(yyval.type)->link = (yyvsp[(2) - (2)].type);
-		sualign((yyval.type));
-	}
-    break;
-
-  case 199:
-#line 1054 "cc.y"
-    {
-		dotag((yyvsp[(2) - (2)].sym), TUNION, 0);
-		(yyval.type) = (yyvsp[(2) - (2)].sym)->suetag;
-	}
-    break;
-
-  case 200:
-#line 1059 "cc.y"
-    {
-		dotag((yyvsp[(2) - (2)].sym), TUNION, autobn);
-	}
-    break;
-
-  case 201:
-#line 1063 "cc.y"
-    {
-		(yyval.type) = (yyvsp[(2) - (4)].sym)->suetag;
-		if((yyval.type)->link != T)
-			diag(Z, "redeclare tag: %s", (yyvsp[(2) - (4)].sym)->name);
-		(yyval.type)->link = (yyvsp[(4) - (4)].type);
-		sualign((yyval.type));
-	}
-    break;
-
-  case 202:
-#line 1071 "cc.y"
-    {
-		taggen++;
-		sprint(symb, "_%d_", taggen);
-		(yyval.type) = dotag(lookup(), TUNION, autobn);
-		(yyval.type)->link = (yyvsp[(2) - (2)].type);
-		sualign((yyval.type));
-	}
-    break;
-
-  case 203:
-#line 1079 "cc.y"
-    {
-		dotag((yyvsp[(2) - (2)].sym), TENUM, 0);
-		(yyval.type) = (yyvsp[(2) - (2)].sym)->suetag;
-		if((yyval.type)->link == T)
-			(yyval.type)->link = types[TINT];
-		(yyval.type) = (yyval.type)->link;
-	}
-    break;
-
-  case 204:
-#line 1087 "cc.y"
-    {
-		dotag((yyvsp[(2) - (2)].sym), TENUM, autobn);
-	}
-    break;
-
-  case 205:
-#line 1091 "cc.y"
-    {
-		en.tenum = T;
-		en.cenum = T;
-	}
-    break;
-
-  case 206:
-#line 1096 "cc.y"
-    {
-		(yyval.type) = (yyvsp[(2) - (7)].sym)->suetag;
-		if((yyval.type)->link != T)
-			diag(Z, "redeclare tag: %s", (yyvsp[(2) - (7)].sym)->name);
-		if(en.tenum == T) {
-			diag(Z, "enum type ambiguous: %s", (yyvsp[(2) - (7)].sym)->name);
-			en.tenum = types[TINT];
-		}
-		(yyval.type)->link = en.tenum;
-		(yyval.type) = en.tenum;
-	}
-    break;
-
-  case 207:
-#line 1108 "cc.y"
-    {
-		en.tenum = T;
-		en.cenum = T;
-	}
-    break;
-
-  case 208:
-#line 1113 "cc.y"
-    {
-		(yyval.type) = en.tenum;
-	}
-    break;
-
-  case 209:
-#line 1117 "cc.y"
-    {
-		(yyval.type) = tcopy((yyvsp[(1) - (1)].sym)->type);
-	}
-    break;
-
-  case 211:
-#line 1124 "cc.y"
-    {
-		(yyval.lval) = typebitor((yyvsp[(1) - (2)].lval), (yyvsp[(2) - (2)].lval));
-	}
-    break;
-
-  case 212:
-#line 1129 "cc.y"
-    {
-		(yyval.lval) = 0;
-	}
-    break;
-
-  case 213:
-#line 1133 "cc.y"
-    {
-		(yyval.lval) = typebitor((yyvsp[(1) - (2)].lval), (yyvsp[(2) - (2)].lval));
-	}
-    break;
-
-  case 218:
-#line 1145 "cc.y"
-    {
-		(yyval.lval) = typebitor((yyvsp[(1) - (2)].lval), (yyvsp[(2) - (2)].lval));
-	}
-    break;
-
-  case 221:
-#line 1155 "cc.y"
-    {
-		doenum((yyvsp[(1) - (1)].sym), Z);
-	}
-    break;
-
-  case 222:
-#line 1159 "cc.y"
-    {
-		doenum((yyvsp[(1) - (3)].sym), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 225:
-#line 1166 "cc.y"
-    { (yyval.lval) = BCHAR; }
-    break;
-
-  case 226:
-#line 1167 "cc.y"
-    { (yyval.lval) = BSHORT; }
-    break;
-
-  case 227:
-#line 1168 "cc.y"
-    { (yyval.lval) = BINT; }
-    break;
-
-  case 228:
-#line 1169 "cc.y"
-    { (yyval.lval) = BLONG; }
-    break;
-
-  case 229:
-#line 1170 "cc.y"
-    { (yyval.lval) = BSIGNED; }
-    break;
-
-  case 230:
-#line 1171 "cc.y"
-    { (yyval.lval) = BUNSIGNED; }
-    break;
-
-  case 231:
-#line 1172 "cc.y"
-    { (yyval.lval) = BFLOAT; }
-    break;
-
-  case 232:
-#line 1173 "cc.y"
-    { (yyval.lval) = BDOUBLE; }
-    break;
-
-  case 233:
-#line 1174 "cc.y"
-    { (yyval.lval) = BVOID; }
-    break;
-
-  case 234:
-#line 1177 "cc.y"
-    { (yyval.lval) = BAUTO; }
-    break;
-
-  case 235:
-#line 1178 "cc.y"
-    { (yyval.lval) = BSTATIC; }
-    break;
-
-  case 236:
-#line 1179 "cc.y"
-    { (yyval.lval) = BEXTERN; }
-    break;
-
-  case 237:
-#line 1180 "cc.y"
-    { (yyval.lval) = BTYPEDEF; }
-    break;
-
-  case 238:
-#line 1181 "cc.y"
-    { (yyval.lval) = BTYPESTR; }
-    break;
-
-  case 239:
-#line 1182 "cc.y"
-    { (yyval.lval) = BREGISTER; }
-    break;
-
-  case 240:
-#line 1183 "cc.y"
-    { (yyval.lval) = 0; }
-    break;
-
-  case 241:
-#line 1186 "cc.y"
-    { (yyval.lval) = BCONSTNT; }
-    break;
-
-  case 242:
-#line 1187 "cc.y"
-    { (yyval.lval) = BVOLATILE; }
-    break;
-
-  case 243:
-#line 1188 "cc.y"
-    { (yyval.lval) = 0; }
-    break;
-
-  case 244:
-#line 1192 "cc.y"
-    {
-		(yyval.node) = new(ONAME, Z, Z);
-		if((yyvsp[(1) - (1)].sym)->class == CLOCAL)
-			(yyvsp[(1) - (1)].sym) = mkstatic((yyvsp[(1) - (1)].sym));
-		(yyval.node)->sym = (yyvsp[(1) - (1)].sym);
-		(yyval.node)->type = (yyvsp[(1) - (1)].sym)->type;
-		(yyval.node)->etype = TVOID;
-		if((yyval.node)->type != T)
-			(yyval.node)->etype = (yyval.node)->type->etype;
-		(yyval.node)->xoffset = (yyvsp[(1) - (1)].sym)->offset;
-		(yyval.node)->class = (yyvsp[(1) - (1)].sym)->class;
-		(yyvsp[(1) - (1)].sym)->aused = 1;
-	}
-    break;
-
-  case 245:
-#line 1207 "cc.y"
-    {
-		(yyval.node) = new(ONAME, Z, Z);
-		(yyval.node)->sym = (yyvsp[(1) - (1)].sym);
-		(yyval.node)->type = (yyvsp[(1) - (1)].sym)->type;
-		(yyval.node)->etype = TVOID;
-		if((yyval.node)->type != T)
-			(yyval.node)->etype = (yyval.node)->type->etype;
-		(yyval.node)->xoffset = (yyvsp[(1) - (1)].sym)->offset;
-		(yyval.node)->class = (yyvsp[(1) - (1)].sym)->class;
-	}
-    break;
-
-
-/* Line 1267 of yacc.c.  */
-#line 3607 "y.tab.c"
-      default: break;
-    }
-  YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
-
-  YYPOPSTACK (yylen);
-  yylen = 0;
-  YY_STACK_PRINT (yyss, yyssp);
-
-  *++yyvsp = yyval;
-
-
-  /* Now `shift' the result of the reduction.  Determine what state
-     that goes to, based on the state we popped back to and the rule
-     number reduced by.  */
-
-  yyn = yyr1[yyn];
-
-  yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
-  if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
-    yystate = yytable[yystate];
-  else
-    yystate = yydefgoto[yyn - YYNTOKENS];
-
-  goto yynewstate;
-
-
-/*------------------------------------.
-| yyerrlab -- here on detecting error |
-`------------------------------------*/
-yyerrlab:
-  /* If not already recovering from an error, report this error.  */
-  if (!yyerrstatus)
-    {
-      ++yynerrs;
-#if ! YYERROR_VERBOSE
-      yyerror (YY_("syntax error"));
-#else
-      {
-	YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
-	if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
-	  {
-	    YYSIZE_T yyalloc = 2 * yysize;
-	    if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
-	      yyalloc = YYSTACK_ALLOC_MAXIMUM;
-	    if (yymsg != yymsgbuf)
-	      YYSTACK_FREE (yymsg);
-	    yymsg = (char *) YYSTACK_ALLOC (yyalloc);
-	    if (yymsg)
-	      yymsg_alloc = yyalloc;
-	    else
-	      {
-		yymsg = yymsgbuf;
-		yymsg_alloc = sizeof yymsgbuf;
-	      }
-	  }
-
-	if (0 < yysize && yysize <= yymsg_alloc)
-	  {
-	    (void) yysyntax_error (yymsg, yystate, yychar);
-	    yyerror (yymsg);
-	  }
-	else
-	  {
-	    yyerror (YY_("syntax error"));
-	    if (yysize != 0)
-	      goto yyexhaustedlab;
-	  }
-      }
-#endif
-    }
-
-
-
-  if (yyerrstatus == 3)
-    {
-      /* If just tried and failed to reuse look-ahead token after an
-	 error, discard it.  */
-
-      if (yychar <= YYEOF)
-	{
-	  /* Return failure if at end of input.  */
-	  if (yychar == YYEOF)
-	    YYABORT;
-	}
-      else
-	{
-	  yydestruct ("Error: discarding",
-		      yytoken, &yylval);
-	  yychar = YYEMPTY;
-	}
-    }
-
-  /* Else will try to reuse look-ahead token after shifting the error
-     token.  */
-  goto yyerrlab1;
-
-
-/*---------------------------------------------------.
-| yyerrorlab -- error raised explicitly by YYERROR.  |
-`---------------------------------------------------*/
-yyerrorlab:
-
-  /* Pacify compilers like GCC when the user code never invokes
-     YYERROR and the label yyerrorlab therefore never appears in user
-     code.  */
-  if (/*CONSTCOND*/ 0)
-     goto yyerrorlab;
-
-  /* Do not reclaim the symbols of the rule which action triggered
-     this YYERROR.  */
-  YYPOPSTACK (yylen);
-  yylen = 0;
-  YY_STACK_PRINT (yyss, yyssp);
-  yystate = *yyssp;
-  goto yyerrlab1;
-
-
-/*-------------------------------------------------------------.
-| yyerrlab1 -- common code for both syntax error and YYERROR.  |
-`-------------------------------------------------------------*/
-yyerrlab1:
-  yyerrstatus = 3;	/* Each real token shifted decrements this.  */
-
-  for (;;)
-    {
-      yyn = yypact[yystate];
-      if (yyn != YYPACT_NINF)
-	{
-	  yyn += YYTERROR;
-	  if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
-	    {
-	      yyn = yytable[yyn];
-	      if (0 < yyn)
-		break;
-	    }
-	}
-
-      /* Pop the current state because it cannot handle the error token.  */
-      if (yyssp == yyss)
-	YYABORT;
-
-
-      yydestruct ("Error: popping",
-		  yystos[yystate], yyvsp);
-      YYPOPSTACK (1);
-      yystate = *yyssp;
-      YY_STACK_PRINT (yyss, yyssp);
-    }
-
-  if (yyn == YYFINAL)
-    YYACCEPT;
-
-  *++yyvsp = yylval;
-
-
-  /* Shift the error token.  */
-  YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
-
-  yystate = yyn;
-  goto yynewstate;
-
-
-/*-------------------------------------.
-| yyacceptlab -- YYACCEPT comes here.  |
-`-------------------------------------*/
-yyacceptlab:
-  yyresult = 0;
-  goto yyreturn;
-
-/*-----------------------------------.
-| yyabortlab -- YYABORT comes here.  |
-`-----------------------------------*/
-yyabortlab:
-  yyresult = 1;
-  goto yyreturn;
-
-#ifndef yyoverflow
-/*-------------------------------------------------.
-| yyexhaustedlab -- memory exhaustion comes here.  |
-`-------------------------------------------------*/
-yyexhaustedlab:
-  yyerror (YY_("memory exhausted"));
-  yyresult = 2;
-  /* Fall through.  */
-#endif
-
-yyreturn:
-  if (yychar != YYEOF && yychar != YYEMPTY)
-     yydestruct ("Cleanup: discarding lookahead",
-		 yytoken, &yylval);
-  /* Do not reclaim the symbols of the rule which action triggered
-     this YYABORT or YYACCEPT.  */
-  YYPOPSTACK (yylen);
-  YY_STACK_PRINT (yyss, yyssp);
-  while (yyssp != yyss)
-    {
-      yydestruct ("Cleanup: popping",
-		  yystos[*yyssp], yyvsp);
-      YYPOPSTACK (1);
-    }
-#ifndef yyoverflow
-  if (yyss != yyssa)
-    YYSTACK_FREE (yyss);
-#endif
-#if YYERROR_VERBOSE
-  if (yymsg != yymsgbuf)
-    YYSTACK_FREE (yymsg);
-#endif
-  /* Make sure YYID is used.  */
-  return YYID (yyresult);
-}
-
-
-#line 1220 "cc.y"
-
-
diff --git a/src/cmd/cc/y.tab.h b/src/cmd/cc/y.tab.h
deleted file mode 100644
index 32daca9..0000000
--- a/src/cmd/cc/y.tab.h
+++ /dev/null
@@ -1,230 +0,0 @@
-/* A Bison parser, made by GNU Bison 2.3.  */
-
-/* Skeleton interface for Bison's Yacc-like parsers in C
-
-   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
-   Free Software Foundation, Inc.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
-   any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301, USA.  */
-
-/* As a special exception, you may create a larger work that contains
-   part or all of the Bison parser skeleton and distribute that work
-   under terms of your choice, so long as that work isn't itself a
-   parser generator using the skeleton or a modified version thereof
-   as a parser skeleton.  Alternatively, if you modify or redistribute
-   the parser skeleton itself, you may (at your option) remove this
-   special exception, which will cause the skeleton and the resulting
-   Bison output files to be licensed under the GNU General Public
-   License without this special exception.
-
-   This special exception was added by the Free Software Foundation in
-   version 2.2 of Bison.  */
-
-/* Tokens.  */
-#ifndef YYTOKENTYPE
-# define YYTOKENTYPE
-   /* Put the tokens into the symbol table, so that GDB and other debuggers
-      know about them.  */
-   enum yytokentype {
-     LORE = 258,
-     LXORE = 259,
-     LANDE = 260,
-     LLSHE = 261,
-     LRSHE = 262,
-     LMDE = 263,
-     LDVE = 264,
-     LMLE = 265,
-     LME = 266,
-     LPE = 267,
-     LOROR = 268,
-     LANDAND = 269,
-     LNE = 270,
-     LEQ = 271,
-     LGE = 272,
-     LLE = 273,
-     LRSH = 274,
-     LLSH = 275,
-     LMG = 276,
-     LPP = 277,
-     LMM = 278,
-     LNAME = 279,
-     LTYPE = 280,
-     LFCONST = 281,
-     LDCONST = 282,
-     LCONST = 283,
-     LLCONST = 284,
-     LUCONST = 285,
-     LULCONST = 286,
-     LVLCONST = 287,
-     LUVLCONST = 288,
-     LSTRING = 289,
-     LLSTRING = 290,
-     LAUTO = 291,
-     LBREAK = 292,
-     LCASE = 293,
-     LCHAR = 294,
-     LCONTINUE = 295,
-     LDEFAULT = 296,
-     LDO = 297,
-     LDOUBLE = 298,
-     LELSE = 299,
-     LEXTERN = 300,
-     LFLOAT = 301,
-     LFOR = 302,
-     LGOTO = 303,
-     LIF = 304,
-     LINT = 305,
-     LLONG = 306,
-     LPREFETCH = 307,
-     LREGISTER = 308,
-     LRETURN = 309,
-     LSHORT = 310,
-     LSIZEOF = 311,
-     LUSED = 312,
-     LSTATIC = 313,
-     LSTRUCT = 314,
-     LSWITCH = 315,
-     LTYPEDEF = 316,
-     LTYPESTR = 317,
-     LUNION = 318,
-     LUNSIGNED = 319,
-     LWHILE = 320,
-     LVOID = 321,
-     LENUM = 322,
-     LSIGNED = 323,
-     LCONSTNT = 324,
-     LVOLATILE = 325,
-     LSET = 326,
-     LSIGNOF = 327,
-     LRESTRICT = 328,
-     LINLINE = 329
-   };
-#endif
-/* Tokens.  */
-#define LORE 258
-#define LXORE 259
-#define LANDE 260
-#define LLSHE 261
-#define LRSHE 262
-#define LMDE 263
-#define LDVE 264
-#define LMLE 265
-#define LME 266
-#define LPE 267
-#define LOROR 268
-#define LANDAND 269
-#define LNE 270
-#define LEQ 271
-#define LGE 272
-#define LLE 273
-#define LRSH 274
-#define LLSH 275
-#define LMG 276
-#define LPP 277
-#define LMM 278
-#define LNAME 279
-#define LTYPE 280
-#define LFCONST 281
-#define LDCONST 282
-#define LCONST 283
-#define LLCONST 284
-#define LUCONST 285
-#define LULCONST 286
-#define LVLCONST 287
-#define LUVLCONST 288
-#define LSTRING 289
-#define LLSTRING 290
-#define LAUTO 291
-#define LBREAK 292
-#define LCASE 293
-#define LCHAR 294
-#define LCONTINUE 295
-#define LDEFAULT 296
-#define LDO 297
-#define LDOUBLE 298
-#define LELSE 299
-#define LEXTERN 300
-#define LFLOAT 301
-#define LFOR 302
-#define LGOTO 303
-#define LIF 304
-#define LINT 305
-#define LLONG 306
-#define LPREFETCH 307
-#define LREGISTER 308
-#define LRETURN 309
-#define LSHORT 310
-#define LSIZEOF 311
-#define LUSED 312
-#define LSTATIC 313
-#define LSTRUCT 314
-#define LSWITCH 315
-#define LTYPEDEF 316
-#define LTYPESTR 317
-#define LUNION 318
-#define LUNSIGNED 319
-#define LWHILE 320
-#define LVOID 321
-#define LENUM 322
-#define LSIGNED 323
-#define LCONSTNT 324
-#define LVOLATILE 325
-#define LSET 326
-#define LSIGNOF 327
-#define LRESTRICT 328
-#define LINLINE 329
-
-
-
-
-#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-typedef union YYSTYPE
-#line 36 "cc.y"
-{
-	Node*	node;
-	Sym*	sym;
-	Type*	type;
-	struct
-	{
-		Type*	t;
-		uchar	c;
-	} tycl;
-	struct
-	{
-		Type*	t1;
-		Type*	t2;
-		Type*	t3;
-		uchar	c;
-	} tyty;
-	struct
-	{
-		char*	s;
-		int32	l;
-	} sval;
-	int32	lval;
-	double	dval;
-	vlong	vval;
-}
-/* Line 1529 of yacc.c.  */
-#line 223 "y.tab.h"
-	YYSTYPE;
-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
-# define YYSTYPE_IS_DECLARED 1
-# define YYSTYPE_IS_TRIVIAL 1
-#endif
-
-extern YYSTYPE yylval;
-
diff --git a/src/cmd/cgo/ast.go b/src/cmd/cgo/ast.go
index 10e2278..8bbd1cc 100644
--- a/src/cmd/cgo/ast.go
+++ b/src/cmd/cgo/ast.go
@@ -235,9 +235,17 @@ func (f *File) saveExport(x interface{}, context string) {
 			error_(c.Pos(), "export comment has wrong name %q, want %q", name, n.Name.Name)
 		}
 
+		doc := ""
+		for _, c1 := range n.Doc.List {
+			if c1 != c {
+				doc += c1.Text + "\n"
+			}
+		}
+
 		f.ExpFunc = append(f.ExpFunc, &ExpFunc{
 			Func:    n,
 			ExpName: name,
+			Doc:     doc,
 		})
 		break
 	}
diff --git a/src/cmd/cgo/doc.go b/src/cmd/cgo/doc.go
index 6179c7a..b2a5428 100644
--- a/src/cmd/cgo/doc.go
+++ b/src/cmd/cgo/doc.go
@@ -20,16 +20,23 @@ the C parts of the package.  For example:
 	// #include <errno.h>
 	import "C"
 
+The preamble may contain any C code, including function and variable
+declarations and definitions.  These may then be referred to from Go
+code as though they were defined in the package "C".  All names
+declared in the preamble may be used, even if they start with a
+lower-case letter.  Exception: static variables in the preamble may
+not be referenced from Go code; static functions are permitted.
+
 See $GOROOT/misc/cgo/stdio and $GOROOT/misc/cgo/gmp for examples.  See
 "C? Go? Cgo!" for an introduction to using cgo:
-http://golang.org/doc/articles/c_go_cgo.html.
+https://golang.org/doc/articles/c_go_cgo.html.
 
 CFLAGS, CPPFLAGS, CXXFLAGS and LDFLAGS may be defined with pseudo #cgo
 directives within these comments to tweak the behavior of the C or C++
 compiler.  Values defined in multiple directives are concatenated
 together.  The directive can include a list of build constraints limiting its
 effect to systems satisfying one of the constraints
-(see http://golang.org/pkg/go/build/#hdr-Build_Constraints for details about the constraint syntax).
+(see https://golang.org/pkg/go/build/#hdr-Build_Constraints for details about the constraint syntax).
 For example:
 
 	// #cgo CFLAGS: -DPNG_DEBUG=1
@@ -60,6 +67,18 @@ concatenated and used at link time.  All the pkg-config directives are
 concatenated and sent to pkg-config simultaneously to add to each appropriate
 set of command-line flags.
 
+When the cgo directives are parsed, any occurrence of the string ${SRCDIR}
+will be replaced by the absolute path to the directory containing the source
+file. This allows pre-compiled static libraries to be included in the package
+directory and linked properly.
+For example if package foo is in the directory /go/src/foo:
+
+       // #cgo LDFLAGS: -L${SRCDIR}/libs -lfoo
+
+Will be expanded to:
+
+       // #cgo LDFLAGS: -L/go/src/foo/libs -lfoo
+
 When the Go tool sees that one or more Go files use the special import
 "C", it will look for other non-Go files in the directory and compile
 them as part of the Go package.  Any .c, .s, or .S files will be
@@ -71,17 +90,19 @@ compilers may be changed by the CC and CXX environment variables,
 respectively; those environment variables may include command line
 options.
 
-To enable cgo during cross compiling builds, set the CGO_ENABLED
-environment variable to 1 when building the Go tools with make.bash.
-Also, set CC_FOR_TARGET to the C cross compiler for the target.  CC will
-be used for compiling for the host.
-
-After the Go tools are built, when running the go command, CC_FOR_TARGET is
-ignored.  The value of CC_FOR_TARGET when running make.bash is the default
-compiler.  However, you can set the environment variable CC, not CC_FOR_TARGET,
-to control the compiler when running the go tool.
+The cgo tool is enabled by default for native builds on systems where
+it is expected to work.  It is disabled by default when
+cross-compiling.  You can control this by setting the CGO_ENABLED
+environment variable when running the go tool: set it to 1 to enable
+the use of cgo, and to 0 to disable it.  The go tool will set the
+build constraint "cgo" if cgo is enabled.
 
-CXX_FOR_TARGET works in a similar way for C++ code.
+When cross-compiling, you must specify a C cross-compiler for cgo to
+use.  You can do this by setting the CC_FOR_TARGET environment
+variable when building the toolchain using make.bash, or by setting
+the CC environment variable any time you run the go tool.  The
+CXX_FOR_TARGET and CXX environment variables work in a similar way for
+C++ code.
 
 Go references to C
 
@@ -195,16 +216,18 @@ Not all Go types can be mapped to C types in a useful way.
 
 Using //export in a file places a restriction on the preamble:
 since it is copied into two different C output files, it must not
-contain any definitions, only declarations. Definitions must be
-placed in preambles in other files, or in C source files.
+contain any definitions, only declarations. If a file contains both
+definitions and declarations, then the two output files will produce
+duplicate symbols and the linker will fail. To avoid this, definitions
+must be placed in preambles in other files, or in C source files.
 
 Using cgo directly
 
 Usage:
-	go tool cgo [cgo options] [-- compiler options] file.go
+	go tool cgo [cgo options] [-- compiler options] gofiles...
 
-Cgo transforms the input file.go into four output files: two Go source
-files, a C file for 6c (or 8c or 5c), and a C file for gcc.
+Cgo transforms the specified input Go source files into several output
+Go and C source files.
 
 The compiler options are passed through uninterpreted when
 invoking the C compiler to compile the C parts of the package.
@@ -217,18 +240,23 @@ The following options are available when running cgo directly:
 		build when building a cgo package.
 	-dynout file
 		Write -dynimport output to file.
+	-dynpackage package
+		Set Go package for -dynimport output.
 	-dynlinker
 		Write dynamic linker as part of -dynimport output.
 	-godefs
 		Write out input file in Go syntax replacing C package
 		names with real values. Used to generate files in the
 		syscall package when bootstrapping a new target.
-	-cdefs
-		Like -godefs, but write file in C syntax.
-		Used to generate files in the runtime package when
-		bootstrapping a new target.
 	-objdir directory
 		Put all generated files in directory.
+	-importpath string
+		The import path for the Go package. Optional; used for
+		nicer comments in the generated files.
+	-exportheader file
+		If there are any exported functions, write the
+		generated export declarations to file.
+		C code can #include this to see the declarations.
 	-gccgo
 		Generate output for the gccgo compiler rather than the
 		gc compiler.
@@ -363,9 +391,9 @@ the translation process.
 
 Translating Go
 
-[The rest of this comment refers to 6g and 6c, the Go and C compilers
-that are part of the amd64 port of the gc Go toolchain. Everything here
-applies to another architecture's compilers as well.]
+[The rest of this comment refers to 6g, the Go compiler that is part
+of the amd64 port of the gc Go toolchain. Everything here applies to
+another architecture's compilers as well.]
 
 Given the input Go files x.go and y.go, cgo generates these source
 files:
@@ -373,44 +401,41 @@ files:
 	x.cgo1.go       # for 6g
 	y.cgo1.go       # for 6g
 	_cgo_gotypes.go # for 6g
-	_cgo_defun.c    # for 6c
+	_cgo_import.go  # for 6g (if -dynout _cgo_import.go)
 	x.cgo2.c        # for gcc
 	y.cgo2.c        # for gcc
+	_cgo_defun.c    # for gcc (if -gccgo)
 	_cgo_export.c   # for gcc
+	_cgo_export.h   # for gcc
 	_cgo_main.c     # for gcc
+	_cgo_flags      # for alternative build tools
 
 The file x.cgo1.go is a copy of x.go with the import "C" removed and
 references to C.xxx replaced with names like _Cfunc_xxx or _Ctype_xxx.
 The definitions of those identifiers, written as Go functions, types,
 or variables, are provided in _cgo_gotypes.go.
 
-Here is a _cgo_gotypes.go containing definitions for C.flush (provided
-in the preamble) and C.puts (from stdio):
+Here is a _cgo_gotypes.go containing definitions for needed C types:
 
 	type _Ctype_char int8
 	type _Ctype_int int32
 	type _Ctype_void [0]byte
 
-	func _Cfunc_CString(string) *_Ctype_char
-	func _Cfunc_flush() _Ctype_void
-	func _Cfunc_puts(*_Ctype_char) _Ctype_int
-
-For functions, cgo only writes an external declaration in the Go
-output. The implementation is in a combination of C for 6c (meaning
-any gc-toolchain compiler) and C for gcc.
-
-The 6c file contains the definitions of the functions. They all have
-similar bodies that invoke runtime·cgocall to make a switch from the
-Go runtime world to the system C (GCC-based) world.
+The _cgo_gotypes.go file also contains the definitions of the
+functions.  They all have similar bodies that invoke runtime·cgocall
+to make a switch from the Go runtime world to the system C (GCC-based)
+world.
 
 For example, here is the definition of _Cfunc_puts:
 
-	void _cgo_be59f0f25121_Cfunc_puts(void*);
+	//go:cgo_import_static _cgo_be59f0f25121_Cfunc_puts
+	//go:linkname __cgofn__cgo_be59f0f25121_Cfunc_puts _cgo_be59f0f25121_Cfunc_puts
+	var __cgofn__cgo_be59f0f25121_Cfunc_puts byte
+	var _cgo_be59f0f25121_Cfunc_puts = unsafe.Pointer(&__cgofn__cgo_be59f0f25121_Cfunc_puts)
 
-	void
-	·_Cfunc_puts(struct{uint8 x[1];}p)
-	{
-		runtime·cgocall(_cgo_be59f0f25121_Cfunc_puts, &p);
+	func _Cfunc_puts(p0 *_Ctype_char) (r1 _Ctype_int) {
+		_cgo_runtime_cgocall(_cgo_be59f0f25121_Cfunc_puts, uintptr(unsafe.Pointer(&p0)))
+		return
 	}
 
 The hexadecimal number is a hash of cgo's input, chosen to be
@@ -421,6 +446,7 @@ file compiled by gcc, the file x.cgo2.c:
 	void
 	_cgo_be59f0f25121_Cfunc_puts(void *v)
 	{
+		_cgo_wait_runtime_init_done();
 		struct {
 			char* p0;
 			int r;
@@ -429,7 +455,8 @@ file compiled by gcc, the file x.cgo2.c:
 		a->r = puts((void*)a->p0);
 	}
 
-It extracts the arguments from the pointer to _Cfunc_puts's argument
+It waits for Go runtime to be initialized (required for shared libraries),
+extracts the arguments from the pointer to _Cfunc_puts's argument
 frame, invokes the system C function (in this case, puts), stores the
 result in the frame, and returns.
 
@@ -448,6 +475,7 @@ _cgo_main.c:
 
 	int main() { return 0; }
 	void crosscall2(void(*fn)(void*, int), void *a, int c) { }
+	void _cgo_wait_runtime_init_done() { }
 	void _cgo_allocate(void *a, int c) { }
 	void _cgo_panic(void *a, int c) { }
 
@@ -456,23 +484,21 @@ code generated for gcc. The build process links this stub, along with
 _cgo_export.c and *.cgo2.c, into a dynamic executable and then lets
 cgo examine the executable. Cgo records the list of shared library
 references and resolved names and writes them into a new file
-_cgo_import.c, which looks like:
+_cgo_import.go, which looks like:
 
-	#pragma cgo_dynamic_linker "/lib64/ld-linux-x86-64.so.2"
-	#pragma cgo_import_dynamic puts puts#GLIBC_2.2.5 "libc.so.6"
-	#pragma cgo_import_dynamic __libc_start_main __libc_start_main#GLIBC_2.2.5 "libc.so.6"
-	#pragma cgo_import_dynamic stdout stdout#GLIBC_2.2.5 "libc.so.6"
-	#pragma cgo_import_dynamic fflush fflush#GLIBC_2.2.5 "libc.so.6"
-	#pragma cgo_import_dynamic _ _ "libpthread.so.0"
-	#pragma cgo_import_dynamic _ _ "libc.so.6"
+	//go:cgo_dynamic_linker "/lib64/ld-linux-x86-64.so.2"
+	//go:cgo_import_dynamic puts puts#GLIBC_2.2.5 "libc.so.6"
+	//go:cgo_import_dynamic __libc_start_main __libc_start_main#GLIBC_2.2.5 "libc.so.6"
+	//go:cgo_import_dynamic stdout stdout#GLIBC_2.2.5 "libc.so.6"
+	//go:cgo_import_dynamic fflush fflush#GLIBC_2.2.5 "libc.so.6"
+	//go:cgo_import_dynamic _ _ "libpthread.so.0"
+	//go:cgo_import_dynamic _ _ "libc.so.6"
 
 In the end, the compiled Go package, which will eventually be
 presented to 6l as part of a larger program, contains:
 
-	_go_.6        # 6g-compiled object for _cgo_gotypes.go *.cgo1.go
-	_cgo_defun.6  # 6c-compiled object for _cgo_defun.c
+	_go_.6        # 6g-compiled object for _cgo_gotypes.go, _cgo_import.go, *.cgo1.go
 	_all.o        # gcc-compiled object for _cgo_export.c, *.cgo2.c
-	_cgo_import.6 # 6c-compiled object for _cgo_import.c
 
 The final program will be a dynamic executable, so that 6l can avoid
 needing to process arbitrary .o files. It only needs to process the .o
@@ -496,20 +522,21 @@ Runtime
 
 When using cgo, Go must not assume that it owns all details of the
 process. In particular it needs to coordinate with C in the use of
-threads and thread-local storage. The runtime package, in its own
-(6c-compiled) C code, declares a few uninitialized (default bss)
+threads and thread-local storage. The runtime package declares a few
 variables:
 
-	bool	runtime·iscgo;
-	void	(*libcgo_thread_start)(void*);
-	void	(*initcgo)(G*);
+	var (
+		iscgo             bool
+		_cgo_init         unsafe.Pointer
+		_cgo_thread_start unsafe.Pointer
+	)
 
 Any package using cgo imports "runtime/cgo", which provides
-initializations for these variables. It sets iscgo to 1, initcgo to a
-gcc-compiled function that can be called early during program startup,
-and libcgo_thread_start to a gcc-compiled function that can be used to
-create a new thread, in place of the runtime's usual direct system
-calls.
+initializations for these variables. It sets iscgo to true, _cgo_init
+to a gcc-compiled function that can be called early during program
+startup, and _cgo_thread_start to a gcc-compiled function that can be
+used to create a new thread, in place of the runtime's usual direct
+system calls.
 
 Internal and External Linking
 
@@ -522,12 +549,12 @@ code can only be used as a dynamic library). On the other hand, when
 using internal linking, 6l can generate Go binaries by itself.
 
 In order to allow linking arbitrary object files without requiring
-dynamic libraries, cgo will soon support an "external" linking mode
-too. In external linking mode, 6l does not process any host object
-files. Instead, it collects all the Go code and writes a single go.o
-object file containing it. Then it invokes the host linker (usually
-gcc) to combine the go.o object file and any supporting non-Go code
-into a final executable. External linking avoids the dynamic library
+dynamic libraries, cgo supports an "external" linking mode too. In
+external linking mode, 6l does not process any host object files.
+Instead, it collects all the Go code and writes a single go.o object
+file containing it. Then it invokes the host linker (usually gcc) to
+combine the go.o object file and any supporting non-Go code into a
+final executable. External linking avoids the dynamic library
 requirement but introduces a requirement that the host linker be
 present to create such a binary.
 
@@ -555,13 +582,13 @@ to be made when linking the final binary.
 Linking Directives
 
 In either linking mode, package-specific directives must be passed
-through to 6l. These are communicated by writing #pragma directives
-in a C source file compiled by 6c. The directives are copied into the .6 object file
-and then processed by the linker.
+through to 6l. These are communicated by writing //go: directives in a
+Go source file compiled by 6g. The directives are copied into the .6
+object file and then processed by the linker.
 
 The directives are:
 
-#pragma cgo_import_dynamic <local> [<remote> ["<library>"]]
+//go:cgo_import_dynamic <local> [<remote> ["<library>"]]
 
 	In internal linking mode, allow an unresolved reference to
 	<local>, assuming it will be resolved by a dynamic library
@@ -572,9 +599,9 @@ The directives are:
 	In the <remote>, # or @ can be used to introduce a symbol version.
 
 	Examples:
-	#pragma cgo_import_dynamic puts
-	#pragma cgo_import_dynamic puts puts#GLIBC_2.2.5
-	#pragma cgo_import_dynamic puts puts#GLIBC_2.2.5 "libc.so.6"
+	//go:cgo_import_dynamic puts
+	//go:cgo_import_dynamic puts puts#GLIBC_2.2.5
+	//go:cgo_import_dynamic puts puts#GLIBC_2.2.5 "libc.so.6"
 
 	A side effect of the cgo_import_dynamic directive with a
 	library is to make the final binary depend on that dynamic
@@ -582,12 +609,12 @@ The directives are:
 	symbols, use _ for local and remote.
 
 	Example:
-	#pragma cgo_import_dynamic _ _ "libc.so.6"
+	//go:cgo_import_dynamic _ _ "libc.so.6"
 
 	For compatibility with current versions of SWIG,
-	#pragma dynimport is an alias for #pragma cgo_import_dynamic.
+	#pragma dynimport is an alias for //go:cgo_import_dynamic.
 
-#pragma cgo_dynamic_linker "<path>"
+//go:cgo_dynamic_linker "<path>"
 
 	In internal linking mode, use "<path>" as the dynamic linker
 	in the final binary. This directive is only needed from one
@@ -595,9 +622,9 @@ The directives are:
 	supplied by runtime/cgo.
 
 	Example:
-	#pragma cgo_dynamic_linker "/lib/ld-linux.so.2"
+	//go:cgo_dynamic_linker "/lib/ld-linux.so.2"
 
-#pragma cgo_export_dynamic <local> <remote>
+//go:cgo_export_dynamic <local> <remote>
 
 	In internal linking mode, put the Go symbol
 	named <local> into the program's exported symbol table as
@@ -606,9 +633,9 @@ The directives are:
 	to share Go's data.
 
 	For compatibility with current versions of SWIG,
-	#pragma dynexport is an alias for #pragma cgo_export_dynamic.
+	#pragma dynexport is an alias for //go:cgo_export_dynamic.
 
-#pragma cgo_import_static <local>
+//go:cgo_import_static <local>
 
 	In external linking mode, allow unresolved references to
 	<local> in the go.o object file prepared for the host linker,
@@ -616,9 +643,9 @@ The directives are:
 	other object files that will be linked with go.o.
 
 	Example:
-	#pragma cgo_import_static puts_wrapper
+	//go:cgo_import_static puts_wrapper
 
-#pragma cgo_export_static <local> <remote>
+//go:cgo_export_static <local> <remote>
 
 	In external linking mode, put the Go symbol
 	named <local> into the program's exported symbol table as
@@ -626,15 +653,15 @@ The directives are:
 	mechanism makes it possible for C code to call back into Go or
 	to share Go's data.
 
-#pragma cgo_ldflag "<arg>"
+//go:cgo_ldflag "<arg>"
 
 	In external linking mode, invoke the host linker (usually gcc)
 	with "<arg>" as a command-line argument following the .o files.
 	Note that the arguments are for "gcc", not "ld".
 
 	Example:
-	#pragma cgo_ldflag "-lpthread"
-	#pragma cgo_ldflag "-L/usr/local/sqlite3/lib"
+	//go:cgo_ldflag "-lpthread"
+	//go:cgo_ldflag "-L/usr/local/sqlite3/lib"
 
 A package compiled with cgo will include directives for both
 internal and external linking; the linker will select the appropriate
@@ -647,22 +674,18 @@ The following code will be generated by cgo:
 
 	// compiled by 6g
 
-	type _Ctype_double float64
-	func _Cfunc_sin(_Ctype_double) _Ctype_double
-
-	// compiled by 6c
+	//go:cgo_ldflag "-lm"
 
-	#pragma cgo_import_dynamic sin sin#GLIBC_2.2.5 "libm.so.6"
-
-	#pragma cgo_import_static _cgo_gcc_Cfunc_sin
-	#pragma cgo_ldflag "-lm"
+	type _Ctype_double float64
 
-	void _cgo_gcc_Cfunc_sin(void*);
+	//go:cgo_import_static _cgo_gcc_Cfunc_sin
+	//go:linkname __cgo_gcc_Cfunc_sin _cgo_gcc_Cfunc_sin
+	var __cgo_gcc_Cfunc_sin byte
+	var _cgo_gcc_Cfunc_sin = unsafe.Pointer(&__cgo_gcc_Cfunc_sin)
 
-	void
-	·_Cfunc_sin(struct{uint8 x[16];}p)
-	{
-		runtime·cgocall(_cgo_gcc_Cfunc_sin, &p);
+	func _Cfunc_sin(p0 _Ctype_double) (r1 _Ctype_double) {
+		_cgo_runtime_cgocall(_cgo_gcc_Cfunc_sin, uintptr(unsafe.Pointer(&p0)))
+		return
 	}
 
 	// compiled by gcc, into foo.cgo2.o
@@ -682,8 +705,8 @@ using the internal or external mode. If other packages are compiled in
 "external only" mode, then the final link will be an external one.
 Otherwise the link will be an internal one.
 
-The directives in the 6c-compiled file are used according to the kind
-of final link used.
+The linking directives are used according to the kind of final link
+used.
 
 In internal mode, 6l itself processes all the host object files, in
 particular foo.cgo2.o. To do so, it uses the cgo_import_dynamic and
@@ -694,10 +717,10 @@ symbol sin with version GLIBC_2.2.5 from the dynamic library
 runtime dynamic linker.
 
 In external mode, 6l does not process any host object files, in
-particular foo.cgo2.o. It links together the 6g- and 6c-generated
-object files, along with any other Go code, into a go.o file. While
-doing that, 6l will discover that there is no definition for
-_cgo_gcc_Cfunc_sin, referred to by the 6c-compiled source file. This
+particular foo.cgo2.o. It links together the 6g-generated object
+files, along with any other Go code, into a go.o file. While doing
+that, 6l will discover that there is no definition for
+_cgo_gcc_Cfunc_sin, referred to by the 6g-compiled source file. This
 is okay, because 6l also processes the cgo_import_static directive and
 knows that _cgo_gcc_Cfunc_sin is expected to be supplied by a host
 object file, so 6l does not treat the missing symbol as an error when
diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go
index abdd369..b64849a 100644
--- a/src/cmd/cgo/gcc.go
+++ b/src/cmd/cgo/gcc.go
@@ -154,20 +154,6 @@ func splitQuoted(s string) (r []string, err error) {
 	return args, err
 }
 
-var safeBytes = []byte(`+-.,/0123456789:=ABCDEFGHIJKLMNOPQRSTUVWXYZ\_abcdefghijklmnopqrstuvwxyz`)
-
-func safeName(s string) bool {
-	if s == "" {
-		return false
-	}
-	for i := 0; i < len(s); i++ {
-		if c := s[i]; c < 0x80 && bytes.IndexByte(safeBytes, c) < 0 {
-			return false
-		}
-	}
-	return true
-}
-
 // Translate rewrites f.AST, the original Go input, to remove
 // references to the imported package C, replacing them with
 // references to the equivalent Go types, functions, and variables.
@@ -213,6 +199,10 @@ func (p *Package) loadDefines(f *File) {
 			val = strings.TrimSpace(line[tabIndex:])
 		}
 
+		if key == "__clang__" {
+			p.GccIsClang = true
+		}
+
 		if n := f.Name[key]; n != nil {
 			if *debugDefine {
 				fmt.Fprintf(os.Stderr, "#define %s %s\n", key, val)
@@ -582,7 +572,7 @@ func (p *Package) mangleName(n *Name) {
 
 // rewriteRef rewrites all the C.xxx references in f.AST to refer to the
 // Go equivalents, now that we have figured out the meaning of all
-// the xxx.  In *godefs or *cdefs mode, rewriteRef replaces the names
+// the xxx.  In *godefs mode, rewriteRef replaces the names
 // with full definitions instead of mangled names.
 func (p *Package) rewriteRef(f *File) {
 	// Keep a list of all the functions, to remove the ones
@@ -673,6 +663,13 @@ func (p *Package) rewriteRef(f *File) {
 				expr = &ast.StarExpr{Star: (*r.Expr).Pos(), X: expr}
 			}
 
+		case "selector":
+			if r.Name.Kind == "var" {
+				expr = &ast.StarExpr{Star: (*r.Expr).Pos(), X: expr}
+			} else {
+				error_(r.Pos(), "only C variables allowed in selector expression", fixGo(r.Name.Go))
+			}
+
 		case "type":
 			if r.Name.Kind != "type" {
 				error_(r.Pos(), "expression C.%s used as type", fixGo(r.Name.Go))
@@ -688,7 +685,7 @@ func (p *Package) rewriteRef(f *File) {
 				error_(r.Pos(), "must call C.%s", fixGo(r.Name.Go))
 			}
 		}
-		if *godefs || *cdefs {
+		if *godefs {
 			// Substitute definition for mangled type name.
 			if id, ok := expr.(*ast.Ident); ok {
 				if t := typedef[id.Name]; t != nil {
@@ -746,6 +743,10 @@ func (p *Package) gccMachine() []string {
 		return []string{"-m32"}
 	case "arm":
 		return []string{"-marm"} // not thumb
+	case "s390":
+		return []string{"-m31"}
+	case "s390x":
+		return []string{"-m64"}
 	}
 	return nil
 }
@@ -765,7 +766,7 @@ func (p *Package) gccCmd() []string {
 		"-c",          // do not link
 		"-xc",         // input language is C
 	)
-	if strings.Contains(c[0], "clang") {
+	if p.GccIsClang {
 		c = append(c,
 			"-ferror-limit=0",
 			// Apple clang version 1.7 (tags/Apple/clang-77) (based on LLVM 2.9svn)
@@ -780,7 +781,7 @@ func (p *Package) gccCmd() []string {
 			// incorrectly typed unsigned long. We work around that
 			// by disabling the builtin functions (this is safe as
 			// it won't affect the actual compilation of the C code).
-			// See: http://golang.org/issue/6506.
+			// See: https://golang.org/issue/6506.
 			"-fno-builtin",
 		)
 	}
@@ -992,8 +993,8 @@ func (c *typeConv) Init(ptrSize, intSize int64) {
 	c.goVoid = c.Ident("_Ctype_void")
 
 	// Normally cgo translates void* to unsafe.Pointer,
-	// but for historical reasons -cdefs and -godefs use *byte instead.
-	if *cdefs || *godefs {
+	// but for historical reasons -godefs uses *byte instead.
+	if *godefs {
 		c.goVoidPtr = &ast.StarExpr{X: c.byte}
 	} else {
 		c.goVoidPtr = c.Ident("unsafe.Pointer")
@@ -1045,7 +1046,7 @@ func (tr *TypeRepr) String() string {
 	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
 }
@@ -1334,8 +1335,8 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
 		// If sub.Go.Name is "_Ctype_struct_foo" or "_Ctype_union_foo" or "_Ctype_class_foo",
 		// use that as the Go form for this typedef too, so that the typedef will be interchangeable
 		// with the base type.
-		// In -godefs and -cdefs mode, do this for all typedefs.
-		if isStructUnionClass(sub.Go) || *godefs || *cdefs {
+		// In -godefs mode, do this for all typedefs.
+		if isStructUnionClass(sub.Go) || *godefs {
 			t.Go = sub.Go
 
 			if isStructUnionClass(sub.Go) {
@@ -1397,7 +1398,7 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
 			name := c.Ident("_Ctype_" + s)
 			tt := *t
 			typedef[name.Name] = &tt
-			if !*godefs && !*cdefs {
+			if !*godefs {
 				t.Go = name
 			}
 		}
@@ -1543,14 +1544,16 @@ func (c *typeConv) intExpr(n int64) ast.Expr {
 }
 
 // Add padding of given size to fld.
-func (c *typeConv) pad(fld []*ast.Field, size int64) []*ast.Field {
+func (c *typeConv) pad(fld []*ast.Field, sizes []int64, size int64) ([]*ast.Field, []int64) {
 	n := len(fld)
 	fld = fld[0 : n+1]
 	fld[n] = &ast.Field{Names: []*ast.Ident{c.Ident("_")}, Type: c.Opaque(size)}
-	return fld
+	sizes = sizes[0 : n+1]
+	sizes[n] = size
+	return fld, sizes
 }
 
-// Struct conversion: return Go and (6g) C syntax for type.
+// Struct conversion: return Go and (gc) C syntax for type.
 func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.StructType, csyntax string, align int64) {
 	// Minimum alignment for a struct is 1 byte.
 	align = 1
@@ -1558,6 +1561,7 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
 	var buf bytes.Buffer
 	buf.WriteString("struct {")
 	fld := make([]*ast.Field, 0, 2*len(dt.Field)+1) // enough for padding around every field
+	sizes := make([]int64, 0, 2*len(dt.Field)+1)
 	off := int64(0)
 
 	// Rename struct fields that happen to be named Go keywords into
@@ -1573,7 +1577,7 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
 		used[f.Name] = true
 	}
 
-	if !*godefs && !*cdefs {
+	if !*godefs {
 		for cid, goid := range ident {
 			if token.Lookup(goid).IsKeyword() {
 				// Avoid keyword
@@ -1593,19 +1597,19 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
 	anon := 0
 	for _, f := range dt.Field {
 		if f.ByteOffset > off {
-			fld = c.pad(fld, f.ByteOffset-off)
+			fld, sizes = c.pad(fld, sizes, f.ByteOffset-off)
 			off = f.ByteOffset
 		}
 
 		name := f.Name
 		ft := f.Type
 
-		// In godefs or cdefs mode, if this field is a C11
+		// In godefs mode, if this field is a C11
 		// anonymous union then treat the first field in the
 		// union as the field in the struct.  This handles
 		// cases like the glibc <sys/resource.h> file; see
 		// issue 6677.
-		if *godefs || *cdefs {
+		if *godefs {
 			if st, ok := f.Type.(*dwarf.StructType); ok && name == "" && st.Kind == "union" && len(st.Field) > 0 && !used[st.Field[0].Name] {
 				name = st.Field[0].Name
 				ident[name] = name
@@ -1635,14 +1639,12 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
 			talign = size
 		}
 
-		if talign > 0 && f.ByteOffset%talign != 0 && !*cdefs {
+		if talign > 0 && f.ByteOffset%talign != 0 {
 			// Drop misaligned fields, the same way we drop integer bit fields.
 			// The goal is to make available what can be made available.
 			// Otherwise one bad and unneeded field in an otherwise okay struct
 			// makes the whole program not compile. Much of the time these
 			// structs are in system headers that cannot be corrected.
-			// Exception: In -cdefs mode, we use #pragma pack, so misaligned
-			// fields should still work.
 			continue
 		}
 		n := len(fld)
@@ -1653,6 +1655,8 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
 			ident[name] = name
 		}
 		fld[n] = &ast.Field{Names: []*ast.Ident{c.Ident(ident[name])}, Type: tgo}
+		sizes = sizes[0 : n+1]
+		sizes[n] = size
 		off += size
 		buf.WriteString(t.C.String())
 		buf.WriteString(" ")
@@ -1663,16 +1667,29 @@ func (c *typeConv) Struct(dt *dwarf.StructType, pos token.Pos) (expr *ast.Struct
 		}
 	}
 	if off < dt.ByteSize {
-		fld = c.pad(fld, dt.ByteSize-off)
+		fld, sizes = c.pad(fld, sizes, dt.ByteSize-off)
 		off = dt.ByteSize
 	}
+
+	// If the last field in a non-zero-sized struct is zero-sized
+	// the compiler is going to pad it by one (see issue 9401).
+	// We can't permit that, because then the size of the Go
+	// struct will not be the same as the size of the C struct.
+	// Our only option in such a case is to remove the field,
+	// which means that it can not be referenced from Go.
+	for off > 0 && sizes[len(sizes)-1] == 0 {
+		n := len(sizes)
+		fld = fld[0 : n-1]
+		sizes = sizes[0 : n-1]
+	}
+
 	if off != dt.ByteSize {
 		fatalf("%s: struct size calculation error off=%d bytesize=%d", lineno(pos), off, dt.ByteSize)
 	}
 	buf.WriteString("}")
 	csyntax = buf.String()
 
-	if *godefs || *cdefs {
+	if *godefs {
 		godefsFields(fld)
 	}
 	expr = &ast.StructType{Fields: &ast.FieldList{List: fld}}
@@ -1707,9 +1724,7 @@ func godefsFields(fld []*ast.Field) {
 				n.Name = "Pad_cgo_" + strconv.Itoa(npad)
 				npad++
 			}
-			if !*cdefs {
-				n.Name = upper(n.Name)
-			}
+			n.Name = upper(n.Name)
 		}
 	}
 }
@@ -1721,9 +1736,6 @@ func godefsFields(fld []*ast.Field) {
 // package syscall's data structures, we drop a common prefix
 // (so sec, usec, which will get turned into Sec, Usec for exporting).
 func fieldPrefix(fld []*ast.Field) string {
-	if *cdefs {
-		return ""
-	}
 	prefix := ""
 	for _, f := range fld {
 		for _, n := range f.Names {
diff --git a/src/cmd/cgo/godefs.go b/src/cmd/cgo/godefs.go
index ce5ac27..1b0ece2 100644
--- a/src/cmd/cgo/godefs.go
+++ b/src/cmd/cgo/godefs.go
@@ -114,173 +114,6 @@ func (p *Package) godefs(f *File, srcfile string) string {
 	return buf.String()
 }
 
-// cdefs returns the output for -cdefs mode.
-// The easiest way to do this is to translate the godefs Go to C.
-func (p *Package) cdefs(f *File, srcfile string) string {
-	godefsOutput := p.godefs(f, srcfile)
-
-	lines := strings.Split(godefsOutput, "\n")
-	lines[0] = "// Created by cgo -cdefs - DO NOT EDIT"
-
-	for i, line := range lines {
-		lines[i] = strings.TrimSpace(line)
-	}
-
-	var out bytes.Buffer
-	printf := func(format string, args ...interface{}) { fmt.Fprintf(&out, format, args...) }
-
-	didTypedef := false
-	for i := 0; i < len(lines); i++ {
-		line := lines[i]
-
-		// Delete
-		//	package x
-		if strings.HasPrefix(line, "package ") {
-			continue
-		}
-
-		// Convert
-		//	const (
-		//		A = 1
-		//		B = 2
-		//	)
-		//
-		// to
-		//
-		//	enum {
-		//		A = 1,
-		//		B = 2,
-		//	};
-		if line == "const (" {
-			printf("enum {\n")
-			for i++; i < len(lines) && lines[i] != ")"; i++ {
-				line = lines[i]
-				if line != "" {
-					printf("\t%s,", line)
-				}
-				printf("\n")
-			}
-			printf("};\n")
-			continue
-		}
-
-		// Convert
-		//	const A = 1
-		// to
-		//	enum { A = 1 };
-		if strings.HasPrefix(line, "const ") {
-			printf("enum { %s };\n", line[len("const "):])
-			continue
-		}
-
-		// On first type definition, typedef all the structs
-		// in case there are dependencies between them.
-		if !didTypedef && strings.HasPrefix(line, "type ") {
-			didTypedef = true
-			for _, line := range lines {
-				line = strings.TrimSpace(line)
-				if strings.HasPrefix(line, "type ") && strings.HasSuffix(line, " struct {") {
-					s := strings.TrimSuffix(strings.TrimPrefix(line, "type "), " struct {")
-					printf("typedef struct %s %s;\n", s, s)
-				}
-			}
-			printf("\n")
-			printf("#pragma pack on\n")
-			printf("\n")
-		}
-
-		// Convert
-		//	type T struct {
-		//		X int64
-		//		Y *int32
-		//		Z [4]byte
-		//	}
-		//
-		// to
-		//
-		//	struct T {
-		//		int64 X;
-		//		int32 *Y;
-		//		byte Z[4];
-		//	}
-		if strings.HasPrefix(line, "type ") && strings.HasSuffix(line, " struct {") {
-			if len(lines) > i+1 && lines[i+1] == "}" {
-				// do not output empty struct
-				i++
-				continue
-			}
-			s := line[len("type ") : len(line)-len(" struct {")]
-			printf("struct %s {\n", s)
-			for i++; i < len(lines) && lines[i] != "}"; i++ {
-				line := lines[i]
-				if line != "" {
-					f := strings.Fields(line)
-					if len(f) != 2 {
-						fmt.Fprintf(os.Stderr, "cgo: cannot parse struct field: %s\n", line)
-						nerrors++
-						continue
-					}
-					printf("\t%s;", cdecl(f[0], f[1]))
-				}
-				printf("\n")
-			}
-			printf("};\n")
-			continue
-		}
-
-		// Convert
-		//	type T int
-		// to
-		//	typedef int T;
-		if strings.HasPrefix(line, "type ") {
-			f := strings.Fields(line[len("type "):])
-			if len(f) != 2 {
-				fmt.Fprintf(os.Stderr, "cgo: cannot parse type definition: %s\n", line)
-				nerrors++
-				continue
-			}
-			printf("typedef\t%s;\n", cdecl(f[0], f[1]))
-			continue
-		}
-
-		printf("%s\n", line)
-	}
-
-	if didTypedef {
-		printf("\n")
-		printf("#pragma pack off\n")
-	}
-
-	return out.String()
-}
-
-// cdecl returns the C declaration for the given Go name and type.
-// It only handles the specific cases necessary for converting godefs output.
-func cdecl(name, typ string) string {
-	// X *[0]byte -> X *void
-	if strings.HasPrefix(typ, "*[0]") {
-		typ = "*void"
-	}
-	// X [4]byte -> X[4] byte
-	for strings.HasPrefix(typ, "[") {
-		i := strings.Index(typ, "]") + 1
-		name = name + typ[:i]
-		typ = typ[i:]
-	}
-	// X *byte -> *X byte
-	for strings.HasPrefix(typ, "*") {
-		name = "*" + name
-		typ = typ[1:]
-	}
-	// X T -> T X
-	// Handle the special case: 'unsafe.Pointer' is 'void *'
-	if typ == "unsafe.Pointer" {
-		typ = "void"
-		name = "*" + name
-	}
-	return typ + "\t" + name
-}
-
 var gofmtBuf bytes.Buffer
 
 // gofmt returns the gofmt-formatted string for an AST node.
diff --git a/src/cmd/cgo/main.go b/src/cmd/cgo/main.go
index 17b0cdd..02d297c 100644
--- a/src/cmd/cgo/main.go
+++ b/src/cmd/cgo/main.go
@@ -6,7 +6,7 @@
 
 // TODO(rsc):
 //	Emit correct line number annotations.
-//	Make 6g understand the annotations.
+//	Make gc understand the annotations.
 
 package main
 
@@ -33,6 +33,7 @@ type Package struct {
 	PtrSize     int64
 	IntSize     int64
 	GccOptions  []string
+	GccIsClang  bool
 	CgoFlags    map[string][]string // #cgo flags (CFLAGS, LDFLAGS)
 	Written     map[string]bool
 	Name        map[string]*Name // accumulated Name from Files
@@ -87,7 +88,7 @@ type Name struct {
 	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"
 }
@@ -98,6 +99,7 @@ func (n *Name) IsVar() bool {
 type ExpFunc struct {
 	Func    *ast.FuncDecl
 	ExpName string // name to use from C
+	Doc     string
 }
 
 // A TypeRepr contains the string representation of a type.
@@ -130,15 +132,25 @@ func usage() {
 }
 
 var ptrSizeMap = map[string]int64{
-	"386":   4,
-	"amd64": 8,
-	"arm":   4,
+	"386":     4,
+	"amd64":   8,
+	"arm":     4,
+	"arm64":   8,
+	"ppc64":   8,
+	"ppc64le": 8,
+	"s390":    4,
+	"s390x":   8,
 }
 
 var intSizeMap = map[string]int64{
-	"386":   4,
-	"amd64": 8,
-	"arm":   4,
+	"386":     4,
+	"amd64":   8,
+	"arm":     4,
+	"arm64":   8,
+	"ppc64":   8,
+	"ppc64le": 8,
+	"s390":    4,
+	"s390x":   4,
 }
 
 var cPrefix string
@@ -146,15 +158,18 @@ var cPrefix string
 var fset = token.NewFileSet()
 
 var dynobj = flag.String("dynimport", "", "if non-empty, print dynamic import data for that file")
-var dynout = flag.String("dynout", "", "write -dynobj output to this file")
-var dynlinker = flag.Bool("dynlinker", false, "record dynamic linker information in dynimport mode")
+var dynout = flag.String("dynout", "", "write -dynimport output to this file")
+var dynpackage = flag.String("dynpackage", "main", "set Go package for -dynimport output")
+var dynlinker = flag.Bool("dynlinker", false, "record dynamic linker information in -dynimport mode")
 
-// These flags are for bootstrapping a new Go implementation,
-// to generate Go and C headers that match the data layout and
+// This flag is for bootstrapping a new Go implementation,
+// to generate Go types that match the data layout and
 // constant values used in the host's C libraries and system calls.
 var godefs = flag.Bool("godefs", false, "for bootstrap: write Go definitions for C file to standard output")
-var cdefs = flag.Bool("cdefs", false, "for bootstrap: write C definitions for C file to standard output")
+
 var objDir = flag.String("objdir", "", "object directory")
+var importPath = flag.String("importpath", "", "import path of package being built (for comments in generated files)")
+var exportHeader = flag.String("exportheader", "", "where to write export header if any exported functions")
 
 var gccgo = flag.Bool("gccgo", false, "generate files for use with gccgo")
 var gccgoprefix = flag.String("gccgoprefix", "", "-fgo-prefix option used with gccgo")
@@ -180,12 +195,7 @@ func main() {
 		return
 	}
 
-	if *godefs && *cdefs {
-		fmt.Fprintf(os.Stderr, "cgo: cannot use -cdefs and -godefs together\n")
-		os.Exit(2)
-	}
-
-	if *godefs || *cdefs {
+	if *godefs {
 		// Generating definitions pulled from header files,
 		// to be checked into Go repositories.
 		// Line numbers are just noise.
@@ -277,14 +287,12 @@ func main() {
 		p.Record(f)
 		if *godefs {
 			os.Stdout.WriteString(p.godefs(f, input))
-		} else if *cdefs {
-			os.Stdout.WriteString(p.cdefs(f, input))
 		} else {
 			p.writeOutput(f, input)
 		}
 	}
 
-	if !*godefs && !*cdefs {
+	if !*godefs {
 		p.writeDefs()
 	}
 	if nerrors > 0 {
diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go
index d92bed9..90a7441 100644
--- a/src/cmd/cgo/out.go
+++ b/src/cmd/cgo/out.go
@@ -13,6 +13,7 @@ import (
 	"go/ast"
 	"go/printer"
 	"go/token"
+	"io"
 	"os"
 	"sort"
 	"strings"
@@ -20,11 +21,17 @@ import (
 
 var conf = printer.Config{Mode: printer.SourcePos, Tabwidth: 8}
 
-// writeDefs creates output files to be compiled by 6g, 6c, and gcc.
-// (The comments here say 6g and 6c but the code applies to the 8 and 5 tools too.)
+// writeDefs creates output files to be compiled by gc and gcc.
 func (p *Package) writeDefs() {
-	fgo2 := creat(*objDir + "_cgo_gotypes.go")
-	fc := creat(*objDir + "_cgo_defun.c")
+	var fgo2, fc io.Writer
+	f := creat(*objDir + "_cgo_gotypes.go")
+	defer f.Close()
+	fgo2 = f
+	if *gccgo {
+		f := creat(*objDir + "_cgo_defun.c")
+		defer f.Close()
+		fc = f
+	}
 	fm := creat(*objDir + "_cgo_main.c")
 
 	var gccgoInit bytes.Buffer
@@ -34,7 +41,7 @@ func (p *Package) writeDefs() {
 		fmt.Fprintf(fflg, "_CGO_%s=%s\n", k, strings.Join(v, " "))
 		if k == "LDFLAGS" && !*gccgo {
 			for _, arg := range v {
-				fmt.Fprintf(fc, "#pragma cgo_ldflag %q\n", arg)
+				fmt.Fprintf(fgo2, "//go:cgo_ldflag %q\n", arg)
 			}
 		}
 	}
@@ -44,14 +51,17 @@ func (p *Package) writeDefs() {
 	fmt.Fprintf(fm, "int main() { return 0; }\n")
 	if *importRuntimeCgo {
 		fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int), void *a, int c) { }\n")
+		fmt.Fprintf(fm, "void _cgo_wait_runtime_init_done() { }\n")
 		fmt.Fprintf(fm, "char* _cgo_topofstack(void) { return (char*)0; }\n")
 	} else {
 		// If we're not importing runtime/cgo, we *are* runtime/cgo,
-		// which provides crosscall2.  We just need a prototype.
+		// which provides these functions.  We just need a prototype.
 		fmt.Fprintf(fm, "void crosscall2(void(*fn)(void*, int), void *a, int c);\n")
+		fmt.Fprintf(fm, "void _cgo_wait_runtime_init_done();\n")
 	}
 	fmt.Fprintf(fm, "void _cgo_allocate(void *a, int c) { }\n")
 	fmt.Fprintf(fm, "void _cgo_panic(void *a, int c) { }\n")
+	fmt.Fprintf(fm, "void _cgo_reginit(void) { }\n")
 
 	// Write second Go output: definitions of _C_xxx.
 	// In a separate file so that the import of "unsafe" does not
@@ -68,6 +78,13 @@ func (p *Package) writeDefs() {
 	}
 	fmt.Fprintf(fgo2, "func _Cgo_ptr(ptr unsafe.Pointer) unsafe.Pointer { return ptr }\n\n")
 
+	if !*gccgo {
+		fmt.Fprintf(fgo2, "//go:linkname _Cgo_always_false runtime.cgoAlwaysFalse\n")
+		fmt.Fprintf(fgo2, "var _Cgo_always_false bool\n")
+		fmt.Fprintf(fgo2, "//go:linkname _Cgo_use runtime.cgoUse\n")
+		fmt.Fprintf(fgo2, "func _Cgo_use(interface{})\n")
+	}
+
 	typedefNames := make([]string, 0, len(typedef))
 	for name := range typedef {
 		typedefNames = append(typedefNames, name)
@@ -88,7 +105,6 @@ func (p *Package) writeDefs() {
 	if *gccgo {
 		fmt.Fprint(fc, p.cPrologGccgo())
 	} else {
-		fmt.Fprint(fc, cProlog)
 		fmt.Fprint(fgo2, goProlog)
 	}
 
@@ -102,44 +118,44 @@ func (p *Package) writeDefs() {
 		}
 
 		if !cVars[n.C] {
-			fmt.Fprintf(fm, "extern char %s[];\n", n.C)
-			fmt.Fprintf(fm, "void *_cgohack_%s = %s;\n\n", n.C, n.C)
-
-			if !*gccgo {
-				fmt.Fprintf(fc, "#pragma cgo_import_static %s\n", n.C)
+			if *gccgo {
+				fmt.Fprintf(fc, "extern byte *%s;\n", n.C)
+			} else {
+				fmt.Fprintf(fm, "extern char %s[];\n", n.C)
+				fmt.Fprintf(fm, "void *_cgohack_%s = %s;\n\n", n.C, n.C)
+				fmt.Fprintf(fgo2, "//go:linkname __cgo_%s %s\n", n.C, n.C)
+				fmt.Fprintf(fgo2, "//go:cgo_import_static %s\n", n.C)
+				fmt.Fprintf(fgo2, "var __cgo_%s byte\n", n.C)
 			}
-
-			fmt.Fprintf(fc, "extern byte *%s;\n", n.C)
-
 			cVars[n.C] = true
 		}
-		var amp string
+
 		var node ast.Node
 		if n.Kind == "var" {
-			amp = "&"
 			node = &ast.StarExpr{X: n.Type.Go}
 		} else if n.Kind == "fpvar" {
 			node = n.Type.Go
-			if *gccgo {
-				amp = "&"
-			}
 		} else {
 			panic(fmt.Errorf("invalid var kind %q", n.Kind))
 		}
 		if *gccgo {
 			fmt.Fprintf(fc, `extern void *%s __asm__("%s.%s");`, n.Mangle, gccgoSymbolPrefix, n.Mangle)
-			fmt.Fprintf(&gccgoInit, "\t%s = %s%s;\n", n.Mangle, amp, n.C)
-		} else {
-			fmt.Fprintf(fc, "#pragma dataflag NOPTR /* C pointer, not heap pointer */ \n")
-			fmt.Fprintf(fc, "void *·%s = %s%s;\n", n.Mangle, amp, n.C)
+			fmt.Fprintf(&gccgoInit, "\t%s = &%s;\n", n.Mangle, n.C)
+			fmt.Fprintf(fc, "\n")
 		}
-		fmt.Fprintf(fc, "\n")
 
 		fmt.Fprintf(fgo2, "var %s ", n.Mangle)
 		conf.Fprint(fgo2, fset, node)
+		if !*gccgo {
+			fmt.Fprintf(fgo2, " = (")
+			conf.Fprint(fgo2, fset, node)
+			fmt.Fprintf(fgo2, ")(unsafe.Pointer(&__cgo_%s))", n.C)
+		}
 		fmt.Fprintf(fgo2, "\n")
 	}
-	fmt.Fprintf(fc, "\n")
+	if *gccgo {
+		fmt.Fprintf(fc, "\n")
+	}
 
 	for _, key := range nameKeys(p.Name) {
 		n := p.Name[key]
@@ -152,14 +168,37 @@ func (p *Package) writeDefs() {
 	for _, key := range nameKeys(p.Name) {
 		n := p.Name[key]
 		if n.FuncType != nil {
-			p.writeDefsFunc(fc, fgo2, n)
+			p.writeDefsFunc(fgo2, n)
 		}
 	}
 
+	fgcc := creat(*objDir + "_cgo_export.c")
+	fgcch := creat(*objDir + "_cgo_export.h")
 	if *gccgo {
-		p.writeGccgoExports(fgo2, fc, fm)
+		p.writeGccgoExports(fgo2, fm, fgcc, fgcch)
 	} else {
-		p.writeExports(fgo2, fc, fm)
+		p.writeExports(fgo2, fm, fgcc, fgcch)
+	}
+	if err := fgcc.Close(); err != nil {
+		fatalf("%s", err)
+	}
+	if err := fgcch.Close(); err != nil {
+		fatalf("%s", err)
+	}
+
+	if *exportHeader != "" && len(p.ExpFunc) > 0 {
+		fexp := creat(*exportHeader)
+		fgcch, err := os.Open(*objDir + "_cgo_export.h")
+		if err != nil {
+			fatalf("%s", err)
+		}
+		_, err = io.Copy(fexp, fgcch)
+		if err != nil {
+			fatalf("%s", err)
+		}
+		if err = fexp.Close(); err != nil {
+			fatalf("%s", err)
+		}
 	}
 
 	init := gccgoInit.String()
@@ -169,9 +208,6 @@ func (p *Package) writeDefs() {
 		fmt.Fprint(fc, init)
 		fmt.Fprintln(fc, "}")
 	}
-
-	fgo2.Close()
-	fc.Close()
 }
 
 func dynimport(obj string) {
@@ -184,13 +220,15 @@ func dynimport(obj string) {
 		stdout = f
 	}
 
+	fmt.Fprintf(stdout, "package %s\n", *dynpackage)
+
 	if f, err := elf.Open(obj); err == nil {
 		if *dynlinker {
 			// Emit the cgo_dynamic_linker line.
 			if sec := f.Section(".interp"); sec != nil {
 				if data, err := sec.Data(); err == nil && len(data) > 1 {
 					// skip trailing \0 in data
-					fmt.Fprintf(stdout, "#pragma cgo_dynamic_linker %q\n", string(data[:len(data)-1]))
+					fmt.Fprintf(stdout, "//go:cgo_dynamic_linker %q\n", string(data[:len(data)-1]))
 				}
 			}
 		}
@@ -203,14 +241,14 @@ func dynimport(obj string) {
 			if s.Version != "" {
 				targ += "#" + s.Version
 			}
-			fmt.Fprintf(stdout, "#pragma cgo_import_dynamic %s %s %q\n", s.Name, targ, s.Library)
+			fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", s.Name, targ, s.Library)
 		}
 		lib, err := f.ImportedLibraries()
 		if err != nil {
 			fatalf("cannot load imported libraries from ELF file %s: %v", obj, err)
 		}
 		for _, l := range lib {
-			fmt.Fprintf(stdout, "#pragma cgo_import_dynamic _ _ %q\n", l)
+			fmt.Fprintf(stdout, "//go:cgo_import_dynamic _ _ %q\n", l)
 		}
 		return
 	}
@@ -224,14 +262,14 @@ func dynimport(obj string) {
 			if len(s) > 0 && s[0] == '_' {
 				s = s[1:]
 			}
-			fmt.Fprintf(stdout, "#pragma cgo_import_dynamic %s %s %q\n", s, s, "")
+			fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", s, s, "")
 		}
 		lib, err := f.ImportedLibraries()
 		if err != nil {
 			fatalf("cannot load imported libraries from Mach-O file %s: %v", obj, err)
 		}
 		for _, l := range lib {
-			fmt.Fprintf(stdout, "#pragma cgo_import_dynamic _ _ %q\n", l)
+			fmt.Fprintf(stdout, "//go:cgo_import_dynamic _ _ %q\n", l)
 		}
 		return
 	}
@@ -244,7 +282,7 @@ func dynimport(obj string) {
 		for _, s := range sym {
 			ss := strings.Split(s, ":")
 			name := strings.Split(ss[0], "@")[0]
-			fmt.Fprintf(stdout, "#pragma cgo_import_dynamic %s %s %q\n", name, ss[0], strings.ToLower(ss[1]))
+			fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", name, ss[0], strings.ToLower(ss[1]))
 		}
 		return
 	}
@@ -252,10 +290,10 @@ func dynimport(obj string) {
 	fatalf("cannot parse %s as ELF, Mach-O or PE", obj)
 }
 
-// Construct a gcc struct matching the 6c argument frame.
+// Construct a gcc struct matching the gc argument frame.
 // Assumes that in gcc, char is 1 byte, short 2 bytes, int 4 bytes, long long 8 bytes.
 // These assumptions are checked by the gccProlog.
-// Also assumes that 6c convention is to word-align the
+// Also assumes that gc convention is to word-align the
 // input and output parameters.
 func (p *Package) structType(n *Name) (string, int64) {
 	var buf bytes.Buffer
@@ -304,7 +342,7 @@ func (p *Package) structType(n *Name) (string, int64) {
 	return buf.String(), off
 }
 
-func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) {
+func (p *Package) writeDefsFunc(fgo2 io.Writer, n *Name) {
 	name := n.Go
 	gtype := n.FuncType.Go
 	void := gtype.Results == nil || len(gtype.Results.List) == 0
@@ -396,11 +434,11 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) {
 		return
 	}
 
-	// C wrapper calls into gcc, passing a pointer to the argument frame.
-	fmt.Fprintf(fc, "#pragma cgo_import_static %s\n", cname)
-	fmt.Fprintf(fc, "void %s(void*);\n", cname)
-	fmt.Fprintf(fc, "#pragma dataflag NOPTR\n")
-	fmt.Fprintf(fc, "void *·%s = %s;\n", cname, cname)
+	// Wrapper calls into gcc, passing a pointer to the argument frame.
+	fmt.Fprintf(fgo2, "//go:cgo_import_static %s\n", cname)
+	fmt.Fprintf(fgo2, "//go:linkname __cgofn_%s %s\n", cname, cname)
+	fmt.Fprintf(fgo2, "var __cgofn_%s byte\n", cname)
+	fmt.Fprintf(fgo2, "var %s = unsafe.Pointer(&__cgofn_%s)\n", cname, cname)
 
 	nret := 0
 	if !void {
@@ -412,7 +450,6 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) {
 	}
 
 	fmt.Fprint(fgo2, "\n")
-	fmt.Fprintf(fgo2, "var %s unsafe.Pointer\n", cname)
 	conf.Fprint(fgo2, fset, d)
 	fmt.Fprint(fgo2, " {\n")
 
@@ -428,16 +465,20 @@ func (p *Package) writeDefsFunc(fc, fgo2 *os.File, n *Name) {
 	if n.AddError {
 		prefix = "errno := "
 	}
-	fmt.Fprintf(fgo2, "\t%s_cgo_runtime_cgocall_errno(%s, %s)\n", prefix, cname, arg)
+	fmt.Fprintf(fgo2, "\t%s_cgo_runtime_cgocall(%s, %s)\n", prefix, cname, arg)
 	if n.AddError {
 		fmt.Fprintf(fgo2, "\tif errno != 0 { r2 = syscall.Errno(errno) }\n")
 	}
+	fmt.Fprintf(fgo2, "\tif _Cgo_always_false {\n")
+	for i := range d.Type.Params.List {
+		fmt.Fprintf(fgo2, "\t\t_Cgo_use(p%d)\n", i)
+	}
+	fmt.Fprintf(fgo2, "\t}\n")
 	fmt.Fprintf(fgo2, "\treturn\n")
 	fmt.Fprintf(fgo2, "}\n")
 }
 
-// writeOutput creates stubs for a specific source file to be compiled by 6g
-// (The comments here say 6g and 6c but the code applies to the 8 and 5 tools too.)
+// writeOutput creates stubs for a specific source file to be compiled by gc
 func (p *Package) writeOutput(f *File, srcfile string) {
 	base := srcfile
 	if strings.HasSuffix(base, ".go") {
@@ -454,7 +495,7 @@ func (p *Package) writeOutput(f *File, srcfile string) {
 	fmt.Fprintf(fgo1, "// Created by cgo - DO NOT EDIT\n\n")
 	conf.Fprint(fgo1, fset, f.AST)
 
-	// While we process the vars and funcs, also write 6c and gcc output.
+	// While we process the vars and funcs, also write gcc output.
 	// Gcc output starts with the preamble.
 	fmt.Fprintf(fgcc, "%s\n", f.Preamble)
 	fmt.Fprintf(fgcc, "%s\n", gccProlog)
@@ -516,7 +557,7 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
 	if n.AddError {
 		fmt.Fprintf(fgcc, "\terrno = 0;\n")
 	}
-	// We're trying to write a gcc struct that matches 6c/8c/5c's layout.
+	// We're trying to write a gcc struct that matches gc's layout.
 	// Use packed attribute to force no padding in this struct in case
 	// gcc has different packing requirements.
 	fmt.Fprintf(fgcc, "\t%s %v *a = v;\n", ctype, p.packedAttribute())
@@ -612,13 +653,13 @@ func (p *Package) writeGccgoOutputFunc(fgcc *os.File, n *Name) {
 }
 
 // packedAttribute returns host compiler struct attribute that will be
-// used to match 6c/8c/5c's struct layout. For example, on 386 Windows,
-// gcc wants to 8-align int64s, but 8c does not.
+// used to match gc's struct layout. For example, on 386 Windows,
+// gcc wants to 8-align int64s, but gc does not.
 // Use __gcc_struct__ to work around http://gcc.gnu.org/PR52991 on x86,
-// and http://golang.org/issue/5603.
+// and https://golang.org/issue/5603.
 func (p *Package) packedAttribute() string {
 	s := "__attribute__((__packed__"
-	if !strings.Contains(p.gccBaseCmd()[0], "clang") && (goarch == "amd64" || goarch == "386") {
+	if !p.GccIsClang && (goarch == "amd64" || goarch == "386") {
 		s += ", __gcc_struct__"
 	}
 	return s + "))"
@@ -626,23 +667,19 @@ func (p *Package) packedAttribute() string {
 
 // Write out the various stubs we need to support functions exported
 // from Go so that they are callable from C.
-func (p *Package) writeExports(fgo2, fc, fm *os.File) {
-	fgcc := creat(*objDir + "_cgo_export.c")
-	fgcch := creat(*objDir + "_cgo_export.h")
-
-	fmt.Fprintf(fgcch, "/* Created by cgo - DO NOT EDIT. */\n")
-	fmt.Fprintf(fgcch, "%s\n", p.Preamble)
-	fmt.Fprintf(fgcch, "%s\n", p.gccExportHeaderProlog())
+func (p *Package) writeExports(fgo2, fm, fgcc, fgcch io.Writer) {
+	p.writeExportHeader(fgcch)
 
 	fmt.Fprintf(fgcc, "/* Created by cgo - DO NOT EDIT. */\n")
-	fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n")
+	fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n\n")
 
-	fmt.Fprintf(fgcc, "\nextern void crosscall2(void (*fn)(void *, int), void *, int);\n\n")
+	fmt.Fprintf(fgcc, "extern void crosscall2(void (*fn)(void *, int), void *, int);\n")
+	fmt.Fprintf(fgcc, "extern void _cgo_wait_runtime_init_done();\n\n")
 
 	for _, exp := range p.ExpFunc {
 		fn := exp.Func
 
-		// Construct a gcc struct matching the 6c argument and
+		// Construct a gcc struct matching the gc argument and
 		// result frame.  The gcc struct will be compiled with
 		// __attribute__((packed)) so all padding must be accounted
 		// for explicitly.
@@ -728,11 +765,16 @@ func (p *Package) writeExports(fgo2, fc, fm *os.File) {
 				s += fmt.Sprintf("%s p%d", p.cgoType(atype).C, i)
 			})
 		s += ")"
+
+		if len(exp.Doc) > 0 {
+			fmt.Fprintf(fgcch, "\n%s", exp.Doc)
+		}
 		fmt.Fprintf(fgcch, "\nextern %s;\n", s)
 
 		fmt.Fprintf(fgcc, "extern void _cgoexp%s_%s(void *, int);\n", cPrefix, exp.ExpName)
 		fmt.Fprintf(fgcc, "\n%s\n", s)
 		fmt.Fprintf(fgcc, "{\n")
+		fmt.Fprintf(fgcc, "\t_cgo_wait_runtime_init_done();\n")
 		fmt.Fprintf(fgcc, "\t%s %v a;\n", ctype, p.packedAttribute())
 		if gccResult != "void" && (len(fntype.Results.List) > 1 || len(fntype.Results.List[0].Names) > 1) {
 			fmt.Fprintf(fgcc, "\t%s r;\n", gccResult)
@@ -758,20 +800,21 @@ func (p *Package) writeExports(fgo2, fc, fm *os.File) {
 		}
 		fmt.Fprintf(fgcc, "}\n")
 
-		// Build the wrapper function compiled by 6c/8c
+		// Build the wrapper function compiled by gc.
 		goname := exp.Func.Name.Name
 		if fn.Recv != nil {
 			goname = "_cgoexpwrap" + cPrefix + "_" + fn.Recv.List[0].Names[0].Name + "_" + goname
 		}
-		fmt.Fprintf(fc, "#pragma cgo_export_dynamic %s\n", goname)
-		fmt.Fprintf(fc, "extern void ·%s();\n\n", goname)
-		fmt.Fprintf(fc, "#pragma cgo_export_static _cgoexp%s_%s\n", cPrefix, exp.ExpName)
-		fmt.Fprintf(fc, "#pragma textflag 7\n") // no split stack, so no use of m or g
-		fmt.Fprintf(fc, "void\n")
-		fmt.Fprintf(fc, "_cgoexp%s_%s(void *a, int32 n)\n", cPrefix, exp.ExpName)
-		fmt.Fprintf(fc, "{\n")
-		fmt.Fprintf(fc, "\truntime·cgocallback(·%s, a, n);\n", goname)
-		fmt.Fprintf(fc, "}\n")
+		fmt.Fprintf(fgo2, "//go:cgo_export_dynamic %s\n", goname)
+		fmt.Fprintf(fgo2, "//go:linkname _cgoexp%s_%s _cgoexp%s_%s\n", cPrefix, exp.ExpName, cPrefix, exp.ExpName)
+		fmt.Fprintf(fgo2, "//go:cgo_export_static _cgoexp%s_%s\n", cPrefix, exp.ExpName)
+		fmt.Fprintf(fgo2, "//go:nosplit\n") // no split stack, so no use of m or g
+		fmt.Fprintf(fgo2, "//go:norace\n")  // must not have race detector calls inserted
+		fmt.Fprintf(fgo2, "func _cgoexp%s_%s(a unsafe.Pointer, n int32) {", cPrefix, exp.ExpName)
+		fmt.Fprintf(fgo2, "\tfn := %s\n", goname)
+		// The indirect here is converting from a Go function pointer to a C function pointer.
+		fmt.Fprintf(fgo2, "\t_cgo_runtime_cgocallback(**(**unsafe.Pointer)(unsafe.Pointer(&fn)), a, uintptr(n));\n")
+		fmt.Fprintf(fgo2, "}\n")
 
 		fmt.Fprintf(fm, "int _cgoexp%s_%s;\n", cPrefix, exp.ExpName)
 
@@ -814,23 +857,20 @@ func (p *Package) writeExports(fgo2, fc, fm *os.File) {
 			fmt.Fprint(fgo2, "}\n")
 		}
 	}
+
+	fmt.Fprintf(fgcch, "%s", gccExportHeaderEpilog)
 }
 
 // Write out the C header allowing C code to call exported gccgo functions.
-func (p *Package) writeGccgoExports(fgo2, fc, fm *os.File) {
-	fgcc := creat(*objDir + "_cgo_export.c")
-	fgcch := creat(*objDir + "_cgo_export.h")
-
+func (p *Package) writeGccgoExports(fgo2, fm, fgcc, fgcch io.Writer) {
 	gccgoSymbolPrefix := p.gccgoSymbolPrefix()
 
-	fmt.Fprintf(fgcch, "/* Created by cgo - DO NOT EDIT. */\n")
-	fmt.Fprintf(fgcch, "%s\n", p.Preamble)
-	fmt.Fprintf(fgcch, "%s\n", p.gccExportHeaderProlog())
+	p.writeExportHeader(fgcch)
 
 	fmt.Fprintf(fgcc, "/* Created by cgo - DO NOT EDIT. */\n")
 	fmt.Fprintf(fgcc, "#include \"_cgo_export.h\"\n")
 
-	fmt.Fprintf(fm, "#include \"_cgo_export.h\"\n")
+	fmt.Fprintf(fgcc, "%s\n", gccgoExportFileProlog)
 
 	for _, exp := range p.ExpFunc {
 		fn := exp.Func
@@ -851,6 +891,7 @@ func (p *Package) writeGccgoExports(fgo2, fc, fm *os.File) {
 				})
 		default:
 			// Declare a result struct.
+			fmt.Fprintf(fgcch, "\n/* Return type for %s */\n", exp.ExpName)
 			fmt.Fprintf(fgcch, "struct %s_result {\n", exp.ExpName)
 			forFieldList(fntype.Results,
 				func(i int, atype ast.Expr) {
@@ -880,6 +921,10 @@ func (p *Package) writeGccgoExports(fgo2, fc, fm *os.File) {
 		fmt.Fprintf(cdeclBuf, ")")
 		cParams := cdeclBuf.String()
 
+		if len(exp.Doc) > 0 {
+			fmt.Fprintf(fgcch, "\n%s", exp.Doc)
+		}
+
 		// We need to use a name that will be exported by the
 		// Go code; otherwise gccgo will make it static and we
 		// will not be able to link against it from the C
@@ -900,6 +945,8 @@ func (p *Package) writeGccgoExports(fgo2, fc, fm *os.File) {
 
 		fmt.Fprint(fgcc, "\n")
 		fmt.Fprintf(fgcc, "%s %s %s {\n", cRet, exp.ExpName, cParams)
+		fmt.Fprintf(fgcc, "\tif(_cgo_wait_runtime_init_done)\n")
+		fmt.Fprintf(fgcc, "\t\t_cgo_wait_runtime_init_done();\n")
 		fmt.Fprint(fgcc, "\t")
 		if resultCount > 0 {
 			fmt.Fprint(fgcc, "return ")
@@ -919,7 +966,8 @@ func (p *Package) writeGccgoExports(fgo2, fc, fm *os.File) {
 		fmt.Fprint(fgcc, "}\n")
 
 		// Dummy declaration for _cgo_main.c
-		fmt.Fprintf(fm, "%s %s %s {}\n", cRet, goName, cParams)
+		fmt.Fprintf(fm, `char %s[1] __asm__("%s.%s");`, goName, gccgoSymbolPrefix, goName)
+		fmt.Fprint(fm, "\n")
 
 		// For gccgo we use a wrapper function in Go, in order
 		// to call CgocallBack and CgocallBackDone.
@@ -974,6 +1022,24 @@ func (p *Package) writeGccgoExports(fgo2, fc, fm *os.File) {
 		fmt.Fprint(fgo2, ")\n")
 		fmt.Fprint(fgo2, "}\n")
 	}
+
+	fmt.Fprintf(fgcch, "%s", gccExportHeaderEpilog)
+}
+
+// writeExportHeader writes out the start of the _cgo_export.h file.
+func (p *Package) writeExportHeader(fgcch io.Writer) {
+	fmt.Fprintf(fgcch, "/* Created by \"go tool cgo\" - DO NOT EDIT. */\n\n")
+	pkg := *importPath
+	if pkg == "" {
+		pkg = p.PackagePath
+	}
+	fmt.Fprintf(fgcch, "/* package %s */\n\n", pkg)
+
+	fmt.Fprintf(fgcch, "/* Start of preamble from import \"C\" comments.  */\n\n")
+	fmt.Fprintf(fgcch, "%s\n", p.Preamble)
+	fmt.Fprintf(fgcch, "\n/* End of preamble from import \"C\" comments.  */\n\n")
+
+	fmt.Fprintf(fgcch, "%s\n", p.gccExportHeaderProlog())
 }
 
 // Return the package prefix when using gccgo.
@@ -1164,60 +1230,39 @@ char *CString(_GoString_);
 void *_CMalloc(size_t);
 `
 
-const cProlog = `
-#include "runtime.h"
-#include "cgocall.h"
-#include "textflag.h"
-
-#pragma dataflag NOPTR
-static void *cgocall_errno = runtime·cgocall_errno;
-#pragma dataflag NOPTR
-void *·_cgo_runtime_cgocall_errno = &cgocall_errno;
-
-#pragma dataflag NOPTR
-static void *runtime_gostring = runtime·gostring;
-#pragma dataflag NOPTR
-void *·_cgo_runtime_gostring = &runtime_gostring;
-
-#pragma dataflag NOPTR
-static void *runtime_gostringn = runtime·gostringn;
-#pragma dataflag NOPTR
-void *·_cgo_runtime_gostringn = &runtime_gostringn;
-
-#pragma dataflag NOPTR
-static void *runtime_gobytes = runtime·gobytes;
-#pragma dataflag NOPTR
-void *·_cgo_runtime_gobytes = &runtime_gobytes;
-
-#pragma dataflag NOPTR
-static void *runtime_cmalloc = runtime·cmalloc;
-#pragma dataflag NOPTR
-void *·_cgo_runtime_cmalloc = &runtime_cmalloc;
-
-void ·_Cerrno(void*, int32);
-`
-
 const goProlog = `
-var _cgo_runtime_cgocall_errno func(unsafe.Pointer, uintptr) int32
-var _cgo_runtime_cmalloc func(uintptr) unsafe.Pointer
+//go:linkname _cgo_runtime_cgocall runtime.cgocall
+func _cgo_runtime_cgocall(unsafe.Pointer, uintptr) int32
+
+//go:linkname _cgo_runtime_cmalloc runtime.cmalloc
+func _cgo_runtime_cmalloc(uintptr) unsafe.Pointer
+
+//go:linkname _cgo_runtime_cgocallback runtime.cgocallback
+func _cgo_runtime_cgocallback(unsafe.Pointer, unsafe.Pointer, uintptr)
 `
 
 const goStringDef = `
-var _cgo_runtime_gostring func(*_Ctype_char) string
+//go:linkname _cgo_runtime_gostring runtime.gostring
+func _cgo_runtime_gostring(*_Ctype_char) string
+
 func _Cfunc_GoString(p *_Ctype_char) string {
 	return _cgo_runtime_gostring(p)
 }
 `
 
 const goStringNDef = `
-var _cgo_runtime_gostringn func(*_Ctype_char, int) string
+//go:linkname _cgo_runtime_gostringn runtime.gostringn
+func _cgo_runtime_gostringn(*_Ctype_char, int) string
+
 func _Cfunc_GoStringN(p *_Ctype_char, l _Ctype_int) string {
 	return _cgo_runtime_gostringn(p, int(l))
 }
 `
 
 const goBytesDef = `
-var _cgo_runtime_gobytes func(unsafe.Pointer, int) []byte
+//go:linkname _cgo_runtime_gobytes runtime.gobytes
+func _cgo_runtime_gobytes(unsafe.Pointer, int) []byte
+
 func _Cfunc_GoBytes(p unsafe.Pointer, l _Ctype_int) []byte {
 	return _cgo_runtime_gobytes(p, int(l))
 }
@@ -1310,6 +1355,11 @@ func (p *Package) gccExportHeaderProlog() string {
 }
 
 const gccExportHeaderProlog = `
+/* Start of boilerplate cgo prologue.  */
+
+#ifndef GO_CGO_PROLOGUE_H
+#define GO_CGO_PROLOGUE_H
+
 typedef signed char GoInt8;
 typedef unsigned char GoUint8;
 typedef short GoInt16;
@@ -1326,9 +1376,44 @@ typedef double GoFloat64;
 typedef __complex float GoComplex64;
 typedef __complex double GoComplex128;
 
+// static assertion to make sure the file is being used on architecture
+// at least with matching size of GoInt.
+typedef char _check_for_GOINTBITS_bit_pointer_matching_GoInt[sizeof(void*)==GOINTBITS/8 ? 1:-1];
+
 typedef struct { char *p; GoInt n; } GoString;
 typedef void *GoMap;
 typedef void *GoChan;
 typedef struct { void *t; void *v; } GoInterface;
 typedef struct { void *data; GoInt len; GoInt cap; } GoSlice;
+
+#endif
+
+/* End of boilerplate cgo prologue.  */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+`
+
+// gccExportHeaderEpilog goes at the end of the generated header file.
+const gccExportHeaderEpilog = `
+#ifdef __cplusplus
+}
+#endif
+`
+
+// gccgoExportFileProlog is written to the _cgo_export.c file when
+// using gccgo.
+// We use weak declarations, and test the addresses, so that this code
+// works with older versions of gccgo.
+const gccgoExportFileProlog = `
+extern _Bool runtime_iscgo __attribute__ ((weak));
+
+static void GoInit(void) __attribute__ ((constructor));
+static void GoInit(void) {
+	if(&runtime_iscgo)
+		runtime_iscgo = 1;
+}
+
+extern void _cgo_wait_runtime_init_done() __attribute__ ((weak));
 `
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 @@ func error_(pos token.Pos, msg string, args ...interface{}) {
 	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/compile/doc.go b/src/cmd/compile/doc.go
new file mode 100644
index 0000000..e362657
--- /dev/null
+++ b/src/cmd/compile/doc.go
@@ -0,0 +1,127 @@
+// 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.
+
+/*
+Compile, typically invoked as ``go tool compile,'' compiles a single Go package
+comprising the files named on the command line. It then writes a single
+object file named for the basename of the first source file with a .o suffix.
+The object file can then be combined with other objects into a package archive
+or passed directly to the linker (``go tool link''). If invoked with -pack, the compiler
+writes an archive directly, bypassing the intermediate object file.
+
+The generated files contain type information about the symbols exported by
+the package and about types used by symbols imported by the package from
+other packages. It is therefore not necessary when compiling client C of
+package P to read the files of P's dependencies, only the compiled output of P.
+
+Command Line
+
+Usage:
+
+	go tool compile [flags] file...
+
+The specified files must be Go source files and all part of the same package.
+The same compiler is used for all target operating systems and architectures.
+The GOOS and GOARCH environment variables set the desired target.
+
+Flags:
+
+	-D path
+		Set relative path for local imports.
+	-I dir1 -I dir2
+		Search for imported packages in dir1, dir2, etc,
+		after consulting $GOROOT/pkg/$GOOS_$GOARCH.
+	-L
+		Show complete file path in error messages.
+	-N
+		Disable optimizations.
+	-S
+		Print assembly listing to standard output (code only).
+	-S -S
+		Print assembly listing to standard output (code and data).
+	-V
+		Print compiler version and exit.
+	-asmhdr file
+		Write assembly header to file.
+	-complete
+		Assume package has no non-Go components.
+	-cpuprofile file
+		Write a CPU profile for the compilation to file.
+	-dynlink
+		Allow references to Go symbols in shared libraries (experimental).
+	-e
+		Remove the limit on the number of errors reported (default limit is 10).
+	-h
+		Halt with a stack trace at the first error detected.
+	-importmap old=new
+		Interpret import "old" as import "new" during compilation.
+		The option may be repeated to add multiple mappings.
+	-installsuffix suffix
+		Look for packages in $GOROOT/pkg/$GOOS_$GOARCH_suffix
+		instead of $GOROOT/pkg/$GOOS_$GOARCH.
+	-largemodel
+		Generated code that assumes a large memory model.
+	-memprofile file
+		Write memory profile for the compilation to file.
+	-memprofilerate rate
+		Set runtime.MemProfileRate for the compilation to rate.
+	-nolocalimports
+		Disallow local (relative) imports.
+	-o file
+		Write object to file (default file.o or, with -pack, file.a).
+	-p path
+		Set expected package import path for the code being compiled,
+		and diagnose imports that would cause a circular dependency.
+	-pack
+		Write a package (archive) file rather than an object file
+	-race
+		Compile with race detector enabled.
+	-u
+		Disallow importing packages not marked as safe; implies -nolocalimports.
+
+There are also a number of debugging flags; run the command with no arguments
+for a usage message.
+
+Compiler Directives
+
+The compiler accepts compiler directives in the form of // comments at the
+beginning of a line. To distinguish them from non-directive comments, the directives
+require no space between the slashes and the name of the directive. However, since
+they are comments, tools unaware of the directive convention or of a particular
+directive can skip over a directive like any other comment.
+
+	//line path/to/file:linenumber
+
+The //line directive specifies that the source line that follows should be recorded
+as having come from the given file path and line number. Successive lines are
+recorded using increasing line numbers, until the next directive. This directive
+typically appears in machine-generated code, so that compilers and debuggers
+will show lines in the original input to the generator.
+
+The //line directive is an historical special case; all other directives are of the form
+//go:name, indicating that the directive is defined by the Go toolchain.
+
+	//go:noescape
+
+The //go:noescape directive specifies that the next declaration in the file, which
+must be a func without a body (meaning that it has an implementation not written
+in Go) does not allow any of the pointers passed as arguments to escape into the
+heap or into the values returned from the function. This information can be used as
+during the compiler's escape analysis of Go code calling the function.
+
+	//go:nosplit
+
+The //go:nosplit directive specifies that the next function declared in the file must
+not include a stack overflow check. This is most commonly used by low-level
+runtime sources invoked at times when it is unsafe for the calling goroutine to be
+preempted.
+
+	//go:linkname localname importpath.name
+
+The //go:linkname directive instructs the compiler to use ``importpath.name'' as the
+object file symbol name for the variable or function declared as ``localname'' in the
+source code. Because this directive can subvert the type system and package
+modularity, it is only enabled in files that have imported "unsafe".
+*/
+package main
diff --git a/src/cmd/compile/internal/amd64/cgen.go b/src/cmd/compile/internal/amd64/cgen.go
new file mode 100644
index 0000000..71f8f88
--- /dev/null
+++ b/src/cmd/compile/internal/amd64/cgen.go
@@ -0,0 +1,151 @@
+// 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 amd64
+
+import (
+	"cmd/compile/internal/gc"
+	"cmd/internal/obj"
+	"cmd/internal/obj/x86"
+)
+
+func blockcopy(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
+	gc.Nodreg(&nodsi, gc.Types[gc.Tptr], x86.REG_SI)
+
+	var nodl gc.Node
+	var nodr gc.Node
+	if n.Ullman >= ns.Ullman {
+		gc.Agenr(n, &nodr, &nodsi)
+		if ns.Op == gc.ONAME {
+			gc.Gvardef(ns)
+		}
+		gc.Agenr(ns, &nodl, &noddi)
+	} else {
+		if ns.Op == gc.ONAME {
+			gc.Gvardef(ns)
+		}
+		gc.Agenr(ns, &nodl, &noddi)
+		gc.Agenr(n, &nodr, &nodsi)
+	}
+
+	if nodl.Reg != x86.REG_DI {
+		gmove(&nodl, &noddi)
+	}
+	if nodr.Reg != x86.REG_SI {
+		gmove(&nodr, &nodsi)
+	}
+	gc.Regfree(&nodl)
+	gc.Regfree(&nodr)
+
+	c := w % 8 // bytes
+	q := w / 8 // quads
+
+	var oldcx gc.Node
+	var cx gc.Node
+	savex(x86.REG_CX, &cx, &oldcx, nil, gc.Types[gc.TINT64])
+
+	// if we are copying forward on the stack and
+	// the src and dst overlap, then reverse direction
+	if osrc < odst && odst < osrc+w {
+		// reverse direction
+		gins(x86.ASTD, nil, nil) // set direction flag
+		if c > 0 {
+			gconreg(addptr, w-1, x86.REG_SI)
+			gconreg(addptr, w-1, x86.REG_DI)
+
+			gconreg(movptr, 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(addptr, -7, x86.REG_SI)
+				gconreg(addptr, -7, x86.REG_DI)
+			} else {
+				gconreg(addptr, w-8, x86.REG_SI)
+				gconreg(addptr, w-8, x86.REG_DI)
+			}
+
+			gconreg(movptr, q, x86.REG_CX)
+			gins(x86.AREP, nil, nil)   // repeat
+			gins(x86.AMOVSQ, nil, nil) // MOVQ *(SI)-,*(DI)-
+		}
+
+		// we leave with the flag clear
+		gins(x86.ACLD, nil, nil)
+	} else {
+		// normal direction
+		if q > 128 || (gc.Nacl && q >= 4) {
+			gconreg(movptr, q, x86.REG_CX)
+			gins(x86.AREP, nil, nil)   // repeat
+			gins(x86.AMOVSQ, nil, nil) // MOVQ *(SI)+,*(DI)+
+		} else if q >= 4 {
+			p := gins(obj.ADUFFCOPY, nil, nil)
+			p.To.Type = obj.TYPE_ADDR
+			p.To.Sym = gc.Linksym(gc.Pkglookup("duffcopy", gc.Runtimepkg))
+
+			// 14 and 128 = magic constants: see ../../runtime/asm_amd64.s
+			p.To.Offset = 14 * (128 - q)
+		} else if !gc.Nacl && c == 0 {
+			// We don't need the MOVSQ side-effect of updating SI and DI,
+			// and issuing a sequence of MOVQs directly is faster.
+			nodsi.Op = gc.OINDREG
+
+			noddi.Op = gc.OINDREG
+			for q > 0 {
+				gmove(&nodsi, &cx) // MOVQ x+(SI),CX
+				gmove(&cx, &noddi) // MOVQ CX,x+(DI)
+				nodsi.Xoffset += 8
+				noddi.Xoffset += 8
+				q--
+			}
+		} else {
+			for q > 0 {
+				gins(x86.AMOVSQ, nil, nil) // MOVQ *(SI)+,*(DI)+
+				q--
+			}
+		}
+
+		// copy the remaining c bytes
+		if w < 4 || c <= 1 || (odst < osrc && osrc < odst+w) {
+			for c > 0 {
+				gins(x86.AMOVSB, nil, nil) // MOVB *(SI)+,*(DI)+
+				c--
+			}
+		} else if w < 8 || c <= 4 {
+			nodsi.Op = gc.OINDREG
+			noddi.Op = gc.OINDREG
+			cx.Type = gc.Types[gc.TINT32]
+			nodsi.Type = gc.Types[gc.TINT32]
+			noddi.Type = gc.Types[gc.TINT32]
+			if c > 4 {
+				nodsi.Xoffset = 0
+				noddi.Xoffset = 0
+				gmove(&nodsi, &cx)
+				gmove(&cx, &noddi)
+			}
+
+			nodsi.Xoffset = c - 4
+			noddi.Xoffset = c - 4
+			gmove(&nodsi, &cx)
+			gmove(&cx, &noddi)
+		} else {
+			nodsi.Op = gc.OINDREG
+			noddi.Op = gc.OINDREG
+			cx.Type = gc.Types[gc.TINT64]
+			nodsi.Type = gc.Types[gc.TINT64]
+			noddi.Type = gc.Types[gc.TINT64]
+			nodsi.Xoffset = c - 8
+			noddi.Xoffset = c - 8
+			gmove(&nodsi, &cx)
+			gmove(&cx, &noddi)
+		}
+	}
+
+	restx(&cx, &oldcx)
+}
diff --git a/src/cmd/compile/internal/amd64/galign.go b/src/cmd/compile/internal/amd64/galign.go
new file mode 100644
index 0000000..79bf94a
--- /dev/null
+++ b/src/cmd/compile/internal/amd64/galign.go
@@ -0,0 +1,129 @@
+// 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 amd64
+
+import (
+	"cmd/compile/internal/gc"
+	"cmd/internal/obj"
+	"cmd/internal/obj/x86"
+)
+
+var (
+	thechar     int           = '6'
+	thestring   string        = "amd64"
+	thelinkarch *obj.LinkArch = &x86.Linkamd64
+)
+
+func linkarchinit() {
+	if obj.Getgoarch() == "amd64p32" {
+		thelinkarch = &x86.Linkamd64p32
+		gc.Thearch.Thelinkarch = thelinkarch
+		thestring = "amd64p32"
+		gc.Thearch.Thestring = "amd64p32"
+	}
+}
+
+var MAXWIDTH int64 = 1 << 50
+
+var (
+	addptr int = x86.AADDQ
+	movptr int = x86.AMOVQ
+	leaptr int = x86.ALEAQ
+	cmpptr int = x86.ACMPQ
+)
+
+/*
+ * go declares several platform-specific type aliases:
+ * int, uint, 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
+	if obj.Getgoarch() == "amd64p32" {
+		gc.Widthptr = 4
+		gc.Widthint = 4
+		addptr = x86.AADDL
+		movptr = x86.AMOVL
+		leaptr = x86.ALEAL
+		cmpptr = x86.ACMPL
+		typedefs[0].Sameas = gc.TINT32
+		typedefs[1].Sameas = gc.TUINT32
+		typedefs[2].Sameas = gc.TUINT32
+	}
+
+	if gc.Ctxt.Flag_dynlink {
+		gc.Thearch.ReservedRegs = append(gc.Thearch.ReservedRegs, x86.REG_R15)
+	}
+}
+
+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.ReservedRegs = resvd
+
+	gc.Thearch.AddIndex = addindex
+	gc.Thearch.Betypeinit = betypeinit
+	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.Getg = getg
+	gc.Thearch.Gins = gins
+	gc.Thearch.Ginsboolval = ginsboolval
+	gc.Thearch.Ginscmp = ginscmp
+	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.Blockcopy = blockcopy
+	gc.Thearch.Sudoaddable = sudoaddable
+	gc.Thearch.Sudoclean = sudoclean
+	gc.Thearch.Excludedregs = excludedregs
+	gc.Thearch.RtoB = RtoB
+	gc.Thearch.FtoB = FtoB
+	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/compile/internal/amd64/ggen.go b/src/cmd/compile/internal/amd64/ggen.go
new file mode 100644
index 0000000..65cf694
--- /dev/null
+++ b/src/cmd/compile/internal/amd64/ggen.go
@@ -0,0 +1,743 @@
+// 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 amd64
+
+import (
+	"cmd/compile/internal/gc"
+	"cmd/internal/obj"
+	"cmd/internal/obj/x86"
+)
+
+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
+	ax := uint32(0)
+
+	// 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.Name.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, &ax)
+
+		// set new range
+		hi = n.Xoffset + n.Type.Width
+
+		lo = n.Xoffset
+	}
+
+	// zero final range
+	zerorange(p, int64(frame), lo, hi, &ax)
+}
+
+// DUFFZERO consists of repeated blocks of 4 MOVs + ADD,
+// with 4 STOSQs at the very end.
+// The trailing STOSQs prevent the need for a DI preadjustment
+// for small numbers of words to clear.
+// See runtime/mkduff.go.
+const (
+	dzBlocks    = 31 // number of MOV/ADD blocks
+	dzBlockLen  = 4  // number of clears per block
+	dzBlockSize = 19 // size of instructions in a single block
+	dzMovSize   = 4  // size of single MOV instruction w/ offset
+	dzAddSize   = 4  // size of single ADD instruction
+	dzDIStep    = 8  // number of bytes cleared by each MOV instruction
+
+	dzTailLen  = 4 // number of final STOSQ instructions
+	dzTailSize = 2 // size of single STOSQ instruction
+
+	dzSize = dzBlocks*dzBlockSize + dzTailLen*dzTailSize // total size of DUFFZERO routine
+)
+
+// duffzeroDI returns the pre-adjustment to DI for a call to DUFFZERO.
+// q is the number of words to zero.
+func dzDI(q int64) int64 {
+	if q < dzTailLen {
+		return 0
+	}
+	q -= dzTailLen
+	if q%dzBlockLen == 0 {
+		return 0
+	}
+	return -dzDIStep * (dzBlockLen - q%dzBlockLen)
+}
+
+// dzOff returns the offset for a jump into DUFFZERO.
+// q is the number of words to zero.
+func dzOff(q int64) int64 {
+	off := int64(dzSize)
+	if q < dzTailLen {
+		return off - q*dzTailSize
+	}
+	off -= dzTailLen * dzTailSize
+	q -= dzTailLen
+	blocks, steps := q/dzBlockLen, q%dzBlockLen
+	off -= dzBlockSize * blocks
+	if steps > 0 {
+		off -= dzAddSize + dzMovSize*steps
+	}
+	return off
+}
+
+func zerorange(p *obj.Prog, frame int64, lo int64, hi int64, ax *uint32) *obj.Prog {
+	cnt := hi - lo
+	if cnt == 0 {
+		return p
+	}
+	if *ax == 0 {
+		p = appendpp(p, x86.AMOVQ, obj.TYPE_CONST, 0, 0, obj.TYPE_REG, x86.REG_AX, 0)
+		*ax = 1
+	}
+
+	if cnt%int64(gc.Widthreg) != 0 {
+		// should only happen with nacl
+		if cnt%int64(gc.Widthptr) != 0 {
+			gc.Fatal("zerorange count not a multiple of widthptr %d", cnt)
+		}
+		p = appendpp(p, x86.AMOVL, obj.TYPE_REG, x86.REG_AX, 0, obj.TYPE_MEM, x86.REG_SP, frame+lo)
+		lo += int64(gc.Widthptr)
+		cnt -= int64(gc.Widthptr)
+	}
+
+	if cnt <= int64(4*gc.Widthreg) {
+		for i := int64(0); i < cnt; i += int64(gc.Widthreg) {
+			p = appendpp(p, x86.AMOVQ, 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)) {
+		q := cnt / int64(gc.Widthreg)
+		p = appendpp(p, leaptr, obj.TYPE_MEM, x86.REG_SP, frame+lo+dzDI(q), obj.TYPE_REG, x86.REG_DI, 0)
+		p = appendpp(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_ADDR, 0, dzOff(q))
+		p.To.Sym = gc.Linksym(gc.Pkglookup("duffzero", gc.Runtimepkg))
+	} else {
+		p = appendpp(p, x86.AMOVQ, obj.TYPE_CONST, 0, cnt/int64(gc.Widthreg), obj.TYPE_REG, x86.REG_CX, 0)
+		p = appendpp(p, leaptr, 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.ASTOSQ, obj.TYPE_NONE, 0, 0, obj.TYPE_NONE, 0, 0)
+	}
+
+	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
+}
+
+var panicdiv *gc.Node
+
+/*
+ * 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 trap.
+	// Also the byte divide instruction needs AH,
+	// which we otherwise don't have to deal with.
+	// Easiest way to avoid for int8, int16: use int32.
+	// For int32 and int64, use explicit test.
+	// Could use int64 hw for int32.
+	t := nl.Type
+
+	t0 := t
+	check := 0
+	if gc.Issigned[t.Etype] {
+		check = 1
+		if gc.Isconst(nl, gc.CTINT) && nl.Int() != -(1<<uint64(t.Width*8-1)) {
+			check = 0
+		} else if gc.Isconst(nr, gc.CTINT) && nr.Int() != -1 {
+			check = 0
+		}
+	}
+
+	if t.Width < 4 {
+		if gc.Issigned[t.Etype] {
+			t = gc.Types[gc.TINT32]
+		} else {
+			t = gc.Types[gc.TUINT32]
+		}
+		check = 0
+	}
+
+	a := optoas(op, t)
+
+	var n3 gc.Node
+	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)
+		gc.Cgen(nl, &ax)
+		gc.Regalloc(&ax, t0, &ax) // mark ax live during cgen
+		gc.Cgen(nr, &n3)
+		gc.Regfree(&ax)
+	} else {
+		gc.Cgen(nr, &n3)
+		savex(x86.REG_AX, &ax, &oldax, res, t0)
+		gc.Cgen(nl, &ax)
+	}
+
+	if t != t0 {
+		// Convert
+		ax1 := ax
+
+		n31 := n3
+		ax.Type = t
+		n3.Type = t
+		gmove(&ax1, &ax)
+		gmove(&n31, &n3)
+	}
+
+	var n4 gc.Node
+	if gc.Nacl {
+		// Native Client does not relay the divide-by-zero trap
+		// to the executing program, so we must insert a check
+		// for ourselves.
+		gc.Nodconst(&n4, t, 0)
+
+		gins(optoas(gc.OCMP, t), &n3, &n4)
+		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 {
+		gc.Nodconst(&n4, t, -1)
+		gins(optoas(gc.OCMP, t), &n3, &n4)
+		p1 := gc.Gbranch(optoas(gc.ONE, t), nil, +1)
+		if op == gc.ODIV {
+			// a / (-1) is -a.
+			gins(optoas(gc.OMINUS, t), nil, &ax)
+
+			gmove(&ax, res)
+		} else {
+			// a % (-1) is 0.
+			gc.Nodconst(&n4, t, 0)
+
+			gmove(&n4, res)
+		}
+
+		p2 = gc.Gbranch(obj.AJMP, nil, 0)
+		gc.Patch(p1, gc.Pc)
+	}
+
+	var olddx gc.Node
+	var dx gc.Node
+	savex(x86.REG_DX, &dx, &olddx, res, t)
+	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)
+	gc.Regfree(&n3)
+	if op == gc.ODIV {
+		gmove(&ax, res)
+	} else {
+		gmove(&dx, res)
+	}
+	restx(&dx, &olddx)
+	if check != 0 {
+		gc.Patch(p2, gc.Pc)
+	}
+	restx(&ax, &oldax)
+}
+
+/*
+ * register dr is one of the special ones (AX, CX, DI, SI, etc.).
+ * we need to use it.  if it is already allocated as a temporary
+ * (r > 1; can only happen if a routine like sgen passed a
+ * special as cgen's res and then cgen used regalloc to reuse
+ * it as its own temporary), then move it for now to another
+ * register.  caller must call restx to move it back.
+ * the move is not necessary if dr == res, because res is
+ * known to be dead.
+ */
+func savex(dr int, x *gc.Node, oldx *gc.Node, res *gc.Node, t *gc.Type) {
+	r := uint8(gc.GetReg(dr))
+
+	// save current ax and dx if they are live
+	// and not the destination
+	*oldx = gc.Node{}
+
+	gc.Nodreg(x, t, dr)
+	if r > 1 && !gc.Samereg(x, res) {
+		gc.Regalloc(oldx, gc.Types[gc.TINT64], nil)
+		x.Type = gc.Types[gc.TINT64]
+		gmove(x, oldx)
+		x.Type = t
+		oldx.Etype = r // squirrel away old r value
+		gc.SetReg(dr, 1)
+	}
+}
+
+func restx(x *gc.Node, oldx *gc.Node) {
+	if oldx.Op != 0 {
+		x.Type = gc.Types[gc.TINT64]
+		gc.SetReg(int(x.Reg), int(oldx.Etype))
+		gmove(oldx, x)
+		gc.Regfree(oldx)
+	}
+}
+
+/*
+ * generate high multiply:
+ *   res = (nl*nr) >> width
+ */
+func cgen_hmul(nl *gc.Node, nr *gc.Node, res *gc.Node) {
+	t := nl.Type
+	a := optoas(gc.OHMUL, t)
+	if nl.Ullman < nr.Ullman {
+		tmp := nl
+		nl = nr
+		nr = tmp
+	}
+
+	var n1 gc.Node
+	gc.Cgenr(nl, &n1, res)
+	var n2 gc.Node
+	gc.Cgenr(nr, &n2, nil)
+	var ax gc.Node
+	gc.Nodreg(&ax, t, x86.REG_AX)
+	gmove(&n1, &ax)
+	gins(a, &n2, nil)
+	gc.Regfree(&n2)
+	gc.Regfree(&n1)
+
+	var dx gc.Node
+	if t.Width == 1 {
+		// byte multiply behaves differently.
+		gc.Nodreg(&ax, t, x86.REG_AH)
+
+		gc.Nodreg(&dx, t, x86.REG_DX)
+		gmove(&ax, &dx)
+	}
+
+	gc.Nodreg(&dx, t, x86.REG_DX)
+	gmove(&dx, res)
+}
+
+/*
+ * 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 := 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(nr.Int())
+		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
+	}
+
+	rcx := gc.GetReg(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]]
+
+	if tcount.Etype < gc.TUINT32 {
+		tcount = gc.Types[gc.TUINT32]
+	}
+
+	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)
+
+	var oldcx gc.Node
+	if rcx > 0 && !gc.Samereg(&cx, res) {
+		gc.Regalloc(&oldcx, gc.Types[gc.TUINT64], nil)
+		gmove(&cx, &oldcx)
+	}
+
+	cx.Type = tcount
+
+	var n2 gc.Node
+	if gc.Samereg(&cx, res) {
+		gc.Regalloc(&n2, nl.Type, nil)
+	} else {
+		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)
+		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] {
+			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)
+
+	if oldcx.Op != 0 {
+		cx.Type = gc.Types[gc.TUINT64]
+		gmove(&oldcx, &cx)
+		gc.Regfree(&oldcx)
+	}
+
+	gmove(&n2, res)
+
+	gc.Regfree(&n1)
+	gc.Regfree(&n2)
+}
+
+/*
+ * generate byte multiply:
+ *	res = nl * nr
+ * 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) bool {
+	if optoas(op, nl.Type) != x86.AIMULB {
+		return false
+	}
+
+	// largest ullman on left.
+	if nl.Ullman < nr.Ullman {
+		tmp := nl
+		nl = nr
+		nr = tmp
+	}
+
+	// generate operands in "8-bit" registers.
+	var n1b gc.Node
+	gc.Regalloc(&n1b, nl.Type, res)
+
+	gc.Cgen(nl, &n1b)
+	var n2b gc.Node
+	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] {
+		t = gc.Types[gc.TINT64]
+	}
+	var n1 gc.Node
+	gc.Nodreg(&n1, t, int(n1b.Reg))
+	var n2 gc.Node
+	gc.Nodreg(&n2, t, int(n2b.Reg))
+	a := optoas(op, t)
+	gins(a, &n2, &n1)
+
+	// truncate.
+	gmove(&n1, res)
+
+	gc.Regfree(&n1b)
+	gc.Regfree(&n2b)
+	return true
+}
+
+func clearfat(nl *gc.Node) {
+	/* clear a fat object */
+	if gc.Debug['g'] != 0 {
+		gc.Dump("\nclearfat", nl)
+	}
+
+	w := nl.Type.Width
+
+	// Avoid taking the address for simple enough types.
+	if gc.Componentgen(nil, nl) {
+		return
+	}
+
+	c := w % 8 // bytes
+	q := w / 8 // quads
+
+	if q < 4 {
+		// Write sequence of MOV 0, off(base) instead of using STOSQ.
+		// The hope is that although the code will be slightly longer,
+		// the MOVs will have no dependencies and pipeline better
+		// than the unrolled STOSQ loop.
+		// NOTE: Must use agen, not igen, so that optimizer sees address
+		// being taken. We are not writing on field boundaries.
+		var n1 gc.Node
+		gc.Agenr(nl, &n1, nil)
+
+		n1.Op = gc.OINDREG
+		var z gc.Node
+		gc.Nodconst(&z, gc.Types[gc.TUINT64], 0)
+		for {
+			tmp14 := q
+			q--
+			if tmp14 <= 0 {
+				break
+			}
+			n1.Type = z.Type
+			gins(x86.AMOVQ, &z, &n1)
+			n1.Xoffset += 8
+		}
+
+		if c >= 4 {
+			gc.Nodconst(&z, gc.Types[gc.TUINT32], 0)
+			n1.Type = z.Type
+			gins(x86.AMOVL, &z, &n1)
+			n1.Xoffset += 4
+			c -= 4
+		}
+
+		gc.Nodconst(&z, gc.Types[gc.TUINT8], 0)
+		for {
+			tmp15 := c
+			c--
+			if tmp15 <= 0 {
+				break
+			}
+			n1.Type = z.Type
+			gins(x86.AMOVB, &z, &n1)
+			n1.Xoffset++
+		}
+
+		gc.Regfree(&n1)
+		return
+	}
+
+	var oldn1 gc.Node
+	var n1 gc.Node
+	savex(x86.REG_DI, &n1, &oldn1, nil, gc.Types[gc.Tptr])
+	gc.Agen(nl, &n1)
+
+	var ax gc.Node
+	var oldax gc.Node
+	savex(x86.REG_AX, &ax, &oldax, nil, gc.Types[gc.Tptr])
+	gconreg(x86.AMOVL, 0, x86.REG_AX)
+
+	if q > 128 || gc.Nacl {
+		gconreg(movptr, q, x86.REG_CX)
+		gins(x86.AREP, nil, nil)   // repeat
+		gins(x86.ASTOSQ, nil, nil) // STOQ AL,*(DI)+
+	} else {
+		if di := dzDI(q); di != 0 {
+			gconreg(addptr, di, x86.REG_DI)
+		}
+		p := gins(obj.ADUFFZERO, nil, nil)
+		p.To.Type = obj.TYPE_ADDR
+		p.To.Sym = gc.Linksym(gc.Pkglookup("duffzero", gc.Runtimepkg))
+		p.To.Offset = dzOff(q)
+	}
+
+	z := ax
+	di := n1
+	if w >= 8 && c >= 4 {
+		di.Op = gc.OINDREG
+		z.Type = gc.Types[gc.TINT64]
+		di.Type = z.Type
+		p := gins(x86.AMOVQ, &z, &di)
+		p.To.Scale = 1
+		p.To.Offset = c - 8
+	} else if c >= 4 {
+		di.Op = gc.OINDREG
+		z.Type = gc.Types[gc.TINT32]
+		di.Type = z.Type
+		gins(x86.AMOVL, &z, &di)
+		if c > 4 {
+			p := gins(x86.AMOVL, &z, &di)
+			p.To.Scale = 1
+			p.To.Offset = c - 4
+		}
+	} else {
+		for c > 0 {
+			gins(x86.ASTOSB, nil, nil) // STOB AL,*(DI)+
+			c--
+		}
+	}
+
+	restx(&n1, &oldn1)
+	restx(&ax, &oldax)
+}
+
+// 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 := firstp; p != nil; p = p.Link {
+		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")
+		}
+
+		// check is
+		//	CMP arg, $0
+		//	JNE 2(PC) (likely)
+		//	MOV AX, 0
+		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 = int16(cmpptr)
+		p.To.Type = obj.TYPE_CONST
+		p.To.Offset = 0
+		p1.As = x86.AJNE
+		p1.From.Type = obj.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.
+		// if possible, since we know arg is 0, use 0(arg),
+		// which will be shorter to encode than plain 0.
+		p2.As = x86.AMOVL
+
+		p2.From.Type = obj.TYPE_REG
+		p2.From.Reg = x86.REG_AX
+		if regtyp(&p.From) {
+			p2.To.Type = obj.TYPE_MEM
+			p2.To.Reg = p.From.Reg
+		} else {
+			p2.To.Type = obj.TYPE_MEM
+			p2.To.Reg = x86.REG_NONE
+		}
+
+		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
+}
+
+// res = runtime.getg()
+func getg(res *gc.Node) {
+	var n1 gc.Node
+	gc.Regalloc(&n1, res.Type, res)
+	mov := optoas(gc.OAS, gc.Types[gc.Tptr])
+	p := gins(mov, nil, &n1)
+	p.From.Type = obj.TYPE_REG
+	p.From.Reg = x86.REG_TLS
+	p = gins(mov, nil, &n1)
+	p.From = p.To
+	p.From.Type = obj.TYPE_MEM
+	p.From.Index = x86.REG_TLS
+	p.From.Scale = 1
+	gmove(&n1, res)
+	gc.Regfree(&n1)
+}
diff --git a/src/cmd/compile/internal/amd64/gsubr.go b/src/cmd/compile/internal/amd64/gsubr.go
new file mode 100644
index 0000000..a8e4170
--- /dev/null
+++ b/src/cmd/compile/internal/amd64/gsubr.go
@@ -0,0 +1,1380 @@
+// 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 at 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 at 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 amd64
+
+import (
+	"cmd/compile/internal/big"
+	"cmd/compile/internal/gc"
+	"cmd/internal/obj"
+	"cmd/internal/obj/x86"
+	"fmt"
+)
+
+var resvd = []int{
+	x86.REG_DI, // for movstring
+	x86.REG_SI, // for movstring
+
+	x86.REG_AX, // for divide
+	x86.REG_CX, // for shift
+	x86.REG_DX, // for divide
+	x86.REG_SP, // for stack
+}
+
+/*
+ * generate
+ *	as $c, reg
+ */
+func gconreg(as int, c int64, reg int) {
+	var nr gc.Node
+
+	switch as {
+	case x86.AADDL,
+		x86.AMOVL,
+		x86.ALEAL:
+		gc.Nodreg(&nr, gc.Types[gc.TINT32], reg)
+
+	default:
+		gc.Nodreg(&nr, gc.Types[gc.TINT64], reg)
+	}
+
+	ginscon(as, c, &nr)
+}
+
+/*
+ * generate
+ *	as $c, n
+ */
+func ginscon(as int, c int64, n2 *gc.Node) {
+	var n1 gc.Node
+
+	switch as {
+	case x86.AADDL,
+		x86.AMOVL,
+		x86.ALEAL:
+		gc.Nodconst(&n1, gc.Types[gc.TINT32], c)
+
+	default:
+		gc.Nodconst(&n1, gc.Types[gc.TINT64], c)
+	}
+
+	if as != x86.AMOVQ && (c < -(1<<31) || c >= 1<<31) {
+		// cannot have 64-bit immediate in ADD, etc.
+		// instead, MOV into register first.
+		var ntmp gc.Node
+		gc.Regalloc(&ntmp, gc.Types[gc.TINT64], nil)
+
+		gins(x86.AMOVQ, &n1, &ntmp)
+		gins(as, &ntmp, n2)
+		gc.Regfree(&ntmp)
+		return
+	}
+
+	gins(as, &n1, n2)
+}
+
+func ginscmp(op int, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
+	if gc.Isint[t.Etype] && n1.Op == gc.OLITERAL && gc.Smallintconst(n1) && n2.Op != gc.OLITERAL {
+		// Reverse comparison to place constant last.
+		op = gc.Brrev(op)
+		n1, n2 = n2, n1
+	}
+	// General case.
+	var r1, r2, g1, g2 gc.Node
+	if n1.Op == gc.ONAME && n1.Class&gc.PHEAP == 0 || n1.Op == gc.OINDREG {
+		r1 = *n1
+	} else {
+		gc.Regalloc(&r1, t, n1)
+		gc.Regalloc(&g1, n1.Type, &r1)
+		gc.Cgen(n1, &g1)
+		gmove(&g1, &r1)
+	}
+	if n2.Op == gc.OLITERAL && gc.Isint[t.Etype] && gc.Smallintconst(n2) {
+		r2 = *n2
+	} else {
+		gc.Regalloc(&r2, t, n2)
+		gc.Regalloc(&g2, n1.Type, &r2)
+		gc.Cgen(n2, &g2)
+		gmove(&g2, &r2)
+	}
+	gins(optoas(gc.OCMP, t), &r1, &r2)
+	if r1.Op == gc.OREGISTER {
+		gc.Regfree(&g1)
+		gc.Regfree(&r1)
+	}
+	if r2.Op == gc.OREGISTER {
+		gc.Regfree(&g2)
+		gc.Regfree(&r2)
+	}
+	return gc.Gbranch(optoas(op, t), nil, likely)
+}
+
+func ginsboolval(a int, n *gc.Node) {
+	gins(jmptoset(a), nil, n)
+}
+
+// set up nodes representing 2^63
+var (
+	bigi         gc.Node
+	bigf         gc.Node
+	bignodes_did bool
+)
+
+func bignodes() {
+	if bignodes_did {
+		return
+	}
+	bignodes_did = true
+
+	var i big.Int
+	i.SetInt64(1)
+	i.Lsh(&i, 63)
+
+	gc.Nodconst(&bigi, gc.Types[gc.TUINT64], 0)
+	bigi.SetBigInt(&i)
+
+	bigi.Convconst(&bigf, gc.Types[gc.TFLOAT64])
+}
+
+/*
+ * 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 := gc.Simsimtype(f.Type)
+	tt := gc.Simsimtype(t.Type)
+	cvt := t.Type
+
+	if gc.Iscomplex[ft] || gc.Iscomplex[tt] {
+		gc.Complexmove(f, t)
+		return
+	}
+
+	// cannot have two memory operands
+	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
+		f.Convconst(&con, t.Type)
+		f = &con
+		ft = tt // so big switch will choose a simple mov
+
+		// some constants can't move directly to memory.
+		if gc.Ismem(t) {
+			// float constants come from memory.
+			if gc.Isfloat[tt] {
+				goto hard
+			}
+
+			// 64-bit immediates are really 32-bit sign-extended
+			// unless moving into a register.
+			if gc.Isint[tt] {
+				if i := con.Int(); int64(int32(i)) != i {
+					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.TINT8<<16 | gc.TUINT8,
+		gc.TUINT8<<16 | gc.TINT8,
+		gc.TUINT8<<16 | gc.TUINT8,
+		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,
+		gc.TINT16<<16 | gc.TUINT8,
+		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 = x86.AMOVB
+
+	case gc.TINT16<<16 | gc.TINT16, // same size
+		gc.TINT16<<16 | gc.TUINT16,
+		gc.TUINT16<<16 | gc.TINT16,
+		gc.TUINT16<<16 | gc.TUINT16,
+		gc.TINT32<<16 | gc.TINT16,
+		// truncate
+		gc.TUINT32<<16 | gc.TINT16,
+		gc.TINT64<<16 | gc.TINT16,
+		gc.TUINT64<<16 | gc.TINT16,
+		gc.TINT32<<16 | gc.TUINT16,
+		gc.TUINT32<<16 | gc.TUINT16,
+		gc.TINT64<<16 | gc.TUINT16,
+		gc.TUINT64<<16 | gc.TUINT16:
+		a = x86.AMOVW
+
+	case gc.TINT32<<16 | gc.TINT32, // same size
+		gc.TINT32<<16 | gc.TUINT32,
+		gc.TUINT32<<16 | gc.TINT32,
+		gc.TUINT32<<16 | gc.TUINT32:
+		a = x86.AMOVL
+
+	case gc.TINT64<<16 | gc.TINT32, // truncate
+		gc.TUINT64<<16 | gc.TINT32,
+		gc.TINT64<<16 | gc.TUINT32,
+		gc.TUINT64<<16 | gc.TUINT32:
+		a = x86.AMOVQL
+
+	case gc.TINT64<<16 | gc.TINT64, // same size
+		gc.TINT64<<16 | gc.TUINT64,
+		gc.TUINT64<<16 | gc.TINT64,
+		gc.TUINT64<<16 | gc.TUINT64:
+		a = x86.AMOVQ
+
+		/*
+		 * integer up-conversions
+		 */
+	case gc.TINT8<<16 | gc.TINT16, // sign extend int8
+		gc.TINT8<<16 | gc.TUINT16:
+		a = x86.AMOVBWSX
+
+		goto rdst
+
+	case gc.TINT8<<16 | gc.TINT32,
+		gc.TINT8<<16 | gc.TUINT32:
+		a = x86.AMOVBLSX
+		goto rdst
+
+	case gc.TINT8<<16 | gc.TINT64,
+		gc.TINT8<<16 | gc.TUINT64:
+		a = x86.AMOVBQSX
+		goto rdst
+
+	case gc.TUINT8<<16 | gc.TINT16, // zero extend uint8
+		gc.TUINT8<<16 | gc.TUINT16:
+		a = x86.AMOVBWZX
+
+		goto rdst
+
+	case gc.TUINT8<<16 | gc.TINT32,
+		gc.TUINT8<<16 | gc.TUINT32:
+		a = x86.AMOVBLZX
+		goto rdst
+
+	case gc.TUINT8<<16 | gc.TINT64,
+		gc.TUINT8<<16 | gc.TUINT64:
+		a = x86.AMOVBQZX
+		goto rdst
+
+	case gc.TINT16<<16 | gc.TINT32, // sign extend int16
+		gc.TINT16<<16 | gc.TUINT32:
+		a = x86.AMOVWLSX
+
+		goto rdst
+
+	case gc.TINT16<<16 | gc.TINT64,
+		gc.TINT16<<16 | gc.TUINT64:
+		a = x86.AMOVWQSX
+		goto rdst
+
+	case gc.TUINT16<<16 | gc.TINT32, // zero extend uint16
+		gc.TUINT16<<16 | gc.TUINT32:
+		a = x86.AMOVWLZX
+
+		goto rdst
+
+	case gc.TUINT16<<16 | gc.TINT64,
+		gc.TUINT16<<16 | gc.TUINT64:
+		a = x86.AMOVWQZX
+		goto rdst
+
+	case gc.TINT32<<16 | gc.TINT64, // sign extend int32
+		gc.TINT32<<16 | gc.TUINT64:
+		a = x86.AMOVLQSX
+
+		goto rdst
+
+		// AMOVL into a register zeros the top of the register,
+	// so this is not always necessary, but if we rely on AMOVL
+	// the optimizer is almost certain to screw with us.
+	case gc.TUINT32<<16 | gc.TINT64, // zero extend uint32
+		gc.TUINT32<<16 | gc.TUINT64:
+		a = x86.AMOVLQZX
+
+		goto rdst
+
+		/*
+		* float to integer
+		 */
+	case gc.TFLOAT32<<16 | gc.TINT32:
+		a = x86.ACVTTSS2SL
+
+		goto rdst
+
+	case gc.TFLOAT64<<16 | gc.TINT32:
+		a = x86.ACVTTSD2SL
+		goto rdst
+
+	case gc.TFLOAT32<<16 | gc.TINT64:
+		a = x86.ACVTTSS2SQ
+		goto rdst
+
+	case gc.TFLOAT64<<16 | gc.TINT64:
+		a = x86.ACVTTSD2SQ
+		goto rdst
+
+		// convert via int32.
+	case gc.TFLOAT32<<16 | gc.TINT16,
+		gc.TFLOAT32<<16 | gc.TINT8,
+		gc.TFLOAT32<<16 | gc.TUINT16,
+		gc.TFLOAT32<<16 | gc.TUINT8,
+		gc.TFLOAT64<<16 | gc.TINT16,
+		gc.TFLOAT64<<16 | gc.TINT8,
+		gc.TFLOAT64<<16 | gc.TUINT16,
+		gc.TFLOAT64<<16 | gc.TUINT8:
+		cvt = gc.Types[gc.TINT32]
+
+		goto hard
+
+		// convert via int64.
+	case gc.TFLOAT32<<16 | gc.TUINT32,
+		gc.TFLOAT64<<16 | gc.TUINT32:
+		cvt = gc.Types[gc.TINT64]
+
+		goto hard
+
+		// algorithm is:
+	//	if small enough, use native float64 -> int64 conversion.
+	//	otherwise, subtract 2^63, convert, and add it back.
+	case gc.TFLOAT32<<16 | gc.TUINT64,
+		gc.TFLOAT64<<16 | gc.TUINT64:
+		a := x86.ACVTTSS2SQ
+
+		if ft == gc.TFLOAT64 {
+			a = x86.ACVTTSD2SQ
+		}
+		bignodes()
+		var r1 gc.Node
+		gc.Regalloc(&r1, gc.Types[ft], nil)
+		var r2 gc.Node
+		gc.Regalloc(&r2, gc.Types[tt], t)
+		var r3 gc.Node
+		gc.Regalloc(&r3, gc.Types[ft], nil)
+		var r4 gc.Node
+		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)
+		gins(a, &r1, &r2)
+		p2 := gc.Gbranch(obj.AJMP, nil, 0)
+		gc.Patch(p1, gc.Pc)
+		gins(optoas(gc.OAS, f.Type), &bigf, &r3)
+		gins(optoas(gc.OSUB, f.Type), &r3, &r1)
+		gins(a, &r1, &r2)
+		gins(x86.AMOVQ, &bigi, &r4)
+		gins(x86.AXORQ, &r4, &r2)
+		gc.Patch(p2, gc.Pc)
+		gmove(&r2, t)
+		gc.Regfree(&r4)
+		gc.Regfree(&r3)
+		gc.Regfree(&r2)
+		gc.Regfree(&r1)
+		return
+
+		/*
+		 * integer to float
+		 */
+	case gc.TINT32<<16 | gc.TFLOAT32:
+		a = x86.ACVTSL2SS
+
+		goto rdst
+
+	case gc.TINT32<<16 | gc.TFLOAT64:
+		a = x86.ACVTSL2SD
+		goto rdst
+
+	case gc.TINT64<<16 | gc.TFLOAT32:
+		a = x86.ACVTSQ2SS
+		goto rdst
+
+	case gc.TINT64<<16 | gc.TFLOAT64:
+		a = x86.ACVTSQ2SD
+		goto rdst
+
+		// convert via int32
+	case gc.TINT16<<16 | gc.TFLOAT32,
+		gc.TINT16<<16 | gc.TFLOAT64,
+		gc.TINT8<<16 | gc.TFLOAT32,
+		gc.TINT8<<16 | gc.TFLOAT64,
+		gc.TUINT16<<16 | gc.TFLOAT32,
+		gc.TUINT16<<16 | gc.TFLOAT64,
+		gc.TUINT8<<16 | gc.TFLOAT32,
+		gc.TUINT8<<16 | gc.TFLOAT64:
+		cvt = gc.Types[gc.TINT32]
+
+		goto hard
+
+		// convert via int64.
+	case gc.TUINT32<<16 | gc.TFLOAT32,
+		gc.TUINT32<<16 | gc.TFLOAT64:
+		cvt = gc.Types[gc.TINT64]
+
+		goto hard
+
+		// algorithm is:
+	//	if small enough, use native int64 -> uint64 conversion.
+	//	otherwise, halve (rounding to odd?), convert, and double.
+	case gc.TUINT64<<16 | gc.TFLOAT32,
+		gc.TUINT64<<16 | gc.TFLOAT64:
+		a := x86.ACVTSQ2SS
+
+		if tt == gc.TFLOAT64 {
+			a = x86.ACVTSQ2SD
+		}
+		var zero gc.Node
+		gc.Nodconst(&zero, gc.Types[gc.TUINT64], 0)
+		var one gc.Node
+		gc.Nodconst(&one, gc.Types[gc.TUINT64], 1)
+		var r1 gc.Node
+		gc.Regalloc(&r1, f.Type, f)
+		var r2 gc.Node
+		gc.Regalloc(&r2, t.Type, t)
+		var r3 gc.Node
+		gc.Regalloc(&r3, f.Type, nil)
+		var r4 gc.Node
+		gc.Regalloc(&r4, f.Type, nil)
+		gmove(f, &r1)
+		gins(x86.ACMPQ, &r1, &zero)
+		p1 := gc.Gbranch(x86.AJLT, nil, +1)
+		gins(a, &r1, &r2)
+		p2 := gc.Gbranch(obj.AJMP, nil, 0)
+		gc.Patch(p1, gc.Pc)
+		gmove(&r1, &r3)
+		gins(x86.ASHRQ, &one, &r3)
+		gmove(&r1, &r4)
+		gins(x86.AANDL, &one, &r4)
+		gins(x86.AORQ, &r4, &r3)
+		gins(a, &r3, &r2)
+		gins(optoas(gc.OADD, t.Type), &r2, &r2)
+		gc.Patch(p2, gc.Pc)
+		gmove(&r2, t)
+		gc.Regfree(&r4)
+		gc.Regfree(&r3)
+		gc.Regfree(&r2)
+		gc.Regfree(&r1)
+		return
+
+		/*
+		 * float to float
+		 */
+	case gc.TFLOAT32<<16 | gc.TFLOAT32:
+		a = x86.AMOVSS
+
+	case gc.TFLOAT64<<16 | gc.TFLOAT64:
+		a = x86.AMOVSD
+
+	case gc.TFLOAT32<<16 | gc.TFLOAT64:
+		a = x86.ACVTSS2SD
+		goto rdst
+
+	case gc.TFLOAT64<<16 | gc.TFLOAT32:
+		a = x86.ACVTSD2SS
+		goto rdst
+	}
+
+	gins(a, f, t)
+	return
+
+	// requires register destination
+rdst:
+	{
+		var r1 gc.Node
+		gc.Regalloc(&r1, t.Type, t)
+
+		gins(a, f, &r1)
+		gmove(&r1, t)
+		gc.Regfree(&r1)
+		return
+	}
+
+	// requires register intermediate
+hard:
+	var r1 gc.Node
+	gc.Regalloc(&r1, cvt, t)
+
+	gmove(f, &r1)
+	gmove(&r1, t)
+	gc.Regfree(&r1)
+	return
+}
+
+func samaddr(f *gc.Node, t *gc.Node) bool {
+	if f.Op != t.Op {
+		return false
+	}
+
+	switch f.Op {
+	case gc.OREGISTER:
+		if f.Reg != t.Reg {
+			break
+		}
+		return true
+	}
+
+	return false
+}
+
+/*
+ * generate one instruction:
+ *	as f, t
+ */
+func gins(as int, f *gc.Node, t *gc.Node) *obj.Prog {
+	//	Node nod;
+
+	//	if(f != N && f->op == OINDEX) {
+	//		gc.Regalloc(&nod, &regnode, Z);
+	//		v = constnode.vconst;
+	//		gc.Cgen(f->right, &nod);
+	//		constnode.vconst = v;
+	//		idx.reg = nod.reg;
+	//		gc.Regfree(&nod);
+	//	}
+	//	if(t != N && t->op == OINDEX) {
+	//		gc.Regalloc(&nod, &regnode, Z);
+	//		v = constnode.vconst;
+	//		gc.Cgen(t->right, &nod);
+	//		constnode.vconst = v;
+	//		idx.reg = nod.reg;
+	//		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,
+		x86.AMOVL,
+		x86.AMOVQ,
+		x86.AMOVSS,
+		x86.AMOVSD:
+		if f != nil && t != nil && samaddr(f, t) {
+			return nil
+		}
+
+	case x86.ALEAQ:
+		if f != nil && gc.Isconst(f, gc.CTNIL) {
+			gc.Fatal("gins LEAQ nil %v", f.Type)
+		}
+	}
+
+	p := gc.Prog(as)
+	gc.Naddr(&p.From, f)
+	gc.Naddr(&p.To, t)
+
+	if gc.Debug['g'] != 0 {
+		fmt.Printf("%v\n", p)
+	}
+
+	w := int32(0)
+	switch as {
+	case x86.AMOVB:
+		w = 1
+
+	case x86.AMOVW:
+		w = 2
+
+	case x86.AMOVL:
+		w = 4
+
+	case x86.AMOVQ:
+		w = 8
+	}
+
+	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, p.From.Width, p.To.Width)
+	}
+
+	if p.To.Type == obj.TYPE_ADDR && w > 0 {
+		gc.Fatal("bad use of addr: %v", p)
+	}
+
+	return p
+}
+
+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)
+}
+
+/*
+ * 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 := obj.AXXX
+	switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) {
+	default:
+		gc.Fatal("optoas: no entry %v-%v", gc.Oconv(int(op), 0), t)
+
+	case gc.OADDR<<16 | gc.TPTR32:
+		a = x86.ALEAL
+
+	case gc.OADDR<<16 | gc.TPTR64:
+		a = x86.ALEAQ
+
+	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 = x86.AJEQ
+
+	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 = 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.OPC<<16 | gc.TBOOL,
+		gc.OPC<<16 | gc.TINT8,
+		gc.OPC<<16 | gc.TUINT8,
+		gc.OPC<<16 | gc.TINT16,
+		gc.OPC<<16 | gc.TUINT16,
+		gc.OPC<<16 | gc.TINT32,
+		gc.OPC<<16 | gc.TUINT32,
+		gc.OPC<<16 | gc.TINT64,
+		gc.OPC<<16 | gc.TUINT64,
+		gc.OPC<<16 | gc.TPTR32,
+		gc.OPC<<16 | gc.TPTR64,
+		gc.OPC<<16 | gc.TFLOAT32,
+		gc.OPC<<16 | gc.TFLOAT64:
+		a = x86.AJPC
+
+	case gc.OLT<<16 | gc.TINT8,
+		gc.OLT<<16 | gc.TINT16,
+		gc.OLT<<16 | gc.TINT32,
+		gc.OLT<<16 | gc.TINT64:
+		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 = x86.AJCS
+
+	case gc.OLE<<16 | gc.TINT8,
+		gc.OLE<<16 | gc.TINT16,
+		gc.OLE<<16 | gc.TINT32,
+		gc.OLE<<16 | gc.TINT64:
+		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 = x86.AJLS
+
+	case gc.OGT<<16 | gc.TINT8,
+		gc.OGT<<16 | gc.TINT16,
+		gc.OGT<<16 | gc.TINT32,
+		gc.OGT<<16 | gc.TINT64:
+		a = x86.AJGT
+
+	case gc.OGT<<16 | gc.TUINT8,
+		gc.OGT<<16 | gc.TUINT16,
+		gc.OGT<<16 | gc.TUINT32,
+		gc.OGT<<16 | gc.TUINT64,
+		gc.OLT<<16 | gc.TFLOAT32,
+		gc.OLT<<16 | gc.TFLOAT64:
+		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 = x86.AJGE
+
+	case gc.OGE<<16 | gc.TUINT8,
+		gc.OGE<<16 | gc.TUINT16,
+		gc.OGE<<16 | gc.TUINT32,
+		gc.OGE<<16 | gc.TUINT64,
+		gc.OLE<<16 | gc.TFLOAT32,
+		gc.OLE<<16 | gc.TFLOAT64:
+		a = x86.AJCC
+
+	case gc.OCMP<<16 | gc.TBOOL,
+		gc.OCMP<<16 | gc.TINT8,
+		gc.OCMP<<16 | gc.TUINT8:
+		a = x86.ACMPB
+
+	case gc.OCMP<<16 | gc.TINT16,
+		gc.OCMP<<16 | gc.TUINT16:
+		a = x86.ACMPW
+
+	case gc.OCMP<<16 | gc.TINT32,
+		gc.OCMP<<16 | gc.TUINT32,
+		gc.OCMP<<16 | gc.TPTR32:
+		a = x86.ACMPL
+
+	case gc.OCMP<<16 | gc.TINT64,
+		gc.OCMP<<16 | gc.TUINT64,
+		gc.OCMP<<16 | gc.TPTR64:
+		a = x86.ACMPQ
+
+	case gc.OCMP<<16 | gc.TFLOAT32:
+		a = x86.AUCOMISS
+
+	case gc.OCMP<<16 | gc.TFLOAT64:
+		a = x86.AUCOMISD
+
+	case gc.OAS<<16 | gc.TBOOL,
+		gc.OAS<<16 | gc.TINT8,
+		gc.OAS<<16 | gc.TUINT8:
+		a = x86.AMOVB
+
+	case gc.OAS<<16 | gc.TINT16,
+		gc.OAS<<16 | gc.TUINT16:
+		a = x86.AMOVW
+
+	case gc.OAS<<16 | gc.TINT32,
+		gc.OAS<<16 | gc.TUINT32,
+		gc.OAS<<16 | gc.TPTR32:
+		a = x86.AMOVL
+
+	case gc.OAS<<16 | gc.TINT64,
+		gc.OAS<<16 | gc.TUINT64,
+		gc.OAS<<16 | gc.TPTR64:
+		a = x86.AMOVQ
+
+	case gc.OAS<<16 | gc.TFLOAT32:
+		a = x86.AMOVSS
+
+	case gc.OAS<<16 | gc.TFLOAT64:
+		a = x86.AMOVSD
+
+	case gc.OADD<<16 | gc.TINT8,
+		gc.OADD<<16 | gc.TUINT8:
+		a = x86.AADDB
+
+	case gc.OADD<<16 | gc.TINT16,
+		gc.OADD<<16 | gc.TUINT16:
+		a = x86.AADDW
+
+	case gc.OADD<<16 | gc.TINT32,
+		gc.OADD<<16 | gc.TUINT32,
+		gc.OADD<<16 | gc.TPTR32:
+		a = x86.AADDL
+
+	case gc.OADD<<16 | gc.TINT64,
+		gc.OADD<<16 | gc.TUINT64,
+		gc.OADD<<16 | gc.TPTR64:
+		a = x86.AADDQ
+
+	case gc.OADD<<16 | gc.TFLOAT32:
+		a = x86.AADDSS
+
+	case gc.OADD<<16 | gc.TFLOAT64:
+		a = x86.AADDSD
+
+	case gc.OSUB<<16 | gc.TINT8,
+		gc.OSUB<<16 | gc.TUINT8:
+		a = x86.ASUBB
+
+	case gc.OSUB<<16 | gc.TINT16,
+		gc.OSUB<<16 | gc.TUINT16:
+		a = x86.ASUBW
+
+	case gc.OSUB<<16 | gc.TINT32,
+		gc.OSUB<<16 | gc.TUINT32,
+		gc.OSUB<<16 | gc.TPTR32:
+		a = x86.ASUBL
+
+	case gc.OSUB<<16 | gc.TINT64,
+		gc.OSUB<<16 | gc.TUINT64,
+		gc.OSUB<<16 | gc.TPTR64:
+		a = x86.ASUBQ
+
+	case gc.OSUB<<16 | gc.TFLOAT32:
+		a = x86.ASUBSS
+
+	case gc.OSUB<<16 | gc.TFLOAT64:
+		a = x86.ASUBSD
+
+	case gc.OINC<<16 | gc.TINT8,
+		gc.OINC<<16 | gc.TUINT8:
+		a = x86.AINCB
+
+	case gc.OINC<<16 | gc.TINT16,
+		gc.OINC<<16 | gc.TUINT16:
+		a = x86.AINCW
+
+	case gc.OINC<<16 | gc.TINT32,
+		gc.OINC<<16 | gc.TUINT32,
+		gc.OINC<<16 | gc.TPTR32:
+		a = x86.AINCL
+
+	case gc.OINC<<16 | gc.TINT64,
+		gc.OINC<<16 | gc.TUINT64,
+		gc.OINC<<16 | gc.TPTR64:
+		a = x86.AINCQ
+
+	case gc.ODEC<<16 | gc.TINT8,
+		gc.ODEC<<16 | gc.TUINT8:
+		a = x86.ADECB
+
+	case gc.ODEC<<16 | gc.TINT16,
+		gc.ODEC<<16 | gc.TUINT16:
+		a = x86.ADECW
+
+	case gc.ODEC<<16 | gc.TINT32,
+		gc.ODEC<<16 | gc.TUINT32,
+		gc.ODEC<<16 | gc.TPTR32:
+		a = x86.ADECL
+
+	case gc.ODEC<<16 | gc.TINT64,
+		gc.ODEC<<16 | gc.TUINT64,
+		gc.ODEC<<16 | gc.TPTR64:
+		a = x86.ADECQ
+
+	case gc.OMINUS<<16 | gc.TINT8,
+		gc.OMINUS<<16 | gc.TUINT8:
+		a = x86.ANEGB
+
+	case gc.OMINUS<<16 | gc.TINT16,
+		gc.OMINUS<<16 | gc.TUINT16:
+		a = x86.ANEGW
+
+	case gc.OMINUS<<16 | gc.TINT32,
+		gc.OMINUS<<16 | gc.TUINT32,
+		gc.OMINUS<<16 | gc.TPTR32:
+		a = x86.ANEGL
+
+	case gc.OMINUS<<16 | gc.TINT64,
+		gc.OMINUS<<16 | gc.TUINT64,
+		gc.OMINUS<<16 | gc.TPTR64:
+		a = x86.ANEGQ
+
+	case gc.OAND<<16 | gc.TBOOL,
+		gc.OAND<<16 | gc.TINT8,
+		gc.OAND<<16 | gc.TUINT8:
+		a = x86.AANDB
+
+	case gc.OAND<<16 | gc.TINT16,
+		gc.OAND<<16 | gc.TUINT16:
+		a = x86.AANDW
+
+	case gc.OAND<<16 | gc.TINT32,
+		gc.OAND<<16 | gc.TUINT32,
+		gc.OAND<<16 | gc.TPTR32:
+		a = x86.AANDL
+
+	case gc.OAND<<16 | gc.TINT64,
+		gc.OAND<<16 | gc.TUINT64,
+		gc.OAND<<16 | gc.TPTR64:
+		a = x86.AANDQ
+
+	case gc.OOR<<16 | gc.TBOOL,
+		gc.OOR<<16 | gc.TINT8,
+		gc.OOR<<16 | gc.TUINT8:
+		a = x86.AORB
+
+	case gc.OOR<<16 | gc.TINT16,
+		gc.OOR<<16 | gc.TUINT16:
+		a = x86.AORW
+
+	case gc.OOR<<16 | gc.TINT32,
+		gc.OOR<<16 | gc.TUINT32,
+		gc.OOR<<16 | gc.TPTR32:
+		a = x86.AORL
+
+	case gc.OOR<<16 | gc.TINT64,
+		gc.OOR<<16 | gc.TUINT64,
+		gc.OOR<<16 | gc.TPTR64:
+		a = x86.AORQ
+
+	case gc.OXOR<<16 | gc.TINT8,
+		gc.OXOR<<16 | gc.TUINT8:
+		a = x86.AXORB
+
+	case gc.OXOR<<16 | gc.TINT16,
+		gc.OXOR<<16 | gc.TUINT16:
+		a = x86.AXORW
+
+	case gc.OXOR<<16 | gc.TINT32,
+		gc.OXOR<<16 | gc.TUINT32,
+		gc.OXOR<<16 | gc.TPTR32:
+		a = x86.AXORL
+
+	case gc.OXOR<<16 | gc.TINT64,
+		gc.OXOR<<16 | gc.TUINT64,
+		gc.OXOR<<16 | gc.TPTR64:
+		a = x86.AXORQ
+
+	case gc.OLROT<<16 | gc.TINT8,
+		gc.OLROT<<16 | gc.TUINT8:
+		a = x86.AROLB
+
+	case gc.OLROT<<16 | gc.TINT16,
+		gc.OLROT<<16 | gc.TUINT16:
+		a = x86.AROLW
+
+	case gc.OLROT<<16 | gc.TINT32,
+		gc.OLROT<<16 | gc.TUINT32,
+		gc.OLROT<<16 | gc.TPTR32:
+		a = x86.AROLL
+
+	case gc.OLROT<<16 | gc.TINT64,
+		gc.OLROT<<16 | gc.TUINT64,
+		gc.OLROT<<16 | gc.TPTR64:
+		a = x86.AROLQ
+
+	case gc.OLSH<<16 | gc.TINT8,
+		gc.OLSH<<16 | gc.TUINT8:
+		a = x86.ASHLB
+
+	case gc.OLSH<<16 | gc.TINT16,
+		gc.OLSH<<16 | gc.TUINT16:
+		a = x86.ASHLW
+
+	case gc.OLSH<<16 | gc.TINT32,
+		gc.OLSH<<16 | gc.TUINT32,
+		gc.OLSH<<16 | gc.TPTR32:
+		a = x86.ASHLL
+
+	case gc.OLSH<<16 | gc.TINT64,
+		gc.OLSH<<16 | gc.TUINT64,
+		gc.OLSH<<16 | gc.TPTR64:
+		a = x86.ASHLQ
+
+	case gc.ORSH<<16 | gc.TUINT8:
+		a = x86.ASHRB
+
+	case gc.ORSH<<16 | gc.TUINT16:
+		a = x86.ASHRW
+
+	case gc.ORSH<<16 | gc.TUINT32,
+		gc.ORSH<<16 | gc.TPTR32:
+		a = x86.ASHRL
+
+	case gc.ORSH<<16 | gc.TUINT64,
+		gc.ORSH<<16 | gc.TPTR64:
+		a = x86.ASHRQ
+
+	case gc.ORSH<<16 | gc.TINT8:
+		a = x86.ASARB
+
+	case gc.ORSH<<16 | gc.TINT16:
+		a = x86.ASARW
+
+	case gc.ORSH<<16 | gc.TINT32:
+		a = x86.ASARL
+
+	case gc.ORSH<<16 | gc.TINT64:
+		a = x86.ASARQ
+
+	case gc.ORROTC<<16 | gc.TINT8,
+		gc.ORROTC<<16 | gc.TUINT8:
+		a = x86.ARCRB
+
+	case gc.ORROTC<<16 | gc.TINT16,
+		gc.ORROTC<<16 | gc.TUINT16:
+		a = x86.ARCRW
+
+	case gc.ORROTC<<16 | gc.TINT32,
+		gc.ORROTC<<16 | gc.TUINT32:
+		a = x86.ARCRL
+
+	case gc.ORROTC<<16 | gc.TINT64,
+		gc.ORROTC<<16 | gc.TUINT64:
+		a = x86.ARCRQ
+
+	case gc.OHMUL<<16 | gc.TINT8,
+		gc.OMUL<<16 | gc.TINT8,
+		gc.OMUL<<16 | gc.TUINT8:
+		a = x86.AIMULB
+
+	case gc.OHMUL<<16 | gc.TINT16,
+		gc.OMUL<<16 | gc.TINT16,
+		gc.OMUL<<16 | gc.TUINT16:
+		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 = x86.AIMULL
+
+	case gc.OHMUL<<16 | gc.TINT64,
+		gc.OMUL<<16 | gc.TINT64,
+		gc.OMUL<<16 | gc.TUINT64,
+		gc.OMUL<<16 | gc.TPTR64:
+		a = x86.AIMULQ
+
+	case gc.OHMUL<<16 | gc.TUINT8:
+		a = x86.AMULB
+
+	case gc.OHMUL<<16 | gc.TUINT16:
+		a = x86.AMULW
+
+	case gc.OHMUL<<16 | gc.TUINT32,
+		gc.OHMUL<<16 | gc.TPTR32:
+		a = x86.AMULL
+
+	case gc.OHMUL<<16 | gc.TUINT64,
+		gc.OHMUL<<16 | gc.TPTR64:
+		a = x86.AMULQ
+
+	case gc.OMUL<<16 | gc.TFLOAT32:
+		a = x86.AMULSS
+
+	case gc.OMUL<<16 | gc.TFLOAT64:
+		a = x86.AMULSD
+
+	case gc.ODIV<<16 | gc.TINT8,
+		gc.OMOD<<16 | gc.TINT8:
+		a = x86.AIDIVB
+
+	case gc.ODIV<<16 | gc.TUINT8,
+		gc.OMOD<<16 | gc.TUINT8:
+		a = x86.ADIVB
+
+	case gc.ODIV<<16 | gc.TINT16,
+		gc.OMOD<<16 | gc.TINT16:
+		a = x86.AIDIVW
+
+	case gc.ODIV<<16 | gc.TUINT16,
+		gc.OMOD<<16 | gc.TUINT16:
+		a = x86.ADIVW
+
+	case gc.ODIV<<16 | gc.TINT32,
+		gc.OMOD<<16 | gc.TINT32:
+		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 = x86.ADIVL
+
+	case gc.ODIV<<16 | gc.TINT64,
+		gc.OMOD<<16 | gc.TINT64:
+		a = x86.AIDIVQ
+
+	case gc.ODIV<<16 | gc.TUINT64,
+		gc.ODIV<<16 | gc.TPTR64,
+		gc.OMOD<<16 | gc.TUINT64,
+		gc.OMOD<<16 | gc.TPTR64:
+		a = x86.ADIVQ
+
+	case gc.OEXTEND<<16 | gc.TINT16:
+		a = x86.ACWD
+
+	case gc.OEXTEND<<16 | gc.TINT32:
+		a = x86.ACDQ
+
+	case gc.OEXTEND<<16 | gc.TINT64:
+		a = x86.ACQO
+
+	case gc.ODIV<<16 | gc.TFLOAT32:
+		a = x86.ADIVSS
+
+	case gc.ODIV<<16 | gc.TFLOAT64:
+		a = x86.ADIVSD
+
+	case gc.OSQRT<<16 | gc.TFLOAT64:
+		a = x86.ASQRTSD
+	}
+
+	return a
+}
+
+// jmptoset returns ASETxx for AJxx.
+func jmptoset(jmp int) int {
+	switch jmp {
+	case x86.AJEQ:
+		return x86.ASETEQ
+	case x86.AJNE:
+		return x86.ASETNE
+	case x86.AJLT:
+		return x86.ASETLT
+	case x86.AJCS:
+		return x86.ASETCS
+	case x86.AJLE:
+		return x86.ASETLE
+	case x86.AJLS:
+		return x86.ASETLS
+	case x86.AJGT:
+		return x86.ASETGT
+	case x86.AJHI:
+		return x86.ASETHI
+	case x86.AJGE:
+		return x86.ASETGE
+	case x86.AJCC:
+		return x86.ASETCC
+	case x86.AJMI:
+		return x86.ASETMI
+	case x86.AJOC:
+		return x86.ASETOC
+	case x86.AJOS:
+		return x86.ASETOS
+	case x86.AJPC:
+		return x86.ASETPC
+	case x86.AJPL:
+		return x86.ASETPL
+	case x86.AJPS:
+		return x86.ASETPS
+	}
+	gc.Fatal("jmptoset: no entry for %v", gc.Oconv(jmp, 0))
+	panic("unreachable")
+}
+
+const (
+	ODynam   = 1 << 0
+	OAddable = 1 << 1
+)
+
+var clean [20]gc.Node
+
+var cleani int = 0
+
+func sudoclean() {
+	if clean[cleani-1].Op != gc.OEMPTY {
+		gc.Regfree(&clean[cleani-1])
+	}
+	if clean[cleani-2].Op != gc.OEMPTY {
+		gc.Regfree(&clean[cleani-2])
+	}
+	cleani -= 2
+}
+
+/*
+ * 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 {
+	if n.Type == nil {
+		return false
+	}
+
+	*a = obj.Addr{}
+
+	switch n.Op {
+	case gc.OLITERAL:
+		if !gc.Isconst(n, gc.CTINT) {
+			break
+		}
+		v := n.Int()
+		if v >= 32000 || v <= -32000 {
+			break
+		}
+		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]
+		reg1 := &clean[cleani-2]
+		reg.Op = gc.OEMPTY
+		reg1.Op = gc.OEMPTY
+		var nn *gc.Node
+		var oary [10]int64
+		o := gc.Dotoffset(n, oary[:], &nn)
+		if nn == nil {
+			sudoclean()
+			return false
+		}
+
+		if nn.Addable && 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
+}
diff --git a/src/cmd/compile/internal/amd64/peep.go b/src/cmd/compile/internal/amd64/peep.go
new file mode 100644
index 0000000..19db68e
--- /dev/null
+++ b/src/cmd/compile/internal/amd64/peep.go
@@ -0,0 +1,1038 @@
+// 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 at 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 at 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 amd64
+
+import (
+	"cmd/compile/internal/gc"
+	"cmd/internal/obj"
+	"cmd/internal/obj/x86"
+	"fmt"
+)
+
+var gactive uint32
+
+const (
+	exregoffset = x86.REG_R15
+)
+
+// do we need the carry bit
+func needc(p *obj.Prog) bool {
+	for p != nil {
+		flags := progcarryflags(p)
+		if flags&gc.UseCarry != 0 {
+			return true
+		}
+		if flags&(gc.SetCarry|gc.KillCarry) != 0 {
+			return false
+		}
+		p = p.Link
+	}
+
+	return false
+}
+
+func rnops(r *gc.Flow) *gc.Flow {
+	if r != nil {
+		var p *obj.Prog
+		var r1 *gc.Flow
+		for {
+			p = r.Prog
+			if p.As != obj.ANOP || p.From.Type != obj.TYPE_NONE || p.To.Type != obj.TYPE_NONE {
+				break
+			}
+			r1 = gc.Uniqs(r)
+			if r1 == nil {
+				break
+			}
+			r = r1
+		}
+	}
+
+	return r
+}
+
+func peep(firstp *obj.Prog) {
+	g := (*gc.Graph)(gc.Flowstart(firstp, nil))
+	if g == nil {
+		return
+	}
+	gactive = 0
+
+	// byte, word arithmetic elimination.
+	elimshortmov(g)
+
+	// constant propagation
+	// find MOV $con,R followed by
+	// another MOV $con,R without
+	// setting R in the interim
+	var p *obj.Prog
+	for r := (*gc.Flow)(g.Start); r != nil; r = r.Link {
+		p = r.Prog
+		switch p.As {
+		case x86.ALEAL,
+			x86.ALEAQ:
+			if regtyp(&p.To) {
+				if p.From.Sym != nil {
+					if p.From.Index == x86.REG_NONE {
+						conprop(r)
+					}
+				}
+			}
+
+		case x86.AMOVB,
+			x86.AMOVW,
+			x86.AMOVL,
+			x86.AMOVQ,
+			x86.AMOVSS,
+			x86.AMOVSD:
+			if regtyp(&p.To) {
+				if p.From.Type == obj.TYPE_CONST || p.From.Type == obj.TYPE_FCONST {
+					conprop(r)
+				}
+			}
+		}
+	}
+
+	var r *gc.Flow
+	var r1 *gc.Flow
+	var p1 *obj.Prog
+	var t int
+loop1:
+	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
+		gc.Dumpit("loop1", g.Start, 0)
+	}
+
+	t = 0
+	for r = g.Start; r != nil; r = r.Link {
+		p = r.Prog
+		switch p.As {
+		case x86.AMOVL,
+			x86.AMOVQ,
+			x86.AMOVSS,
+			x86.AMOVSD:
+			if regtyp(&p.To) {
+				if regtyp(&p.From) {
+					if copyprop(g, r) {
+						excise(r)
+						t++
+					} else if subprop(r) && copyprop(g, r) {
+						excise(r)
+						t++
+					}
+				}
+			}
+
+		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 = x86.AMOVL
+						t++
+					}
+				}
+			}
+
+		case x86.AMOVBQSX,
+			x86.AMOVBQZX,
+			x86.AMOVWQSX,
+			x86.AMOVWQZX,
+			x86.AMOVLQSX,
+			x86.AMOVLQZX,
+			x86.AMOVQL:
+			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 = x86.AMOVQ
+						t++
+					}
+				}
+			}
+
+		case x86.AADDL,
+			x86.AADDQ,
+			x86.AADDW:
+			if p.From.Type != obj.TYPE_CONST || needc(p.Link) {
+				break
+			}
+			if p.From.Offset == -1 {
+				if p.As == x86.AADDQ {
+					p.As = x86.ADECQ
+				} else if p.As == x86.AADDL {
+					p.As = x86.ADECL
+				} else {
+					p.As = x86.ADECW
+				}
+				p.From = obj.Addr{}
+				break
+			}
+
+			if p.From.Offset == 1 {
+				if p.As == x86.AADDQ {
+					p.As = x86.AINCQ
+				} else if p.As == x86.AADDL {
+					p.As = x86.AINCL
+				} else {
+					p.As = x86.AINCW
+				}
+				p.From = obj.Addr{}
+				break
+			}
+
+		case x86.ASUBL,
+			x86.ASUBQ,
+			x86.ASUBW:
+			if p.From.Type != obj.TYPE_CONST || needc(p.Link) {
+				break
+			}
+			if p.From.Offset == -1 {
+				if p.As == x86.ASUBQ {
+					p.As = x86.AINCQ
+				} else if p.As == x86.ASUBL {
+					p.As = x86.AINCL
+				} else {
+					p.As = x86.AINCW
+				}
+				p.From = obj.Addr{}
+				break
+			}
+
+			if p.From.Offset == 1 {
+				if p.As == x86.ASUBQ {
+					p.As = x86.ADECQ
+				} else if p.As == x86.ASUBL {
+					p.As = x86.ADECL
+				} else {
+					p.As = x86.ADECW
+				}
+				p.From = obj.Addr{}
+				break
+			}
+		}
+	}
+
+	if t != 0 {
+		goto loop1
+	}
+
+	// MOVLQZX removal.
+	// The MOVLQZX exists to avoid being confused for a
+	// MOVL that is just copying 32-bit data around during
+	// copyprop.  Now that copyprop is done, remov MOVLQZX R1, R2
+	// if it is dominated by an earlier ADDL/MOVL/etc into R1 that
+	// will have already cleared the high bits.
+	//
+	// MOVSD removal.
+	// We never use packed registers, so a MOVSD between registers
+	// can be replaced by MOVAPD, which moves the pair of float64s
+	// instead of just the lower one.  We only use the lower one, but
+	// the processor can do better if we do moves using both.
+	for r := (*gc.Flow)(g.Start); r != nil; r = r.Link {
+		p = r.Prog
+		if p.As == x86.AMOVLQZX {
+			if regtyp(&p.From) {
+				if p.From.Type == p.To.Type && p.From.Reg == p.To.Reg {
+					if prevl(r, int(p.From.Reg)) {
+						excise(r)
+					}
+				}
+			}
+		}
+
+		if p.As == x86.AMOVSD {
+			if regtyp(&p.From) {
+				if regtyp(&p.To) {
+					p.As = x86.AMOVAPD
+				}
+			}
+		}
+	}
+
+	// load pipelining
+	// push any load from memory as early as possible
+	// to give it time to complete before use.
+	for r := (*gc.Flow)(g.Start); r != nil; r = r.Link {
+		p = r.Prog
+		switch p.As {
+		case x86.AMOVB,
+			x86.AMOVW,
+			x86.AMOVL,
+			x86.AMOVQ,
+			x86.AMOVLQZX:
+			if regtyp(&p.To) && !regconsttyp(&p.From) {
+				pushback(r)
+			}
+		}
+	}
+
+	gc.Flowend(g)
+}
+
+func pushback(r0 *gc.Flow) {
+	var r *gc.Flow
+	var p *obj.Prog
+
+	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
+		if p.As != obj.ANOP {
+			if !regconsttyp(&p.From) || !regtyp(&p.To) {
+				break
+			}
+			if copyu(p, &p0.To, nil) != 0 || copyu(p0, &p.To, nil) != 0 {
+				break
+			}
+		}
+
+		if p.As == obj.ACALL {
+			break
+		}
+		b = r
+	}
+
+	if b == nil {
+		if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
+			fmt.Printf("no pushback: %v\n", r0.Prog)
+			if r != nil {
+				fmt.Printf("\t%v [%v]\n", r.Prog, gc.Uniqs(r) != nil)
+			}
+		}
+
+		return
+	}
+
+	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)
+			if r == r0 {
+				break
+			}
+		}
+	}
+
+	t := obj.Prog(*r0.Prog)
+	for r = gc.Uniqp(r0); ; r = gc.Uniqp(r) {
+		p0 = r.Link.Prog
+		p = r.Prog
+		p0.As = p.As
+		p0.Lineno = p.Lineno
+		p0.From = p.From
+		p0.To = p.To
+
+		if r == b {
+			break
+		}
+	}
+
+	p0 = r.Prog
+	p0.As = t.As
+	p0.Lineno = t.Lineno
+	p0.From = t.From
+	p0.To = t.To
+
+	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)
+			if r == r0 {
+				break
+			}
+		}
+	}
+}
+
+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 {
+	return a.Type == obj.TYPE_REG && (x86.REG_AX <= a.Reg && a.Reg <= x86.REG_R15 || x86.REG_X0 <= a.Reg && a.Reg <= x86.REG_X15)
+}
+
+// movb elimination.
+// movb is simulated by the linker
+// when a register other than ax, bx, cx, dx
+// is used, so rewrite to other instructions
+// when possible.  a movb into a register
+// can smash the entire 32-bit register without
+// causing any trouble.
+//
+// TODO: Using the Q forms here instead of the L forms
+// seems unnecessary, and it makes the instructions longer.
+func elimshortmov(g *gc.Graph) {
+	var p *obj.Prog
+
+	for r := (*gc.Flow)(g.Start); r != nil; r = r.Link {
+		p = r.Prog
+		if regtyp(&p.To) {
+			switch p.As {
+			case x86.AINCB,
+				x86.AINCW:
+				p.As = x86.AINCQ
+
+			case x86.ADECB,
+				x86.ADECW:
+				p.As = x86.ADECQ
+
+			case x86.ANEGB,
+				x86.ANEGW:
+				p.As = x86.ANEGQ
+
+			case x86.ANOTB,
+				x86.ANOTW:
+				p.As = x86.ANOTQ
+			}
+
+			if regtyp(&p.From) || p.From.Type == obj.TYPE_CONST {
+				// move or artihmetic into partial register.
+				// from another register or constant can be movl.
+				// we don't switch to 64-bit arithmetic if it can
+				// change how the carry bit is set (and the carry bit is needed).
+				switch p.As {
+				case x86.AMOVB,
+					x86.AMOVW:
+					p.As = x86.AMOVQ
+
+				case x86.AADDB,
+					x86.AADDW:
+					if !needc(p.Link) {
+						p.As = x86.AADDQ
+					}
+
+				case x86.ASUBB,
+					x86.ASUBW:
+					if !needc(p.Link) {
+						p.As = x86.ASUBQ
+					}
+
+				case x86.AMULB,
+					x86.AMULW:
+					p.As = x86.AMULQ
+
+				case x86.AIMULB,
+					x86.AIMULW:
+					p.As = x86.AIMULQ
+
+				case x86.AANDB,
+					x86.AANDW:
+					p.As = x86.AANDQ
+
+				case x86.AORB,
+					x86.AORW:
+					p.As = x86.AORQ
+
+				case x86.AXORB,
+					x86.AXORW:
+					p.As = x86.AXORQ
+
+				case x86.ASHLB,
+					x86.ASHLW:
+					p.As = x86.ASHLQ
+				}
+			} else if p.From.Type != obj.TYPE_REG {
+				// explicit zero extension, but don't
+				// do that if source is a byte register
+				// (only AH can occur and it's forbidden).
+				switch p.As {
+				case x86.AMOVB:
+					p.As = x86.AMOVBQZX
+
+				case x86.AMOVW:
+					p.As = x86.AMOVWQZX
+				}
+			}
+		}
+	}
+}
+
+// is 'a' a register or constant?
+func regconsttyp(a *obj.Addr) bool {
+	if regtyp(a) {
+		return true
+	}
+	switch a.Type {
+	case obj.TYPE_CONST,
+		obj.TYPE_FCONST,
+		obj.TYPE_SCONST,
+		obj.TYPE_ADDR: // TODO(rsc): Not all TYPE_ADDRs are constants.
+		return true
+	}
+
+	return false
+}
+
+// is reg guaranteed to be truncated by a previous L instruction?
+func prevl(r0 *gc.Flow, reg int) bool {
+	for r := (*gc.Flow)(gc.Uniqp(r0)); r != nil; r = gc.Uniqp(r) {
+		p := r.Prog
+		if p.To.Type == obj.TYPE_REG && int(p.To.Reg) == reg {
+			flags := progflags(p)
+			if flags&gc.RightWrite != 0 {
+				if flags&gc.SizeL != 0 {
+					return true
+				}
+				return false
+			}
+		}
+	}
+
+	return false
+}
+
+/*
+ * the idea is to substitute
+ * one register for another
+ * from one MOV to another
+ *	MOV	a, R0
+ *	ADD	b, R0	/ no use of R1
+ *	MOV	R0, R1
+ * would be converted to
+ *	MOV	a, R1
+ *	ADD	b, R1
+ *	MOV	R1, R0
+ * hopefully, then the former or latter MOV
+ * will be eliminated by copy propagation.
+ */
+func subprop(r0 *gc.Flow) bool {
+	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
+		fmt.Printf("subprop %v\n", r0.Prog)
+	}
+	p := (*obj.Prog)(r0.Prog)
+	v1 := (*obj.Addr)(&p.From)
+	if !regtyp(v1) {
+		if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
+			fmt.Printf("\tnot regtype %v; return 0\n", gc.Ctxt.Dconv(v1))
+		}
+		return false
+	}
+
+	v2 := (*obj.Addr)(&p.To)
+	if !regtyp(v2) {
+		if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
+			fmt.Printf("\tnot regtype %v; return 0\n", gc.Ctxt.Dconv(v2))
+		}
+		return false
+	}
+
+	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)
+		}
+		if gc.Uniqs(r) == nil {
+			if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
+				fmt.Printf("\tno unique successor\n")
+			}
+			break
+		}
+
+		p = r.Prog
+		if p.As == obj.AVARDEF || p.As == obj.AVARKILL {
+			continue
+		}
+		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 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 (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) {
+			if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
+				fmt.Printf("\tcopyau %v failed\n", gc.Ctxt.Dconv(v2))
+			}
+			break
+		}
+
+		if copysub(&p.From, v1, v2, 0) != 0 || copysub(&p.To, v1, v2, 0) != 0 {
+			if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
+				fmt.Printf("\tcopysub failed\n")
+			}
+			break
+		}
+	}
+
+	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
+		fmt.Printf("\tran off end; return 0\n")
+	}
+	return false
+}
+
+/*
+ * The idea is to remove redundant copies.
+ *	v1->v2	F=0
+ *	(use v2	s/v2/v1/)*
+ *	set v1	F=1
+ *	use v2	return fail
+ *	-----------------
+ *	v1->v2	F=0
+ *	(use v2	s/v2/v1/)*
+ *	set v1	F=1
+ *	set v2	return success
+ */
+func copyprop(g *gc.Graph, r0 *gc.Flow) bool {
+	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
+		fmt.Printf("copyprop %v\n", r0.Prog)
+	}
+	p := (*obj.Prog)(r0.Prog)
+	v1 := (*obj.Addr)(&p.From)
+	v2 := (*obj.Addr)(&p.To)
+	if copyas(v1, v2) {
+		return true
+	}
+	gactive++
+	return copy1(v1, v2, r0.S1, 0)
+}
+
+func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool {
+	if uint32(r.Active) == gactive {
+		if gc.Debug['P'] != 0 {
+			fmt.Printf("act set; return 1\n")
+		}
+		return true
+	}
+
+	r.Active = int32(gactive)
+	if gc.Debug['P'] != 0 {
+		fmt.Printf("copy %v->%v f=%d\n", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), f)
+	}
+	var t int
+	var p *obj.Prog
+	for ; r != nil; r = r.S1 {
+		p = r.Prog
+		if gc.Debug['P'] != 0 {
+			fmt.Printf("%v", p)
+		}
+		if f == 0 && gc.Uniqp(r) == nil {
+			f = 1
+			if gc.Debug['P'] != 0 {
+				fmt.Printf("; merge; f=%d", f)
+			}
+		}
+
+		t = copyu(p, v2, nil)
+		switch t {
+		case 2: /* rar, can't split */
+			if gc.Debug['P'] != 0 {
+				fmt.Printf("; %v rar; return 0\n", gc.Ctxt.Dconv(v2))
+			}
+			return false
+
+		case 3: /* set */
+			if gc.Debug['P'] != 0 {
+				fmt.Printf("; %v set; return 1\n", gc.Ctxt.Dconv(v2))
+			}
+			return true
+
+		case 1, /* used, substitute */
+			4: /* use and set */
+			if f != 0 {
+				if gc.Debug['P'] == 0 {
+					return false
+				}
+				if t == 4 {
+					fmt.Printf("; %v used+set and f=%d; return 0\n", gc.Ctxt.Dconv(v2), f)
+				} else {
+					fmt.Printf("; %v used and f=%d; return 0\n", gc.Ctxt.Dconv(v2), f)
+				}
+				return false
+			}
+
+			if copyu(p, v2, v1) != 0 {
+				if gc.Debug['P'] != 0 {
+					fmt.Printf("; sub fail; return 0\n")
+				}
+				return false
+			}
+
+			if gc.Debug['P'] != 0 {
+				fmt.Printf("; sub %v/%v", gc.Ctxt.Dconv(v2), gc.Ctxt.Dconv(v1))
+			}
+			if t == 4 {
+				if gc.Debug['P'] != 0 {
+					fmt.Printf("; %v used+set; return 1\n", gc.Ctxt.Dconv(v2))
+				}
+				return true
+			}
+		}
+
+		if f == 0 {
+			t = copyu(p, v1, nil)
+			if f == 0 && (t == 2 || t == 3 || t == 4) {
+				f = 1
+				if gc.Debug['P'] != 0 {
+					fmt.Printf("; %v set and !f; f=%d", gc.Ctxt.Dconv(v1), f)
+				}
+			}
+		}
+
+		if gc.Debug['P'] != 0 {
+			fmt.Printf("\n")
+		}
+		if r.S2 != nil {
+			if !copy1(v1, v2, r.S2, f) {
+				return false
+			}
+		}
+	}
+
+	return true
+}
+
+/*
+ * return
+ * 1 if v only used (and substitute),
+ * 2 if read-alter-rewrite
+ * 3 if set
+ * 4 if set and used
+ * 0 otherwise (not touched)
+ */
+func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
+	switch p.As {
+	case obj.AJMP:
+		if s != nil {
+			if copysub(&p.To, v, s, 1) != 0 {
+				return 1
+			}
+			return 0
+		}
+
+		if copyau(&p.To, v) {
+			return 1
+		}
+		return 0
+
+	case obj.ARET:
+		if s != nil {
+			return 1
+		}
+		return 3
+
+	case obj.ACALL:
+		if x86.REGEXT != 0 /*TypeKind(100016)*/ && v.Type == obj.TYPE_REG && v.Reg <= x86.REGEXT && v.Reg > exregoffset {
+			return 2
+		}
+		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 {
+			return 2
+		}
+
+		if s != nil {
+			if copysub(&p.To, v, s, 1) != 0 {
+				return 1
+			}
+			return 0
+		}
+
+		if copyau(&p.To, v) {
+			return 4
+		}
+		return 3
+
+	case obj.ATEXT:
+		if x86.REGARG >= 0 && v.Type == obj.TYPE_REG && v.Reg == x86.REGARG {
+			return 3
+		}
+		return 0
+	}
+
+	if p.As == obj.AVARDEF || p.As == obj.AVARKILL {
+		return 0
+	}
+
+	if (p.Info.Reguse|p.Info.Regset)&RtoB(int(v.Reg)) != 0 {
+		return 2
+	}
+
+	if p.Info.Flags&gc.LeftAddr != 0 {
+		if copyas(&p.From, v) {
+			return 2
+		}
+	}
+
+	if p.Info.Flags&(gc.RightRead|gc.RightWrite) == gc.RightRead|gc.RightWrite {
+		if copyas(&p.To, v) {
+			return 2
+		}
+	}
+
+	if p.Info.Flags&gc.RightWrite != 0 {
+		if copyas(&p.To, v) {
+			if s != nil {
+				return copysub(&p.From, v, s, 1)
+			}
+			if copyau(&p.From, v) {
+				return 4
+			}
+			return 3
+		}
+	}
+
+	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
+			}
+			return copysub(&p.To, v, s, 1)
+		}
+
+		if copyau(&p.From, v) {
+			return 1
+		}
+		if copyau(&p.To, v) {
+			return 1
+		}
+	}
+
+	return 0
+}
+
+/*
+ * direct reference,
+ * could be set/use depending on
+ * semantics
+ */
+func copyas(a *obj.Addr, v *obj.Addr) bool {
+	if x86.REG_AL <= a.Reg && a.Reg <= x86.REG_R15B {
+		gc.Fatal("use of byte register")
+	}
+	if x86.REG_AL <= v.Reg && v.Reg <= x86.REG_R15B {
+		gc.Fatal("use of byte register")
+	}
+
+	if a.Type != v.Type || a.Name != v.Name || a.Reg != v.Reg {
+		return false
+	}
+	if regtyp(v) {
+		return true
+	}
+	if v.Type == obj.TYPE_MEM && (v.Name == obj.NAME_AUTO || v.Name == obj.NAME_PARAM) {
+		if v.Offset == a.Offset {
+			return true
+		}
+	}
+	return false
+}
+
+func sameaddr(a *obj.Addr, v *obj.Addr) bool {
+	if a.Type != v.Type || a.Name != v.Name || a.Reg != v.Reg {
+		return false
+	}
+	if regtyp(v) {
+		return true
+	}
+	if v.Type == obj.TYPE_MEM && (v.Name == obj.NAME_AUTO || v.Name == obj.NAME_PARAM) {
+		if v.Offset == a.Offset {
+			return true
+		}
+	}
+	return false
+}
+
+/*
+ * either direct or indirect
+ */
+func copyau(a *obj.Addr, v *obj.Addr) bool {
+	if copyas(a, v) {
+		if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
+			fmt.Printf("\tcopyau: copyas returned 1\n")
+		}
+		return true
+	}
+
+	if regtyp(v) {
+		if a.Type == obj.TYPE_MEM && a.Reg == v.Reg {
+			if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
+				fmt.Printf("\tcopyau: found indir use - return 1\n")
+			}
+			return true
+		}
+
+		if a.Index == v.Reg {
+			if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
+				fmt.Printf("\tcopyau: found index use - return 1\n")
+			}
+			return true
+		}
+	}
+
+	return false
+}
+
+/*
+ * substitute s for v in a
+ * return failure to substitute
+ */
+func copysub(a *obj.Addr, v *obj.Addr, s *obj.Addr, f int) int {
+	if copyas(a, v) {
+		reg := int(int(s.Reg))
+		if reg >= x86.REG_AX && reg <= x86.REG_R15 || reg >= x86.REG_X0 && reg <= x86.REG_X0+15 {
+			if f != 0 {
+				a.Reg = int16(reg)
+			}
+		}
+
+		return 0
+	}
+
+	if regtyp(v) {
+		reg := int(int(v.Reg))
+		if a.Type == obj.TYPE_MEM && int(a.Reg) == reg {
+			if (s.Reg == x86.REG_BP || s.Reg == x86.REG_R13) && a.Index != x86.REG_NONE {
+				return 1 /* can't use BP-base with index */
+			}
+			if f != 0 {
+				a.Reg = s.Reg
+			}
+		}
+
+		//			return 0;
+		if int(a.Index) == reg {
+			if f != 0 {
+				a.Index = s.Reg
+			}
+			return 0
+		}
+
+		return 0
+	}
+
+	return 0
+}
+
+func conprop(r0 *gc.Flow) {
+	var p *obj.Prog
+	var t int
+
+	p0 := (*obj.Prog)(r0.Prog)
+	v0 := (*obj.Addr)(&p0.To)
+	r := (*gc.Flow)(r0)
+
+loop:
+	r = gc.Uniqs(r)
+	if r == nil || r == r0 {
+		return
+	}
+	if gc.Uniqp(r) == nil {
+		return
+	}
+
+	p = r.Prog
+	t = copyu(p, v0, nil)
+	switch t {
+	case 0, // miss
+		1: // use
+		goto loop
+
+	case 2, // rar
+		4: // use and set
+		break
+
+	case 3: // set
+		if p.As == p0.As {
+			if p.From.Type == p0.From.Type {
+				if p.From.Reg == p0.From.Reg {
+					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.Val.(float64) == p0.From.Val.(float64) {
+									if p.From.Index == p0.From.Index {
+										excise(r)
+										goto loop
+									}
+								}
+							}
+						}
+					}
+				}
+			}
+		}
+	}
+}
+
+func smallindir(a *obj.Addr, reg *obj.Addr) bool {
+	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 == x86.REG_SP
+}
diff --git a/src/cmd/compile/internal/amd64/prog.go b/src/cmd/compile/internal/amd64/prog.go
new file mode 100644
index 0000000..00918c8
--- /dev/null
+++ b/src/cmd/compile/internal/amd64/prog.go
@@ -0,0 +1,308 @@
+// 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 amd64
+
+import (
+	"cmd/compile/internal/gc"
+	"cmd/internal/obj"
+	"cmd/internal/obj/x86"
+)
+
+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 = [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.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.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.ASETCC:    {gc.SizeB | gc.RightWrite | gc.UseCarry, 0, 0, 0},
+	x86.ASETCS:    {gc.SizeB | gc.RightWrite | gc.UseCarry, 0, 0, 0},
+	x86.ASETEQ:    {gc.SizeB | gc.RightWrite | gc.UseCarry, 0, 0, 0},
+	x86.ASETGE:    {gc.SizeB | gc.RightWrite | gc.UseCarry, 0, 0, 0},
+	x86.ASETGT:    {gc.SizeB | gc.RightWrite | gc.UseCarry, 0, 0, 0},
+	x86.ASETHI:    {gc.SizeB | gc.RightWrite | gc.UseCarry, 0, 0, 0},
+	x86.ASETLE:    {gc.SizeB | gc.RightWrite | gc.UseCarry, 0, 0, 0},
+	x86.ASETLS:    {gc.SizeB | gc.RightWrite | gc.UseCarry, 0, 0, 0},
+	x86.ASETLT:    {gc.SizeB | gc.RightWrite | gc.UseCarry, 0, 0, 0},
+	x86.ASETMI:    {gc.SizeB | gc.RightWrite | gc.UseCarry, 0, 0, 0},
+	x86.ASETNE:    {gc.SizeB | gc.RightWrite | gc.UseCarry, 0, 0, 0},
+	x86.ASETOC:    {gc.SizeB | gc.RightWrite | gc.UseCarry, 0, 0, 0},
+	x86.ASETOS:    {gc.SizeB | gc.RightWrite | gc.UseCarry, 0, 0, 0},
+	x86.ASETPC:    {gc.SizeB | gc.RightWrite | gc.UseCarry, 0, 0, 0},
+	x86.ASETPL:    {gc.SizeB | gc.RightWrite | gc.UseCarry, 0, 0, 0},
+	x86.ASETPS:    {gc.SizeB | gc.RightWrite | 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.ASQRTSD:   {gc.SizeD | gc.LeftRead | RightRdwr, 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 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)
+	}
+
+	if (info.Flags&gc.ShiftCX != 0) && p.From.Type != obj.TYPE_CONST {
+		info.Reguse |= CX
+	}
+
+	if info.Flags&gc.ImulAXDX != 0 {
+		if p.To.Type == obj.TYPE_NONE {
+			info.Reguse |= AX
+			info.Regset |= AX | DX
+		} else {
+			info.Flags |= RightRdwr
+		}
+	}
+
+	// Addressing makes some registers used.
+	if p.From.Type == obj.TYPE_MEM && p.From.Name == obj.NAME_NONE {
+		info.Regindex |= RtoB(int(p.From.Reg))
+	}
+	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 != x86.REG_NONE {
+		info.Regindex |= RtoB(int(p.To.Index))
+	}
+	if gc.Ctxt.Flag_dynlink {
+		// When -dynlink is passed, many operations on external names (and
+		// also calling duffzero/duffcopy) use R15 as a scratch register.
+		if p.As == x86.ALEAQ || info.Flags == gc.Pseudo || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
+			return
+		}
+		if p.As == obj.ADUFFZERO || p.As == obj.ADUFFCOPY || (p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local) || (p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local) {
+			info.Reguse |= R15
+			info.Regset |= R15
+			return
+		}
+	}
+}
diff --git a/src/cmd/compile/internal/amd64/reg.go b/src/cmd/compile/internal/amd64/reg.go
new file mode 100644
index 0000000..8fab639
--- /dev/null
+++ b/src/cmd/compile/internal/amd64/reg.go
@@ -0,0 +1,152 @@
+// 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 at 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 at 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 amd64
+
+import (
+	"cmd/compile/internal/gc"
+	"cmd/internal/obj"
+	"cmd/internal/obj/x86"
+)
+
+const (
+	NREGVAR = 32
+)
+
+var regname = []string{
+	".AX",
+	".CX",
+	".DX",
+	".BX",
+	".SP",
+	".BP",
+	".SI",
+	".DI",
+	".R8",
+	".R9",
+	".R10",
+	".R11",
+	".R12",
+	".R13",
+	".R14",
+	".R15",
+	".X0",
+	".X1",
+	".X2",
+	".X3",
+	".X4",
+	".X5",
+	".X6",
+	".X7",
+	".X8",
+	".X9",
+	".X10",
+	".X11",
+	".X12",
+	".X13",
+	".X14",
+	".X15",
+}
+
+func regnames(n *int) []string {
+	*n = NREGVAR
+	return regname
+}
+
+func excludedregs() uint64 {
+	return RtoB(x86.REG_SP)
+}
+
+func doregbits(r int) uint64 {
+	b := uint64(0)
+	if r >= x86.REG_AX && r <= x86.REG_R15 {
+		b |= RtoB(r)
+	} else if r >= x86.REG_AL && r <= x86.REG_R15B {
+		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+15 {
+		b |= FtoB(r)
+	}
+	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)
+	R15 = 1 << (x86.REG_R15 - x86.REG_AX)
+)
+
+func RtoB(r int) uint64 {
+	if r < x86.REG_AX || r > x86.REG_R15 {
+		return 0
+	}
+	return 1 << uint(r-x86.REG_AX)
+}
+
+func BtoR(b uint64) int {
+	b &= 0xffff
+	if gc.Nacl {
+		b &^= (1<<(x86.REG_BP-x86.REG_AX) | 1<<(x86.REG_R15-x86.REG_AX))
+	} else if obj.Framepointer_enabled != 0 {
+		// BP is part of the calling convention if framepointer_enabled.
+		b &^= (1 << (x86.REG_BP - x86.REG_AX))
+	}
+	if b == 0 {
+		return 0
+	}
+	return gc.Bitno(b) + x86.REG_AX
+}
+
+/*
+ *	bit	reg
+ *	16	X0
+ *	...
+ *	31	X15
+ */
+func FtoB(f int) uint64 {
+	if f < x86.REG_X0 || f > x86.REG_X15 {
+		return 0
+	}
+	return 1 << uint(f-x86.REG_X0+16)
+}
+
+func BtoF(b uint64) int {
+	b &= 0xFFFF0000
+	if b == 0 {
+		return 0
+	}
+	return gc.Bitno(b) - 16 + x86.REG_X0
+}
diff --git a/src/cmd/compile/internal/arm/cgen.go b/src/cmd/compile/internal/arm/cgen.go
new file mode 100644
index 0000000..8ea6c5f
--- /dev/null
+++ b/src/cmd/compile/internal/arm/cgen.go
@@ -0,0 +1,229 @@
+// 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 arm
+
+import (
+	"cmd/compile/internal/gc"
+	"cmd/internal/obj"
+	"cmd/internal/obj/arm"
+)
+
+/*
+ * generate array index into res.
+ * n might be any size; res is 32-bit.
+ * returns Prog* to patch to panic call.
+ */
+func cgenindex(n *gc.Node, res *gc.Node, bounded bool) *obj.Prog {
+	if !gc.Is64(n.Type) {
+		gc.Cgen(n, res)
+		return nil
+	}
+
+	var tmp gc.Node
+	gc.Tempname(&tmp, gc.Types[gc.TINT64])
+	gc.Cgen(n, &tmp)
+	var lo gc.Node
+	var hi gc.Node
+	split64(&tmp, &lo, &hi)
+	gmove(&lo, res)
+	if bounded {
+		splitclean()
+		return nil
+	}
+
+	var n1 gc.Node
+	gc.Regalloc(&n1, gc.Types[gc.TINT32], nil)
+	var n2 gc.Node
+	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)
+	gins(arm.ACMP, &n1, &n2)
+	gc.Regfree(&n2)
+	gc.Regfree(&n1)
+	splitclean()
+	return gc.Gbranch(arm.ABNE, nil, -1)
+}
+
+func igenindex(n *gc.Node, res *gc.Node, bounded bool) *obj.Prog {
+	gc.Tempname(res, n.Type)
+	return cgenindex(n, res, bounded)
+}
+
+func blockcopy(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, n.Type)
+
+	case 1:
+		op = arm.AMOVB
+
+	case 2:
+		op = arm.AMOVH
+
+	case 4:
+		op = arm.AMOVW
+	}
+
+	if w%int64(align) != 0 {
+		gc.Fatal("sgen: unaligned size %d (align=%d) for %v", w, align, n.Type)
+	}
+	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
+	}
+
+	if op == arm.AMOVW && !gc.Nacl && dir > 0 && c >= 4 && c <= 128 {
+		var r0 gc.Node
+		r0.Op = gc.OREGISTER
+		r0.Reg = arm.REG_R0
+		var r1 gc.Node
+		r1.Op = gc.OREGISTER
+		r1.Reg = arm.REG_R0 + 1
+		var r2 gc.Node
+		r2.Op = gc.OREGISTER
+		r2.Reg = arm.REG_R0 + 2
+
+		var src gc.Node
+		gc.Regalloc(&src, gc.Types[gc.Tptr], &r1)
+		var dst gc.Node
+		gc.Regalloc(&dst, gc.Types[gc.Tptr], &r2)
+		if n.Ullman >= res.Ullman {
+			// eval n first
+			gc.Agen(n, &src)
+
+			if res.Op == gc.ONAME {
+				gc.Gvardef(res)
+			}
+			gc.Agen(res, &dst)
+		} else {
+			// eval res first
+			if res.Op == gc.ONAME {
+				gc.Gvardef(res)
+			}
+			gc.Agen(res, &dst)
+			gc.Agen(n, &src)
+		}
+
+		var tmp gc.Node
+		gc.Regalloc(&tmp, gc.Types[gc.Tptr], &r0)
+		f := gc.Sysfunc("duffcopy")
+		p := gins(obj.ADUFFCOPY, nil, f)
+		gc.Afunclit(&p.To, f)
+
+		// 8 and 128 = magic constants: see ../../runtime/asm_arm.s
+		p.To.Offset = 8 * (128 - int64(c))
+
+		gc.Regfree(&tmp)
+		gc.Regfree(&src)
+		gc.Regfree(&dst)
+		return
+	}
+
+	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(arm.AMOVW, &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.TUINT32], nil)
+
+	// set up end marker
+	var nend gc.Node
+
+	if c >= 4 {
+		gc.Regalloc(&nend, gc.Types[gc.TUINT32], nil)
+
+		p := gins(arm.AMOVW, &src, &nend)
+		p.From.Type = obj.TYPE_ADDR
+		if dir < 0 {
+			p.From.Offset = int64(dir)
+		} else {
+			p.From.Offset = w
+		}
+	}
+
+	// move src and dest to the end of block if necessary
+	if dir < 0 {
+		p := gins(arm.AMOVW, &src, &src)
+		p.From.Type = obj.TYPE_ADDR
+		p.From.Offset = w + int64(dir)
+
+		p = gins(arm.AMOVW, &dst, &dst)
+		p.From.Type = obj.TYPE_ADDR
+		p.From.Offset = w + int64(dir)
+	}
+
+	// move
+	if c >= 4 {
+		p := gins(op, &src, &tmp)
+		p.From.Type = obj.TYPE_MEM
+		p.From.Offset = int64(dir)
+		p.Scond |= arm.C_PBIT
+		ploop := p
+
+		p = gins(op, &tmp, &dst)
+		p.To.Type = obj.TYPE_MEM
+		p.To.Offset = int64(dir)
+		p.Scond |= arm.C_PBIT
+
+		p = gins(arm.ACMP, &src, nil)
+		raddr(&nend, p)
+
+		gc.Patch(gc.Gbranch(arm.ABNE, nil, 0), ploop)
+		gc.Regfree(&nend)
+	} else {
+		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 |= arm.C_PBIT
+
+			p = gins(op, &tmp, &dst)
+			p.To.Type = obj.TYPE_MEM
+			p.To.Offset = int64(dir)
+			p.Scond |= arm.C_PBIT
+		}
+	}
+
+	gc.Regfree(&dst)
+	gc.Regfree(&src)
+	gc.Regfree(&tmp)
+}
diff --git a/src/cmd/compile/internal/arm/cgen64.go b/src/cmd/compile/internal/arm/cgen64.go
new file mode 100644
index 0000000..cc969b8
--- /dev/null
+++ b/src/cmd/compile/internal/arm/cgen64.go
@@ -0,0 +1,859 @@
+// 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 arm
+
+import (
+	"cmd/compile/internal/gc"
+	"cmd/internal/obj"
+	"cmd/internal/obj/arm"
+)
+
+/*
+ * attempt to generate 64-bit
+ *	res = n
+ * return 1 on success, 0 if op not handled.
+ */
+func cgen64(n *gc.Node, res *gc.Node) {
+	if res.Op != gc.OINDREG && res.Op != gc.ONAME {
+		gc.Dump("n", n)
+		gc.Dump("res", res)
+		gc.Fatal("cgen64 %v of %v", gc.Oconv(int(n.Op), 0), gc.Oconv(int(res.Op), 0))
+	}
+
+	l := n.Left
+	var t1 gc.Node
+	if !l.Addable {
+		gc.Tempname(&t1, l.Type)
+		gc.Cgen(l, &t1)
+		l = &t1
+	}
+
+	var hi1 gc.Node
+	var lo1 gc.Node
+	split64(l, &lo1, &hi1)
+	switch n.Op {
+	default:
+		gc.Fatal("cgen64 %v", gc.Oconv(int(n.Op), 0))
+
+	case gc.OMINUS:
+		var lo2 gc.Node
+		var hi2 gc.Node
+		split64(res, &lo2, &hi2)
+
+		gc.Regalloc(&t1, lo1.Type, nil)
+		var al gc.Node
+		gc.Regalloc(&al, lo1.Type, nil)
+		var ah gc.Node
+		gc.Regalloc(&ah, hi1.Type, nil)
+
+		gins(arm.AMOVW, &lo1, &al)
+		gins(arm.AMOVW, &hi1, &ah)
+
+		gmove(ncon(0), &t1)
+		p1 := gins(arm.ASUB, &al, &t1)
+		p1.Scond |= arm.C_SBIT
+		gins(arm.AMOVW, &t1, &lo2)
+
+		gmove(ncon(0), &t1)
+		gins(arm.ASBC, &ah, &t1)
+		gins(arm.AMOVW, &t1, &hi2)
+
+		gc.Regfree(&t1)
+		gc.Regfree(&al)
+		gc.Regfree(&ah)
+		splitclean()
+		splitclean()
+		return
+
+	case gc.OCOM:
+		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
+		gc.Regalloc(&n1, lo1.Type, nil)
+
+		gins(arm.AMOVW, &lo1, &n1)
+		gins(arm.AEOR, &t1, &n1)
+		gins(arm.AMOVW, &n1, &lo2)
+
+		gins(arm.AMOVW, &hi1, &n1)
+		gins(arm.AEOR, &t1, &n1)
+		gins(arm.AMOVW, &n1, &hi2)
+
+		gc.Regfree(&t1)
+		gc.Regfree(&n1)
+		splitclean()
+		splitclean()
+		return
+
+		// binary operators.
+	// common setup below.
+	case gc.OADD,
+		gc.OSUB,
+		gc.OMUL,
+		gc.OLSH,
+		gc.ORSH,
+		gc.OAND,
+		gc.OOR,
+		gc.OXOR,
+		gc.OLROT:
+		break
+	}
+
+	// setup for binary operators
+	r := n.Right
+
+	if r != nil && !r.Addable {
+		var t2 gc.Node
+		gc.Tempname(&t2, r.Type)
+		gc.Cgen(r, &t2)
+		r = &t2
+	}
+
+	var hi2 gc.Node
+	var lo2 gc.Node
+	if gc.Is64(r.Type) {
+		split64(r, &lo2, &hi2)
+	}
+
+	var al gc.Node
+	gc.Regalloc(&al, lo1.Type, nil)
+	var ah gc.Node
+	gc.Regalloc(&ah, hi1.Type, nil)
+
+	// Do op.  Leave result in ah:al.
+	switch n.Op {
+	default:
+		gc.Fatal("cgen64: not implemented: %v\n", n)
+
+		// TODO: Constants
+	case gc.OADD:
+		var bl gc.Node
+		gc.Regalloc(&bl, gc.Types[gc.TPTR32], nil)
+
+		var bh gc.Node
+		gc.Regalloc(&bh, gc.Types[gc.TPTR32], nil)
+		gins(arm.AMOVW, &hi1, &ah)
+		gins(arm.AMOVW, &lo1, &al)
+		gins(arm.AMOVW, &hi2, &bh)
+		gins(arm.AMOVW, &lo2, &bl)
+		p1 := gins(arm.AADD, &bl, &al)
+		p1.Scond |= arm.C_SBIT
+		gins(arm.AADC, &bh, &ah)
+		gc.Regfree(&bl)
+		gc.Regfree(&bh)
+
+		// TODO: Constants.
+	case gc.OSUB:
+		var bl gc.Node
+		gc.Regalloc(&bl, gc.Types[gc.TPTR32], nil)
+
+		var bh gc.Node
+		gc.Regalloc(&bh, gc.Types[gc.TPTR32], nil)
+		gins(arm.AMOVW, &lo1, &al)
+		gins(arm.AMOVW, &hi1, &ah)
+		gins(arm.AMOVW, &lo2, &bl)
+		gins(arm.AMOVW, &hi2, &bh)
+		p1 := gins(arm.ASUB, &bl, &al)
+		p1.Scond |= arm.C_SBIT
+		gins(arm.ASBC, &bh, &ah)
+		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
+		gc.Regalloc(&bl, gc.Types[gc.TPTR32], nil)
+
+		var bh gc.Node
+		gc.Regalloc(&bh, gc.Types[gc.TPTR32], nil)
+		var cl gc.Node
+		gc.Regalloc(&cl, gc.Types[gc.TPTR32], nil)
+		var ch gc.Node
+		gc.Regalloc(&ch, gc.Types[gc.TPTR32], nil)
+
+		// load args into bh:bl and bh:bl.
+		gins(arm.AMOVW, &hi1, &bh)
+
+		gins(arm.AMOVW, &lo1, &bl)
+		gins(arm.AMOVW, &hi2, &ch)
+		gins(arm.AMOVW, &lo2, &cl)
+
+		// bl * cl -> ah al
+		p1 := gins(arm.AMULLU, nil, nil)
+
+		p1.From.Type = obj.TYPE_REG
+		p1.From.Reg = bl.Reg
+		p1.Reg = cl.Reg
+		p1.To.Type = obj.TYPE_REGREG
+		p1.To.Reg = ah.Reg
+		p1.To.Offset = int64(al.Reg)
+
+		//print("%v\n", p1);
+
+		// bl * ch + ah -> ah
+		p1 = gins(arm.AMULA, nil, nil)
+
+		p1.From.Type = obj.TYPE_REG
+		p1.From.Reg = bl.Reg
+		p1.Reg = ch.Reg
+		p1.To.Type = obj.TYPE_REGREG2
+		p1.To.Reg = ah.Reg
+		p1.To.Offset = int64(ah.Reg)
+
+		//print("%v\n", p1);
+
+		// bh * cl + ah -> ah
+		p1 = gins(arm.AMULA, nil, nil)
+
+		p1.From.Type = obj.TYPE_REG
+		p1.From.Reg = bh.Reg
+		p1.Reg = cl.Reg
+		p1.To.Type = obj.TYPE_REGREG2
+		p1.To.Reg = ah.Reg
+		p1.To.Offset = int64(ah.Reg)
+
+		//print("%v\n", p1);
+
+		gc.Regfree(&bh)
+
+		gc.Regfree(&bl)
+		gc.Regfree(&ch)
+		gc.Regfree(&cl)
+
+		// We only rotate by a constant c in [0,64).
+	// if c >= 32:
+	//	lo, hi = hi, lo
+	//	c -= 32
+	// if c == 0:
+	//	no-op
+	// else:
+	//	t = hi
+	//	shld hi:lo, c
+	//	shld lo:t, c
+	case gc.OLROT:
+		v := uint64(r.Int())
+
+		var bl gc.Node
+		gc.Regalloc(&bl, lo1.Type, nil)
+		var bh gc.Node
+		gc.Regalloc(&bh, hi1.Type, nil)
+		if v >= 32 {
+			// reverse during load to do the first 32 bits of rotate
+			v -= 32
+
+			gins(arm.AMOVW, &hi1, &bl)
+			gins(arm.AMOVW, &lo1, &bh)
+		} else {
+			gins(arm.AMOVW, &hi1, &bh)
+			gins(arm.AMOVW, &lo1, &bl)
+		}
+
+		if v == 0 {
+			gins(arm.AMOVW, &bh, &ah)
+			gins(arm.AMOVW, &bl, &al)
+		} else {
+			// rotate by 1 <= v <= 31
+			//	MOVW	bl<<v, al
+			//	MOVW	bh<<v, ah
+			//	OR		bl>>(32-v), ah
+			//	OR		bh>>(32-v), al
+			gshift(arm.AMOVW, &bl, arm.SHIFT_LL, int32(v), &al)
+
+			gshift(arm.AMOVW, &bh, arm.SHIFT_LL, int32(v), &ah)
+			gshift(arm.AORR, &bl, arm.SHIFT_LR, int32(32-v), &ah)
+			gshift(arm.AORR, &bh, arm.SHIFT_LR, int32(32-v), &al)
+		}
+
+		gc.Regfree(&bl)
+		gc.Regfree(&bh)
+
+	case gc.OLSH:
+		var bl gc.Node
+		gc.Regalloc(&bl, lo1.Type, nil)
+		var bh gc.Node
+		gc.Regalloc(&bh, hi1.Type, nil)
+		gins(arm.AMOVW, &hi1, &bh)
+		gins(arm.AMOVW, &lo1, &bl)
+
+		var p6 *obj.Prog
+		var s gc.Node
+		var n1 gc.Node
+		var creg gc.Node
+		var p1 *obj.Prog
+		var p2 *obj.Prog
+		var p3 *obj.Prog
+		var p4 *obj.Prog
+		var p5 *obj.Prog
+		if r.Op == gc.OLITERAL {
+			v := uint64(r.Int())
+			if v >= 64 {
+				// TODO(kaib): replace with gins(AMOVW, nodintconst(0), &al)
+				// here and below (verify it optimizes to EOR)
+				gins(arm.AEOR, &al, &al)
+
+				gins(arm.AEOR, &ah, &ah)
+			} else if v > 32 {
+				gins(arm.AEOR, &al, &al)
+
+				//	MOVW	bl<<(v-32), ah
+				gshift(arm.AMOVW, &bl, arm.SHIFT_LL, int32(v-32), &ah)
+			} else if v == 32 {
+				gins(arm.AEOR, &al, &al)
+				gins(arm.AMOVW, &bl, &ah)
+			} else if v > 0 {
+				//	MOVW	bl<<v, al
+				gshift(arm.AMOVW, &bl, arm.SHIFT_LL, int32(v), &al)
+
+				//	MOVW	bh<<v, ah
+				gshift(arm.AMOVW, &bh, arm.SHIFT_LL, int32(v), &ah)
+
+				//	OR		bl>>(32-v), ah
+				gshift(arm.AORR, &bl, arm.SHIFT_LR, int32(32-v), &ah)
+			} else {
+				gins(arm.AMOVW, &bl, &al)
+				gins(arm.AMOVW, &bh, &ah)
+			}
+
+			goto olsh_break
+		}
+
+		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
+			var ch gc.Node
+			split64(r, &cl, &ch)
+
+			gmove(&ch, &s)
+			gins(arm.ATST, &s, nil)
+			p6 = gc.Gbranch(arm.ABNE, nil, 0)
+			gmove(&cl, &s)
+			splitclean()
+		} else {
+			gmove(r, &s)
+			p6 = nil
+		}
+
+		gins(arm.ATST, &s, nil)
+
+		// shift == 0
+		p1 = gins(arm.AMOVW, &bl, &al)
+
+		p1.Scond = arm.C_SCOND_EQ
+		p1 = gins(arm.AMOVW, &bh, &ah)
+		p1.Scond = arm.C_SCOND_EQ
+		p2 = gc.Gbranch(arm.ABEQ, nil, 0)
+
+		// shift is < 32
+		gc.Nodconst(&n1, gc.Types[gc.TUINT32], 32)
+
+		gmove(&n1, &creg)
+		gins(arm.ACMP, &s, &creg)
+
+		//	MOVW.LO		bl<<s, al
+		p1 = gregshift(arm.AMOVW, &bl, arm.SHIFT_LL, &s, &al)
+
+		p1.Scond = arm.C_SCOND_LO
+
+		//	MOVW.LO		bh<<s, ah
+		p1 = gregshift(arm.AMOVW, &bh, arm.SHIFT_LL, &s, &ah)
+
+		p1.Scond = arm.C_SCOND_LO
+
+		//	SUB.LO		s, creg
+		p1 = gins(arm.ASUB, &s, &creg)
+
+		p1.Scond = arm.C_SCOND_LO
+
+		//	OR.LO		bl>>creg, ah
+		p1 = gregshift(arm.AORR, &bl, arm.SHIFT_LR, &creg, &ah)
+
+		p1.Scond = arm.C_SCOND_LO
+
+		//	BLO	end
+		p3 = gc.Gbranch(arm.ABLO, nil, 0)
+
+		// shift == 32
+		p1 = gins(arm.AEOR, &al, &al)
+
+		p1.Scond = arm.C_SCOND_EQ
+		p1 = gins(arm.AMOVW, &bl, &ah)
+		p1.Scond = arm.C_SCOND_EQ
+		p4 = gc.Gbranch(arm.ABEQ, nil, 0)
+
+		// shift is < 64
+		gc.Nodconst(&n1, gc.Types[gc.TUINT32], 64)
+
+		gmove(&n1, &creg)
+		gins(arm.ACMP, &s, &creg)
+
+		//	EOR.LO	al, al
+		p1 = gins(arm.AEOR, &al, &al)
+
+		p1.Scond = arm.C_SCOND_LO
+
+		//	MOVW.LO		creg>>1, creg
+		p1 = gshift(arm.AMOVW, &creg, arm.SHIFT_LR, 1, &creg)
+
+		p1.Scond = arm.C_SCOND_LO
+
+		//	SUB.LO		creg, s
+		p1 = gins(arm.ASUB, &creg, &s)
+
+		p1.Scond = arm.C_SCOND_LO
+
+		//	MOVW	bl<<s, ah
+		p1 = gregshift(arm.AMOVW, &bl, arm.SHIFT_LL, &s, &ah)
+
+		p1.Scond = arm.C_SCOND_LO
+
+		p5 = gc.Gbranch(arm.ABLO, nil, 0)
+
+		// shift >= 64
+		if p6 != nil {
+			gc.Patch(p6, gc.Pc)
+		}
+		gins(arm.AEOR, &al, &al)
+		gins(arm.AEOR, &ah, &ah)
+
+		gc.Patch(p2, gc.Pc)
+		gc.Patch(p3, gc.Pc)
+		gc.Patch(p4, gc.Pc)
+		gc.Patch(p5, gc.Pc)
+		gc.Regfree(&s)
+		gc.Regfree(&creg)
+
+	olsh_break:
+		gc.Regfree(&bl)
+		gc.Regfree(&bh)
+
+	case gc.ORSH:
+		var bl gc.Node
+		gc.Regalloc(&bl, lo1.Type, nil)
+		var bh gc.Node
+		gc.Regalloc(&bh, hi1.Type, nil)
+		gins(arm.AMOVW, &hi1, &bh)
+		gins(arm.AMOVW, &lo1, &bl)
+
+		var p4 *obj.Prog
+		var p5 *obj.Prog
+		var n1 gc.Node
+		var p6 *obj.Prog
+		var s gc.Node
+		var p1 *obj.Prog
+		var p2 *obj.Prog
+		var creg gc.Node
+		var p3 *obj.Prog
+		if r.Op == gc.OLITERAL {
+			v := uint64(r.Int())
+			if v >= 64 {
+				if bh.Type.Etype == gc.TINT32 {
+					//	MOVW	bh->31, al
+					gshift(arm.AMOVW, &bh, arm.SHIFT_AR, 31, &al)
+
+					//	MOVW	bh->31, ah
+					gshift(arm.AMOVW, &bh, arm.SHIFT_AR, 31, &ah)
+				} else {
+					gins(arm.AEOR, &al, &al)
+					gins(arm.AEOR, &ah, &ah)
+				}
+			} else if v > 32 {
+				if bh.Type.Etype == gc.TINT32 {
+					//	MOVW	bh->(v-32), al
+					gshift(arm.AMOVW, &bh, arm.SHIFT_AR, int32(v-32), &al)
+
+					//	MOVW	bh->31, ah
+					gshift(arm.AMOVW, &bh, arm.SHIFT_AR, 31, &ah)
+				} else {
+					//	MOVW	bh>>(v-32), al
+					gshift(arm.AMOVW, &bh, arm.SHIFT_LR, int32(v-32), &al)
+
+					gins(arm.AEOR, &ah, &ah)
+				}
+			} else if v == 32 {
+				gins(arm.AMOVW, &bh, &al)
+				if bh.Type.Etype == gc.TINT32 {
+					//	MOVW	bh->31, ah
+					gshift(arm.AMOVW, &bh, arm.SHIFT_AR, 31, &ah)
+				} else {
+					gins(arm.AEOR, &ah, &ah)
+				}
+			} else if v > 0 {
+				//	MOVW	bl>>v, al
+				gshift(arm.AMOVW, &bl, arm.SHIFT_LR, int32(v), &al)
+
+				//	OR		bh<<(32-v), al
+				gshift(arm.AORR, &bh, arm.SHIFT_LL, int32(32-v), &al)
+
+				if bh.Type.Etype == gc.TINT32 {
+					//	MOVW	bh->v, ah
+					gshift(arm.AMOVW, &bh, arm.SHIFT_AR, int32(v), &ah)
+				} else {
+					//	MOVW	bh>>v, ah
+					gshift(arm.AMOVW, &bh, arm.SHIFT_LR, int32(v), &ah)
+				}
+			} else {
+				gins(arm.AMOVW, &bl, &al)
+				gins(arm.AMOVW, &bh, &ah)
+			}
+
+			goto orsh_break
+		}
+
+		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
+			var cl gc.Node
+			split64(r, &cl, &ch)
+
+			gmove(&ch, &s)
+			gins(arm.ATST, &s, nil)
+			var p1 *obj.Prog
+			if bh.Type.Etype == gc.TINT32 {
+				p1 = gshift(arm.AMOVW, &bh, arm.SHIFT_AR, 31, &ah)
+			} else {
+				p1 = gins(arm.AEOR, &ah, &ah)
+			}
+			p1.Scond = arm.C_SCOND_NE
+			p6 = gc.Gbranch(arm.ABNE, nil, 0)
+			gmove(&cl, &s)
+			splitclean()
+		} else {
+			gmove(r, &s)
+			p6 = nil
+		}
+
+		gins(arm.ATST, &s, nil)
+
+		// shift == 0
+		p1 = gins(arm.AMOVW, &bl, &al)
+
+		p1.Scond = arm.C_SCOND_EQ
+		p1 = gins(arm.AMOVW, &bh, &ah)
+		p1.Scond = arm.C_SCOND_EQ
+		p2 = gc.Gbranch(arm.ABEQ, nil, 0)
+
+		// check if shift is < 32
+		gc.Nodconst(&n1, gc.Types[gc.TUINT32], 32)
+
+		gmove(&n1, &creg)
+		gins(arm.ACMP, &s, &creg)
+
+		//	MOVW.LO		bl>>s, al
+		p1 = gregshift(arm.AMOVW, &bl, arm.SHIFT_LR, &s, &al)
+
+		p1.Scond = arm.C_SCOND_LO
+
+		//	SUB.LO		s,creg
+		p1 = gins(arm.ASUB, &s, &creg)
+
+		p1.Scond = arm.C_SCOND_LO
+
+		//	OR.LO		bh<<(32-s), al
+		p1 = gregshift(arm.AORR, &bh, arm.SHIFT_LL, &creg, &al)
+
+		p1.Scond = arm.C_SCOND_LO
+
+		if bh.Type.Etype == gc.TINT32 {
+			//	MOVW	bh->s, ah
+			p1 = gregshift(arm.AMOVW, &bh, arm.SHIFT_AR, &s, &ah)
+		} else {
+			//	MOVW	bh>>s, ah
+			p1 = gregshift(arm.AMOVW, &bh, arm.SHIFT_LR, &s, &ah)
+		}
+
+		p1.Scond = arm.C_SCOND_LO
+
+		//	BLO	end
+		p3 = gc.Gbranch(arm.ABLO, nil, 0)
+
+		// shift == 32
+		p1 = gins(arm.AMOVW, &bh, &al)
+
+		p1.Scond = arm.C_SCOND_EQ
+		if bh.Type.Etype == gc.TINT32 {
+			gshift(arm.AMOVW, &bh, arm.SHIFT_AR, 31, &ah)
+		} else {
+			gins(arm.AEOR, &ah, &ah)
+		}
+		p4 = gc.Gbranch(arm.ABEQ, nil, 0)
+
+		// check if shift is < 64
+		gc.Nodconst(&n1, gc.Types[gc.TUINT32], 64)
+
+		gmove(&n1, &creg)
+		gins(arm.ACMP, &s, &creg)
+
+		//	MOVW.LO		creg>>1, creg
+		p1 = gshift(arm.AMOVW, &creg, arm.SHIFT_LR, 1, &creg)
+
+		p1.Scond = arm.C_SCOND_LO
+
+		//	SUB.LO		creg, s
+		p1 = gins(arm.ASUB, &creg, &s)
+
+		p1.Scond = arm.C_SCOND_LO
+
+		if bh.Type.Etype == gc.TINT32 {
+			//	MOVW	bh->(s-32), al
+			p1 := gregshift(arm.AMOVW, &bh, arm.SHIFT_AR, &s, &al)
+
+			p1.Scond = arm.C_SCOND_LO
+		} else {
+			//	MOVW	bh>>(v-32), al
+			p1 := gregshift(arm.AMOVW, &bh, arm.SHIFT_LR, &s, &al)
+
+			p1.Scond = arm.C_SCOND_LO
+		}
+
+		//	BLO	end
+		p5 = gc.Gbranch(arm.ABLO, nil, 0)
+
+		// s >= 64
+		if p6 != nil {
+			gc.Patch(p6, gc.Pc)
+		}
+		if bh.Type.Etype == gc.TINT32 {
+			//	MOVW	bh->31, al
+			gshift(arm.AMOVW, &bh, arm.SHIFT_AR, 31, &al)
+		} else {
+			gins(arm.AEOR, &al, &al)
+		}
+
+		gc.Patch(p2, gc.Pc)
+		gc.Patch(p3, gc.Pc)
+		gc.Patch(p4, gc.Pc)
+		gc.Patch(p5, gc.Pc)
+		gc.Regfree(&s)
+		gc.Regfree(&creg)
+
+	orsh_break:
+		gc.Regfree(&bl)
+		gc.Regfree(&bh)
+
+		// TODO(kaib): literal optimizations
+	// make constant the right side (it usually is anyway).
+	//		if(lo1.op == OLITERAL) {
+	//			nswap(&lo1, &lo2);
+	//			nswap(&hi1, &hi2);
+	//		}
+	//		if(lo2.op == OLITERAL) {
+	//			// special cases for constants.
+	//			lv = mpgetfix(lo2.val.u.xval);
+	//			hv = mpgetfix(hi2.val.u.xval);
+	//			splitclean();	// right side
+	//			split64(res, &lo2, &hi2);
+	//			switch(n->op) {
+	//			case OXOR:
+	//				gmove(&lo1, &lo2);
+	//				gmove(&hi1, &hi2);
+	//				switch(lv) {
+	//				case 0:
+	//					break;
+	//				case 0xffffffffu:
+	//					gins(ANOTL, N, &lo2);
+	//					break;
+	//				default:
+	//					gins(AXORL, ncon(lv), &lo2);
+	//					break;
+	//				}
+	//				switch(hv) {
+	//				case 0:
+	//					break;
+	//				case 0xffffffffu:
+	//					gins(ANOTL, N, &hi2);
+	//					break;
+	//				default:
+	//					gins(AXORL, ncon(hv), &hi2);
+	//					break;
+	//				}
+	//				break;
+
+	//			case OAND:
+	//				switch(lv) {
+	//				case 0:
+	//					gins(AMOVL, ncon(0), &lo2);
+	//					break;
+	//				default:
+	//					gmove(&lo1, &lo2);
+	//					if(lv != 0xffffffffu)
+	//						gins(AANDL, ncon(lv), &lo2);
+	//					break;
+	//				}
+	//				switch(hv) {
+	//				case 0:
+	//					gins(AMOVL, ncon(0), &hi2);
+	//					break;
+	//				default:
+	//					gmove(&hi1, &hi2);
+	//					if(hv != 0xffffffffu)
+	//						gins(AANDL, ncon(hv), &hi2);
+	//					break;
+	//				}
+	//				break;
+
+	//			case OOR:
+	//				switch(lv) {
+	//				case 0:
+	//					gmove(&lo1, &lo2);
+	//					break;
+	//				case 0xffffffffu:
+	//					gins(AMOVL, ncon(0xffffffffu), &lo2);
+	//					break;
+	//				default:
+	//					gmove(&lo1, &lo2);
+	//					gins(AORL, ncon(lv), &lo2);
+	//					break;
+	//				}
+	//				switch(hv) {
+	//				case 0:
+	//					gmove(&hi1, &hi2);
+	//					break;
+	//				case 0xffffffffu:
+	//					gins(AMOVL, ncon(0xffffffffu), &hi2);
+	//					break;
+	//				default:
+	//					gmove(&hi1, &hi2);
+	//					gins(AORL, ncon(hv), &hi2);
+	//					break;
+	//				}
+	//				break;
+	//			}
+	//			splitclean();
+	//			splitclean();
+	//			goto out;
+	//		}
+	case gc.OXOR,
+		gc.OAND,
+		gc.OOR:
+		var n1 gc.Node
+		gc.Regalloc(&n1, lo1.Type, nil)
+
+		gins(arm.AMOVW, &lo1, &al)
+		gins(arm.AMOVW, &hi1, &ah)
+		gins(arm.AMOVW, &lo2, &n1)
+		gins(optoas(int(n.Op), lo1.Type), &n1, &al)
+		gins(arm.AMOVW, &hi2, &n1)
+		gins(optoas(int(n.Op), lo1.Type), &n1, &ah)
+		gc.Regfree(&n1)
+	}
+
+	if gc.Is64(r.Type) {
+		splitclean()
+	}
+	splitclean()
+
+	split64(res, &lo1, &hi1)
+	gins(arm.AMOVW, &al, &lo1)
+	gins(arm.AMOVW, &ah, &hi1)
+	splitclean()
+
+	//out:
+	gc.Regfree(&al)
+
+	gc.Regfree(&ah)
+}
+
+/*
+ * generate comparison of nl, nr, both 64-bit.
+ * nl is memory; nr is constant or memory.
+ */
+func cmp64(nl *gc.Node, nr *gc.Node, op int, likely int, to *obj.Prog) {
+	var lo1 gc.Node
+	var hi1 gc.Node
+	var lo2 gc.Node
+	var hi2 gc.Node
+	var r1 gc.Node
+	var r2 gc.Node
+
+	split64(nl, &lo1, &hi1)
+	split64(nr, &lo2, &hi2)
+
+	// compare most significant word;
+	// if they differ, we're done.
+	t := hi1.Type
+
+	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)
+	gins(arm.ACMP, &r1, &r2)
+	gc.Regfree(&r1)
+	gc.Regfree(&r2)
+
+	var br *obj.Prog
+	switch op {
+	default:
+		gc.Fatal("cmp64 %v %v", gc.Oconv(int(op), 0), t)
+
+		// cmp hi
+	// bne L
+	// cmp lo
+	// beq to
+	// L:
+	case gc.OEQ:
+		br = gc.Gbranch(arm.ABNE, nil, -likely)
+
+		// cmp hi
+	// bne to
+	// cmp lo
+	// bne to
+	case gc.ONE:
+		gc.Patch(gc.Gbranch(arm.ABNE, nil, likely), to)
+
+		// cmp hi
+	// bgt to
+	// blt L
+	// cmp lo
+	// bge to (or bgt to)
+	// L:
+	case gc.OGE,
+		gc.OGT:
+		gc.Patch(gc.Gbranch(optoas(gc.OGT, t), nil, likely), to)
+
+		br = gc.Gbranch(optoas(gc.OLT, t), nil, -likely)
+
+		// cmp hi
+	// blt to
+	// bgt L
+	// cmp lo
+	// ble to (or jlt to)
+	// L:
+	case gc.OLE,
+		gc.OLT:
+		gc.Patch(gc.Gbranch(optoas(gc.OLT, t), nil, likely), to)
+
+		br = gc.Gbranch(optoas(gc.OGT, t), nil, -likely)
+	}
+
+	// compare least significant word
+	t = lo1.Type
+
+	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)
+	gins(arm.ACMP, &r1, &r2)
+	gc.Regfree(&r1)
+	gc.Regfree(&r2)
+
+	// jump again
+	gc.Patch(gc.Gbranch(optoas(op, t), nil, likely), to)
+
+	// point first branch down here if appropriate
+	if br != nil {
+		gc.Patch(br, gc.Pc)
+	}
+
+	splitclean()
+	splitclean()
+}
diff --git a/src/cmd/compile/internal/arm/galign.go b/src/cmd/compile/internal/arm/galign.go
new file mode 100644
index 0000000..60a39d3
--- /dev/null
+++ b/src/cmd/compile/internal/arm/galign.go
@@ -0,0 +1,94 @@
+// 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 arm
+
+import (
+	"cmd/compile/internal/gc"
+	"cmd/internal/obj"
+	"cmd/internal/obj/arm"
+)
+
+var thechar int = '5'
+
+var thestring string = "arm"
+
+var thelinkarch *obj.LinkArch = &arm.Linkarm
+
+func linkarchinit() {
+}
+
+var MAXWIDTH int64 = (1 << 32) - 1
+
+/*
+ * go declares several platform-specific type aliases:
+ * int, uint, and uintptr
+ */
+var typedefs = []gc.Typedef{
+	gc.Typedef{"int", gc.TINT, gc.TINT32},
+	gc.Typedef{"uint", gc.TUINT, gc.TUINT32},
+	gc.Typedef{"uintptr", gc.TUINTPTR, gc.TUINT32},
+}
+
+func betypeinit() {
+	gc.Widthptr = 4
+	gc.Widthint = 4
+	gc.Widthreg = 4
+}
+
+func Main() {
+	gc.Thearch.Thechar = thechar
+	gc.Thearch.Thestring = thestring
+	gc.Thearch.Thelinkarch = thelinkarch
+	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.ReservedRegs = resvd
+
+	gc.Thearch.Betypeinit = betypeinit
+	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.Getg = getg
+	gc.Thearch.Gins = gins
+	gc.Thearch.Ginscmp = ginscmp
+	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.Regtyp = regtyp
+	gc.Thearch.Sameaddr = sameaddr
+	gc.Thearch.Smallindir = smallindir
+	gc.Thearch.Stackaddr = stackaddr
+	gc.Thearch.Blockcopy = blockcopy
+	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/compile/internal/arm/ggen.go b/src/cmd/compile/internal/arm/ggen.go
new file mode 100644
index 0000000..2d19d75
--- /dev/null
+++ b/src/cmd/compile/internal/arm/ggen.go
@@ -0,0 +1,529 @@
+// 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 arm
+
+import (
+	"cmd/compile/internal/gc"
+	"cmd/internal/obj"
+	"cmd/internal/obj/arm"
+)
+
+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 contain ambiguously live variables
+	// so that garbage collector only sees initialized values
+	// when it looks for pointers.
+	p := ptxt
+
+	hi := int64(0)
+	lo := hi
+	r0 := uint32(0)
+	for l := gc.Curfn.Func.Dcl; l != nil; l = l.Next {
+		n = l.N
+		if !n.Name.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.Widthptr) {
+			// merge with range we already have
+			lo = gc.Rnd(n.Xoffset, int64(gc.Widthptr))
+
+			continue
+		}
+
+		// zero old range
+		p = zerorange(p, int64(frame), lo, hi, &r0)
+
+		// set new range
+		hi = n.Xoffset + n.Type.Width
+
+		lo = n.Xoffset
+	}
+
+	// zero final range
+	zerorange(p, int64(frame), lo, hi, &r0)
+}
+
+func zerorange(p *obj.Prog, frame int64, lo int64, hi int64, r0 *uint32) *obj.Prog {
+	cnt := hi - lo
+	if cnt == 0 {
+		return p
+	}
+	if *r0 == 0 {
+		p = appendpp(p, arm.AMOVW, obj.TYPE_CONST, 0, 0, obj.TYPE_REG, arm.REG_R0, 0)
+		*r0 = 1
+	}
+
+	if cnt < int64(4*gc.Widthptr) {
+		for i := int64(0); i < cnt; i += int64(gc.Widthptr) {
+			p = appendpp(p, arm.AMOVW, obj.TYPE_REG, arm.REG_R0, 0, obj.TYPE_MEM, arm.REGSP, int32(4+frame+lo+i))
+		}
+	} else if !gc.Nacl && (cnt <= int64(128*gc.Widthptr)) {
+		p = appendpp(p, arm.AADD, obj.TYPE_CONST, 0, int32(4+frame+lo), obj.TYPE_REG, arm.REG_R1, 0)
+		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(&p.To, f)
+		gc.Afunclit(&p.To, f)
+		p.To.Offset = 4 * (128 - cnt/int64(gc.Widthptr))
+	} else {
+		p = appendpp(p, arm.AADD, obj.TYPE_CONST, 0, int32(4+frame+lo), obj.TYPE_REG, arm.REG_R1, 0)
+		p.Reg = arm.REGSP
+		p = appendpp(p, arm.AADD, obj.TYPE_CONST, 0, int32(cnt), obj.TYPE_REG, arm.REG_R2, 0)
+		p.Reg = arm.REG_R1
+		p = appendpp(p, arm.AMOVW, obj.TYPE_REG, arm.REG_R0, 0, obj.TYPE_MEM, arm.REG_R1, 4)
+		p1 := p
+		p.Scond |= arm.C_PBIT
+		p = appendpp(p, arm.ACMP, obj.TYPE_REG, arm.REG_R1, 0, obj.TYPE_NONE, 0, 0)
+		p.Reg = arm.REG_R2
+		p = appendpp(p, arm.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 int32, ttype int, treg int, toffset int32) *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 = int64(foffset)
+	q.To.Type = int16(ttype)
+	q.To.Reg = int16(treg)
+	q.To.Offset = int64(toffset)
+	q.Link = p.Link
+	p.Link = q
+	return q
+}
+
+/*
+ * generate high multiply
+ *  res = (nl * nr) >> wordsize
+ */
+func cgen_hmul(nl *gc.Node, nr *gc.Node, res *gc.Node) {
+	if nl.Ullman < nr.Ullman {
+		tmp := nl
+		nl = nr
+		nr = tmp
+	}
+
+	t := nl.Type
+	w := int(t.Width * 8)
+	var n1 gc.Node
+	gc.Regalloc(&n1, t, res)
+	gc.Cgen(nl, &n1)
+	var n2 gc.Node
+	gc.Regalloc(&n2, t, nil)
+	gc.Cgen(nr, &n2)
+	switch gc.Simtype[t.Etype] {
+	case gc.TINT8,
+		gc.TINT16:
+		gins(optoas(gc.OMUL, t), &n2, &n1)
+		gshift(arm.AMOVW, &n1, arm.SHIFT_AR, int32(w), &n1)
+
+	case gc.TUINT8,
+		gc.TUINT16:
+		gins(optoas(gc.OMUL, t), &n2, &n1)
+		gshift(arm.AMOVW, &n1, arm.SHIFT_LR, int32(w), &n1)
+
+		// perform a long multiplication.
+	case gc.TINT32,
+		gc.TUINT32:
+		var p *obj.Prog
+		if gc.Issigned[t.Etype] {
+			p = gins(arm.AMULL, &n2, nil)
+		} else {
+			p = gins(arm.AMULLU, &n2, nil)
+		}
+
+		// n2 * n1 -> (n1 n2)
+		p.Reg = n1.Reg
+
+		p.To.Type = obj.TYPE_REGREG
+		p.To.Reg = n1.Reg
+		p.To.Offset = int64(n2.Reg)
+
+	default:
+		gc.Fatal("cgen_hmul %v", t)
+	}
+
+	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) {
+	if nl.Type.Width > 4 {
+		gc.Fatal("cgen_shift %v", nl.Type)
+	}
+
+	w := int(nl.Type.Width * 8)
+
+	if op == gc.OLROT {
+		v := nr.Int()
+		var n1 gc.Node
+		gc.Regalloc(&n1, nl.Type, res)
+		if w == 32 {
+			gc.Cgen(nl, &n1)
+			gshift(arm.AMOVW, &n1, arm.SHIFT_RR, int32(w)-int32(v), &n1)
+		} else {
+			var n2 gc.Node
+			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)
+			gc.Regfree(&n2)
+
+			// Ensure sign/zero-extended result.
+			gins(optoas(gc.OAS, nl.Type), &n1, &n1)
+		}
+
+		gmove(&n1, res)
+		gc.Regfree(&n1)
+		return
+	}
+
+	if nr.Op == gc.OLITERAL {
+		var n1 gc.Node
+		gc.Regalloc(&n1, nl.Type, res)
+		gc.Cgen(nl, &n1)
+		sc := uint64(nr.Int())
+		if sc == 0 {
+		} else // nothing to do
+		if sc >= uint64(nl.Type.Width*8) {
+			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] {
+				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
+			} else {
+				gshift(arm.AMOVW, &n1, arm.SHIFT_LL, int32(sc), &n1)
+			}
+		}
+
+		if w < 32 && op == gc.OLSH {
+			gins(optoas(gc.OAS, nl.Type), &n1, &n1)
+		}
+		gmove(&n1, res)
+		gc.Regfree(&n1)
+		return
+	}
+
+	tr := nr.Type
+	var t gc.Node
+	var n1 gc.Node
+	var n2 gc.Node
+	var n3 gc.Node
+	if tr.Width > 4 {
+		var nt gc.Node
+		gc.Tempname(&nt, nr.Type)
+		if nl.Ullman >= nr.Ullman {
+			gc.Regalloc(&n2, nl.Type, res)
+			gc.Cgen(nl, &n2)
+			gc.Cgen(nr, &nt)
+			n1 = nt
+		} else {
+			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)
+		gc.Regalloc(&n1, gc.Types[gc.TUINT32], nil)
+		gc.Regalloc(&n3, gc.Types[gc.TUINT32], nil)
+		gmove(&lo, &n1)
+		gmove(&hi, &n3)
+		splitclean()
+		gins(arm.ATST, &n3, nil)
+		gc.Nodconst(&t, gc.Types[gc.TUINT32], int64(w))
+		p1 := gins(arm.AMOVW, &t, &n1)
+		p1.Scond = arm.C_SCOND_NE
+		tr = gc.Types[gc.TUINT32]
+		gc.Regfree(&n3)
+	} else {
+		if nl.Ullman >= nr.Ullman {
+			gc.Regalloc(&n2, nl.Type, res)
+			gc.Cgen(nl, &n2)
+			gc.Regalloc(&n1, nr.Type, nil)
+			gc.Cgen(nr, &n1)
+		} else {
+			gc.Regalloc(&n1, nr.Type, nil)
+			gc.Cgen(nr, &n1)
+			gc.Regalloc(&n2, nl.Type, res)
+			gc.Cgen(nl, &n2)
+		}
+	}
+
+	// test for shift being 0
+	gins(arm.ATST, &n1, nil)
+
+	p3 := gc.Gbranch(arm.ABEQ, nil, -1)
+
+	// test and fix up large shifts
+	// TODO: if(!bounded), don't emit some of this.
+	gc.Regalloc(&n3, tr, nil)
+
+	gc.Nodconst(&t, gc.Types[gc.TUINT32], int64(w))
+	gmove(&t, &n3)
+	gins(arm.ACMP, &n1, &n3)
+	if op == gc.ORSH {
+		var p1 *obj.Prog
+		var p2 *obj.Prog
+		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 {
+			p1 = gins(arm.AEOR, &n2, &n2)
+			p2 = gregshift(arm.AMOVW, &n2, arm.SHIFT_LR, &n1, &n2)
+		}
+
+		p1.Scond = arm.C_SCOND_HS
+		p2.Scond = arm.C_SCOND_LO
+	} else {
+		p1 := gins(arm.AEOR, &n2, &n2)
+		p2 := gregshift(arm.AMOVW, &n2, arm.SHIFT_LL, &n1, &n2)
+		p1.Scond = arm.C_SCOND_HS
+		p2.Scond = arm.C_SCOND_LO
+	}
+
+	gc.Regfree(&n3)
+
+	gc.Patch(p3, gc.Pc)
+
+	// Left-shift of smaller word must be sign/zero-extended.
+	if w < 32 && op == gc.OLSH {
+		gins(optoas(gc.OAS, nl.Type), &n2, &n2)
+	}
+	gmove(&n2, res)
+
+	gc.Regfree(&n1)
+	gc.Regfree(&n2)
+}
+
+func clearfat(nl *gc.Node) {
+	/* clear a fat object */
+	if gc.Debug['g'] != 0 {
+		gc.Dump("\nclearfat", nl)
+	}
+
+	w := uint32(nl.Type.Width)
+
+	// Avoid taking the address for simple enough types.
+	if gc.Componentgen(nil, nl) {
+		return
+	}
+
+	c := w % 4 // bytes
+	q := w / 4 // quads
+
+	var r0 gc.Node
+	r0.Op = gc.OREGISTER
+
+	r0.Reg = arm.REG_R0
+	var r1 gc.Node
+	r1.Op = gc.OREGISTER
+	r1.Reg = arm.REG_R1
+	var dst gc.Node
+	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
+	gc.Regalloc(&nz, gc.Types[gc.TUINT32], &r0)
+	gc.Cgen(&nc, &nz)
+
+	if q > 128 {
+		var end gc.Node
+		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
+
+		p = gins(arm.AMOVW, &nz, &dst)
+		p.To.Type = obj.TYPE_MEM
+		p.To.Offset = 4
+		p.Scond |= arm.C_PBIT
+		pl := p
+
+		p = gins(arm.ACMP, &dst, nil)
+		raddr(&end, p)
+		gc.Patch(gc.Gbranch(arm.ABNE, nil, 0), pl)
+
+		gc.Regfree(&end)
+	} else if q >= 4 && !gc.Nacl {
+		f := gc.Sysfunc("duffzero")
+		p := gins(obj.ADUFFZERO, nil, f)
+		gc.Afunclit(&p.To, f)
+
+		// 4 and 128 = magic constants: see ../../runtime/asm_arm.s
+		p.To.Offset = 4 * (128 - int64(q))
+	} else {
+		var p *obj.Prog
+		for q > 0 {
+			p = gins(arm.AMOVW, &nz, &dst)
+			p.To.Type = obj.TYPE_MEM
+			p.To.Offset = 4
+			p.Scond |= arm.C_PBIT
+
+			//print("1. %v\n", p);
+			q--
+		}
+	}
+
+	var p *obj.Prog
+	for c > 0 {
+		p = gins(arm.AMOVB, &nz, &dst)
+		p.To.Type = obj.TYPE_MEM
+		p.To.Offset = 1
+		p.Scond |= arm.C_PBIT
+
+		//print("2. %v\n", p);
+		c--
+	}
+
+	gc.Regfree(&dst)
+	gc.Regfree(&nz)
+}
+
+// Called after regopt and peep have run.
+// Expand CHECKNIL pseudo-op into actual nil pointer check.
+func expandchecks(firstp *obj.Prog) {
+	var reg int
+	var p1 *obj.Prog
+
+	for p := firstp; p != nil; p = p.Link {
+		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", p)
+		}
+		reg = int(p.From.Reg)
+
+		// check is
+		//	CMP arg, $0
+		//	MOV.EQ arg, 0(arg)
+		p1 = gc.Ctxt.NewProg()
+
+		gc.Clearp(p1)
+		p1.Link = p.Link
+		p.Link = p1
+		p1.Lineno = p.Lineno
+		p1.Pc = 9999
+		p1.As = arm.AMOVW
+		p1.From.Type = obj.TYPE_REG
+		p1.From.Reg = int16(reg)
+		p1.To.Type = obj.TYPE_MEM
+		p1.To.Reg = int16(reg)
+		p1.To.Offset = 0
+		p1.Scond = arm.C_SCOND_EQ
+		p.As = arm.ACMP
+		p.From.Type = obj.TYPE_CONST
+		p.From.Reg = 0
+		p.From.Offset = 0
+		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)
+}
+
+func ginscmp(op int, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
+	if gc.Isint[t.Etype] && n1.Op == gc.OLITERAL && n1.Int() == 0 && n2.Op != gc.OLITERAL {
+		op = gc.Brrev(op)
+		n1, n2 = n2, n1
+	}
+	var r1, r2, g1, g2 gc.Node
+	gc.Regalloc(&r1, t, n1)
+	gc.Regalloc(&g1, n1.Type, &r1)
+	gc.Cgen(n1, &g1)
+	gmove(&g1, &r1)
+	if gc.Isint[t.Etype] && n2.Op == gc.OLITERAL && n2.Int() == 0 {
+		gins(arm.ACMP, &r1, n2)
+	} else {
+		gc.Regalloc(&r2, t, n2)
+		gc.Regalloc(&g2, n1.Type, &r2)
+		gc.Cgen(n2, &g2)
+		gmove(&g2, &r2)
+		gins(optoas(gc.OCMP, t), &r1, &r2)
+		gc.Regfree(&g2)
+		gc.Regfree(&r2)
+	}
+	gc.Regfree(&g1)
+	gc.Regfree(&r1)
+	return gc.Gbranch(optoas(op, t), nil, likely)
+}
+
+// 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
+}
+
+// res = runtime.getg()
+func getg(res *gc.Node) {
+	var n1 gc.Node
+	gc.Nodreg(&n1, res.Type, arm.REGG)
+	gmove(&n1, res)
+}
diff --git a/src/cmd/compile/internal/arm/gsubr.go b/src/cmd/compile/internal/arm/gsubr.go
new file mode 100644
index 0000000..a0a7ba2
--- /dev/null
+++ b/src/cmd/compile/internal/arm/gsubr.go
@@ -0,0 +1,1209 @@
+// Derived from Inferno utils/5c/txt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5c/txt.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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 arm
+
+import (
+	"cmd/compile/internal/gc"
+	"cmd/internal/obj"
+	"cmd/internal/obj/arm"
+	"fmt"
+)
+
+var resvd = []int{
+	arm.REG_R9,  // formerly reserved for m; might be okay to reuse now; not sure about NaCl
+	arm.REG_R10, // reserved for g
+}
+
+/*
+ * return constant i node.
+ * overwritten by next call, but useful in calls to gins.
+ */
+
+var ncon_n gc.Node
+
+func ncon(i uint32) *gc.Node {
+	if ncon_n.Type == nil {
+		gc.Nodconst(&ncon_n, gc.Types[gc.TUINT32], 0)
+	}
+	ncon_n.SetInt(int64(i))
+	return &ncon_n
+}
+
+var sclean [10]gc.Node
+
+var nsclean int
+
+/*
+ * n is a 64-bit value.  fill in lo and hi to refer to its 32-bit halves.
+ */
+func split64(n *gc.Node, lo *gc.Node, hi *gc.Node) {
+	if !gc.Is64(n.Type) {
+		gc.Fatal("split64 %v", n.Type)
+	}
+
+	if nsclean >= len(sclean) {
+		gc.Fatal("split64 clean")
+	}
+	sclean[nsclean].Op = gc.OEMPTY
+	nsclean++
+	switch n.Op {
+	default:
+		switch n.Op {
+		default:
+			var n1 gc.Node
+			if !dotaddable(n, &n1) {
+				gc.Igen(n, &n1, nil)
+				sclean[nsclean-1] = n1
+			}
+
+			n = &n1
+
+		case gc.ONAME:
+			if n.Class == gc.PPARAMREF {
+				var n1 gc.Node
+				gc.Cgen(n.Name.Heapaddr, &n1)
+				sclean[nsclean-1] = n1
+				n = &n1
+			}
+
+			// nothing
+		case gc.OINDREG:
+			break
+		}
+
+		*lo = *n
+		*hi = *n
+		lo.Type = gc.Types[gc.TUINT32]
+		if n.Type.Etype == gc.TINT64 {
+			hi.Type = gc.Types[gc.TINT32]
+		} else {
+			hi.Type = gc.Types[gc.TUINT32]
+		}
+		hi.Xoffset += 4
+
+	case gc.OLITERAL:
+		var n1 gc.Node
+		n.Convconst(&n1, n.Type)
+		i := n1.Int()
+		gc.Nodconst(lo, gc.Types[gc.TUINT32], int64(uint32(i)))
+		i >>= 32
+		if n.Type.Etype == gc.TINT64 {
+			gc.Nodconst(hi, gc.Types[gc.TINT32], int64(int32(i)))
+		} else {
+			gc.Nodconst(hi, gc.Types[gc.TUINT32], int64(uint32(i)))
+		}
+	}
+}
+
+func splitclean() {
+	if nsclean <= 0 {
+		gc.Fatal("splitclean")
+	}
+	nsclean--
+	if sclean[nsclean].Op != gc.OEMPTY {
+		gc.Regfree(&sclean[nsclean])
+	}
+}
+
+func gmove(f *gc.Node, t *gc.Node) {
+	if gc.Debug['M'] != 0 {
+		fmt.Printf("gmove %v -> %v\n", f, t)
+	}
+
+	ft := gc.Simsimtype(f.Type)
+	tt := gc.Simsimtype(t.Type)
+	cvt := t.Type
+
+	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 a int
+	var r1 gc.Node
+	if !gc.Is64(f.Type) && !gc.Is64(t.Type) && 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:
+			f.Convconst(&con, t.Type)
+
+		case gc.TINT16,
+			gc.TINT8:
+			var con gc.Node
+			f.Convconst(&con, gc.Types[gc.TINT32])
+			var r1 gc.Node
+			gc.Regalloc(&r1, con.Type, t)
+			gins(arm.AMOVW, &con, &r1)
+			gmove(&r1, t)
+			gc.Regfree(&r1)
+			return
+
+		case gc.TUINT16,
+			gc.TUINT8:
+			var con gc.Node
+			f.Convconst(&con, gc.Types[gc.TUINT32])
+			var r1 gc.Node
+			gc.Regalloc(&r1, con.Type, t)
+			gins(arm.AMOVW, &con, &r1)
+			gmove(&r1, t)
+			gc.Regfree(&r1)
+			return
+		}
+
+		f = &con
+		ft = gc.Simsimtype(con.Type)
+
+		// constants can't move directly to memory
+		if gc.Ismem(t) && !gc.Is64(t.Type) {
+			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:
+		// should not happen
+		gc.Fatal("gmove %v -> %v", f, t)
+		return
+
+		/*
+		 * integer copy and truncate
+		 */
+	case gc.TINT8<<16 | gc.TINT8: // same size
+		if !gc.Ismem(f) {
+			a = arm.AMOVB
+			break
+		}
+		fallthrough
+
+	case 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:
+		a = arm.AMOVBS
+
+	case gc.TUINT8<<16 | gc.TUINT8:
+		if !gc.Ismem(f) {
+			a = arm.AMOVB
+			break
+		}
+		fallthrough
+
+	case gc.TINT8<<16 | gc.TUINT8,
+		gc.TINT16<<16 | gc.TUINT8,
+		gc.TUINT16<<16 | gc.TUINT8,
+		gc.TINT32<<16 | gc.TUINT8,
+		gc.TUINT32<<16 | gc.TUINT8:
+		a = arm.AMOVBU
+
+	case gc.TINT64<<16 | gc.TINT8, // truncate low word
+		gc.TUINT64<<16 | gc.TINT8:
+		a = arm.AMOVBS
+
+		goto trunc64
+
+	case gc.TINT64<<16 | gc.TUINT8,
+		gc.TUINT64<<16 | gc.TUINT8:
+		a = arm.AMOVBU
+		goto trunc64
+
+	case gc.TINT16<<16 | gc.TINT16: // same size
+		if !gc.Ismem(f) {
+			a = arm.AMOVH
+			break
+		}
+		fallthrough
+
+	case gc.TUINT16<<16 | gc.TINT16,
+		gc.TINT32<<16 | gc.TINT16, // truncate
+		gc.TUINT32<<16 | gc.TINT16:
+		a = arm.AMOVHS
+
+	case gc.TUINT16<<16 | gc.TUINT16:
+		if !gc.Ismem(f) {
+			a = arm.AMOVH
+			break
+		}
+		fallthrough
+
+	case gc.TINT16<<16 | gc.TUINT16,
+		gc.TINT32<<16 | gc.TUINT16,
+		gc.TUINT32<<16 | gc.TUINT16:
+		a = arm.AMOVHU
+
+	case gc.TINT64<<16 | gc.TINT16, // truncate low word
+		gc.TUINT64<<16 | gc.TINT16:
+		a = arm.AMOVHS
+
+		goto trunc64
+
+	case gc.TINT64<<16 | gc.TUINT16,
+		gc.TUINT64<<16 | gc.TUINT16:
+		a = arm.AMOVHU
+		goto trunc64
+
+	case gc.TINT32<<16 | gc.TINT32, // same size
+		gc.TINT32<<16 | gc.TUINT32,
+		gc.TUINT32<<16 | gc.TINT32,
+		gc.TUINT32<<16 | gc.TUINT32:
+		a = arm.AMOVW
+
+	case gc.TINT64<<16 | gc.TINT32, // truncate
+		gc.TUINT64<<16 | gc.TINT32,
+		gc.TINT64<<16 | gc.TUINT32,
+		gc.TUINT64<<16 | gc.TUINT32:
+		var flo gc.Node
+		var fhi gc.Node
+		split64(f, &flo, &fhi)
+
+		var r1 gc.Node
+		gc.Regalloc(&r1, t.Type, nil)
+		gins(arm.AMOVW, &flo, &r1)
+		gins(arm.AMOVW, &r1, t)
+		gc.Regfree(&r1)
+		splitclean()
+		return
+
+	case gc.TINT64<<16 | gc.TINT64, // same size
+		gc.TINT64<<16 | gc.TUINT64,
+		gc.TUINT64<<16 | gc.TINT64,
+		gc.TUINT64<<16 | gc.TUINT64:
+		var fhi gc.Node
+		var flo gc.Node
+		split64(f, &flo, &fhi)
+
+		var tlo gc.Node
+		var thi gc.Node
+		split64(t, &tlo, &thi)
+		var r1 gc.Node
+		gc.Regalloc(&r1, flo.Type, nil)
+		var r2 gc.Node
+		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)
+		gc.Regfree(&r1)
+		gc.Regfree(&r2)
+		splitclean()
+		splitclean()
+		return
+
+		/*
+		 * 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:
+		a = arm.AMOVBS
+
+		goto rdst
+
+	case gc.TINT8<<16 | gc.TINT64, // convert via int32
+		gc.TINT8<<16 | gc.TUINT64:
+		cvt = gc.Types[gc.TINT32]
+
+		goto hard
+
+	case gc.TUINT8<<16 | gc.TINT16, // zero extend uint8
+		gc.TUINT8<<16 | gc.TUINT16,
+		gc.TUINT8<<16 | gc.TINT32,
+		gc.TUINT8<<16 | gc.TUINT32:
+		a = arm.AMOVBU
+
+		goto rdst
+
+	case gc.TUINT8<<16 | gc.TINT64, // convert via uint32
+		gc.TUINT8<<16 | gc.TUINT64:
+		cvt = gc.Types[gc.TUINT32]
+
+		goto hard
+
+	case gc.TINT16<<16 | gc.TINT32, // sign extend int16
+		gc.TINT16<<16 | gc.TUINT32:
+		a = arm.AMOVHS
+
+		goto rdst
+
+	case gc.TINT16<<16 | gc.TINT64, // convert via int32
+		gc.TINT16<<16 | gc.TUINT64:
+		cvt = gc.Types[gc.TINT32]
+
+		goto hard
+
+	case gc.TUINT16<<16 | gc.TINT32, // zero extend uint16
+		gc.TUINT16<<16 | gc.TUINT32:
+		a = arm.AMOVHU
+
+		goto rdst
+
+	case gc.TUINT16<<16 | gc.TINT64, // convert via uint32
+		gc.TUINT16<<16 | gc.TUINT64:
+		cvt = gc.Types[gc.TUINT32]
+
+		goto hard
+
+	case gc.TINT32<<16 | gc.TINT64, // sign extend int32
+		gc.TINT32<<16 | gc.TUINT64:
+		var tlo gc.Node
+		var thi gc.Node
+		split64(t, &tlo, &thi)
+
+		var r1 gc.Node
+		gc.Regalloc(&r1, tlo.Type, nil)
+		var r2 gc.Node
+		gc.Regalloc(&r2, thi.Type, nil)
+		gmove(f, &r1)
+		p1 := gins(arm.AMOVW, &r1, &r2)
+		p1.From.Type = obj.TYPE_SHIFT
+		p1.From.Offset = 2<<5 | 31<<7 | int64(r1.Reg)&15 // r1->31
+		p1.From.Reg = 0
+
+		//print("gmove: %v\n", p1);
+		gins(arm.AMOVW, &r1, &tlo)
+
+		gins(arm.AMOVW, &r2, &thi)
+		gc.Regfree(&r1)
+		gc.Regfree(&r2)
+		splitclean()
+		return
+
+	case gc.TUINT32<<16 | gc.TINT64, // zero extend uint32
+		gc.TUINT32<<16 | gc.TUINT64:
+		var thi gc.Node
+		var tlo gc.Node
+		split64(t, &tlo, &thi)
+
+		gmove(f, &tlo)
+		var r1 gc.Node
+		gc.Regalloc(&r1, thi.Type, nil)
+		gins(arm.AMOVW, ncon(0), &r1)
+		gins(arm.AMOVW, &r1, &thi)
+		gc.Regfree(&r1)
+		splitclean()
+		return
+
+		//	case CASE(TFLOAT64, TUINT64):
+	/*
+	* float to integer
+	 */
+	case gc.TFLOAT32<<16 | gc.TINT8,
+		gc.TFLOAT32<<16 | gc.TUINT8,
+		gc.TFLOAT32<<16 | gc.TINT16,
+		gc.TFLOAT32<<16 | gc.TUINT16,
+		gc.TFLOAT32<<16 | gc.TINT32,
+		gc.TFLOAT32<<16 | gc.TUINT32,
+
+		//	case CASE(TFLOAT32, TUINT64):
+
+		gc.TFLOAT64<<16 | gc.TINT8,
+		gc.TFLOAT64<<16 | gc.TUINT8,
+		gc.TFLOAT64<<16 | gc.TINT16,
+		gc.TFLOAT64<<16 | gc.TUINT16,
+		gc.TFLOAT64<<16 | gc.TINT32,
+		gc.TFLOAT64<<16 | gc.TUINT32:
+		fa := arm.AMOVF
+
+		a := arm.AMOVFW
+		if ft == gc.TFLOAT64 {
+			fa = arm.AMOVD
+			a = arm.AMOVDW
+		}
+
+		ta := arm.AMOVW
+		switch tt {
+		case gc.TINT8:
+			ta = arm.AMOVBS
+
+		case gc.TUINT8:
+			ta = arm.AMOVBU
+
+		case gc.TINT16:
+			ta = arm.AMOVHS
+
+		case gc.TUINT16:
+			ta = arm.AMOVHU
+		}
+
+		var r1 gc.Node
+		gc.Regalloc(&r1, gc.Types[ft], f)
+		var r2 gc.Node
+		gc.Regalloc(&r2, gc.Types[tt], t)
+		gins(fa, f, &r1)        // load to fpu
+		p1 := gins(a, &r1, &r1) // convert to w
+		switch tt {
+		case gc.TUINT8,
+			gc.TUINT16,
+			gc.TUINT32:
+			p1.Scond |= arm.C_UBIT
+		}
+
+		gins(arm.AMOVW, &r1, &r2) // copy to cpu
+		gins(ta, &r2, t)          // store
+		gc.Regfree(&r1)
+		gc.Regfree(&r2)
+		return
+
+		/*
+		 * integer to float
+		 */
+	case gc.TINT8<<16 | gc.TFLOAT32,
+		gc.TUINT8<<16 | gc.TFLOAT32,
+		gc.TINT16<<16 | gc.TFLOAT32,
+		gc.TUINT16<<16 | gc.TFLOAT32,
+		gc.TINT32<<16 | gc.TFLOAT32,
+		gc.TUINT32<<16 | gc.TFLOAT32,
+		gc.TINT8<<16 | gc.TFLOAT64,
+		gc.TUINT8<<16 | gc.TFLOAT64,
+		gc.TINT16<<16 | gc.TFLOAT64,
+		gc.TUINT16<<16 | gc.TFLOAT64,
+		gc.TINT32<<16 | gc.TFLOAT64,
+		gc.TUINT32<<16 | gc.TFLOAT64:
+		fa := arm.AMOVW
+
+		switch ft {
+		case gc.TINT8:
+			fa = arm.AMOVBS
+
+		case gc.TUINT8:
+			fa = arm.AMOVBU
+
+		case gc.TINT16:
+			fa = arm.AMOVHS
+
+		case gc.TUINT16:
+			fa = arm.AMOVHU
+		}
+
+		a := arm.AMOVWF
+		ta := arm.AMOVF
+		if tt == gc.TFLOAT64 {
+			a = arm.AMOVWD
+			ta = arm.AMOVD
+		}
+
+		var r1 gc.Node
+		gc.Regalloc(&r1, gc.Types[ft], f)
+		var r2 gc.Node
+		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
+		switch ft {
+		case gc.TUINT8,
+			gc.TUINT16,
+			gc.TUINT32:
+			p1.Scond |= arm.C_UBIT
+		}
+
+		gins(ta, &r2, t) // store
+		gc.Regfree(&r1)
+		gc.Regfree(&r2)
+		return
+
+	case gc.TUINT64<<16 | gc.TFLOAT32,
+		gc.TUINT64<<16 | gc.TFLOAT64:
+		gc.Fatal("gmove UINT64, TFLOAT not implemented")
+		return
+
+		/*
+		 * float to float
+		 */
+	case gc.TFLOAT32<<16 | gc.TFLOAT32:
+		a = arm.AMOVF
+
+	case gc.TFLOAT64<<16 | gc.TFLOAT64:
+		a = arm.AMOVD
+
+	case gc.TFLOAT32<<16 | gc.TFLOAT64:
+		var r1 gc.Node
+		gc.Regalloc(&r1, gc.Types[gc.TFLOAT64], t)
+		gins(arm.AMOVF, f, &r1)
+		gins(arm.AMOVFD, &r1, &r1)
+		gins(arm.AMOVD, &r1, t)
+		gc.Regfree(&r1)
+		return
+
+	case gc.TFLOAT64<<16 | gc.TFLOAT32:
+		var r1 gc.Node
+		gc.Regalloc(&r1, gc.Types[gc.TFLOAT64], t)
+		gins(arm.AMOVD, f, &r1)
+		gins(arm.AMOVDF, &r1, &r1)
+		gins(arm.AMOVF, &r1, t)
+		gc.Regfree(&r1)
+		return
+	}
+
+	gins(a, f, t)
+	return
+
+	// TODO(kaib): we almost always require a register dest anyway, this can probably be
+	// removed.
+	// 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
+
+	// truncate 64 bit integer
+trunc64:
+	var fhi gc.Node
+	var flo gc.Node
+	split64(f, &flo, &fhi)
+
+	gc.Regalloc(&r1, t.Type, nil)
+	gins(a, &flo, &r1)
+	gins(a, &r1, t)
+	gc.Regfree(&r1)
+	splitclean()
+	return
+}
+
+func samaddr(f *gc.Node, t *gc.Node) bool {
+	if f.Op != t.Op {
+		return false
+	}
+
+	switch f.Op {
+	case gc.OREGISTER:
+		if f.Reg != t.Reg {
+			break
+		}
+		return true
+	}
+
+	return false
+}
+
+/*
+ * generate one instruction:
+ *	as f, t
+ */
+func gins(as int, f *gc.Node, t *gc.Node) *obj.Prog {
+	//	Node nod;
+	//	int32 v;
+
+	if f != nil && f.Op == gc.OINDEX {
+		gc.Fatal("gins OINDEX not implemented")
+	}
+
+	//		gc.Regalloc(&nod, &regnode, Z);
+	//		v = constnode.vconst;
+	//		gc.Cgen(f->right, &nod);
+	//		constnode.vconst = v;
+	//		idx.reg = nod.reg;
+	//		gc.Regfree(&nod);
+	if t != nil && t.Op == gc.OINDEX {
+		gc.Fatal("gins OINDEX not implemented")
+	}
+
+	//		gc.Regalloc(&nod, &regnode, Z);
+	//		v = constnode.vconst;
+	//		gc.Cgen(t->right, &nod);
+	//		constnode.vconst = v;
+	//		idx.reg = nod.reg;
+	//		gc.Regfree(&nod);
+
+	p := gc.Prog(as)
+	gc.Naddr(&p.From, f)
+	gc.Naddr(&p.To, t)
+
+	switch as {
+	case arm.ABL:
+		if p.To.Type == obj.TYPE_REG {
+			p.To.Type = obj.TYPE_MEM
+		}
+
+	case arm.ACMP, arm.ACMPF, arm.ACMPD:
+		if t != nil {
+			if f.Op != gc.OREGISTER {
+				/* generate a comparison
+				TODO(kaib): one of the args can actually be a small constant. relax the constraint and fix call sites.
+				*/
+				gc.Fatal("bad operands to gcmp")
+			}
+			p.From = p.To
+			p.To = obj.Addr{}
+			raddr(f, p)
+		}
+
+	case arm.AMULU:
+		if f != nil && f.Op != gc.OREGISTER {
+			gc.Fatal("bad operands to mul")
+		}
+
+	case arm.AMOVW:
+		if (p.From.Type == obj.TYPE_MEM || p.From.Type == obj.TYPE_ADDR || p.From.Type == obj.TYPE_CONST) && (p.To.Type == obj.TYPE_MEM || p.To.Type == obj.TYPE_ADDR) {
+			gc.Fatal("gins double memory")
+		}
+
+	case arm.AADD:
+		if p.To.Type == obj.TYPE_MEM {
+			gc.Fatal("gins arith to mem")
+		}
+
+	case arm.ARSB:
+		if p.From.Type == obj.TYPE_NONE {
+			gc.Fatal("rsb with no from")
+		}
+	}
+
+	if gc.Debug['g'] != 0 {
+		fmt.Printf("%v\n", p)
+	}
+	return p
+}
+
+/*
+ * 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
+	}
+}
+
+/* generate a constant shift
+ * arm encodes a shift by 32 as 0, thus asking for 0 shift is illegal.
+ */
+func gshift(as int, lhs *gc.Node, stype int32, sval int32, rhs *gc.Node) *obj.Prog {
+	if sval <= 0 || sval > 32 {
+		gc.Fatal("bad shift value: %d", sval)
+	}
+
+	sval = sval & 0x1f
+
+	p := gins(as, nil, rhs)
+	p.From.Type = obj.TYPE_SHIFT
+	p.From.Offset = int64(stype) | int64(sval)<<7 | int64(lhs.Reg)&15
+	return p
+}
+
+/* generate a register shift
+ */
+func gregshift(as int, lhs *gc.Node, stype int32, reg *gc.Node, rhs *gc.Node) *obj.Prog {
+	p := gins(as, nil, rhs)
+	p.From.Type = obj.TYPE_SHIFT
+	p.From.Offset = int64(stype) | (int64(reg.Reg)&15)<<8 | 1<<4 | int64(lhs.Reg)&15
+	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 := obj.AXXX
+	switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) {
+	default:
+		gc.Fatal("optoas: no entry %v-%v etype %v simtype %v", gc.Oconv(int(op), 0), t, gc.Types[t.Etype], gc.Types[gc.Simtype[t.Etype]])
+
+		/*	case CASE(OADDR, TPTR32):
+				a = ALEAL;
+				break;
+
+			case CASE(OADDR, TPTR64):
+				a = ALEAQ;
+				break;
+		*/
+	// TODO(kaib): make sure the conditional branches work on all edge cases
+	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 = arm.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 = arm.ABNE
+
+	case gc.OLT<<16 | gc.TINT8,
+		gc.OLT<<16 | gc.TINT16,
+		gc.OLT<<16 | gc.TINT32,
+		gc.OLT<<16 | gc.TINT64,
+		gc.OLT<<16 | gc.TFLOAT32,
+		gc.OLT<<16 | gc.TFLOAT64:
+		a = arm.ABLT
+
+	case gc.OLT<<16 | gc.TUINT8,
+		gc.OLT<<16 | gc.TUINT16,
+		gc.OLT<<16 | gc.TUINT32,
+		gc.OLT<<16 | gc.TUINT64:
+		a = arm.ABLO
+
+	case gc.OLE<<16 | gc.TINT8,
+		gc.OLE<<16 | gc.TINT16,
+		gc.OLE<<16 | gc.TINT32,
+		gc.OLE<<16 | gc.TINT64,
+		gc.OLE<<16 | gc.TFLOAT32,
+		gc.OLE<<16 | gc.TFLOAT64:
+		a = arm.ABLE
+
+	case gc.OLE<<16 | gc.TUINT8,
+		gc.OLE<<16 | gc.TUINT16,
+		gc.OLE<<16 | gc.TUINT32,
+		gc.OLE<<16 | gc.TUINT64:
+		a = arm.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 = arm.ABGT
+
+	case gc.OGT<<16 | gc.TUINT8,
+		gc.OGT<<16 | gc.TUINT16,
+		gc.OGT<<16 | gc.TUINT32,
+		gc.OGT<<16 | gc.TUINT64:
+		a = arm.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 = arm.ABGE
+
+	case gc.OGE<<16 | gc.TUINT8,
+		gc.OGE<<16 | gc.TUINT16,
+		gc.OGE<<16 | gc.TUINT32,
+		gc.OGE<<16 | gc.TUINT64:
+		a = arm.ABHS
+
+	case gc.OCMP<<16 | gc.TBOOL,
+		gc.OCMP<<16 | gc.TINT8,
+		gc.OCMP<<16 | gc.TUINT8,
+		gc.OCMP<<16 | gc.TINT16,
+		gc.OCMP<<16 | gc.TUINT16,
+		gc.OCMP<<16 | gc.TINT32,
+		gc.OCMP<<16 | gc.TUINT32,
+		gc.OCMP<<16 | gc.TPTR32:
+		a = arm.ACMP
+
+	case gc.OCMP<<16 | gc.TFLOAT32:
+		a = arm.ACMPF
+
+	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
+
+	case gc.OAS<<16 | gc.TINT8:
+		a = arm.AMOVBS
+
+	case gc.OAS<<16 | gc.TUINT8:
+		a = arm.AMOVBU
+
+	case gc.OAS<<16 | gc.TINT16:
+		a = arm.AMOVHS
+
+	case gc.OAS<<16 | gc.TUINT16:
+		a = arm.AMOVHU
+
+	case gc.OAS<<16 | gc.TINT32,
+		gc.OAS<<16 | gc.TUINT32,
+		gc.OAS<<16 | gc.TPTR32:
+		a = arm.AMOVW
+
+	case gc.OAS<<16 | gc.TFLOAT32:
+		a = arm.AMOVF
+
+	case gc.OAS<<16 | gc.TFLOAT64:
+		a = arm.AMOVD
+
+	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:
+		a = arm.AADD
+
+	case gc.OADD<<16 | gc.TFLOAT32:
+		a = arm.AADDF
+
+	case gc.OADD<<16 | gc.TFLOAT64:
+		a = arm.AADDD
+
+	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:
+		a = arm.ASUB
+
+	case gc.OSUB<<16 | gc.TFLOAT32:
+		a = arm.ASUBF
+
+	case gc.OSUB<<16 | gc.TFLOAT64:
+		a = arm.ASUBD
+
+	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:
+		a = arm.ARSB
+
+	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:
+		a = arm.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:
+		a = arm.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:
+		a = arm.AEOR
+
+	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:
+		a = arm.ASLL
+
+	case gc.ORSH<<16 | gc.TUINT8,
+		gc.ORSH<<16 | gc.TUINT16,
+		gc.ORSH<<16 | gc.TUINT32,
+		gc.ORSH<<16 | gc.TPTR32:
+		a = arm.ASRL
+
+	case gc.ORSH<<16 | gc.TINT8,
+		gc.ORSH<<16 | gc.TINT16,
+		gc.ORSH<<16 | gc.TINT32:
+		a = arm.ASRA
+
+	case gc.OMUL<<16 | gc.TUINT8,
+		gc.OMUL<<16 | gc.TUINT16,
+		gc.OMUL<<16 | gc.TUINT32,
+		gc.OMUL<<16 | gc.TPTR32:
+		a = arm.AMULU
+
+	case gc.OMUL<<16 | gc.TINT8,
+		gc.OMUL<<16 | gc.TINT16,
+		gc.OMUL<<16 | gc.TINT32:
+		a = arm.AMUL
+
+	case gc.OMUL<<16 | gc.TFLOAT32:
+		a = arm.AMULF
+
+	case gc.OMUL<<16 | gc.TFLOAT64:
+		a = arm.AMULD
+
+	case gc.ODIV<<16 | gc.TUINT8,
+		gc.ODIV<<16 | gc.TUINT16,
+		gc.ODIV<<16 | gc.TUINT32,
+		gc.ODIV<<16 | gc.TPTR32:
+		a = arm.ADIVU
+
+	case gc.ODIV<<16 | gc.TINT8,
+		gc.ODIV<<16 | gc.TINT16,
+		gc.ODIV<<16 | gc.TINT32:
+		a = arm.ADIV
+
+	case gc.OMOD<<16 | gc.TUINT8,
+		gc.OMOD<<16 | gc.TUINT16,
+		gc.OMOD<<16 | gc.TUINT32,
+		gc.OMOD<<16 | gc.TPTR32:
+		a = arm.AMODU
+
+	case gc.OMOD<<16 | gc.TINT8,
+		gc.OMOD<<16 | gc.TINT16,
+		gc.OMOD<<16 | gc.TINT32:
+		a = arm.AMOD
+
+		//	case CASE(OEXTEND, TINT16):
+	//		a = ACWD;
+	//		break;
+
+	//	case CASE(OEXTEND, TINT32):
+	//		a = ACDQ;
+	//		break;
+
+	//	case CASE(OEXTEND, TINT64):
+	//		a = ACQO;
+	//		break;
+
+	case gc.ODIV<<16 | gc.TFLOAT32:
+		a = arm.ADIVF
+
+	case gc.ODIV<<16 | gc.TFLOAT64:
+		a = arm.ADIVD
+
+	case gc.OSQRT<<16 | gc.TFLOAT64:
+		a = arm.ASQRTD
+	}
+
+	return a
+}
+
+const (
+	ODynam = 1 << 0
+	OPtrto = 1 << 1
+)
+
+var clean [20]gc.Node
+
+var cleani int = 0
+
+func sudoclean() {
+	if clean[cleani-1].Op != gc.OEMPTY {
+		gc.Regfree(&clean[cleani-1])
+	}
+	if clean[cleani-2].Op != gc.OEMPTY {
+		gc.Regfree(&clean[cleani-2])
+	}
+	cleani -= 2
+}
+
+func dotaddable(n *gc.Node, n1 *gc.Node) bool {
+	if n.Op != gc.ODOT {
+		return false
+	}
+
+	var oary [10]int64
+	var nn *gc.Node
+	o := gc.Dotoffset(n, oary[:], &nn)
+	if nn != nil && nn.Addable && o == 1 && oary[0] >= 0 {
+		*n1 = *nn
+		n1.Type = n.Type
+		n1.Xoffset += oary[0]
+		return true
+	}
+
+	return false
+}
+
+/*
+ * 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 {
+	if n.Type == nil {
+		return false
+	}
+
+	*a = obj.Addr{}
+
+	switch n.Op {
+	case gc.OLITERAL:
+		if !gc.Isconst(n, gc.CTINT) {
+			break
+		}
+		v := n.Int()
+		if v >= 32000 || v <= -32000 {
+			break
+		}
+		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]
+		reg1 := &clean[cleani-2]
+		reg.Op = gc.OEMPTY
+		reg1.Op = gc.OEMPTY
+		var nn *gc.Node
+		var oary [10]int64
+		o := gc.Dotoffset(n, oary[:], &nn)
+		if nn == nil {
+			sudoclean()
+			return false
+		}
+
+		if nn.Addable && 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
+}
diff --git a/src/cmd/compile/internal/arm/peep.go b/src/cmd/compile/internal/arm/peep.go
new file mode 100644
index 0000000..66eba41
--- /dev/null
+++ b/src/cmd/compile/internal/arm/peep.go
@@ -0,0 +1,1748 @@
+// Inferno utils/5c/peep.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5c/peep.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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 arm
+
+import (
+	"cmd/compile/internal/gc"
+	"cmd/internal/obj"
+	"cmd/internal/obj/arm"
+	"fmt"
+)
+
+var gactive uint32
+
+// UNUSED
+func peep(firstp *obj.Prog) {
+	g := (*gc.Graph)(gc.Flowstart(firstp, nil))
+	if g == nil {
+		return
+	}
+	gactive = 0
+
+	var r *gc.Flow
+	var p *obj.Prog
+	var t int
+loop1:
+	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
+		gc.Dumpit("loop1", g.Start, 0)
+	}
+
+	t = 0
+	for r = g.Start; r != nil; r = r.Link {
+		p = r.Prog
+		switch p.As {
+		/*
+		 * elide shift into TYPE_SHIFT operand of subsequent instruction
+		 */
+		//			if(shiftprop(r)) {
+		//				excise(r);
+		//				t++;
+		//				break;
+		//			}
+		case arm.ASLL,
+			arm.ASRL,
+			arm.ASRA:
+			break
+
+		case arm.AMOVB,
+			arm.AMOVH,
+			arm.AMOVW,
+			arm.AMOVF,
+			arm.AMOVD:
+			if regtyp(&p.From) {
+				if p.From.Type == p.To.Type && isfloatreg(&p.From) == isfloatreg(&p.To) {
+					if p.Scond == arm.C_SCOND_NONE {
+						if copyprop(g, r) {
+							excise(r)
+							t++
+							break
+						}
+
+						if subprop(r) && copyprop(g, r) {
+							excise(r)
+							t++
+							break
+						}
+					}
+				}
+			}
+
+		case arm.AMOVHS,
+			arm.AMOVHU,
+			arm.AMOVBS,
+			arm.AMOVBU:
+			if p.From.Type == obj.TYPE_REG {
+				if shortprop(r) {
+					t++
+				}
+			}
+		}
+	}
+
+	/*
+		if(p->scond == C_SCOND_NONE)
+		if(regtyp(&p->to))
+		if(isdconst(&p->from)) {
+			constprop(&p->from, &p->to, r->s1);
+		}
+		break;
+	*/
+	if t != 0 {
+		goto loop1
+	}
+
+	for r := (*gc.Flow)(g.Start); r != nil; r = r.Link {
+		p = r.Prog
+		switch p.As {
+		/*
+		 * EOR -1,x,y => MVN x,y
+		 */
+		case arm.AEOR:
+			if isdconst(&p.From) && p.From.Offset == -1 {
+				p.As = arm.AMVN
+				p.From.Type = obj.TYPE_REG
+				if p.Reg != 0 {
+					p.From.Reg = p.Reg
+				} else {
+					p.From.Reg = p.To.Reg
+				}
+				p.Reg = 0
+			}
+		}
+	}
+
+	for r := (*gc.Flow)(g.Start); r != nil; r = r.Link {
+		p = r.Prog
+		switch p.As {
+		case arm.AMOVW,
+			arm.AMOVB,
+			arm.AMOVBS,
+			arm.AMOVBU:
+			if p.From.Type == obj.TYPE_MEM && p.From.Offset == 0 {
+				xtramodes(g, r, &p.From)
+			} else if p.To.Type == obj.TYPE_MEM && p.To.Offset == 0 {
+				xtramodes(g, r, &p.To)
+			} else {
+				continue
+			}
+		}
+	}
+
+	//		case ACMP:
+	//			/*
+	//			 * elide CMP $0,x if calculation of x can set condition codes
+	//			 */
+	//			if(isdconst(&p->from) || p->from.offset != 0)
+	//				continue;
+	//			r2 = r->s1;
+	//			if(r2 == nil)
+	//				continue;
+	//			t = r2->prog->as;
+	//			switch(t) {
+	//			default:
+	//				continue;
+	//			case ABEQ:
+	//			case ABNE:
+	//			case ABMI:
+	//			case ABPL:
+	//				break;
+	//			case ABGE:
+	//				t = ABPL;
+	//				break;
+	//			case ABLT:
+	//				t = ABMI;
+	//				break;
+	//			case ABHI:
+	//				t = ABNE;
+	//				break;
+	//			case ABLS:
+	//				t = ABEQ;
+	//				break;
+	//			}
+	//			r1 = r;
+	//			do
+	//				r1 = uniqp(r1);
+	//			while (r1 != nil && r1->prog->as == ANOP);
+	//			if(r1 == nil)
+	//				continue;
+	//			p1 = r1->prog;
+	//			if(p1->to.type != TYPE_REG)
+	//				continue;
+	//			if(p1->to.reg != p->reg)
+	//			if(!(p1->as == AMOVW && p1->from.type == TYPE_REG && p1->from.reg == p->reg))
+	//				continue;
+	//
+	//			switch(p1->as) {
+	//			default:
+	//				continue;
+	//			case AMOVW:
+	//				if(p1->from.type != TYPE_REG)
+	//					continue;
+	//			case AAND:
+	//			case AEOR:
+	//			case AORR:
+	//			case ABIC:
+	//			case AMVN:
+	//			case ASUB:
+	//			case ARSB:
+	//			case AADD:
+	//			case AADC:
+	//			case ASBC:
+	//			case ARSC:
+	//				break;
+	//			}
+	//			p1->scond |= C_SBIT;
+	//			r2->prog->as = t;
+	//			excise(r);
+	//			continue;
+
+	//	predicate(g);
+
+	gc.Flowend(g)
+}
+
+func regtyp(a *obj.Addr) bool {
+	return a.Type == obj.TYPE_REG && (arm.REG_R0 <= a.Reg && a.Reg <= arm.REG_R15 || arm.REG_F0 <= a.Reg && a.Reg <= arm.REG_F15)
+}
+
+/*
+ * the idea is to substitute
+ * one register for another
+ * from one MOV to another
+ *	MOV	a, R0
+ *	ADD	b, R0	/ no use of R1
+ *	MOV	R0, R1
+ * would be converted to
+ *	MOV	a, R1
+ *	ADD	b, R1
+ *	MOV	R1, R0
+ * hopefully, then the former or latter MOV
+ * will be eliminated by copy propagation.
+ */
+func subprop(r0 *gc.Flow) bool {
+	p := (*obj.Prog)(r0.Prog)
+	v1 := (*obj.Addr)(&p.From)
+	if !regtyp(v1) {
+		return false
+	}
+	v2 := (*obj.Addr)(&p.To)
+	if !regtyp(v2) {
+		return false
+	}
+	for r := gc.Uniqp(r0); r != nil; r = gc.Uniqp(r) {
+		if gc.Uniqs(r) == nil {
+			break
+		}
+		p = r.Prog
+		if p.As == obj.AVARDEF || p.As == obj.AVARKILL {
+			continue
+		}
+		if p.Info.Flags&gc.Call != 0 {
+			return false
+		}
+
+		// 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
+		}
+
+		switch p.As {
+		case arm.AMULLU,
+			arm.AMULA,
+			arm.AMVN:
+			return false
+		}
+
+		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 {
+						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
+					}
+				}
+			}
+		}
+
+		if copyau(&p.From, v2) || copyau1(p, v2) || copyau(&p.To, v2) {
+			break
+		}
+		if copysub(&p.From, v1, v2, 0) != 0 || copysub1(p, v1, v2, 0) != 0 || copysub(&p.To, v1, v2, 0) != 0 {
+			break
+		}
+	}
+
+	return false
+}
+
+/*
+ * The idea is to remove redundant copies.
+ *	v1->v2	F=0
+ *	(use v2	s/v2/v1/)*
+ *	set v1	F=1
+ *	use v2	return fail
+ *	-----------------
+ *	v1->v2	F=0
+ *	(use v2	s/v2/v1/)*
+ *	set v1	F=1
+ *	set v2	return success
+ */
+func copyprop(g *gc.Graph, r0 *gc.Flow) bool {
+	p := (*obj.Prog)(r0.Prog)
+	v1 := (*obj.Addr)(&p.From)
+	v2 := (*obj.Addr)(&p.To)
+	if copyas(v1, v2) {
+		return true
+	}
+	gactive++
+	return copy1(v1, v2, r0.S1, 0)
+}
+
+func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool {
+	if uint32(r.Active) == gactive {
+		if gc.Debug['P'] != 0 {
+			fmt.Printf("act set; return 1\n")
+		}
+		return true
+	}
+
+	r.Active = int32(gactive)
+	if gc.Debug['P'] != 0 {
+		fmt.Printf("copy %v->%v f=%d\n", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), f)
+	}
+	var t int
+	var p *obj.Prog
+	for ; r != nil; r = r.S1 {
+		p = r.Prog
+		if gc.Debug['P'] != 0 {
+			fmt.Printf("%v", p)
+		}
+		if f == 0 && gc.Uniqp(r) == nil {
+			f = 1
+			if gc.Debug['P'] != 0 {
+				fmt.Printf("; merge; f=%d", f)
+			}
+		}
+
+		t = copyu(p, v2, nil)
+		switch t {
+		case 2: /* rar, can't split */
+			if gc.Debug['P'] != 0 {
+				fmt.Printf("; %vrar; return 0\n", gc.Ctxt.Dconv(v2))
+			}
+			return false
+
+		case 3: /* set */
+			if gc.Debug['P'] != 0 {
+				fmt.Printf("; %vset; return 1\n", gc.Ctxt.Dconv(v2))
+			}
+			return true
+
+		case 1, /* used, substitute */
+			4: /* use and set */
+			if f != 0 {
+				if gc.Debug['P'] == 0 {
+					return false
+				}
+				if t == 4 {
+					fmt.Printf("; %vused+set and f=%d; return 0\n", gc.Ctxt.Dconv(v2), f)
+				} else {
+					fmt.Printf("; %vused and f=%d; return 0\n", gc.Ctxt.Dconv(v2), f)
+				}
+				return false
+			}
+
+			if copyu(p, v2, v1) != 0 {
+				if gc.Debug['P'] != 0 {
+					fmt.Printf("; sub fail; return 0\n")
+				}
+				return false
+			}
+
+			if gc.Debug['P'] != 0 {
+				fmt.Printf("; sub%v/%v", gc.Ctxt.Dconv(v2), gc.Ctxt.Dconv(v1))
+			}
+			if t == 4 {
+				if gc.Debug['P'] != 0 {
+					fmt.Printf("; %vused+set; return 1\n", gc.Ctxt.Dconv(v2))
+				}
+				return true
+			}
+		}
+
+		if f == 0 {
+			t = copyu(p, v1, nil)
+			if f == 0 && (t == 2 || t == 3 || t == 4) {
+				f = 1
+				if gc.Debug['P'] != 0 {
+					fmt.Printf("; %vset and !f; f=%d", gc.Ctxt.Dconv(v1), f)
+				}
+			}
+		}
+
+		if gc.Debug['P'] != 0 {
+			fmt.Printf("\n")
+		}
+		if r.S2 != nil {
+			if !copy1(v1, v2, r.S2, f) {
+				return false
+			}
+		}
+	}
+
+	return true
+}
+
+// UNUSED
+/*
+ * The idea is to remove redundant constants.
+ *	$c1->v1
+ *	($c1->v2 s/$c1/v1)*
+ *	set v1  return
+ * The v1->v2 should be eliminated by copy propagation.
+ */
+func constprop(c1 *obj.Addr, v1 *obj.Addr, r *gc.Flow) {
+	if gc.Debug['P'] != 0 {
+		fmt.Printf("constprop %v->%v\n", gc.Ctxt.Dconv(c1), gc.Ctxt.Dconv(v1))
+	}
+	var p *obj.Prog
+	for ; r != nil; r = r.S1 {
+		p = r.Prog
+		if gc.Debug['P'] != 0 {
+			fmt.Printf("%v", p)
+		}
+		if gc.Uniqp(r) == nil {
+			if gc.Debug['P'] != 0 {
+				fmt.Printf("; merge; return\n")
+			}
+			return
+		}
+
+		if p.As == arm.AMOVW && copyas(&p.From, c1) {
+			if gc.Debug['P'] != 0 {
+				fmt.Printf("; sub%v/%v", gc.Ctxt.Dconv(&p.From), gc.Ctxt.Dconv(v1))
+			}
+			p.From = *v1
+		} else if copyu(p, v1, nil) > 1 {
+			if gc.Debug['P'] != 0 {
+				fmt.Printf("; %vset; return\n", gc.Ctxt.Dconv(v1))
+			}
+			return
+		}
+
+		if gc.Debug['P'] != 0 {
+			fmt.Printf("\n")
+		}
+		if r.S2 != nil {
+			constprop(c1, v1, r.S2)
+		}
+	}
+}
+
+/*
+ * shortprop eliminates redundant zero/sign extensions.
+ *
+ *   MOVBS x, R
+ *   <no use R>
+ *   MOVBS R, R'
+ *
+ * changed to
+ *
+ *   MOVBS x, R
+ *   ...
+ *   MOVB  R, R' (compiled to mov)
+ *
+ * MOVBS above can be a MOVBS, MOVBU, MOVHS or MOVHU.
+ */
+func shortprop(r *gc.Flow) bool {
+	p := (*obj.Prog)(r.Prog)
+	r1 := (*gc.Flow)(findpre(r, &p.From))
+	if r1 == nil {
+		return false
+	}
+
+	p1 := (*obj.Prog)(r1.Prog)
+	if p1.As == p.As {
+		// Two consecutive extensions.
+		goto gotit
+	}
+
+	if p1.As == arm.AMOVW && isdconst(&p1.From) && p1.From.Offset >= 0 && p1.From.Offset < 128 {
+		// Loaded an immediate.
+		goto gotit
+	}
+
+	return false
+
+gotit:
+	if gc.Debug['P'] != 0 {
+		fmt.Printf("shortprop\n%v\n%v", p1, p)
+	}
+	switch p.As {
+	case arm.AMOVBS,
+		arm.AMOVBU:
+		p.As = arm.AMOVB
+
+	case arm.AMOVHS,
+		arm.AMOVHU:
+		p.As = arm.AMOVH
+	}
+
+	if gc.Debug['P'] != 0 {
+		fmt.Printf(" => %v\n", obj.Aconv(int(p.As)))
+	}
+	return true
+}
+
+// UNUSED
+/*
+ * ASLL x,y,w
+ * .. (not use w, not set x y w)
+ * AXXX w,a,b (a != w)
+ * .. (not use w)
+ * (set w)
+ * ----------- changed to
+ * ..
+ * AXXX (x<<y),a,b
+ * ..
+ */
+func shiftprop(r *gc.Flow) bool {
+	p := (*obj.Prog)(r.Prog)
+	if p.To.Type != obj.TYPE_REG {
+		if gc.Debug['P'] != 0 {
+			fmt.Printf("\tBOTCH: result not reg; FAILURE\n")
+		}
+		return false
+	}
+
+	n := int(int(p.To.Reg))
+	a := obj.Addr(obj.Addr{})
+	if p.Reg != 0 && p.Reg != p.To.Reg {
+		a.Type = obj.TYPE_REG
+		a.Reg = p.Reg
+	}
+
+	if gc.Debug['P'] != 0 {
+		fmt.Printf("shiftprop\n%v", p)
+	}
+	r1 := (*gc.Flow)(r)
+	var p1 *obj.Prog
+	for {
+		/* find first use of shift result; abort if shift operands or result are changed */
+		r1 = gc.Uniqs(r1)
+
+		if r1 == nil {
+			if gc.Debug['P'] != 0 {
+				fmt.Printf("\tbranch; FAILURE\n")
+			}
+			return false
+		}
+
+		if gc.Uniqp(r1) == nil {
+			if gc.Debug['P'] != 0 {
+				fmt.Printf("\tmerge; FAILURE\n")
+			}
+			return false
+		}
+
+		p1 = r1.Prog
+		if gc.Debug['P'] != 0 {
+			fmt.Printf("\n%v", p1)
+		}
+		switch copyu(p1, &p.To, nil) {
+		case 0: /* not used or set */
+			if (p.From.Type == obj.TYPE_REG && copyu(p1, &p.From, nil) > 1) || (a.Type == obj.TYPE_REG && copyu(p1, &a, nil) > 1) {
+				if gc.Debug['P'] != 0 {
+					fmt.Printf("\targs modified; FAILURE\n")
+				}
+				return false
+			}
+
+			continue
+		case 3: /* set, not used */
+			{
+				if gc.Debug['P'] != 0 {
+					fmt.Printf("\tBOTCH: noref; FAILURE\n")
+				}
+				return false
+			}
+		}
+
+		break
+	}
+
+	/* check whether substitution can be done */
+	switch p1.As {
+	default:
+		if gc.Debug['P'] != 0 {
+			fmt.Printf("\tnon-dpi; FAILURE\n")
+		}
+		return false
+
+	case arm.AAND,
+		arm.AEOR,
+		arm.AADD,
+		arm.AADC,
+		arm.AORR,
+		arm.ASUB,
+		arm.ASBC,
+		arm.ARSB,
+		arm.ARSC:
+		if int(p1.Reg) == n || (p1.Reg == 0 && p1.To.Type == obj.TYPE_REG && int(p1.To.Reg) == n) {
+			if p1.From.Type != obj.TYPE_REG {
+				if gc.Debug['P'] != 0 {
+					fmt.Printf("\tcan't swap; FAILURE\n")
+				}
+				return false
+			}
+
+			p1.Reg = p1.From.Reg
+			p1.From.Reg = int16(n)
+			switch p1.As {
+			case arm.ASUB:
+				p1.As = arm.ARSB
+
+			case arm.ARSB:
+				p1.As = arm.ASUB
+
+			case arm.ASBC:
+				p1.As = arm.ARSC
+
+			case arm.ARSC:
+				p1.As = arm.ASBC
+			}
+
+			if gc.Debug['P'] != 0 {
+				fmt.Printf("\t=>%v", p1)
+			}
+		}
+		fallthrough
+
+	case arm.ABIC,
+		arm.ATST,
+		arm.ACMP,
+		arm.ACMN:
+		if int(p1.Reg) == n {
+			if gc.Debug['P'] != 0 {
+				fmt.Printf("\tcan't swap; FAILURE\n")
+			}
+			return false
+		}
+
+		if p1.Reg == 0 && int(p1.To.Reg) == n {
+			if gc.Debug['P'] != 0 {
+				fmt.Printf("\tshift result used twice; FAILURE\n")
+			}
+			return false
+		}
+
+		//	case AMVN:
+		if p1.From.Type == obj.TYPE_SHIFT {
+			if gc.Debug['P'] != 0 {
+				fmt.Printf("\tshift result used in shift; FAILURE\n")
+			}
+			return false
+		}
+
+		if p1.From.Type != obj.TYPE_REG || int(p1.From.Reg) != n {
+			if gc.Debug['P'] != 0 {
+				fmt.Printf("\tBOTCH: where is it used?; FAILURE\n")
+			}
+			return false
+		}
+	}
+
+	/* check whether shift result is used subsequently */
+	p2 := (*obj.Prog)(p1)
+
+	if int(p1.To.Reg) != n {
+		var p1 *obj.Prog
+		for {
+			r1 = gc.Uniqs(r1)
+			if r1 == nil {
+				if gc.Debug['P'] != 0 {
+					fmt.Printf("\tinconclusive; FAILURE\n")
+				}
+				return false
+			}
+
+			p1 = r1.Prog
+			if gc.Debug['P'] != 0 {
+				fmt.Printf("\n%v", p1)
+			}
+			switch copyu(p1, &p.To, nil) {
+			case 0: /* not used or set */
+				continue
+
+			case 3: /* set, not used */
+				break
+
+			default: /* used */
+				if gc.Debug['P'] != 0 {
+					fmt.Printf("\treused; FAILURE\n")
+				}
+				return false
+			}
+
+			break
+		}
+	}
+
+	/* make the substitution */
+	p2.From.Reg = 0
+
+	o := int(int(p.Reg))
+	if o == 0 {
+		o = int(p.To.Reg)
+	}
+	o &= 15
+
+	switch p.From.Type {
+	case obj.TYPE_CONST:
+		o |= int((p.From.Offset & 0x1f) << 7)
+
+	case obj.TYPE_REG:
+		o |= 1<<4 | (int(p.From.Reg)&15)<<8
+	}
+
+	switch p.As {
+	case arm.ASLL:
+		o |= 0 << 5
+
+	case arm.ASRL:
+		o |= 1 << 5
+
+	case arm.ASRA:
+		o |= 2 << 5
+	}
+
+	p2.From = obj.Addr{}
+	p2.From.Type = obj.TYPE_SHIFT
+	p2.From.Offset = int64(o)
+	if gc.Debug['P'] != 0 {
+		fmt.Printf("\t=>%v\tSUCCEED\n", p2)
+	}
+	return true
+}
+
+/*
+ * findpre returns the last instruction mentioning v
+ * before r. It must be a set, and there must be
+ * a unique path from that instruction to r.
+ */
+func findpre(r *gc.Flow, v *obj.Addr) *gc.Flow {
+	var r1 *gc.Flow
+
+	for r1 = gc.Uniqp(r); r1 != nil; r, r1 = r1, gc.Uniqp(r1) {
+		if gc.Uniqs(r1) != r {
+			return nil
+		}
+		switch copyu(r1.Prog, v, nil) {
+		case 1, /* used */
+			2: /* read-alter-rewrite */
+			return nil
+
+		case 3, /* set */
+			4: /* set and used */
+			return r1
+		}
+	}
+
+	return nil
+}
+
+/*
+ * findinc finds ADD instructions with a constant
+ * argument which falls within the immed_12 range.
+ */
+func findinc(r *gc.Flow, r2 *gc.Flow, v *obj.Addr) *gc.Flow {
+	var r1 *gc.Flow
+	var p *obj.Prog
+
+	for r1 = gc.Uniqs(r); r1 != nil && r1 != r2; r, r1 = r1, gc.Uniqs(r1) {
+		if gc.Uniqp(r1) != r {
+			return nil
+		}
+		switch copyu(r1.Prog, v, nil) {
+		case 0: /* not touched */
+			continue
+
+		case 4: /* set and used */
+			p = r1.Prog
+
+			if p.As == arm.AADD {
+				if isdconst(&p.From) {
+					if p.From.Offset > -4096 && p.From.Offset < 4096 {
+						return r1
+					}
+				}
+			}
+			fallthrough
+
+		default:
+			return nil
+		}
+	}
+
+	return nil
+}
+
+func nochange(r *gc.Flow, r2 *gc.Flow, p *obj.Prog) bool {
+	if r == r2 {
+		return true
+	}
+	n := int(0)
+	var a [3]obj.Addr
+	if p.Reg != 0 && p.Reg != p.To.Reg {
+		a[n].Type = obj.TYPE_REG
+		a[n].Reg = p.Reg
+		n++
+	}
+
+	switch p.From.Type {
+	case obj.TYPE_SHIFT:
+		a[n].Type = obj.TYPE_REG
+		a[n].Reg = int16(arm.REG_R0 + (p.From.Offset & 0xf))
+		n++
+		fallthrough
+
+	case obj.TYPE_REG:
+		a[n].Type = obj.TYPE_REG
+		a[n].Reg = p.From.Reg
+		n++
+	}
+
+	if n == 0 {
+		return true
+	}
+	var i int
+	for ; r != nil && r != r2; r = gc.Uniqs(r) {
+		p = r.Prog
+		for i = 0; i < n; i++ {
+			if copyu(p, &a[i], nil) > 1 {
+				return false
+			}
+		}
+	}
+
+	return true
+}
+
+func findu1(r *gc.Flow, v *obj.Addr) bool {
+	for ; r != nil; r = r.S1 {
+		if r.Active != 0 {
+			return false
+		}
+		r.Active = 1
+		switch copyu(r.Prog, v, nil) {
+		case 1, /* used */
+			2, /* read-alter-rewrite */
+			4: /* set and used */
+			return true
+
+		case 3: /* set */
+			return false
+		}
+
+		if r.S2 != nil {
+			if findu1(r.S2, v) {
+				return true
+			}
+		}
+	}
+
+	return false
+}
+
+func finduse(g *gc.Graph, r *gc.Flow, v *obj.Addr) bool {
+	for r1 := (*gc.Flow)(g.Start); r1 != nil; r1 = r1.Link {
+		r1.Active = 0
+	}
+	return findu1(r, v)
+}
+
+/*
+ * xtramodes enables the ARM post increment and
+ * shift offset addressing modes to transform
+ *   MOVW   0(R3),R1
+ *   ADD    $4,R3,R3
+ * into
+ *   MOVW.P 4(R3),R1
+ * and
+ *   ADD    R0,R1
+ *   MOVBU  0(R1),R0
+ * into
+ *   MOVBU  R0<<0(R1),R0
+ */
+func xtramodes(g *gc.Graph, r *gc.Flow, a *obj.Addr) bool {
+	p := (*obj.Prog)(r.Prog)
+	v := obj.Addr(*a)
+	v.Type = obj.TYPE_REG
+	r1 := (*gc.Flow)(findpre(r, &v))
+	if r1 != nil {
+		p1 := r1.Prog
+		if p1.To.Type == obj.TYPE_REG && p1.To.Reg == v.Reg {
+			switch p1.As {
+			case arm.AADD:
+				if p1.Scond&arm.C_SBIT != 0 {
+					// avoid altering ADD.S/ADC sequences.
+					break
+				}
+
+				if p1.From.Type == obj.TYPE_REG || (p1.From.Type == obj.TYPE_SHIFT && p1.From.Offset&(1<<4) == 0 && ((p.As != arm.AMOVB && p.As != arm.AMOVBS) || (a == &p.From && p1.From.Offset&^0xf == 0))) || ((p1.From.Type == obj.TYPE_ADDR || p1.From.Type == obj.TYPE_CONST) && p1.From.Offset > -4096 && p1.From.Offset < 4096) {
+					if nochange(gc.Uniqs(r1), r, p1) {
+						if a != &p.From || v.Reg != p.To.Reg {
+							if finduse(g, r.S1, &v) {
+								if p1.Reg == 0 || p1.Reg == v.Reg {
+									/* pre-indexing */
+									p.Scond |= arm.C_WBIT
+								} else {
+									return false
+								}
+							}
+						}
+
+						switch p1.From.Type {
+						/* register offset */
+						case obj.TYPE_REG:
+							if gc.Nacl {
+								return false
+							}
+							*a = obj.Addr{}
+							a.Type = obj.TYPE_SHIFT
+							a.Offset = int64(p1.From.Reg) & 15
+
+							/* scaled register offset */
+						case obj.TYPE_SHIFT:
+							if gc.Nacl {
+								return false
+							}
+							*a = obj.Addr{}
+							a.Type = obj.TYPE_SHIFT
+							fallthrough
+
+							/* immediate offset */
+						case obj.TYPE_CONST,
+							obj.TYPE_ADDR:
+							a.Offset = p1.From.Offset
+						}
+
+						if p1.Reg != 0 {
+							a.Reg = p1.Reg
+						}
+						excise(r1)
+						return true
+					}
+				}
+
+			case arm.AMOVW:
+				if p1.From.Type == obj.TYPE_REG {
+					r2 := (*gc.Flow)(findinc(r1, r, &p1.From))
+					if r2 != nil {
+						var r3 *gc.Flow
+						for r3 = gc.Uniqs(r2); r3.Prog.As == obj.ANOP; r3 = gc.Uniqs(r3) {
+						}
+						if r3 == r {
+							/* post-indexing */
+							p1 := r2.Prog
+
+							a.Reg = p1.To.Reg
+							a.Offset = p1.From.Offset
+							p.Scond |= arm.C_PBIT
+							if !finduse(g, r, &r1.Prog.To) {
+								excise(r1)
+							}
+							excise(r2)
+							return true
+						}
+					}
+				}
+			}
+		}
+	}
+
+	if a != &p.From || a.Reg != p.To.Reg {
+		r1 := (*gc.Flow)(findinc(r, nil, &v))
+		if r1 != nil {
+			/* post-indexing */
+			p1 := r1.Prog
+
+			a.Offset = p1.From.Offset
+			p.Scond |= arm.C_PBIT
+			excise(r1)
+			return true
+		}
+	}
+
+	return false
+}
+
+/*
+ * return
+ * 1 if v only used (and substitute),
+ * 2 if read-alter-rewrite
+ * 3 if set
+ * 4 if set and used
+ * 0 otherwise (not touched)
+ */
+func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
+	switch p.As {
+	default:
+		fmt.Printf("copyu: can't find %v\n", obj.Aconv(int(p.As)))
+		return 2
+
+	case arm.AMOVM:
+		if v.Type != obj.TYPE_REG {
+			return 0
+		}
+		if p.From.Type == obj.TYPE_CONST { /* read reglist, read/rar */
+			if s != nil {
+				if p.From.Offset&(1<<uint(v.Reg)) != 0 {
+					return 1
+				}
+				if copysub(&p.To, v, s, 1) != 0 {
+					return 1
+				}
+				return 0
+			}
+
+			if copyau(&p.To, v) {
+				if p.Scond&arm.C_WBIT != 0 {
+					return 2
+				}
+				return 1
+			}
+
+			if p.From.Offset&(1<<uint(v.Reg)) != 0 {
+				return 1 /* read/rar, write reglist */
+			}
+		} else {
+			if s != nil {
+				if p.To.Offset&(1<<uint(v.Reg)) != 0 {
+					return 1
+				}
+				if copysub(&p.From, v, s, 1) != 0 {
+					return 1
+				}
+				return 0
+			}
+
+			if copyau(&p.From, v) {
+				if p.Scond&arm.C_WBIT != 0 {
+					return 2
+				}
+				if p.To.Offset&(1<<uint(v.Reg)) != 0 {
+					return 4
+				}
+				return 1
+			}
+
+			if p.To.Offset&(1<<uint(v.Reg)) != 0 {
+				return 3
+			}
+		}
+
+		return 0
+
+	case obj.ANOP, /* read,, write */
+		arm.ASQRTD,
+		arm.AMOVW,
+		arm.AMOVF,
+		arm.AMOVD,
+		arm.AMOVH,
+		arm.AMOVHS,
+		arm.AMOVHU,
+		arm.AMOVB,
+		arm.AMOVBS,
+		arm.AMOVBU,
+		arm.AMOVFW,
+		arm.AMOVWF,
+		arm.AMOVDW,
+		arm.AMOVWD,
+		arm.AMOVFD,
+		arm.AMOVDF:
+		if p.Scond&(arm.C_WBIT|arm.C_PBIT) != 0 {
+			if v.Type == obj.TYPE_REG {
+				if p.From.Type == obj.TYPE_MEM || p.From.Type == obj.TYPE_SHIFT {
+					if p.From.Reg == v.Reg {
+						return 2
+					}
+				} else {
+					if p.To.Reg == v.Reg {
+						return 2
+					}
+				}
+			}
+		}
+
+		if s != nil {
+			if copysub(&p.From, v, s, 1) != 0 {
+				return 1
+			}
+			if !copyas(&p.To, v) {
+				if copysub(&p.To, v, s, 1) != 0 {
+					return 1
+				}
+			}
+			return 0
+		}
+
+		if copyas(&p.To, v) {
+			if p.Scond != arm.C_SCOND_NONE {
+				return 2
+			}
+			if copyau(&p.From, v) {
+				return 4
+			}
+			return 3
+		}
+
+		if copyau(&p.From, v) {
+			return 1
+		}
+		if copyau(&p.To, v) {
+			return 1
+		}
+		return 0
+
+	case arm.AMULLU, /* read, read, write, write */
+		arm.AMULL,
+		arm.AMULA,
+		arm.AMVN:
+		return 2
+
+	case arm.AADD, /* read, read, write */
+		arm.AADC,
+		arm.ASUB,
+		arm.ASBC,
+		arm.ARSB,
+		arm.ASLL,
+		arm.ASRL,
+		arm.ASRA,
+		arm.AORR,
+		arm.AAND,
+		arm.AEOR,
+		arm.AMUL,
+		arm.AMULU,
+		arm.ADIV,
+		arm.ADIVU,
+		arm.AMOD,
+		arm.AMODU,
+		arm.AADDF,
+		arm.AADDD,
+		arm.ASUBF,
+		arm.ASUBD,
+		arm.AMULF,
+		arm.AMULD,
+		arm.ADIVF,
+		arm.ADIVD,
+		obj.ACHECKNIL,
+		/* read */
+		arm.ACMPF, /* read, read, */
+		arm.ACMPD,
+		arm.ACMP,
+		arm.ACMN,
+		arm.ACASE,
+		arm.ATST:
+		/* read,, */
+		if s != nil {
+			if copysub(&p.From, v, s, 1) != 0 {
+				return 1
+			}
+			if copysub1(p, v, s, 1) != 0 {
+				return 1
+			}
+			if !copyas(&p.To, v) {
+				if copysub(&p.To, v, s, 1) != 0 {
+					return 1
+				}
+			}
+			return 0
+		}
+
+		if copyas(&p.To, v) {
+			if p.Scond != arm.C_SCOND_NONE {
+				return 2
+			}
+			if p.Reg == 0 {
+				p.Reg = p.To.Reg
+			}
+			if copyau(&p.From, v) {
+				return 4
+			}
+			if copyau1(p, v) {
+				return 4
+			}
+			return 3
+		}
+
+		if copyau(&p.From, v) {
+			return 1
+		}
+		if copyau1(p, v) {
+			return 1
+		}
+		if copyau(&p.To, v) {
+			return 1
+		}
+		return 0
+
+	case arm.ABEQ, /* read, read */
+		arm.ABNE,
+		arm.ABCS,
+		arm.ABHS,
+		arm.ABCC,
+		arm.ABLO,
+		arm.ABMI,
+		arm.ABPL,
+		arm.ABVS,
+		arm.ABVC,
+		arm.ABHI,
+		arm.ABLS,
+		arm.ABGE,
+		arm.ABLT,
+		arm.ABGT,
+		arm.ABLE:
+		if s != nil {
+			if copysub(&p.From, v, s, 1) != 0 {
+				return 1
+			}
+			return copysub1(p, v, s, 1)
+		}
+
+		if copyau(&p.From, v) {
+			return 1
+		}
+		if copyau1(p, v) {
+			return 1
+		}
+		return 0
+
+	case arm.AB: /* funny */
+		if s != nil {
+			if copysub(&p.To, v, s, 1) != 0 {
+				return 1
+			}
+			return 0
+		}
+
+		if copyau(&p.To, v) {
+			return 1
+		}
+		return 0
+
+	case obj.ARET: /* funny */
+		if s != nil {
+			return 1
+		}
+		return 3
+
+	case arm.ABL: /* funny */
+		if v.Type == obj.TYPE_REG {
+			// TODO(rsc): REG_R0 and REG_F0 used to be
+			// (when register numbers started at 0) exregoffset and exfregoffset,
+			// which are unset entirely.
+			// It's strange that this handles R0 and F0 differently from the other
+			// registers. Possible failure to optimize?
+			if arm.REG_R0 < v.Reg && v.Reg <= arm.REGEXT {
+				return 2
+			}
+			if v.Reg == arm.REGARG {
+				return 2
+			}
+			if arm.REG_F0 < v.Reg && v.Reg <= arm.FREGEXT {
+				return 2
+			}
+		}
+
+		if p.From.Type == obj.TYPE_REG && v.Type == obj.TYPE_REG && p.From.Reg == v.Reg {
+			return 2
+		}
+
+		if s != nil {
+			if copysub(&p.To, v, s, 1) != 0 {
+				return 1
+			}
+			return 0
+		}
+
+		if copyau(&p.To, v) {
+			return 4
+		}
+		return 3
+
+		// R0 is zero, used by DUFFZERO, cannot be substituted.
+	// R1 is ptr to memory, used and set, cannot be substituted.
+	case obj.ADUFFZERO:
+		if v.Type == obj.TYPE_REG {
+			if v.Reg == arm.REG_R0 {
+				return 1
+			}
+			if v.Reg == arm.REG_R0+1 {
+				return 2
+			}
+		}
+
+		return 0
+
+		// R0 is scratch, set by DUFFCOPY, cannot be substituted.
+	// R1, R2 areptr to src, dst, used and set, cannot be substituted.
+	case obj.ADUFFCOPY:
+		if v.Type == obj.TYPE_REG {
+			if v.Reg == arm.REG_R0 {
+				return 3
+			}
+			if v.Reg == arm.REG_R0+1 || v.Reg == arm.REG_R0+2 {
+				return 2
+			}
+		}
+
+		return 0
+
+	case obj.ATEXT: /* funny */
+		if v.Type == obj.TYPE_REG {
+			if v.Reg == arm.REGARG {
+				return 3
+			}
+		}
+		return 0
+
+	case obj.APCDATA,
+		obj.AFUNCDATA,
+		obj.AVARDEF,
+		obj.AVARKILL:
+		return 0
+	}
+}
+
+/*
+ * direct reference,
+ * could be set/use depending on
+ * semantics
+ */
+func copyas(a *obj.Addr, v *obj.Addr) bool {
+	if regtyp(v) {
+		if a.Type == v.Type {
+			if a.Reg == v.Reg {
+				return true
+			}
+		}
+	} else if v.Type == obj.TYPE_CONST { /* for constprop */
+		if a.Type == v.Type {
+			if a.Name == v.Name {
+				if a.Sym == v.Sym {
+					if a.Reg == v.Reg {
+						if a.Offset == v.Offset {
+							return true
+						}
+					}
+				}
+			}
+		}
+	}
+
+	return false
+}
+
+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
+	}
+
+	// TODO(rsc): Change v->type to v->name and enable.
+	//if(v->type == NAME_AUTO || v->type == NAME_PARAM) {
+	//	if(v->offset == a->offset)
+	//		return 1;
+	//}
+	return false
+}
+
+/*
+ * either direct or indirect
+ */
+func copyau(a *obj.Addr, v *obj.Addr) bool {
+	if copyas(a, v) {
+		return true
+	}
+	if v.Type == obj.TYPE_REG {
+		if a.Type == obj.TYPE_ADDR && a.Reg != 0 {
+			if a.Reg == v.Reg {
+				return true
+			}
+		} else if a.Type == obj.TYPE_MEM {
+			if a.Reg == v.Reg {
+				return true
+			}
+		} else if a.Type == obj.TYPE_REGREG || a.Type == obj.TYPE_REGREG2 {
+			if a.Reg == v.Reg {
+				return true
+			}
+			if a.Offset == int64(v.Reg) {
+				return true
+			}
+		} else if a.Type == obj.TYPE_SHIFT {
+			if a.Offset&0xf == int64(v.Reg-arm.REG_R0) {
+				return true
+			}
+			if (a.Offset&(1<<4) != 0) && (a.Offset>>8)&0xf == int64(v.Reg-arm.REG_R0) {
+				return true
+			}
+		}
+	}
+
+	return false
+}
+
+/*
+ * compare v to the center
+ * register in p (p->reg)
+ */
+func copyau1(p *obj.Prog, v *obj.Addr) bool {
+	if v.Type == obj.TYPE_REG && v.Reg == 0 {
+		return false
+	}
+	return p.Reg == v.Reg
+}
+
+/*
+ * substitute s for v in a
+ * return failure to substitute
+ */
+func copysub(a *obj.Addr, v *obj.Addr, s *obj.Addr, f int) int {
+	if f != 0 {
+		if copyau(a, v) {
+			if a.Type == obj.TYPE_SHIFT {
+				if a.Offset&0xf == int64(v.Reg-arm.REG_R0) {
+					a.Offset = a.Offset&^0xf | int64(s.Reg)&0xf
+				}
+				if (a.Offset&(1<<4) != 0) && (a.Offset>>8)&0xf == int64(v.Reg-arm.REG_R0) {
+					a.Offset = a.Offset&^(0xf<<8) | (int64(s.Reg)&0xf)<<8
+				}
+			} else if a.Type == obj.TYPE_REGREG || a.Type == obj.TYPE_REGREG2 {
+				if a.Offset == int64(v.Reg) {
+					a.Offset = int64(s.Reg)
+				}
+				if a.Reg == v.Reg {
+					a.Reg = s.Reg
+				}
+			} else {
+				a.Reg = s.Reg
+			}
+		}
+	}
+
+	return 0
+}
+
+func copysub1(p1 *obj.Prog, v *obj.Addr, s *obj.Addr, f int) int {
+	if f != 0 {
+		if copyau1(p1, v) {
+			p1.Reg = s.Reg
+		}
+	}
+	return 0
+}
+
+var predinfo = []struct {
+	opcode    int
+	notopcode int
+	scond     int
+	notscond  int
+}{
+	{arm.ABEQ, arm.ABNE, 0x0, 0x1},
+	{arm.ABNE, arm.ABEQ, 0x1, 0x0},
+	{arm.ABCS, arm.ABCC, 0x2, 0x3},
+	{arm.ABHS, arm.ABLO, 0x2, 0x3},
+	{arm.ABCC, arm.ABCS, 0x3, 0x2},
+	{arm.ABLO, arm.ABHS, 0x3, 0x2},
+	{arm.ABMI, arm.ABPL, 0x4, 0x5},
+	{arm.ABPL, arm.ABMI, 0x5, 0x4},
+	{arm.ABVS, arm.ABVC, 0x6, 0x7},
+	{arm.ABVC, arm.ABVS, 0x7, 0x6},
+	{arm.ABHI, arm.ABLS, 0x8, 0x9},
+	{arm.ABLS, arm.ABHI, 0x9, 0x8},
+	{arm.ABGE, arm.ABLT, 0xA, 0xB},
+	{arm.ABLT, arm.ABGE, 0xB, 0xA},
+	{arm.ABGT, arm.ABLE, 0xC, 0xD},
+	{arm.ABLE, arm.ABGT, 0xD, 0xC},
+}
+
+type Joininfo struct {
+	start *gc.Flow
+	last  *gc.Flow
+	end   *gc.Flow
+	len   int
+}
+
+const (
+	Join = iota
+	Split
+	End
+	Branch
+	Setcond
+	Toolong
+)
+
+const (
+	Falsecond = iota
+	Truecond
+	Delbranch
+	Keepbranch
+)
+
+func isbranch(p *obj.Prog) bool {
+	return (arm.ABEQ <= p.As) && (p.As <= arm.ABLE)
+}
+
+func predicable(p *obj.Prog) bool {
+	switch p.As {
+	case obj.ANOP,
+		obj.AXXX,
+		obj.ADATA,
+		obj.AGLOBL,
+		obj.ATEXT,
+		arm.AWORD,
+		arm.ABCASE,
+		arm.ACASE:
+		return false
+	}
+
+	if isbranch(p) {
+		return false
+	}
+	return true
+}
+
+/*
+ * Depends on an analysis of the encodings performed by 5l.
+ * These seem to be all of the opcodes that lead to the "S" bit
+ * being set in the instruction encodings.
+ *
+ * C_SBIT may also have been set explicitly in p->scond.
+ */
+func modifiescpsr(p *obj.Prog) bool {
+	switch p.As {
+	case arm.AMULLU,
+		arm.AMULA,
+		arm.AMULU,
+		arm.ADIVU,
+		arm.ATEQ,
+		arm.ACMN,
+		arm.ATST,
+		arm.ACMP,
+		arm.AMUL,
+		arm.ADIV,
+		arm.AMOD,
+		arm.AMODU,
+		arm.ABL:
+		return true
+	}
+
+	if p.Scond&arm.C_SBIT != 0 {
+		return true
+	}
+	return false
+}
+
+/*
+ * Find the maximal chain of instructions starting with r which could
+ * be executed conditionally
+ */
+func joinsplit(r *gc.Flow, j *Joininfo) int {
+	j.start = r
+	j.last = r
+	j.len = 0
+	for {
+		if r.P2 != nil && (r.P1 != nil || r.P2.P2link != nil) {
+			j.end = r
+			return Join
+		}
+
+		if r.S1 != nil && r.S2 != nil {
+			j.end = r
+			return Split
+		}
+
+		j.last = r
+		if r.Prog.As != obj.ANOP {
+			j.len++
+		}
+		if r.S1 == nil && r.S2 == nil {
+			j.end = r.Link
+			return End
+		}
+
+		if r.S2 != nil {
+			j.end = r.S2
+			return Branch
+		}
+
+		if modifiescpsr(r.Prog) {
+			j.end = r.S1
+			return Setcond
+		}
+
+		r = r.S1
+		if j.len >= 4 {
+			break
+		}
+	}
+
+	j.end = r
+	return Toolong
+}
+
+func successor(r *gc.Flow) *gc.Flow {
+	if r.S1 != nil {
+		return r.S1
+	} else {
+		return r.S2
+	}
+}
+
+func applypred(rstart *gc.Flow, j *Joininfo, cond int, branch int) {
+	if j.len == 0 {
+		return
+	}
+	var pred int
+	if cond == Truecond {
+		pred = predinfo[rstart.Prog.As-arm.ABEQ].scond
+	} else {
+		pred = predinfo[rstart.Prog.As-arm.ABEQ].notscond
+	}
+
+	for r := (*gc.Flow)(j.start); ; r = successor(r) {
+		if r.Prog.As == arm.AB {
+			if r != j.last || branch == Delbranch {
+				excise(r)
+			} else {
+				if cond == Truecond {
+					r.Prog.As = int16(predinfo[rstart.Prog.As-arm.ABEQ].opcode)
+				} else {
+					r.Prog.As = int16(predinfo[rstart.Prog.As-arm.ABEQ].notopcode)
+				}
+			}
+		} else if predicable(r.Prog) {
+			r.Prog.Scond = uint8(int(r.Prog.Scond&^arm.C_SCOND) | pred)
+		}
+		if r.S1 != r.Link {
+			r.S1 = r.Link
+			r.Link.P1 = r
+		}
+
+		if r == j.last {
+			break
+		}
+	}
+}
+
+func predicate(g *gc.Graph) {
+	var t1 int
+	var t2 int
+	var j1 Joininfo
+	var j2 Joininfo
+
+	for r := (*gc.Flow)(g.Start); r != nil; r = r.Link {
+		if isbranch(r.Prog) {
+			t1 = joinsplit(r.S1, &j1)
+			t2 = joinsplit(r.S2, &j2)
+			if j1.last.Link != j2.start {
+				continue
+			}
+			if j1.end == j2.end {
+				if (t1 == Branch && (t2 == Join || t2 == Setcond)) || (t2 == Join && (t1 == Join || t1 == Setcond)) {
+					applypred(r, &j1, Falsecond, Delbranch)
+					applypred(r, &j2, Truecond, Delbranch)
+					excise(r)
+					continue
+				}
+			}
+
+			if t1 == End || t1 == Branch {
+				applypred(r, &j1, Falsecond, Keepbranch)
+				excise(r)
+				continue
+			}
+		}
+	}
+}
+
+func isdconst(a *obj.Addr) bool {
+	return a.Type == obj.TYPE_CONST
+}
+
+func isfloatreg(a *obj.Addr) bool {
+	return arm.REG_F0 <= a.Reg && a.Reg <= arm.REG_F15
+}
+
+func stackaddr(a *obj.Addr) bool {
+	return regtyp(a) && a.Reg == arm.REGSP
+}
+
+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 excise(r *gc.Flow) {
+	p := (*obj.Prog)(r.Prog)
+	obj.Nopout(p)
+}
diff --git a/src/cmd/compile/internal/arm/prog.go b/src/cmd/compile/internal/arm/prog.go
new file mode 100644
index 0000000..cdf9d29
--- /dev/null
+++ b/src/cmd/compile/internal/arm/prog.go
@@ -0,0 +1,165 @@
+// 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 arm
+
+import (
+	"cmd/compile/internal/gc"
+	"cmd/internal/obj"
+	"cmd/internal/obj/arm"
+)
+
+const (
+	RightRdwr = 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 = [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.LeftRead | gc.RightWrite, 0, 0, 0},
+
+	// Integer.
+	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.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},
+	arm.ASQRTD: {gc.SizeD | gc.LeftRead | RightRdwr, 0, 0, 0},
+
+	// Conversions.
+	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.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.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.Call, 0, 0, 0},
+
+	// These should be split into the two different conversions instead
+	// of overloading the one.
+	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.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(p *obj.Prog) {
+	info := &p.Info
+	*info = progtable[p.As]
+	if info.Flags == 0 {
+		gc.Fatal("unknown instruction %v", p)
+	}
+
+	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 (info.Flags&gc.RegRead != 0) && p.Reg == 0 {
+		info.Flags &^= gc.RegRead
+		info.Flags |= gc.CanRegRead | gc.RightRead
+	}
+
+	if (p.Scond&arm.C_SCOND != arm.C_SCOND_NONE) && (info.Flags&gc.RightWrite != 0) {
+		info.Flags |= gc.RightRead
+	}
+
+	switch p.As {
+	case arm.ADIV,
+		arm.ADIVU,
+		arm.AMOD,
+		arm.AMODU:
+		info.Regset |= RtoB(arm.REG_R12)
+	}
+}
diff --git a/src/cmd/compile/internal/arm/reg.go b/src/cmd/compile/internal/arm/reg.go
new file mode 100644
index 0000000..b72ccc9
--- /dev/null
+++ b/src/cmd/compile/internal/arm/reg.go
@@ -0,0 +1,136 @@
+// Inferno utils/5c/reg.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5c/reg.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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 arm
+
+import "cmd/internal/obj/arm"
+import "cmd/compile/internal/gc"
+
+const (
+	NREGVAR = 32
+)
+
+var regname = []string{
+	".R0",
+	".R1",
+	".R2",
+	".R3",
+	".R4",
+	".R5",
+	".R6",
+	".R7",
+	".R8",
+	".R9",
+	".R10",
+	".R11",
+	".R12",
+	".R13",
+	".R14",
+	".R15",
+	".F0",
+	".F1",
+	".F2",
+	".F3",
+	".F4",
+	".F5",
+	".F6",
+	".F7",
+	".F8",
+	".F9",
+	".F10",
+	".F11",
+	".F12",
+	".F13",
+	".F14",
+	".F15",
+}
+
+func regnames(n *int) []string {
+	*n = NREGVAR
+	return regname
+}
+
+func excludedregs() uint64 {
+	return RtoB(arm.REGSP) | RtoB(arm.REGLINK) | RtoB(arm.REGPC)
+}
+
+func doregbits(r int) uint64 {
+	return 0
+}
+
+/*
+ *	bit	reg
+ *	0	R0
+ *	1	R1
+ *	...	...
+ *	10	R10
+ *	12  R12
+ *
+ *	bit	reg
+ *	18	F2
+ *	19	F3
+ *	...	...
+ *	31	F15
+ */
+func RtoB(r int) uint64 {
+	if arm.REG_R0 <= r && r <= arm.REG_R15 {
+		if r >= arm.REGTMP-2 && r != arm.REG_R12 { // excluded R9 and R10 for m and g, but not R12
+			return 0
+		}
+		return 1 << uint(r-arm.REG_R0)
+	}
+
+	if arm.REG_F0 <= r && r <= arm.REG_F15 {
+		if r < arm.REG_F2 || r > arm.REG_F0+arm.NFREG-1 {
+			return 0
+		}
+		return 1 << uint((r-arm.REG_F0)+16)
+	}
+
+	return 0
+}
+
+func BtoR(b uint64) int {
+	// TODO Allow R0 and R1, but be careful with a 0 return
+	// TODO Allow R9. Only R10 is reserved now (just g, not m).
+	b &= 0x11fc // excluded R9 and R10 for m and g, but not R12
+	if b == 0 {
+		return 0
+	}
+	return gc.Bitno(b) + arm.REG_R0
+}
+
+func BtoF(b uint64) int {
+	b &= 0xfffc0000
+	if b == 0 {
+		return 0
+	}
+	return gc.Bitno(b) - 16 + arm.REG_F0
+}
diff --git a/src/cmd/compile/internal/arm64/cgen.go b/src/cmd/compile/internal/arm64/cgen.go
new file mode 100644
index 0000000..30326d7
--- /dev/null
+++ b/src/cmd/compile/internal/arm64/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 arm64
+
+import (
+	"cmd/compile/internal/gc"
+	"cmd/internal/obj"
+	"cmd/internal/obj/arm64"
+)
+
+func blockcopy(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, n.Type)
+
+	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, n.Type)
+	}
+	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/compile/internal/arm64/galign.go b/src/cmd/compile/internal/arm64/galign.go
new file mode 100644
index 0000000..38def8f
--- /dev/null
+++ b/src/cmd/compile/internal/arm64/galign.go
@@ -0,0 +1,93 @@
+// 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 arm64
+
+import (
+	"cmd/compile/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, 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.REGZERO = arm64.REGZERO
+	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.Getg = getg
+	gc.Thearch.Gins = gins
+	gc.Thearch.Ginscmp = ginscmp
+	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.Blockcopy = blockcopy
+	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/compile/internal/arm64/ggen.go b/src/cmd/compile/internal/arm64/ggen.go
new file mode 100644
index 0000000..cba4d99
--- /dev/null
+++ b/src/cmd/compile/internal/arm64/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 arm64
+
+import (
+	"cmd/compile/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)))
+
+	// arm64 requires that the frame size (not counting saved LR)
+	// be empty or be 8 mod 16. If not, pad it.
+	if frame != 0 && frame%16 != 8 {
+		frame += 8
+	}
+
+	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.Name.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)
+}
+
+var darwin = obj.Getgoos() == "darwin"
+
+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) && !darwin { // darwin ld64 cannot handle BR26 reloc with non-zero addend
+		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)
+}
+
+var panicdiv *gc.Node
+
+/*
+ * 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) && nl.Int() != -(1<<uint64(t.Width*8-1)) {
+			check = 0
+		} else if gc.Isconst(nr, gc.CTINT) && nr.Int() != -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.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", t)
+	}
+
+	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(nr.Int())
+		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", nl, nl.Type, 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
+
+	var r0 gc.Node
+	gc.Nodreg(&r0, gc.Types[gc.TUINT64], arm64.REGZERO)
+	var dst gc.Node
+
+	// REGRT1 is reserved on arm64, see arm64/gsubr.go.
+	gc.Nodreg(&dst, gc.Types[gc.Tptr], arm64.REGRT1)
+	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 && !darwin { // darwin ld64 cannot handle BR26 reloc with non-zero addend
+		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)
+	}
+}
+
+// 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
+
+	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
+		//	CBNZ arg, 2(PC)
+		//	MOVD ZR, 0(arg)
+		p1 = gc.Ctxt.NewProg()
+		gc.Clearp(p1)
+		p1.Link = p.Link
+		p.Link = p1
+		p1.Lineno = p.Lineno
+		p1.Pc = 9999
+
+		p.As = arm64.ACBNZ
+		p.To.Type = obj.TYPE_BRANCH
+		p.To.Val = p1.Link
+
+		// crash by write to memory address 0.
+		p1.As = arm64.AMOVD
+		p1.From.Type = obj.TYPE_REG
+		p1.From.Reg = arm64.REGZERO
+		p1.To.Type = obj.TYPE_MEM
+		p1.To.Reg = p.From.Reg
+		p1.To.Offset = 0
+	}
+}
+
+// res = runtime.getg()
+func getg(res *gc.Node) {
+	var n1 gc.Node
+	gc.Nodreg(&n1, res.Type, arm64.REGG)
+	gmove(&n1, res)
+}
diff --git a/src/cmd/compile/internal/arm64/gsubr.go b/src/cmd/compile/internal/arm64/gsubr.go
new file mode 100644
index 0000000..0a14654
--- /dev/null
+++ b/src/cmd/compile/internal/arm64/gsubr.go
@@ -0,0 +1,983 @@
+// 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 at 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 at 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/compile/internal/gc"
+	"cmd/internal/obj"
+	"cmd/internal/obj/arm64"
+	"fmt"
+)
+
+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)
+}
+
+func ginscmp(op int, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
+	if gc.Isint[t.Etype] && n1.Op == gc.OLITERAL && n2.Op != gc.OLITERAL {
+		// Reverse comparison to place constant last.
+		op = gc.Brrev(op)
+		n1, n2 = n2, n1
+	}
+
+	var r1, r2, g1, g2 gc.Node
+	gc.Regalloc(&r1, t, n1)
+	gc.Regalloc(&g1, n1.Type, &r1)
+	gc.Cgen(n1, &g1)
+	gmove(&g1, &r1)
+	if gc.Isint[t.Etype] && gc.Isconst(n2, gc.CTINT) {
+		ginscon2(optoas(gc.OCMP, t), &r1, n2.Int())
+	} else {
+		gc.Regalloc(&r2, t, n2)
+		gc.Regalloc(&g2, n1.Type, &r2)
+		gc.Cgen(n2, &g2)
+		gmove(&g2, &r2)
+		gcmp(optoas(gc.OCMP, t), &r1, &r2)
+		gc.Regfree(&g2)
+		gc.Regfree(&r2)
+	}
+	gc.Regfree(&g1)
+	gc.Regfree(&r1)
+	return gc.Gbranch(optoas(op, t), nil, likely)
+}
+
+/*
+ * 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:
+			f.Convconst(&con, t.Type)
+
+		case gc.TINT32,
+			gc.TINT16,
+			gc.TINT8:
+			var con gc.Node
+			f.Convconst(&con, gc.Types[gc.TINT64])
+			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
+			f.Convconst(&con, gc.Types[gc.TUINT64])
+			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) {
+	switch {
+	case n == nil:
+		return
+	case gc.Isconst(n, gc.CTINT):
+		return n.Int(), true
+	case gc.Isconst(n, gc.CTBOOL):
+		return int64(obj.Bool2int(n.Bool())), 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
+}
+
+/*
+ * 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), t)
+
+	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
+
+	case gc.OSQRT<<16 | gc.TFLOAT64:
+		a = arm64.AFSQRTD
+	}
+
+	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/compile/internal/arm64/peep.go b/src/cmd/compile/internal/arm64/peep.go
new file mode 100644
index 0000000..387a30e
--- /dev/null
+++ b/src/cmd/compile/internal/arm64/peep.go
@@ -0,0 +1,809 @@
+// 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 at 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 at 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/compile/internal/gc"
+	"cmd/internal/obj"
+	"cmd/internal/obj/arm64"
+	"fmt"
+)
+
+var gactive uint32
+
+func peep(firstp *obj.Prog) {
+	g := (*gc.Graph)(gc.Flowstart(firstp, nil))
+	if g == nil {
+		return
+	}
+	gactive = 0
+
+	var p *obj.Prog
+	var r *gc.Flow
+	var t int
+loop1:
+	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
+		gc.Dumpit("loop1", g.Start, 0)
+	}
+
+	t = 0
+	for r = g.Start; r != nil; r = r.Link {
+		p = r.Prog
+
+		// TODO(minux) Handle smaller moves. arm and amd64
+		// distinguish between moves that *must* sign/zero
+		// extend and moves that don't care so they
+		// can eliminate moves that don't care without
+		// breaking moves that do care. This might let us
+		// simplify or remove the next peep loop, too.
+		if p.As == arm64.AMOVD || p.As == arm64.AFMOVD {
+			if regtyp(&p.To) {
+				// Try to eliminate reg->reg moves
+				if regtyp(&p.From) {
+					if p.From.Type == p.To.Type {
+						if copyprop(r) {
+							excise(r)
+							t++
+						} else if subprop(r) && copyprop(r) {
+							excise(r)
+							t++
+						}
+					}
+				}
+			}
+		}
+	}
+
+	if t != 0 {
+		goto loop1
+	}
+
+	/*
+	 * look for MOVB x,R; MOVB R,R (for small MOVs not handled above)
+	 */
+	var p1 *obj.Prog
+	var r1 *gc.Flow
+	for r := (*gc.Flow)(g.Start); r != nil; r = r.Link {
+		p = r.Prog
+		switch p.As {
+		default:
+			continue
+
+		case arm64.AMOVH,
+			arm64.AMOVHU,
+			arm64.AMOVB,
+			arm64.AMOVBU,
+			arm64.AMOVW,
+			arm64.AMOVWU:
+			if p.To.Type != obj.TYPE_REG {
+				continue
+			}
+		}
+
+		r1 = r.Link
+		if r1 == nil {
+			continue
+		}
+		p1 = r1.Prog
+		if p1.As != p.As {
+			continue
+		}
+		if p1.From.Type != obj.TYPE_REG || p1.From.Reg != p.To.Reg {
+			continue
+		}
+		if p1.To.Type != obj.TYPE_REG || p1.To.Reg != p.To.Reg {
+			continue
+		}
+		excise(r1)
+	}
+
+	if gc.Debug['D'] > 1 {
+		goto ret /* allow following code improvement to be suppressed */
+	}
+
+	// MOVD $c, R'; ADD R', R (R' unused) -> ADD $c, R
+	for r := (*gc.Flow)(g.Start); r != nil; r = r.Link {
+		p = r.Prog
+		switch p.As {
+		default:
+			continue
+
+		case arm64.AMOVD:
+			if p.To.Type != obj.TYPE_REG {
+				continue
+			}
+			if p.From.Type != obj.TYPE_CONST {
+				continue
+			}
+			if p.From.Offset < 0 || 4096 <= p.From.Offset {
+				continue
+			}
+		}
+		r1 = r.Link
+		if r1 == nil {
+			continue
+		}
+		p1 = r1.Prog
+		if p1.As != arm64.AADD && p1.As != arm64.ASUB { // TODO(aram): also logical after we have bimm.
+			continue
+		}
+		if p1.From.Type != obj.TYPE_REG || p1.From.Reg != p.To.Reg {
+			continue
+		}
+		if p1.To.Type != obj.TYPE_REG {
+			continue
+		}
+		if gc.Debug['P'] != 0 {
+			fmt.Printf("encoding $%d directly into %v in:\n%v\n%v\n", p.From.Offset, obj.Aconv(int(p1.As)), p, p1)
+		}
+		p1.From.Type = obj.TYPE_CONST
+		p1.From = p.From
+		excise(r)
+	}
+
+	/* TODO(minux):
+	 * look for OP x,y,R; CMP R, $0 -> OP.S x,y,R
+	 * when OP can set condition codes correctly
+	 */
+
+ret:
+	gc.Flowend(g)
+}
+
+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
+}
+
+/*
+ * the idea is to substitute
+ * one register for another
+ * from one MOV to another
+ *	MOV	a, R1
+ *	ADD	b, R1	/ no use of R2
+ *	MOV	R1, R2
+ * would be converted to
+ *	MOV	a, R2
+ *	ADD	b, R2
+ *	MOV	R2, R1
+ * hopefully, then the former or latter MOV
+ * will be eliminated by copy propagation.
+ *
+ * r0 (the argument, not the register) is the MOV at the end of the
+ * above sequences. This returns 1 if it modified any instructions.
+ */
+func subprop(r0 *gc.Flow) bool {
+	p := (*obj.Prog)(r0.Prog)
+	v1 := (*obj.Addr)(&p.From)
+	if !regtyp(v1) {
+		return false
+	}
+	v2 := (*obj.Addr)(&p.To)
+	if !regtyp(v2) {
+		return false
+	}
+	for r := gc.Uniqp(r0); r != nil; r = gc.Uniqp(r) {
+		if gc.Uniqs(r) == nil {
+			break
+		}
+		p = r.Prog
+		if p.As == obj.AVARDEF || p.As == obj.AVARKILL {
+			continue
+		}
+		if p.Info.Flags&gc.Call != 0 {
+			return false
+		}
+
+		if p.Info.Flags&(gc.RightRead|gc.RightWrite) == gc.RightWrite {
+			if p.To.Type == v1.Type {
+				if 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 {
+							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
+				}
+			}
+		}
+
+		if copyau(&p.From, v2) || copyau1(p, v2) || copyau(&p.To, v2) {
+			break
+		}
+		if copysub(&p.From, v1, v2, 0) != 0 || copysub1(p, v1, v2, 0) != 0 || copysub(&p.To, v1, v2, 0) != 0 {
+			break
+		}
+	}
+
+	return false
+}
+
+/*
+ * The idea is to remove redundant copies.
+ *	v1->v2	F=0
+ *	(use v2	s/v2/v1/)*
+ *	set v1	F=1
+ *	use v2	return fail (v1->v2 move must remain)
+ *	-----------------
+ *	v1->v2	F=0
+ *	(use v2	s/v2/v1/)*
+ *	set v1	F=1
+ *	set v2	return success (caller can remove v1->v2 move)
+ */
+func copyprop(r0 *gc.Flow) bool {
+	p := (*obj.Prog)(r0.Prog)
+	v1 := (*obj.Addr)(&p.From)
+	v2 := (*obj.Addr)(&p.To)
+	if copyas(v1, v2) {
+		if gc.Debug['P'] != 0 {
+			fmt.Printf("eliminating self-move: %v\n", r0.Prog)
+		}
+		return true
+	}
+
+	gactive++
+	if gc.Debug['P'] != 0 {
+		fmt.Printf("trying to eliminate %v->%v move from:\n%v\n", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), r0.Prog)
+	}
+	return copy1(v1, v2, r0.S1, 0)
+}
+
+// copy1 replaces uses of v2 with v1 starting at r and returns 1 if
+// all uses were rewritten.
+func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool {
+	if uint32(r.Active) == gactive {
+		if gc.Debug['P'] != 0 {
+			fmt.Printf("act set; return 1\n")
+		}
+		return true
+	}
+
+	r.Active = int32(gactive)
+	if gc.Debug['P'] != 0 {
+		fmt.Printf("copy1 replace %v with %v f=%d\n", gc.Ctxt.Dconv(v2), gc.Ctxt.Dconv(v1), f)
+	}
+	var t int
+	var p *obj.Prog
+	for ; r != nil; r = r.S1 {
+		p = r.Prog
+		if gc.Debug['P'] != 0 {
+			fmt.Printf("%v", p)
+		}
+		if f == 0 && gc.Uniqp(r) == nil {
+			// Multiple predecessors; conservatively
+			// assume v1 was set on other path
+			f = 1
+
+			if gc.Debug['P'] != 0 {
+				fmt.Printf("; merge; f=%d", f)
+			}
+		}
+
+		t = copyu(p, v2, nil)
+		switch t {
+		case 2: /* rar, can't split */
+			if gc.Debug['P'] != 0 {
+				fmt.Printf("; %v rar; return 0\n", gc.Ctxt.Dconv(v2))
+			}
+			return false
+
+		case 3: /* set */
+			if gc.Debug['P'] != 0 {
+				fmt.Printf("; %v set; return 1\n", gc.Ctxt.Dconv(v2))
+			}
+			return true
+
+		case 1, /* used, substitute */
+			4: /* use and set */
+			if f != 0 {
+				if gc.Debug['P'] == 0 {
+					return false
+				}
+				if t == 4 {
+					fmt.Printf("; %v used+set and f=%d; return 0\n", gc.Ctxt.Dconv(v2), f)
+				} else {
+					fmt.Printf("; %v used and f=%d; return 0\n", gc.Ctxt.Dconv(v2), f)
+				}
+				return false
+			}
+
+			if copyu(p, v2, v1) != 0 {
+				if gc.Debug['P'] != 0 {
+					fmt.Printf("; sub fail; return 0\n")
+				}
+				return false
+			}
+
+			if gc.Debug['P'] != 0 {
+				fmt.Printf("; sub %v->%v\n => %v", gc.Ctxt.Dconv(v2), gc.Ctxt.Dconv(v1), p)
+			}
+			if t == 4 {
+				if gc.Debug['P'] != 0 {
+					fmt.Printf("; %v used+set; return 1\n", gc.Ctxt.Dconv(v2))
+				}
+				return true
+			}
+		}
+
+		if f == 0 {
+			t = copyu(p, v1, nil)
+			if f == 0 && (t == 2 || t == 3 || t == 4) {
+				f = 1
+				if gc.Debug['P'] != 0 {
+					fmt.Printf("; %v set and !f; f=%d", gc.Ctxt.Dconv(v1), f)
+				}
+			}
+		}
+
+		if gc.Debug['P'] != 0 {
+			fmt.Printf("\n")
+		}
+		if r.S2 != nil {
+			if !copy1(v1, v2, r.S2, f) {
+				return false
+			}
+		}
+	}
+
+	return true
+}
+
+// If s==nil, copyu returns the set/use of v in p; otherwise, it
+// modifies p to replace reads of v with reads of s and returns 0 for
+// success or non-zero for failure.
+//
+// If s==nil, copy returns one of the following values:
+//	1 if v only used
+//	2 if v is set and used in one address (read-alter-rewrite;
+//	  can't substitute)
+//	3 if v is only set
+//	4 if v is set in one address and used in another (so addresses
+//	  can be rewritten independently)
+//	0 otherwise (not touched)
+func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
+	if p.From3Type() != obj.TYPE_NONE {
+		// 7g never generates a from3
+		fmt.Printf("copyu: from3 (%v) not implemented\n", gc.Ctxt.Dconv(p.From3))
+	}
+	if p.RegTo2 != obj.REG_NONE {
+		// 7g never generates a to2
+		fmt.Printf("copyu: RegTo2 (%v) not implemented\n", obj.Rconv(int(p.RegTo2)))
+	}
+
+	switch p.As {
+	default:
+		fmt.Printf("copyu: can't find %v\n", obj.Aconv(int(p.As)))
+		return 2
+
+	case obj.ANOP, /* read p->from, write p->to */
+		arm64.ANEG,
+		arm64.AFNEGD,
+		arm64.AFNEGS,
+		arm64.AFSQRTD,
+		arm64.AFCVTZSD,
+		arm64.AFCVTZSS,
+		arm64.AFCVTZSDW,
+		arm64.AFCVTZSSW,
+		arm64.AFCVTZUD,
+		arm64.AFCVTZUS,
+		arm64.AFCVTZUDW,
+		arm64.AFCVTZUSW,
+		arm64.AFCVTSD,
+		arm64.AFCVTDS,
+		arm64.ASCVTFD,
+		arm64.ASCVTFS,
+		arm64.ASCVTFWD,
+		arm64.ASCVTFWS,
+		arm64.AUCVTFD,
+		arm64.AUCVTFS,
+		arm64.AUCVTFWD,
+		arm64.AUCVTFWS,
+		arm64.AMOVB,
+		arm64.AMOVBU,
+		arm64.AMOVH,
+		arm64.AMOVHU,
+		arm64.AMOVW,
+		arm64.AMOVWU,
+		arm64.AMOVD,
+		arm64.AFMOVS,
+		arm64.AFMOVD:
+		if p.Scond == 0 {
+			if s != nil {
+				if copysub(&p.From, v, s, 1) != 0 {
+					return 1
+				}
+
+				// Update only indirect uses of v in p->to
+				if !copyas(&p.To, v) {
+					if copysub(&p.To, v, s, 1) != 0 {
+						return 1
+					}
+				}
+				return 0
+			}
+
+			if copyas(&p.To, v) {
+				// Fix up implicit from
+				if p.From.Type == obj.TYPE_NONE {
+					p.From = p.To
+				}
+				if copyau(&p.From, v) {
+					return 4
+				}
+				return 3
+			}
+
+			if copyau(&p.From, v) {
+				return 1
+			}
+			if copyau(&p.To, v) {
+				// p->to only indirectly uses v
+				return 1
+			}
+
+			return 0
+		}
+
+		/* rar p->from, write p->to or read p->from, rar p->to */
+		if p.From.Type == obj.TYPE_MEM {
+			if copyas(&p.From, v) {
+				// No s!=nil check; need to fail
+				// anyway in that case
+				return 2
+			}
+
+			if s != nil {
+				if copysub(&p.To, v, s, 1) != 0 {
+					return 1
+				}
+				return 0
+			}
+
+			if copyas(&p.To, v) {
+				return 3
+			}
+		} else if p.To.Type == obj.TYPE_MEM {
+			if copyas(&p.To, v) {
+				return 2
+			}
+			if s != nil {
+				if copysub(&p.From, v, s, 1) != 0 {
+					return 1
+				}
+				return 0
+			}
+
+			if copyau(&p.From, v) {
+				return 1
+			}
+		} else {
+			fmt.Printf("copyu: bad %v\n", p)
+		}
+
+		return 0
+
+	case arm64.AADD, /* read p->from, read p->reg, write p->to */
+		arm64.ASUB,
+		arm64.AAND,
+		arm64.AORR,
+		arm64.AEOR,
+		arm64.AMUL,
+		arm64.ASMULL,
+		arm64.AUMULL,
+		arm64.ASMULH,
+		arm64.AUMULH,
+		arm64.ASDIV,
+		arm64.AUDIV,
+		arm64.ALSL,
+		arm64.ALSR,
+		arm64.AASR,
+		arm64.AFADDD,
+		arm64.AFADDS,
+		arm64.AFSUBD,
+		arm64.AFSUBS,
+		arm64.AFMULD,
+		arm64.AFMULS,
+		arm64.AFDIVD,
+		arm64.AFDIVS:
+		if s != nil {
+			if copysub(&p.From, v, s, 1) != 0 {
+				return 1
+			}
+			if copysub1(p, v, s, 1) != 0 {
+				return 1
+			}
+
+			// Update only indirect uses of v in p->to
+			if !copyas(&p.To, v) {
+				if copysub(&p.To, v, s, 1) != 0 {
+					return 1
+				}
+			}
+			return 0
+		}
+
+		if copyas(&p.To, v) {
+			if p.Reg == 0 {
+				// Fix up implicit reg (e.g., ADD
+				// R3,R4 -> ADD R3,R4,R4) so we can
+				// update reg and to separately.
+				p.Reg = p.To.Reg
+			}
+
+			if copyau(&p.From, v) {
+				return 4
+			}
+			if copyau1(p, v) {
+				return 4
+			}
+			return 3
+		}
+
+		if copyau(&p.From, v) {
+			return 1
+		}
+		if copyau1(p, v) {
+			return 1
+		}
+		if copyau(&p.To, v) {
+			return 1
+		}
+		return 0
+
+	case arm64.ABEQ,
+		arm64.ABNE,
+		arm64.ABGE,
+		arm64.ABLT,
+		arm64.ABGT,
+		arm64.ABLE,
+		arm64.ABLO,
+		arm64.ABLS,
+		arm64.ABHI,
+		arm64.ABHS:
+		return 0
+
+	case obj.ACHECKNIL, /* read p->from */
+		arm64.ACMP, /* read p->from, read p->reg */
+		arm64.AFCMPD,
+		arm64.AFCMPS:
+		if s != nil {
+			if copysub(&p.From, v, s, 1) != 0 {
+				return 1
+			}
+			return copysub1(p, v, s, 1)
+		}
+
+		if copyau(&p.From, v) {
+			return 1
+		}
+		if copyau1(p, v) {
+			return 1
+		}
+		return 0
+
+	case arm64.AB: /* read p->to */
+		if s != nil {
+			if copysub(&p.To, v, s, 1) != 0 {
+				return 1
+			}
+			return 0
+		}
+
+		if copyau(&p.To, v) {
+			return 1
+		}
+		return 0
+
+	case obj.ARET: /* funny */
+		if s != nil {
+			return 0
+		}
+
+		// All registers die at this point, so claim
+		// everything is set (and not used).
+		return 3
+
+	case arm64.ABL: /* funny */
+		if p.From.Type == obj.TYPE_REG && v.Type == obj.TYPE_REG && p.From.Reg == v.Reg {
+			return 2
+		}
+
+		if s != nil {
+			if copysub(&p.To, v, s, 1) != 0 {
+				return 1
+			}
+			return 0
+		}
+
+		if copyau(&p.To, v) {
+			return 4
+		}
+		return 3
+
+	// R31 is zero, used by DUFFZERO, cannot be substituted.
+	// R16 is ptr to memory, used and set, cannot be substituted.
+	case obj.ADUFFZERO:
+		if v.Type == obj.TYPE_REG {
+			if v.Reg == 31 {
+				return 1
+			}
+			if v.Reg == 16 {
+				return 2
+			}
+		}
+
+		return 0
+
+	// R16, R17 are ptr to src, dst, used and set, cannot be substituted.
+	// R27 is scratch, set by DUFFCOPY, cannot be substituted.
+	case obj.ADUFFCOPY:
+		if v.Type == obj.TYPE_REG {
+			if v.Reg == 16 || v.Reg == 17 {
+				return 2
+			}
+			if v.Reg == 27 {
+				return 3
+			}
+		}
+
+		return 0
+
+	case arm64.AHINT,
+		obj.ATEXT,
+		obj.APCDATA,
+		obj.AFUNCDATA,
+		obj.AVARDEF,
+		obj.AVARKILL:
+		return 0
+	}
+}
+
+// copyas returns 1 if a and v address the same register.
+//
+// If a is the from operand, this means this operation reads the
+// register in v. If a is the to operand, this means this operation
+// writes the register in v.
+func copyas(a *obj.Addr, v *obj.Addr) bool {
+	if regtyp(v) {
+		if a.Type == v.Type {
+			if a.Reg == v.Reg {
+				return true
+			}
+		}
+	}
+	return false
+}
+
+// copyau returns 1 if a either directly or indirectly addresses the
+// same register as v.
+//
+// If a is the from operand, this means this operation reads the
+// register in v. If a is the to operand, this means the operation
+// either reads or writes the register in v (if !copyas(a, v), then
+// the operation reads the register in v).
+func copyau(a *obj.Addr, v *obj.Addr) bool {
+	if copyas(a, v) {
+		return true
+	}
+	if v.Type == obj.TYPE_REG {
+		if a.Type == obj.TYPE_MEM || (a.Type == obj.TYPE_ADDR && a.Reg != 0) {
+			if v.Reg == a.Reg {
+				return true
+			}
+		}
+	}
+	return false
+}
+
+// copyau1 returns 1 if p->reg references the same register as v and v
+// is a direct reference.
+func copyau1(p *obj.Prog, v *obj.Addr) bool {
+	if regtyp(v) && v.Reg != 0 {
+		if p.Reg == v.Reg {
+			return true
+		}
+	}
+	return false
+}
+
+// copysub replaces v with s in a if f!=0 or indicates it if could if f==0.
+// Returns 1 on failure to substitute (it always succeeds on arm64).
+func copysub(a *obj.Addr, v *obj.Addr, s *obj.Addr, f int) int {
+	if f != 0 {
+		if copyau(a, v) {
+			a.Reg = s.Reg
+		}
+	}
+	return 0
+}
+
+// copysub1 replaces v with s in p1->reg if f!=0 or indicates if it could if f==0.
+// Returns 1 on failure to substitute (it always succeeds on arm64).
+func copysub1(p1 *obj.Prog, v *obj.Addr, s *obj.Addr, f int) int {
+	if f != 0 {
+		if copyau1(p1, v) {
+			p1.Reg = s.Reg
+		}
+	}
+	return 0
+}
+
+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/compile/internal/arm64/prog.go b/src/cmd/compile/internal/arm64/prog.go
new file mode 100644
index 0000000..1106e78
--- /dev/null
+++ b/src/cmd/compile/internal/arm64/prog.go
@@ -0,0 +1,174 @@
+// 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 arm64
+
+import (
+	"cmd/compile/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.RegRead, 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.AFSQRTD: {gc.SizeD | 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.RegRead, 0, 0, 0},
+	arm64.AFCMPS:  {gc.SizeF | gc.LeftRead | gc.RegRead, 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},
+	arm64.ACBZ:    {gc.Cjmp, 0, 0, 0},
+	arm64.ACBNZ:   {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/compile/internal/arm64/reg.go b/src/cmd/compile/internal/arm64/reg.go
new file mode 100644
index 0000000..b84359a
--- /dev/null
+++ b/src/cmd/compile/internal/arm64/reg.go
@@ -0,0 +1,169 @@
+// 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 at 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 at 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/compile/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))
+
+	// Exclude R26 - R31.
+	for r := arm64.REGMAX + 1; r <= arm64.REGZERO; r++ {
+		regbits |= RtoB(r)
+	}
+
+	// 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/compile/internal/big/accuracy_string.go b/src/cmd/compile/internal/big/accuracy_string.go
new file mode 100644
index 0000000..24ef7f1
--- /dev/null
+++ b/src/cmd/compile/internal/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/cmd/compile/internal/big/arith.go b/src/cmd/compile/internal/big/arith.go
new file mode 100644
index 0000000..d7ea838
--- /dev/null
+++ b/src/cmd/compile/internal/big/arith.go
@@ -0,0 +1,305 @@
+// 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.
+
+// This file provides Go implementations of elementary multi-precision
+// arithmetic operations on word vectors. Needed for platforms without
+// assembly implementations of these routines.
+
+package big
+
+// A Word represents a single digit of a multi-precision unsigned integer.
+type Word uintptr
+
+const (
+	// Compute the size _S of a Word in bytes.
+	_m    = ^Word(0)
+	_logS = _m>>8&1 + _m>>16&1 + _m>>32&1
+	_S    = 1 << _logS
+
+	_W = _S << 3 // word size in bits
+	_B = 1 << _W // digit base
+	_M = _B - 1  // digit mask
+
+	_W2 = _W / 2   // half word size in bits
+	_B2 = 1 << _W2 // half digit base
+	_M2 = _B2 - 1  // half digit mask
+)
+
+// ----------------------------------------------------------------------------
+// Elementary operations on words
+//
+// These operations are used by the vector operations below.
+
+// z1<<_W + z0 = x+y+c, with c == 0 or 1
+func addWW_g(x, y, c Word) (z1, z0 Word) {
+	yc := y + c
+	z0 = x + yc
+	if z0 < x || yc < y {
+		z1 = 1
+	}
+	return
+}
+
+// z1<<_W + z0 = x-y-c, with c == 0 or 1
+func subWW_g(x, y, c Word) (z1, z0 Word) {
+	yc := y + c
+	z0 = x - yc
+	if z0 > x || yc < y {
+		z1 = 1
+	}
+	return
+}
+
+// z1<<_W + z0 = x*y
+// Adapted from Warren, Hacker's Delight, p. 132.
+func mulWW_g(x, y Word) (z1, z0 Word) {
+	x0 := x & _M2
+	x1 := x >> _W2
+	y0 := y & _M2
+	y1 := y >> _W2
+	w0 := x0 * y0
+	t := x1*y0 + w0>>_W2
+	w1 := t & _M2
+	w2 := t >> _W2
+	w1 += x0 * y1
+	z1 = x1*y1 + w2 + w1>>_W2
+	z0 = x * y
+	return
+}
+
+// z1<<_W + z0 = x*y + c
+func mulAddWWW_g(x, y, c Word) (z1, z0 Word) {
+	z1, zz0 := mulWW_g(x, y)
+	if z0 = zz0 + c; z0 < zz0 {
+		z1++
+	}
+	return
+}
+
+// Length of x in bits.
+func bitLen_g(x Word) (n int) {
+	for ; x >= 0x8000; x >>= 16 {
+		n += 16
+	}
+	if x >= 0x80 {
+		x >>= 8
+		n += 8
+	}
+	if x >= 0x8 {
+		x >>= 4
+		n += 4
+	}
+	if x >= 0x2 {
+		x >>= 2
+		n += 2
+	}
+	if x >= 0x1 {
+		n++
+	}
+	return
+}
+
+// log2 computes the integer binary logarithm of x.
+// The result is the integer n for which 2^n <= x < 2^(n+1).
+// If x == 0, the result is -1.
+func log2(x Word) int {
+	return bitLen(x) - 1
+}
+
+// nlz returns the number of leading zeros in x.
+func nlz(x Word) uint {
+	return uint(_W - bitLen(x))
+}
+
+// nlz64 returns the number of leading zeros in x.
+func nlz64(x uint64) uint {
+	switch _W {
+	case 32:
+		w := x >> 32
+		if w == 0 {
+			return 32 + nlz(Word(x))
+		}
+		return nlz(Word(w))
+	case 64:
+		return nlz(Word(x))
+	}
+	panic("unreachable")
+}
+
+// q = (u1<<_W + u0 - r)/y
+// Adapted from Warren, Hacker's Delight, p. 152.
+func divWW_g(u1, u0, v Word) (q, r Word) {
+	if u1 >= v {
+		return 1<<_W - 1, 1<<_W - 1
+	}
+
+	s := nlz(v)
+	v <<= s
+
+	vn1 := v >> _W2
+	vn0 := v & _M2
+	un32 := u1<<s | u0>>(_W-s)
+	un10 := u0 << s
+	un1 := un10 >> _W2
+	un0 := un10 & _M2
+	q1 := un32 / vn1
+	rhat := un32 - q1*vn1
+
+	for q1 >= _B2 || q1*vn0 > _B2*rhat+un1 {
+		q1--
+		rhat += vn1
+		if rhat >= _B2 {
+			break
+		}
+	}
+
+	un21 := un32*_B2 + un1 - q1*v
+	q0 := un21 / vn1
+	rhat = un21 - q0*vn1
+
+	for q0 >= _B2 || q0*vn0 > _B2*rhat+un0 {
+		q0--
+		rhat += vn1
+		if rhat >= _B2 {
+			break
+		}
+	}
+
+	return q1*_B2 + q0, (un21*_B2 + un0 - q0*v) >> s
+}
+
+// Keep for performance debugging.
+// Using addWW_g is likely slower.
+const use_addWW_g = false
+
+// The resulting carry c is either 0 or 1.
+func addVV_g(z, x, y []Word) (c Word) {
+	if use_addWW_g {
+		for i := range z {
+			c, z[i] = addWW_g(x[i], y[i], c)
+		}
+		return
+	}
+
+	for i, xi := range x[:len(z)] {
+		yi := y[i]
+		zi := xi + yi + c
+		z[i] = zi
+		// see "Hacker's Delight", section 2-12 (overflow detection)
+		c = (xi&yi | (xi|yi)&^zi) >> (_W - 1)
+	}
+	return
+}
+
+// The resulting carry c is either 0 or 1.
+func subVV_g(z, x, y []Word) (c Word) {
+	if use_addWW_g {
+		for i := range z {
+			c, z[i] = subWW_g(x[i], y[i], c)
+		}
+		return
+	}
+
+	for i, xi := range x[:len(z)] {
+		yi := y[i]
+		zi := xi - yi - c
+		z[i] = zi
+		// see "Hacker's Delight", section 2-12 (overflow detection)
+		c = (yi&^xi | (yi|^xi)&zi) >> (_W - 1)
+	}
+	return
+}
+
+// The resulting carry c is either 0 or 1.
+func addVW_g(z, x []Word, y Word) (c Word) {
+	if use_addWW_g {
+		c = y
+		for i := range z {
+			c, z[i] = addWW_g(x[i], c, 0)
+		}
+		return
+	}
+
+	c = y
+	for i, xi := range x[:len(z)] {
+		zi := xi + c
+		z[i] = zi
+		c = xi &^ zi >> (_W - 1)
+	}
+	return
+}
+
+func subVW_g(z, x []Word, y Word) (c Word) {
+	if use_addWW_g {
+		c = y
+		for i := range z {
+			c, z[i] = subWW_g(x[i], c, 0)
+		}
+		return
+	}
+
+	c = y
+	for i, xi := range x[:len(z)] {
+		zi := xi - c
+		z[i] = zi
+		c = (zi &^ xi) >> (_W - 1)
+	}
+	return
+}
+
+func shlVU_g(z, x []Word, s uint) (c Word) {
+	if n := len(z); n > 0 {
+		ŝ := _W - s
+		w1 := x[n-1]
+		c = w1 >> ŝ
+		for i := n - 1; i > 0; i-- {
+			w := w1
+			w1 = x[i-1]
+			z[i] = w<<s | w1>>ŝ
+		}
+		z[0] = w1 << s
+	}
+	return
+}
+
+func shrVU_g(z, x []Word, s uint) (c Word) {
+	if n := len(z); n > 0 {
+		ŝ := _W - s
+		w1 := x[0]
+		c = w1 << ŝ
+		for i := 0; i < n-1; i++ {
+			w := w1
+			w1 = x[i+1]
+			z[i] = w>>s | w1<<ŝ
+		}
+		z[n-1] = w1 >> s
+	}
+	return
+}
+
+func mulAddVWW_g(z, x []Word, y, r Word) (c Word) {
+	c = r
+	for i := range z {
+		c, z[i] = mulAddWWW_g(x[i], y, c)
+	}
+	return
+}
+
+// TODO(gri) Remove use of addWW_g here and then we can remove addWW_g and subWW_g.
+func addMulVVW_g(z, x []Word, y Word) (c Word) {
+	for i := range z {
+		z1, z0 := mulAddWWW_g(x[i], y, z[i])
+		c, z[i] = addWW_g(z0, c, 0)
+		c += z1
+	}
+	return
+}
+
+func divWVW_g(z []Word, xn Word, x []Word, y Word) (r Word) {
+	r = xn
+	for i := len(z) - 1; i >= 0; i-- {
+		z[i], r = divWW_g(r, x[i], y)
+	}
+	return
+}
diff --git a/src/cmd/compile/internal/big/arith_decl.go b/src/cmd/compile/internal/big/arith_decl.go
new file mode 100644
index 0000000..fe13577
--- /dev/null
+++ b/src/cmd/compile/internal/big/arith_decl.go
@@ -0,0 +1,53 @@
+// 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
+
+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/cmd/compile/internal/big/arith_test.go b/src/cmd/compile/internal/big/arith_test.go
new file mode 100644
index 0000000..f46a494
--- /dev/null
+++ b/src/cmd/compile/internal/big/arith_test.go
@@ -0,0 +1,457 @@
+// 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 big
+
+import (
+	"math/rand"
+	"testing"
+)
+
+type funWW func(x, y, c Word) (z1, z0 Word)
+type argWW struct {
+	x, y, c, z1, z0 Word
+}
+
+var sumWW = []argWW{
+	{0, 0, 0, 0, 0},
+	{0, 1, 0, 0, 1},
+	{0, 0, 1, 0, 1},
+	{0, 1, 1, 0, 2},
+	{12345, 67890, 0, 0, 80235},
+	{12345, 67890, 1, 0, 80236},
+	{_M, 1, 0, 1, 0},
+	{_M, 0, 1, 1, 0},
+	{_M, 1, 1, 1, 1},
+	{_M, _M, 0, 1, _M - 1},
+	{_M, _M, 1, 1, _M},
+}
+
+func testFunWW(t *testing.T, msg string, f funWW, a argWW) {
+	z1, z0 := f(a.x, a.y, a.c)
+	if z1 != a.z1 || z0 != a.z0 {
+		t.Errorf("%s%+v\n\tgot z1:z0 = %#x:%#x; want %#x:%#x", msg, a, z1, z0, a.z1, a.z0)
+	}
+}
+
+func TestFunWW(t *testing.T) {
+	for _, a := range sumWW {
+		arg := a
+		testFunWW(t, "addWW_g", addWW_g, arg)
+
+		arg = argWW{a.y, a.x, a.c, a.z1, a.z0}
+		testFunWW(t, "addWW_g symmetric", addWW_g, arg)
+
+		arg = argWW{a.z0, a.x, a.c, a.z1, a.y}
+		testFunWW(t, "subWW_g", subWW_g, arg)
+
+		arg = argWW{a.z0, a.y, a.c, a.z1, a.x}
+		testFunWW(t, "subWW_g symmetric", subWW_g, arg)
+	}
+}
+
+type funVV func(z, x, y []Word) (c Word)
+type argVV struct {
+	z, x, y nat
+	c       Word
+}
+
+var sumVV = []argVV{
+	{},
+	{nat{0}, nat{0}, nat{0}, 0},
+	{nat{1}, nat{1}, nat{0}, 0},
+	{nat{0}, nat{_M}, nat{1}, 1},
+	{nat{80235}, nat{12345}, nat{67890}, 0},
+	{nat{_M - 1}, nat{_M}, nat{_M}, 1},
+	{nat{0, 0, 0, 0}, nat{_M, _M, _M, _M}, nat{1, 0, 0, 0}, 1},
+	{nat{0, 0, 0, _M}, nat{_M, _M, _M, _M - 1}, nat{1, 0, 0, 0}, 0},
+	{nat{0, 0, 0, 0}, nat{_M, 0, _M, 0}, nat{1, _M, 0, _M}, 1},
+}
+
+func testFunVV(t *testing.T, msg string, f funVV, a argVV) {
+	z := make(nat, len(a.z))
+	c := f(z, a.x, a.y)
+	for i, zi := range z {
+		if zi != a.z[i] {
+			t.Errorf("%s%+v\n\tgot z[%d] = %#x; want %#x", msg, a, i, zi, a.z[i])
+			break
+		}
+	}
+	if c != a.c {
+		t.Errorf("%s%+v\n\tgot c = %#x; want %#x", msg, a, c, a.c)
+	}
+}
+
+func TestFunVV(t *testing.T) {
+	for _, a := range sumVV {
+		arg := a
+		testFunVV(t, "addVV_g", addVV_g, arg)
+		testFunVV(t, "addVV", addVV, arg)
+
+		arg = argVV{a.z, a.y, a.x, a.c}
+		testFunVV(t, "addVV_g symmetric", addVV_g, arg)
+		testFunVV(t, "addVV symmetric", addVV, arg)
+
+		arg = argVV{a.x, a.z, a.y, a.c}
+		testFunVV(t, "subVV_g", subVV_g, arg)
+		testFunVV(t, "subVV", subVV, arg)
+
+		arg = argVV{a.y, a.z, a.x, a.c}
+		testFunVV(t, "subVV_g symmetric", subVV_g, arg)
+		testFunVV(t, "subVV symmetric", subVV, arg)
+	}
+}
+
+// Always the same seed for reproducible results.
+var rnd = rand.New(rand.NewSource(0))
+
+func rndW() Word {
+	return Word(rnd.Int63()<<1 | rnd.Int63n(2))
+}
+
+func rndV(n int) []Word {
+	v := make([]Word, n)
+	for i := range v {
+		v[i] = rndW()
+	}
+	return v
+}
+
+func benchmarkFunVV(b *testing.B, f funVV, n int) {
+	x := rndV(n)
+	y := rndV(n)
+	z := make([]Word, n)
+	b.SetBytes(int64(n * _W))
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		f(z, x, y)
+	}
+}
+
+func BenchmarkAddVV_1(b *testing.B)   { benchmarkFunVV(b, addVV, 1) }
+func BenchmarkAddVV_2(b *testing.B)   { benchmarkFunVV(b, addVV, 2) }
+func BenchmarkAddVV_3(b *testing.B)   { benchmarkFunVV(b, addVV, 3) }
+func BenchmarkAddVV_4(b *testing.B)   { benchmarkFunVV(b, addVV, 4) }
+func BenchmarkAddVV_5(b *testing.B)   { benchmarkFunVV(b, addVV, 5) }
+func BenchmarkAddVV_1e1(b *testing.B) { benchmarkFunVV(b, addVV, 1e1) }
+func BenchmarkAddVV_1e2(b *testing.B) { benchmarkFunVV(b, addVV, 1e2) }
+func BenchmarkAddVV_1e3(b *testing.B) { benchmarkFunVV(b, addVV, 1e3) }
+func BenchmarkAddVV_1e4(b *testing.B) { benchmarkFunVV(b, addVV, 1e4) }
+func BenchmarkAddVV_1e5(b *testing.B) { benchmarkFunVV(b, addVV, 1e5) }
+
+type funVW func(z, x []Word, y Word) (c Word)
+type argVW struct {
+	z, x nat
+	y    Word
+	c    Word
+}
+
+var sumVW = []argVW{
+	{},
+	{nil, nil, 2, 2},
+	{nat{0}, nat{0}, 0, 0},
+	{nat{1}, nat{0}, 1, 0},
+	{nat{1}, nat{1}, 0, 0},
+	{nat{0}, nat{_M}, 1, 1},
+	{nat{0, 0, 0, 0}, nat{_M, _M, _M, _M}, 1, 1},
+	{nat{585}, nat{314}, 271, 0},
+}
+
+var prodVW = []argVW{
+	{},
+	{nat{0}, nat{0}, 0, 0},
+	{nat{0}, nat{_M}, 0, 0},
+	{nat{0}, nat{0}, _M, 0},
+	{nat{1}, nat{1}, 1, 0},
+	{nat{22793}, nat{991}, 23, 0},
+	{nat{0, 0, 0, 22793}, nat{0, 0, 0, 991}, 23, 0},
+	{nat{0, 0, 0, 0}, nat{7893475, 7395495, 798547395, 68943}, 0, 0},
+	{nat{0, 0, 0, 0}, nat{0, 0, 0, 0}, 894375984, 0},
+	{nat{_M << 1 & _M}, nat{_M}, 1 << 1, _M >> (_W - 1)},
+	{nat{_M << 7 & _M}, nat{_M}, 1 << 7, _M >> (_W - 7)},
+	{nat{_M << 7 & _M, _M, _M, _M}, nat{_M, _M, _M, _M}, 1 << 7, _M >> (_W - 7)},
+}
+
+var lshVW = []argVW{
+	{},
+	{nat{0}, nat{0}, 0, 0},
+	{nat{0}, nat{0}, 1, 0},
+	{nat{0}, nat{0}, 20, 0},
+
+	{nat{_M}, nat{_M}, 0, 0},
+	{nat{_M << 1 & _M}, nat{_M}, 1, 1},
+	{nat{_M << 20 & _M}, nat{_M}, 20, _M >> (_W - 20)},
+
+	{nat{_M, _M, _M}, nat{_M, _M, _M}, 0, 0},
+	{nat{_M << 1 & _M, _M, _M}, nat{_M, _M, _M}, 1, 1},
+	{nat{_M << 20 & _M, _M, _M}, nat{_M, _M, _M}, 20, _M >> (_W - 20)},
+}
+
+var rshVW = []argVW{
+	{},
+	{nat{0}, nat{0}, 0, 0},
+	{nat{0}, nat{0}, 1, 0},
+	{nat{0}, nat{0}, 20, 0},
+
+	{nat{_M}, nat{_M}, 0, 0},
+	{nat{_M >> 1}, nat{_M}, 1, _M << (_W - 1) & _M},
+	{nat{_M >> 20}, nat{_M}, 20, _M << (_W - 20) & _M},
+
+	{nat{_M, _M, _M}, nat{_M, _M, _M}, 0, 0},
+	{nat{_M, _M, _M >> 1}, nat{_M, _M, _M}, 1, _M << (_W - 1) & _M},
+	{nat{_M, _M, _M >> 20}, nat{_M, _M, _M}, 20, _M << (_W - 20) & _M},
+}
+
+func testFunVW(t *testing.T, msg string, f funVW, a argVW) {
+	z := make(nat, len(a.z))
+	c := f(z, a.x, a.y)
+	for i, zi := range z {
+		if zi != a.z[i] {
+			t.Errorf("%s%+v\n\tgot z[%d] = %#x; want %#x", msg, a, i, zi, a.z[i])
+			break
+		}
+	}
+	if c != a.c {
+		t.Errorf("%s%+v\n\tgot c = %#x; want %#x", msg, a, c, a.c)
+	}
+}
+
+func makeFunVW(f func(z, x []Word, s uint) (c Word)) funVW {
+	return func(z, x []Word, s Word) (c Word) {
+		return f(z, x, uint(s))
+	}
+}
+
+func TestFunVW(t *testing.T) {
+	for _, a := range sumVW {
+		arg := a
+		testFunVW(t, "addVW_g", addVW_g, arg)
+		testFunVW(t, "addVW", addVW, arg)
+
+		arg = argVW{a.x, a.z, a.y, a.c}
+		testFunVW(t, "subVW_g", subVW_g, arg)
+		testFunVW(t, "subVW", subVW, arg)
+	}
+
+	shlVW_g := makeFunVW(shlVU_g)
+	shlVW := makeFunVW(shlVU)
+	for _, a := range lshVW {
+		arg := a
+		testFunVW(t, "shlVU_g", shlVW_g, arg)
+		testFunVW(t, "shlVU", shlVW, arg)
+	}
+
+	shrVW_g := makeFunVW(shrVU_g)
+	shrVW := makeFunVW(shrVU)
+	for _, a := range rshVW {
+		arg := a
+		testFunVW(t, "shrVU_g", shrVW_g, arg)
+		testFunVW(t, "shrVU", shrVW, arg)
+	}
+}
+
+func benchmarkFunVW(b *testing.B, f funVW, n int) {
+	x := rndV(n)
+	y := rndW()
+	z := make([]Word, n)
+	b.SetBytes(int64(n * _S))
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		f(z, x, y)
+	}
+}
+
+func BenchmarkAddVW_1(b *testing.B)   { benchmarkFunVW(b, addVW, 1) }
+func BenchmarkAddVW_2(b *testing.B)   { benchmarkFunVW(b, addVW, 2) }
+func BenchmarkAddVW_3(b *testing.B)   { benchmarkFunVW(b, addVW, 3) }
+func BenchmarkAddVW_4(b *testing.B)   { benchmarkFunVW(b, addVW, 4) }
+func BenchmarkAddVW_5(b *testing.B)   { benchmarkFunVW(b, addVW, 5) }
+func BenchmarkAddVW_1e1(b *testing.B) { benchmarkFunVW(b, addVW, 1e1) }
+func BenchmarkAddVW_1e2(b *testing.B) { benchmarkFunVW(b, addVW, 1e2) }
+func BenchmarkAddVW_1e3(b *testing.B) { benchmarkFunVW(b, addVW, 1e3) }
+func BenchmarkAddVW_1e4(b *testing.B) { benchmarkFunVW(b, addVW, 1e4) }
+func BenchmarkAddVW_1e5(b *testing.B) { benchmarkFunVW(b, addVW, 1e5) }
+
+type funVWW func(z, x []Word, y, r Word) (c Word)
+type argVWW struct {
+	z, x nat
+	y, r Word
+	c    Word
+}
+
+var prodVWW = []argVWW{
+	{},
+	{nat{0}, nat{0}, 0, 0, 0},
+	{nat{991}, nat{0}, 0, 991, 0},
+	{nat{0}, nat{_M}, 0, 0, 0},
+	{nat{991}, nat{_M}, 0, 991, 0},
+	{nat{0}, nat{0}, _M, 0, 0},
+	{nat{991}, nat{0}, _M, 991, 0},
+	{nat{1}, nat{1}, 1, 0, 0},
+	{nat{992}, nat{1}, 1, 991, 0},
+	{nat{22793}, nat{991}, 23, 0, 0},
+	{nat{22800}, nat{991}, 23, 7, 0},
+	{nat{0, 0, 0, 22793}, nat{0, 0, 0, 991}, 23, 0, 0},
+	{nat{7, 0, 0, 22793}, nat{0, 0, 0, 991}, 23, 7, 0},
+	{nat{0, 0, 0, 0}, nat{7893475, 7395495, 798547395, 68943}, 0, 0, 0},
+	{nat{991, 0, 0, 0}, nat{7893475, 7395495, 798547395, 68943}, 0, 991, 0},
+	{nat{0, 0, 0, 0}, nat{0, 0, 0, 0}, 894375984, 0, 0},
+	{nat{991, 0, 0, 0}, nat{0, 0, 0, 0}, 894375984, 991, 0},
+	{nat{_M << 1 & _M}, nat{_M}, 1 << 1, 0, _M >> (_W - 1)},
+	{nat{_M<<1&_M + 1}, nat{_M}, 1 << 1, 1, _M >> (_W - 1)},
+	{nat{_M << 7 & _M}, nat{_M}, 1 << 7, 0, _M >> (_W - 7)},
+	{nat{_M<<7&_M + 1<<6}, nat{_M}, 1 << 7, 1 << 6, _M >> (_W - 7)},
+	{nat{_M << 7 & _M, _M, _M, _M}, nat{_M, _M, _M, _M}, 1 << 7, 0, _M >> (_W - 7)},
+	{nat{_M<<7&_M + 1<<6, _M, _M, _M}, nat{_M, _M, _M, _M}, 1 << 7, 1 << 6, _M >> (_W - 7)},
+}
+
+func testFunVWW(t *testing.T, msg string, f funVWW, a argVWW) {
+	z := make(nat, len(a.z))
+	c := f(z, a.x, a.y, a.r)
+	for i, zi := range z {
+		if zi != a.z[i] {
+			t.Errorf("%s%+v\n\tgot z[%d] = %#x; want %#x", msg, a, i, zi, a.z[i])
+			break
+		}
+	}
+	if c != a.c {
+		t.Errorf("%s%+v\n\tgot c = %#x; want %#x", msg, a, c, a.c)
+	}
+}
+
+// TODO(gri) mulAddVWW and divWVW are symmetric operations but
+//           their signature is not symmetric. Try to unify.
+
+type funWVW func(z []Word, xn Word, x []Word, y Word) (r Word)
+type argWVW struct {
+	z  nat
+	xn Word
+	x  nat
+	y  Word
+	r  Word
+}
+
+func testFunWVW(t *testing.T, msg string, f funWVW, a argWVW) {
+	z := make(nat, len(a.z))
+	r := f(z, a.xn, a.x, a.y)
+	for i, zi := range z {
+		if zi != a.z[i] {
+			t.Errorf("%s%+v\n\tgot z[%d] = %#x; want %#x", msg, a, i, zi, a.z[i])
+			break
+		}
+	}
+	if r != a.r {
+		t.Errorf("%s%+v\n\tgot r = %#x; want %#x", msg, a, r, a.r)
+	}
+}
+
+func TestFunVWW(t *testing.T) {
+	for _, a := range prodVWW {
+		arg := a
+		testFunVWW(t, "mulAddVWW_g", mulAddVWW_g, arg)
+		testFunVWW(t, "mulAddVWW", mulAddVWW, arg)
+
+		if a.y != 0 && a.r < a.y {
+			arg := argWVW{a.x, a.c, a.z, a.y, a.r}
+			testFunWVW(t, "divWVW_g", divWVW_g, arg)
+			testFunWVW(t, "divWVW", divWVW, arg)
+		}
+	}
+}
+
+var mulWWTests = []struct {
+	x, y Word
+	q, r Word
+}{
+	{_M, _M, _M - 1, 1},
+	// 32 bit only: {0xc47dfa8c, 50911, 0x98a4, 0x998587f4},
+}
+
+func TestMulWW(t *testing.T) {
+	for i, test := range mulWWTests {
+		q, r := mulWW_g(test.x, test.y)
+		if q != test.q || r != test.r {
+			t.Errorf("#%d got (%x, %x) want (%x, %x)", i, q, r, test.q, test.r)
+		}
+	}
+}
+
+var mulAddWWWTests = []struct {
+	x, y, c Word
+	q, r    Word
+}{
+	// TODO(agl): These will only work on 64-bit platforms.
+	// {15064310297182388543, 0xe7df04d2d35d5d80, 13537600649892366549, 13644450054494335067, 10832252001440893781},
+	// {15064310297182388543, 0xdab2f18048baa68d, 13644450054494335067, 12869334219691522700, 14233854684711418382},
+	{_M, _M, 0, _M - 1, 1},
+	{_M, _M, _M, _M, 0},
+}
+
+func TestMulAddWWW(t *testing.T) {
+	for i, test := range mulAddWWWTests {
+		q, r := mulAddWWW_g(test.x, test.y, test.c)
+		if q != test.q || r != test.r {
+			t.Errorf("#%d got (%x, %x) want (%x, %x)", i, q, r, test.q, test.r)
+		}
+	}
+}
+
+func benchmarkAddMulVVW(b *testing.B, n int) {
+	x := rndV(n)
+	y := rndW()
+	z := make([]Word, n)
+	b.SetBytes(int64(n * _W))
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		addMulVVW(z, x, y)
+	}
+}
+
+func BenchmarkAddMulVVW_1(b *testing.B)   { benchmarkAddMulVVW(b, 1) }
+func BenchmarkAddMulVVW_2(b *testing.B)   { benchmarkAddMulVVW(b, 2) }
+func BenchmarkAddMulVVW_3(b *testing.B)   { benchmarkAddMulVVW(b, 3) }
+func BenchmarkAddMulVVW_4(b *testing.B)   { benchmarkAddMulVVW(b, 4) }
+func BenchmarkAddMulVVW_5(b *testing.B)   { benchmarkAddMulVVW(b, 5) }
+func BenchmarkAddMulVVW_1e1(b *testing.B) { benchmarkAddMulVVW(b, 1e1) }
+func BenchmarkAddMulVVW_1e2(b *testing.B) { benchmarkAddMulVVW(b, 1e2) }
+func BenchmarkAddMulVVW_1e3(b *testing.B) { benchmarkAddMulVVW(b, 1e3) }
+func BenchmarkAddMulVVW_1e4(b *testing.B) { benchmarkAddMulVVW(b, 1e4) }
+func BenchmarkAddMulVVW_1e5(b *testing.B) { benchmarkAddMulVVW(b, 1e5) }
+
+func testWordBitLen(t *testing.T, fname string, f func(Word) int) {
+	for i := 0; i <= _W; i++ {
+		x := Word(1) << uint(i-1) // i == 0 => x == 0
+		n := f(x)
+		if n != i {
+			t.Errorf("got %d; want %d for %s(%#x)", n, i, fname, x)
+		}
+	}
+}
+
+func TestWordBitLen(t *testing.T) {
+	testWordBitLen(t, "bitLen", bitLen)
+	testWordBitLen(t, "bitLen_g", bitLen_g)
+}
+
+// runs b.N iterations of bitLen called on a Word containing (1 << nbits)-1.
+func benchmarkBitLenN(b *testing.B, nbits uint) {
+	testword := Word((uint64(1) << nbits) - 1)
+	for i := 0; i < b.N; i++ {
+		bitLen(testword)
+	}
+}
+
+// Individual bitLen tests.  Numbers chosen to examine both sides
+// of powers-of-two boundaries.
+func BenchmarkBitLen0(b *testing.B)  { benchmarkBitLenN(b, 0) }
+func BenchmarkBitLen1(b *testing.B)  { benchmarkBitLenN(b, 1) }
+func BenchmarkBitLen2(b *testing.B)  { benchmarkBitLenN(b, 2) }
+func BenchmarkBitLen3(b *testing.B)  { benchmarkBitLenN(b, 3) }
+func BenchmarkBitLen4(b *testing.B)  { benchmarkBitLenN(b, 4) }
+func BenchmarkBitLen5(b *testing.B)  { benchmarkBitLenN(b, 5) }
+func BenchmarkBitLen8(b *testing.B)  { benchmarkBitLenN(b, 8) }
+func BenchmarkBitLen9(b *testing.B)  { benchmarkBitLenN(b, 9) }
+func BenchmarkBitLen16(b *testing.B) { benchmarkBitLenN(b, 16) }
+func BenchmarkBitLen17(b *testing.B) { benchmarkBitLenN(b, 17) }
+func BenchmarkBitLen31(b *testing.B) { benchmarkBitLenN(b, 31) }
diff --git a/src/cmd/compile/internal/big/bits_test.go b/src/cmd/compile/internal/big/bits_test.go
new file mode 100644
index 0000000..985b60b
--- /dev/null
+++ b/src/cmd/compile/internal/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.8p+1"},
+		{Bits{1}, "0x.8p+2"},
+		{Bits{-1}, "0x.8p+0"},
+		{Bits{63}, "0x.8p+64"},
+		{Bits{33, -30}, "0x.8000000000000001p+34"},
+		{Bits{255, 0}, "0x.8000000000000000000000000000000000000000000000000000000000000001p+256"},
+
+		// multiple equal bit numbers
+		{Bits{0, 0}, "0x.8p+2"},
+		{Bits{0, 0, 0, 0}, "0x.8p+3"},
+		{Bits{0, 1, 0}, "0x.8p+3"},
+		{append(Bits{2, 1, 0} /* 7 */, Bits{3, 1} /* 10 */ ...), "0x.88p+5" /* 17 */},
+	} {
+		f := test.bits.Float()
+		if got := f.Text('p', 0); got != test.want {
+			t.Errorf("setBits(%v) = %s; want %s", test.bits, got, test.want)
+		}
+	}
+}
diff --git a/src/cmd/compile/internal/big/calibrate_test.go b/src/cmd/compile/internal/big/calibrate_test.go
new file mode 100644
index 0000000..f69ffbf
--- /dev/null
+++ b/src/cmd/compile/internal/big/calibrate_test.go
@@ -0,0 +1,88 @@
+// 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.
+
+// This file prints execution times for the Mul benchmark
+// given different Karatsuba thresholds. The result may be
+// used to manually fine-tune the threshold constant. The
+// results are somewhat fragile; use repeated runs to get
+// a clear picture.
+
+// Usage: go test -run=TestCalibrate -calibrate
+
+package big
+
+import (
+	"flag"
+	"fmt"
+	"testing"
+	"time"
+)
+
+var calibrate = flag.Bool("calibrate", false, "run calibration test")
+
+func karatsubaLoad(b *testing.B) {
+	BenchmarkMul(b)
+}
+
+// measureKaratsuba returns the time to run a Karatsuba-relevant benchmark
+// given Karatsuba threshold th.
+func measureKaratsuba(th int) time.Duration {
+	th, karatsubaThreshold = karatsubaThreshold, th
+	res := testing.Benchmark(karatsubaLoad)
+	karatsubaThreshold = th
+	return time.Duration(res.NsPerOp())
+}
+
+func computeThresholds() {
+	fmt.Printf("Multiplication times for varying Karatsuba thresholds\n")
+	fmt.Printf("(run repeatedly for good results)\n")
+
+	// determine Tk, the work load execution time using basic multiplication
+	Tb := measureKaratsuba(1e9) // th == 1e9 => Karatsuba multiplication disabled
+	fmt.Printf("Tb = %10s\n", Tb)
+
+	// thresholds
+	th := 4
+	th1 := -1
+	th2 := -1
+
+	var deltaOld time.Duration
+	for count := -1; count != 0 && th < 128; count-- {
+		// determine Tk, the work load execution time using Karatsuba multiplication
+		Tk := measureKaratsuba(th)
+
+		// improvement over Tb
+		delta := (Tb - Tk) * 100 / Tb
+
+		fmt.Printf("th = %3d  Tk = %10s  %4d%%", th, Tk, delta)
+
+		// determine break-even point
+		if Tk < Tb && th1 < 0 {
+			th1 = th
+			fmt.Print("  break-even point")
+		}
+
+		// determine diminishing return
+		if 0 < delta && delta < deltaOld && th2 < 0 {
+			th2 = th
+			fmt.Print("  diminishing return")
+		}
+		deltaOld = delta
+
+		fmt.Println()
+
+		// trigger counter
+		if th1 >= 0 && th2 >= 0 && count < 0 {
+			count = 10 // this many extra measurements after we got both thresholds
+		}
+
+		th++
+	}
+}
+
+func TestCalibrate(t *testing.T) {
+	if *calibrate {
+		computeThresholds()
+	}
+}
diff --git a/src/cmd/compile/internal/big/decimal.go b/src/cmd/compile/internal/big/decimal.go
new file mode 100644
index 0000000..2595e5f
--- /dev/null
+++ b/src/cmd/compile/internal/big/decimal.go
@@ -0,0 +1,264 @@
+// 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 multi-precision decimal numbers.
+// The implementation is for float to decimal conversion only;
+// not general purpose use.
+// The only operations are precise conversion from binary to
+// decimal and rounding.
+//
+// The key observation and some code (shr) is borrowed from
+// strconv/decimal.go: conversion of binary fractional values can be done
+// precisely in multi-precision decimal because 2 divides 10 (required for
+// >> of mantissa); but conversion of decimal floating-point values cannot
+// be done precisely in binary representation.
+//
+// In contrast to strconv/decimal.go, only right shift is implemented in
+// decimal format - left shift can be done precisely in binary format.
+
+package big
+
+// A decimal represents an unsigned floating-point number in decimal representation.
+// The value of a non-zero decimal x is x.mant * 10 ** x.exp with 0.5 <= x.mant < 1,
+// with the most-significant mantissa digit at index 0. For the zero decimal, the
+// mantissa length and exponent are 0.
+// The zero value for decimal represents a ready-to-use 0.0.
+type decimal struct {
+	mant []byte // mantissa ASCII digits, big-endian
+	exp  int    // exponent
+}
+
+// Maximum shift amount that can be done in one pass without overflow.
+// A Word has _W bits and (1<<maxShift - 1)*10 + 9 must fit into Word.
+const maxShift = _W - 4
+
+// TODO(gri) Since we know the desired decimal precision when converting
+// a floating-point number, we may be able to limit the number of decimal
+// digits that need to be computed by init by providing an additional
+// 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) {
+	// special case 0
+	if len(m) == 0 {
+		x.mant = x.mant[:0]
+		x.exp = 0
+		return
+	}
+
+	// Optimization: If we need to shift right, first remove any trailing
+	// zero bits from m to reduce shift amount that needs to be done in
+	// decimal format (since that is likely slower).
+	if shift < 0 {
+		ntz := m.trailingZeroBits()
+		s := uint(-shift)
+		if s >= ntz {
+			s = ntz // shift at most ntz bits
+		}
+		m = nat(nil).shr(m, s)
+		shift += int(s)
+	}
+
+	// Do any shift left in binary representation.
+	if shift > 0 {
+		m = nat(nil).shl(m, uint(shift))
+		shift = 0
+	}
+
+	// Convert mantissa into decimal representation.
+	s := m.decimalString() // TODO(gri) avoid string conversion here
+	n := len(s)
+	x.exp = n
+	// Trim trailing zeros; instead the exponent is tracking
+	// the decimal point independent of the number of digits.
+	for n > 0 && s[n-1] == '0' {
+		n--
+	}
+	x.mant = append(x.mant[:0], s[:n]...)
+
+	// Do any (remaining) shift right in decimal representation.
+	if shift < 0 {
+		for shift < -maxShift {
+			shr(x, maxShift)
+			shift += maxShift
+		}
+		shr(x, uint(-shift))
+	}
+}
+
+// Possibly optimization: The current implementation of nat.string takes
+// a charset argument. When a right shift is needed, we could provide
+// "\x00\x01...\x09" instead of "012..9" (as in nat.decimalString) and
+// avoid the repeated +'0' and -'0' operations in decimal.shr (and do a
+// single +'0' pass at the end).
+
+// shr implements x >> s, for s <= maxShift.
+func shr(x *decimal, s uint) {
+	// Division by 1<<s using shift-and-subtract algorithm.
+
+	// pick up enough leading digits to cover first shift
+	r := 0 // read index
+	var n Word
+	for n>>s == 0 && r < len(x.mant) {
+		ch := Word(x.mant[r])
+		r++
+		n = n*10 + ch - '0'
+	}
+	if n == 0 {
+		// x == 0; shouldn't get here, but handle anyway
+		x.mant = x.mant[:0]
+		return
+	}
+	for n>>s == 0 {
+		r++
+		n *= 10
+	}
+	x.exp += 1 - r
+
+	// read a digit, write a digit
+	w := 0 // write index
+	for r < len(x.mant) {
+		ch := Word(x.mant[r])
+		r++
+		d := n >> s
+		n -= d << s
+		x.mant[w] = byte(d + '0')
+		w++
+		n = n*10 + ch - '0'
+	}
+
+	// write extra digits that still fit
+	for n > 0 && w < len(x.mant) {
+		d := n >> s
+		n -= d << s
+		x.mant[w] = byte(d + '0')
+		w++
+		n = n * 10
+	}
+	x.mant = x.mant[:w] // the number may be shorter (e.g. 1024 >> 10)
+
+	// append additional digits that didn't fit
+	for n > 0 {
+		d := n >> s
+		n -= d << s
+		x.mant = append(x.mant, byte(d+'0'))
+		n = n * 10
+	}
+
+	trim(x)
+}
+
+func (x *decimal) String() string {
+	if len(x.mant) == 0 {
+		return "0"
+	}
+
+	var buf []byte
+	switch {
+	case x.exp <= 0:
+		// 0.00ddd
+		buf = append(buf, "0."...)
+		buf = appendZeros(buf, -x.exp)
+		buf = append(buf, x.mant...)
+
+	case /* 0 < */ x.exp < len(x.mant):
+		// dd.ddd
+		buf = append(buf, x.mant[:x.exp]...)
+		buf = append(buf, '.')
+		buf = append(buf, x.mant[x.exp:]...)
+
+	default: // len(x.mant) <= x.exp
+		// ddd00
+		buf = append(buf, x.mant...)
+		buf = appendZeros(buf, x.exp-len(x.mant))
+	}
+
+	return string(buf)
+}
+
+// appendZeros appends n 0 digits to buf and returns buf.
+func appendZeros(buf []byte, n int) []byte {
+	for ; n > 0; n-- {
+		buf = append(buf, '0')
+	}
+	return buf
+}
+
+// shouldRoundUp reports if x should be rounded up
+// if shortened to n digits. n must be a valid index
+// for x.mant.
+func shouldRoundUp(x *decimal, n int) bool {
+	if x.mant[n] == '5' && n+1 == len(x.mant) {
+		// exactly halfway - round to even
+		return n > 0 && (x.mant[n-1]-'0')&1 != 0
+	}
+	// not halfway - digit tells all (x.mant has no trailing zeros)
+	return x.mant[n] >= '5'
+}
+
+// round sets x to (at most) n mantissa digits by rounding it
+// to the nearest even value with n (or fever) mantissa digits.
+// If n < 0, x remains unchanged.
+func (x *decimal) round(n int) {
+	if n < 0 || n >= len(x.mant) {
+		return // nothing to do
+	}
+
+	if shouldRoundUp(x, n) {
+		x.roundUp(n)
+	} else {
+		x.roundDown(n)
+	}
+}
+
+func (x *decimal) roundUp(n int) {
+	if n < 0 || n >= len(x.mant) {
+		return // nothing to do
+	}
+	// 0 <= n < len(x.mant)
+
+	// find first digit < '9'
+	for n > 0 && x.mant[n-1] >= '9' {
+		n--
+	}
+
+	if n == 0 {
+		// all digits are '9's => round up to '1' and update exponent
+		x.mant[0] = '1' // ok since len(x.mant) > n
+		x.mant = x.mant[:1]
+		x.exp++
+		return
+	}
+
+	// n > 0 && x.mant[n-1] < '9'
+	x.mant[n-1]++
+	x.mant = x.mant[:n]
+	// x already trimmed
+}
+
+func (x *decimal) roundDown(n int) {
+	if n < 0 || n >= len(x.mant) {
+		return // nothing to do
+	}
+	x.mant = x.mant[:n]
+	trim(x)
+}
+
+// trim cuts off any trailing zeros from x's mantissa;
+// they are meaningless for the value of x.
+func trim(x *decimal) {
+	i := len(x.mant)
+	for i > 0 && x.mant[i-1] == '0' {
+		i--
+	}
+	x.mant = x.mant[:i]
+	if i == 0 {
+		x.exp = 0
+	}
+}
diff --git a/src/cmd/compile/internal/big/decimal_test.go b/src/cmd/compile/internal/big/decimal_test.go
new file mode 100644
index 0000000..81e022a
--- /dev/null
+++ b/src/cmd/compile/internal/big/decimal_test.go
@@ -0,0 +1,106 @@
+// 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
+
+import "testing"
+
+func TestDecimalString(t *testing.T) {
+	for _, test := range []struct {
+		x    decimal
+		want string
+	}{
+		{want: "0"},
+		{decimal{nil, 1000}, "0"}, // exponent of 0 is ignored
+		{decimal{[]byte("12345"), 0}, "0.12345"},
+		{decimal{[]byte("12345"), -3}, "0.00012345"},
+		{decimal{[]byte("12345"), +3}, "123.45"},
+		{decimal{[]byte("12345"), +10}, "1234500000"},
+	} {
+		if got := test.x.String(); got != test.want {
+			t.Errorf("%v == %s; want %s", test.x, got, test.want)
+		}
+	}
+}
+
+func TestDecimalInit(t *testing.T) {
+	for _, test := range []struct {
+		x     Word
+		shift int
+		want  string
+	}{
+		{0, 0, "0"},
+		{0, -100, "0"},
+		{0, 100, "0"},
+		{1, 0, "1"},
+		{1, 10, "1024"},
+		{1, 100, "1267650600228229401496703205376"},
+		{1, -100, "0.0000000000000000000000000000007888609052210118054117285652827862296732064351090230047702789306640625"},
+		{12345678, 8, "3160493568"},
+		{12345678, -8, "48225.3046875"},
+		{195312, 9, "99999744"},
+		{1953125, 9, "1000000000"},
+	} {
+		var d decimal
+		d.init(nat{test.x}.norm(), test.shift)
+		if got := d.String(); got != test.want {
+			t.Errorf("%d << %d == %s; want %s", test.x, test.shift, got, test.want)
+		}
+	}
+}
+
+func TestDecimalRounding(t *testing.T) {
+	for _, test := range []struct {
+		x              uint64
+		n              int
+		down, even, up string
+	}{
+		{0, 0, "0", "0", "0"},
+		{0, 1, "0", "0", "0"},
+
+		{1, 0, "0", "0", "10"},
+		{5, 0, "0", "0", "10"},
+		{9, 0, "0", "10", "10"},
+
+		{15, 1, "10", "20", "20"},
+		{45, 1, "40", "40", "50"},
+		{95, 1, "90", "100", "100"},
+
+		{12344999, 4, "12340000", "12340000", "12350000"},
+		{12345000, 4, "12340000", "12340000", "12350000"},
+		{12345001, 4, "12340000", "12350000", "12350000"},
+		{23454999, 4, "23450000", "23450000", "23460000"},
+		{23455000, 4, "23450000", "23460000", "23460000"},
+		{23455001, 4, "23450000", "23460000", "23460000"},
+
+		{99994999, 4, "99990000", "99990000", "100000000"},
+		{99995000, 4, "99990000", "100000000", "100000000"},
+		{99999999, 4, "99990000", "100000000", "100000000"},
+
+		{12994999, 4, "12990000", "12990000", "13000000"},
+		{12995000, 4, "12990000", "13000000", "13000000"},
+		{12999999, 4, "12990000", "13000000", "13000000"},
+	} {
+		x := nat(nil).setUint64(test.x)
+
+		var d decimal
+		d.init(x, 0)
+		d.roundDown(test.n)
+		if got := d.String(); got != test.down {
+			t.Errorf("roundDown(%d, %d) = %s; want %s", test.x, test.n, got, test.down)
+		}
+
+		d.init(x, 0)
+		d.round(test.n)
+		if got := d.String(); got != test.even {
+			t.Errorf("round(%d, %d) = %s; want %s", test.x, test.n, got, test.even)
+		}
+
+		d.init(x, 0)
+		d.roundUp(test.n)
+		if got := d.String(); got != test.up {
+			t.Errorf("roundUp(%d, %d) = %s; want %s", test.x, test.n, got, test.up)
+		}
+	}
+}
diff --git a/src/cmd/compile/internal/big/example_test.go b/src/cmd/compile/internal/big/example_test.go
new file mode 100644
index 0000000..cb91bc2
--- /dev/null
+++ b/src/cmd/compile/internal/big/example_test.go
@@ -0,0 +1,51 @@
+// 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.
+
+package big_test
+
+import (
+	"cmd/compile/internal/big"
+	"fmt"
+	"log"
+)
+
+func ExampleRat_SetString() {
+	r := new(big.Rat)
+	r.SetString("355/113")
+	fmt.Println(r.FloatString(3))
+	// Output: 3.142
+}
+
+func ExampleInt_SetString() {
+	i := new(big.Int)
+	i.SetString("644", 8) // octal
+	fmt.Println(i)
+	// Output: 420
+}
+
+func ExampleRat_Scan() {
+	// The Scan function is rarely used directly;
+	// the fmt package recognizes it as an implementation of fmt.Scanner.
+	r := new(big.Rat)
+	_, err := fmt.Sscan("1.5000", r)
+	if err != nil {
+		log.Println("error scanning value:", err)
+	} else {
+		fmt.Println(r)
+	}
+	// Output: 3/2
+}
+
+func ExampleInt_Scan() {
+	// The Scan function is rarely used directly;
+	// the fmt package recognizes it as an implementation of fmt.Scanner.
+	i := new(big.Int)
+	_, err := fmt.Sscan("18446744073709551617", i)
+	if err != nil {
+		log.Println("error scanning value:", err)
+	} else {
+		fmt.Println(i)
+	}
+	// Output: 18446744073709551617
+}
diff --git a/src/cmd/compile/internal/big/float.go b/src/cmd/compile/internal/big/float.go
new file mode 100644
index 0000000..d7aa895
--- /dev/null
+++ b/src/cmd/compile/internal/big/float.go
@@ -0,0 +1,1693 @@
+// 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.
+
+// This file implements multi-precision floating-point numbers.
+// Like in the GNU MPFR library (http://www.mpfr.org/), operands
+// can be of mixed precision. Unlike MPFR, the rounding mode is
+// not specified with each operation, but with each operand. The
+// rounding mode of the result operand determines the rounding
+// mode of an operation. This is a from-scratch implementation.
+
+package big
+
+import (
+	"fmt"
+	"math"
+)
+
+const debugFloat = false // enable for debugging
+
+// 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.
+// 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.
+//
+// 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 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 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
+}
+
+// An ErrNaN panic is raised by a Float operation that would lead to
+// a NaN under IEEE-754 rules. An ErrNaN implements the error interface.
+type ErrNaN struct {
+	msg string
+}
+
+func (err ErrNaN) Error() string {
+	return err.msg
+}
+
+// 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
+	MinExp  = math.MinInt32  // smallest supported exponent
+	MaxPrec = math.MaxUint32 // largest (theoretically) supported precision; likely memory-limited
+)
+
+// 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.
+//
+// A zero or non-finite Float x ignores x.mant and x.exp.
+//
+// x                 form      neg      mant         exp
+// ----------------------------------------------------------
+// ±0                zero      sign     -            -
+// 0 < |x| < +Inf    finite    sign     mantissa     exponent
+// ±Inf              inf       sign     -            -
+
+// A form value describes the internal representation.
+type form byte
+
+// The form value order is relevant - do not change!
+const (
+	zero form = iota
+	finite
+	inf
+)
+
+// 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 byte
+
+// The following rounding modes are supported.
+const (
+	ToNearestEven RoundingMode = iota // == IEEE 754-2008 roundTiesToEven
+	ToNearestAway                     // == IEEE 754-2008 roundTiesToAway
+	ToZero                            // == IEEE 754-2008 roundTowardZero
+	AwayFromZero                      // no IEEE 754-2008 equivalent
+	ToNegativeInf                     // == IEEE 754-2008 roundTowardNegative
+	ToPositiveInf                     // == IEEE 754-2008 roundTowardPositive
+)
+
+//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.
+// 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
+
+	// special case
+	if prec == 0 {
+		z.prec = 0
+		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
+	}
+	old := z.prec
+	z.prec = uint32(prec)
+	if z.prec < old {
+		z.round(0)
+	}
+	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.mode = mode
+	z.acc = Exact
+	return z
+}
+
+// Prec returns the mantissa precision of x in bits.
+// 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 |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()
+}
+
+// Mode returns the rounding mode of x.
+func (x *Float) Mode() RoundingMode {
+	return x.mode
+}
+
+// Acc returns the accuracy of x produced by the most recent operation.
+func (x *Float) Acc() Accuracy {
+	return x.acc
+}
+
+// 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(mant) = 0, with mant set to   ±0
+//	(±Inf).MantExp(mant) = 0, with mant set to ±Inf
+//
+// 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()
+	}
+	if x.form == finite {
+		exp = int(x.exp)
+	}
+	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:
+//
+//	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 z.form != finite {
+		return z
+	}
+	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 values are not integers.
+func (x *Float) IsInt() bool {
+	if debugFloat {
+		x.validate()
+	}
+	// special cases
+	if x.form != finite {
+		return x.form == zero
+	}
+	// x.form == finite
+	if x.exp <= 0 {
+		return false
+	}
+	// x.exp > 0
+	return x.prec <= uint32(x.exp) || x.MinPrec() <= uint(x.exp) // not enough bits for fractional mantissa
+}
+
+// debugging support
+func (x *Float) validate() {
+	if !debugFloat {
+		// avoid performance bugs
+		panic("validate called but debugFloat is not set")
+	}
+	if x.form != finite {
+		return
+	}
+	m := len(x.mant)
+	if m == 0 {
+		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.Text('p', 0)))
+	}
+	if x.prec == 0 {
+		panic("zero precision finite number")
+	}
+}
+
+// round rounds z according to z.mode to z.prec bits and sets z.acc accordingly.
+// sbit must be 0 or 1 and summarizes any "sticky bit" information one might
+// have before calling round. z's mantissa must be normalized (with the msb set)
+// or empty.
+//
+// CAUTION: The rounding modes ToNegativeInf, ToPositiveInf are affected by the
+// sign of z. For correct rounding, the sign of z must be set correctly before
+// calling round.
+func (z *Float) round(sbit uint) {
+	if debugFloat {
+		z.validate()
+	}
+
+	z.acc = Exact
+	if z.form != finite {
+		// ±0 or ±Inf => nothing left to do
+		return
+	}
+	// z.form == finite && len(z.mant) > 0
+	// m > 0 implies z.prec > 0 (checked by validate)
+
+	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
+	}
+	// bits > z.prec
+
+	n := (z.prec + (_W - 1)) / _W // mantissa length in words for desired precision
+
+	// Rounding is based on two bits: the rounding bit (rbit) and the
+	// sticky bit (sbit). The rbit is the bit immediately before the
+	// z.prec leading mantissa bits (the "0.5"). The sbit is set if any
+	// of the bits before the rbit are set (the "0.25", "0.125", etc.):
+	//
+	//   rbit  sbit  => "fractional part"
+	//
+	//   0     0        == 0
+	//   0     1        >  0  , < 0.5
+	//   1     0        == 0.5
+	//   1     1        >  0.5, < 1.0
+
+	// bits > z.prec: mantissa too large => round
+	r := uint(bits - z.prec - 1) // rounding bit position; r >= 0
+	rbit := z.mant.bit(r)        // rounding bit
+	if sbit == 0 {
+		sbit = z.mant.sticky(r)
+	}
+	if debugFloat && sbit&^1 != 0 {
+		panic(fmt.Sprintf("invalid sbit %#x", sbit))
+	}
+
+	// convert ToXInf rounding modes
+	mode := z.mode
+	switch mode {
+	case ToNegativeInf:
+		mode = ToZero
+		if z.neg {
+			mode = AwayFromZero
+		}
+	case ToPositiveInf:
+		mode = AwayFromZero
+		if z.neg {
+			mode = ToZero
+		}
+	}
+
+	// cut off extra words
+	if m > n {
+		copy(z.mant, z.mant[m-n:]) // move n last words to front
+		z.mant = z.mant[:n]
+	}
+
+	// determine number of trailing zero bits t
+	t := n*_W - z.prec // 0 <= t < _W
+	lsb := Word(1) << t
+
+	// make rounding decision
+	// TODO(gri) This can be simplified (see Bits.round in bits_test.go).
+	switch mode {
+	case ToZero:
+		// nothing to do
+	case ToNearestEven, ToNearestAway:
+		if rbit == 0 {
+			// rounding bits == 0b0x
+			mode = ToZero
+		} else if sbit == 1 {
+			// rounding bits == 0b11
+			mode = AwayFromZero
+		}
+	case AwayFromZero:
+		if rbit|sbit == 0 {
+			mode = ToZero
+		}
+	default:
+		// ToXInf modes have been converted to ToZero or AwayFromZero
+		panic("unreachable")
+	}
+
+	// round and determine accuracy
+	switch mode {
+	case ToZero:
+		if rbit|sbit != 0 {
+			z.acc = Below
+		}
+
+	case ToNearestEven, ToNearestAway:
+		if debugFloat && rbit != 1 {
+			panic("internal error in rounding")
+		}
+		if mode == ToNearestEven && sbit == 0 && z.mant[0]&lsb == 0 {
+			z.acc = Below
+			break
+		}
+		// mode == ToNearestAway || sbit == 1 || z.mant[0]&lsb != 0
+		fallthrough
+
+	case AwayFromZero:
+		// add 1 to mantissa
+		if addVW(z.mant, z.mant, lsb) != 0 {
+			// overflow => shift mantissa right by 1 and add msb
+			shrVU(z.mant, z.mant, 1)
+			z.mant[n-1] |= 1 << (_W - 1)
+			// adjust exponent
+			if z.exp < MaxExp {
+				z.exp++
+			} else {
+				// exponent overflow
+				z.acc = makeAcc(!z.neg)
+				z.form = inf
+				return
+			}
+		}
+		z.acc = Above
+	}
+
+	// zero out trailing bits in least-significant word
+	z.mant[0] &^= lsb - 1
+
+	// update accuracy
+	if z.acc != Exact && z.neg {
+		z.acc = -z.acc
+	}
+
+	if debugFloat {
+		z.validate()
+	}
+
+	return
+}
+
+func (z *Float) setBits64(neg bool, x uint64) *Float {
+	if z.prec == 0 {
+		z.prec = 64
+	}
+	z.acc = Exact
+	z.neg = neg
+	if x == 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
+	if z.prec < 64 {
+		z.round(0)
+	}
+	return z
+}
+
+// SetUint64 sets z to the (possibly rounded) value of x and returns z.
+// If z's precision is 0, it is changed to 64 (and rounding will have
+// no effect).
+func (z *Float) SetUint64(x uint64) *Float {
+	return z.setBits64(false, x)
+}
+
+// SetInt64 sets z to the (possibly rounded) value of x and returns z.
+// If z's precision is 0, it is changed to 64 (and rounding will have
+// no effect).
+func (z *Float) SetInt64(x int64) *Float {
+	u := x
+	if u < 0 {
+		u = -u
+	}
+	// We cannot simply call z.SetUint64(uint64(u)) and change
+	// the sign afterwards because the sign affects rounding.
+	return z.setBits64(x < 0, uint64(u))
+}
+
+// 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). 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, -Inf correctly
+	if x == 0 {
+		z.form = zero
+		return z
+	}
+	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
+	if z.prec < 53 {
+		z.round(0)
+	}
+	return z
+}
+
+// fnorm normalizes mantissa m by shifting it to the left
+// such that the msb of the most-significant word (msw) is 1.
+// It returns the shift amount. It assumes that len(m) != 0.
+func fnorm(m nat) int64 {
+	if debugFloat && (len(m) == 0 || m[len(m)-1] == 0) {
+		panic("msw of mantissa is 0")
+	}
+	s := nlz(m[len(m)-1])
+	if s > 0 {
+		c := shlVU(m, m, s)
+		if debugFloat && c != 0 {
+			panic("nlz or shlVU incorrect")
+		}
+	}
+	return int64(s)
+}
+
+// SetInt sets z to the (possibly rounded) value of x and returns z.
+// If z's precision is 0, it is changed to the larger of x.BitLen()
+// or 64 (and rounding will have no effect).
+func (z *Float) SetInt(x *Int) *Float {
+	// TODO(gri) can be more efficient if z.prec > 0
+	// but small compared to the size of x, or if there
+	// are many trailing 0's.
+	bits := uint32(x.BitLen())
+	if z.prec == 0 {
+		z.prec = umax32(bits, 64)
+	}
+	z.acc = Exact
+	z.neg = x.neg
+	if len(x.abs) == 0 {
+		z.form = zero
+		return z
+	}
+	// x != 0
+	z.mant = z.mant.set(x.abs)
+	fnorm(z.mant)
+	z.setExpAndRound(int64(bits), 0)
+	return z
+}
+
+// SetRat sets z to the (possibly rounded) value of x and returns z.
+// If z's precision is 0, it is changed to the largest of a.BitLen(),
+// b.BitLen(), or 64; with x = a/b.
+func (z *Float) SetRat(x *Rat) *Float {
+	if x.IsInt() {
+		return z.SetInt(x.Num())
+	}
+	var a, b Float
+	a.SetInt(x.Num())
+	b.SetInt(x.Denom())
+	if z.prec == 0 {
+		z.prec = umax32(a.prec, b.prec)
+	}
+	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).
+// 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.
+func (z *Float) Set(x *Float) *Float {
+	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
+		} else if z.prec < x.prec {
+			z.round(0)
+		}
+	}
+	return 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 {
+	if debugFloat {
+		x.validate()
+	}
+	if z != x {
+		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
+}
+
+// msb32 returns the 32 most significant bits of x.
+func msb32(x nat) uint32 {
+	i := len(x) - 1
+	if i < 0 {
+		return 0
+	}
+	if debugFloat && x[i]&(1<<(_W-1)) == 0 {
+		panic("x not normalized")
+	}
+	switch _W {
+	case 32:
+		return uint32(x[i])
+	case 64:
+		return uint32(x[i] >> 32)
+	}
+	panic("unreachable")
+}
+
+// msb64 returns the 64 most significant bits of x.
+func msb64(x nat) uint64 {
+	i := len(x) - 1
+	if i < 0 {
+		return 0
+	}
+	if debugFloat && x[i]&(1<<(_W-1)) == 0 {
+		panic("x not normalized")
+	}
+	switch _W {
+	case 32:
+		v := uint64(x[i]) << 32
+		if i > 0 {
+			v |= uint64(x[i-1])
+		}
+		return v
+	case 64:
+		return uint64(x[i])
+	}
+	panic("unreachable")
+}
+
+// Uint64 returns the unsigned integer resulting from truncating x
+// towards zero. If 0 <= x <= math.MaxUint64, the result is Exact
+// if x is an integer and Below otherwise.
+// The result is (0, Above) for x < 0, and (math.MaxUint64, Below)
+// for x > math.MaxUint64.
+func (x *Float) Uint64() (uint64, Accuracy) {
+	if debugFloat {
+		x.validate()
+	}
+
+	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
+		if x.exp <= 64 {
+			// u = trunc(x) fits into a uint64
+			u := msb64(x.mant) >> (64 - uint32(x.exp))
+			if x.MinPrec() <= 64 {
+				return u, Exact
+			}
+			return u, Below // x truncated
+		}
+		// 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.
+func (x *Float) Int64() (int64, Accuracy) {
+	if debugFloat {
+		x.validate()
+	}
+
+	switch x.form {
+	case finite:
+		// 0 < |x| < +Inf
+		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)
+			i := int64(msb64(x.mant) >> (64 - uint32(x.exp)))
+			if x.neg {
+				i = -i
+			}
+			if x.MinPrec() <= uint(x.exp) {
+				return i, Exact
+			}
+			return i, acc // x truncated
+		}
+		if x.neg {
+			// check for special case x == math.MinInt64 (i.e., x == -(0.5 << 64))
+			if x.exp == 64 && x.MinPrec() == 1 {
+				acc = Exact
+			}
+			return math.MinInt64, acc
+		}
+		// 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")
+}
+
+// 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 mantissa m is 0.5 <= m < 1.0; compute exponent for floatxx mantissa.
+		e := x.exp - 1 // exponent for mantissa m with 1.0 <= m < 2.0
+		p := mbits + 1 // precision of normal float
+
+		// If the exponent is too small, we may have a denormal number
+		// in which case we have fewer mantissa bits available: reduce
+		// precision accordingly.
+		if e < emin {
+			p -= emin - int(e)
+			// Make sure we have at least 1 bit so that we don't
+			// lose numbers rounded up to the smallest denormal.
+			if p < 1 {
+				p = 1
+			}
+		}
+
+		// round
+		var r Float
+		r.prec = uint32(p)
+		r.Set(x)
+		e = r.exp - 1
+
+		// Rounding may have caused r to overflow to ±Inf
+		// (rounding never causes underflows to 0).
+		if r.form == inf {
+			e = emax + 1 // cause overflow below
+		}
+
+		// If the exponent is too large, overflow to ±Inf.
+		if e > emax {
+			// overflow
+			if x.neg {
+				return float32(math.Inf(-1)), Below
+			}
+			return float32(math.Inf(+1)), Above
+		}
+		// e <= emax
+
+		// Determine sign, biased exponent, and mantissa.
+		var sign, bexp, mant uint32
+		if x.neg {
+			sign = 1 << (fbits - 1)
+		}
+
+		// Rounding may have caused a denormal number to
+		// become normal. Check again.
+		if e < emin {
+			// denormal number
+			if e < dmin {
+				// underflow to ±0
+				if x.neg {
+					var z float32
+					return -z, Above
+				}
+				return 0.0, Below
+			}
+			// bexp = 0
+			mant = msb32(r.mant) >> (fbits - r.prec)
+		} else {
+			// normal number: emin <= e <= emax
+			bexp = uint32(e+bias) << mbits
+			mant = msb32(r.mant) >> ebits & (1<<mbits - 1) // cut off msb (implicit 1 bit)
+		}
+
+		return math.Float32frombits(sign | bexp | mant), 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
+	}
+
+	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()
+	}
+
+	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 mantissa m is 0.5 <= m < 1.0; compute exponent for floatxx mantissa.
+		e := x.exp - 1 // exponent for mantissa m with 1.0 <= m < 2.0
+		p := mbits + 1 // precision of normal float
+
+		// If the exponent is too small, we may have a denormal number
+		// in which case we have fewer mantissa bits available: reduce
+		// precision accordingly.
+		if e < emin {
+			p -= emin - int(e)
+			// Make sure we have at least 1 bit so that we don't
+			// lose numbers rounded up to the smallest denormal.
+			if p < 1 {
+				p = 1
+			}
+		}
+
+		// round
+		var r Float
+		r.prec = uint32(p)
+		r.Set(x)
+		e = r.exp - 1
+
+		// Rounding may have caused r to overflow to ±Inf
+		// (rounding never causes underflows to 0).
+		if r.form == inf {
+			e = emax + 1 // cause overflow below
+		}
+
+		// If the exponent is too large, overflow to ±Inf.
+		if e > emax {
+			// overflow
+			if x.neg {
+				return math.Inf(-1), Below
+			}
+			return math.Inf(+1), Above
+		}
+		// e <= emax
+
+		// Determine sign, biased exponent, and mantissa.
+		var sign, bexp, mant uint64
+		if x.neg {
+			sign = 1 << (fbits - 1)
+		}
+
+		// Rounding may have caused a denormal number to
+		// become normal. Check again.
+		if e < emin {
+			// denormal number
+			if e < dmin {
+				// underflow to ±0
+				if x.neg {
+					var z float64
+					return -z, Above
+				}
+				return 0.0, Below
+			}
+			// bexp = 0
+			mant = msb64(r.mant) >> (fbits - r.prec)
+		} else {
+			// normal number: emin <= e <= emax
+			bexp = uint64(e+bias) << mbits
+			mant = msb64(r.mant) >> ebits & (1<<mbits - 1) // cut off msb (implicit 1 bit)
+		}
+
+		return math.Float64frombits(sign | bexp | mant), 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
+	}
+
+	panic("unreachable")
+}
+
+// Int returns the result of truncating x towards zero;
+// or nil if x is an infinity.
+// The result is Exact if x.IsInt(); otherwise it is Below
+// for x > 0, and Above for x < 0.
+// If a non-nil *Int argument z is provided, Int stores
+// the result in z instead of allocating a new Int.
+func (x *Float) Int(z *Int) (*Int, Accuracy) {
+	if debugFloat {
+		x.validate()
+	}
+
+	if z == nil && x.form <= finite {
+		z = new(Int)
+	}
+
+	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)
+	}
+
+	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, Accuracy) {
+	if debugFloat {
+		x.validate()
+	}
+
+	if z == nil && x.form <= finite {
+		z = new(Rat)
+	}
+
+	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)
+// and returns z.
+func (z *Float) Abs(x *Float) *Float {
+	z.Set(x)
+	z.neg = false
+	return z
+}
+
+// Neg sets z to the (possibly rounded) value of x with its sign negated,
+// and returns z.
+func (z *Float) Neg(x *Float) *Float {
+	z.Set(x)
+	z.neg = !z.neg
+	return z
+}
+
+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
+	// differ by wide margins. The following article describes
+	// an efficient (but much more complicated) implementation
+	// compatible with the internal representation used here:
+	//
+	// Vincent Lefèvre: "The Generic Multiple-Precision Floating-
+	// Point Addition With Exact Rounding (as in the MPFR Library)"
+	// http://www.vinc17.net/research/papers/rnc6.pdf
+
+	if debugFloat {
+		validateBinaryOperands(x, y)
+	}
+
+	// compute exponents ex, ey for mantissa with "binary point"
+	// on the right (mantissa.0) - use int64 to avoid overflow
+	ex := int64(x.exp) - int64(len(x.mant))*_W
+	ey := int64(y.exp) - int64(len(y.mant))*_W
+
+	// TODO(gri) having a combined add-and-shift primitive
+	//           could make this code significantly faster
+	switch {
+	case ex < ey:
+		// cannot re-use z.mant w/o testing for aliasing
+		t := nat(nil).shl(y.mant, uint(ey-ex))
+		z.mant = z.mant.add(x.mant, t)
+	default:
+		// ex == ey, no shift needed
+		z.mant = z.mant.add(x.mant, y.mant)
+	case ex > ey:
+		// cannot re-use z.mant w/o testing for aliasing
+		t := nat(nil).shl(x.mant, uint(ex-ey))
+		z.mant = z.mant.add(t, y.mant)
+		ex = ey
+	}
+	// len(z.mant) > 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 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 {
+		validateBinaryOperands(x, y)
+	}
+
+	ex := int64(x.exp) - int64(len(x.mant))*_W
+	ey := int64(y.exp) - int64(len(y.mant))*_W
+
+	switch {
+	case ex < ey:
+		// cannot re-use z.mant w/o testing for aliasing
+		t := nat(nil).shl(y.mant, uint(ey-ex))
+		z.mant = t.sub(x.mant, t)
+	default:
+		// ex == ey, no shift needed
+		z.mant = z.mant.sub(x.mant, y.mant)
+	case ex > ey:
+		// cannot re-use z.mant w/o testing for aliasing
+		t := nat(nil).shl(x.mant, uint(ex-ey))
+		z.mant = t.sub(t, y.mant)
+		ex = ey
+	}
+
+	// operands may have cancelled each other out
+	if len(z.mant) == 0 {
+		z.acc = Exact
+		z.form = zero
+		z.neg = false
+		return
+	}
+	// len(z.mant) > 0
+
+	z.setExpAndRound(ex+int64(len(z.mant))*_W-fnorm(z.mant), 0)
+}
+
+// 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 {
+		validateBinaryOperands(x, y)
+	}
+
+	// Note: This is doing too much work if the precision
+	// of z is less than the sum of the precisions of x
+	// and y which is often the case (e.g., if all floats
+	// have the same precision).
+	// TODO(gri) Optimize this for the common case.
+
+	e := int64(x.exp) + int64(y.exp)
+	z.mant = z.mant.mul(x.mant, y.mant)
+
+	z.setExpAndRound(e-fnorm(z.mant), 0)
+}
+
+// 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 {
+		validateBinaryOperands(x, y)
+	}
+
+	// mantissa length in words for desired result precision + 1
+	// (at least one extra bit so we get the rounding bit after
+	// the division)
+	n := int(z.prec/_W) + 1
+
+	// compute adjusted x.mant such that we get enough result precision
+	xadj := x.mant
+	if d := n - len(x.mant) + len(y.mant); d > 0 {
+		// d extra words needed => add d "0 digits" to x
+		xadj = make(nat, len(x.mant)+d)
+		copy(xadj[d:], x.mant)
+	}
+	// TODO(gri): If we have too many digits (d < 0), we should be able
+	// to shorten x for faster division. But we must be extra careful
+	// with rounding in that case.
+
+	// Compute d before division since there may be aliasing of x.mant
+	// (via xadj) or y.mant with z.mant.
+	d := len(xadj) - len(y.mant)
+
+	// divide
+	var r nat
+	z.mant, r = z.mant.div(nil, xadj, y.mant)
+	e := int64(x.exp) - int64(y.exp) - int64(d-len(z.mant))*_W
+
+	// 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
+	// zero, it couldn't have a non-zero remainder).
+	var sbit uint
+	if len(r) > 0 {
+		sbit = 1
+	}
+
+	z.setExpAndRound(e-fnorm(z.mant), sbit)
+}
+
+// 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 {
+		validateBinaryOperands(x, y)
+	}
+
+	switch {
+	case x.exp < y.exp:
+		return -1
+	case x.exp > y.exp:
+		return +1
+	}
+	// x.exp == y.exp
+
+	// compare mantissas
+	i := len(x.mant)
+	j := len(y.mant)
+	for i > 0 || j > 0 {
+		var xm, ym Word
+		if i > 0 {
+			i--
+			xm = x.mant[i]
+		}
+		if j > 0 {
+			j--
+			ym = y.mant[j]
+		}
+		switch {
+		case xm < ym:
+			return -1
+		case xm > ym:
+			return +1
+		}
+	}
+
+	return 0
+}
+
+// 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,
+// or of a difference x−y regarded as a sum x+(−y), differs from at most
+// one of the addends’ signs; and the sign of the result of conversions,
+// the quantize operation, the roundToIntegral operations, and the
+// roundToIntegralExact (see 5.3.1) is the sign of the first or only operand.
+// These rules shall apply even when operands or results are zero or infinite.
+//
+// When the sum of two operands with opposite signs (or the difference of
+// two operands with like signs) is exactly zero, the sign of that sum (or
+// difference) shall be +0 in all rounding-direction attributes except
+// 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: https://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)
+// result. Add panics with ErrNaN if x and y are infinities with opposite
+// signs. The value of z is undefined in that case.
+//
+// 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 {
+		x.validate()
+		y.validate()
+	}
+
+	if z.prec == 0 {
+		z.prec = umax32(x.prec, y.prec)
+	}
+
+	if x.form == finite && y.form == finite {
+		// x + y (commom case)
+		z.neg = x.neg
+		if x.neg == y.neg {
+			// x + y == x + y
+			// (-x) + (-y) == -(x + y)
+			z.uadd(x, y)
+		} else {
+			// x + (-y) == x - y == -(y - x)
+			// (-x) + y == y - x == -(x - y)
+			if x.ucmp(y) > 0 {
+				z.usub(x, y)
+			} else {
+				z.neg = !z.neg
+				z.usub(y, x)
+			}
+		}
+		return z
+	}
+
+	if x.form == inf && y.form == inf && x.neg != y.neg {
+		// +Inf + -Inf
+		// -Inf + +Inf
+		// value of z is undefined but make sure it's valid
+		z.acc = Exact
+		z.form = zero
+		z.neg = false
+		panic(ErrNaN{"addition of infinities with opposite signs"})
+	}
+
+	if x.form == zero && y.form == zero {
+		// ±0 + ±0
+		z.acc = Exact
+		z.form = zero
+		z.neg = x.neg && y.neg // -0 + -0 == -0
+		return z
+	}
+
+	if x.form == inf || y.form == zero {
+		// ±Inf + y
+		// x + ±0
+		return z.Set(x)
+	}
+
+	// ±0 + y
+	// x + ±Inf
+	return z.Set(y)
+}
+
+// Sub sets z to the rounded difference x-y and returns z.
+// Precision, rounding, and accuracy reporting are as for Add.
+// Sub panics with ErrNaN if x and y are infinities with equal
+// signs. The value of z is undefined in that case.
+func (z *Float) Sub(x, y *Float) *Float {
+	if debugFloat {
+		x.validate()
+		y.validate()
+	}
+
+	if z.prec == 0 {
+		z.prec = umax32(x.prec, y.prec)
+	}
+
+	if x.form == finite && y.form == finite {
+		// x - y (common case)
+		z.neg = x.neg
+		if x.neg != y.neg {
+			// x - (-y) == x + y
+			// (-x) - y == -(x + y)
+			z.uadd(x, y)
+		} else {
+			// x - y == x - y == -(y - x)
+			// (-x) - (-y) == y - x == -(x - y)
+			if x.ucmp(y) > 0 {
+				z.usub(x, y)
+			} else {
+				z.neg = !z.neg
+				z.usub(y, x)
+			}
+		}
+		return z
+	}
+
+	if x.form == inf && y.form == inf && x.neg == y.neg {
+		// +Inf - +Inf
+		// -Inf - -Inf
+		// value of z is undefined but make sure it's valid
+		z.acc = Exact
+		z.form = zero
+		z.neg = false
+		panic(ErrNaN{"subtraction of infinities with equal signs"})
+	}
+
+	if x.form == zero && y.form == zero {
+		// ±0 - ±0
+		z.acc = Exact
+		z.form = zero
+		z.neg = x.neg && !y.neg // -0 - +0 == -0
+		return z
+	}
+
+	if x.form == inf || y.form == zero {
+		// ±Inf - y
+		// x - ±0
+		return z.Set(x)
+	}
+
+	// ±0 - y
+	// x - ±Inf
+	return z.Neg(y)
+}
+
+// Mul sets z to the rounded product x*y and returns z.
+// Precision, rounding, and accuracy reporting are as for Add.
+// Mul panics with ErrNaN if one operand is zero and the other
+// operand an infinity. The value of z is undefined in that case.
+func (z *Float) Mul(x, y *Float) *Float {
+	if debugFloat {
+		x.validate()
+		y.validate()
+	}
+
+	if z.prec == 0 {
+		z.prec = umax32(x.prec, y.prec)
+	}
+
+	z.neg = x.neg != y.neg
+
+	if x.form == finite && y.form == finite {
+		// x * y (common case)
+		z.umul(x, y)
+		return z
+	}
+
+	z.acc = Exact
+	if x.form == zero && y.form == inf || x.form == inf && y.form == zero {
+		// ±0 * ±Inf
+		// ±Inf * ±0
+		// value of z is undefined but make sure it's valid
+		z.form = zero
+		z.neg = false
+		panic(ErrNaN{"multiplication of zero with infinity"})
+	}
+
+	if x.form == inf || y.form == inf {
+		// ±Inf * y
+		// x * ±Inf
+		z.form = inf
+		return z
+	}
+
+	// ±0 * y
+	// x * ±0
+	z.form = zero
+	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 with ErrNaN if both operands are zero or infinities.
+// The value of z is undefined in that case.
+func (z *Float) Quo(x, y *Float) *Float {
+	if debugFloat {
+		x.validate()
+		y.validate()
+	}
+
+	if z.prec == 0 {
+		z.prec = umax32(x.prec, y.prec)
+	}
+
+	z.neg = x.neg != y.neg
+
+	if x.form == finite && y.form == finite {
+		// x / y (common case)
+		z.uquo(x, y)
+		return z
+	}
+
+	z.acc = Exact
+	if x.form == zero && y.form == zero || x.form == inf && y.form == inf {
+		// ±0 / ±0
+		// ±Inf / ±Inf
+		// value of z is undefined but make sure it's valid
+		z.form = zero
+		z.neg = false
+		panic(ErrNaN{"division of zero by zero or infinity by infinity"})
+	}
+
+	if x.form == zero || y.form == inf {
+		// ±0 / y
+		// x / ±Inf
+		z.form = zero
+		return z
+	}
+
+	// x / ±0
+	// ±Inf / y
+	z.form = inf
+	return z
+}
+
+// Cmp compares x and y and returns:
+//
+//   -1 if x <  y
+//    0 if x == y (incl. -0 == 0, -Inf == -Inf, and +Inf == +Inf)
+//   +1 if x >  y
+//
+func (x *Float) Cmp(y *Float) int {
+	if debugFloat {
+		x.validate()
+		y.validate()
+	}
+
+	mx := x.ord()
+	my := y.ord()
+	switch {
+	case mx < my:
+		return -1
+	case mx > my:
+		return +1
+	}
+	// mx == my
+
+	// only if |mx| == 1 we have to compare the mantissae
+	switch mx {
+	case -1:
+		return y.ucmp(x)
+	case +1:
+		return x.ucmp(y)
+	}
+
+	return 0
+}
+
+// ord classifies x and returns:
+//
+//	-2 if -Inf == x
+//	-1 if -Inf < x < 0
+//	 0 if x == 0 (signed or unsigned)
+//	+1 if 0 < x < +Inf
+//	+2 if x == +Inf
+//
+func (x *Float) ord() int {
+	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/cmd/compile/internal/big/float_test.go b/src/cmd/compile/internal/big/float_test.go
new file mode 100644
index 0000000..d3b214b
--- /dev/null
+++ b/src/cmd/compile/internal/big/float_test.go
@@ -0,0 +1,1694 @@
+// 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 big
+
+import (
+	"fmt"
+	"math"
+	"strconv"
+	"strings"
+	"testing"
+)
+
+// Verify that ErrNaN implements the error interface.
+var _ error = ErrNaN{}
+
+func (x *Float) uint64() uint64 {
+	u, acc := x.Uint64()
+	if acc != Exact {
+		panic(fmt.Sprintf("%s is not a uint64", x.Text('g', 10)))
+	}
+	return u
+}
+
+func (x *Float) int64() int64 {
+	i, acc := x.Int64()
+	if acc != Exact {
+		panic(fmt.Sprintf("%s is not an int64", x.Text('g', 10)))
+	}
+	return i
+}
+
+func TestFloatZeroValue(t *testing.T) {
+	// zero (uninitialized) value is a ready-to-use 0.0
+	var x Float
+	if s := x.Text('f', 1); s != "0.0" {
+		t.Errorf("zero value = %s; want 0.0", s)
+	}
+
+	// zero value has precision 0
+	if prec := x.Prec(); prec != 0 {
+		t.Errorf("prec = %d; want 0", prec)
+	}
+
+	// zero value can be used in any and all positions of binary operations
+	make := func(x int) *Float {
+		var f Float
+		if x != 0 {
+			f.SetInt64(int64(x))
+		}
+		// x == 0 translates into the zero value
+		return &f
+	}
+	for _, test := range []struct {
+		z, x, y, want int
+		opname        rune
+		op            func(z, x, y *Float) *Float
+	}{
+		{0, 0, 0, 0, '+', (*Float).Add},
+		{0, 1, 2, 3, '+', (*Float).Add},
+		{1, 2, 0, 2, '+', (*Float).Add},
+		{2, 0, 1, 1, '+', (*Float).Add},
+
+		{0, 0, 0, 0, '-', (*Float).Sub},
+		{0, 1, 2, -1, '-', (*Float).Sub},
+		{1, 2, 0, 2, '-', (*Float).Sub},
+		{2, 0, 1, -1, '-', (*Float).Sub},
+
+		{0, 0, 0, 0, '*', (*Float).Mul},
+		{0, 1, 2, 2, '*', (*Float).Mul},
+		{1, 2, 0, 0, '*', (*Float).Mul},
+		{2, 0, 1, 0, '*', (*Float).Mul},
+
+		// {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},
+	} {
+		z := make(test.z)
+		test.op(z, make(test.x), make(test.y))
+		got := 0
+		if !z.IsInf() {
+			got = int(z.int64())
+		}
+		if got != test.want {
+			t.Errorf("%d %c %d = %d; want %d", test.x, test.opname, test.y, got, test.want)
+		}
+	}
+
+	// TODO(gri) test how precision is set for zero value results
+}
+
+func makeFloat(s string) *Float {
+	x, _, err := ParseFloat(s, 0, 1000, ToNearestEven)
+	if err != nil {
+		panic(err)
+	}
+	return x
+}
+
+func TestFloatSetPrec(t *testing.T) {
+	for _, test := range []struct {
+		x    string
+		prec uint
+		want string
+		acc  Accuracy
+	}{
+		// prec 0
+		{"0", 0, "0", Exact},
+		{"-0", 0, "-0", Exact},
+		{"-Inf", 0, "-Inf", Exact},
+		{"+Inf", 0, "+Inf", Exact},
+		{"123", 0, "0", Below},
+		{"-123", 0, "-0", Above},
+
+		// prec at upper limit
+		{"0", MaxPrec, "0", Exact},
+		{"-0", MaxPrec, "-0", Exact},
+		{"-Inf", MaxPrec, "-Inf", Exact},
+		{"+Inf", MaxPrec, "+Inf", Exact},
+
+		// just a few regular cases - general rounding is tested elsewhere
+		{"1.5", 1, "2", Above},
+		{"-1.5", 1, "-2", Below},
+		{"123", 1e6, "123", Exact},
+		{"-123", 1e6, "-123", Exact},
+	} {
+		x := makeFloat(test.x).SetPrec(test.prec)
+		prec := test.prec
+		if prec > MaxPrec {
+			prec = MaxPrec
+		}
+		if got := x.Prec(); got != prec {
+			t.Errorf("%s.SetPrec(%d).Prec() == %d; want %d", test.x, test.prec, got, prec)
+		}
+		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)
+		}
+	}
+}
+
+func TestFloatMinPrec(t *testing.T) {
+	const max = 100
+	for _, test := range []struct {
+		x    string
+		want uint
+	}{
+		{"0", 0},
+		{"-0", 0},
+		{"+Inf", 0},
+		{"-Inf", 0},
+		{"1", 1},
+		{"2", 1},
+		{"3", 2},
+		{"0x8001", 16},
+		{"0x8001p-1000", 16},
+		{"0x8001p+1000", 16},
+		{"0.1", max},
+	} {
+		x := makeFloat(test.x).SetPrec(max)
+		if got := x.MinPrec(); got != test.want {
+			t.Errorf("%s.MinPrec() = %d; want %d", test.x, got, test.want)
+		}
+	}
+}
+
+func TestFloatSign(t *testing.T) {
+	for _, test := range []struct {
+		x string
+		s int
+	}{
+		{"-Inf", -1},
+		{"-1", -1},
+		{"-0", 0},
+		{"+0", 0},
+		{"+1", +1},
+		{"+Inf", +1},
+	} {
+		x := makeFloat(test.x)
+		s := x.Sign()
+		if s != test.s {
+			t.Errorf("%s.Sign() = %d; want %d", test.x, s, test.s)
+		}
+	}
+}
+
+// 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 alike32(x, y float32) bool {
+	// we can ignore NaNs
+	return x == y && math.Signbit(float64(x)) == math.Signbit(float64(y))
+
+}
+
+func alike64(x, y float64) bool {
+	// we can ignore NaNs
+	return x == y && math.Signbit(x) == math.Signbit(y)
+
+}
+
+func TestFloatMantExp(t *testing.T) {
+	for _, test := range []struct {
+		x    string
+		mant string
+		exp  int
+	}{
+		{"0", "0", 0},
+		{"+0", "0", 0},
+		{"-0", "-0", 0},
+		{"Inf", "+Inf", 0},
+		{"+Inf", "+Inf", 0},
+		{"-Inf", "-Inf", 0},
+		{"1.5", "0.75", 1},
+		{"1.024e3", "0.5", 11},
+		{"-0.125", "-0.5", -2},
+	} {
+		x := makeFloat(test.x)
+		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.Text('g', 10), e, test.mant, test.exp)
+		}
+	}
+}
+
+func TestFloatMantExpAliasing(t *testing.T) {
+	x := makeFloat("0.5p10")
+	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.Text('g', 10), want.Text('g', 10))
+	}
+}
+
+func TestFloatSetMantExp(t *testing.T) {
+	for _, test := range []struct {
+		frac string
+		exp  int
+		z    string
+	}{
+		{"0", 0, "0"},
+		{"+0", 0, "0"},
+		{"-0", 0, "-0"},
+		{"Inf", 1234, "+Inf"},
+		{"+Inf", -1234, "+Inf"},
+		{"-Inf", -1234, "-Inf"},
+		{"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"},
+		{"32", 5, "1024"},
+		{"1024", -10, "1"},
+	} {
+		frac := makeFloat(test.frac)
+		want := makeFloat(test.z)
+		var z Float
+		z.SetMantExp(frac, test.exp)
+		if !alike(&z, want) {
+			t.Errorf("SetMantExp(%s, %d) = %s; want %s", test.frac, test.exp, z.Text('g', 10), test.z)
+		}
+		// test inverse property
+		mant := new(Float)
+		if z.SetMantExp(mant, want.MantExp(mant)).Cmp(want) != 0 {
+			t.Errorf("Inverse property not satisfied: got %s; want %s", z.Text('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",
+		"-0 int",
+		"1 int",
+		"-1 int",
+		"0.5",
+		"1.23",
+		"1.23e1",
+		"1.23e2 int",
+		"0.000000001e+8",
+		"0.000000001e+9 int",
+		"1.2345e200 int",
+		"Inf",
+		"+Inf",
+		"-Inf",
+	} {
+		s := strings.TrimSuffix(test, " int")
+		want := s != test
+		if got := makeFloat(s).IsInt(); got != want {
+			t.Errorf("%s.IsInt() == %t", s, got)
+		}
+	}
+}
+
+func fromBinary(s string) int64 {
+	x, err := strconv.ParseInt(s, 2, 64)
+	if err != nil {
+		panic(err)
+	}
+	return x
+}
+
+func toBinary(x int64) string {
+	return strconv.FormatInt(x, 2)
+}
+
+func testFloatRound(t *testing.T, x, r int64, prec uint, mode RoundingMode) {
+	// verify test data
+	var ok bool
+	switch mode {
+	case ToNearestEven, ToNearestAway:
+		ok = true // nothing to do for now
+	case ToZero:
+		if x < 0 {
+			ok = r >= x
+		} else {
+			ok = r <= x
+		}
+	case AwayFromZero:
+		if x < 0 {
+			ok = r <= x
+		} else {
+			ok = r >= x
+		}
+	case ToNegativeInf:
+		ok = r <= x
+	case ToPositiveInf:
+		ok = r >= x
+	default:
+		panic("unreachable")
+	}
+	if !ok {
+		t.Fatalf("incorrect test data for prec = %d, %s: x = %s, r = %s", prec, mode, toBinary(x), toBinary(r))
+	}
+
+	// compute expected accuracy
+	a := Exact
+	switch {
+	case r < x:
+		a = Below
+	case r > x:
+		a = Above
+	}
+
+	// round
+	f := new(Float).SetMode(mode).SetInt64(x).SetPrec(prec)
+
+	// check result
+	r1 := f.int64()
+	p1 := f.Prec()
+	a1 := f.Acc()
+	if r1 != r || p1 != prec || a1 != a {
+		t.Errorf("round %s (%d bits, %s) incorrect: got %s (%d bits, %s); want %s (%d bits, %s)",
+			toBinary(x), prec, mode,
+			toBinary(r1), p1, a1,
+			toBinary(r), prec, a)
+		return
+	}
+
+	// g and f should be the same
+	// (rounding by SetPrec after SetInt64 using default precision
+	// should be the same as rounding by SetInt64 after setting the
+	// precision)
+	g := new(Float).SetMode(mode).SetPrec(prec).SetInt64(x)
+	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()),
+			toBinary(r1),
+			toBinary(r),
+		)
+		return
+	}
+
+	// h and f should be the same
+	// (repeated rounding should be idempotent)
+	h := new(Float).SetMode(mode).SetPrec(prec).Set(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()),
+			toBinary(r1),
+			toBinary(r),
+		)
+		return
+	}
+}
+
+// TestFloatRound tests basic rounding.
+func TestFloatRound(t *testing.T) {
+	for _, test := range []struct {
+		prec                        uint
+		x, zero, neven, naway, away string // input, results rounded to prec bits
+	}{
+		{5, "1000", "1000", "1000", "1000", "1000"},
+		{5, "1001", "1001", "1001", "1001", "1001"},
+		{5, "1010", "1010", "1010", "1010", "1010"},
+		{5, "1011", "1011", "1011", "1011", "1011"},
+		{5, "1100", "1100", "1100", "1100", "1100"},
+		{5, "1101", "1101", "1101", "1101", "1101"},
+		{5, "1110", "1110", "1110", "1110", "1110"},
+		{5, "1111", "1111", "1111", "1111", "1111"},
+
+		{4, "1000", "1000", "1000", "1000", "1000"},
+		{4, "1001", "1001", "1001", "1001", "1001"},
+		{4, "1010", "1010", "1010", "1010", "1010"},
+		{4, "1011", "1011", "1011", "1011", "1011"},
+		{4, "1100", "1100", "1100", "1100", "1100"},
+		{4, "1101", "1101", "1101", "1101", "1101"},
+		{4, "1110", "1110", "1110", "1110", "1110"},
+		{4, "1111", "1111", "1111", "1111", "1111"},
+
+		{3, "1000", "1000", "1000", "1000", "1000"},
+		{3, "1001", "1000", "1000", "1010", "1010"},
+		{3, "1010", "1010", "1010", "1010", "1010"},
+		{3, "1011", "1010", "1100", "1100", "1100"},
+		{3, "1100", "1100", "1100", "1100", "1100"},
+		{3, "1101", "1100", "1100", "1110", "1110"},
+		{3, "1110", "1110", "1110", "1110", "1110"},
+		{3, "1111", "1110", "10000", "10000", "10000"},
+
+		{3, "1000001", "1000000", "1000000", "1000000", "1010000"},
+		{3, "1001001", "1000000", "1010000", "1010000", "1010000"},
+		{3, "1010001", "1010000", "1010000", "1010000", "1100000"},
+		{3, "1011001", "1010000", "1100000", "1100000", "1100000"},
+		{3, "1100001", "1100000", "1100000", "1100000", "1110000"},
+		{3, "1101001", "1100000", "1110000", "1110000", "1110000"},
+		{3, "1110001", "1110000", "1110000", "1110000", "10000000"},
+		{3, "1111001", "1110000", "10000000", "10000000", "10000000"},
+
+		{2, "1000", "1000", "1000", "1000", "1000"},
+		{2, "1001", "1000", "1000", "1000", "1100"},
+		{2, "1010", "1000", "1000", "1100", "1100"},
+		{2, "1011", "1000", "1100", "1100", "1100"},
+		{2, "1100", "1100", "1100", "1100", "1100"},
+		{2, "1101", "1100", "1100", "1100", "10000"},
+		{2, "1110", "1100", "10000", "10000", "10000"},
+		{2, "1111", "1100", "10000", "10000", "10000"},
+
+		{2, "1000001", "1000000", "1000000", "1000000", "1100000"},
+		{2, "1001001", "1000000", "1000000", "1000000", "1100000"},
+		{2, "1010001", "1000000", "1100000", "1100000", "1100000"},
+		{2, "1011001", "1000000", "1100000", "1100000", "1100000"},
+		{2, "1100001", "1100000", "1100000", "1100000", "10000000"},
+		{2, "1101001", "1100000", "1100000", "1100000", "10000000"},
+		{2, "1110001", "1100000", "10000000", "10000000", "10000000"},
+		{2, "1111001", "1100000", "10000000", "10000000", "10000000"},
+
+		{1, "1000", "1000", "1000", "1000", "1000"},
+		{1, "1001", "1000", "1000", "1000", "10000"},
+		{1, "1010", "1000", "1000", "1000", "10000"},
+		{1, "1011", "1000", "1000", "1000", "10000"},
+		{1, "1100", "1000", "10000", "10000", "10000"},
+		{1, "1101", "1000", "10000", "10000", "10000"},
+		{1, "1110", "1000", "10000", "10000", "10000"},
+		{1, "1111", "1000", "10000", "10000", "10000"},
+
+		{1, "1000001", "1000000", "1000000", "1000000", "10000000"},
+		{1, "1001001", "1000000", "1000000", "1000000", "10000000"},
+		{1, "1010001", "1000000", "1000000", "1000000", "10000000"},
+		{1, "1011001", "1000000", "1000000", "1000000", "10000000"},
+		{1, "1100001", "1000000", "10000000", "10000000", "10000000"},
+		{1, "1101001", "1000000", "10000000", "10000000", "10000000"},
+		{1, "1110001", "1000000", "10000000", "10000000", "10000000"},
+		{1, "1111001", "1000000", "10000000", "10000000", "10000000"},
+	} {
+		x := fromBinary(test.x)
+		z := fromBinary(test.zero)
+		e := fromBinary(test.neven)
+		n := fromBinary(test.naway)
+		a := fromBinary(test.away)
+		prec := test.prec
+
+		testFloatRound(t, x, z, prec, ToZero)
+		testFloatRound(t, x, e, prec, ToNearestEven)
+		testFloatRound(t, x, n, prec, ToNearestAway)
+		testFloatRound(t, x, a, prec, AwayFromZero)
+
+		testFloatRound(t, x, z, prec, ToNegativeInf)
+		testFloatRound(t, x, a, prec, ToPositiveInf)
+
+		testFloatRound(t, -x, -a, prec, ToNegativeInf)
+		testFloatRound(t, -x, -z, prec, ToPositiveInf)
+	}
+}
+
+// TestFloatRound24 tests that rounding a float64 to 24 bits
+// matches IEEE-754 rounding to nearest when converting a
+// 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.Float32()
+		want := float32(x)
+		if got != want {
+			t.Errorf("Round(%g, 24) = %g; want %g", x, got, want)
+		}
+	}
+}
+
+func TestFloatSetUint64(t *testing.T) {
+	for _, want := range []uint64{
+		0,
+		1,
+		2,
+		10,
+		100,
+		1<<32 - 1,
+		1 << 32,
+		1<<64 - 1,
+	} {
+		var f Float
+		f.SetUint64(want)
+		if got := f.uint64(); got != want {
+			t.Errorf("got %#x (%s); want %#x", got, f.Text('p', 0), want)
+		}
+	}
+
+	// test basic rounding behavior (exhaustive rounding testing is done elsewhere)
+	const x uint64 = 0x8765432187654321 // 64 bits needed
+	for prec := uint(1); prec <= 64; prec++ {
+		f := new(Float).SetPrec(prec).SetMode(ToZero).SetUint64(x)
+		got := f.uint64()
+		want := x &^ (1<<(64-prec) - 1) // cut off (round to zero) low 64-prec bits
+		if got != want {
+			t.Errorf("got %#x (%s); want %#x", got, f.Text('p', 0), want)
+		}
+	}
+}
+
+func TestFloatSetInt64(t *testing.T) {
+	for _, want := range []int64{
+		0,
+		1,
+		2,
+		10,
+		100,
+		1<<32 - 1,
+		1 << 32,
+		1<<63 - 1,
+	} {
+		for i := range [2]int{} {
+			if i&1 != 0 {
+				want = -want
+			}
+			var f Float
+			f.SetInt64(want)
+			if got := f.int64(); got != want {
+				t.Errorf("got %#x (%s); want %#x", got, f.Text('p', 0), want)
+			}
+		}
+	}
+
+	// test basic rounding behavior (exhaustive rounding testing is done elsewhere)
+	const x int64 = 0x7654321076543210 // 63 bits needed
+	for prec := uint(1); prec <= 63; prec++ {
+		f := new(Float).SetPrec(prec).SetMode(ToZero).SetInt64(x)
+		got := f.int64()
+		want := x &^ (1<<(63-prec) - 1) // cut off (round to zero) low 63-prec bits
+		if got != want {
+			t.Errorf("got %#x (%s); want %#x", got, f.Text('p', 0), want)
+		}
+	}
+}
+
+func TestFloatSetFloat64(t *testing.T) {
+	for _, want := range []float64{
+		0,
+		1,
+		2,
+		12345,
+		1e10,
+		1e100,
+		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),
+	} {
+		for i := range [2]int{} {
+			if i&1 != 0 {
+				want = -want
+			}
+			var f Float
+			f.SetFloat64(want)
+			if got, acc := f.Float64(); got != want || acc != Exact {
+				t.Errorf("got %g (%s, %s); want %g (Exact)", got, f.Text('p', 0), acc, want)
+			}
+		}
+	}
+
+	// test basic rounding behavior (exhaustive rounding testing is done elsewhere)
+	const x uint64 = 0x8765432143218 // 53 bits needed
+	for prec := uint(1); prec <= 52; prec++ {
+		f := new(Float).SetPrec(prec).SetMode(ToZero).SetFloat64(float64(x))
+		got, _ := f.Float64()
+		want := float64(x &^ (1<<(52-prec) - 1)) // cut off (round to zero) low 53-prec bits
+		if got != want {
+			t.Errorf("got %g (%s); want %g", got, f.Text('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.Text('p', 0))
+}
+
+func TestFloatSetInt(t *testing.T) {
+	for _, want := range []string{
+		"0",
+		"1",
+		"-1",
+		"1234567890",
+		"123456789012345678901234567890",
+		"123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890",
+	} {
+		var x Int
+		_, ok := x.SetString(want, 0)
+		if !ok {
+			t.Errorf("invalid integer %s", want)
+			continue
+		}
+		n := x.BitLen()
+
+		var f Float
+		f.SetInt(&x)
+
+		// check precision
+		if n < 64 {
+			n = 64
+		}
+		if prec := f.Prec(); prec != uint(n) {
+			t.Errorf("got prec = %d; want %d", prec, n)
+		}
+
+		// check value
+		got := f.Text('g', 100)
+		if got != want {
+			t.Errorf("got %s (%s); want %s", got, f.Text('p', 0), want)
+		}
+	}
+
+	// TODO(gri) test basic rounding behavior
+}
+
+func TestFloatSetRat(t *testing.T) {
+	for _, want := range []string{
+		"0",
+		"1",
+		"-1",
+		"1234567890",
+		"123456789012345678901234567890",
+		"123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890",
+		"1.2",
+		"3.14159265",
+		// TODO(gri) expand
+	} {
+		var x Rat
+		_, ok := x.SetString(want)
+		if !ok {
+			t.Errorf("invalid fraction %s", want)
+			continue
+		}
+		n := max(x.Num().BitLen(), x.Denom().BitLen())
+
+		var f1, f2 Float
+		f2.SetPrec(1000)
+		f1.SetRat(&x)
+		f2.SetRat(&x)
+
+		// check precision when set automatically
+		if n < 64 {
+			n = 64
+		}
+		if prec := f1.Prec(); prec != uint(n) {
+			t.Errorf("got prec = %d; want %d", prec, n)
+		}
+
+		got := f2.Text('g', 100)
+		if got != want {
+			t.Errorf("got %s (%s); want %s", got, f2.Text('p', 0), want)
+		}
+	}
+}
+
+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
+		out uint64
+		acc Accuracy
+	}{
+		{"-Inf", 0, Above},
+		{"-1", 0, Above},
+		{"-1e-1000", 0, Above},
+		{"-0", 0, Exact},
+		{"0", 0, Exact},
+		{"1e-1000", 0, Below},
+		{"1", 1, Exact},
+		{"1.000000000000000000001", 1, Below},
+		{"12345.0", 12345, Exact},
+		{"12345.000000000000000000001", 12345, Below},
+		{"18446744073709551615", 18446744073709551615, Exact},
+		{"18446744073709551615.000000000000000000001", math.MaxUint64, Below},
+		{"18446744073709551616", math.MaxUint64, Below},
+		{"1e10000", math.MaxUint64, Below},
+		{"+Inf", math.MaxUint64, Below},
+	} {
+		x := makeFloat(test.x)
+		out, acc := x.Uint64()
+		if out != test.out || acc != test.acc {
+			t.Errorf("%s: got %d (%s); want %d (%s)", test.x, out, acc, test.out, test.acc)
+		}
+	}
+}
+
+func TestFloatInt64(t *testing.T) {
+	for _, test := range []struct {
+		x   string
+		out int64
+		acc Accuracy
+	}{
+		{"-Inf", math.MinInt64, Above},
+		{"-1e10000", math.MinInt64, Above},
+		{"-9223372036854775809", math.MinInt64, Above},
+		{"-9223372036854775808.000000000000000000001", math.MinInt64, Above},
+		{"-9223372036854775808", -9223372036854775808, Exact},
+		{"-9223372036854775807.000000000000000000001", -9223372036854775807, Above},
+		{"-9223372036854775807", -9223372036854775807, Exact},
+		{"-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},
+		{"9223372036854775807.000000000000000000001", math.MaxInt64, Below},
+		{"9223372036854775808", math.MaxInt64, Below},
+		{"1e10000", math.MaxInt64, Below},
+		{"+Inf", math.MaxInt64, Below},
+	} {
+		x := makeFloat(test.x)
+		out, acc := x.Int64()
+		if out != test.out || acc != test.acc {
+			t.Errorf("%s: got %d (%s); want %d (%s)", test.x, out, acc, test.out, test.acc)
+		}
+	}
+}
+
+func TestFloatFloat32(t *testing.T) {
+	for _, test := range []struct {
+		x   string
+		out float32
+		acc Accuracy
+	}{
+		{"0", 0, Exact},
+
+		// underflow
+		{"1e-1000", 0, Below},
+		{"0x0.000002p-127", 0, Below},
+		{"0x.0000010p-126", 0, Below},
+
+		// denormals
+		{"1.401298464e-45", math.SmallestNonzeroFloat32, Above}, // rounded up to smallest denormal
+		{"0x.ffffff8p-149", math.SmallestNonzeroFloat32, Above}, // rounded up to smallest denormal
+		{"0x.0000018p-126", math.SmallestNonzeroFloat32, Above}, // rounded up to smallest denormal
+		{"0x.0000020p-126", math.SmallestNonzeroFloat32, Exact},
+		{"0x.8p-148", math.SmallestNonzeroFloat32, Exact},
+		{"1p-149", math.SmallestNonzeroFloat32, Exact},
+		{"0x.fffffep-126", math.Float32frombits(0x7fffff), Exact}, // largest denormal
+
+		// normals
+		{"0x.ffffffp-126", math.Float32frombits(0x00800000), Above}, // rounded up to smallest normal
+		{"1p-126", math.Float32frombits(0x00800000), Exact},         // smallest normal
+		{"0x1.fffffep-126", math.Float32frombits(0x00ffffff), Exact},
+		{"0x1.ffffffp-126", math.Float32frombits(0x01000000), Above}, // rounded up
+		{"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},
+
+		// overflow
+		{"0x1.ffffff0p127", float32(math.Inf(+1)), Above},
+		{"0x1p128", float32(math.Inf(+1)), Above},
+		{"1e10000", float32(math.Inf(+1)), Above},
+		{"0x1.ffffff0p2147483646", float32(math.Inf(+1)), Above}, // overflow in rounding
+
+		// inf
+		{"Inf", float32(math.Inf(+1)), Exact},
+	} {
+		for i := 0; i < 2; i++ {
+			// test both signs
+			tx, tout, tacc := test.x, test.out, test.acc
+			if i != 0 {
+				tx = "-" + tx
+				tout = -tout
+				tacc = -tacc
+			}
+
+			// conversion should match strconv where syntax is agreeable
+			if f, err := strconv.ParseFloat(tx, 32); err == nil && !alike32(float32(f), tout) {
+				t.Errorf("%s: got %g; want %g (incorrect test data)", tx, f, tout)
+			}
+
+			x := makeFloat(tx)
+			out, acc := x.Float32()
+			if !alike32(out, tout) || acc != tacc {
+				t.Errorf("%s: got %g (%#x, %s); want %g (%#x, %s)", tx, out, math.Float32bits(out), acc, test.out, math.Float32bits(test.out), tacc)
+			}
+
+			// test that x.SetFloat64(float64(f)).Float32() == f
+			var x2 Float
+			out2, acc2 := x2.SetFloat64(float64(out)).Float32()
+			if !alike32(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
+	}{
+		{"0", 0, Exact},
+
+		// underflow
+		{"1e-1000", 0, Below},
+		{"0x0.0000000000001p-1023", 0, Below},
+		{"0x0.00000000000008p-1022", 0, Below},
+
+		// denormals
+		{"0x0.0000000000000cp-1022", math.SmallestNonzeroFloat64, Above}, // rounded up to smallest denormal
+		{"0x0.0000000000001p-1022", math.SmallestNonzeroFloat64, Exact},  // smallest denormal
+		{"0x.8p-1073", math.SmallestNonzeroFloat64, Exact},
+		{"1p-1074", math.SmallestNonzeroFloat64, Exact},
+		{"0x.fffffffffffffp-1022", math.Float64frombits(0x000fffffffffffff), Exact}, // largest denormal
+
+		// normals
+		{"0x.fffffffffffff8p-1022", math.Float64frombits(0x0010000000000000), Above}, // rounded up to smallest normal
+		{"1p-1022", math.Float64frombits(0x0010000000000000), Exact},                 // smallest normal
+		{"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},
+
+		// overflow
+		{"0x1.fffffffffffff8p1023", math.Inf(+1), Above},
+		{"0x1p1024", math.Inf(+1), Above},
+		{"1e10000", math.Inf(+1), Above},
+		{"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},
+	} {
+		for i := 0; i < 2; i++ {
+			// test both signs
+			tx, tout, tacc := test.x, test.out, test.acc
+			if i != 0 {
+				tx = "-" + tx
+				tout = -tout
+				tacc = -tacc
+			}
+
+			// conversion should match strconv where syntax is agreeable
+			if f, err := strconv.ParseFloat(tx, 64); err == nil && !alike64(f, tout) {
+				t.Errorf("%s: got %g; want %g (incorrect test data)", tx, f, tout)
+			}
+
+			x := makeFloat(tx)
+			out, acc := x.Float64()
+			if !alike64(out, tout) || acc != tacc {
+				t.Errorf("%s: got %g (%#x, %s); want %g (%#x, %s)", tx, out, math.Float64bits(out), acc, test.out, math.Float64bits(test.out), tacc)
+			}
+
+			// test that x.SetFloat64(f).Float64() == f
+			var x2 Float
+			out2, acc2 := x2.SetFloat64(out).Float64()
+			if !alike64(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
+		want string
+		acc  Accuracy
+	}{
+		{"0", "0", Exact},
+		{"+0", "0", Exact},
+		{"-0", "0", Exact},
+		{"Inf", "nil", Below},
+		{"+Inf", "nil", Below},
+		{"-Inf", "nil", Above},
+		{"1", "1", Exact},
+		{"-1", "-1", Exact},
+		{"1.23", "1", Below},
+		{"-1.23", "-1", Above},
+		{"123e-2", "1", Below},
+		{"123e-3", "0", Below},
+		{"123e-4", "0", Below},
+		{"1e-1000", "0", Below},
+		{"-1e-1000", "0", Above},
+		{"1e+10", "10000000000", Exact},
+		{"1e+100", "10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", Exact},
+	} {
+		x := makeFloat(test.x)
+		res, acc := x.Int(nil)
+		got := "nil"
+		if res != nil {
+			got = res.String()
+		}
+		if got != test.want || acc != test.acc {
+			t.Errorf("%s: got %s (%s); want %s (%s)", test.x, got, acc, test.want, test.acc)
+		}
+	}
+
+	// check that supplied *Int is used
+	for _, f := range []string{"0", "1", "-1", "1234"} {
+		x := makeFloat(f)
+		i := new(Int)
+		if res, _ := x.Int(i); res != i {
+			t.Errorf("(%s).Int is not using supplied *Int", f)
+		}
+	}
+}
+
+func TestFloatRat(t *testing.T) {
+	for _, test := range []struct {
+		x, want string
+		acc     Accuracy
+	}{
+		{"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, acc := x.Rat(nil)
+		got := "nil"
+		if res != nil {
+			got = res.String()
+		}
+		if got != test.want {
+			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 {
+			got := new(Float).SetPrec(64).SetRat(res)
+			if got.Cmp(x) != 0 {
+				t.Errorf("%s: got %s; want %s", test.x, got, x)
+			}
+		}
+	}
+
+	// check that supplied *Rat is used
+	for _, f := range []string{"0", "1", "-1", "1234"} {
+		x := makeFloat(f)
+		r := new(Rat)
+		if res, _ := x.Rat(r); res != r {
+			t.Errorf("(%s).Rat is not using supplied *Rat", f)
+		}
+	}
+}
+
+func TestFloatAbs(t *testing.T) {
+	for _, test := range []string{
+		"0",
+		"1",
+		"1234",
+		"1.23e-2",
+		"1e-1000",
+		"1e1000",
+		"Inf",
+	} {
+		p := makeFloat(test)
+		a := new(Float).Abs(p)
+		if !alike(a, p) {
+			t.Errorf("%s: got %s; want %s", test, a.Text('g', 10), test)
+		}
+
+		n := makeFloat("-" + test)
+		a.Abs(n)
+		if !alike(a, p) {
+			t.Errorf("-%s: got %s; want %s", test, a.Text('g', 10), test)
+		}
+	}
+}
+
+func TestFloatNeg(t *testing.T) {
+	for _, test := range []string{
+		"0",
+		"1",
+		"1234",
+		"1.23e-2",
+		"1e-1000",
+		"1e1000",
+		"Inf",
+	} {
+		p1 := makeFloat(test)
+		n1 := makeFloat("-" + test)
+		n2 := new(Float).Neg(p1)
+		p2 := new(Float).Neg(n2)
+		if !alike(n2, n1) {
+			t.Errorf("%s: got %s; want %s", test, n2.Text('g', 10), n1.Text('g', 10))
+		}
+		if !alike(p2, p1) {
+			t.Errorf("%s: got %s; want %s", test, p2.Text('g', 10), p1.Text('g', 10))
+		}
+	}
+}
+
+func TestFloatInc(t *testing.T) {
+	const n = 10
+	for _, prec := range precList {
+		if 1<<prec < n {
+			continue // prec must be large enough to hold all numbers from 0 to n
+		}
+		var x, one Float
+		x.SetPrec(prec)
+		one.SetInt64(1)
+		for i := 0; i < n; i++ {
+			x.Add(&x, &one)
+		}
+		if x.Cmp(new(Float).SetInt64(n)) != 0 {
+			t.Errorf("prec = %d: got %s; want %d", prec, &x, n)
+		}
+	}
+}
+
+// Selected precisions with which to run various tests.
+var precList = [...]uint{1, 2, 5, 8, 10, 16, 23, 24, 32, 50, 53, 64, 100, 128, 500, 511, 512, 513, 1000, 10000}
+
+// Selected bits with which to run various tests.
+// Each entry is a list of bits representing a floating-point number (see fromBits).
+var bitsList = [...]Bits{
+	{},           // = 0
+	{0},          // = 1
+	{1},          // = 2
+	{-1},         // = 1/2
+	{10},         // = 2**10 == 1024
+	{-10},        // = 2**-10 == 1/1024
+	{100, 10, 1}, // = 2**100 + 2**10 + 2**1
+	{0, -1, -2, -10},
+	// TODO(gri) add more test cases
+}
+
+// TestFloatAdd tests Float.Add/Sub by comparing the result of a "manual"
+// 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 := 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 := 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)
+					}
+
+					got.Sub(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)
+					}
+				}
+			}
+		}
+	}
+}
+
+// TestFloatAdd32 tests that Float.Add/Sub of numbers with
+// 24bit mantissa behaves like float32 addition/subtraction
+// (excluding denormal numbers).
+func TestFloatAdd32(t *testing.T) {
+	// 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++ {
+		for i := range [2]int{} {
+			x0, y0 := float64(base), float64(d)
+			if i&1 != 0 {
+				x0, y0 = y0, x0
+			}
+
+			x := NewFloat(x0)
+			y := NewFloat(y0)
+			z := new(Float).SetPrec(24)
+
+			z.Add(x, y)
+			got, acc := z.Float32()
+			want := float32(y0) + float32(x0)
+			if got != want || acc != Exact {
+				t.Errorf("d = %d: %g + %g = %g (%s); want %g (Exact)", d, x0, y0, got, acc, want)
+			}
+
+			z.Sub(z, y)
+			got, acc = z.Float32()
+			want = float32(want) - float32(y0)
+			if got != want || acc != Exact {
+				t.Errorf("d = %d: %g - %g = %g (%s); want %g (Exact)", d, x0+y0, y0, got, acc, want)
+			}
+		}
+	}
+}
+
+// TestFloatAdd64 tests that Float.Add/Sub of numbers with
+// 53bit mantissa behaves like float64 addition/subtraction.
+func TestFloatAdd64(t *testing.T) {
+	// chose base such that we cross the mantissa precision limit
+	const base = 1<<55 - 0x10 // 11...110000 (55 bits)
+	for d := 0; d <= 0x10; d++ {
+		for i := range [2]int{} {
+			x0, y0 := float64(base), float64(d)
+			if i&1 != 0 {
+				x0, y0 = y0, x0
+			}
+
+			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 (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 (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) {
+	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
+// 53bit mantissa behaves like float64 multiplication/division.
+func TestFloatMul64(t *testing.T) {
+	for _, test := range []struct {
+		x, y float64
+	}{
+		{0, 0},
+		{0, 1},
+		{1, 1},
+		{1, 1.5},
+		{1.234, 0.5678},
+		{2.718281828, 3.14159265358979},
+		{2.718281828e10, 3.14159265358979e-32},
+		{1.0 / 3, 1e200},
+	} {
+		for i := range [8]int{} {
+			x0, y0 := test.x, test.y
+			if i&1 != 0 {
+				x0 = -x0
+			}
+			if i&2 != 0 {
+				y0 = -y0
+			}
+			if i&4 != 0 {
+				x0, y0 = y0, x0
+			}
+
+			x := NewFloat(x0)
+			y := NewFloat(y0)
+			z := new(Float).SetPrec(53)
+
+			z.Mul(x, y)
+			got, _ := z.Float64()
+			want := x0 * y0
+			if got != want {
+				t.Errorf("%g * %g = %g; want %g", x0, y0, got, want)
+			}
+
+			if y0 == 0 {
+				continue // avoid division-by-zero
+			}
+			z.Quo(z, y)
+			got, _ = z.Float64()
+			want /= y0
+			if got != want {
+				t.Errorf("%g / %g = %g; want %g", x0*y0, y0, got, want)
+			}
+		}
+	}
+}
+
+func TestIssue6866(t *testing.T) {
+	for _, prec := range precList {
+		two := new(Float).SetPrec(prec).SetInt64(2)
+		one := new(Float).SetPrec(prec).SetInt64(1)
+		three := new(Float).SetPrec(prec).SetInt64(3)
+		msix := new(Float).SetPrec(prec).SetInt64(-6)
+		psix := new(Float).SetPrec(prec).SetInt64(+6)
+
+		p := new(Float).SetPrec(prec)
+		z1 := new(Float).SetPrec(prec)
+		z2 := new(Float).SetPrec(prec)
+
+		// z1 = 2 + 1.0/3*-6
+		p.Quo(one, three)
+		p.Mul(p, msix)
+		z1.Add(two, p)
+
+		// z2 = 2 - 1.0/3*+6
+		p.Quo(one, three)
+		p.Mul(p, psix)
+		z2.Sub(two, p)
+
+		if z1.Cmp(z2) != 0 {
+			t.Fatalf("prec %d: got z1 = %s != z2 = %s; want z1 == z2\n", prec, z1, z2)
+		}
+		if z1.Sign() != 0 {
+			t.Errorf("prec %d: got z1 = %s; want 0", prec, z1)
+		}
+		if z2.Sign() != 0 {
+			t.Errorf("prec %d: got z2 = %s; want 0", prec, z2)
+		}
+	}
+}
+
+func TestFloatQuo(t *testing.T) {
+	// TODO(gri) make the test vary these precisions
+	preci := 200 // precision of integer part
+	precf := 20  // precision of fractional part
+
+	for i := 0; i < 8; i++ {
+		// compute accurate (not rounded) result z
+		bits := Bits{preci - 1}
+		if i&3 != 0 {
+			bits = append(bits, 0)
+		}
+		if i&2 != 0 {
+			bits = append(bits, -1)
+		}
+		if i&1 != 0 {
+			bits = append(bits, -precf)
+		}
+		z := bits.Float()
+
+		// compute accurate x as z*y
+		y := NewFloat(3.14159265358979323e123)
+
+		x := new(Float).SetPrec(z.Prec() + y.Prec()).SetMode(ToZero)
+		x.Mul(z, y)
+
+		// leave for debugging
+		// fmt.Printf("x = %s\ny = %s\nz = %s\n", x, y, z)
+
+		if got := x.Acc(); got != Exact {
+			t.Errorf("got acc = %s; want exact", got)
+		}
+
+		// round accurate z for a variety of precisions and
+		// modes and compare against result of x / y.
+		for _, mode := range [...]RoundingMode{ToZero, ToNearestEven, AwayFromZero} {
+			for d := -5; d < 5; d++ {
+				prec := uint(preci + d)
+				got := new(Float).SetPrec(prec).SetMode(mode).Quo(x, y)
+				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)
+				}
+			}
+		}
+	}
+}
+
+// TestFloatQuoSmoke tests all divisions x/y for values x, y in the range [-n, +n];
+// it serves as a smoke test for basic correctness of division.
+func TestFloatQuoSmoke(t *testing.T) {
+	n := 1000
+	if testing.Short() {
+		n = 10
+	}
+
+	const dprec = 3         // max. precision variation
+	const prec = 10 + dprec // enough bits to hold n precisely
+	for x := -n; x <= n; x++ {
+		for y := -n; y < n; y++ {
+			if y == 0 {
+				continue
+			}
+
+			a := float64(x)
+			b := float64(y)
+			c := a / b
+
+			// vary operand precision (only ok as long as a, b can be represented correctly)
+			for ad := -dprec; ad <= dprec; ad++ {
+				for bd := -dprec; bd <= dprec; bd++ {
+					A := new(Float).SetPrec(uint(prec + ad)).SetFloat64(a)
+					B := new(Float).SetPrec(uint(prec + bd)).SetFloat64(b)
+					C := new(Float).SetPrec(53).Quo(A, B) // C has float64 mantissa width
+
+					cc, acc := C.Float64()
+					if cc != c {
+						t.Errorf("%g/%g = %s; want %.5g\n", a, b, C.Text('g', 5), c)
+						continue
+					}
+					if acc != Exact {
+						t.Errorf("%g/%g got %s result; want exact result", a, b, acc)
+					}
+				}
+			}
+		}
+	}
+}
+
+// TestFloatArithmeticSpecialValues tests that Float operations produce the
+// correct results for combinations of zero (±0), finite (±1 and ±2.71828),
+// and infinite (±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 {
+				yy.SetFloat64(y)
+				var (
+					op string
+					z  float64
+					f  func(z, x, y *Float) *Float
+				)
+				switch i {
+				case 0:
+					op = "+"
+					z = x + y
+					f = (*Float).Add
+				case 1:
+					op = "-"
+					z = x - y
+					f = (*Float).Sub
+				case 2:
+					op = "*"
+					z = x * y
+					f = (*Float).Mul
+				case 3:
+					op = "/"
+					z = x / y
+					f = (*Float).Quo
+				default:
+					panic("unreachable")
+				}
+				var errnan bool // set if execution of f panicked with ErrNaN
+				// protect execution of f
+				func() {
+					defer func() {
+						if p := recover(); p != nil {
+							_ = p.(ErrNaN) // re-panic if not ErrNaN
+							errnan = true
+						}
+					}()
+					f(got, xx, yy)
+				}()
+				if math.IsNaN(z) {
+					if !errnan {
+						t.Errorf("%5g %s %5g = %5s; want ErrNaN panic", x, op, y, got)
+					}
+					continue
+				}
+				if errnan {
+					t.Errorf("%5g %s %5g panicked with ErrNan; want %5s", x, op, y, want)
+					continue
+				}
+				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.8p+0", "0x.8p+0", "0x.8p+1", Exact}, // smoke test
+
+		{4, ToNearestEven, '+', "0", "0x.8p2147483647", "0x.8p+2147483647", Exact},
+		{4, ToNearestEven, '+', "0x.8p2147483500", "0x.8p2147483647", "0x.8p+2147483647", 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.fp+2147483647", 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.fp+2147483647", 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.8p+2147483647", 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.8p+0", "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.Text('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.Text('p', 0), test.op, y.Text('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
+// by the sign of the value to be rounded. Test that rounding happens after
+// the sign of a result has been set.
+// This test uses specific values that are known to fail if rounding is
+// "factored" out before setting the result sign.
+func TestFloatArithmeticRounding(t *testing.T) {
+	for _, test := range []struct {
+		mode       RoundingMode
+		prec       uint
+		x, y, want int64
+		op         byte
+	}{
+		{ToZero, 3, -0x8, -0x1, -0x8, '+'},
+		{AwayFromZero, 3, -0x8, -0x1, -0xa, '+'},
+		{ToNegativeInf, 3, -0x8, -0x1, -0xa, '+'},
+
+		{ToZero, 3, -0x8, 0x1, -0x8, '-'},
+		{AwayFromZero, 3, -0x8, 0x1, -0xa, '-'},
+		{ToNegativeInf, 3, -0x8, 0x1, -0xa, '-'},
+
+		{ToZero, 3, -0x9, 0x1, -0x8, '*'},
+		{AwayFromZero, 3, -0x9, 0x1, -0xa, '*'},
+		{ToNegativeInf, 3, -0x9, 0x1, -0xa, '*'},
+
+		{ToZero, 3, -0x9, 0x1, -0x8, '/'},
+		{AwayFromZero, 3, -0x9, 0x1, -0xa, '/'},
+		{ToNegativeInf, 3, -0x9, 0x1, -0xa, '/'},
+	} {
+		var x, y, z Float
+		x.SetInt64(test.x)
+		y.SetInt64(test.y)
+		z.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, acc := z.Int64(); got != test.want || acc != Exact {
+			t.Errorf("%s, %d bits: %d %c %d = %d (%s); want %d (Exact)",
+				test.mode, test.prec, test.x, test.op, test.y, got, acc, test.want,
+			)
+		}
+	}
+}
+
+// TestFloatCmpSpecialValues tests that Cmp produces the correct results for
+// combinations of zero (±0), finite (±1 and ±2.71828), and infinite (±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)
+			}
+			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) = %v; want %v", x, y, got, want)
+				}
+			}
+		}
+	}
+}
diff --git a/src/cmd/compile/internal/big/floatconv.go b/src/cmd/compile/internal/big/floatconv.go
new file mode 100644
index 0000000..4a070ca
--- /dev/null
+++ b/src/cmd/compile/internal/big/floatconv.go
@@ -0,0 +1,239 @@
+// 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 string-to-Float conversion functions.
+
+package big
+
+import (
+	"fmt"
+	"io"
+	"strings"
+)
+
+// SetString sets z to the value of s and returns z and a boolean indicating
+// success. s must be a floating-point number of the same format as accepted
+// by Parse, with base argument 0.
+func (z *Float) SetString(s string) (*Float, bool) {
+	if f, _, err := z.Parse(s, 0); err == nil {
+		return f, true
+	}
+	return nil, false
+}
+
+// scan is like Parse but reads the longest possible prefix representing a valid
+// floating point number from an io.ByteScanner rather than a string. It serves
+// as the implementation of Parse. It does not recognize ±Inf and does not expect
+// EOF at the end.
+func (z *Float) scan(r io.ByteScanner, base int) (f *Float, b int, err error) {
+	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 {
+		return
+	}
+
+	// mantissa
+	var fcount int // fractional digit count; valid if <= 0
+	z.mant, b, fcount, err = z.mant.scan(r, base, true)
+	if err != nil {
+		return
+	}
+
+	// exponent
+	var exp int64
+	var ebase int
+	exp, ebase, err = scanExponent(r, true)
+	if err != nil {
+		return
+	}
+
+	// special-case 0
+	if len(z.mant) == 0 {
+		z.prec = prec
+		z.acc = Exact
+		z.form = zero
+		f = z
+		return
+	}
+	// len(z.mant) > 0
+
+	// The mantissa may have a decimal point (fcount <= 0) and there
+	// may be a nonzero exponent exp. The decimal point amounts to a
+	// division by b**(-fcount). An exponent means multiplication by
+	// ebase**exp. Finally, mantissa normalization (shift left) requires
+	// a correcting multiplication by 2**(-shiftcount). Multiplications
+	// are commutative, so we can apply them in any order as long as there
+	// is no loss of precision. We only have powers of 2 and 10; keep
+	// track via separate exponents exp2 and exp10.
+
+	// normalize mantissa and get initial binary exponent
+	var exp2 = int64(len(z.mant))*_W - fnorm(z.mant)
+
+	// determine binary or decimal exponent contribution of decimal point
+	var exp10 int64
+	if fcount < 0 {
+		// The mantissa has a "decimal" point ddd.dddd; and
+		// -fcount is the number of digits to the right of '.'.
+		// Adjust relevant exponent accodingly.
+		switch b {
+		case 16:
+			fcount *= 4 // hexadecimal digits are 4 bits each
+			fallthrough
+		case 2:
+			exp2 += int64(fcount)
+		default: // b == 10
+			exp10 = int64(fcount)
+		}
+		// we don't need fcount anymore
+	}
+
+	// take actual exponent into account
+	if ebase == 2 {
+		exp2 += exp
+	} else { // ebase == 10
+		exp10 += exp
+	}
+	// we don't need exp anymore
+
+	// apply 2**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
+		z.round(0)
+		return
+	}
+	// exp10 != 0
+
+	// apply 10**exp10
+	p := new(Float).SetPrec(z.Prec() + 64) // use more bits for p -- TODO(gri) what is the right number?
+	if exp10 < 0 {
+		z.uquo(z, p.pow10(-exp10))
+	} else {
+		z.umul(z, p.pow10(exp10))
+	}
+
+	return
+}
+
+// These powers of 10 can be represented exactly as a float64.
+var pow10tab = [...]float64{
+	1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
+	1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
+}
+
+// pow10 sets z to 10**n and returns z.
+// n must not be negative.
+func (z *Float) pow10(n int64) *Float {
+	if n < 0 {
+		panic("pow10 called with negative argument")
+	}
+
+	const m = int64(len(pow10tab) - 1)
+	if n <= m {
+		return z.SetFloat64(pow10tab[n])
+	}
+	// n > m
+
+	z.SetFloat64(pow10tab[m])
+	n -= m
+
+	// use more bits for f than for z
+	// TODO(gri) what is the right number?
+	f := new(Float).SetPrec(z.Prec() + 64).SetInt64(10)
+
+	for n > 0 {
+		if n&1 != 0 {
+			z.Mul(z, f)
+		}
+		f.Mul(f, f)
+		n >>= 1
+	}
+
+	return z
+}
+
+// Parse parses s which must contain a text representation of a floating-
+// point number with a mantissa in the given conversion base (the exponent
+// is always a decimal number), or a string representing an infinite value.
+//
+// It sets z to the (possibly rounded) value of the corresponding floating-
+// point value, and returns z, the actual base b, and an error err, if any.
+// If z's precision is 0, it is changed to 64 before rounding takes effect.
+// The number must be of the form:
+//
+//	number   = [ sign ] [ prefix ] mantissa [ exponent ] | infinity .
+//	sign     = "+" | "-" .
+//      prefix   = "0" ( "x" | "X" | "b" | "B" ) .
+//	mantissa = digits | digits "." [ digits ] | "." digits .
+//	exponent = ( "E" | "e" | "p" ) [ sign ] digits .
+//	digits   = digit { digit } .
+//	digit    = "0" ... "9" | "a" ... "z" | "A" ... "Z" .
+//      infinity = [ sign ] ( "inf" | "Inf" ) .
+//
+// The base argument must be 0, 2, 10, or 16. Providing an invalid base
+// argument will lead to a run-time panic.
+//
+// For base 0, the number prefix determines the actual base: A prefix of
+// "0x" or "0X" selects base 16, and a "0b" or "0B" prefix selects
+// base 2; otherwise, the actual base is 10 and no prefix is accepted.
+// The octal prefix "0" is not supported (a leading "0" is simply
+// considered a "0").
+//
+// A "p" exponent indicates a binary (rather then decimal) exponent;
+// for instance "0x1.fffffffffffffp1023" (using base 0) represents the
+// maximum float64 value. For hexadecimal mantissae, the exponent must
+// be binary, if present (an "e" or "E" exponent indicator cannot be
+// distinguished from a mantissa digit).
+//
+// The returned *Float f is nil and the value of z is valid but not
+// defined if an error is reported.
+//
+func (z *Float) Parse(s string, base int) (f *Float, b int, err error) {
+	// scan doesn't handle ±Inf
+	if len(s) == 3 && (s == "Inf" || s == "inf") {
+		f = z.SetInf(false)
+		return
+	}
+	if len(s) == 4 && (s[0] == '+' || s[0] == '-') && (s[1:] == "Inf" || s[1:] == "inf") {
+		f = z.SetInf(s[0] == '-')
+		return
+	}
+
+	r := strings.NewReader(s)
+	if f, b, err = z.scan(r, base); err != nil {
+		return
+	}
+
+	// entire string must have been consumed
+	if ch, err2 := r.ReadByte(); err2 == nil {
+		err = fmt.Errorf("expected end of string, found %q", ch)
+	} else if err2 != io.EOF {
+		err = err2
+	}
+
+	return
+}
+
+// ParseFloat is like f.Parse(s, base) with f set to the given precision
+// and rounding mode.
+func ParseFloat(s string, base int, prec uint, mode RoundingMode) (f *Float, b int, err error) {
+	return new(Float).SetPrec(prec).SetMode(mode).Parse(s, base)
+}
diff --git a/src/cmd/compile/internal/big/floatconv_test.go b/src/cmd/compile/internal/big/floatconv_test.go
new file mode 100644
index 0000000..4f23953
--- /dev/null
+++ b/src/cmd/compile/internal/big/floatconv_test.go
@@ -0,0 +1,573 @@
+// 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
+
+import (
+	"fmt"
+	"math"
+	"strconv"
+	"testing"
+)
+
+func TestFloatSetFloat64String(t *testing.T) {
+	inf := math.Inf(0)
+	nan := math.NaN()
+
+	for _, test := range []struct {
+		s string
+		x float64 // NaNs represent invalid inputs
+	}{
+		// basics
+		{"0", 0},
+		{"-0", -0},
+		{"+0", 0},
+		{"1", 1},
+		{"-1", -1},
+		{"+1", 1},
+		{"1.234", 1.234},
+		{"-1.234", -1.234},
+		{"+1.234", 1.234},
+		{".1", 0.1},
+		{"1.", 1},
+		{"+1.", 1},
+
+		// various zeros
+		{"0e100", 0},
+		{"-0e+100", 0},
+		{"+0e-100", 0},
+		{"0E100", 0},
+		{"-0E+100", 0},
+		{"+0E-100", 0},
+
+		// various decimal exponent formats
+		{"1.e10", 1e10},
+		{"1e+10", 1e10},
+		{"+1e-10", 1e-10},
+		{"1E10", 1e10},
+		{"1.E+10", 1e10},
+		{"+1E-10", 1e-10},
+
+		// infinities
+		{"Inf", inf},
+		{"+Inf", inf},
+		{"-Inf", -inf},
+		{"inf", inf},
+		{"+inf", inf},
+		{"-inf", -inf},
+
+		// invalid numbers
+		{"", nan},
+		{"-", nan},
+		{"0x", nan},
+		{"0e", nan},
+		{"1.2ef", nan},
+		{"2..3", nan},
+		{"123..", nan},
+		{"infinity", nan},
+		{"foobar", nan},
+
+		// misc decimal values
+		{"3.14159265", 3.14159265},
+		{"-687436.79457e-245", -687436.79457e-245},
+		{"-687436.79457E245", -687436.79457e245},
+		{".0000000000000000000000000000000000000001", 1e-40},
+		{"+10000000000000000000000000000000000000000e-0", 1e40},
+
+		// decimal mantissa, binary exponent
+		{"0p0", 0},
+		{"-0p0", -0},
+		{"1p10", 1 << 10},
+		{"1p+10", 1 << 10},
+		{"+1p-10", 1.0 / (1 << 10)},
+		{"1024p-12", 0.25},
+		{"-1p10", -1024},
+		{"1.5p1", 3},
+
+		// binary mantissa, decimal exponent
+		{"0b0", 0},
+		{"-0b0", -0},
+		{"0b0e+10", 0},
+		{"-0b0e-10", -0},
+		{"0b1010", 10},
+		{"0B1010E2", 1000},
+		{"0b.1", 0.5},
+		{"0b.001", 0.125},
+		{"0b.001e3", 125},
+
+		// binary mantissa, binary exponent
+		{"0b0p+10", 0},
+		{"-0b0p-10", -0},
+		{"0b.1010p4", 10},
+		{"0b1p-1", 0.5},
+		{"0b001p-3", 0.125},
+		{"0b.001p3", 1},
+		{"0b0.01p2", 1},
+
+		// hexadecimal mantissa and exponent
+		{"0x0", 0},
+		{"-0x0", -0},
+		{"0x0p+10", 0},
+		{"-0x0p-10", -0},
+		{"0xff", 255},
+		{"0X.8p1", 1},
+		{"-0X0.00008p16", -0.5},
+		{"0x0.0000000000001p-1022", math.SmallestNonzeroFloat64},
+		{"0x1.fffffffffffffp1023", math.MaxFloat64},
+	} {
+		var x Float
+		x.SetPrec(53)
+		_, ok := x.SetString(test.s)
+		if math.IsNaN(test.x) {
+			// test.s is invalid
+			if ok {
+				t.Errorf("%s: want parse error", test.s)
+			}
+			continue
+		}
+		// test.s is valid
+		if !ok {
+			t.Errorf("%s: got parse error", test.s)
+			continue
+		}
+		f, _ := x.Float64()
+		want := new(Float).SetFloat64(test.x)
+		if x.Cmp(want) != 0 {
+			t.Errorf("%s: got %s (%v); want %v", test.s, &x, f, test.x)
+		}
+	}
+}
+
+const (
+	below1e23 = 99999999999999974834176
+	above1e23 = 100000000000000008388608
+)
+
+func TestFloat64Text(t *testing.T) {
+	for _, test := range []struct {
+		x      float64
+		format byte
+		prec   int
+		want   string
+	}{
+		{0, 'f', 0, "0"},
+		{math.Copysign(0, -1), 'f', 0, "-0"},
+		{1, 'f', 0, "1"},
+		{-1, 'f', 0, "-1"},
+
+		{0.001, 'e', 0, "1e-03"},
+		{0.459, 'e', 0, "5e-01"},
+		{1.459, 'e', 0, "1e+00"},
+		{2.459, 'e', 1, "2.5e+00"},
+		{3.459, 'e', 2, "3.46e+00"},
+		{4.459, 'e', 3, "4.459e+00"},
+		{5.459, 'e', 4, "5.4590e+00"},
+
+		{0.001, 'f', 0, "0"},
+		{0.459, 'f', 0, "0"},
+		{1.459, 'f', 0, "1"},
+		{2.459, 'f', 1, "2.5"},
+		{3.459, 'f', 2, "3.46"},
+		{4.459, 'f', 3, "4.459"},
+		{5.459, 'f', 4, "5.4590"},
+
+		{0, 'b', 0, "0"},
+		{math.Copysign(0, -1), 'b', 0, "-0"},
+		{1.0, 'b', 0, "4503599627370496p-52"},
+		{-1.0, 'b', 0, "-4503599627370496p-52"},
+		{4503599627370496, 'b', 0, "4503599627370496p+0"},
+
+		{0, 'p', 0, "0"},
+		{math.Copysign(0, -1), 'p', 0, "-0"},
+		{1024.0, 'p', 0, "0x.8p+11"},
+		{-1024.0, 'p', 0, "-0x.8p+11"},
+
+		// all test cases below from strconv/ftoa_test.go
+		{1, 'e', 5, "1.00000e+00"},
+		{1, 'f', 5, "1.00000"},
+		{1, 'g', 5, "1"},
+		// {1, 'g', -1, "1"},
+		// {20, 'g', -1, "20"},
+		// {1234567.8, 'g', -1, "1.2345678e+06"},
+		// {200000, 'g', -1, "200000"},
+		// {2000000, 'g', -1, "2e+06"},
+
+		// g conversion and zero suppression
+		{400, 'g', 2, "4e+02"},
+		{40, 'g', 2, "40"},
+		{4, 'g', 2, "4"},
+		{.4, 'g', 2, "0.4"},
+		{.04, 'g', 2, "0.04"},
+		{.004, 'g', 2, "0.004"},
+		{.0004, 'g', 2, "0.0004"},
+		{.00004, 'g', 2, "4e-05"},
+		{.000004, 'g', 2, "4e-06"},
+
+		{0, 'e', 5, "0.00000e+00"},
+		{0, 'f', 5, "0.00000"},
+		{0, 'g', 5, "0"},
+		// {0, 'g', -1, "0"},
+
+		{-1, 'e', 5, "-1.00000e+00"},
+		{-1, 'f', 5, "-1.00000"},
+		{-1, 'g', 5, "-1"},
+		// {-1, 'g', -1, "-1"},
+
+		{12, 'e', 5, "1.20000e+01"},
+		{12, 'f', 5, "12.00000"},
+		{12, 'g', 5, "12"},
+		// {12, 'g', -1, "12"},
+
+		{123456700, 'e', 5, "1.23457e+08"},
+		{123456700, 'f', 5, "123456700.00000"},
+		{123456700, 'g', 5, "1.2346e+08"},
+		// {123456700, 'g', -1, "1.234567e+08"},
+
+		{1.2345e6, 'e', 5, "1.23450e+06"},
+		{1.2345e6, 'f', 5, "1234500.00000"},
+		{1.2345e6, 'g', 5, "1.2345e+06"},
+
+		{1e23, 'e', 17, "9.99999999999999916e+22"},
+		{1e23, 'f', 17, "99999999999999991611392.00000000000000000"},
+		{1e23, 'g', 17, "9.9999999999999992e+22"},
+
+		// {1e23, 'e', -1, "1e+23"},
+		// {1e23, 'f', -1, "100000000000000000000000"},
+		// {1e23, 'g', -1, "1e+23"},
+
+		{below1e23, 'e', 17, "9.99999999999999748e+22"},
+		{below1e23, 'f', 17, "99999999999999974834176.00000000000000000"},
+		{below1e23, 'g', 17, "9.9999999999999975e+22"},
+
+		// {below1e23, 'e', -1, "9.999999999999997e+22"},
+		// {below1e23, 'f', -1, "99999999999999970000000"},
+		// {below1e23, 'g', -1, "9.999999999999997e+22"},
+
+		{above1e23, 'e', 17, "1.00000000000000008e+23"},
+		{above1e23, 'f', 17, "100000000000000008388608.00000000000000000"},
+		// {above1e23, 'g', 17, "1.0000000000000001e+23"},
+
+		// {above1e23, 'e', -1, "1.0000000000000001e+23"},
+		// {above1e23, 'f', -1, "100000000000000010000000"},
+		// {above1e23, 'g', -1, "1.0000000000000001e+23"},
+
+		// {fdiv(5e-304, 1e20), 'g', -1, "5e-324"},
+		// {fdiv(-5e-304, 1e20), 'g', -1, "-5e-324"},
+
+		// {32, 'g', -1, "32"},
+		// {32, 'g', 0, "3e+01"},
+
+		// {100, 'x', -1, "%x"},
+
+		// {math.NaN(), 'g', -1, "NaN"},
+		// {-math.NaN(), 'g', -1, "NaN"},
+		{math.Inf(0), 'g', -1, "+Inf"},
+		{math.Inf(-1), 'g', -1, "-Inf"},
+		{-math.Inf(0), 'g', -1, "-Inf"},
+
+		{-1, 'b', -1, "-4503599627370496p-52"},
+
+		// fixed bugs
+		{0.9, 'f', 1, "0.9"},
+		{0.09, 'f', 1, "0.1"},
+		{0.0999, 'f', 1, "0.1"},
+		{0.05, 'f', 1, "0.1"},
+		{0.05, 'f', 0, "0"},
+		{0.5, 'f', 1, "0.5"},
+		{0.5, 'f', 0, "0"},
+		{1.5, 'f', 0, "2"},
+
+		// http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/
+		// {2.2250738585072012e-308, 'g', -1, "2.2250738585072014e-308"},
+		// http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/
+		// {2.2250738585072011e-308, 'g', -1, "2.225073858507201e-308"},
+
+		// Issue 2625.
+		{383260575764816448, 'f', 0, "383260575764816448"},
+		// {383260575764816448, 'g', -1, "3.8326057576481645e+17"},
+	} {
+		f := new(Float).SetFloat64(test.x)
+		got := f.Text(test.format, test.prec)
+		if got != test.want {
+			t.Errorf("%v: got %s; want %s", test, got, test.want)
+		}
+
+		if test.format == 'b' && test.x == 0 {
+			continue // 'b' format in strconv.Float requires knowledge of bias for 0.0
+		}
+		if test.format == 'p' {
+			continue // 'p' format not supported in strconv.Format
+		}
+
+		// verify that Float format matches strconv format
+		want := strconv.FormatFloat(test.x, test.format, test.prec, 64)
+		if got != want {
+			t.Errorf("%v: got %s; want %s (strconv)", test, got, want)
+		}
+	}
+}
+
+func TestFloatText(t *testing.T) {
+	for _, test := range []struct {
+		x      string
+		prec   uint
+		format byte
+		digits int
+		want   string
+	}{
+		{"0", 10, 'f', 0, "0"},
+		{"-0", 10, 'f', 0, "-0"},
+		{"1", 10, 'f', 0, "1"},
+		{"-1", 10, 'f', 0, "-1"},
+
+		{"1.459", 100, 'e', 0, "1e+00"},
+		{"2.459", 100, 'e', 1, "2.5e+00"},
+		{"3.459", 100, 'e', 2, "3.46e+00"},
+		{"4.459", 100, 'e', 3, "4.459e+00"},
+		{"5.459", 100, 'e', 4, "5.4590e+00"},
+
+		{"1.459", 100, 'E', 0, "1E+00"},
+		{"2.459", 100, 'E', 1, "2.5E+00"},
+		{"3.459", 100, 'E', 2, "3.46E+00"},
+		{"4.459", 100, 'E', 3, "4.459E+00"},
+		{"5.459", 100, 'E', 4, "5.4590E+00"},
+
+		{"1.459", 100, 'f', 0, "1"},
+		{"2.459", 100, 'f', 1, "2.5"},
+		{"3.459", 100, 'f', 2, "3.46"},
+		{"4.459", 100, 'f', 3, "4.459"},
+		{"5.459", 100, 'f', 4, "5.4590"},
+
+		{"1.459", 100, 'g', 0, "1"},
+		{"2.459", 100, 'g', 1, "2"},
+		{"3.459", 100, 'g', 2, "3.5"},
+		{"4.459", 100, 'g', 3, "4.46"},
+		{"5.459", 100, 'g', 4, "5.459"},
+
+		{"1459", 53, 'g', 0, "1e+03"},
+		{"2459", 53, 'g', 1, "2e+03"},
+		{"3459", 53, 'g', 2, "3.5e+03"},
+		{"4459", 53, 'g', 3, "4.46e+03"},
+		{"5459", 53, 'g', 4, "5459"},
+
+		{"1459", 53, 'G', 0, "1E+03"},
+		{"2459", 53, 'G', 1, "2E+03"},
+		{"3459", 53, 'G', 2, "3.5E+03"},
+		{"4459", 53, 'G', 3, "4.46E+03"},
+		{"5459", 53, 'G', 4, "5459"},
+
+		{"3", 10, 'e', 40, "3.0000000000000000000000000000000000000000e+00"},
+		{"3", 10, 'f', 40, "3.0000000000000000000000000000000000000000"},
+		{"3", 10, 'g', 40, "3"},
+
+		{"3e40", 100, 'e', 40, "3.0000000000000000000000000000000000000000e+40"},
+		{"3e40", 100, 'f', 4, "30000000000000000000000000000000000000000.0000"},
+		{"3e40", 100, 'g', 40, "3e+40"},
+
+		// make sure "stupid" exponents don't stall the machine
+		{"1e1000000", 64, 'p', 0, "0x.88b3a28a05eade3ap+3321929"},
+		{"1e1000000000", 64, 'p', 0, "0x.ecc5f45aa573d3p+1538481529"},
+		{"1e-1000000", 64, 'p', 0, "0x.efb4542cc8ca418ap-3321928"},
+		{"1e-1000000000", 64, 'p', 0, "0x.8a64dd983a4c7dabp-1538481528"},
+
+		// TODO(gri) need tests for actual large Floats
+
+		{"0", 53, 'b', 0, "0"},
+		{"-0", 53, 'b', 0, "-0"},
+		{"1.0", 53, 'b', 0, "4503599627370496p-52"},
+		{"-1.0", 53, 'b', 0, "-4503599627370496p-52"},
+		{"4503599627370496", 53, 'b', 0, "4503599627370496p+0"},
+
+		// issue 9939
+		{"3", 350, 'b', 0, "1720123961992553633708115671476565205597423741876210842803191629540192157066363606052513914832594264915968p-348"},
+		{"03", 350, 'b', 0, "1720123961992553633708115671476565205597423741876210842803191629540192157066363606052513914832594264915968p-348"},
+		{"3.", 350, 'b', 0, "1720123961992553633708115671476565205597423741876210842803191629540192157066363606052513914832594264915968p-348"},
+		{"3.0", 350, 'b', 0, "1720123961992553633708115671476565205597423741876210842803191629540192157066363606052513914832594264915968p-348"},
+		{"3.00", 350, 'b', 0, "1720123961992553633708115671476565205597423741876210842803191629540192157066363606052513914832594264915968p-348"},
+		{"3.000", 350, 'b', 0, "1720123961992553633708115671476565205597423741876210842803191629540192157066363606052513914832594264915968p-348"},
+
+		{"3", 350, 'p', 0, "0x.cp+2"},
+		{"03", 350, 'p', 0, "0x.cp+2"},
+		{"3.", 350, 'p', 0, "0x.cp+2"},
+		{"3.0", 350, 'p', 0, "0x.cp+2"},
+		{"3.00", 350, 'p', 0, "0x.cp+2"},
+		{"3.000", 350, 'p', 0, "0x.cp+2"},
+
+		{"0", 64, 'p', 0, "0"},
+		{"-0", 64, 'p', 0, "-0"},
+		{"1024.0", 64, 'p', 0, "0x.8p+11"},
+		{"-1024.0", 64, 'p', 0, "-0x.8p+11"},
+
+		// unsupported format
+		{"3.14", 64, 'x', 0, "%x"},
+		{"-3.14", 64, 'x', 0, "%x"},
+	} {
+		f, _, err := ParseFloat(test.x, 0, test.prec, ToNearestEven)
+		if err != nil {
+			t.Errorf("%v: %s", test, err)
+			continue
+		}
+
+		got := f.Text(test.format, test.digits)
+		if got != test.want {
+			t.Errorf("%v: got %s; want %s", test, got, test.want)
+		}
+
+		// compare with strconv.FormatFloat output if possible
+		// ('p' format is not supported by strconv.FormatFloat,
+		// and its output for 0.0 prints a biased exponent value
+		// as in 0p-1074 which makes no sense to emulate here)
+		if test.prec == 53 && test.format != 'p' && f.Sign() != 0 {
+			f64, acc := f.Float64()
+			if acc != Exact {
+				t.Errorf("%v: expected exact conversion to float64", test)
+				continue
+			}
+			got := strconv.FormatFloat(f64, test.format, test.digits, 64)
+			if got != test.want {
+				t.Errorf("%v: got %s; want %s", test, got, test.want)
+			}
+		}
+	}
+}
+
+func TestFloatFormat(t *testing.T) {
+	for _, test := range []struct {
+		format string
+		value  interface{} // float32, float64, or string (== 512bit *Float)
+		want   string
+	}{
+		// TODO(gri) uncomment the disabled 'g'/'G' formats
+		// 	     below once (*Float).Text supports prec < 0
+
+		// from fmt/fmt_test.go
+		{"%+.3e", 0.0, "+0.000e+00"},
+		{"%+.3e", 1.0, "+1.000e+00"},
+		{"%+.3f", -1.0, "-1.000"},
+		{"%+.3F", -1.0, "-1.000"},
+		{"%+.3F", float32(-1.0), "-1.000"},
+		{"%+07.2f", 1.0, "+001.00"},
+		{"%+07.2f", -1.0, "-001.00"},
+		{"%+10.2f", +1.0, "     +1.00"},
+		{"%+10.2f", -1.0, "     -1.00"},
+		{"% .3E", -1.0, "-1.000E+00"},
+		{"% .3e", 1.0, " 1.000e+00"},
+		{"%+.3g", 0.0, "+0"},
+		{"%+.3g", 1.0, "+1"},
+		{"%+.3g", -1.0, "-1"},
+		{"% .3g", -1.0, "-1"},
+		{"% .3g", 1.0, " 1"},
+		{"%b", float32(1.0), "8388608p-23"},
+		{"%b", 1.0, "4503599627370496p-52"},
+
+		// from fmt/fmt_test.go: old test/fmt_test.go
+		{"%e", 1.0, "1.000000e+00"},
+		{"%e", 1234.5678e3, "1.234568e+06"},
+		{"%e", 1234.5678e-8, "1.234568e-05"},
+		{"%e", -7.0, "-7.000000e+00"},
+		{"%e", -1e-9, "-1.000000e-09"},
+		{"%f", 1234.5678e3, "1234567.800000"},
+		{"%f", 1234.5678e-8, "0.000012"},
+		{"%f", -7.0, "-7.000000"},
+		{"%f", -1e-9, "-0.000000"},
+		// {"%g", 1234.5678e3, "1.2345678e+06"},
+		// {"%g", float32(1234.5678e3), "1.2345678e+06"},
+		// {"%g", 1234.5678e-8, "1.2345678e-05"},
+		{"%g", -7.0, "-7"},
+		{"%g", -1e-9, "-1e-09"},
+		{"%g", float32(-1e-9), "-1e-09"},
+		{"%E", 1.0, "1.000000E+00"},
+		{"%E", 1234.5678e3, "1.234568E+06"},
+		{"%E", 1234.5678e-8, "1.234568E-05"},
+		{"%E", -7.0, "-7.000000E+00"},
+		{"%E", -1e-9, "-1.000000E-09"},
+		// {"%G", 1234.5678e3, "1.2345678E+06"},
+		// {"%G", float32(1234.5678e3), "1.2345678E+06"},
+		// {"%G", 1234.5678e-8, "1.2345678E-05"},
+		{"%G", -7.0, "-7"},
+		{"%G", -1e-9, "-1E-09"},
+		{"%G", float32(-1e-9), "-1E-09"},
+
+		{"%20.6e", 1.2345e3, "        1.234500e+03"},
+		{"%20.6e", 1.2345e-3, "        1.234500e-03"},
+		{"%20e", 1.2345e3, "        1.234500e+03"},
+		{"%20e", 1.2345e-3, "        1.234500e-03"},
+		{"%20.8e", 1.2345e3, "      1.23450000e+03"},
+		{"%20f", 1.23456789e3, "         1234.567890"},
+		{"%20f", 1.23456789e-3, "            0.001235"},
+		{"%20f", 12345678901.23456789, "  12345678901.234568"},
+		{"%-20f", 1.23456789e3, "1234.567890         "},
+		{"%20.8f", 1.23456789e3, "       1234.56789000"},
+		{"%20.8f", 1.23456789e-3, "          0.00123457"},
+		// {"%g", 1.23456789e3, "1234.56789"},
+		// {"%g", 1.23456789e-3, "0.00123456789"},
+		// {"%g", 1.23456789e20, "1.23456789e+20"},
+		{"%20e", math.Inf(1), "                +Inf"},
+		{"%-20f", math.Inf(-1), "-Inf                "},
+
+		// from fmt/fmt_test.go: comparison of padding rules with C printf
+		{"%.2f", 1.0, "1.00"},
+		{"%.2f", -1.0, "-1.00"},
+		{"% .2f", 1.0, " 1.00"},
+		{"% .2f", -1.0, "-1.00"},
+		{"%+.2f", 1.0, "+1.00"},
+		{"%+.2f", -1.0, "-1.00"},
+		{"%7.2f", 1.0, "   1.00"},
+		{"%7.2f", -1.0, "  -1.00"},
+		{"% 7.2f", 1.0, "   1.00"},
+		{"% 7.2f", -1.0, "  -1.00"},
+		{"%+7.2f", 1.0, "  +1.00"},
+		{"%+7.2f", -1.0, "  -1.00"},
+		{"%07.2f", 1.0, "0001.00"},
+		{"%07.2f", -1.0, "-001.00"},
+		{"% 07.2f", 1.0, " 001.00"},
+		{"% 07.2f", -1.0, "-001.00"},
+		{"%+07.2f", 1.0, "+001.00"},
+		{"%+07.2f", -1.0, "-001.00"},
+
+		// from fmt/fmt_test.go: zero padding does not apply to infinities
+		{"%020f", math.Inf(-1), "                -Inf"},
+		{"%020f", math.Inf(+1), "                +Inf"},
+		{"% 020f", math.Inf(-1), "                -Inf"},
+		{"% 020f", math.Inf(+1), "                 Inf"},
+		{"%+020f", math.Inf(-1), "                -Inf"},
+		{"%+020f", math.Inf(+1), "                +Inf"},
+		{"%20f", -1.0, "           -1.000000"},
+
+		// handle %v like %g
+		{"%v", 0.0, "0"},
+		{"%v", -7.0, "-7"},
+		{"%v", -1e-9, "-1e-09"},
+		{"%v", float32(-1e-9), "-1e-09"},
+		{"%010v", 0.0, "0000000000"},
+		{"%010v", 0.0, "0000000000"},
+
+		// *Float cases
+		{"%.20f", "1e-20", "0.00000000000000000001"},
+		{"%.20f", "-1e-20", "-0.00000000000000000001"},
+		{"%30.20f", "-1e-20", "       -0.00000000000000000001"},
+		{"%030.20f", "-1e-20", "-00000000.00000000000000000001"},
+		{"%030.20f", "+1e-20", "000000000.00000000000000000001"},
+		{"% 030.20f", "+1e-20", " 00000000.00000000000000000001"},
+
+		// erroneous formats
+		{"%s", 1.0, "%!s(*big.Float=1)"},
+	} {
+		value := new(Float)
+		switch v := test.value.(type) {
+		case float32:
+			value.SetPrec(24).SetFloat64(float64(v))
+		case float64:
+			value.SetPrec(53).SetFloat64(v)
+		case string:
+			value.SetPrec(512).Parse(v, 0)
+		default:
+			t.Fatalf("unsupported test value: %v (%T)", v, v)
+		}
+
+		if got := fmt.Sprintf(test.format, value); got != test.want {
+			t.Errorf("%v: got %q; want %q", test, got, test.want)
+		}
+	}
+}
diff --git a/src/cmd/compile/internal/big/floatexample_test.go b/src/cmd/compile/internal/big/floatexample_test.go
new file mode 100644
index 0000000..6fd291c
--- /dev/null
+++ b/src/cmd/compile/internal/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 (
+	"cmd/compile/internal/big"
+	"fmt"
+	"math"
+)
+
+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 = %.10g (%s, prec = %d, acc = %s)\n", &x, x.Text('p', 0), x.Prec(), x.Acc())
+	fmt.Printf("y = %.10g (%s, prec = %d, acc = %s)\n", &y, y.Text('p', 0), y.Prec(), y.Acc())
+	fmt.Printf("z = %.10g (%s, prec = %d, acc = %s)\n", &z, z.Text('p', 0), z.Prec(), z.Acc())
+	// Output:
+	// x = 1000 (0x.fap+10, prec = 64, acc = Exact)
+	// y = 2.718281828 (0x.adf85458248cd8p+2, prec = 53, acc = Exact)
+	// z = 1002.718282 (0x.faadf854p+10, 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("%4g  %4g  %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/cmd/compile/internal/big/ftoa.go b/src/cmd/compile/internal/big/ftoa.go
new file mode 100644
index 0000000..5c5f2ce
--- /dev/null
+++ b/src/cmd/compile/internal/big/ftoa.go
@@ -0,0 +1,393 @@
+// 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 Float-to-string conversion functions.
+// It is closely following the corresponding implementation
+// in strconv/ftoa.go, but modified and simplified for Float.
+
+package big
+
+import (
+	"fmt"
+	"strconv"
+	"strings"
+)
+
+// Text converts the floating-point number x to a string according
+// to the given format and precision prec. The format is one of:
+//
+//	'e'	-d.dddde±dd, decimal exponent, at least two (possibly 0) exponent digits
+//	'E'	-d.ddddE±dd, decimal exponent, at least two (possibly 0) exponent digits
+//	'f'	-ddddd.dddd, no exponent
+//	'g'	like 'e' for large exponents, like 'f' otherwise
+//	'G'	like 'E' for large exponents, like 'f' otherwise
+//	'b'	-ddddddp±dd, binary exponent
+//	'p'	-0x.dddp±dd, binary exponent, hexadecimal mantissa
+//
+// For the binary exponent formats, the mantissa is printed in normalized form:
+//
+//	'b'	decimal integer mantissa using x.Prec() bits, or -0
+//	'p'	hexadecimal fraction with 0.5 <= 0.mantissa < 1.0, or -0
+//
+// If format is a different character, Text returns a "%" followed by the
+// unrecognized format character.
+//
+// The precision prec controls the number of digits (excluding the exponent)
+// printed by the 'e', 'E', 'f', 'g', and 'G' formats. For 'e', 'E', and 'f'
+// it is the number of digits after the decimal point. For 'g' and 'G' it is
+// the total number of digits. A negative precision selects the smallest
+// number of digits necessary to identify the value x uniquely.
+// The prec value is ignored for the 'b' or 'p' format.
+//
+// BUG(gri) Float.Text does not accept negative precisions (issue #10991).
+func (x *Float) Text(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))
+}
+
+// String formats x like x.Text('g', 10).
+func (x *Float) String() string {
+	return x.Text('g', 10)
+}
+
+// Append appends to buf the string form of the floating-point number x,
+// as generated by x.Text, and returns the extended buffer.
+func (x *Float) Append(buf []byte, fmt byte, prec int) []byte {
+	// sign
+	if x.neg {
+		buf = append(buf, '-')
+	}
+
+	// Inf
+	if x.form == inf {
+		if !x.neg {
+			buf = append(buf, '+')
+		}
+		return append(buf, "Inf"...)
+	}
+
+	// pick off easy formats
+	switch fmt {
+	case 'b':
+		return x.fmtB(buf)
+	case 'p':
+		return x.fmtP(buf)
+	}
+
+	// Algorithm:
+	//   1) convert Float to multiprecision decimal
+	//   2) round to desired precision
+	//   3) read digits out and format
+
+	// 1) convert Float to multiprecision decimal
+	var d decimal // == 0.0
+	if x.form == finite {
+		d.init(x.mant, int(x.exp)-x.mant.bitLen())
+	}
+
+	// 2) round to desired precision
+	shortest := false
+	if prec < 0 {
+		shortest = true
+		panic("unimplemented")
+		// TODO(gri) complete this
+		// roundShortest(&d, f.mant, int(f.exp))
+		// Precision for shortest representation mode.
+		switch fmt {
+		case 'e', 'E':
+			prec = len(d.mant) - 1
+		case 'f':
+			prec = max(len(d.mant)-d.exp, 0)
+		case 'g', 'G':
+			prec = len(d.mant)
+		}
+	} else {
+		// round appropriately
+		switch fmt {
+		case 'e', 'E':
+			// one digit before and number of digits after decimal point
+			d.round(1 + prec)
+		case 'f':
+			// number of digits before and after decimal point
+			d.round(d.exp + prec)
+		case 'g', 'G':
+			if prec == 0 {
+				prec = 1
+			}
+			d.round(prec)
+		}
+	}
+
+	// 3) read digits out and format
+	switch fmt {
+	case 'e', 'E':
+		return fmtE(buf, fmt, prec, d)
+	case 'f':
+		return fmtF(buf, prec, d)
+	case 'g', 'G':
+		// trim trailing fractional zeros in %e format
+		eprec := prec
+		if eprec > len(d.mant) && len(d.mant) >= d.exp {
+			eprec = len(d.mant)
+		}
+		// %e is used if the exponent from the conversion
+		// is less than -4 or greater than or equal to the precision.
+		// If precision was the shortest possible, use eprec = 6 for
+		// this decision.
+		if shortest {
+			eprec = 6
+		}
+		exp := d.exp - 1
+		if exp < -4 || exp >= eprec {
+			if prec > len(d.mant) {
+				prec = len(d.mant)
+			}
+			return fmtE(buf, fmt+'e'-'g', prec-1, d)
+		}
+		if prec > d.exp {
+			prec = len(d.mant)
+		}
+		return fmtF(buf, max(prec-d.exp, 0), d)
+	}
+
+	// unknown format
+	if x.neg {
+		buf = buf[:len(buf)-1] // sign was added prematurely - remove it again
+	}
+	return append(buf, '%', fmt)
+}
+
+// %e: d.ddddde±dd
+func fmtE(buf []byte, fmt byte, prec int, d decimal) []byte {
+	// first digit
+	ch := byte('0')
+	if len(d.mant) > 0 {
+		ch = d.mant[0]
+	}
+	buf = append(buf, ch)
+
+	// .moredigits
+	if prec > 0 {
+		buf = append(buf, '.')
+		i := 1
+		m := min(len(d.mant), prec+1)
+		if i < m {
+			buf = append(buf, d.mant[i:m]...)
+			i = m
+		}
+		for ; i <= prec; i++ {
+			buf = append(buf, '0')
+		}
+	}
+
+	// e±
+	buf = append(buf, fmt)
+	var exp int64
+	if len(d.mant) > 0 {
+		exp = int64(d.exp) - 1 // -1 because first digit was printed before '.'
+	}
+	if exp < 0 {
+		ch = '-'
+		exp = -exp
+	} else {
+		ch = '+'
+	}
+	buf = append(buf, ch)
+
+	// dd...d
+	if exp < 10 {
+		buf = append(buf, '0') // at least 2 exponent digits
+	}
+	return strconv.AppendInt(buf, exp, 10)
+}
+
+// %f: ddddddd.ddddd
+func fmtF(buf []byte, prec int, d decimal) []byte {
+	// integer, padded with zeros as needed
+	if d.exp > 0 {
+		m := min(len(d.mant), d.exp)
+		buf = append(buf, d.mant[:m]...)
+		for ; m < d.exp; m++ {
+			buf = append(buf, '0')
+		}
+	} else {
+		buf = append(buf, '0')
+	}
+
+	// fraction
+	if prec > 0 {
+		buf = append(buf, '.')
+		for i := 0; i < prec; i++ {
+			ch := byte('0')
+			if j := d.exp + i; 0 <= j && j < len(d.mant) {
+				ch = d.mant[j]
+			}
+			buf = append(buf, ch)
+		}
+	}
+
+	return buf
+}
+
+// fmtB appends the string of x in the format mantissa "p" exponent
+// with a decimal mantissa and a binary exponent, or 0" if x is zero,
+// and returns the extended buffer.
+// The mantissa is normalized such that is uses x.Prec() bits in binary
+// representation.
+// The sign of x is ignored, and x must not be an Inf.
+func (x *Float) fmtB(buf []byte) []byte {
+	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
+	m := x.mant
+	switch w := uint32(len(x.mant)) * _W; {
+	case w < x.prec:
+		m = nat(nil).shl(m, uint(x.prec-w))
+	case w > x.prec:
+		m = nat(nil).shr(m, uint(w-x.prec))
+	}
+
+	buf = append(buf, m.decimalString()...)
+	buf = append(buf, 'p')
+	e := int64(x.exp) - int64(x.prec)
+	if e >= 0 {
+		buf = append(buf, '+')
+	}
+	return strconv.AppendInt(buf, e, 10)
+}
+
+// fmtP appends the string of x in the format 0x." mantissa "p" exponent
+// with a hexadecimal mantissa and a binary exponent, or 0" if x is zero,
+// ad returns the extended buffer.
+// The mantissa is normalized such that 0.5 <= 0.mantissa < 1.0.
+// The sign of x is ignored, and x must not be an Inf.
+func (x *Float) fmtP(buf []byte) []byte {
+	if x.form == zero {
+		return append(buf, '0')
+	}
+
+	if debugFloat && x.form != finite {
+		panic("non-finite float")
+	}
+	// x != 0
+
+	// remove trailing 0 words early
+	// (no need to convert to hex 0's and trim later)
+	m := x.mant
+	i := 0
+	for i < len(m) && m[i] == 0 {
+		i++
+	}
+	m = m[i:]
+
+	buf = append(buf, "0x."...)
+	buf = append(buf, strings.TrimRight(m.hexString(), "0")...)
+	buf = append(buf, 'p')
+	if x.exp >= 0 {
+		buf = append(buf, '+')
+	}
+	return strconv.AppendInt(buf, int64(x.exp), 10)
+}
+
+func min(x, y int) int {
+	if x < y {
+		return x
+	}
+	return y
+}
+
+// Format implements fmt.Formatter. It accepts all the regular
+// formats for floating-point numbers ('e', 'E', 'f', 'F', 'g',
+// 'G') as well as 'b', 'p', and 'v'. See (*Float).Text for the
+// interpretation of 'b' and 'p'. The 'v' format is handled like
+// 'g'.
+// Format also supports specification of the minimum precision
+// in digits, the output field width, as well as the format verbs
+// '+' and ' ' for sign control, '0' for space or zero padding,
+// and '-' for left or right justification. See the fmt package
+// for details.
+//
+// BUG(gri) A missing precision for the 'g' format, or a negative
+//          (via '*') precision is not yet supported. Instead the
+//          default precision (6) is used in that case (issue #10991).
+func (x *Float) Format(s fmt.State, format rune) {
+	prec, hasPrec := s.Precision()
+	if !hasPrec {
+		prec = 6 // default precision for 'e', 'f'
+	}
+
+	switch format {
+	case 'e', 'E', 'f', 'b', 'p':
+		// nothing to do
+	case 'F':
+		// (*Float).Text doesn't support 'F'; handle like 'f'
+		format = 'f'
+	case 'v':
+		// handle like 'g'
+		format = 'g'
+		fallthrough
+	case 'g', 'G':
+		if !hasPrec {
+			// TODO(gri) uncomment once (*Float).Text handles prec < 0
+			// prec = -1 // default precision for 'g', 'G'
+		}
+	default:
+		fmt.Fprintf(s, "%%!%c(*big.Float=%s)", format, x.String())
+		return
+	}
+	var buf []byte
+	buf = x.Append(buf, byte(format), prec)
+	if len(buf) == 0 {
+		buf = []byte("?") // should never happen, but don't crash
+	}
+	// len(buf) > 0
+
+	var sign string
+	switch {
+	case buf[0] == '-':
+		sign = "-"
+		buf = buf[1:]
+	case buf[0] == '+':
+		// +Inf
+		sign = "+"
+		if s.Flag(' ') {
+			sign = " "
+		}
+		buf = buf[1:]
+	case s.Flag('+'):
+		sign = "+"
+	case s.Flag(' '):
+		sign = " "
+	}
+
+	var padding int
+	if width, hasWidth := s.Width(); hasWidth && width > len(sign)+len(buf) {
+		padding = width - len(sign) - len(buf)
+	}
+
+	switch {
+	case s.Flag('0') && !x.IsInf():
+		// 0-padding on left
+		writeMultiple(s, sign, 1)
+		writeMultiple(s, "0", padding)
+		s.Write(buf)
+	case s.Flag('-'):
+		// padding on right
+		writeMultiple(s, sign, 1)
+		s.Write(buf)
+		writeMultiple(s, " ", padding)
+	default:
+		// padding on left
+		writeMultiple(s, " ", padding)
+		writeMultiple(s, sign, 1)
+		s.Write(buf)
+	}
+}
diff --git a/src/cmd/compile/internal/big/gcd_test.go b/src/cmd/compile/internal/big/gcd_test.go
new file mode 100644
index 0000000..c0b9f58
--- /dev/null
+++ b/src/cmd/compile/internal/big/gcd_test.go
@@ -0,0 +1,47 @@
+// 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.
+
+// This file implements a GCD benchmark.
+// Usage: go test math/big -test.bench GCD
+
+package big
+
+import (
+	"math/rand"
+	"testing"
+)
+
+// randInt returns a pseudo-random Int in the range [1<<(size-1), (1<<size) - 1]
+func randInt(r *rand.Rand, size uint) *Int {
+	n := new(Int).Lsh(intOne, size-1)
+	x := new(Int).Rand(r, n)
+	return x.Add(x, n) // make sure result > 1<<(size-1)
+}
+
+func runGCD(b *testing.B, aSize, bSize uint) {
+	b.StopTimer()
+	var r = rand.New(rand.NewSource(1234))
+	aa := randInt(r, aSize)
+	bb := randInt(r, bSize)
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		new(Int).GCD(nil, nil, aa, bb)
+	}
+}
+
+func BenchmarkGCD10x10(b *testing.B)         { runGCD(b, 10, 10) }
+func BenchmarkGCD10x100(b *testing.B)        { runGCD(b, 10, 100) }
+func BenchmarkGCD10x1000(b *testing.B)       { runGCD(b, 10, 1000) }
+func BenchmarkGCD10x10000(b *testing.B)      { runGCD(b, 10, 10000) }
+func BenchmarkGCD10x100000(b *testing.B)     { runGCD(b, 10, 100000) }
+func BenchmarkGCD100x100(b *testing.B)       { runGCD(b, 100, 100) }
+func BenchmarkGCD100x1000(b *testing.B)      { runGCD(b, 100, 1000) }
+func BenchmarkGCD100x10000(b *testing.B)     { runGCD(b, 100, 10000) }
+func BenchmarkGCD100x100000(b *testing.B)    { runGCD(b, 100, 100000) }
+func BenchmarkGCD1000x1000(b *testing.B)     { runGCD(b, 1000, 1000) }
+func BenchmarkGCD1000x10000(b *testing.B)    { runGCD(b, 1000, 10000) }
+func BenchmarkGCD1000x100000(b *testing.B)   { runGCD(b, 1000, 100000) }
+func BenchmarkGCD10000x10000(b *testing.B)   { runGCD(b, 10000, 10000) }
+func BenchmarkGCD10000x100000(b *testing.B)  { runGCD(b, 10000, 100000) }
+func BenchmarkGCD100000x100000(b *testing.B) { runGCD(b, 100000, 100000) }
diff --git a/src/cmd/compile/internal/big/hilbert_test.go b/src/cmd/compile/internal/big/hilbert_test.go
new file mode 100644
index 0000000..1a84341
--- /dev/null
+++ b/src/cmd/compile/internal/big/hilbert_test.go
@@ -0,0 +1,160 @@
+// 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.
+
+// A little test program and benchmark for rational arithmetics.
+// Computes a Hilbert matrix, its inverse, multiplies them
+// and verifies that the product is the identity matrix.
+
+package big
+
+import (
+	"fmt"
+	"testing"
+)
+
+type matrix struct {
+	n, m int
+	a    []*Rat
+}
+
+func (a *matrix) at(i, j int) *Rat {
+	if !(0 <= i && i < a.n && 0 <= j && j < a.m) {
+		panic("index out of range")
+	}
+	return a.a[i*a.m+j]
+}
+
+func (a *matrix) set(i, j int, x *Rat) {
+	if !(0 <= i && i < a.n && 0 <= j && j < a.m) {
+		panic("index out of range")
+	}
+	a.a[i*a.m+j] = x
+}
+
+func newMatrix(n, m int) *matrix {
+	if !(0 <= n && 0 <= m) {
+		panic("illegal matrix")
+	}
+	a := new(matrix)
+	a.n = n
+	a.m = m
+	a.a = make([]*Rat, n*m)
+	return a
+}
+
+func newUnit(n int) *matrix {
+	a := newMatrix(n, n)
+	for i := 0; i < n; i++ {
+		for j := 0; j < n; j++ {
+			x := NewRat(0, 1)
+			if i == j {
+				x.SetInt64(1)
+			}
+			a.set(i, j, x)
+		}
+	}
+	return a
+}
+
+func newHilbert(n int) *matrix {
+	a := newMatrix(n, n)
+	for i := 0; i < n; i++ {
+		for j := 0; j < n; j++ {
+			a.set(i, j, NewRat(1, int64(i+j+1)))
+		}
+	}
+	return a
+}
+
+func newInverseHilbert(n int) *matrix {
+	a := newMatrix(n, n)
+	for i := 0; i < n; i++ {
+		for j := 0; j < n; j++ {
+			x1 := new(Rat).SetInt64(int64(i + j + 1))
+			x2 := new(Rat).SetInt(new(Int).Binomial(int64(n+i), int64(n-j-1)))
+			x3 := new(Rat).SetInt(new(Int).Binomial(int64(n+j), int64(n-i-1)))
+			x4 := new(Rat).SetInt(new(Int).Binomial(int64(i+j), int64(i)))
+
+			x1.Mul(x1, x2)
+			x1.Mul(x1, x3)
+			x1.Mul(x1, x4)
+			x1.Mul(x1, x4)
+
+			if (i+j)&1 != 0 {
+				x1.Neg(x1)
+			}
+
+			a.set(i, j, x1)
+		}
+	}
+	return a
+}
+
+func (a *matrix) mul(b *matrix) *matrix {
+	if a.m != b.n {
+		panic("illegal matrix multiply")
+	}
+	c := newMatrix(a.n, b.m)
+	for i := 0; i < c.n; i++ {
+		for j := 0; j < c.m; j++ {
+			x := NewRat(0, 1)
+			for k := 0; k < a.m; k++ {
+				x.Add(x, new(Rat).Mul(a.at(i, k), b.at(k, j)))
+			}
+			c.set(i, j, x)
+		}
+	}
+	return c
+}
+
+func (a *matrix) eql(b *matrix) bool {
+	if a.n != b.n || a.m != b.m {
+		return false
+	}
+	for i := 0; i < a.n; i++ {
+		for j := 0; j < a.m; j++ {
+			if a.at(i, j).Cmp(b.at(i, j)) != 0 {
+				return false
+			}
+		}
+	}
+	return true
+}
+
+func (a *matrix) String() string {
+	s := ""
+	for i := 0; i < a.n; i++ {
+		for j := 0; j < a.m; j++ {
+			s += fmt.Sprintf("\t%s", a.at(i, j))
+		}
+		s += "\n"
+	}
+	return s
+}
+
+func doHilbert(t *testing.T, n int) {
+	a := newHilbert(n)
+	b := newInverseHilbert(n)
+	I := newUnit(n)
+	ab := a.mul(b)
+	if !ab.eql(I) {
+		if t == nil {
+			panic("Hilbert failed")
+		}
+		t.Errorf("a   = %s\n", a)
+		t.Errorf("b   = %s\n", b)
+		t.Errorf("a*b = %s\n", ab)
+		t.Errorf("I   = %s\n", I)
+	}
+}
+
+func TestHilbert(t *testing.T) {
+	doHilbert(t, 10)
+}
+
+func BenchmarkHilbert(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		doHilbert(nil, 10)
+	}
+}
diff --git a/src/cmd/compile/internal/big/int.go b/src/cmd/compile/internal/big/int.go
new file mode 100644
index 0000000..5e31253
--- /dev/null
+++ b/src/cmd/compile/internal/big/int.go
@@ -0,0 +1,966 @@
+// 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.
+
+// This file implements signed multi-precision integers.
+
+package big
+
+import (
+	"fmt"
+	"io"
+	"math/rand"
+	"strings"
+)
+
+// An Int represents a signed multi-precision integer.
+// The zero value for an Int represents the value 0.
+type Int struct {
+	neg bool // sign
+	abs nat  // absolute value of the integer
+}
+
+var intOne = &Int{false, natOne}
+
+// Sign returns:
+//
+//	-1 if x <  0
+//	 0 if x == 0
+//	+1 if x >  0
+//
+func (x *Int) Sign() int {
+	if len(x.abs) == 0 {
+		return 0
+	}
+	if x.neg {
+		return -1
+	}
+	return 1
+}
+
+// SetInt64 sets z to x and returns z.
+func (z *Int) SetInt64(x int64) *Int {
+	neg := false
+	if x < 0 {
+		neg = true
+		x = -x
+	}
+	z.abs = z.abs.setUint64(uint64(x))
+	z.neg = neg
+	return z
+}
+
+// SetUint64 sets z to x and returns z.
+func (z *Int) SetUint64(x uint64) *Int {
+	z.abs = z.abs.setUint64(x)
+	z.neg = false
+	return z
+}
+
+// NewInt allocates and returns a new Int set to x.
+func NewInt(x int64) *Int {
+	return new(Int).SetInt64(x)
+}
+
+// Set sets z to x and returns z.
+func (z *Int) Set(x *Int) *Int {
+	if z != x {
+		z.abs = z.abs.set(x.abs)
+		z.neg = x.neg
+	}
+	return z
+}
+
+// Bits provides raw (unchecked but fast) access to x by returning its
+// absolute value as a little-endian Word slice. The result and x share
+// the same underlying array.
+// Bits is intended to support implementation of missing low-level Int
+// functionality outside this package; it should be avoided otherwise.
+func (x *Int) Bits() []Word {
+	return x.abs
+}
+
+// SetBits provides raw (unchecked but fast) access to z by setting its
+// value to abs, interpreted as a little-endian Word slice, and returning
+// z. The result and abs share the same underlying array.
+// SetBits is intended to support implementation of missing low-level Int
+// functionality outside this package; it should be avoided otherwise.
+func (z *Int) SetBits(abs []Word) *Int {
+	z.abs = nat(abs).norm()
+	z.neg = false
+	return z
+}
+
+// Abs sets z to |x| (the absolute value of x) and returns z.
+func (z *Int) Abs(x *Int) *Int {
+	z.Set(x)
+	z.neg = false
+	return z
+}
+
+// Neg sets z to -x and returns z.
+func (z *Int) Neg(x *Int) *Int {
+	z.Set(x)
+	z.neg = len(z.abs) > 0 && !z.neg // 0 has no sign
+	return z
+}
+
+// Add sets z to the sum x+y and returns z.
+func (z *Int) Add(x, y *Int) *Int {
+	neg := x.neg
+	if x.neg == y.neg {
+		// x + y == x + y
+		// (-x) + (-y) == -(x + y)
+		z.abs = z.abs.add(x.abs, y.abs)
+	} else {
+		// x + (-y) == x - y == -(y - x)
+		// (-x) + y == y - x == -(x - y)
+		if x.abs.cmp(y.abs) >= 0 {
+			z.abs = z.abs.sub(x.abs, y.abs)
+		} else {
+			neg = !neg
+			z.abs = z.abs.sub(y.abs, x.abs)
+		}
+	}
+	z.neg = len(z.abs) > 0 && neg // 0 has no sign
+	return z
+}
+
+// Sub sets z to the difference x-y and returns z.
+func (z *Int) Sub(x, y *Int) *Int {
+	neg := x.neg
+	if x.neg != y.neg {
+		// x - (-y) == x + y
+		// (-x) - y == -(x + y)
+		z.abs = z.abs.add(x.abs, y.abs)
+	} else {
+		// x - y == x - y == -(y - x)
+		// (-x) - (-y) == y - x == -(x - y)
+		if x.abs.cmp(y.abs) >= 0 {
+			z.abs = z.abs.sub(x.abs, y.abs)
+		} else {
+			neg = !neg
+			z.abs = z.abs.sub(y.abs, x.abs)
+		}
+	}
+	z.neg = len(z.abs) > 0 && neg // 0 has no sign
+	return z
+}
+
+// Mul sets z to the product x*y and returns z.
+func (z *Int) Mul(x, y *Int) *Int {
+	// x * y == x * y
+	// x * (-y) == -(x * y)
+	// (-x) * y == -(x * y)
+	// (-x) * (-y) == x * y
+	z.abs = z.abs.mul(x.abs, y.abs)
+	z.neg = len(z.abs) > 0 && x.neg != y.neg // 0 has no sign
+	return z
+}
+
+// MulRange sets z to the product of all integers
+// in the range [a, b] inclusively and returns z.
+// If a > b (empty range), the result is 1.
+func (z *Int) MulRange(a, b int64) *Int {
+	switch {
+	case a > b:
+		return z.SetInt64(1) // empty range
+	case a <= 0 && b >= 0:
+		return z.SetInt64(0) // range includes 0
+	}
+	// a <= b && (b < 0 || a > 0)
+
+	neg := false
+	if a < 0 {
+		neg = (b-a)&1 == 0
+		a, b = -b, -a
+	}
+
+	z.abs = z.abs.mulRange(uint64(a), uint64(b))
+	z.neg = neg
+	return z
+}
+
+// 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)
+	return z.Quo(&a, &b)
+}
+
+// Quo sets z to the quotient x/y for y != 0 and returns z.
+// If y == 0, a division-by-zero run-time panic occurs.
+// Quo implements truncated division (like Go); see QuoRem for more details.
+func (z *Int) Quo(x, y *Int) *Int {
+	z.abs, _ = z.abs.div(nil, x.abs, y.abs)
+	z.neg = len(z.abs) > 0 && x.neg != y.neg // 0 has no sign
+	return z
+}
+
+// Rem sets z to the remainder x%y for y != 0 and returns z.
+// If y == 0, a division-by-zero run-time panic occurs.
+// Rem implements truncated modulus (like Go); see QuoRem for more details.
+func (z *Int) Rem(x, y *Int) *Int {
+	_, z.abs = nat(nil).div(z.abs, x.abs, y.abs)
+	z.neg = len(z.abs) > 0 && x.neg // 0 has no sign
+	return z
+}
+
+// QuoRem sets z to the quotient x/y and r to the remainder x%y
+// and returns the pair (z, r) for y != 0.
+// If y == 0, a division-by-zero run-time panic occurs.
+//
+// QuoRem implements T-division and modulus (like Go):
+//
+//	q = x/y      with the result truncated to zero
+//	r = x - y*q
+//
+// (See Daan Leijen, ``Division and Modulus for Computer Scientists''.)
+// See DivMod for Euclidean division and modulus (unlike Go).
+//
+func (z *Int) QuoRem(x, y, r *Int) (*Int, *Int) {
+	z.abs, r.abs = z.abs.div(r.abs, x.abs, y.abs)
+	z.neg, r.neg = len(z.abs) > 0 && x.neg != y.neg, len(r.abs) > 0 && x.neg // 0 has no sign
+	return z, r
+}
+
+// Div sets z to the quotient x/y for y != 0 and returns z.
+// If y == 0, a division-by-zero run-time panic occurs.
+// Div implements Euclidean division (unlike Go); see DivMod for more details.
+func (z *Int) Div(x, y *Int) *Int {
+	y_neg := y.neg // z may be an alias for y
+	var r Int
+	z.QuoRem(x, y, &r)
+	if r.neg {
+		if y_neg {
+			z.Add(z, intOne)
+		} else {
+			z.Sub(z, intOne)
+		}
+	}
+	return z
+}
+
+// Mod sets z to the modulus x%y for y != 0 and returns z.
+// If y == 0, a division-by-zero run-time panic occurs.
+// Mod implements Euclidean modulus (unlike Go); see DivMod for more details.
+func (z *Int) Mod(x, y *Int) *Int {
+	y0 := y // save y
+	if z == y || alias(z.abs, y.abs) {
+		y0 = new(Int).Set(y)
+	}
+	var q Int
+	q.QuoRem(x, y, z)
+	if z.neg {
+		if y0.neg {
+			z.Sub(z, y0)
+		} else {
+			z.Add(z, y0)
+		}
+	}
+	return z
+}
+
+// DivMod sets z to the quotient x div y and m to the modulus x mod y
+// and returns the pair (z, m) for y != 0.
+// If y == 0, a division-by-zero run-time panic occurs.
+//
+// DivMod implements Euclidean division and modulus (unlike Go):
+//
+//	q = x div y  such that
+//	m = x - y*q  with 0 <= m < |q|
+//
+// (See Raymond T. Boute, ``The Euclidean definition of the functions
+// div and mod''. ACM Transactions on Programming Languages and
+// Systems (TOPLAS), 14(2):127-144, New York, NY, USA, 4/1992.
+// ACM press.)
+// See QuoRem for T-division and modulus (like Go).
+//
+func (z *Int) DivMod(x, y, m *Int) (*Int, *Int) {
+	y0 := y // save y
+	if z == y || alias(z.abs, y.abs) {
+		y0 = new(Int).Set(y)
+	}
+	z.QuoRem(x, y, m)
+	if m.neg {
+		if y0.neg {
+			z.Add(z, intOne)
+			m.Sub(m, y0)
+		} else {
+			z.Sub(z, intOne)
+			m.Add(m, y0)
+		}
+	}
+	return z, m
+}
+
+// Cmp compares x and y and returns:
+//
+//   -1 if x <  y
+//    0 if x == y
+//   +1 if x >  y
+//
+func (x *Int) Cmp(y *Int) (r int) {
+	// x cmp y == x cmp y
+	// x cmp (-y) == x
+	// (-x) cmp y == y
+	// (-x) cmp (-y) == -(x cmp y)
+	switch {
+	case x.neg == y.neg:
+		r = x.abs.cmp(y.abs)
+		if x.neg {
+			r = -r
+		}
+	case x.neg:
+		r = -1
+	default:
+		r = 1
+	}
+	return
+}
+
+// low32 returns the least significant 32 bits of z.
+func low32(z nat) uint32 {
+	if len(z) == 0 {
+		return 0
+	}
+	return uint32(z[0])
+}
+
+// low64 returns the least significant 64 bits of z.
+func low64(z nat) uint64 {
+	if len(z) == 0 {
+		return 0
+	}
+	v := uint64(z[0])
+	if _W == 32 && len(z) > 1 {
+		v |= uint64(z[1]) << 32
+	}
+	return v
+}
+
+// Int64 returns the int64 representation of x.
+// If x cannot be represented in an int64, the result is undefined.
+func (x *Int) Int64() int64 {
+	v := int64(low64(x.abs))
+	if x.neg {
+		v = -v
+	}
+	return v
+}
+
+// Uint64 returns the uint64 representation of x.
+// If x cannot be represented in a uint64, the result is undefined.
+func (x *Int) Uint64() uint64 {
+	return low64(x.abs)
+}
+
+// SetString sets z to the value of s, interpreted in the given base,
+// and returns z and a boolean indicating success. If SetString fails,
+// the value of z is undefined but the returned value is nil.
+//
+// The base argument must be 0 or a value between 2 and MaxBase. If the base
+// is 0, the string prefix determines the actual conversion base. A prefix of
+// ``0x'' or ``0X'' selects base 16; the ``0'' prefix selects base 8, and a
+// ``0b'' or ``0B'' prefix selects base 2. Otherwise the selected base is 10.
+//
+func (z *Int) SetString(s string, base int) (*Int, bool) {
+	r := strings.NewReader(s)
+	_, _, err := z.scan(r, base)
+	if err != nil {
+		return nil, false
+	}
+	_, err = r.ReadByte()
+	if err != io.EOF {
+		return nil, false
+	}
+	return z, true // err == io.EOF => scan consumed all of s
+}
+
+// SetBytes interprets buf as the bytes of a big-endian unsigned
+// integer, sets z to that value, and returns z.
+func (z *Int) SetBytes(buf []byte) *Int {
+	z.abs = z.abs.setBytes(buf)
+	z.neg = false
+	return z
+}
+
+// Bytes returns the absolute value of x as a big-endian byte slice.
+func (x *Int) Bytes() []byte {
+	buf := make([]byte, len(x.abs)*_S)
+	return buf[x.abs.bytes(buf):]
+}
+
+// BitLen returns the length of the absolute value of x in bits.
+// The bit length of 0 is 0.
+func (x *Int) BitLen() int {
+	return x.abs.bitLen()
+}
+
+// Exp sets z = x**y mod |m| (i.e. the sign of m is ignored), and returns z.
+// If y <= 0, the result is 1 mod |m|; if m == nil or m == 0, z = x**y.
+// See Knuth, volume 2, section 4.6.3.
+func (z *Int) Exp(x, y, m *Int) *Int {
+	var yWords nat
+	if !y.neg {
+		yWords = y.abs
+	}
+	// y >= 0
+
+	var mWords nat
+	if m != nil {
+		mWords = m.abs // m.abs may be nil for m == 0
+	}
+
+	z.abs = z.abs.expNN(x.abs, yWords, mWords)
+	z.neg = len(z.abs) > 0 && x.neg && len(yWords) > 0 && yWords[0]&1 == 1 // 0 has no sign
+	if z.neg && len(mWords) > 0 {
+		// make modulus result positive
+		z.abs = z.abs.sub(mWords, z.abs) // z == x**y mod |m| && 0 <= z < |m|
+		z.neg = false
+	}
+
+	return z
+}
+
+// GCD sets z to the greatest common divisor of a and b, which both must
+// be > 0, and returns z.
+// If x and y are not nil, GCD sets x and y such that z = a*x + b*y.
+// If either a or b is <= 0, GCD sets z = x = y = 0.
+func (z *Int) GCD(x, y, a, b *Int) *Int {
+	if a.Sign() <= 0 || b.Sign() <= 0 {
+		z.SetInt64(0)
+		if x != nil {
+			x.SetInt64(0)
+		}
+		if y != nil {
+			y.SetInt64(0)
+		}
+		return z
+	}
+	if x == nil && y == nil {
+		return z.binaryGCD(a, b)
+	}
+
+	A := new(Int).Set(a)
+	B := new(Int).Set(b)
+
+	X := new(Int)
+	Y := new(Int).SetInt64(1)
+
+	lastX := new(Int).SetInt64(1)
+	lastY := new(Int)
+
+	q := new(Int)
+	temp := new(Int)
+
+	for len(B.abs) > 0 {
+		r := new(Int)
+		q, r = q.QuoRem(A, B, r)
+
+		A, B = B, r
+
+		temp.Set(X)
+		X.Mul(X, q)
+		X.neg = !X.neg
+		X.Add(X, lastX)
+		lastX.Set(temp)
+
+		temp.Set(Y)
+		Y.Mul(Y, q)
+		Y.neg = !Y.neg
+		Y.Add(Y, lastY)
+		lastY.Set(temp)
+	}
+
+	if x != nil {
+		*x = *lastX
+	}
+
+	if y != nil {
+		*y = *lastY
+	}
+
+	*z = *A
+	return z
+}
+
+// binaryGCD sets z to the greatest common divisor of a and b, which both must
+// be > 0, and returns z.
+// See Knuth, The Art of Computer Programming, Vol. 2, Section 4.5.2, Algorithm B.
+func (z *Int) binaryGCD(a, b *Int) *Int {
+	u := z
+	v := new(Int)
+
+	// use one Euclidean iteration to ensure that u and v are approx. the same size
+	switch {
+	case len(a.abs) > len(b.abs):
+		u.Set(b)
+		v.Rem(a, b)
+	case len(a.abs) < len(b.abs):
+		u.Set(a)
+		v.Rem(b, a)
+	default:
+		u.Set(a)
+		v.Set(b)
+	}
+
+	// v might be 0 now
+	if len(v.abs) == 0 {
+		return u
+	}
+	// u > 0 && v > 0
+
+	// determine largest k such that u = u' << k, v = v' << k
+	k := u.abs.trailingZeroBits()
+	if vk := v.abs.trailingZeroBits(); vk < k {
+		k = vk
+	}
+	u.Rsh(u, k)
+	v.Rsh(v, k)
+
+	// determine t (we know that u > 0)
+	t := new(Int)
+	if u.abs[0]&1 != 0 {
+		// u is odd
+		t.Neg(v)
+	} else {
+		t.Set(u)
+	}
+
+	for len(t.abs) > 0 {
+		// reduce t
+		t.Rsh(t, t.abs.trailingZeroBits())
+		if t.neg {
+			v, t = t, v
+			v.neg = len(v.abs) > 0 && !v.neg // 0 has no sign
+		} else {
+			u, t = t, u
+		}
+		t.Sub(u, v)
+	}
+
+	return z.Lsh(u, k)
+}
+
+// ProbablyPrime performs n Miller-Rabin tests to check whether x is prime.
+// If it returns true, x is prime with probability 1 - 1/4^n.
+// If it returns false, x is not prime. n must be > 0.
+func (x *Int) ProbablyPrime(n int) bool {
+	if n <= 0 {
+		panic("non-positive n for ProbablyPrime")
+	}
+	return !x.neg && x.abs.probablyPrime(n)
+}
+
+// Rand sets z to a pseudo-random number in [0, n) and returns z.
+func (z *Int) Rand(rnd *rand.Rand, n *Int) *Int {
+	z.neg = false
+	if n.neg == true || len(n.abs) == 0 {
+		z.abs = nil
+		return z
+	}
+	z.abs = z.abs.random(rnd, n.abs, n.abs.bitLen())
+	return z
+}
+
+// ModInverse sets z to the multiplicative inverse of g in the ring ℤ/nℤ
+// and returns z. If g and n are not relatively prime, the result is undefined.
+func (z *Int) ModInverse(g, n *Int) *Int {
+	var d Int
+	d.GCD(z, nil, g, n)
+	// x and y are such that g*x + n*y = d. Since g and n are
+	// relatively prime, d = 1. Taking that modulo n results in
+	// g*x = 1, therefore x is the inverse element.
+	if z.neg {
+		z.Add(z, n)
+	}
+	return z
+}
+
+// Jacobi returns the Jacobi symbol (x/y), either +1, -1, or 0.
+// The y argument must be an odd integer.
+func Jacobi(x, y *Int) int {
+	if len(y.abs) == 0 || y.abs[0]&1 == 0 {
+		panic(fmt.Sprintf("big: invalid 2nd argument to Int.Jacobi: need odd integer but got %s", y))
+	}
+
+	// We use the formulation described in chapter 2, section 2.4,
+	// "The Yacas Book of Algorithms":
+	// http://yacas.sourceforge.net/Algo.book.pdf
+
+	var a, b, c Int
+	a.Set(x)
+	b.Set(y)
+	j := 1
+
+	if b.neg {
+		if a.neg {
+			j = -1
+		}
+		b.neg = false
+	}
+
+	for {
+		if b.Cmp(intOne) == 0 {
+			return j
+		}
+		if len(a.abs) == 0 {
+			return 0
+		}
+		a.Mod(&a, &b)
+		if len(a.abs) == 0 {
+			return 0
+		}
+		// a > 0
+
+		// handle factors of 2 in 'a'
+		s := a.abs.trailingZeroBits()
+		if s&1 != 0 {
+			bmod8 := b.abs[0] & 7
+			if bmod8 == 3 || bmod8 == 5 {
+				j = -j
+			}
+		}
+		c.Rsh(&a, s) // a = 2^s*c
+
+		// swap numerator and denominator
+		if b.abs[0]&3 == 3 && c.abs[0]&3 == 3 {
+			j = -j
+		}
+		a.Set(&b)
+		b.Set(&c)
+	}
+}
+
+// ModSqrt sets z to a square root of x mod p if such a square root exists, and
+// returns z. The modulus p must be an odd prime. If x is not a square mod p,
+// ModSqrt leaves z unchanged and returns nil. This function panics if p is
+// not an odd integer.
+func (z *Int) ModSqrt(x, p *Int) *Int {
+	switch Jacobi(x, p) {
+	case -1:
+		return nil // x is not a square mod p
+	case 0:
+		return z.SetInt64(0) // sqrt(0) mod p = 0
+	case 1:
+		break
+	}
+	if x.neg || x.Cmp(p) >= 0 { // ensure 0 <= x < p
+		x = new(Int).Mod(x, p)
+	}
+
+	// Break p-1 into s*2^e such that s is odd.
+	var s Int
+	s.Sub(p, intOne)
+	e := s.abs.trailingZeroBits()
+	s.Rsh(&s, e)
+
+	// find some non-square n
+	var n Int
+	n.SetInt64(2)
+	for Jacobi(&n, p) != -1 {
+		n.Add(&n, intOne)
+	}
+
+	// Core of the Tonelli-Shanks algorithm. Follows the description in
+	// section 6 of "Square roots from 1; 24, 51, 10 to Dan Shanks" by Ezra
+	// Brown:
+	// https://www.maa.org/sites/default/files/pdf/upload_library/22/Polya/07468342.di020786.02p0470a.pdf
+	var y, b, g, t Int
+	y.Add(&s, intOne)
+	y.Rsh(&y, 1)
+	y.Exp(x, &y, p)  // y = x^((s+1)/2)
+	b.Exp(x, &s, p)  // b = x^s
+	g.Exp(&n, &s, p) // g = n^s
+	r := e
+	for {
+		// find the least m such that ord_p(b) = 2^m
+		var m uint
+		t.Set(&b)
+		for t.Cmp(intOne) != 0 {
+			t.Mul(&t, &t).Mod(&t, p)
+			m++
+		}
+
+		if m == 0 {
+			return z.Set(&y)
+		}
+
+		t.SetInt64(0).SetBit(&t, int(r-m-1), 1).Exp(&g, &t, p)
+		// t = g^(2^(r-m-1)) mod p
+		g.Mul(&t, &t).Mod(&g, p) // g = g^(2^(r-m)) mod p
+		y.Mul(&y, &t).Mod(&y, p)
+		b.Mul(&b, &g).Mod(&b, p)
+		r = m
+	}
+}
+
+// Lsh sets z = x << n and returns z.
+func (z *Int) Lsh(x *Int, n uint) *Int {
+	z.abs = z.abs.shl(x.abs, n)
+	z.neg = x.neg
+	return z
+}
+
+// Rsh sets z = x >> n and returns z.
+func (z *Int) Rsh(x *Int, n uint) *Int {
+	if x.neg {
+		// (-x) >> s == ^(x-1) >> s == ^((x-1) >> s) == -(((x-1) >> s) + 1)
+		t := z.abs.sub(x.abs, natOne) // no underflow because |x| > 0
+		t = t.shr(t, n)
+		z.abs = t.add(t, natOne)
+		z.neg = true // z cannot be zero if x is negative
+		return z
+	}
+
+	z.abs = z.abs.shr(x.abs, n)
+	z.neg = false
+	return z
+}
+
+// Bit returns the value of the i'th bit of x. That is, it
+// returns (x>>i)&1. The bit index i must be >= 0.
+func (x *Int) Bit(i int) uint {
+	if i == 0 {
+		// optimization for common case: odd/even test of x
+		if len(x.abs) > 0 {
+			return uint(x.abs[0] & 1) // bit 0 is same for -x
+		}
+		return 0
+	}
+	if i < 0 {
+		panic("negative bit index")
+	}
+	if x.neg {
+		t := nat(nil).sub(x.abs, natOne)
+		return t.bit(uint(i)) ^ 1
+	}
+
+	return x.abs.bit(uint(i))
+}
+
+// SetBit sets z to x, with x's i'th bit set to b (0 or 1).
+// That is, if b is 1 SetBit sets z = x | (1 << i);
+// if b is 0 SetBit sets z = x &^ (1 << i). If b is not 0 or 1,
+// SetBit will panic.
+func (z *Int) SetBit(x *Int, i int, b uint) *Int {
+	if i < 0 {
+		panic("negative bit index")
+	}
+	if x.neg {
+		t := z.abs.sub(x.abs, natOne)
+		t = t.setBit(t, uint(i), b^1)
+		z.abs = t.add(t, natOne)
+		z.neg = len(z.abs) > 0
+		return z
+	}
+	z.abs = z.abs.setBit(x.abs, uint(i), b)
+	z.neg = false
+	return z
+}
+
+// And sets z = x & y and returns z.
+func (z *Int) And(x, y *Int) *Int {
+	if x.neg == y.neg {
+		if x.neg {
+			// (-x) & (-y) == ^(x-1) & ^(y-1) == ^((x-1) | (y-1)) == -(((x-1) | (y-1)) + 1)
+			x1 := nat(nil).sub(x.abs, natOne)
+			y1 := nat(nil).sub(y.abs, natOne)
+			z.abs = z.abs.add(z.abs.or(x1, y1), natOne)
+			z.neg = true // z cannot be zero if x and y are negative
+			return z
+		}
+
+		// x & y == x & y
+		z.abs = z.abs.and(x.abs, y.abs)
+		z.neg = false
+		return z
+	}
+
+	// x.neg != y.neg
+	if x.neg {
+		x, y = y, x // & is symmetric
+	}
+
+	// x & (-y) == x & ^(y-1) == x &^ (y-1)
+	y1 := nat(nil).sub(y.abs, natOne)
+	z.abs = z.abs.andNot(x.abs, y1)
+	z.neg = false
+	return z
+}
+
+// AndNot sets z = x &^ y and returns z.
+func (z *Int) AndNot(x, y *Int) *Int {
+	if x.neg == y.neg {
+		if x.neg {
+			// (-x) &^ (-y) == ^(x-1) &^ ^(y-1) == ^(x-1) & (y-1) == (y-1) &^ (x-1)
+			x1 := nat(nil).sub(x.abs, natOne)
+			y1 := nat(nil).sub(y.abs, natOne)
+			z.abs = z.abs.andNot(y1, x1)
+			z.neg = false
+			return z
+		}
+
+		// x &^ y == x &^ y
+		z.abs = z.abs.andNot(x.abs, y.abs)
+		z.neg = false
+		return z
+	}
+
+	if x.neg {
+		// (-x) &^ y == ^(x-1) &^ y == ^(x-1) & ^y == ^((x-1) | y) == -(((x-1) | y) + 1)
+		x1 := nat(nil).sub(x.abs, natOne)
+		z.abs = z.abs.add(z.abs.or(x1, y.abs), natOne)
+		z.neg = true // z cannot be zero if x is negative and y is positive
+		return z
+	}
+
+	// x &^ (-y) == x &^ ^(y-1) == x & (y-1)
+	y1 := nat(nil).sub(y.abs, natOne)
+	z.abs = z.abs.and(x.abs, y1)
+	z.neg = false
+	return z
+}
+
+// Or sets z = x | y and returns z.
+func (z *Int) Or(x, y *Int) *Int {
+	if x.neg == y.neg {
+		if x.neg {
+			// (-x) | (-y) == ^(x-1) | ^(y-1) == ^((x-1) & (y-1)) == -(((x-1) & (y-1)) + 1)
+			x1 := nat(nil).sub(x.abs, natOne)
+			y1 := nat(nil).sub(y.abs, natOne)
+			z.abs = z.abs.add(z.abs.and(x1, y1), natOne)
+			z.neg = true // z cannot be zero if x and y are negative
+			return z
+		}
+
+		// x | y == x | y
+		z.abs = z.abs.or(x.abs, y.abs)
+		z.neg = false
+		return z
+	}
+
+	// x.neg != y.neg
+	if x.neg {
+		x, y = y, x // | is symmetric
+	}
+
+	// x | (-y) == x | ^(y-1) == ^((y-1) &^ x) == -(^((y-1) &^ x) + 1)
+	y1 := nat(nil).sub(y.abs, natOne)
+	z.abs = z.abs.add(z.abs.andNot(y1, x.abs), natOne)
+	z.neg = true // z cannot be zero if one of x or y is negative
+	return z
+}
+
+// Xor sets z = x ^ y and returns z.
+func (z *Int) Xor(x, y *Int) *Int {
+	if x.neg == y.neg {
+		if x.neg {
+			// (-x) ^ (-y) == ^(x-1) ^ ^(y-1) == (x-1) ^ (y-1)
+			x1 := nat(nil).sub(x.abs, natOne)
+			y1 := nat(nil).sub(y.abs, natOne)
+			z.abs = z.abs.xor(x1, y1)
+			z.neg = false
+			return z
+		}
+
+		// x ^ y == x ^ y
+		z.abs = z.abs.xor(x.abs, y.abs)
+		z.neg = false
+		return z
+	}
+
+	// x.neg != y.neg
+	if x.neg {
+		x, y = y, x // ^ is symmetric
+	}
+
+	// x ^ (-y) == x ^ ^(y-1) == ^(x ^ (y-1)) == -((x ^ (y-1)) + 1)
+	y1 := nat(nil).sub(y.abs, natOne)
+	z.abs = z.abs.add(z.abs.xor(x.abs, y1), natOne)
+	z.neg = true // z cannot be zero if only one of x or y is negative
+	return z
+}
+
+// Not sets z = ^x and returns z.
+func (z *Int) Not(x *Int) *Int {
+	if x.neg {
+		// ^(-x) == ^(^(x-1)) == x-1
+		z.abs = z.abs.sub(x.abs, natOne)
+		z.neg = false
+		return z
+	}
+
+	// ^x == -x-1 == -(x+1)
+	z.abs = z.abs.add(x.abs, natOne)
+	z.neg = true // z cannot be zero if x is positive
+	return z
+}
+
+// Gob codec version. Permits backward-compatible changes to the encoding.
+const intGobVersion byte = 1
+
+// GobEncode implements the gob.GobEncoder interface.
+func (x *Int) GobEncode() ([]byte, error) {
+	if x == nil {
+		return nil, nil
+	}
+	buf := make([]byte, 1+len(x.abs)*_S) // extra byte for version and sign bit
+	i := x.abs.bytes(buf) - 1            // i >= 0
+	b := intGobVersion << 1              // make space for sign bit
+	if x.neg {
+		b |= 1
+	}
+	buf[i] = b
+	return buf[i:], nil
+}
+
+// GobDecode implements the gob.GobDecoder interface.
+func (z *Int) GobDecode(buf []byte) error {
+	if len(buf) == 0 {
+		// Other side sent a nil or default value.
+		*z = Int{}
+		return nil
+	}
+	b := buf[0]
+	if b>>1 != intGobVersion {
+		return fmt.Errorf("Int.GobDecode: encoding version %d not supported", b>>1)
+	}
+	z.neg = b&1 != 0
+	z.abs = z.abs.setBytes(buf[1:])
+	return nil
+}
+
+// MarshalJSON implements the json.Marshaler interface.
+func (z *Int) MarshalJSON() ([]byte, error) {
+	// TODO(gri): get rid of the []byte/string conversions
+	return []byte(z.String()), nil
+}
+
+// UnmarshalJSON implements the json.Unmarshaler interface.
+func (z *Int) UnmarshalJSON(text []byte) error {
+	// TODO(gri): get rid of the []byte/string conversions
+	if _, ok := z.SetString(string(text), 0); !ok {
+		return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Int", text)
+	}
+	return nil
+}
+
+// MarshalText implements the encoding.TextMarshaler interface.
+func (z *Int) MarshalText() (text []byte, err error) {
+	return []byte(z.String()), nil
+}
+
+// UnmarshalText implements the encoding.TextUnmarshaler interface.
+func (z *Int) UnmarshalText(text []byte) error {
+	if _, ok := z.SetString(string(text), 0); !ok {
+		return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Int", text)
+	}
+	return nil
+}
diff --git a/src/cmd/compile/internal/big/int_test.go b/src/cmd/compile/internal/big/int_test.go
new file mode 100644
index 0000000..16eed9a
--- /dev/null
+++ b/src/cmd/compile/internal/big/int_test.go
@@ -0,0 +1,1525 @@
+// 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 big
+
+import (
+	"bytes"
+	"encoding/gob"
+	"encoding/hex"
+	"encoding/json"
+	"encoding/xml"
+	"fmt"
+	"math/rand"
+	"testing"
+	"testing/quick"
+)
+
+func isNormalized(x *Int) bool {
+	if len(x.abs) == 0 {
+		return !x.neg
+	}
+	// len(x.abs) > 0
+	return x.abs[len(x.abs)-1] != 0
+}
+
+type funZZ func(z, x, y *Int) *Int
+type argZZ struct {
+	z, x, y *Int
+}
+
+var sumZZ = []argZZ{
+	{NewInt(0), NewInt(0), NewInt(0)},
+	{NewInt(1), NewInt(1), NewInt(0)},
+	{NewInt(1111111110), NewInt(123456789), NewInt(987654321)},
+	{NewInt(-1), NewInt(-1), NewInt(0)},
+	{NewInt(864197532), NewInt(-123456789), NewInt(987654321)},
+	{NewInt(-1111111110), NewInt(-123456789), NewInt(-987654321)},
+}
+
+var prodZZ = []argZZ{
+	{NewInt(0), NewInt(0), NewInt(0)},
+	{NewInt(0), NewInt(1), NewInt(0)},
+	{NewInt(1), NewInt(1), NewInt(1)},
+	{NewInt(-991 * 991), NewInt(991), NewInt(-991)},
+	// TODO(gri) add larger products
+}
+
+func TestSignZ(t *testing.T) {
+	var zero Int
+	for _, a := range sumZZ {
+		s := a.z.Sign()
+		e := a.z.Cmp(&zero)
+		if s != e {
+			t.Errorf("got %d; want %d for z = %v", s, e, a.z)
+		}
+	}
+}
+
+func TestSetZ(t *testing.T) {
+	for _, a := range sumZZ {
+		var z Int
+		z.Set(a.z)
+		if !isNormalized(&z) {
+			t.Errorf("%v is not normalized", z)
+		}
+		if (&z).Cmp(a.z) != 0 {
+			t.Errorf("got z = %v; want %v", z, a.z)
+		}
+	}
+}
+
+func TestAbsZ(t *testing.T) {
+	var zero Int
+	for _, a := range sumZZ {
+		var z Int
+		z.Abs(a.z)
+		var e Int
+		e.Set(a.z)
+		if e.Cmp(&zero) < 0 {
+			e.Sub(&zero, &e)
+		}
+		if z.Cmp(&e) != 0 {
+			t.Errorf("got z = %v; want %v", z, e)
+		}
+	}
+}
+
+func testFunZZ(t *testing.T, msg string, f funZZ, a argZZ) {
+	var z Int
+	f(&z, a.x, a.y)
+	if !isNormalized(&z) {
+		t.Errorf("%s%v is not normalized", msg, z)
+	}
+	if (&z).Cmp(a.z) != 0 {
+		t.Errorf("%s%+v\n\tgot z = %v; want %v", msg, a, &z, a.z)
+	}
+}
+
+func TestSumZZ(t *testing.T) {
+	AddZZ := func(z, x, y *Int) *Int { return z.Add(x, y) }
+	SubZZ := func(z, x, y *Int) *Int { return z.Sub(x, y) }
+	for _, a := range sumZZ {
+		arg := a
+		testFunZZ(t, "AddZZ", AddZZ, arg)
+
+		arg = argZZ{a.z, a.y, a.x}
+		testFunZZ(t, "AddZZ symmetric", AddZZ, arg)
+
+		arg = argZZ{a.x, a.z, a.y}
+		testFunZZ(t, "SubZZ", SubZZ, arg)
+
+		arg = argZZ{a.y, a.z, a.x}
+		testFunZZ(t, "SubZZ symmetric", SubZZ, arg)
+	}
+}
+
+func TestProdZZ(t *testing.T) {
+	MulZZ := func(z, x, y *Int) *Int { return z.Mul(x, y) }
+	for _, a := range prodZZ {
+		arg := a
+		testFunZZ(t, "MulZZ", MulZZ, arg)
+
+		arg = argZZ{a.z, a.y, a.x}
+		testFunZZ(t, "MulZZ symmetric", MulZZ, arg)
+	}
+}
+
+// mulBytes returns x*y via grade school multiplication. Both inputs
+// and the result are assumed to be in big-endian representation (to
+// match the semantics of Int.Bytes and Int.SetBytes).
+func mulBytes(x, y []byte) []byte {
+	z := make([]byte, len(x)+len(y))
+
+	// multiply
+	k0 := len(z) - 1
+	for j := len(y) - 1; j >= 0; j-- {
+		d := int(y[j])
+		if d != 0 {
+			k := k0
+			carry := 0
+			for i := len(x) - 1; i >= 0; i-- {
+				t := int(z[k]) + int(x[i])*d + carry
+				z[k], carry = byte(t), t>>8
+				k--
+			}
+			z[k] = byte(carry)
+		}
+		k0--
+	}
+
+	// normalize (remove leading 0's)
+	i := 0
+	for i < len(z) && z[i] == 0 {
+		i++
+	}
+
+	return z[i:]
+}
+
+func checkMul(a, b []byte) bool {
+	var x, y, z1 Int
+	x.SetBytes(a)
+	y.SetBytes(b)
+	z1.Mul(&x, &y)
+
+	var z2 Int
+	z2.SetBytes(mulBytes(a, b))
+
+	return z1.Cmp(&z2) == 0
+}
+
+func TestMul(t *testing.T) {
+	if err := quick.Check(checkMul, nil); err != nil {
+		t.Error(err)
+	}
+}
+
+var mulRangesZ = []struct {
+	a, b int64
+	prod string
+}{
+	// entirely positive ranges are covered by mulRangesN
+	{-1, 1, "0"},
+	{-2, -1, "2"},
+	{-3, -2, "6"},
+	{-3, -1, "-6"},
+	{1, 3, "6"},
+	{-10, -10, "-10"},
+	{0, -1, "1"},                      // empty range
+	{-1, -100, "1"},                   // empty range
+	{-1, 1, "0"},                      // range includes 0
+	{-1e9, 0, "0"},                    // range includes 0
+	{-1e9, 1e9, "0"},                  // range includes 0
+	{-10, -1, "3628800"},              // 10!
+	{-20, -2, "-2432902008176640000"}, // -20!
+	{-99, -1,
+		"-933262154439441526816992388562667004907159682643816214685929" +
+			"638952175999932299156089414639761565182862536979208272237582" +
+			"511852109168640000000000000000000000", // -99!
+	},
+}
+
+func TestMulRangeZ(t *testing.T) {
+	var tmp Int
+	// test entirely positive ranges
+	for i, r := range mulRangesN {
+		prod := tmp.MulRange(int64(r.a), int64(r.b)).String()
+		if prod != r.prod {
+			t.Errorf("#%da: got %s; want %s", i, prod, r.prod)
+		}
+	}
+	// test other ranges
+	for i, r := range mulRangesZ {
+		prod := tmp.MulRange(r.a, r.b).String()
+		if prod != r.prod {
+			t.Errorf("#%db: got %s; want %s", i, prod, r.prod)
+		}
+	}
+}
+
+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
+	q, r int64 // T-division
+	d, m int64 // Euclidian division
+}{
+	{5, 3, 1, 2, 1, 2},
+	{-5, 3, -1, -2, -2, 1},
+	{5, -3, -1, 2, -1, 2},
+	{-5, -3, 1, -2, 2, 1},
+	{1, 2, 0, 1, 0, 1},
+	{8, 4, 2, 0, 2, 0},
+}
+
+func TestDivisionSigns(t *testing.T) {
+	for i, test := range divisionSignsTests {
+		x := NewInt(test.x)
+		y := NewInt(test.y)
+		q := NewInt(test.q)
+		r := NewInt(test.r)
+		d := NewInt(test.d)
+		m := NewInt(test.m)
+
+		q1 := new(Int).Quo(x, y)
+		r1 := new(Int).Rem(x, y)
+		if !isNormalized(q1) {
+			t.Errorf("#%d Quo: %v is not normalized", i, *q1)
+		}
+		if !isNormalized(r1) {
+			t.Errorf("#%d Rem: %v is not normalized", i, *r1)
+		}
+		if q1.Cmp(q) != 0 || r1.Cmp(r) != 0 {
+			t.Errorf("#%d QuoRem: got (%s, %s), want (%s, %s)", i, q1, r1, q, r)
+		}
+
+		q2, r2 := new(Int).QuoRem(x, y, new(Int))
+		if !isNormalized(q2) {
+			t.Errorf("#%d Quo: %v is not normalized", i, *q2)
+		}
+		if !isNormalized(r2) {
+			t.Errorf("#%d Rem: %v is not normalized", i, *r2)
+		}
+		if q2.Cmp(q) != 0 || r2.Cmp(r) != 0 {
+			t.Errorf("#%d QuoRem: got (%s, %s), want (%s, %s)", i, q2, r2, q, r)
+		}
+
+		d1 := new(Int).Div(x, y)
+		m1 := new(Int).Mod(x, y)
+		if !isNormalized(d1) {
+			t.Errorf("#%d Div: %v is not normalized", i, *d1)
+		}
+		if !isNormalized(m1) {
+			t.Errorf("#%d Mod: %v is not normalized", i, *m1)
+		}
+		if d1.Cmp(d) != 0 || m1.Cmp(m) != 0 {
+			t.Errorf("#%d DivMod: got (%s, %s), want (%s, %s)", i, d1, m1, d, m)
+		}
+
+		d2, m2 := new(Int).DivMod(x, y, new(Int))
+		if !isNormalized(d2) {
+			t.Errorf("#%d Div: %v is not normalized", i, *d2)
+		}
+		if !isNormalized(m2) {
+			t.Errorf("#%d Mod: %v is not normalized", i, *m2)
+		}
+		if d2.Cmp(d) != 0 || m2.Cmp(m) != 0 {
+			t.Errorf("#%d DivMod: got (%s, %s), want (%s, %s)", i, d2, m2, d, m)
+		}
+	}
+}
+
+func norm(x nat) nat {
+	i := len(x)
+	for i > 0 && x[i-1] == 0 {
+		i--
+	}
+	return x[:i]
+}
+
+func TestBits(t *testing.T) {
+	for _, test := range []nat{
+		nil,
+		{0},
+		{1},
+		{0, 1, 2, 3, 4},
+		{4, 3, 2, 1, 0},
+		{4, 3, 2, 1, 0, 0, 0, 0},
+	} {
+		var z Int
+		z.neg = true
+		got := z.SetBits(test)
+		want := norm(test)
+		if got.abs.cmp(want) != 0 {
+			t.Errorf("SetBits(%v) = %v; want %v", test, got.abs, want)
+		}
+
+		if got.neg {
+			t.Errorf("SetBits(%v): got negative result", test)
+		}
+
+		bits := nat(z.Bits())
+		if bits.cmp(want) != 0 {
+			t.Errorf("%v.Bits() = %v; want %v", z.abs, bits, want)
+		}
+	}
+}
+
+func checkSetBytes(b []byte) bool {
+	hex1 := hex.EncodeToString(new(Int).SetBytes(b).Bytes())
+	hex2 := hex.EncodeToString(b)
+
+	for len(hex1) < len(hex2) {
+		hex1 = "0" + hex1
+	}
+
+	for len(hex1) > len(hex2) {
+		hex2 = "0" + hex2
+	}
+
+	return hex1 == hex2
+}
+
+func TestSetBytes(t *testing.T) {
+	if err := quick.Check(checkSetBytes, nil); err != nil {
+		t.Error(err)
+	}
+}
+
+func checkBytes(b []byte) bool {
+	b2 := new(Int).SetBytes(b).Bytes()
+	return bytes.Equal(b, b2)
+}
+
+func TestBytes(t *testing.T) {
+	if err := quick.Check(checkBytes, nil); err != nil {
+		t.Error(err)
+	}
+}
+
+func checkQuo(x, y []byte) bool {
+	u := new(Int).SetBytes(x)
+	v := new(Int).SetBytes(y)
+
+	if len(v.abs) == 0 {
+		return true
+	}
+
+	r := new(Int)
+	q, r := new(Int).QuoRem(u, v, r)
+
+	if r.Cmp(v) >= 0 {
+		return false
+	}
+
+	uprime := new(Int).Set(q)
+	uprime.Mul(uprime, v)
+	uprime.Add(uprime, r)
+
+	return uprime.Cmp(u) == 0
+}
+
+var quoTests = []struct {
+	x, y string
+	q, r string
+}{
+	{
+		"476217953993950760840509444250624797097991362735329973741718102894495832294430498335824897858659711275234906400899559094370964723884706254265559534144986498357",
+		"9353930466774385905609975137998169297361893554149986716853295022578535724979483772383667534691121982974895531435241089241440253066816724367338287092081996",
+		"50911",
+		"1",
+	},
+	{
+		"11510768301994997771168",
+		"1328165573307167369775",
+		"8",
+		"885443715537658812968",
+	},
+}
+
+func TestQuo(t *testing.T) {
+	if err := quick.Check(checkQuo, nil); err != nil {
+		t.Error(err)
+	}
+
+	for i, test := range quoTests {
+		x, _ := new(Int).SetString(test.x, 10)
+		y, _ := new(Int).SetString(test.y, 10)
+		expectedQ, _ := new(Int).SetString(test.q, 10)
+		expectedR, _ := new(Int).SetString(test.r, 10)
+
+		r := new(Int)
+		q, r := new(Int).QuoRem(x, y, r)
+
+		if q.Cmp(expectedQ) != 0 || r.Cmp(expectedR) != 0 {
+			t.Errorf("#%d got (%s, %s) want (%s, %s)", i, q, r, expectedQ, expectedR)
+		}
+	}
+}
+
+func TestQuoStepD6(t *testing.T) {
+	// See Knuth, Volume 2, section 4.3.1, exercise 21. This code exercises
+	// a code path which only triggers 1 in 10^{-19} cases.
+
+	u := &Int{false, nat{0, 0, 1 + 1<<(_W-1), _M ^ (1 << (_W - 1))}}
+	v := &Int{false, nat{5, 2 + 1<<(_W-1), 1 << (_W - 1)}}
+
+	r := new(Int)
+	q, r := new(Int).QuoRem(u, v, r)
+	const expectedQ64 = "18446744073709551613"
+	const expectedR64 = "3138550867693340382088035895064302439801311770021610913807"
+	const expectedQ32 = "4294967293"
+	const expectedR32 = "39614081266355540837921718287"
+	if q.String() != expectedQ64 && q.String() != expectedQ32 ||
+		r.String() != expectedR64 && r.String() != expectedR32 {
+		t.Errorf("got (%s, %s) want (%s, %s) or (%s, %s)", q, r, expectedQ64, expectedR64, expectedQ32, expectedR32)
+	}
+}
+
+var bitLenTests = []struct {
+	in  string
+	out int
+}{
+	{"-1", 1},
+	{"0", 0},
+	{"1", 1},
+	{"2", 2},
+	{"4", 3},
+	{"0xabc", 12},
+	{"0x8000", 16},
+	{"0x80000000", 32},
+	{"0x800000000000", 48},
+	{"0x8000000000000000", 64},
+	{"0x80000000000000000000", 80},
+	{"-0x4000000000000000000000", 87},
+}
+
+func TestBitLen(t *testing.T) {
+	for i, test := range bitLenTests {
+		x, ok := new(Int).SetString(test.in, 0)
+		if !ok {
+			t.Errorf("#%d test input invalid: %s", i, test.in)
+			continue
+		}
+
+		if n := x.BitLen(); n != test.out {
+			t.Errorf("#%d got %d want %d", i, n, test.out)
+		}
+	}
+}
+
+var expTests = []struct {
+	x, y, m string
+	out     string
+}{
+	// y <= 0
+	{"0", "0", "", "1"},
+	{"1", "0", "", "1"},
+	{"-10", "0", "", "1"},
+	{"1234", "-1", "", "1"},
+
+	// m == 1
+	{"0", "0", "1", "0"},
+	{"1", "0", "1", "0"},
+	{"-10", "0", "1", "0"},
+	{"1234", "-1", "1", "0"},
+
+	// misc
+	{"5", "1", "3", "2"},
+	{"5", "-7", "", "1"},
+	{"-5", "-7", "", "1"},
+	{"5", "0", "", "1"},
+	{"-5", "0", "", "1"},
+	{"5", "1", "", "5"},
+	{"-5", "1", "", "-5"},
+	{"-5", "1", "7", "2"},
+	{"-2", "3", "2", "0"},
+	{"5", "2", "", "25"},
+	{"1", "65537", "2", "1"},
+	{"0x8000000000000000", "2", "", "0x40000000000000000000000000000000"},
+	{"0x8000000000000000", "2", "6719", "4944"},
+	{"0x8000000000000000", "3", "6719", "5447"},
+	{"0x8000000000000000", "1000", "6719", "1603"},
+	{"0x8000000000000000", "1000000", "6719", "3199"},
+	{"0x8000000000000000", "-1000000", "6719", "1"},
+	{
+		"2938462938472983472983659726349017249287491026512746239764525612965293865296239471239874193284792387498274256129746192347",
+		"298472983472983471903246121093472394872319615612417471234712061",
+		"29834729834729834729347290846729561262544958723956495615629569234729836259263598127342374289365912465901365498236492183464",
+		"23537740700184054162508175125554701713153216681790245129157191391322321508055833908509185839069455749219131480588829346291",
+	},
+	// test case for issue 8822
+	{
+		"-0x1BCE04427D8032319A89E5C4136456671AC620883F2C4139E57F91307C485AD2D6204F4F87A58262652DB5DBBAC72B0613E51B835E7153BEC6068F5C8D696B74DBD18FEC316AEF73985CF0475663208EB46B4F17DD9DA55367B03323E5491A70997B90C059FB34809E6EE55BCFBD5F2F52233BFE62E6AA9E4E26A1D4C2439883D14F2633D55D8AA66A1ACD5595E778AC3A280517F1157989E70C1A437B849F1877B779CC3CDDEDE2DAA6594A6C66D181A00A5F777EE60596D8773998F6E988DEAE4CCA60E4DDCF9590543C89F74F603259FCAD71660D30294FBBE6490300F78A9D63FA660DC9417B8B9DDA28BEB3977B621B98 [...]
+		"0xB08FFB20760FFED58FADA86DFEF71AD72AA0FA763219618FE022C197E54708BB1191C66470250FCE8879487507CEE41381CA4D932F81C2B3F1AB20B539D50DCD",
+		"0xAC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050A37329CBB4A099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50E8083969EDB767B0CF6095179A163AB3661A05FBD5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF747359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A436C6481F1D2B9078717461A5B9D32E688F87748544523B524B0D57D5EA77A2775D2ECFA032CFBDBF52FB3786160279004E57AE6AF874E7303CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DBFBB694B5C803D89F7AE435DE236D525F54759B65E37 [...]
+		"214842521977763024996399388837777103219931130979872010505011829095813593576185795667465563725893853616836105247305090413288550665149633855225708948390358847130516401714741865487135466864767613064364341464751401562843891818086750165768458333404948482836810888865842197505544080605567694866280290287207273932931116788263564804554339092335205041120744013761330771504712375494741491902420104695390064495966115766125739557543490423291306311282346379247864665857034884605402284774408534933920862 [...]
+	},
+}
+
+func TestExp(t *testing.T) {
+	for i, test := range expTests {
+		x, ok1 := new(Int).SetString(test.x, 0)
+		y, ok2 := new(Int).SetString(test.y, 0)
+		out, ok3 := new(Int).SetString(test.out, 0)
+
+		var ok4 bool
+		var m *Int
+
+		if len(test.m) == 0 {
+			m, ok4 = nil, true
+		} else {
+			m, ok4 = new(Int).SetString(test.m, 0)
+		}
+
+		if !ok1 || !ok2 || !ok3 || !ok4 {
+			t.Errorf("#%d: error in input", i)
+			continue
+		}
+
+		z1 := new(Int).Exp(x, y, m)
+		if !isNormalized(z1) {
+			t.Errorf("#%d: %v is not normalized", i, *z1)
+		}
+		if z1.Cmp(out) != 0 {
+			t.Errorf("#%d: got %s want %s", i, z1, out)
+		}
+
+		if m == nil {
+			// The result should be the same as for m == 0;
+			// specifically, there should be no div-zero panic.
+			m = &Int{abs: nat{}} // m != nil && len(m.abs) == 0
+			z2 := new(Int).Exp(x, y, m)
+			if z2.Cmp(z1) != 0 {
+				t.Errorf("#%d: got %s want %s", i, z2, z1)
+			}
+		}
+	}
+}
+
+func checkGcd(aBytes, bBytes []byte) bool {
+	x := new(Int)
+	y := new(Int)
+	a := new(Int).SetBytes(aBytes)
+	b := new(Int).SetBytes(bBytes)
+
+	d := new(Int).GCD(x, y, a, b)
+	x.Mul(x, a)
+	y.Mul(y, b)
+	x.Add(x, y)
+
+	return x.Cmp(d) == 0
+}
+
+var gcdTests = []struct {
+	d, x, y, a, b string
+}{
+	// a <= 0 || b <= 0
+	{"0", "0", "0", "0", "0"},
+	{"0", "0", "0", "0", "7"},
+	{"0", "0", "0", "11", "0"},
+	{"0", "0", "0", "-77", "35"},
+	{"0", "0", "0", "64515", "-24310"},
+	{"0", "0", "0", "-64515", "-24310"},
+
+	{"1", "-9", "47", "120", "23"},
+	{"7", "1", "-2", "77", "35"},
+	{"935", "-3", "8", "64515", "24310"},
+	{"935000000000000000", "-3", "8", "64515000000000000000", "24310000000000000000"},
+	{"1", "-221", "22059940471369027483332068679400581064239780177629666810348940098015901108344", "98920366548084643601728869055592650835572950932266967461790948584315647051443", "991"},
+
+	// test early exit (after one Euclidean iteration) in binaryGCD
+	{"1", "", "", "1", "98920366548084643601728869055592650835572950932266967461790948584315647051443"},
+}
+
+func testGcd(t *testing.T, d, x, y, a, b *Int) {
+	var X *Int
+	if x != nil {
+		X = new(Int)
+	}
+	var Y *Int
+	if y != nil {
+		Y = new(Int)
+	}
+
+	D := new(Int).GCD(X, Y, a, b)
+	if D.Cmp(d) != 0 {
+		t.Errorf("GCD(%s, %s): got d = %s, want %s", a, b, D, d)
+	}
+	if x != nil && X.Cmp(x) != 0 {
+		t.Errorf("GCD(%s, %s): got x = %s, want %s", a, b, X, x)
+	}
+	if y != nil && Y.Cmp(y) != 0 {
+		t.Errorf("GCD(%s, %s): got y = %s, want %s", a, b, Y, y)
+	}
+
+	// binaryGCD requires a > 0 && b > 0
+	if a.Sign() <= 0 || b.Sign() <= 0 {
+		return
+	}
+
+	D.binaryGCD(a, b)
+	if D.Cmp(d) != 0 {
+		t.Errorf("binaryGcd(%s, %s): got d = %s, want %s", a, b, D, d)
+	}
+}
+
+func TestGcd(t *testing.T) {
+	for _, test := range gcdTests {
+		d, _ := new(Int).SetString(test.d, 0)
+		x, _ := new(Int).SetString(test.x, 0)
+		y, _ := new(Int).SetString(test.y, 0)
+		a, _ := new(Int).SetString(test.a, 0)
+		b, _ := new(Int).SetString(test.b, 0)
+
+		testGcd(t, d, nil, nil, a, b)
+		testGcd(t, d, x, nil, a, b)
+		testGcd(t, d, nil, y, a, b)
+		testGcd(t, d, x, y, a, b)
+	}
+
+	quick.Check(checkGcd, nil)
+}
+
+var primes = []string{
+	"2",
+	"3",
+	"5",
+	"7",
+	"11",
+
+	"13756265695458089029",
+	"13496181268022124907",
+	"10953742525620032441",
+	"17908251027575790097",
+
+	// https://golang.org/issue/638
+	"18699199384836356663",
+
+	"98920366548084643601728869055592650835572950932266967461790948584315647051443",
+	"94560208308847015747498523884063394671606671904944666360068158221458669711639",
+
+	// http://primes.utm.edu/lists/small/small3.html
+	"449417999055441493994709297093108513015373787049558499205492347871729927573118262811508386655998299074566974373711472560655026288668094291699357843464363003144674940345912431129144354948751003607115263071543163",
+	"230975859993204150666423538988557839555560243929065415434980904258310530753006723857139742334640122533598517597674807096648905501653461687601339782814316124971547968912893214002992086353183070342498989426570593",
+	"5521712099665906221540423207019333379125265462121169655563495403888449493493629943498064604536961775110765377745550377067893607246020694972959780839151452457728855382113555867743022746090187341871655890805971735385789993",
+	"203956878356401977405765866929034577280193993314348263094772646453283062722701277632936616063144088173312372882677123879538709400158306567338328279154499698366071906766440037074217117805690872792848149112022286332144876183376326512083574821647933992961249917319836219304274280243803104015000563790123",
+
+	// ECC primes: http://tools.ietf.org/html/draft-ladd-safecurves-02
+	"3618502788666131106986593281521497120414687020801267626233049500247285301239",                                                                                  // Curve1174: 2^251-9
+	"57896044618658097711785492504343953926634992332820282019728792003956564819949",                                                                                 // Curve25519: 2^255-19
+	"9850501549098619803069760025035903451269934817616361666987073351061430442874302652853566563721228910201656997576599",                                           // E-382: 2^382-105
+	"42307582002575910332922579714097346549017899709713998034217522897561970639123926132812109468141778230245837569601494931472367",                                 // Curve41417: 2^414-17
+	"6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151", // E-521: 2^521-1
+}
+
+var composites = []string{
+	"0",
+	"1",
+	"21284175091214687912771199898307297748211672914763848041968395774954376176754",
+	"6084766654921918907427900243509372380954290099172559290432744450051395395951",
+	"84594350493221918389213352992032324280367711247940675652888030554255915464401",
+	"82793403787388584738507275144194252681",
+}
+
+func TestProbablyPrime(t *testing.T) {
+	nreps := 20
+	if testing.Short() {
+		nreps = 1
+	}
+	for i, s := range primes {
+		p, _ := new(Int).SetString(s, 10)
+		if !p.ProbablyPrime(nreps) {
+			t.Errorf("#%d prime found to be non-prime (%s)", i, s)
+		}
+	}
+
+	for i, s := range composites {
+		c, _ := new(Int).SetString(s, 10)
+		if c.ProbablyPrime(nreps) {
+			t.Errorf("#%d composite found to be prime (%s)", i, s)
+		}
+		if testing.Short() {
+			break
+		}
+	}
+
+	// check that ProbablyPrime panics if n <= 0
+	c := NewInt(11) // a prime
+	for _, n := range []int{-1, 0, 1} {
+		func() {
+			defer func() {
+				if n <= 0 && recover() == nil {
+					t.Fatalf("expected panic from ProbablyPrime(%d)", n)
+				}
+			}()
+			if !c.ProbablyPrime(n) {
+				t.Fatalf("%v should be a prime", c)
+			}
+		}()
+	}
+}
+
+type intShiftTest struct {
+	in    string
+	shift uint
+	out   string
+}
+
+var rshTests = []intShiftTest{
+	{"0", 0, "0"},
+	{"-0", 0, "0"},
+	{"0", 1, "0"},
+	{"0", 2, "0"},
+	{"1", 0, "1"},
+	{"1", 1, "0"},
+	{"1", 2, "0"},
+	{"2", 0, "2"},
+	{"2", 1, "1"},
+	{"-1", 0, "-1"},
+	{"-1", 1, "-1"},
+	{"-1", 10, "-1"},
+	{"-100", 2, "-25"},
+	{"-100", 3, "-13"},
+	{"-100", 100, "-1"},
+	{"4294967296", 0, "4294967296"},
+	{"4294967296", 1, "2147483648"},
+	{"4294967296", 2, "1073741824"},
+	{"18446744073709551616", 0, "18446744073709551616"},
+	{"18446744073709551616", 1, "9223372036854775808"},
+	{"18446744073709551616", 2, "4611686018427387904"},
+	{"18446744073709551616", 64, "1"},
+	{"340282366920938463463374607431768211456", 64, "18446744073709551616"},
+	{"340282366920938463463374607431768211456", 128, "1"},
+}
+
+func TestRsh(t *testing.T) {
+	for i, test := range rshTests {
+		in, _ := new(Int).SetString(test.in, 10)
+		expected, _ := new(Int).SetString(test.out, 10)
+		out := new(Int).Rsh(in, test.shift)
+
+		if !isNormalized(out) {
+			t.Errorf("#%d: %v is not normalized", i, *out)
+		}
+		if out.Cmp(expected) != 0 {
+			t.Errorf("#%d: got %s want %s", i, out, expected)
+		}
+	}
+}
+
+func TestRshSelf(t *testing.T) {
+	for i, test := range rshTests {
+		z, _ := new(Int).SetString(test.in, 10)
+		expected, _ := new(Int).SetString(test.out, 10)
+		z.Rsh(z, test.shift)
+
+		if !isNormalized(z) {
+			t.Errorf("#%d: %v is not normalized", i, *z)
+		}
+		if z.Cmp(expected) != 0 {
+			t.Errorf("#%d: got %s want %s", i, z, expected)
+		}
+	}
+}
+
+var lshTests = []intShiftTest{
+	{"0", 0, "0"},
+	{"0", 1, "0"},
+	{"0", 2, "0"},
+	{"1", 0, "1"},
+	{"1", 1, "2"},
+	{"1", 2, "4"},
+	{"2", 0, "2"},
+	{"2", 1, "4"},
+	{"2", 2, "8"},
+	{"-87", 1, "-174"},
+	{"4294967296", 0, "4294967296"},
+	{"4294967296", 1, "8589934592"},
+	{"4294967296", 2, "17179869184"},
+	{"18446744073709551616", 0, "18446744073709551616"},
+	{"9223372036854775808", 1, "18446744073709551616"},
+	{"4611686018427387904", 2, "18446744073709551616"},
+	{"1", 64, "18446744073709551616"},
+	{"18446744073709551616", 64, "340282366920938463463374607431768211456"},
+	{"1", 128, "340282366920938463463374607431768211456"},
+}
+
+func TestLsh(t *testing.T) {
+	for i, test := range lshTests {
+		in, _ := new(Int).SetString(test.in, 10)
+		expected, _ := new(Int).SetString(test.out, 10)
+		out := new(Int).Lsh(in, test.shift)
+
+		if !isNormalized(out) {
+			t.Errorf("#%d: %v is not normalized", i, *out)
+		}
+		if out.Cmp(expected) != 0 {
+			t.Errorf("#%d: got %s want %s", i, out, expected)
+		}
+	}
+}
+
+func TestLshSelf(t *testing.T) {
+	for i, test := range lshTests {
+		z, _ := new(Int).SetString(test.in, 10)
+		expected, _ := new(Int).SetString(test.out, 10)
+		z.Lsh(z, test.shift)
+
+		if !isNormalized(z) {
+			t.Errorf("#%d: %v is not normalized", i, *z)
+		}
+		if z.Cmp(expected) != 0 {
+			t.Errorf("#%d: got %s want %s", i, z, expected)
+		}
+	}
+}
+
+func TestLshRsh(t *testing.T) {
+	for i, test := range rshTests {
+		in, _ := new(Int).SetString(test.in, 10)
+		out := new(Int).Lsh(in, test.shift)
+		out = out.Rsh(out, test.shift)
+
+		if !isNormalized(out) {
+			t.Errorf("#%d: %v is not normalized", i, *out)
+		}
+		if in.Cmp(out) != 0 {
+			t.Errorf("#%d: got %s want %s", i, out, in)
+		}
+	}
+	for i, test := range lshTests {
+		in, _ := new(Int).SetString(test.in, 10)
+		out := new(Int).Lsh(in, test.shift)
+		out.Rsh(out, test.shift)
+
+		if !isNormalized(out) {
+			t.Errorf("#%d: %v is not normalized", i, *out)
+		}
+		if in.Cmp(out) != 0 {
+			t.Errorf("#%d: got %s want %s", i, out, in)
+		}
+	}
+}
+
+var int64Tests = []int64{
+	0,
+	1,
+	-1,
+	4294967295,
+	-4294967295,
+	4294967296,
+	-4294967296,
+	9223372036854775807,
+	-9223372036854775807,
+	-9223372036854775808,
+}
+
+func TestInt64(t *testing.T) {
+	for i, testVal := range int64Tests {
+		in := NewInt(testVal)
+		out := in.Int64()
+
+		if out != testVal {
+			t.Errorf("#%d got %d want %d", i, out, testVal)
+		}
+	}
+}
+
+var uint64Tests = []uint64{
+	0,
+	1,
+	4294967295,
+	4294967296,
+	8589934591,
+	8589934592,
+	9223372036854775807,
+	9223372036854775808,
+	18446744073709551615, // 1<<64 - 1
+}
+
+func TestUint64(t *testing.T) {
+	in := new(Int)
+	for i, testVal := range uint64Tests {
+		in.SetUint64(testVal)
+		out := in.Uint64()
+
+		if out != testVal {
+			t.Errorf("#%d got %d want %d", i, out, testVal)
+		}
+
+		str := fmt.Sprint(testVal)
+		strOut := in.String()
+		if strOut != str {
+			t.Errorf("#%d.String got %s want %s", i, strOut, str)
+		}
+	}
+}
+
+var bitwiseTests = []struct {
+	x, y                 string
+	and, or, xor, andNot string
+}{
+	{"0x00", "0x00", "0x00", "0x00", "0x00", "0x00"},
+	{"0x00", "0x01", "0x00", "0x01", "0x01", "0x00"},
+	{"0x01", "0x00", "0x00", "0x01", "0x01", "0x01"},
+	{"-0x01", "0x00", "0x00", "-0x01", "-0x01", "-0x01"},
+	{"-0xaf", "-0x50", "-0xf0", "-0x0f", "0xe1", "0x41"},
+	{"0x00", "-0x01", "0x00", "-0x01", "-0x01", "0x00"},
+	{"0x01", "0x01", "0x01", "0x01", "0x00", "0x00"},
+	{"-0x01", "-0x01", "-0x01", "-0x01", "0x00", "0x00"},
+	{"0x07", "0x08", "0x00", "0x0f", "0x0f", "0x07"},
+	{"0x05", "0x0f", "0x05", "0x0f", "0x0a", "0x00"},
+	{"0xff", "-0x0a", "0xf6", "-0x01", "-0xf7", "0x09"},
+	{"0x013ff6", "0x9a4e", "0x1a46", "0x01bffe", "0x01a5b8", "0x0125b0"},
+	{"-0x013ff6", "0x9a4e", "0x800a", "-0x0125b2", "-0x01a5bc", "-0x01c000"},
+	{"-0x013ff6", "-0x9a4e", "-0x01bffe", "-0x1a46", "0x01a5b8", "0x8008"},
+	{
+		"0x1000009dc6e3d9822cba04129bcbe3401",
+		"0xb9bd7d543685789d57cb918e833af352559021483cdb05cc21fd",
+		"0x1000001186210100001000009048c2001",
+		"0xb9bd7d543685789d57cb918e8bfeff7fddb2ebe87dfbbdfe35fd",
+		"0xb9bd7d543685789d57ca918e8ae69d6fcdb2eae87df2b97215fc",
+		"0x8c40c2d8822caa04120b8321400",
+	},
+	{
+		"0x1000009dc6e3d9822cba04129bcbe3401",
+		"-0xb9bd7d543685789d57cb918e833af352559021483cdb05cc21fd",
+		"0x8c40c2d8822caa04120b8321401",
+		"-0xb9bd7d543685789d57ca918e82229142459020483cd2014001fd",
+		"-0xb9bd7d543685789d57ca918e8ae69d6fcdb2eae87df2b97215fe",
+		"0x1000001186210100001000009048c2000",
+	},
+	{
+		"-0x1000009dc6e3d9822cba04129bcbe3401",
+		"-0xb9bd7d543685789d57cb918e833af352559021483cdb05cc21fd",
+		"-0xb9bd7d543685789d57cb918e8bfeff7fddb2ebe87dfbbdfe35fd",
+		"-0x1000001186210100001000009048c2001",
+		"0xb9bd7d543685789d57ca918e8ae69d6fcdb2eae87df2b97215fc",
+		"0xb9bd7d543685789d57ca918e82229142459020483cd2014001fc",
+	},
+}
+
+type bitFun func(z, x, y *Int) *Int
+
+func testBitFun(t *testing.T, msg string, f bitFun, x, y *Int, exp string) {
+	expected := new(Int)
+	expected.SetString(exp, 0)
+
+	out := f(new(Int), x, y)
+	if out.Cmp(expected) != 0 {
+		t.Errorf("%s: got %s want %s", msg, out, expected)
+	}
+}
+
+func testBitFunSelf(t *testing.T, msg string, f bitFun, x, y *Int, exp string) {
+	self := new(Int)
+	self.Set(x)
+	expected := new(Int)
+	expected.SetString(exp, 0)
+
+	self = f(self, self, y)
+	if self.Cmp(expected) != 0 {
+		t.Errorf("%s: got %s want %s", msg, self, expected)
+	}
+}
+
+func altBit(x *Int, i int) uint {
+	z := new(Int).Rsh(x, uint(i))
+	z = z.And(z, NewInt(1))
+	if z.Cmp(new(Int)) != 0 {
+		return 1
+	}
+	return 0
+}
+
+func altSetBit(z *Int, x *Int, i int, b uint) *Int {
+	one := NewInt(1)
+	m := one.Lsh(one, uint(i))
+	switch b {
+	case 1:
+		return z.Or(x, m)
+	case 0:
+		return z.AndNot(x, m)
+	}
+	panic("set bit is not 0 or 1")
+}
+
+func testBitset(t *testing.T, x *Int) {
+	n := x.BitLen()
+	z := new(Int).Set(x)
+	z1 := new(Int).Set(x)
+	for i := 0; i < n+10; i++ {
+		old := z.Bit(i)
+		old1 := altBit(z1, i)
+		if old != old1 {
+			t.Errorf("bitset: inconsistent value for Bit(%s, %d), got %v want %v", z1, i, old, old1)
+		}
+		z := new(Int).SetBit(z, i, 1)
+		z1 := altSetBit(new(Int), z1, i, 1)
+		if z.Bit(i) == 0 {
+			t.Errorf("bitset: bit %d of %s got 0 want 1", i, x)
+		}
+		if z.Cmp(z1) != 0 {
+			t.Errorf("bitset: inconsistent value after SetBit 1, got %s want %s", z, z1)
+		}
+		z.SetBit(z, i, 0)
+		altSetBit(z1, z1, i, 0)
+		if z.Bit(i) != 0 {
+			t.Errorf("bitset: bit %d of %s got 1 want 0", i, x)
+		}
+		if z.Cmp(z1) != 0 {
+			t.Errorf("bitset: inconsistent value after SetBit 0, got %s want %s", z, z1)
+		}
+		altSetBit(z1, z1, i, old)
+		z.SetBit(z, i, old)
+		if z.Cmp(z1) != 0 {
+			t.Errorf("bitset: inconsistent value after SetBit old, got %s want %s", z, z1)
+		}
+	}
+	if z.Cmp(x) != 0 {
+		t.Errorf("bitset: got %s want %s", z, x)
+	}
+}
+
+var bitsetTests = []struct {
+	x string
+	i int
+	b uint
+}{
+	{"0", 0, 0},
+	{"0", 200, 0},
+	{"1", 0, 1},
+	{"1", 1, 0},
+	{"-1", 0, 1},
+	{"-1", 200, 1},
+	{"0x2000000000000000000000000000", 108, 0},
+	{"0x2000000000000000000000000000", 109, 1},
+	{"0x2000000000000000000000000000", 110, 0},
+	{"-0x2000000000000000000000000001", 108, 1},
+	{"-0x2000000000000000000000000001", 109, 0},
+	{"-0x2000000000000000000000000001", 110, 1},
+}
+
+func TestBitSet(t *testing.T) {
+	for _, test := range bitwiseTests {
+		x := new(Int)
+		x.SetString(test.x, 0)
+		testBitset(t, x)
+		x = new(Int)
+		x.SetString(test.y, 0)
+		testBitset(t, x)
+	}
+	for i, test := range bitsetTests {
+		x := new(Int)
+		x.SetString(test.x, 0)
+		b := x.Bit(test.i)
+		if b != test.b {
+			t.Errorf("#%d got %v want %v", i, b, test.b)
+		}
+	}
+	z := NewInt(1)
+	z.SetBit(NewInt(0), 2, 1)
+	if z.Cmp(NewInt(4)) != 0 {
+		t.Errorf("destination leaked into result; got %s want 4", z)
+	}
+}
+
+func BenchmarkBitset(b *testing.B) {
+	z := new(Int)
+	z.SetBit(z, 512, 1)
+	b.ResetTimer()
+	b.StartTimer()
+	for i := b.N - 1; i >= 0; i-- {
+		z.SetBit(z, i&512, 1)
+	}
+}
+
+func BenchmarkBitsetNeg(b *testing.B) {
+	z := NewInt(-1)
+	z.SetBit(z, 512, 0)
+	b.ResetTimer()
+	b.StartTimer()
+	for i := b.N - 1; i >= 0; i-- {
+		z.SetBit(z, i&512, 0)
+	}
+}
+
+func BenchmarkBitsetOrig(b *testing.B) {
+	z := new(Int)
+	altSetBit(z, z, 512, 1)
+	b.ResetTimer()
+	b.StartTimer()
+	for i := b.N - 1; i >= 0; i-- {
+		altSetBit(z, z, i&512, 1)
+	}
+}
+
+func BenchmarkBitsetNegOrig(b *testing.B) {
+	z := NewInt(-1)
+	altSetBit(z, z, 512, 0)
+	b.ResetTimer()
+	b.StartTimer()
+	for i := b.N - 1; i >= 0; i-- {
+		altSetBit(z, z, i&512, 0)
+	}
+}
+
+func TestBitwise(t *testing.T) {
+	x := new(Int)
+	y := new(Int)
+	for _, test := range bitwiseTests {
+		x.SetString(test.x, 0)
+		y.SetString(test.y, 0)
+
+		testBitFun(t, "and", (*Int).And, x, y, test.and)
+		testBitFunSelf(t, "and", (*Int).And, x, y, test.and)
+		testBitFun(t, "andNot", (*Int).AndNot, x, y, test.andNot)
+		testBitFunSelf(t, "andNot", (*Int).AndNot, x, y, test.andNot)
+		testBitFun(t, "or", (*Int).Or, x, y, test.or)
+		testBitFunSelf(t, "or", (*Int).Or, x, y, test.or)
+		testBitFun(t, "xor", (*Int).Xor, x, y, test.xor)
+		testBitFunSelf(t, "xor", (*Int).Xor, x, y, test.xor)
+	}
+}
+
+var notTests = []struct {
+	in  string
+	out string
+}{
+	{"0", "-1"},
+	{"1", "-2"},
+	{"7", "-8"},
+	{"0", "-1"},
+	{"-81910", "81909"},
+	{
+		"298472983472983471903246121093472394872319615612417471234712061",
+		"-298472983472983471903246121093472394872319615612417471234712062",
+	},
+}
+
+func TestNot(t *testing.T) {
+	in := new(Int)
+	out := new(Int)
+	expected := new(Int)
+	for i, test := range notTests {
+		in.SetString(test.in, 10)
+		expected.SetString(test.out, 10)
+		out = out.Not(in)
+		if out.Cmp(expected) != 0 {
+			t.Errorf("#%d: got %s want %s", i, out, expected)
+		}
+		out = out.Not(out)
+		if out.Cmp(in) != 0 {
+			t.Errorf("#%d: got %s want %s", i, out, in)
+		}
+	}
+}
+
+var modInverseTests = []struct {
+	element string
+	modulus string
+}{
+	{"1234567", "458948883992"},
+	{"239487239847", "2410312426921032588552076022197566074856950548502459942654116941958108831682612228890093858261341614673227141477904012196503648957050582631942730706805009223062734745341073406696246014589361659774041027169249453200378729434170325843778659198143763193776859869524088940195577346119843545301547043747207749969763750084308926339295559968882457872412993810129130294592999947926365264059284647209730384947211681434464714438488520940127459844288859336526896320919633919"},
+}
+
+func TestModInverse(t *testing.T) {
+	var element, modulus, gcd, inverse Int
+	one := NewInt(1)
+	for i, test := range modInverseTests {
+		(&element).SetString(test.element, 10)
+		(&modulus).SetString(test.modulus, 10)
+		(&inverse).ModInverse(&element, &modulus)
+		(&inverse).Mul(&inverse, &element)
+		(&inverse).Mod(&inverse, &modulus)
+		if (&inverse).Cmp(one) != 0 {
+			t.Errorf("#%d: failed (e·e^(-1)=%s)", i, &inverse)
+		}
+	}
+	// exhaustive test for small values
+	for n := 2; n < 100; n++ {
+		(&modulus).SetInt64(int64(n))
+		for x := 1; x < n; x++ {
+			(&element).SetInt64(int64(x))
+			(&gcd).GCD(nil, nil, &element, &modulus)
+			if (&gcd).Cmp(one) != 0 {
+				continue
+			}
+			(&inverse).ModInverse(&element, &modulus)
+			(&inverse).Mul(&inverse, &element)
+			(&inverse).Mod(&inverse, &modulus)
+			if (&inverse).Cmp(one) != 0 {
+				t.Errorf("ModInverse(%d,%d)*%d%%%d=%d, not 1", &element, &modulus, &element, &modulus, &inverse)
+			}
+		}
+	}
+}
+
+// testModSqrt is a helper for TestModSqrt,
+// which checks that ModSqrt can compute a square-root of elt^2.
+func testModSqrt(t *testing.T, elt, mod, sq, sqrt *Int) bool {
+	var sqChk, sqrtChk, sqrtsq Int
+	sq.Mul(elt, elt)
+	sq.Mod(sq, mod)
+	z := sqrt.ModSqrt(sq, mod)
+	if z != sqrt {
+		t.Errorf("ModSqrt returned wrong value %s", z)
+	}
+
+	// test ModSqrt arguments outside the range [0,mod)
+	sqChk.Add(sq, mod)
+	z = sqrtChk.ModSqrt(&sqChk, mod)
+	if z != &sqrtChk || z.Cmp(sqrt) != 0 {
+		t.Errorf("ModSqrt returned inconsistent value %s", z)
+	}
+	sqChk.Sub(sq, mod)
+	z = sqrtChk.ModSqrt(&sqChk, mod)
+	if z != &sqrtChk || z.Cmp(sqrt) != 0 {
+		t.Errorf("ModSqrt returned inconsistent value %s", z)
+	}
+
+	// make sure we actually got a square root
+	if sqrt.Cmp(elt) == 0 {
+		return true // we found the "desired" square root
+	}
+	sqrtsq.Mul(sqrt, sqrt) // make sure we found the "other" one
+	sqrtsq.Mod(&sqrtsq, mod)
+	return sq.Cmp(&sqrtsq) == 0
+}
+
+func TestModSqrt(t *testing.T) {
+	var elt, mod, modx4, sq, sqrt Int
+	r := rand.New(rand.NewSource(9))
+	for i, s := range primes[1:] { // skip 2, use only odd primes
+		mod.SetString(s, 10)
+		modx4.Lsh(&mod, 2)
+
+		// test a few random elements per prime
+		for x := 1; x < 5; x++ {
+			elt.Rand(r, &modx4)
+			elt.Sub(&elt, &mod) // test range [-mod, 3*mod)
+			if !testModSqrt(t, &elt, &mod, &sq, &sqrt) {
+				t.Errorf("#%d: failed (sqrt(e) = %s)", i, &sqrt)
+			}
+		}
+	}
+
+	// exhaustive test for small values
+	for n := 3; n < 100; n++ {
+		mod.SetInt64(int64(n))
+		if !mod.ProbablyPrime(10) {
+			continue
+		}
+		isSquare := make([]bool, n)
+
+		// test all the squares
+		for x := 1; x < n; x++ {
+			elt.SetInt64(int64(x))
+			if !testModSqrt(t, &elt, &mod, &sq, &sqrt) {
+				t.Errorf("#%d: failed (sqrt(%d,%d) = %s)", x, &elt, &mod, &sqrt)
+			}
+			isSquare[sq.Uint64()] = true
+		}
+
+		// test all non-squares
+		for x := 1; x < n; x++ {
+			sq.SetInt64(int64(x))
+			z := sqrt.ModSqrt(&sq, &mod)
+			if !isSquare[x] && z != nil {
+				t.Errorf("#%d: failed (sqrt(%d,%d) = nil)", x, &sqrt, &mod)
+			}
+		}
+	}
+}
+
+func TestJacobi(t *testing.T) {
+	testCases := []struct {
+		x, y   int64
+		result int
+	}{
+		{0, 1, 1},
+		{0, -1, 1},
+		{1, 1, 1},
+		{1, -1, 1},
+		{0, 5, 0},
+		{1, 5, 1},
+		{2, 5, -1},
+		{-2, 5, -1},
+		{2, -5, -1},
+		{-2, -5, 1},
+		{3, 5, -1},
+		{5, 5, 0},
+		{-5, 5, 0},
+		{6, 5, 1},
+		{6, -5, 1},
+		{-6, 5, 1},
+		{-6, -5, -1},
+	}
+
+	var x, y Int
+
+	for i, test := range testCases {
+		x.SetInt64(test.x)
+		y.SetInt64(test.y)
+		expected := test.result
+		actual := Jacobi(&x, &y)
+		if actual != expected {
+			t.Errorf("#%d: Jacobi(%d, %d) = %d, but expected %d", i, test.x, test.y, actual, expected)
+		}
+	}
+}
+
+func TestJacobiPanic(t *testing.T) {
+	const failureMsg = "test failure"
+	defer func() {
+		msg := recover()
+		if msg == nil || msg == failureMsg {
+			panic(msg)
+		}
+		t.Log(msg)
+	}()
+	x := NewInt(1)
+	y := NewInt(2)
+	// Jacobi should panic when the second argument is even.
+	Jacobi(x, y)
+	panic(failureMsg)
+}
+
+var encodingTests = []string{
+	"-539345864568634858364538753846587364875430589374589",
+	"-678645873",
+	"-100",
+	"-2",
+	"-1",
+	"0",
+	"1",
+	"2",
+	"10",
+	"42",
+	"1234567890",
+	"298472983472983471903246121093472394872319615612417471234712061",
+}
+
+func TestIntGobEncoding(t *testing.T) {
+	var medium bytes.Buffer
+	enc := gob.NewEncoder(&medium)
+	dec := gob.NewDecoder(&medium)
+	for _, test := range encodingTests {
+		medium.Reset() // empty buffer for each test case (in case of failures)
+		var tx Int
+		tx.SetString(test, 10)
+		if err := enc.Encode(&tx); err != nil {
+			t.Errorf("encoding of %s failed: %s", &tx, err)
+		}
+		var rx Int
+		if err := dec.Decode(&rx); err != nil {
+			t.Errorf("decoding of %s failed: %s", &tx, err)
+		}
+		if rx.Cmp(&tx) != 0 {
+			t.Errorf("transmission of %s failed: got %s want %s", &tx, &rx, &tx)
+		}
+	}
+}
+
+// Sending a nil Int pointer (inside a slice) on a round trip through gob should yield a zero.
+// TODO: top-level nils.
+func TestGobEncodingNilIntInSlice(t *testing.T) {
+	buf := new(bytes.Buffer)
+	enc := gob.NewEncoder(buf)
+	dec := gob.NewDecoder(buf)
+
+	var in = make([]*Int, 1)
+	err := enc.Encode(&in)
+	if err != nil {
+		t.Errorf("gob encode failed: %q", err)
+	}
+	var out []*Int
+	err = dec.Decode(&out)
+	if err != nil {
+		t.Fatalf("gob decode failed: %q", err)
+	}
+	if len(out) != 1 {
+		t.Fatalf("wrong len; want 1 got %d", len(out))
+	}
+	var zero Int
+	if out[0].Cmp(&zero) != 0 {
+		t.Errorf("transmission of (*Int)(nill) failed: got %s want 0", out)
+	}
+}
+
+func TestIntJSONEncoding(t *testing.T) {
+	for _, test := range encodingTests {
+		var tx Int
+		tx.SetString(test, 10)
+		b, err := json.Marshal(&tx)
+		if err != nil {
+			t.Errorf("marshaling of %s failed: %s", &tx, err)
+		}
+		var rx Int
+		if err := json.Unmarshal(b, &rx); err != nil {
+			t.Errorf("unmarshaling of %s failed: %s", &tx, err)
+		}
+		if rx.Cmp(&tx) != 0 {
+			t.Errorf("JSON encoding of %s failed: got %s want %s", &tx, &rx, &tx)
+		}
+	}
+}
+
+var intVals = []string{
+	"-141592653589793238462643383279502884197169399375105820974944592307816406286",
+	"-1415926535897932384626433832795028841971",
+	"-141592653589793",
+	"-1",
+	"0",
+	"1",
+	"141592653589793",
+	"1415926535897932384626433832795028841971",
+	"141592653589793238462643383279502884197169399375105820974944592307816406286",
+}
+
+func TestIntJSONEncodingTextMarshaller(t *testing.T) {
+	for _, num := range intVals {
+		var tx Int
+		tx.SetString(num, 0)
+		b, err := json.Marshal(&tx)
+		if err != nil {
+			t.Errorf("marshaling of %s failed: %s", &tx, err)
+			continue
+		}
+		var rx Int
+		if err := json.Unmarshal(b, &rx); err != nil {
+			t.Errorf("unmarshaling of %s failed: %s", &tx, err)
+			continue
+		}
+		if rx.Cmp(&tx) != 0 {
+			t.Errorf("JSON encoding of %s failed: got %s want %s", &tx, &rx, &tx)
+		}
+	}
+}
+
+func TestIntXMLEncodingTextMarshaller(t *testing.T) {
+	for _, num := range intVals {
+		var tx Int
+		tx.SetString(num, 0)
+		b, err := xml.Marshal(&tx)
+		if err != nil {
+			t.Errorf("marshaling of %s failed: %s", &tx, err)
+			continue
+		}
+		var rx Int
+		if err := xml.Unmarshal(b, &rx); err != nil {
+			t.Errorf("unmarshaling of %s failed: %s", &tx, err)
+			continue
+		}
+		if rx.Cmp(&tx) != 0 {
+			t.Errorf("XML encoding of %s failed: got %s want %s", &tx, &rx, &tx)
+		}
+	}
+}
+
+func TestIssue2607(t *testing.T) {
+	// This code sequence used to hang.
+	n := NewInt(10)
+	n.Rand(rand.New(rand.NewSource(9)), n)
+}
diff --git a/src/cmd/compile/internal/big/intconv.go b/src/cmd/compile/internal/big/intconv.go
new file mode 100644
index 0000000..9c68a22
--- /dev/null
+++ b/src/cmd/compile/internal/big/intconv.go
@@ -0,0 +1,228 @@
+// 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 int-to-string conversion functions.
+
+package big
+
+import (
+	"errors"
+	"fmt"
+	"io"
+)
+
+func (x *Int) String() string {
+	switch {
+	case x == nil:
+		return "<nil>"
+	case x.neg:
+		return "-" + x.abs.decimalString()
+	}
+	return x.abs.decimalString()
+}
+
+func charset(ch rune) string {
+	switch ch {
+	case 'b':
+		return lowercaseDigits[0:2]
+	case 'o':
+		return lowercaseDigits[0:8]
+	case 'd', 's', 'v':
+		return lowercaseDigits[0:10]
+	case 'x':
+		return lowercaseDigits[0:16]
+	case 'X':
+		return uppercaseDigits[0:16]
+	}
+	return "" // unknown format
+}
+
+// write count copies of text to s
+func writeMultiple(s fmt.State, text string, count int) {
+	if len(text) > 0 {
+		b := []byte(text)
+		for ; count > 0; count-- {
+			s.Write(b)
+		}
+	}
+}
+
+// Format is a support routine for fmt.Formatter. It accepts
+// the formats 'b' (binary), 'o' (octal), 'd' (decimal), 'x'
+// (lowercase hexadecimal), and 'X' (uppercase hexadecimal).
+// Also supported are the full suite of package fmt's format
+// verbs for integral types, including '+', '-', and ' '
+// for sign control, '#' for leading zero in octal and for
+// hexadecimal, a leading "0x" or "0X" for "%#x" and "%#X"
+// respectively, specification of minimum digits precision,
+// output field width, space or zero padding, and left or
+// right justification.
+//
+func (x *Int) Format(s fmt.State, ch rune) {
+	cs := charset(ch)
+
+	// special cases
+	switch {
+	case cs == "":
+		// unknown format
+		fmt.Fprintf(s, "%%!%c(big.Int=%s)", ch, x.String())
+		return
+	case x == nil:
+		fmt.Fprint(s, "<nil>")
+		return
+	}
+
+	// determine sign character
+	sign := ""
+	switch {
+	case x.neg:
+		sign = "-"
+	case s.Flag('+'): // supersedes ' ' when both specified
+		sign = "+"
+	case s.Flag(' '):
+		sign = " "
+	}
+
+	// determine prefix characters for indicating output base
+	prefix := ""
+	if s.Flag('#') {
+		switch ch {
+		case 'o': // octal
+			prefix = "0"
+		case 'x': // hexadecimal
+			prefix = "0x"
+		case 'X':
+			prefix = "0X"
+		}
+	}
+
+	// determine digits with base set by len(cs) and digit characters from cs
+	digits := x.abs.string(cs)
+
+	// number of characters for the three classes of number padding
+	var left int   // space characters to left of digits for right justification ("%8d")
+	var zeroes int // zero characters (actually cs[0]) as left-most digits ("%.8d")
+	var right int  // space characters to right of digits for left justification ("%-8d")
+
+	// determine number padding from precision: the least number of digits to output
+	precision, precisionSet := s.Precision()
+	if precisionSet {
+		switch {
+		case len(digits) < precision:
+			zeroes = precision - len(digits) // count of zero padding
+		case digits == "0" && precision == 0:
+			return // print nothing if zero value (x == 0) and zero precision ("." or ".0")
+		}
+	}
+
+	// determine field pad from width: the least number of characters to output
+	length := len(sign) + len(prefix) + zeroes + len(digits)
+	if width, widthSet := s.Width(); widthSet && length < width { // pad as specified
+		switch d := width - length; {
+		case s.Flag('-'):
+			// pad on the right with spaces; supersedes '0' when both specified
+			right = d
+		case s.Flag('0') && !precisionSet:
+			// pad with zeroes unless precision also specified
+			zeroes = d
+		default:
+			// pad on the left with spaces
+			left = d
+		}
+	}
+
+	// print number as [left pad][sign][prefix][zero pad][digits][right pad]
+	writeMultiple(s, " ", left)
+	writeMultiple(s, sign, 1)
+	writeMultiple(s, prefix, 1)
+	writeMultiple(s, "0", zeroes)
+	writeMultiple(s, digits, 1)
+	writeMultiple(s, " ", right)
+}
+
+// scan sets z to the integer value corresponding to the longest possible prefix
+// read from r representing a signed integer number in a given conversion base.
+// It returns z, the actual conversion base used, and an error, if any. In the
+// error case, the value of z is undefined but the returned value is nil. The
+// syntax follows the syntax of integer literals in Go.
+//
+// The base argument must be 0 or a value from 2 through MaxBase. If the base
+// is 0, the string prefix determines the actual conversion base. A prefix of
+// ``0x'' or ``0X'' selects base 16; the ``0'' prefix selects base 8, and a
+// ``0b'' or ``0B'' prefix selects base 2. Otherwise the selected base is 10.
+//
+func (z *Int) scan(r io.ByteScanner, base int) (*Int, int, error) {
+	// determine sign
+	neg, err := scanSign(r)
+	if err != nil {
+		return nil, 0, err
+	}
+
+	// determine mantissa
+	z.abs, base, _, err = z.abs.scan(r, base, false)
+	if err != nil {
+		return nil, base, err
+	}
+	z.neg = len(z.abs) > 0 && neg // 0 has no sign
+
+	return z, base, nil
+}
+
+func scanSign(r io.ByteScanner) (neg bool, err error) {
+	var ch byte
+	if ch, err = r.ReadByte(); err != nil {
+		return false, err
+	}
+	switch ch {
+	case '-':
+		neg = true
+	case '+':
+		// nothing to do
+	default:
+		r.UnreadByte()
+	}
+	return
+}
+
+// byteReader is a local wrapper around fmt.ScanState;
+// it implements the ByteReader interface.
+type byteReader struct {
+	fmt.ScanState
+}
+
+func (r byteReader) ReadByte() (byte, error) {
+	ch, size, err := r.ReadRune()
+	if size != 1 && err == nil {
+		err = fmt.Errorf("invalid rune %#U", ch)
+	}
+	return byte(ch), err
+}
+
+func (r byteReader) UnreadByte() error {
+	return r.UnreadRune()
+}
+
+// Scan is a support routine for fmt.Scanner; it sets z to the value of
+// the scanned number. It accepts the formats 'b' (binary), 'o' (octal),
+// 'd' (decimal), 'x' (lowercase hexadecimal), and 'X' (uppercase hexadecimal).
+func (z *Int) Scan(s fmt.ScanState, ch rune) error {
+	s.SkipSpace() // skip leading space characters
+	base := 0
+	switch ch {
+	case 'b':
+		base = 2
+	case 'o':
+		base = 8
+	case 'd':
+		base = 10
+	case 'x', 'X':
+		base = 16
+	case 's', 'v':
+		// let scan determine the base
+	default:
+		return errors.New("Int.Scan: invalid verb")
+	}
+	_, _, err := z.scan(byteReader{s}, base)
+	return err
+}
diff --git a/src/cmd/compile/internal/big/intconv_test.go b/src/cmd/compile/internal/big/intconv_test.go
new file mode 100644
index 0000000..2deb84b
--- /dev/null
+++ b/src/cmd/compile/internal/big/intconv_test.go
@@ -0,0 +1,342 @@
+// 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
+
+import (
+	"bytes"
+	"fmt"
+	"testing"
+)
+
+var stringTests = []struct {
+	in   string
+	out  string
+	base int
+	val  int64
+	ok   bool
+}{
+	{in: "", ok: false},
+	{in: "a", ok: false},
+	{in: "z", ok: false},
+	{in: "+", ok: false},
+	{in: "-", ok: false},
+	{in: "0b", ok: false},
+	{in: "0x", ok: false},
+	{in: "2", base: 2, ok: false},
+	{in: "0b2", base: 0, ok: false},
+	{in: "08", ok: false},
+	{in: "8", base: 8, ok: false},
+	{in: "0xg", base: 0, ok: false},
+	{in: "g", base: 16, ok: false},
+	{"0", "0", 0, 0, true},
+	{"0", "0", 10, 0, true},
+	{"0", "0", 16, 0, true},
+	{"+0", "0", 0, 0, true},
+	{"-0", "0", 0, 0, true},
+	{"10", "10", 0, 10, true},
+	{"10", "10", 10, 10, true},
+	{"10", "10", 16, 16, true},
+	{"-10", "-10", 16, -16, true},
+	{"+10", "10", 16, 16, true},
+	{"0x10", "16", 0, 16, true},
+	{in: "0x10", base: 16, ok: false},
+	{"-0x10", "-16", 0, -16, true},
+	{"+0x10", "16", 0, 16, true},
+	{"00", "0", 0, 0, true},
+	{"0", "0", 8, 0, true},
+	{"07", "7", 0, 7, true},
+	{"7", "7", 8, 7, true},
+	{"023", "19", 0, 19, true},
+	{"23", "23", 8, 19, true},
+	{"cafebabe", "cafebabe", 16, 0xcafebabe, true},
+	{"0b0", "0", 0, 0, true},
+	{"-111", "-111", 2, -7, true},
+	{"-0b111", "-7", 0, -7, true},
+	{"0b1001010111", "599", 0, 0x257, true},
+	{"1001010111", "1001010111", 2, 0x257, true},
+}
+
+func format(base int) string {
+	switch base {
+	case 2:
+		return "%b"
+	case 8:
+		return "%o"
+	case 16:
+		return "%x"
+	}
+	return "%d"
+}
+
+func TestGetString(t *testing.T) {
+	z := new(Int)
+	for i, test := range stringTests {
+		if !test.ok {
+			continue
+		}
+		z.SetInt64(test.val)
+
+		if test.base == 10 {
+			s := z.String()
+			if s != test.out {
+				t.Errorf("#%da got %s; want %s", i, s, test.out)
+			}
+		}
+
+		s := fmt.Sprintf(format(test.base), z)
+		if s != test.out {
+			t.Errorf("#%db got %s; want %s", i, s, test.out)
+		}
+	}
+}
+
+func TestSetString(t *testing.T) {
+	tmp := new(Int)
+	for i, test := range stringTests {
+		// initialize to a non-zero value so that issues with parsing
+		// 0 are detected
+		tmp.SetInt64(1234567890)
+		n1, ok1 := new(Int).SetString(test.in, test.base)
+		n2, ok2 := tmp.SetString(test.in, test.base)
+		expected := NewInt(test.val)
+		if ok1 != test.ok || ok2 != test.ok {
+			t.Errorf("#%d (input '%s') ok incorrect (should be %t)", i, test.in, test.ok)
+			continue
+		}
+		if !ok1 {
+			if n1 != nil {
+				t.Errorf("#%d (input '%s') n1 != nil", i, test.in)
+			}
+			continue
+		}
+		if !ok2 {
+			if n2 != nil {
+				t.Errorf("#%d (input '%s') n2 != nil", i, test.in)
+			}
+			continue
+		}
+
+		if ok1 && !isNormalized(n1) {
+			t.Errorf("#%d (input '%s'): %v is not normalized", i, test.in, *n1)
+		}
+		if ok2 && !isNormalized(n2) {
+			t.Errorf("#%d (input '%s'): %v is not normalized", i, test.in, *n2)
+		}
+
+		if n1.Cmp(expected) != 0 {
+			t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n1, test.val)
+		}
+		if n2.Cmp(expected) != 0 {
+			t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n2, test.val)
+		}
+	}
+}
+
+var formatTests = []struct {
+	input  string
+	format string
+	output string
+}{
+	{"<nil>", "%x", "<nil>"},
+	{"<nil>", "%#x", "<nil>"},
+	{"<nil>", "%#y", "%!y(big.Int=<nil>)"},
+
+	{"10", "%b", "1010"},
+	{"10", "%o", "12"},
+	{"10", "%d", "10"},
+	{"10", "%v", "10"},
+	{"10", "%x", "a"},
+	{"10", "%X", "A"},
+	{"-10", "%X", "-A"},
+	{"10", "%y", "%!y(big.Int=10)"},
+	{"-10", "%y", "%!y(big.Int=-10)"},
+
+	{"10", "%#b", "1010"},
+	{"10", "%#o", "012"},
+	{"10", "%#d", "10"},
+	{"10", "%#v", "10"},
+	{"10", "%#x", "0xa"},
+	{"10", "%#X", "0XA"},
+	{"-10", "%#X", "-0XA"},
+	{"10", "%#y", "%!y(big.Int=10)"},
+	{"-10", "%#y", "%!y(big.Int=-10)"},
+
+	{"1234", "%d", "1234"},
+	{"1234", "%3d", "1234"},
+	{"1234", "%4d", "1234"},
+	{"-1234", "%d", "-1234"},
+	{"1234", "% 5d", " 1234"},
+	{"1234", "%+5d", "+1234"},
+	{"1234", "%-5d", "1234 "},
+	{"1234", "%x", "4d2"},
+	{"1234", "%X", "4D2"},
+	{"-1234", "%3x", "-4d2"},
+	{"-1234", "%4x", "-4d2"},
+	{"-1234", "%5x", " -4d2"},
+	{"-1234", "%-5x", "-4d2 "},
+	{"1234", "%03d", "1234"},
+	{"1234", "%04d", "1234"},
+	{"1234", "%05d", "01234"},
+	{"1234", "%06d", "001234"},
+	{"-1234", "%06d", "-01234"},
+	{"1234", "%+06d", "+01234"},
+	{"1234", "% 06d", " 01234"},
+	{"1234", "%-6d", "1234  "},
+	{"1234", "%-06d", "1234  "},
+	{"-1234", "%-06d", "-1234 "},
+
+	{"1234", "%.3d", "1234"},
+	{"1234", "%.4d", "1234"},
+	{"1234", "%.5d", "01234"},
+	{"1234", "%.6d", "001234"},
+	{"-1234", "%.3d", "-1234"},
+	{"-1234", "%.4d", "-1234"},
+	{"-1234", "%.5d", "-01234"},
+	{"-1234", "%.6d", "-001234"},
+
+	{"1234", "%8.3d", "    1234"},
+	{"1234", "%8.4d", "    1234"},
+	{"1234", "%8.5d", "   01234"},
+	{"1234", "%8.6d", "  001234"},
+	{"-1234", "%8.3d", "   -1234"},
+	{"-1234", "%8.4d", "   -1234"},
+	{"-1234", "%8.5d", "  -01234"},
+	{"-1234", "%8.6d", " -001234"},
+
+	{"1234", "%+8.3d", "   +1234"},
+	{"1234", "%+8.4d", "   +1234"},
+	{"1234", "%+8.5d", "  +01234"},
+	{"1234", "%+8.6d", " +001234"},
+	{"-1234", "%+8.3d", "   -1234"},
+	{"-1234", "%+8.4d", "   -1234"},
+	{"-1234", "%+8.5d", "  -01234"},
+	{"-1234", "%+8.6d", " -001234"},
+
+	{"1234", "% 8.3d", "    1234"},
+	{"1234", "% 8.4d", "    1234"},
+	{"1234", "% 8.5d", "   01234"},
+	{"1234", "% 8.6d", "  001234"},
+	{"-1234", "% 8.3d", "   -1234"},
+	{"-1234", "% 8.4d", "   -1234"},
+	{"-1234", "% 8.5d", "  -01234"},
+	{"-1234", "% 8.6d", " -001234"},
+
+	{"1234", "%.3x", "4d2"},
+	{"1234", "%.4x", "04d2"},
+	{"1234", "%.5x", "004d2"},
+	{"1234", "%.6x", "0004d2"},
+	{"-1234", "%.3x", "-4d2"},
+	{"-1234", "%.4x", "-04d2"},
+	{"-1234", "%.5x", "-004d2"},
+	{"-1234", "%.6x", "-0004d2"},
+
+	{"1234", "%8.3x", "     4d2"},
+	{"1234", "%8.4x", "    04d2"},
+	{"1234", "%8.5x", "   004d2"},
+	{"1234", "%8.6x", "  0004d2"},
+	{"-1234", "%8.3x", "    -4d2"},
+	{"-1234", "%8.4x", "   -04d2"},
+	{"-1234", "%8.5x", "  -004d2"},
+	{"-1234", "%8.6x", " -0004d2"},
+
+	{"1234", "%+8.3x", "    +4d2"},
+	{"1234", "%+8.4x", "   +04d2"},
+	{"1234", "%+8.5x", "  +004d2"},
+	{"1234", "%+8.6x", " +0004d2"},
+	{"-1234", "%+8.3x", "    -4d2"},
+	{"-1234", "%+8.4x", "   -04d2"},
+	{"-1234", "%+8.5x", "  -004d2"},
+	{"-1234", "%+8.6x", " -0004d2"},
+
+	{"1234", "% 8.3x", "     4d2"},
+	{"1234", "% 8.4x", "    04d2"},
+	{"1234", "% 8.5x", "   004d2"},
+	{"1234", "% 8.6x", "  0004d2"},
+	{"1234", "% 8.7x", " 00004d2"},
+	{"1234", "% 8.8x", " 000004d2"},
+	{"-1234", "% 8.3x", "    -4d2"},
+	{"-1234", "% 8.4x", "   -04d2"},
+	{"-1234", "% 8.5x", "  -004d2"},
+	{"-1234", "% 8.6x", " -0004d2"},
+	{"-1234", "% 8.7x", "-00004d2"},
+	{"-1234", "% 8.8x", "-000004d2"},
+
+	{"1234", "%-8.3d", "1234    "},
+	{"1234", "%-8.4d", "1234    "},
+	{"1234", "%-8.5d", "01234   "},
+	{"1234", "%-8.6d", "001234  "},
+	{"1234", "%-8.7d", "0001234 "},
+	{"1234", "%-8.8d", "00001234"},
+	{"-1234", "%-8.3d", "-1234   "},
+	{"-1234", "%-8.4d", "-1234   "},
+	{"-1234", "%-8.5d", "-01234  "},
+	{"-1234", "%-8.6d", "-001234 "},
+	{"-1234", "%-8.7d", "-0001234"},
+	{"-1234", "%-8.8d", "-00001234"},
+
+	{"16777215", "%b", "111111111111111111111111"}, // 2**24 - 1
+
+	{"0", "%.d", ""},
+	{"0", "%.0d", ""},
+	{"0", "%3.d", ""},
+}
+
+func TestFormat(t *testing.T) {
+	for i, test := range formatTests {
+		var x *Int
+		if test.input != "<nil>" {
+			var ok bool
+			x, ok = new(Int).SetString(test.input, 0)
+			if !ok {
+				t.Errorf("#%d failed reading input %s", i, test.input)
+			}
+		}
+		output := fmt.Sprintf(test.format, x)
+		if output != test.output {
+			t.Errorf("#%d got %q; want %q, {%q, %q, %q}", i, output, test.output, test.input, test.format, test.output)
+		}
+	}
+}
+
+var scanTests = []struct {
+	input     string
+	format    string
+	output    string
+	remaining int
+}{
+	{"1010", "%b", "10", 0},
+	{"0b1010", "%v", "10", 0},
+	{"12", "%o", "10", 0},
+	{"012", "%v", "10", 0},
+	{"10", "%d", "10", 0},
+	{"10", "%v", "10", 0},
+	{"a", "%x", "10", 0},
+	{"0xa", "%v", "10", 0},
+	{"A", "%X", "10", 0},
+	{"-A", "%X", "-10", 0},
+	{"+0b1011001", "%v", "89", 0},
+	{"0xA", "%v", "10", 0},
+	{"0 ", "%v", "0", 1},
+	{"2+3", "%v", "2", 2},
+	{"0XABC 12", "%v", "2748", 3},
+}
+
+func TestScan(t *testing.T) {
+	var buf bytes.Buffer
+	for i, test := range scanTests {
+		x := new(Int)
+		buf.Reset()
+		buf.WriteString(test.input)
+		if _, err := fmt.Fscanf(&buf, test.format, x); err != nil {
+			t.Errorf("#%d error: %s", i, err)
+		}
+		if x.String() != test.output {
+			t.Errorf("#%d got %s; want %s", i, x.String(), test.output)
+		}
+		if buf.Len() != test.remaining {
+			t.Errorf("#%d got %d bytes remaining; want %d", i, buf.Len(), test.remaining)
+		}
+	}
+}
diff --git a/src/cmd/compile/internal/big/nat.go b/src/cmd/compile/internal/big/nat.go
new file mode 100644
index 0000000..6545bc1
--- /dev/null
+++ b/src/cmd/compile/internal/big/nat.go
@@ -0,0 +1,1274 @@
+// 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 big implements multi-precision arithmetic (big numbers).
+// The following numeric types are supported:
+//
+//   Int    signed integers
+//   Rat    rational numbers
+//   Float  floating-point numbers
+//
+// Methods are typically of the form:
+//
+//   func (z *T) Unary(x *T) *T        // z = op x
+//   func (z *T) Binary(x, y *T) *T    // z = x op y
+//   func (x *T) M() T1                // v = x.M()
+//
+// with T one of Int, Rat, or Float. For unary and binary operations, the
+// result is the receiver (usually named z in that case); if it is one of
+// the operands x or y it may be overwritten (and its memory reused).
+// To enable chaining of operations, the result is also returned. Methods
+// returning a result other than *Int, *Rat, or *Float take an operand as
+// the receiver (usually named x in that case).
+//
+package big
+
+// This file contains operations on unsigned multi-precision integers.
+// These are the building blocks for the operations on signed integers
+// and rationals.
+
+import "math/rand"
+
+// An unsigned integer x of the form
+//
+//   x = x[n-1]*_B^(n-1) + x[n-2]*_B^(n-2) + ... + x[1]*_B + x[0]
+//
+// with 0 <= x[i] < _B and 0 <= i < n is stored in a slice of length n,
+// with the digits x[i] as the slice elements.
+//
+// A number is normalized if the slice contains no leading 0 digits.
+// During arithmetic operations, denormalized values may occur but are
+// always normalized before returning the final result. The normalized
+// representation of 0 is the empty or nil slice (length = 0).
+//
+type nat []Word
+
+var (
+	natOne = nat{1}
+	natTwo = nat{2}
+	natTen = nat{10}
+)
+
+func (z nat) clear() {
+	for i := range z {
+		z[i] = 0
+	}
+}
+
+func (z nat) norm() nat {
+	i := len(z)
+	for i > 0 && z[i-1] == 0 {
+		i--
+	}
+	return z[0:i]
+}
+
+func (z nat) make(n int) nat {
+	if n <= cap(z) {
+		return z[:n] // reuse z
+	}
+	// Choosing a good value for e has significant performance impact
+	// because it increases the chance that a value can be reused.
+	const e = 4 // extra capacity
+	return make(nat, n, n+e)
+}
+
+func (z nat) setWord(x Word) nat {
+	if x == 0 {
+		return z[:0]
+	}
+	z = z.make(1)
+	z[0] = x
+	return z
+}
+
+func (z nat) setUint64(x uint64) nat {
+	// single-digit values
+	if w := Word(x); uint64(w) == x {
+		return z.setWord(w)
+	}
+
+	// compute number of words n required to represent x
+	n := 0
+	for t := x; t > 0; t >>= _W {
+		n++
+	}
+
+	// split x into n words
+	z = z.make(n)
+	for i := range z {
+		z[i] = Word(x & _M)
+		x >>= _W
+	}
+
+	return z
+}
+
+func (z nat) set(x nat) nat {
+	z = z.make(len(x))
+	copy(z, x)
+	return z
+}
+
+func (z nat) add(x, y nat) nat {
+	m := len(x)
+	n := len(y)
+
+	switch {
+	case m < n:
+		return z.add(y, x)
+	case m == 0:
+		// n == 0 because m >= n; result is 0
+		return z[:0]
+	case n == 0:
+		// result is x
+		return z.set(x)
+	}
+	// m > 0
+
+	z = z.make(m + 1)
+	c := addVV(z[0:n], x, y)
+	if m > n {
+		c = addVW(z[n:m], x[n:], c)
+	}
+	z[m] = c
+
+	return z.norm()
+}
+
+func (z nat) sub(x, y nat) nat {
+	m := len(x)
+	n := len(y)
+
+	switch {
+	case m < n:
+		panic("underflow")
+	case m == 0:
+		// n == 0 because m >= n; result is 0
+		return z[:0]
+	case n == 0:
+		// result is x
+		return z.set(x)
+	}
+	// m > 0
+
+	z = z.make(m)
+	c := subVV(z[0:n], x, y)
+	if m > n {
+		c = subVW(z[n:], x[n:], c)
+	}
+	if c != 0 {
+		panic("underflow")
+	}
+
+	return z.norm()
+}
+
+func (x nat) cmp(y nat) (r int) {
+	m := len(x)
+	n := len(y)
+	if m != n || m == 0 {
+		switch {
+		case m < n:
+			r = -1
+		case m > n:
+			r = 1
+		}
+		return
+	}
+
+	i := m - 1
+	for i > 0 && x[i] == y[i] {
+		i--
+	}
+
+	switch {
+	case x[i] < y[i]:
+		r = -1
+	case x[i] > y[i]:
+		r = 1
+	}
+	return
+}
+
+func (z nat) mulAddWW(x nat, y, r Word) nat {
+	m := len(x)
+	if m == 0 || y == 0 {
+		return z.setWord(r) // result is r
+	}
+	// m > 0
+
+	z = z.make(m + 1)
+	z[m] = mulAddVWW(z[0:m], x, y, r)
+
+	return z.norm()
+}
+
+// basicMul multiplies x and y and leaves the result in z.
+// The (non-normalized) result is placed in z[0 : len(x) + len(y)].
+func basicMul(z, x, y nat) {
+	z[0 : len(x)+len(y)].clear() // initialize z
+	for i, d := range y {
+		if d != 0 {
+			z[len(x)+i] = addMulVVW(z[i:i+len(x)], x, d)
+		}
+	}
+}
+
+// montgomery computes x*y*2^(-n*_W) mod m,
+// assuming k = -1/m mod 2^_W.
+// z is used for storing the result which is returned;
+// z must not alias x, y or m.
+func (z nat) montgomery(x, y, m nat, k Word, n int) nat {
+	var c1, c2 Word
+	z = z.make(n)
+	z.clear()
+	for i := 0; i < n; i++ {
+		d := y[i]
+		c1 += addMulVVW(z, x, d)
+		t := z[0] * k
+		c2 = addMulVVW(z, m, t)
+
+		copy(z, z[1:])
+		z[n-1] = c1 + c2
+		if z[n-1] < c1 {
+			c1 = 1
+		} else {
+			c1 = 0
+		}
+	}
+	if c1 != 0 {
+		subVV(z, z, m)
+	}
+	return z
+}
+
+// Fast version of z[0:n+n>>1].add(z[0:n+n>>1], x[0:n]) w/o bounds checks.
+// Factored out for readability - do not use outside karatsuba.
+func karatsubaAdd(z, x nat, n int) {
+	if c := addVV(z[0:n], z, x); c != 0 {
+		addVW(z[n:n+n>>1], z[n:], c)
+	}
+}
+
+// Like karatsubaAdd, but does subtract.
+func karatsubaSub(z, x nat, n int) {
+	if c := subVV(z[0:n], z, x); c != 0 {
+		subVW(z[n:n+n>>1], z[n:], c)
+	}
+}
+
+// Operands that are shorter than karatsubaThreshold are multiplied using
+// "grade school" multiplication; for longer operands the Karatsuba algorithm
+// is used.
+var karatsubaThreshold int = 40 // computed by calibrate.go
+
+// karatsuba multiplies x and y and leaves the result in z.
+// Both x and y must have the same length n and n must be a
+// power of 2. The result vector z must have len(z) >= 6*n.
+// The (non-normalized) result is placed in z[0 : 2*n].
+func karatsuba(z, x, y nat) {
+	n := len(y)
+
+	// Switch to basic multiplication if numbers are odd or small.
+	// (n is always even if karatsubaThreshold is even, but be
+	// conservative)
+	if n&1 != 0 || n < karatsubaThreshold || n < 2 {
+		basicMul(z, x, y)
+		return
+	}
+	// n&1 == 0 && n >= karatsubaThreshold && n >= 2
+
+	// Karatsuba multiplication is based on the observation that
+	// for two numbers x and y with:
+	//
+	//   x = x1*b + x0
+	//   y = y1*b + y0
+	//
+	// the product x*y can be obtained with 3 products z2, z1, z0
+	// instead of 4:
+	//
+	//   x*y = x1*y1*b*b + (x1*y0 + x0*y1)*b + x0*y0
+	//       =    z2*b*b +              z1*b +    z0
+	//
+	// with:
+	//
+	//   xd = x1 - x0
+	//   yd = y0 - y1
+	//
+	//   z1 =      xd*yd                    + z2 + z0
+	//      = (x1-x0)*(y0 - y1)             + z2 + z0
+	//      = x1*y0 - x1*y1 - x0*y0 + x0*y1 + z2 + z0
+	//      = x1*y0 -    z2 -    z0 + x0*y1 + z2 + z0
+	//      = x1*y0                 + x0*y1
+
+	// split x, y into "digits"
+	n2 := n >> 1              // n2 >= 1
+	x1, x0 := x[n2:], x[0:n2] // x = x1*b + y0
+	y1, y0 := y[n2:], y[0:n2] // y = y1*b + y0
+
+	// z is used for the result and temporary storage:
+	//
+	//   6*n     5*n     4*n     3*n     2*n     1*n     0*n
+	// z = [z2 copy|z0 copy| xd*yd | yd:xd | x1*y1 | x0*y0 ]
+	//
+	// For each recursive call of karatsuba, an unused slice of
+	// z is passed in that has (at least) half the length of the
+	// caller's z.
+
+	// compute z0 and z2 with the result "in place" in z
+	karatsuba(z, x0, y0)     // z0 = x0*y0
+	karatsuba(z[n:], x1, y1) // z2 = x1*y1
+
+	// compute xd (or the negative value if underflow occurs)
+	s := 1 // sign of product xd*yd
+	xd := z[2*n : 2*n+n2]
+	if subVV(xd, x1, x0) != 0 { // x1-x0
+		s = -s
+		subVV(xd, x0, x1) // x0-x1
+	}
+
+	// compute yd (or the negative value if underflow occurs)
+	yd := z[2*n+n2 : 3*n]
+	if subVV(yd, y0, y1) != 0 { // y0-y1
+		s = -s
+		subVV(yd, y1, y0) // y1-y0
+	}
+
+	// p = (x1-x0)*(y0-y1) == x1*y0 - x1*y1 - x0*y0 + x0*y1 for s > 0
+	// p = (x0-x1)*(y0-y1) == x0*y0 - x0*y1 - x1*y0 + x1*y1 for s < 0
+	p := z[n*3:]
+	karatsuba(p, xd, yd)
+
+	// save original z2:z0
+	// (ok to use upper half of z since we're done recursing)
+	r := z[n*4:]
+	copy(r, z[:n*2])
+
+	// add up all partial products
+	//
+	//   2*n     n     0
+	// z = [ z2  | z0  ]
+	//   +    [ z0  ]
+	//   +    [ z2  ]
+	//   +    [  p  ]
+	//
+	karatsubaAdd(z[n2:], r, n)
+	karatsubaAdd(z[n2:], r[n:], n)
+	if s > 0 {
+		karatsubaAdd(z[n2:], p, n)
+	} else {
+		karatsubaSub(z[n2:], p, n)
+	}
+}
+
+// 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]
+}
+
+// addAt implements z += x<<(_W*i); z must be long enough.
+// (we don't use nat.add because we need z to stay the same
+// slice, and we don't need to normalize z after each addition)
+func addAt(z, x nat, i int) {
+	if n := len(x); n > 0 {
+		if c := addVV(z[i:i+n], z[i:], x); c != 0 {
+			j := i + n
+			if j < len(z) {
+				addVW(z[j:], z[j:], c)
+			}
+		}
+	}
+}
+
+func max(x, y int) int {
+	if x > y {
+		return x
+	}
+	return y
+}
+
+// karatsubaLen computes an approximation to the maximum k <= n such that
+// k = p<<i for a number p <= karatsubaThreshold and an i >= 0. Thus, the
+// result is the largest number that can be divided repeatedly by 2 before
+// becoming about the value of karatsubaThreshold.
+func karatsubaLen(n int) int {
+	i := uint(0)
+	for n > karatsubaThreshold {
+		n >>= 1
+		i++
+	}
+	return n << i
+}
+
+func (z nat) mul(x, y nat) nat {
+	m := len(x)
+	n := len(y)
+
+	switch {
+	case m < n:
+		return z.mul(y, x)
+	case m == 0 || n == 0:
+		return z[:0]
+	case n == 1:
+		return z.mulAddWW(x, y[0], 0)
+	}
+	// m >= n > 1
+
+	// determine if z can be reused
+	if alias(z, x) || alias(z, y) {
+		z = nil // z is an alias for x or y - cannot reuse
+	}
+
+	// use basic multiplication if the numbers are small
+	if n < karatsubaThreshold {
+		z = z.make(m + n)
+		basicMul(z, x, y)
+		return z.norm()
+	}
+	// m >= n && n >= karatsubaThreshold && n >= 2
+
+	// determine Karatsuba length k such that
+	//
+	//   x = xh*b + x0  (0 <= x0 < b)
+	//   y = yh*b + y0  (0 <= y0 < b)
+	//   b = 1<<(_W*k)  ("base" of digits xi, yi)
+	//
+	k := karatsubaLen(n)
+	// k <= n
+
+	// multiply x0 and y0 via Karatsuba
+	x0 := x[0:k]              // x0 is not normalized
+	y0 := y[0:k]              // y0 is not normalized
+	z = z.make(max(6*k, m+n)) // enough space for karatsuba of x0*y0 and full result of x*y
+	karatsuba(z, x0, y0)
+	z = z[0 : m+n]  // z has final length but may be incomplete
+	z[2*k:].clear() // upper portion of z is garbage (and 2*k <= m+n since k <= n <= m)
+
+	// If xh != 0 or yh != 0, add the missing terms to z. For
+	//
+	//   xh = xi*b^i + ... + x2*b^2 + x1*b (0 <= xi < b)
+	//   yh =                         y1*b (0 <= y1 < b)
+	//
+	// the missing terms are
+	//
+	//   x0*y1*b and xi*y0*b^i, xi*y1*b^(i+1) for i > 0
+	//
+	// since all the yi for i > 1 are 0 by choice of k: If any of them
+	// were > 0, then yh >= b^2 and thus y >= b^2. Then k' = k*2 would
+	// be a larger valid threshold contradicting the assumption about k.
+	//
+	if k < n || m != n {
+		var t nat
+
+		// add x0*y1*b
+		x0 := x0.norm()
+		y1 := y[k:]       // y1 is normalized because y is
+		t = t.mul(x0, y1) // update t so we don't lose t's underlying array
+		addAt(z, t, k)
+
+		// add xi*y0<<i, xi*y1*b<<(i+k)
+		y0 := y0.norm()
+		for i := k; i < len(x); i += k {
+			xi := x[i:]
+			if len(xi) > k {
+				xi = xi[:k]
+			}
+			xi = xi.norm()
+			t = t.mul(xi, y0)
+			addAt(z, t, i)
+			t = t.mul(xi, y1)
+			addAt(z, t, i+k)
+		}
+	}
+
+	return z.norm()
+}
+
+// mulRange computes the product of all the unsigned integers in the
+// range [a, b] inclusively. If a > b (empty range), the result is 1.
+func (z nat) mulRange(a, b uint64) nat {
+	switch {
+	case a == 0:
+		// cut long ranges short (optimization)
+		return z.setUint64(0)
+	case a > b:
+		return z.setUint64(1)
+	case a == b:
+		return z.setUint64(a)
+	case a+1 == b:
+		return z.mul(nat(nil).setUint64(a), nat(nil).setUint64(b))
+	}
+	m := (a + b) / 2
+	return z.mul(nat(nil).mulRange(a, m), nat(nil).mulRange(m+1, b))
+}
+
+// q = (x-r)/y, with 0 <= r < y
+func (z nat) divW(x nat, y Word) (q nat, r Word) {
+	m := len(x)
+	switch {
+	case y == 0:
+		panic("division by zero")
+	case y == 1:
+		q = z.set(x) // result is x
+		return
+	case m == 0:
+		q = z[:0] // result is 0
+		return
+	}
+	// m > 0
+	z = z.make(m)
+	r = divWVW(z, 0, x, y)
+	q = z.norm()
+	return
+}
+
+func (z nat) div(z2, u, v nat) (q, r nat) {
+	if len(v) == 0 {
+		panic("division by zero")
+	}
+
+	if u.cmp(v) < 0 {
+		q = z[:0]
+		r = z2.set(u)
+		return
+	}
+
+	if len(v) == 1 {
+		var r2 Word
+		q, r2 = z.divW(u, v[0])
+		r = z2.setWord(r2)
+		return
+	}
+
+	q, r = z.divLarge(z2, u, v)
+	return
+}
+
+// q = (uIn-r)/v, with 0 <= r < y
+// Uses z as storage for q, and u as storage for r if possible.
+// See Knuth, Volume 2, section 4.3.1, Algorithm D.
+// Preconditions:
+//    len(v) >= 2
+//    len(uIn) >= len(v)
+func (z nat) divLarge(u, uIn, v nat) (q, r nat) {
+	n := len(v)
+	m := len(uIn) - n
+
+	// determine if z can be reused
+	// TODO(gri) should find a better solution - this if statement
+	//           is very costly (see e.g. time pidigits -s -n 10000)
+	if alias(z, uIn) || alias(z, v) {
+		z = nil // z is an alias for uIn or v - cannot reuse
+	}
+	q = z.make(m + 1)
+
+	qhatv := make(nat, n+1)
+	if alias(u, uIn) || alias(u, v) {
+		u = nil // u is an alias for uIn or v - cannot reuse
+	}
+	u = u.make(len(uIn) + 1)
+	u.clear() // TODO(gri) no need to clear if we allocated a new u
+
+	// D1.
+	shift := nlz(v[n-1])
+	if shift > 0 {
+		// do not modify v, it may be used by another goroutine simultaneously
+		v1 := make(nat, n)
+		shlVU(v1, v, shift)
+		v = v1
+	}
+	u[len(uIn)] = shlVU(u[0:len(uIn)], uIn, shift)
+
+	// D2.
+	for j := m; j >= 0; j-- {
+		// D3.
+		qhat := Word(_M)
+		if u[j+n] != v[n-1] {
+			var rhat Word
+			qhat, rhat = divWW(u[j+n], u[j+n-1], v[n-1])
+
+			// x1 | x2 = q̂v_{n-2}
+			x1, x2 := mulWW(qhat, v[n-2])
+			// test if q̂v_{n-2} > br̂ + u_{j+n-2}
+			for greaterThan(x1, x2, rhat, u[j+n-2]) {
+				qhat--
+				prevRhat := rhat
+				rhat += v[n-1]
+				// v[n-1] >= 0, so this tests for overflow.
+				if rhat < prevRhat {
+					break
+				}
+				x1, x2 = mulWW(qhat, v[n-2])
+			}
+		}
+
+		// D4.
+		qhatv[n] = mulAddVWW(qhatv[0:n], v, qhat, 0)
+
+		c := subVV(u[j:j+len(qhatv)], u[j:], qhatv)
+		if c != 0 {
+			c := addVV(u[j:j+n], u[j:], v)
+			u[j+n] += c
+			qhat--
+		}
+
+		q[j] = qhat
+	}
+
+	q = q.norm()
+	shrVU(u, u, shift)
+	r = u.norm()
+
+	return q, r
+}
+
+// Length of x in bits. x must be normalized.
+func (x nat) bitLen() int {
+	if i := len(x) - 1; i >= 0 {
+		return i*_W + bitLen(x[i])
+	}
+	return 0
+}
+
+const deBruijn32 = 0x077CB531
+
+var deBruijn32Lookup = []byte{
+	0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
+	31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9,
+}
+
+const deBruijn64 = 0x03f79d71b4ca8b09
+
+var deBruijn64Lookup = []byte{
+	0, 1, 56, 2, 57, 49, 28, 3, 61, 58, 42, 50, 38, 29, 17, 4,
+	62, 47, 59, 36, 45, 43, 51, 22, 53, 39, 33, 30, 24, 18, 12, 5,
+	63, 55, 48, 27, 60, 41, 37, 16, 46, 35, 44, 21, 52, 32, 23, 11,
+	54, 26, 40, 15, 34, 20, 31, 10, 25, 14, 19, 9, 13, 8, 7, 6,
+}
+
+// trailingZeroBits returns the number of consecutive least significant zero
+// bits of x.
+func trailingZeroBits(x Word) uint {
+	// x & -x leaves only the right-most bit set in the word. Let k be the
+	// index of that bit. Since only a single bit is set, the value is two
+	// to the power of k. Multiplying by a power of two is equivalent to
+	// left shifting, in this case by k bits.  The de Bruijn constant is
+	// such that all six bit, consecutive substrings are distinct.
+	// Therefore, if we have a left shifted version of this constant we can
+	// find by how many bits it was shifted by looking at which six bit
+	// substring ended up at the top of the word.
+	// (Knuth, volume 4, section 7.3.1)
+	switch _W {
+	case 32:
+		return uint(deBruijn32Lookup[((x&-x)*deBruijn32)>>27])
+	case 64:
+		return uint(deBruijn64Lookup[((x&-x)*(deBruijn64&_M))>>58])
+	default:
+		panic("unknown word size")
+	}
+}
+
+// trailingZeroBits returns the number of consecutive least significant zero
+// bits of x.
+func (x nat) trailingZeroBits() uint {
+	if len(x) == 0 {
+		return 0
+	}
+	var i uint
+	for x[i] == 0 {
+		i++
+	}
+	// x[i] != 0
+	return i*_W + trailingZeroBits(x[i])
+}
+
+// z = x << s
+func (z nat) shl(x nat, s uint) nat {
+	m := len(x)
+	if m == 0 {
+		return z[:0]
+	}
+	// m > 0
+
+	n := m + int(s/_W)
+	z = z.make(n + 1)
+	z[n] = shlVU(z[n-m:n], x, s%_W)
+	z[0 : n-m].clear()
+
+	return z.norm()
+}
+
+// z = x >> s
+func (z nat) shr(x nat, s uint) nat {
+	m := len(x)
+	n := m - int(s/_W)
+	if n <= 0 {
+		return z[:0]
+	}
+	// n > 0
+
+	z = z.make(n)
+	shrVU(z, x[m-n:], s%_W)
+
+	return z.norm()
+}
+
+func (z nat) setBit(x nat, i uint, b uint) nat {
+	j := int(i / _W)
+	m := Word(1) << (i % _W)
+	n := len(x)
+	switch b {
+	case 0:
+		z = z.make(n)
+		copy(z, x)
+		if j >= n {
+			// no need to grow
+			return z
+		}
+		z[j] &^= m
+		return z.norm()
+	case 1:
+		if j >= n {
+			z = z.make(j + 1)
+			z[n:].clear()
+		} else {
+			z = z.make(n)
+		}
+		copy(z, x)
+		z[j] |= m
+		// no need to normalize
+		return z
+	}
+	panic("set bit is not 0 or 1")
+}
+
+// bit returns the value of the i'th bit, with lsb == bit 0.
+func (x nat) bit(i uint) uint {
+	j := i / _W
+	if j >= uint(len(x)) {
+		return 0
+	}
+	// 0 <= j < len(x)
+	return uint(x[j] >> (i % _W) & 1)
+}
+
+// sticky returns 1 if there's a 1 bit within the
+// i least significant bits, otherwise it returns 0.
+func (x nat) sticky(i uint) uint {
+	j := i / _W
+	if j >= uint(len(x)) {
+		if len(x) == 0 {
+			return 0
+		}
+		return 1
+	}
+	// 0 <= j < len(x)
+	for _, x := range x[:j] {
+		if x != 0 {
+			return 1
+		}
+	}
+	if x[j]<<(_W-i%_W) != 0 {
+		return 1
+	}
+	return 0
+}
+
+func (z nat) and(x, y nat) nat {
+	m := len(x)
+	n := len(y)
+	if m > n {
+		m = n
+	}
+	// m <= n
+
+	z = z.make(m)
+	for i := 0; i < m; i++ {
+		z[i] = x[i] & y[i]
+	}
+
+	return z.norm()
+}
+
+func (z nat) andNot(x, y nat) nat {
+	m := len(x)
+	n := len(y)
+	if n > m {
+		n = m
+	}
+	// m >= n
+
+	z = z.make(m)
+	for i := 0; i < n; i++ {
+		z[i] = x[i] &^ y[i]
+	}
+	copy(z[n:m], x[n:m])
+
+	return z.norm()
+}
+
+func (z nat) or(x, y nat) nat {
+	m := len(x)
+	n := len(y)
+	s := x
+	if m < n {
+		n, m = m, n
+		s = y
+	}
+	// m >= n
+
+	z = z.make(m)
+	for i := 0; i < n; i++ {
+		z[i] = x[i] | y[i]
+	}
+	copy(z[n:m], s[n:m])
+
+	return z.norm()
+}
+
+func (z nat) xor(x, y nat) nat {
+	m := len(x)
+	n := len(y)
+	s := x
+	if m < n {
+		n, m = m, n
+		s = y
+	}
+	// m >= n
+
+	z = z.make(m)
+	for i := 0; i < n; i++ {
+		z[i] = x[i] ^ y[i]
+	}
+	copy(z[n:m], s[n:m])
+
+	return z.norm()
+}
+
+// greaterThan reports whether (x1<<_W + x2) > (y1<<_W + y2)
+func greaterThan(x1, x2, y1, y2 Word) bool {
+	return x1 > y1 || x1 == y1 && x2 > y2
+}
+
+// modW returns x % d.
+func (x nat) modW(d Word) (r Word) {
+	// TODO(agl): we don't actually need to store the q value.
+	var q nat
+	q = q.make(len(x))
+	return divWVW(q, 0, x, d)
+}
+
+// random creates a random integer in [0..limit), using the space in z if
+// possible. n is the bit length of limit.
+func (z nat) random(rand *rand.Rand, limit nat, n int) nat {
+	if alias(z, limit) {
+		z = nil // z is an alias for limit - cannot reuse
+	}
+	z = z.make(len(limit))
+
+	bitLengthOfMSW := uint(n % _W)
+	if bitLengthOfMSW == 0 {
+		bitLengthOfMSW = _W
+	}
+	mask := Word((1 << bitLengthOfMSW) - 1)
+
+	for {
+		switch _W {
+		case 32:
+			for i := range z {
+				z[i] = Word(rand.Uint32())
+			}
+		case 64:
+			for i := range z {
+				z[i] = Word(rand.Uint32()) | Word(rand.Uint32())<<32
+			}
+		default:
+			panic("unknown word size")
+		}
+		z[len(limit)-1] &= mask
+		if z.cmp(limit) < 0 {
+			break
+		}
+	}
+
+	return z.norm()
+}
+
+// If m != 0 (i.e., len(m) != 0), expNN sets z to x**y mod m;
+// otherwise it sets z to x**y. The result is the value of z.
+func (z nat) expNN(x, y, m nat) nat {
+	if alias(z, x) || alias(z, y) {
+		// We cannot allow in-place modification of x or y.
+		z = nil
+	}
+
+	// x**y mod 1 == 0
+	if len(m) == 1 && m[0] == 1 {
+		return z.setWord(0)
+	}
+	// m == 0 || m > 1
+
+	// x**0 == 1
+	if len(y) == 0 {
+		return z.setWord(1)
+	}
+	// y > 0
+
+	// x**1 mod m == x mod m
+	if len(y) == 1 && y[0] == 1 && len(m) != 0 {
+		_, z = z.div(z, x, m)
+		return z
+	}
+	// y > 1
+
+	if len(m) != 0 {
+		// We likely end up being as long as the modulus.
+		z = z.make(len(m))
+	}
+	z = z.set(x)
+
+	// If the base is non-trivial and the exponent is large, we use
+	// 4-bit, windowed exponentiation. This involves precomputing 14 values
+	// (x^2...x^15) but then reduces the number of multiply-reduces by a
+	// third. Even for a 32-bit exponent, this reduces the number of
+	// operations. Uses Montgomery method for odd moduli.
+	if len(x) > 1 && len(y) > 1 && len(m) > 0 {
+		if m[0]&1 == 1 {
+			return z.expNNMontgomery(x, y, m)
+		}
+		return z.expNNWindowed(x, y, m)
+	}
+
+	v := y[len(y)-1] // v > 0 because y is normalized and y > 0
+	shift := nlz(v) + 1
+	v <<= shift
+	var q nat
+
+	const mask = 1 << (_W - 1)
+
+	// We walk through the bits of the exponent one by one. Each time we
+	// see a bit, we square, thus doubling the power. If the bit is a one,
+	// we also multiply by x, thus adding one to the power.
+
+	w := _W - int(shift)
+	// zz and r are used to avoid allocating in mul and div as
+	// otherwise the arguments would alias.
+	var zz, r nat
+	for j := 0; j < w; j++ {
+		zz = zz.mul(z, z)
+		zz, z = z, zz
+
+		if v&mask != 0 {
+			zz = zz.mul(z, x)
+			zz, z = z, zz
+		}
+
+		if len(m) != 0 {
+			zz, r = zz.div(r, z, m)
+			zz, r, q, z = q, z, zz, r
+		}
+
+		v <<= 1
+	}
+
+	for i := len(y) - 2; i >= 0; i-- {
+		v = y[i]
+
+		for j := 0; j < _W; j++ {
+			zz = zz.mul(z, z)
+			zz, z = z, zz
+
+			if v&mask != 0 {
+				zz = zz.mul(z, x)
+				zz, z = z, zz
+			}
+
+			if len(m) != 0 {
+				zz, r = zz.div(r, z, m)
+				zz, r, q, z = q, z, zz, r
+			}
+
+			v <<= 1
+		}
+	}
+
+	return z.norm()
+}
+
+// expNNWindowed calculates x**y mod m using a fixed, 4-bit window.
+func (z nat) expNNWindowed(x, y, m nat) nat {
+	// zz and r are used to avoid allocating in mul and div as otherwise
+	// the arguments would alias.
+	var zz, r nat
+
+	const n = 4
+	// powers[i] contains x^i.
+	var powers [1 << n]nat
+	powers[0] = natOne
+	powers[1] = x
+	for i := 2; i < 1<<n; i += 2 {
+		p2, p, p1 := &powers[i/2], &powers[i], &powers[i+1]
+		*p = p.mul(*p2, *p2)
+		zz, r = zz.div(r, *p, m)
+		*p, r = r, *p
+		*p1 = p1.mul(*p, x)
+		zz, r = zz.div(r, *p1, m)
+		*p1, r = r, *p1
+	}
+
+	z = z.setWord(1)
+
+	for i := len(y) - 1; i >= 0; i-- {
+		yi := y[i]
+		for j := 0; j < _W; j += n {
+			if i != len(y)-1 || j != 0 {
+				// Unrolled loop for significant performance
+				// gain.  Use go test -bench=".*" in crypto/rsa
+				// to check performance before making changes.
+				zz = zz.mul(z, z)
+				zz, z = z, zz
+				zz, r = zz.div(r, z, m)
+				z, r = r, z
+
+				zz = zz.mul(z, z)
+				zz, z = z, zz
+				zz, r = zz.div(r, z, m)
+				z, r = r, z
+
+				zz = zz.mul(z, z)
+				zz, z = z, zz
+				zz, r = zz.div(r, z, m)
+				z, r = r, z
+
+				zz = zz.mul(z, z)
+				zz, z = z, zz
+				zz, r = zz.div(r, z, m)
+				z, r = r, z
+			}
+
+			zz = zz.mul(z, powers[yi>>(_W-n)])
+			zz, z = z, zz
+			zz, r = zz.div(r, z, m)
+			z, r = r, z
+
+			yi <<= n
+		}
+	}
+
+	return z.norm()
+}
+
+// expNNMontgomery calculates x**y mod m using a fixed, 4-bit window.
+// Uses Montgomery representation.
+func (z nat) expNNMontgomery(x, y, m nat) nat {
+	var zz, one, rr, RR nat
+
+	numWords := len(m)
+
+	// We want the lengths of x and m to be equal.
+	if len(x) > numWords {
+		_, rr = rr.div(rr, x, m)
+	} else if len(x) < numWords {
+		rr = rr.make(numWords)
+		rr.clear()
+		for i := range x {
+			rr[i] = x[i]
+		}
+	} else {
+		rr = x
+	}
+	x = rr
+
+	// Ideally the precomputations would be performed outside, and reused
+	// k0 = -mˆ-1 mod 2ˆ_W. Algorithm from: Dumas, J.G. "On Newton–Raphson
+	// Iteration for Multiplicative Inverses Modulo Prime Powers".
+	k0 := 2 - m[0]
+	t := m[0] - 1
+	for i := 1; i < _W; i <<= 1 {
+		t *= t
+		k0 *= (t + 1)
+	}
+	k0 = -k0
+
+	// RR = 2ˆ(2*_W*len(m)) mod m
+	RR = RR.setWord(1)
+	zz = zz.shl(RR, uint(2*numWords*_W))
+	_, RR = RR.div(RR, zz, m)
+	if len(RR) < numWords {
+		zz = zz.make(numWords)
+		copy(zz, RR)
+		RR = zz
+	}
+	// one = 1, with equal length to that of m
+	one = one.make(numWords)
+	one.clear()
+	one[0] = 1
+
+	const n = 4
+	// powers[i] contains x^i
+	var powers [1 << n]nat
+	powers[0] = powers[0].montgomery(one, RR, m, k0, numWords)
+	powers[1] = powers[1].montgomery(x, RR, m, k0, numWords)
+	for i := 2; i < 1<<n; i++ {
+		powers[i] = powers[i].montgomery(powers[i-1], powers[1], m, k0, numWords)
+	}
+
+	// initialize z = 1 (Montgomery 1)
+	z = z.make(numWords)
+	copy(z, powers[0])
+
+	zz = zz.make(numWords)
+
+	// same windowed exponent, but with Montgomery multiplications
+	for i := len(y) - 1; i >= 0; i-- {
+		yi := y[i]
+		for j := 0; j < _W; j += n {
+			if i != len(y)-1 || j != 0 {
+				zz = zz.montgomery(z, z, m, k0, numWords)
+				z = z.montgomery(zz, zz, m, k0, numWords)
+				zz = zz.montgomery(z, z, m, k0, numWords)
+				z = z.montgomery(zz, zz, m, k0, numWords)
+			}
+			zz = zz.montgomery(z, powers[yi>>(_W-n)], m, k0, numWords)
+			z, zz = zz, z
+			yi <<= n
+		}
+	}
+	// convert to regular number
+	zz = zz.montgomery(z, one, m, k0, numWords)
+	return zz.norm()
+}
+
+// probablyPrime performs reps Miller-Rabin tests to check whether n is prime.
+// If it returns true, n is prime with probability 1 - 1/4^reps.
+// If it returns false, n is not prime.
+func (n nat) probablyPrime(reps int) bool {
+	if len(n) == 0 {
+		return false
+	}
+
+	if len(n) == 1 {
+		if n[0] < 2 {
+			return false
+		}
+
+		if n[0]%2 == 0 {
+			return n[0] == 2
+		}
+
+		// We have to exclude these cases because we reject all
+		// multiples of these numbers below.
+		switch n[0] {
+		case 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53:
+			return true
+		}
+	}
+
+	if n[0]&1 == 0 {
+		return false // n is even
+	}
+
+	const primesProduct32 = 0xC0CFD797         // Π {p ∈ primes, 2 < p <= 29}
+	const primesProduct64 = 0xE221F97C30E94E1D // Π {p ∈ primes, 2 < p <= 53}
+
+	var r Word
+	switch _W {
+	case 32:
+		r = n.modW(primesProduct32)
+	case 64:
+		r = n.modW(primesProduct64 & _M)
+	default:
+		panic("Unknown word size")
+	}
+
+	if r%3 == 0 || r%5 == 0 || r%7 == 0 || r%11 == 0 ||
+		r%13 == 0 || r%17 == 0 || r%19 == 0 || r%23 == 0 || r%29 == 0 {
+		return false
+	}
+
+	if _W == 64 && (r%31 == 0 || r%37 == 0 || r%41 == 0 ||
+		r%43 == 0 || r%47 == 0 || r%53 == 0) {
+		return false
+	}
+
+	nm1 := nat(nil).sub(n, natOne)
+	// determine q, k such that nm1 = q << k
+	k := nm1.trailingZeroBits()
+	q := nat(nil).shr(nm1, k)
+
+	nm3 := nat(nil).sub(nm1, natTwo)
+	rand := rand.New(rand.NewSource(int64(n[0])))
+
+	var x, y, quotient nat
+	nm3Len := nm3.bitLen()
+
+NextRandom:
+	for i := 0; i < reps; i++ {
+		x = x.random(rand, nm3, nm3Len)
+		x = x.add(x, natTwo)
+		y = y.expNN(x, q, n)
+		if y.cmp(natOne) == 0 || y.cmp(nm1) == 0 {
+			continue
+		}
+		for j := uint(1); j < k; j++ {
+			y = y.mul(y, y)
+			quotient, y = quotient.div(y, y, n)
+			if y.cmp(nm1) == 0 {
+				continue NextRandom
+			}
+			if y.cmp(natOne) == 0 {
+				return false
+			}
+		}
+		return false
+	}
+
+	return true
+}
+
+// bytes writes the value of z into buf using big-endian encoding.
+// len(buf) must be >= len(z)*_S. The value of z is encoded in the
+// slice buf[i:]. The number i of unused bytes at the beginning of
+// buf is returned as result.
+func (z nat) bytes(buf []byte) (i int) {
+	i = len(buf)
+	for _, d := range z {
+		for j := 0; j < _S; j++ {
+			i--
+			buf[i] = byte(d)
+			d >>= 8
+		}
+	}
+
+	for i < len(buf) && buf[i] == 0 {
+		i++
+	}
+
+	return
+}
+
+// setBytes interprets buf as the bytes of a big-endian unsigned
+// integer, sets z to that value, and returns z.
+func (z nat) setBytes(buf []byte) nat {
+	z = z.make((len(buf) + _S - 1) / _S)
+
+	k := 0
+	s := uint(0)
+	var d Word
+	for i := len(buf); i > 0; i-- {
+		d |= Word(buf[i-1]) << s
+		if s += 8; s == _S*8 {
+			z[k] = d
+			k++
+			s = 0
+			d = 0
+		}
+	}
+	if k < len(z) {
+		z[k] = d
+	}
+
+	return z.norm()
+}
diff --git a/src/cmd/compile/internal/big/nat_test.go b/src/cmd/compile/internal/big/nat_test.go
new file mode 100644
index 0000000..7ac3cb8
--- /dev/null
+++ b/src/cmd/compile/internal/big/nat_test.go
@@ -0,0 +1,579 @@
+// 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 big
+
+import (
+	"runtime"
+	"strings"
+	"testing"
+)
+
+var cmpTests = []struct {
+	x, y nat
+	r    int
+}{
+	{nil, nil, 0},
+	{nil, nat(nil), 0},
+	{nat(nil), nil, 0},
+	{nat(nil), nat(nil), 0},
+	{nat{0}, nat{0}, 0},
+	{nat{0}, nat{1}, -1},
+	{nat{1}, nat{0}, 1},
+	{nat{1}, nat{1}, 0},
+	{nat{0, _M}, nat{1}, 1},
+	{nat{1}, nat{0, _M}, -1},
+	{nat{1, _M}, nat{0, _M}, 1},
+	{nat{0, _M}, nat{1, _M}, -1},
+	{nat{16, 571956, 8794, 68}, nat{837, 9146, 1, 754489}, -1},
+	{nat{34986, 41, 105, 1957}, nat{56, 7458, 104, 1957}, 1},
+}
+
+func TestCmp(t *testing.T) {
+	for i, a := range cmpTests {
+		r := a.x.cmp(a.y)
+		if r != a.r {
+			t.Errorf("#%d got r = %v; want %v", i, r, a.r)
+		}
+	}
+}
+
+type funNN func(z, x, y nat) nat
+type argNN struct {
+	z, x, y nat
+}
+
+var sumNN = []argNN{
+	{},
+	{nat{1}, nil, nat{1}},
+	{nat{1111111110}, nat{123456789}, nat{987654321}},
+	{nat{0, 0, 0, 1}, nil, nat{0, 0, 0, 1}},
+	{nat{0, 0, 0, 1111111110}, nat{0, 0, 0, 123456789}, nat{0, 0, 0, 987654321}},
+	{nat{0, 0, 0, 1}, nat{0, 0, _M}, nat{0, 0, 1}},
+}
+
+var prodNN = []argNN{
+	{},
+	{nil, nil, nil},
+	{nil, nat{991}, nil},
+	{nat{991}, nat{991}, nat{1}},
+	{nat{991 * 991}, nat{991}, nat{991}},
+	{nat{0, 0, 991 * 991}, nat{0, 991}, nat{0, 991}},
+	{nat{1 * 991, 2 * 991, 3 * 991, 4 * 991}, nat{1, 2, 3, 4}, nat{991}},
+	{nat{4, 11, 20, 30, 20, 11, 4}, nat{1, 2, 3, 4}, nat{4, 3, 2, 1}},
+	// 3^100 * 3^28 = 3^128
+	{
+		natFromString("11790184577738583171520872861412518665678211592275841109096961"),
+		natFromString("515377520732011331036461129765621272702107522001"),
+		natFromString("22876792454961"),
+	},
+	// z = 111....1 (70000 digits)
+	// x = 10^(99*700) + ... + 10^1400 + 10^700 + 1
+	// y = 111....1 (700 digits, larger than Karatsuba threshold on 32-bit and 64-bit)
+	{
+		natFromString(strings.Repeat("1", 70000)),
+		natFromString("1" + strings.Repeat(strings.Repeat("0", 699)+"1", 99)),
+		natFromString(strings.Repeat("1", 700)),
+	},
+	// z = 111....1 (20000 digits)
+	// x = 10^10000 + 1
+	// y = 111....1 (10000 digits)
+	{
+		natFromString(strings.Repeat("1", 20000)),
+		natFromString("1" + strings.Repeat("0", 9999) + "1"),
+		natFromString(strings.Repeat("1", 10000)),
+	},
+}
+
+func natFromString(s string) nat {
+	x, _, _, err := nat(nil).scan(strings.NewReader(s), 0, false)
+	if err != nil {
+		panic(err)
+	}
+	return x
+}
+
+func TestSet(t *testing.T) {
+	for _, a := range sumNN {
+		z := nat(nil).set(a.z)
+		if z.cmp(a.z) != 0 {
+			t.Errorf("got z = %v; want %v", z, a.z)
+		}
+	}
+}
+
+func testFunNN(t *testing.T, msg string, f funNN, a argNN) {
+	z := f(nil, a.x, a.y)
+	if z.cmp(a.z) != 0 {
+		t.Errorf("%s%+v\n\tgot z = %v; want %v", msg, a, z, a.z)
+	}
+}
+
+func TestFunNN(t *testing.T) {
+	for _, a := range sumNN {
+		arg := a
+		testFunNN(t, "add", nat.add, arg)
+
+		arg = argNN{a.z, a.y, a.x}
+		testFunNN(t, "add symmetric", nat.add, arg)
+
+		arg = argNN{a.x, a.z, a.y}
+		testFunNN(t, "sub", nat.sub, arg)
+
+		arg = argNN{a.y, a.z, a.x}
+		testFunNN(t, "sub symmetric", nat.sub, arg)
+	}
+
+	for _, a := range prodNN {
+		arg := a
+		testFunNN(t, "mul", nat.mul, arg)
+
+		arg = argNN{a.z, a.y, a.x}
+		testFunNN(t, "mul symmetric", nat.mul, arg)
+	}
+}
+
+var mulRangesN = []struct {
+	a, b uint64
+	prod string
+}{
+	{0, 0, "0"},
+	{1, 1, "1"},
+	{1, 2, "2"},
+	{1, 3, "6"},
+	{10, 10, "10"},
+	{0, 100, "0"},
+	{0, 1e9, "0"},
+	{1, 0, "1"},                    // empty range
+	{100, 1, "1"},                  // empty range
+	{1, 10, "3628800"},             // 10!
+	{1, 20, "2432902008176640000"}, // 20!
+	{1, 100,
+		"933262154439441526816992388562667004907159682643816214685929" +
+			"638952175999932299156089414639761565182862536979208272237582" +
+			"51185210916864000000000000000000000000", // 100!
+	},
+}
+
+func TestMulRangeN(t *testing.T) {
+	for i, r := range mulRangesN {
+		prod := nat(nil).mulRange(r.a, r.b).decimalString()
+		if prod != r.prod {
+			t.Errorf("#%d: got %s; want %s", i, prod, r.prod)
+		}
+	}
+}
+
+// allocBytes returns the number of bytes allocated by invoking f.
+func allocBytes(f func()) uint64 {
+	var stats runtime.MemStats
+	runtime.ReadMemStats(&stats)
+	t := stats.TotalAlloc
+	f()
+	runtime.ReadMemStats(&stats)
+	return stats.TotalAlloc - t
+}
+
+// TestMulUnbalanced tests that multiplying numbers of different lengths
+// does not cause deep recursion and in turn allocate too much memory.
+// Test case for issue 3807.
+func TestMulUnbalanced(t *testing.T) {
+	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
+	x := rndNat(50000)
+	y := rndNat(40)
+	allocSize := allocBytes(func() {
+		nat(nil).mul(x, y)
+	})
+	inputSize := uint64(len(x)+len(y)) * _S
+	if ratio := allocSize / uint64(inputSize); ratio > 10 {
+		t.Errorf("multiplication uses too much memory (%d > %d times the size of inputs)", allocSize, ratio)
+	}
+}
+
+func rndNat(n int) nat {
+	return nat(rndV(n)).norm()
+}
+
+func BenchmarkMul(b *testing.B) {
+	mulx := rndNat(1e4)
+	muly := rndNat(1e4)
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		var z nat
+		z.mul(mulx, muly)
+	}
+}
+
+func TestNLZ(t *testing.T) {
+	var x Word = _B >> 1
+	for i := 0; i <= _W; i++ {
+		if int(nlz(x)) != i {
+			t.Errorf("failed at %x: got %d want %d", x, nlz(x), i)
+		}
+		x >>= 1
+	}
+}
+
+type shiftTest struct {
+	in    nat
+	shift uint
+	out   nat
+}
+
+var leftShiftTests = []shiftTest{
+	{nil, 0, nil},
+	{nil, 1, nil},
+	{natOne, 0, natOne},
+	{natOne, 1, natTwo},
+	{nat{1 << (_W - 1)}, 1, nat{0}},
+	{nat{1 << (_W - 1), 0}, 1, nat{0, 1}},
+}
+
+func TestShiftLeft(t *testing.T) {
+	for i, test := range leftShiftTests {
+		var z nat
+		z = z.shl(test.in, test.shift)
+		for j, d := range test.out {
+			if j >= len(z) || z[j] != d {
+				t.Errorf("#%d: got: %v want: %v", i, z, test.out)
+				break
+			}
+		}
+	}
+}
+
+var rightShiftTests = []shiftTest{
+	{nil, 0, nil},
+	{nil, 1, nil},
+	{natOne, 0, natOne},
+	{natOne, 1, nil},
+	{natTwo, 1, natOne},
+	{nat{0, 1}, 1, nat{1 << (_W - 1)}},
+	{nat{2, 1, 1}, 1, nat{1<<(_W-1) + 1, 1 << (_W - 1)}},
+}
+
+func TestShiftRight(t *testing.T) {
+	for i, test := range rightShiftTests {
+		var z nat
+		z = z.shr(test.in, test.shift)
+		for j, d := range test.out {
+			if j >= len(z) || z[j] != d {
+				t.Errorf("#%d: got: %v want: %v", i, z, test.out)
+				break
+			}
+		}
+	}
+}
+
+type modWTest struct {
+	in       string
+	dividend string
+	out      string
+}
+
+var modWTests32 = []modWTest{
+	{"23492635982634928349238759823742", "252341", "220170"},
+}
+
+var modWTests64 = []modWTest{
+	{"6527895462947293856291561095690465243862946", "524326975699234", "375066989628668"},
+}
+
+func runModWTests(t *testing.T, tests []modWTest) {
+	for i, test := range tests {
+		in, _ := new(Int).SetString(test.in, 10)
+		d, _ := new(Int).SetString(test.dividend, 10)
+		out, _ := new(Int).SetString(test.out, 10)
+
+		r := in.abs.modW(d.abs[0])
+		if r != out.abs[0] {
+			t.Errorf("#%d failed: got %d want %s", i, r, out)
+		}
+	}
+}
+
+func TestModW(t *testing.T) {
+	if _W >= 32 {
+		runModWTests(t, modWTests32)
+	}
+	if _W >= 64 {
+		runModWTests(t, modWTests64)
+	}
+}
+
+func TestTrailingZeroBits(t *testing.T) {
+	// test 0 case explicitly
+	if n := trailingZeroBits(0); n != 0 {
+		t.Errorf("got trailingZeroBits(0) = %d; want 0", n)
+	}
+
+	x := Word(1)
+	for i := uint(0); i < _W; i++ {
+		n := trailingZeroBits(x)
+		if n != i {
+			t.Errorf("got trailingZeroBits(%#x) = %d; want %d", x, n, i%_W)
+		}
+		x <<= 1
+	}
+
+	// test 0 case explicitly
+	if n := nat(nil).trailingZeroBits(); n != 0 {
+		t.Errorf("got nat(nil).trailingZeroBits() = %d; want 0", n)
+	}
+
+	y := nat(nil).set(natOne)
+	for i := uint(0); i <= 3*_W; i++ {
+		n := y.trailingZeroBits()
+		if n != i {
+			t.Errorf("got 0x%s.trailingZeroBits() = %d; want %d", y.hexString(), n, i)
+		}
+		y = y.shl(y, 1)
+	}
+}
+
+var montgomeryTests = []struct {
+	x, y, m      string
+	k0           uint64
+	out32, out64 string
+}{
+	{
+		"0xffffffffffffffffffffffffffffffffffffffffffffffffe",
+		"0xffffffffffffffffffffffffffffffffffffffffffffffffe",
+		"0xfffffffffffffffffffffffffffffffffffffffffffffffff",
+		0x0000000000000000,
+		"0xffffffffffffffffffffffffffffffffffffffffff",
+		"0xffffffffffffffffffffffffffffffffff",
+	},
+	{
+		"0x0000000080000000",
+		"0x00000000ffffffff",
+		"0x0000000010000001",
+		0xff0000000fffffff,
+		"0x0000000088000000",
+		"0x0000000007800001",
+	},
+	{
+		"0xffffffffffffffffffffffffffffffff00000000000022222223333333333444444444",
+		"0xffffffffffffffffffffffffffffffff999999999999999aaabbbbbbbbcccccccccccc",
+		"0x33377fffffffffffffffffffffffffffffffffffffffffffff0000000000022222eee1",
+		0xdecc8f1249812adf,
+		"0x22bb05b6d95eaaeca2bb7c05e51f807bce9064b5fbad177161695e4558f9474e91cd79",
+		"0x14beb58d230f85b6d95eaaeca2bb7c05e51f807bce9064b5fb45669afa695f228e48cd",
+	},
+	{
+		"0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffff00000000000022222223333333333444444444",
+		"0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffff999999999999999aaabbbbbbbbcccccccccccc",
+		"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff33377fffffffffffffffffffffffffffffffffffffffffffff0000000000022222eee1",
+		0xdecc8f1249812adf,
+		"0x5c0d52f451aec609b15da8e5e5626c4eaa88723bdeac9d25ca9b961269400410ca208a16af9c2fb07d7a11c7772cba02c22f9711078d51a3797eb18e691295293284d988e349fa6deba46b25a4ecd9f715",
+		"0x92fcad4b5c0d52f451aec609b15da8e5e5626c4eaa88723bdeac9d25ca9b961269400410ca208a16af9c2fb07d799c32fe2f3cc5422f9711078d51a3797eb18e691295293284d8f5e69caf6decddfe1df6",
+	},
+}
+
+func TestMontgomery(t *testing.T) {
+	for i, test := range montgomeryTests {
+		x := natFromString(test.x)
+		y := natFromString(test.y)
+		m := natFromString(test.m)
+
+		var out nat
+		if _W == 32 {
+			out = natFromString(test.out32)
+		} else {
+			out = natFromString(test.out64)
+		}
+
+		k0 := Word(test.k0 & _M) // mask k0 to ensure that it fits for 32-bit systems.
+		z := nat(nil).montgomery(x, y, m, k0, len(m))
+		z = z.norm()
+		if z.cmp(out) != 0 {
+			t.Errorf("#%d got %s want %s", i, z.decimalString(), out.decimalString())
+		}
+	}
+}
+
+var expNNTests = []struct {
+	x, y, m string
+	out     string
+}{
+	{"0", "0", "0", "1"},
+	{"0", "0", "1", "0"},
+	{"1", "1", "1", "0"},
+	{"2", "1", "1", "0"},
+	{"2", "2", "1", "0"},
+	{"10", "100000000000", "1", "0"},
+	{"0x8000000000000000", "2", "", "0x40000000000000000000000000000000"},
+	{"0x8000000000000000", "2", "6719", "4944"},
+	{"0x8000000000000000", "3", "6719", "5447"},
+	{"0x8000000000000000", "1000", "6719", "1603"},
+	{"0x8000000000000000", "1000000", "6719", "3199"},
+	{
+		"2938462938472983472983659726349017249287491026512746239764525612965293865296239471239874193284792387498274256129746192347",
+		"298472983472983471903246121093472394872319615612417471234712061",
+		"29834729834729834729347290846729561262544958723956495615629569234729836259263598127342374289365912465901365498236492183464",
+		"23537740700184054162508175125554701713153216681790245129157191391322321508055833908509185839069455749219131480588829346291",
+	},
+}
+
+func TestExpNN(t *testing.T) {
+	for i, test := range expNNTests {
+		x := natFromString(test.x)
+		y := natFromString(test.y)
+		out := natFromString(test.out)
+
+		var m nat
+		if len(test.m) > 0 {
+			m = natFromString(test.m)
+		}
+
+		z := nat(nil).expNN(x, y, m)
+		if z.cmp(out) != 0 {
+			t.Errorf("#%d got %s want %s", i, z.decimalString(), out.decimalString())
+		}
+	}
+}
+
+func ExpHelper(b *testing.B, x, y Word) {
+	var z nat
+	for i := 0; i < b.N; i++ {
+		z.expWW(x, y)
+	}
+}
+
+func BenchmarkExp3Power0x10(b *testing.B)     { ExpHelper(b, 3, 0x10) }
+func BenchmarkExp3Power0x40(b *testing.B)     { ExpHelper(b, 3, 0x40) }
+func BenchmarkExp3Power0x100(b *testing.B)    { ExpHelper(b, 3, 0x100) }
+func BenchmarkExp3Power0x400(b *testing.B)    { ExpHelper(b, 3, 0x400) }
+func BenchmarkExp3Power0x1000(b *testing.B)   { ExpHelper(b, 3, 0x1000) }
+func BenchmarkExp3Power0x4000(b *testing.B)   { ExpHelper(b, 3, 0x4000) }
+func BenchmarkExp3Power0x10000(b *testing.B)  { ExpHelper(b, 3, 0x10000) }
+func BenchmarkExp3Power0x40000(b *testing.B)  { ExpHelper(b, 3, 0x40000) }
+func BenchmarkExp3Power0x100000(b *testing.B) { ExpHelper(b, 3, 0x100000) }
+func BenchmarkExp3Power0x400000(b *testing.B) { ExpHelper(b, 3, 0x400000) }
+
+func fibo(n int) nat {
+	switch n {
+	case 0:
+		return nil
+	case 1:
+		return nat{1}
+	}
+	f0 := fibo(0)
+	f1 := fibo(1)
+	var f2 nat
+	for i := 1; i < n; i++ {
+		f2 = f2.add(f0, f1)
+		f0, f1, f2 = f1, f2, f0
+	}
+	return f1
+}
+
+var fiboNums = []string{
+	"0",
+	"55",
+	"6765",
+	"832040",
+	"102334155",
+	"12586269025",
+	"1548008755920",
+	"190392490709135",
+	"23416728348467685",
+	"2880067194370816120",
+	"354224848179261915075",
+}
+
+func TestFibo(t *testing.T) {
+	for i, want := range fiboNums {
+		n := i * 10
+		got := fibo(n).decimalString()
+		if got != want {
+			t.Errorf("fibo(%d) failed: got %s want %s", n, got, want)
+		}
+	}
+}
+
+func BenchmarkFibo(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		fibo(1e0)
+		fibo(1e1)
+		fibo(1e2)
+		fibo(1e3)
+		fibo(1e4)
+		fibo(1e5)
+	}
+}
+
+var bitTests = []struct {
+	x    string
+	i    uint
+	want uint
+}{
+	{"0", 0, 0},
+	{"0", 1, 0},
+	{"0", 1000, 0},
+
+	{"0x1", 0, 1},
+	{"0x10", 0, 0},
+	{"0x10", 3, 0},
+	{"0x10", 4, 1},
+	{"0x10", 5, 0},
+
+	{"0x8000000000000000", 62, 0},
+	{"0x8000000000000000", 63, 1},
+	{"0x8000000000000000", 64, 0},
+
+	{"0x3" + strings.Repeat("0", 32), 127, 0},
+	{"0x3" + strings.Repeat("0", 32), 128, 1},
+	{"0x3" + strings.Repeat("0", 32), 129, 1},
+	{"0x3" + strings.Repeat("0", 32), 130, 0},
+}
+
+func TestBit(t *testing.T) {
+	for i, test := range bitTests {
+		x := natFromString(test.x)
+		if got := x.bit(test.i); got != test.want {
+			t.Errorf("#%d: %s.bit(%d) = %v; want %v", i, test.x, test.i, got, test.want)
+		}
+	}
+}
+
+var stickyTests = []struct {
+	x    string
+	i    uint
+	want uint
+}{
+	{"0", 0, 0},
+	{"0", 1, 0},
+	{"0", 1000, 0},
+
+	{"0x1", 0, 0},
+	{"0x1", 1, 1},
+
+	{"0x1350", 0, 0},
+	{"0x1350", 4, 0},
+	{"0x1350", 5, 1},
+
+	{"0x8000000000000000", 63, 0},
+	{"0x8000000000000000", 64, 1},
+
+	{"0x1" + strings.Repeat("0", 100), 400, 0},
+	{"0x1" + strings.Repeat("0", 100), 401, 1},
+}
+
+func TestSticky(t *testing.T) {
+	for i, test := range stickyTests {
+		x := natFromString(test.x)
+		if got := x.sticky(test.i); got != test.want {
+			t.Errorf("#%d: %s.sticky(%d) = %v; want %v", i, test.x, test.i, got, test.want)
+		}
+		if test.want == 1 {
+			// all subsequent i's should also return 1
+			for d := uint(1); d <= 3; d++ {
+				if got := x.sticky(test.i + d); got != 1 {
+					t.Errorf("#%d: %s.sticky(%d) = %v; want %v", i, test.x, test.i+d, got, 1)
+				}
+			}
+		}
+	}
+}
diff --git a/src/cmd/compile/internal/big/natconv.go b/src/cmd/compile/internal/big/natconv.go
new file mode 100644
index 0000000..022dcfe
--- /dev/null
+++ b/src/cmd/compile/internal/big/natconv.go
@@ -0,0 +1,495 @@
+// 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 nat-to-string conversion functions.
+
+package big
+
+import (
+	"errors"
+	"fmt"
+	"io"
+	"math"
+	"sync"
+)
+
+// MaxBase is the largest number base accepted for string conversions.
+const MaxBase = 'z' - 'a' + 10 + 1
+
+// maxPow returns (b**n, n) such that b**n is the largest power b**n <= _M.
+// For instance maxPow(10) == (1e19, 19) for 19 decimal digits in a 64bit Word.
+// In other words, at most n digits in base b fit into a Word.
+// TODO(gri) replace this with a table, generated at build time.
+func maxPow(b Word) (p Word, n int) {
+	p, n = b, 1 // assuming b <= _M
+	for max := _M / b; p <= max; {
+		// p == b**n && p <= max
+		p *= b
+		n++
+	}
+	// p == b**n && p <= _M
+	return
+}
+
+// pow returns x**n for n > 0, and 1 otherwise.
+func pow(x Word, n int) (p Word) {
+	// n == sum of bi * 2**i, for 0 <= i < imax, and bi is 0 or 1
+	// thus x**n == product of x**(2**i) for all i where bi == 1
+	// (Russian Peasant Method for exponentiation)
+	p = 1
+	for n > 0 {
+		if n&1 != 0 {
+			p *= x
+		}
+		x *= x
+		n >>= 1
+	}
+	return
+}
+
+// scan scans the number corresponding to the longest possible prefix
+// from r representing an unsigned number in a given conversion base.
+// It returns the corresponding natural number res, the actual base b,
+// a digit count, and a read or syntax error err, if any.
+//
+//	number   = [ prefix ] mantissa .
+//	prefix   = "0" [ "x" | "X" | "b" | "B" ] .
+//      mantissa = digits | digits "." [ digits ] | "." digits .
+//	digits   = digit { digit } .
+//	digit    = "0" ... "9" | "a" ... "z" | "A" ... "Z" .
+//
+// Unless fracOk is set, the base argument must be 0 or a value between
+// 2 and MaxBase. If fracOk is set, the base argument must be one of
+// 0, 2, 10, or 16. Providing an invalid base argument leads to a run-
+// time panic.
+//
+// For base 0, the number prefix determines the actual base: A prefix of
+// ``0x'' or ``0X'' selects base 16; if fracOk is not set, the ``0'' prefix
+// selects base 8, and a ``0b'' or ``0B'' prefix selects base 2. Otherwise
+// the selected base is 10 and no prefix is accepted.
+//
+// If fracOk is set, an octal prefix is ignored (a leading ``0'' simply
+// stands for a zero digit), and a period followed by a fractional part
+// is permitted. The result value is computed as if there were no period
+// present; and the count value is used to determine the fractional part.
+//
+// A result digit count > 0 corresponds to the number of (non-prefix) digits
+// parsed. A digit count <= 0 indicates the presence of a period (if fracOk
+// is set, only), and -count is the number of fractional digits found.
+// In this case, the actual value of the scanned number is res * b**count.
+//
+func (z nat) scan(r io.ByteScanner, base int, fracOk bool) (res nat, b, count int, err error) {
+	// reject illegal bases
+	baseOk := base == 0 ||
+		!fracOk && 2 <= base && base <= MaxBase ||
+		fracOk && (base == 2 || base == 10 || base == 16)
+	if !baseOk {
+		panic(fmt.Sprintf("illegal number base %d", base))
+	}
+
+	// one char look-ahead
+	ch, err := r.ReadByte()
+	if err != nil {
+		return
+	}
+
+	// determine actual base
+	b = base
+	if base == 0 {
+		// actual base is 10 unless there's a base prefix
+		b = 10
+		if ch == '0' {
+			count = 1
+			switch ch, err = r.ReadByte(); err {
+			case nil:
+				// possibly one of 0x, 0X, 0b, 0B
+				if !fracOk {
+					b = 8
+				}
+				switch ch {
+				case 'x', 'X':
+					b = 16
+				case 'b', 'B':
+					b = 2
+				}
+				switch b {
+				case 16, 2:
+					count = 0 // prefix is not counted
+					if ch, err = r.ReadByte(); err != nil {
+						// io.EOF is also an error in this case
+						return
+					}
+				case 8:
+					count = 0 // prefix is not counted
+				}
+			case io.EOF:
+				// input is "0"
+				res = z[:0]
+				err = nil
+				return
+			default:
+				// read error
+				return
+			}
+		}
+	}
+
+	// convert string
+	// Algorithm: Collect digits in groups of at most n digits in di
+	// and then use mulAddWW for every such group to add them to the
+	// result.
+	z = z[:0]
+	b1 := Word(b)
+	bn, n := maxPow(b1) // at most n digits in base b1 fit into Word
+	di := Word(0)       // 0 <= di < b1**i < bn
+	i := 0              // 0 <= i < n
+	dp := -1            // position of decimal point
+	for {
+		if fracOk && ch == '.' {
+			fracOk = false
+			dp = count
+			// advance
+			if ch, err = r.ReadByte(); err != nil {
+				if err == io.EOF {
+					err = nil
+					break
+				}
+				return
+			}
+		}
+
+		// convert rune into digit value d1
+		var d1 Word
+		switch {
+		case '0' <= ch && ch <= '9':
+			d1 = Word(ch - '0')
+		case 'a' <= ch && ch <= 'z':
+			d1 = Word(ch - 'a' + 10)
+		case 'A' <= ch && ch <= 'Z':
+			d1 = Word(ch - 'A' + 10)
+		default:
+			d1 = MaxBase + 1
+		}
+		if d1 >= b1 {
+			r.UnreadByte() // ch does not belong to number anymore
+			break
+		}
+		count++
+
+		// collect d1 in di
+		di = di*b1 + d1
+		i++
+
+		// if di is "full", add it to the result
+		if i == n {
+			z = z.mulAddWW(z, bn, di)
+			di = 0
+			i = 0
+		}
+
+		// advance
+		if ch, err = r.ReadByte(); err != nil {
+			if err == io.EOF {
+				err = nil
+				break
+			}
+			return
+		}
+	}
+
+	if count == 0 {
+		// no digits found
+		switch {
+		case base == 0 && b == 8:
+			// there was only the octal prefix 0 (possibly followed by digits > 7);
+			// count as one digit and return base 10, not 8
+			count = 1
+			b = 10
+		case base != 0 || b != 8:
+			// there was neither a mantissa digit nor the octal prefix 0
+			err = errors.New("syntax error scanning number")
+		}
+		return
+	}
+	// count > 0
+
+	// add remaining digits to result
+	if i > 0 {
+		z = z.mulAddWW(z, pow(b1, i), di)
+	}
+	res = z.norm()
+
+	// adjust for fraction, if any
+	if dp >= 0 {
+		// 0 <= dp <= count > 0
+		count = dp - count
+	}
+
+	return
+}
+
+// Character sets for string conversion.
+const (
+	lowercaseDigits = "0123456789abcdefghijklmnopqrstuvwxyz"
+	uppercaseDigits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+)
+
+// decimalString returns a decimal representation of x.
+// It calls x.string with the charset "0123456789".
+func (x nat) decimalString() string {
+	return x.string(lowercaseDigits[:10])
+}
+
+// hexString returns a hexadecimal representation of x.
+// It calls x.string with the charset "0123456789abcdef".
+func (x nat) hexString() string {
+	return x.string(lowercaseDigits[:16])
+}
+
+// string converts x to a string using digits from a charset; a digit with
+// value d is represented by charset[d]. The conversion base is determined
+// by len(charset), which must be >= 2 and <= 256.
+func (x nat) string(charset string) string {
+	b := Word(len(charset))
+
+	// special cases
+	switch {
+	case b < 2 || b > 256:
+		panic("invalid character set length")
+	case len(x) == 0:
+		return string(charset[0])
+	}
+
+	// allocate buffer for conversion
+	i := int(float64(x.bitLen())/math.Log2(float64(b))) + 1 // off by one at most
+	s := make([]byte, i)
+
+	// convert power of two and non power of two bases separately
+	if b == b&-b {
+		// shift is base-b digit size in bits
+		shift := trailingZeroBits(b) // shift > 0 because b >= 2
+		mask := Word(1)<<shift - 1
+		w := x[0]
+		nbits := uint(_W) // number of unprocessed bits in w
+
+		// convert less-significant words
+		for k := 1; k < len(x); k++ {
+			// convert full digits
+			for nbits >= shift {
+				i--
+				s[i] = charset[w&mask]
+				w >>= shift
+				nbits -= shift
+			}
+
+			// convert any partial leading digit and advance to next word
+			if nbits == 0 {
+				// no partial digit remaining, just advance
+				w = x[k]
+				nbits = _W
+			} else {
+				// partial digit in current (k-1) and next (k) word
+				w |= x[k] << nbits
+				i--
+				s[i] = charset[w&mask]
+
+				// advance
+				w = x[k] >> (shift - nbits)
+				nbits = _W - (shift - nbits)
+			}
+		}
+
+		// convert digits of most-significant word (omit leading zeros)
+		for nbits >= 0 && w != 0 {
+			i--
+			s[i] = charset[w&mask]
+			w >>= shift
+			nbits -= shift
+		}
+
+	} else {
+		bb, ndigits := maxPow(Word(b))
+
+		// construct table of successive squares of bb*leafSize to use in subdivisions
+		// result (table != nil) <=> (len(x) > leafSize > 0)
+		table := divisors(len(x), b, ndigits, bb)
+
+		// preserve x, create local copy for use by convertWords
+		q := nat(nil).set(x)
+
+		// convert q to string s in base b
+		q.convertWords(s, charset, b, ndigits, bb, table)
+
+		// strip leading zeros
+		// (x != 0; thus s must contain at least one non-zero digit
+		// and the loop will terminate)
+		i = 0
+		for zero := charset[0]; s[i] == zero; {
+			i++
+		}
+	}
+
+	return string(s[i:])
+}
+
+// Convert words of q to base b digits in s. If q is large, it is recursively "split in half"
+// by nat/nat division using tabulated divisors. Otherwise, it is converted iteratively using
+// repeated nat/Word division.
+//
+// The iterative method processes n Words by n divW() calls, each of which visits every Word in the
+// incrementally shortened q for a total of n + (n-1) + (n-2) ... + 2 + 1, or n(n+1)/2 divW()'s.
+// Recursive conversion divides q by its approximate square root, yielding two parts, each half
+// the size of q. Using the iterative method on both halves means 2 * (n/2)(n/2 + 1)/2 divW()'s
+// plus the expensive long div(). Asymptotically, the ratio is favorable at 1/2 the divW()'s, and
+// is made better by splitting the subblocks recursively. Best is to split blocks until one more
+// split would take longer (because of the nat/nat div()) than the twice as many divW()'s of the
+// iterative approach. This threshold is represented by leafSize. Benchmarking of leafSize in the
+// range 2..64 shows that values of 8 and 16 work well, with a 4x speedup at medium lengths and
+// ~30x for 20000 digits. Use nat_test.go's BenchmarkLeafSize tests to optimize leafSize for
+// specific hardware.
+//
+func (q nat) convertWords(s []byte, charset string, b Word, ndigits int, bb Word, table []divisor) {
+	// split larger blocks recursively
+	if table != nil {
+		// len(q) > leafSize > 0
+		var r nat
+		index := len(table) - 1
+		for len(q) > leafSize {
+			// find divisor close to sqrt(q) if possible, but in any case < q
+			maxLength := q.bitLen()     // ~= log2 q, or at of least largest possible q of this bit length
+			minLength := maxLength >> 1 // ~= log2 sqrt(q)
+			for index > 0 && table[index-1].nbits > minLength {
+				index-- // desired
+			}
+			if table[index].nbits >= maxLength && table[index].bbb.cmp(q) >= 0 {
+				index--
+				if index < 0 {
+					panic("internal inconsistency")
+				}
+			}
+
+			// split q into the two digit number (q'*bbb + r) to form independent subblocks
+			q, r = q.div(r, q, table[index].bbb)
+
+			// convert subblocks and collect results in s[:h] and s[h:]
+			h := len(s) - table[index].ndigits
+			r.convertWords(s[h:], charset, b, ndigits, bb, table[0:index])
+			s = s[:h] // == q.convertWords(s, charset, b, ndigits, bb, table[0:index+1])
+		}
+	}
+
+	// having split any large blocks now process the remaining (small) block iteratively
+	i := len(s)
+	var r Word
+	if b == 10 {
+		// hard-coding for 10 here speeds this up by 1.25x (allows for / and % by constants)
+		for len(q) > 0 {
+			// extract least significant, base bb "digit"
+			q, r = q.divW(q, bb)
+			for j := 0; j < ndigits && i > 0; j++ {
+				i--
+				// avoid % computation since r%10 == r - int(r/10)*10;
+				// this appears to be faster for BenchmarkString10000Base10
+				// and smaller strings (but a bit slower for larger ones)
+				t := r / 10
+				s[i] = charset[r-t<<3-t-t] // TODO(gri) replace w/ t*10 once compiler produces better code
+				r = t
+			}
+		}
+	} else {
+		for len(q) > 0 {
+			// extract least significant, base bb "digit"
+			q, r = q.divW(q, bb)
+			for j := 0; j < ndigits && i > 0; j++ {
+				i--
+				s[i] = charset[r%b]
+				r /= b
+			}
+		}
+	}
+
+	// prepend high-order zeroes
+	zero := charset[0]
+	for i > 0 { // while need more leading zeroes
+		i--
+		s[i] = zero
+	}
+}
+
+// Split blocks greater than leafSize Words (or set to 0 to disable recursive conversion)
+// Benchmark and configure leafSize using: go test -bench="Leaf"
+//   8 and 16 effective on 3.0 GHz Xeon "Clovertown" CPU (128 byte cache lines)
+//   8 and 16 effective on 2.66 GHz Core 2 Duo "Penryn" CPU
+var leafSize int = 8 // number of Word-size binary values treat as a monolithic block
+
+type divisor struct {
+	bbb     nat // divisor
+	nbits   int // bit length of divisor (discounting leading zeroes) ~= log2(bbb)
+	ndigits int // digit length of divisor in terms of output base digits
+}
+
+var cacheBase10 struct {
+	sync.Mutex
+	table [64]divisor // cached divisors for base 10
+}
+
+// expWW computes x**y
+func (z nat) expWW(x, y Word) nat {
+	return z.expNN(nat(nil).setWord(x), nat(nil).setWord(y), nil)
+}
+
+// construct table of powers of bb*leafSize to use in subdivisions
+func divisors(m int, b Word, ndigits int, bb Word) []divisor {
+	// only compute table when recursive conversion is enabled and x is large
+	if leafSize == 0 || m <= leafSize {
+		return nil
+	}
+
+	// determine k where (bb**leafSize)**(2**k) >= sqrt(x)
+	k := 1
+	for words := leafSize; words < m>>1 && k < len(cacheBase10.table); words <<= 1 {
+		k++
+	}
+
+	// reuse and extend existing table of divisors or create new table as appropriate
+	var table []divisor // for b == 10, table overlaps with cacheBase10.table
+	if b == 10 {
+		cacheBase10.Lock()
+		table = cacheBase10.table[0:k] // reuse old table for this conversion
+	} else {
+		table = make([]divisor, k) // create new table for this conversion
+	}
+
+	// extend table
+	if table[k-1].ndigits == 0 {
+		// add new entries as needed
+		var larger nat
+		for i := 0; i < k; i++ {
+			if table[i].ndigits == 0 {
+				if i == 0 {
+					table[0].bbb = nat(nil).expWW(bb, Word(leafSize))
+					table[0].ndigits = ndigits * leafSize
+				} else {
+					table[i].bbb = nat(nil).mul(table[i-1].bbb, table[i-1].bbb)
+					table[i].ndigits = 2 * table[i-1].ndigits
+				}
+
+				// optimization: exploit aggregated extra bits in macro blocks
+				larger = nat(nil).set(table[i].bbb)
+				for mulAddVWW(larger, larger, b, 0) == 0 {
+					table[i].bbb = table[i].bbb.set(larger)
+					table[i].ndigits++
+				}
+
+				table[i].nbits = table[i].bbb.bitLen()
+			}
+		}
+	}
+
+	if b == 10 {
+		cacheBase10.Unlock()
+	}
+
+	return table
+}
diff --git a/src/cmd/compile/internal/big/natconv_test.go b/src/cmd/compile/internal/big/natconv_test.go
new file mode 100644
index 0000000..f321fbc
--- /dev/null
+++ b/src/cmd/compile/internal/big/natconv_test.go
@@ -0,0 +1,425 @@
+// 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
+
+import (
+	"io"
+	"strings"
+	"testing"
+)
+
+func toString(x nat, charset string) string {
+	base := len(charset)
+
+	// special cases
+	switch {
+	case base < 2:
+		panic("illegal base")
+	case len(x) == 0:
+		return string(charset[0])
+	}
+
+	// allocate buffer for conversion
+	i := x.bitLen()/log2(Word(base)) + 1 // +1: round up
+	s := make([]byte, i)
+
+	// don't destroy x
+	q := nat(nil).set(x)
+
+	// convert
+	for len(q) > 0 {
+		i--
+		var r Word
+		q, r = q.divW(q, Word(base))
+		s[i] = charset[r]
+	}
+
+	return string(s[i:])
+}
+
+var strTests = []struct {
+	x nat    // nat value to be converted
+	c string // conversion charset
+	s string // expected result
+}{
+	{nil, "01", "0"},
+	{nat{1}, "01", "1"},
+	{nat{0xc5}, "01", "11000101"},
+	{nat{03271}, lowercaseDigits[:8], "3271"},
+	{nat{10}, lowercaseDigits[:10], "10"},
+	{nat{1234567890}, uppercaseDigits[:10], "1234567890"},
+	{nat{0xdeadbeef}, lowercaseDigits[:16], "deadbeef"},
+	{nat{0xdeadbeef}, uppercaseDigits[:16], "DEADBEEF"},
+	{nat{0x229be7}, lowercaseDigits[:17], "1a2b3c"},
+	{nat{0x309663e6}, uppercaseDigits[:32], "O9COV6"},
+}
+
+func TestString(t *testing.T) {
+	// test invalid character set explicitly
+	var panicStr string
+	func() {
+		defer func() {
+			panicStr = recover().(string)
+		}()
+		natOne.string("0")
+	}()
+	if panicStr != "invalid character set length" {
+		t.Errorf("expected panic for invalid character set")
+	}
+
+	for _, a := range strTests {
+		s := a.x.string(a.c)
+		if s != a.s {
+			t.Errorf("string%+v\n\tgot s = %s; want %s", a, s, a.s)
+		}
+
+		x, b, _, err := nat(nil).scan(strings.NewReader(a.s), len(a.c), false)
+		if x.cmp(a.x) != 0 {
+			t.Errorf("scan%+v\n\tgot z = %v; want %v", a, x, a.x)
+		}
+		if b != len(a.c) {
+			t.Errorf("scan%+v\n\tgot b = %d; want %d", a, b, len(a.c))
+		}
+		if err != nil {
+			t.Errorf("scan%+v\n\tgot error = %s", a, err)
+		}
+	}
+}
+
+var natScanTests = []struct {
+	s     string // string to be scanned
+	base  int    // input base
+	frac  bool   // fraction ok
+	x     nat    // expected nat
+	b     int    // expected base
+	count int    // expected digit count
+	ok    bool   // expected success
+	next  rune   // next character (or 0, if at EOF)
+}{
+	// error: no mantissa
+	{},
+	{s: "?"},
+	{base: 10},
+	{base: 36},
+	{s: "?", base: 10},
+	{s: "0x"},
+	{s: "345", base: 2},
+
+	// error: incorrect use of decimal point
+	{s: ".0"},
+	{s: ".0", base: 10},
+	{s: ".", base: 0},
+	{s: "0x.0"},
+
+	// no errors
+	{"0", 0, false, nil, 10, 1, true, 0},
+	{"0", 10, false, nil, 10, 1, true, 0},
+	{"0", 36, false, nil, 36, 1, true, 0},
+	{"1", 0, false, nat{1}, 10, 1, true, 0},
+	{"1", 10, false, nat{1}, 10, 1, true, 0},
+	{"0 ", 0, false, nil, 10, 1, true, ' '},
+	{"08", 0, false, nil, 10, 1, true, '8'},
+	{"08", 10, false, nat{8}, 10, 2, true, 0},
+	{"018", 0, false, nat{1}, 8, 1, true, '8'},
+	{"0b1", 0, false, nat{1}, 2, 1, true, 0},
+	{"0b11000101", 0, false, nat{0xc5}, 2, 8, true, 0},
+	{"03271", 0, false, nat{03271}, 8, 4, true, 0},
+	{"10ab", 0, false, nat{10}, 10, 2, true, 'a'},
+	{"1234567890", 0, false, nat{1234567890}, 10, 10, true, 0},
+	{"xyz", 36, false, nat{(33*36+34)*36 + 35}, 36, 3, true, 0},
+	{"xyz?", 36, false, nat{(33*36+34)*36 + 35}, 36, 3, true, '?'},
+	{"0x", 16, false, nil, 16, 1, true, 'x'},
+	{"0xdeadbeef", 0, false, nat{0xdeadbeef}, 16, 8, true, 0},
+	{"0XDEADBEEF", 0, false, nat{0xdeadbeef}, 16, 8, true, 0},
+
+	// no errors, decimal point
+	{"0.", 0, false, nil, 10, 1, true, '.'},
+	{"0.", 10, true, nil, 10, 0, true, 0},
+	{"0.1.2", 10, true, nat{1}, 10, -1, true, '.'},
+	{".000", 10, true, nil, 10, -3, true, 0},
+	{"12.3", 10, true, nat{123}, 10, -1, true, 0},
+	{"012.345", 10, true, nat{12345}, 10, -3, true, 0},
+}
+
+func TestScanBase(t *testing.T) {
+	for _, a := range natScanTests {
+		r := strings.NewReader(a.s)
+		x, b, count, err := nat(nil).scan(r, a.base, a.frac)
+		if err == nil && !a.ok {
+			t.Errorf("scan%+v\n\texpected error", a)
+		}
+		if err != nil {
+			if a.ok {
+				t.Errorf("scan%+v\n\tgot error = %s", a, err)
+			}
+			continue
+		}
+		if x.cmp(a.x) != 0 {
+			t.Errorf("scan%+v\n\tgot z = %v; want %v", a, x, a.x)
+		}
+		if b != a.b {
+			t.Errorf("scan%+v\n\tgot b = %d; want %d", a, b, a.base)
+		}
+		if count != a.count {
+			t.Errorf("scan%+v\n\tgot count = %d; want %d", a, count, a.count)
+		}
+		next, _, err := r.ReadRune()
+		if err == io.EOF {
+			next = 0
+			err = nil
+		}
+		if err == nil && next != a.next {
+			t.Errorf("scan%+v\n\tgot next = %q; want %q", a, next, a.next)
+		}
+	}
+}
+
+var pi = "3" +
+	"14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651" +
+	"32823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461" +
+	"28475648233786783165271201909145648566923460348610454326648213393607260249141273724587006606315588174881520920" +
+	"96282925409171536436789259036001133053054882046652138414695194151160943305727036575959195309218611738193261179" +
+	"31051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798" +
+	"60943702770539217176293176752384674818467669405132000568127145263560827785771342757789609173637178721468440901" +
+	"22495343014654958537105079227968925892354201995611212902196086403441815981362977477130996051870721134999999837" +
+	"29780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083" +
+	"81420617177669147303598253490428755468731159562863882353787593751957781857780532171226806613001927876611195909" +
+	"21642019893809525720106548586327886593615338182796823030195203530185296899577362259941389124972177528347913151" +
+	"55748572424541506959508295331168617278558890750983817546374649393192550604009277016711390098488240128583616035" +
+	"63707660104710181942955596198946767837449448255379774726847104047534646208046684259069491293313677028989152104" +
+	"75216205696602405803815019351125338243003558764024749647326391419927260426992279678235478163600934172164121992" +
+	"45863150302861829745557067498385054945885869269956909272107975093029553211653449872027559602364806654991198818" +
+	"34797753566369807426542527862551818417574672890977772793800081647060016145249192173217214772350141441973568548" +
+	"16136115735255213347574184946843852332390739414333454776241686251898356948556209921922218427255025425688767179" +
+	"04946016534668049886272327917860857843838279679766814541009538837863609506800642251252051173929848960841284886" +
+	"26945604241965285022210661186306744278622039194945047123713786960956364371917287467764657573962413890865832645" +
+	"99581339047802759009946576407895126946839835259570982582262052248940772671947826848260147699090264013639443745" +
+	"53050682034962524517493996514314298091906592509372216964615157098583874105978859597729754989301617539284681382" +
+	"68683868942774155991855925245953959431049972524680845987273644695848653836736222626099124608051243884390451244" +
+	"13654976278079771569143599770012961608944169486855584840635342207222582848864815845602850601684273945226746767" +
+	"88952521385225499546667278239864565961163548862305774564980355936345681743241125150760694794510965960940252288" +
+	"79710893145669136867228748940560101503308617928680920874760917824938589009714909675985261365549781893129784821" +
+	"68299894872265880485756401427047755513237964145152374623436454285844479526586782105114135473573952311342716610" +
+	"21359695362314429524849371871101457654035902799344037420073105785390621983874478084784896833214457138687519435" +
+	"06430218453191048481005370614680674919278191197939952061419663428754440643745123718192179998391015919561814675" +
+	"14269123974894090718649423196156794520809514655022523160388193014209376213785595663893778708303906979207734672" +
+	"21825625996615014215030680384477345492026054146659252014974428507325186660021324340881907104863317346496514539" +
+	"05796268561005508106658796998163574736384052571459102897064140110971206280439039759515677157700420337869936007" +
+	"23055876317635942187312514712053292819182618612586732157919841484882916447060957527069572209175671167229109816" +
+	"90915280173506712748583222871835209353965725121083579151369882091444210067510334671103141267111369908658516398" +
+	"31501970165151168517143765761835155650884909989859982387345528331635507647918535893226185489632132933089857064" +
+	"20467525907091548141654985946163718027098199430992448895757128289059232332609729971208443357326548938239119325" +
+	"97463667305836041428138830320382490375898524374417029132765618093773444030707469211201913020330380197621101100" +
+	"44929321516084244485963766983895228684783123552658213144957685726243344189303968642624341077322697802807318915" +
+	"44110104468232527162010526522721116603966655730925471105578537634668206531098965269186205647693125705863566201" +
+	"85581007293606598764861179104533488503461136576867532494416680396265797877185560845529654126654085306143444318" +
+	"58676975145661406800700237877659134401712749470420562230538994561314071127000407854733269939081454664645880797" +
+	"27082668306343285878569830523580893306575740679545716377525420211495576158140025012622859413021647155097925923" +
+	"09907965473761255176567513575178296664547791745011299614890304639947132962107340437518957359614589019389713111" +
+	"79042978285647503203198691514028708085990480109412147221317947647772622414254854540332157185306142288137585043" +
+	"06332175182979866223717215916077166925474873898665494945011465406284336639379003976926567214638530673609657120" +
+	"91807638327166416274888800786925602902284721040317211860820419000422966171196377921337575114959501566049631862" +
+	"94726547364252308177036751590673502350728354056704038674351362222477158915049530984448933309634087807693259939" +
+	"78054193414473774418426312986080998886874132604721569516239658645730216315981931951673538129741677294786724229" +
+	"24654366800980676928238280689964004824354037014163149658979409243237896907069779422362508221688957383798623001" +
+	"59377647165122893578601588161755782973523344604281512627203734314653197777416031990665541876397929334419521541" +
+	"34189948544473456738316249934191318148092777710386387734317720754565453220777092120190516609628049092636019759" +
+	"88281613323166636528619326686336062735676303544776280350450777235547105859548702790814356240145171806246436267" +
+	"94561275318134078330336254232783944975382437205835311477119926063813346776879695970309833913077109870408591337"
+
+// Test case for BenchmarkScanPi.
+func TestScanPi(t *testing.T) {
+	var x nat
+	z, _, _, err := x.scan(strings.NewReader(pi), 10, false)
+	if err != nil {
+		t.Errorf("scanning pi: %s", err)
+	}
+	if s := z.decimalString(); s != pi {
+		t.Errorf("scanning pi: got %s", s)
+	}
+}
+
+func TestScanPiParallel(t *testing.T) {
+	const n = 2
+	c := make(chan int)
+	for i := 0; i < n; i++ {
+		go func() {
+			TestScanPi(t)
+			c <- 0
+		}()
+	}
+	for i := 0; i < n; i++ {
+		<-c
+	}
+}
+
+func BenchmarkScanPi(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		var x nat
+		x.scan(strings.NewReader(pi), 10, false)
+	}
+}
+
+func BenchmarkStringPiParallel(b *testing.B) {
+	var x nat
+	x, _, _, _ = x.scan(strings.NewReader(pi), 0, false)
+	if x.decimalString() != pi {
+		panic("benchmark incorrect: conversion failed")
+	}
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			x.decimalString()
+		}
+	})
+}
+
+func BenchmarkScan10Base2(b *testing.B)     { ScanHelper(b, 2, 10, 10) }
+func BenchmarkScan100Base2(b *testing.B)    { ScanHelper(b, 2, 10, 100) }
+func BenchmarkScan1000Base2(b *testing.B)   { ScanHelper(b, 2, 10, 1000) }
+func BenchmarkScan10000Base2(b *testing.B)  { ScanHelper(b, 2, 10, 10000) }
+func BenchmarkScan100000Base2(b *testing.B) { ScanHelper(b, 2, 10, 100000) }
+
+func BenchmarkScan10Base8(b *testing.B)     { ScanHelper(b, 8, 10, 10) }
+func BenchmarkScan100Base8(b *testing.B)    { ScanHelper(b, 8, 10, 100) }
+func BenchmarkScan1000Base8(b *testing.B)   { ScanHelper(b, 8, 10, 1000) }
+func BenchmarkScan10000Base8(b *testing.B)  { ScanHelper(b, 8, 10, 10000) }
+func BenchmarkScan100000Base8(b *testing.B) { ScanHelper(b, 8, 10, 100000) }
+
+func BenchmarkScan10Base10(b *testing.B)     { ScanHelper(b, 10, 10, 10) }
+func BenchmarkScan100Base10(b *testing.B)    { ScanHelper(b, 10, 10, 100) }
+func BenchmarkScan1000Base10(b *testing.B)   { ScanHelper(b, 10, 10, 1000) }
+func BenchmarkScan10000Base10(b *testing.B)  { ScanHelper(b, 10, 10, 10000) }
+func BenchmarkScan100000Base10(b *testing.B) { ScanHelper(b, 10, 10, 100000) }
+
+func BenchmarkScan10Base16(b *testing.B)     { ScanHelper(b, 16, 10, 10) }
+func BenchmarkScan100Base16(b *testing.B)    { ScanHelper(b, 16, 10, 100) }
+func BenchmarkScan1000Base16(b *testing.B)   { ScanHelper(b, 16, 10, 1000) }
+func BenchmarkScan10000Base16(b *testing.B)  { ScanHelper(b, 16, 10, 10000) }
+func BenchmarkScan100000Base16(b *testing.B) { ScanHelper(b, 16, 10, 100000) }
+
+func ScanHelper(b *testing.B, base int, x, y Word) {
+	b.StopTimer()
+	var z nat
+	z = z.expWW(x, y)
+
+	var s string
+	s = z.string(lowercaseDigits[:base])
+	if t := toString(z, lowercaseDigits[:base]); t != s {
+		b.Fatalf("scanning: got %s; want %s", s, t)
+	}
+	b.StartTimer()
+
+	for i := 0; i < b.N; i++ {
+		z.scan(strings.NewReader(s), base, false)
+	}
+}
+
+func BenchmarkString10Base2(b *testing.B)     { StringHelper(b, 2, 10, 10) }
+func BenchmarkString100Base2(b *testing.B)    { StringHelper(b, 2, 10, 100) }
+func BenchmarkString1000Base2(b *testing.B)   { StringHelper(b, 2, 10, 1000) }
+func BenchmarkString10000Base2(b *testing.B)  { StringHelper(b, 2, 10, 10000) }
+func BenchmarkString100000Base2(b *testing.B) { StringHelper(b, 2, 10, 100000) }
+
+func BenchmarkString10Base8(b *testing.B)     { StringHelper(b, 8, 10, 10) }
+func BenchmarkString100Base8(b *testing.B)    { StringHelper(b, 8, 10, 100) }
+func BenchmarkString1000Base8(b *testing.B)   { StringHelper(b, 8, 10, 1000) }
+func BenchmarkString10000Base8(b *testing.B)  { StringHelper(b, 8, 10, 10000) }
+func BenchmarkString100000Base8(b *testing.B) { StringHelper(b, 8, 10, 100000) }
+
+func BenchmarkString10Base10(b *testing.B)     { StringHelper(b, 10, 10, 10) }
+func BenchmarkString100Base10(b *testing.B)    { StringHelper(b, 10, 10, 100) }
+func BenchmarkString1000Base10(b *testing.B)   { StringHelper(b, 10, 10, 1000) }
+func BenchmarkString10000Base10(b *testing.B)  { StringHelper(b, 10, 10, 10000) }
+func BenchmarkString100000Base10(b *testing.B) { StringHelper(b, 10, 10, 100000) }
+
+func BenchmarkString10Base16(b *testing.B)     { StringHelper(b, 16, 10, 10) }
+func BenchmarkString100Base16(b *testing.B)    { StringHelper(b, 16, 10, 100) }
+func BenchmarkString1000Base16(b *testing.B)   { StringHelper(b, 16, 10, 1000) }
+func BenchmarkString10000Base16(b *testing.B)  { StringHelper(b, 16, 10, 10000) }
+func BenchmarkString100000Base16(b *testing.B) { StringHelper(b, 16, 10, 100000) }
+
+func StringHelper(b *testing.B, base int, x, y Word) {
+	b.StopTimer()
+	var z nat
+	z = z.expWW(x, y)
+	z.string(lowercaseDigits[:base]) // warm divisor cache
+	b.StartTimer()
+
+	for i := 0; i < b.N; i++ {
+		_ = z.string(lowercaseDigits[:base])
+	}
+}
+
+func BenchmarkLeafSize0(b *testing.B)  { LeafSizeHelper(b, 10, 0) } // test without splitting
+func BenchmarkLeafSize1(b *testing.B)  { LeafSizeHelper(b, 10, 1) }
+func BenchmarkLeafSize2(b *testing.B)  { LeafSizeHelper(b, 10, 2) }
+func BenchmarkLeafSize3(b *testing.B)  { LeafSizeHelper(b, 10, 3) }
+func BenchmarkLeafSize4(b *testing.B)  { LeafSizeHelper(b, 10, 4) }
+func BenchmarkLeafSize5(b *testing.B)  { LeafSizeHelper(b, 10, 5) }
+func BenchmarkLeafSize6(b *testing.B)  { LeafSizeHelper(b, 10, 6) }
+func BenchmarkLeafSize7(b *testing.B)  { LeafSizeHelper(b, 10, 7) }
+func BenchmarkLeafSize8(b *testing.B)  { LeafSizeHelper(b, 10, 8) }
+func BenchmarkLeafSize9(b *testing.B)  { LeafSizeHelper(b, 10, 9) }
+func BenchmarkLeafSize10(b *testing.B) { LeafSizeHelper(b, 10, 10) }
+func BenchmarkLeafSize11(b *testing.B) { LeafSizeHelper(b, 10, 11) }
+func BenchmarkLeafSize12(b *testing.B) { LeafSizeHelper(b, 10, 12) }
+func BenchmarkLeafSize13(b *testing.B) { LeafSizeHelper(b, 10, 13) }
+func BenchmarkLeafSize14(b *testing.B) { LeafSizeHelper(b, 10, 14) }
+func BenchmarkLeafSize15(b *testing.B) { LeafSizeHelper(b, 10, 15) }
+func BenchmarkLeafSize16(b *testing.B) { LeafSizeHelper(b, 10, 16) }
+func BenchmarkLeafSize32(b *testing.B) { LeafSizeHelper(b, 10, 32) } // try some large lengths
+func BenchmarkLeafSize64(b *testing.B) { LeafSizeHelper(b, 10, 64) }
+
+func LeafSizeHelper(b *testing.B, base Word, size int) {
+	b.StopTimer()
+	originalLeafSize := leafSize
+	resetTable(cacheBase10.table[:])
+	leafSize = size
+	b.StartTimer()
+
+	for d := 1; d <= 10000; d *= 10 {
+		b.StopTimer()
+		var z nat
+		z = z.expWW(base, Word(d))           // build target number
+		_ = z.string(lowercaseDigits[:base]) // warm divisor cache
+		b.StartTimer()
+
+		for i := 0; i < b.N; i++ {
+			_ = z.string(lowercaseDigits[:base])
+		}
+	}
+
+	b.StopTimer()
+	resetTable(cacheBase10.table[:])
+	leafSize = originalLeafSize
+	b.StartTimer()
+}
+
+func resetTable(table []divisor) {
+	if table != nil && table[0].bbb != nil {
+		for i := 0; i < len(table); i++ {
+			table[i].bbb = nil
+			table[i].nbits = 0
+			table[i].ndigits = 0
+		}
+	}
+}
+
+func TestStringPowers(t *testing.T) {
+	var b, p Word
+	for b = 2; b <= 16; b++ {
+		for p = 0; p <= 512; p++ {
+			x := nat(nil).expWW(b, p)
+			xs := x.string(lowercaseDigits[:b])
+			xs2 := toString(x, lowercaseDigits[:b])
+			if xs != xs2 {
+				t.Errorf("failed at %d ** %d in base %d: %s != %s", b, p, b, xs, xs2)
+			}
+		}
+		if b >= 3 && testing.Short() {
+			break
+		}
+	}
+}
diff --git a/src/cmd/compile/internal/big/rat.go b/src/cmd/compile/internal/big/rat.go
new file mode 100644
index 0000000..fb16f18
--- /dev/null
+++ b/src/cmd/compile/internal/big/rat.go
@@ -0,0 +1,570 @@
+// Copyright 2010 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 multi-precision rational numbers.
+
+package big
+
+import (
+	"encoding/binary"
+	"errors"
+	"fmt"
+	"math"
+)
+
+// A Rat represents a quotient a/b of arbitrary precision.
+// The zero value for a Rat represents the value 0.
+type Rat struct {
+	// To make zero values for Rat work w/o initialization,
+	// a zero value of b (len(b) == 0) acts like b == 1.
+	// a.neg determines the sign of the Rat, b.neg is ignored.
+	a, b Int
+}
+
+// NewRat creates a new Rat with numerator a and denominator b.
+func NewRat(a, b int64) *Rat {
+	return new(Rat).SetFrac64(a, b)
+}
+
+// SetFloat64 sets z to exactly f and returns z.
+// If f is not finite, SetFloat returns nil.
+func (z *Rat) SetFloat64(f float64) *Rat {
+	const expMask = 1<<11 - 1
+	bits := math.Float64bits(f)
+	mantissa := bits & (1<<52 - 1)
+	exp := int((bits >> 52) & expMask)
+	switch exp {
+	case expMask: // non-finite
+		return nil
+	case 0: // denormal
+		exp -= 1022
+	default: // normal
+		mantissa |= 1 << 52
+		exp -= 1023
+	}
+
+	shift := 52 - exp
+
+	// Optimization (?): partially pre-normalise.
+	for mantissa&1 == 0 && shift > 0 {
+		mantissa >>= 1
+		shift--
+	}
+
+	z.a.SetUint64(mantissa)
+	z.a.neg = f < 0
+	z.b.Set(intOne)
+	if shift > 0 {
+		z.b.Lsh(&z.b, uint(shift))
+	} else {
+		z.a.Lsh(&z.a, uint(-shift))
+	}
+	return z.norm()
+}
+
+// quotToFloat32 returns the non-negative float32 value
+// nearest to the quotient a/b, using round-to-even in
+// halfway cases.  It does not mutate its arguments.
+// Preconditions: b is non-zero; a and b have no common factors.
+func quotToFloat32(a, b nat) (f float32, exact bool) {
+	const (
+		// float size in bits
+		Fsize = 32
+
+		// mantissa
+		Msize  = 23
+		Msize1 = Msize + 1 // incl. implicit 1
+		Msize2 = Msize1 + 1
+
+		// exponent
+		Esize = Fsize - Msize1
+		Ebias = 1<<(Esize-1) - 1
+		Emin  = 1 - Ebias
+		Emax  = Ebias
+	)
+
+	// TODO(adonovan): specialize common degenerate cases: 1.0, integers.
+	alen := a.bitLen()
+	if alen == 0 {
+		return 0, true
+	}
+	blen := b.bitLen()
+	if blen == 0 {
+		panic("division by zero")
+	}
+
+	// 1. Left-shift A or B such that quotient A/B is in [1<<Msize1, 1<<(Msize2+1)
+	// (Msize2 bits if A < B when they are left-aligned, Msize2+1 bits if A >= B).
+	// This is 2 or 3 more than the float32 mantissa field width of Msize:
+	// - the optional extra bit is shifted away in step 3 below.
+	// - the high-order 1 is omitted in "normal" representation;
+	// - the low-order 1 will be used during rounding then discarded.
+	exp := alen - blen
+	var a2, b2 nat
+	a2 = a2.set(a)
+	b2 = b2.set(b)
+	if shift := Msize2 - exp; shift > 0 {
+		a2 = a2.shl(a2, uint(shift))
+	} else if shift < 0 {
+		b2 = b2.shl(b2, uint(-shift))
+	}
+
+	// 2. Compute quotient and remainder (q, r).  NB: due to the
+	// extra shift, the low-order bit of q is logically the
+	// high-order bit of r.
+	var q nat
+	q, r := q.div(a2, a2, b2) // (recycle a2)
+	mantissa := low32(q)
+	haveRem := len(r) > 0 // mantissa&1 && !haveRem => remainder is exactly half
+
+	// 3. If quotient didn't fit in Msize2 bits, redo division by b2<<1
+	// (in effect---we accomplish this incrementally).
+	if mantissa>>Msize2 == 1 {
+		if mantissa&1 == 1 {
+			haveRem = true
+		}
+		mantissa >>= 1
+		exp++
+	}
+	if mantissa>>Msize1 != 1 {
+		panic(fmt.Sprintf("expected exactly %d bits of result", Msize2))
+	}
+
+	// 4. Rounding.
+	if Emin-Msize <= exp && exp <= Emin {
+		// Denormal case; lose 'shift' bits of precision.
+		shift := uint(Emin - (exp - 1)) // [1..Esize1)
+		lostbits := mantissa & (1<<shift - 1)
+		haveRem = haveRem || lostbits != 0
+		mantissa >>= shift
+		exp = 2 - Ebias // == exp + shift
+	}
+	// Round q using round-half-to-even.
+	exact = !haveRem
+	if mantissa&1 != 0 {
+		exact = false
+		if haveRem || mantissa&2 != 0 {
+			if mantissa++; mantissa >= 1<<Msize2 {
+				// Complete rollover 11...1 => 100...0, so shift is safe
+				mantissa >>= 1
+				exp++
+			}
+		}
+	}
+	mantissa >>= 1 // discard rounding bit.  Mantissa now scaled by 1<<Msize1.
+
+	f = float32(math.Ldexp(float64(mantissa), exp-Msize1))
+	if math.IsInf(float64(f), 0) {
+		exact = false
+	}
+	return
+}
+
+// quotToFloat64 returns the non-negative float64 value
+// nearest to the quotient a/b, using round-to-even in
+// halfway cases.  It does not mutate its arguments.
+// Preconditions: b is non-zero; a and b have no common factors.
+func quotToFloat64(a, b nat) (f float64, exact bool) {
+	const (
+		// float size in bits
+		Fsize = 64
+
+		// mantissa
+		Msize  = 52
+		Msize1 = Msize + 1 // incl. implicit 1
+		Msize2 = Msize1 + 1
+
+		// exponent
+		Esize = Fsize - Msize1
+		Ebias = 1<<(Esize-1) - 1
+		Emin  = 1 - Ebias
+		Emax  = Ebias
+	)
+
+	// TODO(adonovan): specialize common degenerate cases: 1.0, integers.
+	alen := a.bitLen()
+	if alen == 0 {
+		return 0, true
+	}
+	blen := b.bitLen()
+	if blen == 0 {
+		panic("division by zero")
+	}
+
+	// 1. Left-shift A or B such that quotient A/B is in [1<<Msize1, 1<<(Msize2+1)
+	// (Msize2 bits if A < B when they are left-aligned, Msize2+1 bits if A >= B).
+	// This is 2 or 3 more than the float64 mantissa field width of Msize:
+	// - the optional extra bit is shifted away in step 3 below.
+	// - the high-order 1 is omitted in "normal" representation;
+	// - the low-order 1 will be used during rounding then discarded.
+	exp := alen - blen
+	var a2, b2 nat
+	a2 = a2.set(a)
+	b2 = b2.set(b)
+	if shift := Msize2 - exp; shift > 0 {
+		a2 = a2.shl(a2, uint(shift))
+	} else if shift < 0 {
+		b2 = b2.shl(b2, uint(-shift))
+	}
+
+	// 2. Compute quotient and remainder (q, r).  NB: due to the
+	// extra shift, the low-order bit of q is logically the
+	// high-order bit of r.
+	var q nat
+	q, r := q.div(a2, a2, b2) // (recycle a2)
+	mantissa := low64(q)
+	haveRem := len(r) > 0 // mantissa&1 && !haveRem => remainder is exactly half
+
+	// 3. If quotient didn't fit in Msize2 bits, redo division by b2<<1
+	// (in effect---we accomplish this incrementally).
+	if mantissa>>Msize2 == 1 {
+		if mantissa&1 == 1 {
+			haveRem = true
+		}
+		mantissa >>= 1
+		exp++
+	}
+	if mantissa>>Msize1 != 1 {
+		panic(fmt.Sprintf("expected exactly %d bits of result", Msize2))
+	}
+
+	// 4. Rounding.
+	if Emin-Msize <= exp && exp <= Emin {
+		// Denormal case; lose 'shift' bits of precision.
+		shift := uint(Emin - (exp - 1)) // [1..Esize1)
+		lostbits := mantissa & (1<<shift - 1)
+		haveRem = haveRem || lostbits != 0
+		mantissa >>= shift
+		exp = 2 - Ebias // == exp + shift
+	}
+	// Round q using round-half-to-even.
+	exact = !haveRem
+	if mantissa&1 != 0 {
+		exact = false
+		if haveRem || mantissa&2 != 0 {
+			if mantissa++; mantissa >= 1<<Msize2 {
+				// Complete rollover 11...1 => 100...0, so shift is safe
+				mantissa >>= 1
+				exp++
+			}
+		}
+	}
+	mantissa >>= 1 // discard rounding bit.  Mantissa now scaled by 1<<Msize1.
+
+	f = math.Ldexp(float64(mantissa), exp-Msize1)
+	if math.IsInf(f, 0) {
+		exact = false
+	}
+	return
+}
+
+// Float32 returns the nearest float32 value for x and a bool indicating
+// whether f represents x exactly. If the magnitude of x is too large to
+// be represented by a float32, f is an infinity and exact is false.
+// The sign of f always matches the sign of x, even if f == 0.
+func (x *Rat) Float32() (f float32, exact bool) {
+	b := x.b.abs
+	if len(b) == 0 {
+		b = b.set(natOne) // materialize denominator
+	}
+	f, exact = quotToFloat32(x.a.abs, b)
+	if x.a.neg {
+		f = -f
+	}
+	return
+}
+
+// Float64 returns the nearest float64 value for x and a bool indicating
+// whether f represents x exactly. If the magnitude of x is too large to
+// be represented by a float64, f is an infinity and exact is false.
+// The sign of f always matches the sign of x, even if f == 0.
+func (x *Rat) Float64() (f float64, exact bool) {
+	b := x.b.abs
+	if len(b) == 0 {
+		b = b.set(natOne) // materialize denominator
+	}
+	f, exact = quotToFloat64(x.a.abs, b)
+	if x.a.neg {
+		f = -f
+	}
+	return
+}
+
+// SetFrac sets z to a/b and returns z.
+func (z *Rat) SetFrac(a, b *Int) *Rat {
+	z.a.neg = a.neg != b.neg
+	babs := b.abs
+	if len(babs) == 0 {
+		panic("division by zero")
+	}
+	if &z.a == b || alias(z.a.abs, babs) {
+		babs = nat(nil).set(babs) // make a copy
+	}
+	z.a.abs = z.a.abs.set(a.abs)
+	z.b.abs = z.b.abs.set(babs)
+	return z.norm()
+}
+
+// SetFrac64 sets z to a/b and returns z.
+func (z *Rat) SetFrac64(a, b int64) *Rat {
+	z.a.SetInt64(a)
+	if b == 0 {
+		panic("division by zero")
+	}
+	if b < 0 {
+		b = -b
+		z.a.neg = !z.a.neg
+	}
+	z.b.abs = z.b.abs.setUint64(uint64(b))
+	return z.norm()
+}
+
+// SetInt sets z to x (by making a copy of x) and returns z.
+func (z *Rat) SetInt(x *Int) *Rat {
+	z.a.Set(x)
+	z.b.abs = z.b.abs[:0]
+	return z
+}
+
+// SetInt64 sets z to x and returns z.
+func (z *Rat) SetInt64(x int64) *Rat {
+	z.a.SetInt64(x)
+	z.b.abs = z.b.abs[:0]
+	return z
+}
+
+// Set sets z to x (by making a copy of x) and returns z.
+func (z *Rat) Set(x *Rat) *Rat {
+	if z != x {
+		z.a.Set(&x.a)
+		z.b.Set(&x.b)
+	}
+	return z
+}
+
+// Abs sets z to |x| (the absolute value of x) and returns z.
+func (z *Rat) Abs(x *Rat) *Rat {
+	z.Set(x)
+	z.a.neg = false
+	return z
+}
+
+// Neg sets z to -x and returns z.
+func (z *Rat) Neg(x *Rat) *Rat {
+	z.Set(x)
+	z.a.neg = len(z.a.abs) > 0 && !z.a.neg // 0 has no sign
+	return z
+}
+
+// Inv sets z to 1/x and returns z.
+func (z *Rat) Inv(x *Rat) *Rat {
+	if len(x.a.abs) == 0 {
+		panic("division by zero")
+	}
+	z.Set(x)
+	a := z.b.abs
+	if len(a) == 0 {
+		a = a.set(natOne) // materialize numerator
+	}
+	b := z.a.abs
+	if b.cmp(natOne) == 0 {
+		b = b[:0] // normalize denominator
+	}
+	z.a.abs, z.b.abs = a, b // sign doesn't change
+	return z
+}
+
+// Sign returns:
+//
+//	-1 if x <  0
+//	 0 if x == 0
+//	+1 if x >  0
+//
+func (x *Rat) Sign() int {
+	return x.a.Sign()
+}
+
+// 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
+}
+
+// Num returns the numerator of x; it may be <= 0.
+// The result is a reference to x's numerator; it
+// may change if a new value is assigned to x, and vice versa.
+// The sign of the numerator corresponds to the sign of x.
+func (x *Rat) Num() *Int {
+	return &x.a
+}
+
+// Denom returns the denominator of x; it is always > 0.
+// The result is a reference to x's denominator; it
+// may change if a new value is assigned to x, and vice versa.
+func (x *Rat) Denom() *Int {
+	x.b.neg = false // the result is always >= 0
+	if len(x.b.abs) == 0 {
+		x.b.abs = x.b.abs.set(natOne) // materialize denominator
+	}
+	return &x.b
+}
+
+func (z *Rat) norm() *Rat {
+	switch {
+	case len(z.a.abs) == 0:
+		// z == 0 - normalize sign and denominator
+		z.a.neg = false
+		z.b.abs = z.b.abs[:0]
+	case len(z.b.abs) == 0:
+		// z is normalized int - nothing to do
+	case z.b.abs.cmp(natOne) == 0:
+		// z is int - normalize denominator
+		z.b.abs = z.b.abs[:0]
+	default:
+		neg := z.a.neg
+		z.a.neg = false
+		z.b.neg = false
+		if f := NewInt(0).binaryGCD(&z.a, &z.b); f.Cmp(intOne) != 0 {
+			z.a.abs, _ = z.a.abs.div(nil, z.a.abs, f.abs)
+			z.b.abs, _ = z.b.abs.div(nil, z.b.abs, f.abs)
+			if z.b.abs.cmp(natOne) == 0 {
+				// z is int - normalize denominator
+				z.b.abs = z.b.abs[:0]
+			}
+		}
+		z.a.neg = neg
+	}
+	return z
+}
+
+// mulDenom sets z to the denominator product x*y (by taking into
+// account that 0 values for x or y must be interpreted as 1) and
+// returns z.
+func mulDenom(z, x, y nat) nat {
+	switch {
+	case len(x) == 0:
+		return z.set(y)
+	case len(y) == 0:
+		return z.set(x)
+	}
+	return z.mul(x, y)
+}
+
+// scaleDenom computes x*f.
+// If f == 0 (zero value of denominator), the result is (a copy of) x.
+func scaleDenom(x *Int, f nat) *Int {
+	var z Int
+	if len(f) == 0 {
+		return z.Set(x)
+	}
+	z.abs = z.abs.mul(x.abs, f)
+	z.neg = x.neg
+	return &z
+}
+
+// Cmp compares x and y and returns:
+//
+//   -1 if x <  y
+//    0 if x == y
+//   +1 if x >  y
+//
+func (x *Rat) Cmp(y *Rat) int {
+	return scaleDenom(&x.a, y.b.abs).Cmp(scaleDenom(&y.a, x.b.abs))
+}
+
+// Add sets z to the sum x+y and returns z.
+func (z *Rat) Add(x, y *Rat) *Rat {
+	a1 := scaleDenom(&x.a, y.b.abs)
+	a2 := scaleDenom(&y.a, x.b.abs)
+	z.a.Add(a1, a2)
+	z.b.abs = mulDenom(z.b.abs, x.b.abs, y.b.abs)
+	return z.norm()
+}
+
+// Sub sets z to the difference x-y and returns z.
+func (z *Rat) Sub(x, y *Rat) *Rat {
+	a1 := scaleDenom(&x.a, y.b.abs)
+	a2 := scaleDenom(&y.a, x.b.abs)
+	z.a.Sub(a1, a2)
+	z.b.abs = mulDenom(z.b.abs, x.b.abs, y.b.abs)
+	return z.norm()
+}
+
+// Mul sets z to the product x*y and returns z.
+func (z *Rat) Mul(x, y *Rat) *Rat {
+	z.a.Mul(&x.a, &y.a)
+	z.b.abs = mulDenom(z.b.abs, x.b.abs, y.b.abs)
+	return z.norm()
+}
+
+// Quo sets z to the quotient x/y and returns z.
+// If y == 0, a division-by-zero run-time panic occurs.
+func (z *Rat) Quo(x, y *Rat) *Rat {
+	if len(y.a.abs) == 0 {
+		panic("division by zero")
+	}
+	a := scaleDenom(&x.a, y.b.abs)
+	b := scaleDenom(&y.a, x.b.abs)
+	z.a.abs = a.abs
+	z.b.abs = b.abs
+	z.a.neg = a.neg != b.neg
+	return z.norm()
+}
+
+// Gob codec version. Permits backward-compatible changes to the encoding.
+const ratGobVersion byte = 1
+
+// GobEncode implements the gob.GobEncoder interface.
+func (x *Rat) GobEncode() ([]byte, error) {
+	if x == nil {
+		return nil, nil
+	}
+	buf := make([]byte, 1+4+(len(x.a.abs)+len(x.b.abs))*_S) // extra bytes for version and sign bit (1), and numerator length (4)
+	i := x.b.abs.bytes(buf)
+	j := x.a.abs.bytes(buf[:i])
+	n := i - j
+	if int(uint32(n)) != n {
+		// this should never happen
+		return nil, errors.New("Rat.GobEncode: numerator too large")
+	}
+	binary.BigEndian.PutUint32(buf[j-4:j], uint32(n))
+	j -= 1 + 4
+	b := ratGobVersion << 1 // make space for sign bit
+	if x.a.neg {
+		b |= 1
+	}
+	buf[j] = b
+	return buf[j:], nil
+}
+
+// GobDecode implements the gob.GobDecoder interface.
+func (z *Rat) GobDecode(buf []byte) error {
+	if len(buf) == 0 {
+		// Other side sent a nil or default value.
+		*z = Rat{}
+		return nil
+	}
+	b := buf[0]
+	if b>>1 != ratGobVersion {
+		return fmt.Errorf("Rat.GobDecode: encoding version %d not supported", b>>1)
+	}
+	const j = 1 + 4
+	i := j + binary.BigEndian.Uint32(buf[j-4:j])
+	z.a.neg = b&1 != 0
+	z.a.abs = z.a.abs.setBytes(buf[j:i])
+	z.b.abs = z.b.abs.setBytes(buf[i:])
+	return nil
+}
+
+// MarshalText implements the encoding.TextMarshaler interface.
+func (r *Rat) MarshalText() (text []byte, err error) {
+	return []byte(r.RatString()), nil
+}
+
+// UnmarshalText implements the encoding.TextUnmarshaler interface.
+func (r *Rat) UnmarshalText(text []byte) error {
+	if _, ok := r.SetString(string(text)); !ok {
+		return fmt.Errorf("math/big: cannot unmarshal %q into a *big.Rat", text)
+	}
+	return nil
+}
diff --git a/src/cmd/compile/internal/big/rat_test.go b/src/cmd/compile/internal/big/rat_test.go
new file mode 100644
index 0000000..012d0c4
--- /dev/null
+++ b/src/cmd/compile/internal/big/rat_test.go
@@ -0,0 +1,736 @@
+// Copyright 2010 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
+
+import (
+	"bytes"
+	"encoding/gob"
+	"encoding/json"
+	"encoding/xml"
+	"math"
+	"testing"
+)
+
+func TestZeroRat(t *testing.T) {
+	var x, y, z Rat
+	y.SetFrac64(0, 42)
+
+	if x.Cmp(&y) != 0 {
+		t.Errorf("x and y should be both equal and zero")
+	}
+
+	if s := x.String(); s != "0/1" {
+		t.Errorf("got x = %s, want 0/1", s)
+	}
+
+	if s := x.RatString(); s != "0" {
+		t.Errorf("got x = %s, want 0", s)
+	}
+
+	z.Add(&x, &y)
+	if s := z.RatString(); s != "0" {
+		t.Errorf("got x+y = %s, want 0", s)
+	}
+
+	z.Sub(&x, &y)
+	if s := z.RatString(); s != "0" {
+		t.Errorf("got x-y = %s, want 0", s)
+	}
+
+	z.Mul(&x, &y)
+	if s := z.RatString(); s != "0" {
+		t.Errorf("got x*y = %s, want 0", s)
+	}
+
+	// check for division by zero
+	defer func() {
+		if s := recover(); s == nil || s.(string) != "division by zero" {
+			panic(s)
+		}
+	}()
+	z.Quo(&x, &y)
+}
+
+func TestRatSign(t *testing.T) {
+	zero := NewRat(0, 1)
+	for _, a := range setStringTests {
+		x, ok := new(Rat).SetString(a.in)
+		if !ok {
+			continue
+		}
+		s := x.Sign()
+		e := x.Cmp(zero)
+		if s != e {
+			t.Errorf("got %d; want %d for z = %v", s, e, &x)
+		}
+	}
+}
+
+var ratCmpTests = []struct {
+	rat1, rat2 string
+	out        int
+}{
+	{"0", "0/1", 0},
+	{"1/1", "1", 0},
+	{"-1", "-2/2", 0},
+	{"1", "0", 1},
+	{"0/1", "1/1", -1},
+	{"-5/1434770811533343057144", "-5/1434770811533343057145", -1},
+	{"49832350382626108453/8964749413", "49832350382626108454/8964749413", -1},
+	{"-37414950961700930/7204075375675961", "37414950961700930/7204075375675961", -1},
+	{"37414950961700930/7204075375675961", "74829901923401860/14408150751351922", 0},
+}
+
+func TestRatCmp(t *testing.T) {
+	for i, test := range ratCmpTests {
+		x, _ := new(Rat).SetString(test.rat1)
+		y, _ := new(Rat).SetString(test.rat2)
+
+		out := x.Cmp(y)
+		if out != test.out {
+			t.Errorf("#%d got out = %v; want %v", i, out, test.out)
+		}
+	}
+}
+
+func TestIsInt(t *testing.T) {
+	one := NewInt(1)
+	for _, a := range setStringTests {
+		x, ok := new(Rat).SetString(a.in)
+		if !ok {
+			continue
+		}
+		i := x.IsInt()
+		e := x.Denom().Cmp(one) == 0
+		if i != e {
+			t.Errorf("got IsInt(%v) == %v; want %v", x, i, e)
+		}
+	}
+}
+
+func TestRatAbs(t *testing.T) {
+	zero := new(Rat)
+	for _, a := range setStringTests {
+		x, ok := new(Rat).SetString(a.in)
+		if !ok {
+			continue
+		}
+		e := new(Rat).Set(x)
+		if e.Cmp(zero) < 0 {
+			e.Sub(zero, e)
+		}
+		z := new(Rat).Abs(x)
+		if z.Cmp(e) != 0 {
+			t.Errorf("got Abs(%v) = %v; want %v", x, z, e)
+		}
+	}
+}
+
+func TestRatNeg(t *testing.T) {
+	zero := new(Rat)
+	for _, a := range setStringTests {
+		x, ok := new(Rat).SetString(a.in)
+		if !ok {
+			continue
+		}
+		e := new(Rat).Sub(zero, x)
+		z := new(Rat).Neg(x)
+		if z.Cmp(e) != 0 {
+			t.Errorf("got Neg(%v) = %v; want %v", x, z, e)
+		}
+	}
+}
+
+func TestRatInv(t *testing.T) {
+	zero := new(Rat)
+	for _, a := range setStringTests {
+		x, ok := new(Rat).SetString(a.in)
+		if !ok {
+			continue
+		}
+		if x.Cmp(zero) == 0 {
+			continue // avoid division by zero
+		}
+		e := new(Rat).SetFrac(x.Denom(), x.Num())
+		z := new(Rat).Inv(x)
+		if z.Cmp(e) != 0 {
+			t.Errorf("got Inv(%v) = %v; want %v", x, z, e)
+		}
+	}
+}
+
+type ratBinFun func(z, x, y *Rat) *Rat
+type ratBinArg struct {
+	x, y, z string
+}
+
+func testRatBin(t *testing.T, i int, name string, f ratBinFun, a ratBinArg) {
+	x, _ := new(Rat).SetString(a.x)
+	y, _ := new(Rat).SetString(a.y)
+	z, _ := new(Rat).SetString(a.z)
+	out := f(new(Rat), x, y)
+
+	if out.Cmp(z) != 0 {
+		t.Errorf("%s #%d got %s want %s", name, i, out, z)
+	}
+}
+
+var ratBinTests = []struct {
+	x, y      string
+	sum, prod string
+}{
+	{"0", "0", "0", "0"},
+	{"0", "1", "1", "0"},
+	{"-1", "0", "-1", "0"},
+	{"-1", "1", "0", "-1"},
+	{"1", "1", "2", "1"},
+	{"1/2", "1/2", "1", "1/4"},
+	{"1/4", "1/3", "7/12", "1/12"},
+	{"2/5", "-14/3", "-64/15", "-28/15"},
+	{"4707/49292519774798173060", "-3367/70976135186689855734", "84058377121001851123459/1749296273614329067191168098769082663020", "-1760941/388732505247628681598037355282018369560"},
+	{"-61204110018146728334/3", "-31052192278051565633/2", "-215564796870448153567/6", "950260896245257153059642991192710872711/3"},
+	{"-854857841473707320655/4237645934602118692642972629634714039", "-18/31750379913563777419", "-27/133467566250814981", "15387441146526731771790/134546868362786310073779084329032722548987800600710485341"},
+	{"618575745270541348005638912139/19198433543745179392300736", "-19948846211000086/637313996471", "27674141753240653/30123979153216", "-6169936206128396568797607742807090270137721977/6117715203873571641674006593837351328"},
+	{"-3/26206484091896184128", "5/2848423294177090248", "15310893822118706237/9330894968229805033368778458685147968", "-5/24882386581946146755650075889827061248"},
+	{"26946729/330400702820", "41563965/225583428284", "1238218672302860271/4658307703098666660055", "224002580204097/14906584649915733312176"},
+	{"-8259900599013409474/7", "-84829337473700364773/56707961321161574960", "-468402123685491748914621885145127724451/396955729248131024720", "350340947706464153265156004876107029701/198477864624065512360"},
+	{"575775209696864/1320203974639986246357", "29/712593081308", "410331716733912717985762465/940768218243776489278275419794956", "808/45524274987585732633"},
+	{"1786597389946320496771/2066653520653241", "6269770/1992362624741777", "3559549865190272133656109052308126637/4117523232840525481453983149257", "8967230/3296219033"},
+	{"-36459180403360509753/32150500941194292113930", "9381566963714/9633539", "301622077145533298008420642898530153/309723104686531919656937098270", "-3784609207827/3426986245"},
+}
+
+func TestRatBin(t *testing.T) {
+	for i, test := range ratBinTests {
+		arg := ratBinArg{test.x, test.y, test.sum}
+		testRatBin(t, i, "Add", (*Rat).Add, arg)
+
+		arg = ratBinArg{test.y, test.x, test.sum}
+		testRatBin(t, i, "Add symmetric", (*Rat).Add, arg)
+
+		arg = ratBinArg{test.sum, test.x, test.y}
+		testRatBin(t, i, "Sub", (*Rat).Sub, arg)
+
+		arg = ratBinArg{test.sum, test.y, test.x}
+		testRatBin(t, i, "Sub symmetric", (*Rat).Sub, arg)
+
+		arg = ratBinArg{test.x, test.y, test.prod}
+		testRatBin(t, i, "Mul", (*Rat).Mul, arg)
+
+		arg = ratBinArg{test.y, test.x, test.prod}
+		testRatBin(t, i, "Mul symmetric", (*Rat).Mul, arg)
+
+		if test.x != "0" {
+			arg = ratBinArg{test.prod, test.x, test.y}
+			testRatBin(t, i, "Quo", (*Rat).Quo, arg)
+		}
+
+		if test.y != "0" {
+			arg = ratBinArg{test.prod, test.y, test.x}
+			testRatBin(t, i, "Quo symmetric", (*Rat).Quo, arg)
+		}
+	}
+}
+
+func TestIssue820(t *testing.T) {
+	x := NewRat(3, 1)
+	y := NewRat(2, 1)
+	z := y.Quo(x, y)
+	q := NewRat(3, 2)
+	if z.Cmp(q) != 0 {
+		t.Errorf("got %s want %s", z, q)
+	}
+
+	y = NewRat(3, 1)
+	x = NewRat(2, 1)
+	z = y.Quo(x, y)
+	q = NewRat(2, 3)
+	if z.Cmp(q) != 0 {
+		t.Errorf("got %s want %s", z, q)
+	}
+
+	x = NewRat(3, 1)
+	z = x.Quo(x, x)
+	q = NewRat(3, 3)
+	if z.Cmp(q) != 0 {
+		t.Errorf("got %s want %s", z, q)
+	}
+}
+
+var setFrac64Tests = []struct {
+	a, b int64
+	out  string
+}{
+	{0, 1, "0"},
+	{0, -1, "0"},
+	{1, 1, "1"},
+	{-1, 1, "-1"},
+	{1, -1, "-1"},
+	{-1, -1, "1"},
+	{-9223372036854775808, -9223372036854775808, "1"},
+}
+
+func TestRatSetFrac64Rat(t *testing.T) {
+	for i, test := range setFrac64Tests {
+		x := new(Rat).SetFrac64(test.a, test.b)
+		if x.RatString() != test.out {
+			t.Errorf("#%d got %s want %s", i, x.RatString(), test.out)
+		}
+	}
+}
+
+func TestRatGobEncoding(t *testing.T) {
+	var medium bytes.Buffer
+	enc := gob.NewEncoder(&medium)
+	dec := gob.NewDecoder(&medium)
+	for _, test := range encodingTests {
+		medium.Reset() // empty buffer for each test case (in case of failures)
+		var tx Rat
+		tx.SetString(test + ".14159265")
+		if err := enc.Encode(&tx); err != nil {
+			t.Errorf("encoding of %s failed: %s", &tx, err)
+		}
+		var rx Rat
+		if err := dec.Decode(&rx); err != nil {
+			t.Errorf("decoding of %s failed: %s", &tx, err)
+		}
+		if rx.Cmp(&tx) != 0 {
+			t.Errorf("transmission of %s failed: got %s want %s", &tx, &rx, &tx)
+		}
+	}
+}
+
+// Sending a nil Rat pointer (inside a slice) on a round trip through gob should yield a zero.
+// TODO: top-level nils.
+func TestGobEncodingNilRatInSlice(t *testing.T) {
+	buf := new(bytes.Buffer)
+	enc := gob.NewEncoder(buf)
+	dec := gob.NewDecoder(buf)
+
+	var in = make([]*Rat, 1)
+	err := enc.Encode(&in)
+	if err != nil {
+		t.Errorf("gob encode failed: %q", err)
+	}
+	var out []*Rat
+	err = dec.Decode(&out)
+	if err != nil {
+		t.Fatalf("gob decode failed: %q", err)
+	}
+	if len(out) != 1 {
+		t.Fatalf("wrong len; want 1 got %d", len(out))
+	}
+	var zero Rat
+	if out[0].Cmp(&zero) != 0 {
+		t.Errorf("transmission of (*Int)(nill) failed: got %s want 0", out)
+	}
+}
+
+var ratNums = []string{
+	"-141592653589793238462643383279502884197169399375105820974944592307816406286",
+	"-1415926535897932384626433832795028841971",
+	"-141592653589793",
+	"-1",
+	"0",
+	"1",
+	"141592653589793",
+	"1415926535897932384626433832795028841971",
+	"141592653589793238462643383279502884197169399375105820974944592307816406286",
+}
+
+var ratDenoms = []string{
+	"1",
+	"718281828459045",
+	"7182818284590452353602874713526624977572",
+	"718281828459045235360287471352662497757247093699959574966967627724076630353",
+}
+
+func TestRatJSONEncoding(t *testing.T) {
+	for _, num := range ratNums {
+		for _, denom := range ratDenoms {
+			var tx Rat
+			tx.SetString(num + "/" + denom)
+			b, err := json.Marshal(&tx)
+			if err != nil {
+				t.Errorf("marshaling of %s failed: %s", &tx, err)
+				continue
+			}
+			var rx Rat
+			if err := json.Unmarshal(b, &rx); err != nil {
+				t.Errorf("unmarshaling of %s failed: %s", &tx, err)
+				continue
+			}
+			if rx.Cmp(&tx) != 0 {
+				t.Errorf("JSON encoding of %s failed: got %s want %s", &tx, &rx, &tx)
+			}
+		}
+	}
+}
+
+func TestRatXMLEncoding(t *testing.T) {
+	for _, num := range ratNums {
+		for _, denom := range ratDenoms {
+			var tx Rat
+			tx.SetString(num + "/" + denom)
+			b, err := xml.Marshal(&tx)
+			if err != nil {
+				t.Errorf("marshaling of %s failed: %s", &tx, err)
+				continue
+			}
+			var rx Rat
+			if err := xml.Unmarshal(b, &rx); err != nil {
+				t.Errorf("unmarshaling of %s failed: %s", &tx, err)
+				continue
+			}
+			if rx.Cmp(&tx) != 0 {
+				t.Errorf("XML encoding of %s failed: got %s want %s", &tx, &rx, &tx)
+			}
+		}
+	}
+}
+
+func TestIssue2379(t *testing.T) {
+	// 1) no aliasing
+	q := NewRat(3, 2)
+	x := new(Rat)
+	x.SetFrac(NewInt(3), NewInt(2))
+	if x.Cmp(q) != 0 {
+		t.Errorf("1) got %s want %s", x, q)
+	}
+
+	// 2) aliasing of numerator
+	x = NewRat(2, 3)
+	x.SetFrac(NewInt(3), x.Num())
+	if x.Cmp(q) != 0 {
+		t.Errorf("2) got %s want %s", x, q)
+	}
+
+	// 3) aliasing of denominator
+	x = NewRat(2, 3)
+	x.SetFrac(x.Denom(), NewInt(2))
+	if x.Cmp(q) != 0 {
+		t.Errorf("3) got %s want %s", x, q)
+	}
+
+	// 4) aliasing of numerator and denominator
+	x = NewRat(2, 3)
+	x.SetFrac(x.Denom(), x.Num())
+	if x.Cmp(q) != 0 {
+		t.Errorf("4) got %s want %s", x, q)
+	}
+
+	// 5) numerator and denominator are the same
+	q = NewRat(1, 1)
+	x = new(Rat)
+	n := NewInt(7)
+	x.SetFrac(n, n)
+	if x.Cmp(q) != 0 {
+		t.Errorf("5) got %s want %s", x, q)
+	}
+}
+
+func TestIssue3521(t *testing.T) {
+	a := new(Int)
+	b := new(Int)
+	a.SetString("64375784358435883458348587", 0)
+	b.SetString("4789759874531", 0)
+
+	// 0) a raw zero value has 1 as denominator
+	zero := new(Rat)
+	one := NewInt(1)
+	if zero.Denom().Cmp(one) != 0 {
+		t.Errorf("0) got %s want %s", zero.Denom(), one)
+	}
+
+	// 1a) a zero value remains zero independent of denominator
+	x := new(Rat)
+	x.Denom().Set(new(Int).Neg(b))
+	if x.Cmp(zero) != 0 {
+		t.Errorf("1a) got %s want %s", x, zero)
+	}
+
+	// 1b) a zero value may have a denominator != 0 and != 1
+	x.Num().Set(a)
+	qab := new(Rat).SetFrac(a, b)
+	if x.Cmp(qab) != 0 {
+		t.Errorf("1b) got %s want %s", x, qab)
+	}
+
+	// 2a) an integral value becomes a fraction depending on denominator
+	x.SetFrac64(10, 2)
+	x.Denom().SetInt64(3)
+	q53 := NewRat(5, 3)
+	if x.Cmp(q53) != 0 {
+		t.Errorf("2a) got %s want %s", x, q53)
+	}
+
+	// 2b) an integral value becomes a fraction depending on denominator
+	x = NewRat(10, 2)
+	x.Denom().SetInt64(3)
+	if x.Cmp(q53) != 0 {
+		t.Errorf("2b) got %s want %s", x, q53)
+	}
+
+	// 3) changing the numerator/denominator of a Rat changes the Rat
+	x.SetFrac(a, b)
+	a = x.Num()
+	b = x.Denom()
+	a.SetInt64(5)
+	b.SetInt64(3)
+	if x.Cmp(q53) != 0 {
+		t.Errorf("3) got %s want %s", x, q53)
+	}
+}
+
+func TestFloat32Distribution(t *testing.T) {
+	// Generate a distribution of (sign, mantissa, exp) values
+	// broader than the float32 range, and check Rat.Float32()
+	// always picks the closest float32 approximation.
+	var add = []int64{
+		0,
+		1,
+		3,
+		5,
+		7,
+		9,
+		11,
+	}
+	var winc, einc = uint64(1), 1 // soak test (~1.5s on x86-64)
+	if testing.Short() {
+		winc, einc = 5, 15 // quick test (~60ms on x86-64)
+	}
+
+	for _, sign := range "+-" {
+		for _, a := range add {
+			for wid := uint64(0); wid < 30; wid += winc {
+				b := 1<<wid + a
+				if sign == '-' {
+					b = -b
+				}
+				for exp := -150; exp < 150; exp += einc {
+					num, den := NewInt(b), NewInt(1)
+					if exp > 0 {
+						num.Lsh(num, uint(exp))
+					} else {
+						den.Lsh(den, uint(-exp))
+					}
+					r := new(Rat).SetFrac(num, den)
+					f, _ := r.Float32()
+
+					if !checkIsBestApprox32(t, f, r) {
+						// Append context information.
+						t.Errorf("(input was mantissa %#x, exp %d; f = %g (%b); f ~ %g; r = %v)",
+							b, exp, f, f, math.Ldexp(float64(b), exp), r)
+					}
+
+					checkNonLossyRoundtrip32(t, f)
+				}
+			}
+		}
+	}
+}
+
+func TestFloat64Distribution(t *testing.T) {
+	// Generate a distribution of (sign, mantissa, exp) values
+	// broader than the float64 range, and check Rat.Float64()
+	// always picks the closest float64 approximation.
+	var add = []int64{
+		0,
+		1,
+		3,
+		5,
+		7,
+		9,
+		11,
+	}
+	var winc, einc = uint64(1), 1 // soak test (~75s on x86-64)
+	if testing.Short() {
+		winc, einc = 10, 500 // quick test (~12ms on x86-64)
+	}
+
+	for _, sign := range "+-" {
+		for _, a := range add {
+			for wid := uint64(0); wid < 60; wid += winc {
+				b := 1<<wid + a
+				if sign == '-' {
+					b = -b
+				}
+				for exp := -1100; exp < 1100; exp += einc {
+					num, den := NewInt(b), NewInt(1)
+					if exp > 0 {
+						num.Lsh(num, uint(exp))
+					} else {
+						den.Lsh(den, uint(-exp))
+					}
+					r := new(Rat).SetFrac(num, den)
+					f, _ := r.Float64()
+
+					if !checkIsBestApprox64(t, f, r) {
+						// Append context information.
+						t.Errorf("(input was mantissa %#x, exp %d; f = %g (%b); f ~ %g; r = %v)",
+							b, exp, f, f, math.Ldexp(float64(b), exp), r)
+					}
+
+					checkNonLossyRoundtrip64(t, f)
+				}
+			}
+		}
+	}
+}
+
+// TestSetFloat64NonFinite checks that SetFloat64 of a non-finite value
+// returns nil.
+func TestSetFloat64NonFinite(t *testing.T) {
+	for _, f := range []float64{math.NaN(), math.Inf(+1), math.Inf(-1)} {
+		var r Rat
+		if r2 := r.SetFloat64(f); r2 != nil {
+			t.Errorf("SetFloat64(%g) was %v, want nil", f, r2)
+		}
+	}
+}
+
+// checkNonLossyRoundtrip32 checks that a float->Rat->float roundtrip is
+// non-lossy for finite f.
+func checkNonLossyRoundtrip32(t *testing.T, f float32) {
+	if !isFinite(float64(f)) {
+		return
+	}
+	r := new(Rat).SetFloat64(float64(f))
+	if r == nil {
+		t.Errorf("Rat.SetFloat64(float64(%g) (%b)) == nil", f, f)
+		return
+	}
+	f2, exact := r.Float32()
+	if f != f2 || !exact {
+		t.Errorf("Rat.SetFloat64(float64(%g)).Float32() = %g (%b), %v, want %g (%b), %v; delta = %b",
+			f, f2, f2, exact, f, f, true, f2-f)
+	}
+}
+
+// checkNonLossyRoundtrip64 checks that a float->Rat->float roundtrip is
+// non-lossy for finite f.
+func checkNonLossyRoundtrip64(t *testing.T, f float64) {
+	if !isFinite(f) {
+		return
+	}
+	r := new(Rat).SetFloat64(f)
+	if r == nil {
+		t.Errorf("Rat.SetFloat64(%g (%b)) == nil", f, f)
+		return
+	}
+	f2, exact := r.Float64()
+	if f != f2 || !exact {
+		t.Errorf("Rat.SetFloat64(%g).Float64() = %g (%b), %v, want %g (%b), %v; delta = %b",
+			f, f2, f2, exact, f, f, true, f2-f)
+	}
+}
+
+// delta returns the absolute difference between r and f.
+func delta(r *Rat, f float64) *Rat {
+	d := new(Rat).Sub(r, new(Rat).SetFloat64(f))
+	return d.Abs(d)
+}
+
+// checkIsBestApprox32 checks that f is the best possible float32
+// approximation of r.
+// Returns true on success.
+func checkIsBestApprox32(t *testing.T, f float32, r *Rat) bool {
+	if math.Abs(float64(f)) >= math.MaxFloat32 {
+		// Cannot check +Inf, -Inf, nor the float next to them (MaxFloat32).
+		// But we have tests for these special cases.
+		return true
+	}
+
+	// r must be strictly between f0 and f1, the floats bracketing f.
+	f0 := math.Nextafter32(f, float32(math.Inf(-1)))
+	f1 := math.Nextafter32(f, float32(math.Inf(+1)))
+
+	// For f to be correct, r must be closer to f than to f0 or f1.
+	df := delta(r, float64(f))
+	df0 := delta(r, float64(f0))
+	df1 := delta(r, float64(f1))
+	if df.Cmp(df0) > 0 {
+		t.Errorf("Rat(%v).Float32() = %g (%b), but previous float32 %g (%b) is closer", r, f, f, f0, f0)
+		return false
+	}
+	if df.Cmp(df1) > 0 {
+		t.Errorf("Rat(%v).Float32() = %g (%b), but next float32 %g (%b) is closer", r, f, f, f1, f1)
+		return false
+	}
+	if df.Cmp(df0) == 0 && !isEven32(f) {
+		t.Errorf("Rat(%v).Float32() = %g (%b); halfway should have rounded to %g (%b) instead", r, f, f, f0, f0)
+		return false
+	}
+	if df.Cmp(df1) == 0 && !isEven32(f) {
+		t.Errorf("Rat(%v).Float32() = %g (%b); halfway should have rounded to %g (%b) instead", r, f, f, f1, f1)
+		return false
+	}
+	return true
+}
+
+// checkIsBestApprox64 checks that f is the best possible float64
+// approximation of r.
+// Returns true on success.
+func checkIsBestApprox64(t *testing.T, f float64, r *Rat) bool {
+	if math.Abs(f) >= math.MaxFloat64 {
+		// Cannot check +Inf, -Inf, nor the float next to them (MaxFloat64).
+		// But we have tests for these special cases.
+		return true
+	}
+
+	// r must be strictly between f0 and f1, the floats bracketing f.
+	f0 := math.Nextafter(f, math.Inf(-1))
+	f1 := math.Nextafter(f, math.Inf(+1))
+
+	// For f to be correct, r must be closer to f than to f0 or f1.
+	df := delta(r, f)
+	df0 := delta(r, f0)
+	df1 := delta(r, f1)
+	if df.Cmp(df0) > 0 {
+		t.Errorf("Rat(%v).Float64() = %g (%b), but previous float64 %g (%b) is closer", r, f, f, f0, f0)
+		return false
+	}
+	if df.Cmp(df1) > 0 {
+		t.Errorf("Rat(%v).Float64() = %g (%b), but next float64 %g (%b) is closer", r, f, f, f1, f1)
+		return false
+	}
+	if df.Cmp(df0) == 0 && !isEven64(f) {
+		t.Errorf("Rat(%v).Float64() = %g (%b); halfway should have rounded to %g (%b) instead", r, f, f, f0, f0)
+		return false
+	}
+	if df.Cmp(df1) == 0 && !isEven64(f) {
+		t.Errorf("Rat(%v).Float64() = %g (%b); halfway should have rounded to %g (%b) instead", r, f, f, f1, f1)
+		return false
+	}
+	return true
+}
+
+func isEven32(f float32) bool { return math.Float32bits(f)&1 == 0 }
+func isEven64(f float64) bool { return math.Float64bits(f)&1 == 0 }
+
+func TestIsFinite(t *testing.T) {
+	finites := []float64{
+		1.0 / 3,
+		4891559871276714924261e+222,
+		math.MaxFloat64,
+		math.SmallestNonzeroFloat64,
+		-math.MaxFloat64,
+		-math.SmallestNonzeroFloat64,
+	}
+	for _, f := range finites {
+		if !isFinite(f) {
+			t.Errorf("!IsFinite(%g (%b))", f, f)
+		}
+	}
+	nonfinites := []float64{
+		math.NaN(),
+		math.Inf(-1),
+		math.Inf(+1),
+	}
+	for _, f := range nonfinites {
+		if isFinite(f) {
+			t.Errorf("IsFinite(%g, (%b))", f, f)
+		}
+	}
+}
diff --git a/src/cmd/compile/internal/big/ratconv.go b/src/cmd/compile/internal/big/ratconv.go
new file mode 100644
index 0000000..778077b
--- /dev/null
+++ b/src/cmd/compile/internal/big/ratconv.go
@@ -0,0 +1,251 @@
+// 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 rat-to-string conversion functions.
+
+package big
+
+import (
+	"errors"
+	"fmt"
+	"io"
+	"strconv"
+	"strings"
+)
+
+func ratTok(ch rune) bool {
+	return strings.IndexRune("+-/0123456789.eE", ch) >= 0
+}
+
+// Scan is a support routine for fmt.Scanner. It accepts the formats
+// 'e', 'E', 'f', 'F', 'g', 'G', and 'v'. All formats are equivalent.
+func (z *Rat) Scan(s fmt.ScanState, ch rune) error {
+	tok, err := s.Token(true, ratTok)
+	if err != nil {
+		return err
+	}
+	if strings.IndexRune("efgEFGv", ch) < 0 {
+		return errors.New("Rat.Scan: invalid verb")
+	}
+	if _, ok := z.SetString(string(tok)); !ok {
+		return errors.New("Rat.Scan: invalid syntax")
+	}
+	return nil
+}
+
+// SetString sets z to the value of s and returns z and a boolean indicating
+// success. s can be given as a fraction "a/b" or as a floating-point number
+// optionally followed by an exponent. If the operation failed, the value of
+// z is undefined but the returned value is nil.
+func (z *Rat) SetString(s string) (*Rat, bool) {
+	if len(s) == 0 {
+		return nil, false
+	}
+	// len(s) > 0
+
+	// parse fraction a/b, if any
+	if sep := strings.Index(s, "/"); sep >= 0 {
+		if _, ok := z.a.SetString(s[:sep], 0); !ok {
+			return nil, false
+		}
+		s = s[sep+1:]
+		var err error
+		if z.b.abs, _, _, err = z.b.abs.scan(strings.NewReader(s), 0, false); err != nil {
+			return nil, false
+		}
+		if len(z.b.abs) == 0 {
+			return nil, false
+		}
+		return z.norm(), true
+	}
+
+	// parse floating-point number
+	r := strings.NewReader(s)
+
+	// sign
+	neg, err := scanSign(r)
+	if err != nil {
+		return nil, false
+	}
+
+	// mantissa
+	var ecorr int
+	z.a.abs, _, ecorr, err = z.a.abs.scan(r, 10, true)
+	if err != nil {
+		return nil, false
+	}
+
+	// exponent
+	var exp int64
+	exp, _, err = scanExponent(r, false)
+	if err != nil {
+		return nil, false
+	}
+
+	// there should be no unread characters left
+	if _, err = r.ReadByte(); err != io.EOF {
+		return nil, false
+	}
+
+	// correct exponent
+	if ecorr < 0 {
+		exp += int64(ecorr)
+	}
+
+	// compute exponent power
+	expabs := exp
+	if expabs < 0 {
+		expabs = -expabs
+	}
+	powTen := nat(nil).expNN(natTen, nat(nil).setWord(Word(expabs)), nil)
+
+	// complete fraction
+	if exp < 0 {
+		z.b.abs = powTen
+		z.norm()
+	} else {
+		z.a.abs = z.a.abs.mul(z.a.abs, powTen)
+		z.b.abs = z.b.abs[:0]
+	}
+
+	z.a.neg = neg && len(z.a.abs) > 0 // 0 has no sign
+
+	return z, true
+}
+
+// scanExponent scans the longest possible prefix of r representing a decimal
+// ('e', 'E') or binary ('p') exponent, if any. It returns the exponent, the
+// exponent base (10 or 2), or a read or syntax error, if any.
+//
+//	exponent = ( "E" | "e" | "p" ) [ sign ] digits .
+//	sign     = "+" | "-" .
+//	digits   = digit { digit } .
+//	digit    = "0" ... "9" .
+//
+// A binary exponent is only permitted if binExpOk is set.
+func scanExponent(r io.ByteScanner, binExpOk bool) (exp int64, base int, err error) {
+	base = 10
+
+	var ch byte
+	if ch, err = r.ReadByte(); err != nil {
+		if err == io.EOF {
+			err = nil // no exponent; same as e0
+		}
+		return
+	}
+
+	switch ch {
+	case 'e', 'E':
+		// ok
+	case 'p':
+		if binExpOk {
+			base = 2
+			break // ok
+		}
+		fallthrough // binary exponent not permitted
+	default:
+		r.UnreadByte()
+		return // no exponent; same as e0
+	}
+
+	var neg bool
+	if neg, err = scanSign(r); err != nil {
+		return
+	}
+
+	var digits []byte
+	if neg {
+		digits = append(digits, '-')
+	}
+
+	// no need to use nat.scan for exponent digits
+	// since we only care about int64 values - the
+	// from-scratch scan is easy enough and faster
+	for i := 0; ; i++ {
+		if ch, err = r.ReadByte(); err != nil {
+			if err != io.EOF || i == 0 {
+				return
+			}
+			err = nil
+			break // i > 0
+		}
+		if ch < '0' || '9' < ch {
+			if i == 0 {
+				r.UnreadByte()
+				err = fmt.Errorf("invalid exponent (missing digits)")
+				return
+			}
+			break // i > 0
+		}
+		digits = append(digits, byte(ch))
+	}
+	// i > 0 => we have at least one digit
+
+	exp, err = strconv.ParseInt(string(digits), 10, 64)
+	return
+}
+
+// String returns a string representation of x in the form "a/b" (even if b == 1).
+func (x *Rat) String() string {
+	s := "/1"
+	if len(x.b.abs) != 0 {
+		s = "/" + x.b.abs.decimalString()
+	}
+	return x.a.String() + s
+}
+
+// RatString returns a string representation of x in the form "a/b" if b != 1,
+// and in the form "a" if b == 1.
+func (x *Rat) RatString() string {
+	if x.IsInt() {
+		return x.a.String()
+	}
+	return x.String()
+}
+
+// FloatString returns a string representation of x in decimal form with prec
+// digits of precision after the decimal point and the last digit rounded.
+func (x *Rat) FloatString(prec int) string {
+	if x.IsInt() {
+		s := x.a.String()
+		if prec > 0 {
+			s += "." + strings.Repeat("0", prec)
+		}
+		return s
+	}
+	// x.b.abs != 0
+
+	q, r := nat(nil).div(nat(nil), x.a.abs, x.b.abs)
+
+	p := natOne
+	if prec > 0 {
+		p = nat(nil).expNN(natTen, nat(nil).setUint64(uint64(prec)), nil)
+	}
+
+	r = r.mul(r, p)
+	r, r2 := r.div(nat(nil), r, x.b.abs)
+
+	// see if we need to round up
+	r2 = r2.add(r2, r2)
+	if x.b.abs.cmp(r2) <= 0 {
+		r = r.add(r, natOne)
+		if r.cmp(p) >= 0 {
+			q = nat(nil).add(q, natOne)
+			r = nat(nil).sub(r, p)
+		}
+	}
+
+	s := q.decimalString()
+	if x.a.neg {
+		s = "-" + s
+	}
+
+	if prec > 0 {
+		rs := r.decimalString()
+		leadingZeros := prec - len(rs)
+		s += "." + strings.Repeat("0", leadingZeros) + rs
+	}
+
+	return s
+}
diff --git a/src/cmd/compile/internal/big/ratconv_test.go b/src/cmd/compile/internal/big/ratconv_test.go
new file mode 100644
index 0000000..16b3a19
--- /dev/null
+++ b/src/cmd/compile/internal/big/ratconv_test.go
@@ -0,0 +1,451 @@
+// 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
+
+import (
+	"bytes"
+	"fmt"
+	"math"
+	"strconv"
+	"strings"
+	"testing"
+)
+
+type StringTest struct {
+	in, out string
+	ok      bool
+}
+
+var setStringTests = []StringTest{
+	{"0", "0", true},
+	{"-0", "0", true},
+	{"1", "1", true},
+	{"-1", "-1", true},
+	{"1.", "1", true},
+	{"1e0", "1", true},
+	{"1.e1", "10", true},
+	{in: "1e"},
+	{in: "1.e"},
+	{in: "1e+14e-5"},
+	{in: "1e4.5"},
+	{in: "r"},
+	{in: "a/b"},
+	{in: "a.b"},
+	{"-0.1", "-1/10", true},
+	{"-.1", "-1/10", true},
+	{"2/4", "1/2", true},
+	{".25", "1/4", true},
+	{"-1/5", "-1/5", true},
+	{"8129567.7690E14", "812956776900000000000", true},
+	{"78189e+4", "781890000", true},
+	{"553019.8935e+8", "55301989350000", true},
+	{"98765432109876543210987654321e-10", "98765432109876543210987654321/10000000000", true},
+	{"9877861857500000E-7", "3951144743/4", true},
+	{"2169378.417e-3", "2169378417/1000000", true},
+	{"884243222337379604041632732738665534", "884243222337379604041632732738665534", true},
+	{"53/70893980658822810696", "53/70893980658822810696", true},
+	{"106/141787961317645621392", "53/70893980658822810696", true},
+	{"204211327800791583.81095", "4084226556015831676219/20000", true},
+	{in: "1/0"},
+}
+
+// These are not supported by fmt.Fscanf.
+var setStringTests2 = []StringTest{
+	{"0x10", "16", true},
+	{"-010/1", "-8", true}, // TODO(gri) should we even permit octal here?
+	{"-010.", "-10", true},
+	{"0x10/0x20", "1/2", true},
+	{"0b1000/3", "8/3", true},
+	// TODO(gri) add more tests
+}
+
+func TestRatSetString(t *testing.T) {
+	var tests []StringTest
+	tests = append(tests, setStringTests...)
+	tests = append(tests, setStringTests2...)
+
+	for i, test := range tests {
+		x, ok := new(Rat).SetString(test.in)
+
+		if ok {
+			if !test.ok {
+				t.Errorf("#%d SetString(%q) expected failure", i, test.in)
+			} else if x.RatString() != test.out {
+				t.Errorf("#%d SetString(%q) got %s want %s", i, test.in, x.RatString(), test.out)
+			}
+		} else if x != nil {
+			t.Errorf("#%d SetString(%q) got %p want nil", i, test.in, x)
+		}
+	}
+}
+
+func TestRatScan(t *testing.T) {
+	var buf bytes.Buffer
+	for i, test := range setStringTests {
+		x := new(Rat)
+		buf.Reset()
+		buf.WriteString(test.in)
+
+		_, err := fmt.Fscanf(&buf, "%v", x)
+		if err == nil != test.ok {
+			if test.ok {
+				t.Errorf("#%d (%s) error: %s", i, test.in, err)
+			} else {
+				t.Errorf("#%d (%s) expected error", i, test.in)
+			}
+			continue
+		}
+		if err == nil && x.RatString() != test.out {
+			t.Errorf("#%d got %s want %s", i, x.RatString(), test.out)
+		}
+	}
+}
+
+var floatStringTests = []struct {
+	in   string
+	prec int
+	out  string
+}{
+	{"0", 0, "0"},
+	{"0", 4, "0.0000"},
+	{"1", 0, "1"},
+	{"1", 2, "1.00"},
+	{"-1", 0, "-1"},
+	{".25", 2, "0.25"},
+	{".25", 1, "0.3"},
+	{".25", 3, "0.250"},
+	{"-1/3", 3, "-0.333"},
+	{"-2/3", 4, "-0.6667"},
+	{"0.96", 1, "1.0"},
+	{"0.999", 2, "1.00"},
+	{"0.9", 0, "1"},
+	{".25", -1, "0"},
+	{".55", -1, "1"},
+}
+
+func TestFloatString(t *testing.T) {
+	for i, test := range floatStringTests {
+		x, _ := new(Rat).SetString(test.in)
+
+		if x.FloatString(test.prec) != test.out {
+			t.Errorf("#%d got %s want %s", i, x.FloatString(test.prec), test.out)
+		}
+	}
+}
+
+// Test inputs to Rat.SetString.  The prefix "long:" causes the test
+// to be skipped in --test.short mode.  (The threshold is about 500us.)
+var float64inputs = []string{
+	// Constants plundered from strconv/testfp.txt.
+
+	// Table 1: Stress Inputs for Conversion to 53-bit Binary, < 1/2 ULP
+	"5e+125",
+	"69e+267",
+	"999e-026",
+	"7861e-034",
+	"75569e-254",
+	"928609e-261",
+	"9210917e+080",
+	"84863171e+114",
+	"653777767e+273",
+	"5232604057e-298",
+	"27235667517e-109",
+	"653532977297e-123",
+	"3142213164987e-294",
+	"46202199371337e-072",
+	"231010996856685e-073",
+	"9324754620109615e+212",
+	"78459735791271921e+049",
+	"272104041512242479e+200",
+	"6802601037806061975e+198",
+	"20505426358836677347e-221",
+	"836168422905420598437e-234",
+	"4891559871276714924261e+222",
+
+	// Table 2: Stress Inputs for Conversion to 53-bit Binary, > 1/2 ULP
+	"9e-265",
+	"85e-037",
+	"623e+100",
+	"3571e+263",
+	"81661e+153",
+	"920657e-023",
+	"4603285e-024",
+	"87575437e-309",
+	"245540327e+122",
+	"6138508175e+120",
+	"83356057653e+193",
+	"619534293513e+124",
+	"2335141086879e+218",
+	"36167929443327e-159",
+	"609610927149051e-255",
+	"3743626360493413e-165",
+	"94080055902682397e-242",
+	"899810892172646163e+283",
+	"7120190517612959703e+120",
+	"25188282901709339043e-252",
+	"308984926168550152811e-052",
+	"6372891218502368041059e+064",
+
+	// Table 14: Stress Inputs for Conversion to 24-bit Binary, <1/2 ULP
+	"5e-20",
+	"67e+14",
+	"985e+15",
+	"7693e-42",
+	"55895e-16",
+	"996622e-44",
+	"7038531e-32",
+	"60419369e-46",
+	"702990899e-20",
+	"6930161142e-48",
+	"25933168707e+13",
+	"596428896559e+20",
+
+	// Table 15: Stress Inputs for Conversion to 24-bit Binary, >1/2 ULP
+	"3e-23",
+	"57e+18",
+	"789e-35",
+	"2539e-18",
+	"76173e+28",
+	"887745e-11",
+	"5382571e-37",
+	"82381273e-35",
+	"750486563e-38",
+	"3752432815e-39",
+	"75224575729e-45",
+	"459926601011e+15",
+
+	// Constants plundered from strconv/atof_test.go.
+
+	"0",
+	"1",
+	"+1",
+	"1e23",
+	"1E23",
+	"100000000000000000000000",
+	"1e-100",
+	"123456700",
+	"99999999999999974834176",
+	"100000000000000000000001",
+	"100000000000000008388608",
+	"100000000000000016777215",
+	"100000000000000016777216",
+	"-1",
+	"-0.1",
+	"-0", // NB: exception made for this input
+	"1e-20",
+	"625e-3",
+
+	// largest float64
+	"1.7976931348623157e308",
+	"-1.7976931348623157e308",
+	// next float64 - too large
+	"1.7976931348623159e308",
+	"-1.7976931348623159e308",
+	// the border is ...158079
+	// borderline - okay
+	"1.7976931348623158e308",
+	"-1.7976931348623158e308",
+	// borderline - too large
+	"1.797693134862315808e308",
+	"-1.797693134862315808e308",
+
+	// a little too large
+	"1e308",
+	"2e308",
+	"1e309",
+
+	// way too large
+	"1e310",
+	"-1e310",
+	"1e400",
+	"-1e400",
+	"long:1e400000",
+	"long:-1e400000",
+
+	// denormalized
+	"1e-305",
+	"1e-306",
+	"1e-307",
+	"1e-308",
+	"1e-309",
+	"1e-310",
+	"1e-322",
+	// smallest denormal
+	"5e-324",
+	"4e-324",
+	"3e-324",
+	// too small
+	"2e-324",
+	// way too small
+	"1e-350",
+	"long:1e-400000",
+	// way too small, negative
+	"-1e-350",
+	"long:-1e-400000",
+
+	// try to overflow exponent
+	// [Disabled: too slow and memory-hungry with rationals.]
+	// "1e-4294967296",
+	// "1e+4294967296",
+	// "1e-18446744073709551616",
+	// "1e+18446744073709551616",
+
+	// http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/
+	"2.2250738585072012e-308",
+	// http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/
+	"2.2250738585072011e-308",
+
+	// A very large number (initially wrongly parsed by the fast algorithm).
+	"4.630813248087435e+307",
+
+	// A different kind of very large number.
+	"22.222222222222222",
+	"long:2." + strings.Repeat("2", 4000) + "e+1",
+
+	// Exactly halfway between 1 and math.Nextafter(1, 2).
+	// Round to even (down).
+	"1.00000000000000011102230246251565404236316680908203125",
+	// Slightly lower; still round down.
+	"1.00000000000000011102230246251565404236316680908203124",
+	// Slightly higher; round up.
+	"1.00000000000000011102230246251565404236316680908203126",
+	// Slightly higher, but you have to read all the way to the end.
+	"long:1.00000000000000011102230246251565404236316680908203125" + strings.Repeat("0", 10000) + "1",
+
+	// Smallest denormal, 2^(-1022-52)
+	"4.940656458412465441765687928682213723651e-324",
+	// Half of smallest denormal, 2^(-1022-53)
+	"2.470328229206232720882843964341106861825e-324",
+	// A little more than the exact half of smallest denormal
+	// 2^-1075 + 2^-1100.  (Rounds to 1p-1074.)
+	"2.470328302827751011111470718709768633275e-324",
+	// The exact halfway between smallest normal and largest denormal:
+	// 2^-1022 - 2^-1075.  (Rounds to 2^-1022.)
+	"2.225073858507201136057409796709131975935e-308",
+
+	"1152921504606846975",  //   1<<60 - 1
+	"-1152921504606846975", // -(1<<60 - 1)
+	"1152921504606846977",  //   1<<60 + 1
+	"-1152921504606846977", // -(1<<60 + 1)
+
+	"1/3",
+}
+
+// isFinite reports whether f represents a finite rational value.
+// It is equivalent to !math.IsNan(f) && !math.IsInf(f, 0).
+func isFinite(f float64) bool {
+	return math.Abs(f) <= math.MaxFloat64
+}
+
+func TestFloat32SpecialCases(t *testing.T) {
+	for _, input := range float64inputs {
+		if strings.HasPrefix(input, "long:") {
+			if testing.Short() {
+				continue
+			}
+			input = input[len("long:"):]
+		}
+
+		r, ok := new(Rat).SetString(input)
+		if !ok {
+			t.Errorf("Rat.SetString(%q) failed", input)
+			continue
+		}
+		f, exact := r.Float32()
+
+		// 1. Check string -> Rat -> float32 conversions are
+		// consistent with strconv.ParseFloat.
+		// Skip this check if the input uses "a/b" rational syntax.
+		if !strings.Contains(input, "/") {
+			e64, _ := strconv.ParseFloat(input, 32)
+			e := float32(e64)
+
+			// Careful: negative Rats too small for
+			// float64 become -0, but Rat obviously cannot
+			// preserve the sign from SetString("-0").
+			switch {
+			case math.Float32bits(e) == math.Float32bits(f):
+				// Ok: bitwise equal.
+			case f == 0 && r.Num().BitLen() == 0:
+				// Ok: Rat(0) is equivalent to both +/- float64(0).
+			default:
+				t.Errorf("strconv.ParseFloat(%q) = %g (%b), want %g (%b); delta = %g", input, e, e, f, f, f-e)
+			}
+		}
+
+		if !isFinite(float64(f)) {
+			continue
+		}
+
+		// 2. Check f is best approximation to r.
+		if !checkIsBestApprox32(t, f, r) {
+			// Append context information.
+			t.Errorf("(input was %q)", input)
+		}
+
+		// 3. Check f->R->f roundtrip is non-lossy.
+		checkNonLossyRoundtrip32(t, f)
+
+		// 4. Check exactness using slow algorithm.
+		if wasExact := new(Rat).SetFloat64(float64(f)).Cmp(r) == 0; wasExact != exact {
+			t.Errorf("Rat.SetString(%q).Float32().exact = %t, want %t", input, exact, wasExact)
+		}
+	}
+}
+
+func TestFloat64SpecialCases(t *testing.T) {
+	for _, input := range float64inputs {
+		if strings.HasPrefix(input, "long:") {
+			if testing.Short() {
+				continue
+			}
+			input = input[len("long:"):]
+		}
+
+		r, ok := new(Rat).SetString(input)
+		if !ok {
+			t.Errorf("Rat.SetString(%q) failed", input)
+			continue
+		}
+		f, exact := r.Float64()
+
+		// 1. Check string -> Rat -> float64 conversions are
+		// consistent with strconv.ParseFloat.
+		// Skip this check if the input uses "a/b" rational syntax.
+		if !strings.Contains(input, "/") {
+			e, _ := strconv.ParseFloat(input, 64)
+
+			// Careful: negative Rats too small for
+			// float64 become -0, but Rat obviously cannot
+			// preserve the sign from SetString("-0").
+			switch {
+			case math.Float64bits(e) == math.Float64bits(f):
+				// Ok: bitwise equal.
+			case f == 0 && r.Num().BitLen() == 0:
+				// Ok: Rat(0) is equivalent to both +/- float64(0).
+			default:
+				t.Errorf("strconv.ParseFloat(%q) = %g (%b), want %g (%b); delta = %g", input, e, e, f, f, f-e)
+			}
+		}
+
+		if !isFinite(f) {
+			continue
+		}
+
+		// 2. Check f is best approximation to r.
+		if !checkIsBestApprox64(t, f, r) {
+			// Append context information.
+			t.Errorf("(input was %q)", input)
+		}
+
+		// 3. Check f->R->f roundtrip is non-lossy.
+		checkNonLossyRoundtrip64(t, f)
+
+		// 4. Check exactness using slow algorithm.
+		if wasExact := new(Rat).SetFloat64(f).Cmp(r) == 0; wasExact != exact {
+			t.Errorf("Rat.SetString(%q).Float64().exact = %t, want %t", input, exact, wasExact)
+		}
+	}
+}
diff --git a/src/cmd/compile/internal/big/roundingmode_string.go b/src/cmd/compile/internal/big/roundingmode_string.go
new file mode 100644
index 0000000..05024b8
--- /dev/null
+++ b/src/cmd/compile/internal/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/cmd/compile/internal/big/vendor.bash b/src/cmd/compile/internal/big/vendor.bash
new file mode 100755
index 0000000..1b191cc
--- /dev/null
+++ b/src/cmd/compile/internal/big/vendor.bash
@@ -0,0 +1,31 @@
+#!/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.
+
+# Run this script to obtain an up-to-date vendored version of math/big.
+
+BIGDIR=../../../../math/big
+
+# Start from scratch.
+rm *.go
+
+# We don't want any assembly files.
+cp $BIGDIR/*.go .
+
+# Use pure Go arith ops w/o build tag.
+sed 's|^// \+build math_big_pure_go$||' arith_decl_pure.go > arith_decl.go
+rm arith_decl_pure.go
+
+# Import vendored math/big in external tests (e.g., floatexample_test.go).
+for f in *_test.go; do
+	sed 's|"math/big"|"cmd/compile/internal/big"|' $f > foo.go
+	mv foo.go $f
+done
+
+# gofmt to clean up after sed
+gofmt -w .
+
+# Test that it works
+go test -short
diff --git a/src/cmd/compile/internal/gc/align.go b/src/cmd/compile/internal/gc/align.go
new file mode 100644
index 0000000..60c59fc
--- /dev/null
+++ b/src/cmd/compile/internal/gc/align.go
@@ -0,0 +1,713 @@
+// 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"
+
+/*
+ * machine size and rounding
+ * alignment is dictated around
+ * the size of a pointer, set in betypeinit
+ * (see ../6g/galign.c).
+ */
+var defercalc int
+
+func Rnd(o int64, r int64) int64 {
+	if r < 1 || r > 8 || r&(r-1) != 0 {
+		Fatal("rnd %d", r)
+	}
+	return (o + r - 1) &^ (r - 1)
+}
+
+func offmod(t *Type) {
+	o := int32(0)
+	for f := t.Type; f != nil; f = f.Down {
+		if f.Etype != TFIELD {
+			Fatal("offmod: not TFIELD: %v", Tconv(f, obj.FmtLong))
+		}
+		f.Width = int64(o)
+		o += int32(Widthptr)
+		if int64(o) >= Thearch.MAXWIDTH {
+			Yyerror("interface too large")
+			o = int32(Widthptr)
+		}
+	}
+}
+
+func widstruct(errtype *Type, t *Type, o int64, flag int) int64 {
+	starto := o
+	maxalign := int32(flag)
+	if maxalign < 1 {
+		maxalign = 1
+	}
+	lastzero := int64(0)
+	var w int64
+	for f := t.Type; f != nil; f = f.Down {
+		if f.Etype != TFIELD {
+			Fatal("widstruct: not TFIELD: %v", Tconv(f, obj.FmtLong))
+		}
+		if f.Type == nil {
+			// broken field, just skip it so that other valid fields
+			// get a width.
+			continue
+		}
+
+		dowidth(f.Type)
+		if int32(f.Type.Align) > maxalign {
+			maxalign = int32(f.Type.Align)
+		}
+		if f.Type.Width < 0 {
+			Fatal("invalid width %d", f.Type.Width)
+		}
+		w = f.Type.Width
+		if f.Type.Align > 0 {
+			o = Rnd(o, int64(f.Type.Align))
+		}
+		f.Width = o // really offset for TFIELD
+		if f.Nname != nil {
+			// this same stackparam logic is in addrescapes
+			// in typecheck.c.  usually addrescapes runs after
+			// widstruct, in which case we could drop this,
+			// but function closure functions are the exception.
+			if f.Nname.Name.Param.Stackparam != nil {
+				f.Nname.Name.Param.Stackparam.Xoffset = o
+				f.Nname.Xoffset = 0
+			} else {
+				f.Nname.Xoffset = o
+			}
+		}
+
+		if w == 0 {
+			lastzero = o
+		}
+		o += w
+		if o >= Thearch.MAXWIDTH {
+			Yyerror("type %v too large", Tconv(errtype, obj.FmtLong))
+			o = 8 // small but nonzero
+		}
+	}
+
+	// For nonzero-sized structs which end in a zero-sized thing, we add
+	// an extra byte of padding to the type.  This padding ensures that
+	// taking the address of the zero-sized thing can't manufacture a
+	// pointer to the next object in the heap.  See issue 9401.
+	if flag == 1 && o > starto && o == lastzero {
+		o++
+	}
+
+	// final width is rounded
+	if flag != 0 {
+		o = Rnd(o, int64(maxalign))
+	}
+	t.Align = uint8(maxalign)
+
+	// type width only includes back to first field's offset
+	t.Width = o - starto
+
+	return o
+}
+
+func dowidth(t *Type) {
+	if Widthptr == 0 {
+		Fatal("dowidth without betypeinit")
+	}
+
+	if t == nil {
+		return
+	}
+
+	if t.Width > 0 {
+		if t.Align == 0 {
+			// See issue 11354
+			Fatal("zero alignment with nonzero size %v", t)
+		}
+		return
+	}
+
+	if t.Width == -2 {
+		lno := int(lineno)
+		lineno = int32(t.Lineno)
+		if t.Broke == 0 {
+			t.Broke = 1
+			Yyerror("invalid recursive type %v", t)
+		}
+
+		t.Width = 0
+		lineno = int32(lno)
+		return
+	}
+
+	// break infinite recursion if the broken recursive type
+	// is referenced again
+	if t.Broke != 0 && t.Width == 0 {
+		return
+	}
+
+	// defer checkwidth calls until after we're done
+	defercalc++
+
+	lno := int(lineno)
+	lineno = int32(t.Lineno)
+	t.Width = -2
+	t.Align = 0
+
+	et := int32(t.Etype)
+	switch et {
+	case TFUNC, TCHAN, TMAP, TSTRING:
+		break
+
+		/* simtype == 0 during bootstrap */
+	default:
+		if Simtype[t.Etype] != 0 {
+			et = int32(Simtype[t.Etype])
+		}
+	}
+
+	w := int64(0)
+	switch et {
+	default:
+		Fatal("dowidth: unknown type: %v", t)
+
+		/* compiler-specific stuff */
+	case TINT8, TUINT8, TBOOL:
+		// bool is int8
+		w = 1
+
+	case TINT16, TUINT16:
+		w = 2
+
+	case TINT32, TUINT32, TFLOAT32:
+		w = 4
+
+	case TINT64, TUINT64, TFLOAT64, TCOMPLEX64:
+		w = 8
+		t.Align = uint8(Widthreg)
+
+	case TCOMPLEX128:
+		w = 16
+		t.Align = uint8(Widthreg)
+
+	case TPTR32:
+		w = 4
+		checkwidth(t.Type)
+
+	case TPTR64:
+		w = 8
+		checkwidth(t.Type)
+
+	case TUNSAFEPTR:
+		w = int64(Widthptr)
+
+	case TINTER: // implemented as 2 pointers
+		w = 2 * int64(Widthptr)
+
+		t.Align = uint8(Widthptr)
+		offmod(t)
+
+	case TCHAN: // implemented as pointer
+		w = int64(Widthptr)
+
+		checkwidth(t.Type)
+
+		// make fake type to check later to
+		// trigger channel argument check.
+		t1 := typ(TCHANARGS)
+
+		t1.Type = t
+		checkwidth(t1)
+
+	case TCHANARGS:
+		t1 := t.Type
+		dowidth(t.Type) // just in case
+		if t1.Type.Width >= 1<<16 {
+			Yyerror("channel element type too large (>64kB)")
+		}
+		t.Width = 1
+
+	case TMAP: // implemented as pointer
+		w = int64(Widthptr)
+
+		checkwidth(t.Type)
+		checkwidth(t.Down)
+
+	case TFORW: // should have been filled in
+		if t.Broke == 0 {
+			Yyerror("invalid recursive type %v", t)
+		}
+		w = 1 // anything will do
+
+		// dummy type; should be replaced before use.
+	case TANY:
+		if Debug['A'] == 0 {
+			Fatal("dowidth any")
+		}
+		w = 1 // anything will do
+
+	case TSTRING:
+		if sizeof_String == 0 {
+			Fatal("early dowidth string")
+		}
+		w = int64(sizeof_String)
+		t.Align = uint8(Widthptr)
+
+	case TARRAY:
+		if t.Type == nil {
+			break
+		}
+		if t.Bound >= 0 {
+			dowidth(t.Type)
+			if t.Type.Width != 0 {
+				cap := (uint64(Thearch.MAXWIDTH) - 1) / uint64(t.Type.Width)
+				if uint64(t.Bound) > cap {
+					Yyerror("type %v larger than address space", Tconv(t, obj.FmtLong))
+				}
+			}
+
+			w = t.Bound * t.Type.Width
+			t.Align = t.Type.Align
+		} else if t.Bound == -1 {
+			w = int64(sizeof_Array)
+			checkwidth(t.Type)
+			t.Align = uint8(Widthptr)
+		} else if t.Bound == -100 {
+			if t.Broke == 0 {
+				Yyerror("use of [...] array outside of array literal")
+				t.Broke = 1
+			}
+		} else {
+			Fatal("dowidth %v", t) // probably [...]T
+		}
+
+	case TSTRUCT:
+		if t.Funarg != 0 {
+			Fatal("dowidth fn struct %v", t)
+		}
+		w = widstruct(t, t, 0, 1)
+
+		// make fake type to check later to
+	// trigger function argument computation.
+	case TFUNC:
+		t1 := typ(TFUNCARGS)
+
+		t1.Type = t
+		checkwidth(t1)
+
+		// width of func type is pointer
+		w = int64(Widthptr)
+
+		// function is 3 cated structures;
+	// compute their widths as side-effect.
+	case TFUNCARGS:
+		t1 := t.Type
+
+		w = widstruct(t.Type, *getthis(t1), 0, 0)
+		w = widstruct(t.Type, *getinarg(t1), w, Widthreg)
+		w = widstruct(t.Type, *Getoutarg(t1), w, Widthreg)
+		t1.Argwid = w
+		if w%int64(Widthreg) != 0 {
+			Warn("bad type %v %d\n", t1, w)
+		}
+		t.Align = 1
+	}
+
+	if Widthptr == 4 && w != int64(int32(w)) {
+		Yyerror("type %v too large", t)
+	}
+
+	t.Width = w
+	if t.Align == 0 {
+		if w > 8 || w&(w-1) != 0 {
+			Fatal("invalid alignment for %v", t)
+		}
+		t.Align = uint8(w)
+	}
+
+	lineno = int32(lno)
+
+	if defercalc == 1 {
+		resumecheckwidth()
+	} else {
+		defercalc--
+	}
+}
+
+/*
+ * when a type's width should be known, we call checkwidth
+ * to compute it.  during a declaration like
+ *
+ *	type T *struct { next T }
+ *
+ * it is necessary to defer the calculation of the struct width
+ * until after T has been initialized to be a pointer to that struct.
+ * similarly, during import processing structs may be used
+ * before their definition.  in those situations, calling
+ * defercheckwidth() stops width calculations until
+ * resumecheckwidth() is called, at which point all the
+ * checkwidths that were deferred are executed.
+ * dowidth should only be called when the type's size
+ * is needed immediately.  checkwidth makes sure the
+ * size is evaluated eventually.
+ */
+type TypeList struct {
+	t    *Type
+	next *TypeList
+}
+
+var tlfree *TypeList
+
+var tlq *TypeList
+
+func checkwidth(t *Type) {
+	if t == nil {
+		return
+	}
+
+	// function arg structs should not be checked
+	// outside of the enclosing function.
+	if t.Funarg != 0 {
+		Fatal("checkwidth %v", t)
+	}
+
+	if defercalc == 0 {
+		dowidth(t)
+		return
+	}
+
+	if t.Deferwidth != 0 {
+		return
+	}
+	t.Deferwidth = 1
+
+	l := tlfree
+	if l != nil {
+		tlfree = l.next
+	} else {
+		l = new(TypeList)
+	}
+
+	l.t = t
+	l.next = tlq
+	tlq = l
+}
+
+func defercheckwidth() {
+	// we get out of sync on syntax errors, so don't be pedantic.
+	if defercalc != 0 && nerrors == 0 {
+		Fatal("defercheckwidth")
+	}
+	defercalc = 1
+}
+
+func resumecheckwidth() {
+	if defercalc == 0 {
+		Fatal("resumecheckwidth")
+	}
+	for l := tlq; l != nil; l = tlq {
+		l.t.Deferwidth = 0
+		tlq = l.next
+		dowidth(l.t)
+		l.next = tlfree
+		tlfree = l
+	}
+
+	defercalc = 0
+}
+
+var itable *Type // distinguished *byte
+
+func typeinit() {
+	if Widthptr == 0 {
+		Fatal("typeinit before betypeinit")
+	}
+
+	for i := 0; i < NTYPE; i++ {
+		Simtype[i] = uint8(i)
+	}
+
+	Types[TPTR32] = typ(TPTR32)
+	dowidth(Types[TPTR32])
+
+	Types[TPTR64] = typ(TPTR64)
+	dowidth(Types[TPTR64])
+
+	t := typ(TUNSAFEPTR)
+	Types[TUNSAFEPTR] = t
+	t.Sym = Pkglookup("Pointer", unsafepkg)
+	t.Sym.Def = typenod(t)
+	t.Sym.Def.Name = new(Name)
+
+	dowidth(Types[TUNSAFEPTR])
+
+	Tptr = TPTR32
+	if Widthptr == 8 {
+		Tptr = TPTR64
+	}
+
+	for i := TINT8; i <= TUINT64; i++ {
+		Isint[i] = true
+	}
+	Isint[TINT] = true
+	Isint[TUINT] = true
+	Isint[TUINTPTR] = true
+
+	Isfloat[TFLOAT32] = true
+	Isfloat[TFLOAT64] = true
+
+	Iscomplex[TCOMPLEX64] = true
+	Iscomplex[TCOMPLEX128] = true
+
+	Isptr[TPTR32] = true
+	Isptr[TPTR64] = true
+
+	isforw[TFORW] = true
+
+	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] || 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] {
+			okforeq[i] = true
+			okforcmp[i] = true
+			okforadd[i] = true
+			okforarith[i] = true
+			okforconst[i] = true
+			issimple[i] = true
+			minfltval[i] = newMpflt()
+			maxfltval[i] = newMpflt()
+		}
+
+		if Iscomplex[i] {
+			okforeq[i] = true
+			okforadd[i] = true
+			okforarith[i] = true
+			okforconst[i] = true
+			issimple[i] = true
+		}
+	}
+
+	issimple[TBOOL] = true
+
+	okforadd[TSTRING] = true
+
+	okforbool[TBOOL] = true
+
+	okforcap[TARRAY] = true
+	okforcap[TCHAN] = true
+
+	okforconst[TBOOL] = true
+	okforconst[TSTRING] = true
+
+	okforlen[TARRAY] = true
+	okforlen[TCHAN] = true
+	okforlen[TMAP] = true
+	okforlen[TSTRING] = true
+
+	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] = true
+
+	var i int
+	for i = 0; i < len(okfor); i++ {
+		okfor[i] = okfornone[:]
+	}
+
+	// binary
+	okfor[OADD] = okforadd[:]
+
+	okfor[OAND] = okforand[:]
+	okfor[OANDAND] = okforbool[:]
+	okfor[OANDNOT] = okforand[:]
+	okfor[ODIV] = okforarith[:]
+	okfor[OEQ] = okforeq[:]
+	okfor[OGE] = okforcmp[:]
+	okfor[OGT] = okforcmp[:]
+	okfor[OLE] = okforcmp[:]
+	okfor[OLT] = okforcmp[:]
+	okfor[OMOD] = okforand[:]
+	okfor[OHMUL] = okforarith[:]
+	okfor[OMUL] = okforarith[:]
+	okfor[ONE] = okforeq[:]
+	okfor[OOR] = okforand[:]
+	okfor[OOROR] = okforbool[:]
+	okfor[OSUB] = okforarith[:]
+	okfor[OXOR] = okforand[:]
+	okfor[OLSH] = okforand[:]
+	okfor[ORSH] = okforand[:]
+
+	// unary
+	okfor[OCOM] = okforand[:]
+
+	okfor[OMINUS] = okforarith[:]
+	okfor[ONOT] = okforbool[:]
+	okfor[OPLUS] = okforarith[:]
+
+	// special
+	okfor[OCAP] = okforcap[:]
+
+	okfor[OLEN] = okforlen[:]
+
+	// comparison
+	iscmp[OLT] = true
+
+	iscmp[OGT] = true
+	iscmp[OGE] = true
+	iscmp[OLE] = true
+	iscmp[OEQ] = true
+	iscmp[ONE] = true
+
+	mpatofix(Maxintval[TINT8], "0x7f")
+	mpatofix(Minintval[TINT8], "-0x80")
+	mpatofix(Maxintval[TINT16], "0x7fff")
+	mpatofix(Minintval[TINT16], "-0x8000")
+	mpatofix(Maxintval[TINT32], "0x7fffffff")
+	mpatofix(Minintval[TINT32], "-0x80000000")
+	mpatofix(Maxintval[TINT64], "0x7fffffffffffffff")
+	mpatofix(Minintval[TINT64], "-0x8000000000000000")
+
+	mpatofix(Maxintval[TUINT8], "0xff")
+	mpatofix(Maxintval[TUINT16], "0xffff")
+	mpatofix(Maxintval[TUINT32], "0xffffffff")
+	mpatofix(Maxintval[TUINT64], "0xffffffffffffffff")
+
+	/* f is valid float if min < f < max.  (min and max are not themselves valid.) */
+	mpatoflt(maxfltval[TFLOAT32], "33554431p103") /* 2^24-1 p (127-23) + 1/2 ulp*/
+	mpatoflt(minfltval[TFLOAT32], "-33554431p103")
+	mpatoflt(maxfltval[TFLOAT64], "18014398509481983p970") /* 2^53-1 p (1023-52) + 1/2 ulp */
+	mpatoflt(minfltval[TFLOAT64], "-18014398509481983p970")
+
+	maxfltval[TCOMPLEX64] = maxfltval[TFLOAT32]
+	minfltval[TCOMPLEX64] = minfltval[TFLOAT32]
+	maxfltval[TCOMPLEX128] = maxfltval[TFLOAT64]
+	minfltval[TCOMPLEX128] = minfltval[TFLOAT64]
+
+	/* for walk to use in error messages */
+	Types[TFUNC] = functype(nil, nil, nil)
+
+	/* types used in front end */
+	// types[TNIL] got set early in lexinit
+	Types[TIDEAL] = typ(TIDEAL)
+
+	Types[TINTER] = typ(TINTER)
+
+	/* simple aliases */
+	Simtype[TMAP] = uint8(Tptr)
+
+	Simtype[TCHAN] = uint8(Tptr)
+	Simtype[TFUNC] = uint8(Tptr)
+	Simtype[TUNSAFEPTR] = uint8(Tptr)
+
+	/* pick up the backend thearch.typedefs */
+	var s1 *Sym
+	var etype int
+	var sameas int
+	var s *Sym
+	for i = range Thearch.Typedefs {
+		s = Lookup(Thearch.Typedefs[i].Name)
+		s1 = Pkglookup(Thearch.Typedefs[i].Name, builtinpkg)
+
+		etype = Thearch.Typedefs[i].Etype
+		if etype < 0 || etype >= len(Types) {
+			Fatal("typeinit: %s bad etype", s.Name)
+		}
+		sameas = Thearch.Typedefs[i].Sameas
+		if sameas < 0 || sameas >= len(Types) {
+			Fatal("typeinit: %s bad sameas", s.Name)
+		}
+		Simtype[etype] = uint8(sameas)
+		minfltval[etype] = minfltval[sameas]
+		maxfltval[etype] = maxfltval[sameas]
+		Minintval[etype] = Minintval[sameas]
+		Maxintval[etype] = Maxintval[sameas]
+
+		t = Types[etype]
+		if t != nil {
+			Fatal("typeinit: %s already defined", s.Name)
+		}
+
+		t = typ(etype)
+		t.Sym = s1
+
+		dowidth(t)
+		Types[etype] = t
+		s1.Def = typenod(t)
+		s1.Def.Name = new(Name)
+	}
+
+	Array_array = int(Rnd(0, int64(Widthptr)))
+	Array_nel = int(Rnd(int64(Array_array)+int64(Widthptr), int64(Widthint)))
+	Array_cap = int(Rnd(int64(Array_nel)+int64(Widthint), int64(Widthint)))
+	sizeof_Array = int(Rnd(int64(Array_cap)+int64(Widthint), int64(Widthptr)))
+
+	// string is same as slice wo the cap
+	sizeof_String = int(Rnd(int64(Array_nel)+int64(Widthint), int64(Widthptr)))
+
+	dowidth(Types[TSTRING])
+	dowidth(idealstring)
+
+	itable = typ(Tptr)
+	itable.Type = Types[TUINT8]
+}
+
+/*
+ * compute total size of f's in/out arguments.
+ */
+func Argsize(t *Type) int {
+	var save Iter
+	var x int64
+
+	w := int64(0)
+
+	fp := Structfirst(&save, Getoutarg(t))
+	for fp != nil {
+		x = fp.Width + fp.Type.Width
+		if x > w {
+			w = x
+		}
+		fp = structnext(&save)
+	}
+
+	fp = funcfirst(&save, t)
+	for fp != nil {
+		x = fp.Width + fp.Type.Width
+		if x > w {
+			w = x
+		}
+		fp = funcnext(&save)
+	}
+
+	w = (w + int64(Widthptr) - 1) &^ (int64(Widthptr) - 1)
+	if int64(int(w)) != w {
+		Fatal("argsize too big")
+	}
+	return int(w)
+}
diff --git a/src/cmd/compile/internal/gc/builtin.go b/src/cmd/compile/internal/gc/builtin.go
new file mode 100644
index 0000000..f09dd56
--- /dev/null
+++ b/src/cmd/compile/internal/gc/builtin.go
@@ -0,0 +1,169 @@
+// AUTO-GENERATED by mkbuiltin.go; DO NOT EDIT
+
+package gc
+
+const runtimeimport = "" +
+	"package runtime\n" +
+	"import runtime \"runtime\"\n" +
+	"func @\"\".newobject (@\"\".typ·2 *byte) (? *any)\n" +
+	"func @\"\".panicindex ()\n" +
+	"func @\"\".panicslice ()\n" +
+	"func @\"\".panicdivide ()\n" +
+	"func @\"\".throwreturn ()\n" +
+	"func @\"\".throwinit ()\n" +
+	"func @\"\".panicwrap (? string, ? string, ? string)\n" +
+	"func @\"\".gopanic (? interface {})\n" +
+	"func @\"\".gorecover (? *int32) (? interface {})\n" +
+	"func @\"\".printbool (? bool)\n" +
+	"func @\"\".printfloat (? float64)\n" +
+	"func @\"\".printint (? int64)\n" +
+	"func @\"\".printhex (? uint64)\n" +
+	"func @\"\".printuint (? uint64)\n" +
+	"func @\"\".printcomplex (? complex128)\n" +
+	"func @\"\".printstring (? string)\n" +
+	"func @\"\".printpointer (? any)\n" +
+	"func @\"\".printiface (? any)\n" +
+	"func @\"\".printeface (? any)\n" +
+	"func @\"\".printslice (? any)\n" +
+	"func @\"\".printnl ()\n" +
+	"func @\"\".printsp ()\n" +
+	"func @\"\".printlock ()\n" +
+	"func @\"\".printunlock ()\n" +
+	"func @\"\".concatstring2 (? *[32]byte, ? string, ? string) (? string)\n" +
+	"func @\"\".concatstring3 (? *[32]byte, ? string, ? string, ? string) (? string)\n" +
+	"func @\"\".concatstring4 (? *[32]byte, ? string, ? string, ? string, ? string) (? string)\n" +
+	"func @\"\".concatstring5 (? *[32]byte, ? string, ? string, ? string, ? string, ? string) (? string)\n" +
+	"func @\"\".concatstrings (? *[32]byte, ? []string) (? string)\n" +
+	"func @\"\".cmpstring (? string, ? string) (? int)\n" +
+	"func @\"\".eqstring (? string, ? string) (? bool)\n" +
+	"func @\"\".intstring (? *[4]byte, ? int64) (? string)\n" +
+	"func @\"\".slicebytetostring (? *[32]byte, ? []byte) (? string)\n" +
+	"func @\"\".slicebytetostringtmp (? []byte) (? string)\n" +
+	"func @\"\".slicerunetostring (? *[32]byte, ? []rune) (? string)\n" +
+	"func @\"\".stringtoslicebyte (? *[32]byte, ? string) (? []byte)\n" +
+	"func @\"\".stringtoslicebytetmp (? string) (? []byte)\n" +
+	"func @\"\".stringtoslicerune (? *[32]rune, ? string) (? []rune)\n" +
+	"func @\"\".stringiter (? string, ? int) (? int)\n" +
+	"func @\"\".stringiter2 (? string, ? int) (@\"\".retk·1 int, @\"\".retv·2 rune)\n" +
+	"func @\"\".slicecopy (@\"\".to·2 any, @\"\".fr·3 any, @\"\".wid·4 uintptr) (? int)\n" +
+	"func @\"\".slicestringcopy (@\"\".to·2 any, @\"\".fr·3 any) (? int)\n" +
+	"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, @\"\".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" +
+	"func @\"\".assertE2I2 (@\"\".typ·2 *byte, @\"\".iface·3 any, @\"\".ret·4 *any) (? bool)\n" +
+	"func @\"\".assertE2T (@\"\".typ·1 *byte, @\"\".iface·2 any, @\"\".ret·3 *any)\n" +
+	"func @\"\".assertE2T2 (@\"\".typ·2 *byte, @\"\".iface·3 any, @\"\".ret·4 *any) (? bool)\n" +
+	"func @\"\".assertI2E (@\"\".typ·1 *byte, @\"\".iface·2 any, @\"\".ret·3 *any)\n" +
+	"func @\"\".assertI2E2 (@\"\".typ·2 *byte, @\"\".iface·3 any, @\"\".ret·4 *any) (? bool)\n" +
+	"func @\"\".assertI2I (@\"\".typ·1 *byte, @\"\".iface·2 any, @\"\".ret·3 *any)\n" +
+	"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" +
+	"func @\"\".efacethash (@\"\".i1·2 any) (@\"\".ret·1 uint32)\n" +
+	"func @\"\".makemap (@\"\".mapType·2 *byte, @\"\".hint·3 int64, @\"\".mapbuf·4 *any, @\"\".bucketbuf·5 *any) (@\"\".hmap·1 map[any]any)\n" +
+	"func @\"\".mapaccess1 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 *any) (@\"\".val·1 *any)\n" +
+	"func @\"\".mapaccess1_fast32 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 any) (@\"\".val·1 *any)\n" +
+	"func @\"\".mapaccess1_fast64 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 any) (@\"\".val·1 *any)\n" +
+	"func @\"\".mapaccess1_faststr (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 any) (@\"\".val·1 *any)\n" +
+	"func @\"\".mapaccess2 (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 *any) (@\"\".val·1 *any, @\"\".pres·2 bool)\n" +
+	"func @\"\".mapaccess2_fast32 (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 any) (@\"\".val·1 *any, @\"\".pres·2 bool)\n" +
+	"func @\"\".mapaccess2_fast64 (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 any) (@\"\".val·1 *any, @\"\".pres·2 bool)\n" +
+	"func @\"\".mapaccess2_faststr (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 any) (@\"\".val·1 *any, @\"\".pres·2 bool)\n" +
+	"func @\"\".mapassign1 (@\"\".mapType·1 *byte, @\"\".hmap·2 map[any]any, @\"\".key·3 *any, @\"\".val·4 *any)\n" +
+	"func @\"\".mapiterinit (@\"\".mapType·1 *byte, @\"\".hmap·2 map[any]any, @\"\".hiter·3 *any)\n" +
+	"func @\"\".mapdelete (@\"\".mapType·1 *byte, @\"\".hmap·2 map[any]any, @\"\".key·3 *any)\n" +
+	"func @\"\".mapiternext (@\"\".hiter·1 *any)\n" +
+	"func @\"\".makechan (@\"\".chanType·2 *byte, @\"\".hint·3 int64) (@\"\".hchan·1 chan any)\n" +
+	"func @\"\".chanrecv1 (@\"\".chanType·1 *byte, @\"\".hchan·2 <-chan any, @\"\".elem·3 *any)\n" +
+	"func @\"\".chanrecv2 (@\"\".chanType·2 *byte, @\"\".hchan·3 <-chan any, @\"\".elem·4 *any) (? bool)\n" +
+	"func @\"\".chansend1 (@\"\".chanType·1 *byte, @\"\".hchan·2 chan<- any, @\"\".elem·3 *any)\n" +
+	"func @\"\".closechan (@\"\".hchan·1 any)\n" +
+	"var @\"\".writeBarrierEnabled bool\n" +
+	"func @\"\".writebarrierptr (@\"\".dst·1 *any, @\"\".src·2 any)\n" +
+	"func @\"\".writebarrierstring (@\"\".dst·1 *any, @\"\".src·2 any)\n" +
+	"func @\"\".writebarrierslice (@\"\".dst·1 *any, @\"\".src·2 any)\n" +
+	"func @\"\".writebarrieriface (@\"\".dst·1 *any, @\"\".src·2 any)\n" +
+	"func @\"\".writebarrierfat01 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+	"func @\"\".writebarrierfat10 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+	"func @\"\".writebarrierfat11 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+	"func @\"\".writebarrierfat001 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+	"func @\"\".writebarrierfat010 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+	"func @\"\".writebarrierfat011 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+	"func @\"\".writebarrierfat100 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+	"func @\"\".writebarrierfat101 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+	"func @\"\".writebarrierfat110 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+	"func @\"\".writebarrierfat111 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+	"func @\"\".writebarrierfat0001 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+	"func @\"\".writebarrierfat0010 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+	"func @\"\".writebarrierfat0011 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+	"func @\"\".writebarrierfat0100 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+	"func @\"\".writebarrierfat0101 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+	"func @\"\".writebarrierfat0110 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+	"func @\"\".writebarrierfat0111 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+	"func @\"\".writebarrierfat1000 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+	"func @\"\".writebarrierfat1001 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+	"func @\"\".writebarrierfat1010 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+	"func @\"\".writebarrierfat1011 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+	"func @\"\".writebarrierfat1100 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+	"func @\"\".writebarrierfat1101 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+	"func @\"\".writebarrierfat1110 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+	"func @\"\".writebarrierfat1111 (@\"\".dst·1 *any, _ uintptr, @\"\".src·3 any)\n" +
+	"func @\"\".typedmemmove (@\"\".typ·1 *byte, @\"\".dst·2 *any, @\"\".src·3 *any)\n" +
+	"func @\"\".typedslicecopy (@\"\".typ·2 *byte, @\"\".dst·3 any, @\"\".src·4 any) (? int)\n" +
+	"func @\"\".selectnbsend (@\"\".chanType·2 *byte, @\"\".hchan·3 chan<- any, @\"\".elem·4 *any) (? bool)\n" +
+	"func @\"\".selectnbrecv (@\"\".chanType·2 *byte, @\"\".elem·3 *any, @\"\".hchan·4 <-chan any) (? bool)\n" +
+	"func @\"\".selectnbrecv2 (@\"\".chanType·2 *byte, @\"\".elem·3 *any, @\"\".received·4 *bool, @\"\".hchan·5 <-chan any) (? bool)\n" +
+	"func @\"\".newselect (@\"\".sel·1 *byte, @\"\".selsize·2 int64, @\"\".size·3 int32)\n" +
+	"func @\"\".selectsend (@\"\".sel·2 *byte, @\"\".hchan·3 chan<- any, @\"\".elem·4 *any) (@\"\".selected·1 bool)\n" +
+	"func @\"\".selectrecv (@\"\".sel·2 *byte, @\"\".hchan·3 <-chan any, @\"\".elem·4 *any) (@\"\".selected·1 bool)\n" +
+	"func @\"\".selectrecv2 (@\"\".sel·2 *byte, @\"\".hchan·3 <-chan any, @\"\".elem·4 *any, @\"\".received·5 *bool) (@\"\".selected·1 bool)\n" +
+	"func @\"\".selectdefault (@\"\".sel·2 *byte) (@\"\".selected·1 bool)\n" +
+	"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, @\"\".cap·4 int) (@\"\".ary·1 []any)\n" +
+	"func @\"\".growslice_n (@\"\".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" +
+	"func @\"\".memequal8 (@\"\".x·2 *any, @\"\".y·3 *any) (? bool)\n" +
+	"func @\"\".memequal16 (@\"\".x·2 *any, @\"\".y·3 *any) (? bool)\n" +
+	"func @\"\".memequal32 (@\"\".x·2 *any, @\"\".y·3 *any) (? bool)\n" +
+	"func @\"\".memequal64 (@\"\".x·2 *any, @\"\".y·3 *any) (? bool)\n" +
+	"func @\"\".memequal128 (@\"\".x·2 *any, @\"\".y·3 *any) (? bool)\n" +
+	"func @\"\".int64div (? int64, ? int64) (? int64)\n" +
+	"func @\"\".uint64div (? uint64, ? uint64) (? uint64)\n" +
+	"func @\"\".int64mod (? int64, ? int64) (? int64)\n" +
+	"func @\"\".uint64mod (? uint64, ? uint64) (? uint64)\n" +
+	"func @\"\".float64toint64 (? float64) (? int64)\n" +
+	"func @\"\".float64touint64 (? float64) (? uint64)\n" +
+	"func @\"\".int64tofloat64 (? int64) (? float64)\n" +
+	"func @\"\".uint64tofloat64 (? uint64) (? float64)\n" +
+	"func @\"\".complex128div (@\"\".num·2 complex128, @\"\".den·3 complex128) (@\"\".quo·1 complex128)\n" +
+	"func @\"\".racefuncenter (? uintptr)\n" +
+	"func @\"\".racefuncexit ()\n" +
+	"func @\"\".raceread (? uintptr)\n" +
+	"func @\"\".racewrite (? uintptr)\n" +
+	"func @\"\".racereadrange (@\"\".addr·1 uintptr, @\"\".size·2 uintptr)\n" +
+	"func @\"\".racewriterange (@\"\".addr·1 uintptr, @\"\".size·2 uintptr)\n" +
+	"\n" +
+	"$$\n"
+
+const unsafeimport = "" +
+	"package unsafe\n" +
+	"import runtime \"runtime\"\n" +
+	"type @\"\".Pointer uintptr\n" +
+	"func @\"\".Offsetof (? any) (? uintptr)\n" +
+	"func @\"\".Sizeof (? any) (? uintptr)\n" +
+	"func @\"\".Alignof (? any) (? uintptr)\n" +
+	"\n" +
+	"$$\n"
diff --git a/src/cmd/compile/internal/gc/builtin/runtime.go b/src/cmd/compile/internal/gc/builtin/runtime.go
new file mode 100644
index 0000000..6210f10
--- /dev/null
+++ b/src/cmd/compile/internal/gc/builtin/runtime.go
@@ -0,0 +1,195 @@
+// 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.
+
+// NOTE: If you change this file you must run "go generate"
+// to update builtin.go.  This is not done automatically
+// to avoid depending on having a working compiler binary.
+
+// +build ignore
+
+package PACKAGE
+
+// emitted by compiler, not referred to by go programs
+
+func newobject(typ *byte) *any
+func panicindex()
+func panicslice()
+func panicdivide()
+func throwreturn()
+func throwinit()
+func panicwrap(string, string, string)
+
+func gopanic(interface{})
+func gorecover(*int32) interface{}
+
+func printbool(bool)
+func printfloat(float64)
+func printint(int64)
+func printhex(uint64)
+func printuint(uint64)
+func printcomplex(complex128)
+func printstring(string)
+func printpointer(any)
+func printiface(any)
+func printeface(any)
+func printslice(any)
+func printnl()
+func printsp()
+func printlock()
+func printunlock()
+
+func concatstring2(*[32]byte, string, string) string
+func concatstring3(*[32]byte, string, string, string) string
+func concatstring4(*[32]byte, string, string, string, string) string
+func concatstring5(*[32]byte, string, string, string, string, string) string
+func concatstrings(*[32]byte, []string) string
+
+func cmpstring(string, string) int
+func eqstring(string, string) bool
+func intstring(*[4]byte, int64) string
+func slicebytetostring(*[32]byte, []byte) string
+func slicebytetostringtmp([]byte) string
+func slicerunetostring(*[32]byte, []rune) string
+func stringtoslicebyte(*[32]byte, string) []byte
+func stringtoslicebytetmp(string) []byte
+func stringtoslicerune(*[32]rune, string) []rune
+func stringiter(string, int) int
+func stringiter2(string, int) (retk int, retv rune)
+func slicecopy(to any, fr any, wid uintptr) int
+func slicestringcopy(to any, fr any) int
+
+// interface conversions
+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, 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)
+func assertE2E2(typ *byte, iface any, ret *any) bool
+func assertE2I(typ *byte, iface any, ret *any)
+func assertE2I2(typ *byte, iface any, ret *any) bool
+func assertE2T(typ *byte, iface any, ret *any)
+func assertE2T2(typ *byte, iface any, ret *any) bool
+func assertI2E(typ *byte, iface any, ret *any)
+func assertI2E2(typ *byte, iface any, ret *any) bool
+func assertI2I(typ *byte, iface any, ret *any)
+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)
+func ifacethash(i1 any) (ret uint32)
+func efacethash(i1 any) (ret uint32)
+
+// *byte is really *runtime.Type
+func makemap(mapType *byte, hint int64, mapbuf *any, bucketbuf *any) (hmap map[any]any)
+func mapaccess1(mapType *byte, hmap map[any]any, key *any) (val *any)
+func mapaccess1_fast32(mapType *byte, hmap map[any]any, key any) (val *any)
+func mapaccess1_fast64(mapType *byte, hmap map[any]any, key any) (val *any)
+func mapaccess1_faststr(mapType *byte, hmap map[any]any, key any) (val *any)
+func mapaccess2(mapType *byte, hmap map[any]any, key *any) (val *any, pres bool)
+func mapaccess2_fast32(mapType *byte, hmap map[any]any, key any) (val *any, pres bool)
+func mapaccess2_fast64(mapType *byte, hmap map[any]any, key any) (val *any, pres bool)
+func mapaccess2_faststr(mapType *byte, hmap map[any]any, key any) (val *any, pres bool)
+func mapassign1(mapType *byte, hmap map[any]any, key *any, val *any)
+func mapiterinit(mapType *byte, hmap map[any]any, hiter *any)
+func mapdelete(mapType *byte, hmap map[any]any, key *any)
+func mapiternext(hiter *any)
+
+// *byte is really *runtime.Type
+func makechan(chanType *byte, hint int64) (hchan chan any)
+func chanrecv1(chanType *byte, hchan <-chan any, elem *any)
+func chanrecv2(chanType *byte, hchan <-chan any, elem *any) bool
+func chansend1(chanType *byte, hchan chan<- any, elem *any)
+func closechan(hchan any)
+
+var writeBarrierEnabled bool
+
+func writebarrierptr(dst *any, src any)
+func writebarrierstring(dst *any, src any)
+func writebarrierslice(dst *any, src any)
+func writebarrieriface(dst *any, src any)
+
+// The unused *byte argument makes sure that src is 2-pointer-aligned,
+// which is the maximum alignment on NaCl amd64p32
+// (and possibly on 32-bit systems if we start 64-bit aligning uint64s).
+// The bitmap in the name tells which words being copied are pointers.
+func writebarrierfat01(dst *any, _ uintptr, src any)
+func writebarrierfat10(dst *any, _ uintptr, src any)
+func writebarrierfat11(dst *any, _ uintptr, src any)
+func writebarrierfat001(dst *any, _ uintptr, src any)
+func writebarrierfat010(dst *any, _ uintptr, src any)
+func writebarrierfat011(dst *any, _ uintptr, src any)
+func writebarrierfat100(dst *any, _ uintptr, src any)
+func writebarrierfat101(dst *any, _ uintptr, src any)
+func writebarrierfat110(dst *any, _ uintptr, src any)
+func writebarrierfat111(dst *any, _ uintptr, src any)
+func writebarrierfat0001(dst *any, _ uintptr, src any)
+func writebarrierfat0010(dst *any, _ uintptr, src any)
+func writebarrierfat0011(dst *any, _ uintptr, src any)
+func writebarrierfat0100(dst *any, _ uintptr, src any)
+func writebarrierfat0101(dst *any, _ uintptr, src any)
+func writebarrierfat0110(dst *any, _ uintptr, src any)
+func writebarrierfat0111(dst *any, _ uintptr, src any)
+func writebarrierfat1000(dst *any, _ uintptr, src any)
+func writebarrierfat1001(dst *any, _ uintptr, src any)
+func writebarrierfat1010(dst *any, _ uintptr, src any)
+func writebarrierfat1011(dst *any, _ uintptr, src any)
+func writebarrierfat1100(dst *any, _ uintptr, src any)
+func writebarrierfat1101(dst *any, _ uintptr, src any)
+func writebarrierfat1110(dst *any, _ uintptr, src any)
+func writebarrierfat1111(dst *any, _ uintptr, src any)
+
+// *byte is really *runtime.Type
+func typedmemmove(typ *byte, dst *any, src *any)
+func typedslicecopy(typ *byte, dst any, src any) int
+
+func selectnbsend(chanType *byte, hchan chan<- any, elem *any) bool
+func selectnbrecv(chanType *byte, elem *any, hchan <-chan any) bool
+func selectnbrecv2(chanType *byte, elem *any, received *bool, hchan <-chan any) bool
+
+func newselect(sel *byte, selsize int64, size int32)
+func selectsend(sel *byte, hchan chan<- any, elem *any) (selected bool)
+func selectrecv(sel *byte, hchan <-chan any, elem *any) (selected bool)
+func selectrecv2(sel *byte, hchan <-chan any, elem *any, received *bool) (selected bool)
+func selectdefault(sel *byte) (selected bool)
+func selectgo(sel *byte)
+func block()
+
+func makeslice(typ *byte, nel int64, cap int64) (ary []any)
+func growslice(typ *byte, old []any, cap int) (ary []any)
+func growslice_n(typ *byte, old []any, n int) (ary []any)
+func memmove(to *any, frm *any, length uintptr)
+func memclr(ptr *byte, length uintptr)
+
+func memequal(x, y *any, size uintptr) bool
+func memequal8(x, y *any) bool
+func memequal16(x, y *any) bool
+func memequal32(x, y *any) bool
+func memequal64(x, y *any) bool
+func memequal128(x, y *any) bool
+
+// only used on 32-bit
+func int64div(int64, int64) int64
+func uint64div(uint64, uint64) uint64
+func int64mod(int64, int64) int64
+func uint64mod(uint64, uint64) uint64
+func float64toint64(float64) int64
+func float64touint64(float64) uint64
+func int64tofloat64(int64) float64
+func uint64tofloat64(uint64) float64
+
+func complex128div(num complex128, den complex128) (quo complex128)
+
+// race detection
+func racefuncenter(uintptr)
+func racefuncexit()
+func raceread(uintptr)
+func racewrite(uintptr)
+func racereadrange(addr, size uintptr)
+func racewriterange(addr, size uintptr)
diff --git a/src/cmd/compile/internal/gc/builtin/unsafe.go b/src/cmd/compile/internal/gc/builtin/unsafe.go
new file mode 100644
index 0000000..ce50869
--- /dev/null
+++ b/src/cmd/compile/internal/gc/builtin/unsafe.go
@@ -0,0 +1,18 @@
+// 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.
+
+// NOTE: If you change this file you must run "go generate"
+// to update builtin.go.  This is not done automatically
+// to avoid depending on having a working compiler binary.
+
+// +build ignore
+
+package PACKAGE
+
+type Pointer uintptr // not really; filled in by compiler
+
+// return types here are ignored; see unsafe.go
+func Offsetof(any) uintptr
+func Sizeof(any) uintptr
+func Alignof(any) uintptr
diff --git a/src/cmd/compile/internal/gc/bv.go b/src/cmd/compile/internal/gc/bv.go
new file mode 100644
index 0000000..2b988e6
--- /dev/null
+++ b/src/cmd/compile/internal/gc/bv.go
@@ -0,0 +1,195 @@
+// 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
+
+import "fmt"
+
+const (
+	WORDSIZE  = 4
+	WORDBITS  = 32
+	WORDMASK  = WORDBITS - 1
+	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 {
+	return bv.n
+}
+
+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)}
+}
+
+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) {
+	for i, x := range src1.b {
+		dst.b[i] = x &^ src2.b[i]
+	}
+}
+
+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)
+	}
+	for i, x := range bv1.b {
+		if x != bv2.b[i] {
+			return 1
+		}
+	}
+	return 0
+}
+
+func bvcopy(dst Bvec, src Bvec) {
+	for i, x := range src.b {
+		dst.b[i] = x
+	}
+}
+
+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 {
+			bvset(dst, i)
+		}
+	}
+	for i := int32(0); i < src2.n; i++ {
+		if bvget(src2, i) != 0 {
+			bvset(dst, i+src1.n)
+		}
+	}
+	return dst
+}
+
+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)
+	}
+	return int((bv.b[i>>WORDSHIFT] >> uint(i&WORDMASK)) & 1)
+}
+
+// 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 {
+	if i >= bv.n {
+		return -1
+	}
+
+	// Jump i ahead to next word with bits.
+	if bv.b[i>>WORDSHIFT]>>uint(i&WORDMASK) == 0 {
+		i &^= WORDMASK
+		i += WORDBITS
+		for i < bv.n && bv.b[i>>WORDSHIFT] == 0 {
+			i += WORDBITS
+		}
+	}
+
+	if i >= bv.n {
+		return -1
+	}
+
+	// Find 1 bit.
+	w := bv.b[i>>WORDSHIFT] >> uint(i&WORDMASK)
+
+	for w&1 == 0 {
+		w >>= 1
+		i++
+	}
+
+	return int(i)
+}
+
+func bvisempty(bv Bvec) bool {
+	for i := int32(0); i < bv.n; i += WORDBITS {
+		if bv.b[i>>WORDSHIFT] != 0 {
+			return false
+		}
+	}
+	return true
+}
+
+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) {
+	for i, x := range src1.b {
+		dst.b[i] = x | src2.b[i]
+	}
+}
+
+/* intersection */
+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) {
+	fmt.Printf("#*")
+	for i := int32(0); i < bv.n; i++ {
+		fmt.Printf("%d", bvget(bv, i))
+	}
+}
+
+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)
+	}
+	mask := uint32(^(1 << uint(i%WORDBITS)))
+	bv.b[i/WORDBITS] &= mask
+}
+
+func bvresetall(bv Bvec) {
+	for i := range bv.b {
+		bv.b[i] = 0
+	}
+}
+
+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)
+	}
+	mask := uint32(1 << uint(i%WORDBITS))
+	bv.b[i/WORDBITS] |= mask
+}
diff --git a/src/cmd/compile/internal/gc/cgen.go b/src/cmd/compile/internal/gc/cgen.go
new file mode 100644
index 0000000..b6a3e5b
--- /dev/null
+++ b/src/cmd/compile/internal/gc/cgen.go
@@ -0,0 +1,3566 @@
+// 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.
+ * if wb is true, need to emit write barriers.
+ */
+func Cgen(n, res *Node) {
+	cgen_wb(n, res, false)
+}
+
+func cgen_wb(n, res *Node, wb bool) {
+	if Debug['g'] != 0 {
+		op := "cgen"
+		if wb {
+			op = "cgen_wb"
+		}
+		Dump("\n"+op+"-n", n)
+		Dump(op+"-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:
+		cgen_slice(n, res, wb)
+		return
+
+	case OEFACE:
+		if res.Op != ONAME || !res.Addable || wb {
+			var n1 Node
+			Tempname(&n1, n.Type)
+			Cgen_eface(n, &n1)
+			cgen_wb(&n1, res, wb)
+		} else {
+			Cgen_eface(n, res)
+		}
+		return
+
+	case ODOTTYPE:
+		cgen_dottype(n, res, nil, wb)
+		return
+
+	case OAPPEND:
+		cgen_append(n, res)
+		return
+	}
+
+	if n.Ullman >= UINF {
+		if n.Op == OINDREG {
+			Fatal("cgen: this is going to miscompile")
+		}
+		if res.Ullman >= UINF {
+			var n1 Node
+			Tempname(&n1, n.Type)
+			Cgen(n, &n1)
+			cgen_wb(&n1, res, wb)
+			return
+		}
+	}
+
+	if Isfat(n.Type) {
+		if n.Type.Width < 0 {
+			Fatal("forgot to compute width for %v", n.Type)
+		}
+		sgen_wb(n, res, n.Type.Width, wb)
+		return
+	}
+
+	if !res.Addable {
+		if n.Ullman > res.Ullman {
+			if Ctxt.Arch.Regsize == 4 && Is64(n.Type) {
+				var n1 Node
+				Tempname(&n1, n.Type)
+				Cgen(n, &n1)
+				cgen_wb(&n1, res, wb)
+				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_wb(&n1, res, wb)
+			Regfree(&n1)
+			return
+		}
+
+		var f int
+		if res.Ullman < UINF {
+			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 && !wb {
+				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
+				}
+			}
+		}
+
+		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)
+			cgen_wb(&n1, &n2, wb)
+			Regfree(&n2)
+			return
+		}
+
+		var n1 Node
+		Igen(res, &n1, nil)
+		cgen_wb(n, &n1, wb)
+		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 wb {
+		if int(Simtype[res.Type.Etype]) != Tptr {
+			Fatal("cgen_wb of type %v", res.Type)
+		}
+		if n.Ullman >= UINF {
+			var n1 Node
+			Tempname(&n1, n.Type)
+			Cgen(n, &n1)
+			n = &n1
+		}
+		cgen_wbptr(n, res)
+		return
+	}
+
+	// Write barrier now handled. Code below this line can ignore wb.
+
+	if Ctxt.Arch.Thechar == '5' { // TODO(rsc): Maybe more often?
+		// if both are addressable, move
+		if n.Addable && res.Addable {
+			if Is64(n.Type) || Is64(res.Type) || n.Op == OREGISTER || res.Op == OREGISTER || 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 && !res.Addable {
+			// 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 {
+			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 {
+		Thearch.Gmove(n, res)
+		return
+	}
+
+	if Ctxt.Arch.Thechar == '7' || Ctxt.Arch.Thechar == '9' {
+		// if both are addressable, move
+		if n.Addable {
+			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))
+
+	case OOROR, OANDAND,
+		OEQ, ONE,
+		OLT, OLE,
+		OGE, OGT,
+		ONOT:
+		Bvgen(n, res, true)
+		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
+
+	case OSQRT:
+		var n1 Node
+		Regalloc(&n1, nl.Type, res)
+		Cgen(n.Left, &n1)
+		Thearch.Gins(Thearch.Optoas(OSQRT, nl.Type), &n1, &n1)
+		Thearch.Gmove(&n1, res)
+		Regfree(&n1)
+		return
+
+	case OGETG:
+		Thearch.Getg(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 && !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.(string), &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)
+			p1 := Thearch.Ginscmp(OEQ, Types[Tptr], &n1, &n2, 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)
+			p1 := Thearch.Ginscmp(OEQ, Types[Tptr], &n1, &n2, 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)
+}
+
+var sys_wbptr *Node
+
+func cgen_wbptr(n, res *Node) {
+	if Curfn != nil && Curfn.Func.Nowritebarrier {
+		Yyerror("write barrier prohibited")
+	}
+	if Debug_wb > 0 {
+		Warn("write barrier")
+	}
+
+	var dst, src Node
+	Igen(res, &dst, nil)
+	if n.Op == OREGISTER {
+		src = *n
+		Regrealloc(&src)
+	} else {
+		Cgenr(n, &src, nil)
+	}
+
+	wbEnabled := syslook("writeBarrierEnabled", 0)
+	pbr := Thearch.Ginscmp(ONE, Types[TUINT8], wbEnabled, Nodintconst(0), -1)
+	Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &src, &dst)
+	pjmp := Gbranch(obj.AJMP, nil, 0)
+	Patch(pbr, Pc)
+	var adst Node
+	Agenr(&dst, &adst, &dst)
+	p := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &adst, nil)
+	a := &p.To
+	a.Type = obj.TYPE_MEM
+	a.Reg = int16(Thearch.REGSP)
+	a.Offset = 0
+	if HasLinkRegister() {
+		a.Offset += int64(Widthptr)
+	}
+	p2 := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &src, nil)
+	p2.To = p.To
+	p2.To.Offset += int64(Widthptr)
+	Regfree(&adst)
+	if sys_wbptr == nil {
+		sys_wbptr = writebarrierfn("writebarrierptr", Types[Tptr], Types[Tptr])
+	}
+	Ginscall(sys_wbptr, 0)
+	Patch(pjmp, Pc)
+
+	Regfree(&dst)
+	Regfree(&src)
+}
+
+func cgen_wbfat(n, res *Node) {
+	if Curfn != nil && Curfn.Func.Nowritebarrier {
+		Yyerror("write barrier prohibited")
+	}
+	if Debug_wb > 0 {
+		Warn("write barrier")
+	}
+	needType := true
+	funcName := "typedmemmove"
+	var dst, src Node
+	if n.Ullman >= res.Ullman {
+		Agenr(n, &src, nil)
+		Agenr(res, &dst, nil)
+	} else {
+		Agenr(res, &dst, nil)
+		Agenr(n, &src, nil)
+	}
+	p := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &dst, nil)
+	a := &p.To
+	a.Type = obj.TYPE_MEM
+	a.Reg = int16(Thearch.REGSP)
+	a.Offset = 0
+	if HasLinkRegister() {
+		a.Offset += int64(Widthptr)
+	}
+	if needType {
+		a.Offset += int64(Widthptr)
+	}
+	p2 := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &src, nil)
+	p2.To = p.To
+	p2.To.Offset += int64(Widthptr)
+	Regfree(&dst)
+	if needType {
+		src.Type = Types[Tptr]
+		Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), typename(n.Type), &src)
+		p3 := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), &src, nil)
+		p3.To = p2.To
+		p3.To.Offset -= 2 * int64(Widthptr)
+	}
+	Regfree(&src)
+	Ginscall(writebarrierfn(funcName, Types[Tptr], Types[Tptr]), 0)
+}
+
+// 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 {
+		*n1 = *n
+		if n1.Op == OREGISTER || n1.Op == OINDREG {
+			reg[n.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 {
+		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 {
+				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 {
+				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.(*Mpint)))
+				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)
+						Nodconst(&n2, Types[TUINT32], int64(v))
+						p1 := Thearch.Ginscmp(OGT, Types[TUINT32], &n1, &n2, +1)
+						Ginscall(Panicindex, -1)
+						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.(string))))
+				} 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)
+				}
+				p1 := Thearch.Ginscmp(OLT, Types[TUINT32], &n2, &n4, +1)
+				if n4.Op == OREGISTER {
+					Regfree(&n4)
+				}
+				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.(string), &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 {
+				if w&(w-1) == 0 {
+					// Power of 2.  Use shift.
+					Thearch.Ginscon(Thearch.Optoas(OLSH, Types[TUINT32]), int64(log2(uint64(w))), &n2)
+				} else {
+					// Not a power of 2.  Use multiply.
+					Regalloc(&n4, Types[TUINT32], nil)
+					Nodconst(&n1, Types[TUINT32], int64(w))
+					Thearch.Gmove(&n1, &n4)
+					Thearch.Gins(Thearch.Optoas(OMUL, Types[TUINT32]), &n4, &n2)
+					Regfree(&n4)
+				}
+				Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &n2, &n3)
+			}
+			*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 {
+				// 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 {
+				// 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.(*Mpint)))
+				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))
+						p1 := Thearch.Ginscmp(OGT, Types[TUINT32], &nlen, &n2, +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.(string))))
+				} 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)
+				}
+
+				p1 := Thearch.Ginscmp(OLT, t, &n2, &nlen, +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.(string), &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 {
+				if w&(w-1) == 0 {
+					// Power of 2.  Use shift.
+					Thearch.Ginscon(Thearch.Optoas(OLSH, Types[TUINT32]), int64(log2(uint64(w))), &n2)
+				} else {
+					// Not a power of 2.  Use multiply.
+					Thearch.Ginscon(Thearch.Optoas(OMUL, Types[TUINT32]), int64(w), &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 {
+			goto irad
+		}
+		if nl.Addable {
+			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 {
+					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.(*Mpint)))
+			if Isslice(nl.Type) || nl.Type.Etype == TSTRING {
+				if Debug['B'] == 0 && !n.Bounded {
+					p1 := Thearch.Ginscmp(OGT, Types[Simtype[TUINT]], &nlen, Nodintconst(int64(v)), +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.(string))))
+			} else if Isslice(nl.Type) || nl.Type.Etype == TSTRING {
+				// nlen already initialized
+			} else {
+				Nodconst(&nlen, t, nl.Type.Bound)
+			}
+
+			p1 := Thearch.Ginscmp(OLT, t, &n2, &nlen, +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.(string), &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 {
+			if w&(w-1) == 0 {
+				// Power of 2.  Use shift.
+				Thearch.Ginscon(Thearch.Optoas(OLSH, t), int64(log2(w)), &n2)
+			} else {
+				// Not a power of 2.  Use multiply.
+				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)
+	}
+}
+
+// log2 returns the logarithm base 2 of n.  n must be a power of 2.
+func log2(n uint64) int {
+	x := 0
+	for n>>uint(x) != 1 {
+		x++
+	}
+	return x
+}
+
+/*
+ * 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.Op == OINDREG && n.Xoffset == 0 {
+		// Generate MOVW R0, R1 instead of MOVW $0(R0), R1.
+		// This allows better move propagation in the back ends
+		// (and maybe it helps the processor).
+		n1 := *n
+		n1.Op = OREGISTER
+		n1.Type = res.Type
+		Thearch.Gmove(&n1, res)
+		return
+	}
+
+	if n.Addable {
+		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.Name.Funcdepth > 0 && n.Name.Funcdepth != Funcdepth {
+			Dump("bad agen", n)
+			Fatal("agen: bad ONAME funcdepth %d != %d", n.Name.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.Name.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.Reg != int16(Thearch.REGSP) {
+			reg[n.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.Reg = int16(Thearch.REGSP)
+		a.Addable = true
+		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.(*Mpint)) * n.Type.Width
+				Fixlargeoffset(a)
+				return
+			}
+		}
+	}
+
+	Agenr(n, a, res)
+	a.Op = OINDREG
+	a.Type = n.Type
+}
+
+// Bgen generates code for branches:
+//
+// 	if n == wantTrue {
+// 		goto to
+// 	}
+func Bgen(n *Node, wantTrue bool, likely int, to *obj.Prog) {
+	bgenx(n, nil, wantTrue, likely, to)
+}
+
+// Bvgen generates code for calculating boolean values:
+// 	res = n == wantTrue
+func Bvgen(n, res *Node, wantTrue bool) {
+	if Thearch.Ginsboolval == nil {
+		// Direct value generation not implemented for this architecture.
+		// Implement using jumps.
+		bvgenjump(n, res, wantTrue, true)
+		return
+	}
+	bgenx(n, res, wantTrue, 0, nil)
+}
+
+// bvgenjump implements boolean value generation using jumps:
+// 	if n == wantTrue {
+// 		res = 1
+// 	} else {
+// 		res = 0
+// 	}
+// geninit controls whether n's Ninit is generated.
+func bvgenjump(n, res *Node, wantTrue, geninit bool) {
+	init := n.Ninit
+	if !geninit {
+		n.Ninit = nil
+	}
+	p1 := Gbranch(obj.AJMP, nil, 0)
+	p2 := Pc
+	Thearch.Gmove(Nodbool(true), res)
+	p3 := Gbranch(obj.AJMP, nil, 0)
+	Patch(p1, Pc)
+	Bgen(n, wantTrue, 0, p2)
+	Thearch.Gmove(Nodbool(false), res)
+	Patch(p3, Pc)
+	n.Ninit = init
+}
+
+// bgenx is the backend for Bgen and Bvgen.
+// If res is nil, it generates a branch.
+// Otherwise, it generates a boolean value.
+func bgenx(n, res *Node, wantTrue bool, likely int, to *obj.Prog) {
+	if Debug['g'] != 0 {
+		fmt.Printf("\nbgenx wantTrue=%t likely=%d to=%v\n", wantTrue, likely, to)
+		Dump("n", n)
+		Dump("res", res)
+	}
+
+	genval := res != nil
+
+	if n == nil {
+		n = Nodbool(true)
+	}
+
+	Genlist(n.Ninit)
+
+	if n.Type == nil {
+		Convlit(&n, Types[TBOOL])
+		if n.Type == nil {
+			return
+		}
+	}
+
+	if n.Type.Etype != TBOOL {
+		Fatal("bgen: bad type %v for %v", n.Type, Oconv(int(n.Op), 0))
+	}
+
+	for n.Op == OCONVNOP {
+		n = n.Left
+		Genlist(n.Ninit)
+	}
+
+	if Thearch.Bgen_float != nil && n.Left != nil && Isfloat[n.Left.Type.Etype] {
+		if genval {
+			bvgenjump(n, res, wantTrue, false)
+			return
+		}
+		Thearch.Bgen_float(n, wantTrue, likely, to)
+		return
+	}
+
+	switch n.Op {
+	default:
+		if genval {
+			Cgen(n, res)
+			if !wantTrue {
+				Thearch.Gins(Thearch.Optoas(OXOR, Types[TUINT8]), Nodintconst(1), res)
+			}
+			return
+		}
+
+		var tmp Node
+		Regalloc(&tmp, n.Type, nil)
+		Cgen(n, &tmp)
+		bgenNonZero(&tmp, nil, wantTrue, likely, to)
+		Regfree(&tmp)
+		return
+
+	case ONAME:
+		if genval {
+			// 5g, 7g, and 9g might need a temporary or other help here,
+			// but they don't support direct generation of a bool value yet.
+			// We can fix that as we go.
+			switch Ctxt.Arch.Thechar {
+			case '5', '7', '9':
+				Fatal("genval 5g, 7g, 9g ONAMES not fully implemented")
+			}
+			Cgen(n, res)
+			if !wantTrue {
+				Thearch.Gins(Thearch.Optoas(OXOR, Types[TUINT8]), Nodintconst(1), res)
+			}
+			return
+		}
+
+		if n.Addable && Ctxt.Arch.Thechar != '5' && Ctxt.Arch.Thechar != '7' && Ctxt.Arch.Thechar != '9' {
+			// no need for a temporary
+			bgenNonZero(n, nil, wantTrue, likely, to)
+			return
+		}
+		var tmp Node
+		Regalloc(&tmp, n.Type, nil)
+		Cgen(n, &tmp)
+		bgenNonZero(&tmp, nil, wantTrue, likely, to)
+		Regfree(&tmp)
+		return
+
+	case OLITERAL:
+		// n is a constant.
+		if !Isconst(n, CTBOOL) {
+			Fatal("bgen: non-bool const %v\n", Nconv(n, obj.FmtLong))
+		}
+		if genval {
+			Cgen(Nodbool(wantTrue == n.Val().U.(bool)), res)
+			return
+		}
+		// If n == wantTrue, jump; otherwise do nothing.
+		if wantTrue == n.Val().U.(bool) {
+			Patch(Gbranch(obj.AJMP, nil, likely), to)
+		}
+		return
+
+	case OANDAND, OOROR:
+		and := (n.Op == OANDAND) == wantTrue
+		if genval {
+			p1 := Gbranch(obj.AJMP, nil, 0)
+			p2 := Gbranch(obj.AJMP, nil, 0)
+			Patch(p2, Pc)
+			Cgen(Nodbool(!and), res)
+			p3 := Gbranch(obj.AJMP, nil, 0)
+			Patch(p1, Pc)
+			Bgen(n.Left, wantTrue != and, 0, p2)
+			Bvgen(n.Right, res, wantTrue)
+			Patch(p3, Pc)
+			return
+		}
+
+		if and {
+			p1 := Gbranch(obj.AJMP, nil, 0)
+			p2 := Gbranch(obj.AJMP, nil, 0)
+			Patch(p1, Pc)
+			Bgen(n.Left, !wantTrue, -likely, p2)
+			Bgen(n.Right, !wantTrue, -likely, p2)
+			p1 = Gbranch(obj.AJMP, nil, 0)
+			Patch(p1, to)
+			Patch(p2, Pc)
+		} else {
+			Bgen(n.Left, wantTrue, likely, to)
+			Bgen(n.Right, wantTrue, likely, to)
+		}
+		return
+
+	case ONOT: // unary
+		if n.Left == nil || n.Left.Type == nil {
+			return
+		}
+		bgenx(n.Left, res, !wantTrue, likely, to)
+		return
+
+	case OEQ, ONE, OLT, OGT, OLE, OGE:
+		if n.Left == nil || n.Left.Type == nil || n.Right == nil || n.Right.Type == nil {
+			return
+		}
+	}
+
+	// n.Op is one of OEQ, ONE, OLT, OGT, OLE, OGE
+	nl := n.Left
+	nr := n.Right
+	a := int(n.Op)
+
+	if !wantTrue {
+		if Isfloat[nr.Type.Etype] {
+			// Brcom is not valid on floats when NaN is involved.
+			ll := n.Ninit // avoid re-genning Ninit
+			n.Ninit = nil
+			if genval {
+				bgenx(n, res, true, likely, to)
+				Thearch.Gins(Thearch.Optoas(OXOR, Types[TUINT8]), Nodintconst(1), res) // res = !res
+				n.Ninit = ll
+				return
+			}
+			p1 := Gbranch(obj.AJMP, nil, 0)
+			p2 := Gbranch(obj.AJMP, nil, 0)
+			Patch(p1, Pc)
+			bgenx(n, res, true, -likely, p2)
+			Patch(Gbranch(obj.AJMP, nil, 0), to)
+			Patch(p2, Pc)
+			n.Ninit = ll
+			return
+		}
+
+		a = Brcom(a)
+	}
+	wantTrue = true
+
+	// make simplest on right
+	if nl.Op == OLITERAL || (nl.Ullman < nr.Ullman && nl.Ullman < UINF) {
+		a = Brrev(a)
+		nl, nr = nr, nl
+	}
+
+	if Isslice(nl.Type) || Isinter(nl.Type) {
+		// front end should only leave cmp to literal nil
+		if (a != OEQ && a != ONE) || nr.Op != OLITERAL {
+			if Isslice(nl.Type) {
+				Yyerror("illegal slice comparison")
+			} else {
+				Yyerror("illegal interface comparison")
+			}
+			return
+		}
+
+		var ptr Node
+		Igen(nl, &ptr, nil)
+		if Isslice(nl.Type) {
+			ptr.Xoffset += int64(Array_array)
+		}
+		ptr.Type = Types[Tptr]
+		var tmp Node
+		Regalloc(&tmp, ptr.Type, &ptr)
+		Cgen(&ptr, &tmp)
+		Regfree(&ptr)
+		bgenNonZero(&tmp, res, a == OEQ != wantTrue, likely, to)
+		Regfree(&tmp)
+		return
+	}
+
+	if Iscomplex[nl.Type.Etype] {
+		complexbool(a, nl, nr, res, wantTrue, likely, to)
+		return
+	}
+
+	if Ctxt.Arch.Regsize == 4 && Is64(nr.Type) {
+		if genval {
+			// TODO: Teach Cmp64 to generate boolean values and remove this.
+			bvgenjump(n, res, wantTrue, false)
+			return
+		}
+		if !nl.Addable || Isconst(nl, CTINT) {
+			nl = CgenTemp(nl)
+		}
+		if !nr.Addable {
+			nr = CgenTemp(nr)
+		}
+		Thearch.Cmp64(nl, nr, a, likely, to)
+		return
+	}
+
+	if nr.Ullman >= UINF {
+		var n1 Node
+		Regalloc(&n1, nl.Type, nil)
+		Cgen(nl, &n1)
+		nl = &n1
+
+		var tmp Node
+		Tempname(&tmp, nl.Type)
+		Thearch.Gmove(&n1, &tmp)
+		Regfree(&n1)
+
+		var n2 Node
+		Regalloc(&n2, nr.Type, nil)
+		Cgen(nr, &n2)
+		nr = &n2
+
+		Regalloc(&n1, nl.Type, nil)
+		Cgen(&tmp, &n1)
+		Regfree(&n1)
+		Regfree(&n2)
+	} else {
+		var n1 Node
+		if !nl.Addable && Ctxt.Arch.Thechar == '8' {
+			Tempname(&n1, nl.Type)
+		} else {
+			Regalloc(&n1, nl.Type, nil)
+			defer Regfree(&n1)
+		}
+		Cgen(nl, &n1)
+		nl = &n1
+
+		if Smallintconst(nr) && Ctxt.Arch.Thechar != '9' {
+			Thearch.Gins(Thearch.Optoas(OCMP, nr.Type), nl, nr)
+			bins(nr.Type, res, a, likely, to)
+			return
+		}
+
+		if !nr.Addable && Ctxt.Arch.Thechar == '8' {
+			nr = CgenTemp(nr)
+		}
+
+		var n2 Node
+		Regalloc(&n2, nr.Type, nil)
+		Cgen(nr, &n2)
+		nr = &n2
+		Regfree(&n2)
+	}
+
+	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)
+	}
+
+	// Do the comparison.
+	Thearch.Gins(Thearch.Optoas(OCMP, nr.Type), l, r)
+
+	// Handle floating point special cases.
+	// Note that 8g has Bgen_float and is handled above.
+	if Isfloat[nl.Type.Etype] {
+		switch Ctxt.Arch.Thechar {
+		case '5':
+			if genval {
+				Fatal("genval 5g Isfloat special cases not implemented")
+			}
+			switch n.Op {
+			case ONE:
+				Patch(Gbranch(Thearch.Optoas(OPS, nr.Type), nr.Type, likely), to)
+				Patch(Gbranch(Thearch.Optoas(a, nr.Type), nr.Type, likely), to)
+			default:
+				p := Gbranch(Thearch.Optoas(OPS, nr.Type), nr.Type, -likely)
+				Patch(Gbranch(Thearch.Optoas(a, nr.Type), nr.Type, likely), to)
+				Patch(p, Pc)
+			}
+			return
+		case '6':
+			switch n.Op {
+			case OEQ:
+				// neither NE nor P
+				if genval {
+					var reg Node
+					Regalloc(&reg, Types[TBOOL], nil)
+					Thearch.Ginsboolval(Thearch.Optoas(OEQ, nr.Type), &reg)
+					Thearch.Ginsboolval(Thearch.Optoas(OPC, nr.Type), res)
+					Thearch.Gins(Thearch.Optoas(OAND, Types[TBOOL]), &reg, res)
+					Regfree(&reg)
+				} else {
+					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)
+				}
+				return
+			case ONE:
+				// either NE or P
+				if genval {
+					var reg Node
+					Regalloc(&reg, Types[TBOOL], nil)
+					Thearch.Ginsboolval(Thearch.Optoas(ONE, nr.Type), &reg)
+					Thearch.Ginsboolval(Thearch.Optoas(OPS, nr.Type), res)
+					Thearch.Gins(Thearch.Optoas(OOR, Types[TBOOL]), &reg, res)
+					Regfree(&reg)
+				} else {
+					Patch(Gbranch(Thearch.Optoas(ONE, nr.Type), nil, likely), to)
+					Patch(Gbranch(Thearch.Optoas(OPS, nr.Type), nil, likely), to)
+				}
+				return
+			}
+		case '7', '9':
+			if genval {
+				Fatal("genval 7g, 9g Isfloat special cases not implemented")
+			}
+			switch n.Op {
+			// On arm64 and ppc64, <= and >= mishandle NaN. Must decompose into < or > and =.
+			// TODO(josh): Convert a <= b to b > a instead?
+			case OLE, OGE:
+				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)
+				return
+			}
+		}
+	}
+
+	// Not a special case. Insert the conditional jump or value gen.
+	bins(nr.Type, res, a, likely, to)
+}
+
+func bgenNonZero(n, res *Node, wantTrue bool, likely int, to *obj.Prog) {
+	// TODO: Optimize on systems that can compare to zero easily.
+	a := ONE
+	if !wantTrue {
+		a = OEQ
+	}
+	var zero Node
+	Nodconst(&zero, n.Type, 0)
+	Thearch.Gins(Thearch.Optoas(OCMP, n.Type), n, &zero)
+	bins(n.Type, res, a, likely, to)
+}
+
+// bins inserts an instruction to handle the result of a compare.
+// If res is non-nil, it inserts appropriate value generation instructions.
+// If res is nil, it inserts a branch to to.
+func bins(typ *Type, res *Node, a, likely int, to *obj.Prog) {
+	a = Thearch.Optoas(a, typ)
+	if res != nil {
+		// value gen
+		Thearch.Ginsboolval(a, res)
+	} else {
+		// jump
+		Patch(Gbranch(a, typ, likely), to)
+	}
+}
+
+// stkof returns n's offset from SP if n is on the stack
+// (either a local variable or the return value from a function call
+// or the arguments to a function call).
+// If n is not on the stack, stkof returns -1000.
+// If n is on the stack but in an unknown location
+// (due to array index arithmetic), stkof returns +1000.
+//
+// NOTE(rsc): It is possible that the ODOT and OINDEX cases
+// are not relevant here, since it shouldn't be possible for them
+// to be involved in an overlapping copy. Only function results
+// from one call and the arguments to the next can overlap in
+// any non-trivial way. If they can be dropped, then this function
+// becomes much simpler and also more trustworthy.
+// The fact that it works at all today is probably due to the fact
+// that ODOT and OINDEX are irrelevant.
+func stkof(n *Node) int64 {
+	switch n.Op {
+	case OINDREG:
+		if n.Reg != int16(Thearch.REGSP) {
+			return -1000 // not on stack
+		}
+		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.(*Mpint))
+		}
+		return +1000 // on stack but not sure exactly where
+
+	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 // not on stack
+}
+
+/*
+ * block copy:
+ *	memmove(&ns, &n, w);
+ * if wb is true, needs write barrier.
+ */
+func sgen_wb(n *Node, ns *Node, w int64, wb bool) {
+	if Debug['g'] != 0 {
+		op := "sgen"
+		if wb {
+			op = "sgen-wb"
+		}
+		fmt.Printf("\n%s w=%d\n", op, 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_wb(n, ns, wb) {
+		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 odst != -1000 {
+		// on stack, write barrier not needed after all
+		wb = false
+	}
+
+	if osrc != -1000 && odst != -1000 && (osrc == 1000 || odst == 1000) || wb && osrc != -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.
+		//
+		// OR: write barrier needed and source is on stack.
+		// Invoking the write barrier will use the stack to prepare its call.
+		// Copy to temporary.
+		var tmp Node
+		Tempname(&tmp, n.Type)
+		sgen_wb(n, &tmp, w, false)
+		sgen_wb(&tmp, ns, w, wb)
+		return
+	}
+
+	if wb {
+		cgen_wbfat(n, ns)
+		return
+	}
+
+	Thearch.Blockcopy(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.Reg = int16(Thearch.REGSP)
+		stk.Xoffset = 0
+		if HasLinkRegister() {
+			stk.Xoffset += int64(Ctxt.Arch.Ptrsize)
+		}
+		Thearch.Ginscon(Thearch.Optoas(OAS, Types[TINT32]), 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)
+			p := Thearch.Ginscmp(OEQ, Types[TINT32], &reg, Nodintconst(0), +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 {
+		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.Name.Method = true
+
+	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.Reg = int16(Thearch.REGSP)
+	nod.Addable = true
+
+	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.Reg = int16(Thearch.REGSP)
+	nod1.Addable = true
+	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.(*Mpint)))
+		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.(*Mpint))
+		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.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
+	}
+}
+
+func cgen_append(n, res *Node) {
+	if Debug['g'] != 0 {
+		Dump("cgen_append-n", n)
+		Dump("cgen_append-res", res)
+	}
+	if res.Op != ONAME && !samesafeexpr(res, n.List.N) {
+		Dump("cgen_append-n", n)
+		Dump("cgen_append-res", res)
+		Fatal("append not lowered")
+	}
+	for l := n.List; l != nil; l = l.Next {
+		if l.N.Ullman >= UINF {
+			Fatal("append with function call arguments")
+		}
+	}
+
+	// res = append(src, x, y, z)
+	//
+	// If res and src are the same, we can avoid writing to base and cap
+	// unless we grow the underlying array.
+	needFullUpdate := !samesafeexpr(res, n.List.N)
+
+	// Copy src triple into base, len, cap.
+	base := temp(Types[Tptr])
+	len := temp(Types[TUINT])
+	cap := temp(Types[TUINT])
+
+	var src Node
+	Igen(n.List.N, &src, nil)
+	src.Type = Types[Tptr]
+	Thearch.Gmove(&src, base)
+	src.Type = Types[TUINT]
+	src.Xoffset += int64(Widthptr)
+	Thearch.Gmove(&src, len)
+	src.Xoffset += int64(Widthptr)
+	Thearch.Gmove(&src, cap)
+
+	// if len+argc <= cap goto L1
+	var rlen Node
+	Regalloc(&rlen, Types[TUINT], nil)
+	Thearch.Gmove(len, &rlen)
+	Thearch.Ginscon(Thearch.Optoas(OADD, Types[TUINT]), int64(count(n.List)-1), &rlen)
+	p := Thearch.Ginscmp(OLE, Types[TUINT], &rlen, cap, +1)
+	// Note: rlen and src are Regrealloc'ed below at the target of the
+	// branch we just emitted; do not reuse these Go variables for
+	// other purposes. They need to still describe the same things
+	// below that they describe right here.
+	Regfree(&src)
+
+	// base, len, cap = growslice(type, base, len, cap, newlen)
+	var arg Node
+	arg.Op = OINDREG
+	arg.Reg = int16(Thearch.REGSP)
+	arg.Addable = true
+	arg.Xoffset = 0
+	if HasLinkRegister() {
+		arg.Xoffset = int64(Ctxt.Arch.Ptrsize)
+	}
+	arg.Type = Ptrto(Types[TUINT8])
+	Cgen(typename(res.Type), &arg)
+	arg.Xoffset += int64(Widthptr)
+
+	arg.Type = Types[Tptr]
+	Cgen(base, &arg)
+	arg.Xoffset += int64(Widthptr)
+
+	arg.Type = Types[TUINT]
+	Cgen(len, &arg)
+	arg.Xoffset += int64(Widthptr)
+
+	arg.Type = Types[TUINT]
+	Cgen(cap, &arg)
+	arg.Xoffset += int64(Widthptr)
+
+	arg.Type = Types[TUINT]
+	Cgen(&rlen, &arg)
+	arg.Xoffset += int64(Widthptr)
+	Regfree(&rlen)
+
+	fn := syslook("growslice", 1)
+	substArgTypes(fn, res.Type.Type, res.Type.Type)
+	Ginscall(fn, 0)
+
+	if Widthptr == 4 && Widthreg == 8 {
+		arg.Xoffset += 4
+	}
+
+	arg.Type = Types[Tptr]
+	Cgen(&arg, base)
+	arg.Xoffset += int64(Widthptr)
+
+	arg.Type = Types[TUINT]
+	Cgen(&arg, len)
+	arg.Xoffset += int64(Widthptr)
+
+	arg.Type = Types[TUINT]
+	Cgen(&arg, cap)
+
+	// Update res with base, len+argc, cap.
+	if needFullUpdate {
+		if Debug_append > 0 {
+			Warn("append: full update")
+		}
+		Patch(p, Pc)
+	}
+	if res.Op == ONAME {
+		Gvardef(res)
+	}
+	var dst, r1 Node
+	Igen(res, &dst, nil)
+	dst.Type = Types[TUINT]
+	dst.Xoffset += int64(Widthptr)
+	Regalloc(&r1, Types[TUINT], nil)
+	Thearch.Gmove(len, &r1)
+	Thearch.Ginscon(Thearch.Optoas(OADD, Types[TUINT]), int64(count(n.List)-1), &r1)
+	Thearch.Gmove(&r1, &dst)
+	Regfree(&r1)
+	dst.Xoffset += int64(Widthptr)
+	Thearch.Gmove(cap, &dst)
+	dst.Type = Types[Tptr]
+	dst.Xoffset -= 2 * int64(Widthptr)
+	cgen_wb(base, &dst, needwritebarrier(&dst, base))
+	Regfree(&dst)
+
+	if !needFullUpdate {
+		if Debug_append > 0 {
+			Warn("append: len-only update")
+		}
+		// goto L2;
+		// L1:
+		//	update len only
+		// L2:
+		q := Gbranch(obj.AJMP, nil, 0)
+		Patch(p, Pc)
+		// At the goto above, src refers to cap and rlen holds the new len
+		if src.Op == OREGISTER || src.Op == OINDREG {
+			Regrealloc(&src)
+		}
+		Regrealloc(&rlen)
+		src.Xoffset -= int64(Widthptr)
+		Thearch.Gmove(&rlen, &src)
+		Regfree(&src)
+		Regfree(&rlen)
+		Patch(q, Pc)
+	}
+
+	// Copy data into place.
+	// Could do write barrier check around entire copy instead of each element.
+	// Could avoid reloading registers on each iteration if we know the cgen_wb
+	// is not going to use a write barrier.
+	i := 0
+	var r2 Node
+	for l := n.List.Next; l != nil; l = l.Next {
+		Regalloc(&r1, Types[Tptr], nil)
+		Thearch.Gmove(base, &r1)
+		Regalloc(&r2, Types[TUINT], nil)
+		Thearch.Gmove(len, &r2)
+		if i > 0 {
+			Thearch.Gins(Thearch.Optoas(OADD, Types[TUINT]), Nodintconst(int64(i)), &r2)
+		}
+		w := res.Type.Type.Width
+		if Thearch.AddIndex != nil && Thearch.AddIndex(&r2, w, &r1) {
+			// r1 updated by back end
+		} else if w == 1 {
+			Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &r2, &r1)
+		} else {
+			Thearch.Ginscon(Thearch.Optoas(OMUL, Types[TUINT]), int64(w), &r2)
+			Thearch.Gins(Thearch.Optoas(OADD, Types[Tptr]), &r2, &r1)
+		}
+		Regfree(&r2)
+
+		r1.Op = OINDREG
+		r1.Type = res.Type.Type
+		cgen_wb(l.N, &r1, needwritebarrier(&r1, l.N))
+		Regfree(&r1)
+		i++
+	}
+}
+
+// Generate res = n, where n is x[i:j] or x[i:j:k].
+// If wb is true, need write barrier updating res's base pointer.
+// On systems with 32-bit ints, i, j, k are guaranteed to be 32-bit values.
+func cgen_slice(n, res *Node, wb bool) {
+	if Debug['g'] != 0 {
+		Dump("cgen_slice-n", n)
+		Dump("cgen_slice-res", res)
+	}
+
+	needFullUpdate := !samesafeexpr(n.Left, res)
+
+	// orderexpr has made sure that x is safe (but possibly expensive)
+	// and i, j, k are cheap. On a system with registers (anything but 386)
+	// we can evaluate x first and then know we have enough registers
+	// for i, j, k as well.
+	var x, xbase, xlen, xcap, i, j, k Node
+	if n.Op != OSLICEARR && n.Op != OSLICE3ARR {
+		Igen(n.Left, &x, nil)
+	}
+
+	indexRegType := Types[TUINT]
+	if Widthreg > Widthptr { // amd64p32
+		indexRegType = Types[TUINT64]
+	}
+
+	// On most systems, we use registers.
+	// The 386 has basically no registers, so substitute functions
+	// that can work with temporaries instead.
+	regalloc := Regalloc
+	ginscon := Thearch.Ginscon
+	gins := Thearch.Gins
+	if Thearch.Thechar == '8' {
+		regalloc = func(n *Node, t *Type, reuse *Node) {
+			Tempname(n, t)
+		}
+		ginscon = func(as int, c int64, n *Node) {
+			var n1 Node
+			Regalloc(&n1, n.Type, n)
+			Thearch.Gmove(n, &n1)
+			Thearch.Ginscon(as, c, &n1)
+			Thearch.Gmove(&n1, n)
+			Regfree(&n1)
+		}
+		gins = func(as int, f, t *Node) *obj.Prog {
+			var n1 Node
+			Regalloc(&n1, t.Type, t)
+			Thearch.Gmove(t, &n1)
+			Thearch.Gins(as, f, &n1)
+			Thearch.Gmove(&n1, t)
+			Regfree(&n1)
+			return nil
+		}
+	}
+
+	panics := make([]*obj.Prog, 0, 6) // 3 loads + 3 checks
+
+	loadlen := func() {
+		if xlen.Op != 0 {
+			return
+		}
+		if n.Op == OSLICEARR || n.Op == OSLICE3ARR {
+			Nodconst(&xlen, indexRegType, n.Left.Type.Type.Bound)
+			return
+		}
+		if n.Op == OSLICESTR && Isconst(n.Left, CTSTR) {
+			Nodconst(&xlen, indexRegType, int64(len(n.Left.Val().U.(string))))
+			return
+		}
+		regalloc(&xlen, indexRegType, nil)
+		x.Xoffset += int64(Widthptr)
+		x.Type = Types[TUINT]
+		Thearch.Gmove(&x, &xlen)
+		x.Xoffset -= int64(Widthptr)
+	}
+
+	loadcap := func() {
+		if xcap.Op != 0 {
+			return
+		}
+		if n.Op == OSLICEARR || n.Op == OSLICE3ARR || n.Op == OSLICESTR {
+			loadlen()
+			xcap = xlen
+			if xcap.Op == OREGISTER {
+				Regrealloc(&xcap)
+			}
+			return
+		}
+		regalloc(&xcap, indexRegType, nil)
+		x.Xoffset += 2 * int64(Widthptr)
+		x.Type = Types[TUINT]
+		Thearch.Gmove(&x, &xcap)
+		x.Xoffset -= 2 * int64(Widthptr)
+	}
+
+	var x1, x2, x3 *Node // unevaluated index arguments
+	x1 = n.Right.Left
+	switch n.Op {
+	default:
+		x2 = n.Right.Right
+	case OSLICE3, OSLICE3ARR:
+		x2 = n.Right.Right.Left
+		x3 = n.Right.Right.Right
+	}
+
+	// load computes src into targ, but if src refers to the len or cap of n.Left,
+	// load copies those from xlen, xcap, loading xlen if needed.
+	// If targ.Op == OREGISTER on return, it must be Regfreed,
+	// but it should not be modified without first checking whether it is
+	// xlen or xcap's register.
+	load := func(src, targ *Node) {
+		if src == nil {
+			return
+		}
+		switch src.Op {
+		case OLITERAL:
+			*targ = *src
+			return
+		case OLEN:
+			// NOTE(rsc): This doesn't actually trigger, because order.go
+			// has pulled all the len and cap calls into separate assignments
+			// to temporaries. There are tests in test/sliceopt.go that could
+			// be enabled if this is fixed.
+			if samesafeexpr(n.Left, src.Left) {
+				if Debug_slice > 0 {
+					Warn("slice: reuse len")
+				}
+				loadlen()
+				*targ = xlen
+				if targ.Op == OREGISTER {
+					Regrealloc(targ)
+				}
+				return
+			}
+		case OCAP:
+			// NOTE(rsc): This doesn't actually trigger; see note in case OLEN above.
+			if samesafeexpr(n.Left, src.Left) {
+				if Debug_slice > 0 {
+					Warn("slice: reuse cap")
+				}
+				loadcap()
+				*targ = xcap
+				if targ.Op == OREGISTER {
+					Regrealloc(targ)
+				}
+				return
+			}
+		}
+		if i.Op != 0 && samesafeexpr(x1, src) {
+			if Debug_slice > 0 {
+				Warn("slice: reuse 1st index")
+			}
+			*targ = i
+			if targ.Op == OREGISTER {
+				Regrealloc(targ)
+			}
+			return
+		}
+		if j.Op != 0 && samesafeexpr(x2, src) {
+			if Debug_slice > 0 {
+				Warn("slice: reuse 2nd index")
+			}
+			*targ = j
+			if targ.Op == OREGISTER {
+				Regrealloc(targ)
+			}
+			return
+		}
+		if Thearch.Cgenindex != nil {
+			regalloc(targ, indexRegType, nil)
+			p := Thearch.Cgenindex(src, targ, false)
+			if p != nil {
+				panics = append(panics, p)
+			}
+		} else if Thearch.Igenindex != nil {
+			p := Thearch.Igenindex(src, targ, false)
+			if p != nil {
+				panics = append(panics, p)
+			}
+		} else {
+			regalloc(targ, indexRegType, nil)
+			var tmp Node
+			Cgenr(src, &tmp, targ)
+			Thearch.Gmove(&tmp, targ)
+			Regfree(&tmp)
+		}
+	}
+
+	load(x1, &i)
+	load(x2, &j)
+	load(x3, &k)
+
+	// i defaults to 0.
+	if i.Op == 0 {
+		Nodconst(&i, indexRegType, 0)
+	}
+
+	// j defaults to len(x)
+	if j.Op == 0 {
+		loadlen()
+		j = xlen
+		if j.Op == OREGISTER {
+			Regrealloc(&j)
+		}
+	}
+
+	// k defaults to cap(x)
+	// Only need to load it if we're recalculating cap or doing a full update.
+	if k.Op == 0 && n.Op != OSLICESTR && (!iszero(&i) || needFullUpdate) {
+		loadcap()
+		k = xcap
+		if k.Op == OREGISTER {
+			Regrealloc(&k)
+		}
+	}
+
+	// Check constant indexes for negative values, and against constant length if known.
+	// The func obvious below checks for out-of-order constant indexes.
+	var bound int64 = -1
+	if n.Op == OSLICEARR || n.Op == OSLICE3ARR {
+		bound = n.Left.Type.Type.Bound
+	} else if n.Op == OSLICESTR && Isconst(n.Left, CTSTR) {
+		bound = int64(len(n.Left.Val().U.(string)))
+	}
+	if Isconst(&i, CTINT) {
+		if mpcmpfixc(i.Val().U.(*Mpint), 0) < 0 || bound >= 0 && mpcmpfixc(i.Val().U.(*Mpint), bound) > 0 {
+			Yyerror("slice index out of bounds")
+		}
+	}
+	if Isconst(&j, CTINT) {
+		if mpcmpfixc(j.Val().U.(*Mpint), 0) < 0 || bound >= 0 && mpcmpfixc(j.Val().U.(*Mpint), bound) > 0 {
+			Yyerror("slice index out of bounds")
+		}
+	}
+	if Isconst(&k, CTINT) {
+		if mpcmpfixc(k.Val().U.(*Mpint), 0) < 0 || bound >= 0 && mpcmpfixc(k.Val().U.(*Mpint), bound) > 0 {
+			Yyerror("slice index out of bounds")
+		}
+	}
+
+	// same reports whether n1 and n2 are the same register or constant.
+	same := func(n1, n2 *Node) bool {
+		return n1.Op == OREGISTER && n2.Op == OREGISTER && n1.Reg == n2.Reg ||
+			n1.Op == ONAME && n2.Op == ONAME && n1.Orig == n2.Orig && n1.Type == n2.Type && n1.Xoffset == n2.Xoffset ||
+			n1.Op == OLITERAL && n2.Op == OLITERAL && Mpcmpfixfix(n1.Val().U.(*Mpint), n2.Val().U.(*Mpint)) == 0
+	}
+
+	// obvious reports whether n1 <= n2 is obviously true,
+	// and it calls Yyerror if n1 <= n2 is obviously false.
+	obvious := func(n1, n2 *Node) bool {
+		if Debug['B'] != 0 { // -B disables bounds checks
+			return true
+		}
+		if same(n1, n2) {
+			return true // n1 == n2
+		}
+		if iszero(n1) {
+			return true // using unsigned compare, so 0 <= n2 always true
+		}
+		if xlen.Op != 0 && same(n1, &xlen) && xcap.Op != 0 && same(n2, &xcap) {
+			return true // len(x) <= cap(x) always true
+		}
+		if Isconst(n1, CTINT) && Isconst(n2, CTINT) {
+			if Mpcmpfixfix(n1.Val().U.(*Mpint), n2.Val().U.(*Mpint)) <= 0 {
+				return true // n1, n2 constants such that n1 <= n2
+			}
+			Yyerror("slice index out of bounds")
+			return true
+		}
+		return false
+	}
+
+	compare := func(n1, n2 *Node) {
+		// n1 might be a 64-bit constant, even on 32-bit architectures,
+		// but it will be represented in 32 bits.
+		if Ctxt.Arch.Regsize == 4 && Is64(n1.Type) {
+			if mpcmpfixc(n1.Val().U.(*Mpint), 1<<31) >= 0 {
+				Fatal("missed slice out of bounds check")
+			}
+			var tmp Node
+			Nodconst(&tmp, indexRegType, Mpgetfix(n1.Val().U.(*Mpint)))
+			n1 = &tmp
+		}
+		p := Thearch.Ginscmp(OGT, indexRegType, n1, n2, -1)
+		panics = append(panics, p)
+	}
+
+	loadcap()
+	max := &xcap
+	if k.Op != 0 && (n.Op == OSLICE3 || n.Op == OSLICE3ARR) {
+		if obvious(&k, max) {
+			if Debug_slice > 0 {
+				Warn("slice: omit check for 3rd index")
+			}
+		} else {
+			compare(&k, max)
+		}
+		max = &k
+	}
+	if j.Op != 0 {
+		if obvious(&j, max) {
+			if Debug_slice > 0 {
+				Warn("slice: omit check for 2nd index")
+			}
+		} else {
+			compare(&j, max)
+		}
+		max = &j
+	}
+	if i.Op != 0 {
+		if obvious(&i, max) {
+			if Debug_slice > 0 {
+				Warn("slice: omit check for 1st index")
+			}
+		} else {
+			compare(&i, max)
+		}
+		max = &i
+	}
+	if k.Op != 0 && i.Op != 0 {
+		obvious(&i, &k) // emit compile-time error for x[3:n:2]
+	}
+
+	if len(panics) > 0 {
+		p := Gbranch(obj.AJMP, nil, 0)
+		for _, q := range panics {
+			Patch(q, Pc)
+		}
+		Ginscall(panicslice, -1)
+		Patch(p, Pc)
+	}
+
+	// Checks are done.
+	// Compute new len as j-i, cap as k-i.
+	// If i and j are same register, len is constant 0.
+	// If i and k are same register, cap is constant 0.
+	// If j and k are same register, len and cap are same.
+
+	// Done with xlen and xcap.
+	// Now safe to modify j and k even if they alias xlen, xcap.
+	if xlen.Op == OREGISTER {
+		Regfree(&xlen)
+	}
+	if xcap.Op == OREGISTER {
+		Regfree(&xcap)
+	}
+
+	// are j and k the same value?
+	sameJK := same(&j, &k)
+
+	if i.Op != 0 {
+		// j -= i
+		if same(&i, &j) {
+			if Debug_slice > 0 {
+				Warn("slice: result len == 0")
+			}
+			if j.Op == OREGISTER {
+				Regfree(&j)
+			}
+			Nodconst(&j, indexRegType, 0)
+		} else {
+			switch j.Op {
+			case OLITERAL:
+				if Isconst(&i, CTINT) {
+					Nodconst(&j, indexRegType, Mpgetfix(j.Val().U.(*Mpint))-Mpgetfix(i.Val().U.(*Mpint)))
+					if Debug_slice > 0 {
+						Warn("slice: result len == %d", Mpgetfix(j.Val().U.(*Mpint)))
+					}
+					break
+				}
+				fallthrough
+			case ONAME:
+				if !istemp(&j) {
+					var r Node
+					regalloc(&r, indexRegType, nil)
+					Thearch.Gmove(&j, &r)
+					j = r
+				}
+				fallthrough
+			case OREGISTER:
+				if i.Op == OLITERAL {
+					v := Mpgetfix(i.Val().U.(*Mpint))
+					if v != 0 {
+						ginscon(Thearch.Optoas(OSUB, indexRegType), v, &j)
+					}
+				} else {
+					gins(Thearch.Optoas(OSUB, indexRegType), &i, &j)
+				}
+			}
+		}
+
+		// k -= i if k different from j and cap is needed.j
+		// (The modifications to j above cannot affect i: if j and i were aliased,
+		// we replace j with a constant 0 instead of doing a subtraction,
+		// leaving i unmodified.)
+		if k.Op == 0 {
+			if Debug_slice > 0 && n.Op != OSLICESTR {
+				Warn("slice: result cap not computed")
+			}
+			// no need
+		} else if same(&i, &k) {
+			if k.Op == OREGISTER {
+				Regfree(&k)
+			}
+			Nodconst(&k, indexRegType, 0)
+			if Debug_slice > 0 {
+				Warn("slice: result cap == 0")
+			}
+		} else if sameJK {
+			if Debug_slice > 0 {
+				Warn("slice: result cap == result len")
+			}
+			// k and j were the same value; make k-i the same as j-i.
+			if k.Op == OREGISTER {
+				Regfree(&k)
+			}
+			k = j
+			if k.Op == OREGISTER {
+				Regrealloc(&k)
+			}
+		} else {
+			switch k.Op {
+			case OLITERAL:
+				if Isconst(&i, CTINT) {
+					Nodconst(&k, indexRegType, Mpgetfix(k.Val().U.(*Mpint))-Mpgetfix(i.Val().U.(*Mpint)))
+					if Debug_slice > 0 {
+						Warn("slice: result cap == %d", Mpgetfix(k.Val().U.(*Mpint)))
+					}
+					break
+				}
+				fallthrough
+			case ONAME:
+				if !istemp(&k) {
+					var r Node
+					regalloc(&r, indexRegType, nil)
+					Thearch.Gmove(&k, &r)
+					k = r
+				}
+				fallthrough
+			case OREGISTER:
+				if same(&i, &k) {
+					Regfree(&k)
+					Nodconst(&k, indexRegType, 0)
+					if Debug_slice > 0 {
+						Warn("slice: result cap == 0")
+					}
+				} else if i.Op == OLITERAL {
+					v := Mpgetfix(i.Val().U.(*Mpint))
+					if v != 0 {
+						ginscon(Thearch.Optoas(OSUB, indexRegType), v, &k)
+					}
+				} else {
+					gins(Thearch.Optoas(OSUB, indexRegType), &i, &k)
+				}
+			}
+		}
+	}
+
+	adjustBase := true
+	if i.Op == 0 || iszero(&i) {
+		if Debug_slice > 0 {
+			Warn("slice: skip base adjustment for 1st index 0")
+		}
+		adjustBase = false
+	} else if k.Op != 0 && iszero(&k) || k.Op == 0 && iszero(&j) {
+		if Debug_slice > 0 {
+			if n.Op == OSLICESTR {
+				Warn("slice: skip base adjustment for string len == 0")
+			} else {
+				Warn("slice: skip base adjustment for cap == 0")
+			}
+		}
+		adjustBase = false
+	}
+
+	if !adjustBase && !needFullUpdate {
+		if Debug_slice > 0 {
+			if k.Op != 0 {
+				Warn("slice: len/cap-only update")
+			} else {
+				Warn("slice: len-only update")
+			}
+		}
+		if i.Op == OREGISTER {
+			Regfree(&i)
+		}
+		// Write len (and cap if needed) back to x.
+		x.Xoffset += int64(Widthptr)
+		x.Type = Types[TUINT]
+		Thearch.Gmove(&j, &x)
+		x.Xoffset -= int64(Widthptr)
+		if k.Op != 0 {
+			x.Xoffset += 2 * int64(Widthptr)
+			x.Type = Types[TUINT]
+			Thearch.Gmove(&k, &x)
+			x.Xoffset -= 2 * int64(Widthptr)
+		}
+		Regfree(&x)
+	} else {
+		// Compute new base. May smash i.
+		if n.Op == OSLICEARR || n.Op == OSLICE3ARR {
+			Cgenr(n.Left, &xbase, nil)
+			Cgen_checknil(&xbase)
+		} else {
+			regalloc(&xbase, Ptrto(res.Type.Type), nil)
+			x.Type = xbase.Type
+			Thearch.Gmove(&x, &xbase)
+			Regfree(&x)
+		}
+		if i.Op != 0 && adjustBase {
+			// Branch around the base adjustment if the resulting cap will be 0.
+			var p *obj.Prog
+			size := &k
+			if k.Op == 0 {
+				size = &j
+			}
+			if Isconst(size, CTINT) {
+				// zero was checked above, must be non-zero.
+			} else {
+				var tmp Node
+				Nodconst(&tmp, indexRegType, 0)
+				p = Thearch.Ginscmp(OEQ, indexRegType, size, &tmp, -1)
+			}
+			var w int64
+			if n.Op == OSLICESTR {
+				w = 1 // res is string, elem size is 1 (byte)
+			} else {
+				w = res.Type.Type.Width // res is []T, elem size is T.width
+			}
+			if Isconst(&i, CTINT) {
+				ginscon(Thearch.Optoas(OADD, xbase.Type), Mpgetfix(i.Val().U.(*Mpint))*w, &xbase)
+			} else if Thearch.AddIndex != nil && Thearch.AddIndex(&i, w, &xbase) {
+				// done by back end
+			} else if w == 1 {
+				gins(Thearch.Optoas(OADD, xbase.Type), &i, &xbase)
+			} else {
+				if i.Op == ONAME && !istemp(&i) {
+					var tmp Node
+					Tempname(&tmp, i.Type)
+					Thearch.Gmove(&i, &tmp)
+					i = tmp
+				}
+				ginscon(Thearch.Optoas(OMUL, i.Type), w, &i)
+				gins(Thearch.Optoas(OADD, xbase.Type), &i, &xbase)
+			}
+			if p != nil {
+				Patch(p, Pc)
+			}
+		}
+		if i.Op == OREGISTER {
+			Regfree(&i)
+		}
+
+		// Write len, cap, base to result.
+		if res.Op == ONAME {
+			Gvardef(res)
+		}
+		Igen(res, &x, nil)
+		x.Xoffset += int64(Widthptr)
+		x.Type = Types[TUINT]
+		Thearch.Gmove(&j, &x)
+		x.Xoffset -= int64(Widthptr)
+		if k.Op != 0 {
+			x.Xoffset += 2 * int64(Widthptr)
+			Thearch.Gmove(&k, &x)
+			x.Xoffset -= 2 * int64(Widthptr)
+		}
+		x.Type = xbase.Type
+		cgen_wb(&xbase, &x, wb)
+		Regfree(&xbase)
+		Regfree(&x)
+	}
+
+	if j.Op == OREGISTER {
+		Regfree(&j)
+	}
+	if k.Op == OREGISTER {
+		Regfree(&k)
+	}
+}
diff --git a/src/cmd/compile/internal/gc/closure.go b/src/cmd/compile/internal/gc/closure.go
new file mode 100644
index 0000000..a0dfa0b
--- /dev/null
+++ b/src/cmd/compile/internal/gc/closure.go
@@ -0,0 +1,690 @@
+// 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"
+)
+
+/*
+ * function literals aka closures
+ */
+func closurehdr(ntype *Node) {
+	var name *Node
+	var a *Node
+
+	n := Nod(OCLOSURE, nil, nil)
+	n.Func.Ntype = ntype
+	n.Func.Depth = Funcdepth
+	n.Func.Outerfunc = Curfn
+
+	funchdr(n)
+
+	// steal ntype's argument names and
+	// leave a fresh copy in their place.
+	// references to these variables need to
+	// refer to the variables in the external
+	// function declared below; see walkclosure.
+	n.List = ntype.List
+
+	n.Rlist = ntype.Rlist
+	ntype.List = nil
+	ntype.Rlist = nil
+	for l := n.List; l != nil; l = l.Next {
+		name = l.N.Left
+		if name != nil {
+			name = newname(name.Sym)
+		}
+		a = Nod(ODCLFIELD, name, l.N.Right)
+		a.Isddd = l.N.Isddd
+		if name != nil {
+			name.Isddd = a.Isddd
+		}
+		ntype.List = list(ntype.List, a)
+	}
+
+	for l := n.Rlist; l != nil; l = l.Next {
+		name = l.N.Left
+		if name != nil {
+			name = newname(name.Sym)
+		}
+		ntype.Rlist = list(ntype.Rlist, Nod(ODCLFIELD, name, l.N.Right))
+	}
+}
+
+func closurebody(body *NodeList) *Node {
+	if body == nil {
+		body = list1(Nod(OEMPTY, nil, nil))
+	}
+
+	func_ := Curfn
+	func_.Nbody = body
+	func_.Func.Endlineno = lineno
+	funcbody(func_)
+
+	// closure-specific variables are hanging off the
+	// ordinary ones in the symbol table; see oldname.
+	// unhook them.
+	// make the list of pointers for the closure call.
+	var v *Node
+	for l := func_.Func.Cvars; l != nil; l = l.Next {
+		v = l.N
+		v.Name.Param.Closure.Name.Param.Closure = v.Name.Param.Outer
+		v.Name.Param.Outerexpr = oldname(v.Sym)
+	}
+
+	return func_
+}
+
+func typecheckclosure(func_ *Node, top int) {
+	var n *Node
+
+	for l := func_.Func.Cvars; l != nil; l = l.Next {
+		n = l.N.Name.Param.Closure
+		if !n.Name.Captured {
+			n.Name.Captured = true
+			if n.Name.Decldepth == 0 {
+				Fatal("typecheckclosure: var %v does not have decldepth assigned", Nconv(n, obj.FmtShort))
+			}
+
+			// Ignore assignments to the variable in straightline code
+			// preceding the first capturing by a closure.
+			if n.Name.Decldepth == decldepth {
+				n.Assigned = false
+			}
+		}
+	}
+
+	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.Name.Decldepth = 1
+		}
+	}
+
+	oldfn := Curfn
+	typecheck(&func_.Func.Ntype, Etype)
+	func_.Type = func_.Func.Ntype.Type
+	func_.Func.Top = top
+
+	// Type check the body now, but only if we're inside a function.
+	// At top level (in a variable initialization: curfn==nil) we're not
+	// ready to type check code yet; we'll check it later, because the
+	// underlying closure function we create is added to xtop.
+	if Curfn != nil && func_.Type != nil {
+		Curfn = func_
+		olddd := decldepth
+		decldepth = 1
+		typechecklist(func_.Nbody, Etop)
+		decldepth = olddd
+		Curfn = oldfn
+	}
+
+	// Create top-level function
+	xtop = list(xtop, makeclosure(func_))
+}
+
+// closurename returns name for OCLOSURE n.
+// It is not as simple as it ought to be, because we typecheck nested closures
+// starting from the innermost one. So when we check the inner closure,
+// we don't yet have name for the outer closure. This function uses recursion
+// to generate names all the way up if necessary.
+
+var closurename_closgen int
+
+func closurename(n *Node) *Sym {
+	if n.Sym != nil {
+		return n.Sym
+	}
+	gen := 0
+	outer := ""
+	prefix := ""
+	if n.Func.Outerfunc == nil {
+		// Global closure.
+		outer = "glob"
+
+		prefix = "func"
+		closurename_closgen++
+		gen = closurename_closgen
+	} else if n.Func.Outerfunc.Op == ODCLFUNC {
+		// The outermost closure inside of a named function.
+		outer = n.Func.Outerfunc.Func.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.Func.Outerfunc.Func.Nname) {
+			n.Func.Outerfunc.Func.Closgen++
+			gen = n.Func.Outerfunc.Func.Closgen
+		} else {
+			closurename_closgen++
+			gen = closurename_closgen
+		}
+	} else if n.Func.Outerfunc.Op == OCLOSURE {
+		// Nested closure, recurse.
+		outer = closurename(n.Func.Outerfunc).Name
+
+		prefix = ""
+		n.Func.Outerfunc.Func.Closgen++
+		gen = n.Func.Outerfunc.Func.Closgen
+	} else {
+		Fatal("closurename called for %v", Nconv(n, obj.FmtShort))
+	}
+	n.Sym = Lookupf("%s.%s%d", outer, prefix, gen)
+	return n.Sym
+}
+
+func makeclosure(func_ *Node) *Node {
+	/*
+	 * wrap body in external function
+	 * that begins by reading closure parameters.
+	 */
+	xtype := Nod(OTFUNC, nil, nil)
+
+	xtype.List = func_.List
+	xtype.Rlist = func_.Rlist
+
+	// create the function
+	xfunc := Nod(ODCLFUNC, nil, nil)
+
+	xfunc.Func.Nname = newfuncname(closurename(func_))
+	xfunc.Func.Nname.Sym.Flags |= SymExported // disable export
+	xfunc.Func.Nname.Name.Param.Ntype = xtype
+	xfunc.Func.Nname.Name.Defn = xfunc
+	declare(xfunc.Func.Nname, PFUNC)
+	xfunc.Func.Nname.Name.Funcdepth = func_.Func.Depth
+	xfunc.Func.Depth = func_.Func.Depth
+	xfunc.Func.Endlineno = func_.Func.Endlineno
+	makefuncsym(xfunc.Func.Nname.Sym)
+
+	xfunc.Nbody = func_.Nbody
+	xfunc.Func.Dcl = concat(func_.Func.Dcl, xfunc.Func.Dcl)
+	if xfunc.Nbody == nil {
+		Fatal("empty body - won't generate any code")
+	}
+	typecheck(&xfunc, Etop)
+
+	xfunc.Func.Closure = func_
+	func_.Func.Closure = xfunc
+
+	func_.Nbody = nil
+	func_.List = nil
+	func_.Rlist = nil
+
+	return xfunc
+}
+
+// capturevars is called in a separate phase after all typechecking is done.
+// It decides whether each variable captured by a closure should be captured
+// by value or by reference.
+// We use value capturing for values <= 128 bytes that are never reassigned
+// after capturing (effectively constant).
+func capturevars(xfunc *Node) {
+	var v *Node
+	var outer *Node
+
+	lno := int(lineno)
+	lineno = xfunc.Lineno
+
+	func_ := xfunc.Func.Closure
+	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
+			// going to be used in the closure but wasn't.
+			// this happens because when parsing a, b, c := f()
+			// the a, b, c gets parsed as references to older
+			// a, b, c before the parser figures out this is a
+			// declaration.
+			v.Op = OXXX
+
+			continue
+		}
+
+		// type check the & of closed variables outside the closure,
+		// so that the outer frame also grabs them and knows they escape.
+		dowidth(v.Type)
+
+		outer = v.Name.Param.Outerexpr
+		v.Name.Param.Outerexpr = nil
+
+		// out parameters will be assigned to implicitly upon return.
+		if outer.Class != PPARAMOUT && !v.Name.Param.Closure.Addrtaken && !v.Name.Param.Closure.Assigned && v.Type.Width <= 128 {
+			v.Name.Byval = true
+		} else {
+			v.Name.Param.Closure.Addrtaken = true
+			outer = Nod(OADDR, outer, nil)
+		}
+
+		if Debug['m'] > 1 {
+			var name *Sym
+			if v.Name.Curfn != nil && v.Name.Curfn.Func.Nname != nil {
+				name = v.Name.Curfn.Func.Nname.Sym
+			}
+			how := "ref"
+			if v.Name.Byval {
+				how = "value"
+			}
+			Warnl(int(v.Lineno), "%v capturing by %s: %v (addr=%v assign=%v width=%d)", name, how, v.Sym, v.Name.Param.Closure.Addrtaken, v.Name.Param.Closure.Assigned, int32(v.Type.Width))
+		}
+
+		typecheck(&outer, Erv)
+		func_.Func.Enter = list(func_.Func.Enter, outer)
+	}
+
+	lineno = int32(lno)
+}
+
+// transformclosure is called in a separate phase after escape analysis.
+// It transform closure bodies to properly reference captured variables.
+func transformclosure(xfunc *Node) {
+	lno := int(lineno)
+	lineno = xfunc.Lineno
+	func_ := xfunc.Func.Closure
+
+	if func_.Func.Top&Ecall != 0 {
+		// If the closure is directly called, we transform it to a plain function call
+		// with variables passed as args. This avoids allocation of a closure object.
+		// Here we do only a part of the transformation. Walk of OCALLFUNC(OCLOSURE)
+		// will complete the transformation later.
+		// For illustration, the following closure:
+		//	func(a int) {
+		//		println(byval)
+		//		byref++
+		//	}(42)
+		// becomes:
+		//	func(a int, byval int, &byref *int) {
+		//		println(byval)
+		//		(*&byref)++
+		//	}(byval, &byref, 42)
+
+		// f is ONAME of the actual function.
+		f := xfunc.Func.Nname
+
+		// Get pointer to input arguments.
+		// We are going to insert captured variables before input args.
+		param := &getinargx(f.Type).Type
+		original_args := *param // old input args
+		original_dcl := xfunc.Func.Dcl
+		xfunc.Func.Dcl = nil
+
+		var v *Node
+		var addr *Node
+		var fld *Type
+		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.Name.Byval {
+				// If v is captured by value, we merely downgrade it to PPARAM.
+				v.Class = PPARAM
+
+				v.Ullman = 1
+				fld.Nname = v
+			} else {
+				// If v of type T is captured by reference,
+				// we introduce function param &v *T
+				// and v remains PPARAMREF with &v heapaddr
+				// (accesses will implicitly deref &v).
+				addr = newname(Lookupf("&%s", v.Sym.Name))
+				addr.Type = Ptrto(v.Type)
+				addr.Class = PPARAM
+				v.Name.Heapaddr = addr
+				fld.Nname = addr
+			}
+
+			fld.Type = fld.Nname.Type
+			fld.Sym = fld.Nname.Sym
+
+			// Declare the new param and add it the first part of the input arguments.
+			xfunc.Func.Dcl = list(xfunc.Func.Dcl, fld.Nname)
+
+			*param = fld
+			param = &fld.Down
+		}
+		*param = original_args
+		xfunc.Func.Dcl = concat(xfunc.Func.Dcl, original_dcl)
+
+		// Recalculate param offsets.
+		if f.Type.Width > 0 {
+			Fatal("transformclosure: width is already calculated")
+		}
+		dowidth(f.Type)
+		xfunc.Type = f.Type // update type of ODCLFUNC
+	} else {
+		// The closure is not called, so it is going to stay as closure.
+		nvar := 0
+
+		var body *NodeList
+		offset := int64(Widthptr)
+		var addr *Node
+		var v *Node
+		var cv *Node
+		for l := func_.Func.Cvars; l != nil; l = l.Next {
+			v = l.N
+			if v.Op == OXXX {
+				continue
+			}
+			nvar++
+
+			// cv refers to the field inside of closure OSTRUCTLIT.
+			cv = Nod(OCLOSUREVAR, nil, nil)
+
+			cv.Type = v.Type
+			if !v.Name.Byval {
+				cv.Type = Ptrto(v.Type)
+			}
+			offset = Rnd(offset, int64(cv.Type.Align))
+			cv.Xoffset = offset
+			offset += cv.Type.Width
+
+			if v.Name.Byval && v.Type.Width <= int64(2*Widthptr) {
+				// If it is a small variable captured by value, downgrade it to PAUTO.
+				v.Class = PAUTO
+				v.Ullman = 1
+				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.
+				addr = newname(Lookupf("&%s", v.Sym.Name))
+				addr.Name.Param.Ntype = Nod(OIND, typenod(v.Type), nil)
+				addr.Class = PAUTO
+				addr.Used = true
+				addr.Name.Curfn = xfunc
+				xfunc.Func.Dcl = list(xfunc.Func.Dcl, addr)
+				v.Name.Heapaddr = addr
+				if v.Name.Byval {
+					cv = Nod(OADDR, cv, nil)
+				}
+				body = list(body, Nod(OAS, addr, cv))
+			}
+		}
+
+		typechecklist(body, Etop)
+		walkstmtlist(body)
+		xfunc.Func.Enter = body
+		xfunc.Func.Needctxt = nvar > 0
+	}
+
+	lineno = int32(lno)
+}
+
+func walkclosure(func_ *Node, init **NodeList) *Node {
+	// If no closure vars, don't bother wrapping.
+	if func_.Func.Cvars == nil {
+		return func_.Func.Closure.Func.Nname
+	}
+
+	// Create closure in the form of a composite literal.
+	// supposing the closure captures an int i and a string s
+	// and has one float64 argument and no results,
+	// the generated code looks like:
+	//
+	//	clos = &struct{.F uintptr; i *int; s *string}{func.1, &i, &s}
+	//
+	// The use of the struct provides type information to the garbage
+	// collector so that it can walk the closure. We could use (in this case)
+	// [3]unsafe.Pointer instead, but that would leave the gc in the dark.
+	// The information appears in the binary in the form of type descriptors;
+	// the struct is unnamed so that closures in multiple packages with the
+	// same struct type can share the descriptor.
+
+	typ := Nod(OTSTRUCT, nil, nil)
+
+	typ.List = list1(Nod(ODCLFIELD, newname(Lookup(".F")), typenod(Types[TUINTPTR])))
+	var typ1 *Node
+	var v *Node
+	for l := func_.Func.Cvars; l != nil; l = l.Next {
+		v = l.N
+		if v.Op == OXXX {
+			continue
+		}
+		typ1 = typenod(v.Type)
+		if !v.Name.Byval {
+			typ1 = Nod(OIND, typ1, nil)
+		}
+		typ.List = list(typ.List, Nod(ODCLFIELD, newname(v.Sym), typ1))
+	}
+
+	clos := Nod(OCOMPLIT, nil, Nod(OIND, typ, nil))
+	clos.Esc = func_.Esc
+	clos.Right.Implicit = true
+	clos.List = concat(list1(Nod(OCFUNC, func_.Func.Closure.Func.Nname, nil)), func_.Func.Enter)
+
+	// Force type conversion from *struct to the func type.
+	clos = Nod(OCONVNOP, clos, nil)
+
+	clos.Type = func_.Type
+
+	typecheck(&clos, Erv)
+
+	// typecheck will insert a PTRLIT node under CONVNOP,
+	// tag it with escape analysis result.
+	clos.Left.Esc = func_.Esc
+
+	// non-escaping temp to use, if any.
+	// orderexpr did not compute the type; fill it in now.
+	if x := prealloc[func_]; x != nil {
+		x.Type = clos.Left.Left.Type
+		x.Orig.Type = x.Type
+		clos.Left.Right = x
+		delete(prealloc, func_)
+	}
+
+	walkexpr(&clos, init)
+
+	return clos
+}
+
+func typecheckpartialcall(fn *Node, sym *Node) {
+	switch fn.Op {
+	case ODOTINTER, ODOTMETH:
+		break
+
+	default:
+		Fatal("invalid typecheckpartialcall")
+	}
+
+	// Create top-level function.
+	xfunc := makepartialcall(fn, fn.Type, sym)
+	fn.Func = xfunc.Func
+	fn.Right = sym
+	fn.Op = OCALLPART
+	fn.Type = xfunc.Type
+}
+
+var makepartialcall_gopkg *Pkg
+
+func makepartialcall(fn *Node, t0 *Type, meth *Node) *Node {
+	var p string
+
+	rcvrtype := fn.Left.Type
+	if exportname(meth.Sym.Name) {
+		p = fmt.Sprintf("(%v).%s-fm", Tconv(rcvrtype, obj.FmtLeft|obj.FmtShort), meth.Sym.Name)
+	} else {
+		p = fmt.Sprintf("(%v).(%v)-fm", Tconv(rcvrtype, obj.FmtLeft|obj.FmtShort), Sconv(meth.Sym, obj.FmtLeft))
+	}
+	basetype := rcvrtype
+	if Isptr[rcvrtype.Etype] {
+		basetype = basetype.Type
+	}
+	if basetype.Etype != TINTER && basetype.Sym == nil {
+		Fatal("missing base type for %v", rcvrtype)
+	}
+
+	var spkg *Pkg
+	if basetype.Sym != nil {
+		spkg = basetype.Sym.Pkg
+	}
+	if spkg == nil {
+		if makepartialcall_gopkg == nil {
+			makepartialcall_gopkg = mkpkg("go")
+		}
+		spkg = makepartialcall_gopkg
+	}
+
+	sym := Pkglookup(p, spkg)
+
+	if sym.Flags&SymUniq != 0 {
+		return sym.Def
+	}
+	sym.Flags |= SymUniq
+
+	savecurfn := Curfn
+	Curfn = nil
+
+	xtype := Nod(OTFUNC, nil, nil)
+	i := 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 {
+		n = newname(Lookupf("a%d", i))
+		i++
+		n.Class = PPARAM
+		xfunc.Func.Dcl = list(xfunc.Func.Dcl, n)
+		callargs = list(callargs, n)
+		fld = Nod(ODCLFIELD, n, typenod(t.Type))
+		if t.Isddd {
+			fld.Isddd = true
+			ddd = true
+		}
+
+		l = list(l, fld)
+	}
+
+	xtype.List = l
+	i = 0
+	l = nil
+	var retargs *NodeList
+	for t := getoutargx(t0).Type; t != nil; t = t.Down {
+		n = newname(Lookupf("r%d", i))
+		i++
+		n.Class = PPARAMOUT
+		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.Func.Dupok = true
+	xfunc.Func.Nname = newfuncname(sym)
+	xfunc.Func.Nname.Sym.Flags |= SymExported // disable export
+	xfunc.Func.Nname.Name.Param.Ntype = xtype
+	xfunc.Func.Nname.Name.Defn = xfunc
+	declare(xfunc.Func.Nname, PFUNC)
+
+	// Declare and initialize variable holding receiver.
+
+	xfunc.Func.Needctxt = true
+	cv := Nod(OCLOSUREVAR, nil, nil)
+	cv.Xoffset = int64(Widthptr)
+	cv.Type = rcvrtype
+	if int(cv.Type.Align) > Widthptr {
+		cv.Xoffset = int64(cv.Type.Align)
+	}
+	ptr := Nod(ONAME, nil, nil)
+	ptr.Sym = Lookup("rcvr")
+	ptr.Class = PAUTO
+	ptr.Addable = true
+	ptr.Ullman = 1
+	ptr.Used = true
+	ptr.Name.Curfn = xfunc
+	xfunc.Func.Dcl = list(xfunc.Func.Dcl, ptr)
+	var body *NodeList
+	if Isptr[rcvrtype.Etype] || Isinter(rcvrtype) {
+		ptr.Name.Param.Ntype = typenod(rcvrtype)
+		body = list(body, Nod(OAS, ptr, cv))
+	} else {
+		ptr.Name.Param.Ntype = typenod(Ptrto(rcvrtype))
+		body = list(body, Nod(OAS, ptr, Nod(OADDR, cv, nil)))
+	}
+
+	call := Nod(OCALL, Nod(OXDOT, ptr, meth), nil)
+	call.List = callargs
+	call.Isddd = ddd
+	if t0.Outtuple == 0 {
+		body = list(body, call)
+	} else {
+		n := Nod(OAS2, nil, nil)
+		n.List = retargs
+		n.Rlist = list1(call)
+		body = list(body, n)
+		n = Nod(ORETURN, nil, nil)
+		body = list(body, n)
+	}
+
+	xfunc.Nbody = body
+
+	typecheck(&xfunc, Etop)
+	sym.Def = xfunc
+	xtop = list(xtop, xfunc)
+	Curfn = savecurfn
+
+	return xfunc
+}
+
+func walkpartialcall(n *Node, init **NodeList) *Node {
+	// Create closure in the form of a composite literal.
+	// For x.M with receiver (x) type T, the generated code looks like:
+	//
+	//	clos = &struct{F uintptr; R T}{M.T·f, x}
+	//
+	// Like walkclosure above.
+
+	if Isinter(n.Left.Type) {
+		// Trigger panic for method on nil interface now.
+		// Otherwise it happens in the wrapper and is confusing.
+		n.Left = cheapexpr(n.Left, init)
+
+		checknil(n.Left, init)
+	}
+
+	typ := Nod(OTSTRUCT, nil, nil)
+	typ.List = list1(Nod(ODCLFIELD, newname(Lookup("F")), typenod(Types[TUINTPTR])))
+	typ.List = list(typ.List, Nod(ODCLFIELD, newname(Lookup("R")), typenod(n.Left.Type)))
+
+	clos := Nod(OCOMPLIT, nil, Nod(OIND, typ, nil))
+	clos.Esc = n.Esc
+	clos.Right.Implicit = true
+	clos.List = list1(Nod(OCFUNC, n.Func.Nname, nil))
+	clos.List = list(clos.List, n.Left)
+
+	// Force type conversion from *struct to the func type.
+	clos = Nod(OCONVNOP, clos, nil)
+
+	clos.Type = n.Type
+
+	typecheck(&clos, Erv)
+
+	// typecheck will insert a PTRLIT node under CONVNOP,
+	// tag it with escape analysis result.
+	clos.Left.Esc = n.Esc
+
+	// non-escaping temp to use, if any.
+	// orderexpr did not compute the type; fill it in now.
+	if x := prealloc[n]; x != nil {
+		x.Type = clos.Left.Left.Type
+		x.Orig.Type = x.Type
+		clos.Left.Right = x
+		delete(prealloc, n)
+	}
+
+	walkexpr(&clos, init)
+
+	return clos
+}
diff --git a/src/cmd/compile/internal/gc/const.go b/src/cmd/compile/internal/gc/const.go
new file mode 100644
index 0000000..9eb4983
--- /dev/null
+++ b/src/cmd/compile/internal/gc/const.go
@@ -0,0 +1,1715 @@
+// 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/compile/internal/big"
+	"cmd/internal/obj"
+	"strings"
+)
+
+// Int returns n as an int.
+// n must be an integer constant.
+func (n *Node) Int() int64 {
+	if !Isconst(n, CTINT) {
+		Fatal("Int(%v)", n)
+	}
+	return Mpgetfix(n.Val().U.(*Mpint))
+}
+
+// SetInt sets n's value to i.
+// n must be an integer constant.
+func (n *Node) SetInt(i int64) {
+	if !Isconst(n, CTINT) {
+		Fatal("SetInt(%v)", n)
+	}
+	Mpmovecfix(n.Val().U.(*Mpint), i)
+}
+
+// SetBigInt sets n's value to x.
+// n must be an integer constant.
+func (n *Node) SetBigInt(x *big.Int) {
+	if !Isconst(n, CTINT) {
+		Fatal("SetBigInt(%v)", n)
+	}
+	n.Val().U.(*Mpint).Val.Set(x)
+}
+
+// Bool returns n as an bool.
+// n must be an boolean constant.
+func (n *Node) Bool() bool {
+	if !Isconst(n, CTBOOL) {
+		Fatal("Int(%v)", n)
+	}
+	return n.Val().U.(bool)
+}
+
+/*
+ * truncate float literal fv to 32-bit or 64-bit precision
+ * according to type; return truncated value.
+ */
+func truncfltlit(oldv *Mpflt, t *Type) *Mpflt {
+	if t == nil {
+		return oldv
+	}
+
+	var v Val
+	v.U = oldv
+	overflow(v, t)
+
+	fv := newMpflt()
+	mpmovefltflt(fv, oldv)
+
+	// convert large precision literal floating
+	// into limited precision (float64 or float32)
+	switch t.Etype {
+	case TFLOAT64:
+		d := mpgetflt(fv)
+		Mpmovecflt(fv, d)
+
+	case TFLOAT32:
+		d := mpgetflt32(fv)
+		Mpmovecflt(fv, d)
+	}
+
+	return fv
+}
+
+/*
+ * convert n, if literal, to type t.
+ * implicit conversion.
+ */
+func Convlit(np **Node, t *Type) {
+	convlit1(np, t, false)
+}
+
+/*
+ * convert n, if literal, to type t.
+ * return a new node if necessary
+ * (if n is a named constant, can't edit n->type directly).
+ */
+func convlit1(np **Node, t *Type, explicit bool) {
+	n := *np
+	if n == nil || t == nil || n.Type == nil || isideal(t) || n.Type == t {
+		return
+	}
+	if !explicit && !isideal(n.Type) {
+		return
+	}
+
+	if n.Op == OLITERAL {
+		nn := Nod(OXXX, nil, nil)
+		*nn = *n
+		n = nn
+		*np = n
+	}
+
+	switch n.Op {
+	default:
+		if n.Type == idealbool {
+			if t.Etype == TBOOL {
+				n.Type = t
+			} else {
+				n.Type = Types[TBOOL]
+			}
+		}
+
+		if n.Type.Etype == TIDEAL {
+			Convlit(&n.Left, t)
+			Convlit(&n.Right, t)
+			n.Type = t
+		}
+
+		return
+
+		// target is invalid type for a constant?  leave alone.
+	case OLITERAL:
+		if !okforconst[t.Etype] && n.Type.Etype != TNIL {
+			defaultlit(&n, nil)
+			*np = n
+			return
+		}
+
+	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.SetVal(toint(n.Val()))
+		}
+		if t != nil && !Isint[t.Etype] {
+			Yyerror("invalid operation: %v (shift of type %v)", n, t)
+			t = nil
+		}
+
+		n.Type = t
+		return
+
+	case OCOMPLEX:
+		if n.Type.Etype == TIDEAL {
+			switch t.Etype {
+			// If trying to convert to non-complex type,
+			// leave as complex128 and let typechecker complain.
+			default:
+				t = Types[TCOMPLEX128]
+				fallthrough
+
+				//fallthrough
+			case TCOMPLEX128:
+				n.Type = t
+
+				Convlit(&n.Left, Types[TFLOAT64])
+				Convlit(&n.Right, Types[TFLOAT64])
+
+			case TCOMPLEX64:
+				n.Type = t
+				Convlit(&n.Left, Types[TFLOAT32])
+				Convlit(&n.Right, Types[TFLOAT32])
+			}
+		}
+
+		return
+	}
+
+	// avoided repeated calculations, errors
+	if Eqtype(n.Type, t) {
+		return
+	}
+
+	ct := consttype(n)
+	var et int
+	if ct < 0 {
+		goto bad
+	}
+
+	et = int(t.Etype)
+	if et == TINTER {
+		if ct == CTNIL && n.Type == Types[TNIL] {
+			n.Type = t
+			return
+		}
+
+		defaultlit(np, nil)
+		return
+	}
+
+	switch ct {
+	default:
+		goto bad
+
+	case CTNIL:
+		switch et {
+		default:
+			n.Type = nil
+			goto bad
+
+			// let normal conversion code handle it
+		case TSTRING:
+			return
+
+		case TARRAY:
+			if !Isslice(t) {
+				goto bad
+			}
+
+		case TPTR32,
+			TPTR64,
+			TINTER,
+			TMAP,
+			TCHAN,
+			TFUNC,
+			TUNSAFEPTR:
+			break
+
+			// A nil literal may be converted to uintptr
+		// if it is an unsafe.Pointer
+		case TUINTPTR:
+			if n.Type.Etype == TUNSAFEPTR {
+				n.SetVal(Val{new(Mpint)})
+				Mpmovecfix(n.Val().U.(*Mpint), 0)
+			} else {
+				goto bad
+			}
+		}
+
+	case CTSTR, CTBOOL:
+		if et != int(n.Type.Etype) {
+			goto bad
+		}
+
+	case CTINT, CTRUNE, CTFLT, CTCPLX:
+		if n.Type.Etype == TUNSAFEPTR && t.Etype != TUINTPTR {
+			goto bad
+		}
+		ct := int(n.Val().Ctype())
+		if Isint[et] {
+			switch ct {
+			default:
+				goto bad
+
+			case CTCPLX, CTFLT, CTRUNE:
+				n.SetVal(toint(n.Val()))
+				fallthrough
+
+				// flowthrough
+			case CTINT:
+				overflow(n.Val(), t)
+			}
+		} else if Isfloat[et] {
+			switch ct {
+			default:
+				goto bad
+
+			case CTCPLX, CTINT, CTRUNE:
+				n.SetVal(toflt(n.Val()))
+				fallthrough
+
+				// flowthrough
+			case CTFLT:
+				n.SetVal(Val{truncfltlit(n.Val().U.(*Mpflt), t)})
+			}
+		} else if Iscomplex[et] {
+			switch ct {
+			default:
+				goto bad
+
+			case CTFLT, CTINT, CTRUNE:
+				n.SetVal(tocplx(n.Val()))
+
+			case CTCPLX:
+				overflow(n.Val(), t)
+			}
+		} else if et == TSTRING && (ct == CTINT || ct == CTRUNE) && explicit {
+			n.SetVal(tostr(n.Val()))
+		} else {
+			goto bad
+		}
+	}
+
+	n.Type = t
+	return
+
+bad:
+	if n.Diag == 0 {
+		if t.Broke == 0 {
+			Yyerror("cannot convert %v to type %v", n, t)
+		}
+		n.Diag = 1
+	}
+
+	if isideal(n.Type) {
+		defaultlit(&n, nil)
+		*np = n
+	}
+}
+
+func copyval(v Val) Val {
+	switch v.Ctype() {
+	case CTINT, CTRUNE:
+		i := new(Mpint)
+		mpmovefixfix(i, v.U.(*Mpint))
+		i.Rune = v.U.(*Mpint).Rune
+		v.U = i
+
+	case CTFLT:
+		f := newMpflt()
+		mpmovefltflt(f, v.U.(*Mpflt))
+		v.U = f
+
+	case CTCPLX:
+		c := new(Mpcplx)
+		mpmovefltflt(&c.Real, &v.U.(*Mpcplx).Real)
+		mpmovefltflt(&c.Imag, &v.U.(*Mpcplx).Imag)
+		v.U = c
+	}
+
+	return v
+}
+
+func tocplx(v Val) Val {
+	switch v.Ctype() {
+	case CTINT, CTRUNE:
+		c := new(Mpcplx)
+		Mpmovefixflt(&c.Real, v.U.(*Mpint))
+		Mpmovecflt(&c.Imag, 0.0)
+		v.U = c
+
+	case CTFLT:
+		c := new(Mpcplx)
+		mpmovefltflt(&c.Real, v.U.(*Mpflt))
+		Mpmovecflt(&c.Imag, 0.0)
+		v.U = c
+	}
+
+	return v
+}
+
+func toflt(v Val) Val {
+	switch v.Ctype() {
+	case CTINT, CTRUNE:
+		f := newMpflt()
+		Mpmovefixflt(f, v.U.(*Mpint))
+		v.U = f
+
+	case CTCPLX:
+		f := newMpflt()
+		mpmovefltflt(f, &v.U.(*Mpcplx).Real)
+		if mpcmpfltc(&v.U.(*Mpcplx).Imag, 0) != 0 {
+			Yyerror("constant %v%vi truncated to real", Fconv(&v.U.(*Mpcplx).Real, obj.FmtSharp), Fconv(&v.U.(*Mpcplx).Imag, obj.FmtSharp|obj.FmtSign))
+		}
+		v.U = f
+	}
+
+	return v
+}
+
+func toint(v Val) Val {
+	switch v.Ctype() {
+	case CTRUNE:
+		i := new(Mpint)
+		mpmovefixfix(i, v.U.(*Mpint))
+		v.U = i
+
+	case CTFLT:
+		i := new(Mpint)
+		if mpmovefltfix(i, v.U.(*Mpflt)) < 0 {
+			Yyerror("constant %v truncated to integer", Fconv(v.U.(*Mpflt), obj.FmtSharp))
+		}
+		v.U = i
+
+	case CTCPLX:
+		i := new(Mpint)
+		if mpmovefltfix(i, &v.U.(*Mpcplx).Real) < 0 {
+			Yyerror("constant %v%vi truncated to integer", Fconv(&v.U.(*Mpcplx).Real, obj.FmtSharp), Fconv(&v.U.(*Mpcplx).Imag, obj.FmtSharp|obj.FmtSign))
+		}
+		if mpcmpfltc(&v.U.(*Mpcplx).Imag, 0) != 0 {
+			Yyerror("constant %v%vi truncated to real", Fconv(&v.U.(*Mpcplx).Real, obj.FmtSharp), Fconv(&v.U.(*Mpcplx).Imag, obj.FmtSharp|obj.FmtSign))
+		}
+		v.U = i
+	}
+
+	return v
+}
+
+func doesoverflow(v Val, t *Type) bool {
+	switch v.Ctype() {
+	case CTINT, CTRUNE:
+		if !Isint[t.Etype] {
+			Fatal("overflow: %v integer constant", t)
+		}
+		if Mpcmpfixfix(v.U.(*Mpint), Minintval[t.Etype]) < 0 || Mpcmpfixfix(v.U.(*Mpint), Maxintval[t.Etype]) > 0 {
+			return true
+		}
+
+	case CTFLT:
+		if !Isfloat[t.Etype] {
+			Fatal("overflow: %v floating-point constant", t)
+		}
+		if mpcmpfltflt(v.U.(*Mpflt), minfltval[t.Etype]) <= 0 || mpcmpfltflt(v.U.(*Mpflt), maxfltval[t.Etype]) >= 0 {
+			return true
+		}
+
+	case CTCPLX:
+		if !Iscomplex[t.Etype] {
+			Fatal("overflow: %v complex constant", t)
+		}
+		if mpcmpfltflt(&v.U.(*Mpcplx).Real, minfltval[t.Etype]) <= 0 || mpcmpfltflt(&v.U.(*Mpcplx).Real, maxfltval[t.Etype]) >= 0 || mpcmpfltflt(&v.U.(*Mpcplx).Imag, minfltval[t.Etype]) <= 0 || mpcmpfltflt(&v.U.(*Mpcplx).Imag, maxfltval[t.Etype]) >= 0 {
+			return true
+		}
+	}
+
+	return false
+}
+
+func overflow(v Val, t *Type) {
+	// v has already been converted
+	// to appropriate form for t.
+	if t == nil || t.Etype == TIDEAL {
+		return
+	}
+
+	// Only uintptrs may be converted to unsafe.Pointer, which cannot overflow.
+	if t.Etype == TUNSAFEPTR {
+		return
+	}
+
+	if !doesoverflow(v, t) {
+		return
+	}
+
+	switch v.Ctype() {
+	case CTINT, CTRUNE:
+		Yyerror("constant %v overflows %v", v.U.(*Mpint), t)
+
+	case CTFLT:
+		Yyerror("constant %v overflows %v", Fconv(v.U.(*Mpflt), obj.FmtSharp), t)
+
+	case CTCPLX:
+		Yyerror("constant %v overflows %v", Fconv(v.U.(*Mpflt), obj.FmtSharp), t)
+	}
+}
+
+func tostr(v Val) Val {
+	switch v.Ctype() {
+	case CTINT, CTRUNE:
+		if Mpcmpfixfix(v.U.(*Mpint), Minintval[TINT]) < 0 || Mpcmpfixfix(v.U.(*Mpint), Maxintval[TINT]) > 0 {
+			Yyerror("overflow in int -> string")
+		}
+		r := uint(Mpgetfix(v.U.(*Mpint)))
+		v = Val{}
+		v.U = string(r)
+
+	case CTFLT:
+		Yyerror("no float -> string")
+		fallthrough
+
+	case CTNIL:
+		v = Val{}
+		v.U = ""
+	}
+
+	return v
+}
+
+func consttype(n *Node) int {
+	if n == nil || n.Op != OLITERAL {
+		return -1
+	}
+	return int(n.Val().Ctype())
+}
+
+func Isconst(n *Node, ct int) bool {
+	t := consttype(n)
+
+	// If the caller is asking for CTINT, allow CTRUNE too.
+	// Makes life easier for back ends.
+	return t == ct || (ct == CTINT && t == CTRUNE)
+}
+
+func saveorig(n *Node) *Node {
+	if n == n.Orig {
+		// duplicate node for n->orig.
+		n1 := Nod(OLITERAL, nil, nil)
+
+		n.Orig = n1
+		*n1 = *n
+	}
+
+	return n.Orig
+}
+
+/*
+ * if n is constant, rewrite as OLITERAL node.
+ */
+func evconst(n *Node) {
+	// pick off just the opcodes that can be
+	// constant evaluated.
+	switch n.Op {
+	default:
+		return
+
+	case OADD,
+		OAND,
+		OANDAND,
+		OANDNOT,
+		OARRAYBYTESTR,
+		OCOM,
+		ODIV,
+		OEQ,
+		OGE,
+		OGT,
+		OLE,
+		OLSH,
+		OLT,
+		OMINUS,
+		OMOD,
+		OMUL,
+		ONE,
+		ONOT,
+		OOR,
+		OOROR,
+		OPLUS,
+		ORSH,
+		OSUB,
+		OXOR:
+		break
+
+	case OCONV:
+		if n.Type == nil {
+			return
+		}
+		if !okforconst[n.Type.Etype] && n.Type.Etype != TNIL {
+			return
+		}
+
+		// merge adjacent constants in the argument list.
+	case OADDSTR:
+		var nr *Node
+		var nl *Node
+		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
+				var strs []string
+				l2 = l1
+				for l2 != nil && Isconst(l2.N, CTSTR) {
+					nr = l2.N
+					strs = append(strs, nr.Val().U.(string))
+					l2 = l2.Next
+				}
+
+				nl = Nod(OXXX, nil, nil)
+				*nl = *l1.N
+				nl.Orig = nl
+				nl.SetVal(Val{strings.Join(strs, "")})
+				l1.N = nl
+				l1.Next = l2
+			}
+		}
+
+		// fix list end pointer.
+		for l2 := n.List; l2 != nil; l2 = l2.Next {
+			n.List.End = l2
+		}
+
+		// collapse single-constant list to single constant.
+		if count(n.List) == 1 && Isconst(n.List.N, CTSTR) {
+			n.Op = OLITERAL
+			n.SetVal(n.List.N.Val())
+		}
+
+		return
+	}
+
+	nl := n.Left
+	if nl == nil || nl.Type == nil {
+		return
+	}
+	if consttype(nl) < 0 {
+		return
+	}
+	wl := int(nl.Type.Etype)
+	if Isint[wl] || Isfloat[wl] || Iscomplex[wl] {
+		wl = TIDEAL
+	}
+
+	nr := n.Right
+	var rv Val
+	var lno int
+	var wr int
+	var v Val
+	var norig *Node
+	if nr == nil {
+		// 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), nl.Type)
+				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.(*Mpint))
+
+		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.(*Mpint), &b)
+
+		case OPLUS<<16 | CTFLT:
+			break
+
+		case OMINUS<<16 | CTFLT:
+			mpnegflt(v.U.(*Mpflt))
+
+		case OPLUS<<16 | CTCPLX:
+			break
+
+		case OMINUS<<16 | CTCPLX:
+			mpnegflt(&v.U.(*Mpcplx).Real)
+			mpnegflt(&v.U.(*Mpcplx).Imag)
+
+		case ONOT<<16 | CTBOOL:
+			if !v.U.(bool) {
+				goto settrue
+			}
+			goto setfalse
+		}
+		goto ret
+	}
+	if nr.Type == nil {
+		return
+	}
+	if consttype(nr) < 0 {
+		return
+	}
+	wr = int(nr.Type.Etype)
+	if Isint[wr] || Isfloat[wr] || Iscomplex[wr] {
+		wr = TIDEAL
+	}
+
+	// check for compatible general types (numeric, string, etc)
+	if wl != wr {
+		goto illegal
+	}
+
+	// check for compatible types.
+	switch n.Op {
+	// ideal const mixes with anything but otherwise must match.
+	default:
+		if nl.Type.Etype != TIDEAL {
+			defaultlit(&nr, nl.Type)
+			n.Right = nr
+		}
+
+		if nr.Type.Etype != TIDEAL {
+			defaultlit(&nl, nr.Type)
+			n.Left = nl
+		}
+
+		if nl.Type.Etype != nr.Type.Etype {
+			goto illegal
+		}
+
+		// right must be unsigned.
+	// left can be ideal.
+	case OLSH, ORSH:
+		defaultlit(&nr, Types[TUINT])
+
+		n.Right = nr
+		if nr.Type != nil && (Issigned[nr.Type.Etype] || !Isint[nr.Type.Etype]) {
+			goto illegal
+		}
+		if nl.Val().Ctype() != CTRUNE {
+			nl.SetVal(toint(nl.Val()))
+		}
+		nr.SetVal(toint(nr.Val()))
+	}
+
+	// copy numeric value to avoid modifying
+	// n->left, in case someone still refers to it (e.g. iota).
+	v = nl.Val()
+
+	if wl == TIDEAL {
+		v = copyval(v)
+	}
+
+	rv = nr.Val()
+
+	// convert to common ideal
+	if v.Ctype() == CTCPLX || rv.Ctype() == CTCPLX {
+		v = tocplx(v)
+		rv = tocplx(rv)
+	}
+
+	if v.Ctype() == CTFLT || rv.Ctype() == CTFLT {
+		v = toflt(v)
+		rv = toflt(rv)
+	}
+
+	// Rune and int turns into rune.
+	if v.Ctype() == CTRUNE && rv.Ctype() == CTINT {
+		i := new(Mpint)
+		mpmovefixfix(i, rv.U.(*Mpint))
+		i.Rune = true
+		rv.U = i
+	}
+	if v.Ctype() == CTINT && rv.Ctype() == CTRUNE {
+		if n.Op == OLSH || n.Op == ORSH {
+			i := new(Mpint)
+			mpmovefixfix(i, rv.U.(*Mpint))
+			rv.U = i
+		} else {
+			i := new(Mpint)
+			mpmovefixfix(i, v.U.(*Mpint))
+			i.Rune = true
+			v.U = i
+		}
+	}
+
+	if v.Ctype() != rv.Ctype() {
+		// Use of undefined name as constant?
+		if (v.Ctype() == 0 || rv.Ctype() == 0) && nerrors > 0 {
+			return
+		}
+		Fatal("constant type mismatch %v(%d) %v(%d)", nl.Type, v.Ctype(), nr.Type, rv.Ctype())
+	}
+
+	// run op
+	switch uint32(n.Op)<<16 | uint32(v.Ctype()) {
+	default:
+		goto illegal
+
+	case OADD<<16 | CTINT,
+		OADD<<16 | CTRUNE:
+		mpaddfixfix(v.U.(*Mpint), rv.U.(*Mpint), 0)
+
+	case OSUB<<16 | CTINT,
+		OSUB<<16 | CTRUNE:
+		mpsubfixfix(v.U.(*Mpint), rv.U.(*Mpint))
+
+	case OMUL<<16 | CTINT,
+		OMUL<<16 | CTRUNE:
+		mpmulfixfix(v.U.(*Mpint), rv.U.(*Mpint))
+
+	case ODIV<<16 | CTINT,
+		ODIV<<16 | CTRUNE:
+		if mpcmpfixc(rv.U.(*Mpint), 0) == 0 {
+			Yyerror("division by zero")
+			mpsetovf(v.U.(*Mpint))
+			break
+		}
+
+		mpdivfixfix(v.U.(*Mpint), rv.U.(*Mpint))
+
+	case OMOD<<16 | CTINT,
+		OMOD<<16 | CTRUNE:
+		if mpcmpfixc(rv.U.(*Mpint), 0) == 0 {
+			Yyerror("division by zero")
+			mpsetovf(v.U.(*Mpint))
+			break
+		}
+
+		mpmodfixfix(v.U.(*Mpint), rv.U.(*Mpint))
+
+	case OLSH<<16 | CTINT,
+		OLSH<<16 | CTRUNE:
+		mplshfixfix(v.U.(*Mpint), rv.U.(*Mpint))
+
+	case ORSH<<16 | CTINT,
+		ORSH<<16 | CTRUNE:
+		mprshfixfix(v.U.(*Mpint), rv.U.(*Mpint))
+
+	case OOR<<16 | CTINT,
+		OOR<<16 | CTRUNE:
+		mporfixfix(v.U.(*Mpint), rv.U.(*Mpint))
+
+	case OAND<<16 | CTINT,
+		OAND<<16 | CTRUNE:
+		mpandfixfix(v.U.(*Mpint), rv.U.(*Mpint))
+
+	case OANDNOT<<16 | CTINT,
+		OANDNOT<<16 | CTRUNE:
+		mpandnotfixfix(v.U.(*Mpint), rv.U.(*Mpint))
+
+	case OXOR<<16 | CTINT,
+		OXOR<<16 | CTRUNE:
+		mpxorfixfix(v.U.(*Mpint), rv.U.(*Mpint))
+
+	case OADD<<16 | CTFLT:
+		mpaddfltflt(v.U.(*Mpflt), rv.U.(*Mpflt))
+
+	case OSUB<<16 | CTFLT:
+		mpsubfltflt(v.U.(*Mpflt), rv.U.(*Mpflt))
+
+	case OMUL<<16 | CTFLT:
+		mpmulfltflt(v.U.(*Mpflt), rv.U.(*Mpflt))
+
+	case ODIV<<16 | CTFLT:
+		if mpcmpfltc(rv.U.(*Mpflt), 0) == 0 {
+			Yyerror("division by zero")
+			Mpmovecflt(v.U.(*Mpflt), 1.0)
+			break
+		}
+
+		mpdivfltflt(v.U.(*Mpflt), rv.U.(*Mpflt))
+
+		// The default case above would print 'ideal % ideal',
+	// which is not quite an ideal error.
+	case OMOD<<16 | CTFLT:
+		if n.Diag == 0 {
+			Yyerror("illegal constant expression: floating-point %% operation")
+			n.Diag = 1
+		}
+
+		return
+
+	case OADD<<16 | CTCPLX:
+		mpaddfltflt(&v.U.(*Mpcplx).Real, &rv.U.(*Mpcplx).Real)
+		mpaddfltflt(&v.U.(*Mpcplx).Imag, &rv.U.(*Mpcplx).Imag)
+
+	case OSUB<<16 | CTCPLX:
+		mpsubfltflt(&v.U.(*Mpcplx).Real, &rv.U.(*Mpcplx).Real)
+		mpsubfltflt(&v.U.(*Mpcplx).Imag, &rv.U.(*Mpcplx).Imag)
+
+	case OMUL<<16 | CTCPLX:
+		cmplxmpy(v.U.(*Mpcplx), rv.U.(*Mpcplx))
+
+	case ODIV<<16 | CTCPLX:
+		if mpcmpfltc(&rv.U.(*Mpcplx).Real, 0) == 0 && mpcmpfltc(&rv.U.(*Mpcplx).Imag, 0) == 0 {
+			Yyerror("complex division by zero")
+			Mpmovecflt(&rv.U.(*Mpcplx).Real, 1.0)
+			Mpmovecflt(&rv.U.(*Mpcplx).Imag, 0.0)
+			break
+		}
+
+		cmplxdiv(v.U.(*Mpcplx), rv.U.(*Mpcplx))
+
+	case OEQ<<16 | CTNIL:
+		goto settrue
+
+	case ONE<<16 | CTNIL:
+		goto setfalse
+
+	case OEQ<<16 | CTINT,
+		OEQ<<16 | CTRUNE:
+		if Mpcmpfixfix(v.U.(*Mpint), rv.U.(*Mpint)) == 0 {
+			goto settrue
+		}
+		goto setfalse
+
+	case ONE<<16 | CTINT,
+		ONE<<16 | CTRUNE:
+		if Mpcmpfixfix(v.U.(*Mpint), rv.U.(*Mpint)) != 0 {
+			goto settrue
+		}
+		goto setfalse
+
+	case OLT<<16 | CTINT,
+		OLT<<16 | CTRUNE:
+		if Mpcmpfixfix(v.U.(*Mpint), rv.U.(*Mpint)) < 0 {
+			goto settrue
+		}
+		goto setfalse
+
+	case OLE<<16 | CTINT,
+		OLE<<16 | CTRUNE:
+		if Mpcmpfixfix(v.U.(*Mpint), rv.U.(*Mpint)) <= 0 {
+			goto settrue
+		}
+		goto setfalse
+
+	case OGE<<16 | CTINT,
+		OGE<<16 | CTRUNE:
+		if Mpcmpfixfix(v.U.(*Mpint), rv.U.(*Mpint)) >= 0 {
+			goto settrue
+		}
+		goto setfalse
+
+	case OGT<<16 | CTINT,
+		OGT<<16 | CTRUNE:
+		if Mpcmpfixfix(v.U.(*Mpint), rv.U.(*Mpint)) > 0 {
+			goto settrue
+		}
+		goto setfalse
+
+	case OEQ<<16 | CTFLT:
+		if mpcmpfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) == 0 {
+			goto settrue
+		}
+		goto setfalse
+
+	case ONE<<16 | CTFLT:
+		if mpcmpfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) != 0 {
+			goto settrue
+		}
+		goto setfalse
+
+	case OLT<<16 | CTFLT:
+		if mpcmpfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) < 0 {
+			goto settrue
+		}
+		goto setfalse
+
+	case OLE<<16 | CTFLT:
+		if mpcmpfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) <= 0 {
+			goto settrue
+		}
+		goto setfalse
+
+	case OGE<<16 | CTFLT:
+		if mpcmpfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) >= 0 {
+			goto settrue
+		}
+		goto setfalse
+
+	case OGT<<16 | CTFLT:
+		if mpcmpfltflt(v.U.(*Mpflt), rv.U.(*Mpflt)) > 0 {
+			goto settrue
+		}
+		goto setfalse
+
+	case OEQ<<16 | CTCPLX:
+		if mpcmpfltflt(&v.U.(*Mpcplx).Real, &rv.U.(*Mpcplx).Real) == 0 && mpcmpfltflt(&v.U.(*Mpcplx).Imag, &rv.U.(*Mpcplx).Imag) == 0 {
+			goto settrue
+		}
+		goto setfalse
+
+	case ONE<<16 | CTCPLX:
+		if mpcmpfltflt(&v.U.(*Mpcplx).Real, &rv.U.(*Mpcplx).Real) != 0 || mpcmpfltflt(&v.U.(*Mpcplx).Imag, &rv.U.(*Mpcplx).Imag) != 0 {
+			goto settrue
+		}
+		goto setfalse
+
+	case OEQ<<16 | CTSTR:
+		if cmpslit(nl, nr) == 0 {
+			goto settrue
+		}
+		goto setfalse
+
+	case ONE<<16 | CTSTR:
+		if cmpslit(nl, nr) != 0 {
+			goto settrue
+		}
+		goto setfalse
+
+	case OLT<<16 | CTSTR:
+		if cmpslit(nl, nr) < 0 {
+			goto settrue
+		}
+		goto setfalse
+
+	case OLE<<16 | CTSTR:
+		if cmpslit(nl, nr) <= 0 {
+			goto settrue
+		}
+		goto setfalse
+
+	case OGE<<16 | CTSTR:
+		if cmpslit(nl, nr) >= 0 {
+			goto settrue
+		}
+		goto setfalse
+
+	case OGT<<16 | CTSTR:
+		if cmpslit(nl, nr) > 0 {
+			goto settrue
+		}
+		goto setfalse
+
+	case OOROR<<16 | CTBOOL:
+		if v.U.(bool) || rv.U.(bool) {
+			goto settrue
+		}
+		goto setfalse
+
+	case OANDAND<<16 | CTBOOL:
+		if v.U.(bool) && rv.U.(bool) {
+			goto settrue
+		}
+		goto setfalse
+
+	case OEQ<<16 | CTBOOL:
+		if v.U.(bool) == rv.U.(bool) {
+			goto settrue
+		}
+		goto setfalse
+
+	case ONE<<16 | CTBOOL:
+		if v.U.(bool) != rv.U.(bool) {
+			goto settrue
+		}
+		goto setfalse
+	}
+
+	goto ret
+
+ret:
+	norig = saveorig(n)
+	*n = *nl
+
+	// restore value of n->orig.
+	n.Orig = norig
+
+	n.SetVal(v)
+
+	// check range.
+	lno = int(setlineno(n))
+
+	overflow(v, n.Type)
+	lineno = int32(lno)
+
+	// truncate precision for non-ideal float.
+	if v.Ctype() == CTFLT && n.Type.Etype != TIDEAL {
+		n.SetVal(Val{truncfltlit(v.U.(*Mpflt), n.Type)})
+	}
+	return
+
+settrue:
+	norig = saveorig(n)
+	*n = *Nodbool(true)
+	n.Orig = norig
+	return
+
+setfalse:
+	norig = saveorig(n)
+	*n = *Nodbool(false)
+	n.Orig = norig
+	return
+
+illegal:
+	if n.Diag == 0 {
+		Yyerror("illegal constant expression: %v %v %v", nl.Type, Oconv(int(n.Op), 0), nr.Type)
+		n.Diag = 1
+	}
+
+	return
+}
+
+func nodlit(v Val) *Node {
+	n := Nod(OLITERAL, nil, nil)
+	n.SetVal(v)
+	switch v.Ctype() {
+	default:
+		Fatal("nodlit ctype %d", v.Ctype())
+
+	case CTSTR:
+		n.Type = idealstring
+
+	case CTBOOL:
+		n.Type = idealbool
+
+	case CTINT, CTRUNE, CTFLT, CTCPLX:
+		n.Type = Types[TIDEAL]
+
+	case CTNIL:
+		n.Type = Types[TNIL]
+	}
+
+	return n
+}
+
+func nodcplxlit(r Val, i Val) *Node {
+	r = toflt(r)
+	i = toflt(i)
+
+	c := new(Mpcplx)
+	n := Nod(OLITERAL, nil, nil)
+	n.Type = Types[TIDEAL]
+	n.SetVal(Val{c})
+
+	if r.Ctype() != CTFLT || i.Ctype() != CTFLT {
+		Fatal("nodcplxlit ctype %d/%d", r.Ctype(), i.Ctype())
+	}
+
+	mpmovefltflt(&c.Real, r.U.(*Mpflt))
+	mpmovefltflt(&c.Imag, i.U.(*Mpflt))
+	return n
+}
+
+// idealkind returns a constant kind like consttype
+// but for an arbitrary "ideal" (untyped constant) expression.
+func idealkind(n *Node) int {
+	if n == nil || !isideal(n.Type) {
+		return CTxxx
+	}
+
+	switch n.Op {
+	default:
+		return CTxxx
+
+	case OLITERAL:
+		return int(n.Val().Ctype())
+
+		// numeric kinds.
+	case OADD,
+		OAND,
+		OANDNOT,
+		OCOM,
+		ODIV,
+		OMINUS,
+		OMOD,
+		OMUL,
+		OSUB,
+		OXOR,
+		OOR,
+		OPLUS:
+		k1 := idealkind(n.Left)
+
+		k2 := idealkind(n.Right)
+		if k1 > k2 {
+			return k1
+		} else {
+			return k2
+		}
+
+	case OREAL, OIMAG:
+		return CTFLT
+
+	case OCOMPLEX:
+		return CTCPLX
+
+	case OADDSTR:
+		return CTSTR
+
+	case OANDAND,
+		OEQ,
+		OGE,
+		OGT,
+		OLE,
+		OLT,
+		ONE,
+		ONOT,
+		OOROR,
+		OCMPSTR,
+		OCMPIFACE:
+		return CTBOOL
+
+		// shifts (beware!).
+	case OLSH, ORSH:
+		return idealkind(n.Left)
+	}
+}
+
+func defaultlit(np **Node, t *Type) {
+	n := *np
+	if n == nil || !isideal(n.Type) {
+		return
+	}
+
+	if n.Op == OLITERAL {
+		nn := Nod(OXXX, nil, nil)
+		*nn = *n
+		n = nn
+		*np = n
+	}
+
+	lno := int(setlineno(n))
+	ctype := idealkind(n)
+	var t1 *Type
+	switch ctype {
+	default:
+		if t != nil {
+			Convlit(np, t)
+			return
+		}
+
+		if n.Val().Ctype() == CTNIL {
+			lineno = int32(lno)
+			if n.Diag == 0 {
+				Yyerror("use of untyped nil")
+				n.Diag = 1
+			}
+
+			n.Type = nil
+			break
+		}
+
+		if n.Val().Ctype() == CTSTR {
+			t1 := Types[TSTRING]
+			Convlit(np, t1)
+			break
+		}
+
+		Yyerror("defaultlit: unknown literal: %v", n)
+
+	case CTxxx:
+		Fatal("defaultlit: idealkind is CTxxx: %v", Nconv(n, obj.FmtSign))
+
+	case CTBOOL:
+		t1 := Types[TBOOL]
+		if t != nil && t.Etype == TBOOL {
+			t1 = t
+		}
+		Convlit(np, t1)
+
+	case CTINT:
+		t1 = Types[TINT]
+		goto num
+
+	case CTRUNE:
+		t1 = runetype
+		goto num
+
+	case CTFLT:
+		t1 = Types[TFLOAT64]
+		goto num
+
+	case CTCPLX:
+		t1 = Types[TCOMPLEX128]
+		goto num
+	}
+
+	lineno = int32(lno)
+	return
+
+num:
+	if t != nil {
+		if Isint[t.Etype] {
+			t1 = t
+			n.SetVal(toint(n.Val()))
+		} else if Isfloat[t.Etype] {
+			t1 = t
+			n.SetVal(toflt(n.Val()))
+		} else if Iscomplex[t.Etype] {
+			t1 = t
+			n.SetVal(tocplx(n.Val()))
+		}
+	}
+
+	overflow(n.Val(), t1)
+	Convlit(np, t1)
+	lineno = int32(lno)
+	return
+}
+
+/*
+ * defaultlit on both nodes simultaneously;
+ * if they're both ideal going in they better
+ * get the same type going out.
+ * force means must assign concrete (non-ideal) type.
+ */
+func defaultlit2(lp **Node, rp **Node, force int) {
+	l := *lp
+	r := *rp
+	if l.Type == nil || r.Type == nil {
+		return
+	}
+	if !isideal(l.Type) {
+		Convlit(rp, l.Type)
+		return
+	}
+
+	if !isideal(r.Type) {
+		Convlit(lp, r.Type)
+		return
+	}
+
+	if force == 0 {
+		return
+	}
+	if l.Type.Etype == TBOOL {
+		Convlit(lp, Types[TBOOL])
+		Convlit(rp, Types[TBOOL])
+	}
+
+	lkind := idealkind(l)
+	rkind := idealkind(r)
+	if lkind == CTCPLX || rkind == CTCPLX {
+		Convlit(lp, Types[TCOMPLEX128])
+		Convlit(rp, Types[TCOMPLEX128])
+		return
+	}
+
+	if lkind == CTFLT || rkind == CTFLT {
+		Convlit(lp, Types[TFLOAT64])
+		Convlit(rp, Types[TFLOAT64])
+		return
+	}
+
+	if lkind == CTRUNE || rkind == CTRUNE {
+		Convlit(lp, runetype)
+		Convlit(rp, runetype)
+		return
+	}
+
+	Convlit(lp, Types[TINT])
+	Convlit(rp, Types[TINT])
+}
+
+func cmpslit(l, r *Node) int {
+	return stringsCompare(l.Val().U.(string), r.Val().U.(string))
+}
+
+func Smallintconst(n *Node) bool {
+	if n.Op == OLITERAL && Isconst(n, CTINT) && n.Type != nil {
+		switch Simtype[n.Type.Etype] {
+		case TINT8,
+			TUINT8,
+			TINT16,
+			TUINT16,
+			TINT32,
+			TUINT32,
+			TBOOL,
+			TPTR32:
+			return true
+
+		case TIDEAL, TINT64, TUINT64, TPTR64:
+			if Mpcmpfixfix(n.Val().U.(*Mpint), Minintval[TINT32]) < 0 || Mpcmpfixfix(n.Val().U.(*Mpint), Maxintval[TINT32]) > 0 {
+				break
+			}
+			return true
+		}
+	}
+
+	return false
+}
+
+func nonnegconst(n *Node) int {
+	if n.Op == OLITERAL && n.Type != nil {
+		switch Simtype[n.Type.Etype] {
+		// check negative and 2^31
+		case TINT8,
+			TUINT8,
+			TINT16,
+			TUINT16,
+			TINT32,
+			TUINT32,
+			TINT64,
+			TUINT64,
+			TIDEAL:
+			if Mpcmpfixfix(n.Val().U.(*Mpint), Minintval[TUINT32]) < 0 || Mpcmpfixfix(n.Val().U.(*Mpint), Maxintval[TINT32]) > 0 {
+				break
+			}
+			return int(Mpgetfix(n.Val().U.(*Mpint)))
+		}
+	}
+
+	return -1
+}
+
+/*
+ * convert x to type et and back to int64
+ * for sign extension and truncation.
+ */
+func iconv(x int64, et int) int64 {
+	switch et {
+	case TINT8:
+		x = int64(int8(x))
+
+	case TUINT8:
+		x = int64(uint8(x))
+
+	case TINT16:
+		x = int64(int16(x))
+
+	case TUINT16:
+		x = int64(uint64(x))
+
+	case TINT32:
+		x = int64(int32(x))
+
+	case TUINT32:
+		x = int64(uint32(x))
+
+	case TINT64, TUINT64:
+		break
+	}
+
+	return x
+}
+
+// Convconst converts constant node n to type t and
+// places the result in con.
+func (n *Node) Convconst(con *Node, t *Type) {
+	tt := Simsimtype(t)
+
+	// copy the constant for conversion
+	Nodconst(con, Types[TINT8], 0)
+
+	con.Type = t
+	con.SetVal(n.Val())
+
+	if Isint[tt] {
+		con.SetVal(Val{new(Mpint)})
+		var i int64
+		switch n.Val().Ctype() {
+		default:
+			Fatal("convconst ctype=%d %v", n.Val().Ctype(), Tconv(t, obj.FmtLong))
+
+		case CTINT, CTRUNE:
+			i = Mpgetfix(n.Val().U.(*Mpint))
+
+		case CTBOOL:
+			i = int64(obj.Bool2int(n.Val().U.(bool)))
+
+		case CTNIL:
+			i = 0
+		}
+
+		i = iconv(i, tt)
+		Mpmovecfix(con.Val().U.(*Mpint), i)
+		return
+	}
+
+	if Isfloat[tt] {
+		con.SetVal(toflt(con.Val()))
+		if con.Val().Ctype() != CTFLT {
+			Fatal("convconst ctype=%d %v", con.Val().Ctype(), t)
+		}
+		if tt == TFLOAT32 {
+			con.SetVal(Val{truncfltlit(con.Val().U.(*Mpflt), t)})
+		}
+		return
+	}
+
+	if Iscomplex[tt] {
+		con.SetVal(tocplx(con.Val()))
+		if tt == TCOMPLEX64 {
+			con.Val().U.(*Mpcplx).Real = *truncfltlit(&con.Val().U.(*Mpcplx).Real, Types[TFLOAT32])
+			con.Val().U.(*Mpcplx).Imag = *truncfltlit(&con.Val().U.(*Mpcplx).Imag, Types[TFLOAT32])
+		}
+		return
+	}
+
+	Fatal("convconst %v constant", Tconv(t, obj.FmtLong))
+}
+
+// complex multiply v *= rv
+//	(a, b) * (c, d) = (a*c - b*d, b*c + a*d)
+func cmplxmpy(v *Mpcplx, rv *Mpcplx) {
+	var ac Mpflt
+	var bd Mpflt
+	var bc Mpflt
+	var ad Mpflt
+
+	mpmovefltflt(&ac, &v.Real)
+	mpmulfltflt(&ac, &rv.Real) // ac
+
+	mpmovefltflt(&bd, &v.Imag)
+
+	mpmulfltflt(&bd, &rv.Imag) // bd
+
+	mpmovefltflt(&bc, &v.Imag)
+
+	mpmulfltflt(&bc, &rv.Real) // bc
+
+	mpmovefltflt(&ad, &v.Real)
+
+	mpmulfltflt(&ad, &rv.Imag) // ad
+
+	mpmovefltflt(&v.Real, &ac)
+
+	mpsubfltflt(&v.Real, &bd) // ac-bd
+
+	mpmovefltflt(&v.Imag, &bc)
+
+	mpaddfltflt(&v.Imag, &ad) // bc+ad
+}
+
+// complex divide v /= rv
+//	(a, b) / (c, d) = ((a*c + b*d), (b*c - a*d))/(c*c + d*d)
+func cmplxdiv(v *Mpcplx, rv *Mpcplx) {
+	var ac Mpflt
+	var bd Mpflt
+	var bc Mpflt
+	var ad Mpflt
+	var cc_plus_dd Mpflt
+
+	mpmovefltflt(&cc_plus_dd, &rv.Real)
+	mpmulfltflt(&cc_plus_dd, &rv.Real) // cc
+
+	mpmovefltflt(&ac, &rv.Imag)
+
+	mpmulfltflt(&ac, &rv.Imag) // dd
+
+	mpaddfltflt(&cc_plus_dd, &ac) // cc+dd
+
+	mpmovefltflt(&ac, &v.Real)
+
+	mpmulfltflt(&ac, &rv.Real) // ac
+
+	mpmovefltflt(&bd, &v.Imag)
+
+	mpmulfltflt(&bd, &rv.Imag) // bd
+
+	mpmovefltflt(&bc, &v.Imag)
+
+	mpmulfltflt(&bc, &rv.Real) // bc
+
+	mpmovefltflt(&ad, &v.Real)
+
+	mpmulfltflt(&ad, &rv.Imag) // ad
+
+	mpmovefltflt(&v.Real, &ac)
+
+	mpaddfltflt(&v.Real, &bd)         // ac+bd
+	mpdivfltflt(&v.Real, &cc_plus_dd) // (ac+bd)/(cc+dd)
+
+	mpmovefltflt(&v.Imag, &bc)
+
+	mpsubfltflt(&v.Imag, &ad)         // bc-ad
+	mpdivfltflt(&v.Imag, &cc_plus_dd) // (bc+ad)/(cc+dd)
+}
+
+// Is n a Go language constant (as opposed to a compile-time constant)?
+// Expressions derived from nil, like string([]byte(nil)), while they
+// may be known at compile time, are not Go language constants.
+// Only called for expressions known to evaluated to compile-time
+// constants.
+func isgoconst(n *Node) bool {
+	if n.Orig != nil {
+		n = n.Orig
+	}
+
+	switch n.Op {
+	case OADD,
+		OADDSTR,
+		OAND,
+		OANDAND,
+		OANDNOT,
+		OCOM,
+		ODIV,
+		OEQ,
+		OGE,
+		OGT,
+		OLE,
+		OLSH,
+		OLT,
+		OMINUS,
+		OMOD,
+		OMUL,
+		ONE,
+		ONOT,
+		OOR,
+		OOROR,
+		OPLUS,
+		ORSH,
+		OSUB,
+		OXOR,
+		OIOTA,
+		OCOMPLEX,
+		OREAL,
+		OIMAG:
+		if isgoconst(n.Left) && (n.Right == nil || isgoconst(n.Right)) {
+			return true
+		}
+
+	case OCONV:
+		if okforconst[n.Type.Etype] && isgoconst(n.Left) {
+			return true
+		}
+
+	case OLEN, OCAP:
+		l := n.Left
+		if isgoconst(l) {
+			return true
+		}
+
+		// Special case: len/cap is constant when applied to array or
+		// pointer to array when the expression does not contain
+		// function calls or channel receive operations.
+		t := l.Type
+
+		if t != nil && Isptr[t.Etype] {
+			t = t.Type
+		}
+		if Isfixedarray(t) && !hascallchan(l) {
+			return true
+		}
+
+	case OLITERAL:
+		if n.Val().Ctype() != CTNIL {
+			return true
+		}
+
+	case ONAME:
+		l := n.Sym.Def
+		if l != nil && l.Op == OLITERAL && n.Val().Ctype() != CTNIL {
+			return true
+		}
+
+	case ONONAME:
+		if n.Sym.Def != nil && n.Sym.Def.Op == OIOTA {
+			return true
+		}
+
+		// Only constant calls are unsafe.Alignof, Offsetof, and Sizeof.
+	case OCALL:
+		l := n.Left
+
+		for l.Op == OPAREN {
+			l = l.Left
+		}
+		if l.Op != ONAME || l.Sym.Pkg != unsafepkg {
+			break
+		}
+		if l.Sym.Name == "Alignof" || l.Sym.Name == "Offsetof" || l.Sym.Name == "Sizeof" {
+			return true
+		}
+	}
+
+	//dump("nonconst", n);
+	return false
+}
+
+func hascallchan(n *Node) bool {
+	if n == nil {
+		return false
+	}
+	switch n.Op {
+	case OAPPEND,
+		OCALL,
+		OCALLFUNC,
+		OCALLINTER,
+		OCALLMETH,
+		OCAP,
+		OCLOSE,
+		OCOMPLEX,
+		OCOPY,
+		ODELETE,
+		OIMAG,
+		OLEN,
+		OMAKE,
+		ONEW,
+		OPANIC,
+		OPRINT,
+		OPRINTN,
+		OREAL,
+		ORECOVER,
+		ORECV:
+		return true
+	}
+
+	if hascallchan(n.Left) || hascallchan(n.Right) {
+		return true
+	}
+
+	for l := n.List; l != nil; l = l.Next {
+		if hascallchan(l.N) {
+			return true
+		}
+	}
+	for l := n.Rlist; l != nil; l = l.Next {
+		if hascallchan(l.N) {
+			return true
+		}
+	}
+
+	return false
+}
diff --git a/src/cmd/compile/internal/gc/cplx.go b/src/cmd/compile/internal/gc/cplx.go
new file mode 100644
index 0000000..1643f26
--- /dev/null
+++ b/src/cmd/compile/internal/gc/cplx.go
@@ -0,0 +1,479 @@
+// 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"
+
+func overlap_cplx(f *Node, t *Node) bool {
+	// check whether f and t could be overlapping stack references.
+	// not exact, because it's hard to check for the stack register
+	// in portable code.  close enough: worst case we will allocate
+	// an extra temporary and the registerizer will clean it up.
+	return f.Op == OINDREG && t.Op == OINDREG && f.Xoffset+f.Type.Width >= t.Xoffset && t.Xoffset+t.Type.Width >= f.Xoffset
+}
+
+func complexbool(op int, nl, nr, res *Node, wantTrue bool, likely int, to *obj.Prog) {
+	// make both sides addable in ullman order
+	if nr != nil {
+		if nl.Ullman > nr.Ullman && !nl.Addable {
+			nl = CgenTemp(nl)
+		}
+
+		if !nr.Addable {
+			nr = CgenTemp(nr)
+		}
+	}
+	if !nl.Addable {
+		nl = CgenTemp(nl)
+	}
+
+	// Break nl and nr into real and imaginary components.
+	var lreal, limag, rreal, rimag Node
+	subnode(&lreal, &limag, nl)
+	subnode(&rreal, &rimag, nr)
+
+	// build tree
+	// if branching:
+	// 	real(l) == real(r) && imag(l) == imag(r)
+	// if generating a value, use a branch-free version:
+	// 	real(l) == real(r) & imag(l) == imag(r)
+	realeq := Node{
+		Op:    OEQ,
+		Left:  &lreal,
+		Right: &rreal,
+		Type:  Types[TBOOL],
+	}
+	imageq := Node{
+		Op:    OEQ,
+		Left:  &limag,
+		Right: &rimag,
+		Type:  Types[TBOOL],
+	}
+	and := Node{
+		Op:    OANDAND,
+		Left:  &realeq,
+		Right: &imageq,
+		Type:  Types[TBOOL],
+	}
+
+	if res != nil {
+		// generating a value
+		and.Op = OAND
+		if op == ONE {
+			and.Op = OOR
+			realeq.Op = ONE
+			imageq.Op = ONE
+		}
+		Bvgen(&and, res, true)
+		return
+	}
+
+	// generating a branch
+	if op == ONE {
+		wantTrue = !wantTrue
+	}
+
+	Bgen(&and, wantTrue, likely, to)
+}
+
+// break addable nc-complex into nr-real and ni-imaginary
+func subnode(nr *Node, ni *Node, nc *Node) {
+	if !nc.Addable {
+		Fatal("subnode not addable")
+	}
+
+	tc := Simsimtype(nc.Type)
+	tc = cplxsubtype(tc)
+	t := Types[tc]
+
+	if nc.Op == OLITERAL {
+		nodfconst(nr, t, &nc.Val().U.(*Mpcplx).Real)
+		nodfconst(ni, t, &nc.Val().U.(*Mpcplx).Imag)
+		return
+	}
+
+	*nr = *nc
+	nr.Type = t
+
+	*ni = *nc
+	ni.Type = t
+	ni.Xoffset += t.Width
+}
+
+// generate code res = -nl
+func minus(nl *Node, res *Node) {
+	var ra Node
+	ra.Op = OMINUS
+	ra.Left = nl
+	ra.Type = nl.Type
+	Cgen(&ra, res)
+}
+
+// build and execute tree
+//	real(res) = -real(nl)
+//	imag(res) = -imag(nl)
+func complexminus(nl *Node, res *Node) {
+	var n1 Node
+	var n2 Node
+	var n5 Node
+	var n6 Node
+
+	subnode(&n1, &n2, nl)
+	subnode(&n5, &n6, res)
+
+	minus(&n1, &n5)
+	minus(&n2, &n6)
+}
+
+// build and execute tree
+//	real(res) = real(nl) op real(nr)
+//	imag(res) = imag(nl) op imag(nr)
+func complexadd(op int, nl *Node, nr *Node, res *Node) {
+	var n1 Node
+	var n2 Node
+	var n3 Node
+	var n4 Node
+	var n5 Node
+	var n6 Node
+
+	subnode(&n1, &n2, nl)
+	subnode(&n3, &n4, nr)
+	subnode(&n5, &n6, res)
+
+	var ra Node
+	ra.Op = uint8(op)
+	ra.Left = &n1
+	ra.Right = &n3
+	ra.Type = n1.Type
+	Cgen(&ra, &n5)
+
+	ra = Node{}
+	ra.Op = uint8(op)
+	ra.Left = &n2
+	ra.Right = &n4
+	ra.Type = n2.Type
+	Cgen(&ra, &n6)
+}
+
+// build and execute tree
+//	tmp       = real(nl)*real(nr) - imag(nl)*imag(nr)
+//	imag(res) = real(nl)*imag(nr) + imag(nl)*real(nr)
+//	real(res) = tmp
+func complexmul(nl *Node, nr *Node, res *Node) {
+	var n1 Node
+	var n2 Node
+	var n3 Node
+	var n4 Node
+	var n5 Node
+	var n6 Node
+	var tmp Node
+
+	subnode(&n1, &n2, nl)
+	subnode(&n3, &n4, nr)
+	subnode(&n5, &n6, res)
+	Tempname(&tmp, n5.Type)
+
+	// real part -> tmp
+	var rm1 Node
+
+	rm1.Op = OMUL
+	rm1.Left = &n1
+	rm1.Right = &n3
+	rm1.Type = n1.Type
+
+	var rm2 Node
+	rm2.Op = OMUL
+	rm2.Left = &n2
+	rm2.Right = &n4
+	rm2.Type = n2.Type
+
+	var ra Node
+	ra.Op = OSUB
+	ra.Left = &rm1
+	ra.Right = &rm2
+	ra.Type = rm1.Type
+	Cgen(&ra, &tmp)
+
+	// imag part
+	rm1 = Node{}
+
+	rm1.Op = OMUL
+	rm1.Left = &n1
+	rm1.Right = &n4
+	rm1.Type = n1.Type
+
+	rm2 = Node{}
+	rm2.Op = OMUL
+	rm2.Left = &n2
+	rm2.Right = &n3
+	rm2.Type = n2.Type
+
+	ra = Node{}
+	ra.Op = OADD
+	ra.Left = &rm1
+	ra.Right = &rm2
+	ra.Type = rm1.Type
+	Cgen(&ra, &n6)
+
+	// tmp ->real part
+	Cgen(&tmp, &n5)
+}
+
+func nodfconst(n *Node, t *Type, fval *Mpflt) {
+	*n = Node{}
+	n.Op = OLITERAL
+	n.Addable = true
+	ullmancalc(n)
+	n.SetVal(Val{fval})
+	n.Type = t
+
+	if !Isfloat[t.Etype] {
+		Fatal("nodfconst: bad type %v", t)
+	}
+}
+
+func Complexop(n *Node, res *Node) bool {
+	if n != nil && n.Type != nil {
+		if Iscomplex[n.Type.Etype] {
+			goto maybe
+		}
+	}
+
+	if res != nil && res.Type != nil {
+		if Iscomplex[res.Type.Etype] {
+			goto maybe
+		}
+	}
+
+	if n.Op == OREAL || n.Op == OIMAG {
+		//dump("\ncomplex-yes", n);
+		return true
+	}
+
+	//dump("\ncomplex-no", n);
+	return false
+
+maybe:
+	switch n.Op {
+	case OCONV, // implemented ops
+		OADD,
+		OSUB,
+		OMUL,
+		OMINUS,
+		OCOMPLEX,
+		OREAL,
+		OIMAG:
+		//dump("\ncomplex-yes", n);
+		return true
+
+	case ODOT,
+		ODOTPTR,
+		OINDEX,
+		OIND,
+		ONAME:
+		//dump("\ncomplex-yes", n);
+		return true
+	}
+
+	//dump("\ncomplex-no", n);
+	return false
+}
+
+func Complexmove(f *Node, t *Node) {
+	if Debug['g'] != 0 {
+		Dump("\ncomplexmove-f", f)
+		Dump("complexmove-t", t)
+	}
+
+	if !t.Addable {
+		Fatal("complexmove: to not addable")
+	}
+
+	ft := Simsimtype(f.Type)
+	tt := Simsimtype(t.Type)
+	switch uint32(ft)<<16 | uint32(tt) {
+	default:
+		Fatal("complexmove: unknown conversion: %v -> %v\n", f.Type, t.Type)
+
+		// complex to complex move/convert.
+	// make f addable.
+	// also use temporary if possible stack overlap.
+	case TCOMPLEX64<<16 | TCOMPLEX64,
+		TCOMPLEX64<<16 | TCOMPLEX128,
+		TCOMPLEX128<<16 | TCOMPLEX64,
+		TCOMPLEX128<<16 | TCOMPLEX128:
+		if !f.Addable || overlap_cplx(f, t) {
+			var tmp Node
+			Tempname(&tmp, f.Type)
+			Complexmove(f, &tmp)
+			f = &tmp
+		}
+
+		var n1 Node
+		var n2 Node
+		subnode(&n1, &n2, f)
+		var n4 Node
+		var n3 Node
+		subnode(&n3, &n4, t)
+
+		Cgen(&n1, &n3)
+		Cgen(&n2, &n4)
+	}
+}
+
+func Complexgen(n *Node, res *Node) {
+	if Debug['g'] != 0 {
+		Dump("\ncomplexgen-n", n)
+		Dump("complexgen-res", res)
+	}
+
+	for n.Op == OCONVNOP {
+		n = n.Left
+	}
+
+	// pick off float/complex opcodes
+	switch n.Op {
+	case OCOMPLEX:
+		if res.Addable {
+			var n1 Node
+			var n2 Node
+			subnode(&n1, &n2, res)
+			var tmp Node
+			Tempname(&tmp, n1.Type)
+			Cgen(n.Left, &tmp)
+			Cgen(n.Right, &n2)
+			Cgen(&tmp, &n1)
+			return
+		}
+
+	case OREAL, OIMAG:
+		nl := n.Left
+		if !nl.Addable {
+			var tmp Node
+			Tempname(&tmp, nl.Type)
+			Complexgen(nl, &tmp)
+			nl = &tmp
+		}
+
+		var n1 Node
+		var n2 Node
+		subnode(&n1, &n2, nl)
+		if n.Op == OREAL {
+			Cgen(&n1, res)
+			return
+		}
+
+		Cgen(&n2, res)
+		return
+	}
+
+	// perform conversion from n to res
+	tl := Simsimtype(res.Type)
+
+	tl = cplxsubtype(tl)
+	tr := Simsimtype(n.Type)
+	tr = cplxsubtype(tr)
+	if tl != tr {
+		if !n.Addable {
+			var n1 Node
+			Tempname(&n1, n.Type)
+			Complexmove(n, &n1)
+			n = &n1
+		}
+
+		Complexmove(n, res)
+		return
+	}
+
+	if !res.Addable {
+		var n1 Node
+		Igen(res, &n1, nil)
+		Cgen(n, &n1)
+		Regfree(&n1)
+		return
+	}
+
+	if n.Addable {
+		Complexmove(n, res)
+		return
+	}
+
+	switch n.Op {
+	default:
+		Dump("complexgen: unknown op", n)
+		Fatal("complexgen: unknown op %v", Oconv(int(n.Op), 0))
+
+	case ODOT,
+		ODOTPTR,
+		OINDEX,
+		OIND,
+		ONAME, // PHEAP or PPARAMREF var
+		OCALLFUNC,
+		OCALLMETH,
+		OCALLINTER:
+		var n1 Node
+		Igen(n, &n1, res)
+
+		Complexmove(&n1, res)
+		Regfree(&n1)
+		return
+
+	case OCONV,
+		OADD,
+		OSUB,
+		OMUL,
+		OMINUS,
+		OCOMPLEX,
+		OREAL,
+		OIMAG:
+		break
+	}
+
+	nl := n.Left
+	if nl == nil {
+		return
+	}
+	nr := n.Right
+
+	// make both sides addable in ullman order
+	var tnl Node
+	if nr != nil {
+		if nl.Ullman > nr.Ullman && !nl.Addable {
+			Tempname(&tnl, nl.Type)
+			Cgen(nl, &tnl)
+			nl = &tnl
+		}
+
+		if !nr.Addable {
+			var tnr Node
+			Tempname(&tnr, nr.Type)
+			Cgen(nr, &tnr)
+			nr = &tnr
+		}
+	}
+
+	if !nl.Addable {
+		Tempname(&tnl, nl.Type)
+		Cgen(nl, &tnl)
+		nl = &tnl
+	}
+
+	switch n.Op {
+	default:
+		Fatal("complexgen: unknown op %v", Oconv(int(n.Op), 0))
+
+	case OCONV:
+		Complexmove(nl, res)
+
+	case OMINUS:
+		complexminus(nl, res)
+
+	case OADD, OSUB:
+		complexadd(int(n.Op), nl, nr, res)
+
+	case OMUL:
+		complexmul(nl, nr, res)
+	}
+}
diff --git a/src/cmd/compile/internal/gc/dcl.go b/src/cmd/compile/internal/gc/dcl.go
new file mode 100644
index 0000000..c8864f3
--- /dev/null
+++ b/src/cmd/compile/internal/gc/dcl.go
@@ -0,0 +1,1513 @@
+// 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"
+	"strings"
+)
+
+func dflag() bool {
+	if Debug['d'] == 0 {
+		return false
+	}
+	if Debug['y'] != 0 {
+		return true
+	}
+	if incannedimport != 0 {
+		return false
+	}
+	return true
+}
+
+/*
+ * declaration stack & operations
+ */
+func dcopy(a *Sym, b *Sym) {
+	a.Pkg = b.Pkg
+	a.Name = b.Name
+	a.Def = b.Def
+	a.Block = b.Block
+	a.Lastlineno = b.Lastlineno
+}
+
+func push() *Sym {
+	d := new(Sym)
+	d.Lastlineno = lineno
+	d.Link = dclstack
+	dclstack = d
+	return d
+}
+
+func pushdcl(s *Sym) *Sym {
+	d := push()
+	dcopy(d, s)
+	if dflag() {
+		fmt.Printf("\t%v push %v %p\n", Ctxt.Line(int(lineno)), s, s.Def)
+	}
+	return d
+}
+
+func popdcl() {
+	var d *Sym
+	var s *Sym
+	var lno int
+
+	//	if(dflag())
+	//		print("revert\n");
+
+	for d = dclstack; d != nil; d = d.Link {
+		if d.Name == "" {
+			break
+		}
+		s = Pkglookup(d.Name, d.Pkg)
+		lno = int(s.Lastlineno)
+		dcopy(s, d)
+		d.Lastlineno = int32(lno)
+		if dflag() {
+			fmt.Printf("\t%v pop %v %p\n", Ctxt.Line(int(lineno)), s, s.Def)
+		}
+	}
+
+	if d == nil {
+		Fatal("popdcl: no mark")
+	}
+	dclstack = d.Link
+	block = d.Block
+}
+
+func poptodcl() {
+	// pop the old marker and push a new one
+	// (cannot reuse the existing one)
+	// because we use the markers to identify blocks
+	// for the goto restriction checks.
+	popdcl()
+
+	markdcl()
+}
+
+func markdcl() {
+	d := push()
+	d.Name = "" // used as a mark in fifo
+	d.Block = block
+
+	blockgen++
+	block = blockgen
+}
+
+//	if(dflag())
+//		print("markdcl\n");
+func dumpdcl(st string) {
+	var s *Sym
+
+	i := 0
+	for d := dclstack; d != nil; d = d.Link {
+		i++
+		fmt.Printf("    %.2d %p", i, d)
+		if d.Name == "" {
+			fmt.Printf("\n")
+			continue
+		}
+
+		fmt.Printf(" '%s'", d.Name)
+		s = Pkglookup(d.Name, d.Pkg)
+		fmt.Printf(" %v\n", s)
+	}
+}
+
+func testdclstack() {
+	for d := dclstack; d != nil; d = d.Link {
+		if d.Name == "" {
+			if nerrors != 0 {
+				errorexit()
+			}
+			Yyerror("mark left on the stack")
+			continue
+		}
+	}
+}
+
+func redeclare(s *Sym, where string) {
+	if s.Lastlineno == 0 {
+		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 %q", s, where, pkgstr)
+	} else {
+		line1 := parserline()
+		line2 := int(s.Lastlineno)
+
+		// When an import and a declaration collide in separate files,
+		// present the import as the "redeclared", because the declaration
+		// is visible where the import is, but not vice versa.
+		// See issue 4510.
+		if s.Def == nil {
+			line2 = line1
+			line1 = int(s.Lastlineno)
+		}
+
+		yyerrorl(int(line1), "%v redeclared %s\n"+"\tprevious declaration at %v", s, where, Ctxt.Line(line2))
+	}
+}
+
+var vargen int
+
+/*
+ * declare individual names - var, typ, const
+ */
+
+var declare_typegen int
+
+func declare(n *Node, ctxt uint8) {
+	if ctxt == PDISCARD {
+		return
+	}
+
+	if isblank(n) {
+		return
+	}
+
+	if n.Name == nil {
+		// named OLITERAL needs Name; most OLITERALs don't.
+		n.Name = new(Name)
+	}
+	n.Lineno = int32(parserline())
+	s := n.Sym
+
+	// kludgy: typecheckok means we're past parsing.  Eg genwrapper may declare out of package names later.
+	if importpkg == nil && typecheckok == 0 && s.Pkg != localpkg {
+		Yyerror("cannot declare name %v", s)
+	}
+
+	if ctxt == PEXTERN && s.Name == "init" {
+		Yyerror("cannot declare init - must be func")
+	}
+
+	gen := 0
+	if ctxt == PEXTERN {
+		externdcl = list(externdcl, n)
+		if dflag() {
+			fmt.Printf("\t%v global decl %v %p\n", Ctxt.Line(int(lineno)), s, n)
+		}
+	} else {
+		if Curfn == nil && ctxt == PAUTO {
+			Fatal("automatic outside function")
+		}
+		if Curfn != nil {
+			Curfn.Func.Dcl = list(Curfn.Func.Dcl, n)
+		}
+		if n.Op == OTYPE {
+			declare_typegen++
+			gen = declare_typegen
+		} else if n.Op == ONAME && ctxt == PAUTO && !strings.Contains(s.Name, "·") {
+			vargen++
+			gen = vargen
+		}
+		pushdcl(s)
+		n.Name.Curfn = Curfn
+	}
+
+	if ctxt == PAUTO {
+		n.Xoffset = 0
+	}
+
+	if s.Block == block {
+		// functype will print errors about duplicate function arguments.
+		// Don't repeat the error here.
+		if ctxt != PPARAM && ctxt != PPARAMOUT {
+			redeclare(s, "in this block")
+		}
+	}
+
+	s.Block = block
+	s.Lastlineno = int32(parserline())
+	s.Def = n
+	n.Name.Vargen = int32(gen)
+	n.Name.Funcdepth = Funcdepth
+	n.Class = uint8(ctxt)
+
+	autoexport(n, ctxt)
+}
+
+func addvar(n *Node, t *Type, ctxt uint8) {
+	if n == nil || n.Sym == nil || (n.Op != ONAME && n.Op != ONONAME) || t == nil {
+		Fatal("addvar: n=%v t=%v nil", n, t)
+	}
+
+	n.Op = ONAME
+	declare(n, ctxt)
+	n.Type = t
+}
+
+/*
+ * declare variables from grammar
+ * new_name_list (type | [type] = expr_list)
+ */
+func variter(vl *NodeList, t *Node, el *NodeList) *NodeList {
+	var init *NodeList
+	doexpr := el != nil
+
+	if count(el) == 1 && count(vl) > 1 {
+		e := el.N
+		as2 := Nod(OAS2, nil, nil)
+		as2.List = vl
+		as2.Rlist = list1(e)
+		var v *Node
+		for ; vl != nil; vl = vl.Next {
+			v = vl.N
+			v.Op = ONAME
+			declare(v, dclcontext)
+			v.Name.Param.Ntype = t
+			v.Name.Defn = as2
+			if Funcdepth > 0 {
+				init = list(init, Nod(ODCL, v, nil))
+			}
+		}
+
+		return list(init, as2)
+	}
+
+	var v *Node
+	var e *Node
+	for ; vl != nil; vl = vl.Next {
+		if doexpr {
+			if el == nil {
+				Yyerror("missing expression in var declaration")
+				break
+			}
+
+			e = el.N
+			el = el.Next
+		} else {
+			e = nil
+		}
+
+		v = vl.N
+		v.Op = ONAME
+		declare(v, dclcontext)
+		v.Name.Param.Ntype = t
+
+		if e != nil || Funcdepth > 0 || isblank(v) {
+			if Funcdepth > 0 {
+				init = list(init, Nod(ODCL, v, nil))
+			}
+			e = Nod(OAS, v, e)
+			init = list(init, e)
+			if e.Right != nil {
+				v.Name.Defn = e
+			}
+		}
+	}
+
+	if el != nil {
+		Yyerror("extra expression in var declaration")
+	}
+	return init
+}
+
+/*
+ * declare constants from grammar
+ * new_name_list [[type] = expr_list]
+ */
+func constiter(vl *NodeList, t *Node, cl *NodeList) *NodeList {
+	lno := int32(0) // default is to leave line number alone in listtreecopy
+	if cl == nil {
+		if t != nil {
+			Yyerror("const declaration cannot have type without expression")
+		}
+		cl = lastconst
+		t = lasttype
+		lno = vl.N.Lineno
+	} else {
+		lastconst = cl
+		lasttype = t
+	}
+	cl = listtreecopy(cl, lno)
+
+	var v *Node
+	var c *Node
+	var vv *NodeList
+	for ; vl != nil; vl = vl.Next {
+		if cl == nil {
+			Yyerror("missing value in const declaration")
+			break
+		}
+
+		c = cl.N
+		cl = cl.Next
+
+		v = vl.N
+		v.Op = OLITERAL
+		declare(v, dclcontext)
+
+		v.Name.Param.Ntype = t
+		v.Name.Defn = c
+
+		vv = list(vv, Nod(ODCLCONST, v, nil))
+	}
+
+	if cl != nil {
+		Yyerror("extra expression in const declaration")
+	}
+	iota_ += 1
+	return vv
+}
+
+/*
+ * this generates a new name node,
+ * typically for labels or other one-off names.
+ */
+func newname(s *Sym) *Node {
+	if s == nil {
+		Fatal("newname nil")
+	}
+
+	n := Nod(ONAME, nil, nil)
+	n.Sym = s
+	n.Type = nil
+	n.Addable = true
+	n.Ullman = 1
+	n.Xoffset = 0
+	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)
+	n.Func.FCurfn = Curfn
+	return n
+}
+
+/*
+ * this generates a new name node for a name
+ * being declared.
+ */
+func dclname(s *Sym) *Node {
+	n := newname(s)
+	n.Op = ONONAME // caller will correct it
+	return n
+}
+
+func typenod(t *Type) *Node {
+	// if we copied another type with *t = *u
+	// then t->nod might be out of date, so
+	// check t->nod->type too
+	if t.Nod == nil || t.Nod.Type != t {
+		t.Nod = Nod(OTYPE, nil, nil)
+		t.Nod.Type = t
+		t.Nod.Sym = t.Sym
+	}
+
+	return t.Nod
+}
+
+/*
+ * this will return an old name
+ * that has already been pushed on the
+ * declaration list. a diagnostic is
+ * generated if no name has been defined.
+ */
+func oldname(s *Sym) *Node {
+	n := s.Def
+	if n == nil {
+		// maybe a top-level name will come along
+		// to give this a definition later.
+		// walkdef will check s->def again once
+		// all the input source has been processed.
+		n = newname(s)
+		n.Op = ONONAME
+		n.Name.Iota = iota_ // save current iota value in const declarations
+	}
+
+	if Curfn != nil && n.Op == ONAME && n.Name.Funcdepth > 0 && n.Name.Funcdepth != Funcdepth {
+		// inner func is referring to var in outer func.
+		//
+		// TODO(rsc): If there is an outer variable x and we
+		// are parsing x := 5 inside the closure, until we get to
+		// the := it looks like a reference to the outer x so we'll
+		// make x a closure variable unnecessarily.
+		if n.Name.Param.Closure == nil || n.Name.Param.Closure.Name.Funcdepth != Funcdepth {
+			// create new closure var.
+			c := Nod(ONAME, nil, nil)
+
+			c.Sym = s
+			c.Class = PPARAMREF
+			c.Isddd = n.Isddd
+			c.Name.Defn = n
+			c.Addable = false
+			c.Ullman = 2
+			c.Name.Funcdepth = Funcdepth
+			c.Name.Param.Outer = n.Name.Param.Closure
+			n.Name.Param.Closure = c
+			c.Name.Param.Closure = n
+			c.Xoffset = 0
+			Curfn.Func.Cvars = list(Curfn.Func.Cvars, c)
+		}
+
+		// return ref to closure var, not original
+		return n.Name.Param.Closure
+	}
+
+	return n
+}
+
+/*
+ * := declarations
+ */
+func colasname(n *Node) bool {
+	switch n.Op {
+	case ONAME,
+		ONONAME,
+		OPACK,
+		OTYPE,
+		OLITERAL:
+		return n.Sym != nil
+	}
+
+	return false
+}
+
+func colasdefn(left *NodeList, defn *Node) {
+	for l := left; l != nil; l = l.Next {
+		if l.N.Sym != nil {
+			l.N.Sym.Flags |= SymUniq
+		}
+	}
+
+	nnew := 0
+	nerr := 0
+	var n *Node
+	for l := left; l != nil; l = l.Next {
+		n = l.N
+		if isblank(n) {
+			continue
+		}
+		if !colasname(n) {
+			yyerrorl(int(defn.Lineno), "non-name %v on left side of :=", n)
+			nerr++
+			continue
+		}
+
+		if n.Sym.Flags&SymUniq == 0 {
+			yyerrorl(int(defn.Lineno), "%v repeated on left side of :=", n.Sym)
+			n.Diag++
+			nerr++
+			continue
+		}
+
+		n.Sym.Flags &^= SymUniq
+		if n.Sym.Block == block {
+			continue
+		}
+
+		nnew++
+		n = newname(n.Sym)
+		declare(n, dclcontext)
+		n.Name.Defn = defn
+		defn.Ninit = list(defn.Ninit, Nod(ODCL, n, nil))
+		l.N = n
+	}
+
+	if nnew == 0 && nerr == 0 {
+		yyerrorl(int(defn.Lineno), "no new variables on left side of :=")
+	}
+}
+
+func colas(left *NodeList, right *NodeList, lno int32) *Node {
+	as := Nod(OAS2, nil, nil)
+	as.List = left
+	as.Rlist = right
+	as.Colas = true
+	as.Lineno = lno
+	colasdefn(left, as)
+
+	// make the tree prettier; not necessary
+	if count(left) == 1 && count(right) == 1 {
+		as.Left = as.List.N
+		as.Right = as.Rlist.N
+		as.List = nil
+		as.Rlist = nil
+		as.Op = OAS
+	}
+
+	return as
+}
+
+/*
+ * declare the arguments in an
+ * interface field declaration.
+ */
+func ifacedcl(n *Node) {
+	if n.Op != ODCLFIELD || n.Right == nil {
+		Fatal("ifacedcl")
+	}
+
+	if isblank(n.Left) {
+		Yyerror("methods must have a unique non-blank name")
+	}
+
+	n.Func = new(Func)
+	n.Func.FCurfn = Curfn
+	dclcontext = PPARAM
+	markdcl()
+	Funcdepth++
+	n.Func.Outer = Curfn
+	Curfn = n
+	funcargs(n.Right)
+
+	// funcbody is normally called after the parser has
+	// seen the body of a function but since an interface
+	// field declaration does not have a body, we must
+	// call it now to pop the current declaration context.
+	dclcontext = PAUTO
+
+	funcbody(n)
+}
+
+/*
+ * declare the function proper
+ * and declare the arguments.
+ * called in extern-declaration context
+ * returns in auto-declaration context.
+ */
+func funchdr(n *Node) {
+	// change the declaration context from extern to auto
+	if Funcdepth == 0 && dclcontext != PEXTERN {
+		Fatal("funchdr: dclcontext")
+	}
+
+	if importpkg == nil && n.Func.Nname != nil {
+		makefuncsym(n.Func.Nname.Sym)
+	}
+
+	dclcontext = PAUTO
+	markdcl()
+	Funcdepth++
+
+	n.Func.Outer = Curfn
+	Curfn = n
+
+	if n.Func.Nname != nil {
+		funcargs(n.Func.Nname.Name.Param.Ntype)
+	} else if n.Func.Ntype != nil {
+		funcargs(n.Func.Ntype)
+	} else {
+		funcargs2(n.Type)
+	}
+}
+
+func funcargs(nt *Node) {
+	if nt.Op != OTFUNC {
+		Fatal("funcargs %v", Oconv(int(nt.Op), 0))
+	}
+
+	// re-start the variable generation number
+	// we want to use small numbers for the return variables,
+	// so let them have the chunk starting at 1.
+	vargen = count(nt.Rlist)
+
+	// declare the receiver and in arguments.
+	// no n->defn because type checking of func header
+	// will not fill in the types until later
+	if nt.Left != nil {
+		n := nt.Left
+		if n.Op != ODCLFIELD {
+			Fatal("funcargs receiver %v", Oconv(int(n.Op), 0))
+		}
+		if n.Left != nil {
+			n.Left.Op = ONAME
+			n.Left.Name.Param.Ntype = n.Right
+			declare(n.Left, PPARAM)
+			if dclcontext == PAUTO {
+				vargen++
+				n.Left.Name.Vargen = int32(vargen)
+			}
+		}
+	}
+
+	var n *Node
+	for l := nt.List; l != nil; l = l.Next {
+		n = l.N
+		if n.Op != ODCLFIELD {
+			Fatal("funcargs in %v", Oconv(int(n.Op), 0))
+		}
+		if n.Left != nil {
+			n.Left.Op = ONAME
+			n.Left.Name.Param.Ntype = n.Right
+			declare(n.Left, PPARAM)
+			if dclcontext == PAUTO {
+				vargen++
+				n.Left.Name.Vargen = int32(vargen)
+			}
+		}
+	}
+
+	// declare the out arguments.
+	gen := count(nt.List)
+	var i int = 0
+	var nn *Node
+	for l := nt.Rlist; l != nil; l = l.Next {
+		n = l.N
+
+		if n.Op != ODCLFIELD {
+			Fatal("funcargs out %v", Oconv(int(n.Op), 0))
+		}
+
+		if n.Left == nil {
+			// Name so that escape analysis can track it. ~r stands for 'result'.
+			n.Left = newname(Lookupf("~r%d", gen))
+			gen++
+		}
+
+		// TODO: n->left->missing = 1;
+		n.Left.Op = ONAME
+
+		if isblank(n.Left) {
+			// Give it a name so we can assign to it during return. ~b stands for 'blank'.
+			// The name must be different from ~r above because if you have
+			//	func f() (_ int)
+			//	func g() int
+			// f is allowed to use a plain 'return' with no arguments, while g is not.
+			// So the two cases must be distinguished.
+			// We do not record a pointer to the original node (n->orig).
+			// Having multiple names causes too much confusion in later passes.
+			nn = Nod(OXXX, nil, nil)
+
+			*nn = *n.Left
+			nn.Orig = nn
+			nn.Sym = Lookupf("~b%d", gen)
+			gen++
+			n.Left = nn
+		}
+
+		n.Left.Name.Param.Ntype = n.Right
+		declare(n.Left, PPARAMOUT)
+		if dclcontext == PAUTO {
+			i++
+			n.Left.Name.Vargen = int32(i)
+		}
+	}
+}
+
+/*
+ * Same as funcargs, except run over an already constructed TFUNC.
+ * This happens during import, where the hidden_fndcl rule has
+ * used functype directly to parse the function's type.
+ */
+func funcargs2(t *Type) {
+	if t.Etype != TFUNC {
+		Fatal("funcargs2 %v", t)
+	}
+
+	if t.Thistuple != 0 {
+		var n *Node
+		for ft := getthisx(t).Type; ft != nil; ft = ft.Down {
+			if ft.Nname == nil || ft.Nname.Sym == nil {
+				continue
+			}
+			n = ft.Nname // no need for newname(ft->nname->sym)
+			n.Type = ft.Type
+			declare(n, PPARAM)
+		}
+	}
+
+	if t.Intuple != 0 {
+		var n *Node
+		for ft := getinargx(t).Type; ft != nil; ft = ft.Down {
+			if ft.Nname == nil || ft.Nname.Sym == nil {
+				continue
+			}
+			n = ft.Nname
+			n.Type = ft.Type
+			declare(n, PPARAM)
+		}
+	}
+
+	if t.Outtuple != 0 {
+		var n *Node
+		for ft := getoutargx(t).Type; ft != nil; ft = ft.Down {
+			if ft.Nname == nil || ft.Nname.Sym == nil {
+				continue
+			}
+			n = ft.Nname
+			n.Type = ft.Type
+			declare(n, PPARAMOUT)
+		}
+	}
+}
+
+/*
+ * finish the body.
+ * called in auto-declaration context.
+ * returns in extern-declaration context.
+ */
+func funcbody(n *Node) {
+	// change the declaration context from auto to extern
+	if dclcontext != PAUTO {
+		Fatal("funcbody: dclcontext")
+	}
+	popdcl()
+	Funcdepth--
+	Curfn = n.Func.Outer
+	n.Func.Outer = nil
+	if Funcdepth == 0 {
+		dclcontext = PEXTERN
+	}
+}
+
+/*
+ * new type being defined with name s.
+ */
+func typedcl0(s *Sym) *Node {
+	n := newname(s)
+	n.Op = OTYPE
+	declare(n, dclcontext)
+	return n
+}
+
+/*
+ * node n, which was returned by typedcl0
+ * is being declared to have uncompiled type t.
+ * return the ODCLTYPE node to use.
+ */
+func typedcl1(n *Node, t *Node, local bool) *Node {
+	n.Name.Param.Ntype = t
+	n.Local = local
+	return Nod(ODCLTYPE, n, nil)
+}
+
+/*
+ * structs, functions, and methods.
+ * they don't belong here, but where do they belong?
+ */
+func checkembeddedtype(t *Type) {
+	if t == nil {
+		return
+	}
+
+	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] {
+		Yyerror("embedded type cannot be a pointer")
+	} else if t.Etype == TFORW && t.Embedlineno == 0 {
+		t.Embedlineno = lineno
+	}
+}
+
+func structfield(n *Node) *Type {
+	lno := int(lineno)
+	lineno = n.Lineno
+
+	if n.Op != ODCLFIELD {
+		Fatal("structfield: oops %v\n", n)
+	}
+
+	f := typ(TFIELD)
+	f.Isddd = n.Isddd
+
+	if n.Right != nil {
+		typecheck(&n.Right, Etype)
+		n.Type = n.Right.Type
+		if n.Left != nil {
+			n.Left.Type = n.Type
+		}
+		if n.Embedded != 0 {
+			checkembeddedtype(n.Type)
+		}
+	}
+
+	n.Right = nil
+
+	f.Type = n.Type
+	if f.Type == nil {
+		f.Broke = 1
+	}
+
+	switch n.Val().Ctype() {
+	case CTSTR:
+		f.Note = new(string)
+		*f.Note = n.Val().U.(string)
+
+	default:
+		Yyerror("field annotation must be string")
+		fallthrough
+
+	case CTxxx:
+		f.Note = nil
+	}
+
+	if n.Left != nil && n.Left.Op == ONAME {
+		f.Nname = n.Left
+		f.Embedded = n.Embedded
+		f.Sym = f.Nname.Sym
+	}
+
+	lineno = int32(lno)
+	return f
+}
+
+var uniqgen uint32
+
+func checkdupfields(t *Type, what string) {
+	lno := int(lineno)
+
+	for ; t != nil; t = t.Down {
+		if t.Sym != nil && t.Nname != nil && !isblank(t.Nname) {
+			if t.Sym.Uniqgen == uniqgen {
+				lineno = t.Nname.Lineno
+				Yyerror("duplicate %s %s", what, t.Sym.Name)
+			} else {
+				t.Sym.Uniqgen = uniqgen
+			}
+		}
+	}
+
+	lineno = int32(lno)
+}
+
+/*
+ * convert a parsed id/type list into
+ * a type for struct/interface/arglist
+ */
+func tostruct(l *NodeList) *Type {
+	var f *Type
+	t := typ(TSTRUCT)
+
+	for tp := &t.Type; l != nil; l = l.Next {
+		f = structfield(l.N)
+
+		*tp = f
+		tp = &f.Down
+	}
+
+	for f := t.Type; f != nil && t.Broke == 0; f = f.Down {
+		if f.Broke != 0 {
+			t.Broke = 1
+		}
+	}
+
+	uniqgen++
+	checkdupfields(t.Type, "field")
+
+	if t.Broke == 0 {
+		checkwidth(t)
+	}
+
+	return t
+}
+
+func tofunargs(l *NodeList) *Type {
+	var f *Type
+
+	t := typ(TSTRUCT)
+	t.Funarg = 1
+
+	for tp := &t.Type; l != nil; l = l.Next {
+		f = structfield(l.N)
+		f.Funarg = 1
+
+		// esc.c needs to find f given a PPARAM to add the tag.
+		if l.N.Left != nil && l.N.Left.Class == PPARAM {
+			l.N.Left.Name.Param.Field = f
+		}
+
+		*tp = f
+		tp = &f.Down
+	}
+
+	for f := t.Type; f != nil && t.Broke == 0; f = f.Down {
+		if f.Broke != 0 {
+			t.Broke = 1
+		}
+	}
+
+	return t
+}
+
+func interfacefield(n *Node) *Type {
+	lno := int(lineno)
+	lineno = n.Lineno
+
+	if n.Op != ODCLFIELD {
+		Fatal("interfacefield: oops %v\n", n)
+	}
+
+	if n.Val().Ctype() != CTxxx {
+		Yyerror("interface method cannot have annotation")
+	}
+
+	f := typ(TFIELD)
+	f.Isddd = n.Isddd
+
+	if n.Right != nil {
+		if n.Left != nil {
+			// queue resolution of method type for later.
+			// right now all we need is the name list.
+			// avoids cycles for recursive interface types.
+			n.Type = typ(TINTERMETH)
+
+			n.Type.Nname = n.Right
+			n.Left.Type = n.Type
+			queuemethod(n)
+
+			if n.Left.Op == ONAME {
+				f.Nname = n.Left
+				f.Embedded = n.Embedded
+				f.Sym = f.Nname.Sym
+			}
+		} else {
+			typecheck(&n.Right, Etype)
+			n.Type = n.Right.Type
+
+			if n.Embedded != 0 {
+				checkembeddedtype(n.Type)
+			}
+
+			if n.Type != nil {
+				switch n.Type.Etype {
+				case TINTER:
+					break
+
+				case TFORW:
+					Yyerror("interface type loop involving %v", n.Type)
+					f.Broke = 1
+
+				default:
+					Yyerror("interface contains embedded non-interface %v", n.Type)
+					f.Broke = 1
+				}
+			}
+		}
+	}
+
+	n.Right = nil
+
+	f.Type = n.Type
+	if f.Type == nil {
+		f.Broke = 1
+	}
+
+	lineno = int32(lno)
+	return f
+}
+
+func tointerface(l *NodeList) *Type {
+	var f *Type
+	var t1 *Type
+
+	t := typ(TINTER)
+
+	tp := &t.Type
+	for ; l != nil; l = l.Next {
+		f = interfacefield(l.N)
+
+		if l.N.Left == nil && f.Type.Etype == TINTER {
+			// embedded interface, inline methods
+			for t1 = f.Type.Type; t1 != nil; t1 = t1.Down {
+				f = typ(TFIELD)
+				f.Type = t1.Type
+				f.Broke = t1.Broke
+				f.Sym = t1.Sym
+				if f.Sym != nil {
+					f.Nname = newname(f.Sym)
+				}
+				*tp = f
+				tp = &f.Down
+			}
+		} else {
+			*tp = f
+			tp = &f.Down
+		}
+	}
+
+	for f := t.Type; f != nil && t.Broke == 0; f = f.Down {
+		if f.Broke != 0 {
+			t.Broke = 1
+		}
+	}
+
+	uniqgen++
+	checkdupfields(t.Type, "method")
+	t = sortinter(t)
+	checkwidth(t)
+
+	return t
+}
+
+func embedded(s *Sym, pkg *Pkg) *Node {
+	const (
+		CenterDot = 0xB7
+	)
+	// Names sometimes have disambiguation junk
+	// appended after a center dot.  Discard it when
+	// making the name for the embedded struct field.
+	name := s.Name
+
+	if i := strings.Index(s.Name, string(CenterDot)); i >= 0 {
+		name = s.Name[:i]
+	}
+
+	var n *Node
+	if exportname(name) {
+		n = newname(Lookup(name))
+	} else if s.Pkg == builtinpkg {
+		// The name of embedded builtins belongs to pkg.
+		n = newname(Pkglookup(name, pkg))
+	} else {
+		n = newname(Pkglookup(name, s.Pkg))
+	}
+	n = Nod(ODCLFIELD, n, oldname(s))
+	n.Embedded = 1
+	return n
+}
+
+/*
+ * check that the list of declarations is either all anonymous or all named
+ */
+func findtype(l *NodeList) *Node {
+	for ; l != nil; l = l.Next {
+		if l.N.Op == OKEY {
+			return l.N.Right
+		}
+	}
+	return nil
+}
+
+func checkarglist(all *NodeList, input int) *NodeList {
+	named := 0
+	for l := all; l != nil; l = l.Next {
+		if l.N.Op == OKEY {
+			named = 1
+			break
+		}
+	}
+
+	if named != 0 {
+		var n *Node
+		var l *NodeList
+		for l = all; l != nil; l = l.Next {
+			n = l.N
+			if n.Op != OKEY && n.Sym == nil {
+				Yyerror("mixed named and unnamed function parameters")
+				break
+			}
+		}
+
+		if l == nil && n != nil && n.Op != OKEY {
+			Yyerror("final function parameter must have type")
+		}
+	}
+
+	var nextt *Node
+	var t *Node
+	var n *Node
+	for l := all; l != nil; l = l.Next {
+		// can cache result from findtype to avoid
+		// quadratic behavior here, but unlikely to matter.
+		n = l.N
+
+		if named != 0 {
+			if n.Op == OKEY {
+				t = n.Right
+				n = n.Left
+				nextt = nil
+			} else {
+				if nextt == nil {
+					nextt = findtype(l)
+				}
+				t = nextt
+			}
+		} else {
+			t = n
+			n = nil
+		}
+
+		// during import l->n->op is OKEY, but l->n->left->sym == S
+		// means it was a '?', not that it was
+		// a lone type This doesn't matter for the exported
+		// declarations, which are parsed by rules that don't
+		// use checkargs, but can happen for func literals in
+		// the inline bodies.
+		// TODO(rsc) this can go when typefmt case TFIELD in exportmode fmt.c prints _ instead of ?
+		if importpkg != nil && n.Sym == nil {
+			n = nil
+		}
+
+		if n != nil && n.Sym == nil {
+			t = n
+			n = nil
+		}
+
+		if n != nil {
+			n = newname(n.Sym)
+		}
+		n = Nod(ODCLFIELD, n, t)
+		if n.Right != nil && n.Right.Op == ODDD {
+			if input == 0 {
+				Yyerror("cannot use ... in output argument list")
+			} else if l.Next != nil {
+				Yyerror("can only use ... as final argument in list")
+			}
+			n.Right.Op = OTARRAY
+			n.Right.Right = n.Right.Left
+			n.Right.Left = nil
+			n.Isddd = true
+			if n.Left != nil {
+				n.Left.Isddd = true
+			}
+		}
+
+		l.N = n
+	}
+
+	return all
+}
+
+func fakethis() *Node {
+	n := Nod(ODCLFIELD, nil, typenod(Ptrto(typ(TSTRUCT))))
+	return n
+}
+
+/*
+ * Is this field a method on an interface?
+ * Those methods have an anonymous
+ * *struct{} as the receiver.
+ * (See fakethis above.)
+ */
+func isifacemethod(f *Type) bool {
+	rcvr := getthisx(f).Type
+	if rcvr.Sym != nil {
+		return false
+	}
+	t := rcvr.Type
+	if !Isptr[t.Etype] {
+		return false
+	}
+	t = t.Type
+	if t.Sym != nil || t.Etype != TSTRUCT || t.Type != nil {
+		return false
+	}
+	return true
+}
+
+/*
+ * turn a parsed function declaration
+ * into a type
+ */
+func functype(this *Node, in *NodeList, out *NodeList) *Type {
+	t := typ(TFUNC)
+
+	var rcvr *NodeList
+	if this != nil {
+		rcvr = list1(this)
+	}
+	t.Type = tofunargs(rcvr)
+	t.Type.Down = tofunargs(out)
+	t.Type.Down.Down = tofunargs(in)
+
+	uniqgen++
+	checkdupfields(t.Type.Type, "argument")
+	checkdupfields(t.Type.Down.Type, "argument")
+	checkdupfields(t.Type.Down.Down.Type, "argument")
+
+	if t.Type.Broke != 0 || t.Type.Down.Broke != 0 || t.Type.Down.Down.Broke != 0 {
+		t.Broke = 1
+	}
+
+	if this != nil {
+		t.Thistuple = 1
+	}
+	t.Outtuple = count(out)
+	t.Intuple = count(in)
+	t.Outnamed = 0
+	if t.Outtuple > 0 && out.N.Left != nil && out.N.Left.Orig != nil {
+		s := out.N.Left.Orig.Sym
+		if s != nil && (s.Name[0] != '~' || s.Name[1] != 'r') { // ~r%d is the name invented for an unnamed result
+			t.Outnamed = 1
+		}
+	}
+
+	return t
+}
+
+var methodsym_toppkg *Pkg
+
+func methodsym(nsym *Sym, t0 *Type, iface int) *Sym {
+	var s *Sym
+	var p string
+	var suffix string
+	var spkg *Pkg
+
+	t := t0
+	if t == nil {
+		goto bad
+	}
+	s = t.Sym
+	if s == nil && Isptr[t.Etype] {
+		t = t.Type
+		if t == nil {
+			goto bad
+		}
+		s = t.Sym
+	}
+
+	spkg = nil
+	if s != nil {
+		spkg = s.Pkg
+	}
+
+	// if t0 == *t and t0 has a sym,
+	// we want to see *t, not t0, in the method name.
+	if t != t0 && t0.Sym != nil {
+		t0 = Ptrto(t)
+	}
+
+	suffix = ""
+	if iface != 0 {
+		dowidth(t0)
+		if t0.Width < Types[Tptr].Width {
+			suffix = "·i"
+		}
+	}
+
+	if (spkg == nil || nsym.Pkg != spkg) && !exportname(nsym.Name) {
+		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] {
+			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)
+		}
+	}
+
+	if spkg == nil {
+		if methodsym_toppkg == nil {
+			methodsym_toppkg = mkpkg("go")
+		}
+		spkg = methodsym_toppkg
+	}
+
+	s = Pkglookup(p, spkg)
+
+	return s
+
+bad:
+	Yyerror("illegal receiver type: %v", t0)
+	return nil
+}
+
+func methodname(n *Node, t *Type) *Node {
+	s := methodsym(n.Sym, t, 0)
+	if s == nil {
+		return n
+	}
+	return newname(s)
+}
+
+func methodname1(n *Node, t *Node) *Node {
+	star := ""
+	if t.Op == OIND {
+		star = "*"
+		t = t.Left
+	}
+
+	if t.Sym == nil || isblank(n) {
+		return newfuncname(n.Sym)
+	}
+
+	var p string
+	if star != "" {
+		p = fmt.Sprintf("(%s%v).%v", star, t.Sym, n.Sym)
+	} else {
+		p = fmt.Sprintf("%v.%v", t.Sym, n.Sym)
+	}
+
+	if exportname(t.Sym.Name) {
+		n = newfuncname(Lookup(p))
+	} else {
+		n = newfuncname(Pkglookup(p, t.Sym.Pkg))
+	}
+
+	return n
+}
+
+/*
+ * add a method, declared as a function,
+ * n is fieldname, pa is base type, t is function type
+ */
+func addmethod(sf *Sym, t *Type, local bool, nointerface bool) {
+	// get field sym
+	if sf == nil {
+		Fatal("no method symbol")
+	}
+
+	// get parent type sym
+	pa := getthisx(t).Type // ptr to this structure
+	if pa == nil {
+		Yyerror("missing receiver")
+		return
+	}
+
+	pa = pa.Type
+	f := methtype(pa, 1)
+	if f == nil {
+		t = pa
+		if t == nil { // rely on typecheck having complained before
+			return
+		}
+		if t != nil {
+			if Isptr[t.Etype] {
+				if t.Sym != nil {
+					Yyerror("invalid receiver type %v (%v is a pointer type)", pa, t)
+					return
+				}
+
+				t = t.Type
+			}
+
+			if t.Broke != 0 { // rely on typecheck having complained before
+				return
+			}
+			if t.Sym == nil {
+				Yyerror("invalid receiver type %v (%v is an unnamed type)", pa, t)
+				return
+			}
+
+			if Isptr[t.Etype] {
+				Yyerror("invalid receiver type %v (%v is a pointer type)", pa, t)
+				return
+			}
+
+			if t.Etype == TINTER {
+				Yyerror("invalid receiver type %v (%v is an interface type)", pa, t)
+				return
+			}
+		}
+
+		// Should have picked off all the reasons above,
+		// but just in case, fall back to generic error.
+		Yyerror("invalid receiver type %v (%v / %v)", pa, Tconv(pa, obj.FmtLong), Tconv(t, obj.FmtLong))
+
+		return
+	}
+
+	pa = f
+	if pa.Etype == TSTRUCT {
+		for f := pa.Type; f != nil; f = f.Down {
+			if f.Sym == sf {
+				Yyerror("type %v has both field and method named %v", pa, sf)
+				return
+			}
+		}
+	}
+
+	if local && !pa.Local {
+		// defining method on non-local type.
+		Yyerror("cannot define new methods on non-local type %v", pa)
+
+		return
+	}
+
+	n := Nod(ODCLFIELD, newname(sf), nil)
+	n.Type = t
+
+	var d *Type // last found
+	for f := pa.Method; f != nil; f = f.Down {
+		d = f
+		if f.Etype != TFIELD {
+			Fatal("addmethod: not TFIELD: %v", Tconv(f, obj.FmtLong))
+		}
+		if sf.Name != f.Sym.Name {
+			continue
+		}
+		if !Eqtype(t, f.Type) {
+			Yyerror("method redeclared: %v.%v\n\t%v\n\t%v", pa, sf, f.Type, t)
+		}
+		return
+	}
+
+	f = structfield(n)
+	f.Nointerface = nointerface
+
+	// during import unexported method names should be in the type's package
+	if importpkg != nil && f.Sym != nil && !exportname(f.Sym.Name) && f.Sym.Pkg != structpkg {
+		Fatal("imported method name %v in wrong package %s\n", Sconv(f.Sym, obj.FmtSign), structpkg.Name)
+	}
+
+	if d == nil {
+		pa.Method = f
+	} else {
+		d.Down = f
+	}
+	return
+}
+
+func funccompile(n *Node) {
+	Stksize = BADWIDTH
+	Maxarg = 0
+
+	if n.Type == nil {
+		if nerrors == 0 {
+			Fatal("funccompile missing type")
+		}
+		return
+	}
+
+	// assign parameter offsets
+	checkwidth(n.Type)
+
+	if Curfn != nil {
+		Fatal("funccompile %v inside %v", n.Func.Nname.Sym, Curfn.Func.Nname.Sym)
+	}
+
+	Stksize = 0
+	dclcontext = PAUTO
+	Funcdepth = n.Func.Depth + 1
+	compile(n)
+	Curfn = nil
+	Funcdepth = 0
+	dclcontext = PEXTERN
+}
+
+func funcsym(s *Sym) *Sym {
+	if s.Fsym != nil {
+		return s.Fsym
+	}
+
+	s1 := Pkglookup(s.Name+"·f", s.Pkg)
+	s.Fsym = s1
+	return s1
+}
+
+func makefuncsym(s *Sym) {
+	if isblanksym(s) {
+		return
+	}
+	if compiling_runtime != 0 && s.Name == "getg" {
+		// runtime.getg() is not a real function and so does
+		// not get a funcsym.
+		return
+	}
+	s1 := funcsym(s)
+	s1.Def = newfuncname(s1)
+	s1.Def.Func.Shortname = newname(s)
+	funcsyms = list(funcsyms, s1.Def)
+}
diff --git a/src/cmd/compile/internal/gc/esc.go b/src/cmd/compile/internal/gc/esc.go
new file mode 100644
index 0000000..4c4455f
--- /dev/null
+++ b/src/cmd/compile/internal/gc/esc.go
@@ -0,0 +1,1821 @@
+// 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 gc
+
+import (
+	"cmd/internal/obj"
+	"fmt"
+	"strings"
+)
+
+// Run analysis on minimal sets of mutually recursive functions
+// or single non-recursive functions, bottom up.
+//
+// Finding these sets is finding strongly connected components
+// in the static call graph.  The algorithm for doing that is taken
+// from Sedgewick, Algorithms, Second Edition, p. 482, with two
+// adaptations.
+//
+// First, a hidden closure function (n->curfn != N) cannot be the
+// root of a connected component. Refusing to use it as a root
+// forces it into the component of the function in which it appears.
+// This is more convenient for escape analysis.
+//
+// Second, each function becomes two virtual nodes in the graph,
+// with numbers n and n+1. We record the function's node number as n
+// but search from node n+1. If the search tells us that the component
+// number (min) is n+1, we know that this is a trivial component: one function
+// plus its closures. If the search tells us that the component number is
+// n, then there was a path from node n+1 back to node n, meaning that
+// the function set is mutually recursive. The escape analysis can be
+// more precise when analyzing a single non-recursive function than
+// when analyzing a set of mutually recursive functions.
+
+type bottomUpVisitor struct {
+	analyze  func(*NodeList, bool)
+	visitgen uint32
+	nodeID   map[*Node]uint32
+	stack    *NodeList
+}
+
+// visitBottomUp invokes analyze on the ODCLFUNC nodes listed in list.
+// It calls analyze with successive groups of functions, working from
+// the bottom of the call graph upward. Each time analyze is called with
+// a list of functions, every function on that list only calls other functions
+// on the list or functions that have been passed in previous invocations of
+// analyze. Closures appear in the same list as their outer functions.
+// The lists are as short as possible while preserving those requirements.
+// (In a typical program, many invocations of analyze will be passed just
+// a single function.) The boolean argument 'recursive' passed to analyze
+// specifies whether the functions on the list are mutually recursive.
+// If recursive is false, the list consists of only a single function and its closures.
+// If recursive is true, the list may still contain only a single function,
+// if that function is itself recursive.
+func visitBottomUp(list *NodeList, analyze func(list *NodeList, recursive bool)) {
+	var v bottomUpVisitor
+	v.analyze = analyze
+	v.nodeID = make(map[*Node]uint32)
+	for l := list; l != nil; l = l.Next {
+		if l.N.Op == ODCLFUNC && l.N.Func.FCurfn == nil {
+			v.visit(l.N)
+		}
+	}
+}
+
+func (v *bottomUpVisitor) visit(n *Node) uint32 {
+	if id := v.nodeID[n]; id > 0 {
+		// already visited
+		return id
+	}
+
+	v.visitgen++
+	id := v.visitgen
+	v.nodeID[n] = id
+	v.visitgen++
+	min := v.visitgen
+
+	l := new(NodeList)
+	l.Next = v.stack
+	l.N = n
+	v.stack = l
+	min = v.visitcodelist(n.Nbody, min)
+	if (min == id || min == id+1) && n.Func.FCurfn == nil {
+		// This node is the root of a strongly connected component.
+
+		// The original min passed to visitcodelist was n->walkgen+1.
+		// If visitcodelist found its way back to n->walkgen, then this
+		// block is a set of mutually recursive functions.
+		// Otherwise it's just a lone function that does not recurse.
+		recursive := min == id
+
+		// Remove connected component from stack.
+		// Mark walkgen so that future visits return a large number
+		// so as not to affect the caller's min.
+		block := v.stack
+
+		var l *NodeList
+		for l = v.stack; l.N != n; l = l.Next {
+			v.nodeID[l.N] = ^uint32(0)
+		}
+		v.nodeID[n] = ^uint32(0)
+		v.stack = l.Next
+		l.Next = nil
+
+		// Run escape analysis on this set of functions.
+		v.analyze(block, recursive)
+	}
+
+	return min
+}
+
+func (v *bottomUpVisitor) visitcodelist(l *NodeList, min uint32) uint32 {
+	for ; l != nil; l = l.Next {
+		min = v.visitcode(l.N, min)
+	}
+	return min
+}
+
+func (v *bottomUpVisitor) visitcode(n *Node, min uint32) uint32 {
+	if n == nil {
+		return min
+	}
+
+	min = v.visitcodelist(n.Ninit, min)
+	min = v.visitcode(n.Left, min)
+	min = v.visitcode(n.Right, min)
+	min = v.visitcodelist(n.List, min)
+	min = v.visitcodelist(n.Nbody, min)
+	min = v.visitcodelist(n.Rlist, min)
+
+	if n.Op == OCALLFUNC || n.Op == OCALLMETH {
+		fn := n.Left
+		if n.Op == OCALLMETH {
+			fn = n.Left.Right.Sym.Def
+		}
+		if fn != nil && fn.Op == ONAME && fn.Class == PFUNC && fn.Name.Defn != nil {
+			m := v.visit(fn.Name.Defn)
+			if m < min {
+				min = m
+			}
+		}
+	}
+
+	if n.Op == OCLOSURE {
+		m := v.visit(n.Func.Closure)
+		if m < min {
+			min = m
+		}
+	}
+
+	return min
+}
+
+// Escape analysis.
+
+// An escape analysis pass for a set of functions.
+// The analysis assumes that closures and the functions in which they
+// appear are analyzed together, so that the aliasing between their
+// variables can be modeled more precisely.
+//
+// First escfunc, esc and escassign recurse over the ast of each
+// function to dig out flow(dst,src) edges between any
+// pointer-containing nodes and store them in dst->escflowsrc.  For
+// variables assigned to a variable in an outer scope or used as a
+// return value, they store a flow(theSink, src) edge to a fake node
+// 'the Sink'.  For variables referenced in closures, an edge
+// flow(closure, &var) is recorded and the flow of a closure itself to
+// an outer scope is tracked the same way as other variables.
+//
+// Then escflood walks the graph starting at theSink and tags all
+// variables of it can reach an & node as escaping and all function
+// parameters it can reach as leaking.
+//
+// If a value's address is taken but the address does not escape,
+// then the value can stay on the stack.  If the value new(T) does
+// not escape, then new(T) can be rewritten into a stack allocation.
+// The same is true of slice literals.
+//
+// If optimizations are disabled (-N), this code is not used.
+// Instead, the compiler assumes that any value whose address
+// is taken without being immediately dereferenced
+// needs to be moved to the heap, and new(T) and slice
+// literals are always real allocations.
+
+func escapes(all *NodeList) {
+	visitBottomUp(all, escAnalyze)
+}
+
+const (
+	EscFuncUnknown = 0 + iota
+	EscFuncPlanned
+	EscFuncStarted
+	EscFuncTagged
+)
+
+// There appear to be some loops in the escape graph, causing
+// arbitrary recursion into deeper and deeper levels.
+// Cut this off safely by making minLevel sticky: once you
+// get that deep, you cannot go down any further but you also
+// cannot go up any further. This is a conservative fix.
+// Making minLevel smaller (more negative) would handle more
+// complex chains of indirections followed by address-of operations,
+// at the cost of repeating the traversal once for each additional
+// allowed level when a loop is encountered. Using -2 suffices to
+// pass all the tests we have written so far, which we assume matches
+// the level of complexity we want the escape analysis code to handle.
+const (
+	MinLevel = -2
+)
+
+// A Level encodes the reference state and context applied to
+// (stack, heap) allocated memory.
+//
+// value is the overall sum of *(1) and &(-1) operations encountered
+// along a path from a destination (sink, return value) to a source
+// (allocation, parameter).
+//
+// suffixValue is the maximum-copy-started-suffix-level applied to a sink.
+// For example:
+// sink = x.left.left --> level=2, x is dereferenced twice and does not escape to sink.
+// sink = &Node{x} --> level=-1, x is accessible from sink via one "address of"
+// sink = &Node{&Node{x}} --> level=-2, x is accessible from sink via two "address of"
+// sink = &Node{&Node{x.left}} --> level=-1, but x is NOT accessible from sink because it was indirected and then copied.
+// (The copy operations are sometimes implicit in the source code; in this case,
+// value of x.left was copied into a field of a newly allocated Node)
+//
+// There's one of these for each Node, and the integer values
+// rarely exceed even what can be stored in 4 bits, never mind 8.
+type Level struct {
+	value, suffixValue int8
+}
+
+func (l Level) int() int {
+	return int(l.value)
+}
+
+func levelFrom(i int) Level {
+	if i <= MinLevel {
+		return Level{value: MinLevel}
+	}
+	return Level{value: int8(i)}
+}
+
+func satInc8(x int8) int8 {
+	if x == 127 {
+		return 127
+	}
+	return x + 1
+}
+
+func satAdd8(x, y int8) int8 {
+	z := x + y
+	if x^y < 0 || x^z >= 0 {
+		return z
+	}
+	if x < 0 {
+		return -128
+	}
+	return 127
+}
+
+func min8(a, b int8) int8 {
+	if a < b {
+		return a
+	}
+	return b
+}
+
+func max8(a, b int8) int8 {
+	if a > b {
+		return a
+	}
+	return b
+}
+
+// inc returns the level l + 1, representing the effect of an indirect (*) operation.
+func (l Level) inc() Level {
+	if l.value <= MinLevel {
+		return Level{value: MinLevel}
+	}
+	return Level{value: satInc8(l.value), suffixValue: satInc8(l.suffixValue)}
+}
+
+// dec returns the level l - 1, representing the effect of an address-of (&) operation.
+func (l Level) dec() Level {
+	if l.value <= MinLevel {
+		return Level{value: MinLevel}
+	}
+	return Level{value: l.value - 1, suffixValue: l.suffixValue - 1}
+}
+
+// copy returns the level for a copy of a value with level l.
+func (l Level) copy() Level {
+	return Level{value: l.value, suffixValue: max8(l.suffixValue, 0)}
+}
+
+func (l1 Level) min(l2 Level) Level {
+	return Level{
+		value:       min8(l1.value, l2.value),
+		suffixValue: min8(l1.suffixValue, l2.suffixValue)}
+}
+
+// guaranteedDereference returns the number of dereferences
+// applied to a pointer before addresses are taken/generated.
+// This is the maximum level computed from path suffixes starting
+// with copies where paths flow from destination to source.
+func (l Level) guaranteedDereference() int {
+	return int(l.suffixValue)
+}
+
+type NodeEscState struct {
+	Curfn        *Node
+	Escflowsrc   *NodeList // flow(this, src)
+	Escretval    *NodeList // on OCALLxxx, list of dummy return values
+	Escloopdepth int32     // -1: global, 0: return variables, 1:function top level, increased inside function for every loop or label to mark scopes
+	Esclevel     Level
+	Walkgen      uint32
+}
+
+func (e *EscState) nodeEscState(n *Node) *NodeEscState {
+	if nE, ok := n.Opt().(*NodeEscState); ok {
+		return nE
+	}
+	if n.Opt() != nil {
+		Fatal("nodeEscState: opt in use (%T)", n.Opt())
+	}
+	nE := new(NodeEscState)
+	nE.Curfn = Curfn
+	n.SetOpt(nE)
+	e.opts = append(e.opts, n)
+	return nE
+}
+
+func (e *EscState) track(n *Node) {
+	if Curfn == nil {
+		Fatal("EscState.track: Curfn nil")
+	}
+	n.Esc = EscNone // until proven otherwise
+	nE := e.nodeEscState(n)
+	nE.Escloopdepth = e.loopdepth
+	e.noesc = list(e.noesc, n)
+}
+
+// Escape constants are numbered in order of increasing "escapiness"
+// to help make inferences be monotonic.  With the exception of
+// EscNever which is sticky, eX < eY means that eY is more exposed
+// than eX, and hence replaces it in a conservative analysis.
+const (
+	EscUnknown = iota
+	EscNone    // Does not escape to heap, result, or parameters.
+	EscReturn  // Is returned or reachable from returned.
+	EscScope   // Allocated in an inner loop scope, assigned to an outer loop scope,
+	// which allows the construction of non-escaping but arbitrarily large linked
+	// data structures (i.e., not eligible for allocation in a fixed-size stack frame).
+	EscHeap           // Reachable from the heap
+	EscNever          // By construction will not escape.
+	EscBits           = 3
+	EscMask           = (1 << EscBits) - 1
+	EscContentEscapes = 1 << EscBits // value obtained by indirect of parameter escapes to heap
+	EscReturnBits     = EscBits + 1
+	// Node.esc encoding = | escapeReturnEncoding:(width-4) | contentEscapes:1 | escEnum:3
+)
+
+// escMax returns the maximum of an existing escape value
+// (and its additional parameter flow flags) and a new escape type.
+func escMax(e, etype uint16) uint16 {
+	if e&EscMask >= EscScope {
+		// normalize
+		if e&^EscMask != 0 {
+			Fatal("Escape information had unexpected return encoding bits (w/ EscScope, EscHeap, EscNever), e&EscMask=%v", e&EscMask)
+		}
+	}
+	if e&EscMask > etype {
+		return e
+	}
+	if etype == EscNone || etype == EscReturn {
+		return (e &^ EscMask) | etype
+	}
+	return etype
+}
+
+// For each input parameter to a function, the escapeReturnEncoding describes
+// how the parameter may leak to the function's outputs.  This is currently the
+// "level" of the leak where level is 0 or larger (negative level means stored into
+// something whose address is returned -- but that implies stored into the heap,
+// hence EscHeap, which means that the details are not currently relevant. )
+const (
+	bitsPerOutputInTag = 3                                         // For each output, the number of bits for a tag
+	bitsMaskForTag     = uint16(1<<bitsPerOutputInTag) - 1         // The bit mask to extract a single tag.
+	outputsPerTag      = (16 - EscReturnBits) / bitsPerOutputInTag // The number of outputs that can be tagged.
+	maxEncodedLevel    = int(bitsMaskForTag - 1)                   // The largest level that can be stored in a tag.
+)
+
+type EscState struct {
+	// Fake node that all
+	//   - return values and output variables
+	//   - parameters on imported functions not marked 'safe'
+	//   - assignments to global variables
+	// flow to.
+	theSink Node
+
+	dsts      *NodeList // all dst nodes
+	loopdepth int32     // 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.
+	opts      []*Node   // nodes with .Opt initialized
+	walkgen   uint32
+}
+
+// funcSym returns fn.Func.Nname.Sym if no nils are encountered along the way.
+func funcSym(fn *Node) *Sym {
+	if fn == nil || fn.Func.Nname == nil {
+		return nil
+	}
+	return fn.Func.Nname.Sym
+}
+
+// curfnSym returns n.Curfn.Nname.Sym if no nils are encountered along the way.
+func (e *EscState) curfnSym(n *Node) *Sym {
+	nE := e.nodeEscState(n)
+	return funcSym(nE.Curfn)
+}
+
+func escAnalyze(all *NodeList, recursive bool) {
+	var es EscState
+	e := &es
+	e.theSink.Op = ONAME
+	e.theSink.Orig = &e.theSink
+	e.theSink.Class = PEXTERN
+	e.theSink.Sym = Lookup(".sink")
+	e.nodeEscState(&e.theSink).Escloopdepth = -1
+	e.recursive = recursive
+
+	for l := all; l != nil; l = l.Next {
+		if l.N.Op == ODCLFUNC {
+			l.N.Esc = EscFuncPlanned
+		}
+	}
+
+	// flow-analyze functions
+	for l := all; l != nil; l = l.Next {
+		if l.N.Op == ODCLFUNC {
+			escfunc(e, l.N)
+		}
+	}
+
+	// print("escapes: %d e->dsts, %d edges\n", e->dstcount, e->edgecount);
+
+	// visit the upstream of each dst, mark address nodes with
+	// addrescapes, mark parameters unsafe
+	for l := e.dsts; l != nil; l = l.Next {
+		escflood(e, l.N)
+	}
+
+	// for all top level functions, tag the typenodes corresponding to the param nodes
+	for l := all; l != nil; l = l.Next {
+		if l.N.Op == ODCLFUNC {
+			esctag(e, l.N)
+		}
+	}
+
+	if Debug['m'] != 0 {
+		for l := e.noesc; l != nil; l = l.Next {
+			if l.N.Esc == EscNone {
+				Warnl(int(l.N.Lineno), "%v %v does not escape", e.curfnSym(l.N), Nconv(l.N, obj.FmtShort))
+			}
+		}
+	}
+	for _, x := range e.opts {
+		x.SetOpt(nil)
+	}
+}
+
+func escfunc(e *EscState, func_ *Node) {
+	//	print("escfunc %N %s\n", func->nname, e->recursive?"(recursive)":"");
+	if func_.Esc != 1 {
+		Fatal("repeat escfunc %v", func_.Func.Nname)
+	}
+	func_.Esc = EscFuncStarted
+
+	saveld := e.loopdepth
+	e.loopdepth = 1
+	savefn := Curfn
+	Curfn = func_
+
+	for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
+		if ll.N.Op != ONAME {
+			continue
+		}
+		llNE := e.nodeEscState(ll.N)
+		switch ll.N.Class {
+		// out params are in a loopdepth between the sink and all local variables
+		case PPARAMOUT:
+			llNE.Escloopdepth = 0
+
+		case PPARAM:
+			llNE.Escloopdepth = 1
+			if ll.N.Type != nil && !haspointers(ll.N.Type) {
+				break
+			}
+			if Curfn.Nbody == nil && !Curfn.Noescape {
+				ll.N.Esc = EscHeap
+			} else {
+				ll.N.Esc = EscNone // prime for escflood later
+			}
+			e.noesc = list(e.noesc, ll.N)
+		}
+	}
+
+	// in a mutually recursive group we lose track of the return values
+	if e.recursive {
+		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)
+			}
+		}
+	}
+
+	escloopdepthlist(e, Curfn.Nbody)
+	esclist(e, Curfn.Nbody, Curfn)
+	Curfn = savefn
+	e.loopdepth = saveld
+}
+
+// Mark labels that have no backjumps to them as not increasing e->loopdepth.
+// Walk hasn't generated (goto|label)->left->sym->label yet, so we'll cheat
+// and set it to one of the following two.  Then in esc we'll clear it again.
+var looping Label
+
+var nonlooping Label
+
+func escloopdepthlist(e *EscState, l *NodeList) {
+	for ; l != nil; l = l.Next {
+		escloopdepth(e, l.N)
+	}
+}
+
+func escloopdepth(e *EscState, n *Node) {
+	if n == nil {
+		return
+	}
+
+	escloopdepthlist(e, n.Ninit)
+
+	switch n.Op {
+	case OLABEL:
+		if n.Left == nil || n.Left.Sym == nil {
+			Fatal("esc:label without label: %v", Nconv(n, obj.FmtSign))
+		}
+
+		// Walk will complain about this label being already defined, but that's not until
+		// after escape analysis. in the future, maybe pull label & goto analysis out of walk and put before esc
+		// if(n->left->sym->label != nil)
+		//	fatal("escape analysis messed up analyzing label: %+N", n);
+		n.Left.Sym.Label = &nonlooping
+
+	case OGOTO:
+		if n.Left == nil || n.Left.Sym == nil {
+			Fatal("esc:goto without label: %v", Nconv(n, obj.FmtSign))
+		}
+
+		// If we come past one that's uninitialized, this must be a (harmless) forward jump
+		// but if it's set to nonlooping the label must have preceded this goto.
+		if n.Left.Sym.Label == &nonlooping {
+			n.Left.Sym.Label = &looping
+		}
+	}
+
+	escloopdepth(e, n.Left)
+	escloopdepth(e, n.Right)
+	escloopdepthlist(e, n.List)
+	escloopdepthlist(e, n.Nbody)
+	escloopdepthlist(e, n.Rlist)
+}
+
+func esclist(e *EscState, l *NodeList, up *Node) {
+	for ; l != nil; l = l.Next {
+		esc(e, l.N, up)
+	}
+}
+
+func esc(e *EscState, n *Node, up *Node) {
+	if n == nil {
+		return
+	}
+
+	lno := int(setlineno(n))
+
+	// ninit logically runs at a different loopdepth than the rest of the for loop.
+	esclist(e, n.Ninit, n)
+
+	if n.Op == OFOR || n.Op == ORANGE {
+		e.loopdepth++
+	}
+
+	// type switch variables have no ODCL.
+	// process type switch as declaration.
+	// must happen before processing of switch body,
+	// so before recursion.
+	if n.Op == OSWITCH && n.Left != nil && n.Left.Op == OTYPESW {
+		for ll := n.List; ll != nil; ll = ll.Next { // cases
+
+			// ll.N.Rlist is the variable per case
+			if ll.N.Rlist != nil {
+				e.nodeEscState(ll.N.Rlist.N).Escloopdepth = e.loopdepth
+			}
+		}
+	}
+
+	// Big stuff escapes unconditionally
+	// "Big" conditions that were scattered around in walk have been gathered here
+	if n.Esc != EscHeap && n.Type != nil && (n.Type.Width > MaxStackVarSize ||
+		n.Op == ONEW && n.Type.Type.Width >= 1<<16 ||
+		n.Op == OMAKESLICE && !isSmallMakeSlice(n)) {
+		if Debug['m'] > 1 {
+			Warnl(int(n.Lineno), "%v is too large for stack", n)
+		}
+		n.Esc = EscHeap
+		addrescapes(n)
+		escassign(e, &e.theSink, n)
+	}
+
+	esc(e, n.Left, n)
+	esc(e, n.Right, n)
+	esclist(e, n.Nbody, n)
+	esclist(e, n.List, n)
+	esclist(e, n.Rlist, n)
+
+	if n.Op == OFOR || n.Op == ORANGE {
+		e.loopdepth--
+	}
+
+	if Debug['m'] > 1 {
+		fmt.Printf("%v:[%d] %v esc: %v\n", Ctxt.Line(int(lineno)), e.loopdepth, funcSym(Curfn), n)
+	}
+
+	switch n.Op {
+	// Record loop depth at declaration.
+	case ODCL:
+		if n.Left != nil {
+			e.nodeEscState(n.Left).Escloopdepth = e.loopdepth
+		}
+
+	case OLABEL:
+		if n.Left.Sym.Label == &nonlooping {
+			if Debug['m'] > 1 {
+				fmt.Printf("%v:%v non-looping label\n", Ctxt.Line(int(lineno)), n)
+			}
+		} else if n.Left.Sym.Label == &looping {
+			if Debug['m'] > 1 {
+				fmt.Printf("%v: %v looping label\n", Ctxt.Line(int(lineno)), n)
+			}
+			e.loopdepth++
+		}
+
+		// See case OLABEL in escloopdepth above
+		// else if(n->left->sym->label == nil)
+		//	fatal("escape analysis missed or messed up a label: %+N", n);
+
+		n.Left.Sym.Label = nil
+
+		// Everything but fixed array is a dereference.
+	case ORANGE:
+		if n.List != nil && n.List.Next != nil {
+			if Isfixedarray(n.Type) {
+				escassign(e, n.List.Next.N, n.Right)
+			} else {
+				escassignDereference(e, n.List.Next.N, n.Right)
+			}
+		}
+
+	case OSWITCH:
+		if n.Left != nil && n.Left.Op == OTYPESW {
+			for ll := n.List; ll != nil; ll = ll.Next {
+				// cases
+				// n.Left.Right is the argument of the .(type),
+				// ll.N.Rlist is the variable per case
+				if ll.N.Rlist != nil {
+					escassign(e, ll.N.Rlist.N, n.Left.Right)
+				}
+			}
+		}
+
+		// Filter out the following special case.
+	//
+	//	func (b *Buffer) Foo() {
+	//		n, m := ...
+	//		b.buf = b.buf[n:m]
+	//	}
+	//
+	// 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, OASWB:
+		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.
+			// Otherwise base ONAME value could change between the moments
+			// when we evaluate it for dst and for src.
+			//
+			// Note, this optimization does not apply to OSLICEARR,
+			// because it does introduce a new pointer into b that was not already there
+			// (pointer to b itself). After such assignment, if b contents escape,
+			// b escapes as well. If we ignore such OSLICEARR, we will conclude
+			// that b does not escape when b contents do.
+			if Debug['m'] != 0 {
+				Warnl(int(n.Lineno), "%v ignoring self-assignment to %v", e.curfnSym(n), Nconv(n.Left, obj.FmtShort))
+			}
+
+			break
+		}
+
+		escassign(e, n.Left, n.Right)
+
+	case OAS2: // x,y = a,b
+		if count(n.List) == count(n.Rlist) {
+			ll := n.List
+			lr := n.Rlist
+			for ; ll != nil; ll, lr = ll.Next, lr.Next {
+				escassign(e, ll.N, lr.N)
+			}
+		}
+
+	case OAS2RECV, // v, ok = <-ch
+		OAS2MAPR,    // v, ok = m[k]
+		OAS2DOTTYPE: // v, ok = x.(type)
+		escassign(e, n.List.N, n.Rlist.N)
+
+	case OSEND: // ch <- x
+		escassign(e, &e.theSink, n.Right)
+
+	case ODEFER:
+		if e.loopdepth == 1 { // top level
+			break
+		}
+		// 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 {
+			escassign(e, &e.theSink, ll.N)
+		}
+
+	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 := e.nodeEscState(n.Rlist.N).Escretval
+
+		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 {
+			Fatal("esc oas2func")
+		}
+
+	case ORETURN:
+		ll := n.List
+		if count(n.List) == 1 && Curfn.Type.Outtuple > 1 {
+			// OAS2FUNC in disguise
+			// esccall already done on n->list->n
+			// tie n->list->n->escretval to curfn->dcl PPARAMOUT's
+			ll = e.nodeEscState(n.List.N).Escretval
+		}
+
+		for lr := Curfn.Func.Dcl; lr != nil && ll != nil; lr = lr.Next {
+			if lr.N.Op != ONAME || lr.N.Class != PPARAMOUT {
+				continue
+			}
+			escassign(e, lr.N, ll.N)
+			ll = ll.Next
+		}
+
+		if ll != nil {
+			Fatal("esc return list")
+		}
+
+		// Argument could leak through recover.
+	case OPANIC:
+		escassign(e, &e.theSink, n.Left)
+
+	case OAPPEND:
+		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
+			}
+		} else {
+			// append(slice1, slice2...) -- slice2 itself does not escape, but contents do.
+			slice2 := n.List.Next.N
+			escassignDereference(e, &e.theSink, slice2) // lose track of assign of dereference
+			if Debug['m'] > 2 {
+				Warnl(int(n.Lineno), "%v special treatment of append(slice1, slice2...) %v", e.curfnSym(n), Nconv(n, obj.FmtShort))
+			}
+		}
+		escassignDereference(e, &e.theSink, n.List.N) // The original elements are now leaked, too
+
+	case OCOPY:
+		escassignDereference(e, &e.theSink, n.Right) // lose track of assign of dereference
+
+	case OCONV, OCONVNOP:
+		escassign(e, n, n.Left)
+
+	case OCONVIFACE:
+		e.track(n)
+		escassign(e, n, n.Left)
+
+	case OARRAYLIT:
+		if Isslice(n.Type) {
+			// Slice itself is not leaked until proven otherwise
+			e.track(n)
+		}
+
+		// Link values to array/slice
+		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 {
+			escassign(e, n, ll.N.Right)
+		}
+
+	case OPTRLIT:
+		e.track(n)
+
+		// Link OSTRUCTLIT to OPTRLIT; if OPTRLIT escapes, OSTRUCTLIT elements do too.
+		escassign(e, n, n.Left)
+
+	case OCALLPART:
+		e.track(n)
+
+		// Contents make it to memory, lose track.
+		escassign(e, &e.theSink, n.Left)
+
+	case OMAPLIT:
+		e.track(n)
+
+		// Keys and values make it to memory, lose track.
+		for ll := n.List; ll != nil; ll = ll.Next {
+			escassign(e, &e.theSink, ll.N.Left)
+			escassign(e, &e.theSink, ll.N.Right)
+		}
+
+		// Link addresses of captured variables to closure.
+	case OCLOSURE:
+		var a *Node
+		var v *Node
+		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.Name.Param.Closure
+			if !v.Name.Byval {
+				a = Nod(OADDR, a, nil)
+				a.Lineno = v.Lineno
+				e.nodeEscState(a).Escloopdepth = e.loopdepth
+				typecheck(&a, Erv)
+			}
+
+			escassign(e, n, a)
+		}
+		fallthrough
+
+	case OMAKECHAN,
+		OMAKEMAP,
+		OMAKESLICE,
+		ONEW,
+		OARRAYRUNESTR,
+		OARRAYBYTESTR,
+		OSTRARRAYRUNE,
+		OSTRARRAYBYTE,
+		ORUNESTR:
+		e.track(n)
+
+	case OADDSTR:
+		e.track(n)
+		// Arguments of OADDSTR do not escape.
+
+	case OADDR:
+		// current loop depth is an upper bound on actual loop depth
+		// of addressed value.
+		e.track(n)
+
+		// for &x, use loop depth of x if known.
+		// it should always be known, but if not, be conservative
+		// and keep the current loop depth.
+		if n.Left.Op == ONAME {
+			switch n.Left.Class {
+			case PAUTO:
+				nE := e.nodeEscState(n)
+				leftE := e.nodeEscState(n.Left)
+				if leftE.Escloopdepth != 0 {
+					nE.Escloopdepth = leftE.Escloopdepth
+				}
+
+				// PPARAM is loop depth 1 always.
+			// PPARAMOUT is loop depth 0 for writes
+			// but considered loop depth 1 for address-of,
+			// 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:
+				nE := e.nodeEscState(n)
+				nE.Escloopdepth = 1
+			}
+		}
+	}
+
+	lineno = int32(lno)
+}
+
+// Assert that expr somehow gets assigned to dst, if non nil.  for
+// dst==nil, any name node expr still must be marked as being
+// evaluated in curfn.	For expr==nil, dst must still be examined for
+// evaluations inside it (e.g *f(x) = y)
+func escassign(e *EscState, dst *Node, src *Node) {
+	if isblank(dst) || dst == nil || src == nil || src.Op == ONONAME || src.Op == OXXX {
+		return
+	}
+
+	if Debug['m'] > 1 {
+		fmt.Printf("%v:[%d] %v escassign: %v(%v)[%v] = %v(%v)[%v]\n",
+			Ctxt.Line(int(lineno)), e.loopdepth, funcSym(Curfn),
+			Nconv(dst, obj.FmtShort), Jconv(dst, obj.FmtShort), Oconv(int(dst.Op), 0),
+			Nconv(src, obj.FmtShort), Jconv(src, obj.FmtShort), Oconv(int(src.Op), 0))
+	}
+
+	setlineno(dst)
+
+	// Analyze lhs of assignment.
+	// Replace dst with e->theSink if we can't track it.
+	switch dst.Op {
+	default:
+		Dump("dst", dst)
+		Fatal("escassign: unexpected dst")
+
+	case OARRAYLIT,
+		OCLOSURE,
+		OCONV,
+		OCONVIFACE,
+		OCONVNOP,
+		OMAPLIT,
+		OSTRUCTLIT,
+		OPTRLIT,
+		OCALLPART:
+		break
+
+	case ONAME:
+		if dst.Class == PEXTERN {
+			dst = &e.theSink
+		}
+
+	case ODOT: // treat "dst.x  = src" as "dst = src"
+		escassign(e, dst.Left, src)
+
+		return
+
+	case OINDEX:
+		if Isfixedarray(dst.Left.Type) {
+			escassign(e, dst.Left, src)
+			return
+		}
+
+		dst = &e.theSink // lose track of dereference
+
+	case OIND, ODOTPTR:
+		dst = &e.theSink // lose track of dereference
+
+		// lose track of key and value
+	case OINDEXMAP:
+		escassign(e, &e.theSink, dst.Right)
+
+		dst = &e.theSink
+	}
+
+	lno := int(setlineno(src))
+	e.pdepth++
+
+	switch src.Op {
+	case OADDR, // dst = &x
+		OIND,    // dst = *x
+		ODOTPTR, // dst = (*x).f
+		ONAME,
+		OPARAM,
+		ODDDARG,
+		OPTRLIT,
+		OARRAYLIT,
+		OMAPLIT,
+		OSTRUCTLIT,
+		OMAKECHAN,
+		OMAKEMAP,
+		OMAKESLICE,
+		OARRAYRUNESTR,
+		OARRAYBYTESTR,
+		OSTRARRAYRUNE,
+		OSTRARRAYBYTE,
+		OADDSTR,
+		ONEW,
+		OCALLPART,
+		ORUNESTR,
+		OCONVIFACE:
+		escflows(e, dst, src)
+
+	case OCLOSURE:
+		// OCLOSURE is lowered to OPTRLIT,
+		// insert OADDR to account for the additional indirection.
+		a := Nod(OADDR, src, nil)
+		a.Lineno = src.Lineno
+		e.nodeEscState(a).Escloopdepth = e.nodeEscState(src).Escloopdepth
+		a.Type = Ptrto(src.Type)
+		escflows(e, dst, a)
+
+	// Flowing multiple returns to a single dst happens when
+	// analyzing "go f(g())": here g() flows to sink (issue 4529).
+	case OCALLMETH, OCALLFUNC, OCALLINTER:
+		for ll := e.nodeEscState(src).Escretval; ll != nil; ll = ll.Next {
+			escflows(e, dst, ll.N)
+		}
+
+		// A non-pointer escaping from a struct does not concern us.
+	case ODOT:
+		if src.Type != nil && !haspointers(src.Type) {
+			break
+		}
+		fallthrough
+
+		// Conversions, field access, slice all preserve the input value.
+	case OCONV,
+		OCONVNOP,
+		ODOTMETH,
+		// treat recv.meth as a value with recv in it, only happens in ODEFER and OPROC
+		// iface.method already leaks iface in esccall, no need to put in extra ODOTINTER edge here
+		ODOTTYPE,
+		ODOTTYPE2,
+		OSLICE,
+		OSLICE3,
+		OSLICEARR,
+		OSLICE3ARR,
+		OSLICESTR:
+		// Conversions, field access, slice all preserve the input value.
+		escassign(e, dst, src.Left)
+
+	case OAPPEND:
+		// Append returns first argument.
+		// Subsequent arguments are already leaked because they are operands to append.
+		escassign(e, dst, src.List.N)
+
+	case OINDEX:
+		// Index of array preserves input value.
+		if Isfixedarray(src.Left.Type) {
+			escassign(e, dst, src.Left)
+		} else {
+			escflows(e, dst, src)
+		}
+
+		// Might be pointer arithmetic, in which case
+	// the operands flow into the result.
+	// TODO(rsc): Decide what the story is here.  This is unsettling.
+	case OADD,
+		OSUB,
+		OOR,
+		OXOR,
+		OMUL,
+		ODIV,
+		OMOD,
+		OLSH,
+		ORSH,
+		OAND,
+		OANDNOT,
+		OPLUS,
+		OMINUS,
+		OCOM:
+		escassign(e, dst, src.Left)
+
+		escassign(e, dst, src.Right)
+	}
+
+	e.pdepth--
+	lineno = int32(lno)
+}
+
+// Common case for escapes is 16 bits 000000000xxxEEEE
+// where commonest cases for xxx encoding in-to-out pointer
+//  flow are 000, 001, 010, 011  and EEEE is computed Esc bits.
+// Note width of xxx depends on value of constant
+// bitsPerOutputInTag -- expect 2 or 3, so in practice the
+// tag cache array is 64 or 128 long.  Some entries will
+// never be populated.
+var tags [1 << (bitsPerOutputInTag + EscReturnBits)]string
+
+// mktag returns the string representation for an escape analysis tag.
+func mktag(mask int) *string {
+	switch mask & EscMask {
+	case EscNone, EscReturn:
+		break
+
+	default:
+		Fatal("escape mktag")
+	}
+
+	if mask < len(tags) && tags[mask] != "" {
+		return &tags[mask]
+	}
+
+	s := fmt.Sprintf("esc:0x%x", mask)
+	if mask < len(tags) {
+		tags[mask] = s
+	}
+	return &s
+}
+
+// parsetag decodes an escape analysis tag and returns the esc value.
+func parsetag(note *string) uint16 {
+	if note == nil || !strings.HasPrefix(*note, "esc:") {
+		return EscUnknown
+	}
+	em := uint16(atoi((*note)[4:]))
+	if em == 0 {
+		return EscNone
+	}
+	return em
+}
+
+// describeEscape returns a string describing the escape tag.
+// The result is either one of {EscUnknown, EscNone, EscHeap} which all have no further annotation
+// or a description of parameter flow, which takes the form of an optional "contentToHeap"
+// indicating that the content of this parameter is leaked to the heap, followed by a sequence
+// of level encodings separated by spaces, one for each parameter, where _ means no flow,
+// = means direct flow, and N asterisks (*) encodes content (obtained by indirection) flow.
+// e.g., "contentToHeap _ =" means that a parameter's content (one or more dereferences)
+// escapes to the heap, the parameter does not leak to the first output, but does leak directly
+// to the second output (and if there are more than two outputs, there is no flow to those.)
+func describeEscape(em uint16) string {
+	var s string
+	if em&EscMask == EscUnknown {
+		s = "EscUnknown"
+	}
+	if em&EscMask == EscNone {
+		s = "EscNone"
+	}
+	if em&EscMask == EscHeap {
+		s = "EscHeap"
+	}
+	if em&EscMask == EscReturn {
+		s = "EscReturn"
+	}
+	if em&EscMask == EscScope {
+		s = "EscScope"
+	}
+	if em&EscContentEscapes != 0 {
+		if s != "" {
+			s += " "
+		}
+		s += "contentToHeap"
+	}
+	for em >>= EscReturnBits; em != 0; em = em >> bitsPerOutputInTag {
+		// See encoding description above
+		if s != "" {
+			s += " "
+		}
+		switch embits := em & bitsMaskForTag; embits {
+		case 0:
+			s += "_"
+		case 1:
+			s += "="
+		default:
+			for i := uint16(0); i < embits-1; i++ {
+				s += "*"
+			}
+		}
+
+	}
+	return s
+}
+
+// escassignfromtag models the input-to-output assignment flow of one of a function
+// calls arguments, where the flow is encoded in "note".
+func escassignfromtag(e *EscState, note *string, dsts *NodeList, src *Node) uint16 {
+	em := parsetag(note)
+	if src.Op == OLITERAL {
+		return em
+	}
+
+	if Debug['m'] > 2 {
+		fmt.Printf("%v::assignfromtag:: src=%v, em=%s\n",
+			Ctxt.Line(int(lineno)), Nconv(src, obj.FmtShort), describeEscape(em))
+	}
+
+	if em == EscUnknown {
+		escassign(e, &e.theSink, src)
+		return em
+	}
+
+	if em == EscNone {
+		return em
+	}
+
+	// If content inside parameter (reached via indirection)
+	// escapes to heap, mark as such.
+	if em&EscContentEscapes != 0 {
+		escassign(e, &e.theSink, e.addDereference(src))
+	}
+
+	em0 := em
+	for em >>= EscReturnBits; em != 0 && dsts != nil; em, dsts = em>>bitsPerOutputInTag, dsts.Next {
+		// Prefer the lowest-level path to the reference (for escape purposes).
+		// Two-bit encoding (for example. 1, 3, and 4 bits are other options)
+		//  01 = 0-level
+		//  10 = 1-level, (content escapes),
+		//  11 = 2-level, (content of content escapes),
+		embits := em & bitsMaskForTag
+		if embits > 0 {
+			n := src
+			for i := uint16(0); i < embits-1; i++ {
+				n = e.addDereference(n) // encode level>0 as indirections
+			}
+			escassign(e, dsts.N, n)
+		}
+	}
+	// If there are too many outputs to fit in the tag,
+	// that is handled at the encoding end as EscHeap,
+	// so there is no need to check here.
+
+	if em != 0 && dsts == nil {
+		Fatal("corrupt esc tag %q or messed up escretval list\n", note)
+	}
+	return em0
+}
+
+func escassignDereference(e *EscState, dst *Node, src *Node) {
+	if src.Op == OLITERAL {
+		return
+	}
+	escassign(e, dst, e.addDereference(src))
+}
+
+// addDereference constructs a suitable OIND note applied to src.
+// Because this is for purposes of escape accounting, not execution,
+// some semantically dubious node combinations are (currently) possible.
+func (e *EscState) addDereference(n *Node) *Node {
+	ind := Nod(OIND, n, nil)
+	e.nodeEscState(ind).Escloopdepth = e.nodeEscState(n).Escloopdepth
+	ind.Lineno = n.Lineno
+	t := n.Type
+	if Istype(t, Tptr) {
+		// This should model our own sloppy use of OIND to encode
+		// decreasing levels of indirection; i.e., "indirecting" an array
+		// might yield the type of an element.  To be enhanced...
+		t = t.Type
+	}
+	ind.Type = t
+	return ind
+}
+
+// escNoteOutputParamFlow encodes maxEncodedLevel/.../1/0-level flow to the vargen'th parameter.
+// Levels greater than maxEncodedLevel are replaced with maxEncodedLevel.
+// If the encoding cannot describe the modified input level and output number, then EscHeap is returned.
+func escNoteOutputParamFlow(e uint16, vargen int32, level Level) uint16 {
+	// Flow+level is encoded in two bits.
+	// 00 = not flow, xx = level+1 for 0 <= level <= maxEncodedLevel
+	// 16 bits for Esc allows 6x2bits or 4x3bits or 3x4bits if additional information would be useful.
+	if level.int() <= 0 && level.guaranteedDereference() > 0 {
+		return escMax(e|EscContentEscapes, EscNone) // At least one deref, thus only content.
+	}
+	if level.int() < 0 {
+		return EscHeap
+	}
+	if level.int() > maxEncodedLevel {
+		// Cannot encode larger values than maxEncodedLevel.
+		level = levelFrom(maxEncodedLevel)
+	}
+	encoded := uint16(level.int() + 1)
+
+	shift := uint(bitsPerOutputInTag*(vargen-1) + EscReturnBits)
+	old := (e >> shift) & bitsMaskForTag
+	if old == 0 || encoded != 0 && encoded < old {
+		old = encoded
+	}
+
+	encodedFlow := old << shift
+	if (encodedFlow>>shift)&bitsMaskForTag != old {
+		// Encoding failure defaults to heap.
+		return EscHeap
+	}
+
+	return (e &^ (bitsMaskForTag << shift)) | encodedFlow
+}
+
+func initEscretval(e *EscState, n *Node, fntype *Type) {
+	i := 0
+	nE := e.nodeEscState(n)
+	nE.Escretval = nil // Suspect this is not nil for indirect calls.
+	for t := getoutargx(fntype).Type; t != nil; t = t.Down {
+		src := Nod(ONAME, nil, nil)
+		buf := fmt.Sprintf(".out%d", i)
+		i++
+		src.Sym = Lookup(buf)
+		src.Type = t.Type
+		src.Class = PAUTO
+		src.Name.Curfn = Curfn
+		e.nodeEscState(src).Escloopdepth = e.loopdepth
+		src.Used = true
+		src.Lineno = n.Lineno
+		nE.Escretval = list(nE.Escretval, src)
+	}
+}
+
+// This is a bit messier than fortunate, pulled out of esc's big
+// switch for clarity.	We either have the paramnodes, which may be
+// connected to other things through flows or we have the parameter type
+// nodes, which may be marked "noescape". Navigating the ast is slightly
+// different for methods vs plain functions and for imported vs
+// this-package
+func esccall(e *EscState, n *Node, up *Node) {
+	var fntype *Type
+	var indirect bool
+	var fn *Node
+	switch n.Op {
+	default:
+		Fatal("esccall")
+
+	case OCALLFUNC:
+		fn = n.Left
+		fntype = fn.Type
+		indirect = fn.Op != ONAME || fn.Class != PFUNC
+
+	case OCALLMETH:
+		fn = n.Left.Right.Sym.Def
+		if fn != nil {
+			fntype = fn.Type
+		} else {
+			fntype = n.Left.Type
+		}
+
+	case OCALLINTER:
+		fntype = n.Left.Type
+		indirect = true
+	}
+
+	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()).
+			ll = e.nodeEscState(a).Escretval
+		}
+	}
+
+	if indirect {
+		// We know nothing!
+		// Leak all the parameters
+		for ; ll != nil; ll = ll.Next {
+			escassign(e, &e.theSink, ll.N)
+			if Debug['m'] > 2 {
+				fmt.Printf("%v::esccall:: indirect call <- %v, untracked\n", Ctxt.Line(int(lineno)), Nconv(ll.N, obj.FmtShort))
+			}
+		}
+		// Set up bogus outputs
+		initEscretval(e, n, fntype)
+		// If there is a receiver, it also leaks to heap.
+		if n.Op != OCALLFUNC {
+			t := getthisx(fntype).Type
+			src := n.Left.Left
+			if haspointers(t.Type) {
+				escassign(e, &e.theSink, src)
+			}
+		}
+		return
+	}
+
+	nE := e.nodeEscState(n)
+	if fn != nil && fn.Op == ONAME && fn.Class == PFUNC &&
+		fn.Name.Defn != nil && fn.Name.Defn.Nbody != nil && fn.Name.Param.Ntype != nil && fn.Name.Defn.Esc < EscFuncTagged {
+		if Debug['m'] > 2 {
+			fmt.Printf("%v::esccall:: %v in recursive group\n", Ctxt.Line(int(lineno)), Nconv(n, obj.FmtShort))
+		}
+
+		// function in same mutually recursive group.  Incorporate into flow graph.
+		//		print("esc local fn: %N\n", fn->ntype);
+		if fn.Name.Defn.Esc == EscFuncUnknown || nE.Escretval != nil {
+			Fatal("graph inconsistency")
+		}
+
+		// set up out list on this call node
+		for lr := fn.Name.Param.Ntype.Rlist; lr != nil; lr = lr.Next {
+			nE.Escretval = list(nE.Escretval, lr.N.Left) // type.rlist ->  dclfield -> ONAME (PPARAMOUT)
+		}
+
+		// Receiver.
+		if n.Op != OCALLFUNC {
+			escassign(e, fn.Name.Param.Ntype.Left.Left, n.Left.Left)
+		}
+
+		var src *Node
+		for lr := fn.Name.Param.Ntype.List; ll != nil && lr != nil; ll, lr = ll.Next, lr.Next {
+			src = ll.N
+			if lr.N.Isddd && !n.Isddd {
+				// Introduce ODDDARG node to represent ... allocation.
+				src = Nod(ODDDARG, nil, nil)
+				src.Type = typ(TARRAY)
+				src.Type.Type = lr.N.Type.Type
+				src.Type.Bound = int64(count(ll))
+				src.Type = Ptrto(src.Type) // make pointer so it will be tracked
+				src.Lineno = n.Lineno
+				e.track(src)
+				n.Right = src
+			}
+
+			if lr.N.Left != nil {
+				escassign(e, lr.N.Left, src)
+			}
+			if src != ll.N {
+				break
+			}
+		}
+
+		// "..." arguments are untracked
+		for ; ll != nil; ll = ll.Next {
+			if Debug['m'] > 2 {
+				fmt.Printf("%v::esccall:: ... <- %v, untracked\n", Ctxt.Line(int(lineno)), Nconv(ll.N, obj.FmtShort))
+			}
+			escassign(e, &e.theSink, ll.N)
+		}
+
+		return
+	}
+
+	// Imported or completely analyzed function.  Use the escape tags.
+	if nE.Escretval != nil {
+		Fatal("esc already decorated call %v\n", Nconv(n, obj.FmtSign))
+	}
+
+	if Debug['m'] > 2 {
+		fmt.Printf("%v::esccall:: %v not recursive\n", Ctxt.Line(int(lineno)), Nconv(n, obj.FmtShort))
+	}
+
+	// set up out list on this call node with dummy auto ONAMES in the current (calling) function.
+	initEscretval(e, n, fntype)
+
+	//	print("esc analyzed fn: %#N (%+T) returning (%+H)\n", fn, fntype, n->escretval);
+
+	// Receiver.
+	if n.Op != OCALLFUNC {
+		t := getthisx(fntype).Type
+		src := n.Left.Left
+		if haspointers(t.Type) {
+			escassignfromtag(e, t.Note, nE.Escretval, src)
+		}
+	}
+
+	for t := getinargx(fntype).Type; ll != nil; ll = ll.Next {
+		src := ll.N
+		if t.Isddd && !n.Isddd {
+			// Introduce ODDDARG node to represent ... allocation.
+			src = Nod(ODDDARG, nil, nil)
+			src.Lineno = n.Lineno
+			src.Type = typ(TARRAY)
+			src.Type.Type = t.Type.Type
+			src.Type.Bound = int64(count(ll))
+			src.Type = Ptrto(src.Type) // make pointer so it will be tracked
+			e.track(src)
+			n.Right = src
+		}
+
+		if haspointers(t.Type) {
+			if escassignfromtag(e, t.Note, nE.Escretval, src) == EscNone && up.Op != ODEFER && up.Op != OPROC {
+				a := src
+				for a.Op == OCONVNOP {
+					a = a.Left
+				}
+				switch a.Op {
+				// The callee has already been analyzed, so its arguments have esc tags.
+				// The argument is marked as not escaping at all.
+				// Record that fact so that any temporary used for
+				// synthesizing this expression can be reclaimed when
+				// the function returns.
+				// This 'noescape' is even stronger than the usual esc == EscNone.
+				// src->esc == EscNone means that src does not escape the current function.
+				// src->noescape = 1 here means that src does not escape this statement
+				// in the current function.
+				case OCALLPART,
+					OCLOSURE,
+					ODDDARG,
+					OARRAYLIT,
+					OPTRLIT,
+					OSTRUCTLIT:
+					a.Noescape = true
+				}
+			}
+		}
+
+		if src != ll.N {
+			break
+		}
+		t = t.Down
+	}
+
+	// "..." arguments are untracked
+	for ; ll != nil; ll = ll.Next {
+		escassign(e, &e.theSink, ll.N)
+		if Debug['m'] > 2 {
+			fmt.Printf("%v::esccall:: ... <- %v, untracked\n", Ctxt.Line(int(lineno)), Nconv(ll.N, obj.FmtShort))
+		}
+	}
+}
+
+// escflows records the link src->dst in dst, throwing out some quick wins,
+// and also ensuring that dst is noted as a flow destination.
+func escflows(e *EscState, dst *Node, src *Node) {
+	if dst == nil || src == nil || dst == src {
+		return
+	}
+
+	// Don't bother building a graph for scalars.
+	if src.Type != nil && !haspointers(src.Type) {
+		return
+	}
+
+	if Debug['m'] > 2 {
+		fmt.Printf("%v::flows:: %v <- %v\n", Ctxt.Line(int(lineno)), Nconv(dst, obj.FmtShort), Nconv(src, obj.FmtShort))
+	}
+
+	dstE := e.nodeEscState(dst)
+	if dstE.Escflowsrc == nil {
+		e.dsts = list(e.dsts, dst)
+		e.dstcount++
+	}
+
+	e.edgecount++
+
+	dstE.Escflowsrc = list(dstE.Escflowsrc, src)
+}
+
+// Whenever we hit a reference node, the level goes up by one, and whenever
+// we hit an OADDR, the level goes down by one. as long as we're on a level > 0
+// finding an OADDR just means we're following the upstream of a dereference,
+// so this address doesn't leak (yet).
+// If level == 0, it means the /value/ of this node can reach the root of this flood.
+// so if this node is an OADDR, it's argument should be marked as escaping iff
+// it's currfn/e->loopdepth are different from the flood's root.
+// Once an object has been moved to the heap, all of it's upstream should be considered
+// escaping to the global scope.
+func escflood(e *EscState, dst *Node) {
+	switch dst.Op {
+	case ONAME, OCLOSURE:
+		break
+
+	default:
+		return
+	}
+
+	dstE := e.nodeEscState(dst)
+	if Debug['m'] > 1 {
+		fmt.Printf("\nescflood:%d: dst %v scope:%v[%d]\n", e.walkgen, Nconv(dst, obj.FmtShort), e.curfnSym(dst), dstE.Escloopdepth)
+	}
+
+	for l := dstE.Escflowsrc; l != nil; l = l.Next {
+		e.walkgen++
+		escwalk(e, levelFrom(0), dst, l.N)
+	}
+}
+
+// funcOutputAndInput reports whether dst and src correspond to output and input parameters of the same function.
+func funcOutputAndInput(dst, src *Node) bool {
+	// Note if dst is marked as escaping, then "returned" is too weak.
+	return dst.Op == ONAME && dst.Class == PPARAMOUT &&
+		src.Op == ONAME && src.Class == PPARAM && src.Name.Curfn == dst.Name.Curfn
+}
+
+func escwalk(e *EscState, level Level, dst *Node, src *Node) {
+	if src.Op == OLITERAL {
+		return
+	}
+	srcE := e.nodeEscState(src)
+	if srcE.Walkgen == e.walkgen {
+		// Esclevels are vectors, do not compare as integers,
+		// and must use "min" of old and new to guarantee
+		// convergence.
+		level = level.min(srcE.Esclevel)
+		if level == srcE.Esclevel {
+			return
+		}
+	}
+
+	srcE.Walkgen = e.walkgen
+	srcE.Esclevel = level
+
+	if Debug['m'] > 1 {
+		fmt.Printf("escwalk: level:%d depth:%d %.*s op=%v %v(%v) scope:%v[%d]\n",
+			level, e.pdepth, e.pdepth, "\t\t\t\t\t\t\t\t\t\t", Oconv(int(src.Op), 0), Nconv(src, obj.FmtShort), Jconv(src, obj.FmtShort), e.curfnSym(src), srcE.Escloopdepth)
+	}
+
+	e.pdepth++
+
+	// Input parameter flowing to output parameter?
+	var leaks bool
+	dstE := e.nodeEscState(dst)
+	if funcOutputAndInput(dst, src) && src.Esc&EscMask < EscScope && dst.Esc != EscHeap {
+		// This case handles:
+		// 1. return in
+		// 2. return &in
+		// 3. tmp := in; return &tmp
+		// 4. return *in
+		if Debug['m'] != 0 {
+			if Debug['m'] == 1 {
+				Warnl(int(src.Lineno), "leaking param: %v to result %v level=%v", Nconv(src, obj.FmtShort), dst.Sym, level.int())
+			} else {
+				Warnl(int(src.Lineno), "leaking param: %v to result %v level=%v", Nconv(src, obj.FmtShort), dst.Sym, level)
+			}
+		}
+		if src.Esc&EscMask != EscReturn {
+			src.Esc = EscReturn | src.Esc&EscContentEscapes
+		}
+		src.Esc = escNoteOutputParamFlow(src.Esc, dst.Name.Vargen, level)
+		goto recurse
+	}
+
+	// If parameter content escapes to heap, set EscContentEscapes
+	// Note minor confusion around escape from pointer-to-struct vs escape from struct
+	if dst.Esc == EscHeap &&
+		src.Op == ONAME && src.Class == PPARAM && src.Esc&EscMask < EscScope &&
+		level.int() > 0 {
+		src.Esc = escMax(EscContentEscapes|src.Esc, EscNone)
+		if Debug['m'] != 0 {
+			Warnl(int(src.Lineno), "mark escaped content: %v", Nconv(src, obj.FmtShort))
+		}
+	}
+
+	leaks = level.int() <= 0 && level.guaranteedDereference() <= 0 && dstE.Escloopdepth < srcE.Escloopdepth
+
+	switch src.Op {
+	case ONAME:
+		if src.Class == PPARAM && (leaks || dstE.Escloopdepth < 0) && src.Esc&EscMask < EscScope {
+			if level.guaranteedDereference() > 0 {
+				src.Esc = escMax(EscContentEscapes|src.Esc, EscNone)
+				if Debug['m'] != 0 {
+					if Debug['m'] == 1 {
+						Warnl(int(src.Lineno), "leaking param content: %v", Nconv(src, obj.FmtShort))
+					} else {
+						Warnl(int(src.Lineno), "leaking param content: %v level=%v dst.eld=%v src.eld=%v dst=%v",
+							Nconv(src, obj.FmtShort), level, dstE.Escloopdepth, srcE.Escloopdepth, Nconv(dst, obj.FmtShort))
+					}
+				}
+			} else {
+				src.Esc = EscScope
+				if Debug['m'] != 0 {
+					if Debug['m'] == 1 {
+						Warnl(int(src.Lineno), "leaking param: %v", Nconv(src, obj.FmtShort))
+					} else {
+						Warnl(int(src.Lineno), "leaking param: %v level=%v dst.eld=%v src.eld=%v dst=%v",
+							Nconv(src, obj.FmtShort), level, dstE.Escloopdepth, srcE.Escloopdepth, Nconv(dst, obj.FmtShort))
+					}
+				}
+			}
+		}
+
+		// Treat a PPARAMREF closure variable as equivalent to the
+		// original variable.
+		if src.Class == PPARAMREF {
+			if leaks && Debug['m'] != 0 {
+				Warnl(int(src.Lineno), "leaking closure reference %v", Nconv(src, obj.FmtShort))
+			}
+			escwalk(e, level, dst, src.Name.Param.Closure)
+		}
+
+	case OPTRLIT, OADDR:
+		if leaks {
+			src.Esc = EscHeap
+			addrescapes(src.Left)
+			if Debug['m'] != 0 {
+				p := src
+				if p.Left.Op == OCLOSURE {
+					p = p.Left // merely to satisfy error messages in tests
+				}
+				if Debug['m'] > 1 {
+					Warnl(int(src.Lineno), "%v escapes to heap, level=%v, dst.eld=%v, src.eld=%v",
+						Nconv(p, obj.FmtShort), level, dstE.Escloopdepth, srcE.Escloopdepth)
+				} else {
+					Warnl(int(src.Lineno), "%v escapes to heap", Nconv(p, obj.FmtShort))
+				}
+			}
+		}
+
+		escwalk(e, level.dec(), dst, src.Left)
+
+	case OAPPEND:
+		escwalk(e, level, dst, src.List.N)
+
+	case OARRAYLIT:
+		if Isfixedarray(src.Type) {
+			break
+		}
+		for ll := src.List; ll != nil; ll = ll.Next {
+			escwalk(e, level.dec(), dst, ll.N.Right)
+		}
+
+		fallthrough
+
+	case ODDDARG,
+		OMAKECHAN,
+		OMAKEMAP,
+		OMAKESLICE,
+		OARRAYRUNESTR,
+		OARRAYBYTESTR,
+		OSTRARRAYRUNE,
+		OSTRARRAYBYTE,
+		OADDSTR,
+		OMAPLIT,
+		ONEW,
+		OCLOSURE,
+		OCALLPART,
+		ORUNESTR,
+		OCONVIFACE:
+		if leaks {
+			src.Esc = EscHeap
+			if Debug['m'] != 0 {
+				Warnl(int(src.Lineno), "%v escapes to heap", Nconv(src, obj.FmtShort))
+			}
+		}
+
+	case ODOT,
+		ODOTTYPE,
+		OSLICE,
+		OSLICEARR,
+		OSLICE3,
+		OSLICE3ARR,
+		OSLICESTR:
+		escwalk(e, level, dst, src.Left)
+
+	case OINDEX:
+		if Isfixedarray(src.Left.Type) {
+			escwalk(e, level, dst, src.Left)
+			break
+		}
+		fallthrough
+
+	case ODOTPTR, OINDEXMAP, OIND:
+		escwalk(e, level.inc(), dst, src.Left)
+
+	// In this case a link went directly to a call, but should really go
+	// to the dummy .outN outputs that were created for the call that
+	// themselves link to the inputs with levels adjusted.
+	// See e.g. #10466
+	// This can only happen with functions returning a single result.
+	case OCALLMETH, OCALLFUNC, OCALLINTER:
+		if srcE.Escretval != nil {
+			if Debug['m'] > 1 {
+				fmt.Printf("%v:[%d] dst %v escwalk replace src: %v with %v\n",
+					Ctxt.Line(int(lineno)), e.loopdepth,
+					Nconv(dst, obj.FmtShort), Nconv(src, obj.FmtShort), Nconv(srcE.Escretval.N, obj.FmtShort))
+			}
+			src = srcE.Escretval.N
+			srcE = e.nodeEscState(src)
+		}
+	}
+
+recurse:
+	level = level.copy()
+	for ll := srcE.Escflowsrc; ll != nil; ll = ll.Next {
+		escwalk(e, level, dst, ll.N)
+	}
+
+	e.pdepth--
+}
+
+func esctag(e *EscState, func_ *Node) {
+	func_.Esc = EscFuncTagged
+
+	// External functions are assumed unsafe,
+	// unless //go:noescape is given before the declaration.
+	if func_.Nbody == nil {
+		if func_.Noescape {
+			for t := getinargx(func_.Type).Type; t != nil; t = t.Down {
+				if haspointers(t.Type) {
+					t.Note = mktag(EscNone)
+				}
+			}
+		}
+
+		return
+	}
+
+	savefn := Curfn
+	Curfn = func_
+
+	for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
+		if ll.N.Op != ONAME {
+			continue
+		}
+
+		switch ll.N.Esc & EscMask {
+		case EscNone, // not touched by escflood
+			EscReturn:
+			if haspointers(ll.N.Type) { // don't bother tagging for scalars
+				ll.N.Name.Param.Field.Note = mktag(int(ll.N.Esc))
+			}
+
+		case EscHeap, // touched by escflood, moved to heap
+			EscScope: // touched by escflood, value leaves scope
+			break
+		}
+	}
+
+	Curfn = savefn
+}
diff --git a/src/cmd/compile/internal/gc/export.go b/src/cmd/compile/internal/gc/export.go
new file mode 100644
index 0000000..66ae881
--- /dev/null
+++ b/src/cmd/compile/internal/gc/export.go
@@ -0,0 +1,561 @@
+// 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"
+	"sort"
+	"unicode"
+	"unicode/utf8"
+)
+
+var asmlist *NodeList
+
+// Mark n's symbol as exported
+func exportsym(n *Node) {
+	if n == nil || n.Sym == nil {
+		return
+	}
+	if n.Sym.Flags&(SymExport|SymPackage) != 0 {
+		if n.Sym.Flags&SymPackage != 0 {
+			Yyerror("export/package mismatch: %v", n.Sym)
+		}
+		return
+	}
+
+	n.Sym.Flags |= SymExport
+
+	if Debug['E'] != 0 {
+		fmt.Printf("export symbol %v\n", n.Sym)
+	}
+	exportlist = list(exportlist, n)
+}
+
+func exportname(s string) bool {
+	if s[0] < utf8.RuneSelf {
+		return 'A' <= s[0] && s[0] <= 'Z'
+	}
+	r, _ := utf8.DecodeRuneInString(s)
+	return unicode.IsUpper(r)
+}
+
+func initname(s string) bool {
+	return s == "init"
+}
+
+// exportedsym reports whether a symbol will be visible
+// to files that import our package.
+func exportedsym(sym *Sym) bool {
+	// Builtins are visible everywhere.
+	if sym.Pkg == builtinpkg || sym.Origpkg == builtinpkg {
+		return true
+	}
+
+	return sym.Pkg == localpkg && exportname(sym.Name)
+}
+
+func autoexport(n *Node, ctxt uint8) {
+	if n == nil || n.Sym == nil {
+		return
+	}
+	if (ctxt != PEXTERN && ctxt != PFUNC) || dclcontext != PEXTERN {
+		return
+	}
+	if n.Name.Param != nil && n.Name.Param.Ntype != nil && n.Name.Param.Ntype.Op == OTFUNC && n.Name.Param.Ntype.Left != nil { // method
+		return
+	}
+
+	// -A is for cmd/gc/mkbuiltin script, so export everything
+	if Debug['A'] != 0 || exportname(n.Sym.Name) || initname(n.Sym.Name) {
+		exportsym(n)
+	}
+	if asmhdr != "" && n.Sym.Pkg == localpkg && n.Sym.Flags&SymAsm == 0 {
+		n.Sym.Flags |= SymAsm
+		asmlist = list(asmlist, n)
+	}
+}
+
+func dumppkg(p *Pkg) {
+	if p == nil || p == localpkg || p.Exported != 0 || p == builtinpkg {
+		return
+	}
+	p.Exported = 1
+	suffix := ""
+	if p.Direct == 0 {
+		suffix = " // indirect"
+	}
+	fmt.Fprintf(bout, "\timport %s %q%s\n", p.Name, p.Path, suffix)
+}
+
+// Look for anything we need for the inline body
+func reexportdeplist(ll *NodeList) {
+	for ; ll != nil; ll = ll.Next {
+		reexportdep(ll.N)
+	}
+}
+
+func reexportdep(n *Node) {
+	if n == nil {
+		return
+	}
+
+	//print("reexportdep %+hN\n", n);
+	switch n.Op {
+	case ONAME:
+		switch n.Class &^ PHEAP {
+		// methods will be printed along with their type
+		// nodes for T.Method expressions
+		case PFUNC:
+			if n.Left != nil && n.Left.Op == OTYPE {
+				break
+			}
+
+			// nodes for method calls.
+			if n.Type == nil || n.Type.Thistuple > 0 {
+				break
+			}
+			fallthrough
+
+		case PEXTERN:
+			if n.Sym != nil && !exportedsym(n.Sym) {
+				if Debug['E'] != 0 {
+					fmt.Printf("reexport name %v\n", n.Sym)
+				}
+				exportlist = list(exportlist, n)
+			}
+		}
+
+		// Local variables in the bodies need their type.
+	case ODCL:
+		t := n.Left.Type
+
+		if t != Types[t.Etype] && t != idealbool && t != idealstring {
+			if Isptr[t.Etype] {
+				t = t.Type
+			}
+			if t != nil && t.Sym != nil && t.Sym.Def != nil && !exportedsym(t.Sym) {
+				if Debug['E'] != 0 {
+					fmt.Printf("reexport type %v from declaration\n", t.Sym)
+				}
+				exportlist = list(exportlist, t.Sym.Def)
+			}
+		}
+
+	case OLITERAL:
+		t := n.Type
+		if t != Types[n.Type.Etype] && t != idealbool && t != idealstring {
+			if Isptr[t.Etype] {
+				t = t.Type
+			}
+			if t != nil && t.Sym != nil && t.Sym.Def != nil && !exportedsym(t.Sym) {
+				if Debug['E'] != 0 {
+					fmt.Printf("reexport literal type %v\n", t.Sym)
+				}
+				exportlist = list(exportlist, t.Sym.Def)
+			}
+		}
+		fallthrough
+
+	case OTYPE:
+		if n.Sym != nil && !exportedsym(n.Sym) {
+			if Debug['E'] != 0 {
+				fmt.Printf("reexport literal/type %v\n", n.Sym)
+			}
+			exportlist = list(exportlist, n)
+		}
+
+		// for operations that need a type when rendered, put the type on the export list.
+	case OCONV,
+		OCONVIFACE,
+		OCONVNOP,
+		ORUNESTR,
+		OARRAYBYTESTR,
+		OARRAYRUNESTR,
+		OSTRARRAYBYTE,
+		OSTRARRAYRUNE,
+		ODOTTYPE,
+		ODOTTYPE2,
+		OSTRUCTLIT,
+		OARRAYLIT,
+		OPTRLIT,
+		OMAKEMAP,
+		OMAKESLICE,
+		OMAKECHAN:
+		t := n.Type
+
+		if t.Sym == nil && t.Type != nil {
+			t = t.Type
+		}
+		if t != nil && t.Sym != nil && t.Sym.Def != nil && !exportedsym(t.Sym) {
+			if Debug['E'] != 0 {
+				fmt.Printf("reexport type for expression %v\n", t.Sym)
+			}
+			exportlist = list(exportlist, t.Sym.Def)
+		}
+	}
+
+	reexportdep(n.Left)
+	reexportdep(n.Right)
+	reexportdeplist(n.List)
+	reexportdeplist(n.Rlist)
+	reexportdeplist(n.Ninit)
+	reexportdeplist(n.Nbody)
+}
+
+func dumpexportconst(s *Sym) {
+	n := s.Def
+	typecheck(&n, Erv)
+	if n == nil || n.Op != OLITERAL {
+		Fatal("dumpexportconst: oconst nil: %v", s)
+	}
+
+	t := n.Type // may or may not be specified
+	dumpexporttype(t)
+
+	if t != nil && !isideal(t) {
+		fmt.Fprintf(bout, "\tconst %v %v = %v\n", Sconv(s, obj.FmtSharp), Tconv(t, obj.FmtSharp), Vconv(n.Val(), obj.FmtSharp))
+	} else {
+		fmt.Fprintf(bout, "\tconst %v = %v\n", Sconv(s, obj.FmtSharp), Vconv(n.Val(), obj.FmtSharp))
+	}
+}
+
+func dumpexportvar(s *Sym) {
+	n := s.Def
+	typecheck(&n, Erv|Ecall)
+	if n == nil || n.Type == nil {
+		Yyerror("variable exported but not defined: %v", s)
+		return
+	}
+
+	t := n.Type
+	dumpexporttype(t)
+
+	if t.Etype == TFUNC && n.Class == PFUNC {
+		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 {
+				typecheckinl(n)
+			}
+
+			// 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.Func.Inl, obj.FmtSharp))
+
+			reexportdeplist(n.Func.Inl)
+		} else {
+			fmt.Fprintf(bout, "\tfunc %v %v\n", Sconv(s, obj.FmtSharp), Tconv(t, obj.FmtShort|obj.FmtSharp))
+		}
+	} else {
+		fmt.Fprintf(bout, "\tvar %v %v\n", Sconv(s, obj.FmtSharp), Tconv(t, obj.FmtSharp))
+	}
+}
+
+type methodbyname []*Type
+
+func (x methodbyname) Len() int {
+	return len(x)
+}
+
+func (x methodbyname) Swap(i, j int) {
+	x[i], x[j] = x[j], x[i]
+}
+
+func (x methodbyname) Less(i, j int) bool {
+	a := x[i]
+	b := x[j]
+	return stringsCompare(a.Sym.Name, b.Sym.Name) < 0
+}
+
+func dumpexporttype(t *Type) {
+	if t == nil {
+		return
+	}
+	if t.Printed != 0 || t == Types[t.Etype] || t == bytetype || t == runetype || t == errortype {
+		return
+	}
+	t.Printed = 1
+
+	if t.Sym != nil && t.Etype != TFIELD {
+		dumppkg(t.Sym.Pkg)
+	}
+
+	dumpexporttype(t.Type)
+	dumpexporttype(t.Down)
+
+	if t.Sym == nil || t.Etype == TFIELD {
+		return
+	}
+
+	n := 0
+	for f := t.Method; f != nil; f = f.Down {
+		dumpexporttype(f)
+		n++
+	}
+
+	m := make([]*Type, n)
+	i := 0
+	for f := t.Method; f != nil; f = f.Down {
+		m[i] = f
+		i++
+	}
+	sort.Sort(methodbyname(m[:n]))
+
+	fmt.Fprintf(bout, "\ttype %v %v\n", Sconv(t.Sym, obj.FmtSharp), Tconv(t, obj.FmtSharp|obj.FmtLong))
+	var f *Type
+	for i := 0; i < n; i++ {
+		f = m[i]
+		if f.Nointerface {
+			fmt.Fprintf(bout, "\t//go:nointerface\n")
+		}
+		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.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))
+		}
+	}
+}
+
+func dumpsym(s *Sym) {
+	if s.Flags&SymExported != 0 {
+		return
+	}
+	s.Flags |= SymExported
+
+	if s.Def == nil {
+		Yyerror("unknown export symbol: %v", s)
+		return
+	}
+
+	//	print("dumpsym %O %+S\n", s->def->op, s);
+	dumppkg(s.Pkg)
+
+	switch s.Def.Op {
+	default:
+		Yyerror("unexpected export symbol: %v %v", Oconv(int(s.Def.Op), 0), s)
+
+	case OLITERAL:
+		dumpexportconst(s)
+
+	case OTYPE:
+		if s.Def.Type.Etype == TFORW {
+			Yyerror("export of incomplete type %v", s)
+		} else {
+			dumpexporttype(s.Def.Type)
+		}
+
+	case ONAME:
+		dumpexportvar(s)
+	}
+}
+
+func dumpexport() {
+	lno := lineno
+
+	if buildid != "" {
+		fmt.Fprintf(bout, "build id %q\n", buildid)
+	}
+	fmt.Fprintf(bout, "\n$$\npackage %s", localpkg.Name)
+	if safemode != 0 {
+		fmt.Fprintf(bout, " safe")
+	}
+	fmt.Fprintf(bout, "\n")
+
+	for _, p := range pkgs {
+		if p.Direct != 0 {
+			dumppkg(p)
+		}
+	}
+
+	for l := exportlist; l != nil; l = l.Next {
+		lineno = l.N.Lineno
+		dumpsym(l.N.Sym)
+	}
+
+	fmt.Fprintf(bout, "\n$$\n")
+	lineno = lno
+}
+
+/*
+ * import
+ */
+
+/*
+ * return the sym for ss, which should match lexical
+ */
+func importsym(s *Sym, op int) *Sym {
+	if s.Def != nil && int(s.Def.Op) != op {
+		pkgstr := fmt.Sprintf("during import %q", importpkg.Path)
+		redeclare(s, pkgstr)
+	}
+
+	// mark the symbol so it is not reexported
+	if s.Def == nil {
+		if exportname(s.Name) || initname(s.Name) {
+			s.Flags |= SymExport
+		} else {
+			s.Flags |= SymPackage // package scope
+		}
+	}
+
+	return s
+}
+
+/*
+ * return the type pkg.name, forward declaring if needed
+ */
+func pkgtype(s *Sym) *Type {
+	importsym(s, OTYPE)
+	if s.Def == nil || s.Def.Op != OTYPE {
+		t := typ(TFORW)
+		t.Sym = s
+		s.Def = typenod(t)
+		s.Def.Name = new(Name)
+	}
+
+	if s.Def.Type == nil {
+		Yyerror("pkgtype %v", s)
+	}
+	return s.Def.Type
+}
+
+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(path) {
+		errorexit()
+	}
+	p := mkpkg(path)
+	if p.Name == "" {
+		p.Name = s.Name
+		numImport[s.Name]++
+	} else if p.Name != s.Name {
+		Yyerror("conflicting names %s and %s for package %q", p.Name, s.Name, p.Path)
+	}
+
+	if incannedimport == 0 && myimportpath != "" && path == myimportpath {
+		Yyerror("import %q: package depends on %q (import cycle)", importpkg.Path, path)
+		errorexit()
+	}
+}
+
+func importconst(s *Sym, t *Type, n *Node) {
+	importsym(s, OLITERAL)
+	Convlit(&n, t)
+
+	if s.Def != nil { // TODO: check if already the same.
+		return
+	}
+
+	if n.Op != OLITERAL {
+		Yyerror("expression must be a constant")
+		return
+	}
+
+	if n.Sym != nil {
+		n1 := Nod(OXXX, nil, nil)
+		*n1 = *n
+		n = n1
+	}
+
+	n.Orig = newname(s)
+	n.Sym = s
+	declare(n, PEXTERN)
+
+	if Debug['E'] != 0 {
+		fmt.Printf("import const %v\n", s)
+	}
+}
+
+func importvar(s *Sym, t *Type) {
+	importsym(s, ONAME)
+	if s.Def != nil && s.Def.Op == ONAME {
+		if Eqtype(t, s.Def.Type) {
+			return
+		}
+		Yyerror("inconsistent definition for var %v during import\n\t%v (in %q)\n\t%v (in %q)", s, s.Def.Type, s.Importdef.Path, t, importpkg.Path)
+	}
+
+	n := newname(s)
+	s.Importdef = importpkg
+	n.Type = t
+	declare(n, PEXTERN)
+
+	if Debug['E'] != 0 {
+		fmt.Printf("import var %v %v\n", s, Tconv(t, obj.FmtLong))
+	}
+}
+
+func importtype(pt *Type, t *Type) {
+	// override declaration in unsafe.go for Pointer.
+	// there is no way in Go code to define unsafe.Pointer
+	// so we have to supply it.
+	if incannedimport != 0 && importpkg.Name == "unsafe" && pt.Nod.Sym.Name == "Pointer" {
+		t = Types[TUNSAFEPTR]
+	}
+
+	if pt.Etype == TFORW {
+		n := pt.Nod
+		copytype(pt.Nod, t)
+		pt.Nod = n // unzero nod
+		pt.Sym.Importdef = importpkg
+		pt.Sym.Lastlineno = int32(parserline())
+		declare(n, PEXTERN)
+		checkwidth(pt)
+	} else if !Eqtype(pt.Orig, t) {
+		Yyerror("inconsistent definition for type %v during import\n\t%v (in %q)\n\t%v (in %q)", pt.Sym, Tconv(pt, obj.FmtLong), pt.Sym.Importdef.Path, Tconv(t, obj.FmtLong), importpkg.Path)
+	}
+
+	if Debug['E'] != 0 {
+		fmt.Printf("import type %v %v\n", pt, Tconv(t, obj.FmtLong))
+	}
+}
+
+func dumpasmhdr() {
+	var b *obj.Biobuf
+
+	b, err := obj.Bopenw(asmhdr)
+	if err != nil {
+		Fatal("%v", err)
+	}
+	fmt.Fprintf(b, "// generated by %cg -asmhdr from package %s\n\n", Thearch.Thechar, localpkg.Name)
+	var n *Node
+	var t *Type
+	for l := asmlist; l != nil; l = l.Next {
+		n = l.N
+		if isblanksym(n.Sym) {
+			continue
+		}
+		switch n.Op {
+		case OLITERAL:
+			fmt.Fprintf(b, "#define const_%s %v\n", n.Sym.Name, Vconv(n.Val(), obj.FmtSharp))
+
+		case OTYPE:
+			t = n.Type
+			if t.Etype != TSTRUCT || t.Map != nil || t.Funarg != 0 {
+				break
+			}
+			fmt.Fprintf(b, "#define %s__size %d\n", t.Sym.Name, int(t.Width))
+			for t = t.Type; t != nil; t = t.Down {
+				if !isblanksym(t.Sym) {
+					fmt.Fprintf(b, "#define %s_%s %d\n", n.Sym.Name, t.Sym.Name, int(t.Width))
+				}
+			}
+		}
+	}
+
+	obj.Bterm(b)
+}
diff --git a/src/cmd/compile/internal/gc/fmt.go b/src/cmd/compile/internal/gc/fmt.go
new file mode 100644
index 0000000..b40014b
--- /dev/null
+++ b/src/cmd/compile/internal/gc/fmt.go
@@ -0,0 +1,1724 @@
+// 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 gc
+
+import (
+	"bytes"
+	"cmd/internal/obj"
+	"fmt"
+	"strconv"
+	"strings"
+	"unicode/utf8"
+)
+
+//
+// Format conversions
+//	%L int		Line numbers
+//
+//	%E int		etype values (aka 'Kind')
+//
+//	%O int		Node Opcodes
+//		Flags: "%#O": print go syntax. (automatic unless fmtmode == FDbg)
+//
+//	%J Node*	Node details
+//		Flags: "%hJ" suppresses things not relevant until walk.
+//
+//	%V Val*		Constant values
+//
+//	%S Sym*		Symbols
+//		Flags: +,- #: mode (see below)
+//			"%hS"	unqualified identifier in any mode
+//			"%hhS"  in export mode: unqualified identifier if exported, qualified if not
+//
+//	%T Type*	Types
+//		Flags: +,- #: mode (see below)
+//			'l' definition instead of name.
+//			'h' omit "func" and receiver in function types
+//			'u' (only in -/Sym mode) print type identifiers wit package name instead of prefix.
+//
+//	%N Node*	Nodes
+//		Flags: +,- #: mode (see below)
+//			'h' (only in +/debug mode) suppress recursion
+//			'l' (only in Error mode) print "foo (type Bar)"
+//
+//	%H NodeList*	NodeLists
+//		Flags: those of %N
+//			','  separate items with ',' instead of ';'
+//
+//   In mparith1.c:
+//      %B Mpint*	Big integers
+//	%F Mpflt*	Big floats
+//
+//   %S, %T and %N obey use the following flags to set the format mode:
+const (
+	FErr = iota
+	FDbg
+	FExp
+	FTypeId
+)
+
+var fmtmode int = FErr
+
+var fmtpkgpfx int // %uT stickyness
+
+//
+// E.g. for %S:	%+S %#S %-S	print an identifier properly qualified for debug/export/internal mode.
+//
+// The mode flags  +, - and # are sticky, meaning they persist through
+// recursions of %N, %T and %S, but not the h and l flags.  The u flag is
+// sticky only on %T recursions and only used in %-/Sym mode.
+
+//
+// Useful format combinations:
+//
+//	%+N   %+H	multiline recursive debug dump of node/nodelist
+//	%+hN  %+hH	non recursive debug dump
+//
+//	%#N   %#T	export format
+//	%#lT		type definition instead of name
+//	%#hT		omit"func" and receiver in function signature
+//
+//	%lN		"foo (type Bar)" for error messages
+//
+//	%-T		type identifiers
+//	%-hT		type identifiers without "func" and arg names in type signatures (methodsym)
+//	%-uT		type identifiers with package name instead of prefix (typesym, dcommontype, typehash)
+//
+
+func setfmode(flags *int) int {
+	fm := fmtmode
+	if *flags&obj.FmtSign != 0 {
+		fmtmode = FDbg
+	} else if *flags&obj.FmtSharp != 0 {
+		fmtmode = FExp
+	} else if *flags&obj.FmtLeft != 0 {
+		fmtmode = FTypeId
+	}
+
+	*flags &^= (obj.FmtSharp | obj.FmtLeft | obj.FmtSign)
+	return fm
+}
+
+// Fmt "%L": Linenumbers
+
+var goopnames = []string{
+	OADDR:     "&",
+	OADD:      "+",
+	OADDSTR:   "+",
+	OANDAND:   "&&",
+	OANDNOT:   "&^",
+	OAND:      "&",
+	OAPPEND:   "append",
+	OAS:       "=",
+	OAS2:      "=",
+	OBREAK:    "break",
+	OCALL:     "function call", // not actual syntax
+	OCAP:      "cap",
+	OCASE:     "case",
+	OCLOSE:    "close",
+	OCOMPLEX:  "complex",
+	OCOM:      "^",
+	OCONTINUE: "continue",
+	OCOPY:     "copy",
+	ODEC:      "--",
+	ODELETE:   "delete",
+	ODEFER:    "defer",
+	ODIV:      "/",
+	OEQ:       "==",
+	OFALL:     "fallthrough",
+	OFOR:      "for",
+	OGE:       ">=",
+	OGOTO:     "goto",
+	OGT:       ">",
+	OIF:       "if",
+	OIMAG:     "imag",
+	OINC:      "++",
+	OIND:      "*",
+	OLEN:      "len",
+	OLE:       "<=",
+	OLSH:      "<<",
+	OLT:       "<",
+	OMAKE:     "make",
+	OMINUS:    "-",
+	OMOD:      "%",
+	OMUL:      "*",
+	ONEW:      "new",
+	ONE:       "!=",
+	ONOT:      "!",
+	OOROR:     "||",
+	OOR:       "|",
+	OPANIC:    "panic",
+	OPLUS:     "+",
+	OPRINTN:   "println",
+	OPRINT:    "print",
+	ORANGE:    "range",
+	OREAL:     "real",
+	ORECV:     "<-",
+	ORECOVER:  "recover",
+	ORETURN:   "return",
+	ORSH:      ">>",
+	OSELECT:   "select",
+	OSEND:     "<-",
+	OSUB:      "-",
+	OSWITCH:   "switch",
+	OXOR:      "^",
+}
+
+// Fmt "%O":  Node opcodes
+func Oconv(o int, flag int) string {
+	if (flag&obj.FmtSharp != 0) || fmtmode != FDbg {
+		if o >= 0 && o < len(goopnames) && goopnames[o] != "" {
+			return goopnames[o]
+		}
+	}
+
+	if o >= 0 && o < len(opnames) && opnames[o] != "" {
+		return opnames[o]
+	}
+
+	return fmt.Sprintf("O-%d", o)
+}
+
+var classnames = []string{
+	"Pxxx",
+	"PEXTERN",
+	"PAUTO",
+	"PPARAM",
+	"PPARAMOUT",
+	"PPARAMREF",
+	"PFUNC",
+}
+
+// Fmt "%J": Node details.
+func Jconv(n *Node, flag int) string {
+	var buf bytes.Buffer
+
+	c := flag & obj.FmtShort
+
+	if c == 0 && n.Ullman != 0 {
+		fmt.Fprintf(&buf, " u(%d)", n.Ullman)
+	}
+
+	if c == 0 && n.Addable {
+		fmt.Fprintf(&buf, " a(%v)", n.Addable)
+	}
+
+	if c == 0 && n.Name != nil && n.Name.Vargen != 0 {
+		fmt.Fprintf(&buf, " g(%d)", n.Name.Vargen)
+	}
+
+	if n.Lineno != 0 {
+		fmt.Fprintf(&buf, " l(%d)", n.Lineno)
+	}
+
+	if c == 0 && n.Xoffset != BADWIDTH {
+		fmt.Fprintf(&buf, " x(%d%+d)", n.Xoffset, stkdelta[n])
+	}
+
+	if n.Class != 0 {
+		s := ""
+		if n.Class&PHEAP != 0 {
+			s = ",heap"
+		}
+		if int(n.Class&^PHEAP) < len(classnames) {
+			fmt.Fprintf(&buf, " class(%s%s)", classnames[n.Class&^PHEAP], s)
+		} else {
+			fmt.Fprintf(&buf, " class(%d?%s)", n.Class&^PHEAP, s)
+		}
+	}
+
+	if n.Colas {
+		fmt.Fprintf(&buf, " colas(%v)", n.Colas)
+	}
+
+	if n.Name != nil && n.Name.Funcdepth != 0 {
+		fmt.Fprintf(&buf, " f(%d)", n.Name.Funcdepth)
+	}
+	if n.Func != nil && n.Func.Depth != 0 {
+		fmt.Fprintf(&buf, " ff(%d)", n.Func.Depth)
+	}
+
+	switch n.Esc {
+	case EscUnknown:
+		break
+
+	case EscHeap:
+		buf.WriteString(" esc(h)")
+
+	case EscScope:
+		buf.WriteString(" esc(s)")
+
+	case EscNone:
+		buf.WriteString(" esc(no)")
+
+	case EscNever:
+		if c == 0 {
+			buf.WriteString(" esc(N)")
+		}
+
+	default:
+		fmt.Fprintf(&buf, " esc(%d)", n.Esc)
+	}
+
+	if e, ok := n.Opt().(*NodeEscState); ok && e.Escloopdepth != 0 {
+		fmt.Fprintf(&buf, " ld(%d)", e.Escloopdepth)
+	}
+
+	if c == 0 && n.Typecheck != 0 {
+		fmt.Fprintf(&buf, " tc(%d)", n.Typecheck)
+	}
+
+	if c == 0 && n.Dodata != 0 {
+		fmt.Fprintf(&buf, " dd(%d)", n.Dodata)
+	}
+
+	if n.Isddd {
+		fmt.Fprintf(&buf, " isddd(%v)", n.Isddd)
+	}
+
+	if n.Implicit {
+		fmt.Fprintf(&buf, " implicit(%v)", n.Implicit)
+	}
+
+	if n.Embedded != 0 {
+		fmt.Fprintf(&buf, " embedded(%d)", n.Embedded)
+	}
+
+	if n.Addrtaken {
+		buf.WriteString(" addrtaken")
+	}
+
+	if n.Assigned {
+		buf.WriteString(" assigned")
+	}
+
+	if c == 0 && n.Used {
+		fmt.Fprintf(&buf, " used(%v)", n.Used)
+	}
+	return buf.String()
+}
+
+// Fmt "%V": Values
+func Vconv(v Val, flag int) string {
+	switch v.Ctype() {
+	case CTINT:
+		if (flag&obj.FmtSharp != 0) || fmtmode == FExp {
+			return Bconv(v.U.(*Mpint), obj.FmtSharp)
+		}
+		return Bconv(v.U.(*Mpint), 0)
+
+	case CTRUNE:
+		x := Mpgetfix(v.U.(*Mpint))
+		if ' ' <= x && x < 0x80 && x != '\\' && x != '\'' {
+			return fmt.Sprintf("'%c'", int(x))
+		}
+		if 0 <= x && x < 1<<16 {
+			return fmt.Sprintf("'\\u%04x'", uint(int(x)))
+		}
+		if 0 <= x && x <= utf8.MaxRune {
+			return fmt.Sprintf("'\\U%08x'", uint64(x))
+		}
+		return fmt.Sprintf("('\\x00' + %v)", v.U.(*Mpint))
+
+	case CTFLT:
+		if (flag&obj.FmtSharp != 0) || fmtmode == FExp {
+			return Fconv(v.U.(*Mpflt), 0)
+		}
+		return Fconv(v.U.(*Mpflt), obj.FmtSharp)
+
+	case CTCPLX:
+		if (flag&obj.FmtSharp != 0) || fmtmode == FExp {
+			return fmt.Sprintf("(%v+%vi)", &v.U.(*Mpcplx).Real, &v.U.(*Mpcplx).Imag)
+		}
+		if mpcmpfltc(&v.U.(*Mpcplx).Real, 0) == 0 {
+			return fmt.Sprintf("%vi", Fconv(&v.U.(*Mpcplx).Imag, obj.FmtSharp))
+		}
+		if mpcmpfltc(&v.U.(*Mpcplx).Imag, 0) == 0 {
+			return Fconv(&v.U.(*Mpcplx).Real, obj.FmtSharp)
+		}
+		if mpcmpfltc(&v.U.(*Mpcplx).Imag, 0) < 0 {
+			return fmt.Sprintf("(%v%vi)", Fconv(&v.U.(*Mpcplx).Real, obj.FmtSharp), Fconv(&v.U.(*Mpcplx).Imag, obj.FmtSharp))
+		}
+		return fmt.Sprintf("(%v+%vi)", Fconv(&v.U.(*Mpcplx).Real, obj.FmtSharp), Fconv(&v.U.(*Mpcplx).Imag, obj.FmtSharp))
+
+	case CTSTR:
+		return strconv.Quote(v.U.(string))
+
+	case CTBOOL:
+		if v.U.(bool) {
+			return "true"
+		}
+		return "false"
+
+	case CTNIL:
+		return "nil"
+	}
+
+	return fmt.Sprintf("<ctype=%d>", v.Ctype)
+}
+
+/*
+s%,%,\n%g
+s%\n+%\n%g
+s%^[	]*T%%g
+s%,.*%%g
+s%.+%	[T&]		= "&",%g
+s%^	........*\]%&~%g
+s%~	%%g
+*/
+var etnames = []string{
+	TINT:        "INT",
+	TUINT:       "UINT",
+	TINT8:       "INT8",
+	TUINT8:      "UINT8",
+	TINT16:      "INT16",
+	TUINT16:     "UINT16",
+	TINT32:      "INT32",
+	TUINT32:     "UINT32",
+	TINT64:      "INT64",
+	TUINT64:     "UINT64",
+	TUINTPTR:    "UINTPTR",
+	TFLOAT32:    "FLOAT32",
+	TFLOAT64:    "FLOAT64",
+	TCOMPLEX64:  "COMPLEX64",
+	TCOMPLEX128: "COMPLEX128",
+	TBOOL:       "BOOL",
+	TPTR32:      "PTR32",
+	TPTR64:      "PTR64",
+	TFUNC:       "FUNC",
+	TARRAY:      "ARRAY",
+	TSTRUCT:     "STRUCT",
+	TCHAN:       "CHAN",
+	TMAP:        "MAP",
+	TINTER:      "INTER",
+	TFORW:       "FORW",
+	TFIELD:      "FIELD",
+	TSTRING:     "STRING",
+	TANY:        "ANY",
+}
+
+// Fmt "%E": etype
+func Econv(et int, flag int) string {
+	if et >= 0 && et < len(etnames) && etnames[et] != "" {
+		return etnames[et]
+	}
+	return fmt.Sprintf("E-%d", et)
+}
+
+// Fmt "%S": syms
+func symfmt(s *Sym, flag int) string {
+	if s.Pkg != nil && flag&obj.FmtShort == 0 {
+		switch fmtmode {
+		case FErr: // This is for the user
+			if s.Pkg == localpkg {
+				return s.Name
+			}
+
+			// If the name was used by multiple packages, display the full path,
+			if s.Pkg.Name != "" && numImport[s.Pkg.Name] > 1 {
+				return fmt.Sprintf("%q.%s", s.Pkg.Path, s.Name)
+			}
+			return fmt.Sprintf("%s.%s", s.Pkg.Name, s.Name)
+
+		case FDbg:
+			return fmt.Sprintf("%s.%s", s.Pkg.Name, s.Name)
+
+		case FTypeId:
+			if flag&obj.FmtUnsigned != 0 {
+				return fmt.Sprintf("%s.%s", s.Pkg.Name, s.Name) // dcommontype, typehash
+			}
+			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("@%q.%s", s.Pkg.Path, s.Name)
+			}
+		}
+	}
+
+	if flag&obj.FmtByte != 0 {
+		// FmtByte (hh) implies FmtShort (h)
+		// skip leading "type." in method name
+		p := s.Name
+		if i := strings.LastIndex(s.Name, "."); i >= 0 {
+			p = s.Name[i+1:]
+		}
+
+		// exportname needs to see the name without the prefix too.
+		if (fmtmode == FExp && !exportname(p)) || fmtmode == FDbg {
+			return fmt.Sprintf("@%q.%s", s.Pkg.Path, p)
+		}
+
+		return p
+	}
+
+	return s.Name
+}
+
+var basicnames = []string{
+	TINT:        "int",
+	TUINT:       "uint",
+	TINT8:       "int8",
+	TUINT8:      "uint8",
+	TINT16:      "int16",
+	TUINT16:     "uint16",
+	TINT32:      "int32",
+	TUINT32:     "uint32",
+	TINT64:      "int64",
+	TUINT64:     "uint64",
+	TUINTPTR:    "uintptr",
+	TFLOAT32:    "float32",
+	TFLOAT64:    "float64",
+	TCOMPLEX64:  "complex64",
+	TCOMPLEX128: "complex128",
+	TBOOL:       "bool",
+	TANY:        "any",
+	TSTRING:     "string",
+	TNIL:        "nil",
+	TIDEAL:      "untyped number",
+	TBLANK:      "blank",
+}
+
+func typefmt(t *Type, flag int) string {
+	if t == nil {
+		return "<T>"
+	}
+
+	if t == bytetype || t == runetype {
+		// in %-T mode collapse rune and byte with their originals.
+		if fmtmode != FTypeId {
+			return Sconv(t.Sym, obj.FmtShort)
+		}
+		t = Types[t.Etype]
+	}
+
+	if t == errortype {
+		return "error"
+	}
+
+	// Unless the 'l' flag was specified, if the type has a name, just print that name.
+	if flag&obj.FmtLong == 0 && t.Sym != nil && t.Etype != TFIELD && t != Types[t.Etype] {
+		switch fmtmode {
+		case FTypeId:
+			if flag&obj.FmtShort != 0 {
+				if t.Vargen != 0 {
+					return fmt.Sprintf("%v·%d", Sconv(t.Sym, obj.FmtShort), t.Vargen)
+				}
+				return Sconv(t.Sym, obj.FmtShort)
+			}
+
+			if flag&obj.FmtUnsigned != 0 {
+				return Sconv(t.Sym, obj.FmtUnsigned)
+			}
+			fallthrough
+
+		case FExp:
+			if t.Sym.Pkg == localpkg && t.Vargen != 0 {
+				return fmt.Sprintf("%v·%d", t.Sym, t.Vargen)
+			}
+		}
+
+		return Sconv(t.Sym, 0)
+	}
+
+	if int(t.Etype) < len(basicnames) && basicnames[t.Etype] != "" {
+		prefix := ""
+		if fmtmode == FErr && (t == idealbool || t == idealstring) {
+			prefix = "untyped "
+		}
+		return prefix + basicnames[t.Etype]
+	}
+
+	if fmtmode == FDbg {
+		fmtmode = 0
+		str := Econv(int(t.Etype), 0) + "-" + typefmt(t, flag)
+		fmtmode = FDbg
+		return str
+	}
+
+	switch t.Etype {
+	case TPTR32, TPTR64:
+		if fmtmode == FTypeId && (flag&obj.FmtShort != 0) {
+			return fmt.Sprintf("*%v", Tconv(t.Type, obj.FmtShort))
+		}
+		return fmt.Sprintf("*%v", t.Type)
+
+	case TARRAY:
+		if t.Bound >= 0 {
+			return fmt.Sprintf("[%d]%v", t.Bound, t.Type)
+		}
+		if t.Bound == -100 {
+			return fmt.Sprintf("[...]%v", t.Type)
+		}
+		return fmt.Sprintf("[]%v", t.Type)
+
+	case TCHAN:
+		switch t.Chan {
+		case Crecv:
+			return fmt.Sprintf("<-chan %v", t.Type)
+
+		case Csend:
+			return fmt.Sprintf("chan<- %v", t.Type)
+		}
+
+		if t.Type != nil && t.Type.Etype == TCHAN && t.Type.Sym == nil && t.Type.Chan == Crecv {
+			return fmt.Sprintf("chan (%v)", t.Type)
+		}
+		return fmt.Sprintf("chan %v", t.Type)
+
+	case TMAP:
+		return fmt.Sprintf("map[%v]%v", t.Down, t.Type)
+
+	case TINTER:
+		var buf bytes.Buffer
+		buf.WriteString("interface {")
+		for t1 := t.Type; t1 != nil; t1 = t1.Down {
+			buf.WriteString(" ")
+			if exportname(t1.Sym.Name) {
+				buf.WriteString(Sconv(t1.Sym, obj.FmtShort))
+			} else {
+				buf.WriteString(Sconv(t1.Sym, obj.FmtUnsigned))
+			}
+			buf.WriteString(Tconv(t1.Type, obj.FmtShort))
+			if t1.Down != nil {
+				buf.WriteString(";")
+			}
+		}
+		if t.Type != nil {
+			buf.WriteString(" ")
+		}
+		buf.WriteString("}")
+		return buf.String()
+
+	case TFUNC:
+		var buf bytes.Buffer
+		if flag&obj.FmtShort != 0 {
+			// no leading func
+		} else {
+			if t.Thistuple != 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:
+			break
+
+		case 1:
+			if fmtmode != FExp {
+				buf.WriteString(" ")
+				buf.WriteString(Tconv(getoutargx(t).Type.Type, 0)) // struct->field->field's type
+				break
+			}
+			fallthrough
+
+		default:
+			buf.WriteString(" ")
+			buf.WriteString(Tconv(getoutargx(t), 0))
+		}
+		return buf.String()
+
+	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 {
+				return fmt.Sprintf("map.bucket[%v]%v", t.Map.Down, t.Map.Type)
+			}
+
+			if t.Map.Hmap == t {
+				return fmt.Sprintf("map.hdr[%v]%v", t.Map.Down, t.Map.Type)
+			}
+
+			if t.Map.Hiter == t {
+				return fmt.Sprintf("map.iter[%v]%v", t.Map.Down, t.Map.Type)
+			}
+
+			Yyerror("unknown internal map type")
+		}
+
+		var buf bytes.Buffer
+		if t.Funarg != 0 {
+			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 {
+						buf.WriteString(", ")
+					}
+				}
+			} else {
+				for t1 := t.Type; t1 != nil; t1 = t1.Down {
+					buf.WriteString(Tconv(t1, 0))
+					if t1.Down != nil {
+						buf.WriteString(", ")
+					}
+				}
+			}
+			buf.WriteString(")")
+		} else {
+			buf.WriteString("struct {")
+			for t1 := t.Type; t1 != nil; t1 = t1.Down {
+				buf.WriteString(" ")
+				buf.WriteString(Tconv(t1, obj.FmtLong))
+				if t1.Down != nil {
+					buf.WriteString(";")
+				}
+			}
+			if t.Type != nil {
+				buf.WriteString(" ")
+			}
+			buf.WriteString("}")
+		}
+		return buf.String()
+
+	case TFIELD:
+		var name string
+		if flag&obj.FmtShort == 0 {
+			s := t.Sym
+
+			// Take the name from the original, lest we substituted it with ~r%d or ~b%d.
+			// ~r%d is a (formerly) unnamed result.
+			if (fmtmode == FErr || fmtmode == FExp) && t.Nname != nil {
+				if t.Nname.Orig != nil {
+					s = t.Nname.Orig.Sym
+					if s != nil && s.Name[0] == '~' {
+						if s.Name[1] == 'r' { // originally an unnamed result
+							s = nil
+						} else if s.Name[1] == 'b' { // originally the blank identifier _
+							s = Lookup("_")
+						}
+					}
+				} else {
+					s = nil
+				}
+			}
+
+			if s != nil && t.Embedded == 0 {
+				if t.Funarg != 0 {
+					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 {
+					name = Sconv(s, 0)
+				}
+			} else if fmtmode == FExp {
+				// TODO(rsc) this breaks on the eliding of unused arguments in the backend
+				// when this is fixed, the special case in dcl.c checkarglist can go.
+				//if(t->funarg)
+				//	fmtstrcpy(fp, "_ ");
+				//else
+				if t.Embedded != 0 && s.Pkg != nil && len(s.Pkg.Path) > 0 {
+					name = fmt.Sprintf("@%q.?", s.Pkg.Path)
+				} else {
+					name = "?"
+				}
+			}
+		}
+
+		var typ string
+		if t.Isddd {
+			typ = "..." + Tconv(t.Type.Type, 0)
+		} else {
+			typ = Tconv(t.Type, 0)
+		}
+
+		str := typ
+		if name != "" {
+			str = name + " " + typ
+		}
+		if flag&obj.FmtShort == 0 && t.Note != nil {
+			str += " " + strconv.Quote(*t.Note)
+		}
+		return str
+
+	case TFORW:
+		if t.Sym != nil {
+			return fmt.Sprintf("undefined %v", t.Sym)
+		}
+		return "undefined"
+
+	case TUNSAFEPTR:
+		if fmtmode == FExp {
+			return "@\"unsafe\".Pointer"
+		}
+		return "unsafe.Pointer"
+	}
+
+	if fmtmode == FExp {
+		Fatal("missing %v case during export", Econv(int(t.Etype), 0))
+	}
+
+	// Don't know how to handle - fall back to detailed prints.
+	return fmt.Sprintf("%v <%v> %v", Econv(int(t.Etype), 0), t.Sym, t.Type)
+}
+
+// Statements which may be rendered with a simplestmt as init.
+func stmtwithinit(op int) bool {
+	switch op {
+	case OIF, OFOR, OSWITCH:
+		return true
+	}
+
+	return false
+}
+
+func stmtfmt(n *Node) string {
+	var f string
+
+	// some statements allow for an init, but at most one,
+	// but we may have an arbitrary number added, eg by typecheck
+	// and inlining.  If it doesn't fit the syntax, emit an enclosing
+	// block starting with the init statements.
+
+	// if we can just say "for" n->ninit; ... then do so
+	simpleinit := n.Ninit != nil && n.Ninit.Next == nil && n.Ninit.N.Ninit == nil && stmtwithinit(int(n.Op))
+
+	// otherwise, print the inits as separate statements
+	complexinit := n.Ninit != nil && !simpleinit && (fmtmode != FErr)
+
+	// but if it was for if/for/switch, put in an extra surrounding block to limit the scope
+	extrablock := complexinit && stmtwithinit(int(n.Op))
+
+	if extrablock {
+		f += "{"
+	}
+
+	if complexinit {
+		f += fmt.Sprintf(" %v; ", n.Ninit)
+	}
+
+	switch n.Op {
+	case ODCL:
+		if fmtmode == FExp {
+			switch n.Left.Class &^ PHEAP {
+			case PPARAM, PPARAMOUT, PAUTO:
+				f += fmt.Sprintf("var %v %v", n.Left, n.Left.Type)
+				goto ret
+			}
+		}
+
+		f += fmt.Sprintf("var %v %v", n.Left.Sym, n.Left.Type)
+
+	case ODCLFIELD:
+		if n.Left != nil {
+			f += fmt.Sprintf("%v %v", n.Left, n.Right)
+		} else {
+			f += Nconv(n.Right, 0)
+		}
+
+		// Don't export "v = <N>" initializing statements, hope they're always
+	// preceded by the DCL which will be re-parsed and typecheck to reproduce
+	// the "v = <N>" again.
+	case OAS, OASWB:
+		if fmtmode == FExp && n.Right == nil {
+			break
+		}
+
+		if n.Colas && !complexinit {
+			f += fmt.Sprintf("%v := %v", n.Left, n.Right)
+		} else {
+			f += fmt.Sprintf("%v = %v", n.Left, n.Right)
+		}
+
+	case OASOP:
+		if n.Implicit {
+			if n.Etype == OADD {
+				f += fmt.Sprintf("%v++", n.Left)
+			} else {
+				f += fmt.Sprintf("%v--", n.Left)
+			}
+			break
+		}
+
+		f += fmt.Sprintf("%v %v= %v", n.Left, Oconv(int(n.Etype), obj.FmtSharp), n.Right)
+
+	case OAS2:
+		if n.Colas && !complexinit {
+			f += fmt.Sprintf("%v := %v", Hconv(n.List, obj.FmtComma), Hconv(n.Rlist, obj.FmtComma))
+			break
+		}
+		fallthrough
+
+	case OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:
+		f += fmt.Sprintf("%v = %v", Hconv(n.List, obj.FmtComma), Hconv(n.Rlist, obj.FmtComma))
+
+	case ORETURN:
+		f += fmt.Sprintf("return %v", Hconv(n.List, obj.FmtComma))
+
+	case ORETJMP:
+		f += fmt.Sprintf("retjmp %v", n.Sym)
+
+	case OPROC:
+		f += fmt.Sprintf("go %v", n.Left)
+
+	case ODEFER:
+		f += fmt.Sprintf("defer %v", n.Left)
+
+	case OIF:
+		if simpleinit {
+			f += fmt.Sprintf("if %v; %v { %v }", n.Ninit.N, n.Left, n.Nbody)
+		} else {
+			f += fmt.Sprintf("if %v { %v }", n.Left, n.Nbody)
+		}
+		if n.Rlist != nil {
+			f += fmt.Sprintf(" else { %v }", n.Rlist)
+		}
+
+	case OFOR:
+		if fmtmode == FErr { // TODO maybe only if FmtShort, same below
+			f += "for loop"
+			break
+		}
+
+		f += "for"
+		if simpleinit {
+			f += fmt.Sprintf(" %v;", n.Ninit.N)
+		} else if n.Right != nil {
+			f += " ;"
+		}
+
+		if n.Left != nil {
+			f += fmt.Sprintf(" %v", n.Left)
+		}
+
+		if n.Right != nil {
+			f += fmt.Sprintf("; %v", n.Right)
+		} else if simpleinit {
+			f += ";"
+		}
+
+		f += fmt.Sprintf(" { %v }", n.Nbody)
+
+	case ORANGE:
+		if fmtmode == FErr {
+			f += "for loop"
+			break
+		}
+
+		if n.List == nil {
+			f += fmt.Sprintf("for range %v { %v }", n.Right, n.Nbody)
+			break
+		}
+
+		f += fmt.Sprintf("for %v = range %v { %v }", Hconv(n.List, obj.FmtComma), n.Right, n.Nbody)
+
+	case OSELECT, OSWITCH:
+		if fmtmode == FErr {
+			f += fmt.Sprintf("%v statement", Oconv(int(n.Op), 0))
+			break
+		}
+
+		f += Oconv(int(n.Op), obj.FmtSharp)
+		if simpleinit {
+			f += fmt.Sprintf(" %v;", n.Ninit.N)
+		}
+		if n.Left != nil {
+			f += Nconv(n.Left, 0)
+		}
+
+		f += fmt.Sprintf(" { %v }", n.List)
+
+	case OCASE, OXCASE:
+		if n.List != nil {
+			f += fmt.Sprintf("case %v: %v", Hconv(n.List, obj.FmtComma), n.Nbody)
+		} else {
+			f += fmt.Sprintf("default: %v", n.Nbody)
+		}
+
+	case OBREAK,
+		OCONTINUE,
+		OGOTO,
+		OFALL,
+		OXFALL:
+		if n.Left != nil {
+			f += fmt.Sprintf("%v %v", Oconv(int(n.Op), obj.FmtSharp), n.Left)
+		} else {
+			f += Oconv(int(n.Op), obj.FmtSharp)
+		}
+
+	case OEMPTY:
+		break
+
+	case OLABEL:
+		f += fmt.Sprintf("%v: ", n.Left)
+	}
+
+ret:
+	if extrablock {
+		f += "}"
+	}
+
+	return f
+}
+
+var opprec = []int{
+	OAPPEND:       8,
+	OARRAYBYTESTR: 8,
+	OARRAYLIT:     8,
+	OARRAYRUNESTR: 8,
+	OCALLFUNC:     8,
+	OCALLINTER:    8,
+	OCALLMETH:     8,
+	OCALL:         8,
+	OCAP:          8,
+	OCLOSE:        8,
+	OCONVIFACE:    8,
+	OCONVNOP:      8,
+	OCONV:         8,
+	OCOPY:         8,
+	ODELETE:       8,
+	OGETG:         8,
+	OLEN:          8,
+	OLITERAL:      8,
+	OMAKESLICE:    8,
+	OMAKE:         8,
+	OMAPLIT:       8,
+	ONAME:         8,
+	ONEW:          8,
+	ONONAME:       8,
+	OPACK:         8,
+	OPANIC:        8,
+	OPAREN:        8,
+	OPRINTN:       8,
+	OPRINT:        8,
+	ORUNESTR:      8,
+	OSTRARRAYBYTE: 8,
+	OSTRARRAYRUNE: 8,
+	OSTRUCTLIT:    8,
+	OTARRAY:       8,
+	OTCHAN:        8,
+	OTFUNC:        8,
+	OTINTER:       8,
+	OTMAP:         8,
+	OTSTRUCT:      8,
+	OINDEXMAP:     8,
+	OINDEX:        8,
+	OSLICE:        8,
+	OSLICESTR:     8,
+	OSLICEARR:     8,
+	OSLICE3:       8,
+	OSLICE3ARR:    8,
+	ODOTINTER:     8,
+	ODOTMETH:      8,
+	ODOTPTR:       8,
+	ODOTTYPE2:     8,
+	ODOTTYPE:      8,
+	ODOT:          8,
+	OXDOT:         8,
+	OCALLPART:     8,
+	OPLUS:         7,
+	ONOT:          7,
+	OCOM:          7,
+	OMINUS:        7,
+	OADDR:         7,
+	OIND:          7,
+	ORECV:         7,
+	OMUL:          6,
+	ODIV:          6,
+	OMOD:          6,
+	OLSH:          6,
+	ORSH:          6,
+	OAND:          6,
+	OANDNOT:       6,
+	OADD:          5,
+	OSUB:          5,
+	OOR:           5,
+	OXOR:          5,
+	OEQ:           4,
+	OLT:           4,
+	OLE:           4,
+	OGE:           4,
+	OGT:           4,
+	ONE:           4,
+	OCMPSTR:       4,
+	OCMPIFACE:     4,
+	OSEND:         3,
+	OANDAND:       2,
+	OOROR:         1,
+	// Statements handled by stmtfmt
+	OAS:         -1,
+	OAS2:        -1,
+	OAS2DOTTYPE: -1,
+	OAS2FUNC:    -1,
+	OAS2MAPR:    -1,
+	OAS2RECV:    -1,
+	OASOP:       -1,
+	OBREAK:      -1,
+	OCASE:       -1,
+	OCONTINUE:   -1,
+	ODCL:        -1,
+	ODCLFIELD:   -1,
+	ODEFER:      -1,
+	OEMPTY:      -1,
+	OFALL:       -1,
+	OFOR:        -1,
+	OGOTO:       -1,
+	OIF:         -1,
+	OLABEL:      -1,
+	OPROC:       -1,
+	ORANGE:      -1,
+	ORETURN:     -1,
+	OSELECT:     -1,
+	OSWITCH:     -1,
+	OXCASE:      -1,
+	OXFALL:      -1,
+	OEND:        0,
+}
+
+func exprfmt(n *Node, prec int) string {
+	for n != nil && n.Implicit && (n.Op == OIND || n.Op == OADDR) {
+		n = n.Left
+	}
+
+	if n == nil {
+		return "<N>"
+	}
+
+	nprec := opprec[n.Op]
+	if n.Op == OTYPE && n.Sym != nil {
+		nprec = 8
+	}
+
+	if prec > nprec {
+		return fmt.Sprintf("(%v)", n)
+	}
+
+	switch n.Op {
+	case OPAREN:
+		return fmt.Sprintf("(%v)", n.Left)
+
+	case ODDDARG:
+		return "... argument"
+
+	case OREGISTER:
+		return obj.Rconv(int(n.Reg))
+
+	case OLITERAL: // this is a bit of a mess
+		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 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] || (n.Type.Etype == TCHAN && n.Type.Chan == Crecv) {
+				return fmt.Sprintf("(%v)(%v)", n.Type, Vconv(n.Val(), 0))
+			} else {
+				return fmt.Sprintf("%v(%v)", n.Type, Vconv(n.Val(), 0))
+			}
+		}
+
+		return Vconv(n.Val(), 0)
+
+		// Special case: name used as local variable in export.
+	// _ becomes ~b%d internally; print as _ for export
+	case ONAME:
+		if (fmtmode == FExp || fmtmode == FErr) && n.Sym != nil && n.Sym.Name[0] == '~' && n.Sym.Name[1] == 'b' {
+			return "_"
+		}
+		if fmtmode == FExp && n.Sym != nil && !isblank(n) && n.Name.Vargen > 0 {
+			return fmt.Sprintf("%v·%d", n.Sym, n.Name.Vargen)
+		}
+
+		// Special case: explicit name of func (*T) method(...) is turned into pkg.(*T).method,
+		// 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] {
+				return fmt.Sprintf("(%v).%v", n.Left.Type, Sconv(n.Right.Sym, obj.FmtShort|obj.FmtByte))
+			} else {
+				return fmt.Sprintf("%v.%v", n.Left.Type, Sconv(n.Right.Sym, obj.FmtShort|obj.FmtByte))
+			}
+		}
+		fallthrough
+
+		//fallthrough
+	case OPACK, ONONAME:
+		return Sconv(n.Sym, 0)
+
+	case OTYPE:
+		if n.Type == nil && n.Sym != nil {
+			return Sconv(n.Sym, 0)
+		}
+		return Tconv(n.Type, 0)
+
+	case OTARRAY:
+		if n.Left != nil {
+			return fmt.Sprintf("[]%v", n.Left)
+		}
+		var f string
+		f += fmt.Sprintf("[]%v", n.Right)
+		return f // happens before typecheck
+
+	case OTMAP:
+		return fmt.Sprintf("map[%v]%v", n.Left, n.Right)
+
+	case OTCHAN:
+		switch n.Etype {
+		case Crecv:
+			return fmt.Sprintf("<-chan %v", n.Left)
+
+		case Csend:
+			return fmt.Sprintf("chan<- %v", n.Left)
+
+		default:
+			if n.Left != nil && n.Left.Op == OTCHAN && n.Left.Sym == nil && n.Left.Etype == Crecv {
+				return fmt.Sprintf("chan (%v)", n.Left)
+			} else {
+				return fmt.Sprintf("chan %v", n.Left)
+			}
+		}
+
+	case OTSTRUCT:
+		return "<struct>"
+
+	case OTINTER:
+		return "<inter>"
+
+	case OTFUNC:
+		return "<func>"
+
+	case OCLOSURE:
+		if fmtmode == FErr {
+			return "func literal"
+		}
+		if n.Nbody != nil {
+			return fmt.Sprintf("%v { %v }", n.Type, n.Nbody)
+		}
+		return fmt.Sprintf("%v { %v }", n.Type, n.Name.Param.Closure.Nbody)
+
+	case OCOMPLIT:
+		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 {
+				if ptrlit {
+					return fmt.Sprintf("&%v literal", n.Right.Type.Type)
+				} else {
+					return fmt.Sprintf("%v literal", n.Right.Type)
+				}
+			}
+
+			return "composite literal"
+		}
+
+		if fmtmode == FExp && ptrlit {
+			// typecheck has overwritten OIND by OTYPE with pointer type.
+			return fmt.Sprintf("(&%v{ %v })", n.Right.Type.Type, Hconv(n.List, obj.FmtComma))
+		}
+
+		return fmt.Sprintf("(%v{ %v })", n.Right, Hconv(n.List, obj.FmtComma))
+
+	case OPTRLIT:
+		if fmtmode == FExp && n.Left.Implicit {
+			return Nconv(n.Left, 0)
+		}
+		return fmt.Sprintf("&%v", n.Left)
+
+	case OSTRUCTLIT:
+		if fmtmode == FExp { // requires special handling of field names
+			var f string
+			if n.Implicit {
+				f += "{"
+			} else {
+				f += fmt.Sprintf("(%v{", n.Type)
+			}
+			for l := n.List; l != nil; l = l.Next {
+				f += fmt.Sprintf(" %v:%v", Sconv(l.N.Left.Sym, obj.FmtShort|obj.FmtByte), l.N.Right)
+
+				if l.Next != nil {
+					f += ","
+				} else {
+					f += " "
+				}
+			}
+
+			if !n.Implicit {
+				f += "})"
+				return f
+			}
+			f += "}"
+			return f
+		}
+		fallthrough
+
+	case OARRAYLIT, OMAPLIT:
+		if fmtmode == FErr {
+			return fmt.Sprintf("%v literal", n.Type)
+		}
+		if fmtmode == FExp && n.Implicit {
+			return fmt.Sprintf("{ %v }", Hconv(n.List, obj.FmtComma))
+		}
+		return fmt.Sprintf("(%v{ %v })", n.Type, Hconv(n.List, obj.FmtComma))
+
+	case OKEY:
+		if n.Left != nil && n.Right != nil {
+			if fmtmode == FExp && n.Left.Type != nil && n.Left.Type.Etype == TFIELD {
+				// requires special handling of field names
+				return fmt.Sprintf("%v:%v", Sconv(n.Left.Sym, obj.FmtShort|obj.FmtByte), n.Right)
+			} else {
+				return fmt.Sprintf("%v:%v", n.Left, n.Right)
+			}
+		}
+
+		if n.Left == nil && n.Right != nil {
+			return fmt.Sprintf(":%v", n.Right)
+		}
+		if n.Left != nil && n.Right == nil {
+			return fmt.Sprintf("%v:", n.Left)
+		}
+		return ":"
+
+	case OXDOT,
+		ODOT,
+		ODOTPTR,
+		ODOTINTER,
+		ODOTMETH,
+		OCALLPART:
+		var f string
+		f += exprfmt(n.Left, nprec)
+		if n.Right == nil || n.Right.Sym == nil {
+			f += ".<nil>"
+			return f
+		}
+		f += fmt.Sprintf(".%v", Sconv(n.Right.Sym, obj.FmtShort|obj.FmtByte))
+		return f
+
+	case ODOTTYPE, ODOTTYPE2:
+		var f string
+		f += exprfmt(n.Left, nprec)
+		if n.Right != nil {
+			f += fmt.Sprintf(".(%v)", n.Right)
+			return f
+		}
+		f += fmt.Sprintf(".(%v)", n.Type)
+		return f
+
+	case OINDEX,
+		OINDEXMAP,
+		OSLICE,
+		OSLICESTR,
+		OSLICEARR,
+		OSLICE3,
+		OSLICE3ARR:
+		var f string
+		f += exprfmt(n.Left, nprec)
+		f += fmt.Sprintf("[%v]", n.Right)
+		return f
+
+	case OCOPY, OCOMPLEX:
+		return fmt.Sprintf("%v(%v, %v)", Oconv(int(n.Op), obj.FmtSharp), n.Left, n.Right)
+
+	case OCONV,
+		OCONVIFACE,
+		OCONVNOP,
+		OARRAYBYTESTR,
+		OARRAYRUNESTR,
+		OSTRARRAYBYTE,
+		OSTRARRAYRUNE,
+		ORUNESTR:
+		if n.Type == nil || n.Type.Sym == nil {
+			return fmt.Sprintf("(%v)(%v)", n.Type, n.Left)
+		}
+		if n.Left != nil {
+			return fmt.Sprintf("%v(%v)", n.Type, n.Left)
+		}
+		return fmt.Sprintf("%v(%v)", n.Type, Hconv(n.List, obj.FmtComma))
+
+	case OREAL,
+		OIMAG,
+		OAPPEND,
+		OCAP,
+		OCLOSE,
+		ODELETE,
+		OLEN,
+		OMAKE,
+		ONEW,
+		OPANIC,
+		ORECOVER,
+		OPRINT,
+		OPRINTN:
+		if n.Left != nil {
+			return fmt.Sprintf("%v(%v)", Oconv(int(n.Op), obj.FmtSharp), n.Left)
+		}
+		if n.Isddd {
+			return fmt.Sprintf("%v(%v...)", Oconv(int(n.Op), obj.FmtSharp), Hconv(n.List, obj.FmtComma))
+		}
+		return fmt.Sprintf("%v(%v)", Oconv(int(n.Op), obj.FmtSharp), Hconv(n.List, obj.FmtComma))
+
+	case OCALL, OCALLFUNC, OCALLINTER, OCALLMETH, OGETG:
+		var f string
+		f += exprfmt(n.Left, nprec)
+		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:
+		if n.List != nil { // pre-typecheck
+			return fmt.Sprintf("make(%v, %v)", n.Type, Hconv(n.List, obj.FmtComma))
+		}
+		if n.Right != nil {
+			return fmt.Sprintf("make(%v, %v, %v)", n.Type, n.Left, n.Right)
+		}
+		if n.Left != nil && (n.Op == OMAKESLICE || !isideal(n.Left.Type)) {
+			return fmt.Sprintf("make(%v, %v)", n.Type, n.Left)
+		}
+		return fmt.Sprintf("make(%v)", n.Type)
+
+		// Unary
+	case OPLUS,
+		OMINUS,
+		OADDR,
+		OCOM,
+		OIND,
+		ONOT,
+		ORECV:
+		var f string
+		if n.Left.Op == n.Op {
+			f += fmt.Sprintf("%v ", Oconv(int(n.Op), obj.FmtSharp))
+		} else {
+			f += Oconv(int(n.Op), obj.FmtSharp)
+		}
+		f += exprfmt(n.Left, nprec+1)
+		return f
+
+		// Binary
+	case OADD,
+		OAND,
+		OANDAND,
+		OANDNOT,
+		ODIV,
+		OEQ,
+		OGE,
+		OGT,
+		OLE,
+		OLT,
+		OLSH,
+		OMOD,
+		OMUL,
+		ONE,
+		OOR,
+		OOROR,
+		ORSH,
+		OSEND,
+		OSUB,
+		OXOR:
+		var f string
+		f += exprfmt(n.Left, nprec)
+
+		f += fmt.Sprintf(" %v ", Oconv(int(n.Op), obj.FmtSharp))
+		f += exprfmt(n.Right, nprec+1)
+		return f
+
+	case OADDSTR:
+		var f string
+		for l := n.List; l != nil; l = l.Next {
+			if l != n.List {
+				f += " + "
+			}
+			f += exprfmt(l.N, nprec)
+		}
+
+		return f
+
+	case OCMPSTR, OCMPIFACE:
+		var f string
+		f += exprfmt(n.Left, nprec)
+		f += fmt.Sprintf(" %v ", Oconv(int(n.Etype), obj.FmtSharp))
+		f += exprfmt(n.Right, nprec+1)
+		return f
+	}
+
+	return fmt.Sprintf("<node %v>", Oconv(int(n.Op), 0))
+}
+
+func nodefmt(n *Node, flag int) string {
+	t := n.Type
+
+	// we almost always want the original, except in export mode for literals
+	// this saves the importer some work, and avoids us having to redo some
+	// special casing for package unsafe
+	if (fmtmode != FExp || n.Op != OLITERAL) && n.Orig != nil {
+		n = n.Orig
+	}
+
+	if flag&obj.FmtLong != 0 && t != nil {
+		if t.Etype == TNIL {
+			return "nil"
+		} else {
+			return fmt.Sprintf("%v (type %v)", n, t)
+		}
+	}
+
+	// TODO inlining produces expressions with ninits. we can't print these yet.
+
+	if opprec[n.Op] < 0 {
+		return stmtfmt(n)
+	}
+
+	return exprfmt(n, 0)
+}
+
+var dumpdepth int
+
+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 {
+		return ""
+	}
+
+	recur := flag&obj.FmtShort == 0
+
+	var buf bytes.Buffer
+	if recur {
+		indent(&buf)
+		if dumpdepth > 10 {
+			buf.WriteString("...")
+			return buf.String()
+		}
+
+		if n.Ninit != nil {
+			fmt.Fprintf(&buf, "%v-init%v", Oconv(int(n.Op), 0), n.Ninit)
+			indent(&buf)
+		}
+	}
+
+	switch n.Op {
+	default:
+		fmt.Fprintf(&buf, "%v%v", Oconv(int(n.Op), 0), Jconv(n, 0))
+
+	case OREGISTER, OINDREG:
+		fmt.Fprintf(&buf, "%v-%v%v", Oconv(int(n.Op), 0), obj.Rconv(int(n.Reg)), Jconv(n, 0))
+
+	case OLITERAL:
+		fmt.Fprintf(&buf, "%v-%v%v", Oconv(int(n.Op), 0), Vconv(n.Val(), 0), Jconv(n, 0))
+
+	case ONAME, ONONAME:
+		if n.Sym != nil {
+			fmt.Fprintf(&buf, "%v-%v%v", Oconv(int(n.Op), 0), n.Sym, Jconv(n, 0))
+		} else {
+			fmt.Fprintf(&buf, "%v%v", Oconv(int(n.Op), 0), Jconv(n, 0))
+		}
+		if recur && n.Type == nil && n.Name.Param.Ntype != nil {
+			indent(&buf)
+			fmt.Fprintf(&buf, "%v-ntype%v", Oconv(int(n.Op), 0), n.Name.Param.Ntype)
+		}
+
+	case OASOP:
+		fmt.Fprintf(&buf, "%v-%v%v", Oconv(int(n.Op), 0), Oconv(int(n.Etype), 0), Jconv(n, 0))
+
+	case OTYPE:
+		fmt.Fprintf(&buf, "%v %v%v type=%v", Oconv(int(n.Op), 0), n.Sym, Jconv(n, 0), n.Type)
+		if recur && n.Type == nil && n.Name.Param.Ntype != nil {
+			indent(&buf)
+			fmt.Fprintf(&buf, "%v-ntype%v", Oconv(int(n.Op), 0), n.Name.Param.Ntype)
+		}
+	}
+
+	if n.Sym != nil && n.Op != ONAME {
+		fmt.Fprintf(&buf, " %v", n.Sym)
+	}
+
+	if n.Type != nil {
+		fmt.Fprintf(&buf, " %v", n.Type)
+	}
+
+	if recur {
+		if n.Left != nil {
+			buf.WriteString(Nconv(n.Left, 0))
+		}
+		if n.Right != nil {
+			buf.WriteString(Nconv(n.Right, 0))
+		}
+		if n.List != nil {
+			indent(&buf)
+			fmt.Fprintf(&buf, "%v-list%v", Oconv(int(n.Op), 0), n.List)
+		}
+
+		if n.Rlist != nil {
+			indent(&buf)
+			fmt.Fprintf(&buf, "%v-rlist%v", Oconv(int(n.Op), 0), n.Rlist)
+		}
+
+		if n.Nbody != nil {
+			indent(&buf)
+			fmt.Fprintf(&buf, "%v-body%v", Oconv(int(n.Op), 0), n.Nbody)
+		}
+	}
+
+	return buf.String()
+}
+
+func (s *Sym) String() string {
+	return Sconv(s, 0)
+}
+
+// Fmt "%S": syms
+// Flags:  "%hS" suppresses qualifying with package
+func Sconv(s *Sym, flag int) string {
+	if flag&obj.FmtLong != 0 {
+		panic("linksymfmt")
+	}
+
+	if s == nil {
+		return "<S>"
+	}
+
+	if s.Name == "_" {
+		return "_"
+	}
+
+	sf := flag
+	sm := setfmode(&flag)
+	var r int
+	_ = r
+	str := symfmt(s, flag)
+	flag = sf
+	fmtmode = sm
+	return str
+}
+
+func (t *Type) String() string {
+	return Tconv(t, 0)
+}
+
+// Fmt "%T": types.
+// Flags: 'l' print definition, not name
+//	  'h' omit 'func' and receiver from function types, short type names
+//	  'u' package name, not prefix (FTypeId mode, sticky)
+func Tconv(t *Type, flag int) string {
+	if t == nil {
+		return "<T>"
+	}
+
+	if t.Trecur > 4 {
+		return "<...>"
+	}
+
+	t.Trecur++
+	sf := flag
+	sm := setfmode(&flag)
+
+	if fmtmode == FTypeId && (sf&obj.FmtUnsigned != 0) {
+		fmtpkgpfx++
+	}
+	if fmtpkgpfx != 0 {
+		flag |= obj.FmtUnsigned
+	}
+
+	var r int
+	_ = r
+	str := typefmt(t, flag)
+
+	if fmtmode == FTypeId && (sf&obj.FmtUnsigned != 0) {
+		fmtpkgpfx--
+	}
+
+	flag = sf
+	fmtmode = sm
+	t.Trecur--
+	return str
+}
+
+func (n *Node) String() string {
+	return Nconv(n, 0)
+}
+
+// Fmt '%N': Nodes.
+// Flags: 'l' suffix with "(type %T)" where possible
+//	  '+h' in debug mode, don't recurse, no multiline output
+func Nconv(n *Node, flag int) string {
+	if n == nil {
+		return "<N>"
+	}
+	sf := flag
+	sm := setfmode(&flag)
+
+	var r int
+	_ = r
+	var str string
+	switch fmtmode {
+	case FErr, FExp:
+		str = nodefmt(n, flag)
+
+	case FDbg:
+		dumpdepth++
+		str = nodedump(n, flag)
+		dumpdepth--
+
+	default:
+		Fatal("unhandled %%N mode")
+	}
+
+	flag = sf
+	fmtmode = sm
+	return str
+}
+
+func (l *NodeList) String() string {
+	return Hconv(l, 0)
+}
+
+// Fmt '%H': NodeList.
+// Flags: all those of %N plus ',': separate with comma's instead of semicolons.
+func Hconv(l *NodeList, flag int) string {
+	if l == nil && fmtmode == FDbg {
+		return "<nil>"
+	}
+
+	sf := flag
+	sm := setfmode(&flag)
+	var r int
+	_ = r
+	sep := "; "
+	if fmtmode == FDbg {
+		sep = "\n"
+	} else if flag&obj.FmtComma != 0 {
+		sep = ", "
+	}
+
+	var buf bytes.Buffer
+	for ; l != nil; l = l.Next {
+		buf.WriteString(Nconv(l.N, 0))
+		if l.Next != nil {
+			buf.WriteString(sep)
+		}
+	}
+
+	flag = sf
+	fmtmode = sm
+	return buf.String()
+}
+
+func dumplist(s string, l *NodeList) {
+	fmt.Printf("%s%v\n", s, Hconv(l, obj.FmtSign))
+}
+
+func Dump(s string, n *Node) {
+	fmt.Printf("%s [%p]%v\n", s, n, Nconv(n, obj.FmtSign))
+}
diff --git a/src/cmd/compile/internal/gc/gen.go b/src/cmd/compile/internal/gc/gen.go
new file mode 100644
index 0000000..764895f
--- /dev/null
+++ b/src/cmd/compile/internal/gc/gen.go
@@ -0,0 +1,1276 @@
+// 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"
+)
+
+/*
+ * portable half of code generator.
+ * mainly statements and control flow.
+ */
+var labellist *Label
+
+var lastlabel *Label
+
+func Sysfunc(name string) *Node {
+	n := newname(Pkglookup(name, Runtimepkg))
+	n.Class = PFUNC
+	return n
+}
+
+// addrescapes tags node n as having had its address taken
+// by "increasing" the "value" of n.Esc to EscHeap.
+// Storage is allocated as necessary to allow the address
+// to be taken.
+func addrescapes(n *Node) {
+	switch n.Op {
+	// probably a type error already.
+	// dump("addrescapes", n);
+	default:
+		break
+
+	case ONAME:
+		if n == nodfp {
+			break
+		}
+
+		// if this is a tmpname (PAUTO), it was tagged by tmpname as not escaping.
+		// on PPARAM it means something different.
+		if n.Class == PAUTO && n.Esc == EscNever {
+			break
+		}
+
+		switch n.Class {
+		case PPARAMREF:
+			addrescapes(n.Name.Defn)
+
+		// if func param, need separate temporary
+		// to hold heap pointer.
+		// the function type has already been checked
+		// (we're in the function body)
+		// so the param already has a valid xoffset.
+
+		// expression to refer to stack copy
+		case PPARAM, PPARAMOUT:
+			n.Name.Param.Stackparam = Nod(OPARAM, n, nil)
+
+			n.Name.Param.Stackparam.Type = n.Type
+			n.Name.Param.Stackparam.Addable = true
+			if n.Xoffset == BADWIDTH {
+				Fatal("addrescapes before param assignment")
+			}
+			n.Name.Param.Stackparam.Xoffset = n.Xoffset
+			fallthrough
+
+		case PAUTO:
+			n.Class |= PHEAP
+
+			n.Addable = false
+			n.Ullman = 2
+			n.Xoffset = 0
+
+			// create stack variable to hold pointer to heap
+			oldfn := Curfn
+
+			Curfn = n.Name.Curfn
+			n.Name.Heapaddr = temp(Ptrto(n.Type))
+			buf := fmt.Sprintf("&%v", n.Sym)
+			n.Name.Heapaddr.Sym = Lookup(buf)
+			n.Name.Heapaddr.Orig.Sym = n.Name.Heapaddr.Sym
+			n.Esc = EscHeap
+			if Debug['m'] != 0 {
+				fmt.Printf("%v: moved to heap: %v\n", n.Line(), n)
+			}
+			Curfn = oldfn
+		}
+
+	case OIND, ODOTPTR:
+		break
+
+	// ODOTPTR has already been introduced,
+	// so these are the non-pointer ODOT and OINDEX.
+	// 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, OPAREN, OCONVNOP:
+		if !Isslice(n.Left.Type) {
+			addrescapes(n.Left)
+		}
+	}
+}
+
+func clearlabels() {
+	for l := labellist; l != nil; l = l.Link {
+		l.Sym.Label = nil
+	}
+
+	labellist = nil
+	lastlabel = nil
+}
+
+func newlab(n *Node) *Label {
+	s := n.Left.Sym
+	lab := s.Label
+	if lab == nil {
+		lab = new(Label)
+		if lastlabel == nil {
+			labellist = lab
+		} else {
+			lastlabel.Link = lab
+		}
+		lastlabel = lab
+		lab.Sym = s
+		s.Label = lab
+	}
+
+	if n.Op == OLABEL {
+		if lab.Def != nil {
+			Yyerror("label %v already defined at %v", s, lab.Def.Line())
+		} else {
+			lab.Def = n
+		}
+	} else {
+		lab.Use = list(lab.Use, n)
+	}
+
+	return lab
+}
+
+func checkgoto(from *Node, to *Node) {
+	if from.Sym == to.Sym {
+		return
+	}
+
+	nf := 0
+	for fs := from.Sym; fs != nil; fs = fs.Link {
+		nf++
+	}
+	nt := 0
+	for fs := to.Sym; fs != nil; fs = fs.Link {
+		nt++
+	}
+	fs := from.Sym
+	for ; nf > nt; nf-- {
+		fs = fs.Link
+	}
+	if fs != to.Sym {
+		lno := int(lineno)
+		setlineno(from)
+
+		// decide what to complain about.
+		// prefer to complain about 'into block' over declarations,
+		// so scan backward to find most recent block or else dcl.
+		var block *Sym
+
+		var dcl *Sym
+		ts := to.Sym
+		for ; nt > nf; nt-- {
+			if ts.Pkg == nil {
+				block = ts
+			} else {
+				dcl = ts
+			}
+			ts = ts.Link
+		}
+
+		for ts != fs {
+			if ts.Pkg == nil {
+				block = ts
+			} else {
+				dcl = ts
+			}
+			ts = ts.Link
+			fs = fs.Link
+		}
+
+		if block != nil {
+			Yyerror("goto %v jumps into block starting at %v", from.Left.Sym, Ctxt.Line(int(block.Lastlineno)))
+		} else {
+			Yyerror("goto %v jumps over declaration of %v at %v", from.Left.Sym, dcl, Ctxt.Line(int(dcl.Lastlineno)))
+		}
+		lineno = int32(lno)
+	}
+}
+
+func stmtlabel(n *Node) *Label {
+	if n.Sym != nil {
+		lab := n.Sym.Label
+		if lab != nil {
+			if lab.Def != nil {
+				if lab.Def.Name.Defn == n {
+					return lab
+				}
+			}
+		}
+	}
+	return nil
+}
+
+/*
+ * compile statements
+ */
+func Genlist(l *NodeList) {
+	for ; l != nil; l = l.Next {
+		gen(l.N)
+	}
+}
+
+/*
+ * generate code to start new proc running call n.
+ */
+func cgen_proc(n *Node, proc int) {
+	switch n.Left.Op {
+	default:
+		Fatal("cgen_proc: unknown call %v", Oconv(int(n.Left.Op), 0))
+
+	case OCALLMETH:
+		cgen_callmeth(n.Left, proc)
+
+	case OCALLINTER:
+		cgen_callinter(n.Left, nil, proc)
+
+	case OCALLFUNC:
+		cgen_call(n.Left, proc)
+	}
+}
+
+/*
+ * generate declaration.
+ * have to allocate heap copy
+ * for escaped variables.
+ */
+func cgen_dcl(n *Node) {
+	if Debug['g'] != 0 {
+		Dump("\ncgen-dcl", n)
+	}
+	if n.Op != ONAME {
+		Dump("cgen_dcl", n)
+		Fatal("cgen_dcl")
+	}
+
+	if n.Class&PHEAP == 0 {
+		return
+	}
+	if compiling_runtime != 0 {
+		Yyerror("%v escapes to heap, not allowed in runtime.", n)
+	}
+	if prealloc[n] == nil {
+		prealloc[n] = callnew(n.Type)
+	}
+	Cgen_as(n.Name.Heapaddr, prealloc[n])
+}
+
+/*
+ * generate discard of value
+ */
+func cgen_discard(nr *Node) {
+	if nr == nil {
+		return
+	}
+
+	switch nr.Op {
+	case ONAME:
+		if nr.Class&PHEAP == 0 && nr.Class != PEXTERN && nr.Class != PFUNC && nr.Class != PPARAMREF {
+			gused(nr)
+		}
+
+		// unary
+	case OADD,
+		OAND,
+		ODIV,
+		OEQ,
+		OGE,
+		OGT,
+		OLE,
+		OLSH,
+		OLT,
+		OMOD,
+		OMUL,
+		ONE,
+		OOR,
+		ORSH,
+		OSUB,
+		OXOR:
+		cgen_discard(nr.Left)
+
+		cgen_discard(nr.Right)
+
+		// binary
+	case OCAP,
+		OCOM,
+		OLEN,
+		OMINUS,
+		ONOT,
+		OPLUS:
+		cgen_discard(nr.Left)
+
+	case OIND:
+		Cgen_checknil(nr.Left)
+
+		// special enough to just evaluate
+	default:
+		var tmp Node
+		Tempname(&tmp, nr.Type)
+
+		Cgen_as(&tmp, nr)
+		gused(&tmp)
+	}
+}
+
+/*
+ * clearslim generates code to zero a slim node.
+ */
+func Clearslim(n *Node) {
+	var z Node
+	z.Op = OLITERAL
+	z.Type = n.Type
+	z.Addable = true
+
+	switch Simtype[n.Type.Etype] {
+	case TCOMPLEX64, TCOMPLEX128:
+		z.SetVal(Val{new(Mpcplx)})
+		Mpmovecflt(&z.Val().U.(*Mpcplx).Real, 0.0)
+		Mpmovecflt(&z.Val().U.(*Mpcplx).Imag, 0.0)
+
+	case TFLOAT32, TFLOAT64:
+		var zero Mpflt
+		Mpmovecflt(&zero, 0.0)
+		z.SetVal(Val{&zero})
+
+	case TPTR32, TPTR64, TCHAN, TMAP:
+		z.SetVal(Val{new(NilVal)})
+
+	case TBOOL:
+		z.SetVal(Val{false})
+
+	case TINT8,
+		TINT16,
+		TINT32,
+		TINT64,
+		TUINT8,
+		TUINT16,
+		TUINT32,
+		TUINT64:
+		z.SetVal(Val{new(Mpint)})
+		Mpmovecfix(z.Val().U.(*Mpint), 0)
+
+	default:
+		Fatal("clearslim called on type %v", n.Type)
+	}
+
+	ullmancalc(&z)
+	Cgen(&z, n)
+}
+
+/*
+ * generate:
+ *	res = iface{typ, data}
+ * n->left is typ
+ * n->right is data
+ */
+func Cgen_eface(n *Node, res *Node) {
+	/*
+	 * the right node of an eface may contain function calls that uses res as an argument,
+	 * so it's important that it is done first
+	 */
+
+	tmp := temp(Types[Tptr])
+	Cgen(n.Right, tmp)
+
+	Gvardef(res)
+
+	dst := *res
+	dst.Type = Types[Tptr]
+	dst.Xoffset += int64(Widthptr)
+	Cgen(tmp, &dst)
+
+	dst.Xoffset -= int64(Widthptr)
+	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, wb bool) {
+	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.
+		p := Thearch.Ginscmp(OEQ, byteptr, &r1, Nodintconst(0), -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)
+	p := Thearch.Ginscmp(ONE, byteptr, &r1, &r2, -1)
+	Regfree(&r2) // not needed for success path; reclaimed on one failure path
+	iface.Xoffset += int64(Widthptr)
+	Cgen(&iface, &r1)
+	Regfree(&iface)
+
+	if resok == nil {
+		r1.Type = res.Type
+		cgen_wb(&r1, res, wb)
+		q := Gbranch(obj.AJMP, nil, 0)
+		Patch(p, Pc)
+		Regrealloc(&r2) // reclaim from above, for this failure path
+		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.
+		r1.Type = res.Type
+		if !isblank(res) {
+			cgen_wb(&r1, res, wb)
+		}
+		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.
+		p := Thearch.Ginscmp(OEQ, byteptr, &r1, Nodintconst(0), -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)
+	p := Thearch.Ginscmp(ONE, byteptr, &r1, &r2, -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)
+}
+
+/*
+ * gather series of offsets
+ * >=0 is direct addressed field
+ * <0 is pointer to next field (+1)
+ */
+func Dotoffset(n *Node, oary []int64, nn **Node) int {
+	var i int
+
+	switch n.Op {
+	case ODOT:
+		if n.Xoffset == BADWIDTH {
+			Dump("bad width in dotoffset", n)
+			Fatal("bad width in dotoffset")
+		}
+
+		i = Dotoffset(n.Left, oary, nn)
+		if i > 0 {
+			if oary[i-1] >= 0 {
+				oary[i-1] += n.Xoffset
+			} else {
+				oary[i-1] -= n.Xoffset
+			}
+			break
+		}
+
+		if i < 10 {
+			oary[i] = n.Xoffset
+			i++
+		}
+
+	case ODOTPTR:
+		if n.Xoffset == BADWIDTH {
+			Dump("bad width in dotoffset", n)
+			Fatal("bad width in dotoffset")
+		}
+
+		i = Dotoffset(n.Left, oary, nn)
+		if i < 10 {
+			oary[i] = -(n.Xoffset + 1)
+			i++
+		}
+
+	default:
+		*nn = n
+		return 0
+	}
+
+	if i >= 10 {
+		*nn = nil
+	}
+	return i
+}
+
+/*
+ * make a new off the books
+ */
+func Tempname(nn *Node, t *Type) {
+	if Curfn == nil {
+		Fatal("no curfn for tempname")
+	}
+
+	if t == nil {
+		Yyerror("tempname called with nil type")
+		t = Types[TINT32]
+	}
+
+	// give each tmp a different name so that there
+	// a chance to registerizer them
+	s := Lookupf("autotmp_%.4d", statuniqgen)
+	statuniqgen++
+	n := Nod(ONAME, nil, nil)
+	n.Sym = s
+	s.Def = n
+	n.Type = t
+	n.Class = PAUTO
+	n.Addable = true
+	n.Ullman = 1
+	n.Esc = EscNever
+	n.Name.Curfn = Curfn
+	Curfn.Func.Dcl = list(Curfn.Func.Dcl, n)
+
+	dowidth(t)
+	n.Xoffset = 0
+	*nn = *n
+}
+
+func temp(t *Type) *Node {
+	n := Nod(OXXX, nil, nil)
+	Tempname(n, t)
+	n.Sym.Def.Used = true
+	return n.Orig
+}
+
+func gen(n *Node) {
+	//dump("gen", n);
+
+	lno := setlineno(n)
+
+	wasregalloc := Anyregalloc()
+
+	if n == nil {
+		goto ret
+	}
+
+	if n.Ninit != nil {
+		Genlist(n.Ninit)
+	}
+
+	setlineno(n)
+
+	switch n.Op {
+	default:
+		Fatal("gen: unknown op %v", Nconv(n, obj.FmtShort|obj.FmtSign))
+
+	case OCASE,
+		OFALL,
+		OXCASE,
+		OXFALL,
+		ODCLCONST,
+		ODCLFUNC,
+		ODCLTYPE:
+		break
+
+	case OEMPTY:
+		break
+
+	case OBLOCK:
+		Genlist(n.List)
+
+	case OLABEL:
+		if isblanksym(n.Left.Sym) {
+			break
+		}
+
+		lab := newlab(n)
+
+		// if there are pending gotos, resolve them all to the current pc.
+		var p2 *obj.Prog
+		for p1 := lab.Gotopc; p1 != nil; p1 = p2 {
+			p2 = unpatch(p1)
+			Patch(p1, Pc)
+		}
+
+		lab.Gotopc = nil
+		if lab.Labelpc == nil {
+			lab.Labelpc = Pc
+		}
+
+		if n.Name.Defn != nil {
+			switch n.Name.Defn.Op {
+			// so stmtlabel can find the label
+			case OFOR, OSWITCH, OSELECT:
+				n.Name.Defn.Sym = lab.Sym
+			}
+		}
+
+		// if label is defined, emit jump to it.
+	// otherwise save list of pending gotos in lab->gotopc.
+	// the list is linked through the normal jump target field
+	// to avoid a second list.  (the jumps are actually still
+	// valid code, since they're just going to another goto
+	// to the same label.  we'll unwind it when we learn the pc
+	// of the label in the OLABEL case above.)
+	case OGOTO:
+		lab := newlab(n)
+
+		if lab.Labelpc != nil {
+			gjmp(lab.Labelpc)
+		} else {
+			lab.Gotopc = gjmp(lab.Gotopc)
+		}
+
+	case OBREAK:
+		if n.Left != nil {
+			lab := n.Left.Sym.Label
+			if lab == nil {
+				Yyerror("break label not defined: %v", n.Left.Sym)
+				break
+			}
+
+			lab.Used = 1
+			if lab.Breakpc == nil {
+				Yyerror("invalid break label %v", n.Left.Sym)
+				break
+			}
+
+			gjmp(lab.Breakpc)
+			break
+		}
+
+		if breakpc == nil {
+			Yyerror("break is not in a loop")
+			break
+		}
+
+		gjmp(breakpc)
+
+	case OCONTINUE:
+		if n.Left != nil {
+			lab := n.Left.Sym.Label
+			if lab == nil {
+				Yyerror("continue label not defined: %v", n.Left.Sym)
+				break
+			}
+
+			lab.Used = 1
+			if lab.Continpc == nil {
+				Yyerror("invalid continue label %v", n.Left.Sym)
+				break
+			}
+
+			gjmp(lab.Continpc)
+			break
+		}
+
+		if continpc == nil {
+			Yyerror("continue is not in a loop")
+			break
+		}
+
+		gjmp(continpc)
+
+	case OFOR:
+		sbreak := breakpc
+		p1 := gjmp(nil)     //		goto test
+		breakpc = gjmp(nil) // break:	goto done
+		scontin := continpc
+		continpc = Pc
+
+		// define break and continue labels
+		lab := stmtlabel(n)
+		if lab != nil {
+			lab.Breakpc = breakpc
+			lab.Continpc = continpc
+		}
+
+		gen(n.Right)                     // contin:	incr
+		Patch(p1, Pc)                    // test:
+		Bgen(n.Left, false, -1, breakpc) //		if(!test) goto break
+		Genlist(n.Nbody)                 //		body
+		gjmp(continpc)
+		Patch(breakpc, Pc) // done:
+		continpc = scontin
+		breakpc = sbreak
+		if lab != nil {
+			lab.Breakpc = nil
+			lab.Continpc = nil
+		}
+
+	case OIF:
+		p1 := gjmp(nil)                         //		goto test
+		p2 := gjmp(nil)                         // p2:		goto else
+		Patch(p1, Pc)                           // test:
+		Bgen(n.Left, false, int(-n.Likely), p2) //		if(!test) goto p2
+		Genlist(n.Nbody)                        //		then
+		p3 := gjmp(nil)                         //		goto done
+		Patch(p2, Pc)                           // else:
+		Genlist(n.Rlist)                        //		else
+		Patch(p3, Pc)                           // done:
+
+	case OSWITCH:
+		sbreak := breakpc
+		p1 := gjmp(nil)     //		goto test
+		breakpc = gjmp(nil) // break:	goto done
+
+		// define break label
+		lab := stmtlabel(n)
+		if lab != nil {
+			lab.Breakpc = breakpc
+		}
+
+		Patch(p1, Pc)      // test:
+		Genlist(n.Nbody)   //		switch(test) body
+		Patch(breakpc, Pc) // done:
+		breakpc = sbreak
+		if lab != nil {
+			lab.Breakpc = nil
+		}
+
+	case OSELECT:
+		sbreak := breakpc
+		p1 := gjmp(nil)     //		goto test
+		breakpc = gjmp(nil) // break:	goto done
+
+		// define break label
+		lab := stmtlabel(n)
+		if lab != nil {
+			lab.Breakpc = breakpc
+		}
+
+		Patch(p1, Pc)      // test:
+		Genlist(n.Nbody)   //		select() body
+		Patch(breakpc, Pc) // done:
+		breakpc = sbreak
+		if lab != nil {
+			lab.Breakpc = nil
+		}
+
+	case ODCL:
+		cgen_dcl(n.Left)
+
+	case OAS:
+		if gen_as_init(n) {
+			break
+		}
+		Cgen_as(n.Left, n.Right)
+
+	case OASWB:
+		Cgen_as_wb(n.Left, n.Right, true)
+
+	case OAS2DOTTYPE:
+		cgen_dottype(n.Rlist.N, n.List.N, n.List.Next.N, false)
+
+	case OCALLMETH:
+		cgen_callmeth(n, 0)
+
+	case OCALLINTER:
+		cgen_callinter(n, nil, 0)
+
+	case OCALLFUNC:
+		cgen_call(n, 0)
+
+	case OPROC:
+		cgen_proc(n, 1)
+
+	case ODEFER:
+		cgen_proc(n, 2)
+
+	case ORETURN, ORETJMP:
+		cgen_ret(n)
+
+	// Function calls turned into compiler intrinsics.
+	// At top level, can just ignore the call and make sure to preserve side effects in the argument, if any.
+	case OGETG:
+		// nothing
+	case OSQRT:
+		cgen_discard(n.Left)
+
+	case OCHECKNIL:
+		Cgen_checknil(n.Left)
+
+	case OVARKILL:
+		gvarkill(n.Left)
+	}
+
+ret:
+	if Anyregalloc() != wasregalloc {
+		Dump("node", n)
+		Fatal("registers left allocated")
+	}
+
+	lineno = lno
+}
+
+func Cgen_as(nl, nr *Node) {
+	Cgen_as_wb(nl, nr, false)
+}
+
+func Cgen_as_wb(nl, nr *Node, wb bool) {
+	if Debug['g'] != 0 {
+		op := "cgen_as"
+		if wb {
+			op = "cgen_as_wb"
+		}
+		Dump(op, nl)
+		Dump(op+" = ", nr)
+	}
+
+	for nr != nil && nr.Op == OCONVNOP {
+		nr = nr.Left
+	}
+
+	if nl == nil || isblank(nl) {
+		cgen_discard(nr)
+		return
+	}
+
+	if nr == nil || iszero(nr) {
+		// heaps should already be clear
+		if nr == nil && (nl.Class&PHEAP != 0) {
+			return
+		}
+
+		tl := nl.Type
+		if tl == nil {
+			return
+		}
+		if Isfat(tl) {
+			if nl.Op == ONAME {
+				Gvardef(nl)
+			}
+			Thearch.Clearfat(nl)
+			return
+		}
+
+		Clearslim(nl)
+		return
+	}
+
+	tl := nl.Type
+	if tl == nil {
+		return
+	}
+
+	cgen_wb(nr, nl, wb)
+}
+
+func cgen_callmeth(n *Node, proc int) {
+	// generate a rewrite in n2 for the method call
+	// (p.f)(...) goes to (f)(p,...)
+
+	l := n.Left
+
+	if l.Op != ODOTMETH {
+		Fatal("cgen_callmeth: not dotmethod: %v", l)
+	}
+
+	n2 := *n
+	n2.Op = OCALLFUNC
+	n2.Left = l.Right
+	n2.Left.Type = l.Type
+
+	if n2.Left.Op == ONAME {
+		n2.Left.Class = PFUNC
+	}
+	cgen_call(&n2, proc)
+}
+
+// CgenTemp creates a temporary node, assigns n to it, and returns it.
+func CgenTemp(n *Node) *Node {
+	var tmp Node
+	Tempname(&tmp, n.Type)
+	Cgen(n, &tmp)
+	return &tmp
+}
+
+func checklabels() {
+	var l *NodeList
+
+	for lab := labellist; lab != nil; lab = lab.Link {
+		if lab.Def == nil {
+			for l = lab.Use; l != nil; l = l.Next {
+				yyerrorl(int(l.N.Lineno), "label %v not defined", lab.Sym)
+			}
+			continue
+		}
+
+		if lab.Use == nil && lab.Used == 0 {
+			yyerrorl(int(lab.Def.Lineno), "label %v defined and not used", lab.Sym)
+			continue
+		}
+
+		if lab.Gotopc != nil {
+			Fatal("label %v never resolved", lab.Sym)
+		}
+		for l = lab.Use; l != nil; l = l.Next {
+			checkgoto(l.N, lab.Def)
+		}
+	}
+}
+
+// Componentgen copies 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 nil when assigning a zero value.
+func Componentgen(nr, nl *Node) bool {
+	return componentgen_wb(nr, nl, false)
+}
+
+// componentgen_wb is like componentgen but if wb==true emits write barriers for pointer updates.
+func componentgen_wb(nr, nl *Node, wb bool) bool {
+	// Don't generate any code for complete copy of a variable into itself.
+	// It's useless, and the VARDEF will incorrectly mark the old value as dead.
+	// (This check assumes that the arguments passed to componentgen did not
+	// themselves come from Igen, or else we could have Op==ONAME but
+	// with a Type and Xoffset describing an individual field, not the entire
+	// variable.)
+	if nl.Op == ONAME && nl == nr {
+		return true
+	}
+
+	// Count number of moves required to move components.
+	// If using write barrier, can only emit one pointer.
+	// TODO(rsc): Allow more pointers, for reflect.Value.
+	const maxMoves = 8
+	n := 0
+	numPtr := 0
+	visitComponents(nl.Type, 0, func(t *Type, offset int64) bool {
+		n++
+		if int(Simtype[t.Etype]) == Tptr && t != itable {
+			numPtr++
+		}
+		return n <= maxMoves && (!wb || numPtr <= 1)
+	})
+	if n > maxMoves || wb && numPtr > 1 {
+		return false
+	}
+
+	// Must call emitVardef after evaluating rhs but before writing to lhs.
+	emitVardef := func() {
+		// Emit vardef if needed.
+		if nl.Op == ONAME {
+			switch nl.Type.Etype {
+			case TARRAY, TSTRING, TINTER, TSTRUCT:
+				Gvardef(nl)
+			}
+		}
+	}
+
+	isConstString := Isconst(nr, CTSTR)
+
+	if !cadable(nl) && nr != nil && !cadable(nr) && !isConstString {
+		return false
+	}
+
+	var nodl Node
+	if cadable(nl) {
+		nodl = *nl
+	} else {
+		if nr != nil && !cadable(nr) && !isConstString {
+			return false
+		}
+		if nr == nil || isConstString || nl.Ullman >= nr.Ullman {
+			Igen(nl, &nodl, nil)
+			defer Regfree(&nodl)
+		}
+	}
+	lbase := nodl.Xoffset
+
+	// Special case: zeroing.
+	var nodr Node
+	if nr == nil {
+		// When zeroing, prepare a register containing zero.
+		// TODO(rsc): Check that this is actually generating the best code.
+		if Thearch.REGZERO != 0 {
+			// cpu has a dedicated zero register
+			Nodreg(&nodr, Types[TUINT], Thearch.REGZERO)
+		} else {
+			// no dedicated zero register
+			var zero Node
+			Nodconst(&zero, nl.Type, 0)
+			Regalloc(&nodr, Types[TUINT], nil)
+			Thearch.Gmove(&zero, &nodr)
+			defer Regfree(&nodr)
+		}
+
+		emitVardef()
+		visitComponents(nl.Type, 0, func(t *Type, offset int64) bool {
+			nodl.Type = t
+			nodl.Xoffset = lbase + offset
+			nodr.Type = t
+			if Isfloat[t.Etype] {
+				// TODO(rsc): Cache zero register like we do for integers?
+				Clearslim(&nodl)
+			} else {
+				Thearch.Gmove(&nodr, &nodl)
+			}
+			return true
+		})
+		return true
+	}
+
+	// Special case: assignment of string constant.
+	if isConstString {
+		emitVardef()
+
+		// base
+		nodl.Type = Ptrto(Types[TUINT8])
+		Regalloc(&nodr, Types[Tptr], nil)
+		p := Thearch.Gins(Thearch.Optoas(OAS, Types[Tptr]), nil, &nodr)
+		Datastring(nr.Val().U.(string), &p.From)
+		p.From.Type = obj.TYPE_ADDR
+		Thearch.Gmove(&nodr, &nodl)
+		Regfree(&nodr)
+
+		// length
+		nodl.Type = Types[Simtype[TUINT]]
+		nodl.Xoffset += int64(Array_nel) - int64(Array_array)
+		Nodconst(&nodr, nodl.Type, int64(len(nr.Val().U.(string))))
+		Thearch.Gmove(&nodr, &nodl)
+		return true
+	}
+
+	// General case: copy nl = nr.
+	nodr = *nr
+	if !cadable(nr) {
+		if nr.Ullman >= UINF && nodl.Op == OINDREG {
+			Fatal("miscompile")
+		}
+		Igen(nr, &nodr, nil)
+		defer Regfree(&nodr)
+	}
+	rbase := nodr.Xoffset
+
+	if nodl.Op == 0 {
+		Igen(nl, &nodl, nil)
+		defer Regfree(&nodl)
+		lbase = nodl.Xoffset
+	}
+
+	emitVardef()
+	var (
+		ptrType   *Type
+		ptrOffset int64
+	)
+	visitComponents(nl.Type, 0, func(t *Type, offset int64) bool {
+		if wb && int(Simtype[t.Etype]) == Tptr && t != itable {
+			if ptrType != nil {
+				Fatal("componentgen_wb %v", Tconv(nl.Type, 0))
+			}
+			ptrType = t
+			ptrOffset = offset
+			return true
+		}
+		nodl.Type = t
+		nodl.Xoffset = lbase + offset
+		nodr.Type = t
+		nodr.Xoffset = rbase + offset
+		Thearch.Gmove(&nodr, &nodl)
+		return true
+	})
+	if ptrType != nil {
+		nodl.Type = ptrType
+		nodl.Xoffset = lbase + ptrOffset
+		nodr.Type = ptrType
+		nodr.Xoffset = rbase + ptrOffset
+		cgen_wbptr(&nodr, &nodl)
+	}
+	return true
+}
+
+// visitComponents walks the individual components of the type t,
+// walking into array elements, struct fields, the real and imaginary
+// parts of complex numbers, and on 32-bit systems the high and
+// low halves of 64-bit integers.
+// It calls f for each such component, passing the component (aka element)
+// type and memory offset, assuming t starts at startOffset.
+// If f ever returns false, visitComponents returns false without any more
+// calls to f. Otherwise visitComponents returns true.
+func visitComponents(t *Type, startOffset int64, f func(elem *Type, elemOffset int64) bool) bool {
+	switch t.Etype {
+	case TINT64:
+		if Widthreg == 8 {
+			break
+		}
+		// NOTE: Assuming little endian (signed top half at offset 4).
+		// We don't have any 32-bit big-endian systems.
+		if Thearch.Thechar != '5' && Thearch.Thechar != '8' {
+			Fatal("unknown 32-bit architecture")
+		}
+		return f(Types[TUINT32], startOffset) &&
+			f(Types[TINT32], startOffset+4)
+
+	case TUINT64:
+		if Widthreg == 8 {
+			break
+		}
+		return f(Types[TUINT32], startOffset) &&
+			f(Types[TUINT32], startOffset+4)
+
+	case TCOMPLEX64:
+		return f(Types[TFLOAT32], startOffset) &&
+			f(Types[TFLOAT32], startOffset+4)
+
+	case TCOMPLEX128:
+		return f(Types[TFLOAT64], startOffset) &&
+			f(Types[TFLOAT64], startOffset+8)
+
+	case TINTER:
+		return f(itable, startOffset) &&
+			f(Ptrto(Types[TUINT8]), startOffset+int64(Widthptr))
+		return true
+
+	case TSTRING:
+		return f(Ptrto(Types[TUINT8]), startOffset) &&
+			f(Types[Simtype[TUINT]], startOffset+int64(Widthptr))
+
+	case TARRAY:
+		if Isslice(t) {
+			return f(Ptrto(t.Type), startOffset+int64(Array_array)) &&
+				f(Types[Simtype[TUINT]], startOffset+int64(Array_nel)) &&
+				f(Types[Simtype[TUINT]], startOffset+int64(Array_cap))
+		}
+
+		// Short-circuit [1e6]struct{}.
+		if t.Type.Width == 0 {
+			return true
+		}
+
+		for i := int64(0); i < t.Bound; i++ {
+			if !visitComponents(t.Type, startOffset+i*t.Type.Width, f) {
+				return false
+			}
+		}
+		return true
+
+	case TSTRUCT:
+		if t.Type != nil && t.Type.Width != 0 {
+			// NOTE(rsc): If this happens, the right thing to do is to say
+			//	startOffset -= t.Type.Width
+			// but I want to see if it does.
+			// The old version of componentgen handled this,
+			// in code introduced in CL 6932045 to fix issue #4518.
+			// But the test case in issue 4518 does not trigger this anymore,
+			// so maybe this complication is no longer needed.
+			Fatal("struct not at offset 0")
+		}
+
+		for field := t.Type; field != nil; field = field.Down {
+			if field.Etype != TFIELD {
+				Fatal("bad struct")
+			}
+			if !visitComponents(field.Type, startOffset+field.Width, f) {
+				return false
+			}
+		}
+		return true
+	}
+	return f(t, startOffset)
+}
+
+func cadable(n *Node) bool {
+	// Note: Not sure why you can have n.Op == ONAME without n.Addable, but you can.
+	return n.Addable && n.Op == ONAME
+}
diff --git a/src/cmd/compile/internal/gc/go.go b/src/cmd/compile/internal/gc/go.go
new file mode 100644
index 0000000..67d27bb
--- /dev/null
+++ b/src/cmd/compile/internal/gc/go.go
@@ -0,0 +1,870 @@
+// 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 (
+	"bytes"
+	"cmd/compile/internal/big"
+	"cmd/internal/obj"
+)
+
+// avoid <ctype.h>
+
+// The parser's maximum stack size.
+// We have to use a #define macro here since yacc
+// 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
+	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
+	AMEM32
+	AMEM64
+	AMEM128
+	ANOEQ
+	ANOEQ0
+	ANOEQ8
+	ANOEQ16
+	ANOEQ32
+	ANOEQ64
+	ANOEQ128
+	ASTRING
+	AINTER
+	ANILINTER
+	ASLICE
+	AFLOAT32
+	AFLOAT64
+	ACPLX64
+	ACPLX128
+	AUNK = 100
+)
+
+const (
+	// Maximum size in bits for Mpints before signalling
+	// overflow and also mantissa precision for Mpflts.
+	Mpprec = 512
+	// Turn on for constant arithmetic debugging output.
+	Mpdebug = false
+)
+
+// Mpint represents an integer constant.
+type Mpint struct {
+	Val  big.Int
+	Ovf  bool // set if Val overflowed compiler limit (sticky)
+	Rune bool // set if syntax indicates default type rune
+}
+
+// Mpflt represents a floating-point constant.
+type Mpflt struct {
+	Val big.Float
+}
+
+// Mpcplx represents a complex constant.
+type Mpcplx struct {
+	Real Mpflt
+	Imag Mpflt
+}
+
+type Val struct {
+	// U contains one of:
+	// bool     bool when n.ValCtype() == CTBOOL
+	// *Mpint   int when n.ValCtype() == CTINT, rune when n.ValCtype() == CTRUNE
+	// *Mpflt   float when n.ValCtype() == CTFLT
+	// *Mpcplx  pair of floats when n.ValCtype() == CTCPLX
+	// string   string when n.ValCtype() == CTSTR
+	// *Nilval  when n.ValCtype() == CTNIL
+	U interface{}
+}
+
+type NilVal struct{}
+
+func (v Val) Ctype() int {
+	switch x := v.U.(type) {
+	default:
+		Fatal("unexpected Ctype for %T", v.U)
+		panic("not reached")
+	case nil:
+		return 0
+	case *NilVal:
+		return CTNIL
+	case bool:
+		return CTBOOL
+	case *Mpint:
+		if x.Rune {
+			return CTRUNE
+		}
+		return CTINT
+	case *Mpflt:
+		return CTFLT
+	case *Mpcplx:
+		return CTCPLX
+	case string:
+		return CTSTR
+	}
+}
+
+type Pkg struct {
+	Name     string // package name
+	Path     string // string literal used in import statement
+	Pathsym  *Sym
+	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
+	Link      *Sym
+	Uniqgen   uint32
+	Importdef *Pkg   // where imported definition was found
+	Linkname  string // link name
+
+	// saved and restored by dcopy
+	Pkg        *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
+	Fsym       *Sym // funcsym
+}
+
+type Type struct {
+	Etype       uint8
+	Nointerface bool
+	Noalg       uint8
+	Chan        uint8
+	Trecur      uint8 // to detect loops
+	Printed     uint8
+	Embedded    uint8 // TFIELD embedded type
+	Siggen      uint8
+	Funarg      uint8 // on TSTRUCT and TFIELD
+	Copyany     uint8
+	Local       bool // created in this file
+	Deferwidth  uint8
+	Broke       uint8 // broken type definition.
+	Isddd       bool  // TFIELD is ... argument
+	Align       uint8
+	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
+
+	// 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 // struct, array only
+	Expr    *Node // bytes of run-time computed expressions
+}
+
+type InitPlan struct {
+	Lit  int64
+	Zero int64
+	Expr int64
+	E    []InitEntry
+}
+
+const (
+	SymExport   = 1 << 0 // to be exported
+	SymPackage  = 1 << 1
+	SymExported = 1 << 2 // already written out by export
+	SymUniq     = 1 << 3
+	SymSiggen   = 1 << 4
+	SymAsm      = 1 << 5
+	SymAlgGen   = 1 << 6
+)
+
+var dclstack *Sym
+
+type Iter struct {
+	Done  int
+	Tfunc *Type
+	T     *Type
+}
+
+const (
+	Txxx = iota
+
+	TINT8
+	TUINT8
+	TINT16
+	TUINT16
+	TINT32
+	TUINT32
+	TINT64
+	TUINT64
+	TINT
+	TUINT
+	TUINTPTR
+
+	TCOMPLEX64
+	TCOMPLEX128
+
+	TFLOAT32
+	TFLOAT64
+
+	TBOOL
+
+	TPTR32
+	TPTR64
+
+	TFUNC
+	TARRAY
+	T_old_DARRAY
+	TSTRUCT
+	TCHAN
+	TMAP
+	TINTER
+	TFORW
+	TFIELD
+	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
+	CTCPLX
+	CTSTR
+	CTBOOL
+	CTNIL
+)
+
+const (
+	/* types of channel */
+	/* must match ../../pkg/nreflect/type.go:/Chandir */
+	Cxxx  = 0
+	Crecv = 1 << 0
+	Csend = 1 << 1
+	Cboth = Crecv | Csend
+)
+
+// declaration context
+const (
+	Pxxx      = uint8(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 = uint8(1 << 7) // an extra bit to identify an escaped variable
+)
+
+const (
+	Etop      = 1 << 1 // evaluated at statement level
+	Erv       = 1 << 2 // evaluated in value context
+	Etype     = 1 << 3
+	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
+)
+
+type Typedef struct {
+	Name   string
+	Etype  int
+	Sameas int
+}
+
+type Sig struct {
+	name   string
+	pkg    *Pkg
+	isym   *Sym
+	tsym   *Sym
+	type_  *Type
+	mtype  *Type
+	offset int32
+	link   *Sig
+}
+
+type Io struct {
+	infile     string
+	bin        *obj.Biobuf
+	nlsemi     int
+	eofnl      int
+	last       int
+	peekc      int
+	peekc1     int    // second peekc for ...
+	cp         string // used for content when bin==nil
+	importsafe bool
+}
+
+type Dlist struct {
+	field *Type
+}
+
+type Idir struct {
+	link *Idir
+	dir  string
+}
+
+/*
+ * argument passing to/from
+ * smagic and umagic
+ */
+type Magic struct {
+	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
+}
+
+/*
+ * note this is the runtime representation
+ * of the compilers arrays.
+ *
+ * typedef	struct
+ * {				// must not move anything
+ *	uchar	array[8];	// pointer to data
+ *	uchar	nel[4];		// number of elements
+ *	uchar	cap[4];		// allocated number of elements
+ * } Array;
+ */
+var Array_array int // runtime offsetof(Array,array) - same for String
+
+var Array_nel int // runtime offsetof(Array,nel) - same for String
+
+var Array_cap int // runtime offsetof(Array,cap)
+
+var sizeof_Array int // runtime sizeof(Array)
+
+/*
+ * note this is the runtime representation
+ * of the compilers strings.
+ *
+ * typedef	struct
+ * {				// must not move anything
+ *	uchar	array[8];	// pointer to data
+ *	uchar	nel[4];		// number of elements
+ * } String;
+ */
+var sizeof_String int // runtime sizeof(String)
+
+var dotlist [10]Dlist // size is max depth of embeddeds
+
+var curio Io
+
+var pushedio Io
+
+var lexlineno int32
+
+var lineno int32
+
+var prevlineno int32
+
+var pragcgobuf string
+
+var infile string
+
+var outfile string
+
+var bout *obj.Biobuf
+
+var nerrors int
+
+var nsavederrors int
+
+var nsyntaxerrors int
+
+var decldepth int32
+
+var safemode int
+
+var nolocalimports int
+
+var lexbuf bytes.Buffer
+var strbuf bytes.Buffer
+
+var litbuf string
+
+var Debug [256]int
+
+var debugstr string
+
+var Debug_checknil int
+var Debug_typeassert int
+
+var importmyname *Sym // my name for package
+
+var localpkg *Pkg // package being compiled
+
+var importpkg *Pkg // package being imported
+
+var structpkg *Pkg // package that declared struct, during import
+
+var builtinpkg *Pkg // fake package for builtins
+
+var gostringpkg *Pkg // fake pkg for Go strings
+
+var itabpkg *Pkg // fake pkg for itab cache
+
+var Runtimepkg *Pkg // package runtime
+
+var racepkg *Pkg // package runtime/race
+
+var typepkg *Pkg // fake package for runtime type info (headers)
+
+var typelinkpkg *Pkg // fake package for runtime type info (data)
+
+var weaktypepkg *Pkg // weak references to runtime type info
+
+var unsafepkg *Pkg // package unsafe
+
+var trackpkg *Pkg // fake package for field tracking
+
+var Tptr int // either TPTR32 or TPTR64
+
+var myimportpath string
+
+var idirs *Idir
+
+var localimport string
+
+var asmhdr string
+
+var Types [NTYPE]*Type
+
+var idealstring *Type
+
+var idealbool *Type
+
+var bytetype *Type
+
+var runetype *Type
+
+var errortype *Type
+
+var Simtype [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 (
+	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 (
+	okfor [OEND][]bool
+	iscmp [OEND]bool
+)
+
+var Minintval [NTYPE]*Mpint
+
+var Maxintval [NTYPE]*Mpint
+
+var minfltval [NTYPE]*Mpflt
+
+var maxfltval [NTYPE]*Mpflt
+
+var xtop *NodeList
+
+var externdcl *NodeList
+
+var exportlist *NodeList
+
+var importlist *NodeList // imported functions and methods with inlinable bodies
+
+var funcsyms *NodeList
+
+var dclcontext uint8 // PEXTERN/PAUTO
+
+var incannedimport int
+
+var statuniqgen int // name generator for static temps
+
+var loophack int
+
+var iota_ int32
+
+var lastconst *NodeList
+
+var lasttype *Node
+
+var Maxarg int64
+
+var Stksize int64 // stack size for current frame
+
+var stkptrsize int64 // prefix of stack containing pointers
+
+var blockgen int32 // max block number
+
+var block int32 // current block number
+
+var Hasdefer int // flag that curfn has defer statetment
+
+var Curfn *Node
+
+var Widthptr int
+
+var Widthint int
+
+var Widthreg int
+
+var typesw *Node
+
+var nblank *Node
+
+var hunk string
+
+var nhunk int32
+
+var thunk int32
+
+var Funcdepth int32
+
+var typecheckok int
+
+var compiling_runtime int
+
+var compiling_wrappers int
+
+var use_writebarrier int
+
+var pure_go int
+
+var flag_installsuffix string
+
+var flag_race int
+
+var flag_largemodel int
+
+// Pending annotations for next func declaration.
+var (
+	noescape       bool
+	nosplit        bool
+	nowritebarrier bool
+	systemstack    bool
+	norace         bool
+)
+
+var debuglive int
+
+var Ctxt *obj.Link
+
+var nointerface bool
+
+var writearchive int
+
+var bstdout obj.Biobuf
+
+var Nacl bool
+
+var continpc *obj.Prog
+
+var breakpc *obj.Prog
+
+var Pc *obj.Prog
+
+var nodfp *Node
+
+var Disable_checknil int
+
+var zerosize int64
+
+type Flow struct {
+	Prog   *obj.Prog // actual instruction
+	P1     *Flow     // predecessors of this instruction: p1,
+	P2     *Flow     // and then p2 linked though p2link.
+	P2link *Flow
+	S1     *Flow // successors of this instruction (at most two: s1 and s2).
+	S2     *Flow
+	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
+
+	// 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
+ */
+
+const (
+	// 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
+
+	// 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
+	REGCALLX     int // BX
+	REGCALLX2    int // AX
+	REGRETURN    int // AX
+	REGMIN       int
+	REGMAX       int
+	REGZERO      int // architectural zero register, if available
+	FREGMIN      int
+	FREGMAX      int
+	MAXWIDTH     int64
+	ReservedRegs []int
+
+	AddIndex     func(*Node, int64, *Node) bool // optional
+	Betypeinit   func()
+	Bgen_float   func(*Node, bool, 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)
+	Getg         func(*Node)
+	Gins         func(int, *Node, *Node) *obj.Prog
+
+	// Ginscmp generates code comparing n1 to n2 and jumping away if op is satisfied.
+	// The returned prog should be Patch'ed with the jump target.
+	// If op is not satisfied, code falls through to the next emitted instruction.
+	// Likely is the branch prediction hint: +1 for likely, -1 for unlikely, 0 for no opinion.
+	//
+	// Ginscmp must be able to handle all kinds of arguments for n1 and n2,
+	// not just simple registers, although it can assume that there are no
+	// function calls needed during the evaluation, and on 32-bit systems
+	// the values are guaranteed not to be 64-bit values, so no in-memory
+	// temporaries are necessary.
+	Ginscmp func(op int, t *Type, n1, n2 *Node, likely int) *obj.Prog
+
+	// Ginsboolval inserts instructions to convert the result
+	// of a just-completed comparison to a boolean value.
+	// The first argument is the conditional jump instruction
+	// corresponding to the desired value.
+	// The second argument is the destination.
+	// If not present, Ginsboolval will be emulated with jumps.
+	Ginsboolval func(int, *Node)
+
+	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
+	Blockcopy    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
+	Use387       bool // should 8g use 387 FP instructions instead of sse2.
+}
+
+var pcloc int32
+
+var Thearch Arch
+
+var Newproc *Node
+
+var Deferproc *Node
+
+var Deferreturn *Node
+
+var Panicindex *Node
+
+var panicslice *Node
+
+var throwreturn *Node
diff --git a/src/cmd/compile/internal/gc/go.y b/src/cmd/compile/internal/gc/go.y
new file mode 100644
index 0000000..c6d1607
--- /dev/null
+++ b/src/cmd/compile/internal/gc/go.y
@@ -0,0 +1,2316 @@
+// 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.
+
+/*
+ * Go language grammar.
+ *
+ * The Go semicolon rules are:
+ *
+ *  1. all statements and declarations are terminated by semicolons.
+ *  2. semicolons can be omitted before a closing ) or }.
+ *  3. semicolons are inserted by the lexer before a newline
+ *      following a specific list of tokens.
+ *
+ * Rules #1 and #2 are accomplished by writing the lists as
+ * semicolon-separated lists with an optional trailing semicolon.
+ * Rule #3 is implemented in yylex.
+ */
+
+%{
+package gc
+
+import (
+	"fmt"
+	"strings"
+)
+%}
+%union	{
+	node *Node
+	list *NodeList
+	typ *Type
+	sym *Sym
+	val Val
+	i int
+}
+
+// |sed 's/.*	//' |9 fmt -l1 |sort |9 fmt -l50 | sed 's/^/%xxx		/'
+
+%token	<val>	LLITERAL
+%token	<i>	LASOP LCOLAS
+%token	<sym>	LBREAK LCASE LCHAN LCONST LCONTINUE LDDD
+%token	<sym>	LDEFAULT LDEFER LELSE LFALL LFOR LFUNC LGO LGOTO
+%token	<sym>	LIF LIMPORT LINTERFACE LMAP LNAME
+%token	<sym>	LPACKAGE LRANGE LRETURN LSELECT LSTRUCT LSWITCH
+%token	<sym>	LTYPE LVAR
+
+%token		LANDAND LANDNOT LBODY LCOMM LDEC LEQ LGE LGT
+%token		LIGNORE LINC LLE LLSH LLT LNE LOROR LRSH
+
+%type	<i>	lbrace import_here
+%type	<sym>	sym packname
+%type	<val>	oliteral
+
+%type	<node>	stmt ntype
+%type	<node>	arg_type
+%type	<node>	case caseblock
+%type	<node>	compound_stmt dotname embed expr complitexpr bare_complitexpr
+%type	<node>	expr_or_type
+%type	<node>	fndcl hidden_fndcl fnliteral
+%type	<node>	for_body for_header for_stmt if_header if_stmt non_dcl_stmt
+%type	<node>	interfacedcl keyval labelname name
+%type	<node>	name_or_type non_expr_type
+%type	<node>	new_name dcl_name oexpr typedclname
+%type	<node>	onew_name
+%type	<node>	osimple_stmt pexpr pexpr_no_paren
+%type	<node>	pseudocall range_stmt select_stmt
+%type	<node>	simple_stmt
+%type	<node>	switch_stmt uexpr
+%type	<node>	xfndcl typedcl start_complit
+
+%type	<list>	xdcl fnbody fnres loop_body dcl_name_list
+%type	<list>	new_name_list expr_list keyval_list braced_keyval_list expr_or_type_list xdcl_list
+%type	<list>	oexpr_list caseblock_list elseif elseif_list else stmt_list oarg_type_list_ocomma arg_type_list
+%type	<list>	interfacedcl_list vardcl vardcl_list structdcl structdcl_list
+%type	<list>	common_dcl constdcl constdcl1 constdcl_list typedcl_list
+
+%type	<node>	convtype comptype dotdotdot
+%type	<node>	indcl interfacetype structtype ptrtype
+%type	<node>	recvchantype non_recvchantype othertype fnret_type fntype
+
+%type	<sym>	hidden_importsym hidden_pkg_importsym
+
+%type	<node>	hidden_constant hidden_literal hidden_funarg
+%type	<node>	hidden_interfacedcl hidden_structdcl
+
+%type	<list>	hidden_funres
+%type	<list>	ohidden_funres
+%type	<list>	hidden_funarg_list ohidden_funarg_list
+%type	<list>	hidden_interfacedcl_list ohidden_interfacedcl_list
+%type	<list>	hidden_structdcl_list ohidden_structdcl_list
+
+%type	<typ>	hidden_type hidden_type_misc hidden_pkgtype
+%type	<typ>	hidden_type_func
+%type	<typ>	hidden_type_recv_chan hidden_type_non_recv_chan
+
+%left		LCOMM	/* outside the usual hierarchy; here for good error messages */
+
+%left		LOROR
+%left		LANDAND
+%left		LEQ LNE LLE LGE LLT LGT
+%left		'+' '-' '|' '^'
+%left		'*' '/' '%' '&' LLSH LRSH LANDNOT
+
+/*
+ * manual override of shift/reduce conflicts.
+ * the general form is that we assign a precedence
+ * to the token being shifted and then introduce
+ * NotToken with lower precedence or PreferToToken with higher
+ * and annotate the reducing rule accordingly.
+ */
+%left		NotPackage
+%left		LPACKAGE
+
+%left		NotParen
+%left		'('
+
+%left		')'
+%left		PreferToRightParen
+
+%error loadsys package LIMPORT '(' LLITERAL import_package import_there ',':
+	"unexpected comma during import block"
+
+%error loadsys package LIMPORT LNAME ';':
+	"missing import path; require quoted string"
+
+%error loadsys package imports LFUNC LNAME '(' ')' '{' LIF if_header ';':
+	"missing { after if clause"
+
+%error loadsys package imports LFUNC LNAME '(' ')' '{' LSWITCH if_header ';':
+	"missing { after switch clause"
+
+%error loadsys package imports LFUNC LNAME '(' ')' '{' LFOR for_header ';':
+	"missing { after for clause"
+
+%error loadsys package imports LFUNC LNAME '(' ')' '{' LFOR ';' LBODY:
+	"missing { after for clause"
+
+%error loadsys package imports LFUNC LNAME '(' ')' ';' '{':
+	"unexpected semicolon or newline before {"
+
+%error loadsys package imports LTYPE LNAME ';':
+	"unexpected semicolon or newline in type declaration"
+
+%error loadsys package imports LCHAN '}':
+	"unexpected } in channel type"
+
+%error loadsys package imports LCHAN ')':
+	"unexpected ) in channel type"
+
+%error loadsys package imports LCHAN ',':
+	"unexpected comma in channel type"
+
+%error loadsys package imports LFUNC LNAME '(' ')' '{' if_stmt ';' LELSE:
+	"unexpected semicolon or newline before else"
+
+%error loadsys package imports LTYPE LNAME LINTERFACE '{' LNAME ',' LNAME:
+	"name list not allowed in interface type"
+
+%error loadsys package imports LFUNC LNAME '(' ')' '{' LFOR LVAR LNAME '=' LNAME:
+	"var declaration not allowed in for initializer"
+
+%error loadsys package imports LVAR LNAME '[' ']' LNAME '{':
+	"unexpected { at end of statement"
+
+%error loadsys package imports LFUNC LNAME '(' ')' '{' LVAR LNAME '[' ']' LNAME '{':
+	"unexpected { at end of statement"
+
+%error loadsys package imports LFUNC LNAME '(' ')' '{' LDEFER LNAME ';':
+	"argument to go/defer must be function call"
+
+%error loadsys package imports LVAR LNAME '=' LNAME '{' LNAME ';':
+	"need trailing comma before newline in composite literal"
+
+%error loadsys package imports LVAR LNAME '=' comptype '{' LNAME ';':
+	"need trailing comma before newline in composite literal"
+
+%error loadsys package imports LFUNC LNAME '(' ')' '{' LFUNC LNAME:
+	"nested func not allowed"
+
+%error loadsys package imports LFUNC LNAME '(' ')' '{' LIF if_header loop_body LELSE ';':
+	"else must be followed by if or statement block"
+
+%%
+file:
+	loadsys
+	package
+	imports
+	xdcl_list
+	{
+		xtop = concat(xtop, $4);
+	}
+
+package:
+	%prec NotPackage
+	{
+		prevlineno = lineno;
+		Yyerror("package statement must be first");
+		errorexit();
+	}
+|	LPACKAGE sym ';'
+	{
+		mkpackage($2.Name);
+	}
+
+/*
+ * this loads the definitions for the low-level runtime functions,
+ * so that the compiler can generate calls to them,
+ * but does not make the name "runtime" visible as a package.
+ */
+loadsys:
+	{
+		importpkg = Runtimepkg;
+
+		if Debug['A'] != 0 {
+			cannedimports("runtime.Builtin", "package runtime\n\n$$\n\n");
+		} else {
+			cannedimports("runtime.Builtin", runtimeimport);
+		}
+		curio.importsafe = true
+	}
+	import_package
+	import_there
+	{
+		importpkg = nil;
+	}
+
+imports:
+|	imports import ';'
+
+import:
+	LIMPORT import_stmt
+|	LIMPORT '(' import_stmt_list osemi ')'
+|	LIMPORT '(' ')'
+
+import_stmt:
+	import_here import_package import_there
+	{
+		ipkg := importpkg;
+		my := importmyname;
+		importpkg = nil;
+		importmyname = nil;
+
+		if my == nil {
+			my = Lookup(ipkg.Name);
+		}
+
+		pack := Nod(OPACK, nil, nil);
+		pack.Sym = my;
+		pack.Name.Pkg = ipkg;
+		pack.Lineno = int32($1);
+
+		if strings.HasPrefix(my.Name, ".") {
+			importdot(ipkg, pack);
+			break;
+		}
+		if my.Name == "init" {
+			Yyerror("cannot import package as init - init must be a func");
+			break;
+		}
+		if my.Name == "_" {
+			break;
+		}
+		if my.Def != nil {
+			lineno = int32($1);
+			redeclare(my, "as imported package name");
+		}
+		my.Def = pack;
+		my.Lastlineno = int32($1);
+		my.Block = 1;	// at top level
+	}
+|	import_here import_there
+	{
+		// When an invalid import path is passed to importfile,
+		// it calls Yyerror and then sets up a fake import with
+		// no package statement. This allows us to test more
+		// than one invalid import statement in a single file.
+		if nerrors == 0 {
+			Fatal("phase error in import");
+		}
+	}
+
+import_stmt_list:
+	import_stmt
+|	import_stmt_list ';' import_stmt
+
+import_here:
+	LLITERAL
+	{
+		// import with original name
+		$$ = parserline();
+		importmyname = nil;
+		importfile(&$1, $$);
+	}
+|	sym LLITERAL
+	{
+		// import with given name
+		$$ = parserline();
+		importmyname = $1;
+		importfile(&$2, $$);
+	}
+|	'.' LLITERAL
+	{
+		// import into my name space
+		$$ = parserline();
+		importmyname = Lookup(".");
+		importfile(&$2, $$);
+	}
+
+import_package:
+	LPACKAGE LNAME import_safety ';'
+	{
+		if importpkg.Name == "" {
+			importpkg.Name = $2.Name;
+			numImport[$2.Name]++
+		} else if importpkg.Name != $2.Name {
+			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 %q", importpkg.Path);
+		}
+	}
+
+import_safety:
+|	LNAME
+	{
+		if $1.Name == "safe" {
+			curio.importsafe = true
+		}
+	}
+
+import_there:
+	{
+		defercheckwidth();
+	}
+	hidden_import_list '$' '$'
+	{
+		resumecheckwidth();
+		unimportfile();
+	}
+
+/*
+ * declarations
+ */
+xdcl:
+	{
+		Yyerror("empty top-level declaration");
+		$$ = nil;
+	}
+|	common_dcl
+|	xfndcl
+	{
+		$$ = list1($1);
+	}
+|	non_dcl_stmt
+	{
+		Yyerror("non-declaration statement outside function body");
+		$$ = nil;
+	}
+|	error
+	{
+		$$ = nil;
+	}
+
+common_dcl:
+	LVAR vardcl
+	{
+		$$ = $2;
+	}
+|	LVAR '(' vardcl_list osemi ')'
+	{
+		$$ = $3;
+	}
+|	LVAR '(' ')'
+	{
+		$$ = nil;
+	}
+|	lconst constdcl
+	{
+		$$ = $2;
+		iota_ = -100000;
+		lastconst = nil;
+	}
+|	lconst '(' constdcl osemi ')'
+	{
+		$$ = $3;
+		iota_ = -100000;
+		lastconst = nil;
+	}
+|	lconst '(' constdcl ';' constdcl_list osemi ')'
+	{
+		$$ = concat($3, $5);
+		iota_ = -100000;
+		lastconst = nil;
+	}
+|	lconst '(' ')'
+	{
+		$$ = nil;
+		iota_ = -100000;
+	}
+|	LTYPE typedcl
+	{
+		$$ = list1($2);
+	}
+|	LTYPE '(' typedcl_list osemi ')'
+	{
+		$$ = $3;
+	}
+|	LTYPE '(' ')'
+	{
+		$$ = nil;
+	}
+
+lconst:
+	LCONST
+	{
+		iota_ = 0;
+	}
+
+vardcl:
+	dcl_name_list ntype
+	{
+		$$ = variter($1, $2, nil);
+	}
+|	dcl_name_list ntype '=' expr_list
+	{
+		$$ = variter($1, $2, $4);
+	}
+|	dcl_name_list '=' expr_list
+	{
+		$$ = variter($1, nil, $3);
+	}
+
+constdcl:
+	dcl_name_list ntype '=' expr_list
+	{
+		$$ = constiter($1, $2, $4);
+	}
+|	dcl_name_list '=' expr_list
+	{
+		$$ = constiter($1, nil, $3);
+	}
+
+constdcl1:
+	constdcl
+|	dcl_name_list ntype
+	{
+		$$ = constiter($1, $2, nil);
+	}
+|	dcl_name_list
+	{
+		$$ = constiter($1, nil, nil);
+	}
+
+typedclname:
+	sym
+	{
+		// different from dclname because the name
+		// becomes visible right here, not at the end
+		// of the declaration.
+		$$ = typedcl0($1);
+	}
+
+typedcl:
+	typedclname ntype
+	{
+		$$ = typedcl1($1, $2, true);
+	}
+
+simple_stmt:
+	expr
+	{
+		$$ = $1;
+
+		// These nodes do not carry line numbers.
+		// Since a bare name used as an expression is an error,
+		// introduce a wrapper node to give the correct line.
+		switch($$.Op) {
+		case ONAME, ONONAME, OTYPE, OPACK, OLITERAL:
+			$$ = Nod(OPAREN, $$, nil);
+			$$.Implicit = true;
+			break;
+		}
+	}
+|	expr LASOP expr
+	{
+		$$ = Nod(OASOP, $1, $3);
+		$$.Etype = uint8($2);			// rathole to pass opcode
+	}
+|	expr_list '=' expr_list
+	{
+		if $1.Next == nil && $3.Next == nil {
+			// simple
+			$$ = Nod(OAS, $1.N, $3.N);
+			break;
+		}
+		// multiple
+		$$ = Nod(OAS2, nil, nil);
+		$$.List = $1;
+		$$.Rlist = $3;
+	}
+|	expr_list LCOLAS expr_list
+	{
+		if $3.N.Op == OTYPESW {
+			$$ = Nod(OTYPESW, nil, $3.N.Right);
+			if $3.Next != nil {
+				Yyerror("expr.(type) must be alone in list");
+			}
+			if $1.Next != nil {
+				Yyerror("argument count mismatch: %d = %d", count($1), 1);
+			} else if ($1.N.Op != ONAME && $1.N.Op != OTYPE && $1.N.Op != ONONAME) || isblank($1.N) {
+				Yyerror("invalid variable name %s in type switch", $1.N);
+			} else {
+				$$.Left = dclname($1.N.Sym);
+			}  // it's a colas, so must not re-use an oldname.
+			break;
+		}
+		$$ = colas($1, $3, int32($2));
+	}
+|	expr LINC
+	{
+		$$ = Nod(OASOP, $1, Nodintconst(1));
+		$$.Implicit = true;
+		$$.Etype = OADD;
+	}
+|	expr LDEC
+	{
+		$$ = Nod(OASOP, $1, Nodintconst(1));
+		$$.Implicit = true;
+		$$.Etype = OSUB;
+	}
+
+case:
+	LCASE expr_or_type_list ':'
+	{
+		var n, nn *Node
+
+		// will be converted to OCASE
+		// right will point to next case
+		// done in casebody()
+		markdcl();
+		$$ = Nod(OXCASE, nil, nil);
+		$$.List = $2;
+		if typesw != nil && typesw.Right != nil {
+			n = typesw.Right.Left
+			if n != nil {
+				// type switch - declare variable
+				nn = newname(n.Sym);
+				declare(nn, dclcontext);
+				$$.Rlist = list1(nn);
+	
+				// keep track of the instances for reporting unused
+				nn.Name.Defn = typesw.Right;
+			}
+		}
+	}
+|	LCASE expr_or_type_list '=' expr ':'
+	{
+		var n *Node
+
+		// will be converted to OCASE
+		// right will point to next case
+		// done in casebody()
+		markdcl();
+		$$ = Nod(OXCASE, nil, nil);
+		if $2.Next == nil {
+			n = Nod(OAS, $2.N, $4);
+		} else {
+			n = Nod(OAS2, nil, nil);
+			n.List = $2;
+			n.Rlist = list1($4);
+		}
+		$$.List = list1(n);
+	}
+|	LCASE expr_or_type_list LCOLAS expr ':'
+	{
+		// will be converted to OCASE
+		// right will point to next case
+		// done in casebody()
+		markdcl();
+		$$ = Nod(OXCASE, nil, nil);
+		$$.List = list1(colas($2, list1($4), int32($3)));
+	}
+|	LDEFAULT ':'
+	{
+		var n, nn *Node
+
+		markdcl();
+		$$ = Nod(OXCASE, nil, nil);
+		if typesw != nil && typesw.Right != nil {
+			n = typesw.Right.Left
+			if n != nil {
+				// type switch - declare variable
+				nn = newname(n.Sym);
+				declare(nn, dclcontext);
+				$$.Rlist = list1(nn);
+	
+				// keep track of the instances for reporting unused
+				nn.Name.Defn = typesw.Right;
+			}
+		}
+	}
+
+compound_stmt:
+	'{'
+	{
+		markdcl();
+	}
+	stmt_list '}'
+	{
+		if $3 == nil {
+			$$ = Nod(OEMPTY, nil, nil);
+		} else {
+			$$ = liststmt($3);
+		}
+		popdcl();
+	}
+
+caseblock:
+	case
+	{
+		// If the last token read by the lexer was consumed
+		// as part of the case, clear it (parser has cleared yychar).
+		// If the last token read by the lexer was the lookahead
+		// leave it alone (parser has it cached in yychar).
+		// This is so that the stmt_list action doesn't look at
+		// the case tokens if the stmt_list is empty.
+		yylast = yychar;
+		$1.Xoffset = int64(block);
+	}
+	stmt_list
+	{
+		// This is the only place in the language where a statement
+		// list is not allowed to drop the final semicolon, because
+		// it's the only place where a statement list is not followed 
+		// by a closing brace.  Handle the error for pedantry.
+
+		// Find the final token of the statement list.
+		// yylast is lookahead; yyprev is last of stmt_list
+		last := yyprev;
+
+		if last > 0 && last != ';' && yychar != '}' {
+			Yyerror("missing statement after label");
+		}
+		$$ = $1;
+		$$.Nbody = $3;
+		popdcl();
+	}
+
+caseblock_list:
+	{
+		$$ = nil;
+	}
+|	caseblock_list caseblock
+	{
+		$$ = list($1, $2);
+	}
+
+loop_body:
+	LBODY
+	{
+		markdcl();
+	}
+	stmt_list '}'
+	{
+		$$ = $3;
+		popdcl();
+	}
+
+range_stmt:
+	expr_list '=' LRANGE expr
+	{
+		$$ = Nod(ORANGE, nil, $4);
+		$$.List = $1;
+		$$.Etype = 0;	// := flag
+	}
+|	expr_list LCOLAS LRANGE expr
+	{
+		$$ = Nod(ORANGE, nil, $4);
+		$$.List = $1;
+		$$.Colas = true;
+		colasdefn($1, $$);
+	}
+|	LRANGE expr
+	{
+		$$ = Nod(ORANGE, nil, $2);
+		$$.Etype = 0; // := flag
+	}
+
+for_header:
+	osimple_stmt ';' osimple_stmt ';' osimple_stmt
+	{
+		// init ; test ; incr
+		if $5 != nil && $5.Colas {
+			Yyerror("cannot declare in the for-increment");
+		}
+		$$ = Nod(OFOR, nil, nil);
+		if $1 != nil {
+			$$.Ninit = list1($1);
+		}
+		$$.Left = $3;
+		$$.Right = $5;
+	}
+|	osimple_stmt
+	{
+		// normal test
+		$$ = Nod(OFOR, nil, nil);
+		$$.Left = $1;
+	}
+|	range_stmt
+
+for_body:
+	for_header loop_body
+	{
+		$$ = $1;
+		$$.Nbody = concat($$.Nbody, $2);
+	}
+
+for_stmt:
+	LFOR
+	{
+		markdcl();
+	}
+	for_body
+	{
+		$$ = $3;
+		popdcl();
+	}
+
+if_header:
+	osimple_stmt
+	{
+		// test
+		$$ = Nod(OIF, nil, nil);
+		$$.Left = $1;
+	}
+|	osimple_stmt ';' osimple_stmt
+	{
+		// init ; test
+		$$ = Nod(OIF, nil, nil);
+		if $1 != nil {
+			$$.Ninit = list1($1);
+		}
+		$$.Left = $3;
+	}
+
+/* IF cond body (ELSE IF cond body)* (ELSE block)? */
+if_stmt:
+	LIF
+	{
+		markdcl();
+	}
+	if_header
+	{
+		if $3.Left == nil {
+			Yyerror("missing condition in if statement");
+		}
+	}
+	loop_body
+	{
+		$3.Nbody = $5;
+	}
+	elseif_list else
+	{
+		var n *Node
+		var nn *NodeList
+
+		$$ = $3;
+		n = $3;
+		popdcl();
+		for nn = concat($7, $8); nn != nil; nn = nn.Next {
+			if nn.N.Op == OIF {
+				popdcl();
+			}
+			n.Rlist = list1(nn.N);
+			n = nn.N;
+		}
+	}
+
+elseif:
+	LELSE LIF 
+	{
+		markdcl();
+	}
+	if_header loop_body
+	{
+		if $4.Left == nil {
+			Yyerror("missing condition in if statement");
+		}
+		$4.Nbody = $5;
+		$$ = list1($4);
+	}
+
+elseif_list:
+	{
+		$$ = nil;
+	}
+|	elseif_list elseif
+	{
+		$$ = concat($1, $2);
+	}
+
+else:
+	{
+		$$ = nil;
+	}
+|	LELSE compound_stmt
+	{
+		l := &NodeList{N: $2}
+		l.End = l
+		$$ = l;
+	}
+
+switch_stmt:
+	LSWITCH
+	{
+		markdcl();
+	}
+	if_header
+	{
+		var n *Node
+		n = $3.Left;
+		if n != nil && n.Op != OTYPESW {
+			n = nil;
+		}
+		typesw = Nod(OXXX, typesw, n);
+	}
+	LBODY caseblock_list '}'
+	{
+		$$ = $3;
+		$$.Op = OSWITCH;
+		$$.List = $6;
+		typesw = typesw.Left;
+		popdcl();
+	}
+
+select_stmt:
+	LSELECT
+	{
+		typesw = Nod(OXXX, typesw, nil);
+	}
+	LBODY caseblock_list '}'
+	{
+		$$ = Nod(OSELECT, nil, nil);
+		$$.Lineno = typesw.Lineno;
+		$$.List = $4;
+		typesw = typesw.Left;
+	}
+
+/*
+ * expressions
+ */
+expr:
+	uexpr
+|	expr LOROR expr
+	{
+		$$ = Nod(OOROR, $1, $3);
+	}
+|	expr LANDAND expr
+	{
+		$$ = Nod(OANDAND, $1, $3);
+	}
+|	expr LEQ expr
+	{
+		$$ = Nod(OEQ, $1, $3);
+	}
+|	expr LNE expr
+	{
+		$$ = Nod(ONE, $1, $3);
+	}
+|	expr LLT expr
+	{
+		$$ = Nod(OLT, $1, $3);
+	}
+|	expr LLE expr
+	{
+		$$ = Nod(OLE, $1, $3);
+	}
+|	expr LGE expr
+	{
+		$$ = Nod(OGE, $1, $3);
+	}
+|	expr LGT expr
+	{
+		$$ = Nod(OGT, $1, $3);
+	}
+|	expr '+' expr
+	{
+		$$ = Nod(OADD, $1, $3);
+	}
+|	expr '-' expr
+	{
+		$$ = Nod(OSUB, $1, $3);
+	}
+|	expr '|' expr
+	{
+		$$ = Nod(OOR, $1, $3);
+	}
+|	expr '^' expr
+	{
+		$$ = Nod(OXOR, $1, $3);
+	}
+|	expr '*' expr
+	{
+		$$ = Nod(OMUL, $1, $3);
+	}
+|	expr '/' expr
+	{
+		$$ = Nod(ODIV, $1, $3);
+	}
+|	expr '%' expr
+	{
+		$$ = Nod(OMOD, $1, $3);
+	}
+|	expr '&' expr
+	{
+		$$ = Nod(OAND, $1, $3);
+	}
+|	expr LANDNOT expr
+	{
+		$$ = Nod(OANDNOT, $1, $3);
+	}
+|	expr LLSH expr
+	{
+		$$ = Nod(OLSH, $1, $3);
+	}
+|	expr LRSH expr
+	{
+		$$ = Nod(ORSH, $1, $3);
+	}
+	/* not an expression anymore, but left in so we can give a good error */
+|	expr LCOMM expr
+	{
+		$$ = Nod(OSEND, $1, $3);
+	}
+
+uexpr:
+	pexpr
+|	'*' uexpr
+	{
+		$$ = Nod(OIND, $2, nil);
+	}
+|	'&' uexpr
+	{
+		if $2.Op == OCOMPLIT {
+			// Special case for &T{...}: turn into (*T){...}.
+			$$ = $2;
+			$$.Right = Nod(OIND, $$.Right, nil);
+			$$.Right.Implicit = true;
+		} else {
+			$$ = Nod(OADDR, $2, nil);
+		}
+	}
+|	'+' uexpr
+	{
+		$$ = Nod(OPLUS, $2, nil);
+	}
+|	'-' uexpr
+	{
+		$$ = Nod(OMINUS, $2, nil);
+	}
+|	'!' uexpr
+	{
+		$$ = Nod(ONOT, $2, nil);
+	}
+|	'~' uexpr
+	{
+		Yyerror("the bitwise complement operator is ^");
+		$$ = Nod(OCOM, $2, nil);
+	}
+|	'^' uexpr
+	{
+		$$ = Nod(OCOM, $2, nil);
+	}
+|	LCOMM uexpr
+	{
+		$$ = Nod(ORECV, $2, nil);
+	}
+
+/*
+ * call-like statements that
+ * can be preceded by 'defer' and 'go'
+ */
+pseudocall:
+	pexpr '(' ')'
+	{
+		$$ = Nod(OCALL, $1, nil);
+	}
+|	pexpr '(' expr_or_type_list ocomma ')'
+	{
+		$$ = Nod(OCALL, $1, nil);
+		$$.List = $3;
+	}
+|	pexpr '(' expr_or_type_list LDDD ocomma ')'
+	{
+		$$ = Nod(OCALL, $1, nil);
+		$$.List = $3;
+		$$.Isddd = true;
+	}
+
+pexpr_no_paren:
+	LLITERAL
+	{
+		$$ = nodlit($1);
+	}
+|	name
+|	pexpr '.' sym
+	{
+		if $1.Op == OPACK {
+			var s *Sym
+			s = restrictlookup($3.Name, $1.Name.Pkg);
+			$1.Used = true;
+			$$ = oldname(s);
+			break;
+		}
+		$$ = Nod(OXDOT, $1, newname($3));
+	}
+|	pexpr '.' '(' expr_or_type ')'
+	{
+		$$ = Nod(ODOTTYPE, $1, $4);
+	}
+|	pexpr '.' '(' LTYPE ')'
+	{
+		$$ = Nod(OTYPESW, nil, $1);
+	}
+|	pexpr '[' expr ']'
+	{
+		$$ = Nod(OINDEX, $1, $3);
+	}
+|	pexpr '[' oexpr ':' oexpr ']'
+	{
+		$$ = Nod(OSLICE, $1, Nod(OKEY, $3, $5));
+	}
+|	pexpr '[' oexpr ':' oexpr ':' oexpr ']'
+	{
+		if $5 == nil {
+			Yyerror("middle index required in 3-index slice");
+		}
+		if $7 == nil {
+			Yyerror("final index required in 3-index slice");
+		}
+		$$ = Nod(OSLICE3, $1, Nod(OKEY, $3, Nod(OKEY, $5, $7)));
+	}
+|	pseudocall
+|	convtype '(' expr ocomma ')'
+	{
+		// conversion
+		$$ = Nod(OCALL, $1, nil);
+		$$.List = list1($3);
+	}
+|	comptype lbrace start_complit braced_keyval_list '}'
+	{
+		$$ = $3;
+		$$.Right = $1;
+		$$.List = $4;
+		fixlbrace($2);
+	}
+|	pexpr_no_paren '{' start_complit braced_keyval_list '}'
+	{
+		$$ = $3;
+		$$.Right = $1;
+		$$.List = $4;
+	}
+|	'(' expr_or_type ')' '{' start_complit braced_keyval_list '}'
+	{
+		Yyerror("cannot parenthesize type in composite literal");
+		$$ = $5;
+		$$.Right = $2;
+		$$.List = $6;
+	}
+|	fnliteral
+
+start_complit:
+	{
+		// composite expression.
+		// make node early so we get the right line number.
+		$$ = Nod(OCOMPLIT, nil, nil);
+	}
+
+keyval:
+	complitexpr ':' complitexpr
+	{
+		$$ = Nod(OKEY, $1, $3);
+	}
+
+bare_complitexpr:
+	expr
+	{
+		// These nodes do not carry line numbers.
+		// Since a composite literal commonly spans several lines,
+		// the line number on errors may be misleading.
+		// Introduce a wrapper node to give the correct line.
+		$$ = $1;
+		switch($$.Op) {
+		case ONAME, ONONAME, OTYPE, OPACK, OLITERAL:
+			$$ = Nod(OPAREN, $$, nil);
+			$$.Implicit = true;
+		}
+	}
+|	'{' start_complit braced_keyval_list '}'
+	{
+		$$ = $2;
+		$$.List = $3;
+	}
+
+complitexpr:
+	expr
+|	'{' start_complit braced_keyval_list '}'
+	{
+		$$ = $2;
+		$$.List = $3;
+	}
+
+pexpr:
+	pexpr_no_paren
+|	'(' expr_or_type ')'
+	{
+		$$ = $2;
+		
+		// Need to know on lhs of := whether there are ( ).
+		// Don't bother with the OPAREN in other cases:
+		// it's just a waste of memory and time.
+		switch($$.Op) {
+		case ONAME, ONONAME, OPACK, OTYPE, OLITERAL, OTYPESW:
+			$$ = Nod(OPAREN, $$, nil);
+		}
+	}
+
+expr_or_type:
+	expr
+|	non_expr_type	%prec PreferToRightParen
+
+name_or_type:
+	ntype
+
+lbrace:
+	LBODY
+	{
+		$$ = LBODY;
+	}
+|	'{'
+	{
+		$$ = '{';
+	}
+
+/*
+ * names and types
+ *	newname is used before declared
+ *	oldname is used after declared
+ */
+new_name:
+	sym
+	{
+		if $1 == nil {
+			$$ = nil;
+		} else {
+			$$ = newname($1);
+		}
+	}
+
+dcl_name:
+	sym
+	{
+		$$ = dclname($1);
+	}
+
+onew_name:
+	{
+		$$ = nil;
+	}
+|	new_name
+
+sym:
+	LNAME
+	{
+		$$ = $1;
+		// during imports, unqualified non-exported identifiers are from builtinpkg
+		if importpkg != nil && !exportname($1.Name) {
+			$$ = Pkglookup($1.Name, builtinpkg);
+		}
+	}
+|	hidden_importsym
+|	'?'
+	{
+		$$ = nil;
+	}
+
+hidden_importsym:
+	'@' LLITERAL '.' LNAME
+	{
+		var p *Pkg
+
+		if $2.U.(string) == "" {
+			p = importpkg;
+		} else {
+			if isbadimport($2.U.(string)) {
+				errorexit();
+			}
+			p = mkpkg($2.U.(string));
+		}
+		$$ = Pkglookup($4.Name, p);
+	}
+|	'@' LLITERAL '.' '?'
+	{
+		var p *Pkg
+
+		if $2.U.(string) == "" {
+			p = importpkg;
+		} else {
+			if isbadimport($2.U.(string)) {
+				errorexit();
+			}
+			p = mkpkg($2.U.(string));
+		}
+		$$ = Pkglookup("?", p);
+	}
+
+name:
+	sym	%prec NotParen
+	{
+		$$ = oldname($1);
+		if $$.Name != nil && $$.Name.Pack != nil {
+			$$.Name.Pack.Used = true;
+		}
+	}
+
+labelname:
+	new_name
+
+/*
+ * to avoid parsing conflicts, type is split into
+ *	channel types
+ *	function types
+ *	parenthesized types
+ *	any other type
+ * the type system makes additional restrictions,
+ * but those are not implemented in the grammar.
+ */
+dotdotdot:
+	LDDD
+	{
+		Yyerror("final argument in variadic function missing type");
+		$$ = Nod(ODDD, typenod(typ(TINTER)), nil);
+	}
+|	LDDD ntype
+	{
+		$$ = Nod(ODDD, $2, nil);
+	}
+
+ntype:
+	recvchantype
+|	fntype
+|	othertype
+|	ptrtype
+|	dotname
+|	'(' ntype ')'
+	{
+		$$ = $2;
+	}
+
+non_expr_type:
+	recvchantype
+|	fntype
+|	othertype
+|	'*' non_expr_type
+	{
+		$$ = Nod(OIND, $2, nil);
+	}
+
+non_recvchantype:
+	fntype
+|	othertype
+|	ptrtype
+|	dotname
+|	'(' ntype ')'
+	{
+		$$ = $2;
+	}
+
+convtype:
+	fntype
+|	othertype
+
+comptype:
+	othertype
+
+fnret_type:
+	recvchantype
+|	fntype
+|	othertype
+|	ptrtype
+|	dotname
+
+dotname:
+	name
+|	name '.' sym
+	{
+		if $1.Op == OPACK {
+			var s *Sym
+			s = restrictlookup($3.Name, $1.Name.Pkg);
+			$1.Used = true;
+			$$ = oldname(s);
+			break;
+		}
+		$$ = Nod(OXDOT, $1, newname($3));
+	}
+
+othertype:
+	'[' oexpr ']' ntype
+	{
+		$$ = Nod(OTARRAY, $2, $4);
+	}
+|	'[' LDDD ']' ntype
+	{
+		// array literal of nelem
+		$$ = Nod(OTARRAY, Nod(ODDD, nil, nil), $4);
+	}
+|	LCHAN non_recvchantype
+	{
+		$$ = Nod(OTCHAN, $2, nil);
+		$$.Etype = Cboth;
+	}
+|	LCHAN LCOMM ntype
+	{
+		$$ = Nod(OTCHAN, $3, nil);
+		$$.Etype = Csend;
+	}
+|	LMAP '[' ntype ']' ntype
+	{
+		$$ = Nod(OTMAP, $3, $5);
+	}
+|	structtype
+|	interfacetype
+
+ptrtype:
+	'*' ntype
+	{
+		$$ = Nod(OIND, $2, nil);
+	}
+
+recvchantype:
+	LCOMM LCHAN ntype
+	{
+		$$ = Nod(OTCHAN, $3, nil);
+		$$.Etype = Crecv;
+	}
+
+structtype:
+	LSTRUCT lbrace structdcl_list osemi '}'
+	{
+		$$ = Nod(OTSTRUCT, nil, nil);
+		$$.List = $3;
+		fixlbrace($2);
+	}
+|	LSTRUCT lbrace '}'
+	{
+		$$ = Nod(OTSTRUCT, nil, nil);
+		fixlbrace($2);
+	}
+
+interfacetype:
+	LINTERFACE lbrace interfacedcl_list osemi '}'
+	{
+		$$ = Nod(OTINTER, nil, nil);
+		$$.List = $3;
+		fixlbrace($2);
+	}
+|	LINTERFACE lbrace '}'
+	{
+		$$ = Nod(OTINTER, nil, nil);
+		fixlbrace($2);
+	}
+
+/*
+ * function stuff
+ * all in one place to show how crappy it all is
+ */
+xfndcl:
+	LFUNC fndcl fnbody
+	{
+		$$ = $2;
+		if $$ == nil {
+			break;
+		}
+		if noescape && $3 != nil {
+			Yyerror("can only use //go:noescape with external func implementations");
+		}
+		$$.Nbody = $3;
+		$$.Func.Endlineno = lineno;
+		$$.Noescape = noescape;
+		$$.Func.Norace = norace;
+		$$.Func.Nosplit = nosplit;
+		$$.Func.Nowritebarrier = nowritebarrier;
+		$$.Func.Systemstack = systemstack;
+		funcbody($$);
+	}
+
+fndcl:
+	sym '(' oarg_type_list_ocomma ')' fnres
+	{
+		var t *Node
+
+		$$ = nil;
+		$3 = checkarglist($3, 1);
+
+		if $1.Name == "init" {
+			$1 = renameinit();
+			if $3 != nil || $5 != nil {
+				Yyerror("func init must have no arguments and no return values");
+			}
+		}
+		if localpkg.Name == "main" && $1.Name == "main" {
+			if $3 != nil || $5 != nil {
+				Yyerror("func main must have no arguments and no return values");
+			}
+		}
+
+		t = Nod(OTFUNC, nil, nil);
+		t.List = $3;
+		t.Rlist = $5;
+
+		$$ = Nod(ODCLFUNC, nil, nil);
+		$$.Func.Nname = newfuncname($1);
+		$$.Func.Nname.Name.Defn = $$;
+		$$.Func.Nname.Name.Param.Ntype = t;		// TODO: check if nname already has an ntype
+		declare($$.Func.Nname, PFUNC);
+
+		funchdr($$);
+	}
+|	'(' oarg_type_list_ocomma ')' sym '(' oarg_type_list_ocomma ')' fnres
+	{
+		var rcvr, t *Node
+
+		$$ = nil;
+		$2 = checkarglist($2, 0);
+		$6 = checkarglist($6, 1);
+
+		if $2 == nil {
+			Yyerror("method has no receiver");
+			break;
+		}
+		if $2.Next != nil {
+			Yyerror("method has multiple receivers");
+			break;
+		}
+		rcvr = $2.N;
+		if rcvr.Op != ODCLFIELD {
+			Yyerror("bad receiver in method");
+			break;
+		}
+
+		t = Nod(OTFUNC, rcvr, nil);
+		t.List = $6;
+		t.Rlist = $8;
+
+		$$ = Nod(ODCLFUNC, nil, nil);
+		$$.Func.Shortname = newfuncname($4);
+		$$.Func.Nname = methodname1($$.Func.Shortname, rcvr.Right);
+		$$.Func.Nname.Name.Defn = $$;
+		$$.Func.Nname.Name.Param.Ntype = t;
+		$$.Func.Nname.Nointerface = nointerface;
+		declare($$.Func.Nname, PFUNC);
+
+		funchdr($$);
+	}
+
+hidden_fndcl:
+	hidden_pkg_importsym '(' ohidden_funarg_list ')' ohidden_funres
+	{
+		var s *Sym
+		var t *Type
+
+		$$ = nil;
+
+		s = $1;
+		t = functype(nil, $3, $5);
+
+		importsym(s, ONAME);
+		if s.Def != nil && s.Def.Op == ONAME {
+			if Eqtype(t, s.Def.Type) {
+				dclcontext = PDISCARD;  // since we skip funchdr below
+				break;
+			}
+			Yyerror("inconsistent definition for func %v during import\n\t%v\n\t%v", s, s.Def.Type, t);
+		}
+
+		$$ = newfuncname(s);
+		$$.Type = t;
+		declare($$, PFUNC);
+
+		funchdr($$);
+	}
+|	'(' hidden_funarg_list ')' sym '(' ohidden_funarg_list ')' ohidden_funres
+	{
+		$$ = methodname1(newname($4), $2.N.Right); 
+		$$.Type = functype($2.N, $6, $8);
+
+		checkwidth($$.Type);
+		addmethod($4, $$.Type, false, nointerface);
+		nointerface = false
+		funchdr($$);
+		
+		// inl.C's inlnode in on a dotmeth node expects to find the inlineable body as
+		// (dotmeth's type).Nname.Inl, and dotmeth's type has been pulled
+		// out by typecheck's lookdot as this $$.ttype.  So by providing
+		// this back link here we avoid special casing there.
+		$$.Type.Nname = $$;
+	}
+
+fntype:
+	LFUNC '(' oarg_type_list_ocomma ')' fnres
+	{
+		$3 = checkarglist($3, 1);
+		$$ = Nod(OTFUNC, nil, nil);
+		$$.List = $3;
+		$$.Rlist = $5;
+	}
+
+fnbody:
+	{
+		$$ = nil;
+	}
+|	'{' stmt_list '}'
+	{
+		$$ = $2;
+		if $$ == nil {
+			$$ = list1(Nod(OEMPTY, nil, nil));
+		}
+	}
+
+fnres:
+	%prec NotParen
+	{
+		$$ = nil;
+	}
+|	fnret_type
+	{
+		$$ = list1(Nod(ODCLFIELD, nil, $1));
+	}
+|	'(' oarg_type_list_ocomma ')'
+	{
+		$2 = checkarglist($2, 0);
+		$$ = $2;
+	}
+
+fnlitdcl:
+	fntype
+	{
+		closurehdr($1);
+	}
+
+fnliteral:
+	fnlitdcl lbrace stmt_list '}'
+	{
+		$$ = closurebody($3);
+		fixlbrace($2);
+	}
+|	fnlitdcl error
+	{
+		$$ = closurebody(nil);
+	}
+
+/*
+ * lists of things
+ * note that they are left recursive
+ * to conserve yacc stack. they need to
+ * be reversed to interpret correctly
+ */
+xdcl_list:
+	{
+		$$ = nil;
+	}
+|	xdcl_list xdcl ';'
+	{
+		$$ = concat($1, $2);
+		if nsyntaxerrors == 0 {
+			testdclstack();
+		}
+		nointerface = false
+		noescape = false
+		norace = false
+		nosplit = false
+		nowritebarrier = false
+		systemstack = false
+	}
+
+vardcl_list:
+	vardcl
+|	vardcl_list ';' vardcl
+	{
+		$$ = concat($1, $3);
+	}
+
+constdcl_list:
+	constdcl1
+|	constdcl_list ';' constdcl1
+	{
+		$$ = concat($1, $3);
+	}
+
+typedcl_list:
+	typedcl
+	{
+		$$ = list1($1);
+	}
+|	typedcl_list ';' typedcl
+	{
+		$$ = list($1, $3);
+	}
+
+structdcl_list:
+	structdcl
+|	structdcl_list ';' structdcl
+	{
+		$$ = concat($1, $3);
+	}
+
+interfacedcl_list:
+	interfacedcl
+	{
+		$$ = list1($1);
+	}
+|	interfacedcl_list ';' interfacedcl
+	{
+		$$ = list($1, $3);
+	}
+
+structdcl:
+	new_name_list ntype oliteral
+	{
+		var l *NodeList
+
+		var n *Node
+		l = $1;
+		if l == nil || l.N.Sym.Name == "?" {
+			// ? symbol, during import (list1(nil) == nil)
+			n = $2;
+			if n.Op == OIND {
+				n = n.Left;
+			}
+			n = embedded(n.Sym, importpkg);
+			n.Right = $2;
+			n.SetVal($3)
+			$$ = list1(n);
+			break;
+		}
+
+		for l=$1; l != nil; l=l.Next {
+			l.N = Nod(ODCLFIELD, l.N, $2);
+			l.N.SetVal($3)
+		}
+	}
+|	embed oliteral
+	{
+		$1.SetVal($2)
+		$$ = list1($1);
+	}
+|	'(' embed ')' oliteral
+	{
+		$2.SetVal($4)
+		$$ = list1($2);
+		Yyerror("cannot parenthesize embedded type");
+	}
+|	'*' embed oliteral
+	{
+		$2.Right = Nod(OIND, $2.Right, nil);
+		$2.SetVal($3)
+		$$ = list1($2);
+	}
+|	'(' '*' embed ')' oliteral
+	{
+		$3.Right = Nod(OIND, $3.Right, nil);
+		$3.SetVal($5)
+		$$ = list1($3);
+		Yyerror("cannot parenthesize embedded type");
+	}
+|	'*' '(' embed ')' oliteral
+	{
+		$3.Right = Nod(OIND, $3.Right, nil);
+		$3.SetVal($5)
+		$$ = list1($3);
+		Yyerror("cannot parenthesize embedded type");
+	}
+
+packname:
+	LNAME
+	{
+		var n *Node
+
+		$$ = $1;
+		n = oldname($1);
+		if n.Name != nil && n.Name.Pack != nil {
+			n.Name.Pack.Used = true;
+		}
+	}
+|	LNAME '.' sym
+	{
+		var pkg *Pkg
+
+		if $1.Def == nil || $1.Def.Op != OPACK {
+			Yyerror("%v is not a package", $1);
+			pkg = localpkg;
+		} else {
+			$1.Def.Used = true;
+			pkg = $1.Def.Name.Pkg;
+		}
+		$$ = restrictlookup($3.Name, pkg);
+	}
+
+embed:
+	packname
+	{
+		$$ = embedded($1, localpkg);
+	}
+
+interfacedcl:
+	new_name indcl
+	{
+		$$ = Nod(ODCLFIELD, $1, $2);
+		ifacedcl($$);
+	}
+|	packname
+	{
+		$$ = Nod(ODCLFIELD, nil, oldname($1));
+	}
+|	'(' packname ')'
+	{
+		$$ = Nod(ODCLFIELD, nil, oldname($2));
+		Yyerror("cannot parenthesize embedded type");
+	}
+
+indcl:
+	'(' oarg_type_list_ocomma ')' fnres
+	{
+		// without func keyword
+		$2 = checkarglist($2, 1);
+		$$ = Nod(OTFUNC, fakethis(), nil);
+		$$.List = $2;
+		$$.Rlist = $4;
+	}
+
+/*
+ * function arguments.
+ */
+arg_type:
+	name_or_type
+|	sym name_or_type
+	{
+		$$ = Nod(ONONAME, nil, nil);
+		$$.Sym = $1;
+		$$ = Nod(OKEY, $$, $2);
+	}
+|	sym dotdotdot
+	{
+		$$ = Nod(ONONAME, nil, nil);
+		$$.Sym = $1;
+		$$ = Nod(OKEY, $$, $2);
+	}
+|	dotdotdot
+
+arg_type_list:
+	arg_type
+	{
+		$$ = list1($1);
+	}
+|	arg_type_list ',' arg_type
+	{
+		$$ = list($1, $3);
+	}
+
+oarg_type_list_ocomma:
+	{
+		$$ = nil;
+	}
+|	arg_type_list ocomma
+	{
+		$$ = $1;
+	}
+
+/*
+ * statement
+ */
+stmt:
+	{
+		$$ = nil;
+	}
+|	compound_stmt
+|	common_dcl
+	{
+		$$ = liststmt($1);
+	}
+|	non_dcl_stmt
+|	error
+	{
+		$$ = nil;
+	}
+
+non_dcl_stmt:
+	simple_stmt
+|	for_stmt
+|	switch_stmt
+|	select_stmt
+|	if_stmt
+|	labelname ':'
+	{
+		$1 = Nod(OLABEL, $1, nil);
+		$1.Sym = dclstack;  // context, for goto restrictions
+	}
+	stmt
+	{
+		var l *NodeList
+
+		$1.Name.Defn = $4;
+		l = list1($1);
+		if $4 != nil {
+			l = list(l, $4);
+		}
+		$$ = liststmt(l);
+	}
+|	LFALL
+	{
+		// will be converted to OFALL
+		$$ = Nod(OXFALL, nil, nil);
+		$$.Xoffset = int64(block);
+	}
+|	LBREAK onew_name
+	{
+		$$ = Nod(OBREAK, $2, nil);
+	}
+|	LCONTINUE onew_name
+	{
+		$$ = Nod(OCONTINUE, $2, nil);
+	}
+|	LGO pseudocall
+	{
+		$$ = Nod(OPROC, $2, nil);
+	}
+|	LDEFER pseudocall
+	{
+		$$ = Nod(ODEFER, $2, nil);
+	}
+|	LGOTO new_name
+	{
+		$$ = Nod(OGOTO, $2, nil);
+		$$.Sym = dclstack;  // context, for goto restrictions
+	}
+|	LRETURN oexpr_list
+	{
+		$$ = Nod(ORETURN, nil, nil);
+		$$.List = $2;
+		if $$.List == nil && Curfn != nil {
+			var l *NodeList
+
+			for l=Curfn.Func.Dcl; l != nil; l=l.Next {
+				if l.N.Class == PPARAM {
+					continue;
+				}
+				if l.N.Class != PPARAMOUT {
+					break;
+				}
+				if l.N.Sym.Def != l.N {
+					Yyerror("%s is shadowed during return", l.N.Sym.Name);
+				}
+			}
+		}
+	}
+
+stmt_list:
+	stmt
+	{
+		$$ = nil;
+		if $1 != nil {
+			$$ = list1($1);
+		}
+	}
+|	stmt_list ';' stmt
+	{
+		$$ = $1;
+		if $3 != nil {
+			$$ = list($$, $3);
+		}
+	}
+
+new_name_list:
+	new_name
+	{
+		$$ = list1($1);
+	}
+|	new_name_list ',' new_name
+	{
+		$$ = list($1, $3);
+	}
+
+dcl_name_list:
+	dcl_name
+	{
+		$$ = list1($1);
+	}
+|	dcl_name_list ',' dcl_name
+	{
+		$$ = list($1, $3);
+	}
+
+expr_list:
+	expr
+	{
+		$$ = list1($1);
+	}
+|	expr_list ',' expr
+	{
+		$$ = list($1, $3);
+	}
+
+expr_or_type_list:
+	expr_or_type
+	{
+		$$ = list1($1);
+	}
+|	expr_or_type_list ',' expr_or_type
+	{
+		$$ = list($1, $3);
+	}
+
+/*
+ * list of combo of keyval and val
+ */
+keyval_list:
+	keyval
+	{
+		$$ = list1($1);
+	}
+|	bare_complitexpr
+	{
+		$$ = list1($1);
+	}
+|	keyval_list ',' keyval
+	{
+		$$ = list($1, $3);
+	}
+|	keyval_list ',' bare_complitexpr
+	{
+		$$ = list($1, $3);
+	}
+
+braced_keyval_list:
+	{
+		$$ = nil;
+	}
+|	keyval_list ocomma
+	{
+		$$ = $1;
+	}
+
+/*
+ * optional things
+ */
+osemi:
+|	';'
+
+ocomma:
+|	','
+
+oexpr:
+	{
+		$$ = nil;
+	}
+|	expr
+
+oexpr_list:
+	{
+		$$ = nil;
+	}
+|	expr_list
+
+osimple_stmt:
+	{
+		$$ = nil;
+	}
+|	simple_stmt
+
+ohidden_funarg_list:
+	{
+		$$ = nil;
+	}
+|	hidden_funarg_list
+
+ohidden_structdcl_list:
+	{
+		$$ = nil;
+	}
+|	hidden_structdcl_list
+
+ohidden_interfacedcl_list:
+	{
+		$$ = nil;
+	}
+|	hidden_interfacedcl_list
+
+oliteral:
+	{
+		$$.U = nil
+	}
+|	LLITERAL
+
+/*
+ * import syntax from package header
+ */
+hidden_import:
+	LIMPORT LNAME LLITERAL ';'
+	{
+		importimport($2, $3.U.(string));
+	}
+|	LVAR hidden_pkg_importsym hidden_type ';'
+	{
+		importvar($2, $3);
+	}
+|	LCONST hidden_pkg_importsym '=' hidden_constant ';'
+	{
+		importconst($2, Types[TIDEAL], $4);
+	}
+|	LCONST hidden_pkg_importsym hidden_type '=' hidden_constant ';'
+	{
+		importconst($2, $3, $5);
+	}
+|	LTYPE hidden_pkgtype hidden_type ';'
+	{
+		importtype($2, $3);
+	}
+|	LFUNC hidden_fndcl fnbody ';'
+	{
+		if $2 == nil {
+			dclcontext = PEXTERN;  // since we skip the funcbody below
+			break;
+		}
+
+		$2.Func.Inl = $3;
+
+		funcbody($2);
+		importlist = list(importlist, $2);
+
+		if Debug['E'] > 0 {
+			fmt.Printf("import [%q] func %v \n", importpkg.Path, $2)
+			if Debug['m'] > 2 && $2.Func.Inl != nil {
+				fmt.Printf("inl body:%v\n", $2.Func.Inl)
+			}
+		}
+	}
+
+hidden_pkg_importsym:
+	hidden_importsym
+	{
+		$$ = $1;
+		structpkg = $$.Pkg;
+	}
+
+hidden_pkgtype:
+	hidden_pkg_importsym
+	{
+		$$ = pkgtype($1);
+		importsym($1, OTYPE);
+	}
+
+/*
+ *  importing types
+ */
+
+hidden_type:
+	hidden_type_misc
+|	hidden_type_recv_chan
+|	hidden_type_func
+
+hidden_type_non_recv_chan:
+	hidden_type_misc
+|	hidden_type_func
+
+hidden_type_misc:
+	hidden_importsym
+	{
+		$$ = pkgtype($1);
+	}
+|	LNAME
+	{
+		// predefined name like uint8
+		$1 = Pkglookup($1.Name, builtinpkg);
+		if $1.Def == nil || $1.Def.Op != OTYPE {
+			Yyerror("%s is not a type", $1.Name);
+			$$ = nil;
+		} else {
+			$$ = $1.Def.Type;
+		}
+	}
+|	'[' ']' hidden_type
+	{
+		$$ = aindex(nil, $3);
+	}
+|	'[' LLITERAL ']' hidden_type
+	{
+		$$ = aindex(nodlit($2), $4);
+	}
+|	LMAP '[' hidden_type ']' hidden_type
+	{
+		$$ = maptype($3, $5);
+	}
+|	LSTRUCT '{' ohidden_structdcl_list '}'
+	{
+		$$ = tostruct($3);
+	}
+|	LINTERFACE '{' ohidden_interfacedcl_list '}'
+	{
+		$$ = tointerface($3);
+	}
+|	'*' hidden_type
+	{
+		$$ = Ptrto($2);
+	}
+|	LCHAN hidden_type_non_recv_chan
+	{
+		$$ = typ(TCHAN);
+		$$.Type = $2;
+		$$.Chan = Cboth;
+	}
+|	LCHAN '(' hidden_type_recv_chan ')'
+	{
+		$$ = typ(TCHAN);
+		$$.Type = $3;
+		$$.Chan = Cboth;
+	}
+|	LCHAN LCOMM hidden_type
+	{
+		$$ = typ(TCHAN);
+		$$.Type = $3;
+		$$.Chan = Csend;
+	}
+
+hidden_type_recv_chan:
+	LCOMM LCHAN hidden_type
+	{
+		$$ = typ(TCHAN);
+		$$.Type = $3;
+		$$.Chan = Crecv;
+	}
+
+hidden_type_func:
+	LFUNC '(' ohidden_funarg_list ')' ohidden_funres
+	{
+		$$ = functype(nil, $3, $5);
+	}
+
+hidden_funarg:
+	sym hidden_type oliteral
+	{
+		$$ = Nod(ODCLFIELD, nil, typenod($2));
+		if $1 != nil {
+			$$.Left = newname($1);
+		}
+		$$.SetVal($3)
+	}
+|	sym LDDD hidden_type oliteral
+	{
+		var t *Type
+	
+		t = typ(TARRAY);
+		t.Bound = -1;
+		t.Type = $3;
+
+		$$ = Nod(ODCLFIELD, nil, typenod(t));
+		if $1 != nil {
+			$$.Left = newname($1);
+		}
+		$$.Isddd = true;
+		$$.SetVal($4)
+	}
+
+hidden_structdcl:
+	sym hidden_type oliteral
+	{
+		var s *Sym
+		var p *Pkg
+
+		if $1 != nil && $1.Name != "?" {
+			$$ = Nod(ODCLFIELD, newname($1), typenod($2));
+			$$.SetVal($3)
+		} else {
+			s = $2.Sym;
+			if s == nil && Isptr[$2.Etype] {
+				s = $2.Type.Sym;
+			}
+			p = importpkg;
+			if $1 != nil {
+				p = $1.Pkg;
+			}
+			$$ = embedded(s, p);
+			$$.Right = typenod($2);
+			$$.SetVal($3)
+		}
+	}
+
+hidden_interfacedcl:
+	sym '(' ohidden_funarg_list ')' ohidden_funres
+	{
+		$$ = Nod(ODCLFIELD, newname($1), typenod(functype(fakethis(), $3, $5)));
+	}
+|	hidden_type
+	{
+		$$ = Nod(ODCLFIELD, nil, typenod($1));
+	}
+
+ohidden_funres:
+	{
+		$$ = nil;
+	}
+|	hidden_funres
+
+hidden_funres:
+	'(' ohidden_funarg_list ')'
+	{
+		$$ = $2;
+	}
+|	hidden_type
+	{
+		$$ = list1(Nod(ODCLFIELD, nil, typenod($1)));
+	}
+
+/*
+ *  importing constants
+ */
+
+hidden_literal:
+	LLITERAL
+	{
+		$$ = nodlit($1);
+	}
+|	'-' LLITERAL
+	{
+		$$ = nodlit($2);
+		switch($$.Val().Ctype()){
+		case CTINT, CTRUNE:
+			mpnegfix($$.Val().U.(*Mpint));
+			break;
+		case CTFLT:
+			mpnegflt($$.Val().U.(*Mpflt));
+			break;
+		case CTCPLX:
+			mpnegflt(&$$.Val().U.(*Mpcplx).Real);
+			mpnegflt(&$$.Val().U.(*Mpcplx).Imag);
+			break;
+		default:
+			Yyerror("bad negated constant");
+		}
+	}
+|	sym
+	{
+		$$ = oldname(Pkglookup($1.Name, builtinpkg));
+		if $$.Op != OLITERAL {
+			Yyerror("bad constant %v", $$.Sym);
+		}
+	}
+
+hidden_constant:
+	hidden_literal
+|	'(' hidden_literal '+' hidden_literal ')'
+	{
+		if $2.Val().Ctype() == CTRUNE && $4.Val().Ctype() == CTINT {
+			$$ = $2;
+			mpaddfixfix($2.Val().U.(*Mpint), $4.Val().U.(*Mpint), 0);
+			break;
+		}
+		$4.Val().U.(*Mpcplx).Real = $4.Val().U.(*Mpcplx).Imag;
+		Mpmovecflt(&$4.Val().U.(*Mpcplx).Imag, 0.0);
+		$$ = nodcplxlit($2.Val(), $4.Val());
+	}
+
+hidden_import_list:
+|	hidden_import_list hidden_import
+
+hidden_funarg_list:
+	hidden_funarg
+	{
+		$$ = list1($1);
+	}
+|	hidden_funarg_list ',' hidden_funarg
+	{
+		$$ = list($1, $3);
+	}
+
+hidden_structdcl_list:
+	hidden_structdcl
+	{
+		$$ = list1($1);
+	}
+|	hidden_structdcl_list ';' hidden_structdcl
+	{
+		$$ = list($1, $3);
+	}
+
+hidden_interfacedcl_list:
+	hidden_interfacedcl
+	{
+		$$ = list1($1);
+	}
+|	hidden_interfacedcl_list ';' hidden_interfacedcl
+	{
+		$$ = list($1, $3);
+	}
+
+%%
+func fixlbrace(lbr int) {
+	// If the opening brace was an LBODY,
+	// set up for another one now that we're done.
+	// See comment in lex.C about loophack.
+	if lbr == LBODY {
+		loophack = 1
+	}
+}
diff --git a/src/cmd/compile/internal/gc/gsubr.go b/src/cmd/compile/internal/gc/gsubr.go
new file mode 100644
index 0000000..2c575f3
--- /dev/null
+++ b/src/cmd/compile/internal/gc/gsubr.go
@@ -0,0 +1,836 @@
+// 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 at 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 at 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"
+	"runtime"
+	"strings"
+)
+
+var ddumped int
+
+var dfirst *obj.Prog
+
+var dpc *obj.Prog
+
+/*
+ * Is this node a memory operand?
+ */
+func Ismem(n *Node) bool {
+	switch n.Op {
+	case OITAB,
+		OSPTR,
+		OLEN,
+		OCAP,
+		OINDREG,
+		ONAME,
+		OPARAM,
+		OCLOSUREVAR:
+		return true
+
+	case OADDR:
+		return Thearch.Thechar == '6' || Thearch.Thechar == '9' // because 6g uses PC-relative addressing; TODO(rsc): not sure why 9g too
+	}
+
+	return false
+}
+
+func Samereg(a *Node, b *Node) bool {
+	if a == nil || b == nil {
+		return false
+	}
+	if a.Op != OREGISTER {
+		return false
+	}
+	if b.Op != OREGISTER {
+		return false
+	}
+	if a.Reg != b.Reg {
+		return false
+	}
+	return true
+}
+
+func Gbranch(as int, t *Type, likely int) *obj.Prog {
+	p := Prog(as)
+	p.To.Type = obj.TYPE_BRANCH
+	p.To.Val = nil
+	if as != obj.AJMP && likely != 0 && Thearch.Thechar != '9' && Thearch.Thechar != '7' {
+		p.From.Type = obj.TYPE_CONST
+		p.From.Offset = int64(obj.Bool2int(likely > 0))
+	}
+
+	if Debug['g'] != 0 {
+		fmt.Printf("%v\n", p)
+	}
+
+	return p
+}
+
+func Prog(as int) *obj.Prog {
+	var p *obj.Prog
+
+	if as == obj.ADATA || as == obj.AGLOBL {
+		if ddumped != 0 {
+			Fatal("already dumped data")
+		}
+		if dpc == nil {
+			dpc = Ctxt.NewProg()
+			dfirst = dpc
+		}
+
+		p = dpc
+		dpc = Ctxt.NewProg()
+		p.Link = dpc
+	} else {
+		p = Pc
+		Pc = Ctxt.NewProg()
+		Clearp(Pc)
+		p.Link = Pc
+	}
+
+	if lineno == 0 {
+		if Debug['K'] != 0 {
+			Warn("prog: line 0")
+		}
+	}
+
+	p.As = int16(as)
+	p.Lineno = lineno
+	return p
+}
+
+func Nodreg(n *Node, t *Type, r int) {
+	if t == nil {
+		Fatal("nodreg: t nil")
+	}
+
+	*n = Node{}
+	n.Op = OREGISTER
+	n.Addable = true
+	ullmancalc(n)
+	n.Reg = int16(r)
+	n.Type = t
+}
+
+func Nodindreg(n *Node, t *Type, r int) {
+	Nodreg(n, t, r)
+	n.Op = OINDREG
+}
+
+func Afunclit(a *obj.Addr, n *Node) {
+	if a.Type == obj.TYPE_ADDR && a.Name == obj.NAME_EXTERN {
+		a.Type = obj.TYPE_MEM
+		a.Sym = Linksym(n.Sym)
+	}
+}
+
+func Clearp(p *obj.Prog) {
+	obj.Nopout(p)
+	p.As = obj.AEND
+	p.Pc = int64(pcloc)
+	pcloc++
+}
+
+func dumpdata() {
+	ddumped = 1
+	if dfirst == nil {
+		return
+	}
+	newplist()
+	*Pc = *dfirst
+	Pc = dpc
+	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 {
+			*lp = p.Link
+			continue
+		}
+
+		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
+			// the no-ops.
+			obj.Nopout(p)
+
+			continue
+		}
+
+		if p.From.Name == obj.NAME_AUTO && p.From.Node != nil {
+			p.From.Offset += stkdelta[p.From.Node.(*Node)]
+		}
+
+		if p.To.Name == obj.NAME_AUTO && p.To.Node != nil {
+			p.To.Offset += stkdelta[p.To.Node.(*Node)]
+		}
+
+		lp = &p.Link
+	}
+}
+
+func ggloblnod(nam *Node) {
+	p := Thearch.Gins(obj.AGLOBL, nam, nil)
+	p.Lineno = nam.Lineno
+	p.From.Sym.Gotype = Linksym(ngotype(nam))
+	p.To.Sym = nil
+	p.To.Type = obj.TYPE_CONST
+	p.To.Offset = nam.Type.Width
+	p.From3 = new(obj.Addr)
+	if nam.Name.Readonly {
+		p.From3.Offset = obj.RODATA
+	}
+	if nam.Type != nil && !haspointers(nam.Type) {
+		p.From3.Offset |= obj.NOPTR
+	}
+}
+
+func ggloblsym(s *Sym, width int32, flags int16) {
+	p := Thearch.Gins(obj.AGLOBL, nil, nil)
+	p.From.Type = obj.TYPE_MEM
+	p.From.Name = obj.NAME_EXTERN
+	p.From.Sym = Linksym(s)
+	if flags&obj.LOCAL != 0 {
+		p.From.Sym.Local = true
+		flags &= ^obj.LOCAL
+	}
+	p.To.Type = obj.TYPE_CONST
+	p.To.Offset = int64(width)
+	p.From3 = new(obj.Addr)
+	p.From3.Offset = int64(flags)
+}
+
+func gjmp(to *obj.Prog) *obj.Prog {
+	p := Gbranch(obj.AJMP, nil, 0)
+	if to != nil {
+		Patch(p, to)
+	}
+	return p
+}
+
+func gtrack(s *Sym) {
+	p := Thearch.Gins(obj.AUSEFIELD, nil, nil)
+	p.From.Type = obj.TYPE_MEM
+	p.From.Name = obj.NAME_EXTERN
+	p.From.Sym = Linksym(s)
+}
+
+func gused(n *Node) {
+	Thearch.Gins(obj.ANOP, n, nil) // used
+}
+
+func Isfat(t *Type) bool {
+	if t != nil {
+		switch t.Etype {
+		case TSTRUCT, TARRAY, TSTRING,
+			TINTER: // maybe remove later
+			return true
+		}
+	}
+
+	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 {
+			continue
+		}
+
+		if p.From.Node != nil {
+			((p.From.Node).(*Node)).Used = true
+		}
+
+		if p.To.Node != nil {
+			((p.To.Node).(*Node)).Used = true
+		}
+	}
+}
+
+// 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
+	}
+
+	if n.Type != nil && n.Type.Etype != TIDEAL {
+		// TODO(rsc): This is undone by the selective clearing of width below,
+		// to match architectures that were not as aggressive in setting width
+		// during naddr. Those widths must be cleared to avoid triggering
+		// failures in gins when it detects real but heretofore latent (and one
+		// hopes innocuous) type mismatches.
+		// The type mismatches should be fixed and the clearing below removed.
+		dowidth(n.Type)
+
+		a.Width = n.Type.Width
+	}
+
+	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:
+		a.Type = obj.TYPE_REG
+		a.Reg = n.Reg
+		a.Sym = nil
+		if Thearch.Thechar == '8' { // TODO(rsc): Never clear a->width.
+			a.Width = 0
+		}
+
+	case OINDREG:
+		a.Type = obj.TYPE_MEM
+		a.Reg = n.Reg
+		a.Sym = Linksym(n.Sym)
+		a.Offset = n.Xoffset
+		if a.Offset != int64(int32(a.Offset)) {
+			Yyerror("offset %d too large for OINDREG", a.Offset)
+		}
+		if Thearch.Thechar == '8' { // TODO(rsc): Never clear a->width.
+			a.Width = 0
+		}
+
+		// n->left is PHEAP ONAME for stack parameter.
+	// compute address of actual parameter on stack.
+	case OPARAM:
+		a.Etype = Simtype[n.Left.Type.Etype]
+
+		a.Width = n.Left.Type.Width
+		a.Offset = n.Xoffset
+		a.Sym = Linksym(n.Left.Sym)
+		a.Type = obj.TYPE_MEM
+		a.Name = obj.NAME_PARAM
+		a.Node = n.Left.Orig
+
+	case OCLOSUREVAR:
+		if !Curfn.Func.Needctxt {
+			Fatal("closurevar without needctxt")
+		}
+		a.Type = obj.TYPE_MEM
+		a.Reg = int16(Thearch.REGCTXT)
+		a.Sym = nil
+		a.Offset = n.Xoffset
+
+	case OCFUNC:
+		Naddr(a, n.Left)
+		a.Sym = Linksym(n.Left.Sym)
+
+	case ONAME:
+		a.Etype = 0
+		if n.Type != nil {
+			a.Etype = Simtype[n.Type.Etype]
+		}
+		a.Offset = n.Xoffset
+		s := n.Sym
+		a.Node = n.Orig
+
+		//if(a->node >= (Node*)&n)
+		//	fatal("stack node");
+		if s == nil {
+			s = Lookup(".noname")
+		}
+		if n.Name.Method {
+			if n.Type != nil {
+				if n.Type.Sym != nil {
+					if n.Type.Sym.Pkg != nil {
+						s = Pkglookup(s.Name, n.Type.Sym.Pkg)
+					}
+				}
+			}
+		}
+
+		a.Type = obj.TYPE_MEM
+		switch n.Class {
+		default:
+			Fatal("naddr: ONAME class %v %d\n", n.Sym, n.Class)
+
+		case PEXTERN:
+			a.Name = obj.NAME_EXTERN
+
+		case PAUTO:
+			a.Name = obj.NAME_AUTO
+
+		case PPARAM, PPARAMOUT:
+			a.Name = obj.NAME_PARAM
+
+		case PFUNC:
+			a.Name = obj.NAME_EXTERN
+			a.Type = obj.TYPE_ADDR
+			a.Width = int64(Widthptr)
+			s = funcsym(s)
+		}
+
+		a.Sym = Linksym(s)
+
+	case OLITERAL:
+		if Thearch.Thechar == '8' {
+			a.Width = 0
+		}
+		switch n.Val().Ctype() {
+		default:
+			Fatal("naddr: const %v", Tconv(n.Type, obj.FmtLong))
+
+		case CTFLT:
+			a.Type = obj.TYPE_FCONST
+			a.Val = mpgetflt(n.Val().U.(*Mpflt))
+
+		case CTINT, CTRUNE:
+			a.Sym = nil
+			a.Type = obj.TYPE_CONST
+			a.Offset = Mpgetfix(n.Val().U.(*Mpint))
+
+		case CTSTR:
+			datagostring(n.Val().U.(string), a)
+
+		case CTBOOL:
+			a.Sym = nil
+			a.Type = obj.TYPE_CONST
+			a.Offset = int64(obj.Bool2int(n.Val().U.(bool)))
+
+		case CTNIL:
+			a.Sym = nil
+			a.Type = obj.TYPE_CONST
+			a.Offset = 0
+		}
+
+	case OADDR:
+		Naddr(a, n.Left)
+		a.Etype = uint8(Tptr)
+		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(a, n.Left)
+
+		if a.Type == obj.TYPE_CONST && a.Offset == 0 {
+			break // itab(nil)
+		}
+		a.Etype = uint8(Tptr)
+		a.Width = int64(Widthptr)
+
+		// pointer in a string or slice
+	case OSPTR:
+		Naddr(a, n.Left)
+
+		if a.Type == obj.TYPE_CONST && a.Offset == 0 {
+			break // ptr(nil)
+		}
+		a.Etype = Simtype[Tptr]
+		a.Offset += int64(Array_array)
+		a.Width = int64(Widthptr)
+
+		// len of string or slice
+	case OLEN:
+		Naddr(a, n.Left)
+
+		if a.Type == obj.TYPE_CONST && a.Offset == 0 {
+			break // len(nil)
+		}
+		a.Etype = Simtype[TUINT]
+		a.Offset += int64(Array_nel)
+		if Thearch.Thechar != '5' { // TODO(rsc): Do this even on arm.
+			a.Width = int64(Widthint)
+		}
+
+		// cap of string or slice
+	case OCAP:
+		Naddr(a, n.Left)
+
+		if a.Type == obj.TYPE_CONST && a.Offset == 0 {
+			break // cap(nil)
+		}
+		a.Etype = Simtype[TUINT]
+		a.Offset += int64(Array_cap)
+		if Thearch.Thechar != '5' { // TODO(rsc): Do this even on arm.
+			a.Width = int64(Widthint)
+		}
+	}
+	return
+}
+
+func newplist() *obj.Plist {
+	pl := obj.Linknewplist(Ctxt)
+
+	Pc = Ctxt.NewProg()
+	Clearp(Pc)
+	pl.Firstpc = Pc
+
+	return pl
+}
+
+func nodarg(t *Type, fp int) *Node {
+	var n *Node
+
+	// entire argument struct, not just one arg
+	if t.Etype == TSTRUCT && t.Funarg != 0 {
+		n = Nod(ONAME, nil, nil)
+		n.Sym = Lookup(".args")
+		n.Type = t
+		var savet Iter
+		first := Structfirst(&savet, &t)
+		if first == nil {
+			Fatal("nodarg: bad struct")
+		}
+		if first.Width == BADWIDTH {
+			Fatal("nodarg: offset not computed for %v", t)
+		}
+		n.Xoffset = first.Width
+		n.Addable = true
+		goto fp
+	}
+
+	if t.Etype != TFIELD {
+		Fatal("nodarg: not field %v", t)
+	}
+
+	if fp == 1 {
+		var n *Node
+		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
+			}
+		}
+	}
+
+	n = Nod(ONAME, nil, nil)
+	n.Type = t.Type
+	n.Sym = t.Sym
+
+	if t.Width == BADWIDTH {
+		Fatal("nodarg: offset not computed for %v", t)
+	}
+	n.Xoffset = t.Width
+	n.Addable = true
+	n.Orig = t.Nname
+
+	// Rewrite argument named _ to __,
+	// or else the assignment to _ will be
+	// discarded during code generation.
+fp:
+	if isblank(n) {
+		n.Sym = Lookup("__")
+	}
+
+	switch fp {
+	case 0: // output arg
+		n.Op = OINDREG
+
+		n.Reg = int16(Thearch.REGSP)
+		if HasLinkRegister() {
+			n.Xoffset += int64(Ctxt.Arch.Ptrsize)
+		}
+
+	case 1: // input arg
+		n.Class = PPARAM
+
+	case 2: // offset output arg
+		Fatal("shouldn't be used")
+	}
+
+	n.Typecheck = 1
+	return n
+}
+
+func Patch(p *obj.Prog, to *obj.Prog) {
+	if p.To.Type != obj.TYPE_BRANCH {
+		Fatal("patch: not a branch")
+	}
+	p.To.Val = to
+	p.To.Offset = to.Pc
+}
+
+func unpatch(p *obj.Prog) *obj.Prog {
+	if p.To.Type != obj.TYPE_BRANCH {
+		Fatal("unpatch: not a branch")
+	}
+	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 GetReg(r int) int {
+	return reg[r-Thearch.REGMIN]
+}
+func SetReg(r, v int) {
+	reg[r-Thearch.REGMIN] = v
+}
+
+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 {
+			if Debug['v'] != 0 {
+				Regdump()
+			}
+			Yyerror("reg %v left allocated", obj.Rconv(r))
+		}
+	}
+
+	for r := Thearch.FREGMIN; r <= Thearch.FREGMAX; r++ {
+		n := reg[r-Thearch.REGMIN]
+		if n != 0 {
+			if Debug['v'] != 0 {
+				Regdump()
+			}
+			Yyerror("reg %v left allocated", obj.Rconv(r))
+		}
+	}
+}
+
+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", t)
+
+	case TINT8, TUINT8, TINT16, TUINT16, TINT32, TUINT32, TINT64, TUINT64, TPTR32, TPTR64, TBOOL:
+		if o != nil && o.Op == OREGISTER {
+			i = int(o.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.Use387 {
+			i = Thearch.FREGMIN // x86.REG_F0
+			break Switch
+		}
+		if o != nil && o.Op == OREGISTER {
+			i = int(o.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.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.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/compile/internal/gc/init.go b/src/cmd/compile/internal/gc/init.go
new file mode 100644
index 0000000..5fbc82d
--- /dev/null
+++ b/src/cmd/compile/internal/gc/init.go
@@ -0,0 +1,189 @@
+// 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
+
+//	case OADD:
+//		if(n->right->op == OLITERAL) {
+//			v = n->right->vconst;
+//			naddr(n->left, a, canemitcode);
+//		} else
+//		if(n->left->op == OLITERAL) {
+//			v = n->left->vconst;
+//			naddr(n->right, a, canemitcode);
+//		} else
+//			goto bad;
+//		a->offset += v;
+//		break;
+
+/*
+ * a function named init is a special case.
+ * it is called by the initialization before
+ * main is run. to make it unique within a
+ * package and also uncallable, the name,
+ * normally "pkg.init", is altered to "pkg.init.1".
+ */
+
+var renameinit_initgen int
+
+func renameinit() *Sym {
+	renameinit_initgen++
+	return Lookupf("init.%d", renameinit_initgen)
+}
+
+/*
+ * hand-craft the following initialization code
+ *	var initdone· uint8 				(1)
+ *	func init()					(2)
+ *		if initdone· != 0 {			(3)
+ *			if initdone· == 2		(4)
+ *				return
+ *			throw();			(5)
+ *		}
+ *		initdone· = 1;				(6)
+ *		// over all matching imported symbols
+ *			<pkg>.init()			(7)
+ *		{ <init stmts> }			(8)
+ *		init.<n>() // if any			(9)
+ *		initdone· = 2;				(10)
+ *		return					(11)
+ *	}
+ */
+func anyinit(n *NodeList) bool {
+	// are there any interesting init statements
+	for l := n; l != nil; l = l.Next {
+		switch l.N.Op {
+		case ODCLFUNC, ODCLCONST, ODCLTYPE, OEMPTY:
+			break
+
+		case OAS, OASWB:
+			if isblank(l.N.Left) && candiscard(l.N.Right) {
+				break
+			}
+			fallthrough
+
+			// fall through
+		default:
+			return true
+		}
+	}
+
+	// is this main
+	if localpkg.Name == "main" {
+		return true
+	}
+
+	// is there an explicit init function
+	s := Lookup("init.1")
+
+	if s.Def != nil {
+		return true
+	}
+
+	// are there any imported init functions
+	for _, s := range initSyms {
+		if s.Def != nil {
+			return true
+		}
+	}
+
+	// then none
+	return false
+}
+
+func fninit(n *NodeList) {
+	if Debug['A'] != 0 {
+		// sys.go or unsafe.go during compiler build
+		return
+	}
+
+	n = initfix(n)
+	if !anyinit(n) {
+		return
+	}
+
+	var r *NodeList
+
+	// (1)
+	gatevar := newname(Lookup("initdone·"))
+	addvar(gatevar, Types[TUINT8], PEXTERN)
+
+	// (2)
+	Maxarg = 0
+
+	fn := Nod(ODCLFUNC, nil, nil)
+	initsym := Lookup("init")
+	fn.Func.Nname = newname(initsym)
+	fn.Func.Nname.Name.Defn = fn
+	fn.Func.Nname.Name.Param.Ntype = Nod(OTFUNC, nil, nil)
+	declare(fn.Func.Nname, PFUNC)
+	funchdr(fn)
+
+	// (3)
+	a := Nod(OIF, nil, nil)
+
+	a.Left = Nod(ONE, gatevar, Nodintconst(0))
+	r = list(r, a)
+
+	// (4)
+	b := Nod(OIF, nil, nil)
+
+	b.Left = Nod(OEQ, gatevar, Nodintconst(2))
+	b.Nbody = list1(Nod(ORETURN, nil, nil))
+	a.Nbody = list1(b)
+
+	// (5)
+	b = syslook("throwinit", 0)
+
+	b = Nod(OCALL, b, nil)
+	a.Nbody = list(a.Nbody, b)
+
+	// (6)
+	a = Nod(OAS, gatevar, Nodintconst(1))
+
+	r = list(r, a)
+
+	// (7)
+	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)
+		}
+	}
+
+	// (8)
+	r = concat(r, n)
+
+	// (9)
+	// could check that it is fn of no args/returns
+	for i := 1; ; i++ {
+		s := Lookupf("init.%d", i)
+		if s.Def == nil {
+			break
+		}
+		a = Nod(OCALL, s.Def, nil)
+		r = list(r, a)
+	}
+
+	// (10)
+	a = Nod(OAS, gatevar, Nodintconst(2))
+
+	r = list(r, a)
+
+	// (11)
+	a = Nod(ORETURN, nil, nil)
+
+	r = list(r, a)
+	exportsym(fn.Func.Nname)
+
+	fn.Nbody = r
+	funcbody(fn)
+
+	Curfn = fn
+	typecheck(&fn, Etop)
+	typechecklist(r, Etop)
+	Curfn = nil
+	funccompile(fn)
+}
diff --git a/src/cmd/compile/internal/gc/inl.go b/src/cmd/compile/internal/gc/inl.go
new file mode 100644
index 0000000..b2eeeed
--- /dev/null
+++ b/src/cmd/compile/internal/gc/inl.go
@@ -0,0 +1,995 @@
+// 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.
+//
+// The inlining facility makes 2 passes: first caninl determines which
+// functions are suitable for inlining, and for those that are it
+// saves a copy of the body. Then inlcalls walks each function body to
+// expand calls to inlinable functions.
+//
+// The debug['l'] flag controls the agressiveness. Note that main() swaps level 0 and 1,
+// making 1 the default and -l disable.  -ll and more is useful to flush out bugs.
+// These additional levels (beyond -l) may be buggy and are not supported.
+//      0: disabled
+//      1: 40-nodes leaf functions, oneliners, lazy typechecking (default)
+//      2: early typechecking of all imported bodies
+//      3: allow variadic functions
+//      4: allow non-leaf functions , (breaks runtime.Caller)
+//
+//  At some point this may get another default and become switch-offable with -N.
+//
+//  The debug['m'] flag enables diagnostic output.  a single -m is useful for verifying
+//  which calls get inlined or not, more is for debugging, and may go away at any point.
+//
+// TODO:
+//   - inline functions with ... args
+//   - handle T.meth(f()) with func f() (t T, arg, arg, )
+
+package gc
+
+import (
+	"cmd/internal/obj"
+	"fmt"
+)
+
+// Used by caninl.
+
+// Used by inlcalls
+
+// Used during inlsubst[list]
+var inlfn *Node // function currently being inlined
+
+var inlretlabel *Node // target of the goto substituted in place of a return
+
+var inlretvars *NodeList // temp out variables
+
+// Get the function's package.  For ordinary functions it's on the ->sym, but for imported methods
+// the ->sym can be re-used in the local package, so peel it off the receiver's type.
+func fnpkg(fn *Node) *Pkg {
+	if fn.Type.Thistuple != 0 {
+		// method
+		rcvr := getthisx(fn.Type).Type.Type
+
+		if Isptr[rcvr.Etype] {
+			rcvr = rcvr.Type
+		}
+		if rcvr.Sym == nil {
+			Fatal("receiver with no sym: [%v] %v  (%v)", fn.Sym, Nconv(fn, obj.FmtLong), rcvr)
+		}
+		return rcvr.Sym.Pkg
+	}
+
+	// non-method
+	return fn.Sym.Pkg
+}
+
+// Lazy typechecking of imported bodies.  For local functions, caninl will set ->typecheck
+// because they're a copy of an already checked body.
+func typecheckinl(fn *Node) {
+	lno := int(setlineno(fn))
+
+	// typecheckinl is only for imported functions;
+	// their bodies may refer to unsafe as long as the package
+	// was marked safe during import (which was checked then).
+	// the ->inl of a local function has been typechecked before caninl copied it.
+	pkg := fnpkg(fn)
+
+	if pkg == localpkg || pkg == nil {
+		return // typecheckinl on local function
+	}
+
+	if Debug['m'] > 2 {
+		fmt.Printf("typecheck import [%v] %v { %v }\n", fn.Sym, Nconv(fn, obj.FmtLong), Hconv(fn.Func.Inl, obj.FmtSharp))
+	}
+
+	save_safemode := safemode
+	safemode = 0
+
+	savefn := Curfn
+	Curfn = fn
+	typechecklist(fn.Func.Inl, Etop)
+	Curfn = savefn
+
+	safemode = save_safemode
+
+	lineno = int32(lno)
+}
+
+// Caninl determines whether fn is inlineable.
+// If so, caninl saves fn->nbody in fn->inl and substitutes it with a copy.
+// fn and ->nbody will already have been typechecked.
+func caninl(fn *Node) {
+	if fn.Op != ODCLFUNC {
+		Fatal("caninl %v", fn)
+	}
+	if fn.Func.Nname == nil {
+		Fatal("caninl no nname %v", Nconv(fn, obj.FmtSign))
+	}
+
+	// If fn has no body (is defined outside of Go), cannot inline it.
+	if fn.Nbody == nil {
+		return
+	}
+
+	if fn.Typecheck == 0 {
+		Fatal("caninl on non-typechecked function %v", fn)
+	}
+
+	// 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 {
+				return
+			}
+		}
+	}
+
+	// Runtime package must not be race instrumented.
+	// Racewalk skips runtime package. However, some runtime code can be
+	// inlined into other packages and instrumented there. To avoid this,
+	// we disable inlining of runtime functions in race mode.
+	// The example that we observed is inlining of LockOSThread,
+	// which lead to false race reports on m contents.
+	if flag_race != 0 && myimportpath == "runtime" {
+		return
+	}
+
+	const maxBudget = 80
+	budget := maxBudget // allowed hairyness
+	if ishairylist(fn.Nbody, &budget) || budget < 0 {
+		return
+	}
+
+	savefn := Curfn
+	Curfn = fn
+
+	fn.Func.Nname.Func.Inl = fn.Nbody
+	fn.Nbody = inlcopylist(fn.Func.Nname.Func.Inl)
+	fn.Func.Nname.Func.Inldcl = inlcopylist(fn.Func.Nname.Name.Defn.Func.Dcl)
+	fn.Func.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.Func.Nname
+
+	if Debug['m'] > 1 {
+		fmt.Printf("%v: can inline %v as: %v { %v }\n", fn.Line(), Nconv(fn.Func.Nname, obj.FmtSharp), Tconv(fn.Type, obj.FmtSharp), Hconv(fn.Func.Nname.Func.Inl, obj.FmtSharp))
+	} else if Debug['m'] != 0 {
+		fmt.Printf("%v: can inline %v\n", fn.Line(), fn.Func.Nname)
+	}
+
+	Curfn = savefn
+}
+
+// Look for anything we want to punt on.
+func ishairylist(ll *NodeList, budget *int) bool {
+	for ; ll != nil; ll = ll.Next {
+		if ishairy(ll.N, budget) {
+			return true
+		}
+	}
+	return false
+}
+
+func ishairy(n *Node, budget *int) bool {
+	if n == nil {
+		return false
+	}
+
+	switch n.Op {
+	// Call is okay if inlinable and we have the budget for the body.
+	case OCALLFUNC:
+		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.Func.Inl != nil {
+				*budget -= int(n.Left.Sym.Def.Func.InlCost)
+				break
+			}
+		}
+		if Debug['l'] < 4 {
+			return true
+		}
+
+	// Call is okay if inlinable and we have the budget for the body.
+	case OCALLMETH:
+		if n.Left.Type == nil {
+			Fatal("no function type for [%p] %v\n", n.Left, Nconv(n.Left, obj.FmtSign))
+		}
+		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.Func.Inl != nil {
+			*budget -= int(n.Left.Type.Nname.Func.InlCost)
+			break
+		}
+		if Debug['l'] < 4 {
+			return true
+		}
+
+	// Things that are too hairy, irrespective of the budget
+	case OCALL, OCALLINTER, OPANIC, ORECOVER:
+		if Debug['l'] < 4 {
+			return true
+		}
+
+	case OCLOSURE,
+		OCALLPART,
+		ORANGE,
+		OFOR,
+		OSELECT,
+		OSWITCH,
+		OPROC,
+		ODEFER,
+		ODCLTYPE,  // can't print yet
+		ODCLCONST, // can't print yet
+		ORETJMP:
+		return true
+	}
+
+	(*budget)--
+
+	return *budget < 0 || ishairy(n.Left, budget) || ishairy(n.Right, budget) || ishairylist(n.List, budget) || ishairylist(n.Rlist, budget) || ishairylist(n.Ninit, budget) || ishairylist(n.Nbody, budget)
+}
+
+// Inlcopy and inlcopylist recursively copy the body of a function.
+// Any name-like node of non-local class is marked for re-export by adding it to
+// the exportlist.
+func inlcopylist(ll *NodeList) *NodeList {
+	var l *NodeList
+	for ; ll != nil; ll = ll.Next {
+		l = list(l, inlcopy(ll.N))
+	}
+	return l
+}
+
+func inlcopy(n *Node) *Node {
+	if n == nil {
+		return nil
+	}
+
+	switch n.Op {
+	case ONAME, OTYPE, OLITERAL:
+		return n
+	}
+
+	m := Nod(OXXX, nil, nil)
+	*m = *n
+	if m.Func != nil {
+		m.Func.Inl = nil
+	}
+	m.Left = inlcopy(n.Left)
+	m.Right = inlcopy(n.Right)
+	m.List = inlcopylist(n.List)
+	m.Rlist = inlcopylist(n.Rlist)
+	m.Ninit = inlcopylist(n.Ninit)
+	m.Nbody = inlcopylist(n.Nbody)
+
+	return m
+}
+
+// Inlcalls/nodelist/node walks fn's statements and expressions and substitutes any
+// calls made to inlineable functions.  This is the external entry point.
+func inlcalls(fn *Node) {
+	savefn := Curfn
+	Curfn = fn
+	inlnode(&fn)
+	if fn != Curfn {
+		Fatal("inlnode replaced curfn")
+	}
+	Curfn = savefn
+}
+
+// Turn an OINLCALL into a statement.
+func inlconv2stmt(n *Node) {
+	n.Op = OBLOCK
+
+	// n->ninit stays
+	n.List = n.Nbody
+
+	n.Nbody = nil
+	n.Rlist = nil
+}
+
+// Turn an OINLCALL into a single valued expression.
+func inlconv2expr(np **Node) {
+	n := *np
+	r := n.Rlist.N
+	addinit(&r, concat(n.Ninit, n.Nbody))
+	*np = r
+}
+
+// Turn the rlist (with the return values) of the OINLCALL in
+// n into an expression list lumping the ninit and body
+// containing the inlined statements on the first list element so
+// order will be preserved Used in return, oas2func and call
+// statements.
+func inlconv2list(n *Node) *NodeList {
+	if n.Op != OINLCALL || n.Rlist == nil {
+		Fatal("inlconv2list %v\n", Nconv(n, obj.FmtSign))
+	}
+
+	l := n.Rlist
+	addinit(&l.N, concat(n.Ninit, n.Nbody))
+	return l
+}
+
+func inlnodelist(l *NodeList) {
+	for ; l != nil; l = l.Next {
+		inlnode(&l.N)
+	}
+}
+
+// inlnode recurses over the tree to find inlineable calls, which will
+// be turned into OINLCALLs by mkinlcall.  When the recursion comes
+// back up will examine left, right, list, rlist, ninit, ntest, nincr,
+// nbody and nelse and use one of the 4 inlconv/glue functions above
+// to turn the OINLCALL into an expression, a statement, or patch it
+// in to this nodes list or rlist as appropriate.
+// NOTE it makes no sense to pass the glue functions down the
+// recursion to the level where the OINLCALL gets created because they
+// have to edit /this/ n, so you'd have to push that one down as well,
+// but then you may as well do it here.  so this is cleaner and
+// shorter and less complicated.
+func inlnode(np **Node) {
+	if *np == nil {
+		return
+	}
+
+	n := *np
+
+	switch n.Op {
+	// inhibit inlining of their argument
+	case ODEFER, OPROC:
+		switch n.Left.Op {
+		case OCALLFUNC, OCALLMETH:
+			n.Left.Etype = n.Op
+		}
+		fallthrough
+
+		// TODO do them here (or earlier),
+	// so escape analysis can avoid more heapmoves.
+	case OCLOSURE:
+		return
+	}
+
+	lno := int(setlineno(n))
+
+	inlnodelist(n.Ninit)
+	for l := n.Ninit; l != nil; l = l.Next {
+		if l.N.Op == OINLCALL {
+			inlconv2stmt(l.N)
+		}
+	}
+
+	inlnode(&n.Left)
+	if n.Left != nil && n.Left.Op == OINLCALL {
+		inlconv2expr(&n.Left)
+	}
+
+	inlnode(&n.Right)
+	if n.Right != nil && n.Right.Op == OINLCALL {
+		if n.Op == OFOR {
+			inlconv2stmt(n.Right)
+		} else {
+			inlconv2expr(&n.Right)
+		}
+	}
+
+	inlnodelist(n.List)
+	switch n.Op {
+	case OBLOCK:
+		for l := n.List; l != nil; l = l.Next {
+			if l.N.Op == OINLCALL {
+				inlconv2stmt(l.N)
+			}
+		}
+
+		// if we just replaced arg in f(arg()) or return arg with an inlined call
+	// and arg returns multiple values, glue as list
+	case ORETURN,
+		OCALLFUNC,
+		OCALLMETH,
+		OCALLINTER,
+		OAPPEND,
+		OCOMPLEX:
+		if count(n.List) == 1 && n.List.N.Op == OINLCALL && count(n.List.N.Rlist) > 1 {
+			n.List = inlconv2list(n.List.N)
+			break
+		}
+		fallthrough
+
+	default:
+		for l := n.List; l != nil; l = l.Next {
+			if l.N.Op == OINLCALL {
+				inlconv2expr(&l.N)
+			}
+		}
+	}
+
+	inlnodelist(n.Rlist)
+	switch n.Op {
+	case OAS2FUNC:
+		if n.Rlist.N.Op == OINLCALL {
+			n.Rlist = inlconv2list(n.Rlist.N)
+			n.Op = OAS2
+			n.Typecheck = 0
+			typecheck(np, Etop)
+			break
+		}
+		fallthrough
+
+	default:
+		for l := n.Rlist; l != nil; l = l.Next {
+			if l.N.Op == OINLCALL {
+				if n.Op == OIF {
+					inlconv2stmt(l.N)
+				} else {
+					inlconv2expr(&l.N)
+				}
+			}
+		}
+	}
+
+	inlnodelist(n.Nbody)
+	for l := n.Nbody; l != nil; l = l.Next {
+		if l.N.Op == OINLCALL {
+			inlconv2stmt(l.N)
+		}
+	}
+
+	// with all the branches out of the way, it is now time to
+	// transmogrify this node itself unless inhibited by the
+	// switch at the top of this function.
+	switch n.Op {
+	case OCALLFUNC, OCALLMETH:
+		if n.Etype == OPROC || n.Etype == ODEFER {
+			return
+		}
+	}
+
+	switch n.Op {
+	case OCALLFUNC:
+		if Debug['m'] > 3 {
+			fmt.Printf("%v:call to func %v\n", n.Line(), Nconv(n.Left, obj.FmtSign))
+		}
+		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, n.Isddd)
+			}
+		}
+
+	case OCALLMETH:
+		if Debug['m'] > 3 {
+			fmt.Printf("%v:call to meth %v\n", n.Line(), Nconv(n.Left.Right, obj.FmtLong))
+		}
+
+		// typecheck should have resolved ODOTMETH->type, whose nname points to the actual function.
+		if n.Left.Type == nil {
+			Fatal("no function type for [%p] %v\n", n.Left, Nconv(n.Left, obj.FmtSign))
+		}
+
+		if n.Left.Type.Nname == nil {
+			Fatal("no function definition for [%p] %v\n", n.Left.Type, Tconv(n.Left.Type, obj.FmtSign))
+		}
+
+		mkinlcall(np, n.Left.Type.Nname, n.Isddd)
+	}
+
+	lineno = int32(lno)
+}
+
+func mkinlcall(np **Node, fn *Node, isddd bool) {
+	save_safemode := safemode
+
+	// imported functions may refer to unsafe as long as the
+	// package was marked safe during import (already checked).
+	pkg := fnpkg(fn)
+
+	if pkg != localpkg && pkg != nil {
+		safemode = 0
+	}
+	mkinlcall1(np, fn, isddd)
+	safemode = save_safemode
+}
+
+func tinlvar(t *Type) *Node {
+	if t.Nname != nil && !isblank(t.Nname) {
+		if t.Nname.Name.Inlvar == nil {
+			Fatal("missing inlvar for %v\n", t.Nname)
+		}
+		return t.Nname.Name.Inlvar
+	}
+
+	typecheck(&nblank, Erv|Easgn)
+	return nblank
+}
+
+var inlgen int
+
+// if *np is a call, and fn is a function with an inlinable body, substitute *np with an OINLCALL.
+// 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 bool) {
+	// For variadic fn.
+	if fn.Func.Inl == nil {
+		return
+	}
+
+	if fn == Curfn || fn.Name.Defn == Curfn {
+		return
+	}
+
+	if Debug['l'] < 2 {
+		typecheckinl(fn)
+	}
+
+	n := *np
+
+	// 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(), fn.Sym, 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(), fn)
+	}
+
+	if Debug['m'] > 2 {
+		fmt.Printf("%v: Before inlining: %v\n", n.Line(), Nconv(n, obj.FmtSign))
+	}
+
+	saveinlfn := inlfn
+	inlfn = fn
+
+	ninit := n.Ninit
+
+	//dumplist("ninit pre", ninit);
+
+	var dcl *NodeList
+	if fn.Name.Defn != nil { // local function
+		dcl = fn.Func.Inldcl // imported function
+	} else {
+		dcl = fn.Func.Dcl
+	}
+
+	inlretvars = nil
+	i := 0
+
+	// Make temp names to use instead of the originals
+	for ll := dcl; ll != nil; ll = ll.Next {
+		if ll.N.Class == PPARAMOUT { // return values handled below.
+			continue
+		}
+		if ll.N.Op == ONAME {
+			ll.N.Name.Inlvar = inlvar(ll.N)
+
+			// Typecheck because inlvar is not necessarily a function parameter.
+			typecheck(&ll.N.Name.Inlvar, Erv)
+
+			if ll.N.Class&^PHEAP != PAUTO {
+				ninit = list(ninit, Nod(ODCL, ll.N.Name.Inlvar, nil)) // otherwise gen won't emit the allocations for heapallocs
+			}
+		}
+	}
+
+	// temporaries for return values.
+	var m *Node
+	for t := getoutargx(fn.Type).Type; t != nil; t = t.Down {
+		if t != nil && t.Nname != nil && !isblank(t.Nname) {
+			m = inlvar(t.Nname)
+			typecheck(&m, Erv)
+			t.Nname.Name.Inlvar = m
+		} else {
+			// anonymous return values, synthesize names for use in assignment that replaces return
+			m = retvar(t, i)
+			i++
+		}
+
+		ninit = list(ninit, Nod(ODCL, m, nil))
+		inlretvars = list(inlretvars, m)
+	}
+
+	// assign receiver.
+	var as *Node
+	if fn.Type.Thistuple != 0 && n.Left.Op == ODOTMETH {
+		// method call with a receiver.
+		t := getthisx(fn.Type).Type
+
+		if t != nil && t.Nname != nil && !isblank(t.Nname) && t.Nname.Name.Inlvar == nil {
+			Fatal("missing inlvar for %v\n", t.Nname)
+		}
+		if n.Left.Left == nil {
+			Fatal("method call without receiver: %v", Nconv(n, obj.FmtSign))
+		}
+		if t == nil {
+			Fatal("method call unknown receiver type: %v", Nconv(n, obj.FmtSign))
+		}
+		as = Nod(OAS, tinlvar(t), n.Left.Left)
+		if as != nil {
+			typecheck(&as, Etop)
+			ninit = list(ninit, as)
+		}
+	}
+
+	// check if inlined function is variadic.
+	variadic := false
+
+	var varargtype *Type
+	varargcount := 0
+	for t := fn.Type.Type.Down.Down.Type; t != nil; t = t.Down {
+		if t.Isddd {
+			variadic = true
+			varargtype = t.Type
+		}
+	}
+
+	// but if argument is dotted too forget about variadicity.
+	if variadic && isddd {
+		variadic = false
+	}
+
+	// check if argument is actually a returned tuple from call.
+	multiret := 0
+
+	if n.List != nil && n.List.Next == nil {
+		switch n.List.N.Op {
+		case OCALL, OCALLFUNC, OCALLINTER, OCALLMETH:
+			if n.List.N.Left.Type.Outtuple > 1 {
+				multiret = n.List.N.Left.Type.Outtuple - 1
+			}
+		}
+	}
+
+	if variadic {
+		varargcount = count(n.List) + multiret
+		if n.Left.Op != ODOTMETH {
+			varargcount -= fn.Type.Thistuple
+		}
+		varargcount -= fn.Type.Intuple - 1
+	}
+
+	// assign arguments to the parameters' temp names
+	as = Nod(OAS2, nil, nil)
+
+	as.Rlist = n.List
+	ll := n.List
+
+	// TODO: if len(nlist) == 1 but multiple args, check that n->list->n is a call?
+	if fn.Type.Thistuple != 0 && n.Left.Op != ODOTMETH {
+		// non-method call to method
+		if n.List == nil {
+			Fatal("non-method call to method without first arg: %v", Nconv(n, obj.FmtSign))
+		}
+
+		// append receiver inlvar to LHS.
+		t := getthisx(fn.Type).Type
+
+		if t != nil && t.Nname != nil && !isblank(t.Nname) && t.Nname.Name.Inlvar == nil {
+			Fatal("missing inlvar for %v\n", t.Nname)
+		}
+		if t == nil {
+			Fatal("method call unknown receiver type: %v", Nconv(n, obj.FmtSign))
+		}
+		as.List = list(as.List, tinlvar(t))
+		ll = ll.Next // track argument count.
+	}
+
+	// append ordinary arguments to LHS.
+	chkargcount := n.List != nil && n.List.Next != nil
+
+	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 {
+				vararg = tinlvar(t)
+				for i = 0; i < varargcount && ll != nil; i++ {
+					m = argvar(varargtype, i)
+					varargs = list(varargs, m)
+					as.List = list(as.List, m)
+				}
+
+				break
+			}
+
+			as.List = list(as.List, tinlvar(t))
+		}
+	} else {
+		// match arguments except final variadic (unless the call is dotted itself)
+		var t *Type
+		for t = getinargx(fn.Type).Type; t != nil; {
+			if ll == nil {
+				break
+			}
+			if variadic && t.Isddd {
+				break
+			}
+			as.List = list(as.List, tinlvar(t))
+			t = t.Down
+			ll = ll.Next
+		}
+
+		// match varargcount arguments with variadic parameters.
+		if variadic && t != nil && t.Isddd {
+			vararg = tinlvar(t)
+			var i int
+			for i = 0; i < varargcount && ll != nil; i++ {
+				m = argvar(varargtype, i)
+				varargs = list(varargs, m)
+				as.List = list(as.List, m)
+				ll = ll.Next
+			}
+
+			if i == varargcount {
+				t = t.Down
+			}
+		}
+
+		if ll != nil || t != nil {
+			Fatal("arg count mismatch: %v  vs %v\n", Tconv(getinargx(fn.Type), obj.FmtSharp), Hconv(n.List, obj.FmtComma))
+		}
+	}
+
+	if as.Rlist != nil {
+		typecheck(&as, Etop)
+		ninit = list(ninit, as)
+	}
+
+	// turn the variadic args into a slice.
+	if variadic {
+		as = Nod(OAS, vararg, nil)
+		if varargcount == 0 {
+			as.Right = nodnil()
+			as.Right.Type = varargtype
+		} else {
+			vararrtype := typ(TARRAY)
+			vararrtype.Type = varargtype.Type
+			vararrtype.Bound = int64(varargcount)
+
+			as.Right = Nod(OCOMPLIT, nil, typenod(varargtype))
+			as.Right.List = varargs
+			as.Right = Nod(OSLICE, as.Right, Nod(OKEY, nil, nil))
+		}
+
+		typecheck(&as, Etop)
+		ninit = list(ninit, as)
+	}
+
+	// zero the outparams
+	for ll := inlretvars; ll != nil; ll = ll.Next {
+		as = Nod(OAS, ll.N, nil)
+		typecheck(&as, Etop)
+		ninit = list(ninit, as)
+	}
+
+	inlretlabel = newlabel_inl()
+	inlgen++
+	body := inlsubstlist(fn.Func.Inl)
+
+	body = list(body, Nod(OGOTO, inlretlabel, nil)) // avoid 'not used' when function doesn't have return
+	body = list(body, Nod(OLABEL, inlretlabel, nil))
+
+	typechecklist(body, Etop)
+
+	//dumplist("ninit post", ninit);
+
+	call := Nod(OINLCALL, nil, nil)
+
+	call.Ninit = ninit
+	call.Nbody = body
+	call.Rlist = inlretvars
+	call.Type = n.Type
+	call.Typecheck = 1
+
+	// Hide the args from setlno -- the parameters to the inlined
+	// call already have good line numbers that should be preserved.
+	args := as.Rlist
+	as.Rlist = nil
+
+	setlno(call, int(n.Lineno))
+
+	as.Rlist = args
+
+	//dumplist("call body", body);
+
+	*np = call
+
+	inlfn = saveinlfn
+
+	// transitive inlining
+	// might be nice to do this before exporting the body,
+	// but can't emit the body with inlining expanded.
+	// instead we emit the things that the body needs
+	// and each use must redo the inlining.
+	// luckily these are small.
+	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.Func.Inl = body
+
+	if Debug['m'] > 2 {
+		fmt.Printf("%v: After inlining %v\n\n", n.Line(), Nconv(*np, obj.FmtSign))
+	}
+}
+
+// Every time we expand a function we generate a new set of tmpnames,
+// PAUTO's in the calling functions, and link them off of the
+// PPARAM's, PAUTOS and PPARAMOUTs of the called function.
+func inlvar(var_ *Node) *Node {
+	if Debug['m'] > 3 {
+		fmt.Printf("inlvar %v\n", Nconv(var_, obj.FmtSign))
+	}
+
+	n := newname(var_.Sym)
+	n.Type = var_.Type
+	n.Class = PAUTO
+	n.Used = true
+	n.Name.Curfn = Curfn // the calling function, not the called one
+	n.Addrtaken = var_.Addrtaken
+
+	// This may no longer be necessary now that we run escape analysis
+	// after wrapper generation, but for 1.5 this is conservatively left
+	// unchanged.  See bugs 11053 and 9537.
+	if var_.Esc == EscHeap {
+		addrescapes(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 {
+	n := newname(Lookupf("~r%d", i))
+	n.Type = t.Type
+	n.Class = PAUTO
+	n.Used = true
+	n.Name.Curfn = Curfn // the calling function, not the called one
+	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 {
+	n := newname(Lookupf("~arg%d", i))
+	n.Type = t.Type
+	n.Class = PAUTO
+	n.Used = true
+	n.Name.Curfn = Curfn // the calling function, not the called one
+	Curfn.Func.Dcl = list(Curfn.Func.Dcl, n)
+	return n
+}
+
+var newlabel_inl_label int
+
+func newlabel_inl() *Node {
+	newlabel_inl_label++
+	n := newname(Lookupf(".inlret%.6d", newlabel_inl_label))
+	n.Etype = 1 // flag 'safe' for escape analysis (no backjumps)
+	return n
+}
+
+// inlsubst and inlsubstlist recursively copy the body of the saved
+// pristine ->inl body of the function while substituting references
+// to input/output parameters with ones to the tmpnames, and
+// substituting returns with assignments to the output.
+func inlsubstlist(ll *NodeList) *NodeList {
+	var l *NodeList
+	for ; ll != nil; ll = ll.Next {
+		l = list(l, inlsubst(ll.N))
+	}
+	return l
+}
+
+func inlsubst(n *Node) *Node {
+	if n == nil {
+		return nil
+	}
+
+	switch n.Op {
+	case ONAME:
+		if n.Name.Inlvar != nil { // These will be set during inlnode
+			if Debug['m'] > 2 {
+				fmt.Printf("substituting name %v  ->  %v\n", Nconv(n, obj.FmtSign), Nconv(n.Name.Inlvar, obj.FmtSign))
+			}
+			return n.Name.Inlvar
+		}
+
+		if Debug['m'] > 2 {
+			fmt.Printf("not substituting name %v\n", Nconv(n, obj.FmtSign))
+		}
+		return n
+
+	case OLITERAL, OTYPE:
+		return n
+
+		// Since we don't handle bodies with closures, this return is guaranteed to belong to the current inlined function.
+
+	//		dump("Return before substitution", n);
+	case ORETURN:
+		m := Nod(OGOTO, inlretlabel, nil)
+
+		m.Ninit = inlsubstlist(n.Ninit)
+
+		if inlretvars != nil && n.List != nil {
+			as := Nod(OAS2, nil, nil)
+
+			// shallow copy or OINLCALL->rlist will be the same list, and later walk and typecheck may clobber that.
+			for ll := inlretvars; ll != nil; ll = ll.Next {
+				as.List = list(as.List, ll.N)
+			}
+			as.Rlist = inlsubstlist(n.List)
+			typecheck(&as, Etop)
+			m.Ninit = list(m.Ninit, as)
+		}
+
+		typechecklist(m.Ninit, Etop)
+		typecheck(&m, Etop)
+
+		//		dump("Return after substitution", m);
+		return m
+
+	case OGOTO, OLABEL:
+		m := Nod(OXXX, nil, nil)
+		*m = *n
+		m.Ninit = nil
+		p := fmt.Sprintf("%s·%d", n.Left.Sym.Name, inlgen)
+		m.Left = newname(Lookup(p))
+
+		return m
+	}
+
+	m := Nod(OXXX, nil, nil)
+	*m = *n
+	m.Ninit = nil
+
+	if n.Op == OCLOSURE {
+		Fatal("cannot inline function containing closure: %v", Nconv(n, obj.FmtSign))
+	}
+
+	m.Left = inlsubst(n.Left)
+	m.Right = inlsubst(n.Right)
+	m.List = inlsubstlist(n.List)
+	m.Rlist = inlsubstlist(n.Rlist)
+	m.Ninit = concat(m.Ninit, inlsubstlist(n.Ninit))
+	m.Nbody = inlsubstlist(n.Nbody)
+
+	return m
+}
+
+// Plaster over linenumbers
+func setlnolist(ll *NodeList, lno int) {
+	for ; ll != nil; ll = ll.Next {
+		setlno(ll.N, lno)
+	}
+}
+
+func setlno(n *Node, lno int) {
+	if n == nil {
+		return
+	}
+
+	// don't clobber names, unless they're freshly synthesized
+	if n.Op != ONAME || n.Lineno == 0 {
+		n.Lineno = int32(lno)
+	}
+
+	setlno(n.Left, lno)
+	setlno(n.Right, lno)
+	setlnolist(n.List, lno)
+	setlnolist(n.Rlist, lno)
+	setlnolist(n.Ninit, lno)
+	setlnolist(n.Nbody, lno)
+}
diff --git a/src/cmd/compile/internal/gc/lex.go b/src/cmd/compile/internal/gc/lex.go
new file mode 100644
index 0000000..606298b
--- /dev/null
+++ b/src/cmd/compile/internal/gc/lex.go
@@ -0,0 +1,2653 @@
+// 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.
+
+//go:generate go tool yacc go.y
+//go:generate go run mkbuiltin.go runtime unsafe
+
+package gc
+
+import (
+	"bytes"
+	"cmd/internal/obj"
+	"flag"
+	"fmt"
+	"io"
+	"log"
+	"os"
+	"path"
+	"strconv"
+	"strings"
+	"unicode"
+	"unicode/utf8"
+)
+
+var yyprev int
+
+var yylast int
+
+var imported_unsafe int
+
+var (
+	goos    string
+	goarch  string
+	goroot  string
+	buildid string
+)
+
+var (
+	Debug_append int
+	Debug_panic  int
+	Debug_slice  int
+	Debug_wb     int
+)
+
+// Debug arguments.
+// These can be specified with the -d flag, as in "-d nil"
+// to set the debug_checknil variable. In general the list passed
+// to -d can be comma-separated.
+var debugtab = []struct {
+	name string
+	val  *int
+}{
+	{"append", &Debug_append},         // print information about append compilation
+	{"disablenil", &Disable_checknil}, // disable nil checks
+	{"gcprog", &Debug_gcprog},         // print dump of GC programs
+	{"nil", &Debug_checknil},          // print information about nil checks
+	{"panic", &Debug_panic},           // do not hide any compiler panic
+	{"slice", &Debug_slice},           // print information about slice compilation
+	{"typeassert", &Debug_typeassert}, // print information about type assertion inlining
+	{"wb", &Debug_wb},                 // print information about write barriers
+}
+
+// Our own isdigit, isspace, isalpha, isalnum that take care
+// of EOF and other out of range arguments.
+func yy_isdigit(c int) bool {
+	return c >= 0 && c <= 0xFF && isdigit(c)
+}
+
+func yy_isspace(c int) bool {
+	return c == ' ' || c == '\t' || c == '\n' || c == '\r'
+}
+
+func yy_isalpha(c int) bool {
+	return 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z'
+}
+
+func yy_isalnum(c int) bool {
+	return c >= 0 && c <= 0xFF && isalnum(c)
+}
+
+// Disallow use of isdigit etc.
+
+const (
+	EOF = -1
+)
+
+func usage() {
+	fmt.Printf("usage: %cg [options] file.go...\n", Thearch.Thechar)
+	obj.Flagprint(1)
+	Exit(2)
+}
+
+func hidePanic() {
+	if Debug_panic == 0 && nsavederrors+nerrors > 0 {
+		// If we've already complained about things
+		// in the program, don't bother complaining
+		// about a panic too; let the user clean up
+		// the code and try again.
+		if err := recover(); err != nil {
+			errorexit()
+		}
+	}
+}
+
+func doversion() {
+	p := obj.Expstring()
+	if p == "X:none" {
+		p = ""
+	}
+	sep := ""
+	if p != "" {
+		sep = " "
+	}
+	fmt.Printf("%cg version %s%s%s\n", Thearch.Thechar, obj.Getgoversion(), sep, p)
+	os.Exit(0)
+}
+
+func Main() {
+	defer hidePanic()
+
+	// Allow GOARCH=thearch.thestring or GOARCH=thearch.thestringsuffix,
+	// but not other values.
+	p := obj.Getgoarch()
+
+	if !strings.HasPrefix(p, Thearch.Thestring) {
+		log.Fatalf("cannot use %cg with GOARCH=%s", Thearch.Thechar, p)
+	}
+	goarch = p
+
+	Thearch.Linkarchinit()
+	Ctxt = obj.Linknew(Thearch.Thelinkarch)
+	Ctxt.Diag = Yyerror
+	Ctxt.Bso = &bstdout
+	bstdout = *obj.Binitw(os.Stdout)
+
+	localpkg = mkpkg("")
+	localpkg.Prefix = "\"\""
+
+	// pseudo-package, for scoping
+	builtinpkg = mkpkg("go.builtin")
+
+	builtinpkg.Prefix = "go.builtin" // not go%2ebuiltin
+
+	// pseudo-package, accessed by import "unsafe"
+	unsafepkg = mkpkg("unsafe")
+
+	unsafepkg.Name = "unsafe"
+
+	// real package, referred to by generated runtime calls
+	Runtimepkg = mkpkg("runtime")
+
+	Runtimepkg.Name = "runtime"
+
+	// pseudo-packages used in symbol tables
+	gostringpkg = mkpkg("go.string")
+
+	gostringpkg.Name = "go.string"
+	gostringpkg.Prefix = "go.string" // not go%2estring
+
+	itabpkg = mkpkg("go.itab")
+
+	itabpkg.Name = "go.itab"
+	itabpkg.Prefix = "go.itab" // not go%2eitab
+
+	weaktypepkg = mkpkg("go.weak.type")
+
+	weaktypepkg.Name = "go.weak.type"
+	weaktypepkg.Prefix = "go.weak.type" // not go%2eweak%2etype
+
+	typelinkpkg = mkpkg("go.typelink")
+	typelinkpkg.Name = "go.typelink"
+	typelinkpkg.Prefix = "go.typelink" // not go%2etypelink
+
+	trackpkg = mkpkg("go.track")
+
+	trackpkg.Name = "go.track"
+	trackpkg.Prefix = "go.track" // not go%2etrack
+
+	typepkg = mkpkg("type")
+
+	typepkg.Name = "type"
+
+	goroot = obj.Getgoroot()
+	goos = obj.Getgoos()
+
+	Nacl = goos == "nacl"
+	if Nacl {
+		flag_largemodel = 1
+	}
+
+	outfile = ""
+	obj.Flagcount("+", "compiling runtime", &compiling_runtime)
+	obj.Flagcount("%", "debug non-static initializers", &Debug['%'])
+	obj.Flagcount("A", "for bootstrapping, allow 'any' type", &Debug['A'])
+	obj.Flagcount("B", "disable bounds checking", &Debug['B'])
+	obj.Flagstr("D", "set relative `path` for local imports", &localimport)
+	obj.Flagcount("E", "debug symbol export", &Debug['E'])
+	obj.Flagfn1("I", "add `directory` to import search path", addidir)
+	obj.Flagcount("K", "debug missing line numbers", &Debug['K'])
+	obj.Flagcount("L", "use full (long) path in error messages", &Debug['L'])
+	obj.Flagcount("M", "debug move generation", &Debug['M'])
+	obj.Flagcount("N", "disable optimizations", &Debug['N'])
+	obj.Flagcount("P", "debug peephole optimizer", &Debug['P'])
+	obj.Flagcount("R", "debug register optimizer", &Debug['R'])
+	obj.Flagcount("S", "print assembly listing", &Debug['S'])
+	obj.Flagfn0("V", "print compiler version", doversion)
+	obj.Flagcount("W", "debug parse tree after type checking", &Debug['W'])
+	obj.Flagstr("asmhdr", "write assembly header to `file`", &asmhdr)
+	obj.Flagstr("buildid", "record `id` as the build id in the export metadata", &buildid)
+	obj.Flagcount("complete", "compiling complete package (no C or assembly)", &pure_go)
+	obj.Flagstr("d", "print debug information about items in `list`", &debugstr)
+	obj.Flagcount("e", "no limit on number of errors reported", &Debug['e'])
+	obj.Flagcount("f", "debug stack frames", &Debug['f'])
+	obj.Flagcount("g", "debug code generation", &Debug['g'])
+	obj.Flagcount("h", "halt on error", &Debug['h'])
+	obj.Flagcount("i", "debug line number stack", &Debug['i'])
+	obj.Flagfn1("importmap", "add `definition` of the form source=actual to import map", addImportMap)
+	obj.Flagstr("installsuffix", "set pkg directory `suffix`", &flag_installsuffix)
+	obj.Flagcount("j", "debug runtime-initialized variables", &Debug['j'])
+	obj.Flagcount("l", "disable inlining", &Debug['l'])
+	obj.Flagcount("live", "debug liveness analysis", &debuglive)
+	obj.Flagcount("m", "print optimization decisions", &Debug['m'])
+	obj.Flagcount("nolocalimports", "reject local (relative) imports", &nolocalimports)
+	obj.Flagstr("o", "write output to `file`", &outfile)
+	obj.Flagstr("p", "set expected package import `path`", &myimportpath)
+	obj.Flagcount("pack", "write package file instead of object file", &writearchive)
+	obj.Flagcount("r", "debug generated wrappers", &Debug['r'])
+	obj.Flagcount("race", "enable race detector", &flag_race)
+	obj.Flagcount("s", "warn about composite literals that can be simplified", &Debug['s'])
+	obj.Flagstr("trimpath", "remove `prefix` from recorded source file paths", &Ctxt.LineHist.TrimPathPrefix)
+	obj.Flagcount("u", "reject unsafe code", &safemode)
+	obj.Flagcount("v", "increase debug verbosity", &Debug['v'])
+	obj.Flagcount("w", "debug type checking", &Debug['w'])
+	use_writebarrier = 1
+	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
+	var flag_dynlink bool
+	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)
+		flag.BoolVar(&flag_dynlink, "dynlink", false, "support references to Go symbols defined in other shared libraries")
+	}
+	obj.Flagstr("cpuprofile", "write cpu profile to `file`", &cpuprofile)
+	obj.Flagstr("memprofile", "write memory profile to `file`", &memprofile)
+	obj.Flagint64("memprofilerate", "set runtime.MemProfileRate to `rate`", &memprofilerate)
+	obj.Flagparse(usage)
+
+	if flag_dynlink {
+		flag_shared = 1
+	}
+	Ctxt.Flag_shared = int32(flag_shared)
+	Ctxt.Flag_dynlink = flag_dynlink
+
+	Ctxt.Debugasm = int32(Debug['S'])
+	Ctxt.Debugvlog = int32(Debug['v'])
+
+	if flag.NArg() < 1 {
+		usage()
+	}
+
+	startProfile()
+
+	if flag_race != 0 {
+		racepkg = mkpkg("runtime/race")
+		racepkg.Name = "race"
+	}
+
+	// parse -d argument
+	if debugstr != "" {
+	Split:
+		for _, name := range strings.Split(debugstr, ",") {
+			if name == "" {
+				continue
+			}
+			val := 1
+			if i := strings.Index(name, "="); i >= 0 {
+				var err error
+				val, err = strconv.Atoi(name[i+1:])
+				if err != nil {
+					log.Fatalf("invalid debug value %v", name)
+				}
+				name = name[:i]
+			}
+			for _, t := range debugtab {
+				if t.name == name {
+					if t.val != nil {
+						*t.val = val
+						continue Split
+					}
+				}
+			}
+			log.Fatalf("unknown debug key -d %s\n", name)
+		}
+	}
+
+	// enable inlining.  for now:
+	//	default: inlining on.  (debug['l'] == 1)
+	//	-l: inlining off  (debug['l'] == 0)
+	//	-ll, -lll: inlining on again, with extra debugging (debug['l'] > 1)
+	if Debug['l'] <= 1 {
+		Debug['l'] = 1 - Debug['l']
+	}
+
+	Thearch.Betypeinit()
+	if Widthptr == 0 {
+		Fatal("betypeinit failed")
+	}
+
+	lexinit()
+	typeinit()
+	lexinit1()
+	// TODO(rsc): Restore yytinit?
+
+	blockgen = 1
+	dclcontext = PEXTERN
+	nerrors = 0
+	lexlineno = 1
+
+	for _, infile = range flag.Args() {
+		linehistpush(infile)
+
+		curio.infile = infile
+		var err error
+		curio.bin, err = obj.Bopenr(infile)
+		if err != nil {
+			fmt.Printf("open %s: %v\n", infile, err)
+			errorexit()
+		}
+
+		curio.peekc = 0
+		curio.peekc1 = 0
+		curio.nlsemi = 0
+		curio.eofnl = 0
+		curio.last = 0
+
+		// Skip initial BOM if present.
+		if obj.Bgetrune(curio.bin) != obj.BOM {
+			obj.Bungetrune(curio.bin)
+		}
+
+		block = 1
+		iota_ = -1000000
+
+		imported_unsafe = 0
+
+		yyparse()
+		if nsyntaxerrors != 0 {
+			errorexit()
+		}
+
+		linehistpop()
+		if curio.bin != nil {
+			obj.Bterm(curio.bin)
+		}
+	}
+
+	testdclstack()
+	mkpackage(localpkg.Name) // final import not used checks
+	lexfini()
+
+	typecheckok = 1
+	if Debug['f'] != 0 {
+		frame(1)
+	}
+
+	// Process top-level declarations in phases.
+
+	// Phase 1: const, type, and names and types of funcs.
+	//   This will gather all the information about types
+	//   and methods but doesn't depend on any of it.
+	defercheckwidth()
+
+	for l := xtop; l != nil; l = l.Next {
+		if l.N.Op != ODCL && l.N.Op != OAS && l.N.Op != OAS2 {
+			typecheck(&l.N, Etop)
+		}
+	}
+
+	// Phase 2: Variable assignments.
+	//   To check interface assignments, depends on phase 1.
+	for l := xtop; l != nil; l = l.Next {
+		if l.N.Op == ODCL || l.N.Op == OAS || l.N.Op == OAS2 {
+			typecheck(&l.N, Etop)
+		}
+	}
+	resumecheckwidth()
+
+	// Phase 3: Type check function bodies.
+	for l := xtop; l != nil; l = l.Next {
+		if l.N.Op == ODCLFUNC || l.N.Op == OCLOSURE {
+			Curfn = l.N
+			decldepth = 1
+			saveerrors()
+			typechecklist(l.N.Nbody, Etop)
+			checkreturn(l.N)
+			if nerrors != 0 {
+				l.N.Nbody = nil // type errors; do not compile
+			}
+		}
+	}
+
+	// Phase 4: Decide how to capture closed variables.
+	// This needs to run before escape analysis,
+	// because variables captured by value do not escape.
+	for l := xtop; l != nil; l = l.Next {
+		if l.N.Op == ODCLFUNC && l.N.Func.Closure != nil {
+			Curfn = l.N
+			capturevars(l.N)
+		}
+	}
+
+	Curfn = nil
+
+	if nsavederrors+nerrors != 0 {
+		errorexit()
+	}
+
+	// Phase 5: Inlining
+	if Debug['l'] > 1 {
+		// 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.Func.Inl != nil {
+				saveerrors()
+				typecheckinl(l.N)
+			}
+		}
+
+		if nsavederrors+nerrors != 0 {
+			errorexit()
+		}
+	}
+
+	if Debug['l'] != 0 {
+		// Find functions that can be inlined and clone them before walk expands them.
+		visitBottomUp(xtop, func(list *NodeList, recursive bool) {
+			for l := list; l != nil; l = l.Next {
+				if l.N.Op == ODCLFUNC {
+					caninl(l.N)
+					inlcalls(l.N)
+				}
+			}
+		})
+	}
+
+	// Phase 6: Escape analysis.
+	// Required for moving heap allocations onto stack,
+	// which in turn is required by the closure implementation,
+	// which stores the addresses of stack variables into the closure.
+	// If the closure does not escape, it needs to be on the stack
+	// or else the stack copier will not update it.
+	// Large values are also moved off stack in escape analysis;
+	// because large values may contain pointers, it must happen early.
+	escapes(xtop)
+
+	// Phase 7: Transform closure bodies to properly reference captured variables.
+	// This needs to happen before walk, because closures must be transformed
+	// before walk reaches a call of a closure.
+	for l := xtop; l != nil; l = l.Next {
+		if l.N.Op == ODCLFUNC && l.N.Func.Closure != nil {
+			Curfn = l.N
+			transformclosure(l.N)
+		}
+	}
+
+	Curfn = nil
+
+	// Phase 8: Compile top level functions.
+	for l := xtop; l != nil; l = l.Next {
+		if l.N.Op == ODCLFUNC {
+			funccompile(l.N)
+		}
+	}
+
+	if nsavederrors+nerrors == 0 {
+		fninit(xtop)
+	}
+
+	// Phase 9: Check external declarations.
+	for l := externdcl; l != nil; l = l.Next {
+		if l.N.Op == ONAME {
+			typecheck(&l.N, Erv)
+		}
+	}
+
+	if nerrors+nsavederrors != 0 {
+		errorexit()
+	}
+
+	dumpobj()
+
+	if asmhdr != "" {
+		dumpasmhdr()
+	}
+
+	if nerrors+nsavederrors != 0 {
+		errorexit()
+	}
+
+	Flusherrors()
+}
+
+var importMap = map[string]string{}
+
+func addImportMap(s string) {
+	if strings.Count(s, "=") != 1 {
+		log.Fatal("-importmap argument must be of the form source=actual")
+	}
+	i := strings.Index(s, "=")
+	source, actual := s[:i], s[i+1:]
+	if source == "" || actual == "" {
+		log.Fatal("-importmap argument must be of the form source=actual; source and actual must be non-empty")
+	}
+	importMap[source] = actual
+}
+
+func saveerrors() {
+	nsavederrors += nerrors
+	nerrors = 0
+}
+
+func arsize(b *obj.Biobuf, name string) int {
+	var buf [ArhdrSize]byte
+	if _, err := io.ReadFull(b, buf[:]); err != nil {
+		return -1
+	}
+	aname := strings.Trim(string(buf[0:16]), " ")
+	if !strings.HasPrefix(aname, name) {
+		return -1
+	}
+	asize := strings.Trim(string(buf[48:58]), " ")
+	i, _ := strconv.Atoi(asize)
+	return i
+}
+
+func skiptopkgdef(b *obj.Biobuf) bool {
+	/* archive header */
+	p := obj.Brdline(b, '\n')
+	if p == "" {
+		return false
+	}
+	if obj.Blinelen(b) != 8 {
+		return false
+	}
+	if p != "!<arch>\n" {
+		return false
+	}
+
+	/* symbol table may be first; skip it */
+	sz := arsize(b, "__.GOSYMDEF")
+
+	if sz >= 0 {
+		obj.Bseek(b, int64(sz), 1)
+	} else {
+		obj.Bseek(b, 8, 0)
+	}
+
+	/* package export block is next */
+	sz = arsize(b, "__.PKGDEF")
+
+	if sz <= 0 {
+		return false
+	}
+	return true
+}
+
+func addidir(dir string) {
+	if dir == "" {
+		return
+	}
+
+	var pp **Idir
+	for pp = &idirs; *pp != nil; pp = &(*pp).link {
+	}
+	*pp = new(Idir)
+	(*pp).link = nil
+	(*pp).dir = dir
+}
+
+// is this path a local name?  begins with ./ or ../ or /
+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 string) (file string, ok bool) {
+	if islocalname(name) {
+		if safemode != 0 || nolocalimports != 0 {
+			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.
+		file = fmt.Sprintf("%s.a", name)
+		if obj.Access(file, 0) >= 0 {
+			return file, true
+		}
+		file = fmt.Sprintf("%s.o", name)
+		if obj.Access(file, 0) >= 0 {
+			return file, true
+		}
+		return "", false
+	}
+
+	// local imports should be canonicalized already.
+	// don't want to see "encoding/../encoding/base64"
+	// as different from "encoding/base64".
+	var q string
+	_ = q
+	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 {
+		file = fmt.Sprintf("%s/%s.a", p.dir, name)
+		if obj.Access(file, 0) >= 0 {
+			return file, true
+		}
+		file = fmt.Sprintf("%s/%s.o", p.dir, name)
+		if obj.Access(file, 0) >= 0 {
+			return file, true
+		}
+	}
+
+	if goroot != "" {
+		suffix := ""
+		suffixsep := ""
+		if flag_installsuffix != "" {
+			suffixsep = "_"
+			suffix = flag_installsuffix
+		} else if flag_race != 0 {
+			suffixsep = "_"
+			suffix = "race"
+		}
+
+		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
+		}
+		file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.o", goroot, goos, goarch, suffixsep, suffix, name)
+		if obj.Access(file, 0) >= 0 {
+			return file, true
+		}
+	}
+
+	return "", false
+}
+
+func fakeimport() {
+	importpkg = mkpkg("fake")
+	cannedimports("fake.o", "$$\n")
+}
+
+func importfile(f *Val, line int) {
+	if _, ok := f.U.(string); !ok {
+		Yyerror("import statement not a string")
+		fakeimport()
+		return
+	}
+
+	if len(f.U.(string)) == 0 {
+		Yyerror("import path is empty")
+		fakeimport()
+		return
+	}
+
+	if isbadimport(f.U.(string)) {
+		fakeimport()
+		return
+	}
+
+	// The package name main is no longer reserved,
+	// 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.(string) == "main" {
+		Yyerror("cannot import \"main\"")
+		errorexit()
+	}
+
+	if myimportpath != "" && f.U.(string) == myimportpath {
+		Yyerror("import %q while compiling that package (import cycle)", f.U.(string))
+		errorexit()
+	}
+
+	if f.U.(string) == "unsafe" {
+		if safemode != 0 {
+			Yyerror("cannot import package unsafe")
+			errorexit()
+		}
+
+		importpkg = mkpkg(f.U.(string))
+		cannedimports("unsafe.o", unsafeimport)
+		imported_unsafe = 1
+		return
+	}
+
+	path_ := f.U.(string)
+
+	if mapped, ok := importMap[path_]; ok {
+		path_ = mapped
+	}
+
+	if islocalname(path_) {
+		if path_[0] == '/' {
+			Yyerror("import path cannot be absolute path")
+			fakeimport()
+			return
+		}
+
+		prefix := Ctxt.Pathname
+		if localimport != "" {
+			prefix = localimport
+		}
+		cleanbuf := prefix
+		cleanbuf += "/"
+		cleanbuf += path_
+		cleanbuf = path.Clean(cleanbuf)
+		path_ = cleanbuf
+
+		if isbadimport(path_) {
+			fakeimport()
+			return
+		}
+	}
+
+	file, found := findpkg(path_)
+	if !found {
+		Yyerror("can't find import: %q", f.U.(string))
+		errorexit()
+	}
+
+	importpkg = mkpkg(path_)
+
+	// If we already saw that package, feed a dummy statement
+	// to the lexer to avoid parsing export data twice.
+	if importpkg.Imported != 0 {
+		tag := ""
+		if importpkg.Safe {
+			tag = "safe"
+		}
+
+		p := fmt.Sprintf("package %s %s\n$$\n", importpkg.Name, tag)
+		cannedimports(file, p)
+		return
+	}
+
+	importpkg.Imported = 1
+
+	var err error
+	var imp *obj.Biobuf
+	imp, err = obj.Bopenr(file)
+	if err != nil {
+		Yyerror("can't open import: %q: %v", f.U.(string), err)
+		errorexit()
+	}
+
+	if strings.HasSuffix(file, ".a") {
+		if !skiptopkgdef(imp) {
+			Yyerror("import %s: not a package file", file)
+			errorexit()
+		}
+	}
+
+	// check object header
+	p := obj.Brdstr(imp, '\n', 1)
+
+	if p != "empty archive" {
+		if !strings.HasPrefix(p, "go object ") {
+			Yyerror("import %s: not a go object file", file)
+			errorexit()
+		}
+
+		q := fmt.Sprintf("%s %s %s %s", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion(), obj.Expstring())
+		if p[10:] != q {
+			Yyerror("import %s: object is [%s] expected [%s]", file, p[10:], q)
+			errorexit()
+		}
+	}
+
+	// assume files move (get installed)
+	// so don't record the full path.
+	linehistpragma(file[len(file)-len(path_)-2:]) // acts as #pragma lib
+
+	/*
+	 * position the input right
+	 * after $$ and return
+	 */
+	pushedio = curio
+
+	curio.bin = imp
+	curio.peekc = 0
+	curio.peekc1 = 0
+	curio.infile = file
+	curio.nlsemi = 0
+	typecheckok = 1
+
+	var c int32
+	for {
+		c = int32(getc())
+		if c == EOF {
+			break
+		}
+		if c != '$' {
+			continue
+		}
+		c = int32(getc())
+		if c == EOF {
+			break
+		}
+		if c != '$' {
+			continue
+		}
+		return
+	}
+
+	Yyerror("no import in %q", f.U.(string))
+	unimportfile()
+}
+
+func unimportfile() {
+	if curio.bin != nil {
+		obj.Bterm(curio.bin)
+		curio.bin = nil
+	} else {
+		lexlineno-- // re correct sys.6 line number
+	}
+
+	curio = pushedio
+
+	pushedio.bin = nil
+	incannedimport = 0
+	typecheckok = 0
+}
+
+func cannedimports(file string, cp string) {
+	lexlineno++ // if sys.6 is included on line 1,
+
+	pushedio = curio
+
+	curio.bin = nil
+	curio.peekc = 0
+	curio.peekc1 = 0
+	curio.infile = file
+	curio.cp = cp
+	curio.nlsemi = 0
+	curio.importsafe = false
+
+	typecheckok = 1
+	incannedimport = 1
+}
+
+func isfrog(c int) bool {
+	// complain about possibly invisible control characters
+	if c < ' ' {
+		return !yy_isspace(c) // exclude good white space
+	}
+
+	if 0x7f <= c && c <= 0xa0 { // DEL, unicode block including unbreakable space.
+		return true
+	}
+	return false
+}
+
+type Loophack struct {
+	v    int
+	next *Loophack
+}
+
+var _yylex_lstk *Loophack
+
+func _yylex(yylval *yySymType) int32 {
+	var c1 int
+	var escflag int
+	var v int64
+	var cp *bytes.Buffer
+	var rune_ uint
+	var s *Sym
+	var h *Loophack
+	var str string
+
+	prevlineno = lineno
+
+l0:
+	c := getc()
+	if yy_isspace(c) {
+		if c == '\n' && curio.nlsemi != 0 {
+			ungetc(c)
+			if Debug['x'] != 0 {
+				fmt.Printf("lex: implicit semi\n")
+			}
+			return ';'
+		}
+
+		goto l0
+	}
+
+	lineno = lexlineno /* start of token */
+
+	if c >= utf8.RuneSelf {
+		/* all multibyte runes are alpha */
+		cp = &lexbuf
+		cp.Reset()
+
+		goto talph
+	}
+
+	if yy_isalpha(c) {
+		cp = &lexbuf
+		cp.Reset()
+		goto talph
+	}
+
+	if yy_isdigit(c) {
+		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 {
+	case EOF:
+		lineno = prevlineno
+		ungetc(EOF)
+		return -1
+
+	case '_':
+		cp = &lexbuf
+		cp.Reset()
+		goto talph
+
+	case '.':
+		c1 = getc()
+		if yy_isdigit(c1) {
+			cp = &lexbuf
+			cp.Reset()
+			cp.WriteByte(byte(c))
+			c = c1
+			goto casedot
+		}
+
+		if c1 == '.' {
+			c1 = getc()
+			if c1 == '.' {
+				c = LDDD
+				goto lx
+			}
+
+			ungetc(c1)
+			c1 = '.'
+		}
+
+		/* "..." */
+	case '"':
+		lexbuf.Reset()
+		lexbuf.WriteString(`"<string>"`)
+
+		cp = &strbuf
+		cp.Reset()
+
+		for {
+			if escchar('"', &escflag, &v) {
+				break
+			}
+			if v < utf8.RuneSelf || escflag != 0 {
+				cp.WriteByte(byte(v))
+			} else {
+				rune_ = uint(v)
+				cp.WriteRune(rune(rune_))
+			}
+		}
+
+		goto strlit
+
+		/* `...` */
+	case '`':
+		lexbuf.Reset()
+		lexbuf.WriteString("`<string>`")
+
+		cp = &strbuf
+		cp.Reset()
+
+		for {
+			c = int(getr())
+			if c == '\r' {
+				continue
+			}
+			if c == EOF {
+				Yyerror("eof in string")
+				break
+			}
+
+			if c == '`' {
+				break
+			}
+			cp.WriteRune(rune(c))
+		}
+
+		goto strlit
+
+		/* '.' */
+	case '\'':
+		if escchar('\'', &escflag, &v) {
+			Yyerror("empty character literal or unescaped ' in character literal")
+			v = '\''
+		}
+
+		if !escchar('\'', &escflag, &v) {
+			Yyerror("missing '")
+			ungetc(int(v))
+		}
+
+		x := new(Mpint)
+		yylval.val.U = x
+		Mpmovecfix(x, v)
+		x.Rune = true
+		if Debug['x'] != 0 {
+			fmt.Printf("lex: codepoint literal\n")
+		}
+		litbuf = "string literal"
+		return LLITERAL
+
+	case '/':
+		c1 = getc()
+		if c1 == '*' {
+			nl := 0
+			for {
+				c = int(getr())
+				if c == '\n' {
+					nl = 1
+				}
+				for c == '*' {
+					c = int(getr())
+					if c == '/' {
+						if nl != 0 {
+							ungetc('\n')
+						}
+						goto l0
+					}
+
+					if c == '\n' {
+						nl = 1
+					}
+				}
+
+				if c == EOF {
+					Yyerror("eof in comment")
+					errorexit()
+				}
+			}
+		}
+
+		if c1 == '/' {
+			c = getlinepragma()
+			for {
+				if c == '\n' || c == EOF {
+					ungetc(c)
+					goto l0
+				}
+
+				c = int(getr())
+			}
+		}
+
+		if c1 == '=' {
+			c = ODIV
+			goto asop
+		}
+
+	case ':':
+		c1 = getc()
+		if c1 == '=' {
+			c = LCOLAS
+			yylval.i = int(lexlineno)
+			goto lx
+		}
+
+	case '*':
+		c1 = getc()
+		if c1 == '=' {
+			c = OMUL
+			goto asop
+		}
+
+	case '%':
+		c1 = getc()
+		if c1 == '=' {
+			c = OMOD
+			goto asop
+		}
+
+	case '+':
+		c1 = getc()
+		if c1 == '+' {
+			c = LINC
+			goto lx
+		}
+
+		if c1 == '=' {
+			c = OADD
+			goto asop
+		}
+
+	case '-':
+		c1 = getc()
+		if c1 == '-' {
+			c = LDEC
+			goto lx
+		}
+
+		if c1 == '=' {
+			c = OSUB
+			goto asop
+		}
+
+	case '>':
+		c1 = getc()
+		if c1 == '>' {
+			c = LRSH
+			c1 = getc()
+			if c1 == '=' {
+				c = ORSH
+				goto asop
+			}
+
+			break
+		}
+
+		if c1 == '=' {
+			c = LGE
+			goto lx
+		}
+
+		c = LGT
+
+	case '<':
+		c1 = getc()
+		if c1 == '<' {
+			c = LLSH
+			c1 = getc()
+			if c1 == '=' {
+				c = OLSH
+				goto asop
+			}
+
+			break
+		}
+
+		if c1 == '=' {
+			c = LLE
+			goto lx
+		}
+
+		if c1 == '-' {
+			c = LCOMM
+			goto lx
+		}
+
+		c = LLT
+
+	case '=':
+		c1 = getc()
+		if c1 == '=' {
+			c = LEQ
+			goto lx
+		}
+
+	case '!':
+		c1 = getc()
+		if c1 == '=' {
+			c = LNE
+			goto lx
+		}
+
+	case '&':
+		c1 = getc()
+		if c1 == '&' {
+			c = LANDAND
+			goto lx
+		}
+
+		if c1 == '^' {
+			c = LANDNOT
+			c1 = getc()
+			if c1 == '=' {
+				c = OANDNOT
+				goto asop
+			}
+
+			break
+		}
+
+		if c1 == '=' {
+			c = OAND
+			goto asop
+		}
+
+	case '|':
+		c1 = getc()
+		if c1 == '|' {
+			c = LOROR
+			goto lx
+		}
+
+		if c1 == '=' {
+			c = OOR
+			goto asop
+		}
+
+	case '^':
+		c1 = getc()
+		if c1 == '=' {
+			c = OXOR
+			goto asop
+		}
+
+		/*
+		 * clumsy dance:
+		 * to implement rule that disallows
+		 *	if T{1}[0] { ... }
+		 * but allows
+		 * 	if (T{1}[0]) { ... }
+		 * the block bodies for if/for/switch/select
+		 * begin with an LBODY token, not '{'.
+		 *
+		 * when we see the keyword, the next
+		 * non-parenthesized '{' becomes an LBODY.
+		 * loophack is normally 0.
+		 * a keyword makes it go up to 1.
+		 * parens push loophack onto a stack and go back to 0.
+		 * a '{' with loophack == 1 becomes LBODY and disables loophack.
+		 *
+		 * i said it was clumsy.
+		 */
+	case '(', '[':
+		if loophack != 0 || _yylex_lstk != nil {
+			h = new(Loophack)
+			if h == nil {
+				Flusherrors()
+				Yyerror("out of memory")
+				errorexit()
+			}
+
+			h.v = loophack
+			h.next = _yylex_lstk
+			_yylex_lstk = h
+			loophack = 0
+		}
+
+		goto lx
+
+	case ')', ']':
+		if _yylex_lstk != nil {
+			h = _yylex_lstk
+			loophack = h.v
+			_yylex_lstk = h.next
+		}
+
+		goto lx
+
+	case '{':
+		if loophack == 1 {
+			if Debug['x'] != 0 {
+				fmt.Printf("%v lex: LBODY\n", Ctxt.Line(int(lexlineno)))
+			}
+			loophack = 0
+			return LBODY
+		}
+
+		goto lx
+
+	default:
+		goto lx
+	}
+
+	ungetc(c1)
+
+lx:
+	if c > 0xff {
+		if Debug['x'] != 0 {
+			fmt.Printf("%v lex: TOKEN %s\n", Ctxt.Line(int(lexlineno)), lexname(c))
+		}
+	} else {
+		if Debug['x'] != 0 {
+			fmt.Printf("%v lex: TOKEN '%c'\n", Ctxt.Line(int(lexlineno)), c)
+		}
+	}
+	if isfrog(c) {
+		Yyerror("illegal character 0x%x", uint(c))
+		goto l0
+	}
+
+	if importpkg == nil && (c == '#' || c == '$' || c == '?' || c == '@' || c == '\\') {
+		Yyerror("%s: unexpected %c", "syntax error", c)
+		goto l0
+	}
+
+	return int32(c)
+
+asop:
+	yylval.i = c // rathole to hold which asop
+	if Debug['x'] != 0 {
+		fmt.Printf("lex: TOKEN ASOP %c\n", c)
+	}
+	return LASOP
+
+	/*
+	 * cp is set to lexbuf and some
+	 * prefix has been stored
+	 */
+talph:
+	for {
+		if c >= utf8.RuneSelf {
+			ungetc(c)
+			rune_ = uint(getr())
+
+			// 0xb7 · is used for internal names
+			if !unicode.IsLetter(rune(rune_)) && !unicode.IsDigit(rune(rune_)) && (importpkg == nil || rune_ != 0xb7) {
+				Yyerror("invalid identifier character U+%04x", rune_)
+			}
+			cp.WriteRune(rune(rune_))
+		} else if !yy_isalnum(c) && c != '_' {
+			break
+		} else {
+			cp.WriteByte(byte(c))
+		}
+		c = getc()
+	}
+
+	cp = nil
+	ungetc(c)
+
+	s = LookupBytes(lexbuf.Bytes())
+	switch s.Lexical {
+	case LIGNORE:
+		goto l0
+
+	case LFOR, LIF, LSWITCH, LSELECT:
+		loophack = 1 // see comment about loophack above
+	}
+
+	if Debug['x'] != 0 {
+		fmt.Printf("lex: %s %s\n", s, lexname(int(s.Lexical)))
+	}
+	yylval.sym = s
+	return int32(s.Lexical)
+
+ncu:
+	cp = nil
+	ungetc(c)
+
+	str = lexbuf.String()
+	yylval.val.U = new(Mpint)
+	mpatofix(yylval.val.U.(*Mpint), str)
+	if yylval.val.U.(*Mpint).Ovf {
+		Yyerror("overflow in constant")
+		Mpmovecfix(yylval.val.U.(*Mpint), 0)
+	}
+
+	if Debug['x'] != 0 {
+		fmt.Printf("lex: integer literal\n")
+	}
+	litbuf = "literal " + str
+	return LLITERAL
+
+casedot:
+	for {
+		cp.WriteByte(byte(c))
+		c = getc()
+		if !yy_isdigit(c) {
+			break
+		}
+	}
+
+	if c == 'i' {
+		goto casei
+	}
+	if c != 'e' && c != 'E' {
+		goto caseout
+	}
+
+caseep:
+	if importpkg == nil && (c == 'p' || c == 'P') {
+		// <mantissa>p<base-2-exponent> is allowed in .a/.o imports,
+		// but not in .go sources.  See #9036.
+		Yyerror("malformed floating point constant")
+	}
+	cp.WriteByte(byte(c))
+	c = getc()
+	if c == '+' || c == '-' {
+		cp.WriteByte(byte(c))
+		c = getc()
+	}
+
+	if !yy_isdigit(c) {
+		Yyerror("malformed floating point constant exponent")
+	}
+	for yy_isdigit(c) {
+		cp.WriteByte(byte(c))
+		c = getc()
+	}
+
+	if c == 'i' {
+		goto casei
+	}
+	goto caseout
+
+	// imaginary constant
+casei:
+	cp = nil
+
+	str = lexbuf.String()
+	yylval.val.U = new(Mpcplx)
+	Mpmovecflt(&yylval.val.U.(*Mpcplx).Real, 0.0)
+	mpatoflt(&yylval.val.U.(*Mpcplx).Imag, str)
+	if yylval.val.U.(*Mpcplx).Imag.Val.IsInf() {
+		Yyerror("overflow in imaginary constant")
+		Mpmovecflt(&yylval.val.U.(*Mpcplx).Real, 0.0)
+	}
+
+	if Debug['x'] != 0 {
+		fmt.Printf("lex: imaginary literal\n")
+	}
+	litbuf = "literal " + str
+	return LLITERAL
+
+caseout:
+	cp = nil
+	ungetc(c)
+
+	str = lexbuf.String()
+	yylval.val.U = newMpflt()
+	mpatoflt(yylval.val.U.(*Mpflt), str)
+	if yylval.val.U.(*Mpflt).Val.IsInf() {
+		Yyerror("overflow in float constant")
+		Mpmovecflt(yylval.val.U.(*Mpflt), 0.0)
+	}
+
+	if Debug['x'] != 0 {
+		fmt.Printf("lex: floating literal\n")
+	}
+	litbuf = "literal " + str
+	return LLITERAL
+
+strlit:
+	yylval.val.U = internString(cp.Bytes())
+	if Debug['x'] != 0 {
+		fmt.Printf("lex: string literal\n")
+	}
+	litbuf = "string literal"
+	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])) {
+		p = p[1:]
+	}
+	*pp = p
+	return p != ""
+}
+
+/*
+ * read and interpret syntax that looks like
+ * //line parse.y:15
+ * as a discontinuity in sequential line numbers.
+ * the next line of input comes from parse.y:15
+ */
+func getlinepragma() int {
+	var cmd, verb, name string
+
+	c := int(getr())
+	if c == 'g' {
+		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 := strings.TrimSuffix(lexbuf.String(), "\r")
+
+		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:norace" {
+			norace = true
+			return c
+		}
+
+		if verb == "go:nosplit" {
+			nosplit = true
+			return c
+		}
+
+		if verb == "go:systemstack" {
+			systemstack = 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' {
+		return c
+	}
+	for i := 1; i < 5; i++ {
+		c = int(getr())
+		if c != int("line "[i]) {
+			return c
+		}
+	}
+
+	cp := &lexbuf
+	cp.Reset()
+	linep := 0
+	for {
+		c = int(getr())
+		if c == EOF {
+			return c
+		}
+		if c == '\n' {
+			break
+		}
+		if c == ' ' {
+			continue
+		}
+		if c == ':' {
+			linep = cp.Len() + 1
+		}
+		cp.WriteByte(byte(c))
+	}
+
+	cp = nil
+
+	if linep == 0 {
+		return c
+	}
+	text := strings.TrimSuffix(lexbuf.String(), "\r")
+	n := 0
+	for _, c := range text[linep:] {
+		if c < '0' || c > '9' {
+			goto out
+		}
+		n = n*10 + int(c) - '0'
+		if n > 1e8 {
+			Yyerror("line number out of range")
+			errorexit()
+		}
+	}
+
+	if n <= 0 {
+		return c
+	}
+
+	name = text[:linep-1]
+	linehistupdate(name, n)
+	return c
+
+out:
+	return c
+}
+
+func getimpsym(pp *string) string {
+	more(pp) // skip spaces
+	p := *pp
+	if p == "" || p[0] == '"' {
+		return ""
+	}
+	i := 0
+	for i < len(p) && !yy_isspace(int(p[i])) && p[i] != '"' {
+		i++
+	}
+	sym := p[:i]
+	*pp = p[i:]
+	return sym
+}
+
+func getquoted(pp *string) (string, bool) {
+	more(pp) // skip spaces
+	p := *pp
+	if p == "" || p[0] != '"' {
+		return "", false
+	}
+	p = p[1:]
+	i := strings.Index(p, `"`)
+	if i < 0 {
+		return "", false
+	}
+	*pp = p[i+1:]
+	return p[:i], true
+}
+
+// Copied nearly verbatim from the C compiler's #pragma parser.
+// TODO: Rewrite more cleanly once the compiler is written in Go.
+func pragcgo(text string) {
+	var q string
+
+	if i := strings.Index(text, " "); i >= 0 {
+		text, q = text[:i], text[i:]
+	}
+
+	verb := text[3:] // skip "go:"
+
+	if verb == "cgo_dynamic_linker" || verb == "dynlinker" {
+		var ok bool
+		var p string
+		p, ok = getquoted(&q)
+		if !ok {
+			Yyerror("usage: //go:cgo_dynamic_linker \"path\"")
+			return
+		}
+		pragcgobuf += fmt.Sprintf("cgo_dynamic_linker %v\n", plan9quote(p))
+		return
+
+	}
+
+	if verb == "dynexport" {
+		verb = "cgo_export_dynamic"
+	}
+	if verb == "cgo_export_static" || verb == "cgo_export_dynamic" {
+		local := getimpsym(&q)
+		var remote string
+		if local == "" {
+			goto err2
+		}
+		if !more(&q) {
+			pragcgobuf += fmt.Sprintf("%s %v\n", verb, plan9quote(local))
+			return
+		}
+
+		remote = getimpsym(&q)
+		if remote == "" {
+			goto err2
+		}
+		pragcgobuf += fmt.Sprintf("%s %v %v\n", verb, plan9quote(local), plan9quote(remote))
+		return
+
+	err2:
+		Yyerror("usage: //go:%s local [remote]", verb)
+		return
+	}
+
+	if verb == "cgo_import_dynamic" || verb == "dynimport" {
+		var ok bool
+		local := getimpsym(&q)
+		var p string
+		var remote string
+		if local == "" {
+			goto err3
+		}
+		if !more(&q) {
+			pragcgobuf += fmt.Sprintf("cgo_import_dynamic %v\n", plan9quote(local))
+			return
+		}
+
+		remote = getimpsym(&q)
+		if remote == "" {
+			goto err3
+		}
+		if !more(&q) {
+			pragcgobuf += fmt.Sprintf("cgo_import_dynamic %v %v\n", plan9quote(local), plan9quote(remote))
+			return
+		}
+
+		p, ok = getquoted(&q)
+		if !ok {
+			goto err3
+		}
+		pragcgobuf += fmt.Sprintf("cgo_import_dynamic %v %v %v\n", plan9quote(local), plan9quote(remote), plan9quote(p))
+		return
+
+	err3:
+		Yyerror("usage: //go:cgo_import_dynamic local [remote [\"library\"]]")
+		return
+	}
+
+	if verb == "cgo_import_static" {
+		local := getimpsym(&q)
+		if local == "" || more(&q) {
+			Yyerror("usage: //go:cgo_import_static local")
+			return
+		}
+		pragcgobuf += fmt.Sprintf("cgo_import_static %v\n", plan9quote(local))
+		return
+
+	}
+
+	if verb == "cgo_ldflag" {
+		var ok bool
+		var p string
+		p, ok = getquoted(&q)
+		if !ok {
+			Yyerror("usage: //go:cgo_ldflag \"arg\"")
+			return
+		}
+		pragcgobuf += fmt.Sprintf("cgo_ldflag %v\n", plan9quote(p))
+		return
+
+	}
+}
+
+type yy struct{}
+
+func (yy) Lex(v *yySymType) int {
+	return int(yylex(v))
+}
+
+func (yy) Error(msg string) {
+	Yyerror("%s", msg)
+}
+
+var theparser yyParser
+var parsing bool
+
+func yyparse() {
+	theparser = yyNewParser()
+	parsing = true
+	theparser.Parse(yy{})
+	parsing = false
+}
+
+func yylex(yylval *yySymType) int32 {
+	lx := int(_yylex(yylval))
+
+	if curio.nlsemi != 0 && lx == EOF {
+		// Treat EOF as "end of line" for the purposes
+		// of inserting a semicolon.
+		lx = ';'
+	}
+
+	switch lx {
+	case LNAME,
+		LLITERAL,
+		LBREAK,
+		LCONTINUE,
+		LFALL,
+		LRETURN,
+		LINC,
+		LDEC,
+		')',
+		'}',
+		']':
+		curio.nlsemi = 1
+
+	default:
+		curio.nlsemi = 0
+	}
+
+	// Track last two tokens returned by yylex.
+	yyprev = yylast
+
+	yylast = lx
+	return int32(lx)
+}
+
+func getc() int {
+	c := curio.peekc
+	if c != 0 {
+		curio.peekc = curio.peekc1
+		curio.peekc1 = 0
+		goto check
+	}
+
+	if curio.bin == nil {
+		if len(curio.cp) == 0 {
+			c = 0
+		} else {
+			c = int(curio.cp[0])
+			curio.cp = curio.cp[1:]
+		}
+	} else {
+	loop:
+		c = obj.Bgetc(curio.bin)
+		if c == 0xef {
+			buf, err := curio.bin.Peek(2)
+			if err != nil {
+				log.Fatalf("getc: peeking: %v", err)
+			}
+			if buf[0] == 0xbb && buf[1] == 0xbf {
+				yyerrorl(int(lexlineno), "Unicode (UTF-8) BOM in middle of file")
+
+				// consume BOM bytes
+				obj.Bgetc(curio.bin)
+				obj.Bgetc(curio.bin)
+				goto loop
+			}
+		}
+	}
+
+check:
+	switch c {
+	case 0:
+		if curio.bin != nil {
+			Yyerror("illegal NUL byte")
+			break
+		}
+		fallthrough
+
+		// insert \n at EOF
+	case EOF:
+		if curio.eofnl != 0 || curio.last == '\n' {
+			return EOF
+		}
+		curio.eofnl = 1
+		c = '\n'
+		fallthrough
+
+	case '\n':
+		if pushedio.bin == nil {
+			lexlineno++
+		}
+	}
+
+	curio.last = c
+	return c
+}
+
+func ungetc(c int) {
+	curio.peekc1 = curio.peekc
+	curio.peekc = c
+	if c == '\n' && pushedio.bin == nil {
+		lexlineno--
+	}
+}
+
+func getr() int32 {
+	var buf [utf8.UTFMax]byte
+
+	for i := 0; ; i++ {
+		c := getc()
+		if i == 0 && c < utf8.RuneSelf {
+			return int32(c)
+		}
+		buf[i] = byte(c)
+		if i+1 == len(buf) || utf8.FullRune(buf[:i+1]) {
+			r, w := utf8.DecodeRune(buf[:i+1])
+			if r == utf8.RuneError && w == 1 {
+				lineno = lexlineno
+				// 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)
+		}
+	}
+}
+
+func escchar(e int, escflg *int, val *int64) bool {
+	*escflg = 0
+
+	c := int(getr())
+	switch c {
+	case EOF:
+		Yyerror("eof in string")
+		return true
+
+	case '\n':
+		Yyerror("newline in string")
+		return true
+
+	case '\\':
+		break
+
+	default:
+		if c == e {
+			return true
+		}
+		*val = int64(c)
+		return false
+	}
+
+	u := 0
+	c = int(getr())
+	var i int
+	switch c {
+	case 'x':
+		*escflg = 1 // it's a byte
+		i = 2
+		goto hex
+
+	case 'u':
+		i = 4
+		u = 1
+		goto hex
+
+	case 'U':
+		i = 8
+		u = 1
+		goto hex
+
+	case '0',
+		'1',
+		'2',
+		'3',
+		'4',
+		'5',
+		'6',
+		'7':
+		*escflg = 1 // it's a byte
+		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'
+	case 'b':
+		c = '\b'
+	case 'f':
+		c = '\f'
+	case 'n':
+		c = '\n'
+	case 'r':
+		c = '\r'
+	case 't':
+		c = '\t'
+	case 'v':
+		c = '\v'
+	case '\\':
+		c = '\\'
+
+	default:
+		if c != e {
+			Yyerror("unknown escape sequence: %c", c)
+		}
+	}
+
+	*val = int64(c)
+	return false
+
+hex:
+	l := int64(0)
+	for ; i > 0; i-- {
+		c = getc()
+		if c >= '0' && c <= '9' {
+			l = l*16 + int64(c) - '0'
+			continue
+		}
+
+		if c >= 'a' && c <= 'f' {
+			l = l*16 + int64(c) - 'a' + 10
+			continue
+		}
+
+		if c >= 'A' && c <= 'F' {
+			l = l*16 + int64(c) - 'A' + 10
+			continue
+		}
+
+		Yyerror("non-hex character in escape sequence: %c", c)
+		ungetc(c)
+		break
+	}
+
+	if u != 0 && (l > utf8.MaxRune || (0xd800 <= l && l < 0xe000)) {
+		Yyerror("invalid Unicode code point in escape sequence: %#x", l)
+		l = utf8.RuneError
+	}
+
+	*val = l
+	return false
+}
+
+var syms = []struct {
+	name    string
+	lexical int
+	etype   int
+	op      int
+}{
+	/* basic types */
+	{"int8", LNAME, TINT8, OXXX},
+	{"int16", LNAME, TINT16, OXXX},
+	{"int32", LNAME, TINT32, OXXX},
+	{"int64", LNAME, TINT64, OXXX},
+	{"uint8", LNAME, TUINT8, OXXX},
+	{"uint16", LNAME, TUINT16, OXXX},
+	{"uint32", LNAME, TUINT32, OXXX},
+	{"uint64", LNAME, TUINT64, OXXX},
+	{"float32", LNAME, TFLOAT32, OXXX},
+	{"float64", LNAME, TFLOAT64, OXXX},
+	{"complex64", LNAME, TCOMPLEX64, OXXX},
+	{"complex128", LNAME, TCOMPLEX128, OXXX},
+	{"bool", LNAME, TBOOL, OXXX},
+	{"string", LNAME, TSTRING, OXXX},
+	{"any", LNAME, TANY, OXXX},
+	{"break", LBREAK, Txxx, OXXX},
+	{"case", LCASE, Txxx, OXXX},
+	{"chan", LCHAN, Txxx, OXXX},
+	{"const", LCONST, Txxx, OXXX},
+	{"continue", LCONTINUE, Txxx, OXXX},
+	{"default", LDEFAULT, Txxx, OXXX},
+	{"else", LELSE, Txxx, OXXX},
+	{"defer", LDEFER, Txxx, OXXX},
+	{"fallthrough", LFALL, Txxx, OXXX},
+	{"for", LFOR, Txxx, OXXX},
+	{"func", LFUNC, Txxx, OXXX},
+	{"go", LGO, Txxx, OXXX},
+	{"goto", LGOTO, Txxx, OXXX},
+	{"if", LIF, Txxx, OXXX},
+	{"import", LIMPORT, Txxx, OXXX},
+	{"interface", LINTERFACE, Txxx, OXXX},
+	{"map", LMAP, Txxx, OXXX},
+	{"package", LPACKAGE, Txxx, OXXX},
+	{"range", LRANGE, Txxx, OXXX},
+	{"return", LRETURN, Txxx, OXXX},
+	{"select", LSELECT, Txxx, OXXX},
+	{"struct", LSTRUCT, Txxx, OXXX},
+	{"switch", LSWITCH, Txxx, OXXX},
+	{"type", LTYPE, Txxx, OXXX},
+	{"var", LVAR, Txxx, OXXX},
+	{"append", LNAME, Txxx, OAPPEND},
+	{"cap", LNAME, Txxx, OCAP},
+	{"close", LNAME, Txxx, OCLOSE},
+	{"complex", LNAME, Txxx, OCOMPLEX},
+	{"copy", LNAME, Txxx, OCOPY},
+	{"delete", LNAME, Txxx, ODELETE},
+	{"imag", LNAME, Txxx, OIMAG},
+	{"len", LNAME, Txxx, OLEN},
+	{"make", LNAME, Txxx, OMAKE},
+	{"new", LNAME, Txxx, ONEW},
+	{"panic", LNAME, Txxx, OPANIC},
+	{"print", LNAME, Txxx, OPRINT},
+	{"println", LNAME, Txxx, OPRINTN},
+	{"real", LNAME, Txxx, OREAL},
+	{"recover", LNAME, Txxx, ORECOVER},
+	{"notwithstanding", LIGNORE, Txxx, OXXX},
+	{"thetruthofthematter", LIGNORE, Txxx, OXXX},
+	{"despiteallobjections", LIGNORE, Txxx, OXXX},
+	{"whereas", LIGNORE, Txxx, OXXX},
+	{"insofaras", LIGNORE, Txxx, OXXX},
+}
+
+func lexinit() {
+	var lex int
+	var s *Sym
+	var s1 *Sym
+	var t *Type
+	var etype int
+
+	/*
+	 * initialize basic types array
+	 * initialize known symbols
+	 */
+	for i := 0; i < len(syms); i++ {
+		lex = syms[i].lexical
+		s = Lookup(syms[i].name)
+		s.Lexical = uint16(lex)
+
+		etype = syms[i].etype
+		if etype != Txxx {
+			if etype < 0 || etype >= len(Types) {
+				Fatal("lexinit: %s bad etype", s.Name)
+			}
+			s1 = Pkglookup(syms[i].name, builtinpkg)
+			t = Types[etype]
+			if t == nil {
+				t = typ(etype)
+				t.Sym = s1
+
+				if etype != TANY && etype != TSTRING {
+					dowidth(t)
+				}
+				Types[etype] = t
+			}
+
+			s1.Lexical = LNAME
+			s1.Def = typenod(t)
+			s1.Def.Name = new(Name)
+			continue
+		}
+
+		etype = syms[i].op
+		if etype != OXXX {
+			s1 = Pkglookup(syms[i].name, builtinpkg)
+			s1.Lexical = LNAME
+			s1.Def = Nod(ONAME, nil, nil)
+			s1.Def.Sym = s1
+			s1.Def.Etype = uint8(etype)
+		}
+	}
+
+	// logically, the type of a string literal.
+	// types[TSTRING] is the named type string
+	// (the type of x in var x string or var x = "hello").
+	// this is the ideal form
+	// (the type of x in const x = "hello").
+	idealstring = typ(TSTRING)
+
+	idealbool = typ(TBOOL)
+
+	s = Pkglookup("true", builtinpkg)
+	s.Def = Nodbool(true)
+	s.Def.Sym = Lookup("true")
+	s.Def.Name = new(Name)
+	s.Def.Type = idealbool
+
+	s = Pkglookup("false", builtinpkg)
+	s.Def = Nodbool(false)
+	s.Def.Sym = Lookup("false")
+	s.Def.Name = new(Name)
+	s.Def.Type = idealbool
+
+	s = Lookup("_")
+	s.Block = -100
+	s.Def = Nod(ONAME, nil, nil)
+	s.Def.Sym = s
+	Types[TBLANK] = typ(TBLANK)
+	s.Def.Type = Types[TBLANK]
+	nblank = s.Def
+
+	s = Pkglookup("_", builtinpkg)
+	s.Block = -100
+	s.Def = Nod(ONAME, nil, nil)
+	s.Def.Sym = s
+	Types[TBLANK] = typ(TBLANK)
+	s.Def.Type = Types[TBLANK]
+
+	Types[TNIL] = typ(TNIL)
+	s = Pkglookup("nil", builtinpkg)
+	var v Val
+	v.U = new(NilVal)
+	s.Def = nodlit(v)
+	s.Def.Sym = s
+	s.Def.Name = new(Name)
+}
+
+func lexinit1() {
+	// t = interface { Error() string }
+	rcvr := typ(TSTRUCT)
+
+	rcvr.Type = typ(TFIELD)
+	rcvr.Type.Type = Ptrto(typ(TSTRUCT))
+	rcvr.Funarg = 1
+	in := typ(TSTRUCT)
+	in.Funarg = 1
+	out := typ(TSTRUCT)
+	out.Type = typ(TFIELD)
+	out.Type.Type = Types[TSTRING]
+	out.Funarg = 1
+	f := typ(TFUNC)
+	*getthis(f) = rcvr
+	*Getoutarg(f) = out
+	*getinarg(f) = in
+	f.Thistuple = 1
+	f.Intuple = 0
+	f.Outnamed = 0
+	f.Outtuple = 1
+	t := typ(TINTER)
+	t.Type = typ(TFIELD)
+	t.Type.Sym = Lookup("Error")
+	t.Type.Type = f
+
+	// error type
+	s := Lookup("error")
+
+	s.Lexical = LNAME
+	s1 := Pkglookup("error", builtinpkg)
+	errortype = t
+	errortype.Sym = s1
+	s1.Lexical = LNAME
+	s1.Def = typenod(errortype)
+
+	// byte alias
+	s = Lookup("byte")
+
+	s.Lexical = LNAME
+	s1 = Pkglookup("byte", builtinpkg)
+	bytetype = typ(TUINT8)
+	bytetype.Sym = s1
+	s1.Lexical = LNAME
+	s1.Def = typenod(bytetype)
+	s1.Def.Name = new(Name)
+
+	// rune alias
+	s = Lookup("rune")
+
+	s.Lexical = LNAME
+	s1 = Pkglookup("rune", builtinpkg)
+	runetype = typ(TINT32)
+	runetype.Sym = s1
+	s1.Lexical = LNAME
+	s1.Def = typenod(runetype)
+	s1.Def.Name = new(Name)
+}
+
+func lexfini() {
+	var s *Sym
+	var lex int
+	var etype int
+	var i int
+
+	for i = 0; i < len(syms); i++ {
+		lex = syms[i].lexical
+		if lex != LNAME {
+			continue
+		}
+		s = Lookup(syms[i].name)
+		s.Lexical = uint16(lex)
+
+		etype = syms[i].etype
+		if etype != Txxx && (etype != TANY || Debug['A'] != 0) && s.Def == nil {
+			s.Def = typenod(Types[etype])
+			s.Def.Name = new(Name)
+			s.Origpkg = builtinpkg
+		}
+
+		etype = syms[i].op
+		if etype != OXXX && s.Def == nil {
+			s.Def = Nod(ONAME, nil, nil)
+			s.Def.Sym = s
+			s.Def.Etype = uint8(etype)
+			s.Origpkg = builtinpkg
+		}
+	}
+
+	// backend-specific builtin types (e.g. int).
+	for i = range Thearch.Typedefs {
+		s = Lookup(Thearch.Typedefs[i].Name)
+		if s.Def == nil {
+			s.Def = typenod(Types[Thearch.Typedefs[i].Etype])
+			s.Def.Name = new(Name)
+			s.Origpkg = builtinpkg
+		}
+	}
+
+	// there's only so much table-driven we can handle.
+	// these are special cases.
+	s = Lookup("byte")
+
+	if s.Def == nil {
+		s.Def = typenod(bytetype)
+		s.Def.Name = new(Name)
+		s.Origpkg = builtinpkg
+	}
+
+	s = Lookup("error")
+	if s.Def == nil {
+		s.Def = typenod(errortype)
+		s.Def.Name = new(Name)
+		s.Origpkg = builtinpkg
+	}
+
+	s = Lookup("rune")
+	if s.Def == nil {
+		s.Def = typenod(runetype)
+		s.Def.Name = new(Name)
+		s.Origpkg = builtinpkg
+	}
+
+	s = Lookup("nil")
+	if s.Def == nil {
+		var v Val
+		v.U = new(NilVal)
+		s.Def = nodlit(v)
+		s.Def.Sym = s
+		s.Def.Name = new(Name)
+		s.Origpkg = builtinpkg
+	}
+
+	s = Lookup("iota")
+	if s.Def == nil {
+		s.Def = Nod(OIOTA, nil, nil)
+		s.Def.Sym = s
+		s.Origpkg = builtinpkg
+	}
+
+	s = Lookup("true")
+	if s.Def == nil {
+		s.Def = Nodbool(true)
+		s.Def.Sym = s
+		s.Def.Name = new(Name)
+		s.Origpkg = builtinpkg
+	}
+
+	s = Lookup("false")
+	if s.Def == nil {
+		s.Def = Nodbool(false)
+		s.Def.Sym = s
+		s.Def.Name = new(Name)
+		s.Origpkg = builtinpkg
+	}
+
+	nodfp = Nod(ONAME, nil, nil)
+	nodfp.Type = Types[TINT32]
+	nodfp.Xoffset = 0
+	nodfp.Class = PPARAM
+	nodfp.Sym = Lookup(".fp")
+}
+
+var lexn = []struct {
+	lex  int
+	name string
+}{
+	{LANDAND, "ANDAND"},
+	{LANDNOT, "ANDNOT"},
+	{LASOP, "ASOP"},
+	{LBREAK, "BREAK"},
+	{LCASE, "CASE"},
+	{LCHAN, "CHAN"},
+	{LCOLAS, "COLAS"},
+	{LCOMM, "<-"},
+	{LCONST, "CONST"},
+	{LCONTINUE, "CONTINUE"},
+	{LDDD, "..."},
+	{LDEC, "DEC"},
+	{LDEFAULT, "DEFAULT"},
+	{LDEFER, "DEFER"},
+	{LELSE, "ELSE"},
+	{LEQ, "EQ"},
+	{LFALL, "FALL"},
+	{LFOR, "FOR"},
+	{LFUNC, "FUNC"},
+	{LGE, "GE"},
+	{LGO, "GO"},
+	{LGOTO, "GOTO"},
+	{LGT, "GT"},
+	{LIF, "IF"},
+	{LIMPORT, "IMPORT"},
+	{LINC, "INC"},
+	{LINTERFACE, "INTERFACE"},
+	{LLE, "LE"},
+	{LLITERAL, "LITERAL"},
+	{LLSH, "LSH"},
+	{LLT, "LT"},
+	{LMAP, "MAP"},
+	{LNAME, "NAME"},
+	{LNE, "NE"},
+	{LOROR, "OROR"},
+	{LPACKAGE, "PACKAGE"},
+	{LRANGE, "RANGE"},
+	{LRETURN, "RETURN"},
+	{LRSH, "RSH"},
+	{LSELECT, "SELECT"},
+	{LSTRUCT, "STRUCT"},
+	{LSWITCH, "SWITCH"},
+	{LTYPE, "TYPE"},
+	{LVAR, "VAR"},
+}
+
+func lexname(lex int) string {
+	for i := 0; i < len(lexn); i++ {
+		if lexn[i].lex == lex {
+			return lexn[i].name
+		}
+	}
+	return fmt.Sprintf("LEX-%d", lex)
+}
+
+var yytfix = []struct {
+	have string
+	want string
+}{
+	{"$end", "EOF"},
+	{"LASOP", "op="},
+	{"LBREAK", "break"},
+	{"LCASE", "case"},
+	{"LCHAN", "chan"},
+	{"LCOLAS", ":="},
+	{"LCONST", "const"},
+	{"LCONTINUE", "continue"},
+	{"LDDD", "..."},
+	{"LDEFAULT", "default"},
+	{"LDEFER", "defer"},
+	{"LELSE", "else"},
+	{"LFALL", "fallthrough"},
+	{"LFOR", "for"},
+	{"LFUNC", "func"},
+	{"LGO", "go"},
+	{"LGOTO", "goto"},
+	{"LIF", "if"},
+	{"LIMPORT", "import"},
+	{"LINTERFACE", "interface"},
+	{"LMAP", "map"},
+	{"LNAME", "name"},
+	{"LPACKAGE", "package"},
+	{"LRANGE", "range"},
+	{"LRETURN", "return"},
+	{"LSELECT", "select"},
+	{"LSTRUCT", "struct"},
+	{"LSWITCH", "switch"},
+	{"LTYPE", "type"},
+	{"LVAR", "var"},
+	{"LANDAND", "&&"},
+	{"LANDNOT", "&^"},
+	{"LBODY", "{"},
+	{"LCOMM", "<-"},
+	{"LDEC", "--"},
+	{"LINC", "++"},
+	{"LEQ", "=="},
+	{"LGE", ">="},
+	{"LGT", ">"},
+	{"LLE", "<="},
+	{"LLT", "<"},
+	{"LLSH", "<<"},
+	{"LRSH", ">>"},
+	{"LOROR", "||"},
+	{"LNE", "!="},
+	// spell out to avoid confusion with punctuation in error messages
+	{"';'", "semicolon or newline"},
+	{"','", "comma"},
+}
+
+func init() {
+	yyErrorVerbose = true
+
+Outer:
+	for i, s := range yyToknames {
+		// Apply yytfix if possible.
+		for _, fix := range yytfix {
+			if s == fix.have {
+				yyToknames[i] = fix.want
+				continue Outer
+			}
+		}
+
+		// Turn 'x' into x.
+		if len(s) == 3 && s[0] == '\'' && s[2] == '\'' {
+			yyToknames[i] = s[1:2]
+			continue
+		}
+	}
+}
+
+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
+	if i := strings.LastIndex(elem, "/"); i >= 0 {
+		elem = elem[i+1:]
+	}
+	if name == "" || elem == name {
+		yyerrorl(int(lineno), "imported and not used: %q", path)
+	} else {
+		yyerrorl(int(lineno), "imported and not used: %q as %s", path, name)
+	}
+}
+
+func mkpackage(pkgname string) {
+	if localpkg.Name == "" {
+		if pkgname == "_" {
+			Yyerror("invalid package name _")
+		}
+		localpkg.Name = pkgname
+	} else {
+		if pkgname != localpkg.Name {
+			Yyerror("package %s; expected %s", pkgname, localpkg.Name)
+		}
+		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.Name.Pkg.Path, s.Name)
+				}
+				s.Def = nil
+				continue
+			}
+
+			if s.Def.Sym != s {
+				// throw away top-level name left over
+				// from previous import . "x"
+				if s.Def.Name != nil && s.Def.Name.Pack != nil && !s.Def.Name.Pack.Used && nsyntaxerrors == 0 {
+					pkgnotused(int(s.Def.Name.Pack.Lineno), s.Def.Name.Pack.Name.Pkg.Path, "")
+					s.Def.Name.Pack.Used = true
+				}
+
+				s.Def = nil
+				continue
+			}
+		}
+	}
+
+	if outfile == "" {
+		p := infile
+		if i := strings.LastIndex(p, "/"); i >= 0 {
+			p = p[i+1:]
+		}
+		if Ctxt.Windows != 0 {
+			if i := strings.LastIndex(p, `\`); i >= 0 {
+				p = p[i+1:]
+			}
+		}
+		if i := strings.LastIndex(p, "."); i >= 0 {
+			p = p[:i]
+		}
+		suffix := ".o"
+		if writearchive > 0 {
+			suffix = ".a"
+		}
+		outfile = p + suffix
+	}
+}
diff --git a/src/cmd/compile/internal/gc/mkbuiltin.go b/src/cmd/compile/internal/gc/mkbuiltin.go
new file mode 100644
index 0000000..ea3877f
--- /dev/null
+++ b/src/cmd/compile/internal/gc/mkbuiltin.go
@@ -0,0 +1,97 @@
+// 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.
+
+// +build ignore
+
+// Generate builtin.go from $* (runtime.go and unsafe.go).
+// Run this after changing runtime.go and unsafe.go
+// or after changing the export metadata format in the compiler.
+// Either way, you need to have a working compiler binary first.
+package main
+
+import (
+	"bufio"
+	"fmt"
+	"io"
+	"log"
+	"os"
+	"os/exec"
+	"strings"
+)
+
+func main() {
+	f, err := os.Create("builtin.go")
+	if err != nil {
+		log.Fatal(err)
+	}
+	defer f.Close()
+	w := bufio.NewWriter(f)
+
+	fmt.Fprintln(w, "// AUTO-GENERATED by mkbuiltin.go; DO NOT EDIT")
+	fmt.Fprintln(w, "")
+	fmt.Fprintln(w, "package gc")
+
+	for _, name := range os.Args[1:] {
+		mkbuiltin(w, name)
+	}
+
+	if err := w.Flush(); err != nil {
+		log.Fatal(err)
+	}
+}
+
+// Compile .go file, import data from .6 file, and write Go string version.
+func mkbuiltin(w io.Writer, name string) {
+	if err := exec.Command("go", "tool", "compile", "-A", "builtin/"+name+".go").Run(); err != nil {
+		log.Fatal(err)
+	}
+	obj := name + ".o"
+	defer os.Remove(obj)
+
+	r, err := os.Open(obj)
+	if err != nil {
+		log.Fatal(err)
+	}
+	defer r.Close()
+	scanner := bufio.NewScanner(r)
+
+	// Look for $$ that introduces imports.
+	for scanner.Scan() {
+		if strings.Contains(scanner.Text(), "$$") {
+			goto Begin
+		}
+	}
+	log.Fatal("did not find beginning of imports")
+
+Begin:
+	initfunc := fmt.Sprintf("init_%s_function", name)
+
+	fmt.Fprintf(w, "\nconst %simport = \"\" +\n", name)
+
+	// sys.go claims to be in package PACKAGE to avoid
+	// conflicts during "go tool compile sys.go".  Rename PACKAGE to $2.
+	replacer := strings.NewReplacer("PACKAGE", name)
+
+	// Process imports, stopping at $$ that closes them.
+	for scanner.Scan() {
+		p := scanner.Text()
+		if strings.Contains(p, "$$") {
+			goto End
+		}
+
+		// Chop leading white space.
+		p = strings.TrimLeft(p, " \t")
+
+		// Cut out decl of init_$1_function - it doesn't exist.
+		if strings.Contains(p, initfunc) {
+			continue
+		}
+
+		fmt.Fprintf(w, "\t%q +\n", replacer.Replace(p)+"\n")
+	}
+	log.Fatal("did not find end of imports")
+
+End:
+	fmt.Fprintf(w, "\t\"$$\\n\"\n")
+}
diff --git a/src/cmd/compile/internal/gc/mparith2.go b/src/cmd/compile/internal/gc/mparith2.go
new file mode 100644
index 0000000..2c7e517
--- /dev/null
+++ b/src/cmd/compile/internal/gc/mparith2.go
@@ -0,0 +1,300 @@
+// 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/compile/internal/big"
+	"cmd/internal/obj"
+	"fmt"
+)
+
+/// implements fix arithmetic
+
+func mpsetovf(a *Mpint) {
+	a.Val.SetUint64(1) // avoid spurious div-zero errors
+	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.
+	if a.Val.BitLen()+extra > Mpprec {
+		mpsetovf(a)
+	}
+	return a.Ovf
+}
+
+func mpmovefixfix(a, b *Mpint) {
+	a.Val.Set(&b.Val)
+}
+
+func mpmovefltfix(a *Mpint, b *Mpflt) int {
+	if _, acc := b.Val.Int(&a.Val); acc == big.Exact {
+		return 0
+	}
+
+	const delta = 16 // a reasonably small number of bits > 0
+	var t big.Float
+	t.SetPrec(Mpprec - delta)
+
+	// try rounding down a little
+	t.SetMode(big.ToZero)
+	t.Set(&b.Val)
+	if _, acc := t.Int(&a.Val); acc == big.Exact {
+		return 0
+	}
+
+	// try rounding up a little
+	t.SetMode(big.AwayFromZero)
+	t.Set(&b.Val)
+	if _, acc := t.Int(&a.Val); acc == big.Exact {
+		return 0
+	}
+
+	return -1
+}
+
+func mpaddfixfix(a, b *Mpint, quiet int) {
+	if a.Ovf || b.Ovf {
+		if nsavederrors+nerrors == 0 {
+			Yyerror("ovf in mpaddfixfix")
+		}
+		mpsetovf(a)
+		return
+	}
+
+	a.Val.Add(&a.Val, &b.Val)
+
+	if mptestovf(a, 0) && quiet == 0 {
+		Yyerror("constant addition overflow")
+	}
+}
+
+func mpsubfixfix(a, b *Mpint) {
+	if a.Ovf || b.Ovf {
+		if nsavederrors+nerrors == 0 {
+			Yyerror("ovf in mpsubfixfix")
+		}
+		mpsetovf(a)
+		return
+	}
+
+	a.Val.Sub(&a.Val, &b.Val)
+
+	if mptestovf(a, 0) {
+		Yyerror("constant subtraction overflow")
+	}
+}
+
+func mpmulfixfix(a, b *Mpint) {
+	if a.Ovf || b.Ovf {
+		if nsavederrors+nerrors == 0 {
+			Yyerror("ovf in mpmulfixfix")
+		}
+		mpsetovf(a)
+		return
+	}
+
+	a.Val.Mul(&a.Val, &b.Val)
+
+	if mptestovf(a, 0) {
+		Yyerror("constant multiplication overflow")
+	}
+}
+
+func mpdivfixfix(a, b *Mpint) {
+	if a.Ovf || b.Ovf {
+		if nsavederrors+nerrors == 0 {
+			Yyerror("ovf in mpdivfixfix")
+		}
+		mpsetovf(a)
+		return
+	}
+
+	a.Val.Quo(&a.Val, &b.Val)
+
+	if mptestovf(a, 0) {
+		// can only happen for div-0 which should be checked elsewhere
+		Yyerror("constant division overflow")
+	}
+}
+
+func mpmodfixfix(a, b *Mpint) {
+	if a.Ovf || b.Ovf {
+		if nsavederrors+nerrors == 0 {
+			Yyerror("ovf in mpmodfixfix")
+		}
+		mpsetovf(a)
+		return
+	}
+
+	a.Val.Rem(&a.Val, &b.Val)
+
+	if mptestovf(a, 0) {
+		// should never happen
+		Yyerror("constant modulo overflow")
+	}
+}
+
+func mporfixfix(a, b *Mpint) {
+	if a.Ovf || b.Ovf {
+		if nsavederrors+nerrors == 0 {
+			Yyerror("ovf in mporfixfix")
+		}
+		mpsetovf(a)
+		return
+	}
+
+	a.Val.Or(&a.Val, &b.Val)
+}
+
+func mpandfixfix(a, b *Mpint) {
+	if a.Ovf || b.Ovf {
+		if nsavederrors+nerrors == 0 {
+			Yyerror("ovf in mpandfixfix")
+		}
+		mpsetovf(a)
+		return
+	}
+
+	a.Val.And(&a.Val, &b.Val)
+}
+
+func mpandnotfixfix(a, b *Mpint) {
+	if a.Ovf || b.Ovf {
+		if nsavederrors+nerrors == 0 {
+			Yyerror("ovf in mpandnotfixfix")
+		}
+		mpsetovf(a)
+		return
+	}
+
+	a.Val.AndNot(&a.Val, &b.Val)
+}
+
+func mpxorfixfix(a, b *Mpint) {
+	if a.Ovf || b.Ovf {
+		if nsavederrors+nerrors == 0 {
+			Yyerror("ovf in mpxorfixfix")
+		}
+		mpsetovf(a)
+		return
+	}
+
+	a.Val.Xor(&a.Val, &b.Val)
+}
+
+// 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))
+	}
+}
+
+func mplshfixfix(a, b *Mpint) {
+	if a.Ovf || b.Ovf {
+		if nsavederrors+nerrors == 0 {
+			Yyerror("ovf in mplshfixfix")
+		}
+		mpsetovf(a)
+		return
+	}
+
+	s := Mpgetfix(b)
+	if s < 0 || s >= Mpprec {
+		Yyerror("stupid shift: %d", s)
+		Mpmovecfix(a, 0)
+		return
+	}
+
+	Mpshiftfix(a, int(s))
+}
+
+func mprshfixfix(a, b *Mpint) {
+	if a.Ovf || b.Ovf {
+		if nsavederrors+nerrors == 0 {
+			Yyerror("ovf in mprshfixfix")
+		}
+		mpsetovf(a)
+		return
+	}
+
+	s := Mpgetfix(b)
+	if s < 0 || s >= Mpprec {
+		Yyerror("stupid shift: %d", s)
+		if a.Val.Sign() < 0 {
+			Mpmovecfix(a, -1)
+		} else {
+			Mpmovecfix(a, 0)
+		}
+		return
+	}
+
+	Mpshiftfix(a, int(-s))
+}
+
+func Mpcmpfixfix(a, b *Mpint) int {
+	return a.Val.Cmp(&b.Val)
+}
+
+func mpcmpfixc(b *Mpint, c int64) int {
+	return b.Val.Cmp(big.NewInt(c))
+}
+
+func mpnegfix(a *Mpint) {
+	a.Val.Neg(&a.Val)
+}
+
+func Mpgetfix(a *Mpint) int64 {
+	if a.Ovf {
+		if nsavederrors+nerrors == 0 {
+			Yyerror("constant overflow")
+		}
+		return 0
+	}
+
+	return a.Val.Int64()
+}
+
+func Mpmovecfix(a *Mpint, c int64) {
+	a.Val.SetInt64(c)
+}
+
+func mpatofix(a *Mpint, as string) {
+	_, 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
+	}
+	if mptestovf(a, 0) {
+		Yyerror("constant too large: %s", as)
+	}
+}
+
+func (x *Mpint) String() string {
+	return Bconv(x, 0)
+}
+
+func Bconv(xval *Mpint, flag int) string {
+	if flag&obj.FmtSharp != 0 {
+		return fmt.Sprintf("%#x", &xval.Val)
+	}
+	return xval.Val.String()
+}
diff --git a/src/cmd/compile/internal/gc/mparith3.go b/src/cmd/compile/internal/gc/mparith3.go
new file mode 100644
index 0000000..bf37f2d
--- /dev/null
+++ b/src/cmd/compile/internal/gc/mparith3.go
@@ -0,0 +1,250 @@
+// 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/compile/internal/big"
+	"cmd/internal/obj"
+	"fmt"
+	"math"
+	"strings"
+)
+
+/// implements float arihmetic
+
+func newMpflt() *Mpflt {
+	var a Mpflt
+	a.Val.SetPrec(Mpprec)
+	return &a
+}
+
+func Mpmovefixflt(a *Mpflt, b *Mpint) {
+	if b.Ovf {
+		// sign doesn't really matter but copy anyway
+		a.Val.SetInf(b.Val.Sign() < 0)
+		return
+	}
+	a.Val.SetInt(&b.Val)
+}
+
+func mpmovefltflt(a *Mpflt, b *Mpflt) {
+	a.Val.Set(&b.Val)
+}
+
+func mpaddfltflt(a *Mpflt, b *Mpflt) {
+	if Mpdebug {
+		fmt.Printf("\n%v + %v", a, b)
+	}
+
+	a.Val.Add(&a.Val, &b.Val)
+
+	if Mpdebug {
+		fmt.Printf(" = %v\n\n", a)
+	}
+}
+
+func mpaddcflt(a *Mpflt, c float64) {
+	var b Mpflt
+
+	Mpmovecflt(&b, c)
+	mpaddfltflt(a, &b)
+}
+
+func mpsubfltflt(a *Mpflt, b *Mpflt) {
+	if Mpdebug {
+		fmt.Printf("\n%v - %v", a, b)
+	}
+
+	a.Val.Sub(&a.Val, &b.Val)
+
+	if Mpdebug {
+		fmt.Printf(" = %v\n\n", a)
+	}
+}
+
+func mpmulfltflt(a *Mpflt, b *Mpflt) {
+	if Mpdebug {
+		fmt.Printf("%v\n * %v\n", a, b)
+	}
+
+	a.Val.Mul(&a.Val, &b.Val)
+
+	if Mpdebug {
+		fmt.Printf(" = %v\n\n", a)
+	}
+}
+
+func mpmulcflt(a *Mpflt, c float64) {
+	var b Mpflt
+
+	Mpmovecflt(&b, c)
+	mpmulfltflt(a, &b)
+}
+
+func mpdivfltflt(a *Mpflt, b *Mpflt) {
+	if Mpdebug {
+		fmt.Printf("%v\n / %v\n", a, b)
+	}
+
+	a.Val.Quo(&a.Val, &b.Val)
+
+	if Mpdebug {
+		fmt.Printf(" = %v\n\n", a)
+	}
+}
+
+func mpcmpfltflt(a *Mpflt, b *Mpflt) int {
+	return a.Val.Cmp(&b.Val)
+}
+
+func mpcmpfltc(b *Mpflt, c float64) int {
+	var a Mpflt
+
+	Mpmovecflt(&a, c)
+	return mpcmpfltflt(b, &a)
+}
+
+func mpgetflt(a *Mpflt) float64 {
+	x, _ := a.Val.Float64()
+
+	// check for overflow
+	if math.IsInf(x, 0) && nsavederrors+nerrors == 0 {
+		Yyerror("mpgetflt ovf")
+	}
+
+	return x
+}
+
+func mpgetflt32(a *Mpflt) float64 {
+	x32, _ := a.Val.Float32()
+	x := float64(x32)
+
+	// check for overflow
+	if math.IsInf(x, 0) && nsavederrors+nerrors == 0 {
+		Yyerror("mpgetflt32 ovf")
+	}
+
+	return x
+}
+
+func Mpmovecflt(a *Mpflt, c float64) {
+	if Mpdebug {
+		fmt.Printf("\nconst %g", c)
+	}
+
+	a.Val.SetFloat64(c)
+
+	if Mpdebug {
+		fmt.Printf(" = %v\n", a)
+	}
+}
+
+func mpnegflt(a *Mpflt) {
+	a.Val.Neg(&a.Val)
+}
+
+//
+// floating point input
+// required syntax is [+-]d*[.]d*[e[+-]d*] or [+-]0xH*[e[+-]d*]
+//
+func mpatoflt(a *Mpflt, as string) {
+	for len(as) > 0 && (as[0] == ' ' || as[0] == '\t') {
+		as = as[1:]
+	}
+
+	// The spec requires accepting exponents that fit in int32.
+	// Don't accept much more than that.
+	// Count digits in exponent and stop early if there are too many.
+	if i := strings.Index(as, "e"); i >= 0 {
+		i++
+		if i < len(as) && (as[i] == '-' || as[i] == '+') {
+			i++
+		}
+		for i < len(as) && as[i] == '0' {
+			i++
+		}
+		// TODO(rsc): This should be > 10, because we're supposed
+		// to accept any signed 32-bit int as an exponent.
+		// But that's not working terribly well, so we deviate from the
+		// spec in order to make sure that what we accept works.
+		// We can remove this restriction once those larger exponents work.
+		// See golang.org/issue/11326 and test/fixedbugs/issue11326*.go.
+		if len(as)-i > 8 {
+			Yyerror("malformed constant: %s (exponent too large)", as)
+			a.Val.SetUint64(0)
+			return
+		}
+	}
+
+	f, ok := a.Val.SetString(as)
+	if !ok {
+		// At the moment we lose precise error cause;
+		// the old code additionally distinguished between:
+		// - malformed hex constant
+		// - decimal point in hex constant
+		// - constant exponent out of range
+		// - decimal point and binary point in constant
+		// TODO(gri) use different conversion function or check separately
+		Yyerror("malformed constant: %s", as)
+		a.Val.SetUint64(0)
+		return
+	}
+
+	if f.IsInf() {
+		Yyerror("constant too large: %s", as)
+		a.Val.SetUint64(0)
+		return
+	}
+}
+
+func (f *Mpflt) String() string {
+	return Fconv(f, 0)
+}
+
+func Fconv(fvp *Mpflt, flag int) string {
+	if flag&obj.FmtSharp == 0 {
+		return fvp.Val.Text('b', 0)
+	}
+
+	// use decimal format for error messages
+
+	// determine sign
+	f := &fvp.Val
+	var sign string
+	if fvp.Val.Signbit() {
+		sign = "-"
+		f = new(big.Float).Abs(f)
+	} else if flag&obj.FmtSign != 0 {
+		sign = "+"
+	}
+
+	// Use fmt formatting if in float64 range (common case).
+	if x, _ := f.Float64(); !math.IsInf(x, 0) {
+		return fmt.Sprintf("%s%.6g", sign, x)
+	}
+
+	// Out of float64 range. Do approximate manual to decimal
+	// conversion to avoid precise but possibly slow Float
+	// formatting. The exponent is > 0 since a negative out-
+	// of-range exponent would have underflowed and led to 0.
+	// f = mant * 2**exp
+	var mant big.Float
+	exp := float64(f.MantExp(&mant)) // 0.5 <= mant < 1.0, exp > 0
+
+	// approximate float64 mantissa m and decimal exponent d
+	// f ~ m * 10**d
+	m, _ := mant.Float64()            // 0.5 <= m < 1.0
+	d := exp * (math.Ln2 / math.Ln10) // log_10(2)
+
+	// adjust m for truncated (integer) decimal exponent e
+	e := int64(d)
+	m *= math.Pow(10, d-float64(e))
+	for m >= 10 {
+		m /= 10
+		e++
+	}
+
+	return fmt.Sprintf("%s%.5fe+%d", sign, m, e)
+}
diff --git a/src/cmd/compile/internal/gc/obj.go b/src/cmd/compile/internal/gc/obj.go
new file mode 100644
index 0000000..d2ac813
--- /dev/null
+++ b/src/cmd/compile/internal/gc/obj.go
@@ -0,0 +1,450 @@
+// 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"
+	"strconv"
+)
+
+/*
+ * architecture-independent object file output
+ */
+const (
+	ArhdrSize = 60
+)
+
+func formathdr(arhdr []byte, name string, size int64) {
+	copy(arhdr[:], fmt.Sprintf("%-16s%-12d%-6d%-6d%-8o%-10d`\n", name, 0, 0, 0, 0644, size))
+}
+
+func dumpobj() {
+	var err error
+	bout, err = obj.Bopenw(outfile)
+	if err != nil {
+		Flusherrors()
+		fmt.Printf("can't create %s: %v\n", outfile, err)
+		errorexit()
+	}
+
+	startobj := int64(0)
+	var arhdr [ArhdrSize]byte
+	if writearchive != 0 {
+		obj.Bwritestring(bout, "!<arch>\n")
+		arhdr = [ArhdrSize]byte{}
+		bout.Write(arhdr[:])
+		startobj = obj.Boffset(bout)
+	}
+
+	fmt.Fprintf(bout, "go object %s %s %s %s\n", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion(), obj.Expstring())
+	dumpexport()
+
+	if writearchive != 0 {
+		bout.Flush()
+		size := obj.Boffset(bout) - startobj
+		if size&1 != 0 {
+			obj.Bputc(bout, 0)
+		}
+		obj.Bseek(bout, startobj-ArhdrSize, 0)
+		formathdr(arhdr[:], "__.PKGDEF", size)
+		bout.Write(arhdr[:])
+		bout.Flush()
+
+		obj.Bseek(bout, startobj+size+(size&1), 0)
+		arhdr = [ArhdrSize]byte{}
+		bout.Write(arhdr[:])
+		startobj = obj.Boffset(bout)
+		fmt.Fprintf(bout, "go object %s %s %s %s\n", obj.Getgoos(), obj.Getgoarch(), obj.Getgoversion(), obj.Expstring())
+	}
+
+	if pragcgobuf != "" {
+		if writearchive != 0 {
+			// write empty export section; must be before cgo section
+			fmt.Fprintf(bout, "\n$$\n\n$$\n\n")
+		}
+
+		fmt.Fprintf(bout, "\n$$  // cgo\n")
+		fmt.Fprintf(bout, "%s\n$$\n\n", pragcgobuf)
+	}
+
+	fmt.Fprintf(bout, "\n!\n")
+
+	var externs *NodeList
+	if externdcl != nil {
+		externs = externdcl.End
+	}
+
+	dumpglobls()
+	dumptypestructs()
+
+	// Dump extra globals.
+	tmp := externdcl
+
+	if externs != nil {
+		externdcl = externs.Next
+	}
+	dumpglobls()
+	externdcl = tmp
+
+	zero := Pkglookup("zerovalue", Runtimepkg)
+	ggloblsym(zero, int32(zerosize), obj.DUPOK|obj.RODATA)
+
+	dumpdata()
+	obj.Writeobjdirect(Ctxt, bout)
+
+	if writearchive != 0 {
+		bout.Flush()
+		size := obj.Boffset(bout) - startobj
+		if size&1 != 0 {
+			obj.Bputc(bout, 0)
+		}
+		obj.Bseek(bout, startobj-ArhdrSize, 0)
+		formathdr(arhdr[:], "_go_.o", size)
+		bout.Write(arhdr[:])
+	}
+
+	obj.Bterm(bout)
+}
+
+func dumpglobls() {
+	var n *Node
+
+	// add globals
+	for l := externdcl; l != nil; l = l.Next {
+		n = l.N
+		if n.Op != ONAME {
+			continue
+		}
+
+		if n.Type == nil {
+			Fatal("external %v nil type\n", n)
+		}
+		if n.Class == PFUNC {
+			continue
+		}
+		if n.Sym.Pkg != localpkg {
+			continue
+		}
+		dowidth(n.Type)
+
+		ggloblnod(n)
+	}
+
+	for l := funcsyms; l != nil; l = l.Next {
+		n = l.N
+		dsymptr(n.Sym, 0, n.Sym.Def.Func.Shortname.Sym, 0)
+		ggloblsym(n.Sym, int32(Widthptr), obj.DUPOK|obj.RODATA)
+	}
+
+	// Do not reprocess funcsyms on next dumpglobls call.
+	funcsyms = nil
+}
+
+func Bputname(b *obj.Biobuf, s *obj.LSym) {
+	obj.Bwritestring(b, s.Name)
+	obj.Bputc(b, 0)
+}
+
+func Linksym(s *Sym) *obj.LSym {
+	if s == nil {
+		return nil
+	}
+	if s.Lsym != nil {
+		return s.Lsym
+	}
+	var name string
+	if isblanksym(s) {
+		name = "_"
+	} else if s.Linkname != "" {
+		name = s.Linkname
+	} else {
+		name = s.Pkg.Prefix + "." + s.Name
+	}
+
+	ls := obj.Linklookup(Ctxt, name, 0)
+	s.Lsym = ls
+	return ls
+}
+
+func duintxx(s *Sym, off int, v uint64, wid int) int {
+	// Update symbol data directly instead of generating a
+	// DATA instruction that liblink will have to interpret later.
+	// This reduces compilation time and memory usage.
+	off = int(Rnd(int64(off), int64(wid)))
+
+	return int(obj.Setuintxx(Ctxt, Linksym(s), int64(off), v, int64(wid)))
+}
+
+func duint8(s *Sym, off int, v uint8) int {
+	return duintxx(s, off, uint64(v), 1)
+}
+
+func duint16(s *Sym, off int, v uint16) int {
+	return duintxx(s, off, uint64(v), 2)
+}
+
+func duint32(s *Sym, off int, v uint32) int {
+	return duintxx(s, off, uint64(v), 4)
+}
+
+func duint64(s *Sym, off int, v uint64) int {
+	return duintxx(s, off, v, 8)
+}
+
+func duintptr(s *Sym, off int, v uint64) int {
+	return duintxx(s, off, v, Widthptr)
+}
+
+var stringsym_gen int
+
+func stringsym(s string) (hdr, data *Sym) {
+	var symname string
+	var pkg *Pkg
+	if len(s) > 100 {
+		// huge strings are made static to avoid long names
+		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.
+		symname = strconv.Quote(s)
+		pkg = gostringpkg
+	}
+
+	symhdr := Pkglookup("hdr."+symname, pkg)
+	symdata := Pkglookup(symname, pkg)
+
+	// SymUniq flag indicates that data is generated already
+	if symhdr.Flags&SymUniq != 0 {
+		return symhdr, symdata
+	}
+	symhdr.Flags |= SymUniq
+	symhdr.Def = newname(symhdr)
+
+	// string header
+	off := 0
+	off = dsymptr(symhdr, off, symdata, 0)
+	off = duintxx(symhdr, off, uint64(len(s)), Widthint)
+	ggloblsym(symhdr, int32(off), obj.DUPOK|obj.RODATA|obj.LOCAL)
+
+	// string data
+	if symdata.Flags&SymUniq != 0 {
+		return symhdr, symdata
+	}
+	symdata.Flags |= SymUniq
+	symdata.Def = newname(symdata)
+
+	off = 0
+	var m int
+	for n := 0; n < len(s); n += m {
+		m = 8
+		if m > len(s)-n {
+			m = len(s) - n
+		}
+		off = dsname(symdata, off, s[n:n+m])
+	}
+
+	off = duint8(symdata, off, 0)                // terminating NUL for runtime
+	off = (off + Widthptr - 1) &^ (Widthptr - 1) // round to pointer alignment
+	ggloblsym(symdata, int32(off), obj.DUPOK|obj.RODATA|obj.LOCAL)
+
+	return symhdr, symdata
+}
+
+var slicebytes_gen int
+
+func slicebytes(nam *Node, s string, len int) {
+	var m int
+
+	slicebytes_gen++
+	symname := fmt.Sprintf(".gobytes.%d", slicebytes_gen)
+	sym := Pkglookup(symname, localpkg)
+	sym.Def = newname(sym)
+
+	off := 0
+	for n := 0; n < len; n += m {
+		m = 8
+		if m > len-n {
+			m = len - n
+		}
+		off = dsname(sym, off, s[n:n+m])
+	}
+
+	ggloblsym(sym, int32(off), obj.NOPTR|obj.LOCAL)
+
+	if nam.Op != ONAME {
+		Fatal("slicebytes %v", nam)
+	}
+	off = int(nam.Xoffset)
+	off = dsymptr(nam.Sym, off, sym, 0)
+	off = duintxx(nam.Sym, off, uint64(len), Widthint)
+	duintxx(nam.Sym, off, uint64(len), Widthint)
+}
+
+func dstringptr(s *Sym, off int, str string) int {
+	off = int(Rnd(int64(off), int64(Widthptr)))
+	p := Thearch.Gins(obj.ADATA, nil, nil)
+	p.From.Type = obj.TYPE_MEM
+	p.From.Name = obj.NAME_EXTERN
+	p.From.Sym = Linksym(s)
+	p.From.Offset = int64(off)
+	p.From3 = new(obj.Addr)
+	p.From3.Type = obj.TYPE_CONST
+	p.From3.Offset = int64(Widthptr)
+
+	Datastring(str+"\x00", &p.To) // TODO(rsc): Remove NUL
+	p.To.Type = obj.TYPE_ADDR
+	p.To.Etype = Simtype[TINT]
+	off += Widthptr
+
+	return off
+}
+
+func Datastring(s string, a *obj.Addr) {
+	_, symdata := stringsym(s)
+	a.Type = obj.TYPE_MEM
+	a.Name = obj.NAME_EXTERN
+	a.Sym = Linksym(symdata)
+	a.Node = symdata.Def
+	a.Offset = 0
+	a.Etype = Simtype[TINT]
+}
+
+func datagostring(sval string, a *obj.Addr) {
+	symhdr, _ := stringsym(sval)
+	a.Type = obj.TYPE_MEM
+	a.Name = obj.NAME_EXTERN
+	a.Sym = Linksym(symhdr)
+	a.Node = symhdr.Def
+	a.Offset = 0
+	a.Etype = TSTRING
+}
+
+func dgostringptr(s *Sym, off int, str string) int {
+	if str == "" {
+		return duintptr(s, off, 0)
+	}
+	return dgostrlitptr(s, off, &str)
+}
+
+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
+	p.From.Name = obj.NAME_EXTERN
+	p.From.Sym = Linksym(s)
+	p.From.Offset = int64(off)
+	p.From3 = new(obj.Addr)
+	p.From3.Type = obj.TYPE_CONST
+	p.From3.Offset = int64(Widthptr)
+	datagostring(*lit, &p.To)
+	p.To.Type = obj.TYPE_ADDR
+	p.To.Etype = Simtype[TINT]
+	off += Widthptr
+
+	return off
+}
+
+func dsname(s *Sym, off int, t string) int {
+	p := Thearch.Gins(obj.ADATA, nil, nil)
+	p.From.Type = obj.TYPE_MEM
+	p.From.Name = obj.NAME_EXTERN
+	p.From.Offset = int64(off)
+	p.From.Sym = Linksym(s)
+	p.From3 = new(obj.Addr)
+	p.From3.Type = obj.TYPE_CONST
+	p.From3.Offset = int64(len(t))
+
+	p.To.Type = obj.TYPE_SCONST
+	p.To.Val = t
+	return off + len(t)
+}
+
+func dsymptr(s *Sym, off int, x *Sym, xoff int) int {
+	off = int(Rnd(int64(off), int64(Widthptr)))
+
+	p := Thearch.Gins(obj.ADATA, nil, nil)
+	p.From.Type = obj.TYPE_MEM
+	p.From.Name = obj.NAME_EXTERN
+	p.From.Sym = Linksym(s)
+	p.From.Offset = int64(off)
+	p.From3 = new(obj.Addr)
+	p.From3.Type = obj.TYPE_CONST
+	p.From3.Offset = int64(Widthptr)
+	p.To.Type = obj.TYPE_ADDR
+	p.To.Name = obj.NAME_EXTERN
+	p.To.Sym = Linksym(x)
+	p.To.Offset = int64(xoff)
+	off += Widthptr
+
+	return off
+}
+
+func gdata(nam *Node, nr *Node, wid int) {
+	if nr.Op == OLITERAL {
+		switch nr.Val().Ctype() {
+		case CTCPLX:
+			gdatacomplex(nam, nr.Val().U.(*Mpcplx))
+			return
+
+		case CTSTR:
+			gdatastring(nam, nr.Val().U.(string))
+			return
+		}
+	}
+
+	p := Thearch.Gins(obj.ADATA, nam, nr)
+	p.From3 = new(obj.Addr)
+	p.From3.Type = obj.TYPE_CONST
+	p.From3.Offset = int64(wid)
+}
+
+func gdatacomplex(nam *Node, cval *Mpcplx) {
+	w := cplxsubtype(int(nam.Type.Etype))
+	w = int(Types[w].Width)
+
+	p := Thearch.Gins(obj.ADATA, nam, nil)
+	p.From3 = new(obj.Addr)
+	p.From3.Type = obj.TYPE_CONST
+	p.From3.Offset = int64(w)
+	p.To.Type = obj.TYPE_FCONST
+	p.To.Val = mpgetflt(&cval.Real)
+
+	p = Thearch.Gins(obj.ADATA, nam, nil)
+	p.From3 = new(obj.Addr)
+	p.From3.Type = obj.TYPE_CONST
+	p.From3.Offset = int64(w)
+	p.From.Offset += int64(w)
+	p.To.Type = obj.TYPE_FCONST
+	p.To.Val = mpgetflt(&cval.Imag)
+}
+
+func gdatastring(nam *Node, sval string) {
+	var nod1 Node
+
+	p := Thearch.Gins(obj.ADATA, nam, nil)
+	Datastring(sval, &p.To)
+	p.From3 = new(obj.Addr)
+	p.From3.Type = obj.TYPE_CONST
+	p.From3.Offset = Types[Tptr].Width
+	p.To.Type = obj.TYPE_ADDR
+
+	//print("%v\n", p);
+
+	Nodconst(&nod1, Types[TINT], int64(len(sval)))
+
+	p = Thearch.Gins(obj.ADATA, nam, &nod1)
+	p.From3 = new(obj.Addr)
+	p.From3.Type = obj.TYPE_CONST
+	p.From3.Offset = int64(Widthint)
+	p.From.Offset += int64(Widthptr)
+}
diff --git a/src/cmd/compile/internal/gc/opnames.go b/src/cmd/compile/internal/gc/opnames.go
new file mode 100644
index 0000000..9134bd4
--- /dev/null
+++ b/src/cmd/compile/internal/gc/opnames.go
@@ -0,0 +1,163 @@
+// 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 gc
+
+// auto generated by go tool dist
+var opnames = []string{
+	OXXX:             "XXX",
+	ONAME:            "NAME",
+	ONONAME:          "NONAME",
+	OTYPE:            "TYPE",
+	OPACK:            "PACK",
+	OLITERAL:         "LITERAL",
+	OADD:             "ADD",
+	OSUB:             "SUB",
+	OOR:              "OR",
+	OXOR:             "XOR",
+	OADDSTR:          "ADDSTR",
+	OADDR:            "ADDR",
+	OANDAND:          "ANDAND",
+	OAPPEND:          "APPEND",
+	OARRAYBYTESTR:    "ARRAYBYTESTR",
+	OARRAYBYTESTRTMP: "ARRAYBYTESTRTMP",
+	OARRAYRUNESTR:    "ARRAYRUNESTR",
+	OSTRARRAYBYTE:    "STRARRAYBYTE",
+	OSTRARRAYBYTETMP: "STRARRAYBYTETMP",
+	OSTRARRAYRUNE:    "STRARRAYRUNE",
+	OAS:              "AS",
+	OAS2:             "AS2",
+	OAS2FUNC:         "AS2FUNC",
+	OAS2RECV:         "AS2RECV",
+	OAS2MAPR:         "AS2MAPR",
+	OAS2DOTTYPE:      "AS2DOTTYPE",
+	OASOP:            "ASOP",
+	OASWB:            "ASWB",
+	OCALL:            "CALL",
+	OCALLFUNC:        "CALLFUNC",
+	OCALLMETH:        "CALLMETH",
+	OCALLINTER:       "CALLINTER",
+	OCALLPART:        "CALLPART",
+	OCAP:             "CAP",
+	OCLOSE:           "CLOSE",
+	OCLOSURE:         "CLOSURE",
+	OCMPIFACE:        "CMPIFACE",
+	OCMPSTR:          "CMPSTR",
+	OCOMPLIT:         "COMPLIT",
+	OMAPLIT:          "MAPLIT",
+	OSTRUCTLIT:       "STRUCTLIT",
+	OARRAYLIT:        "ARRAYLIT",
+	OPTRLIT:          "PTRLIT",
+	OCONV:            "CONV",
+	OCONVIFACE:       "CONVIFACE",
+	OCONVNOP:         "CONVNOP",
+	OCOPY:            "COPY",
+	ODCL:             "DCL",
+	ODCLFUNC:         "DCLFUNC",
+	ODCLFIELD:        "DCLFIELD",
+	ODCLCONST:        "DCLCONST",
+	ODCLTYPE:         "DCLTYPE",
+	ODELETE:          "DELETE",
+	ODOT:             "DOT",
+	ODOTPTR:          "DOTPTR",
+	ODOTMETH:         "DOTMETH",
+	ODOTINTER:        "DOTINTER",
+	OXDOT:            "XDOT",
+	ODOTTYPE:         "DOTTYPE",
+	ODOTTYPE2:        "DOTTYPE2",
+	OEQ:              "EQ",
+	ONE:              "NE",
+	OLT:              "LT",
+	OLE:              "LE",
+	OGE:              "GE",
+	OGT:              "GT",
+	OIND:             "IND",
+	OINDEX:           "INDEX",
+	OINDEXMAP:        "INDEXMAP",
+	OKEY:             "KEY",
+	OPARAM:           "PARAM",
+	OLEN:             "LEN",
+	OMAKE:            "MAKE",
+	OMAKECHAN:        "MAKECHAN",
+	OMAKEMAP:         "MAKEMAP",
+	OMAKESLICE:       "MAKESLICE",
+	OMUL:             "MUL",
+	ODIV:             "DIV",
+	OMOD:             "MOD",
+	OLSH:             "LSH",
+	ORSH:             "RSH",
+	OAND:             "AND",
+	OANDNOT:          "ANDNOT",
+	ONEW:             "NEW",
+	ONOT:             "NOT",
+	OCOM:             "COM",
+	OPLUS:            "PLUS",
+	OMINUS:           "MINUS",
+	OOROR:            "OROR",
+	OPANIC:           "PANIC",
+	OPRINT:           "PRINT",
+	OPRINTN:          "PRINTN",
+	OPAREN:           "PAREN",
+	OSEND:            "SEND",
+	OSLICE:           "SLICE",
+	OSLICEARR:        "SLICEARR",
+	OSLICESTR:        "SLICESTR",
+	OSLICE3:          "SLICE3",
+	OSLICE3ARR:       "SLICE3ARR",
+	ORECOVER:         "RECOVER",
+	ORECV:            "RECV",
+	ORUNESTR:         "RUNESTR",
+	OSELRECV:         "SELRECV",
+	OSELRECV2:        "SELRECV2",
+	OIOTA:            "IOTA",
+	OREAL:            "REAL",
+	OIMAG:            "IMAG",
+	OCOMPLEX:         "COMPLEX",
+	OBLOCK:           "BLOCK",
+	OBREAK:           "BREAK",
+	OCASE:            "CASE",
+	OXCASE:           "XCASE",
+	OCONTINUE:        "CONTINUE",
+	ODEFER:           "DEFER",
+	OEMPTY:           "EMPTY",
+	OFALL:            "FALL",
+	OXFALL:           "XFALL",
+	OFOR:             "FOR",
+	OGOTO:            "GOTO",
+	OIF:              "IF",
+	OLABEL:           "LABEL",
+	OPROC:            "PROC",
+	ORANGE:           "RANGE",
+	ORETURN:          "RETURN",
+	OSELECT:          "SELECT",
+	OSWITCH:          "SWITCH",
+	OTYPESW:          "TYPESW",
+	OTCHAN:           "TCHAN",
+	OTMAP:            "TMAP",
+	OTSTRUCT:         "TSTRUCT",
+	OTINTER:          "TINTER",
+	OTFUNC:           "TFUNC",
+	OTARRAY:          "TARRAY",
+	ODDD:             "DDD",
+	ODDDARG:          "DDDARG",
+	OINLCALL:         "INLCALL",
+	OEFACE:           "EFACE",
+	OITAB:            "ITAB",
+	OSPTR:            "SPTR",
+	OCLOSUREVAR:      "CLOSUREVAR",
+	OCFUNC:           "CFUNC",
+	OCHECKNIL:        "CHECKNIL",
+	OVARKILL:         "VARKILL",
+	OREGISTER:        "REGISTER",
+	OINDREG:          "INDREG",
+	OCMP:             "CMP",
+	ODEC:             "DEC",
+	OINC:             "INC",
+	OEXTEND:          "EXTEND",
+	OHMUL:            "HMUL",
+	OLROT:            "LROT",
+	ORROTC:           "RROTC",
+	ORETJMP:          "RETJMP",
+	OEND:             "END",
+}
diff --git a/src/cmd/compile/internal/gc/order.go b/src/cmd/compile/internal/gc/order.go
new file mode 100644
index 0000000..799a17e
--- /dev/null
+++ b/src/cmd/compile/internal/gc/order.go
@@ -0,0 +1,1179 @@
+// 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.
+
+package gc
+
+import (
+	"fmt"
+	"strings"
+)
+
+// Rewrite tree to use separate statements to enforce
+// order of evaluation.  Makes walk easier, because it
+// can (after this runs) reorder at will within an expression.
+//
+// Rewrite x op= y into x = x op y.
+//
+// Introduce temporaries as needed by runtime routines.
+// For example, the map runtime routines take the map key
+// by reference, so make sure all map keys are addressable
+// by copying them to temporaries as needed.
+// The same is true for channel operations.
+//
+// Arrange that map index expressions only appear in direct
+// assignments x = m[k] or m[k] = x, never in larger expressions.
+//
+// Arrange that receive expressions only appear in direct assignments
+// x = <-c or as standalone statements <-c, never in larger expressions.
+
+// TODO(rsc): The temporary introduction during multiple assignments
+// should be moved into this file, so that the temporaries can be cleaned
+// and so that conversions implicit in the OAS2FUNC and OAS2RECV
+// nodes can be made explicit and then have their temporaries cleaned.
+
+// TODO(rsc): Goto and multilevel break/continue can jump over
+// inserted VARKILL annotations. Work out a way to handle these.
+// The current implementation is safe, in that it will execute correctly.
+// But it won't reuse temporaries as aggressively as it might, and
+// it can result in unnecessary zeroing of those variables in the function
+// prologue.
+
+// Order holds state during the ordering process.
+type Order struct {
+	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
+// described in the comment at the top of the file.
+func order(fn *Node) {
+	if Debug['W'] > 1 {
+		s := fmt.Sprintf("\nbefore order %v", fn.Func.Nname.Sym)
+		dumplist(s, fn.Nbody)
+	}
+
+	orderblock(&fn.Nbody)
+}
+
+// Ordertemp allocates a new temporary with the given type,
+// pushes it onto the temp stack, and returns it.
+// If clear is true, ordertemp emits code to zero the temporary.
+func ordertemp(t *Type, order *Order, clear bool) *Node {
+	var_ := temp(t)
+	if clear {
+		a := Nod(OAS, var_, nil)
+		typecheck(&a, Etop)
+		order.out = list(order.out, a)
+	}
+
+	l := order.free
+	if l == nil {
+		l = new(NodeList)
+	}
+	order.free = l.Next
+	l.Next = order.temp
+	l.N = var_
+	order.temp = l
+	return var_
+}
+
+// Ordercopyexpr behaves like ordertemp but also emits
+// code to initialize the temporary to the value n.
+//
+// The clear argument is provided for use when the evaluation
+// of tmp = n turns into a function call that is passed a pointer
+// to the temporary as the output space. If the call blocks before
+// tmp has been written, the garbage collector will still treat the
+// temporary as live, so we must zero it before entering that call.
+// Today, this only happens for channel receive operations.
+// (The other candidate would be map access, but map access
+// returns a pointer to the result data instead of taking a pointer
+// to be filled in.)
+func ordercopyexpr(n *Node, t *Type, order *Order, clear int) *Node {
+	var_ := ordertemp(t, order, clear != 0)
+	a := Nod(OAS, var_, n)
+	typecheck(&a, Etop)
+	order.out = list(order.out, a)
+	return var_
+}
+
+// Ordercheapexpr returns a cheap version of n.
+// The definition of cheap is that n is a variable or constant.
+// If not, ordercheapexpr allocates a new tmp, emits tmp = n,
+// and then returns tmp.
+func ordercheapexpr(n *Node, order *Order) *Node {
+	if n == nil {
+		return nil
+	}
+	switch n.Op {
+	case ONAME, OLITERAL:
+		return n
+	case OLEN, OCAP:
+		l := ordercheapexpr(n.Left, order)
+		if l == n.Left {
+			return n
+		}
+		a := Nod(OXXX, nil, nil)
+		*a = *n
+		a.Orig = a
+		a.Left = l
+		typecheck(&a, Erv)
+		return a
+	}
+
+	return ordercopyexpr(n, n.Type, order, 0)
+}
+
+// Ordersafeexpr returns a safe version of n.
+// The definition of safe is that n can appear multiple times
+// without violating the semantics of the original program,
+// and that assigning to the safe version has the same effect
+// as assigning to the original n.
+//
+// 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:
+		return n
+
+	case ODOT, OLEN, OCAP:
+		l := ordersafeexpr(n.Left, order)
+		if l == n.Left {
+			return n
+		}
+		a := Nod(OXXX, nil, nil)
+		*a = *n
+		a.Orig = a
+		a.Left = l
+		typecheck(&a, Erv)
+		return a
+
+	case ODOTPTR, OIND:
+		l := ordercheapexpr(n.Left, order)
+		if l == n.Left {
+			return n
+		}
+		a := Nod(OXXX, nil, nil)
+		*a = *n
+		a.Orig = a
+		a.Left = l
+		typecheck(&a, Erv)
+		return a
+
+	case OINDEX, OINDEXMAP:
+		var l *Node
+		if Isfixedarray(n.Left.Type) {
+			l = ordersafeexpr(n.Left, order)
+		} else {
+			l = ordercheapexpr(n.Left, order)
+		}
+		r := ordercheapexpr(n.Right, order)
+		if l == n.Left && r == n.Right {
+			return n
+		}
+		a := Nod(OXXX, nil, nil)
+		*a = *n
+		a.Orig = a
+		a.Left = l
+		a.Right = r
+		typecheck(&a, Erv)
+		return a
+	}
+
+	Fatal("ordersafeexpr %v", Oconv(int(n.Op), 0))
+	return nil // not reached
+}
+
+// Istemp reports whether n is a temporary variable.
+func istemp(n *Node) bool {
+	if n.Op != ONAME {
+		return false
+	}
+	return strings.HasPrefix(n.Sym.Name, "autotmp_")
+}
+
+// Isaddrokay reports whether it is okay to pass n's address to runtime routines.
+// Taking the address of a variable makes the liveness and optimization analyses
+// lose track of where the variable's lifetime ends. To avoid hurting the analyses
+// of ordinary stack variables, those are not 'isaddrokay'. Temporaries are okay,
+// because we emit explicit VARKILL instructions marking the end of those
+// temporaries' lifetimes.
+func isaddrokay(n *Node) bool {
+	return islvalue(n) && (n.Op != ONAME || n.Class == PEXTERN || istemp(n))
+}
+
+// Orderaddrtemp ensures that *np is okay to pass by address to runtime routines.
+// If the original argument *np is not okay, orderaddrtemp creates a tmp, emits
+// tmp = *np, and then sets *np to the tmp variable.
+func orderaddrtemp(np **Node, order *Order) {
+	n := *np
+	if isaddrokay(n) {
+		return
+	}
+	*np = ordercopyexpr(n, n.Type, order, 0)
+}
+
+// Marktemp returns the top of the temporary variable stack.
+func marktemp(order *Order) *NodeList {
+	return order.temp
+}
+
+// Poptemp pops temporaries off the stack until reaching the mark,
+// which must have been returned by marktemp.
+func poptemp(mark *NodeList, order *Order) {
+	var l *NodeList
+
+	for {
+		l = order.temp
+		if l == mark {
+			break
+		}
+		order.temp = l.Next
+		l.Next = order.free
+		order.free = l
+	}
+}
+
+// Cleantempnopop emits to *out VARKILL instructions for each temporary
+// above the mark on the temporary stack, but it does not pop them
+// from the stack.
+func cleantempnopop(mark *NodeList, order *Order, out **NodeList) {
+	var kill *Node
+
+	for l := order.temp; l != mark; l = l.Next {
+		kill = Nod(OVARKILL, l.N, nil)
+		typecheck(&kill, Etop)
+		*out = list(*out, kill)
+	}
+}
+
+// Cleantemp emits VARKILL instructions for each temporary above the
+// mark on the temporary stack and removes them from the stack.
+func cleantemp(top *NodeList, order *Order) {
+	cleantempnopop(top, order, &order.out)
+	poptemp(top, order)
+}
+
+// Orderstmtlist orders each of the statements in the list.
+func orderstmtlist(l *NodeList, order *Order) {
+	for ; l != nil; l = l.Next {
+		orderstmt(l.N, order)
+	}
+}
+
+// Orderblock orders the block of statements *l onto a new list,
+// and then replaces *l with that list.
+func orderblock(l **NodeList) {
+	var order Order
+	mark := marktemp(&order)
+	orderstmtlist(*l, &order)
+	cleantemp(mark, &order)
+	*l = order.out
+}
+
+// Orderexprinplace orders the side effects in *np and
+// leaves them as the init list of the final *np.
+func orderexprinplace(np **Node, outer *Order) {
+	n := *np
+	var order Order
+	orderexpr(&n, &order, nil)
+	addinit(&n, order.out)
+
+	// insert new temporaries from order
+	// at head of outer list.
+	lp := &order.temp
+
+	for *lp != nil {
+		lp = &(*lp).Next
+	}
+	*lp = outer.temp
+	outer.temp = order.temp
+
+	*np = n
+}
+
+// Orderstmtinplace orders the side effects of the single statement *np
+// and replaces it with the resulting statement list.
+func orderstmtinplace(np **Node) {
+	n := *np
+	var order Order
+	mark := marktemp(&order)
+	orderstmt(n, &order)
+	cleantemp(mark, &order)
+	*np = liststmt(order.out)
+}
+
+// Orderinit moves n's init list to order->out.
+func orderinit(n *Node, order *Order) {
+	orderstmtlist(n.Ninit, order)
+	n.Ninit = nil
+}
+
+// Ismulticall reports whether the list l is f() for a multi-value function.
+// Such an f() could appear as the lone argument to a multi-arg function.
+func ismulticall(l *NodeList) bool {
+	// one arg only
+	if l == nil || l.Next != nil {
+		return false
+	}
+	n := l.N
+
+	// must be call
+	switch n.Op {
+	default:
+		return false
+
+	case OCALLFUNC, OCALLMETH, OCALLINTER:
+		break
+	}
+
+	// call must return multiple values
+	return n.Left.Type.Outtuple > 1
+}
+
+// Copyret emits t1, t2, ... = n, where n is a function call,
+// and then returns the list t1, t2, ....
+func copyret(n *Node, order *Order) *NodeList {
+	if n.Type.Etype != TSTRUCT || n.Type.Funarg == 0 {
+		Fatal("copyret %v %d", n.Type, n.Left.Type.Outtuple)
+	}
+
+	var l1 *NodeList
+	var l2 *NodeList
+	var tl Iter
+	var tmp *Node
+	for t := Structfirst(&tl, &n.Type); t != nil; t = structnext(&tl) {
+		tmp = temp(t.Type)
+		l1 = list(l1, tmp)
+		l2 = list(l2, tmp)
+	}
+
+	as := Nod(OAS2, nil, nil)
+	as.List = l1
+	as.Rlist = list1(n)
+	typecheck(&as, Etop)
+	orderstmt(as, order)
+
+	return l2
+}
+
+// Ordercallargs orders the list of call arguments *l.
+func ordercallargs(l **NodeList, order *Order) {
+	if ismulticall(*l) {
+		// return f() where f() is multiple values.
+		*l = copyret((*l).N, order)
+	} else {
+		orderexprlist(*l, order)
+	}
+}
+
+// Ordercall orders the call expression n.
+// n->op is OCALLMETH/OCALLFUNC/OCALLINTER or a builtin like OCOPY.
+func ordercall(n *Node, order *Order) {
+	orderexpr(&n.Left, order, nil)
+	orderexpr(&n.Right, order, nil) // ODDDARG temp
+	ordercallargs(&n.List, order)
+}
+
+// Ordermapassign appends n to order->out, introducing temporaries
+// to make sure that all map assignments have the form m[k] = x,
+// where x is adressable.
+// (Orderexpr has already been called on n, so we know k is addressable.)
+//
+// If n is m[k] = x where x is not addressable, the rewrite is:
+//	tmp = x
+//	m[k] = tmp
+//
+// If n is the multiple assignment form ..., m[k], ... = ..., the rewrite is
+//	t1 = m
+//	t2 = k
+//	...., t3, ... = x
+//	t1[t2] = t3
+//
+// The temporaries t1, t2 are needed in case the ... being assigned
+// contain m or k. They are usually unnecessary, but in the unnecessary
+// cases they are also typically registerizable, so not much harm done.
+// And this only applies to the multiple-assignment form.
+// We could do a more precise analysis if needed, like in walk.c.
+//
+// Ordermapassign also inserts these temporaries if needed for
+// calling writebarrierfat with a pointer to n->right.
+func ordermapassign(n *Node, order *Order) {
+	switch n.Op {
+	default:
+		Fatal("ordermapassign %v", Oconv(int(n.Op), 0))
+
+	case OAS:
+		order.out = list(order.out, n)
+
+		// We call writebarrierfat only for values > 4 pointers long. See walk.c.
+		if (n.Left.Op == OINDEXMAP || (needwritebarrier(n.Left, n.Right) && n.Left.Type.Width > int64(4*Widthptr))) && !isaddrokay(n.Right) {
+			m := n.Left
+			n.Left = ordertemp(m.Type, order, false)
+			a := Nod(OAS, m, n.Left)
+			typecheck(&a, Etop)
+			order.out = list(order.out, a)
+		}
+
+	case OAS2, OAS2DOTTYPE, OAS2MAPR, OAS2FUNC:
+		var post *NodeList
+		var m *Node
+		var a *Node
+		for l := n.List; l != nil; l = l.Next {
+			if l.N.Op == OINDEXMAP {
+				m = l.N
+				if !istemp(m.Left) {
+					m.Left = ordercopyexpr(m.Left, m.Left.Type, order, 0)
+				}
+				if !istemp(m.Right) {
+					m.Right = ordercopyexpr(m.Right, m.Right.Type, order, 0)
+				}
+				l.N = ordertemp(m.Type, order, false)
+				a = Nod(OAS, m, l.N)
+				typecheck(&a, Etop)
+				post = list(post, a)
+			} else if flag_race != 0 && n.Op == OAS2FUNC && !isblank(l.N) {
+				m = l.N
+				l.N = ordertemp(m.Type, order, false)
+				a = Nod(OAS, m, l.N)
+				typecheck(&a, Etop)
+				post = list(post, a)
+			}
+		}
+
+		order.out = list(order.out, n)
+		order.out = concat(order.out, post)
+	}
+}
+
+// Orderstmt orders the statement n, appending to order->out.
+// Temporaries created during the statement are cleaned
+// up using VARKILL instructions as possible.
+func orderstmt(n *Node, order *Order) {
+	if n == nil {
+		return
+	}
+
+	lno := int(setlineno(n))
+
+	orderinit(n, order)
+
+	switch n.Op {
+	default:
+		Fatal("orderstmt %v", Oconv(int(n.Op), 0))
+
+	case OVARKILL:
+		order.out = list(order.out, n)
+
+	case OAS:
+		t := marktemp(order)
+		orderexpr(&n.Left, order, nil)
+		orderexpr(&n.Right, order, n.Left)
+		ordermapassign(n, order)
+		cleantemp(t, order)
+
+	case OAS2,
+		OCLOSE,
+		OCOPY,
+		OPRINT,
+		OPRINTN,
+		ORECOVER,
+		ORECV:
+		t := marktemp(order)
+		orderexpr(&n.Left, order, nil)
+		orderexpr(&n.Right, order, nil)
+		orderexprlist(n.List, order)
+		orderexprlist(n.Rlist, order)
+		switch n.Op {
+		case OAS2, OAS2DOTTYPE:
+			ordermapassign(n, order)
+		default:
+			order.out = list(order.out, n)
+		}
+		cleantemp(t, order)
+
+	case OASOP:
+		// Special: rewrite l op= r into l = l op r.
+		// This simplifies quite a few operations;
+		// most important is that it lets us separate
+		// out map read from map write when l is
+		// a map index expression.
+		t := marktemp(order)
+
+		orderexpr(&n.Left, order, nil)
+		n.Left = ordersafeexpr(n.Left, order)
+		tmp1 := treecopy(n.Left, 0)
+		if tmp1.Op == OINDEXMAP {
+			tmp1.Etype = 0 // now an rvalue not an lvalue
+		}
+		tmp1 = ordercopyexpr(tmp1, n.Left.Type, order, 0)
+		n.Right = Nod(int(n.Etype), tmp1, n.Right)
+		typecheck(&n.Right, Erv)
+		orderexpr(&n.Right, order, nil)
+		n.Etype = 0
+		n.Op = OAS
+		ordermapassign(n, order)
+		cleantemp(t, order)
+
+		// Special: make sure key is addressable,
+	// and make sure OINDEXMAP is not copied out.
+	case OAS2MAPR:
+		t := marktemp(order)
+
+		orderexprlist(n.List, order)
+		r := n.Rlist.N
+		orderexpr(&r.Left, order, nil)
+		orderexpr(&r.Right, order, nil)
+
+		// See case OINDEXMAP below.
+		if r.Right.Op == OARRAYBYTESTR {
+			r.Right.Op = OARRAYBYTESTRTMP
+		}
+		orderaddrtemp(&r.Right, order)
+		ordermapassign(n, order)
+		cleantemp(t, order)
+
+		// Special: avoid copy of func call n->rlist->n.
+	case OAS2FUNC:
+		t := marktemp(order)
+
+		orderexprlist(n.List, order)
+		ordercall(n.Rlist.N, order)
+		ordermapassign(n, order)
+		cleantemp(t, order)
+
+		// Special: use temporary variables to hold result,
+	// so that assertI2Tetc can take address of temporary.
+	// No temporary for blank assignment.
+	case OAS2DOTTYPE:
+		t := marktemp(order)
+
+		orderexprlist(n.List, order)
+		orderexpr(&n.Rlist.N.Left, order, nil) // i in i.(T)
+		if isblank(n.List.N) {
+			order.out = list(order.out, n)
+		} else {
+			typ := n.Rlist.N.Type
+			tmp1 := ordertemp(typ, order, haspointers(typ))
+			order.out = list(order.out, n)
+			r := Nod(OAS, n.List.N, tmp1)
+			typecheck(&r, Etop)
+			ordermapassign(r, order)
+			n.List = list(list1(tmp1), n.List.Next.N)
+		}
+
+		cleantemp(t, order)
+
+		// Special: use temporary variables to hold result,
+	// so that chanrecv can take address of temporary.
+	case OAS2RECV:
+		t := marktemp(order)
+
+		orderexprlist(n.List, order)
+		orderexpr(&n.Rlist.N.Left, order, nil) // arg to recv
+		ch := n.Rlist.N.Left.Type
+		tmp1 := ordertemp(ch.Type, order, haspointers(ch.Type))
+		var tmp2 *Node
+		if !isblank(n.List.Next.N) {
+			tmp2 = ordertemp(n.List.Next.N.Type, order, false)
+		} else {
+			tmp2 = ordertemp(Types[TBOOL], order, false)
+		}
+		order.out = list(order.out, n)
+		r := Nod(OAS, n.List.N, tmp1)
+		typecheck(&r, Etop)
+		ordermapassign(r, order)
+		r = Nod(OAS, n.List.Next.N, tmp2)
+		typecheck(&r, Etop)
+		ordermapassign(r, order)
+		n.List = list(list1(tmp1), tmp2)
+		cleantemp(t, order)
+
+		// Special: does not save n onto out.
+	case OBLOCK, OEMPTY:
+		orderstmtlist(n.List, order)
+
+		// Special: n->left is not an expression; save as is.
+	case OBREAK,
+		OCONTINUE,
+		ODCL,
+		ODCLCONST,
+		ODCLTYPE,
+		OFALL,
+		OXFALL,
+		OGOTO,
+		OLABEL,
+		ORETJMP:
+		order.out = list(order.out, n)
+
+		// Special: handle call arguments.
+	case OCALLFUNC, OCALLINTER, OCALLMETH:
+		t := marktemp(order)
+
+		ordercall(n, order)
+		order.out = list(order.out, n)
+		cleantemp(t, order)
+
+		// Special: order arguments to inner call but not call itself.
+	case ODEFER, OPROC:
+		t := marktemp(order)
+
+		switch n.Left.Op {
+		// Delete will take the address of the key.
+		// Copy key into new temp and do not clean it
+		// (it persists beyond the statement).
+		case ODELETE:
+			orderexprlist(n.Left.List, order)
+
+			t1 := marktemp(order)
+			np := &n.Left.List.Next.N // map key
+			*np = ordercopyexpr(*np, (*np).Type, order, 0)
+			poptemp(t1, order)
+
+		default:
+			ordercall(n.Left, order)
+		}
+
+		order.out = list(order.out, n)
+		cleantemp(t, order)
+
+	case ODELETE:
+		t := marktemp(order)
+		orderexpr(&n.List.N, order, nil)
+		orderexpr(&n.List.Next.N, order, nil)
+		orderaddrtemp(&n.List.Next.N, order) // map key
+		order.out = list(order.out, n)
+		cleantemp(t, order)
+
+		// Clean temporaries from condition evaluation at
+	// beginning of loop body and after for statement.
+	case OFOR:
+		t := marktemp(order)
+
+		orderexprinplace(&n.Left, order)
+		var l *NodeList
+		cleantempnopop(t, order, &l)
+		n.Nbody = concat(l, n.Nbody)
+		orderblock(&n.Nbody)
+		orderstmtinplace(&n.Right)
+		order.out = list(order.out, n)
+		cleantemp(t, order)
+
+		// Clean temporaries from condition at
+	// beginning of both branches.
+	case OIF:
+		t := marktemp(order)
+
+		orderexprinplace(&n.Left, order)
+		var l *NodeList
+		cleantempnopop(t, order, &l)
+		n.Nbody = concat(l, n.Nbody)
+		l = nil
+		cleantempnopop(t, order, &l)
+		n.Rlist = concat(l, n.Rlist)
+		poptemp(t, order)
+		orderblock(&n.Nbody)
+		orderblock(&n.Rlist)
+		order.out = list(order.out, n)
+
+		// Special: argument will be converted to interface using convT2E
+	// so make sure it is an addressable temporary.
+	case OPANIC:
+		t := marktemp(order)
+
+		orderexpr(&n.Left, order, nil)
+		if !Isinter(n.Left.Type) {
+			orderaddrtemp(&n.Left, order)
+		}
+		order.out = list(order.out, n)
+		cleantemp(t, order)
+
+		// n->right is the expression being ranged over.
+	// order it, and then make a copy if we need one.
+	// We almost always do, to ensure that we don't
+	// see any value changes made during the loop.
+	// Usually the copy is cheap (e.g., array pointer, chan, slice, string are all tiny).
+	// The exception is ranging over an array value (not a slice, not a pointer to array),
+	// which must make a copy to avoid seeing updates made during
+	// the range body. Ranging over an array value is uncommon though.
+	case ORANGE:
+		t := marktemp(order)
+
+		orderexpr(&n.Right, order, nil)
+		switch n.Type.Etype {
+		default:
+			Fatal("orderstmt range %v", n.Type)
+
+			// Mark []byte(str) range expression to reuse string backing storage.
+		// It is safe because the storage cannot be mutated.
+		case TARRAY:
+			if n.Right.Op == OSTRARRAYBYTE {
+				n.Right.Op = OSTRARRAYBYTETMP
+			}
+			if count(n.List) < 2 || isblank(n.List.Next.N) {
+				// for i := range x will only use x once, to compute len(x).
+				// No need to copy it.
+				break
+			}
+			fallthrough
+
+			// chan, string, slice, array ranges use value multiple times.
+		// make copy.
+		// fall through
+		case TCHAN, TSTRING:
+			r := n.Right
+
+			if r.Type.Etype == TSTRING && r.Type != Types[TSTRING] {
+				r = Nod(OCONV, r, nil)
+				r.Type = Types[TSTRING]
+				typecheck(&r, Erv)
+			}
+
+			n.Right = ordercopyexpr(r, r.Type, order, 0)
+
+			// copy the map value in case it is a map literal.
+		// TODO(rsc): Make tmp = literal expressions reuse tmp.
+		// For maps tmp is just one word so it hardly matters.
+		case TMAP:
+			r := n.Right
+
+			n.Right = ordercopyexpr(r, r.Type, order, 0)
+
+			// n->alloc is the temp for the iterator.
+			prealloc[n] = ordertemp(Types[TUINT8], order, true)
+		}
+
+		for l := n.List; l != nil; l = l.Next {
+			orderexprinplace(&l.N, order)
+		}
+		orderblock(&n.Nbody)
+		order.out = list(order.out, n)
+		cleantemp(t, order)
+
+	case ORETURN:
+		ordercallargs(&n.List, order)
+		order.out = list(order.out, n)
+
+		// Special: clean case temporaries in each block entry.
+	// Select must enter one of its blocks, so there is no
+	// need for a cleaning at the end.
+	// Doubly special: evaluation order for select is stricter
+	// than ordinary expressions. Even something like p.c
+	// has to be hoisted into a temporary, so that it cannot be
+	// reordered after the channel evaluation for a different
+	// case (if p were nil, then the timing of the fault would
+	// give this away).
+	case OSELECT:
+		t := marktemp(order)
+
+		var tmp1 *Node
+		var tmp2 *Node
+		var r *Node
+		for l := n.List; l != nil; l = l.Next {
+			if l.N.Op != OXCASE {
+				Fatal("order select case %v", Oconv(int(l.N.Op), 0))
+			}
+			r = l.N.Left
+			setlineno(l.N)
+
+			// Append any new body prologue to ninit.
+			// The next loop will insert ninit into nbody.
+			if l.N.Ninit != nil {
+				Fatal("order select ninit")
+			}
+			if r != nil {
+				switch r.Op {
+				default:
+					Yyerror("unknown op in select %v", Oconv(int(r.Op), 0))
+					Dump("select case", r)
+
+					// If this is case x := <-ch or case x, y := <-ch, the case has
+				// 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:
+					if r.Colas {
+						t = r.Ninit
+						if t != nil && t.N.Op == ODCL && t.N.Left == r.Left {
+							t = t.Next
+						}
+						if t != nil && t.N.Op == ODCL && r.List != nil && t.N.Left == r.List.N {
+							t = t.Next
+						}
+						if t == nil {
+							r.Ninit = nil
+						}
+					}
+
+					if r.Ninit != nil {
+						Yyerror("ninit on select recv")
+						dumplist("ninit", r.Ninit)
+					}
+
+					// case x = <-c
+					// case x, ok = <-c
+					// r->left is x, r->ntest is ok, r->right is ORECV, r->right->left is c.
+					// r->left == N means 'case <-c'.
+					// c is always evaluated; x and ok are only evaluated when assigned.
+					orderexpr(&r.Right.Left, order, nil)
+
+					if r.Right.Left.Op != ONAME {
+						r.Right.Left = ordercopyexpr(r.Right.Left, r.Right.Left.Type, order, 0)
+					}
+
+					// Introduce temporary for receive and move actual copy into case body.
+					// avoids problems with target being addressed, as usual.
+					// NOTE: If we wanted to be clever, we could arrange for just one
+					// temporary per distinct type, sharing the temp among all receives
+					// with that temp. Similarly one ok bool could be shared among all
+					// the x,ok receives. Not worth doing until there's a clear need.
+					if r.Left != nil && isblank(r.Left) {
+						r.Left = nil
+					}
+					if r.Left != nil {
+						// use channel element type for temporary to avoid conversions,
+						// such as in case interfacevalue = <-intchan.
+						// the conversion happens in the OAS instead.
+						tmp1 = r.Left
+
+						if r.Colas {
+							tmp2 = Nod(ODCL, tmp1, nil)
+							typecheck(&tmp2, Etop)
+							l.N.Ninit = list(l.N.Ninit, tmp2)
+						}
+
+						r.Left = ordertemp(r.Right.Left.Type.Type, order, haspointers(r.Right.Left.Type.Type))
+						tmp2 = Nod(OAS, tmp1, r.Left)
+						typecheck(&tmp2, Etop)
+						l.N.Ninit = list(l.N.Ninit, tmp2)
+					}
+
+					if r.List != nil && isblank(r.List.N) {
+						r.List = nil
+					}
+					if r.List != nil {
+						tmp1 = r.List.N
+						if r.Colas {
+							tmp2 = Nod(ODCL, tmp1, nil)
+							typecheck(&tmp2, Etop)
+							l.N.Ninit = list(l.N.Ninit, tmp2)
+						}
+
+						r.List = list1(ordertemp(tmp1.Type, order, false))
+						tmp2 = Nod(OAS, tmp1, r.List.N)
+						typecheck(&tmp2, Etop)
+						l.N.Ninit = list(l.N.Ninit, tmp2)
+					}
+
+					orderblock(&l.N.Ninit)
+
+				case OSEND:
+					if r.Ninit != nil {
+						Yyerror("ninit on select send")
+						dumplist("ninit", r.Ninit)
+					}
+
+					// case c <- x
+					// r->left is c, r->right is x, both are always evaluated.
+					orderexpr(&r.Left, order, nil)
+
+					if !istemp(r.Left) {
+						r.Left = ordercopyexpr(r.Left, r.Left.Type, order, 0)
+					}
+					orderexpr(&r.Right, order, nil)
+					if !istemp(r.Right) {
+						r.Right = ordercopyexpr(r.Right, r.Right.Type, order, 0)
+					}
+				}
+			}
+
+			orderblock(&l.N.Nbody)
+		}
+
+		// Now that we have accumulated all the temporaries, clean them.
+		// Also insert any ninit queued during the previous loop.
+		// (The temporary cleaning must follow that ninit work.)
+		for l := n.List; l != nil; l = l.Next {
+			cleantempnopop(t, order, &l.N.Ninit)
+			l.N.Nbody = concat(l.N.Ninit, l.N.Nbody)
+			l.N.Ninit = nil
+		}
+
+		order.out = list(order.out, n)
+		poptemp(t, order)
+
+		// Special: value being sent is passed as a pointer; make it addressable.
+	case OSEND:
+		t := marktemp(order)
+
+		orderexpr(&n.Left, order, nil)
+		orderexpr(&n.Right, order, nil)
+		orderaddrtemp(&n.Right, order)
+		order.out = list(order.out, n)
+		cleantemp(t, order)
+
+		// TODO(rsc): Clean temporaries more aggressively.
+	// Note that because walkswitch will rewrite some of the
+	// switch into a binary search, this is not as easy as it looks.
+	// (If we ran that code here we could invoke orderstmt on
+	// the if-else chain instead.)
+	// For now just clean all the temporaries at the end.
+	// In practice that's fine.
+	case OSWITCH:
+		t := marktemp(order)
+
+		orderexpr(&n.Left, order, nil)
+		for l := n.List; l != nil; l = l.Next {
+			if l.N.Op != OXCASE {
+				Fatal("order switch case %v", Oconv(int(l.N.Op), 0))
+			}
+			orderexprlistinplace(l.N.List, order)
+			orderblock(&l.N.Nbody)
+		}
+
+		order.out = list(order.out, n)
+		cleantemp(t, order)
+	}
+
+	lineno = int32(lno)
+}
+
+// Orderexprlist orders the expression list l into order.
+func orderexprlist(l *NodeList, order *Order) {
+	for ; l != nil; l = l.Next {
+		orderexpr(&l.N, order, nil)
+	}
+}
+
+// Orderexprlist orders the expression list l but saves
+// the side effects on the individual expression ninit lists.
+func orderexprlistinplace(l *NodeList, order *Order) {
+	for ; l != nil; l = l.Next {
+		orderexprinplace(&l.N, order)
+	}
+}
+
+// prealloc[x] records the allocation to use for x.
+var prealloc = map[*Node]*Node{}
+
+// Orderexpr orders a single expression, appending side
+// effects to order->out as needed.
+// If this is part of an assignment lhs = *np, lhs is given.
+// Otherwise lhs == nil. (When lhs != nil it may be possible
+// to avoid copying the result of the expression to a temporary.)
+func orderexpr(np **Node, order *Order, lhs *Node) {
+	n := *np
+	if n == nil {
+		return
+	}
+
+	lno := int(setlineno(n))
+	orderinit(n, order)
+
+	switch n.Op {
+	default:
+		orderexpr(&n.Left, order, nil)
+		orderexpr(&n.Right, order, nil)
+		orderexprlist(n.List, order)
+		orderexprlist(n.Rlist, order)
+
+		// Addition of strings turns into a function call.
+	// Allocate a temporary to hold the strings.
+	// Fewer than 5 strings use direct runtime helpers.
+	case OADDSTR:
+		orderexprlist(n.List, order)
+
+		if count(n.List) > 5 {
+			t := typ(TARRAY)
+			t.Bound = int64(count(n.List))
+			t.Type = Types[TSTRING]
+			prealloc[n] = ordertemp(t, order, false)
+		}
+
+		// Mark string(byteSlice) arguments to reuse byteSlice backing
+		// buffer during conversion. String concatenation does not
+		// memorize the strings for later use, so it is safe.
+		// However, we can do it only if there is at least one non-empty string literal.
+		// Otherwise if all other arguments are empty strings,
+		// concatstrings will return the reference to the temp string
+		// to the caller.
+		hasbyte := false
+
+		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.(string)) != 0
+		}
+
+		if haslit && hasbyte {
+			for l := n.List; l != nil; l = l.Next {
+				if l.N.Op == OARRAYBYTESTR {
+					l.N.Op = OARRAYBYTESTRTMP
+				}
+			}
+		}
+
+	case OCMPSTR:
+		orderexpr(&n.Left, order, nil)
+		orderexpr(&n.Right, order, nil)
+
+		// Mark string(byteSlice) arguments to reuse byteSlice backing
+		// buffer during conversion. String comparison does not
+		// memorize the strings for later use, so it is safe.
+		if n.Left.Op == OARRAYBYTESTR {
+			n.Left.Op = OARRAYBYTESTRTMP
+		}
+		if n.Right.Op == OARRAYBYTESTR {
+			n.Right.Op = OARRAYBYTESTRTMP
+		}
+
+		// key must be addressable
+	case OINDEXMAP:
+		orderexpr(&n.Left, order, nil)
+
+		orderexpr(&n.Right, order, nil)
+
+		// For x = m[string(k)] where k is []byte, the allocation of
+		// backing bytes for the string can be avoided by reusing
+		// the []byte backing array. This is a special case that it
+		// would be nice to handle more generally, but because
+		// there are no []byte-keyed maps, this specific case comes
+		// up in important cases in practice. See issue 3512.
+		// Nothing can change the []byte we are not copying before
+		// the map index, because the map access is going to
+		// be forced to happen immediately following this
+		// conversion (by the ordercopyexpr a few lines below).
+		if n.Etype == 0 && n.Right.Op == OARRAYBYTESTR {
+			n.Right.Op = OARRAYBYTESTRTMP
+		}
+
+		orderaddrtemp(&n.Right, order)
+		if n.Etype == 0 {
+			// use of value (not being assigned);
+			// make copy in temporary.
+			n = ordercopyexpr(n, n.Type, order, 0)
+		}
+
+		// concrete type (not interface) argument must be addressable
+	// temporary to pass to runtime.
+	case OCONVIFACE:
+		orderexpr(&n.Left, order, nil)
+
+		if !Isinter(n.Left.Type) {
+			orderaddrtemp(&n.Left, order)
+		}
+
+	case OANDAND, OOROR:
+		mark := marktemp(order)
+		orderexpr(&n.Left, order, nil)
+
+		// 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.
+		var l *NodeList
+
+		cleantempnopop(mark, order, &l)
+		n.Right.Ninit = concat(l, n.Right.Ninit)
+		orderexprinplace(&n.Right, order)
+
+	case OCALLFUNC,
+		OCALLINTER,
+		OCALLMETH,
+		OCAP,
+		OCOMPLEX,
+		OCOPY,
+		OIMAG,
+		OLEN,
+		OMAKECHAN,
+		OMAKEMAP,
+		OMAKESLICE,
+		ONEW,
+		OREAL,
+		ORECOVER:
+		ordercall(n, order)
+		if lhs == nil || lhs.Op != ONAME || flag_race != 0 {
+			n = ordercopyexpr(n, n.Type, order, 0)
+		}
+
+	case OAPPEND:
+		ordercallargs(&n.List, order)
+		if lhs == nil || lhs.Op != ONAME && !samesafeexpr(lhs, n.List.N) {
+			n = ordercopyexpr(n, n.Type, order, 0)
+		}
+
+	case OSLICE, OSLICEARR, OSLICESTR:
+		orderexpr(&n.Left, order, nil)
+		orderexpr(&n.Right.Left, order, nil)
+		n.Right.Left = ordercheapexpr(n.Right.Left, order)
+		orderexpr(&n.Right.Right, order, nil)
+		n.Right.Right = ordercheapexpr(n.Right.Right, order)
+		if lhs == nil || lhs.Op != ONAME && !samesafeexpr(lhs, n.Left) {
+			n = ordercopyexpr(n, n.Type, order, 0)
+		}
+
+	case OSLICE3, OSLICE3ARR:
+		orderexpr(&n.Left, order, nil)
+		orderexpr(&n.Right.Left, order, nil)
+		n.Right.Left = ordercheapexpr(n.Right.Left, order)
+		orderexpr(&n.Right.Right.Left, order, nil)
+		n.Right.Right.Left = ordercheapexpr(n.Right.Right.Left, order)
+		orderexpr(&n.Right.Right.Right, order, nil)
+		n.Right.Right.Right = ordercheapexpr(n.Right.Right.Right, order)
+		if lhs == nil || lhs.Op != ONAME && !samesafeexpr(lhs, n.Left) {
+			n = ordercopyexpr(n, n.Type, order, 0)
+		}
+
+	case OCLOSURE:
+		if n.Noescape && n.Func.Cvars != nil {
+			prealloc[n] = ordertemp(Types[TUINT8], order, false) // walk will fill in correct type
+		}
+
+	case OARRAYLIT, OCALLPART:
+		orderexpr(&n.Left, order, nil)
+		orderexpr(&n.Right, order, nil)
+		orderexprlist(n.List, order)
+		orderexprlist(n.Rlist, order)
+		if n.Noescape {
+			prealloc[n] = ordertemp(Types[TUINT8], order, false) // walk will fill in correct type
+		}
+
+	case ODDDARG:
+		if n.Noescape {
+			// The ddd argument does not live beyond the call it is created for.
+			// Allocate a temporary that will be cleaned up when this statement
+			// completes. We could be more aggressive and try to arrange for it
+			// to be cleaned up when the call completes.
+			prealloc[n] = ordertemp(n.Type.Type, order, false)
+		}
+
+	case ODOTTYPE, ODOTTYPE2:
+		orderexpr(&n.Left, order, nil)
+		// 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, nil)
+		n = ordercopyexpr(n, n.Type, order, 1)
+
+	case OEQ, ONE:
+		orderexpr(&n.Left, order, nil)
+		orderexpr(&n.Right, order, nil)
+		t := n.Left.Type
+		if t.Etype == TSTRUCT || Isfixedarray(t) {
+			// for complex comparisons, we need both args to be
+			// addressable so we can pass them to the runtime.
+			orderaddrtemp(&n.Left, order)
+			orderaddrtemp(&n.Right, order)
+		}
+	}
+
+	lineno = int32(lno)
+
+	*np = n
+}
diff --git a/src/cmd/compile/internal/gc/pgen.go b/src/cmd/compile/internal/gc/pgen.go
new file mode 100644
index 0000000..47cb8b1
--- /dev/null
+++ b/src/cmd/compile/internal/gc/pgen.go
@@ -0,0 +1,544 @@
+// 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 gc
+
+import (
+	"cmd/internal/obj"
+	"crypto/md5"
+	"fmt"
+	"strings"
+)
+
+// "Portable" code generation.
+
+var makefuncdatasym_nsym int32
+
+func makefuncdatasym(namefmt string, funcdatakind int64) *Sym {
+	var nod Node
+
+	sym := Lookupf(namefmt, makefuncdatasym_nsym)
+	makefuncdatasym_nsym++
+	pnod := newname(sym)
+	pnod.Class = PEXTERN
+	Nodconst(&nod, Types[TINT32], funcdatakind)
+	Thearch.Gins(obj.AFUNCDATA, &nod, pnod)
+	return sym
+}
+
+// gvardef inserts a VARDEF for n into the instruction stream.
+// VARDEF is an annotation for the liveness analysis, marking a place
+// where a complete initialization (definition) of a variable begins.
+// Since the liveness analysis can see initialization of single-word
+// variables quite easy, gvardef is usually only called for multi-word
+// or 'fat' variables, those satisfying isfat(n->type).
+// However, gvardef is also called when a non-fat variable is initialized
+// via a block move; the only time this happens is when you have
+//	return f()
+// for a function with multiple return values exactly matching the return
+// types of the current function.
+//
+// A 'VARDEF x' annotation in the instruction stream tells the liveness
+// analysis to behave as though the variable x is being initialized at that
+// point in the instruction stream. The VARDEF must appear before the
+// actual (multi-instruction) initialization, and it must also appear after
+// any uses of the previous value, if any. For example, if compiling:
+//
+//	x = x[1:]
+//
+// it is important to generate code like:
+//
+//	base, len, cap = pieces of x[1:]
+//	VARDEF x
+//	x = {base, len, cap}
+//
+// If instead the generated code looked like:
+//
+//	VARDEF x
+//	base, len, cap = pieces of x[1:]
+//	x = {base, len, cap}
+//
+// then the liveness analysis would decide the previous value of x was
+// unnecessary even though it is about to be used by the x[1:] computation.
+// Similarly, if the generated code looked like:
+//
+//	base, len, cap = pieces of x[1:]
+//	x = {base, len, cap}
+//	VARDEF x
+//
+// then the liveness analysis will not preserve the new value of x, because
+// the VARDEF appears to have "overwritten" it.
+//
+// VARDEF is a bit of a kludge to work around the fact that the instruction
+// stream is working on single-word values but the liveness analysis
+// wants to work on individual variables, which might be multi-word
+// aggregates. It might make sense at some point to look into letting
+// the liveness analysis work on single-word values as well, although
+// there are complications around interface values, slices, and strings,
+// all of which cannot be treated as individual words.
+//
+// VARKILL is the opposite of VARDEF: it marks a value as no longer needed,
+// even if its address has been taken. That is, a VARKILL annotation asserts
+// that its argument is certainly dead, for use when the liveness analysis
+// would not otherwise be able to deduce that fact.
+
+func gvardefx(n *Node, as int) {
+	if n == nil {
+		Fatal("gvardef nil")
+	}
+	if n.Op != ONAME {
+		Yyerror("gvardef %v; %v", Oconv(int(n.Op), obj.FmtSharp), n)
+		return
+	}
+
+	switch n.Class {
+	case PAUTO, PPARAM, PPARAMOUT:
+		Thearch.Gins(as, nil, n)
+	}
+}
+
+func Gvardef(n *Node) {
+	gvardefx(n, obj.AVARDEF)
+}
+
+func gvarkill(n *Node) {
+	gvardefx(n, obj.AVARKILL)
+}
+
+func removevardef(firstp *obj.Prog) {
+	for p := firstp; p != nil; p = p.Link {
+		for p.Link != nil && (p.Link.As == obj.AVARDEF || p.Link.As == obj.AVARKILL) {
+			p.Link = p.Link.Link
+		}
+		if p.To.Type == obj.TYPE_BRANCH {
+			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
+			}
+		}
+	}
+}
+
+func gcsymdup(s *Sym) {
+	ls := Linksym(s)
+	if len(ls.R) > 0 {
+		Fatal("cannot rosymdup %s with relocations", ls.Name)
+	}
+	ls.Name = fmt.Sprintf("gclocals·%x", md5.Sum(ls.P))
+	ls.Dupok = 1
+}
+
+func emitptrargsmap() {
+	sym := Lookup(fmt.Sprintf("%s.args_stackmap", Curfn.Func.Nname.Sym.Name))
+
+	nptr := int(Curfn.Type.Argwid / int64(Widthptr))
+	bv := bvalloc(int32(nptr) * 2)
+	nbitmap := 1
+	if Curfn.Type.Outtuple > 0 {
+		nbitmap = 2
+	}
+	off := duint32(sym, 0, uint32(nbitmap))
+	off = duint32(sym, off, uint32(bv.n))
+	var xoffset int64
+	if Curfn.Type.Thistuple > 0 {
+		xoffset = 0
+		onebitwalktype1(getthisx(Curfn.Type), &xoffset, bv)
+	}
+
+	if Curfn.Type.Intuple > 0 {
+		xoffset = 0
+		onebitwalktype1(getinargx(Curfn.Type), &xoffset, bv)
+	}
+
+	for j := 0; int32(j) < bv.n; j += 32 {
+		off = duint32(sym, off, bv.b[j/32])
+	}
+	if Curfn.Type.Outtuple > 0 {
+		xoffset = 0
+		onebitwalktype1(getoutargx(Curfn.Type), &xoffset, bv)
+		for j := 0; int32(j) < bv.n; j += 32 {
+			off = duint32(sym, off, bv.b[j/32])
+		}
+	}
+
+	ggloblsym(sym, int32(off), obj.RODATA|obj.LOCAL)
+}
+
+// Sort the list of stack variables. Autos after anything else,
+// within autos, unused after used, within used, things with
+// pointers first, zeroed things first, and then decreasing size.
+// Because autos are laid out in decreasing addresses
+// on the stack, pointers first, zeroed things first and decreasing size
+// really means, in memory, things with pointers needing zeroing at
+// the top of the stack and increasing in size.
+// Non-autos sort on offset.
+func cmpstackvar(a *Node, b *Node) int {
+	if a.Class != b.Class {
+		if a.Class == PAUTO {
+			return +1
+		}
+		return -1
+	}
+
+	if a.Class != PAUTO {
+		if a.Xoffset < b.Xoffset {
+			return -1
+		}
+		if a.Xoffset > b.Xoffset {
+			return +1
+		}
+		return 0
+	}
+
+	if a.Used != b.Used {
+		return obj.Bool2int(b.Used) - obj.Bool2int(a.Used)
+	}
+
+	ap := obj.Bool2int(haspointers(a.Type))
+	bp := obj.Bool2int(haspointers(b.Type))
+	if ap != bp {
+		return bp - ap
+	}
+
+	ap = obj.Bool2int(a.Name.Needzero)
+	bp = obj.Bool2int(b.Name.Needzero)
+	if ap != bp {
+		return bp - ap
+	}
+
+	if a.Type.Width < b.Type.Width {
+		return +1
+	}
+	if a.Type.Width > b.Type.Width {
+		return -1
+	}
+
+	return stringsCompare(a.Sym.Name, b.Sym.Name)
+}
+
+// stkdelta records the stack offset delta for a node
+// during the compaction of the stack frame to remove
+// unused stack slots.
+var stkdelta = map[*Node]int64{}
+
+// TODO(lvd) find out where the PAUTO/OLITERAL nodes come from.
+func allocauto(ptxt *obj.Prog) {
+	Stksize = 0
+	stkptrsize = 0
+
+	if Curfn.Func.Dcl == nil {
+		return
+	}
+
+	// Mark the PAUTO's unused.
+	for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
+		if ll.N.Class == PAUTO {
+			ll.N.Used = false
+		}
+	}
+
+	markautoused(ptxt)
+
+	listsort(&Curfn.Func.Dcl, cmpstackvar)
+
+	// Unused autos are at the end, chop 'em off.
+	ll := Curfn.Func.Dcl
+
+	n := ll.N
+	if n.Class == PAUTO && n.Op == ONAME && !n.Used {
+		// No locals used at all
+		Curfn.Func.Dcl = nil
+
+		fixautoused(ptxt)
+		return
+	}
+
+	for ll := Curfn.Func.Dcl; ll.Next != nil; ll = ll.Next {
+		n = ll.Next.N
+		if n.Class == PAUTO && n.Op == ONAME && !n.Used {
+			ll.Next = nil
+			Curfn.Func.Dcl.End = ll
+			break
+		}
+	}
+
+	// Reassign stack offsets of the locals that are still there.
+	var w int64
+	for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
+		n = ll.N
+		if n.Class != PAUTO || n.Op != ONAME {
+			continue
+		}
+
+		dowidth(n.Type)
+		w = n.Type.Width
+		if w >= Thearch.MAXWIDTH || w < 0 {
+			Fatal("bad width")
+		}
+		Stksize += w
+		Stksize = Rnd(Stksize, int64(n.Type.Align))
+		if haspointers(n.Type) {
+			stkptrsize = Stksize
+		}
+		if Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9' {
+			Stksize = Rnd(Stksize, int64(Widthptr))
+		}
+		if Stksize >= 1<<31 {
+			setlineno(Curfn)
+			Yyerror("stack frame too large (>2GB)")
+		}
+
+		stkdelta[n] = -Stksize - n.Xoffset
+	}
+
+	Stksize = Rnd(Stksize, int64(Widthreg))
+	stkptrsize = Rnd(stkptrsize, int64(Widthreg))
+
+	fixautoused(ptxt)
+
+	// The debug information needs accurate offsets on the symbols.
+	for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
+		if ll.N.Class != PAUTO || ll.N.Op != ONAME {
+			continue
+		}
+		ll.N.Xoffset += stkdelta[ll.N]
+		delete(stkdelta, ll.N)
+	}
+}
+
+func Cgen_checknil(n *Node) {
+	if Disable_checknil != 0 {
+		return
+	}
+
+	// Ideally we wouldn't see any integer types here, but we do.
+	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 == '7' || Thearch.Thechar == '9') && n.Op != OREGISTER) || !n.Addable || n.Op == OLITERAL {
+		var reg Node
+		Regalloc(&reg, Types[Tptr], n)
+		Cgen(n, &reg)
+		Thearch.Gins(obj.ACHECKNIL, &reg, nil)
+		Regfree(&reg)
+		return
+	}
+
+	Thearch.Gins(obj.ACHECKNIL, n, nil)
+}
+
+func compile(fn *Node) {
+	if Newproc == nil {
+		Newproc = Sysfunc("newproc")
+		Deferproc = Sysfunc("deferproc")
+		Deferreturn = Sysfunc("deferreturn")
+		Panicindex = Sysfunc("panicindex")
+		panicslice = Sysfunc("panicslice")
+		throwreturn = Sysfunc("throwreturn")
+	}
+
+	lno := setlineno(fn)
+
+	Curfn = fn
+	dowidth(Curfn.Type)
+
+	var oldstksize int64
+	var nod1 Node
+	var ptxt *obj.Prog
+	var pl *obj.Plist
+	var p *obj.Prog
+	var n *Node
+	var nam *Node
+	var gcargs *Sym
+	var gclocals *Sym
+	if fn.Nbody == nil {
+		if pure_go != 0 || strings.HasPrefix(fn.Func.Nname.Sym.Name, "init.") {
+			Yyerror("missing function body for %q", fn.Func.Nname.Sym.Name)
+			goto ret
+		}
+
+		if Debug['A'] != 0 {
+			goto ret
+		}
+		emitptrargsmap()
+		goto ret
+	}
+
+	saveerrors()
+
+	// set up domain for labels
+	clearlabels()
+
+	if Curfn.Type.Outnamed != 0 {
+		// add clearing of the output parameters
+		var save Iter
+		t := Structfirst(&save, Getoutarg(Curfn.Type))
+
+		for t != nil {
+			if t.Nname != nil {
+				n = Nod(OAS, t.Nname, nil)
+				typecheck(&n, Etop)
+				Curfn.Nbody = concat(list1(n), Curfn.Nbody)
+			}
+
+			t = structnext(&save)
+		}
+	}
+
+	order(Curfn)
+	if nerrors != 0 {
+		goto ret
+	}
+
+	Hasdefer = 0
+	walk(Curfn)
+	if nerrors != 0 {
+		goto ret
+	}
+	if flag_race != 0 {
+		racewalk(Curfn)
+	}
+	if nerrors != 0 {
+		goto ret
+	}
+
+	continpc = nil
+	breakpc = nil
+
+	pl = newplist()
+	pl.Name = Linksym(Curfn.Func.Nname.Sym)
+
+	setlineno(Curfn)
+
+	Nodconst(&nod1, Types[TINT32], 0)
+	nam = Curfn.Func.Nname
+	if isblank(nam) {
+		nam = nil
+	}
+	ptxt = Thearch.Gins(obj.ATEXT, nam, &nod1)
+	Afunclit(&ptxt.From, Curfn.Func.Nname)
+	ptxt.From3 = new(obj.Addr)
+	if fn.Func.Dupok {
+		ptxt.From3.Offset |= obj.DUPOK
+	}
+	if fn.Func.Wrapper {
+		ptxt.From3.Offset |= obj.WRAPPER
+	}
+	if fn.Func.Needctxt {
+		ptxt.From3.Offset |= obj.NEEDCTXT
+	}
+	if fn.Func.Nosplit {
+		ptxt.From3.Offset |= obj.NOSPLIT
+	}
+	if fn.Func.Systemstack {
+		ptxt.From.Sym.Cfunc = 1
+	}
+
+	// Clumsy but important.
+	// See test/recover.go for test cases and src/reflect/value.go
+	// for the actual functions being considered.
+	if myimportpath != "" && myimportpath == "reflect" {
+		if Curfn.Func.Nname.Sym.Name == "callReflect" || Curfn.Func.Nname.Sym.Name == "callMethod" {
+			ptxt.From3.Offset |= obj.WRAPPER
+		}
+	}
+
+	ginit()
+
+	gcargs = makefuncdatasym("gcargs·%d", obj.FUNCDATA_ArgsPointerMaps)
+	gclocals = makefuncdatasym("gclocals·%d", obj.FUNCDATA_LocalsPointerMaps)
+
+	for _, t := range Curfn.Func.Fieldtrack {
+		gtrack(tracksym(t))
+	}
+
+	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:
+			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.Func.Enter)
+	Genlist(Curfn.Nbody)
+	gclean()
+	checklabels()
+	if nerrors != 0 {
+		goto ret
+	}
+	if Curfn.Func.Endlineno != 0 {
+		lineno = Curfn.Func.Endlineno
+	}
+
+	if Curfn.Type.Outtuple != 0 {
+		Ginscall(throwreturn, 0)
+	}
+
+	ginit()
+
+	// TODO: Determine when the final cgen_ret can be omitted. Perhaps always?
+	cgen_ret(nil)
+
+	if Hasdefer != 0 {
+		// deferreturn pretends to have one uintptr argument.
+		// Reserve space for it so stack scanner is happy.
+		if Maxarg < int64(Widthptr) {
+			Maxarg = int64(Widthptr)
+		}
+	}
+
+	gclean()
+	if nerrors != 0 {
+		goto ret
+	}
+
+	Pc.As = obj.ARET // overwrite AEND
+	Pc.Lineno = lineno
+
+	fixjmp(ptxt)
+	if Debug['N'] == 0 || Debug['R'] != 0 || Debug['P'] != 0 {
+		regopt(ptxt)
+		nilopt(ptxt)
+	}
+
+	Thearch.Expandchecks(ptxt)
+
+	oldstksize = Stksize
+	allocauto(ptxt)
+
+	if false {
+		fmt.Printf("allocauto: %d to %d\n", oldstksize, int64(Stksize))
+	}
+
+	setlineno(Curfn)
+	if int64(Stksize)+Maxarg > 1<<31 {
+		Yyerror("stack frame too large (>2GB)")
+		goto ret
+	}
+
+	// Emit garbage collection symbols.
+	liveness(Curfn, ptxt, gcargs, gclocals)
+
+	gcsymdup(gcargs)
+	gcsymdup(gclocals)
+
+	Thearch.Defframe(ptxt)
+
+	if Debug['f'] != 0 {
+		frame(0)
+	}
+
+	// Remove leftover instrumentation from the instruction stream.
+	removevardef(ptxt)
+
+ret:
+	lineno = lno
+}
diff --git a/src/cmd/compile/internal/gc/plive.go b/src/cmd/compile/internal/gc/plive.go
new file mode 100644
index 0000000..efaf69f
--- /dev/null
+++ b/src/cmd/compile/internal/gc/plive.go
@@ -0,0 +1,1830 @@
+// 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.
+
+// 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 (
+	"cmd/internal/obj"
+	"fmt"
+	"sort"
+)
+
+const (
+	UNVISITED = 0
+	VISITED   = 1
+)
+
+// An ordinary basic block.
+//
+// Instructions are threaded together in a doubly-linked list.  To iterate in
+// program order follow the link pointer from the first node and stop after the
+// last node has been visited
+//
+//   for(p = bb->first;; p = p->link) {
+//     ...
+//     if(p == bb->last)
+//       break;
+//   }
+//
+// To iterate in reverse program order by following the opt pointer from the
+// last node
+//
+//   for(p = bb->last; p != nil; p = p->opt) {
+//     ...
+//   }
+type BasicBlock struct {
+	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
+
+	// 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{} {
+	result := (interface{})(make([]byte, size))
+	if result == nil {
+		Fatal("malloc failed")
+	}
+	return result
+}
+
+// Constructs a new basic block containing a single instruction.
+func newblock(prog *obj.Prog) *BasicBlock {
+	if prog == nil {
+		Fatal("newblock: prog cannot be nil")
+	}
+	result := new(BasicBlock)
+	result.rpo = -1
+	result.mark = UNVISITED
+	result.first = prog
+	result.last = prog
+	result.pred = make([]*BasicBlock, 0, 2)
+	result.succ = make([]*BasicBlock, 0, 2)
+	return result
+}
+
+// Frees a basic block and all of its leaf data structures.
+func freeblock(bb *BasicBlock) {
+	if bb == nil {
+		Fatal("freeblock: cannot free nil")
+	}
+}
+
+// Adds an edge between two basic blocks by making from a predecessor of to and
+// to a successor of from.
+func addedge(from *BasicBlock, to *BasicBlock) {
+	if from == nil {
+		Fatal("addedge: from is nil")
+	}
+	if to == nil {
+		Fatal("addedge: to is nil")
+	}
+	from.succ = append(from.succ, to)
+	to.pred = append(to.pred, from)
+}
+
+// Inserts prev before curr in the instruction
+// stream.  Any control flow, such as branches or fall throughs, that target the
+// existing instruction are adjusted to target the new instruction.
+func splicebefore(lv *Liveness, bb *BasicBlock, prev *obj.Prog, curr *obj.Prog) {
+	// There may be other instructions pointing at curr,
+	// and we want them to now point at prev. Instead of
+	// trying to find all such instructions, swap the contents
+	// so that the problem becomes inserting next after curr.
+	// The "opt" field is the backward link in the linked list.
+
+	// Overwrite curr's data with prev, but keep the list links.
+	tmp := *curr
+
+	*curr = *prev
+	curr.Opt = tmp.Opt
+	curr.Link = tmp.Link
+
+	// Overwrite prev (now next) with curr's old data.
+	next := prev
+
+	*next = tmp
+	next.Opt = nil
+	next.Link = nil
+
+	// Now insert next after curr.
+	next.Link = curr.Link
+
+	next.Opt = curr
+	curr.Link = next
+	if next.Link != nil && next.Link.Opt == curr {
+		next.Link.Opt = next
+	}
+
+	if bb.last == curr {
+		bb.last = next
+	}
+}
+
+// A pretty printer for basic blocks.
+func printblock(bb *BasicBlock) {
+	fmt.Printf("basic block %d\n", bb.rpo)
+	fmt.Printf("\tpred:")
+	for _, pred := range bb.pred {
+		fmt.Printf(" %d", pred.rpo)
+	}
+	fmt.Printf("\n")
+	fmt.Printf("\tsucc:")
+	for _, succ := range bb.succ {
+		fmt.Printf(" %d", succ.rpo)
+	}
+	fmt.Printf("\n")
+	fmt.Printf("\tprog:\n")
+	for prog := bb.first; ; prog = prog.Link {
+		fmt.Printf("\t\t%v\n", prog)
+		if prog == bb.last {
+			break
+		}
+	}
+}
+
+// Iterates over a basic block applying a callback to each instruction.  There
+// are two criteria for termination.  If the end of basic block is reached a
+// value of zero is returned.  If the callback returns a non-zero value, the
+// iteration is stopped and the value of the callback is returned.
+func blockany(bb *BasicBlock, f func(*obj.Prog) bool) bool {
+	for p := bb.last; p != nil; p = p.Opt.(*obj.Prog) {
+		if f(p) {
+			return true
+		}
+	}
+	return false
+}
+
+// Collects and returns and array of Node*s for functions arguments and local
+// variables.
+func getvariables(fn *Node) []*Node {
+	result := make([]*Node, 0, 0)
+	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.
+			// For local variables, the bitmap only covers the stkptrsize
+			// bytes in the frame where variables containing pointers live.
+			// For arguments and results, the bitmap covers all variables,
+			// so we must include all the variables, even the ones without
+			// pointers.
+			//
+			// The Node.opt field is available for use by optimization passes.
+			// We use it to hold the index of the node in the variables array, plus 1
+			// (so that 0 means the Node is not in the variables array).
+			// Each pass should clear opt when done, but you never know,
+			// so clear them all ourselves too.
+			// The Node.curfn field is supposed to be set to the current function
+			// already, but for some compiler-introduced names it seems not to be,
+			// so fix that here.
+			// Later, when we want to find the index of a node in the variables list,
+			// we will check that n->curfn == curfn and n->opt > 0. Then n->opt - 1
+			// is the index in the variables list.
+			ll.N.SetOpt(nil)
+
+			// The compiler doesn't emit initializations for zero-width parameters or results.
+			if ll.N.Type.Width == 0 {
+				continue
+			}
+
+			ll.N.Name.Curfn = Curfn
+			switch ll.N.Class {
+			case PAUTO:
+				if haspointers(ll.N.Type) {
+					ll.N.SetOpt(int32(len(result)))
+					result = append(result, ll.N)
+				}
+
+			case PPARAM, PPARAMOUT:
+				ll.N.SetOpt(int32(len(result)))
+				result = append(result, ll.N)
+			}
+		}
+	}
+
+	return result
+}
+
+// A pretty printer for control flow graphs.  Takes an array of BasicBlock*s.
+func printcfg(cfg []*BasicBlock) {
+	for _, bb := range cfg {
+		printblock(bb)
+	}
+}
+
+// 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) {
+	root.mark = VISITED
+	for _, bb := range root.succ {
+		if bb.mark == UNVISITED {
+			reversepostorder(bb, rpo)
+		}
+	}
+	*rpo -= 1
+	root.rpo = int(*rpo)
+}
+
+// Comparison predicate used for sorting basic blocks by their rpo in ascending
+// order.
+type blockrpocmp []*BasicBlock
+
+func (x blockrpocmp) Len() int           { return len(x) }
+func (x blockrpocmp) Swap(i, j int)      { x[i], x[j] = x[j], x[i] }
+func (x blockrpocmp) Less(i, j int) bool { return x[i].rpo < x[j].rpo }
+
+// A pattern matcher for call instructions.  Returns true when the instruction
+// is a call to a specific package qualified function name.
+func iscall(prog *obj.Prog, name *obj.LSym) bool {
+	if prog == nil {
+		Fatal("iscall: prog is nil")
+	}
+	if name == nil {
+		Fatal("iscall: function name is nil")
+	}
+	if prog.As != obj.ACALL {
+		return false
+	}
+	return name == prog.To.Sym
+}
+
+// Returns true for instructions that call a runtime function implementing a
+// select communication clause.
+
+var selectNames [4]*obj.LSym
+
+func isselectcommcasecall(prog *obj.Prog) bool {
+	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 _, name := range selectNames {
+		if iscall(prog, name) {
+			return true
+		}
+	}
+	return false
+}
+
+// Returns true for call instructions that target runtime·newselect.
+
+var isnewselect_sym *obj.LSym
+
+func isnewselect(prog *obj.Prog) bool {
+	if isnewselect_sym == nil {
+		isnewselect_sym = Linksym(Pkglookup("newselect", Runtimepkg))
+	}
+	return iscall(prog, isnewselect_sym)
+}
+
+// Returns true for call instructions that target runtime·selectgo.
+
+var isselectgocall_sym *obj.LSym
+
+func isselectgocall(prog *obj.Prog) bool {
+	if isselectgocall_sym == nil {
+		isselectgocall_sym = Linksym(Pkglookup("selectgo", Runtimepkg))
+	}
+	return iscall(prog, isselectgocall_sym)
+}
+
+var isdeferreturn_sym *obj.LSym
+
+func isdeferreturn(prog *obj.Prog) bool {
+	if isdeferreturn_sym == nil {
+		isdeferreturn_sym = Linksym(Pkglookup("deferreturn", Runtimepkg))
+	}
+	return iscall(prog, isdeferreturn_sym)
+}
+
+// Walk backwards from a runtime·selectgo call up to its immediately dominating
+// runtime·newselect call.  Any successor nodes of communication clause nodes
+// are implicit successors of the runtime·selectgo call node.  The goal of this
+// analysis is to add these missing edges to complete the control flow graph.
+func addselectgosucc(selectgo *BasicBlock) {
+	var succ *BasicBlock
+
+	pred := selectgo
+	for {
+		if len(pred.pred) == 0 {
+			Fatal("selectgo does not have a newselect")
+		}
+		pred = pred.pred[0]
+		if blockany(pred, isselectcommcasecall) {
+			// A select comm case block should have exactly one
+			// successor.
+			if len(pred.succ) != 1 {
+				Fatal("select comm case has too many successors")
+			}
+			succ = pred.succ[0]
+
+			// Its successor should have exactly two successors.
+			// The drop through should flow to the selectgo block
+			// and the branch should lead to the select case
+			// statements block.
+			if len(succ.succ) != 2 {
+				Fatal("select comm case successor has too many successors")
+			}
+
+			// Add the block as a successor of the selectgo block.
+			addedge(selectgo, succ)
+		}
+
+		if blockany(pred, isnewselect) {
+			// Reached the matching newselect.
+			break
+		}
+	}
+}
+
+// The entry point for the missing selectgo control flow algorithm.  Takes an
+// array of BasicBlock*s containing selectgo calls.
+func fixselectgo(selectgo []*BasicBlock) {
+	for _, bb := range selectgo {
+		addselectgosucc(bb)
+	}
+}
+
+// Constructs a control flow graph from a sequence of instructions.  This
+// procedure is complicated by various sources of implicit control flow that are
+// not accounted for using the standard cfg construction algorithm.  Returns an
+// array of BasicBlock*s in control flow graph form (basic blocks ordered by
+// their RPO number).
+func newcfg(firstp *obj.Prog) []*BasicBlock {
+	// Reset the opt field of each prog to nil.  In the first and second
+	// passes, instructions that are labels temporarily use the opt field to
+	// point to their basic block.  In the third pass, the opt field reset
+	// to point to the predecessor of an instruction in its basic block.
+	for p := firstp; p != nil; p = p.Link {
+		p.Opt = nil
+	}
+
+	// Allocate an array to remember where we have seen selectgo calls.
+	// These blocks will be revisited to add successor control flow edges.
+	selectgo := make([]*BasicBlock, 0, 0)
+
+	// Loop through all instructions identifying branch targets
+	// and fall-throughs and allocate basic blocks.
+	cfg := make([]*BasicBlock, 0, 0)
+
+	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.Val == nil {
+				Fatal("prog branch to nil")
+			}
+			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 {
+				p.Link.Opt = newblock(p.Link)
+				cfg = append(cfg, p.Link.Opt.(*BasicBlock))
+			}
+		} else if isselectcommcasecall(p) || isselectgocall(p) {
+			// Accommodate implicit selectgo control flow.
+			if p.Link.Opt == nil {
+				p.Link.Opt = newblock(p.Link)
+				cfg = append(cfg, p.Link.Opt.(*BasicBlock))
+			}
+		}
+	}
+
+	// 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.
+	for _, bb := range cfg {
+		for p := bb.last; p != nil; p = p.Link {
+			if p.Opt != nil && p != bb.last {
+				break
+			}
+			bb.last = p
+
+			// Stop before an unreachable RET, to avoid creating
+			// unreachable control flow nodes.
+			if p.Link != nil && p.Link.As == obj.ARET && p.Link.Mode == 1 {
+				break
+			}
+
+			// Collect basic blocks with selectgo calls.
+			if isselectgocall(p) {
+				selectgo = append(selectgo, bb)
+			}
+		}
+
+		if bb.last.To.Type == obj.TYPE_BRANCH {
+			addedge(bb, bb.last.To.Val.(*obj.Prog).Opt.(*BasicBlock))
+		}
+		if bb.last.Link != nil {
+			// Add a fall-through when the instruction is
+			// not an unconditional control transfer.
+			if bb.last.As != obj.AJMP && bb.last.As != obj.ARET && bb.last.As != obj.AUNDEF {
+				addedge(bb, bb.last.Link.Opt.(*BasicBlock))
+			}
+		}
+	}
+
+	// Add back links so the instructions in a basic block can be traversed
+	// backward.  This is the final state of the instruction opt field.
+	for _, bb := range cfg {
+		p := bb.first
+		var prev *obj.Prog
+		for {
+			p.Opt = prev
+			if p == bb.last {
+				break
+			}
+			prev = p
+			p = p.Link
+		}
+	}
+
+	// Add missing successor edges to the selectgo blocks.
+	if len(selectgo) != 0 {
+		fixselectgo([]*BasicBlock(selectgo))
+	}
+
+	// Find a depth-first order and assign a depth-first number to
+	// all basic blocks.
+	for _, bb := range cfg {
+		bb.mark = UNVISITED
+	}
+	bb = cfg[0]
+	rpo := int32(len(cfg))
+	reversepostorder(bb, &rpo)
+
+	// Sort the basic blocks by their depth first number.  The
+	// array is now a depth-first spanning tree with the first
+	// node being the root.
+	sort.Sort(blockrpocmp(cfg))
+
+	// 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)
+		Fatal("newcfg: invalid control flow graph")
+	}
+
+	return cfg
+}
+
+// Frees a control flow graph (an array of BasicBlock*s) and all of its leaf
+// data structures.
+func freecfg(cfg []*BasicBlock) {
+	if len(cfg) > 0 {
+		bb0 := cfg[0]
+		for p := bb0.first; p != nil; p = p.Link {
+			p.Opt = nil
+		}
+	}
+}
+
+// Returns true if the node names a variable that is otherwise uninteresting to
+// the liveness computation.
+func isfunny(n *Node) bool {
+	return n.Sym != nil && (n.Sym.Name == ".fp" || n.Sym.Name == ".args")
+}
+
+// Computes the effects of an instruction on a set of
+// variables.  The vars argument is an array of Node*s.
+//
+// The output vectors give bits for variables:
+//	uevar - used by this instruction
+//	varkill - killed by this instruction
+//		for variables without address taken, means variable was set
+//		for variables with address taken, means variable was marked dead
+//	avarinit - initialized or referred to by this instruction,
+//		only for variables with address taken but not escaping to heap
+//
+// 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) {
+	bvresetall(uevar)
+	bvresetall(varkill)
+	bvresetall(avarinit)
+
+	if prog.As == obj.ARET {
+		// Return instructions implicitly read all the arguments.  For
+		// the sake of correctness, out arguments must be read.  For the
+		// sake of backtrace quality, we read in arguments as well.
+		//
+		// A return instruction with a p->to is a tail return, which brings
+		// the stack pointer back up (if it ever went down) and then jumps
+		// to a new function entirely. That form of instruction must read
+		// all the parameters for correctness, and similarly it must not
+		// read the out arguments - they won't be set until the new
+		// function runs.
+		for i, node := range vars {
+			switch node.Class &^ PHEAP {
+			case PPARAM:
+				bvset(uevar, int32(i))
+
+				// If the result had its address taken, it is being tracked
+			// by the avarinit code, which does not use uevar.
+			// If we added it to uevar too, we'd not see any kill
+			// and decide that the variable was live entry, which it is not.
+			// So only use uevar in the non-addrtaken case.
+			// The p->to.type == thearch.D_NONE limits the bvset to
+			// non-tail-call return instructions; see note above
+			// the for loop for details.
+			case PPARAMOUT:
+				if !node.Addrtaken && prog.To.Type == obj.TYPE_NONE {
+					bvset(uevar, int32(i))
+				}
+			}
+		}
+
+		return
+	}
+
+	if prog.As == obj.ATEXT {
+		// A text instruction marks the entry point to a function and
+		// the definition point of all in arguments.
+		for i, node := range vars {
+			switch node.Class &^ PHEAP {
+			case PPARAM:
+				if node.Addrtaken {
+					bvset(avarinit, int32(i))
+				}
+				bvset(varkill, int32(i))
+			}
+		}
+
+		return
+	}
+
+	if prog.Info.Flags&(LeftRead|LeftWrite|LeftAddr) != 0 {
+		from := &prog.From
+		if from.Node != nil && from.Sym != nil && ((from.Node).(*Node)).Name.Curfn == Curfn {
+			switch ((from.Node).(*Node)).Class &^ PHEAP {
+			case PAUTO, PPARAM, PPARAMOUT:
+				pos, ok := from.Node.(*Node).Opt().(int32) // index in vars
+				if !ok {
+					goto Next
+				}
+				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 {
+					bvset(avarinit, pos)
+				} else {
+					if prog.Info.Flags&(LeftRead|LeftAddr) != 0 {
+						bvset(uevar, pos)
+					}
+					if prog.Info.Flags&LeftWrite != 0 {
+						if from.Node != nil && !Isfat(((from.Node).(*Node)).Type) {
+							bvset(varkill, pos)
+						}
+					}
+				}
+			}
+		}
+	}
+
+Next:
+	if prog.Info.Flags&(RightRead|RightWrite|RightAddr) != 0 {
+		to := &prog.To
+		if to.Node != nil && to.Sym != nil && ((to.Node).(*Node)).Name.Curfn == Curfn {
+			switch ((to.Node).(*Node)).Class &^ PHEAP {
+			case PAUTO, PPARAM, PPARAMOUT:
+				pos, ok := to.Node.(*Node).Opt().(int32) // index in vars
+				if !ok {
+					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 {
+					if prog.As != obj.AVARKILL {
+						bvset(avarinit, pos)
+					}
+					if prog.As == obj.AVARDEF || prog.As == obj.AVARKILL {
+						bvset(varkill, pos)
+					}
+				} else {
+					// RightRead is a read, obviously.
+					// RightAddr by itself is also implicitly a read.
+					//
+					// RightAddr|RightWrite means that the address is being taken
+					// but only so that the instruction can write to the value.
+					// 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 (prog.Info.Flags&RightRead != 0) || prog.Info.Flags&(RightAddr|RightWrite) == RightAddr {
+						bvset(uevar, pos)
+					}
+					if prog.Info.Flags&RightWrite != 0 {
+						if to.Node != nil && (!Isfat(((to.Node).(*Node)).Type) || prog.As == obj.AVARDEF) {
+							bvset(varkill, pos)
+						}
+					}
+				}
+			}
+		}
+	}
+}
+
+// Constructs a new liveness structure used to hold the global state of the
+// liveness computation.  The cfg argument is an array of BasicBlock*s and the
+// vars argument is an array of Node*s.
+func newliveness(fn *Node, ptxt *obj.Prog, cfg []*BasicBlock, vars []*Node) *Liveness {
+	result := new(Liveness)
+	result.fn = fn
+	result.ptxt = ptxt
+	result.cfg = cfg
+	result.vars = vars
+
+	nblocks := int32(len(cfg))
+	nvars := int32(len(vars))
+	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)
+	return result
+}
+
+// Frees the liveness structure and all of its leaf data structures.
+func freeliveness(lv *Liveness) {
+	if lv == nil {
+		Fatal("freeliveness: cannot free nil")
+	}
+}
+
+func printeffects(p *obj.Prog, uevar Bvec, varkill Bvec, avarinit Bvec) {
+	fmt.Printf("effects of %v", p)
+	fmt.Printf("\nuevar: ")
+	bvprint(uevar)
+	fmt.Printf("\nvarkill: ")
+	bvprint(varkill)
+	fmt.Printf("\navarinit: ")
+	bvprint(avarinit)
+	fmt.Printf("\n")
+}
+
+// Pretty print a variable node.  Uses Pascal like conventions for pointers and
+// addresses to avoid confusing the C like conventions used in the node variable
+// names.
+func printnode(node *Node) {
+	p := ""
+	if haspointers(node.Type) {
+		p = "^"
+	}
+	a := ""
+	if node.Addrtaken {
+		a = "@"
+	}
+	fmt.Printf(" %v%s%s", node, 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) {
+	fmt.Printf("%s:", name)
+	for i, node := range vars {
+		if bvget(bv, int32(i)) != 0 {
+			printnode(node)
+		}
+	}
+	fmt.Printf("\n")
+}
+
+// Prints a basic block annotated with the information computed by liveness
+// analysis.
+func livenessprintblock(lv *Liveness, bb *BasicBlock) {
+	fmt.Printf("basic block %d\n", bb.rpo)
+
+	fmt.Printf("\tpred:")
+	for _, pred := range bb.pred {
+		fmt.Printf(" %d", pred.rpo)
+	}
+	fmt.Printf("\n")
+
+	fmt.Printf("\tsucc:")
+	for _, succ := range bb.succ {
+		fmt.Printf(" %d", succ.rpo)
+	}
+	fmt.Printf("\n")
+
+	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")
+	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]
+			fmt.Printf(" ")
+			bvprint(live)
+		}
+
+		fmt.Printf("\n")
+		if prog == bb.last {
+			break
+		}
+	}
+}
+
+// Prints a control flow graph annotated with any information computed by
+// liveness analysis.
+func livenessprintcfg(lv *Liveness) {
+	for _, bb := range lv.cfg {
+		livenessprintblock(lv, bb)
+	}
+}
+
+func checkauto(fn *Node, p *obj.Prog, n *Node) {
+	for l := fn.Func.Dcl; l != nil; l = l.Next {
+		if l.N.Op == ONAME && l.N.Class == PAUTO && l.N == n {
+			return
+		}
+	}
+
+	if n == nil {
+		fmt.Printf("%v: checkauto %v: nil node in %v\n", p.Line(), Curfn, p)
+		return
+	}
+
+	fmt.Printf("checkauto %v: %v (%p; class=%d) not found in %v\n", Curfn, n, n, n.Class, p)
+	for l := fn.Func.Dcl; l != nil; l = l.Next {
+		fmt.Printf("\t%v (%p; class=%d)\n", l.N, l.N, l.N.Class)
+	}
+	Yyerror("checkauto: invariant lost")
+}
+
+func checkparam(fn *Node, p *obj.Prog, n *Node) {
+	if isfunny(n) {
+		return
+	}
+	var a *Node
+	var class uint8
+	for l := fn.Func.Dcl; l != nil; l = l.Next {
+		a = l.N
+		class = a.Class &^ PHEAP
+		if a.Op == ONAME && (class == PPARAM || class == PPARAMOUT) && a == n {
+			return
+		}
+	}
+
+	fmt.Printf("checkparam %v: %v (%p; class=%d) not found in %v\n", Curfn, n, n, n.Class, p)
+	for l := fn.Func.Dcl; l != nil; l = l.Next {
+		fmt.Printf("\t%v (%p; class=%d)\n", l.N, l.N, l.N.Class)
+	}
+	Yyerror("checkparam: invariant lost")
+}
+
+func checkprog(fn *Node, p *obj.Prog) {
+	if p.From.Name == obj.NAME_AUTO {
+		checkauto(fn, p, p.From.Node.(*Node))
+	}
+	if p.From.Name == obj.NAME_PARAM {
+		checkparam(fn, p, p.From.Node.(*Node))
+	}
+	if p.To.Name == obj.NAME_AUTO {
+		checkauto(fn, p, p.To.Node.(*Node))
+	}
+	if p.To.Name == obj.NAME_PARAM {
+		checkparam(fn, p, p.To.Node.(*Node))
+	}
+}
+
+// Check instruction invariants.  We assume that the nodes corresponding to the
+// sources and destinations of memory operations will be declared in the
+// function.  This is not strictly true, as is the case for the so-called funny
+// nodes and there are special cases to skip over that stuff.  The analysis will
+// fail if this invariant blindly changes.
+func checkptxt(fn *Node, firstp *obj.Prog) {
+	if debuglive == 0 {
+		return
+	}
+
+	for p := firstp; p != nil; p = p.Link {
+		if false {
+			fmt.Printf("analyzing '%v'\n", p)
+		}
+		if p.As != obj.ADATA && p.As != obj.AGLOBL && p.As != obj.ATYPE {
+			checkprog(fn, p)
+		}
+	}
+}
+
+// NOTE: The bitmap for a specific type t should be cached in t after the first run
+// 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, onebitwalktype1
+// accounts for 40% of the 6g execution time.
+func onebitwalktype1(t *Type, xoffset *int64, bv Bvec) {
+	if t.Align > 0 && *xoffset&int64(t.Align-1) != 0 {
+		Fatal("onebitwalktype1: invalid initial alignment, %v", t)
+	}
+
+	switch t.Etype {
+	case TINT8,
+		TUINT8,
+		TINT16,
+		TUINT16,
+		TINT32,
+		TUINT32,
+		TINT64,
+		TUINT64,
+		TINT,
+		TUINT,
+		TUINTPTR,
+		TBOOL,
+		TFLOAT32,
+		TFLOAT64,
+		TCOMPLEX64,
+		TCOMPLEX128:
+		*xoffset += t.Width
+
+	case TPTR32,
+		TPTR64,
+		TUNSAFEPTR,
+		TFUNC,
+		TCHAN,
+		TMAP:
+		if *xoffset&int64(Widthptr-1) != 0 {
+			Fatal("onebitwalktype1: invalid alignment, %v", t)
+		}
+		bvset(bv, int32(*xoffset/int64(Widthptr))) // pointer
+		*xoffset += t.Width
+
+	case TSTRING:
+		// struct { byte *str; intgo len; }
+		if *xoffset&int64(Widthptr-1) != 0 {
+			Fatal("onebitwalktype1: invalid alignment, %v", t)
+		}
+		bvset(bv, int32(*xoffset/int64(Widthptr))) //pointer in first slot
+		*xoffset += t.Width
+
+	case TINTER:
+		// struct { Itab *tab;	void *data; }
+		// or, when isnilinter(t)==true:
+		// struct { Type *type; void *data; }
+		if *xoffset&int64(Widthptr-1) != 0 {
+			Fatal("onebitwalktype1: invalid alignment, %v", t)
+		}
+		bvset(bv, int32(*xoffset/int64(Widthptr)))   // pointer in first slot
+		bvset(bv, int32(*xoffset/int64(Widthptr)+1)) // pointer in second slot
+		*xoffset += t.Width
+
+	case TARRAY:
+		// The value of t->bound is -1 for slices types and >=0 for
+		// for fixed array types.  All other values are invalid.
+		if t.Bound < -1 {
+			Fatal("onebitwalktype1: invalid bound, %v", t)
+		}
+		if Isslice(t) {
+			// struct { byte *array; uintgo len; uintgo cap; }
+			if *xoffset&int64(Widthptr-1) != 0 {
+				Fatal("onebitwalktype1: invalid TARRAY alignment, %v", t)
+			}
+			bvset(bv, int32(*xoffset/int64(Widthptr))) // pointer in first slot (BitsPointer)
+			*xoffset += t.Width
+		} else {
+			for i := int64(0); i < t.Bound; i++ {
+				onebitwalktype1(t.Type, xoffset, bv)
+			}
+		}
+
+	case TSTRUCT:
+		o := int64(0)
+		var fieldoffset int64
+		for t1 := t.Type; t1 != nil; t1 = t1.Down {
+			fieldoffset = t1.Width
+			*xoffset += fieldoffset - o
+			onebitwalktype1(t1.Type, xoffset, bv)
+			o = fieldoffset + t1.Type.Width
+		}
+
+		*xoffset += t.Width - o
+
+	default:
+		Fatal("onebitwalktype1: unexpected type, %v", t)
+	}
+}
+
+// Returns the number of words of local variables.
+func localswords() int32 {
+	return int32(stkptrsize / int64(Widthptr))
+}
+
+// Returns the number of words of in and out arguments.
+func argswords() int32 {
+	return int32(Curfn.Type.Argwid / int64(Widthptr))
+}
+
+// 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 onebitlivepointermap(lv *Liveness, liveout Bvec, vars []*Node, args Bvec, locals Bvec) {
+	var node *Node
+	var xoffset int64
+
+	for i := int32(0); ; i++ {
+		i = int32(bvnext(liveout, i))
+		if i < 0 {
+			break
+		}
+		node = vars[i]
+		switch node.Class {
+		case PAUTO:
+			xoffset = node.Xoffset + stkptrsize
+			onebitwalktype1(node.Type, &xoffset, locals)
+
+		case PPARAM, PPARAMOUT:
+			xoffset = node.Xoffset
+			onebitwalktype1(node.Type, &xoffset, args)
+		}
+	}
+
+	// The node list only contains declared names.
+	// If the receiver or arguments are unnamed, they will be omitted
+	// from the list above. Preserve those values - even though they are unused -
+	// in order to keep their addresses live for use in stack traces.
+	thisargtype := getthisx(lv.fn.Type)
+
+	if thisargtype != nil {
+		xoffset = 0
+		onebitwalktype1(thisargtype, &xoffset, args)
+	}
+
+	inargtype := getinargx(lv.fn.Type)
+	if inargtype != nil {
+		xoffset = 0
+		onebitwalktype1(inargtype, &xoffset, args)
+	}
+}
+
+// Construct a disembodied instruction.
+func unlinkedprog(as int) *obj.Prog {
+	p := Ctxt.NewProg()
+	Clearp(p)
+	p.As = int16(as)
+	return p
+}
+
+// Construct a new PCDATA instruction associated with and for the purposes of
+// covering an existing instruction.
+func newpcdataprog(prog *obj.Prog, index int32) *obj.Prog {
+	var from Node
+	var to Node
+
+	Nodconst(&from, Types[TINT32], obj.PCDATA_StackMapIndex)
+	Nodconst(&to, Types[TINT32], int64(index))
+	pcdata := unlinkedprog(obj.APCDATA)
+	pcdata.Lineno = prog.Lineno
+	Naddr(&pcdata.From, &from)
+	Naddr(&pcdata.To, &to)
+	return pcdata
+}
+
+// Returns true for instructions that are safe points that must be annotated
+// with liveness information.
+func issafepoint(prog *obj.Prog) bool {
+	return prog.As == obj.ATEXT || prog.As == obj.ACALL
+}
+
+// Initializes the sets for solving the live variables.  Visits all the
+// instructions in each basic block to summarizes the information at each basic
+// block
+func livenessprologue(lv *Liveness) {
+	nvars := int32(len(lv.vars))
+	uevar := bvalloc(nvars)
+	varkill := bvalloc(nvars)
+	avarinit := bvalloc(nvars)
+	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) {
+			progeffects(p, []*Node(lv.vars), uevar, varkill, avarinit)
+			if debuglive >= 3 {
+				printeffects(p, uevar, varkill, avarinit)
+			}
+			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 {
+			progeffects(p, []*Node(lv.vars), uevar, varkill, avarinit)
+			if debuglive >= 3 {
+				printeffects(p, uevar, varkill, avarinit)
+			}
+			bvandnot(bb.avarinit, bb.avarinit, varkill)
+			bvor(bb.avarinit, bb.avarinit, avarinit)
+			if p == bb.last {
+				break
+			}
+		}
+	}
+}
+
+// Solve the liveness dataflow equations.
+func livenesssolve(lv *Liveness) {
+	// These temporary bitvectors exist to avoid successive allocations and
+	// frees within the loop.
+	newlivein := bvalloc(int32(len(lv.vars)))
+
+	newliveout := bvalloc(int32(len(lv.vars)))
+	any := bvalloc(int32(len(lv.vars)))
+	all := bvalloc(int32(len(lv.vars)))
+
+	// 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, bb := range lv.cfg {
+		if i == 0 {
+			bvcopy(bb.avarinitall, bb.avarinit)
+		} else {
+			bvresetall(bb.avarinitall)
+			bvnot(bb.avarinitall)
+		}
+		bvcopy(bb.avarinitany, bb.avarinit)
+	}
+
+	change := int32(1)
+	for change != 0 {
+		change = 0
+		for _, bb := range lv.cfg {
+			bvresetall(any)
+			bvresetall(all)
+			for j, pred := range bb.pred {
+				if j == 0 {
+					bvcopy(any, pred.avarinitany)
+					bvcopy(all, pred.avarinitall)
+				} else {
+					bvor(any, any, pred.avarinitany)
+					bvand(all, all, pred.avarinitall)
+				}
+			}
+
+			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(bb.avarinitany, any)
+			}
+
+			if bvcmp(all, bb.avarinitall) != 0 {
+				change = 1
+				bvcopy(bb.avarinitall, all)
+			}
+		}
+	}
+
+	// Iterate through the blocks in reverse round-robin fashion.  A work
+	// queue might be slightly faster.  As is, the number of iterations is
+	// so low that it hardly seems to be worth the complexity.
+	change = 1
+
+	for change != 0 {
+		change = 0
+
+		// Walk blocks in the general direction of propagation.  This
+		// improves convergence.
+		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]
+			bvresetall(newliveout)
+			for _, succ := range bb.succ {
+				bvor(newliveout, newliveout, succ.livein)
+			}
+
+			if bvcmp(bb.liveout, newliveout) != 0 {
+				change = 1
+				bvcopy(bb.liveout, newliveout)
+			}
+
+			// A variable is live on input to this block
+			// if it is live on output from this block and
+			// not set by the code in this block.
+			//
+			// in[b] = uevar[b] \cup (out[b] \setminus varkill[b])
+			bvandnot(newlivein, bb.liveout, bb.varkill)
+
+			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 {
+	switch n.Class {
+	case PPARAM, PPARAMOUT:
+		for i := 0; int64(i) < n.Type.Width/int64(Widthptr); i++ {
+			if bvget(args, int32(n.Xoffset/int64(Widthptr)+int64(i))) != 0 {
+				return true
+			}
+		}
+
+	case PAUTO:
+		for i := 0; int64(i) < n.Type.Width/int64(Widthptr); i++ {
+			if bvget(locals, int32((n.Xoffset+stkptrsize)/int64(Widthptr)+int64(i))) != 0 {
+				return true
+			}
+		}
+	}
+
+	return false
+}
+
+// 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 pred *BasicBlock
+	var args Bvec
+	var locals Bvec
+	var n *Node
+	var p *obj.Prog
+	var j int32
+	var pos int32
+	var xoffset int64
+
+	nvars := int32(len(lv.vars))
+	livein := bvalloc(nvars)
+	liveout := bvalloc(nvars)
+	uevar := bvalloc(nvars)
+	varkill := bvalloc(nvars)
+	avarinit := bvalloc(nvars)
+	any := bvalloc(nvars)
+	all := bvalloc(nvars)
+	ambig := bvalloc(localswords())
+	nmsg := int32(0)
+	startmsg := int32(0)
+
+	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.
+		bvresetall(any)
+
+		bvresetall(all)
+		for j = 0; j < int32(len(bb.pred)); j++ {
+			pred = bb.pred[j]
+			if j == 0 {
+				bvcopy(any, pred.avarinitany)
+				bvcopy(all, pred.avarinitall)
+			} else {
+				bvor(any, any, pred.avarinitany)
+				bvand(all, all, pred.avarinitall)
+			}
+		}
+
+		// Walk forward through the basic block instructions and
+		// allocate liveness maps for those instructions that need them.
+		// Seed the maps with information about the addrtaken variables.
+		for p = bb.first; ; p = p.Link {
+			progeffects(p, []*Node(lv.vars), uevar, varkill, avarinit)
+			bvandnot(any, any, varkill)
+			bvandnot(all, all, varkill)
+			bvor(any, any, avarinit)
+			bvor(all, all, avarinit)
+
+			if issafepoint(p) {
+				// Annotate ambiguously live variables so that they can
+				// be zeroed at function entry.
+				// livein and liveout are dead here and used as temporaries.
+				bvresetall(livein)
+
+				bvandnot(liveout, any, all)
+				if !bvisempty(liveout) {
+					for pos = 0; pos < liveout.n; pos++ {
+						if bvget(liveout, pos) == 0 {
+							continue
+						}
+						bvset(all, pos) // silence future warnings in this block
+						n = lv.vars[pos]
+						if !n.Name.Needzero {
+							n.Name.Needzero = true
+							if debuglive >= 1 {
+								Warnl(int(p.Lineno), "%v: %v is ambiguously live", Curfn.Func.Nname, Nconv(n, obj.FmtLong))
+							}
+
+							// Record in 'ambiguous' bitmap.
+							xoffset = n.Xoffset + stkptrsize
+
+							onebitwalktype1(n.Type, &xoffset, ambig)
+						}
+					}
+				}
+
+				// Allocate a bit vector for each class and facet of
+				// value we are tracking.
+
+				// Live stuff first.
+				args = bvalloc(argswords())
+
+				lv.argslivepointers = append(lv.argslivepointers, args)
+				locals = bvalloc(localswords())
+				lv.livepointers = append(lv.livepointers, locals)
+
+				if debuglive >= 3 {
+					fmt.Printf("%v\n", p)
+					printvars("avarinitany", any, lv.vars)
+				}
+
+				// Record any values with an "address taken" reaching
+				// this code position as live. Must do now instead of below
+				// because the any/all calculation requires walking forward
+				// over the block (as this loop does), while the liveout
+				// requires walking backward (as the next loop does).
+				onebitlivepointermap(lv, any, lv.vars, args, locals)
+			}
+
+			if p == bb.last {
+				break
+			}
+		}
+
+		bb.lastbitmapindex = len(lv.livepointers) - 1
+	}
+
+	var fmt_ string
+	var next *obj.Prog
+	var numlive int32
+	var msg []string
+	for _, bb := range lv.cfg {
+		if debuglive >= 1 && Curfn.Func.Nname.Sym.Name != "init" && Curfn.Func.Nname.Sym.Name[0] != '.' {
+			nmsg = int32(len(lv.livepointers))
+			startmsg = nmsg
+			msg = make([]string, nmsg)
+			for j = 0; j < nmsg; j++ {
+				msg[j] = ""
+			}
+		}
+
+		// walk backward, emit pcdata and populate the maps
+		pos = int32(bb.lastbitmapindex)
+
+		if pos < 0 {
+			// the first block we encounter should have the ATEXT so
+			// at no point should pos ever be less than zero.
+			Fatal("livenessepilogue")
+		}
+
+		bvcopy(livein, bb.liveout)
+		for p = bb.last; p != nil; p = next {
+			next = p.Opt.(*obj.Prog) // splicebefore modifies p->opt
+
+			// Propagate liveness information
+			progeffects(p, lv.vars, uevar, varkill, avarinit)
+
+			bvcopy(liveout, livein)
+			bvandnot(livein, liveout, varkill)
+			bvor(livein, livein, uevar)
+			if debuglive >= 3 && issafepoint(p) {
+				fmt.Printf("%v\n", p)
+				printvars("uevar", uevar, lv.vars)
+				printvars("varkill", varkill, lv.vars)
+				printvars("livein", livein, lv.vars)
+				printvars("liveout", liveout, lv.vars)
+			}
+
+			if issafepoint(p) {
+				// Found an interesting instruction, record the
+				// corresponding liveness information.
+
+				// Useful sanity check: on entry to the function,
+				// the only things that can possibly be live are the
+				// input parameters.
+				if p.As == obj.ATEXT {
+					for j = 0; j < liveout.n; j++ {
+						if bvget(liveout, j) == 0 {
+							continue
+						}
+						n = lv.vars[j]
+						if n.Class != PPARAM {
+							yyerrorl(int(p.Lineno), "internal error: %v %v recorded as live on entry", Curfn.Func.Nname, Nconv(n, obj.FmtLong))
+						}
+					}
+				}
+
+				// Record live pointers.
+				args = lv.argslivepointers[pos]
+
+				locals = lv.livepointers[pos]
+				onebitlivepointermap(lv, liveout, lv.vars, args, locals)
+
+				// Ambiguously live variables are zeroed immediately after
+				// function entry. Mark them live for all the non-entry bitmaps
+				// so that GODEBUG=gcdead=1 mode does not poison them.
+				if p.As == obj.ACALL {
+					bvor(locals, locals, ambig)
+				}
+
+				// Show live pointer bitmaps.
+				// We're interpreting the args and locals bitmap instead of liveout so that we
+				// include the bits added by the avarinit logic in the
+				// previous loop.
+				if msg != nil {
+					fmt_ = ""
+					fmt_ += fmt.Sprintf("%v: live at ", p.Line())
+					if p.As == obj.ACALL && p.To.Node != nil {
+						fmt_ += fmt.Sprintf("call to %s:", ((p.To.Node).(*Node)).Sym.Name)
+					} else if p.As == obj.ACALL {
+						fmt_ += "indirect call:"
+					} else {
+						fmt_ += fmt.Sprintf("entry to %s:", ((p.From.Node).(*Node)).Sym.Name)
+					}
+					numlive = 0
+					for j = 0; j < int32(len(lv.vars)); j++ {
+						n = lv.vars[j]
+						if islive(n, args, locals) {
+							fmt_ += fmt.Sprintf(" %v", n)
+							numlive++
+						}
+					}
+
+					fmt_ += "\n"
+					if numlive == 0 { // squelch message
+
+					} else {
+						startmsg--
+						msg[startmsg] = fmt_
+					}
+				}
+
+				// Only CALL instructions need a PCDATA annotation.
+				// The TEXT instruction annotation is implicit.
+				if p.As == obj.ACALL {
+					if isdeferreturn(p) {
+						// runtime.deferreturn modifies its return address to return
+						// back to the CALL, not to the subsequent instruction.
+						// Because the return comes back one instruction early,
+						// the PCDATA must begin one instruction early too.
+						// The instruction before a call to deferreturn is always a
+						// no-op, to keep PC-specific data unambiguous.
+						splicebefore(lv, bb, newpcdataprog(p.Opt.(*obj.Prog), pos), p.Opt.(*obj.Prog))
+					} else {
+						splicebefore(lv, bb, newpcdataprog(p, pos), p)
+					}
+				}
+
+				pos--
+			}
+		}
+
+		if msg != nil {
+			for j = startmsg; j < nmsg; j++ {
+				if msg[j] != "" {
+					fmt.Printf("%s", msg[j])
+				}
+			}
+
+			msg = nil
+			nmsg = 0
+			startmsg = 0
+		}
+	}
+
+	Flusherrors()
+}
+
+// FNV-1 hash function constants.
+const (
+	H0 = 2166136261
+	Hp = 16777619
+)
+
+func hashbitmap(h uint32, bv Bvec) uint32 {
+	var w uint32
+
+	n := int((bv.n + 31) / 32)
+	for i := 0; i < n; i++ {
+		w = bv.b[i]
+		h = (h * Hp) ^ (w & 0xff)
+		h = (h * Hp) ^ ((w >> 8) & 0xff)
+		h = (h * Hp) ^ ((w >> 16) & 0xff)
+		h = (h * Hp) ^ ((w >> 24) & 0xff)
+	}
+
+	return h
+}
+
+// Compact liveness information by coalescing identical per-call-site bitmaps.
+// The merging only happens for a single function, not across the entire binary.
+//
+// There are actually two lists of bitmaps, one list for the local variables and one
+// list for the function arguments. Both lists are indexed by the same PCDATA
+// index, so the corresponding pairs must be considered together when
+// merging duplicates. The argument bitmaps change much less often during
+// function execution than the local variable bitmaps, so it is possible that
+// we could introduce a separate PCDATA index for arguments vs locals and
+// then compact the set of argument bitmaps separately from the set of
+// local variable bitmaps. As of 2014-04-02, doing this to the godoc binary
+// is actually a net loss: we save about 50k of argument bitmaps but the new
+// PCDATA tables cost about 100k. So for now we keep using a single index for
+// both bitmap lists.
+func livenesscompact(lv *Liveness) {
+	// Linear probing hash table of bitmaps seen so far.
+	// The hash table has 4n entries to keep the linear
+	// scan short. An entry of -1 indicates an empty slot.
+	n := len(lv.livepointers)
+
+	tablesize := 4 * n
+	table := make([]int, tablesize)
+	for i := range table {
+		table[i] = -1
+	}
+
+	// remap[i] = the new index of the old bit vector #i.
+	remap := make([]int, n)
+
+	for i := range remap {
+		remap[i] = -1
+	}
+	uniq := 0 // unique tables found so far
+
+	// Consider bit vectors in turn.
+	// If new, assign next number using uniq,
+	// 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 j int
+	var h uint32
+	var arg Bvec
+	var jlocal Bvec
+	var local Bvec
+	for i := 0; i < n; i++ {
+		local = lv.livepointers[i]
+		arg = lv.argslivepointers[i]
+		h = hashbitmap(hashbitmap(H0, local), arg) % uint32(tablesize)
+
+		for {
+			j = table[h]
+			if j < 0 {
+				break
+			}
+			jlocal = lv.livepointers[j]
+			jarg = lv.argslivepointers[j]
+			if bvcmp(local, jlocal) == 0 && bvcmp(arg, jarg) == 0 {
+				remap[i] = j
+				goto Next
+			}
+
+			h++
+			if h == uint32(tablesize) {
+				h = 0
+			}
+		}
+
+		table[h] = uniq
+		remap[i] = uniq
+		lv.livepointers[uniq] = local
+		lv.argslivepointers[uniq] = arg
+		uniq++
+	Next:
+	}
+
+	// We've already reordered lv->livepointers[0:uniq]
+	// and lv->argslivepointers[0:uniq] and freed the bitmaps
+	// we don't need anymore. Clear the pointers later in the
+	// 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] = Bvec{}
+		lv.argslivepointers[j] = Bvec{}
+	}
+
+	// Rewrite PCDATA instructions to use new numbering.
+	var i int
+	for p := lv.ptxt; p != nil; p = p.Link {
+		if p.As == obj.APCDATA && p.From.Offset == obj.PCDATA_StackMapIndex {
+			i = int(p.To.Offset)
+			if i >= 0 {
+				p.To.Offset = int64(remap[i])
+			}
+		}
+	}
+}
+
+func printbitset(printed int, name string, vars []*Node, bits Bvec) int {
+	started := 0
+	for i, n := range vars {
+		if bvget(bits, int32(i)) == 0 {
+			continue
+		}
+		if started == 0 {
+			if printed == 0 {
+				fmt.Printf("\t")
+			} else {
+				fmt.Printf(" ")
+			}
+			started = 1
+			printed = 1
+			fmt.Printf("%s=", name)
+		} else {
+			fmt.Printf(",")
+		}
+
+		fmt.Printf("%s", n.Sym.Name)
+	}
+
+	return printed
+}
+
+// Prints the computed liveness information and inputs, for debugging.
+// This format synthesizes the information used during the multiple passes
+// into a single presentation.
+func livenessprintdebug(lv *Liveness) {
+	var j int
+	var printed int
+	var p *obj.Prog
+	var args Bvec
+	var locals Bvec
+	var n *Node
+
+	fmt.Printf("liveness: %s\n", Curfn.Func.Nname.Sym.Name)
+
+	uevar := bvalloc(int32(len(lv.vars)))
+	varkill := bvalloc(int32(len(lv.vars)))
+	avarinit := bvalloc(int32(len(lv.vars)))
+
+	pcdata := 0
+	for i, bb := range lv.cfg {
+		if i > 0 {
+			fmt.Printf("\n")
+		}
+
+		// bb#0 pred=1,2 succ=3,4
+		fmt.Printf("bb#%d pred=", i)
+
+		for j = 0; j < len(bb.pred); j++ {
+			if j > 0 {
+				fmt.Printf(",")
+			}
+			fmt.Printf("%d", (bb.pred[j]).rpo)
+		}
+
+		fmt.Printf(" succ=")
+		for j = 0; j < len(bb.succ); j++ {
+			if j > 0 {
+				fmt.Printf(",")
+			}
+			fmt.Printf("%d", (bb.succ[j]).rpo)
+		}
+
+		fmt.Printf("\n")
+
+		// initial settings
+		printed = 0
+
+		printed = printbitset(printed, "uevar", lv.vars, bb.uevar)
+		printed = printbitset(printed, "livein", lv.vars, bb.livein)
+		if printed != 0 {
+			fmt.Printf("\n")
+		}
+
+		// program listing, with individual effects listed
+		for p = bb.first; ; p = p.Link {
+			fmt.Printf("%v\n", p)
+			if p.As == obj.APCDATA && p.From.Offset == obj.PCDATA_StackMapIndex {
+				pcdata = int(p.To.Offset)
+			}
+			progeffects(p, lv.vars, uevar, varkill, avarinit)
+			printed = 0
+			printed = printbitset(printed, "uevar", lv.vars, uevar)
+			printed = printbitset(printed, "varkill", lv.vars, varkill)
+			printed = printbitset(printed, "avarinit", lv.vars, avarinit)
+			if printed != 0 {
+				fmt.Printf("\n")
+			}
+			if issafepoint(p) {
+				args = lv.argslivepointers[pcdata]
+				locals = lv.livepointers[pcdata]
+				fmt.Printf("\tlive=")
+				printed = 0
+				for j = 0; j < len(lv.vars); j++ {
+					n = lv.vars[j]
+					if islive(n, args, locals) {
+						tmp9 := printed
+						printed++
+						if tmp9 != 0 {
+							fmt.Printf(",")
+						}
+						fmt.Printf("%v", n)
+					}
+				}
+
+				fmt.Printf("\n")
+			}
+
+			if p == bb.last {
+				break
+			}
+		}
+
+		// bb bitsets
+		fmt.Printf("end\n")
+
+		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")
+		}
+	}
+
+	fmt.Printf("\n")
+}
+
+// Dumps an array of bitmaps to a symbol as a sequence of uint32 values.  The
+// first word dumped is the total number of bitmaps.  The second word is the
+// 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 onebitwritesymbol(arr []Bvec, sym *Sym) {
+	var i int
+	var j int
+	var word uint32
+
+	n := len(arr)
+	off := 0
+	off += 4 // number of bitmaps, to fill in later
+	bv := arr[0]
+	off = duint32(sym, off, uint32(bv.n)) // number of bits in each bitmap
+	for i = 0; i < n; i++ {
+		// bitmap words
+		bv = arr[i]
+
+		if bv.b == nil {
+			break
+		}
+		for j = 0; int32(j) < bv.n; j += 32 {
+			word = bv.b[j/32]
+
+			// Runtime reads the bitmaps as byte arrays. Oblige.
+			off = duint8(sym, off, uint8(word))
+
+			off = duint8(sym, off, uint8(word>>8))
+			off = duint8(sym, off, uint8(word>>16))
+			off = duint8(sym, off, uint8(word>>24))
+		}
+	}
+
+	duint32(sym, 0, uint32(i)) // number of bitmaps
+	ggloblsym(sym, int32(off), obj.RODATA)
+}
+
+func printprog(p *obj.Prog) {
+	for p != nil {
+		fmt.Printf("%v\n", p)
+		p = p.Link
+	}
+}
+
+// Entry pointer for liveness analysis.  Constructs a complete CFG, solves for
+// the liveness of pointer variables in the function, and emits a runtime data
+// structure read by the garbage collector.
+func liveness(fn *Node, firstp *obj.Prog, argssym *Sym, livesym *Sym) {
+	// Change name to dump debugging information only for a specific function.
+	debugdelta := 0
+
+	if Curfn.Func.Nname.Sym.Name == "!" {
+		debugdelta = 2
+	}
+
+	debuglive += debugdelta
+	if debuglive >= 3 {
+		fmt.Printf("liveness: %s\n", Curfn.Func.Nname.Sym.Name)
+		printprog(firstp)
+	}
+
+	checkptxt(fn, firstp)
+
+	// Construct the global liveness state.
+	cfg := newcfg(firstp)
+
+	if debuglive >= 3 {
+		printcfg([]*BasicBlock(cfg))
+	}
+	vars := getvariables(fn)
+	lv := newliveness(fn, firstp, cfg, vars)
+
+	// Run the dataflow framework.
+	livenessprologue(lv)
+
+	if debuglive >= 3 {
+		livenessprintcfg(lv)
+	}
+	livenesssolve(lv)
+	if debuglive >= 3 {
+		livenessprintcfg(lv)
+	}
+	livenessepilogue(lv)
+	if debuglive >= 3 {
+		livenessprintcfg(lv)
+	}
+	livenesscompact(lv)
+
+	if debuglive >= 2 {
+		livenessprintdebug(lv)
+	}
+
+	// Emit the live pointer map data structures
+	onebitwritesymbol(lv.livepointers, livesym)
+
+	onebitwritesymbol(lv.argslivepointers, argssym)
+
+	// Free everything.
+	for l := fn.Func.Dcl; l != nil; l = l.Next {
+		if l.N != nil {
+			l.N.SetOpt(nil)
+		}
+	}
+	freeliveness(lv)
+
+	freecfg([]*BasicBlock(cfg))
+
+	debuglive -= debugdelta
+}
diff --git a/src/cmd/compile/internal/gc/popt.go b/src/cmd/compile/internal/gc/popt.go
new file mode 100644
index 0000000..4fc562c
--- /dev/null
+++ b/src/cmd/compile/internal/gc/popt.go
@@ -0,0 +1,1086 @@
+// Derived from Inferno utils/6c/gc.h
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/gc.h
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
+
+// "Portable" optimizations.
+
+package gc
+
+import (
+	"cmd/internal/obj"
+	"fmt"
+	"sort"
+	"strings"
+)
+
+type OptStats struct {
+	Ncvtreg int32
+	Nspill  int32
+	Nreload int32
+	Ndelmov int32
+	Nvar    int32
+	Naddr   int32
+}
+
+var Ostats OptStats
+
+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)
+		noreturn_symlist[1] = Pkglookup("panicslice", Runtimepkg)
+		noreturn_symlist[2] = Pkglookup("throwinit", Runtimepkg)
+		noreturn_symlist[3] = Pkglookup("gopanic", Runtimepkg)
+		noreturn_symlist[4] = Pkglookup("panicwrap", Runtimepkg)
+		noreturn_symlist[5] = Pkglookup("throwreturn", Runtimepkg)
+		noreturn_symlist[6] = Pkglookup("selectgo", Runtimepkg)
+		noreturn_symlist[7] = Pkglookup("block", Runtimepkg)
+	}
+
+	if p.To.Node == nil {
+		return false
+	}
+	s := ((p.To.Node).(*Node)).Sym
+	if s == nil {
+		return false
+	}
+	for i := 0; noreturn_symlist[i] != nil; i++ {
+		if s == noreturn_symlist[i] {
+			return true
+		}
+	}
+	return false
+}
+
+// JMP chasing and removal.
+//
+// The code generator depends on being able to write out jump
+// instructions that it can jump to now but fill in later.
+// the linker will resolve them nicely, but they make the code
+// longer and more difficult to follow during debugging.
+// Remove them.
+
+/* what instruction does a JMP to p eventually land on? */
+func chasejmp(p *obj.Prog, jmploop *int) *obj.Prog {
+	n := 0
+	for p != nil && p.As == obj.AJMP && p.To.Type == obj.TYPE_BRANCH {
+		n++
+		if n > 10 {
+			*jmploop = 1
+			break
+		}
+
+		p = p.To.Val.(*obj.Prog)
+	}
+
+	return p
+}
+
+/*
+ * reuse reg pointer for mark/sweep state.
+ * leave reg==nil at end because alive==nil.
+ */
+var alive interface{} = nil
+var dead interface{} = 1
+
+/* mark all code reachable from firstp as alive */
+func mark(firstp *obj.Prog) {
+	for p := firstp; p != nil; p = p.Link {
+		if p.Opt != dead {
+			break
+		}
+		p.Opt = alive
+		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
+		}
+	}
+}
+
+func fixjmp(firstp *obj.Prog) {
+	if Debug['R'] != 0 && Debug['v'] != 0 {
+		fmt.Printf("\nfixjmp\n")
+	}
+
+	// pass 1: resolve jump to jump, mark all code as dead.
+	jmploop := 0
+
+	for p := firstp; p != nil; p = p.Link {
+		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.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)
+			}
+		}
+
+		p.Opt = dead
+	}
+
+	if Debug['R'] != 0 && Debug['v'] != 0 {
+		fmt.Printf("\n")
+	}
+
+	// pass 2: mark all reachable code alive
+	mark(firstp)
+
+	// pass 3: delete dead code (mostly JMPs).
+	var last *obj.Prog
+
+	for p := firstp; p != nil; p = p.Link {
+		if p.Opt == dead {
+			if p.Link == nil && p.As == obj.ARET && last != nil && last.As != obj.ARET {
+				// This is the final ARET, and the code so far doesn't have one.
+				// Let it stay. The register allocator assumes that all live code in
+				// the function can be traversed by starting at all the RET instructions
+				// and following predecessor links. If we remove the final RET,
+				// this assumption will not hold in the case of an infinite loop
+				// at the end of a function.
+				// Keep the RET but mark it dead for the liveness analysis.
+				p.Mode = 1
+			} else {
+				if Debug['R'] != 0 && Debug['v'] != 0 {
+					fmt.Printf("del %v\n", p)
+				}
+				continue
+			}
+		}
+
+		if last != nil {
+			last.Link = p
+		}
+		last = p
+	}
+
+	last.Link = nil
+
+	// pass 4: elide JMP to next instruction.
+	// only safe if there are no jumps to JMPs anymore.
+	if jmploop == 0 {
+		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.Val == p.Link {
+				if Debug['R'] != 0 && Debug['v'] != 0 {
+					fmt.Printf("del %v\n", p)
+				}
+				continue
+			}
+
+			if last != nil {
+				last.Link = p
+			}
+			last = p
+		}
+
+		last.Link = nil
+	}
+
+	if Debug['R'] != 0 && Debug['v'] != 0 {
+		fmt.Printf("\n")
+		for p := firstp; p != nil; p = p.Link {
+			fmt.Printf("%v\n", p)
+		}
+		fmt.Printf("\n")
+	}
+}
+
+// Control flow analysis. The Flow structures hold predecessor and successor
+// information as well as basic loop analysis.
+//
+//	graph = flowstart(firstp, 0);
+//	... use flow graph ...
+//	flowend(graph); // free graph
+//
+// Typical uses of the flow graph are to iterate over all the flow-relevant instructions:
+//
+//	for(f = graph->start; f != nil; f = f->link)
+//
+// or, given an instruction f, to iterate over all the predecessors, which is
+// f->p1 and this list:
+//
+//	for(f2 = f->p2; f2 != nil; f2 = f2->p2link)
+//
+// The size argument to flowstart specifies an amount of zeroed memory
+// to allocate in every f->data field, for use by the client.
+// If size == 0, f->data will be nil.
+
+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(p)
+		if p.Info.Flags&Skip != 0 {
+			continue
+		}
+		p.Opt = &flowmark
+		nf++
+	}
+
+	if nf == 0 {
+		return nil
+	}
+
+	if nf >= MaxFlowProg {
+		if Debug['v'] != 0 {
+			Warn("%v is too big (%d instructions)", Curfn.Func.Nname.Sym, nf)
+		}
+		return nil
+	}
+
+	// Allocate annotations and assign to instructions.
+	graph := new(Graph)
+	ff := make([]Flow, nf)
+	start := &ff[0]
+	id := 0
+	var last *Flow
+	for p := firstp; p != nil; p = p.Link {
+		if p.Opt == nil {
+			continue
+		}
+		f := &ff[0]
+		ff = ff[1:]
+		p.Opt = f
+		f.Prog = p
+		if last != nil {
+			last.Link = f
+		}
+		last = f
+		if newData != nil {
+			f.Data = newData()
+		}
+		f.Id = int32(id)
+		id++
+	}
+
+	// Fill in pred/succ information.
+	var f1 *Flow
+	var p *obj.Prog
+	for f := start; f != nil; f = f.Link {
+		p = f.Prog
+		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.Val == nil {
+				Fatal("pnil %v", p)
+			}
+			f1 = p.To.Val.(*obj.Prog).Opt.(*Flow)
+			if f1 == nil {
+				Fatal("fnil %v / %v", p, p.To.Val.(*obj.Prog))
+			}
+			if f1 == f {
+				//fatal("self loop %v", p);
+				continue
+			}
+
+			f.S2 = f1
+			f.P2link = f1.P2
+			f1.P2 = f
+		}
+	}
+
+	graph.Start = start
+	graph.Num = nf
+	return graph
+}
+
+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
+	}
+}
+
+/*
+ * find looping structure
+ *
+ * 1) find reverse postordering
+ * 2) find approximate dominators,
+ *	the actual dominators if the flow graph is reducible
+ *	otherwise, dominators plus some other non-dominators.
+ *	See Matthew S. Hecht and Jeffrey D. Ullman,
+ *	"Analysis of a Simple Algorithm for Global Data Flow Problems",
+ *	Conf.  Record of ACM Symp. on Principles of Prog. Langs, Boston, Massachusetts,
+ *	Oct. 1-3, 1973, pp.  207-217.
+ * 3) find all nodes with a predecessor dominated by the current node.
+ *	such a node is a loop head.
+ *	recursively, all preds with a greater rpo number are in the loop
+ */
+func postorder(r *Flow, rpo2r []*Flow, n int32) int32 {
+	r.Rpo = 1
+	r1 := r.S1
+	if r1 != nil && r1.Rpo == 0 {
+		n = postorder(r1, rpo2r, n)
+	}
+	r1 = r.S2
+	if r1 != nil && r1.Rpo == 0 {
+		n = postorder(r1, rpo2r, n)
+	}
+	rpo2r[n] = r
+	n++
+	return n
+}
+
+func rpolca(idom []int32, rpo1 int32, rpo2 int32) int32 {
+	if rpo1 == -1 {
+		return rpo2
+	}
+	var t int32
+	for rpo1 != rpo2 {
+		if rpo1 > rpo2 {
+			t = rpo2
+			rpo2 = rpo1
+			rpo1 = t
+		}
+
+		for rpo1 < rpo2 {
+			t = idom[rpo2]
+			if t >= rpo2 {
+				Fatal("bad idom")
+			}
+			rpo2 = t
+		}
+	}
+
+	return rpo1
+}
+
+func doms(idom []int32, r int32, s int32) bool {
+	for s > r {
+		s = idom[s]
+	}
+	return s == r
+}
+
+func loophead(idom []int32, r *Flow) bool {
+	src := r.Rpo
+	if r.P1 != nil && doms(idom, src, r.P1.Rpo) {
+		return true
+	}
+	for r = r.P2; r != nil; r = r.P2link {
+		if doms(idom, src, r.Rpo) {
+			return true
+		}
+	}
+	return false
+}
+
+func loopmark(rpo2r **Flow, head int32, r *Flow) {
+	if r.Rpo < head || r.Active == head {
+		return
+	}
+	r.Active = head
+	r.Loop += LOOP
+	if r.P1 != nil {
+		loopmark(rpo2r, head, r.P1)
+	}
+	for r = r.P2; r != nil; r = r.P2link {
+		loopmark(rpo2r, head, r)
+	}
+}
+
+func flowrpo(g *Graph) {
+	g.Rpo = make([]*Flow, g.Num)
+	idom := make([]int32, g.Num)
+
+	for r1 := g.Start; r1 != nil; r1 = r1.Link {
+		r1.Active = 0
+	}
+
+	rpo2r := g.Rpo
+	d := postorder(g.Start, rpo2r, 0)
+	nr := int32(g.Num)
+	if d > nr {
+		Fatal("too many reg nodes %d %d", d, nr)
+	}
+	nr = d
+	var r1 *Flow
+	for i := int32(0); i < nr/2; i++ {
+		r1 = rpo2r[i]
+		rpo2r[i] = rpo2r[nr-1-i]
+		rpo2r[nr-1-i] = r1
+	}
+
+	for i := int32(0); i < nr; i++ {
+		rpo2r[i].Rpo = i
+	}
+
+	idom[0] = 0
+	var me int32
+	for i := int32(0); i < nr; i++ {
+		r1 = rpo2r[i]
+		me = r1.Rpo
+		d = -1
+
+		// rpo2r[r->rpo] == r protects against considering dead code,
+		// which has r->rpo == 0.
+		if r1.P1 != nil && rpo2r[r1.P1.Rpo] == r1.P1 && r1.P1.Rpo < me {
+			d = r1.P1.Rpo
+		}
+		for r1 = r1.P2; r1 != nil; r1 = r1.P2link {
+			if rpo2r[r1.Rpo] == r1 && r1.Rpo < me {
+				d = rpolca(idom, d, r1.Rpo)
+			}
+		}
+		idom[i] = d
+	}
+
+	for i := int32(0); i < nr; i++ {
+		r1 = rpo2r[i]
+		r1.Loop++
+		if r1.P2 != nil && loophead(idom, r1) {
+			loopmark(&rpo2r[0], i, r1)
+		}
+	}
+
+	for r1 := g.Start; r1 != nil; r1 = r1.Link {
+		r1.Active = 0
+	}
+}
+
+func Uniqp(r *Flow) *Flow {
+	r1 := r.P1
+	if r1 == nil {
+		r1 = r.P2
+		if r1 == nil || r1.P2link != nil {
+			return nil
+		}
+	} else if r.P2 != nil {
+		return nil
+	}
+	return r1
+}
+
+func Uniqs(r *Flow) *Flow {
+	r1 := r.S1
+	if r1 == nil {
+		r1 = r.S2
+		if r1 == nil {
+			return nil
+		}
+	} else if r.S2 != nil {
+		return nil
+	}
+	return r1
+}
+
+// The compilers assume they can generate temporary variables
+// as needed to preserve the right semantics or simplify code
+// generation and the back end will still generate good code.
+// This results in a large number of ephemeral temporary variables.
+// Merge temps with non-overlapping lifetimes and equal types using the
+// greedy algorithm in Poletto and Sarkar, "Linear Scan Register Allocation",
+// ACM TOPLAS 1999.
+
+type TempVar struct {
+	node    *Node
+	def     *Flow    // definition of temp var
+	use     *Flow    // use list, chained through Flow.data
+	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
+
+func (x startcmp) Len() int {
+	return len(x)
+}
+
+func (x startcmp) Swap(i, j int) {
+	x[i], x[j] = x[j], x[i]
+}
+
+func (x startcmp) Less(i, j int) bool {
+	a := x[i]
+	b := x[j]
+
+	if a.start < b.start {
+		return true
+	}
+	if a.start > b.start {
+		return false
+	}
+
+	// Order what's left by id or symbol name,
+	// just so that sort is forced into a specific ordering,
+	// so that the result of the sort does not depend on
+	// the sort implementation.
+	if a.def != b.def {
+		return int(a.def.Id-b.def.Id) < 0
+	}
+	if a.node != b.node {
+		return stringsCompare(a.node.Sym.Name, b.node.Sym.Name) < 0
+	}
+	return false
+}
+
+// Is n available for merging?
+func canmerge(n *Node) bool {
+	return n.Class == PAUTO && strings.HasPrefix(n.Sym.Name, "autotmp")
+}
+
+func mergetemp(firstp *obj.Prog) {
+	const (
+		debugmerge = 0
+	)
+
+	g := Flowstart(firstp, nil)
+	if g == nil {
+		return
+	}
+
+	// Build list of all mergeable variables.
+	nvar := 0
+	for l := Curfn.Func.Dcl; l != nil; l = l.Next {
+		if canmerge(l.N) {
+			nvar++
+		}
+	}
+
+	var_ := make([]TempVar, nvar)
+	nvar = 0
+	var n *Node
+	var v *TempVar
+	for l := Curfn.Func.Dcl; l != nil; l = l.Next {
+		n = l.N
+		if canmerge(n) {
+			v = &var_[nvar]
+			nvar++
+			n.SetOpt(v)
+			v.node = n
+		}
+	}
+
+	// Build list of uses.
+	// 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!).
+	for f := g.Start; f != nil; f = f.Link {
+		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)
+		}
+		v = nil
+		n, _ = p.From.Node.(*Node)
+		if n != nil {
+			v, _ = n.Opt().(*TempVar)
+		}
+		if v == nil {
+			n, _ = p.To.Node.(*Node)
+			if n != nil {
+				v, _ = n.Opt().(*TempVar)
+			}
+		}
+		if v != nil {
+			if v.def == nil {
+				v.def = f
+			}
+			f.Data = v.use
+			v.use = f
+			if n == p.From.Node && (p.Info.Flags&LeftAddr != 0) {
+				v.addr = 1
+			}
+		}
+	}
+
+	if debugmerge > 1 && Debug['v'] != 0 {
+		Dumpit("before", g.Start, 0)
+	}
+
+	nkill := 0
+
+	// Special case.
+	for i := 0; i < len(var_); i++ {
+		v = &var_[i]
+		if v.addr != 0 {
+			continue
+		}
+
+		// Used in only one instruction, which had better be a write.
+		f := v.use
+		if f != nil && f.Data.(*Flow) == nil {
+			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
+				if debugmerge > 0 && Debug['v'] != 0 {
+					fmt.Printf("drop write-only %v\n", v.node.Sym)
+				}
+			} else {
+				Fatal("temp used and not set: %v", p)
+			}
+			nkill++
+			continue
+		}
+
+		// Written in one instruction, read in the next, otherwise unused,
+		// 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
+			p1 := f.Link.Prog
+			const (
+				SizeAny = SizeB | SizeW | SizeL | SizeQ | SizeF | SizeD
+			)
+			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
+				if debugmerge > 0 && Debug['v'] != 0 {
+					fmt.Printf("drop immediate-use %v\n", v.node.Sym)
+				}
+			}
+
+			nkill++
+			continue
+		}
+	}
+
+	// Traverse live range of each variable to set start, end.
+	// Each flood uses a new value of gen so that we don't have
+	// to clear all the r->active words after each variable.
+	gen := int32(0)
+
+	for i := 0; i < len(var_); i++ {
+		v = &var_[i]
+		gen++
+		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) {
+				varkillwalk(v, f, uint32(gen))
+			}
+		}
+	}
+
+	// Sort variables by start.
+	bystart := make([]*TempVar, len(var_))
+
+	for i := 0; i < len(var_); i++ {
+		bystart[i] = &var_[i]
+	}
+	sort.Sort(startcmp(bystart[:len(var_)]))
+
+	// List of in-use variables, sorted by end, so that the ones that
+	// will last the longest are the earliest ones in the array.
+	// The tail inuse[nfree:] holds no-longer-used variables.
+	// In theory we should use a sorted tree so that insertions are
+	// guaranteed O(log n) and then the loop is guaranteed O(n log n).
+	// In practice, it doesn't really matter.
+	inuse := make([]*TempVar, len(var_))
+
+	ninuse := 0
+	nfree := len(var_)
+	var t *Type
+	var v1 *TempVar
+	var j int
+	for i := 0; i < len(var_); i++ {
+		v = bystart[i]
+		if debugmerge > 0 && Debug['v'] != 0 {
+			fmt.Printf("consider %v: removed=%d\n", Nconv(v.node, obj.FmtSharp), v.removed)
+		}
+
+		if v.removed != 0 {
+			continue
+		}
+
+		// Expire no longer in use.
+		for ninuse > 0 && inuse[ninuse-1].end < v.start {
+			ninuse--
+			v1 = inuse[ninuse]
+			nfree--
+			inuse[nfree] = v1
+		}
+
+		if debugmerge > 0 && Debug['v'] != 0 {
+			fmt.Printf("consider %v: removed=%d nfree=%d nvar=%d\n", Nconv(v.node, obj.FmtSharp), v.removed, nfree, len(var_))
+		}
+
+		// Find old temp to reuse if possible.
+		t = v.node.Type
+
+		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=%v,%v\n", Nconv(v.node, obj.FmtSharp), Nconv(v1.node, obj.FmtSharp), t, v1.node.Type, v.node.Addrtaken, v1.node.Addrtaken)
+			}
+
+			// Require the types to match but also require the addrtaken bits to match.
+			// If a variable's address is taken, that disables registerization for the individual
+			// words of the variable (for example, the base,len,cap of a slice).
+			// We don't want to merge a non-addressed var with an addressed one and
+			// inhibit registerization of the former.
+			if Eqtype(t, v1.node.Type) && v.node.Addrtaken == v1.node.Addrtaken {
+				inuse[j] = inuse[nfree]
+				nfree++
+				if v1.merge != nil {
+					v.merge = v1.merge
+				} else {
+					v.merge = v1
+				}
+				nkill++
+				break
+			}
+		}
+
+		// Sort v into inuse.
+		j = ninuse
+		ninuse++
+
+		for j > 0 && inuse[j-1].end < v.end {
+			inuse[j] = inuse[j-1]
+			j--
+		}
+
+		inuse[j] = v
+	}
+
+	if debugmerge > 0 && Debug['v'] != 0 {
+		fmt.Printf("%v [%d - %d]\n", Curfn.Func.Nname.Sym, len(var_), nkill)
+		var v *TempVar
+		for i := 0; i < len(var_); i++ {
+			v = &var_[i]
+			fmt.Printf("var %v %v %d-%d", Nconv(v.node, obj.FmtSharp), v.node.Type, v.start, v.end)
+			if v.addr != 0 {
+				fmt.Printf(" addr=1")
+			}
+			if v.removed != 0 {
+				fmt.Printf(" dead=1")
+			}
+			if v.merge != nil {
+				fmt.Printf(" merge %v", Nconv(v.merge.node, obj.FmtSharp))
+			}
+			if v.start == v.end && v.def != nil {
+				fmt.Printf(" %v", v.def.Prog)
+			}
+			fmt.Printf("\n")
+		}
+
+		if debugmerge > 1 && Debug['v'] != 0 {
+			Dumpit("after", g.Start, 0)
+		}
+	}
+
+	// Update node references to use merged temporaries.
+	for f := g.Start; f != nil; f = f.Link {
+		p := f.Prog
+		n, _ = p.From.Node.(*Node)
+		if n != nil {
+			v, _ = n.Opt().(*TempVar)
+			if v != nil && v.merge != nil {
+				p.From.Node = v.merge.node
+			}
+		}
+		n, _ = p.To.Node.(*Node)
+		if n != nil {
+			v, _ = n.Opt().(*TempVar)
+			if v != nil && v.merge != nil {
+				p.To.Node = v.merge.node
+			}
+		}
+	}
+
+	// Delete merged nodes from declaration list.
+	var l *NodeList
+	for lp := &Curfn.Func.Dcl; ; {
+		l = *lp
+		if l == nil {
+			break
+		}
+
+		Curfn.Func.Dcl.End = l
+		n = l.N
+		v, _ = n.Opt().(*TempVar)
+		if v != nil && (v.merge != nil || v.removed != 0) {
+			*lp = l.Next
+			continue
+		}
+
+		lp = &l.Next
+	}
+
+	// Clear aux structures.
+	for i := 0; i < len(var_); i++ {
+		var_[i].node.SetOpt(nil)
+	}
+
+	Flowend(g)
+}
+
+func mergewalk(v *TempVar, f0 *Flow, gen uint32) {
+	var p *obj.Prog
+	var f1 *Flow
+
+	for f1 = f0; f1 != nil; f1 = f1.P1 {
+		if uint32(f1.Active) == gen {
+			break
+		}
+		f1.Active = int32(gen)
+		p = f1.Prog
+		if v.end < p.Pc {
+			v.end = p.Pc
+		}
+		if f1 == v.def {
+			v.start = p.Pc
+			break
+		}
+	}
+
+	var f2 *Flow
+	for f := f0; f != f1; f = f.P1 {
+		for f2 = f.P2; f2 != nil; f2 = f2.P2link {
+			mergewalk(v, f2, gen)
+		}
+	}
+}
+
+func varkillwalk(v *TempVar, f0 *Flow, gen uint32) {
+	var p *obj.Prog
+	var f1 *Flow
+
+	for f1 = f0; f1 != nil; f1 = f1.S1 {
+		if uint32(f1.Active) == gen {
+			break
+		}
+		f1.Active = int32(gen)
+		p = f1.Prog
+		if v.end < p.Pc {
+			v.end = p.Pc
+		}
+		if v.start > p.Pc {
+			v.start = p.Pc
+		}
+		if p.As == obj.ARET || (p.As == obj.AVARKILL && p.To.Node == v.node) {
+			break
+		}
+	}
+
+	for f := f0; f != f1; f = f.S1 {
+		varkillwalk(v, f.S2, gen)
+	}
+}
+
+// Eliminate redundant nil pointer checks.
+//
+// The code generation pass emits a CHECKNIL for every possibly nil pointer.
+// This pass removes a CHECKNIL if every predecessor path has already
+// checked this value for nil.
+//
+// Simple backwards flood from check to definition.
+// Run prog loop backward from end of program to beginning to avoid quadratic
+// behavior removing a run of checks.
+//
+// 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.
+
+var killed int // f->data is either nil or &killed
+
+func nilopt(firstp *obj.Prog) {
+	g := Flowstart(firstp, nil)
+	if g == nil {
+		return
+	}
+
+	if Debug_checknil > 1 { /* || strcmp(curfn->nname->sym->name, "f1") == 0 */
+		Dumpit("nilopt", g.Start, 0)
+	}
+
+	ncheck := 0
+	nkill := 0
+	var p *obj.Prog
+	for f := g.Start; f != nil; f = f.Link {
+		p = f.Prog
+		if p.As != obj.ACHECKNIL || !Thearch.Regtyp(&p.From) {
+			continue
+		}
+		ncheck++
+		if Thearch.Stackaddr(&p.From) {
+			if Debug_checknil != 0 && p.Lineno > 1 {
+				Warnl(int(p.Lineno), "removed nil check of SP address")
+			}
+			f.Data = &killed
+			continue
+		}
+
+		nilwalkfwd(f)
+		if f.Data != nil {
+			if Debug_checknil != 0 && p.Lineno > 1 {
+				Warnl(int(p.Lineno), "removed nil check before indirect")
+			}
+			continue
+		}
+
+		nilwalkback(f)
+		if f.Data != nil {
+			if Debug_checknil != 0 && p.Lineno > 1 {
+				Warnl(int(p.Lineno), "removed repeated nil check")
+			}
+			continue
+		}
+	}
+
+	for f := g.Start; f != nil; f = f.Link {
+		if f.Data != nil {
+			nkill++
+			Thearch.Excise(f)
+		}
+	}
+
+	Flowend(g)
+
+	if Debug_checknil > 1 {
+		fmt.Printf("%v: removed %d of %d nil checks\n", Curfn.Func.Nname.Sym, nkill, ncheck)
+	}
+}
+
+func nilwalkback(fcheck *Flow) {
+	for f := fcheck; f != nil; f = Uniqp(f) {
+		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
+		}
+
+		if f != fcheck && p.As == obj.ACHECKNIL && Thearch.Sameaddr(&p.From, &fcheck.Prog.From) {
+			fcheck.Data = &killed
+			return
+		}
+	}
+}
+
+// Here is a more complex version that scans backward across branches.
+// It assumes fcheck->kill = 1 has been set on entry, and its job is to find a reason
+// to keep the check (setting fcheck->kill = 0).
+// It doesn't handle copying of aggregates as well as I would like,
+// nor variables with their address taken,
+// and it's too subtle to turn on this late in Go 1.2. Perhaps for Go 1.3.
+/*
+for(f1 = f0; f1 != nil; f1 = f1->p1) {
+	if(f1->active == gen)
+		break;
+	f1->active = gen;
+	p = f1->prog;
+
+	// If same check, stop this loop but still check
+	// alternate predecessors up to this point.
+	if(f1 != fcheck && p->as == ACHECKNIL && thearch.sameaddr(&p->from, &fcheck->prog->from))
+		break;
+
+	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;
+		return;
+	}
+
+	if(f1->p1 == nil && f1->p2 == nil) {
+		print("lost pred for %v\n", fcheck->prog);
+		for(f1=f0; f1!=nil; f1=f1->p1) {
+			thearch.proginfo(&info, f1->prog);
+			print("\t%v %d %d %D %D\n", r1->prog, info.flags&RightWrite, thearch.sameaddr(&f1->prog->to, &fcheck->prog->from), &f1->prog->to, &fcheck->prog->from);
+		}
+		fatal("lost pred trail");
+	}
+}
+
+for(f = f0; f != f1; f = f->p1)
+	for(f2 = f->p2; f2 != nil; f2 = f2->p2link)
+		nilwalkback(fcheck, f2, gen);
+*/
+
+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
+	// that implicit check. Only consider this basic block to
+	// avoid problems like:
+	//	_ = *x // should panic
+	//	for {} // no writes but infinite loop may be considered visible
+
+	var last *Flow
+	for f := Uniqs(fcheck); f != nil; f = Uniqs(f) {
+		p := f.Prog
+		if (p.Info.Flags&LeftRead != 0) && Thearch.Smallindir(&p.From, &fcheck.Prog.From) {
+			fcheck.Data = &killed
+			return
+		}
+
+		if (p.Info.Flags&(RightRead|RightWrite) != 0) && Thearch.Smallindir(&p.To, &fcheck.Prog.From) {
+			fcheck.Data = &killed
+			return
+		}
+
+		// Stop if another nil check happens.
+		if p.As == obj.ACHECKNIL {
+			return
+		}
+
+		// Stop if value is lost.
+		if (p.Info.Flags&RightWrite != 0) && Thearch.Sameaddr(&p.To, &fcheck.Prog.From) {
+			return
+		}
+
+		// Stop if memory write.
+		if (p.Info.Flags&RightWrite != 0) && !Thearch.Regtyp(&p.To) {
+			return
+		}
+
+		// Stop if we jump backward.
+		if last != nil && f.Id <= last.Id {
+			return
+		}
+		last = f
+	}
+}
diff --git a/src/cmd/compile/internal/gc/racewalk.go b/src/cmd/compile/internal/gc/racewalk.go
new file mode 100644
index 0000000..f53e8ec
--- /dev/null
+++ b/src/cmd/compile/internal/gc/racewalk.go
@@ -0,0 +1,622 @@
+// 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.
+
+package gc
+
+import (
+	"fmt"
+	"strings"
+)
+
+// The racewalk pass modifies the code tree for the function as follows:
+//
+// 1. It inserts a call to racefuncenter at the beginning of each function.
+// 2. It inserts a call to racefuncexit at the end of each function.
+// 3. It inserts a call to raceread before each memory read.
+// 4. It inserts a call to racewrite before each memory write.
+//
+// The rewriting is not yet complete. Certain nodes are not rewritten
+// but should be.
+
+// TODO(dvyukov): do not instrument initialization as writes:
+// a := make([]int, 10)
+
+// Do not instrument the following packages at all,
+// at best instrumentation would cause infinite recursion.
+var omit_pkgs = []string{"runtime", "runtime/race"}
+
+// Only insert racefuncenter/racefuncexit into the following packages.
+// Memory accesses in the packages are either uninteresting or will cause false positives.
+var noinst_pkgs = []string{"sync", "sync/atomic"}
+
+func ispkgin(pkgs []string) bool {
+	if myimportpath != "" {
+		for i := 0; i < len(pkgs); i++ {
+			if myimportpath == pkgs[i] {
+				return true
+			}
+		}
+	}
+
+	return false
+}
+
+// TODO(rsc): Remove. Put //go:norace on forkAndExecInChild instead.
+func isforkfunc(fn *Node) bool {
+	// Special case for syscall.forkAndExecInChild.
+	// In the child, this function must not acquire any locks, because
+	// they might have been locked at the time of the fork.  This means
+	// no rescheduling, no malloc calls, and no new stack segments.
+	// Race instrumentation does all of the above.
+	return myimportpath != "" && myimportpath == "syscall" && fn.Func.Nname.Sym.Name == "forkAndExecInChild"
+}
+
+func racewalk(fn *Node) {
+	if ispkgin(omit_pkgs) || isforkfunc(fn) || fn.Func.Norace {
+		return
+	}
+
+	if !ispkgin(noinst_pkgs) {
+		racewalklist(fn.Nbody, nil)
+
+		// nothing interesting for race detector in fn->enter
+		racewalklist(fn.Func.Exit, nil)
+	}
+
+	// nodpc is the PC of the caller as extracted by
+	// getcallerpc. We use -widthptr(FP) for x86.
+	// BUG: this will not work on arm.
+	nodpc := Nod(OXXX, nil, nil)
+
+	*nodpc = *nodfp
+	nodpc.Type = Types[TUINTPTR]
+	nodpc.Xoffset = int64(-Widthptr)
+	nd := mkcall("racefuncenter", nil, nil, nodpc)
+	fn.Func.Enter = concat(list1(nd), fn.Func.Enter)
+	nd = mkcall("racefuncexit", nil, nil)
+	fn.Func.Exit = list(fn.Func.Exit, nd)
+
+	if Debug['W'] != 0 {
+		s := fmt.Sprintf("after racewalk %v", fn.Func.Nname.Sym)
+		dumplist(s, fn.Nbody)
+		s = fmt.Sprintf("enter %v", fn.Func.Nname.Sym)
+		dumplist(s, fn.Func.Enter)
+		s = fmt.Sprintf("exit %v", fn.Func.Nname.Sym)
+		dumplist(s, fn.Func.Exit)
+	}
+}
+
+func racewalklist(l *NodeList, init **NodeList) {
+	var instr *NodeList
+
+	for ; l != nil; l = l.Next {
+		instr = nil
+		racewalknode(&l.N, &instr, 0, 0)
+		if init == nil {
+			l.N.Ninit = concat(l.N.Ninit, instr)
+		} else {
+			*init = concat(*init, instr)
+		}
+	}
+}
+
+// walkexpr and walkstmt combined
+// walks the tree and adds calls to the
+// instrumentation code to top-level (statement) nodes' init
+func racewalknode(np **Node, init **NodeList, wr int, skip int) {
+	n := *np
+
+	if n == nil {
+		return
+	}
+
+	if Debug['w'] > 1 {
+		Dump("racewalk-before", n)
+	}
+	setlineno(n)
+	if init == nil {
+		Fatal("racewalk: bad init list")
+	}
+	if init == &n.Ninit {
+		// If init == &n->ninit and n->ninit is non-nil,
+		// racewalknode might append it to itself.
+		// nil it out and handle it separately before putting it back.
+		l := n.Ninit
+
+		n.Ninit = nil
+		racewalklist(l, nil)
+		racewalknode(&n, &l, wr, skip) // recurse with nil n->ninit
+		appendinit(&n, l)
+		*np = n
+		return
+	}
+
+	racewalklist(n.Ninit, nil)
+
+	switch n.Op {
+	default:
+		Fatal("racewalk: unknown node type %v", Oconv(int(n.Op), 0))
+
+	case OAS, OASWB, OAS2FUNC:
+		racewalknode(&n.Left, init, 1, 0)
+		racewalknode(&n.Right, init, 0, 0)
+		goto ret
+
+		// can't matter
+	case OCFUNC, OVARKILL:
+		goto ret
+
+	case OBLOCK:
+		var out *NodeList
+		for l := n.List; l != nil; l = l.Next {
+			switch l.N.Op {
+			case OCALLFUNC, OCALLMETH, OCALLINTER:
+				racewalknode(&l.N, &out, 0, 0)
+				out = list(out, l.N)
+				// Scan past OAS nodes copying results off stack.
+				// Those must not be instrumented, because the
+				// instrumentation calls will smash the results.
+				// The assignments are to temporaries, so they cannot
+				// be involved in races and need not be instrumented.
+				for l.Next != nil && l.Next.N.Op == OAS && iscallret(l.Next.N.Right) {
+					l = l.Next
+					out = list(out, l.N)
+				}
+			default:
+				racewalknode(&l.N, &out, 0, 0)
+				out = list(out, l.N)
+			}
+		}
+		n.List = out
+		goto ret
+
+	case ODEFER:
+		racewalknode(&n.Left, init, 0, 0)
+		goto ret
+
+	case OPROC:
+		racewalknode(&n.Left, init, 0, 0)
+		goto ret
+
+	case OCALLINTER:
+		racewalknode(&n.Left, init, 0, 0)
+		goto ret
+
+		// Instrument dst argument of runtime.writebarrier* calls
+	// as we do not instrument runtime code.
+	// typedslicecopy is instrumented in runtime.
+	case OCALLFUNC:
+		racewalknode(&n.Left, init, 0, 0)
+		goto ret
+
+	case ONOT,
+		OMINUS,
+		OPLUS,
+		OREAL,
+		OIMAG,
+		OCOM,
+		OSQRT:
+		racewalknode(&n.Left, init, wr, 0)
+		goto ret
+
+	case ODOTINTER:
+		racewalknode(&n.Left, init, 0, 0)
+		goto ret
+
+	case ODOT:
+		racewalknode(&n.Left, init, 0, 1)
+		callinstr(&n, init, wr, skip)
+		goto ret
+
+	case ODOTPTR: // dst = (*x).f with implicit *; otherwise it's ODOT+OIND
+		racewalknode(&n.Left, init, 0, 0)
+
+		callinstr(&n, init, wr, skip)
+		goto ret
+
+	case OIND: // *p
+		racewalknode(&n.Left, init, 0, 0)
+
+		callinstr(&n, init, wr, skip)
+		goto ret
+
+	case OSPTR, OLEN, OCAP:
+		racewalknode(&n.Left, init, 0, 0)
+		if Istype(n.Left.Type, TMAP) {
+			n1 := Nod(OCONVNOP, n.Left, nil)
+			n1.Type = Ptrto(Types[TUINT8])
+			n1 = Nod(OIND, n1, nil)
+			typecheck(&n1, Erv)
+			callinstr(&n1, init, 0, skip)
+		}
+
+		goto ret
+
+	case OLSH,
+		ORSH,
+		OLROT,
+		OAND,
+		OANDNOT,
+		OOR,
+		OXOR,
+		OSUB,
+		OMUL,
+		OHMUL,
+		OEQ,
+		ONE,
+		OLT,
+		OLE,
+		OGE,
+		OGT,
+		OADD,
+		OCOMPLEX:
+		racewalknode(&n.Left, init, wr, 0)
+		racewalknode(&n.Right, init, wr, 0)
+		goto ret
+
+	case OANDAND, OOROR:
+		racewalknode(&n.Left, init, wr, 0)
+
+		// walk has ensured the node has moved to a location where
+		// side effects are safe.
+		// n->right may not be executed,
+		// so instrumentation goes to n->right->ninit, not init.
+		racewalknode(&n.Right, &n.Right.Ninit, wr, 0)
+
+		goto ret
+
+	case ONAME:
+		callinstr(&n, init, wr, skip)
+		goto ret
+
+	case OCONV:
+		racewalknode(&n.Left, init, wr, 0)
+		goto ret
+
+	case OCONVNOP:
+		racewalknode(&n.Left, init, wr, 0)
+		goto ret
+
+	case ODIV, OMOD:
+		racewalknode(&n.Left, init, wr, 0)
+		racewalknode(&n.Right, init, wr, 0)
+		goto ret
+
+	case OINDEX:
+		if !Isfixedarray(n.Left.Type) {
+			racewalknode(&n.Left, init, 0, 0)
+		} else if !islvalue(n.Left) {
+			// index of unaddressable array, like Map[k][i].
+			racewalknode(&n.Left, init, wr, 0)
+
+			racewalknode(&n.Right, init, 0, 0)
+			goto ret
+		}
+
+		racewalknode(&n.Right, init, 0, 0)
+		if n.Left.Type.Etype != TSTRING {
+			callinstr(&n, init, wr, skip)
+		}
+		goto ret
+
+	case OSLICE, OSLICEARR, OSLICE3, OSLICE3ARR, OSLICESTR:
+		racewalknode(&n.Left, init, 0, 0)
+		racewalknode(&n.Right, init, 0, 0)
+		goto ret
+
+	case OKEY:
+		racewalknode(&n.Left, init, 0, 0)
+		racewalknode(&n.Right, init, 0, 0)
+		goto ret
+
+	case OADDR:
+		racewalknode(&n.Left, init, 0, 1)
+		goto ret
+
+		// n->left is Type* which is not interesting.
+	case OEFACE:
+		racewalknode(&n.Right, init, 0, 0)
+
+		goto ret
+
+	case OITAB:
+		racewalknode(&n.Left, init, 0, 0)
+		goto ret
+
+		// should not appear in AST by now
+	case OSEND,
+		ORECV,
+		OCLOSE,
+		ONEW,
+		OXCASE,
+		OXFALL,
+		OCASE,
+		OPANIC,
+		ORECOVER,
+		OCONVIFACE,
+		OCMPIFACE,
+		OMAKECHAN,
+		OMAKEMAP,
+		OMAKESLICE,
+		OCALL,
+		OCOPY,
+		OAPPEND,
+		ORUNESTR,
+		OARRAYBYTESTR,
+		OARRAYRUNESTR,
+		OSTRARRAYBYTE,
+		OSTRARRAYRUNE,
+		OINDEXMAP,
+		// lowered to call
+		OCMPSTR,
+		OADDSTR,
+		ODOTTYPE,
+		ODOTTYPE2,
+		OAS2DOTTYPE,
+		OCALLPART,
+		// lowered to PTRLIT
+		OCLOSURE,  // lowered to PTRLIT
+		ORANGE,    // lowered to ordinary for loop
+		OARRAYLIT, // lowered to assignments
+		OMAPLIT,
+		OSTRUCTLIT,
+		OAS2,
+		OAS2RECV,
+		OAS2MAPR,
+		OASOP:
+		Yyerror("racewalk: %v must be lowered by now", Oconv(int(n.Op), 0))
+
+		goto ret
+
+		// impossible nodes: only appear in backend.
+	case ORROTC, OEXTEND:
+		Yyerror("racewalk: %v cannot exist now", Oconv(int(n.Op), 0))
+		goto ret
+
+	case OGETG:
+		Yyerror("racewalk: OGETG can happen only in runtime which we don't instrument")
+		goto ret
+
+	case OFOR:
+		if n.Left != nil {
+			racewalknode(&n.Left, &n.Left.Ninit, 0, 0)
+		}
+		if n.Right != nil {
+			racewalknode(&n.Right, &n.Right.Ninit, 0, 0)
+		}
+		goto ret
+
+	case OIF, OSWITCH:
+		if n.Left != nil {
+			racewalknode(&n.Left, &n.Left.Ninit, 0, 0)
+		}
+		goto ret
+
+		// just do generic traversal
+	case OCALLMETH,
+		ORETURN,
+		ORETJMP,
+		OSELECT,
+		OEMPTY,
+		OBREAK,
+		OCONTINUE,
+		OFALL,
+		OGOTO,
+		OLABEL:
+		goto ret
+
+		// does not require instrumentation
+	case OPRINT, // don't bother instrumenting it
+		OPRINTN,     // don't bother instrumenting it
+		OCHECKNIL,   // always followed by a read.
+		OPARAM,      // it appears only in fn->exit to copy heap params back
+		OCLOSUREVAR, // immutable pointer to captured variable
+		ODOTMETH,    // either part of CALLMETH or CALLPART (lowered to PTRLIT)
+		OINDREG,     // at this stage, only n(SP) nodes from nodarg
+		ODCL,        // declarations (without value) cannot be races
+		ODCLCONST,
+		ODCLTYPE,
+		OTYPE,
+		ONONAME,
+		OLITERAL,
+		OTYPESW: // ignored by code generation, do not instrument.
+		goto ret
+	}
+
+ret:
+	if n.Op != OBLOCK { // OBLOCK is handled above in a special way.
+		racewalklist(n.List, init)
+	}
+	racewalklist(n.Nbody, nil)
+	racewalklist(n.Rlist, nil)
+	*np = n
+}
+
+func isartificial(n *Node) bool {
+	// compiler-emitted artificial things that we do not want to instrument,
+	// cant' possibly participate in a data race.
+	if n.Op == ONAME && n.Sym != nil && n.Sym.Name != "" {
+		if n.Sym.Name == "_" {
+			return true
+		}
+
+		// autotmp's are always local
+		if strings.HasPrefix(n.Sym.Name, "autotmp_") {
+			return true
+		}
+
+		// statictmp's are read-only
+		if strings.HasPrefix(n.Sym.Name, "statictmp_") {
+			return true
+		}
+
+		// go.itab is accessed only by the compiler and runtime (assume safe)
+		if n.Sym.Pkg != nil && n.Sym.Pkg.Name != "" && n.Sym.Pkg.Name == "go.itab" {
+			return true
+		}
+	}
+
+	return false
+}
+
+func callinstr(np **Node, init **NodeList, wr int, skip int) bool {
+	n := *np
+
+	//print("callinstr for %+N [ %O ] etype=%E class=%d\n",
+	//	  n, n->op, n->type ? n->type->etype : -1, n->class);
+
+	if skip != 0 || n.Type == nil || n.Type.Etype >= TIDEAL {
+		return false
+	}
+	t := n.Type
+	if isartificial(n) {
+		return false
+	}
+
+	b := outervalue(n)
+
+	// it skips e.g. stores to ... parameter array
+	if isartificial(b) {
+		return false
+	}
+	class := b.Class
+
+	// BUG: we _may_ want to instrument PAUTO sometimes
+	// e.g. if we've got a local variable/method receiver
+	// that has got a pointer inside. Whether it points to
+	// the heap or not is impossible to know at compile time
+	if (class&PHEAP != 0) || class == PPARAMREF || class == PEXTERN || b.Op == OINDEX || b.Op == ODOTPTR || b.Op == OIND {
+		hascalls := 0
+		foreach(n, hascallspred, &hascalls)
+		if hascalls != 0 {
+			n = detachexpr(n, init)
+			*np = n
+		}
+
+		n = treecopy(n, 0)
+		makeaddable(n)
+		var f *Node
+		if t.Etype == TSTRUCT || Isfixedarray(t) {
+			name := "racereadrange"
+			if wr != 0 {
+				name = "racewriterange"
+			}
+			f = mkcall(name, nil, init, uintptraddr(n), Nodintconst(t.Width))
+		} else {
+			name := "raceread"
+			if wr != 0 {
+				name = "racewrite"
+			}
+			f = mkcall(name, nil, init, uintptraddr(n))
+		}
+
+		*init = list(*init, f)
+		return true
+	}
+
+	return false
+}
+
+// makeaddable returns a node whose memory location is the
+// same as n, but which is addressable in the Go language
+// sense.
+// This is different from functions like cheapexpr that may make
+// a copy of their argument.
+func makeaddable(n *Node) {
+	// The arguments to uintptraddr technically have an address but
+	// may not be addressable in the Go sense: for example, in the case
+	// of T(v).Field where T is a struct type and v is
+	// an addressable value.
+	switch n.Op {
+	case OINDEX:
+		if Isfixedarray(n.Left.Type) {
+			makeaddable(n.Left)
+		}
+
+		// Turn T(v).Field into v.Field
+	case ODOT, OXDOT:
+		if n.Left.Op == OCONVNOP {
+			n.Left = n.Left.Left
+		}
+		makeaddable(n.Left)
+
+		// nothing to do
+	case ODOTPTR:
+		fallthrough
+	default:
+		break
+	}
+}
+
+func uintptraddr(n *Node) *Node {
+	r := Nod(OADDR, n, nil)
+	r.Bounded = true
+	r = conv(r, Types[TUNSAFEPTR])
+	r = conv(r, Types[TUINTPTR])
+	return r
+}
+
+func detachexpr(n *Node, init **NodeList) *Node {
+	addr := Nod(OADDR, n, nil)
+	l := temp(Ptrto(n.Type))
+	as := Nod(OAS, l, addr)
+	typecheck(&as, Etop)
+	walkexpr(&as, init)
+	*init = list(*init, as)
+	ind := Nod(OIND, l, nil)
+	typecheck(&ind, Erv)
+	walkexpr(&ind, init)
+	return ind
+}
+
+func foreachnode(n *Node, f func(*Node, interface{}), c interface{}) {
+	if n != nil {
+		f(n, c)
+	}
+}
+
+func foreachlist(l *NodeList, f func(*Node, interface{}), c interface{}) {
+	for ; l != nil; l = l.Next {
+		foreachnode(l.N, f, c)
+	}
+}
+
+func foreach(n *Node, f func(*Node, interface{}), c interface{}) {
+	foreachlist(n.Ninit, f, c)
+	foreachnode(n.Left, f, c)
+	foreachnode(n.Right, f, c)
+	foreachlist(n.List, f, c)
+	foreachlist(n.Nbody, f, c)
+	foreachlist(n.Rlist, f, c)
+}
+
+func hascallspred(n *Node, c interface{}) {
+	switch n.Op {
+	case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER:
+		(*c.(*int))++
+	}
+}
+
+// appendinit is like addinit in subr.go
+// but appends rather than prepends.
+func appendinit(np **Node, init *NodeList) {
+	if init == nil {
+		return
+	}
+
+	n := *np
+	switch n.Op {
+	// There may be multiple refs to this node;
+	// introduce OCONVNOP to hold init list.
+	case ONAME, OLITERAL:
+		n = Nod(OCONVNOP, n, nil)
+
+		n.Type = n.Left.Type
+		n.Typecheck = 1
+		*np = n
+	}
+
+	n.Ninit = concat(n.Ninit, init)
+	n.Ullman = UINF
+}
diff --git a/src/cmd/compile/internal/gc/range.go b/src/cmd/compile/internal/gc/range.go
new file mode 100644
index 0000000..26f05d9
--- /dev/null
+++ b/src/cmd/compile/internal/gc/range.go
@@ -0,0 +1,406 @@
+// 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"
+
+/*
+ * range
+ */
+func typecheckrange(n *Node) {
+	var toomany int
+	var why string
+	var t1 *Type
+	var t2 *Type
+	var v1 *Node
+	var v2 *Node
+
+	// Typechecking order is important here:
+	// 0. first typecheck range expression (slice/map/chan),
+	//	it is evaluated only once and so logically it is not part of the loop.
+	// 1. typcheck produced values,
+	//	this part can declare new vars and so it must be typechecked before body,
+	//	because body can contain a closure that captures the vars.
+	// 2. decldepth++ to denote loop body.
+	// 3. typecheck body.
+	// 4. decldepth--.
+
+	typecheck(&n.Right, Erv)
+
+	t := n.Right.Type
+	if t == nil {
+		goto out
+	}
+
+	// delicate little dance.  see typecheckas2
+	for ll := n.List; ll != nil; ll = ll.Next {
+		if ll.N.Name == nil || ll.N.Name.Defn != n {
+			typecheck(&ll.N, Erv|Easgn)
+		}
+	}
+
+	if Isptr[t.Etype] && Isfixedarray(t.Type) {
+		t = t.Type
+	}
+	n.Type = t
+
+	toomany = 0
+	switch t.Etype {
+	default:
+		Yyerror("cannot range over %v", Nconv(n.Right, obj.FmtLong))
+		goto out
+
+	case TARRAY:
+		t1 = Types[TINT]
+		t2 = t.Type
+
+	case TMAP:
+		t1 = t.Down
+		t2 = t.Type
+
+	case TCHAN:
+		if t.Chan&Crecv == 0 {
+			Yyerror("invalid operation: range %v (receive from send-only type %v)", n.Right, n.Right.Type)
+			goto out
+		}
+
+		t1 = t.Type
+		t2 = nil
+		if count(n.List) == 2 {
+			toomany = 1
+		}
+
+	case TSTRING:
+		t1 = Types[TINT]
+		t2 = runetype
+	}
+
+	if count(n.List) > 2 || toomany != 0 {
+		Yyerror("too many variables in range")
+	}
+
+	v1 = nil
+	if n.List != nil {
+		v1 = n.List.N
+	}
+	v2 = nil
+	if n.List != nil && n.List.Next != nil {
+		v2 = n.List.Next.N
+	}
+
+	// this is not only a optimization but also a requirement in the spec.
+	// "if the second iteration variable is the blank identifier, the range
+	// clause is equivalent to the same clause with only the first variable
+	// present."
+	if isblank(v2) {
+		if v1 != nil {
+			n.List = list1(v1)
+		}
+		v2 = nil
+	}
+
+	if v1 != nil {
+		if v1.Name != nil && v1.Name.Defn == n {
+			v1.Type = t1
+		} else if v1.Type != nil && assignop(t1, v1.Type, &why) == 0 {
+			Yyerror("cannot assign type %v to %v in range%s", t1, Nconv(v1, obj.FmtLong), why)
+		}
+		checkassign(n, v1)
+	}
+
+	if v2 != nil {
+		if v2.Name != nil && v2.Name.Defn == n {
+			v2.Type = t2
+		} else if v2.Type != nil && assignop(t2, v2.Type, &why) == 0 {
+			Yyerror("cannot assign type %v to %v in range%s", t2, Nconv(v2, obj.FmtLong), why)
+		}
+		checkassign(n, v2)
+	}
+
+	// second half of dance
+out:
+	n.Typecheck = 1
+
+	for ll := n.List; ll != nil; ll = ll.Next {
+		if ll.N.Typecheck == 0 {
+			typecheck(&ll.N, Erv|Easgn)
+		}
+	}
+
+	decldepth++
+	typechecklist(n.Nbody, Etop)
+	decldepth--
+}
+
+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
+
+	a := n.Right
+	lno := int(setlineno(a))
+	n.Right = nil
+
+	var v1 *Node
+	if n.List != nil {
+		v1 = n.List.N
+	}
+	var v2 *Node
+	if n.List != nil && n.List.Next != nil && !isblank(n.List.Next.N) {
+		v2 = n.List.Next.N
+	}
+
+	// n->list has no meaning anymore, clear it
+	// to avoid erroneous processing by racewalk.
+	n.List = nil
+
+	var body *NodeList
+	var init *NodeList
+	switch t.Etype {
+	default:
+		Fatal("walkrange")
+
+		// Lower n into runtime·memclr if possible, for
+	// fast zeroing of slices and arrays (issue 5373).
+	// Look for instances of
+	//
+	// for i := range a {
+	// 	a[i] = zero
+	// }
+	//
+	// in which the evaluation of a is side-effect-free.
+	case TARRAY:
+		if Debug['N'] == 0 {
+			if flag_race == 0 {
+				if v1 != nil {
+					if v2 == nil {
+						if n.Nbody != nil {
+							if n.Nbody.N != nil { // at least one statement in body
+								if n.Nbody.Next == nil { // at most one statement in body
+									tmp := n.Nbody.N // first statement of body
+									if tmp.Op == OAS {
+										if tmp.Left.Op == OINDEX {
+											if samesafeexpr(tmp.Left.Left, a) {
+												if samesafeexpr(tmp.Left.Right, v1) {
+													if t.Type.Width > 0 {
+														if iszero(tmp.Right) {
+															// Convert to
+															// if len(a) != 0 {
+															// 	hp = &a[0]
+															// 	hn = len(a)*sizeof(elem(a))
+															// 	memclr(hp, hn)
+															// 	i = len(a) - 1
+															// }
+															n.Op = OIF
+
+															n.Nbody = nil
+															n.Left = Nod(ONE, Nod(OLEN, a, nil), Nodintconst(0))
+
+															// hp = &a[0]
+															hp := temp(Ptrto(Types[TUINT8]))
+
+															tmp := Nod(OINDEX, a, Nodintconst(0))
+															tmp.Bounded = true
+															tmp = Nod(OADDR, tmp, nil)
+															tmp = Nod(OCONVNOP, tmp, nil)
+															tmp.Type = Ptrto(Types[TUINT8])
+															n.Nbody = list(n.Nbody, Nod(OAS, hp, tmp))
+
+															// hn = len(a) * sizeof(elem(a))
+															hn := temp(Types[TUINTPTR])
+
+															tmp = Nod(OLEN, a, nil)
+															tmp = Nod(OMUL, tmp, Nodintconst(t.Type.Width))
+															tmp = conv(tmp, Types[TUINTPTR])
+															n.Nbody = list(n.Nbody, Nod(OAS, hn, tmp))
+
+															// memclr(hp, hn)
+															fn := mkcall("memclr", nil, nil, hp, hn)
+
+															n.Nbody = list(n.Nbody, fn)
+
+															// i = len(a) - 1
+															v1 = Nod(OAS, v1, Nod(OSUB, Nod(OLEN, a, nil), Nodintconst(1)))
+
+															n.Nbody = list(n.Nbody, v1)
+
+															typecheck(&n.Left, Erv)
+															typechecklist(n.Nbody, Etop)
+															walkstmt(&n)
+															lineno = int32(lno)
+															return
+														}
+													}
+												}
+											}
+										}
+									}
+								}
+							}
+						}
+					}
+				}
+			}
+		}
+
+		// orderstmt arranged for a copy of the array/slice variable if needed.
+		ha := a
+
+		hv1 := temp(Types[TINT])
+		hn := temp(Types[TINT])
+		var hp *Node
+
+		init = list(init, Nod(OAS, hv1, nil))
+		init = list(init, Nod(OAS, hn, Nod(OLEN, ha, nil)))
+		if v2 != nil {
+			hp = temp(Ptrto(n.Type.Type))
+			tmp := Nod(OINDEX, ha, Nodintconst(0))
+			tmp.Bounded = true
+			init = list(init, Nod(OAS, hp, Nod(OADDR, tmp, nil)))
+		}
+
+		n.Left = Nod(OLT, hv1, hn)
+		n.Right = Nod(OAS, hv1, Nod(OADD, hv1, Nodintconst(1)))
+		if v1 == nil {
+			body = nil
+		} else if v2 == nil {
+			body = list1(Nod(OAS, v1, hv1))
+		} else {
+			a := Nod(OAS2, nil, nil)
+			a.List = list(list1(v1), v2)
+			a.Rlist = list(list1(hv1), Nod(OIND, hp, nil))
+			body = list1(a)
+
+			// Advance pointer as part of increment.
+			// We used to advance the pointer before executing the loop body,
+			// but doing so would make the pointer point past the end of the
+			// array during the final iteration, possibly causing another unrelated
+			// piece of memory not to be garbage collected until the loop finished.
+			// Advancing during the increment ensures that the pointer p only points
+			// pass the end of the array during the final "p++; i++; if(i >= len(x)) break;",
+			// after which p is dead, so it cannot confuse the collector.
+			tmp := Nod(OADD, hp, Nodintconst(t.Type.Width))
+
+			tmp.Type = hp.Type
+			tmp.Typecheck = 1
+			tmp.Right.Type = Types[Tptr]
+			tmp.Right.Typecheck = 1
+			a = Nod(OAS, hp, tmp)
+			typecheck(&a, Etop)
+			n.Right.Ninit = list1(a)
+		}
+
+		// orderstmt allocated the iterator for us.
+	// we only use a once, so no copy needed.
+	case TMAP:
+		ha := a
+
+		th := hiter(t)
+		hit := prealloc[n]
+		hit.Type = th
+		n.Left = nil
+		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)
+
+		substArgTypes(fn, t.Down, t.Type, th)
+		init = list(init, mkcall1(fn, nil, nil, typename(t), ha, Nod(OADDR, hit, nil)))
+		n.Left = Nod(ONE, Nod(ODOT, hit, keyname), nodnil())
+
+		fn = syslook("mapiternext", 1)
+		substArgTypes(fn, th)
+		n.Right = mkcall1(fn, nil, nil, Nod(OADDR, hit, nil))
+
+		key := Nod(ODOT, hit, keyname)
+		key = Nod(OIND, key, nil)
+		if v1 == nil {
+			body = nil
+		} else if v2 == nil {
+			body = list1(Nod(OAS, v1, key))
+		} else {
+			val := Nod(ODOT, hit, valname)
+			val = Nod(OIND, val, nil)
+			a := Nod(OAS2, nil, nil)
+			a.List = list(list1(v1), v2)
+			a.Rlist = list(list1(key), val)
+			body = list1(a)
+		}
+
+		// orderstmt arranged for a copy of the channel variable.
+	case TCHAN:
+		ha := a
+
+		n.Left = nil
+
+		hv1 := temp(t.Type)
+		hv1.Typecheck = 1
+		if haspointers(t.Type) {
+			init = list(init, Nod(OAS, hv1, nil))
+		}
+		hb := temp(Types[TBOOL])
+
+		n.Left = Nod(ONE, hb, Nodbool(false))
+		a := Nod(OAS2RECV, nil, nil)
+		a.Typecheck = 1
+		a.List = list(list1(hv1), hb)
+		a.Rlist = list1(Nod(ORECV, ha, nil))
+		n.Left.Ninit = list1(a)
+		if v1 == nil {
+			body = nil
+		} else {
+			body = list1(Nod(OAS, v1, hv1))
+		}
+
+		// orderstmt arranged for a copy of the string variable.
+	case TSTRING:
+		ha := a
+
+		ohv1 := temp(Types[TINT])
+
+		hv1 := temp(Types[TINT])
+		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 {
+			hv2 = temp(runetype)
+			a = Nod(OAS2, nil, nil)
+			a.List = list(list1(hv1), hv2)
+			fn := syslook("stringiter2", 0)
+			a.Rlist = list1(mkcall1(fn, getoutargx(fn.Type), nil, ha, hv1))
+		}
+
+		n.Left = Nod(ONE, hv1, Nodintconst(0))
+		n.Left.Ninit = list(list1(Nod(OAS, ohv1, hv1)), a)
+
+		body = nil
+		if v1 != nil {
+			body = list1(Nod(OAS, v1, ohv1))
+		}
+		if v2 != nil {
+			body = list(body, Nod(OAS, v2, hv2))
+		}
+	}
+
+	n.Op = OFOR
+	typechecklist(init, Etop)
+	n.Ninit = concat(n.Ninit, init)
+	typechecklist(n.Left.Ninit, Etop)
+	typecheck(&n.Left, Erv)
+	typecheck(&n.Right, Etop)
+	typechecklist(body, Etop)
+	n.Nbody = concat(body, n.Nbody)
+	walkstmt(&n)
+
+	lineno = int32(lno)
+}
diff --git a/src/cmd/compile/internal/gc/reflect.go b/src/cmd/compile/internal/gc/reflect.go
new file mode 100644
index 0000000..1ac4a03
--- /dev/null
+++ b/src/cmd/compile/internal/gc/reflect.go
@@ -0,0 +1,1607 @@
+// 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/gcprog"
+	"cmd/internal/obj"
+	"fmt"
+	"os"
+)
+
+/*
+ * runtime interface and reflection data structures
+ */
+var signatlist *NodeList
+
+func sigcmp(a *Sig, b *Sig) int {
+	i := stringsCompare(a.name, b.name)
+	if i != 0 {
+		return i
+	}
+	if a.pkg == b.pkg {
+		return 0
+	}
+	if a.pkg == nil {
+		return -1
+	}
+	if b.pkg == nil {
+		return +1
+	}
+	return stringsCompare(a.pkg.Path, b.pkg.Path)
+}
+
+func lsort(l *Sig, f func(*Sig, *Sig) int) *Sig {
+	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 = lsort(l, f)
+	l2 = lsort(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
+		} else {
+			le.link = l2
+			le = l2
+			l2 = l2.link
+		}
+	}
+
+	le.link = nil
+	return l
+}
+
+// Builds a type representing a Bucket structure for
+// 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.go!
+const (
+	BUCKETSIZE = 8
+	MAXKEYSIZE = 128
+	MAXVALSIZE = 128
+)
+
+func makefield(name string, t *Type) *Type {
+	f := typ(TFIELD)
+	f.Type = t
+	f.Sym = new(Sym)
+	f.Sym.Name = name
+	return f
+}
+
+func mapbucket(t *Type) *Type {
+	if t.Bucket != nil {
+		return t.Bucket
+	}
+
+	bucket := typ(TSTRUCT)
+	keytype := t.Down
+	valtype := t.Type
+	dowidth(keytype)
+	dowidth(valtype)
+	if keytype.Width > MAXKEYSIZE {
+		keytype = Ptrto(keytype)
+	}
+	if valtype.Width > MAXVALSIZE {
+		valtype = Ptrto(valtype)
+	}
+
+	// The first field is: uint8 topbits[BUCKETSIZE].
+	arr := typ(TARRAY)
+
+	arr.Type = Types[TUINT8]
+	arr.Bound = BUCKETSIZE
+	field := make([]*Type, 0, 5)
+	field = append(field, makefield("topbits", arr))
+	arr = typ(TARRAY)
+	arr.Type = keytype
+	arr.Bound = BUCKETSIZE
+	field = append(field, makefield("keys", arr))
+	arr = typ(TARRAY)
+	arr.Type = valtype
+	arr.Bound = BUCKETSIZE
+	field = append(field, makefield("values", arr))
+
+	// Make sure the overflow pointer is the last memory in the struct,
+	// because the runtime assumes it can use size-ptrSize as the
+	// offset of the overflow pointer. We double-check that property
+	// below once the offsets and size are computed.
+	//
+	// BUCKETSIZE is 8, so the struct is aligned to 64 bits to this point.
+	// On 32-bit systems, the max alignment is 32-bit, and the
+	// overflow pointer will add another 32-bit field, and the struct
+	// will end with no padding.
+	// On 64-bit systems, the max alignment is 64-bit, and the
+	// overflow pointer will add another 64-bit field, and the struct
+	// will end with no padding.
+	// On nacl/amd64p32, however, the max alignment is 64-bit,
+	// but the overflow pointer will add only a 32-bit field,
+	// so if the struct needs 64-bit padding (because a key or value does)
+	// then it would end with an extra 32-bit padding field.
+	// Preempt that by emitting the padding here.
+	if int(t.Type.Align) > Widthptr || int(t.Down.Align) > Widthptr {
+		field = append(field, makefield("pad", Types[TUINTPTR]))
+	}
+
+	// If keys and values have no pointers, the map implementation
+	// can keep a list of overflow pointers on the side so that
+	// buckets can be marked as having no pointers.
+	// Arrange for the bucket to have no pointers by changing
+	// the type of the overflow field to uintptr in this case.
+	// See comment on hmap.overflow in ../../../../runtime/hashmap.go.
+	otyp := Ptrto(bucket)
+	if !haspointers(t.Type) && !haspointers(t.Down) && t.Type.Width <= MAXKEYSIZE && t.Down.Width <= MAXVALSIZE {
+		otyp = Types[TUINTPTR]
+	}
+	ovf := makefield("overflow", otyp)
+	field = append(field, ovf)
+
+	// link up fields
+	bucket.Noalg = 1
+	bucket.Local = t.Local
+	bucket.Type = field[0]
+	for n := int32(0); n < int32(len(field)-1); n++ {
+		field[n].Down = field[n+1]
+	}
+	field[len(field)-1].Down = nil
+	dowidth(bucket)
+
+	// Double-check that overflow field is final memory in struct,
+	// with no padding at end. See comment above.
+	if ovf.Width != bucket.Width-int64(Widthptr) {
+		Yyerror("bad math in mapbucket for %v", t)
+	}
+
+	t.Bucket = bucket
+
+	bucket.Map = t
+	return bucket
+}
+
+// Builds a type representing a Hmap structure for the given map type.
+// Make sure this stays in sync with ../../runtime/hashmap.go!
+func hmap(t *Type) *Type {
+	if t.Hmap != nil {
+		return t.Hmap
+	}
+
+	bucket := mapbucket(t)
+	var field [8]*Type
+	field[0] = makefield("count", Types[TINT])
+	field[1] = makefield("flags", Types[TUINT8])
+	field[2] = makefield("B", Types[TUINT8])
+	field[3] = makefield("hash0", Types[TUINT32])
+	field[4] = makefield("buckets", Ptrto(bucket))
+	field[5] = makefield("oldbuckets", Ptrto(bucket))
+	field[6] = makefield("nevacuate", Types[TUINTPTR])
+	field[7] = makefield("overflow", Types[TUNSAFEPTR])
+
+	h := typ(TSTRUCT)
+	h.Noalg = 1
+	h.Local = t.Local
+	h.Type = field[0]
+	for n := int32(0); n < int32(len(field)-1); n++ {
+		field[n].Down = field[n+1]
+	}
+	field[len(field)-1].Down = nil
+	dowidth(h)
+	t.Hmap = h
+	h.Map = t
+	return h
+}
+
+func hiter(t *Type) *Type {
+	if t.Hiter != nil {
+		return t.Hiter
+	}
+
+	// build a struct:
+	// hash_iter {
+	//    key *Key
+	//    val *Value
+	//    t *MapType
+	//    h *Hmap
+	//    buckets *Bucket
+	//    bptr *Bucket
+	//    overflow0 unsafe.Pointer
+	//    overflow1 unsafe.Pointer
+	//    startBucket uintptr
+	//    stuff uintptr
+	//    bucket uintptr
+	//    checkBucket uintptr
+	// }
+	// must match ../../runtime/hashmap.go:hash_iter.
+	var field [12]*Type
+	field[0] = makefield("key", Ptrto(t.Down))
+
+	field[1] = makefield("val", Ptrto(t.Type))
+	field[2] = makefield("t", Ptrto(Types[TUINT8]))
+	field[3] = makefield("h", Ptrto(hmap(t)))
+	field[4] = makefield("buckets", Ptrto(mapbucket(t)))
+	field[5] = makefield("bptr", Ptrto(mapbucket(t)))
+	field[6] = makefield("overflow0", Types[TUNSAFEPTR])
+	field[7] = makefield("overflow1", Types[TUNSAFEPTR])
+	field[8] = makefield("startBucket", Types[TUINTPTR])
+	field[9] = makefield("stuff", Types[TUINTPTR]) // offset+wrapped+B+I
+	field[10] = makefield("bucket", Types[TUINTPTR])
+	field[11] = makefield("checkBucket", Types[TUINTPTR])
+
+	// build iterator struct holding the above fields
+	i := typ(TSTRUCT)
+
+	i.Noalg = 1
+	i.Type = field[0]
+	for n := int32(0); n < int32(len(field)-1); n++ {
+		field[n].Down = field[n+1]
+	}
+	field[len(field)-1].Down = nil
+	dowidth(i)
+	if i.Width != int64(12*Widthptr) {
+		Yyerror("hash_iter size not correct %d %d", i.Width, 12*Widthptr)
+	}
+	t.Hiter = i
+	i.Map = t
+	return i
+}
+
+/*
+ * f is method type, with receiver.
+ * return function type, receiver as first argument (or not).
+ */
+func methodfunc(f *Type, receiver *Type) *Type {
+	var in *NodeList
+	if receiver != nil {
+		d := Nod(ODCLFIELD, nil, nil)
+		d.Type = receiver
+		in = list(in, d)
+	}
+
+	var d *Node
+	for t := getinargx(f).Type; t != nil; t = t.Down {
+		d = Nod(ODCLFIELD, nil, nil)
+		d.Type = t.Type
+		d.Isddd = t.Isddd
+		in = list(in, d)
+	}
+
+	var out *NodeList
+	for t := getoutargx(f).Type; t != nil; t = t.Down {
+		d = Nod(ODCLFIELD, nil, nil)
+		d.Type = t.Type
+		out = list(out, d)
+	}
+
+	t := functype(nil, in, out)
+	if f.Nname != nil {
+		// Link to name of original method function.
+		t.Nname = f.Nname
+	}
+
+	return t
+}
+
+/*
+ * return methods of non-interface type t, sorted by name.
+ * generates stub functions as needed.
+ */
+func methods(t *Type) *Sig {
+	// method type
+	mt := methtype(t, 0)
+
+	if mt == nil {
+		return nil
+	}
+	expandmeth(mt)
+
+	// type stored in interface word
+	it := t
+
+	if !isdirectiface(it) {
+		it = Ptrto(t)
+	}
+
+	// make list of methods for t,
+	// generating code if necessary.
+	var a *Sig
+
+	var this *Type
+	var b *Sig
+	var method *Sym
+	for f := mt.Xmethod; f != nil; f = f.Down {
+		if f.Etype != TFIELD {
+			Fatal("methods: not field %v", f)
+		}
+		if f.Type.Etype != TFUNC || f.Type.Thistuple == 0 {
+			Fatal("non-method on %v method %v %v\n", mt, f.Sym, f)
+		}
+		if getthisx(f.Type).Type == nil {
+			Fatal("receiver with no type on %v method %v %v\n", mt, f.Sym, f)
+		}
+		if f.Nointerface {
+			continue
+		}
+
+		method = f.Sym
+		if method == nil {
+			continue
+		}
+
+		// get receiver type for this particular method.
+		// if pointer receiver but non-pointer t and
+		// this is not an embedded pointer inside a struct,
+		// method does not apply.
+		this = getthisx(f.Type).Type.Type
+
+		if Isptr[this.Etype] && this.Type == t {
+			continue
+		}
+		if Isptr[this.Etype] && !Isptr[t.Etype] && f.Embedded != 2 && !isifacemethod(f.Type) {
+			continue
+		}
+
+		b = new(Sig)
+		b.link = a
+		a = b
+
+		a.name = method.Name
+		if !exportname(method.Name) {
+			if method.Pkg == nil {
+				Fatal("methods: missing package")
+			}
+			a.pkg = method.Pkg
+		}
+
+		a.isym = methodsym(method, it, 1)
+		a.tsym = methodsym(method, t, 0)
+		a.type_ = methodfunc(f.Type, t)
+		a.mtype = methodfunc(f.Type, nil)
+
+		if a.isym.Flags&SymSiggen == 0 {
+			a.isym.Flags |= SymSiggen
+			if !Eqtype(this, it) || this.Width < Types[Tptr].Width {
+				compiling_wrappers = 1
+				genwrapper(it, f, a.isym, 1)
+				compiling_wrappers = 0
+			}
+		}
+
+		if a.tsym.Flags&SymSiggen == 0 {
+			a.tsym.Flags |= SymSiggen
+			if !Eqtype(this, t) {
+				compiling_wrappers = 1
+				genwrapper(t, f, a.tsym, 0)
+				compiling_wrappers = 0
+			}
+		}
+	}
+
+	return lsort(a, sigcmp)
+}
+
+/*
+ * return methods of interface type t, sorted by name.
+ */
+func imethods(t *Type) *Sig {
+	var a *Sig
+	var method *Sym
+	var isym *Sym
+
+	var all *Sig
+	var last *Sig
+	for f := t.Type; f != nil; f = f.Down {
+		if f.Etype != TFIELD {
+			Fatal("imethods: not field")
+		}
+		if f.Type.Etype != TFUNC || f.Sym == nil {
+			continue
+		}
+		method = f.Sym
+		a = new(Sig)
+		a.name = method.Name
+		if !exportname(method.Name) {
+			if method.Pkg == nil {
+				Fatal("imethods: missing package")
+			}
+			a.pkg = method.Pkg
+		}
+
+		a.mtype = f.Type
+		a.offset = 0
+		a.type_ = methodfunc(f.Type, nil)
+
+		if last != nil && sigcmp(last, a) >= 0 {
+			Fatal("sigcmp vs sortinter %s %s", last.name, a.name)
+		}
+		if last == nil {
+			all = a
+		} else {
+			last.link = a
+		}
+		last = a
+
+		// Compiler can only refer to wrappers for non-blank methods.
+		if isblanksym(method) {
+			continue
+		}
+
+		// NOTE(rsc): Perhaps an oversight that
+		// IfaceType.Method is not in the reflect data.
+		// Generate the method body, so that compiled
+		// code can refer to it.
+		isym = methodsym(method, t, 0)
+
+		if isym.Flags&SymSiggen == 0 {
+			isym.Flags |= SymSiggen
+			genwrapper(t, f, isym, 0)
+		}
+	}
+
+	return all
+}
+
+var dimportpath_gopkg *Pkg
+
+func dimportpath(p *Pkg) {
+	if p.Pathsym != nil {
+		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("go")
+		dimportpath_gopkg.Name = "go"
+	}
+
+	nam := "importpath." + p.Prefix + "."
+
+	n := Nod(ONAME, nil, nil)
+	n.Sym = Pkglookup(nam, dimportpath_gopkg)
+
+	n.Class = PEXTERN
+	n.Xoffset = 0
+	p.Pathsym = n.Sym
+
+	if p == localpkg {
+		// Note: myimportpath != "", or else dgopkgpath won't call dimportpath.
+		gdatastring(n, myimportpath)
+	} else {
+		gdatastring(n, p.Path)
+	}
+	ggloblsym(n.Sym, int32(Types[TSTRING].Width), obj.DUPOK|obj.RODATA)
+}
+
+func dgopkgpath(s *Sym, ot int, pkg *Pkg) int {
+	if pkg == nil {
+		return dgostringptr(s, ot, "")
+	}
+
+	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("go"))
+		}
+		return dsymptr(s, ot, ns, 0)
+	}
+
+	dimportpath(pkg)
+	return dsymptr(s, ot, pkg.Pathsym, 0)
+}
+
+/*
+ * uncommonType
+ * ../../runtime/type.go:/uncommonType
+ */
+func dextratype(sym *Sym, off int, t *Type, ptroff int) int {
+	m := methods(t)
+	if t.Sym == nil && m == nil {
+		return off
+	}
+
+	// fill in *extraType pointer in header
+	off = int(Rnd(int64(off), int64(Widthptr)))
+
+	dsymptr(sym, ptroff, sym, off)
+
+	n := 0
+	for a := m; a != nil; a = a.link {
+		dtypesym(a.type_)
+		n++
+	}
+
+	ot := off
+	s := sym
+	if t.Sym != nil {
+		ot = dgostringptr(s, ot, t.Sym.Name)
+		if t != Types[t.Etype] && t != errortype {
+			ot = dgopkgpath(s, ot, t.Sym.Pkg)
+		} else {
+			ot = dgostringptr(s, ot, "")
+		}
+	} else {
+		ot = dgostringptr(s, ot, "")
+		ot = dgostringptr(s, ot, "")
+	}
+
+	// slice header
+	ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint)
+
+	ot = duintxx(s, ot, uint64(n), Widthint)
+	ot = duintxx(s, ot, uint64(n), Widthint)
+
+	// methods
+	for a := m; a != nil; a = a.link {
+		// method
+		// ../../runtime/type.go:/method
+		ot = dgostringptr(s, ot, a.name)
+
+		ot = dgopkgpath(s, ot, a.pkg)
+		ot = dsymptr(s, ot, dtypesym(a.mtype), 0)
+		ot = dsymptr(s, ot, dtypesym(a.type_), 0)
+		if a.isym != nil {
+			ot = dsymptr(s, ot, a.isym, 0)
+		} else {
+			ot = duintptr(s, ot, 0)
+		}
+		if a.tsym != nil {
+			ot = dsymptr(s, ot, a.tsym, 0)
+		} else {
+			ot = duintptr(s, ot, 0)
+		}
+	}
+
+	return ot
+}
+
+var kinds = []int{
+	TINT:        obj.KindInt,
+	TUINT:       obj.KindUint,
+	TINT8:       obj.KindInt8,
+	TUINT8:      obj.KindUint8,
+	TINT16:      obj.KindInt16,
+	TUINT16:     obj.KindUint16,
+	TINT32:      obj.KindInt32,
+	TUINT32:     obj.KindUint32,
+	TINT64:      obj.KindInt64,
+	TUINT64:     obj.KindUint64,
+	TUINTPTR:    obj.KindUintptr,
+	TFLOAT32:    obj.KindFloat32,
+	TFLOAT64:    obj.KindFloat64,
+	TBOOL:       obj.KindBool,
+	TSTRING:     obj.KindString,
+	TPTR32:      obj.KindPtr,
+	TPTR64:      obj.KindPtr,
+	TSTRUCT:     obj.KindStruct,
+	TINTER:      obj.KindInterface,
+	TCHAN:       obj.KindChan,
+	TMAP:        obj.KindMap,
+	TARRAY:      obj.KindArray,
+	TFUNC:       obj.KindFunc,
+	TCOMPLEX64:  obj.KindComplex64,
+	TCOMPLEX128: obj.KindComplex128,
+	TUNSAFEPTR:  obj.KindUnsafePointer,
+}
+
+func haspointers(t *Type) bool {
+	if t.Haspointers != 0 {
+		return t.Haspointers-1 != 0
+	}
+
+	var ret bool
+	switch t.Etype {
+	case TINT,
+		TUINT,
+		TINT8,
+		TUINT8,
+		TINT16,
+		TUINT16,
+		TINT32,
+		TUINT32,
+		TINT64,
+		TUINT64,
+		TUINTPTR,
+		TFLOAT32,
+		TFLOAT64,
+		TCOMPLEX64,
+		TCOMPLEX128,
+		TBOOL:
+		ret = false
+
+	case TARRAY:
+		if t.Bound < 0 { // slice
+			ret = true
+			break
+		}
+
+		if t.Bound == 0 { // empty array
+			ret = false
+			break
+		}
+
+		ret = haspointers(t.Type)
+
+	case TSTRUCT:
+		ret = false
+		for t1 := t.Type; t1 != nil; t1 = t1.Down {
+			if haspointers(t1.Type) {
+				ret = true
+				break
+			}
+		}
+
+	case TSTRING,
+		TPTR32,
+		TPTR64,
+		TUNSAFEPTR,
+		TINTER,
+		TCHAN,
+		TMAP,
+		TFUNC:
+		fallthrough
+	default:
+		ret = true
+
+	case TFIELD:
+		Fatal("haspointers: unexpected type, %v", t)
+	}
+
+	t.Haspointers = 1 + uint8(obj.Bool2int(ret))
+	return ret
+}
+
+// typeptrdata returns the length in bytes of the prefix of t
+// containing pointer data. Anything after this offset is scalar data.
+func typeptrdata(t *Type) int64 {
+	if !haspointers(t) {
+		return 0
+	}
+
+	switch t.Etype {
+	case TPTR32,
+		TPTR64,
+		TUNSAFEPTR,
+		TFUNC,
+		TCHAN,
+		TMAP:
+		return int64(Widthptr)
+
+	case TSTRING:
+		// struct { byte *str; intgo len; }
+		return int64(Widthptr)
+
+	case TINTER:
+		// struct { Itab *tab;	void *data; } or
+		// struct { Type *type; void *data; }
+		return 2 * int64(Widthptr)
+
+	case TARRAY:
+		if Isslice(t) {
+			// struct { byte *array; uintgo len; uintgo cap; }
+			return int64(Widthptr)
+		}
+		// haspointers already eliminated t.Bound == 0.
+		return (t.Bound-1)*t.Type.Width + typeptrdata(t.Type)
+
+	case TSTRUCT:
+		// Find the last field that has pointers.
+		var lastPtrField *Type
+		for t1 := t.Type; t1 != nil; t1 = t1.Down {
+			if haspointers(t1.Type) {
+				lastPtrField = t1
+			}
+		}
+		return lastPtrField.Width + typeptrdata(lastPtrField.Type)
+
+	default:
+		Fatal("typeptrdata: unexpected type, %v", t)
+		return 0
+	}
+}
+
+/*
+ * commonType
+ * ../../runtime/type.go:/commonType
+ */
+
+var dcommontype_algarray *Sym
+
+func dcommontype(s *Sym, ot int, t *Type) int {
+	if ot != 0 {
+		Fatal("dcommontype %d", ot)
+	}
+
+	sizeofAlg := 2 * Widthptr
+	if dcommontype_algarray == nil {
+		dcommontype_algarray = Pkglookup("algarray", Runtimepkg)
+	}
+	dowidth(t)
+	alg := algtype(t)
+	var algsym *Sym
+	if alg < 0 || alg == AMEM {
+		algsym = dalgsym(t)
+	}
+
+	var sptr *Sym
+	tptr := Ptrto(t)
+	if !Isptr[t.Etype] && (t.Sym != nil || methods(tptr) != nil) {
+		sptr = dtypesym(tptr)
+	} else {
+		sptr = weaktypesym(tptr)
+	}
+
+	// All (non-reflect-allocated) Types share the same zero object.
+	// Each place in the compiler where a pointer to the zero object
+	// might be returned by a runtime call (map access return value,
+	// 2-arg type cast) declares the size of the zerovalue it needs.
+	// The linker magically takes the max of all the sizes.
+	zero := Pkglookup("zerovalue", Runtimepkg)
+
+	gcsym, useGCProg, ptrdata := dgcsym(t)
+
+	// We use size 0 here so we get the pointer to the zero value,
+	// but don't allocate space for the zero value unless we need it.
+	// TODO: how do we get this symbol into bss?  We really want
+	// a read-only bss, but I don't think such a thing exists.
+
+	// ../../pkg/reflect/type.go:/^type.commonType
+	// actual type structure
+	//	type commonType struct {
+	//		size          uintptr
+	//		ptrsize       uintptr
+	//		hash          uint32
+	//		_             uint8
+	//		align         uint8
+	//		fieldAlign    uint8
+	//		kind          uint8
+	//		alg           unsafe.Pointer
+	//		gcdata        unsafe.Pointer
+	//		string        *string
+	//		*extraType
+	//		ptrToThis     *Type
+	//		zero          unsafe.Pointer
+	//	}
+	ot = duintptr(s, ot, uint64(t.Width))
+	ot = duintptr(s, ot, uint64(ptrdata))
+
+	ot = duint32(s, ot, typehash(t))
+	ot = duint8(s, ot, 0) // unused
+
+	// runtime (and common sense) expects alignment to be a power of two.
+	i := int(t.Align)
+
+	if i == 0 {
+		i = 1
+	}
+	if i&(i-1) != 0 {
+		Fatal("invalid alignment %d for %v", t.Align, t)
+	}
+	ot = duint8(s, ot, t.Align) // align
+	ot = duint8(s, ot, t.Align) // fieldAlign
+
+	i = kinds[t.Etype]
+	if t.Etype == TARRAY && t.Bound < 0 {
+		i = obj.KindSlice
+	}
+	if !haspointers(t) {
+		i |= obj.KindNoPointers
+	}
+	if isdirectiface(t) {
+		i |= obj.KindDirectIface
+	}
+	if useGCProg {
+		i |= obj.KindGCProg
+	}
+	ot = duint8(s, ot, uint8(i)) // kind
+	if algsym == nil {
+		ot = dsymptr(s, ot, dcommontype_algarray, alg*sizeofAlg)
+	} else {
+		ot = dsymptr(s, ot, algsym, 0)
+	}
+	ot = dsymptr(s, ot, gcsym, 0)
+
+	p := Tconv(t, obj.FmtLeft|obj.FmtUnsigned)
+
+	//print("dcommontype: %s\n", p);
+	ot = dgostringptr(s, ot, p) // string
+
+	// skip pointer to extraType,
+	// which follows the rest of this type structure.
+	// caller will fill in if needed.
+	// otherwise linker will assume 0.
+	ot += Widthptr
+
+	ot = dsymptr(s, ot, sptr, 0) // ptrto type
+	ot = dsymptr(s, ot, zero, 0) // ptr to zero value
+	return ot
+}
+
+func typesym(t *Type) *Sym {
+	return Pkglookup(Tconv(t, obj.FmtLeft), typepkg)
+}
+
+func tracksym(t *Type) *Sym {
+	return Pkglookup(Tconv(t.Outer, obj.FmtLeft)+"."+t.Sym.Name, trackpkg)
+}
+
+func typelinksym(t *Type) *Sym {
+	// %-uT is what the generated Type's string field says.
+	// It uses (ambiguous) package names instead of import paths.
+	// %-T is the complete, unambiguous type name.
+	// We want the types to end up sorted by string field,
+	// so use that first in the name, and then add :%-T to
+	// disambiguate. We use a tab character as the separator to
+	// ensure the types appear sorted by their string field. 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 := Tconv(t, obj.FmtLeft|obj.FmtUnsigned) + "\t" + Tconv(t, obj.FmtLeft)
+
+	s := Pkglookup(p, typelinkpkg)
+
+	//print("typelinksym: %s -> %+S\n", p, s);
+
+	return s
+}
+
+func typesymprefix(prefix string, t *Type) *Sym {
+	p := prefix + "." + Tconv(t, obj.FmtLeft)
+	s := Pkglookup(p, typepkg)
+
+	//print("algsym: %s -> %+S\n", p, s);
+
+	return s
+}
+
+func typenamesym(t *Type) *Sym {
+	if t == nil || (Isptr[t.Etype] && t.Type == nil) || isideal(t) {
+		Fatal("typename %v", t)
+	}
+	s := typesym(t)
+	if s.Def == nil {
+		n := Nod(ONAME, nil, nil)
+		n.Sym = s
+		n.Type = Types[TUINT8]
+		n.Addable = true
+		n.Ullman = 1
+		n.Class = PEXTERN
+		n.Xoffset = 0
+		n.Typecheck = 1
+		s.Def = n
+
+		signatlist = list(signatlist, typenod(t))
+	}
+
+	return s.Def.Sym
+}
+
+func typename(t *Type) *Node {
+	s := typenamesym(t)
+	n := Nod(OADDR, s.Def, nil)
+	n.Type = Ptrto(s.Def.Type)
+	n.Addable = true
+	n.Ullman = 2
+	n.Typecheck = 1
+	return n
+}
+
+func weaktypesym(t *Type) *Sym {
+	p := Tconv(t, obj.FmtLeft)
+	s := Pkglookup(p, weaktypepkg)
+
+	//print("weaktypesym: %s -> %+S\n", p, s);
+
+	return s
+}
+
+/*
+ * Returns 1 if t has a reflexive equality operator.
+ * That is, if x==x for all x of type t.
+ */
+func isreflexive(t *Type) bool {
+	switch t.Etype {
+	case TBOOL,
+		TINT,
+		TUINT,
+		TINT8,
+		TUINT8,
+		TINT16,
+		TUINT16,
+		TINT32,
+		TUINT32,
+		TINT64,
+		TUINT64,
+		TUINTPTR,
+		TPTR32,
+		TPTR64,
+		TUNSAFEPTR,
+		TSTRING,
+		TCHAN:
+		return true
+
+	case TFLOAT32,
+		TFLOAT64,
+		TCOMPLEX64,
+		TCOMPLEX128,
+		TINTER:
+		return false
+
+	case TARRAY:
+		if Isslice(t) {
+			Fatal("slice can't be a map key: %v", t)
+		}
+		return isreflexive(t.Type)
+
+	case TSTRUCT:
+		for t1 := t.Type; t1 != nil; t1 = t1.Down {
+			if !isreflexive(t1.Type) {
+				return false
+			}
+		}
+
+		return true
+
+	default:
+		Fatal("bad type for map key: %v", t)
+		return false
+	}
+}
+
+func dtypesym(t *Type) *Sym {
+	// 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.
+	if t == bytetype || t == runetype {
+		t = Types[t.Etype]
+	}
+
+	if isideal(t) {
+		Fatal("dtypesym %v", t)
+	}
+
+	s := typesym(t)
+	if s.Flags&SymSiggen != 0 {
+		return s
+	}
+	s.Flags |= SymSiggen
+
+	// special case (look for runtime below):
+	// when compiling package runtime,
+	// emit the type structures for int, float, etc.
+	tbase := t
+
+	if Isptr[t.Etype] && t.Sym == nil && t.Type.Sym != nil {
+		tbase = t.Type
+	}
+	dupok := 0
+	if tbase.Sym == nil {
+		dupok = obj.DUPOK
+	}
+
+	if compiling_runtime != 0 && (tbase == Types[tbase.Etype] || tbase == bytetype || tbase == runetype || tbase == errortype) { // int, float, etc
+		goto ok
+	}
+
+	// named types from other files are defined only by those files
+	if tbase.Sym != nil && !tbase.Local {
+		return s
+	}
+	if isforw[tbase.Etype] {
+		return s
+	}
+
+ok:
+	ot := 0
+	xt := 0
+	switch t.Etype {
+	default:
+		ot = dcommontype(s, ot, t)
+		xt = ot - 3*Widthptr
+
+	case TARRAY:
+		if t.Bound >= 0 {
+			// ../../runtime/type.go:/ArrayType
+			s1 := dtypesym(t.Type)
+
+			t2 := typ(TARRAY)
+			t2.Type = t.Type
+			t2.Bound = -1 // slice
+			s2 := dtypesym(t2)
+			ot = dcommontype(s, ot, t)
+			xt = ot - 3*Widthptr
+			ot = dsymptr(s, ot, s1, 0)
+			ot = dsymptr(s, ot, s2, 0)
+			ot = duintptr(s, ot, uint64(t.Bound))
+		} else {
+			// ../../runtime/type.go:/SliceType
+			s1 := dtypesym(t.Type)
+
+			ot = dcommontype(s, ot, t)
+			xt = ot - 3*Widthptr
+			ot = dsymptr(s, ot, s1, 0)
+		}
+
+		// ../../runtime/type.go:/ChanType
+	case TCHAN:
+		s1 := dtypesym(t.Type)
+
+		ot = dcommontype(s, ot, t)
+		xt = ot - 3*Widthptr
+		ot = dsymptr(s, ot, s1, 0)
+		ot = duintptr(s, ot, uint64(t.Chan))
+
+	case TFUNC:
+		for t1 := getthisx(t).Type; t1 != nil; t1 = t1.Down {
+			dtypesym(t1.Type)
+		}
+		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 {
+			dtypesym(t1.Type)
+		}
+
+		ot = dcommontype(s, ot, t)
+		xt = ot - 3*Widthptr
+		ot = duint8(s, ot, uint8(obj.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
+		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)
+		ot = duintxx(s, ot, uint64(t.Outtuple), Widthint)
+		ot = duintxx(s, ot, uint64(t.Outtuple), Widthint)
+
+		// slice data
+		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; t1 = t1.Down {
+			ot = dsymptr(s, ot, dtypesym(t1.Type), 0)
+			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
+		for a := m; a != nil; a = a.link {
+			dtypesym(a.type_)
+			n++
+		}
+
+		// ../../runtime/type.go:/InterfaceType
+		ot = dcommontype(s, ot, t)
+
+		xt = ot - 3*Widthptr
+		ot = dsymptr(s, ot, s, ot+Widthptr+2*Widthint)
+		ot = duintxx(s, ot, uint64(n), Widthint)
+		ot = duintxx(s, ot, uint64(n), Widthint)
+		for a := m; a != nil; a = a.link {
+			// ../../runtime/type.go:/imethod
+			ot = dgostringptr(s, ot, a.name)
+
+			ot = dgopkgpath(s, ot, a.pkg)
+			ot = dsymptr(s, ot, dtypesym(a.type_), 0)
+		}
+
+		// ../../runtime/type.go:/MapType
+	case TMAP:
+		s1 := dtypesym(t.Down)
+
+		s2 := dtypesym(t.Type)
+		s3 := dtypesym(mapbucket(t))
+		s4 := dtypesym(hmap(t))
+		ot = dcommontype(s, ot, t)
+		xt = ot - 3*Widthptr
+		ot = dsymptr(s, ot, s1, 0)
+		ot = dsymptr(s, ot, s2, 0)
+		ot = dsymptr(s, ot, s3, 0)
+		ot = dsymptr(s, ot, s4, 0)
+		if t.Down.Width > MAXKEYSIZE {
+			ot = duint8(s, ot, uint8(Widthptr))
+			ot = duint8(s, ot, 1) // indirect
+		} else {
+			ot = duint8(s, ot, uint8(t.Down.Width))
+			ot = duint8(s, ot, 0) // not indirect
+		}
+
+		if t.Type.Width > MAXVALSIZE {
+			ot = duint8(s, ot, uint8(Widthptr))
+			ot = duint8(s, ot, 1) // indirect
+		} else {
+			ot = duint8(s, ot, uint8(t.Type.Width))
+			ot = duint8(s, ot, 0) // not indirect
+		}
+
+		ot = duint16(s, ot, uint16(mapbucket(t).Width))
+		ot = duint8(s, ot, uint8(obj.Bool2int(isreflexive(t.Down))))
+
+	case TPTR32, TPTR64:
+		if t.Type.Etype == TANY {
+			// ../../runtime/type.go:/UnsafePointerType
+			ot = dcommontype(s, ot, t)
+
+			break
+		}
+
+		// ../../runtime/type.go:/PtrType
+		s1 := dtypesym(t.Type)
+
+		ot = dcommontype(s, ot, t)
+		xt = ot - 3*Widthptr
+		ot = dsymptr(s, ot, s1, 0)
+
+		// ../../runtime/type.go:/StructType
+	// for security, only the exported fields.
+	case TSTRUCT:
+		n := 0
+
+		for t1 := t.Type; t1 != nil; t1 = t1.Down {
+			dtypesym(t1.Type)
+			n++
+		}
+
+		ot = dcommontype(s, ot, t)
+		xt = ot - 3*Widthptr
+		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 {
+			// ../../runtime/type.go:/structField
+			if t1.Sym != nil && t1.Embedded == 0 {
+				ot = dgostringptr(s, ot, t1.Sym.Name)
+				if exportname(t1.Sym.Name) {
+					ot = dgostringptr(s, ot, "")
+				} else {
+					ot = dgopkgpath(s, ot, t1.Sym.Pkg)
+				}
+			} else {
+				ot = dgostringptr(s, ot, "")
+				if t1.Type.Sym != nil && t1.Type.Sym.Pkg == builtinpkg {
+					ot = dgopkgpath(s, ot, localpkg)
+				} else {
+					ot = dgostringptr(s, ot, "")
+				}
+			}
+
+			ot = dsymptr(s, ot, dtypesym(t1.Type), 0)
+			ot = dgostrlitptr(s, ot, t1.Note)
+			ot = duintptr(s, ot, uint64(t1.Width)) // field offset
+		}
+	}
+
+	ot = dextratype(s, ot, t, xt)
+	ggloblsym(s, int32(ot), int16(dupok|obj.RODATA))
+
+	// generate typelink.foo pointing at s = type.foo.
+	// The linker will leave a table of all the typelinks for
+	// types in the binary, so reflect can find them.
+	// We only need the link for unnamed composites that
+	// we want be able to find.
+	if t.Sym == nil {
+		switch t.Etype {
+		case TPTR32, TPTR64:
+			// The ptrto field of the type data cannot be relied on when
+			// dynamic linking: a type T may be defined in a module that makes
+			// no use of pointers to that type, but another module can contain
+			// a package that imports the first one and does use *T pointers.
+			// The second module will end up defining type data for *T and a
+			// type.*T symbol pointing at it. It's important that calling
+			// .PtrTo() on the reflect.Type for T returns this type data and
+			// not some synthesized object, so we need reflect to be able to
+			// find it!
+			if !Ctxt.Flag_dynlink {
+				break
+			}
+			fallthrough
+		case TARRAY, TCHAN, TFUNC, TMAP:
+			slink := typelinksym(t)
+			dsymptr(slink, 0, s, 0)
+			ggloblsym(slink, int32(Widthptr), int16(dupok|obj.RODATA))
+		}
+	}
+
+	return s
+}
+
+func dumptypestructs() {
+	var n *Node
+
+	// copy types from externdcl list to signatlist
+	for l := externdcl; l != nil; l = l.Next {
+		n = l.N
+		if n.Op != OTYPE {
+			continue
+		}
+		signatlist = list(signatlist, n)
+	}
+
+	// process signatlist
+	var t *Type
+	for l := signatlist; l != nil; l = l.Next {
+		n = l.N
+		if n.Op != OTYPE {
+			continue
+		}
+		t = n.Type
+		dtypesym(t)
+		if t.Sym != nil {
+			dtypesym(Ptrto(t))
+		}
+	}
+
+	// generate import strings for imported packages
+	for _, p := range pkgs {
+		if p.Direct != 0 {
+			dimportpath(p)
+		}
+	}
+
+	// do basic types if compiling package runtime.
+	// they have to be in at least one package,
+	// and runtime is always loaded implicitly,
+	// so this is as good as any.
+	// another possible choice would be package main,
+	// but using runtime means fewer copies in .6 files.
+	if compiling_runtime != 0 {
+		for i := 1; i <= TBOOL; i++ {
+			dtypesym(Ptrto(Types[i]))
+		}
+		dtypesym(Ptrto(Types[TSTRING]))
+		dtypesym(Ptrto(Types[TUNSAFEPTR]))
+
+		// emit type structs for error and func(error) string.
+		// The latter is the type of an auto-generated wrapper.
+		dtypesym(Ptrto(errortype))
+
+		dtypesym(functype(nil, list1(Nod(ODCLFIELD, nil, typenod(errortype))), list1(Nod(ODCLFIELD, nil, typenod(Types[TSTRING])))))
+
+		// add paths for runtime and main, which 6l imports implicitly.
+		dimportpath(Runtimepkg)
+
+		if flag_race != 0 {
+			dimportpath(racepkg)
+		}
+		dimportpath(mkpkg("main"))
+	}
+}
+
+func dalgsym(t *Type) *Sym {
+	var s *Sym
+	var hashfunc *Sym
+	var eqfunc *Sym
+
+	// dalgsym is only called for a type that needs an algorithm table,
+	// which implies that the type is comparable (or else it would use ANOEQ).
+
+	if algtype(t) == AMEM {
+		// we use one algorithm table for all AMEM types of a given size
+		p := fmt.Sprintf(".alg%d", t.Width)
+
+		s = Pkglookup(p, typepkg)
+
+		if s.Flags&SymAlgGen != 0 {
+			return s
+		}
+		s.Flags |= SymAlgGen
+
+		// make hash closure
+		p = fmt.Sprintf(".hashfunc%d", t.Width)
+
+		hashfunc = Pkglookup(p, typepkg)
+
+		ot := 0
+		ot = dsymptr(hashfunc, ot, Pkglookup("memhash_varlen", Runtimepkg), 0)
+		ot = duintxx(hashfunc, ot, uint64(t.Width), Widthptr) // size encoded in closure
+		ggloblsym(hashfunc, int32(ot), obj.DUPOK|obj.RODATA)
+
+		// make equality closure
+		p = fmt.Sprintf(".eqfunc%d", t.Width)
+
+		eqfunc = Pkglookup(p, typepkg)
+
+		ot = 0
+		ot = dsymptr(eqfunc, ot, Pkglookup("memequal_varlen", Runtimepkg), 0)
+		ot = duintxx(eqfunc, ot, uint64(t.Width), Widthptr)
+		ggloblsym(eqfunc, int32(ot), obj.DUPOK|obj.RODATA)
+	} else {
+		// generate an alg table specific to this type
+		s = typesymprefix(".alg", t)
+
+		hash := typesymprefix(".hash", t)
+		eq := typesymprefix(".eq", t)
+		hashfunc = typesymprefix(".hashfunc", t)
+		eqfunc = typesymprefix(".eqfunc", t)
+
+		genhash(hash, t)
+		geneq(eq, t)
+
+		// make Go funcs (closures) for calling hash and equal from Go
+		dsymptr(hashfunc, 0, hash, 0)
+
+		ggloblsym(hashfunc, int32(Widthptr), obj.DUPOK|obj.RODATA)
+		dsymptr(eqfunc, 0, eq, 0)
+		ggloblsym(eqfunc, int32(Widthptr), obj.DUPOK|obj.RODATA)
+	}
+
+	// ../../runtime/alg.go:/typeAlg
+	ot := 0
+
+	ot = dsymptr(s, ot, hashfunc, 0)
+	ot = dsymptr(s, ot, eqfunc, 0)
+	ggloblsym(s, int32(ot), obj.DUPOK|obj.RODATA)
+	return s
+}
+
+// maxPtrmaskBytes is the maximum length of a GC ptrmask bitmap,
+// which holds 1-bit entries describing where pointers are in a given type.
+// 16 bytes is enough to describe 128 pointer-sized words, 512 or 1024 bytes
+// depending on the system. Above this length, the GC information is
+// recorded as a GC program, which can express repetition compactly.
+// In either form, the information is used by the runtime to initialize the
+// heap bitmap, and for large types (like 128 or more words), they are
+// roughly the same speed. GC programs are never much larger and often
+// more compact. (If large arrays are involved, they can be arbitrarily more
+// compact.)
+//
+// The cutoff must be large enough that any allocation large enough to
+// use a GC program is large enough that it does not share heap bitmap
+// bytes with any other objects, allowing the GC program execution to
+// assume an aligned start and not use atomic operations. In the current
+// runtime, this means all malloc size classes larger than the cutoff must
+// be multiples of four words. On 32-bit systems that's 16 bytes, and
+// all size classes >= 16 bytes are 16-byte aligned, so no real constraint.
+// On 64-bit systems, that's 32 bytes, and 32-byte alignment is guaranteed
+// for size classes >= 256 bytes. On a 64-bit sytem, 256 bytes allocated
+// is 32 pointers, the bits for which fit in 4 bytes. So maxPtrmaskBytes
+// must be >= 4.
+//
+// We used to use 16 because the GC programs do have some constant overhead
+// to get started, and processing 128 pointers seems to be enough to
+// amortize that overhead well.
+//
+// To make sure that the runtime's chansend can call typeBitsBulkBarrier,
+// we raised the limit to 2048, so that even 32-bit systems are guaranteed to
+// use bitmaps for objects up to 64 kB in size.
+//
+// Also known to reflect/type.go.
+//
+const maxPtrmaskBytes = 2048
+
+// dgcsym emits and returns a data symbol containing GC information for type t,
+// along with a boolean reporting whether the UseGCProg bit should be set in
+// the type kind, and the ptrdata field to record in the reflect type information.
+func dgcsym(t *Type) (sym *Sym, useGCProg bool, ptrdata int64) {
+	ptrdata = typeptrdata(t)
+	if ptrdata/int64(Widthptr) <= maxPtrmaskBytes*8 {
+		sym = dgcptrmask(t)
+		return
+	}
+
+	useGCProg = true
+	sym, ptrdata = dgcprog(t)
+	return
+}
+
+// dgcptrmask emits and returns the symbol containing a pointer mask for type t.
+func dgcptrmask(t *Type) *Sym {
+	ptrmask := make([]byte, (typeptrdata(t)/int64(Widthptr)+7)/8)
+	fillptrmask(t, ptrmask)
+	p := fmt.Sprintf("gcbits.%x", ptrmask)
+
+	sym := Pkglookup(p, Runtimepkg)
+	if sym.Flags&SymUniq == 0 {
+		sym.Flags |= SymUniq
+		for i, x := range ptrmask {
+			duint8(sym, i, x)
+		}
+		ggloblsym(sym, int32(len(ptrmask)), obj.DUPOK|obj.RODATA|obj.LOCAL)
+	}
+	return sym
+}
+
+// fillptrmask fills in ptrmask with 1s corresponding to the
+// word offsets in t that hold pointers.
+// ptrmask is assumed to fit at least typeptrdata(t)/Widthptr bits.
+func fillptrmask(t *Type, ptrmask []byte) {
+	for i := range ptrmask {
+		ptrmask[i] = 0
+	}
+	if !haspointers(t) {
+		return
+	}
+
+	vec := bvalloc(8 * int32(len(ptrmask)))
+	xoffset := int64(0)
+	onebitwalktype1(t, &xoffset, vec)
+
+	nptr := typeptrdata(t) / int64(Widthptr)
+	for i := int64(0); i < nptr; i++ {
+		if bvget(vec, int32(i)) == 1 {
+			ptrmask[i/8] |= 1 << (uint(i) % 8)
+		}
+	}
+}
+
+// dgcprog emits and returns the symbol containing a GC program for type t
+// along with the size of the data described by the program (in the range [typeptrdata(t), t.Width]).
+// In practice, the size is typeptrdata(t) except for non-trivial arrays.
+// For non-trivial arrays, the program describes the full t.Width size.
+func dgcprog(t *Type) (*Sym, int64) {
+	dowidth(t)
+	if t.Width == BADWIDTH {
+		Fatal("dgcprog: %v badwidth", t)
+	}
+	sym := typesymprefix(".gcprog", t)
+	var p GCProg
+	p.init(sym)
+	p.emit(t, 0)
+	offset := p.w.BitIndex() * int64(Widthptr)
+	p.end()
+	if ptrdata := typeptrdata(t); offset < ptrdata || offset > t.Width {
+		Fatal("dgcprog: %v: offset=%d but ptrdata=%d size=%d", t, offset, ptrdata, t.Width)
+	}
+	return sym, offset
+}
+
+type GCProg struct {
+	sym    *Sym
+	symoff int
+	w      gcprog.Writer
+}
+
+var Debug_gcprog int // set by -d gcprog
+
+func (p *GCProg) init(sym *Sym) {
+	p.sym = sym
+	p.symoff = 4 // first 4 bytes hold program length
+	p.w.Init(p.writeByte)
+	if Debug_gcprog > 0 {
+		fmt.Fprintf(os.Stderr, "compile: start GCProg for %v\n", sym)
+		p.w.Debug(os.Stderr)
+	}
+}
+
+func (p *GCProg) writeByte(x byte) {
+	p.symoff = duint8(p.sym, p.symoff, x)
+}
+
+func (p *GCProg) end() {
+	p.w.End()
+	duint32(p.sym, 0, uint32(p.symoff-4))
+	ggloblsym(p.sym, int32(p.symoff), obj.DUPOK|obj.RODATA|obj.LOCAL)
+	if Debug_gcprog > 0 {
+		fmt.Fprintf(os.Stderr, "compile: end GCProg for %v\n", p.sym)
+	}
+}
+
+func (p *GCProg) emit(t *Type, offset int64) {
+	dowidth(t)
+	if !haspointers(t) {
+		return
+	}
+	if t.Width == int64(Widthptr) {
+		p.w.Ptr(offset / int64(Widthptr))
+		return
+	}
+	switch t.Etype {
+	default:
+		Fatal("GCProg.emit: unexpected type %v", t)
+
+	case TSTRING:
+		p.w.Ptr(offset / int64(Widthptr))
+
+	case TINTER:
+		p.w.Ptr(offset / int64(Widthptr))
+		p.w.Ptr(offset/int64(Widthptr) + 1)
+
+	case TARRAY:
+		if Isslice(t) {
+			p.w.Ptr(offset / int64(Widthptr))
+			return
+		}
+		if t.Bound == 0 {
+			// should have been handled by haspointers check above
+			Fatal("GCProg.emit: empty array")
+		}
+
+		// Flatten array-of-array-of-array to just a big array by multiplying counts.
+		count := t.Bound
+		elem := t.Type
+		for Isfixedarray(elem) {
+			count *= elem.Bound
+			elem = elem.Type
+		}
+
+		if !p.w.ShouldRepeat(elem.Width/int64(Widthptr), count) {
+			// Cheaper to just emit the bits.
+			for i := int64(0); i < count; i++ {
+				p.emit(elem, offset+i*elem.Width)
+			}
+			return
+		}
+		p.emit(elem, offset)
+		p.w.ZeroUntil((offset + elem.Width) / int64(Widthptr))
+		p.w.Repeat(elem.Width/int64(Widthptr), count-1)
+
+	case TSTRUCT:
+		for t1 := t.Type; t1 != nil; t1 = t1.Down {
+			p.emit(t1.Type, offset+t1.Width)
+		}
+	}
+}
diff --git a/src/cmd/compile/internal/gc/reg.go b/src/cmd/compile/internal/gc/reg.go
new file mode 100644
index 0000000..0fa0535
--- /dev/null
+++ b/src/cmd/compile/internal/gc/reg.go
@@ -0,0 +1,1559 @@
+// 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 at 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 at 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 (
+	"bytes"
+	"cmd/internal/obj"
+	"fmt"
+	"sort"
+	"strings"
+)
+
+// 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
+}
+
+// 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
+
+func (x rcmp) Len() int {
+	return len(x)
+}
+
+func (x rcmp) Swap(i, j int) {
+	x[i], x[j] = x[j], x[i]
+}
+
+func (x rcmp) Less(i, j int) bool {
+	p1 := &x[i]
+	p2 := &x[j]
+	if p1.cost != p2.cost {
+		return int(p2.cost)-int(p1.cost) < 0
+	}
+	if p1.varno != p2.varno {
+		return int(p2.varno)-int(p1.varno) < 0
+	}
+	if p1.enter != p2.enter {
+		return int(p2.enter.Id-p1.enter.Id) < 0
+	}
+	return false
+}
+
+func setaddrs(bit Bits) {
+	var i int
+	var n int
+	var v *Var
+	var node *Node
+
+	for bany(&bit) {
+		// convert each bit to a variable
+		i = bnum(bit)
+
+		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 = &vars[i]
+			if v.node == node && int(v.name) == n {
+				v.addr = 2
+			}
+		}
+	}
+}
+
+var regnodes [64]*Node
+
+func walkvardef(n *Node, f *Flow, active int) {
+	var f1 *Flow
+	var bn int
+	var v *Var
+
+	for f1 = f; f1 != nil; f1 = f1.S1 {
+		if f1.Active == int32(active) {
+			break
+		}
+		f1.Active = int32(active)
+		if f1.Prog.As == obj.AVARKILL && f1.Prog.To.Node == n {
+			break
+		}
+		for v, _ = n.Opt().(*Var); v != nil; v = v.nextinnode {
+			bn = v.id
+			biset(&(f1.Data.(*Reg)).act, uint(bn))
+		}
+
+		if f1.Prog.As == obj.ACALL {
+			break
+		}
+	}
+
+	for f2 := f; f2 != f1; f2 = f2.S1 {
+		if f2.S2 != nil {
+			walkvardef(n, f2.S2, active)
+		}
+	}
+}
+
+/*
+ * add mov b,rn
+ * just after r
+ */
+func addmove(r *Flow, bn int, rn int, f int) {
+	p1 := Ctxt.NewProg()
+	Clearp(p1)
+	p1.Pc = 9999
+
+	p := r.Prog
+	p1.Link = p.Link
+	p.Link = p1
+	p1.Lineno = p.Lineno
+
+	v := &vars[bn]
+
+	a := &p1.To
+	a.Offset = v.offset
+	a.Etype = uint8(v.etype)
+	a.Type = obj.TYPE_MEM
+	a.Name = v.name
+	a.Node = v.node
+	a.Sym = Linksym(v.node.Sym)
+
+	/* NOTE(rsc): 9g did
+	if(a->etype == TARRAY)
+		a->type = TYPE_ADDR;
+	else if(a->sym == nil)
+		a->type = TYPE_CONST;
+	*/
+	p1.As = int16(Thearch.Optoas(OAS, Types[uint8(v.etype)]))
+
+	// TODO(rsc): Remove special case here.
+	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
+	p1.From.Reg = int16(rn)
+	p1.From.Name = obj.NAME_NONE
+	if f == 0 {
+		p1.From = *a
+		*a = obj.Addr{}
+		a.Type = obj.TYPE_REG
+		a.Reg = int16(rn)
+	}
+
+	if Debug['R'] != 0 && Debug['v'] != 0 {
+		fmt.Printf("%v ===add=== %v\n", p, p1)
+	}
+	Ostats.Nspill++
+}
+
+func overlap_reg(o1 int64, w1 int, o2 int64, w2 int) bool {
+	t1 := o1 + int64(w1)
+	t2 := o2 + int64(w2)
+
+	if t1 <= o2 || t2 <= o1 {
+		return false
+	}
+
+	return true
+}
+
+func mkvar(f *Flow, a *obj.Addr) Bits {
+	/*
+	 * mark registers used
+	 */
+	if a.Type == obj.TYPE_NONE {
+		return zbits
+	}
+
+	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 {
+			return zbits
+		}
+		bit := zbits
+		bit.b[0] = regu
+		return bit
+
+		// TODO(rsc): Remove special case here.
+	case obj.TYPE_ADDR:
+		var bit Bits
+		if Thearch.Thechar == '5' || Thearch.Thechar == '7' || Thearch.Thechar == '9' {
+			goto memcase
+		}
+		a.Type = obj.TYPE_MEM
+		bit = mkvar(f, a)
+		setaddrs(bit)
+		a.Type = obj.TYPE_ADDR
+		Ostats.Naddr++
+		return zbits
+
+	memcase:
+		fallthrough
+
+	case obj.TYPE_MEM:
+		if r != nil {
+			r.use1.b[0] |= Thearch.RtoB(int(a.Reg))
+		}
+
+		/* NOTE: 5g did
+		if(r->f.prog->scond & (C_PBIT|C_WBIT))
+			r->set.b[0] |= RtoB(a->reg);
+		*/
+		switch a.Name {
+		default:
+			// 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_PARAM,
+			obj.NAME_AUTO:
+			n = int(a.Name)
+		}
+	}
+
+	node, _ := a.Node.(*Node)
+	if node == nil || node.Op != ONAME || node.Orig == nil {
+		return zbits
+	}
+	node = node.Orig
+	if node.Orig != node {
+		Fatal("%v: bad node", Ctxt.Dconv(a))
+	}
+	if node.Sym == nil || node.Sym.Name[0] == '.' {
+		return zbits
+	}
+	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
+	var v *Var
+	for i := 0; i < nvar; i++ {
+		v = &vars[i]
+		if v.node == node && int(v.name) == n {
+			if v.offset == o {
+				if int(v.etype) == et {
+					if int64(v.width) == w {
+						// TODO(rsc): Remove special case for arm here.
+						if flag == 0 || Thearch.Thechar != '5' {
+							return blsh(uint(i))
+						}
+					}
+				}
+			}
+
+			// if they overlap, disable both
+			if overlap_reg(v.offset, v.width, o, int(w)) {
+				//				print("disable overlap %s %d %d %d %d, %E != %E\n", s->name, v->offset, v->width, o, w, v->etype, et);
+				v.addr = 1
+
+				flag = 1
+			}
+		}
+	}
+
+	switch et {
+	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
+		// live at all calls. otherwise we might optimize away part of
+		// a variable but not all of it.
+		var v *Var
+		for i := 0; i < nvar; i++ {
+			v = &vars[i]
+			if v.node == node {
+				v.addr = 1
+			}
+		}
+
+		return zbits
+	}
+
+	i := nvar
+	nvar++
+	v = &vars[i]
+	v.id = i
+	v.offset = o
+	v.name = int8(n)
+	v.etype = int8(et)
+	v.width = int(w)
+	v.addr = int8(flag) // funny punning
+	v.node = node
+
+	// node->opt is the head of a linked list
+	// of Vars within the given Node, so that
+	// we can start at a Var and find all the other
+	// Vars in the same Go variable.
+	v.nextinnode, _ = node.Opt().(*Var)
+
+	node.SetOpt(v)
+
+	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]
+		}
+	}
+	if n == obj.NAME_PARAM {
+		for z := 0; z < BITS; z++ {
+			params.b[z] |= bit.b[z]
+		}
+	}
+
+	if node.Class == PPARAM {
+		for z := 0; z < BITS; z++ {
+			ivar.b[z] |= bit.b[z]
+		}
+	}
+	if node.Class == PPARAMOUT {
+		for z := 0; z < BITS; z++ {
+			ovar.b[z] |= bit.b[z]
+		}
+	}
+
+	// Treat values with their address taken as live at calls,
+	// because the garbage collector's liveness analysis in ../gc/plive.c does.
+	// These must be consistent or else we will elide stores and the garbage
+	// collector will see uninitialized data.
+	// The typical case where our own analysis is out of sync is when the
+	// node appears to have its address taken but that code doesn't actually
+	// get generated and therefore doesn't show up as an address being
+	// taken when we analyze the instruction stream.
+	// One instance of this case is when a closure uses the same name as
+	// an outer variable for one of its own variables declared with :=.
+	// The parser flags the outer variable as possibly shared, and therefore
+	// sets addrtaken, even though it ends up not being actually shared.
+	// 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 {
+		v.addr = 1
+	}
+
+	// Disable registerization for globals, because:
+	// (1) we might panic at any time and we want the recovery code
+	// to see the latest values (issue 1304).
+	// (2) we don't know what pointers might point at them and we want
+	// loads via those pointers to see updated values and vice versa (issue 7995).
+	//
+	// Disable registerization for results if using defer, because the deferred func
+	// might recover and return, causing the current values to be used.
+	if node.Class == PEXTERN || (Hasdefer != 0 && node.Class == PPARAMOUT) {
+		v.addr = 1
+	}
+
+	if Debug['R'] != 0 {
+		fmt.Printf("bit=%2d et=%v w=%d+%d %v %v flag=%d\n", i, Econv(int(et), 0), o, w, Nconv(node, obj.FmtSharp), Ctxt.Dconv(a), v.addr)
+	}
+	Ostats.Nvar++
+
+	return bit
+}
+
+var change int
+
+func prop(f *Flow, ref Bits, cal Bits) {
+	var f1 *Flow
+	var r1 *Reg
+	var z int
+	var i int
+	var v *Var
+	var v1 *Var
+
+	for f1 = f; f1 != nil; f1 = f1.P1 {
+		r1 = f1.Data.(*Reg)
+		for z = 0; z < BITS; z++ {
+			ref.b[z] |= r1.refahead.b[z]
+			if ref.b[z] != r1.refahead.b[z] {
+				r1.refahead.b[z] = ref.b[z]
+				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 = 1
+			}
+		}
+
+		switch f1.Prog.As {
+		case obj.ACALL:
+			if Noreturn(f1.Prog) {
+				break
+			}
+
+			// Mark all input variables (ivar) as used, because that's what the
+			// liveness bitmaps say. The liveness bitmaps say that so that a
+			// panic will not show stale values in the parameter dump.
+			// Mark variables with a recent VARDEF (r1->act) as used,
+			// so that the optimizer flushes initializations to memory,
+			// so that if a garbage collection happens during this CALL,
+			// the collector will see initialized memory. Again this is to
+			// match what the liveness bitmaps say.
+			for z = 0; z < BITS; z++ {
+				cal.b[z] |= ref.b[z] | externs.b[z] | ivar.b[z] | r1.act.b[z]
+				ref.b[z] = 0
+			}
+
+			// cal.b is the current approximation of what's live across the call.
+			// Every bit in cal.b is a single stack word. For each such word,
+			// find all the other tracked stack words in the same Go variable
+			// (struct/slice/string/interface) and mark them live too.
+			// This is necessary because the liveness analysis for the garbage
+			// collector works at variable granularity, not at word granularity.
+			// It is fundamental for slice/string/interface: the garbage collector
+			// needs the whole value, not just some of the words, in order to
+			// interpret the other bits correctly. Specifically, slice needs a consistent
+			// ptr and cap, string needs a consistent ptr and len, and interface
+			// needs a consistent type word and data word.
+			for z = 0; z < BITS; z++ {
+				if cal.b[z] == 0 {
+					continue
+				}
+				for i = 0; i < 64; i++ {
+					if z*64+i >= nvar || (cal.b[z]>>uint(i))&1 == 0 {
+						continue
+					}
+					v = &vars[z*64+i]
+					if v.node.Opt() == nil { // v represents fixed register, not Go variable
+						continue
+					}
+
+					// v->node->opt is the head of a linked list of Vars
+					// corresponding to tracked words from the Go variable v->node.
+					// Walk the list and set all the bits.
+					// For a large struct this could end up being quadratic:
+					// after the first setting, the outer loop (for z, i) would see a 1 bit
+					// for all of the remaining words in the struct, and for each such
+					// word would go through and turn on all the bits again.
+					// To avoid the quadratic behavior, we only turn on the bits if
+					// v is the head of the list or if the head's bit is not yet turned on.
+					// This will set the bits at most twice, keeping the overall loop linear.
+					v1, _ = v.node.Opt().(*Var)
+
+					if v == v1 || !btest(&cal, uint(v1.id)) {
+						for ; v1 != nil; v1 = v1.nextinnode {
+							biset(&cal, uint(v1.id))
+						}
+					}
+				}
+			}
+
+		case obj.ATEXT:
+			for z = 0; z < BITS; z++ {
+				cal.b[z] = 0
+				ref.b[z] = 0
+			}
+
+		case obj.ARET:
+			for z = 0; z < BITS; z++ {
+				cal.b[z] = externs.b[z] | ovar.b[z]
+				ref.b[z] = 0
+			}
+		}
+
+		for z = 0; z < BITS; z++ {
+			ref.b[z] = ref.b[z]&^r1.set.b[z] | r1.use1.b[z] | r1.use2.b[z]
+			cal.b[z] &^= (r1.set.b[z] | r1.use1.b[z] | r1.use2.b[z])
+			r1.refbehind.b[z] = ref.b[z]
+			r1.calbehind.b[z] = cal.b[z]
+		}
+
+		if f1.Active != 0 {
+			break
+		}
+		f1.Active = 1
+	}
+
+	var r *Reg
+	var f2 *Flow
+	for ; f != f1; f = f.P1 {
+		r = f.Data.(*Reg)
+		for f2 = f.P2; f2 != nil; f2 = f2.P2link {
+			prop(f2, r.refbehind, r.calbehind)
+		}
+	}
+}
+
+func synch(f *Flow, dif Bits) {
+	var r1 *Reg
+	var z int
+
+	for f1 := f; f1 != nil; f1 = f1.S1 {
+		r1 = f1.Data.(*Reg)
+		for z = 0; z < BITS; z++ {
+			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 = 1
+			}
+		}
+
+		if f1.Active != 0 {
+			break
+		}
+		f1.Active = 1
+		for z = 0; z < BITS; z++ {
+			dif.b[z] &^= (^r1.calbehind.b[z] & r1.calahead.b[z])
+		}
+		if f1.S2 != nil {
+			synch(f1.S2, dif)
+		}
+	}
+}
+
+func allreg(b uint64, r *Rgn) uint64 {
+	v := &vars[r.varno]
+	r.regno = 0
+	switch v.etype {
+	default:
+		Fatal("unknown etype %d/%v", Bitno(b), Econv(int(v.etype), 0))
+
+	case TINT8,
+		TUINT8,
+		TINT16,
+		TUINT16,
+		TINT32,
+		TUINT32,
+		TINT64,
+		TUINT64,
+		TINT,
+		TUINT,
+		TUINTPTR,
+		TBOOL,
+		TPTR32,
+		TPTR64:
+		i := Thearch.BtoR(^b)
+		if i != 0 && r.cost > 0 {
+			r.regno = int16(i)
+			return Thearch.RtoB(i)
+		}
+
+	case TFLOAT32, TFLOAT64:
+		i := Thearch.BtoF(^b)
+		if i != 0 && r.cost > 0 {
+			r.regno = int16(i)
+			return Thearch.FtoB(i)
+		}
+	}
+
+	return 0
+}
+
+func LOAD(r *Reg, z int) uint64 {
+	return ^r.refbehind.b[z] & r.refahead.b[z]
+}
+
+func STORE(r *Reg, z int) uint64 {
+	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))
+	r := f.Data.(*Reg)
+	if r.act.b[z]&bb != 0 {
+		return
+	}
+	var f1 *Flow
+	var r1 *Reg
+	for {
+		if r.refbehind.b[z]&bb == 0 {
+			break
+		}
+		f1 = f.P1
+		if f1 == nil {
+			break
+		}
+		r1 = f1.Data.(*Reg)
+		if r1.refahead.b[z]&bb == 0 {
+			break
+		}
+		if r1.act.b[z]&bb != 0 {
+			break
+		}
+		f = f1
+		r = r1
+	}
+
+	if LOAD(r, z)&^(r.set.b[z]&^(r.use1.b[z]|r.use2.b[z]))&bb != 0 {
+		change -= CLOAD * int(f.Loop)
+	}
+
+	for {
+		r.act.b[z] |= bb
+
+		if f.Prog.As != obj.ANOP { // don't give credit for NOPs
+			if r.use1.b[z]&bb != 0 {
+				change += CREF * int(f.Loop)
+			}
+			if (r.use2.b[z]|r.set.b[z])&bb != 0 {
+				change += CREF * int(f.Loop)
+			}
+		}
+
+		if STORE(r, z)&r.regdiff.b[z]&bb != 0 {
+			change -= CLOAD * int(f.Loop)
+		}
+
+		if r.refbehind.b[z]&bb != 0 {
+			for f1 = f.P2; f1 != nil; f1 = f1.P2link {
+				if (f1.Data.(*Reg)).refahead.b[z]&bb != 0 {
+					paint1(f1, bn)
+				}
+			}
+		}
+
+		if r.refahead.b[z]&bb == 0 {
+			break
+		}
+		f1 = f.S2
+		if f1 != nil {
+			if (f1.Data.(*Reg)).refbehind.b[z]&bb != 0 {
+				paint1(f1, bn)
+			}
+		}
+		f = f.S1
+		if f == nil {
+			break
+		}
+		r = f.Data.(*Reg)
+		if r.act.b[z]&bb != 0 {
+			break
+		}
+		if r.refbehind.b[z]&bb == 0 {
+			break
+		}
+	}
+}
+
+func paint2(f *Flow, bn int, depth int) uint64 {
+	z := bn / 64
+	bb := uint64(1 << uint(bn%64))
+	vreg := regbits
+	r := f.Data.(*Reg)
+	if r.act.b[z]&bb == 0 {
+		return vreg
+	}
+	var r1 *Reg
+	var f1 *Flow
+	for {
+		if r.refbehind.b[z]&bb == 0 {
+			break
+		}
+		f1 = f.P1
+		if f1 == nil {
+			break
+		}
+		r1 = f1.Data.(*Reg)
+		if r1.refahead.b[z]&bb == 0 {
+			break
+		}
+		if r1.act.b[z]&bb == 0 {
+			break
+		}
+		f = f1
+		r = r1
+	}
+
+	for {
+		if Debug['R'] != 0 && Debug['v'] != 0 {
+			fmt.Printf("  paint2 %d %v\n", depth, f.Prog)
+		}
+
+		r.act.b[z] &^= bb
+
+		vreg |= r.regu
+
+		if r.refbehind.b[z]&bb != 0 {
+			for f1 = f.P2; f1 != nil; f1 = f1.P2link {
+				if (f1.Data.(*Reg)).refahead.b[z]&bb != 0 {
+					vreg |= paint2(f1, bn, depth+1)
+				}
+			}
+		}
+
+		if r.refahead.b[z]&bb == 0 {
+			break
+		}
+		f1 = f.S2
+		if f1 != nil {
+			if (f1.Data.(*Reg)).refbehind.b[z]&bb != 0 {
+				vreg |= paint2(f1, bn, depth+1)
+			}
+		}
+		f = f.S1
+		if f == nil {
+			break
+		}
+		r = f.Data.(*Reg)
+		if r.act.b[z]&bb == 0 {
+			break
+		}
+		if r.refbehind.b[z]&bb == 0 {
+			break
+		}
+	}
+
+	return vreg
+}
+
+func paint3(f *Flow, bn int, rb uint64, rn int) {
+	z := bn / 64
+	bb := uint64(1 << uint(bn%64))
+	r := f.Data.(*Reg)
+	if r.act.b[z]&bb != 0 {
+		return
+	}
+	var r1 *Reg
+	var f1 *Flow
+	for {
+		if r.refbehind.b[z]&bb == 0 {
+			break
+		}
+		f1 = f.P1
+		if f1 == nil {
+			break
+		}
+		r1 = f1.Data.(*Reg)
+		if r1.refahead.b[z]&bb == 0 {
+			break
+		}
+		if r1.act.b[z]&bb != 0 {
+			break
+		}
+		f = f1
+		r = r1
+	}
+
+	if LOAD(r, z)&^(r.set.b[z]&^(r.use1.b[z]|r.use2.b[z]))&bb != 0 {
+		addmove(f, bn, rn, 0)
+	}
+	var p *obj.Prog
+	for {
+		r.act.b[z] |= bb
+		p = f.Prog
+
+		if r.use1.b[z]&bb != 0 {
+			if Debug['R'] != 0 && Debug['v'] != 0 {
+				fmt.Printf("%v", p)
+			}
+			addreg(&p.From, rn)
+			if Debug['R'] != 0 && Debug['v'] != 0 {
+				fmt.Printf(" ===change== %v\n", p)
+			}
+		}
+
+		if (r.use2.b[z]|r.set.b[z])&bb != 0 {
+			if Debug['R'] != 0 && Debug['v'] != 0 {
+				fmt.Printf("%v", p)
+			}
+			addreg(&p.To, rn)
+			if Debug['R'] != 0 && Debug['v'] != 0 {
+				fmt.Printf(" ===change== %v\n", p)
+			}
+		}
+
+		if STORE(r, z)&r.regdiff.b[z]&bb != 0 {
+			addmove(f, bn, rn, 1)
+		}
+		r.regu |= rb
+
+		if r.refbehind.b[z]&bb != 0 {
+			for f1 = f.P2; f1 != nil; f1 = f1.P2link {
+				if (f1.Data.(*Reg)).refahead.b[z]&bb != 0 {
+					paint3(f1, bn, rb, rn)
+				}
+			}
+		}
+
+		if r.refahead.b[z]&bb == 0 {
+			break
+		}
+		f1 = f.S2
+		if f1 != nil {
+			if (f1.Data.(*Reg)).refbehind.b[z]&bb != 0 {
+				paint3(f1, bn, rb, rn)
+			}
+		}
+		f = f.S1
+		if f == nil {
+			break
+		}
+		r = f.Data.(*Reg)
+		if r.act.b[z]&bb != 0 {
+			break
+		}
+		if r.refbehind.b[z]&bb == 0 {
+			break
+		}
+	}
+}
+
+func addreg(a *obj.Addr, rn int) {
+	a.Sym = nil
+	a.Node = nil
+	a.Offset = 0
+	a.Type = obj.TYPE_REG
+	a.Reg = int16(rn)
+	a.Name = 0
+
+	Ostats.Ncvtreg++
+}
+
+func dumpone(f *Flow, isreg int) {
+	fmt.Printf("%d:%v", f.Loop, f.Prog)
+	if isreg != 0 {
+		r := f.Data.(*Reg)
+		var bit Bits
+		for z := 0; z < BITS; z++ {
+			bit.b[z] = r.set.b[z] | r.use1.b[z] | r.use2.b[z] | r.refbehind.b[z] | r.refahead.b[z] | r.calbehind.b[z] | r.calahead.b[z] | r.regdiff.b[z] | r.act.b[z] | 0
+		}
+		if bany(&bit) {
+			fmt.Printf("\t")
+			if bany(&r.set) {
+				fmt.Printf(" s:%v", &r.set)
+			}
+			if bany(&r.use1) {
+				fmt.Printf(" u1:%v", &r.use1)
+			}
+			if bany(&r.use2) {
+				fmt.Printf(" u2:%v", &r.use2)
+			}
+			if bany(&r.refbehind) {
+				fmt.Printf(" rb:%v ", &r.refbehind)
+			}
+			if bany(&r.refahead) {
+				fmt.Printf(" ra:%v ", &r.refahead)
+			}
+			if bany(&r.calbehind) {
+				fmt.Printf(" cb:%v ", &r.calbehind)
+			}
+			if bany(&r.calahead) {
+				fmt.Printf(" ca:%v ", &r.calahead)
+			}
+			if bany(&r.regdiff) {
+				fmt.Printf(" d:%v ", &r.regdiff)
+			}
+			if bany(&r.act) {
+				fmt.Printf(" a:%v ", &r.act)
+			}
+		}
+	}
+
+	fmt.Printf("\n")
+}
+
+func Dumpit(str string, r0 *Flow, isreg int) {
+	var r1 *Flow
+
+	fmt.Printf("\n%s\n", str)
+	for r := r0; r != nil; r = r.Link {
+		dumpone(r, isreg)
+		r1 = r.P2
+		if r1 != nil {
+			fmt.Printf("\tpred:")
+			for ; r1 != nil; r1 = r1.P2link {
+				fmt.Printf(" %.4d", uint(int(r1.Prog.Pc)))
+			}
+			if r.P1 != nil {
+				fmt.Printf(" (and %.4d)", uint(int(r.P1.Prog.Pc)))
+			} else {
+				fmt.Printf(" (only)")
+			}
+			fmt.Printf("\n")
+		}
+
+		// Print successors if it's not just the next one
+		if r.S1 != r.Link || r.S2 != nil {
+			fmt.Printf("\tsucc:")
+			if r.S1 != nil {
+				fmt.Printf(" %.4d", uint(int(r.S1.Prog.Pc)))
+			}
+			if r.S2 != nil {
+				fmt.Printf(" %.4d", uint(int(r.S2.Prog.Pc)))
+			}
+			fmt.Printf("\n")
+		}
+	}
+}
+
+func regopt(firstp *obj.Prog) {
+	mergetemp(firstp)
+
+	/*
+	 * control flow is more complicated in generated go code
+	 * than in generated c code.  define pseudo-variables for
+	 * registers, so we have complete register usage information.
+	 */
+	var nreg int
+	regnames := Thearch.Regnames(&nreg)
+
+	nvar = nreg
+	for i := 0; i < nreg; i++ {
+		vars[i] = Var{}
+	}
+	for i := 0; i < nreg; i++ {
+		if regnodes[i] == nil {
+			regnodes[i] = newname(Lookup(regnames[i]))
+		}
+		vars[i].node = regnodes[i]
+	}
+
+	regbits = Thearch.Excludedregs()
+	externs = zbits
+	params = zbits
+	consts = zbits
+	addrs = zbits
+	ivar = zbits
+	ovar = zbits
+
+	/*
+	 * pass 1
+	 * build aux data structure
+	 * allocate pcs
+	 * find use and set of variables
+	 */
+	g := Flowstart(firstp, func() interface{} { return new(Reg) })
+	if g == nil {
+		for i := 0; i < nvar; i++ {
+			vars[i].node.SetOpt(nil)
+		}
+		return
+	}
+
+	firstf := g.Start
+
+	for f := firstf; f != nil; f = f.Link {
+		p := f.Prog
+		if p.As == obj.AVARDEF || p.As == obj.AVARKILL {
+			continue
+		}
+
+		// Avoid making variables for direct-called functions.
+		if p.As == obj.ACALL && p.To.Type == obj.TYPE_MEM && p.To.Name == obj.NAME_EXTERN {
+			continue
+		}
+
+		// from vs to doesn't matter for registers.
+		r := f.Data.(*Reg)
+		r.use1.b[0] |= p.Info.Reguse | p.Info.Regindex
+		r.set.b[0] |= p.Info.Regset
+
+		bit := mkvar(f, &p.From)
+		if bany(&bit) {
+			if p.Info.Flags&LeftAddr != 0 {
+				setaddrs(bit)
+			}
+			if p.Info.Flags&LeftRead != 0 {
+				for z := 0; z < BITS; z++ {
+					r.use1.b[z] |= bit.b[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 p.Info.Flags&RegRead != 0 {
+			r.use1.b[0] |= Thearch.RtoB(int(p.Reg))
+		}
+
+		// Currently we never generate three register forms.
+		// If we do, this will need to change.
+		if p.From3Type() != obj.TYPE_NONE {
+			Fatal("regopt not implemented for from3")
+		}
+
+		bit = mkvar(f, &p.To)
+		if bany(&bit) {
+			if p.Info.Flags&RightAddr != 0 {
+				setaddrs(bit)
+			}
+			if p.Info.Flags&RightRead != 0 {
+				for z := 0; z < BITS; z++ {
+					r.use2.b[z] |= bit.b[z]
+				}
+			}
+			if p.Info.Flags&RightWrite != 0 {
+				for z := 0; z < BITS; z++ {
+					r.set.b[z] |= bit.b[z]
+				}
+			}
+		}
+	}
+
+	for i := 0; i < nvar; i++ {
+		v := &vars[i]
+		if v.addr != 0 {
+			bit := blsh(uint(i))
+			for z := 0; z < BITS; z++ {
+				addrs.b[z] |= bit.b[z]
+			}
+		}
+
+		if Debug['R'] != 0 && Debug['v'] != 0 {
+			fmt.Printf("bit=%2d addr=%d et=%v w=%-2d s=%v + %d\n", i, v.addr, Econv(int(v.etype), 0), v.width, v.node, v.offset)
+		}
+	}
+
+	if Debug['R'] != 0 && Debug['v'] != 0 {
+		Dumpit("pass1", firstf, 1)
+	}
+
+	/*
+	 * pass 2
+	 * find looping structure
+	 */
+	flowrpo(g)
+
+	if Debug['R'] != 0 && Debug['v'] != 0 {
+		Dumpit("pass2", firstf, 1)
+	}
+
+	/*
+	 * pass 2.5
+	 * iterate propagating fat vardef covering forward
+	 * r->act records vars with a VARDEF since the last CALL.
+	 * (r->act will be reused in pass 5 for something else,
+	 * but we'll be done with it by then.)
+	 */
+	active := 0
+
+	for f := firstf; f != nil; f = f.Link {
+		f.Active = 0
+		r := f.Data.(*Reg)
+		r.act = zbits
+	}
+
+	for f := firstf; f != nil; f = f.Link {
+		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)
+		}
+	}
+
+	/*
+	 * pass 3
+	 * iterate propagating usage
+	 * 	back until flow graph is complete
+	 */
+	var f1 *Flow
+	var i int
+	var f *Flow
+loop1:
+	change = 0
+
+	for f = firstf; f != nil; f = f.Link {
+		f.Active = 0
+	}
+	for f = firstf; f != nil; f = f.Link {
+		if f.Prog.As == obj.ARET {
+			prop(f, zbits, zbits)
+		}
+	}
+
+	/* pick up unreachable code */
+loop11:
+	i = 0
+
+	for f = firstf; f != nil; f = f1 {
+		f1 = f.Link
+		if f1 != nil && f1.Active != 0 && f.Active == 0 {
+			prop(f, zbits, zbits)
+			i = 1
+		}
+	}
+
+	if i != 0 {
+		goto loop11
+	}
+	if change != 0 {
+		goto loop1
+	}
+
+	if Debug['R'] != 0 && Debug['v'] != 0 {
+		Dumpit("pass3", firstf, 1)
+	}
+
+	/*
+	 * pass 4
+	 * iterate propagating register/variable synchrony
+	 * 	forward until graph is complete
+	 */
+loop2:
+	change = 0
+
+	for f = firstf; f != nil; f = f.Link {
+		f.Active = 0
+	}
+	synch(firstf, zbits)
+	if change != 0 {
+		goto loop2
+	}
+
+	if Debug['R'] != 0 && Debug['v'] != 0 {
+		Dumpit("pass4", firstf, 1)
+	}
+
+	/*
+	 * pass 4.5
+	 * move register pseudo-variables into regu.
+	 */
+	mask := uint64((1 << uint(nreg)) - 1)
+	for f := firstf; f != nil; f = f.Link {
+		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
+		r.use2.b[0] &^= mask
+		r.refbehind.b[0] &^= mask
+		r.refahead.b[0] &^= mask
+		r.calbehind.b[0] &^= mask
+		r.calahead.b[0] &^= mask
+		r.regdiff.b[0] &^= mask
+		r.act.b[0] &^= mask
+	}
+
+	if Debug['R'] != 0 && Debug['v'] != 0 {
+		Dumpit("pass4.5", firstf, 1)
+	}
+
+	/*
+	 * pass 5
+	 * isolate regions
+	 * calculate costs (paint1)
+	 */
+	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])
+		}
+		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(), &bit)
+			}
+			f.Refset = 1
+		}
+	}
+
+	for f := firstf; f != nil; f = f.Link {
+		(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++ {
+			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(), &bit)
+			}
+			f.Refset = 1
+			Thearch.Excise(f)
+		}
+
+		for z := 0; z < BITS; z++ {
+			bit.b[z] = LOAD(r, z) &^ (r.act.b[z] | addrs.b[z])
+		}
+		for bany(&bit) {
+			i = bnum(bit)
+			change = 0
+			paint1(f, i)
+			biclr(&bit, uint(i))
+			if change <= 0 {
+				continue
+			}
+			if nregion >= MaxRgn {
+				nregion++
+				continue
+			}
+
+			region = append(region, Rgn{
+				enter: f,
+				cost:  int16(change),
+				varno: int16(i),
+			})
+			nregion++
+		}
+	}
+
+	if false && Debug['v'] != 0 && strings.Contains(Curfn.Func.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 {
+		Dumpit("pass5", firstf, 1)
+	}
+
+	/*
+	 * pass 6
+	 * determine used registers (paint2)
+	 * replace code (paint3)
+	 */
+	if Debug['R'] != 0 && Debug['v'] != 0 {
+		fmt.Printf("\nregisterizing\n")
+	}
+	var usedreg uint64
+	var vreg uint64
+	for i := 0; i < nregion; i++ {
+		rgp = &region[i]
+		if Debug['R'] != 0 && Debug['v'] != 0 {
+			fmt.Printf("region %d: cost %d varno %d enter %d\n", i, rgp.cost, rgp.varno, rgp.enter.Prog.Pc)
+		}
+		bit = blsh(uint(rgp.varno))
+		usedreg = paint2(rgp.enter, int(rgp.varno), 0)
+		vreg = allreg(usedreg, rgp)
+		if rgp.regno != 0 {
+			if Debug['R'] != 0 && Debug['v'] != 0 {
+				v := &vars[rgp.varno]
+				fmt.Printf("registerize %v+%d (bit=%2d et=%v) in %v usedreg=%#x vreg=%#x\n", v.node, v.offset, rgp.varno, Econv(int(v.etype), 0), obj.Rconv(int(rgp.regno)), usedreg, vreg)
+			}
+
+			paint3(rgp.enter, int(rgp.varno), vreg, int(rgp.regno))
+		}
+	}
+
+	/*
+	 * free aux structures. peep allocates new ones.
+	 */
+	for i := 0; i < nvar; i++ {
+		vars[i].node.SetOpt(nil)
+	}
+	Flowend(g)
+	firstf = nil
+
+	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)
+		firstf = nil
+	}
+
+	/*
+	 * pass 7
+	 * peep-hole on basic block
+	 */
+	if Debug['R'] == 0 || Debug['P'] != 0 {
+		Thearch.Peep(firstp)
+	}
+
+	/*
+	 * eliminate nops
+	 */
+	for p := firstp; p != nil; p = p.Link {
+		for p.Link != nil && p.Link.As == obj.ANOP {
+			p.Link = p.Link.Link
+		}
+		if p.To.Type == obj.TYPE_BRANCH {
+			for p.To.Val.(*obj.Prog) != nil && p.To.Val.(*obj.Prog).As == obj.ANOP {
+				p.To.Val = p.To.Val.(*obj.Prog).Link
+			}
+		}
+	}
+
+	if Debug['R'] != 0 {
+		if Ostats.Ncvtreg != 0 || Ostats.Nspill != 0 || Ostats.Nreload != 0 || Ostats.Ndelmov != 0 || Ostats.Nvar != 0 || Ostats.Naddr != 0 || false {
+			fmt.Printf("\nstats\n")
+		}
+
+		if Ostats.Ncvtreg != 0 {
+			fmt.Printf("\t%4d cvtreg\n", Ostats.Ncvtreg)
+		}
+		if Ostats.Nspill != 0 {
+			fmt.Printf("\t%4d spill\n", Ostats.Nspill)
+		}
+		if Ostats.Nreload != 0 {
+			fmt.Printf("\t%4d reload\n", Ostats.Nreload)
+		}
+		if Ostats.Ndelmov != 0 {
+			fmt.Printf("\t%4d delmov\n", Ostats.Ndelmov)
+		}
+		if Ostats.Nvar != 0 {
+			fmt.Printf("\t%4d var\n", Ostats.Nvar)
+		}
+		if Ostats.Naddr != 0 {
+			fmt.Printf("\t%4d addr\n", Ostats.Naddr)
+		}
+
+		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/compile/internal/gc/select.go b/src/cmd/compile/internal/gc/select.go
new file mode 100644
index 0000000..db20778
--- /dev/null
+++ b/src/cmd/compile/internal/gc/select.go
@@ -0,0 +1,369 @@
+// 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
+
+/*
+ * select
+ */
+func typecheckselect(sel *Node) {
+	var ncase *Node
+	var n *Node
+
+	var def *Node
+	lno := int(setlineno(sel))
+	count := 0
+	typechecklist(sel.Ninit, Etop)
+	for l := sel.List; l != nil; l = l.Next {
+		count++
+		ncase = l.N
+		setlineno(ncase)
+		if ncase.Op != OXCASE {
+			Fatal("typecheckselect %v", Oconv(int(ncase.Op), 0))
+		}
+
+		if ncase.List == nil {
+			// default
+			if def != nil {
+				Yyerror("multiple defaults in select (first at %v)", def.Line())
+			} else {
+				def = ncase
+			}
+		} else if ncase.List.Next != nil {
+			Yyerror("select cases cannot be lists")
+		} else {
+			n = typecheck(&ncase.List.N, Etop)
+			ncase.Left = n
+			ncase.List = nil
+			setlineno(n)
+			switch n.Op {
+			default:
+				Yyerror("select case must be receive, send or assign recv")
+
+				// convert x = <-c into OSELRECV(x, <-c).
+			// remove implicit conversions; the eventual assignment
+			// will reintroduce them.
+			case OAS:
+				if (n.Right.Op == OCONVNOP || n.Right.Op == OCONVIFACE) && n.Right.Implicit {
+					n.Right = n.Right.Left
+				}
+
+				if n.Right.Op != ORECV {
+					Yyerror("select assignment must have receive on right hand side")
+					break
+				}
+
+				n.Op = OSELRECV
+
+				// convert x, ok = <-c into OSELRECV2(x, <-c) with ntest=ok
+			case OAS2RECV:
+				if n.Rlist.N.Op != ORECV {
+					Yyerror("select assignment must have receive on right hand side")
+					break
+				}
+
+				n.Op = OSELRECV2
+				n.Left = n.List.N
+				n.List = list1(n.List.Next.N)
+				n.Right = n.Rlist.N
+				n.Rlist = nil
+
+				// convert <-c into OSELRECV(N, <-c)
+			case ORECV:
+				n = Nod(OSELRECV, nil, n)
+
+				n.Typecheck = 1
+				ncase.Left = n
+
+			case OSEND:
+				break
+			}
+		}
+
+		typechecklist(ncase.Nbody, Etop)
+	}
+
+	sel.Xoffset = int64(count)
+	lineno = int32(lno)
+}
+
+func walkselect(sel *Node) {
+	if sel.List == nil && sel.Xoffset != 0 {
+		Fatal("double walkselect") // already rewrote
+	}
+
+	lno := int(setlineno(sel))
+	i := count(sel.List)
+
+	// optimization: zero-case select
+	var init *NodeList
+	var r *Node
+	var n *Node
+	var var_ *Node
+	var selv *Node
+	var cas *Node
+	if i == 0 {
+		sel.Nbody = list1(mkcall("block", nil, nil))
+		goto out
+	}
+
+	// optimization: one-case select: single op.
+	// TODO(rsc): Reenable optimization once order.c can handle it.
+	// golang.org/issue/7672.
+	if i == 1 {
+		cas := sel.List.N
+		setlineno(cas)
+		l := cas.Ninit
+		if cas.Left != nil { // not default:
+			n := cas.Left
+			l = concat(l, n.Ninit)
+			n.Ninit = nil
+			var ch *Node
+			switch n.Op {
+			default:
+				Fatal("select %v", Oconv(int(n.Op), 0))
+
+				// ok already
+			case OSEND:
+				ch = n.Left
+
+			case OSELRECV, OSELRECV2:
+				ch = n.Right.Left
+				if n.Op == OSELRECV || n.List == nil {
+					if n.Left == nil {
+						n = n.Right
+					} else {
+						n.Op = OAS
+					}
+					break
+				}
+
+				if n.Left == nil {
+					typecheck(&nblank, Erv|Easgn)
+					n.Left = nblank
+				}
+
+				n.Op = OAS2
+				n.List = concat(list1(n.Left), n.List)
+				n.Rlist = list1(n.Right)
+				n.Right = nil
+				n.Left = nil
+				n.Typecheck = 0
+				typecheck(&n, Etop)
+			}
+
+			// if ch == nil { block() }; n;
+			a := Nod(OIF, nil, nil)
+
+			a.Left = Nod(OEQ, ch, nodnil())
+			a.Nbody = list1(mkcall("block", nil, &l))
+			typecheck(&a, Etop)
+			l = list(l, a)
+			l = list(l, n)
+		}
+
+		l = concat(l, cas.Nbody)
+		sel.Nbody = l
+		goto out
+	}
+
+	// convert case value arguments to addresses.
+	// this rewrite is used by both the general code and the next optimization.
+	for l := sel.List; l != nil; l = l.Next {
+		cas = l.N
+		setlineno(cas)
+		n = cas.Left
+		if n == nil {
+			continue
+		}
+		switch n.Op {
+		case OSEND:
+			n.Right = Nod(OADDR, n.Right, nil)
+			typecheck(&n.Right, Erv)
+
+		case OSELRECV, OSELRECV2:
+			if n.Op == OSELRECV2 && n.List == nil {
+				n.Op = OSELRECV
+			}
+			if n.Op == OSELRECV2 {
+				n.List.N = Nod(OADDR, n.List.N, nil)
+				typecheck(&n.List.N, Erv)
+			}
+
+			if n.Left == nil {
+				n.Left = nodnil()
+			} else {
+				n.Left = Nod(OADDR, n.Left, nil)
+				typecheck(&n.Left, Erv)
+			}
+		}
+	}
+
+	// optimization: two-case select but one is default: single non-blocking op.
+	if i == 2 && (sel.List.N.Left == nil || sel.List.Next.N.Left == nil) {
+		var cas *Node
+		var dflt *Node
+		if sel.List.N.Left == nil {
+			cas = sel.List.Next.N
+			dflt = sel.List.N
+		} else {
+			dflt = sel.List.Next.N
+			cas = sel.List.N
+		}
+
+		n := cas.Left
+		setlineno(n)
+		r := Nod(OIF, nil, nil)
+		r.Ninit = cas.Ninit
+		switch n.Op {
+		default:
+			Fatal("select %v", Oconv(int(n.Op), 0))
+
+			// if selectnbsend(c, v) { body } else { default body }
+		case OSEND:
+			ch := n.Left
+
+			r.Left = mkcall1(chanfn("selectnbsend", 2, ch.Type), Types[TBOOL], &r.Ninit, typename(ch.Type), ch, n.Right)
+
+			// if c != nil && selectnbrecv(&v, c) { body } else { default body }
+		case OSELRECV:
+			r = Nod(OIF, nil, nil)
+
+			r.Ninit = cas.Ninit
+			ch := n.Right.Left
+			r.Left = mkcall1(chanfn("selectnbrecv", 2, ch.Type), Types[TBOOL], &r.Ninit, typename(ch.Type), n.Left, ch)
+
+			// if c != nil && selectnbrecv2(&v, c) { body } else { default body }
+		case OSELRECV2:
+			r = Nod(OIF, nil, nil)
+
+			r.Ninit = cas.Ninit
+			ch := n.Right.Left
+			r.Left = mkcall1(chanfn("selectnbrecv2", 2, ch.Type), Types[TBOOL], &r.Ninit, typename(ch.Type), n.Left, n.List.N, ch)
+		}
+
+		typecheck(&r.Left, Erv)
+		r.Nbody = cas.Nbody
+		r.Rlist = concat(dflt.Ninit, dflt.Nbody)
+		sel.Nbody = list1(r)
+		goto out
+	}
+
+	init = sel.Ninit
+	sel.Ninit = nil
+
+	// generate sel-struct
+	setlineno(sel)
+
+	selv = temp(selecttype(int32(sel.Xoffset)))
+	r = Nod(OAS, selv, nil)
+	typecheck(&r, Etop)
+	init = list(init, r)
+	var_ = conv(conv(Nod(OADDR, selv, nil), Types[TUNSAFEPTR]), Ptrto(Types[TUINT8]))
+	r = mkcall("newselect", nil, nil, var_, Nodintconst(selv.Type.Width), Nodintconst(sel.Xoffset))
+	typecheck(&r, Etop)
+	init = list(init, r)
+
+	// register cases
+	for l := sel.List; l != nil; l = l.Next {
+		cas = l.N
+		setlineno(cas)
+		n = cas.Left
+		r = Nod(OIF, nil, nil)
+		r.Ninit = cas.Ninit
+		cas.Ninit = nil
+		if n != nil {
+			r.Ninit = concat(r.Ninit, n.Ninit)
+			n.Ninit = nil
+		}
+
+		if n == nil {
+			// selectdefault(sel *byte);
+			r.Left = mkcall("selectdefault", Types[TBOOL], &r.Ninit, var_)
+		} else {
+			switch n.Op {
+			default:
+				Fatal("select %v", Oconv(int(n.Op), 0))
+
+				// selectsend(sel *byte, hchan *chan any, elem *any) (selected bool);
+			case OSEND:
+				r.Left = mkcall1(chanfn("selectsend", 2, n.Left.Type), Types[TBOOL], &r.Ninit, var_, n.Left, n.Right)
+
+				// selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool);
+			case OSELRECV:
+				r.Left = mkcall1(chanfn("selectrecv", 2, n.Right.Left.Type), Types[TBOOL], &r.Ninit, var_, n.Right.Left, n.Left)
+
+				// selectrecv2(sel *byte, hchan *chan any, elem *any, received *bool) (selected bool);
+			case OSELRECV2:
+				r.Left = mkcall1(chanfn("selectrecv2", 2, n.Right.Left.Type), Types[TBOOL], &r.Ninit, var_, n.Right.Left, n.Left, n.List.N)
+			}
+		}
+
+		// selv is no longer alive after use.
+		r.Nbody = list(r.Nbody, Nod(OVARKILL, selv, nil))
+
+		r.Nbody = concat(r.Nbody, cas.Nbody)
+		r.Nbody = list(r.Nbody, Nod(OBREAK, nil, nil))
+		init = list(init, r)
+	}
+
+	// run the select
+	setlineno(sel)
+
+	init = list(init, mkcall("selectgo", nil, nil, var_))
+	sel.Nbody = init
+
+out:
+	sel.List = nil
+	walkstmtlist(sel.Nbody)
+	lineno = int32(lno)
+}
+
+// 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.
+	sudog := Nod(OTSTRUCT, nil, nil)
+
+	sudog.List = list(sudog.List, Nod(ODCLFIELD, newname(Lookup("g")), typenod(Ptrto(Types[TUINT8]))))
+	sudog.List = list(sudog.List, Nod(ODCLFIELD, newname(Lookup("selectdone")), typenod(Ptrto(Types[TUINT8]))))
+	sudog.List = list(sudog.List, Nod(ODCLFIELD, newname(Lookup("next")), typenod(Ptrto(Types[TUINT8]))))
+	sudog.List = list(sudog.List, Nod(ODCLFIELD, newname(Lookup("prev")), typenod(Ptrto(Types[TUINT8]))))
+	sudog.List = list(sudog.List, Nod(ODCLFIELD, newname(Lookup("elem")), typenod(Ptrto(Types[TUINT8]))))
+	sudog.List = list(sudog.List, Nod(ODCLFIELD, newname(Lookup("releasetime")), typenod(Types[TUINT64])))
+	sudog.List = list(sudog.List, Nod(ODCLFIELD, newname(Lookup("nrelease")), typenod(Types[TINT32])))
+	sudog.List = list(sudog.List, Nod(ODCLFIELD, newname(Lookup("waitlink")), typenod(Ptrto(Types[TUINT8]))))
+	typecheck(&sudog, Etype)
+	sudog.Type.Noalg = 1
+	sudog.Type.Local = true
+
+	scase := Nod(OTSTRUCT, nil, nil)
+	scase.List = list(scase.List, Nod(ODCLFIELD, newname(Lookup("elem")), typenod(Ptrto(Types[TUINT8]))))
+	scase.List = list(scase.List, Nod(ODCLFIELD, newname(Lookup("chan")), typenod(Ptrto(Types[TUINT8]))))
+	scase.List = list(scase.List, Nod(ODCLFIELD, newname(Lookup("pc")), typenod(Types[TUINTPTR])))
+	scase.List = list(scase.List, Nod(ODCLFIELD, newname(Lookup("kind")), typenod(Types[TUINT16])))
+	scase.List = list(scase.List, Nod(ODCLFIELD, newname(Lookup("so")), typenod(Types[TUINT16])))
+	scase.List = list(scase.List, Nod(ODCLFIELD, newname(Lookup("receivedp")), typenod(Ptrto(Types[TUINT8]))))
+	scase.List = list(scase.List, Nod(ODCLFIELD, newname(Lookup("releasetime")), typenod(Types[TUINT64])))
+	typecheck(&scase, Etype)
+	scase.Type.Noalg = 1
+	scase.Type.Local = true
+
+	sel := Nod(OTSTRUCT, nil, nil)
+	sel.List = list(sel.List, Nod(ODCLFIELD, newname(Lookup("tcase")), typenod(Types[TUINT16])))
+	sel.List = list(sel.List, Nod(ODCLFIELD, newname(Lookup("ncase")), typenod(Types[TUINT16])))
+	sel.List = list(sel.List, Nod(ODCLFIELD, newname(Lookup("pollorder")), typenod(Ptrto(Types[TUINT8]))))
+	sel.List = list(sel.List, Nod(ODCLFIELD, newname(Lookup("lockorder")), typenod(Ptrto(Types[TUINT8]))))
+	arr := Nod(OTARRAY, Nodintconst(int64(size)), scase)
+	sel.List = list(sel.List, Nod(ODCLFIELD, newname(Lookup("scase")), arr))
+	arr = Nod(OTARRAY, Nodintconst(int64(size)), typenod(Ptrto(Types[TUINT8])))
+	sel.List = list(sel.List, Nod(ODCLFIELD, newname(Lookup("lockorderarr")), arr))
+	arr = Nod(OTARRAY, Nodintconst(int64(size)), typenod(Types[TUINT16]))
+	sel.List = list(sel.List, Nod(ODCLFIELD, newname(Lookup("pollorderarr")), arr))
+	typecheck(&sel, Etype)
+	sel.Type.Noalg = 1
+	sel.Type.Local = true
+
+	return sel.Type
+}
diff --git a/src/cmd/compile/internal/gc/sinit.go b/src/cmd/compile/internal/gc/sinit.go
new file mode 100644
index 0000000..0ced4ef
--- /dev/null
+++ b/src/cmd/compile/internal/gc/sinit.go
@@ -0,0 +1,1551 @@
+// 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"
+)
+
+/*
+ * static initialization
+ */
+const (
+	InitNotStarted = 0
+	InitDone       = 1
+	InitPending    = 2
+)
+
+var (
+	initlist  *NodeList
+	initplans map[*Node]*InitPlan
+	inittemps = make(map[*Node]*Node)
+)
+
+// init1 walks the AST starting at n, and accumulates in out
+// the list of definitions needing init code in dependency order.
+func init1(n *Node, out **NodeList) {
+	if n == nil {
+		return
+	}
+	init1(n.Left, out)
+	init1(n.Right, out)
+	for l := n.List; l != nil; l = l.Next {
+		init1(l.N, out)
+	}
+
+	if n.Left != nil && n.Type != nil && n.Left.Op == OTYPE && n.Class == PFUNC {
+		// Methods called as Type.Method(receiver, ...).
+		// Definitions for method expressions are stored in type->nname.
+		init1(n.Type.Nname, out)
+	}
+
+	if n.Op != ONAME {
+		return
+	}
+	switch n.Class {
+	case PEXTERN, PFUNC:
+		break
+
+	default:
+		if isblank(n) && n.Name.Curfn == nil && n.Name.Defn != nil && n.Name.Defn.Initorder == InitNotStarted {
+			// blank names initialization is part of init() but not
+			// when they are inside a function.
+			break
+		}
+
+		return
+	}
+
+	if n.Initorder == InitDone {
+		return
+	}
+	if n.Initorder == InitPending {
+		// Since mutually recursive sets of functions are allowed,
+		// we don't necessarily raise an error if n depends on a node
+		// which is already waiting for its dependencies to be visited.
+		//
+		// initlist contains a cycle of identifiers referring to each other.
+		// If this cycle contains a variable, then this variable refers to itself.
+		// Conversely, if there exists an initialization cycle involving
+		// a variable in the program, the tree walk will reach a cycle
+		// involving that variable.
+		var nv *Node
+		if n.Class != PFUNC {
+			nv = n
+			goto foundinitloop
+		}
+
+		for l := initlist; l.N != n; l = l.Next {
+			if l.N.Class != PFUNC {
+				nv = l.N
+				goto foundinitloop
+			}
+		}
+
+		// The loop involves only functions, ok.
+		return
+
+		// if there have already been errors printed,
+		// those errors probably confused us and
+		// there might not be a loop.  let the user
+		// fix those first.
+	foundinitloop:
+		Flusherrors()
+
+		if nerrors > 0 {
+			errorexit()
+		}
+
+		// There is a loop involving nv. We know about
+		// n and initlist = n1 <- ... <- nv <- ... <- n <- ...
+		fmt.Printf("%v: initialization loop:\n", nv.Line())
+
+		// Build back pointers in initlist.
+		for l := initlist; l != nil; l = l.Next {
+			if l.Next != nil {
+				l.Next.End = l
+			}
+		}
+
+		// Print nv -> ... -> n1 -> n.
+		var l *NodeList
+		for l = initlist; l.N != nv; l = l.Next {
+		}
+		for ; l != nil; l = l.End {
+			fmt.Printf("\t%v %v refers to\n", l.N.Line(), l.N.Sym)
+		}
+
+		// Print n -> ... -> nv.
+		for l = initlist; l.N != n; l = l.Next {
+		}
+		for ; l.N != nv; l = l.End {
+			fmt.Printf("\t%v %v refers to\n", l.N.Line(), l.N.Sym)
+		}
+		fmt.Printf("\t%v %v\n", nv.Line(), nv.Sym)
+		errorexit()
+	}
+
+	// reached a new unvisited node.
+	n.Initorder = InitPending
+
+	l := new(NodeList)
+	if l == nil {
+		Flusherrors()
+		Yyerror("out of memory")
+		errorexit()
+	}
+
+	l.Next = initlist
+	l.N = n
+	l.End = nil
+	initlist = l
+
+	// make sure that everything n depends on is initialized.
+	// n->defn is an assignment to n
+	if defn := n.Name.Defn; defn != nil {
+		switch defn.Op {
+		default:
+			goto bad
+
+		case ODCLFUNC:
+			init2list(defn.Nbody, out)
+
+		case OAS:
+			if defn.Left != n {
+				goto bad
+			}
+			if isblank(defn.Left) && candiscard(defn.Right) {
+				defn.Op = OEMPTY
+				defn.Left = nil
+				defn.Right = nil
+				break
+			}
+
+			init2(defn.Right, out)
+			if Debug['j'] != 0 {
+				fmt.Printf("%v\n", n.Sym)
+			}
+			if isblank(n) || !staticinit(n, out) {
+				if Debug['%'] != 0 {
+					Dump("nonstatic", defn)
+				}
+				*out = list(*out, defn)
+			}
+
+		case OAS2FUNC, OAS2MAPR, OAS2DOTTYPE, OAS2RECV:
+			if defn.Initorder != InitNotStarted {
+				break
+			}
+			defn.Initorder = InitDone
+			for l := defn.Rlist; l != nil; l = l.Next {
+				init1(l.N, out)
+			}
+			if Debug['%'] != 0 {
+				Dump("nonstatic", defn)
+			}
+			*out = list(*out, defn)
+		}
+	}
+
+	l = initlist
+	initlist = l.Next
+	if l.N != n {
+		Fatal("bad initlist")
+	}
+
+	n.Initorder = InitDone
+	return
+
+bad:
+	Dump("defn", n.Name.Defn)
+	Fatal("init1: bad defn")
+}
+
+// recurse over n, doing init1 everywhere.
+func init2(n *Node, out **NodeList) {
+	if n == nil || n.Initorder == InitDone {
+		return
+	}
+
+	if n.Op == ONAME && n.Ninit != nil {
+		Fatal("name %v with ninit: %v\n", n.Sym, Nconv(n, obj.FmtSign))
+	}
+
+	init1(n, out)
+	init2(n.Left, out)
+	init2(n.Right, out)
+	init2list(n.Ninit, out)
+	init2list(n.List, out)
+	init2list(n.Rlist, out)
+	init2list(n.Nbody, out)
+
+	if n.Op == OCLOSURE {
+		init2list(n.Func.Closure.Nbody, out)
+	}
+	if n.Op == ODOTMETH || n.Op == OCALLPART {
+		init2(n.Type.Nname, out)
+	}
+}
+
+func init2list(l *NodeList, out **NodeList) {
+	for ; l != nil; l = l.Next {
+		init2(l.N, out)
+	}
+}
+
+func initreorder(l *NodeList, out **NodeList) {
+	var n *Node
+
+	for ; l != nil; l = l.Next {
+		n = l.N
+		switch n.Op {
+		case ODCLFUNC, ODCLCONST, ODCLTYPE:
+			continue
+		}
+
+		initreorder(n.Ninit, out)
+		n.Ninit = nil
+		init1(n, out)
+	}
+}
+
+// initfix computes initialization order for a list l of top-level
+// declarations and outputs the corresponding list of statements
+// to include in the init() function body.
+func initfix(l *NodeList) *NodeList {
+	var lout *NodeList
+	initplans = make(map[*Node]*InitPlan)
+	lno := int(lineno)
+	initreorder(l, &lout)
+	lineno = int32(lno)
+	initplans = nil
+	return lout
+}
+
+/*
+ * compilation of top-level (static) assignments
+ * into DATA statements if at all possible.
+ */
+func staticinit(n *Node, out **NodeList) bool {
+	if n.Op != ONAME || n.Class != PEXTERN || n.Name.Defn == nil || n.Name.Defn.Op != OAS {
+		Fatal("staticinit")
+	}
+
+	lineno = n.Lineno
+	l := n.Name.Defn.Left
+	r := n.Name.Defn.Right
+	return staticassign(l, r, out)
+}
+
+// like staticassign but we are copying an already
+// initialized value r.
+func staticcopy(l *Node, r *Node, out **NodeList) bool {
+	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.Name.Defn == nil { // probably zeroed but perhaps supplied externally and of unknown value
+		return false
+	}
+	if r.Name.Defn.Op != OAS {
+		return false
+	}
+	orig := r
+	r = r.Name.Defn.Right
+
+	for r.Op == OCONVNOP {
+		r = r.Left
+	}
+
+	switch r.Op {
+	case ONAME:
+		if staticcopy(l, r, out) {
+			return true
+		}
+		*out = list(*out, Nod(OAS, l, r))
+		return true
+
+	case OLITERAL:
+		if iszero(r) {
+			return true
+		}
+		gdata(l, r, int(l.Type.Width))
+		return true
+
+	case OADDR:
+		switch r.Left.Op {
+		case ONAME:
+			gdata(l, r, int(l.Type.Width))
+			return true
+		}
+
+	case OPTRLIT:
+		switch r.Left.Op {
+		//dump("not static addr", r);
+		default:
+			break
+
+			// copy pointer
+		case OARRAYLIT, OSTRUCTLIT, OMAPLIT:
+			gdata(l, Nod(OADDR, inittemps[r], nil), int(l.Type.Width))
+
+			return true
+		}
+
+	case OARRAYLIT:
+		if Isslice(r.Type) {
+			// copy slice
+			a := inittemps[r]
+
+			n1 := *l
+			n1.Xoffset = l.Xoffset + int64(Array_array)
+			gdata(&n1, Nod(OADDR, a, nil), Widthptr)
+			n1.Xoffset = l.Xoffset + int64(Array_nel)
+			gdata(&n1, r.Right, Widthint)
+			n1.Xoffset = l.Xoffset + int64(Array_cap)
+			gdata(&n1, r.Right, Widthint)
+			return true
+		}
+		fallthrough
+
+		// fall through
+	case OSTRUCTLIT:
+		p := initplans[r]
+
+		n1 := *l
+		var e *InitEntry
+		var ll *Node
+		var rr *Node
+		for i := 0; i < len(p.E); i++ {
+			e = &p.E[i]
+			n1.Xoffset = l.Xoffset + e.Xoffset
+			n1.Type = e.Expr.Type
+			if e.Expr.Op == OLITERAL {
+				gdata(&n1, e.Expr, int(n1.Type.Width))
+			} else {
+				ll = Nod(OXXX, nil, nil)
+				*ll = n1
+				ll.Orig = ll // completely separate copy
+				if !staticassign(ll, e.Expr, out) {
+					// Requires computation, but we're
+					// copying someone else's computation.
+					rr = Nod(OXXX, nil, nil)
+
+					*rr = *orig
+					rr.Orig = rr // completely separate copy
+					rr.Type = ll.Type
+					rr.Xoffset += e.Xoffset
+					setlineno(rr)
+					*out = list(*out, Nod(OAS, ll, rr))
+				}
+			}
+		}
+
+		return true
+	}
+
+	return false
+}
+
+func staticassign(l *Node, r *Node, out **NodeList) bool {
+	var n1 Node
+
+	for r.Op == OCONVNOP {
+		r = r.Left
+	}
+
+	switch r.Op {
+	//dump("not static", r);
+	default:
+		break
+
+	case ONAME:
+		return staticcopy(l, r, out)
+
+	case OLITERAL:
+		if iszero(r) {
+			return true
+		}
+		gdata(l, r, int(l.Type.Width))
+		return true
+
+	case OADDR:
+		var nam Node
+		if stataddr(&nam, r.Left) {
+			n1 := *r
+			n1.Left = &nam
+			gdata(l, &n1, int(l.Type.Width))
+			return true
+		}
+		fallthrough
+
+	case OPTRLIT:
+		switch r.Left.Op {
+		//dump("not static ptrlit", r);
+		default:
+			break
+
+			// Init pointer.
+		case OARRAYLIT, OMAPLIT, OSTRUCTLIT:
+			a := staticname(r.Left.Type, 1)
+
+			inittemps[r] = a
+			gdata(l, Nod(OADDR, a, nil), int(l.Type.Width))
+
+			// Init underlying literal.
+			if !staticassign(a, r.Left, out) {
+				*out = list(*out, Nod(OAS, a, r.Left))
+			}
+			return true
+		}
+
+	case OSTRARRAYBYTE:
+		if l.Class == PEXTERN && r.Left.Op == OLITERAL {
+			sval := r.Left.Val().U.(string)
+			slicebytes(l, sval, len(sval))
+			return true
+		}
+
+	case OARRAYLIT:
+		initplan(r)
+		if Isslice(r.Type) {
+			// Init slice.
+			ta := typ(TARRAY)
+
+			ta.Type = r.Type.Type
+			ta.Bound = Mpgetfix(r.Right.Val().U.(*Mpint))
+			a := staticname(ta, 1)
+			inittemps[r] = a
+			n1 = *l
+			n1.Xoffset = l.Xoffset + int64(Array_array)
+			gdata(&n1, Nod(OADDR, a, nil), Widthptr)
+			n1.Xoffset = l.Xoffset + int64(Array_nel)
+			gdata(&n1, r.Right, Widthint)
+			n1.Xoffset = l.Xoffset + int64(Array_cap)
+			gdata(&n1, r.Right, Widthint)
+
+			// Fall through to init underlying array.
+			l = a
+		}
+		fallthrough
+
+		// fall through
+	case OSTRUCTLIT:
+		initplan(r)
+
+		p := initplans[r]
+		n1 = *l
+		var e *InitEntry
+		var a *Node
+		for i := 0; i < len(p.E); i++ {
+			e = &p.E[i]
+			n1.Xoffset = l.Xoffset + e.Xoffset
+			n1.Type = e.Expr.Type
+			if e.Expr.Op == OLITERAL {
+				gdata(&n1, e.Expr, int(n1.Type.Width))
+			} else {
+				setlineno(e.Expr)
+				a = Nod(OXXX, nil, nil)
+				*a = n1
+				a.Orig = a // completely separate copy
+				if !staticassign(a, e.Expr, out) {
+					*out = list(*out, Nod(OAS, a, e.Expr))
+				}
+			}
+		}
+
+		return true
+
+		// TODO: Table-driven map insert.
+	case OMAPLIT:
+		break
+	}
+
+	return false
+}
+
+/*
+ * from here down is the walk analysis
+ * of composite literals.
+ * most of the work is to generate
+ * data statements for the constant
+ * part of the composite literal.
+ */
+func staticname(t *Type, ctxt int) *Node {
+	n := newname(Lookupf("statictmp_%.4d", statuniqgen))
+	statuniqgen++
+	if ctxt == 0 {
+		n.Name.Readonly = true
+	}
+	addvar(n, t, PEXTERN)
+	return n
+}
+
+func isliteral(n *Node) bool {
+	if n.Op == OLITERAL {
+		if n.Val().Ctype() != CTNIL {
+			return true
+		}
+	}
+	return false
+}
+
+func simplename(n *Node) bool {
+	if n.Op != ONAME {
+		return false
+	}
+	if !n.Addable {
+		return false
+	}
+	if n.Class&PHEAP != 0 {
+		return false
+	}
+	if n.Class == PPARAMREF {
+		return false
+	}
+	return true
+}
+
+func litas(l *Node, r *Node, init **NodeList) {
+	a := Nod(OAS, l, r)
+	typecheck(&a, Etop)
+	walkexpr(&a, init)
+	*init = list(*init, a)
+}
+
+const (
+	MODEDYNAM = 1
+	MODECONST = 2
+)
+
+func getdyn(n *Node, top int) int {
+	mode := 0
+	switch n.Op {
+	default:
+		if isliteral(n) {
+			return MODECONST
+		}
+		return MODEDYNAM
+
+	case OARRAYLIT:
+		if top == 0 && n.Type.Bound < 0 {
+			return MODEDYNAM
+		}
+		fallthrough
+
+	case OSTRUCTLIT:
+		break
+	}
+
+	var value *Node
+	for nl := n.List; nl != nil; nl = nl.Next {
+		value = nl.N.Right
+		mode |= getdyn(value, 0)
+		if mode == MODEDYNAM|MODECONST {
+			break
+		}
+	}
+
+	return mode
+}
+
+func structlit(ctxt int, pass int, n *Node, var_ *Node, init **NodeList) {
+	var r *Node
+	var a *Node
+	var index *Node
+	var value *Node
+
+	for nl := n.List; nl != nil; nl = nl.Next {
+		r = nl.N
+		if r.Op != OKEY {
+			Fatal("structlit: rhs not OKEY: %v", r)
+		}
+		index = r.Left
+		value = r.Right
+
+		switch value.Op {
+		case OARRAYLIT:
+			if value.Type.Bound < 0 {
+				if pass == 1 && ctxt != 0 {
+					a = Nod(ODOT, var_, newname(index.Sym))
+					slicelit(ctxt, value, a, init)
+				} else if pass == 2 && ctxt == 0 {
+					a = Nod(ODOT, var_, newname(index.Sym))
+					slicelit(ctxt, value, a, init)
+				} else if pass == 3 {
+					break
+				}
+				continue
+			}
+
+			a = Nod(ODOT, var_, newname(index.Sym))
+			arraylit(ctxt, pass, value, a, init)
+			continue
+
+		case OSTRUCTLIT:
+			a = Nod(ODOT, var_, newname(index.Sym))
+			structlit(ctxt, pass, value, a, init)
+			continue
+		}
+
+		if isliteral(value) {
+			if pass == 2 {
+				continue
+			}
+		} else if pass == 1 {
+			continue
+		}
+
+		// build list of var.field = expr
+		setlineno(value)
+		a = Nod(ODOT, var_, newname(index.Sym))
+
+		a = Nod(OAS, a, value)
+		typecheck(&a, Etop)
+		if pass == 1 {
+			walkexpr(&a, init) // add any assignments in r to top
+			if a.Op != OAS {
+				Fatal("structlit: not as")
+			}
+			a.Dodata = 2
+		} else {
+			orderstmtinplace(&a)
+			walkstmt(&a)
+		}
+
+		*init = list(*init, a)
+	}
+}
+
+func arraylit(ctxt int, pass int, n *Node, var_ *Node, init **NodeList) {
+	var r *Node
+	var a *Node
+	var index *Node
+	var value *Node
+
+	for l := n.List; l != nil; l = l.Next {
+		r = l.N
+		if r.Op != OKEY {
+			Fatal("arraylit: rhs not OKEY: %v", r)
+		}
+		index = r.Left
+		value = r.Right
+
+		switch value.Op {
+		case OARRAYLIT:
+			if value.Type.Bound < 0 {
+				if pass == 1 && ctxt != 0 {
+					a = Nod(OINDEX, var_, index)
+					slicelit(ctxt, value, a, init)
+				} else if pass == 2 && ctxt == 0 {
+					a = Nod(OINDEX, var_, index)
+					slicelit(ctxt, value, a, init)
+				} else if pass == 3 {
+					break
+				}
+				continue
+			}
+
+			a = Nod(OINDEX, var_, index)
+			arraylit(ctxt, pass, value, a, init)
+			continue
+
+		case OSTRUCTLIT:
+			a = Nod(OINDEX, var_, index)
+			structlit(ctxt, pass, value, a, init)
+			continue
+		}
+
+		if isliteral(index) && isliteral(value) {
+			if pass == 2 {
+				continue
+			}
+		} else if pass == 1 {
+			continue
+		}
+
+		// build list of var[index] = value
+		setlineno(value)
+		a = Nod(OINDEX, var_, index)
+
+		a = Nod(OAS, a, value)
+		typecheck(&a, Etop)
+		if pass == 1 {
+			walkexpr(&a, init)
+			if a.Op != OAS {
+				Fatal("arraylit: not as")
+			}
+			a.Dodata = 2
+		} else {
+			orderstmtinplace(&a)
+			walkstmt(&a)
+		}
+
+		*init = list(*init, a)
+	}
+}
+
+func slicelit(ctxt int, n *Node, var_ *Node, init **NodeList) {
+	// make an array type
+	t := shallow(n.Type)
+
+	t.Bound = Mpgetfix(n.Right.Val().U.(*Mpint))
+	t.Width = 0
+	t.Sym = nil
+	t.Haspointers = 0
+	dowidth(t)
+
+	if ctxt != 0 {
+		// put everything into static array
+		vstat := staticname(t, ctxt)
+
+		arraylit(ctxt, 1, n, vstat, init)
+		arraylit(ctxt, 2, n, vstat, init)
+
+		// copy static to slice
+		a := Nod(OSLICE, vstat, Nod(OKEY, nil, nil))
+
+		a = Nod(OAS, var_, a)
+		typecheck(&a, Etop)
+		a.Dodata = 2
+		*init = list(*init, a)
+		return
+	}
+
+	// recipe for var = []t{...}
+	// 1. make a static array
+	//	var vstat [...]t
+	// 2. assign (data statements) the constant part
+	//	vstat = constpart{}
+	// 3. make an auto pointer to array and allocate heap to it
+	//	var vauto *[...]t = new([...]t)
+	// 4. copy the static array to the auto array
+	//	*vauto = vstat
+	// 5. assign slice of allocated heap to var
+	//	var = [0:]*auto
+	// 6. for each dynamic part assign to the slice
+	//	var[i] = dynamic part
+	//
+	// an optimization is done if there is no constant part
+	//	3. var vauto *[...]t = new([...]t)
+	//	5. var = [0:]*auto
+	//	6. var[i] = dynamic part
+
+	// if the literal contains constants,
+	// make static initialized array (1),(2)
+	var vstat *Node
+
+	mode := getdyn(n, 1)
+	if mode&MODECONST != 0 {
+		vstat = staticname(t, ctxt)
+		arraylit(ctxt, 1, n, vstat, init)
+	}
+
+	// make new auto *array (3 declare)
+	vauto := temp(Ptrto(t))
+
+	// set auto to point at new temp or heap (3 assign)
+	var a *Node
+	if x := prealloc[n]; x != nil {
+		// temp allocated during order.c for dddarg
+		x.Type = t
+
+		if vstat == nil {
+			a = Nod(OAS, x, nil)
+			typecheck(&a, Etop)
+			*init = list(*init, a) // zero new temp
+		}
+
+		a = Nod(OADDR, x, nil)
+	} else if n.Esc == EscNone {
+		a = temp(t)
+		if vstat == nil {
+			a = Nod(OAS, temp(t), nil)
+			typecheck(&a, Etop)
+			*init = list(*init, a) // zero new temp
+			a = a.Left
+		}
+
+		a = Nod(OADDR, a, nil)
+	} else {
+		a = Nod(ONEW, nil, nil)
+		a.List = list1(typenod(t))
+	}
+
+	a = Nod(OAS, vauto, a)
+	typecheck(&a, Etop)
+	walkexpr(&a, init)
+	*init = list(*init, a)
+
+	if vstat != nil {
+		// copy static to heap (4)
+		a = Nod(OIND, vauto, nil)
+
+		a = Nod(OAS, a, vstat)
+		typecheck(&a, Etop)
+		walkexpr(&a, init)
+		*init = list(*init, a)
+	}
+
+	// make slice out of heap (5)
+	a = Nod(OAS, var_, Nod(OSLICE, vauto, Nod(OKEY, nil, nil)))
+
+	typecheck(&a, Etop)
+	orderstmtinplace(&a)
+	walkstmt(&a)
+	*init = list(*init, a)
+
+	// put dynamics into slice (6)
+	var value *Node
+	var r *Node
+	var index *Node
+	for l := n.List; l != nil; l = l.Next {
+		r = l.N
+		if r.Op != OKEY {
+			Fatal("slicelit: rhs not OKEY: %v", r)
+		}
+		index = r.Left
+		value = r.Right
+		a = Nod(OINDEX, var_, index)
+		a.Bounded = true
+
+		// TODO need to check bounds?
+
+		switch value.Op {
+		case OARRAYLIT:
+			if value.Type.Bound < 0 {
+				break
+			}
+			arraylit(ctxt, 2, value, a, init)
+			continue
+
+		case OSTRUCTLIT:
+			structlit(ctxt, 2, value, a, init)
+			continue
+		}
+
+		if isliteral(index) && isliteral(value) {
+			continue
+		}
+
+		// build list of var[c] = expr
+		setlineno(value)
+		a = Nod(OAS, a, value)
+
+		typecheck(&a, Etop)
+		orderstmtinplace(&a)
+		walkstmt(&a)
+		*init = list(*init, a)
+	}
+}
+
+func maplit(ctxt int, n *Node, var_ *Node, init **NodeList) {
+	var r *Node
+	var index *Node
+	var value *Node
+
+	ctxt = 0
+
+	// make the map var
+	nerr := nerrors
+
+	a := Nod(OMAKE, nil, nil)
+	a.List = list1(typenod(n.Type))
+	litas(var_, a, init)
+
+	// count the initializers
+	b := int64(0)
+
+	for l := n.List; l != nil; l = l.Next {
+		r = l.N
+
+		if r.Op != OKEY {
+			Fatal("maplit: rhs not OKEY: %v", r)
+		}
+		index = r.Left
+		value = r.Right
+
+		if isliteral(index) && isliteral(value) {
+			b++
+		}
+	}
+
+	if b != 0 {
+		// build type [count]struct { a Tindex, b Tvalue }
+		t := n.Type
+
+		tk := t.Down
+		tv := t.Type
+
+		symb := Lookup("b")
+		t = typ(TFIELD)
+		t.Type = tv
+		t.Sym = symb
+
+		syma := Lookup("a")
+		t1 := t
+		t = typ(TFIELD)
+		t.Type = tk
+		t.Sym = syma
+		t.Down = t1
+
+		t1 = t
+		t = typ(TSTRUCT)
+		t.Type = t1
+
+		t1 = t
+		t = typ(TARRAY)
+		t.Bound = b
+		t.Type = t1
+
+		dowidth(t)
+
+		// make and initialize static array
+		vstat := staticname(t, ctxt)
+
+		b := int64(0)
+		var index *Node
+		var r *Node
+		var value *Node
+		for l := n.List; l != nil; l = l.Next {
+			r = l.N
+
+			if r.Op != OKEY {
+				Fatal("maplit: rhs not OKEY: %v", r)
+			}
+			index = r.Left
+			value = r.Right
+
+			if isliteral(index) && isliteral(value) {
+				// build vstat[b].a = key;
+				setlineno(index)
+				a = Nodintconst(b)
+
+				a = Nod(OINDEX, vstat, a)
+				a = Nod(ODOT, a, newname(syma))
+				a = Nod(OAS, a, index)
+				typecheck(&a, Etop)
+				walkexpr(&a, init)
+				a.Dodata = 2
+				*init = list(*init, a)
+
+				// build vstat[b].b = value;
+				setlineno(value)
+				a = Nodintconst(b)
+
+				a = Nod(OINDEX, vstat, a)
+				a = Nod(ODOT, a, newname(symb))
+				a = Nod(OAS, a, value)
+				typecheck(&a, Etop)
+				walkexpr(&a, init)
+				a.Dodata = 2
+				*init = list(*init, a)
+
+				b++
+			}
+		}
+
+		// loop adding structure elements to map
+		// for i = 0; i < len(vstat); i++ {
+		//	map[vstat[i].a] = vstat[i].b
+		// }
+		index = temp(Types[TINT])
+
+		a = Nod(OINDEX, vstat, index)
+		a.Bounded = true
+		a = Nod(ODOT, a, newname(symb))
+
+		r = Nod(OINDEX, vstat, index)
+		r.Bounded = true
+		r = Nod(ODOT, r, newname(syma))
+		r = Nod(OINDEX, var_, r)
+
+		r = Nod(OAS, r, a)
+
+		a = Nod(OFOR, nil, nil)
+		a.Nbody = list1(r)
+
+		a.Ninit = list1(Nod(OAS, index, Nodintconst(0)))
+		a.Left = Nod(OLT, index, Nodintconst(t.Bound))
+		a.Right = Nod(OAS, index, Nod(OADD, index, Nodintconst(1)))
+
+		typecheck(&a, Etop)
+		walkstmt(&a)
+		*init = list(*init, a)
+	}
+
+	// put in dynamic entries one-at-a-time
+	var key *Node
+
+	var val *Node
+	for l := n.List; l != nil; l = l.Next {
+		r = l.N
+
+		if r.Op != OKEY {
+			Fatal("maplit: rhs not OKEY: %v", r)
+		}
+		index = r.Left
+		value = r.Right
+
+		if isliteral(index) && isliteral(value) {
+			continue
+		}
+
+		// build list of var[c] = expr.
+		// use temporary so that mapassign1 can have addressable key, val.
+		if key == nil {
+			key = temp(var_.Type.Down)
+			val = temp(var_.Type.Type)
+		}
+
+		setlineno(r.Left)
+		a = Nod(OAS, key, r.Left)
+		typecheck(&a, Etop)
+		walkstmt(&a)
+		*init = list(*init, a)
+		setlineno(r.Right)
+		a = Nod(OAS, val, r.Right)
+		typecheck(&a, Etop)
+		walkstmt(&a)
+		*init = list(*init, a)
+
+		setlineno(val)
+		a = Nod(OAS, Nod(OINDEX, var_, key), val)
+		typecheck(&a, Etop)
+		walkstmt(&a)
+		*init = list(*init, a)
+
+		if nerr != nerrors {
+			break
+		}
+	}
+
+	if key != nil {
+		a = Nod(OVARKILL, key, nil)
+		typecheck(&a, Etop)
+		*init = list(*init, a)
+		a = Nod(OVARKILL, val, nil)
+		typecheck(&a, Etop)
+		*init = list(*init, a)
+	}
+}
+
+func anylit(ctxt int, n *Node, var_ *Node, init **NodeList) {
+	t := n.Type
+	switch n.Op {
+	default:
+		Fatal("anylit: not lit")
+
+	case OPTRLIT:
+		if !Isptr[t.Etype] {
+			Fatal("anylit: not ptr")
+		}
+
+		var r *Node
+		if n.Right != nil {
+			r = Nod(OADDR, n.Right, nil)
+			typecheck(&r, Erv)
+		} else {
+			r = Nod(ONEW, nil, nil)
+			r.Typecheck = 1
+			r.Type = t
+			r.Esc = n.Esc
+		}
+
+		walkexpr(&r, init)
+		a := Nod(OAS, var_, r)
+
+		typecheck(&a, Etop)
+		*init = list(*init, a)
+
+		var_ = Nod(OIND, var_, nil)
+		typecheck(&var_, Erv|Easgn)
+		anylit(ctxt, n.Left, var_, init)
+
+	case OSTRUCTLIT:
+		if t.Etype != TSTRUCT {
+			Fatal("anylit: not struct")
+		}
+
+		if simplename(var_) && count(n.List) > 4 {
+			if ctxt == 0 {
+				// lay out static data
+				vstat := staticname(t, ctxt)
+
+				structlit(ctxt, 1, n, vstat, init)
+
+				// copy static to var
+				a := Nod(OAS, var_, vstat)
+
+				typecheck(&a, Etop)
+				walkexpr(&a, init)
+				*init = list(*init, a)
+
+				// add expressions to automatic
+				structlit(ctxt, 2, n, var_, init)
+
+				break
+			}
+
+			structlit(ctxt, 1, n, var_, init)
+			structlit(ctxt, 2, n, var_, init)
+			break
+		}
+
+		// initialize of not completely specified
+		if simplename(var_) || count(n.List) < structcount(t) {
+			a := Nod(OAS, var_, nil)
+			typecheck(&a, Etop)
+			walkexpr(&a, init)
+			*init = list(*init, a)
+		}
+
+		structlit(ctxt, 3, n, var_, init)
+
+	case OARRAYLIT:
+		if t.Etype != TARRAY {
+			Fatal("anylit: not array")
+		}
+		if t.Bound < 0 {
+			slicelit(ctxt, n, var_, init)
+			break
+		}
+
+		if simplename(var_) && count(n.List) > 4 {
+			if ctxt == 0 {
+				// lay out static data
+				vstat := staticname(t, ctxt)
+
+				arraylit(1, 1, n, vstat, init)
+
+				// copy static to automatic
+				a := Nod(OAS, var_, vstat)
+
+				typecheck(&a, Etop)
+				walkexpr(&a, init)
+				*init = list(*init, a)
+
+				// add expressions to automatic
+				arraylit(ctxt, 2, n, var_, init)
+
+				break
+			}
+
+			arraylit(ctxt, 1, n, var_, init)
+			arraylit(ctxt, 2, n, var_, init)
+			break
+		}
+
+		// initialize of not completely specified
+		if simplename(var_) || int64(count(n.List)) < t.Bound {
+			a := Nod(OAS, var_, nil)
+			typecheck(&a, Etop)
+			walkexpr(&a, init)
+			*init = list(*init, a)
+		}
+
+		arraylit(ctxt, 3, n, var_, init)
+
+	case OMAPLIT:
+		if t.Etype != TMAP {
+			Fatal("anylit: not map")
+		}
+		maplit(ctxt, n, var_, init)
+	}
+}
+
+func oaslit(n *Node, init **NodeList) bool {
+	if n.Left == nil || n.Right == nil {
+		// not a special composit literal assignment
+		return false
+	}
+	if n.Left.Type == nil || n.Right.Type == nil {
+		// not a special composit literal assignment
+		return false
+	}
+	if !simplename(n.Left) {
+		// not a special composit literal assignment
+		return false
+	}
+	if !Eqtype(n.Left.Type, n.Right.Type) {
+		// 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
+
+	//	if(n->dodata == 1)
+	//		ctxt = 1;
+
+	switch n.Right.Op {
+	default:
+		// not a special composit literal assignment
+		return false
+
+	case OSTRUCTLIT, OARRAYLIT, OMAPLIT:
+		if vmatch1(n.Left, n.Right) {
+			// not a special composit literal assignment
+			return false
+		}
+		anylit(ctxt, n.Right, n.Left, init)
+	}
+
+	n.Op = OEMPTY
+	n.Right = nil
+	return true
+}
+
+func getlit(lit *Node) int {
+	if Smallintconst(lit) {
+		return int(Mpgetfix(lit.Val().U.(*Mpint)))
+	}
+	return -1
+}
+
+func stataddr(nam *Node, n *Node) bool {
+	if n == nil {
+		return false
+	}
+
+	switch n.Op {
+	case ONAME:
+		*nam = *n
+		return n.Addable
+
+	case ODOT:
+		if !stataddr(nam, n.Left) {
+			break
+		}
+		nam.Xoffset += n.Xoffset
+		nam.Type = n.Type
+		return true
+
+	case OINDEX:
+		if n.Left.Type.Bound < 0 {
+			break
+		}
+		if !stataddr(nam, n.Left) {
+			break
+		}
+		l := getlit(n.Right)
+		if l < 0 {
+			break
+		}
+
+		// Check for overflow.
+		if n.Type.Width != 0 && Thearch.MAXWIDTH/n.Type.Width <= int64(l) {
+			break
+		}
+		nam.Xoffset += int64(l) * n.Type.Width
+		nam.Type = n.Type
+		return true
+	}
+
+	return false
+}
+
+func initplan(n *Node) {
+	if initplans[n] != nil {
+		return
+	}
+	p := new(InitPlan)
+	initplans[n] = p
+	switch n.Op {
+	default:
+		Fatal("initplan")
+
+	case OARRAYLIT:
+		var a *Node
+		for l := n.List; l != nil; l = l.Next {
+			a = l.N
+			if a.Op != OKEY || !Smallintconst(a.Left) {
+				Fatal("initplan arraylit")
+			}
+			addvalue(p, n.Type.Type.Width*Mpgetfix(a.Left.Val().U.(*Mpint)), nil, a.Right)
+		}
+
+	case OSTRUCTLIT:
+		var a *Node
+		for l := n.List; l != nil; l = l.Next {
+			a = l.N
+			if a.Op != OKEY || a.Left.Type == nil {
+				Fatal("initplan structlit")
+			}
+			addvalue(p, a.Left.Type.Width, nil, a.Right)
+		}
+
+	case OMAPLIT:
+		var a *Node
+		for l := n.List; l != nil; l = l.Next {
+			a = l.N
+			if a.Op != OKEY {
+				Fatal("initplan maplit")
+			}
+			addvalue(p, -1, a.Left, a.Right)
+		}
+	}
+}
+
+func addvalue(p *InitPlan, xoffset int64, key *Node, n *Node) {
+	// special case: zero can be dropped entirely
+	if iszero(n) {
+		p.Zero += n.Type.Width
+		return
+	}
+
+	// special case: inline struct and array (not slice) literals
+	if isvaluelit(n) {
+		initplan(n)
+		q := initplans[n]
+		var e *InitEntry
+		for i := 0; i < len(q.E); i++ {
+			e = entry(p)
+			*e = q.E[i]
+			e.Xoffset += xoffset
+		}
+
+		return
+	}
+
+	// add to plan
+	if n.Op == OLITERAL {
+		p.Lit += n.Type.Width
+	} else {
+		p.Expr += n.Type.Width
+	}
+
+	e := entry(p)
+	e.Xoffset = xoffset
+	e.Expr = n
+}
+
+func iszero(n *Node) bool {
+	switch n.Op {
+	case OLITERAL:
+		switch n.Val().Ctype() {
+		default:
+			Dump("unexpected literal", n)
+			Fatal("iszero")
+
+		case CTNIL:
+			return true
+
+		case CTSTR:
+			return n.Val().U.(string) == ""
+
+		case CTBOOL:
+			return !n.Val().U.(bool)
+
+		case CTINT, CTRUNE:
+			return mpcmpfixc(n.Val().U.(*Mpint), 0) == 0
+
+		case CTFLT:
+			return mpcmpfltc(n.Val().U.(*Mpflt), 0) == 0
+
+		case CTCPLX:
+			return mpcmpfltc(&n.Val().U.(*Mpcplx).Real, 0) == 0 && mpcmpfltc(&n.Val().U.(*Mpcplx).Imag, 0) == 0
+		}
+
+	case OARRAYLIT:
+		if Isslice(n.Type) {
+			break
+		}
+		fallthrough
+
+		// fall through
+	case OSTRUCTLIT:
+		for l := n.List; l != nil; l = l.Next {
+			if !iszero(l.N.Right) {
+				return false
+			}
+		}
+		return true
+	}
+
+	return false
+}
+
+func isvaluelit(n *Node) bool {
+	return (n.Op == OARRAYLIT && Isfixedarray(n.Type)) || n.Op == OSTRUCTLIT
+}
+
+func entry(p *InitPlan) *InitEntry {
+	p.E = append(p.E, InitEntry{})
+	return &p.E[len(p.E)-1]
+}
+
+func gen_as_init(n *Node) bool {
+	var nr *Node
+	var nl *Node
+	var nam Node
+
+	if n.Dodata == 0 {
+		goto no
+	}
+
+	nr = n.Right
+	nl = n.Left
+	if nr == nil {
+		var nam Node
+		if !stataddr(&nam, nl) {
+			goto no
+		}
+		if nam.Class != PEXTERN {
+			goto no
+		}
+		return true
+	}
+
+	if nr.Type == nil || !Eqtype(nl.Type, nr.Type) {
+		goto no
+	}
+
+	if !stataddr(&nam, nl) {
+		goto no
+	}
+
+	if nam.Class != PEXTERN {
+		goto no
+	}
+
+	switch nr.Op {
+	default:
+		goto no
+
+	case OCONVNOP:
+		nr = nr.Left
+		if nr == nil || nr.Op != OSLICEARR {
+			goto no
+		}
+		fallthrough
+
+		// fall through
+	case OSLICEARR:
+		if nr.Right.Op == OKEY && nr.Right.Left == nil && nr.Right.Right == nil {
+			nr = nr.Left
+			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
+
+	case OLITERAL:
+		break
+	}
+
+	switch nr.Type.Etype {
+	default:
+		goto no
+
+	case TBOOL,
+		TINT8,
+		TUINT8,
+		TINT16,
+		TUINT16,
+		TINT32,
+		TUINT32,
+		TINT64,
+		TUINT64,
+		TINT,
+		TUINT,
+		TUINTPTR,
+		TPTR32,
+		TPTR64,
+		TFLOAT32,
+		TFLOAT64:
+		gdata(&nam, nr, int(nr.Type.Width))
+
+	case TCOMPLEX64, TCOMPLEX128:
+		gdatacomplex(&nam, nr.Val().U.(*Mpcplx))
+
+	case TSTRING:
+		gdatastring(&nam, nr.Val().U.(string))
+	}
+
+	return true
+
+no:
+	if n.Dodata == 2 {
+		Dump("\ngen_as_init", n)
+		Fatal("gen_as_init couldnt make data statement")
+	}
+
+	return false
+}
diff --git a/src/cmd/compile/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go
new file mode 100644
index 0000000..866d8e1
--- /dev/null
+++ b/src/cmd/compile/internal/gc/subr.go
@@ -0,0 +1,3589 @@
+// 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 (
+	"bytes"
+	"cmd/internal/obj"
+	"crypto/md5"
+	"encoding/binary"
+	"fmt"
+	"os"
+	"sort"
+	"strings"
+	"unicode"
+	"unicode/utf8"
+)
+
+type Error struct {
+	lineno int
+	seq    int
+	msg    string
+}
+
+var errors []Error
+
+func errorexit() {
+	Flusherrors()
+	if outfile != "" {
+		os.Remove(outfile)
+	}
+	os.Exit(2)
+}
+
+func parserline() int {
+	if parsing && theparser.Lookahead() > 0 {
+		// parser has one symbol lookahead
+		return int(prevlineno)
+	}
+	return int(lineno)
+}
+
+func adderrorname(n *Node) {
+	if n.Op != ODOT {
+		return
+	}
+	old := fmt.Sprintf("%v: undefined: %v\n", n.Line(), n.Left)
+	if len(errors) > 0 && int32(errors[len(errors)-1].lineno) == n.Lineno && errors[len(errors)-1].msg == old {
+		errors[len(errors)-1].msg = fmt.Sprintf("%v: undefined: %v in %v\n", n.Line(), n.Left, n)
+	}
+}
+
+func adderr(line int, format string, args ...interface{}) {
+	errors = append(errors, Error{
+		seq:    len(errors),
+		lineno: line,
+		msg:    fmt.Sprintf("%v: %s\n", Ctxt.Line(line), fmt.Sprintf(format, args...)),
+	})
+}
+
+type errcmp []Error
+
+func (x errcmp) Len() int {
+	return len(x)
+}
+
+func (x errcmp) Swap(i, j int) {
+	x[i], x[j] = x[j], x[i]
+}
+
+func (x errcmp) Less(i, j int) bool {
+	a := &x[i]
+	b := &x[j]
+	if a.lineno != b.lineno {
+		return a.lineno-b.lineno < 0
+	}
+	if a.seq != b.seq {
+		return a.seq-b.seq < 0
+	}
+	return stringsCompare(a.msg, b.msg) < 0
+}
+
+func Flusherrors() {
+	bstdout.Flush()
+	if len(errors) == 0 {
+		return
+	}
+	sort.Sort(errcmp(errors[:len(errors)]))
+	for i := 0; i < len(errors); i++ {
+		if i == 0 || errors[i].msg != errors[i-1].msg {
+			fmt.Printf("%s", errors[i].msg)
+		}
+	}
+	errors = errors[:0]
+}
+
+func hcrash() {
+	if Debug['h'] != 0 {
+		Flusherrors()
+		if outfile != "" {
+			os.Remove(outfile)
+		}
+		var x *int
+		*x = 0
+	}
+}
+
+func yyerrorl(line int, format string, args ...interface{}) {
+	adderr(line, format, args...)
+
+	hcrash()
+	nerrors++
+	if nsavederrors+nerrors >= 10 && Debug['e'] == 0 {
+		Flusherrors()
+		fmt.Printf("%v: too many errors\n", Ctxt.Line(line))
+		errorexit()
+	}
+}
+
+var yyerror_lastsyntax int
+
+func Yyerror(format string, args ...interface{}) {
+	msg := fmt.Sprintf(format, args...)
+	if strings.HasPrefix(msg, "syntax error") {
+		nsyntaxerrors++
+
+		// An unexpected EOF caused a syntax error. Use the previous
+		// line number since getc generated a fake newline character.
+		if curio.eofnl != 0 {
+			lexlineno = prevlineno
+		}
+
+		// only one syntax error per line
+		if int32(yyerror_lastsyntax) == lexlineno {
+			return
+		}
+		yyerror_lastsyntax = int(lexlineno)
+
+		// plain "syntax error" gets "near foo" added
+		if msg == "syntax error" {
+			yyerrorl(int(lexlineno), "syntax error near %s", lexbuf.String())
+			return
+		}
+
+		// The grammar has { and LBRACE but both show up as {.
+		// Rewrite syntax error referring to "{ or {" to say just "{".
+		// The grammar has ? and @ but only for reading imports.
+		// Silence them in ordinary errors.
+		msg = strings.Replace(msg, "{ or {", "{", -1)
+		msg = strings.Replace(msg, " or ?", "", -1)
+		msg = strings.Replace(msg, " or @", "", -1)
+
+		msg = strings.Replace(msg, "LLITERAL", litbuf, -1)
+
+		yyerrorl(int(lexlineno), "%s", msg)
+		return
+	}
+
+	adderr(parserline(), "%s", msg)
+
+	hcrash()
+	nerrors++
+	if nsavederrors+nerrors >= 10 && Debug['e'] == 0 {
+		Flusherrors()
+		fmt.Printf("%v: too many errors\n", Ctxt.Line(parserline()))
+		errorexit()
+	}
+}
+
+func Warn(fmt_ string, args ...interface{}) {
+	adderr(parserline(), fmt_, args...)
+
+	hcrash()
+}
+
+func Warnl(line int, fmt_ string, args ...interface{}) {
+	adderr(line, fmt_, args...)
+	if Debug['m'] != 0 {
+		Flusherrors()
+	}
+}
+
+func Fatal(fmt_ string, args ...interface{}) {
+	Flusherrors()
+
+	fmt.Printf("%v: internal compiler error: ", Ctxt.Line(int(lineno)))
+	fmt.Printf(fmt_, args...)
+	fmt.Printf("\n")
+
+	// If this is a released compiler version, ask for a bug report.
+	if strings.HasPrefix(obj.Getgoversion(), "release") {
+		fmt.Printf("\n")
+		fmt.Printf("Please file a bug report including a short program that triggers the error.\n")
+		fmt.Printf("https://golang.org/issue/new\n")
+	}
+
+	hcrash()
+	errorexit()
+}
+
+func linehistpragma(file string) {
+	if Debug['i'] != 0 {
+		fmt.Printf("pragma %s at line %v\n", file, Ctxt.Line(int(lexlineno)))
+	}
+	Ctxt.AddImport(file)
+}
+
+func linehistpush(file string) {
+	if Debug['i'] != 0 {
+		fmt.Printf("import %s at line %v\n", file, Ctxt.Line(int(lexlineno)))
+	}
+	Ctxt.LineHist.Push(int(lexlineno), file)
+}
+
+func linehistpop() {
+	if Debug['i'] != 0 {
+		fmt.Printf("end of import at line %v\n", Ctxt.Line(int(lexlineno)))
+	}
+	Ctxt.LineHist.Pop(int(lexlineno))
+}
+
+func linehistupdate(file string, off int) {
+	if Debug['i'] != 0 {
+		fmt.Printf("line %s at line %v\n", file, Ctxt.Line(int(lexlineno)))
+	}
+	Ctxt.LineHist.Update(int(lexlineno), file, off)
+}
+
+func setlineno(n *Node) int32 {
+	lno := lineno
+	if n != nil {
+		switch n.Op {
+		case ONAME, OTYPE, OPACK:
+			break
+
+		case OLITERAL:
+			if n.Sym != nil {
+				break
+			}
+			fallthrough
+
+		default:
+			lineno = n.Lineno
+			if lineno == 0 {
+				if Debug['K'] != 0 {
+					Warn("setlineno: line 0")
+				}
+				lineno = lno
+			}
+		}
+	}
+
+	return lno
+}
+
+func Lookup(name string) *Sym {
+	return localpkg.Lookup(name)
+}
+
+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 {
+	return pkg.Lookup(name)
+}
+
+func restrictlookup(name string, pkg *Pkg) *Sym {
+	if !exportname(name) && pkg != localpkg {
+		Yyerror("cannot refer to unexported name %s.%s", pkg.Name, name)
+	}
+	return Pkglookup(name, pkg)
+}
+
+// find all the exported symbols in package opkg
+// and make them available in the current package
+func importdot(opkg *Pkg, pack *Node) {
+	var s1 *Sym
+	var pkgerror string
+
+	n := 0
+	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
+		if s1.Def.Name == nil {
+			Dump("s1def", s1.Def)
+			Fatal("missing Name")
+		}
+		s1.Def.Name.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: %q", opkg.Path)
+	}
+}
+
+func gethunk() {
+	nh := int32(NHUNK)
+	if thunk >= 10*NHUNK {
+		nh = 10 * NHUNK
+	}
+	h := string(make([]byte, nh))
+	if h == "" {
+		Flusherrors()
+		Yyerror("out of memory")
+		errorexit()
+	}
+
+	hunk = h
+	nhunk = nh
+	thunk += nh
+}
+
+func Nod(op int, nleft *Node, nright *Node) *Node {
+	n := new(Node)
+	n.Op = uint8(op)
+	n.Left = nleft
+	n.Right = nright
+	n.Lineno = int32(parserline())
+	n.Xoffset = BADWIDTH
+	n.Orig = n
+	switch op {
+	case OCLOSURE, ODCLFUNC:
+		n.Func = new(Func)
+		n.Func.FCurfn = Curfn
+	case ONAME:
+		n.Name = new(Name)
+		n.Name.Param = new(Param)
+	case OLABEL, OPACK:
+		n.Name = new(Name)
+	case ODCLFIELD:
+		if nleft != nil {
+			n.Name = nleft.Name
+		} else {
+			n.Name = new(Name)
+			n.Name.Param = new(Param)
+		}
+	}
+	if n.Name != nil {
+		n.Name.Curfn = Curfn
+	}
+	return n
+}
+
+func saveorignode(n *Node) {
+	if n.Orig != nil {
+		return
+	}
+	norig := Nod(int(n.Op), nil, nil)
+	*norig = *n
+	n.Orig = norig
+}
+
+// ispaddedfield reports whether the given field
+// is followed by padding. For the case where t is
+// the last field, total gives the size of the enclosing struct.
+func ispaddedfield(t *Type, total int64) bool {
+	if t.Etype != TFIELD {
+		Fatal("ispaddedfield called non-field %v", t)
+	}
+	if t.Down == nil {
+		return t.Width+t.Type.Width != total
+	}
+	return t.Width+t.Type.Width != t.Down.Width
+}
+
+func algtype1(t *Type, bad **Type) int {
+	if bad != nil {
+		*bad = nil
+	}
+	if t.Broke != 0 {
+		return AMEM
+	}
+	if t.Noalg != 0 {
+		return ANOEQ
+	}
+
+	switch t.Etype {
+	// will be defined later.
+	case TANY, TFORW:
+		*bad = t
+
+		return -1
+
+	case TINT8,
+		TUINT8,
+		TINT16,
+		TUINT16,
+		TINT32,
+		TUINT32,
+		TINT64,
+		TUINT64,
+		TINT,
+		TUINT,
+		TUINTPTR,
+		TBOOL,
+		TPTR32,
+		TPTR64,
+		TCHAN,
+		TUNSAFEPTR:
+		return AMEM
+
+	case TFUNC, TMAP:
+		if bad != nil {
+			*bad = t
+		}
+		return ANOEQ
+
+	case TFLOAT32:
+		return AFLOAT32
+
+	case TFLOAT64:
+		return AFLOAT64
+
+	case TCOMPLEX64:
+		return ACPLX64
+
+	case TCOMPLEX128:
+		return ACPLX128
+
+	case TSTRING:
+		return ASTRING
+
+	case TINTER:
+		if isnilinter(t) {
+			return ANILINTER
+		}
+		return AINTER
+
+	case TARRAY:
+		if Isslice(t) {
+			if bad != nil {
+				*bad = t
+			}
+			return ANOEQ
+		}
+
+		a := algtype1(t.Type, bad)
+		if a == ANOEQ || a == AMEM {
+			if a == ANOEQ && bad != nil {
+				*bad = t
+			}
+			return a
+		}
+
+		return -1 // needs special compare
+
+	case TSTRUCT:
+		if t.Type != nil && t.Type.Down == nil && !isblanksym(t.Type.Sym) {
+			// One-field struct is same as that one field alone.
+			return algtype1(t.Type.Type, bad)
+		}
+
+		ret := AMEM
+		var a int
+		for t1 := t.Type; t1 != nil; t1 = t1.Down {
+			// All fields must be comparable.
+			a = algtype1(t1.Type, bad)
+
+			if a == ANOEQ {
+				return ANOEQ
+			}
+
+			// Blank fields, padded fields, fields with non-memory
+			// equality need special compare.
+			if a != AMEM || isblanksym(t1.Sym) || ispaddedfield(t1, t.Width) {
+				ret = -1
+				continue
+			}
+		}
+
+		return ret
+	}
+
+	Fatal("algtype1: unexpected type %v", t)
+	return 0
+}
+
+func algtype(t *Type) int {
+	a := algtype1(t, nil)
+	if a == AMEM || a == ANOEQ {
+		if Isslice(t) {
+			return ASLICE
+		}
+		switch t.Width {
+		case 0:
+			return a + AMEM0 - AMEM
+
+		case 1:
+			return a + AMEM8 - AMEM
+
+		case 2:
+			return a + AMEM16 - AMEM
+
+		case 4:
+			return a + AMEM32 - AMEM
+
+		case 8:
+			return a + AMEM64 - AMEM
+
+		case 16:
+			return a + AMEM128 - AMEM
+		}
+	}
+
+	return a
+}
+
+func maptype(key *Type, val *Type) *Type {
+	if key != nil {
+		var bad *Type
+		atype := algtype1(key, &bad)
+		var mtype int
+		if bad == nil {
+			mtype = int(key.Etype)
+		} else {
+			mtype = int(bad.Etype)
+		}
+		switch mtype {
+		default:
+			if atype == ANOEQ {
+				Yyerror("invalid map key type %v", key)
+			}
+
+			// will be resolved later.
+		case TANY:
+			break
+
+			// map[key] used during definition of key.
+		// postpone check until key is fully defined.
+		// if there are multiple uses of map[key]
+		// before key is fully defined, the error
+		// will only be printed for the first one.
+		// good enough.
+		case TFORW:
+			if key.Maplineno == 0 {
+				key.Maplineno = lineno
+			}
+		}
+	}
+
+	t := typ(TMAP)
+	t.Down = key
+	t.Type = val
+	return t
+}
+
+func typ(et int) *Type {
+	t := new(Type)
+	t.Etype = uint8(et)
+	t.Width = BADWIDTH
+	t.Lineno = int(lineno)
+	t.Orig = t
+	return t
+}
+
+type methcmp []*Type
+
+func (x methcmp) Len() int {
+	return len(x)
+}
+
+func (x methcmp) Swap(i, j int) {
+	x[i], x[j] = x[j], x[i]
+}
+
+func (x methcmp) Less(i, j int) bool {
+	a := x[i]
+	b := x[j]
+	if a.Sym == nil && b.Sym == nil {
+		return false
+	}
+	if a.Sym == nil {
+		return true
+	}
+	if b.Sym == nil {
+		return 1 < 0
+	}
+	k := stringsCompare(a.Sym.Name, b.Sym.Name)
+	if k != 0 {
+		return k < 0
+	}
+	if !exportname(a.Sym.Name) {
+		k := stringsCompare(a.Sym.Pkg.Path, b.Sym.Pkg.Path)
+		if k != 0 {
+			return k < 0
+		}
+	}
+
+	return false
+}
+
+func sortinter(t *Type) *Type {
+	if t.Type == nil || t.Type.Down == nil {
+		return t
+	}
+
+	i := 0
+	for f := t.Type; f != nil; f = f.Down {
+		i++
+	}
+	a := make([]*Type, i)
+	i = 0
+	var f *Type
+	for f = t.Type; f != nil; f = f.Down {
+		a[i] = f
+		i++
+	}
+	sort.Sort(methcmp(a[:i]))
+	for {
+		tmp11 := i
+		i--
+		if tmp11 <= 0 {
+			break
+		}
+		a[i].Down = f
+		f = a[i]
+	}
+
+	t.Type = f
+	return t
+}
+
+func Nodintconst(v int64) *Node {
+	c := Nod(OLITERAL, nil, nil)
+	c.Addable = true
+	c.SetVal(Val{new(Mpint)})
+	Mpmovecfix(c.Val().U.(*Mpint), v)
+	c.Type = Types[TIDEAL]
+	ullmancalc(c)
+	return c
+}
+
+func nodfltconst(v *Mpflt) *Node {
+	c := Nod(OLITERAL, nil, nil)
+	c.Addable = true
+	c.SetVal(Val{newMpflt()})
+	mpmovefltflt(c.Val().U.(*Mpflt), v)
+	c.Type = Types[TIDEAL]
+	ullmancalc(c)
+	return c
+}
+
+func Nodconst(n *Node, t *Type, v int64) {
+	*n = Node{}
+	n.Op = OLITERAL
+	n.Addable = true
+	ullmancalc(n)
+	n.SetVal(Val{new(Mpint)})
+	Mpmovecfix(n.Val().U.(*Mpint), v)
+	n.Type = t
+
+	if Isfloat[t.Etype] {
+		Fatal("nodconst: bad type %v", t)
+	}
+}
+
+func nodnil() *Node {
+	c := Nodintconst(0)
+	c.SetVal(Val{new(NilVal)})
+	c.Type = Types[TNIL]
+	return c
+}
+
+func Nodbool(b bool) *Node {
+	c := Nodintconst(0)
+	c.SetVal(Val{b})
+	c.Type = idealbool
+	return c
+}
+
+func aindex(b *Node, t *Type) *Type {
+	bound := int64(-1) // open bound
+	typecheck(&b, Erv)
+	if b != nil {
+		switch consttype(b) {
+		default:
+			Yyerror("array bound must be an integer expression")
+
+		case CTINT, CTRUNE:
+			bound = Mpgetfix(b.Val().U.(*Mpint))
+			if bound < 0 {
+				Yyerror("array bound must be non negative")
+			}
+		}
+	}
+
+	// fixed array
+	r := typ(TARRAY)
+
+	r.Type = t
+	r.Bound = bound
+	return r
+}
+
+// treecopy recursively copies n, with the exception of
+// ONAME, OLITERAL, OTYPE, and non-iota ONONAME leaves.
+// Copies of iota ONONAME nodes are assigned the current
+// value of iota_. If lineno != 0, it sets the line number
+// of newly allocated nodes to lineno.
+func treecopy(n *Node, lineno int32) *Node {
+	if n == nil {
+		return nil
+	}
+
+	var m *Node
+	switch n.Op {
+	default:
+		m = Nod(OXXX, nil, nil)
+		*m = *n
+		m.Orig = m
+		m.Left = treecopy(n.Left, lineno)
+		m.Right = treecopy(n.Right, lineno)
+		m.List = listtreecopy(n.List, lineno)
+		if lineno != 0 {
+			m.Lineno = lineno
+		}
+		if m.Name != nil && n.Op != ODCLFIELD {
+			Dump("treecopy", n)
+			Fatal("treecopy Name")
+		}
+
+	case ONONAME:
+		if n.Sym == Lookup("iota") {
+			// Not sure yet whether this is the real iota,
+			// but make a copy of the Node* just in case,
+			// so that all the copies of this const definition
+			// don't have the same iota value.
+			m = Nod(OXXX, nil, nil)
+			*m = *n
+			if lineno != 0 {
+				m.Lineno = lineno
+			}
+			m.Name = new(Name)
+			*m.Name = *n.Name
+			m.Name.Iota = iota_
+			break
+		}
+		fallthrough
+
+	case ONAME, OLITERAL, OTYPE:
+		m = n
+	}
+
+	return m
+}
+
+func isnil(n *Node) bool {
+	if n == nil {
+		return false
+	}
+	if n.Op != OLITERAL {
+		return false
+	}
+	if n.Val().Ctype() != CTNIL {
+		return false
+	}
+	return true
+}
+
+func isptrto(t *Type, et int) bool {
+	if t == nil {
+		return false
+	}
+	if !Isptr[t.Etype] {
+		return false
+	}
+	t = t.Type
+	if t == nil {
+		return false
+	}
+	if int(t.Etype) != et {
+		return false
+	}
+	return true
+}
+
+func Istype(t *Type, et int) bool {
+	return t != nil && int(t.Etype) == et
+}
+
+func Isfixedarray(t *Type) bool {
+	return t != nil && t.Etype == TARRAY && t.Bound >= 0
+}
+
+func Isslice(t *Type) bool {
+	return t != nil && t.Etype == TARRAY && t.Bound < 0
+}
+
+func isblank(n *Node) bool {
+	if n == nil {
+		return false
+	}
+	return isblanksym(n.Sym)
+}
+
+func isblanksym(s *Sym) bool {
+	return s != nil && s.Name == "_"
+}
+
+func Isinter(t *Type) bool {
+	return t != nil && t.Etype == TINTER
+}
+
+func isnilinter(t *Type) bool {
+	if !Isinter(t) {
+		return false
+	}
+	if t.Type != nil {
+		return false
+	}
+	return true
+}
+
+func isideal(t *Type) bool {
+	if t == nil {
+		return false
+	}
+	if t == idealstring || t == idealbool {
+		return true
+	}
+	switch t.Etype {
+	case TNIL, TIDEAL:
+		return true
+	}
+
+	return false
+}
+
+/*
+ * given receiver of type t (t == r or t == *r)
+ * return type to hang methods off (r).
+ */
+func methtype(t *Type, mustname int) *Type {
+	if t == nil {
+		return nil
+	}
+
+	// strip away pointer if it's there
+	if Isptr[t.Etype] {
+		if t.Sym != nil {
+			return nil
+		}
+		t = t.Type
+		if t == nil {
+			return nil
+		}
+	}
+
+	// need a type name
+	if t.Sym == nil && (mustname != 0 || t.Etype != TSTRUCT) {
+		return nil
+	}
+
+	// check types
+	if !issimple[t.Etype] {
+		switch t.Etype {
+		default:
+			return nil
+
+		case TSTRUCT,
+			TARRAY,
+			TMAP,
+			TCHAN,
+			TSTRING,
+			TFUNC:
+			break
+		}
+	}
+
+	return t
+}
+
+func cplxsubtype(et int) int {
+	switch et {
+	case TCOMPLEX64:
+		return TFLOAT32
+
+	case TCOMPLEX128:
+		return TFLOAT64
+	}
+
+	Fatal("cplxsubtype: %v\n", Econv(int(et), 0))
+	return 0
+}
+
+func eqnote(a, b *string) bool {
+	return a == b || a != nil && b != nil && *a == *b
+}
+
+type TypePairList struct {
+	t1   *Type
+	t2   *Type
+	next *TypePairList
+}
+
+func onlist(l *TypePairList, t1 *Type, t2 *Type) bool {
+	for ; l != nil; l = l.next {
+		if (l.t1 == t1 && l.t2 == t2) || (l.t1 == t2 && l.t2 == t1) {
+			return true
+		}
+	}
+	return false
+}
+
+// Return 1 if t1 and t2 are identical, following the spec rules.
+//
+// Any cyclic type must go through a named type, and if one is
+// named, it is only identical to the other if they are the same
+// pointer (t1 == t2), so there's no chance of chasing cycles
+// ad infinitum, so no need for a depth counter.
+func Eqtype(t1 *Type, t2 *Type) bool {
+	return eqtype1(t1, t2, nil)
+}
+
+func eqtype1(t1 *Type, t2 *Type, assumed_equal *TypePairList) bool {
+	if t1 == t2 {
+		return true
+	}
+	if t1 == nil || t2 == nil || t1.Etype != t2.Etype {
+		return false
+	}
+	if t1.Sym != nil || t2.Sym != nil {
+		// Special case: we keep byte and uint8 separate
+		// for error messages.  Treat them as equal.
+		switch t1.Etype {
+		case TUINT8:
+			if (t1 == Types[TUINT8] || t1 == bytetype) && (t2 == Types[TUINT8] || t2 == bytetype) {
+				return true
+			}
+
+		case TINT, TINT32:
+			if (t1 == Types[runetype.Etype] || t1 == runetype) && (t2 == Types[runetype.Etype] || t2 == runetype) {
+				return true
+			}
+		}
+
+		return false
+	}
+
+	if onlist(assumed_equal, t1, t2) {
+		return true
+	}
+	var l TypePairList
+	l.next = assumed_equal
+	l.t1 = t1
+	l.t2 = t2
+
+	switch t1.Etype {
+	case TINTER, TSTRUCT:
+		t1 = t1.Type
+		t2 = t2.Type
+		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", t1, t2)
+			}
+			if t1.Sym != t2.Sym || t1.Embedded != t2.Embedded || !eqtype1(t1.Type, t2.Type, &l) || !eqnote(t1.Note, t2.Note) {
+				return false
+			}
+		}
+
+		if t1 == nil && t2 == nil {
+			return true
+		}
+		return false
+
+		// Loop over structs: receiver, in, out.
+	case TFUNC:
+		t1 = t1.Type
+		t2 = t2.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", t1, t2)
+			}
+
+			// Loop over fields in structs, ignoring argument names.
+			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", ta, tb)
+				}
+				if ta.Isddd != tb.Isddd || !eqtype1(ta.Type, tb.Type, &l) {
+					return false
+				}
+			}
+
+			if ta != nil || tb != nil {
+				return false
+			}
+		}
+
+		if t1 == nil && t2 == nil {
+			return true
+		}
+		return false
+
+	case TARRAY:
+		if t1.Bound != t2.Bound {
+			return false
+		}
+
+	case TCHAN:
+		if t1.Chan != t2.Chan {
+			return false
+		}
+	}
+
+	if eqtype1(t1.Down, t2.Down, &l) && eqtype1(t1.Type, t2.Type, &l) {
+		return true
+	}
+	return false
+}
+
+// Are t1 and t2 equal struct types when field names are ignored?
+// For deciding whether the result struct from g can be copied
+// directly when compiling f(g()).
+func eqtypenoname(t1 *Type, t2 *Type) bool {
+	if t1 == nil || t2 == nil || t1.Etype != TSTRUCT || t2.Etype != TSTRUCT {
+		return false
+	}
+
+	t1 = t1.Type
+	t2 = t2.Type
+	for {
+		if !Eqtype(t1, t2) {
+			return false
+		}
+		if t1 == nil {
+			return true
+		}
+		t1 = t1.Down
+		t2 = t2.Down
+	}
+}
+
+// Is type src assignment compatible to type dst?
+// If so, return op code to use in conversion.
+// If not, return 0.
+func assignop(src *Type, dst *Type, why *string) int {
+	if why != nil {
+		*why = ""
+	}
+
+	// TODO(rsc,lvd): This behaves poorly in the presence of inlining.
+	// https://golang.org/issue/2795
+	if safemode != 0 && importpkg == nil && src != nil && src.Etype == TUNSAFEPTR {
+		Yyerror("cannot use unsafe.Pointer")
+		errorexit()
+	}
+
+	if src == dst {
+		return OCONVNOP
+	}
+	if src == nil || dst == nil || src.Etype == TFORW || dst.Etype == TFORW || src.Orig == nil || dst.Orig == nil {
+		return 0
+	}
+
+	// 1. src type is identical to dst.
+	if Eqtype(src, dst) {
+		return OCONVNOP
+	}
+
+	// 2. src and dst have identical underlying types
+	// and either src or dst is not a named type or
+	// both are empty interface types.
+	// For assignable but different non-empty interface types,
+	// we want to recompute the itab.
+	if Eqtype(src.Orig, dst.Orig) && (src.Sym == nil || dst.Sym == nil || isnilinter(src)) {
+		return OCONVNOP
+	}
+
+	// 3. dst is an interface type and src implements dst.
+	if dst.Etype == TINTER && src.Etype != TNIL {
+		var missing *Type
+		var ptr int
+		var have *Type
+		if implements(src, dst, &missing, &have, &ptr) {
+			return OCONVIFACE
+		}
+
+		// we'll have complained about this method anyway, suppress spurious messages.
+		if have != nil && have.Sym == missing.Sym && (have.Type.Broke != 0 || missing.Type.Broke != 0) {
+			return OCONVIFACE
+		}
+
+		if why != nil {
+			if isptrto(src, TINTER) {
+				*why = fmt.Sprintf(":\n\t%v is pointer to interface, not interface", src)
+			} else if have != nil && have.Sym == missing.Sym && have.Nointerface {
+				*why = fmt.Sprintf(":\n\t%v does not implement %v (%v method is marked 'nointerface')", src, dst, missing.Sym)
+			} else if have != nil && have.Sym == missing.Sym {
+				*why = fmt.Sprintf(":\n\t%v does not implement %v (wrong type for %v method)\n"+"\t\thave %v%v\n\t\twant %v%v", src, dst, missing.Sym, have.Sym, Tconv(have.Type, obj.FmtShort|obj.FmtByte), missing.Sym, Tconv(missing.Type, obj.FmtShort|obj.FmtByte))
+			} else if ptr != 0 {
+				*why = fmt.Sprintf(":\n\t%v does not implement %v (%v method has pointer receiver)", src, dst, missing.Sym)
+			} else if have != nil {
+				*why = fmt.Sprintf(":\n\t%v does not implement %v (missing %v method)\n"+"\t\thave %v%v\n\t\twant %v%v", src, dst, missing.Sym, have.Sym, Tconv(have.Type, obj.FmtShort|obj.FmtByte), missing.Sym, Tconv(missing.Type, obj.FmtShort|obj.FmtByte))
+			} else {
+				*why = fmt.Sprintf(":\n\t%v does not implement %v (missing %v method)", src, dst, missing.Sym)
+			}
+		}
+
+		return 0
+	}
+
+	if isptrto(dst, TINTER) {
+		if why != nil {
+			*why = fmt.Sprintf(":\n\t%v is pointer to interface, not interface", dst)
+		}
+		return 0
+	}
+
+	if src.Etype == TINTER && dst.Etype != TBLANK {
+		var have *Type
+		var ptr int
+		var missing *Type
+		if why != nil && implements(dst, src, &missing, &have, &ptr) {
+			*why = ": need type assertion"
+		}
+		return 0
+	}
+
+	// 4. src is a bidirectional channel value, dst is a channel type,
+	// src and dst have identical element types, and
+	// either src or dst is not a named type.
+	if src.Etype == TCHAN && src.Chan == Cboth && dst.Etype == TCHAN {
+		if Eqtype(src.Type, dst.Type) && (src.Sym == nil || dst.Sym == nil) {
+			return OCONVNOP
+		}
+	}
+
+	// 5. src is the predeclared identifier nil and dst is a nillable type.
+	if src.Etype == TNIL {
+		switch dst.Etype {
+		case TARRAY:
+			if dst.Bound != -100 { // not slice
+				break
+			}
+			fallthrough
+
+		case TPTR32,
+			TPTR64,
+			TFUNC,
+			TMAP,
+			TCHAN,
+			TINTER:
+			return OCONVNOP
+		}
+	}
+
+	// 6. rule about untyped constants - already converted by defaultlit.
+
+	// 7. Any typed value can be assigned to the blank identifier.
+	if dst.Etype == TBLANK {
+		return OCONVNOP
+	}
+
+	return 0
+}
+
+// Can we convert a value of type src to a value of type dst?
+// If so, return op code to use in conversion (maybe OCONVNOP).
+// If not, return 0.
+func convertop(src *Type, dst *Type, why *string) int {
+	if why != nil {
+		*why = ""
+	}
+
+	if src == dst {
+		return OCONVNOP
+	}
+	if src == nil || dst == nil {
+		return 0
+	}
+
+	// 1. src can be assigned to dst.
+	op := assignop(src, dst, why)
+	if op != 0 {
+		return op
+	}
+
+	// The rules for interfaces are no different in conversions
+	// than assignments.  If interfaces are involved, stop now
+	// with the good message from assignop.
+	// Otherwise clear the error.
+	if src.Etype == TINTER || dst.Etype == TINTER {
+		return 0
+	}
+	if why != nil {
+		*why = ""
+	}
+
+	// 2. src and dst have identical underlying types.
+	if Eqtype(src.Orig, dst.Orig) {
+		return OCONVNOP
+	}
+
+	// 3. src and dst are unnamed pointer types
+	// and their base types have identical underlying types.
+	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] || Isfloat[src.Etype]) && (Isint[dst.Etype] || Isfloat[dst.Etype]) {
+		if Simtype[src.Etype] == Simtype[dst.Etype] {
+			return OCONVNOP
+		}
+		return OCONV
+	}
+
+	// 5. src and dst are both complex types.
+	if Iscomplex[src.Etype] && Iscomplex[dst.Etype] {
+		if Simtype[src.Etype] == Simtype[dst.Etype] {
+			return OCONVNOP
+		}
+		return OCONV
+	}
+
+	// 6. src is an integer or has type []byte or []rune
+	// and dst is a string type.
+	if Isint[src.Etype] && dst.Etype == TSTRING {
+		return ORUNESTR
+	}
+
+	if Isslice(src) && dst.Etype == TSTRING {
+		if src.Type.Etype == bytetype.Etype {
+			return OARRAYBYTESTR
+		}
+		if src.Type.Etype == runetype.Etype {
+			return OARRAYRUNESTR
+		}
+	}
+
+	// 7. src is a string and dst is []byte or []rune.
+	// String to slice.
+	if src.Etype == TSTRING && Isslice(dst) {
+		if dst.Type.Etype == bytetype.Etype {
+			return OSTRARRAYBYTE
+		}
+		if dst.Type.Etype == runetype.Etype {
+			return OSTRARRAYRUNE
+		}
+	}
+
+	// 8. src is a pointer or uintptr and dst is unsafe.Pointer.
+	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] || dst.Etype == TUINTPTR) {
+		return OCONVNOP
+	}
+
+	return 0
+}
+
+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
+	}
+
+	if t.Etype == TBLANK && n.Type.Etype == TNIL {
+		Yyerror("use of untyped nil")
+	}
+
+	old := n
+	old.Diag++ // silence errors about n; we'll issue one below
+	defaultlit(&n, t)
+	old.Diag--
+	if t.Etype == TBLANK {
+		return n
+	}
+
+	// Convert ideal bool from comparison to plain bool
+	// if the next step is non-bool (like interface{}).
+	if n.Type == idealbool && t.Etype != TBOOL {
+		if n.Op == ONAME || n.Op == OLITERAL {
+			r := Nod(OCONVNOP, n, nil)
+			r.Type = Types[TBOOL]
+			r.Typecheck = 1
+			r.Implicit = true
+			n = r
+		}
+	}
+
+	if Eqtype(n.Type, t) {
+		return n
+	}
+
+	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), t, context(), why)
+		op = OCONV
+	}
+
+	r := Nod(op, n, nil)
+	r.Type = t
+	r.Typecheck = 1
+	r.Implicit = true
+	r.Orig = n.Orig
+	return r
+}
+
+// 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)
+	}
+	substAny(&n.Type, &types)
+	if len(types) > 0 {
+		Fatal("substArgTypes: too many argument types")
+	}
+}
+
+// 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
+		}
+		if t.Etype == TANY && t.Copyany != 0 {
+			if len(*types) == 0 {
+				Fatal("substArgTypes: not enough argument types")
+			}
+			*tp = (*types)[0]
+			*types = (*types)[1:]
+		}
+
+		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
+	}
+}
+
+/*
+ * Is this a 64-bit type?
+ */
+func Is64(t *Type) bool {
+	if t == nil {
+		return false
+	}
+	switch Simtype[t.Etype] {
+	case TINT64, TUINT64, TPTR64:
+		return true
+	}
+
+	return false
+}
+
+/*
+ * Is a conversion between t1 and t2 a no-op?
+ */
+func Noconv(t1 *Type, t2 *Type) bool {
+	e1 := int(Simtype[t1.Etype])
+	e2 := int(Simtype[t2.Etype])
+
+	switch e1 {
+	case TINT8, TUINT8:
+		return e2 == TINT8 || e2 == TUINT8
+
+	case TINT16, TUINT16:
+		return e2 == TINT16 || e2 == TUINT16
+
+	case TINT32, TUINT32, TPTR32:
+		return e2 == TINT32 || e2 == TUINT32 || e2 == TPTR32
+
+	case TINT64, TUINT64, TPTR64:
+		return e2 == TINT64 || e2 == TUINT64 || e2 == TPTR64
+
+	case TFLOAT32:
+		return e2 == TFLOAT32
+
+	case TFLOAT64:
+		return e2 == TFLOAT64
+	}
+
+	return false
+}
+
+func shallow(t *Type) *Type {
+	if t == nil {
+		return nil
+	}
+	nt := typ(0)
+	*nt = *t
+	if t.Orig == t {
+		nt.Orig = nt
+	}
+	return nt
+}
+
+func deep(t *Type) *Type {
+	if t == nil {
+		return nil
+	}
+
+	var nt *Type
+	switch t.Etype {
+	default:
+		nt = t // share from here down
+
+	case TANY:
+		nt = shallow(t)
+		nt.Copyany = 1
+
+	case TPTR32, TPTR64, TCHAN, TARRAY:
+		nt = shallow(t)
+		nt.Type = deep(t.Type)
+
+	case TMAP:
+		nt = shallow(t)
+		nt.Down = deep(t.Down)
+		nt.Type = deep(t.Type)
+
+	case TFUNC:
+		nt = shallow(t)
+		nt.Type = deep(t.Type)
+		nt.Type.Down = deep(t.Type.Down)
+		nt.Type.Down.Down = deep(t.Type.Down.Down)
+
+	case TSTRUCT:
+		nt = shallow(t)
+		nt.Type = shallow(t.Type)
+		xt := nt.Type
+
+		for t = t.Type; t != nil; t = t.Down {
+			xt.Type = deep(t.Type)
+			xt.Down = shallow(t.Down)
+			xt = xt.Down
+		}
+	}
+
+	return nt
+}
+
+func syslook(name string, copy int) *Node {
+	s := Pkglookup(name, Runtimepkg)
+	if s == nil || s.Def == nil {
+		Fatal("syslook: can't find runtime.%s", name)
+	}
+
+	if copy == 0 {
+		return s.Def
+	}
+
+	n := Nod(0, nil, nil)
+	*n = *s.Def
+	n.Type = deep(s.Def.Type)
+
+	return n
+}
+
+/*
+ * compute a hash value for type t.
+ * if t is a method type, ignore the receiver
+ * so that the hash can be used in interface checks.
+ * %T already contains
+ * all the necessary logic to generate a representation
+ * of the type that completely describes it.
+ * using smprint here avoids duplicating that code.
+ * using md5 here is overkill, but i got tired of
+ * accidental collisions making the runtime think
+ * two types are equal when they really aren't.
+ */
+func typehash(t *Type) uint32 {
+	var p string
+
+	if t.Thistuple != 0 {
+		// hide method receiver from Tpretty
+		t.Thistuple = 0
+
+		p = Tconv(t, obj.FmtLeft|obj.FmtUnsigned)
+		t.Thistuple = 1
+	} else {
+		p = Tconv(t, obj.FmtLeft|obj.FmtUnsigned)
+	}
+
+	//print("typehash: %s\n", p);
+	h := md5.Sum([]byte(p))
+	return binary.LittleEndian.Uint32(h[:4])
+}
+
+var initPtrtoDone bool
+
+var (
+	ptrToUint8  *Type
+	ptrToAny    *Type
+	ptrToString *Type
+	ptrToBool   *Type
+	ptrToInt32  *Type
+)
+
+func initPtrto() {
+	ptrToUint8 = ptrto1(Types[TUINT8])
+	ptrToAny = ptrto1(Types[TANY])
+	ptrToString = ptrto1(Types[TSTRING])
+	ptrToBool = ptrto1(Types[TBOOL])
+	ptrToInt32 = ptrto1(Types[TINT32])
+}
+
+func ptrto1(t *Type) *Type {
+	t1 := typ(Tptr)
+	t1.Type = t
+	t1.Width = int64(Widthptr)
+	t1.Align = uint8(Widthptr)
+	return t1
+}
+
+// Ptrto returns the Type *t.
+// The returned struct must not be modified.
+func Ptrto(t *Type) *Type {
+	if Tptr == 0 {
+		Fatal("ptrto: no tptr")
+	}
+	// Reduce allocations by pre-creating common cases.
+	if !initPtrtoDone {
+		initPtrto()
+		initPtrtoDone = true
+	}
+	switch t {
+	case Types[TUINT8]:
+		return ptrToUint8
+	case Types[TINT32]:
+		return ptrToInt32
+	case Types[TANY]:
+		return ptrToAny
+	case Types[TSTRING]:
+		return ptrToString
+	case Types[TBOOL]:
+		return ptrToBool
+	}
+	return ptrto1(t)
+}
+
+func frame(context int) {
+	var l *NodeList
+
+	if context != 0 {
+		fmt.Printf("--- external frame ---\n")
+		l = externdcl
+	} else if Curfn != nil {
+		fmt.Printf("--- %v frame ---\n", Curfn.Func.Nname.Sym)
+		l = Curfn.Func.Dcl
+	} else {
+		return
+	}
+
+	var n *Node
+	var w int64
+	for ; l != nil; l = l.Next {
+		n = l.N
+		w = -1
+		if n.Type != nil {
+			w = n.Type.Width
+		}
+		switch n.Op {
+		case ONAME:
+			fmt.Printf("%v %v G%d %v width=%d\n", Oconv(int(n.Op), 0), n.Sym, n.Name.Vargen, n.Type, w)
+
+		case OTYPE:
+			fmt.Printf("%v %v width=%d\n", Oconv(int(n.Op), 0), n.Type, w)
+		}
+	}
+}
+
+/*
+ * calculate sethi/ullman number
+ * roughly how many registers needed to
+ * compile a node. used to compile the
+ * hardest side first to minimize registers.
+ */
+func ullmancalc(n *Node) {
+	if n == nil {
+		return
+	}
+
+	var ul int
+	var ur int
+	if n.Ninit != nil {
+		ul = UINF
+		goto out
+	}
+
+	switch n.Op {
+	case OREGISTER, OLITERAL, ONAME:
+		ul = 1
+		if n.Class == PPARAMREF || (n.Class&PHEAP != 0) {
+			ul++
+		}
+		goto out
+
+	case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER, OASWB:
+		ul = UINF
+		goto out
+
+		// hard with race detector
+	case OANDAND, OOROR:
+		if flag_race != 0 {
+			ul = UINF
+			goto out
+		}
+	}
+
+	ul = 1
+	if n.Left != nil {
+		ul = int(n.Left.Ullman)
+	}
+	ur = 1
+	if n.Right != nil {
+		ur = int(n.Right.Ullman)
+	}
+	if ul == ur {
+		ul += 1
+	}
+	if ur > ul {
+		ul = ur
+	}
+
+out:
+	if ul > 200 {
+		ul = 200 // clamp to uchar with room to grow
+	}
+	n.Ullman = uint8(ul)
+}
+
+func badtype(o int, tl *Type, tr *Type) {
+	fmt_ := ""
+	if tl != nil {
+		fmt_ += fmt.Sprintf("\n\t%v", tl)
+	}
+	if tr != nil {
+		fmt_ += fmt.Sprintf("\n\t%v", tr)
+	}
+
+	// common mistake: *struct and *interface.
+	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 {
+			fmt_ += "\n\t(*interface vs *struct)"
+		}
+	}
+
+	s := fmt_
+	Yyerror("illegal types for operand: %v%s", Oconv(int(o), 0), s)
+}
+
+/*
+ * iterator to walk a structure declaration
+ */
+func Structfirst(s *Iter, nn **Type) *Type {
+	var t *Type
+
+	n := *nn
+	if n == nil {
+		goto bad
+	}
+
+	switch n.Etype {
+	default:
+		goto bad
+
+	case TSTRUCT, TINTER, TFUNC:
+		break
+	}
+
+	t = n.Type
+	if t == nil {
+		return nil
+	}
+
+	if t.Etype != TFIELD {
+		Fatal("structfirst: not field %v", t)
+	}
+
+	s.T = t
+	return t
+
+bad:
+	Fatal("structfirst: not struct %v", n)
+
+	return nil
+}
+
+func structnext(s *Iter) *Type {
+	n := s.T
+	t := n.Down
+	if t == nil {
+		return nil
+	}
+
+	if t.Etype != TFIELD {
+		Fatal("structnext: not struct %v", n)
+
+		return nil
+	}
+
+	s.T = t
+	return t
+}
+
+/*
+ * iterator to this and inargs in a function
+ */
+func funcfirst(s *Iter, t *Type) *Type {
+	var fp *Type
+
+	if t == nil {
+		goto bad
+	}
+
+	if t.Etype != TFUNC {
+		goto bad
+	}
+
+	s.Tfunc = t
+	s.Done = 0
+	fp = Structfirst(s, getthis(t))
+	if fp == nil {
+		s.Done = 1
+		fp = Structfirst(s, getinarg(t))
+	}
+
+	return fp
+
+bad:
+	Fatal("funcfirst: not func %v", t)
+	return nil
+}
+
+func funcnext(s *Iter) *Type {
+	fp := structnext(s)
+	if fp == nil && s.Done == 0 {
+		s.Done = 1
+		fp = Structfirst(s, getinarg(s.Tfunc))
+	}
+
+	return fp
+}
+
+func getthis(t *Type) **Type {
+	if t.Etype != TFUNC {
+		Fatal("getthis: not a func %v", t)
+	}
+	return &t.Type
+}
+
+func Getoutarg(t *Type) **Type {
+	if t.Etype != TFUNC {
+		Fatal("getoutarg: not a func %v", t)
+	}
+	return &t.Type.Down
+}
+
+func getinarg(t *Type) **Type {
+	if t.Etype != TFUNC {
+		Fatal("getinarg: not a func %v", t)
+	}
+	return &t.Type.Down.Down
+}
+
+func getthisx(t *Type) *Type {
+	return *getthis(t)
+}
+
+func getoutargx(t *Type) *Type {
+	return *Getoutarg(t)
+}
+
+func getinargx(t *Type) *Type {
+	return *getinarg(t)
+}
+
+// Brcom returns !(op).
+// For example, Brcom(==) is !=.
+func Brcom(a int) int {
+	switch a {
+	case OEQ:
+		return ONE
+	case ONE:
+		return OEQ
+	case OLT:
+		return OGE
+	case OGT:
+		return OLE
+	case OLE:
+		return OGT
+	case OGE:
+		return OLT
+	}
+	Fatal("brcom: no com for %v\n", Oconv(a, 0))
+	return a
+}
+
+// Brrev returns reverse(op).
+// For example, Brrev(<) is >.
+func Brrev(a int) int {
+	switch a {
+	case OEQ:
+		return OEQ
+	case ONE:
+		return ONE
+	case OLT:
+		return OGT
+	case OGT:
+		return OLT
+	case OLE:
+		return OGE
+	case OGE:
+		return OLE
+	}
+	Fatal("brrev: no rev for %v\n", Oconv(a, 0))
+	return a
+}
+
+/*
+ * return side effect-free n, appending side effects to init.
+ * result is assignable if n is.
+ */
+func safeexpr(n *Node, init **NodeList) *Node {
+	if n == nil {
+		return nil
+	}
+
+	if n.Ninit != nil {
+		walkstmtlist(n.Ninit)
+		*init = concat(*init, n.Ninit)
+		n.Ninit = nil
+	}
+
+	switch n.Op {
+	case ONAME, OLITERAL:
+		return n
+
+	case ODOT, OLEN, OCAP:
+		l := safeexpr(n.Left, init)
+		if l == n.Left {
+			return n
+		}
+		r := Nod(OXXX, nil, nil)
+		*r = *n
+		r.Left = l
+		typecheck(&r, Erv)
+		walkexpr(&r, init)
+		return r
+
+	case ODOTPTR, OIND:
+		l := safeexpr(n.Left, init)
+		if l == n.Left {
+			return n
+		}
+		a := Nod(OXXX, nil, nil)
+		*a = *n
+		a.Left = l
+		walkexpr(&a, init)
+		return a
+
+	case OINDEX, OINDEXMAP:
+		l := safeexpr(n.Left, init)
+		r := safeexpr(n.Right, init)
+		if l == n.Left && r == n.Right {
+			return n
+		}
+		a := Nod(OXXX, nil, nil)
+		*a = *n
+		a.Left = l
+		a.Right = r
+		walkexpr(&a, init)
+		return a
+	}
+
+	// make a copy; must not be used as an lvalue
+	if islvalue(n) {
+		Fatal("missing lvalue case in safeexpr: %v", n)
+	}
+	return cheapexpr(n, init)
+}
+
+func copyexpr(n *Node, t *Type, init **NodeList) *Node {
+	l := temp(t)
+	a := Nod(OAS, l, n)
+	typecheck(&a, Etop)
+	walkexpr(&a, init)
+	*init = list(*init, a)
+	return l
+}
+
+/*
+ * return side-effect free and cheap n, appending side effects to init.
+ * result may not be assignable.
+ */
+func cheapexpr(n *Node, init **NodeList) *Node {
+	switch n.Op {
+	case ONAME, OLITERAL:
+		return n
+	}
+
+	return copyexpr(n, n.Type, init)
+}
+
+/*
+ * return n in a local variable of type t if it is not already.
+ * the value is guaranteed not to change except by direct
+ * assignment to it.
+ */
+func localexpr(n *Node, t *Type, init **NodeList) *Node {
+	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
+	}
+
+	return copyexpr(n, t, init)
+}
+
+func Setmaxarg(t *Type, extra int32) {
+	dowidth(t)
+	w := t.Argwid
+	if w >= Thearch.MAXWIDTH {
+		Fatal("bad argwid %v", t)
+	}
+	w += int64(extra)
+	if w >= Thearch.MAXWIDTH {
+		Fatal("bad argwid %d + %v", extra, t)
+	}
+	if w > Maxarg {
+		Maxarg = w
+	}
+}
+
+/*
+ * unicode-aware case-insensitive strcmp
+ */
+
+/*
+ * code to resolve elided DOTs
+ * in embedded types
+ */
+
+// search depth 0 --
+// return count of fields+methods
+// found with a given name
+func lookdot0(s *Sym, t *Type, save **Type, ignorecase int) int {
+	u := t
+	if Isptr[u.Etype] {
+		u = u.Type
+	}
+
+	c := 0
+	if u.Etype == TSTRUCT || u.Etype == TINTER {
+		for f := u.Type; f != nil; f = f.Down {
+			if f.Sym == s || (ignorecase != 0 && f.Type.Etype == TFUNC && f.Type.Thistuple > 0 && strings.EqualFold(f.Sym.Name, s.Name)) {
+				if save != nil {
+					*save = f
+				}
+				c++
+			}
+		}
+	}
+
+	u = methtype(t, 0)
+	if u != nil {
+		for f := u.Method; f != nil; f = f.Down {
+			if f.Embedded == 0 && (f.Sym == s || (ignorecase != 0 && strings.EqualFold(f.Sym.Name, s.Name))) {
+				if save != nil {
+					*save = f
+				}
+				c++
+			}
+		}
+	}
+
+	return c
+}
+
+// search depth d for field/method s --
+// return count of fields+methods
+// found at search depth.
+// answer is in dotlist array and
+// count of number of ways is returned.
+func adddot1(s *Sym, t *Type, d int, save **Type, ignorecase int) int {
+	if t.Trecur != 0 {
+		return 0
+	}
+	t.Trecur = 1
+
+	var c int
+	var u *Type
+	var a int
+	if d == 0 {
+		c = lookdot0(s, t, save, ignorecase)
+		goto out
+	}
+
+	c = 0
+	u = t
+	if Isptr[u.Etype] {
+		u = u.Type
+	}
+	if u.Etype != TSTRUCT && u.Etype != TINTER {
+		goto out
+	}
+
+	d--
+	for f := u.Type; f != nil; f = f.Down {
+		if f.Embedded == 0 {
+			continue
+		}
+		if f.Sym == nil {
+			continue
+		}
+		a = adddot1(s, f.Type, d, save, ignorecase)
+		if a != 0 && c == 0 {
+			dotlist[d].field = f
+		}
+		c += a
+	}
+
+out:
+	t.Trecur = 0
+	return c
+}
+
+// in T.field
+// find missing fields that
+// will give shortest unique addressing.
+// modify the tree with missing type names.
+func adddot(n *Node) *Node {
+	typecheck(&n.Left, Etype|Erv)
+	n.Diag |= n.Left.Diag
+	t := n.Left.Type
+	if t == nil {
+		return n
+	}
+
+	if n.Left.Op == OTYPE {
+		return n
+	}
+
+	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", n)
+				n.Left = nil
+				return n
+			}
+
+			// rebuild elided dots
+			for c := d - 1; c >= 0; c-- {
+				n.Left = Nod(ODOT, n.Left, newname(dotlist[c].field.Sym))
+				n.Left.Implicit = true
+			}
+
+			return n
+		}
+	}
+
+	return n
+}
+
+/*
+ * code to help generate trampoline
+ * functions for methods on embedded
+ * subtypes.
+ * these are approx the same as
+ * the corresponding adddot routines
+ * except that they expect to be called
+ * with unique tasks and they return
+ * the actual methods.
+ */
+type Symlink struct {
+	field     *Type
+	good      uint8
+	followptr uint8
+	link      *Symlink
+}
+
+var slist *Symlink
+
+func expand0(t *Type, followptr int) {
+	u := t
+	if Isptr[u.Etype] {
+		followptr = 1
+		u = u.Type
+	}
+
+	if u.Etype == TINTER {
+		var sl *Symlink
+		for f := u.Type; f != nil; f = f.Down {
+			if f.Sym.Flags&SymUniq != 0 {
+				continue
+			}
+			f.Sym.Flags |= SymUniq
+			sl = new(Symlink)
+			sl.field = f
+			sl.link = slist
+			sl.followptr = uint8(followptr)
+			slist = sl
+		}
+
+		return
+	}
+
+	u = methtype(t, 0)
+	if u != nil {
+		var sl *Symlink
+		for f := u.Method; f != nil; f = f.Down {
+			if f.Sym.Flags&SymUniq != 0 {
+				continue
+			}
+			f.Sym.Flags |= SymUniq
+			sl = new(Symlink)
+			sl.field = f
+			sl.link = slist
+			sl.followptr = uint8(followptr)
+			slist = sl
+		}
+	}
+}
+
+func expand1(t *Type, d int, followptr int) {
+	if t.Trecur != 0 {
+		return
+	}
+	if d == 0 {
+		return
+	}
+	t.Trecur = 1
+
+	if d != len(dotlist)-1 {
+		expand0(t, followptr)
+	}
+
+	u := t
+	if Isptr[u.Etype] {
+		followptr = 1
+		u = u.Type
+	}
+
+	if u.Etype != TSTRUCT && u.Etype != TINTER {
+		goto out
+	}
+
+	for f := u.Type; f != nil; f = f.Down {
+		if f.Embedded == 0 {
+			continue
+		}
+		if f.Sym == nil {
+			continue
+		}
+		expand1(f.Type, d-1, followptr)
+	}
+
+out:
+	t.Trecur = 0
+}
+
+func expandmeth(t *Type) {
+	if t == nil || t.Xmethod != nil {
+		return
+	}
+
+	// mark top-level method symbols
+	// so that expand1 doesn't consider them.
+	var f *Type
+	for f = t.Method; f != nil; f = f.Down {
+		f.Sym.Flags |= SymUniq
+	}
+
+	// generate all reachable methods
+	slist = nil
+
+	expand1(t, len(dotlist)-1, 0)
+
+	// check each method to be uniquely reachable
+	var c int
+	var d int
+	for sl := slist; sl != nil; sl = sl.link {
+		sl.field.Sym.Flags &^= SymUniq
+		for d = 0; d < len(dotlist); d++ {
+			c = adddot1(sl.field.Sym, t, d, &f, 0)
+			if c == 0 {
+				continue
+			}
+			if c == 1 {
+				// addot1 may have dug out arbitrary fields, we only want methods.
+				if f.Type.Etype == TFUNC && f.Type.Thistuple > 0 {
+					sl.good = 1
+					sl.field = f
+				}
+			}
+
+			break
+		}
+	}
+
+	for f = t.Method; f != nil; f = f.Down {
+		f.Sym.Flags &^= SymUniq
+	}
+
+	t.Xmethod = t.Method
+	for sl := slist; sl != nil; sl = sl.link {
+		if sl.good != 0 {
+			// add it to the base type method list
+			f = typ(TFIELD)
+
+			*f = *sl.field
+			f.Embedded = 1 // needs a trampoline
+			if sl.followptr != 0 {
+				f.Embedded = 2
+			}
+			f.Down = t.Xmethod
+			t.Xmethod = f
+		}
+	}
+}
+
+/*
+ * Given funarg struct list, return list of ODCLFIELD Node fn args.
+ */
+func structargs(tl **Type, mustname int) *NodeList {
+	var savet Iter
+	var a *Node
+	var n *Node
+	var buf string
+
+	var args *NodeList
+	gen := 0
+	for t := Structfirst(&savet, tl); t != nil; t = structnext(&savet) {
+		n = nil
+		if mustname != 0 && (t.Sym == nil || t.Sym.Name == "_") {
+			// invent a name so that we can refer to it in the trampoline
+			buf = fmt.Sprintf(".anon%d", gen)
+			gen++
+
+			n = newname(Lookup(buf))
+		} else if t.Sym != nil {
+			n = newname(t.Sym)
+		}
+		a = Nod(ODCLFIELD, n, typenod(t.Type))
+		a.Isddd = t.Isddd
+		if n != nil {
+			n.Isddd = t.Isddd
+		}
+		args = list(args, a)
+	}
+
+	return args
+}
+
+/*
+ * Generate a wrapper function to convert from
+ * a receiver of type T to a receiver of type U.
+ * That is,
+ *
+ *	func (t T) M() {
+ *		...
+ *	}
+ *
+ * already exists; this function generates
+ *
+ *	func (u U) M() {
+ *		u.M()
+ *	}
+ *
+ * where the types T and U are such that u.M() is valid
+ * and calls the T.M method.
+ * The resulting function is for use in method tables.
+ *
+ *	rcvr - U
+ *	method - M func (t T)(), a TFIELD type struct
+ *	newnam - the eventual mangled name of this function
+ */
+
+var genwrapper_linehistdone int = 0
+
+func genwrapper(rcvr *Type, method *Type, newnam *Sym, iface int) {
+	if false && Debug['r'] != 0 {
+		fmt.Printf("genwrapper rcvrtype=%v method=%v newnam=%v\n", rcvr, method, newnam)
+	}
+
+	lexlineno++
+	lineno = lexlineno
+	if genwrapper_linehistdone == 0 {
+		// All the wrappers can share the same linehist entry.
+		linehistpush("<autogenerated>")
+
+		genwrapper_linehistdone = 1
+	}
+
+	dclcontext = PEXTERN
+	markdcl()
+
+	this := Nod(ODCLFIELD, newname(Lookup(".this")), typenod(rcvr))
+	this.Left.Name.Param.Ntype = this.Right
+	in := structargs(getinarg(method.Type), 1)
+	out := structargs(Getoutarg(method.Type), 0)
+
+	t := Nod(OTFUNC, nil, nil)
+	l := list1(this)
+	if iface != 0 && rcvr.Width < Types[Tptr].Width {
+		// Building method for interface table and receiver
+		// is smaller than the single pointer-sized word
+		// that the interface call will pass in.
+		// Add a dummy padding argument after the
+		// receiver to make up the difference.
+		tpad := typ(TARRAY)
+
+		tpad.Type = Types[TUINT8]
+		tpad.Bound = Types[Tptr].Width - rcvr.Width
+		pad := Nod(ODCLFIELD, newname(Lookup(".pad")), typenod(tpad))
+		l = list(l, pad)
+	}
+
+	t.List = concat(l, in)
+	t.Rlist = out
+
+	fn := Nod(ODCLFUNC, nil, nil)
+	fn.Func.Nname = newname(newnam)
+	fn.Func.Nname.Name.Defn = fn
+	fn.Func.Nname.Name.Param.Ntype = t
+	declare(fn.Func.Nname, PFUNC)
+	funchdr(fn)
+
+	// arg list
+	var args *NodeList
+
+	isddd := false
+	for l := in; l != nil; l = l.Next {
+		args = list(args, l.N.Left)
+		isddd = l.N.Left.Isddd
+	}
+
+	methodrcvr := getthisx(method.Type).Type.Type
+
+	// generate nil pointer check for better error
+	if Isptr[rcvr.Etype] && rcvr.Type == methodrcvr {
+		// generating wrapper from *T to T.
+		n := Nod(OIF, nil, nil)
+
+		n.Left = Nod(OEQ, this.Left, nodnil())
+
+		// these strings are already in the reflect tables,
+		// so no space cost to use them here.
+		var l *NodeList
+
+		var v Val
+		v.U = rcvr.Type.Sym.Pkg.Name // package name
+		l = list(l, nodlit(v))
+		v.U = rcvr.Type.Sym.Name // type name
+		l = list(l, nodlit(v))
+		v.U = method.Sym.Name
+		l = list(l, nodlit(v)) // method name
+		call := Nod(OCALL, syslook("panicwrap", 0), nil)
+		call.List = l
+		n.Nbody = list1(call)
+		fn.Nbody = list(fn.Nbody, n)
+	}
+
+	dot := adddot(Nod(OXDOT, this.Left, newname(method.Sym)))
+
+	// generate call
+	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] {
+			dot = Nod(OADDR, dot, nil)
+		}
+		as := Nod(OAS, this.Left, Nod(OCONVNOP, dot, nil))
+		as.Right.Type = rcvr
+		fn.Nbody = list(fn.Nbody, as)
+		n := Nod(ORETJMP, nil, nil)
+		n.Left = newname(methodsym(method.Sym, methodrcvr, 0))
+		fn.Nbody = list(fn.Nbody, n)
+	} else {
+		fn.Func.Wrapper = true // ignore frame for panic+recover matching
+		call := Nod(OCALL, dot, nil)
+		call.List = args
+		call.Isddd = isddd
+		if method.Type.Outtuple > 0 {
+			n := Nod(ORETURN, nil, nil)
+			n.List = list1(call)
+			call = n
+		}
+
+		fn.Nbody = list(fn.Nbody, call)
+	}
+
+	if false && Debug['r'] != 0 {
+		dumplist("genwrapper body", fn.Nbody)
+	}
+
+	funcbody(fn)
+	Curfn = fn
+
+	// wrappers where T is anonymous (struct or interface) can be duplicated.
+	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)
+
+	inlcalls(fn)
+	escAnalyze(list1(fn), false)
+
+	Curfn = nil
+	funccompile(fn)
+}
+
+func hashmem(t *Type) *Node {
+	sym := Pkglookup("memhash", Runtimepkg)
+
+	n := newname(sym)
+	n.Class = PFUNC
+	tfn := Nod(OTFUNC, nil, nil)
+	tfn.List = list(tfn.List, Nod(ODCLFIELD, nil, typenod(Ptrto(t))))
+	tfn.List = list(tfn.List, Nod(ODCLFIELD, nil, typenod(Types[TUINTPTR])))
+	tfn.List = list(tfn.List, Nod(ODCLFIELD, nil, typenod(Types[TUINTPTR])))
+	tfn.Rlist = list(tfn.Rlist, Nod(ODCLFIELD, nil, typenod(Types[TUINTPTR])))
+	typecheck(&tfn, Etype)
+	n.Type = tfn.Type
+	return n
+}
+
+func hashfor(t *Type) *Node {
+	var sym *Sym
+
+	a := algtype1(t, nil)
+	switch a {
+	case AMEM:
+		Fatal("hashfor with AMEM type")
+
+	case AINTER:
+		sym = Pkglookup("interhash", Runtimepkg)
+
+	case ANILINTER:
+		sym = Pkglookup("nilinterhash", Runtimepkg)
+
+	case ASTRING:
+		sym = Pkglookup("strhash", Runtimepkg)
+
+	case AFLOAT32:
+		sym = Pkglookup("f32hash", Runtimepkg)
+
+	case AFLOAT64:
+		sym = Pkglookup("f64hash", Runtimepkg)
+
+	case ACPLX64:
+		sym = Pkglookup("c64hash", Runtimepkg)
+
+	case ACPLX128:
+		sym = Pkglookup("c128hash", Runtimepkg)
+
+	default:
+		sym = typesymprefix(".hash", t)
+	}
+
+	n := newname(sym)
+	n.Class = PFUNC
+	tfn := Nod(OTFUNC, nil, nil)
+	tfn.List = list(tfn.List, Nod(ODCLFIELD, nil, typenod(Ptrto(t))))
+	tfn.List = list(tfn.List, Nod(ODCLFIELD, nil, typenod(Types[TUINTPTR])))
+	tfn.Rlist = list(tfn.Rlist, Nod(ODCLFIELD, nil, typenod(Types[TUINTPTR])))
+	typecheck(&tfn, Etype)
+	n.Type = tfn.Type
+	return n
+}
+
+/*
+ * Generate a helper function to compute the hash of a value of type t.
+ */
+func genhash(sym *Sym, t *Type) {
+	if Debug['r'] != 0 {
+		fmt.Printf("genhash %v %v\n", sym, t)
+	}
+
+	lineno = 1 // less confusing than end of input
+	dclcontext = PEXTERN
+	markdcl()
+
+	// func sym(p *T, h uintptr) uintptr
+	fn := Nod(ODCLFUNC, nil, nil)
+
+	fn.Func.Nname = newname(sym)
+	fn.Func.Nname.Class = PFUNC
+	tfn := Nod(OTFUNC, nil, nil)
+	fn.Func.Nname.Name.Param.Ntype = tfn
+
+	n := Nod(ODCLFIELD, newname(Lookup("p")), typenod(Ptrto(t)))
+	tfn.List = list(tfn.List, n)
+	np := n.Left
+	n = Nod(ODCLFIELD, newname(Lookup("h")), typenod(Types[TUINTPTR]))
+	tfn.List = list(tfn.List, n)
+	nh := n.Left
+	n = Nod(ODCLFIELD, nil, typenod(Types[TUINTPTR])) // return value
+	tfn.Rlist = list(tfn.Rlist, n)
+
+	funchdr(fn)
+	typecheck(&fn.Func.Nname.Name.Param.Ntype, Etype)
+
+	// genhash is only called for types that have equality but
+	// cannot be handled by the standard algorithms,
+	// so t must be either an array or a struct.
+	switch t.Etype {
+	default:
+		Fatal("genhash %v", t)
+
+	case TARRAY:
+		if Isslice(t) {
+			Fatal("genhash %v", t)
+		}
+
+		// An array of pure memory would be handled by the
+		// standard algorithm, so the element type must not be
+		// pure memory.
+		hashel := hashfor(t.Type)
+
+		n := Nod(ORANGE, nil, Nod(OIND, np, nil))
+		ni := newname(Lookup("i"))
+		ni.Type = Types[TINT]
+		n.List = list1(ni)
+		n.Colas = true
+		colasdefn(n.List, n)
+		ni = n.List.N
+
+		// TODO: with aeshash we don't need these shift/mul parts
+
+		// h = h<<3 | h>>61
+		n.Nbody = list(n.Nbody, Nod(OAS, nh, Nod(OOR, Nod(OLSH, nh, Nodintconst(3)), Nod(ORSH, nh, Nodintconst(int64(Widthptr)*8-3)))))
+
+		// h *= mul
+		// Same multipliers as in runtime.memhash.
+		var mul int64
+		if Widthptr == 4 {
+			mul = 3267000013
+		} else {
+			mul = 23344194077549503
+		}
+		n.Nbody = list(n.Nbody, Nod(OAS, nh, Nod(OMUL, nh, Nodintconst(mul))))
+
+		// h = hashel(&p[i], h)
+		call := Nod(OCALL, hashel, nil)
+
+		nx := Nod(OINDEX, np, ni)
+		nx.Bounded = true
+		na := Nod(OADDR, nx, nil)
+		na.Etype = 1 // no escape to heap
+		call.List = list(call.List, na)
+		call.List = list(call.List, nh)
+		n.Nbody = list(n.Nbody, Nod(OAS, nh, call))
+
+		fn.Nbody = list(fn.Nbody, n)
+
+		// Walk the struct using memhash for runs of AMEM
+	// and calling specific hash functions for the others.
+	case TSTRUCT:
+		var first *Type
+
+		offend := int64(0)
+		var size int64
+		var call *Node
+		var nx *Node
+		var na *Node
+		var hashel *Node
+		for t1 := t.Type; ; t1 = t1.Down {
+			if t1 != nil && algtype1(t1.Type, nil) == AMEM && !isblanksym(t1.Sym) {
+				offend = t1.Width + t1.Type.Width
+				if first == nil {
+					first = t1
+				}
+
+				// If it's a memory field but it's padded, stop here.
+				if ispaddedfield(t1, t.Width) {
+					t1 = t1.Down
+				} else {
+					continue
+				}
+			}
+
+			// Run memhash for fields up to this one.
+			if first != nil {
+				size = offend - first.Width // first->width is offset
+				hashel = hashmem(first.Type)
+
+				// h = hashel(&p.first, size, h)
+				call = Nod(OCALL, hashel, nil)
+
+				nx = Nod(OXDOT, np, newname(first.Sym)) // TODO: fields from other packages?
+				na = Nod(OADDR, nx, nil)
+				na.Etype = 1 // no escape to heap
+				call.List = list(call.List, na)
+				call.List = list(call.List, nh)
+				call.List = list(call.List, Nodintconst(size))
+				fn.Nbody = list(fn.Nbody, Nod(OAS, nh, call))
+
+				first = nil
+			}
+
+			if t1 == nil {
+				break
+			}
+			if isblanksym(t1.Sym) {
+				continue
+			}
+
+			// Run hash for this field.
+			if algtype1(t1.Type, nil) == AMEM {
+				hashel = hashmem(t1.Type)
+
+				// h = memhash(&p.t1, h, size)
+				call = Nod(OCALL, hashel, nil)
+
+				nx = Nod(OXDOT, np, newname(t1.Sym)) // TODO: fields from other packages?
+				na = Nod(OADDR, nx, nil)
+				na.Etype = 1 // no escape to heap
+				call.List = list(call.List, na)
+				call.List = list(call.List, nh)
+				call.List = list(call.List, Nodintconst(t1.Type.Width))
+				fn.Nbody = list(fn.Nbody, Nod(OAS, nh, call))
+			} else {
+				hashel = hashfor(t1.Type)
+
+				// h = hashel(&p.t1, h)
+				call = Nod(OCALL, hashel, nil)
+
+				nx = Nod(OXDOT, np, newname(t1.Sym)) // TODO: fields from other packages?
+				na = Nod(OADDR, nx, nil)
+				na.Etype = 1 // no escape to heap
+				call.List = list(call.List, na)
+				call.List = list(call.List, nh)
+				fn.Nbody = list(fn.Nbody, Nod(OAS, nh, call))
+			}
+		}
+	}
+
+	r := Nod(ORETURN, nil, nil)
+	r.List = list(r.List, nh)
+	fn.Nbody = list(fn.Nbody, r)
+
+	if Debug['r'] != 0 {
+		dumplist("genhash body", fn.Nbody)
+	}
+
+	funcbody(fn)
+	Curfn = fn
+	fn.Func.Dupok = true
+	typecheck(&fn, Etop)
+	typechecklist(fn.Nbody, Etop)
+	Curfn = nil
+
+	// Disable safemode while compiling this code: the code we
+	// generate internally can refer to unsafe.Pointer.
+	// In this case it can happen if we need to generate an ==
+	// for a struct containing a reflect.Value, which itself has
+	// an unexported field of type unsafe.Pointer.
+	old_safemode := safemode
+
+	safemode = 0
+	funccompile(fn)
+	safemode = old_safemode
+}
+
+// Return node for
+//	if p.field != q.field { return false }
+func eqfield(p *Node, q *Node, field *Node) *Node {
+	nx := Nod(OXDOT, p, field)
+	ny := Nod(OXDOT, q, field)
+	nif := Nod(OIF, nil, nil)
+	nif.Left = Nod(ONE, nx, ny)
+	r := Nod(ORETURN, nil, nil)
+	r.List = list(r.List, Nodbool(false))
+	nif.Nbody = list(nif.Nbody, r)
+	return nif
+}
+
+func eqmemfunc(size int64, type_ *Type, needsize *int) *Node {
+	var fn *Node
+
+	switch size {
+	default:
+		fn = syslook("memequal", 1)
+		*needsize = 1
+
+	case 1, 2, 4, 8, 16:
+		buf := fmt.Sprintf("memequal%d", int(size)*8)
+		fn = syslook(buf, 1)
+		*needsize = 0
+	}
+
+	substArgTypes(fn, type_, type_)
+	return fn
+}
+
+// Return node for
+//	if !memequal(&p.field, &q.field [, size]) { return false }
+func eqmem(p *Node, q *Node, field *Node, size int64) *Node {
+	var needsize int
+
+	nx := Nod(OADDR, Nod(OXDOT, p, field), nil)
+	nx.Etype = 1 // does not escape
+	ny := Nod(OADDR, Nod(OXDOT, q, field), nil)
+	ny.Etype = 1 // does not escape
+	typecheck(&nx, Erv)
+	typecheck(&ny, Erv)
+
+	call := Nod(OCALL, eqmemfunc(size, nx.Type.Type, &needsize), nil)
+	call.List = list(call.List, nx)
+	call.List = list(call.List, ny)
+	if needsize != 0 {
+		call.List = list(call.List, Nodintconst(size))
+	}
+
+	nif := Nod(OIF, nil, nil)
+	nif.Left = Nod(ONOT, call, nil)
+	r := Nod(ORETURN, nil, nil)
+	r.List = list(r.List, Nodbool(false))
+	nif.Nbody = list(nif.Nbody, r)
+	return nif
+}
+
+/*
+ * Generate a helper function to check equality of two values of type t.
+ */
+func geneq(sym *Sym, t *Type) {
+	if Debug['r'] != 0 {
+		fmt.Printf("geneq %v %v\n", sym, t)
+	}
+
+	lineno = 1 // less confusing than end of input
+	dclcontext = PEXTERN
+	markdcl()
+
+	// func sym(p, q *T) bool
+	fn := Nod(ODCLFUNC, nil, nil)
+
+	fn.Func.Nname = newname(sym)
+	fn.Func.Nname.Class = PFUNC
+	tfn := Nod(OTFUNC, nil, nil)
+	fn.Func.Nname.Name.Param.Ntype = tfn
+
+	n := Nod(ODCLFIELD, newname(Lookup("p")), typenod(Ptrto(t)))
+	tfn.List = list(tfn.List, n)
+	np := n.Left
+	n = Nod(ODCLFIELD, newname(Lookup("q")), typenod(Ptrto(t)))
+	tfn.List = list(tfn.List, n)
+	nq := n.Left
+	n = Nod(ODCLFIELD, nil, typenod(Types[TBOOL]))
+	tfn.Rlist = list(tfn.Rlist, n)
+
+	funchdr(fn)
+
+	// geneq is only called for types that have equality but
+	// cannot be handled by the standard algorithms,
+	// so t must be either an array or a struct.
+	switch t.Etype {
+	default:
+		Fatal("geneq %v", t)
+
+	case TARRAY:
+		if Isslice(t) {
+			Fatal("geneq %v", t)
+		}
+
+		// An array of pure memory would be handled by the
+		// standard memequal, so the element type must not be
+		// pure memory.  Even if we unrolled the range loop,
+		// each iteration would be a function call, so don't bother
+		// unrolling.
+		nrange := Nod(ORANGE, nil, Nod(OIND, np, nil))
+
+		ni := newname(Lookup("i"))
+		ni.Type = Types[TINT]
+		nrange.List = list1(ni)
+		nrange.Colas = true
+		colasdefn(nrange.List, nrange)
+		ni = nrange.List.N
+
+		// if p[i] != q[i] { return false }
+		nx := Nod(OINDEX, np, ni)
+
+		nx.Bounded = true
+		ny := Nod(OINDEX, nq, ni)
+		ny.Bounded = true
+
+		nif := Nod(OIF, nil, nil)
+		nif.Left = Nod(ONE, nx, ny)
+		r := Nod(ORETURN, nil, nil)
+		r.List = list(r.List, Nodbool(false))
+		nif.Nbody = list(nif.Nbody, r)
+		nrange.Nbody = list(nrange.Nbody, nif)
+		fn.Nbody = list(fn.Nbody, nrange)
+
+		// Walk the struct using memequal for runs of AMEM
+	// and calling specific equality tests for the others.
+	// Skip blank-named fields.
+	case TSTRUCT:
+		var first *Type
+
+		offend := int64(0)
+		var size int64
+		for t1 := t.Type; ; t1 = t1.Down {
+			if t1 != nil && algtype1(t1.Type, nil) == AMEM && !isblanksym(t1.Sym) {
+				offend = t1.Width + t1.Type.Width
+				if first == nil {
+					first = t1
+				}
+
+				// If it's a memory field but it's padded, stop here.
+				if ispaddedfield(t1, t.Width) {
+					t1 = t1.Down
+				} else {
+					continue
+				}
+			}
+
+			// Run memequal for fields up to this one.
+			// TODO(rsc): All the calls to newname are wrong for
+			// cross-package unexported fields.
+			if first != nil {
+				if first.Down == t1 {
+					fn.Nbody = list(fn.Nbody, eqfield(np, nq, newname(first.Sym)))
+				} else if first.Down.Down == t1 {
+					fn.Nbody = list(fn.Nbody, eqfield(np, nq, newname(first.Sym)))
+					first = first.Down
+					if !isblanksym(first.Sym) {
+						fn.Nbody = list(fn.Nbody, eqfield(np, nq, newname(first.Sym)))
+					}
+				} else {
+					// More than two fields: use memequal.
+					size = offend - first.Width // first->width is offset
+					fn.Nbody = list(fn.Nbody, eqmem(np, nq, newname(first.Sym), size))
+				}
+
+				first = nil
+			}
+
+			if t1 == nil {
+				break
+			}
+			if isblanksym(t1.Sym) {
+				continue
+			}
+
+			// Check this field, which is not just memory.
+			fn.Nbody = list(fn.Nbody, eqfield(np, nq, newname(t1.Sym)))
+		}
+	}
+
+	// return true
+	r := Nod(ORETURN, nil, nil)
+
+	r.List = list(r.List, Nodbool(true))
+	fn.Nbody = list(fn.Nbody, r)
+
+	if Debug['r'] != 0 {
+		dumplist("geneq body", fn.Nbody)
+	}
+
+	funcbody(fn)
+	Curfn = fn
+	fn.Func.Dupok = true
+	typecheck(&fn, Etop)
+	typechecklist(fn.Nbody, Etop)
+	Curfn = nil
+
+	// Disable safemode while compiling this code: the code we
+	// generate internally can refer to unsafe.Pointer.
+	// In this case it can happen if we need to generate an ==
+	// for a struct containing a reflect.Value, which itself has
+	// an unexported field of type unsafe.Pointer.
+	old_safemode := safemode
+
+	safemode = 0
+	funccompile(fn)
+	safemode = old_safemode
+}
+
+func ifacelookdot(s *Sym, t *Type, followptr *int, ignorecase int) *Type {
+	*followptr = 0
+
+	if t == nil {
+		return nil
+	}
+
+	var m *Type
+	var i int
+	var c int
+	for d := 0; d < len(dotlist); d++ {
+		c = adddot1(s, t, d, &m, ignorecase)
+		if c > 1 {
+			Yyerror("%v.%v is ambiguous", t, s)
+			return nil
+		}
+
+		if c == 1 {
+			for i = 0; i < d; i++ {
+				if Isptr[dotlist[i].field.Type.Etype] {
+					*followptr = 1
+					break
+				}
+			}
+
+			if m.Type.Etype != TFUNC || m.Type.Thistuple == 0 {
+				Yyerror("%v.%v is a field, not a method", t, s)
+				return nil
+			}
+
+			return m
+		}
+	}
+
+	return nil
+}
+
+func implements(t *Type, iface *Type, m **Type, samename **Type, ptr *int) bool {
+	t0 := t
+	if t == nil {
+		return false
+	}
+
+	// if this is too slow,
+	// could sort these first
+	// and then do one loop.
+
+	if t.Etype == TINTER {
+		var tm *Type
+		for im := iface.Type; im != nil; im = im.Down {
+			for tm = t.Type; tm != nil; tm = tm.Down {
+				if tm.Sym == im.Sym {
+					if Eqtype(tm.Type, im.Type) {
+						goto found
+					}
+					*m = im
+					*samename = tm
+					*ptr = 0
+					return false
+				}
+			}
+
+			*m = im
+			*samename = nil
+			*ptr = 0
+			return false
+		found:
+		}
+
+		return true
+	}
+
+	t = methtype(t, 0)
+	if t != nil {
+		expandmeth(t)
+	}
+	var tm *Type
+	var imtype *Type
+	var followptr int
+	var rcvr *Type
+	for im := iface.Type; im != nil; im = im.Down {
+		imtype = methodfunc(im.Type, nil)
+		tm = ifacelookdot(im.Sym, t, &followptr, 0)
+		if tm == nil || tm.Nointerface || !Eqtype(methodfunc(tm.Type, nil), imtype) {
+			if tm == nil {
+				tm = ifacelookdot(im.Sym, t, &followptr, 1)
+			}
+			*m = im
+			*samename = tm
+			*ptr = 0
+			return false
+		}
+
+		// if pointer receiver in method,
+		// the method does not exist for value types.
+		rcvr = getthisx(tm.Type).Type.Type
+
+		if Isptr[rcvr.Etype] && !Isptr[t0.Etype] && followptr == 0 && !isifacemethod(tm.Type) {
+			if false && Debug['r'] != 0 {
+				Yyerror("interface pointer mismatch")
+			}
+
+			*m = im
+			*samename = nil
+			*ptr = 1
+			return false
+		}
+	}
+
+	return true
+}
+
+/*
+ * even simpler simtype; get rid of ptr, bool.
+ * assuming that the front end has rejected
+ * all the invalid conversions (like ptr -> bool)
+ */
+func Simsimtype(t *Type) int {
+	if t == nil {
+		return 0
+	}
+
+	et := int(Simtype[t.Etype])
+	switch et {
+	case TPTR32:
+		et = TUINT32
+
+	case TPTR64:
+		et = TUINT64
+
+	case TBOOL:
+		et = TUINT8
+	}
+
+	return et
+}
+
+func listtreecopy(l *NodeList, lineno int32) *NodeList {
+	var out *NodeList
+	for ; l != nil; l = l.Next {
+		out = list(out, treecopy(l.N, lineno))
+	}
+	return out
+}
+
+func liststmt(l *NodeList) *Node {
+	n := Nod(OBLOCK, nil, nil)
+	n.List = l
+	if l != nil {
+		n.Lineno = l.N.Lineno
+	}
+	return n
+}
+
+/*
+ * return nelem of list
+ */
+func structcount(t *Type) int {
+	var s Iter
+
+	v := 0
+	for t = Structfirst(&s, &t); t != nil; t = structnext(&s) {
+		v++
+	}
+	return v
+}
+
+/*
+ * return power of 2 of the constant
+ * operand. -1 if it is not a power of 2.
+ * 1000+ if it is a -(power of 2)
+ */
+func powtwo(n *Node) int {
+	if n == nil || n.Op != OLITERAL || n.Type == nil {
+		return -1
+	}
+	if !Isint[n.Type.Etype] {
+		return -1
+	}
+
+	v := uint64(Mpgetfix(n.Val().U.(*Mpint)))
+	b := uint64(1)
+	for i := 0; i < 64; i++ {
+		if b == v {
+			return i
+		}
+		b = b << 1
+	}
+
+	if !Issigned[n.Type.Etype] {
+		return -1
+	}
+
+	v = -v
+	b = 1
+	for i := 0; i < 64; i++ {
+		if b == v {
+			return i + 1000
+		}
+		b = b << 1
+	}
+
+	return -1
+}
+
+/*
+ * return the unsigned type for
+ * a signed integer type.
+ * returns T if input is not a
+ * signed integer type.
+ */
+func tounsigned(t *Type) *Type {
+	// this is types[et+1], but not sure
+	// that this relation is immutable
+	switch t.Etype {
+	default:
+		fmt.Printf("tounsigned: unknown type %v\n", t)
+		t = nil
+
+	case TINT:
+		t = Types[TUINT]
+
+	case TINT8:
+		t = Types[TUINT8]
+
+	case TINT16:
+		t = Types[TUINT16]
+
+	case TINT32:
+		t = Types[TUINT32]
+
+	case TINT64:
+		t = Types[TUINT64]
+	}
+
+	return t
+}
+
+/*
+ * magic number for signed division
+ * see hacker's delight chapter 10
+ */
+func Smagic(m *Magic) {
+	var mask uint64
+
+	m.Bad = 0
+	switch m.W {
+	default:
+		m.Bad = 1
+		return
+
+	case 8:
+		mask = 0xff
+
+	case 16:
+		mask = 0xffff
+
+	case 32:
+		mask = 0xffffffff
+
+	case 64:
+		mask = 0xffffffffffffffff
+	}
+
+	two31 := mask ^ (mask >> 1)
+
+	p := m.W - 1
+	ad := uint64(m.Sd)
+	if m.Sd < 0 {
+		ad = -uint64(m.Sd)
+	}
+
+	// bad denominators
+	if ad == 0 || ad == 1 || ad == two31 {
+		m.Bad = 1
+		return
+	}
+
+	t := two31
+	ad &= mask
+
+	anc := t - 1 - t%ad
+	anc &= mask
+
+	q1 := two31 / anc
+	r1 := two31 - q1*anc
+	q1 &= mask
+	r1 &= mask
+
+	q2 := two31 / ad
+	r2 := two31 - q2*ad
+	q2 &= mask
+	r2 &= mask
+
+	var delta uint64
+	for {
+		p++
+		q1 <<= 1
+		r1 <<= 1
+		q1 &= mask
+		r1 &= mask
+		if r1 >= anc {
+			q1++
+			r1 -= anc
+			q1 &= mask
+			r1 &= mask
+		}
+
+		q2 <<= 1
+		r2 <<= 1
+		q2 &= mask
+		r2 &= mask
+		if r2 >= ad {
+			q2++
+			r2 -= ad
+			q2 &= mask
+			r2 &= mask
+		}
+
+		delta = ad - r2
+		delta &= mask
+		if q1 < delta || (q1 == delta && r1 == 0) {
+			continue
+		}
+
+		break
+	}
+
+	m.Sm = int64(q2 + 1)
+	if uint64(m.Sm)&two31 != 0 {
+		m.Sm |= ^int64(mask)
+	}
+	m.S = p - m.W
+}
+
+/*
+ * magic number for unsigned division
+ * see hacker's delight chapter 10
+ */
+func Umagic(m *Magic) {
+	var mask uint64
+
+	m.Bad = 0
+	m.Ua = 0
+
+	switch m.W {
+	default:
+		m.Bad = 1
+		return
+
+	case 8:
+		mask = 0xff
+
+	case 16:
+		mask = 0xffff
+
+	case 32:
+		mask = 0xffffffff
+
+	case 64:
+		mask = 0xffffffffffffffff
+	}
+
+	two31 := mask ^ (mask >> 1)
+
+	m.Ud &= mask
+	if m.Ud == 0 || m.Ud == two31 {
+		m.Bad = 1
+		return
+	}
+
+	nc := mask - (-m.Ud&mask)%m.Ud
+	p := m.W - 1
+
+	q1 := two31 / nc
+	r1 := two31 - q1*nc
+	q1 &= mask
+	r1 &= mask
+
+	q2 := (two31 - 1) / m.Ud
+	r2 := (two31 - 1) - q2*m.Ud
+	q2 &= mask
+	r2 &= mask
+
+	var delta uint64
+	for {
+		p++
+		if r1 >= nc-r1 {
+			q1 <<= 1
+			q1++
+			r1 <<= 1
+			r1 -= nc
+		} else {
+			q1 <<= 1
+			r1 <<= 1
+		}
+
+		q1 &= mask
+		r1 &= mask
+		if r2+1 >= m.Ud-r2 {
+			if q2 >= two31-1 {
+				m.Ua = 1
+			}
+
+			q2 <<= 1
+			q2++
+			r2 <<= 1
+			r2++
+			r2 -= m.Ud
+		} else {
+			if q2 >= two31 {
+				m.Ua = 1
+			}
+
+			q2 <<= 1
+			r2 <<= 1
+			r2++
+		}
+
+		q2 &= mask
+		r2 &= mask
+
+		delta = m.Ud - 1 - r2
+		delta &= mask
+
+		if p < m.W+m.W {
+			if q1 < delta || (q1 == delta && r1 == 0) {
+				continue
+			}
+		}
+
+		break
+	}
+
+	m.Um = q2 + 1
+	m.S = p - m.W
+}
+
+func ngotype(n *Node) *Sym {
+	if n.Type != nil {
+		return typenamesym(n.Type)
+	}
+	return nil
+}
+
+/*
+ * Convert raw string to the prefix that will be used in the symbol
+ * table.  All control characters, space, '%' and '"', as well as
+ * non-7-bit clean bytes turn into %xx.  The period needs escaping
+ * only in the last segment of the path, and it makes for happier
+ * users if we escape that as little as possible.
+ *
+ * If you edit this, edit ../ld/lib.c:/^pathtoprefix too.
+ * If you edit this, edit ../../debug/goobj/read.go:/importPathToPrefix too.
+ */
+func pathtoprefix(s string) string {
+	slash := strings.LastIndex(s, "/")
+	for i := 0; i < len(s); i++ {
+		c := s[i]
+		if c <= ' ' || i >= slash && c == '.' || c == '%' || c == '"' || c >= 0x7F {
+			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
+}
+
+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)
+	p.Syms = make(map[string]*Sym)
+	pkgMap[path] = p
+	pkgs = append(pkgs, p)
+	return p
+}
+
+func addinit(np **Node, init *NodeList) {
+	if init == nil {
+		return
+	}
+
+	n := *np
+	switch n.Op {
+	// There may be multiple refs to this node;
+	// introduce OCONVNOP to hold init list.
+	case ONAME, OLITERAL:
+		n = Nod(OCONVNOP, n, nil)
+
+		n.Type = n.Left.Type
+		n.Typecheck = 1
+		*np = n
+	}
+
+	n.Ninit = concat(init, n.Ninit)
+	n.Ullman = UINF
+}
+
+var reservedimports = []string{
+	"go",
+	"type",
+}
+
+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 == reservedimports[i] {
+			Yyerror("import path %q is reserved and cannot be used", path)
+			return true
+		}
+	}
+
+	var s string
+	_ = s
+	var r uint
+	_ = r
+	for _, r := range path {
+		if r == utf8.RuneError {
+			Yyerror("import path contains invalid UTF-8 sequence: %q", path)
+			return true
+		}
+
+		if r < 0x20 || r == 0x7f {
+			Yyerror("import path contains control character: %q", path)
+			return true
+		}
+
+		if r == '\\' {
+			Yyerror("import path contains backslash; use slash: %q", path)
+			return true
+		}
+
+		if unicode.IsSpace(rune(r)) {
+			Yyerror("import path contains space character: %q", path)
+			return true
+		}
+
+		if strings.ContainsRune("!\"#$%&'()*,:;<=>?[]^`{|}", r) {
+			Yyerror("import path contains invalid character '%c': %q", r, path)
+			return true
+		}
+	}
+
+	return false
+}
+
+func checknil(x *Node, init **NodeList) {
+	if Isinter(x.Type) {
+		x = Nod(OITAB, x, nil)
+		typecheck(&x, Erv)
+	}
+
+	n := Nod(OCHECKNIL, x, nil)
+	n.Typecheck = 1
+	*init = list(*init, n)
+}
+
+/*
+ * Can this type be stored directly in an interface word?
+ * Yes, if the representation is a single pointer.
+ */
+func isdirectiface(t *Type) bool {
+	switch t.Etype {
+	case TPTR32,
+		TPTR64,
+		TCHAN,
+		TMAP,
+		TFUNC,
+		TUNSAFEPTR:
+		return true
+
+		// Array of 1 direct iface type can be direct.
+	case TARRAY:
+		return t.Bound == 1 && isdirectiface(t.Type)
+
+		// Struct with 1 field of direct iface type can be direct.
+	case TSTRUCT:
+		return t.Type != nil && t.Type.Down == nil && isdirectiface(t.Type.Type)
+	}
+
+	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/compile/internal/gc/swt.go b/src/cmd/compile/internal/gc/swt.go
new file mode 100644
index 0000000..f34b1c6
--- /dev/null
+++ b/src/cmd/compile/internal/gc/swt.go
@@ -0,0 +1,848 @@
+// 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"
+	"sort"
+	"strconv"
+)
+
+const (
+	// expression switch
+	switchKindExpr  = iota // switch a {...} or switch 5 {...}
+	switchKindTrue         // switch true {...} or switch {...}
+	switchKindFalse        // switch false {...}
+
+	// type switch
+	switchKindType // switch a.(type) {...}
+)
+
+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*)
+}
+
+// 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
+}
+
+// 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
+}
+
+// typecheckswitch typechecks a switch statement.
+func typecheckswitch(n *Node) {
+	lno := int(lineno)
+	typechecklist(n.Ninit, Etop)
+
+	var nilonly string
+	var top int
+	var t *Type
+
+	if n.Left != nil && n.Left.Op == OTYPESW {
+		// type switch
+		top = Etype
+		typecheck(&n.Left.Right, Erv)
+		t = n.Left.Right.Type
+		if t != nil && t.Etype != TINTER {
+			Yyerror("cannot type switch on non-interface value %v", Nconv(n.Left.Right, obj.FmtLong))
+		}
+	} else {
+		// expression switch
+		top = Erv
+		if n.Left != nil {
+			typecheck(&n.Left, Erv)
+			defaultlit(&n.Left, nil)
+			t = n.Left.Type
+		} else {
+			t = Types[TBOOL]
+		}
+		if t != nil {
+			var badtype *Type
+			switch {
+			case !okforeq[t.Etype]:
+				Yyerror("cannot switch on %v", Nconv(n.Left, 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.Left, obj.FmtLong))
+			case t.Etype == TSTRUCT && algtype1(t, &badtype) == ANOEQ:
+				Yyerror("cannot switch on %v (struct containing %v cannot be compared)", Nconv(n.Left, obj.FmtLong), badtype)
+			case t.Etype == TFUNC:
+				nilonly = "func"
+			case t.Etype == TMAP:
+				nilonly = "map"
+			}
+		}
+	}
+
+	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", ll.N.Type)
+					case ll.N.Type != nil && assignop(ll.N.Type, t, nil) == 0 && assignop(t, ll.N.Type, nil) == 0:
+						if n.Left != nil {
+							Yyerror("invalid case %v in switch on %v (mismatched types %v and %v)", ll.N, n.Left, ll.N.Type, t)
+						} else {
+							Yyerror("invalid case %v in switch (mismatched types %v and bool)", ll.N, ll.N.Type)
+						}
+					case nilonly != "" && !Isconst(ll.N, CTNIL):
+						Yyerror("invalid case %v in switch (can only compare %s %v to nil)", ll.N, nilonly, n.Left)
+					}
+
+				// 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.Left.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.Left.Right, obj.FmtLong), ll.N.Type, missing.Sym, have.Sym, Tconv(have.Type, obj.FmtShort), missing.Sym, 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.Left.Right, obj.FmtLong), ll.N.Type, missing.Sym)
+						}
+					}
+				}
+			}
+		}
+
+		if top == Etype && n.Type != nil {
+			ll = ncase.List
+			if ncase.Rlist != nil {
+				nvar := ncase.Rlist.N
+				if ll != nil && ll.Next == nil && ll.N.Type != nil && !Istype(ll.N.Type, TNIL) {
+					// single entry type switch
+					nvar.Name.Param.Ntype = typenod(ll.N.Type)
+				} else {
+					// multiple entry type switch or default
+					nvar.Name.Param.Ntype = typenod(n.Type)
+				}
+
+				typecheck(&nvar, Erv|Easgn)
+				ncase.Rlist.N = nvar
+			}
+		}
+
+		typechecklist(ncase.Nbody, Etop)
+	}
+
+	lineno = int32(lno)
+}
+
+// walkswitch walks a switch statement.
+func walkswitch(sw *Node) {
+	// convert switch {...} to switch true {...}
+	if sw.Left == nil {
+		sw.Left = Nodbool(true)
+		typecheck(&sw.Left, Erv)
+	}
+
+	if sw.Left.Op == OTYPESW {
+		var s typeSwitch
+		s.walk(sw)
+	} else {
+		var s exprSwitch
+		s.walk(sw)
+	}
+}
+
+// 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)
+
+	cond := sw.Left
+	sw.Left = nil
+
+	s.kind = switchKindExpr
+	if Isconst(cond, CTBOOL) {
+		s.kind = switchKindTrue
+		if !cond.Val().U.(bool) {
+			s.kind = switchKindFalse
+		}
+	}
+
+	walkexpr(&cond, &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(cond) >= 0 {
+		// leave constants to enable dead code elimination (issue 9608)
+		s.exprname = cond
+	} else {
+		s.exprname = temp(cond.Type)
+		cas = list1(Nod(OAS, s.exprname, cond))
+		typechecklist(cas, Etop)
+	}
+
+	// enumerate the cases, and lop off the default case
+	cc := caseClauses(sw, s.kind)
+	sw.List = nil
+	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)
+		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.Left = Nod(OEQ, s.exprname, n.Left) // if name == val
+				typecheck(&a.Left, Erv)
+			} else if s.kind == switchKindTrue {
+				a.Left = n.Left // if val
+			} else {
+				// s.kind == switchKindFalse
+				a.Left = Nod(ONOT, n.Left, nil) // if !val
+				typecheck(&a.Left, 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.Left = Nod(OOROR, lenlt, Nod(OANDAND, leneq, le))
+	} else {
+		a.Left = le
+	}
+	typecheck(&a.Left, Erv)
+	a.Nbody = list1(s.walkCases(cc[:half]))
+	a.Rlist = 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
+	}
+
+	lno := setlineno(sw)
+
+	var cas *NodeList  // cases
+	var stat *NodeList // statements
+	var def *Node      // defaults
+	br := Nod(OBREAK, nil, nil)
+
+	for l := sw.List; l != nil; l = l.Next {
+		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
+
+		jmp := Nod(OGOTO, newCaseLabel(), nil)
+		if n.List == nil {
+			if def != nil {
+				Yyerror("more than one default case")
+			}
+			// reuse original default case
+			n.Right = jmp
+			def = n
+		}
+
+		if n.List != nil && n.List.Next == nil {
+			// 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 {
+				cas = list(cas, Nod(OCASE, lc.N, jmp))
+			}
+		}
+
+		stat = list(stat, Nod(OLABEL, jmp.Left, nil))
+		if typeswvar != nil && needvar && n.Rlist != nil {
+			l := list1(Nod(ODCL, n.Rlist.N, nil))
+			l = list(l, Nod(OAS, n.Rlist.N, typeswvar))
+			typechecklist(l, Etop)
+			stat = concat(stat, l)
+		}
+		stat = concat(stat, n.Nbody)
+
+		// botch - shouldn't fall thru declaration
+		last := stat.End.N
+		if last.Xoffset == n.Xoffset && last.Op == OXFALL {
+			if typeswvar != nil {
+				setlineno(last)
+				Yyerror("cannot fallthrough in type switch")
+			}
+
+			if l.Next == nil {
+				setlineno(last)
+				Yyerror("cannot fallthrough final case in switch")
+			}
+
+			last.Op = OFALL
+		} else {
+			stat = list(stat, br)
+		}
+	}
+
+	stat = list(stat, br)
+	if def != nil {
+		cas = list(cas, def)
+	}
+
+	sw.List = cas
+	sw.Nbody = stat
+	lineno = lno
+}
+
+// nSwitchLabel is the number of switch labels generated.
+// This should be per-function, but it is a global counter for now.
+var nSwitchLabel int
+
+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
+		c := new(caseClause)
+		cc = append(cc, c)
+		c.ordinal = len(cc)
+		c.node = n
+
+		if n.Left == nil {
+			c.typ = caseKindDefault
+			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)
+			}
+		} else {
+			// expression switch
+			switch consttype(n.Left) {
+			case CTFLT, CTINT, CTRUNE, CTSTR:
+				c.typ = caseKindExprConst
+			default:
+				c.typ = caseKindExprVar
+			}
+		}
+	}
+
+	if cc == nil {
+		return nil
+	}
+
+	// sort by value and diagnose duplicate cases
+	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 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", c2.node.Left.Type, c1.node.Line())
+				}
+			}
+		}
+	} 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(c2.node)
+			Yyerror("duplicate case %v in switch\n\tprevious case at %v", c1.node.Left, c1.node.Line())
+		}
+	}
+
+	// put list back in processing order
+	sort.Sort(caseClauseByOrd(cc))
+	return cc
+}
+
+// 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) {
+	cond := sw.Left
+	sw.Left = nil
+
+	if cond == nil {
+		sw.List = nil
+		return
+	}
+	if cond.Right == nil {
+		setlineno(sw)
+		Yyerror("type switch must have an assignment")
+		return
+	}
+
+	walkexpr(&cond.Right, &sw.Ninit)
+	if !Istype(cond.Right.Type, TINTER) {
+		Yyerror("type switch must be on an interface")
+		return
+	}
+
+	var cas *NodeList
+
+	// predeclare temporary variables and the boolean var
+	s.facename = temp(cond.Right.Type)
+
+	a := Nod(OAS, s.facename, cond.Right)
+	typecheck(&a, Etop)
+	cas = list(cas, a)
+
+	s.okname = temp(Types[TBOOL])
+	typecheck(&s.okname, Erv)
+
+	s.hashname = temp(Types[TUINT32])
+	typecheck(&s.hashname, Erv)
+
+	// set up labels and jumps
+	casebody(sw, s.facename)
+
+	// calculate type hash
+	t := cond.Right.Type
+	if isnilinter(t) {
+		a = syslook("efacethash", 1)
+	} else {
+		a = syslook("ifacethash", 1)
+	}
+	substArgTypes(a, t)
+	a = Nod(OCALL, a, nil)
+	a.List = list1(s.facename)
+	a = Nod(OAS, s.hashname, a)
+	typecheck(&a, Etop)
+	cas = list(cas, a)
+
+	cc := caseClauses(sw, switchKindType)
+	sw.List = nil
+	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)
+	}
+
+	// insert type equality check into each case block
+	for _, c := range cc {
+		n := c.node
+		switch c.typ {
+		case caseKindTypeNil:
+			var v Val
+			v.U = new(NilVal)
+			a = Nod(OIF, nil, nil)
+			a.Left = Nod(OEQ, s.facename, nodlit(v))
+			typecheck(&a.Left, Erv)
+			a.Nbody = list1(n.Right) // if i==nil { goto l }
+			n.Right = a
+
+		case caseKindTypeVar, caseKindTypeConst:
+			n.Right = s.typeone(n)
+		}
+	}
+
+	// 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)
+			cc = cc[1:]
+			continue
+		}
+
+		// identify run of constants
+		var run int
+		for run = 1; run < len(cc) && cc[run].typ == caseKindTypeConst; run++ {
+		}
+
+		// sort by hash
+		sort.Sort(caseClauseByType(cc[:run]))
+
+		// for debugging: linear search
+		if false {
+			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 i := 0; i < run; i++ {
+			ncase++
+			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)
+			}
+			cc[i].node.Right = liststmt(hash)
+		}
+
+		// binary search among cases to narrow by hash
+		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)
+		sw.List = nil
+		walkstmtlist(sw.Nbody)
+	}
+}
+
+// typeone generates an AST that jumps to the
+// case body if the variable is of type t.
+func (s *typeSwitch) typeone(t *Node) *Node {
+	var name *Node
+	var init *NodeList
+	if t.Rlist == nil {
+		name = nblank
+		typecheck(&nblank, Erv|Easgn)
+	} else {
+		name = t.Rlist.N
+		init = list1(Nod(ODCL, name, nil))
+		a := Nod(OAS, name, nil)
+		typecheck(&a, Etop)
+		init = list(init, a)
+	}
+
+	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)
+
+	c := Nod(OIF, nil, nil)
+	c.Left = s.okname
+	c.Nbody = list1(t.Right) // if ok { goto l }
+
+	return liststmt(list(init, c))
+}
+
+// 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.Left = Nod(OEQ, s.hashname, Nodintconst(int64(c.hash)))
+			typecheck(&a.Left, 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.Left = Nod(OLE, s.hashname, Nodintconst(int64(cc[half-1].hash)))
+	typecheck(&a.Left, Erv)
+	a.Nbody = list1(s.walkCases(cc[:half]))
+	a.Rlist = 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
+		}
+	}
+
+	// sort by constant value to enable binary search
+	switch ct {
+	case CTFLT:
+		return mpcmpfltflt(n1.Val().U.(*Mpflt), n2.Val().U.(*Mpflt))
+	case CTINT, CTRUNE:
+		return Mpcmpfixfix(n1.Val().U.(*Mpint), n2.Val().U.(*Mpint))
+	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.(string)
+		b := n2.Val().U.(string)
+		if len(a) < len(b) {
+			return -1
+		}
+		if len(a) > len(b) {
+			return +1
+		}
+		return stringsCompare(a, b)
+	}
+
+	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/compile/internal/gc/syntax.go b/src/cmd/compile/internal/gc/syntax.go
new file mode 100644
index 0000000..7f03a4e
--- /dev/null
+++ b/src/cmd/compile/internal/gc/syntax.go
@@ -0,0 +1,484 @@
+// 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
+	Ninit *NodeList
+	Nbody *NodeList
+	List  *NodeList
+	Rlist *NodeList
+
+	// most nodes
+	Type *Type
+	Orig *Node // original form, for printing, and tracking copies of ONAMEs
+
+	// func
+	Func *Func
+
+	// ONAME
+	Name *Name
+
+	Sym *Sym        // various
+	E   interface{} // Opt or Val, see methods below
+
+	Xoffset int64
+
+	Lineno int32
+
+	// OREGISTER, OINDREG
+	Reg int16
+
+	Esc uint16 // EscXXX
+
+	Op          uint8
+	Nointerface bool
+	Ullman      uint8 // sethi/ullman number
+	Addable     bool  // addressable
+	Etype       uint8 // op for OASOP, etype for OTYPE, exclam for export, 6g saved reg
+	Bounded     bool  // bounds check unnecessary
+	Class       uint8 // PPARAM, PAUTO, PEXTERN, etc
+	Embedded    uint8 // ODCLFIELD embedded type
+	Colas       bool  // 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
+	Implicit    bool
+	Addrtaken   bool // address taken, even if not moved to heap
+	Assigned    bool // is the variable ever assigned to
+	Likely      int8 // likeliness of if statement
+	Hasbreak    bool // has break statement
+	hasVal      int8 // +1 for Val, -1 for Opt, 0 for not yet set
+}
+
+// Val returns the Val for the node.
+func (n *Node) Val() Val {
+	if n.hasVal != +1 {
+		return Val{}
+	}
+	return Val{n.E}
+}
+
+// SetVal sets the Val for the node, which must not have been used with SetOpt.
+func (n *Node) SetVal(v Val) {
+	if n.hasVal == -1 {
+		Debug['h'] = 1
+		Dump("have Opt", n)
+		Fatal("have Opt")
+	}
+	n.hasVal = +1
+	n.E = v.U
+}
+
+// Opt returns the optimizer data for the node.
+func (n *Node) Opt() interface{} {
+	if n.hasVal != -1 {
+		return nil
+	}
+	return n.E
+}
+
+// SetOpt sets the optimizer data for the node, which must not have been used with SetVal.
+// SetOpt(nil) is ignored for Vals to simplify call sites that are clearing Opts.
+func (n *Node) SetOpt(x interface{}) {
+	if x == nil && n.hasVal >= 0 {
+		return
+	}
+	if n.hasVal == +1 {
+		Debug['h'] = 1
+		Dump("have Val", n)
+		Fatal("have Val")
+	}
+	n.hasVal = -1
+	n.E = x
+}
+
+// Name holds Node fields used only by named nodes (ONAME, OPACK, some OLITERAL).
+type Name struct {
+	Pack      *Node // real package for import . names
+	Pkg       *Pkg  // pkg for OPACK nodes
+	Heapaddr  *Node // temp holding heap address of param
+	Inlvar    *Node // ONAME substitute while inlining
+	Defn      *Node // initializing assignment
+	Curfn     *Node // function for local variables
+	Param     *Param
+	Decldepth int32 // declaration loop depth, increased for every loop or label
+	Vargen    int32 // unique name for ONAME within a function.  Function outputs are numbered starting at one.
+	Iota      int32 // value if this name is iota
+	Funcdepth int32
+	Method    bool // OCALLMETH name
+	Readonly  bool
+	Captured  bool // is the variable captured by a closure
+	Byval     bool // is the variable captured by value or by reference
+	Needzero  bool // if it contains pointers, needs to be zeroed on function entry
+}
+
+type Param struct {
+	Ntype *Node
+
+	// ONAME func param with PHEAP
+	Outerexpr  *Node // expression copied into closure for variable
+	Stackparam *Node // OPARAM node referring to stack copy of param
+
+	// ONAME PPARAM
+	Field *Type // TFIELD in arg struct
+
+	// ONAME closure param with PPARAMREF
+	Outer   *Node // outer PPARAMREF in nested closure
+	Closure *Node // ONAME/PHEAP <-> ONAME/PPARAMREF
+}
+
+// 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
+	Fieldtrack []*Type
+	Outer      *Node // outer func for closure
+	Ntype      *Node // signature
+	Top        int   // top context (Ecall, Eproc, etc)
+	Closure    *Node // OCLOSURE <-> ODCLFUNC
+	FCurfn     *Node
+	Nname      *Node
+
+	Inl     *NodeList // copy of the body for use in inlining
+	InlCost int32
+	Depth   int32
+
+	Endlineno int32
+
+	Norace         bool // func must not have race detector annotations
+	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)
+	Systemstack    bool // must run on system stack
+}
+
+// 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             // Left + Right
+	OSUB             // Left - Right
+	OOR              // Left | Right
+	OXOR             // Left ^ Right
+	OADDSTR          // Left + Right (string addition)
+	OADDR            // &Left
+	OANDAND          // Left && Right
+	OAPPEND          // append(List)
+	OARRAYBYTESTR    // Type(Left) (Type is string, Left is a []byte)
+	OARRAYBYTESTRTMP // Type(Left) (Type is string, Left is a []byte, ephemeral)
+	OARRAYRUNESTR    // Type(Left) (Type is string, Left is a []rune)
+	OSTRARRAYBYTE    // Type(Left) (Type is []byte, Left is a string)
+	OSTRARRAYBYTETMP // Type(Left) (Type is []byte, Left is a string, ephemeral)
+	OSTRARRAYRUNE    // Type(Left) (Type is []rune, Left is a string)
+	OAS              // Left = Right or (if Colas=true) Left := Right
+	OAS2             // List = Rlist (x, y, z = a, b, c)
+	OAS2FUNC         // List = Rlist (x, y = f())
+	OAS2RECV         // List = Rlist (x, ok = <-c)
+	OAS2MAPR         // List = Rlist (x, ok = m["foo"])
+	OAS2DOTTYPE      // List = Rlist (x, ok = I.(int))
+	OASOP            // Left Etype= Right (x += y)
+	OASWB            // Left = Right (with write barrier)
+	OCALL            // Left(List) (function call, method call or type conversion)
+	OCALLFUNC        // Left(List) (function call f(args))
+	OCALLMETH        // Left(List) (direct method call x.Method(args))
+	OCALLINTER       // Left(List) (interface method call x.Method(args))
+	OCALLPART        // Left.Right (method expression x.Method, not called)
+	OCAP             // cap(Left)
+	OCLOSE           // close(Left)
+	OCLOSURE         // func Type { Body } (func literal)
+	OCMPIFACE        // Left Etype Right (interface comparison, x == y or x != y)
+	OCMPSTR          // Left Etype Right (string comparison, x == y, x < y, etc)
+	OCOMPLIT         // Right{List} (composite literal, not yet lowered to specific form)
+	OMAPLIT          // Type{List} (composite literal, Type is map)
+	OSTRUCTLIT       // Type{List} (composite literal, Type is struct)
+	OARRAYLIT        // Type{List} (composite literal, Type is array or slice)
+	OPTRLIT          // &Left (left is composite literal)
+	OCONV            // Type(Left) (type conversion)
+	OCONVIFACE       // Type(Left) (type conversion, to interface)
+	OCONVNOP         // Type(Left) (type conversion, no effect)
+	OCOPY            // copy(Left, Right)
+	ODCL             // var Left (declares Left of type Left.Type)
+
+	// Used during parsing but don't last.
+	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(Left, Right)
+	ODOT       // Left.Right (Left is of struct type)
+	ODOTPTR    // Left.Right (Left is of pointer to struct type)
+	ODOTMETH   // Left.Right (Left is non-interface, Right is method name)
+	ODOTINTER  // Left.Right (Left is interface, Right is method name)
+	OXDOT      // Left.Right (before rewrite to one of the preceding)
+	ODOTTYPE   // Left.Right or Left.Type (.Right during parsing, .Type once resolved)
+	ODOTTYPE2  // Left.Right or Left.Type (.Right during parsing, .Type once resolved; on rhs of OAS2DOTTYPE)
+	OEQ        // Left == Right
+	ONE        // Left != Right
+	OLT        // Left < Right
+	OLE        // Left <= Right
+	OGE        // Left >= Right
+	OGT        // Left > Right
+	OIND       // *Left
+	OINDEX     // Left[Right] (index of array or slice)
+	OINDEXMAP  // Left[Right] (index of map)
+	OKEY       // Left:Right (key:value in struct/array/map literal, or slice index pair)
+	OPARAM     // variant of ONAME for on-stack copy of a parameter or return value that escapes.
+	OLEN       // len(Left)
+	OMAKE      // make(List) (before type checking converts to one of the following)
+	OMAKECHAN  // make(Type, Left) (type is chan)
+	OMAKEMAP   // make(Type, Left) (type is map)
+	OMAKESLICE // make(Type, Left, Right) (type is slice)
+	OMUL       // Left * Right
+	ODIV       // Left / Right
+	OMOD       // Left % Right
+	OLSH       // Left << Right
+	ORSH       // Left >> Right
+	OAND       // Left & Right
+	OANDNOT    // Left &^ Right
+	ONEW       // new(Left)
+	ONOT       // !Left
+	OCOM       // ^Left
+	OPLUS      // +Left
+	OMINUS     // -Left
+	OOROR      // Left || Right
+	OPANIC     // panic(Left)
+	OPRINT     // print(List)
+	OPRINTN    // println(List)
+	OPAREN     // (Left)
+	OSEND      // Left <- Right
+	OSLICE     // Left[Right.Left : Right.Right] (Left is untypechecked or slice; Right.Op==OKEY)
+	OSLICEARR  // Left[Right.Left : Right.Right] (Left is array)
+	OSLICESTR  // Left[Right.Left : Right.Right] (Left is string)
+	OSLICE3    // Left[R.Left : R.R.Left : R.R.R] (R=Right; Left is untypedchecked or slice; R.Op and R.R.Op==OKEY)
+	OSLICE3ARR // Left[R.Left : R.R.Left : R.R.R] (R=Right; Left is array; R.Op and R.R.Op==OKEY)
+	ORECOVER   // recover()
+	ORECV      // <-Left
+	ORUNESTR   // Type(Left) (Type is string, Left is rune)
+	OSELRECV   // Left = <-Right.Left: (appears as .Left of OCASE; Right.Op == ORECV)
+	OSELRECV2  // List = <-Right.Left: (apperas as .Left of OCASE; count(List) == 2, Right.Op == ORECV)
+	OIOTA      // iota
+	OREAL      // real(Left)
+	OIMAG      // imag(Left)
+	OCOMPLEX   // complex(Left, Right)
+
+	// statements
+	OBLOCK    // { List } (block of code)
+	OBREAK    // break
+	OCASE     // case List: Nbody (select case after processing; List==nil means default)
+	OXCASE    // case List: Nbody (select case before processing; List==nil means default)
+	OCONTINUE // continue
+	ODEFER    // defer Left (Left must be call)
+	OEMPTY    // no-op (empty statement)
+	OFALL     // fallthrough (after processing)
+	OXFALL    // fallthrough (before processing)
+	OFOR      // for Ninit; Left; Right { Nbody }
+	OGOTO     // goto Left
+	OIF       // if Ninit; Left { Nbody } else { Rlist }
+	OLABEL    // Left:
+	OPROC     // go Left (Left must be call)
+	ORANGE    // for List = range Right { Nbody }
+	ORETURN   // return List
+	OSELECT   // select { List } (List is list of OXCASE or OCASE)
+	OSWITCH   // switch Ninit; Left { List } (List is a list of OXCASE or OCASE)
+	OTYPESW   // List = Left.(type) (appears as .Left of OSWITCH)
+
+	// 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).
+
+	// arch-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)
+	OPC     // compare parity clear (for x86 NaN check)
+	OSQRT   // sqrt(float64), on systems that have hw support
+	OGETG   // runtime.getg() (read g pointer)
+
+	OEND
+)
+
+// 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/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go
new file mode 100644
index 0000000..befe3b2
--- /dev/null
+++ b/src/cmd/compile/internal/gc/typecheck.go
@@ -0,0 +1,4035 @@
+// 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"
+	"math"
+	"strings"
+)
+
+/*
+ * type check the whole tree of an expression.
+ * calculates expression types.
+ * evaluates compile time constants.
+ * marks variables that escape the local frame.
+ * rewrites n->op to be more specific in some cases.
+ */
+var typecheckdefstack *NodeList
+
+/*
+ * resolve ONONAME to definition, if any.
+ */
+func resolve(n *Node) *Node {
+	if n != nil && n.Op == ONONAME && n.Sym != nil {
+		r := n.Sym.Def
+		if r != nil {
+			if r.Op != OIOTA {
+				n = r
+			} else if n.Name.Iota >= 0 {
+				n = Nodintconst(int64(n.Name.Iota))
+			}
+		}
+	}
+
+	return n
+}
+
+func typechecklist(l *NodeList, top int) {
+	for ; l != nil; l = l.Next {
+		typecheck(&l.N, top)
+	}
+}
+
+var _typekind = []string{
+	TINT:        "int",
+	TUINT:       "uint",
+	TINT8:       "int8",
+	TUINT8:      "uint8",
+	TINT16:      "int16",
+	TUINT16:     "uint16",
+	TINT32:      "int32",
+	TUINT32:     "uint32",
+	TINT64:      "int64",
+	TUINT64:     "uint64",
+	TUINTPTR:    "uintptr",
+	TCOMPLEX64:  "complex64",
+	TCOMPLEX128: "complex128",
+	TFLOAT32:    "float32",
+	TFLOAT64:    "float64",
+	TBOOL:       "bool",
+	TSTRING:     "string",
+	TPTR32:      "pointer",
+	TPTR64:      "pointer",
+	TUNSAFEPTR:  "unsafe.Pointer",
+	TSTRUCT:     "struct",
+	TINTER:      "interface",
+	TCHAN:       "chan",
+	TMAP:        "map",
+	TARRAY:      "array",
+	TFUNC:       "func",
+	TNIL:        "nil",
+	TIDEAL:      "untyped number",
+}
+
+func typekind(t *Type) string {
+	if Isslice(t) {
+		return "slice"
+	}
+	et := int(t.Etype)
+	if 0 <= et && et < len(_typekind) {
+		s := _typekind[et]
+		if s != "" {
+			return s
+		}
+	}
+	return fmt.Sprintf("etype=%d", et)
+}
+
+/*
+ * sprint_depchain prints a dependency chain
+ * of nodes into fmt.
+ * It is used by typecheck in the case of OLITERAL nodes
+ * to print constant definition loops.
+ */
+func sprint_depchain(fmt_ *string, stack *NodeList, cur *Node, first *Node) {
+	for l := stack; l != nil; l = l.Next {
+		if l.N.Op == cur.Op {
+			if l.N != first {
+				sprint_depchain(fmt_, l.Next, l.N, first)
+			}
+			*fmt_ += fmt.Sprintf("\n\t%v: %v uses %v", l.N.Line(), l.N, cur)
+			return
+		}
+	}
+}
+
+/*
+ * type check node *np.
+ * replaces *np with a new pointer in some cases.
+ * returns the final value of *np as a convenience.
+ */
+
+var typecheck_tcstack *NodeList
+var typecheck_tcfree *NodeList
+
+func typecheck(np **Node, top int) *Node {
+	// cannot type check until all the source has been parsed
+	if typecheckok == 0 {
+		Fatal("early typecheck")
+	}
+
+	n := *np
+	if n == nil {
+		return nil
+	}
+
+	lno := int(setlineno(n))
+
+	// Skip over parens.
+	for n.Op == OPAREN {
+		n = n.Left
+	}
+
+	// Resolve definition of name and value of iota lazily.
+	n = resolve(n)
+
+	*np = n
+
+	// Skip typecheck if already done.
+	// 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:
+			break
+
+		default:
+			lineno = int32(lno)
+			return n
+		}
+	}
+
+	if n.Typecheck == 2 {
+		// Typechecking loop. Trying printing a meaningful message,
+		// otherwise a stack trace of typechecking.
+		var fmt_ string
+		switch n.Op {
+		// We can already diagnose variables used as types.
+		case ONAME:
+			if top&(Erv|Etype) == Etype {
+				Yyerror("%v is not a type", n)
+			}
+
+		case OLITERAL:
+			if top&(Erv|Etype) == Etype {
+				Yyerror("%v is not a type", n)
+				break
+			}
+
+			fmt_ = ""
+			sprint_depchain(&fmt_, typecheck_tcstack, n, n)
+			yyerrorl(int(n.Lineno), "constant definition loop%s", fmt_)
+		}
+
+		if nsavederrors+nerrors == 0 {
+			fmt_ = ""
+			for l := typecheck_tcstack; l != nil; l = l.Next {
+				fmt_ += fmt.Sprintf("\n\t%v %v", l.N.Line(), l.N)
+			}
+			Yyerror("typechecking loop involving %v%s", n, fmt_)
+		}
+
+		lineno = int32(lno)
+		return n
+	}
+
+	n.Typecheck = 2
+
+	var l *NodeList
+	if typecheck_tcfree != nil {
+		l = typecheck_tcfree
+		typecheck_tcfree = l.Next
+	} else {
+		l = new(NodeList)
+	}
+	l.Next = typecheck_tcstack
+	l.N = n
+	typecheck_tcstack = l
+
+	typecheck1(&n, top)
+	*np = n
+	n.Typecheck = 1
+
+	if typecheck_tcstack != l {
+		Fatal("typecheck stack out of sync")
+	}
+	typecheck_tcstack = l.Next
+	l.Next = typecheck_tcfree
+	typecheck_tcfree = l
+
+	lineno = int32(lno)
+	return n
+}
+
+/*
+ * does n contain a call or receive operation?
+ */
+func callrecv(n *Node) bool {
+	if n == nil {
+		return false
+	}
+
+	switch n.Op {
+	case OCALL,
+		OCALLMETH,
+		OCALLINTER,
+		OCALLFUNC,
+		ORECV,
+		OCAP,
+		OLEN,
+		OCOPY,
+		ONEW,
+		OAPPEND,
+		ODELETE:
+		return true
+	}
+
+	return callrecv(n.Left) || callrecv(n.Right) || callrecvlist(n.Ninit) || callrecvlist(n.Nbody) || callrecvlist(n.List) || callrecvlist(n.Rlist)
+}
+
+func callrecvlist(l *NodeList) bool {
+	for ; l != nil; l = l.Next {
+		if callrecv(l.N) {
+			return true
+		}
+	}
+	return false
+}
+
+// indexlit implements typechecking of untyped values as
+// array/slice indexes. It is equivalent to defaultlit
+// except for constants of numerical kind, which are acceptable
+// whenever they can be represented by a value of type int.
+func indexlit(np **Node) {
+	n := *np
+	if n == nil || !isideal(n.Type) {
+		return
+	}
+	switch consttype(n) {
+	case CTINT, CTRUNE, CTFLT, CTCPLX:
+		defaultlit(np, Types[TINT])
+	}
+
+	defaultlit(np, nil)
+}
+
+func typecheck1(np **Node, top int) {
+	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", n.Sym)
+			n.Type = nil
+			return
+		}
+
+		typecheckdef(n)
+		if n.Op == ONONAME {
+			n.Type = nil
+			return
+		}
+	}
+
+	ok := 0
+OpSwitch:
+	switch n.Op {
+	// until typecheck is complete, do nothing.
+	default:
+		Dump("typecheck", n)
+
+		Fatal("typecheck %v", Oconv(int(n.Op), 0))
+
+		/*
+		 * names
+		 */
+	case OLITERAL:
+		ok |= Erv
+
+		if n.Type == nil && n.Val().Ctype() == CTSTR {
+			n.Type = idealstring
+		}
+		break OpSwitch
+
+	case ONONAME:
+		ok |= Erv
+		break OpSwitch
+
+	case ONAME:
+		if n.Name.Decldepth == 0 {
+			n.Name.Decldepth = decldepth
+		}
+		if n.Etype != 0 {
+			ok |= Ecall
+			break OpSwitch
+		}
+
+		if top&Easgn == 0 {
+			// not a write to the variable
+			if isblank(n) {
+				Yyerror("cannot use _ as value")
+				n.Type = nil
+				return
+			}
+
+			n.Used = true
+		}
+
+		if top&Ecall == 0 && isunsafebuiltin(n) {
+			Yyerror("%v is not an expression, must be called", n)
+			n.Type = nil
+			return
+		}
+
+		ok |= Erv
+		break OpSwitch
+
+	case OPACK:
+		Yyerror("use of package %v without selector", n.Sym)
+		n.Type = nil
+		return
+
+	case ODDD:
+		break
+
+		/*
+		 * types (OIND is with exprs)
+		 */
+	case OTYPE:
+		ok |= Etype
+
+		if n.Type == nil {
+			n.Type = nil
+			return
+		}
+
+	case OTARRAY:
+		ok |= Etype
+		t := typ(TARRAY)
+		l := n.Left
+		r := n.Right
+		if l == nil {
+			t.Bound = -1 // slice
+		} else if l.Op == ODDD {
+			t.Bound = -100 // to be filled in
+			if top&Ecomplit == 0 && n.Diag == 0 {
+				t.Broke = 1
+				n.Diag = 1
+				Yyerror("use of [...] array outside of array literal")
+			}
+		} else {
+			l := typecheck(&n.Left, Erv)
+			var v Val
+			switch consttype(l) {
+			case CTINT, CTRUNE:
+				v = l.Val()
+
+			case CTFLT:
+				v = toint(l.Val())
+
+			default:
+				if l.Type != nil && Isint[l.Type.Etype] && l.Op != OLITERAL {
+					Yyerror("non-constant array bound %v", l)
+				} else {
+					Yyerror("invalid array bound %v", l)
+				}
+				n.Type = nil
+				return
+			}
+
+			t.Bound = Mpgetfix(v.U.(*Mpint))
+			if doesoverflow(v, Types[TINT]) {
+				Yyerror("array bound is too large")
+				n.Type = nil
+				return
+			} else if t.Bound < 0 {
+				Yyerror("array bound must be non-negative")
+				n.Type = nil
+				return
+			}
+		}
+
+		typecheck(&r, Etype)
+		if r.Type == nil {
+			n.Type = nil
+			return
+		}
+		t.Type = r.Type
+		n.Op = OTYPE
+		n.Type = t
+		n.Left = nil
+		n.Right = nil
+		if t.Bound != -100 {
+			checkwidth(t)
+		}
+
+	case OTMAP:
+		ok |= Etype
+		l := typecheck(&n.Left, Etype)
+		r := typecheck(&n.Right, Etype)
+		if l.Type == nil || r.Type == nil {
+			n.Type = nil
+			return
+		}
+		n.Op = OTYPE
+		n.Type = maptype(l.Type, r.Type)
+		n.Left = nil
+		n.Right = nil
+
+	case OTCHAN:
+		ok |= Etype
+		l := typecheck(&n.Left, Etype)
+		if l.Type == nil {
+			n.Type = nil
+			return
+		}
+		t := typ(TCHAN)
+		t.Type = l.Type
+		t.Chan = n.Etype
+		n.Op = OTYPE
+		n.Type = t
+		n.Left = nil
+		n.Etype = 0
+
+	case OTSTRUCT:
+		ok |= Etype
+		n.Op = OTYPE
+		n.Type = tostruct(n.List)
+		if n.Type == nil || n.Type.Broke != 0 {
+			n.Type = nil
+			return
+		}
+		n.List = nil
+
+	case OTINTER:
+		ok |= Etype
+		n.Op = OTYPE
+		n.Type = tointerface(n.List)
+		if n.Type == nil {
+			n.Type = nil
+			return
+		}
+
+	case OTFUNC:
+		ok |= Etype
+		n.Op = OTYPE
+		n.Type = functype(n.Left, n.List, n.Rlist)
+		if n.Type == nil {
+			n.Type = nil
+			return
+		}
+
+		/*
+		 * type or expr
+		 */
+	case OIND:
+		ntop := Erv | Etype
+
+		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
+		if t == nil {
+			n.Type = nil
+			return
+		}
+		if l.Op == OTYPE {
+			ok |= Etype
+			n.Op = OTYPE
+			n.Type = Ptrto(l.Type)
+			n.Left = nil
+			break OpSwitch
+		}
+
+		if !Isptr[t.Etype] {
+			if top&(Erv|Etop) != 0 {
+				Yyerror("invalid indirect of %v", Nconv(n.Left, obj.FmtLong))
+				n.Type = nil
+				return
+			}
+
+			break OpSwitch
+		}
+
+		ok |= Erv
+		n.Type = t.Type
+		break OpSwitch
+
+		/*
+		 * arithmetic exprs
+		 */
+	case OASOP,
+		OADD,
+		OAND,
+		OANDAND,
+		OANDNOT,
+		ODIV,
+		OEQ,
+		OGE,
+		OGT,
+		OHMUL,
+		OLE,
+		OLT,
+		OLSH,
+		ORSH,
+		OMOD,
+		OMUL,
+		ONE,
+		OOR,
+		OOROR,
+		OSUB,
+		OXOR:
+		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)
+		}
+		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)", n, r.Type)
+				n.Type = nil
+				return
+			}
+
+			t = l.Type
+			if t != nil && t.Etype != TIDEAL && !Isint[t.Etype] {
+				Yyerror("invalid operation: %v (shift of type %v)", n, t)
+				n.Type = nil
+				return
+			}
+
+			// no defaultlit for left
+			// the outer context gives the type
+			n.Type = l.Type
+
+			break OpSwitch
+		}
+
+		// 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)", n, 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)", n, 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)", n, l.Type)
+				n.Type = nil
+				return
+			}
+
+			if Isinter(r.Type) == Isinter(l.Type) || aop == 0 {
+				Yyerror("invalid operation: %v (mismatched types %v and %v)", n, l.Type, r.Type)
+				n.Type = nil
+				return
+			}
+		}
+
+		if !okfor[op][et] {
+			Yyerror("invalid operation: %v (operator %v not defined on %s)", n, 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)", n, l.Type)
+			n.Type = nil
+			return
+		}
+
+		if Isslice(l.Type) && !isnil(l) && !isnil(r) {
+			Yyerror("invalid operation: %v (slice can only be compared to nil)", n)
+			n.Type = nil
+			return
+		}
+
+		if l.Type.Etype == TMAP && !isnil(l) && !isnil(r) {
+			Yyerror("invalid operation: %v (map can only be compared to nil)", n)
+			n.Type = nil
+			return
+		}
+
+		if l.Type.Etype == TFUNC && !isnil(l) && !isnil(r) {
+			Yyerror("invalid operation: %v (func can only be compared to nil)", n)
+			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)", n, badtype)
+			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.(*Mpint), 0) == 0 {
+				Yyerror("division by zero")
+				n.Type = nil
+				return
+			}
+		}
+
+		n.Type = t
+		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), t)
+			n.Type = nil
+			return
+		}
+
+		n.Type = t
+		break OpSwitch
+
+		/*
+		 * exprs
+		 */
+	case OADDR:
+		ok |= Erv
+
+		typecheck(&n.Left, Erv|Eaddr)
+		if n.Left.Type == nil {
+			n.Type = nil
+			return
+		}
+		checklvalue(n.Left, "take the address of")
+		r := outervalue(n.Left)
+		var l *Node
+		for l = n.Left; l != r; l = l.Left {
+			l.Addrtaken = true
+			if l.Name != nil && l.Name.Param != nil && l.Name.Param.Closure != nil {
+				l.Name.Param.Closure.Addrtaken = true
+			}
+		}
+
+		if l.Orig != l && l.Op == ONAME {
+			Fatal("found non-orig name node %v", l)
+		}
+		l.Addrtaken = true
+		if l.Name != nil && l.Name.Param != nil && l.Name.Param.Closure != nil {
+			l.Name.Param.Closure.Addrtaken = true
+		}
+		defaultlit(&n.Left, nil)
+		l = n.Left
+		t := l.Type
+		if t == nil {
+			n.Type = nil
+			return
+		}
+		n.Type = Ptrto(t)
+		break OpSwitch
+
+	case OCOMPLIT:
+		ok |= Erv
+		typecheckcomplit(&n)
+		if n.Type == nil {
+			n.Type = nil
+			return
+		}
+		break OpSwitch
+
+	case OXDOT, ODOT:
+		if n.Op == OXDOT {
+			n = adddot(n)
+			n.Op = ODOT
+			if n.Left == nil {
+				n.Type = nil
+				return
+			}
+		}
+
+		typecheck(&n.Left, Erv|Etype)
+
+		defaultlit(&n.Left, nil)
+		if n.Right.Op != ONAME {
+			Yyerror("rhs of . must be a name") // impossible
+			n.Type = nil
+			return
+		}
+
+		t := n.Left.Type
+		if t == nil {
+			adderrorname(n)
+			n.Type = nil
+			return
+		}
+
+		r := n.Right
+
+		if n.Left.Op == OTYPE {
+			if !looktypedot(n, t, 0) {
+				if looktypedot(n, t, 1) {
+					Yyerror("%v undefined (cannot refer to unexported method %v)", n, n.Right.Sym)
+				} else {
+					Yyerror("%v undefined (type %v has no method %v)", n, t, n.Right.Sym)
+				}
+				n.Type = nil
+				return
+			}
+
+			if n.Type.Etype != TFUNC || n.Type.Thistuple != 1 {
+				Yyerror("type %v has no method %v", n.Left.Type, Sconv(n.Right.Sym, obj.FmtShort))
+				n.Type = nil
+				n.Type = nil
+				return
+			}
+
+			n.Op = ONAME
+			if n.Name == nil {
+				n.Name = new(Name)
+			}
+			n.Sym = n.Right.Sym
+			n.Type = methodfunc(n.Type, n.Left.Type)
+			n.Xoffset = 0
+			n.Class = PFUNC
+			ok = Erv
+			break OpSwitch
+		}
+
+		if Isptr[t.Etype] && t.Type.Etype != TINTER {
+			t = t.Type
+			if t == nil {
+				n.Type = nil
+				return
+			}
+			n.Op = ODOTPTR
+			checkwidth(t)
+		}
+
+		if isblank(n.Right) {
+			Yyerror("cannot refer to blank field or method")
+			n.Type = nil
+			return
+		}
+
+		if lookdot(n, t, 0) == nil {
+			// Legitimate field or method lookup failed, try to explain the error
+			switch {
+			case isnilinter(t):
+				Yyerror("%v undefined (type %v is interface with no methods)", n, n.Left.Type)
+
+			case Isptr[t.Etype] && Isinter(t.Type):
+				// Pointer to interface is almost always a mistake.
+				Yyerror("%v undefined (type %v is pointer to interface, not interface)", n, n.Left.Type)
+
+			case lookdot(n, t, 1) != nil:
+				// Field or method matches by name, but it is not exported.
+				Yyerror("%v undefined (cannot refer to unexported field or method %v)", n, n.Right.Sym)
+
+			default:
+				if mt := lookdot(n, t, 2); mt != nil { // Case-insensitive lookup.
+					Yyerror("%v undefined (type %v has no field or method %v, but does have %v)", n, n.Left.Type, n.Right.Sym, mt.Sym)
+				} else {
+					Yyerror("%v undefined (type %v has no field or method %v)", n, n.Left.Type, n.Right.Sym)
+				}
+			}
+			n.Type = nil
+			return
+		}
+
+		switch n.Op {
+		case ODOTINTER, ODOTMETH:
+			if top&Ecall != 0 {
+				ok |= Ecall
+			} else {
+				typecheckpartialcall(n, r)
+				ok |= Erv
+			}
+
+		default:
+			ok |= Erv
+		}
+
+		break OpSwitch
+
+	case ODOTTYPE:
+		ok |= Erv
+		typecheck(&n.Left, Erv)
+		defaultlit(&n.Left, nil)
+		l := n.Left
+		t := l.Type
+		if t == nil {
+			n.Type = nil
+			return
+		}
+		if !Isinter(t) {
+			Yyerror("invalid type assertion: %v (non-interface type %v on left)", n, t)
+			n.Type = nil
+			return
+		}
+
+		if n.Right != nil {
+			typecheck(&n.Right, Etype)
+			n.Type = n.Right.Type
+			n.Right = nil
+			if n.Type == nil {
+				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", n.Type, t, missing.Sym, have.Sym, Tconv(have.Type, obj.FmtShort|obj.FmtByte), missing.Sym, Tconv(missing.Type, obj.FmtShort|obj.FmtByte))
+				} else if ptr != 0 {
+					Yyerror("impossible type assertion:\n\t%v does not implement %v (%v method has pointer receiver)", n.Type, t, missing.Sym)
+				} else if have != nil {
+					Yyerror("impossible type assertion:\n\t%v does not implement %v (missing %v method)\n"+"\t\thave %v%v\n\t\twant %v%v", n.Type, t, missing.Sym, have.Sym, Tconv(have.Type, obj.FmtShort|obj.FmtByte), missing.Sym, Tconv(missing.Type, obj.FmtShort|obj.FmtByte))
+				} else {
+					Yyerror("impossible type assertion:\n\t%v does not implement %v (missing %v method)", n.Type, t, missing.Sym)
+				}
+				n.Type = nil
+				return
+			}
+		}
+
+		break OpSwitch
+
+	case OINDEX:
+		ok |= Erv
+		typecheck(&n.Left, Erv)
+		defaultlit(&n.Left, nil)
+		implicitstar(&n.Left)
+		l := n.Left
+		typecheck(&n.Right, Erv)
+		r := n.Right
+		t := l.Type
+		if t == nil || r.Type == nil {
+			n.Type = nil
+			return
+		}
+		switch t.Etype {
+		default:
+			Yyerror("invalid operation: %v (type %v does not support indexing)", n, t)
+			n.Type = nil
+			return
+
+		case TSTRING, TARRAY:
+			indexlit(&n.Right)
+			if t.Etype == TSTRING {
+				n.Type = bytetype
+			} else {
+				n.Type = t.Type
+			}
+			why := "string"
+			if t.Etype == TARRAY {
+				if Isfixedarray(t) {
+					why = "array"
+				} else {
+					why = "slice"
+				}
+			}
+
+			if n.Right.Type != nil && !Isint[n.Right.Type.Etype] {
+				Yyerror("non-integer %s index %v", why, n.Right)
+				break
+			}
+
+			if Isconst(n.Right, CTINT) {
+				x := Mpgetfix(n.Right.Val().U.(*Mpint))
+				if x < 0 {
+					Yyerror("invalid %s index %v (index must be non-negative)", why, n.Right)
+				} else if Isfixedarray(t) && t.Bound > 0 && x >= t.Bound {
+					Yyerror("invalid array index %v (out of bounds for %d-element array)", n.Right, t.Bound)
+				} else if Isconst(n.Left, CTSTR) && x >= int64(len(n.Left.Val().U.(string))) {
+					Yyerror("invalid string index %v (out of bounds for %d-byte string)", n.Right, len(n.Left.Val().U.(string)))
+				} else if Mpcmpfixfix(n.Right.Val().U.(*Mpint), Maxintval[TINT]) > 0 {
+					Yyerror("invalid %s index %v (index too large)", why, n.Right)
+				}
+			}
+
+		case TMAP:
+			n.Etype = 0
+			defaultlit(&n.Right, t.Down)
+			if n.Right.Type != nil {
+				n.Right = assignconv(n.Right, t.Down, "map index")
+			}
+			n.Type = t.Type
+			n.Op = OINDEXMAP
+		}
+
+		break OpSwitch
+
+	case ORECV:
+		ok |= Etop | Erv
+		typecheck(&n.Left, Erv)
+		defaultlit(&n.Left, nil)
+		l := n.Left
+		t := l.Type
+		if t == nil {
+			n.Type = nil
+			return
+		}
+		if t.Etype != TCHAN {
+			Yyerror("invalid operation: %v (receive from non-chan type %v)", n, t)
+			n.Type = nil
+			return
+		}
+
+		if t.Chan&Crecv == 0 {
+			Yyerror("invalid operation: %v (receive from send-only type %v)", n, t)
+			n.Type = nil
+			return
+		}
+
+		n.Type = t.Type
+		break OpSwitch
+
+	case OSEND:
+		ok |= Etop
+		l := typecheck(&n.Left, Erv)
+		typecheck(&n.Right, Erv)
+		defaultlit(&n.Left, nil)
+		l = n.Left
+		t := l.Type
+		if t == nil {
+			n.Type = nil
+			return
+		}
+		if t.Etype != TCHAN {
+			Yyerror("invalid operation: %v (send to non-chan type %v)", n, t)
+			n.Type = nil
+			return
+		}
+
+		if t.Chan&Csend == 0 {
+			Yyerror("invalid operation: %v (send to receive-only type %v)", n, t)
+			n.Type = nil
+			return
+		}
+
+		defaultlit(&n.Right, t.Type)
+		r := n.Right
+		if r.Type == nil {
+			n.Type = nil
+			return
+		}
+		n.Right = assignconv(r, l.Type.Type, "send")
+
+		// TODO: more aggressive
+		n.Etype = 0
+
+		n.Type = nil
+		break OpSwitch
+
+	case OSLICE:
+		ok |= Erv
+		typecheck(&n.Left, top)
+		typecheck(&n.Right.Left, Erv)
+		typecheck(&n.Right.Right, Erv)
+		defaultlit(&n.Left, nil)
+		indexlit(&n.Right.Left)
+		indexlit(&n.Right.Right)
+		l := n.Left
+		if Isfixedarray(l.Type) {
+			if !islvalue(n.Left) {
+				Yyerror("invalid operation %v (slice of unaddressable value)", n)
+				n.Type = nil
+				return
+			}
+
+			n.Left = Nod(OADDR, n.Left, nil)
+			n.Left.Implicit = true
+			typecheck(&n.Left, Erv)
+			l = n.Left
+		}
+
+		t := l.Type
+		if t == nil {
+			n.Type = nil
+			return
+		}
+		var tp *Type
+		if Istype(t, TSTRING) {
+			n.Type = t
+			n.Op = OSLICESTR
+		} else if Isptr[t.Etype] && Isfixedarray(t.Type) {
+			tp = t.Type
+			n.Type = typ(TARRAY)
+			n.Type.Type = tp.Type
+			n.Type.Bound = -1
+			dowidth(n.Type)
+			n.Op = OSLICEARR
+		} else if Isslice(t) {
+			n.Type = t
+		} else {
+			Yyerror("cannot slice %v (type %v)", l, t)
+			n.Type = nil
+			return
+		}
+
+		lo := n.Right.Left
+		if lo != nil && checksliceindex(l, lo, tp) < 0 {
+			n.Type = nil
+			return
+		}
+		hi := n.Right.Right
+		if hi != nil && checksliceindex(l, hi, tp) < 0 {
+			n.Type = nil
+			return
+		}
+		if checksliceconst(lo, hi) < 0 {
+			n.Type = nil
+			return
+		}
+		break OpSwitch
+
+	case OSLICE3:
+		ok |= Erv
+		typecheck(&n.Left, top)
+		typecheck(&n.Right.Left, Erv)
+		typecheck(&n.Right.Right.Left, Erv)
+		typecheck(&n.Right.Right.Right, Erv)
+		defaultlit(&n.Left, nil)
+		indexlit(&n.Right.Left)
+		indexlit(&n.Right.Right.Left)
+		indexlit(&n.Right.Right.Right)
+		l := n.Left
+		if Isfixedarray(l.Type) {
+			if !islvalue(n.Left) {
+				Yyerror("invalid operation %v (slice of unaddressable value)", n)
+				n.Type = nil
+				return
+			}
+
+			n.Left = Nod(OADDR, n.Left, nil)
+			n.Left.Implicit = true
+			typecheck(&n.Left, Erv)
+			l = n.Left
+		}
+
+		t := l.Type
+		if t == nil {
+			n.Type = nil
+			return
+		}
+		if Istype(t, TSTRING) {
+			Yyerror("invalid operation %v (3-index slice of string)", n)
+			n.Type = nil
+			return
+		}
+
+		var tp *Type
+		if Isptr[t.Etype] && Isfixedarray(t.Type) {
+			tp = t.Type
+			n.Type = typ(TARRAY)
+			n.Type.Type = tp.Type
+			n.Type.Bound = -1
+			dowidth(n.Type)
+			n.Op = OSLICE3ARR
+		} else if Isslice(t) {
+			n.Type = t
+		} else {
+			Yyerror("cannot slice %v (type %v)", l, t)
+			n.Type = nil
+			return
+		}
+
+		lo := n.Right.Left
+		if lo != nil && checksliceindex(l, lo, tp) < 0 {
+			n.Type = nil
+			return
+		}
+		mid := n.Right.Right.Left
+		if mid != nil && checksliceindex(l, mid, tp) < 0 {
+			n.Type = nil
+			return
+		}
+		hi := n.Right.Right.Right
+		if hi != nil && checksliceindex(l, hi, tp) < 0 {
+			n.Type = nil
+			return
+		}
+		if checksliceconst(lo, hi) < 0 || checksliceconst(lo, mid) < 0 || checksliceconst(mid, hi) < 0 {
+			n.Type = nil
+			return
+		}
+		break OpSwitch
+
+		/*
+		 * call and call like
+		 */
+	case OCALL:
+		l := n.Left
+
+		if l.Op == ONAME {
+			r := unsafenmagic(n)
+			if r != nil {
+				if n.Isddd {
+					Yyerror("invalid use of ... with builtin %v", l)
+				}
+				n = r
+				typecheck1(&n, top)
+				return
+			}
+		}
+
+		typecheck(&n.Left, Erv|Etype|Ecall|top&Eproc)
+		n.Diag |= n.Left.Diag
+		l = n.Left
+		if l.Op == ONAME && l.Etype != 0 {
+			if n.Isddd && l.Etype != OAPPEND {
+				Yyerror("invalid use of ... with builtin %v", l)
+			}
+
+			// builtin: OLEN, OCAP, etc.
+			n.Op = l.Etype
+
+			n.Left = n.Right
+			n.Right = nil
+			typecheck1(&n, top)
+			return
+		}
+
+		defaultlit(&n.Left, nil)
+		l = n.Left
+		if l.Op == OTYPE {
+			if n.Isddd || l.Type.Bound == -100 {
+				if l.Type.Broke == 0 {
+					Yyerror("invalid use of ... in type conversion to %v", l.Type)
+				}
+				n.Diag = 1
+			}
+
+			// pick off before type-checking arguments
+			ok |= Erv
+
+			// turn CALL(type, arg) into CONV(arg) w/ type
+			n.Left = nil
+
+			n.Op = OCONV
+			n.Type = l.Type
+			if onearg(n, "conversion to %v", l.Type) < 0 {
+				n.Type = nil
+				return
+			}
+			typecheck1(&n, top)
+			return
+		}
+
+		if count(n.List) == 1 && !n.Isddd {
+			typecheck(&n.List.N, Erv|Efnstruct)
+		} else {
+			typechecklist(n.List, Erv)
+		}
+		t := l.Type
+		if t == nil {
+			n.Type = nil
+			return
+		}
+		checkwidth(t)
+
+		switch l.Op {
+		case ODOTINTER:
+			n.Op = OCALLINTER
+
+		case ODOTMETH:
+			n.Op = OCALLMETH
+
+			// typecheckaste was used here but there wasn't enough
+			// information further down the call chain to know if we
+			// were testing a method receiver for unexported fields.
+			// It isn't necessary, so just do a sanity check.
+			tp := getthisx(t).Type.Type
+
+			if l.Left == nil || !Eqtype(l.Left.Type, tp) {
+				Fatal("method receiver")
+			}
+
+		default:
+			n.Op = OCALLFUNC
+			if t.Etype != TFUNC {
+				Yyerror("cannot call non-function %v (type %v)", l, t)
+				n.Type = nil
+				return
+			}
+		}
+
+		typecheckaste(OCALL, n.Left, n.Isddd, getinargx(t), n.List, func() string { return fmt.Sprintf("argument to %v", n.Left) })
+		ok |= Etop
+		if t.Outtuple == 0 {
+			break OpSwitch
+		}
+		ok |= Erv
+		if t.Outtuple == 1 {
+			t := getoutargx(l.Type).Type
+			if t == nil {
+				n.Type = nil
+				return
+			}
+			if t.Etype == TFIELD {
+				t = t.Type
+			}
+			n.Type = t
+
+			if n.Op == OCALLFUNC && n.Left.Op == ONAME && (compiling_runtime != 0 || n.Left.Sym.Pkg == Runtimepkg) && n.Left.Sym.Name == "getg" {
+				// Emit code for runtime.getg() directly instead of calling function.
+				// Most such rewrites (for example the similar one for math.Sqrt) should be done in walk,
+				// so that the ordering pass can make sure to preserve the semantics of the original code
+				// (in particular, the exact time of the function call) by introducing temporaries.
+				// In this case, we know getg() always returns the same result within a given function
+				// and we want to avoid the temporaries, so we do the rewrite earlier than is typical.
+				n.Op = OGETG
+			}
+
+			break OpSwitch
+		}
+
+		// multiple return
+		if top&(Efnstruct|Etop) == 0 {
+			Yyerror("multiple-value %v() in single-value context", l)
+			break OpSwitch
+		}
+
+		n.Type = getoutargx(l.Type)
+
+		break OpSwitch
+
+	case OCAP, OLEN, OREAL, OIMAG:
+		ok |= Erv
+		if onearg(n, "%v", Oconv(int(n.Op), 0)) < 0 {
+			n.Type = nil
+			return
+		}
+		typecheck(&n.Left, Erv)
+		defaultlit(&n.Left, nil)
+		implicitstar(&n.Left)
+		l := n.Left
+		t := l.Type
+		if t == nil {
+			n.Type = nil
+			return
+		}
+		switch n.Op {
+		case OCAP:
+			if !okforcap[t.Etype] {
+				goto badcall1
+			}
+
+		case OLEN:
+			if !okforlen[t.Etype] {
+				goto badcall1
+			}
+
+		case OREAL, OIMAG:
+			if !Iscomplex[t.Etype] {
+				goto badcall1
+			}
+			if Isconst(l, CTCPLX) {
+				r := n
+				if n.Op == OREAL {
+					n = nodfltconst(&l.Val().U.(*Mpcplx).Real)
+				} else {
+					n = nodfltconst(&l.Val().U.(*Mpcplx).Imag)
+				}
+				n.Orig = r
+			}
+
+			n.Type = Types[cplxsubtype(int(t.Etype))]
+			break OpSwitch
+		}
+
+		// might be constant
+		switch t.Etype {
+		case TSTRING:
+			if Isconst(l, CTSTR) {
+				r := Nod(OXXX, nil, nil)
+				Nodconst(r, Types[TINT], int64(len(l.Val().U.(string))))
+				r.Orig = n
+				n = r
+			}
+
+		case TARRAY:
+			if t.Bound < 0 { // slice
+				break
+			}
+			if callrecv(l) { // has call or receive
+				break
+			}
+			r := Nod(OXXX, nil, nil)
+			Nodconst(r, Types[TINT], t.Bound)
+			r.Orig = n
+			n = r
+		}
+
+		n.Type = Types[TINT]
+		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
+		var r *Node
+		var l *Node
+		if count(n.List) == 1 {
+			typechecklist(n.List, Efnstruct)
+			if n.List.N.Op != OCALLFUNC && n.List.N.Op != OCALLMETH {
+				Yyerror("invalid operation: complex expects two arguments")
+				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", n.List.N, t.Outtuple)
+				n.Type = nil
+				return
+			}
+
+			t = n.List.N.Type.Type
+			l = t.Nname
+			r = t.Down.Nname
+		} else {
+			if twoarg(n) < 0 {
+				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 {
+				n.Type = nil
+				return
+			}
+			defaultlit2(&l, &r, 0)
+			if l.Type == nil || r.Type == nil {
+				n.Type = nil
+				return
+			}
+			n.Left = l
+			n.Right = r
+		}
+
+		if !Eqtype(l.Type, r.Type) {
+			Yyerror("invalid operation: %v (mismatched types %v and %v)", n, l.Type, r.Type)
+			n.Type = nil
+			return
+		}
+
+		var t *Type
+		switch l.Type.Etype {
+		default:
+			Yyerror("invalid operation: %v (arguments have type %v, expected floating-point)", n, l.Type)
+			n.Type = nil
+			return
+
+		case TIDEAL:
+			t = Types[TIDEAL]
+
+		case TFLOAT32:
+			t = Types[TCOMPLEX64]
+
+		case TFLOAT64:
+			t = Types[TCOMPLEX128]
+		}
+
+		if l.Op == OLITERAL && r.Op == OLITERAL {
+			// make it a complex literal
+			r = nodcplxlit(l.Val(), r.Val())
+
+			r.Orig = n
+			n = r
+		}
+
+		n.Type = t
+		break OpSwitch
+
+	case OCLOSE:
+		if onearg(n, "%v", Oconv(int(n.Op), 0)) < 0 {
+			n.Type = nil
+			return
+		}
+		typecheck(&n.Left, Erv)
+		defaultlit(&n.Left, nil)
+		l := n.Left
+		t := l.Type
+		if t == nil {
+			n.Type = nil
+			return
+		}
+		if t.Etype != TCHAN {
+			Yyerror("invalid operation: %v (non-chan type %v)", n, t)
+			n.Type = nil
+			return
+		}
+
+		if t.Chan&Csend == 0 {
+			Yyerror("invalid operation: %v (cannot close receive-only channel)", n)
+			n.Type = nil
+			return
+		}
+
+		ok |= Etop
+		break OpSwitch
+
+	case ODELETE:
+		args := n.List
+		if args == nil {
+			Yyerror("missing arguments to delete")
+			n.Type = nil
+			return
+		}
+
+		if args.Next == nil {
+			Yyerror("missing second (key) argument to delete")
+			n.Type = nil
+			return
+		}
+
+		if args.Next.Next != nil {
+			Yyerror("too many arguments to delete")
+			n.Type = nil
+			return
+		}
+
+		ok |= Etop
+		typechecklist(args, Erv)
+		l := args.N
+		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))
+			n.Type = nil
+			return
+		}
+
+		args.Next.N = assignconv(r, l.Type.Down, "delete")
+		break OpSwitch
+
+	case OAPPEND:
+		ok |= Erv
+		args := n.List
+		if args == nil {
+			Yyerror("missing arguments to append")
+			n.Type = nil
+			return
+		}
+
+		if count(args) == 1 && !n.Isddd {
+			typecheck(&args.N, Erv|Efnstruct)
+		} else {
+			typechecklist(args, Erv)
+		}
+
+		t := args.N.Type
+		if t == nil {
+			n.Type = nil
+			return
+		}
+
+		// Unpack multiple-return result before type-checking.
+		var funarg *Type
+		if Istype(t, TSTRUCT) && t.Funarg != 0 {
+			funarg = t
+			t = t.Type.Type
+		}
+
+		n.Type = t
+		if !Isslice(t) {
+			if Isconst(args.N, CTNIL) {
+				Yyerror("first argument to append must be typed slice; have untyped nil")
+				n.Type = nil
+				return
+			}
+
+			Yyerror("first argument to append must be slice; have %v", Tconv(t, obj.FmtLong))
+			n.Type = nil
+			return
+		}
+
+		if n.Isddd {
+			if args.Next == nil {
+				Yyerror("cannot use ... on first argument to append")
+				n.Type = nil
+				return
+			}
+
+			if args.Next.Next != nil {
+				Yyerror("too many arguments to append")
+				n.Type = nil
+				return
+			}
+
+			if Istype(t.Type, TUINT8) && Istype(args.Next.N.Type, TSTRING) {
+				defaultlit(&args.Next.N, Types[TSTRING])
+				break OpSwitch
+			}
+
+			args.Next.N = assignconv(args.Next.N, t.Orig, "append")
+			break OpSwitch
+		}
+
+		if funarg != nil {
+			for t := funarg.Type.Down; t != nil; t = t.Down {
+				if assignop(t.Type, n.Type.Type, nil) == 0 {
+					Yyerror("cannot append %v value to []%v", t.Type, n.Type.Type)
+				}
+			}
+		} else {
+			for args = args.Next; args != nil; args = args.Next {
+				if args.N.Type == nil {
+					continue
+				}
+				args.N = assignconv(args.N, t.Type, "append")
+			}
+		}
+
+		break OpSwitch
+
+	case OCOPY:
+		ok |= Etop | Erv
+		args := n.List
+		if args == nil || args.Next == nil {
+			Yyerror("missing arguments to copy")
+			n.Type = nil
+			return
+		}
+
+		if args.Next.Next != nil {
+			Yyerror("too many arguments to copy")
+			n.Type = nil
+			return
+		}
+
+		n.Left = args.N
+		n.Right = args.Next.N
+		n.List = nil
+		n.Type = Types[TINT]
+		typecheck(&n.Left, Erv)
+		typecheck(&n.Right, Erv)
+		if n.Left.Type == nil || n.Right.Type == nil {
+			n.Type = nil
+			return
+		}
+		defaultlit(&n.Left, nil)
+		defaultlit(&n.Right, nil)
+		if n.Left.Type == nil || n.Right.Type == nil {
+			n.Type = nil
+			return
+		}
+
+		// copy([]byte, string)
+		if Isslice(n.Left.Type) && n.Right.Type.Etype == TSTRING {
+			if Eqtype(n.Left.Type.Type, bytetype) {
+				break OpSwitch
+			}
+			Yyerror("arguments to copy have different element types: %v and string", Tconv(n.Left.Type, obj.FmtLong))
+			n.Type = nil
+			return
+		}
+
+		if !Isslice(n.Left.Type) || !Isslice(n.Right.Type) {
+			if !Isslice(n.Left.Type) && !Isslice(n.Right.Type) {
+				Yyerror("arguments to copy must be slices; have %v, %v", Tconv(n.Left.Type, obj.FmtLong), Tconv(n.Right.Type, obj.FmtLong))
+			} else if !Isslice(n.Left.Type) {
+				Yyerror("first argument to copy should be slice; have %v", Tconv(n.Left.Type, obj.FmtLong))
+			} else {
+				Yyerror("second argument to copy should be slice or string; have %v", Tconv(n.Right.Type, obj.FmtLong))
+			}
+			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))
+			n.Type = nil
+			return
+		}
+
+		break OpSwitch
+
+	case OCONV:
+		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), n.Type, 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.SetVal(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
+
+	case OMAKE:
+		ok |= Erv
+		args := n.List
+		if args == nil {
+			Yyerror("missing argument to make")
+			n.Type = nil
+			return
+		}
+
+		n.List = nil
+		l := args.N
+		args = args.Next
+		typecheck(&l, Etype)
+		t := l.Type
+		if t == nil {
+			n.Type = nil
+			return
+		}
+
+		switch t.Etype {
+		default:
+			Yyerror("cannot make type %v", t)
+			n.Type = nil
+			return
+
+		case TARRAY:
+			if !Isslice(t) {
+				Yyerror("cannot make type %v", t)
+				n.Type = nil
+				return
+			}
+
+			if args == nil {
+				Yyerror("missing len argument to make(%v)", t)
+				n.Type = nil
+				return
+			}
+
+			l = args.N
+			args = args.Next
+			typecheck(&l, Erv)
+			var r *Node
+			if args != nil {
+				r = args.N
+				args = args.Next
+				typecheck(&r, Erv)
+			}
+
+			if l.Type == nil || (r != nil && r.Type == nil) {
+				n.Type = nil
+				return
+			}
+			et := obj.Bool2int(checkmake(t, "len", l) < 0)
+			et |= obj.Bool2int(r != nil && checkmake(t, "cap", r) < 0)
+			if et != 0 {
+				n.Type = nil
+				return
+			}
+			if Isconst(l, CTINT) && r != nil && Isconst(r, CTINT) && Mpcmpfixfix(l.Val().U.(*Mpint), r.Val().U.(*Mpint)) > 0 {
+				Yyerror("len larger than cap in make(%v)", t)
+				n.Type = nil
+				return
+			}
+
+			n.Left = l
+			n.Right = r
+			n.Op = OMAKESLICE
+
+		case TMAP:
+			if args != nil {
+				l = args.N
+				args = args.Next
+				typecheck(&l, Erv)
+				defaultlit(&l, Types[TINT])
+				if l.Type == nil {
+					n.Type = nil
+					return
+				}
+				if checkmake(t, "size", l) < 0 {
+					n.Type = nil
+					return
+				}
+				n.Left = l
+			} else {
+				n.Left = Nodintconst(0)
+			}
+			n.Op = OMAKEMAP
+
+		case TCHAN:
+			l = nil
+			if args != nil {
+				l = args.N
+				args = args.Next
+				typecheck(&l, Erv)
+				defaultlit(&l, Types[TINT])
+				if l.Type == nil {
+					n.Type = nil
+					return
+				}
+				if checkmake(t, "buffer", l) < 0 {
+					n.Type = nil
+					return
+				}
+				n.Left = l
+			} else {
+				n.Left = Nodintconst(0)
+			}
+			n.Op = OMAKECHAN
+		}
+
+		if args != nil {
+			Yyerror("too many arguments to make(%v)", t)
+			n.Op = OMAKE
+			n.Type = nil
+			return
+		}
+
+		n.Type = t
+		break OpSwitch
+
+	case ONEW:
+		ok |= Erv
+		args := n.List
+		if args == nil {
+			Yyerror("missing argument to new")
+			n.Type = nil
+			return
+		}
+
+		l := args.N
+		typecheck(&l, Etype)
+		t := l.Type
+		if t == nil {
+			n.Type = nil
+			return
+		}
+		if args.Next != nil {
+			Yyerror("too many arguments to new(%v)", t)
+			n.Type = nil
+			return
+		}
+
+		n.Left = l
+		n.Type = Ptrto(t)
+		break OpSwitch
+
+	case OPRINT, OPRINTN:
+		ok |= Etop
+		typechecklist(n.List, Erv|Eindir) // Eindir: address does not escape
+		for args := n.List; args != nil; args = args.Next {
+			// Special case for print: int constant is int64, not int.
+			if Isconst(args.N, CTINT) {
+				defaultlit(&args.N, Types[TINT64])
+			} else {
+				defaultlit(&args.N, nil)
+			}
+		}
+
+		break OpSwitch
+
+	case OPANIC:
+		ok |= Etop
+		if onearg(n, "panic") < 0 {
+			n.Type = nil
+			return
+		}
+		typecheck(&n.Left, Erv)
+		defaultlit(&n.Left, Types[TINTER])
+		if n.Left.Type == nil {
+			n.Type = nil
+			return
+		}
+		break OpSwitch
+
+	case ORECOVER:
+		ok |= Erv | Etop
+		if n.List != nil {
+			Yyerror("too many arguments to recover")
+			n.Type = nil
+			return
+		}
+
+		n.Type = Types[TINTER]
+		break OpSwitch
+
+	case OCLOSURE:
+		ok |= Erv
+		typecheckclosure(n, top)
+		if n.Type == nil {
+			n.Type = nil
+			return
+		}
+		break OpSwitch
+
+	case OITAB:
+		ok |= Erv
+		typecheck(&n.Left, Erv)
+		t := n.Left.Type
+		if t == nil {
+			n.Type = nil
+			return
+		}
+		if t.Etype != TINTER {
+			Fatal("OITAB of %v", t)
+		}
+		n.Type = Ptrto(Types[TUINTPTR])
+		break OpSwitch
+
+	case OSPTR:
+		ok |= Erv
+		typecheck(&n.Left, Erv)
+		t := n.Left.Type
+		if t == nil {
+			n.Type = nil
+			return
+		}
+		if !Isslice(t) && t.Etype != TSTRING {
+			Fatal("OSPTR of %v", t)
+		}
+		if t.Etype == TSTRING {
+			n.Type = Ptrto(Types[TUINT8])
+		} else {
+			n.Type = Ptrto(t.Type)
+		}
+		break OpSwitch
+
+	case OCLOSUREVAR:
+		ok |= Erv
+		break OpSwitch
+
+	case OCFUNC:
+		ok |= Erv
+		typecheck(&n.Left, Erv)
+		n.Type = Types[TUINTPTR]
+		break OpSwitch
+
+	case OCONVNOP:
+		ok |= Erv
+		typecheck(&n.Left, Erv)
+		break OpSwitch
+
+		/*
+		 * statements
+		 */
+	case OAS:
+		ok |= Etop
+
+		typecheckas(n)
+
+		// Code that creates temps does not bother to set defn, so do it here.
+		if n.Left.Op == ONAME && strings.HasPrefix(n.Left.Sym.Name, "autotmp_") {
+			n.Left.Name.Defn = n
+		}
+		break OpSwitch
+
+	case OAS2:
+		ok |= Etop
+		typecheckas2(n)
+		break OpSwitch
+
+	case OBREAK,
+		OCONTINUE,
+		ODCL,
+		OEMPTY,
+		OGOTO,
+		OXFALL,
+		OVARKILL:
+		ok |= Etop
+		break OpSwitch
+
+	case OLABEL:
+		ok |= Etop
+		decldepth++
+		break OpSwitch
+
+	case ODEFER:
+		ok |= Etop
+		typecheck(&n.Left, Etop|Erv)
+		if n.Left.Diag == 0 {
+			checkdefergo(n)
+		}
+		break OpSwitch
+
+	case OPROC:
+		ok |= Etop
+		typecheck(&n.Left, Etop|Eproc|Erv)
+		checkdefergo(n)
+		break OpSwitch
+
+	case OFOR:
+		ok |= Etop
+		typechecklist(n.Ninit, Etop)
+		decldepth++
+		typecheck(&n.Left, Erv)
+		if n.Left != nil {
+			t := n.Left.Type
+			if t != nil && t.Etype != TBOOL {
+				Yyerror("non-bool %v used as for condition", Nconv(n.Left, obj.FmtLong))
+			}
+		}
+		typecheck(&n.Right, Etop)
+		typechecklist(n.Nbody, Etop)
+		decldepth--
+		break OpSwitch
+
+	case OIF:
+		ok |= Etop
+		typechecklist(n.Ninit, Etop)
+		typecheck(&n.Left, Erv)
+		if n.Left != nil {
+			t := n.Left.Type
+			if t != nil && t.Etype != TBOOL {
+				Yyerror("non-bool %v used as if condition", Nconv(n.Left, obj.FmtLong))
+			}
+		}
+		typechecklist(n.Nbody, Etop)
+		typechecklist(n.Rlist, Etop)
+		break OpSwitch
+
+	case ORETURN:
+		ok |= Etop
+		if count(n.List) == 1 {
+			typechecklist(n.List, Erv|Efnstruct)
+		} else {
+			typechecklist(n.List, Erv)
+		}
+		if Curfn == nil {
+			Yyerror("return outside function")
+			n.Type = nil
+			return
+		}
+
+		if Curfn.Type.Outnamed != 0 && n.List == nil {
+			break OpSwitch
+		}
+		typecheckaste(ORETURN, nil, false, getoutargx(Curfn.Type), n.List, func() string { return "return argument" })
+		break OpSwitch
+
+	case ORETJMP:
+		ok |= Etop
+		break OpSwitch
+
+	case OSELECT:
+		ok |= Etop
+		typecheckselect(n)
+		break OpSwitch
+
+	case OSWITCH:
+		ok |= Etop
+		typecheckswitch(n)
+		break OpSwitch
+
+	case ORANGE:
+		ok |= Etop
+		typecheckrange(n)
+		break OpSwitch
+
+	case OTYPESW:
+		Yyerror("use of .(type) outside type switch")
+		n.Type = nil
+		return
+
+	case OXCASE:
+		ok |= Etop
+		typechecklist(n.List, Erv)
+		typechecklist(n.Nbody, Etop)
+		break OpSwitch
+
+	case ODCLFUNC:
+		ok |= Etop
+		typecheckfunc(n)
+		break OpSwitch
+
+	case ODCLCONST:
+		ok |= Etop
+		typecheck(&n.Left, Erv)
+		break OpSwitch
+
+	case ODCLTYPE:
+		ok |= Etop
+		typecheck(&n.Left, Etype)
+		if incannedimport == 0 {
+			checkwidth(n.Left.Type)
+		}
+		break OpSwitch
+	}
+
+	t := n.Type
+	if t != nil && t.Funarg == 0 && n.Op != OTYPE {
+		switch t.Etype {
+		case TFUNC, // might have TANY; wait until its called
+			TANY,
+			TFORW,
+			TIDEAL,
+			TNIL,
+			TBLANK:
+			break
+
+		default:
+			checkwidth(t)
+		}
+	}
+
+	if safemode != 0 && incannedimport == 0 && importpkg == nil && compiling_wrappers == 0 && t != nil && t.Etype == TUNSAFEPTR {
+		Yyerror("cannot use unsafe.Pointer")
+	}
+
+	evconst(n)
+	if n.Op == OTYPE && top&Etype == 0 {
+		Yyerror("type %v is not an expression", n.Type)
+		n.Type = nil
+		return
+	}
+
+	if top&(Erv|Etype) == Etype && n.Op != OTYPE {
+		Yyerror("%v is not a type", n)
+		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", n)
+		n.Type = nil
+		return
+	}
+
+	if (top&Etop != 0) && top&(Ecall|Erv|Etype) == 0 && ok&Etop == 0 {
+		if n.Diag == 0 {
+			Yyerror("%v evaluated but not used", n)
+			n.Diag = 1
+		}
+
+		n.Type = nil
+		return
+	}
+
+	/* TODO
+	if(n->type == T)
+		fatal("typecheck nil type");
+	*/
+}
+
+func checksliceindex(l *Node, r *Node, tp *Type) int {
+	t := r.Type
+	if t == nil {
+		return -1
+	}
+	if !Isint[t.Etype] {
+		Yyerror("invalid slice index %v (type %v)", r, t)
+		return -1
+	}
+
+	if r.Op == OLITERAL {
+		if Mpgetfix(r.Val().U.(*Mpint)) < 0 {
+			Yyerror("invalid slice index %v (index must be non-negative)", r)
+			return -1
+		} else if tp != nil && tp.Bound > 0 && Mpgetfix(r.Val().U.(*Mpint)) > tp.Bound {
+			Yyerror("invalid slice index %v (out of bounds for %d-element array)", r, tp.Bound)
+			return -1
+		} else if Isconst(l, CTSTR) && Mpgetfix(r.Val().U.(*Mpint)) > int64(len(l.Val().U.(string))) {
+			Yyerror("invalid slice index %v (out of bounds for %d-byte string)", r, len(l.Val().U.(string)))
+			return -1
+		} else if Mpcmpfixfix(r.Val().U.(*Mpint), Maxintval[TINT]) > 0 {
+			Yyerror("invalid slice index %v (index too large)", r)
+			return -1
+		}
+	}
+
+	return 0
+}
+
+func checksliceconst(lo *Node, hi *Node) int {
+	if lo != nil && hi != nil && lo.Op == OLITERAL && hi.Op == OLITERAL && Mpcmpfixfix(lo.Val().U.(*Mpint), hi.Val().U.(*Mpint)) > 0 {
+		Yyerror("invalid slice index: %v > %v", lo, hi)
+		return -1
+	}
+
+	return 0
+}
+
+func checkdefergo(n *Node) {
+	what := "defer"
+	if n.Op == OPROC {
+		what = "go"
+	}
+
+	switch n.Left.Op {
+	// ok
+	case OCALLINTER,
+		OCALLMETH,
+		OCALLFUNC,
+		OCLOSE,
+		OCOPY,
+		ODELETE,
+		OPANIC,
+		OPRINT,
+		OPRINTN,
+		ORECOVER:
+		return
+
+	case OAPPEND,
+		OCAP,
+		OCOMPLEX,
+		OIMAG,
+		OLEN,
+		OMAKE,
+		OMAKESLICE,
+		OMAKECHAN,
+		OMAKEMAP,
+		ONEW,
+		OREAL,
+		OLITERAL: // conversion or unsafe.Alignof, Offsetof, Sizeof
+		if n.Left.Orig != nil && n.Left.Orig.Op == OCONV {
+			break
+		}
+		Yyerror("%s discards result of %v", what, n.Left)
+		return
+	}
+
+	// type is broken or missing, most likely a method call on a broken type
+	// we will warn about the broken type elsewhere. no need to emit a potentially confusing error
+	if n.Left.Type == nil || n.Left.Type.Broke != 0 {
+		return
+	}
+
+	if n.Diag == 0 {
+		// The syntax made sure it was a call, so this must be
+		// a conversion.
+		n.Diag = 1
+
+		Yyerror("%s requires function call, not conversion", what)
+	}
+}
+
+func implicitstar(nn **Node) {
+	// insert implicit * if needed for fixed array
+	n := *nn
+
+	t := n.Type
+	if t == nil || !Isptr[t.Etype] {
+		return
+	}
+	t = t.Type
+	if t == nil {
+		return
+	}
+	if !Isfixedarray(t) {
+		return
+	}
+	n = Nod(OIND, n, nil)
+	n.Implicit = true
+	typecheck(&n, Erv)
+	*nn = n
+}
+
+func onearg(n *Node, f string, args ...interface{}) int {
+	if n.Left != nil {
+		return 0
+	}
+	if n.List == nil {
+		p := fmt.Sprintf(f, args...)
+		Yyerror("missing argument to %s: %v", p, n)
+		return -1
+	}
+
+	if n.List.Next != nil {
+		p := fmt.Sprintf(f, args...)
+		Yyerror("too many arguments to %s: %v", p, n)
+		n.Left = n.List.N
+		n.List = nil
+		return -1
+	}
+
+	n.Left = n.List.N
+	n.List = nil
+	return 0
+}
+
+func twoarg(n *Node) int {
+	if n.Left != nil {
+		return 0
+	}
+	if n.List == nil {
+		Yyerror("missing argument to %v - %v", Oconv(int(n.Op), 0), n)
+		return -1
+	}
+
+	n.Left = n.List.N
+	if n.List.Next == nil {
+		Yyerror("missing argument to %v - %v", Oconv(int(n.Op), 0), n)
+		n.List = nil
+		return -1
+	}
+
+	if n.List.Next.Next != nil {
+		Yyerror("too many arguments to %v - %v", Oconv(int(n.Op), 0), n)
+		n.List = nil
+		return -1
+	}
+
+	n.Right = n.List.Next.N
+	n.List = nil
+	return 0
+}
+
+func lookdot1(errnode *Node, s *Sym, t *Type, f *Type, dostrcmp int) *Type {
+	var r *Type
+	for ; f != nil; f = f.Down {
+		if dostrcmp != 0 && f.Sym.Name == s.Name {
+			return f
+		}
+		if dostrcmp == 2 && strings.EqualFold(f.Sym.Name, s.Name) {
+			return f
+		}
+		if f.Sym != s {
+			continue
+		}
+		if r != nil {
+			if errnode != nil {
+				Yyerror("ambiguous selector %v", errnode)
+			} else if Isptr[t.Etype] {
+				Yyerror("ambiguous selector (%v).%v", t, s)
+			} else {
+				Yyerror("ambiguous selector %v.%v", t, s)
+			}
+			break
+		}
+
+		r = f
+	}
+
+	return r
+}
+
+func looktypedot(n *Node, t *Type, dostrcmp int) bool {
+	s := n.Right.Sym
+
+	if t.Etype == TINTER {
+		f1 := lookdot1(n, s, t, t.Type, dostrcmp)
+		if f1 == nil {
+			return false
+		}
+
+		n.Right = methodname(n.Right, t)
+		n.Xoffset = f1.Width
+		n.Type = f1.Type
+		n.Op = ODOTINTER
+		return true
+	}
+
+	// Find the base type: methtype will fail if t
+	// is not of the form T or *T.
+	f2 := methtype(t, 0)
+
+	if f2 == nil {
+		return false
+	}
+
+	expandmeth(f2)
+	f2 = lookdot1(n, s, f2, f2.Xmethod, dostrcmp)
+	if f2 == nil {
+		return false
+	}
+
+	// disallow T.m if m requires *T receiver
+	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)", n, t, Sconv(f2.Sym, obj.FmtShort))
+		return false
+	}
+
+	n.Right = methodname(n.Right, t)
+	n.Xoffset = f2.Width
+	n.Type = f2.Type
+	n.Op = ODOTMETH
+	return true
+}
+
+func derefall(t *Type) *Type {
+	for t != nil && int(t.Etype) == Tptr {
+		t = t.Type
+	}
+	return t
+}
+
+type typeSym struct {
+	t *Type
+	s *Sym
+}
+
+// dotField maps (*Type, *Sym) pairs to the corresponding struct field (*Type with Etype==TFIELD).
+// It is a cache for use during usefield in walk.go, only enabled when field tracking.
+var dotField = map[typeSym]*Type{}
+
+func lookdot(n *Node, t *Type, dostrcmp int) *Type {
+	s := n.Right.Sym
+
+	dowidth(t)
+	var f1 *Type
+	if t.Etype == TSTRUCT || t.Etype == TINTER {
+		f1 = lookdot1(n, s, t, t.Type, dostrcmp)
+	}
+
+	var f2 *Type
+	if n.Left.Type == t || n.Left.Type.Sym == nil {
+		f2 = methtype(t, 0)
+		if f2 != nil {
+			// Use f2->method, not f2->xmethod: adddot has
+			// already inserted all the necessary embedded dots.
+			f2 = lookdot1(n, s, f2, f2.Method, dostrcmp)
+		}
+	}
+
+	if f1 != nil {
+		if dostrcmp > 1 {
+			// Already in the process of diagnosing an error.
+			return f1
+		}
+		if f2 != nil {
+			Yyerror("%v is both field and method", n.Right.Sym)
+		}
+		if f1.Width == BADWIDTH {
+			Fatal("lookdot badwidth %v %p", f1, f1)
+		}
+		n.Xoffset = f1.Width
+		n.Type = f1.Type
+		if obj.Fieldtrack_enabled > 0 {
+			dotField[typeSym{t.Orig, s}] = f1
+		}
+		if t.Etype == TINTER {
+			if Isptr[n.Left.Type.Etype] {
+				n.Left = Nod(OIND, n.Left, nil) // implicitstar
+				n.Left.Implicit = true
+				typecheck(&n.Left, Erv)
+			}
+
+			n.Op = ODOTINTER
+		}
+
+		return f1
+	}
+
+	if f2 != nil {
+		if dostrcmp > 1 {
+			// Already in the process of diagnosing an error.
+			return f2
+		}
+		tt := n.Left.Type
+		dowidth(tt)
+		rcvr := getthisx(f2.Type).Type.Type
+		if !Eqtype(rcvr, tt) {
+			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 = 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 = 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", n.Right, Nconv(n.Left, obj.FmtLong))
+				for int(tt.Etype) == Tptr {
+					// Stop one level early for method with pointer receiver.
+					if int(rcvr.Etype) == Tptr && int(tt.Type.Etype) != Tptr {
+						break
+					}
+					n.Left = Nod(OIND, n.Left, nil)
+					n.Left.Implicit = true
+					typecheck(&n.Left, Etype|Erv)
+					tt = tt.Type
+				}
+			} else {
+				Fatal("method mismatch: %v for %v", rcvr, tt)
+			}
+		}
+
+		pll := n
+		ll := n.Left
+		for ll.Left != nil && (ll.Op == ODOT || ll.Op == ODOTPTR || ll.Op == OIND) {
+			pll = ll
+			ll = ll.Left
+		}
+		if pll.Implicit && 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
+			return nil
+		}
+
+		n.Right = methodname(n.Right, n.Left.Type)
+		n.Xoffset = f2.Width
+		n.Type = f2.Type
+
+		//		print("lookdot found [%p] %T\n", f2->type, f2->type);
+		n.Op = ODOTMETH
+
+		return f2
+	}
+
+	return nil
+}
+
+func nokeys(l *NodeList) bool {
+	for ; l != nil; l = l.Next {
+		if l.N.Op == OKEY {
+			return false
+		}
+	}
+	return true
+}
+
+func hasddd(t *Type) bool {
+	for tl := t.Type; tl != nil; tl = tl.Down {
+		if tl.Isddd {
+			return true
+		}
+	}
+
+	return false
+}
+
+func downcount(t *Type) int {
+	n := 0
+	for tl := t.Type; tl != nil; tl = tl.Down {
+		n++
+	}
+
+	return n
+}
+
+/*
+ * typecheck assignment: type list = expression list
+ */
+func typecheckaste(op int, call *Node, isddd bool, tstruct *Type, nl *NodeList, desc func() string) {
+	var t *Type
+	var n *Node
+	var n1 int
+	var n2 int
+
+	lno := int(lineno)
+
+	if tstruct.Broke != 0 {
+		goto out
+	}
+
+	n = nil
+	if nl != nil && nl.Next == nil {
+		n = nl.N
+		if n.Type != nil {
+			if n.Type.Etype == TSTRUCT && n.Type.Funarg != 0 {
+				if !hasddd(tstruct) {
+					n1 := downcount(tstruct)
+					n2 := downcount(n.Type)
+					if n2 > n1 {
+						goto toomany
+					}
+					if n2 < n1 {
+						goto notenough
+					}
+				}
+
+				tn := n.Type.Type
+				var why string
+				for tl := tstruct.Type; tl != nil; tl = tl.Down {
+					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", tn.Type, tl.Type.Type, call, why)
+								} else {
+									Yyerror("cannot use %v as type %v in %s%s", tn.Type, tl.Type.Type, desc(), why)
+								}
+							}
+						}
+
+						goto out
+					}
+
+					if tn == nil {
+						goto notenough
+					}
+					if assignop(tn.Type, tl.Type, &why) == 0 {
+						if call != nil {
+							Yyerror("cannot use %v as type %v in argument to %v%s", tn.Type, tl.Type, call, why)
+						} else {
+							Yyerror("cannot use %v as type %v in %s%s", tn.Type, tl.Type, desc(), why)
+						}
+					}
+
+					tn = tn.Down
+				}
+
+				if tn != nil {
+					goto toomany
+				}
+				goto out
+			}
+		}
+	}
+
+	n1 = downcount(tstruct)
+	n2 = count(nl)
+	if !hasddd(tstruct) {
+		if n2 > n1 {
+			goto toomany
+		}
+		if n2 < n1 {
+			goto notenough
+		}
+	} else {
+		if !isddd {
+			if n2 < n1-1 {
+				goto notenough
+			}
+		} else {
+			if n2 > n1 {
+				goto toomany
+			}
+			if n2 < n1 {
+				goto notenough
+			}
+		}
+	}
+
+	for tl := tstruct.Type; tl != nil; tl = tl.Down {
+		t = tl.Type
+		if tl.Isddd {
+			if isddd {
+				if nl == nil {
+					goto notenough
+				}
+				if nl.Next != nil {
+					goto toomany
+				}
+				n = nl.N
+				setlineno(n)
+				if n.Type != nil {
+					nl.N = assignconvfn(n, t, desc)
+				}
+				goto out
+			}
+
+			for ; nl != nil; nl = nl.Next {
+				n = nl.N
+				setlineno(nl.N)
+				if n.Type != nil {
+					nl.N = assignconvfn(n, t.Type, desc)
+				}
+			}
+
+			goto out
+		}
+
+		if nl == nil {
+			goto notenough
+		}
+		n = nl.N
+		setlineno(n)
+		if n.Type != nil {
+			nl.N = assignconvfn(n, t, desc)
+		}
+		nl = nl.Next
+	}
+
+	if nl != nil {
+		goto toomany
+	}
+	if isddd {
+		if call != nil {
+			Yyerror("invalid use of ... in call to %v", call)
+		} else {
+			Yyerror("invalid use of ... in %v", Oconv(int(op), 0))
+		}
+	}
+
+out:
+	lineno = int32(lno)
+	return
+
+notenough:
+	if n == nil || n.Diag == 0 {
+		if call != nil {
+			// call is the expression being called, not the overall call.
+			// Method expressions have the form T.M, and the compiler has
+			// rewritten those to ONAME nodes but left T in Left.
+			if call.Op == ONAME && call.Left != nil && call.Left.Op == OTYPE {
+				Yyerror("not enough arguments in call to method expression %v", call)
+			} else {
+				Yyerror("not enough arguments in call to %v", call)
+			}
+		} else {
+			Yyerror("not enough arguments to %v", Oconv(int(op), 0))
+		}
+		if n != nil {
+			n.Diag = 1
+		}
+	}
+
+	goto out
+
+toomany:
+	if call != nil {
+		Yyerror("too many arguments in call to %v", call)
+	} else {
+		Yyerror("too many arguments to %v", Oconv(int(op), 0))
+	}
+	goto out
+}
+
+/*
+ * type check composite
+ */
+func fielddup(n *Node, hash map[string]bool) {
+	if n.Op != ONAME {
+		Fatal("fielddup: not ONAME")
+	}
+	name := n.Sym.Name
+	if hash[name] {
+		Yyerror("duplicate field name in struct literal: %s", name)
+		return
+	}
+	hash[name] = true
+}
+
+func keydup(n *Node, hash map[uint32][]*Node) {
+	orign := n
+	if n.Op == OCONVIFACE {
+		n = n.Left
+	}
+	evconst(n)
+	if n.Op != OLITERAL {
+		return // we don't check variables
+	}
+
+	var h uint32
+	switch n.Val().Ctype() {
+	default: // unknown, bool, nil
+		h = 23
+
+	case CTINT, CTRUNE:
+		h = uint32(Mpgetfix(n.Val().U.(*Mpint)))
+
+	case CTFLT:
+		d := mpgetflt(n.Val().U.(*Mpflt))
+		x := math.Float64bits(d)
+		for i := 0; i < 8; i++ {
+			h = h*PRIME1 + uint32(x&0xFF)
+			x >>= 8
+		}
+
+	case CTSTR:
+		h = 0
+		s := n.Val().U.(string)
+		for i := len(n.Val().U.(string)); i > 0; i-- {
+			h = h*PRIME1 + uint32(s[0])
+			s = s[1:]
+		}
+	}
+
+	var cmp Node
+	for _, a := range hash[h] {
+		cmp.Op = OEQ
+		cmp.Left = n
+		b := uint32(0)
+		if a.Op == OCONVIFACE && orign.Op == OCONVIFACE {
+			if Eqtype(a.Left.Type, n.Type) {
+				cmp.Right = a.Left
+				evconst(&cmp)
+				b = uint32(obj.Bool2int(cmp.Val().U.(bool)))
+			}
+		} else if Eqtype(a.Type, n.Type) {
+			cmp.Right = a
+			evconst(&cmp)
+			b = uint32(obj.Bool2int(cmp.Val().U.(bool)))
+		}
+
+		if b != 0 {
+			Yyerror("duplicate key %v in map literal", n)
+			return
+		}
+	}
+
+	hash[h] = append(hash[h], orign)
+}
+
+func indexdup(n *Node, hash map[int64]*Node) {
+	if n.Op != OLITERAL {
+		Fatal("indexdup: not OLITERAL")
+	}
+
+	v := Mpgetfix(n.Val().U.(*Mpint))
+	if hash[v] != nil {
+		Yyerror("duplicate index in array literal: %d", v)
+		return
+	}
+	hash[v] = n
+}
+
+func iscomptype(t *Type) bool {
+	switch t.Etype {
+	case TARRAY, TSTRUCT, TMAP:
+		return true
+
+	case TPTR32, TPTR64:
+		switch t.Type.Etype {
+		case TARRAY, TSTRUCT, TMAP:
+			return true
+		}
+	}
+
+	return false
+}
+
+func pushtype(n *Node, t *Type) {
+	if n == nil || n.Op != OCOMPLIT || !iscomptype(t) {
+		return
+	}
+
+	if n.Right == nil {
+		n.Right = typenod(t)
+		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) {
+			fmt.Printf("%v: redundant type: %v\n", n.Line(), t)
+		}
+	}
+}
+
+func typecheckcomplit(np **Node) {
+	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")
+		n.Type = nil
+		return
+	}
+
+	// Save original node (including n->right)
+	norig := Nod(int(n.Op), nil, nil)
+
+	*norig = *n
+
+	setlineno(n.Right)
+	l := typecheck(&n.Right, Etype|Ecomplit) /* sic */
+	t := l.Type
+	if t == nil {
+		n.Type = nil
+		return
+	}
+	nerr := nerrors
+	n.Type = t
+
+	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 {
+			Yyerror("invalid pointer type %v for composite literal (use &%v instead)", t, t.Type)
+			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", t)
+			n.Type = nil
+			return
+		}
+
+		t = t.Type
+	}
+
+	var r *Node
+	switch t.Etype {
+	default:
+		Yyerror("invalid type for composite literal: %v", t)
+		n.Type = nil
+
+	case TARRAY:
+		// Only allocate hash if there are some key/value pairs.
+		var hash map[int64]*Node
+		for ll := n.List; ll != nil; ll = ll.Next {
+			if ll.N.Op == OKEY {
+				hash = make(map[int64]*Node)
+				break
+			}
+		}
+		length := int64(0)
+		i := 0
+		var l *Node
+		for ll := n.List; ll != nil; ll = ll.Next {
+			l = ll.N
+			setlineno(l)
+			if l.Op != OKEY {
+				l = Nod(OKEY, Nodintconst(int64(i)), l)
+				l.Left.Type = Types[TINT]
+				l.Left.Typecheck = 1
+				ll.N = l
+			}
+
+			typecheck(&l.Left, Erv)
+			evconst(l.Left)
+			i = nonnegconst(l.Left)
+			if i < 0 && l.Left.Diag == 0 {
+				Yyerror("array index must be non-negative integer constant")
+				l.Left.Diag = 1
+				i = -(1 << 30) // stay negative for a while
+			}
+
+			if i >= 0 && hash != nil {
+				indexdup(l.Left, hash)
+			}
+			i++
+			if int64(i) > length {
+				length = int64(i)
+				if t.Bound >= 0 && length > t.Bound {
+					setlineno(l)
+					Yyerror("array index %d out of bounds [0:%d]", length-1, t.Bound)
+					t.Bound = -1 // no more errors
+				}
+			}
+
+			r = l.Right
+			pushtype(r, t.Type)
+			typecheck(&r, Erv)
+			defaultlit(&r, t.Type)
+			l.Right = assignconv(r, t.Type, "array element")
+		}
+
+		if t.Bound == -100 {
+			t.Bound = length
+		}
+		if t.Bound < 0 {
+			n.Right = Nodintconst(length)
+		}
+		n.Op = OARRAYLIT
+
+	case TMAP:
+		hash := make(map[uint32][]*Node)
+		var l *Node
+		for ll := n.List; ll != nil; ll = ll.Next {
+			l = ll.N
+			setlineno(l)
+			if l.Op != OKEY {
+				typecheck(&ll.N, Erv)
+				Yyerror("missing key in map literal")
+				continue
+			}
+
+			r = l.Left
+			pushtype(r, t.Down)
+			typecheck(&r, Erv)
+			defaultlit(&r, t.Down)
+			l.Left = assignconv(r, t.Down, "map key")
+			if l.Left.Op != OCONV {
+				keydup(l.Left, hash)
+			}
+
+			r = l.Right
+			pushtype(r, t.Type)
+			typecheck(&r, Erv)
+			defaultlit(&r, t.Type)
+			l.Right = assignconv(r, t.Type, "map value")
+		}
+
+		n.Op = OMAPLIT
+
+	case TSTRUCT:
+		bad := 0
+		if n.List != nil && nokeys(n.List) {
+			// simple list of variables
+			f := t.Type
+
+			var s *Sym
+			for ll := n.List; ll != nil; ll = ll.Next {
+				setlineno(ll.N)
+				typecheck(&ll.N, Erv)
+				if f == nil {
+					tmp12 := bad
+					bad++
+					if tmp12 == 0 {
+						Yyerror("too many values in struct initializer")
+					}
+					continue
+				}
+
+				s = f.Sym
+				if s != nil && !exportname(s.Name) && s.Pkg != localpkg {
+					Yyerror("implicit assignment of unexported field '%s' in %v literal", s.Name, t)
+				}
+
+				// No pushtype allowed here.  Must name fields for that.
+				ll.N = assignconv(ll.N, f.Type, "field value")
+
+				ll.N = Nod(OKEY, newname(f.Sym), ll.N)
+				ll.N.Left.Type = f
+				ll.N.Left.Typecheck = 1
+				f = f.Down
+			}
+
+			if f != nil {
+				Yyerror("too few values in struct initializer")
+			}
+		} else {
+			hash := make(map[string]bool)
+
+			// keyed list
+			var s *Sym
+			var f *Type
+			var l *Node
+			var s1 *Sym
+			for ll := n.List; ll != nil; ll = ll.Next {
+				l = ll.N
+				setlineno(l)
+				if l.Op != OKEY {
+					tmp13 := bad
+					bad++
+					if tmp13 == 0 {
+						Yyerror("mixture of field:value and value initializers")
+					}
+					typecheck(&ll.N, Erv)
+					continue
+				}
+
+				s = l.Left.Sym
+				if s == nil {
+					Yyerror("invalid field name %v in struct initializer", l.Left)
+					typecheck(&l.Right, Erv)
+					continue
+				}
+
+				// Sym might have resolved to name in other top-level
+				// package, because of import dot.  Redirect to correct sym
+				// before we do the lookup.
+				if s.Pkg != localpkg && exportname(s.Name) {
+					s1 = Lookup(s.Name)
+					if s1.Origpkg == s.Pkg {
+						s = s1
+					}
+				}
+
+				f = lookdot1(nil, s, t, t.Type, 0)
+				if f == nil {
+					Yyerror("unknown %v field '%v' in struct literal", t, s)
+					continue
+				}
+
+				l.Left = newname(s)
+				l.Left.Typecheck = 1
+				l.Left.Type = f
+				s = f.Sym
+				fielddup(newname(s), hash)
+				r = l.Right
+
+				// No pushtype allowed here.  Tried and rejected.
+				typecheck(&r, Erv)
+
+				l.Right = assignconv(r, f.Type, "field value")
+			}
+		}
+
+		n.Op = OSTRUCTLIT
+	}
+
+	if nerr != nerrors {
+		n.Type = nil
+		return
+	}
+
+	n.Orig = norig
+	if Isptr[n.Type.Etype] {
+		n = Nod(OPTRLIT, n, nil)
+		n.Typecheck = 1
+		n.Type = n.Left.Type
+		n.Left.Type = t
+		n.Left.Typecheck = 1
+	}
+
+	n.Orig = norig
+	return
+}
+
+/*
+ * lvalue etc
+ */
+func islvalue(n *Node) bool {
+	switch n.Op {
+	case OINDEX:
+		if Isfixedarray(n.Left.Type) {
+			return islvalue(n.Left)
+		}
+		if n.Left.Type != nil && n.Left.Type.Etype == TSTRING {
+			return false
+		}
+		fallthrough
+
+		// fall through
+	case OIND, ODOTPTR, OCLOSUREVAR, OPARAM:
+		return true
+
+	case ODOT:
+		return islvalue(n.Left)
+
+	case ONAME:
+		if n.Class == PFUNC {
+			return false
+		}
+		return true
+	}
+
+	return false
+}
+
+func checklvalue(n *Node, verb string) {
+	if !islvalue(n) {
+		Yyerror("cannot %s %v", verb, n)
+	}
+}
+
+func checkassign(stmt *Node, n *Node) {
+	// Variables declared in ORANGE are assigned on every iteration.
+	if n.Name == nil || n.Name.Defn != stmt || stmt.Op == ORANGE {
+		r := outervalue(n)
+		var l *Node
+		for l = n; l != r; l = l.Left {
+			l.Assigned = true
+			if l.Name != nil && l.Name.Param != nil && l.Name.Param.Closure != nil {
+				l.Name.Param.Closure.Assigned = true
+			}
+		}
+
+		l.Assigned = true
+		if l.Name != nil && l.Name.Param != nil && l.Name.Param.Closure != nil {
+			l.Name.Param.Closure.Assigned = true
+		}
+	}
+
+	if islvalue(n) {
+		return
+	}
+	if n.Op == OINDEXMAP {
+		n.Etype = 1
+		return
+	}
+
+	// have already complained about n being undefined
+	if n.Op == ONONAME {
+		return
+	}
+
+	Yyerror("cannot assign to %v", n)
+}
+
+func checkassignlist(stmt *Node, l *NodeList) {
+	for ; l != nil; l = l.Next {
+		checkassign(stmt, l.N)
+	}
+}
+
+// Check whether l and r are the same side effect-free expression,
+// so that it is safe to reuse one instead of computing both.
+func samesafeexpr(l *Node, r *Node) bool {
+	if l.Op != r.Op || !Eqtype(l.Type, r.Type) {
+		return false
+	}
+
+	switch l.Op {
+	case ONAME, OCLOSUREVAR:
+		return l == r
+
+	case ODOT, ODOTPTR:
+		return l.Right != nil && r.Right != nil && l.Right.Sym == r.Right.Sym && samesafeexpr(l.Left, r.Left)
+
+	case OIND:
+		return samesafeexpr(l.Left, r.Left)
+
+	case OINDEX:
+		return samesafeexpr(l.Left, r.Left) && samesafeexpr(l.Right, r.Right)
+	}
+
+	return false
+}
+
+/*
+ * type check assignment.
+ * if this assignment is the definition of a var on the left side,
+ * fill in the var's type.
+ */
+func typecheckas(n *Node) {
+	// delicate little dance.
+	// the definition of n may refer to this assignment
+	// as its definition, in which case it will call typecheckas.
+	// in that case, do not call typecheck back, or it will cycle.
+	// if the variable has a type (ntype) then typechecking
+	// will not look at defn, so it is okay (and desirable,
+	// so that the conversion below happens).
+	n.Left = resolve(n.Left)
+
+	if n.Left.Name == nil || n.Left.Name.Defn != n || n.Left.Name.Param.Ntype != nil {
+		typecheck(&n.Left, Erv|Easgn)
+	}
+
+	typecheck(&n.Right, Erv)
+	checkassign(n, n.Left)
+	if n.Right != nil && n.Right.Type != nil {
+		if n.Left.Type != nil {
+			n.Right = assignconv(n.Right, n.Left.Type, "assignment")
+		}
+	}
+
+	if n.Left.Name != nil && n.Left.Name.Defn == n && n.Left.Name.Param.Ntype == nil {
+		defaultlit(&n.Right, nil)
+		n.Left.Type = n.Right.Type
+	}
+
+	// second half of dance.
+	// now that right is done, typecheck the left
+	// just to get it over with.  see dance above.
+	n.Typecheck = 1
+
+	if n.Left.Typecheck == 0 {
+		typecheck(&n.Left, Erv|Easgn)
+	}
+}
+
+func checkassignto(src *Type, dst *Node) {
+	var why string
+
+	if assignop(src, dst.Type, &why) == 0 {
+		Yyerror("cannot assign %v to %v in multiple assignment%s", src, Nconv(dst, obj.FmtLong), why)
+		return
+	}
+}
+
+func typecheckas2(n *Node) {
+	for ll := n.List; ll != nil; ll = ll.Next {
+		// delicate little dance.
+		ll.N = resolve(ll.N)
+
+		if ll.N.Name == nil || ll.N.Name.Defn != n || ll.N.Name.Param.Ntype != nil {
+			typecheck(&ll.N, Erv|Easgn)
+		}
+	}
+
+	cl := count(n.List)
+	cr := count(n.Rlist)
+	if cl > 1 && cr == 1 {
+		typecheck(&n.Rlist.N, Erv|Efnstruct)
+	} else {
+		typechecklist(n.Rlist, Erv)
+	}
+	checkassignlist(n, n.List)
+
+	var l *Node
+	var r *Node
+	if cl == cr {
+		// easy
+		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")
+			}
+			if ll.N.Name != nil && ll.N.Name.Defn == n && ll.N.Name.Param.Ntype == nil {
+				defaultlit(&lr.N, nil)
+				ll.N.Type = lr.N.Type
+			}
+		}
+
+		goto out
+	}
+
+	l = n.List.N
+	r = n.Rlist.N
+
+	// x,y,z = f()
+	if cr == 1 {
+		if r.Type == nil {
+			goto out
+		}
+		switch r.Op {
+		case OCALLMETH, OCALLINTER, OCALLFUNC:
+			if r.Type.Etype != TSTRUCT || r.Type.Funarg == 0 {
+				break
+			}
+			cr = structcount(r.Type)
+			if cr != cl {
+				goto mismatch
+			}
+			n.Op = OAS2FUNC
+			var s Iter
+			t := Structfirst(&s, &r.Type)
+			for ll := n.List; ll != nil; ll = ll.Next {
+				if t.Type != nil && ll.N.Type != nil {
+					checkassignto(t.Type, ll.N)
+				}
+				if ll.N.Name != nil && ll.N.Name.Defn == n && ll.N.Name.Param.Ntype == nil {
+					ll.N.Type = t.Type
+				}
+				t = structnext(&s)
+			}
+
+			goto out
+		}
+	}
+
+	// x, ok = y
+	if cl == 2 && cr == 1 {
+		if r.Type == nil {
+			goto out
+		}
+		switch r.Op {
+		case OINDEXMAP, ORECV, ODOTTYPE:
+			switch r.Op {
+			case OINDEXMAP:
+				n.Op = OAS2MAPR
+
+			case ORECV:
+				n.Op = OAS2RECV
+
+			case ODOTTYPE:
+				n.Op = OAS2DOTTYPE
+				r.Op = ODOTTYPE2
+			}
+
+			if l.Type != nil {
+				checkassignto(r.Type, l)
+			}
+			if l.Name != nil && l.Name.Defn == n {
+				l.Type = r.Type
+			}
+			l := n.List.Next.N
+			if l.Type != nil && l.Type.Etype != TBOOL {
+				checkassignto(Types[TBOOL], l)
+			}
+			if l.Name != nil && l.Name.Defn == n && l.Name.Param.Ntype == nil {
+				l.Type = Types[TBOOL]
+			}
+			goto out
+		}
+	}
+
+mismatch:
+	Yyerror("assignment count mismatch: %d = %d", cl, cr)
+
+	// second half of dance
+out:
+	n.Typecheck = 1
+
+	for ll := n.List; ll != nil; ll = ll.Next {
+		if ll.N.Typecheck == 0 {
+			typecheck(&ll.N, Erv|Easgn)
+		}
+	}
+}
+
+/*
+ * type check function definition
+ */
+func typecheckfunc(n *Node) {
+	typecheck(&n.Func.Nname, Erv|Easgn)
+	t := n.Func.Nname.Type
+	if t == nil {
+		return
+	}
+	n.Type = t
+	t.Nname = n.Func.Nname
+	rcvr := getthisx(t).Type
+	if rcvr != nil && n.Func.Shortname != nil && !isblank(n.Func.Shortname) {
+		addmethod(n.Func.Shortname.Sym, t, true, n.Func.Nname.Nointerface)
+	}
+
+	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.Name.Decldepth = 1
+		}
+	}
+}
+
+func stringtoarraylit(np **Node) {
+	n := *np
+	if n.Left.Op != OLITERAL || n.Left.Val().Ctype() != CTSTR {
+		Fatal("stringtoarraylit %v", n)
+	}
+
+	s := n.Left.Val().U.(string)
+	var l *NodeList
+	if n.Type.Type.Etype == TUINT8 {
+		// []byte
+		for i := 0; i < len(s); i++ {
+			l = list(l, Nod(OKEY, Nodintconst(int64(i)), Nodintconst(int64(s[0]))))
+		}
+	} else {
+		// []rune
+		i := 0
+		for _, r := range s {
+			l = list(l, Nod(OKEY, Nodintconst(int64(i)), Nodintconst(int64(r))))
+			i++
+		}
+	}
+
+	nn := Nod(OCOMPLIT, nil, typenod(n.Type))
+	nn.List = l
+	typecheck(&nn, Erv)
+	*np = nn
+}
+
+var ntypecheckdeftype int
+
+var methodqueue *NodeList
+
+func domethod(n *Node) {
+	nt := n.Type.Nname
+	typecheck(&nt, Etype)
+	if nt.Type == nil {
+		// type check failed; leave empty func
+		n.Type.Etype = TFUNC
+
+		n.Type.Nod = nil
+		return
+	}
+
+	// If we have
+	//	type I interface {
+	//		M(_ int)
+	//	}
+	// then even though I.M looks like it doesn't care about the
+	// value of its argument, a specific implementation of I may
+	// care.  The _ would suppress the assignment to that argument
+	// while generating a call, so remove it.
+	for t := getinargx(nt.Type).Type; t != nil; t = t.Down {
+		if t.Sym != nil && t.Sym.Name == "_" {
+			t.Sym = nil
+		}
+	}
+
+	*n.Type = *nt.Type
+	n.Type.Nod = nil
+	checkwidth(n.Type)
+}
+
+var mapqueue *NodeList
+
+func copytype(n *Node, t *Type) {
+	if t.Etype == TFORW {
+		// This type isn't computed yet; when it is, update n.
+		t.Copyto = list(t.Copyto, n)
+
+		return
+	}
+
+	maplineno := int(n.Type.Maplineno)
+	embedlineno := int(n.Type.Embedlineno)
+
+	l := n.Type.Copyto
+	*n.Type = *t
+
+	t = n.Type
+	t.Sym = n.Sym
+	t.Local = n.Local
+	if n.Name != nil {
+		t.Vargen = n.Name.Vargen
+	}
+	t.Siggen = 0
+	t.Method = nil
+	t.Xmethod = nil
+	t.Nod = nil
+	t.Printed = 0
+	t.Deferwidth = 0
+	t.Copyto = nil
+
+	// Update nodes waiting on this type.
+	for ; l != nil; l = l.Next {
+		copytype(l.N, t)
+	}
+
+	// Double-check use of type as embedded type.
+	lno := int(lineno)
+
+	if embedlineno != 0 {
+		lineno = int32(embedlineno)
+		if Isptr[t.Etype] {
+			Yyerror("embedded type cannot be a pointer")
+		}
+	}
+
+	lineno = int32(lno)
+
+	// Queue check for map until all the types are done settling.
+	if maplineno != 0 {
+		t.Maplineno = int32(maplineno)
+		mapqueue = list(mapqueue, n)
+	}
+}
+
+func typecheckdeftype(n *Node) {
+	ntypecheckdeftype++
+	lno := int(lineno)
+	setlineno(n)
+	n.Type.Sym = n.Sym
+	n.Typecheck = 1
+	typecheck(&n.Name.Param.Ntype, Etype)
+	t := n.Name.Param.Ntype.Type
+	if t == nil {
+		n.Diag = 1
+		n.Type = nil
+		goto ret
+	}
+
+	if n.Type == nil {
+		n.Diag = 1
+		goto ret
+	}
+
+	// copy new type and clear fields
+	// that don't come along.
+	// anything zeroed here must be zeroed in
+	// typedcl2 too.
+	copytype(n, t)
+
+ret:
+	lineno = int32(lno)
+
+	// if there are no type definitions going on, it's safe to
+	// try to resolve the method types for the interfaces
+	// we just read.
+	if ntypecheckdeftype == 1 {
+		var l *NodeList
+		for {
+			l = methodqueue
+			if l == nil {
+				break
+			}
+			methodqueue = nil
+			for ; l != nil; l = l.Next {
+				domethod(l.N)
+			}
+		}
+
+		for l := mapqueue; l != nil; l = l.Next {
+			lineno = l.N.Type.Maplineno
+			maptype(l.N.Type, Types[TBOOL])
+		}
+
+		lineno = int32(lno)
+	}
+
+	ntypecheckdeftype--
+}
+
+func queuemethod(n *Node) {
+	if ntypecheckdeftype == 0 {
+		domethod(n)
+		return
+	}
+
+	methodqueue = list(methodqueue, n)
+}
+
+func typecheckdef(n *Node) *Node {
+	lno := int(lineno)
+	setlineno(n)
+
+	if n.Op == ONONAME {
+		if n.Diag == 0 {
+			n.Diag = 1
+			if n.Lineno != 0 {
+				lineno = n.Lineno
+			}
+
+			// Note: adderrorname looks for this string and
+			// adds context about the outer expression
+			Yyerror("undefined: %v", n.Sym)
+		}
+
+		return n
+	}
+
+	if n.Walkdef == 1 {
+		return n
+	}
+
+	l := new(NodeList)
+	l.N = n
+	l.Next = typecheckdefstack
+	typecheckdefstack = l
+
+	if n.Walkdef == 2 {
+		Flusherrors()
+		fmt.Printf("typecheckdef loop:")
+		for l := typecheckdefstack; l != nil; l = l.Next {
+			fmt.Printf(" %v", l.N.Sym)
+		}
+		fmt.Printf("\n")
+		Fatal("typecheckdef loop")
+	}
+
+	n.Walkdef = 2
+
+	if n.Type != nil || n.Sym == nil { // builtin or no name
+		goto ret
+	}
+
+	switch n.Op {
+	default:
+		Fatal("typecheckdef %v", Oconv(int(n.Op), 0))
+
+		// not really syms
+	case OGOTO, OLABEL:
+		break
+
+	case OLITERAL:
+		if n.Name.Param.Ntype != nil {
+			typecheck(&n.Name.Param.Ntype, Etype)
+			n.Type = n.Name.Param.Ntype.Type
+			n.Name.Param.Ntype = nil
+			if n.Type == nil {
+				n.Diag = 1
+				goto ret
+			}
+		}
+
+		e := n.Name.Defn
+		n.Name.Defn = nil
+		if e == nil {
+			lineno = n.Lineno
+			Dump("typecheckdef nil defn", n)
+			Yyerror("xxx")
+		}
+
+		typecheck(&e, Erv|Eiota)
+		if Isconst(e, CTNIL) {
+			Yyerror("const initializer cannot be nil")
+			goto ret
+		}
+
+		if e.Type != nil && e.Op != OLITERAL || !isgoconst(e) {
+			if e.Diag == 0 {
+				Yyerror("const initializer %v is not a constant", e)
+				e.Diag = 1
+			}
+
+			goto ret
+		}
+
+		t := n.Type
+		if t != nil {
+			if !okforconst[t.Etype] {
+				Yyerror("invalid constant type %v", t)
+				goto ret
+			}
+
+			if !isideal(e.Type) && !Eqtype(t, e.Type) {
+				Yyerror("cannot use %v as type %v in const initializer", Nconv(e, obj.FmtLong), t)
+				goto ret
+			}
+
+			Convlit(&e, t)
+		}
+
+		n.SetVal(e.Val())
+		n.Type = e.Type
+
+	case ONAME:
+		if n.Name.Param.Ntype != nil {
+			typecheck(&n.Name.Param.Ntype, Etype)
+			n.Type = n.Name.Param.Ntype.Type
+			if n.Type == nil {
+				n.Diag = 1
+				goto ret
+			}
+		}
+
+		if n.Type != nil {
+			break
+		}
+		if n.Name.Defn == nil {
+			if n.Etype != 0 { // like OPRINTN
+				break
+			}
+			if nsavederrors+nerrors > 0 {
+				// Can have undefined variables in x := foo
+				// that make x have an n->ndefn == nil.
+				// If there are other errors anyway, don't
+				// bother adding to the noise.
+				break
+			}
+
+			Fatal("var without type, init: %v", n.Sym)
+		}
+
+		if n.Name.Defn.Op == ONAME {
+			typecheck(&n.Name.Defn, Erv)
+			n.Type = n.Name.Defn.Type
+			break
+		}
+
+		typecheck(&n.Name.Defn, Etop) // fills in n->type
+
+	case OTYPE:
+		if Curfn != nil {
+			defercheckwidth()
+		}
+		n.Walkdef = 1
+		n.Type = typ(TFORW)
+		n.Type.Sym = n.Sym
+		nerrors0 := nerrors
+		typecheckdeftype(n)
+		if n.Type.Etype == TFORW && nerrors > nerrors0 {
+			// Something went wrong during type-checking,
+			// but it was reported. Silence future errors.
+			n.Type.Broke = 1
+		}
+
+		if Curfn != nil {
+			resumecheckwidth()
+		}
+
+		// nothing to see here
+	case OPACK:
+		break
+	}
+
+ret:
+	if n.Op != OLITERAL && n.Type != nil && isideal(n.Type) {
+		Fatal("got %v for %v", n.Type, n)
+	}
+	if typecheckdefstack.N != n {
+		Fatal("typecheckdefstack mismatch")
+	}
+	l = typecheckdefstack
+	typecheckdefstack = l.Next
+
+	lineno = int32(lno)
+	n.Walkdef = 1
+	return n
+}
+
+func checkmake(t *Type, arg string, n *Node) int {
+	if n.Op == OLITERAL {
+		switch n.Val().Ctype() {
+		case CTINT, CTRUNE, CTFLT, CTCPLX:
+			n.SetVal(toint(n.Val()))
+			if mpcmpfixc(n.Val().U.(*Mpint), 0) < 0 {
+				Yyerror("negative %s argument in make(%v)", arg, t)
+				return -1
+			}
+
+			if Mpcmpfixfix(n.Val().U.(*Mpint), Maxintval[TINT]) > 0 {
+				Yyerror("%s argument too large in make(%v)", arg, t)
+				return -1
+			}
+
+			// Delay defaultlit until after we've checked range, to avoid
+			// a redundant "constant NNN overflows int" error.
+			defaultlit(&n, Types[TINT])
+
+			return 0
+
+		default:
+			break
+		}
+	}
+
+	if !Isint[n.Type.Etype] && n.Type.Etype != TIDEAL {
+		Yyerror("non-integer %s argument in make(%v) - %v", arg, t, n.Type)
+		return -1
+	}
+
+	// Defaultlit still necessary for non-constant: n might be 1<<k.
+	defaultlit(&n, Types[TINT])
+
+	return 0
+}
+
+func markbreak(n *Node, implicit *Node) {
+	if n == nil {
+		return
+	}
+
+	switch n.Op {
+	case OBREAK:
+		if n.Left == nil {
+			if implicit != nil {
+				implicit.Hasbreak = true
+			}
+		} else {
+			lab := n.Left.Sym.Label
+			if lab != nil {
+				lab.Def.Hasbreak = true
+			}
+		}
+
+	case OFOR,
+		OSWITCH,
+		OTYPESW,
+		OSELECT,
+		ORANGE:
+		implicit = n
+		fallthrough
+
+		// fall through
+	default:
+		markbreak(n.Left, implicit)
+
+		markbreak(n.Right, implicit)
+		markbreaklist(n.Ninit, implicit)
+		markbreaklist(n.Nbody, implicit)
+		markbreaklist(n.List, implicit)
+		markbreaklist(n.Rlist, implicit)
+	}
+}
+
+func markbreaklist(l *NodeList, implicit *Node) {
+	var n *Node
+	var lab *Label
+
+	for ; l != nil; l = l.Next {
+		n = l.N
+		if n.Op == OLABEL && l.Next != nil && n.Name.Defn == l.Next.N {
+			switch n.Name.Defn.Op {
+			case OFOR,
+				OSWITCH,
+				OTYPESW,
+				OSELECT,
+				ORANGE:
+				lab = new(Label)
+				lab.Def = n.Name.Defn
+				n.Left.Sym.Label = lab
+				markbreak(n.Name.Defn, n.Name.Defn)
+				n.Left.Sym.Label = nil
+				l = l.Next
+				continue
+			}
+		}
+
+		markbreak(n, implicit)
+	}
+}
+
+func isterminating(l *NodeList, top int) bool {
+	if l == nil {
+		return false
+	}
+	if top != 0 {
+		for l.Next != nil && l.N.Op != OLABEL {
+			l = l.Next
+		}
+		markbreaklist(l, nil)
+	}
+
+	for l.Next != nil {
+		l = l.Next
+	}
+	n := l.N
+
+	if n == nil {
+		return false
+	}
+
+	switch n.Op {
+	// NOTE: OLABEL is treated as a separate statement,
+	// not a separate prefix, so skipping to the last statement
+	// in the block handles the labeled statement case by
+	// skipping over the label. No case OLABEL here.
+
+	case OBLOCK:
+		return isterminating(n.List, 0)
+
+	case OGOTO,
+		ORETURN,
+		ORETJMP,
+		OPANIC,
+		OXFALL:
+		return true
+
+	case OFOR:
+		if n.Left != nil {
+			return false
+		}
+		if n.Hasbreak {
+			return false
+		}
+		return true
+
+	case OIF:
+		return isterminating(n.Nbody, 0) && isterminating(n.Rlist, 0)
+
+	case OSWITCH, OTYPESW, OSELECT:
+		if n.Hasbreak {
+			return false
+		}
+		def := 0
+		for l = n.List; l != nil; l = l.Next {
+			if !isterminating(l.N.Nbody, 0) {
+				return false
+			}
+			if l.N.List == nil { // default
+				def = 1
+			}
+		}
+
+		if n.Op != OSELECT && def == 0 {
+			return false
+		}
+		return true
+	}
+
+	return false
+}
+
+func checkreturn(fn *Node) {
+	if fn.Type.Outtuple != 0 && fn.Nbody != nil {
+		if !isterminating(fn.Nbody, 1) {
+			yyerrorl(int(fn.Func.Endlineno), "missing return at end of function")
+		}
+	}
+}
diff --git a/src/cmd/compile/internal/gc/unsafe.go b/src/cmd/compile/internal/gc/unsafe.go
new file mode 100644
index 0000000..a01765b
--- /dev/null
+++ b/src/cmd/compile/internal/gc/unsafe.go
@@ -0,0 +1,165 @@
+// 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"
+
+/*
+ * look for
+ *	unsafe.Sizeof
+ *	unsafe.Offsetof
+ *	unsafe.Alignof
+ * rewrite with a constant
+ */
+func unsafenmagic(nn *Node) *Node {
+	fn := nn.Left
+	args := nn.List
+
+	if safemode != 0 || fn == nil || fn.Op != ONAME {
+		return nil
+	}
+	s := fn.Sym
+	if s == nil {
+		return nil
+	}
+	if s.Pkg != unsafepkg {
+		return nil
+	}
+
+	if args == nil {
+		Yyerror("missing argument for %v", s)
+		return nil
+	}
+
+	r := args.N
+
+	var v int64
+	if s.Name == "Sizeof" {
+		typecheck(&r, Erv)
+		defaultlit(&r, nil)
+		tr := r.Type
+		if tr == nil {
+			goto bad
+		}
+		dowidth(tr)
+		v = tr.Width
+		goto yes
+	}
+
+	if s.Name == "Offsetof" {
+		// must be a selector.
+		if r.Op != OXDOT {
+			goto bad
+		}
+
+		// Remember base of selector to find it back after dot insertion.
+		// Since r->left may be mutated by typechecking, check it explicitly
+		// first to track it correctly.
+		typecheck(&r.Left, Erv)
+
+		base := r.Left
+		typecheck(&r, Erv)
+		switch r.Op {
+		case ODOT, ODOTPTR:
+			break
+
+		case OCALLPART:
+			Yyerror("invalid expression %v: argument is a method value", nn)
+			v = 0
+			goto ret
+
+		default:
+			goto bad
+		}
+
+		v = 0
+
+		// add offsets for inserted dots.
+		var r1 *Node
+		for r1 = r; r1.Left != base; r1 = r1.Left {
+			switch r1.Op {
+			case ODOT:
+				v += r1.Xoffset
+
+			case ODOTPTR:
+				Yyerror("invalid expression %v: selector implies indirection of embedded %v", nn, r1.Left)
+				goto ret
+
+			default:
+				Dump("unsafenmagic", r)
+				Fatal("impossible %v node after dot insertion", Oconv(int(r1.Op), obj.FmtSharp))
+				goto bad
+			}
+		}
+
+		v += r1.Xoffset
+		goto yes
+	}
+
+	if s.Name == "Alignof" {
+		typecheck(&r, Erv)
+		defaultlit(&r, nil)
+		tr := r.Type
+		if tr == nil {
+			goto bad
+		}
+
+		// make struct { byte; T; }
+		t := typ(TSTRUCT)
+
+		t.Type = typ(TFIELD)
+		t.Type.Type = Types[TUINT8]
+		t.Type.Down = typ(TFIELD)
+		t.Type.Down.Type = tr
+
+		// compute struct widths
+		dowidth(t)
+
+		// the offset of T is its required alignment
+		v = t.Type.Down.Width
+
+		goto yes
+	}
+
+	return nil
+
+bad:
+	Yyerror("invalid expression %v", nn)
+	v = 0
+	goto ret
+
+yes:
+	if args.Next != nil {
+		Yyerror("extra arguments for %v", s)
+	}
+
+	// any side effects disappear; ignore init
+ret:
+	var val Val
+	val.U = new(Mpint)
+	Mpmovecfix(val.U.(*Mpint), v)
+	n := Nod(OLITERAL, nil, nil)
+	n.Orig = nn
+	n.SetVal(val)
+	n.Type = Types[TUINTPTR]
+	nn.Type = Types[TUINTPTR]
+	return n
+}
+
+func isunsafebuiltin(n *Node) bool {
+	if n == nil || n.Op != ONAME || n.Sym == nil || n.Sym.Pkg != unsafepkg {
+		return false
+	}
+	if n.Sym.Name == "Sizeof" {
+		return true
+	}
+	if n.Sym.Name == "Offsetof" {
+		return true
+	}
+	if n.Sym.Name == "Alignof" {
+		return true
+	}
+	return false
+}
diff --git a/src/cmd/compile/internal/gc/util.go b/src/cmd/compile/internal/gc/util.go
new file mode 100644
index 0000000..c59af06
--- /dev/null
+++ b/src/cmd/compile/internal/gc/util.go
@@ -0,0 +1,103 @@
+package gc
+
+import (
+	"os"
+	"runtime"
+	"runtime/pprof"
+	"strconv"
+	"strings"
+)
+
+func (n *Node) Line() string {
+	return Ctxt.LineHist.LineString(int(n.Lineno))
+}
+
+func atoi(s string) int {
+	// NOTE: Not strconv.Atoi, accepts hex and octal prefixes.
+	n, _ := strconv.ParseInt(s, 0, 0)
+	return int(n)
+}
+
+func isalnum(c int) bool {
+	return isalpha(c) || isdigit(c)
+}
+
+func isalpha(c int) bool {
+	return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z'
+}
+
+func isdigit(c int) bool {
+	return '0' <= c && c <= '9'
+}
+
+func plan9quote(s string) string {
+	if s == "" {
+		return "'" + strings.Replace(s, "'", "''", -1) + "'"
+	}
+	for i := 0; i < len(s); i++ {
+		if s[i] <= ' ' || s[i] == '\'' {
+			return "'" + strings.Replace(s, "'", "''", -1) + "'"
+		}
+	}
+	return s
+}
+
+// strings.Compare, introduced in Go 1.5.
+func stringsCompare(a, b string) int {
+	if a == b {
+		return 0
+	}
+	if a < b {
+		return -1
+	}
+	return +1
+}
+
+var atExitFuncs []func()
+
+func AtExit(f func()) {
+	atExitFuncs = append(atExitFuncs, f)
+}
+
+func Exit(code int) {
+	for i := len(atExitFuncs) - 1; i >= 0; i-- {
+		f := atExitFuncs[i]
+		atExitFuncs = atExitFuncs[:i]
+		f()
+	}
+	os.Exit(code)
+}
+
+var (
+	cpuprofile     string
+	memprofile     string
+	memprofilerate int64
+)
+
+func startProfile() {
+	if cpuprofile != "" {
+		f, err := os.Create(cpuprofile)
+		if err != nil {
+			Fatal("%v", err)
+		}
+		if err := pprof.StartCPUProfile(f); err != nil {
+			Fatal("%v", err)
+		}
+		AtExit(pprof.StopCPUProfile)
+	}
+	if memprofile != "" {
+		if memprofilerate != 0 {
+			runtime.MemProfileRate = int(memprofilerate)
+		}
+		f, err := os.Create(memprofile)
+		if err != nil {
+			Fatal("%v", err)
+		}
+		AtExit(func() {
+			runtime.GC() // profile all outstanding allocations
+			if err := pprof.WriteHeapProfile(f); err != nil {
+				Fatal("%v", err)
+			}
+		})
+	}
+}
diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go
new file mode 100644
index 0000000..af3e1cc
--- /dev/null
+++ b/src/cmd/compile/internal/gc/walk.go
@@ -0,0 +1,4074 @@
+// 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"
+	"strings"
+)
+
+var mpzero Mpint
+
+// The constant is known to runtime.
+const (
+	tmpstringbufsize = 32
+)
+
+func walk(fn *Node) {
+	Curfn = fn
+
+	if Debug['W'] != 0 {
+		s := fmt.Sprintf("\nbefore %v", Curfn.Func.Nname.Sym)
+		dumplist(s, Curfn.Nbody)
+	}
+
+	lno := int(lineno)
+
+	// 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.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.Func.Dcl; l != nil; l = l.Next {
+		if l.N.Op == ONAME && l.N.Class&^PHEAP == PAUTO && l.N.Name.Defn != nil && l.N.Name.Defn.Op == OTYPESW && l.N.Used {
+			l.N.Name.Defn.Left.Used = true
+		}
+	}
+
+	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 defn := l.N.Name.Defn; defn != nil && defn.Op == OTYPESW {
+			if defn.Left.Used {
+				continue
+			}
+			lineno = defn.Left.Lineno
+			Yyerror("%v declared and not used", l.N.Sym)
+			defn.Left.Used = true // suppress repeats
+		} else {
+			lineno = l.N.Lineno
+			Yyerror("%v declared and not used", l.N.Sym)
+		}
+	}
+
+	lineno = int32(lno)
+	if nerrors != 0 {
+		return
+	}
+	walkstmtlist(Curfn.Nbody)
+	if Debug['W'] != 0 {
+		s := fmt.Sprintf("after walk %v", Curfn.Func.Nname.Sym)
+		dumplist(s, Curfn.Nbody)
+	}
+
+	heapmoves()
+	if Debug['W'] != 0 && Curfn.Func.Enter != nil {
+		s := fmt.Sprintf("enter %v", Curfn.Func.Nname.Sym)
+		dumplist(s, Curfn.Func.Enter)
+	}
+}
+
+func walkstmtlist(l *NodeList) {
+	for ; l != nil; l = l.Next {
+		walkstmt(&l.N)
+	}
+}
+
+func samelist(a *NodeList, b *NodeList) bool {
+	for ; a != nil && b != nil; a, b = a.Next, b.Next {
+		if a.N != b.N {
+			return false
+		}
+	}
+	return a == b
+}
+
+func paramoutheap(fn *Node) bool {
+	for l := fn.Func.Dcl; l != nil; l = l.Next {
+		switch l.N.Class {
+		case PPARAMOUT,
+			PPARAMOUT | PHEAP:
+			return l.N.Addrtaken
+
+			// stop early - parameters are over
+		case PAUTO,
+			PAUTO | PHEAP:
+			return false
+		}
+	}
+
+	return false
+}
+
+// adds "adjust" to all the argument locations for the call n.
+// n must be a defer or go node that has already been walked.
+func adjustargs(n *Node, adjust int) {
+	var arg *Node
+	var lhs *Node
+
+	callfunc := n.Left
+	for args := callfunc.List; args != nil; args = args.Next {
+		arg = args.N
+		if arg.Op != OAS {
+			Yyerror("call arg not assignment")
+		}
+		lhs = arg.Left
+		if lhs.Op == ONAME {
+			// This is a temporary introduced by reorder1.
+			// The real store to the stack appears later in the arg list.
+			continue
+		}
+
+		if lhs.Op != OINDREG {
+			Yyerror("call argument store does not use OINDREG")
+		}
+
+		// can't really check this in machine-indep code.
+		//if(lhs->val.u.reg != D_SP)
+		//      yyerror("call arg assign not indreg(SP)");
+		lhs.Xoffset += int64(adjust)
+	}
+}
+
+func walkstmt(np **Node) {
+	n := *np
+	if n == nil {
+		return
+	}
+	if n.Dodata == 2 { // don't walk, generated by anylit.
+		return
+	}
+
+	setlineno(n)
+
+	walkstmtlist(n.Ninit)
+
+	switch n.Op {
+	default:
+		if n.Op == ONAME {
+			Yyerror("%v is not a top level statement", n.Sym)
+		} else {
+			Yyerror("%v is not a top level statement", Oconv(int(n.Op), 0))
+		}
+		Dump("nottop", n)
+
+	case OAS,
+		OASOP,
+		OAS2,
+		OAS2DOTTYPE,
+		OAS2RECV,
+		OAS2FUNC,
+		OAS2MAPR,
+		OCLOSE,
+		OCOPY,
+		OCALLMETH,
+		OCALLINTER,
+		OCALL,
+		OCALLFUNC,
+		ODELETE,
+		OSEND,
+		OPRINT,
+		OPRINTN,
+		OPANIC,
+		OEMPTY,
+		ORECOVER,
+		OGETG:
+		if n.Typecheck == 0 {
+			Fatal("missing typecheck: %v", Nconv(n, obj.FmtSign))
+		}
+		init := n.Ninit
+		n.Ninit = nil
+		walkexpr(&n, &init)
+		addinit(&n, init)
+		if (*np).Op == OCOPY && n.Op == OCONVNOP {
+			n.Op = OEMPTY // don't leave plain values as statements.
+		}
+
+		// special case for a receive where we throw away
+	// the value received.
+	case ORECV:
+		if n.Typecheck == 0 {
+			Fatal("missing typecheck: %v", Nconv(n, obj.FmtSign))
+		}
+		init := n.Ninit
+		n.Ninit = nil
+
+		walkexpr(&n.Left, &init)
+		n = mkcall1(chanfn("chanrecv1", 2, n.Left.Type), nil, &init, typename(n.Left.Type), n.Left, nodnil())
+		walkexpr(&n, &init)
+
+		addinit(&n, init)
+
+	case OBREAK,
+		ODCL,
+		OCONTINUE,
+		OFALL,
+		OGOTO,
+		OLABEL,
+		ODCLCONST,
+		ODCLTYPE,
+		OCHECKNIL,
+		OVARKILL:
+		break
+
+	case OBLOCK:
+		walkstmtlist(n.List)
+
+	case OXCASE:
+		Yyerror("case statement out of place")
+		n.Op = OCASE
+		fallthrough
+
+	case OCASE:
+		walkstmt(&n.Right)
+
+	case ODEFER:
+		Hasdefer = 1
+		switch n.Left.Op {
+		case OPRINT, OPRINTN:
+			walkprintfunc(&n.Left, &n.Ninit)
+
+		case OCOPY:
+			n.Left = copyany(n.Left, &n.Ninit, 1)
+
+		default:
+			walkexpr(&n.Left, &n.Ninit)
+		}
+
+		// make room for size & fn arguments.
+		adjustargs(n, 2*Widthptr)
+
+	case OFOR:
+		if n.Left != nil {
+			walkstmtlist(n.Left.Ninit)
+			init := n.Left.Ninit
+			n.Left.Ninit = nil
+			walkexpr(&n.Left, &init)
+			addinit(&n.Left, init)
+		}
+
+		walkstmt(&n.Right)
+		walkstmtlist(n.Nbody)
+
+	case OIF:
+		walkexpr(&n.Left, &n.Ninit)
+		walkstmtlist(n.Nbody)
+		walkstmtlist(n.Rlist)
+
+	case OPROC:
+		switch n.Left.Op {
+		case OPRINT, OPRINTN:
+			walkprintfunc(&n.Left, &n.Ninit)
+
+		case OCOPY:
+			n.Left = copyany(n.Left, &n.Ninit, 1)
+
+		default:
+			walkexpr(&n.Left, &n.Ninit)
+		}
+
+		// make room for size & fn arguments.
+		adjustargs(n, 2*Widthptr)
+
+	case ORETURN:
+		walkexprlist(n.List, &n.Ninit)
+		if n.List == nil {
+			break
+		}
+		if (Curfn.Type.Outnamed != 0 && count(n.List) > 1) || paramoutheap(Curfn) {
+			// assign to the function out parameters,
+			// so that reorder3 can fix up conflicts
+			var rl *NodeList
+
+			var cl uint8
+			for ll := Curfn.Func.Dcl; ll != nil; ll = ll.Next {
+				cl = ll.N.Class &^ PHEAP
+				if cl == PAUTO {
+					break
+				}
+				if cl == PPARAMOUT {
+					rl = list(rl, ll.N)
+				}
+			}
+
+			if samelist(rl, n.List) {
+				// special return in disguise
+				n.List = nil
+
+				break
+			}
+
+			if count(n.List) == 1 && count(rl) > 1 {
+				// OAS2FUNC in disguise
+				f := n.List.N
+
+				if f.Op != OCALLFUNC && f.Op != OCALLMETH && f.Op != OCALLINTER {
+					Fatal("expected return of call, have %v", f)
+				}
+				n.List = concat(list1(f), ascompatet(int(n.Op), rl, &f.Type, 0, &n.Ninit))
+				break
+			}
+
+			// move function calls out, to make reorder3's job easier.
+			walkexprlistsafe(n.List, &n.Ninit)
+
+			ll := ascompatee(int(n.Op), rl, n.List, &n.Ninit)
+			n.List = reorder3(ll)
+			break
+		}
+
+		ll := ascompatte(int(n.Op), nil, false, Getoutarg(Curfn.Type), n.List, 1, &n.Ninit)
+		n.List = ll
+
+	case ORETJMP:
+		break
+
+	case OSELECT:
+		walkselect(n)
+
+	case OSWITCH:
+		walkswitch(n)
+
+	case ORANGE:
+		walkrange(n)
+
+	case OXFALL:
+		Yyerror("fallthrough statement out of place")
+		n.Op = OFALL
+	}
+
+	if n.Op == ONAME {
+		Fatal("walkstmt ended up with name: %v", Nconv(n, obj.FmtSign))
+	}
+
+	*np = n
+}
+
+func isSmallMakeSlice(n *Node) bool {
+	if n.Op != OMAKESLICE {
+		return false
+	}
+	l := n.Left
+	r := n.Right
+	if r == nil {
+		r = l
+	}
+	t := n.Type
+
+	return Smallintconst(l) && Smallintconst(r) && (t.Type.Width == 0 || Mpgetfix(r.Val().U.(*Mpint)) < (1<<16)/t.Type.Width)
+}
+
+/*
+ * walk the whole tree of the body of an
+ * expression or simple statement.
+ * the types expressions are calculated.
+ * compile-time constants are evaluated.
+ * complex side effects like statements are appended to init
+ */
+func walkexprlist(l *NodeList, init **NodeList) {
+	for ; l != nil; l = l.Next {
+		walkexpr(&l.N, init)
+	}
+}
+
+func walkexprlistsafe(l *NodeList, init **NodeList) {
+	for ; l != nil; l = l.Next {
+		l.N = safeexpr(l.N, init)
+		walkexpr(&l.N, init)
+	}
+}
+
+func walkexprlistcheap(l *NodeList, init **NodeList) {
+	for ; l != nil; l = l.Next {
+		l.N = cheapexpr(l.N, init)
+		walkexpr(&l.N, init)
+	}
+}
+
+func walkexpr(np **Node, init **NodeList) {
+	n := *np
+
+	if n == nil {
+		return
+	}
+
+	if init == &n.Ninit {
+		// not okay to use n->ninit when walking n,
+		// because we might replace n with some other node
+		// and would lose the init list.
+		Fatal("walkexpr init == &n->ninit")
+	}
+
+	if n.Ninit != nil {
+		walkstmtlist(n.Ninit)
+		*init = concat(*init, n.Ninit)
+		n.Ninit = nil
+	}
+
+	// annoying case - not typechecked
+	if n.Op == OKEY {
+		walkexpr(&n.Left, init)
+		walkexpr(&n.Right, init)
+		return
+	}
+
+	lno := setlineno(n)
+
+	if Debug['w'] > 1 {
+		Dump("walk-before", n)
+	}
+
+	if n.Typecheck != 1 {
+		Fatal("missed typecheck: %v\n", Nconv(n, obj.FmtSign))
+	}
+
+	switch n.Op {
+	default:
+		Dump("walk", n)
+		Fatal("walkexpr: switch 1 unknown op %v", Nconv(n, obj.FmtShort|obj.FmtSign))
+
+	case OTYPE,
+		ONONAME,
+		OINDREG,
+		OEMPTY,
+		OPARAM,
+		OGETG:
+		goto ret
+
+	case ONOT,
+		OMINUS,
+		OPLUS,
+		OCOM,
+		OREAL,
+		OIMAG,
+		ODOTMETH,
+		ODOTINTER:
+		walkexpr(&n.Left, init)
+		goto ret
+
+	case OIND:
+		walkexpr(&n.Left, init)
+		goto ret
+
+	case ODOT:
+		usefield(n)
+		walkexpr(&n.Left, init)
+		goto ret
+
+	case ODOTPTR:
+		usefield(n)
+		if n.Op == ODOTPTR && n.Left.Type.Type.Width == 0 {
+			// No actual copy will be generated, so emit an explicit nil check.
+			n.Left = cheapexpr(n.Left, init)
+
+			checknil(n.Left, init)
+		}
+
+		walkexpr(&n.Left, init)
+		goto ret
+
+	case OEFACE:
+		walkexpr(&n.Left, init)
+		walkexpr(&n.Right, init)
+		goto ret
+
+	case OSPTR, OITAB:
+		walkexpr(&n.Left, init)
+		goto ret
+
+	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] {
+			t = t.Type
+		}
+		if Isfixedarray(t) {
+			safeexpr(n.Left, init)
+			Nodconst(n, n.Type, t.Bound)
+			n.Typecheck = 1
+		}
+
+		goto ret
+
+	case OLSH, ORSH:
+		walkexpr(&n.Left, init)
+		walkexpr(&n.Right, init)
+		t := n.Left.Type
+		n.Bounded = bounded(n.Right, 8*t.Width)
+		if Debug['m'] != 0 && n.Etype != 0 && !Isconst(n.Right, CTINT) {
+			Warn("shift bounds check elided")
+		}
+		goto ret
+
+		// Use results from call expression as arguments for complex.
+	case OAND,
+		OSUB,
+		OHMUL,
+		OLT,
+		OLE,
+		OGE,
+		OGT,
+		OADD,
+		OCOMPLEX,
+		OLROT:
+		if n.Op == OCOMPLEX && n.Left == nil && n.Right == nil {
+			n.Left = n.List.N
+			n.Right = n.List.Next.N
+		}
+
+		walkexpr(&n.Left, init)
+		walkexpr(&n.Right, init)
+		goto ret
+
+	case OOR, OXOR:
+		walkexpr(&n.Left, init)
+		walkexpr(&n.Right, init)
+		walkrotate(&n)
+		goto ret
+
+	case OEQ, ONE:
+		walkexpr(&n.Left, init)
+		walkexpr(&n.Right, init)
+
+		// Disable safemode while compiling this code: the code we
+		// generate internally can refer to unsafe.Pointer.
+		// In this case it can happen if we need to generate an ==
+		// for a struct containing a reflect.Value, which itself has
+		// an unexported field of type unsafe.Pointer.
+		old_safemode := safemode
+
+		safemode = 0
+		walkcompare(&n, init)
+		safemode = old_safemode
+		goto ret
+
+	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.
+		var ll *NodeList
+
+		walkexpr(&n.Right, &ll)
+		addinit(&n.Right, ll)
+		goto ret
+
+	case OPRINT, OPRINTN:
+		walkexprlist(n.List, init)
+		n = walkprint(n, init)
+		goto ret
+
+	case OPANIC:
+		n = mkcall("gopanic", nil, init, n.Left)
+		goto ret
+
+	case ORECOVER:
+		n = mkcall("gorecover", n.Type, init, Nod(OADDR, nodfp, nil))
+		goto ret
+
+	case OLITERAL:
+		n.Addable = true
+		goto ret
+
+	case OCLOSUREVAR, OCFUNC:
+		n.Addable = true
+		goto ret
+
+	case ONAME:
+		if n.Class&PHEAP == 0 && n.Class != PPARAMREF {
+			n.Addable = true
+		}
+		goto ret
+
+	case OCALLINTER:
+		t := n.Left.Type
+		if n.List != nil && n.List.N.Op == OAS {
+			goto ret
+		}
+		walkexpr(&n.Left, init)
+		walkexprlist(n.List, init)
+		ll := ascompatte(int(n.Op), n, n.Isddd, getinarg(t), n.List, 0, init)
+		n.List = reorder1(ll)
+		goto ret
+
+	case OCALLFUNC:
+		if n.Left.Op == OCLOSURE {
+			// Transform direct call of a closure to call of a normal function.
+			// transformclosure already did all preparation work.
+
+			// Prepend captured variables to argument list.
+			n.List = concat(n.Left.Func.Enter, n.List)
+
+			n.Left.Func.Enter = nil
+
+			// Replace OCLOSURE with ONAME/PFUNC.
+			n.Left = n.Left.Func.Closure.Func.Nname
+
+			// Update type of OCALLFUNC node.
+			// Output arguments had not changed, but their offsets could.
+			if n.Left.Type.Outtuple == 1 {
+				t := getoutargx(n.Left.Type).Type
+				if t.Etype == TFIELD {
+					t = t.Type
+				}
+				n.Type = t
+			} else {
+				n.Type = getoutargx(n.Left.Type)
+			}
+		}
+
+		t := n.Left.Type
+		if n.List != nil && n.List.N.Op == OAS {
+			goto ret
+		}
+
+		walkexpr(&n.Left, init)
+		walkexprlist(n.List, init)
+
+		if n.Left.Op == ONAME && n.Left.Sym.Name == "Sqrt" && n.Left.Sym.Pkg.Path == "math" {
+			switch Thearch.Thechar {
+			case '5', '6', '7':
+				n.Op = OSQRT
+				n.Left = n.List.N
+				n.List = nil
+				goto ret
+			}
+		}
+
+		ll := ascompatte(int(n.Op), n, n.Isddd, getinarg(t), n.List, 0, init)
+		n.List = reorder1(ll)
+		goto ret
+
+	case OCALLMETH:
+		t := n.Left.Type
+		if n.List != nil && n.List.N.Op == OAS {
+			goto ret
+		}
+		walkexpr(&n.Left, init)
+		walkexprlist(n.List, 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)
+		n.List = reorder1(ll)
+		goto ret
+
+	case OAS:
+		*init = concat(*init, n.Ninit)
+		n.Ninit = nil
+
+		walkexpr(&n.Left, init)
+		n.Left = safeexpr(n.Left, init)
+
+		if oaslit(n, init) {
+			goto ret
+		}
+
+		if n.Right == nil || iszero(n.Right) && flag_race == 0 {
+			goto ret
+		}
+
+		switch n.Right.Op {
+		default:
+			walkexpr(&n.Right, init)
+
+		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)
+
+			if Debug_typeassert > 0 {
+				Warn("type assertion not inlined")
+			}
+
+			buf := "assert" + type2IET(r.Left.Type) + "2" + type2IET(r.Type)
+			fn := syslook(buf, 1)
+			substArgTypes(fn, r.Left.Type, r.Type)
+
+			n = mkcall1(fn, nil, init, typename(r.Type), r.Left, n1)
+			walkexpr(&n, init)
+			goto ret
+
+		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)
+			r := n.Right.Left // the channel
+			n = mkcall1(chanfn("chanrecv1", 2, r.Type), nil, init, typename(r.Type), r, n1)
+			walkexpr(&n, init)
+			goto ret
+
+		case OAPPEND:
+			// x = append(...)
+			r := n.Right
+			if r.Isddd {
+				r = appendslice(r, init) // also works for append(slice, string).
+			} else {
+				r = walkappend(r, init, n)
+			}
+			n.Right = r
+			if r.Op == OAPPEND {
+				// Left in place for back end.
+				// Do not add a new write barrier.
+				goto ret
+			}
+			// Otherwise, lowered for race detector.
+			// Treat as ordinary assignment.
+		}
+
+		if n.Left != nil && n.Right != nil {
+			r := convas(Nod(OAS, n.Left, n.Right), init)
+			r.Dodata = n.Dodata
+			n = r
+			n = applywritebarrier(n, init)
+		}
+
+		goto ret
+
+	case OAS2:
+		*init = concat(*init, n.Ninit)
+		n.Ninit = nil
+		walkexprlistsafe(n.List, init)
+		walkexprlistsafe(n.Rlist, init)
+		ll := ascompatee(OAS, n.List, n.Rlist, init)
+		ll = reorder3(ll)
+		for lr := ll; lr != nil; lr = lr.Next {
+			lr.N = applywritebarrier(lr.N, init)
+		}
+		n = liststmt(ll)
+		goto ret
+
+		// a,b,... = fn()
+	case OAS2FUNC:
+		*init = concat(*init, n.Ninit)
+
+		n.Ninit = nil
+		r := n.Rlist.N
+		walkexprlistsafe(n.List, init)
+		walkexpr(&r, init)
+
+		ll := ascompatet(int(n.Op), n.List, &r.Type, 0, init)
+		for lr := ll; lr != nil; lr = lr.Next {
+			lr.N = applywritebarrier(lr.N, init)
+		}
+		n = liststmt(concat(list1(r), ll))
+		goto ret
+
+		// x, y = <-c
+	// orderstmt made sure x is addressable.
+	case OAS2RECV:
+		*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
+		fn := chanfn("chanrecv2", 2, r.Left.Type)
+		r = mkcall1(fn, n.List.Next.N.Type, init, typename(r.Left.Type), r.Left, n1)
+		n = Nod(OAS, n.List.Next.N, r)
+		typecheck(&n, Etop)
+		goto ret
+
+		// a,b = m[i];
+	case OAS2MAPR:
+		*init = concat(*init, n.Ninit)
+
+		n.Ninit = nil
+		r := n.Rlist.N
+		walkexprlistsafe(n.List, init)
+		walkexpr(&r.Left, init)
+		walkexpr(&r.Right, init)
+		t := r.Left.Type
+		p := ""
+		if t.Type.Width <= 128 { // Check ../../runtime/hashmap.go:maxValueSize before changing.
+			switch Simsimtype(t.Down) {
+			case TINT32, TUINT32:
+				p = "mapaccess2_fast32"
+
+			case TINT64, TUINT64:
+				p = "mapaccess2_fast64"
+
+			case TSTRING:
+				p = "mapaccess2_faststr"
+			}
+		}
+
+		var key *Node
+		if p != "" {
+			// fast versions take key by value
+			key = r.Right
+		} else {
+			// standard version takes key by reference
+			// orderexpr made sure key is addressable.
+			key = Nod(OADDR, r.Right, nil)
+
+			p = "mapaccess2"
+		}
+
+		// from:
+		//   a,b = m[i]
+		// to:
+		//   var,b = mapaccess2*(t, m, i)
+		//   a = *var
+		a := n.List.N
+
+		fn := mapfn(p, t)
+		r = mkcall1(fn, getoutargx(fn.Type), init, typename(t), r.Left, key)
+
+		// mapaccess2* returns a typed bool, but due to spec changes,
+		// the boolean result of i.(T) is now untyped so we make it the
+		// same type as the variable on the lhs.
+		if !isblank(n.List.Next.N) {
+			r.Type.Type.Down.Type = n.List.Next.N.Type
+		}
+		n.Rlist = list1(r)
+		n.Op = OAS2FUNC
+
+		// don't generate a = *var if a is _
+		if !isblank(a) {
+			var_ := temp(Ptrto(t.Type))
+			var_.Typecheck = 1
+			n.List.N = var_
+			walkexpr(&n, init)
+			*init = list(*init, n)
+			n = Nod(OAS, a, Nod(OIND, var_, nil))
+		}
+
+		typecheck(&n, Etop)
+		walkexpr(&n, init)
+
+		// mapaccess needs a zero value to be at least this big.
+		if zerosize < t.Type.Width {
+			zerosize = t.Type.Width
+		}
+
+		// TODO: ptr is always non-nil, so disable nil check for this OIND op.
+		goto ret
+
+	case ODELETE:
+		*init = concat(*init, n.Ninit)
+		n.Ninit = nil
+		map_ := n.List.N
+		key := n.List.Next.N
+		walkexpr(&map_, init)
+		walkexpr(&key, init)
+
+		// orderstmt made sure key is addressable.
+		key = Nod(OADDR, key, nil)
+
+		t := map_.Type
+		n = mkcall1(mapfndel("mapdelete", t), nil, init, typename(t), map_, key)
+		goto ret
+
+	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
+
+		walkexprlistsafe(n.List, init)
+		walkexpr(&e.Left, init)
+		t := e.Type    // T
+		from := e.Left // i
+
+		oktype := Types[TBOOL]
+		ok := n.List.Next.N
+		if !isblank(ok) {
+			oktype = ok.Type
+		}
+
+		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:
+		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)
+
+		// Optimize convT2E as a two-word copy when T is pointer-shaped.
+		if isnilinter(n.Type) && isdirectiface(n.Left.Type) {
+			l := Nod(OEFACE, typename(n.Left.Type), n.Left)
+			l.Type = n.Type
+			l.Typecheck = n.Typecheck
+			n = l
+			goto ret
+		}
+
+		// Build name of function: convI2E etc.
+		// Not all names are possible
+		// (e.g., we'll never generate convE2E or convE2I).
+		buf := "conv" + type2IET(n.Left.Type) + "2" + type2IET(n.Type)
+		fn := syslook(buf, 1)
+		var ll *NodeList
+		if !Isinter(n.Left.Type) {
+			ll = list(ll, typename(n.Left.Type))
+		}
+		if !isnilinter(n.Type) {
+			ll = list(ll, typename(n.Type))
+		}
+		if !Isinter(n.Left.Type) && !isnilinter(n.Type) {
+			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
+				l.Type = Ptrto(Types[TUINT8])
+				l.Addable = true
+				l.Class = PEXTERN
+				l.Xoffset = 0
+				sym.Def = l
+				ggloblsym(sym, int32(Widthptr), obj.DUPOK|obj.NOPTR)
+			}
+
+			l := Nod(OADDR, sym.Def, nil)
+			l.Addable = true
+			ll = list(ll, l)
+
+			if isdirectiface(n.Left.Type) {
+				/* For pointer types, we can make a special form of optimization
+				 *
+				 * These statements are put onto the expression init list:
+				 * 	Itab *tab = atomicloadtype(&cache);
+				 * 	if(tab == nil)
+				 * 		tab = typ2Itab(type, itype, &cache);
+				 *
+				 * The CONVIFACE expression is replaced with this:
+				 * 	OEFACE{tab, ptr};
+				 */
+				l := temp(Ptrto(Types[TUINT8]))
+
+				n1 := Nod(OAS, l, sym.Def)
+				typecheck(&n1, Etop)
+				*init = list(*init, n1)
+
+				fn := syslook("typ2Itab", 1)
+				n1 = Nod(OCALL, fn, nil)
+				n1.List = ll
+				typecheck(&n1, Erv)
+				walkexpr(&n1, init)
+
+				n2 := Nod(OIF, nil, nil)
+				n2.Left = Nod(OEQ, l, nodnil())
+				n2.Nbody = list1(Nod(OAS, l, n1))
+				n2.Likely = -1
+				typecheck(&n2, Etop)
+				*init = list(*init, n2)
+
+				l = Nod(OEFACE, l, n.Left)
+				l.Typecheck = n.Typecheck
+				l.Type = n.Type
+				n = l
+				goto ret
+			}
+		}
+
+		if Isinter(n.Left.Type) {
+			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
+			// 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
+			// have to fall back on allocating a temp here.
+			if islvalue(n.Left) {
+				ll = list(ll, Nod(OADDR, n.Left, nil))
+			} 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)
+		}
+
+		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
+		typecheck(&n, Erv)
+		walkexpr(&n, init)
+		goto ret
+
+	case OCONV, OCONVNOP:
+		if Thearch.Thechar == '5' {
+			if Isfloat[n.Left.Type.Etype] {
+				if n.Type.Etype == TINT64 {
+					n = mkcall("float64toint64", n.Type, init, conv(n.Left, Types[TFLOAT64]))
+					goto ret
+				}
+
+				if n.Type.Etype == TUINT64 {
+					n = mkcall("float64touint64", n.Type, init, conv(n.Left, Types[TFLOAT64]))
+					goto ret
+				}
+			}
+
+			if Isfloat[n.Type.Etype] {
+				if n.Left.Type.Etype == TINT64 {
+					n = mkcall("int64tofloat64", n.Type, init, conv(n.Left, Types[TINT64]))
+					goto ret
+				}
+
+				if n.Left.Type.Etype == TUINT64 {
+					n = mkcall("uint64tofloat64", n.Type, init, conv(n.Left, Types[TUINT64]))
+					goto ret
+				}
+			}
+		}
+
+		walkexpr(&n.Left, init)
+		goto ret
+
+	case OANDNOT:
+		walkexpr(&n.Left, init)
+		n.Op = OAND
+		n.Right = Nod(OCOM, n.Right, nil)
+		typecheck(&n.Right, Erv)
+		walkexpr(&n.Right, init)
+		goto ret
+
+	case OMUL:
+		walkexpr(&n.Left, init)
+		walkexpr(&n.Right, init)
+		walkmul(&n, init)
+		goto ret
+
+	case ODIV, OMOD:
+		walkexpr(&n.Left, init)
+		walkexpr(&n.Right, init)
+
+		/*
+		 * rewrite complex div into function call.
+		 */
+		et := int(n.Left.Type.Etype)
+
+		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)
+			goto ret
+		}
+
+		// Nothing to do for float divisions.
+		if Isfloat[et] {
+			goto ret
+		}
+
+		// Try rewriting as shifts or magic multiplies.
+		walkdiv(&n, init)
+
+		/*
+		 * rewrite 64-bit div and mod into function calls
+		 * on 32-bit architectures.
+		 */
+		switch n.Op {
+		case OMOD, ODIV:
+			if Widthreg >= 8 || (et != TUINT64 && et != TINT64) {
+				goto ret
+			}
+			var fn string
+			if et == TINT64 {
+				fn = "int64"
+			} else {
+				fn = "uint64"
+			}
+			if n.Op == ODIV {
+				fn += "div"
+			} else {
+				fn += "mod"
+			}
+			n = mkcall(fn, n.Type, init, conv(n.Left, Types[et]), conv(n.Right, Types[et]))
+
+		default:
+			break
+		}
+
+		goto ret
+
+	case OINDEX:
+		walkexpr(&n.Left, init)
+
+		// save the original node for bounds checking elision.
+		// If it was a ODIV/OMOD walk might rewrite it.
+		r := n.Right
+
+		walkexpr(&n.Right, init)
+
+		// if range of type cannot exceed static array bound,
+		// disable bounds check.
+		if n.Bounded {
+			goto ret
+		}
+		t := n.Left.Type
+		if t != nil && Isptr[t.Etype] {
+			t = t.Type
+		}
+		if Isfixedarray(t) {
+			n.Bounded = bounded(r, t.Bound)
+			if Debug['m'] != 0 && n.Bounded && !Isconst(n.Right, CTINT) {
+				Warn("index bounds check elided")
+			}
+			if Smallintconst(n.Right) && !n.Bounded {
+				Yyerror("index out of bounds")
+			}
+		} else if Isconst(n.Left, CTSTR) {
+			n.Bounded = bounded(r, int64(len(n.Left.Val().U.(string))))
+			if Debug['m'] != 0 && n.Bounded && !Isconst(n.Right, CTINT) {
+				Warn("index bounds check elided")
+			}
+			if Smallintconst(n.Right) {
+				if !n.Bounded {
+					Yyerror("index out of bounds")
+				} else {
+					// replace "abc"[1] with 'b'.
+					// delayed until now because "abc"[1] is not
+					// an ideal constant.
+					v := Mpgetfix(n.Right.Val().U.(*Mpint))
+
+					Nodconst(n, n.Type, int64(n.Left.Val().U.(string)[v]))
+					n.Typecheck = 1
+				}
+			}
+		}
+
+		if Isconst(n.Right, CTINT) {
+			if Mpcmpfixfix(n.Right.Val().U.(*Mpint), &mpzero) < 0 || Mpcmpfixfix(n.Right.Val().U.(*Mpint), Maxintval[TINT]) > 0 {
+				Yyerror("index out of bounds")
+			}
+		}
+		goto ret
+
+	case OINDEXMAP:
+		if n.Etype == 1 {
+			goto ret
+		}
+		walkexpr(&n.Left, init)
+		walkexpr(&n.Right, init)
+
+		t := n.Left.Type
+		p := ""
+		if t.Type.Width <= 128 { // Check ../../runtime/hashmap.go:maxValueSize before changing.
+			switch Simsimtype(t.Down) {
+			case TINT32, TUINT32:
+				p = "mapaccess1_fast32"
+
+			case TINT64, TUINT64:
+				p = "mapaccess1_fast64"
+
+			case TSTRING:
+				p = "mapaccess1_faststr"
+			}
+		}
+
+		var key *Node
+		if p != "" {
+			// fast versions take key by value
+			key = n.Right
+		} else {
+			// standard version takes key by reference.
+			// orderexpr made sure key is addressable.
+			key = Nod(OADDR, n.Right, nil)
+
+			p = "mapaccess1"
+		}
+
+		n = mkcall1(mapfn(p, t), Ptrto(t.Type), init, typename(t), n.Left, key)
+		n = Nod(OIND, n, nil)
+		n.Type = t.Type
+		n.Typecheck = 1
+
+		// mapaccess needs a zero value to be at least this big.
+		if zerosize < t.Type.Width {
+			zerosize = t.Type.Width
+		}
+		goto ret
+
+	case ORECV:
+		Fatal("walkexpr ORECV") // should see inside OAS only
+
+	case OSLICE, OSLICEARR, OSLICESTR:
+		walkexpr(&n.Left, init)
+		walkexpr(&n.Right.Left, init)
+		if n.Right.Left != nil && iszero(n.Right.Left) {
+			// Reduce x[0:j] to x[:j].
+			n.Right.Left = nil
+		}
+		walkexpr(&n.Right.Right, init)
+		n = reduceSlice(n)
+		goto ret
+
+	case OSLICE3, OSLICE3ARR:
+		walkexpr(&n.Left, init)
+		walkexpr(&n.Right.Left, init)
+		if n.Right.Left != nil && iszero(n.Right.Left) {
+			// Reduce x[0:j:k] to x[:j:k].
+			n.Right.Left = nil
+		}
+		walkexpr(&n.Right.Right.Left, init)
+		walkexpr(&n.Right.Right.Right, init)
+
+		r := n.Right.Right.Right
+		if r != nil && r.Op == OCAP && samesafeexpr(n.Left, r.Left) {
+			// Reduce x[i:j:cap(x)] to x[i:j].
+			n.Right.Right = n.Right.Right.Left
+			if n.Op == OSLICE3 {
+				n.Op = OSLICE
+			} else {
+				n.Op = OSLICEARR
+			}
+			n = reduceSlice(n)
+			goto ret
+		}
+		goto ret
+
+	case OADDR:
+		walkexpr(&n.Left, init)
+		goto ret
+
+	case ONEW:
+		if n.Esc == EscNone {
+			if n.Type.Type.Width >= 1<<16 {
+				Fatal("large ONEW with EscNone: %v", n)
+			}
+			r := temp(n.Type.Type)
+			r = Nod(OAS, r, nil) // zero temp
+			typecheck(&r, Etop)
+			*init = list(*init, r)
+			r = Nod(OADDR, r.Left, nil)
+			typecheck(&r, Erv)
+			n = r
+		} else {
+			n = callnew(n.Type.Type)
+		}
+
+		goto ret
+
+		// If one argument to the comparison is an empty string,
+	// 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.(string)) == 0) || (Isconst(n.Right, CTSTR) && len(n.Right.Val().U.(string)) == 0) {
+			r := Nod(int(n.Etype), Nod(OLEN, n.Left, nil), Nod(OLEN, n.Right, nil))
+			typecheck(&r, Erv)
+			walkexpr(&r, init)
+			r.Type = n.Type
+			n = r
+			goto ret
+		}
+
+		// s + "badgerbadgerbadger" == "badgerbadgerbadger"
+		if (n.Etype == OEQ || n.Etype == ONE) && Isconst(n.Right, CTSTR) && n.Left.Op == OADDSTR && count(n.Left.List) == 2 && Isconst(n.Left.List.Next.N, CTSTR) && cmpslit(n.Right, n.Left.List.Next.N) == 0 {
+			r := Nod(int(n.Etype), Nod(OLEN, n.Left.List.N, nil), Nodintconst(0))
+			typecheck(&r, Erv)
+			walkexpr(&r, init)
+			r.Type = n.Type
+			n = r
+			goto ret
+		}
+
+		var r *Node
+		if n.Etype == OEQ || n.Etype == ONE {
+			// prepare for rewrite below
+			n.Left = cheapexpr(n.Left, init)
+
+			n.Right = cheapexpr(n.Right, init)
+
+			r = mkcall("eqstring", Types[TBOOL], init, conv(n.Left, Types[TSTRING]), conv(n.Right, Types[TSTRING]))
+
+			// quick check of len before full compare for == or !=
+			// eqstring assumes that the lengths are equal
+			if n.Etype == OEQ {
+				// len(left) == len(right) && eqstring(left, right)
+				r = Nod(OANDAND, Nod(OEQ, Nod(OLEN, n.Left, nil), Nod(OLEN, n.Right, nil)), r)
+			} else {
+				// len(left) != len(right) || !eqstring(left, right)
+				r = Nod(ONOT, r, nil)
+
+				r = Nod(OOROR, Nod(ONE, Nod(OLEN, n.Left, nil), Nod(OLEN, n.Right, nil)), r)
+			}
+
+			typecheck(&r, Erv)
+			walkexpr(&r, nil)
+		} else {
+			// sys_cmpstring(s1, s2) :: 0
+			r = mkcall("cmpstring", Types[TINT], init, conv(n.Left, Types[TSTRING]), conv(n.Right, Types[TSTRING]))
+
+			r = Nod(int(n.Etype), r, Nodintconst(0))
+		}
+
+		typecheck(&r, Erv)
+		if n.Type.Etype != TBOOL {
+			Fatal("cmp %v", n.Type)
+		}
+		r.Type = n.Type
+		n = r
+		goto ret
+
+	case OADDSTR:
+		n = addstr(n, init)
+		goto ret
+
+	case OAPPEND:
+		// order should make sure we only see OAS(node, OAPPEND), which we handle above.
+		Fatal("append outside assignment")
+
+	case OCOPY:
+		n = copyany(n, init, flag_race)
+		goto ret
+
+		// cannot use chanfn - closechan takes any, not chan any
+	case OCLOSE:
+		fn := syslook("closechan", 1)
+
+		substArgTypes(fn, n.Left.Type)
+		n = mkcall1(fn, nil, init, n.Left)
+		goto ret
+
+	case OMAKECHAN:
+		n = mkcall1(chanfn("makechan", 1, n.Type), n.Type, init, typename(n.Type), conv(n.Left, Types[TINT64]))
+		goto ret
+
+	case OMAKEMAP:
+		t := n.Type
+
+		fn := syslook("makemap", 1)
+
+		a := nodnil() // hmap buffer
+		r := nodnil() // bucket buffer
+		if n.Esc == EscNone {
+			// Allocate hmap buffer on stack.
+			var_ := temp(hmap(t))
+
+			a = Nod(OAS, var_, nil) // zero temp
+			typecheck(&a, Etop)
+			*init = list(*init, a)
+			a = Nod(OADDR, var_, nil)
+
+			// Allocate one bucket on stack.
+			// Maximum key/value size is 128 bytes, larger objects
+			// are stored with an indirection. So max bucket size is 2048+eps.
+			var_ = temp(mapbucket(t))
+
+			r = Nod(OAS, var_, nil) // zero temp
+			typecheck(&r, Etop)
+			*init = list(*init, r)
+			r = Nod(OADDR, var_, nil)
+		}
+
+		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
+
+	case OMAKESLICE:
+		l := n.Left
+		r := n.Right
+		if r == nil {
+			r = safeexpr(l, init)
+			l = r
+		}
+		t := n.Type
+		if n.Esc == EscNone {
+			if !isSmallMakeSlice(n) {
+				Fatal("non-small OMAKESLICE with EscNone: %v", n)
+			}
+			// var arr [r]T
+			// n = arr[:l]
+			t = aindex(r, t.Type) // [r]T
+			var_ := temp(t)
+			a := Nod(OAS, var_, nil) // zero temp
+			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.
+			typecheck(&r, Erv)
+			walkexpr(&r, init)
+			n = r
+		} else {
+			// makeslice(t *Type, nel int64, max int64) (ary []any)
+			fn := syslook("makeslice", 1)
+
+			substArgTypes(fn, t.Type) // any-1
+			n = mkcall1(fn, n.Type, init, typename(n.Type), conv(l, Types[TINT64]), conv(r, Types[TINT64]))
+		}
+
+		goto ret
+
+	case ORUNESTR:
+		a := nodnil()
+		if n.Esc == EscNone {
+			t := aindex(Nodintconst(4), Types[TUINT8])
+			var_ := temp(t)
+			a = Nod(OADDR, var_, nil)
+		}
+
+		// intstring(*[4]byte, rune)
+		n = mkcall("intstring", n.Type, init, a, conv(n.Left, Types[TINT64]))
+
+		goto ret
+
+	case OARRAYBYTESTR:
+		a := nodnil()
+		if n.Esc == EscNone {
+			// Create temporary buffer for string on stack.
+			t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
+
+			a = Nod(OADDR, temp(t), nil)
+		}
+
+		// slicebytetostring(*[32]byte, []byte) string;
+		n = mkcall("slicebytetostring", n.Type, init, a, n.Left)
+
+		goto ret
+
+		// slicebytetostringtmp([]byte) string;
+	case OARRAYBYTESTRTMP:
+		n = mkcall("slicebytetostringtmp", n.Type, init, n.Left)
+
+		goto ret
+
+		// slicerunetostring(*[32]byte, []rune) string;
+	case OARRAYRUNESTR:
+		a := nodnil()
+
+		if n.Esc == EscNone {
+			// Create temporary buffer for string on stack.
+			t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
+
+			a = Nod(OADDR, temp(t), nil)
+		}
+
+		n = mkcall("slicerunetostring", n.Type, init, a, n.Left)
+		goto ret
+
+		// stringtoslicebyte(*32[byte], string) []byte;
+	case OSTRARRAYBYTE:
+		a := nodnil()
+
+		if n.Esc == EscNone {
+			// Create temporary buffer for slice on stack.
+			t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
+
+			a = Nod(OADDR, temp(t), nil)
+		}
+
+		n = mkcall("stringtoslicebyte", n.Type, init, a, conv(n.Left, Types[TSTRING]))
+		goto ret
+
+		// stringtoslicebytetmp(string) []byte;
+	case OSTRARRAYBYTETMP:
+		n = mkcall("stringtoslicebytetmp", n.Type, init, conv(n.Left, Types[TSTRING]))
+
+		goto ret
+
+		// stringtoslicerune(*[32]rune, string) []rune
+	case OSTRARRAYRUNE:
+		a := nodnil()
+
+		if n.Esc == EscNone {
+			// Create temporary buffer for slice on stack.
+			t := aindex(Nodintconst(tmpstringbufsize), Types[TINT32])
+
+			a = Nod(OADDR, temp(t), nil)
+		}
+
+		n = mkcall("stringtoslicerune", n.Type, init, a, n.Left)
+		goto ret
+
+		// ifaceeq(i1 any-1, i2 any-2) (ret bool);
+	case OCMPIFACE:
+		if !Eqtype(n.Left.Type, n.Right.Type) {
+			Fatal("ifaceeq %v %v %v", Oconv(int(n.Op), 0), n.Left.Type, n.Right.Type)
+		}
+		var fn *Node
+		if isnilinter(n.Left.Type) {
+			fn = syslook("efaceeq", 1)
+		} else {
+			fn = syslook("ifaceeq", 1)
+		}
+
+		n.Right = cheapexpr(n.Right, init)
+		n.Left = cheapexpr(n.Left, init)
+		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)
+		}
+
+		// check itable/type before full compare.
+		if n.Etype == OEQ {
+			r = Nod(OANDAND, Nod(OEQ, Nod(OITAB, n.Left, nil), Nod(OITAB, n.Right, nil)), r)
+		} else {
+			r = Nod(OOROR, Nod(ONE, Nod(OITAB, n.Left, nil), Nod(OITAB, n.Right, nil)), r)
+		}
+		typecheck(&r, Erv)
+		walkexpr(&r, init)
+		r.Type = n.Type
+		n = r
+		goto ret
+
+	case OARRAYLIT, OMAPLIT, OSTRUCTLIT, OPTRLIT:
+		var_ := temp(n.Type)
+		anylit(0, n, var_, init)
+		n = var_
+		goto ret
+
+	case OSEND:
+		n1 := n.Right
+		n1 = assignconv(n1, n.Left.Type.Type, "chan send")
+		walkexpr(&n1, init)
+		n1 = Nod(OADDR, n1, nil)
+		n = mkcall1(chanfn("chansend1", 2, n.Left.Type), nil, init, typename(n.Left.Type), n.Left, n1)
+		goto ret
+
+	case OCLOSURE:
+		n = walkclosure(n, init)
+		goto ret
+
+	case OCALLPART:
+		n = walkpartialcall(n, init)
+		goto ret
+	}
+
+	Fatal("missing switch %v", Oconv(int(n.Op), 0))
+
+	// Expressions that are constant at run time but not
+	// considered const by the language spec are not turned into
+	// constants until walk. For example, if n is y%1 == 0, the
+	// walk of y%1 may have replaced it by 0.
+	// Check whether n with its updated args is itself now a constant.
+ret:
+	t := n.Type
+
+	evconst(n)
+	n.Type = t
+	if n.Op == OLITERAL {
+		typecheck(&n, Erv)
+	}
+
+	ullmancalc(n)
+
+	if Debug['w'] != 0 && n != nil {
+		Dump("walk", n)
+	}
+
+	lineno = lno
+	*np = n
+}
+
+func reduceSlice(n *Node) *Node {
+	r := n.Right.Right
+	if r != nil && r.Op == OLEN && samesafeexpr(n.Left, r.Left) {
+		// Reduce x[i:len(x)] to x[i:].
+		n.Right.Right = nil
+	}
+	if (n.Op == OSLICE || n.Op == OSLICESTR) && n.Right.Left == nil && n.Right.Right == nil {
+		// Reduce x[:] to x.
+		if Debug_slice > 0 {
+			Warn("slice: omit slice operation")
+		}
+		return n.Left
+	}
+	return n
+}
+
+func ascompatee1(op int, l *Node, r *Node, init **NodeList) *Node {
+	// convas will turn map assigns into function calls,
+	// making it impossible for reorder3 to work.
+	n := Nod(OAS, l, r)
+
+	if l.Op == OINDEXMAP {
+		return n
+	}
+
+	return convas(n, init)
+}
+
+func ascompatee(op int, nl *NodeList, nr *NodeList, init **NodeList) *NodeList {
+	/*
+	 * check assign expression list to
+	 * a expression list. called in
+	 *	expr-list = expr-list
+	 */
+
+	// ensure order of evaluation for function calls
+	for ll := nl; ll != nil; ll = ll.Next {
+		ll.N = safeexpr(ll.N, init)
+	}
+	for lr := nr; lr != nil; lr = lr.Next {
+		lr.N = safeexpr(lr.N, init)
+	}
+
+	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
+		}
+		nn = list(nn, ascompatee1(op, ll.N, lr.N, init))
+	}
+
+	// cannot happen: caller checked that lists had same length
+	if ll != nil || lr != nil {
+		Yyerror("error in shape across %v %v %v / %d %d [%s]", Hconv(nl, obj.FmtSign), Oconv(int(op), 0), Hconv(nr, obj.FmtSign), count(nl), count(nr), Curfn.Func.Nname.Sym.Name)
+	}
+	return nn
+}
+
+/*
+ * l is an lv and rt is the type of an rv
+ * return 1 if this implies a function call
+ * evaluating the lv or a function call
+ * in the conversion of the types
+ */
+func fncall(l *Node, rt *Type) bool {
+	if l.Ullman >= UINF || l.Op == OINDEXMAP {
+		return true
+	}
+	var r Node
+	if needwritebarrier(l, &r) {
+		return true
+	}
+	if Eqtype(l.Type, rt) {
+		return false
+	}
+	return true
+}
+
+func ascompatet(op int, nl *NodeList, nr **Type, fp int, init **NodeList) *NodeList {
+	var l *Node
+	var tmp *Node
+	var a *Node
+	var ll *NodeList
+	var saver Iter
+
+	/*
+	 * check assign type list to
+	 * a expression list. called in
+	 *	expr-list = func()
+	 */
+	r := Structfirst(&saver, nr)
+
+	var nn *NodeList
+	var mm *NodeList
+	ucount := 0
+	for ll = nl; ll != nil; ll = ll.Next {
+		if r == nil {
+			break
+		}
+		l = ll.N
+		if isblank(l) {
+			r = structnext(&saver)
+			continue
+		}
+
+		// any lv that causes a fn call must be
+		// deferred until all the return arguments
+		// have been pulled from the output arguments
+		if fncall(l, r.Type) {
+			tmp = temp(r.Type)
+			typecheck(&tmp, Erv)
+			a = Nod(OAS, l, tmp)
+			a = convas(a, init)
+			mm = list(mm, a)
+			l = tmp
+		}
+
+		a = Nod(OAS, l, nodarg(r, fp))
+		a = convas(a, init)
+		ullmancalc(a)
+		if a.Ullman >= UINF {
+			Dump("ascompatet ucount", a)
+			ucount++
+		}
+
+		nn = list(nn, a)
+		r = structnext(&saver)
+	}
+
+	if ll != nil || r != nil {
+		Yyerror("ascompatet: assignment count mismatch: %d = %d", count(nl), structcount(*nr))
+	}
+
+	if ucount != 0 {
+		Fatal("ascompatet: too many function calls evaluating parameters")
+	}
+	return concat(nn, mm)
+}
+
+/*
+* 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 := uint16(EscUnknown)
+	if ddd != nil {
+		esc = ddd.Esc
+	}
+
+	tslice := typ(TARRAY)
+	tslice.Type = l.Type.Type
+	tslice.Bound = -1
+
+	var n *Node
+	if count(lr0) == 0 {
+		n = nodnil()
+		n.Type = tslice
+	} else {
+		n = Nod(OCOMPLIT, nil, typenod(tslice))
+		if ddd != nil && prealloc[ddd] != nil {
+			prealloc[n] = prealloc[ddd] // temporary to use
+		}
+		n.List = lr0
+		n.Esc = esc
+		typecheck(&n, Erv)
+		if n.Type == nil {
+			Fatal("mkdotargslice: typecheck failed")
+		}
+		walkexpr(&n, init)
+	}
+
+	a := Nod(OAS, nodarg(l, fp), n)
+	nn = list(nn, convas(a, init))
+	return nn
+}
+
+/*
+ * helpers for shape errors
+ */
+func dumptypes(nl **Type, what string) string {
+	var savel Iter
+
+	fmt_ := ""
+	fmt_ += "\t"
+	first := 1
+	for l := Structfirst(&savel, nl); l != nil; l = structnext(&savel) {
+		if first != 0 {
+			first = 0
+		} else {
+			fmt_ += ", "
+		}
+		fmt_ += Tconv(l, 0)
+	}
+
+	if first != 0 {
+		fmt_ += fmt.Sprintf("[no arguments %s]", what)
+	}
+	return fmt_
+}
+
+func dumpnodetypes(l *NodeList, what string) string {
+	var r *Node
+
+	fmt_ := ""
+	fmt_ += "\t"
+	first := 1
+	for ; l != nil; l = l.Next {
+		r = l.N
+		if first != 0 {
+			first = 0
+		} else {
+			fmt_ += ", "
+		}
+		fmt_ += Tconv(r.Type, 0)
+	}
+
+	if first != 0 {
+		fmt_ += fmt.Sprintf("[no arguments %s]", what)
+	}
+	return fmt_
+}
+
+/*
+ * check assign expression list to
+ * a type list. called in
+ *	return expr-list
+ *	func(expr-list)
+ */
+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)
+	var r *Node
+	if lr != nil {
+		r = lr.N
+	}
+	var nn *NodeList
+
+	// f(g()) where g has multiple return values
+	var a *Node
+	var l2 string
+	var ll *Type
+	var l1 string
+	if r != nil && lr.Next == nil && r.Type.Etype == TSTRUCT && r.Type.Funarg != 0 {
+		// optimization - can do block copy
+		if eqtypenoname(r.Type, *nl) {
+			a := nodarg(*nl, fp)
+			r = Nod(OCONVNOP, r, nil)
+			r.Type = a.Type
+			nn = list1(convas(Nod(OAS, a, r), init))
+			goto ret
+		}
+
+		// conversions involved.
+		// copy into temporaries.
+		var alist *NodeList
+
+		for l := Structfirst(&savel, &r.Type); l != nil; l = structnext(&savel) {
+			a = temp(l.Type)
+			alist = list(alist, a)
+		}
+
+		a = Nod(OAS2, nil, nil)
+		a.List = alist
+		a.Rlist = lr
+		typecheck(&a, Etop)
+		walkstmt(&a)
+		*init = list(*init, a)
+		lr = alist
+		r = lr.N
+		l = Structfirst(&savel, nl)
+	}
+
+loop:
+	if l != nil && l.Isddd {
+		// the ddd parameter must be last
+		ll = structnext(&savel)
+
+		if ll != nil {
+			Yyerror("... must be last argument")
+		}
+
+		// special case --
+		// 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 && Eqtype(l.Type, r.Type) {
+			a = Nod(OAS, nodarg(l, fp), r)
+			a = convas(a, init)
+			nn = list(nn, a)
+			goto ret
+		}
+
+		// normal case -- make a slice of all
+		// remaining arguments and pass it to
+		// the ddd parameter.
+		nn = mkdotargslice(lr, nn, l, fp, init, call.Right)
+
+		goto ret
+	}
+
+	if l == nil || r == nil {
+		if l != nil || r != nil {
+			l1 = dumptypes(nl, "expected")
+			l2 = dumpnodetypes(lr0, "given")
+			if l != nil {
+				Yyerror("not enough arguments to %v\n%s\n%s", Oconv(int(op), 0), l1, l2)
+			} else {
+				Yyerror("too many arguments to %v\n%s\n%s", Oconv(int(op), 0), l1, l2)
+			}
+		}
+
+		goto ret
+	}
+
+	a = Nod(OAS, nodarg(l, fp), r)
+	a = convas(a, init)
+	nn = list(nn, a)
+
+	l = structnext(&savel)
+	r = nil
+	lr = lr.Next
+	if lr != nil {
+		r = lr.N
+	}
+	goto loop
+
+ret:
+	for lr = nn; lr != nil; lr = lr.Next {
+		lr.N.Typecheck = 1
+	}
+	return nn
+}
+
+// generate code for print
+func walkprint(nn *Node, init **NodeList) *Node {
+	var r *Node
+	var n *Node
+	var on *Node
+	var t *Type
+	var et int
+
+	op := int(nn.Op)
+	all := nn.List
+	var calls *NodeList
+	notfirst := false
+
+	// Hoist all the argument evaluation up before the lock.
+	walkexprlistcheap(all, init)
+
+	calls = list(calls, mkcall("printlock", nil, init))
+
+	for l := all; l != nil; l = l.Next {
+		if notfirst {
+			calls = list(calls, mkcall("printsp", nil, init))
+		}
+
+		notfirst = op == OPRINTN
+
+		n = l.N
+		if n.Op == OLITERAL {
+			switch n.Val().Ctype() {
+			case CTRUNE:
+				defaultlit(&n, runetype)
+
+			case CTINT:
+				defaultlit(&n, Types[TINT64])
+
+			case CTFLT:
+				defaultlit(&n, Types[TFLOAT64])
+			}
+		}
+
+		if n.Op != OLITERAL && n.Type != nil && n.Type.Etype == TIDEAL {
+			defaultlit(&n, Types[TINT64])
+		}
+		defaultlit(&n, nil)
+		l.N = n
+		if n.Type == nil || n.Type.Etype == TFORW {
+			continue
+		}
+
+		t = n.Type
+		et = int(n.Type.Etype)
+		if Isinter(n.Type) {
+			if isnilinter(n.Type) {
+				on = syslook("printeface", 1)
+			} else {
+				on = syslook("printiface", 1)
+			}
+			substArgTypes(on, n.Type) // any-1
+		} else if Isptr[et] || et == TCHAN || et == TMAP || et == TFUNC || et == TUNSAFEPTR {
+			on = syslook("printpointer", 1)
+			substArgTypes(on, n.Type) // any-1
+		} else if Isslice(n.Type) {
+			on = syslook("printslice", 1)
+			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)
+				} else {
+					on = syslook("printuint", 0)
+				}
+			} else {
+				on = syslook("printint", 0)
+			}
+		} else if Isfloat[et] {
+			on = syslook("printfloat", 0)
+		} else if Iscomplex[et] {
+			on = syslook("printcomplex", 0)
+		} else if et == TBOOL {
+			on = syslook("printbool", 0)
+		} else if et == TSTRING {
+			on = syslook("printstring", 0)
+		} else {
+			badtype(OPRINT, n.Type, nil)
+			continue
+		}
+
+		t = *getinarg(on.Type)
+		if t != nil {
+			t = t.Type
+		}
+		if t != nil {
+			t = t.Type
+		}
+
+		if !Eqtype(t, n.Type) {
+			n = Nod(OCONV, n, nil)
+			n.Type = t
+		}
+
+		r = Nod(OCALL, on, nil)
+		r.List = list1(n)
+		calls = list(calls, r)
+	}
+
+	if op == OPRINTN {
+		calls = list(calls, mkcall("printnl", nil, nil))
+	}
+
+	calls = list(calls, mkcall("printunlock", nil, init))
+
+	typechecklist(calls, Etop)
+	walkexprlist(calls, init)
+
+	r = Nod(OEMPTY, nil, nil)
+	typecheck(&r, Etop)
+	walkexpr(&r, init)
+	r.Ninit = calls
+	return r
+}
+
+func callnew(t *Type) *Node {
+	dowidth(t)
+	fn := syslook("newobject", 1)
+	substArgTypes(fn, t)
+	return mkcall1(fn, Ptrto(t), nil, typename(t))
+}
+
+func iscallret(n *Node) bool {
+	n = outervalue(n)
+	return n.Op == OINDREG && n.Reg == int16(Thearch.REGSP)
+}
+
+func isstack(n *Node) bool {
+	n = outervalue(n)
+
+	// If n is *autotmp and autotmp = &foo, replace n with foo.
+	// We introduce such temps when initializing struct literals.
+	if n.Op == OIND && n.Left.Op == ONAME && strings.HasPrefix(n.Left.Sym.Name, "autotmp_") {
+		defn := n.Left.Name.Defn
+		if defn != nil && defn.Op == OAS && defn.Right.Op == OADDR {
+			n = defn.Right.Left
+		}
+	}
+
+	switch n.Op {
+	case OINDREG:
+		return n.Reg == int16(Thearch.REGSP)
+
+	case ONAME:
+		switch n.Class {
+		case PAUTO, PPARAM, PPARAMOUT:
+			return true
+		}
+	}
+
+	return false
+}
+
+func isglobal(n *Node) bool {
+	n = outervalue(n)
+
+	switch n.Op {
+	case ONAME:
+		switch n.Class {
+		case PEXTERN:
+			return true
+		}
+	}
+
+	return false
+}
+
+// Do we need a write barrier for the assignment l = r?
+func needwritebarrier(l *Node, r *Node) bool {
+	if use_writebarrier == 0 {
+		return false
+	}
+
+	if l == nil || isblank(l) {
+		return false
+	}
+
+	// No write barrier for write of non-pointers.
+	dowidth(l.Type)
+
+	if !haspointers(l.Type) {
+		return false
+	}
+
+	// No write barrier for write to stack.
+	if isstack(l) {
+		return false
+	}
+
+	// No write barrier for implicit zeroing.
+	if r == nil {
+		return false
+	}
+
+	// Ignore no-op conversions when making decision.
+	// Ensures that xp = unsafe.Pointer(&x) is treated
+	// the same as xp = &x.
+	for r.Op == OCONVNOP {
+		r = r.Left
+	}
+
+	// No write barrier for zeroing or initialization to constant.
+	if iszero(r) || r.Op == OLITERAL {
+		return false
+	}
+
+	// No write barrier for storing static (read-only) data.
+	if r.Op == ONAME && strings.HasPrefix(r.Sym.Name, "statictmp_") {
+		return false
+	}
+
+	// No write barrier for storing address of stack values,
+	// which are guaranteed only to be written to the stack.
+	if r.Op == OADDR && isstack(r.Left) {
+		return false
+	}
+
+	// No write barrier for storing address of global, which
+	// is live no matter what.
+	if r.Op == OADDR && isglobal(r.Left) {
+		return false
+	}
+
+	// Otherwise, be conservative and use write barrier.
+	return true
+}
+
+// TODO(rsc): Perhaps componentgen should run before this.
+
+var applywritebarrier_bv Bvec
+
+func applywritebarrier(n *Node, init **NodeList) *Node {
+	if n.Left != nil && n.Right != nil && needwritebarrier(n.Left, n.Right) {
+		if Debug_wb > 1 {
+			Warnl(int(n.Lineno), "marking %v for barrier", Nconv(n.Left, 0))
+		}
+		n.Op = OASWB
+		return n
+	}
+	return n
+}
+
+func convas(n *Node, init **NodeList) *Node {
+	if n.Op != OAS {
+		Fatal("convas: not OAS %v", Oconv(int(n.Op), 0))
+	}
+
+	n.Typecheck = 1
+
+	var lt *Type
+	var rt *Type
+	if n.Left == nil || n.Right == nil {
+		goto out
+	}
+
+	lt = n.Left.Type
+	rt = n.Right.Type
+	if lt == nil || rt == nil {
+		goto out
+	}
+
+	if isblank(n.Left) {
+		defaultlit(&n.Right, nil)
+		goto out
+	}
+
+	if n.Left.Op == OINDEXMAP {
+		map_ := n.Left.Left
+		key := n.Left.Right
+		val := n.Right
+		walkexpr(&map_, init)
+		walkexpr(&key, init)
+		walkexpr(&val, init)
+
+		// orderexpr made sure key and val are addressable.
+		key = Nod(OADDR, key, nil)
+
+		val = Nod(OADDR, val, nil)
+		n = mkcall1(mapfn("mapassign1", map_.Type), nil, init, typename(map_.Type), map_, key, val)
+		goto out
+	}
+
+	if !Eqtype(lt, rt) {
+		n.Right = assignconv(n.Right, lt, "assignment")
+		walkexpr(&n.Right, init)
+	}
+
+out:
+	ullmancalc(n)
+	return n
+}
+
+/*
+ * from ascompat[te]
+ * evaluating actual function arguments.
+ *	f(a,b)
+ * if there is exactly one function expr,
+ * then it is done first. otherwise must
+ * make temp variables
+ */
+func reorder1(all *NodeList) *NodeList {
+	var n *Node
+
+	c := 0 // function calls
+	t := 0 // total parameters
+
+	for l := all; l != nil; l = l.Next {
+		n = l.N
+		t++
+		ullmancalc(n)
+		if n.Ullman >= UINF {
+			c++
+		}
+	}
+
+	if c == 0 || t == 1 {
+		return all
+	}
+
+	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 {
+		n = l.N
+		if n.Ullman < UINF {
+			r = list(r, n)
+			continue
+		}
+
+		d++
+		if d == c {
+			f = n
+			continue
+		}
+
+		// make assignment of fncall to tempname
+		a = temp(n.Right.Type)
+
+		a = Nod(OAS, a, n.Right)
+		g = list(g, a)
+
+		// put normal arg assignment on list
+		// with fncall replaced by tempname
+		n.Right = a.Left
+
+		r = list(r, n)
+	}
+
+	if f != nil {
+		g = list(g, f)
+	}
+	return concat(g, r)
+}
+
+/*
+ * from ascompat[ee]
+ *	a,b = c,d
+ * simultaneous assignment. there cannot
+ * be later use of an earlier lvalue.
+ *
+ * function calls have been removed.
+ */
+func reorder3(all *NodeList) *NodeList {
+	var l *Node
+
+	// If a needed expression may be affected by an
+	// earlier assignment, make an early copy of that
+	// expression and use the copy instead.
+	var early *NodeList
+
+	var mapinit *NodeList
+	for list := all; list != nil; list = list.Next {
+		l = list.N.Left
+
+		// Save subexpressions needed on left side.
+		// Drill through non-dereferences.
+		for {
+			if l.Op == ODOT || l.Op == OPAREN {
+				l = l.Left
+				continue
+			}
+
+			if l.Op == OINDEX && Isfixedarray(l.Left.Type) {
+				reorder3save(&l.Right, all, list, &early)
+				l = l.Left
+				continue
+			}
+
+			break
+		}
+
+		switch l.Op {
+		default:
+			Fatal("reorder3 unexpected lvalue %v", Oconv(int(l.Op), obj.FmtSharp))
+
+		case ONAME:
+			break
+
+		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:
+			reorder3save(&l.Left, all, list, &early)
+		}
+
+		// Save expression on right side.
+		reorder3save(&list.N.Right, all, list, &early)
+	}
+
+	early = concat(mapinit, early)
+	return concat(early, all)
+}
+
+/*
+ * if the evaluation of *np would be affected by the
+ * assignments in all up to but not including stop,
+ * copy into a temporary during *early and
+ * replace *np with that temp.
+ */
+func reorder3save(np **Node, all *NodeList, stop *NodeList, early **NodeList) {
+	n := *np
+	if !aliased(n, all, stop) {
+		return
+	}
+
+	q := temp(n.Type)
+	q = Nod(OAS, q, n)
+	typecheck(&q, Etop)
+	*early = list(*early, q)
+	*np = q.Left
+}
+
+/*
+ * what's the outer value that a write to n affects?
+ * outer value means containing struct or array.
+ */
+func outervalue(n *Node) *Node {
+	for {
+		if n.Op == OXDOT {
+			Fatal("OXDOT in walk")
+		}
+		if n.Op == ODOT || n.Op == OPAREN || n.Op == OCONVNOP {
+			n = n.Left
+			continue
+		}
+
+		if n.Op == OINDEX && Isfixedarray(n.Left.Type) {
+			n = n.Left
+			continue
+		}
+
+		break
+	}
+
+	return n
+}
+
+/*
+ * Is it possible that the computation of n might be
+ * affected by writes in as up to but not including stop?
+ */
+func aliased(n *Node, all *NodeList, stop *NodeList) bool {
+	if n == nil {
+		return false
+	}
+
+	// Look for obvious aliasing: a variable being assigned
+	// during the all list and appearing in n.
+	// Also record whether there are any writes to main memory.
+	// Also record whether there are any writes to variables
+	// whose addresses have been taken.
+	memwrite := 0
+
+	varwrite := 0
+	var a *Node
+	for l := all; l != stop; l = l.Next {
+		a = outervalue(l.N.Left)
+		if a.Op != ONAME {
+			memwrite = 1
+			continue
+		}
+
+		switch n.Class {
+		default:
+			varwrite = 1
+			continue
+
+		case PAUTO, PPARAM, PPARAMOUT:
+			if n.Addrtaken {
+				varwrite = 1
+				continue
+			}
+
+			if vmatch2(a, n) {
+				// Direct hit.
+				return true
+			}
+		}
+	}
+
+	// The variables being written do not appear in n.
+	// However, n might refer to computed addresses
+	// that are being written.
+
+	// If no computed addresses are affected by the writes, no aliasing.
+	if memwrite == 0 && varwrite == 0 {
+		return false
+	}
+
+	// If n does not refer to computed addresses
+	// (that is, if n only refers to variables whose addresses
+	// have not been taken), no aliasing.
+	if varexpr(n) {
+		return false
+	}
+
+	// Otherwise, both the writes and n refer to computed memory addresses.
+	// Assume that they might conflict.
+	return true
+}
+
+/*
+ * does the evaluation of n only refer to variables
+ * whose addresses have not been taken?
+ * (and no other memory)
+ */
+func varexpr(n *Node) bool {
+	if n == nil {
+		return true
+	}
+
+	switch n.Op {
+	case OLITERAL:
+		return true
+
+	case ONAME:
+		switch n.Class {
+		case PAUTO, PPARAM, PPARAMOUT:
+			if !n.Addrtaken {
+				return true
+			}
+		}
+
+		return false
+
+	case OADD,
+		OSUB,
+		OOR,
+		OXOR,
+		OMUL,
+		ODIV,
+		OMOD,
+		OLSH,
+		ORSH,
+		OAND,
+		OANDNOT,
+		OPLUS,
+		OMINUS,
+		OCOM,
+		OPAREN,
+		OANDAND,
+		OOROR,
+		ODOT, // but not ODOTPTR
+		OCONV,
+		OCONVNOP,
+		OCONVIFACE,
+		ODOTTYPE:
+		return varexpr(n.Left) && varexpr(n.Right)
+	}
+
+	// Be conservative.
+	return false
+}
+
+/*
+ * is the name l mentioned in r?
+ */
+func vmatch2(l *Node, r *Node) bool {
+	if r == nil {
+		return false
+	}
+	switch r.Op {
+	// match each right given left
+	case ONAME:
+		return l == r
+
+	case OLITERAL:
+		return false
+	}
+
+	if vmatch2(l, r.Left) {
+		return true
+	}
+	if vmatch2(l, r.Right) {
+		return true
+	}
+	for ll := r.List; ll != nil; ll = ll.Next {
+		if vmatch2(l, ll.N) {
+			return true
+		}
+	}
+	return false
+}
+
+/*
+ * is any name mentioned in l also mentioned in r?
+ * called by sinit.go
+ */
+func vmatch1(l *Node, r *Node) bool {
+	/*
+	 * isolate all left sides
+	 */
+	if l == nil || r == nil {
+		return false
+	}
+	switch l.Op {
+	case ONAME:
+		switch l.Class {
+		case PPARAM, PPARAMREF, PAUTO:
+			break
+
+			// assignment to non-stack variable
+		// must be delayed if right has function calls.
+		default:
+			if r.Ullman >= UINF {
+				return true
+			}
+		}
+
+		return vmatch2(l, r)
+
+	case OLITERAL:
+		return false
+	}
+
+	if vmatch1(l.Left, r) {
+		return true
+	}
+	if vmatch1(l.Right, r) {
+		return true
+	}
+	for ll := l.List; ll != nil; ll = ll.Next {
+		if vmatch1(ll.N, r) {
+			return true
+		}
+	}
+	return false
+}
+
+/*
+ * walk through argin parameters.
+ * generate and return code to allocate
+ * copies of escaped parameters to the heap.
+ */
+func paramstoheap(argin **Type, out int) *NodeList {
+	var savet Iter
+	var v *Node
+	var as *Node
+
+	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
+			v = nil
+		}
+
+		// For precise stacks, the garbage collector assumes results
+		// are always live, so zero them always.
+		if out != 0 {
+			// Defer might stop a panic and show the
+			// return values as they exist at the time of panic.
+			// Make sure to zero them on entry to the function.
+			nn = list(nn, Nod(OAS, nodarg(t, 1), nil))
+		}
+
+		if v == nil || v.Class&PHEAP == 0 {
+			continue
+		}
+
+		// generate allocation & copying code
+		if compiling_runtime != 0 {
+			Yyerror("%v escapes to heap, not allowed in runtime.", v)
+		}
+		if prealloc[v] == nil {
+			prealloc[v] = callnew(v.Type)
+		}
+		nn = list(nn, Nod(OAS, v.Name.Heapaddr, prealloc[v]))
+		if v.Class&^PHEAP != PPARAMOUT {
+			as = Nod(OAS, v, v.Name.Param.Stackparam)
+			v.Name.Param.Stackparam.Typecheck = 1
+			typecheck(&as, Etop)
+			as = applywritebarrier(as, &nn)
+			nn = list(nn, as)
+		}
+	}
+
+	return nn
+}
+
+/*
+ * walk through argout parameters copying back to stack
+ */
+func returnsfromheap(argin **Type) *NodeList {
+	var savet Iter
+	var v *Node
+
+	var nn *NodeList
+	for t := Structfirst(&savet, argin); t != nil; t = structnext(&savet) {
+		v = t.Nname
+		if v == nil || v.Class != PHEAP|PPARAMOUT {
+			continue
+		}
+		nn = list(nn, Nod(OAS, v.Name.Param.Stackparam, v))
+	}
+
+	return nn
+}
+
+/*
+ * take care of migrating any function in/out args
+ * between the stack and the heap.  adds code to
+ * curfn's before and after lists.
+ */
+func heapmoves() {
+	lno := lineno
+	lineno = Curfn.Lineno
+	nn := paramstoheap(getthis(Curfn.Type), 0)
+	nn = concat(nn, paramstoheap(getinarg(Curfn.Type), 0))
+	nn = concat(nn, paramstoheap(Getoutarg(Curfn.Type), 1))
+	Curfn.Func.Enter = concat(Curfn.Func.Enter, nn)
+	lineno = Curfn.Func.Endlineno
+	Curfn.Func.Exit = returnsfromheap(Getoutarg(Curfn.Type))
+	lineno = lno
+}
+
+func vmkcall(fn *Node, t *Type, init **NodeList, va []*Node) *Node {
+	if fn.Type == nil || fn.Type.Etype != TFUNC {
+		Fatal("mkcall %v %v", fn, fn.Type)
+	}
+
+	var args *NodeList
+	n := fn.Type.Intuple
+	for i := 0; i < n; i++ {
+		args = list(args, va[i])
+	}
+
+	r := Nod(OCALL, fn, nil)
+	r.List = args
+	if fn.Type.Outtuple > 0 {
+		typecheck(&r, Erv|Efnstruct)
+	} else {
+		typecheck(&r, Etop)
+	}
+	walkexpr(&r, init)
+	r.Type = t
+	return r
+}
+
+func mkcall(name string, t *Type, init **NodeList, args ...*Node) *Node {
+	return vmkcall(syslook(name, 0), t, init, args)
+}
+
+func mkcall1(fn *Node, t *Type, init **NodeList, args ...*Node) *Node {
+	return vmkcall(fn, t, init, args)
+}
+
+func conv(n *Node, t *Type) *Node {
+	if Eqtype(n.Type, t) {
+		return n
+	}
+	n = Nod(OCONV, n, nil)
+	n.Type = t
+	typecheck(&n, Erv)
+	return n
+}
+
+func chanfn(name string, n int, t *Type) *Node {
+	if t.Etype != TCHAN {
+		Fatal("chanfn %v", t)
+	}
+	fn := syslook(name, 1)
+	switch n {
+	default:
+		Fatal("chanfn %d", n)
+	case 1:
+		substArgTypes(fn, t.Type)
+	case 2:
+		substArgTypes(fn, t.Type, t.Type)
+	}
+	return fn
+}
+
+func mapfn(name string, t *Type) *Node {
+	if t.Etype != TMAP {
+		Fatal("mapfn %v", t)
+	}
+	fn := syslook(name, 1)
+	substArgTypes(fn, t.Down, t.Type, t.Down, t.Type)
+	return fn
+}
+
+func mapfndel(name string, t *Type) *Node {
+	if t.Etype != TMAP {
+		Fatal("mapfn %v", t)
+	}
+	fn := syslook(name, 1)
+	substArgTypes(fn, t.Down, t.Type, t.Down)
+	return fn
+}
+
+func writebarrierfn(name string, l *Type, r *Type) *Node {
+	fn := syslook(name, 1)
+	substArgTypes(fn, l, r)
+	return fn
+}
+
+func addstr(n *Node, init **NodeList) *Node {
+	// orderexpr rewrote OADDSTR to have a list of strings.
+	c := count(n.List)
+
+	if c < 2 {
+		Yyerror("addstr count %d too small", c)
+	}
+
+	buf := nodnil()
+	if n.Esc == EscNone {
+		sz := int64(0)
+		for l := n.List; l != nil; l = l.Next {
+			if n.Op == OLITERAL {
+				sz += int64(len(n.Val().U.(string)))
+			}
+		}
+
+		// Don't allocate the buffer if the result won't fit.
+		if sz < tmpstringbufsize {
+			// Create temporary buffer for result string on stack.
+			t := aindex(Nodintconst(tmpstringbufsize), Types[TUINT8])
+
+			buf = Nod(OADDR, temp(t), nil)
+		}
+	}
+
+	// build list of string arguments
+	args := list1(buf)
+
+	for l := n.List; l != nil; l = l.Next {
+		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.
+		fn = fmt.Sprintf("concatstring%d", c)
+	} else {
+		// large numbers of strings are passed to the runtime as a slice.
+		fn = "concatstrings"
+
+		t := typ(TARRAY)
+		t.Type = Types[TSTRING]
+		t.Bound = -1
+		slice := Nod(OCOMPLIT, nil, typenod(t))
+		if prealloc[n] != nil {
+			prealloc[slice] = prealloc[n]
+		}
+		slice.List = args.Next // skip buf arg
+		args = list1(buf)
+		args = list(args, slice)
+		slice.Esc = EscNone
+	}
+
+	cat := syslook(fn, 1)
+	r := Nod(OCALL, cat, nil)
+	r.List = args
+	typecheck(&r, Erv)
+	walkexpr(&r, init)
+	r.Type = n.Type
+
+	return r
+}
+
+// expand append(l1, l2...) to
+//   init {
+//     s := l1
+//     if n := len(l1) + len(l2) - cap(s); n > 0 {
+//       s = growslice_n(s, n)
+//     }
+//     s = s[:len(l1)+len(l2)]
+//     memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T))
+//   }
+//   s
+//
+// l2 is allowed to be a string.
+func appendslice(n *Node, init **NodeList) *Node {
+	walkexprlistsafe(n.List, init)
+
+	// walkexprlistsafe will leave OINDEX (s[n]) alone if both s
+	// and n are name or literal, but those may index the slice we're
+	// modifying here.  Fix explicitly.
+	for l := n.List; l != nil; l = l.Next {
+		l.N = cheapexpr(l.N, init)
+	}
+
+	l1 := n.List.N
+	l2 := n.List.Next.N
+
+	s := temp(l1.Type) // var s []T
+	var l *NodeList
+	l = list(l, Nod(OAS, s, l1)) // s = l1
+
+	nt := temp(Types[TINT])
+
+	nif := Nod(OIF, nil, nil)
+
+	// n := len(s) + len(l2) - cap(s)
+	nif.Ninit = list1(Nod(OAS, nt, Nod(OSUB, Nod(OADD, Nod(OLEN, s, nil), Nod(OLEN, l2, nil)), Nod(OCAP, s, nil))))
+
+	nif.Left = Nod(OGT, nt, Nodintconst(0))
+
+	// instantiate growslice_n(Type*, []any, int) []any
+	fn := syslook("growslice_n", 1) //   growslice_n(<type>, old []T, n int64) (ret []T)
+	substArgTypes(fn, s.Type.Type, s.Type.Type)
+
+	// s = growslice_n(T, s, n)
+	nif.Nbody = list1(Nod(OAS, s, mkcall1(fn, s.Type, &nif.Ninit, typename(s.Type), s, nt)))
+
+	l = list(l, nif)
+
+	if haspointers(l1.Type.Type) {
+		// copy(s[len(l1):len(l1)+len(l2)], l2)
+		nptr1 := Nod(OSLICE, s, Nod(OKEY, Nod(OLEN, l1, nil), Nod(OADD, Nod(OLEN, l1, nil), Nod(OLEN, l2, nil))))
+
+		nptr1.Etype = 1
+		nptr2 := l2
+		fn := syslook("typedslicecopy", 1)
+		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 {
+		// rely on runtime to instrument copy.
+		// copy(s[len(l1):len(l1)+len(l2)], l2)
+		nptr1 := Nod(OSLICE, s, Nod(OKEY, Nod(OLEN, l1, nil), Nod(OADD, Nod(OLEN, l1, nil), Nod(OLEN, l2, nil))))
+
+		nptr1.Etype = 1
+		nptr2 := l2
+		var fn *Node
+		if l2.Type.Etype == TSTRING {
+			fn = syslook("slicestringcopy", 1)
+		} else {
+			fn = syslook("slicecopy", 1)
+		}
+		substArgTypes(fn, l1.Type, l2.Type)
+		nt := mkcall1(fn, Types[TINT], &l, nptr1, nptr2, Nodintconst(s.Type.Type.Width))
+		l = list(l, nt)
+	} else {
+		// memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T))
+		nptr1 := Nod(OINDEX, s, Nod(OLEN, l1, nil))
+
+		nptr1.Bounded = true
+		nptr1 = Nod(OADDR, nptr1, nil)
+
+		nptr2 := Nod(OSPTR, l2, nil)
+
+		fn := syslook("memmove", 1)
+		substArgTypes(fn, s.Type.Type, s.Type.Type)
+
+		nwid := cheapexpr(conv(Nod(OLEN, l2, nil), Types[TUINTPTR]), &l)
+
+		nwid = Nod(OMUL, nwid, Nodintconst(s.Type.Type.Width))
+		nt := mkcall1(fn, nil, &l, nptr1, nptr2, nwid)
+		l = list(l, nt)
+	}
+
+	// s = s[:len(l1)+len(l2)]
+	nt = Nod(OADD, Nod(OLEN, l1, nil), Nod(OLEN, l2, nil))
+
+	nt = Nod(OSLICE, s, Nod(OKEY, nil, nt))
+	nt.Etype = 1
+	l = list(l, Nod(OAS, s, nt))
+
+	typechecklist(l, Etop)
+	walkstmtlist(l)
+	*init = concat(*init, l)
+	return s
+}
+
+// Rewrite append(src, x, y, z) so that any side effects in
+// x, y, z (including runtime panics) are evaluated in
+// initialization statements before the append.
+// For normal code generation, stop there and leave the
+// rest to cgen_append.
+//
+// For race detector, expand append(src, a [, b]* ) to
+//
+//   init {
+//     s := src
+//     const argc = len(args) - 1
+//     if cap(s) - len(s) < argc {
+//	    s = growslice(s, len(s)+argc)
+//     }
+//     n := len(s)
+//     s = s[:n+argc]
+//     s[n] = a
+//     s[n+1] = b
+//     ...
+//   }
+//   s
+func walkappend(n *Node, init **NodeList, dst *Node) *Node {
+	if !samesafeexpr(dst, n.List.N) {
+		l := n.List
+		l.N = safeexpr(l.N, init)
+		walkexpr(&l.N, init)
+	}
+	walkexprlistsafe(n.List.Next, init)
+
+	// walkexprlistsafe will leave OINDEX (s[n]) alone if both s
+	// and n are name or literal, but those may index the slice we're
+	// modifying here.  Fix explicitly.
+	// Using cheapexpr also makes sure that the evaluation
+	// of all arguments (and especially any panics) happen
+	// before we begin to modify the slice in a visible way.
+	for l := n.List.Next; l != nil; l = l.Next {
+		l.N = cheapexpr(l.N, init)
+	}
+
+	nsrc := n.List.N
+
+	// Resolve slice type of multi-valued return.
+	if Istype(nsrc.Type, TSTRUCT) {
+		nsrc.Type = nsrc.Type.Type.Type
+	}
+	argc := count(n.List) - 1
+	if argc < 1 {
+		return nsrc
+	}
+
+	// General case, with no function calls left as arguments.
+	// Leave for gen, except that race detector requires old form
+	if flag_race == 0 {
+		return n
+	}
+
+	var l *NodeList
+
+	ns := temp(nsrc.Type)
+	l = list(l, Nod(OAS, ns, nsrc)) // s = src
+
+	na := Nodintconst(int64(argc)) // const argc
+	nx := Nod(OIF, nil, nil)       // if cap(s) - len(s) < argc
+	nx.Left = Nod(OLT, Nod(OSUB, Nod(OCAP, ns, nil), Nod(OLEN, ns, nil)), na)
+
+	fn := syslook("growslice", 1) //   growslice(<type>, old []T, mincap 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, Nod(OADD, Nod(OLEN, ns, nil), na))))
+
+	l = list(l, nx)
+
+	nn := temp(Types[TINT])
+	l = list(l, Nod(OAS, nn, Nod(OLEN, ns, nil))) // n = len(s)
+
+	nx = Nod(OSLICE, ns, Nod(OKEY, nil, Nod(OADD, nn, na))) // ...s[:n+argc]
+	nx.Etype = 1
+	l = list(l, Nod(OAS, ns, nx)) // s = s[:n+argc]
+
+	for a := n.List.Next; a != nil; a = a.Next {
+		nx = Nod(OINDEX, ns, nn) // s[n] ...
+		nx.Bounded = true
+		l = list(l, Nod(OAS, nx, a.N)) // s[n] = arg
+		if a.Next != nil {
+			l = list(l, Nod(OAS, nn, Nod(OADD, nn, Nodintconst(1)))) // n = n + 1
+		}
+	}
+
+	typechecklist(l, Etop)
+	walkstmtlist(l)
+	*init = concat(*init, l)
+	return ns
+}
+
+// Lower copy(a, b) to a memmove call or a runtime call.
+//
+// init {
+//   n := len(a)
+//   if n > len(b) { n = len(b) }
+//   memmove(a.ptr, b.ptr, n*sizeof(elem(a)))
+// }
+// n;
+//
+// Also works if b is a string.
+//
+func copyany(n *Node, init **NodeList, runtimecall int) *Node {
+	if haspointers(n.Left.Type.Type) {
+		fn := writebarrierfn("typedslicecopy", n.Left.Type, n.Right.Type)
+		return mkcall1(fn, n.Type, init, typename(n.Left.Type.Type), n.Left, n.Right)
+	}
+
+	if runtimecall != 0 {
+		var fn *Node
+		if n.Right.Type.Etype == TSTRING {
+			fn = syslook("slicestringcopy", 1)
+		} else {
+			fn = syslook("slicecopy", 1)
+		}
+		substArgTypes(fn, n.Left.Type, n.Right.Type)
+		return mkcall1(fn, n.Type, init, n.Left, n.Right, Nodintconst(n.Left.Type.Type.Width))
+	}
+
+	walkexpr(&n.Left, init)
+	walkexpr(&n.Right, init)
+	nl := temp(n.Left.Type)
+	nr := temp(n.Right.Type)
+	var l *NodeList
+	l = list(l, Nod(OAS, nl, n.Left))
+	l = list(l, Nod(OAS, nr, n.Right))
+
+	nfrm := Nod(OSPTR, nr, nil)
+	nto := Nod(OSPTR, nl, nil)
+
+	nlen := temp(Types[TINT])
+
+	// n = len(to)
+	l = list(l, Nod(OAS, nlen, Nod(OLEN, nl, nil)))
+
+	// if n > len(frm) { n = len(frm) }
+	nif := Nod(OIF, nil, nil)
+
+	nif.Left = Nod(OGT, nlen, Nod(OLEN, nr, nil))
+	nif.Nbody = list(nif.Nbody, Nod(OAS, nlen, Nod(OLEN, nr, nil)))
+	l = list(l, nif)
+
+	// Call memmove.
+	fn := syslook("memmove", 1)
+
+	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))
+	l = list(l, mkcall1(fn, nil, init, nto, nfrm, nwid))
+
+	typechecklist(l, Etop)
+	walkstmtlist(l)
+	*init = concat(*init, l)
+	return nlen
+}
+
+func eqfor(t *Type, needsize *int) *Node {
+	// Should only arrive here with large memory or
+	// a struct/array containing a non-memory field/element.
+	// Small memory is handled inline, and single non-memory
+	// is handled during type check (OCMPSTR etc).
+	a := algtype1(t, nil)
+
+	if a != AMEM && a != -1 {
+		Fatal("eqfor %v", t)
+	}
+
+	if a == AMEM {
+		n := syslook("memequal", 1)
+		substArgTypes(n, t, t)
+		*needsize = 1
+		return n
+	}
+
+	sym := typesymprefix(".eq", t)
+	n := newname(sym)
+	n.Class = PFUNC
+	ntype := Nod(OTFUNC, nil, nil)
+	ntype.List = list(ntype.List, Nod(ODCLFIELD, nil, typenod(Ptrto(t))))
+	ntype.List = list(ntype.List, Nod(ODCLFIELD, nil, typenod(Ptrto(t))))
+	ntype.Rlist = list(ntype.Rlist, Nod(ODCLFIELD, nil, typenod(Types[TBOOL])))
+	typecheck(&ntype, Etype)
+	n.Type = ntype.Type
+	*needsize = 0
+	return n
+}
+
+func countfield(t *Type) int {
+	n := 0
+	for t1 := t.Type; t1 != nil; t1 = t1.Down {
+		n++
+	}
+	return n
+}
+
+func walkcompare(np **Node, init **NodeList) {
+	n := *np
+
+	// Given interface value l and concrete value r, rewrite
+	//   l == r
+	// to
+	//   x, ok := l.(type(r)); ok && x == r
+	// Handle != similarly.
+	// This avoids the allocation that would be required
+	// to convert r to l for comparison.
+	var l *Node
+
+	var r *Node
+	if Isinter(n.Left.Type) && !Isinter(n.Right.Type) {
+		l = n.Left
+		r = n.Right
+	} else if !Isinter(n.Left.Type) && Isinter(n.Right.Type) {
+		l = n.Right
+		r = n.Left
+	}
+
+	if l != nil {
+		x := temp(r.Type)
+		if haspointers(r.Type) {
+			a := Nod(OAS, x, nil)
+			typecheck(&a, Etop)
+			*init = list(*init, a)
+		}
+		ok := temp(Types[TBOOL])
+
+		// l.(type(r))
+		a := Nod(ODOTTYPE, l, nil)
+
+		a.Type = r.Type
+
+		// x, ok := l.(type(r))
+		expr := Nod(OAS2, nil, nil)
+
+		expr.List = list1(x)
+		expr.List = list(expr.List, ok)
+		expr.Rlist = list1(a)
+		typecheck(&expr, Etop)
+		walkexpr(&expr, init)
+
+		if n.Op == OEQ {
+			r = Nod(OANDAND, ok, Nod(OEQ, x, r))
+		} else {
+			r = Nod(OOROR, Nod(ONOT, ok, nil), Nod(ONE, x, r))
+		}
+		*init = list(*init, expr)
+		finishcompare(np, n, r, init)
+		return
+	}
+
+	// Must be comparison of array or struct.
+	// Otherwise back end handles it.
+	t := n.Left.Type
+
+	switch t.Etype {
+	default:
+		return
+
+	case TARRAY:
+		if Isslice(t) {
+			return
+		}
+
+	case TSTRUCT:
+		break
+	}
+
+	cmpl := n.Left
+	for cmpl != nil && cmpl.Op == OCONVNOP {
+		cmpl = cmpl.Left
+	}
+	cmpr := n.Right
+	for cmpr != nil && cmpr.Op == OCONVNOP {
+		cmpr = cmpr.Left
+	}
+
+	if !islvalue(cmpl) || !islvalue(cmpr) {
+		Fatal("arguments of comparison must be lvalues - %v %v", cmpl, cmpr)
+	}
+
+	l = temp(Ptrto(t))
+	a := Nod(OAS, l, Nod(OADDR, cmpl, nil))
+	a.Right.Etype = 1 // addr does not escape
+	typecheck(&a, Etop)
+	*init = list(*init, a)
+
+	r = temp(Ptrto(t))
+	a = Nod(OAS, r, Nod(OADDR, cmpr, nil))
+	a.Right.Etype = 1 // addr does not escape
+	typecheck(&a, Etop)
+	*init = list(*init, a)
+
+	andor := OANDAND
+	if n.Op == ONE {
+		andor = OOROR
+	}
+
+	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
+		var ri *Node
+		for i := 0; int64(i) < t.Bound; i++ {
+			li = Nod(OINDEX, l, Nodintconst(int64(i)))
+			ri = Nod(OINDEX, r, Nodintconst(int64(i)))
+			a = Nod(int(n.Op), li, ri)
+			if expr == nil {
+				expr = a
+			} else {
+				expr = Nod(andor, expr, a)
+			}
+		}
+
+		if expr == nil {
+			expr = Nodbool(n.Op == OEQ)
+		}
+		finishcompare(np, n, expr, init)
+		return
+	}
+
+	if t.Etype == TSTRUCT && countfield(t) <= 4 {
+		// Struct of four or fewer fields.
+		// Inline comparisons.
+		var li *Node
+		var ri *Node
+		for t1 := t.Type; t1 != nil; t1 = t1.Down {
+			if isblanksym(t1.Sym) {
+				continue
+			}
+			li = Nod(OXDOT, l, newname(t1.Sym))
+			ri = Nod(OXDOT, r, newname(t1.Sym))
+			a = Nod(int(n.Op), li, ri)
+			if expr == nil {
+				expr = a
+			} else {
+				expr = Nod(andor, expr, a)
+			}
+		}
+
+		if expr == nil {
+			expr = Nodbool(n.Op == OEQ)
+		}
+		finishcompare(np, n, expr, init)
+		return
+	}
+
+	// Chose not to inline.  Call equality function directly.
+	var needsize int
+	call := Nod(OCALL, eqfor(t, &needsize), nil)
+
+	call.List = list(call.List, l)
+	call.List = list(call.List, r)
+	if needsize != 0 {
+		call.List = list(call.List, Nodintconst(t.Width))
+	}
+	r = call
+	if n.Op != OEQ {
+		r = Nod(ONOT, r, nil)
+	}
+
+	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
+	}
+}
+
+func samecheap(a *Node, b *Node) bool {
+	var ar *Node
+	var br *Node
+	for a != nil && b != nil && a.Op == b.Op {
+		switch a.Op {
+		default:
+			return false
+
+		case ONAME:
+			return a == b
+
+		case ODOT, ODOTPTR:
+			ar = a.Right
+			br = b.Right
+			if ar.Op != ONAME || br.Op != ONAME || ar.Sym != br.Sym {
+				return false
+			}
+
+		case OINDEX:
+			ar = a.Right
+			br = b.Right
+			if !Isconst(ar, CTINT) || !Isconst(br, CTINT) || Mpcmpfixfix(ar.Val().U.(*Mpint), br.Val().U.(*Mpint)) != 0 {
+				return false
+			}
+		}
+
+		a = a.Left
+		b = b.Left
+	}
+
+	return false
+}
+
+func walkrotate(np **Node) {
+	if Thearch.Thechar == '7' || Thearch.Thechar == '9' {
+		return
+	}
+
+	n := *np
+
+	// Want << | >> or >> | << or << ^ >> or >> ^ << on unsigned value.
+	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] || l.Op == r.Op {
+		return
+	}
+
+	// Want same, side effect-free expression on lhs of both shifts.
+	if !samecheap(l.Left, r.Left) {
+		return
+	}
+
+	// Constants adding to width?
+	w := int(l.Type.Width * 8)
+
+	if Smallintconst(l.Right) && Smallintconst(r.Right) {
+		sl := int(Mpgetfix(l.Right.Val().U.(*Mpint)))
+		if sl >= 0 {
+			sr := int(Mpgetfix(r.Right.Val().U.(*Mpint)))
+			if sr >= 0 && sl+sr == w {
+				// 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.(*Mpint)))
+
+				if s == 0 || s == w {
+					n = n.Left
+				}
+
+				*np = n
+				return
+			}
+		}
+		return
+	}
+
+	// TODO: Could allow s and 32-s if s is bounded (maybe s&31 and 32-s&31).
+	return
+}
+
+/*
+ * walkmul rewrites integer multiplication by powers of two as shifts.
+ */
+func walkmul(np **Node, init **NodeList) {
+	n := *np
+	if !Isint[n.Type.Etype] {
+		return
+	}
+
+	var nr *Node
+	var nl *Node
+	if n.Right.Op == OLITERAL {
+		nl = n.Left
+		nr = n.Right
+	} else if n.Left.Op == OLITERAL {
+		nl = n.Right
+		nr = n.Left
+	} else {
+		return
+	}
+
+	neg := 0
+
+	// x*0 is 0 (and side effects of x).
+	var pow int
+	var w int
+	if Mpgetfix(nr.Val().U.(*Mpint)) == 0 {
+		cheapexpr(nl, init)
+		Nodconst(n, n.Type, 0)
+		goto ret
+	}
+
+	// nr is a constant.
+	pow = powtwo(nr)
+
+	if pow < 0 {
+		return
+	}
+	if pow >= 1000 {
+		// negative power of 2, like -16
+		neg = 1
+
+		pow -= 1000
+	}
+
+	w = int(nl.Type.Width * 8)
+	if pow+1 >= w { // too big, shouldn't happen
+		return
+	}
+
+	nl = cheapexpr(nl, init)
+
+	if pow == 0 {
+		// x*1 is x
+		n = nl
+
+		goto ret
+	}
+
+	n = Nod(OLSH, nl, Nodintconst(int64(pow)))
+
+ret:
+	if neg != 0 {
+		n = Nod(OMINUS, n, nil)
+	}
+
+	typecheck(&n, Erv)
+	walkexpr(&n, init)
+	*np = n
+}
+
+/*
+ * walkdiv rewrites division by a constant as less expensive
+ * operations.
+ */
+func walkdiv(np **Node, init **NodeList) {
+	// if >= 0, nr is 1<<pow // 1 if nr is negative.
+
+	// TODO(minux)
+	if Thearch.Thechar == '7' || Thearch.Thechar == '9' {
+		return
+	}
+
+	n := *np
+	if n.Right.Op != OLITERAL {
+		return
+	}
+
+	// nr is a constant.
+	nl := cheapexpr(n.Left, init)
+
+	nr := n.Right
+
+	// special cases of mod/div
+	// by a constant
+	w := int(nl.Type.Width * 8)
+
+	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
+
+		pow -= 1000
+	}
+
+	if pow+1 >= w {
+		// divisor too large.
+		return
+	}
+
+	if pow < 0 {
+		// 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.(*Mpint))
+			Smagic(&m)
+		} else {
+			m.Ud = uint64(Mpgetfix(nr.Val().U.(*Mpint)))
+			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(OHMUL, nl, nc)
+			typecheck(&n1, Erv)
+			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(OHMUL, nl, nc)
+			typecheck(&n1, Erv)
+			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 {
+	case 0:
+		if n.Op == OMOD {
+			// nl % 1 is zero.
+			Nodconst(n, n.Type, 0)
+		} else if s != 0 {
+			// divide by -1
+			n.Op = OMINUS
+
+			n.Right = nil
+		} else {
+			// divide by 1
+			n = nl
+		}
+
+	default:
+		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,
+				// nl & (2^pow-1) is (nl+1)%2^pow - 1.
+				nc := Nod(OXXX, nil, nil)
+
+				Nodconst(nc, Types[Simtype[TUINT]], int64(w)-1)
+				n1 := Nod(ORSH, nl, nc) // n1 = -1 iff nl < 0.
+				if pow == 1 {
+					typecheck(&n1, Erv)
+					n1 = cheapexpr(n1, init)
+
+					// n = (nl+ε)&1 -ε where ε=1 iff nl<0.
+					n2 := Nod(OSUB, nl, n1)
+
+					nc := Nod(OXXX, nil, nil)
+					Nodconst(nc, nl.Type, 1)
+					n3 := Nod(OAND, n2, nc)
+					n = Nod(OADD, n3, n1)
+				} else {
+					// n = (nl+ε)&(nr-1) - ε where ε=2^pow-1 iff nl<0.
+					nc := Nod(OXXX, nil, nil)
+
+					Nodconst(nc, nl.Type, (1<<uint(pow))-1)
+					n2 := Nod(OAND, n1, nc) // n2 = 2^pow-1 iff nl<0.
+					typecheck(&n2, Erv)
+					n2 = cheapexpr(n2, init)
+
+					n3 := Nod(OADD, nl, n2)
+					n4 := Nod(OAND, n3, nc)
+					n = Nod(OSUB, n4, n2)
+				}
+
+				break
+			} else {
+				// arithmetic right shift does not give the correct rounding.
+				// if nl >= 0, nl >> n == nl / nr
+				// if nl < 0, we want to add 2^n-1 first.
+				nc := Nod(OXXX, nil, nil)
+
+				Nodconst(nc, Types[Simtype[TUINT]], int64(w)-1)
+				n1 := Nod(ORSH, nl, nc) // n1 = -1 iff nl < 0.
+				if pow == 1 {
+					// nl+1 is nl-(-1)
+					n.Left = Nod(OSUB, nl, n1)
+				} else {
+					// Do a logical right right on -1 to keep pow bits.
+					nc := Nod(OXXX, nil, nil)
+
+					Nodconst(nc, Types[Simtype[TUINT]], int64(w)-int64(pow))
+					n2 := Nod(ORSH, conv(n1, tounsigned(nl.Type)), nc)
+					n.Left = Nod(OADD, nl, conv(n2, nl.Type))
+				}
+
+				// n = (nl + 2^pow-1) >> pow
+				n.Op = ORSH
+
+				nc = Nod(OXXX, nil, nil)
+				Nodconst(nc, Types[Simtype[TUINT]], int64(pow))
+				n.Right = nc
+				n.Typecheck = 0
+			}
+
+			if s != 0 {
+				n = Nod(OMINUS, n, nil)
+			}
+			break
+		}
+
+		nc := Nod(OXXX, nil, nil)
+		if n.Op == OMOD {
+			// n = nl & (nr-1)
+			n.Op = OAND
+
+			Nodconst(nc, nl.Type, Mpgetfix(nr.Val().U.(*Mpint))-1)
+		} else {
+			// n = nl >> pow
+			n.Op = ORSH
+
+			Nodconst(nc, Types[Simtype[TUINT]], int64(pow))
+		}
+
+		n.Typecheck = 0
+		n.Right = nc
+	}
+
+	goto ret
+
+ret:
+	typecheck(&n, Erv)
+	walkexpr(&n, init)
+	*np = n
+}
+
+// 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] {
+		return false
+	}
+
+	sign := Issigned[n.Type.Etype]
+	bits := int32(8 * n.Type.Width)
+
+	if Smallintconst(n) {
+		v := Mpgetfix(n.Val().U.(*Mpint))
+		return 0 <= v && v < max
+	}
+
+	switch n.Op {
+	case OAND:
+		v := int64(-1)
+		if Smallintconst(n.Left) {
+			v = Mpgetfix(n.Left.Val().U.(*Mpint))
+		} else if Smallintconst(n.Right) {
+			v = Mpgetfix(n.Right.Val().U.(*Mpint))
+		}
+
+		if 0 <= v && v < max {
+			return true
+		}
+
+	case OMOD:
+		if !sign && Smallintconst(n.Right) {
+			v := Mpgetfix(n.Right.Val().U.(*Mpint))
+			if 0 <= v && v <= max {
+				return true
+			}
+		}
+
+	case ODIV:
+		if !sign && Smallintconst(n.Right) {
+			v := Mpgetfix(n.Right.Val().U.(*Mpint))
+			for bits > 0 && v >= 2 {
+				bits--
+				v >>= 1
+			}
+		}
+
+	case ORSH:
+		if !sign && Smallintconst(n.Right) {
+			v := Mpgetfix(n.Right.Val().U.(*Mpint))
+			if v > int64(bits) {
+				return true
+			}
+			bits -= int32(v)
+		}
+	}
+
+	if !sign && bits <= 62 && 1<<uint(bits) <= max {
+		return true
+	}
+
+	return false
+}
+
+func usefield(n *Node) {
+	if obj.Fieldtrack_enabled == 0 {
+		return
+	}
+
+	switch n.Op {
+	default:
+		Fatal("usefield %v", Oconv(int(n.Op), 0))
+
+	case ODOT, ODOTPTR:
+		break
+	}
+
+	t := n.Left.Type
+	if Isptr[t.Etype] {
+		t = t.Type
+	}
+	field := dotField[typeSym{t.Orig, n.Right.Sym}]
+	if field == nil {
+		Fatal("usefield %v %v without paramfld", n.Left.Type, n.Right.Sym)
+	}
+	if field.Note == nil || !strings.Contains(*field.Note, "go:\"track\"") {
+		return
+	}
+
+	// dedup on list
+	if field.Lastfn == Curfn {
+		return
+	}
+	field.Lastfn = Curfn
+	field.Outer = n.Left.Type
+	if Isptr[field.Outer.Etype] {
+		field.Outer = field.Outer.Type
+	}
+	if field.Outer.Sym == nil {
+		Yyerror("tracked field must be in named struct type")
+	}
+	if !exportname(field.Sym.Name) {
+		Yyerror("tracked field must be exported (upper case)")
+	}
+
+	Curfn.Func.Fieldtrack = append(Curfn.Func.Fieldtrack, field)
+}
+
+func candiscardlist(l *NodeList) bool {
+	for ; l != nil; l = l.Next {
+		if !candiscard(l.N) {
+			return false
+		}
+	}
+	return true
+}
+
+func candiscard(n *Node) bool {
+	if n == nil {
+		return true
+	}
+
+	switch n.Op {
+	default:
+		return false
+
+		// Discardable as long as the subpieces are.
+	case ONAME,
+		ONONAME,
+		OTYPE,
+		OPACK,
+		OLITERAL,
+		OADD,
+		OSUB,
+		OOR,
+		OXOR,
+		OADDSTR,
+		OADDR,
+		OANDAND,
+		OARRAYBYTESTR,
+		OARRAYRUNESTR,
+		OSTRARRAYBYTE,
+		OSTRARRAYRUNE,
+		OCAP,
+		OCMPIFACE,
+		OCMPSTR,
+		OCOMPLIT,
+		OMAPLIT,
+		OSTRUCTLIT,
+		OARRAYLIT,
+		OPTRLIT,
+		OCONV,
+		OCONVIFACE,
+		OCONVNOP,
+		ODOT,
+		OEQ,
+		ONE,
+		OLT,
+		OLE,
+		OGT,
+		OGE,
+		OKEY,
+		OLEN,
+		OMUL,
+		OLSH,
+		ORSH,
+		OAND,
+		OANDNOT,
+		ONEW,
+		ONOT,
+		OCOM,
+		OPLUS,
+		OMINUS,
+		OOROR,
+		OPAREN,
+		ORUNESTR,
+		OREAL,
+		OIMAG,
+		OCOMPLEX:
+		break
+
+		// Discardable as long as we know it's not division by zero.
+	case ODIV, OMOD:
+		if Isconst(n.Right, CTINT) && mpcmpfixc(n.Right.Val().U.(*Mpint), 0) != 0 {
+			break
+		}
+		if Isconst(n.Right, CTFLT) && mpcmpfltc(n.Right.Val().U.(*Mpflt), 0) != 0 {
+			break
+		}
+		return false
+
+		// Discardable as long as we know it won't fail because of a bad size.
+	case OMAKECHAN, OMAKEMAP:
+		if Isconst(n.Left, CTINT) && mpcmpfixc(n.Left.Val().U.(*Mpint), 0) == 0 {
+			break
+		}
+		return false
+
+		// Difficult to tell what sizes are okay.
+	case OMAKESLICE:
+		return false
+	}
+
+	if !candiscard(n.Left) || !candiscard(n.Right) || !candiscardlist(n.Ninit) || !candiscardlist(n.Nbody) || !candiscardlist(n.List) || !candiscardlist(n.Rlist) {
+		return false
+	}
+
+	return true
+}
+
+// rewrite
+//	print(x, y, z)
+// into
+//	func(a1, a2, a3) {
+//		print(a1, a2, a3)
+//	}(x, y, z)
+// and same for println.
+
+var walkprintfunc_prgen int
+
+func walkprintfunc(np **Node, init **NodeList) {
+	n := *np
+
+	if n.Ninit != nil {
+		walkstmtlist(n.Ninit)
+		*init = concat(*init, n.Ninit)
+		n.Ninit = nil
+	}
+
+	t := Nod(OTFUNC, nil, nil)
+	num := 0
+	var printargs *NodeList
+	var a *Node
+	var buf string
+	for l := n.List; l != nil; l = l.Next {
+		buf = fmt.Sprintf("a%d", num)
+		num++
+		a = Nod(ODCLFIELD, newname(Lookup(buf)), typenod(l.N.Type))
+		t.List = list(t.List, a)
+		printargs = list(printargs, a.Left)
+	}
+
+	fn := Nod(ODCLFUNC, nil, nil)
+	walkprintfunc_prgen++
+	buf = fmt.Sprintf("print·%d", walkprintfunc_prgen)
+	fn.Func.Nname = newname(Lookup(buf))
+	fn.Func.Nname.Name.Defn = fn
+	fn.Func.Nname.Name.Param.Ntype = t
+	declare(fn.Func.Nname, PFUNC)
+
+	oldfn := Curfn
+	Curfn = nil
+	funchdr(fn)
+
+	a = Nod(int(n.Op), nil, nil)
+	a.List = printargs
+	typecheck(&a, Etop)
+	walkstmt(&a)
+
+	fn.Nbody = list1(a)
+
+	funcbody(fn)
+
+	typecheck(&fn, Etop)
+	typechecklist(fn.Nbody, Etop)
+	xtop = list(xtop, fn)
+	Curfn = oldfn
+
+	a = Nod(OCALL, nil, nil)
+	a.Left = fn.Func.Nname
+	a.List = n.List
+	typecheck(&a, Etop)
+	walkexpr(&a, init)
+	*np = a
+}
diff --git a/src/cmd/compile/internal/gc/y.go b/src/cmd/compile/internal/gc/y.go
new file mode 100644
index 0000000..2b61c07
--- /dev/null
+++ b/src/cmd/compile/internal/gc/y.go
@@ -0,0 +1,3526 @@
+//line go.y:21
+package gc
+
+import __yyfmt__ "fmt"
+
+//line go.y:21
+import (
+	"fmt"
+	"strings"
+)
+
+//line go.y:28
+type yySymType struct {
+	yys  int
+	node *Node
+	list *NodeList
+	typ  *Type
+	sym  *Sym
+	val  Val
+	i    int
+}
+
+const LLITERAL = 57346
+const LASOP = 57347
+const LCOLAS = 57348
+const LBREAK = 57349
+const LCASE = 57350
+const LCHAN = 57351
+const LCONST = 57352
+const LCONTINUE = 57353
+const LDDD = 57354
+const LDEFAULT = 57355
+const LDEFER = 57356
+const LELSE = 57357
+const LFALL = 57358
+const LFOR = 57359
+const LFUNC = 57360
+const LGO = 57361
+const LGOTO = 57362
+const LIF = 57363
+const LIMPORT = 57364
+const LINTERFACE = 57365
+const LMAP = 57366
+const LNAME = 57367
+const LPACKAGE = 57368
+const LRANGE = 57369
+const LRETURN = 57370
+const LSELECT = 57371
+const LSTRUCT = 57372
+const LSWITCH = 57373
+const LTYPE = 57374
+const LVAR = 57375
+const LANDAND = 57376
+const LANDNOT = 57377
+const LBODY = 57378
+const LCOMM = 57379
+const LDEC = 57380
+const LEQ = 57381
+const LGE = 57382
+const LGT = 57383
+const LIGNORE = 57384
+const LINC = 57385
+const LLE = 57386
+const LLSH = 57387
+const LLT = 57388
+const LNE = 57389
+const LOROR = 57390
+const LRSH = 57391
+const NotPackage = 57392
+const NotParen = 57393
+const PreferToRightParen = 57394
+
+var yyToknames = [...]string{
+	"$end",
+	"error",
+	"$unk",
+	"LLITERAL",
+	"LASOP",
+	"LCOLAS",
+	"LBREAK",
+	"LCASE",
+	"LCHAN",
+	"LCONST",
+	"LCONTINUE",
+	"LDDD",
+	"LDEFAULT",
+	"LDEFER",
+	"LELSE",
+	"LFALL",
+	"LFOR",
+	"LFUNC",
+	"LGO",
+	"LGOTO",
+	"LIF",
+	"LIMPORT",
+	"LINTERFACE",
+	"LMAP",
+	"LNAME",
+	"LPACKAGE",
+	"LRANGE",
+	"LRETURN",
+	"LSELECT",
+	"LSTRUCT",
+	"LSWITCH",
+	"LTYPE",
+	"LVAR",
+	"LANDAND",
+	"LANDNOT",
+	"LBODY",
+	"LCOMM",
+	"LDEC",
+	"LEQ",
+	"LGE",
+	"LGT",
+	"LIGNORE",
+	"LINC",
+	"LLE",
+	"LLSH",
+	"LLT",
+	"LNE",
+	"LOROR",
+	"LRSH",
+	"'+'",
+	"'-'",
+	"'|'",
+	"'^'",
+	"'*'",
+	"'/'",
+	"'%'",
+	"'&'",
+	"NotPackage",
+	"NotParen",
+	"'('",
+	"')'",
+	"PreferToRightParen",
+	"';'",
+	"'.'",
+	"'$'",
+	"'='",
+	"':'",
+	"'{'",
+	"'}'",
+	"'!'",
+	"'~'",
+	"'['",
+	"']'",
+	"'?'",
+	"'@'",
+	"','",
+}
+var yyStatenames = [...]string{}
+
+const yyEofCode = 1
+const yyErrCode = 2
+const yyMaxDepth = 200
+
+//line go.y:2308
+func fixlbrace(lbr int) {
+	// If the opening brace was an LBODY,
+	// set up for another one now that we're done.
+	// See comment in lex.C about loophack.
+	if lbr == LBODY {
+		loophack = 1
+	}
+}
+
+//line yacctab:1
+var yyExca = [...]int{
+	-1, 1,
+	1, -1,
+	-2, 0,
+	-1, 17,
+	1, 1,
+	63, 23,
+	-2, 0,
+	-1, 48,
+	6, 276,
+	66, 276,
+	76, 276,
+	-2, 49,
+	-1, 56,
+	67, 153,
+	-2, 162,
+	-1, 74,
+	60, 181,
+	-2, 215,
+	-1, 75,
+	60, 182,
+	-2, 183,
+	-1, 121,
+	60, 134,
+	64, 134,
+	68, 134,
+	72, 134,
+	-2, 266,
+	-1, 125,
+	60, 134,
+	64, 134,
+	68, 134,
+	72, 134,
+	-2, 267,
+	-1, 176,
+	2, 215,
+	36, 215,
+	60, 181,
+	68, 215,
+	-2, 173,
+	-1, 177,
+	36, 183,
+	60, 182,
+	68, 183,
+	-2, 174,
+	-1, 184,
+	63, 251,
+	69, 251,
+	-2, 0,
+	-1, 242,
+	63, 251,
+	69, 251,
+	-2, 0,
+	-1, 252,
+	8, 251,
+	13, 251,
+	63, 251,
+	69, 251,
+	-2, 0,
+	-1, 325,
+	4, 236,
+	63, 236,
+	69, 236,
+	-2, 157,
+	-1, 403,
+	67, 144,
+	-2, 142,
+	-1, 408,
+	36, 176,
+	60, 176,
+	68, 176,
+	-2, 167,
+	-1, 409,
+	36, 177,
+	60, 177,
+	68, 177,
+	-2, 168,
+	-1, 410,
+	36, 178,
+	60, 178,
+	68, 178,
+	-2, 169,
+	-1, 411,
+	36, 179,
+	60, 179,
+	68, 179,
+	-2, 170,
+	-1, 417,
+	8, 251,
+	13, 251,
+	63, 251,
+	69, 251,
+	-2, 0,
+	-1, 418,
+	63, 251,
+	69, 251,
+	-2, 0,
+	-1, 498,
+	63, 251,
+	69, 251,
+	-2, 0,
+	-1, 553,
+	60, 157,
+	-2, 318,
+	-1, 554,
+	60, 158,
+	-2, 317,
+	-1, 579,
+	8, 251,
+	13, 251,
+	63, 251,
+	69, 251,
+	-2, 0,
+	-1, 593,
+	36, 180,
+	60, 180,
+	68, 180,
+	-2, 171,
+	-1, 632,
+	67, 145,
+	-2, 143,
+}
+
+const yyNprod = 352
+const yyPrivate = 57344
+
+var yyTokenNames []string
+var yyStates []string
+
+const yyLast = 2321
+
+var yyAct = [...]int{
+
+	74, 304, 381, 291, 487, 611, 459, 285, 546, 229,
+	398, 467, 34, 296, 75, 302, 402, 550, 290, 186,
+	286, 479, 458, 356, 400, 401, 389, 338, 103, 318,
+	328, 245, 303, 339, 324, 243, 337, 468, 101, 374,
+	109, 104, 248, 85, 14, 246, 241, 174, 480, 212,
+	6, 181, 325, 155, 470, 469, 325, 385, 332, 517,
+	108, 627, 414, 373, 13, 208, 585, 11, 176, 461,
+	470, 172, 584, 461, 652, 600, 230, 219, 392, 191,
+	106, 322, 177, 542, 226, 322, 423, 321, 193, 88,
+	10, 321, 13, 192, 10, 310, 317, 309, 154, 160,
+	447, 12, 13, 161, 227, 12, 13, 446, 198, 227,
+	10, 162, 227, 320, 209, 227, 462, 384, 228, 663,
+	462, 626, 625, 228, 55, 460, 228, 155, 184, 228,
+	203, 628, 205, 633, 199, 200, 108, 632, 204, 12,
+	13, 222, 393, 12, 13, 86, 214, 216, 218, 90,
+	604, 239, 175, 10, 449, 194, 233, 88, 153, 12,
+	13, 176, 661, 213, 213, 213, 213, 288, 155, 282,
+	282, 601, 282, 537, 417, 177, 445, 280, 10, 176,
+	621, 528, 295, 163, 164, 165, 166, 167, 168, 169,
+	170, 227, 417, 177, 417, 301, 227, 227, 594, 227,
+	485, 88, 12, 13, 185, 228, 417, 524, 48, 308,
+	228, 228, 416, 228, 202, 347, 516, 90, 472, 448,
+	405, 428, 10, 242, 349, 171, 298, 12, 13, 345,
+	343, 341, 227, 581, 507, 330, 344, 507, 182, 508,
+	519, 397, 508, 348, 116, 175, 228, 367, 227, 334,
+	464, 227, 227, 360, 227, 129, 325, 355, 371, 210,
+	346, 90, 228, 175, 353, 228, 228, 362, 228, 182,
+	183, 12, 13, 54, 435, 314, 173, 10, 342, 358,
+	340, 13, 340, 340, 91, 379, 188, 378, 325, 380,
+	376, 331, 365, 375, 176, 623, 369, 394, 505, 417,
+	408, 183, 610, 163, 170, 12, 13, 605, 177, 410,
+	227, 227, 415, 238, 409, 118, 118, 602, 575, 126,
+	227, 569, 559, 331, 228, 228, 12, 13, 466, 465,
+	391, 444, 327, 443, 228, 437, 425, 12, 13, 254,
+	413, 388, 255, 256, 257, 258, 259, 260, 261, 262,
+	263, 264, 265, 266, 267, 268, 269, 270, 271, 272,
+	273, 274, 129, 129, 277, 227, 440, 383, 370, 173,
+	366, 294, 359, 491, 227, 424, 411, 442, 175, 228,
+	10, 455, 493, 333, 454, 436, 100, 492, 228, 300,
+	99, 84, 10, 509, 176, 481, 282, 512, 474, 20,
+	657, 282, 656, 655, 499, 495, 614, 227, 177, 503,
+	654, 484, 10, 227, 340, 340, 234, 515, 520, 521,
+	646, 228, 620, 617, 227, 340, 608, 228, 221, 12,
+	13, 607, 511, 129, 526, 430, 433, 69, 228, 518,
+	227, 12, 13, 598, 597, 129, 596, 293, 96, 494,
+	525, 593, 583, 563, 228, 529, 98, 490, 540, 532,
+	94, 12, 13, 523, 514, 513, 510, 560, 538, 558,
+	97, 95, 330, 323, 329, 539, 497, 496, 175, 483,
+	555, 477, 227, 476, 10, 473, 441, 562, 432, 421,
+	227, 372, 297, 386, 565, 615, 228, 491, 491, 606,
+	571, 573, 173, 92, 228, 403, 493, 493, 176, 10,
+	403, 492, 492, 340, 574, 340, 197, 554, 10, 114,
+	457, 340, 177, 434, 340, 572, 580, 439, 10, 578,
+	354, 591, 592, 12, 13, 253, 588, 568, 251, 180,
+	340, 197, 586, 587, 110, 533, 197, 609, 535, 197,
+	432, 348, 197, 107, 117, 382, 70, 502, 12, 13,
+	287, 7, 5, 102, 432, 211, 24, 12, 13, 129,
+	16, 19, 227, 494, 494, 651, 129, 12, 13, 431,
+	456, 490, 490, 364, 429, 561, 228, 335, 282, 207,
+	206, 618, 175, 129, 129, 624, 622, 120, 481, 491,
+	121, 125, 173, 636, 631, 630, 188, 619, 493, 21,
+	340, 638, 305, 492, 642, 340, 643, 306, 641, 336,
+	57, 351, 352, 640, 93, 644, 252, 645, 197, 176,
+	26, 340, 512, 197, 197, 28, 197, 76, 158, 387,
+	157, 666, 653, 177, 582, 390, 159, 491, 530, 156,
+	498, 658, 579, 662, 418, 534, 493, 31, 22, 15,
+	664, 492, 23, 665, 122, 122, 201, 18, 340, 197,
+	668, 3, 123, 554, 667, 494, 340, 8, 9, 282,
+	4, 2, 1, 490, 451, 197, 215, 544, 197, 197,
+	56, 197, 89, 566, 545, 548, 549, 612, 488, 323,
+	249, 531, 189, 105, 105, 112, 115, 80, 81, 576,
+	577, 329, 438, 175, 119, 119, 173, 72, 119, 71,
+	237, 478, 340, 494, 149, 340, 403, 316, 589, 403,
+	403, 490, 220, 326, 150, 244, 649, 197, 151, 141,
+	142, 143, 144, 145, 146, 147, 148, 197, 197, 629,
+	650, 127, 17, 450, 595, 399, 319, 197, 25, 89,
+	27, 36, 37, 78, 471, 281, 49, 66, 111, 39,
+	38, 35, 124, 279, 278, 105, 149, 83, 79, 10,
+	105, 73, 217, 112, 82, 113, 150, 247, 504, 616,
+	151, 232, 506, 87, 188, 145, 146, 147, 148, 0,
+	0, 0, 197, 0, 223, 0, 0, 0, 196, 235,
+	197, 197, 240, 128, 231, 0, 0, 0, 634, 635,
+	236, 0, 0, 0, 0, 639, 77, 0, 12, 13,
+	225, 0, 0, 0, 292, 647, 648, 173, 0, 0,
+	403, 0, 0, 0, 197, 0, 0, 0, 0, 0,
+	197, 0, 541, 0, 543, 0, 552, 56, 0, 0,
+	556, 197, 0, 557, 0, 0, 0, 347, 0, 0,
+	0, 0, 119, 119, 0, 0, 349, 197, 0, 567,
+	0, 345, 343, 341, 0, 0, 0, 0, 344, 0,
+	0, 311, 357, 0, 0, 348, 312, 313, 105, 315,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 346, 0, 0, 56, 0, 0, 613, 197,
+	275, 276, 0, 283, 247, 56, 247, 197, 0, 0,
+	342, 0, 363, 13, 197, 197, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 599,
+	0, 377, 134, 149, 603, 152, 0, 135, 139, 140,
+	0, 0, 138, 150, 137, 136, 133, 151, 141, 142,
+	143, 144, 145, 146, 147, 148, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 422, 0, 0,
+	0, 361, 0, 0, 414, 0, 0, 0, 0, 0,
+	407, 0, 0, 368, 0, 0, 89, 637, 0, 197,
+	419, 420, 552, 0, 0, 0, 0, 0, 0, 347,
+	426, 0, 0, 463, 0, 0, 0, 357, 349, 0,
+	0, 0, 105, 345, 343, 341, 197, 0, 0, 105,
+	344, 0, 0, 112, 0, 486, 247, 348, 0, 0,
+	0, 0, 0, 0, 0, 0, 134, 149, 0, 152,
+	0, 135, 139, 140, 346, 407, 138, 150, 137, 136,
+	133, 151, 141, 142, 143, 144, 145, 146, 147, 148,
+	0, 0, 342, 0, 197, 13, 0, 0, 0, 0,
+	56, 56, 0, 0, 0, 396, 0, 0, 119, 0,
+	119, 0, 0, 0, 0, 0, 0, 311, 536, 0,
+	119, 0, 247, 522, 0, 0, 0, 0, 0, 0,
+	0, 547, 551, 0, 527, 0, 0, 475, 0, 0,
+	357, 0, 0, 463, 482, 0, 0, 463, 0, 0,
+	0, 0, 564, 357, 0, 0, 0, 0, 0, 0,
+	0, 275, 276, 0, 0, 0, 0, 0, 307, 0,
+	68, 0, 247, 41, 0, 78, 47, 42, 0, 0,
+	44, 56, 40, 50, 124, 43, 45, 53, 0, 83,
+	79, 10, 570, 0, 46, 52, 82, 51, 32, 30,
+	0, 0, 0, 65, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 60, 61, 0, 64,
+	58, 0, 0, 59, 0, 0, 67, 0, 0, 0,
+	0, 0, 0, 0, 308, 0, 62, 63, 77, 0,
+	12, 13, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 29, 105, 68, 247, 0, 41, 0, 78, 47,
+	42, 0, 56, 44, 0, 40, 50, 33, 43, 45,
+	53, 0, 83, 79, 10, 0, 0, 46, 52, 82,
+	51, 32, 30, 0, 0, 547, 65, 0, 551, 357,
+	0, 0, 463, 0, 0, 0, 357, 0, 357, 60,
+	61, 0, 64, 58, 0, 0, 59, 0, 68, 67,
+	0, 0, 0, 78, 0, 0, 0, 0, 0, 62,
+	63, 77, 124, 12, 13, 0, 0, 83, 79, 10,
+	68, 0, 0, 0, 82, 78, 0, 0, 0, 0,
+	0, 65, 0, 0, 124, 0, 0, 0, 0, 83,
+	79, 10, 0, 0, 60, 61, 82, 64, 58, 0,
+	0, 59, 0, 68, 67, 0, 0, 0, 78, 0,
+	0, 0, 404, 0, 62, 63, 77, 124, 12, 13,
+	0, 0, 83, 79, 10, 0, 67, 0, 0, 82,
+	0, 0, 0, 0, 0, 0, 65, 0, 77, 0,
+	12, 13, 0, 0, 0, 0, 0, 0, 0, 60,
+	61, 0, 64, 58, 0, 0, 59, 0, 68, 67,
+	0, 0, 0, 78, 0, 0, 0, 590, 0, 62,
+	63, 77, 124, 12, 13, 0, 0, 83, 79, 10,
+	0, 501, 0, 0, 82, 0, 0, 0, 0, 0,
+	0, 65, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 60, 61, 0, 64, 58, 0,
+	0, 59, 0, 68, 67, 0, 0, 0, 78, 0,
+	0, 0, 0, 0, 62, 63, 77, 124, 12, 13,
+	0, 0, 83, 79, 10, 0, 500, 0, 0, 82,
+	0, 0, 0, 0, 0, 0, 65, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 60,
+	61, 0, 64, 58, 0, 0, 59, 0, 68, 67,
+	0, 0, 0, 78, 0, 0, 0, 78, 0, 62,
+	63, 77, 124, 12, 13, 0, 124, 83, 79, 10,
+	0, 83, 79, 10, 82, 0, 395, 0, 82, 0,
+	0, 179, 0, 0, 0, 232, 0, 0, 0, 0,
+	0, 68, 0, 0, 60, 61, 78, 64, 178, 0,
+	0, 59, 196, 0, 67, 124, 0, 0, 489, 0,
+	83, 79, 10, 0, 62, 63, 77, 82, 12, 13,
+	77, 0, 12, 13, 179, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 60, 61, 0,
+	64, 178, 0, 0, 59, 0, 68, 67, 289, 0,
+	0, 78, 0, 0, 0, 0, 0, 62, 63, 77,
+	124, 12, 13, 0, 0, 83, 79, 10, 0, 284,
+	0, 0, 82, 0, 0, 0, 0, 0, 0, 65,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 68,
+	0, 0, 60, 61, 78, 64, 58, 187, 0, 59,
+	0, 0, 67, 124, 0, 0, 0, 0, 83, 79,
+	10, 0, 62, 63, 77, 82, 12, 13, 0, 0,
+	0, 0, 65, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 68, 0, 0, 60, 61, 78, 64, 58,
+	0, 0, 59, 0, 0, 67, 124, 0, 0, 0,
+	0, 83, 79, 10, 0, 62, 63, 77, 82, 12,
+	13, 0, 0, 0, 0, 65, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 68, 0, 0, 60, 61,
+	78, 64, 58, 0, 0, 59, 0, 0, 67, 124,
+	0, 0, 0, 0, 83, 79, 10, 0, 62, 63,
+	77, 82, 12, 13, 0, 0, 0, 0, 179, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 68, 0,
+	0, 60, 61, 299, 64, 178, 0, 0, 59, 0,
+	0, 67, 124, 0, 0, 0, 0, 83, 79, 10,
+	0, 62, 63, 77, 82, 12, 13, 0, 0, 0,
+	0, 65, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 60, 61, 78, 64, 58, 0,
+	0, 59, 0, 0, 67, 124, 0, 0, 0, 0,
+	83, 79, 10, 0, 62, 63, 77, 82, 12, 13,
+	0, 78, 0, 0, 232, 0, 0, 0, 0, 0,
+	124, 0, 0, 0, 0, 83, 79, 10, 0, 0,
+	0, 196, 82, 0, 0, 0, 0, 231, 0, 232,
+	0, 0, 0, 224, 0, 0, 0, 0, 0, 77,
+	0, 12, 13, 225, 0, 0, 196, 0, 0, 0,
+	0, 0, 231, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 77, 0, 12, 13, 427, 134,
+	149, 0, 152, 0, 135, 139, 140, 0, 0, 138,
+	150, 137, 136, 133, 151, 141, 142, 143, 144, 145,
+	146, 147, 148, 134, 149, 0, 152, 0, 135, 139,
+	140, 0, 660, 138, 150, 137, 136, 133, 151, 141,
+	142, 143, 144, 145, 146, 147, 148, 0, 78, 0,
+	0, 250, 78, 0, 0, 0, 659, 124, 0, 0,
+	0, 124, 83, 79, 10, 0, 83, 79, 10, 82,
+	0, 0, 0, 82, 299, 0, 232, 0, 0, 0,
+	232, 0, 0, 124, 0, 0, 0, 0, 83, 79,
+	10, 0, 0, 196, 0, 82, 0, 196, 0, 231,
+	0, 0, 232, 231, 0, 0, 0, 78, 0, 0,
+	0, 77, 0, 12, 13, 77, 124, 12, 13, 196,
+	0, 83, 79, 10, 0, 231, 0, 0, 82, 78,
+	0, 0, 0, 347, 0, 406, 0, 77, 124, 12,
+	13, 0, 349, 83, 79, 10, 0, 345, 343, 553,
+	82, 0, 196, 0, 344, 0, 0, 190, 412, 0,
+	0, 348, 0, 0, 0, 0, 0, 0, 0, 0,
+	77, 0, 12, 13, 196, 0, 0, 0, 346, 0,
+	195, 0, 0, 0, 0, 0, 0, 0, 347, 0,
+	0, 0, 77, 0, 12, 13, 342, 349, 12, 13,
+	0, 0, 345, 343, 341, 0, 0, 0, 347, 344,
+	0, 0, 0, 0, 0, 0, 453, 349, 0, 0,
+	0, 0, 345, 343, 341, 0, 0, 0, 0, 344,
+	0, 0, 0, 346, 0, 0, 348, 0, 0, 452,
+	0, 0, 0, 130, 0, 0, 0, 0, 0, 0,
+	0, 342, 0, 346, 13, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 350, 0, 0, 0, 0,
+	0, 342, 134, 149, 13, 152, 132, 135, 139, 140,
+	0, 131, 138, 150, 137, 136, 133, 151, 141, 142,
+	143, 144, 145, 146, 147, 148, 134, 149, 0, 152,
+	0, 135, 139, 140, 0, 0, 138, 150, 137, 136,
+	133, 151, 141, 142, 143, 144, 145, 146, 147, 148,
+	134, 149, 0, 0, 0, 135, 139, 140, 0, 0,
+	138, 150, 137, 136, 133, 151, 141, 142, 143, 144,
+	145, 146, 147, 148, 134, 149, 0, 0, 0, 135,
+	139, 140, 0, 0, 138, 150, 137, 136, 0, 151,
+	141, 142, 143, 144, 145, 146, 147, 148, 149, 0,
+	0, 0, 135, 139, 140, 0, 0, 138, 150, 137,
+	136, 0, 151, 141, 142, 143, 144, 145, 146, 147,
+	148,
+}
+var yyPact = [...]int{
+
+	-1000, -1000, 536, 535, -1000, 128, -1000, 545, 549, 336,
+	-1000, -1000, -1000, 605, -1000, -1000, 541, 1239, 328, 85,
+	-1000, 220, 438, 327, -1000, 323, -1000, -1000, -1000, -1000,
+	503, 493, 484, 459, -1000, -1000, -1000, -1000, -1000, 177,
+	-1000, 128, 128, 1316, 1316, 128, 1698, -1000, 2168, 92,
+	-1000, -1000, -1000, -1000, -1000, -1000, -1000, 39, 1698, 1698,
+	1698, 1698, 1698, 1698, 1698, 1698, 157, 1741, -1000, -1000,
+	-1000, 479, 233, -1000, -1000, -1000, 202, 1655, 2050, 36,
+	-1000, -1000, 233, 233, -1000, -1000, 153, 535, -1000, 586,
+	585, 40, 194, -1000, 540, -11, -11, -11, 17, -1000,
+	-1000, -1000, 367, 1827, -1000, -1000, -1000, 355, 754, -1000,
+	252, 1973, -1000, 155, 1969, 478, -1000, -1000, -1000, -1000,
+	-1000, -1000, 39, -1000, 475, -1000, -1000, -1000, -23, 2192,
+	1698, -1000, -1000, 1698, 1698, 1698, 1698, 1698, 1698, 1698,
+	1698, 1698, 1698, 1698, 1698, 1698, 1698, 1698, 1698, 1698,
+	1698, 1698, 1698, 1698, 1698, 1698, 1612, 1698, 524, 1698,
+	1557, 387, 1698, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
+	-1000, -1000, 431, 2192, -1000, -1000, -1000, -1000, 1741, 1784,
+	1698, -1000, -1000, -1000, 1156, -1000, 24, 22, 2192, -1000,
+	1973, -1000, -1000, -1000, -1000, 1973, 1973, 211, 1973, 27,
+	263, 320, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
+	-1000, 583, 1010, -1000, 2129, 1010, -1000, 155, 470, 128,
+	309, -1000, -1000, 187, 1698, 128, -1000, -1000, -1000, -1000,
+	-1000, 1973, 574, 307, -1000, 181, 1698, 305, -1000, -1000,
+	-1000, -1000, 1156, 430, -13, -1000, -1000, 1969, -1000, -1000,
+	1973, 1969, 1156, 1969, 2192, 2240, 2263, 689, 689, 689,
+	689, 689, 689, 741, 741, 741, 741, -1000, -1000, -1000,
+	-1000, -1000, -1000, -1000, 2216, -23, -23, 2192, -1000, 519,
+	304, -1000, -1000, 51, 1698, -1000, 278, -1000, -1000, -1000,
+	66, -1000, -1000, 1514, 1022, 174, 1294, 152, -1000, 2028,
+	918, 1294, 143, -1000, -1000, -1000, -1000, -1000, -1000, 1973,
+	1973, -1000, 428, -1000, 128, 13, 273, -1000, -1000, 1852,
+	580, 525, 463, -1000, -1000, 210, 272, -1000, -1000, 467,
+	-1000, 539, 425, 197, -1000, 270, 268, -1000, -1000, -1000,
+	-1000, -1000, 103, 28, 151, 86, 1010, 2109, 571, 460,
+	65, 184, 266, 265, 128, -6, -1000, 206, 424, 128,
+	1698, -23, -1000, 422, 1973, 420, 128, 1698, -23, 418,
+	128, 131, 1518, 1969, -1000, -1000, -1000, -1000, 416, -1000,
+	415, -1000, -1000, 1698, 1459, 1404, 2192, 521, 1698, 229,
+	519, 405, -14, 1741, 404, 403, -1000, 1698, 147, -17,
+	-1000, -1000, 173, 2192, -1000, -1000, 1995, -1000, -1000, -1000,
+	-1000, -1000, 1973, 402, -1000, 138, -1000, 1156, 1156, -1000,
+	-1000, -1000, -1000, 1973, 112, 31, 580, 128, -1000, -1000,
+	398, 539, 210, 580, 539, 128, 104, 231, -1000, 1969,
+	397, -1000, -1000, -1000, -1000, 1010, 10, 1010, 128, 2054,
+	-1000, -1000, 514, 1010, -1000, -1000, 1010, 128, 259, -1000,
+	69, -1000, 581, -1000, 65, -1000, -1000, 392, -22, 128,
+	128, 580, 1010, -1000, -1000, -23, -1000, -1000, 258, -1000,
+	-1000, 754, -23, -1000, -1000, -1000, 440, -1000, -1000, 1969,
+	-1000, -1000, -1000, -1000, -1000, -1000, 1518, 1518, 1156, 255,
+	1698, 1698, -1000, -1000, -1000, -1000, -1000, 1741, 166, -1000,
+	-1000, 391, -1000, -1000, -1000, -1, -1000, 1294, -1000, 1349,
+	1294, 1294, 390, -1000, -1000, -1000, 129, -1000, -1000, -1000,
+	-1000, -1000, 580, 385, -1000, 383, -1000, -1000, -1000, 382,
+	-1000, -1000, 1010, 2, 102, 254, -1000, 1010, 81, 244,
+	-1000, 439, -1000, -1000, -1000, 370, -1000, -1000, 365, -1000,
+	497, -1000, 239, 858, 435, -1000, -1000, 580, 362, 128,
+	181, 1969, 361, -1000, 111, 1698, 2192, 2192, 226, 1156,
+	55, -1000, -1000, -1000, -1000, 1698, -1000, -1000, -1000, 2192,
+	-1000, 68, 64, -1000, -1000, -1000, 580, 580, 1518, -1000,
+	1010, -1000, 128, 580, -1000, 2054, 128, -1000, 858, 69,
+	-1000, -1000, -1000, 128, -1000, 128, -1000, -1000, -1000, 359,
+	-1000, -1000, -1000, -1000, 236, -1000, 1698, 1698, 1741, 560,
+	1, 1294, -1000, -1000, -1000, -1000, -1000, -1000, -1000, -1000,
+	-1000, 349, -1000, 342, 341, 339, 1518, 1919, 1895, -1000,
+	-1000, 141, -1000, 50, 858, -1000, -1000, 858, -1000, -1000,
+	-1000, -1000, -1000, -1000, -1000, -1000, 1698, 519, -1000,
+}
+var yyPgo = [...]int{
+
+	0, 51, 793, 672, 34, 221, 32, 700, 31, 792,
+	788, 1, 76, 113, 208, 16, 25, 3, 785, 782,
+	781, 774, 773, 771, 7, 770, 617, 30, 24, 769,
+	437, 45, 47, 273, 41, 19, 768, 554, 20, 620,
+	767, 556, 765, 762, 12, 761, 124, 760, 40, 13,
+	758, 46, 4, 2, 28, 756, 766, 755, 10, 18,
+	752, 751, 26, 750, 749, 736, 15, 35, 735, 733,
+	38, 732, 29, 727, 612, 48, 21, 721, 720, 719,
+	717, 42, 712, 708, 707, 9, 84, 702, 14, 698,
+	0, 67, 49, 22, 6, 23, 17, 8, 697, 5,
+	37, 11, 696, 695, 694, 687, 406, 36, 686, 33,
+	27, 684, 682, 681, 680, 677, 671, 50, 44, 667,
+	43, 666, 58, 662, 659, 658, 657, 654, 652, 650,
+	649, 646, 645, 644, 641, 640, 639, 638, 39, 637,
+	626, 624,
+}
+var yyR1 = [...]int{
+
+	0, 112, 114, 114, 116, 113, 115, 115, 119, 119,
+	119, 120, 120, 121, 121, 2, 2, 2, 117, 123,
+	123, 124, 118, 50, 50, 50, 50, 50, 74, 74,
+	74, 74, 74, 74, 74, 74, 74, 74, 126, 70,
+	70, 70, 75, 75, 76, 76, 76, 36, 48, 44,
+	44, 44, 44, 44, 44, 9, 9, 9, 9, 127,
+	11, 128, 10, 62, 62, 129, 53, 42, 42, 42,
+	22, 22, 22, 21, 130, 23, 24, 24, 131, 132,
+	133, 25, 134, 63, 64, 64, 65, 65, 135, 136,
+	45, 137, 43, 14, 14, 14, 14, 14, 14, 14,
+	14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+	14, 14, 14, 14, 46, 46, 46, 46, 46, 46,
+	46, 46, 46, 41, 41, 41, 40, 40, 40, 40,
+	40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+	49, 28, 16, 16, 15, 15, 39, 39, 17, 17,
+	31, 1, 1, 33, 34, 37, 37, 3, 3, 3,
+	91, 91, 30, 29, 81, 81, 7, 7, 7, 7,
+	7, 7, 32, 32, 32, 32, 87, 87, 87, 87,
+	87, 79, 79, 80, 89, 89, 89, 89, 89, 12,
+	12, 88, 88, 88, 88, 88, 88, 88, 85, 86,
+	84, 84, 83, 83, 47, 18, 18, 19, 19, 90,
+	51, 51, 52, 52, 52, 139, 20, 20, 60, 60,
+	71, 71, 77, 77, 78, 78, 73, 73, 69, 69,
+	72, 72, 72, 72, 72, 72, 4, 4, 13, 27,
+	27, 27, 82, 8, 8, 8, 8, 68, 68, 67,
+	67, 6, 6, 6, 6, 6, 26, 26, 26, 26,
+	26, 140, 26, 26, 26, 26, 26, 26, 26, 26,
+	66, 66, 55, 55, 54, 54, 56, 56, 59, 59,
+	57, 57, 57, 57, 58, 58, 122, 122, 138, 138,
+	35, 35, 61, 61, 38, 38, 101, 101, 105, 105,
+	103, 103, 5, 5, 141, 141, 141, 141, 141, 141,
+	92, 108, 106, 106, 106, 111, 111, 107, 107, 107,
+	107, 107, 107, 107, 107, 107, 107, 107, 110, 109,
+	95, 95, 97, 96, 96, 99, 99, 98, 98, 94,
+	94, 94, 93, 93, 125, 125, 100, 100, 104, 104,
+	102, 102,
+}
+var yyR2 = [...]int{
+
+	0, 4, 0, 3, 0, 3, 0, 3, 2, 5,
+	3, 3, 2, 1, 3, 1, 2, 2, 4, 0,
+	1, 0, 4, 0, 1, 1, 1, 1, 2, 5,
+	3, 2, 5, 7, 3, 2, 5, 3, 1, 2,
+	4, 3, 4, 3, 1, 2, 1, 1, 2, 1,
+	3, 3, 3, 2, 2, 3, 5, 5, 2, 0,
+	4, 0, 3, 0, 2, 0, 4, 4, 4, 2,
+	5, 1, 1, 2, 0, 3, 1, 3, 0, 0,
+	0, 8, 0, 5, 0, 2, 0, 2, 0, 0,
+	7, 0, 5, 1, 3, 3, 3, 3, 3, 3,
+	3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+	3, 3, 3, 3, 1, 2, 2, 2, 2, 2,
+	2, 2, 2, 3, 5, 6, 1, 1, 3, 5,
+	5, 4, 6, 8, 1, 5, 5, 5, 7, 1,
+	0, 3, 1, 4, 1, 4, 1, 3, 1, 1,
+	1, 1, 1, 1, 1, 0, 1, 1, 1, 1,
+	4, 4, 1, 1, 1, 2, 1, 1, 1, 1,
+	1, 3, 1, 1, 1, 2, 1, 1, 1, 1,
+	3, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+	3, 4, 4, 2, 3, 5, 1, 1, 2, 3,
+	5, 3, 5, 3, 3, 5, 8, 5, 8, 5,
+	0, 3, 0, 1, 3, 1, 4, 2, 0, 3,
+	1, 3, 1, 3, 1, 3, 1, 3, 1, 3,
+	3, 2, 4, 3, 5, 5, 1, 3, 1, 2,
+	1, 3, 4, 1, 2, 2, 1, 1, 3, 0,
+	2, 0, 1, 1, 1, 1, 1, 1, 1, 1,
+	1, 0, 4, 1, 2, 2, 2, 2, 2, 2,
+	1, 3, 1, 3, 1, 3, 1, 3, 1, 3,
+	1, 1, 3, 3, 0, 2, 0, 1, 0, 1,
+	0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
+	0, 1, 0, 1, 4, 4, 5, 6, 4, 4,
+	1, 1, 1, 1, 1, 1, 1, 1, 1, 3,
+	4, 5, 4, 4, 2, 2, 4, 3, 3, 5,
+	3, 4, 3, 5, 1, 0, 1, 3, 1, 1,
+	2, 1, 1, 5, 0, 2, 1, 3, 1, 3,
+	1, 3,
+}
+var yyChk = [...]int{
+
+	-1000, -112, -113, -116, -114, 26, -117, 26, -115, -3,
+	25, -91, 74, 75, -118, -124, 25, -60, -119, 22,
+	63, 4, -125, -123, 25, -50, -74, -47, -26, 2,
+	33, -126, 32, 18, -44, -23, -45, -43, -25, -29,
+	16, 7, 11, 19, 14, 20, 28, 10, -14, -56,
+	17, 31, 29, 21, -33, -46, -3, -39, 54, 57,
+	50, 51, 70, 71, 53, 37, -40, 60, 4, -30,
+	-41, -79, -80, -20, -90, -88, -139, 72, 9, 24,
+	-84, -83, 30, 23, 63, -120, 60, -2, 4, -3,
+	64, 64, 65, -141, 22, 33, 10, 32, 18, 63,
+	63, -70, 60, -54, -34, -3, -75, 60, -54, -48,
+	60, -36, -3, -18, 60, -3, 67, -37, -33, -3,
+	-37, -41, -39, -3, 18, -41, -33, -61, -56, -14,
+	5, 43, 38, 48, 34, 39, 47, 46, 44, 40,
+	41, 50, 51, 52, 53, 54, 55, 56, 57, 35,
+	45, 49, 37, 66, 6, 76, -130, -135, -137, -131,
+	60, 64, 72, -46, -46, -46, -46, -46, -46, -46,
+	-46, 68, -17, -14, -32, -86, -90, -88, 54, 37,
+	60, -1, 36, 68, -1, 2, -35, 12, -14, -87,
+	37, -90, -88, -85, -12, 60, 54, -30, 72, -1,
+	-1, -121, 61, -120, -117, -118, 4, 4, 25, 74,
+	65, 25, -92, -91, -92, -108, -92, -19, -92, 60,
+	-71, 61, -70, -7, 66, 76, -86, -90, -88, -85,
+	-12, 60, 37, -75, 61, -7, 66, -78, 61, -48,
+	-7, -51, 68, -67, -68, -8, -31, -3, -81, -7,
+	12, 60, -140, 60, -14, -14, -14, -14, -14, -14,
+	-14, -14, -14, -14, -14, -14, -14, -14, -14, -14,
+	-14, -14, -14, -14, -14, -56, -56, -14, -21, -22,
+	-38, -42, -44, -56, 27, -24, -38, 36, -24, 61,
+	-59, -17, -3, 60, -14, -35, -49, 61, -32, 9,
+	-14, -49, -66, -6, -11, -74, -26, 2, 68, 73,
+	73, -7, -7, -7, 64, -7, -73, 69, -72, -55,
+	-13, 60, 54, -33, -4, 25, -69, 69, -27, -33,
+	-4, 60, -122, 63, -118, 4, -106, -107, -110, -109,
+	-91, 25, 72, 24, 30, 23, 54, 9, 37, 18,
+	66, -106, -106, -51, 60, -100, -95, -3, -122, 63,
+	66, -56, -34, -7, 9, -122, 63, 66, -56, -122,
+	63, -66, 61, 76, -138, -31, -81, -7, -67, -6,
+	-67, -53, 36, 63, 66, 6, -14, -136, 63, -62,
+	-132, -138, 12, 76, -17, 32, 73, 67, -58, -57,
+	-28, -16, -15, -14, 68, 68, 37, -7, -90, -88,
+	-85, -12, 60, -138, 76, -58, 69, 63, -127, -7,
+	-7, 61, -3, 73, -122, 63, -7, 76, -5, 4,
+	-13, 54, 25, -13, 60, 64, -122, 63, -82, 60,
+	-4, 61, -120, 63, 63, 73, 4, 72, 68, 68,
+	-106, -111, 60, 37, -107, -109, 9, 60, -93, -94,
+	60, 4, 51, -3, 66, 63, 63, -101, -100, 61,
+	76, -106, 12, 61, -70, -56, 61, 61, -77, -76,
+	-75, -54, -56, 61, -48, 69, -3, -52, -89, 60,
+	-86, -90, -88, -85, -12, -8, 61, 61, -129, -38,
+	27, 27, 36, -38, -10, 69, -9, 8, 13, -53,
+	61, -138, -17, 61, 61, -35, 69, 76, -138, 67,
+	-49, -49, -7, 61, 69, -6, -66, -7, 69, -72,
+	-5, -33, 61, -13, -5, -13, -3, 69, -27, -67,
+	61, -106, 73, -106, -105, -104, -97, -3, -103, -102,
+	-96, -3, -106, 25, -91, -110, -106, -106, -101, 63,
+	-94, 4, -93, 61, -3, -95, -5, -106, -122, 63,
+	-7, 60, -67, -52, -66, 63, -14, -14, -62, -128,
+	-59, 67, -133, 61, 73, 67, -28, -16, -15, -14,
+	68, -58, -58, 61, 69, -5, 61, 61, 61, -106,
+	73, 69, 63, -106, 69, 63, 60, 61, 61, 50,
+	63, -99, -98, 60, -106, 60, -5, 61, -76, -67,
+	61, 69, -38, 69, -66, 67, 66, 6, 76, -64,
+	-35, -49, 69, 69, -5, -5, -52, -106, -97, -5,
+	-96, -101, -99, -94, -101, -101, 61, -14, -14, -65,
+	-63, 15, 73, -58, 61, 61, 61, 61, -52, 67,
+	67, 21, -11, 69, -99, -99, -134, -24, -53,
+}
+var yyDef = [...]int{
+
+	4, -2, 2, 0, 6, 0, 21, 0, 218, 0,
+	157, 158, 159, 0, 5, 344, 19, -2, 0, 0,
+	3, 0, 0, 0, 20, 0, 24, 25, 26, 27,
+	0, 0, 0, 0, 256, 257, 258, 259, 260, 0,
+	263, 155, 155, 0, 0, 0, 292, 38, -2, 0,
+	74, 88, 91, 78, 163, 93, -2, 114, 0, 0,
+	0, 0, 0, 0, 0, 0, 146, 0, 126, 127,
+	134, 0, 0, 139, -2, -2, 0, 290, 0, 0,
+	196, 197, 0, 0, 7, 8, 0, 21, 15, 0,
+	0, 0, 0, 345, 0, 0, 0, 0, 0, 18,
+	219, 28, 0, 0, 274, 154, 31, 0, 0, 35,
+	0, 0, 47, 210, 249, 0, 261, 264, 156, 153,
+	265, -2, 0, 162, 0, -2, 268, 269, 293, 276,
+	0, 53, 54, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 294, 294, 0, 294,
+	0, 0, 290, 115, 116, 117, 118, 119, 120, 121,
+	122, 140, 0, 148, 149, 172, -2, -2, 0, 0,
+	0, 140, 151, 152, -2, 217, 0, 0, 291, 193,
+	0, 176, 177, 178, 179, 0, 0, 189, 0, 0,
+	0, 286, 10, 13, 21, 12, 16, 17, 160, 161,
+	22, 0, 0, 310, 0, 0, 311, 210, 0, 0,
+	286, 30, 220, 39, 0, 0, 166, 167, 168, 169,
+	170, 0, 0, 286, 34, 0, 0, 286, 37, 224,
+	48, 204, -2, 0, 288, 247, 243, 162, 246, 150,
+	164, 249, -2, 249, 50, 94, 95, 96, 97, 98,
+	99, 100, 101, 102, 103, 104, 105, 106, 107, 108,
+	109, 110, 111, 112, 113, 51, 52, 277, 75, 0,
+	71, 72, 295, 0, 0, 89, 76, 63, 79, 123,
+	288, 278, 128, 0, 291, 0, 284, 147, 175, 0,
+	288, 284, 0, 270, 252, 253, 254, 255, 59, 0,
+	0, 194, 0, 198, 0, 0, 286, 201, 226, 0,
+	302, 0, 0, 272, 238, -2, 286, 203, 228, 0,
+	240, 0, 0, 287, 11, 0, 0, 312, 313, 314,
+	317, 318, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 296, 0, 346, 0, 0, 287,
+	0, 41, 275, 0, 0, 0, 287, 0, 43, 0,
+	287, 0, 212, 289, 250, 244, 245, 165, 0, 262,
+	0, 73, 65, 294, 0, 0, 69, 0, 294, 0,
+	0, 0, 288, 289, 0, 0, 131, 290, 0, 288,
+	280, 281, 0, -2, 140, 140, 0, 199, -2, -2,
+	-2, -2, 0, 0, 289, 0, 216, -2, -2, 191,
+	192, 180, 190, 0, 0, 287, 302, 0, 231, 303,
+	0, 0, 236, 302, 0, 0, 0, 287, 239, 249,
+	0, 9, 14, 304, 305, 0, 0, 0, 298, 300,
+	324, 325, 0, 0, 315, 316, 0, 296, 0, 342,
+	0, 339, 0, 341, 0, 308, 309, 0, 297, 0,
+	0, 302, 0, 29, 221, 40, 171, 32, 286, 222,
+	44, 46, 42, 36, 225, 211, 162, 209, 213, 249,
+	184, 185, 186, 187, 188, 248, 212, 212, -2, 0,
+	0, 0, 63, 77, 64, 92, 61, 0, 0, 80,
+	124, 0, 279, 129, 130, 0, 137, 289, 285, 0,
+	284, 284, 0, 135, 136, 271, 0, 195, 200, 227,
+	230, 273, 302, 0, 233, 0, 237, 202, 229, 0,
+	241, 319, 0, 0, 0, 299, 348, 0, 0, 301,
+	350, 0, 334, -2, -2, 0, 327, 328, 0, 306,
+	0, 340, 0, 335, 0, 347, 330, 302, 0, 287,
+	45, 249, 0, 205, 0, 294, 67, 68, 0, -2,
+	0, 58, 84, 125, 132, 290, 282, 283, 141, 144,
+	140, 0, 0, -2, 60, 232, 302, 302, 212, 320,
+	0, 322, 0, 302, 323, 0, 296, 326, 335, 0,
+	307, 207, 336, 296, 338, 296, 331, 33, 223, 0,
+	214, 66, 70, 90, 62, 55, 0, 0, 0, 86,
+	0, 284, -2, 138, 234, 235, 242, 321, 349, 332,
+	351, 0, 329, 0, 0, 0, 212, 0, 0, 81,
+	85, 0, 133, 0, 335, 343, 337, 335, 206, 56,
+	57, 82, 87, 145, 333, 208, 294, 0, 83,
+}
+var yyTok1 = [...]int{
+
+	1, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+	3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+	3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+	3, 3, 3, 70, 3, 3, 65, 56, 57, 3,
+	60, 61, 54, 50, 76, 51, 64, 55, 3, 3,
+	3, 3, 3, 3, 3, 3, 3, 3, 67, 63,
+	3, 66, 3, 74, 75, 3, 3, 3, 3, 3,
+	3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+	3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+	3, 72, 3, 73, 53, 3, 3, 3, 3, 3,
+	3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+	3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+	3, 3, 3, 68, 52, 69, 71,
+}
+var yyTok2 = [...]int{
+
+	2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+	12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+	22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+	32, 33, 34, 35, 36, 37, 38, 39, 40, 41,
+	42, 43, 44, 45, 46, 47, 48, 49, 58, 59,
+	62,
+}
+var yyTok3 = [...]int{
+	0,
+}
+
+var yyErrorMessages = [...]struct {
+	state int
+	token int
+	msg   string
+}{
+	{332, 76, "unexpected comma during import block"},
+	{89, 63, "missing import path; require quoted string"},
+	{390, 63, "missing { after if clause"},
+	{387, 63, "missing { after switch clause"},
+	{279, 63, "missing { after for clause"},
+	{499, 36, "missing { after for clause"},
+	{17, 68, "unexpected semicolon or newline before {"},
+	{111, 63, "unexpected semicolon or newline in type declaration"},
+	{78, 69, "unexpected } in channel type"},
+	{78, 61, "unexpected ) in channel type"},
+	{78, 76, "unexpected comma in channel type"},
+	{417, 15, "unexpected semicolon or newline before else"},
+	{329, 76, "name list not allowed in interface type"},
+	{279, 33, "var declaration not allowed in for initializer"},
+	{25, 68, "unexpected { at end of statement"},
+	{371, 68, "unexpected { at end of statement"},
+	{122, 63, "argument to go/defer must be function call"},
+	{398, 63, "need trailing comma before newline in composite literal"},
+	{415, 63, "need trailing comma before newline in composite literal"},
+	{124, 25, "nested func not allowed"},
+	{651, 63, "else must be followed by if or statement block"},
+}
+
+//line yaccpar:1
+
+/*	parser for yacc output	*/
+
+var (
+	yyDebug        = 0
+	yyErrorVerbose = false
+)
+
+type yyLexer interface {
+	Lex(lval *yySymType) int
+	Error(s string)
+}
+
+type yyParser interface {
+	Parse(yyLexer) int
+	Lookahead() int
+}
+
+type yyParserImpl struct {
+	lookahead func() int
+}
+
+func (p *yyParserImpl) Lookahead() int {
+	return p.lookahead()
+}
+
+func yyNewParser() yyParser {
+	p := &yyParserImpl{
+		lookahead: func() int { return -1 },
+	}
+	return p
+}
+
+const yyFlag = -1000
+
+func yyTokname(c int) string {
+	if c >= 1 && c-1 < len(yyToknames) {
+		if yyToknames[c-1] != "" {
+			return yyToknames[c-1]
+		}
+	}
+	return __yyfmt__.Sprintf("tok-%v", c)
+}
+
+func yyStatname(s int) string {
+	if s >= 0 && s < len(yyStatenames) {
+		if yyStatenames[s] != "" {
+			return yyStatenames[s]
+		}
+	}
+	return __yyfmt__.Sprintf("state-%v", s)
+}
+
+func yyErrorMessage(state, lookAhead int) string {
+	const TOKSTART = 4
+
+	if !yyErrorVerbose {
+		return "syntax error"
+	}
+
+	for _, e := range yyErrorMessages {
+		if e.state == state && e.token == lookAhead {
+			return "syntax error: " + e.msg
+		}
+	}
+
+	res := "syntax error: unexpected " + yyTokname(lookAhead)
+
+	// To match Bison, suggest at most four expected tokens.
+	expected := make([]int, 0, 4)
+
+	// Look for shiftable tokens.
+	base := yyPact[state]
+	for tok := TOKSTART; tok-1 < len(yyToknames); tok++ {
+		if n := base + tok; n >= 0 && n < yyLast && yyChk[yyAct[n]] == tok {
+			if len(expected) == cap(expected) {
+				return res
+			}
+			expected = append(expected, tok)
+		}
+	}
+
+	if yyDef[state] == -2 {
+		i := 0
+		for yyExca[i] != -1 || yyExca[i+1] != state {
+			i += 2
+		}
+
+		// Look for tokens that we accept or reduce.
+		for i += 2; yyExca[i] >= 0; i += 2 {
+			tok := yyExca[i]
+			if tok < TOKSTART || yyExca[i+1] == 0 {
+				continue
+			}
+			if len(expected) == cap(expected) {
+				return res
+			}
+			expected = append(expected, tok)
+		}
+
+		// If the default action is to accept or reduce, give up.
+		if yyExca[i+1] != 0 {
+			return res
+		}
+	}
+
+	for i, tok := range expected {
+		if i == 0 {
+			res += ", expecting "
+		} else {
+			res += " or "
+		}
+		res += yyTokname(tok)
+	}
+	return res
+}
+
+func yylex1(lex yyLexer, lval *yySymType) (char, token int) {
+	token = 0
+	char = lex.Lex(lval)
+	if char <= 0 {
+		token = yyTok1[0]
+		goto out
+	}
+	if char < len(yyTok1) {
+		token = yyTok1[char]
+		goto out
+	}
+	if char >= yyPrivate {
+		if char < yyPrivate+len(yyTok2) {
+			token = yyTok2[char-yyPrivate]
+			goto out
+		}
+	}
+	for i := 0; i < len(yyTok3); i += 2 {
+		token = yyTok3[i+0]
+		if token == char {
+			token = yyTok3[i+1]
+			goto out
+		}
+	}
+
+out:
+	if token == 0 {
+		token = yyTok2[1] /* unknown char */
+	}
+	if yyDebug >= 3 {
+		__yyfmt__.Printf("lex %s(%d)\n", yyTokname(token), uint(char))
+	}
+	return char, token
+}
+
+func yyParse(yylex yyLexer) int {
+	return yyNewParser().Parse(yylex)
+}
+
+func (yyrcvr *yyParserImpl) Parse(yylex yyLexer) int {
+	var yyn int
+	var yylval yySymType
+	var yyVAL yySymType
+	var yyDollar []yySymType
+	yyS := make([]yySymType, yyMaxDepth)
+
+	Nerrs := 0   /* number of errors */
+	Errflag := 0 /* error recovery flag */
+	yystate := 0
+	yychar := -1
+	yytoken := -1 // yychar translated into internal numbering
+	yyrcvr.lookahead = func() int { return yychar }
+	defer func() {
+		// Make sure we report no lookahead when not parsing.
+		yystate = -1
+		yychar = -1
+		yytoken = -1
+	}()
+	yyp := -1
+	goto yystack
+
+ret0:
+	return 0
+
+ret1:
+	return 1
+
+yystack:
+	/* put a state and value onto the stack */
+	if yyDebug >= 4 {
+		__yyfmt__.Printf("char %v in %v\n", yyTokname(yytoken), yyStatname(yystate))
+	}
+
+	yyp++
+	if yyp >= len(yyS) {
+		nyys := make([]yySymType, len(yyS)*2)
+		copy(nyys, yyS)
+		yyS = nyys
+	}
+	yyS[yyp] = yyVAL
+	yyS[yyp].yys = yystate
+
+yynewstate:
+	yyn = yyPact[yystate]
+	if yyn <= yyFlag {
+		goto yydefault /* simple state */
+	}
+	if yychar < 0 {
+		yychar, yytoken = yylex1(yylex, &yylval)
+	}
+	yyn += yytoken
+	if yyn < 0 || yyn >= yyLast {
+		goto yydefault
+	}
+	yyn = yyAct[yyn]
+	if yyChk[yyn] == yytoken { /* valid shift */
+		yychar = -1
+		yytoken = -1
+		yyVAL = yylval
+		yystate = yyn
+		if Errflag > 0 {
+			Errflag--
+		}
+		goto yystack
+	}
+
+yydefault:
+	/* default state action */
+	yyn = yyDef[yystate]
+	if yyn == -2 {
+		if yychar < 0 {
+			yychar, yytoken = yylex1(yylex, &yylval)
+		}
+
+		/* look through exception table */
+		xi := 0
+		for {
+			if yyExca[xi+0] == -1 && yyExca[xi+1] == yystate {
+				break
+			}
+			xi += 2
+		}
+		for xi += 2; ; xi += 2 {
+			yyn = yyExca[xi+0]
+			if yyn < 0 || yyn == yytoken {
+				break
+			}
+		}
+		yyn = yyExca[xi+1]
+		if yyn < 0 {
+			goto ret0
+		}
+	}
+	if yyn == 0 {
+		/* error ... attempt to resume parsing */
+		switch Errflag {
+		case 0: /* brand new error */
+			yylex.Error(yyErrorMessage(yystate, yytoken))
+			Nerrs++
+			if yyDebug >= 1 {
+				__yyfmt__.Printf("%s", yyStatname(yystate))
+				__yyfmt__.Printf(" saw %s\n", yyTokname(yytoken))
+			}
+			fallthrough
+
+		case 1, 2: /* incompletely recovered error ... try again */
+			Errflag = 3
+
+			/* find a state where "error" is a legal shift action */
+			for yyp >= 0 {
+				yyn = yyPact[yyS[yyp].yys] + yyErrCode
+				if yyn >= 0 && yyn < yyLast {
+					yystate = yyAct[yyn] /* simulate a shift of "error" */
+					if yyChk[yystate] == yyErrCode {
+						goto yystack
+					}
+				}
+
+				/* the current p has no shift on "error", pop stack */
+				if yyDebug >= 2 {
+					__yyfmt__.Printf("error recovery pops state %d\n", yyS[yyp].yys)
+				}
+				yyp--
+			}
+			/* there is no state on the stack with an error shift ... abort */
+			goto ret1
+
+		case 3: /* no shift yet; clobber input char */
+			if yyDebug >= 2 {
+				__yyfmt__.Printf("error recovery discards %s\n", yyTokname(yytoken))
+			}
+			if yytoken == yyEofCode {
+				goto ret1
+			}
+			yychar = -1
+			yytoken = -1
+			goto yynewstate /* try again in the same state */
+		}
+	}
+
+	/* reduction by production yyn */
+	if yyDebug >= 2 {
+		__yyfmt__.Printf("reduce %v in:\n\t%v\n", yyn, yyStatname(yystate))
+	}
+
+	yynt := yyn
+	yypt := yyp
+	_ = yypt // guard against "declared and not used"
+
+	yyp -= yyR2[yyn]
+	// yyp is now the index of $0. Perform the default action. Iff the
+	// reduced production is ε, $1 is possibly out of range.
+	if yyp+1 >= len(yyS) {
+		nyys := make([]yySymType, len(yyS)*2)
+		copy(nyys, yyS)
+		yyS = nyys
+	}
+	yyVAL = yyS[yyp+1]
+
+	/* consult goto table to find next state */
+	yyn = yyR1[yyn]
+	yyg := yyPgo[yyn]
+	yyj := yyg + yyS[yyp].yys + 1
+
+	if yyj >= yyLast {
+		yystate = yyAct[yyg]
+	} else {
+		yystate = yyAct[yyj]
+		if yyChk[yystate] != -yyn {
+			yystate = yyAct[yyg]
+		}
+	}
+	// dummy call; replaced with literal code
+	switch yynt {
+
+	case 1:
+		yyDollar = yyS[yypt-4 : yypt+1]
+		//line go.y:189
+		{
+			xtop = concat(xtop, yyDollar[4].list)
+		}
+	case 2:
+		yyDollar = yyS[yypt-0 : yypt+1]
+		//line go.y:195
+		{
+			prevlineno = lineno
+			Yyerror("package statement must be first")
+			errorexit()
+		}
+	case 3:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:201
+		{
+			mkpackage(yyDollar[2].sym.Name)
+		}
+	case 4:
+		yyDollar = yyS[yypt-0 : yypt+1]
+		//line go.y:211
+		{
+			importpkg = Runtimepkg
+
+			if Debug['A'] != 0 {
+				cannedimports("runtime.Builtin", "package runtime\n\n$$\n\n")
+			} else {
+				cannedimports("runtime.Builtin", runtimeimport)
+			}
+			curio.importsafe = true
+		}
+	case 5:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:223
+		{
+			importpkg = nil
+		}
+	case 11:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:237
+		{
+			ipkg := importpkg
+			my := importmyname
+			importpkg = nil
+			importmyname = nil
+
+			if my == nil {
+				my = Lookup(ipkg.Name)
+			}
+
+			pack := Nod(OPACK, nil, nil)
+			pack.Sym = my
+			pack.Name.Pkg = ipkg
+			pack.Lineno = int32(yyDollar[1].i)
+
+			if strings.HasPrefix(my.Name, ".") {
+				importdot(ipkg, pack)
+				break
+			}
+			if my.Name == "init" {
+				Yyerror("cannot import package as init - init must be a func")
+				break
+			}
+			if my.Name == "_" {
+				break
+			}
+			if my.Def != nil {
+				lineno = int32(yyDollar[1].i)
+				redeclare(my, "as imported package name")
+			}
+			my.Def = pack
+			my.Lastlineno = int32(yyDollar[1].i)
+			my.Block = 1 // at top level
+		}
+	case 12:
+		yyDollar = yyS[yypt-2 : yypt+1]
+		//line go.y:272
+		{
+			// When an invalid import path is passed to importfile,
+			// it calls Yyerror and then sets up a fake import with
+			// no package statement. This allows us to test more
+			// than one invalid import statement in a single file.
+			if nerrors == 0 {
+				Fatal("phase error in import")
+			}
+		}
+	case 15:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:288
+		{
+			// import with original name
+			yyVAL.i = parserline()
+			importmyname = nil
+			importfile(&yyDollar[1].val, yyVAL.i)
+		}
+	case 16:
+		yyDollar = yyS[yypt-2 : yypt+1]
+		//line go.y:295
+		{
+			// import with given name
+			yyVAL.i = parserline()
+			importmyname = yyDollar[1].sym
+			importfile(&yyDollar[2].val, yyVAL.i)
+		}
+	case 17:
+		yyDollar = yyS[yypt-2 : yypt+1]
+		//line go.y:302
+		{
+			// import into my name space
+			yyVAL.i = parserline()
+			importmyname = Lookup(".")
+			importfile(&yyDollar[2].val, yyVAL.i)
+		}
+	case 18:
+		yyDollar = yyS[yypt-4 : yypt+1]
+		//line go.y:311
+		{
+			if importpkg.Name == "" {
+				importpkg.Name = yyDollar[2].sym.Name
+				numImport[yyDollar[2].sym.Name]++
+			} else if importpkg.Name != yyDollar[2].sym.Name {
+				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 %q", importpkg.Path)
+			}
+		}
+	case 20:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:328
+		{
+			if yyDollar[1].sym.Name == "safe" {
+				curio.importsafe = true
+			}
+		}
+	case 21:
+		yyDollar = yyS[yypt-0 : yypt+1]
+		//line go.y:335
+		{
+			defercheckwidth()
+		}
+	case 22:
+		yyDollar = yyS[yypt-4 : yypt+1]
+		//line go.y:339
+		{
+			resumecheckwidth()
+			unimportfile()
+		}
+	case 23:
+		yyDollar = yyS[yypt-0 : yypt+1]
+		//line go.y:348
+		{
+			Yyerror("empty top-level declaration")
+			yyVAL.list = nil
+		}
+	case 25:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:354
+		{
+			yyVAL.list = list1(yyDollar[1].node)
+		}
+	case 26:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:358
+		{
+			Yyerror("non-declaration statement outside function body")
+			yyVAL.list = nil
+		}
+	case 27:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:363
+		{
+			yyVAL.list = nil
+		}
+	case 28:
+		yyDollar = yyS[yypt-2 : yypt+1]
+		//line go.y:369
+		{
+			yyVAL.list = yyDollar[2].list
+		}
+	case 29:
+		yyDollar = yyS[yypt-5 : yypt+1]
+		//line go.y:373
+		{
+			yyVAL.list = yyDollar[3].list
+		}
+	case 30:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:377
+		{
+			yyVAL.list = nil
+		}
+	case 31:
+		yyDollar = yyS[yypt-2 : yypt+1]
+		//line go.y:381
+		{
+			yyVAL.list = yyDollar[2].list
+			iota_ = -100000
+			lastconst = nil
+		}
+	case 32:
+		yyDollar = yyS[yypt-5 : yypt+1]
+		//line go.y:387
+		{
+			yyVAL.list = yyDollar[3].list
+			iota_ = -100000
+			lastconst = nil
+		}
+	case 33:
+		yyDollar = yyS[yypt-7 : yypt+1]
+		//line go.y:393
+		{
+			yyVAL.list = concat(yyDollar[3].list, yyDollar[5].list)
+			iota_ = -100000
+			lastconst = nil
+		}
+	case 34:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:399
+		{
+			yyVAL.list = nil
+			iota_ = -100000
+		}
+	case 35:
+		yyDollar = yyS[yypt-2 : yypt+1]
+		//line go.y:404
+		{
+			yyVAL.list = list1(yyDollar[2].node)
+		}
+	case 36:
+		yyDollar = yyS[yypt-5 : yypt+1]
+		//line go.y:408
+		{
+			yyVAL.list = yyDollar[3].list
+		}
+	case 37:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:412
+		{
+			yyVAL.list = nil
+		}
+	case 38:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:418
+		{
+			iota_ = 0
+		}
+	case 39:
+		yyDollar = yyS[yypt-2 : yypt+1]
+		//line go.y:424
+		{
+			yyVAL.list = variter(yyDollar[1].list, yyDollar[2].node, nil)
+		}
+	case 40:
+		yyDollar = yyS[yypt-4 : yypt+1]
+		//line go.y:428
+		{
+			yyVAL.list = variter(yyDollar[1].list, yyDollar[2].node, yyDollar[4].list)
+		}
+	case 41:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:432
+		{
+			yyVAL.list = variter(yyDollar[1].list, nil, yyDollar[3].list)
+		}
+	case 42:
+		yyDollar = yyS[yypt-4 : yypt+1]
+		//line go.y:438
+		{
+			yyVAL.list = constiter(yyDollar[1].list, yyDollar[2].node, yyDollar[4].list)
+		}
+	case 43:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:442
+		{
+			yyVAL.list = constiter(yyDollar[1].list, nil, yyDollar[3].list)
+		}
+	case 45:
+		yyDollar = yyS[yypt-2 : yypt+1]
+		//line go.y:449
+		{
+			yyVAL.list = constiter(yyDollar[1].list, yyDollar[2].node, nil)
+		}
+	case 46:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:453
+		{
+			yyVAL.list = constiter(yyDollar[1].list, nil, nil)
+		}
+	case 47:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:459
+		{
+			// different from dclname because the name
+			// becomes visible right here, not at the end
+			// of the declaration.
+			yyVAL.node = typedcl0(yyDollar[1].sym)
+		}
+	case 48:
+		yyDollar = yyS[yypt-2 : yypt+1]
+		//line go.y:468
+		{
+			yyVAL.node = typedcl1(yyDollar[1].node, yyDollar[2].node, true)
+		}
+	case 49:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:474
+		{
+			yyVAL.node = yyDollar[1].node
+
+			// These nodes do not carry line numbers.
+			// Since a bare name used as an expression is an error,
+			// introduce a wrapper node to give the correct line.
+			switch yyVAL.node.Op {
+			case ONAME, ONONAME, OTYPE, OPACK, OLITERAL:
+				yyVAL.node = Nod(OPAREN, yyVAL.node, nil)
+				yyVAL.node.Implicit = true
+				break
+			}
+		}
+	case 50:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:488
+		{
+			yyVAL.node = Nod(OASOP, yyDollar[1].node, yyDollar[3].node)
+			yyVAL.node.Etype = uint8(yyDollar[2].i) // rathole to pass opcode
+		}
+	case 51:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:493
+		{
+			if yyDollar[1].list.Next == nil && yyDollar[3].list.Next == nil {
+				// simple
+				yyVAL.node = Nod(OAS, yyDollar[1].list.N, yyDollar[3].list.N)
+				break
+			}
+			// multiple
+			yyVAL.node = Nod(OAS2, nil, nil)
+			yyVAL.node.List = yyDollar[1].list
+			yyVAL.node.Rlist = yyDollar[3].list
+		}
+	case 52:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:505
+		{
+			if yyDollar[3].list.N.Op == OTYPESW {
+				yyVAL.node = Nod(OTYPESW, nil, yyDollar[3].list.N.Right)
+				if yyDollar[3].list.Next != nil {
+					Yyerror("expr.(type) must be alone in list")
+				}
+				if yyDollar[1].list.Next != nil {
+					Yyerror("argument count mismatch: %d = %d", count(yyDollar[1].list), 1)
+				} else if (yyDollar[1].list.N.Op != ONAME && yyDollar[1].list.N.Op != OTYPE && yyDollar[1].list.N.Op != ONONAME) || isblank(yyDollar[1].list.N) {
+					Yyerror("invalid variable name %s in type switch", yyDollar[1].list.N)
+				} else {
+					yyVAL.node.Left = dclname(yyDollar[1].list.N.Sym)
+				} // it's a colas, so must not re-use an oldname.
+				break
+			}
+			yyVAL.node = colas(yyDollar[1].list, yyDollar[3].list, int32(yyDollar[2].i))
+		}
+	case 53:
+		yyDollar = yyS[yypt-2 : yypt+1]
+		//line go.y:523
+		{
+			yyVAL.node = Nod(OASOP, yyDollar[1].node, Nodintconst(1))
+			yyVAL.node.Implicit = true
+			yyVAL.node.Etype = OADD
+		}
+	case 54:
+		yyDollar = yyS[yypt-2 : yypt+1]
+		//line go.y:529
+		{
+			yyVAL.node = Nod(OASOP, yyDollar[1].node, Nodintconst(1))
+			yyVAL.node.Implicit = true
+			yyVAL.node.Etype = OSUB
+		}
+	case 55:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:537
+		{
+			var n, nn *Node
+
+			// will be converted to OCASE
+			// right will point to next case
+			// done in casebody()
+			markdcl()
+			yyVAL.node = Nod(OXCASE, nil, nil)
+			yyVAL.node.List = yyDollar[2].list
+			if typesw != nil && typesw.Right != nil {
+				n = typesw.Right.Left
+				if n != nil {
+					// type switch - declare variable
+					nn = newname(n.Sym)
+					declare(nn, dclcontext)
+					yyVAL.node.Rlist = list1(nn)
+
+					// keep track of the instances for reporting unused
+					nn.Name.Defn = typesw.Right
+				}
+			}
+		}
+	case 56:
+		yyDollar = yyS[yypt-5 : yypt+1]
+		//line go.y:560
+		{
+			var n *Node
+
+			// will be converted to OCASE
+			// right will point to next case
+			// done in casebody()
+			markdcl()
+			yyVAL.node = Nod(OXCASE, nil, nil)
+			if yyDollar[2].list.Next == nil {
+				n = Nod(OAS, yyDollar[2].list.N, yyDollar[4].node)
+			} else {
+				n = Nod(OAS2, nil, nil)
+				n.List = yyDollar[2].list
+				n.Rlist = list1(yyDollar[4].node)
+			}
+			yyVAL.node.List = list1(n)
+		}
+	case 57:
+		yyDollar = yyS[yypt-5 : yypt+1]
+		//line go.y:578
+		{
+			// will be converted to OCASE
+			// right will point to next case
+			// done in casebody()
+			markdcl()
+			yyVAL.node = Nod(OXCASE, nil, nil)
+			yyVAL.node.List = list1(colas(yyDollar[2].list, list1(yyDollar[4].node), int32(yyDollar[3].i)))
+		}
+	case 58:
+		yyDollar = yyS[yypt-2 : yypt+1]
+		//line go.y:587
+		{
+			var n, nn *Node
+
+			markdcl()
+			yyVAL.node = Nod(OXCASE, nil, nil)
+			if typesw != nil && typesw.Right != nil {
+				n = typesw.Right.Left
+				if n != nil {
+					// type switch - declare variable
+					nn = newname(n.Sym)
+					declare(nn, dclcontext)
+					yyVAL.node.Rlist = list1(nn)
+
+					// keep track of the instances for reporting unused
+					nn.Name.Defn = typesw.Right
+				}
+			}
+		}
+	case 59:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:608
+		{
+			markdcl()
+		}
+	case 60:
+		yyDollar = yyS[yypt-4 : yypt+1]
+		//line go.y:612
+		{
+			if yyDollar[3].list == nil {
+				yyVAL.node = Nod(OEMPTY, nil, nil)
+			} else {
+				yyVAL.node = liststmt(yyDollar[3].list)
+			}
+			popdcl()
+		}
+	case 61:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:623
+		{
+			// If the last token read by the lexer was consumed
+			// as part of the case, clear it (parser has cleared yychar).
+			// If the last token read by the lexer was the lookahead
+			// leave it alone (parser has it cached in yychar).
+			// This is so that the stmt_list action doesn't look at
+			// the case tokens if the stmt_list is empty.
+			yylast = yychar
+			yyDollar[1].node.Xoffset = int64(block)
+		}
+	case 62:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:634
+		{
+			// This is the only place in the language where a statement
+			// list is not allowed to drop the final semicolon, because
+			// it's the only place where a statement list is not followed
+			// by a closing brace.  Handle the error for pedantry.
+
+			// Find the final token of the statement list.
+			// yylast is lookahead; yyprev is last of stmt_list
+			last := yyprev
+
+			if last > 0 && last != ';' && yychar != '}' {
+				Yyerror("missing statement after label")
+			}
+			yyVAL.node = yyDollar[1].node
+			yyVAL.node.Nbody = yyDollar[3].list
+			popdcl()
+		}
+	case 63:
+		yyDollar = yyS[yypt-0 : yypt+1]
+		//line go.y:653
+		{
+			yyVAL.list = nil
+		}
+	case 64:
+		yyDollar = yyS[yypt-2 : yypt+1]
+		//line go.y:657
+		{
+			yyVAL.list = list(yyDollar[1].list, yyDollar[2].node)
+		}
+	case 65:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:663
+		{
+			markdcl()
+		}
+	case 66:
+		yyDollar = yyS[yypt-4 : yypt+1]
+		//line go.y:667
+		{
+			yyVAL.list = yyDollar[3].list
+			popdcl()
+		}
+	case 67:
+		yyDollar = yyS[yypt-4 : yypt+1]
+		//line go.y:674
+		{
+			yyVAL.node = Nod(ORANGE, nil, yyDollar[4].node)
+			yyVAL.node.List = yyDollar[1].list
+			yyVAL.node.Etype = 0 // := flag
+		}
+	case 68:
+		yyDollar = yyS[yypt-4 : yypt+1]
+		//line go.y:680
+		{
+			yyVAL.node = Nod(ORANGE, nil, yyDollar[4].node)
+			yyVAL.node.List = yyDollar[1].list
+			yyVAL.node.Colas = true
+			colasdefn(yyDollar[1].list, yyVAL.node)
+		}
+	case 69:
+		yyDollar = yyS[yypt-2 : yypt+1]
+		//line go.y:687
+		{
+			yyVAL.node = Nod(ORANGE, nil, yyDollar[2].node)
+			yyVAL.node.Etype = 0 // := flag
+		}
+	case 70:
+		yyDollar = yyS[yypt-5 : yypt+1]
+		//line go.y:694
+		{
+			// init ; test ; incr
+			if yyDollar[5].node != nil && yyDollar[5].node.Colas {
+				Yyerror("cannot declare in the for-increment")
+			}
+			yyVAL.node = Nod(OFOR, nil, nil)
+			if yyDollar[1].node != nil {
+				yyVAL.node.Ninit = list1(yyDollar[1].node)
+			}
+			yyVAL.node.Left = yyDollar[3].node
+			yyVAL.node.Right = yyDollar[5].node
+		}
+	case 71:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:707
+		{
+			// normal test
+			yyVAL.node = Nod(OFOR, nil, nil)
+			yyVAL.node.Left = yyDollar[1].node
+		}
+	case 73:
+		yyDollar = yyS[yypt-2 : yypt+1]
+		//line go.y:716
+		{
+			yyVAL.node = yyDollar[1].node
+			yyVAL.node.Nbody = concat(yyVAL.node.Nbody, yyDollar[2].list)
+		}
+	case 74:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:723
+		{
+			markdcl()
+		}
+	case 75:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:727
+		{
+			yyVAL.node = yyDollar[3].node
+			popdcl()
+		}
+	case 76:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:734
+		{
+			// test
+			yyVAL.node = Nod(OIF, nil, nil)
+			yyVAL.node.Left = yyDollar[1].node
+		}
+	case 77:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:740
+		{
+			// init ; test
+			yyVAL.node = Nod(OIF, nil, nil)
+			if yyDollar[1].node != nil {
+				yyVAL.node.Ninit = list1(yyDollar[1].node)
+			}
+			yyVAL.node.Left = yyDollar[3].node
+		}
+	case 78:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:752
+		{
+			markdcl()
+		}
+	case 79:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:756
+		{
+			if yyDollar[3].node.Left == nil {
+				Yyerror("missing condition in if statement")
+			}
+		}
+	case 80:
+		yyDollar = yyS[yypt-5 : yypt+1]
+		//line go.y:762
+		{
+			yyDollar[3].node.Nbody = yyDollar[5].list
+		}
+	case 81:
+		yyDollar = yyS[yypt-8 : yypt+1]
+		//line go.y:766
+		{
+			var n *Node
+			var nn *NodeList
+
+			yyVAL.node = yyDollar[3].node
+			n = yyDollar[3].node
+			popdcl()
+			for nn = concat(yyDollar[7].list, yyDollar[8].list); nn != nil; nn = nn.Next {
+				if nn.N.Op == OIF {
+					popdcl()
+				}
+				n.Rlist = list1(nn.N)
+				n = nn.N
+			}
+		}
+	case 82:
+		yyDollar = yyS[yypt-2 : yypt+1]
+		//line go.y:784
+		{
+			markdcl()
+		}
+	case 83:
+		yyDollar = yyS[yypt-5 : yypt+1]
+		//line go.y:788
+		{
+			if yyDollar[4].node.Left == nil {
+				Yyerror("missing condition in if statement")
+			}
+			yyDollar[4].node.Nbody = yyDollar[5].list
+			yyVAL.list = list1(yyDollar[4].node)
+		}
+	case 84:
+		yyDollar = yyS[yypt-0 : yypt+1]
+		//line go.y:797
+		{
+			yyVAL.list = nil
+		}
+	case 85:
+		yyDollar = yyS[yypt-2 : yypt+1]
+		//line go.y:801
+		{
+			yyVAL.list = concat(yyDollar[1].list, yyDollar[2].list)
+		}
+	case 86:
+		yyDollar = yyS[yypt-0 : yypt+1]
+		//line go.y:806
+		{
+			yyVAL.list = nil
+		}
+	case 87:
+		yyDollar = yyS[yypt-2 : yypt+1]
+		//line go.y:810
+		{
+			l := &NodeList{N: yyDollar[2].node}
+			l.End = l
+			yyVAL.list = l
+		}
+	case 88:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:818
+		{
+			markdcl()
+		}
+	case 89:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:822
+		{
+			var n *Node
+			n = yyDollar[3].node.Left
+			if n != nil && n.Op != OTYPESW {
+				n = nil
+			}
+			typesw = Nod(OXXX, typesw, n)
+		}
+	case 90:
+		yyDollar = yyS[yypt-7 : yypt+1]
+		//line go.y:831
+		{
+			yyVAL.node = yyDollar[3].node
+			yyVAL.node.Op = OSWITCH
+			yyVAL.node.List = yyDollar[6].list
+			typesw = typesw.Left
+			popdcl()
+		}
+	case 91:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:841
+		{
+			typesw = Nod(OXXX, typesw, nil)
+		}
+	case 92:
+		yyDollar = yyS[yypt-5 : yypt+1]
+		//line go.y:845
+		{
+			yyVAL.node = Nod(OSELECT, nil, nil)
+			yyVAL.node.Lineno = typesw.Lineno
+			yyVAL.node.List = yyDollar[4].list
+			typesw = typesw.Left
+		}
+	case 94:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:858
+		{
+			yyVAL.node = Nod(OOROR, yyDollar[1].node, yyDollar[3].node)
+		}
+	case 95:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:862
+		{
+			yyVAL.node = Nod(OANDAND, yyDollar[1].node, yyDollar[3].node)
+		}
+	case 96:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:866
+		{
+			yyVAL.node = Nod(OEQ, yyDollar[1].node, yyDollar[3].node)
+		}
+	case 97:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:870
+		{
+			yyVAL.node = Nod(ONE, yyDollar[1].node, yyDollar[3].node)
+		}
+	case 98:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:874
+		{
+			yyVAL.node = Nod(OLT, yyDollar[1].node, yyDollar[3].node)
+		}
+	case 99:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:878
+		{
+			yyVAL.node = Nod(OLE, yyDollar[1].node, yyDollar[3].node)
+		}
+	case 100:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:882
+		{
+			yyVAL.node = Nod(OGE, yyDollar[1].node, yyDollar[3].node)
+		}
+	case 101:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:886
+		{
+			yyVAL.node = Nod(OGT, yyDollar[1].node, yyDollar[3].node)
+		}
+	case 102:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:890
+		{
+			yyVAL.node = Nod(OADD, yyDollar[1].node, yyDollar[3].node)
+		}
+	case 103:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:894
+		{
+			yyVAL.node = Nod(OSUB, yyDollar[1].node, yyDollar[3].node)
+		}
+	case 104:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:898
+		{
+			yyVAL.node = Nod(OOR, yyDollar[1].node, yyDollar[3].node)
+		}
+	case 105:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:902
+		{
+			yyVAL.node = Nod(OXOR, yyDollar[1].node, yyDollar[3].node)
+		}
+	case 106:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:906
+		{
+			yyVAL.node = Nod(OMUL, yyDollar[1].node, yyDollar[3].node)
+		}
+	case 107:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:910
+		{
+			yyVAL.node = Nod(ODIV, yyDollar[1].node, yyDollar[3].node)
+		}
+	case 108:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:914
+		{
+			yyVAL.node = Nod(OMOD, yyDollar[1].node, yyDollar[3].node)
+		}
+	case 109:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:918
+		{
+			yyVAL.node = Nod(OAND, yyDollar[1].node, yyDollar[3].node)
+		}
+	case 110:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:922
+		{
+			yyVAL.node = Nod(OANDNOT, yyDollar[1].node, yyDollar[3].node)
+		}
+	case 111:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:926
+		{
+			yyVAL.node = Nod(OLSH, yyDollar[1].node, yyDollar[3].node)
+		}
+	case 112:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:930
+		{
+			yyVAL.node = Nod(ORSH, yyDollar[1].node, yyDollar[3].node)
+		}
+	case 113:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:935
+		{
+			yyVAL.node = Nod(OSEND, yyDollar[1].node, yyDollar[3].node)
+		}
+	case 115:
+		yyDollar = yyS[yypt-2 : yypt+1]
+		//line go.y:942
+		{
+			yyVAL.node = Nod(OIND, yyDollar[2].node, nil)
+		}
+	case 116:
+		yyDollar = yyS[yypt-2 : yypt+1]
+		//line go.y:946
+		{
+			if yyDollar[2].node.Op == OCOMPLIT {
+				// 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 = true
+			} else {
+				yyVAL.node = Nod(OADDR, yyDollar[2].node, nil)
+			}
+		}
+	case 117:
+		yyDollar = yyS[yypt-2 : yypt+1]
+		//line go.y:957
+		{
+			yyVAL.node = Nod(OPLUS, yyDollar[2].node, nil)
+		}
+	case 118:
+		yyDollar = yyS[yypt-2 : yypt+1]
+		//line go.y:961
+		{
+			yyVAL.node = Nod(OMINUS, yyDollar[2].node, nil)
+		}
+	case 119:
+		yyDollar = yyS[yypt-2 : yypt+1]
+		//line go.y:965
+		{
+			yyVAL.node = Nod(ONOT, yyDollar[2].node, nil)
+		}
+	case 120:
+		yyDollar = yyS[yypt-2 : yypt+1]
+		//line go.y:969
+		{
+			Yyerror("the bitwise complement operator is ^")
+			yyVAL.node = Nod(OCOM, yyDollar[2].node, nil)
+		}
+	case 121:
+		yyDollar = yyS[yypt-2 : yypt+1]
+		//line go.y:974
+		{
+			yyVAL.node = Nod(OCOM, yyDollar[2].node, nil)
+		}
+	case 122:
+		yyDollar = yyS[yypt-2 : yypt+1]
+		//line go.y:978
+		{
+			yyVAL.node = Nod(ORECV, yyDollar[2].node, nil)
+		}
+	case 123:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:988
+		{
+			yyVAL.node = Nod(OCALL, yyDollar[1].node, nil)
+		}
+	case 124:
+		yyDollar = yyS[yypt-5 : yypt+1]
+		//line go.y:992
+		{
+			yyVAL.node = Nod(OCALL, yyDollar[1].node, nil)
+			yyVAL.node.List = yyDollar[3].list
+		}
+	case 125:
+		yyDollar = yyS[yypt-6 : yypt+1]
+		//line go.y:997
+		{
+			yyVAL.node = Nod(OCALL, yyDollar[1].node, nil)
+			yyVAL.node.List = yyDollar[3].list
+			yyVAL.node.Isddd = true
+		}
+	case 126:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:1005
+		{
+			yyVAL.node = nodlit(yyDollar[1].val)
+		}
+	case 128:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:1010
+		{
+			if yyDollar[1].node.Op == OPACK {
+				var s *Sym
+				s = restrictlookup(yyDollar[3].sym.Name, yyDollar[1].node.Name.Pkg)
+				yyDollar[1].node.Used = true
+				yyVAL.node = oldname(s)
+				break
+			}
+			yyVAL.node = Nod(OXDOT, yyDollar[1].node, newname(yyDollar[3].sym))
+		}
+	case 129:
+		yyDollar = yyS[yypt-5 : yypt+1]
+		//line go.y:1021
+		{
+			yyVAL.node = Nod(ODOTTYPE, yyDollar[1].node, yyDollar[4].node)
+		}
+	case 130:
+		yyDollar = yyS[yypt-5 : yypt+1]
+		//line go.y:1025
+		{
+			yyVAL.node = Nod(OTYPESW, nil, yyDollar[1].node)
+		}
+	case 131:
+		yyDollar = yyS[yypt-4 : yypt+1]
+		//line go.y:1029
+		{
+			yyVAL.node = Nod(OINDEX, yyDollar[1].node, yyDollar[3].node)
+		}
+	case 132:
+		yyDollar = yyS[yypt-6 : yypt+1]
+		//line go.y:1033
+		{
+			yyVAL.node = Nod(OSLICE, yyDollar[1].node, Nod(OKEY, yyDollar[3].node, yyDollar[5].node))
+		}
+	case 133:
+		yyDollar = yyS[yypt-8 : yypt+1]
+		//line go.y:1037
+		{
+			if yyDollar[5].node == nil {
+				Yyerror("middle index required in 3-index slice")
+			}
+			if yyDollar[7].node == nil {
+				Yyerror("final index required in 3-index slice")
+			}
+			yyVAL.node = Nod(OSLICE3, yyDollar[1].node, Nod(OKEY, yyDollar[3].node, Nod(OKEY, yyDollar[5].node, yyDollar[7].node)))
+		}
+	case 135:
+		yyDollar = yyS[yypt-5 : yypt+1]
+		//line go.y:1048
+		{
+			// conversion
+			yyVAL.node = Nod(OCALL, yyDollar[1].node, nil)
+			yyVAL.node.List = list1(yyDollar[3].node)
+		}
+	case 136:
+		yyDollar = yyS[yypt-5 : yypt+1]
+		//line go.y:1054
+		{
+			yyVAL.node = yyDollar[3].node
+			yyVAL.node.Right = yyDollar[1].node
+			yyVAL.node.List = yyDollar[4].list
+			fixlbrace(yyDollar[2].i)
+		}
+	case 137:
+		yyDollar = yyS[yypt-5 : yypt+1]
+		//line go.y:1061
+		{
+			yyVAL.node = yyDollar[3].node
+			yyVAL.node.Right = yyDollar[1].node
+			yyVAL.node.List = yyDollar[4].list
+		}
+	case 138:
+		yyDollar = yyS[yypt-7 : yypt+1]
+		//line go.y:1067
+		{
+			Yyerror("cannot parenthesize type in composite literal")
+			yyVAL.node = yyDollar[5].node
+			yyVAL.node.Right = yyDollar[2].node
+			yyVAL.node.List = yyDollar[6].list
+		}
+	case 140:
+		yyDollar = yyS[yypt-0 : yypt+1]
+		//line go.y:1076
+		{
+			// composite expression.
+			// make node early so we get the right line number.
+			yyVAL.node = Nod(OCOMPLIT, nil, nil)
+		}
+	case 141:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:1084
+		{
+			yyVAL.node = Nod(OKEY, yyDollar[1].node, yyDollar[3].node)
+		}
+	case 142:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:1090
+		{
+			// These nodes do not carry line numbers.
+			// Since a composite literal commonly spans several lines,
+			// the line number on errors may be misleading.
+			// Introduce a wrapper node to give the correct line.
+			yyVAL.node = yyDollar[1].node
+			switch yyVAL.node.Op {
+			case ONAME, ONONAME, OTYPE, OPACK, OLITERAL:
+				yyVAL.node = Nod(OPAREN, yyVAL.node, nil)
+				yyVAL.node.Implicit = true
+			}
+		}
+	case 143:
+		yyDollar = yyS[yypt-4 : yypt+1]
+		//line go.y:1103
+		{
+			yyVAL.node = yyDollar[2].node
+			yyVAL.node.List = yyDollar[3].list
+		}
+	case 145:
+		yyDollar = yyS[yypt-4 : yypt+1]
+		//line go.y:1111
+		{
+			yyVAL.node = yyDollar[2].node
+			yyVAL.node.List = yyDollar[3].list
+		}
+	case 147:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:1119
+		{
+			yyVAL.node = yyDollar[2].node
+
+			// Need to know on lhs of := whether there are ( ).
+			// Don't bother with the OPAREN in other cases:
+			// it's just a waste of memory and time.
+			switch yyVAL.node.Op {
+			case ONAME, ONONAME, OPACK, OTYPE, OLITERAL, OTYPESW:
+				yyVAL.node = Nod(OPAREN, yyVAL.node, nil)
+			}
+		}
+	case 151:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:1140
+		{
+			yyVAL.i = LBODY
+		}
+	case 152:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:1144
+		{
+			yyVAL.i = '{'
+		}
+	case 153:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:1155
+		{
+			if yyDollar[1].sym == nil {
+				yyVAL.node = nil
+			} else {
+				yyVAL.node = newname(yyDollar[1].sym)
+			}
+		}
+	case 154:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:1165
+		{
+			yyVAL.node = dclname(yyDollar[1].sym)
+		}
+	case 155:
+		yyDollar = yyS[yypt-0 : yypt+1]
+		//line go.y:1170
+		{
+			yyVAL.node = nil
+		}
+	case 157:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:1177
+		{
+			yyVAL.sym = yyDollar[1].sym
+			// during imports, unqualified non-exported identifiers are from builtinpkg
+			if importpkg != nil && !exportname(yyDollar[1].sym.Name) {
+				yyVAL.sym = Pkglookup(yyDollar[1].sym.Name, builtinpkg)
+			}
+		}
+	case 159:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:1186
+		{
+			yyVAL.sym = nil
+		}
+	case 160:
+		yyDollar = yyS[yypt-4 : yypt+1]
+		//line go.y:1192
+		{
+			var p *Pkg
+
+			if yyDollar[2].val.U.(string) == "" {
+				p = importpkg
+			} else {
+				if isbadimport(yyDollar[2].val.U.(string)) {
+					errorexit()
+				}
+				p = mkpkg(yyDollar[2].val.U.(string))
+			}
+			yyVAL.sym = Pkglookup(yyDollar[4].sym.Name, p)
+		}
+	case 161:
+		yyDollar = yyS[yypt-4 : yypt+1]
+		//line go.y:1206
+		{
+			var p *Pkg
+
+			if yyDollar[2].val.U.(string) == "" {
+				p = importpkg
+			} else {
+				if isbadimport(yyDollar[2].val.U.(string)) {
+					errorexit()
+				}
+				p = mkpkg(yyDollar[2].val.U.(string))
+			}
+			yyVAL.sym = Pkglookup("?", p)
+		}
+	case 162:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:1222
+		{
+			yyVAL.node = oldname(yyDollar[1].sym)
+			if yyVAL.node.Name != nil && yyVAL.node.Name.Pack != nil {
+				yyVAL.node.Name.Pack.Used = true
+			}
+		}
+	case 164:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:1243
+		{
+			Yyerror("final argument in variadic function missing type")
+			yyVAL.node = Nod(ODDD, typenod(typ(TINTER)), nil)
+		}
+	case 165:
+		yyDollar = yyS[yypt-2 : yypt+1]
+		//line go.y:1248
+		{
+			yyVAL.node = Nod(ODDD, yyDollar[2].node, nil)
+		}
+	case 171:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:1259
+		{
+			yyVAL.node = yyDollar[2].node
+		}
+	case 175:
+		yyDollar = yyS[yypt-2 : yypt+1]
+		//line go.y:1268
+		{
+			yyVAL.node = Nod(OIND, yyDollar[2].node, nil)
+		}
+	case 180:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:1278
+		{
+			yyVAL.node = yyDollar[2].node
+		}
+	case 190:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:1299
+		{
+			if yyDollar[1].node.Op == OPACK {
+				var s *Sym
+				s = restrictlookup(yyDollar[3].sym.Name, yyDollar[1].node.Name.Pkg)
+				yyDollar[1].node.Used = true
+				yyVAL.node = oldname(s)
+				break
+			}
+			yyVAL.node = Nod(OXDOT, yyDollar[1].node, newname(yyDollar[3].sym))
+		}
+	case 191:
+		yyDollar = yyS[yypt-4 : yypt+1]
+		//line go.y:1312
+		{
+			yyVAL.node = Nod(OTARRAY, yyDollar[2].node, yyDollar[4].node)
+		}
+	case 192:
+		yyDollar = yyS[yypt-4 : yypt+1]
+		//line go.y:1316
+		{
+			// array literal of nelem
+			yyVAL.node = Nod(OTARRAY, Nod(ODDD, nil, nil), yyDollar[4].node)
+		}
+	case 193:
+		yyDollar = yyS[yypt-2 : yypt+1]
+		//line go.y:1321
+		{
+			yyVAL.node = Nod(OTCHAN, yyDollar[2].node, nil)
+			yyVAL.node.Etype = Cboth
+		}
+	case 194:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:1326
+		{
+			yyVAL.node = Nod(OTCHAN, yyDollar[3].node, nil)
+			yyVAL.node.Etype = Csend
+		}
+	case 195:
+		yyDollar = yyS[yypt-5 : yypt+1]
+		//line go.y:1331
+		{
+			yyVAL.node = Nod(OTMAP, yyDollar[3].node, yyDollar[5].node)
+		}
+	case 198:
+		yyDollar = yyS[yypt-2 : yypt+1]
+		//line go.y:1339
+		{
+			yyVAL.node = Nod(OIND, yyDollar[2].node, nil)
+		}
+	case 199:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:1345
+		{
+			yyVAL.node = Nod(OTCHAN, yyDollar[3].node, nil)
+			yyVAL.node.Etype = Crecv
+		}
+	case 200:
+		yyDollar = yyS[yypt-5 : yypt+1]
+		//line go.y:1352
+		{
+			yyVAL.node = Nod(OTSTRUCT, nil, nil)
+			yyVAL.node.List = yyDollar[3].list
+			fixlbrace(yyDollar[2].i)
+		}
+	case 201:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:1358
+		{
+			yyVAL.node = Nod(OTSTRUCT, nil, nil)
+			fixlbrace(yyDollar[2].i)
+		}
+	case 202:
+		yyDollar = yyS[yypt-5 : yypt+1]
+		//line go.y:1365
+		{
+			yyVAL.node = Nod(OTINTER, nil, nil)
+			yyVAL.node.List = yyDollar[3].list
+			fixlbrace(yyDollar[2].i)
+		}
+	case 203:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:1371
+		{
+			yyVAL.node = Nod(OTINTER, nil, nil)
+			fixlbrace(yyDollar[2].i)
+		}
+	case 204:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:1382
+		{
+			yyVAL.node = yyDollar[2].node
+			if yyVAL.node == nil {
+				break
+			}
+			if noescape && yyDollar[3].list != nil {
+				Yyerror("can only use //go:noescape with external func implementations")
+			}
+			yyVAL.node.Nbody = yyDollar[3].list
+			yyVAL.node.Func.Endlineno = lineno
+			yyVAL.node.Noescape = noescape
+			yyVAL.node.Func.Norace = norace
+			yyVAL.node.Func.Nosplit = nosplit
+			yyVAL.node.Func.Nowritebarrier = nowritebarrier
+			yyVAL.node.Func.Systemstack = systemstack
+			funcbody(yyVAL.node)
+		}
+	case 205:
+		yyDollar = yyS[yypt-5 : yypt+1]
+		//line go.y:1402
+		{
+			var t *Node
+
+			yyVAL.node = nil
+			yyDollar[3].list = checkarglist(yyDollar[3].list, 1)
+
+			if yyDollar[1].sym.Name == "init" {
+				yyDollar[1].sym = renameinit()
+				if yyDollar[3].list != nil || yyDollar[5].list != nil {
+					Yyerror("func init must have no arguments and no return values")
+				}
+			}
+			if localpkg.Name == "main" && yyDollar[1].sym.Name == "main" {
+				if yyDollar[3].list != nil || yyDollar[5].list != nil {
+					Yyerror("func main must have no arguments and no return values")
+				}
+			}
+
+			t = Nod(OTFUNC, nil, nil)
+			t.List = yyDollar[3].list
+			t.Rlist = yyDollar[5].list
+
+			yyVAL.node = Nod(ODCLFUNC, nil, nil)
+			yyVAL.node.Func.Nname = newfuncname(yyDollar[1].sym)
+			yyVAL.node.Func.Nname.Name.Defn = yyVAL.node
+			yyVAL.node.Func.Nname.Name.Param.Ntype = t // TODO: check if nname already has an ntype
+			declare(yyVAL.node.Func.Nname, PFUNC)
+
+			funchdr(yyVAL.node)
+		}
+	case 206:
+		yyDollar = yyS[yypt-8 : yypt+1]
+		//line go.y:1433
+		{
+			var rcvr, t *Node
+
+			yyVAL.node = nil
+			yyDollar[2].list = checkarglist(yyDollar[2].list, 0)
+			yyDollar[6].list = checkarglist(yyDollar[6].list, 1)
+
+			if yyDollar[2].list == nil {
+				Yyerror("method has no receiver")
+				break
+			}
+			if yyDollar[2].list.Next != nil {
+				Yyerror("method has multiple receivers")
+				break
+			}
+			rcvr = yyDollar[2].list.N
+			if rcvr.Op != ODCLFIELD {
+				Yyerror("bad receiver in method")
+				break
+			}
+
+			t = Nod(OTFUNC, rcvr, nil)
+			t.List = yyDollar[6].list
+			t.Rlist = yyDollar[8].list
+
+			yyVAL.node = Nod(ODCLFUNC, nil, nil)
+			yyVAL.node.Func.Shortname = newfuncname(yyDollar[4].sym)
+			yyVAL.node.Func.Nname = methodname1(yyVAL.node.Func.Shortname, rcvr.Right)
+			yyVAL.node.Func.Nname.Name.Defn = yyVAL.node
+			yyVAL.node.Func.Nname.Name.Param.Ntype = t
+			yyVAL.node.Func.Nname.Nointerface = nointerface
+			declare(yyVAL.node.Func.Nname, PFUNC)
+
+			funchdr(yyVAL.node)
+		}
+	case 207:
+		yyDollar = yyS[yypt-5 : yypt+1]
+		//line go.y:1471
+		{
+			var s *Sym
+			var t *Type
+
+			yyVAL.node = nil
+
+			s = yyDollar[1].sym
+			t = functype(nil, yyDollar[3].list, yyDollar[5].list)
+
+			importsym(s, ONAME)
+			if s.Def != nil && s.Def.Op == ONAME {
+				if Eqtype(t, s.Def.Type) {
+					dclcontext = PDISCARD // since we skip funchdr below
+					break
+				}
+				Yyerror("inconsistent definition for func %v during import\n\t%v\n\t%v", s, s.Def.Type, t)
+			}
+
+			yyVAL.node = newfuncname(s)
+			yyVAL.node.Type = t
+			declare(yyVAL.node, PFUNC)
+
+			funchdr(yyVAL.node)
+		}
+	case 208:
+		yyDollar = yyS[yypt-8 : yypt+1]
+		//line go.y:1496
+		{
+			yyVAL.node = methodname1(newname(yyDollar[4].sym), yyDollar[2].list.N.Right)
+			yyVAL.node.Type = functype(yyDollar[2].list.N, yyDollar[6].list, yyDollar[8].list)
+
+			checkwidth(yyVAL.node.Type)
+			addmethod(yyDollar[4].sym, yyVAL.node.Type, false, nointerface)
+			nointerface = false
+			funchdr(yyVAL.node)
+
+			// inl.C's inlnode in on a dotmeth node expects to find the inlineable body as
+			// (dotmeth's type).Nname.Inl, and dotmeth's type has been pulled
+			// out by typecheck's lookdot as this $$.ttype.  So by providing
+			// this back link here we avoid special casing there.
+			yyVAL.node.Type.Nname = yyVAL.node
+		}
+	case 209:
+		yyDollar = yyS[yypt-5 : yypt+1]
+		//line go.y:1514
+		{
+			yyDollar[3].list = checkarglist(yyDollar[3].list, 1)
+			yyVAL.node = Nod(OTFUNC, nil, nil)
+			yyVAL.node.List = yyDollar[3].list
+			yyVAL.node.Rlist = yyDollar[5].list
+		}
+	case 210:
+		yyDollar = yyS[yypt-0 : yypt+1]
+		//line go.y:1522
+		{
+			yyVAL.list = nil
+		}
+	case 211:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:1526
+		{
+			yyVAL.list = yyDollar[2].list
+			if yyVAL.list == nil {
+				yyVAL.list = list1(Nod(OEMPTY, nil, nil))
+			}
+		}
+	case 212:
+		yyDollar = yyS[yypt-0 : yypt+1]
+		//line go.y:1535
+		{
+			yyVAL.list = nil
+		}
+	case 213:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:1539
+		{
+			yyVAL.list = list1(Nod(ODCLFIELD, nil, yyDollar[1].node))
+		}
+	case 214:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:1543
+		{
+			yyDollar[2].list = checkarglist(yyDollar[2].list, 0)
+			yyVAL.list = yyDollar[2].list
+		}
+	case 215:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:1550
+		{
+			closurehdr(yyDollar[1].node)
+		}
+	case 216:
+		yyDollar = yyS[yypt-4 : yypt+1]
+		//line go.y:1556
+		{
+			yyVAL.node = closurebody(yyDollar[3].list)
+			fixlbrace(yyDollar[2].i)
+		}
+	case 217:
+		yyDollar = yyS[yypt-2 : yypt+1]
+		//line go.y:1561
+		{
+			yyVAL.node = closurebody(nil)
+		}
+	case 218:
+		yyDollar = yyS[yypt-0 : yypt+1]
+		//line go.y:1572
+		{
+			yyVAL.list = nil
+		}
+	case 219:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:1576
+		{
+			yyVAL.list = concat(yyDollar[1].list, yyDollar[2].list)
+			if nsyntaxerrors == 0 {
+				testdclstack()
+			}
+			nointerface = false
+			noescape = false
+			norace = false
+			nosplit = false
+			nowritebarrier = false
+			systemstack = false
+		}
+	case 221:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:1592
+		{
+			yyVAL.list = concat(yyDollar[1].list, yyDollar[3].list)
+		}
+	case 223:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:1599
+		{
+			yyVAL.list = concat(yyDollar[1].list, yyDollar[3].list)
+		}
+	case 224:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:1605
+		{
+			yyVAL.list = list1(yyDollar[1].node)
+		}
+	case 225:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:1609
+		{
+			yyVAL.list = list(yyDollar[1].list, yyDollar[3].node)
+		}
+	case 227:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:1616
+		{
+			yyVAL.list = concat(yyDollar[1].list, yyDollar[3].list)
+		}
+	case 228:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:1622
+		{
+			yyVAL.list = list1(yyDollar[1].node)
+		}
+	case 229:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:1626
+		{
+			yyVAL.list = list(yyDollar[1].list, yyDollar[3].node)
+		}
+	case 230:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:1632
+		{
+			var l *NodeList
+
+			var n *Node
+			l = yyDollar[1].list
+			if l == nil || l.N.Sym.Name == "?" {
+				// ? symbol, during import (list1(nil) == nil)
+				n = yyDollar[2].node
+				if n.Op == OIND {
+					n = n.Left
+				}
+				n = embedded(n.Sym, importpkg)
+				n.Right = yyDollar[2].node
+				n.SetVal(yyDollar[3].val)
+				yyVAL.list = list1(n)
+				break
+			}
+
+			for l = yyDollar[1].list; l != nil; l = l.Next {
+				l.N = Nod(ODCLFIELD, l.N, yyDollar[2].node)
+				l.N.SetVal(yyDollar[3].val)
+			}
+		}
+	case 231:
+		yyDollar = yyS[yypt-2 : yypt+1]
+		//line go.y:1656
+		{
+			yyDollar[1].node.SetVal(yyDollar[2].val)
+			yyVAL.list = list1(yyDollar[1].node)
+		}
+	case 232:
+		yyDollar = yyS[yypt-4 : yypt+1]
+		//line go.y:1661
+		{
+			yyDollar[2].node.SetVal(yyDollar[4].val)
+			yyVAL.list = list1(yyDollar[2].node)
+			Yyerror("cannot parenthesize embedded type")
+		}
+	case 233:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:1667
+		{
+			yyDollar[2].node.Right = Nod(OIND, yyDollar[2].node.Right, nil)
+			yyDollar[2].node.SetVal(yyDollar[3].val)
+			yyVAL.list = list1(yyDollar[2].node)
+		}
+	case 234:
+		yyDollar = yyS[yypt-5 : yypt+1]
+		//line go.y:1673
+		{
+			yyDollar[3].node.Right = Nod(OIND, yyDollar[3].node.Right, nil)
+			yyDollar[3].node.SetVal(yyDollar[5].val)
+			yyVAL.list = list1(yyDollar[3].node)
+			Yyerror("cannot parenthesize embedded type")
+		}
+	case 235:
+		yyDollar = yyS[yypt-5 : yypt+1]
+		//line go.y:1680
+		{
+			yyDollar[3].node.Right = Nod(OIND, yyDollar[3].node.Right, nil)
+			yyDollar[3].node.SetVal(yyDollar[5].val)
+			yyVAL.list = list1(yyDollar[3].node)
+			Yyerror("cannot parenthesize embedded type")
+		}
+	case 236:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:1689
+		{
+			var n *Node
+
+			yyVAL.sym = yyDollar[1].sym
+			n = oldname(yyDollar[1].sym)
+			if n.Name != nil && n.Name.Pack != nil {
+				n.Name.Pack.Used = true
+			}
+		}
+	case 237:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:1699
+		{
+			var pkg *Pkg
+
+			if yyDollar[1].sym.Def == nil || yyDollar[1].sym.Def.Op != OPACK {
+				Yyerror("%v is not a package", yyDollar[1].sym)
+				pkg = localpkg
+			} else {
+				yyDollar[1].sym.Def.Used = true
+				pkg = yyDollar[1].sym.Def.Name.Pkg
+			}
+			yyVAL.sym = restrictlookup(yyDollar[3].sym.Name, pkg)
+		}
+	case 238:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:1714
+		{
+			yyVAL.node = embedded(yyDollar[1].sym, localpkg)
+		}
+	case 239:
+		yyDollar = yyS[yypt-2 : yypt+1]
+		//line go.y:1720
+		{
+			yyVAL.node = Nod(ODCLFIELD, yyDollar[1].node, yyDollar[2].node)
+			ifacedcl(yyVAL.node)
+		}
+	case 240:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:1725
+		{
+			yyVAL.node = Nod(ODCLFIELD, nil, oldname(yyDollar[1].sym))
+		}
+	case 241:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:1729
+		{
+			yyVAL.node = Nod(ODCLFIELD, nil, oldname(yyDollar[2].sym))
+			Yyerror("cannot parenthesize embedded type")
+		}
+	case 242:
+		yyDollar = yyS[yypt-4 : yypt+1]
+		//line go.y:1736
+		{
+			// without func keyword
+			yyDollar[2].list = checkarglist(yyDollar[2].list, 1)
+			yyVAL.node = Nod(OTFUNC, fakethis(), nil)
+			yyVAL.node.List = yyDollar[2].list
+			yyVAL.node.Rlist = yyDollar[4].list
+		}
+	case 244:
+		yyDollar = yyS[yypt-2 : yypt+1]
+		//line go.y:1750
+		{
+			yyVAL.node = Nod(ONONAME, nil, nil)
+			yyVAL.node.Sym = yyDollar[1].sym
+			yyVAL.node = Nod(OKEY, yyVAL.node, yyDollar[2].node)
+		}
+	case 245:
+		yyDollar = yyS[yypt-2 : yypt+1]
+		//line go.y:1756
+		{
+			yyVAL.node = Nod(ONONAME, nil, nil)
+			yyVAL.node.Sym = yyDollar[1].sym
+			yyVAL.node = Nod(OKEY, yyVAL.node, yyDollar[2].node)
+		}
+	case 247:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:1765
+		{
+			yyVAL.list = list1(yyDollar[1].node)
+		}
+	case 248:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:1769
+		{
+			yyVAL.list = list(yyDollar[1].list, yyDollar[3].node)
+		}
+	case 249:
+		yyDollar = yyS[yypt-0 : yypt+1]
+		//line go.y:1774
+		{
+			yyVAL.list = nil
+		}
+	case 250:
+		yyDollar = yyS[yypt-2 : yypt+1]
+		//line go.y:1778
+		{
+			yyVAL.list = yyDollar[1].list
+		}
+	case 251:
+		yyDollar = yyS[yypt-0 : yypt+1]
+		//line go.y:1786
+		{
+			yyVAL.node = nil
+		}
+	case 253:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:1791
+		{
+			yyVAL.node = liststmt(yyDollar[1].list)
+		}
+	case 255:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:1796
+		{
+			yyVAL.node = nil
+		}
+	case 261:
+		yyDollar = yyS[yypt-2 : yypt+1]
+		//line go.y:1807
+		{
+			yyDollar[1].node = Nod(OLABEL, yyDollar[1].node, nil)
+			yyDollar[1].node.Sym = dclstack // context, for goto restrictions
+		}
+	case 262:
+		yyDollar = yyS[yypt-4 : yypt+1]
+		//line go.y:1812
+		{
+			var l *NodeList
+
+			yyDollar[1].node.Name.Defn = yyDollar[4].node
+			l = list1(yyDollar[1].node)
+			if yyDollar[4].node != nil {
+				l = list(l, yyDollar[4].node)
+			}
+			yyVAL.node = liststmt(l)
+		}
+	case 263:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:1823
+		{
+			// will be converted to OFALL
+			yyVAL.node = Nod(OXFALL, nil, nil)
+			yyVAL.node.Xoffset = int64(block)
+		}
+	case 264:
+		yyDollar = yyS[yypt-2 : yypt+1]
+		//line go.y:1829
+		{
+			yyVAL.node = Nod(OBREAK, yyDollar[2].node, nil)
+		}
+	case 265:
+		yyDollar = yyS[yypt-2 : yypt+1]
+		//line go.y:1833
+		{
+			yyVAL.node = Nod(OCONTINUE, yyDollar[2].node, nil)
+		}
+	case 266:
+		yyDollar = yyS[yypt-2 : yypt+1]
+		//line go.y:1837
+		{
+			yyVAL.node = Nod(OPROC, yyDollar[2].node, nil)
+		}
+	case 267:
+		yyDollar = yyS[yypt-2 : yypt+1]
+		//line go.y:1841
+		{
+			yyVAL.node = Nod(ODEFER, yyDollar[2].node, nil)
+		}
+	case 268:
+		yyDollar = yyS[yypt-2 : yypt+1]
+		//line go.y:1845
+		{
+			yyVAL.node = Nod(OGOTO, yyDollar[2].node, nil)
+			yyVAL.node.Sym = dclstack // context, for goto restrictions
+		}
+	case 269:
+		yyDollar = yyS[yypt-2 : yypt+1]
+		//line go.y:1850
+		{
+			yyVAL.node = Nod(ORETURN, nil, nil)
+			yyVAL.node.List = yyDollar[2].list
+			if yyVAL.node.List == nil && Curfn != nil {
+				var l *NodeList
+
+				for l = Curfn.Func.Dcl; l != nil; l = l.Next {
+					if l.N.Class == PPARAM {
+						continue
+					}
+					if l.N.Class != PPARAMOUT {
+						break
+					}
+					if l.N.Sym.Def != l.N {
+						Yyerror("%s is shadowed during return", l.N.Sym.Name)
+					}
+				}
+			}
+		}
+	case 270:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:1872
+		{
+			yyVAL.list = nil
+			if yyDollar[1].node != nil {
+				yyVAL.list = list1(yyDollar[1].node)
+			}
+		}
+	case 271:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:1879
+		{
+			yyVAL.list = yyDollar[1].list
+			if yyDollar[3].node != nil {
+				yyVAL.list = list(yyVAL.list, yyDollar[3].node)
+			}
+		}
+	case 272:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:1888
+		{
+			yyVAL.list = list1(yyDollar[1].node)
+		}
+	case 273:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:1892
+		{
+			yyVAL.list = list(yyDollar[1].list, yyDollar[3].node)
+		}
+	case 274:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:1898
+		{
+			yyVAL.list = list1(yyDollar[1].node)
+		}
+	case 275:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:1902
+		{
+			yyVAL.list = list(yyDollar[1].list, yyDollar[3].node)
+		}
+	case 276:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:1908
+		{
+			yyVAL.list = list1(yyDollar[1].node)
+		}
+	case 277:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:1912
+		{
+			yyVAL.list = list(yyDollar[1].list, yyDollar[3].node)
+		}
+	case 278:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:1918
+		{
+			yyVAL.list = list1(yyDollar[1].node)
+		}
+	case 279:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:1922
+		{
+			yyVAL.list = list(yyDollar[1].list, yyDollar[3].node)
+		}
+	case 280:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:1931
+		{
+			yyVAL.list = list1(yyDollar[1].node)
+		}
+	case 281:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:1935
+		{
+			yyVAL.list = list1(yyDollar[1].node)
+		}
+	case 282:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:1939
+		{
+			yyVAL.list = list(yyDollar[1].list, yyDollar[3].node)
+		}
+	case 283:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:1943
+		{
+			yyVAL.list = list(yyDollar[1].list, yyDollar[3].node)
+		}
+	case 284:
+		yyDollar = yyS[yypt-0 : yypt+1]
+		//line go.y:1948
+		{
+			yyVAL.list = nil
+		}
+	case 285:
+		yyDollar = yyS[yypt-2 : yypt+1]
+		//line go.y:1952
+		{
+			yyVAL.list = yyDollar[1].list
+		}
+	case 290:
+		yyDollar = yyS[yypt-0 : yypt+1]
+		//line go.y:1966
+		{
+			yyVAL.node = nil
+		}
+	case 292:
+		yyDollar = yyS[yypt-0 : yypt+1]
+		//line go.y:1972
+		{
+			yyVAL.list = nil
+		}
+	case 294:
+		yyDollar = yyS[yypt-0 : yypt+1]
+		//line go.y:1978
+		{
+			yyVAL.node = nil
+		}
+	case 296:
+		yyDollar = yyS[yypt-0 : yypt+1]
+		//line go.y:1984
+		{
+			yyVAL.list = nil
+		}
+	case 298:
+		yyDollar = yyS[yypt-0 : yypt+1]
+		//line go.y:1990
+		{
+			yyVAL.list = nil
+		}
+	case 300:
+		yyDollar = yyS[yypt-0 : yypt+1]
+		//line go.y:1996
+		{
+			yyVAL.list = nil
+		}
+	case 302:
+		yyDollar = yyS[yypt-0 : yypt+1]
+		//line go.y:2002
+		{
+			yyVAL.val.U = nil
+		}
+	case 304:
+		yyDollar = yyS[yypt-4 : yypt+1]
+		//line go.y:2012
+		{
+			importimport(yyDollar[2].sym, yyDollar[3].val.U.(string))
+		}
+	case 305:
+		yyDollar = yyS[yypt-4 : yypt+1]
+		//line go.y:2016
+		{
+			importvar(yyDollar[2].sym, yyDollar[3].typ)
+		}
+	case 306:
+		yyDollar = yyS[yypt-5 : yypt+1]
+		//line go.y:2020
+		{
+			importconst(yyDollar[2].sym, Types[TIDEAL], yyDollar[4].node)
+		}
+	case 307:
+		yyDollar = yyS[yypt-6 : yypt+1]
+		//line go.y:2024
+		{
+			importconst(yyDollar[2].sym, yyDollar[3].typ, yyDollar[5].node)
+		}
+	case 308:
+		yyDollar = yyS[yypt-4 : yypt+1]
+		//line go.y:2028
+		{
+			importtype(yyDollar[2].typ, yyDollar[3].typ)
+		}
+	case 309:
+		yyDollar = yyS[yypt-4 : yypt+1]
+		//line go.y:2032
+		{
+			if yyDollar[2].node == nil {
+				dclcontext = PEXTERN // since we skip the funcbody below
+				break
+			}
+
+			yyDollar[2].node.Func.Inl = yyDollar[3].list
+
+			funcbody(yyDollar[2].node)
+			importlist = list(importlist, yyDollar[2].node)
+
+			if Debug['E'] > 0 {
+				fmt.Printf("import [%q] func %v \n", importpkg.Path, yyDollar[2].node)
+				if Debug['m'] > 2 && yyDollar[2].node.Func.Inl != nil {
+					fmt.Printf("inl body:%v\n", yyDollar[2].node.Func.Inl)
+				}
+			}
+		}
+	case 310:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:2053
+		{
+			yyVAL.sym = yyDollar[1].sym
+			structpkg = yyVAL.sym.Pkg
+		}
+	case 311:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:2060
+		{
+			yyVAL.typ = pkgtype(yyDollar[1].sym)
+			importsym(yyDollar[1].sym, OTYPE)
+		}
+	case 317:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:2080
+		{
+			yyVAL.typ = pkgtype(yyDollar[1].sym)
+		}
+	case 318:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:2084
+		{
+			// predefined name like uint8
+			yyDollar[1].sym = Pkglookup(yyDollar[1].sym.Name, builtinpkg)
+			if yyDollar[1].sym.Def == nil || yyDollar[1].sym.Def.Op != OTYPE {
+				Yyerror("%s is not a type", yyDollar[1].sym.Name)
+				yyVAL.typ = nil
+			} else {
+				yyVAL.typ = yyDollar[1].sym.Def.Type
+			}
+		}
+	case 319:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:2095
+		{
+			yyVAL.typ = aindex(nil, yyDollar[3].typ)
+		}
+	case 320:
+		yyDollar = yyS[yypt-4 : yypt+1]
+		//line go.y:2099
+		{
+			yyVAL.typ = aindex(nodlit(yyDollar[2].val), yyDollar[4].typ)
+		}
+	case 321:
+		yyDollar = yyS[yypt-5 : yypt+1]
+		//line go.y:2103
+		{
+			yyVAL.typ = maptype(yyDollar[3].typ, yyDollar[5].typ)
+		}
+	case 322:
+		yyDollar = yyS[yypt-4 : yypt+1]
+		//line go.y:2107
+		{
+			yyVAL.typ = tostruct(yyDollar[3].list)
+		}
+	case 323:
+		yyDollar = yyS[yypt-4 : yypt+1]
+		//line go.y:2111
+		{
+			yyVAL.typ = tointerface(yyDollar[3].list)
+		}
+	case 324:
+		yyDollar = yyS[yypt-2 : yypt+1]
+		//line go.y:2115
+		{
+			yyVAL.typ = Ptrto(yyDollar[2].typ)
+		}
+	case 325:
+		yyDollar = yyS[yypt-2 : yypt+1]
+		//line go.y:2119
+		{
+			yyVAL.typ = typ(TCHAN)
+			yyVAL.typ.Type = yyDollar[2].typ
+			yyVAL.typ.Chan = Cboth
+		}
+	case 326:
+		yyDollar = yyS[yypt-4 : yypt+1]
+		//line go.y:2125
+		{
+			yyVAL.typ = typ(TCHAN)
+			yyVAL.typ.Type = yyDollar[3].typ
+			yyVAL.typ.Chan = Cboth
+		}
+	case 327:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:2131
+		{
+			yyVAL.typ = typ(TCHAN)
+			yyVAL.typ.Type = yyDollar[3].typ
+			yyVAL.typ.Chan = Csend
+		}
+	case 328:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:2139
+		{
+			yyVAL.typ = typ(TCHAN)
+			yyVAL.typ.Type = yyDollar[3].typ
+			yyVAL.typ.Chan = Crecv
+		}
+	case 329:
+		yyDollar = yyS[yypt-5 : yypt+1]
+		//line go.y:2147
+		{
+			yyVAL.typ = functype(nil, yyDollar[3].list, yyDollar[5].list)
+		}
+	case 330:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:2153
+		{
+			yyVAL.node = Nod(ODCLFIELD, nil, typenod(yyDollar[2].typ))
+			if yyDollar[1].sym != nil {
+				yyVAL.node.Left = newname(yyDollar[1].sym)
+			}
+			yyVAL.node.SetVal(yyDollar[3].val)
+		}
+	case 331:
+		yyDollar = yyS[yypt-4 : yypt+1]
+		//line go.y:2161
+		{
+			var t *Type
+
+			t = typ(TARRAY)
+			t.Bound = -1
+			t.Type = yyDollar[3].typ
+
+			yyVAL.node = Nod(ODCLFIELD, nil, typenod(t))
+			if yyDollar[1].sym != nil {
+				yyVAL.node.Left = newname(yyDollar[1].sym)
+			}
+			yyVAL.node.Isddd = true
+			yyVAL.node.SetVal(yyDollar[4].val)
+		}
+	case 332:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:2178
+		{
+			var s *Sym
+			var p *Pkg
+
+			if yyDollar[1].sym != nil && yyDollar[1].sym.Name != "?" {
+				yyVAL.node = Nod(ODCLFIELD, newname(yyDollar[1].sym), typenod(yyDollar[2].typ))
+				yyVAL.node.SetVal(yyDollar[3].val)
+			} else {
+				s = yyDollar[2].typ.Sym
+				if s == nil && Isptr[yyDollar[2].typ.Etype] {
+					s = yyDollar[2].typ.Type.Sym
+				}
+				p = importpkg
+				if yyDollar[1].sym != nil {
+					p = yyDollar[1].sym.Pkg
+				}
+				yyVAL.node = embedded(s, p)
+				yyVAL.node.Right = typenod(yyDollar[2].typ)
+				yyVAL.node.SetVal(yyDollar[3].val)
+			}
+		}
+	case 333:
+		yyDollar = yyS[yypt-5 : yypt+1]
+		//line go.y:2202
+		{
+			yyVAL.node = Nod(ODCLFIELD, newname(yyDollar[1].sym), typenod(functype(fakethis(), yyDollar[3].list, yyDollar[5].list)))
+		}
+	case 334:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:2206
+		{
+			yyVAL.node = Nod(ODCLFIELD, nil, typenod(yyDollar[1].typ))
+		}
+	case 335:
+		yyDollar = yyS[yypt-0 : yypt+1]
+		//line go.y:2211
+		{
+			yyVAL.list = nil
+		}
+	case 337:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:2218
+		{
+			yyVAL.list = yyDollar[2].list
+		}
+	case 338:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:2222
+		{
+			yyVAL.list = list1(Nod(ODCLFIELD, nil, typenod(yyDollar[1].typ)))
+		}
+	case 339:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:2232
+		{
+			yyVAL.node = nodlit(yyDollar[1].val)
+		}
+	case 340:
+		yyDollar = yyS[yypt-2 : yypt+1]
+		//line go.y:2236
+		{
+			yyVAL.node = nodlit(yyDollar[2].val)
+			switch yyVAL.node.Val().Ctype() {
+			case CTINT, CTRUNE:
+				mpnegfix(yyVAL.node.Val().U.(*Mpint))
+				break
+			case CTFLT:
+				mpnegflt(yyVAL.node.Val().U.(*Mpflt))
+				break
+			case CTCPLX:
+				mpnegflt(&yyVAL.node.Val().U.(*Mpcplx).Real)
+				mpnegflt(&yyVAL.node.Val().U.(*Mpcplx).Imag)
+				break
+			default:
+				Yyerror("bad negated constant")
+			}
+		}
+	case 341:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:2254
+		{
+			yyVAL.node = oldname(Pkglookup(yyDollar[1].sym.Name, builtinpkg))
+			if yyVAL.node.Op != OLITERAL {
+				Yyerror("bad constant %v", yyVAL.node.Sym)
+			}
+		}
+	case 343:
+		yyDollar = yyS[yypt-5 : yypt+1]
+		//line go.y:2264
+		{
+			if yyDollar[2].node.Val().Ctype() == CTRUNE && yyDollar[4].node.Val().Ctype() == CTINT {
+				yyVAL.node = yyDollar[2].node
+				mpaddfixfix(yyDollar[2].node.Val().U.(*Mpint), yyDollar[4].node.Val().U.(*Mpint), 0)
+				break
+			}
+			yyDollar[4].node.Val().U.(*Mpcplx).Real = yyDollar[4].node.Val().U.(*Mpcplx).Imag
+			Mpmovecflt(&yyDollar[4].node.Val().U.(*Mpcplx).Imag, 0.0)
+			yyVAL.node = nodcplxlit(yyDollar[2].node.Val(), yyDollar[4].node.Val())
+		}
+	case 346:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:2280
+		{
+			yyVAL.list = list1(yyDollar[1].node)
+		}
+	case 347:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:2284
+		{
+			yyVAL.list = list(yyDollar[1].list, yyDollar[3].node)
+		}
+	case 348:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:2290
+		{
+			yyVAL.list = list1(yyDollar[1].node)
+		}
+	case 349:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:2294
+		{
+			yyVAL.list = list(yyDollar[1].list, yyDollar[3].node)
+		}
+	case 350:
+		yyDollar = yyS[yypt-1 : yypt+1]
+		//line go.y:2300
+		{
+			yyVAL.list = list1(yyDollar[1].node)
+		}
+	case 351:
+		yyDollar = yyS[yypt-3 : yypt+1]
+		//line go.y:2304
+		{
+			yyVAL.list = list(yyDollar[1].list, yyDollar[3].node)
+		}
+	}
+	goto yystack /* stack new state and value */
+}
diff --git a/src/cmd/compile/internal/ppc64/cgen.go b/src/cmd/compile/internal/ppc64/cgen.go
new file mode 100644
index 0000000..37dd6ce
--- /dev/null
+++ b/src/cmd/compile/internal/ppc64/cgen.go
@@ -0,0 +1,149 @@
+// 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 ppc64
+
+import (
+	"cmd/compile/internal/gc"
+	"cmd/internal/obj"
+	"cmd/internal/obj/ppc64"
+)
+
+func blockcopy(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, n.Type)
+
+	case 1:
+		op = ppc64.AMOVBU
+
+	case 2:
+		op = ppc64.AMOVHU
+
+	case 4:
+		op = ppc64.AMOVWZU // there is no lwau, only lwaux
+
+	case 8:
+		op = ppc64.AMOVDU
+	}
+
+	if w%int64(align) != 0 {
+		gc.Fatal("sgen: unaligned size %d (align=%d) for %v", w, align, n.Type)
+	}
+	c := int32(w / int64(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(ppc64.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(ppc64.AMOVD, &src, &nend)
+		}
+
+		p := gins(ppc64.AADD, nil, &src)
+		p.From.Type = obj.TYPE_CONST
+		p.From.Offset = w
+
+		p = gins(ppc64.AADD, nil, &dst)
+		p.From.Type = obj.TYPE_CONST
+		p.From.Offset = w
+	} else {
+		p := gins(ppc64.AADD, nil, &src)
+		p.From.Type = obj.TYPE_CONST
+		p.From.Offset = int64(-dir)
+
+		p = gins(ppc64.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(ppc64.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)
+		ploop := p
+
+		p = gins(op, &tmp, &dst)
+		p.To.Type = obj.TYPE_MEM
+		p.To.Offset = int64(dir)
+
+		p = gins(ppc64.ACMP, &src, &nend)
+
+		gc.Patch(gc.Gbranch(ppc64.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 = gins(op, &tmp, &dst)
+			p.To.Type = obj.TYPE_MEM
+			p.To.Offset = int64(dir)
+		}
+	}
+
+	gc.Regfree(&dst)
+	gc.Regfree(&src)
+	gc.Regfree(&tmp)
+}
diff --git a/src/cmd/compile/internal/ppc64/galign.go b/src/cmd/compile/internal/ppc64/galign.go
new file mode 100644
index 0000000..73aef6f
--- /dev/null
+++ b/src/cmd/compile/internal/ppc64/galign.go
@@ -0,0 +1,100 @@
+// 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 ppc64
+
+import (
+	"cmd/compile/internal/gc"
+	"cmd/internal/obj"
+	"cmd/internal/obj/ppc64"
+)
+
+var thechar int = '9'
+
+var thestring string = "ppc64"
+
+var thelinkarch *obj.LinkArch
+
+func linkarchinit() {
+	thestring = obj.Getgoarch()
+	gc.Thearch.Thestring = thestring
+	if thestring == "ppc64le" {
+		thelinkarch = &ppc64.Linkppc64le
+	} else {
+		thelinkarch = &ppc64.Linkppc64
+	}
+	gc.Thearch.Thelinkarch = thelinkarch
+}
+
+var MAXWIDTH int64 = 1 << 50
+
+/*
+ * go declares several platform-specific type aliases:
+ * int, uint, 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 = 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.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.Getg = getg
+	gc.Thearch.Gins = gins
+	gc.Thearch.Ginscmp = ginscmp
+	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.Blockcopy = blockcopy
+	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/compile/internal/ppc64/ggen.go b/src/cmd/compile/internal/ppc64/ggen.go
new file mode 100644
index 0000000..5b282eb
--- /dev/null
+++ b/src/cmd/compile/internal/ppc64/ggen.go
@@ -0,0 +1,564 @@
+// 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 ppc64
+
+import (
+	"cmd/compile/internal/gc"
+	"cmd/internal/obj"
+	"cmd/internal/obj/ppc64"
+	"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.Name.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, ppc64.AMOVD, obj.TYPE_REG, ppc64.REGZERO, 0, obj.TYPE_MEM, ppc64.REGSP, 8+frame+lo+i)
+		}
+		// TODO(dfc): https://golang.org/issue/12108
+		// If DUFFZERO is used inside a tail call (see genwrapper) it will
+		// overwrite the link register.
+	} else if false && cnt <= int64(128*gc.Widthptr) {
+		p = appendpp(p, ppc64.AADD, obj.TYPE_CONST, 0, 8+frame+lo-8, obj.TYPE_REG, ppc64.REGRT1, 0)
+		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(&p.To, f)
+		gc.Afunclit(&p.To, f)
+		p.To.Offset = 4 * (128 - cnt/int64(gc.Widthptr))
+	} else {
+		p = appendpp(p, ppc64.AMOVD, obj.TYPE_CONST, 0, 8+frame+lo-8, obj.TYPE_REG, ppc64.REGTMP, 0)
+		p = appendpp(p, ppc64.AADD, obj.TYPE_REG, ppc64.REGTMP, 0, obj.TYPE_REG, ppc64.REGRT1, 0)
+		p.Reg = ppc64.REGSP
+		p = appendpp(p, ppc64.AMOVD, obj.TYPE_CONST, 0, cnt, obj.TYPE_REG, ppc64.REGTMP, 0)
+		p = appendpp(p, ppc64.AADD, obj.TYPE_REG, ppc64.REGTMP, 0, obj.TYPE_REG, ppc64.REGRT2, 0)
+		p.Reg = ppc64.REGRT1
+		p = appendpp(p, ppc64.AMOVDU, obj.TYPE_REG, ppc64.REGZERO, 0, obj.TYPE_MEM, ppc64.REGRT1, int64(gc.Widthptr))
+		p1 := p
+		p = appendpp(p, ppc64.ACMP, obj.TYPE_REG, ppc64.REGRT1, 0, obj.TYPE_REG, ppc64.REGRT2, 0)
+		p = appendpp(p, ppc64.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 reg gc.Node
+	gc.Nodreg(&reg, gc.Types[gc.TINT], ppc64.REG_R0)
+	gins(ppc64.AOR, &reg, &reg)
+}
+
+var panicdiv *gc.Node
+
+/*
+ * 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) && nl.Int() != -(1<<uint64(t.Width*8-1)) {
+			check = 0
+		} else if gc.Isconst(nr, gc.CTINT) && nr.Int() != -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.To.Type = obj.TYPE_REG
+	p1.To.Reg = ppc64.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)
+		gins(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), nil, &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.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(ppc64.ASRAD, 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(ppc64.ASRD, nil, &n1))
+		p.From.Type = obj.TYPE_CONST
+		p.From.Offset = int64(w)
+
+	case gc.TINT64,
+		gc.TUINT64:
+		if gc.Issigned[t.Etype] {
+			gins(ppc64.AMULHD, &n2, &n1)
+		} else {
+			gins(ppc64.AMULHDU, &n2, &n1)
+		}
+
+	default:
+		gc.Fatal("cgen_hmul %v", t)
+	}
+
+	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(nr.Int())
+		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)
+		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] {
+			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", nl, nl.Type, 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 gc.Reginuse(ppc64.REGRT1) {
+		gc.Fatal("%v in use during clearfat", obj.Rconv(ppc64.REGRT1))
+	}
+
+	var r0 gc.Node
+	gc.Nodreg(&r0, gc.Types[gc.TUINT64], ppc64.REGZERO)
+	var dst gc.Node
+	gc.Nodreg(&dst, gc.Types[gc.Tptr], ppc64.REGRT1)
+	gc.Regrealloc(&dst)
+	gc.Agen(nl, &dst)
+
+	var boff uint64
+	if q > 128 {
+		p := gins(ppc64.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(ppc64.AMOVD, &dst, &end)
+		p.From.Type = obj.TYPE_ADDR
+		p.From.Offset = int64(q * 8)
+
+		p = gins(ppc64.AMOVDU, &r0, &dst)
+		p.To.Type = obj.TYPE_MEM
+		p.To.Offset = 8
+		pl := (*obj.Prog)(p)
+
+		p = gins(ppc64.ACMP, &dst, &end)
+		gc.Patch(gc.Gbranch(ppc64.ABNE, nil, 0), pl)
+
+		gc.Regfree(&end)
+
+		// The loop leaves R3 on the last zeroed dword
+		boff = 8
+		// TODO(dfc): https://golang.org/issue/12108
+		// If DUFFZERO is used inside a tail call (see genwrapper) it will
+		// overwrite the link register.
+	} else if false && q >= 4 {
+		p := gins(ppc64.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_ppc64x.s
+		p.To.Offset = int64(4 * (128 - q))
+
+		// 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
+			p.To.Offset = int64(8 * t)
+		}
+
+		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)
+	}
+
+	gc.Regfree(&dst)
+}
+
+// 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
+			//	TD $4, R0, arg (R0 is always zero)
+			// eqv. to:
+			// 	tdeq r0, arg
+			// NOTE: this needs special runtime support to make SIGTRAP recoverable.
+			reg = p->from.reg;
+			p->as = ATD;
+			p->from = p->to = p->from3 = zprog.from;
+			p->from.type = TYPE_CONST;
+			p->from.offset = 4;
+			p->from.reg = 0;
+			p->reg = REGZERO;
+			p->to.type = TYPE_REG;
+			p->to.reg = reg;
+		*/
+		// check is
+		//	CMP arg, R0
+		//	BNE 2(PC) [likely]
+		//	MOVD R0, 0(R0)
+		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 = ppc64.ACMP
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = ppc64.REGZERO
+		p1.As = ppc64.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 = ppc64.AMOVD
+
+		p2.From.Type = obj.TYPE_REG
+		p2.From.Reg = ppc64.REGZERO
+		p2.To.Type = obj.TYPE_MEM
+		p2.To.Reg = ppc64.REGZERO
+		p2.To.Offset = 0
+	}
+}
+
+// res = runtime.getg()
+func getg(res *gc.Node) {
+	var n1 gc.Node
+	gc.Nodreg(&n1, res.Type, ppc64.REGG)
+	gmove(&n1, res)
+}
diff --git a/src/cmd/compile/internal/ppc64/gsubr.go b/src/cmd/compile/internal/ppc64/gsubr.go
new file mode 100644
index 0000000..2501972
--- /dev/null
+++ b/src/cmd/compile/internal/ppc64/gsubr.go
@@ -0,0 +1,1031 @@
+// 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 at 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 at 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 ppc64
+
+import (
+	"cmd/compile/internal/big"
+	"cmd/compile/internal/gc"
+	"cmd/internal/obj"
+	"cmd/internal/obj/ppc64"
+	"fmt"
+)
+
+var resvd = []int{
+	ppc64.REGZERO,
+	ppc64.REGSP, // reserved for SP
+	// We need to preserve the C ABI TLS pointer because sigtramp
+	// may happen during C code and needs to access the g.  C
+	// clobbers REGG, so if Go were to clobber REGTLS, sigtramp
+	// won't know which convention to use.  By preserving REGTLS,
+	// we can just retrieve g from TLS when we aren't sure.
+	ppc64.REGTLS,
+
+	// TODO(austin): Consolidate REGTLS and REGG?
+	ppc64.REGG,
+	ppc64.REGTMP, // REGTMP
+	ppc64.FREGCVI,
+	ppc64.FREGZERO,
+	ppc64.FREGHALF,
+	ppc64.FREGONE,
+	ppc64.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 != 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
+		gc.Regalloc(&ntmp, gc.Types[gc.TINT64], nil)
+
+		rawgins(ppc64.AMOVD, &n1, &ntmp)
+		rawgins(as, &ntmp, n2)
+		gc.Regfree(&ntmp)
+		return
+	}
+
+	rawgins(as, &n1, n2)
+}
+
+/*
+ * generate
+ *	as n, $c (CMP/CMPU)
+ */
+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 ppc64.ACMP:
+		if -ppc64.BIG <= c && c <= ppc64.BIG {
+			rawgins(as, n2, &n1)
+			return
+		}
+
+	case ppc64.ACMPU:
+		if 0 <= c && c <= 2*ppc64.BIG {
+			rawgins(as, n2, &n1)
+			return
+		}
+	}
+
+	// MOV n1 into register first
+	var ntmp gc.Node
+	gc.Regalloc(&ntmp, gc.Types[gc.TINT64], nil)
+
+	rawgins(ppc64.AMOVD, &n1, &ntmp)
+	rawgins(as, n2, &ntmp)
+	gc.Regfree(&ntmp)
+}
+
+func ginscmp(op int, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
+	if gc.Isint[t.Etype] && n1.Op == gc.OLITERAL && n2.Op != gc.OLITERAL {
+		// Reverse comparison to place constant last.
+		op = gc.Brrev(op)
+		n1, n2 = n2, n1
+	}
+
+	var r1, r2, g1, g2 gc.Node
+	gc.Regalloc(&r1, t, n1)
+	gc.Regalloc(&g1, n1.Type, &r1)
+	gc.Cgen(n1, &g1)
+	gmove(&g1, &r1)
+	if gc.Isint[t.Etype] && gc.Isconst(n2, gc.CTINT) {
+		ginscon2(optoas(gc.OCMP, t), &r1, n2.Int())
+	} else {
+		gc.Regalloc(&r2, t, n2)
+		gc.Regalloc(&g2, n1.Type, &r2)
+		gc.Cgen(n2, &g2)
+		gmove(&g2, &r2)
+		rawgins(optoas(gc.OCMP, t), &r1, &r2)
+		gc.Regfree(&g2)
+		gc.Regfree(&r2)
+	}
+	gc.Regfree(&g1)
+	gc.Regfree(&r1)
+	return gc.Gbranch(optoas(op, t), nil, likely)
+}
+
+// set up nodes representing 2^63
+var (
+	bigi         gc.Node
+	bigf         gc.Node
+	bignodes_did bool
+)
+
+func bignodes() {
+	if bignodes_did {
+		return
+	}
+	bignodes_did = true
+
+	var i big.Int
+	i.SetInt64(1)
+	i.Lsh(&i, 63)
+
+	gc.Nodconst(&bigi, gc.Types[gc.TUINT64], 0)
+	bigi.SetBigInt(&i)
+
+	bigi.Convconst(&bigf, gc.Types[gc.TFLOAT64])
+}
+
+/*
+ * 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 r2 gc.Node
+	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:
+			f.Convconst(&con, t.Type)
+
+		case gc.TINT32,
+			gc.TINT16,
+			gc.TINT8:
+			var con gc.Node
+			f.Convconst(&con, gc.Types[gc.TINT64])
+			var r1 gc.Node
+			gc.Regalloc(&r1, con.Type, t)
+			gins(ppc64.AMOVD, &con, &r1)
+			gmove(&r1, t)
+			gc.Regfree(&r1)
+			return
+
+		case gc.TUINT32,
+			gc.TUINT16,
+			gc.TUINT8:
+			var con gc.Node
+			f.Convconst(&con, gc.Types[gc.TUINT64])
+			var r1 gc.Node
+			gc.Regalloc(&r1, con.Type, t)
+			gins(ppc64.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
+		}
+	}
+
+	// float constants come from memory.
+	//if(isfloat[tt])
+	//	goto hard;
+
+	// 64-bit immediates are also from memory.
+	//if(isint[tt])
+	//	goto hard;
+	//// 64-bit immediates are really 32-bit sign-extended
+	//// unless moving into a register.
+	//if(isint[tt]) {
+	//	if(mpcmpfixfix(con.val.u.xval, minintval[TINT32]) < 0)
+	//		goto hard;
+	//	if(mpcmpfixfix(con.val.u.xval, maxintval[TINT32]) > 0)
+	//		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 = ppc64.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 = ppc64.AMOVBZ
+
+	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 = ppc64.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 = ppc64.AMOVHZ
+
+	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 = ppc64.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 = ppc64.AMOVWZ
+
+	case gc.TINT64<<16 | gc.TINT64, // same size
+		gc.TINT64<<16 | gc.TUINT64,
+		gc.TUINT64<<16 | gc.TINT64,
+		gc.TUINT64<<16 | gc.TUINT64:
+		a = ppc64.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 = ppc64.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 = ppc64.AMOVBZ
+
+		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 = ppc64.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 = ppc64.AMOVHZ
+
+		goto rdst
+
+	case gc.TINT32<<16 | gc.TINT64, // sign extend int32
+		gc.TINT32<<16 | gc.TUINT64:
+		a = ppc64.AMOVW
+
+		goto rdst
+
+	case gc.TUINT32<<16 | gc.TINT64, // zero extend uint32
+		gc.TUINT32<<16 | gc.TUINT64:
+		a = ppc64.AMOVWZ
+
+		goto rdst
+
+		//warn("gmove: convert float to int not implemented: %N -> %N\n", f, t);
+	//return;
+	// algorithm is:
+	//	if small enough, use native float64 -> int64 conversion.
+	//	otherwise, subtract 2^63, convert, and add it back.
+	/*
+	* float to integer
+	 */
+	case gc.TFLOAT32<<16 | gc.TINT32,
+		gc.TFLOAT64<<16 | gc.TINT32,
+		gc.TFLOAT32<<16 | gc.TINT64,
+		gc.TFLOAT64<<16 | gc.TINT64,
+		gc.TFLOAT32<<16 | gc.TINT16,
+		gc.TFLOAT32<<16 | gc.TINT8,
+		gc.TFLOAT32<<16 | gc.TUINT16,
+		gc.TFLOAT32<<16 | gc.TUINT8,
+		gc.TFLOAT64<<16 | gc.TINT16,
+		gc.TFLOAT64<<16 | gc.TINT8,
+		gc.TFLOAT64<<16 | gc.TUINT16,
+		gc.TFLOAT64<<16 | gc.TUINT8,
+		gc.TFLOAT32<<16 | gc.TUINT32,
+		gc.TFLOAT64<<16 | gc.TUINT32,
+		gc.TFLOAT32<<16 | gc.TUINT64,
+		gc.TFLOAT64<<16 | gc.TUINT64:
+		bignodes()
+
+		var r1 gc.Node
+		gc.Regalloc(&r1, gc.Types[ft], f)
+		gmove(f, &r1)
+		if tt == gc.TUINT64 {
+			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)
+			gc.Regfree(&r2)
+		}
+
+		gc.Regalloc(&r2, gc.Types[gc.TFLOAT64], nil)
+		var r3 gc.Node
+		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
+		p1.To.Reg = ppc64.REGSP
+		p1.To.Offset = -8
+		p1 = gins(ppc64.AMOVD, nil, &r3)
+		p1.From.Type = obj.TYPE_MEM
+		p1.From.Reg = ppc64.REGSP
+		p1.From.Offset = -8
+		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)
+			gins(ppc64.AMOVD, &bigi, &r1)
+			gins(ppc64.AADD, &r1, &r3)
+			gc.Patch(p1, gc.Pc)
+		}
+
+		gmove(&r3, t)
+		gc.Regfree(&r3)
+		return
+
+		//warn("gmove: convert int to float not implemented: %N -> %N\n", f, t);
+	//return;
+	// algorithm is:
+	//	if small enough, use native int64 -> uint64 conversion.
+	//	otherwise, halve (rounding to odd?), convert, and double.
+	/*
+	 * integer to float
+	 */
+	case gc.TINT32<<16 | gc.TFLOAT32,
+		gc.TINT32<<16 | gc.TFLOAT64,
+		gc.TINT64<<16 | gc.TFLOAT32,
+		gc.TINT64<<16 | gc.TFLOAT64,
+		gc.TINT16<<16 | gc.TFLOAT32,
+		gc.TINT16<<16 | gc.TFLOAT64,
+		gc.TINT8<<16 | gc.TFLOAT32,
+		gc.TINT8<<16 | gc.TFLOAT64,
+		gc.TUINT16<<16 | gc.TFLOAT32,
+		gc.TUINT16<<16 | gc.TFLOAT64,
+		gc.TUINT8<<16 | gc.TFLOAT32,
+		gc.TUINT8<<16 | gc.TFLOAT64,
+		gc.TUINT32<<16 | gc.TFLOAT32,
+		gc.TUINT32<<16 | gc.TFLOAT64,
+		gc.TUINT64<<16 | gc.TFLOAT32,
+		gc.TUINT64<<16 | gc.TFLOAT64:
+		bignodes()
+
+		var r1 gc.Node
+		gc.Regalloc(&r1, gc.Types[gc.TINT64], nil)
+		gmove(f, &r1)
+		if ft == gc.TUINT64 {
+			gc.Nodreg(&r2, gc.Types[gc.TUINT64], ppc64.REGTMP)
+			gmove(&bigi, &r2)
+			gins(ppc64.ACMPU, &r1, &r2)
+			p1 := (*obj.Prog)(gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT64]), nil, +1))
+			p2 := (*obj.Prog)(gins(ppc64.ASRD, nil, &r1))
+			p2.From.Type = obj.TYPE_CONST
+			p2.From.Offset = 1
+			gc.Patch(p1, gc.Pc)
+		}
+
+		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
+		p1.To.Offset = -8
+		p1 = gins(ppc64.AFMOVD, nil, &r2)
+		p1.From.Type = obj.TYPE_MEM
+		p1.From.Reg = ppc64.REGSP
+		p1.From.Offset = -8
+		gins(ppc64.AFCFID, &r2, &r2)
+		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)
+			gins(ppc64.AFMUL, &r1, &r2)
+			gc.Patch(p1, gc.Pc)
+		}
+
+		gmove(&r2, t)
+		gc.Regfree(&r2)
+		return
+
+		/*
+		 * float to float
+		 */
+	case gc.TFLOAT32<<16 | gc.TFLOAT32:
+		a = ppc64.AFMOVS
+
+	case gc.TFLOAT64<<16 | gc.TFLOAT64:
+		a = ppc64.AFMOVD
+
+	case gc.TFLOAT32<<16 | gc.TFLOAT64:
+		a = ppc64.AFMOVS
+		goto rdst
+
+	case gc.TFLOAT64<<16 | gc.TFLOAT32:
+		a = ppc64.AFRSP
+		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) {
+	switch {
+	case n == nil:
+		return
+	case gc.Isconst(n, gc.CTINT):
+		return n.Int(), true
+	case gc.Isconst(n, gc.CTBOOL):
+		return int64(obj.Bool2int(n.Bool())), 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 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 obj.ACALL:
+		if p.To.Type == obj.TYPE_REG && p.To.Reg != ppc64.REG_CTR {
+			// Allow front end to emit CALL REG, and rewrite into MOV REG, CTR; CALL CTR.
+			pp := gc.Prog(as)
+			pp.From = p.From
+			pp.To.Type = obj.TYPE_REG
+			pp.To.Reg = ppc64.REG_CTR
+
+			p.As = ppc64.AMOVD
+			p.From = p.To
+			p.To.Type = obj.TYPE_REG
+			p.To.Reg = ppc64.REG_CTR
+
+			if gc.Debug['g'] != 0 {
+				fmt.Printf("%v\n", p)
+				fmt.Printf("%v\n", pp)
+			}
+
+			return pp
+		}
+
+	// Bad things the front end has done to us. Crash to find call stack.
+	case ppc64.AAND, ppc64.AMULLD:
+		if p.From.Type == obj.TYPE_CONST {
+			gc.Debug['h'] = 1
+			gc.Fatal("bad inst: %v", p)
+		}
+	case ppc64.ACMP, ppc64.ACMPU:
+		if p.From.Type == obj.TYPE_MEM || p.To.Type == obj.TYPE_MEM {
+			gc.Debug['h'] = 1
+			gc.Fatal("bad inst: %v", p)
+		}
+	}
+
+	if gc.Debug['g'] != 0 {
+		fmt.Printf("%v\n", p)
+	}
+
+	w := int32(0)
+	switch as {
+	case ppc64.AMOVB,
+		ppc64.AMOVBU,
+		ppc64.AMOVBZ,
+		ppc64.AMOVBZU:
+		w = 1
+
+	case ppc64.AMOVH,
+		ppc64.AMOVHU,
+		ppc64.AMOVHZ,
+		ppc64.AMOVHZU:
+		w = 2
+
+	case ppc64.AMOVW,
+		ppc64.AMOVWU,
+		ppc64.AMOVWZ,
+		ppc64.AMOVWZU:
+		w = 4
+
+	case ppc64.AMOVD,
+		ppc64.AMOVDU:
+		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
+}
+
+/*
+ * 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), t)
+
+	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 = ppc64.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 = ppc64.ABNE
+
+	case gc.OLT<<16 | gc.TINT8, // ACMP
+		gc.OLT<<16 | gc.TINT16,
+		gc.OLT<<16 | gc.TINT32,
+		gc.OLT<<16 | gc.TINT64,
+		gc.OLT<<16 | gc.TUINT8,
+		// ACMPU
+		gc.OLT<<16 | gc.TUINT16,
+		gc.OLT<<16 | gc.TUINT32,
+		gc.OLT<<16 | gc.TUINT64,
+		gc.OLT<<16 | gc.TFLOAT32,
+		// AFCMPU
+		gc.OLT<<16 | gc.TFLOAT64:
+		a = ppc64.ABLT
+
+	case gc.OLE<<16 | gc.TINT8, // ACMP
+		gc.OLE<<16 | gc.TINT16,
+		gc.OLE<<16 | gc.TINT32,
+		gc.OLE<<16 | gc.TINT64,
+		gc.OLE<<16 | gc.TUINT8,
+		// ACMPU
+		gc.OLE<<16 | gc.TUINT16,
+		gc.OLE<<16 | gc.TUINT32,
+		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,
+		gc.OGT<<16 | gc.TINT16,
+		gc.OGT<<16 | gc.TINT32,
+		gc.OGT<<16 | gc.TINT64,
+		gc.OGT<<16 | gc.TUINT8,
+		gc.OGT<<16 | gc.TUINT16,
+		gc.OGT<<16 | gc.TUINT32,
+		gc.OGT<<16 | gc.TUINT64,
+		gc.OGT<<16 | gc.TFLOAT32,
+		gc.OGT<<16 | gc.TFLOAT64:
+		a = ppc64.ABGT
+
+	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.TUINT8,
+		gc.OGE<<16 | gc.TUINT16,
+		gc.OGE<<16 | gc.TUINT32,
+		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,
+		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:
+		a = ppc64.ACMP
+
+	case 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 = ppc64.ACMPU
+
+	case gc.OCMP<<16 | gc.TFLOAT32,
+		gc.OCMP<<16 | gc.TFLOAT64:
+		a = ppc64.AFCMPU
+
+	case gc.OAS<<16 | gc.TBOOL,
+		gc.OAS<<16 | gc.TINT8:
+		a = ppc64.AMOVB
+
+	case gc.OAS<<16 | gc.TUINT8:
+		a = ppc64.AMOVBZ
+
+	case gc.OAS<<16 | gc.TINT16:
+		a = ppc64.AMOVH
+
+	case gc.OAS<<16 | gc.TUINT16:
+		a = ppc64.AMOVHZ
+
+	case gc.OAS<<16 | gc.TINT32:
+		a = ppc64.AMOVW
+
+	case gc.OAS<<16 | gc.TUINT32,
+		gc.OAS<<16 | gc.TPTR32:
+		a = ppc64.AMOVWZ
+
+	case gc.OAS<<16 | gc.TINT64,
+		gc.OAS<<16 | gc.TUINT64,
+		gc.OAS<<16 | gc.TPTR64:
+		a = ppc64.AMOVD
+
+	case gc.OAS<<16 | gc.TFLOAT32:
+		a = ppc64.AFMOVS
+
+	case gc.OAS<<16 | gc.TFLOAT64:
+		a = ppc64.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 = ppc64.AADD
+
+	case gc.OADD<<16 | gc.TFLOAT32:
+		a = ppc64.AFADDS
+
+	case gc.OADD<<16 | gc.TFLOAT64:
+		a = ppc64.AFADD
+
+	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 = ppc64.ASUB
+
+	case gc.OSUB<<16 | gc.TFLOAT32:
+		a = ppc64.AFSUBS
+
+	case gc.OSUB<<16 | gc.TFLOAT64:
+		a = ppc64.AFSUB
+
+	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 = ppc64.ANEG
+
+	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 = ppc64.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 = ppc64.AOR
+
+	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 = ppc64.AXOR
+
+		// 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 = ppc64.ASLD
+
+	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 = ppc64.ASRD
+
+	case gc.ORSH<<16 | gc.TINT8,
+		gc.ORSH<<16 | gc.TINT16,
+		gc.ORSH<<16 | gc.TINT32,
+		gc.ORSH<<16 | gc.TINT64:
+		a = ppc64.ASRAD
+
+		// 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 = ppc64.AMULHD
+
+	case gc.OHMUL<<16 | gc.TUINT64,
+		gc.OHMUL<<16 | gc.TPTR64:
+		a = ppc64.AMULHDU
+
+	case gc.OMUL<<16 | gc.TINT8,
+		gc.OMUL<<16 | gc.TINT16,
+		gc.OMUL<<16 | gc.TINT32,
+		gc.OMUL<<16 | gc.TINT64:
+		a = ppc64.AMULLD
+
+	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.
+		gc.OMUL<<16 | gc.TUINT64,
+		gc.OMUL<<16 | gc.TPTR64:
+		// for 64-bit multiplies, signedness doesn't matter.
+		a = ppc64.AMULLD
+
+	case gc.OMUL<<16 | gc.TFLOAT32:
+		a = ppc64.AFMULS
+
+	case gc.OMUL<<16 | gc.TFLOAT64:
+		a = ppc64.AFMUL
+
+	case gc.ODIV<<16 | gc.TINT8,
+		gc.ODIV<<16 | gc.TINT16,
+		gc.ODIV<<16 | gc.TINT32,
+		gc.ODIV<<16 | gc.TINT64:
+		a = ppc64.ADIVD
+
+	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 = ppc64.ADIVDU
+
+	case gc.ODIV<<16 | gc.TFLOAT32:
+		a = ppc64.AFDIVS
+
+	case gc.ODIV<<16 | gc.TFLOAT64:
+		a = ppc64.AFDIV
+	}
+
+	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/compile/internal/ppc64/opt.go b/src/cmd/compile/internal/ppc64/opt.go
new file mode 100644
index 0000000..1704f63
--- /dev/null
+++ b/src/cmd/compile/internal/ppc64/opt.go
@@ -0,0 +1,12 @@
+// 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 ppc64
+
+// Many Power ISA arithmetic and logical instructions come in four
+// standard variants.  These bits let us map between variants.
+const (
+	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/compile/internal/ppc64/peep.go b/src/cmd/compile/internal/ppc64/peep.go
new file mode 100644
index 0000000..9c3f1ed
--- /dev/null
+++ b/src/cmd/compile/internal/ppc64/peep.go
@@ -0,0 +1,1051 @@
+// 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 at 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 at 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 ppc64
+
+import (
+	"cmd/compile/internal/gc"
+	"cmd/internal/obj"
+	"cmd/internal/obj/ppc64"
+	"fmt"
+)
+
+var gactive uint32
+
+func peep(firstp *obj.Prog) {
+	g := (*gc.Graph)(gc.Flowstart(firstp, nil))
+	if g == nil {
+		return
+	}
+	gactive = 0
+
+	var p *obj.Prog
+	var r *gc.Flow
+	var t int
+loop1:
+	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
+		gc.Dumpit("loop1", g.Start, 0)
+	}
+
+	t = 0
+	for r = g.Start; r != nil; r = r.Link {
+		p = r.Prog
+
+		// TODO(austin) Handle smaller moves.  arm and amd64
+		// distinguish between moves that moves that *must*
+		// sign/zero extend and moves that don't care so they
+		// can eliminate moves that don't care without
+		// breaking moves that do care.  This might let us
+		// simplify or remove the next peep loop, too.
+		if p.As == ppc64.AMOVD || p.As == ppc64.AFMOVD {
+			if regtyp(&p.To) {
+				// Try to eliminate reg->reg moves
+				if regtyp(&p.From) {
+					if p.From.Type == p.To.Type {
+						if copyprop(r) {
+							excise(r)
+							t++
+						} else if subprop(r) && copyprop(r) {
+							excise(r)
+							t++
+						}
+					}
+				}
+
+				// Convert uses to $0 to uses of R0 and
+				// propagate R0
+				if regzer(&p.From) != 0 {
+					if p.To.Type == obj.TYPE_REG {
+						p.From.Type = obj.TYPE_REG
+						p.From.Reg = ppc64.REGZERO
+						if copyprop(r) {
+							excise(r)
+							t++
+						} else if subprop(r) && copyprop(r) {
+							excise(r)
+							t++
+						}
+					}
+				}
+			}
+		}
+	}
+
+	if t != 0 {
+		goto loop1
+	}
+
+	/*
+	 * look for MOVB x,R; MOVB R,R (for small MOVs not handled above)
+	 */
+	var p1 *obj.Prog
+	var r1 *gc.Flow
+	for r := (*gc.Flow)(g.Start); r != nil; r = r.Link {
+		p = r.Prog
+		switch p.As {
+		default:
+			continue
+
+		case ppc64.AMOVH,
+			ppc64.AMOVHZ,
+			ppc64.AMOVB,
+			ppc64.AMOVBZ,
+			ppc64.AMOVW,
+			ppc64.AMOVWZ:
+			if p.To.Type != obj.TYPE_REG {
+				continue
+			}
+		}
+
+		r1 = r.Link
+		if r1 == nil {
+			continue
+		}
+		p1 = r1.Prog
+		if p1.As != p.As {
+			continue
+		}
+		if p1.From.Type != obj.TYPE_REG || p1.From.Reg != p.To.Reg {
+			continue
+		}
+		if p1.To.Type != obj.TYPE_REG || p1.To.Reg != p.To.Reg {
+			continue
+		}
+		excise(r1)
+	}
+
+	if gc.Debug['D'] > 1 {
+		goto ret /* allow following code improvement to be suppressed */
+	}
+
+	/*
+	 * look for OP x,y,R; CMP R, $0 -> OPCC x,y,R
+	 * when OP can set condition codes correctly
+	 */
+	for r := (*gc.Flow)(g.Start); r != nil; r = r.Link {
+		p = r.Prog
+		switch p.As {
+		case ppc64.ACMP,
+			ppc64.ACMPW: /* always safe? */
+			if regzer(&p.To) == 0 {
+				continue
+			}
+			r1 = r.S1
+			if r1 == nil {
+				continue
+			}
+			switch r1.Prog.As {
+			default:
+				continue
+
+				/* the conditions can be complex and these are currently little used */
+			case ppc64.ABCL,
+				ppc64.ABC:
+				continue
+
+			case ppc64.ABEQ,
+				ppc64.ABGE,
+				ppc64.ABGT,
+				ppc64.ABLE,
+				ppc64.ABLT,
+				ppc64.ABNE,
+				ppc64.ABVC,
+				ppc64.ABVS:
+				break
+			}
+
+			r1 = r
+			for {
+				r1 = gc.Uniqp(r1)
+				if r1 == nil || r1.Prog.As != obj.ANOP {
+					break
+				}
+			}
+
+			if r1 == nil {
+				continue
+			}
+			p1 = r1.Prog
+			if p1.To.Type != obj.TYPE_REG || p1.To.Reg != p.From.Reg {
+				continue
+			}
+			switch p1.As {
+			/* irregular instructions */
+			case ppc64.ASUB,
+				ppc64.AADD,
+				ppc64.AXOR,
+				ppc64.AOR:
+				if p1.From.Type == obj.TYPE_CONST || p1.From.Type == obj.TYPE_ADDR {
+					continue
+				}
+			}
+
+			switch p1.As {
+			default:
+				continue
+
+			case ppc64.AMOVW,
+				ppc64.AMOVD:
+				if p1.From.Type != obj.TYPE_REG {
+					continue
+				}
+				continue
+
+			case ppc64.AANDCC,
+				ppc64.AANDNCC,
+				ppc64.AORCC,
+				ppc64.AORNCC,
+				ppc64.AXORCC,
+				ppc64.ASUBCC,
+				ppc64.ASUBECC,
+				ppc64.ASUBMECC,
+				ppc64.ASUBZECC,
+				ppc64.AADDCC,
+				ppc64.AADDCCC,
+				ppc64.AADDECC,
+				ppc64.AADDMECC,
+				ppc64.AADDZECC,
+				ppc64.ARLWMICC,
+				ppc64.ARLWNMCC,
+				/* don't deal with floating point instructions for now */
+				/*
+					case AFABS:
+					case AFADD:
+					case AFADDS:
+					case AFCTIW:
+					case AFCTIWZ:
+					case AFDIV:
+					case AFDIVS:
+					case AFMADD:
+					case AFMADDS:
+					case AFMOVD:
+					case AFMSUB:
+					case AFMSUBS:
+					case AFMUL:
+					case AFMULS:
+					case AFNABS:
+					case AFNEG:
+					case AFNMADD:
+					case AFNMADDS:
+					case AFNMSUB:
+					case AFNMSUBS:
+					case AFRSP:
+					case AFSUB:
+					case AFSUBS:
+					case ACNTLZW:
+					case AMTFSB0:
+					case AMTFSB1:
+				*/
+				ppc64.AADD,
+				ppc64.AADDV,
+				ppc64.AADDC,
+				ppc64.AADDCV,
+				ppc64.AADDME,
+				ppc64.AADDMEV,
+				ppc64.AADDE,
+				ppc64.AADDEV,
+				ppc64.AADDZE,
+				ppc64.AADDZEV,
+				ppc64.AAND,
+				ppc64.AANDN,
+				ppc64.ADIVW,
+				ppc64.ADIVWV,
+				ppc64.ADIVWU,
+				ppc64.ADIVWUV,
+				ppc64.ADIVD,
+				ppc64.ADIVDV,
+				ppc64.ADIVDU,
+				ppc64.ADIVDUV,
+				ppc64.AEQV,
+				ppc64.AEXTSB,
+				ppc64.AEXTSH,
+				ppc64.AEXTSW,
+				ppc64.AMULHW,
+				ppc64.AMULHWU,
+				ppc64.AMULLW,
+				ppc64.AMULLWV,
+				ppc64.AMULHD,
+				ppc64.AMULHDU,
+				ppc64.AMULLD,
+				ppc64.AMULLDV,
+				ppc64.ANAND,
+				ppc64.ANEG,
+				ppc64.ANEGV,
+				ppc64.ANOR,
+				ppc64.AOR,
+				ppc64.AORN,
+				ppc64.AREM,
+				ppc64.AREMV,
+				ppc64.AREMU,
+				ppc64.AREMUV,
+				ppc64.AREMD,
+				ppc64.AREMDV,
+				ppc64.AREMDU,
+				ppc64.AREMDUV,
+				ppc64.ARLWMI,
+				ppc64.ARLWNM,
+				ppc64.ASLW,
+				ppc64.ASRAW,
+				ppc64.ASRW,
+				ppc64.ASLD,
+				ppc64.ASRAD,
+				ppc64.ASRD,
+				ppc64.ASUB,
+				ppc64.ASUBV,
+				ppc64.ASUBC,
+				ppc64.ASUBCV,
+				ppc64.ASUBME,
+				ppc64.ASUBMEV,
+				ppc64.ASUBE,
+				ppc64.ASUBEV,
+				ppc64.ASUBZE,
+				ppc64.ASUBZEV,
+				ppc64.AXOR:
+				t = variant2as(int(p1.As), as2variant(int(p1.As))|V_CC)
+			}
+
+			if gc.Debug['D'] != 0 {
+				fmt.Printf("cmp %v; %v -> ", p1, p)
+			}
+			p1.As = int16(t)
+			if gc.Debug['D'] != 0 {
+				fmt.Printf("%v\n", p1)
+			}
+			excise(r)
+			continue
+		}
+	}
+
+ret:
+	gc.Flowend(g)
+}
+
+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++
+}
+
+/*
+ * regzer returns 1 if a's value is 0 (a is R0 or $0)
+ */
+func regzer(a *obj.Addr) int {
+	if a.Type == obj.TYPE_CONST || a.Type == obj.TYPE_ADDR {
+		if a.Sym == nil && a.Reg == 0 {
+			if a.Offset == 0 {
+				return 1
+			}
+		}
+	}
+	if a.Type == obj.TYPE_REG {
+		if a.Reg == ppc64.REGZERO {
+			return 1
+		}
+	}
+	return 0
+}
+
+func regtyp(a *obj.Addr) bool {
+	// TODO(rsc): Floating point register exclusions?
+	return a.Type == obj.TYPE_REG && ppc64.REG_R0 <= a.Reg && a.Reg <= ppc64.REG_F31 && a.Reg != ppc64.REGZERO
+}
+
+/*
+ * the idea is to substitute
+ * one register for another
+ * from one MOV to another
+ *	MOV	a, R1
+ *	ADD	b, R1	/ no use of R2
+ *	MOV	R1, R2
+ * would be converted to
+ *	MOV	a, R2
+ *	ADD	b, R2
+ *	MOV	R2, R1
+ * hopefully, then the former or latter MOV
+ * will be eliminated by copy propagation.
+ *
+ * r0 (the argument, not the register) is the MOV at the end of the
+ * above sequences.  This returns 1 if it modified any instructions.
+ */
+func subprop(r0 *gc.Flow) bool {
+	p := (*obj.Prog)(r0.Prog)
+	v1 := (*obj.Addr)(&p.From)
+	if !regtyp(v1) {
+		return false
+	}
+	v2 := (*obj.Addr)(&p.To)
+	if !regtyp(v2) {
+		return false
+	}
+	for r := gc.Uniqp(r0); r != nil; r = gc.Uniqp(r) {
+		if gc.Uniqs(r) == nil {
+			break
+		}
+		p = r.Prog
+		if p.As == obj.AVARDEF || p.As == obj.AVARKILL {
+			continue
+		}
+		if p.Info.Flags&gc.Call != 0 {
+			return false
+		}
+
+		if p.Info.Flags&(gc.RightRead|gc.RightWrite) == gc.RightWrite {
+			if p.To.Type == v1.Type {
+				if 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 {
+							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
+				}
+			}
+		}
+
+		if copyau(&p.From, v2) || copyau1(p, v2) || copyau(&p.To, v2) {
+			break
+		}
+		if copysub(&p.From, v1, v2, 0) != 0 || copysub1(p, v1, v2, 0) != 0 || copysub(&p.To, v1, v2, 0) != 0 {
+			break
+		}
+	}
+
+	return false
+}
+
+/*
+ * The idea is to remove redundant copies.
+ *	v1->v2	F=0
+ *	(use v2	s/v2/v1/)*
+ *	set v1	F=1
+ *	use v2	return fail (v1->v2 move must remain)
+ *	-----------------
+ *	v1->v2	F=0
+ *	(use v2	s/v2/v1/)*
+ *	set v1	F=1
+ *	set v2	return success (caller can remove v1->v2 move)
+ */
+func copyprop(r0 *gc.Flow) bool {
+	p := (*obj.Prog)(r0.Prog)
+	v1 := (*obj.Addr)(&p.From)
+	v2 := (*obj.Addr)(&p.To)
+	if copyas(v1, v2) {
+		if gc.Debug['P'] != 0 {
+			fmt.Printf("eliminating self-move: %v\n", r0.Prog)
+		}
+		return true
+	}
+
+	gactive++
+	if gc.Debug['P'] != 0 {
+		fmt.Printf("trying to eliminate %v->%v move from:\n%v\n", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), r0.Prog)
+	}
+	return copy1(v1, v2, r0.S1, 0)
+}
+
+// copy1 replaces uses of v2 with v1 starting at r and returns 1 if
+// all uses were rewritten.
+func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool {
+	if uint32(r.Active) == gactive {
+		if gc.Debug['P'] != 0 {
+			fmt.Printf("act set; return 1\n")
+		}
+		return true
+	}
+
+	r.Active = int32(gactive)
+	if gc.Debug['P'] != 0 {
+		fmt.Printf("copy1 replace %v with %v f=%d\n", gc.Ctxt.Dconv(v2), gc.Ctxt.Dconv(v1), f)
+	}
+	var t int
+	var p *obj.Prog
+	for ; r != nil; r = r.S1 {
+		p = r.Prog
+		if gc.Debug['P'] != 0 {
+			fmt.Printf("%v", p)
+		}
+		if f == 0 && gc.Uniqp(r) == nil {
+			// Multiple predecessors; conservatively
+			// assume v1 was set on other path
+			f = 1
+
+			if gc.Debug['P'] != 0 {
+				fmt.Printf("; merge; f=%d", f)
+			}
+		}
+
+		t = copyu(p, v2, nil)
+		switch t {
+		case 2: /* rar, can't split */
+			if gc.Debug['P'] != 0 {
+				fmt.Printf("; %v rar; return 0\n", gc.Ctxt.Dconv(v2))
+			}
+			return false
+
+		case 3: /* set */
+			if gc.Debug['P'] != 0 {
+				fmt.Printf("; %v set; return 1\n", gc.Ctxt.Dconv(v2))
+			}
+			return true
+
+		case 1, /* used, substitute */
+			4: /* use and set */
+			if f != 0 {
+				if gc.Debug['P'] == 0 {
+					return false
+				}
+				if t == 4 {
+					fmt.Printf("; %v used+set and f=%d; return 0\n", gc.Ctxt.Dconv(v2), f)
+				} else {
+					fmt.Printf("; %v used and f=%d; return 0\n", gc.Ctxt.Dconv(v2), f)
+				}
+				return false
+			}
+
+			if copyu(p, v2, v1) != 0 {
+				if gc.Debug['P'] != 0 {
+					fmt.Printf("; sub fail; return 0\n")
+				}
+				return false
+			}
+
+			if gc.Debug['P'] != 0 {
+				fmt.Printf("; sub %v->%v\n => %v", gc.Ctxt.Dconv(v2), gc.Ctxt.Dconv(v1), p)
+			}
+			if t == 4 {
+				if gc.Debug['P'] != 0 {
+					fmt.Printf("; %v used+set; return 1\n", gc.Ctxt.Dconv(v2))
+				}
+				return true
+			}
+		}
+
+		if f == 0 {
+			t = copyu(p, v1, nil)
+			if f == 0 && (t == 2 || t == 3 || t == 4) {
+				f = 1
+				if gc.Debug['P'] != 0 {
+					fmt.Printf("; %v set and !f; f=%d", gc.Ctxt.Dconv(v1), f)
+				}
+			}
+		}
+
+		if gc.Debug['P'] != 0 {
+			fmt.Printf("\n")
+		}
+		if r.S2 != nil {
+			if !copy1(v1, v2, r.S2, f) {
+				return false
+			}
+		}
+	}
+
+	return true
+}
+
+// If s==nil, copyu returns the set/use of v in p; otherwise, it
+// modifies p to replace reads of v with reads of s and returns 0 for
+// success or non-zero for failure.
+//
+// If s==nil, copy returns one of the following values:
+// 	1 if v only used
+//	2 if v is set and used in one address (read-alter-rewrite;
+// 	  can't substitute)
+//	3 if v is only set
+//	4 if v is set in one address and used in another (so addresses
+// 	  can be rewritten independently)
+//	0 otherwise (not touched)
+func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
+	if p.From3Type() != obj.TYPE_NONE {
+		// 9g never generates a from3
+		fmt.Printf("copyu: from3 (%v) not implemented\n", gc.Ctxt.Dconv(p.From3))
+	}
+
+	switch p.As {
+	default:
+		fmt.Printf("copyu: can't find %v\n", obj.Aconv(int(p.As)))
+		return 2
+
+	case obj.ANOP, /* read p->from, write p->to */
+		ppc64.AMOVH,
+		ppc64.AMOVHZ,
+		ppc64.AMOVB,
+		ppc64.AMOVBZ,
+		ppc64.AMOVW,
+		ppc64.AMOVWZ,
+		ppc64.AMOVD,
+		ppc64.ANEG,
+		ppc64.ANEGCC,
+		ppc64.AADDME,
+		ppc64.AADDMECC,
+		ppc64.AADDZE,
+		ppc64.AADDZECC,
+		ppc64.ASUBME,
+		ppc64.ASUBMECC,
+		ppc64.ASUBZE,
+		ppc64.ASUBZECC,
+		ppc64.AFCTIW,
+		ppc64.AFCTIWZ,
+		ppc64.AFCTID,
+		ppc64.AFCTIDZ,
+		ppc64.AFCFID,
+		ppc64.AFCFIDCC,
+		ppc64.AFMOVS,
+		ppc64.AFMOVD,
+		ppc64.AFRSP,
+		ppc64.AFNEG,
+		ppc64.AFNEGCC:
+		if s != nil {
+			if copysub(&p.From, v, s, 1) != 0 {
+				return 1
+			}
+
+			// Update only indirect uses of v in p->to
+			if !copyas(&p.To, v) {
+				if copysub(&p.To, v, s, 1) != 0 {
+					return 1
+				}
+			}
+			return 0
+		}
+
+		if copyas(&p.To, v) {
+			// Fix up implicit from
+			if p.From.Type == obj.TYPE_NONE {
+				p.From = p.To
+			}
+			if copyau(&p.From, v) {
+				return 4
+			}
+			return 3
+		}
+
+		if copyau(&p.From, v) {
+			return 1
+		}
+		if copyau(&p.To, v) {
+			// p->to only indirectly uses v
+			return 1
+		}
+
+		return 0
+
+	case ppc64.AMOVBU, /* rar p->from, write p->to or read p->from, rar p->to */
+		ppc64.AMOVBZU,
+		ppc64.AMOVHU,
+		ppc64.AMOVHZU,
+		ppc64.AMOVWZU,
+		ppc64.AMOVDU:
+		if p.From.Type == obj.TYPE_MEM {
+			if copyas(&p.From, v) {
+				// No s!=nil check; need to fail
+				// anyway in that case
+				return 2
+			}
+
+			if s != nil {
+				if copysub(&p.To, v, s, 1) != 0 {
+					return 1
+				}
+				return 0
+			}
+
+			if copyas(&p.To, v) {
+				return 3
+			}
+		} else if p.To.Type == obj.TYPE_MEM {
+			if copyas(&p.To, v) {
+				return 2
+			}
+			if s != nil {
+				if copysub(&p.From, v, s, 1) != 0 {
+					return 1
+				}
+				return 0
+			}
+
+			if copyau(&p.From, v) {
+				return 1
+			}
+		} else {
+			fmt.Printf("copyu: bad %v\n", p)
+		}
+
+		return 0
+
+	case ppc64.ARLWMI, /* read p->from, read p->reg, rar p->to */
+		ppc64.ARLWMICC:
+		if copyas(&p.To, v) {
+			return 2
+		}
+		fallthrough
+
+		/* fall through */
+	case ppc64.AADD,
+		/* read p->from, read p->reg, write p->to */
+		ppc64.AADDC,
+		ppc64.AADDE,
+		ppc64.ASUB,
+		ppc64.ASLW,
+		ppc64.ASRW,
+		ppc64.ASRAW,
+		ppc64.ASLD,
+		ppc64.ASRD,
+		ppc64.ASRAD,
+		ppc64.AOR,
+		ppc64.AORCC,
+		ppc64.AORN,
+		ppc64.AORNCC,
+		ppc64.AAND,
+		ppc64.AANDCC,
+		ppc64.AANDN,
+		ppc64.AANDNCC,
+		ppc64.ANAND,
+		ppc64.ANANDCC,
+		ppc64.ANOR,
+		ppc64.ANORCC,
+		ppc64.AXOR,
+		ppc64.AMULHW,
+		ppc64.AMULHWU,
+		ppc64.AMULLW,
+		ppc64.AMULLD,
+		ppc64.ADIVW,
+		ppc64.ADIVD,
+		ppc64.ADIVWU,
+		ppc64.ADIVDU,
+		ppc64.AREM,
+		ppc64.AREMU,
+		ppc64.AREMD,
+		ppc64.AREMDU,
+		ppc64.ARLWNM,
+		ppc64.ARLWNMCC,
+		ppc64.AFADDS,
+		ppc64.AFADD,
+		ppc64.AFSUBS,
+		ppc64.AFSUB,
+		ppc64.AFMULS,
+		ppc64.AFMUL,
+		ppc64.AFDIVS,
+		ppc64.AFDIV:
+		if s != nil {
+			if copysub(&p.From, v, s, 1) != 0 {
+				return 1
+			}
+			if copysub1(p, v, s, 1) != 0 {
+				return 1
+			}
+
+			// Update only indirect uses of v in p->to
+			if !copyas(&p.To, v) {
+				if copysub(&p.To, v, s, 1) != 0 {
+					return 1
+				}
+			}
+			return 0
+		}
+
+		if copyas(&p.To, v) {
+			if p.Reg == 0 {
+				// Fix up implicit reg (e.g., ADD
+				// R3,R4 -> ADD R3,R4,R4) so we can
+				// update reg and to separately.
+				p.Reg = p.To.Reg
+			}
+
+			if copyau(&p.From, v) {
+				return 4
+			}
+			if copyau1(p, v) {
+				return 4
+			}
+			return 3
+		}
+
+		if copyau(&p.From, v) {
+			return 1
+		}
+		if copyau1(p, v) {
+			return 1
+		}
+		if copyau(&p.To, v) {
+			return 1
+		}
+		return 0
+
+	case ppc64.ABEQ,
+		ppc64.ABGT,
+		ppc64.ABGE,
+		ppc64.ABLT,
+		ppc64.ABLE,
+		ppc64.ABNE,
+		ppc64.ABVC,
+		ppc64.ABVS:
+		return 0
+
+	case obj.ACHECKNIL, /* read p->from */
+		ppc64.ACMP, /* read p->from, read p->to */
+		ppc64.ACMPU,
+		ppc64.ACMPW,
+		ppc64.ACMPWU,
+		ppc64.AFCMPO,
+		ppc64.AFCMPU:
+		if s != nil {
+			if copysub(&p.From, v, s, 1) != 0 {
+				return 1
+			}
+			return copysub(&p.To, v, s, 1)
+		}
+
+		if copyau(&p.From, v) {
+			return 1
+		}
+		if copyau(&p.To, v) {
+			return 1
+		}
+		return 0
+
+		// 9g never generates a branch to a GPR (this isn't
+	// even a normal instruction; liblink turns it in to a
+	// mov and a branch).
+	case ppc64.ABR: /* read p->to */
+		if s != nil {
+			if copysub(&p.To, v, s, 1) != 0 {
+				return 1
+			}
+			return 0
+		}
+
+		if copyau(&p.To, v) {
+			return 1
+		}
+		return 0
+
+	case obj.ARET: /* funny */
+		if s != nil {
+			return 0
+		}
+
+		// All registers die at this point, so claim
+		// everything is set (and not used).
+		return 3
+
+	case ppc64.ABL: /* funny */
+		if v.Type == obj.TYPE_REG {
+			// TODO(rsc): REG_R0 and REG_F0 used to be
+			// (when register numbers started at 0) exregoffset and exfregoffset,
+			// which are unset entirely.
+			// It's strange that this handles R0 and F0 differently from the other
+			// registers. Possible failure to optimize?
+			if ppc64.REG_R0 < v.Reg && v.Reg <= ppc64.REGEXT {
+				return 2
+			}
+			if v.Reg == ppc64.REGARG {
+				return 2
+			}
+			if ppc64.REG_F0 < v.Reg && v.Reg <= ppc64.FREGEXT {
+				return 2
+			}
+		}
+
+		if p.From.Type == obj.TYPE_REG && v.Type == obj.TYPE_REG && p.From.Reg == v.Reg {
+			return 2
+		}
+
+		if s != nil {
+			if copysub(&p.To, v, s, 1) != 0 {
+				return 1
+			}
+			return 0
+		}
+
+		if copyau(&p.To, v) {
+			return 4
+		}
+		return 3
+
+		// R0 is zero, used by DUFFZERO, cannot be substituted.
+	// R3 is ptr to memory, used and set, cannot be substituted.
+	case obj.ADUFFZERO:
+		if v.Type == obj.TYPE_REG {
+			if v.Reg == 0 {
+				return 1
+			}
+			if v.Reg == 3 {
+				return 2
+			}
+		}
+
+		return 0
+
+		// R3, R4 are ptr to src, dst, used and set, cannot be substituted.
+	// R5 is scratch, set by DUFFCOPY, cannot be substituted.
+	case obj.ADUFFCOPY:
+		if v.Type == obj.TYPE_REG {
+			if v.Reg == 3 || v.Reg == 4 {
+				return 2
+			}
+			if v.Reg == 5 {
+				return 3
+			}
+		}
+
+		return 0
+
+	case obj.ATEXT: /* funny */
+		if v.Type == obj.TYPE_REG {
+			if v.Reg == ppc64.REGARG {
+				return 3
+			}
+		}
+		return 0
+
+	case obj.APCDATA,
+		obj.AFUNCDATA,
+		obj.AVARDEF,
+		obj.AVARKILL:
+		return 0
+	}
+}
+
+// copyas returns 1 if a and v address the same register.
+//
+// If a is the from operand, this means this operation reads the
+// register in v.  If a is the to operand, this means this operation
+// writes the register in v.
+func copyas(a *obj.Addr, v *obj.Addr) bool {
+	if regtyp(v) {
+		if a.Type == v.Type {
+			if a.Reg == v.Reg {
+				return true
+			}
+		}
+	}
+	return false
+}
+
+// copyau returns 1 if a either directly or indirectly addresses the
+// same register as v.
+//
+// If a is the from operand, this means this operation reads the
+// register in v.  If a is the to operand, this means the operation
+// either reads or writes the register in v (if !copyas(a, v), then
+// the operation reads the register in v).
+func copyau(a *obj.Addr, v *obj.Addr) bool {
+	if copyas(a, v) {
+		return true
+	}
+	if v.Type == obj.TYPE_REG {
+		if a.Type == obj.TYPE_MEM || (a.Type == obj.TYPE_ADDR && a.Reg != 0) {
+			if v.Reg == a.Reg {
+				return true
+			}
+		}
+	}
+	return false
+}
+
+// copyau1 returns 1 if p->reg references the same register as v and v
+// is a direct reference.
+func copyau1(p *obj.Prog, v *obj.Addr) bool {
+	if regtyp(v) && v.Reg != 0 {
+		if p.Reg == v.Reg {
+			return true
+		}
+	}
+	return false
+}
+
+// copysub replaces v with s in a if f!=0 or indicates it if could if f==0.
+// Returns 1 on failure to substitute (it always succeeds on ppc64).
+func copysub(a *obj.Addr, v *obj.Addr, s *obj.Addr, f int) int {
+	if f != 0 {
+		if copyau(a, v) {
+			a.Reg = s.Reg
+		}
+	}
+	return 0
+}
+
+// copysub1 replaces v with s in p1->reg if f!=0 or indicates if it could if f==0.
+// Returns 1 on failure to substitute (it always succeeds on ppc64).
+func copysub1(p1 *obj.Prog, v *obj.Addr, s *obj.Addr, f int) int {
+	if f != 0 {
+		if copyau1(p1, v) {
+			p1.Reg = s.Reg
+		}
+	}
+	return 0
+}
+
+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 == ppc64.REGSP
+}
diff --git a/src/cmd/compile/internal/ppc64/prog.go b/src/cmd/compile/internal/ppc64/prog.go
new file mode 100644
index 0000000..328b2ce
--- /dev/null
+++ b/src/cmd/compile/internal/ppc64/prog.go
@@ -0,0 +1,314 @@
+// 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 ppc64
+
+import (
+	"cmd/compile/internal/gc"
+	"cmd/internal/obj"
+	"cmd/internal/obj/ppc64"
+)
+
+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 = [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.LeftRead | gc.RightWrite, 0, 0, 0},
+
+	// Integer
+	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.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.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.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.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},
+	obj.ARET:      {gc.Break, 0, 0, 0},
+	obj.ADUFFZERO: {gc.Call, 0, 0, 0},
+	obj.ADUFFCOPY: {gc.Call, 0, 0, 0},
+}
+
+var initproginfo_initialized int
+
+func initproginfo() {
+	var addvariant = []int{V_CC, V_V, V_CC | V_V}
+
+	if initproginfo_initialized != 0 {
+		return
+	}
+	initproginfo_initialized = 1
+
+	// Perform one-time expansion of instructions in progtable to
+	// their CC, V, and VCC variants
+	var as2 int
+	var i int
+	var variant int
+	for as := int(0); as < len(progtable); as++ {
+		if progtable[as].Flags == 0 {
+			continue
+		}
+		variant = as2variant(as)
+		for i = 0; i < len(addvariant); i++ {
+			as2 = variant2as(as, variant|addvariant[i])
+			if as2 != 0 && progtable[as2].Flags == 0 {
+				progtable[as2] = progtable[as]
+			}
+		}
+	}
+}
+
+func proginfo(p *obj.Prog) {
+	initproginfo()
+
+	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 info.Flags&gc.PostInc != 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 info.Flags&gc.PostInc != 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 |= 1<<0 | RtoB(ppc64.REG_R3)
+		info.Regset |= RtoB(ppc64.REG_R3)
+	}
+
+	if p.As == obj.ADUFFCOPY {
+		// TODO(austin) Revisit when duffcopy is implemented
+		info.Reguse |= RtoB(ppc64.REG_R3) | RtoB(ppc64.REG_R4) | RtoB(ppc64.REG_R5)
+
+		info.Regset |= RtoB(ppc64.REG_R3) | RtoB(ppc64.REG_R4)
+	}
+}
+
+// Instruction variants table.  Initially this contains entries only
+// for the "base" form of each instruction.  On the first call to
+// as2variant or variant2as, we'll add the variants to the table.
+var varianttable = [ppc64.ALAST][4]int{
+	ppc64.AADD:     [4]int{ppc64.AADD, ppc64.AADDCC, ppc64.AADDV, ppc64.AADDVCC},
+	ppc64.AADDC:    [4]int{ppc64.AADDC, ppc64.AADDCCC, ppc64.AADDCV, ppc64.AADDCVCC},
+	ppc64.AADDE:    [4]int{ppc64.AADDE, ppc64.AADDECC, ppc64.AADDEV, ppc64.AADDEVCC},
+	ppc64.AADDME:   [4]int{ppc64.AADDME, ppc64.AADDMECC, ppc64.AADDMEV, ppc64.AADDMEVCC},
+	ppc64.AADDZE:   [4]int{ppc64.AADDZE, ppc64.AADDZECC, ppc64.AADDZEV, ppc64.AADDZEVCC},
+	ppc64.AAND:     [4]int{ppc64.AAND, ppc64.AANDCC, 0, 0},
+	ppc64.AANDN:    [4]int{ppc64.AANDN, ppc64.AANDNCC, 0, 0},
+	ppc64.ACNTLZD:  [4]int{ppc64.ACNTLZD, ppc64.ACNTLZDCC, 0, 0},
+	ppc64.ACNTLZW:  [4]int{ppc64.ACNTLZW, ppc64.ACNTLZWCC, 0, 0},
+	ppc64.ADIVD:    [4]int{ppc64.ADIVD, ppc64.ADIVDCC, ppc64.ADIVDV, ppc64.ADIVDVCC},
+	ppc64.ADIVDU:   [4]int{ppc64.ADIVDU, ppc64.ADIVDUCC, ppc64.ADIVDUV, ppc64.ADIVDUVCC},
+	ppc64.ADIVW:    [4]int{ppc64.ADIVW, ppc64.ADIVWCC, ppc64.ADIVWV, ppc64.ADIVWVCC},
+	ppc64.ADIVWU:   [4]int{ppc64.ADIVWU, ppc64.ADIVWUCC, ppc64.ADIVWUV, ppc64.ADIVWUVCC},
+	ppc64.AEQV:     [4]int{ppc64.AEQV, ppc64.AEQVCC, 0, 0},
+	ppc64.AEXTSB:   [4]int{ppc64.AEXTSB, ppc64.AEXTSBCC, 0, 0},
+	ppc64.AEXTSH:   [4]int{ppc64.AEXTSH, ppc64.AEXTSHCC, 0, 0},
+	ppc64.AEXTSW:   [4]int{ppc64.AEXTSW, ppc64.AEXTSWCC, 0, 0},
+	ppc64.AFABS:    [4]int{ppc64.AFABS, ppc64.AFABSCC, 0, 0},
+	ppc64.AFADD:    [4]int{ppc64.AFADD, ppc64.AFADDCC, 0, 0},
+	ppc64.AFADDS:   [4]int{ppc64.AFADDS, ppc64.AFADDSCC, 0, 0},
+	ppc64.AFCFID:   [4]int{ppc64.AFCFID, ppc64.AFCFIDCC, 0, 0},
+	ppc64.AFCTID:   [4]int{ppc64.AFCTID, ppc64.AFCTIDCC, 0, 0},
+	ppc64.AFCTIDZ:  [4]int{ppc64.AFCTIDZ, ppc64.AFCTIDZCC, 0, 0},
+	ppc64.AFCTIW:   [4]int{ppc64.AFCTIW, ppc64.AFCTIWCC, 0, 0},
+	ppc64.AFCTIWZ:  [4]int{ppc64.AFCTIWZ, ppc64.AFCTIWZCC, 0, 0},
+	ppc64.AFDIV:    [4]int{ppc64.AFDIV, ppc64.AFDIVCC, 0, 0},
+	ppc64.AFDIVS:   [4]int{ppc64.AFDIVS, ppc64.AFDIVSCC, 0, 0},
+	ppc64.AFMADD:   [4]int{ppc64.AFMADD, ppc64.AFMADDCC, 0, 0},
+	ppc64.AFMADDS:  [4]int{ppc64.AFMADDS, ppc64.AFMADDSCC, 0, 0},
+	ppc64.AFMOVD:   [4]int{ppc64.AFMOVD, ppc64.AFMOVDCC, 0, 0},
+	ppc64.AFMSUB:   [4]int{ppc64.AFMSUB, ppc64.AFMSUBCC, 0, 0},
+	ppc64.AFMSUBS:  [4]int{ppc64.AFMSUBS, ppc64.AFMSUBSCC, 0, 0},
+	ppc64.AFMUL:    [4]int{ppc64.AFMUL, ppc64.AFMULCC, 0, 0},
+	ppc64.AFMULS:   [4]int{ppc64.AFMULS, ppc64.AFMULSCC, 0, 0},
+	ppc64.AFNABS:   [4]int{ppc64.AFNABS, ppc64.AFNABSCC, 0, 0},
+	ppc64.AFNEG:    [4]int{ppc64.AFNEG, ppc64.AFNEGCC, 0, 0},
+	ppc64.AFNMADD:  [4]int{ppc64.AFNMADD, ppc64.AFNMADDCC, 0, 0},
+	ppc64.AFNMADDS: [4]int{ppc64.AFNMADDS, ppc64.AFNMADDSCC, 0, 0},
+	ppc64.AFNMSUB:  [4]int{ppc64.AFNMSUB, ppc64.AFNMSUBCC, 0, 0},
+	ppc64.AFNMSUBS: [4]int{ppc64.AFNMSUBS, ppc64.AFNMSUBSCC, 0, 0},
+	ppc64.AFRES:    [4]int{ppc64.AFRES, ppc64.AFRESCC, 0, 0},
+	ppc64.AFRSP:    [4]int{ppc64.AFRSP, ppc64.AFRSPCC, 0, 0},
+	ppc64.AFRSQRTE: [4]int{ppc64.AFRSQRTE, ppc64.AFRSQRTECC, 0, 0},
+	ppc64.AFSEL:    [4]int{ppc64.AFSEL, ppc64.AFSELCC, 0, 0},
+	ppc64.AFSQRT:   [4]int{ppc64.AFSQRT, ppc64.AFSQRTCC, 0, 0},
+	ppc64.AFSQRTS:  [4]int{ppc64.AFSQRTS, ppc64.AFSQRTSCC, 0, 0},
+	ppc64.AFSUB:    [4]int{ppc64.AFSUB, ppc64.AFSUBCC, 0, 0},
+	ppc64.AFSUBS:   [4]int{ppc64.AFSUBS, ppc64.AFSUBSCC, 0, 0},
+	ppc64.AMTFSB0:  [4]int{ppc64.AMTFSB0, ppc64.AMTFSB0CC, 0, 0},
+	ppc64.AMTFSB1:  [4]int{ppc64.AMTFSB1, ppc64.AMTFSB1CC, 0, 0},
+	ppc64.AMULHD:   [4]int{ppc64.AMULHD, ppc64.AMULHDCC, 0, 0},
+	ppc64.AMULHDU:  [4]int{ppc64.AMULHDU, ppc64.AMULHDUCC, 0, 0},
+	ppc64.AMULHW:   [4]int{ppc64.AMULHW, ppc64.AMULHWCC, 0, 0},
+	ppc64.AMULHWU:  [4]int{ppc64.AMULHWU, ppc64.AMULHWUCC, 0, 0},
+	ppc64.AMULLD:   [4]int{ppc64.AMULLD, ppc64.AMULLDCC, ppc64.AMULLDV, ppc64.AMULLDVCC},
+	ppc64.AMULLW:   [4]int{ppc64.AMULLW, ppc64.AMULLWCC, ppc64.AMULLWV, ppc64.AMULLWVCC},
+	ppc64.ANAND:    [4]int{ppc64.ANAND, ppc64.ANANDCC, 0, 0},
+	ppc64.ANEG:     [4]int{ppc64.ANEG, ppc64.ANEGCC, ppc64.ANEGV, ppc64.ANEGVCC},
+	ppc64.ANOR:     [4]int{ppc64.ANOR, ppc64.ANORCC, 0, 0},
+	ppc64.AOR:      [4]int{ppc64.AOR, ppc64.AORCC, 0, 0},
+	ppc64.AORN:     [4]int{ppc64.AORN, ppc64.AORNCC, 0, 0},
+	ppc64.AREM:     [4]int{ppc64.AREM, ppc64.AREMCC, ppc64.AREMV, ppc64.AREMVCC},
+	ppc64.AREMD:    [4]int{ppc64.AREMD, ppc64.AREMDCC, ppc64.AREMDV, ppc64.AREMDVCC},
+	ppc64.AREMDU:   [4]int{ppc64.AREMDU, ppc64.AREMDUCC, ppc64.AREMDUV, ppc64.AREMDUVCC},
+	ppc64.AREMU:    [4]int{ppc64.AREMU, ppc64.AREMUCC, ppc64.AREMUV, ppc64.AREMUVCC},
+	ppc64.ARLDC:    [4]int{ppc64.ARLDC, ppc64.ARLDCCC, 0, 0},
+	ppc64.ARLDCL:   [4]int{ppc64.ARLDCL, ppc64.ARLDCLCC, 0, 0},
+	ppc64.ARLDCR:   [4]int{ppc64.ARLDCR, ppc64.ARLDCRCC, 0, 0},
+	ppc64.ARLDMI:   [4]int{ppc64.ARLDMI, ppc64.ARLDMICC, 0, 0},
+	ppc64.ARLWMI:   [4]int{ppc64.ARLWMI, ppc64.ARLWMICC, 0, 0},
+	ppc64.ARLWNM:   [4]int{ppc64.ARLWNM, ppc64.ARLWNMCC, 0, 0},
+	ppc64.ASLD:     [4]int{ppc64.ASLD, ppc64.ASLDCC, 0, 0},
+	ppc64.ASLW:     [4]int{ppc64.ASLW, ppc64.ASLWCC, 0, 0},
+	ppc64.ASRAD:    [4]int{ppc64.ASRAD, ppc64.ASRADCC, 0, 0},
+	ppc64.ASRAW:    [4]int{ppc64.ASRAW, ppc64.ASRAWCC, 0, 0},
+	ppc64.ASRD:     [4]int{ppc64.ASRD, ppc64.ASRDCC, 0, 0},
+	ppc64.ASRW:     [4]int{ppc64.ASRW, ppc64.ASRWCC, 0, 0},
+	ppc64.ASUB:     [4]int{ppc64.ASUB, ppc64.ASUBCC, ppc64.ASUBV, ppc64.ASUBVCC},
+	ppc64.ASUBC:    [4]int{ppc64.ASUBC, ppc64.ASUBCCC, ppc64.ASUBCV, ppc64.ASUBCVCC},
+	ppc64.ASUBE:    [4]int{ppc64.ASUBE, ppc64.ASUBECC, ppc64.ASUBEV, ppc64.ASUBEVCC},
+	ppc64.ASUBME:   [4]int{ppc64.ASUBME, ppc64.ASUBMECC, ppc64.ASUBMEV, ppc64.ASUBMEVCC},
+	ppc64.ASUBZE:   [4]int{ppc64.ASUBZE, ppc64.ASUBZECC, ppc64.ASUBZEV, ppc64.ASUBZEVCC},
+	ppc64.AXOR:     [4]int{ppc64.AXOR, ppc64.AXORCC, 0, 0},
+}
+
+var initvariants_initialized int
+
+func initvariants() {
+	if initvariants_initialized != 0 {
+		return
+	}
+	initvariants_initialized = 1
+
+	var j int
+	for i := int(0); i < len(varianttable); i++ {
+		if varianttable[i][0] == 0 {
+			// Instruction has no variants
+			varianttable[i][0] = i
+
+			continue
+		}
+
+		// Copy base form to other variants
+		if varianttable[i][0] == i {
+			for j = 0; j < len(varianttable[i]); j++ {
+				varianttable[varianttable[i][j]] = varianttable[i]
+			}
+		}
+	}
+}
+
+// as2variant returns the variant (V_*) flags of instruction as.
+func as2variant(as int) int {
+	initvariants()
+	for i := int(0); i < len(varianttable[as]); i++ {
+		if varianttable[as][i] == as {
+			return i
+		}
+	}
+	gc.Fatal("as2variant: instruction %v is not a variant of itself", obj.Aconv(as))
+	return 0
+}
+
+// variant2as returns the instruction as with the given variant (V_*) flags.
+// If no such variant exists, this returns 0.
+func variant2as(as int, flags int) int {
+	initvariants()
+	return varianttable[as][flags]
+}
diff --git a/src/cmd/compile/internal/ppc64/reg.go b/src/cmd/compile/internal/ppc64/reg.go
new file mode 100644
index 0000000..fa1cb71
--- /dev/null
+++ b/src/cmd/compile/internal/ppc64/reg.go
@@ -0,0 +1,162 @@
+// 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 at 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 at 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 ppc64
+
+import "cmd/internal/obj/ppc64"
+import "cmd/compile/internal/gc"
+
+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(1<<0 | RtoB(ppc64.REGSP) | RtoB(ppc64.REGG) | RtoB(ppc64.REGTLS))
+
+	// Also exclude floating point registers with fixed constants
+	regbits |= RtoB(ppc64.REG_F27) | RtoB(ppc64.REG_F28) | RtoB(ppc64.REG_F29) | RtoB(ppc64.REG_F30) | RtoB(ppc64.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 > ppc64.REG_R0 && r <= ppc64.REG_R31 {
+		return 1 << uint(r-ppc64.REG_R0)
+	}
+	if r >= ppc64.REG_F0 && r <= ppc64.REG_F31 {
+		return 1 << uint(32+r-ppc64.REG_F0)
+	}
+	return 0
+}
+
+func BtoR(b uint64) int {
+	b &= 0xffffffff
+	if b == 0 {
+		return 0
+	}
+	return gc.Bitno(b) + ppc64.REG_R0
+}
+
+func BtoF(b uint64) int {
+	b >>= 32
+	if b == 0 {
+		return 0
+	}
+	return gc.Bitno(b) + ppc64.REG_F0
+}
diff --git a/src/cmd/compile/internal/x86/cgen.go b/src/cmd/compile/internal/x86/cgen.go
new file mode 100644
index 0000000..1768674
--- /dev/null
+++ b/src/cmd/compile/internal/x86/cgen.go
@@ -0,0 +1,159 @@
+// 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 x86
+
+import (
+	"cmd/compile/internal/gc"
+	"cmd/internal/obj"
+	"cmd/internal/obj/x86"
+)
+
+/*
+ * 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 bool) *obj.Prog {
+	if !gc.Is64(n.Type) {
+		if n.Addable && (gc.Simtype[n.Etype] == gc.TUINT32 || gc.Simtype[n.Etype] == gc.TINT32) {
+			// nothing to do.
+			*res = *n
+		} else {
+			gc.Tempname(res, gc.Types[gc.TUINT32])
+			gc.Cgen(n, res)
+		}
+
+		return nil
+	}
+
+	var tmp gc.Node
+	gc.Tempname(&tmp, gc.Types[gc.TINT64])
+	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 {
+		splitclean()
+		return nil
+	}
+
+	var zero gc.Node
+	gc.Nodconst(&zero, gc.Types[gc.TINT32], 0)
+	gins(x86.ACMPL, &hi, &zero)
+	splitclean()
+	return gc.Gbranch(x86.AJNE, nil, +1)
+}
+
+func blockcopy(n, res *gc.Node, osrc, odst, w int64) {
+	var dst gc.Node
+	gc.Nodreg(&dst, gc.Types[gc.Tptr], x86.REG_DI)
+	var src gc.Node
+	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 {
+		gc.Agen(n, &tsrc)
+	}
+	if !res.Addable {
+		gc.Agen(res, &tdst)
+	}
+	if n.Addable {
+		gc.Agen(n, &src)
+	} else {
+		gmove(&tsrc, &src)
+	}
+
+	if res.Op == gc.ONAME {
+		gc.Gvardef(res)
+	}
+
+	if res.Addable {
+		gc.Agen(res, &dst)
+	} else {
+		gmove(&tdst, &dst)
+	}
+
+	c := int32(w % 4) // bytes
+	q := int32(w / 4) // doublewords
+
+	// if we are copying forward on the stack and
+	// the src and dst overlap, then reverse direction
+	if osrc < odst && int64(odst) < int64(osrc)+w {
+		// reverse direction
+		gins(x86.ASTD, nil, nil) // set direction flag
+		if c > 0 {
+			gconreg(x86.AADDL, w-1, x86.REG_SI)
+			gconreg(x86.AADDL, w-1, x86.REG_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(x86.AADDL, -3, x86.REG_SI)
+				gconreg(x86.AADDL, -3, x86.REG_DI)
+			} else {
+				gconreg(x86.AADDL, w-4, x86.REG_SI)
+				gconreg(x86.AADDL, w-4, x86.REG_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(x86.ACLD, nil, nil)
+	} else {
+		gins(x86.ACLD, nil, nil) // paranoia.  TODO(rsc): remove?
+
+		// normal direction
+		if q > 128 || (q >= 4 && gc.Nacl) {
+			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
+			p.To.Sym = gc.Linksym(gc.Pkglookup("duffcopy", gc.Runtimepkg))
+
+			// 10 and 128 = magic constants: see ../../runtime/asm_386.s
+			p.To.Offset = 10 * (128 - int64(q))
+		} else if !gc.Nacl && c == 0 {
+			var cx gc.Node
+			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.
+			src.Op = gc.OINDREG
+
+			dst.Op = gc.OINDREG
+			for q > 0 {
+				gmove(&src, &cx) // MOVL x+(SI),CX
+				gmove(&cx, &dst) // MOVL CX,x+(DI)
+				src.Xoffset += 4
+				dst.Xoffset += 4
+				q--
+			}
+		} else {
+			for q > 0 {
+				gins(x86.AMOVSL, nil, nil) // MOVL *(SI)+,*(DI)+
+				q--
+			}
+		}
+
+		for c > 0 {
+			gins(x86.AMOVSB, nil, nil) // MOVB *(SI)+,*(DI)+
+			c--
+		}
+	}
+}
diff --git a/src/cmd/compile/internal/x86/cgen64.go b/src/cmd/compile/internal/x86/cgen64.go
new file mode 100644
index 0000000..0b061ff
--- /dev/null
+++ b/src/cmd/compile/internal/x86/cgen64.go
@@ -0,0 +1,598 @@
+// 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 x86
+
+import (
+	"cmd/compile/internal/gc"
+	"cmd/internal/obj"
+	"cmd/internal/obj/x86"
+)
+
+/*
+ * attempt to generate 64-bit
+ *	res = n
+ * return 1 on success, 0 if op not handled.
+ */
+func cgen64(n *gc.Node, res *gc.Node) {
+	if res.Op != gc.OINDREG && res.Op != gc.ONAME {
+		gc.Dump("n", n)
+		gc.Dump("res", res)
+		gc.Fatal("cgen64 %v of %v", gc.Oconv(int(n.Op), 0), gc.Oconv(int(res.Op), 0))
+	}
+
+	switch n.Op {
+	default:
+		gc.Fatal("cgen64 %v", gc.Oconv(int(n.Op), 0))
+
+	case gc.OMINUS:
+		gc.Cgen(n.Left, res)
+		var hi1 gc.Node
+		var lo1 gc.Node
+		split64(res, &lo1, &hi1)
+		gins(x86.ANEGL, nil, &lo1)
+		gins(x86.AADCL, ncon(0), &hi1)
+		gins(x86.ANEGL, nil, &hi1)
+		splitclean()
+		return
+
+	case gc.OCOM:
+		gc.Cgen(n.Left, res)
+		var lo1 gc.Node
+		var hi1 gc.Node
+		split64(res, &lo1, &hi1)
+		gins(x86.ANOTL, nil, &lo1)
+		gins(x86.ANOTL, nil, &hi1)
+		splitclean()
+		return
+
+		// binary operators.
+	// common setup below.
+	case gc.OADD,
+		gc.OSUB,
+		gc.OMUL,
+		gc.OLROT,
+		gc.OLSH,
+		gc.ORSH,
+		gc.OAND,
+		gc.OOR,
+		gc.OXOR:
+		break
+	}
+
+	l := n.Left
+	r := n.Right
+	if !l.Addable {
+		var t1 gc.Node
+		gc.Tempname(&t1, l.Type)
+		gc.Cgen(l, &t1)
+		l = &t1
+	}
+
+	if r != nil && !r.Addable {
+		var t2 gc.Node
+		gc.Tempname(&t2, r.Type)
+		gc.Cgen(r, &t2)
+		r = &t2
+	}
+
+	var ax gc.Node
+	gc.Nodreg(&ax, gc.Types[gc.TINT32], x86.REG_AX)
+	var cx gc.Node
+	gc.Nodreg(&cx, gc.Types[gc.TINT32], x86.REG_CX)
+	var dx gc.Node
+	gc.Nodreg(&dx, gc.Types[gc.TINT32], x86.REG_DX)
+
+	// Setup for binary operation.
+	var hi1 gc.Node
+	var lo1 gc.Node
+	split64(l, &lo1, &hi1)
+
+	var lo2 gc.Node
+	var hi2 gc.Node
+	if gc.Is64(r.Type) {
+		split64(r, &lo2, &hi2)
+	}
+
+	// Do op.  Leave result in DX:AX.
+	switch n.Op {
+	// TODO: Constants
+	case gc.OADD:
+		gins(x86.AMOVL, &lo1, &ax)
+
+		gins(x86.AMOVL, &hi1, &dx)
+		gins(x86.AADDL, &lo2, &ax)
+		gins(x86.AADCL, &hi2, &dx)
+
+		// TODO: Constants.
+	case gc.OSUB:
+		gins(x86.AMOVL, &lo1, &ax)
+
+		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
+		gc.Regalloc(&ex, gc.Types[gc.TPTR32], nil)
+
+		var fx gc.Node
+		gc.Regalloc(&fx, gc.Types[gc.TPTR32], nil)
+
+		// load args into DX:AX and EX:CX.
+		gins(x86.AMOVL, &lo1, &ax)
+
+		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(x86.AMOVL, &dx, &fx)
+
+		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(x86.AIMULL, &cx, &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)
+
+		gc.Regfree(&ex)
+		gc.Regfree(&fx)
+
+		// We only rotate by a constant c in [0,64).
+	// if c >= 32:
+	//	lo, hi = hi, lo
+	//	c -= 32
+	// if c == 0:
+	//	no-op
+	// else:
+	//	t = hi
+	//	shld hi:lo, c
+	//	shld lo:t, c
+	case gc.OLROT:
+		v := uint64(r.Int())
+
+		if v >= 32 {
+			// reverse during load to do the first 32 bits of rotate
+			v -= 32
+
+			gins(x86.AMOVL, &lo1, &dx)
+			gins(x86.AMOVL, &hi1, &ax)
+		} else {
+			gins(x86.AMOVL, &lo1, &ax)
+			gins(x86.AMOVL, &hi1, &dx)
+		}
+
+		if v == 0 {
+		} else // done
+		{
+			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(x86.ASHLL, ncon(uint32(v)), &ax)
+			p1.From.Index = x86.REG_CX // double-width shift
+			p1.From.Scale = 0
+		}
+
+	case gc.OLSH:
+		if r.Op == gc.OLITERAL {
+			v := uint64(r.Int())
+			if v >= 64 {
+				if gc.Is64(r.Type) {
+					splitclean()
+				}
+				splitclean()
+				split64(res, &lo2, &hi2)
+				gins(x86.AMOVL, ncon(0), &lo2)
+				gins(x86.AMOVL, ncon(0), &hi2)
+				splitclean()
+				return
+			}
+
+			if v >= 32 {
+				if gc.Is64(r.Type) {
+					splitclean()
+				}
+				split64(res, &lo2, &hi2)
+				gmove(&lo1, &hi2)
+				if v > 32 {
+					gins(x86.ASHLL, ncon(uint32(v-32)), &hi2)
+				}
+
+				gins(x86.AMOVL, ncon(0), &lo2)
+				splitclean()
+				splitclean()
+				return
+			}
+
+			// general shift
+			gins(x86.AMOVL, &lo1, &ax)
+
+			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(x86.ASHLL, ncon(uint32(v)), &ax)
+			break
+		}
+
+		// load value into DX:AX.
+		gins(x86.AMOVL, &lo1, &ax)
+
+		gins(x86.AMOVL, &hi1, &dx)
+
+		// load shift value into register.
+		// if high bits are set, zero value.
+		var p1 *obj.Prog
+
+		if gc.Is64(r.Type) {
+			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(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(x86.AXORL, &dx, &dx)
+		gins(x86.AXORL, &ax, &ax)
+		gc.Patch(p2, gc.Pc)
+
+		// if shift count is >= 32, zero low.
+		gins(x86.ACMPL, &cx, ncon(32))
+
+		p1 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1)
+		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(x86.ASHLL, &cx, &dx)
+
+		p1.From.Index = x86.REG_AX // double-width shift
+		p1.From.Scale = 0
+		gins(x86.ASHLL, &cx, &ax)
+		gc.Patch(p2, gc.Pc)
+
+	case gc.ORSH:
+		if r.Op == gc.OLITERAL {
+			v := uint64(r.Int())
+			if v >= 64 {
+				if gc.Is64(r.Type) {
+					splitclean()
+				}
+				splitclean()
+				split64(res, &lo2, &hi2)
+				if hi1.Type.Etype == gc.TINT32 {
+					gmove(&hi1, &lo2)
+					gins(x86.ASARL, ncon(31), &lo2)
+					gmove(&hi1, &hi2)
+					gins(x86.ASARL, ncon(31), &hi2)
+				} else {
+					gins(x86.AMOVL, ncon(0), &lo2)
+					gins(x86.AMOVL, ncon(0), &hi2)
+				}
+
+				splitclean()
+				return
+			}
+
+			if v >= 32 {
+				if gc.Is64(r.Type) {
+					splitclean()
+				}
+				split64(res, &lo2, &hi2)
+				gmove(&hi1, &lo2)
+				if v > 32 {
+					gins(optoas(gc.ORSH, hi1.Type), ncon(uint32(v-32)), &lo2)
+				}
+				if hi1.Type.Etype == gc.TINT32 {
+					gmove(&hi1, &hi2)
+					gins(x86.ASARL, ncon(31), &hi2)
+				} else {
+					gins(x86.AMOVL, ncon(0), &hi2)
+				}
+				splitclean()
+				splitclean()
+				return
+			}
+
+			// general shift
+			gins(x86.AMOVL, &lo1, &ax)
+
+			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(x86.AMOVL, &lo1, &ax)
+
+		gins(x86.AMOVL, &hi1, &dx)
+
+		// load shift value into register.
+		// if high bits are set, zero value.
+		var p1 *obj.Prog
+
+		if gc.Is64(r.Type) {
+			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(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(x86.ASARL, ncon(31), &dx)
+			gins(x86.AMOVL, &dx, &ax)
+		} else {
+			gins(x86.AXORL, &dx, &dx)
+			gins(x86.AXORL, &ax, &ax)
+		}
+
+		gc.Patch(p2, gc.Pc)
+
+		// if shift count is >= 32, sign-extend hi.
+		gins(x86.ACMPL, &cx, ncon(32))
+
+		p1 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1)
+		gins(x86.AMOVL, &dx, &ax)
+		if hi1.Type.Etype == gc.TINT32 {
+			gins(x86.ASARL, &cx, &ax) // SARL only uses bottom 5 bits of count
+			gins(x86.ASARL, ncon(31), &dx)
+		} else {
+			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(x86.ASHRL, &cx, &ax)
+
+		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)
+
+		// make constant the right side (it usually is anyway).
+	case gc.OXOR,
+		gc.OAND,
+		gc.OOR:
+		if lo1.Op == gc.OLITERAL {
+			nswap(&lo1, &lo2)
+			nswap(&hi1, &hi2)
+		}
+
+		if lo2.Op == gc.OLITERAL {
+			// special cases for constants.
+			lv := uint32(lo2.Int())
+			hv := uint32(hi2.Int())
+			splitclean() // right side
+			split64(res, &lo2, &hi2)
+			switch n.Op {
+			case gc.OXOR:
+				gmove(&lo1, &lo2)
+				gmove(&hi1, &hi2)
+				switch lv {
+				case 0:
+					break
+
+				case 0xffffffff:
+					gins(x86.ANOTL, nil, &lo2)
+
+				default:
+					gins(x86.AXORL, ncon(lv), &lo2)
+				}
+
+				switch hv {
+				case 0:
+					break
+
+				case 0xffffffff:
+					gins(x86.ANOTL, nil, &hi2)
+
+				default:
+					gins(x86.AXORL, ncon(hv), &hi2)
+				}
+
+			case gc.OAND:
+				switch lv {
+				case 0:
+					gins(x86.AMOVL, ncon(0), &lo2)
+
+				default:
+					gmove(&lo1, &lo2)
+					if lv != 0xffffffff {
+						gins(x86.AANDL, ncon(lv), &lo2)
+					}
+				}
+
+				switch hv {
+				case 0:
+					gins(x86.AMOVL, ncon(0), &hi2)
+
+				default:
+					gmove(&hi1, &hi2)
+					if hv != 0xffffffff {
+						gins(x86.AANDL, ncon(hv), &hi2)
+					}
+				}
+
+			case gc.OOR:
+				switch lv {
+				case 0:
+					gmove(&lo1, &lo2)
+
+				case 0xffffffff:
+					gins(x86.AMOVL, ncon(0xffffffff), &lo2)
+
+				default:
+					gmove(&lo1, &lo2)
+					gins(x86.AORL, ncon(lv), &lo2)
+				}
+
+				switch hv {
+				case 0:
+					gmove(&hi1, &hi2)
+
+				case 0xffffffff:
+					gins(x86.AMOVL, ncon(0xffffffff), &hi2)
+
+				default:
+					gmove(&hi1, &hi2)
+					gins(x86.AORL, ncon(hv), &hi2)
+				}
+			}
+
+			splitclean()
+			splitclean()
+			return
+		}
+
+		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)
+	}
+
+	if gc.Is64(r.Type) {
+		splitclean()
+	}
+	splitclean()
+
+	split64(res, &lo1, &hi1)
+	gins(x86.AMOVL, &ax, &lo1)
+	gins(x86.AMOVL, &dx, &hi1)
+	splitclean()
+}
+
+/*
+ * generate comparison of nl, nr, both 64-bit.
+ * nl is memory; nr is constant or memory.
+ */
+func cmp64(nl *gc.Node, nr *gc.Node, op int, likely int, to *obj.Prog) {
+	var lo1 gc.Node
+	var hi1 gc.Node
+	var lo2 gc.Node
+	var hi2 gc.Node
+	var rr gc.Node
+
+	split64(nl, &lo1, &hi1)
+	split64(nr, &lo2, &hi2)
+
+	// compare most significant word;
+	// if they differ, we're done.
+	t := hi1.Type
+
+	if nl.Op == gc.OLITERAL || nr.Op == gc.OLITERAL {
+		gins(x86.ACMPL, &hi1, &hi2)
+	} else {
+		gc.Regalloc(&rr, gc.Types[gc.TINT32], nil)
+		gins(x86.AMOVL, &hi1, &rr)
+		gins(x86.ACMPL, &rr, &hi2)
+		gc.Regfree(&rr)
+	}
+
+	var br *obj.Prog
+	switch op {
+	default:
+		gc.Fatal("cmp64 %v %v", gc.Oconv(int(op), 0), t)
+
+		// cmp hi
+	// jne L
+	// cmp lo
+	// jeq to
+	// L:
+	case gc.OEQ:
+		br = gc.Gbranch(x86.AJNE, nil, -likely)
+
+		// cmp hi
+	// jne to
+	// cmp lo
+	// jne to
+	case gc.ONE:
+		gc.Patch(gc.Gbranch(x86.AJNE, nil, likely), to)
+
+		// cmp hi
+	// jgt to
+	// jlt L
+	// cmp lo
+	// jge to (or jgt to)
+	// L:
+	case gc.OGE,
+		gc.OGT:
+		gc.Patch(gc.Gbranch(optoas(gc.OGT, t), nil, likely), to)
+
+		br = gc.Gbranch(optoas(gc.OLT, t), nil, -likely)
+
+		// cmp hi
+	// jlt to
+	// jgt L
+	// cmp lo
+	// jle to (or jlt to)
+	// L:
+	case gc.OLE,
+		gc.OLT:
+		gc.Patch(gc.Gbranch(optoas(gc.OLT, t), nil, likely), to)
+
+		br = gc.Gbranch(optoas(gc.OGT, t), nil, -likely)
+	}
+
+	// compare least significant word
+	t = lo1.Type
+
+	if nl.Op == gc.OLITERAL || nr.Op == gc.OLITERAL {
+		gins(x86.ACMPL, &lo1, &lo2)
+	} else {
+		gc.Regalloc(&rr, gc.Types[gc.TINT32], nil)
+		gins(x86.AMOVL, &lo1, &rr)
+		gins(x86.ACMPL, &rr, &lo2)
+		gc.Regfree(&rr)
+	}
+
+	// jump again
+	gc.Patch(gc.Gbranch(optoas(op, t), nil, likely), to)
+
+	// point first branch down here if appropriate
+	if br != nil {
+		gc.Patch(br, gc.Pc)
+	}
+
+	splitclean()
+	splitclean()
+}
diff --git a/src/cmd/compile/internal/x86/galign.go b/src/cmd/compile/internal/x86/galign.go
new file mode 100644
index 0000000..2b602e1
--- /dev/null
+++ b/src/cmd/compile/internal/x86/galign.go
@@ -0,0 +1,110 @@
+// 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 x86
+
+import (
+	"cmd/compile/internal/gc"
+	"cmd/internal/obj"
+	"cmd/internal/obj/x86"
+	"fmt"
+	"os"
+)
+
+var thechar int = '8'
+
+var thestring string = "386"
+
+var thelinkarch *obj.LinkArch = &x86.Link386
+
+func linkarchinit() {
+}
+
+var MAXWIDTH int64 = (1 << 32) - 1
+
+/*
+ * go declares several platform-specific type aliases:
+ * int, uint, and uintptr
+ */
+var typedefs = []gc.Typedef{
+	gc.Typedef{"int", gc.TINT, gc.TINT32},
+	gc.Typedef{"uint", gc.TUINT, gc.TUINT32},
+	gc.Typedef{"uintptr", gc.TUINTPTR, gc.TUINT32},
+}
+
+func betypeinit() {
+	gc.Widthptr = 4
+	gc.Widthint = 4
+	gc.Widthreg = 4
+}
+
+func Main() {
+	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_DI
+	switch v := obj.Getgo386(); v {
+	case "387":
+		gc.Thearch.FREGMIN = x86.REG_F0
+		gc.Thearch.FREGMAX = x86.REG_F7
+		gc.Thearch.Use387 = true
+	case "sse2":
+		gc.Thearch.FREGMIN = x86.REG_X0
+		gc.Thearch.FREGMAX = x86.REG_X7
+	default:
+		fmt.Fprintf(os.Stderr, "unsupported setting GO386=%s\n", v)
+		gc.Exit(1)
+	}
+	gc.Thearch.MAXWIDTH = MAXWIDTH
+	gc.Thearch.ReservedRegs = resvd
+
+	gc.Thearch.Betypeinit = betypeinit
+	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.Getg = getg
+	gc.Thearch.Gins = gins
+	gc.Thearch.Ginscmp = ginscmp
+	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.Regtyp = regtyp
+	gc.Thearch.Sameaddr = sameaddr
+	gc.Thearch.Smallindir = smallindir
+	gc.Thearch.Stackaddr = stackaddr
+	gc.Thearch.Blockcopy = blockcopy
+	gc.Thearch.Sudoaddable = sudoaddable
+	gc.Thearch.Sudoclean = sudoclean
+	gc.Thearch.Excludedregs = excludedregs
+	gc.Thearch.RtoB = RtoB
+	gc.Thearch.FtoB = FtoB
+	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/compile/internal/x86/ggen.go b/src/cmd/compile/internal/x86/ggen.go
new file mode 100644
index 0000000..ae9881d
--- /dev/null
+++ b/src/cmd/compile/internal/x86/ggen.go
@@ -0,0 +1,940 @@
+// 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 x86
+
+import (
+	"cmd/compile/internal/gc"
+	"cmd/internal/obj"
+	"cmd/internal/obj/x86"
+)
+
+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
+	ax := uint32(0)
+	for l := gc.Curfn.Func.Dcl; l != nil; l = l.Next {
+		n = l.N
+		if !n.Name.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.Widthptr) {
+			// merge with range we already have
+			lo = n.Xoffset
+
+			continue
+		}
+
+		// zero old range
+		p = zerorange(p, int64(frame), lo, hi, &ax)
+
+		// set new range
+		hi = n.Xoffset + n.Type.Width
+
+		lo = n.Xoffset
+	}
+
+	// zero final range
+	zerorange(p, int64(frame), lo, hi, &ax)
+}
+
+func zerorange(p *obj.Prog, frame int64, lo int64, hi int64, ax *uint32) *obj.Prog {
+	cnt := hi - lo
+	if cnt == 0 {
+		return p
+	}
+	if *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, 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, 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, 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
+}
+
+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 clearfat(nl *gc.Node) {
+	/* clear a fat object */
+	if gc.Debug['g'] != 0 {
+		gc.Dump("\nclearfat", nl)
+	}
+
+	w := uint32(nl.Type.Width)
+
+	// Avoid taking the address for simple enough types.
+	if gc.Componentgen(nil, nl) {
+		return
+	}
+
+	c := w % 4 // bytes
+	q := w / 4 // quads
+
+	if q < 4 {
+		// Write sequence of MOV 0, off(base) instead of using STOSL.
+		// The hope is that although the code will be slightly longer,
+		// the MOVs will have no dependencies and pipeline better
+		// than the unrolled STOSL loop.
+		// NOTE: Must use agen, not igen, so that optimizer sees address
+		// being taken. We are not writing on field boundaries.
+		var n1 gc.Node
+		gc.Regalloc(&n1, gc.Types[gc.Tptr], nil)
+
+		gc.Agen(nl, &n1)
+		n1.Op = gc.OINDREG
+		var z gc.Node
+		gc.Nodconst(&z, gc.Types[gc.TUINT64], 0)
+		for {
+			tmp14 := q
+			q--
+			if tmp14 <= 0 {
+				break
+			}
+			n1.Type = z.Type
+			gins(x86.AMOVL, &z, &n1)
+			n1.Xoffset += 4
+		}
+
+		gc.Nodconst(&z, gc.Types[gc.TUINT8], 0)
+		for {
+			tmp15 := c
+			c--
+			if tmp15 <= 0 {
+				break
+			}
+			n1.Type = z.Type
+			gins(x86.AMOVB, &z, &n1)
+			n1.Xoffset++
+		}
+
+		gc.Regfree(&n1)
+		return
+	}
+
+	var n1 gc.Node
+	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(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
+		p.To.Sym = gc.Linksym(gc.Pkglookup("duffzero", gc.Runtimepkg))
+
+		// 1 and 128 = magic constants: see ../../runtime/asm_386.s
+		p.To.Offset = 1 * (128 - int64(q))
+	} else {
+		for q > 0 {
+			gins(x86.ASTOSL, nil, nil) // STOL AL,*(DI)+
+			q--
+		}
+	}
+
+	for c > 0 {
+		gins(x86.ASTOSB, nil, nil) // STOB AL,*(DI)+
+		c--
+	}
+}
+
+var panicdiv *gc.Node
+
+/*
+ * generate division.
+ * caller must set:
+ *	ax = allocated AX register
+ *	dx = allocated DX register
+ * 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, ax *gc.Node, dx *gc.Node) {
+	// Have to be careful about handling
+	// most negative int divided by -1 correctly.
+	// The hardware will trap.
+	// Also the byte divide instruction needs AH,
+	// which we otherwise don't have to deal with.
+	// Easiest way to avoid for int8, int16: use int32.
+	// For int32 and int64, use explicit test.
+	// Could use int64 hw for int32.
+	t := nl.Type
+
+	t0 := t
+	check := 0
+	if gc.Issigned[t.Etype] {
+		check = 1
+		if gc.Isconst(nl, gc.CTINT) && nl.Int() != -1<<uint64(t.Width*8-1) {
+			check = 0
+		} else if gc.Isconst(nr, gc.CTINT) && nr.Int() != -1 {
+			check = 0
+		}
+	}
+
+	if t.Width < 4 {
+		if gc.Issigned[t.Etype] {
+			t = gc.Types[gc.TINT32]
+		} else {
+			t = gc.Types[gc.TUINT32]
+		}
+		check = 0
+	}
+
+	var t1 gc.Node
+	gc.Tempname(&t1, t)
+	var t2 gc.Node
+	gc.Tempname(&t2, t)
+	if t0 != t {
+		var t3 gc.Node
+		gc.Tempname(&t3, t0)
+		var t4 gc.Node
+		gc.Tempname(&t4, t0)
+		gc.Cgen(nl, &t3)
+		gc.Cgen(nr, &t4)
+
+		// Convert.
+		gmove(&t3, &t1)
+
+		gmove(&t4, &t2)
+	} else {
+		gc.Cgen(nl, &t1)
+		gc.Cgen(nr, &t2)
+	}
+
+	var n1 gc.Node
+	if !gc.Samereg(ax, res) && !gc.Samereg(dx, res) {
+		gc.Regalloc(&n1, t, res)
+	} else {
+		gc.Regalloc(&n1, t, nil)
+	}
+	gmove(&t2, &n1)
+	gmove(&t1, ax)
+	var p2 *obj.Prog
+	var n4 gc.Node
+	if gc.Nacl {
+		// Native Client does not relay the divide-by-zero trap
+		// to the executing program, so we must insert a check
+		// for ourselves.
+		gc.Nodconst(&n4, t, 0)
+
+		gins(optoas(gc.OCMP, t), &n1, &n4)
+		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)
+	}
+
+	if check != 0 {
+		gc.Nodconst(&n4, t, -1)
+		gins(optoas(gc.OCMP, t), &n1, &n4)
+		p1 := gc.Gbranch(optoas(gc.ONE, t), nil, +1)
+		if op == gc.ODIV {
+			// a / (-1) is -a.
+			gins(optoas(gc.OMINUS, t), nil, ax)
+
+			gmove(ax, res)
+		} else {
+			// a % (-1) is 0.
+			gc.Nodconst(&n4, t, 0)
+
+			gmove(&n4, res)
+		}
+
+		p2 = gc.Gbranch(obj.AJMP, nil, 0)
+		gc.Patch(p1, gc.Pc)
+	}
+
+	if !gc.Issigned[t.Etype] {
+		var nz gc.Node
+		gc.Nodconst(&nz, t, 0)
+		gmove(&nz, dx)
+	} else {
+		gins(optoas(gc.OEXTEND, t), nil, nil)
+	}
+	gins(optoas(op, t), &n1, nil)
+	gc.Regfree(&n1)
+
+	if op == gc.ODIV {
+		gmove(ax, res)
+	} else {
+		gmove(dx, res)
+	}
+	if check != 0 {
+		gc.Patch(p2, gc.Pc)
+	}
+}
+
+func savex(dr int, x *gc.Node, oldx *gc.Node, res *gc.Node, t *gc.Type) {
+	r := gc.GetReg(dr)
+	gc.Nodreg(x, gc.Types[gc.TINT32], dr)
+
+	// save current ax and dx if they are live
+	// and not the destination
+	*oldx = gc.Node{}
+
+	if r > 0 && !gc.Samereg(x, res) {
+		gc.Tempname(oldx, gc.Types[gc.TINT32])
+		gmove(x, oldx)
+	}
+
+	gc.Regalloc(x, t, x)
+}
+
+func restx(x *gc.Node, oldx *gc.Node) {
+	gc.Regfree(x)
+
+	if oldx.Op != 0 {
+		x.Type = gc.Types[gc.TINT32]
+		gmove(oldx, x)
+	}
+}
+
+/*
+ * 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) {
+	if gc.Is64(nl.Type) {
+		gc.Fatal("cgen_div %v", nl.Type)
+	}
+
+	var t *gc.Type
+	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(x86.REG_AX, &ax, &oldax, res, t)
+	var olddx gc.Node
+	var dx gc.Node
+	savex(x86.REG_DX, &dx, &olddx, res, t)
+	dodiv(op, nl, nr, res, &ax, &dx)
+	restx(&dx, &olddx)
+	restx(&ax, &oldax)
+}
+
+/*
+ * 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) {
+	if nl.Type.Width > 4 {
+		gc.Fatal("cgen_shift %v", nl.Type)
+	}
+
+	w := int(nl.Type.Width * 8)
+
+	a := optoas(op, nl.Type)
+
+	if nr.Op == gc.OLITERAL {
+		var n2 gc.Node
+		gc.Tempname(&n2, nl.Type)
+		gc.Cgen(nl, &n2)
+		var n1 gc.Node
+		gc.Regalloc(&n1, nl.Type, res)
+		gmove(&n2, &n1)
+		sc := uint64(nr.Int())
+		if sc >= uint64(nl.Type.Width*8) {
+			// large shift gets 2 shifts by width-1
+			gins(a, ncon(uint32(w)-1), &n1)
+
+			gins(a, ncon(uint32(w)-1), &n1)
+		} else {
+			gins(a, nr, &n1)
+		}
+		gmove(&n1, res)
+		gc.Regfree(&n1)
+		return
+	}
+
+	var oldcx gc.Node
+	var cx gc.Node
+	gc.Nodreg(&cx, gc.Types[gc.TUINT32], x86.REG_CX)
+	if gc.GetReg(x86.REG_CX) > 1 && !gc.Samereg(&cx, res) {
+		gc.Tempname(&oldcx, gc.Types[gc.TUINT32])
+		gmove(&cx, &oldcx)
+	}
+
+	var n1 gc.Node
+	var nt gc.Node
+	if nr.Type.Width > 4 {
+		gc.Tempname(&nt, nr.Type)
+		n1 = nt
+	} else {
+		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) {
+		gc.Regalloc(&n2, nl.Type, nil)
+	} else {
+		gc.Regalloc(&n2, nl.Type, res)
+	}
+	if nl.Ullman >= nr.Ullman {
+		gc.Cgen(nl, &n2)
+		gc.Cgen(nr, &n1)
+	} else {
+		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], x86.REG_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)
+			gmove(&lo, &n1)
+			splitclean()
+		}
+	} else {
+		var p1 *obj.Prog
+		if nr.Type.Width > 4 {
+			// delayed reg alloc
+			gc.Nodreg(&n1, gc.Types[gc.TUINT32], x86.REG_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)
+			gmove(&lo, &n1)
+			gins(optoas(gc.OCMP, gc.Types[gc.TUINT32]), &hi, ncon(0))
+			p2 := gc.Gbranch(optoas(gc.ONE, gc.Types[gc.TUINT32]), nil, +1)
+			gins(optoas(gc.OCMP, gc.Types[gc.TUINT32]), &n1, ncon(uint32(w)))
+			p1 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1)
+			splitclean()
+			gc.Patch(p2, gc.Pc)
+		} else {
+			gins(optoas(gc.OCMP, nr.Type), &n1, ncon(uint32(w)))
+			p1 = gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT32]), nil, +1)
+		}
+
+		if op == gc.ORSH && gc.Issigned[nl.Type.Etype] {
+			gins(a, ncon(uint32(w)-1), &n2)
+		} else {
+			gmove(ncon(0), &n2)
+		}
+
+		gc.Patch(p1, gc.Pc)
+	}
+
+	gins(a, &n1, &n2)
+
+	if oldcx.Op != 0 {
+		gmove(&oldcx, &cx)
+	}
+
+	gmove(&n2, res)
+
+	gc.Regfree(&n1)
+	gc.Regfree(&n2)
+}
+
+/*
+ * generate byte multiply:
+ *	res = nl * nr
+ * 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) 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] {
+		t = gc.Types[gc.TINT32]
+	}
+
+	// largest ullman on left.
+	if nl.Ullman < nr.Ullman {
+		tmp := nl
+		nl = nr
+		nr = tmp
+	}
+
+	var nt gc.Node
+	gc.Tempname(&nt, nl.Type)
+	gc.Cgen(nl, &nt)
+	var n1 gc.Node
+	gc.Regalloc(&n1, t, res)
+	gc.Cgen(nr, &n1)
+	var n2 gc.Node
+	gc.Regalloc(&n2, t, nil)
+	gmove(&nt, &n2)
+	a := optoas(op, t)
+	gins(a, &n2, &n1)
+	gc.Regfree(&n2)
+	gmove(&n1, res)
+	gc.Regfree(&n1)
+
+	return true
+}
+
+/*
+ * generate high multiply:
+ *   res = (nl*nr) >> width
+ */
+func cgen_hmul(nl *gc.Node, nr *gc.Node, res *gc.Node) {
+	var n1 gc.Node
+	var n2 gc.Node
+	var ax gc.Node
+	var dx gc.Node
+
+	t := nl.Type
+	a := optoas(gc.OHMUL, t)
+
+	// gen nl in n1.
+	gc.Tempname(&n1, t)
+
+	gc.Cgen(nl, &n1)
+
+	// gen nr in n2.
+	gc.Regalloc(&n2, t, res)
+
+	gc.Cgen(nr, &n2)
+
+	// multiply.
+	gc.Nodreg(&ax, t, x86.REG_AX)
+
+	gmove(&n2, &ax)
+	gins(a, &n1, nil)
+	gc.Regfree(&n2)
+
+	if t.Width == 1 {
+		// byte multiply behaves differently.
+		gc.Nodreg(&ax, t, x86.REG_AH)
+
+		gc.Nodreg(&dx, t, x86.REG_DX)
+		gmove(&ax, &dx)
+	}
+
+	gc.Nodreg(&dx, t, x86.REG_DX)
+	gmove(&dx, res)
+}
+
+/*
+ * generate floating-point operation.
+ */
+func cgen_float(n *gc.Node, res *gc.Node) {
+	nl := n.Left
+	switch n.Op {
+	case gc.OEQ,
+		gc.ONE,
+		gc.OLT,
+		gc.OLE,
+		gc.OGE:
+		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)
+		gc.Bgen(n, true, 0, p2)
+		gmove(gc.Nodbool(false), res)
+		gc.Patch(p3, gc.Pc)
+		return
+
+	case gc.OPLUS:
+		gc.Cgen(nl, res)
+		return
+
+	case gc.OCONV:
+		if gc.Eqtype(n.Type, nl.Type) || gc.Noconv(n.Type, nl.Type) {
+			gc.Cgen(nl, res)
+			return
+		}
+
+		var n2 gc.Node
+		gc.Tempname(&n2, n.Type)
+		var n1 gc.Node
+		gc.Mgen(nl, &n1, res)
+		gmove(&n1, &n2)
+		gmove(&n2, res)
+		gc.Mfree(&n1)
+		return
+	}
+
+	if gc.Thearch.Use387 {
+		cgen_float387(n, res)
+	} else {
+		cgen_floatsse(n, res)
+	}
+}
+
+// floating-point.  387 (not SSE2)
+func cgen_float387(n *gc.Node, res *gc.Node) {
+	var f0 gc.Node
+	var f1 gc.Node
+
+	nl := n.Left
+	nr := n.Right
+	gc.Nodreg(&f0, nl.Type, x86.REG_F0)
+	gc.Nodreg(&f1, n.Type, x86.REG_F0+1)
+	if nr != nil {
+		// binary
+		if nl.Ullman >= nr.Ullman {
+			gc.Cgen(nl, &f0)
+			if nr.Addable {
+				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 {
+				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
+	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
+}
+
+func cgen_floatsse(n *gc.Node, res *gc.Node) {
+	var a int
+
+	nl := n.Left
+	nr := n.Right
+	switch n.Op {
+	default:
+		gc.Dump("cgen_floatsse", n)
+		gc.Fatal("cgen_floatsse %v", gc.Oconv(int(n.Op), 0))
+		return
+
+	case gc.OMINUS,
+		gc.OCOM:
+		nr = gc.Nodintconst(-1)
+		gc.Convlit(&nr, n.Type)
+		a = foptoas(gc.OMUL, nl.Type, 0)
+		goto sbop
+
+		// symmetric binary
+	case gc.OADD,
+		gc.OMUL:
+		a = foptoas(int(n.Op), nl.Type, 0)
+
+		goto sbop
+
+		// asymmetric binary
+	case gc.OSUB,
+		gc.OMOD,
+		gc.ODIV:
+		a = foptoas(int(n.Op), nl.Type, 0)
+
+		goto abop
+	}
+
+sbop: // symmetric binary
+	if nl.Ullman < nr.Ullman || nl.Op == gc.OLITERAL {
+		r := nl
+		nl = nr
+		nr = r
+	}
+
+abop: // asymmetric binary
+	if nl.Ullman >= nr.Ullman {
+		var nt gc.Node
+		gc.Tempname(&nt, nl.Type)
+		gc.Cgen(nl, &nt)
+		var n2 gc.Node
+		gc.Mgen(nr, &n2, nil)
+		var n1 gc.Node
+		gc.Regalloc(&n1, nl.Type, res)
+		gmove(&nt, &n1)
+		gins(a, &n2, &n1)
+		gmove(&n1, res)
+		gc.Regfree(&n1)
+		gc.Mfree(&n2)
+	} else {
+		var n2 gc.Node
+		gc.Regalloc(&n2, nr.Type, res)
+		gc.Cgen(nr, &n2)
+		var n1 gc.Node
+		gc.Regalloc(&n1, nl.Type, nil)
+		gc.Cgen(nl, &n1)
+		gins(a, &n2, &n1)
+		gc.Regfree(&n2)
+		gmove(&n1, res)
+		gc.Regfree(&n1)
+	}
+
+	return
+}
+
+func bgen_float(n *gc.Node, wantTrue bool, likely int, to *obj.Prog) {
+	nl := n.Left
+	nr := n.Right
+	a := int(n.Op)
+	if !wantTrue {
+		// 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)
+
+		// No need to avoid re-genning ninit.
+		bgen_float(n, true, -likely, p2)
+
+		gc.Patch(gc.Gbranch(obj.AJMP, nil, 0), to)
+		gc.Patch(p2, gc.Pc)
+		return
+	}
+
+	if gc.Thearch.Use387 {
+		a = gc.Brrev(a) // because the args are stacked
+		if a == gc.OGE || a == gc.OGT {
+			// only < and <= work right with NaN; reverse if needed
+			nl, nr = nr, nl
+			a = gc.Brrev(a)
+		}
+
+		var ax, n2, tmp gc.Node
+		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)
+		if gc.Simsimtype(nr.Type) == gc.TFLOAT64 {
+			if nl.Ullman > nr.Ullman {
+				gc.Cgen(nl, &tmp)
+				gc.Cgen(nr, &tmp)
+				gins(x86.AFXCHD, &tmp, &n2)
+			} else {
+				gc.Cgen(nr, &tmp)
+				gc.Cgen(nl, &tmp)
+			}
+
+			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.
+			// This handles 32-bit comparison but presumably
+			// all the other ops have the same problem.
+			// We need to figure out what the right general
+			// solution is, besides telling people to use float64.
+			var t1 gc.Node
+			gc.Tempname(&t1, gc.Types[gc.TFLOAT32])
+
+			var t2 gc.Node
+			gc.Tempname(&t2, gc.Types[gc.TFLOAT32])
+			gc.Cgen(nr, &t1)
+			gc.Cgen(nl, &t2)
+			gmove(&t2, &tmp)
+			gins(x86.AFCOMFP, &t1, &tmp)
+			gins(x86.AFSTSW, nil, &ax)
+			gins(x86.ASAHF, nil, nil)
+		}
+	} else {
+		// Not 387
+		if !nl.Addable {
+			nl = gc.CgenTemp(nl)
+		}
+		if !nr.Addable {
+			nr = gc.CgenTemp(nr)
+		}
+
+		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
+			nl, nr = nr, nl
+			a = gc.Brrev(a)
+		}
+
+		gins(foptoas(gc.OCMP, nr.Type, 0), nl, nr)
+		if nl.Op == gc.OREGISTER {
+			gc.Regfree(nl)
+		}
+		gc.Regfree(nr)
+	}
+
+	switch a {
+	case 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)
+	case gc.ONE:
+		// either NE or P
+		gc.Patch(gc.Gbranch(x86.AJNE, nil, likely), to)
+		gc.Patch(gc.Gbranch(x86.AJPS, nil, likely), to)
+	default:
+		gc.Patch(gc.Gbranch(optoas(a, nr.Type), nil, likely), to)
+	}
+}
+
+// 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 := firstp; p != nil; p = p.Link {
+		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")
+		}
+
+		// check is
+		//	CMP arg, $0
+		//	JNE 2(PC) (likely)
+		//	MOV AX, 0
+		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 = x86.ACMPL
+		p.To.Type = obj.TYPE_CONST
+		p.To.Offset = 0
+		p1.As = x86.AJNE
+		p1.From.Type = obj.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.
+		// if possible, since we know arg is 0, use 0(arg),
+		// which will be shorter to encode than plain 0.
+		p2.As = x86.AMOVL
+
+		p2.From.Type = obj.TYPE_REG
+		p2.From.Reg = x86.REG_AX
+		if regtyp(&p.From) {
+			p2.To.Type = obj.TYPE_MEM
+			p2.To.Reg = p.From.Reg
+		} else {
+			p2.To.Type = obj.TYPE_MEM
+		}
+		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
+}
+
+// res = runtime.getg()
+func getg(res *gc.Node) {
+	var n1 gc.Node
+	gc.Regalloc(&n1, res.Type, res)
+	mov := optoas(gc.OAS, gc.Types[gc.Tptr])
+	p := gins(mov, nil, &n1)
+	p.From.Type = obj.TYPE_REG
+	p.From.Reg = x86.REG_TLS
+	p = gins(mov, nil, &n1)
+	p.From = p.To
+	p.From.Type = obj.TYPE_MEM
+	p.From.Index = x86.REG_TLS
+	p.From.Scale = 1
+	gmove(&n1, res)
+	gc.Regfree(&n1)
+}
diff --git a/src/cmd/compile/internal/x86/gsubr.go b/src/cmd/compile/internal/x86/gsubr.go
new file mode 100644
index 0000000..7593d04
--- /dev/null
+++ b/src/cmd/compile/internal/x86/gsubr.go
@@ -0,0 +1,1801 @@
+// Derived from Inferno utils/8c/txt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8c/txt.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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 x86
+
+import (
+	"cmd/compile/internal/big"
+	"cmd/compile/internal/gc"
+	"cmd/internal/obj"
+	"cmd/internal/obj/x86"
+	"fmt"
+)
+
+// TODO(rsc): Can make this bigger if we move
+// the text segment up higher in 8l for all GOOS.
+// At the same time, can raise StackBig in ../../runtime/stack.h.
+var unmappedzero uint32 = 4096
+
+// foptoas flags
+const (
+	Frev  = 1 << 0
+	Fpop  = 1 << 1
+	Fpop2 = 1 << 2
+)
+
+/*
+ * 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 := obj.AXXX
+	switch uint32(op)<<16 | uint32(gc.Simtype[t.Etype]) {
+	default:
+		gc.Fatal("optoas: no entry %v-%v", gc.Oconv(int(op), 0), t)
+
+	case gc.OADDR<<16 | gc.TPTR32:
+		a = x86.ALEAL
+
+	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 = x86.AJEQ
+
+	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 = x86.AJNE
+
+	case gc.OLT<<16 | gc.TINT8,
+		gc.OLT<<16 | gc.TINT16,
+		gc.OLT<<16 | gc.TINT32,
+		gc.OLT<<16 | gc.TINT64:
+		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 = x86.AJCS
+
+	case gc.OLE<<16 | gc.TINT8,
+		gc.OLE<<16 | gc.TINT16,
+		gc.OLE<<16 | gc.TINT32,
+		gc.OLE<<16 | gc.TINT64:
+		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 = x86.AJLS
+
+	case gc.OGT<<16 | gc.TINT8,
+		gc.OGT<<16 | gc.TINT16,
+		gc.OGT<<16 | gc.TINT32,
+		gc.OGT<<16 | gc.TINT64:
+		a = x86.AJGT
+
+	case gc.OGT<<16 | gc.TUINT8,
+		gc.OGT<<16 | gc.TUINT16,
+		gc.OGT<<16 | gc.TUINT32,
+		gc.OGT<<16 | gc.TUINT64,
+		gc.OLT<<16 | gc.TFLOAT32,
+		gc.OLT<<16 | gc.TFLOAT64:
+		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 = x86.AJGE
+
+	case gc.OGE<<16 | gc.TUINT8,
+		gc.OGE<<16 | gc.TUINT16,
+		gc.OGE<<16 | gc.TUINT32,
+		gc.OGE<<16 | gc.TUINT64,
+		gc.OLE<<16 | gc.TFLOAT32,
+		gc.OLE<<16 | gc.TFLOAT64:
+		a = x86.AJCC
+
+	case gc.OCMP<<16 | gc.TBOOL,
+		gc.OCMP<<16 | gc.TINT8,
+		gc.OCMP<<16 | gc.TUINT8:
+		a = x86.ACMPB
+
+	case gc.OCMP<<16 | gc.TINT16,
+		gc.OCMP<<16 | gc.TUINT16:
+		a = x86.ACMPW
+
+	case gc.OCMP<<16 | gc.TINT32,
+		gc.OCMP<<16 | gc.TUINT32,
+		gc.OCMP<<16 | gc.TPTR32:
+		a = x86.ACMPL
+
+	case gc.OAS<<16 | gc.TBOOL,
+		gc.OAS<<16 | gc.TINT8,
+		gc.OAS<<16 | gc.TUINT8:
+		a = x86.AMOVB
+
+	case gc.OAS<<16 | gc.TINT16,
+		gc.OAS<<16 | gc.TUINT16:
+		a = x86.AMOVW
+
+	case gc.OAS<<16 | gc.TINT32,
+		gc.OAS<<16 | gc.TUINT32,
+		gc.OAS<<16 | gc.TPTR32:
+		a = x86.AMOVL
+
+	case gc.OAS<<16 | gc.TFLOAT32:
+		a = x86.AMOVSS
+
+	case gc.OAS<<16 | gc.TFLOAT64:
+		a = x86.AMOVSD
+
+	case gc.OADD<<16 | gc.TINT8,
+		gc.OADD<<16 | gc.TUINT8:
+		a = x86.AADDB
+
+	case gc.OADD<<16 | gc.TINT16,
+		gc.OADD<<16 | gc.TUINT16:
+		a = x86.AADDW
+
+	case gc.OADD<<16 | gc.TINT32,
+		gc.OADD<<16 | gc.TUINT32,
+		gc.OADD<<16 | gc.TPTR32:
+		a = x86.AADDL
+
+	case gc.OSUB<<16 | gc.TINT8,
+		gc.OSUB<<16 | gc.TUINT8:
+		a = x86.ASUBB
+
+	case gc.OSUB<<16 | gc.TINT16,
+		gc.OSUB<<16 | gc.TUINT16:
+		a = x86.ASUBW
+
+	case gc.OSUB<<16 | gc.TINT32,
+		gc.OSUB<<16 | gc.TUINT32,
+		gc.OSUB<<16 | gc.TPTR32:
+		a = x86.ASUBL
+
+	case gc.OINC<<16 | gc.TINT8,
+		gc.OINC<<16 | gc.TUINT8:
+		a = x86.AINCB
+
+	case gc.OINC<<16 | gc.TINT16,
+		gc.OINC<<16 | gc.TUINT16:
+		a = x86.AINCW
+
+	case gc.OINC<<16 | gc.TINT32,
+		gc.OINC<<16 | gc.TUINT32,
+		gc.OINC<<16 | gc.TPTR32:
+		a = x86.AINCL
+
+	case gc.ODEC<<16 | gc.TINT8,
+		gc.ODEC<<16 | gc.TUINT8:
+		a = x86.ADECB
+
+	case gc.ODEC<<16 | gc.TINT16,
+		gc.ODEC<<16 | gc.TUINT16:
+		a = x86.ADECW
+
+	case gc.ODEC<<16 | gc.TINT32,
+		gc.ODEC<<16 | gc.TUINT32,
+		gc.ODEC<<16 | gc.TPTR32:
+		a = x86.ADECL
+
+	case gc.OCOM<<16 | gc.TINT8,
+		gc.OCOM<<16 | gc.TUINT8:
+		a = x86.ANOTB
+
+	case gc.OCOM<<16 | gc.TINT16,
+		gc.OCOM<<16 | gc.TUINT16:
+		a = x86.ANOTW
+
+	case gc.OCOM<<16 | gc.TINT32,
+		gc.OCOM<<16 | gc.TUINT32,
+		gc.OCOM<<16 | gc.TPTR32:
+		a = x86.ANOTL
+
+	case gc.OMINUS<<16 | gc.TINT8,
+		gc.OMINUS<<16 | gc.TUINT8:
+		a = x86.ANEGB
+
+	case gc.OMINUS<<16 | gc.TINT16,
+		gc.OMINUS<<16 | gc.TUINT16:
+		a = x86.ANEGW
+
+	case gc.OMINUS<<16 | gc.TINT32,
+		gc.OMINUS<<16 | gc.TUINT32,
+		gc.OMINUS<<16 | gc.TPTR32:
+		a = x86.ANEGL
+
+	case gc.OAND<<16 | gc.TINT8,
+		gc.OAND<<16 | gc.TUINT8:
+		a = x86.AANDB
+
+	case gc.OAND<<16 | gc.TINT16,
+		gc.OAND<<16 | gc.TUINT16:
+		a = x86.AANDW
+
+	case gc.OAND<<16 | gc.TINT32,
+		gc.OAND<<16 | gc.TUINT32,
+		gc.OAND<<16 | gc.TPTR32:
+		a = x86.AANDL
+
+	case gc.OOR<<16 | gc.TINT8,
+		gc.OOR<<16 | gc.TUINT8:
+		a = x86.AORB
+
+	case gc.OOR<<16 | gc.TINT16,
+		gc.OOR<<16 | gc.TUINT16:
+		a = x86.AORW
+
+	case gc.OOR<<16 | gc.TINT32,
+		gc.OOR<<16 | gc.TUINT32,
+		gc.OOR<<16 | gc.TPTR32:
+		a = x86.AORL
+
+	case gc.OXOR<<16 | gc.TINT8,
+		gc.OXOR<<16 | gc.TUINT8:
+		a = x86.AXORB
+
+	case gc.OXOR<<16 | gc.TINT16,
+		gc.OXOR<<16 | gc.TUINT16:
+		a = x86.AXORW
+
+	case gc.OXOR<<16 | gc.TINT32,
+		gc.OXOR<<16 | gc.TUINT32,
+		gc.OXOR<<16 | gc.TPTR32:
+		a = x86.AXORL
+
+	case gc.OLROT<<16 | gc.TINT8,
+		gc.OLROT<<16 | gc.TUINT8:
+		a = x86.AROLB
+
+	case gc.OLROT<<16 | gc.TINT16,
+		gc.OLROT<<16 | gc.TUINT16:
+		a = x86.AROLW
+
+	case gc.OLROT<<16 | gc.TINT32,
+		gc.OLROT<<16 | gc.TUINT32,
+		gc.OLROT<<16 | gc.TPTR32:
+		a = x86.AROLL
+
+	case gc.OLSH<<16 | gc.TINT8,
+		gc.OLSH<<16 | gc.TUINT8:
+		a = x86.ASHLB
+
+	case gc.OLSH<<16 | gc.TINT16,
+		gc.OLSH<<16 | gc.TUINT16:
+		a = x86.ASHLW
+
+	case gc.OLSH<<16 | gc.TINT32,
+		gc.OLSH<<16 | gc.TUINT32,
+		gc.OLSH<<16 | gc.TPTR32:
+		a = x86.ASHLL
+
+	case gc.ORSH<<16 | gc.TUINT8:
+		a = x86.ASHRB
+
+	case gc.ORSH<<16 | gc.TUINT16:
+		a = x86.ASHRW
+
+	case gc.ORSH<<16 | gc.TUINT32,
+		gc.ORSH<<16 | gc.TPTR32:
+		a = x86.ASHRL
+
+	case gc.ORSH<<16 | gc.TINT8:
+		a = x86.ASARB
+
+	case gc.ORSH<<16 | gc.TINT16:
+		a = x86.ASARW
+
+	case gc.ORSH<<16 | gc.TINT32:
+		a = x86.ASARL
+
+	case gc.OHMUL<<16 | gc.TINT8,
+		gc.OMUL<<16 | gc.TINT8,
+		gc.OMUL<<16 | gc.TUINT8:
+		a = x86.AIMULB
+
+	case gc.OHMUL<<16 | gc.TINT16,
+		gc.OMUL<<16 | gc.TINT16,
+		gc.OMUL<<16 | gc.TUINT16:
+		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 = x86.AIMULL
+
+	case gc.OHMUL<<16 | gc.TUINT8:
+		a = x86.AMULB
+
+	case gc.OHMUL<<16 | gc.TUINT16:
+		a = x86.AMULW
+
+	case gc.OHMUL<<16 | gc.TUINT32,
+		gc.OHMUL<<16 | gc.TPTR32:
+		a = x86.AMULL
+
+	case gc.ODIV<<16 | gc.TINT8,
+		gc.OMOD<<16 | gc.TINT8:
+		a = x86.AIDIVB
+
+	case gc.ODIV<<16 | gc.TUINT8,
+		gc.OMOD<<16 | gc.TUINT8:
+		a = x86.ADIVB
+
+	case gc.ODIV<<16 | gc.TINT16,
+		gc.OMOD<<16 | gc.TINT16:
+		a = x86.AIDIVW
+
+	case gc.ODIV<<16 | gc.TUINT16,
+		gc.OMOD<<16 | gc.TUINT16:
+		a = x86.ADIVW
+
+	case gc.ODIV<<16 | gc.TINT32,
+		gc.OMOD<<16 | gc.TINT32:
+		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 = x86.ADIVL
+
+	case gc.OEXTEND<<16 | gc.TINT16:
+		a = x86.ACWD
+
+	case gc.OEXTEND<<16 | gc.TINT32:
+		a = x86.ACDQ
+	}
+
+	return a
+}
+
+func foptoas(op int, t *gc.Type, flg int) int {
+	a := obj.AXXX
+	et := int(gc.Simtype[t.Etype])
+
+	if !gc.Thearch.Use387 {
+		switch uint32(op)<<16 | uint32(et) {
+		default:
+			gc.Fatal("foptoas-sse: no entry %v-%v", gc.Oconv(int(op), 0), t)
+
+		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
+	// two different floating-point registers, not memory.
+	// There the instruction only has a float64 form.
+	if flg&Fpop != 0 {
+		et = gc.TFLOAT64
+	}
+
+	// clear Frev if unneeded
+	switch op {
+	case gc.OADD,
+		gc.OMUL:
+		flg &^= Frev
+	}
+
+	switch uint32(op)<<16 | (uint32(et)<<8 | uint32(flg)) {
+	case gc.OADD<<16 | (gc.TFLOAT32<<8 | 0):
+		return x86.AFADDF
+
+	case gc.OADD<<16 | (gc.TFLOAT64<<8 | 0):
+		return x86.AFADDD
+
+	case gc.OADD<<16 | (gc.TFLOAT64<<8 | Fpop):
+		return x86.AFADDDP
+
+	case gc.OSUB<<16 | (gc.TFLOAT32<<8 | 0):
+		return x86.AFSUBF
+
+	case gc.OSUB<<16 | (gc.TFLOAT32<<8 | Frev):
+		return x86.AFSUBRF
+
+	case gc.OSUB<<16 | (gc.TFLOAT64<<8 | 0):
+		return x86.AFSUBD
+
+	case gc.OSUB<<16 | (gc.TFLOAT64<<8 | Frev):
+		return x86.AFSUBRD
+
+	case gc.OSUB<<16 | (gc.TFLOAT64<<8 | Fpop):
+		return x86.AFSUBDP
+
+	case gc.OSUB<<16 | (gc.TFLOAT64<<8 | (Fpop | Frev)):
+		return x86.AFSUBRDP
+
+	case gc.OMUL<<16 | (gc.TFLOAT32<<8 | 0):
+		return x86.AFMULF
+
+	case gc.OMUL<<16 | (gc.TFLOAT64<<8 | 0):
+		return x86.AFMULD
+
+	case gc.OMUL<<16 | (gc.TFLOAT64<<8 | Fpop):
+		return x86.AFMULDP
+
+	case gc.ODIV<<16 | (gc.TFLOAT32<<8 | 0):
+		return x86.AFDIVF
+
+	case gc.ODIV<<16 | (gc.TFLOAT32<<8 | Frev):
+		return x86.AFDIVRF
+
+	case gc.ODIV<<16 | (gc.TFLOAT64<<8 | 0):
+		return x86.AFDIVD
+
+	case gc.ODIV<<16 | (gc.TFLOAT64<<8 | Frev):
+		return x86.AFDIVRD
+
+	case gc.ODIV<<16 | (gc.TFLOAT64<<8 | Fpop):
+		return x86.AFDIVDP
+
+	case gc.ODIV<<16 | (gc.TFLOAT64<<8 | (Fpop | Frev)):
+		return x86.AFDIVRDP
+
+	case gc.OCMP<<16 | (gc.TFLOAT32<<8 | 0):
+		return x86.AFCOMF
+
+	case gc.OCMP<<16 | (gc.TFLOAT32<<8 | Fpop):
+		return x86.AFCOMFP
+
+	case gc.OCMP<<16 | (gc.TFLOAT64<<8 | 0):
+		return x86.AFCOMD
+
+	case gc.OCMP<<16 | (gc.TFLOAT64<<8 | Fpop):
+		return x86.AFCOMDP
+
+	case gc.OCMP<<16 | (gc.TFLOAT64<<8 | Fpop2):
+		return x86.AFCOMDPP
+
+	case gc.OMINUS<<16 | (gc.TFLOAT32<<8 | 0):
+		return x86.AFCHS
+
+	case gc.OMINUS<<16 | (gc.TFLOAT64<<8 | 0):
+		return x86.AFCHS
+	}
+
+	gc.Fatal("foptoas %v %v %#x", gc.Oconv(int(op), 0), t, flg)
+	return 0
+}
+
+var resvd = []int{
+	//	REG_DI,	// for movstring
+	//	REG_SI,	// for movstring
+
+	x86.REG_AX, // for divide
+	x86.REG_CX, // for shift
+	x86.REG_DX, // for divide, context
+	x86.REG_SP, // for stack
+}
+
+/*
+ * generate
+ *	as $c, reg
+ */
+func gconreg(as int, c int64, reg int) {
+	var n1 gc.Node
+	var n2 gc.Node
+
+	gc.Nodconst(&n1, gc.Types[gc.TINT64], c)
+	gc.Nodreg(&n2, gc.Types[gc.TINT64], reg)
+	gins(as, &n1, &n2)
+}
+
+/*
+ * 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)
+}
+
+func ginscmp(op int, t *gc.Type, n1, n2 *gc.Node, likely int) *obj.Prog {
+	if gc.Isint[t.Etype] || int(t.Etype) == gc.Tptr {
+		if (n1.Op == gc.OLITERAL || n1.Op == gc.OADDR && n1.Left.Op == gc.ONAME) && n2.Op != gc.OLITERAL {
+			// Reverse comparison to place constant (including address constant) last.
+			op = gc.Brrev(op)
+			n1, n2 = n2, n1
+		}
+	}
+
+	// General case.
+	var r1, r2, g1, g2 gc.Node
+	if n1.Op == gc.ONAME && n1.Class&gc.PHEAP == 0 || n1.Op == gc.OINDREG {
+		r1 = *n1
+	} else {
+		gc.Regalloc(&r1, t, n1)
+		gc.Regalloc(&g1, n1.Type, &r1)
+		gc.Cgen(n1, &g1)
+		gmove(&g1, &r1)
+	}
+	if n2.Op == gc.OLITERAL && gc.Isint[t.Etype] || n2.Op == gc.OADDR && n2.Left.Op == gc.ONAME && n2.Left.Class == gc.PEXTERN {
+		r2 = *n2
+	} else {
+		gc.Regalloc(&r2, t, n2)
+		gc.Regalloc(&g2, n1.Type, &r2)
+		gc.Cgen(n2, &g2)
+		gmove(&g2, &r2)
+	}
+	gins(optoas(gc.OCMP, t), &r1, &r2)
+	if r1.Op == gc.OREGISTER {
+		gc.Regfree(&g1)
+		gc.Regfree(&r1)
+	}
+	if r2.Op == gc.OREGISTER {
+		gc.Regfree(&g2)
+		gc.Regfree(&r2)
+	}
+	return gc.Gbranch(optoas(op, t), nil, likely)
+}
+
+/*
+ * swap node contents
+ */
+func nswap(a *gc.Node, b *gc.Node) {
+	t := *a
+	*a = *b
+	*b = t
+}
+
+/*
+ * return constant i node.
+ * overwritten by next call, but useful in calls to gins.
+ */
+
+var ncon_n gc.Node
+
+func ncon(i uint32) *gc.Node {
+	if ncon_n.Type == nil {
+		gc.Nodconst(&ncon_n, gc.Types[gc.TUINT32], 0)
+	}
+	ncon_n.SetInt(int64(i))
+	return &ncon_n
+}
+
+var sclean [10]gc.Node
+
+var nsclean int
+
+/*
+ * n is a 64-bit value.  fill in lo and hi to refer to its 32-bit halves.
+ */
+func split64(n *gc.Node, lo *gc.Node, hi *gc.Node) {
+	if !gc.Is64(n.Type) {
+		gc.Fatal("split64 %v", n.Type)
+	}
+
+	if nsclean >= len(sclean) {
+		gc.Fatal("split64 clean")
+	}
+	sclean[nsclean].Op = gc.OEMPTY
+	nsclean++
+	switch n.Op {
+	default:
+		switch n.Op {
+		default:
+			var n1 gc.Node
+			if !dotaddable(n, &n1) {
+				gc.Igen(n, &n1, nil)
+				sclean[nsclean-1] = n1
+			}
+
+			n = &n1
+
+		case gc.ONAME:
+			if n.Class == gc.PPARAMREF {
+				var n1 gc.Node
+				gc.Cgen(n.Name.Heapaddr, &n1)
+				sclean[nsclean-1] = n1
+				n = &n1
+			}
+
+			// nothing
+		case gc.OINDREG:
+			break
+		}
+
+		*lo = *n
+		*hi = *n
+		lo.Type = gc.Types[gc.TUINT32]
+		if n.Type.Etype == gc.TINT64 {
+			hi.Type = gc.Types[gc.TINT32]
+		} else {
+			hi.Type = gc.Types[gc.TUINT32]
+		}
+		hi.Xoffset += 4
+
+	case gc.OLITERAL:
+		var n1 gc.Node
+		n.Convconst(&n1, n.Type)
+		i := n1.Int()
+		gc.Nodconst(lo, gc.Types[gc.TUINT32], int64(uint32(i)))
+		i >>= 32
+		if n.Type.Etype == gc.TINT64 {
+			gc.Nodconst(hi, gc.Types[gc.TINT32], int64(int32(i)))
+		} else {
+			gc.Nodconst(hi, gc.Types[gc.TUINT32], int64(uint32(i)))
+		}
+	}
+}
+
+func splitclean() {
+	if nsclean <= 0 {
+		gc.Fatal("splitclean")
+	}
+	nsclean--
+	if sclean[nsclean].Op != gc.OEMPTY {
+		gc.Regfree(&sclean[nsclean])
+	}
+}
+
+// set up nodes representing fp constants
+var (
+	zerof        gc.Node
+	two63f       gc.Node
+	two64f       gc.Node
+	bignodes_did bool
+)
+
+func bignodes() {
+	if bignodes_did {
+		return
+	}
+	bignodes_did = true
+
+	gc.Nodconst(&zerof, gc.Types[gc.TINT64], 0)
+	zerof.Convconst(&zerof, gc.Types[gc.TFLOAT64])
+
+	var i big.Int
+	i.SetInt64(1)
+	i.Lsh(&i, 63)
+	var bigi gc.Node
+
+	gc.Nodconst(&bigi, gc.Types[gc.TUINT64], 0)
+	bigi.SetBigInt(&i)
+	bigi.Convconst(&two63f, gc.Types[gc.TFLOAT64])
+
+	gc.Nodconst(&bigi, gc.Types[gc.TUINT64], 0)
+	i.Lsh(&i, 1)
+	bigi.SetBigInt(&i)
+	bigi.Convconst(&two64f, gc.Types[gc.TFLOAT64])
+}
+
+func memname(n *gc.Node, t *gc.Type) {
+	gc.Tempname(n, t)
+	n.Sym = gc.Lookup("." + n.Sym.Name[1:]) // keep optimizer from registerizing
+	n.Orig.Sym = n.Sym
+}
+
+func gmove(f *gc.Node, t *gc.Node) {
+	if gc.Debug['M'] != 0 {
+		fmt.Printf("gmove %v -> %v\n", f, t)
+	}
+
+	ft := gc.Simsimtype(f.Type)
+	tt := gc.Simsimtype(t.Type)
+	cvt := t.Type
+
+	if gc.Iscomplex[ft] || gc.Iscomplex[tt] {
+		gc.Complexmove(f, t)
+		return
+	}
+
+	if gc.Isfloat[ft] || gc.Isfloat[tt] {
+		floatmove(f, t)
+		return
+	}
+
+	// cannot have two integer memory operands;
+	// except 64-bit, which always copies via registers anyway.
+	var r1 gc.Node
+	var a int
+	if gc.Isint[ft] && gc.Isint[tt] && !gc.Is64(f.Type) && !gc.Is64(t.Type) && gc.Ismem(f) && gc.Ismem(t) {
+		goto hard
+	}
+
+	// convert constant to desired type
+	if f.Op == gc.OLITERAL {
+		var con gc.Node
+		f.Convconst(&con, t.Type)
+		f = &con
+		ft = gc.Simsimtype(con.Type)
+	}
+
+	// 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:
+		// should not happen
+		gc.Fatal("gmove %v -> %v", f, t)
+		return
+
+		/*
+		 * integer copy and truncate
+		 */
+	case gc.TINT8<<16 | gc.TINT8, // same size
+		gc.TINT8<<16 | gc.TUINT8,
+		gc.TUINT8<<16 | gc.TINT8,
+		gc.TUINT8<<16 | gc.TUINT8:
+		a = x86.AMOVB
+
+	case gc.TINT16<<16 | gc.TINT8, // truncate
+		gc.TUINT16<<16 | gc.TINT8,
+		gc.TINT32<<16 | gc.TINT8,
+		gc.TUINT32<<16 | gc.TINT8,
+		gc.TINT16<<16 | gc.TUINT8,
+		gc.TUINT16<<16 | gc.TUINT8,
+		gc.TINT32<<16 | gc.TUINT8,
+		gc.TUINT32<<16 | gc.TUINT8:
+		a = x86.AMOVB
+
+		goto rsrc
+
+	case gc.TINT64<<16 | gc.TINT8, // truncate low word
+		gc.TUINT64<<16 | gc.TINT8,
+		gc.TINT64<<16 | gc.TUINT8,
+		gc.TUINT64<<16 | gc.TUINT8:
+		var flo gc.Node
+		var fhi gc.Node
+		split64(f, &flo, &fhi)
+
+		var r1 gc.Node
+		gc.Nodreg(&r1, t.Type, x86.REG_AX)
+		gmove(&flo, &r1)
+		gins(x86.AMOVB, &r1, t)
+		splitclean()
+		return
+
+	case gc.TINT16<<16 | gc.TINT16, // same size
+		gc.TINT16<<16 | gc.TUINT16,
+		gc.TUINT16<<16 | gc.TINT16,
+		gc.TUINT16<<16 | gc.TUINT16:
+		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 = x86.AMOVW
+
+		goto rsrc
+
+	case gc.TINT64<<16 | gc.TINT16, // truncate low word
+		gc.TUINT64<<16 | gc.TINT16,
+		gc.TINT64<<16 | gc.TUINT16,
+		gc.TUINT64<<16 | gc.TUINT16:
+		var flo gc.Node
+		var fhi gc.Node
+		split64(f, &flo, &fhi)
+
+		var r1 gc.Node
+		gc.Nodreg(&r1, t.Type, x86.REG_AX)
+		gmove(&flo, &r1)
+		gins(x86.AMOVW, &r1, t)
+		splitclean()
+		return
+
+	case gc.TINT32<<16 | gc.TINT32, // same size
+		gc.TINT32<<16 | gc.TUINT32,
+		gc.TUINT32<<16 | gc.TINT32,
+		gc.TUINT32<<16 | gc.TUINT32:
+		a = x86.AMOVL
+
+	case gc.TINT64<<16 | gc.TINT32, // truncate
+		gc.TUINT64<<16 | gc.TINT32,
+		gc.TINT64<<16 | gc.TUINT32,
+		gc.TUINT64<<16 | gc.TUINT32:
+		var fhi gc.Node
+		var flo gc.Node
+		split64(f, &flo, &fhi)
+
+		var r1 gc.Node
+		gc.Nodreg(&r1, t.Type, x86.REG_AX)
+		gmove(&flo, &r1)
+		gins(x86.AMOVL, &r1, t)
+		splitclean()
+		return
+
+	case gc.TINT64<<16 | gc.TINT64, // same size
+		gc.TINT64<<16 | gc.TUINT64,
+		gc.TUINT64<<16 | gc.TINT64,
+		gc.TUINT64<<16 | gc.TUINT64:
+		var fhi gc.Node
+		var flo gc.Node
+		split64(f, &flo, &fhi)
+
+		var tlo gc.Node
+		var thi gc.Node
+		split64(t, &tlo, &thi)
+		if f.Op == gc.OLITERAL {
+			gins(x86.AMOVL, &flo, &tlo)
+			gins(x86.AMOVL, &fhi, &thi)
+		} else {
+			// Implementation of conversion-free x = y for int64 or uint64 x.
+			// This is generated by the code that copies small values out of closures,
+			// and that code has DX live, so avoid DX and use CX instead.
+			var r1 gc.Node
+			gc.Nodreg(&r1, gc.Types[gc.TUINT32], x86.REG_AX)
+			var r2 gc.Node
+			gc.Nodreg(&r2, gc.Types[gc.TUINT32], x86.REG_CX)
+			gins(x86.AMOVL, &flo, &r1)
+			gins(x86.AMOVL, &fhi, &r2)
+			gins(x86.AMOVL, &r1, &tlo)
+			gins(x86.AMOVL, &r2, &thi)
+		}
+
+		splitclean()
+		splitclean()
+		return
+
+		/*
+		 * integer up-conversions
+		 */
+	case gc.TINT8<<16 | gc.TINT16, // sign extend int8
+		gc.TINT8<<16 | gc.TUINT16:
+		a = x86.AMOVBWSX
+
+		goto rdst
+
+	case gc.TINT8<<16 | gc.TINT32,
+		gc.TINT8<<16 | gc.TUINT32:
+		a = x86.AMOVBLSX
+		goto rdst
+
+	case gc.TINT8<<16 | gc.TINT64, // convert via int32
+		gc.TINT8<<16 | gc.TUINT64:
+		cvt = gc.Types[gc.TINT32]
+
+		goto hard
+
+	case gc.TUINT8<<16 | gc.TINT16, // zero extend uint8
+		gc.TUINT8<<16 | gc.TUINT16:
+		a = x86.AMOVBWZX
+
+		goto rdst
+
+	case gc.TUINT8<<16 | gc.TINT32,
+		gc.TUINT8<<16 | gc.TUINT32:
+		a = x86.AMOVBLZX
+		goto rdst
+
+	case gc.TUINT8<<16 | gc.TINT64, // convert via uint32
+		gc.TUINT8<<16 | gc.TUINT64:
+		cvt = gc.Types[gc.TUINT32]
+
+		goto hard
+
+	case gc.TINT16<<16 | gc.TINT32, // sign extend int16
+		gc.TINT16<<16 | gc.TUINT32:
+		a = x86.AMOVWLSX
+
+		goto rdst
+
+	case gc.TINT16<<16 | gc.TINT64, // convert via int32
+		gc.TINT16<<16 | gc.TUINT64:
+		cvt = gc.Types[gc.TINT32]
+
+		goto hard
+
+	case gc.TUINT16<<16 | gc.TINT32, // zero extend uint16
+		gc.TUINT16<<16 | gc.TUINT32:
+		a = x86.AMOVWLZX
+
+		goto rdst
+
+	case gc.TUINT16<<16 | gc.TINT64, // convert via uint32
+		gc.TUINT16<<16 | gc.TUINT64:
+		cvt = gc.Types[gc.TUINT32]
+
+		goto hard
+
+	case gc.TINT32<<16 | gc.TINT64, // sign extend int32
+		gc.TINT32<<16 | gc.TUINT64:
+		var thi gc.Node
+		var tlo gc.Node
+		split64(t, &tlo, &thi)
+
+		var flo gc.Node
+		gc.Nodreg(&flo, tlo.Type, x86.REG_AX)
+		var fhi gc.Node
+		gc.Nodreg(&fhi, thi.Type, x86.REG_DX)
+		gmove(f, &flo)
+		gins(x86.ACDQ, nil, nil)
+		gins(x86.AMOVL, &flo, &tlo)
+		gins(x86.AMOVL, &fhi, &thi)
+		splitclean()
+		return
+
+	case gc.TUINT32<<16 | gc.TINT64, // zero extend uint32
+		gc.TUINT32<<16 | gc.TUINT64:
+		var tlo gc.Node
+		var thi gc.Node
+		split64(t, &tlo, &thi)
+
+		gmove(f, &tlo)
+		gins(x86.AMOVL, ncon(0), &thi)
+		splitclean()
+		return
+	}
+
+	gins(a, f, t)
+	return
+
+	// requires register source
+rsrc:
+	gc.Regalloc(&r1, f.Type, t)
+
+	gmove(f, &r1)
+	gins(a, &r1, t)
+	gc.Regfree(&r1)
+	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 floatmove(f *gc.Node, t *gc.Node) {
+	var r1 gc.Node
+
+	ft := gc.Simsimtype(f.Type)
+	tt := gc.Simsimtype(t.Type)
+	cvt := t.Type
+
+	// cannot have two floating point memory operands.
+	if gc.Isfloat[ft] && gc.Isfloat[tt] && gc.Ismem(f) && gc.Ismem(t) {
+		goto hard
+	}
+
+	// convert constant to desired type
+	if f.Op == gc.OLITERAL {
+		var con gc.Node
+		f.Convconst(&con, t.Type)
+		f = &con
+		ft = gc.Simsimtype(con.Type)
+
+		// some constants can't move directly to memory.
+		if gc.Ismem(t) {
+			// float constants come from memory.
+			if gc.Isfloat[tt] {
+				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:
+		if gc.Thearch.Use387 {
+			floatmove_387(f, t)
+		} else {
+			floatmove_sse(f, t)
+		}
+		return
+
+		// float to very long integer.
+	case gc.TFLOAT32<<16 | gc.TINT64,
+		gc.TFLOAT64<<16 | gc.TINT64:
+		if f.Op == gc.OREGISTER {
+			cvt = f.Type
+			goto hardmem
+		}
+
+		var r1 gc.Node
+		gc.Nodreg(&r1, gc.Types[ft], x86.REG_F0)
+		if ft == gc.TFLOAT32 {
+			gins(x86.AFMOVF, f, &r1)
+		} else {
+			gins(x86.AFMOVD, f, &r1)
+		}
+
+		// set round to zero mode during conversion
+		var t1 gc.Node
+		memname(&t1, gc.Types[gc.TUINT16])
+
+		var t2 gc.Node
+		memname(&t2, gc.Types[gc.TUINT16])
+		gins(x86.AFSTCW, nil, &t1)
+		gins(x86.AMOVW, ncon(0xf7f), &t2)
+		gins(x86.AFLDCW, &t2, nil)
+		if tt == gc.TINT16 {
+			gins(x86.AFMOVWP, &r1, t)
+		} else if tt == gc.TINT32 {
+			gins(x86.AFMOVLP, &r1, t)
+		} else {
+			gins(x86.AFMOVVP, &r1, t)
+		}
+		gins(x86.AFLDCW, &t1, nil)
+		return
+
+	case gc.TFLOAT32<<16 | gc.TUINT64,
+		gc.TFLOAT64<<16 | gc.TUINT64:
+		if !gc.Ismem(f) {
+			cvt = f.Type
+			goto hardmem
+		}
+
+		bignodes()
+		var f0 gc.Node
+		gc.Nodreg(&f0, gc.Types[ft], x86.REG_F0)
+		var f1 gc.Node
+		gc.Nodreg(&f1, gc.Types[ft], x86.REG_F0+1)
+		var ax gc.Node
+		gc.Nodreg(&ax, gc.Types[gc.TUINT16], x86.REG_AX)
+
+		if ft == gc.TFLOAT32 {
+			gins(x86.AFMOVF, f, &f0)
+		} else {
+			gins(x86.AFMOVD, f, &f0)
+		}
+
+		// if 0 > v { answer = 0 }
+		gins(x86.AFMOVD, &zerof, &f0)
+
+		gins(x86.AFUCOMIP, &f0, &f1)
+		p1 := gc.Gbranch(optoas(gc.OGT, gc.Types[tt]), nil, 0)
+
+		// if 1<<64 <= v { answer = 0 too }
+		gins(x86.AFMOVD, &two64f, &f0)
+
+		gins(x86.AFUCOMIP, &f0, &f1)
+		p2 := gc.Gbranch(optoas(gc.OGT, gc.Types[tt]), nil, 0)
+		gc.Patch(p1, gc.Pc)
+		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(x86.AMOVL, ncon(0), &tlo)
+		gins(x86.AMOVL, ncon(0), &thi)
+		splitclean()
+		p1 = gc.Gbranch(obj.AJMP, nil, 0)
+		gc.Patch(p2, gc.Pc)
+
+		// in range; algorithm is:
+		//	if small enough, use native float64 -> int64 conversion.
+		//	otherwise, subtract 2^63, convert, and add it back.
+
+		// set round to zero mode during conversion
+		var t1 gc.Node
+		memname(&t1, gc.Types[gc.TUINT16])
+
+		var t2 gc.Node
+		memname(&t2, gc.Types[gc.TUINT16])
+		gins(x86.AFSTCW, nil, &t1)
+		gins(x86.AMOVW, ncon(0xf7f), &t2)
+		gins(x86.AFLDCW, &t2, nil)
+
+		// actual work
+		gins(x86.AFMOVD, &two63f, &f0)
+
+		gins(x86.AFUCOMIP, &f0, &f1)
+		p2 = gc.Gbranch(optoas(gc.OLE, gc.Types[tt]), nil, 0)
+		gins(x86.AFMOVVP, &f0, t)
+		p3 := gc.Gbranch(obj.AJMP, nil, 0)
+		gc.Patch(p2, gc.Pc)
+		gins(x86.AFMOVD, &two63f, &f0)
+		gins(x86.AFSUBDP, &f0, &f1)
+		gins(x86.AFMOVVP, &f0, t)
+		split64(t, &tlo, &thi)
+		gins(x86.AXORL, ncon(0x80000000), &thi) // + 2^63
+		gc.Patch(p3, gc.Pc)
+		splitclean()
+
+		// restore rounding mode
+		gins(x86.AFLDCW, &t1, nil)
+
+		gc.Patch(p1, gc.Pc)
+		return
+
+		/*
+		 * integer to float
+		 */
+	case gc.TINT64<<16 | gc.TFLOAT32,
+		gc.TINT64<<16 | gc.TFLOAT64:
+		if t.Op == gc.OREGISTER {
+			goto hardmem
+		}
+		var f0 gc.Node
+		gc.Nodreg(&f0, t.Type, x86.REG_F0)
+		gins(x86.AFMOVV, f, &f0)
+		if tt == gc.TFLOAT32 {
+			gins(x86.AFMOVFP, &f0, t)
+		} else {
+			gins(x86.AFMOVDP, &f0, t)
+		}
+		return
+
+		// algorithm is:
+	//	if small enough, use native int64 -> float64 conversion.
+	//	otherwise, halve (rounding to odd?), convert, and double.
+	case gc.TUINT64<<16 | gc.TFLOAT32,
+		gc.TUINT64<<16 | gc.TFLOAT64:
+		var ax gc.Node
+		gc.Nodreg(&ax, gc.Types[gc.TUINT32], x86.REG_AX)
+
+		var dx gc.Node
+		gc.Nodreg(&dx, gc.Types[gc.TUINT32], x86.REG_DX)
+		var cx gc.Node
+		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(x86.ACMPL, &thi, ncon(0))
+		p1 := gc.Gbranch(x86.AJLT, nil, 0)
+
+		// native
+		var r1 gc.Node
+		gc.Nodreg(&r1, gc.Types[tt], x86.REG_F0)
+
+		gins(x86.AFMOVV, &t1, &r1)
+		if tt == gc.TFLOAT32 {
+			gins(x86.AFMOVFP, &r1, t)
+		} else {
+			gins(x86.AFMOVDP, &r1, t)
+		}
+		p2 := gc.Gbranch(obj.AJMP, nil, 0)
+
+		// simulated
+		gc.Patch(p1, gc.Pc)
+
+		gmove(&tlo, &ax)
+		gmove(&thi, &dx)
+		p1 = gins(x86.ASHRL, ncon(1), &ax)
+		p1.From.Index = x86.REG_DX // double-width shift DX -> AX
+		p1.From.Scale = 0
+		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], x86.REG_F0)
+		var r2 gc.Node
+		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(x86.AFMOVFP, &r1, t)
+		} else {
+			gins(x86.AFMOVDP, &r1, t)
+		}
+		gc.Patch(p2, gc.Pc)
+		splitclean()
+		return
+	}
+
+	// requires register intermediate
+hard:
+	gc.Regalloc(&r1, cvt, t)
+
+	gmove(f, &r1)
+	gmove(&r1, t)
+	gc.Regfree(&r1)
+	return
+
+	// requires memory intermediate
+hardmem:
+	gc.Tempname(&r1, cvt)
+
+	gmove(f, &r1)
+	gmove(&r1, t)
+	return
+}
+
+func floatmove_387(f *gc.Node, t *gc.Node) {
+	var r1 gc.Node
+	var a int
+
+	ft := gc.Simsimtype(f.Type)
+	tt := gc.Simsimtype(t.Type)
+	cvt := t.Type
+
+	switch uint32(ft)<<16 | uint32(tt) {
+	default:
+		goto fatal
+
+		/*
+		* float to integer
+		 */
+	case gc.TFLOAT32<<16 | gc.TINT16,
+		gc.TFLOAT32<<16 | gc.TINT32,
+		gc.TFLOAT32<<16 | gc.TINT64,
+		gc.TFLOAT64<<16 | gc.TINT16,
+		gc.TFLOAT64<<16 | gc.TINT32,
+		gc.TFLOAT64<<16 | gc.TINT64:
+		if t.Op == gc.OREGISTER {
+			goto hardmem
+		}
+		var r1 gc.Node
+		gc.Nodreg(&r1, gc.Types[ft], x86.REG_F0)
+		if f.Op != gc.OREGISTER {
+			if ft == gc.TFLOAT32 {
+				gins(x86.AFMOVF, f, &r1)
+			} else {
+				gins(x86.AFMOVD, f, &r1)
+			}
+		}
+
+		// set round to zero mode during conversion
+		var t1 gc.Node
+		memname(&t1, gc.Types[gc.TUINT16])
+
+		var t2 gc.Node
+		memname(&t2, gc.Types[gc.TUINT16])
+		gins(x86.AFSTCW, nil, &t1)
+		gins(x86.AMOVW, ncon(0xf7f), &t2)
+		gins(x86.AFLDCW, &t2, nil)
+		if tt == gc.TINT16 {
+			gins(x86.AFMOVWP, &r1, t)
+		} else if tt == gc.TINT32 {
+			gins(x86.AFMOVLP, &r1, t)
+		} else {
+			gins(x86.AFMOVVP, &r1, t)
+		}
+		gins(x86.AFLDCW, &t1, nil)
+		return
+
+		// convert via int32.
+	case gc.TFLOAT32<<16 | gc.TINT8,
+		gc.TFLOAT32<<16 | gc.TUINT16,
+		gc.TFLOAT32<<16 | gc.TUINT8,
+		gc.TFLOAT64<<16 | gc.TINT8,
+		gc.TFLOAT64<<16 | gc.TUINT16,
+		gc.TFLOAT64<<16 | gc.TUINT8:
+		var t1 gc.Node
+		gc.Tempname(&t1, gc.Types[gc.TINT32])
+
+		gmove(f, &t1)
+		switch tt {
+		default:
+			gc.Fatal("gmove %v", t)
+
+		case gc.TINT8:
+			gins(x86.ACMPL, &t1, ncon(-0x80&(1<<32-1)))
+			p1 := gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TINT32]), nil, -1)
+			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)
+			gc.Patch(p2, gc.Pc)
+			gmove(ncon(-0x80&(1<<32-1)), &t1)
+			gc.Patch(p3, gc.Pc)
+			gmove(&t1, t)
+
+		case gc.TUINT8:
+			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(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)
+		}
+
+		return
+
+		// convert via int64.
+	case gc.TFLOAT32<<16 | gc.TUINT32,
+		gc.TFLOAT64<<16 | gc.TUINT32:
+		cvt = gc.Types[gc.TINT64]
+
+		goto hardmem
+
+		/*
+		 * integer to float
+		 */
+	case gc.TINT16<<16 | gc.TFLOAT32,
+		gc.TINT16<<16 | gc.TFLOAT64,
+		gc.TINT32<<16 | gc.TFLOAT32,
+		gc.TINT32<<16 | gc.TFLOAT64,
+		gc.TINT64<<16 | gc.TFLOAT32,
+		gc.TINT64<<16 | gc.TFLOAT64:
+		if t.Op != gc.OREGISTER {
+			goto hard
+		}
+		if f.Op == gc.OREGISTER {
+			cvt = f.Type
+			goto hardmem
+		}
+
+		switch ft {
+		case gc.TINT16:
+			a = x86.AFMOVW
+
+		case gc.TINT32:
+			a = x86.AFMOVL
+
+		default:
+			a = x86.AFMOVV
+		}
+
+		// convert via int32 memory
+	case gc.TINT8<<16 | gc.TFLOAT32,
+		gc.TINT8<<16 | gc.TFLOAT64,
+		gc.TUINT16<<16 | gc.TFLOAT32,
+		gc.TUINT16<<16 | gc.TFLOAT64,
+		gc.TUINT8<<16 | gc.TFLOAT32,
+		gc.TUINT8<<16 | gc.TFLOAT64:
+		cvt = gc.Types[gc.TINT32]
+
+		goto hardmem
+
+		// convert via int64 memory
+	case gc.TUINT32<<16 | gc.TFLOAT32,
+		gc.TUINT32<<16 | gc.TFLOAT64:
+		cvt = gc.Types[gc.TINT64]
+
+		goto hardmem
+
+		// The way the code generator uses floating-point
+	// registers, a move from F0 to F0 is intended as a no-op.
+	// On the x86, it's not: it pushes a second copy of F0
+	// on the floating point stack.  So toss it away here.
+	// Also, F0 is the *only* register we ever evaluate
+	// into, so we should only see register/register as F0/F0.
+	/*
+	 * float to float
+	 */
+	case gc.TFLOAT32<<16 | gc.TFLOAT32,
+		gc.TFLOAT64<<16 | gc.TFLOAT64:
+		if gc.Ismem(f) && gc.Ismem(t) {
+			goto hard
+		}
+		if f.Op == gc.OREGISTER && t.Op == gc.OREGISTER {
+			if f.Reg != x86.REG_F0 || t.Reg != x86.REG_F0 {
+				goto fatal
+			}
+			return
+		}
+
+		a = x86.AFMOVF
+		if ft == gc.TFLOAT64 {
+			a = x86.AFMOVD
+		}
+		if gc.Ismem(t) {
+			if f.Op != gc.OREGISTER || f.Reg != x86.REG_F0 {
+				gc.Fatal("gmove %v", f)
+			}
+			a = x86.AFMOVFP
+			if ft == gc.TFLOAT64 {
+				a = x86.AFMOVDP
+			}
+		}
+
+	case gc.TFLOAT32<<16 | gc.TFLOAT64:
+		if gc.Ismem(f) && gc.Ismem(t) {
+			goto hard
+		}
+		if f.Op == gc.OREGISTER && t.Op == gc.OREGISTER {
+			if f.Reg != x86.REG_F0 || t.Reg != x86.REG_F0 {
+				goto fatal
+			}
+			return
+		}
+
+		if f.Op == gc.OREGISTER {
+			gins(x86.AFMOVDP, f, t)
+		} else {
+			gins(x86.AFMOVF, f, t)
+		}
+		return
+
+	case gc.TFLOAT64<<16 | gc.TFLOAT32:
+		if gc.Ismem(f) && gc.Ismem(t) {
+			goto hard
+		}
+		if f.Op == gc.OREGISTER && t.Op == gc.OREGISTER {
+			var r1 gc.Node
+			gc.Tempname(&r1, gc.Types[gc.TFLOAT32])
+			gins(x86.AFMOVFP, f, &r1)
+			gins(x86.AFMOVF, &r1, t)
+			return
+		}
+
+		if f.Op == gc.OREGISTER {
+			gins(x86.AFMOVFP, f, t)
+		} else {
+			gins(x86.AFMOVD, f, t)
+		}
+		return
+	}
+
+	gins(a, f, t)
+	return
+
+	// requires register intermediate
+hard:
+	gc.Regalloc(&r1, cvt, t)
+
+	gmove(f, &r1)
+	gmove(&r1, t)
+	gc.Regfree(&r1)
+	return
+
+	// requires memory intermediate
+hardmem:
+	gc.Tempname(&r1, cvt)
+
+	gmove(f, &r1)
+	gmove(&r1, t)
+	return
+
+	// should not happen
+fatal:
+	gc.Fatal("gmove %v -> %v", gc.Nconv(f, obj.FmtLong), gc.Nconv(t, obj.FmtLong))
+
+	return
+}
+
+func floatmove_sse(f *gc.Node, t *gc.Node) {
+	var r1 gc.Node
+	var cvt *gc.Type
+	var a int
+
+	ft := gc.Simsimtype(f.Type)
+	tt := gc.Simsimtype(t.Type)
+
+	switch uint32(ft)<<16 | uint32(tt) {
+	// should not happen
+	default:
+		gc.Fatal("gmove %v -> %v", f, t)
+
+		return
+
+		// convert via int32.
+	/*
+	* float to integer
+	 */
+	case gc.TFLOAT32<<16 | gc.TINT16,
+		gc.TFLOAT32<<16 | gc.TINT8,
+		gc.TFLOAT32<<16 | gc.TUINT16,
+		gc.TFLOAT32<<16 | gc.TUINT8,
+		gc.TFLOAT64<<16 | gc.TINT16,
+		gc.TFLOAT64<<16 | gc.TINT8,
+		gc.TFLOAT64<<16 | gc.TUINT16,
+		gc.TFLOAT64<<16 | gc.TUINT8:
+		cvt = gc.Types[gc.TINT32]
+
+		goto hard
+
+		// convert via int64.
+	case gc.TFLOAT32<<16 | gc.TUINT32,
+		gc.TFLOAT64<<16 | gc.TUINT32:
+		cvt = gc.Types[gc.TINT64]
+
+		goto hardmem
+
+	case gc.TFLOAT32<<16 | gc.TINT32:
+		a = x86.ACVTTSS2SL
+		goto rdst
+
+	case gc.TFLOAT64<<16 | gc.TINT32:
+		a = x86.ACVTTSD2SL
+		goto rdst
+
+		// convert via int32 memory
+	/*
+	 * integer to float
+	 */
+	case gc.TINT8<<16 | gc.TFLOAT32,
+		gc.TINT8<<16 | gc.TFLOAT64,
+		gc.TINT16<<16 | gc.TFLOAT32,
+		gc.TINT16<<16 | gc.TFLOAT64,
+		gc.TUINT16<<16 | gc.TFLOAT32,
+		gc.TUINT16<<16 | gc.TFLOAT64,
+		gc.TUINT8<<16 | gc.TFLOAT32,
+		gc.TUINT8<<16 | gc.TFLOAT64:
+		cvt = gc.Types[gc.TINT32]
+
+		goto hard
+
+		// convert via int64 memory
+	case gc.TUINT32<<16 | gc.TFLOAT32,
+		gc.TUINT32<<16 | gc.TFLOAT64:
+		cvt = gc.Types[gc.TINT64]
+
+		goto hardmem
+
+	case gc.TINT32<<16 | gc.TFLOAT32:
+		a = x86.ACVTSL2SS
+		goto rdst
+
+	case gc.TINT32<<16 | gc.TFLOAT64:
+		a = x86.ACVTSL2SD
+		goto rdst
+
+		/*
+		 * float to float
+		 */
+	case gc.TFLOAT32<<16 | gc.TFLOAT32:
+		a = x86.AMOVSS
+
+	case gc.TFLOAT64<<16 | gc.TFLOAT64:
+		a = x86.AMOVSD
+
+	case gc.TFLOAT32<<16 | gc.TFLOAT64:
+		a = x86.ACVTSS2SD
+		goto rdst
+
+	case gc.TFLOAT64<<16 | gc.TFLOAT32:
+		a = x86.ACVTSD2SS
+		goto rdst
+	}
+
+	gins(a, f, t)
+	return
+
+	// requires register intermediate
+hard:
+	gc.Regalloc(&r1, cvt, t)
+
+	gmove(f, &r1)
+	gmove(&r1, t)
+	gc.Regfree(&r1)
+	return
+
+	// requires memory intermediate
+hardmem:
+	gc.Tempname(&r1, cvt)
+
+	gmove(f, &r1)
+	gmove(&r1, t)
+	return
+
+	// requires register destination
+rdst:
+	gc.Regalloc(&r1, t.Type, t)
+
+	gins(a, f, &r1)
+	gmove(&r1, t)
+	gc.Regfree(&r1)
+	return
+}
+
+func samaddr(f *gc.Node, t *gc.Node) bool {
+	if f.Op != t.Op {
+		return false
+	}
+
+	switch f.Op {
+	case gc.OREGISTER:
+		if f.Reg != t.Reg {
+			break
+		}
+		return true
+	}
+
+	return false
+}
+
+/*
+ * generate one instruction:
+ *	as f, t
+ */
+func gins(as int, f *gc.Node, t *gc.Node) *obj.Prog {
+	if as == x86.AFMOVF && f != nil && f.Op == gc.OREGISTER && t != nil && t.Op == gc.OREGISTER {
+		gc.Fatal("gins MOVF reg, reg")
+	}
+	if as == x86.ACVTSD2SS && f != nil && f.Op == gc.OLITERAL {
+		gc.Fatal("gins CVTSD2SS const")
+	}
+	if as == x86.AMOVSD && t != nil && t.Op == gc.OREGISTER && t.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 x86.AMOVB,
+		x86.AMOVW,
+		x86.AMOVL:
+		if f != nil && t != nil && samaddr(f, t) {
+			return nil
+		}
+
+	case x86.ALEAL:
+		if f != nil && gc.Isconst(f, gc.CTNIL) {
+			gc.Fatal("gins LEAL nil %v", f.Type)
+		}
+	}
+
+	p := gc.Prog(as)
+	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 x86.AMOVB:
+		w = 1
+
+	case x86.AMOVW:
+		w = 2
+
+	case x86.AMOVL:
+		w = 4
+	}
+
+	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, p.From.Width, p.To.Width)
+	}
+
+	if p.To.Type == obj.TYPE_ADDR && w > 0 {
+		gc.Fatal("bad use of addr: %v", p)
+	}
+
+	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
+	}
+
+	var oary [10]int64
+	var nn *gc.Node
+	o := gc.Dotoffset(n, oary[:], &nn)
+	if nn != nil && nn.Addable && o == 1 && oary[0] >= 0 {
+		*n1 = *nn
+		n1.Type = n.Type
+		n1.Xoffset += oary[0]
+		return true
+	}
+
+	return false
+}
+
+func sudoclean() {
+}
+
+func sudoaddable(as int, n *gc.Node, a *obj.Addr) bool {
+	*a = obj.Addr{}
+	return false
+}
diff --git a/src/cmd/compile/internal/x86/peep.go b/src/cmd/compile/internal/x86/peep.go
new file mode 100644
index 0000000..8b50eab
--- /dev/null
+++ b/src/cmd/compile/internal/x86/peep.go
@@ -0,0 +1,814 @@
+// 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 at 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 at 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 x86
+
+import (
+	"cmd/compile/internal/gc"
+	"cmd/internal/obj"
+	"cmd/internal/obj/x86"
+	"fmt"
+)
+
+const (
+	REGEXT      = 0
+	exregoffset = x86.REG_DI
+)
+
+var gactive uint32
+
+// do we need the carry bit
+func needc(p *obj.Prog) bool {
+	for p != nil {
+		if p.Info.Flags&gc.UseCarry != 0 {
+			return true
+		}
+		if p.Info.Flags&(gc.SetCarry|gc.KillCarry) != 0 {
+			return false
+		}
+		p = p.Link
+	}
+
+	return false
+}
+
+func rnops(r *gc.Flow) *gc.Flow {
+	if r != nil {
+		var p *obj.Prog
+		var r1 *gc.Flow
+		for {
+			p = r.Prog
+			if p.As != obj.ANOP || p.From.Type != obj.TYPE_NONE || p.To.Type != obj.TYPE_NONE {
+				break
+			}
+			r1 = gc.Uniqs(r)
+			if r1 == nil {
+				break
+			}
+			r = r1
+		}
+	}
+
+	return r
+}
+
+func peep(firstp *obj.Prog) {
+	g := gc.Flowstart(firstp, nil)
+	if g == nil {
+		return
+	}
+	gactive = 0
+
+	// byte, word arithmetic elimination.
+	elimshortmov(g)
+
+	// constant propagation
+	// find MOV $con,R followed by
+	// another MOV $con,R without
+	// setting R in the interim
+	var p *obj.Prog
+	for r := g.Start; r != nil; r = r.Link {
+		p = r.Prog
+		switch p.As {
+		case x86.ALEAL:
+			if regtyp(&p.To) {
+				if p.From.Sym != nil {
+					if p.From.Index == x86.REG_NONE {
+						conprop(r)
+					}
+				}
+			}
+
+		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)
+				}
+			}
+		}
+	}
+
+	var r1 *gc.Flow
+	var p1 *obj.Prog
+	var r *gc.Flow
+	var t int
+loop1:
+	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
+		gc.Dumpit("loop1", g.Start, 0)
+	}
+
+	t = 0
+	for r = g.Start; r != nil; r = r.Link {
+		p = r.Prog
+		switch p.As {
+		case x86.AMOVL,
+			x86.AMOVSS,
+			x86.AMOVSD:
+			if regtyp(&p.To) {
+				if regtyp(&p.From) {
+					if copyprop(g, r) {
+						excise(r)
+						t++
+					} else if subprop(r) && copyprop(g, r) {
+						excise(r)
+						t++
+					}
+				}
+			}
+
+		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 = x86.AMOVL
+						t++
+					}
+				}
+			}
+
+		case x86.AADDL,
+			x86.AADDW:
+			if p.From.Type != obj.TYPE_CONST || needc(p.Link) {
+				break
+			}
+			if p.From.Offset == -1 {
+				if p.As == x86.AADDL {
+					p.As = x86.ADECL
+				} else {
+					p.As = x86.ADECW
+				}
+				p.From = obj.Addr{}
+				break
+			}
+
+			if p.From.Offset == 1 {
+				if p.As == x86.AADDL {
+					p.As = x86.AINCL
+				} else {
+					p.As = x86.AINCW
+				}
+				p.From = obj.Addr{}
+				break
+			}
+
+		case x86.ASUBL,
+			x86.ASUBW:
+			if p.From.Type != obj.TYPE_CONST || needc(p.Link) {
+				break
+			}
+			if p.From.Offset == -1 {
+				if p.As == x86.ASUBL {
+					p.As = x86.AINCL
+				} else {
+					p.As = x86.AINCW
+				}
+				p.From = obj.Addr{}
+				break
+			}
+
+			if p.From.Offset == 1 {
+				if p.As == x86.ASUBL {
+					p.As = x86.ADECL
+				} else {
+					p.As = x86.ADECW
+				}
+				p.From = obj.Addr{}
+				break
+			}
+		}
+	}
+
+	if t != 0 {
+		goto loop1
+	}
+
+	// MOVSD removal.
+	// We never use packed registers, so a MOVSD between registers
+	// can be replaced by MOVAPD, which moves the pair of float64s
+	// instead of just the lower one.  We only use the lower one, but
+	// 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 == x86.AMOVSD {
+			if regtyp(&p.From) {
+				if regtyp(&p.To) {
+					p.As = x86.AMOVAPD
+				}
+			}
+		}
+	}
+
+	gc.Flowend(g)
+}
+
+func excise(r *gc.Flow) {
+	p := 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 {
+	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.
+// movb is simulated by the linker
+// when a register other than ax, bx, cx, dx
+// is used, so rewrite to other instructions
+// when possible.  a movb into a register
+// can smash the entire 64-bit register without
+// causing any trouble.
+func elimshortmov(g *gc.Graph) {
+	var p *obj.Prog
+
+	for r := g.Start; r != nil; r = r.Link {
+		p = r.Prog
+		if regtyp(&p.To) {
+			switch p.As {
+			case x86.AINCB,
+				x86.AINCW:
+				p.As = x86.AINCL
+
+			case x86.ADECB,
+				x86.ADECW:
+				p.As = x86.ADECL
+
+			case x86.ANEGB,
+				x86.ANEGW:
+				p.As = x86.ANEGL
+
+			case x86.ANOTB,
+				x86.ANOTW:
+				p.As = x86.ANOTL
+			}
+
+			if regtyp(&p.From) || p.From.Type == obj.TYPE_CONST {
+				// move or artihmetic into partial register.
+				// from another register or constant can be movl.
+				// 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 x86.AMOVB,
+					x86.AMOVW:
+					p.As = x86.AMOVL
+
+				case x86.AADDB,
+					x86.AADDW:
+					if !needc(p.Link) {
+						p.As = x86.AADDL
+					}
+
+				case x86.ASUBB,
+					x86.ASUBW:
+					if !needc(p.Link) {
+						p.As = x86.ASUBL
+					}
+
+				case x86.AMULB,
+					x86.AMULW:
+					p.As = x86.AMULL
+
+				case x86.AIMULB,
+					x86.AIMULW:
+					p.As = x86.AIMULL
+
+				case x86.AANDB,
+					x86.AANDW:
+					p.As = x86.AANDL
+
+				case x86.AORB,
+					x86.AORW:
+					p.As = x86.AORL
+
+				case x86.AXORB,
+					x86.AXORW:
+					p.As = x86.AXORL
+
+				case x86.ASHLB,
+					x86.ASHLW:
+					p.As = x86.ASHLL
+				}
+			} else {
+				// explicit zero extension
+				switch p.As {
+				case x86.AMOVB:
+					p.As = x86.AMOVBLZX
+
+				case x86.AMOVW:
+					p.As = x86.AMOVWLZX
+				}
+			}
+		}
+	}
+}
+
+/*
+ * the idea is to substitute
+ * one register for another
+ * from one MOV to another
+ *	MOV	a, R0
+ *	ADD	b, R0	/ no use of R1
+ *	MOV	R0, R1
+ * would be converted to
+ *	MOV	a, R1
+ *	ADD	b, R1
+ *	MOV	R1, R0
+ * hopefully, then the former or latter MOV
+ * will be eliminated by copy propagation.
+ */
+func subprop(r0 *gc.Flow) bool {
+	p := r0.Prog
+	v1 := &p.From
+	if !regtyp(v1) {
+		return false
+	}
+	v2 := &p.To
+	if !regtyp(v2) {
+		return false
+	}
+	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)
+		}
+		if gc.Uniqs(r) == nil {
+			break
+		}
+		p = r.Prog
+		if p.As == obj.AVARDEF || p.As == obj.AVARKILL {
+			continue
+		}
+		if p.Info.Flags&gc.Call != 0 {
+			return false
+		}
+
+		if p.Info.Reguse|p.Info.Regset != 0 {
+			return false
+		}
+
+		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) {
+			break
+		}
+		if copysub(&p.From, v1, v2, 0) != 0 || copysub(&p.To, v1, v2, 0) != 0 {
+			break
+		}
+	}
+
+	return false
+}
+
+/*
+ * The idea is to remove redundant copies.
+ *	v1->v2	F=0
+ *	(use v2	s/v2/v1/)*
+ *	set v1	F=1
+ *	use v2	return fail
+ *	-----------------
+ *	v1->v2	F=0
+ *	(use v2	s/v2/v1/)*
+ *	set v1	F=1
+ *	set v2	return success
+ */
+func copyprop(g *gc.Graph, r0 *gc.Flow) bool {
+	p := r0.Prog
+	v1 := &p.From
+	v2 := &p.To
+	if copyas(v1, v2) {
+		return true
+	}
+	gactive++
+	return copy1(v1, v2, r0.S1, 0)
+}
+
+func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool {
+	if uint32(r.Active) == gactive {
+		if gc.Debug['P'] != 0 {
+			fmt.Printf("act set; return 1\n")
+		}
+		return true
+	}
+
+	r.Active = int32(gactive)
+	if gc.Debug['P'] != 0 {
+		fmt.Printf("copy %v->%v f=%d\n", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), f)
+	}
+	var t int
+	var p *obj.Prog
+	for ; r != nil; r = r.S1 {
+		p = r.Prog
+		if gc.Debug['P'] != 0 {
+			fmt.Printf("%v", p)
+		}
+		if f == 0 && gc.Uniqp(r) == nil {
+			f = 1
+			if gc.Debug['P'] != 0 {
+				fmt.Printf("; merge; f=%d", f)
+			}
+		}
+
+		t = copyu(p, v2, nil)
+		switch t {
+		case 2: /* rar, can't split */
+			if gc.Debug['P'] != 0 {
+				fmt.Printf("; %v rar; return 0\n", gc.Ctxt.Dconv(v2))
+			}
+			return false
+
+		case 3: /* set */
+			if gc.Debug['P'] != 0 {
+				fmt.Printf("; %v set; return 1\n", gc.Ctxt.Dconv(v2))
+			}
+			return true
+
+		case 1, /* used, substitute */
+			4: /* use and set */
+			if f != 0 {
+				if gc.Debug['P'] == 0 {
+					return false
+				}
+				if t == 4 {
+					fmt.Printf("; %v used+set and f=%d; return 0\n", gc.Ctxt.Dconv(v2), f)
+				} else {
+					fmt.Printf("; %v used and f=%d; return 0\n", gc.Ctxt.Dconv(v2), f)
+				}
+				return false
+			}
+
+			if copyu(p, v2, v1) != 0 {
+				if gc.Debug['P'] != 0 {
+					fmt.Printf("; sub fail; return 0\n")
+				}
+				return false
+			}
+
+			if gc.Debug['P'] != 0 {
+				fmt.Printf("; sub %v/%v", gc.Ctxt.Dconv(v2), gc.Ctxt.Dconv(v1))
+			}
+			if t == 4 {
+				if gc.Debug['P'] != 0 {
+					fmt.Printf("; %v used+set; return 1\n", gc.Ctxt.Dconv(v2))
+				}
+				return true
+			}
+		}
+
+		if f == 0 {
+			t = copyu(p, v1, nil)
+			if f == 0 && (t == 2 || t == 3 || t == 4) {
+				f = 1
+				if gc.Debug['P'] != 0 {
+					fmt.Printf("; %v set and !f; f=%d", gc.Ctxt.Dconv(v1), f)
+				}
+			}
+		}
+
+		if gc.Debug['P'] != 0 {
+			fmt.Printf("\n")
+		}
+		if r.S2 != nil {
+			if !copy1(v1, v2, r.S2, f) {
+				return false
+			}
+		}
+	}
+
+	return true
+}
+
+/*
+ * return
+ * 1 if v only used (and substitute),
+ * 2 if read-alter-rewrite
+ * 3 if set
+ * 4 if set and used
+ * 0 otherwise (not touched)
+ */
+func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
+	switch p.As {
+	case obj.AJMP:
+		if s != nil {
+			if copysub(&p.To, v, s, 1) != 0 {
+				return 1
+			}
+			return 0
+		}
+
+		if copyau(&p.To, v) {
+			return 1
+		}
+		return 0
+
+	case obj.ARET:
+		if s != nil {
+			return 1
+		}
+		return 3
+
+	case obj.ACALL:
+		if REGEXT != 0 /*TypeKind(100016)*/ && v.Type == obj.TYPE_REG && v.Reg <= REGEXT && v.Reg > exregoffset {
+			return 2
+		}
+		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 {
+			return 2
+		}
+
+		if s != nil {
+			if copysub(&p.To, v, s, 1) != 0 {
+				return 1
+			}
+			return 0
+		}
+
+		if copyau(&p.To, v) {
+			return 4
+		}
+		return 3
+
+	case obj.ATEXT:
+		if x86.REGARG >= 0 && v.Type == obj.TYPE_REG && v.Reg == x86.REGARG {
+			return 3
+		}
+		return 0
+	}
+
+	if p.As == obj.AVARDEF || p.As == obj.AVARKILL {
+		return 0
+	}
+
+	if (p.Info.Reguse|p.Info.Regset)&RtoB(int(v.Reg)) != 0 {
+		return 2
+	}
+
+	if p.Info.Flags&gc.LeftAddr != 0 {
+		if copyas(&p.From, v) {
+			return 2
+		}
+	}
+
+	if p.Info.Flags&(gc.RightRead|gc.RightWrite) == gc.RightRead|gc.RightWrite {
+		if copyas(&p.To, v) {
+			return 2
+		}
+	}
+
+	if p.Info.Flags&gc.RightWrite != 0 {
+		if copyas(&p.To, v) {
+			if s != nil {
+				return copysub(&p.From, v, s, 1)
+			}
+			if copyau(&p.From, v) {
+				return 4
+			}
+			return 3
+		}
+	}
+
+	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
+			}
+			return copysub(&p.To, v, s, 1)
+		}
+
+		if copyau(&p.From, v) {
+			return 1
+		}
+		if copyau(&p.To, v) {
+			return 1
+		}
+	}
+
+	return 0
+}
+
+/*
+ * direct reference,
+ * could be set/use depending on
+ * semantics
+ */
+func copyas(a *obj.Addr, v *obj.Addr) bool {
+	if x86.REG_AL <= a.Reg && a.Reg <= x86.REG_BL {
+		gc.Fatal("use of byte register")
+	}
+	if x86.REG_AL <= v.Reg && v.Reg <= x86.REG_BL {
+		gc.Fatal("use of byte register")
+	}
+
+	if a.Type != v.Type || a.Name != v.Name || a.Reg != v.Reg {
+		return false
+	}
+	if regtyp(v) {
+		return true
+	}
+	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
+		}
+	}
+	return false
+}
+
+func sameaddr(a *obj.Addr, v *obj.Addr) bool {
+	if a.Type != v.Type || a.Name != v.Name || a.Reg != v.Reg {
+		return false
+	}
+	if regtyp(v) {
+		return true
+	}
+	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
+		}
+	}
+	return false
+}
+
+/*
+ * either direct or indirect
+ */
+func copyau(a *obj.Addr, v *obj.Addr) bool {
+	if copyas(a, v) {
+		return true
+	}
+	if regtyp(v) {
+		if (a.Type == obj.TYPE_MEM || a.Type == obj.TYPE_ADDR) && a.Reg == v.Reg {
+			return true
+		}
+		if a.Index == v.Reg {
+			return true
+		}
+	}
+
+	return false
+}
+
+/*
+ * substitute s for v in a
+ * return failure to substitute
+ */
+func copysub(a *obj.Addr, v *obj.Addr, s *obj.Addr, f int) int {
+	if copyas(a, v) {
+		reg := int(s.Reg)
+		if reg >= x86.REG_AX && reg <= x86.REG_DI || reg >= x86.REG_X0 && reg <= x86.REG_X7 {
+			if f != 0 {
+				a.Reg = int16(reg)
+			}
+		}
+
+		return 0
+	}
+
+	if regtyp(v) {
+		reg := int(v.Reg)
+		if (a.Type == obj.TYPE_MEM || a.Type == obj.TYPE_ADDR) && int(a.Reg) == reg {
+			if (s.Reg == x86.REG_BP) && a.Index != obj.TYPE_NONE {
+				return 1 /* can't use BP-base with index */
+			}
+			if f != 0 {
+				a.Reg = s.Reg
+			}
+		}
+
+		//			return 0;
+		if int(a.Index) == reg {
+			if f != 0 {
+				a.Index = s.Reg
+			}
+			return 0
+		}
+
+		return 0
+	}
+
+	return 0
+}
+
+func conprop(r0 *gc.Flow) {
+	var p *obj.Prog
+	var t int
+
+	p0 := r0.Prog
+	v0 := &p0.To
+	r := r0
+
+loop:
+	r = gc.Uniqs(r)
+	if r == nil || r == r0 {
+		return
+	}
+	if gc.Uniqp(r) == nil {
+		return
+	}
+
+	p = r.Prog
+	t = copyu(p, v0, nil)
+	switch t {
+	case 0, // miss
+		1: // use
+		goto loop
+
+	case 2, // rar
+		4: // use and set
+		break
+
+	case 3: // set
+		if p.As == p0.As {
+			if p.From.Type == p0.From.Type {
+				if p.From.Reg == p0.From.Reg {
+					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.Val.(float64) == p0.From.Val.(float64) {
+									if p.From.Index == p0.From.Index {
+										excise(r)
+										goto loop
+									}
+								}
+							}
+						}
+					}
+				}
+			}
+		}
+	}
+}
+
+func smallindir(a *obj.Addr, reg *obj.Addr) bool {
+	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 == x86.REG_SP
+}
diff --git a/src/cmd/compile/internal/x86/prog.go b/src/cmd/compile/internal/x86/prog.go
new file mode 100644
index 0000000..f96a1aa
--- /dev/null
+++ b/src/cmd/compile/internal/x86/prog.go
@@ -0,0 +1,292 @@
+// 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 x86
+
+import (
+	"cmd/compile/internal/gc"
+	"cmd/internal/obj"
+	"cmd/internal/obj/x86"
+)
+
+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)
+	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 = [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.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
+
+	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.
+	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.
+	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(p *obj.Prog) {
+	info := &p.Info
+	*info = progtable[p.As]
+	if info.Flags == 0 {
+		gc.Fatal("unknown instruction %v", p)
+	}
+
+	if (info.Flags&gc.ShiftCX != 0) && p.From.Type != obj.TYPE_CONST {
+		info.Reguse |= CX
+	}
+
+	if info.Flags&gc.ImulAXDX != 0 {
+		if p.To.Type == obj.TYPE_NONE {
+			info.Reguse |= AX
+			info.Regset |= AX | DX
+		} else {
+			info.Flags |= RightRdwr
+		}
+	}
+
+	// Addressing makes some registers used.
+	if p.From.Type == obj.TYPE_MEM && p.From.Name == obj.NAME_NONE {
+		info.Regindex |= RtoB(int(p.From.Reg))
+	}
+	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 != x86.REG_NONE {
+		info.Regindex |= RtoB(int(p.To.Index))
+	}
+}
diff --git a/src/cmd/compile/internal/x86/reg.go b/src/cmd/compile/internal/x86/reg.go
new file mode 100644
index 0000000..b3a5fdf
--- /dev/null
+++ b/src/cmd/compile/internal/x86/reg.go
@@ -0,0 +1,110 @@
+// 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 at 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 at 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 x86
+
+import "cmd/internal/obj/x86"
+import "cmd/compile/internal/gc"
+
+const (
+	NREGVAR = 16 /* 8 integer + 8 floating */
+)
+
+var regname = []string{
+	".ax",
+	".cx",
+	".dx",
+	".bx",
+	".sp",
+	".bp",
+	".si",
+	".di",
+	".x0",
+	".x1",
+	".x2",
+	".x3",
+	".x4",
+	".x5",
+	".x6",
+	".x7",
+}
+
+func regnames(n *int) []string {
+	*n = NREGVAR
+	return regname
+}
+
+func excludedregs() uint64 {
+	return RtoB(x86.REG_SP)
+}
+
+func doregbits(r int) uint64 {
+	b := uint64(0)
+	if r >= x86.REG_AX && r <= x86.REG_DI {
+		b |= RtoB(r)
+	} 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 < x86.REG_AX || r > x86.REG_DI {
+		return 0
+	}
+	return 1 << uint(r-x86.REG_AX)
+}
+
+func BtoR(b uint64) int {
+	b &= 0xff
+	if b == 0 {
+		return 0
+	}
+	return gc.Bitno(b) + x86.REG_AX
+}
+
+func FtoB(f int) uint64 {
+	if f < x86.REG_X0 || f > x86.REG_X7 {
+		return 0
+	}
+	return 1 << uint(f-x86.REG_X0+8)
+}
+
+func BtoF(b uint64) int {
+	b &= 0xFF00
+	if b == 0 {
+		return 0
+	}
+	return gc.Bitno(b) - 8 + x86.REG_X0
+}
diff --git a/src/cmd/compile/main.go b/src/cmd/compile/main.go
new file mode 100644
index 0000000..7b69c34
--- /dev/null
+++ b/src/cmd/compile/main.go
@@ -0,0 +1,34 @@
+// 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 (
+	"cmd/compile/internal/amd64"
+	"cmd/compile/internal/arm"
+	"cmd/compile/internal/arm64"
+	"cmd/compile/internal/ppc64"
+	"cmd/compile/internal/x86"
+	"cmd/internal/obj"
+	"fmt"
+	"os"
+)
+
+func main() {
+	switch obj.Getgoarch() {
+	default:
+		fmt.Fprintf(os.Stderr, "compile: unknown architecture %q\n", obj.Getgoarch())
+		os.Exit(2)
+	case "386":
+		x86.Main()
+	case "amd64", "amd64p32":
+		amd64.Main()
+	case "arm":
+		arm.Main()
+	case "arm64":
+		arm64.Main()
+	case "ppc64", "ppc64le":
+		ppc64.Main()
+	}
+}
diff --git a/src/cmd/cover/cover.go b/src/cmd/cover/cover.go
new file mode 100644
index 0000000..31ec434
--- /dev/null
+++ b/src/cmd/cover/cover.go
@@ -0,0 +1,722 @@
+// 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 main
+
+import (
+	"bytes"
+	"flag"
+	"fmt"
+	"go/ast"
+	"go/parser"
+	"go/printer"
+	"go/token"
+	"io"
+	"io/ioutil"
+	"log"
+	"os"
+	"path/filepath"
+	"sort"
+	"strconv"
+	"strings"
+)
+
+const usageMessage = "" +
+	`Usage of 'go tool cover':
+Given a coverage profile produced by 'go test':
+	go test -coverprofile=c.out
+
+Open a web browser displaying annotated source code:
+	go tool cover -html=c.out
+
+Write out an HTML file instead of launching a web browser:
+	go tool cover -html=c.out -o coverage.html
+
+Display coverage percentages to stdout for each function:
+	go tool cover -func=c.out
+
+Finally, to generate modified source code with coverage annotations
+(what go test -cover does):
+	go tool cover -mode=set -var=CoverageVariableName program.go
+`
+
+func usage() {
+	fmt.Fprintln(os.Stderr, usageMessage)
+	fmt.Fprintln(os.Stderr, "Flags:")
+	flag.PrintDefaults()
+	fmt.Fprintln(os.Stderr, "\n  Only one of -html, -func, or -mode may be set.")
+	os.Exit(2)
+}
+
+var (
+	mode    = flag.String("mode", "", "coverage mode: set, count, atomic")
+	varVar  = flag.String("var", "GoCover", "name of coverage variable to generate")
+	output  = flag.String("o", "", "file for output; default: stdout")
+	htmlOut = flag.String("html", "", "generate HTML representation of coverage profile")
+	funcOut = flag.String("func", "", "output coverage profile information for each function")
+)
+
+var profile string // The profile to read; the value of -html or -func
+
+var counterStmt func(*File, ast.Expr) ast.Stmt
+
+const (
+	atomicPackagePath = "sync/atomic"
+	atomicPackageName = "_cover_atomic_"
+)
+
+func main() {
+	flag.Usage = usage
+	flag.Parse()
+
+	// Usage information when no arguments.
+	if flag.NFlag() == 0 && flag.NArg() == 0 {
+		flag.Usage()
+	}
+
+	err := parseFlags()
+	if err != nil {
+		fmt.Fprintln(os.Stderr, err)
+		fmt.Fprintln(os.Stderr, `For usage information, run "go tool cover -help"`)
+		os.Exit(2)
+	}
+
+	// Generate coverage-annotated source.
+	if *mode != "" {
+		annotate(flag.Arg(0))
+		return
+	}
+
+	// Output HTML or function coverage information.
+	if *htmlOut != "" {
+		err = htmlOutput(profile, *output)
+	} else {
+		err = funcOutput(profile, *output)
+	}
+
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "cover: %v\n", err)
+		os.Exit(2)
+	}
+}
+
+// parseFlags sets the profile and counterStmt globals and performs validations.
+func parseFlags() error {
+	profile = *htmlOut
+	if *funcOut != "" {
+		if profile != "" {
+			return fmt.Errorf("too many options")
+		}
+		profile = *funcOut
+	}
+
+	// Must either display a profile or rewrite Go source.
+	if (profile == "") == (*mode == "") {
+		return fmt.Errorf("too many options")
+	}
+
+	if *mode != "" {
+		switch *mode {
+		case "set":
+			counterStmt = setCounterStmt
+		case "count":
+			counterStmt = incCounterStmt
+		case "atomic":
+			counterStmt = atomicCounterStmt
+		default:
+			return fmt.Errorf("unknown -mode %v", *mode)
+		}
+
+		if flag.NArg() == 0 {
+			return fmt.Errorf("missing source file")
+		} else if flag.NArg() == 1 {
+			return nil
+		}
+	} else if flag.NArg() == 0 {
+		return nil
+	}
+	return fmt.Errorf("too many arguments")
+}
+
+// Block represents the information about a basic block to be recorded in the analysis.
+// Note: Our definition of basic block is based on control structures; we don't break
+// apart && and ||. We could but it doesn't seem important enough to bother.
+type Block struct {
+	startByte token.Pos
+	endByte   token.Pos
+	numStmt   int
+}
+
+// File is a wrapper for the state of a file used in the parser.
+// The basic parse tree walker is a method of this type.
+type File struct {
+	fset      *token.FileSet
+	name      string // Name of file.
+	astFile   *ast.File
+	blocks    []Block
+	atomicPkg string // Package name for "sync/atomic" in this file.
+}
+
+// Visit implements the ast.Visitor interface.
+func (f *File) Visit(node ast.Node) ast.Visitor {
+	switch n := node.(type) {
+	case *ast.BlockStmt:
+		// If it's a switch or select, the body is a list of case clauses; don't tag the block itself.
+		if len(n.List) > 0 {
+			switch n.List[0].(type) {
+			case *ast.CaseClause: // switch
+				for _, n := range n.List {
+					clause := n.(*ast.CaseClause)
+					clause.Body = f.addCounters(clause.Pos(), clause.End(), clause.Body, false)
+				}
+				return f
+			case *ast.CommClause: // select
+				for _, n := range n.List {
+					clause := n.(*ast.CommClause)
+					clause.Body = f.addCounters(clause.Pos(), clause.End(), clause.Body, false)
+				}
+				return f
+			}
+		}
+		n.List = f.addCounters(n.Lbrace, n.Rbrace+1, n.List, true) // +1 to step past closing brace.
+	case *ast.IfStmt:
+		ast.Walk(f, n.Body)
+		if n.Else == nil {
+			return nil
+		}
+		// The elses are special, because if we have
+		//	if x {
+		//	} else if y {
+		//	}
+		// we want to cover the "if y". To do this, we need a place to drop the counter,
+		// so we add a hidden block:
+		//	if x {
+		//	} else {
+		//		if y {
+		//		}
+		//	}
+		switch stmt := n.Else.(type) {
+		case *ast.IfStmt:
+			block := &ast.BlockStmt{
+				Lbrace: n.Body.End(), // Start at end of the "if" block so the covered part looks like it starts at the "else".
+				List:   []ast.Stmt{stmt},
+				Rbrace: stmt.End(),
+			}
+			n.Else = block
+		case *ast.BlockStmt:
+			stmt.Lbrace = n.Body.End() // Start at end of the "if" block so the covered part looks like it starts at the "else".
+		default:
+			panic("unexpected node type in if")
+		}
+		ast.Walk(f, n.Else)
+		return nil
+	case *ast.SelectStmt:
+		// Don't annotate an empty select - creates a syntax error.
+		if n.Body == nil || len(n.Body.List) == 0 {
+			return nil
+		}
+	case *ast.SwitchStmt:
+		// Don't annotate an empty switch - creates a syntax error.
+		if n.Body == nil || len(n.Body.List) == 0 {
+			return nil
+		}
+	case *ast.TypeSwitchStmt:
+		// Don't annotate an empty type switch - creates a syntax error.
+		if n.Body == nil || len(n.Body.List) == 0 {
+			return nil
+		}
+	}
+	return f
+}
+
+// unquote returns the unquoted string.
+func unquote(s string) string {
+	t, err := strconv.Unquote(s)
+	if err != nil {
+		log.Fatalf("cover: improperly quoted string %q\n", s)
+	}
+	return t
+}
+
+// addImport adds an import for the specified path, if one does not already exist, and returns
+// the local package name.
+func (f *File) addImport(path string) string {
+	// Does the package already import it?
+	for _, s := range f.astFile.Imports {
+		if unquote(s.Path.Value) == path {
+			if s.Name != nil {
+				return s.Name.Name
+			}
+			return filepath.Base(path)
+		}
+	}
+	newImport := &ast.ImportSpec{
+		Name: ast.NewIdent(atomicPackageName),
+		Path: &ast.BasicLit{
+			Kind:  token.STRING,
+			Value: fmt.Sprintf("%q", path),
+		},
+	}
+	impDecl := &ast.GenDecl{
+		Tok: token.IMPORT,
+		Specs: []ast.Spec{
+			newImport,
+		},
+	}
+	// Make the new import the first Decl in the file.
+	astFile := f.astFile
+	astFile.Decls = append(astFile.Decls, nil)
+	copy(astFile.Decls[1:], astFile.Decls[0:])
+	astFile.Decls[0] = impDecl
+	astFile.Imports = append(astFile.Imports, newImport)
+
+	// Now refer to the package, just in case it ends up unused.
+	// That is, append to the end of the file the declaration
+	//	var _ = _cover_atomic_.AddUint32
+	reference := &ast.GenDecl{
+		Tok: token.VAR,
+		Specs: []ast.Spec{
+			&ast.ValueSpec{
+				Names: []*ast.Ident{
+					ast.NewIdent("_"),
+				},
+				Values: []ast.Expr{
+					&ast.SelectorExpr{
+						X:   ast.NewIdent(atomicPackageName),
+						Sel: ast.NewIdent("AddUint32"),
+					},
+				},
+			},
+		},
+	}
+	astFile.Decls = append(astFile.Decls, reference)
+	return atomicPackageName
+}
+
+var slashslash = []byte("//")
+
+// initialComments returns the prefix of content containing only
+// whitespace and line comments.  Any +build directives must appear
+// within this region.  This approach is more reliable than using
+// go/printer to print a modified AST containing comments.
+//
+func initialComments(content []byte) []byte {
+	// Derived from go/build.Context.shouldBuild.
+	end := 0
+	p := content
+	for len(p) > 0 {
+		line := p
+		if i := bytes.IndexByte(line, '\n'); i >= 0 {
+			line, p = line[:i], p[i+1:]
+		} else {
+			p = p[len(p):]
+		}
+		line = bytes.TrimSpace(line)
+		if len(line) == 0 { // Blank line.
+			end = len(content) - len(p)
+			continue
+		}
+		if !bytes.HasPrefix(line, slashslash) { // Not comment line.
+			break
+		}
+	}
+	return content[:end]
+}
+
+func annotate(name string) {
+	fset := token.NewFileSet()
+	content, err := ioutil.ReadFile(name)
+	if err != nil {
+		log.Fatalf("cover: %s: %s", name, err)
+	}
+	parsedFile, err := parser.ParseFile(fset, name, content, parser.ParseComments)
+	if err != nil {
+		log.Fatalf("cover: %s: %s", name, err)
+	}
+	parsedFile.Comments = trimComments(parsedFile, fset)
+
+	file := &File{
+		fset:    fset,
+		name:    name,
+		astFile: parsedFile,
+	}
+	if *mode == "atomic" {
+		file.atomicPkg = file.addImport(atomicPackagePath)
+	}
+	ast.Walk(file, file.astFile)
+	fd := os.Stdout
+	if *output != "" {
+		var err error
+		fd, err = os.Create(*output)
+		if err != nil {
+			log.Fatalf("cover: %s", err)
+		}
+	}
+	fd.Write(initialComments(content)) // Retain '// +build' directives.
+	file.print(fd)
+	// After printing the source tree, add some declarations for the counters etc.
+	// We could do this by adding to the tree, but it's easier just to print the text.
+	file.addVariables(fd)
+}
+
+// trimComments drops all but the //go: comments, some of which are semantically important.
+// We drop all others because they can appear in places that cause our counters
+// to appear in syntactically incorrect places. //go: appears at the beginning of
+// the line and is syntactically safe.
+func trimComments(file *ast.File, fset *token.FileSet) []*ast.CommentGroup {
+	var comments []*ast.CommentGroup
+	for _, group := range file.Comments {
+		var list []*ast.Comment
+		for _, comment := range group.List {
+			if strings.HasPrefix(comment.Text, "//go:") && fset.Position(comment.Slash).Column == 1 {
+				list = append(list, comment)
+			}
+		}
+		if list != nil {
+			comments = append(comments, &ast.CommentGroup{list})
+		}
+	}
+	return comments
+}
+
+func (f *File) print(w io.Writer) {
+	printer.Fprint(w, f.fset, f.astFile)
+}
+
+// intLiteral returns an ast.BasicLit representing the integer value.
+func (f *File) intLiteral(i int) *ast.BasicLit {
+	node := &ast.BasicLit{
+		Kind:  token.INT,
+		Value: fmt.Sprint(i),
+	}
+	return node
+}
+
+// index returns an ast.BasicLit representing the number of counters present.
+func (f *File) index() *ast.BasicLit {
+	return f.intLiteral(len(f.blocks))
+}
+
+// setCounterStmt returns the expression: __count[23] = 1.
+func setCounterStmt(f *File, counter ast.Expr) ast.Stmt {
+	return &ast.AssignStmt{
+		Lhs: []ast.Expr{counter},
+		Tok: token.ASSIGN,
+		Rhs: []ast.Expr{f.intLiteral(1)},
+	}
+}
+
+// incCounterStmt returns the expression: __count[23]++.
+func incCounterStmt(f *File, counter ast.Expr) ast.Stmt {
+	return &ast.IncDecStmt{
+		X:   counter,
+		Tok: token.INC,
+	}
+}
+
+// atomicCounterStmt returns the expression: atomic.AddUint32(&__count[23], 1)
+func atomicCounterStmt(f *File, counter ast.Expr) ast.Stmt {
+	return &ast.ExprStmt{
+		X: &ast.CallExpr{
+			Fun: &ast.SelectorExpr{
+				X:   ast.NewIdent(f.atomicPkg),
+				Sel: ast.NewIdent("AddUint32"),
+			},
+			Args: []ast.Expr{&ast.UnaryExpr{
+				Op: token.AND,
+				X:  counter,
+			},
+				f.intLiteral(1),
+			},
+		},
+	}
+}
+
+// newCounter creates a new counter expression of the appropriate form.
+func (f *File) newCounter(start, end token.Pos, numStmt int) ast.Stmt {
+	counter := &ast.IndexExpr{
+		X: &ast.SelectorExpr{
+			X:   ast.NewIdent(*varVar),
+			Sel: ast.NewIdent("Count"),
+		},
+		Index: f.index(),
+	}
+	stmt := counterStmt(f, counter)
+	f.blocks = append(f.blocks, Block{start, end, numStmt})
+	return stmt
+}
+
+// addCounters takes a list of statements and adds counters to the beginning of
+// each basic block at the top level of that list. For instance, given
+//
+//	S1
+//	if cond {
+//		S2
+// 	}
+//	S3
+//
+// counters will be added before S1 and before S3. The block containing S2
+// will be visited in a separate call.
+// TODO: Nested simple blocks get unnecessary (but correct) counters
+func (f *File) addCounters(pos, blockEnd token.Pos, list []ast.Stmt, extendToClosingBrace bool) []ast.Stmt {
+	// Special case: make sure we add a counter to an empty block. Can't do this below
+	// or we will add a counter to an empty statement list after, say, a return statement.
+	if len(list) == 0 {
+		return []ast.Stmt{f.newCounter(pos, blockEnd, 0)}
+	}
+	// We have a block (statement list), but it may have several basic blocks due to the
+	// appearance of statements that affect the flow of control.
+	var newList []ast.Stmt
+	for {
+		// Find first statement that affects flow of control (break, continue, if, etc.).
+		// It will be the last statement of this basic block.
+		var last int
+		end := blockEnd
+		for last = 0; last < len(list); last++ {
+			end = f.statementBoundary(list[last])
+			if f.endsBasicSourceBlock(list[last]) {
+				extendToClosingBrace = false // Block is broken up now.
+				last++
+				break
+			}
+		}
+		if extendToClosingBrace {
+			end = blockEnd
+		}
+		if pos != end { // Can have no source to cover if e.g. blocks abut.
+			newList = append(newList, f.newCounter(pos, end, last))
+		}
+		newList = append(newList, list[0:last]...)
+		list = list[last:]
+		if len(list) == 0 {
+			break
+		}
+		pos = list[0].Pos()
+	}
+	return newList
+}
+
+// hasFuncLiteral reports the existence and position of the first func literal
+// in the node, if any. If a func literal appears, it usually marks the termination
+// of a basic block because the function body is itself a block.
+// Therefore we draw a line at the start of the body of the first function literal we find.
+// TODO: what if there's more than one? Probably doesn't matter much.
+func hasFuncLiteral(n ast.Node) (bool, token.Pos) {
+	if n == nil {
+		return false, 0
+	}
+	var literal funcLitFinder
+	ast.Walk(&literal, n)
+	return literal.found(), token.Pos(literal)
+}
+
+// statementBoundary finds the location in s that terminates the current basic
+// block in the source.
+func (f *File) statementBoundary(s ast.Stmt) token.Pos {
+	// Control flow statements are easy.
+	switch s := s.(type) {
+	case *ast.BlockStmt:
+		// Treat blocks like basic blocks to avoid overlapping counters.
+		return s.Lbrace
+	case *ast.IfStmt:
+		found, pos := hasFuncLiteral(s.Init)
+		if found {
+			return pos
+		}
+		found, pos = hasFuncLiteral(s.Cond)
+		if found {
+			return pos
+		}
+		return s.Body.Lbrace
+	case *ast.ForStmt:
+		found, pos := hasFuncLiteral(s.Init)
+		if found {
+			return pos
+		}
+		found, pos = hasFuncLiteral(s.Cond)
+		if found {
+			return pos
+		}
+		found, pos = hasFuncLiteral(s.Post)
+		if found {
+			return pos
+		}
+		return s.Body.Lbrace
+	case *ast.LabeledStmt:
+		return f.statementBoundary(s.Stmt)
+	case *ast.RangeStmt:
+		found, pos := hasFuncLiteral(s.X)
+		if found {
+			return pos
+		}
+		return s.Body.Lbrace
+	case *ast.SwitchStmt:
+		found, pos := hasFuncLiteral(s.Init)
+		if found {
+			return pos
+		}
+		found, pos = hasFuncLiteral(s.Tag)
+		if found {
+			return pos
+		}
+		return s.Body.Lbrace
+	case *ast.SelectStmt:
+		return s.Body.Lbrace
+	case *ast.TypeSwitchStmt:
+		found, pos := hasFuncLiteral(s.Init)
+		if found {
+			return pos
+		}
+		return s.Body.Lbrace
+	}
+	// If not a control flow statement, it is a declaration, expression, call, etc. and it may have a function literal.
+	// If it does, that's tricky because we want to exclude the body of the function from this block.
+	// Draw a line at the start of the body of the first function literal we find.
+	// TODO: what if there's more than one? Probably doesn't matter much.
+	found, pos := hasFuncLiteral(s)
+	if found {
+		return pos
+	}
+	return s.End()
+}
+
+// endsBasicSourceBlock reports whether s changes the flow of control: break, if, etc.,
+// or if it's just problematic, for instance contains a function literal, which will complicate
+// accounting due to the block-within-an expression.
+func (f *File) endsBasicSourceBlock(s ast.Stmt) bool {
+	switch s := s.(type) {
+	case *ast.BlockStmt:
+		// Treat blocks like basic blocks to avoid overlapping counters.
+		return true
+	case *ast.BranchStmt:
+		return true
+	case *ast.ForStmt:
+		return true
+	case *ast.IfStmt:
+		return true
+	case *ast.LabeledStmt:
+		return f.endsBasicSourceBlock(s.Stmt)
+	case *ast.RangeStmt:
+		return true
+	case *ast.SwitchStmt:
+		return true
+	case *ast.SelectStmt:
+		return true
+	case *ast.TypeSwitchStmt:
+		return true
+	case *ast.ExprStmt:
+		// Calls to panic change the flow.
+		// We really should verify that "panic" is the predefined function,
+		// but without type checking we can't and the likelihood of it being
+		// an actual problem is vanishingly small.
+		if call, ok := s.X.(*ast.CallExpr); ok {
+			if ident, ok := call.Fun.(*ast.Ident); ok && ident.Name == "panic" && len(call.Args) == 1 {
+				return true
+			}
+		}
+	}
+	found, _ := hasFuncLiteral(s)
+	return found
+}
+
+// funcLitFinder implements the ast.Visitor pattern to find the location of any
+// function literal in a subtree.
+type funcLitFinder token.Pos
+
+func (f *funcLitFinder) Visit(node ast.Node) (w ast.Visitor) {
+	if f.found() {
+		return nil // Prune search.
+	}
+	switch n := node.(type) {
+	case *ast.FuncLit:
+		*f = funcLitFinder(n.Body.Lbrace)
+		return nil // Prune search.
+	}
+	return f
+}
+
+func (f *funcLitFinder) found() bool {
+	return token.Pos(*f) != token.NoPos
+}
+
+// Sort interface for []block1; used for self-check in addVariables.
+
+type block1 struct {
+	Block
+	index int
+}
+
+type blockSlice []block1
+
+func (b blockSlice) Len() int           { return len(b) }
+func (b blockSlice) Less(i, j int) bool { return b[i].startByte < b[j].startByte }
+func (b blockSlice) Swap(i, j int)      { b[i], b[j] = b[j], b[i] }
+
+// offset translates a token position into a 0-indexed byte offset.
+func (f *File) offset(pos token.Pos) int {
+	return f.fset.Position(pos).Offset
+}
+
+// addVariables adds to the end of the file the declarations to set up the counter and position variables.
+func (f *File) addVariables(w io.Writer) {
+	// Self-check: Verify that the instrumented basic blocks are disjoint.
+	t := make([]block1, len(f.blocks))
+	for i := range f.blocks {
+		t[i].Block = f.blocks[i]
+		t[i].index = i
+	}
+	sort.Sort(blockSlice(t))
+	for i := 1; i < len(t); i++ {
+		if t[i-1].endByte > t[i].startByte {
+			fmt.Fprintf(os.Stderr, "cover: internal error: block %d overlaps block %d\n", t[i-1].index, t[i].index)
+			// Note: error message is in byte positions, not token positions.
+			fmt.Fprintf(os.Stderr, "\t%s:#%d,#%d %s:#%d,#%d\n",
+				f.name, f.offset(t[i-1].startByte), f.offset(t[i-1].endByte),
+				f.name, f.offset(t[i].startByte), f.offset(t[i].endByte))
+		}
+	}
+
+	// Declare the coverage struct as a package-level variable.
+	fmt.Fprintf(w, "\nvar %s = struct {\n", *varVar)
+	fmt.Fprintf(w, "\tCount     [%d]uint32\n", len(f.blocks))
+	fmt.Fprintf(w, "\tPos       [3 * %d]uint32\n", len(f.blocks))
+	fmt.Fprintf(w, "\tNumStmt   [%d]uint16\n", len(f.blocks))
+	fmt.Fprintf(w, "} {\n")
+
+	// Initialize the position array field.
+	fmt.Fprintf(w, "\tPos: [3 * %d]uint32{\n", len(f.blocks))
+
+	// A nice long list of positions. Each position is encoded as follows to reduce size:
+	// - 32-bit starting line number
+	// - 32-bit ending line number
+	// - (16 bit ending column number << 16) | (16-bit starting column number).
+	for i, block := range f.blocks {
+		start := f.fset.Position(block.startByte)
+		end := f.fset.Position(block.endByte)
+		fmt.Fprintf(w, "\t\t%d, %d, %#x, // [%d]\n", start.Line, end.Line, (end.Column&0xFFFF)<<16|(start.Column&0xFFFF), i)
+	}
+
+	// Close the position array.
+	fmt.Fprintf(w, "\t},\n")
+
+	// Initialize the position array field.
+	fmt.Fprintf(w, "\tNumStmt: [%d]uint16{\n", len(f.blocks))
+
+	// A nice long list of statements-per-block, so we can give a conventional
+	// valuation of "percent covered". To save space, it's a 16-bit number, so we
+	// clamp it if it overflows - won't matter in practice.
+	for i, block := range f.blocks {
+		n := block.numStmt
+		if n > 1<<16-1 {
+			n = 1<<16 - 1
+		}
+		fmt.Fprintf(w, "\t\t%d, // %d\n", n, i)
+	}
+
+	// Close the statements-per-block array.
+	fmt.Fprintf(w, "\t},\n")
+
+	// Close the struct initialization.
+	fmt.Fprintf(w, "}\n")
+}
diff --git a/src/cmd/cover/cover_test.go b/src/cmd/cover/cover_test.go
new file mode 100644
index 0000000..f01f138
--- /dev/null
+++ b/src/cmd/cover/cover_test.go
@@ -0,0 +1,92 @@
+// 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 main_test
+
+import (
+	"bytes"
+	"fmt"
+	"internal/testenv"
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"testing"
+)
+
+const (
+	// Data directory, also the package directory for the test.
+	testdata = "testdata"
+
+	// Binaries we compile.
+	testcover = "./testcover.exe"
+)
+
+var (
+	// Files we use.
+	testMain    = filepath.Join(testdata, "main.go")
+	testTest    = filepath.Join(testdata, "test.go")
+	coverInput  = filepath.Join(testdata, "test_line.go")
+	coverOutput = filepath.Join(testdata, "test_cover.go")
+)
+
+var debug = false // Keeps the rewritten files around if set.
+
+// Run this shell script, but do it in Go so it can be run by "go test".
+//
+//	replace the word LINE with the line number < testdata/test.go > testdata/test_line.go
+// 	go build -o ./testcover
+// 	./testcover -mode=count -var=CoverTest -o ./testdata/test_cover.go testdata/test_line.go
+//	go run ./testdata/main.go ./testdata/test.go
+//
+func TestCover(t *testing.T) {
+	testenv.MustHaveGoBuild(t)
+
+	// Read in the test file (testTest) and write it, with LINEs specified, to coverInput.
+	file, err := ioutil.ReadFile(testTest)
+	if err != nil {
+		t.Fatal(err)
+	}
+	lines := bytes.Split(file, []byte("\n"))
+	for i, line := range lines {
+		lines[i] = bytes.Replace(line, []byte("LINE"), []byte(fmt.Sprint(i+1)), -1)
+	}
+	if err := ioutil.WriteFile(coverInput, bytes.Join(lines, []byte("\n")), 0666); err != nil {
+		t.Fatal(err)
+	}
+
+	// defer removal of test_line.go
+	if !debug {
+		defer os.Remove(coverInput)
+	}
+
+	// go build -o testcover
+	cmd := exec.Command("go", "build", "-o", testcover)
+	run(cmd, t)
+
+	// defer removal of testcover
+	defer os.Remove(testcover)
+
+	// ./testcover -mode=count -var=coverTest -o ./testdata/test_cover.go testdata/test_line.go
+	cmd = exec.Command(testcover, "-mode=count", "-var=coverTest", "-o", coverOutput, coverInput)
+	run(cmd, t)
+
+	// defer removal of ./testdata/test_cover.go
+	if !debug {
+		defer os.Remove(coverOutput)
+	}
+
+	// go run ./testdata/main.go ./testdata/test.go
+	cmd = exec.Command("go", "run", testMain, coverOutput)
+	run(cmd, t)
+}
+
+func run(c *exec.Cmd, t *testing.T) {
+	c.Stdout = os.Stdout
+	c.Stderr = os.Stderr
+	err := c.Run()
+	if err != nil {
+		t.Fatal(err)
+	}
+}
diff --git a/src/cmd/cover/doc.go b/src/cmd/cover/doc.go
new file mode 100644
index 0000000..636d7e0
--- /dev/null
+++ b/src/cmd/cover/doc.go
@@ -0,0 +1,21 @@
+// 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.
+
+/*
+Cover is a program for analyzing the coverage profiles generated by
+'go test -coverprofile=cover.out'.
+
+Cover is also used by 'go test -cover' to rewrite the source code with
+annotations to track which parts of each function are executed.
+It operates on one Go source file at a time, computing approximate
+basic block information by studying the source. It is thus more portable
+than binary-rewriting coverage tools, but also a little less capable.
+For instance, it does not probe inside && and || expressions, and can
+be mildly confused by single statements with multiple function literals.
+
+For usage information, please see:
+	go help testflag
+	go tool cover -help
+*/
+package main
diff --git a/src/cmd/cover/func.go b/src/cmd/cover/func.go
new file mode 100644
index 0000000..66ec242
--- /dev/null
+++ b/src/cmd/cover/func.go
@@ -0,0 +1,164 @@
+// 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.
+
+// This file implements the visitor that computes the (line, column)-(line-column) range for each function.
+
+package main
+
+import (
+	"bufio"
+	"fmt"
+	"go/ast"
+	"go/build"
+	"go/parser"
+	"go/token"
+	"os"
+	"path/filepath"
+	"text/tabwriter"
+)
+
+// funcOutput takes two file names as arguments, a coverage profile to read as input and an output
+// file to write ("" means to write to standard output). The function reads the profile and produces
+// as output the coverage data broken down by function, like this:
+//
+//	fmt/format.go:30:	init			100.0%
+//	fmt/format.go:57:	clearflags		100.0%
+//	...
+//	fmt/scan.go:1046:	doScan			100.0%
+//	fmt/scan.go:1075:	advance			96.2%
+//	fmt/scan.go:1119:	doScanf			96.8%
+//	total:		(statements)			91.9%
+
+func funcOutput(profile, outputFile string) error {
+	profiles, err := ParseProfiles(profile)
+	if err != nil {
+		return err
+	}
+
+	var out *bufio.Writer
+	if outputFile == "" {
+		out = bufio.NewWriter(os.Stdout)
+	} else {
+		fd, err := os.Create(outputFile)
+		if err != nil {
+			return err
+		}
+		defer fd.Close()
+		out = bufio.NewWriter(fd)
+	}
+	defer out.Flush()
+
+	tabber := tabwriter.NewWriter(out, 1, 8, 1, '\t', 0)
+	defer tabber.Flush()
+
+	var total, covered int64
+	for _, profile := range profiles {
+		fn := profile.FileName
+		file, err := findFile(fn)
+		if err != nil {
+			return err
+		}
+		funcs, err := findFuncs(file)
+		if err != nil {
+			return err
+		}
+		// Now match up functions and profile blocks.
+		for _, f := range funcs {
+			c, t := f.coverage(profile)
+			fmt.Fprintf(tabber, "%s:%d:\t%s\t%.1f%%\n", fn, f.startLine, f.name, 100.0*float64(c)/float64(t))
+			total += t
+			covered += c
+		}
+	}
+	fmt.Fprintf(tabber, "total:\t(statements)\t%.1f%%\n", 100.0*float64(covered)/float64(total))
+
+	return nil
+}
+
+// findFuncs parses the file and returns a slice of FuncExtent descriptors.
+func findFuncs(name string) ([]*FuncExtent, error) {
+	fset := token.NewFileSet()
+	parsedFile, err := parser.ParseFile(fset, name, nil, 0)
+	if err != nil {
+		return nil, err
+	}
+	visitor := &FuncVisitor{
+		fset:    fset,
+		name:    name,
+		astFile: parsedFile,
+	}
+	ast.Walk(visitor, visitor.astFile)
+	return visitor.funcs, nil
+}
+
+// FuncExtent describes a function's extent in the source by file and position.
+type FuncExtent struct {
+	name      string
+	startLine int
+	startCol  int
+	endLine   int
+	endCol    int
+}
+
+// FuncVisitor implements the visitor that builds the function position list for a file.
+type FuncVisitor struct {
+	fset    *token.FileSet
+	name    string // Name of file.
+	astFile *ast.File
+	funcs   []*FuncExtent
+}
+
+// Visit implements the ast.Visitor interface.
+func (v *FuncVisitor) Visit(node ast.Node) ast.Visitor {
+	switch n := node.(type) {
+	case *ast.FuncDecl:
+		start := v.fset.Position(n.Pos())
+		end := v.fset.Position(n.End())
+		fe := &FuncExtent{
+			name:      n.Name.Name,
+			startLine: start.Line,
+			startCol:  start.Column,
+			endLine:   end.Line,
+			endCol:    end.Column,
+		}
+		v.funcs = append(v.funcs, fe)
+	}
+	return v
+}
+
+// coverage returns the fraction of the statements in the function that were covered, as a numerator and denominator.
+func (f *FuncExtent) coverage(profile *Profile) (num, den int64) {
+	// We could avoid making this n^2 overall by doing a single scan and annotating the functions,
+	// but the sizes of the data structures is never very large and the scan is almost instantaneous.
+	var covered, total int64
+	// The blocks are sorted, so we can stop counting as soon as we reach the end of the relevant block.
+	for _, b := range profile.Blocks {
+		if b.StartLine > f.endLine || (b.StartLine == f.endLine && b.StartCol >= f.endCol) {
+			// Past the end of the function.
+			break
+		}
+		if b.EndLine < f.startLine || (b.EndLine == f.startLine && b.EndCol <= f.startCol) {
+			// Before the beginning of the function
+			continue
+		}
+		total += int64(b.NumStmt)
+		if b.Count > 0 {
+			covered += int64(b.NumStmt)
+		}
+	}
+	if total == 0 {
+		total = 1 // Avoid zero denominator.
+	}
+	return covered, total
+}
+
+// findFile finds the location of the named file in GOROOT, GOPATH etc.
+func findFile(file string) (string, error) {
+	dir, file := filepath.Split(file)
+	pkg, err := build.Import(dir, ".", build.FindOnly)
+	if err != nil {
+		return "", fmt.Errorf("can't find %q: %v", file, err)
+	}
+	return filepath.Join(pkg.Dir, file), nil
+}
diff --git a/src/cmd/cover/html.go b/src/cmd/cover/html.go
new file mode 100644
index 0000000..bb0a495
--- /dev/null
+++ b/src/cmd/cover/html.go
@@ -0,0 +1,279 @@
+// 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 main
+
+import (
+	"bufio"
+	"bytes"
+	"fmt"
+	"html/template"
+	"io"
+	"io/ioutil"
+	"math"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"runtime"
+)
+
+// htmlOutput reads the profile data from profile and generates an HTML
+// coverage report, writing it to outfile. If outfile is empty,
+// it writes the report to a temporary file and opens it in a web browser.
+func htmlOutput(profile, outfile string) error {
+	profiles, err := ParseProfiles(profile)
+	if err != nil {
+		return err
+	}
+
+	var d templateData
+
+	for _, profile := range profiles {
+		fn := profile.FileName
+		if profile.Mode == "set" {
+			d.Set = true
+		}
+		file, err := findFile(fn)
+		if err != nil {
+			return err
+		}
+		src, err := ioutil.ReadFile(file)
+		if err != nil {
+			return fmt.Errorf("can't read %q: %v", fn, err)
+		}
+		var buf bytes.Buffer
+		err = htmlGen(&buf, src, profile.Boundaries(src))
+		if err != nil {
+			return err
+		}
+		d.Files = append(d.Files, &templateFile{
+			Name:     fn,
+			Body:     template.HTML(buf.String()),
+			Coverage: percentCovered(profile),
+		})
+	}
+
+	var out *os.File
+	if outfile == "" {
+		var dir string
+		dir, err = ioutil.TempDir("", "cover")
+		if err != nil {
+			return err
+		}
+		out, err = os.Create(filepath.Join(dir, "coverage.html"))
+	} else {
+		out, err = os.Create(outfile)
+	}
+	err = htmlTemplate.Execute(out, d)
+	if err == nil {
+		err = out.Close()
+	}
+	if err != nil {
+		return err
+	}
+
+	if outfile == "" {
+		if !startBrowser("file://" + out.Name()) {
+			fmt.Fprintf(os.Stderr, "HTML output written to %s\n", out.Name())
+		}
+	}
+
+	return nil
+}
+
+// percentCovered returns, as a percentage, the fraction of the statements in
+// the profile covered by the test run.
+// In effect, it reports the coverage of a given source file.
+func percentCovered(p *Profile) float64 {
+	var total, covered int64
+	for _, b := range p.Blocks {
+		total += int64(b.NumStmt)
+		if b.Count > 0 {
+			covered += int64(b.NumStmt)
+		}
+	}
+	if total == 0 {
+		return 0
+	}
+	return float64(covered) / float64(total) * 100
+}
+
+// htmlGen generates an HTML coverage report with the provided filename,
+// source code, and tokens, and writes it to the given Writer.
+func htmlGen(w io.Writer, src []byte, boundaries []Boundary) error {
+	dst := bufio.NewWriter(w)
+	for i := range src {
+		for len(boundaries) > 0 && boundaries[0].Offset == i {
+			b := boundaries[0]
+			if b.Start {
+				n := 0
+				if b.Count > 0 {
+					n = int(math.Floor(b.Norm*9)) + 1
+				}
+				fmt.Fprintf(dst, `<span class="cov%v" title="%v">`, n, b.Count)
+			} else {
+				dst.WriteString("</span>")
+			}
+			boundaries = boundaries[1:]
+		}
+		switch b := src[i]; b {
+		case '>':
+			dst.WriteString(">")
+		case '<':
+			dst.WriteString("<")
+		case '&':
+			dst.WriteString("&")
+		case '\t':
+			dst.WriteString("        ")
+		default:
+			dst.WriteByte(b)
+		}
+	}
+	return dst.Flush()
+}
+
+// startBrowser tries to open the URL in a browser
+// and reports whether it succeeds.
+func startBrowser(url string) bool {
+	// try to start the browser
+	var args []string
+	switch runtime.GOOS {
+	case "darwin":
+		args = []string{"open"}
+	case "windows":
+		args = []string{"cmd", "/c", "start"}
+	default:
+		args = []string{"xdg-open"}
+	}
+	cmd := exec.Command(args[0], append(args[1:], url)...)
+	return cmd.Start() == nil
+}
+
+// rgb returns an rgb value for the specified coverage value
+// between 0 (no coverage) and 10 (max coverage).
+func rgb(n int) string {
+	if n == 0 {
+		return "rgb(192, 0, 0)" // Red
+	}
+	// Gradient from gray to green.
+	r := 128 - 12*(n-1)
+	g := 128 + 12*(n-1)
+	b := 128 + 3*(n-1)
+	return fmt.Sprintf("rgb(%v, %v, %v)", r, g, b)
+}
+
+// colors generates the CSS rules for coverage colors.
+func colors() template.CSS {
+	var buf bytes.Buffer
+	for i := 0; i < 11; i++ {
+		fmt.Fprintf(&buf, ".cov%v { color: %v }\n", i, rgb(i))
+	}
+	return template.CSS(buf.String())
+}
+
+var htmlTemplate = template.Must(template.New("html").Funcs(template.FuncMap{
+	"colors": colors,
+}).Parse(tmplHTML))
+
+type templateData struct {
+	Files []*templateFile
+	Set   bool
+}
+
+type templateFile struct {
+	Name     string
+	Body     template.HTML
+	Coverage float64
+}
+
+const tmplHTML = `
+<!DOCTYPE html>
+<html>
+	<head>
+		<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+		<style>
+			body {
+				background: black;
+				color: rgb(80, 80, 80);
+			}
+			body, pre, #legend span {
+				font-family: Menlo, monospace;
+				font-weight: bold;
+			}
+			#topbar {
+				background: black;
+				position: fixed;
+				top: 0; left: 0; right: 0;
+				height: 42px;
+				border-bottom: 1px solid rgb(80, 80, 80);
+			}
+			#content {
+				margin-top: 50px;
+			}
+			#nav, #legend {
+				float: left;
+				margin-left: 10px;
+			}
+			#legend {
+				margin-top: 12px;
+			}
+			#nav {
+				margin-top: 10px;
+			}
+			#legend span {
+				margin: 0 5px;
+			}
+			{{colors}}
+		</style>
+	</head>
+	<body>
+		<div id="topbar">
+			<div id="nav">
+				<select id="files">
+				{{range $i, $f := .Files}}
+				<option value="file{{$i}}">{{$f.Name}} ({{printf "%.1f" $f.Coverage}}%)</option>
+				{{end}}
+				</select>
+			</div>
+			<div id="legend">
+				<span>not tracked</span>
+			{{if .Set}}
+				<span class="cov0">not covered</span>
+				<span class="cov8">covered</span>
+			{{else}}
+				<span class="cov0">no coverage</span>
+				<span class="cov1">low coverage</span>
+				<span class="cov2">*</span>
+				<span class="cov3">*</span>
+				<span class="cov4">*</span>
+				<span class="cov5">*</span>
+				<span class="cov6">*</span>
+				<span class="cov7">*</span>
+				<span class="cov8">*</span>
+				<span class="cov9">*</span>
+				<span class="cov10">high coverage</span>
+			{{end}}
+			</div>
+		</div>
+		<div id="content">
+		{{range $i, $f := .Files}}
+		<pre class="file" id="file{{$i}}" {{if $i}}style="display: none"{{end}}>{{$f.Body}}</pre>
+		{{end}}
+		</div>
+	</body>
+	<script>
+	(function() {
+		var files = document.getElementById('files');
+		var visible = document.getElementById('file0');
+		files.addEventListener('change', onChange, false);
+		function onChange() {
+			visible.style.display = 'none';
+			visible = document.getElementById(files.value);
+			visible.style.display = 'block';
+			window.scrollTo(0, 0);
+		}
+	})();
+	</script>
+</html>
+`
diff --git a/src/cmd/cover/profile.go b/src/cmd/cover/profile.go
new file mode 100644
index 0000000..a03b5d5
--- /dev/null
+++ b/src/cmd/cover/profile.go
@@ -0,0 +1,192 @@
+// 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.
+
+// This file provides support for parsing coverage profiles
+// generated by "go test -coverprofile=cover.out".
+// It is a copy of golang.org/x/tools/cover/profile.go.
+
+package main
+
+import (
+	"bufio"
+	"fmt"
+	"math"
+	"os"
+	"regexp"
+	"sort"
+	"strconv"
+	"strings"
+)
+
+// Profile represents the profiling data for a specific file.
+type Profile struct {
+	FileName string
+	Mode     string
+	Blocks   []ProfileBlock
+}
+
+// ProfileBlock represents a single block of profiling data.
+type ProfileBlock struct {
+	StartLine, StartCol int
+	EndLine, EndCol     int
+	NumStmt, Count      int
+}
+
+type byFileName []*Profile
+
+func (p byFileName) Len() int           { return len(p) }
+func (p byFileName) Less(i, j int) bool { return p[i].FileName < p[j].FileName }
+func (p byFileName) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
+
+// ParseProfiles parses profile data in the specified file and returns a
+// Profile for each source file described therein.
+func ParseProfiles(fileName string) ([]*Profile, error) {
+	pf, err := os.Open(fileName)
+	if err != nil {
+		return nil, err
+	}
+	defer pf.Close()
+
+	files := make(map[string]*Profile)
+	buf := bufio.NewReader(pf)
+	// First line is "mode: foo", where foo is "set", "count", or "atomic".
+	// Rest of file is in the format
+	//	encoding/base64/base64.go:34.44,37.40 3 1
+	// where the fields are: name.go:line.column,line.column numberOfStatements count
+	s := bufio.NewScanner(buf)
+	mode := ""
+	for s.Scan() {
+		line := s.Text()
+		if mode == "" {
+			const p = "mode: "
+			if !strings.HasPrefix(line, p) || line == p {
+				return nil, fmt.Errorf("bad mode line: %v", line)
+			}
+			mode = line[len(p):]
+			continue
+		}
+		m := lineRe.FindStringSubmatch(line)
+		if m == nil {
+			return nil, fmt.Errorf("line %q doesn't match expected format: %v", m, lineRe)
+		}
+		fn := m[1]
+		p := files[fn]
+		if p == nil {
+			p = &Profile{
+				FileName: fn,
+				Mode:     mode,
+			}
+			files[fn] = p
+		}
+		p.Blocks = append(p.Blocks, ProfileBlock{
+			StartLine: toInt(m[2]),
+			StartCol:  toInt(m[3]),
+			EndLine:   toInt(m[4]),
+			EndCol:    toInt(m[5]),
+			NumStmt:   toInt(m[6]),
+			Count:     toInt(m[7]),
+		})
+	}
+	if err := s.Err(); err != nil {
+		return nil, err
+	}
+	for _, p := range files {
+		sort.Sort(blocksByStart(p.Blocks))
+	}
+	// Generate a sorted slice.
+	profiles := make([]*Profile, 0, len(files))
+	for _, profile := range files {
+		profiles = append(profiles, profile)
+	}
+	sort.Sort(byFileName(profiles))
+	return profiles, nil
+}
+
+type blocksByStart []ProfileBlock
+
+func (b blocksByStart) Len() int      { return len(b) }
+func (b blocksByStart) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
+func (b blocksByStart) Less(i, j int) bool {
+	bi, bj := b[i], b[j]
+	return bi.StartLine < bj.StartLine || bi.StartLine == bj.StartLine && bi.StartCol < bj.StartCol
+}
+
+var lineRe = regexp.MustCompile(`^(.+):([0-9]+).([0-9]+),([0-9]+).([0-9]+) ([0-9]+) ([0-9]+)$`)
+
+func toInt(s string) int {
+	i, err := strconv.Atoi(s)
+	if err != nil {
+		panic(err)
+	}
+	return i
+}
+
+// Boundary represents the position in a source file of the beginning or end of a
+// block as reported by the coverage profile. In HTML mode, it will correspond to
+// the opening or closing of a <span> tag and will be used to colorize the source
+type Boundary struct {
+	Offset int     // Location as a byte offset in the source file.
+	Start  bool    // Is this the start of a block?
+	Count  int     // Event count from the cover profile.
+	Norm   float64 // Count normalized to [0..1].
+}
+
+// Boundaries returns a Profile as a set of Boundary objects within the provided src.
+func (p *Profile) Boundaries(src []byte) (boundaries []Boundary) {
+	// Find maximum count.
+	max := 0
+	for _, b := range p.Blocks {
+		if b.Count > max {
+			max = b.Count
+		}
+	}
+	// Divisor for normalization.
+	divisor := math.Log(float64(max))
+
+	// boundary returns a Boundary, populating the Norm field with a normalized Count.
+	boundary := func(offset int, start bool, count int) Boundary {
+		b := Boundary{Offset: offset, Start: start, Count: count}
+		if !start || count == 0 {
+			return b
+		}
+		if max <= 1 {
+			b.Norm = 0.8 // Profile is in"set" mode; we want a heat map. Use cov8 in the CSS.
+		} else if count > 0 {
+			b.Norm = math.Log(float64(count)) / divisor
+		}
+		return b
+	}
+
+	line, col := 1, 2 // TODO: Why is this 2?
+	for si, bi := 0, 0; si < len(src) && bi < len(p.Blocks); {
+		b := p.Blocks[bi]
+		if b.StartLine == line && b.StartCol == col {
+			boundaries = append(boundaries, boundary(si, true, b.Count))
+		}
+		if b.EndLine == line && b.EndCol == col || line > b.EndLine {
+			boundaries = append(boundaries, boundary(si, false, 0))
+			bi++
+			continue // Don't advance through src; maybe the next block starts here.
+		}
+		if src[si] == '\n' {
+			line++
+			col = 0
+		}
+		col++
+		si++
+	}
+	sort.Sort(boundariesByPos(boundaries))
+	return
+}
+
+type boundariesByPos []Boundary
+
+func (b boundariesByPos) Len() int      { return len(b) }
+func (b boundariesByPos) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
+func (b boundariesByPos) Less(i, j int) bool {
+	if b[i].Offset == b[j].Offset {
+		return !b[i].Start && b[j].Start
+	}
+	return b[i].Offset < b[j].Offset
+}
diff --git a/src/cmd/cover/testdata/main.go b/src/cmd/cover/testdata/main.go
new file mode 100644
index 0000000..6ed39c4
--- /dev/null
+++ b/src/cmd/cover/testdata/main.go
@@ -0,0 +1,112 @@
+// 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.
+
+// Test runner for coverage test. This file is not coverage-annotated; test.go is.
+// It knows the coverage counter is called "coverTest".
+
+package main
+
+import (
+	"fmt"
+	"os"
+)
+
+func main() {
+	testAll()
+	verify()
+}
+
+type block struct {
+	count uint32
+	line  uint32
+}
+
+var counters = make(map[block]bool)
+
+// check records the location and expected value for a counter.
+func check(line, count uint32) {
+	b := block{
+		count,
+		line,
+	}
+	counters[b] = true
+}
+
+// checkVal is a version of check that returns its extra argument,
+// so it can be used in conditionals.
+func checkVal(line, count uint32, val int) int {
+	b := block{
+		count,
+		line,
+	}
+	counters[b] = true
+	return val
+}
+
+var PASS = true
+
+// verify checks the expected counts against the actual. It runs after the test has completed.
+func verify() {
+	for b := range counters {
+		got, index := count(b.line)
+		if b.count == anything && got != 0 {
+			got = anything
+		}
+		if got != b.count {
+			fmt.Fprintf(os.Stderr, "test_go:%d expected count %d got %d [counter %d]\n", b.line, b.count, got, index)
+			PASS = false
+		}
+	}
+	verifyPanic()
+	if !PASS {
+		fmt.Fprintf(os.Stderr, "FAIL\n")
+		os.Exit(2)
+	}
+}
+
+// verifyPanic is a special check for the known counter that should be
+// after the panic call in testPanic.
+func verifyPanic() {
+	if coverTest.Count[panicIndex-1] != 1 {
+		// Sanity check for test before panic.
+		fmt.Fprintf(os.Stderr, "bad before panic")
+		PASS = false
+	}
+	if coverTest.Count[panicIndex] != 0 {
+		fmt.Fprintf(os.Stderr, "bad at panic: %d should be 0\n", coverTest.Count[panicIndex])
+		PASS = false
+	}
+	if coverTest.Count[panicIndex+1] != 1 {
+		fmt.Fprintf(os.Stderr, "bad after panic")
+		PASS = false
+	}
+}
+
+// count returns the count and index for the counter at the specified line.
+func count(line uint32) (uint32, int) {
+	// Linear search is fine. Choose perfect fit over approximate.
+	// We can have a closing brace for a range on the same line as a condition for an "else if"
+	// and we don't want that brace to steal the count for the condition on the "if".
+	// Therefore we test for a perfect (lo==line && hi==line) match, but if we can't
+	// find that we take the first imperfect match.
+	index := -1
+	indexLo := uint32(1e9)
+	for i := range coverTest.Count {
+		lo, hi := coverTest.Pos[3*i], coverTest.Pos[3*i+1]
+		if lo == line && line == hi {
+			return coverTest.Count[i], i
+		}
+		// Choose the earliest match (the counters are in unpredictable order).
+		if lo <= line && line <= hi && indexLo > lo {
+			index = i
+			indexLo = lo
+		}
+	}
+	if index == -1 {
+		fmt.Fprintln(os.Stderr, "cover_test: no counter for line", line)
+		PASS = false
+		return 0, 0
+	}
+	return coverTest.Count[index], index
+}
diff --git a/src/cmd/cover/testdata/test.go b/src/cmd/cover/testdata/test.go
new file mode 100644
index 0000000..9013950
--- /dev/null
+++ b/src/cmd/cover/testdata/test.go
@@ -0,0 +1,218 @@
+// 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.
+
+// This program is processed by the cover command, and then testAll is called.
+// The test driver in main.go can then compare the coverage statistics with expectation.
+
+// The word LINE is replaced by the line number in this file. When the file is executed,
+// the coverage processing has changed the line numbers, so we can't use runtime.Caller.
+
+package main
+
+const anything = 1e9 // Just some unlikely value that means "we got here, don't care how often"
+
+func testAll() {
+	testSimple()
+	testBlockRun()
+	testIf()
+	testFor()
+	testRange()
+	testSwitch()
+	testTypeSwitch()
+	testSelect1()
+	testSelect2()
+	testPanic()
+	testEmptySwitches()
+}
+
+// The indexes of the counters in testPanic are known to main.go
+const panicIndex = 3
+
+// This test appears first because the index of its counters is known to main.go
+func testPanic() {
+	defer func() {
+		recover()
+	}()
+	check(LINE, 1)
+	panic("should not get next line")
+	check(LINE, 0) // this is GoCover.Count[panicIndex]
+	// The next counter is in testSimple and it will be non-zero.
+	// If the panic above does not trigger a counter, the test will fail
+	// because GoCover.Count[panicIndex] will be the one in testSimple.
+}
+
+func testSimple() {
+	check(LINE, 1)
+}
+
+func testIf() {
+	if true {
+		check(LINE, 1)
+	} else {
+		check(LINE, 0)
+	}
+	if false {
+		check(LINE, 0)
+	} else {
+		check(LINE, 1)
+	}
+	for i := 0; i < 3; i++ {
+		if checkVal(LINE, 3, i) <= 2 {
+			check(LINE, 3)
+		}
+		if checkVal(LINE, 3, i) <= 1 {
+			check(LINE, 2)
+		}
+		if checkVal(LINE, 3, i) <= 0 {
+			check(LINE, 1)
+		}
+	}
+	for i := 0; i < 3; i++ {
+		if checkVal(LINE, 3, i) <= 1 {
+			check(LINE, 2)
+		} else {
+			check(LINE, 1)
+		}
+	}
+	for i := 0; i < 3; i++ {
+		if checkVal(LINE, 3, i) <= 0 {
+			check(LINE, 1)
+		} else if checkVal(LINE, 2, i) <= 1 {
+			check(LINE, 1)
+		} else if checkVal(LINE, 1, i) <= 2 {
+			check(LINE, 1)
+		} else if checkVal(LINE, 0, i) <= 3 {
+			check(LINE, 0)
+		}
+	}
+	if func(a, b int) bool { return a < b }(3, 4) {
+		check(LINE, 1)
+	}
+}
+
+func testFor() {
+	for i := 0; i < 10; func() { i++; check(LINE, 10) }() {
+		check(LINE, 10)
+	}
+}
+
+func testRange() {
+	for _, f := range []func(){
+		func() { check(LINE, 1) },
+	} {
+		f()
+		check(LINE, 1)
+	}
+}
+
+func testBlockRun() {
+	check(LINE, 1)
+	{
+		check(LINE, 1)
+	}
+	{
+		check(LINE, 1)
+	}
+	check(LINE, 1)
+	{
+		check(LINE, 1)
+	}
+	{
+		check(LINE, 1)
+	}
+	check(LINE, 1)
+}
+
+func testSwitch() {
+	for i := 0; i < 5; func() { i++; check(LINE, 5) }() {
+		switch i {
+		case 0:
+			check(LINE, 1)
+		case 1:
+			check(LINE, 1)
+		case 2:
+			check(LINE, 1)
+		default:
+			check(LINE, 2)
+		}
+	}
+}
+
+func testTypeSwitch() {
+	var x = []interface{}{1, 2.0, "hi"}
+	for _, v := range x {
+		switch func() { check(LINE, 3) }(); v.(type) {
+		case int:
+			check(LINE, 1)
+		case float64:
+			check(LINE, 1)
+		case string:
+			check(LINE, 1)
+		case complex128:
+			check(LINE, 0)
+		default:
+			check(LINE, 0)
+		}
+	}
+}
+
+func testSelect1() {
+	c := make(chan int)
+	go func() {
+		for i := 0; i < 1000; i++ {
+			c <- i
+		}
+	}()
+	for {
+		select {
+		case <-c:
+			check(LINE, anything)
+		case <-c:
+			check(LINE, anything)
+		default:
+			check(LINE, 1)
+			return
+		}
+	}
+}
+
+func testSelect2() {
+	c1 := make(chan int, 1000)
+	c2 := make(chan int, 1000)
+	for i := 0; i < 1000; i++ {
+		c1 <- i
+		c2 <- i
+	}
+	for {
+		select {
+		case <-c1:
+			check(LINE, 1000)
+		case <-c2:
+			check(LINE, 1000)
+		default:
+			check(LINE, 1)
+			return
+		}
+	}
+}
+
+// Empty control statements created syntax errors. This function
+// is here just to be sure that those are handled correctly now.
+func testEmptySwitches() {
+	check(LINE, 1)
+	switch 3 {
+	}
+	check(LINE, 1)
+	switch i := (interface{})(3).(int); i {
+	}
+	check(LINE, 1)
+	c := make(chan int)
+	go func() {
+		check(LINE, 1)
+		c <- 1
+		select {}
+	}()
+	<-c
+	check(LINE, 1)
+}
diff --git a/src/cmd/dist/README b/src/cmd/dist/README
index e6d08cf..0649e88 100644
--- a/src/cmd/dist/README
+++ b/src/cmd/dist/README
@@ -1,45 +1,27 @@
 This program, dist, is the bootstrapping tool for the Go distribution.
-It takes care of building the C programs (like the Go compiler) and
-the initial bootstrap copy of the go tool.  It also serves as a catch-all
-to replace odd jobs previously done with shell scripts.
 
-Dist is itself written in very simple C.  All interaction with C libraries,
-even standard C libraries, is confined to a single system-specific file
-(plan9.c, unix.c, windows.c), to aid portability.  Functionality needed
-by other files should be exposed via the portability layer.  Functions
-in the portability layer begin with an x prefix when they would otherwise
-use the same name as or be confused for an existing function.
-For example, xprintf is the portable printf.
+As of Go 1.5, dist and other parts of the compiler toolchain are written
+in Go, making bootstrapping a little more involved than in the past.
+The approach is to build the current release of Go with an earlier one.
 
-By far the most common data types in dist are strings and arrays of
-strings.  Instead of using char* and char**, though, dist uses two named
-data structures, Buf and Vec, which own all the data they point at.
-The Buf operations are functions beginning with b; the Vec operations
-are functions beginning with v.  The basic form of any function declaring
-Bufs or Vecs on the stack should be
+The process to install Go 1.x, for x ≥ 5, is:
 
-	void
-	myfunc(void)
-	{
-		Buf b1, b2;
-		Vec v1;
-		
-		binit(&b1);
-		binit(&b2);
-		vinit(&v1);
-		
-		... main code ...
-		bprintf(&b1, "hello, world");
-		vadd(&v1, bstr(&b1));  // v1 takes a copy of its argument
-		bprintf(&b2, "another string");
-		vadd(&v1, bstr(&b2));  // v1 now has two strings
-		
-		bfree(&b1);
-		bfree(&b2);
-		vfree(&v1);
-	}
-	
-The binit/vinit calls prepare a buffer or vector for use, initializing the 
-data structures, and the bfree/vfree calls free any memory they are still
-holding onto.  Use of this idiom gives us lexically scoped allocations.
+1. Build cmd/dist with Go 1.4.
+2. Using dist, build Go 1.x compiler toolchain with Go 1.4.
+3. Using dist, rebuild Go 1.x compiler toolchain with itself.
+4. Using dist, build Go 1.x cmd/go (as go_bootstrap) with Go 1.x compiler toolchain.
+5. Using go_bootstrap, build the remaining Go 1.x standard library and commands.
 
+NOTE: During the transition from the old C-based toolchain to the Go-based one,
+step 2 also builds the parts of the toolchain written in C, and step 3 does not
+recompile those.
+
+Because of backward compatibility, although the steps above say Go 1.4,
+in practice any release ≥ Go 1.4 but < Go 1.x will work as the bootstrap base.
+
+See golang.org/s/go15bootstrap for more details.
+
+Compared to Go 1.4 and earlier, dist will also take over much of what used to
+be done by make.bash/make.bat/make.rc and all of what used to be done by
+run.bash/run.bat/run.rc, because it is nicer to implement that logic in Go
+than in three different scripting languages simultaneously.
diff --git a/src/cmd/dist/a.h b/src/cmd/dist/a.h
deleted file mode 100644
index 288063b..0000000
--- a/src/cmd/dist/a.h
+++ /dev/null
@@ -1,165 +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.
-
-typedef int bool;
-
-// The Time unit is unspecified; we just need to
-// be able to compare whether t1 is older than t2 with t1 < t2.
-typedef long long Time;
-
-#define nil ((void*)0)
-#define nelem(x) (sizeof(x)/sizeof((x)[0]))
-#ifndef PLAN9
-#define USED(x) ((void)(x))
-#endif
-
-// A Buf is a byte buffer, like Go's []byte.
-typedef struct Buf Buf;
-struct Buf
-{
-	char *p;
-	int len;
-	int cap;
-};
-
-// A Vec is a string vector, like Go's []string.
-typedef struct Vec Vec;
-struct Vec
-{
-	char **p;
-	int len;
-	int cap;
-};
-
-// Modes for run.
-enum {
-	CheckExit = 1,
-};
-
-// buf.c
-bool	bequal(Buf *s, Buf *t);
-void	bsubst(Buf *b, char *x, char *y);
-void	bfree(Buf *b);
-void	bgrow(Buf *b, int n);
-void	binit(Buf *b);
-char*	bpathf(Buf *b, char *fmt, ...);
-char*	bprintf(Buf *b, char *fmt, ...);
-void	bwritef(Buf *b, char *fmt, ...);
-void	breset(Buf *b);
-char*	bstr(Buf *b);
-char*	btake(Buf *b);
-void	bwrite(Buf *b, void *v, int n);
-void	bwriteb(Buf *dst, Buf *src);
-void	bwritestr(Buf *b, char *p);
-void	bswap(Buf *b, Buf *b1);
-void	vadd(Vec *v, char *p);
-void	vcopy(Vec *dst, char **src, int n);
-void	vfree(Vec *v);
-void	vgrow(Vec *v, int n);
-void	vinit(Vec *v);
-void	vreset(Vec *v);
-void	vuniq(Vec *v);
-void	splitlines(Vec*, char*);
-void	splitfields(Vec*, char*);
-
-// build.c
-extern char *goarch;
-extern char *gobin;
-extern char *gochar;
-extern char *gohostarch;
-extern char *gohostos;
-extern char *goos;
-extern char *goroot;
-extern char *goroot_final;
-extern char *goextlinkenabled;
-extern char *goversion;
-extern char *defaultcc;
-extern char *defaultcxxtarget;
-extern char *defaultcctarget;
-extern char *workdir;
-extern char *tooldir;
-extern char *slash;
-extern bool rebuildall;
-extern bool defaultclang;
-
-int	find(char*, char**, int);
-void	init(void);
-void	cmdbanner(int, char**);
-void	cmdbootstrap(int, char**);
-void	cmdclean(int, char**);
-void	cmdenv(int, char**);
-void	cmdinstall(int, char**);
-void	cmdversion(int, char**);
-
-// buildgc.c
-void	gcopnames(char*, char*);
-void	mkanames(char*, char*);
-
-// buildruntime.c
-void	mkzasm(char*, char*);
-void	mkzsys(char*, char*);
-void	mkzgoarch(char*, char*);
-void	mkzgoos(char*, char*);
-void	mkzruntimedefs(char*, char*);
-void	mkzversion(char*, char*);
-void	mkzexperiment(char*, char*);
-
-// buildgo.c
-void	mkzdefaultcc(char*, char*);
-
-// main.c
-extern int vflag;
-extern int sflag;
-void	usage(void);
-void	xmain(int argc, char **argv);
-
-// portability layer (plan9.c, unix.c, windows.c)
-bool	contains(char *p, char *sep);
-void	errprintf(char*, ...);
-void	fatal(char *msg, ...);
-bool	hasprefix(char *p, char *prefix);
-bool	hassuffix(char *p, char *suffix);
-bool	isabs(char*);
-bool	isdir(char *p);
-bool	isfile(char *p);
-char*	lastelem(char*);
-Time	mtime(char*);
-void	readfile(Buf*, char*);
-void	copyfile(char*, char*, int);
-void	run(Buf *b, char *dir, int mode, char *cmd, ...);
-void	runv(Buf *b, char *dir, int mode, Vec *argv);
-void	bgrunv(char *dir, int mode, Vec *argv);
-void	bgwait(void);
-bool	streq(char*, char*);
-bool	cansse2(void);
-void	writefile(Buf*, char*, int);
-void	xatexit(void (*f)(void));
-void	xexit(int);
-void	xfree(void*);
-void	xgetenv(Buf *b, char *name);
-void	xgetwd(Buf *b);
-void*	xmalloc(int n);
-void*	xmalloc(int);
-int	xmemcmp(void*, void*, int);
-void	xmemmove(void*, void*, int);
-void	xmkdir(char *p);
-void	xmkdirall(char*);
-Time	xmtime(char *p);
-void	xprintf(char*, ...);
-void	xqsort(void*, int, int, int(*)(const void*, const void*));
-void	xreaddir(Vec *dst, char *dir);
-void*	xrealloc(void*, int);
-void	xrealwd(Buf *b, char *path);
-void	xremove(char *p);
-void	xremoveall(char *p);
-void	xsetenv(char*, char*);
-int	xstrcmp(char*, char*);
-char*	xstrdup(char *p);
-int	xstrlen(char*);
-char*	xstrrchr(char*, int);
-char*	xstrstr(char*, char*);
-char*	xworkdir(void);
-int	xsamefile(char*, char*);
-char*	xgetgoarm(void);
-int	xtryexecfunc(void (*)(void));
diff --git a/src/cmd/dist/arg.h b/src/cmd/dist/arg.h
deleted file mode 100644
index 9819765..0000000
--- a/src/cmd/dist/arg.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
-Derived from Inferno include/kern.h.
-
-http://code.google.com/p/inferno-os/source/browse/include/kern.h
-
-	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  All rights reserved.
-	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.
-*/
-
-/* command line */
-extern char	*argv0;
-#define	ARGBEGIN	for((argv0=(argv0?argv0:*argv)),argv++,argc--;\
-			    argv[0] && argv[0][0]=='-' && argv[0][1];\
-			    argc--, argv++) {\
-				char *_args, *_argt;\
-				char _argc;\
-				_args = &argv[0][1];\
-				if(_args[0]=='-' && _args[1]==0){\
-					argc--; argv++; break;\
-				}\
-				while((_argc = *_args++) != 0)\
-				switch(_argc)
-#define	ARGEND		_argt=0;USED(_argt);USED(_argc);USED(_args);}USED(argv);USED(argc);
-#define	ARGF()		(_argt=_args, _args="",\
-				(*_argt? _argt: argv[1]? (argc--, *++argv): 0))
-#define	EARGF(x)	(_argt=_args, _args="",\
-				(*_argt? _argt: argv[1]? (argc--, *++argv): ((x), fatal("usage"), (char*)0)))
-
-#define	ARGC()		_argc
-
diff --git a/src/cmd/dist/arm.c b/src/cmd/dist/arm.c
deleted file mode 100644
index 1ce7b77..0000000
--- a/src/cmd/dist/arm.c
+++ /dev/null
@@ -1,72 +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.
-
-#include "a.h"
-
-#ifndef __ARMEL__
-char *
-xgetgoarm(void)
-{
-	return "6";
-}
-#else
-static void useVFPv3(void);
-static void useVFPv1(void);
-
-char *
-xgetgoarm(void)
-{
-#if defined(__FreeBSD__)
-	// FreeBSD has broken VFP support
-	return "5";
-#endif
-	// NaCl always has VFP support.
-	if(streq(goos, "nacl") || xtryexecfunc(useVFPv3))
-		return "7";
-	else if(xtryexecfunc(useVFPv1))
-		return "6";
-	return "5";
-}
-
-static void
-useVFPv3(void)
-{
-	// try to run VFPv3-only "vmov.f64 d0, #112" instruction
-	// we can't use that instruction directly, because we
-	// might be compiling with a soft-float only toolchain.
-	//
-	// some newer toolchains are configured to use thumb
-	// by default, so we need to do some mode changing magic
-	// here.
-	// We can use "bx pc; nop" here, but GNU as(1) insists
-	// on warning us
-	// "use of r15 in bx in ARM mode is not really useful"
-	// so we workaround that by using "bx r0"
-	__asm__ __volatile__ ("mov r0, pc");
-	__asm__ __volatile__ ("bx r0");
-	__asm__ __volatile__ (".word 0xeeb70b00"); // vmov.f64 d0, #112
-	__asm__ __volatile__ (".word 0xe12fff1e"); // bx lr
-}
-
-static void
-useVFPv1(void)
-{
-	// try to run "vmov.f64 d0, d0" instruction
-	// we can't use that instruction directly, because we
-	// might be compiling with a soft-float only toolchain
-	//
-	// some newer toolchains are configured to use thumb
-	// by default, so we need to do some mode changing magic
-	// here.
-	// We can use "bx pc; nop" here, but GNU as(1) insists
-	// on warning us
-	// "use of r15 in bx in ARM mode is not really useful"
-	// so we workaround that by using "bx r0"
-	__asm__ __volatile__ ("mov r0, pc");
-	__asm__ __volatile__ ("bx r0");
-	__asm__ __volatile__ (".word 0xeeb00b40"); // vomv.f64 d0, d0
-	__asm__ __volatile__ (".word 0xe12fff1e"); // bx lr
-}
-
-#endif
diff --git a/src/cmd/dist/buf.c b/src/cmd/dist/buf.c
deleted file mode 100644
index 2ddc6be..0000000
--- a/src/cmd/dist/buf.c
+++ /dev/null
@@ -1,279 +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.
-
-// Byte buffers and string vectors.
-
-#include "a.h"
-
-// binit prepares an uninitialized buffer for use.
-void
-binit(Buf *b)
-{
-	b->p = nil;
-	b->len = 0;
-	b->cap = 0;
-}
-
-// breset truncates the buffer back to zero length.
-void
-breset(Buf *b)
-{
-	b->len = 0;
-}
-
-// bfree frees the storage associated with a buffer.
-void
-bfree(Buf *b)
-{
-	xfree(b->p);
-	binit(b);
-}
-
-// bgrow ensures that the buffer has at least n more bytes
-// between its len and cap.
-void
-bgrow(Buf *b, int n)
-{
-	int want;
-	
-	want = b->len+n;
-	if(want > b->cap) {
-		b->cap = 2*want;
-		if(b->cap < 64)
-			b->cap = 64;
-		b->p = xrealloc(b->p, b->cap);
-	}
-}
-
-// bwrite appends the n bytes at v to the buffer.
-void
-bwrite(Buf *b, void *v, int n)
-{
-	bgrow(b, n);
-	xmemmove(b->p+b->len, v, n);
-	b->len += n;
-}
-
-// bwritestr appends the string p to the buffer.
-void
-bwritestr(Buf *b, char *p)
-{
-	bwrite(b, p, xstrlen(p));
-}
-
-// bstr returns a pointer to a NUL-terminated string of the
-// buffer contents.  The pointer points into the buffer.
-char*
-bstr(Buf *b)
-{
-	bgrow(b, 1);
-	b->p[b->len] = '\0';
-	return b->p;
-}
-
-// btake takes ownership of the string form of the buffer.
-// After this call, the buffer has zero length and does not
-// refer to the memory that btake returned.
-char*
-btake(Buf *b)
-{
-	char *p;
-	
-	p = bstr(b);
-	binit(b);
-	return p;
-}
-
-// bwriteb appends the src buffer to the dst buffer.
-void
-bwriteb(Buf *dst, Buf *src)
-{
-	bwrite(dst, src->p, src->len);
-}
-
-// bequal reports whether the buffers have the same content.
-bool
-bequal(Buf *s, Buf *t)
-{
-	return s->len == t->len && xmemcmp(s->p, t->p, s->len) == 0;
-}
-
-// bsubst rewites b to replace all occurrences of x with y.
-void
-bsubst(Buf *b, char *x, char *y)
-{
-	char *p;
-	int nx, ny, pos;
-
-	nx = xstrlen(x);
-	ny = xstrlen(y);
-
-	pos = 0;
-	for(;;) {
-		p = xstrstr(bstr(b)+pos, x);
-		if(p == nil)
-			break;
-		if(nx != ny) {
-			if(nx < ny) {
-				pos = p - b->p;
-				bgrow(b, ny-nx);
-				p = b->p + pos;
-			}
-			xmemmove(p+ny, p+nx, (b->p+b->len)-(p+nx));
-		}
-		xmemmove(p, y, ny);
-		pos = p+ny - b->p;
-		b->len += ny - nx;
-	}
-}
-
-// The invariant with the vectors is that v->p[0:v->len] is allocated
-// strings that are owned by the vector.  The data beyond v->len may
-// be garbage.
-
-// vinit prepares an uninitialized vector for use.
-void
-vinit(Vec *v)
-{
-	v->p = nil;
-	v->len = 0;
-	v->cap = 0;
-}
-
-// vreset truncates the vector back to zero length.
-void
-vreset(Vec *v)
-{
-	int i;
-	
-	for(i=0; i<v->len; i++) {
-		xfree(v->p[i]);
-		v->p[i] = nil;
-	}
-	v->len = 0;
-}
-
-// vfree frees the storage associated with the vector.
-void
-vfree(Vec *v)
-{
-	vreset(v);
-	xfree(v->p);
-	vinit(v);
-}
-
-
-// vgrow ensures that the vector has room for at least 
-// n more entries between len and cap.
-void
-vgrow(Vec *v, int n)
-{
-	int want;
-	
-	want = v->len+n;
-	if(want > v->cap) {
-		v->cap = 2*want;
-		if(v->cap < 64)
-			v->cap = 64;
-		v->p = xrealloc(v->p, v->cap*sizeof v->p[0]);
-	}
-}
-
-// vcopy copies the srclen strings at src into the vector.
-void
-vcopy(Vec *dst, char **src, int srclen)
-{
-	int i;
-	
-	// use vadd, to make copies of strings
-	for(i=0; i<srclen; i++)
-		vadd(dst, src[i]);
-}
-
-// vadd adds a copy of the string p to the vector.
-void
-vadd(Vec *v, char *p)
-{
-	vgrow(v, 1);
-	if(p != nil)
-		p = xstrdup(p);
-	v->p[v->len++] = p;
-}
-
-// vaddn adds a string consisting of the n bytes at p to the vector.
-static void
-vaddn(Vec *v, char *p, int n)
-{
-	char *q;
-
-	vgrow(v, 1);
-	q = xmalloc(n+1);
-	xmemmove(q, p, n);
-	q[n] = '\0';
-	v->p[v->len++] = q;
-}
-
-static int
-strpcmp(const void *a, const void *b)
-{
-	return xstrcmp(*(char**)a, *(char**)b);
-}
-
-// vuniq sorts the vector and then discards duplicates,
-// in the manner of sort | uniq.
-void
-vuniq(Vec *v)
-{
-	int i, n;
-
-	xqsort(v->p, v->len, sizeof(v->p[0]), strpcmp);
-	n = 0;
-	for(i=0; i<v->len; i++) {
-		if(n>0 && streq(v->p[i], v->p[n-1]))
-			xfree(v->p[i]);
-		else
-			v->p[n++] = v->p[i];
-	}
-	v->len = n;
-}
-
-// splitlines replaces the vector v with the result of splitting
-// the input p after each \n.
-void
-splitlines(Vec *v, char *p)
-{
-	int i;
-	char *start;
-	
-	vreset(v);
-	start = p;
-	for(i=0; p[i]; i++) {
-		if(p[i] == '\n') {
-			vaddn(v, start, (p+i+1)-start);
-			start = p+i+1;
-		}
-	}
-	if(*start != '\0')
-		vadd(v, start);
-}
-
-// splitfields replaces the vector v with the result of splitting
-// the input p into non-empty fields containing no spaces.
-void
-splitfields(Vec *v, char *p)
-{
-	char *start;
-
-	vreset(v);
-	for(;;) {
-		while(*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')
-			p++;
-		if(*p == '\0')
-			break;
-		start = p;
-		while(*p != ' ' && *p != '\t' && *p != '\r' && *p != '\n' && *p != '\0')
-			p++;
-		vaddn(v, start, p-start);
-	}
-}
diff --git a/src/cmd/dist/build.c b/src/cmd/dist/build.c
deleted file mode 100644
index 8d82167..0000000
--- a/src/cmd/dist/build.c
+++ /dev/null
@@ -1,1803 +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.
-
-#include "a.h"
-#include "arg.h"
-
-/*
- * Initialization for any invocation.
- */
-
-// The usual variables.
-char *goarch;
-char *gobin;
-char *gohostarch;
-char *gohostchar;
-char *gohostos;
-char *goos;
-char *goarm;
-char *go386;
-char *goroot = GOROOT_FINAL;
-char *goroot_final = GOROOT_FINAL;
-char *goextlinkenabled = "";
-char *workdir;
-char *tooldir;
-char *gochar;
-char *goversion;
-char *slash;	// / for unix, \ for windows
-char *defaultcc;
-char *defaultcflags;
-char *defaultldflags;
-char *defaultcxxtarget;
-char *defaultcctarget;
-bool	rebuildall;
-bool defaultclang;
-
-static bool shouldbuild(char*, char*);
-static void dopack(char*, char*, char**, int);
-static char *findgoversion(void);
-
-// The known architecture letters.
-static char *gochars = "5668";
-
-// The known architectures.
-static char *okgoarch[] = {
-	// same order as gochars
-	"arm",
-	"amd64",
-	"amd64p32",
-	"386",
-};
-
-// The known operating systems.
-static char *okgoos[] = {
-	"darwin",
-	"dragonfly",
-	"linux",
-	"android",
-	"solaris",
-	"freebsd",
-	"nacl",
-	"netbsd",
-	"openbsd",
-	"plan9",
-	"windows",
-};
-
-static void rmworkdir(void);
-
-// find reports the first index of p in l[0:n], or else -1.
-int
-find(char *p, char **l, int n)
-{
-	int i;
-
-	for(i=0; i<n; i++)
-		if(streq(p, l[i]))
-			return i;
-	return -1;
-}
-
-// init handles initialization of the various global state, like goroot and goarch.
-void
-init(void)
-{
-	char *p;
-	int i;
-	Buf b;
-
-	binit(&b);
-
-	xgetenv(&b, "GOROOT");
-	if(b.len > 0) {
-		// if not "/", then strip trailing path separator
-		if(b.len >= 2 && b.p[b.len - 1] == slash[0])
-			b.len--;
-		goroot = btake(&b);
-	}
-
-	xgetenv(&b, "GOBIN");
-	if(b.len == 0)
-		bprintf(&b, "%s%sbin", goroot, slash);
-	gobin = btake(&b);
-
-	xgetenv(&b, "GOOS");
-	if(b.len == 0)
-		bwritestr(&b, gohostos);
-	goos = btake(&b);
-	if(find(goos, okgoos, nelem(okgoos)) < 0)
-		fatal("unknown $GOOS %s", goos);
-
-	xgetenv(&b, "GOARM");
-	if(b.len == 0)
-		bwritestr(&b, xgetgoarm());
-	goarm = btake(&b);
-
-	xgetenv(&b, "GO386");
-	if(b.len == 0) {
-		if(cansse2())
-			bwritestr(&b, "sse2");
-		else
-			bwritestr(&b, "387");
-	}
-	go386 = btake(&b);
-
-	p = bpathf(&b, "%s/include/u.h", goroot);
-	if(!isfile(p)) {
-		fatal("$GOROOT is not set correctly or not exported\n"
-			"\tGOROOT=%s\n"
-			"\t%s does not exist", goroot, p);
-	}
-
-	xgetenv(&b, "GOHOSTARCH");
-	if(b.len > 0)
-		gohostarch = btake(&b);
-
-	i = find(gohostarch, okgoarch, nelem(okgoarch));
-	if(i < 0)
-		fatal("unknown $GOHOSTARCH %s", gohostarch);
-	bprintf(&b, "%c", gochars[i]);
-	gohostchar = btake(&b);
-
-	xgetenv(&b, "GOARCH");
-	if(b.len == 0)
-		bwritestr(&b, gohostarch);
-	goarch = btake(&b);
-	i = find(goarch, okgoarch, nelem(okgoarch));
-	if(i < 0)
-		fatal("unknown $GOARCH %s", goarch);
-	bprintf(&b, "%c", gochars[i]);
-	gochar = btake(&b);
-
-	xgetenv(&b, "GO_EXTLINK_ENABLED");
-	if(b.len > 0) {
-		goextlinkenabled = btake(&b);
-		if(!streq(goextlinkenabled, "0") && !streq(goextlinkenabled, "1"))
-			fatal("unknown $GO_EXTLINK_ENABLED %s", goextlinkenabled);
-	}
-	
-	xgetenv(&b, "CC");
-	if(b.len == 0) {
-		// Use clang on OS X, because gcc is deprecated there.
-		// Xcode for OS X 10.9 Mavericks will ship a fake "gcc" binary that
-		// actually runs clang. We prepare different command
-		// lines for the two binaries, so it matters what we call it.
-		// See golang.org/issue/5822.
-		if(defaultclang)
-			bprintf(&b, "clang");
-		else
-			bprintf(&b, "gcc");
-	}
-	defaultcc = btake(&b);
-
-	xgetenv(&b, "CFLAGS");
-	defaultcflags = btake(&b);
-
-	xgetenv(&b, "LDFLAGS");
-	defaultldflags = btake(&b);
-
-	xgetenv(&b, "CC_FOR_TARGET");
-	if(b.len == 0) {
-		bprintf(&b, defaultcc);
-	}
-	defaultcctarget = btake(&b);
-
-	xgetenv(&b, "CXX_FOR_TARGET");
-	if(b.len == 0) {
-		xgetenv(&b, "CXX");
-		if(b.len == 0) {
-			if(defaultclang)
-				bprintf(&b, "clang++");
-			else
-				bprintf(&b, "g++");
-		}
-	}
-	defaultcxxtarget = btake(&b);
-
-	xsetenv("GOROOT", goroot);
-	xsetenv("GOARCH", goarch);
-	xsetenv("GOOS", goos);
-	xsetenv("GOARM", goarm);
-	xsetenv("GO386", go386);
-
-	// Make the environment more predictable.
-	xsetenv("LANG", "C");
-	xsetenv("LANGUAGE", "en_US.UTF8");
-
-	goversion = findgoversion();
-
-	workdir = xworkdir();
-	xatexit(rmworkdir);
-
-	bpathf(&b, "%s/pkg/tool/%s_%s", goroot, gohostos, gohostarch);
-	tooldir = btake(&b);
-
-	bfree(&b);
-}
-
-// rmworkdir deletes the work directory.
-static void
-rmworkdir(void)
-{
-	if(vflag > 1)
-		errprintf("rm -rf %s\n", workdir);
-	xremoveall(workdir);
-}
-
-// Remove trailing spaces.
-static void
-chomp(Buf *b)
-{
-	int c;
-
-	while(b->len > 0 && ((c=b->p[b->len-1]) == ' ' || c == '\t' || c == '\r' || c == '\n'))
-		b->len--;
-}
-
-static char*
-branchtag(char *branch, bool *precise)
-{
-	char *tag, *p, *q;
-	int i;
-	Buf b, arg;
-	Vec tags;
-
-	binit(&b);
-	binit(&arg);
-	vinit(&tags);
-
-	bprintf(&arg, "master..%s", branch);
-	run(&b, goroot, CheckExit, "git", "log", "--decorate=full", "--format=format:%d", bstr(&arg), nil);
-
-	splitlines(&tags, bstr(&b));
-	tag = branch;
-	for(i=0; i < tags.len; i++) {
-		// Each line is either blank, or looks like
-		//	  (tag: refs/tags/go1.4rc2, refs/remotes/origin/release-branch.go1.4, refs/heads/release-branch.go1.4)
-		// We need to find an element starting with refs/tags/.
-		p = xstrstr(tags.p[i], " refs/tags/");
-		if(p == nil)
-			continue;
-		p += xstrlen(" refs/tags/");
-		// The tag name ends at a comma or paren (prefer the first).
-		q = xstrstr(p, ",");
-		if(q == nil)
-			q = xstrstr(p, ")");
-		if(q == nil)
-			continue;  // malformed line; ignore it
-		*q = '\0';
-		tag = xstrdup(p);
-		if(i == 0)
-			*precise = 1;  // tag denotes HEAD
-		break;
-	}
-
-	bfree(&b);
-	bfree(&arg);
-	vfree(&tags);
-	return tag;
-}
-
-// findgoversion determines the Go version to use in the version string.
-static char*
-findgoversion(void)
-{
-	char *tag, *p;
-	bool precise;
-	Buf b, path, bmore, branch;
-
-	binit(&b);
-	binit(&path);
-	binit(&bmore);
-	binit(&branch);
-
-	// The $GOROOT/VERSION file takes priority, for distributions
-	// without the source repo.
-	bpathf(&path, "%s/VERSION", goroot);
-	if(isfile(bstr(&path))) {
-		readfile(&b, bstr(&path));
-		chomp(&b);
-		// Commands such as "dist version > VERSION" will cause
-		// the shell to create an empty VERSION file and set dist's
-		// stdout to its fd. dist in turn looks at VERSION and uses
-		// its content if available, which is empty at this point.
-		if(b.len > 0)
-			goto done;
-	}
-
-	// The $GOROOT/VERSION.cache file is a cache to avoid invoking
-	// git every time we run this command.  Unlike VERSION, it gets
-	// deleted by the clean command.
-	bpathf(&path, "%s/VERSION.cache", goroot);
-	if(isfile(bstr(&path))) {
-		readfile(&b, bstr(&path));
-		chomp(&b);
-		goto done;
-	}
-
-	// Otherwise, use Git.
-	// What is the current branch?
-	run(&branch, goroot, CheckExit, "git", "rev-parse", "--abbrev-ref", "HEAD", nil);
-	chomp(&branch);
-
-	// What are the tags along the current branch?
-	tag = "devel";
-	precise = 0;
-
-	// If we're on a release branch, use the closest matching tag
-	// that is on the release branch (and not on the master branch).
-	if(hasprefix(bstr(&branch), "release-branch."))
-		tag = branchtag(bstr(&branch), &precise);
-
-	bprintf(&b, "%s", tag);
-	if(!precise) {
-		// Tag does not point at HEAD; add hash and date to version.
-		run(&bmore, goroot, CheckExit, "git", "log", "-n", "1", "--format=format: +%h %cd", "HEAD", nil);
-		chomp(&bmore);
-		bwriteb(&b, &bmore);
-	}
-
-	// Cache version.
-	writefile(&b, bstr(&path), 0);
-
-done:
-	p = btake(&b);
-
-
-	bfree(&b);
-	bfree(&path);
-	bfree(&bmore);
-	bfree(&branch);
-
-	return p;
-}
-
-/*
- * Initial tree setup.
- */
-
-// The old tools that no longer live in $GOBIN or $GOROOT/bin.
-static char *oldtool[] = {
-	"5a", "5c", "5g", "5l",
-	"6a", "6c", "6g", "6l",
-	"8a", "8c", "8g", "8l",
-	"6cov",
-	"6nm",
-	"6prof",
-	"cgo",
-	"ebnflint",
-	"goapi",
-	"gofix",
-	"goinstall",
-	"gomake",
-	"gopack",
-	"gopprof",
-	"gotest",
-	"gotype",
-	"govet",
-	"goyacc",
-	"quietgcc",
-};
-
-// Unreleased directories (relative to $GOROOT) that should
-// not be in release branches.
-static char *unreleased[] = {
-	"src/cmd/link",
-	"src/debug/goobj",
-	"src/old",
-};
-
-// setup sets up the tree for the initial build.
-static void
-setup(void)
-{
-	int i;
-	Buf b;
-	char *p;
-
-	binit(&b);
-
-	// Create bin directory.
-	p = bpathf(&b, "%s/bin", goroot);
-	if(!isdir(p))
-		xmkdir(p);
-
-	// Create package directory.
-	p = bpathf(&b, "%s/pkg", goroot);
-	if(!isdir(p))
-		xmkdir(p);
-	p = bpathf(&b, "%s/pkg/%s_%s", goroot, gohostos, gohostarch);
-	if(rebuildall)
-		xremoveall(p);
-	xmkdirall(p);
-	if(!streq(goos, gohostos) || !streq(goarch, gohostarch)) {
-		p = bpathf(&b, "%s/pkg/%s_%s", goroot, goos, goarch);
-		if(rebuildall)
-			xremoveall(p);
-		xmkdirall(p);
-	}
-
-	// Create object directory.
-	// We keep it in pkg/ so that all the generated binaries
-	// are in one tree.  If pkg/obj/libgc.a exists, it is a dreg from
-	// before we used subdirectories of obj.  Delete all of obj
-	// to clean up.
-	bpathf(&b, "%s/pkg/obj/libgc.a", goroot);
-	if(isfile(bstr(&b)))
-		xremoveall(bpathf(&b, "%s/pkg/obj", goroot));
-	p = bpathf(&b, "%s/pkg/obj/%s_%s", goroot, gohostos, gohostarch);
-	if(rebuildall)
-		xremoveall(p);
-	xmkdirall(p);
-
-	// Create tool directory.
-	// We keep it in pkg/, just like the object directory above.
-	if(rebuildall)
-		xremoveall(tooldir);
-	xmkdirall(tooldir);
-
-	// Remove tool binaries from before the tool/gohostos_gohostarch
-	xremoveall(bpathf(&b, "%s/bin/tool", goroot));
-
-	// Remove old pre-tool binaries.
-	for(i=0; i<nelem(oldtool); i++)
-		xremove(bpathf(&b, "%s/bin/%s", goroot, oldtool[i]));
-
-	// If $GOBIN is set and has a Go compiler, it must be cleaned.
-	for(i=0; gochars[i]; i++) {
-		if(isfile(bprintf(&b, "%s%s%c%s", gobin, slash, gochars[i], "g"))) {
-			for(i=0; i<nelem(oldtool); i++)
-				xremove(bprintf(&b, "%s%s%s", gobin, slash, oldtool[i]));
-			break;
-		}
-	}
-
-	// For release, make sure excluded things are excluded.
-	if(hasprefix(goversion, "release.") || (hasprefix(goversion, "go") && !contains(goversion, "beta"))) {
-		for(i=0; i<nelem(unreleased); i++)
-			if(isdir(bpathf(&b, "%s/%s", goroot, unreleased[i])))
-				fatal("%s should not exist in release build", bstr(&b));
-	}
-
-	bfree(&b);
-}
-
-/*
- * C library and tool building
- */
-
-// gccargs is the gcc command line to use for compiling a single C file.
-static char *proto_gccargs[] = {
-	"-Wall",
-	// native Plan 9 compilers don't like non-standard prototypes
-	// so let gcc catch them.
-	"-Wstrict-prototypes",
-	"-Wextra",
-	"-Wunused",
-	"-Wno-sign-compare",
-	"-Wno-missing-braces",
-	"-Wno-parentheses",
-	"-Wno-unknown-pragmas",
-	"-Wno-switch",
-	"-Wno-comment",
-	"-Wno-missing-field-initializers",
-	"-fno-common",
-	"-ggdb",
-	"-pipe",
-};
-
-// gccargs2 is the second part of gccargs.
-// it is used if the environment isn't defining CFLAGS.
-static char *proto_gccargs2[] = {
-	// on older versions of GCC, -Wuninitialized is not supported
-	// without -O, so put it here together with -O settings in case
-	// the user's $CFLAGS doesn't include -O.
-	"-Wuninitialized",
-#if defined(__NetBSD__) && defined(__arm__)
-	// GCC 4.5.4 (NetBSD nb1 20120916) on ARM is known to mis-optimize gc/mparith3.c
-	// Fix available at http://patchwork.ozlabs.org/patch/64562/.
-	"-O1",
-#else
-	"-O2",
-#endif
-};
-
-static Vec gccargs, ldargs;
-
-// deptab lists changes to the default dependencies for a given prefix.
-// deps ending in /* read the whole directory; deps beginning with -
-// exclude files with that prefix.
-static struct {
-	char *prefix;  // prefix of target
-	char *dep[20];  // dependency tweaks for targets with that prefix
-} deptab[] = {
-	{"lib9", {
-		"$GOROOT/include/u.h",
-		"$GOROOT/include/utf.h",
-		"$GOROOT/include/fmt.h",
-		"$GOROOT/include/libc.h",
-		"fmt/*",
-		"utf/*",
-	}},
-	{"libbio", {
-		"$GOROOT/include/u.h",
-		"$GOROOT/include/utf.h",
-		"$GOROOT/include/fmt.h",
-		"$GOROOT/include/libc.h",
-		"$GOROOT/include/bio.h",
-	}},
-	{"liblink", {
-		"$GOROOT/include/u.h",
-		"$GOROOT/include/utf.h",
-		"$GOROOT/include/fmt.h",
-		"$GOROOT/include/libc.h",
-		"$GOROOT/include/bio.h",
-		"$GOROOT/include/ar.h",
-		"$GOROOT/include/link.h",
-		"anames5.c",
-		"anames6.c",
-		"anames8.c",
-	}},
-	{"cmd/cc", {
-		"-pgen.c",
-		"-pswt.c",
-	}},
-	{"cmd/gc", {
-		"-cplx.c",
-		"-pgen.c",
-		"-plive.c",
-		"-popt.c",
-		"-y1.tab.c",  // makefile dreg
-		"opnames.h",
-	}},
-	{"cmd/5c", {
-		"../cc/pgen.c",
-		"../cc/pswt.c",
-		"$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libcc.a",
-	}},
-	{"cmd/6c", {
-		"../cc/pgen.c",
-		"../cc/pswt.c",
-		"$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libcc.a",
-	}},
-	{"cmd/8c", {
-		"../cc/pgen.c",
-		"../cc/pswt.c",
-		"$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libcc.a",
-	}},
-	{"cmd/5g", {
-		"../gc/cplx.c",
-		"../gc/pgen.c",
-		"../gc/plive.c",
-		"../gc/popt.c",
-		"../gc/popt.h",
-		"$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libgc.a",
-	}},
-	{"cmd/6g", {
-		"../gc/cplx.c",
-		"../gc/pgen.c",
-		"../gc/plive.c",
-		"../gc/popt.c",
-		"../gc/popt.h",
-		"$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libgc.a",
-	}},
-	{"cmd/8g", {
-		"../gc/cplx.c",
-		"../gc/pgen.c",
-		"../gc/plive.c",
-		"../gc/popt.c",
-		"../gc/popt.h",
-		"$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libgc.a",
-	}},
-	{"cmd/5l", {
-		"../ld/*",
-	}},
-	{"cmd/6l", {
-		"../ld/*",
-	}},
-	{"cmd/8l", {
-		"../ld/*",
-	}},
-	{"cmd/go", {
-		"zdefaultcc.go",
-	}},
-	{"cmd/", {
-		"$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/liblink.a",
-		"$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/libbio.a",
-		"$GOROOT/pkg/obj/$GOHOSTOS_$GOHOSTARCH/lib9.a",
-	}},
-	{"runtime", {
-		"zaexperiment.h", // must sort above zasm
-		"zasm_$GOOS_$GOARCH.h",
-		"zsys_$GOOS_$GOARCH.s",
-		"zgoarch_$GOARCH.go",
-		"zgoos_$GOOS.go",
-		"zruntime_defs_$GOOS_$GOARCH.go",
-		"zversion.go",
-	}},
-};
-
-// depsuffix records the allowed suffixes for source files.
-char *depsuffix[] = {
-	".c",
-	".h",
-	".s",
-	".go",
-};
-
-// gentab records how to generate some trivial files.
-static struct {
-	char *nameprefix;
-	void (*gen)(char*, char*);
-} gentab[] = {
-	{"opnames.h", gcopnames},
-	{"anames5.c", mkanames},
-	{"anames6.c", mkanames},
-	{"anames8.c", mkanames},
-	{"zasm_", mkzasm},
-	{"zdefaultcc.go", mkzdefaultcc},
-	{"zsys_", mkzsys},
-	{"zgoarch_", mkzgoarch},
-	{"zgoos_", mkzgoos},
-	{"zruntime_defs_", mkzruntimedefs},
-	{"zversion.go", mkzversion},
-	{"zaexperiment.h", mkzexperiment},
-
-	// not generated anymore, but delete the file if we see it
-	{"enam.c", nil},
-};
-
-// install installs the library, package, or binary associated with dir,
-// which is relative to $GOROOT/src.
-static void
-install(char *dir)
-{
-	char *name, *p, *elem, *prefix, *exe;
-	bool islib, ispkg, isgo, stale, ispackcmd;
-	Buf b, b1, path, final_path, final_name;
-	Vec compile, files, link, go, missing, clean, lib, extra;
-	Time ttarg, t;
-	int i, j, k, n, doclean, targ;
-
-	if(vflag) {
-		if(!streq(goos, gohostos) || !streq(goarch, gohostarch))
-			errprintf("%s (%s/%s)\n", dir, goos, goarch);
-		else
-			errprintf("%s\n", dir);
-	}
-
-	binit(&b);
-	binit(&b1);
-	binit(&path);
-	binit(&final_path);
-	binit(&final_name);
-	vinit(&compile);
-	vinit(&files);
-	vinit(&link);
-	vinit(&go);
-	vinit(&missing);
-	vinit(&clean);
-	vinit(&lib);
-	vinit(&extra);
-
-
-	// path = full path to dir.
-	bpathf(&path, "%s/src/%s", goroot, dir);
-	bpathf(&final_path, "%s/src/%s", goroot_final, dir);
-	name = lastelem(dir);
-
-	// set up gcc command line on first run.
-	if(gccargs.len == 0) {
-		bprintf(&b, "%s %s", defaultcc, defaultcflags);
-		splitfields(&gccargs, bstr(&b));
-		for(i=0; i<nelem(proto_gccargs); i++)
-			vadd(&gccargs, proto_gccargs[i]);
-		if(defaultcflags[0] == '\0') {
-			for(i=0; i<nelem(proto_gccargs2); i++)
-				vadd(&gccargs, proto_gccargs2[i]);
-		}
-		if(contains(gccargs.p[0], "clang")) {
-			// disable ASCII art in clang errors, if possible
-			vadd(&gccargs, "-fno-caret-diagnostics");
-			// clang is too smart about unused command-line arguments
-			vadd(&gccargs, "-Qunused-arguments");
-		}
-		// disable word wrapping in error messages
-		vadd(&gccargs, "-fmessage-length=0");
-		if(streq(gohostos, "darwin")) {
-			// golang.org/issue/5261
-			vadd(&gccargs, "-mmacosx-version-min=10.6");
-		}
-	}
-	if(ldargs.len == 0 && defaultldflags[0] != '\0') {
-		bprintf(&b, "%s", defaultldflags);
-		splitfields(&ldargs, bstr(&b));
-	}
-
-	islib = hasprefix(dir, "lib") || streq(dir, "cmd/cc") || streq(dir, "cmd/gc");
-	ispkg = !islib && !hasprefix(dir, "cmd/");
-	isgo = ispkg || streq(dir, "cmd/go") || streq(dir, "cmd/cgo");
-
-	exe = "";
-	if(streq(gohostos, "windows"))
-		exe = ".exe";
-
-	// Start final link command line.
-	// Note: code below knows that link.p[targ] is the target.
-	ispackcmd = 0;
-	if(islib) {
-		// C library.
-		vadd(&link, "ar");
-		if(streq(gohostos, "plan9"))
-			vadd(&link, "rc");
-		else
-			vadd(&link, "rsc");
-		prefix = "";
-		if(!hasprefix(name, "lib"))
-			prefix = "lib";
-		targ = link.len;
-		vadd(&link, bpathf(&b, "%s/pkg/obj/%s_%s/%s%s.a", goroot, gohostos, gohostarch, prefix, name));
-	} else if(ispkg) {
-		// Go library (package).
-		ispackcmd = 1;
-		vadd(&link, "pack"); // program name - unused here, but all the other cases record one
-		p = bprintf(&b, "%s/pkg/%s_%s/%s", goroot, goos, goarch, dir);
-		*xstrrchr(p, '/') = '\0';
-		xmkdirall(p);
-		targ = link.len;
-		vadd(&link, bpathf(&b, "%s/pkg/%s_%s/%s.a", goroot, goos, goarch, dir));
-	} else if(streq(dir, "cmd/go") || streq(dir, "cmd/cgo")) {
-		// Go command.
-		vadd(&link, bpathf(&b, "%s/%sl", tooldir, gochar));
-		vadd(&link, "-o");
-		elem = name;
-		if(streq(elem, "go"))
-			elem = "go_bootstrap";
-		targ = link.len;
-		vadd(&link, bpathf(&b, "%s/%s%s", tooldir, elem, exe));
-	} else {
-		// C command. Use gccargs and ldargs.
-		if(streq(gohostos, "plan9")) {
-			vadd(&link, bprintf(&b, "%sl", gohostchar));
-			vadd(&link, "-o");
-			targ = link.len;
-			vadd(&link, bpathf(&b, "%s/%s", tooldir, name));
-		} else {
-			vcopy(&link, gccargs.p, gccargs.len);
-			vcopy(&link, ldargs.p, ldargs.len);
-			if(sflag)
-				vadd(&link, "-static");
-			vadd(&link, "-o");
-			targ = link.len;
-			vadd(&link, bpathf(&b, "%s/%s%s", tooldir, name, exe));
-			if(streq(gohostarch, "amd64"))
-				vadd(&link, "-m64");
-			else if(streq(gohostarch, "386"))
-				vadd(&link, "-m32");
-		}
-	}
-	ttarg = mtime(link.p[targ]);
-
-	// Gather files that are sources for this target.
-	// Everything in that directory, and any target-specific
-	// additions.
-	xreaddir(&files, bstr(&path));
-
-	// Remove files beginning with . or _,
-	// which are likely to be editor temporary files.
-	// This is the same heuristic build.ScanDir uses.
-	// There do exist real C files beginning with _,
-	// so limit that check to just Go files.
-	n = 0;
-	for(i=0; i<files.len; i++) {
-		p = files.p[i];
-		if(hasprefix(p, ".") || (hasprefix(p, "_") && hassuffix(p, ".go")))
-			xfree(p);
-		else
-			files.p[n++] = p;
-	}
-	files.len = n;
-
-	for(i=0; i<nelem(deptab); i++) {
-		if(streq(dir, deptab[i].prefix) ||
-		   (hassuffix(deptab[i].prefix, "/") && hasprefix(dir, deptab[i].prefix))) {
-			for(j=0; (p=deptab[i].dep[j])!=nil; j++) {
-				breset(&b1);
-				bwritestr(&b1, p);
-				bsubst(&b1, "$GOROOT", goroot);
-				bsubst(&b1, "$GOOS", goos);
-				bsubst(&b1, "$GOARCH", goarch);
-				bsubst(&b1, "$GOHOSTOS", gohostos);
-				bsubst(&b1, "$GOHOSTARCH", gohostarch);
-				p = bstr(&b1);
-				if(hassuffix(p, ".a")) {
-					vadd(&lib, bpathf(&b, "%s", p));
-					continue;
-				}
-				if(hassuffix(p, "/*")) {
-					bpathf(&b, "%s/%s", bstr(&path), p);
-					b.len -= 2;
-					xreaddir(&extra, bstr(&b));
-					bprintf(&b, "%s", p);
-					b.len -= 2;
-					for(k=0; k<extra.len; k++)
-						vadd(&files, bpathf(&b1, "%s/%s", bstr(&b), extra.p[k]));
-					continue;
-				}
-				if(hasprefix(p, "-")) {
-					p++;
-					n = 0;
-					for(k=0; k<files.len; k++) {
-						if(hasprefix(files.p[k], p))
-							xfree(files.p[k]);
-						else
-							files.p[n++] = files.p[k];
-					}
-					files.len = n;
-					continue;
-				}
-				vadd(&files, p);
-			}
-		}
-	}
-	vuniq(&files);
-
-	// Convert to absolute paths.
-	for(i=0; i<files.len; i++) {
-		if(!isabs(files.p[i])) {
-			bpathf(&b, "%s/%s", bstr(&path), files.p[i]);
-			xfree(files.p[i]);
-			files.p[i] = btake(&b);
-		}
-	}
-
-	// Is the target up-to-date?
-	stale = rebuildall;
-	n = 0;
-	for(i=0; i<files.len; i++) {
-		p = files.p[i];
-		for(j=0; j<nelem(depsuffix); j++)
-			if(hassuffix(p, depsuffix[j]))
-				goto ok;
-		xfree(files.p[i]);
-		continue;
-	ok:
-		t = mtime(p);
-		if(t != 0 && !hassuffix(p, ".a") && !shouldbuild(p, dir)) {
-			xfree(files.p[i]);
-			continue;
-		}
-		if(hassuffix(p, ".go"))
-			vadd(&go, p);
-		if(t > ttarg)
-			stale = 1;
-		if(t == 0) {
-			vadd(&missing, p);
-			files.p[n++] = files.p[i];
-			continue;
-		}
-		files.p[n++] = files.p[i];
-	}
-	files.len = n;
-
-	// If there are no files to compile, we're done.
-	if(files.len == 0)
-		goto out;
-	
-	for(i=0; i<lib.len && !stale; i++)
-		if(mtime(lib.p[i]) > ttarg)
-			stale = 1;
-
-	if(!stale)
-		goto out;
-
-	// For package runtime, copy some files into the work space.
-	if(streq(dir, "runtime")) {
-		copyfile(bpathf(&b, "%s/arch_GOARCH.h", workdir),
-			bpathf(&b1, "%s/arch_%s.h", bstr(&path), goarch), 0);
-		copyfile(bpathf(&b, "%s/defs_GOOS_GOARCH.h", workdir),
-			bpathf(&b1, "%s/defs_%s_%s.h", bstr(&path), goos, goarch), 0);
-		p = bpathf(&b1, "%s/signal_%s_%s.h", bstr(&path), goos, goarch);
-		if(isfile(p))
-			copyfile(bpathf(&b, "%s/signal_GOOS_GOARCH.h", workdir), p, 0);
-		copyfile(bpathf(&b, "%s/os_GOOS.h", workdir),
-			bpathf(&b1, "%s/os_%s.h", bstr(&path), goos), 0);
-		copyfile(bpathf(&b, "%s/signals_GOOS.h", workdir),
-			bpathf(&b1, "%s/signals_%s.h", bstr(&path), goos), 0);
-		copyfile(bpathf(&b, "%s/pkg/%s_%s/textflag.h", goroot, goos, goarch),
-			bpathf(&b1, "%s/src/cmd/ld/textflag.h", goroot), 0);
-		copyfile(bpathf(&b, "%s/pkg/%s_%s/funcdata.h", goroot, goos, goarch),
-			bpathf(&b1, "%s/src/runtime/funcdata.h", goroot), 0);
-	}
-
-	// Generate any missing files; regenerate existing ones.
-	for(i=0; i<files.len; i++) {
-		p = files.p[i];
-		elem = lastelem(p);
-		for(j=0; j<nelem(gentab); j++) {
-			if(gentab[j].gen == nil)
-				continue;
-			if(hasprefix(elem, gentab[j].nameprefix)) {
-				if(vflag > 1)
-					errprintf("generate %s\n", p);
-				gentab[j].gen(bstr(&path), p);
-				// Do not add generated file to clean list.
-				// In runtime, we want to be able to
-				// build the package with the go tool,
-				// and it assumes these generated files already
-				// exist (it does not know how to build them).
-				// The 'clean' command can remove
-				// the generated files.
-				goto built;
-			}
-		}
-		// Did not rebuild p.
-		if(find(p, missing.p, missing.len) >= 0)
-			fatal("missing file %s", p);
-	built:;
-	}
-
-	// One more copy for package runtime.
-	// The last batch was required for the generators.
-	// This one is generated.
-	if(streq(dir, "runtime")) {
-		copyfile(bpathf(&b, "%s/zasm_GOOS_GOARCH.h", workdir),
-			bpathf(&b1, "%s/zasm_%s_%s.h", bstr(&path), goos, goarch), 0);
-	}
-
-	if((!streq(goos, gohostos) || !streq(goarch, gohostarch)) && isgo) {
-		// We've generated the right files; the go command can do the build.
-		if(vflag > 1)
-			errprintf("skip build for cross-compile %s\n", dir);
-		goto nobuild;
-	}
-
-	// Compile the files.
-	for(i=0; i<files.len; i++) {
-		if(!hassuffix(files.p[i], ".c") && !hassuffix(files.p[i], ".s"))
-			continue;
-		name = lastelem(files.p[i]);
-
-		vreset(&compile);
-		if(!isgo) {
-			// C library or tool.
-			if(streq(gohostos, "plan9")) {
-				vadd(&compile, bprintf(&b, "%sc", gohostchar));
-				vadd(&compile, "-FTVwp");
-				vadd(&compile, "-DPLAN9");
-				vadd(&compile, "-D__STDC__=1");
-				vadd(&compile, "-D__SIZE_TYPE__=ulong"); // for GNU Bison
-				vadd(&compile, bpathf(&b, "-I%s/include/plan9", goroot));
-				vadd(&compile, bpathf(&b, "-I%s/include/plan9/%s", goroot, gohostarch));
-			} else {
-				vcopy(&compile, gccargs.p, gccargs.len);
-				vadd(&compile, "-c");
-				if(streq(gohostarch, "amd64"))
-					vadd(&compile, "-m64");
-				else if(streq(gohostarch, "386"))
-					vadd(&compile, "-m32");
-	
-				vadd(&compile, "-I");
-				vadd(&compile, bpathf(&b, "%s/include", goroot));
-			}
-
-			if(streq(dir, "lib9"))
-				vadd(&compile, "-DPLAN9PORT");
-
-
-			vadd(&compile, "-I");
-			vadd(&compile, bstr(&path));
-
-			// lib9/goos.c gets the default constants hard-coded.
-			if(streq(name, "goos.c")) {
-				vadd(&compile, "-D");
-				vadd(&compile, bprintf(&b, "GOOS=\"%s\"", goos));
-				vadd(&compile, "-D");
-				vadd(&compile, bprintf(&b, "GOARCH=\"%s\"", goarch));
-				bprintf(&b1, "%s", goroot_final);
-				bsubst(&b1, "\\", "\\\\");  // turn into C string
-				vadd(&compile, "-D");
-				vadd(&compile, bprintf(&b, "GOROOT=\"%s\"", bstr(&b1)));
-				vadd(&compile, "-D");
-				vadd(&compile, bprintf(&b, "GOVERSION=\"%s\"", goversion));
-				vadd(&compile, "-D");
-				vadd(&compile, bprintf(&b, "GOARM=\"%s\"", goarm));
-				vadd(&compile, "-D");
-				vadd(&compile, bprintf(&b, "GO386=\"%s\"", go386));
-				vadd(&compile, "-D");
-				vadd(&compile, bprintf(&b, "GO_EXTLINK_ENABLED=\"%s\"", goextlinkenabled));
-			}
-
-			// gc/lex.c records the GOEXPERIMENT setting used during the build.
-			if(streq(name, "lex.c")) {
-				xgetenv(&b, "GOEXPERIMENT");
-				vadd(&compile, "-D");
-				vadd(&compile, bprintf(&b1, "GOEXPERIMENT=\"%s\"", bstr(&b)));
-			}
-		} else {
-			// Supporting files for a Go package.
-			if(hassuffix(files.p[i], ".s"))
-				vadd(&compile, bpathf(&b, "%s/%sa", tooldir, gochar));
-			else {
-				vadd(&compile, bpathf(&b, "%s/%sc", tooldir, gochar));
-				vadd(&compile, "-F");
-				vadd(&compile, "-V");
-				vadd(&compile, "-w");
-			}
-			vadd(&compile, "-I");
-			vadd(&compile, workdir);
-			vadd(&compile, "-I");
-			vadd(&compile, bprintf(&b, "%s/pkg/%s_%s", goroot, goos, goarch));
-			vadd(&compile, "-D");
-			vadd(&compile, bprintf(&b, "GOOS_%s", goos));
-			vadd(&compile, "-D");
-			vadd(&compile, bprintf(&b, "GOARCH_%s", goarch));
-			vadd(&compile, "-D");
-			vadd(&compile, bprintf(&b, "GOOS_GOARCH_%s_%s", goos, goarch));
-		}
-
-		bpathf(&b, "%s/%s", workdir, lastelem(files.p[i]));
-		doclean = 1;
-		if(!isgo && streq(gohostos, "darwin")) {
-			// To debug C programs on OS X, it is not enough to say -ggdb
-			// on the command line.  You have to leave the object files
-			// lying around too.  Leave them in pkg/obj/, which does not
-			// get removed when this tool exits.
-			bpathf(&b1, "%s/pkg/obj/%s", goroot, dir);
-			xmkdirall(bstr(&b1));
-			bpathf(&b, "%s/%s", bstr(&b1), lastelem(files.p[i]));
-			doclean = 0;
-		}
-
-		// Change the last character of the output file (which was c or s).
-		if(streq(gohostos, "plan9"))
-			b.p[b.len-1] = gohostchar[0];
-		else
-			b.p[b.len-1] = 'o';
-		vadd(&compile, "-o");
-		vadd(&compile, bstr(&b));
-		vadd(&compile, files.p[i]);
-		bgrunv(bstr(&path), CheckExit, &compile);
-
-		vadd(&link, bstr(&b));
-		if(doclean)
-			vadd(&clean, bstr(&b));
-	}
-	bgwait();
-
-	if(isgo) {
-		// The last loop was compiling individual files.
-		// Hand the Go files to the compiler en masse.
-		vreset(&compile);
-		vadd(&compile, bpathf(&b, "%s/%sg", tooldir, gochar));
-
-		bpathf(&b, "%s/_go_.a", workdir);
-		vadd(&compile, "-pack");
-		vadd(&compile, "-o");
-		vadd(&compile, bstr(&b));
-		vadd(&clean, bstr(&b));
-		if(!ispackcmd)
-			vadd(&link, bstr(&b));
-
-		vadd(&compile, "-p");
-		if(hasprefix(dir, "pkg/"))
-			vadd(&compile, dir+4);
-		else
-			vadd(&compile, "main");
-
-		if(streq(dir, "runtime"))
-			vadd(&compile, "-+");
-
-		vcopy(&compile, go.p, go.len);
-
-		runv(nil, bstr(&path), CheckExit, &compile);
-
-		if(ispackcmd) {
-			xremove(link.p[targ]);
-			dopack(link.p[targ], bstr(&b), &link.p[targ+1], link.len - (targ+1));
-			goto nobuild;
-		}
-	}
-
-	if(!islib && !isgo) {
-		// C binaries need the libraries explicitly, and -lm.
-		vcopy(&link, lib.p, lib.len);
-		if(!streq(gohostos, "plan9"))
-			vadd(&link, "-lm");
-	}
-
-	// Remove target before writing it.
-	xremove(link.p[targ]);
-
-	runv(nil, nil, CheckExit, &link);
-
-nobuild:
-	// In package runtime, we install runtime.h and cgocall.h too,
-	// for use by cgo compilation.
-	if(streq(dir, "runtime")) {
-		copyfile(bpathf(&b, "%s/pkg/%s_%s/cgocall.h", goroot, goos, goarch),
-			bpathf(&b1, "%s/src/runtime/cgocall.h", goroot), 0);
-		copyfile(bpathf(&b, "%s/pkg/%s_%s/runtime.h", goroot, goos, goarch),
-			bpathf(&b1, "%s/src/runtime/runtime.h", goroot), 0);
-	}
-
-
-out:
-	for(i=0; i<clean.len; i++)
-		xremove(clean.p[i]);
-
-	bfree(&b);
-	bfree(&b1);
-	bfree(&path);
-	vfree(&compile);
-	vfree(&files);
-	vfree(&link);
-	vfree(&go);
-	vfree(&missing);
-	vfree(&clean);
-	vfree(&lib);
-	vfree(&extra);
-}
-
-// matchfield reports whether the field matches this build.
-static bool
-matchfield(char *f)
-{
-	char *p;
-	bool res;
-
-	p = xstrrchr(f, ',');
-	if(p == nil)
-		return streq(f, goos) || streq(f, goarch) || streq(f, "cmd_go_bootstrap") || streq(f, "go1.1") || (streq(goos, "android") && streq(f, "linux"));
-	*p = 0;
-	res = matchfield(f) && matchfield(p+1);
-	*p = ',';
-	return res;
-}
-
-// shouldbuild reports whether we should build this file.
-// It applies the same rules that are used with context tags
-// in package go/build, except that the GOOS and GOARCH
-// can appear anywhere in the file name, not just after _.
-// In particular, they can be the entire file name (like windows.c).
-// We also allow the special tag cmd_go_bootstrap.
-// See ../go/bootstrap.go and package go/build.
-static bool
-shouldbuild(char *file, char *dir)
-{
-	char *name, *p;
-	int i, j, ret;
-	Buf b;
-	Vec lines, fields;
-	
-	// Check file name for GOOS or GOARCH.
-	name = lastelem(file);
-	for(i=0; i<nelem(okgoos); i++)
-		if(contains(name, okgoos[i]) && !streq(okgoos[i], goos))
-			return 0;
-	for(i=0; i<nelem(okgoarch); i++)
-		if(contains(name, okgoarch[i]) && !streq(okgoarch[i], goarch))
-			return 0;
-
-	// Omit test files.
-	if(contains(name, "_test"))
-		return 0;
-
-	// cmd/go/doc.go has a giant /* */ comment before
-	// it gets to the important detail that it is not part of
-	// package main.  We don't parse those comments,
-	// so special case that file.
-	if(hassuffix(file, "cmd/go/doc.go") || hassuffix(file, "cmd\\go\\doc.go"))
-		return 0;
-	if(hassuffix(file, "cmd/cgo/doc.go") || hassuffix(file, "cmd\\cgo\\doc.go"))
-		return 0;
-
-	// Check file contents for // +build lines.
-	binit(&b);
-	vinit(&lines);
-	vinit(&fields);
-
-	ret = 1;
-	readfile(&b, file);
-	splitlines(&lines, bstr(&b));
-	for(i=0; i<lines.len; i++) {
-		p = lines.p[i];
-		while(*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n')
-			p++;
-		if(*p == '\0')
-			continue;
-		if(contains(p, "package documentation")) {
-			ret = 0;
-			goto out;
-		}
-		if(contains(p, "package main") && !streq(dir, "cmd/go") && !streq(dir, "cmd/cgo")) {
-			ret = 0;
-			goto out;
-		}
-		if(!hasprefix(p, "//"))
-			break;
-		if(!contains(p, "+build"))
-			continue;
-		splitfields(&fields, lines.p[i]);
-		if(fields.len < 2 || !streq(fields.p[1], "+build"))
-			continue;
-		for(j=2; j<fields.len; j++) {
-			p = fields.p[j];
-			if((*p == '!' && !matchfield(p+1)) || matchfield(p))
-				goto fieldmatch;
-		}
-		ret = 0;
-		goto out;
-	fieldmatch:;
-	}
-
-out:
-	bfree(&b);
-	vfree(&lines);
-	vfree(&fields);
-
-	return ret;
-}
-
-// copy copies the file src to dst, via memory (so only good for small files).
-void
-copyfile(char *dst, char *src, int exec)
-{
-	Buf b;
-
-	if(vflag > 1)
-		errprintf("cp %s %s\n", src, dst);
-
-	binit(&b);
-	readfile(&b, src);
-	writefile(&b, dst, exec);
-	bfree(&b);
-}
-
-// dopack copies the package src to dst,
-// appending the files listed in extra.
-// The archive format is the traditional Unix ar format.
-static void
-dopack(char *dst, char *src, char **extra, int nextra)
-{
-	int i;
-	char c, *p, *q;
-	Buf b, bdst;
-	
-	binit(&b);
-	binit(&bdst);
-
-	readfile(&bdst, src);
-	for(i=0; i<nextra; i++) {
-		readfile(&b, extra[i]);
-		// find last path element for archive member name
-		p = xstrrchr(extra[i], '/');
-		if(p)
-			p++;
-		q = xstrrchr(extra[i], '\\');
-		if(q) {
-			q++;
-			if(p == nil || q > p)
-				p = q;
-		}
-		if(p == nil)
-			p = extra[i];
-		bwritef(&bdst, "%-16.16s%-12d%-6d%-6d%-8o%-10d`\n", p, 0, 0, 0, 0644, b.len);
-		bwriteb(&bdst, &b);
-		if(b.len&1) {
-			c = 0;
-			bwrite(&bdst, &c, 1);
-		}
-	}
-
-	writefile(&bdst, dst, 0);
-
-	bfree(&b);
-	bfree(&bdst);
-}
-
-// buildorder records the order of builds for the 'go bootstrap' command.
-static char *buildorder[] = {
-	"lib9",
-	"libbio",
-	"liblink",
-
-	"cmd/cc",  // must be before c
-	"cmd/gc",  // must be before g
-	"cmd/%sl",  // must be before a, c, g
-	"cmd/%sa",
-	"cmd/%sc",
-	"cmd/%sg",
-
-	// The dependency order here was copied from a buildscript
-	// back when there were build scripts.  Will have to
-	// be maintained by hand, but shouldn't change very
-	// often.
-	"runtime",
-	"errors",
-	"sync/atomic",
-	"sync",
-	"io",
-	"unicode",
-	"unicode/utf8",
-	"unicode/utf16",
-	"bytes",
-	"math",
-	"strings",
-	"strconv",
-	"bufio",
-	"sort",
-	"container/heap",
-	"encoding/base64",
-	"syscall",
-	"time",
-	"os",
-	"reflect",
-	"fmt",
-	"encoding",
-	"encoding/json",
-	"flag",
-	"path/filepath",
-	"path",
-	"io/ioutil",
-	"log",
-	"regexp/syntax",
-	"regexp",
-	"go/token",
-	"go/scanner",
-	"go/ast",
-	"go/parser",
-	"os/exec",
-	"os/signal",
-	"net/url",
-	"text/template/parse",
-	"text/template",
-	"go/doc",
-	"go/build",
-	"cmd/go",
-};
-
-// cleantab records the directories to clean in 'go clean'.
-// It is bigger than the buildorder because we clean all the
-// compilers but build only the $GOARCH ones.
-static char *cleantab[] = {
-	// Commands and C libraries.
-	"cmd/5a",
-	"cmd/5c",
-	"cmd/5g",
-	"cmd/5l",
-	"cmd/6a",
-	"cmd/6c",
-	"cmd/6g",
-	"cmd/6l",
-	"cmd/8a",
-	"cmd/8c",
-	"cmd/8g",
-	"cmd/8l",
-	"cmd/cc",
-	"cmd/gc",
-	"cmd/go",	
-	"lib9",
-	"libbio",
-	"liblink",
-
-	// Go packages.
-	"bufio",
-	"bytes",
-	"container/heap",
-	"encoding",
-	"encoding/base64",
-	"encoding/json",
-	"errors",
-	"flag",
-	"fmt",
-	"go/ast",
-	"go/build",
-	"go/doc",
-	"go/parser",
-	"go/scanner",
-	"go/token",
-	"io",
-	"io/ioutil",
-	"log",
-	"math",
-	"net/url",
-	"os",
-	"os/exec",
-	"path",
-	"path/filepath",
-	"reflect",
-	"regexp",
-	"regexp/syntax",
-	"runtime",
-	"sort",
-	"strconv",
-	"strings",
-	"sync",
-	"sync/atomic",
-	"syscall",
-	"text/template",
-	"text/template/parse",
-	"time",
-	"unicode",
-	"unicode/utf16",
-	"unicode/utf8",
-};
-
-static void
-clean(void)
-{
-	int i, j, k;
-	Buf b, path;
-	Vec dir;
-
-	binit(&b);
-	binit(&path);
-	vinit(&dir);
-
-	for(i=0; i<nelem(cleantab); i++) {
-		bpathf(&path, "%s/src/%s", goroot, cleantab[i]);
-		xreaddir(&dir, bstr(&path));
-		// Remove generated files.
-		for(j=0; j<dir.len; j++) {
-			for(k=0; k<nelem(gentab); k++) {
-				if(hasprefix(dir.p[j], gentab[k].nameprefix))
-					xremove(bpathf(&b, "%s/%s", bstr(&path), dir.p[j]));
-			}
-		}
-		// Remove generated binary named for directory.
-		if(hasprefix(cleantab[i], "cmd/"))
-			xremove(bpathf(&b, "%s/%s", bstr(&path), cleantab[i]+4));
-	}
-
-	// remove src/runtime/z* unconditionally
-	vreset(&dir);
-	bpathf(&path, "%s/src/runtime", goroot);
-	xreaddir(&dir, bstr(&path));
-	for(j=0; j<dir.len; j++) {
-		if(hasprefix(dir.p[j], "z"))
-			xremove(bpathf(&b, "%s/%s", bstr(&path), dir.p[j]));
-	}
-
-	if(rebuildall) {
-		// Remove object tree.
-		xremoveall(bpathf(&b, "%s/pkg/obj/%s_%s", goroot, gohostos, gohostarch));
-
-		// Remove installed packages and tools.
-		xremoveall(bpathf(&b, "%s/pkg/%s_%s", goroot, gohostos, gohostarch));
-		xremoveall(bpathf(&b, "%s/pkg/%s_%s", goroot, goos, goarch));
-		xremoveall(tooldir);
-
-		// Remove cached version info.
-		xremove(bpathf(&b, "%s/VERSION.cache", goroot));
-	}
-
-	bfree(&b);
-	bfree(&path);
-	vfree(&dir);
-}
-
-/*
- * command implementations
- */
-
-void
-usage(void)
-{
-	xprintf("usage: go tool dist [command]\n"
-		"Commands are:\n"
-		"\n"
-		"banner         print installation banner\n"
-		"bootstrap      rebuild everything\n"
-		"clean          deletes all built files\n"
-		"env [-p]       print environment (-p: include $PATH)\n"
-		"install [dir]  install individual directory\n"
-		"version        print Go version\n"
-		"\n"
-		"All commands take -v flags to emit extra information.\n"
-	);
-	xexit(2);
-}
-
-// The env command prints the default environment.
-void
-cmdenv(int argc, char **argv)
-{
-	bool pflag;
-	char *sep;
-	Buf b, b1;
-	char *format;
-
-	binit(&b);
-	binit(&b1);
-
-	format = "%s=\"%s\"\n";
-	pflag = 0;
-	ARGBEGIN{
-	case '9':
-		format = "%s='%s'\n";
-		break;
-	case 'p':
-		pflag = 1;
-		break;
-	case 'v':
-		vflag++;
-		break;
-	case 'w':
-		format = "set %s=%s\r\n";
-		break;
-	default:
-		usage();
-	}ARGEND
-
-	if(argc > 0)
-		usage();
-
-	xprintf(format, "CC", defaultcc);
-	xprintf(format, "CC_FOR_TARGET", defaultcctarget);
-	xprintf(format, "GOROOT", goroot);
-	xprintf(format, "GOBIN", gobin);
-	xprintf(format, "GOARCH", goarch);
-	xprintf(format, "GOOS", goos);
-	xprintf(format, "GOHOSTARCH", gohostarch);
-	xprintf(format, "GOHOSTOS", gohostos);
-	xprintf(format, "GOTOOLDIR", tooldir);
-	xprintf(format, "GOCHAR", gochar);
-	if(streq(goarch, "arm"))
-		xprintf(format, "GOARM", goarm);
-	if(streq(goarch, "386"))
-		xprintf(format, "GO386", go386);
-
-	if(pflag) {
-		sep = ":";
-		if(streq(gohostos, "windows"))
-			sep = ";";
-		xgetenv(&b, "PATH");
-		bprintf(&b1, "%s%s%s", gobin, sep, bstr(&b));
-		xprintf(format, "PATH", bstr(&b1));
-	}
-
-	bfree(&b);
-	bfree(&b1);
-}
-
-// The bootstrap command runs a build from scratch,
-// stopping at having installed the go_bootstrap command.
-void
-cmdbootstrap(int argc, char **argv)
-{
-	int i;
-	Buf b;
-	char *oldgoos, *oldgoarch, *oldgochar;
-
-	binit(&b);
-
-	ARGBEGIN{
-	case 'a':
-		rebuildall = 1;
-		break;
-	case 's':
-		sflag++;
-		break;
-	case 'v':
-		vflag++;
-		break;
-	default:
-		usage();
-	}ARGEND
-
-	if(argc > 0)
-		usage();
-
-	if(isdir(bpathf(&b, "%s/src/pkg", goroot))) {
-		fatal("\n\n"
-			"The Go package sources have moved to $GOROOT/src.\n"
-			"*** %s still exists. ***\n"
-			"It probably contains stale files that may confuse the build.\n"
-			"Please (check what's there and) remove it and try again.\n"
-			"See http://golang.org/s/go14nopkg\n", bpathf(&b, "%s/src/pkg", goroot));
-	}
-	
-	if(rebuildall)
-		clean();
-	goversion = findgoversion();
-	setup();
-
-	xsetenv("GOROOT", goroot);
-	xsetenv("GOROOT_FINAL", goroot_final);
-
-	// For the main bootstrap, building for host os/arch.
-	oldgoos = goos;
-	oldgoarch = goarch;
-	oldgochar = gochar;
-	goos = gohostos;
-	goarch = gohostarch;
-	gochar = gohostchar;
-	xsetenv("GOARCH", goarch);
-	xsetenv("GOOS", goos);
-
-	for(i=0; i<nelem(buildorder); i++) {
-		install(bprintf(&b, buildorder[i], gohostchar));
-		if(!streq(oldgochar, gohostchar) && xstrstr(buildorder[i], "%s"))
-			install(bprintf(&b, buildorder[i], oldgochar));
-	}
-
-	goos = oldgoos;
-	goarch = oldgoarch;
-	gochar = oldgochar;
-	xsetenv("GOARCH", goarch);
-	xsetenv("GOOS", goos);
-
-	// Build runtime for actual goos/goarch too.
-	if(!streq(goos, gohostos) || !streq(goarch, gohostarch))
-		install("runtime");
-
-	bfree(&b);
-}
-
-static char*
-defaulttarg(void)
-{
-	char *p;
-	Buf pwd, src, real_src;
-
-	binit(&pwd);
-	binit(&src);
-	binit(&real_src);
-
-	// xgetwd might return a path with symlinks fully resolved, and if
-	// there happens to be symlinks in goroot, then the hasprefix test
-	// will never succeed. Instead, we use xrealwd to get a canonical
-	// goroot/src before the comparison to avoid this problem.
-	xgetwd(&pwd);
-	p = btake(&pwd);
-	bpathf(&src, "%s/src/", goroot);
-	xrealwd(&real_src, bstr(&src));
-	if(!hasprefix(p, bstr(&real_src)))
-		fatal("current directory %s is not under %s", p, bstr(&real_src));
-	p += real_src.len;
-	// guard againt xrealwd return the directory without the trailing /
-	if(*p == slash[0])
-		p++;
-
-	bfree(&pwd);
-	bfree(&src);
-	bfree(&real_src);
-
-	return p;
-}
-
-// Install installs the list of packages named on the command line.
-void
-cmdinstall(int argc, char **argv)
-{
-	int i;
-
-	ARGBEGIN{
-	case 's':
-		sflag++;
-		break;
-	case 'v':
-		vflag++;
-		break;
-	default:
-		usage();
-	}ARGEND
-
-	if(argc == 0)
-		install(defaulttarg());
-
-	for(i=0; i<argc; i++)
-		install(argv[i]);
-}
-
-// Clean deletes temporary objects.
-// Clean -i deletes the installed objects too.
-void
-cmdclean(int argc, char **argv)
-{
-	ARGBEGIN{
-	case 'v':
-		vflag++;
-		break;
-	default:
-		usage();
-	}ARGEND
-
-	if(argc > 0)
-		usage();
-
-	clean();
-}
-
-// Banner prints the 'now you've installed Go' banner.
-void
-cmdbanner(int argc, char **argv)
-{
-	char *pathsep, *pid, *ns;
-	Buf b, b1, search, path;
-
-	ARGBEGIN{
-	case 'v':
-		vflag++;
-		break;
-	default:
-		usage();
-	}ARGEND
-
-	if(argc > 0)
-		usage();
-
-	binit(&b);
-	binit(&b1);
-	binit(&search);
-	binit(&path);
-
-	xprintf("\n");
-	xprintf("---\n");
-	xprintf("Installed Go for %s/%s in %s\n", goos, goarch, goroot);
-	xprintf("Installed commands in %s\n", gobin);
-
-	if(!xsamefile(goroot_final, goroot)) {
-		// If the files are to be moved, don't check that gobin
-		// is on PATH; assume they know what they are doing.
-	} else if(streq(gohostos, "plan9")) {
-		// Check that gobin is bound before /bin.
-		readfile(&b, "#c/pid");
-		bsubst(&b, " ", "");
-		pid = btake(&b);
-		bprintf(&b, "/proc/%s/ns", pid);
-		ns = btake(&b);
-		readfile(&b, ns);
-		bprintf(&search, "bind -b %s /bin\n", gobin);
-		if(xstrstr(bstr(&b), bstr(&search)) == nil)
-			xprintf("*** You need to bind %s before /bin.\n", gobin);
-	} else {
-		// Check that gobin appears in $PATH.
-		xgetenv(&b, "PATH");
-		pathsep = ":";
-		if(streq(gohostos, "windows"))
-			pathsep = ";";
-		bprintf(&b1, "%s%s%s", pathsep, bstr(&b), pathsep);
-		bprintf(&search, "%s%s%s", pathsep, gobin, pathsep);
-		if(xstrstr(bstr(&b1), bstr(&search)) == nil)
-			xprintf("*** You need to add %s to your PATH.\n", gobin);
-	}
-
-	if(streq(gohostos, "darwin")) {
-		if(isfile(bpathf(&path, "%s/cov", tooldir)))
-			xprintf("\n"
-				"On OS X the debuggers must be installed setgid procmod.\n"
-				"Read and run ./sudo.bash to install the debuggers.\n");
-	}
-
-	if(!xsamefile(goroot_final, goroot)) {
-		xprintf("\n"
-			"The binaries expect %s to be copied or moved to %s\n",
-			goroot, goroot_final);
-	}
-
-	bfree(&b);
-	bfree(&b1);
-	bfree(&search);
-	bfree(&path);
-}
-
-// Version prints the Go version.
-void
-cmdversion(int argc, char **argv)
-{
-	ARGBEGIN{
-	case 'v':
-		vflag++;
-		break;
-	default:
-		usage();
-	}ARGEND
-
-	if(argc > 0)
-		usage();
-
-	xprintf("%s\n", goversion);
-}
diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go
new file mode 100644
index 0000000..184f973
--- /dev/null
+++ b/src/cmd/dist/build.go
@@ -0,0 +1,1202 @@
+// 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.
+
+package main
+
+import (
+	"bytes"
+	"flag"
+	"fmt"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"strings"
+)
+
+// Initialization for any invocation.
+
+// The usual variables.
+var (
+	goarch           string
+	gobin            string
+	gohostarch       string
+	gohostos         string
+	goos             string
+	goarm            string
+	go386            string
+	goroot           string
+	goroot_final     string
+	goextlinkenabled string
+	workdir          string
+	tooldir          string
+	oldgoos          string
+	oldgoarch        string
+	slash            string
+	exe              string
+	defaultcc        string
+	defaultcflags    string
+	defaultldflags   string
+	defaultcxxtarget string
+	defaultcctarget  string
+	rebuildall       bool
+	defaultclang     bool
+
+	sflag bool // build static binaries
+	vflag int  // verbosity
+)
+
+// The known architectures.
+var okgoarch = []string{
+	"386",
+	"amd64",
+	"amd64p32",
+	"arm",
+	"arm64",
+	"ppc64",
+	"ppc64le",
+}
+
+// The known operating systems.
+var okgoos = []string{
+	"darwin",
+	"dragonfly",
+	"linux",
+	"android",
+	"solaris",
+	"freebsd",
+	"nacl",
+	"netbsd",
+	"openbsd",
+	"plan9",
+	"windows",
+}
+
+// find reports the first index of p in l[0:n], or else -1.
+func find(p string, l []string) int {
+	for i, s := range l {
+		if p == s {
+			return i
+		}
+	}
+	return -1
+}
+
+// xinit handles initialization of the various global state, like goroot and goarch.
+func xinit() {
+	goroot = os.Getenv("GOROOT")
+	if slash == "/" && len(goroot) > 1 || slash == `\` && len(goroot) > 3 {
+		// if not "/" or "c:\", then strip trailing path separator
+		goroot = strings.TrimSuffix(goroot, slash)
+	}
+	if goroot == "" {
+		fatal("$GOROOT must be set")
+	}
+
+	goroot_final = os.Getenv("GOROOT_FINAL")
+	if goroot_final == "" {
+		goroot_final = goroot
+	}
+
+	b := os.Getenv("GOBIN")
+	if b == "" {
+		b = goroot + slash + "bin"
+	}
+	gobin = b
+
+	b = os.Getenv("GOOS")
+	if b == "" {
+		b = gohostos
+	}
+	goos = b
+	if find(goos, okgoos) < 0 {
+		fatal("unknown $GOOS %s", goos)
+	}
+
+	b = os.Getenv("GOARM")
+	if b == "" {
+		b = xgetgoarm()
+	}
+	goarm = b
+
+	b = os.Getenv("GO386")
+	if b == "" {
+		if cansse2() {
+			b = "sse2"
+		} else {
+			b = "387"
+		}
+	}
+	go386 = b
+
+	p := pathf("%s/src/all.bash", goroot)
+	if !isfile(p) {
+		fatal("$GOROOT is not set correctly or not exported\n"+
+			"\tGOROOT=%s\n"+
+			"\t%s does not exist", goroot, p)
+	}
+
+	b = os.Getenv("GOHOSTARCH")
+	if b != "" {
+		gohostarch = b
+	}
+
+	if find(gohostarch, okgoarch) < 0 {
+		fatal("unknown $GOHOSTARCH %s", gohostarch)
+	}
+
+	b = os.Getenv("GOARCH")
+	if b == "" {
+		b = gohostarch
+	}
+	goarch = b
+	if find(goarch, okgoarch) < 0 {
+		fatal("unknown $GOARCH %s", goarch)
+	}
+
+	b = os.Getenv("GO_EXTLINK_ENABLED")
+	if b != "" {
+		if b != "0" && b != "1" {
+			fatal("unknown $GO_EXTLINK_ENABLED %s", b)
+		}
+		goextlinkenabled = b
+	}
+
+	b = os.Getenv("CC")
+	if b == "" {
+		// Use clang on OS X, because gcc is deprecated there.
+		// Xcode for OS X 10.9 Mavericks will ship a fake "gcc" binary that
+		// actually runs clang. We prepare different command
+		// lines for the two binaries, so it matters what we call it.
+		// See golang.org/issue/5822.
+		if defaultclang {
+			b = "clang"
+		} else {
+			b = "gcc"
+		}
+	}
+	defaultcc = b
+
+	defaultcflags = os.Getenv("CFLAGS")
+
+	defaultldflags = os.Getenv("LDFLAGS")
+
+	b = os.Getenv("CC_FOR_TARGET")
+	if b == "" {
+		b = defaultcc
+	}
+	defaultcctarget = b
+
+	b = os.Getenv("CXX_FOR_TARGET")
+	if b == "" {
+		b = os.Getenv("CXX")
+		if b == "" {
+			if defaultclang {
+				b = "clang++"
+			} else {
+				b = "g++"
+			}
+		}
+	}
+	defaultcxxtarget = b
+
+	// For tools being invoked but also for os.ExpandEnv.
+	os.Setenv("GO386", go386)
+	os.Setenv("GOARCH", goarch)
+	os.Setenv("GOARM", goarm)
+	os.Setenv("GOHOSTARCH", gohostarch)
+	os.Setenv("GOHOSTOS", gohostos)
+	os.Setenv("GOOS", goos)
+	os.Setenv("GOROOT", goroot)
+	os.Setenv("GOROOT_FINAL", goroot_final)
+
+	// Make the environment more predictable.
+	os.Setenv("LANG", "C")
+	os.Setenv("LANGUAGE", "en_US.UTF8")
+
+	workdir = xworkdir()
+	xatexit(rmworkdir)
+
+	tooldir = pathf("%s/pkg/tool/%s_%s", goroot, gohostos, gohostarch)
+}
+
+// rmworkdir deletes the work directory.
+func rmworkdir() {
+	if vflag > 1 {
+		errprintf("rm -rf %s\n", workdir)
+	}
+	xremoveall(workdir)
+}
+
+// Remove trailing spaces.
+func chomp(s string) string {
+	return strings.TrimRight(s, " \t\r\n")
+}
+
+func branchtag(branch string) (tag string, precise bool) {
+	b := run(goroot, CheckExit, "git", "log", "--decorate=full", "--format=format:%d", "master.."+branch)
+	tag = branch
+	for _, line := range splitlines(b) {
+		// Each line is either blank, or looks like
+		//	  (tag: refs/tags/go1.4rc2, refs/remotes/origin/release-branch.go1.4, refs/heads/release-branch.go1.4)
+		// We need to find an element starting with refs/tags/.
+		i := strings.Index(line, " refs/tags/")
+		if i < 0 {
+			continue
+		}
+		i += len(" refs/tags/")
+		// The tag name ends at a comma or paren (prefer the first).
+		j := strings.Index(line[i:], ",")
+		if j < 0 {
+			j = strings.Index(line[i:], ")")
+		}
+		if j < 0 {
+			continue // malformed line; ignore it
+		}
+		tag = line[i : i+j]
+		if i == 0 {
+			precise = true // tag denotes HEAD
+		}
+		break
+	}
+	return
+}
+
+// findgoversion determines the Go version to use in the version string.
+func findgoversion() string {
+	// The $GOROOT/VERSION file takes priority, for distributions
+	// without the source repo.
+	path := pathf("%s/VERSION", goroot)
+	if isfile(path) {
+		b := chomp(readfile(path))
+		// Commands such as "dist version > VERSION" will cause
+		// the shell to create an empty VERSION file and set dist's
+		// stdout to its fd. dist in turn looks at VERSION and uses
+		// its content if available, which is empty at this point.
+		// Only use the VERSION file if it is non-empty.
+		if b != "" {
+			return b
+		}
+	}
+
+	// The $GOROOT/VERSION.cache file is a cache to avoid invoking
+	// git every time we run this command.  Unlike VERSION, it gets
+	// deleted by the clean command.
+	path = pathf("%s/VERSION.cache", goroot)
+	if isfile(path) {
+		return chomp(readfile(path))
+	}
+
+	// Show a nicer error message if this isn't a Git repo.
+	if !isGitRepo() {
+		fatal("FAILED: not a Git repo; must put a VERSION file in $GOROOT")
+	}
+
+	// Otherwise, use Git.
+	// What is the current branch?
+	branch := chomp(run(goroot, CheckExit, "git", "rev-parse", "--abbrev-ref", "HEAD"))
+
+	// What are the tags along the current branch?
+	tag := "devel"
+	precise := false
+
+	// If we're on a release branch, use the closest matching tag
+	// that is on the release branch (and not on the master branch).
+	if strings.HasPrefix(branch, "release-branch.") {
+		tag, precise = branchtag(branch)
+	}
+
+	if !precise {
+		// Tag does not point at HEAD; add hash and date to version.
+		tag += chomp(run(goroot, CheckExit, "git", "log", "-n", "1", "--format=format: +%h %cd", "HEAD"))
+	}
+
+	// Cache version.
+	writefile(tag, path, 0)
+
+	return tag
+}
+
+// isGitRepo reports whether the working directory is inside a Git repository.
+func isGitRepo() bool {
+	p := ".git"
+	for {
+		fi, err := os.Stat(p)
+		if os.IsNotExist(err) {
+			p = filepath.Join("..", p)
+			continue
+		}
+		if err != nil || !fi.IsDir() {
+			return false
+		}
+		return true
+	}
+}
+
+/*
+ * Initial tree setup.
+ */
+
+// The old tools that no longer live in $GOBIN or $GOROOT/bin.
+var oldtool = []string{
+	"5a", "5c", "5g", "5l",
+	"6a", "6c", "6g", "6l",
+	"8a", "8c", "8g", "8l",
+	"9a", "9c", "9g", "9l",
+	"6cov",
+	"6nm",
+	"6prof",
+	"cgo",
+	"ebnflint",
+	"goapi",
+	"gofix",
+	"goinstall",
+	"gomake",
+	"gopack",
+	"gopprof",
+	"gotest",
+	"gotype",
+	"govet",
+	"goyacc",
+	"quietgcc",
+}
+
+// Unreleased directories (relative to $GOROOT) that should
+// not be in release branches.
+var unreleased = []string{
+	"src/cmd/newlink",
+	"src/cmd/objwriter",
+	"src/debug/goobj",
+	"src/old",
+}
+
+// setup sets up the tree for the initial build.
+func setup() {
+	// Create bin directory.
+	if p := pathf("%s/bin", goroot); !isdir(p) {
+		xmkdir(p)
+	}
+
+	// Create package directory.
+	if p := pathf("%s/pkg", goroot); !isdir(p) {
+		xmkdir(p)
+	}
+
+	p := pathf("%s/pkg/%s_%s", goroot, gohostos, gohostarch)
+	if rebuildall {
+		xremoveall(p)
+	}
+	xmkdirall(p)
+
+	if goos != gohostos || goarch != gohostarch {
+		p := pathf("%s/pkg/%s_%s", goroot, goos, goarch)
+		if rebuildall {
+			xremoveall(p)
+		}
+		xmkdirall(p)
+	}
+
+	// Create object directory.
+	// We keep it in pkg/ so that all the generated binaries
+	// are in one tree.  If pkg/obj/libgc.a exists, it is a dreg from
+	// before we used subdirectories of obj.  Delete all of obj
+	// to clean up.
+	if p := pathf("%s/pkg/obj/libgc.a", goroot); isfile(p) {
+		xremoveall(pathf("%s/pkg/obj", goroot))
+	}
+	p = pathf("%s/pkg/obj/%s_%s", goroot, gohostos, gohostarch)
+	if rebuildall {
+		xremoveall(p)
+	}
+	xmkdirall(p)
+
+	// Create tool directory.
+	// We keep it in pkg/, just like the object directory above.
+	if rebuildall {
+		xremoveall(tooldir)
+	}
+	xmkdirall(tooldir)
+
+	// Remove tool binaries from before the tool/gohostos_gohostarch
+	xremoveall(pathf("%s/bin/tool", goroot))
+
+	// Remove old pre-tool binaries.
+	for _, old := range oldtool {
+		xremove(pathf("%s/bin/%s", goroot, old))
+	}
+
+	// If $GOBIN is set and has a Go compiler, it must be cleaned.
+	for _, char := range "56789" {
+		if isfile(pathf("%s%s%c%s", gobin, slash, char, "g")) {
+			for _, old := range oldtool {
+				xremove(pathf("%s/%s", gobin, old))
+			}
+			break
+		}
+	}
+
+	// For release, make sure excluded things are excluded.
+	goversion := findgoversion()
+	if strings.HasPrefix(goversion, "release.") || (strings.HasPrefix(goversion, "go") && !strings.Contains(goversion, "beta")) {
+		for _, dir := range unreleased {
+			if p := pathf("%s/%s", goroot, dir); isdir(p) {
+				fatal("%s should not exist in release build", p)
+			}
+		}
+	}
+}
+
+/*
+ * Tool building
+ */
+
+// deptab lists changes to the default dependencies for a given prefix.
+// deps ending in /* read the whole directory; deps beginning with -
+// exclude files with that prefix.
+var deptab = []struct {
+	prefix string   // prefix of target
+	dep    []string // dependency tweaks for targets with that prefix
+}{
+	{"cmd/go", []string{
+		"zdefaultcc.go",
+	}},
+	{"runtime", []string{
+		"zversion.go",
+	}},
+}
+
+// depsuffix records the allowed suffixes for source files.
+var depsuffix = []string{
+	".s",
+	".go",
+}
+
+// gentab records how to generate some trivial files.
+var gentab = []struct {
+	nameprefix string
+	gen        func(string, string)
+}{
+	{"zdefaultcc.go", mkzdefaultcc},
+	{"zversion.go", mkzversion},
+
+	// not generated anymore, but delete the file if we see it
+	{"enam.c", nil},
+	{"anames5.c", nil},
+	{"anames6.c", nil},
+	{"anames8.c", nil},
+	{"anames9.c", nil},
+}
+
+// install installs the library, package, or binary associated with dir,
+// which is relative to $GOROOT/src.
+func install(dir string) {
+	if vflag > 0 {
+		if goos != gohostos || goarch != gohostarch {
+			errprintf("%s (%s/%s)\n", dir, goos, goarch)
+		} else {
+			errprintf("%s\n", dir)
+		}
+	}
+
+	var clean []string
+	defer func() {
+		for _, name := range clean {
+			xremove(name)
+		}
+	}()
+
+	// path = full path to dir.
+	path := pathf("%s/src/%s", goroot, dir)
+	name := filepath.Base(dir)
+
+	ispkg := !strings.HasPrefix(dir, "cmd/") || strings.HasPrefix(dir, "cmd/internal/") || strings.HasPrefix(dir, "cmd/asm/internal/")
+
+	// Start final link command line.
+	// Note: code below knows that link.p[targ] is the target.
+	var (
+		link      []string
+		targ      int
+		ispackcmd bool
+	)
+	if ispkg {
+		// Go library (package).
+		ispackcmd = true
+		link = []string{"pack", pathf("%s/pkg/%s_%s/%s.a", goroot, goos, goarch, dir)}
+		targ = len(link) - 1
+		xmkdirall(filepath.Dir(link[targ]))
+	} else {
+		// Go command.
+		elem := name
+		if elem == "go" {
+			elem = "go_bootstrap"
+		}
+		link = []string{pathf("%s/link", tooldir), "-o", pathf("%s/%s%s", tooldir, elem, exe)}
+		targ = len(link) - 1
+	}
+	ttarg := mtime(link[targ])
+
+	// Gather files that are sources for this target.
+	// Everything in that directory, and any target-specific
+	// additions.
+	files := xreaddir(path)
+
+	// Remove files beginning with . or _,
+	// which are likely to be editor temporary files.
+	// This is the same heuristic build.ScanDir uses.
+	// There do exist real C files beginning with _,
+	// so limit that check to just Go files.
+	files = filter(files, func(p string) bool {
+		return !strings.HasPrefix(p, ".") && (!strings.HasPrefix(p, "_") || !strings.HasSuffix(p, ".go"))
+	})
+
+	for _, dt := range deptab {
+		if dir == dt.prefix || strings.HasSuffix(dt.prefix, "/") && strings.HasPrefix(dir, dt.prefix) {
+			for _, p := range dt.dep {
+				p = os.ExpandEnv(p)
+				files = append(files, p)
+			}
+		}
+	}
+	files = uniq(files)
+
+	// Convert to absolute paths.
+	for i, p := range files {
+		if !isabs(p) {
+			files[i] = pathf("%s/%s", path, p)
+		}
+	}
+
+	// Is the target up-to-date?
+	var gofiles, missing []string
+	stale := rebuildall
+	files = filter(files, func(p string) bool {
+		for _, suf := range depsuffix {
+			if strings.HasSuffix(p, suf) {
+				goto ok
+			}
+		}
+		return false
+	ok:
+		t := mtime(p)
+		if !t.IsZero() && !strings.HasSuffix(p, ".a") && !shouldbuild(p, dir) {
+			return false
+		}
+		if strings.HasSuffix(p, ".go") {
+			gofiles = append(gofiles, p)
+		}
+		if t.After(ttarg) {
+			stale = true
+		}
+		if t.IsZero() {
+			missing = append(missing, p)
+		}
+		return true
+	})
+
+	// If there are no files to compile, we're done.
+	if len(files) == 0 {
+		return
+	}
+
+	if !stale {
+		return
+	}
+
+	// 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/include/textflag.h", goroot),
+			pathf("%s/src/runtime/textflag.h", goroot), 0)
+		copyfile(pathf("%s/pkg/include/funcdata.h", goroot),
+			pathf("%s/src/runtime/funcdata.h", goroot), 0)
+	}
+
+	// Generate any missing files; regenerate existing ones.
+	for _, p := range files {
+		elem := filepath.Base(p)
+		for _, gt := range gentab {
+			if gt.gen == nil {
+				continue
+			}
+			if strings.HasPrefix(elem, gt.nameprefix) {
+				if vflag > 1 {
+					errprintf("generate %s\n", p)
+				}
+				gt.gen(path, p)
+				// Do not add generated file to clean list.
+				// In runtime, we want to be able to
+				// build the package with the go tool,
+				// and it assumes these generated files already
+				// exist (it does not know how to build them).
+				// The 'clean' command can remove
+				// the generated files.
+				goto built
+			}
+		}
+		// Did not rebuild p.
+		if find(p, missing) >= 0 {
+			fatal("missing file %s", p)
+		}
+	built:
+	}
+
+	if goos != gohostos || goarch != gohostarch {
+		// We've generated the right files; the go command can do the build.
+		if vflag > 1 {
+			errprintf("skip build for cross-compile %s\n", dir)
+		}
+		return
+	}
+
+	var archive string
+	// The next loop will compile individual non-Go files.
+	// Hand the Go files to the compiler en masse.
+	// For package runtime, this writes go_asm.h, which
+	// the assembly files will need.
+	pkg := dir
+	if strings.HasPrefix(dir, "cmd/") {
+		pkg = "main"
+	}
+	b := pathf("%s/_go_.a", workdir)
+	clean = append(clean, b)
+	if !ispackcmd {
+		link = append(link, b)
+	} else {
+		archive = b
+	}
+	compile := []string{pathf("%s/compile", tooldir), "-pack", "-o", b, "-p", pkg}
+	if dir == "runtime" {
+		compile = append(compile, "-+", "-asmhdr", pathf("%s/go_asm.h", workdir))
+	}
+	compile = append(compile, gofiles...)
+	run(path, CheckExit|ShowOutput, compile...)
+
+	// Compile the files.
+	for _, p := range files {
+		if !strings.HasSuffix(p, ".s") {
+			continue
+		}
+
+		var compile []string
+		// Assembly file for a Go package.
+		compile = []string{
+			pathf("%s/asm", tooldir),
+			"-I", workdir,
+			"-I", pathf("%s/pkg/include", goroot),
+			"-D", "GOOS_" + goos,
+			"-D", "GOARCH_" + goarch,
+			"-D", "GOOS_GOARCH_" + goos + "_" + goarch,
+		}
+
+		doclean := true
+		b := pathf("%s/%s", workdir, filepath.Base(p))
+
+		// Change the last character of the output file (which was c or s).
+		b = b[:len(b)-1] + "o"
+		compile = append(compile, "-o", b, p)
+		bgrun(path, compile...)
+
+		link = append(link, b)
+		if doclean {
+			clean = append(clean, b)
+		}
+	}
+	bgwait()
+
+	if ispackcmd {
+		xremove(link[targ])
+		dopack(link[targ], archive, link[targ+1:])
+		return
+	}
+
+	// Remove target before writing it.
+	xremove(link[targ])
+	run("", CheckExit|ShowOutput, link...)
+}
+
+// matchfield reports whether the field (x,y,z) matches this build.
+// all the elements in the field must be satisfied.
+func matchfield(f string) bool {
+	for _, tag := range strings.Split(f, ",") {
+		if !matchtag(tag) {
+			return false
+		}
+	}
+	return true
+}
+
+// matchtag reports whether the tag (x or !x) matches this build.
+func matchtag(tag string) bool {
+	if tag == "" {
+		return false
+	}
+	if tag[0] == '!' {
+		if len(tag) == 1 || tag[1] == '!' {
+			return false
+		}
+		return !matchtag(tag[1:])
+	}
+	return tag == goos || tag == goarch || tag == "cmd_go_bootstrap" || tag == "go1.1" || (goos == "android" && tag == "linux")
+}
+
+// shouldbuild reports whether we should build this file.
+// It applies the same rules that are used with context tags
+// in package go/build, except that the GOOS and GOARCH
+// can appear anywhere in the file name, not just after _.
+// In particular, they can be the entire file name (like windows.c).
+// We also allow the special tag cmd_go_bootstrap.
+// See ../go/bootstrap.go and package go/build.
+func shouldbuild(file, dir string) bool {
+	// Check file name for GOOS or GOARCH.
+	name := filepath.Base(file)
+	excluded := func(list []string, ok string) bool {
+		for _, x := range list {
+			if x == ok {
+				continue
+			}
+			i := strings.Index(name, x)
+			if i < 0 {
+				continue
+			}
+			i += len(x)
+			if i == len(name) || name[i] == '.' || name[i] == '_' {
+				return true
+			}
+		}
+		return false
+	}
+	if excluded(okgoos, goos) || excluded(okgoarch, goarch) {
+		return false
+	}
+
+	// Omit test files.
+	if strings.Contains(name, "_test") {
+		return false
+	}
+
+	// Check file contents for // +build lines.
+	for _, p := range splitlines(readfile(file)) {
+		p = strings.TrimSpace(p)
+		if p == "" {
+			continue
+		}
+		if strings.Contains(p, "package documentation") {
+			return false
+		}
+		if strings.Contains(p, "package main") && dir != "cmd/go" && dir != "cmd/cgo" {
+			return false
+		}
+		if !strings.HasPrefix(p, "//") {
+			break
+		}
+		if !strings.Contains(p, "+build") {
+			continue
+		}
+		fields := splitfields(p)
+		if len(fields) < 2 || fields[1] != "+build" {
+			continue
+		}
+		for _, p := range fields[2:] {
+			if matchfield(p) {
+				goto fieldmatch
+			}
+		}
+		return false
+	fieldmatch:
+	}
+
+	return true
+}
+
+// copy copies the file src to dst, via memory (so only good for small files).
+func copyfile(dst, src string, flag int) {
+	if vflag > 1 {
+		errprintf("cp %s %s\n", src, dst)
+	}
+	writefile(readfile(src), dst, flag)
+}
+
+// dopack copies the package src to dst,
+// appending the files listed in extra.
+// The archive format is the traditional Unix ar format.
+func dopack(dst, src string, extra []string) {
+	bdst := bytes.NewBufferString(readfile(src))
+	for _, file := range extra {
+		b := readfile(file)
+		// find last path element for archive member name
+		i := strings.LastIndex(file, "/") + 1
+		j := strings.LastIndex(file, `\`) + 1
+		if i < j {
+			i = j
+		}
+		fmt.Fprintf(bdst, "%-16.16s%-12d%-6d%-6d%-8o%-10d`\n", file[i:], 0, 0, 0, 0644, len(b))
+		bdst.WriteString(b)
+		if len(b)&1 != 0 {
+			bdst.WriteByte(0)
+		}
+	}
+	writefile(bdst.String(), dst, 0)
+}
+
+// buildorder records the order of builds for the 'go bootstrap' command.
+// The Go packages and commands must be in dependency order,
+// maintained by hand, but the order doesn't change often.
+var buildorder = []string{
+	// Go libraries and programs for bootstrap.
+	"runtime",
+	"errors",
+	"sync/atomic",
+	"sync",
+	"internal/singleflight",
+	"io",
+	"unicode",
+	"unicode/utf8",
+	"unicode/utf16",
+	"bytes",
+	"math",
+	"strings",
+	"strconv",
+	"bufio",
+	"sort",
+	"container/heap",
+	"encoding/base64",
+	"syscall",
+	"internal/syscall/windows/registry",
+	"time",
+	"internal/syscall/windows",
+	"os",
+	"reflect",
+	"fmt",
+	"encoding",
+	"encoding/binary",
+	"encoding/json",
+	"flag",
+	"path/filepath",
+	"path",
+	"io/ioutil",
+	"log",
+	"regexp/syntax",
+	"regexp",
+	"go/token",
+	"go/scanner",
+	"go/ast",
+	"go/parser",
+	"os/exec",
+	"os/signal",
+	"net/url",
+	"text/template/parse",
+	"text/template",
+	"go/doc",
+	"go/build",
+	"hash",
+	"crypto",
+	"crypto/sha1",
+	"debug/dwarf",
+	"debug/elf",
+	"cmd/go",
+}
+
+var runtimegen = []string{
+	"zaexperiment.h",
+	"zversion.go",
+}
+
+func clean() {
+	for _, name := range buildorder {
+		path := pathf("%s/src/%s", goroot, name)
+		// Remove generated files.
+		for _, elem := range xreaddir(path) {
+			for _, gt := range gentab {
+				if strings.HasPrefix(elem, gt.nameprefix) {
+					xremove(pathf("%s/%s", path, elem))
+				}
+			}
+		}
+		// Remove generated binary named for directory.
+		if strings.HasPrefix(name, "cmd/") {
+			xremove(pathf("%s/%s", path, name[4:]))
+		}
+	}
+
+	// remove runtimegen files.
+	path := pathf("%s/src/runtime", goroot)
+	for _, elem := range runtimegen {
+		xremove(pathf("%s/%s", path, elem))
+	}
+
+	if rebuildall {
+		// Remove object tree.
+		xremoveall(pathf("%s/pkg/obj/%s_%s", goroot, gohostos, gohostarch))
+
+		// Remove installed packages and tools.
+		xremoveall(pathf("%s/pkg/%s_%s", goroot, gohostos, gohostarch))
+		xremoveall(pathf("%s/pkg/%s_%s", goroot, goos, goarch))
+		xremoveall(tooldir)
+
+		// Remove cached version info.
+		xremove(pathf("%s/VERSION.cache", goroot))
+	}
+}
+
+/*
+ * command implementations
+ */
+
+func usage() {
+	xprintf("usage: go tool dist [command]\n" +
+		"Commands are:\n" +
+		"\n" +
+		"banner         print installation banner\n" +
+		"bootstrap      rebuild everything\n" +
+		"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",
+	)
+	xexit(2)
+}
+
+// The env command prints the default environment.
+func cmdenv() {
+	path := flag.Bool("p", false, "emit updated PATH")
+	plan9 := flag.Bool("9", false, "emit plan 9 syntax")
+	windows := flag.Bool("w", false, "emit windows syntax")
+	xflagparse(0)
+
+	format := "%s=\"%s\"\n"
+	switch {
+	case *plan9:
+		format = "%s='%s'\n"
+	case *windows:
+		format = "set %s=%s\r\n"
+	}
+
+	xprintf(format, "CC", defaultcc)
+	xprintf(format, "CC_FOR_TARGET", defaultcctarget)
+	xprintf(format, "GOROOT", goroot)
+	xprintf(format, "GOBIN", gobin)
+	xprintf(format, "GOARCH", goarch)
+	xprintf(format, "GOOS", goos)
+	xprintf(format, "GOHOSTARCH", gohostarch)
+	xprintf(format, "GOHOSTOS", gohostos)
+	xprintf(format, "GOTOOLDIR", tooldir)
+	if goarch == "arm" {
+		xprintf(format, "GOARM", goarm)
+	}
+	if goarch == "386" {
+		xprintf(format, "GO386", go386)
+	}
+
+	if *path {
+		sep := ":"
+		if gohostos == "windows" {
+			sep = ";"
+		}
+		xprintf(format, "PATH", fmt.Sprintf("%s%s%s", gobin, sep, os.Getenv("PATH")))
+	}
+}
+
+// The bootstrap command runs a build from scratch,
+// stopping at having installed the go_bootstrap command.
+func cmdbootstrap() {
+	flag.BoolVar(&rebuildall, "a", rebuildall, "rebuild all")
+	flag.BoolVar(&sflag, "s", sflag, "build static binaries")
+	xflagparse(0)
+
+	if isdir(pathf("%s/src/pkg", goroot)) {
+		fatal("\n\n"+
+			"The Go package sources have moved to $GOROOT/src.\n"+
+			"*** %s still exists. ***\n"+
+			"It probably contains stale files that may confuse the build.\n"+
+			"Please (check what's there and) remove it and try again.\n"+
+			"See https://golang.org/s/go14nopkg\n",
+			pathf("%s/src/pkg", goroot))
+	}
+
+	if rebuildall {
+		clean()
+	}
+
+	setup()
+
+	checkCC()
+	bootstrapBuildTools()
+
+	// For the main bootstrap, building for host os/arch.
+	oldgoos = goos
+	oldgoarch = goarch
+	goos = gohostos
+	goarch = gohostarch
+	os.Setenv("GOHOSTARCH", gohostarch)
+	os.Setenv("GOHOSTOS", gohostos)
+	os.Setenv("GOARCH", goarch)
+	os.Setenv("GOOS", goos)
+
+	// TODO(rsc): Enable when appropriate.
+	// This step is only needed if we believe that the Go compiler built from Go 1.4
+	// will produce different object files than the Go compiler built from itself.
+	// In the absence of bugs, that should not happen.
+	// And if there are bugs, they're more likely in the current development tree
+	// than in a standard release like Go 1.4, so don't do this rebuild by default.
+	if false {
+		xprintf("##### Building Go toolchain using itself.\n")
+		for _, dir := range buildorder {
+			if dir == "cmd/go" {
+				break
+			}
+			install(dir)
+		}
+		xprintf("\n")
+	}
+
+	xprintf("##### Building go_bootstrap for host, %s/%s.\n", gohostos, gohostarch)
+	for _, dir := range buildorder {
+		install(dir)
+	}
+
+	goos = oldgoos
+	goarch = oldgoarch
+	os.Setenv("GOARCH", goarch)
+	os.Setenv("GOOS", goos)
+
+	// Build runtime for actual goos/goarch too.
+	if goos != gohostos || goarch != gohostarch {
+		install("runtime")
+	}
+}
+
+// Copied from go/build/build.go.
+// Cannot use go/build directly because cmd/dist for a new release
+// builds against an old release's go/build, which may be out of sync.
+var cgoEnabled = map[string]bool{
+	"darwin/386":      true,
+	"darwin/amd64":    true,
+	"darwin/arm":      true,
+	"darwin/arm64":    true,
+	"dragonfly/amd64": true,
+	"freebsd/386":     true,
+	"freebsd/amd64":   true,
+	"linux/386":       true,
+	"linux/amd64":     true,
+	"linux/arm":       true,
+	"linux/arm64":     true,
+	"linux/ppc64le":   true,
+	"android/386":     true,
+	"android/amd64":   true,
+	"android/arm":     true,
+	"netbsd/386":      true,
+	"netbsd/amd64":    true,
+	"netbsd/arm":      true,
+	"openbsd/386":     true,
+	"openbsd/amd64":   true,
+	"solaris/amd64":   true,
+	"windows/386":     true,
+	"windows/amd64":   true,
+}
+
+func needCC() bool {
+	switch os.Getenv("CGO_ENABLED") {
+	case "1":
+		return true
+	case "0":
+		return false
+	}
+	return cgoEnabled[gohostos+"/"+gohostarch]
+}
+
+func checkCC() {
+	if !needCC() {
+		return
+	}
+	if _, err := exec.Command(defaultcc, "--help").Output(); err != nil {
+		fatal("cannot invoke C compiler %q: %v\n\n"+
+			"Go needs a system C compiler for use with cgo.\n"+
+			"To set a C compiler, export CC=the-compiler.\n"+
+			"To disable cgo, export CGO_ENABLED=0.\n", defaultcc, err)
+	}
+}
+
+func defaulttarg() string {
+	// xgetwd might return a path with symlinks fully resolved, and if
+	// there happens to be symlinks in goroot, then the hasprefix test
+	// will never succeed. Instead, we use xrealwd to get a canonical
+	// goroot/src before the comparison to avoid this problem.
+	pwd := xgetwd()
+	src := pathf("%s/src/", goroot)
+	real_src := xrealwd(src)
+	if !strings.HasPrefix(pwd, real_src) {
+		fatal("current directory %s is not under %s", pwd, real_src)
+	}
+	pwd = pwd[len(real_src):]
+	// guard againt xrealwd return the directory without the trailing /
+	pwd = strings.TrimPrefix(pwd, "/")
+
+	return pwd
+}
+
+// Install installs the list of packages named on the command line.
+func cmdinstall() {
+	flag.BoolVar(&sflag, "s", sflag, "build static binaries")
+	xflagparse(-1)
+
+	if flag.NArg() == 0 {
+		install(defaulttarg())
+	}
+
+	for _, arg := range flag.Args() {
+		install(arg)
+	}
+}
+
+// Clean deletes temporary objects.
+func cmdclean() {
+	xflagparse(0)
+	clean()
+}
+
+// Banner prints the 'now you've installed Go' banner.
+func cmdbanner() {
+	xflagparse(0)
+
+	xprintf("\n")
+	xprintf("---\n")
+	xprintf("Installed Go for %s/%s in %s\n", goos, goarch, goroot)
+	xprintf("Installed commands in %s\n", gobin)
+
+	if !xsamefile(goroot_final, goroot) {
+		// If the files are to be moved, don't check that gobin
+		// is on PATH; assume they know what they are doing.
+	} else if gohostos == "plan9" {
+		// Check that gobin is bound before /bin.
+		pid := strings.Replace(readfile("#c/pid"), " ", "", -1)
+		ns := fmt.Sprintf("/proc/%s/ns", pid)
+		if !strings.Contains(readfile(ns), fmt.Sprintf("bind -b %s /bin", gobin)) {
+			xprintf("*** You need to bind %s before /bin.\n", gobin)
+		}
+	} else {
+		// Check that gobin appears in $PATH.
+		pathsep := ":"
+		if gohostos == "windows" {
+			pathsep = ";"
+		}
+		if !strings.Contains(pathsep+os.Getenv("PATH")+pathsep, pathsep+gobin+pathsep) {
+			xprintf("*** You need to add %s to your PATH.\n", gobin)
+		}
+	}
+
+	if !xsamefile(goroot_final, goroot) {
+		xprintf("\n"+
+			"The binaries expect %s to be copied or moved to %s\n",
+			goroot, goroot_final)
+	}
+}
+
+// Version prints the Go version.
+func cmdversion() {
+	xflagparse(0)
+	xprintf("%s\n", findgoversion())
+}
diff --git a/src/cmd/dist/buildgc.c b/src/cmd/dist/buildgc.c
deleted file mode 100644
index 66adf68..0000000
--- a/src/cmd/dist/buildgc.c
+++ /dev/null
@@ -1,137 +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.
-
-#include "a.h"
-
-/*
- * Helpers for building cmd/gc.
- */
-
-// gcopnames creates opnames.h from go.h.
-// It finds the OXXX enum, pulls out all the constants
-// from OXXX to OEND, and writes a table mapping
-// op to string.
-void
-gcopnames(char *dir, char *file)
-{
-	char *p, *q;
-	int i, j, end;
-	Buf in, b, out;
-	Vec lines, fields;
-	
-	binit(&in);
-	binit(&b);
-	binit(&out);
-	vinit(&lines);
-	vinit(&fields);
-	
-	bwritestr(&out, bprintf(&b, "// auto generated by go tool dist\n"));
-	bwritestr(&out, bprintf(&b, "static char *opnames[] = {\n"));
-
-	readfile(&in, bprintf(&b, "%s/go.h", dir));
-	splitlines(&lines, bstr(&in));
-	i = 0;
-	while(i<lines.len && !contains(lines.p[i], "OXXX"))
-		i++;
-	end = 0;
-	for(; i<lines.len && !end; i++) {
-		p = xstrstr(lines.p[i], "//");
-		if(p != nil)
-			*p = '\0';
-		end = contains(lines.p[i], "OEND");
-		splitfields(&fields, lines.p[i]);
-		for(j=0; j<fields.len; j++) {
-			q = fields.p[j];
-			if(*q == 'O')
-				q++;
-			p = q+xstrlen(q)-1;
-			if(*p == ',')
-				*p = '\0';
-			bwritestr(&out, bprintf(&b, "	[O%s] = \"%s\",\n", q, q));
-		}
-	}
-	
-	bwritestr(&out, bprintf(&b, "};\n"));
-
-	writefile(&out, file, 0);
-
-	bfree(&in);
-	bfree(&b);
-	bfree(&out);
-	vfree(&lines);
-	vfree(&fields);
-}
-
-// mkanames reads [568].out.h and writes anames[568].c
-// The format is much the same as the Go opcodes above.
-// it also writes out cnames array for C_* constants.
-void
-mkanames(char *dir, char *file)
-{
-	int i, j, ch;
-	Buf in, b, out, out2;
-	Vec lines;
-	char *p;
-
-	binit(&b);
-	binit(&in);
-	binit(&out);
-	binit(&out2);
-	vinit(&lines);
-
-	ch = file[xstrlen(file)-3];
-	bprintf(&b, "%s/../cmd/%cl/%c.out.h", dir, ch, ch);
-	readfile(&in, bstr(&b));
-	splitlines(&lines, bstr(&in));
-	
-	// Include link.h so that the extern declaration there is
-	// checked against the non-extern declaration we are generating.
-	bwritestr(&out, bprintf(&b, "#include <u.h>\n"));
-	bwritestr(&out, bprintf(&b, "#include <libc.h>\n"));
-	bwritestr(&out, bprintf(&b, "#include <bio.h>\n"));
-	bwritestr(&out, bprintf(&b, "#include <link.h>\n"));
-	bwritestr(&out, bprintf(&b, "\n"));
-
-	bwritestr(&out, bprintf(&b, "char*	anames%c[] = {\n", ch));
-	for(i=0; i<lines.len; i++) {
-		if(hasprefix(lines.p[i], "\tA")) {
-			p = xstrstr(lines.p[i], ",");
-			if(p)
-				*p = '\0';
-			p = xstrstr(lines.p[i], "\n");
-			if(p)
-				*p = '\0';
-			p = lines.p[i] + 2;
-			bwritestr(&out, bprintf(&b, "\t\"%s\",\n", p));
-		}
-	}
-	bwritestr(&out, "};\n");
-
-	j=0;
-	bprintf(&out2, "char*	cnames%c[] = {\n", ch);
-	for(i=0; i<lines.len; i++) {
-		if(hasprefix(lines.p[i], "\tC_")) {
-			p = xstrstr(lines.p[i], ",");
-			if(p)
-				*p = '\0';
-			p = xstrstr(lines.p[i], "\n");
-			if(p)
-				*p = '\0';
-			p = lines.p[i] + 3;
-			bwritestr(&out2, bprintf(&b, "\t\"%s\",\n", p));
-			j++;
-		}
-	}
-	bwritestr(&out2, "};\n");
-	if(j>0)
-		bwriteb(&out, &out2);
-
-	writefile(&out, file, 0);
-
-	bfree(&b);
-	bfree(&in);
-	bfree(&out);
-	bfree(&out2);
-	vfree(&lines);
-}
diff --git a/src/cmd/dist/buildgo.c b/src/cmd/dist/buildgo.c
deleted file mode 100644
index 41208fa..0000000
--- a/src/cmd/dist/buildgo.c
+++ /dev/null
@@ -1,49 +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.
-
-#include "a.h"
-
-/*
- * Helpers for building cmd/go and cmd/cgo.
- */
-
-// mkzdefaultcc writes zdefaultcc.go:
-//
-//	package main
-//	const defaultCC = <defaultcc>
-//	const defaultCXX = <defaultcxx>
-//
-// It is invoked to write cmd/go/zdefaultcc.go
-// but we also write cmd/cgo/zdefaultcc.go.
-void
-mkzdefaultcc(char *dir, char *file)
-{
-	Buf b, out;
-	
-	USED(dir);
-
-	binit(&out);
-	bprintf(&out,
-		"// auto generated by go tool dist\n"
-		"\n"
-		"package main\n"
-		"\n"
-		"const defaultCC = `%s`\n"
-		"const defaultCXX = `%s`\n",
-		defaultcctarget, defaultcxxtarget);
-
-	writefile(&out, file, 0);
-
-	// Convert file name to replace.
-	binit(&b);	
-	bwritestr(&b, file);
-	if(slash[0] == '/')
-		bsubst(&b, "/go/zdefaultcc.go", "/cgo/zdefaultcc.go");
-	else
-		bsubst(&b, "\\go\\zdefaultcc.go", "\\cgo\\zdefaultcc.go");
-	writefile(&out, bstr(&b), 0);
-
-	bfree(&b);
-	bfree(&out);
-}
diff --git a/src/cmd/dist/buildgo.go b/src/cmd/dist/buildgo.go
new file mode 100644
index 0000000..437e9dd
--- /dev/null
+++ b/src/cmd/dist/buildgo.go
@@ -0,0 +1,39 @@
+// 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.
+
+package main
+
+import "fmt"
+
+/*
+ * Helpers for building cmd/go and cmd/cgo.
+ */
+
+// mkzdefaultcc writes zdefaultcc.go:
+//
+//	package main
+//	const defaultCC = <defaultcc>
+//	const defaultCXX = <defaultcxx>
+//
+// It is invoked to write cmd/go/zdefaultcc.go
+// but we also write cmd/cgo/zdefaultcc.go
+func mkzdefaultcc(dir, file string) {
+	var out string
+
+	out = fmt.Sprintf(
+		"// auto generated by go tool dist\n"+
+			"\n"+
+			"package main\n"+
+			"\n"+
+			"const defaultCC = `%s`\n"+
+			"const defaultCXX = `%s`\n",
+		defaultcctarget, defaultcxxtarget)
+
+	writefile(out, file, writeSkipSame)
+
+	// Convert file name to replace: turn go into cgo.
+	i := len(file) - len("go/zdefaultcc.go")
+	file = file[:i] + "c" + file[i:]
+	writefile(out, file, writeSkipSame)
+}
diff --git a/src/cmd/dist/buildruntime.c b/src/cmd/dist/buildruntime.c
deleted file mode 100644
index bb774e0..0000000
--- a/src/cmd/dist/buildruntime.c
+++ /dev/null
@@ -1,468 +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.
-
-#include "a.h"
-
-/*
- * Helpers for building runtime.
- */
-
-// mkzversion writes zversion.go:
-//
-//	package runtime
-//	const defaultGoroot = <goroot>
-//	const theVersion = <version>
-//
-void
-mkzversion(char *dir, char *file)
-{
-	Buf b, out;
-	
-	USED(dir);
-
-	binit(&b);
-	binit(&out);
-	
-	bwritestr(&out, bprintf(&b,
-		"// auto generated by go tool dist\n"
-		"\n"
-		"package runtime\n"
-		"\n"
-		"const defaultGoroot = `%s`\n"
-		"const theVersion = `%s`\n"
-		"var buildVersion = theVersion\n", goroot_final, goversion));
-
-	writefile(&out, file, 0);
-	
-	bfree(&b);
-	bfree(&out);
-}
-
-// mkzexperiment writes zaexperiment.h (sic):
-//
-//	#define GOEXPERIMENT "experiment string"
-//
-void
-mkzexperiment(char *dir, char *file)
-{
-	Buf b, out, exp;
-	
-	USED(dir);
-
-	binit(&b);
-	binit(&out);
-	binit(&exp);
-	
-	xgetenv(&exp, "GOEXPERIMENT");
-	bwritestr(&out, bprintf(&b,
-		"// auto generated by go tool dist\n"
-		"\n"
-		"#define GOEXPERIMENT \"%s\"\n", bstr(&exp)));
-
-	writefile(&out, file, 0);
-	
-	bfree(&b);
-	bfree(&out);
-	bfree(&exp);
-}
-
-// mkzgoarch writes zgoarch_$GOARCH.go:
-//
-//	package runtime
-//	const theGoarch = <goarch>
-//
-void
-mkzgoarch(char *dir, char *file)
-{
-	Buf b, out;
-
-	USED(dir);
-	
-	binit(&b);
-	binit(&out);
-	
-	bwritestr(&out, bprintf(&b,
-		"// auto generated by go tool dist\n"
-		"\n"
-		"package runtime\n"
-		"\n"
-		"const theGoarch = `%s`\n", goarch));
-
-	writefile(&out, file, 0);
-	
-	bfree(&b);
-	bfree(&out);
-}
-
-// mkzgoos writes zgoos_$GOOS.go:
-//
-//	package runtime
-//	const theGoos = <goos>
-//
-void
-mkzgoos(char *dir, char *file)
-{
-	Buf b, out;
-
-	USED(dir);
-	
-	binit(&b);
-	binit(&out);
-
-	bwritestr(&out, "// auto generated by go tool dist\n\n");
-
-	if(streq(goos, "linux")) {
-		bwritestr(&out, "// +build !android\n\n");
-	}
-	
-	bwritestr(&out, bprintf(&b,
-		"package runtime\n"
-		"\n"
-		"const theGoos = `%s`\n", goos));
-
-	writefile(&out, file, 0);
-	
-	bfree(&b);
-	bfree(&out);
-}
-
-static struct {
-	char *goarch;
-	char *goos;
-	char *hdr;
-} zasmhdr[] = {
-	{"386", "",
-		"#define	get_tls(r)	MOVL TLS, r\n"
-		"#define	g(r)	0(r)(TLS*1)\n"
-	},
-	{"amd64p32", "",
-		"#define	get_tls(r)	MOVL TLS, r\n"
-		"#define	g(r)	0(r)(TLS*1)\n"
-	},
-	{"amd64", "",
-		"#define	get_tls(r)	MOVQ TLS, r\n"
-		"#define	g(r)	0(r)(TLS*1)\n"
-	},	
-
-	{"arm", "",
-	"#define	LR	R14\n"
-	},
-};
-
-#define MAXWINCB 2000 /* maximum number of windows callbacks allowed */
-
-// mkzasm writes zasm_$GOOS_$GOARCH.h,
-// which contains struct offsets for use by
-// assembly files.  It also writes a copy to the work space
-// under the name zasm_GOOS_GOARCH.h (no expansion).
-// 
-void
-mkzasm(char *dir, char *file)
-{
-	int i, n;
-	char *aggr, *p;
-	Buf in, b, b1, out, exp;
-	Vec argv, lines, fields;
-
-	binit(&in);
-	binit(&b);
-	binit(&b1);
-	binit(&out);
-	binit(&exp);
-	vinit(&argv);
-	vinit(&lines);
-	vinit(&fields);
-	
-	bwritestr(&out, "// auto generated by go tool dist\n\n");
-	if(streq(goos, "linux")) {
-		bwritestr(&out, "// +build !android\n\n");
-	}
-	
-	for(i=0; i<nelem(zasmhdr); i++) {
-		if(hasprefix(goarch, zasmhdr[i].goarch) && hasprefix(goos, zasmhdr[i].goos)) {
-			bwritestr(&out, zasmhdr[i].hdr);
-			goto ok;
-		}
-	}
-	fatal("unknown $GOOS/$GOARCH in mkzasm");
-ok:
-
-	copyfile(bpathf(&b, "%s/pkg/%s_%s/textflag.h", goroot, goos, goarch),
-		bpathf(&b1, "%s/src/cmd/ld/textflag.h", goroot), 0);
-
-	// Run 6c -D GOOS_goos -D GOARCH_goarch -I workdir -a -n -o workdir/proc.acid proc.c
-	// to get acid [sic] output. Run once without the -a -o workdir/proc.acid in order to
-	// report compilation failures (the -o redirects all messages, unfortunately).
-	vreset(&argv);
-	vadd(&argv, bpathf(&b, "%s/%sc", tooldir, gochar));
-	vadd(&argv, "-D");
-	vadd(&argv, bprintf(&b, "GOOS_%s", goos));
-	vadd(&argv, "-D");
-	vadd(&argv, bprintf(&b, "GOARCH_%s", goarch));
-	vadd(&argv, "-I");
-	vadd(&argv, bprintf(&b, "%s", workdir));
-	vadd(&argv, "-I");
-	vadd(&argv, bprintf(&b, "%s/pkg/%s_%s", goroot, goos, goarch));
-	vadd(&argv, "-n");
-	vadd(&argv, "-a");
-	vadd(&argv, "-o");
-	vadd(&argv, bpathf(&b, "%s/proc.acid", workdir));
-	vadd(&argv, "proc.c");
-	runv(nil, dir, CheckExit, &argv);
-	readfile(&in, bpathf(&b, "%s/proc.acid", workdir));
-	
-	// Convert input like
-	//	aggr G
-	//	{
-	//		Gobuf 24 sched;
-	//		'Y' 48 stack0;
-	//	}
-	//	StackMin = 128;
-	// into output like
-	//	#define g_sched 24
-	//	#define g_stack0 48
-	//	#define const_StackMin 128
-	aggr = nil;
-	splitlines(&lines, bstr(&in));
-	for(i=0; i<lines.len; i++) {
-		splitfields(&fields, lines.p[i]);
-		if(fields.len == 2 && streq(fields.p[0], "aggr")) {
-			if(streq(fields.p[1], "G"))
-				aggr = "g";
-			else if(streq(fields.p[1], "M"))
-				aggr = "m";
-			else if(streq(fields.p[1], "P"))
-				aggr = "p";
-			else if(streq(fields.p[1], "Gobuf"))
-				aggr = "gobuf";
-			else if(streq(fields.p[1], "LibCall"))
-				aggr = "libcall";
-			else if(streq(fields.p[1], "WinCallbackContext"))
-				aggr = "cbctxt";
-			else if(streq(fields.p[1], "SEH"))
-				aggr = "seh";
-			else if(streq(fields.p[1], "Alg"))
-				aggr = "alg";
-			else if(streq(fields.p[1], "Panic"))
-				aggr = "panic";
-			else if(streq(fields.p[1], "Stack"))
-				aggr = "stack";
-		}
-		if(hasprefix(lines.p[i], "}"))
-			aggr = nil;
-		if(aggr && hasprefix(lines.p[i], "\t") && fields.len >= 2) {
-			n = fields.len;
-			p = fields.p[n-1];
-			if(p[xstrlen(p)-1] == ';')
-				p[xstrlen(p)-1] = '\0';
-			bwritestr(&out, bprintf(&b, "#define %s_%s %s\n", aggr, fields.p[n-1], fields.p[n-2]));
-		}
-		if(fields.len == 3 && streq(fields.p[1], "=")) { // generated from enumerated constants
-			p = fields.p[2];
-			if(p[xstrlen(p)-1] == ';')
-				p[xstrlen(p)-1] = '\0';
-			bwritestr(&out, bprintf(&b, "#define const_%s %s\n", fields.p[0], p));
-		}
-	}
-
-	// Some #defines that are used for .c files.
-	if(streq(goos, "windows")) {
-		bwritestr(&out, bprintf(&b, "#define cb_max %d\n", MAXWINCB));
-	}
-	
-	xgetenv(&exp, "GOEXPERIMENT");
-	bwritestr(&out, bprintf(&b, "#define GOEXPERIMENT \"%s\"\n", bstr(&exp)));
-	
-	// Write both to file and to workdir/zasm_GOOS_GOARCH.h.
-	writefile(&out, file, 0);
-	writefile(&out, bprintf(&b, "%s/zasm_GOOS_GOARCH.h", workdir), 0);
-
-	bfree(&in);
-	bfree(&b);
-	bfree(&b1);
-	bfree(&out);
-	bfree(&exp);
-	vfree(&argv);
-	vfree(&lines);
-	vfree(&fields);
-}
-
-// mkzsys writes zsys_$GOOS_$GOARCH.s,
-// which contains arch or os specific asm code.
-// 
-void
-mkzsys(char *dir, char *file)
-{
-	int i;
-	Buf out;
-
-	USED(dir);
-	
-	binit(&out);
-	
-	bwritestr(&out, "// auto generated by go tool dist\n\n");
-	if(streq(goos, "linux")) {
-		bwritestr(&out, "// +build !android\n\n");
-	}
-	
-	if(streq(goos, "windows")) {
-		bwritef(&out,
-			"// runtime·callbackasm is called by external code to\n"
-			"// execute Go implemented callback function. It is not\n"
-			"// called from the start, instead runtime·compilecallback\n"
-			"// always returns address into runtime·callbackasm offset\n"
-			"// appropriately so different callbacks start with different\n"
-			"// CALL instruction in runtime·callbackasm. This determines\n"
-			"// which Go callback function is executed later on.\n"
-			"TEXT runtime·callbackasm(SB),7,$0\n");
-		for(i=0; i<MAXWINCB; i++) {
-			bwritef(&out, "\tCALL\truntime·callbackasm1(SB)\n");
-		}
-		bwritef(&out, "\tRET\n");
-	}
-
-	writefile(&out, file, 0);
-	
-	bfree(&out);
-}
-
-static char *runtimedefs[] = {
-	"defs.c",
-	"malloc.c",
-	"mcache.c",
-	"mgc0.c",
-	"proc.c",
-	"parfor.c",
-	"stack.c",
-};
-
-// mkzruntimedefs writes zruntime_defs_$GOOS_$GOARCH.h,
-// which contains Go struct definitions equivalent to the C ones.
-// Mostly we just write the output of 6c -q to the file.
-// However, we run it on multiple files, so we have to delete
-// the duplicated definitions, and we don't care about the funcs,
-// so we delete those too.
-// 
-void
-mkzruntimedefs(char *dir, char *file)
-{
-	int i, skip;
-	char *p;
-	Buf in, b, b1, out;
-	Vec argv, lines, fields, seen;
-	
-	binit(&in);
-	binit(&b);
-	binit(&b1);
-	binit(&out);
-	vinit(&argv);
-	vinit(&lines);
-	vinit(&fields);
-	vinit(&seen);
-	
-	bwritestr(&out, "// auto generated by go tool dist\n"
-		"\n");
-
-	if(streq(goos, "linux")) {
-		bwritestr(&out, "// +build !android\n\n");
-	}
-	
-	bwritestr(&out,
-		"package runtime\n"
-		"import \"unsafe\"\n"
-		"var _ unsafe.Pointer\n"
-		"\n"
-	);
-
-	// Do not emit definitions for these.
-	vadd(&seen, "true");
-	vadd(&seen, "false");
-	vadd(&seen, "raceenabled");
-	vadd(&seen, "allgs");
-	
-	// Run 6c -D GOOS_goos -D GOARCH_goarch -I workdir -q -n -o workdir/runtimedefs
-	// on each of the runtimedefs C files.
-	vadd(&argv, bpathf(&b, "%s/%sc", tooldir, gochar));
-	vadd(&argv, "-D");
-	vadd(&argv, bprintf(&b, "GOOS_%s", goos));
-	vadd(&argv, "-D");
-	vadd(&argv, bprintf(&b, "GOARCH_%s", goarch));
-	vadd(&argv, "-I");
-	vadd(&argv, bprintf(&b, "%s", workdir));
-	vadd(&argv, "-I");
-	vadd(&argv, bprintf(&b, "%s/pkg/%s_%s", goroot, goos, goarch));
-	vadd(&argv, "-q");
-	vadd(&argv, "-n");
-	vadd(&argv, "-o");
-	vadd(&argv, bpathf(&b, "%s/runtimedefs", workdir));
-	vadd(&argv, "");
-	p = argv.p[argv.len-1];
-	for(i=0; i<nelem(runtimedefs); i++) {
-		argv.p[argv.len-1] = runtimedefs[i];
-		runv(nil, dir, CheckExit, &argv);
-		readfile(&b, bpathf(&b1, "%s/runtimedefs", workdir));
-		bwriteb(&in, &b);
-	}
-	argv.p[argv.len-1] = p;
-		
-	// Process the aggregate output.
-	skip = 0;
-	splitlines(&lines, bstr(&in));
-	for(i=0; i<lines.len; i++) {
-		p = lines.p[i];
-		// Drop comment and func lines.
-		if(hasprefix(p, "//") || hasprefix(p, "func"))
-			continue;
-		
-		// Note beginning of type or var decl, which can be multiline.
-		// Remove duplicates.  The linear check of seen here makes the
-		// whole processing quadratic in aggregate, but there are only
-		// about 100 declarations, so this is okay (and simple).
-		if(hasprefix(p, "type ") || hasprefix(p, "var ") || hasprefix(p, "const ")) {
-			splitfields(&fields, p);
-			if(fields.len < 2)
-				continue;
-			if(find(fields.p[1], seen.p, seen.len) >= 0) {
-				if(streq(fields.p[fields.len-1], "{"))
-					skip = 1;  // skip until }
-				continue;
-			}
-			vadd(&seen, fields.p[1]);
-		}
-
-		// Const lines are printed in original case (usually upper). Add a leading _ as needed.
-		if(hasprefix(p, "const ")) {
-			if('A' <= p[6] && p[6] <= 'Z')
-				bwritestr(&out, "const _");
-			else
-				bwritestr(&out, "const ");
-			bwritestr(&out, p+6);
-			continue;
-		}
-
-		if(skip) {
-			if(hasprefix(p, "}"))
-				skip = 0;
-			continue;
-		}
-		
-		bwritestr(&out, p);
-	}
-
-	// Some windows specific const.
-	if(streq(goos, "windows")) {
-		bwritestr(&out, bprintf(&b, "const cb_max = %d\n", MAXWINCB));
-	}
-	
-	writefile(&out, file, 0);
-
-	bfree(&in);
-	bfree(&b);
-	bfree(&b1);
-	bfree(&out);
-	vfree(&argv);
-	vfree(&lines);
-	vfree(&fields);
-	vfree(&seen);
-}
diff --git a/src/cmd/dist/buildruntime.go b/src/cmd/dist/buildruntime.go
new file mode 100644
index 0000000..4e9bede
--- /dev/null
+++ b/src/cmd/dist/buildruntime.go
@@ -0,0 +1,96 @@
+// 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.
+
+package main
+
+import (
+	"fmt"
+	"os"
+	"strings"
+)
+
+/*
+ * Helpers for building runtime.
+ */
+
+// mkzversion writes zversion.go:
+//
+//	package runtime
+//	const defaultGoroot = <goroot>
+//	const theVersion = <version>
+//	const goexperiment = <goexperiment>
+//	const stackGuardMultiplier = <multiplier value>
+//	const buildVersion = <build version>
+//
+func mkzversion(dir, file string) {
+	out := fmt.Sprintf(
+		"// auto generated by go tool dist\n"+
+			"\n"+
+			"package runtime\n"+
+			"\n"+
+			"const defaultGoroot = `%s`\n"+
+			"const theVersion = `%s`\n"+
+			"const goexperiment = `%s`\n"+
+			"const stackGuardMultiplier = %d\n"+
+			"var buildVersion = theVersion\n", goroot_final, findgoversion(), os.Getenv("GOEXPERIMENT"), stackGuardMultiplier())
+
+	writefile(out, file, writeSkipSame)
+}
+
+// mkzbootstrap writes cmd/internal/obj/zbootstrap.go:
+//
+//	package obj
+//
+//	const defaultGOROOT = <goroot>
+//	const defaultGO386 = <go386>
+//	const defaultGOARM = <goarm>
+//	const defaultGOOS = runtime.GOOS
+//	const defaultGOARCH = runtime.GOARCH
+//	const defaultGO_EXTLINK_ENABLED = <goextlinkenabled>
+//	const version = <version>
+//	const stackGuardMultiplier = <multiplier value>
+//	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/compile
+//
+// 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 = runtime.GOOS\n"+
+			"const defaultGOARCH = runtime.GOARCH\n"+
+			"const defaultGO_EXTLINK_ENABLED = `%s`\n"+
+			"const version = `%s`\n"+
+			"const stackGuardMultiplier = %d\n"+
+			"const goexperiment = `%s`\n",
+		goroot_final, go386, goarm, goextlinkenabled, findgoversion(), stackGuardMultiplier(), os.Getenv("GOEXPERIMENT"))
+
+	writefile(out, file, writeSkipSame)
+}
+
+// stackGuardMultiplier returns a multiplier to apply to the default
+// stack guard size.  Larger multipliers are used for non-optimized
+// builds that have larger stack frames.
+func stackGuardMultiplier() int {
+	for _, s := range strings.Split(os.Getenv("GO_GCFLAGS"), " ") {
+		if s == "-N" {
+			return 2
+		}
+	}
+	return 1
+}
diff --git a/src/cmd/dist/buildtool.go b/src/cmd/dist/buildtool.go
new file mode 100644
index 0000000..8a55b5d
--- /dev/null
+++ b/src/cmd/dist/buildtool.go
@@ -0,0 +1,144 @@
+// 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 toolchain using Go 1.4.
+//
+// The general strategy is to copy the source files we need into
+// a new GOPATH workspace, adjust import paths appropriately,
+// invoke the Go 1.4 go command to build those sources,
+// and then copy the binaries back.
+
+package main
+
+import (
+	"os"
+	"strings"
+)
+
+// bootstrapDirs is a list of directories holding code that must be
+// compiled with a Go 1.4 toolchain to produce the bootstrapTargets.
+// All directories in this list are relative to and must be below $GOROOT/src/cmd.
+// The list is assumed to have two kinds of entries: names without slashes,
+// which are commands, and entries beginning with internal/, which are
+// packages supporting the commands.
+var bootstrapDirs = []string{
+	"asm",
+	"asm/internal/arch",
+	"asm/internal/asm",
+	"asm/internal/flags",
+	"asm/internal/lex",
+	"compile",
+	"compile/internal/amd64",
+	"compile/internal/arm",
+	"compile/internal/arm64",
+	"compile/internal/big",
+	"compile/internal/gc",
+	"compile/internal/ppc64",
+	"compile/internal/x86",
+	"internal/gcprog",
+	"internal/obj",
+	"internal/obj/arm",
+	"internal/obj/arm64",
+	"internal/obj/ppc64",
+	"internal/obj/x86",
+	"link",
+	"link/internal/amd64",
+	"link/internal/arm",
+	"link/internal/arm64",
+	"link/internal/ld",
+	"link/internal/ppc64",
+	"link/internal/x86",
+}
+
+func bootstrapBuildTools() {
+	goroot_bootstrap := os.Getenv("GOROOT_BOOTSTRAP")
+	if goroot_bootstrap == "" {
+		goroot_bootstrap = pathf("%s/go1.4", os.Getenv("HOME"))
+	}
+	xprintf("##### Building Go toolchain using %s.\n", goroot_bootstrap)
+
+	mkzbootstrap(pathf("%s/src/cmd/internal/obj/zbootstrap.go", goroot))
+
+	// Use $GOROOT/pkg/bootstrap as the bootstrap workspace root.
+	// We use a subdirectory of $GOROOT/pkg because that's the
+	// space within $GOROOT where we store all generated objects.
+	// We could use a temporary directory outside $GOROOT instead,
+	// but it is easier to debug on failure if the files are in a known location.
+	workspace := pathf("%s/pkg/bootstrap", goroot)
+	xremoveall(workspace)
+	base := pathf("%s/src/bootstrap", workspace)
+	xmkdirall(base)
+
+	// Copy source code into $GOROOT/pkg/bootstrap and rewrite import paths.
+	for _, dir := range bootstrapDirs {
+		src := pathf("%s/src/cmd/%s", goroot, dir)
+		dst := pathf("%s/%s", base, dir)
+		xmkdirall(dst)
+		for _, name := range xreaddirfiles(src) {
+			srcFile := pathf("%s/%s", src, name)
+			text := readfile(srcFile)
+			text = bootstrapFixImports(text, srcFile)
+			writefile(text, pathf("%s/%s", dst, name), 0)
+		}
+	}
+
+	// Set up environment for invoking Go 1.4 go command.
+	// GOROOT points at Go 1.4 GOROOT,
+	// GOPATH points at our bootstrap workspace,
+	// GOBIN is empty, so that binaries are installed to GOPATH/bin,
+	// and GOOS, GOHOSTOS, GOARCH, and GOHOSTOS are empty,
+	// so that Go 1.4 builds whatever kind of binary it knows how to build.
+	// Restore GOROOT, GOPATH, and GOBIN when done.
+	// Don't bother with GOOS, GOHOSTOS, GOARCH, and GOHOSTARCH,
+	// because setup will take care of those when bootstrapBuildTools returns.
+
+	defer os.Setenv("GOROOT", os.Getenv("GOROOT"))
+	os.Setenv("GOROOT", goroot_bootstrap)
+
+	defer os.Setenv("GOPATH", os.Getenv("GOPATH"))
+	os.Setenv("GOPATH", workspace)
+
+	defer os.Setenv("GOBIN", os.Getenv("GOBIN"))
+	os.Setenv("GOBIN", "")
+
+	os.Setenv("GOOS", "")
+	os.Setenv("GOHOSTOS", "")
+	os.Setenv("GOARCH", "")
+	os.Setenv("GOHOSTARCH", "")
+
+	// Run Go 1.4 to build binaries.
+	run(workspace, ShowOutput|CheckExit, pathf("%s/bin/go", goroot_bootstrap), "install", "-v", "bootstrap/...")
+
+	// Copy binaries into tool binary directory.
+	for _, name := range bootstrapDirs {
+		if !strings.Contains(name, "/") {
+			copyfile(pathf("%s/%s%s", tooldir, name, exe), pathf("%s/bin/%s%s", workspace, name, exe), writeExec)
+		}
+	}
+
+	xprintf("\n")
+}
+
+func bootstrapFixImports(text, srcFile string) string {
+	lines := strings.SplitAfter(text, "\n")
+	inBlock := false
+	for i, line := range lines {
+		if strings.HasPrefix(line, "import (") {
+			inBlock = true
+			continue
+		}
+		if inBlock && strings.HasPrefix(line, ")") {
+			inBlock = false
+			continue
+		}
+		if strings.HasPrefix(line, `import "`) || strings.HasPrefix(line, `import . "`) ||
+			inBlock && (strings.HasPrefix(line, "\t\"") || strings.HasPrefix(line, "\t. \"")) {
+			lines[i] = strings.Replace(line, `"cmd/`, `"bootstrap/`, -1)
+		}
+	}
+
+	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/cpuid_386.s b/src/cmd/dist/cpuid_386.s
new file mode 100644
index 0000000..ed4fb52
--- /dev/null
+++ b/src/cmd/dist/cpuid_386.s
@@ -0,0 +1,16 @@
+// 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 !gccgo
+
+TEXT ·cpuid(SB),$0-8
+	MOVL ax+4(FP), AX
+	CPUID
+	MOVL info+0(FP), DI
+	MOVL AX, 0(DI)
+	MOVL BX, 4(DI)
+	MOVL CX, 8(DI)
+	MOVL DX, 12(DI)
+	RET
+
diff --git a/src/cmd/dist/cpuid_amd64.s b/src/cmd/dist/cpuid_amd64.s
new file mode 100644
index 0000000..b6cdfed
--- /dev/null
+++ b/src/cmd/dist/cpuid_amd64.s
@@ -0,0 +1,16 @@
+// 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 !gccgo
+
+TEXT ·cpuid(SB),$0-12
+	MOVL ax+8(FP), AX
+	CPUID
+	MOVQ info+0(FP), DI
+	MOVL AX, 0(DI)
+	MOVL BX, 4(DI)
+	MOVL CX, 8(DI)
+	MOVL DX, 12(DI)
+	RET
+
diff --git a/src/cmd/dist/cpuid_default.s b/src/cmd/dist/cpuid_default.s
new file mode 100644
index 0000000..165b4a9
--- /dev/null
+++ b/src/cmd/dist/cpuid_default.s
@@ -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 !386,!amd64,!gccgo
+
+#include "textflag.h"
+
+TEXT ·cpuid(SB),NOSPLIT,$0-0
+	RET
diff --git a/src/cmd/dist/main.c b/src/cmd/dist/main.c
deleted file mode 100644
index fad0180..0000000
--- a/src/cmd/dist/main.c
+++ /dev/null
@@ -1,42 +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.
-
-#include "a.h"
-
-int vflag;
-int sflag;
-char *argv0;
-
-// cmdtab records the available commands.
-static struct {
-	char *name;
-	void (*f)(int, char**);
-} cmdtab[] = {
-	{"banner", cmdbanner},
-	{"bootstrap", cmdbootstrap},
-	{"clean", cmdclean},
-	{"env", cmdenv},
-	{"install", cmdinstall},
-	{"version", cmdversion},
-};
-
-// The OS-specific main calls into the portable code here.
-void
-xmain(int argc, char **argv)
-{
-	int i;
-
-	if(argc <= 1)
-		usage();
-	
-	for(i=0; i<nelem(cmdtab); i++) {
-		if(streq(cmdtab[i].name, argv[1])) {
-			cmdtab[i].f(argc-1, argv+1);
-			return;
-		}
-	}
-
-	xprintf("unknown command %s\n", argv[1]);
-	usage();
-}
diff --git a/src/cmd/dist/main.go b/src/cmd/dist/main.go
new file mode 100644
index 0000000..1f19a7c
--- /dev/null
+++ b/src/cmd/dist/main.go
@@ -0,0 +1,86 @@
+// 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.
+
+package main
+
+import (
+	"flag"
+	"fmt"
+	"os"
+	"strconv"
+)
+
+// cmdtab records the available commands.
+var cmdtab = []struct {
+	name string
+	f    func()
+}{
+	{"banner", cmdbanner},
+	{"bootstrap", cmdbootstrap},
+	{"clean", cmdclean},
+	{"env", cmdenv},
+	{"install", cmdinstall},
+	{"test", cmdtest},
+	{"version", cmdversion},
+}
+
+// The OS-specific main calls into the portable code here.
+func xmain() {
+	if len(os.Args) < 2 {
+		usage()
+	}
+	cmd := os.Args[1]
+	os.Args = os.Args[1:] // for flag parsing during cmd
+	for _, ct := range cmdtab {
+		if ct.name == cmd {
+			flag.Usage = func() {
+				fmt.Fprintf(os.Stderr, "usage: go tool dist %s [options]\n", cmd)
+				flag.PrintDefaults()
+				os.Exit(2)
+			}
+			ct.f()
+			return
+		}
+	}
+
+	xprintf("unknown command %s\n", cmd)
+	usage()
+}
+
+func xflagparse(maxargs int) {
+	flag.Var((*count)(&vflag), "v", "verbosity")
+	flag.Parse()
+	if maxargs >= 0 && flag.NArg() > maxargs {
+		flag.Usage()
+	}
+}
+
+// count is a flag.Value that is like a flag.Bool and a flag.Int.
+// If used as -name, it increments the count, but -name=x sets the count.
+// Used for verbose flag -v.
+type count int
+
+func (c *count) String() string {
+	return fmt.Sprint(int(*c))
+}
+
+func (c *count) Set(s string) error {
+	switch s {
+	case "true":
+		*c++
+	case "false":
+		*c = 0
+	default:
+		n, err := strconv.Atoi(s)
+		if err != nil {
+			return fmt.Errorf("invalid count %q", s)
+		}
+		*c = count(n)
+	}
+	return nil
+}
+
+func (c *count) IsBoolFlag() bool {
+	return true
+}
diff --git a/src/cmd/dist/plan9.c b/src/cmd/dist/plan9.c
deleted file mode 100644
index e4bf251..0000000
--- a/src/cmd/dist/plan9.c
+++ /dev/null
@@ -1,764 +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.
-
-// These #ifdefs are being used as a substitute for
-// build configuration, so that on any system, this
-// tool can be built with the local equivalent of
-//	cc *.c
-//
-#ifdef PLAN9
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#undef nil
-#undef nelem
-#include "a.h"
-
-// bprintf replaces the buffer with the result of the printf formatting
-// and returns a pointer to the NUL-terminated buffer contents.
-char*
-bprintf(Buf *b, char *fmt, ...)
-{
-	va_list arg;
-	char buf[4096];
-
-	breset(b);
-	va_start(arg, fmt);
-	vsnprintf(buf, sizeof buf, fmt, arg);
-	va_end(arg);
-	bwritestr(b, buf);
-	return bstr(b);
-}
-
-// bpathf is the same as bprintf (on windows it turns / into \ after the printf).
-// It returns a pointer to the NUL-terminated buffer contents.
-char*
-bpathf(Buf *b, char *fmt, ...)
-{
-	va_list arg;
-	char buf[4096];
-	
-	breset(b);
-	va_start(arg, fmt);
-	vsnprintf(buf, sizeof buf, fmt, arg);
-	va_end(arg);
-	bwritestr(b, buf);
-	return bstr(b);
-}
-
-// bwritef is like bprintf but does not reset the buffer
-// and does not return the NUL-terminated string.
-void
-bwritef(Buf *b, char *fmt, ...)
-{
-	va_list arg;
-	char buf[4096];
-	
-	va_start(arg, fmt);
-	vsnprintf(buf, sizeof buf, fmt, arg);
-	va_end(arg);
-	bwritestr(b, buf);
-}
-
-// breadfrom appends to b all the data that can be read from fd.
-static void
-breadfrom(Buf *b, int fd)
-{
-	int n;
-
-	for(;;) {
-		bgrow(b, 4096);
-		n = read(fd, b->p+b->len, 4096);
-		if(n < 0)
-			fatal("read");
-		if(n == 0)
-			break;
-		b->len += n;
-	}
-}
-
-// xgetenv replaces b with the value of the named environment variable.
-void
-xgetenv(Buf *b, char *name)
-{
-	char *p;
-	
-	breset(b);
-	p = getenv(name);
-	if(p != nil)
-		bwritestr(b, p);
-}
-
-static void genrun(Buf *b, char *dir, int mode, Vec *argv, int bg);
-
-// run runs the command named by cmd.
-// If b is not nil, run replaces b with the output of the command.
-// If dir is not nil, run runs the command in that directory.
-// If mode is CheckExit, run calls fatal if the command is not successful.
-void
-run(Buf *b, char *dir, int mode, char *cmd, ...)
-{
-	va_list arg;
-	Vec argv;
-	char *p;
-	
-	vinit(&argv);
-	vadd(&argv, cmd);
-	va_start(arg, cmd);
-	while((p = va_arg(arg, char*)) != nil)
-		vadd(&argv, p);
-	va_end(arg);
-	
-	runv(b, dir, mode, &argv);
-	
-	vfree(&argv);
-}
-
-// runv is like run but takes a vector.
-void
-runv(Buf *b, char *dir, int mode, Vec *argv)
-{
-	genrun(b, dir, mode, argv, 1);
-}
-
-// bgrunv is like run but runs the command in the background.
-// bgwait waits for pending bgrunv to finish.
-void
-bgrunv(char *dir, int mode, Vec *argv)
-{
-	genrun(nil, dir, mode, argv, 0);
-}
-
-#define MAXBG 4 /* maximum number of jobs to run at once */
-
-static struct {
-	int pid;
-	int mode;
-	char *cmd;
-	Buf *b;
-} bg[MAXBG];
-static int nbg;
-static int maxnbg = nelem(bg);
-
-static void bgwait1(void);
-
-// genrun is the generic run implementation.
-static void
-genrun(Buf *b, char *dir, int mode, Vec *argv, int wait)
-{
-	int i, p[2], pid;
-	Buf b1, cmd;
-	char *q;
-
-	while(nbg >= maxnbg)
-		bgwait1();
-
-	binit(&b1);
-	binit(&cmd);
-
-	if(!isabs(argv->p[0])) {
-		bpathf(&b1, "/bin/%s", argv->p[0]);
-		free(argv->p[0]);
-		argv->p[0] = xstrdup(bstr(&b1));
-	}
-
-	// Generate a copy of the command to show in a log.
-	// Substitute $WORK for the work directory.
-	for(i=0; i<argv->len; i++) {
-		if(i > 0)
-			bwritestr(&cmd, " ");
-		q = argv->p[i];
-		if(workdir != nil && hasprefix(q, workdir)) {
-			bwritestr(&cmd, "$WORK");
-			q += strlen(workdir);
-		}
-		bwritestr(&cmd, q);
-	}
-	if(vflag > 1)
-		errprintf("%s\n", bstr(&cmd));
-
-	if(b != nil) {
-		breset(b);
-		if(pipe(p) < 0)
-			fatal("pipe");
-	}
-
-	switch(pid = fork()) {
-	case -1:
-		fatal("fork");
-	case 0:
-		if(b != nil) {
-			close(0);
-			close(p[0]);
-			dup(p[1], 1);
-			dup(p[1], 2);
-			if(p[1] > 2)
-				close(p[1]);
-		}
-		if(dir != nil) {
-			if(chdir(dir) < 0) {
-				fprint(2, "chdir: %r\n");
-				_exits("chdir");
-			}
-		}
-		vadd(argv, nil);
-		exec(argv->p[0], argv->p);
-		fprint(2, "%s\n", bstr(&cmd));
-		fprint(2, "exec: %r\n");
-		_exits("exec");
-	}
-	if(b != nil) {
-		close(p[1]);
-		breadfrom(b, p[0]);
-		close(p[0]);
-	}
-
-	if(nbg < 0)
-		fatal("bad bookkeeping");
-	bg[nbg].pid = pid;
-	bg[nbg].mode = mode;
-	bg[nbg].cmd = btake(&cmd);
-	bg[nbg].b = b;
-	nbg++;
-	
-	if(wait)
-		bgwait();
-
-	bfree(&cmd);
-	bfree(&b1);
-}
-
-// bgwait1 waits for a single background job.
-static void
-bgwait1(void)
-{
-	Waitmsg *w;
-	int i, mode;
-	char *cmd;
-	Buf *b;
-
-	w = wait();
-	if(w == nil)
-		fatal("wait");
-		
-	for(i=0; i<nbg; i++)
-		if(bg[i].pid == w->pid)
-			goto ok;
-	fatal("wait: unexpected pid");
-
-ok:
-	cmd = bg[i].cmd;
-	mode = bg[i].mode;
-	bg[i].pid = 0;
-	b = bg[i].b;
-	bg[i].b = nil;
-	bg[i] = bg[--nbg];
-	
-	if(mode == CheckExit && w->msg[0]) {
-		if(b != nil)
-			xprintf("%s\n", bstr(b));
-		fatal("FAILED: %s", cmd);
-	}
-	xfree(cmd);
-}
-
-// bgwait waits for all the background jobs.
-void
-bgwait(void)
-{
-	while(nbg > 0)
-		bgwait1();
-}
-
-// xgetwd replaces b with the current directory.
-void
-xgetwd(Buf *b)
-{
-	char buf[4096];
-	
-	breset(b);
-	if(getwd(buf, sizeof buf) == nil)
-		fatal("getwd");
-	bwritestr(b, buf);
-}
-
-// xrealwd replaces b with the 'real' name for the given path.
-// real is defined as what getcwd returns in that directory.
-void
-xrealwd(Buf *b, char *path)
-{
-	char buf[4096];
-	int fd;
-
-	fd = open(path, OREAD);
-	if(fd2path(fd, buf, sizeof buf) < 0)
-		fatal("fd2path");
-	close(fd);
-	breset(b);
-	bwritestr(b, buf);
-}
-
-// isdir reports whether p names an existing directory.
-bool
-isdir(char *p)
-{
-	Dir *d;
-	ulong mode;
-
-	d = dirstat(p);
-	if(d == nil)
-		return 0;
-	mode = d->mode;
-	free(d);
-	return (mode & DMDIR) == DMDIR;
-}
-
-// isfile reports whether p names an existing file.
-bool
-isfile(char *p)
-{
-	Dir *d;
-	ulong mode;
-
-	d = dirstat(p);
-	if(d == nil)
-		return 0;
-	mode = d->mode;
-	free(d);
-	return (mode & DMDIR) == 0;
-}
-
-// mtime returns the modification time of the file p.
-Time
-mtime(char *p)
-{
-	Dir *d;
-	ulong t;
-
-	d = dirstat(p);
-	if(d == nil)
-		return 0;
-	t = d->mtime;
-	free(d);
-	return (Time)t;
-}
-
-// isabs reports whether p is an absolute path.
-bool
-isabs(char *p)
-{
-	return hasprefix(p, "/");
-}
-
-// readfile replaces b with the content of the named file.
-void
-readfile(Buf *b, char *file)
-{
-	int fd;
-
-	breset(b);
-	fd = open(file, OREAD);
-	if(fd < 0)
-		fatal("open %s", file);
-	breadfrom(b, fd);
-	close(fd);
-}
-
-// writefile writes b to the named file, creating it if needed.
-void
-writefile(Buf *b, char *file, int exec)
-{
-	int fd;
-	Dir d;
-	
-	fd = create(file, ORDWR, 0666);
-	if(fd < 0)
-		fatal("create %s", file);
-	if(write(fd, b->p, b->len) != b->len)
-		fatal("short write");
-	if(exec) {
-		nulldir(&d);
-		d.mode = 0755;
-		dirfwstat(fd, &d);
-	}
-	close(fd);
-}
-
-// xmkdir creates the directory p.
-void
-xmkdir(char *p)
-{
-	int fd;
-
-	if(isdir(p))
-		return;
-	fd = create(p, OREAD, 0777|DMDIR);
-	close(fd);
-	if(fd < 0)
-		fatal("mkdir %s", p);
-}
-
-// xmkdirall creates the directory p and its parents, as needed.
-void
-xmkdirall(char *p)
-{
-	char *q;
-
-	if(isdir(p))
-		return;
-	q = strrchr(p, '/');
-	if(q != nil) {
-		*q = '\0';
-		xmkdirall(p);
-		*q = '/';
-	}
-	xmkdir(p);
-}
-
-// xremove removes the file p.
-void
-xremove(char *p)
-{
-	if(vflag > 2)
-		errprintf("rm %s\n", p);
-	remove(p);
-}
-
-// xremoveall removes the file or directory tree rooted at p.
-void
-xremoveall(char *p)
-{
-	int i;
-	Buf b;
-	Vec dir;
-
-	binit(&b);
-	vinit(&dir);
-
-	if(isdir(p)) {
-		xreaddir(&dir, p);
-		for(i=0; i<dir.len; i++) {
-			bprintf(&b, "%s/%s", p, dir.p[i]);
-			xremoveall(bstr(&b));
-		}
-	}
-	if(vflag > 2)
-		errprintf("rm %s\n", p);
-	remove(p);
-	
-	bfree(&b);
-	vfree(&dir);	
-}
-
-// xreaddir replaces dst with a list of the names of the files in dir.
-// The names are relative to dir; they are not full paths.
-void
-xreaddir(Vec *dst, char *dir)
-{
-	Dir *d;
-	int fd, i, n;
-
-	vreset(dst);
-
-	fd = open(dir, OREAD);
-	if(fd < 0)
-		fatal("open %s", dir);
-	n = dirreadall(fd, &d);
-	for(i=0; i<n; i++)
-		vadd(dst, d[i].name);
-	free(d);
-	close(fd);
-}
-
-// xworkdir creates a new temporary directory to hold object files
-// and returns the name of that directory.
-char*
-xworkdir(void)
-{
-	Buf b;
-	char *p;
-	int fd, tries;
-
-	binit(&b);
-
-	fd = 0;
-	for(tries=0; tries<1000; tries++) {
-		bprintf(&b, "/tmp/go-cbuild-%06x", nrand((1<<24)-1));
-		fd = create(bstr(&b), OREAD|OEXCL, 0700|DMDIR);
-		if(fd >= 0)
-			goto done;
-	}
-	fatal("xworkdir create");
-
-done:
-	close(fd);
-	p = btake(&b);
-
-	bfree(&b);
-	return p;
-}
-
-// fatal prints an error message to standard error and exits.
-void
-fatal(char *msg, ...)
-{
-	char buf[ERRMAX];
-	va_list arg;
-	
-	rerrstr(buf, sizeof buf);
-
-	fflush(stdout);
-	fprintf(stderr, "go tool dist: ");
-	va_start(arg, msg);
-	vfprintf(stderr, msg, arg);
-	va_end(arg);
-
-	if(buf[0])
-		fprintf(stderr, ": %s", buf);
-	fprintf(stderr, "\n");
-
-	bgwait();
-	exits(msg);
-}
-
-// xmalloc returns a newly allocated zeroed block of n bytes of memory.
-// It calls fatal if it runs out of memory.
-void*
-xmalloc(int n)
-{
-	void *p;
-	
-	p = malloc(n);
-	if(p == nil)
-		fatal("out of memory");
-	memset(p, 0, n);
-	return p;
-}
-
-// xstrdup returns a newly allocated copy of p.
-// It calls fatal if it runs out of memory.
-char*
-xstrdup(char *p)
-{
-	p = strdup(p);
-	if(p == nil)
-		fatal("out of memory");
-	return p;
-}
-
-// xrealloc grows the allocation p to n bytes and
-// returns the new (possibly moved) pointer.
-// It calls fatal if it runs out of memory.
-void*
-xrealloc(void *p, int n)
-{
-	p = realloc(p, n);
-	if(p == nil)
-		fatal("out of memory");
-	return p;
-}
-
-// xfree frees the result returned by xmalloc, xstrdup, or xrealloc.
-void
-xfree(void *p)
-{
-	free(p);
-}
-
-// hassuffix reports whether p ends with suffix.
-bool
-hassuffix(char *p, char *suffix)
-{
-	int np, ns;
-
-	np = strlen(p);
-	ns = strlen(suffix);
-	return np >= ns && streq(p+np-ns, suffix);
-}
-
-// hasprefix reports whether p begins with prefix.
-bool
-hasprefix(char *p, char *prefix)
-{
-	return strncmp(p, prefix, strlen(prefix)) == 0;
-}
-
-// contains reports whether sep appears in p.
-bool
-contains(char *p, char *sep)
-{
-	return strstr(p, sep) != nil;
-}
-
-// streq reports whether p and q are the same string.
-bool
-streq(char *p, char *q)
-{
-	return strcmp(p, q) == 0;
-}
-
-// lastelem returns the final path element in p.
-char*
-lastelem(char *p)
-{
-	char *out;
-
-	out = p;
-	for(; *p; p++)
-		if(*p == '/')
-			out = p+1;
-	return out;
-}
-
-// xmemmove copies n bytes from src to dst.
-void
-xmemmove(void *dst, void *src, int n)
-{
-	memmove(dst, src, n);
-}
-
-// xmemcmp compares the n-byte regions starting at a and at b.
-int
-xmemcmp(void *a, void *b, int n)
-{
-	return memcmp(a, b, n);
-}
-
-// xstrlen returns the length of the NUL-terminated string at p.
-int
-xstrlen(char *p)
-{
-	return strlen(p);
-}
-
-// xexit exits the process with return code n.
-void
-xexit(int n)
-{
-	char buf[32];
-
-	snprintf(buf, sizeof buf, "%d", n);
-	exits(buf);
-}
-
-// xatexit schedules the exit-handler f to be run when the program exits.
-void
-xatexit(void (*f)(void))
-{
-	atexit(f);
-}
-
-// xprintf prints a message to standard output.
-void
-xprintf(char *fmt, ...)
-{
-	va_list arg;
-	
-	va_start(arg, fmt);
-	vprintf(fmt, arg);
-	va_end(arg);
-}
-
-// errprintf prints a message to standard output.
-void
-errprintf(char *fmt, ...)
-{
-	va_list arg;
-	
-	va_start(arg, fmt);
-	vfprintf(stderr, fmt, arg);
-	va_end(arg);
-}
-
-// xsetenv sets the environment variable $name to the given value.
-void
-xsetenv(char *name, char *value)
-{
-	putenv(name, value);
-}
-
-// main takes care of OS-specific startup and dispatches to xmain.
-void
-main(int argc, char **argv)
-{
-	Buf b;
-
-	setvbuf(stdout, nil, _IOLBF, BUFSIZ);
-	setvbuf(stderr, nil, _IOLBF, BUFSIZ);
-
-	binit(&b);
-
-	rfork(RFENVG);
-
-	slash = "/";
-	gohostos = "plan9";
-
-	xgetenv(&b, "objtype");
-	if(b.len == 0)
-		fatal("$objtype is unset");
-	gohostarch = btake(&b);
-
-	srand(time(0)+getpid());
-	init();
-	xmain(argc, argv);
-
-	bfree(&b);
-	exits(nil);
-}
-
-// xqsort is a wrapper for the C standard qsort.
-void
-xqsort(void *data, int n, int elemsize, int (*cmp)(const void*, const void*))
-{
-	qsort(data, n, elemsize, cmp);
-}
-
-// xstrcmp compares the NUL-terminated strings a and b.
-int
-xstrcmp(char *a, char *b)
-{
-	return strcmp(a, b);
-}
-
-// xstrstr returns a pointer to the first occurrence of b in a.
-char*
-xstrstr(char *a, char *b)
-{
-	return strstr(a, b);
-}
-
-// xstrrchr returns a pointer to the final occurrence of c in p.
-char*
-xstrrchr(char *p, int c)
-{
-	return strrchr(p, c);
-}
-
-// xsamefile reports whether f1 and f2 are the same file (or dir)
-int
-xsamefile(char *f1, char *f2)
-{
-	return streq(f1, f2); // suffice for now
-}
-
-// xtryexecfunc tries to execute function f, if any illegal instruction
-// signal received in the course of executing that function, it will
-// return 0, otherwise it will return 1.
-int
-xtryexecfunc(void (*f)(void))
-{
-	USED(f);
-	return 0; // suffice for now
-}
-
-bool
-cansse2(void)
-{
-	// if we had access to cpuid, could answer this question
-	// less conservatively.
-	return 0;
-}
-
-#endif // PLAN9
diff --git a/src/cmd/dist/sys_default.go b/src/cmd/dist/sys_default.go
new file mode 100644
index 0000000..d7bc464
--- /dev/null
+++ b/src/cmd/dist/sys_default.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 !windows
+
+package main
+
+func sysinit() {
+}
diff --git a/src/cmd/dist/sys_windows.go b/src/cmd/dist/sys_windows.go
new file mode 100644
index 0000000..e9bfe9e
--- /dev/null
+++ b/src/cmd/dist/sys_windows.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.
+
+package main
+
+import (
+	"syscall"
+	"unsafe"
+)
+
+var (
+	modkernel32       = syscall.NewLazyDLL("kernel32.dll")
+	procGetSystemInfo = modkernel32.NewProc("GetSystemInfo")
+)
+
+// see http://msdn.microsoft.com/en-us/library/windows/desktop/ms724958(v=vs.85).aspx
+type systeminfo struct {
+	wProcessorArchitecture      uint16
+	wReserved                   uint16
+	dwPageSize                  uint32
+	lpMinimumApplicationAddress uintptr
+	lpMaximumApplicationAddress uintptr
+	dwActiveProcessorMask       uintptr
+	dwNumberOfProcessors        uint32
+	dwProcessorType             uint32
+	dwAllocationGranularity     uint32
+	wProcessorLevel             uint16
+	wProcessorRevision          uint16
+}
+
+const (
+	PROCESSOR_ARCHITECTURE_AMD64 = 9
+	PROCESSOR_ARCHITECTURE_INTEL = 0
+)
+
+var sysinfo systeminfo
+
+func sysinit() {
+	syscall.Syscall(procGetSystemInfo.Addr(), 1, uintptr(unsafe.Pointer(&sysinfo)), 0, 0)
+	switch sysinfo.wProcessorArchitecture {
+	case PROCESSOR_ARCHITECTURE_AMD64:
+		gohostarch = "amd64"
+	case PROCESSOR_ARCHITECTURE_INTEL:
+		gohostarch = "386"
+	default:
+		fatal("unknown processor architecture")
+	}
+}
diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go
new file mode 100755
index 0000000..d0e6346
--- /dev/null
+++ b/src/cmd/dist/test.go
@@ -0,0 +1,866 @@
+// 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.BoolVar(&t.keepGoing, "k", false, "keep going even when error occurred")
+	flag.BoolVar(&t.race, "race", false, "run in race builder mode (different set of tests)")
+	flag.StringVar(&t.banner, "banner", "##### ", "banner prefix; blank means no section banners")
+	flag.StringVar(&t.runRxStr, "run", os.Getenv("GOTESTONLY"),
+		"run only those tests matching the regular expression; empty means to run all. "+
+			"Special exception: if the string begins with '!', the match is inverted.")
+	xflagparse(-1) // any number of args
+	t.run()
+}
+
+// tester executes cmdtest.
+type tester struct {
+	race      bool
+	listMode  bool
+	noRebuild bool
+	keepGoing bool
+	runRxStr  string
+	runRx     *regexp.Regexp
+	runRxWant bool     // want runRx to match (true) or not match (false)
+	runNames  []string // tests to run, exclusive with runRx; empty means all
+	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 flag.NArg() > 0 && t.runRxStr != "" {
+		log.Fatalf("the -run regular expression flag is mutually exclusive with test name arguments")
+	}
+	t.runNames = flag.Args()
+
+	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)
+		}
+	}
+
+	if t.iOS() {
+		// Install the Mach exception handler used to intercept
+		// EXC_BAD_ACCESS and convert it into a Go panic. This is
+		// necessary for a Go program running under lldb (the way
+		// we run tests). It is disabled by default because iOS
+		// apps are not allowed to access the exc_server symbol.
+		cmd := exec.Command("go", "install", "-a", "-tags", "lldb", "runtime/cgo")
+		cmd.Stdout = os.Stdout
+		cmd.Stderr = os.Stderr
+		if err := cmd.Run(); err != nil {
+			log.Fatalf("building mach exception handler: %v", err)
+		}
+
+		defer func() {
+			cmd := exec.Command("go", "install", "-a", "runtime/cgo")
+			cmd.Stdout = os.Stdout
+			cmd.Stderr = os.Stderr
+			if err := cmd.Run(); err != nil {
+				log.Fatalf("reverting mach exception handler: %v", err)
+			}
+		}()
+	}
+
+	t.timeoutScale = 1
+	if t.goarch == "arm" || t.goos == "windows" {
+		t.timeoutScale = 2
+	}
+	if s := os.Getenv("GO_TEST_TIMEOUT_SCALE"); s != "" {
+		t.timeoutScale, err = strconv.Atoi(s)
+		if err != nil {
+			log.Fatalf("failed to parse $GO_TEST_TIMEOUT_SCALE = %q as integer: %v", s, err)
+		}
+	}
+
+	if t.runRxStr != "" {
+		if t.runRxStr[0] == '!' {
+			t.runRxWant = false
+			t.runRxStr = t.runRxStr[1:]
+		} else {
+			t.runRxWant = true
+		}
+		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")
+
+	for _, name := range t.runNames {
+		if !t.isRegisteredTestName(name) {
+			log.Fatalf("unknown test %q", name)
+		}
+	}
+
+	var lastHeading string
+	ok := true
+	for _, dt := range t.tests {
+		if !t.shouldRunTest(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 {
+			ok = false
+			if t.keepGoing {
+				log.Printf("Failed: %v", err)
+			} else {
+				log.Fatalf("Failed: %v", err)
+			}
+		}
+	}
+	if !ok {
+		fmt.Println("\nFAILED")
+		os.Exit(1)
+	} else if t.partial {
+		fmt.Println("\nALL TESTS PASSED (some were excluded)")
+	} else {
+		fmt.Println("\nALL TESTS PASSED")
+	}
+}
+
+func (t *tester) shouldRunTest(name string) bool {
+	if t.runRx != nil {
+		return t.runRx.MatchString(name) == t.runRxWant
+	}
+	if len(t.runNames) == 0 {
+		return true
+	}
+	for _, runName := range t.runNames {
+		if runName == name {
+			return true
+		}
+	}
+	return false
+}
+
+func (t *tester) tags() string {
+	if t.iOS() {
+		return "-tags=lldb"
+	}
+	return "-tags="
+}
+
+func (t *tester) timeout(sec int) string {
+	return "-timeout=" + fmt.Sprint(time.Duration(sec)*time.Second*time.Duration(t.timeoutScale))
+}
+
+// ranGoTest and stdMatches are state closed over by the stdlib
+// testing func in registerStdTest below. The tests are run
+// sequentially, so there's no need for locks.
+//
+// ranGoBench and benchMatches are the same, but are only used
+// in -race mode.
+var (
+	ranGoTest  bool
+	stdMatches []string
+
+	ranGoBench   bool
+	benchMatches []string
+)
+
+func (t *tester) registerStdTest(pkg string) {
+	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
+			args := []string{
+				"test",
+				"-short",
+				t.tags(),
+				t.timeout(180),
+				"-gcflags=" + os.Getenv("GO_GCFLAGS"),
+			}
+			if t.race {
+				args = append(args, "-race")
+			}
+			args = append(args, stdMatches...)
+			cmd := exec.Command("go", args...)
+			cmd.Stdout = os.Stdout
+			cmd.Stderr = os.Stderr
+			return cmd.Run()
+		},
+	})
+}
+
+func (t *tester) registerRaceBenchTest(pkg string) {
+	testName := "go_test_bench:" + pkg
+	if t.runRx == nil || t.runRx.MatchString(testName) {
+		benchMatches = append(benchMatches, pkg)
+	}
+	t.tests = append(t.tests, distTest{
+		name:    testName,
+		heading: "Running benchmarks briefly.",
+		fn: func() error {
+			if ranGoBench {
+				return nil
+			}
+			ranGoBench = true
+			args := []string{
+				"test",
+				"-short",
+				"-race",
+				"-run=^$", // nothing. only benchmarks.
+				"-bench=.*",
+				"-benchtime=.1s",
+				"-cpu=4",
+			}
+			args = append(args, benchMatches...)
+			cmd := exec.Command("go", args...)
+			cmd.Stdout = os.Stdout
+			cmd.Stderr = os.Stderr
+			return cmd.Run()
+		},
+	})
+}
+
+func (t *tester) registerTests() {
+	// Fast path to avoid the ~1 second of `go list std cmd` when
+	// the caller lists specific tests to run. (as the continuous
+	// build coordinator does).
+	if len(t.runNames) > 0 {
+		for _, name := range t.runNames {
+			if strings.HasPrefix(name, "go_test:") {
+				t.registerStdTest(strings.TrimPrefix(name, "go_test:"))
+			}
+			if strings.HasPrefix(name, "go_test_bench:") {
+				t.registerRaceBenchTest(strings.TrimPrefix(name, "go_test_bench:"))
+			}
+		}
+	} else {
+		// Use a format string to only list packages and commands that have tests.
+		const format = "{{if (or .TestGoFiles .XTestGoFiles)}}{{.ImportPath}}{{end}}"
+		cmd := exec.Command("go", "list", "-f", format, "std")
+		if !t.race {
+			cmd.Args = append(cmd.Args, "cmd")
+		}
+		all, err := cmd.CombinedOutput()
+		if err != nil {
+			log.Fatalf("Error running go list std cmd: %v, %s", err, all)
+		}
+		pkgs := strings.Fields(string(all))
+		for _, pkg := range pkgs {
+			t.registerStdTest(pkg)
+		}
+		if t.race {
+			for _, pkg := range pkgs {
+				t.registerRaceBenchTest(pkg)
+			}
+		}
+	}
+
+	if t.race {
+		return
+	}
+
+	// Runtime CPU tests.
+	testName := "runtime:cpu124"
+	t.tests = append(t.tests, distTest{
+		name:    testName,
+		heading: "GOMAXPROCS=2 runtime -cpu=1,2,4",
+		fn: func() error {
+			cmd := t.dirCmd("src", "go", "test", "-short", t.timeout(300), t.tags(), "runtime", "-cpu=1,2,4")
+			// 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("src", "go", "test", "sync", "-short", t.timeout(120), t.tags(), "-cpu=10").Run()
+		},
+	})
+
+	if t.cgoEnabled && t.goos != "android" && !t.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" && !t.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.cgoTestSOSupported() {
+			t.tests = append(t.tests, distTest{
+				name:    "testso",
+				heading: "../misc/cgo/testso",
+				fn: func() error {
+					return t.cgoTestSO("misc/cgo/testso")
+				},
+			})
+			t.tests = append(t.tests, distTest{
+				name:    "testsovar",
+				heading: "../misc/cgo/testsovar",
+				fn: func() error {
+					return t.cgoTestSO("misc/cgo/testsovar")
+				},
+			})
+		}
+		if t.supportedBuildmode("c-archive") {
+			t.registerTest("testcarchive", "../misc/cgo/testcarchive", "./test.bash")
+		}
+		if t.supportedBuildmode("c-shared") {
+			t.registerTest("testcshared", "../misc/cgo/testcshared", "./test.bash")
+		}
+		if t.supportedBuildmode("shared") {
+			t.registerTest("testshared", "../misc/cgo/testshared", "go", "test")
+		}
+		if t.gohostos == "linux" && t.goarch == "amd64" {
+			t.registerTest("testasan", "../misc/cgo/testasan", "go", "run", "main.go")
+		}
+		if t.hasBash() && t.goos != "android" && !t.iOS() && t.gohostos != "windows" {
+			t.registerTest("cgo_errors", "../misc/cgo/errors", "./test.bash")
+		}
+		if t.gohostos == "linux" && t.extLink() {
+			t.registerTest("testsigfwd", "../misc/cgo/testsigfwd", "go", "run", "main.go")
+		}
+	}
+	if t.hasBash() && t.goos != "nacl" && t.goos != "android" && !t.iOS() {
+		t.registerTest("doc_progs", "../doc/progs", "time", "go", "run", "run.go")
+		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" && !t.iOS() {
+		t.registerTest("bench_go1", "../test/bench/go1", "go", "test")
+	}
+	if t.goos != "android" && !t.iOS() {
+		const nShards = 5
+		for shard := 0; shard < nShards; shard++ {
+			shard := shard
+			t.tests = append(t.tests, distTest{
+				name:    fmt.Sprintf("test:%d_%d", shard, nShards),
+				heading: "../test",
+				fn:      func() error { return t.testDirTest(shard, nShards) },
+			})
+		}
+	}
+	if t.goos != "nacl" && t.goos != "android" && !t.iOS() {
+		t.tests = append(t.tests, distTest{
+			name:    "api",
+			heading: "API check",
+			fn: func() error {
+				return t.dirCmd("src", "go", "run", filepath.Join(t.goroot, "src/cmd/api/run.go")).Run()
+			},
+		})
+	}
+}
+
+// isRegisteredTestName reports whether a test named testName has already
+// been registered.
+func (t *tester) isRegisteredTestName(testName string) bool {
+	for _, tt := range t.tests {
+		if tt.name == testName {
+			return true
+		}
+	}
+	return false
+}
+
+func (t *tester) registerTest(name, dirBanner, bin string, args ...string) {
+	if bin == "time" && !t.haveTime {
+		bin, args = args[0], args[1:]
+	}
+	if t.isRegisteredTestName(name) {
+		panic("duplicate registered test name " + name)
+	}
+	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
+	if vflag > 1 {
+		errprintf("%s\n", strings.Join(cmd.Args, " "))
+	}
+	return cmd
+}
+
+func (t *tester) iOS() bool {
+	return t.goos == "darwin" && (t.goarch == "arm" || t.goarch == "arm64")
+}
+
+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",
+		"darwin-arm", "darwin-arm64",
+		"dragonfly-386", "dragonfly-amd64",
+		"freebsd-386", "freebsd-amd64", "freebsd-arm",
+		"linux-386", "linux-amd64", "linux-arm", "linux-arm64",
+		"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) supportedBuildmode(mode string) bool {
+	pair := t.goos + "-" + t.goarch
+	switch mode {
+	case "c-archive":
+		if !t.extLink() {
+			return false
+		}
+		switch pair {
+		case "darwin-amd64", "darwin-arm", "darwin-arm64",
+			"linux-amd64", "linux-386":
+			return true
+		}
+		return false
+	case "c-shared":
+		// TODO(hyangah): add linux-386.
+		switch pair {
+		case "linux-amd64", "darwin-amd64", "android-arm":
+			return true
+		}
+		return false
+	case "shared":
+		switch pair {
+		case "linux-amd64":
+			return true
+		}
+		return false
+	default:
+		log.Fatal("internal error: unknown buildmode %s", mode)
+		return false
+	}
+}
+
+func (t *tester) cgoTest() error {
+	env := mergeEnvLists([]string{"GOTRACEBACK=2"}, os.Environ())
+
+	if t.goos == "android" || t.iOS() {
+		cmd := t.dirCmd("misc/cgo/test", "go", "test", t.tags())
+		cmd.Env = env
+		return cmd.Run()
+	}
+
+	cmd := t.dirCmd("misc/cgo/test", "go", "test", t.tags(), "-ldflags", "-linkmode=auto")
+	cmd.Env = env
+	if err := cmd.Run(); err != nil {
+		return err
+	}
+
+	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 "darwin-386", "darwin-amd64",
+		"openbsd-386", "openbsd-amd64",
+		"windows-386", "windows-amd64":
+		// test linkmode=external, but __thread not supported, so skip testtls.
+		if !t.extLink() {
+			break
+		}
+		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/test", "go", "test", "-ldflags", "-linkmode=external -s")
+		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) cgoTestSOSupported() bool {
+	if t.goos == "android" || t.iOS() {
+		// No exec facility on Android or iOS.
+		return false
+	}
+	if t.goarch == "ppc64le" || t.goarch == "ppc64" {
+		// External linking not implemented on ppc64 (issue #8912).
+		return false
+	}
+	return true
+}
+
+func (t *tester) cgoTestSO(testpath string) error {
+	dir := filepath.Join(t.goroot, testpath)
+
+	// build shared object
+	output, err := exec.Command("go", "env", "CC").Output()
+	if err != nil {
+		return fmt.Errorf("Error running go env CC: %v", err)
+	}
+	cc := strings.TrimSuffix(string(output), "\n")
+	if cc == "" {
+		return errors.New("CC environment variable (go env CC) cannot be empty")
+	}
+	output, err = exec.Command("go", "env", "GOGCCFLAGS").Output()
+	if err != nil {
+		return fmt.Errorf("Error running go env GOGCCFLAGS: %v", err)
+	}
+	gogccflags := strings.Split(strings.TrimSuffix(string(output), "\n"), " ")
+
+	ext := "so"
+	args := append(gogccflags, "-shared")
+	switch t.goos {
+	case "darwin":
+		ext = "dylib"
+		args = append(args, "-undefined", "suppress", "-flat_namespace")
+	case "windows":
+		ext = "dll"
+		args = append(args, "-DEXPORT_DLL")
+	}
+	sofname := "libcgosotest." + ext
+	args = append(args, "-o", sofname, "cgoso_c.c")
+
+	if err := t.dirCmd(dir, cc, args...).Run(); err != nil {
+		return err
+	}
+	defer os.Remove(filepath.Join(dir, sofname))
+
+	if err := t.dirCmd(dir, "go", "build", "-o", "main.exe", "main.go").Run(); err != nil {
+		return err
+	}
+	defer os.Remove(filepath.Join(dir, "main.exe"))
+
+	cmd := t.dirCmd(dir, "./main.exe")
+	if t.goos != "windows" {
+		s := "LD_LIBRARY_PATH"
+		if t.goos == "darwin" {
+			s = "DYLD_LIBRARY_PATH"
+		}
+		cmd.Env = mergeEnvLists([]string{s + "=."}, os.Environ())
+	}
+	return cmd.Run()
+}
+
+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("src", "go", "test", "-race", "-i", "runtime/race", "flag", "os/exec").Run(); err != nil {
+		return err
+	}
+	if err := t.dirCmd("src", "go", "test", "-race", "-run=Output", "runtime/race").Run(); err != nil {
+		return err
+	}
+	if err := t.dirCmd("src", "go", "test", "-race", "-short", "flag", "os/exec").Run(); err != nil {
+		return err
+	}
+	if t.cgoEnabled {
+		env := mergeEnvLists([]string{"GOTRACEBACK=2"}, os.Environ())
+		cmd := t.dirCmd("misc/cgo/test", "go", "test", "-race", "-short")
+		cmd.Env = env
+		if err := cmd.Run(); err != nil {
+			return err
+		}
+	}
+	if t.extLink() {
+		// Test with external linking; see issue 9133.
+		if err := t.dirCmd("src", "go", "test", "-race", "-short", "-ldflags=-linkmode=external", "flag", "os/exec").Run(); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func (t *tester) testDirTest(shard, shards int) 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)
+	return t.dirCmd("test", absExe,
+		fmt.Sprintf("--shard=%d", shard),
+		fmt.Sprintf("--shards=%d", shards),
+	).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/unix.c b/src/cmd/dist/unix.c
deleted file mode 100644
index 4a78684..0000000
--- a/src/cmd/dist/unix.c
+++ /dev/null
@@ -1,843 +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.
-
-// These #ifdefs are being used as a substitute for
-// build configuration, so that on any system, this
-// tool can be built with the local equivalent of
-//	cc *.c
-//
-#ifndef WIN32
-#ifndef PLAN9
-
-#include "a.h"
-#include <unistd.h>
-#include <dirent.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-#include <sys/param.h>
-#include <sys/utsname.h>
-#include <fcntl.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <stdarg.h>
-#include <setjmp.h>
-#include <signal.h>
-
-// bprintf replaces the buffer with the result of the printf formatting
-// and returns a pointer to the NUL-terminated buffer contents.
-char*
-bprintf(Buf *b, char *fmt, ...)
-{
-	va_list arg;
-	char buf[4096];
-	
-	breset(b);
-	va_start(arg, fmt);
-	vsnprintf(buf, sizeof buf, fmt, arg);
-	va_end(arg);
-	bwritestr(b, buf);
-	return bstr(b);
-}
-
-// bpathf is the same as bprintf (on windows it turns / into \ after the printf).
-// It returns a pointer to the NUL-terminated buffer contents.
-char*
-bpathf(Buf *b, char *fmt, ...)
-{
-	va_list arg;
-	char buf[4096];
-	
-	breset(b);
-	va_start(arg, fmt);
-	vsnprintf(buf, sizeof buf, fmt, arg);
-	va_end(arg);
-	bwritestr(b, buf);
-	return bstr(b);
-}
-
-// bwritef is like bprintf but does not reset the buffer
-// and does not return the NUL-terminated string.
-void
-bwritef(Buf *b, char *fmt, ...)
-{
-	va_list arg;
-	char buf[4096];
-	
-	va_start(arg, fmt);
-	vsnprintf(buf, sizeof buf, fmt, arg);
-	va_end(arg);
-	bwritestr(b, buf);
-}
-
-// breadfrom appends to b all the data that can be read from fd.
-static void
-breadfrom(Buf *b, int fd)
-{
-	int n;
-
-	for(;;) {
-		bgrow(b, 4096);
-		n = read(fd, b->p+b->len, 4096);
-		if(n < 0)
-			fatal("read: %s", strerror(errno));
-		if(n == 0)
-			break;
-		b->len += n;
-	}
-}
-
-// xgetenv replaces b with the value of the named environment variable.
-void
-xgetenv(Buf *b, char *name)
-{
-	char *p;
-	
-	breset(b);
-	p = getenv(name);
-	if(p != NULL)
-		bwritestr(b, p);
-}
-
-static void genrun(Buf *b, char *dir, int mode, Vec *argv, int bg);
-
-// run runs the command named by cmd.
-// If b is not nil, run replaces b with the output of the command.
-// If dir is not nil, run runs the command in that directory.
-// If mode is CheckExit, run calls fatal if the command is not successful.
-void
-run(Buf *b, char *dir, int mode, char *cmd, ...)
-{
-	va_list arg;
-	Vec argv;
-	char *p;
-	
-	vinit(&argv);
-	vadd(&argv, cmd);
-	va_start(arg, cmd);
-	while((p = va_arg(arg, char*)) != nil)
-		vadd(&argv, p);
-	va_end(arg);
-	
-	runv(b, dir, mode, &argv);
-	
-	vfree(&argv);
-}
-
-// runv is like run but takes a vector.
-void
-runv(Buf *b, char *dir, int mode, Vec *argv)
-{
-	genrun(b, dir, mode, argv, 1);
-}
-
-// bgrunv is like run but runs the command in the background.
-// bgwait waits for pending bgrunv to finish.
-void
-bgrunv(char *dir, int mode, Vec *argv)
-{
-	genrun(nil, dir, mode, argv, 0);
-}
-
-#define MAXBG 4 /* maximum number of jobs to run at once */
-
-static struct {
-	int pid;
-	int mode;
-	char *cmd;
-	Buf *b;
-} bg[MAXBG];
-static int nbg;
-static int maxnbg = nelem(bg);
-
-static void bgwait1(void);
-
-// genrun is the generic run implementation.
-static void
-genrun(Buf *b, char *dir, int mode, Vec *argv, int wait)
-{
-	int i, p[2], pid;
-	Buf cmd;
-	char *q;
-
-	while(nbg >= maxnbg)
-		bgwait1();
-
-	// Generate a copy of the command to show in a log.
-	// Substitute $WORK for the work directory.
-	binit(&cmd);
-	for(i=0; i<argv->len; i++) {
-		if(i > 0)
-			bwritestr(&cmd, " ");
-		q = argv->p[i];
-		if(workdir != nil && hasprefix(q, workdir)) {
-			bwritestr(&cmd, "$WORK");
-			q += strlen(workdir);
-		}
-		bwritestr(&cmd, q);
-	}
-	if(vflag > 1)
-		errprintf("%s\n", bstr(&cmd));
-
-	if(b != nil) {
-		breset(b);
-		if(pipe(p) < 0)
-			fatal("pipe: %s", strerror(errno));
-	}
-
-	switch(pid = fork()) {
-	case -1:
-		fatal("fork: %s", strerror(errno));
-	case 0:
-		if(b != nil) {
-			close(0);
-			close(p[0]);
-			dup2(p[1], 1);
-			dup2(p[1], 2);
-			if(p[1] > 2)
-				close(p[1]);
-		}
-		if(dir != nil) {
-			if(chdir(dir) < 0) {
-				fprintf(stderr, "chdir %s: %s\n", dir, strerror(errno));
-				_exit(1);
-			}
-		}
-		vadd(argv, nil);
-		execvp(argv->p[0], argv->p);
-		fprintf(stderr, "%s\n", bstr(&cmd));
-		fprintf(stderr, "exec %s: %s\n", argv->p[0], strerror(errno));
-		_exit(1);
-	}
-	if(b != nil) {
-		close(p[1]);
-		breadfrom(b, p[0]);
-		close(p[0]);
-	}
-
-	if(nbg < 0)
-		fatal("bad bookkeeping");
-	bg[nbg].pid = pid;
-	bg[nbg].mode = mode;
-	bg[nbg].cmd = btake(&cmd);
-	bg[nbg].b = b;
-	nbg++;
-	
-	if(wait)
-		bgwait();
-
-	bfree(&cmd);
-}
-
-// bgwait1 waits for a single background job.
-static void
-bgwait1(void)
-{
-	int i, pid, status, mode;
-	char *cmd;
-	Buf *b;
-
-	errno = 0;
-	while((pid = wait(&status)) < 0) {
-		if(errno != EINTR)
-			fatal("waitpid: %s", strerror(errno));
-	}
-	for(i=0; i<nbg; i++)
-		if(bg[i].pid == pid)
-			goto ok;
-	fatal("waitpid: unexpected pid");
-
-ok:
-	cmd = bg[i].cmd;
-	mode = bg[i].mode;
-	bg[i].pid = 0;
-	b = bg[i].b;
-	bg[i].b = nil;
-	bg[i] = bg[--nbg];
-	
-	if(mode == CheckExit && (!WIFEXITED(status) || WEXITSTATUS(status) != 0)) {
-		if(b != nil)
-			xprintf("%s\n", bstr(b));
-		fatal("FAILED: %s", cmd);
-	}
-	xfree(cmd);
-}
-
-// bgwait waits for all the background jobs.
-void
-bgwait(void)
-{
-	while(nbg > 0)
-		bgwait1();
-}
-
-// xgetwd replaces b with the current directory.
-void
-xgetwd(Buf *b)
-{
-	char buf[MAXPATHLEN];
-	
-	breset(b);
-	if(getcwd(buf, MAXPATHLEN) == nil)
-		fatal("getcwd: %s", strerror(errno));
-	bwritestr(b, buf);	
-}
-
-// xrealwd replaces b with the 'real' name for the given path.
-// real is defined as what getcwd returns in that directory.
-void
-xrealwd(Buf *b, char *path)
-{
-	int fd;
-	
-	fd = open(".", 0);
-	if(fd < 0)
-		fatal("open .: %s", strerror(errno));
-	if(chdir(path) < 0)
-		fatal("chdir %s: %s", path, strerror(errno));
-	xgetwd(b);
-	if(fchdir(fd) < 0)
-		fatal("fchdir: %s", strerror(errno));
-	close(fd);
-}
-
-// isdir reports whether p names an existing directory.
-bool
-isdir(char *p)
-{
-	struct stat st;
-	
-	return stat(p, &st) >= 0 && S_ISDIR(st.st_mode);
-}
-
-// isfile reports whether p names an existing file.
-bool
-isfile(char *p)
-{
-	struct stat st;
-	
-	return stat(p, &st) >= 0 && S_ISREG(st.st_mode);
-}
-
-// mtime returns the modification time of the file p.
-Time
-mtime(char *p)
-{
-	struct stat st;
-	
-	if(stat(p, &st) < 0)
-		return 0;
-	return (Time)st.st_mtime*1000000000LL;
-}
-
-// isabs reports whether p is an absolute path.
-bool
-isabs(char *p)
-{
-	return hasprefix(p, "/");
-}
-
-// readfile replaces b with the content of the named file.
-void
-readfile(Buf *b, char *file)
-{
-	int fd;
-	
-	breset(b);
-	fd = open(file, 0);
-	if(fd < 0)
-		fatal("open %s: %s", file, strerror(errno));
-	breadfrom(b, fd);
-	close(fd);
-}
-
-// writefile writes b to the named file, creating it if needed.  if
-// exec is non-zero, marks the file as executable.
-void
-writefile(Buf *b, char *file, int exec)
-{
-	int fd;
-	
-	fd = creat(file, 0666);
-	if(fd < 0)
-		fatal("create %s: %s", file, strerror(errno));
-	if(write(fd, b->p, b->len) != b->len)
-		fatal("short write: %s", strerror(errno));
-	if(exec)
-		fchmod(fd, 0755);
-	close(fd);
-}
-
-// xmkdir creates the directory p.
-void
-xmkdir(char *p)
-{
-	if(mkdir(p, 0777) < 0)
-		fatal("mkdir %s: %s", p, strerror(errno));
-}
-
-// xmkdirall creates the directory p and its parents, as needed.
-void
-xmkdirall(char *p)
-{
-	char *q;
-
-	if(isdir(p))
-		return;
-	q = strrchr(p, '/');
-	if(q != nil) {
-		*q = '\0';
-		xmkdirall(p);
-		*q = '/';
-	}
-	xmkdir(p);
-}
-
-// xremove removes the file p.
-void
-xremove(char *p)
-{
-	if(vflag > 2)
-		errprintf("rm %s\n", p);
-	unlink(p);
-}
-
-// xremoveall removes the file or directory tree rooted at p.
-void
-xremoveall(char *p)
-{
-	int i;
-	Buf b;
-	Vec dir;
-
-	binit(&b);
-	vinit(&dir);
-
-	if(isdir(p)) {
-		xreaddir(&dir, p);
-		for(i=0; i<dir.len; i++) {
-			bprintf(&b, "%s/%s", p, dir.p[i]);
-			xremoveall(bstr(&b));
-		}
-		if(vflag > 2)
-			errprintf("rm %s\n", p);
-		rmdir(p);
-	} else {
-		if(vflag > 2)
-			errprintf("rm %s\n", p);
-		unlink(p);
-	}
-	
-	bfree(&b);
-	vfree(&dir);
-}
-
-// xreaddir replaces dst with a list of the names of the files in dir.
-// The names are relative to dir; they are not full paths.
-void
-xreaddir(Vec *dst, char *dir)
-{
-	DIR *d;
-	struct dirent *dp;
-
-	vreset(dst);
-	d = opendir(dir);
-	if(d == nil)
-		fatal("opendir %s: %s", dir, strerror(errno));
-	while((dp = readdir(d)) != nil) {
-		if(streq(dp->d_name, ".") || streq(dp->d_name, ".."))
-			continue;
-		vadd(dst, dp->d_name);
-	}
-	closedir(d);
-}
-
-// xworkdir creates a new temporary directory to hold object files
-// and returns the name of that directory.
-char*
-xworkdir(void)
-{
-	Buf b;
-	char *p;
-
-	binit(&b);
-
-	xgetenv(&b, "TMPDIR");
-	if(b.len == 0)
-		bwritestr(&b, "/var/tmp");
-	if(b.p[b.len-1] != '/')
-		bwrite(&b, "/", 1);
-	bwritestr(&b, "go-cbuild-XXXXXX");
-	p = bstr(&b);
-	if(mkdtemp(p) == nil)
-		fatal("mkdtemp(%s): %s", p, strerror(errno));
-	p = btake(&b);
-
-	bfree(&b);
-
-	return p;
-}
-
-// fatal prints an error message to standard error and exits.
-void
-fatal(char *msg, ...)
-{
-	va_list arg;
-	
-	fflush(stdout);
-	fprintf(stderr, "go tool dist: ");
-	va_start(arg, msg);
-	vfprintf(stderr, msg, arg);
-	va_end(arg);
-	fprintf(stderr, "\n");
-	
-	bgwait();
-	exit(1);
-}
-
-// xmalloc returns a newly allocated zeroed block of n bytes of memory.
-// It calls fatal if it runs out of memory.
-void*
-xmalloc(int n)
-{
-	void *p;
-	
-	p = malloc(n);
-	if(p == nil)
-		fatal("out of memory");
-	memset(p, 0, n);
-	return p;
-}
-
-// xstrdup returns a newly allocated copy of p.
-// It calls fatal if it runs out of memory.
-char*
-xstrdup(char *p)
-{
-	p = strdup(p);
-	if(p == nil)
-		fatal("out of memory");
-	return p;
-}
-
-// xrealloc grows the allocation p to n bytes and
-// returns the new (possibly moved) pointer.
-// It calls fatal if it runs out of memory.
-void*
-xrealloc(void *p, int n)
-{
-	p = realloc(p, n);
-	if(p == nil)
-		fatal("out of memory");
-	return p;
-}
-
-// xfree frees the result returned by xmalloc, xstrdup, or xrealloc.
-void
-xfree(void *p)
-{
-	free(p);
-}
-
-// hassuffix reports whether p ends with suffix.
-bool
-hassuffix(char *p, char *suffix)
-{
-	int np, ns;
-
-	np = strlen(p);
-	ns = strlen(suffix);
-	return np >= ns && streq(p+np-ns, suffix);
-}
-
-// hasprefix reports whether p begins with prefix.
-bool
-hasprefix(char *p, char *prefix)
-{
-	return strncmp(p, prefix, strlen(prefix)) == 0;
-}
-
-// contains reports whether sep appears in p.
-bool
-contains(char *p, char *sep)
-{
-	return strstr(p, sep) != nil;
-}
-
-// streq reports whether p and q are the same string.
-bool
-streq(char *p, char *q)
-{
-	return strcmp(p, q) == 0;
-}
-
-// lastelem returns the final path element in p.
-char*
-lastelem(char *p)
-{
-	char *out;
-
-	out = p;
-	for(; *p; p++)
-		if(*p == '/')
-			out = p+1;
-	return out;
-}
-
-// xmemmove copies n bytes from src to dst.
-void
-xmemmove(void *dst, void *src, int n)
-{
-	memmove(dst, src, n);
-}
-
-// xmemcmp compares the n-byte regions starting at a and at b.
-int
-xmemcmp(void *a, void *b, int n)
-{
-	return memcmp(a, b, n);
-}
-
-// xstrlen returns the length of the NUL-terminated string at p.
-int
-xstrlen(char *p)
-{
-	return strlen(p);
-}
-
-// xexit exits the process with return code n.
-void
-xexit(int n)
-{
-	exit(n);
-}
-
-// xatexit schedules the exit-handler f to be run when the program exits.
-void
-xatexit(void (*f)(void))
-{
-	atexit(f);
-}
-
-// xprintf prints a message to standard output.
-void
-xprintf(char *fmt, ...)
-{
-	va_list arg;
-	
-	va_start(arg, fmt);
-	vprintf(fmt, arg);
-	va_end(arg);
-}
-
-// errprintf prints a message to standard output.
-void
-errprintf(char *fmt, ...)
-{
-	va_list arg;
-	
-	va_start(arg, fmt);
-	vfprintf(stderr, fmt, arg);
-	va_end(arg);
-}
-
-// xsetenv sets the environment variable $name to the given value.
-void
-xsetenv(char *name, char *value)
-{
-	setenv(name, value, 1);
-}
-
-// main takes care of OS-specific startup and dispatches to xmain.
-int
-main(int argc, char **argv)
-{
-	Buf b;
-	int osx;
-	struct utsname u;
-
-	setvbuf(stdout, nil, _IOLBF, 0);
-	setvbuf(stderr, nil, _IOLBF, 0);
-
-	setenv("TERM", "dumb", 1); // disable escape codes in clang errors
-
-	binit(&b);
-	
-	slash = "/";
-
-#if defined(__APPLE__)
-	gohostos = "darwin";
-	// Even on 64-bit platform, darwin uname -m prints i386.
-	run(&b, nil, 0, "sysctl", "machdep.cpu.extfeatures", nil);
-	if(contains(bstr(&b), "EM64T"))
-		gohostarch = "amd64";
-#elif defined(__linux__)
-	gohostos = "linux";
-#elif defined(__DragonFly__)
-	gohostos = "dragonfly";
-#elif defined(__FreeBSD__)
-	gohostos = "freebsd";
-#elif defined(__FreeBSD_kernel__)
-	// detect debian/kFreeBSD. 
-	// http://wiki.debian.org/Debian_GNU/kFreeBSD_FAQ#Q._How_do_I_detect_kfreebsd_with_preprocessor_directives_in_a_C_program.3F
-	gohostos = "freebsd";	
-#elif defined(__OpenBSD__)
-	gohostos = "openbsd";
-#elif defined(__NetBSD__)
-	gohostos = "netbsd";
-#elif defined(__sun) && defined(__SVR4)
-	gohostos = "solaris";
-	// Even on 64-bit platform, solaris uname -m prints i86pc.
-	run(&b, nil, 0, "isainfo", "-n", nil);
-	if(contains(bstr(&b), "amd64"))
-		gohostarch = "amd64";
-	if(contains(bstr(&b), "i386"))
-		gohostarch = "386";
-#else
-	fatal("unknown operating system");
-#endif
-
-	if(gohostarch == nil) {
-		if(uname(&u) < 0)
-			fatal("uname: %s", strerror(errno));
-		if(contains(u.machine, "x86_64") || contains(u.machine, "amd64"))
-			gohostarch = "amd64";
-		else if(hassuffix(u.machine, "86"))
-			gohostarch = "386";
-		else if(contains(u.machine, "arm"))
-			gohostarch = "arm";
-		else
-			fatal("unknown architecture: %s", u.machine);
-	}
-
-	if(streq(gohostarch, "arm"))
-		maxnbg = 1;
-
-	// The OS X 10.6 linker does not support external linking mode.
-	// See golang.org/issue/5130.
-	//
-	// OS X 10.6 does not work with clang either, but OS X 10.9 requires it.
-	// It seems to work with OS X 10.8, so we default to clang for 10.8 and later.
-	// See golang.org/issue/5822.
-	//
-	// Roughly, OS X 10.N shows up as uname release (N+4),
-	// so OS X 10.6 is uname version 10 and OS X 10.8 is uname version 12.
-	if(streq(gohostos, "darwin")) {
-		if(uname(&u) < 0)
-			fatal("uname: %s", strerror(errno));
-		osx = atoi(u.release) - 4;
-		if(osx <= 6)
-			goextlinkenabled = "0";
-		if(osx >= 8)
-			defaultclang = 1;
-	}
-
-	init();
-	xmain(argc, argv);
-	bfree(&b);
-	return 0;
-}
-
-// xqsort is a wrapper for the C standard qsort.
-void
-xqsort(void *data, int n, int elemsize, int (*cmp)(const void*, const void*))
-{
-	qsort(data, n, elemsize, cmp);
-}
-
-// xstrcmp compares the NUL-terminated strings a and b.
-int
-xstrcmp(char *a, char *b)
-{
-	return strcmp(a, b);
-}
-
-// xstrstr returns a pointer to the first occurrence of b in a.
-char*
-xstrstr(char *a, char *b)
-{
-	return strstr(a, b);
-}
-
-// xstrrchr returns a pointer to the final occurrence of c in p.
-char*
-xstrrchr(char *p, int c)
-{
-	return strrchr(p, c);
-}
-
-// xsamefile reports whether f1 and f2 are the same file (or dir)
-int
-xsamefile(char *f1, char *f2)
-{
-	return streq(f1, f2); // suffice for now
-}
-
-sigjmp_buf sigill_jmpbuf;
-static void sigillhand(int);
-
-// xtryexecfunc tries to execute function f, if any illegal instruction
-// signal received in the course of executing that function, it will
-// return 0, otherwise it will return 1.
-// Some systems (notably NetBSD) will spin and spin when executing VFPv3
-// instructions on VFPv2 system (e.g. Raspberry Pi) without ever triggering
-// SIGILL, so we set a 1-second alarm to catch that case.
-int
-xtryexecfunc(void (*f)(void))
-{
-	int r;
-	r = 0;
-	signal(SIGILL, sigillhand);
-	signal(SIGALRM, sigillhand);
-	alarm(1);
-	if(sigsetjmp(sigill_jmpbuf, 1) == 0) {
-		f();
-		r = 1;
-	}
-	signal(SIGILL, SIG_DFL);
-	alarm(0);
-	signal(SIGALRM, SIG_DFL);
-	return r;
-}
-
-// SIGILL handler helper
-static void
-sigillhand(int signum)
-{
-	USED(signum);
-	siglongjmp(sigill_jmpbuf, 1);
-}
-
-static void
-__cpuid(int dst[4], int ax)
-{
-#ifdef __i386__
-	// we need to avoid ebx on i386 (esp. when -fPIC).
-	asm volatile(
-		"mov %%ebx, %%edi\n\t"
-		"cpuid\n\t"
-		"xchgl %%ebx, %%edi"
-		: "=a" (dst[0]), "=D" (dst[1]), "=c" (dst[2]), "=d" (dst[3])
-		: "0" (ax));
-#elif defined(__x86_64__)
-	asm volatile("cpuid"
-		: "=a" (dst[0]), "=b" (dst[1]), "=c" (dst[2]), "=d" (dst[3])
-		: "0" (ax));
-#else
-	dst[0] = dst[1] = dst[2] = dst[3] = 0;
-#endif
-}
-
-bool
-cansse2(void)
-{
-	int info[4];
-	
-	__cpuid(info, 1);
-	return (info[3] & (1<<26)) != 0;	// SSE2
-}
-
-#endif // PLAN9
-#endif // __WINDOWS__
diff --git a/src/cmd/dist/util.go b/src/cmd/dist/util.go
new file mode 100644
index 0000000..f13210f
--- /dev/null
+++ b/src/cmd/dist/util.go
@@ -0,0 +1,559 @@
+// 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.
+
+package main
+
+import (
+	"bytes"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"runtime"
+	"sort"
+	"strconv"
+	"strings"
+	"sync"
+	"sync/atomic"
+	"time"
+)
+
+// pathf is fmt.Sprintf for generating paths
+// (on windows it turns / into \ after the printf).
+func pathf(format string, args ...interface{}) string {
+	return filepath.Clean(fmt.Sprintf(format, args...))
+}
+
+// filter returns a slice containing the elements x from list for which f(x) == true.
+func filter(list []string, f func(string) bool) []string {
+	var out []string
+	for _, x := range list {
+		if f(x) {
+			out = append(out, x)
+		}
+	}
+	return out
+}
+
+// uniq returns a sorted slice containing the unique elements of list.
+func uniq(list []string) []string {
+	out := make([]string, len(list))
+	copy(out, list)
+	sort.Strings(out)
+	keep := out[:0]
+	for _, x := range out {
+		if len(keep) == 0 || keep[len(keep)-1] != x {
+			keep = append(keep, x)
+		}
+	}
+	return keep
+}
+
+// splitlines returns a slice with the result of splitting
+// the input p after each \n.
+func splitlines(p string) []string {
+	return strings.SplitAfter(p, "\n")
+}
+
+// splitfields replaces the vector v with the result of splitting
+// the input p into non-empty fields containing no spaces.
+func splitfields(p string) []string {
+	return strings.Fields(p)
+}
+
+const (
+	CheckExit = 1 << iota
+	ShowOutput
+	Background
+)
+
+var outputLock sync.Mutex
+
+// run runs the command line cmd in dir.
+// If mode has ShowOutput set, run collects cmd's output and returns it as a string;
+// otherwise, run prints cmd's output to standard output after the command finishes.
+// If mode has CheckExit set and the command fails, run calls fatal.
+// If mode has Background set, this command is being run as a
+// Background job. Only bgrun should use the Background mode,
+// not other callers.
+func run(dir string, mode int, cmd ...string) string {
+	if vflag > 1 {
+		errprintf("run: %s\n", strings.Join(cmd, " "))
+	}
+
+	xcmd := exec.Command(cmd[0], cmd[1:]...)
+	xcmd.Dir = dir
+	var data []byte
+	var err error
+
+	// If we want to show command output and this is not
+	// a background command, assume it's the only thing
+	// running, so we can just let it write directly stdout/stderr
+	// as it runs without fear of mixing the output with some
+	// other command's output. Not buffering lets the output
+	// appear as it is printed instead of once the command exits.
+	// This is most important for the invocation of 'go1.4 build -v bootstrap/...'.
+	if mode&(Background|ShowOutput) == ShowOutput {
+		xcmd.Stdout = os.Stdout
+		xcmd.Stderr = os.Stderr
+		err = xcmd.Run()
+	} else {
+		data, err = xcmd.CombinedOutput()
+	}
+	if err != nil && mode&CheckExit != 0 {
+		outputLock.Lock()
+		if len(data) > 0 {
+			xprintf("%s\n", data)
+		}
+		outputLock.Unlock()
+		if mode&Background != 0 {
+			bgdied.Done()
+		}
+		fatal("FAILED: %v: %v", strings.Join(cmd, " "), err)
+	}
+	if mode&ShowOutput != 0 {
+		outputLock.Lock()
+		os.Stdout.Write(data)
+		outputLock.Unlock()
+	}
+	if vflag > 2 {
+		errprintf("run: %s DONE\n", strings.Join(cmd, " "))
+	}
+	return string(data)
+}
+
+var maxbg = 4 /* maximum number of jobs to run at once */
+
+var (
+	bgwork = make(chan func(), 1e5)
+	bgdone = make(chan struct{}, 1e5)
+
+	bgdied sync.WaitGroup
+	nwork  int32
+	ndone  int32
+
+	dying  = make(chan bool)
+	nfatal int32
+)
+
+func bginit() {
+	bgdied.Add(maxbg)
+	for i := 0; i < maxbg; i++ {
+		go bghelper()
+	}
+}
+
+func bghelper() {
+	for {
+		w := <-bgwork
+		w()
+
+		// Stop if we're dying.
+		if atomic.LoadInt32(&nfatal) > 0 {
+			bgdied.Done()
+			return
+		}
+	}
+}
+
+// bgrun is like run but runs the command in the background.
+// CheckExit|ShowOutput mode is implied (since output cannot be returned).
+func bgrun(dir string, cmd ...string) {
+	bgwork <- func() {
+		run(dir, CheckExit|ShowOutput|Background, cmd...)
+	}
+}
+
+// bgwait waits for pending bgruns to finish.
+// bgwait must be called from only a single goroutine at a time.
+func bgwait() {
+	var wg sync.WaitGroup
+	wg.Add(maxbg)
+	done := make(chan bool)
+	for i := 0; i < maxbg; i++ {
+		bgwork <- func() {
+			wg.Done()
+
+			// Hold up bg goroutine until either the wait finishes
+			// or the program starts dying due to a call to fatal.
+			select {
+			case <-dying:
+			case <-done:
+			}
+		}
+	}
+	wg.Wait()
+	close(done)
+}
+
+// xgetwd returns the current directory.
+func xgetwd() string {
+	wd, err := os.Getwd()
+	if err != nil {
+		fatal("%s", err)
+	}
+	return wd
+}
+
+// xrealwd returns the 'real' name for the given path.
+// real is defined as what xgetwd returns in that directory.
+func xrealwd(path string) string {
+	old := xgetwd()
+	if err := os.Chdir(path); err != nil {
+		fatal("chdir %s: %v", path, err)
+	}
+	real := xgetwd()
+	if err := os.Chdir(old); err != nil {
+		fatal("chdir %s: %v", old, err)
+	}
+	return real
+}
+
+// isdir reports whether p names an existing directory.
+func isdir(p string) bool {
+	fi, err := os.Stat(p)
+	return err == nil && fi.IsDir()
+}
+
+// isfile reports whether p names an existing file.
+func isfile(p string) bool {
+	fi, err := os.Stat(p)
+	return err == nil && fi.Mode().IsRegular()
+}
+
+// mtime returns the modification time of the file p.
+func mtime(p string) time.Time {
+	fi, err := os.Stat(p)
+	if err != nil {
+		return time.Time{}
+	}
+	return fi.ModTime()
+}
+
+// isabs reports whether p is an absolute path.
+func isabs(p string) bool {
+	return filepath.IsAbs(p)
+}
+
+// readfile returns the content of the named file.
+func readfile(file string) string {
+	data, err := ioutil.ReadFile(file)
+	if err != nil {
+		fatal("%v", err)
+	}
+	return string(data)
+}
+
+const (
+	writeExec = 1 << iota
+	writeSkipSame
+)
+
+// writefile writes b to the named file, creating it if needed.
+// if exec is non-zero, marks the file as executable.
+// If the file already exists and has the expected content,
+// it is not rewritten, to avoid changing the time stamp.
+func writefile(b, file string, flag int) {
+	new := []byte(b)
+	if flag&writeSkipSame != 0 {
+		old, err := ioutil.ReadFile(file)
+		if err == nil && bytes.Equal(old, new) {
+			return
+		}
+	}
+	mode := os.FileMode(0666)
+	if flag&writeExec != 0 {
+		mode = 0777
+	}
+	err := ioutil.WriteFile(file, new, mode)
+	if err != nil {
+		fatal("%v", err)
+	}
+}
+
+// xmkdir creates the directory p.
+func xmkdir(p string) {
+	err := os.Mkdir(p, 0777)
+	if err != nil {
+		fatal("%v", err)
+	}
+}
+
+// xmkdirall creates the directory p and its parents, as needed.
+func xmkdirall(p string) {
+	err := os.MkdirAll(p, 0777)
+	if err != nil {
+		fatal("%v", err)
+	}
+}
+
+// xremove removes the file p.
+func xremove(p string) {
+	if vflag > 2 {
+		errprintf("rm %s\n", p)
+	}
+	os.Remove(p)
+}
+
+// xremoveall removes the file or directory tree rooted at p.
+func xremoveall(p string) {
+	if vflag > 2 {
+		errprintf("rm -r %s\n", p)
+	}
+	os.RemoveAll(p)
+}
+
+// xreaddir replaces dst with a list of the names of the files and subdirectories in dir.
+// The names are relative to dir; they are not full paths.
+func xreaddir(dir string) []string {
+	f, err := os.Open(dir)
+	if err != nil {
+		fatal("%v", err)
+	}
+	defer f.Close()
+	names, err := f.Readdirnames(-1)
+	if err != nil {
+		fatal("reading %s: %v", dir, err)
+	}
+	return names
+}
+
+// xreaddir replaces dst with a list of the names of the files in dir.
+// The names are relative to dir; they are not full paths.
+func xreaddirfiles(dir string) []string {
+	f, err := os.Open(dir)
+	if err != nil {
+		fatal("%v", err)
+	}
+	defer f.Close()
+	infos, err := f.Readdir(-1)
+	if err != nil {
+		fatal("reading %s: %v", dir, err)
+	}
+	var names []string
+	for _, fi := range infos {
+		if !fi.IsDir() {
+			names = append(names, fi.Name())
+		}
+	}
+	return names
+}
+
+// xworkdir creates a new temporary directory to hold object files
+// and returns the name of that directory.
+func xworkdir() string {
+	name, err := ioutil.TempDir("", "go-tool-dist-")
+	if err != nil {
+		fatal("%v", err)
+	}
+	return name
+}
+
+// fatal prints an error message to standard error and exits.
+func fatal(format string, args ...interface{}) {
+	fmt.Fprintf(os.Stderr, "go tool dist: %s\n", fmt.Sprintf(format, args...))
+
+	// Wait for background goroutines to finish,
+	// so that exit handler that removes the work directory
+	// is not fighting with active writes or open files.
+	if atomic.AddInt32(&nfatal, 1) == 1 {
+		close(dying)
+	}
+	for i := 0; i < maxbg; i++ {
+		bgwork <- func() {} // wake up workers so they notice nfatal > 0
+	}
+	bgdied.Wait()
+
+	xexit(2)
+}
+
+var atexits []func()
+
+// xexit exits the process with return code n.
+func xexit(n int) {
+	for i := len(atexits) - 1; i >= 0; i-- {
+		atexits[i]()
+	}
+	os.Exit(n)
+}
+
+// xatexit schedules the exit-handler f to be run when the program exits.
+func xatexit(f func()) {
+	atexits = append(atexits, f)
+}
+
+// xprintf prints a message to standard output.
+func xprintf(format string, args ...interface{}) {
+	fmt.Printf(format, args...)
+}
+
+// errprintf prints a message to standard output.
+func errprintf(format string, args ...interface{}) {
+	fmt.Fprintf(os.Stderr, format, args...)
+}
+
+// main takes care of OS-specific startup and dispatches to xmain.
+func main() {
+	os.Setenv("TERM", "dumb") // disable escape codes in clang errors
+
+	slash = string(filepath.Separator)
+
+	gohostos = runtime.GOOS
+	switch gohostos {
+	case "darwin":
+		// Even on 64-bit platform, darwin uname -m prints i386.
+		if strings.Contains(run("", CheckExit, "sysctl", "machdep.cpu.extfeatures"), "EM64T") {
+			gohostarch = "amd64"
+		}
+	case "solaris":
+		// Even on 64-bit platform, solaris uname -m prints i86pc.
+		out := run("", CheckExit, "isainfo", "-n")
+		if strings.Contains(out, "amd64") {
+			gohostarch = "amd64"
+		}
+		if strings.Contains(out, "i386") {
+			gohostarch = "386"
+		}
+	case "plan9":
+		gohostarch = os.Getenv("objtype")
+		if gohostarch == "" {
+			fatal("$objtype is unset")
+		}
+	case "windows":
+		exe = ".exe"
+	}
+
+	sysinit()
+
+	if gohostarch == "" {
+		// Default Unix system.
+		out := run("", CheckExit, "uname", "-m")
+		switch {
+		case strings.Contains(out, "x86_64"), strings.Contains(out, "amd64"):
+			gohostarch = "amd64"
+		case strings.Contains(out, "86"):
+			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"):
+			gohostarch = "ppc64"
+		case gohostos == "darwin":
+			if strings.Contains(run("", CheckExit, "uname", "-v"), "RELEASE_ARM_") {
+				gohostarch = "arm"
+			}
+		default:
+			fatal("unknown architecture: %s", out)
+		}
+	}
+
+	if gohostarch == "arm" {
+		maxbg = min(maxbg, runtime.NumCPU())
+	}
+	bginit()
+
+	// The OS X 10.6 linker does not support external linking mode.
+	// See golang.org/issue/5130.
+	//
+	// OS X 10.6 does not work with clang either, but OS X 10.9 requires it.
+	// It seems to work with OS X 10.8, so we default to clang for 10.8 and later.
+	// See golang.org/issue/5822.
+	//
+	// Roughly, OS X 10.N shows up as uname release (N+4),
+	// so OS X 10.6 is uname version 10 and OS X 10.8 is uname version 12.
+	if gohostos == "darwin" {
+		rel := run("", CheckExit, "uname", "-r")
+		if i := strings.Index(rel, "."); i >= 0 {
+			rel = rel[:i]
+		}
+		osx, _ := strconv.Atoi(rel)
+		if osx <= 6+4 {
+			goextlinkenabled = "0"
+		}
+		if osx >= 8+4 {
+			defaultclang = true
+		}
+	}
+
+	xinit()
+	xmain()
+	xexit(0)
+}
+
+// xsamefile reports whether f1 and f2 are the same file (or dir)
+func xsamefile(f1, f2 string) bool {
+	fi1, err1 := os.Stat(f1)
+	fi2, err2 := os.Stat(f2)
+	if err1 != nil || err2 != nil {
+		return f1 == f2
+	}
+	return os.SameFile(fi1, fi2)
+}
+
+func xgetgoarm() string {
+	if goos == "nacl" {
+		// NaCl guarantees VFPv3 and is always cross-compiled.
+		return "7"
+	}
+	if goos == "darwin" {
+		// Assume all darwin/arm devices are have VFPv3. This
+		// port is also mostly cross-compiled, so it makes little
+		// sense to auto-detect the setting.
+		return "7"
+	}
+	if gohostarch != "arm" || goos != gohostos {
+		// Conservative default for cross-compilation.
+		return "5"
+	}
+	if goos == "freebsd" || goos == "openbsd" {
+		// FreeBSD has broken VFP support.
+		// OpenBSD currently only supports softfloat.
+		return "5"
+	}
+	if goos != "linux" {
+		// All other arm platforms that we support
+		// require ARMv7.
+		return "7"
+	}
+	cpuinfo := readfile("/proc/cpuinfo")
+	goarm := "5"
+	for _, line := range splitlines(cpuinfo) {
+		line := strings.SplitN(line, ":", 2)
+		if len(line) < 2 {
+			continue
+		}
+		if strings.TrimSpace(line[0]) != "Features" {
+			continue
+		}
+		features := splitfields(line[1])
+		sort.Strings(features) // so vfpv3 sorts after vfp
+
+		// Infer GOARM value from the vfp features available
+		// on this host. Values of GOARM detected are:
+		// 5: no vfp support was found
+		// 6: vfp (v1) support was detected, but no higher
+		// 7: vfpv3 support was detected.
+		// This matches the assertions in runtime.checkarm.
+		for _, f := range features {
+			switch f {
+			case "vfp":
+				goarm = "6"
+			case "vfpv3":
+				goarm = "7"
+			}
+		}
+	}
+	return goarm
+}
+
+func min(a, b int) int {
+	if a < b {
+		return a
+	}
+	return b
+}
diff --git a/src/cmd/dist/util_gc.go b/src/cmd/dist/util_gc.go
new file mode 100644
index 0000000..9f6cfd0
--- /dev/null
+++ b/src/cmd/dist/util_gc.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.
+
+// +build !gccgo
+
+package main
+
+func cpuid(info *[4]uint32, ax uint32)
+
+func cansse2() bool {
+	if gohostarch != "386" && gohostarch != "amd64" {
+		return false
+	}
+
+	var info [4]uint32
+	cpuid(&info, 1)
+	return info[3]&(1<<26) != 0 // SSE2
+}
diff --git a/src/cmd/dist/util_gccgo.go b/src/cmd/dist/util_gccgo.go
new file mode 100644
index 0000000..14ac70b
--- /dev/null
+++ b/src/cmd/dist/util_gccgo.go
@@ -0,0 +1,20 @@
+// 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 gccgo
+
+package main
+
+/*
+int supports_sse2() {
+#if defined(__i386__) || defined(__x86_64__)
+	return __builtin_cpu_supports("sse2");
+#else
+	return 0;
+#endif
+}
+*/
+import "C"
+
+func cansse2() bool { return C.supports_sse2() != 0 }
diff --git a/src/cmd/dist/windows.c b/src/cmd/dist/windows.c
deleted file mode 100644
index ff1a273..0000000
--- a/src/cmd/dist/windows.c
+++ /dev/null
@@ -1,989 +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.
-
-// These #ifdefs are being used as a substitute for
-// build configuration, so that on any system, this
-// tool can be built with the local equivalent of
-//	cc *.c
-//
-#ifdef WIN32
-
-// Portability layer implemented for Windows.
-// See unix.c for doc comments about exported functions.
-
-#include "a.h"
-#include <windows.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-
-/*
- * Windows uses 16-bit rune strings in the APIs.
- * Define conversions between Rune* and UTF-8 char*.
- */
-
-typedef unsigned char uchar;
-typedef unsigned short Rune;  // same as Windows
-
-// encoderune encodes the rune r into buf and returns
-// the number of bytes used.
-static int
-encoderune(char *buf, Rune r)
-{
-	if(r < 0x80) {  // 7 bits
-		buf[0] = r;
-		return 1;
-	}
-	if(r < 0x800) {  // 5+6 bits
-		buf[0] = 0xc0 | (r>>6);
-		buf[1] = 0x80 | (r&0x3f);
-		return 2;
-	}
-	buf[0] = 0xe0 | (r>>12);
-	buf[1] = 0x80 | ((r>>6)&0x3f);
-	buf[2] = 0x80 | (r&0x3f);
-	return 3;
-}
-
-// decoderune decodes the rune encoding at sbuf into r
-// and returns the number of bytes used.
-static int
-decoderune(Rune *r, char *sbuf)
-{
-	uchar *buf;
-
-	buf = (uchar*)sbuf;
-	if(buf[0] < 0x80) {
-		*r = buf[0];
-		return 1;
-	}
-	if((buf[0]&0xe0) == 0xc0 && (buf[1]&0xc0) == 0x80) {
-		*r = (buf[0]&~0xc0)<<6 | (buf[1]&~0x80);
-		if(*r < 0x80)
-			goto err;
-		return 2;
-	}
-	if((buf[0]&0xf0) == 0xe0 && (buf[1]&0xc0) == 0x80 && (buf[2]&0xc0) == 0x80) {
-		*r = (buf[0]&~0xc0)<<12 | (buf[1]&~0x80)<<6 | (buf[2]&~0x80);
-		if(*r < 0x800)
-			goto err;
-		return 3;
-	}
-err:
-	*r = 0xfffd;
-	return 1;
-}
-
-// toutf replaces b with the UTF-8 encoding of the rune string r.	
-static void
-toutf(Buf *b, Rune *r)
-{
-	int i, n;
-	char buf[4];
-
-	breset(b);
-	for(i=0; r[i]; i++) {
-		n = encoderune(buf, r[i]);
-		bwrite(b, buf, n);
-	}
-}
-
-// torune replaces *rp with a pointer to a newly allocated
-// rune string equivalent of the UTF-8 string p.
-static void
-torune(Rune **rp, char *p)
-{
-	Rune *r, *w;
-
-	r = xmalloc((strlen(p)+1) * sizeof r[0]);
-	w = r;
-	while(*p)
-		p += decoderune(w++, p);
-	*w = 0;
-	*rp = r;
-}
-
-// errstr returns the most recent Windows error, in string form.
-static char*
-errstr(void)
-{
-	DWORD code;
-	Rune *r;
-	Buf b;
-
-	binit(&b);
-	code = GetLastError();
-	r = nil;
-	FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
-		nil, code, 0, (Rune*)&r, 0, nil);
-	toutf(&b, r);
-	return bstr(&b);  // leak but we're dying anyway
-}
-
-void
-xgetenv(Buf *b, char *name)
-{
-	Rune *buf;
-	int n;
-	Rune *r;
-
-	breset(b);
-	torune(&r, name);
-	n = GetEnvironmentVariableW(r, NULL, 0);
-	if(n > 0) {
-		buf = xmalloc((n+1)*sizeof buf[0]);
-		GetEnvironmentVariableW(r, buf, n+1);
-		buf[n] = '\0';
-		toutf(b, buf);
-		xfree(buf);
-	}
-	xfree(r);
-}
-
-void
-xsetenv(char *name, char *value)
-{
-	Rune *rname, *rvalue;
-
-	torune(&rname, name);
-	torune(&rvalue, value);
-	SetEnvironmentVariableW(rname, rvalue);
-	xfree(rname);
-	xfree(rvalue);
-}
-
-char*
-bprintf(Buf *b, char *fmt, ...)
-{
-	va_list arg;
-	char buf[4096];
-	
-	breset(b);
-	va_start(arg, fmt);
-	vsnprintf(buf, sizeof buf, fmt, arg);
-	va_end(arg);
-	bwritestr(b, buf);
-	return bstr(b);
-}
-
-void
-bwritef(Buf *b, char *fmt, ...)
-{
-	va_list arg;
-	char buf[4096];
-	
-	// no reset
-	va_start(arg, fmt);
-	vsnprintf(buf, sizeof buf, fmt, arg);
-	va_end(arg);
-	bwritestr(b, buf);
-}
-
-// bpathf is like bprintf but replaces / with \ in the result,
-// to make it a canonical windows file path.
-char*
-bpathf(Buf *b, char *fmt, ...)
-{
-	int i;
-	va_list arg;
-	char buf[4096];
-	
-	breset(b);
-	va_start(arg, fmt);
-	vsnprintf(buf, sizeof buf, fmt, arg);
-	va_end(arg);
-	bwritestr(b, buf);
-
-	for(i=0; i<b->len; i++)
-		if(b->p[i] == '/')
-			b->p[i] = '\\';
-
-	return bstr(b);
-}
-
-
-static void
-breadfrom(Buf *b, HANDLE h)
-{
-	DWORD n;
-
-	for(;;) {
-		if(b->len > 1<<22)
-			fatal("unlikely file size in readfrom");
-		bgrow(b, 4096);
-		n = 0;
-		if(!ReadFile(h, b->p+b->len, 4096, &n, nil)) {
-			// Happens for pipe reads.
-			break;
-		}
-		if(n == 0)
-			break;
-		b->len += n;
-	}
-}
-
-void
-run(Buf *b, char *dir, int mode, char *cmd, ...)
-{
-	va_list arg;
-	Vec argv;
-	char *p;
-	
-	vinit(&argv);
-	vadd(&argv, cmd);
-	va_start(arg, cmd);
-	while((p = va_arg(arg, char*)) != nil)
-		vadd(&argv, p);
-	va_end(arg);
-	
-	runv(b, dir, mode, &argv);
-	
-	vfree(&argv);
-}
-
-static void genrun(Buf*, char*, int, Vec*, int);
-
-void
-runv(Buf *b, char *dir, int mode, Vec *argv)
-{
-	genrun(b, dir, mode, argv, 1);
-}
-
-void
-bgrunv(char *dir, int mode, Vec *argv)
-{
-	genrun(nil, dir, mode, argv, 0);
-}
-
-#define MAXBG 4 /* maximum number of jobs to run at once */
-
-static struct {
-	PROCESS_INFORMATION pi;
-	int mode;
-	char *cmd;
-} bg[MAXBG];
-
-static int nbg;
-
-static void bgwait1(void);
-
-static void
-genrun(Buf *b, char *dir, int mode, Vec *argv, int wait)
-{
-	// Another copy of this logic is in ../../lib9/run_windows.c.
-	// If there's a bug here, fix the logic there too.
-	int i, j, nslash;
-	Buf cmd;
-	char *q;
-	Rune *rcmd, *rexe, *rdir;
-	STARTUPINFOW si;
-	PROCESS_INFORMATION pi;
-	HANDLE p[2];
-
-	while(nbg >= nelem(bg))
-		bgwait1();
-
-	binit(&cmd);
-
-	for(i=0; i<argv->len; i++) {
-		q = argv->p[i];
-		if(i == 0 && streq(q, "hg"))
-			bwritestr(&cmd, "cmd.exe /c ");
-		if(i > 0)
-			bwritestr(&cmd, " ");
-		if(contains(q, " ") || contains(q, "\t") || contains(q, "\"") || contains(q, "\\\\") || hassuffix(q, "\\")) {
-			bwritestr(&cmd, "\"");
-			nslash = 0;
-			for(; *q; q++) {
-				if(*q == '\\') {
-					nslash++;
-					continue;
-				}
-				if(*q == '"') {
-					for(j=0; j<2*nslash+1; j++)
-						bwritestr(&cmd, "\\");
-					nslash = 0;
-				}
-				for(j=0; j<nslash; j++)
-					bwritestr(&cmd, "\\");
-				nslash = 0;
-				bwrite(&cmd, q, 1);
-			}
-			for(j=0; j<2*nslash; j++)
-				bwritestr(&cmd, "\\");
-			bwritestr(&cmd, "\"");
-		} else {
-			bwritestr(&cmd, q);
-		}
-	}
-	if(vflag > 1)
-		errprintf("%s\n", bstr(&cmd));
-
-	torune(&rcmd, bstr(&cmd));
-	rexe = nil;
-	rdir = nil;
-	if(dir != nil)
-		torune(&rdir, dir);
-
-	memset(&si, 0, sizeof si);
-	si.cb = sizeof si;
-	si.dwFlags = STARTF_USESTDHANDLES;
-	si.hStdInput = INVALID_HANDLE_VALUE;
-	if(b == nil) {
-		si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
-		si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
-	} else {
-		SECURITY_ATTRIBUTES seci;
-
-		memset(&seci, 0, sizeof seci);
-		seci.nLength = sizeof seci;
-		seci.bInheritHandle = 1;
-		breset(b);
-		if(!CreatePipe(&p[0], &p[1], &seci, 0))
-			fatal("CreatePipe: %s", errstr());
-		si.hStdOutput = p[1];
-		si.hStdError = p[1];
-	}
-
-	if(!CreateProcessW(rexe, rcmd, nil, nil, TRUE, 0, nil, rdir, &si, &pi)) {
-		if(mode!=CheckExit)
-			return;
-		fatal("%s: %s", argv->p[0], errstr());
-	}
-	if(rexe != nil)
-		xfree(rexe);
-	xfree(rcmd);
-	if(rdir != nil)
-		xfree(rdir);
-	if(b != nil) {
-		CloseHandle(p[1]);
-		breadfrom(b, p[0]);
-		CloseHandle(p[0]);
-	}
-
-	if(nbg < 0)
-		fatal("bad bookkeeping");
-	bg[nbg].pi = pi;
-	bg[nbg].mode = mode;
-	bg[nbg].cmd = btake(&cmd);
-	nbg++;
-
-	if(wait)
-		bgwait();
-
-	bfree(&cmd);
-}
-
-// closes the background job for bgwait1
-static void
-bgwaitclose(int i)
-{
-	if(i < 0 || i >= nbg)
-		return;
-
-	CloseHandle(bg[i].pi.hProcess);
-	CloseHandle(bg[i].pi.hThread);
-	
-	bg[i] = bg[--nbg];
-}
-
-// bgwait1 waits for a single background job
-static void
-bgwait1(void)
-{
-	int i, mode;
-	char *cmd;
-	HANDLE bgh[MAXBG];
-	DWORD code;
-
-	if(nbg == 0)
-		fatal("bgwait1: nothing left");
-
-	for(i=0; i<nbg; i++)
-		bgh[i] = bg[i].pi.hProcess;
-	i = WaitForMultipleObjects(nbg, bgh, FALSE, INFINITE);
-	if(i < 0 || i >= nbg)
-		fatal("WaitForMultipleObjects: %s", errstr());
-
-	cmd = bg[i].cmd;
-	mode = bg[i].mode;
-	if(!GetExitCodeProcess(bg[i].pi.hProcess, &code)) {
-		bgwaitclose(i);
-		fatal("GetExitCodeProcess: %s", errstr());
-		return;
-	}
-
-	if(mode==CheckExit && code != 0) {
-		bgwaitclose(i);
-		fatal("FAILED: %s", cmd);
-		return;
-	}
-
-	bgwaitclose(i);
-}
-
-void
-bgwait(void)
-{
-	while(nbg > 0)
-		bgwait1();
-}
-
-// rgetwd returns a rune string form of the current directory's path.
-static Rune*
-rgetwd(void)
-{
-	int n;
-	Rune *r;
-
-	n = GetCurrentDirectoryW(0, nil);
-	r = xmalloc((n+1)*sizeof r[0]);
-	GetCurrentDirectoryW(n+1, r);
-	r[n] = '\0';
-	return r;
-}
-
-void
-xgetwd(Buf *b)
-{
-	Rune *r;
-
-	r = rgetwd();
-	breset(b);
-	toutf(b, r);
-	xfree(r);
-}
-
-void
-xrealwd(Buf *b, char *path)
-{
-	Rune *old;
-	Rune *rnew;
-
-	old = rgetwd();
-	torune(&rnew, path);
-	if(!SetCurrentDirectoryW(rnew))
-		fatal("chdir %s: %s", path, errstr());
-	xfree(rnew);
-	xgetwd(b);
-	if(!SetCurrentDirectoryW(old)) {
-		breset(b);
-		toutf(b, old);
-		fatal("chdir %s: %s", bstr(b), errstr());
-	}
-}
-
-bool
-isdir(char *p)
-{
-	DWORD attr;
-	Rune *r;
-
-	torune(&r, p);
-	attr = GetFileAttributesW(r);
-	xfree(r);
-	return attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY);
-}
-
-bool
-isfile(char *p)
-{
-	DWORD attr;
-	Rune *r;
-
-	torune(&r, p);
-	attr = GetFileAttributesW(r);
-	xfree(r);
-	return attr != INVALID_FILE_ATTRIBUTES && !(attr & FILE_ATTRIBUTE_DIRECTORY);
-}
-
-Time
-mtime(char *p)
-{
-	HANDLE h;
-	WIN32_FIND_DATAW data;
-	Rune *r;
-	FILETIME *ft;
-
-	torune(&r, p);
-	h = FindFirstFileW(r, &data);
-	xfree(r);
-	if(h == INVALID_HANDLE_VALUE)
-		return 0;
-	FindClose(h);
-	ft = &data.ftLastWriteTime;
-	return (Time)ft->dwLowDateTime + ((Time)ft->dwHighDateTime<<32);
-}
-
-bool
-isabs(char *p)
-{
-	// c:/ or c:\ at beginning
-	if(('A' <= p[0] && p[0] <= 'Z') || ('a' <= p[0] && p[0] <= 'z'))
-		return p[1] == ':' && (p[2] == '/' || p[2] == '\\');
-	// / or \ at beginning
-	return p[0] == '/' || p[0] == '\\';
-}
-
-void
-readfile(Buf *b, char *file)
-{
-	HANDLE h;
-	Rune *r;
-
-	breset(b);
-	if(vflag > 2)
-		errprintf("read %s\n", file);
-	torune(&r, file);
-	h = CreateFileW(r, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
-	if(h == INVALID_HANDLE_VALUE)
-		fatal("open %s: %s", file, errstr());
-	breadfrom(b, h);
-	CloseHandle(h);
-}
-
-void
-writefile(Buf *b, char *file, int exec)
-{
-	HANDLE h;
-	Rune *r;
-	DWORD n;
-
-	USED(exec);
-
-	if(vflag > 2)
-		errprintf("write %s\n", file);
-	torune(&r, file);
-	h = CreateFileW(r, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, nil, CREATE_ALWAYS, 0, 0);
-	if(h == INVALID_HANDLE_VALUE)
-		fatal("create %s: %s", file, errstr());
-	n = 0;
-	if(!WriteFile(h, b->p, b->len, &n, 0))
-		fatal("write %s: %s", file, errstr());
-	CloseHandle(h);
-}
-	
-
-void
-xmkdir(char *p)
-{
-	Rune *r;
-
-	torune(&r, p);
-	if(!CreateDirectoryW(r, nil))
-		fatal("mkdir %s: %s", p, errstr());
-	xfree(r);
-}
-
-void
-xmkdirall(char *p)
-{
-	int c;
-	char *q, *q2;
-	
-	if(isdir(p))
-		return;
-	q = strrchr(p, '/');
-	q2 = strrchr(p, '\\');
-	if(q2 != nil && (q == nil || q < q2))
-		q = q2;
-	if(q != nil) {
-		c = *q;
-		*q = '\0';
-		xmkdirall(p);
-		*q = c;
-	}
-	xmkdir(p);
-}
-
-void
-xremove(char *p)
-{
-	int attr;
-	Rune *r;
-
-	torune(&r, p);
-	attr = GetFileAttributesW(r);
-	if(attr >= 0) {
-		if(attr & FILE_ATTRIBUTE_DIRECTORY)
-			RemoveDirectoryW(r);
-		else
-			DeleteFileW(r);
-	}
-	xfree(r);
-}
-
-void
-xreaddir(Vec *dst, char *dir)
-{
-	Rune *r;
-	Buf b;
-	HANDLE h;
-	WIN32_FIND_DATAW data;
-	char *p, *q;
-
-	binit(&b);
-	vreset(dst);
-
-	bwritestr(&b, dir);
-	bwritestr(&b, "\\*");
-	torune(&r, bstr(&b));
-
-	h = FindFirstFileW(r, &data);
-	xfree(r);
-	if(h == INVALID_HANDLE_VALUE)
-		goto out;
-	do{
-		toutf(&b, data.cFileName);
-		p = bstr(&b);
-		q = xstrrchr(p, '\\');
-		if(q != nil)
-			p = q+1;
-		if(!streq(p, ".") && !streq(p, ".."))
-			vadd(dst, p);
-	}while(FindNextFileW(h, &data));
-	FindClose(h);
-
-out:
-	bfree(&b);
-}
-
-char*
-xworkdir(void)
-{
-	Rune buf[1024];
-	Rune tmp[MAX_PATH];
-	Rune go[3] = {'g', 'o', '\0'};
-	int n;
-	Buf b;
-
-	n = GetTempPathW(nelem(buf), buf);
-	if(n <= 0)
-		fatal("GetTempPath: %s", errstr());
-	buf[n] = '\0';
-
-	if(GetTempFileNameW(buf, go, 0, tmp) == 0)
-		fatal("GetTempFileName: %s", errstr());
-	DeleteFileW(tmp);
-	if(!CreateDirectoryW(tmp, nil))
-		fatal("create tempdir: %s", errstr());
-	
-	binit(&b);
-	toutf(&b, tmp);
-	return btake(&b);
-}
-
-void
-xremoveall(char *p)
-{
-	int i;
-	Buf b;
-	Vec dir;
-	Rune *r;
-
-	binit(&b);
-	vinit(&dir);
-
-	torune(&r, p);
-	if(isdir(p)) {
-		xreaddir(&dir, p);
-		for(i=0; i<dir.len; i++) {
-			bprintf(&b, "%s/%s", p, dir.p[i]);
-			xremoveall(bstr(&b));
-		}
-		RemoveDirectoryW(r);
-	} else {
-		DeleteFileW(r);
-	}
-	xfree(r);
-	
-	bfree(&b);
-	vfree(&dir);	
-}
-
-void
-fatal(char *msg, ...)
-{
-	static char buf1[1024];
-	va_list arg;
-
-	va_start(arg, msg);
-	vsnprintf(buf1, sizeof buf1, msg, arg);
-	va_end(arg);
-
-	errprintf("go tool dist: %s\n", buf1);
-	
-	bgwait();
-	ExitProcess(1);
-}
-
-// HEAP is the persistent handle to the default process heap.
-static HANDLE HEAP = INVALID_HANDLE_VALUE;
-
-void*
-xmalloc(int n)
-{
-	void *p;
-
-	if(HEAP == INVALID_HANDLE_VALUE)
-		HEAP = GetProcessHeap();
-	p = HeapAlloc(HEAP, 0, n);
-	if(p == nil)
-		fatal("out of memory allocating %d: %s", n, errstr());
-	memset(p, 0, n);
-	return p;
-}
-
-char*
-xstrdup(char *p)
-{
-	char *q;
-
-	q = xmalloc(strlen(p)+1);
-	strcpy(q, p);
-	return q;
-}
-
-void
-xfree(void *p)
-{
-	if(HEAP == INVALID_HANDLE_VALUE)
-		HEAP = GetProcessHeap();
-	HeapFree(HEAP, 0, p);
-}
-
-void*
-xrealloc(void *p, int n)
-{
-	if(p == nil)
-		return xmalloc(n);
-	if(HEAP == INVALID_HANDLE_VALUE)
-		HEAP = GetProcessHeap();
-	p = HeapReAlloc(HEAP, 0, p, n);
-	if(p == nil)
-		fatal("out of memory reallocating %d", n);
-	return p;
-}
-
-bool
-hassuffix(char *p, char *suffix)
-{
-	int np, ns;
-
-	np = strlen(p);
-	ns = strlen(suffix);
-	return np >= ns && streq(p+np-ns, suffix);
-}
-
-bool
-hasprefix(char *p, char *prefix)
-{
-	return strncmp(p, prefix, strlen(prefix)) == 0;
-}
-
-bool
-contains(char *p, char *sep)
-{
-	return strstr(p, sep) != nil;
-}
-
-bool
-streq(char *p, char *q)
-{
-	return strcmp(p, q) == 0;
-}
-
-char*
-lastelem(char *p)
-{
-	char *out;
-
-	out = p;
-	for(; *p; p++)
-		if(*p == '/' || *p == '\\')
-			out = p+1;
-	return out;
-}
-
-void
-xmemmove(void *dst, void *src, int n)
-{
-	memmove(dst, src, n);
-}
-
-int
-xmemcmp(void *a, void *b, int n)
-{
-	return memcmp(a, b, n);
-}
-
-int
-xstrlen(char *p)
-{
-	return strlen(p);
-}
-
-void
-xexit(int n)
-{
-	ExitProcess(n);
-}
-
-void
-xatexit(void (*f)(void))
-{
-	atexit(f);
-}
-
-void
-xprintf(char *fmt, ...)
-{
-	va_list arg;
-	
-	va_start(arg, fmt);
-	vprintf(fmt, arg);
-	va_end(arg);
-}
-
-void
-errprintf(char *fmt, ...)
-{
-	va_list arg;
-	
-	va_start(arg, fmt);
-	vfprintf(stderr, fmt, arg);
-	va_end(arg);
-}
-
-int
-main(int argc, char **argv)
-{
-	SYSTEM_INFO si;
-
-	setvbuf(stdout, nil, _IOLBF, 0);
-	setvbuf(stderr, nil, _IOLBF, 0);
-
-	slash = "\\";
-	gohostos = "windows";
-
-	GetSystemInfo(&si);
-	switch(si.wProcessorArchitecture) {
-	case PROCESSOR_ARCHITECTURE_AMD64:
-		gohostarch = "amd64";
-		break;
-	case PROCESSOR_ARCHITECTURE_INTEL:
-		gohostarch = "386";
-		break;
-	default:
-		fatal("unknown processor architecture");
-	}
-
-	init();
-
-	xmain(argc, argv);
-	return 0;
-}
-
-void
-xqsort(void *data, int n, int elemsize, int (*cmp)(const void*, const void*))
-{
-	qsort(data, n, elemsize, cmp);
-}
-
-int
-xstrcmp(char *a, char *b)
-{
-	return strcmp(a, b);
-}
-
-char*
-xstrstr(char *a, char *b)
-{
-	return strstr(a, b);
-}
-
-char*
-xstrrchr(char *p, int c)
-{
-	char *ep;
-	
-	ep = p+strlen(p);
-	for(ep=p+strlen(p); ep >= p; ep--)
-		if(*ep == c)
-			return ep;
-	return nil;
-}
-
-// xsamefile reports whether f1 and f2 are the same file (or dir)
-int
-xsamefile(char *f1, char *f2)
-{
-	Rune *ru;
-	HANDLE fd1, fd2;
-	BY_HANDLE_FILE_INFORMATION fi1, fi2;
-	int r;
-
-	// trivial case
-	if(streq(f1, f2))
-		return 1;
-	
-	torune(&ru, f1);
-	// refer to ../../os/stat_windows.go:/sameFile
-	fd1 = CreateFileW(ru, 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
-	xfree(ru);
-	if(fd1 == INVALID_HANDLE_VALUE)
-		return 0;
-	torune(&ru, f2);
-	fd2 = CreateFileW(ru, 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
-	xfree(ru);
-	if(fd2 == INVALID_HANDLE_VALUE) {
-		CloseHandle(fd1);
-		return 0;
-	}
-	r = GetFileInformationByHandle(fd1, &fi1) != 0 && GetFileInformationByHandle(fd2, &fi2) != 0;
-	CloseHandle(fd2);
-	CloseHandle(fd1);
-	if(r != 0 &&
-	   fi1.dwVolumeSerialNumber == fi2.dwVolumeSerialNumber &&
-	   fi1.nFileIndexHigh == fi2.nFileIndexHigh &&
-	   fi1.nFileIndexLow == fi2.nFileIndexLow)
-	   	return 1;
-	return 0;
-}
-
-// xtryexecfunc tries to execute function f, if any illegal instruction
-// signal received in the course of executing that function, it will
-// return 0, otherwise it will return 1.
-int
-xtryexecfunc(void (*f)(void))
-{
-	return 0; // suffice for now
-}
-
-static void
-cpuid(int dst[4], int ax)
-{
-	// NOTE: This asm statement is for mingw.
-	// If we ever support MSVC, use __cpuid(dst, ax)
-	// to use the built-in.
-#if defined(__i386__) || defined(__x86_64__)
-	asm volatile("cpuid"
-		: "=a" (dst[0]), "=b" (dst[1]), "=c" (dst[2]), "=d" (dst[3])
-		: "0" (ax));
-#else
-	dst[0] = dst[1] = dst[2] = dst[3] = 0;
-#endif
-}
-
-bool
-cansse2(void)
-{
-	int info[4];
-	
-	cpuid(info, 1);
-	return (info[3] & (1<<26)) != 0;	// SSE2
-}
-
-
-#endif // __WINDOWS__
diff --git a/src/cmd/doc/doc_test.go b/src/cmd/doc/doc_test.go
new file mode 100644
index 0000000..b97cc76
--- /dev/null
+++ b/src/cmd/doc/doc_test.go
@@ -0,0 +1,348 @@
+// 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"
+	"flag"
+	"os"
+	"os/exec"
+	"regexp"
+	"runtime"
+	"testing"
+)
+
+const (
+	dataDir = "testdata"
+	binary  = "testdoc"
+)
+
+type test struct {
+	name string
+	args []string // Arguments to "[go] doc".
+	yes  []string // Regular expressions that should match.
+	no   []string // Regular expressions that should not match.
+}
+
+const p = "cmd/doc/testdata"
+
+var tests = []test{
+	// Sanity check.
+	{
+		"sanity check",
+		[]string{p},
+		[]string{`type ExportedType struct`},
+		nil,
+	},
+
+	// Package dump includes import, package statement.
+	{
+		"package clause",
+		[]string{p},
+		[]string{`package pkg.*cmd/doc/testdata`},
+		nil,
+	},
+
+	// Constants.
+	// Package dump
+	{
+		"full package",
+		[]string{p},
+		[]string{
+			`Package comment`,
+			`const ExportedConstant = 1`,                            // Simple constant.
+			`const ConstOne = 1`,                                    // First entry in constant block.
+			`var ExportedVariable = 1`,                              // Simple variable.
+			`var VarOne = 1`,                                        // First entry in variable block.
+			`func ExportedFunc\(a int\) bool`,                       // Function.
+			`type ExportedType struct { ... }`,                      // Exported type.
+			`const ExportedTypedConstant ExportedType = iota`,       // Typed constant.
+			`const ExportedTypedConstant_unexported unexportedType`, // Typed constant, exported for unexported type.
+		},
+		[]string{
+			`const internalConstant = 2`,        // No internal constants.
+			`var internalVariable = 2`,          // No internal variables.
+			`func internalFunc(a int) bool`,     // No internal functions.
+			`Comment about exported constant`,   // No comment for single constant.
+			`Comment about exported variable`,   // No comment for single variable.
+			`Comment about block of constants.`, // No comment for constant block.
+			`Comment about block of variables.`, // No comment for variable block.
+			`Comment before ConstOne`,           // No comment for first entry in constant block.
+			`Comment before VarOne`,             // No comment for first entry in variable block.
+			`ConstTwo = 2`,                      // No second entry in constant block.
+			`VarTwo = 2`,                        // No second entry in variable block.
+			`type unexportedType`,               // No unexported type.
+			`unexportedTypedConstant`,           // No unexported typed constant.
+			`Field`,                             // No fields.
+			`Method`,                            // No methods.
+		},
+	},
+	// Package dump -u
+	{
+		"full package with u",
+		[]string{`-u`, p},
+		[]string{
+			`const ExportedConstant = 1`,      // Simple constant.
+			`const internalConstant = 2`,      // Internal constants.
+			`func internalFunc\(a int\) bool`, // Internal functions.
+		},
+		[]string{
+			`Comment about exported constant`,  // No comment for simple constant.
+			`Comment about block of constants`, // No comment for constant block.
+			`Comment about internal function`,  // No comment for internal function.
+		},
+	},
+
+	// Single constant.
+	{
+		"single constant",
+		[]string{p, `ExportedConstant`},
+		[]string{
+			`Comment about exported constant`, // Include comment.
+			`const ExportedConstant = 1`,
+		},
+		nil,
+	},
+	// Single constant -u.
+	{
+		"single constant with -u",
+		[]string{`-u`, p, `internalConstant`},
+		[]string{
+			`Comment about internal constant`, // Include comment.
+			`const internalConstant = 2`,
+		},
+		nil,
+	},
+	// Block of constants.
+	{
+		"block of constants",
+		[]string{p, `ConstTwo`},
+		[]string{
+			`Comment before ConstOne.\n.*ConstOne = 1`,    // First...
+			`ConstTwo = 2.*Comment on line with ConstTwo`, // And second show up.
+			`Comment about block of constants`,            // Comment does too.
+		},
+		[]string{
+			`constThree`, // No unexported constant.
+		},
+	},
+	// Block of constants -u.
+	{
+		"block of constants with -u",
+		[]string{"-u", p, `constThree`},
+		[]string{
+			`constThree = 3.*Comment on line with constThree`,
+		},
+		nil,
+	},
+
+	// Single variable.
+	{
+		"single variable",
+		[]string{p, `ExportedVariable`},
+		[]string{
+			`ExportedVariable`, // Include comment.
+			`var ExportedVariable = 1`,
+		},
+		nil,
+	},
+	// Single variable -u.
+	{
+		"single variable with -u",
+		[]string{`-u`, p, `internalVariable`},
+		[]string{
+			`Comment about internal variable`, // Include comment.
+			`var internalVariable = 2`,
+		},
+		nil,
+	},
+	// Block of variables.
+	{
+		"block of variables",
+		[]string{p, `VarTwo`},
+		[]string{
+			`Comment before VarOne.\n.*VarOne = 1`,    // First...
+			`VarTwo = 2.*Comment on line with VarTwo`, // And second show up.
+			`Comment about block of variables`,        // Comment does too.
+		},
+		[]string{
+			`varThree= 3`, // No unexported variable.
+		},
+	},
+	// Block of variables -u.
+	{
+		"block of variables with -u",
+		[]string{"-u", p, `varThree`},
+		[]string{
+			`varThree = 3.*Comment on line with varThree`,
+		},
+		nil,
+	},
+
+	// Function.
+	{
+		"function",
+		[]string{p, `ExportedFunc`},
+		[]string{
+			`Comment about exported function`, // Include comment.
+			`func ExportedFunc\(a int\) bool`,
+		},
+		nil,
+	},
+	// Function -u.
+	{
+		"function with -u",
+		[]string{"-u", p, `internalFunc`},
+		[]string{
+			`Comment about internal function`, // Include comment.
+			`func internalFunc\(a int\) bool`,
+		},
+		nil,
+	},
+
+	// Type.
+	{
+		"type",
+		[]string{p, `ExportedType`},
+		[]string{
+			`Comment about exported type`, // Include comment.
+			`type ExportedType struct`,    // Type definition.
+			`Comment before exported field.*\n.*ExportedField +int`,
+			`Has unexported fields`,
+			`func \(ExportedType\) ExportedMethod\(a int\) bool`,
+			`const ExportedTypedConstant ExportedType = iota`, // Must include associated constant.
+			`func ExportedTypeConstructor\(\) \*ExportedType`, // Must include constructor.
+		},
+		[]string{
+			`unexportedField`,                // No unexported field.
+			`Comment about exported method.`, // No comment about exported method.
+			`unexportedMethod`,               // No unexported method.
+			`unexportedTypedConstant`,        // No unexported constant.
+		},
+	},
+	// Type -u with unexported fields.
+	{
+		"type with unexported fields and -u",
+		[]string{"-u", p, `ExportedType`},
+		[]string{
+			`Comment about exported type`, // Include comment.
+			`type ExportedType struct`,    // Type definition.
+			`Comment before exported field.*\n.*ExportedField +int`,
+			`unexportedField int.*Comment on line with unexported field.`,
+			`func \(ExportedType\) unexportedMethod\(a int\) bool`,
+			`unexportedTypedConstant`,
+		},
+		[]string{
+			`Has unexported fields`,
+		},
+	},
+	// Unexported type with -u.
+	{
+		"unexported type with -u",
+		[]string{"-u", p, `unexportedType`},
+		[]string{
+			`Comment about unexported type`, // Include comment.
+			`type unexportedType int`,       // Type definition.
+			`func \(unexportedType\) ExportedMethod\(\) bool`,
+			`func \(unexportedType\) unexportedMethod\(\) bool`,
+			`ExportedTypedConstant_unexported unexportedType = iota`,
+			`const unexportedTypedConstant unexportedType = 1`,
+		},
+		nil,
+	},
+
+	// Method.
+	{
+		"method",
+		[]string{p, `ExportedType.ExportedMethod`},
+		[]string{
+			`func \(ExportedType\) ExportedMethod\(a int\) bool`,
+			`Comment about exported method.`,
+		},
+		nil,
+	},
+	// Method  with -u.
+	{
+		"method with -u",
+		[]string{"-u", p, `ExportedType.unexportedMethod`},
+		[]string{
+			`func \(ExportedType\) unexportedMethod\(a int\) bool`,
+			`Comment about unexported method.`,
+		},
+		nil,
+	},
+
+	// Case matching off.
+	{
+		"case matching off",
+		[]string{p, `casematch`},
+		[]string{
+			`CaseMatch`,
+			`Casematch`,
+		},
+		nil,
+	},
+
+	// Case matching on.
+	{
+		"case matching on",
+		[]string{"-c", p, `Casematch`},
+		[]string{
+			`Casematch`,
+		},
+		[]string{
+			`CaseMatch`,
+		},
+	},
+}
+
+func TestDoc(t *testing.T) {
+	if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") {
+		t.Skip("TODO: on darwin/arm, test fails: no such package cmd/doc/testdata")
+	}
+	for _, test := range tests {
+		var b bytes.Buffer
+		var flagSet flag.FlagSet
+		err := do(&b, &flagSet, test.args)
+		if err != nil {
+			t.Fatalf("%s: %s\n", test.name, err)
+		}
+		output := b.Bytes()
+		failed := false
+		for j, yes := range test.yes {
+			re, err := regexp.Compile(yes)
+			if err != nil {
+				t.Fatalf("%s.%d: compiling %#q: %s", test.name, j, yes, err)
+			}
+			if !re.Match(output) {
+				t.Errorf("%s.%d: no match for %s %#q", test.name, j, test.args, yes)
+				failed = true
+			}
+		}
+		for j, no := range test.no {
+			re, err := regexp.Compile(no)
+			if err != nil {
+				t.Fatalf("%s.%d: compiling %#q: %s", test.name, j, no, err)
+			}
+			if re.Match(output) {
+				t.Errorf("%s.%d: incorrect match for %s %#q", test.name, j, test.args, no)
+				failed = true
+			}
+		}
+		if failed {
+			t.Logf("\n%s", output)
+		}
+	}
+}
+
+// run runs the command, but calls t.Fatal if there is an error.
+func run(c *exec.Cmd, t *testing.T) []byte {
+	output, err := c.CombinedOutput()
+	if err != nil {
+		os.Stdout.Write(output)
+		t.Fatal(err)
+	}
+	return output
+}
diff --git a/src/cmd/doc/main.go b/src/cmd/doc/main.go
new file mode 100644
index 0000000..dda6aec
--- /dev/null
+++ b/src/cmd/doc/main.go
@@ -0,0 +1,354 @@
+// 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.
+
+// Doc (usually run as go doc) accepts zero, one or two arguments.
+//
+// Zero arguments:
+//	go doc
+// Show the documentation for the package in the current directory.
+//
+// One argument:
+//	go doc <pkg>
+//	go doc <sym>[.<method>]
+//	go doc [<pkg>].<sym>[.<method>]
+// The first item in this list that succeeds is the one whose documentation
+// is printed. If there is a symbol but no package, the package in the current
+// directory is chosen.
+//
+// Two arguments:
+//	go doc <pkg> <sym>[.<method>]
+//
+// Show the documentation for the package, symbol, and method. The
+// first argument must be a full package path. This is similar to the
+// command-line usage for the godoc command.
+//
+// For commands, unless the -cmd flag is present "go doc command"
+// shows only the package-level docs for the package.
+//
+// For complete documentation, run "go help doc".
+package main
+
+import (
+	"flag"
+	"fmt"
+	"go/build"
+	"io"
+	"log"
+	"os"
+	"path"
+	"path/filepath"
+	"strings"
+	"unicode"
+	"unicode/utf8"
+)
+
+var (
+	unexported bool // -u flag
+	matchCase  bool // -c flag
+	showCmd    bool // -cmd flag
+)
+
+// usage is a replacement usage function for the flags package.
+func usage() {
+	fmt.Fprintf(os.Stderr, "Usage of [go] doc:\n")
+	fmt.Fprintf(os.Stderr, "\tgo doc\n")
+	fmt.Fprintf(os.Stderr, "\tgo doc <pkg>\n")
+	fmt.Fprintf(os.Stderr, "\tgo doc <sym>[.<method>]\n")
+	fmt.Fprintf(os.Stderr, "\tgo doc [<pkg>].<sym>[.<method>]\n")
+	fmt.Fprintf(os.Stderr, "\tgo doc <pkg> <sym>[.<method>]\n")
+	fmt.Fprintf(os.Stderr, "For more information run\n")
+	fmt.Fprintf(os.Stderr, "\tgo help doc\n\n")
+	fmt.Fprintf(os.Stderr, "Flags:\n")
+	flag.PrintDefaults()
+	os.Exit(2)
+}
+
+func main() {
+	log.SetFlags(0)
+	log.SetPrefix("doc: ")
+	err := do(os.Stdout, flag.CommandLine, os.Args[1:])
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+
+// do is the workhorse, broken out of main to make testing easier.
+func do(writer io.Writer, flagSet *flag.FlagSet, args []string) (err error) {
+	flagSet.Usage = usage
+	unexported = false
+	matchCase = false
+	flagSet.BoolVar(&unexported, "u", false, "show unexported symbols as well as exported")
+	flagSet.BoolVar(&matchCase, "c", false, "symbol matching honors case (paths not affected)")
+	flagSet.BoolVar(&showCmd, "cmd", false, "show symbols with package docs even if package is a command")
+	flagSet.Parse(args)
+	buildPackage, userPath, symbol := parseArgs(flagSet.Args())
+	symbol, method := parseSymbol(symbol)
+	pkg := parsePackage(writer, buildPackage, userPath)
+	defer func() {
+		pkg.flush()
+		e := recover()
+		if e == nil {
+			return
+		}
+		pkgError, ok := e.(PackageError)
+		if ok {
+			err = pkgError
+			return
+		}
+		panic(e)
+	}()
+	switch {
+	case symbol == "":
+		pkg.packageDoc()
+		return
+	case method == "":
+		pkg.symbolDoc(symbol)
+	default:
+		pkg.methodDoc(symbol, method)
+	}
+	return nil
+}
+
+// parseArgs analyzes the arguments (if any) and returns the package
+// it represents, the part of the argument the user used to identify
+// the path (or "" if it's the current package) and the symbol
+// (possibly with a .method) within that package.
+// parseSymbol is used to analyze the symbol itself.
+func parseArgs(args []string) (*build.Package, string, string) {
+	switch len(args) {
+	default:
+		usage()
+	case 0:
+		// Easy: current directory.
+		return importDir(pwd()), "", ""
+	case 1:
+		// Done below.
+	case 2:
+		// Package must be importable.
+		pkg, err := build.Import(args[0], "", build.ImportComment)
+		if err != nil {
+			log.Fatalf("%s", err)
+		}
+		return pkg, args[0], args[1]
+	}
+	// Usual case: one argument.
+	arg := args[0]
+	// If it contains slashes, it begins with a package path.
+	// First, is it a complete package path as it is? If so, we are done.
+	// This avoids confusion over package paths that have other
+	// package paths as their prefix.
+	pkg, err := build.Import(arg, "", build.ImportComment)
+	if err == nil {
+		return pkg, arg, ""
+	}
+	// Another disambiguator: If the symbol starts with an upper
+	// case letter, it can only be a symbol in the current directory.
+	// Kills the problem caused by case-insensitive file systems
+	// matching an upper case name as a package name.
+	if isUpper(arg) {
+		pkg, err := build.ImportDir(".", build.ImportComment)
+		if err == nil {
+			return pkg, "", arg
+		}
+	}
+	// If it has a slash, it must be a package path but there is a symbol.
+	// It's the last package path we care about.
+	slash := strings.LastIndex(arg, "/")
+	// There may be periods in the package path before or after the slash
+	// and between a symbol and method.
+	// Split the string at various periods to see what we find.
+	// In general there may be ambiguities but this should almost always
+	// work.
+	var period int
+	// slash+1: if there's no slash, the value is -1 and start is 0; otherwise
+	// start is the byte after the slash.
+	for start := slash + 1; start < len(arg); start = period + 1 {
+		period = strings.Index(arg[start:], ".")
+		symbol := ""
+		if period < 0 {
+			period = len(arg)
+		} else {
+			period += start
+			symbol = arg[period+1:]
+		}
+		// Have we identified a package already?
+		pkg, err := build.Import(arg[0:period], "", build.ImportComment)
+		if err == nil {
+			return pkg, arg[0:period], symbol
+		}
+		// See if we have the basename or tail of a package, as in json for encoding/json
+		// or ivy/value for robpike.io/ivy/value.
+		path := findPackage(arg[0:period])
+		if path != "" {
+			return importDir(path), arg[0:period], symbol
+		}
+	}
+	// If it has a slash, we've failed.
+	if slash >= 0 {
+		log.Fatalf("no such package %s", arg[0:period])
+	}
+	// Guess it's a symbol in the current directory.
+	return importDir(pwd()), "", arg
+}
+
+// importDir is just an error-catching wrapper for build.ImportDir.
+func importDir(dir string) *build.Package {
+	pkg, err := build.ImportDir(dir, build.ImportComment)
+	if err != nil {
+		log.Fatal(err)
+	}
+	return pkg
+}
+
+// parseSymbol breaks str apart into a symbol and method.
+// Both may be missing or the method may be missing.
+// If present, each must be a valid Go identifier.
+func parseSymbol(str string) (symbol, method string) {
+	if str == "" {
+		return
+	}
+	elem := strings.Split(str, ".")
+	switch len(elem) {
+	case 1:
+	case 2:
+		method = elem[1]
+		isIdentifier(method)
+	default:
+		log.Printf("too many periods in symbol specification")
+		usage()
+	}
+	symbol = elem[0]
+	isIdentifier(symbol)
+	return
+}
+
+// isIdentifier checks that the name is valid Go identifier, and
+// logs and exits if it is not.
+func isIdentifier(name string) {
+	if len(name) == 0 {
+		log.Fatal("empty symbol")
+	}
+	for i, ch := range name {
+		if unicode.IsLetter(ch) || ch == '_' || i > 0 && unicode.IsDigit(ch) {
+			continue
+		}
+		log.Fatalf("invalid identifier %q", name)
+	}
+}
+
+// isExported reports whether the name is an exported identifier.
+// If the unexported flag (-u) is true, isExported returns true because
+// it means that we treat the name as if it is exported.
+func isExported(name string) bool {
+	return unexported || isUpper(name)
+}
+
+// isUpper reports whether the name starts with an upper case letter.
+func isUpper(name string) bool {
+	ch, _ := utf8.DecodeRuneInString(name)
+	return unicode.IsUpper(ch)
+}
+
+// findPackage returns the full file name path specified by the
+// (perhaps partial) package path pkg.
+func findPackage(pkg string) string {
+	if pkg == "" {
+		return ""
+	}
+	if isUpper(pkg) {
+		return "" // Upper case symbol cannot be a package name.
+	}
+	path := pathFor(build.Default.GOROOT, pkg)
+	if path != "" {
+		return path
+	}
+	for _, root := range splitGopath() {
+		path = pathFor(root, pkg)
+		if path != "" {
+			return path
+		}
+	}
+	return ""
+}
+
+// splitGopath splits $GOPATH into a list of roots.
+func splitGopath() []string {
+	return filepath.SplitList(build.Default.GOPATH)
+}
+
+// pathsFor recursively walks the tree at root looking for possible directories for the package:
+// those whose package path is pkg or which have a proper suffix pkg.
+func pathFor(root, pkg string) (result string) {
+	root = path.Join(root, "src")
+	slashDot := string(filepath.Separator) + "."
+	// We put a slash on the pkg so can use simple string comparison below
+	// yet avoid inadvertent matches, like /foobar matching bar.
+	pkgString := filepath.Clean(string(filepath.Separator) + pkg)
+
+	// We use panic/defer to short-circuit processing at the first match.
+	// A nil panic reports that the path has been found.
+	defer func() {
+		err := recover()
+		if err != nil {
+			panic(err)
+		}
+	}()
+
+	visit := func(pathName string, f os.FileInfo, err error) error {
+		if err != nil {
+			return nil
+		}
+		// One package per directory. Ignore the files themselves.
+		if !f.IsDir() {
+			return nil
+		}
+		// No .git or other dot nonsense please.
+		if strings.Contains(pathName, slashDot) {
+			return filepath.SkipDir
+		}
+		// Is the tail of the path correct?
+		if strings.HasSuffix(pathName, pkgString) && hasGoFiles(pathName) {
+			result = pathName
+			panic(nil)
+		}
+		return nil
+	}
+
+	filepath.Walk(root, visit)
+	return "" // Call to panic above sets the real value.
+}
+
+// hasGoFiles tests whether the directory contains at least one file with ".go"
+// extension
+func hasGoFiles(path string) bool {
+	dir, err := os.Open(path)
+	if err != nil {
+		// ignore unreadable directories
+		return false
+	}
+	defer dir.Close()
+
+	names, err := dir.Readdirnames(0)
+	if err != nil {
+		// ignore unreadable directories
+		return false
+	}
+
+	for _, name := range names {
+		if strings.HasSuffix(name, ".go") {
+			return true
+		}
+	}
+
+	return false
+}
+
+// pwd returns the current directory.
+func pwd() string {
+	wd, err := os.Getwd()
+	if err != nil {
+		log.Fatal(err)
+	}
+	return wd
+}
diff --git a/src/cmd/doc/pkg.go b/src/cmd/doc/pkg.go
new file mode 100644
index 0000000..569c7a3
--- /dev/null
+++ b/src/cmd/doc/pkg.go
@@ -0,0 +1,552 @@
+// 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"
+	"fmt"
+	"go/ast"
+	"go/build"
+	"go/doc"
+	"go/format"
+	"go/parser"
+	"go/token"
+	"io"
+	"log"
+	"os"
+	"unicode"
+	"unicode/utf8"
+)
+
+const (
+	punchedCardWidth = 80 // These things just won't leave us alone.
+	indentedWidth    = punchedCardWidth - len(indent)
+	indent           = "    "
+)
+
+type Package struct {
+	writer     io.Writer // Destination for output.
+	name       string    // Package name, json for encoding/json.
+	userPath   string    // String the user used to find this package.
+	unexported bool
+	matchCase  bool
+	pkg        *ast.Package // Parsed package.
+	file       *ast.File    // Merged from all files in the package
+	doc        *doc.Package
+	build      *build.Package
+	fs         *token.FileSet // Needed for printing.
+	buf        bytes.Buffer
+}
+
+type PackageError string // type returned by pkg.Fatalf.
+
+func (p PackageError) Error() string {
+	return string(p)
+}
+
+// pkg.Fatalf is like log.Fatalf, but panics so it can be recovered in the
+// main do function, so it doesn't cause an exit. Allows testing to work
+// without running a subprocess. The log prefix will be added when
+// logged in main; it is not added here.
+func (pkg *Package) Fatalf(format string, args ...interface{}) {
+	panic(PackageError(fmt.Sprintf(format, args...)))
+}
+
+// parsePackage turns the build package we found into a parsed package
+// we can then use to generate documentation.
+func parsePackage(writer io.Writer, pkg *build.Package, userPath string) *Package {
+	fs := token.NewFileSet()
+	// include tells parser.ParseDir which files to include.
+	// That means the file must be in the build package's GoFiles or CgoFiles
+	// list only (no tag-ignored files, tests, swig or other non-Go files).
+	include := func(info os.FileInfo) bool {
+		for _, name := range pkg.GoFiles {
+			if name == info.Name() {
+				return true
+			}
+		}
+		for _, name := range pkg.CgoFiles {
+			if name == info.Name() {
+				return true
+			}
+		}
+		return false
+	}
+	pkgs, err := parser.ParseDir(fs, pkg.Dir, include, parser.ParseComments)
+	if err != nil {
+		log.Fatal(err)
+	}
+	// Make sure they are all in one package.
+	if len(pkgs) != 1 {
+		log.Fatalf("multiple packages in directory %s", pkg.Dir)
+	}
+	astPkg := pkgs[pkg.Name]
+
+	// TODO: go/doc does not include typed constants in the constants
+	// list, which is what we want. For instance, time.Sunday is of type
+	// time.Weekday, so it is defined in the type but not in the
+	// Consts list for the package. This prevents
+	//	go doc time.Sunday
+	// from finding the symbol. Work around this for now, but we
+	// should fix it in go/doc.
+	// A similar story applies to factory functions.
+	docPkg := doc.New(astPkg, pkg.ImportPath, doc.AllDecls)
+	for _, typ := range docPkg.Types {
+		docPkg.Consts = append(docPkg.Consts, typ.Consts...)
+		docPkg.Vars = append(docPkg.Vars, typ.Vars...)
+		docPkg.Funcs = append(docPkg.Funcs, typ.Funcs...)
+	}
+
+	return &Package{
+		writer:   writer,
+		name:     pkg.Name,
+		userPath: userPath,
+		pkg:      astPkg,
+		file:     ast.MergePackageFiles(astPkg, 0),
+		doc:      docPkg,
+		build:    pkg,
+		fs:       fs,
+	}
+}
+
+func (pkg *Package) Printf(format string, args ...interface{}) {
+	fmt.Fprintf(&pkg.buf, format, args...)
+}
+
+func (pkg *Package) flush() {
+	_, err := pkg.writer.Write(pkg.buf.Bytes())
+	if err != nil {
+		log.Fatal(err)
+	}
+	pkg.buf.Reset() // Not needed, but it's a flush.
+}
+
+var newlineBytes = []byte("\n\n") // We never ask for more than 2.
+
+// newlines guarantees there are n newlines at the end of the buffer.
+func (pkg *Package) newlines(n int) {
+	for !bytes.HasSuffix(pkg.buf.Bytes(), newlineBytes[:n]) {
+		pkg.buf.WriteRune('\n')
+	}
+}
+
+// emit prints the node.
+func (pkg *Package) emit(comment string, node ast.Node) {
+	if node != nil {
+		err := format.Node(&pkg.buf, pkg.fs, node)
+		if err != nil {
+			log.Fatal(err)
+		}
+		if comment != "" {
+			pkg.newlines(2) // Guarantee blank line before comment.
+			doc.ToText(&pkg.buf, comment, "    ", indent, indentedWidth)
+		}
+		pkg.newlines(1)
+	}
+}
+
+var formatBuf bytes.Buffer // Reusable to avoid allocation.
+
+// formatNode is a helper function for printing.
+func (pkg *Package) formatNode(node ast.Node) []byte {
+	formatBuf.Reset()
+	format.Node(&formatBuf, pkg.fs, node)
+	return formatBuf.Bytes()
+}
+
+// oneLineFunc prints a function declaration as a single line.
+func (pkg *Package) oneLineFunc(decl *ast.FuncDecl) {
+	decl.Doc = nil
+	decl.Body = nil
+	pkg.emit("", decl)
+}
+
+// oneLineValueGenDecl prints a var or const declaration as a single line.
+func (pkg *Package) oneLineValueGenDecl(decl *ast.GenDecl) {
+	decl.Doc = nil
+	dotDotDot := ""
+	if len(decl.Specs) > 1 {
+		dotDotDot = " ..."
+	}
+	// Find the first relevant spec.
+	for i, spec := range decl.Specs {
+		valueSpec := spec.(*ast.ValueSpec) // Must succeed; we can't mix types in one genDecl.
+		if !isExported(valueSpec.Names[0].Name) {
+			continue
+		}
+		typ := ""
+		if valueSpec.Type != nil {
+			typ = fmt.Sprintf(" %s", pkg.formatNode(valueSpec.Type))
+		}
+		val := ""
+		if i < len(valueSpec.Values) && valueSpec.Values[i] != nil {
+			val = fmt.Sprintf(" = %s", pkg.formatNode(valueSpec.Values[i]))
+		}
+		pkg.Printf("%s %s%s%s%s\n", decl.Tok, valueSpec.Names[0], typ, val, dotDotDot)
+		break
+	}
+}
+
+// oneLineTypeDecl prints a type declaration as a single line.
+func (pkg *Package) oneLineTypeDecl(spec *ast.TypeSpec) {
+	spec.Doc = nil
+	spec.Comment = nil
+	switch spec.Type.(type) {
+	case *ast.InterfaceType:
+		pkg.Printf("type %s interface { ... }\n", spec.Name)
+	case *ast.StructType:
+		pkg.Printf("type %s struct { ... }\n", spec.Name)
+	default:
+		pkg.Printf("type %s %s\n", spec.Name, pkg.formatNode(spec.Type))
+	}
+}
+
+// packageDoc prints the docs for the package (package doc plus one-liners of the rest).
+func (pkg *Package) packageDoc() {
+	defer pkg.flush()
+	if pkg.showInternals() {
+		pkg.packageClause(false)
+	}
+
+	doc.ToText(&pkg.buf, pkg.doc.Doc, "", indent, indentedWidth)
+	pkg.newlines(1)
+
+	if !pkg.showInternals() {
+		// Show only package docs for commands.
+		return
+	}
+
+	pkg.newlines(1)
+	pkg.valueSummary(pkg.doc.Consts)
+	pkg.valueSummary(pkg.doc.Vars)
+	pkg.funcSummary(pkg.doc.Funcs)
+	pkg.typeSummary()
+	pkg.bugs()
+}
+
+// showInternals reports whether we should show the internals
+// of a package as opposed to just the package docs.
+// Used to decide whether to suppress internals for commands.
+// Called only by Package.packageDoc.
+func (pkg *Package) showInternals() bool {
+	return pkg.pkg.Name != "main" || showCmd
+}
+
+// packageClause prints the package clause.
+// The argument boolean, if true, suppresses the output if the
+// user's argument is identical to the actual package path or
+// is empty, meaning it's the current directory.
+func (pkg *Package) packageClause(checkUserPath bool) {
+	if checkUserPath {
+		if pkg.userPath == "" || pkg.userPath == pkg.build.ImportPath {
+			return
+		}
+	}
+	importPath := pkg.build.ImportComment
+	if importPath == "" {
+		importPath = pkg.build.ImportPath
+	}
+	pkg.Printf("package %s // import %q\n\n", pkg.name, importPath)
+	if importPath != pkg.build.ImportPath {
+		pkg.Printf("WARNING: package source is installed in %q\n", pkg.build.ImportPath)
+	}
+}
+
+// valueSummary prints a one-line summary for each set of values and constants.
+func (pkg *Package) valueSummary(values []*doc.Value) {
+	for _, value := range values {
+		// Only print first item in spec, show ... to stand for the rest.
+		spec := value.Decl.Specs[0].(*ast.ValueSpec) // Must succeed.
+		exported := true
+		for _, name := range spec.Names {
+			if !isExported(name.Name) {
+				exported = false
+				break
+			}
+		}
+		if exported {
+			pkg.oneLineValueGenDecl(value.Decl)
+		}
+	}
+}
+
+// funcSummary prints a one-line summary for each function.
+func (pkg *Package) funcSummary(funcs []*doc.Func) {
+	for _, fun := range funcs {
+		decl := fun.Decl
+		// Exported functions only. The go/doc package does not include methods here.
+		if isExported(fun.Name) {
+			pkg.oneLineFunc(decl)
+		}
+	}
+}
+
+// typeSummary prints a one-line summary for each type.
+func (pkg *Package) typeSummary() {
+	for _, typ := range pkg.doc.Types {
+		for _, spec := range typ.Decl.Specs {
+			typeSpec := spec.(*ast.TypeSpec) // Must succeed.
+			if isExported(typeSpec.Name.Name) {
+				pkg.oneLineTypeDecl(typeSpec)
+			}
+		}
+	}
+}
+
+// bugs prints the BUGS information for the package.
+// TODO: Provide access to TODOs and NOTEs as well (very noisy so off by default)?
+func (pkg *Package) bugs() {
+	if pkg.doc.Notes["BUG"] == nil {
+		return
+	}
+	pkg.Printf("\n")
+	for _, note := range pkg.doc.Notes["BUG"] {
+		pkg.Printf("%s: %v\n", "BUG", note.Body)
+	}
+}
+
+// findValues finds the doc.Values that describe the symbol.
+func (pkg *Package) findValues(symbol string, docValues []*doc.Value) (values []*doc.Value) {
+	for _, value := range docValues {
+		for _, name := range value.Names {
+			if match(symbol, name) {
+				values = append(values, value)
+			}
+		}
+	}
+	return
+}
+
+// findFuncs finds the doc.Funcs that describes the symbol.
+func (pkg *Package) findFuncs(symbol string) (funcs []*doc.Func) {
+	for _, fun := range pkg.doc.Funcs {
+		if match(symbol, fun.Name) {
+			funcs = append(funcs, fun)
+		}
+	}
+	return
+}
+
+// findTypes finds the doc.Types that describes the symbol.
+// If symbol is empty, it finds all exported types.
+func (pkg *Package) findTypes(symbol string) (types []*doc.Type) {
+	for _, typ := range pkg.doc.Types {
+		if symbol == "" && isExported(typ.Name) || match(symbol, typ.Name) {
+			types = append(types, typ)
+		}
+	}
+	return
+}
+
+// findTypeSpec returns the ast.TypeSpec within the declaration that defines the symbol.
+// The name must match exactly.
+func (pkg *Package) findTypeSpec(decl *ast.GenDecl, symbol string) *ast.TypeSpec {
+	for _, spec := range decl.Specs {
+		typeSpec := spec.(*ast.TypeSpec) // Must succeed.
+		if symbol == typeSpec.Name.Name {
+			return typeSpec
+		}
+	}
+	return nil
+}
+
+// symbolDoc prints the docs for symbol. There may be multiple matches.
+// If symbol matches a type, output includes its methods factories and associated constants.
+// If there is no top-level symbol, symbolDoc looks for methods that match.
+func (pkg *Package) symbolDoc(symbol string) {
+	defer pkg.flush()
+	found := false
+	// Functions.
+	for _, fun := range pkg.findFuncs(symbol) {
+		if !found {
+			pkg.packageClause(true)
+		}
+		// Symbol is a function.
+		decl := fun.Decl
+		decl.Body = nil
+		pkg.emit(fun.Doc, decl)
+		found = true
+	}
+	// Constants and variables behave the same.
+	values := pkg.findValues(symbol, pkg.doc.Consts)
+	values = append(values, pkg.findValues(symbol, pkg.doc.Vars)...)
+	for _, value := range values {
+		// Print each spec only if there is at least one exported symbol in it.
+		// (See issue 11008.)
+		// TODO: Should we elide unexported symbols from a single spec?
+		// It's an unlikely scenario, probably not worth the trouble.
+		// TODO: Would be nice if go/doc did this for us.
+		specs := make([]ast.Spec, 0, len(value.Decl.Specs))
+		for _, spec := range value.Decl.Specs {
+			vspec := spec.(*ast.ValueSpec)
+			for _, ident := range vspec.Names {
+				if isExported(ident.Name) {
+					specs = append(specs, vspec)
+					break
+				}
+			}
+		}
+		if len(specs) == 0 {
+			continue
+		}
+		value.Decl.Specs = specs
+		if !found {
+			pkg.packageClause(true)
+		}
+		pkg.emit(value.Doc, value.Decl)
+		found = true
+	}
+	// Types.
+	for _, typ := range pkg.findTypes(symbol) {
+		if !found {
+			pkg.packageClause(true)
+		}
+		decl := typ.Decl
+		spec := pkg.findTypeSpec(decl, typ.Name)
+		trimUnexportedElems(spec)
+		// If there are multiple types defined, reduce to just this one.
+		if len(decl.Specs) > 1 {
+			decl.Specs = []ast.Spec{spec}
+		}
+		pkg.emit(typ.Doc, decl)
+		// Show associated methods, constants, etc.
+		if len(typ.Consts) > 0 || len(typ.Vars) > 0 || len(typ.Funcs) > 0 || len(typ.Methods) > 0 {
+			pkg.Printf("\n")
+		}
+		pkg.valueSummary(typ.Consts)
+		pkg.valueSummary(typ.Vars)
+		pkg.funcSummary(typ.Funcs)
+		pkg.funcSummary(typ.Methods)
+		found = true
+	}
+	if !found {
+		// See if there are methods.
+		if !pkg.printMethodDoc("", symbol) {
+			log.Printf("symbol %s not present in package %s installed in %q", symbol, pkg.name, pkg.build.ImportPath)
+		}
+	}
+}
+
+// trimUnexportedElems modifies spec in place to elide unexported fields from
+// structs and methods from interfaces (unless the unexported flag is set).
+func trimUnexportedElems(spec *ast.TypeSpec) {
+	if unexported {
+		return
+	}
+	switch typ := spec.Type.(type) {
+	case *ast.StructType:
+		typ.Fields = trimUnexportedFields(typ.Fields, "fields")
+	case *ast.InterfaceType:
+		typ.Methods = trimUnexportedFields(typ.Methods, "methods")
+	}
+}
+
+// trimUnexportedFields returns the field list trimmed of unexported fields.
+func trimUnexportedFields(fields *ast.FieldList, what string) *ast.FieldList {
+	trimmed := false
+	list := make([]*ast.Field, 0, len(fields.List))
+	for _, field := range fields.List {
+		// Trims if any is unexported. Good enough in practice.
+		ok := true
+		for _, name := range field.Names {
+			if !isExported(name.Name) {
+				trimmed = true
+				ok = false
+				break
+			}
+		}
+		if ok {
+			list = append(list, field)
+		}
+	}
+	if !trimmed {
+		return fields
+	}
+	unexportedField := &ast.Field{
+		Type: ast.NewIdent(""), // Hack: printer will treat this as a field with a named type.
+		Comment: &ast.CommentGroup{
+			List: []*ast.Comment{
+				&ast.Comment{
+					Text: fmt.Sprintf("// Has unexported %s.\n", what),
+				},
+			},
+		},
+	}
+	return &ast.FieldList{
+		Opening: fields.Opening,
+		List:    append(list, unexportedField),
+		Closing: fields.Closing,
+	}
+}
+
+// printMethodDoc prints the docs for matches of symbol.method.
+// If symbol is empty, it prints all methods that match the name.
+// It reports whether it found any methods.
+func (pkg *Package) printMethodDoc(symbol, method string) bool {
+	defer pkg.flush()
+	types := pkg.findTypes(symbol)
+	if types == nil {
+		if symbol == "" {
+			return false
+		}
+		pkg.Fatalf("symbol %s is not a type in package %s installed in %q", symbol, pkg.name, pkg.build.ImportPath)
+	}
+	found := false
+	for _, typ := range types {
+		for _, meth := range typ.Methods {
+			if match(method, meth.Name) {
+				decl := meth.Decl
+				decl.Body = nil
+				pkg.emit(meth.Doc, decl)
+				found = true
+			}
+		}
+	}
+	return found
+}
+
+// methodDoc prints the docs for matches of symbol.method.
+func (pkg *Package) methodDoc(symbol, method string) {
+	defer pkg.flush()
+	if !pkg.printMethodDoc(symbol, method) {
+		pkg.Fatalf("no method %s.%s in package %s installed in %q", symbol, method, pkg.name, pkg.build.ImportPath)
+	}
+}
+
+// match reports whether the user's symbol matches the program's.
+// A lower-case character in the user's string matches either case in the program's.
+// The program string must be exported.
+func match(user, program string) bool {
+	if !isExported(program) {
+		return false
+	}
+	if matchCase {
+		return user == program
+	}
+	for _, u := range user {
+		p, w := utf8.DecodeRuneInString(program)
+		program = program[w:]
+		if u == p {
+			continue
+		}
+		if unicode.IsLower(u) && simpleFold(u) == simpleFold(p) {
+			continue
+		}
+		return false
+	}
+	return program == ""
+}
+
+// simpleFold returns the minimum rune equivalent to r
+// under Unicode-defined simple case folding.
+func simpleFold(r rune) rune {
+	for {
+		r1 := unicode.SimpleFold(r)
+		if r1 <= r {
+			return r1 // wrapped around, found min
+		}
+		r = r1
+	}
+}
diff --git a/src/cmd/doc/testdata/pkg.go b/src/cmd/doc/testdata/pkg.go
new file mode 100644
index 0000000..ebefb50
--- /dev/null
+++ b/src/cmd/doc/testdata/pkg.go
@@ -0,0 +1,96 @@
+// 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 comment.
+package pkg
+
+// Constants
+
+// Comment about exported constant.
+const ExportedConstant = 1
+
+// Comment about internal constant.
+const internalConstant = 2
+
+// Comment about block of constants.
+const (
+	// Comment before ConstOne.
+	ConstOne   = 1
+	ConstTwo   = 2 // Comment on line with ConstTwo.
+	constThree = 3 // Comment on line with constThree.
+)
+
+// Variables
+
+// Comment about exported variable.
+var ExportedVariable = 1
+
+// Comment about internal variable.
+var internalVariable = 2
+
+// Comment about block of variables.
+var (
+	// Comment before VarOne.
+	VarOne   = 1
+	VarTwo   = 2 // Comment on line with VarTwo.
+	varThree = 3 // Comment on line with varThree.
+)
+
+// Comment about exported function.
+func ExportedFunc(a int) bool
+
+// Comment about internal function.
+func internalFunc(a int) bool
+
+// Comment about exported type.
+type ExportedType struct {
+	// Comment before exported field.
+	ExportedField   int
+	unexportedField int // Comment on line with unexported field.
+}
+
+// Comment about exported method.
+func (ExportedType) ExportedMethod(a int) bool {
+	return true
+}
+
+// Comment about unexported method.
+func (ExportedType) unexportedMethod(a int) bool {
+	return true
+}
+
+// Constants tied to ExportedType. (The type is a struct so this isn't valid Go,
+// but it parses and that's all we need.)
+const (
+	ExportedTypedConstant ExportedType = iota
+)
+
+// Comment about constructor for exported type.
+func ExportedTypeConstructor() *ExportedType {
+	return nil
+}
+
+const unexportedTypedConstant ExportedType = 1 // In a separate section to test -u.
+
+// Comment about unexported type.
+type unexportedType int
+
+func (unexportedType) ExportedMethod() bool {
+	return true
+}
+
+func (unexportedType) unexportedMethod() bool {
+	return true
+}
+
+// Constants tied to unexportedType.
+const (
+	ExportedTypedConstant_unexported unexportedType = iota
+)
+
+const unexportedTypedConstant unexportedType = 1 // In a separate section to test -u.
+
+// For case matching.
+const CaseMatch = 1
+const Casematch = 2
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 @@ func walkBeforeAfter(x interface{}, before, after func(interface{})) {
 	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 @@ func declImports(gen *ast.GenDecl, path string) bool {
 	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 @@ func isIdent(n interface{}) *ast.Ident {
 	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 @@ func refersTo(n ast.Node, x *ast.Ident) bool {
 	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 @@ func rewriteUses(x *ast.Ident, f, fnot func(token.Pos) ast.Expr, scope []ast.Stm
 	}
 }
 
-// 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/fix/gotypes.go b/src/cmd/fix/gotypes.go
new file mode 100644
index 0000000..8c7b466
--- /dev/null
+++ b/src/cmd/fix/gotypes.go
@@ -0,0 +1,75 @@
+// 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 (
+	"go/ast"
+	"strconv"
+)
+
+func init() {
+	register(gotypesFix)
+}
+
+var gotypesFix = fix{
+	"gotypes",
+	"2015-07-16",
+	gotypes,
+	`Change imports of golang.org/x/tools/go/{exact,types} to go/{constant,types}`,
+}
+
+func gotypes(f *ast.File) bool {
+	truth := fixGoTypes(f)
+	if fixGoExact(f) {
+		truth = true
+	}
+	return truth
+}
+
+func fixGoTypes(f *ast.File) bool {
+	return rewriteImport(f, "golang.org/x/tools/go/types", "go/types")
+}
+
+func fixGoExact(f *ast.File) bool {
+	// This one is harder because the import name changes.
+	// First find the import spec.
+	var importSpec *ast.ImportSpec
+	walk(f, func(n interface{}) {
+		if importSpec != nil {
+			return
+		}
+		spec, ok := n.(*ast.ImportSpec)
+		if !ok {
+			return
+		}
+		path, err := strconv.Unquote(spec.Path.Value)
+		if err != nil {
+			return
+		}
+		if path == "golang.org/x/tools/go/exact" {
+			importSpec = spec
+		}
+
+	})
+	if importSpec == nil {
+		return false
+	}
+
+	// We are about to rename exact.* to constant.*, but constant is a common
+	// name. See if it will conflict. This is a hack but it is effective.
+	exists := renameTop(f, "constant", "constant")
+	suffix := ""
+	if exists {
+		suffix = "_"
+	}
+	// Now we need to rename all the uses of the import. RewriteImport
+	// affects renameTop, but not vice versa, so do them in this order.
+	renameTop(f, "exact", "constant"+suffix)
+	rewriteImport(f, "golang.org/x/tools/go/exact", "go/constant")
+	// renameTop will also rewrite the imported package name. Fix that;
+	// we know it should be missing.
+	importSpec.Name = nil
+	return true
+}
diff --git a/src/cmd/fix/gotypes_test.go b/src/cmd/fix/gotypes_test.go
new file mode 100644
index 0000000..1ecb7a2
--- /dev/null
+++ b/src/cmd/fix/gotypes_test.go
@@ -0,0 +1,89 @@
+// 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.
+
+package main
+
+func init() {
+	addTestCases(gotypesTests, gotypes)
+}
+
+var gotypesTests = []testCase{
+	{
+		Name: "gotypes.0",
+		In: `package main
+
+import "golang.org/x/tools/go/types"
+import "golang.org/x/tools/go/exact"
+
+var _ = exact.Kind
+
+func f() {
+	_ = exact.MakeBool(true)
+}
+`,
+		Out: `package main
+
+import "go/types"
+import "go/constant"
+
+var _ = constant.Kind
+
+func f() {
+	_ = constant.MakeBool(true)
+}
+`,
+	},
+	{
+		Name: "gotypes.1",
+		In: `package main
+
+import "golang.org/x/tools/go/types"
+import foo "golang.org/x/tools/go/exact"
+
+var _ = foo.Kind
+
+func f() {
+	_ = foo.MakeBool(true)
+}
+`,
+		Out: `package main
+
+import "go/types"
+import "go/constant"
+
+var _ = foo.Kind
+
+func f() {
+	_ = foo.MakeBool(true)
+}
+`,
+	},
+	{
+		Name: "gotypes.0",
+		In: `package main
+
+import "golang.org/x/tools/go/types"
+import "golang.org/x/tools/go/exact"
+
+var _ = exact.Kind
+var constant = 23 // Use of new package name.
+
+func f() {
+	_ = exact.MakeBool(true)
+}
+`,
+		Out: `package main
+
+import "go/types"
+import "go/constant"
+
+var _ = constant_.Kind
+var constant = 23 // Use of new package name.
+
+func f() {
+	_ = constant_.MakeBool(true)
+}
+`,
+	},
+}
diff --git a/src/cmd/gc/Makefile b/src/cmd/gc/Makefile
deleted file mode 100644
index 58e25fa..0000000
--- a/src/cmd/gc/Makefile
+++ /dev/null
@@ -1,17 +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.
-
-include ../../Make.dist
-
-install: y.tab.h builtin.c
-
-y.tab.h: go.y go.errors bisonerrors
-	bison -v -y -d go.y
-	# make yystate global, yytname mutable
-	cat y.tab.c | sed '/ int yystate;/d; s/int yychar;/int yychar, yystate;/; s/static const char \*const yytname/const char *yytname/; s/char const \*yymsgp/char *yymsgp/' >y1.tab.c
-	mv y1.tab.c y.tab.c
-	awk -f bisonerrors y.output go.errors >yerr.h
-
-builtin.c: runtime.go unsafe.go
-	./mkbuiltin
diff --git a/src/cmd/gc/align.c b/src/cmd/gc/align.c
deleted file mode 100644
index 63ed2e5..0000000
--- a/src/cmd/gc/align.c
+++ /dev/null
@@ -1,680 +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 <u.h>
-#include <libc.h>
-#include "go.h"
-
-/*
- * machine size and rounding
- * alignment is dictated around
- * the size of a pointer, set in betypeinit
- * (see ../6g/galign.c).
- */
-
-static int defercalc;
-
-vlong
-rnd(vlong o, vlong r)
-{
-	if(r < 1 || r > 8 || (r&(r-1)) != 0)
-		fatal("rnd");
-	return (o+r-1)&~(r-1);
-}
-
-static void
-offmod(Type *t)
-{
-	Type *f;
-	int32 o;
-
-	o = 0;
-	for(f=t->type; f!=T; f=f->down) {
-		if(f->etype != TFIELD)
-			fatal("offmod: not TFIELD: %lT", f);
-		f->width = o;
-		o += widthptr;
-		if(o >= MAXWIDTH) {
-			yyerror("interface too large");
-			o = widthptr;
-		}
-	}
-}
-
-static vlong
-widstruct(Type *errtype, Type *t, vlong o, int flag)
-{
-	Type *f;
-	int64 w;
-	int32 maxalign;
-	
-	maxalign = flag;
-	if(maxalign < 1)
-		maxalign = 1;
-	for(f=t->type; f!=T; f=f->down) {
-		if(f->etype != TFIELD)
-			fatal("widstruct: not TFIELD: %lT", f);
-		if(f->type == T) {
-			// broken field, just skip it so that other valid fields
-			// get a width.
-			continue;
-		}
-		dowidth(f->type);
-		if(f->type->align > maxalign)
-			maxalign = f->type->align;
-		if(f->type->width < 0)
-			fatal("invalid width %lld", f->type->width);
-		w = f->type->width;
-		if(f->type->align > 0)
-			o = rnd(o, f->type->align);
-		f->width = o;	// really offset for TFIELD
-		if(f->nname != N) {
-			// this same stackparam logic is in addrescapes
-			// in typecheck.c.  usually addrescapes runs after
-			// widstruct, in which case we could drop this,
-			// but function closure functions are the exception.
-			if(f->nname->stackparam) {
-				f->nname->stackparam->xoffset = o;
-				f->nname->xoffset = 0;
-			} else
-				f->nname->xoffset = o;
-		}
-		o += w;
-		if(o >= MAXWIDTH) {
-			yyerror("type %lT too large", errtype);
-			o = 8;  // small but nonzero
-		}
-	}
-	// final width is rounded
-	if(flag)
-		o = rnd(o, maxalign);
-	t->align = maxalign;
-
-	// type width only includes back to first field's offset
-	if(t->type == T)
-		t->width = 0;
-	else
-		t->width = o - t->type->width;
-	return o;
-}
-
-void
-dowidth(Type *t)
-{
-	int32 et;
-	int64 w;
-	int lno;
-	Type *t1;
-
-	if(widthptr == 0)
-		fatal("dowidth without betypeinit");
-
-	if(t == T)
-		return;
-
-	if(t->width > 0)
-		return;
-
-	if(t->width == -2) {
-		lno = lineno;
-		lineno = t->lineno;
-		if(!t->broke) {
-			t->broke = 1;
-			yyerror("invalid recursive type %T", t);
-		}
-		t->width = 0;
-		lineno = lno;
-		return;
-	}
-
-	// break infinite recursion if the broken recursive type
-	// is referenced again
-	if(t->broke && t->width == 0)
-		return;
-
-	// defer checkwidth calls until after we're done
-	defercalc++;
-
-	lno = lineno;
-	lineno = t->lineno;
-	t->width = -2;
-	t->align = 0;
-
-	et = t->etype;
-	switch(et) {
-	case TFUNC:
-	case TCHAN:
-	case TMAP:
-	case TSTRING:
-		break;
-
-	default:
-		/* simtype == 0 during bootstrap */
-		if(simtype[t->etype] != 0)
-			et = simtype[t->etype];
-		break;
-	}
-
-	w = 0;
-	switch(et) {
-	default:
-		fatal("dowidth: unknown type: %T", t);
-		break;
-
-	/* compiler-specific stuff */
-	case TINT8:
-	case TUINT8:
-	case TBOOL:		// bool is int8
-		w = 1;
-		break;
-	case TINT16:
-	case TUINT16:
-		w = 2;
-		break;
-	case TINT32:
-	case TUINT32:
-	case TFLOAT32:
-		w = 4;
-		break;
-	case TINT64:
-	case TUINT64:
-	case TFLOAT64:
-	case TCOMPLEX64:
-		w = 8;
-		t->align = widthreg;
-		break;
-	case TCOMPLEX128:
-		w = 16;
-		t->align = widthreg;
-		break;
-	case TPTR32:
-		w = 4;
-		checkwidth(t->type);
-		break;
-	case TPTR64:
-		w = 8;
-		checkwidth(t->type);
-		break;
-	case TUNSAFEPTR:
-		w = widthptr;
-		break;
-	case TINTER:		// implemented as 2 pointers
-		w = 2*widthptr;
-		t->align = widthptr;
-		offmod(t);
-		break;
-	case TCHAN:		// implemented as pointer
-		w = widthptr;
-		checkwidth(t->type);
-
-		// make fake type to check later to
-		// trigger channel argument check.
-		t1 = typ(TCHANARGS);
-		t1->type = t;
-		checkwidth(t1);
-		break;
-	case TCHANARGS:
-		t1 = t->type;
-		dowidth(t->type);	// just in case
-		if(t1->type->width >= (1<<16))
-			yyerror("channel element type too large (>64kB)");
-		t->width = 1;
-		break;
-	case TMAP:		// implemented as pointer
-		w = widthptr;
-		checkwidth(t->type);
-		checkwidth(t->down);
-		break;
-	case TFORW:		// should have been filled in
-		if(!t->broke)
-			yyerror("invalid recursive type %T", t);
-		w = 1;	// anything will do
-		break;
-	case TANY:
-		// dummy type; should be replaced before use.
-		if(!debug['A'])
-			fatal("dowidth any");
-		w = 1;	// anything will do
-		break;
-	case TSTRING:
-		if(sizeof_String == 0)
-			fatal("early dowidth string");
-		w = sizeof_String;
-		t->align = widthptr;
-		break;
-	case TARRAY:
-		if(t->type == T)
-			break;
-		if(t->bound >= 0) {
-			uint64 cap;
-
-			dowidth(t->type);
-			if(t->type->width != 0) {
-				cap = (MAXWIDTH-1) / t->type->width;
-				if(t->bound > cap)
-					yyerror("type %lT larger than address space", t);
-			}
-			w = t->bound * t->type->width;
-			t->align = t->type->align;
-		}
-		else if(t->bound == -1) {
-			w = sizeof_Array;
-			checkwidth(t->type);
-			t->align = widthptr;
-		}
-		else if(t->bound == -100) {
-			if(!t->broke) {
-				yyerror("use of [...] array outside of array literal");
-				t->broke = 1;
-			}
-		}
-		else
-			fatal("dowidth %T", t);	// probably [...]T
-		break;
-
-	case TSTRUCT:
-		if(t->funarg)
-			fatal("dowidth fn struct %T", t);
-		w = widstruct(t, t, 0, 1);
-		break;
-
-	case TFUNC:
-		// make fake type to check later to
-		// trigger function argument computation.
-		t1 = typ(TFUNCARGS);
-		t1->type = t;
-		checkwidth(t1);
-
-		// width of func type is pointer
-		w = widthptr;
-		break;
-
-	case TFUNCARGS:
-		// function is 3 cated structures;
-		// compute their widths as side-effect.
-		t1 = t->type;
-		w = widstruct(t->type, *getthis(t1), 0, 0);
-		w = widstruct(t->type, *getinarg(t1), w, widthreg);
-		w = widstruct(t->type, *getoutarg(t1), w, widthreg);
-		t1->argwid = w;
-		if(w%widthreg)
-			warn("bad type %T %d\n", t1, w);
-		t->align = 1;
-		break;
-	}
-
-	if(widthptr == 4 && w != (int32)w)
-		yyerror("type %T too large", t);
-
-	t->width = w;
-	if(t->align == 0) {
-		if(w > 8 || (w&(w-1)) != 0)
-			fatal("invalid alignment for %T", t);
-		t->align = w;
-	}
-	lineno = lno;
-
-	if(defercalc == 1)
-		resumecheckwidth();
-	else
-		--defercalc;
-}
-
-/*
- * when a type's width should be known, we call checkwidth
- * to compute it.  during a declaration like
- *
- *	type T *struct { next T }
- *
- * it is necessary to defer the calculation of the struct width
- * until after T has been initialized to be a pointer to that struct.
- * similarly, during import processing structs may be used
- * before their definition.  in those situations, calling
- * defercheckwidth() stops width calculations until
- * resumecheckwidth() is called, at which point all the
- * checkwidths that were deferred are executed.
- * dowidth should only be called when the type's size
- * is needed immediately.  checkwidth makes sure the
- * size is evaluated eventually.
- */
-typedef struct TypeList TypeList;
-struct TypeList {
-	Type *t;
-	TypeList *next;
-};
-
-static TypeList *tlfree;
-static TypeList *tlq;
-
-void
-checkwidth(Type *t)
-{
-	TypeList *l;
-
-	if(t == T)
-		return;
-
-	// function arg structs should not be checked
-	// outside of the enclosing function.
-	if(t->funarg)
-		fatal("checkwidth %T", t);
-
-	if(!defercalc) {
-		dowidth(t);
-		return;
-	}
-	if(t->deferwidth)
-		return;
-	t->deferwidth = 1;
-
-	l = tlfree;
-	if(l != nil)
-		tlfree = l->next;
-	else
-		l = mal(sizeof *l);
-
-	l->t = t;
-	l->next = tlq;
-	tlq = l;
-}
-
-void
-defercheckwidth(void)
-{
-	// we get out of sync on syntax errors, so don't be pedantic.
-	if(defercalc && nerrors == 0)
-		fatal("defercheckwidth");
-	defercalc = 1;
-}
-
-void
-resumecheckwidth(void)
-{
-	TypeList *l;
-
-	if(!defercalc)
-		fatal("resumecheckwidth");
-	for(l = tlq; l != nil; l = tlq) {
-		l->t->deferwidth = 0;
-		tlq = l->next;
-		dowidth(l->t);
-		l->next = tlfree;
-		tlfree = l;
-	}
-	defercalc = 0;
-}
-
-void
-typeinit(void)
-{
-	int i, etype, sameas;
-	Type *t;
-	Sym *s, *s1;
-
-	if(widthptr == 0)
-		fatal("typeinit before betypeinit");
-
-	for(i=0; i<NTYPE; i++)
-		simtype[i] = i;
-
-	types[TPTR32] = typ(TPTR32);
-	dowidth(types[TPTR32]);
-
-	types[TPTR64] = typ(TPTR64);
-	dowidth(types[TPTR64]);
-	
-	t = typ(TUNSAFEPTR);
-	types[TUNSAFEPTR] = t;
-	t->sym = pkglookup("Pointer", unsafepkg);
-	t->sym->def = typenod(t);
-	
-	dowidth(types[TUNSAFEPTR]);
-
-	tptr = TPTR32;
-	if(widthptr == 8)
-		tptr = TPTR64;
-
-	for(i=TINT8; i<=TUINT64; i++)
-		isint[i] = 1;
-	isint[TINT] = 1;
-	isint[TUINT] = 1;
-	isint[TUINTPTR] = 1;
-
-	isfloat[TFLOAT32] = 1;
-	isfloat[TFLOAT64] = 1;
-
-	iscomplex[TCOMPLEX64] = 1;
-	iscomplex[TCOMPLEX128] = 1;
-
-	isptr[TPTR32] = 1;
-	isptr[TPTR64] = 1;
-
-	isforw[TFORW] = 1;
-
-	issigned[TINT] = 1;
-	issigned[TINT8] = 1;
-	issigned[TINT16] = 1;
-	issigned[TINT32] = 1;
-	issigned[TINT64] = 1;
-
-	/*
-	 * initialize okfor
-	 */
-	for(i=0; i<NTYPE; i++) {
-		if(isint[i] || i == TIDEAL) {
-			okforeq[i] = 1;
-			okforcmp[i] = 1;
-			okforarith[i] = 1;
-			okforadd[i] = 1;
-			okforand[i] = 1;
-			okforconst[i] = 1;
-			issimple[i] = 1;
-			minintval[i] = mal(sizeof(*minintval[i]));
-			maxintval[i] = mal(sizeof(*maxintval[i]));
-		}
-		if(isfloat[i]) {
-			okforeq[i] = 1;
-			okforcmp[i] = 1;
-			okforadd[i] = 1;
-			okforarith[i] = 1;
-			okforconst[i] = 1;
-			issimple[i] = 1;
-			minfltval[i] = mal(sizeof(*minfltval[i]));
-			maxfltval[i] = mal(sizeof(*maxfltval[i]));
-		}
-		if(iscomplex[i]) {
-			okforeq[i] = 1;
-			okforadd[i] = 1;
-			okforarith[i] = 1;
-			okforconst[i] = 1;
-			issimple[i] = 1;
-		}
-	}
-
-	issimple[TBOOL] = 1;
-
-	okforadd[TSTRING] = 1;
-
-	okforbool[TBOOL] = 1;
-
-	okforcap[TARRAY] = 1;
-	okforcap[TCHAN] = 1;
-
-	okforconst[TBOOL] = 1;
-	okforconst[TSTRING] = 1;
-
-	okforlen[TARRAY] = 1;
-	okforlen[TCHAN] = 1;
-	okforlen[TMAP] = 1;
-	okforlen[TSTRING] = 1;
-
-	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
-
-	okforcmp[TSTRING] = 1;
-
-	for(i=0; i<nelem(okfor); i++)
-		okfor[i] = okfornone;
-
-	// binary
-	okfor[OADD] = okforadd;
-	okfor[OAND] = okforand;
-	okfor[OANDAND] = okforbool;
-	okfor[OANDNOT] = okforand;
-	okfor[ODIV] = okforarith;
-	okfor[OEQ] = okforeq;
-	okfor[OGE] = okforcmp;
-	okfor[OGT] = okforcmp;
-	okfor[OLE] = okforcmp;
-	okfor[OLT] = okforcmp;
-	okfor[OMOD] = okforand;
-	okfor[OMUL] = okforarith;
-	okfor[ONE] = okforeq;
-	okfor[OOR] = okforand;
-	okfor[OOROR] = okforbool;
-	okfor[OSUB] = okforarith;
-	okfor[OXOR] = okforand;
-	okfor[OLSH] = okforand;
-	okfor[ORSH] = okforand;
-
-	// unary
-	okfor[OCOM] = okforand;
-	okfor[OMINUS] = okforarith;
-	okfor[ONOT] = okforbool;
-	okfor[OPLUS] = okforarith;
-
-	// special
-	okfor[OCAP] = okforcap;
-	okfor[OLEN] = okforlen;
-
-	// comparison
-	iscmp[OLT] = 1;
-	iscmp[OGT] = 1;
-	iscmp[OGE] = 1;
-	iscmp[OLE] = 1;
-	iscmp[OEQ] = 1;
-	iscmp[ONE] = 1;
-
-	mpatofix(maxintval[TINT8], "0x7f");
-	mpatofix(minintval[TINT8], "-0x80");
-	mpatofix(maxintval[TINT16], "0x7fff");
-	mpatofix(minintval[TINT16], "-0x8000");
-	mpatofix(maxintval[TINT32], "0x7fffffff");
-	mpatofix(minintval[TINT32], "-0x80000000");
-	mpatofix(maxintval[TINT64], "0x7fffffffffffffff");
-	mpatofix(minintval[TINT64], "-0x8000000000000000");
-
-	mpatofix(maxintval[TUINT8], "0xff");
-	mpatofix(maxintval[TUINT16], "0xffff");
-	mpatofix(maxintval[TUINT32], "0xffffffff");
-	mpatofix(maxintval[TUINT64], "0xffffffffffffffff");
-
-	/* f is valid float if min < f < max.  (min and max are not themselves valid.) */
-	mpatoflt(maxfltval[TFLOAT32], "33554431p103");	/* 2^24-1 p (127-23) + 1/2 ulp*/
-	mpatoflt(minfltval[TFLOAT32], "-33554431p103");
-	mpatoflt(maxfltval[TFLOAT64], "18014398509481983p970");	/* 2^53-1 p (1023-52) + 1/2 ulp */
-	mpatoflt(minfltval[TFLOAT64], "-18014398509481983p970");
-
-	maxfltval[TCOMPLEX64] = maxfltval[TFLOAT32];
-	minfltval[TCOMPLEX64] = minfltval[TFLOAT32];
-	maxfltval[TCOMPLEX128] = maxfltval[TFLOAT64];
-	minfltval[TCOMPLEX128] = minfltval[TFLOAT64];
-
-	/* for walk to use in error messages */
-	types[TFUNC] = functype(N, nil, nil);
-
-	/* types used in front end */
-	// types[TNIL] got set early in lexinit
-	types[TIDEAL] = typ(TIDEAL);
-	types[TINTER] = typ(TINTER);
-
-	/* simple aliases */
-	simtype[TMAP] = tptr;
-	simtype[TCHAN] = tptr;
-	simtype[TFUNC] = tptr;
-	simtype[TUNSAFEPTR] = tptr;
-
-	/* pick up the backend typedefs */
-	for(i=0; typedefs[i].name; i++) {
-		s = lookup(typedefs[i].name);
-		s1 = pkglookup(typedefs[i].name, builtinpkg);
-
-		etype = typedefs[i].etype;
-		if(etype < 0 || etype >= nelem(types))
-			fatal("typeinit: %s bad etype", s->name);
-		sameas = typedefs[i].sameas;
-		if(sameas < 0 || sameas >= nelem(types))
-			fatal("typeinit: %s bad sameas", s->name);
-		simtype[etype] = sameas;
-		minfltval[etype] = minfltval[sameas];
-		maxfltval[etype] = maxfltval[sameas];
-		minintval[etype] = minintval[sameas];
-		maxintval[etype] = maxintval[sameas];
-
-		t = types[etype];
-		if(t != T)
-			fatal("typeinit: %s already defined", s->name);
-
-		t = typ(etype);
-		t->sym = s1;
-
-		dowidth(t);
-		types[etype] = t;
-		s1->def = typenod(t);
-	}
-
-	Array_array = rnd(0, widthptr);
-	Array_nel = rnd(Array_array+widthptr, widthint);
-	Array_cap = rnd(Array_nel+widthint, widthint);
-	sizeof_Array = rnd(Array_cap+widthint, widthptr);
-
-	// string is same as slice wo the cap
-	sizeof_String = rnd(Array_nel+widthint, widthptr);
-
-	dowidth(types[TSTRING]);
-	dowidth(idealstring);
-}
-
-/*
- * compute total size of f's in/out arguments.
- */
-int
-argsize(Type *t)
-{
-	Iter save;
-	Type *fp;
-	int64 w, x;
-
-	w = 0;
-
-	fp = structfirst(&save, getoutarg(t));
-	while(fp != T) {
-		x = fp->width + fp->type->width;
-		if(x > w)
-			w = x;
-		fp = structnext(&save);
-	}
-
-	fp = funcfirst(&save, t);
-	while(fp != T) {
-		x = fp->width + fp->type->width;
-		if(x > w)
-			w = x;
-		fp = funcnext(&save);
-	}
-
-	w = (w+widthptr-1) & ~(widthptr-1);
-	if((int)w != w)
-		fatal("argsize too big");
-	return w;
-}
diff --git a/src/cmd/gc/array.c b/src/cmd/gc/array.c
deleted file mode 100644
index 611fc9f..0000000
--- a/src/cmd/gc/array.c
+++ /dev/null
@@ -1,115 +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.
-
-#include <u.h>
-#include <libc.h>
-#include "go.h"
-
-enum {
-	DEFAULTCAPACITY = 16,
-};
-
-struct Array
-{
-	int32	length;  // number of elements
-	int32	size;  // element size
-	int32	capacity;  // size of data in elements
-	char	*data;  // element storage
-};
-
-Array*
-arraynew(int32 capacity, int32 size)
-{
-	Array *result;
-
-	if(capacity < 0)
-		fatal("arraynew: capacity %d is not positive", capacity);
-	if(size < 0)
-		fatal("arraynew: size %d is not positive\n", size);
-	result = malloc(sizeof(*result));
-	if(result == nil)
-		fatal("arraynew: malloc failed\n");
-	result->length = 0;
-	result->size = size;
-	result->capacity = capacity == 0 ? DEFAULTCAPACITY : capacity;
-	result->data = malloc(result->capacity * result->size);
-	if(result->data == nil)
-		fatal("arraynew: malloc failed\n");
-	return result;
-}
-
-void
-arrayfree(Array *array)
-{
-	if(array == nil)
-		return;
-	free(array->data);
-	free(array);
-}
-
-int32
-arraylength(Array *array)
-{
-	return array->length;
-}
-
-void*
-arrayget(Array *array, int32 index)
-{
-	if(array == nil)
-		fatal("arrayget: array is nil\n");
-	if(index < 0 || index >= array->length)
-		fatal("arrayget: index %d is out of bounds for length %d\n", index, array->length);
-	return array->data + index * array->size;
-}
-
-void
-arrayset(Array *array, int32 index, void *element)
-{
-	if(array == nil)
-		fatal("arrayset: array is nil\n");
-	if(element == nil)
-		fatal("arrayset: element is nil\n");
-	if(index < 0 || index >= array->length)
-		fatal("arrayget: index %d is out of bounds for length %d\n", index, array->length);
-	memmove(array->data + index * array->size, element, array->size);
-}
-
-static void
-ensurecapacity(Array *array, int32 capacity)
-{
-	int32 newcapacity;
-	char *newdata;
-
-	if(array == nil)
-		fatal("ensurecapacity: array is nil\n");
-	if(capacity < 0)
-		fatal("ensurecapacity: capacity %d is not positive", capacity);
-	if(capacity >= array->capacity) {
-		newcapacity = capacity + (capacity >> 1);
-		newdata = realloc(array->data, newcapacity * array->size);
-		if(newdata == nil)
-			fatal("ensurecapacity: realloc failed\n");
-		array->capacity = newcapacity;
-		array->data = newdata;
-	}
-}
-
-void
-arrayadd(Array *array, void *element)
-{
-	if(array == nil)
-		fatal("arrayset: array is nil\n");
-	if(element == nil)
-		fatal("arrayset: element is nil\n");
-	ensurecapacity(array, array->length + 1);
-	array->length++;
-	arrayset(array, array->length - 1, element);
-}
-
-void
-arraysort(Array *array, int (*cmp)(const void*, const void*))
-{
-	qsort(array->data, array->length, array->size, cmp);
-}
diff --git a/src/cmd/gc/bisonerrors b/src/cmd/gc/bisonerrors
deleted file mode 100755
index fa74c67..0000000
--- a/src/cmd/gc/bisonerrors
+++ /dev/null
@@ -1,156 +0,0 @@
-#!/usr/bin/awk -f
-# Copyright 2010 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 implements the core idea from
-#
-#	Clinton L. Jeffery, Generating LR syntax error messages from examples,
-#	ACM TOPLAS 25(5) (September 2003).  http://doi.acm.org/10.1145/937563.937566
-# 
-# It reads Bison's summary of a grammar followed by a file
-# like go.errors, replacing lines beginning with % by the 
-# yystate and yychar that will be active when an error happens
-# while parsing that line.  
-#
-# Unlike the system described in the paper, the lines in go.errors
-# give grammar symbol name lists, not actual program fragments.
-# This is a little less programmer-friendly but doesn't require being
-# able to run the text through lex.c.
-
-BEGIN{
-	bison = 1
-	grammar = 0
-	states = 0
-	open = 0
-}
-
-# In Grammar section of y.output,
-# record lhs and length of rhs for each rule.
-bison && /^Grammar/ { grammar = 1 }
-bison && /^(Terminals|state 0)/ { grammar = 0 }
-grammar && NF>0 {
-	if($2 != "|") {
-		r = $2
-		sub(/:$/, "", r)
-	}
-	rulelhs[$1] = r
-	rulesize[$1] = NF-2
-	if(rulesize[$1] == 1 && $3 == "%empty") {
-		rulesize[$1] = 0
-	}
-	if(rulesize[$1] == 3 && $3 $4 $5 == "/*empty*/") {
-		rulesize[$1] = 0
-	}
-}
-
-# In state dumps, record shift/reduce actions.
-bison && /^[Ss]tate 0/ { grammar = 0; states = 1 }
-
-states && /^[Ss]tate / { state = $2 }
-states { statetext[state] = statetext[state] $0 "\n" }
-
-states && / shift/ {
-	n = nshift[state]++
-	if($0 ~ /and go to/)
-		shift[state,n] = $7 # GNU Bison
-	else
-		shift[state,n] = $3 # Plan 9 Yacc
-	shifttoken[state,n] = $1
-	next
-}
-states && / (go to|goto)/ {
-	n = nshift[state]++
-	if($0 ~ /go to/)
-		shift[state,n] = $5 # GNU Bison
-	else
-		shift[state,n] = $3 # Plan 9 Yacc
-	shifttoken[state,n] = $1
-	next
-}
-states && / reduce/ {
-	n = nreduce[state]++
-	if($0 ~ /reduce using rule/)
-		reduce[state,n] = $5 # GNU Bison
-	else
-		reduce[state,n] = $3 # Plan 9 yacc
-	reducetoken[state,n] = $1
-	next
-}
-
-# Skip over the summary information printed by Plan 9 yacc.
-/nonterminals$/,/^maximum spread/ { next }
-
-# First // comment marks the beginning of the pattern file.
-/^\/\// { bison = 0; grammar = 0; state = 0 }
-bison { next }
-
-# Treat % as first field on line as introducing a pattern (token sequence).
-# Run it through the LR machine and print the induced "yystate, yychar,"
-# at the point where the error happens.
-$1 == "%" {
-	nstack = 0
-	state = 0
-	f = 2
-	tok = ""
-	for(;;) {
-		if(tok == "" && f <= NF) {
-			tok = $f
-			f++
-		}
-		found = 0
-		for(j=0; j<nshift[state]; j++) {
-			if(shifttoken[state,j] == tok) {
-				# print "SHIFT " tok " " state " -> " shift[state,j]
-				stack[nstack++] = state
-				state = shift[state,j]
-				found = 1
-				tok = ""
-				break
-			}
-		}
-		if(found)
-			continue
-		for(j=0; j<nreduce[state]; j++) {
-			t = reducetoken[state,j]
-			if(t == tok || t == "$default" || t == ".") {
-				stack[nstack++] = state
-				rule = reduce[state,j]
-				nstack -= rulesize[rule]
-				state = stack[--nstack]
-				lhs = rulelhs[rule]
-				if(tok != "")
-					--f
-				tok = rulelhs[rule]
-				# print "REDUCE " nstack " " state " " tok " rule " rule " size " rulesize[rule]
-				found = 1
-				break
-			}
-		}
-		if(found)
-			continue
-
-		# No shift or reduce applied - found the error.
-		printf("\t{%s, %s,\n", state, tok);
-		open = 1;
-		break
-	}
-	next
-}
-
-# Print other lines verbatim.
-open && /,$/ {
-	s = $0;
-	sub(",", "},", s)
-	print s
-	open = 0
-	next
-}
-
-open && /"$/ {
-	print $0 "}"
-	open = 0
-	next
-}
-
-{print}
diff --git a/src/cmd/gc/bits.c b/src/cmd/gc/bits.c
deleted file mode 100644
index 2e79f6f..0000000
--- a/src/cmd/gc/bits.c
+++ /dev/null
@@ -1,163 +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 at 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 at 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.
-
-#include <u.h>
-#include <libc.h>
-#include "go.h"
-
-/*
-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;
-}
-*/
-
-int
-bany(Bits *a)
-{
-	int i;
-
-	for(i=0; i<BITS; i++)
-		if(a->b[i])
-			return 1;
-	return 0;
-}
-
-/*
-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;
-}
-*/
-
-int
-bnum(Bits a)
-{
-	int i;
-	int32 b;
-
-	for(i=0; i<BITS; i++)
-		if(b = a.b[i])
-			return 32*i + bitno(b);
-	fatal("bad in bnum");
-	return 0;
-}
-
-Bits
-blsh(uint n)
-{
-	Bits c;
-
-	c = zbits;
-	c.b[n/32] = 1L << (n%32);
-	return c;
-}
-
-/*
-int
-bset(Bits a, uint n)
-{
-	if(a.b[n/32] & (1L << (n%32)))
-		return 1;
-	return 0;
-}
-*/
-
-int
-bitno(int32 b)
-{
-	int i;
-
-	for(i=0; i<32; i++)
-		if(b & (1L<<i))
-			return i;
-	fatal("bad in bitno");
-	return 0;
-}
-
-int
-Qconv(Fmt *fp)
-{
-	Bits bits;
-	int i, first;
-
-	first = 1;
-	bits = va_arg(fp->args, Bits);
-	while(bany(&bits)) {
-		i = bnum(bits);
-		if(first)
-			first = 0;
-		else
-			fmtprint(fp, " ");
-		if(var[i].node == N || var[i].node->sym == S)
-			fmtprint(fp, "$%d", i);
-		else {
-			fmtprint(fp, "%s(%d)", var[i].node->sym->name, i);
-			if(var[i].offset != 0)
-				fmtprint(fp, "%+lld", (vlong)var[i].offset);
-		}
-		bits.b[i/32] &= ~(1L << (i%32));
-	}
-	return 0;
-}
diff --git a/src/cmd/gc/builtin.c b/src/cmd/gc/builtin.c
deleted file mode 100644
index fbca4ee..0000000
--- a/src/cmd/gc/builtin.c
+++ /dev/null
@@ -1,137 +0,0 @@
-// AUTO-GENERATED by mkbuiltin; DO NOT EDIT
-char *runtimeimport =
-	"package runtime\n"
-	"import runtime \"runtime\"\n"
-	"func @\"\".newobject (@\"\".typ·2 *byte) (? *any)\n"
-	"func @\"\".panicindex ()\n"
-	"func @\"\".panicslice ()\n"
-	"func @\"\".panicdivide ()\n"
-	"func @\"\".throwreturn ()\n"
-	"func @\"\".throwinit ()\n"
-	"func @\"\".panicwrap (? string, ? string, ? string)\n"
-	"func @\"\".gopanic (? interface {})\n"
-	"func @\"\".gorecover (? *int32) (? interface {})\n"
-	"func @\"\".printbool (? bool)\n"
-	"func @\"\".printfloat (? float64)\n"
-	"func @\"\".printint (? int64)\n"
-	"func @\"\".printhex (? uint64)\n"
-	"func @\"\".printuint (? uint64)\n"
-	"func @\"\".printcomplex (? complex128)\n"
-	"func @\"\".printstring (? string)\n"
-	"func @\"\".printpointer (? any)\n"
-	"func @\"\".printiface (? any)\n"
-	"func @\"\".printeface (? any)\n"
-	"func @\"\".printslice (? any)\n"
-	"func @\"\".printnl ()\n"
-	"func @\"\".printsp ()\n"
-	"func @\"\".concatstring2 (? string, ? string) (? string)\n"
-	"func @\"\".concatstring3 (? string, ? string, ? string) (? string)\n"
-	"func @\"\".concatstring4 (? string, ? string, ? string, ? string) (? string)\n"
-	"func @\"\".concatstring5 (? string, ? string, ? string, ? string, ? string) (? string)\n"
-	"func @\"\".concatstrings (? []string) (? string)\n"
-	"func @\"\".cmpstring (? string, ? string) (? int)\n"
-	"func @\"\".eqstring (? string, ? string) (? bool)\n"
-	"func @\"\".intstring (? int64) (? string)\n"
-	"func @\"\".slicebytetostring (? []byte) (? string)\n"
-	"func @\"\".slicebytetostringtmp (? []byte) (? string)\n"
-	"func @\"\".slicerunetostring (? []rune) (? string)\n"
-	"func @\"\".stringtoslicebyte (? string) (? []byte)\n"
-	"func @\"\".stringtoslicerune (? string) (? []rune)\n"
-	"func @\"\".stringiter (? string, ? int) (? int)\n"
-	"func @\"\".stringiter2 (? string, ? int) (@\"\".retk·1 int, @\"\".retv·2 rune)\n"
-	"func @\"\".slicecopy (@\"\".to·2 any, @\"\".fr·3 any, @\"\".wid·4 uintptr) (? int)\n"
-	"func @\"\".slicestringcopy (@\"\".to·2 any, @\"\".fr·3 any) (? int)\n"
-	"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 @\"\".assertE2E (@\"\".typ·2 *byte, @\"\".iface·3 any) (@\"\".ret·1 any)\n"
-	"func @\"\".assertE2E2 (@\"\".typ·3 *byte, @\"\".iface·4 any) (@\"\".ret·1 any, @\"\".ok·2 bool)\n"
-	"func @\"\".assertE2I (@\"\".typ·2 *byte, @\"\".iface·3 any) (@\"\".ret·1 any)\n"
-	"func @\"\".assertE2I2 (@\"\".typ·3 *byte, @\"\".iface·4 any) (@\"\".ret·1 any, @\"\".ok·2 bool)\n"
-	"func @\"\".assertE2T (@\"\".typ·2 *byte, @\"\".iface·3 any) (@\"\".ret·1 any)\n"
-	"func @\"\".assertE2T2 (@\"\".typ·3 *byte, @\"\".iface·4 any) (@\"\".ret·1 any, @\"\".ok·2 bool)\n"
-	"func @\"\".assertI2E (@\"\".typ·2 *byte, @\"\".iface·3 any) (@\"\".ret·1 any)\n"
-	"func @\"\".assertI2E2 (@\"\".typ·3 *byte, @\"\".iface·4 any) (@\"\".ret·1 any, @\"\".ok·2 bool)\n"
-	"func @\"\".assertI2I (@\"\".typ·2 *byte, @\"\".iface·3 any) (@\"\".ret·1 any)\n"
-	"func @\"\".assertI2I2 (@\"\".typ·3 *byte, @\"\".iface·4 any) (@\"\".ret·1 any, @\"\".ok·2 bool)\n"
-	"func @\"\".assertI2T (@\"\".typ·2 *byte, @\"\".iface·3 any) (@\"\".ret·1 any)\n"
-	"func @\"\".assertI2T2 (@\"\".typ·3 *byte, @\"\".iface·4 any) (@\"\".ret·1 any, @\"\".ok·2 bool)\n"
-	"func @\"\".assertI2TOK (@\"\".typ·2 *byte, @\"\".iface·3 any) (@\"\".ok·1 bool)\n"
-	"func @\"\".assertE2TOK (@\"\".typ·2 *byte, @\"\".iface·3 any) (@\"\".ok·1 bool)\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"
-	"func @\"\".efacethash (@\"\".i1·2 any) (@\"\".ret·1 uint32)\n"
-	"func @\"\".makemap (@\"\".mapType·2 *byte, @\"\".hint·3 int64) (@\"\".hmap·1 map[any]any)\n"
-	"func @\"\".mapaccess1 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 *any) (@\"\".val·1 *any)\n"
-	"func @\"\".mapaccess1_fast32 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 any) (@\"\".val·1 *any)\n"
-	"func @\"\".mapaccess1_fast64 (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 any) (@\"\".val·1 *any)\n"
-	"func @\"\".mapaccess1_faststr (@\"\".mapType·2 *byte, @\"\".hmap·3 map[any]any, @\"\".key·4 any) (@\"\".val·1 *any)\n"
-	"func @\"\".mapaccess2 (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 *any) (@\"\".val·1 *any, @\"\".pres·2 bool)\n"
-	"func @\"\".mapaccess2_fast32 (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 any) (@\"\".val·1 *any, @\"\".pres·2 bool)\n"
-	"func @\"\".mapaccess2_fast64 (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 any) (@\"\".val·1 *any, @\"\".pres·2 bool)\n"
-	"func @\"\".mapaccess2_faststr (@\"\".mapType·3 *byte, @\"\".hmap·4 map[any]any, @\"\".key·5 any) (@\"\".val·1 *any, @\"\".pres·2 bool)\n"
-	"func @\"\".mapassign1 (@\"\".mapType·1 *byte, @\"\".hmap·2 map[any]any, @\"\".key·3 *any, @\"\".val·4 *any)\n"
-	"func @\"\".mapiterinit (@\"\".mapType·1 *byte, @\"\".hmap·2 map[any]any, @\"\".hiter·3 *any)\n"
-	"func @\"\".mapdelete (@\"\".mapType·1 *byte, @\"\".hmap·2 map[any]any, @\"\".key·3 *any)\n"
-	"func @\"\".mapiternext (@\"\".hiter·1 *any)\n"
-	"func @\"\".makechan (@\"\".chanType·2 *byte, @\"\".hint·3 int64) (@\"\".hchan·1 chan any)\n"
-	"func @\"\".chanrecv1 (@\"\".chanType·1 *byte, @\"\".hchan·2 <-chan any, @\"\".elem·3 *any)\n"
-	"func @\"\".chanrecv2 (@\"\".chanType·2 *byte, @\"\".hchan·3 <-chan any, @\"\".elem·4 *any) (? bool)\n"
-	"func @\"\".chansend1 (@\"\".chanType·1 *byte, @\"\".hchan·2 chan<- any, @\"\".elem·3 *any)\n"
-	"func @\"\".closechan (@\"\".hchan·1 any)\n"
-	"func @\"\".writebarrierptr (@\"\".dst·1 *any, @\"\".src·2 any)\n"
-	"func @\"\".writebarrierstring (@\"\".dst·1 *any, @\"\".src·2 any)\n"
-	"func @\"\".writebarrierslice (@\"\".dst·1 *any, @\"\".src·2 any)\n"
-	"func @\"\".writebarrieriface (@\"\".dst·1 *any, @\"\".src·2 any)\n"
-	"func @\"\".writebarrierfat2 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
-	"func @\"\".writebarrierfat3 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
-	"func @\"\".writebarrierfat4 (@\"\".dst·1 *any, _ *byte, @\"\".src·3 any)\n"
-	"func @\"\".writebarrierfat (@\"\".typ·1 *byte, @\"\".dst·2 *any, @\"\".src·3 *any)\n"
-	"func @\"\".selectnbsend (@\"\".chanType·2 *byte, @\"\".hchan·3 chan<- any, @\"\".elem·4 *any) (? bool)\n"
-	"func @\"\".selectnbrecv (@\"\".chanType·2 *byte, @\"\".elem·3 *any, @\"\".hchan·4 <-chan any) (? bool)\n"
-	"func @\"\".selectnbrecv2 (@\"\".chanType·2 *byte, @\"\".elem·3 *any, @\"\".received·4 *bool, @\"\".hchan·5 <-chan any) (? bool)\n"
-	"func @\"\".newselect (@\"\".sel·1 *byte, @\"\".selsize·2 int64, @\"\".size·3 int32)\n"
-	"func @\"\".selectsend (@\"\".sel·2 *byte, @\"\".hchan·3 chan<- any, @\"\".elem·4 *any) (@\"\".selected·1 bool)\n"
-	"func @\"\".selectrecv (@\"\".sel·2 *byte, @\"\".hchan·3 <-chan any, @\"\".elem·4 *any) (@\"\".selected·1 bool)\n"
-	"func @\"\".selectrecv2 (@\"\".sel·2 *byte, @\"\".hchan·3 <-chan any, @\"\".elem·4 *any, @\"\".received·5 *bool) (@\"\".selected·1 bool)\n"
-	"func @\"\".selectdefault (@\"\".sel·2 *byte) (@\"\".selected·1 bool)\n"
-	"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 @\"\".memmove (@\"\".to·1 *any, @\"\".frm·2 *any, @\"\".length·3 uintptr)\n"
-	"func @\"\".memequal (@\"\".x·2 *any, @\"\".y·3 *any, @\"\".size·4 uintptr) (? bool)\n"
-	"func @\"\".memequal8 (@\"\".x·2 *any, @\"\".y·3 *any, @\"\".size·4 uintptr) (? bool)\n"
-	"func @\"\".memequal16 (@\"\".x·2 *any, @\"\".y·3 *any, @\"\".size·4 uintptr) (? bool)\n"
-	"func @\"\".memequal32 (@\"\".x·2 *any, @\"\".y·3 *any, @\"\".size·4 uintptr) (? bool)\n"
-	"func @\"\".memequal64 (@\"\".x·2 *any, @\"\".y·3 *any, @\"\".size·4 uintptr) (? bool)\n"
-	"func @\"\".memequal128 (@\"\".x·2 *any, @\"\".y·3 *any, @\"\".size·4 uintptr) (? bool)\n"
-	"func @\"\".int64div (? int64, ? int64) (? int64)\n"
-	"func @\"\".uint64div (? uint64, ? uint64) (? uint64)\n"
-	"func @\"\".int64mod (? int64, ? int64) (? int64)\n"
-	"func @\"\".uint64mod (? uint64, ? uint64) (? uint64)\n"
-	"func @\"\".float64toint64 (? float64) (? int64)\n"
-	"func @\"\".float64touint64 (? float64) (? uint64)\n"
-	"func @\"\".int64tofloat64 (? int64) (? float64)\n"
-	"func @\"\".uint64tofloat64 (? uint64) (? float64)\n"
-	"func @\"\".complex128div (@\"\".num·2 complex128, @\"\".den·3 complex128) (@\"\".quo·1 complex128)\n"
-	"func @\"\".racefuncenter (? uintptr)\n"
-	"func @\"\".racefuncexit ()\n"
-	"func @\"\".raceread (? uintptr)\n"
-	"func @\"\".racewrite (? uintptr)\n"
-	"func @\"\".racereadrange (@\"\".addr·1 uintptr, @\"\".size·2 uintptr)\n"
-	"func @\"\".racewriterange (@\"\".addr·1 uintptr, @\"\".size·2 uintptr)\n"
-	"\n"
-	"$$\n";
-char *unsafeimport =
-	"package unsafe\n"
-	"import runtime \"runtime\"\n"
-	"type @\"\".Pointer uintptr\n"
-	"func @\"\".Offsetof (? any) (? uintptr)\n"
-	"func @\"\".Sizeof (? any) (? uintptr)\n"
-	"func @\"\".Alignof (? any) (? uintptr)\n"
-	"\n"
-	"$$\n";
diff --git a/src/cmd/gc/bv.c b/src/cmd/gc/bv.c
deleted file mode 100644
index cfd1cd2..0000000
--- a/src/cmd/gc/bv.c
+++ /dev/null
@@ -1,213 +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.
-
-#include <u.h>
-#include <libc.h>
-#include "go.h"
-
-enum {
-	WORDSIZE = sizeof(uint32),
-	WORDBITS = 32,
-	WORDMASK = WORDBITS - 1,
-	WORDSHIFT = 5,
-};
-
-static uintptr
-bvsize(uintptr n)
-{
-	return ((n + WORDBITS - 1) / WORDBITS) * WORDSIZE;
-}
-
-int32
-bvbits(Bvec *bv)
-{
-	return bv->n;
-}
-
-int32
-bvwords(Bvec *bv)
-{
-	return (bv->n + WORDBITS - 1) / WORDBITS;
-}
-
-Bvec*
-bvalloc(int32 n)
-{
-	Bvec *bv;
-	uintptr nbytes;
-
-	if(n < 0)
-		fatal("bvalloc: initial size is negative\n");
-	nbytes = sizeof(Bvec) + bvsize(n);
-	bv = malloc(nbytes);
-	if(bv == nil)
-		fatal("bvalloc: malloc failed\n");
-	memset(bv, 0, nbytes);
-	bv->n = n;
-	return bv;
-}
-
-/* difference */
-void
-bvandnot(Bvec *dst, Bvec *src1, Bvec *src2)
-{
-	int32 i, w;
-
-	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);
-	for(i = 0, w = 0; i < dst->n; i += WORDBITS, w++)
-		dst->b[w] = src1->b[w] & ~src2->b[w];
-}
-
-int
-bvcmp(Bvec *bv1, Bvec *bv2)
-{
-	uintptr nbytes;
-
-	if(bv1->n != bv2->n)
-		fatal("bvequal: lengths %d and %d are not equal", bv1->n, bv2->n);
-	nbytes = bvsize(bv1->n);
-	return memcmp(bv1->b, bv2->b, nbytes);
-}
-
-void
-bvcopy(Bvec *dst, Bvec *src)
-{
-	memmove(dst->b, src->b, bvsize(dst->n));
-}
-
-Bvec*
-bvconcat(Bvec *src1, Bvec *src2)
-{
-	Bvec *dst;
-	int32 i;
-
-	dst = bvalloc(src1->n + src2->n);
-	for(i = 0; i < src1->n; i++)
-		if(bvget(src1, i))
-			bvset(dst, i);
-	for(i = 0; i < src2->n; i++)
-		if(bvget(src2, i))
-			bvset(dst, i + src1->n);
-	return dst;
-}
-
-int
-bvget(Bvec *bv, int32 i)
-{
-	if(i < 0 || i >= bv->n)
-		fatal("bvget: index %d is out of bounds with length %d\n", i, bv->n);
-	return (bv->b[i>>WORDSHIFT] >> (i&WORDMASK)) & 1;
-}
-
-// bvnext returns the smallest index >= i for which bvget(bv, i) == 1.
-// If there is no such index, bvnext returns -1.
-int
-bvnext(Bvec *bv, int32 i)
-{
-	uint32 w;
-
-	if(i >= bv->n)
-		return -1;
-
-	// Jump i ahead to next word with bits.
-	if((bv->b[i>>WORDSHIFT]>>(i&WORDMASK)) == 0) {
-		i &= ~WORDMASK;
-		i += WORDBITS;
-		while(i < bv->n && bv->b[i>>WORDSHIFT] == 0)
-			i += WORDBITS;
-	}
-	if(i >= bv->n)
-		return -1;
-
-	// Find 1 bit.
-	w = bv->b[i>>WORDSHIFT]>>(i&WORDMASK);
-	while((w&1) == 0) {
-		w>>=1;
-		i++;
-	}
-	return i;
-}
-
-int
-bvisempty(Bvec *bv)
-{
-	int32 i;
-
-	for(i = 0; i < bv->n; i += WORDBITS)
-		if(bv->b[i>>WORDSHIFT] != 0)
-			return 0;
-	return 1;
-}
-
-void
-bvnot(Bvec *bv)
-{
-	int32 i, w;
-
-	for(i = 0, w = 0; i < bv->n; i += WORDBITS, w++)
-		bv->b[w] = ~bv->b[w];
-}
-
-/* union */
-void
-bvor(Bvec *dst, Bvec *src1, Bvec *src2)
-{
-	int32 i, w;
-
-	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);
-	for(i = 0, w = 0; i < dst->n; i += WORDBITS, w++)
-		dst->b[w] = src1->b[w] | src2->b[w];
-}
-
-/* intersection */
-void
-bvand(Bvec *dst, Bvec *src1, Bvec *src2)
-{
-	int32 i, w;
-
-	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);
-	for(i = 0, w = 0; i < dst->n; i += WORDBITS, w++)
-		dst->b[w] = src1->b[w] & src2->b[w];
-}
-
-void
-bvprint(Bvec *bv)
-{
-	int32 i;
-
-	print("#*");
-	for(i = 0; i < bv->n; i++)
-		print("%d", bvget(bv, i));
-}
-
-void
-bvreset(Bvec *bv, int32 i)
-{
-	uint32 mask;
-
-	if(i < 0 || i >= bv->n)
-		fatal("bvreset: index %d is out of bounds with length %d\n", i, bv->n);
-	mask = ~(1 << (i % WORDBITS));
-	bv->b[i / WORDBITS] &= mask;
-}
-
-void
-bvresetall(Bvec *bv)
-{
-	memset(bv->b, 0x00, bvsize(bv->n));
-}
-
-void
-bvset(Bvec *bv, int32 i)
-{
-	uint32 mask;
-
-	if(i < 0 || i >= bv->n)
-		fatal("bvset: index %d is out of bounds with length %d\n", i, bv->n);
-	mask = 1U << (i % WORDBITS);
-	bv->b[i / WORDBITS] |= mask;
-}
diff --git a/src/cmd/gc/closure.c b/src/cmd/gc/closure.c
deleted file mode 100644
index ad4e5bd..0000000
--- a/src/cmd/gc/closure.c
+++ /dev/null
@@ -1,467 +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.
-
-/*
- * function literals aka closures
- */
-
-#include <u.h>
-#include <libc.h>
-#include "go.h"
-
-void
-closurehdr(Node *ntype)
-{
-	Node *n, *name, *a;
-	NodeList *l;
-
-	n = nod(OCLOSURE, N, N);
-	n->ntype = ntype;
-	n->funcdepth = funcdepth;
-
-	funchdr(n);
-
-	// steal ntype's argument names and
-	// leave a fresh copy in their place.
-	// references to these variables need to
-	// refer to the variables in the external
-	// function declared below; see walkclosure.
-	n->list = ntype->list;
-	n->rlist = ntype->rlist;
-	ntype->list = nil;
-	ntype->rlist = nil;
-	for(l=n->list; l; l=l->next) {
-		name = l->n->left;
-		if(name)
-			name = newname(name->sym);
-		a = nod(ODCLFIELD, name, l->n->right);
-		a->isddd = l->n->isddd;
-		if(name)
-			name->isddd = a->isddd;
-		ntype->list = list(ntype->list, a);
-	}
-	for(l=n->rlist; l; l=l->next) {
-		name = l->n->left;
-		if(name)
-			name = newname(name->sym);
-		ntype->rlist = list(ntype->rlist, nod(ODCLFIELD, name, l->n->right));
-	}
-}
-
-Node*
-closurebody(NodeList *body)
-{
-	Node *func, *v;
-	NodeList *l;
-
-	if(body == nil)
-		body = list1(nod(OEMPTY, N, N));
-
-	func = curfn;
-	func->nbody = body;
-	func->endlineno = lineno;
-	funcbody(func);
-
-	// closure-specific variables are hanging off the
-	// ordinary ones in the symbol table; see oldname.
-	// unhook them.
-	// make the list of pointers for the closure call.
-	for(l=func->cvars; l; l=l->next) {
-		v = l->n;
-		v->closure->closure = v->outer;
-		v->heapaddr = nod(OADDR, oldname(v->sym), N);
-	}
-
-	return func;
-}
-
-static Node* makeclosure(Node *func);
-
-void
-typecheckclosure(Node *func, int top)
-{
-	Node *oldfn;
-	NodeList *l;
-	Node *v;
-
-	oldfn = curfn;
-	typecheck(&func->ntype, Etype);
-	func->type = func->ntype->type;
-	
-	// Type check the body now, but only if we're inside a function.
-	// At top level (in a variable initialization: curfn==nil) we're not
-	// ready to type check code yet; we'll check it later, because the
-	// underlying closure function we create is added to xtop.
-	if(curfn && func->type != T) {
-		curfn = func;
-		typechecklist(func->nbody, Etop);
-		curfn = oldfn;
-	}
-
-	// type check the & of closed variables outside the closure,
-	// so that the outer frame also grabs them and knows they
-	// escape.
-	func->enter = nil;
-	for(l=func->cvars; l; l=l->next) {
-		v = l->n;
-		if(v->type == T) {
-			// if v->type is nil, it means v looked like it was
-			// going to be used in the closure but wasn't.
-			// this happens because when parsing a, b, c := f()
-			// the a, b, c gets parsed as references to older
-			// a, b, c before the parser figures out this is a
-			// declaration.
-			v->op = 0;
-			continue;
-		}
-		// For a closure that is called in place, but not
-		// inside a go statement, avoid moving variables to the heap.
-		if ((top & (Ecall|Eproc)) == Ecall)
-			v->heapaddr->etype = 1;
-		typecheck(&v->heapaddr, Erv);
-		func->enter = list(func->enter, v->heapaddr);
-		v->heapaddr = N;
-	}
-
-	// Create top-level function 
-	xtop = list(xtop, makeclosure(func));
-}
-
-static Node*
-makeclosure(Node *func)
-{
-	Node *xtype, *v, *addr, *xfunc, *cv;
-	NodeList *l, *body;
-	static int closgen;
-	char *p;
-	vlong offset;
-
-	/*
-	 * wrap body in external function
-	 * that begins by reading closure parameters.
-	 */
-	xtype = nod(OTFUNC, N, N);
-	xtype->list = func->list;
-	xtype->rlist = func->rlist;
-
-	// create the function
-	xfunc = nod(ODCLFUNC, N, N);
-	snprint(namebuf, sizeof namebuf, "func·%.3d", ++closgen);
-	xfunc->nname = newname(lookup(namebuf));
-	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;
-	
-	// declare variables holding addresses taken from closure
-	// and initialize in entry prologue.
-	body = nil;
-	offset = widthptr;
-	xfunc->needctxt = func->cvars != nil;
-	for(l=func->cvars; l; l=l->next) {
-		v = l->n;
-		if(v->op == 0)
-			continue;
-		addr = nod(ONAME, N, N);
-		p = smprint("&%s", v->sym->name);
-		addr->sym = lookup(p);
-		free(p);
-		addr->ntype = nod(OIND, typenod(v->type), N);
-		addr->class = PAUTO;
-		addr->addable = 1;
-		addr->ullman = 1;
-		addr->used = 1;
-		addr->curfn = xfunc;
-		xfunc->dcl = list(xfunc->dcl, addr);
-		v->heapaddr = addr;
-		cv = nod(OCLOSUREVAR, N, N);
-		cv->type = ptrto(v->type);
-		cv->xoffset = offset;
-		body = list(body, nod(OAS, addr, cv));
-		offset += widthptr;
-	}
-	typechecklist(body, Etop);
-	walkstmtlist(body);
-	xfunc->enter = body;
-
-	xfunc->nbody = func->nbody;
-	xfunc->dcl = concat(func->dcl, xfunc->dcl);
-	if(xfunc->nbody == nil)
-		fatal("empty body - won't generate any code");
-	typecheck(&xfunc, Etop);
-
-	xfunc->closure = func;
-	func->closure = xfunc;
-	
-	func->nbody = nil;
-	func->list = nil;
-	func->rlist = nil;
-
-	return xfunc;
-}
-
-Node*
-walkclosure(Node *func, NodeList **init)
-{
-	Node *clos, *typ;
-	NodeList *l;
-	char buf[20];
-	int narg;
-
-	// If no closure vars, don't bother wrapping.
-	if(func->cvars == nil)
-		return func->closure->nname;
-
-	// Create closure in the form of a composite literal.
-	// supposing the closure captures an int i and a string s
-	// and has one float64 argument and no results,
-	// the generated code looks like:
-	//
-	//	clos = &struct{F uintptr; A0 *int; A1 *string}{func·001, &i, &s}
-	//
-	// The use of the struct provides type information to the garbage
-	// collector so that it can walk the closure. We could use (in this case)
-	// [3]unsafe.Pointer instead, but that would leave the gc in the dark.
-	// The information appears in the binary in the form of type descriptors;
-	// the struct is unnamed so that closures in multiple packages with the
-	// same struct type can share the descriptor.
-
-	narg = 0;
-	typ = nod(OTSTRUCT, N, N);
-	typ->list = list1(nod(ODCLFIELD, newname(lookup("F")), typenod(types[TUINTPTR])));
-	for(l=func->cvars; l; l=l->next) {
-		if(l->n->op == 0)
-			continue;
-		snprint(buf, sizeof buf, "A%d", narg++);
-		typ->list = list(typ->list, nod(ODCLFIELD, newname(lookup(buf)), l->n->heapaddr->ntype));
-	}
-
-	clos = nod(OCOMPLIT, N, nod(OIND, typ, N));
-	clos->esc = func->esc;
-	clos->right->implicit = 1;
-	clos->list = concat(list1(nod(OCFUNC, func->closure->nname, N)), func->enter);
-
-	// Force type conversion from *struct to the func type.
-	clos = nod(OCONVNOP, clos, N);
-	clos->type = func->type;
-
-	typecheck(&clos, Erv);
-	// typecheck will insert a PTRLIT node under CONVNOP,
-	// tag it with escape analysis result.
-	clos->left->esc = func->esc;
-	// non-escaping temp to use, if any.
-	// orderexpr did not compute the type; fill it in now.
-	if(func->alloc != N) {
-		func->alloc->type = clos->left->left->type;
-		func->alloc->orig->type = func->alloc->type;
-		clos->left->right = func->alloc;
-		func->alloc = N;
-	}
-	walkexpr(&clos, init);
-
-	return clos;
-}
-
-static Node *makepartialcall(Node*, Type*, Node*);
-
-void
-typecheckpartialcall(Node *fn, Node *sym)
-{
-	switch(fn->op) {
-	case ODOTINTER:
-	case ODOTMETH:
-		break;
-	default:
-		fatal("invalid typecheckpartialcall");
-	}
-
-	// Create top-level function.
-	fn->nname = makepartialcall(fn, fn->type, sym);
-	fn->right = sym;
-	fn->op = OCALLPART;
-	fn->type = fn->nname->type;
-}
-
-static Node*
-makepartialcall(Node *fn, Type *t0, Node *meth)
-{
-	Node *ptr, *n, *fld, *call, *xtype, *xfunc, *cv, *savecurfn;
-	Type *rcvrtype, *basetype, *t;
-	NodeList *body, *l, *callargs, *retargs;
-	char *p;
-	Sym *sym;
-	Pkg *spkg;
-	static Pkg* gopkg;
-	int i, ddd;
-
-	// TODO: names are not right
-	rcvrtype = fn->left->type;
-	if(exportname(meth->sym->name))
-		p = smprint("%-hT.%s·fm", rcvrtype, meth->sym->name);
-	else
-		p = smprint("%-hT.(%-S)·fm", rcvrtype, meth->sym);
-	basetype = rcvrtype;
-	if(isptr[rcvrtype->etype])
-		basetype = basetype->type;
-	if(basetype->etype != TINTER && basetype->sym == S)
-		fatal("missing base type for %T", rcvrtype);
-
-	spkg = nil;
-	if(basetype->sym != S)
-		spkg = basetype->sym->pkg;
-	if(spkg == nil) {
-		if(gopkg == nil)
-			gopkg = mkpkg(strlit("go"));
-		spkg = gopkg;
-	}
-	sym = pkglookup(p, spkg);
-	free(p);
-	if(sym->flags & SymUniq)
-		return sym->def;
-	sym->flags |= SymUniq;
-	
-	savecurfn = curfn;
-	curfn = N;
-
-	xtype = nod(OTFUNC, N, N);
-	i = 0;
-	l = nil;
-	callargs = nil;
-	ddd = 0;
-	xfunc = nod(ODCLFUNC, N, N);
-	curfn = xfunc;
-	for(t = getinargx(t0)->type; t; t = t->down) {
-		snprint(namebuf, sizeof namebuf, "a%d", i++);
-		n = newname(lookup(namebuf));
-		n->class = PPARAM;
-		xfunc->dcl = list(xfunc->dcl, n);
-		callargs = list(callargs, n);
-		fld = nod(ODCLFIELD, n, typenod(t->type));
-		if(t->isddd) {
-			fld->isddd = 1;
-			ddd = 1;
-		}
-		l = list(l, fld);
-	}
-	xtype->list = l;
-	i = 0;
-	l = nil;
-	retargs = nil;
-	for(t = getoutargx(t0)->type; t; t = t->down) {
-		snprint(namebuf, sizeof namebuf, "r%d", i++);
-		n = newname(lookup(namebuf));
-		n->class = PPARAMOUT;
-		xfunc->dcl = list(xfunc->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->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 = nil;
-	xfunc->needctxt = 1;
-	cv = nod(OCLOSUREVAR, N, N);
-	cv->xoffset = widthptr;
-	cv->type = rcvrtype;
-	if(cv->type->align > widthptr)
-		cv->xoffset = cv->type->align;
-	ptr = nod(ONAME, N, N);
-	ptr->sym = lookup("rcvr");
-	ptr->class = PAUTO;
-	ptr->addable = 1;
-	ptr->ullman = 1;
-	ptr->used = 1;
-	ptr->curfn = xfunc;
-	xfunc->dcl = list(xfunc->dcl, ptr);
-	if(isptr[rcvrtype->etype] || isinter(rcvrtype)) {
-		ptr->ntype = typenod(rcvrtype);
-		body = list(body, nod(OAS, ptr, cv));
-	} else {
-		ptr->ntype = typenod(ptrto(rcvrtype));
-		body = list(body, nod(OAS, ptr, nod(OADDR, cv, N)));
-	}
-
-	call = nod(OCALL, nod(OXDOT, ptr, meth), N);
-	call->list = callargs;
-	call->isddd = ddd;
-	if(t0->outtuple == 0) {
-		body = list(body, call);
-	} else {
-		n = nod(OAS2, N, N);
-		n->list = retargs;
-		n->rlist = list1(call);
-		body = list(body, n);
-		n = nod(ORETURN, N, N);
-		body = list(body, n);
-	}
-
-	xfunc->nbody = body;
-
-	typecheck(&xfunc, Etop);
-	sym->def = xfunc;
-	xtop = list(xtop, xfunc);
-	curfn = savecurfn;
-
-	return xfunc;
-}
-
-Node*
-walkpartialcall(Node *n, NodeList **init)
-{
-	Node *clos, *typ;
-
-	// Create closure in the form of a composite literal.
-	// For x.M with receiver (x) type T, the generated code looks like:
-	//
-	//	clos = &struct{F uintptr; R T}{M.T·f, x}
-	//
-	// Like walkclosure above.
-
-	if(isinter(n->left->type)) {
-		// Trigger panic for method on nil interface now.
-		// Otherwise it happens in the wrapper and is confusing.
-		n->left = cheapexpr(n->left, init);
-		checknil(n->left, init);
-	}
-
-	typ = nod(OTSTRUCT, N, N);
-	typ->list = list1(nod(ODCLFIELD, newname(lookup("F")), typenod(types[TUINTPTR])));
-	typ->list = list(typ->list, nod(ODCLFIELD, newname(lookup("R")), typenod(n->left->type)));
-
-	clos = nod(OCOMPLIT, N, nod(OIND, typ, N));
-	clos->esc = n->esc;
-	clos->right->implicit = 1;
-	clos->list = list1(nod(OCFUNC, n->nname->nname, N));
-	clos->list = list(clos->list, n->left);
-
-	// Force type conversion from *struct to the func type.
-	clos = nod(OCONVNOP, clos, N);
-	clos->type = n->type;
-
-	typecheck(&clos, Erv);
-	// typecheck will insert a PTRLIT node under CONVNOP,
-	// tag it with escape analysis result.
-	clos->left->esc = n->esc;
-	// non-escaping temp to use, if any.
-	// orderexpr did not compute the type; fill it in now.
-	if(n->alloc != N) {
-		n->alloc->type = clos->left->left->type;
-		n->alloc->orig->type = n->alloc->type;
-		clos->left->right = n->alloc;
-		n->alloc = N;
-	}
-	walkexpr(&clos, init);
-
-	return clos;
-}
diff --git a/src/cmd/gc/const.c b/src/cmd/gc/const.c
deleted file mode 100644
index e418b9c..0000000
--- a/src/cmd/gc/const.c
+++ /dev/null
@@ -1,1674 +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	<u.h>
-#include	<libc.h>
-#include	"go.h"
-#define	TUP(x,y)	(((x)<<16)|(y))
-/*c2go int TUP(int, int); */
-
-static	Val	tocplx(Val);
-static	Val	toflt(Val);
-static	Val	tostr(Val);
-static	Val	copyval(Val);
-static	void	cmplxmpy(Mpcplx*, Mpcplx*);
-static	void	cmplxdiv(Mpcplx*, Mpcplx*);
-
-/*
- * truncate float literal fv to 32-bit or 64-bit precision
- * according to type; return truncated value.
- */
-Mpflt*
-truncfltlit(Mpflt *oldv, Type *t)
-{
-	double d;
-	Mpflt *fv;
-	Val v;
-
-	if(t == T)
-		return oldv;
-
-	memset(&v, 0, sizeof v);
-	v.ctype = CTFLT;
-	v.u.fval = oldv;
-	overflow(v, t);
-
-	fv = mal(sizeof *fv);
-	*fv = *oldv;
-
-	// convert large precision literal floating
-	// into limited precision (float64 or float32)
-	switch(t->etype) {
-	case TFLOAT64:
-		d = mpgetflt(fv);
-		mpmovecflt(fv, d);
-		break;
-
-	case TFLOAT32:
-		d = mpgetflt32(fv);
-		mpmovecflt(fv, d);
-
-		break;
-	}
-	return fv;
-}
-
-/*
- * convert n, if literal, to type t.
- * implicit conversion.
- */
-void
-convlit(Node **np, Type *t)
-{
-	convlit1(np, t, 0);
-}
-
-/*
- * convert n, if literal, to type t.
- * return a new node if necessary
- * (if n is a named constant, can't edit n->type directly).
- */
-void
-convlit1(Node **np, Type *t, int explicit)
-{
-	int ct, et;
-	Node *n, *nn;
-
-	n = *np;
-	if(n == N || t == T || n->type == T || isideal(t) || n->type == t)
-		return;
-	if(!explicit && !isideal(n->type))
-		return;
-
-	if(n->op == OLITERAL) {
-		nn = nod(OXXX, N, N);
-		*nn = *n;
-		n = nn;
-		*np = n;
-	}
-
-	switch(n->op) {
-	default:
-		if(n->type == idealbool) {
-			if(t->etype == TBOOL)
-				n->type = t;
-			else
-				n->type = types[TBOOL];
-		}
-		if(n->type->etype == TIDEAL) {
-			convlit(&n->left, t);
-			convlit(&n->right, t);
-			n->type = t;
-		}
-		return;
-	case OLITERAL:
-		// target is invalid type for a constant?  leave alone.
-		if(!okforconst[t->etype] && n->type->etype != TNIL) {
-			defaultlit(&n, T);
-			*np = n;
-			return;
-		}
-		break;
-	case OLSH:
-	case ORSH:
-		convlit1(&n->left, t, explicit && isideal(n->left->type));
-		t = n->left->type;
-		if(t != T && t->etype == TIDEAL && n->val.ctype != CTINT)
-			n->val = toint(n->val);
-		if(t != T && !isint[t->etype]) {
-			yyerror("invalid operation: %N (shift of type %T)", n, t);
-			t = T;
-		}
-		n->type = t;
-		return;
-	case OCOMPLEX:
-		if(n->type->etype == TIDEAL) {
-			switch(t->etype) {
-			default:
-				// If trying to convert to non-complex type,
-				// leave as complex128 and let typechecker complain.
-				t = types[TCOMPLEX128];
-				//fallthrough
-			case TCOMPLEX128:
-				n->type = t;
-				convlit(&n->left, types[TFLOAT64]);
-				convlit(&n->right, types[TFLOAT64]);
-				break;
-			case TCOMPLEX64:
-				n->type = t;
-				convlit(&n->left, types[TFLOAT32]);
-				convlit(&n->right, types[TFLOAT32]);
-				break;
-			}
-		}
-		return;
-	}
-
-	// avoided repeated calculations, errors
-	if(eqtype(n->type, t))
-		return;
-
-	ct = consttype(n);
-	if(ct < 0)
-		goto bad;
-
-	et = t->etype;
-	if(et == TINTER) {
-		if(ct == CTNIL && n->type == types[TNIL]) {
-			n->type = t;
-			return;
-		}
-		defaultlit(np, T);
-		return;
-	}
-
-	switch(ct) {
-	default:
-		goto bad;
-
-	case CTNIL:
-		switch(et) {
-		default:
-			n->type = T;
-			goto bad;
-
-		case TSTRING:
-			// let normal conversion code handle it
-			return;
-
-		case TARRAY:
-			if(!isslice(t))
-				goto bad;
-			break;
-
-		case TPTR32:
-		case TPTR64:
-		case TINTER:
-		case TMAP:
-		case TCHAN:
-		case TFUNC:
-		case TUNSAFEPTR:
-			break;
-
-		case TUINTPTR:
-			// A nil literal may be converted to uintptr
-			// if it is an unsafe.Pointer
-			if(n->type->etype == TUNSAFEPTR) {
-				n->val.u.xval = mal(sizeof(*n->val.u.xval));
-				mpmovecfix(n->val.u.xval, 0);
-				n->val.ctype = CTINT;
-			} else
-				goto bad;
-		}
-		break;
-
-	case CTSTR:
-	case CTBOOL:
-		if(et != n->type->etype)
-			goto bad;
-		break;
-
-	case CTINT:
-	case CTRUNE:
-	case CTFLT:
-	case CTCPLX:
-		ct = n->val.ctype;
-		if(isint[et]) {
-			switch(ct) {
-			default:
-				goto bad;
-			case CTCPLX:
-			case CTFLT:
-			case CTRUNE:
-				n->val = toint(n->val);
-				// flowthrough
-			case CTINT:
-				overflow(n->val, t);
-				break;
-			}
-		} else
-		if(isfloat[et]) {
-			switch(ct) {
-			default:
-				goto bad;
-			case CTCPLX:
-			case CTINT:
-			case CTRUNE:
-				n->val = toflt(n->val);
-				// flowthrough
-			case CTFLT:
-				n->val.u.fval = truncfltlit(n->val.u.fval, t);
-				break;
-			}
-		} else
-		if(iscomplex[et]) {
-			switch(ct) {
-			default:
-				goto bad;
-			case CTFLT:
-			case CTINT:
-			case CTRUNE:
-				n->val = tocplx(n->val);
-				break;
-			case CTCPLX:
-				overflow(n->val, t);
-				break;
-			}
-		} else
-		if(et == TSTRING && (ct == CTINT || ct == CTRUNE) && explicit)
-			n->val = tostr(n->val);
-		else
-			goto bad;
-		break;
-	}
-	n->type = t;
-	return;
-
-bad:
-	if(!n->diag) {
-		if(!t->broke)
-			yyerror("cannot convert %N to type %T", n, t);
-		n->diag = 1;
-	}
-	if(isideal(n->type)) {
-		defaultlit(&n, T);
-		*np = n;
-	}
-	return;
-}
-
-static Val
-copyval(Val v)
-{
-	Mpint *i;
-	Mpflt *f;
-	Mpcplx *c;
-
-	switch(v.ctype) {
-	case CTINT:
-	case CTRUNE:
-		i = mal(sizeof(*i));
-		mpmovefixfix(i, v.u.xval);
-		v.u.xval = i;
-		break;
-	case CTFLT:
-		f = mal(sizeof(*f));
-		mpmovefltflt(f, v.u.fval);
-		v.u.fval = f;
-		break;
-	case CTCPLX:
-		c = mal(sizeof(*c));
-		mpmovefltflt(&c->real, &v.u.cval->real);
-		mpmovefltflt(&c->imag, &v.u.cval->imag);
-		v.u.cval = c;
-		break;
-	}
-	return v;
-}
-
-static Val
-tocplx(Val v)
-{
-	Mpcplx *c;
-
-	switch(v.ctype) {
-	case CTINT:
-	case CTRUNE:
-		c = mal(sizeof(*c));
-		mpmovefixflt(&c->real, v.u.xval);
-		mpmovecflt(&c->imag, 0.0);
-		v.ctype = CTCPLX;
-		v.u.cval = c;
-		break;
-	case CTFLT:
-		c = mal(sizeof(*c));
-		mpmovefltflt(&c->real, v.u.fval);
-		mpmovecflt(&c->imag, 0.0);
-		v.ctype = CTCPLX;
-		v.u.cval = c;
-		break;
-	}
-	return v;
-}
-
-static Val
-toflt(Val v)
-{
-	Mpflt *f;
-
-	switch(v.ctype) {
-	case CTINT:
-	case CTRUNE:
-		f = mal(sizeof(*f));
-		mpmovefixflt(f, v.u.xval);
-		v.ctype = CTFLT;
-		v.u.fval = f;
-		break;
-	case CTCPLX:
-		f = mal(sizeof(*f));
-		mpmovefltflt(f, &v.u.cval->real);
-		if(mpcmpfltc(&v.u.cval->imag, 0) != 0)
-			yyerror("constant %#F%+#Fi truncated to real", &v.u.cval->real, &v.u.cval->imag);
-		v.ctype = CTFLT;
-		v.u.fval = f;
-		break;
-	}
-	return v;
-}
-
-Val
-toint(Val v)
-{
-	Mpint *i;
-
-	switch(v.ctype) {
-	case CTRUNE:
-		v.ctype = CTINT;
-		break;
-	case CTFLT:
-		i = mal(sizeof(*i));
-		if(mpmovefltfix(i, v.u.fval) < 0)
-			yyerror("constant %#F truncated to integer", v.u.fval);
-		v.ctype = CTINT;
-		v.u.xval = i;
-		break;
-	case CTCPLX:
-		i = mal(sizeof(*i));
-		if(mpmovefltfix(i, &v.u.cval->real) < 0)
-			yyerror("constant %#F%+#Fi truncated to integer", &v.u.cval->real, &v.u.cval->imag);
-		if(mpcmpfltc(&v.u.cval->imag, 0) != 0)
-			yyerror("constant %#F%+#Fi truncated to real", &v.u.cval->real, &v.u.cval->imag);
-		v.ctype = CTINT;
-		v.u.xval = i;
-		break;
-	}
-	return v;
-}
-
-int
-doesoverflow(Val v, Type *t)
-{
-	switch(v.ctype) {
-	case CTINT:
-	case CTRUNE:
-		if(!isint[t->etype])
-			fatal("overflow: %T integer constant", t);
-		if(mpcmpfixfix(v.u.xval, minintval[t->etype]) < 0 ||
-		   mpcmpfixfix(v.u.xval, maxintval[t->etype]) > 0)
-			return 1;
-		break;
-	case CTFLT:
-		if(!isfloat[t->etype])
-			fatal("overflow: %T floating-point constant", t);
-		if(mpcmpfltflt(v.u.fval, minfltval[t->etype]) <= 0 ||
-		   mpcmpfltflt(v.u.fval, maxfltval[t->etype]) >= 0)
-			return 1;
-		break;
-	case CTCPLX:
-		if(!iscomplex[t->etype])
-			fatal("overflow: %T complex constant", t);
-		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)
-			return 1;
-		break;
-	}
-	return 0;
-}
-
-void
-overflow(Val v, Type *t)
-{
-	// v has already been converted
-	// to appropriate form for t.
-	if(t == T || t->etype == TIDEAL)
-		return;
-
-	if(!doesoverflow(v, t))
-		return;
-
-	switch(v.ctype) {
-	case CTINT:
-	case CTRUNE:
-		yyerror("constant %B overflows %T", v.u.xval, t);
-		break;
-	case CTFLT:
-		yyerror("constant %#F overflows %T", v.u.fval, t);
-		break;
-	case CTCPLX:
-		yyerror("constant %#F overflows %T", v.u.fval, t);
-		break;
-	}
-}
-
-static Val
-tostr(Val v)
-{
-	Rune rune;
-	int l;
-	Strlit *s;
-
-	switch(v.ctype) {
-	case CTINT:
-	case CTRUNE:
-		if(mpcmpfixfix(v.u.xval, minintval[TINT]) < 0 ||
-		   mpcmpfixfix(v.u.xval, maxintval[TINT]) > 0)
-			yyerror("overflow in int -> string");
-		rune = mpgetfix(v.u.xval);
-		l = runelen(rune);
-		s = mal(sizeof(*s)+l);
-		s->len = l;
-		runetochar((char*)s->s, &rune);
-		memset(&v, 0, sizeof v);
-		v.ctype = CTSTR;
-		v.u.sval = s;
-		break;
-
-	case CTFLT:
-		yyerror("no float -> string");
-
-	case CTNIL:
-		memset(&v, 0, sizeof v);
-		v.ctype = CTSTR;
-		v.u.sval = mal(sizeof *s);
-		break;
-	}
-	return v;
-}
-
-int
-consttype(Node *n)
-{
-	if(n == N || n->op != OLITERAL)
-		return -1;
-	return n->val.ctype;
-}
-
-int
-isconst(Node *n, int ct)
-{
-	int t;
-	
-	t = consttype(n);
-	// If the caller is asking for CTINT, allow CTRUNE too.
-	// Makes life easier for back ends.
-	return t == ct || (ct == CTINT && t == CTRUNE);
-}
-
-static Node*
-saveorig(Node *n)
-{
-	Node *n1;
-
-	if(n == n->orig) {
-		// duplicate node for n->orig.
-		n1 = nod(OLITERAL, N, N);
-		n->orig = n1;
-		*n1 = *n;
-	}
-	return n->orig;
-}
-
-/*
- * if n is constant, rewrite as OLITERAL node.
- */
-void
-evconst(Node *n)
-{
-	Node *nl, *nr, *norig;
-	int32 len;
-	Strlit *str;
-	int wl, wr, lno, et;
-	Val v, rv;
-	Mpint b;
-	NodeList *l1, *l2;
-
-	// pick off just the opcodes that can be
-	// constant evaluated.
-	switch(n->op) {
-	default:
-		return;
-	case OADD:
-	case OAND:
-	case OANDAND:
-	case OANDNOT:
-	case OARRAYBYTESTR:
-	case OCOM:
-	case ODIV:
-	case OEQ:
-	case OGE:
-	case OGT:
-	case OLE:
-	case OLSH:
-	case OLT:
-	case OMINUS:
-	case OMOD:
-	case OMUL:
-	case ONE:
-	case ONOT:
-	case OOR:
-	case OOROR:
-	case OPLUS:
-	case ORSH:
-	case OSUB:
-	case OXOR:
-		break;
-	case OCONV:
-		if(n->type == T)
-			return;
-		if(!okforconst[n->type->etype] && n->type->etype != TNIL)
-			return;
-		break;
-	
-	case OADDSTR:
-		// merge adjacent constants in the argument list.
-		for(l1=n->list; l1 != nil; l1= l1->next) {
-			if(isconst(l1->n, CTSTR) && l1->next != nil && isconst(l1->next->n, CTSTR)) {
-				l2 = l1;
-				len = 0;
-				while(l2 != nil && isconst(l2->n, CTSTR)) {
-					nr = l2->n;
-					len += nr->val.u.sval->len;
-					l2 = l2->next;
-				}
-				// merge from l1 up to but not including l2
-				str = mal(sizeof(*str) + len);
-				str->len = len;
-				len = 0;
-				l2 = l1;
-				while(l2 != nil && isconst(l2->n, CTSTR)) {
-					nr = l2->n;
-					memmove(str->s+len, nr->val.u.sval->s, nr->val.u.sval->len);
-					len += nr->val.u.sval->len;
-					l2 = l2->next;
-				}
-				nl = nod(OXXX, N, N);
-				*nl = *l1->n;
-				nl->orig = nl;
-				nl->val.ctype = CTSTR;
-				nl->val.u.sval = str;
-				l1->n = nl;
-				l1->next = l2;
-			}
-		}
-		// fix list end pointer.
-		for(l2=n->list; l2 != nil; l2=l2->next)
-			n->list->end = l2;
-		// collapse single-constant list to single constant.
-		if(count(n->list) == 1 && isconst(n->list->n, CTSTR)) {
-			n->op = OLITERAL;
-			n->val = n->list->n->val;
-		}
-		return;
-	}
-
-	nl = n->left;
-	if(nl == N || nl->type == T)
-		return;
-	if(consttype(nl) < 0)
-		return;
-	wl = nl->type->etype;
-	if(isint[wl] || isfloat[wl] || iscomplex[wl])
-		wl = TIDEAL;
-
-	nr = n->right;
-	if(nr == N)
-		goto unary;
-	if(nr->type == T)
-		return;
-	if(consttype(nr) < 0)
-		return;
-	wr = nr->type->etype;
-	if(isint[wr] || isfloat[wr] || iscomplex[wr])
-		wr = TIDEAL;
-
-	// check for compatible general types (numeric, string, etc)
-	if(wl != wr)
-		goto illegal;
-
-	// check for compatible types.
-	switch(n->op) {
-	default:
-		// ideal const mixes with anything but otherwise must match.
-		if(nl->type->etype != TIDEAL) {
-			defaultlit(&nr, nl->type);
-			n->right = nr;
-		}
-		if(nr->type->etype != TIDEAL) {
-			defaultlit(&nl, nr->type);
-			n->left = nl;
-		}
-		if(nl->type->etype != nr->type->etype)
-			goto illegal;
-		break;
-
-	case OLSH:
-	case ORSH:
-		// right must be unsigned.
-		// left can be ideal.
-		defaultlit(&nr, types[TUINT]);
-		n->right = nr;
-		if(nr->type && (issigned[nr->type->etype] || !isint[nr->type->etype]))
-			goto illegal;
-		if(nl->val.ctype != CTRUNE)
-			nl->val = toint(nl->val);
-		nr->val = toint(nr->val);
-		break;
-	}
-
-	// copy numeric value to avoid modifying
-	// n->left, in case someone still refers to it (e.g. iota).
-	v = nl->val;
-	if(wl == TIDEAL)
-		v = copyval(v);
-
-	rv = nr->val;
-
-	// convert to common ideal
-	if(v.ctype == CTCPLX || rv.ctype == CTCPLX) {
-		v = tocplx(v);
-		rv = tocplx(rv);
-	}
-	if(v.ctype == CTFLT || rv.ctype == CTFLT) {
-		v = toflt(v);
-		rv = toflt(rv);
-	}
-
-	// Rune and int turns into rune.
-	if(v.ctype == CTRUNE && rv.ctype == CTINT)
-		rv.ctype = CTRUNE;
-	if(v.ctype == CTINT && rv.ctype == CTRUNE) {
-		if(n->op == OLSH || n->op == ORSH)
-			rv.ctype = CTINT;
-		else
-			v.ctype = CTRUNE;
-	}
-
-	if(v.ctype != rv.ctype) {
-		// Use of undefined name as constant?
-		if((v.ctype == 0 || rv.ctype == 0) && nerrors > 0)
-			return;
-		fatal("constant type mismatch %T(%d) %T(%d)", nl->type, v.ctype, nr->type, rv.ctype);
-	}
-
-	// run op
-	switch(TUP(n->op, v.ctype)) {
-	default:
-	illegal:
-		if(!n->diag) {
-			yyerror("illegal constant expression: %T %O %T",
-				nl->type, n->op, nr->type);
-			n->diag = 1;
-		}
-		return;
-
-	case TUP(OADD, CTINT):
-	case TUP(OADD, CTRUNE):
-		mpaddfixfix(v.u.xval, rv.u.xval, 0);
-		break;
-	case TUP(OSUB, CTINT):
-	case TUP(OSUB, CTRUNE):
-		mpsubfixfix(v.u.xval, rv.u.xval);
-		break;
-	case TUP(OMUL, CTINT):
-	case TUP(OMUL, CTRUNE):
-		mpmulfixfix(v.u.xval, rv.u.xval);
-		break;
-	case TUP(ODIV, CTINT):
-	case TUP(ODIV, CTRUNE):
-		if(mpcmpfixc(rv.u.xval, 0) == 0) {
-			yyerror("division by zero");
-			mpmovecfix(v.u.xval, 1);
-			break;
-		}
-		mpdivfixfix(v.u.xval, rv.u.xval);
-		break;
-	case TUP(OMOD, CTINT):
-	case TUP(OMOD, CTRUNE):
-		if(mpcmpfixc(rv.u.xval, 0) == 0) {
-			yyerror("division by zero");
-			mpmovecfix(v.u.xval, 1);
-			break;
-		}
-		mpmodfixfix(v.u.xval, rv.u.xval);
-		break;
-
-	case TUP(OLSH, CTINT):
-	case TUP(OLSH, CTRUNE):
-		mplshfixfix(v.u.xval, rv.u.xval);
-		break;
-	case TUP(ORSH, CTINT):
-	case TUP(ORSH, CTRUNE):
-		mprshfixfix(v.u.xval, rv.u.xval);
-		break;
-	case TUP(OOR, CTINT):
-	case TUP(OOR, CTRUNE):
-		mporfixfix(v.u.xval, rv.u.xval);
-		break;
-	case TUP(OAND, CTINT):
-	case TUP(OAND, CTRUNE):
-		mpandfixfix(v.u.xval, rv.u.xval);
-		break;
-	case TUP(OANDNOT, CTINT):
-	case TUP(OANDNOT, CTRUNE):
-		mpandnotfixfix(v.u.xval, rv.u.xval);
-		break;
-	case TUP(OXOR, CTINT):
-	case TUP(OXOR, CTRUNE):
-		mpxorfixfix(v.u.xval, rv.u.xval);
-		break;
-
-	case TUP(OADD, CTFLT):
-		mpaddfltflt(v.u.fval, rv.u.fval);
-		break;
-	case TUP(OSUB, CTFLT):
-		mpsubfltflt(v.u.fval, rv.u.fval);
-		break;
-	case TUP(OMUL, CTFLT):
-		mpmulfltflt(v.u.fval, rv.u.fval);
-		break;
-	case TUP(ODIV, CTFLT):
-		if(mpcmpfltc(rv.u.fval, 0) == 0) {
-			yyerror("division by zero");
-			mpmovecflt(v.u.fval, 1.0);
-			break;
-		}
-		mpdivfltflt(v.u.fval, rv.u.fval);
-		break;
-	case TUP(OMOD, CTFLT):
-		// The default case above would print 'ideal % ideal',
-		// which is not quite an ideal error.
-		if(!n->diag) {
-			yyerror("illegal constant expression: floating-point %% operation");
-			n->diag = 1;
-		}
-		return;
-
-	case TUP(OADD, CTCPLX):
-		mpaddfltflt(&v.u.cval->real, &rv.u.cval->real);
-		mpaddfltflt(&v.u.cval->imag, &rv.u.cval->imag);
-		break;
-	case TUP(OSUB, CTCPLX):
-		mpsubfltflt(&v.u.cval->real, &rv.u.cval->real);
-		mpsubfltflt(&v.u.cval->imag, &rv.u.cval->imag);
-		break;
-	case TUP(OMUL, CTCPLX):
-		cmplxmpy(v.u.cval, rv.u.cval);
-		break;
-	case TUP(ODIV, CTCPLX):
-		if(mpcmpfltc(&rv.u.cval->real, 0) == 0 &&
-		   mpcmpfltc(&rv.u.cval->imag, 0) == 0) {
-			yyerror("complex division by zero");
-			mpmovecflt(&rv.u.cval->real, 1.0);
-			mpmovecflt(&rv.u.cval->imag, 0.0);
-			break;
-		}
-		cmplxdiv(v.u.cval, rv.u.cval);
-		break;
-
-	case TUP(OEQ, CTNIL):
-		goto settrue;
-	case TUP(ONE, CTNIL):
-		goto setfalse;
-
-	case TUP(OEQ, CTINT):
-	case TUP(OEQ, CTRUNE):
-		if(mpcmpfixfix(v.u.xval, rv.u.xval) == 0)
-			goto settrue;
-		goto setfalse;
-	case TUP(ONE, CTINT):
-	case TUP(ONE, CTRUNE):
-		if(mpcmpfixfix(v.u.xval, rv.u.xval) != 0)
-			goto settrue;
-		goto setfalse;
-	case TUP(OLT, CTINT):
-	case TUP(OLT, CTRUNE):
-		if(mpcmpfixfix(v.u.xval, rv.u.xval) < 0)
-			goto settrue;
-		goto setfalse;
-	case TUP(OLE, CTINT):
-	case TUP(OLE, CTRUNE):
-		if(mpcmpfixfix(v.u.xval, rv.u.xval) <= 0)
-			goto settrue;
-		goto setfalse;
-	case TUP(OGE, CTINT):
-	case TUP(OGE, CTRUNE):
-		if(mpcmpfixfix(v.u.xval, rv.u.xval) >= 0)
-			goto settrue;
-		goto setfalse;
-	case TUP(OGT, CTINT):
-	case TUP(OGT, CTRUNE):
-		if(mpcmpfixfix(v.u.xval, rv.u.xval) > 0)
-			goto settrue;
-		goto setfalse;
-
-	case TUP(OEQ, CTFLT):
-		if(mpcmpfltflt(v.u.fval, rv.u.fval) == 0)
-			goto settrue;
-		goto setfalse;
-	case TUP(ONE, CTFLT):
-		if(mpcmpfltflt(v.u.fval, rv.u.fval) != 0)
-			goto settrue;
-		goto setfalse;
-	case TUP(OLT, CTFLT):
-		if(mpcmpfltflt(v.u.fval, rv.u.fval) < 0)
-			goto settrue;
-		goto setfalse;
-	case TUP(OLE, CTFLT):
-		if(mpcmpfltflt(v.u.fval, rv.u.fval) <= 0)
-			goto settrue;
-		goto setfalse;
-	case TUP(OGE, CTFLT):
-		if(mpcmpfltflt(v.u.fval, rv.u.fval) >= 0)
-			goto settrue;
-		goto setfalse;
-	case TUP(OGT, CTFLT):
-		if(mpcmpfltflt(v.u.fval, rv.u.fval) > 0)
-			goto settrue;
-		goto setfalse;
-
-	case TUP(OEQ, CTCPLX):
-		if(mpcmpfltflt(&v.u.cval->real, &rv.u.cval->real) == 0 &&
-		   mpcmpfltflt(&v.u.cval->imag, &rv.u.cval->imag) == 0)
-			goto settrue;
-		goto setfalse;
-	case TUP(ONE, CTCPLX):
-		if(mpcmpfltflt(&v.u.cval->real, &rv.u.cval->real) != 0 ||
-		   mpcmpfltflt(&v.u.cval->imag, &rv.u.cval->imag) != 0)
-			goto settrue;
-		goto setfalse;
-
-	case TUP(OEQ, CTSTR):
-		if(cmpslit(nl, nr) == 0)
-			goto settrue;
-		goto setfalse;
-	case TUP(ONE, CTSTR):
-		if(cmpslit(nl, nr) != 0)
-			goto settrue;
-		goto setfalse;
-	case TUP(OLT, CTSTR):
-		if(cmpslit(nl, nr) < 0)
-			goto settrue;
-		goto setfalse;
-	case TUP(OLE, CTSTR):
-		if(cmpslit(nl, nr) <= 0)
-			goto settrue;
-		goto setfalse;
-	case TUP(OGE, CTSTR):
-		if(cmpslit(nl, nr) >= 0l)
-			goto settrue;
-		goto setfalse;
-	case TUP(OGT, CTSTR):
-		if(cmpslit(nl, nr) > 0)
-			goto settrue;
-		goto setfalse;
-
-	case TUP(OOROR, CTBOOL):
-		if(v.u.bval || rv.u.bval)
-			goto settrue;
-		goto setfalse;
-	case TUP(OANDAND, CTBOOL):
-		if(v.u.bval && rv.u.bval)
-			goto settrue;
-		goto setfalse;
-	case TUP(OEQ, CTBOOL):
-		if(v.u.bval == rv.u.bval)
-			goto settrue;
-		goto setfalse;
-	case TUP(ONE, CTBOOL):
-		if(v.u.bval != rv.u.bval)
-			goto settrue;
-		goto setfalse;
-	}
-	goto ret;
-
-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(TUP(n->op, v.ctype)) {
-	default:
-		if(!n->diag) {
-			yyerror("illegal constant expression %O %T", n->op, nl->type);
-			n->diag = 1;
-		}
-		return;
-
-	case TUP(OCONV, CTNIL):
-	case TUP(OARRAYBYTESTR, CTNIL):
-		if(n->type->etype == TSTRING) {
-			v = tostr(v);
-			nl->type = n->type;
-			break;
-		}
-		// fall through
-	case TUP(OCONV, CTINT):
-	case TUP(OCONV, CTRUNE):
-	case TUP(OCONV, CTFLT):
-	case TUP(OCONV, CTSTR):
-		convlit1(&nl, n->type, 1);
-		v = nl->val;
-		break;
-
-	case TUP(OPLUS, CTINT):
-	case TUP(OPLUS, CTRUNE):
-		break;
-	case TUP(OMINUS, CTINT):
-	case TUP(OMINUS, CTRUNE):
-		mpnegfix(v.u.xval);
-		break;
-	case TUP(OCOM, CTINT):
-	case TUP(OCOM, CTRUNE):
-		et = Txxx;
-		if(nl->type != T)
-			et = nl->type->etype;
-
-		// calculate the mask in b
-		// result will be (a ^ mask)
-		switch(et) {
-		default:
-			// signed guys change sign
-			mpmovecfix(&b, -1);
-			break;
-
-		case TUINT8:
-		case TUINT16:
-		case TUINT32:
-		case TUINT64:
-		case TUINT:
-		case TUINTPTR:
-			// unsigned guys invert their bits
-			mpmovefixfix(&b, maxintval[et]);
-			break;
-		}
-		mpxorfixfix(v.u.xval, &b);
-		break;
-
-	case TUP(OPLUS, CTFLT):
-		break;
-	case TUP(OMINUS, CTFLT):
-		mpnegflt(v.u.fval);
-		break;
-
-	case TUP(OPLUS, CTCPLX):
-		break;
-	case TUP(OMINUS, CTCPLX):
-		mpnegflt(&v.u.cval->real);
-		mpnegflt(&v.u.cval->imag);
-		break;
-
-	case TUP(ONOT, CTBOOL):
-		if(!v.u.bval)
-			goto settrue;
-		goto setfalse;
-	}
-
-ret:
-	norig = saveorig(n);
-	*n = *nl;
-	// restore value of n->orig.
-	n->orig = norig;
-	n->val = v;
-
-	// check range.
-	lno = setlineno(n);
-	overflow(v, n->type);
-	lineno = lno;
-
-	// truncate precision for non-ideal float.
-	if(v.ctype == CTFLT && n->type->etype != TIDEAL)
-		n->val.u.fval = truncfltlit(v.u.fval, n->type);
-	return;
-
-settrue:
-	norig = saveorig(n);
-	*n = *nodbool(1);
-	n->orig = norig;
-	return;
-
-setfalse:
-	norig = saveorig(n);
-	*n = *nodbool(0);
-	n->orig = norig;
-	return;
-}
-
-Node*
-nodlit(Val v)
-{
-	Node *n;
-
-	n = nod(OLITERAL, N, N);
-	n->val = v;
-	switch(v.ctype) {
-	default:
-		fatal("nodlit ctype %d", v.ctype);
-	case CTSTR:
-		n->type = idealstring;
-		break;
-	case CTBOOL:
-		n->type = idealbool;
-		break;
-	case CTINT:
-	case CTRUNE:
-	case CTFLT:
-	case CTCPLX:
-		n->type = types[TIDEAL];
-		break;
-	case CTNIL:
-		n->type = types[TNIL];
-		break;
-	}
-	return n;
-}
-
-Node*
-nodcplxlit(Val r, Val i)
-{
-	Node *n;
-	Mpcplx *c;
-
-	r = toflt(r);
-	i = toflt(i);
-
-	c = mal(sizeof(*c));
-	n = nod(OLITERAL, N, N);
-	n->type = types[TIDEAL];
-	n->val.u.cval = c;
-	n->val.ctype = CTCPLX;
-
-	if(r.ctype != CTFLT || i.ctype != CTFLT)
-		fatal("nodcplxlit ctype %d/%d", r.ctype, i.ctype);
-
-	mpmovefltflt(&c->real, r.u.fval);
-	mpmovefltflt(&c->imag, i.u.fval);
-	return n;
-}
-
-// idealkind returns a constant kind like consttype
-// but for an arbitrary "ideal" (untyped constant) expression.
-static int
-idealkind(Node *n)
-{
-	int k1, k2;
-
-	if(n == N || !isideal(n->type))
-		return CTxxx;
-
-	switch(n->op) {
-	default:
-		return CTxxx;
-	case OLITERAL:
-		return n->val.ctype;
-	case OADD:
-	case OAND:
-	case OANDNOT:
-	case OCOM:
-	case ODIV:
-	case OMINUS:
-	case OMOD:
-	case OMUL:
-	case OSUB:
-	case OXOR:
-	case OOR:
-	case OPLUS:
-		// numeric kinds.
-		k1 = idealkind(n->left);
-		k2 = idealkind(n->right);
-		if(k1 > k2)
-			return k1;
-		else
-			return k2;
-	case OREAL:
-	case OIMAG:
-		return CTFLT;
-	case OCOMPLEX:
-		return CTCPLX;
-	case OADDSTR:
-		return CTSTR;
-	case OANDAND:
-	case OEQ:
-	case OGE:
-	case OGT:
-	case OLE:
-	case OLT:
-	case ONE:
-	case ONOT:
-	case OOROR:
-	case OCMPSTR:
-	case OCMPIFACE:
-		return CTBOOL;
-	case OLSH:
-	case ORSH:
-		// shifts (beware!).
-		return idealkind(n->left);
-	}
-}
-
-void
-defaultlit(Node **np, Type *t)
-{
-	int lno;
-	int ctype;
-	Node *n, *nn;
-	Type *t1;
-
-	n = *np;
-	if(n == N || !isideal(n->type))
-		return;
-
-	if(n->op == OLITERAL) {
-		nn = nod(OXXX, N, N);
-		*nn = *n;
-		n = nn;
-		*np = n;
-	}
-
-	lno = setlineno(n);
-	ctype = idealkind(n);
-	switch(ctype) {
-	default:
-		if(t != T) {
-			convlit(np, t);
-			return;
-		}
-		if(n->val.ctype == CTNIL) {
-			lineno = lno;
-			if(!n->diag) {
-				yyerror("use of untyped nil");
-				n->diag = 1;
-			}
-			n->type = T;
-			break;
-		}
-		if(n->val.ctype == CTSTR) {
-			t1 = types[TSTRING];
-			convlit(np, t1);
-			break;
-		}
-		yyerror("defaultlit: unknown literal: %N", n);
-		break;
-	case CTxxx:
-		fatal("defaultlit: idealkind is CTxxx: %+N", n);
-		break;
-	case CTBOOL:
-		t1 = types[TBOOL];
-		if(t != T && t->etype == TBOOL)
-			t1 = t;
-		convlit(np, t1);
-		break;
-	case CTINT:
-		t1 = types[TINT];
-		goto num;
-	case CTRUNE:
-		t1 = runetype;
-		goto num;
-	case CTFLT:
-		t1 = types[TFLOAT64];
-		goto num;
-	case CTCPLX:
-		t1 = types[TCOMPLEX128];
-		goto num;
-	num:
-		if(t != T) {
-			if(isint[t->etype]) {
-				t1 = t;
-				n->val = toint(n->val);
-			}
-			else
-			if(isfloat[t->etype]) {
-				t1 = t;
-				n->val = toflt(n->val);
-			}
-			else
-			if(iscomplex[t->etype]) {
-				t1 = t;
-				n->val = tocplx(n->val);
-			}
-		}
-		overflow(n->val, t1);
-		convlit(np, t1);
-		break;
-	}
-	lineno = lno;
-}
-
-/*
- * defaultlit on both nodes simultaneously;
- * if they're both ideal going in they better
- * get the same type going out.
- * force means must assign concrete (non-ideal) type.
- */
-void
-defaultlit2(Node **lp, Node **rp, int force)
-{
-	Node *l, *r;
-	int lkind, rkind;
-
-	l = *lp;
-	r = *rp;
-	if(l->type == T || r->type == T)
-		return;
-	if(!isideal(l->type)) {
-		convlit(rp, l->type);
-		return;
-	}
-	if(!isideal(r->type)) {
-		convlit(lp, r->type);
-		return;
-	}
-	if(!force)
-		return;
-	if(l->type->etype == TBOOL) {
-		convlit(lp, types[TBOOL]);
-		convlit(rp, types[TBOOL]);
-	}
-	lkind = idealkind(l);
-	rkind = idealkind(r);
-	if(lkind == CTCPLX || rkind == CTCPLX) {
-		convlit(lp, types[TCOMPLEX128]);
-		convlit(rp, types[TCOMPLEX128]);
-		return;
-	}
-	if(lkind == CTFLT || rkind == CTFLT) {
-		convlit(lp, types[TFLOAT64]);
-		convlit(rp, types[TFLOAT64]);
-		return;
-	}
-
-	if(lkind == CTRUNE || rkind == CTRUNE) {
-		convlit(lp, runetype);
-		convlit(rp, runetype);
-		return;
-	}
-
-	convlit(lp, types[TINT]);
-	convlit(rp, types[TINT]);
-}
-
-int
-cmpslit(Node *l, Node *r)
-{
-	int32 l1, l2, i, m;
-	uchar *s1, *s2;
-
-	l1 = l->val.u.sval->len;
-	l2 = r->val.u.sval->len;
-	s1 = (uchar*)l->val.u.sval->s;
-	s2 = (uchar*)r->val.u.sval->s;
-
-	m = l1;
-	if(l2 < m)
-		m = l2;
-
-	for(i=0; i<m; i++) {
-		if(s1[i] == s2[i])
-			continue;
-		if(s1[i] > s2[i])
-			return +1;
-		return -1;
-	}
-	if(l1 == l2)
-		return 0;
-	if(l1 > l2)
-		return +1;
-	return -1;
-}
-
-int
-smallintconst(Node *n)
-{
-	if(n->op == OLITERAL && isconst(n, CTINT) && n->type != T)
-	switch(simtype[n->type->etype]) {
-	case TINT8:
-	case TUINT8:
-	case TINT16:
-	case TUINT16:
-	case TINT32:
-	case TUINT32:
-	case TBOOL:
-	case TPTR32:
-		return 1;
-	case TIDEAL:
-	case TINT64:
-	case TUINT64:
-	case TPTR64:
-		if(mpcmpfixfix(n->val.u.xval, minintval[TINT32]) < 0
-		|| mpcmpfixfix(n->val.u.xval, maxintval[TINT32]) > 0)
-			break;
-		return 1;
-	}
-	return 0;
-}
-
-long
-nonnegconst(Node *n)
-{
-	if(n->op == OLITERAL && n->type != T)
-	switch(simtype[n->type->etype]) {
-	case TINT8:
-	case TUINT8:
-	case TINT16:
-	case TUINT16:
-	case TINT32:
-	case TUINT32:
-	case TINT64:
-	case TUINT64:
-	case TIDEAL:
-		// check negative and 2^31
-		if(mpcmpfixfix(n->val.u.xval, minintval[TUINT32]) < 0
-		|| mpcmpfixfix(n->val.u.xval, maxintval[TINT32]) > 0)
-			break;
-		return mpgetfix(n->val.u.xval);
-	}
-	return -1;
-}
-
-/*
- * convert x to type et and back to int64
- * for sign extension and truncation.
- */
-static int64
-iconv(int64 x, int et)
-{
-	switch(et) {
-	case TINT8:
-		x = (int8)x;
-		break;
-	case TUINT8:
-		x = (uint8)x;
-		break;
-	case TINT16:
-		x = (int16)x;
-		break;
-	case TUINT16:
-		x = (uint64)x;
-		break;
-	case TINT32:
-		x = (int32)x;
-		break;
-	case TUINT32:
-		x = (uint32)x;
-		break;
-	case TINT64:
-	case TUINT64:
-		break;
-	}
-	return x;
-}
-
-/*
- * convert constant val to type t; leave in con.
- * for back end.
- */
-void
-convconst(Node *con, Type *t, Val *val)
-{
-	int64 i;
-	int tt;
-
-	tt = simsimtype(t);
-
-	// copy the constant for conversion
-	nodconst(con, types[TINT8], 0);
-	con->type = t;
-	con->val = *val;
-
-	if(isint[tt]) {
-		con->val.ctype = CTINT;
-		con->val.u.xval = mal(sizeof *con->val.u.xval);
-		switch(val->ctype) {
-		default:
-			fatal("convconst ctype=%d %lT", val->ctype, t);
-		case CTINT:
-		case CTRUNE:
-			i = mpgetfix(val->u.xval);
-			break;
-		case CTBOOL:
-			i = val->u.bval;
-			break;
-		case CTNIL:
-			i = 0;
-			break;
-		}
-		i = iconv(i, tt);
-		mpmovecfix(con->val.u.xval, i);
-		return;
-	}
-
-	if(isfloat[tt]) {
-		con->val = toflt(con->val);
-		if(con->val.ctype != CTFLT)
-			fatal("convconst ctype=%d %T", con->val.ctype, t);
-		if(tt == TFLOAT32)
-			con->val.u.fval = truncfltlit(con->val.u.fval, t);
-		return;
-	}
-
-	if(iscomplex[tt]) {
-		con->val = tocplx(con->val);
-		if(tt == TCOMPLEX64) {
-			con->val.u.cval->real = *truncfltlit(&con->val.u.cval->real, types[TFLOAT32]);
-			con->val.u.cval->imag = *truncfltlit(&con->val.u.cval->imag, types[TFLOAT32]);
-		}
-		return;
-	}
-
-	fatal("convconst %lT constant", t);
-
-}
-
-// complex multiply v *= rv
-//	(a, b) * (c, d) = (a*c - b*d, b*c + a*d)
-static void
-cmplxmpy(Mpcplx *v, Mpcplx *rv)
-{
-	Mpflt ac, bd, bc, ad;
-
-	mpmovefltflt(&ac, &v->real);
-	mpmulfltflt(&ac, &rv->real);	// ac
-
-	mpmovefltflt(&bd, &v->imag);
-	mpmulfltflt(&bd, &rv->imag);	// bd
-
-	mpmovefltflt(&bc, &v->imag);
-	mpmulfltflt(&bc, &rv->real);	// bc
-
-	mpmovefltflt(&ad, &v->real);
-	mpmulfltflt(&ad, &rv->imag);	// ad
-
-	mpmovefltflt(&v->real, &ac);
-	mpsubfltflt(&v->real, &bd);	// ac-bd
-
-	mpmovefltflt(&v->imag, &bc);
-	mpaddfltflt(&v->imag, &ad);	// bc+ad
-}
-
-// complex divide v /= rv
-//	(a, b) / (c, d) = ((a*c + b*d), (b*c - a*d))/(c*c + d*d)
-static void
-cmplxdiv(Mpcplx *v, Mpcplx *rv)
-{
-	Mpflt ac, bd, bc, ad, cc_plus_dd;
-
-	mpmovefltflt(&cc_plus_dd, &rv->real);
-	mpmulfltflt(&cc_plus_dd, &rv->real);	// cc
-
-	mpmovefltflt(&ac, &rv->imag);
-	mpmulfltflt(&ac, &rv->imag);		// dd
-
-	mpaddfltflt(&cc_plus_dd, &ac);		// cc+dd
-
-	mpmovefltflt(&ac, &v->real);
-	mpmulfltflt(&ac, &rv->real);		// ac
-
-	mpmovefltflt(&bd, &v->imag);
-	mpmulfltflt(&bd, &rv->imag);		// bd
-
-	mpmovefltflt(&bc, &v->imag);
-	mpmulfltflt(&bc, &rv->real);		// bc
-
-	mpmovefltflt(&ad, &v->real);
-	mpmulfltflt(&ad, &rv->imag);		// ad
-
-	mpmovefltflt(&v->real, &ac);
-	mpaddfltflt(&v->real, &bd);		// ac+bd
-	mpdivfltflt(&v->real, &cc_plus_dd);	// (ac+bd)/(cc+dd)
-
-	mpmovefltflt(&v->imag, &bc);
-	mpsubfltflt(&v->imag, &ad);		// bc-ad
-	mpdivfltflt(&v->imag, &cc_plus_dd);	// (bc+ad)/(cc+dd)
-}
-
-static int hascallchan(Node*);
-
-// Is n a Go language constant (as opposed to a compile-time constant)?
-// Expressions derived from nil, like string([]byte(nil)), while they
-// may be known at compile time, are not Go language constants.
-// Only called for expressions known to evaluated to compile-time
-// constants.
-int
-isgoconst(Node *n)
-{
-	Node *l;
-	Type *t;
-
-	if(n->orig != N)
-		n = n->orig;
-
-	switch(n->op) {
-	case OADD:
-	case OADDSTR:
-	case OAND:
-	case OANDAND:
-	case OANDNOT:
-	case OCOM:
-	case ODIV:
-	case OEQ:
-	case OGE:
-	case OGT:
-	case OLE:
-	case OLSH:
-	case OLT:
-	case OMINUS:
-	case OMOD:
-	case OMUL:
-	case ONE:
-	case ONOT:
-	case OOR:
-	case OOROR:
-	case OPLUS:
-	case ORSH:
-	case OSUB:
-	case OXOR:
-	case OIOTA:
-	case OCOMPLEX:
-	case OREAL:
-	case OIMAG:
-		if(isgoconst(n->left) && (n->right == N || isgoconst(n->right)))
-			return 1;
-		break;
-
-	case OCONV:
-		if(okforconst[n->type->etype] && isgoconst(n->left))
-			return 1;
-		break;
-
-	case OLEN:
-	case OCAP:
-		l = n->left;
-		if(isgoconst(l))
-			return 1;
-		// Special case: len/cap is constant when applied to array or
-		// pointer to array when the expression does not contain
-		// function calls or channel receive operations.
-		t = l->type;
-		if(t != T && isptr[t->etype])
-			t = t->type;
-		if(isfixedarray(t) && !hascallchan(l))
-			return 1;
-		break;
-
-	case OLITERAL:
-		if(n->val.ctype != CTNIL)
-			return 1;
-		break;
-
-	case ONAME:
-		l = n->sym->def;
-		if(l && l->op == OLITERAL && n->val.ctype != CTNIL)
-			return 1;
-		break;
-	
-	case ONONAME:
-		if(n->sym->def != N && n->sym->def->op == OIOTA)
-			return 1;
-		break;
-	
-	case OCALL:
-		// Only constant calls are unsafe.Alignof, Offsetof, and Sizeof.
-		l = n->left;
-		while(l->op == OPAREN)
-			l = l->left;
-		if(l->op != ONAME || l->sym->pkg != unsafepkg)
-			break;
-		if(strcmp(l->sym->name, "Alignof") == 0 ||
-		   strcmp(l->sym->name, "Offsetof") == 0 ||
-		   strcmp(l->sym->name, "Sizeof") == 0)
-			return 1;
-		break;		
-	}
-
-	//dump("nonconst", n);
-	return 0;
-}
-
-static int
-hascallchan(Node *n)
-{
-	NodeList *l;
-
-	if(n == N)
-		return 0;
-	switch(n->op) {
-	case OAPPEND:
-	case OCALL:
-	case OCALLFUNC:
-	case OCALLINTER:
-	case OCALLMETH:
-	case OCAP:
-	case OCLOSE:
-	case OCOMPLEX:
-	case OCOPY:
-	case ODELETE:
-	case OIMAG:
-	case OLEN:
-	case OMAKE:
-	case ONEW:
-	case OPANIC:
-	case OPRINT:
-	case OPRINTN:
-	case OREAL:
-	case ORECOVER:
-	case ORECV:
-		return 1;
-	}
-	
-	if(hascallchan(n->left) ||
-	   hascallchan(n->right))
-		return 1;
-	
-	for(l=n->list; l; l=l->next)
-		if(hascallchan(l->n))
-			return 1;
-	for(l=n->rlist; l; l=l->next)
-		if(hascallchan(l->n))
-			return 1;
-
-	return 0;
-}
diff --git a/src/cmd/gc/cplx.c b/src/cmd/gc/cplx.c
deleted file mode 100644
index c9bab7a..0000000
--- a/src/cmd/gc/cplx.c
+++ /dev/null
@@ -1,486 +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 <u.h>
-#include <libc.h>
-#include "gg.h"
-
-static	void	subnode(Node *nr, Node *ni, Node *nc);
-static	void	minus(Node *nl, Node *res);
-	void	complexminus(Node*, Node*);
-	void	complexadd(int op, Node*, Node*, Node*);
-	void	complexmul(Node*, Node*, Node*);
-
-#define	CASE(a,b)	(((a)<<16)|((b)<<0))
-
-static int
-overlap(Node *f, Node *t)
-{
-	// check whether f and t could be overlapping stack references.
-	// not exact, because it's hard to check for the stack register
-	// in portable code.  close enough: worst case we will allocate
-	// an extra temporary and the registerizer will clean it up.
-	return f->op == OINDREG &&
-		t->op == OINDREG &&
-		f->xoffset+f->type->width >= t->xoffset &&
-		t->xoffset+t->type->width >= f->xoffset;
-}
-
-/*
- * generate:
- *	res = n;
- * simplifies and calls gmove.
- */
-void
-complexmove(Node *f, Node *t)
-{
-	int ft, tt;
-	Node n1, n2, n3, n4, tmp;
-
-	if(debug['g']) {
-		dump("\ncomplexmove-f", f);
-		dump("complexmove-t", t);
-	}
-
-	if(!t->addable)
-		fatal("complexmove: to not addable");
-
-	ft = simsimtype(f->type);
-	tt = simsimtype(t->type);
-	switch(CASE(ft,tt)) {
-
-	default:
-		fatal("complexmove: unknown conversion: %T -> %T\n",
-			f->type, t->type);
-
-	case CASE(TCOMPLEX64,TCOMPLEX64):
-	case CASE(TCOMPLEX64,TCOMPLEX128):
-	case CASE(TCOMPLEX128,TCOMPLEX64):
-	case CASE(TCOMPLEX128,TCOMPLEX128):
-		// complex to complex move/convert.
-		// make f addable.
-		// also use temporary if possible stack overlap.
-		if(!f->addable || overlap(f, t)) {
-			tempname(&tmp, f->type);
-			complexmove(f, &tmp);
-			f = &tmp;
-		}
-
-		subnode(&n1, &n2, f);
-		subnode(&n3, &n4, t);
-
-		cgen(&n1, &n3);
-		cgen(&n2, &n4);
-		break;
-	}
-}
-
-int
-complexop(Node *n, Node *res)
-{
-	if(n != N && n->type != T)
-	if(iscomplex[n->type->etype]) {
-		goto maybe;
-	}
-	if(res != N && res->type != T)
-	if(iscomplex[res->type->etype]) {
-		goto maybe;
-	}
-
-	if(n->op == OREAL || n->op == OIMAG)
-		goto yes;
-
-	goto no;
-
-maybe:
-	switch(n->op) {
-	case OCONV:	// implemented ops
-	case OADD:
-	case OSUB:
-	case OMUL:
-	case OMINUS:
-	case OCOMPLEX:
-	case OREAL:
-	case OIMAG:
-		goto yes;
-
-	case ODOT:
-	case ODOTPTR:
-	case OINDEX:
-	case OIND:
-	case ONAME:
-		goto yes;
-	}
-
-no:
-//dump("\ncomplex-no", n);
-	return 0;
-yes:
-//dump("\ncomplex-yes", n);
-	return 1;
-}
-
-void
-complexgen(Node *n, Node *res)
-{
-	Node *nl, *nr;
-	Node tnl, tnr;
-	Node n1, n2, tmp;
-	int tl, tr;
-
-	if(debug['g']) {
-		dump("\ncomplexgen-n", n);
-		dump("complexgen-res", res);
-	}
-	
-	while(n->op == OCONVNOP)
-		n = n->left;
-
-	// pick off float/complex opcodes
-	switch(n->op) {
-	case OCOMPLEX:
-		if(res->addable) {
-			subnode(&n1, &n2, res);
-			tempname(&tmp, n1.type);
-			cgen(n->left, &tmp);
-			cgen(n->right, &n2);
-			cgen(&tmp, &n1);
-			return;
-		}
-		break;
-
-	case OREAL:
-	case OIMAG:
-		nl = n->left;
-		if(!nl->addable) {
-			tempname(&tmp, nl->type);
-			complexgen(nl, &tmp);
-			nl = &tmp;
-		}
-		subnode(&n1, &n2, nl);
-		if(n->op == OREAL) {
-			cgen(&n1, res);
-			return;
-		}
-		cgen(&n2, res);
-		return;
-	}
-
-	// perform conversion from n to res
-	tl = simsimtype(res->type);
-	tl = cplxsubtype(tl);
-	tr = simsimtype(n->type);
-	tr = cplxsubtype(tr);
-	if(tl != tr) {
-		if(!n->addable) {
-			tempname(&n1, n->type);
-			complexmove(n, &n1);
-			n = &n1;
-		}
-		complexmove(n, res);
-		return;
-	}
-
-	if(!res->addable) {
-		igen(res, &n1, N);
-		cgen(n, &n1);
-		regfree(&n1);
-		return;
-	}
-	if(n->addable) {
-		complexmove(n, res);
-		return;
-	}
-
-	switch(n->op) {
-	default:
-		dump("complexgen: unknown op", n);
-		fatal("complexgen: unknown op %O", n->op);
-
-	case ODOT:
-	case ODOTPTR:
-	case OINDEX:
-	case OIND:
-	case ONAME:	// PHEAP or PPARAMREF var
-	case OCALLFUNC:
-	case OCALLMETH:
-	case OCALLINTER:
-		igen(n, &n1, res);
-		complexmove(&n1, res);
-		regfree(&n1);
-		return;
-
-	case OCONV:
-	case OADD:
-	case OSUB:
-	case OMUL:
-	case OMINUS:
-	case OCOMPLEX:
-	case OREAL:
-	case OIMAG:
-		break;
-	}
-
-	nl = n->left;
-	if(nl == N)
-		return;
-	nr = n->right;
-
-	// make both sides addable in ullman order
-	if(nr != N) {
-		if(nl->ullman > nr->ullman && !nl->addable) {
-			tempname(&tnl, nl->type);
-			cgen(nl, &tnl);
-			nl = &tnl;
-		}
-		if(!nr->addable) {
-			tempname(&tnr, nr->type);
-			cgen(nr, &tnr);
-			nr = &tnr;
-		}
-	}
-	if(!nl->addable) {
-		tempname(&tnl, nl->type);
-		cgen(nl, &tnl);
-		nl = &tnl;
-	}
-
-	switch(n->op) {
-	default:
-		fatal("complexgen: unknown op %O", n->op);
-		break;
-
-	case OCONV:
-		complexmove(nl, res);
-		break;
-
-	case OMINUS:
-		complexminus(nl, res);
-		break;
-
-	case OADD:
-	case OSUB:
-		complexadd(n->op, nl, nr, res);
-		break;
-
-	case OMUL:
-		complexmul(nl, nr, res);
-		break;
-	}
-}
-
-void
-complexbool(int op, Node *nl, Node *nr, int true, int likely, Prog *to)
-{
-	Node tnl, tnr;
-	Node n1, n2, n3, n4;
-	Node na, nb, nc;
-
-	// make both sides addable in ullman order
-	if(nr != N) {
-		if(nl->ullman > nr->ullman && !nl->addable) {
-			tempname(&tnl, nl->type);
-			cgen(nl, &tnl);
-			nl = &tnl;
-		}
-		if(!nr->addable) {
-			tempname(&tnr, nr->type);
-			cgen(nr, &tnr);
-			nr = &tnr;
-		}
-	}
-	if(!nl->addable) {
-		tempname(&tnl, nl->type);
-		cgen(nl, &tnl);
-		nl = &tnl;
-	}
-
-	// build tree
-	// real(l) == real(r) && imag(l) == imag(r)
-
-	subnode(&n1, &n2, nl);
-	subnode(&n3, &n4, nr);
-
-	memset(&na, 0, sizeof(na));
-	na.op = OANDAND;
-	na.left = &nb;
-	na.right = &nc;
-	na.type = types[TBOOL];
-
-	memset(&nb, 0, sizeof(na));
-	nb.op = OEQ;
-	nb.left = &n1;
-	nb.right = &n3;
-	nb.type = types[TBOOL];
-
-	memset(&nc, 0, sizeof(na));
-	nc.op = OEQ;
-	nc.left = &n2;
-	nc.right = &n4;
-	nc.type = types[TBOOL];
-
-	if(op == ONE)
-		true = !true;
-
-	bgen(&na, true, likely, to);
-}
-
-void
-nodfconst(Node *n, Type *t, Mpflt* fval)
-{
-	memset(n, 0, sizeof(*n));
-	n->op = OLITERAL;
-	n->addable = 1;
-	ullmancalc(n);
-	n->val.u.fval = fval;
-	n->val.ctype = CTFLT;
-	n->type = t;
-
-	if(!isfloat[t->etype])
-		fatal("nodfconst: bad type %T", t);
-}
-
-// break addable nc-complex into nr-real and ni-imaginary
-static void
-subnode(Node *nr, Node *ni, Node *nc)
-{
-	int tc;
-	Type *t;
-
-	if(!nc->addable)
-		fatal("subnode not addable");
-
-	tc = simsimtype(nc->type);
-	tc = cplxsubtype(tc);
-	t = types[tc];
-
-	if(nc->op == OLITERAL) {
-		nodfconst(nr, t, &nc->val.u.cval->real);
-		nodfconst(ni, t, &nc->val.u.cval->imag);
-		return;
-	}
-
-	*nr = *nc;
-	nr->type = t;
-
-	*ni = *nc;
-	ni->type = t;
-	ni->xoffset += t->width;
-}
-
-// generate code res = -nl
-static void
-minus(Node *nl, Node *res)
-{
-	Node ra;
-
-	memset(&ra, 0, sizeof(ra));
-	ra.op = OMINUS;
-	ra.left = nl;
-	ra.type = nl->type;
-	cgen(&ra, res);
-}
-
-// build and execute tree
-//	real(res) = -real(nl)
-//	imag(res) = -imag(nl)
-void
-complexminus(Node *nl, Node *res)
-{
-	Node n1, n2, n5, n6;
-
-	subnode(&n1, &n2, nl);
-	subnode(&n5, &n6, res);
-
-	minus(&n1, &n5);
-	minus(&n2, &n6);
-}
-
-
-// build and execute tree
-//	real(res) = real(nl) op real(nr)
-//	imag(res) = imag(nl) op imag(nr)
-void
-complexadd(int op, Node *nl, Node *nr, Node *res)
-{
-	Node n1, n2, n3, n4, n5, n6;
-	Node ra;
-
-	subnode(&n1, &n2, nl);
-	subnode(&n3, &n4, nr);
-	subnode(&n5, &n6, res);
-
-	memset(&ra, 0, sizeof(ra));
-	ra.op = op;
-	ra.left = &n1;
-	ra.right = &n3;
-	ra.type = n1.type;
-	cgen(&ra, &n5);
-
-	memset(&ra, 0, sizeof(ra));
-	ra.op = op;
-	ra.left = &n2;
-	ra.right = &n4;
-	ra.type = n2.type;
-	cgen(&ra, &n6);
-}
-
-// build and execute tree
-//	tmp       = real(nl)*real(nr) - imag(nl)*imag(nr)
-//	imag(res) = real(nl)*imag(nr) + imag(nl)*real(nr)
-//	real(res) = tmp
-void
-complexmul(Node *nl, Node *nr, Node *res)
-{
-	Node n1, n2, n3, n4, n5, n6;
-	Node rm1, rm2, ra, tmp;
-
-	subnode(&n1, &n2, nl);
-	subnode(&n3, &n4, nr);
-	subnode(&n5, &n6, res);
-	tempname(&tmp, n5.type);
-
-	// real part -> tmp
-	memset(&rm1, 0, sizeof(ra));
-	rm1.op = OMUL;
-	rm1.left = &n1;
-	rm1.right = &n3;
-	rm1.type = n1.type;
-
-	memset(&rm2, 0, sizeof(ra));
-	rm2.op = OMUL;
-	rm2.left = &n2;
-	rm2.right = &n4;
-	rm2.type = n2.type;
-
-	memset(&ra, 0, sizeof(ra));
-	ra.op = OSUB;
-	ra.left = &rm1;
-	ra.right = &rm2;
-	ra.type = rm1.type;
-	cgen(&ra, &tmp);
-
-	// imag part
-	memset(&rm1, 0, sizeof(ra));
-	rm1.op = OMUL;
-	rm1.left = &n1;
-	rm1.right = &n4;
-	rm1.type = n1.type;
-
-	memset(&rm2, 0, sizeof(ra));
-	rm2.op = OMUL;
-	rm2.left = &n2;
-	rm2.right = &n3;
-	rm2.type = n2.type;
-
-	memset(&ra, 0, sizeof(ra));
-	ra.op = OADD;
-	ra.left = &rm1;
-	ra.right = &rm2;
-	ra.type = rm1.type;
-	cgen(&ra, &n6);
-
-	// tmp ->real part
-	cgen(&tmp, &n5);
-}
diff --git a/src/cmd/gc/dcl.c b/src/cmd/gc/dcl.c
deleted file mode 100644
index dfcf475..0000000
--- a/src/cmd/gc/dcl.c
+++ /dev/null
@@ -1,1494 +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	<u.h>
-#include	<libc.h>
-#include	"go.h"
-#include	"y.tab.h"
-
-static	void	funcargs(Node*);
-static	void	funcargs2(Type*);
-
-static int
-dflag(void)
-{
-	if(!debug['d'])
-		return 0;
-	if(debug['y'])
-		return 1;
-	if(incannedimport)
-		return 0;
-	return 1;
-}
-
-/*
- * declaration stack & operations
- */
-
-static void
-dcopy(Sym *a, Sym *b)
-{
-	a->pkg = b->pkg;
-	a->name = b->name;
-	a->def = b->def;
-	a->block = b->block;
-	a->lastlineno = b->lastlineno;
-}
-
-static Sym*
-push(void)
-{
-	Sym *d;
-
-	d = mal(sizeof(*d));
-	d->lastlineno = lineno;
-	d->link = dclstack;
-	dclstack = d;
-	return d;
-}
-
-static Sym*
-pushdcl(Sym *s)
-{
-	Sym *d;
-
-	d = push();
-	dcopy(d, s);
-	if(dflag())
-		print("\t%L push %S %p\n", lineno, s, s->def);
-	return d;
-}
-
-void
-popdcl(void)
-{
-	Sym *d, *s;
-	int lno;
-
-//	if(dflag())
-//		print("revert\n");
-
-	for(d=dclstack; d!=S; d=d->link) {
-		if(d->name == nil)
-			break;
-		s = pkglookup(d->name, d->pkg);
-		lno = s->lastlineno;
-		dcopy(s, d);
-		d->lastlineno = lno;
-		if(dflag())
-			print("\t%L pop %S %p\n", lineno, s, s->def);
-	}
-	if(d == S)
-		fatal("popdcl: no mark");
-	dclstack = d->link;
-	block = d->block;
-}
-
-void
-poptodcl(void)
-{
-	// pop the old marker and push a new one
-	// (cannot reuse the existing one)
-	// because we use the markers to identify blocks
-	// for the goto restriction checks.
-	popdcl();
-	markdcl();
-}
-
-void
-markdcl(void)
-{
-	Sym *d;
-
-	d = push();
-	d->name = nil;		// used as a mark in fifo
-	d->block = block;
-
-	blockgen++;
-	block = blockgen;
-
-//	if(dflag())
-//		print("markdcl\n");
-}
-
-void
-dumpdcl(char *st)
-{
-	Sym *s, *d;
-	int i;
-
-	USED(st);
-
-	i = 0;
-	for(d=dclstack; d!=S; d=d->link) {
-		i++;
-		print("    %.2d %p", i, d);
-		if(d->name == nil) {
-			print("\n");
-			continue;
-		}
-		print(" '%s'", d->name);
-		s = pkglookup(d->name, d->pkg);
-		print(" %S\n", s);
-	}
-}
-
-void
-testdclstack(void)
-{
-	Sym *d;
-
-	for(d=dclstack; d!=S; d=d->link) {
-		if(d->name == nil) {
-			if(nerrors != 0)
-				errorexit();
-			yyerror("mark left on the stack");
-			continue;
-		}
-	}
-}
-
-void
-redeclare(Sym *s, char *where)
-{
-	Strlit *pkgstr;
-	int line1, line2;
-
-	if(s->lastlineno == 0) {
-		pkgstr = s->origpkg ? s->origpkg->path : s->pkg->path;
-		yyerror("%S redeclared %s\n"
-			"\tprevious declaration during import \"%Z\"",
-			s, where, pkgstr);
-	} else {
-		line1 = parserline();
-		line2 = s->lastlineno;
-		
-		// When an import and a declaration collide in separate files,
-		// present the import as the "redeclared", because the declaration
-		// is visible where the import is, but not vice versa.
-		// See issue 4510.
-		if(s->def == N) {
-			line2 = line1;
-			line1 = s->lastlineno;
-		}
-
-		yyerrorl(line1, "%S redeclared %s\n"
-			"\tprevious declaration at %L",
-			s, where, line2);
-	}
-}
-
-static int vargen;
-
-/*
- * declare individual names - var, typ, const
- */
-void
-declare(Node *n, int ctxt)
-{
-	Sym *s;
-	int gen;
-	static int typegen;
-	
-	if(ctxt == PDISCARD)
-		return;
-
-	if(isblank(n))
-		return;
-
-	n->lineno = parserline();
-	s = n->sym;
-
-	// kludgy: typecheckok means we're past parsing.  Eg genwrapper may declare out of package names later.
-	if(importpkg == nil && !typecheckok && s->pkg != localpkg)
-		yyerror("cannot declare name %S", s);
-
-	if(ctxt == PEXTERN && strcmp(s->name, "init") == 0)
-		yyerror("cannot declare init - must be func", s);
-
-	gen = 0;
-	if(ctxt == PEXTERN) {
-		externdcl = list(externdcl, n);
-		if(dflag())
-			print("\t%L global decl %S %p\n", lineno, s, n);
-	} else {
-		if(curfn == nil && ctxt == PAUTO)
-			fatal("automatic outside function");
-		if(curfn != nil)
-			curfn->dcl = list(curfn->dcl, n);
-		if(n->op == OTYPE)
-			gen = ++typegen;
-		else if(n->op == ONAME && ctxt == PAUTO && strstr(s->name, "·") == nil)
-			gen = ++vargen;
-		pushdcl(s);
-		n->curfn = curfn;
-	}
-	if(ctxt == PAUTO)
-		n->xoffset = 0;
-
-	if(s->block == block) {
-		// functype will print errors about duplicate function arguments.
-		// Don't repeat the error here.
-		if(ctxt != PPARAM && ctxt != PPARAMOUT)
-			redeclare(s, "in this block");
-	}
-
-	s->block = block;
-	s->lastlineno = parserline();
-	s->def = n;
-	n->vargen = gen;
-	n->funcdepth = funcdepth;
-	n->class = ctxt;
-
-	autoexport(n, ctxt);
-}
-
-void
-addvar(Node *n, Type *t, int ctxt)
-{
-	if(n==N || n->sym == S || (n->op != ONAME && n->op != ONONAME) || t == T)
-		fatal("addvar: n=%N t=%T nil", n, t);
-
-	n->op = ONAME;
-	declare(n, ctxt);
-	n->type = t;
-}
-
-/*
- * declare variables from grammar
- * new_name_list (type | [type] = expr_list)
- */
-NodeList*
-variter(NodeList *vl, Node *t, NodeList *el)
-{
-	int doexpr;
-	Node *v, *e, *as2;
-	NodeList *init;
-
-	init = nil;
-	doexpr = el != nil;
-
-	if(count(el) == 1 && count(vl) > 1) {
-		e = el->n;
-		as2 = nod(OAS2, N, N);
-		as2->list = vl;
-		as2->rlist = list1(e);
-		for(; vl; vl=vl->next) {
-			v = vl->n;
-			v->op = ONAME;
-			declare(v, dclcontext);
-			v->ntype = t;
-			v->defn = as2;
-			if(funcdepth > 0)
-				init = list(init, nod(ODCL, v, N));
-		}
-		return list(init, as2);
-	}
-	
-	for(; vl; vl=vl->next) {
-		if(doexpr) {
-			if(el == nil) {
-				yyerror("missing expression in var declaration");
-				break;
-			}
-			e = el->n;
-			el = el->next;
-		} else
-			e = N;
-
-		v = vl->n;
-		v->op = ONAME;
-		declare(v, dclcontext);
-		v->ntype = t;
-
-		if(e != N || funcdepth > 0 || isblank(v)) {
-			if(funcdepth > 0)
-				init = list(init, nod(ODCL, v, N));
-			e = nod(OAS, v, e);
-			init = list(init, e);
-			if(e->right != N)
-				v->defn = e;
-		}
-	}
-	if(el != nil)
-		yyerror("extra expression in var declaration");
-	return init;
-}
-
-/*
- * declare constants from grammar
- * new_name_list [[type] = expr_list]
- */
-NodeList*
-constiter(NodeList *vl, Node *t, NodeList *cl)
-{
-	Node *v, *c;
-	NodeList *vv;
-
-	vv = nil;
-	if(cl == nil) {
-		if(t != N)
-			yyerror("const declaration cannot have type without expression");
-		cl = lastconst;
-		t = lasttype;
-	} else {
-		lastconst = cl;
-		lasttype = t;
-	}
-	cl = listtreecopy(cl);
-
-	for(; vl; vl=vl->next) {
-		if(cl == nil) {
-			yyerror("missing value in const declaration");
-			break;
-		}
-		c = cl->n;
-		cl = cl->next;
-
-		v = vl->n;
-		v->op = OLITERAL;
-		declare(v, dclcontext);
-
-		v->ntype = t;
-		v->defn = c;
-
-		vv = list(vv, nod(ODCLCONST, v, N));
-	}
-	if(cl != nil)
-		yyerror("extra expression in const declaration");
-	iota += 1;
-	return vv;
-}
-
-/*
- * this generates a new name node,
- * typically for labels or other one-off names.
- */
-Node*
-newname(Sym *s)
-{
-	Node *n;
-
-	if(s == S)
-		fatal("newname nil");
-
-	n = nod(ONAME, N, N);
-	n->sym = s;
-	n->type = T;
-	n->addable = 1;
-	n->ullman = 1;
-	n->xoffset = 0;
-	return n;
-}
-
-/*
- * this generates a new name node for a name
- * being declared.
- */
-Node*
-dclname(Sym *s)
-{
-	Node *n;
-
-	n = newname(s);
-	n->op = ONONAME;	// caller will correct it
-	return n;
-}
-
-Node*
-typenod(Type *t)
-{
-	// if we copied another type with *t = *u
-	// then t->nod might be out of date, so
-	// check t->nod->type too
-	if(t->nod == N || t->nod->type != t) {
-		t->nod = nod(OTYPE, N, N);
-		t->nod->type = t;
-		t->nod->sym = t->sym;
-	}
-	return t->nod;
-}
-
-
-/*
- * this will return an old name
- * that has already been pushed on the
- * declaration list. a diagnostic is
- * generated if no name has been defined.
- */
-Node*
-oldname(Sym *s)
-{
-	Node *n;
-	Node *c;
-
-	n = s->def;
-	if(n == N) {
-		// maybe a top-level name will come along
-		// to give this a definition later.
-		// walkdef will check s->def again once
-		// all the input source has been processed.
-		n = newname(s);
-		n->op = ONONAME;
-		n->iota = iota;	// save current iota value in const declarations
-	}
-	if(curfn != nil && n->funcdepth > 0 && n->funcdepth != funcdepth && n->op == ONAME) {
-		// inner func is referring to var in outer func.
-		//
-		// TODO(rsc): If there is an outer variable x and we
-		// are parsing x := 5 inside the closure, until we get to
-		// the := it looks like a reference to the outer x so we'll
-		// make x a closure variable unnecessarily.
-		if(n->closure == N || n->closure->funcdepth != funcdepth) {
-			// create new closure var.
-			c = nod(ONAME, N, N);
-			c->sym = s;
-			c->class = PPARAMREF;
-			c->isddd = n->isddd;
-			c->defn = n;
-			c->addable = 0;
-			c->ullman = 2;
-			c->funcdepth = funcdepth;
-			c->outer = n->closure;
-			n->closure = c;
-			n->addrtaken = 1;
-			c->closure = n;
-			c->xoffset = 0;
-			curfn->cvars = list(curfn->cvars, c);
-		}
-		// return ref to closure var, not original
-		return n->closure;
-	}
-	return n;
-}
-
-/*
- * := declarations
- */
-
-static int
-colasname(Node *n)
-{
-	switch(n->op) {
-	case ONAME:
-	case ONONAME:
-	case OPACK:
-	case OTYPE:
-	case OLITERAL:
-		return n->sym != S;
-	}
-	return 0;
-}
-
-void
-colasdefn(NodeList *left, Node *defn)
-{
-	int nnew, nerr;
-	NodeList *l;
-	Node *n;
-
-	for(l=left; l; l=l->next)
-		if(l->n->sym != S)
-			l->n->sym->flags |= SymUniq;
-
-	nnew = 0;
-	nerr = 0;
-	for(l=left; l; l=l->next) {
-		n = l->n;
-		if(isblank(n))
-			continue;
-		if(!colasname(n)) {
-			yyerrorl(defn->lineno, "non-name %N on left side of :=", n);
-			nerr++;
-			continue;
-		}
-		if((n->sym->flags & SymUniq) == 0) {
-			yyerrorl(defn->lineno, "%S repeated on left side of :=", n->sym);
-			n->diag++;
-			nerr++;
-			continue;
-		}
-		n->sym->flags &= ~SymUniq;
-		if(n->sym->block == block)
-			continue;
-
-		nnew++;
-		n = newname(n->sym);
-		declare(n, dclcontext);
-		n->defn = defn;
-		defn->ninit = list(defn->ninit, nod(ODCL, n, N));
-		l->n = n;
-	}
-	if(nnew == 0 && nerr == 0)
-		yyerrorl(defn->lineno, "no new variables on left side of :=");
-}
-
-Node*
-colas(NodeList *left, NodeList *right, int32 lno)
-{
-	Node *as;
-
-	as = nod(OAS2, N, N);
-	as->list = left;
-	as->rlist = right;
-	as->colas = 1;
-	as->lineno = lno;
-	colasdefn(left, as);
-
-	// make the tree prettier; not necessary
-	if(count(left) == 1 && count(right) == 1) {
-		as->left = as->list->n;
-		as->right = as->rlist->n;
-		as->list = nil;
-		as->rlist = nil;
-		as->op = OAS;
-	}
-
-	return as;
-}
-
-/*
- * declare the arguments in an
- * interface field declaration.
- */
-void
-ifacedcl(Node *n)
-{
-	if(n->op != ODCLFIELD || n->right == N)
-		fatal("ifacedcl");
-
-	if(isblank(n->left))
-		yyerror("methods must have a unique non-blank name");
-
-	dclcontext = PPARAM;
-	markdcl();
-	funcdepth++;
-	n->outer = curfn;
-	curfn = n;
-	funcargs(n->right);
-
-	// funcbody is normally called after the parser has
-	// seen the body of a function but since an interface
-	// field declaration does not have a body, we must
-	// call it now to pop the current declaration context.
-	dclcontext = PAUTO;
-	funcbody(n);
-}
-
-/*
- * declare the function proper
- * and declare the arguments.
- * called in extern-declaration context
- * returns in auto-declaration context.
- */
-void
-funchdr(Node *n)
-{
-	// change the declaration context from extern to auto
-	if(funcdepth == 0 && dclcontext != PEXTERN)
-		fatal("funchdr: dclcontext");
-
-	dclcontext = PAUTO;
-	markdcl();
-	funcdepth++;
-
-	n->outer = curfn;
-	curfn = n;
-
-	if(n->nname)
-		funcargs(n->nname->ntype);
-	else if (n->ntype)
-		funcargs(n->ntype);
-	else
-		funcargs2(n->type);
-}
-
-static void
-funcargs(Node *nt)
-{
-	Node *n, *nn;
-	NodeList *l;
-	int gen;
-
-	if(nt->op != OTFUNC)
-		fatal("funcargs %O", nt->op);
-
-	// re-start the variable generation number
-	// we want to use small numbers for the return variables,
-	// so let them have the chunk starting at 1.
-	vargen = count(nt->rlist);
-
-	// declare the receiver and in arguments.
-	// no n->defn because type checking of func header
-	// will not fill in the types until later
-	if(nt->left != N) {
-		n = nt->left;
-		if(n->op != ODCLFIELD)
-			fatal("funcargs receiver %O", n->op);
-		if(n->left != N) {
-			n->left->op = ONAME;
-			n->left->ntype = n->right;
-			declare(n->left, PPARAM);
-			if(dclcontext == PAUTO)
-				n->left->vargen = ++vargen;
-		}
-	}
-	for(l=nt->list; l; l=l->next) {
-		n = l->n;
-		if(n->op != ODCLFIELD)
-			fatal("funcargs in %O", n->op);
-		if(n->left != N) {
-			n->left->op = ONAME;
-			n->left->ntype = n->right;
-			declare(n->left, PPARAM);
-			if(dclcontext == PAUTO)
-				n->left->vargen = ++vargen;
-		}
-	}
-
-	// declare the out arguments.
-	gen = count(nt->list);
-	int i = 0;
-	for(l=nt->rlist; l; l=l->next) {
-		n = l->n;
-
-		if(n->op != ODCLFIELD)
-			fatal("funcargs out %O", n->op);
-
-		if(n->left == N) {
-			// Name so that escape analysis can track it. ~r stands for 'result'.
-			snprint(namebuf, sizeof(namebuf), "~r%d", gen++);
-			n->left = newname(lookup(namebuf));
-			// TODO: n->left->missing = 1;
-		} 
-
-		n->left->op = ONAME;
-
-		if(isblank(n->left)) {
-			// Give it a name so we can assign to it during return. ~b stands for 'blank'.
-			// The name must be different from ~r above because if you have
-			//	func f() (_ int)
-			//	func g() int
-			// f is allowed to use a plain 'return' with no arguments, while g is not.
-			// So the two cases must be distinguished.
-			// We do not record a pointer to the original node (n->orig).
-			// Having multiple names causes too much confusion in later passes.
-			nn = nod(OXXX, N, N);
-			*nn = *n->left;
-			nn->orig = nn;
-			snprint(namebuf, sizeof(namebuf), "~b%d", gen++);
-			nn->sym = lookup(namebuf);
-			n->left = nn;
-		}
-
-		n->left->ntype = n->right;
-		declare(n->left, PPARAMOUT);
-		if(dclcontext == PAUTO)
-			n->left->vargen = ++i;
-	}
-}
-
-/*
- * Same as funcargs, except run over an already constructed TFUNC.
- * This happens during import, where the hidden_fndcl rule has
- * used functype directly to parse the function's type.
- */
-static void
-funcargs2(Type *t)
-{
-	Type *ft;
-	Node *n;
-
-	if(t->etype != TFUNC)
-		fatal("funcargs2 %T", t);
-	
-	if(t->thistuple)
-		for(ft=getthisx(t)->type; ft; ft=ft->down) {
-			if(!ft->nname || !ft->nname->sym)
-				continue;
-			n = ft->nname;  // no need for newname(ft->nname->sym)
-			n->type = ft->type;
-			declare(n, PPARAM);
-		}
-
-	if(t->intuple)
-		for(ft=getinargx(t)->type; ft; ft=ft->down) {
-			if(!ft->nname || !ft->nname->sym)
-				continue;
-			n = ft->nname;
-			n->type = ft->type;
-			declare(n, PPARAM);
-		}
-
-	if(t->outtuple)
-		for(ft=getoutargx(t)->type; ft; ft=ft->down) {
-			if(!ft->nname || !ft->nname->sym)
-				continue;
-			n = ft->nname;
-			n->type = ft->type;
-			declare(n, PPARAMOUT);
-		}
-}
-
-/*
- * finish the body.
- * called in auto-declaration context.
- * returns in extern-declaration context.
- */
-void
-funcbody(Node *n)
-{
-	// change the declaration context from auto to extern
-	if(dclcontext != PAUTO)
-		fatal("funcbody: dclcontext");
-	popdcl();
-	funcdepth--;
-	curfn = n->outer;
-	n->outer = N;
-	if(funcdepth == 0)
-		dclcontext = PEXTERN;
-}
-
-/*
- * new type being defined with name s.
- */
-Node*
-typedcl0(Sym *s)
-{
-	Node *n;
-
-	n = newname(s);
-	n->op = OTYPE;
-	declare(n, dclcontext);
-	return n;
-}
-
-/*
- * node n, which was returned by typedcl0
- * is being declared to have uncompiled type t.
- * return the ODCLTYPE node to use.
- */
-Node*
-typedcl1(Node *n, Node *t, int local)
-{
-	n->ntype = t;
-	n->local = local;
-	return nod(ODCLTYPE, n, N);
-}
-
-/*
- * structs, functions, and methods.
- * they don't belong here, but where do they belong?
- */
-
-static void
-checkembeddedtype(Type *t)
-{
-	if (t == T)
-		return;
-
-	if(t->sym == S && isptr[t->etype]) {
-		t = t->type;
-		if(t->etype == TINTER)
-			yyerror("embedded type cannot be a pointer to interface");
-	}
-	if(isptr[t->etype])
-		yyerror("embedded type cannot be a pointer");
-	else if(t->etype == TFORW && t->embedlineno == 0)
-		t->embedlineno = lineno;
-}
-
-static Type*
-structfield(Node *n)
-{
-	Type *f;
-	int lno;
-
-	lno = lineno;
-	lineno = n->lineno;
-
-	if(n->op != ODCLFIELD)
-		fatal("structfield: oops %N\n", n);
-
-	f = typ(TFIELD);
-	f->isddd = n->isddd;
-
-	if(n->right != N) {
-		typecheck(&n->right, Etype);
-		n->type = n->right->type;
-		if(n->left != N)
-			n->left->type = n->type;
-		if(n->embedded)
-			checkembeddedtype(n->type);
-	}
-	n->right = N;
-		
-	f->type = n->type;
-	if(f->type == T)
-		f->broke = 1;
-
-	switch(n->val.ctype) {
-	case CTSTR:
-		f->note = n->val.u.sval;
-		break;
-	default:
-		yyerror("field annotation must be string");
-		// fallthrough
-	case CTxxx:
-		f->note = nil;
-		break;
-	}
-
-	if(n->left && n->left->op == ONAME) {
-		f->nname = n->left;
-		f->embedded = n->embedded;
-		f->sym = f->nname->sym;
-	}
-
-	lineno = lno;
-	return f;
-}
-
-static uint32 uniqgen;
-
-static void
-checkdupfields(Type *t, char* what)
-{
-	int lno;
-
-	lno = lineno;
-
-	for( ; t; t=t->down) {
-		if(t->sym && t->nname && !isblank(t->nname)) {
-			if(t->sym->uniqgen == uniqgen) {
-				lineno = t->nname->lineno;
-				yyerror("duplicate %s %s", what, t->sym->name);
-			} else
-				t->sym->uniqgen = uniqgen;
-		}
-	}
-
-	lineno = lno;
-}
-
-/*
- * convert a parsed id/type list into
- * a type for struct/interface/arglist
- */
-Type*
-tostruct(NodeList *l)
-{
-	Type *t, *f, **tp;
-	t = typ(TSTRUCT);
-
-	for(tp = &t->type; l; l=l->next) {
-		f = structfield(l->n);
-
-		*tp = f;
-		tp = &f->down;
-	}
-
-	for(f=t->type; f && !t->broke; f=f->down)
-		if(f->broke)
-			t->broke = 1;
-
-	uniqgen++;
-	checkdupfields(t->type, "field");
-
-	if (!t->broke)
-		checkwidth(t);
-
-	return t;
-}
-
-static Type*
-tofunargs(NodeList *l)
-{
-	Type *t, *f, **tp;
-
-	t = typ(TSTRUCT);
-	t->funarg = 1;
-
-	for(tp = &t->type; l; l=l->next) {
-		f = structfield(l->n);
-		f->funarg = 1;
-
-		// esc.c needs to find f given a PPARAM to add the tag.
-		if(l->n->left && l->n->left->class == PPARAM)
-			l->n->left->paramfld = f;
-
-		*tp = f;
-		tp = &f->down;
-	}
-
-	for(f=t->type; f && !t->broke; f=f->down)
-		if(f->broke)
-			t->broke = 1;
-
-	return t;
-}
-
-static Type*
-interfacefield(Node *n)
-{
-	Type *f;
-	int lno;
-
-	lno = lineno;
-	lineno = n->lineno;
-
-	if(n->op != ODCLFIELD)
-		fatal("interfacefield: oops %N\n", n);
-
-	if (n->val.ctype != CTxxx)
-		yyerror("interface method cannot have annotation");
-
-	f = typ(TFIELD);
-	f->isddd = n->isddd;
-	
-	if(n->right != N) {
-		if(n->left != N) {
-			// queue resolution of method type for later.
-			// right now all we need is the name list.
-			// avoids cycles for recursive interface types.
-			n->type = typ(TINTERMETH);
-			n->type->nname = n->right;
-			n->left->type = n->type;
-			queuemethod(n);
-
-			if(n->left->op == ONAME) {
-				f->nname = n->left;
-				f->embedded = n->embedded;
-				f->sym = f->nname->sym;
-			}
-
-		} else {
-
-			typecheck(&n->right, Etype);
-			n->type = n->right->type;
-
-			if(n->embedded)
-				checkembeddedtype(n->type);
-
-			if(n->type)
-				switch(n->type->etype) {
-				case TINTER:
-					break;
-				case TFORW:
-					yyerror("interface type loop involving %T", n->type);
-					f->broke = 1;
-					break;
-				default:
-					yyerror("interface contains embedded non-interface %T", n->type);
-					f->broke = 1;
-					break;
-				}
-		}
-	}
-
-	n->right = N;
-	
-	f->type = n->type;
-	if(f->type == T)
-		f->broke = 1;
-	
-	lineno = lno;
-	return f;
-}
-
-Type*
-tointerface(NodeList *l)
-{
-	Type *t, *f, **tp, *t1;
-
-	t = typ(TINTER);
-
-	tp = &t->type;
-	for(; l; l=l->next) {
-		f = interfacefield(l->n);
-
-		if (l->n->left == N && f->type->etype == TINTER) {
-			// embedded interface, inline methods
-			for(t1=f->type->type; t1; t1=t1->down) {
-				f = typ(TFIELD);
-				f->type = t1->type;
-				f->broke = t1->broke;
-				f->sym = t1->sym;
-				if(f->sym)
-					f->nname = newname(f->sym);
-				*tp = f;
-				tp = &f->down;
-			}
-		} else {
-			*tp = f;
-			tp = &f->down;
-		}
-	}
-
-	for(f=t->type; f && !t->broke; f=f->down)
-		if(f->broke)
-			t->broke = 1;
-
-	uniqgen++;
-	checkdupfields(t->type, "method");
-	t = sortinter(t);
-	checkwidth(t);
-
-	return t;
-}
-
-Node*
-embedded(Sym *s, Pkg *pkg)
-{
-	Node *n;
-	char *name;
-
-	// Names sometimes have disambiguation junk
-	// appended after a center dot.  Discard it when
-	// making the name for the embedded struct field.
-	enum { CenterDot = 0xB7 };
-	name = s->name;
-	if(utfrune(s->name, CenterDot)) {
-		name = strdup(s->name);
-		*utfrune(name, CenterDot) = 0;
-	}
-
-	if(exportname(name))
-		n = newname(lookup(name));
-	else if(s->pkg == builtinpkg)
-		// The name of embedded builtins belongs to pkg.
-		n = newname(pkglookup(name, pkg));
-	else
-		n = newname(pkglookup(name, s->pkg));
-	n = nod(ODCLFIELD, n, oldname(s));
-	n->embedded = 1;
-	return n;
-}
-
-/*
- * check that the list of declarations is either all anonymous or all named
- */
-
-static Node*
-findtype(NodeList *l)
-{
-	for(; l; l=l->next)
-		if(l->n->op == OKEY)
-			return l->n->right;
-	return N;
-}
-
-NodeList*
-checkarglist(NodeList *all, int input)
-{
-	int named;
-	Node *n, *t, *nextt;
-	NodeList *l;
-
-	named = 0;
-	for(l=all; l; l=l->next) {
-		if(l->n->op == OKEY) {
-			named = 1;
-			break;
-		}
-	}
-	if(named) {
-		n = N;
-		for(l=all; l; l=l->next) {
-			n = l->n;
-			if(n->op != OKEY && n->sym == S) {
-				yyerror("mixed named and unnamed function parameters");
-				break;
-			}
-		}
-		if(l == nil && n != N && n->op != OKEY)
-			yyerror("final function parameter must have type");
-	}
-
-	nextt = nil;
-	for(l=all; l; l=l->next) {
-		// can cache result from findtype to avoid
-		// quadratic behavior here, but unlikely to matter.
-		n = l->n;
-		if(named) {
-			if(n->op == OKEY) {
-				t = n->right;
-				n = n->left;
-				nextt = nil;
-			} else {
-				if(nextt == nil)
-					nextt = findtype(l);
-				t = nextt;
-			}
-		} else {
-			t = n;
-			n = N;
-		}
-
-		// during import l->n->op is OKEY, but l->n->left->sym == S
-		// means it was a '?', not that it was
-		// a lone type This doesn't matter for the exported
-		// declarations, which are parsed by rules that don't
-		// use checkargs, but can happen for func literals in
-		// the inline bodies.
-		// TODO(rsc) this can go when typefmt case TFIELD in exportmode fmt.c prints _ instead of ?
-		if(importpkg && n->sym == S)
-			n = N;
-
-		if(n != N && n->sym == S) {
-			t = n;
-			n = N;
-		}
-		if(n != N)
-			n = newname(n->sym);
-		n = nod(ODCLFIELD, n, t);
-		if(n->right != N && n->right->op == ODDD) {
-			if(!input)
-				yyerror("cannot use ... in output argument list");
-			else if(l->next != nil)
-				yyerror("can only use ... as final argument in list");
-			n->right->op = OTARRAY;
-			n->right->right = n->right->left;
-			n->right->left = N;
-			n->isddd = 1;
-			if(n->left != N)
-				n->left->isddd = 1;
-		}
-		l->n = n;
-	}
-	return all;
-}
-
-
-Node*
-fakethis(void)
-{
-	Node *n;
-
-	n = nod(ODCLFIELD, N, typenod(ptrto(typ(TSTRUCT))));
-	return n;
-}
-
-/*
- * Is this field a method on an interface?
- * Those methods have an anonymous
- * *struct{} as the receiver.
- * (See fakethis above.)
- */
-int
-isifacemethod(Type *f)
-{
-	Type *rcvr;
-	Type *t;
-
-	rcvr = getthisx(f)->type;
-	if(rcvr->sym != S)
-		return 0;
-	t = rcvr->type;
-	if(!isptr[t->etype])
-		return 0;
-	t = t->type;
-	if(t->sym != S || t->etype != TSTRUCT || t->type != T)
-		return 0;
-	return 1;
-}
-
-/*
- * turn a parsed function declaration
- * into a type
- */
-Type*
-functype(Node *this, NodeList *in, NodeList *out)
-{
-	Type *t;
-	NodeList *rcvr;
-	Sym *s;
-
-	t = typ(TFUNC);
-
-	rcvr = nil;
-	if(this)
-		rcvr = list1(this);
-	t->type = tofunargs(rcvr);
-	t->type->down = tofunargs(out);
-	t->type->down->down = tofunargs(in);
-
-	uniqgen++;
-	checkdupfields(t->type->type, "argument");
-	checkdupfields(t->type->down->type, "argument");
-	checkdupfields(t->type->down->down->type, "argument");
-
-	if (t->type->broke || t->type->down->broke || t->type->down->down->broke)
-		t->broke = 1;
-
-	if(this)
-		t->thistuple = 1;
-	t->outtuple = count(out);
-	t->intuple = count(in);
-	t->outnamed = 0;
-	if(t->outtuple > 0 && out->n->left != N && out->n->left->orig != N) {
-		s = out->n->left->orig->sym;
-		if(s != S && (s->name[0] != '~' || s->name[1] != 'r')) // ~r%d is the name invented for an unnamed result
-			t->outnamed = 1;
-	}
-
-	return t;
-}
-
-Sym*
-methodsym(Sym *nsym, Type *t0, int iface)
-{
-	Sym *s;
-	char *p;
-	Type *t;
-	char *suffix;
-	Pkg *spkg;
-	static Pkg *toppkg;
-
-	t = t0;
-	if(t == T)
-		goto bad;
-	s = t->sym;
-	if(s == S && isptr[t->etype]) {
-		t = t->type;
-		if(t == T)
-			goto bad;
-		s = t->sym;
-	}
-	spkg = nil;
-	if(s != S)
-		spkg = s->pkg;
-
-	// if t0 == *t and t0 has a sym,
-	// we want to see *t, not t0, in the method name.
-	if(t != t0 && t0->sym)
-		t0 = ptrto(t);
-
-	suffix = "";
-	if(iface) {
-		dowidth(t0);
-		if(t0->width < types[tptr]->width)
-			suffix = "·i";
-	}
-	if((spkg == nil || nsym->pkg != spkg) && !exportname(nsym->name)) {
-		if(t0->sym == S && isptr[t0->etype])
-			p = smprint("(%-hT).%s.%s%s", t0, nsym->pkg->prefix, nsym->name, suffix);
-		else
-			p = smprint("%-hT.%s.%s%s", t0, nsym->pkg->prefix, nsym->name, suffix);
-	} else {
-		if(t0->sym == S && isptr[t0->etype])
-			p = smprint("(%-hT).%s%s", t0, nsym->name, suffix);
-		else
-			p = smprint("%-hT.%s%s", t0, nsym->name, suffix);
-	}
-	if(spkg == nil) {
-		if(toppkg == nil)
-			toppkg = mkpkg(strlit("go"));
-		spkg = toppkg;
-	}
-	s = pkglookup(p, spkg);
-	free(p);
-	return s;
-
-bad:
-	yyerror("illegal receiver type: %T", t0);
-	return S;
-}
-
-Node*
-methodname(Node *n, Type *t)
-{
-	Sym *s;
-
-	s = methodsym(n->sym, t, 0);
-	if(s == S)
-		return n;
-	return newname(s);
-}
-
-Node*
-methodname1(Node *n, Node *t)
-{
-	char *star;
-	char *p;
-
-	star = nil;
-	if(t->op == OIND) {
-		star = "*";
-		t = t->left;
-	}
-	if(t->sym == S || isblank(n))
-		return newname(n->sym);
-
-	if(star)
-		p = smprint("(%s%S).%S", star, t->sym, n->sym);
-	else
-		p = smprint("%S.%S", t->sym, n->sym);
-
-	if(exportname(t->sym->name))
-		n = newname(lookup(p));
-	else
-		n = newname(pkglookup(p, t->sym->pkg));
-	free(p);
-	return n;
-}
-
-/*
- * add a method, declared as a function,
- * n is fieldname, pa is base type, t is function type
- */
-void
-addmethod(Sym *sf, Type *t, int local, int nointerface)
-{
-	Type *f, *d, *pa;
-	Node *n;
-
-	// get field sym
-	if(sf == S)
-		fatal("no method symbol");
-
-	// get parent type sym
-	pa = getthisx(t)->type;	// ptr to this structure
-	if(pa == T) {
-		yyerror("missing receiver");
-		return;
-	}
-
-	pa = pa->type;
-	f = methtype(pa, 1);
-	if(f == T) {
-		t = pa;
-		if(t == T) // rely on typecheck having complained before
-			return;
-		if(t != T) {
-			if(isptr[t->etype]) {
-				if(t->sym != S) {
-					yyerror("invalid receiver type %T (%T is a pointer type)", pa, t);
-					return;
-				}
-				t = t->type;
-			}
-			if(t->broke) // rely on typecheck having complained before
-				return;
-			if(t->sym == S) {
-				yyerror("invalid receiver type %T (%T is an unnamed type)", pa, t);
-				return;
-			}
-			if(isptr[t->etype]) {
-				yyerror("invalid receiver type %T (%T is a pointer type)", pa, t);
-				return;
-			}
-			if(t->etype == TINTER) {
-				yyerror("invalid receiver type %T (%T is an interface type)", pa, t);
-				return;
-			}
-		}
-		// Should have picked off all the reasons above,
-		// but just in case, fall back to generic error.
-		yyerror("invalid receiver type %T (%lT / %lT)", pa, pa, t);
-		return;
-	}
-
-	pa = f;
-	if(pa->etype == TSTRUCT) {
-		for(f=pa->type; f; f=f->down) {
-			if(f->sym == sf) {
-				yyerror("type %T has both field and method named %S", pa, sf);
-				return;
-			}
-		}
-	}
-
-	if(local && !pa->local) {
-		// defining method on non-local type.
-		yyerror("cannot define new methods on non-local type %T", pa);
-		return;
-	}
-
-	n = nod(ODCLFIELD, newname(sf), N);
-	n->type = t;
-
-	d = T;	// last found
-	for(f=pa->method; f!=T; f=f->down) {
-		d = f;
-		if(f->etype != TFIELD)
-			fatal("addmethod: not TFIELD: %N", f);
-		if(strcmp(sf->name, f->sym->name) != 0)
-			continue;
-		if(!eqtype(t, f->type))
-			yyerror("method redeclared: %T.%S\n\t%T\n\t%T", pa, sf, f->type, t);
-		return;
-	}
-
-	f = structfield(n);
-	f->nointerface = nointerface;
-
-	// during import unexported method names should be in the type's package
-	if(importpkg && f->sym && !exportname(f->sym->name) && f->sym->pkg != structpkg)
-		fatal("imported method name %+S in wrong package %s\n", f->sym, structpkg->name);
-
-	if(d == T)
-		pa->method = f;
-	else
-		d->down = f;
-	return;
-}
-
-void
-funccompile(Node *n, int isclosure)
-{
-	stksize = BADWIDTH;
-	maxarg = 0;
-
-	if(n->type == T) {
-		if(nerrors == 0)
-			fatal("funccompile missing type");
-		return;
-	}
-
-	// assign parameter offsets
-	checkwidth(n->type);
-	
-	// record offset to actual frame pointer.
-	// for closure, have to skip over leading pointers and PC slot.
-	// TODO(rsc): this is the old jit closure handling code.
-	// with the new closures, isclosure is always 0; delete this block.
-	nodfp->xoffset = 0;
-	if(isclosure) {
-		NodeList *l;
-		for(l=n->nname->ntype->list; l; l=l->next) {
-			nodfp->xoffset += widthptr;
-			if(l->n->left == N)	// found slot for PC
-				break;
-		}
-	}
-
-	if(curfn)
-		fatal("funccompile %S inside %S", n->nname->sym, curfn->nname->sym);
-
-	stksize = 0;
-	dclcontext = PAUTO;
-	funcdepth = n->funcdepth + 1;
-	compile(n);
-	curfn = nil;
-	funcdepth = 0;
-	dclcontext = PEXTERN;
-}
-
-Sym*
-funcsym(Sym *s)
-{
-	char *p;
-	Sym *s1;
-	
-	p = smprint("%s·f", s->name);
-	s1 = pkglookup(p, s->pkg);
-	free(p);
-	if(s1->def == N) {
-		s1->def = newname(s1);
-		s1->def->shortname = newname(s);
-		funcsyms = list(funcsyms, s1->def);
-	}
-	return s1;
-}
diff --git a/src/cmd/gc/doc.go b/src/cmd/gc/doc.go
deleted file mode 100644
index 03df93a..0000000
--- a/src/cmd/gc/doc.go
+++ /dev/null
@@ -1,95 +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.
-
-// +build ignore
-
-/*
-
-Gc is the generic label for the family of Go compilers
-that function as part of the (modified) Plan 9 tool chain.  The C compiler
-documentation at
-
-	http://plan9.bell-labs.com/sys/doc/comp.pdf     (Tools overview)
-	http://plan9.bell-labs.com/sys/doc/compiler.pdf (C compiler architecture)
-
-gives the overall design of the tool chain.  Aside from a few adapted pieces,
-such as the optimizer, the Go compilers are wholly new programs.
-
-The compiler reads in a set of Go files, typically suffixed ".go".  They
-must all be part of one package.  The output is a single intermediate file
-representing the "binary assembly" of the compiled package, ready as input
-for the linker (6l, etc.).
-
-The generated files contain type information about the symbols exported by
-the package and about types used by symbols imported by the package from
-other packages. It is therefore not necessary when compiling client C of
-package P to read the files of P's dependencies, only the compiled output
-of P.
-
-Command Line
-
-Usage:
-	go tool 6g [flags] file...
-The specified files must be Go source files and all part of the same package.
-Substitute 6g with 8g or 5g where appropriate.
-
-Flags:
-	-o file
-		output file, default file.6 for 6g, etc.
-	-pack
-		write an archive file rather than an object file
-	-e
-		normally the compiler quits after 10 errors; -e prints all errors
-	-p path
-		assume that path is the eventual import path for this code,
-		and diagnose any attempt to import a package that depends on it.
-	-D path
-		treat a relative import as relative to path
-	-L
-		show entire file path when printing line numbers in errors
-	-I dir1 -I dir2
-		add dir1 and dir2 to the list of paths to check for imported packages
-	-N
-		disable optimizations
-	-nolocalimports
-		disallow local (relative) imports
-	-S
-		write assembly language text to standard output (code only)
-	-S -S
-		write assembly language text to standard output (code and data)
-	-u
-		disallow importing packages not marked as safe; implies -nolocalimports
-	-V
-		print the compiler version
-	-race
-		compile with race detection enabled
-
-There are also a number of debugging flags; run the command with no arguments
-to get a usage message.
-
-Compiler Directives
-
-The compiler accepts two compiler directives in the form of // comments at the
-beginning of a line. To distinguish them from non-directive comments, the directives
-require no space between the slashes and the name of the directive. However, since
-they are comments, tools unaware of the directive convention or of a particular
-directive can skip over a directive like any other comment.
-
-    //line path/to/file:linenumber
-
-The //line directive specifies that the source line that follows should be recorded
-as having come from the given file path and line number. Successive lines are
-recorded using increasing line numbers, until the next directive. This directive
-typically appears in machine-generated code, so that compilers and debuggers
-will show lines in the original input to the generator.
-
-    //go:noescape
-
-The //go:noescape directive specifies that the next declaration in the file, which
-must be a func without a body (meaning that it has an implementation not written
-in Go) does not allow any of the pointers passed as arguments to escape into the
-heap or into the values returned from the function. This information can be used as
-during the compiler's escape analysis of Go code calling the function.
-*/
-package main
diff --git a/src/cmd/gc/esc.c b/src/cmd/gc/esc.c
deleted file mode 100644
index 324f24f..0000000
--- a/src/cmd/gc/esc.c
+++ /dev/null
@@ -1,1281 +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.
-
-// Escape analysis.
-
-#include <u.h>
-#include <libc.h>
-#include "go.h"
-
-// Run analysis on minimal sets of mutually recursive functions
-// or single non-recursive functions, bottom up.
-//
-// Finding these sets is finding strongly connected components
-// in the static call graph.  The algorithm for doing that is taken
-// from Sedgewick, Algorithms, Second Edition, p. 482, with two
-// adaptations.
-//
-// First, a hidden closure function (n->curfn != N) cannot be the
-// root of a connected component. Refusing to use it as a root
-// forces it into the component of the function in which it appears.
-// The analysis assumes that closures and the functions in which they
-// appear are analyzed together, so that the aliasing between their
-// variables can be modeled more precisely.
-//
-// Second, each function becomes two virtual nodes in the graph,
-// with numbers n and n+1. We record the function's node number as n
-// but search from node n+1. If the search tells us that the component
-// number (min) is n+1, we know that this is a trivial component: one function
-// plus its closures. If the search tells us that the component number is
-// n, then there was a path from node n+1 back to node n, meaning that
-// the function set is mutually recursive. The escape analysis can be
-// more precise when analyzing a single non-recursive function than
-// when analyzing a set of mutually recursive functions.
-
-static NodeList *stack;
-static uint32 visitgen;
-static uint32 visit(Node*);
-static uint32 visitcode(Node*, uint32);
-static uint32 visitcodelist(NodeList*, uint32);
-
-static void analyze(NodeList*, int);
-
-enum
-{
-	EscFuncUnknown = 0,
-	EscFuncPlanned,
-	EscFuncStarted,
-	EscFuncTagged,
-};
-
-void
-escapes(NodeList *all)
-{
-	NodeList *l;
-
-	for(l=all; l; l=l->next)
-		l->n->walkgen = 0;
-
-	visitgen = 0;
-	for(l=all; l; l=l->next)
-		if(l->n->op == ODCLFUNC && l->n->curfn == N)
-			visit(l->n);
-
-	for(l=all; l; l=l->next)
-		l->n->walkgen = 0;
-}
-
-static uint32
-visit(Node *n)
-{
-	uint32 min, recursive;
-	NodeList *l, *block;
-
-	if(n->walkgen > 0) {
-		// already visited
-		return n->walkgen;
-	}
-	
-	visitgen++;
-	n->walkgen = visitgen;
-	visitgen++;
-	min = visitgen;
-
-	l = mal(sizeof *l);
-	l->next = stack;
-	l->n = n;
-	stack = l;
-	min = visitcodelist(n->nbody, min);
-	if((min == n->walkgen || min == n->walkgen+1) && n->curfn == N) {
-		// This node is the root of a strongly connected component.
-
-		// The original min passed to visitcodelist was n->walkgen+1.
-		// If visitcodelist found its way back to n->walkgen, then this
-		// block is a set of mutually recursive functions.
-		// Otherwise it's just a lone function that does not recurse.
-		recursive = min == n->walkgen;
-
-		// Remove connected component from stack.
-		// Mark walkgen so that future visits return a large number
-		// so as not to affect the caller's min.
-		block = stack;
-		for(l=stack; l->n != n; l=l->next)
-			l->n->walkgen = (uint32)~0U;
-		n->walkgen = (uint32)~0U;
-		stack = l->next;
-		l->next = nil;
-
-		// Run escape analysis on this set of functions.
-		analyze(block, recursive);
-	}
-
-	return min;
-}
-
-static uint32
-visitcodelist(NodeList *l, uint32 min)
-{
-	for(; l; l=l->next)
-		min = visitcode(l->n, min);
-	return min;
-}
-
-static uint32
-visitcode(Node *n, uint32 min)
-{
-	Node *fn;
-	uint32 m;
-
-	if(n == N)
-		return min;
-
-	min = visitcodelist(n->ninit, min);
-	min = visitcode(n->left, min);
-	min = visitcode(n->right, min);
-	min = visitcodelist(n->list, min);
-	min = visitcode(n->ntest, min);
-	min = visitcode(n->nincr, min);
-	min = visitcodelist(n->nbody, min);
-	min = visitcodelist(n->nelse, min);
-	min = visitcodelist(n->rlist, min);
-	
-	if(n->op == OCALLFUNC || n->op == OCALLMETH) {
-		fn = n->left;
-		if(n->op == OCALLMETH)
-			fn = n->left->right->sym->def;
-		if(fn && fn->op == ONAME && fn->class == PFUNC && fn->defn)
-			if((m = visit(fn->defn)) < min)
-				min = m;
-	}
-	
-	if(n->op == OCLOSURE)
-		if((m = visit(n->closure)) < min)
-			min = m;
-
-	return min;
-}
-
-// An escape analysis pass for a set of functions.
-//
-// First escfunc, esc and escassign recurse over the ast of each
-// function to dig out flow(dst,src) edges between any
-// pointer-containing nodes and store them in dst->escflowsrc.  For
-// variables assigned to a variable in an outer scope or used as a
-// return value, they store a flow(theSink, src) edge to a fake node
-// 'the Sink'.  For variables referenced in closures, an edge
-// flow(closure, &var) is recorded and the flow of a closure itself to
-// an outer scope is tracked the same way as other variables.
-//
-// Then escflood walks the graph starting at theSink and tags all
-// variables of it can reach an & node as escaping and all function
-// parameters it can reach as leaking.
-//
-// If a value's address is taken but the address does not escape,
-// then the value can stay on the stack.  If the value new(T) does
-// not escape, then new(T) can be rewritten into a stack allocation.
-// The same is true of slice literals.
-//
-// If optimizations are disabled (-N), this code is not used.
-// Instead, the compiler assumes that any value whose address
-// is taken without being immediately dereferenced
-// needs to be moved to the heap, and new(T) and slice
-// literals are always real allocations.
-
-typedef struct EscState EscState;
-
-static void escfunc(EscState*, Node *func);
-static void esclist(EscState*, NodeList *l, Node *up);
-static void esc(EscState*, Node *n, Node *up);
-static void escloopdepthlist(EscState*, NodeList *l);
-static void escloopdepth(EscState*, Node *n);
-static void escassign(EscState*, Node *dst, Node *src);
-static void esccall(EscState*, Node*, Node *up);
-static void escflows(EscState*, Node *dst, Node *src);
-static void escflood(EscState*, Node *dst);
-static void escwalk(EscState*, int level, Node *dst, Node *src);
-static void esctag(EscState*, Node *func);
-
-struct EscState {
-	// Fake node that all
-	//   - return values and output variables
-	//   - parameters on imported functions not marked 'safe'
-	//   - assignments to global variables
-	// flow to.
-	Node	theSink;
-	
-	// 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.
-	Node	funcParam;	
-	
-	NodeList*	dsts;		// all dst nodes
-	int	loopdepth;	// for detecting nested loop scopes
-	int	pdepth;		// for debug printing in recursions.
-	int	dstcount, edgecount;	// diagnostic
-	NodeList*	noesc;	// list of possible non-escaping nodes, for printing
-	int	recursive;	// recursive function or group of mutually recursive functions.
-};
-
-static Strlit *tags[16];
-
-static Strlit*
-mktag(int mask)
-{
-	Strlit *s;
-	char buf[40];
-
-	switch(mask&EscMask) {
-	case EscNone:
-	case EscReturn:
-		break;
-	default:
-		fatal("escape mktag");
-	}
-
-	mask >>= EscBits;
-
-	if(mask < nelem(tags) && tags[mask] != nil)
-		return tags[mask];
-
-	snprint(buf, sizeof buf, "esc:0x%x", mask);
-	s = strlit(buf);
-	if(mask < nelem(tags))
-		tags[mask] = s;
-	return s;
-}
-
-static int
-parsetag(Strlit *note)
-{
-	int em;
-
-	if(note == nil)
-		return EscUnknown;
-	if(strncmp(note->s, "esc:", 4) != 0)
-		return EscUnknown;
-	em = atoi(note->s + 4);
-	if (em == 0)
-		return EscNone;
-	return EscReturn | (em << EscBits);
-}
-
-static void
-analyze(NodeList *all, int recursive)
-{
-	NodeList *l;
-	EscState es, *e;
-	
-	memset(&es, 0, sizeof es);
-	e = &es;
-	e->theSink.op = ONAME;
-	e->theSink.orig = &e->theSink;
-	e->theSink.class = PEXTERN;
-	e->theSink.sym = lookup(".sink");
-	e->theSink.escloopdepth = -1;
-	e->recursive = recursive;
-	
-	e->funcParam.op = ONAME;
-	e->funcParam.orig = &e->funcParam;
-	e->funcParam.class = PAUTO;
-	e->funcParam.sym = lookup(".param");
-	e->funcParam.escloopdepth = 10000000;
-	
-	for(l=all; l; l=l->next)
-		if(l->n->op == ODCLFUNC)
-			l->n->esc = EscFuncPlanned;
-
-	// flow-analyze functions
-	for(l=all; l; l=l->next)
-		if(l->n->op == ODCLFUNC)
-			escfunc(e, l->n);
-
-	// print("escapes: %d e->dsts, %d edges\n", e->dstcount, e->edgecount);
-
-	// visit the upstream of each dst, mark address nodes with
-	// addrescapes, mark parameters unsafe
-	for(l = e->dsts; l; l=l->next)
-		escflood(e, l->n);
-
-	// for all top level functions, tag the typenodes corresponding to the param nodes
-	for(l=all; l; l=l->next)
-		if(l->n->op == ODCLFUNC)
-			esctag(e, l->n);
-
-	if(debug['m']) {
-		for(l=e->noesc; l; l=l->next)
-			if(l->n->esc == EscNone)
-				warnl(l->n->lineno, "%S %hN does not escape",
-					(l->n->curfn && l->n->curfn->nname) ? l->n->curfn->nname->sym : S,
-					l->n);
-	}
-}
-
-
-static void
-escfunc(EscState *e, Node *func)
-{
-	Node *savefn;
-	NodeList *ll;
-	int saveld;
-
-//	print("escfunc %N %s\n", func->nname, e->recursive?"(recursive)":"");
-
-	if(func->esc != 1)
-		fatal("repeat escfunc %N", func->nname);
-	func->esc = EscFuncStarted;
-
-	saveld = e->loopdepth;
-	e->loopdepth = 1;
-	savefn = curfn;
-	curfn = func;
-
-	for(ll=curfn->dcl; ll; ll=ll->next) {
-		if(ll->n->op != ONAME)
-			continue;
-		switch (ll->n->class) {
-		case PPARAMOUT:
-			// out params are in a loopdepth between the sink and all local variables
-			ll->n->escloopdepth = 0;
-			break;
-		case PPARAM:
-			ll->n->escloopdepth = 1; 
-			if(ll->n->type && !haspointers(ll->n->type))
-				break;
-			if(curfn->nbody == nil && !curfn->noescape)
-				ll->n->esc = EscHeap;
-			else
-				ll->n->esc = EscNone;	// prime for escflood later
-			e->noesc = list(e->noesc, ll->n);
-			break;
-		}
-	}
-
-	// in a mutually recursive group we lose track of the return values
-	if(e->recursive)
-		for(ll=curfn->dcl; ll; ll=ll->next)
-			if(ll->n->op == ONAME && ll->n->class == PPARAMOUT)
-				escflows(e, &e->theSink, ll->n);
-
-	escloopdepthlist(e, curfn->nbody);
-	esclist(e, curfn->nbody, curfn);
-	curfn = savefn;
-	e->loopdepth = saveld;
-}
-
-// Mark labels that have no backjumps to them as not increasing e->loopdepth.
-// Walk hasn't generated (goto|label)->left->sym->label yet, so we'll cheat
-// and set it to one of the following two.  Then in esc we'll clear it again.
-static Label looping;
-static Label nonlooping;
-
-static void
-escloopdepthlist(EscState *e, NodeList *l)
-{
-	for(; l; l=l->next)
-		escloopdepth(e, l->n);
-}
-
-static void
-escloopdepth(EscState *e, Node *n)
-{
-	if(n == N)
-		return;
-
-	escloopdepthlist(e, n->ninit);
-
-	switch(n->op) {
-	case OLABEL:
-		if(!n->left || !n->left->sym)
-			fatal("esc:label without label: %+N", n);
-		// Walk will complain about this label being already defined, but that's not until
-		// after escape analysis. in the future, maybe pull label & goto analysis out of walk and put before esc
-		// if(n->left->sym->label != nil)
-		//	fatal("escape analysis messed up analyzing label: %+N", n);
-		n->left->sym->label = &nonlooping;
-		break;
-	case OGOTO:
-		if(!n->left || !n->left->sym)
-			fatal("esc:goto without label: %+N", n);
-		// If we come past one that's uninitialized, this must be a (harmless) forward jump
-		// but if it's set to nonlooping the label must have preceded this goto.
-		if(n->left->sym->label == &nonlooping)
-			n->left->sym->label = &looping;
-		break;
-	}
-
-	escloopdepth(e, n->left);
-	escloopdepth(e, n->right);
-	escloopdepthlist(e, n->list);
-	escloopdepth(e, n->ntest);
-	escloopdepth(e, n->nincr);
-	escloopdepthlist(e, n->nbody);
-	escloopdepthlist(e, n->nelse);
-	escloopdepthlist(e, n->rlist);
-
-}
-
-static void
-esclist(EscState *e, NodeList *l, Node *up)
-{
-	for(; l; l=l->next)
-		esc(e, l->n, up);
-}
-
-static void
-esc(EscState *e, Node *n, Node *up)
-{
-	int lno;
-	NodeList *ll, *lr;
-	Node *a;
-
-	if(n == N)
-		return;
-
-	lno = setlineno(n);
-
-	// ninit logically runs at a different loopdepth than the rest of the for loop.
-	esclist(e, n->ninit, n);
-
-	if(n->op == OFOR || n->op == ORANGE)
-		e->loopdepth++;
-
-	// type switch variables have no ODCL.
-	// process type switch as declaration.
-	// must happen before processing of switch body,
-	// so before recursion.
-	if(n->op == OSWITCH && n->ntest && n->ntest->op == OTYPESW) {
-		for(ll=n->list; ll; ll=ll->next) {  // cases
-			// ll->n->nname is the variable per case
-			if(ll->n->nname)
-				ll->n->nname->escloopdepth = e->loopdepth;
-		}
-	}
-
-	esc(e, n->left, n);
-	esc(e, n->right, n);
-	esc(e, n->ntest, n);
-	esc(e, n->nincr, n);
-	esclist(e, n->nbody, n);
-	esclist(e, n->nelse, n);
-	esclist(e, n->list, n);
-	esclist(e, n->rlist, n);
-
-	if(n->op == OFOR || n->op == ORANGE)
-		e->loopdepth--;
-
-	if(debug['m'] > 1)
-		print("%L:[%d] %S esc: %N\n", lineno, e->loopdepth,
-		      (curfn && curfn->nname) ? curfn->nname->sym : S, n);
-
-	switch(n->op) {
-	case ODCL:
-		// Record loop depth at declaration.
-		if(n->left)
-			n->left->escloopdepth = e->loopdepth;
-		break;
-
-	case OLABEL:
-		if(n->left->sym->label == &nonlooping) {
-			if(debug['m'] > 1)
-				print("%L:%N non-looping label\n", lineno, n);
-		} else if(n->left->sym->label == &looping) {
-			if(debug['m'] > 1)
-				print("%L: %N looping label\n", lineno, n);
-			e->loopdepth++;
-		}
-		// See case OLABEL in escloopdepth above
-		// else if(n->left->sym->label == nil)
-		//	fatal("escape analysis missed or messed up a label: %+N", n);
-
-		n->left->sym->label = nil;
-		break;
-
-	case ORANGE:
-		// Everything but fixed array is a dereference.
-		if(isfixedarray(n->type) && n->list && n->list->next)
-			escassign(e, n->list->next->n, n->right);
-		break;
-
-	case OSWITCH:
-		if(n->ntest && n->ntest->op == OTYPESW) {
-			for(ll=n->list; ll; ll=ll->next) {  // cases
-				// ntest->right is the argument of the .(type),
-				// ll->n->nname is the variable per case
-				escassign(e, ll->n->nname, n->ntest->right);
-			}
-		}
-		break;
-
-	case OAS:
-	case OASOP:
-		escassign(e, n->left, n->right);
-		break;
-
-	case OAS2:	// x,y = a,b
-		if(count(n->list) == count(n->rlist))
-			for(ll=n->list, lr=n->rlist; ll; ll=ll->next, lr=lr->next)
-				escassign(e, ll->n, lr->n);
-		break;
-
-	case OAS2RECV:		// v, ok = <-ch
-	case OAS2MAPR:		// v, ok = m[k]
-	case OAS2DOTTYPE:	// v, ok = x.(type)
-		escassign(e, n->list->n, n->rlist->n);
-		break;
-
-	case OSEND:		// ch <- x
-		escassign(e, &e->theSink, n->right);
-		break;
-
-	case ODEFER:
-		if(e->loopdepth == 1)  // top level
-			break;
-		// 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; ll=ll->next)
-			escassign(e, &e->theSink, ll->n);
-		break;
-
-	case OCALLMETH:
-	case OCALLFUNC:
-	case OCALLINTER:
-		esccall(e, n, up);
-		break;
-
-	case OAS2FUNC:	// x,y = f()
-		// esccall already done on n->rlist->n. tie it's escretval to n->list
-		lr=n->rlist->n->escretval;
-		for(ll=n->list; lr && ll; lr=lr->next, ll=ll->next)
-			escassign(e, ll->n, lr->n);
-		if(lr || ll)
-			fatal("esc oas2func");
-		break;
-
-	case ORETURN:
-		ll=n->list;
-		if(count(n->list) == 1 && curfn->type->outtuple > 1) {
-			// OAS2FUNC in disguise
-			// esccall already done on n->list->n
-			// tie n->list->n->escretval to curfn->dcl PPARAMOUT's
-			ll = n->list->n->escretval;
-		}
-
-		for(lr = curfn->dcl; lr && ll; lr=lr->next) {
-			if (lr->n->op != ONAME || lr->n->class != PPARAMOUT)
-				continue;
-			escassign(e, lr->n, ll->n);
-			ll = ll->next;
-		}
-		if (ll != nil)
-			fatal("esc return list");
-		break;
-
-	case OPANIC:
-		// Argument could leak through recover.
-		escassign(e, &e->theSink, n->left);
-		break;
-
-	case OAPPEND:
-		if(!n->isddd)
-			for(ll=n->list->next; ll; ll=ll->next)
-				escassign(e, &e->theSink, ll->n);  // lose track of assign to dereference
-		break;
-
-	case OCONV:
-	case OCONVNOP:
-	case OCONVIFACE:
-		escassign(e, n, n->left);
-		break;
-
-	case OARRAYLIT:
-		if(isslice(n->type)) {
-			n->esc = EscNone;  // until proven otherwise
-			e->noesc = list(e->noesc, n);
-			n->escloopdepth = e->loopdepth;
-			// Values make it to memory, lose track.
-			for(ll=n->list; ll; ll=ll->next)
-				escassign(e, &e->theSink, ll->n->right);
-		} else {
-			// Link values to array.
-			for(ll=n->list; ll; ll=ll->next)
-				escassign(e, n, ll->n->right);
-		}
-		break;
-
-	case OSTRUCTLIT:
-		// Link values to struct.
-		for(ll=n->list; ll; ll=ll->next)
-			escassign(e, n, ll->n->right);
-		break;
-	
-	case OPTRLIT:
-		n->esc = EscNone;  // until proven otherwise
-		e->noesc = list(e->noesc, n);
-		n->escloopdepth = e->loopdepth;
-		// Contents make it to memory, lose track.
-		escassign(e, &e->theSink, n->left);
-		break;
-	
-	case OCALLPART:
-		n->esc = EscNone; // until proven otherwise
-		e->noesc = list(e->noesc, n);
-		n->escloopdepth = e->loopdepth;
-		// Contents make it to memory, lose track.
-		escassign(e, &e->theSink, n->left);
-		break;
-
-	case OMAPLIT:
-		n->esc = EscNone;  // until proven otherwise
-		e->noesc = list(e->noesc, n);
-		n->escloopdepth = e->loopdepth;
-		// Keys and values make it to memory, lose track.
-		for(ll=n->list; ll; ll=ll->next) {
-			escassign(e, &e->theSink, ll->n->left);
-			escassign(e, &e->theSink, ll->n->right);
-		}
-		break;
-	
-	case OCLOSURE:
-		// Link addresses of captured variables to closure.
-		for(ll=n->cvars; ll; ll=ll->next) {
-			if(ll->n->op == OXXX)  // unnamed out argument; see dcl.c:/^funcargs
-				continue;
-			a = nod(OADDR, ll->n->closure, N);
-			a->lineno = ll->n->lineno;
-			a->escloopdepth = e->loopdepth;
-			typecheck(&a, Erv);
-			escassign(e, n, a);
-		}
-		// fallthrough
-	case OMAKECHAN:
-	case OMAKEMAP:
-	case OMAKESLICE:
-	case ONEW:
-		n->escloopdepth = e->loopdepth;
-		n->esc = EscNone;  // until proven otherwise
-		e->noesc = list(e->noesc, n);
-		break;
-
-	case OADDR:
-		n->esc = EscNone;  // until proven otherwise
-		e->noesc = list(e->noesc, n);
-		// current loop depth is an upper bound on actual loop depth
-		// of addressed value.
-		n->escloopdepth = e->loopdepth;
-		// for &x, use loop depth of x if known.
-		// it should always be known, but if not, be conservative
-		// and keep the current loop depth.
-		if(n->left->op == ONAME) {
-			switch(n->left->class) {
-			case PAUTO:
-				if(n->left->escloopdepth != 0)
-					n->escloopdepth = n->left->escloopdepth;
-				break;
-			case PPARAM:
-			case PPARAMOUT:
-				// PPARAM is loop depth 1 always.
-				// PPARAMOUT is loop depth 0 for writes
-				// but considered loop depth 1 for address-of,
-				// so that writing the address of one result
-				// to another (or the same) result makes the
-				// first result move to the heap.
-				n->escloopdepth = 1;
-				break;
-			}
-		}
-		break;
-	}
-
-	lineno = lno;
-}
-
-// Assert that expr somehow gets assigned to dst, if non nil.  for
-// dst==nil, any name node expr still must be marked as being
-// evaluated in curfn.	For expr==nil, dst must still be examined for
-// evaluations inside it (e.g *f(x) = y)
-static void
-escassign(EscState *e, Node *dst, Node *src)
-{
-	int lno;
-	NodeList *ll;
-
-	if(isblank(dst) || dst == N || src == N || src->op == ONONAME || src->op == OXXX)
-		return;
-
-	if(debug['m'] > 1)
-		print("%L:[%d] %S escassign: %hN(%hJ) = %hN(%hJ)\n", lineno, e->loopdepth,
-		      (curfn && curfn->nname) ? curfn->nname->sym : S, dst, dst, src, src);
-
-	setlineno(dst);
-	
-	// Analyze lhs of assignment.
-	// Replace dst with e->theSink if we can't track it.
-	switch(dst->op) {
-	default:
-		dump("dst", dst);
-		fatal("escassign: unexpected dst");
-
-	case OARRAYLIT:
-	case OCLOSURE:
-	case OCONV:
-	case OCONVIFACE:
-	case OCONVNOP:
-	case OMAPLIT:
-	case OSTRUCTLIT:
-	case OCALLPART:
-		break;
-
-	case ONAME:
-		if(dst->class == PEXTERN)
-			dst = &e->theSink;
-		break;
-	case ODOT:	      // treat "dst.x  = src" as "dst = src"
-		escassign(e, dst->left, src);
-		return;
-	case OINDEX:
-		if(isfixedarray(dst->left->type)) {
-			escassign(e, dst->left, src);
-			return;
-		}
-		dst = &e->theSink;  // lose track of dereference
-		break;
-	case OIND:
-	case ODOTPTR:
-		dst = &e->theSink;  // lose track of dereference
-		break;
-	case OINDEXMAP:
-		// lose track of key and value
-		escassign(e, &e->theSink, dst->right);
-		dst = &e->theSink;
-		break;
-	}
-
-	lno = setlineno(src);
-	e->pdepth++;
-
-	switch(src->op) {
-	case OADDR:	// dst = &x
-	case OIND:	// dst = *x
-	case ODOTPTR:	// dst = (*x).f
-	case ONAME:
-	case OPARAM:
-	case ODDDARG:
-	case OPTRLIT:
-	case OARRAYLIT:
-	case OMAPLIT:
-	case OSTRUCTLIT:
-	case OMAKECHAN:
-	case OMAKEMAP:
-	case OMAKESLICE:
-	case ONEW:
-	case OCLOSURE:
-	case OCALLPART:
-		escflows(e, dst, src);
-		break;
-
-	case OCALLMETH:
-	case OCALLFUNC:
-	case OCALLINTER:
-		// Flowing multiple returns to a single dst happens when
-		// analyzing "go f(g())": here g() flows to sink (issue 4529).
-		for(ll=src->escretval; ll; ll=ll->next)
-			escflows(e, dst, ll->n);
-		break;
-
-	case ODOT:
-		// A non-pointer escaping from a struct does not concern us.
-		if(src->type && !haspointers(src->type))
-			break;
-		// fallthrough
-	case OCONV:
-	case OCONVIFACE:
-	case OCONVNOP:
-	case ODOTMETH:	// treat recv.meth as a value with recv in it, only happens in ODEFER and OPROC
-			// iface.method already leaks iface in esccall, no need to put in extra ODOTINTER edge here
-	case ODOTTYPE:
-	case ODOTTYPE2:
-	case OSLICE:
-	case OSLICE3:
-	case OSLICEARR:
-	case OSLICE3ARR:
-		// Conversions, field access, slice all preserve the input value.
-		escassign(e, dst, src->left);
-		break;
-
-	case OAPPEND:
-		// Append returns first argument.
-		escassign(e, dst, src->list->n);
-		break;
-	
-	case OINDEX:
-		// Index of array preserves input value.
-		if(isfixedarray(src->left->type))
-			escassign(e, dst, src->left);
-		break;
-
-	case OADD:
-	case OSUB:
-	case OOR:
-	case OXOR:
-	case OMUL:
-	case ODIV:
-	case OMOD:
-	case OLSH:
-	case ORSH:
-	case OAND:
-	case OANDNOT:
-	case OPLUS:
-	case OMINUS:
-	case OCOM:
-		// Might be pointer arithmetic, in which case
-		// the operands flow into the result.
-		// TODO(rsc): Decide what the story is here.  This is unsettling.
-		escassign(e, dst, src->left);
-		escassign(e, dst, src->right);
-		break;
-	}
-
-	e->pdepth--;
-	lineno = lno;
-}
-
-static int
-escassignfromtag(EscState *e, Strlit *note, NodeList *dsts, Node *src)
-{
-	int em, em0;
-	
-	em = parsetag(note);
-
-	if(em == EscUnknown) {
-		escassign(e, &e->theSink, src);
-		return em;
-	}
-
-	if(em == EscNone)
-		return em;
-	
-	// If content inside parameter (reached via indirection)
-	// escapes back to results, mark as such.
-	if(em & EscContentEscapes)
-		escassign(e, &e->funcParam, src);
-
-	em0 = em;
-	for(em >>= EscReturnBits; em && dsts; em >>= 1, dsts=dsts->next)
-		if(em & 1)
-			escassign(e, dsts->n, src);
-
-	if (em != 0 && dsts == nil)
-		fatal("corrupt esc tag %Z or messed up escretval list\n", note);
-	return em0;
-}
-
-// This is a bit messier than fortunate, pulled out of esc's big
-// switch for clarity.	We either have the paramnodes, which may be
-// connected to other things through flows or we have the parameter type
-// nodes, which may be marked "noescape". Navigating the ast is slightly
-// different for methods vs plain functions and for imported vs
-// this-package
-static void
-esccall(EscState *e, Node *n, Node *up)
-{
-	NodeList *ll, *lr;
-	Node *a, *fn, *src;
-	Type *t, *fntype;
-	char buf[40];
-	int i;
-
-	fn = N;
-	switch(n->op) {
-	default:
-		fatal("esccall");
-
-	case OCALLFUNC:
-		fn = n->left;
-		fntype = fn->type;
-		break;
-
-	case OCALLMETH:
-		fn = n->left->right->sym->def;
-		if(fn)
-			fntype = fn->type;
-		else
-			fntype = n->left->type;
-		break;
-
-	case OCALLINTER:
-		fntype = n->left->type;
-		break;
-	}
-
-	ll = n->list;
-	if(n->list != nil && n->list->next == nil) {
-		a = n->list->n;
-		if(a->type->etype == TSTRUCT && a->type->funarg) // f(g()).
-			ll = a->escretval;
-	}
-
-	if(fn && fn->op == ONAME && fn->class == PFUNC && fn->defn && fn->defn->nbody && fn->ntype && fn->defn->esc < EscFuncTagged) {
-		// function in same mutually recursive group.  Incorporate into flow graph.
-//		print("esc local fn: %N\n", fn->ntype);
-		if(fn->defn->esc == EscFuncUnknown || n->escretval != nil)
-			fatal("graph inconsistency");
-
-		// set up out list on this call node
-		for(lr=fn->ntype->rlist; lr; lr=lr->next)
-			n->escretval = list(n->escretval, lr->n->left);  // type.rlist ->  dclfield -> ONAME (PPARAMOUT)
-
-		// Receiver.
-		if(n->op != OCALLFUNC)
-			escassign(e, fn->ntype->left->left, n->left->left);
-
-		for(lr=fn->ntype->list; ll && lr; ll=ll->next, lr=lr->next) {
-			src = ll->n;
-			if(lr->n->isddd && !n->isddd) {
-				// Introduce ODDDARG node to represent ... allocation.
-				src = nod(ODDDARG, N, N);
-				src->type = typ(TARRAY);
-				src->type->type = lr->n->type->type;
-				src->type->bound = count(ll);
-				src->type = ptrto(src->type); // make pointer so it will be tracked
-				src->escloopdepth = e->loopdepth;
-				src->lineno = n->lineno;
-				src->esc = EscNone;  // until we find otherwise
-				e->noesc = list(e->noesc, src);
-				n->right = src;
-			}
-			if(lr->n->left != N)
-				escassign(e, lr->n->left, src);
-			if(src != ll->n)
-				break;
-		}
-		// "..." arguments are untracked
-		for(; ll; ll=ll->next)
-			escassign(e, &e->theSink, ll->n);
-
-		return;
-	}
-
-	// Imported or completely analyzed function.  Use the escape tags.
-	if(n->escretval != nil)
-		fatal("esc already decorated call %+N\n", n);
-
-	// set up out list on this call node with dummy auto ONAMES in the current (calling) function.
-	i = 0;
-	for(t=getoutargx(fntype)->type; t; t=t->down) {
-		src = nod(ONAME, N, N);
-		snprint(buf, sizeof buf, ".dum%d", i++);
-		src->sym = lookup(buf);
-		src->type = t->type;
-		src->class = PAUTO;
-		src->curfn = curfn;
-		src->escloopdepth = e->loopdepth;
-		src->used = 1;
-		src->lineno = n->lineno;
-		n->escretval = list(n->escretval, src); 
-	}
-
-//	print("esc analyzed fn: %#N (%+T) returning (%+H)\n", fn, fntype, n->escretval);
-
-	// Receiver.
-	if(n->op != OCALLFUNC) {
-		t = getthisx(fntype)->type;
-		src = n->left->left;
-		if(haspointers(t->type))
-			escassignfromtag(e, t->note, n->escretval, src);
-	}
-	
-	for(t=getinargx(fntype)->type; ll; ll=ll->next) {
-		src = ll->n;
-		if(t->isddd && !n->isddd) {
-			// Introduce ODDDARG node to represent ... allocation.
-			src = nod(ODDDARG, N, N);
-			src->escloopdepth = e->loopdepth;
-			src->lineno = n->lineno;
-			src->type = typ(TARRAY);
-			src->type->type = t->type->type;
-			src->type->bound = count(ll);
-			src->type = ptrto(src->type); // make pointer so it will be tracked
-			src->esc = EscNone;  // until we find otherwise
-			e->noesc = list(e->noesc, src);
-			n->right = src;
-		}
-		if(haspointers(t->type)) {
-			if(escassignfromtag(e, t->note, n->escretval, src) == EscNone && up->op != ODEFER && up->op != OPROC) {
-				a = src;
-				while(a->op == OCONVNOP)
-					a = a->left;
-				switch(a->op) {
-				case OCALLPART:
-				case OCLOSURE:
-				case ODDDARG:
-				case OARRAYLIT:
-				case OPTRLIT:
-				case OSTRUCTLIT:
-					// The callee has already been analyzed, so its arguments have esc tags.
-					// The argument is marked as not escaping at all.
-					// Record that fact so that any temporary used for
-					// synthesizing this expression can be reclaimed when
-					// the function returns.
-					// This 'noescape' is even stronger than the usual esc == EscNone.
-					// src->esc == EscNone means that src does not escape the current function.
-					// src->noescape = 1 here means that src does not escape this statement
-					// in the current function.
-					a->noescape = 1;
-					break;
-				}
-			}
-		}
-		if(src != ll->n)
-			break;
-		t = t->down;
-	}
-	// "..." arguments are untracked
-	for(; ll; ll=ll->next)
-		escassign(e, &e->theSink, ll->n);
-}
-
-// Store the link src->dst in dst, throwing out some quick wins.
-static void
-escflows(EscState *e, Node *dst, Node *src)
-{
-	if(dst == nil || src == nil || dst == src)
-		return;
-
-	// Don't bother building a graph for scalars.
-	if(src->type && !haspointers(src->type))
-		return;
-
-	if(debug['m']>2)
-		print("%L::flows:: %hN <- %hN\n", lineno, dst, src);
-
-	if(dst->escflowsrc == nil) {
-		e->dsts = list(e->dsts, dst);
-		e->dstcount++;
-	}
-	e->edgecount++;
-
-	dst->escflowsrc = list(dst->escflowsrc, src);
-}
-
-// Whenever we hit a reference node, the level goes up by one, and whenever
-// we hit an OADDR, the level goes down by one. as long as we're on a level > 0
-// finding an OADDR just means we're following the upstream of a dereference,
-// so this address doesn't leak (yet).
-// If level == 0, it means the /value/ of this node can reach the root of this flood.
-// so if this node is an OADDR, it's argument should be marked as escaping iff
-// it's currfn/e->loopdepth are different from the flood's root.
-// Once an object has been moved to the heap, all of it's upstream should be considered
-// escaping to the global scope.
-static void
-escflood(EscState *e, Node *dst)
-{
-	NodeList *l;
-
-	switch(dst->op) {
-	case ONAME:
-	case OCLOSURE:
-		break;
-	default:
-		return;
-	}
-
-	if(debug['m']>1)
-		print("\nescflood:%d: dst %hN scope:%S[%d]\n", walkgen, dst,
-		      (dst->curfn && dst->curfn->nname) ? dst->curfn->nname->sym : S,
-		      dst->escloopdepth);
-
-	for(l = dst->escflowsrc; l; l=l->next) {
-		walkgen++;
-		escwalk(e, 0, dst, l->n);
-	}
-}
-
-// There appear to be some loops in the escape graph, causing
-// arbitrary recursion into deeper and deeper levels.
-// Cut this off safely by making minLevel sticky: once you
-// get that deep, you cannot go down any further but you also
-// cannot go up any further. This is a conservative fix.
-// Making minLevel smaller (more negative) would handle more
-// complex chains of indirections followed by address-of operations,
-// at the cost of repeating the traversal once for each additional
-// allowed level when a loop is encountered. Using -2 suffices to
-// pass all the tests we have written so far, which we assume matches
-// the level of complexity we want the escape analysis code to handle.
-#define MinLevel (-2)
-/*c2go enum { MinLevel = -2 };*/
-
-static void
-escwalk(EscState *e, int level, Node *dst, Node *src)
-{
-	NodeList *ll;
-	int leaks, newlevel;
-
-	if(src->walkgen == walkgen && src->esclevel <= level)
-		return;
-	src->walkgen = walkgen;
-	src->esclevel = level;
-
-	if(debug['m']>1)
-		print("escwalk: level:%d depth:%d %.*s %hN(%hJ) scope:%S[%d]\n",
-		      level, e->pdepth, e->pdepth, "\t\t\t\t\t\t\t\t\t\t", src, src,
-		      (src->curfn && src->curfn->nname) ? src->curfn->nname->sym : S, src->escloopdepth);
-
-	e->pdepth++;
-
-	// Input parameter flowing to output parameter?
-	if(dst->op == ONAME && dst->class == PPARAMOUT && dst->vargen <= 20) {
-		if(src->op == ONAME && src->class == PPARAM && src->curfn == dst->curfn && src->esc != EscScope && src->esc != EscHeap) {
-			if(level == 0) {
-				if(debug['m'])
-					warnl(src->lineno, "leaking param: %hN to result %S", src, dst->sym);
-				if((src->esc&EscMask) != EscReturn)
-					src->esc = EscReturn;
-				src->esc |= 1<<((dst->vargen-1) + EscReturnBits);
-				goto recurse;
-			} else if(level > 0) {
-				if(debug['m'])
-					warnl(src->lineno, "%N leaking param %hN content to result %S", src->curfn->nname, src, dst->sym);
-				if((src->esc&EscMask) != EscReturn)
-					src->esc = EscReturn;
-				src->esc |= EscContentEscapes;
-				goto recurse;
-			}
-		}
-	}
-
-	// The second clause is for values pointed at by an object passed to a call
-	// that returns something reached via indirect from the object.
-	// We don't know which result it is or how many indirects, so we treat it as leaking.
-	leaks = level <= 0 && dst->escloopdepth < src->escloopdepth ||
-		level < 0 && dst == &e->funcParam && haspointers(src->type);
-
-	switch(src->op) {
-	case ONAME:
-		if(src->class == PPARAM && (leaks || dst->escloopdepth < 0) && src->esc != EscHeap) {
-			src->esc = EscScope;
-			if(debug['m'])
-				warnl(src->lineno, "leaking param: %hN", src);
-		}
-
-		// Treat a PPARAMREF closure variable as equivalent to the
-		// original variable.
-		if(src->class == PPARAMREF) {
-			if(leaks && debug['m'])
-				warnl(src->lineno, "leaking closure reference %hN", src);
-			escwalk(e, level, dst, src->closure);
-		}
-		break;
-
-	case OPTRLIT:
-	case OADDR:
-		if(leaks) {
-			src->esc = EscHeap;
-			addrescapes(src->left);
-			if(debug['m'])
-				warnl(src->lineno, "%hN escapes to heap", src);
-		}
-		newlevel = level;
-		if(level > MinLevel)
-			newlevel--;
-		escwalk(e, newlevel, dst, src->left);
-		break;
-
-	case OARRAYLIT:
-		if(isfixedarray(src->type))
-			break;
-		// fall through
-	case ODDDARG:
-	case OMAKECHAN:
-	case OMAKEMAP:
-	case OMAKESLICE:
-	case OMAPLIT:
-	case ONEW:
-	case OCLOSURE:
-	case OCALLPART:
-		if(leaks) {
-			src->esc = EscHeap;
-			if(debug['m'])
-				warnl(src->lineno, "%hN escapes to heap", src);
-		}
-		break;
-
-	case ODOT:
-	case OSLICE:
-	case OSLICEARR:
-	case OSLICE3:
-	case OSLICE3ARR:
-		escwalk(e, level, dst, src->left);
-		break;
-
-	case OINDEX:
-		if(isfixedarray(src->left->type)) {
-			escwalk(e, level, dst, src->left);
-			break;
-		}
-		// fall through
-	case ODOTPTR:
-	case OINDEXMAP:
-	case OIND:
-		newlevel = level;
-		if(level > MinLevel)
-			newlevel++;
-		escwalk(e, newlevel, dst, src->left);
-	}
-
-recurse:
-	for(ll=src->escflowsrc; ll; ll=ll->next)
-		escwalk(e, level, dst, ll->n);
-
-	e->pdepth--;
-}
-
-static void
-esctag(EscState *e, Node *func)
-{
-	Node *savefn;
-	NodeList *ll;
-	Type *t;
-
-	USED(e);
-	func->esc = EscFuncTagged;
-	
-	// External functions are assumed unsafe,
-	// unless //go:noescape is given before the declaration.
-	if(func->nbody == nil) {
-		if(func->noescape) {
-			for(t=getinargx(func->type)->type; t; t=t->down)
-				if(haspointers(t->type))
-					t->note = mktag(EscNone);
-		}
-		return;
-	}
-
-	savefn = curfn;
-	curfn = func;
-
-	for(ll=curfn->dcl; ll; ll=ll->next) {
-		if(ll->n->op != ONAME || ll->n->class != PPARAM)
-			continue;
-
-		switch (ll->n->esc&EscMask) {
-		case EscNone:	// not touched by escflood
-		case EscReturn:	
-			if(haspointers(ll->n->type)) // don't bother tagging for scalars
-				ll->n->paramfld->note = mktag(ll->n->esc);
-			break;
-		case EscHeap:	// touched by escflood, moved to heap
-		case EscScope:	// touched by escflood, value leaves scope
-			break;
-		}
-	}
-
-	curfn = savefn;
-}
diff --git a/src/cmd/gc/export.c b/src/cmd/gc/export.c
deleted file mode 100644
index da5984c..0000000
--- a/src/cmd/gc/export.c
+++ /dev/null
@@ -1,521 +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	<u.h>
-#include	<libc.h>
-#include	"go.h"
-#include	"y.tab.h"
-
-static void	dumpexporttype(Type *t);
-
-// Mark n's symbol as exported
-void
-exportsym(Node *n)
-{
-	if(n == N || n->sym == S)
-		return;
-	if(n->sym->flags & (SymExport|SymPackage)) {
-		if(n->sym->flags & SymPackage)
-			yyerror("export/package mismatch: %S", n->sym);
-		return;
-	}
-	n->sym->flags |= SymExport;
-
-	if(debug['E'])
-		print("export symbol %S\n", n->sym);
-	exportlist = list(exportlist, n);
-}
-
-int
-exportname(char *s)
-{
-	Rune r;
-
-	if((uchar)s[0] < Runeself)
-		return 'A' <= s[0] && s[0] <= 'Z';
-	chartorune(&r, s);
-	return isupperrune(r);
-}
-
-static int
-initname(char *s)
-{
-	return strcmp(s, "init") == 0;
-}
-
-// exportedsym reports whether a symbol will be visible
-// to files that import our package.
-static int
-exportedsym(Sym *sym)
-{
-	// Builtins are visible everywhere.
-	if(sym->pkg == builtinpkg || sym->origpkg == builtinpkg)
-		return 1;
-
-	return sym->pkg == localpkg && exportname(sym->name);
-}
-
-void
-autoexport(Node *n, int ctxt)
-{
-	if(n == N || n->sym == S)
-		return;
-	if((ctxt != PEXTERN && ctxt != PFUNC) || dclcontext != PEXTERN)
-		return;
-	if(n->ntype && n->ntype->op == OTFUNC && n->ntype->left)	// method
-		return;
-	// -A is for cmd/gc/mkbuiltin script, so export everything
-	if(debug['A'] || exportname(n->sym->name) || initname(n->sym->name))
-		exportsym(n);
-}
-
-static void
-dumppkg(Pkg *p)
-{
-	char *suffix;
-
-	if(p == nil || p == localpkg || p->exported || p == builtinpkg)
-		return;
-	p->exported = 1;
-	suffix = "";
-	if(!p->direct)
-		suffix = " // indirect";
-	Bprint(bout, "\timport %s \"%Z\"%s\n", p->name, p->path, suffix);
-}
-
-// Look for anything we need for the inline body
-static void reexportdep(Node *n);
-static void
-reexportdeplist(NodeList *ll)
-{
-	for(; ll ;ll=ll->next)
-		reexportdep(ll->n);
-}
-
-static void
-reexportdep(Node *n)
-{
-	Type *t;
-
-	if(!n)
-		return;
-
-	//print("reexportdep %+hN\n", n);
-	switch(n->op) {
-	case ONAME:
-		switch(n->class&~PHEAP) {
-		case PFUNC:
-			// methods will be printed along with their type
-			// nodes for T.Method expressions
-			if(n->left && n->left->op == OTYPE)
-				break;
-			// nodes for method calls.
-			if(!n->type || n->type->thistuple > 0)
-				break;
-			// fallthrough
-		case PEXTERN:
-			if(n->sym && !exportedsym(n->sym)) {
-				if(debug['E'])
-					print("reexport name %S\n", n->sym);
-				exportlist = list(exportlist, n);
-			}
-		}
-		break;
-
-	case ODCL:
-		// Local variables in the bodies need their type.
-		t = n->left->type;
-		if(t != types[t->etype] && t != idealbool && t != idealstring) {
-			if(isptr[t->etype])
-				t = t->type;
-			if(t && t->sym && t->sym->def && !exportedsym(t->sym)) {
-				if(debug['E'])
-					print("reexport type %S from declaration\n", t->sym);
-				exportlist = list(exportlist, t->sym->def);
-			}
-		}
-		break;
-
-	case OLITERAL:
-		t = n->type;
-		if(t != types[n->type->etype] && t != idealbool && t != idealstring) {
-			if(isptr[t->etype])
-				t = t->type;
-			if(t && t->sym && t->sym->def && !exportedsym(t->sym)) {
-				if(debug['E'])
-					print("reexport literal type %S\n", t->sym);
-				exportlist = list(exportlist, t->sym->def);
-			}
-		}
-		// fallthrough
-	case OTYPE:
-		if(n->sym && !exportedsym(n->sym)) {
-			if(debug['E'])
-				print("reexport literal/type %S\n", n->sym);
-			exportlist = list(exportlist, n);
-		}
-		break;
-
-	// for operations that need a type when rendered, put the type on the export list.
-	case OCONV:
-	case OCONVIFACE:
-	case OCONVNOP:
-	case ORUNESTR:
-	case OARRAYBYTESTR:
-	case OARRAYRUNESTR:
-	case OSTRARRAYBYTE:
-	case OSTRARRAYRUNE:
-	case ODOTTYPE:
-	case ODOTTYPE2:
-	case OSTRUCTLIT:
-	case OARRAYLIT:
-	case OPTRLIT:
-	case OMAKEMAP:
-	case OMAKESLICE:
-	case OMAKECHAN:
-		t = n->type;
-		if(!t->sym && t->type)
-			t = t->type;
-		if(t && t->sym && t->sym->def && !exportedsym(t->sym)) {
-			if(debug['E'])
-				print("reexport type for expression %S\n", t->sym);
-			exportlist = list(exportlist, t->sym->def);
-		}
-		break;
-	}
-
-	reexportdep(n->left);
-	reexportdep(n->right);
-	reexportdeplist(n->list);
-	reexportdeplist(n->rlist);
-	reexportdeplist(n->ninit);
-	reexportdep(n->ntest);
-	reexportdep(n->nincr);
-	reexportdeplist(n->nbody);
-	reexportdeplist(n->nelse);
-}
-
-
-static void
-dumpexportconst(Sym *s)
-{
-	Node *n;
-	Type *t;
-
-	n = s->def;
-	typecheck(&n, Erv);
-	if(n == N || n->op != OLITERAL)
-		fatal("dumpexportconst: oconst nil: %S", s);
-
-	t = n->type;	// may or may not be specified
-	dumpexporttype(t);
-
-	if(t != T && !isideal(t))
-		Bprint(bout, "\tconst %#S %#T = %#V\n", s, t, &n->val);
-	else
-		Bprint(bout, "\tconst %#S = %#V\n", s, &n->val);
-}
-
-static void
-dumpexportvar(Sym *s)
-{
-	Node *n;
-	Type *t;
-
-	n = s->def;
-	typecheck(&n, Erv|Ecall);
-	if(n == N || n->type == T) {
-		yyerror("variable exported but not defined: %S", s);
-		return;
-	}
-
-	t = n->type;
-	dumpexporttype(t);
-
-	if(t->etype == TFUNC && n->class == PFUNC) {
-		if (n->inl) {
-			// 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(n);
-			// NOTE: The space after %#S here is necessary for ld's export data parser.
-			Bprint(bout, "\tfunc %#S %#hT { %#H }\n", s, t, n->inl);
-			reexportdeplist(n->inl);
-		} else
-			Bprint(bout, "\tfunc %#S %#hT\n", s, t);
-	} else
-		Bprint(bout, "\tvar %#S %#T\n", s, t);
-}
-
-static int
-methcmp(const void *va, const void *vb)
-{
-	Type *a, *b;
-	
-	a = *(Type**)va;
-	b = *(Type**)vb;
-	return strcmp(a->sym->name, b->sym->name);
-}
-
-static void
-dumpexporttype(Type *t)
-{
-	Type *f;
-	Type **m;
-	int i, n;
-
-	if(t == T)
-		return;
-	if(t->printed || t == types[t->etype] || t == bytetype || t == runetype || t == errortype)
-		return;
-	t->printed = 1;
-
-	if(t->sym != S && t->etype != TFIELD)
-		dumppkg(t->sym->pkg);
-
-	dumpexporttype(t->type);
-	dumpexporttype(t->down);
-
-	if (t->sym == S || t->etype == TFIELD)
-		return;
-
-	n = 0;
-	for(f=t->method; f!=T; f=f->down) {	
-		dumpexporttype(f);
-		n++;
-	}
-
-	m = mal(n*sizeof m[0]);
-	i = 0;
-	for(f=t->method; f!=T; f=f->down)
-		m[i++] = f;
-	qsort(m, n, sizeof m[0], methcmp);
-
-	Bprint(bout, "\ttype %#S %#lT\n", t->sym, t);
-	for(i=0; i<n; i++) {
-		f = m[i];
-		if(f->nointerface)
-			Bprint(bout, "\t//go:nointerface\n");
-		if (f->type->nname && f->type->nname->inl) { // 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);
-			Bprint(bout, "\tfunc (%#T) %#hhS %#hT { %#H }\n", getthisx(f->type)->type, f->sym, f->type, f->type->nname->inl);
-			reexportdeplist(f->type->nname->inl);
-		} else
-			Bprint(bout, "\tfunc (%#T) %#hhS %#hT\n", getthisx(f->type)->type, f->sym, f->type);
-	}
-}
-
-static void
-dumpsym(Sym *s)
-{
-	if(s->flags & SymExported)
-		return;
-	s->flags |= SymExported;
-
-	if(s->def == N) {
-		yyerror("unknown export symbol: %S", s);
-		return;
-	}
-//	print("dumpsym %O %+S\n", s->def->op, s);
-	dumppkg(s->pkg);
-
-	switch(s->def->op) {
-	default:
-		yyerror("unexpected export symbol: %O %S", s->def->op, s);
-		break;
-
-	case OLITERAL:
-		dumpexportconst(s);
-		break;
-
-	case OTYPE:
-		if(s->def->type->etype == TFORW)
-			yyerror("export of incomplete type %S", s);
-		else
-			dumpexporttype(s->def->type);
-		break;
-
-	case ONAME:
-		dumpexportvar(s);
-		break;
-	}
-}
-
-void
-dumpexport(void)
-{
-	NodeList *l;
-	int32 i, lno;
-	Pkg *p;
-
-	lno = lineno;
-
-	Bprint(bout, "\n$$\npackage %s", localpkg->name);
-	if(safemode)
-		Bprint(bout, " safe");
-	Bprint(bout, "\n");
-
-	for(i=0; i<nelem(phash); i++)
-		for(p=phash[i]; p; p=p->link)
-			if(p->direct)
-				dumppkg(p);
-
-	for(l=exportlist; l; l=l->next) {
-		lineno = l->n->lineno;
-		dumpsym(l->n->sym);
-	}
-
-	Bprint(bout, "\n$$\n");
-	lineno = lno;
-}
-
-/*
- * import
- */
-
-/*
- * return the sym for ss, which should match lexical
- */
-Sym*
-importsym(Sym *s, int op)
-{
-	char *pkgstr;
-
-	if(s->def != N && s->def->op != op) {
-		pkgstr = smprint("during import \"%Z\"", importpkg->path);
-		redeclare(s, pkgstr);
-	}
-
-	// mark the symbol so it is not reexported
-	if(s->def == N) {
-		if(exportname(s->name) || initname(s->name))
-			s->flags |= SymExport;
-		else
-			s->flags |= SymPackage;	// package scope
-	}
-	return s;
-}
-
-/*
- * return the type pkg.name, forward declaring if needed
- */
-Type*
-pkgtype(Sym *s)
-{
-	Type *t;
-
-	importsym(s, OTYPE);
-	if(s->def == N || s->def->op != OTYPE) {
-		t = typ(TFORW);
-		t->sym = s;
-		s->def = typenod(t);
-	}
-	if(s->def->type == T)
-		yyerror("pkgtype %S", s);
-	return s->def->type;
-}
-
-void
-importimport(Sym *s, Strlit *z)
-{
-	// Informational: record package name
-	// associated with import path, for use in
-	// human-readable messages.
-	Pkg *p;
-
-	if(isbadimport(z))
-		errorexit();
-	p = mkpkg(z);
-	if(p->name == nil) {
-		p->name = s->name;
-		pkglookup(s->name, nil)->npkg++;
-	} else if(strcmp(p->name, s->name) != 0)
-		yyerror("conflicting names %s and %s for package \"%Z\"", p->name, s->name, p->path);
-	
-	if(!incannedimport && myimportpath != nil && strcmp(z->s, myimportpath) == 0) {
-		yyerror("import \"%Z\": package depends on \"%Z\" (import cycle)", importpkg->path, z);
-		errorexit();
-	}
-}
-
-void
-importconst(Sym *s, Type *t, Node *n)
-{
-	Node *n1;
-
-	importsym(s, OLITERAL);
-	convlit(&n, t);
-
-	if(s->def != N)	 // TODO: check if already the same.
-		return;
-
-	if(n->op != OLITERAL) {
-		yyerror("expression must be a constant");
-		return;
-	}
-
-	if(n->sym != S) {
-		n1 = nod(OXXX, N, N);
-		*n1 = *n;
-		n = n1;
-	}
-	n->orig = newname(s);
-	n->sym = s;
-	declare(n, PEXTERN);
-
-	if(debug['E'])
-		print("import const %S\n", s);
-}
-
-void
-importvar(Sym *s, Type *t)
-{
-	Node *n;
-
-	importsym(s, ONAME);
-	if(s->def != N && s->def->op == ONAME) {
-		if(eqtype(t, s->def->type))
-			return;
-		yyerror("inconsistent definition for var %S during import\n\t%T (in \"%Z\")\n\t%T (in \"%Z\")", s, s->def->type, s->importdef->path, t, importpkg->path);
-	}
-	n = newname(s);
-	s->importdef = importpkg;
-	n->type = t;
-	declare(n, PEXTERN);
-
-	if(debug['E'])
-		print("import var %S %lT\n", s, t);
-}
-
-void
-importtype(Type *pt, Type *t)
-{
-	Node *n;
-
-	// override declaration in unsafe.go for Pointer.
-	// there is no way in Go code to define unsafe.Pointer
-	// so we have to supply it.
-	if(incannedimport &&
-	   strcmp(importpkg->name, "unsafe") == 0 &&
-	   strcmp(pt->nod->sym->name, "Pointer") == 0) {
-		t = types[TUNSAFEPTR];
-	}
-
-	if(pt->etype == TFORW) {
-		n = pt->nod;
-		copytype(pt->nod, t);
-		pt->nod = n;		// unzero nod
-		pt->sym->importdef = importpkg;
-		pt->sym->lastlineno = parserline();
-		declare(n, PEXTERN);
-		checkwidth(pt);
-	} else if(!eqtype(pt->orig, t))
-		yyerror("inconsistent definition for type %S during import\n\t%lT (in \"%Z\")\n\t%lT (in \"%Z\")", pt->sym, pt, pt->sym->importdef->path, t, importpkg->path);
-
-	if(debug['E'])
-		print("import type %T %lT\n", pt, t);
-}
diff --git a/src/cmd/gc/fmt.c b/src/cmd/gc/fmt.c
deleted file mode 100644
index 89d2a14..0000000
--- a/src/cmd/gc/fmt.c
+++ /dev/null
@@ -1,1691 +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.
-
-#include	<u.h>
-#include	<libc.h>
-#include	"go.h"
-#include	"opnames.h"
-
-//
-// Format conversions
-//	%L int		Line numbers
-//
-//	%E int		etype values (aka 'Kind')
-//
-//	%O int		Node Opcodes
-//		Flags: "%#O": print go syntax. (automatic unless fmtmode == FDbg)
-//
-//	%J Node*	Node details
-//		Flags: "%hJ" suppresses things not relevant until walk.
-//
-//	%V Val*		Constant values
-//
-//	%S Sym*		Symbols
-//		Flags: +,- #: mode (see below)
-//			"%hS"	unqualified identifier in any mode
-//			"%hhS"  in export mode: unqualified identifier if exported, qualified if not
-//
-//	%T Type*	Types
-//		Flags: +,- #: mode (see below)
-//			'l' definition instead of name.
-//			'h' omit "func" and receiver in function types
-//			'u' (only in -/Sym mode) print type identifiers wit package name instead of prefix.
-//
-//	%N Node*	Nodes
-//		Flags: +,- #: mode (see below)
-//			'h' (only in +/debug mode) suppress recursion
-//			'l' (only in Error mode) print "foo (type Bar)"
-//
-//	%H NodeList*	NodeLists
-//		Flags: those of %N
-//			','  separate items with ',' instead of ';'
-//
-//	%Z Strlit*	String literals
-//
-//   In mparith1.c:
-//      %B Mpint*	Big integers
-//	%F Mpflt*	Big floats
-//
-//   %S, %T and %N obey use the following flags to set the format mode:
-enum {
-	FErr,	//     error mode (default)
-	FDbg,	//     "%+N" debug mode
-	FExp,	//     "%#N" export mode
-	FTypeId,  //   "%-N" turning-types-into-symbols-mode: identical types give identical strings
-};
-static int fmtmode;
-static int fmtpkgpfx;	// %uT stickyness
-//
-// E.g. for %S:	%+S %#S %-S	print an identifier properly qualified for debug/export/internal mode.
-//
-// The mode flags  +, - and # are sticky, meaning they persist through
-// recursions of %N, %T and %S, but not the h and l flags.  The u flag is
-// sticky only on %T recursions and only used in %-/Sym mode.
-
-//
-// Useful format combinations:
-//
-//	%+N   %+H	multiline recursive debug dump of node/nodelist
-//	%+hN  %+hH	non recursive debug dump
-//
-//	%#N   %#T	export format
-//	%#lT		type definition instead of name
-//	%#hT		omit"func" and receiver in function signature
-//
-//	%lN		"foo (type Bar)" for error messages
-//
-//	%-T		type identifiers
-//	%-hT		type identifiers without "func" and arg names in type signatures (methodsym)
-//	%-uT		type identifiers with package name instead of prefix (typesym, dcommontype, typehash)
-//
-
-
-static int
-setfmode(unsigned long *flags)
-{
-	int fm;
-
-	fm = fmtmode;
-	if(*flags & FmtSign)
-		fmtmode = FDbg;
-	else if(*flags & FmtSharp)
-		fmtmode = FExp;
-	else if(*flags & FmtLeft)
-		fmtmode = FTypeId;
-
-	*flags &= ~(FmtSharp|FmtLeft|FmtSign);
-	return fm;
-}
-
-// Fmt "%L": Linenumbers
-static int
-Lconv(Fmt *fp)
-{
-	return linklinefmt(ctxt, fp);
-}
-
-static char*
-goopnames[] =
-{
-	[OADDR]		= "&",
-	[OADD]		= "+",
-	[OADDSTR]	= "+",
-	[OANDAND]	= "&&",
-	[OANDNOT]	= "&^",
-	[OAND]		= "&",
-	[OAPPEND]	= "append",
-	[OAS]		= "=",
-	[OAS2]		= "=",
-	[OBREAK]	= "break",
-	[OCALL]		= "function call",	// not actual syntax
-	[OCAP]		= "cap",
-	[OCASE]		= "case",
-	[OCLOSE]	= "close",
-	[OCOMPLEX]	= "complex",
-	[OCOM]		= "^",
-	[OCONTINUE]	= "continue",
-	[OCOPY]		= "copy",
-	[ODEC]		= "--",
-	[ODELETE]	= "delete",
-	[ODEFER]	= "defer",
-	[ODIV]		= "/",
-	[OEQ]		= "==",
-	[OFALL]		= "fallthrough",
-	[OFOR]		= "for",
-	[OGE]		= ">=",
-	[OGOTO]		= "goto",
-	[OGT]		= ">",
-	[OIF]		= "if",
-	[OIMAG]		= "imag",
-	[OINC]		= "++",
-	[OIND]		= "*",
-	[OLEN]		= "len",
-	[OLE]		= "<=",
-	[OLSH]		= "<<",
-	[OLT]		= "<",
-	[OMAKE]		= "make",
-	[OMINUS]	= "-",
-	[OMOD]		= "%",
-	[OMUL]		= "*",
-	[ONEW]		= "new",
-	[ONE]		= "!=",
-	[ONOT]		= "!",
-	[OOROR]		= "||",
-	[OOR]		= "|",
-	[OPANIC]	= "panic",
-	[OPLUS]		= "+",
-	[OPRINTN]	= "println",
-	[OPRINT]	= "print",
-	[ORANGE]	= "range",
-	[OREAL]		= "real",
-	[ORECV]		= "<-",
-	[ORECOVER]	= "recover",
-	[ORETURN]	= "return",
-	[ORSH]		= ">>",
-	[OSELECT]	= "select",
-	[OSEND]		= "<-",
-	[OSUB]		= "-",
-	[OSWITCH]	= "switch",
-	[OXOR]		= "^",
-};
-
-// Fmt "%O":  Node opcodes
-static int
-Oconv(Fmt *fp)
-{
-	int o;
-
-	o = va_arg(fp->args, int);
-	if((fp->flags & FmtSharp) || fmtmode != FDbg)
-		if(o >= 0 && o < nelem(goopnames) && goopnames[o] != nil)
-			return fmtstrcpy(fp, goopnames[o]);
-
-	if(o >= 0 && o < nelem(opnames) && opnames[o] != nil)
-		return fmtstrcpy(fp, opnames[o]);
-
-	return fmtprint(fp, "O-%d", o);
-}
-
-static const char* classnames[] = {
-	"Pxxx",
-	"PEXTERN",
-	"PAUTO",
-	"PPARAM",
-	"PPARAMOUT",
-	"PPARAMREF",
-	"PFUNC",
-};
-
-// Fmt "%J": Node details.
-static int
-Jconv(Fmt *fp)
-{
-	Node *n;
-	char *s;
-	int c;
-
-	n = va_arg(fp->args, Node*);
-
-	c = fp->flags&FmtShort;
-
-	if(!c && n->ullman != 0)
-		fmtprint(fp, " u(%d)", n->ullman);
-
-	if(!c && n->addable != 0)
-		fmtprint(fp, " a(%d)", n->addable);
-
-	if(!c && n->vargen != 0)
-		fmtprint(fp, " g(%d)", n->vargen);
-
-	if(n->lineno != 0)
-		fmtprint(fp, " l(%d)", n->lineno);
-
-	if(!c && n->xoffset != BADWIDTH)
-		fmtprint(fp, " x(%lld%+lld)", n->xoffset, n->stkdelta);
-
-	if(n->class != 0) {
-		s = "";
-		if(n->class & PHEAP) s = ",heap";
-		if((n->class & ~PHEAP) < nelem(classnames))
-			fmtprint(fp, " class(%s%s)", classnames[n->class&~PHEAP], s);
-		else
-			fmtprint(fp, " class(%d?%s)", n->class&~PHEAP, s);
-	}
-
-	if(n->colas != 0)
-		fmtprint(fp, " colas(%d)", n->colas);
-
-	if(n->funcdepth != 0)
-		fmtprint(fp, " f(%d)", n->funcdepth);
-
-	switch(n->esc) {
-	case EscUnknown:
-		break;
-	case EscHeap:
-		fmtprint(fp, " esc(h)");
-		break;
-	case EscScope:
-		fmtprint(fp, " esc(s)");
-		break;
-	case EscNone:
-		fmtprint(fp, " esc(no)");
-		break;
-	case EscNever:
-		if(!c)
-			fmtprint(fp, " esc(N)");
-		break;
-	default:
-		fmtprint(fp, " esc(%d)", n->esc);
-		break;
-	}
-
-	if(n->escloopdepth)
-		fmtprint(fp, " ld(%d)", n->escloopdepth);
-
-	if(!c && n->typecheck != 0)
-		fmtprint(fp, " tc(%d)", n->typecheck);
-
-	if(!c && n->dodata != 0)
-		fmtprint(fp, " dd(%d)", n->dodata);
-
-	if(n->isddd != 0)
-		fmtprint(fp, " isddd(%d)", n->isddd);
-
-	if(n->implicit != 0)
-		fmtprint(fp, " implicit(%d)", n->implicit);
-
-	if(n->embedded != 0)
-		fmtprint(fp, " embedded(%d)", n->embedded);
-
-	if(!c && n->used != 0)
-		fmtprint(fp, " used(%d)", n->used);
-	return 0;
-}
-
-// Fmt "%V": Values
-static int
-Vconv(Fmt *fp)
-{
-	Val *v;
-	vlong x;
-
-	v = va_arg(fp->args, Val*);
-
-	switch(v->ctype) {
-	case CTINT:
-		if((fp->flags & FmtSharp) || fmtmode == FExp)
-			return fmtprint(fp, "%#B", v->u.xval);
-		return fmtprint(fp, "%B", v->u.xval);
-	case CTRUNE:
-		x = mpgetfix(v->u.xval);
-		if(' ' <= x && x < 0x80 && x != '\\' && x != '\'')
-			return fmtprint(fp, "'%c'", (int)x);
-		if(0 <= x && x < (1<<16))
-			return fmtprint(fp, "'\\u%04ux'", (int)x);
-		if(0 <= x && x <= Runemax)
-			return fmtprint(fp, "'\\U%08llux'", x);
-		return fmtprint(fp, "('\\x00' + %B)", v->u.xval);
-	case CTFLT:
-		if((fp->flags & FmtSharp) || fmtmode == FExp)
-			return fmtprint(fp, "%F", v->u.fval);
-		return fmtprint(fp, "%#F", v->u.fval);
-	case CTCPLX:
-		if((fp->flags & FmtSharp) || fmtmode == FExp)
-			return fmtprint(fp, "(%F+%Fi)", &v->u.cval->real, &v->u.cval->imag);
-		if(mpcmpfltc(&v->u.cval->real, 0) == 0)
-			return fmtprint(fp, "%#Fi", &v->u.cval->imag);
-		if(mpcmpfltc(&v->u.cval->imag, 0) == 0)
-			return fmtprint(fp, "%#F", &v->u.cval->real);
-		if(mpcmpfltc(&v->u.cval->imag, 0) < 0)
-			return fmtprint(fp, "(%#F%#Fi)", &v->u.cval->real, &v->u.cval->imag);
-		return fmtprint(fp, "(%#F+%#Fi)", &v->u.cval->real, &v->u.cval->imag);
-	case CTSTR:
-		return fmtprint(fp, "\"%Z\"", v->u.sval);
-	case CTBOOL:
-		if( v->u.bval)
-			return fmtstrcpy(fp, "true");
-		return fmtstrcpy(fp, "false");
-	case CTNIL:
-		return fmtstrcpy(fp, "nil");
-	}
-	return fmtprint(fp, "<ctype=%d>", v->ctype);
-}
-
-// Fmt "%Z": escaped string literals
-static int
-Zconv(Fmt *fp)
-{
-	Rune r;
-	Strlit *sp;
-	char *s, *se;
-	int n;
-
-	sp = va_arg(fp->args, Strlit*);
-	if(sp == nil)
-		return fmtstrcpy(fp, "<nil>");
-
-	s = sp->s;
-	se = s + sp->len;
-
-	// NOTE: Keep in sync with ../ld/go.c:/^Zconv.
-	while(s < se) {
-		n = chartorune(&r, s);
-		s += n;
-		switch(r) {
-		case Runeerror:
-			if(n == 1) {
-				fmtprint(fp, "\\x%02x", (uchar)*(s-1));
-				break;
-			}
-			// fall through
-		default:
-			if(r < ' ') {
-				fmtprint(fp, "\\x%02x", r);
-				break;
-			}
-			fmtrune(fp, r);
-			break;
-		case '\t':
-			fmtstrcpy(fp, "\\t");
-			break;
-		case '\n':
-			fmtstrcpy(fp, "\\n");
-			break;
-		case '\"':
-		case '\\':
-			fmtrune(fp, '\\');
-			fmtrune(fp, r);
-			break;
-		case 0xFEFF: // BOM, basically disallowed in source code
-			fmtstrcpy(fp, "\\uFEFF");
-			break;
-		}
-	}
-	return 0;
-}
-
-/*
-s%,%,\n%g
-s%\n+%\n%g
-s%^[	]*T%%g
-s%,.*%%g
-s%.+%	[T&]		= "&",%g
-s%^	........*\]%&~%g
-s%~	%%g
-*/
-
-static char*
-etnames[] =
-{
-	[TINT]		= "INT",
-	[TUINT]		= "UINT",
-	[TINT8]		= "INT8",
-	[TUINT8]	= "UINT8",
-	[TINT16]	= "INT16",
-	[TUINT16]	= "UINT16",
-	[TINT32]	= "INT32",
-	[TUINT32]	= "UINT32",
-	[TINT64]	= "INT64",
-	[TUINT64]	= "UINT64",
-	[TUINTPTR]	= "UINTPTR",
-	[TFLOAT32]	= "FLOAT32",
-	[TFLOAT64]	= "FLOAT64",
-	[TCOMPLEX64]	= "COMPLEX64",
-	[TCOMPLEX128]	= "COMPLEX128",
-	[TBOOL]		= "BOOL",
-	[TPTR32]	= "PTR32",
-	[TPTR64]	= "PTR64",
-	[TFUNC]		= "FUNC",
-	[TARRAY]	= "ARRAY",
-	[TSTRUCT]	= "STRUCT",
-	[TCHAN]		= "CHAN",
-	[TMAP]		= "MAP",
-	[TINTER]	= "INTER",
-	[TFORW]		= "FORW",
-	[TFIELD]	= "FIELD",
-	[TSTRING]	= "STRING",
-	[TANY]		= "ANY",
-};
-
-// Fmt "%E": etype
-static int
-Econv(Fmt *fp)
-{
-	int et;
-
-	et = va_arg(fp->args, int);
-	if(et >= 0 && et < nelem(etnames) && etnames[et] != nil)
-		return fmtstrcpy(fp, etnames[et]);
-	return fmtprint(fp, "E-%d", et);
-}
-
-// Fmt "%S": syms
-static int
-symfmt(Fmt *fp, Sym *s)
-{
-	char *p;
-
-	if(s->pkg && !(fp->flags&FmtShort)) {
-		switch(fmtmode) {
-		case FErr:	// This is for the user
-			if(s->pkg == localpkg)
-				return fmtstrcpy(fp, s->name);
-			// If the name was used by multiple packages, display the full path,
-			if(s->pkg->name && pkglookup(s->pkg->name, nil)->npkg > 1)
-				return fmtprint(fp, "\"%Z\".%s", s->pkg->path, s->name);
-			return fmtprint(fp, "%s.%s", s->pkg->name, s->name);
-		case FDbg:
-			return fmtprint(fp, "%s.%s", s->pkg->name, s->name);
-		case FTypeId:
-			if(fp->flags&FmtUnsigned)
-				return fmtprint(fp, "%s.%s", s->pkg->name, s->name);	// dcommontype, typehash
-			return fmtprint(fp, "%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 fmtprint(fp, "@\"%Z\".%s", s->pkg->path, s->name);
-		}
-	}
-
-	if(fp->flags&FmtByte) {  // FmtByte (hh) implies FmtShort (h)
-		// skip leading "type." in method name
-		p = utfrrune(s->name, '.');
-		if(p)
-			p++;
-		else
-			p = s->name;
-
-		// exportname needs to see the name without the prefix too.
-		if((fmtmode == FExp && !exportname(p)) || fmtmode == FDbg)
-			return fmtprint(fp, "@\"%Z\".%s", s->pkg->path, p);
-
-		return fmtstrcpy(fp, p);
-	}
-
-	return fmtstrcpy(fp, s->name);
-}
-
-static char*
-basicnames[] =
-{
-	[TINT]		= "int",
-	[TUINT]		= "uint",
-	[TINT8]		= "int8",
-	[TUINT8]	= "uint8",
-	[TINT16]	= "int16",
-	[TUINT16]	= "uint16",
-	[TINT32]	= "int32",
-	[TUINT32]	= "uint32",
-	[TINT64]	= "int64",
-	[TUINT64]	= "uint64",
-	[TUINTPTR]	= "uintptr",
-	[TFLOAT32]	= "float32",
-	[TFLOAT64]	= "float64",
-	[TCOMPLEX64]	= "complex64",
-	[TCOMPLEX128]	= "complex128",
-	[TBOOL]		= "bool",
-	[TANY]		= "any",
-	[TSTRING]	= "string",
-	[TNIL]		= "nil",
-	[TIDEAL]	= "untyped number",
-	[TBLANK]	= "blank",
-};
-
-static int
-typefmt(Fmt *fp, Type *t)
-{
-	Type *t1;
-	Sym *s;
-
-	if(t == T)
-		return fmtstrcpy(fp, "<T>");
-
-	if (t == bytetype || t == runetype) {
-		// in %-T mode collapse rune and byte with their originals.
-		if(fmtmode != FTypeId)
-			return fmtprint(fp, "%hS", t->sym);
-		t = types[t->etype];
-	}
-
-	if(t == errortype)
-		return fmtstrcpy(fp, "error");
-
-	// Unless the 'l' flag was specified, if the type has a name, just print that name.
-	if(!(fp->flags&FmtLong) && t->sym && t->etype != TFIELD && t != types[t->etype]) {
-		switch(fmtmode) {
-		case FTypeId:
-			if(fp->flags&FmtShort) {
-				if(t->vargen)
-					return fmtprint(fp, "%hS·%d", t->sym, t->vargen);
-				return fmtprint(fp, "%hS", t->sym);
-			}
-			if(fp->flags&FmtUnsigned)
-				return fmtprint(fp, "%uS", t->sym);
-			// fallthrough
-		case FExp:
-			if(t->sym->pkg == localpkg && t->vargen)
-				return fmtprint(fp, "%S·%d", t->sym, t->vargen);
-			break;
-		}
-		return fmtprint(fp, "%S", t->sym);
-	}
-
-	if(t->etype < nelem(basicnames) && basicnames[t->etype] != nil) {
-		if(fmtmode == FErr && (t == idealbool || t == idealstring))
-			fmtstrcpy(fp, "untyped ");
-		return fmtstrcpy(fp, basicnames[t->etype]);
-	}
-
-	if(fmtmode == FDbg)
-		fmtprint(fp, "%E-", t->etype);
-
-	switch(t->etype) {
-	case TPTR32:
-	case TPTR64:
-		if(fmtmode == FTypeId && (fp->flags&FmtShort))
-			return fmtprint(fp, "*%hT", t->type);
-		return fmtprint(fp, "*%T", t->type);
-
-	case TARRAY:
-		if(t->bound >= 0)
-			return fmtprint(fp, "[%lld]%T", t->bound, t->type);
-		if(t->bound == -100)
-			return fmtprint(fp, "[...]%T", t->type);
-		return fmtprint(fp, "[]%T", t->type);
-
-	case TCHAN:
-		switch(t->chan) {
-		case Crecv:
-			return fmtprint(fp, "<-chan %T", t->type);
-		case Csend:
-			return fmtprint(fp, "chan<- %T", t->type);
-		}
-
-		if(t->type != T && t->type->etype == TCHAN && t->type->sym == S && t->type->chan == Crecv)
-			return fmtprint(fp, "chan (%T)", t->type);
-		return fmtprint(fp, "chan %T", t->type);
-
-	case TMAP:
-		return fmtprint(fp, "map[%T]%T", t->down, t->type);
-
-	case TINTER:
-		fmtstrcpy(fp, "interface {");
-		for(t1=t->type; t1!=T; t1=t1->down)
-			if(exportname(t1->sym->name)) {
-				if(t1->down)
-					fmtprint(fp, " %hS%hT;", t1->sym, t1->type);
-				else
-					fmtprint(fp, " %hS%hT ", t1->sym, t1->type);
-			} else {
-				// non-exported method names must be qualified
-				if(t1->down)
-					fmtprint(fp, " %uS%hT;", t1->sym, t1->type);
-				else
-					fmtprint(fp, " %uS%hT ", t1->sym, t1->type);
-			}
-		fmtstrcpy(fp, "}");
-		return 0;
-
-	case TFUNC:
-		if(fp->flags & FmtShort) {
-			fmtprint(fp, "%T", getinargx(t));
-		} else {
-			if(t->thistuple)
-				fmtprint(fp, "method%T func%T", getthisx(t), getinargx(t));
-			else
-				fmtprint(fp, "func%T", getinargx(t));
-		}
-		switch(t->outtuple) {
-		case 0:
-			break;
-		case 1:
-			if(fmtmode != FExp) {
-				fmtprint(fp, " %T", getoutargx(t)->type->type);	 // struct->field->field's type
-				break;
-			}
-		default:
-			fmtprint(fp, " %T", getoutargx(t));
-			break;
-		}
-		return 0;
-
-	case TSTRUCT:
-		// 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 != T) {
-			if(t->map->bucket == t) {
-				return fmtprint(fp, "map.bucket[%T]%T", t->map->down, t->map->type);
-			}
-			if(t->map->hmap == t) {
-				return fmtprint(fp, "map.hdr[%T]%T", t->map->down, t->map->type);
-			}
-			if(t->map->hiter == t) {
-				return fmtprint(fp, "map.iter[%T]%T", t->map->down, t->map->type);
-			}
-			yyerror("unknown internal map type");
-		}
-
-		if(t->funarg) {
-			fmtstrcpy(fp, "(");
-			if(fmtmode == FTypeId || fmtmode == FErr) {	// no argument names on function signature, and no "noescape"/"nosplit" tags
-				for(t1=t->type; t1!=T; t1=t1->down)
-					if(t1->down)
-						fmtprint(fp, "%hT, ", t1);
-					else
-						fmtprint(fp, "%hT", t1);
-			} else {
-				for(t1=t->type; t1!=T; t1=t1->down)
-					if(t1->down)
-						fmtprint(fp, "%T, ", t1);
-					else
-						fmtprint(fp, "%T", t1);
-			}
-			fmtstrcpy(fp, ")");
-		} else {
-			fmtstrcpy(fp, "struct {");
-			for(t1=t->type; t1!=T; t1=t1->down)
-				if(t1->down)
-					fmtprint(fp, " %lT;", t1);
-				else
-					fmtprint(fp, " %lT ", t1);
-			fmtstrcpy(fp, "}");
-		}
-		return 0;
-
-	case TFIELD:
-		if(!(fp->flags&FmtShort)) {
-			s = t->sym;
-
-			// Take the name from the original, lest we substituted it with ~r%d or ~b%d.
-			// ~r%d is a (formerly) unnamed result.
-			if ((fmtmode == FErr || fmtmode == FExp) && t->nname != N) {
-				if(t->nname->orig != N) {
-					s = t->nname->orig->sym;
-					if(s != S && s->name[0] == '~') {
-						if(s->name[1] == 'r') // originally an unnamed result
-							s = S;
-						else if(s->name[1] == 'b') // originally the blank identifier _
-							s = lookup("_");
-					}
-				} else 
-					s = S;
-			}
-			
-			if(s != S && !t->embedded) {
-				if(t->funarg)
-					fmtprint(fp, "%N ", t->nname);
-				else if(fp->flags&FmtLong)
-					fmtprint(fp, "%hhS ", s);  // qualify non-exported names (used on structs, not on funarg)
-				else 
-					fmtprint(fp, "%S ", s);
-			} else if(fmtmode == FExp) {
-				// TODO(rsc) this breaks on the eliding of unused arguments in the backend
-				// when this is fixed, the special case in dcl.c checkarglist can go.
-				//if(t->funarg)
-				//	fmtstrcpy(fp, "_ ");
-				//else
-				if(t->embedded && s->pkg != nil && s->pkg->path->len > 0)
-					fmtprint(fp, "@\"%Z\".? ", s->pkg->path);
-				else
-					fmtstrcpy(fp, "? ");
-			}
-		}
-
-		if(t->isddd)
-			fmtprint(fp, "...%T", t->type->type);
-		else
-			fmtprint(fp, "%T", t->type);
-
-		if(!(fp->flags&FmtShort) && t->note)
-			fmtprint(fp, " \"%Z\"", t->note);
-		return 0;
-
-	case TFORW:
-		if(t->sym)
-			return fmtprint(fp, "undefined %S", t->sym);
-		return fmtstrcpy(fp, "undefined");
-
-	case TUNSAFEPTR:
-		if(fmtmode == FExp)
-			return fmtprint(fp, "@\"unsafe\".Pointer");
-		return fmtprint(fp, "unsafe.Pointer");
-	}
-
-	if(fmtmode == FExp)
-		fatal("missing %E case during export", t->etype);
-	// Don't know how to handle - fall back to detailed prints.
-	return fmtprint(fp, "%E <%S> %T", t->etype, t->sym, t->type);
-}
-
-// Statements which may be rendered with a simplestmt as init.
-static int
-stmtwithinit(int op)
-{
-	switch(op) {
-	case OIF:
-	case OFOR:
-	case OSWITCH:
-		return 1;
-	}
-	return 0;
-}
-
-static int
-stmtfmt(Fmt *f, Node *n)
-{
-	int complexinit, simpleinit, extrablock;
-
-	// some statements allow for an init, but at most one,
-	// but we may have an arbitrary number added, eg by typecheck
-	// and inlining.  If it doesn't fit the syntax, emit an enclosing
-	// block starting with the init statements.
-
-	// if we can just say "for" n->ninit; ... then do so
-	simpleinit = n->ninit && !n->ninit->next && !n->ninit->n->ninit && stmtwithinit(n->op);
-	// otherwise, print the inits as separate statements
-	complexinit = n->ninit && !simpleinit && (fmtmode != FErr);
-	// but if it was for if/for/switch, put in an extra surrounding block to limit the scope
-	extrablock = complexinit && stmtwithinit(n->op);
-
-	if(extrablock)
-		fmtstrcpy(f, "{");
-
-	if(complexinit)
-		fmtprint(f, " %H; ", n->ninit);
-
-	switch(n->op){
-	case ODCL:
-		if(fmtmode == FExp) {
-			switch(n->left->class&~PHEAP) {
-			case PPARAM:
-			case PPARAMOUT:
-			case PAUTO:
-				fmtprint(f, "var %N %T", n->left, n->left->type);
-				goto ret;
-			}
-		}			
-		fmtprint(f, "var %S %T", n->left->sym, n->left->type);
-		break;
-
-	case ODCLFIELD:
-		if(n->left)
-			fmtprint(f, "%N %N", n->left, n->right);
-		else
-			fmtprint(f, "%N", n->right);
-		break;
-
-	case OAS:
-		// Don't export "v = <N>" initializing statements, hope they're always 
-		// preceded by the DCL which will be re-parsed and typecheck to reproduce
-		// the "v = <N>" again.
-		if(fmtmode == FExp && n->right == N)
-			break;
-
-		if(n->colas && !complexinit)
-			fmtprint(f, "%N := %N", n->left, n->right);
-		else
-			fmtprint(f, "%N = %N", n->left, n->right);
-		break;
-
-	case OASOP:
-		if(n->implicit) {
-			if(n->etype == OADD)
-				fmtprint(f, "%N++", n->left);
-			else
-				fmtprint(f, "%N--", n->left);
-			break;
-		}
-		fmtprint(f, "%N %#O= %N", n->left, n->etype, n->right);
-		break;
-
-	case OAS2:
-		if(n->colas && !complexinit) {
-			fmtprint(f, "%,H := %,H", n->list, n->rlist);
-			break;
-		}
-		// fallthrough
-	case OAS2DOTTYPE:
-	case OAS2FUNC:
-	case OAS2MAPR:
-	case OAS2RECV:
-		fmtprint(f, "%,H = %,H", n->list, n->rlist);
-		break;
-
-	case ORETURN:
-		fmtprint(f, "return %,H", n->list);
-		break;
-
-	case ORETJMP:
-		fmtprint(f, "retjmp %S", n->sym);
-		break;
-	
-	case OPROC:
-		fmtprint(f, "go %N", n->left);
-		break;
-
-	case ODEFER:
-		fmtprint(f, "defer %N", n->left);
-		break;
-
-	case OIF:
-		if(simpleinit)
-			fmtprint(f, "if %N; %N { %H }", n->ninit->n, n->ntest, n->nbody);
-		else
-			fmtprint(f, "if %N { %H }", n->ntest, n->nbody);
-		if(n->nelse)
-			fmtprint(f, " else { %H }", n->nelse);
-		break;
-
-	case OFOR:
-		if(fmtmode == FErr) {	// TODO maybe only if FmtShort, same below
-			fmtstrcpy(f, "for loop");
-			break;
-		}
-
-		fmtstrcpy(f, "for");
-		if(simpleinit)
-			fmtprint(f, " %N;", n->ninit->n);
-		else if(n->nincr)
-			fmtstrcpy(f, " ;");
-
-		if(n->ntest)
-			fmtprint(f, " %N", n->ntest);
-
-		if(n->nincr)
-			fmtprint(f, "; %N", n->nincr);
-		else if(simpleinit)
-			fmtstrcpy(f, ";");
-
-
-		fmtprint(f, " { %H }", n->nbody);
-		break;
-
-	case ORANGE:
-		if(fmtmode == FErr) {
-			fmtstrcpy(f, "for loop");
-			break;
-		}
-		
-		if(n->list == nil) {
-			fmtprint(f, "for range %N { %H }", n->right, n->nbody);
-			break;
-		}
-		fmtprint(f, "for %,H = range %N { %H }", n->list, n->right, n->nbody);
-		break;
-
-	case OSELECT:
-	case OSWITCH:
-		if(fmtmode == FErr) {
-			fmtprint(f, "%O statement", n->op);
-			break;
-		}
-
-		fmtprint(f, "%#O", n->op);
-		if(simpleinit)
-			fmtprint(f, " %N;", n->ninit->n);
-		if(n->ntest)
-			fmtprint(f, "%N", n->ntest);
-
-		fmtprint(f, " { %H }", n->list);
-		break;
-
-	case OCASE:
-	case OXCASE:
-		if(n->list)
-			fmtprint(f, "case %,H: %H", n->list, n->nbody);
-		else
-			fmtprint(f, "default: %H", n->nbody);
-		break;
-
-	case OBREAK:
-	case OCONTINUE:
-	case OGOTO:
-	case OFALL:
-	case OXFALL:
-		if(n->left)
-			fmtprint(f, "%#O %N", n->op, n->left);
-		else
-			fmtprint(f, "%#O", n->op);
-		break;
-
-	case OEMPTY:
-		break;
-
-	case OLABEL:
-		fmtprint(f, "%N: ", n->left);
-		break;
-	  
-	}
-ret:
-
-	if(extrablock)
-		fmtstrcpy(f, "}");
-
-	return 0;
-}
-
-
-static int opprec[] = {
-	[OAPPEND] = 8,
-	[OARRAYBYTESTR] = 8,
-	[OARRAYLIT] = 8,
-	[OARRAYRUNESTR] = 8,
-	[OCALLFUNC] = 8,
-	[OCALLINTER] = 8,
-	[OCALLMETH] = 8,
-	[OCALL] = 8,
-	[OCAP] = 8,
-	[OCLOSE] = 8,
-	[OCONVIFACE] = 8,
-	[OCONVNOP] = 8,
-	[OCONV] = 8,
-	[OCOPY] = 8,
-	[ODELETE] = 8,
-	[OLEN] = 8,
-	[OLITERAL] = 8,
-	[OMAKESLICE] = 8,
-	[OMAKE] = 8,
-	[OMAPLIT] = 8,
-	[ONAME] = 8,
-	[ONEW] = 8,
-	[ONONAME] = 8,
-	[OPACK] = 8,
-	[OPANIC] = 8,
-	[OPAREN] = 8,
-	[OPRINTN] = 8,
-	[OPRINT] = 8,
-	[ORUNESTR] = 8,
-	[OSTRARRAYBYTE] = 8,
-	[OSTRARRAYRUNE] = 8,
-	[OSTRUCTLIT] = 8,
-	[OTARRAY] = 8,
-	[OTCHAN] = 8,
-	[OTFUNC] = 8,
-	[OTINTER] = 8,
-	[OTMAP] = 8,
-	[OTSTRUCT] = 8,
-
-	[OINDEXMAP] = 8,
-	[OINDEX] = 8,
-	[OSLICE] = 8,
-	[OSLICESTR] = 8,
-	[OSLICEARR] = 8,
-	[OSLICE3] = 8,
-	[OSLICE3ARR] = 8,
-	[ODOTINTER] = 8,
-	[ODOTMETH] = 8,
-	[ODOTPTR] = 8,
-	[ODOTTYPE2] = 8,
-	[ODOTTYPE] = 8,
-	[ODOT] = 8,
-	[OXDOT] = 8,
-	[OCALLPART] = 8,
-
-	[OPLUS] = 7,
-	[ONOT] = 7,
-	[OCOM] = 7,
-	[OMINUS] = 7,
-	[OADDR] = 7,
-	[OIND] = 7,
-	[ORECV] = 7,
-
-	[OMUL] = 6,
-	[ODIV] = 6,
-	[OMOD] = 6,
-	[OLSH] = 6,
-	[ORSH] = 6,
-	[OAND] = 6,
-	[OANDNOT] = 6,
-
-	[OADD] = 5,
-	[OSUB] = 5,
-	[OOR] = 5,
-	[OXOR] = 5,
-
-	[OEQ] = 4,
-	[OLT] = 4,
-	[OLE] = 4,
-	[OGE] = 4,
-	[OGT] = 4,
-	[ONE] = 4,
-	[OCMPSTR] = 4,
-	[OCMPIFACE] = 4,
-
-	[OSEND] = 3,
-	[OANDAND] = 2,
-	[OOROR] = 1,
-
-	// Statements handled by stmtfmt
-	[OAS] = -1,
-	[OAS2] = -1,
-	[OAS2DOTTYPE] = -1,
-	[OAS2FUNC] = -1,
-	[OAS2MAPR] = -1,
-	[OAS2RECV] = -1,
-	[OASOP] = -1,
-	[OBREAK] = -1,
-	[OCASE] = -1,
-	[OCONTINUE] = -1,
-	[ODCL] = -1,
-	[ODCLFIELD] = -1,
-	[ODEFER] = -1,
-	[OEMPTY] = -1,
-	[OFALL] = -1,
-	[OFOR] = -1,
-	[OGOTO] = -1,
-	[OIF] = -1,
-	[OLABEL] = -1,
-	[OPROC] = -1,
-	[ORANGE] = -1,
-	[ORETURN] = -1,
-	[OSELECT] = -1,
-	[OSWITCH] = -1,
-	[OXCASE] = -1,
-	[OXFALL] = -1,
-
-	[OEND] = 0
-};
-
-static int
-exprfmt(Fmt *f, Node *n, int prec)
-{
-	int nprec;
-	int ptrlit;
-	NodeList *l;
-
-	while(n && n->implicit && (n->op == OIND || n->op == OADDR))
-		n = n->left;
-
-	if(n == N)
-		return fmtstrcpy(f, "<N>");
-
-	nprec = opprec[n->op];
-	if(n->op == OTYPE && n->sym != S)
-		nprec = 8;
-
-	if(prec > nprec)
-		return fmtprint(f, "(%N)", n);
-
-	switch(n->op) {
-	case OPAREN:
-		return fmtprint(f, "(%N)", n->left);
-
-	case ODDDARG:
-		return fmtprint(f, "... argument");
-
-	case OREGISTER:
-		return fmtprint(f, "%R", n->val.u.reg);
-
-	case OLITERAL:  // this is a bit of a mess
-		if(fmtmode == FErr && n->sym != S)
-			return fmtprint(f, "%S", n->sym);
-		if(n->val.ctype == CTNIL && n->orig != N && n->orig != n)
-			return exprfmt(f, n->orig, prec);
-		if(n->type != T && 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] || (n->type->etype == TCHAN && n->type->chan == Crecv))
-				return fmtprint(f, "(%T)(%V)", n->type, &n->val);
-			else 
-				return fmtprint(f, "%T(%V)", n->type, &n->val);
-		}
-		return fmtprint(f, "%V", &n->val);
-
-	case ONAME:
-		// Special case: name used as local variable in export.
-		// _ becomes ~b%d internally; print as _ for export
-		if(fmtmode == FExp && n->sym && n->sym->name[0] == '~' && n->sym->name[1] == 'b')
-			return fmtprint(f, "_");
-		if(fmtmode == FExp && n->sym && !isblank(n) && n->vargen > 0)
-			return fmtprint(f, "%S·%d", n->sym, n->vargen);
-
-		// Special case: explicit name of func (*T) method(...) is turned into pkg.(*T).method,
-		// 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 && n->left->op == OTYPE && n->right && n->right->op == ONAME) {
-			if(isptr[n->left->type->etype])
-				return fmtprint(f, "(%T).%hhS", n->left->type, n->right->sym);
-			else
-				return fmtprint(f, "%T.%hhS", n->left->type, n->right->sym);
-		}
-		//fallthrough
-	case OPACK:
-	case ONONAME:
-		return fmtprint(f, "%S", n->sym);
-
-	case OTYPE:
-		if(n->type == T && n->sym != S)
-			return fmtprint(f, "%S", n->sym);
-		return fmtprint(f, "%T", n->type);
-
-	case OTARRAY:
-		if(n->left)
-			return fmtprint(f, "[]%N", n->left);
-		return fmtprint(f, "[]%N", n->right);  // happens before typecheck
-
-	case OTMAP:
-		return fmtprint(f, "map[%N]%N", n->left, n->right);
-
-	case OTCHAN:
-		switch(n->etype) {
-		case Crecv:
-			return fmtprint(f, "<-chan %N", n->left);
-		case Csend:
-			return fmtprint(f, "chan<- %N", n->left);
-		default:
-			if(n->left != N && n->left->op == OTCHAN && n->left->sym == S && n->left->etype == Crecv)
-				return fmtprint(f, "chan (%N)", n->left);
-			else
-				return fmtprint(f, "chan %N", n->left);
-		}
-
-	case OTSTRUCT:
-		return fmtprint(f, "<struct>");
-
-	case OTINTER:
-		return fmtprint(f, "<inter>");
-
-	case OTFUNC:
-		return fmtprint(f, "<func>");
-
-	case OCLOSURE:
-		if(fmtmode == FErr)
-			return fmtstrcpy(f, "func literal");
-		if(n->nbody)
-			return fmtprint(f, "%T { %H }", n->type, n->nbody);
-		return fmtprint(f, "%T { %H }", n->type, n->closure->nbody);
-
-	case OCOMPLIT:
-		ptrlit = n->right != N && n->right->implicit && n->right->type && isptr[n->right->type->etype];
-		if(fmtmode == FErr) {
-			if(n->right != N && n->right->type != T && !n->implicit) {
-				if(ptrlit)
-					return fmtprint(f, "&%T literal", n->right->type->type);
-				else
-					return fmtprint(f, "%T literal", n->right->type);
-			}
-			return fmtstrcpy(f, "composite literal");
-		}
-		if(fmtmode == FExp && ptrlit)
-			// typecheck has overwritten OIND by OTYPE with pointer type.
-			return fmtprint(f, "(&%T{ %,H })", n->right->type->type, n->list);
-		return fmtprint(f, "(%N{ %,H })", n->right, n->list);
-
-	case OPTRLIT:
-		if(fmtmode == FExp && n->left->implicit)
-			return fmtprint(f, "%N", n->left);
-		return fmtprint(f, "&%N", n->left);
-
-	case OSTRUCTLIT:
-		if(fmtmode == FExp) {   // requires special handling of field names
-			if(n->implicit)
-				fmtstrcpy(f, "{");
-			else
-				fmtprint(f, "(%T{", n->type);
-			for(l=n->list; l; l=l->next) {
-				fmtprint(f, " %hhS:%N", l->n->left->sym, l->n->right);
-
-				if(l->next)
-					fmtstrcpy(f, ",");
-				else
-					fmtstrcpy(f, " ");
-			}
-			if(!n->implicit)
-				return fmtstrcpy(f, "})");
-			return fmtstrcpy(f, "}");
-		}
-		// fallthrough
-
-	case OARRAYLIT:
-	case OMAPLIT:
-		if(fmtmode == FErr)
-			return fmtprint(f, "%T literal", n->type);
-		if(fmtmode == FExp && n->implicit)
-			return fmtprint(f, "{ %,H }", n->list);
-		return fmtprint(f, "(%T{ %,H })", n->type, n->list);
-
-	case OKEY:
-		if(n->left && n->right) {
-			if(fmtmode == FExp && n->left->type && n->left->type->etype == TFIELD) {
-				// requires special handling of field names
-				return fmtprint(f, "%hhS:%N", n->left->sym, n->right);
-			} else
-				return fmtprint(f, "%N:%N", n->left, n->right);
-		}
-		if(!n->left && n->right)
-			return fmtprint(f, ":%N", n->right);
-		if(n->left && !n->right)
-			return fmtprint(f, "%N:", n->left);
-		return fmtstrcpy(f, ":");
-
-	case OXDOT:
-	case ODOT:
-	case ODOTPTR:
-	case ODOTINTER:
-	case ODOTMETH:
-	case OCALLPART:
-		exprfmt(f, n->left, nprec);
-		if(n->right == N || n->right->sym == S)
-			return fmtstrcpy(f, ".<nil>");
-		return fmtprint(f, ".%hhS", n->right->sym);
-
-	case ODOTTYPE:
-	case ODOTTYPE2:
-		exprfmt(f, n->left, nprec);
-		if(n->right != N)
-			return fmtprint(f, ".(%N)", n->right);
-		return fmtprint(f, ".(%T)", n->type);
-
-	case OINDEX:
-	case OINDEXMAP:
-	case OSLICE:
-	case OSLICESTR:
-	case OSLICEARR:
-	case OSLICE3:
-	case OSLICE3ARR:
-		exprfmt(f, n->left, nprec);
-		return fmtprint(f, "[%N]", n->right);
-
-	case OCOPY:
-	case OCOMPLEX:
-		return fmtprint(f, "%#O(%N, %N)", n->op, n->left, n->right);
-
-	case OCONV:
-	case OCONVIFACE:
-	case OCONVNOP:
-	case OARRAYBYTESTR:
-	case OARRAYRUNESTR:
-	case OSTRARRAYBYTE:
-	case OSTRARRAYRUNE:
-	case ORUNESTR:
-		if(n->type == T || n->type->sym == S)
-			return fmtprint(f, "(%T)(%N)", n->type, n->left);
-		if(n->left)
-			return fmtprint(f, "%T(%N)", n->type, n->left);
-		return fmtprint(f, "%T(%,H)", n->type, n->list);
-
-	case OREAL:
-	case OIMAG:
-	case OAPPEND:
-	case OCAP:
-	case OCLOSE:
-	case ODELETE:
-	case OLEN:
-	case OMAKE:
-	case ONEW:
-	case OPANIC:
-	case ORECOVER:
-	case OPRINT:
-	case OPRINTN:
-		if(n->left)
-			return fmtprint(f, "%#O(%N)", n->op, n->left);
-		if(n->isddd)
-			return fmtprint(f, "%#O(%,H...)", n->op, n->list);
-		return fmtprint(f, "%#O(%,H)", n->op, n->list);
-
-	case OCALL:
-	case OCALLFUNC:
-	case OCALLINTER:
-	case OCALLMETH:
-		exprfmt(f, n->left, nprec);
-		if(n->isddd)
-			return fmtprint(f, "(%,H...)", n->list);
-		return fmtprint(f, "(%,H)", n->list);
-
-	case OMAKEMAP:
-	case OMAKECHAN:
-	case OMAKESLICE:
-		if(n->list) // pre-typecheck
-			return fmtprint(f, "make(%T, %,H)", n->type, n->list);
-		if(n->right)
-			return fmtprint(f, "make(%T, %N, %N)", n->type, n->left, n->right);
-		if(n->left)
-			return fmtprint(f, "make(%T, %N)", n->type, n->left);
-		return fmtprint(f, "make(%T)", n->type);
-
-	// Unary
-	case OPLUS:
-	case OMINUS:
-	case OADDR:
-	case OCOM:
-	case OIND:
-	case ONOT:
-	case ORECV:
-		if(n->left->op == n->op)
-			fmtprint(f, "%#O ", n->op);
-		else
-			fmtprint(f, "%#O", n->op);
-		return exprfmt(f, n->left, nprec+1);
-
-	// Binary
-	case OADD:
-	case OAND:
-	case OANDAND:
-	case OANDNOT:
-	case ODIV:
-	case OEQ:
-	case OGE:
-	case OGT:
-	case OLE:
-	case OLT:
-	case OLSH:
-	case OMOD:
-	case OMUL:
-	case ONE:
-	case OOR:
-	case OOROR:
-	case ORSH:
-	case OSEND:
-	case OSUB:
-	case OXOR:
-		exprfmt(f, n->left, nprec);
-		fmtprint(f, " %#O ", n->op);
-		exprfmt(f, n->right, nprec+1);
-		return 0;
-
-	case OADDSTR:
-		for(l=n->list; l; l=l->next) {
-			if(l != n->list)
-				fmtprint(f, " + ");
-			exprfmt(f, l->n, nprec);
-		}
-		return 0;
-
-	case OCMPSTR:
-	case OCMPIFACE:
-		exprfmt(f, n->left, nprec);
-		fmtprint(f, " %#O ", n->etype);
-		exprfmt(f, n->right, nprec+1);
-		return 0;
-	}
-
-	return fmtprint(f, "<node %O>", n->op);
-}
-
-static int
-nodefmt(Fmt *f, Node *n)
-{
-	Type *t;
-
-	t = n->type;
-
-	// we almost always want the original, except in export mode for literals
-	// this saves the importer some work, and avoids us having to redo some
-	// special casing for package unsafe
-	if((fmtmode != FExp || n->op != OLITERAL) && n->orig != N)
-		n = n->orig;
-
-	if(f->flags&FmtLong && t != T) {
-		if(t->etype == TNIL)
-			return fmtprint(f, "nil");
-		else
-			return fmtprint(f, "%N (type %T)", n, t);
-	}
-
-	// TODO inlining produces expressions with ninits. we can't print these yet.
-
-	if(opprec[n->op] < 0)
-		return stmtfmt(f, n);
-
-	return exprfmt(f, n, 0);
-}
-
-static int dumpdepth;
-
-static void
-indent(Fmt *fp)
-{
-	int i;
-
-	fmtstrcpy(fp, "\n");
-	for(i = 0; i < dumpdepth; ++i)
-		fmtstrcpy(fp, ".   ");
-}
-
-static int
-nodedump(Fmt *fp, Node *n)
-{
-	int recur;
-
-	if(n == N)
-		return 0;
-
-	recur = !(fp->flags&FmtShort);
-
-	if(recur) {
-		indent(fp);
-		if(dumpdepth > 10)
-			return fmtstrcpy(fp, "...");
-
-		if(n->ninit != nil) {
-			fmtprint(fp, "%O-init%H", n->op, n->ninit);
-			indent(fp);
-		}
-	}
-
-//	fmtprint(fp, "[%p]", n);
-
-	switch(n->op) {
-	default:
-		fmtprint(fp, "%O%J", n->op, n);
-		break;
-	case OREGISTER:
-	case OINDREG:
-		fmtprint(fp, "%O-%R%J", n->op, n->val.u.reg, n);
-		break;
-	case OLITERAL:
-		fmtprint(fp, "%O-%V%J", n->op, &n->val, n);
-		break;
-	case ONAME:
-	case ONONAME:
-		if(n->sym != S)
-			fmtprint(fp, "%O-%S%J", n->op, n->sym, n);
-		else
-			fmtprint(fp, "%O%J", n->op, n);
-		if(recur && n->type == T && n->ntype) {
-			indent(fp);
-			fmtprint(fp, "%O-ntype%N", n->op, n->ntype);
-		}
-		break;
-	case OASOP:
-		fmtprint(fp, "%O-%O%J", n->op, n->etype, n);
-		break;
-	case OTYPE:
-		fmtprint(fp, "%O %S%J type=%T", n->op, n->sym, n, n->type);
-		if(recur && n->type == T && n->ntype) {
-			indent(fp);
-			fmtprint(fp, "%O-ntype%N", n->op, n->ntype);
-		}
-		break;
-	}
-
-	if(n->sym != S && n->op != ONAME)
-		fmtprint(fp, " %S G%d", n->sym, n->vargen);
-
-	if(n->type != T)
-		fmtprint(fp, " %T", n->type);
-
-	if(recur) {
-		if(n->left)
-			fmtprint(fp, "%N", n->left);
-		if(n->right)
-			fmtprint(fp, "%N", n->right);
-		if(n->list) {
-			indent(fp);
-			fmtprint(fp, "%O-list%H", n->op, n->list);
-		}
-		if(n->rlist) {
-			indent(fp);
-			fmtprint(fp, "%O-rlist%H", n->op, n->rlist);
-		}
-		if(n->ntest) {
-			indent(fp);
-			fmtprint(fp, "%O-test%N", n->op, n->ntest);
-		}
-		if(n->nbody) {
-			indent(fp);
-			fmtprint(fp, "%O-body%H", n->op, n->nbody);
-		}
-		if(n->nelse) {
-			indent(fp);
-			fmtprint(fp, "%O-else%H", n->op, n->nelse);
-		}
-		if(n->nincr) {
-			indent(fp);
-			fmtprint(fp, "%O-incr%N", n->op, n->nincr);
-		}
-	}
-
-	return 0;
-}
-
-// Fmt "%S": syms
-// Flags:  "%hS" suppresses qualifying with package
-static int
-Sconv(Fmt *fp)
-{
-	Sym *s;
-	int r, sm;
-	unsigned long sf;
-
-	if(fp->flags&FmtLong)
-		return linksymfmt(fp);
-
-	s = va_arg(fp->args, Sym*);
-	if(s == S)
-		return fmtstrcpy(fp, "<S>");
-
-	if(s->name && s->name[0] == '_' && s->name[1] == '\0')
-		return fmtstrcpy(fp, "_");
-
-	sf = fp->flags;
-	sm = setfmode(&fp->flags);
-	r = symfmt(fp, s);
-	fp->flags = sf;
-	fmtmode = sm;
-	return r;
-}
-
-// Fmt "%T": types.
-// Flags: 'l' print definition, not name
-//	  'h' omit 'func' and receiver from function types, short type names
-//	  'u' package name, not prefix (FTypeId mode, sticky)
-static int
-Tconv(Fmt *fp)
-{
-	Type *t;
-	int r, sm;
-	unsigned long sf;
-
-	t = va_arg(fp->args, Type*);
-	if(t == T)
-		return fmtstrcpy(fp, "<T>");
-
-	if(t->trecur > 4)
-		return fmtstrcpy(fp, "<...>");
-
-	t->trecur++;
-	sf = fp->flags;
-	sm = setfmode(&fp->flags);
-
-	if(fmtmode == FTypeId && (sf&FmtUnsigned))
-		fmtpkgpfx++;
-	if(fmtpkgpfx)
-		fp->flags |= FmtUnsigned;
-
-	r = typefmt(fp, t);
-
-	if(fmtmode == FTypeId && (sf&FmtUnsigned))
-		fmtpkgpfx--;
-
-	fp->flags = sf;
-	fmtmode = sm;
-	t->trecur--;
-	return r;
-}
-
-// Fmt '%N': Nodes.
-// Flags: 'l' suffix with "(type %T)" where possible
-//	  '+h' in debug mode, don't recurse, no multiline output
-static int
-Nconv(Fmt *fp)
-{
-	Node *n;
-	int r, sm;
-	unsigned long sf;
-
-	n = va_arg(fp->args, Node*);
-	if(n == N)
-		return fmtstrcpy(fp, "<N>");
-	sf = fp->flags;
-	sm = setfmode(&fp->flags);
-
-	r = -1;
-	switch(fmtmode) {
-	case FErr:
-	case FExp:
-		r = nodefmt(fp, n);
-		break;
-	case FDbg:
-		dumpdepth++;
-		r = nodedump(fp, n);
-		dumpdepth--;
-		break;
-	default:
-		fatal("unhandled %%N mode");
-	}
-
-	fp->flags = sf;
-	fmtmode = sm;
-	return r;
-}
-
-// Fmt '%H': NodeList.
-// Flags: all those of %N plus ',': separate with comma's instead of semicolons.
-static int
-Hconv(Fmt *fp)
-{
-	NodeList *l;
-	int r, sm;
-	unsigned long sf;
-	char *sep;
-
-	l = va_arg(fp->args, NodeList*);
-
-	if(l == nil && fmtmode == FDbg)
-		return fmtstrcpy(fp, "<nil>");
-
-	sf = fp->flags;
-	sm = setfmode(&fp->flags);
-	r = 0;
-	sep = "; ";
-	if(fmtmode == FDbg)
-		sep = "\n";
-	else if(fp->flags & FmtComma)
-		sep = ", ";
-
-	for(;l; l=l->next) {
-		r += fmtprint(fp, "%N", l->n);
-		if(l->next)
-			r += fmtstrcpy(fp, sep);
-	}
-
-	fp->flags = sf;
-	fmtmode = sm;
-	return r;
-}
-
-void
-fmtinstallgo(void)
-{
-	fmtmode = FErr;
-	fmtinstall('E', Econv);		// etype opcodes
-	fmtinstall('J', Jconv);		// all the node flags
-	fmtinstall('H', Hconv);		// node lists
-	fmtinstall('L', Lconv);		// line number
-	fmtinstall('N', Nconv);		// node pointer
-	fmtinstall('O', Oconv);		// node opcodes
-	fmtinstall('S', Sconv);		// sym pointer
-	fmtinstall('T', Tconv);		// type pointer
-	fmtinstall('V', Vconv);		// val pointer
-	fmtinstall('Z', Zconv);		// escaped string
-
-	// These are in mparith1.c
-	fmtinstall('B', Bconv);	// big numbers
-	fmtinstall('F', Fconv);	// big float numbers
-
-}
-
-void
-dumplist(char *s, NodeList *l)
-{
-	print("%s%+H\n", s, l);
-}
-
-void
-dump(char *s, Node *n)
-{
-	print("%s [%p]%+N\n", s, n, n);
-}
diff --git a/src/cmd/gc/gen.c b/src/cmd/gc/gen.c
deleted file mode 100644
index c7c9fcd..0000000
--- a/src/cmd/gc/gen.c
+++ /dev/null
@@ -1,991 +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.
-
-/*
- * portable half of code generator.
- * mainly statements and control flow.
- */
-
-#include <u.h>
-#include <libc.h>
-#include "go.h"
-
-static void	cgen_dcl(Node *n);
-static void	cgen_proc(Node *n, int proc);
-static void	checkgoto(Node*, Node*);
-
-static Label *labellist;
-static Label *lastlabel;
-
-Node*
-sysfunc(char *name)
-{
-	Node *n;
-
-	n = newname(pkglookup(name, runtimepkg));
-	n->class = PFUNC;
-	return n;
-}
-
-/*
- * the address of n has been taken and might be used after
- * the current function returns.  mark any local vars
- * as needing to move to the heap.
- */
-void
-addrescapes(Node *n)
-{
-	char buf[100];
-	Node *oldfn;
-
-	switch(n->op) {
-	default:
-		// probably a type error already.
-		// dump("addrescapes", n);
-		break;
-
-	case ONAME:
-		if(n == nodfp)
-			break;
-
-		// if this is a tmpname (PAUTO), it was tagged by tmpname as not escaping.
-		// on PPARAM it means something different.
-		if(n->class == PAUTO && n->esc == EscNever)
-			break;
-
-		switch(n->class) {
-		case PPARAMREF:
-			addrescapes(n->defn);
-			break;
-		case PPARAM:
-		case PPARAMOUT:
-			// if func param, need separate temporary
-			// to hold heap pointer.
-			// the function type has already been checked
-			// (we're in the function body)
-			// so the param already has a valid xoffset.
-
-			// expression to refer to stack copy
-			n->stackparam = nod(OPARAM, n, N);
-			n->stackparam->type = n->type;
-			n->stackparam->addable = 1;
-			if(n->xoffset == BADWIDTH)
-				fatal("addrescapes before param assignment");
-			n->stackparam->xoffset = n->xoffset;
-			// fallthrough
-
-		case PAUTO:
-			n->class |= PHEAP;
-			n->addable = 0;
-			n->ullman = 2;
-			n->xoffset = 0;
-
-			// create stack variable to hold pointer to heap
-			oldfn = curfn;
-			curfn = n->curfn;
-			n->heapaddr = temp(ptrto(n->type));
-			snprint(buf, sizeof buf, "&%S", n->sym);
-			n->heapaddr->sym = lookup(buf);
-			n->heapaddr->orig->sym = n->heapaddr->sym;
-			n->esc = EscHeap;
-			if(debug['m'])
-				print("%L: moved to heap: %N\n", n->lineno, n);
-			curfn = oldfn;
-			break;
-		}
-		break;
-
-	case OIND:
-	case ODOTPTR:
-		break;
-
-	case ODOT:
-	case OINDEX:
-		// ODOTPTR has already been introduced,
-		// so these are the non-pointer ODOT and OINDEX.
-		// 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.
-		if(!isslice(n->left->type))
-			addrescapes(n->left);
-		break;
-	}
-}
-
-void
-clearlabels(void)
-{
-	Label *l;
-
-	for(l=labellist; l!=L; l=l->link)
-		l->sym->label = L;
-	
-	labellist = L;
-	lastlabel = L;
-}
-
-static Label*
-newlab(Node *n)
-{
-	Sym *s;
-	Label *lab;
-	
-	s = n->left->sym;
-	if((lab = s->label) == L) {
-		lab = mal(sizeof(*lab));
-		if(lastlabel == nil)
-			labellist = lab;
-		else
-			lastlabel->link = lab;
-		lastlabel = lab;
-		lab->sym = s;
-		s->label = lab;
-	}
-	
-	if(n->op == OLABEL) {
-		if(lab->def != N)
-			yyerror("label %S already defined at %L", s, lab->def->lineno);
-		else
-			lab->def = n;
-	} else
-		lab->use = list(lab->use, n);
-
-	return lab;
-}
-
-void
-checklabels(void)
-{
-	Label *lab;
-	NodeList *l;
-
-	for(lab=labellist; lab!=L; lab=lab->link) {
-		if(lab->def == N) {
-			for(l=lab->use; l; l=l->next)
-				yyerrorl(l->n->lineno, "label %S not defined", lab->sym);
-			continue;
-		}
-		if(lab->use == nil && !lab->used) {
-			yyerrorl(lab->def->lineno, "label %S defined and not used", lab->sym);
-			continue;
-		}
-		if(lab->gotopc != P)
-			fatal("label %S never resolved", lab->sym);
-		for(l=lab->use; l; l=l->next)
-			checkgoto(l->n, lab->def);
-	}
-}
-
-static void
-checkgoto(Node *from, Node *to)
-{
-	int nf, nt;
-	Sym *block, *dcl, *fs, *ts;
-	int lno;
-
-	if(from->sym == to->sym)
-		return;
-
-	nf = 0;
-	for(fs=from->sym; fs; fs=fs->link)
-		nf++;
-	nt = 0;
-	for(fs=to->sym; fs; fs=fs->link)
-		nt++;
-	fs = from->sym;
-	for(; nf > nt; nf--)
-		fs = fs->link;
-	if(fs != to->sym) {
-		lno = lineno;
-		setlineno(from);
-
-		// 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 = S;
-		dcl = S;
-		ts = to->sym;
-		for(; nt > nf; nt--) {
-			if(ts->pkg == nil)
-				block = ts;
-			else
-				dcl = ts;
-			ts = ts->link;
-		}
-		while(ts != fs) {
-			if(ts->pkg == nil)
-				block = ts;
-			else
-				dcl = ts;
-			ts = ts->link;
-			fs = fs->link;
-		}
-
-		if(block)
-			yyerror("goto %S jumps into block starting at %L", from->left->sym, block->lastlineno);
-		else
-			yyerror("goto %S jumps over declaration of %S at %L", from->left->sym, dcl, dcl->lastlineno);
-		lineno = lno;
-	}
-}
-
-static Label*
-stmtlabel(Node *n)
-{
-	Label *lab;
-
-	if(n->sym != S)
-	if((lab = n->sym->label) != L)
-	if(lab->def != N)
-	if(lab->def->defn == n)
-		return lab;
-	return L;
-}
-
-/*
- * compile statements
- */
-void
-genlist(NodeList *l)
-{
-	for(; l; l=l->next)
-		gen(l->n);
-}
-
-void
-gen(Node *n)
-{
-	int32 lno;
-	Prog *scontin, *sbreak;
-	Prog *p1, *p2, *p3;
-	Label *lab;
-	int32 wasregalloc;
-
-//dump("gen", n);
-
-	lno = setlineno(n);
-	wasregalloc = anyregalloc();
-
-	if(n == N)
-		goto ret;
-
-	if(n->ninit)
-		genlist(n->ninit);
-
-	setlineno(n);
-
-	switch(n->op) {
-	default:
-		fatal("gen: unknown op %+hN", n);
-		break;
-
-	case OCASE:
-	case OFALL:
-	case OXCASE:
-	case OXFALL:
-	case ODCLCONST:
-	case ODCLFUNC:
-	case ODCLTYPE:
-		break;
-
-	case OEMPTY:
-		break;
-
-	case OBLOCK:
-		genlist(n->list);
-		break;
-
-	case OLABEL:
-		if(isblanksym(n->left->sym))
-			break;
-		
-		lab = newlab(n);
-
-		// if there are pending gotos, resolve them all to the current pc.
-		for(p1=lab->gotopc; p1; p1=p2) {
-			p2 = unpatch(p1);
-			patch(p1, pc);
-		}
-		lab->gotopc = P;
-		if(lab->labelpc == P)
-			lab->labelpc = pc;
-
-		if(n->defn) {
-			switch(n->defn->op) {
-			case OFOR:
-			case OSWITCH:
-			case OSELECT:
-				// so stmtlabel can find the label
-				n->defn->sym = lab->sym;
-			}
-		}
-		break;
-
-	case OGOTO:
-		// if label is defined, emit jump to it.
-		// otherwise save list of pending gotos in lab->gotopc.
-		// the list is linked through the normal jump target field
-		// to avoid a second list.  (the jumps are actually still
-		// valid code, since they're just going to another goto
-		// to the same label.  we'll unwind it when we learn the pc
-		// of the label in the OLABEL case above.)
-		lab = newlab(n);
-		if(lab->labelpc != P)
-			gjmp(lab->labelpc);
-		else
-			lab->gotopc = gjmp(lab->gotopc);
-		break;
-
-	case OBREAK:
-		if(n->left != N) {
-			lab = n->left->sym->label;
-			if(lab == L) {
-				yyerror("break label not defined: %S", n->left->sym);
-				break;
-			}
-			lab->used = 1;
-			if(lab->breakpc == P) {
-				yyerror("invalid break label %S", n->left->sym);
-				break;
-			}
-			gjmp(lab->breakpc);
-			break;
-		}
-		if(breakpc == P) {
-			yyerror("break is not in a loop");
-			break;
-		}
-		gjmp(breakpc);
-		break;
-
-	case OCONTINUE:
-		if(n->left != N) {
-			lab = n->left->sym->label;
-			if(lab == L) {
-				yyerror("continue label not defined: %S", n->left->sym);
-				break;
-			}
-			lab->used = 1;
-			if(lab->continpc == P) {
-				yyerror("invalid continue label %S", n->left->sym);
-				break;
-			}
-			gjmp(lab->continpc);
-			break;
-		}
-		if(continpc == P) {
-			yyerror("continue is not in a loop");
-			break;
-		}
-		gjmp(continpc);
-		break;
-
-	case OFOR:
-		sbreak = breakpc;
-		p1 = gjmp(P);			//		goto test
-		breakpc = gjmp(P);		// break:	goto done
-		scontin = continpc;
-		continpc = pc;
-
-		// define break and continue labels
-		if((lab = stmtlabel(n)) != L) {
-			lab->breakpc = breakpc;
-			lab->continpc = continpc;
-		}
-		gen(n->nincr);				// contin:	incr
-		patch(p1, pc);				// test:
-		bgen(n->ntest, 0, -1, breakpc);		//		if(!test) goto break
-		genlist(n->nbody);				//		body
-		gjmp(continpc);
-		patch(breakpc, pc);			// done:
-		continpc = scontin;
-		breakpc = sbreak;
-		if(lab) {
-			lab->breakpc = P;
-			lab->continpc = P;
-		}
-		break;
-
-	case OIF:
-		p1 = gjmp(P);			//		goto test
-		p2 = gjmp(P);			// p2:		goto else
-		patch(p1, pc);				// test:
-		bgen(n->ntest, 0, -n->likely, p2);		//		if(!test) goto p2
-		genlist(n->nbody);				//		then
-		p3 = gjmp(P);			//		goto done
-		patch(p2, pc);				// else:
-		genlist(n->nelse);				//		else
-		patch(p3, pc);				// done:
-		break;
-
-	case OSWITCH:
-		sbreak = breakpc;
-		p1 = gjmp(P);			//		goto test
-		breakpc = gjmp(P);		// break:	goto done
-
-		// define break label
-		if((lab = stmtlabel(n)) != L)
-			lab->breakpc = breakpc;
-
-		patch(p1, pc);				// test:
-		genlist(n->nbody);				//		switch(test) body
-		patch(breakpc, pc);			// done:
-		breakpc = sbreak;
-		if(lab != L)
-			lab->breakpc = P;
-		break;
-
-	case OSELECT:
-		sbreak = breakpc;
-		p1 = gjmp(P);			//		goto test
-		breakpc = gjmp(P);		// break:	goto done
-
-		// define break label
-		if((lab = stmtlabel(n)) != L)
-			lab->breakpc = breakpc;
-
-		patch(p1, pc);				// test:
-		genlist(n->nbody);				//		select() body
-		patch(breakpc, pc);			// done:
-		breakpc = sbreak;
-		if(lab != L)
-			lab->breakpc = P;
-		break;
-
-	case OASOP:
-		cgen_asop(n);
-		break;
-
-	case ODCL:
-		cgen_dcl(n->left);
-		break;
-
-	case OAS:
-		if(gen_as_init(n))
-			break;
-		cgen_as(n->left, n->right);
-		break;
-
-	case OCALLMETH:
-		cgen_callmeth(n, 0);
-		break;
-
-	case OCALLINTER:
-		cgen_callinter(n, N, 0);
-		break;
-
-	case OCALLFUNC:
-		cgen_call(n, 0);
-		break;
-
-	case OPROC:
-		cgen_proc(n, 1);
-		break;
-
-	case ODEFER:
-		cgen_proc(n, 2);
-		break;
-
-	case ORETURN:
-	case ORETJMP:
-		cgen_ret(n);
-		break;
-	
-	case OCHECKNIL:
-		cgen_checknil(n->left);
-		break;
-	
-	case OVARKILL:
-		gvarkill(n->left);
-		break;
-	}
-
-ret:
-	if(anyregalloc() != wasregalloc) {
-		dump("node", n);
-		fatal("registers left allocated");
-	}
-
-	lineno = lno;
-}
-
-/*
- * generate call to non-interface method
- *	proc=0	normal call
- *	proc=1	goroutine run in new proc
- *	proc=2	defer call save away stack
- */
-void
-cgen_callmeth(Node *n, int proc)
-{
-	Node n2;
-	Node *l;
-
-	// generate a rewrite in n2 for the method call
-	// (p.f)(...) goes to (f)(p,...)
-
-	l = n->left;
-	if(l->op != ODOTMETH)
-		fatal("cgen_callmeth: not dotmethod: %N");
-
-	n2 = *n;
-	n2.op = OCALLFUNC;
-	n2.left = l->right;
-	n2.left->type = l->type;
-
-	if(n2.left->op == ONAME)
-		n2.left->class = PFUNC;
-	cgen_call(&n2, proc);
-}
-
-/*
- * generate code to start new proc running call n.
- */
-static void
-cgen_proc(Node *n, int proc)
-{
-	switch(n->left->op) {
-	default:
-		fatal("cgen_proc: unknown call %O", n->left->op);
-
-	case OCALLMETH:
-		cgen_callmeth(n->left, proc);
-		break;
-
-	case OCALLINTER:
-		cgen_callinter(n->left, N, proc);
-		break;
-
-	case OCALLFUNC:
-		cgen_call(n->left, proc);
-		break;
-	}
-
-}
-
-/*
- * generate declaration.
- * have to allocate heap copy
- * for escaped variables.
- */
-static void
-cgen_dcl(Node *n)
-{
-	if(debug['g'])
-		dump("\ncgen-dcl", n);
-	if(n->op != ONAME) {
-		dump("cgen_dcl", n);
-		fatal("cgen_dcl");
-	}
-	if(!(n->class & PHEAP))
-		return;
-	if(compiling_runtime)
-		yyerror("%N escapes to heap, not allowed in runtime.", n);
-	if(n->alloc == nil)
-		n->alloc = callnew(n->type);
-	cgen_as(n->heapaddr, n->alloc);
-}
-
-/*
- * generate discard of value
- */
-static void
-cgen_discard(Node *nr)
-{
-	Node tmp;
-
-	if(nr == N)
-		return;
-
-	switch(nr->op) {
-	case ONAME:
-		if(!(nr->class & PHEAP) && nr->class != PEXTERN && nr->class != PFUNC && nr->class != PPARAMREF)
-			gused(nr);
-		break;
-
-	// unary
-	case OADD:
-	case OAND:
-	case ODIV:
-	case OEQ:
-	case OGE:
-	case OGT:
-	case OLE:
-	case OLSH:
-	case OLT:
-	case OMOD:
-	case OMUL:
-	case ONE:
-	case OOR:
-	case ORSH:
-	case OSUB:
-	case OXOR:
-		cgen_discard(nr->left);
-		cgen_discard(nr->right);
-		break;
-
-	// binary
-	case OCAP:
-	case OCOM:
-	case OLEN:
-	case OMINUS:
-	case ONOT:
-	case OPLUS:
-		cgen_discard(nr->left);
-		break;
-	
-	case OIND:
-		cgen_checknil(nr->left);
-		break;
-
-	// special enough to just evaluate
-	default:
-		tempname(&tmp, nr->type);
-		cgen_as(&tmp, nr);
-		gused(&tmp);
-	}
-}
-
-/*
- * clearslim generates code to zero a slim node.
- */
-void
-clearslim(Node *n)
-{
-	Node z;
-	Mpflt zero;
-
-	memset(&z, 0, sizeof(z));
-	z.op = OLITERAL;
-	z.type = n->type;
-	z.addable = 1;
-
-	switch(simtype[n->type->etype]) {
-	case TCOMPLEX64:
-	case TCOMPLEX128:
-		z.val.u.cval = mal(sizeof(*z.val.u.cval));
-		mpmovecflt(&z.val.u.cval->real, 0.0);
-		mpmovecflt(&z.val.u.cval->imag, 0.0);
-		break;
-
-	case TFLOAT32:
-	case TFLOAT64:
-		mpmovecflt(&zero, 0.0);
-		z.val.ctype = CTFLT;
-		z.val.u.fval = &zero;
-		break;
-
-	case TPTR32:
-	case TPTR64:
-	case TCHAN:
-	case TMAP:
-		z.val.ctype = CTNIL;
-		break;
-
-	case TBOOL:
-		z.val.ctype = CTBOOL;
-		break;
-
-	case TINT8:
-	case TINT16:
-	case TINT32:
-	case TINT64:
-	case TUINT8:
-	case TUINT16:
-	case TUINT32:
-	case TUINT64:
-		z.val.ctype = CTINT;
-		z.val.u.xval = mal(sizeof(*z.val.u.xval));
-		mpmovecfix(z.val.u.xval, 0);
-		break;
-
-	default:
-		fatal("clearslim called on type %T", n->type);
-	}
-
-	ullmancalc(&z);
-	cgen(&z, n);
-}
-
-/*
- * generate assignment:
- *	nl = nr
- * nr == N means zero nl.
- */
-void
-cgen_as(Node *nl, Node *nr)
-{
-	Type *tl;
-
-	if(debug['g']) {
-		dump("cgen_as", nl);
-		dump("cgen_as = ", nr);
-	}
-
-	while(nr != N && nr->op == OCONVNOP)
-		nr = nr->left;
-
-	if(nl == N || isblank(nl)) {
-		cgen_discard(nr);
-		return;
-	}
-
-	if(nr == N || iszero(nr)) {
-		// heaps should already be clear
-		if(nr == N && (nl->class & PHEAP))
-			return;
-
-		tl = nl->type;
-		if(tl == T)
-			return;
-		if(isfat(tl)) {
-			if(nl->op == ONAME)
-				gvardef(nl);
-			clearfat(nl);
-			return;
-		}
-		clearslim(nl);
-		return;
-	}
-
-	tl = nl->type;
-	if(tl == T)
-		return;
-
-	cgen(nr, nl);
-}
-
-/*
- * generate:
- *	res = iface{typ, data}
- * n->left is typ
- * n->right is data
- */
-void
-cgen_eface(Node *n, Node *res)
-{
-	/* 
-	 * the right node of an eface may contain function calls that uses res as an argument,
-	 * so it's important that it is done first
-	 */
-	Node dst;
-	Node *tmp;
-
-	tmp = temp(types[tptr]);
-	cgen(n->right, tmp);
-
-	gvardef(res);
-
-	dst = *res;
-	dst.type = types[tptr];
-	dst.xoffset += widthptr;
-	cgen(tmp, &dst);
-
-	dst.xoffset -= widthptr;
-	cgen(n->left, &dst);
-}
-
-/*
- * generate:
- *	res = s[lo, hi];
- * n->left is s
- * n->list is (cap(s)-lo(TUINT), hi-lo(TUINT)[, lo*width(TUINTPTR)])
- * caller (cgen) guarantees res is an addable ONAME.
- *
- * called for OSLICE, OSLICE3, OSLICEARR, OSLICE3ARR, OSLICESTR.
- */
-void
-cgen_slice(Node *n, Node *res)
-{
-	Node src, dst, *cap, *len, *offs, *add, *base, *tmpcap, *tmplen, *cmp, con;
-	Prog *p1, *p2;
-
-	cap = n->list->n;
-	len = n->list->next->n;
-	offs = N;
-	if(n->list->next->next)
-		offs = n->list->next->next->n;
-
-	// evaluate base pointer first, because it is the only
-	// possibly complex expression. once that is evaluated
-	// and stored, updating the len and cap can be done
-	// without making any calls, so without doing anything that
-	// might cause preemption or garbage collection.
-	// this makes the whole slice update atomic as far as the
-	// garbage collector can see.
-	
-	base = temp(types[TUINTPTR]);
-	tmplen = temp(types[TINT]);
-	if(n->op != OSLICESTR)
-		tmpcap = temp(types[TINT]);
-	else
-		tmpcap = tmplen;
-
-	if(isnil(n->left)) {
-		tempname(&src, n->left->type);
-		cgen(n->left, &src);
-	} else
-		src = *n->left;
-	if(n->op == OSLICE || n->op == OSLICE3 || n->op == OSLICESTR)
-		src.xoffset += Array_array;
-
-	if(n->op == OSLICEARR || n->op == OSLICE3ARR) {
-		if(!isptr[n->left->type->etype])
-			fatal("slicearr is supposed to work on pointer: %+N\n", n);
-		cgen(&src, base);
-		cgen_checknil(base);
-	} else {
-		src.type = types[tptr];
-		cgen(&src, base);
-	}
-	
-	// committed to the update
-	gvardef(res);
-
-	// compute len and cap.
-	// len = n-i, cap = m-i, and offs = i*width.
-	// computing offs last lets the multiply overwrite i.
-	cgen(len, tmplen);
-	if(n->op != OSLICESTR)
-		cgen(cap, tmpcap);
-
-	// if new cap != 0 { base += add }
-	// This avoids advancing base past the end of the underlying array/string,
-	// so that it cannot point at the next object in memory.
-	// If cap == 0, the base doesn't matter except insofar as it is 0 or non-zero.
-	// In essence we are replacing x[i:j:k] where i == j == k
-	// or x[i:j] where i == j == cap(x) with x[0:0:0].
-	if(offs != N) {
-		p1 = gjmp(P);
-		p2 = gjmp(P);
-		patch(p1, pc);
-
-		nodconst(&con, tmpcap->type, 0);
-		cmp = nod(OEQ, tmpcap, &con);
-		typecheck(&cmp, Erv);
-		bgen(cmp, 1, -1, p2);
-
-		add = nod(OADD, base, offs);
-		typecheck(&add, Erv);
-		cgen(add, base);
-
-		patch(p2, pc);
-	}
-
-	// dst.array = src.array  [ + lo *width ]
-	dst = *res;
-	dst.xoffset += Array_array;
-	dst.type = types[tptr];
-	cgen(base, &dst);
-
-	// dst.len = hi [ - lo ]
-	dst = *res;
-	dst.xoffset += Array_nel;
-	dst.type = types[simtype[TUINT]];
-	cgen(tmplen, &dst);
-
-	if(n->op != OSLICESTR) {
-		// dst.cap = cap [ - lo ]
-		dst = *res;
-		dst.xoffset += Array_cap;
-		dst.type = types[simtype[TUINT]];
-		cgen(tmpcap, &dst);
-	}
-}
-
-/*
- * gather series of offsets
- * >=0 is direct addressed field
- * <0 is pointer to next field (+1)
- */
-int
-dotoffset(Node *n, int64 *oary, Node **nn)
-{
-	int i;
-
-	switch(n->op) {
-	case ODOT:
-		if(n->xoffset == BADWIDTH) {
-			dump("bad width in dotoffset", n);
-			fatal("bad width in dotoffset");
-		}
-		i = dotoffset(n->left, oary, nn);
-		if(i > 0) {
-			if(oary[i-1] >= 0)
-				oary[i-1] += n->xoffset;
-			else
-				oary[i-1] -= n->xoffset;
-			break;
-		}
-		if(i < 10)
-			oary[i++] = n->xoffset;
-		break;
-
-	case ODOTPTR:
-		if(n->xoffset == BADWIDTH) {
-			dump("bad width in dotoffset", n);
-			fatal("bad width in dotoffset");
-		}
-		i = dotoffset(n->left, oary, nn);
-		if(i < 10)
-			oary[i++] = -(n->xoffset+1);
-		break;
-
-	default:
-		*nn = n;
-		return 0;
-	}
-	if(i >= 10)
-		*nn = N;
-	return i;
-}
-
-/*
- * make a new off the books
- */
-void
-tempname(Node *nn, Type *t)
-{
-	Node *n;
-	Sym *s;
-
-	if(curfn == N)
-		fatal("no curfn for tempname");
-
-	if(t == T) {
-		yyerror("tempname called with nil type");
-		t = types[TINT32];
-	}
-
-	// give each tmp a different name so that there
-	// a chance to registerizer them
-	snprint(namebuf, sizeof(namebuf), "autotmp_%.4d", statuniqgen);
-	statuniqgen++;
-	s = lookup(namebuf);
-	n = nod(ONAME, N, N);
-	n->sym = s;
-	s->def = n;
-	n->type = t;
-	n->class = PAUTO;
-	n->addable = 1;
-	n->ullman = 1;
-	n->esc = EscNever;
-	n->curfn = curfn;
-	curfn->dcl = list(curfn->dcl, n);
-
-	dowidth(t);
-	n->xoffset = 0;
-	*nn = *n;
-}
-
-Node*
-temp(Type *t)
-{
-	Node *n;
-	
-	n = nod(OXXX, N, N);
-	tempname(n, t);
-	n->sym->def->used = 1;
-	return n->orig;
-}
diff --git a/src/cmd/gc/go.errors b/src/cmd/gc/go.errors
deleted file mode 100644
index f90d619..0000000
--- a/src/cmd/gc/go.errors
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright 2010 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.
-
-// Example-based syntax error messages.
-// See bisonerrors, Makefile, go.y.
-
-static struct {
-	int yystate;
-	int yychar;
-	char *msg;
-} yymsg[] = {
-	// Each line of the form % token list
-	// is converted by bisonerrors into the yystate and yychar caused
-	// by that token list.
-
-	% loadsys package LIMPORT '(' LLITERAL import_package import_there ','
-	"unexpected comma during import block",
-
-	% loadsys package LIMPORT LNAME ';'
-	"missing import path; require quoted string",
-
-	% loadsys package imports LFUNC LNAME '(' ')' '{' LIF if_header ';'
-	"missing { after if clause",
-
-	% loadsys package imports LFUNC LNAME '(' ')' '{' LSWITCH if_header ';'
-	"missing { after switch clause",
-
-	% loadsys package imports LFUNC LNAME '(' ')' '{' LFOR for_header ';'
-	"missing { after for clause",
-
-	% loadsys package imports LFUNC LNAME '(' ')' '{' LFOR ';' LBODY
-	"missing { after for clause",
-
-	% loadsys package imports LFUNC LNAME '(' ')' ';' '{'
-	"unexpected semicolon or newline before {",
-
-	% loadsys package imports LTYPE LNAME ';'
-	"unexpected semicolon or newline in type declaration",
-
-	% loadsys package imports LCHAN '}'
-	"unexpected } in channel type",
-	
-	% loadsys package imports LCHAN ')'
-	"unexpected ) in channel type",
-	
-	% loadsys package imports LCHAN ','
-	"unexpected comma in channel type",
-
-	% loadsys package imports LFUNC LNAME '(' ')' '{' if_stmt ';' LELSE
-	"unexpected semicolon or newline before else",
-
-	% loadsys package imports LTYPE LNAME LINTERFACE '{' LNAME ',' LNAME
-	"name list not allowed in interface type",
-
-	% loadsys package imports LFUNC LNAME '(' ')' '{' LFOR LVAR LNAME '=' LNAME
-	"var declaration not allowed in for initializer",
-
-	% loadsys package imports LVAR LNAME '[' ']' LNAME '{'
-	"unexpected { at end of statement",
-
-	% loadsys package imports LFUNC LNAME '(' ')' '{' LVAR LNAME '[' ']' LNAME '{'
-	"unexpected { at end of statement",
-	
-	% loadsys package imports LFUNC LNAME '(' ')' '{' LDEFER LNAME ';'
-	"argument to go/defer must be function call",
-	
-	% loadsys package imports LVAR LNAME '=' LNAME '{' LNAME ';'
-	"need trailing comma before newline in composite literal",
-	
-	% loadsys package imports LVAR LNAME '=' comptype '{' LNAME ';'
-	"need trailing comma before newline in composite literal",
-	
-	% loadsys package imports LFUNC LNAME '(' ')' '{' LFUNC LNAME
-	"nested func not allowed",
-
-	% loadsys package imports LFUNC LNAME '(' ')' '{' LIF if_header loop_body LELSE ';'
-	"else must be followed by if or statement block"
-};
diff --git a/src/cmd/gc/go.h b/src/cmd/gc/go.h
deleted file mode 100644
index bbb8835..0000000
--- a/src/cmd/gc/go.h
+++ /dev/null
@@ -1,1555 +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	<bio.h>
-#include	<link.h>
-
-#undef OAPPEND
-
-// avoid <ctype.h>
-#undef isblank
-#define isblank goisblank
-
-#ifndef	EXTERN
-#define	EXTERN	extern
-#endif
-
-#undef	BUFSIZ
-
-// The parser's maximum stack size.
-// We have to use a #define macro here since yacc
-// or bison will check for its definition and use
-// a potentially smaller value if it is undefined.
-#define YYMAXDEPTH 500
-
-enum
-{
-	NHUNK		= 50000,
-	BUFSIZ		= 8192,
-	NSYMB		= 500,
-	NHASH		= 1024,
-	STRINGSZ	= 200,
-	MAXALIGN	= 7,
-	UINF		= 100,
-
-	PRIME1		= 3,
-
-	AUNK		= 100,
-
-	// These values are known by runtime.
-	// The MEMx and NOEQx values must run in parallel.  See algtype.
-	AMEM		= 0,
-	AMEM0,
-	AMEM8,
-	AMEM16,
-	AMEM32,
-	AMEM64,
-	AMEM128,
-	ANOEQ,
-	ANOEQ0,
-	ANOEQ8,
-	ANOEQ16,
-	ANOEQ32,
-	ANOEQ64,
-	ANOEQ128,
-	ASTRING,
-	AINTER,
-	ANILINTER,
-	ASLICE,
-	AFLOAT32,
-	AFLOAT64,
-	ACPLX64,
-	ACPLX128,
-
-	BADWIDTH	= -1000000000,
-	
-	MaxStackVarSize = 10*1024*1024,
-};
-
-extern vlong	MAXWIDTH;
-
-/*
- * note this is the representation
- * of the compilers string literals,
- * it is not the runtime representation
- */
-typedef	struct	Strlit	Strlit;
-struct	Strlit
-{
-	int32	len;
-	char	s[1]; // variable
-};
-
-enum
-{
-	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	= 1L << Mpscale,
-	Mpsign	= Mpbase >> 1,
-	Mpmask	= Mpbase - 1,
-	Mpdebug	= 0,
-};
-
-typedef	struct	Mpint	Mpint;
-struct	Mpint
-{
-	long	a[Mpprec];
-	uchar	neg;
-	uchar	ovf;
-};
-
-typedef	struct	Mpflt	Mpflt;
-struct	Mpflt
-{
-	Mpint	val;
-	short	exp;
-};
-
-typedef	struct	Mpcplx	Mpcplx;
-struct	Mpcplx
-{
-	Mpflt	real;
-	Mpflt	imag;
-};
-
-typedef	struct	Val	Val;
-struct	Val
-{
-	short	ctype;
-	union
-	{
-		short	reg;		// OREGISTER
-		short	bval;		// bool value CTBOOL
-		Mpint*	xval;		// int CTINT, rune CTRUNE
-		Mpflt*	fval;		// float CTFLT
-		Mpcplx*	cval;		// float CTCPLX
-		Strlit*	sval;		// string CTSTR
-	} u;
-};
-
-// prevent incompatible type signatures between libgc and 8g on Plan 9
-#pragma incomplete struct Array
-
-typedef	struct	Array	Array;
-typedef	struct	Bvec	Bvec;
-typedef	struct	Pkg Pkg;
-typedef	struct	Sym	Sym;
-typedef	struct	Node	Node;
-typedef	struct	NodeList	NodeList;
-typedef	struct	Type	Type;
-typedef	struct	Label	Label;
-
-struct	Type
-{
-	uchar	etype;
-	uchar	nointerface;
-	uchar	noalg;
-	uchar	chan;
-	uchar	trecur;		// to detect loops
-	uchar	printed;
-	uchar	embedded;	// TFIELD embedded type
-	uchar	siggen;
-	uchar	funarg;		// on TSTRUCT and TFIELD
-	uchar	copyany;
-	uchar	local;		// created in this file
-	uchar	deferwidth;
-	uchar	broke;  	// broken type definition.
-	uchar	isddd;		// TFIELD is ... argument
-	uchar	align;
-	uchar	haspointers;	// 0 unknown, 1 no, 2 yes
-
-	Node*	nod;		// canonical OTYPE node
-	Type*	orig;		// original type (type literal or predefined type)
-	int		lineno;
-
-	// TFUNC
-	int	thistuple;
-	int	outtuple;
-	int	intuple;
-	uchar	outnamed;
-
-	Type*	method;
-	Type*	xmethod;
-
-	Sym*	sym;
-	int32	vargen;		// unique name for OTYPE/ONAME
-
-	Node*	nname;
-	vlong	argwid;
-
-	// most nodes
-	Type*	type;   	// actual type for TFIELD, element type for TARRAY, TCHAN, TMAP, TPTRxx
-	vlong	width;  	// offset in TFIELD, width in all others
-
-	// TFIELD
-	Type*	down;		// next struct field, also key type in TMAP
-	Type*	outer;		// outer struct
-	Strlit*	note;		// literal string annotation
-
-	// TARRAY
-	vlong	bound;		// negative is dynamic array
-
-	// TMAP
-	Type*	bucket;		// internal type representing a hash bucket
-	Type*	hmap;		// internal type representing a Hmap (map header object)
-	Type*	hiter;		// internal type representing hash iterator state
-	Type*	map;		// link from the above 3 internal types back to the map type.
-
-	int32	maplineno;	// first use of TFORW as map key
-	int32	embedlineno;	// first use of TFORW as embedded type
-	
-	// for TFORW, where to copy the eventual value to
-	NodeList	*copyto;
-	
-	Node	*lastfn;	// for usefield
-};
-#define	T	((Type*)0)
-
-typedef struct InitEntry InitEntry;
-typedef struct InitPlan InitPlan;
-
-struct InitEntry
-{
-	vlong xoffset;  // struct, array only
-	Node *key;  // map only
-	Node *expr;
-};
-
-struct InitPlan
-{
-	vlong lit;  // bytes of initialized non-zero literals
-	vlong zero;  // bytes of zeros
-	vlong expr;  // bytes of run-time computed expressions
-
-	InitEntry *e;
-	int len;
-	int cap;
-};
-
-enum
-{
-	EscUnknown,
-	EscHeap,
-	EscScope,
-	EscNone,
-	EscReturn,
-	EscNever,
-	EscBits = 3,
-	EscMask = (1<<EscBits) - 1,
-	EscContentEscapes = 1<<EscBits, // value obtained by indirect of parameter escapes to some returned result
-	EscReturnBits = EscBits+1,
-};
-
-struct	Node
-{
-	// Tree structure.
-	// Generic recursive walks should follow these fields.
-	Node*	left;
-	Node*	right;
-	Node*	ntest;
-	Node*	nincr;
-	NodeList*	ninit;
-	NodeList*	nbody;
-	NodeList*	nelse;
-	NodeList*	list;
-	NodeList*	rlist;
-
-	uchar	op;
-	uchar	nointerface;
-	uchar	ullman;		// sethi/ullman number
-	uchar	addable;	// type of addressability - 0 is not addressable
-	uchar	trecur;		// to detect loops
-	uchar	etype;		// op for OASOP, etype for OTYPE, exclam for export
-	uchar	bounded;	// bounds check unnecessary
-	uchar	class;		// PPARAM, PAUTO, PEXTERN, etc
-	uchar	method;		// OCALLMETH name
-	uchar	embedded;	// ODCLFIELD embedded type
-	uchar	colas;		// OAS resulting from :=
-	uchar	diag;		// already printed error about this
-	uchar	noescape;	// func arguments do not escape
-	uchar	nosplit;	// func should not execute on separate stack
-	uchar	builtin;	// built-in name, like len or close
-	uchar	walkdef;
-	uchar	typecheck;
-	uchar	local;
-	uchar	dodata;
-	uchar	initorder;
-	uchar	used;
-	uchar	isddd;
-	uchar	readonly;
-	uchar	implicit;
-	uchar	addrtaken;	// address taken, even if not moved to heap
-	uchar	dupok;	// duplicate definitions ok (for func)
-	uchar	wrapper;	// is method wrapper (for func)
-	uchar	reslice;	// this is a reslice x = x[0:y] or x = append(x, ...)
-	schar	likely; // likeliness of if statement
-	uchar	hasbreak;	// has break statement
-	uchar	needzero; // if it contains pointers, needs to be zeroed on function entry
-	uchar	needctxt;	// function uses context register (has closure variables)
-	uint	esc;		// EscXXX
-	int	funcdepth;
-
-	// most nodes
-	Type*	type;
-	Node*	orig;		// original form, for printing, and tracking copies of ONAMEs
-
-	// func
-	Node*	nname;
-	Node*	shortname;
-	NodeList*	enter;
-	NodeList*	exit;
-	NodeList*	cvars;	// closure params
-	NodeList*	dcl;	// autodcl for this func/closure
-	NodeList*	inl;	// copy of the body for use in inlining
-	NodeList*	inldcl;	// copy of dcl for use in inlining
-
-	// OLITERAL/OREGISTER
-	Val	val;
-
-	// ONAME
-	Node*	ntype;
-	Node*	defn;	// ONAME: initializing assignment; OLABEL: labeled statement
-	Node*	pack;	// real package for import . names
-	Node*	curfn;	// function for local variables
-	Type*	paramfld; // TFIELD for this PPARAM; also for ODOT, curfn
-
-	// ONAME func param with PHEAP
-	Node*	heapaddr;	// temp holding heap address of param
-	Node*	stackparam;	// OPARAM node referring to stack copy of param
-	Node*	alloc;	// allocation call
-
-	// ONAME closure param with PPARAMREF
-	Node*	outer;	// outer PPARAMREF in nested closure
-	Node*	closure;	// ONAME/PHEAP <-> ONAME/PPARAMREF
-
-	// ONAME substitute while inlining
-	Node* inlvar;
-
-	// OPACK
-	Pkg*	pkg;
-	
-	// OARRAYLIT, OMAPLIT, OSTRUCTLIT.
-	InitPlan*	initplan;
-
-	// Escape analysis.
-	NodeList* escflowsrc;	// flow(this, src)
-	NodeList* escretval;	// on OCALLxxx, list of dummy return values
-	int	escloopdepth;	// -1: global, 0: return variables, 1:function top level, increased inside function for every loop or label to mark scopes
-
-	Sym*	sym;		// various
-	int32	vargen;		// unique name for OTYPE/ONAME
-	int32	lineno;
-	int32	endlineno;
-	vlong	xoffset;
-	vlong	stkdelta;	// offset added by stack frame compaction phase.
-	int32	ostk;
-	int32	iota;
-	uint32	walkgen;
-	int32	esclevel;
-	void*	opt;	// for optimization passes
-};
-#define	N	((Node*)0)
-
-/*
- * 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.
- */
-EXTERN	uint32	walkgen;
-
-struct	NodeList
-{
-	Node*	n;
-	NodeList*	next;
-	NodeList*	end;
-};
-
-enum
-{
-	SymExport	= 1<<0,	// to be exported
-	SymPackage	= 1<<1,
-	SymExported	= 1<<2,	// already written out by export
-	SymUniq		= 1<<3,
-	SymSiggen	= 1<<4,
-};
-
-struct	Sym
-{
-	ushort	lexical;
-	uchar	flags;
-	uchar	sym;		// huffman encoding in object file
-	Sym*	link;
-	int32	npkg;	// number of imported packages with this name
-	uint32	uniqgen;
-	Pkg*	importdef;	// where imported definition was found
-
-	// saved and restored by dcopy
-	Pkg*	pkg;
-	char*	name;		// variable name
-	Node*	def;		// definition: ONAME OTYPE OPACK or OLITERAL
-	Label*	label;	// corresponding label (ephemeral)
-	int32	block;		// blocknumber to catch redeclaration
-	int32	lastlineno;	// last declaration for diagnostic
-	Pkg*	origpkg;	// original package for . import
-	LSym*	lsym;
-};
-#define	S	((Sym*)0)
-
-EXTERN	Sym*	dclstack;
-
-struct	Pkg
-{
-	char*	name;		// package name
-	Strlit*	path;		// string literal used in import statement
-	Sym*	pathsym;
-	char*	prefix;		// escaped path for use in symbol table
-	Pkg*	link;
-	uchar	imported;	// export data of this package was parsed
-	char	exported;	// import line written in export data
-	char	direct;	// imported directly
-	char	safe;	// whether the package is marked as safe
-};
-
-typedef	struct	Iter	Iter;
-struct	Iter
-{
-	int	done;
-	Type*	tfunc;
-	Type*	t;
-	Node**	an;
-	Node*	n;
-};
-
-// Node ops.
-enum
-{
-	OXXX,
-
-	// 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)
-	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,	// x * y
-	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
-
-	// arch-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
-
-	OEND,
-};
-
-enum
-{
-	Txxx,			// 0
-
-	TINT8,	TUINT8,		// 1
-	TINT16,	TUINT16,
-	TINT32,	TUINT32,
-	TINT64,	TUINT64,
-	TINT, TUINT, TUINTPTR,
-
-	TCOMPLEX64,		// 12
-	TCOMPLEX128,
-
-	TFLOAT32,		// 14
-	TFLOAT64,
-
-	TBOOL,			// 16
-
-	TPTR32, TPTR64,		// 17
-
-	TFUNC,			// 19
-	TARRAY,
-	T_old_DARRAY,
-	TSTRUCT,		// 22
-	TCHAN,
-	TMAP,
-	TINTER,			// 25
-	TFORW,
-	TFIELD,
-	TANY,
-	TSTRING,
-	TUNSAFEPTR,
-
-	// pseudo-types for literals
-	TIDEAL,			// 31
-	TNIL,
-	TBLANK,
-
-	// pseudo-type for frame layout
-	TFUNCARGS,
-	TCHANARGS,
-	TINTERMETH,
-
-	NTYPE,
-};
-
-enum
-{
-	CTxxx,
-
-	CTINT,
-	CTRUNE,
-	CTFLT,
-	CTCPLX,
-	CTSTR,
-	CTBOOL,
-	CTNIL,
-};
-
-enum
-{
-	/* types of channel */
-	/* must match ../../pkg/nreflect/type.go:/Chandir */
-	Cxxx,
-	Crecv = 1<<0,
-	Csend = 1<<1,
-	Cboth = Crecv | Csend,
-};
-
-// declaration context
-enum
-{
-	Pxxx,
-
-	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
-};
-
-enum
-{
-	Etop = 1<<1,		// evaluated at statement level
-	Erv = 1<<2,		// evaluated in value context
-	Etype = 1<<3,
-	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
-};
-
-#define	BITS	5
-#define	NVAR	(BITS*sizeof(uint32)*8)
-
-typedef	struct	Bits	Bits;
-struct	Bits
-{
-	uint32	b[BITS];
-};
-
-EXTERN	Bits	zbits;
-
-struct Bvec
-{
-	int32	n;	// number of bits
-	uint32	b[];
-};
-
-typedef	struct	Var	Var;
-struct	Var
-{
-	vlong	offset;
-	Node*	node;
-	Var*	nextinnode;
-	int	width;
-	char	name;
-	char	etype;
-	char	addr;
-};
-
-EXTERN	Var	var[NVAR];
-
-typedef	struct	Typedef	Typedef;
-struct	Typedef
-{
-	char*	name;
-	int	etype;
-	int	sameas;
-};
-
-extern	Typedef	typedefs[];
-
-typedef	struct	Sig	Sig;
-struct	Sig
-{
-	char*	name;
-	Pkg*	pkg;
-	Sym*	isym;
-	Sym*	tsym;
-	Type*	type;
-	Type*	mtype;
-	int32	offset;
-	Sig*	link;
-};
-
-typedef	struct	Io	Io;
-struct	Io
-{
-	char*	infile;
-	Biobuf*	bin;
-	int32	ilineno;
-	int	nlsemi;
-	int	eofnl;
-	int	last;
-	int	peekc;
-	int	peekc1;	// second peekc for ...
-	char*	cp;	// used for content when bin==nil
-	int	importsafe;
-};
-
-typedef	struct	Dlist	Dlist;
-struct	Dlist
-{
-	Type*	field;
-};
-
-typedef	struct	Idir	Idir;
-struct Idir
-{
-	Idir*	link;
-	char*	dir;
-};
-
-/*
- * argument passing to/from
- * smagic and umagic
- */
-typedef	struct	Magic Magic;
-struct	Magic
-{
-	int	w;	// input for both - width
-	int	s;	// output for both - shift
-	int	bad;	// output for both - unexpected failure
-
-	// magic multiplier for signed literal divisors
-	int64	sd;	// input - literal divisor
-	int64	sm;	// output - multiplier
-
-	// magic multiplier for unsigned literal divisors
-	uint64	ud;	// input - literal divisor
-	uint64	um;	// output - multiplier
-	int	ua;	// output - adder
-};
-
-struct	Label
-{
-	uchar	used;
-	Sym*	sym;
-	Node*	def;
-	NodeList*	use;
-	Label*	link;
-	
-	// for use during gen
-	Prog*	gotopc;	// pointer to unresolved gotos
-	Prog*	labelpc;	// pointer to code
-	Prog*	breakpc;	// pointer to code
-	Prog*	continpc;	// pointer to code
-};
-#define	L	((Label*)0)
-
-/*
- * note this is the runtime representation
- * of the compilers arrays.
- *
- * typedef	struct
- * {				// must not move anything
- *	uchar	array[8];	// pointer to data
- *	uchar	nel[4];		// number of elements
- *	uchar	cap[4];		// allocated number of elements
- * } Array;
- */
-EXTERN	int	Array_array;	// runtime offsetof(Array,array) - same for String
-EXTERN	int	Array_nel;	// runtime offsetof(Array,nel) - same for String
-EXTERN	int	Array_cap;	// runtime offsetof(Array,cap)
-EXTERN	int	sizeof_Array;	// runtime sizeof(Array)
-
-
-/*
- * note this is the runtime representation
- * of the compilers strings.
- *
- * typedef	struct
- * {				// must not move anything
- *	uchar	array[8];	// pointer to data
- *	uchar	nel[4];		// number of elements
- * } String;
- */
-EXTERN	int	sizeof_String;	// runtime sizeof(String)
-
-EXTERN	Dlist	dotlist[10];	// size is max depth of embeddeds
-
-EXTERN	Io	curio;
-EXTERN	Io	pushedio;
-EXTERN	int32	lexlineno;
-EXTERN	int32	lineno;
-EXTERN	int32	prevlineno;
-
-EXTERN	char*	infile;
-EXTERN	char*	outfile;
-EXTERN	Biobuf*	bout;
-EXTERN	int	nerrors;
-EXTERN	int	nsavederrors;
-EXTERN	int	nsyntaxerrors;
-EXTERN	int	safemode;
-EXTERN	int	nolocalimports;
-EXTERN	char	namebuf[NSYMB];
-EXTERN	char	lexbuf[NSYMB];
-EXTERN	char	litbuf[NSYMB];
-EXTERN	int	debug[256];
-EXTERN	char*	debugstr;
-EXTERN	int	debug_checknil;
-EXTERN	Sym*	hash[NHASH];
-EXTERN	Sym*	importmyname;	// my name for package
-EXTERN	Pkg*	localpkg;	// package being compiled
-EXTERN	Pkg*	importpkg;	// package being imported
-EXTERN	Pkg*	structpkg;	// package that declared struct, during import
-EXTERN	Pkg*	builtinpkg;	// fake package for builtins
-EXTERN	Pkg*	gostringpkg;	// fake pkg for Go strings
-EXTERN	Pkg*	itabpkg;	// fake pkg for itab cache
-EXTERN	Pkg*	runtimepkg;	// package runtime
-EXTERN	Pkg*	racepkg;	// package runtime/race
-EXTERN	Pkg*	stringpkg;	// fake package for C strings
-EXTERN	Pkg*	typepkg;	// fake package for runtime type info (headers)
-EXTERN	Pkg*	typelinkpkg;	// fake package for runtime type info (data)
-EXTERN	Pkg*	weaktypepkg;	// weak references to runtime type info
-EXTERN	Pkg*	unsafepkg;	// package unsafe
-EXTERN	Pkg*	trackpkg;	// fake package for field tracking
-EXTERN	Pkg*	phash[128];
-EXTERN	int	tptr;		// either TPTR32 or TPTR64
-extern	char*	runtimeimport;
-extern	char*	unsafeimport;
-EXTERN	char*	myimportpath;
-EXTERN	Idir*	idirs;
-EXTERN	char*	localimport;
-
-EXTERN	Type*	types[NTYPE];
-EXTERN	Type*	idealstring;
-EXTERN	Type*	idealbool;
-EXTERN	Type*	bytetype;
-EXTERN	Type*	runetype;
-EXTERN	Type*	errortype;
-EXTERN	uchar	simtype[NTYPE];
-EXTERN	uchar	isptr[NTYPE];
-EXTERN	uchar	isforw[NTYPE];
-EXTERN	uchar	isint[NTYPE];
-EXTERN	uchar	isfloat[NTYPE];
-EXTERN	uchar	iscomplex[NTYPE];
-EXTERN	uchar	issigned[NTYPE];
-EXTERN	uchar	issimple[NTYPE];
-
-EXTERN	uchar	okforeq[NTYPE];
-EXTERN	uchar	okforadd[NTYPE];
-EXTERN	uchar	okforand[NTYPE];
-EXTERN	uchar	okfornone[NTYPE];
-EXTERN	uchar	okforcmp[NTYPE];
-EXTERN	uchar	okforbool[NTYPE];
-EXTERN	uchar	okforcap[NTYPE];
-EXTERN	uchar	okforlen[NTYPE];
-EXTERN	uchar	okforarith[NTYPE];
-EXTERN	uchar	okforconst[NTYPE];
-EXTERN	uchar*	okfor[OEND];
-EXTERN	uchar	iscmp[OEND];
-
-EXTERN	Mpint*	minintval[NTYPE];
-EXTERN	Mpint*	maxintval[NTYPE];
-EXTERN	Mpflt*	minfltval[NTYPE];
-EXTERN	Mpflt*	maxfltval[NTYPE];
-
-EXTERN	NodeList*	xtop;
-EXTERN	NodeList*	externdcl;
-EXTERN	NodeList*	closures;
-EXTERN	NodeList*	exportlist;
-EXTERN	NodeList*	importlist;	// imported functions and methods with inlinable bodies
-EXTERN	NodeList*	funcsyms;
-EXTERN	int	dclcontext;		// PEXTERN/PAUTO
-EXTERN	int	incannedimport;
-EXTERN	int	statuniqgen;		// name generator for static temps
-EXTERN	int	loophack;
-
-EXTERN	int32	iota;
-EXTERN	NodeList*	lastconst;
-EXTERN	Node*	lasttype;
-EXTERN	vlong	maxarg;
-EXTERN	vlong	stksize;		// stack size for current frame
-EXTERN	vlong	stkptrsize;		// prefix of stack containing pointers
-EXTERN	int32	blockgen;		// max block number
-EXTERN	int32	block;			// current block number
-EXTERN	int	hasdefer;		// flag that curfn has defer statetment
-
-EXTERN	Node*	curfn;
-
-EXTERN	int	widthptr;
-EXTERN	int	widthint;
-EXTERN	int	widthreg;
-
-EXTERN	Node*	typesw;
-EXTERN	Node*	nblank;
-
-extern	int	thechar;
-extern	char*	thestring;
-extern	LinkArch*	thelinkarch;
-EXTERN	int  	use_sse;
-
-EXTERN	char*	hunk;
-EXTERN	int32	nhunk;
-EXTERN	int32	thunk;
-
-EXTERN	int	funcdepth;
-EXTERN	int	typecheckok;
-EXTERN	int	compiling_runtime;
-EXTERN	int	compiling_wrappers;
-EXTERN	int	inl_nonlocal;
-EXTERN	int	use_writebarrier;
-EXTERN	int	pure_go;
-EXTERN	char*	flag_installsuffix;
-EXTERN	int	flag_race;
-EXTERN	int	flag_largemodel;
-EXTERN	int	noescape;
-EXTERN	int	nosplit;
-EXTERN	int	debuglive;
-EXTERN	Link*	ctxt;
-
-EXTERN	int	nointerface;
-EXTERN	int	fieldtrack_enabled;
-EXTERN	int	precisestack_enabled;
-EXTERN	int	writearchive;
-
-EXTERN	Biobuf	bstdout;
-
-EXTERN	int	nacl;
-
-/*
- *	y.tab.c
- */
-int	yyparse(void);
-
-/*
- *	align.c
- */
-int	argsize(Type *t);
-void	checkwidth(Type *t);
-void	defercheckwidth(void);
-void	dowidth(Type *t);
-void	resumecheckwidth(void);
-vlong	rnd(vlong o, vlong r);
-void	typeinit(void);
-
-/*
- *	array.c
- */
-Array*	arraynew(int32 capacity, int32 size);
-void	arrayfree(Array *array);
-int32	arraylength(Array *array);
-void*	arrayget(Array *array, int32 index);
-void	arrayset(Array *array, int32 index, void *element);
-void	arrayadd(Array *array, void *element);
-void	arraysort(Array* array, int (*cmp)(const void*, const void*));
-
-/*
- *	bits.c
- */
-int	Qconv(Fmt *fp);
-Bits	band(Bits a, Bits b);
-int	bany(Bits *a);
-int	beq(Bits a, Bits b);
-int	bitno(int32 b);
-Bits	blsh(uint n);
-Bits	bnot(Bits a);
-int	bnum(Bits a);
-Bits	bor(Bits a, Bits b);
-int	bset(Bits a, uint n);
-
-/*
- *	bv.c
- */
-Bvec*	bvalloc(int32 n);
-void	bvandnot(Bvec *dst, Bvec *src1, Bvec *src2);
-int	bvcmp(Bvec *bv1, Bvec *bv2);
-void	bvcopy(Bvec *dst, Bvec *src);
-Bvec*	bvconcat(Bvec *src1, Bvec *src2);
-int	bvget(Bvec *bv, int32 i);
-int32	bvnext(Bvec *bv, int32 i);
-int	bvisempty(Bvec *bv);
-void	bvnot(Bvec *bv);
-void	bvor(Bvec *dst, Bvec *src1, Bvec *src2);
-void	bvand(Bvec *dst, Bvec *src1, Bvec *src2);
-void	bvprint(Bvec *bv);
-void	bvreset(Bvec *bv, int32 i);
-void	bvresetall(Bvec *bv);
-void	bvset(Bvec *bv, int32 i);
-
-/*
- *	closure.c
- */
-Node*	closurebody(NodeList *body);
-void	closurehdr(Node *ntype);
-void	typecheckclosure(Node *func, int top);
-Node*	walkclosure(Node *func, NodeList **init);
-void	typecheckpartialcall(Node*, Node*);
-Node*	walkpartialcall(Node*, NodeList**);
-
-/*
- *	const.c
- */
-int	cmpslit(Node *l, Node *r);
-int	consttype(Node *n);
-void	convconst(Node *con, Type *t, Val *val);
-void	convlit(Node **np, Type *t);
-void	convlit1(Node **np, Type *t, int explicit);
-void	defaultlit(Node **np, Type *t);
-void	defaultlit2(Node **lp, Node **rp, int force);
-void	evconst(Node *n);
-int	isconst(Node *n, int ct);
-int	isgoconst(Node *n);
-Node*	nodcplxlit(Val r, Val i);
-Node*	nodlit(Val v);
-long	nonnegconst(Node *n);
-int	doesoverflow(Val v, Type *t);
-void	overflow(Val v, Type *t);
-int	smallintconst(Node *n);
-Val	toint(Val v);
-Mpflt*	truncfltlit(Mpflt *oldv, Type *t);
-
-/*
- *	cplx.c
- */
-void	complexadd(int op, Node *nl, Node *nr, Node *res);
-void	complexbool(int op, Node *nl, Node *nr, int true, int likely, Prog *to);
-void	complexgen(Node *n, Node *res);
-void	complexminus(Node *nl, Node *res);
-void	complexmove(Node *f, Node *t);
-void	complexmul(Node *nl, Node *nr, Node *res);
-int	complexop(Node *n, Node *res);
-void	nodfconst(Node *n, Type *t, Mpflt* fval);
-
-/*
- *	dcl.c
- */
-void	addmethod(Sym *sf, Type *t, int local, int nointerface);
-void	addvar(Node *n, Type *t, int ctxt);
-NodeList*	checkarglist(NodeList *all, int input);
-Node*	colas(NodeList *left, NodeList *right, int32 lno);
-void	colasdefn(NodeList *left, Node *defn);
-NodeList*	constiter(NodeList *vl, Node *t, NodeList *cl);
-Node*	dclname(Sym *s);
-void	declare(Node *n, int ctxt);
-void	dumpdcl(char *st);
-Node*	embedded(Sym *s, Pkg *pkg);
-Node*	fakethis(void);
-void	funcbody(Node *n);
-void	funccompile(Node *n, int isclosure);
-void	funchdr(Node *n);
-Type*	functype(Node *this, NodeList *in, NodeList *out);
-void	ifacedcl(Node *n);
-int	isifacemethod(Type *f);
-void	markdcl(void);
-Node*	methodname(Node *n, Type *t);
-Node*	methodname1(Node *n, Node *t);
-Sym*	methodsym(Sym *nsym, Type *t0, int iface);
-Node*	newname(Sym *s);
-Node*	oldname(Sym *s);
-void	popdcl(void);
-void	poptodcl(void);
-void	redeclare(Sym *s, char *where);
-void	testdclstack(void);
-Type*	tointerface(NodeList *l);
-Type*	tostruct(NodeList *l);
-Node*	typedcl0(Sym *s);
-Node*	typedcl1(Node *n, Node *t, int local);
-Node*	typenod(Type *t);
-NodeList*	variter(NodeList *vl, Node *t, NodeList *el);
-Sym*	funcsym(Sym*);
-
-/*
- *	esc.c
- */
-void	escapes(NodeList*);
-
-/*
- *	export.c
- */
-void	autoexport(Node *n, int ctxt);
-void	dumpexport(void);
-int	exportname(char *s);
-void	exportsym(Node *n);
-void    importconst(Sym *s, Type *t, Node *n);
-void	importimport(Sym *s, Strlit *z);
-Sym*    importsym(Sym *s, int op);
-void    importtype(Type *pt, Type *t);
-void    importvar(Sym *s, Type *t);
-Type*	pkgtype(Sym *s);
-
-/*
- *	fmt.c
- */
-void	fmtinstallgo(void);
-void	dump(char *s, Node *n);
-void	dumplist(char *s, NodeList *l);
-
-/*
- *	gen.c
- */
-void	addrescapes(Node *n);
-void	cgen_as(Node *nl, Node *nr);
-void	cgen_callmeth(Node *n, int proc);
-void	cgen_eface(Node* n, Node* res);
-void	cgen_slice(Node* n, Node* res);
-void	clearlabels(void);
-void	clearslim(Node*);
-void	checklabels(void);
-int	dotoffset(Node *n, int64 *oary, Node **nn);
-void	gen(Node *n);
-void	genlist(NodeList *l);
-Node*	sysfunc(char *name);
-void	tempname(Node *n, Type *t);
-Node*	temp(Type*);
-
-/*
- *	init.c
- */
-void	fninit(NodeList *n);
-Sym*	renameinit(void);
-
-/*
- *	inl.c
- */
-void	caninl(Node *fn);
-void	inlcalls(Node *fn);
-void	typecheckinl(Node *fn);
-
-/*
- *	lex.c
- */
-void	cannedimports(char *file, char *cp);
-void	importfile(Val *f, int line);
-char*	lexname(int lex);
-char*	expstring(void);
-void	mkpackage(char* pkgname);
-void	unimportfile(void);
-int32	yylex(void);
-extern	int	yylast;
-extern	int	yyprev;
-
-/*
- *	mparith1.c
- */
-int	Bconv(Fmt *fp);
-int	Fconv(Fmt *fp);
-void	mpaddcfix(Mpint *a, vlong c);
-void	mpaddcflt(Mpflt *a, double c);
-void	mpatofix(Mpint *a, char *as);
-void	mpatoflt(Mpflt *a, char *as);
-int	mpcmpfixc(Mpint *b, vlong c);
-int	mpcmpfixfix(Mpint *a, Mpint *b);
-int	mpcmpfixflt(Mpint *a, Mpflt *b);
-int	mpcmpfltc(Mpflt *b, double c);
-int	mpcmpfltfix(Mpflt *a, Mpint *b);
-int	mpcmpfltflt(Mpflt *a, Mpflt *b);
-void	mpcomfix(Mpint *a);
-void	mpdivfixfix(Mpint *a, Mpint *b);
-void	mpmodfixfix(Mpint *a, Mpint *b);
-void	mpmovefixfix(Mpint *a, Mpint *b);
-void	mpmovefixflt(Mpflt *a, Mpint *b);
-int	mpmovefltfix(Mpint *a, Mpflt *b);
-void	mpmovefltflt(Mpflt *a, Mpflt *b);
-void	mpmulcfix(Mpint *a, vlong c);
-void	mpmulcflt(Mpflt *a, double c);
-void	mpsubfixfix(Mpint *a, Mpint *b);
-void	mpsubfltflt(Mpflt *a, Mpflt *b);
-
-/*
- *	mparith2.c
- */
-void	mpaddfixfix(Mpint *a, Mpint *b, int);
-void	mpandfixfix(Mpint *a, Mpint *b);
-void	mpandnotfixfix(Mpint *a, Mpint *b);
-void	mpdivfract(Mpint *a, Mpint *b);
-void	mpdivmodfixfix(Mpint *q, Mpint *r, Mpint *n, Mpint *d);
-vlong	mpgetfix(Mpint *a);
-void	mplshfixfix(Mpint *a, Mpint *b);
-void	mpmovecfix(Mpint *a, vlong c);
-void	mpmulfixfix(Mpint *a, Mpint *b);
-void	mpmulfract(Mpint *a, Mpint *b);
-void	mpnegfix(Mpint *a);
-void	mporfixfix(Mpint *a, Mpint *b);
-void	mprshfixfix(Mpint *a, Mpint *b);
-void	mpshiftfix(Mpint *a, int s);
-int	mptestfix(Mpint *a);
-void	mpxorfixfix(Mpint *a, Mpint *b);
-
-/*
- *	mparith3.c
- */
-void	mpaddfltflt(Mpflt *a, Mpflt *b);
-void	mpdivfltflt(Mpflt *a, Mpflt *b);
-double	mpgetflt(Mpflt *a);
-double	mpgetflt32(Mpflt *a);
-void	mpmovecflt(Mpflt *a, double c);
-void	mpmulfltflt(Mpflt *a, Mpflt *b);
-void	mpnegflt(Mpflt *a);
-void	mpnorm(Mpflt *a);
-void	mpsetexp(Mpflt *a, int exp);
-int	mptestflt(Mpflt *a);
-int	sigfig(Mpflt *a);
-
-/*
- *	obj.c
- */
-void	Bputname(Biobuf *b, LSym *s);
-int	duint16(Sym *s, int off, uint16 v);
-int	duint32(Sym *s, int off, uint32 v);
-int	duint64(Sym *s, int off, uint64 v);
-int	duint8(Sym *s, int off, uint8 v);
-int	duintptr(Sym *s, int off, uint64 v);
-int	dsname(Sym *s, int off, char *dat, int ndat);
-void	dumpobj(void);
-Sym*	stringsym(char*, int);
-void	slicebytes(Node*, char*, int);
-LSym*	linksym(Sym*);
-
-/*
- *	order.c
- */
-void	order(Node *fn);
-void	orderstmtinplace(Node **stmt);
-
-/*
- *	range.c
- */
-void	typecheckrange(Node *n);
-void	walkrange(Node *n);
-
-/*
- *	reflect.c
- */
-void	dumptypestructs(void);
-Type*	methodfunc(Type *f, Type*);
-Node*	typename(Type *t);
-Sym*	typesym(Type *t);
-Sym*	typenamesym(Type *t);
-Sym*	tracksym(Type *t);
-Sym*	typesymprefix(char *prefix, Type *t);
-int	haspointers(Type *t);
-Type*	hiter(Type* t);
-
-/*
- *	select.c
- */
-void	typecheckselect(Node *sel);
-void	walkselect(Node *sel);
-
-/*
- *	sinit.c
- */
-void	anylit(int, Node *n, Node *var, NodeList **init);
-int	gen_as_init(Node *n);
-NodeList*	initfix(NodeList *l);
-int	oaslit(Node *n, NodeList **init);
-int	stataddr(Node *nam, Node *n);
-
-/*
- *	subr.c
- */
-Node*	adddot(Node *n);
-int	adddot1(Sym *s, Type *t, int d, Type **save, int ignorecase);
-void	addinit(Node**, NodeList*);
-Type*	aindex(Node *b, Type *t);
-int	algtype(Type *t);
-int	algtype1(Type *t, Type **bad);
-void	argtype(Node *on, Type *t);
-Node*	assignconv(Node *n, Type *t, char *context);
-int	assignop(Type *src, Type *dst, char **why);
-void	badtype(int o, Type *tl, Type *tr);
-int	brcom(int a);
-int	brrev(int a);
-NodeList*	concat(NodeList *a, NodeList *b);
-int	convertop(Type *src, Type *dst, char **why);
-Node*	copyexpr(Node*, Type*, NodeList**);
-int	count(NodeList *l);
-int	cplxsubtype(int et);
-int	eqtype(Type *t1, Type *t2);
-int	eqtypenoname(Type *t1, Type *t2);
-void	errorexit(void);
-void	expandmeth(Type *t);
-void	fatal(char *fmt, ...);
-void	flusherrors(void);
-void	frame(int context);
-Type*	funcfirst(Iter *s, Type *t);
-Type*	funcnext(Iter *s);
-void	genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface);
-void	genhash(Sym *sym, Type *t);
-void	geneq(Sym *sym, Type *t);
-Type**	getinarg(Type *t);
-Type*	getinargx(Type *t);
-Type**	getoutarg(Type *t);
-Type*	getoutargx(Type *t);
-Type**	getthis(Type *t);
-Type*	getthisx(Type *t);
-int	implements(Type *t, Type *iface, Type **missing, Type **have, int *ptr);
-void	importdot(Pkg *opkg, Node *pack);
-int	is64(Type *t);
-int	isbadimport(Strlit *s);
-int	isblank(Node *n);
-int	isblanksym(Sym *s);
-int	isdirectiface(Type*);
-int	isfixedarray(Type *t);
-int	isideal(Type *t);
-int	isinter(Type *t);
-int	isnil(Node *n);
-int	isnilinter(Type *t);
-int	isptrto(Type *t, int et);
-int	isslice(Type *t);
-int	istype(Type *t, int et);
-int	iszero(Node *n);
-void	linehist(char *file, int32 off, int relative);
-NodeList*	list(NodeList *l, Node *n);
-NodeList*	list1(Node *n);
-void	listsort(NodeList**, int(*f)(Node*, Node*));
-Node*	liststmt(NodeList *l);
-NodeList*	listtreecopy(NodeList *l);
-Sym*	lookup(char *name);
-void*	mal(int32 n);
-Type*	maptype(Type *key, Type *val);
-Type*	methtype(Type *t, int mustname);
-Pkg*	mkpkg(Strlit *path);
-Sym*	ngotype(Node *n);
-int	noconv(Type *t1, Type *t2);
-Node*	nod(int op, Node *nleft, Node *nright);
-Node*	nodbool(int b);
-void	nodconst(Node *n, Type *t, int64 v);
-Node*	nodintconst(int64 v);
-Node*	nodfltconst(Mpflt *v);
-Node*	nodnil(void);
-int	parserline(void);
-Sym*	pkglookup(char *name, Pkg *pkg);
-int	powtwo(Node *n);
-Type*	ptrto(Type *t);
-void*	remal(void *p, int32 on, int32 n);
-Sym*	restrictlookup(char *name, Pkg *pkg);
-Node*	safeexpr(Node *n, NodeList **init);
-void	saveerrors(void);
-Node*	cheapexpr(Node *n, NodeList **init);
-Node*	localexpr(Node *n, Type *t, NodeList **init);
-void	saveorignode(Node *n);
-int32	setlineno(Node *n);
-void	setmaxarg(Type *t);
-Type*	shallow(Type *t);
-int	simsimtype(Type *t);
-void	smagic(Magic *m);
-Type*	sortinter(Type *t);
-uint32	stringhash(char *p);
-Strlit*	strlit(char *s);
-int	structcount(Type *t);
-Type*	structfirst(Iter *s, Type **nn);
-Type*	structnext(Iter *s);
-Node*	syslook(char *name, int copy);
-Type*	tounsigned(Type *t);
-Node*	treecopy(Node *n);
-Type*	typ(int et);
-uint32	typehash(Type *t);
-void	ullmancalc(Node *n);
-void	umagic(Magic *m);
-void	warn(char *fmt, ...);
-void	warnl(int line, char *fmt, ...);
-void	yyerror(char *fmt, ...);
-void	yyerrorl(int line, char *fmt, ...);
-
-/*
- *	swt.c
- */
-void	typecheckswitch(Node *n);
-void	walkswitch(Node *sw);
-
-/*
- *	typecheck.c
- */
-int	islvalue(Node *n);
-Node*	typecheck(Node **np, int top);
-void	typechecklist(NodeList *l, int top);
-Node*	typecheckdef(Node *n);
-void	copytype(Node *n, Type *t);
-void	checkreturn(Node*);
-void	queuemethod(Node *n);
-
-/*
- *	unsafe.c
- */
-int	isunsafebuiltin(Node *n);
-Node*	unsafenmagic(Node *n);
-
-/*
- *	walk.c
- */
-Node*	callnew(Type *t);
-Node*	chanfn(char *name, int n, Type *t);
-Node*	mkcall(char *name, Type *t, NodeList **init, ...);
-Node*	mkcall1(Node *fn, Type *t, NodeList **init, ...);
-int	vmatch1(Node *l, Node *r);
-void	walk(Node *fn);
-void	walkexpr(Node **np, NodeList **init);
-void	walkexprlist(NodeList *l, NodeList **init);
-void	walkexprlistsafe(NodeList *l, NodeList **init);
-void	walkstmt(Node **np);
-void	walkstmtlist(NodeList *l);
-Node*	conv(Node*, Type*);
-int	candiscard(Node*);
-int	needwritebarrier(Node*, Node*);
-Node*	outervalue(Node*);
-void	usefield(Node*);
-
-/*
- *	arch-specific ggen.c/gsubr.c/gobj.c/pgen.c/plive.c
- */
-#define	P	((Prog*)0)
-
-EXTERN	Prog*	continpc;
-EXTERN	Prog*	breakpc;
-EXTERN	Prog*	pc;
-EXTERN	Prog*	firstpc;
-
-EXTERN	Node*	nodfp;
-EXTERN	int	disable_checknil;
-EXTERN	vlong	zerosize;
-
-int	anyregalloc(void);
-void	betypeinit(void);
-void	bgen(Node *n, int true, int likely, Prog *to);
-void	checknil(Node*, NodeList**);
-void	expandchecks(Prog*);
-void	cgen(Node*, Node*);
-void	cgen_asop(Node *n);
-void	cgen_call(Node *n, int proc);
-void	cgen_callinter(Node *n, Node *res, int proc);
-void	cgen_checknil(Node*);
-void	cgen_ret(Node *n);
-void	clearfat(Node *n);
-void	compile(Node*);
-void	defframe(Prog*);
-int	dgostringptr(Sym*, int off, char *str);
-int	dgostrlitptr(Sym*, int off, Strlit*);
-int	dstringptr(Sym *s, int off, char *str);
-int	dsymptr(Sym *s, int off, Sym *x, int xoff);
-int	duintxx(Sym *s, int off, uint64 v, int wid);
-void	dumpdata(void);
-void	fixautoused(Prog*);
-void	gdata(Node*, Node*, int);
-void	gdatacomplex(Node*, Mpcplx*);
-void	gdatastring(Node*, Strlit*);
-void	ggloblnod(Node *nam);
-void	ggloblsym(Sym *s, int32 width, int8 flags);
-void	gvardef(Node*);
-void	gvarkill(Node*);
-Prog*	gjmp(Prog*);
-void	gused(Node*);
-void	movelarge(NodeList*);
-int	isfat(Type*);
-void	linkarchinit(void);
-void	liveness(Node*, Prog*, Sym*, Sym*);
-void	twobitwalktype1(Type*, vlong*, Bvec*);
-void	markautoused(Prog*);
-Plist*	newplist(void);
-Node*	nodarg(Type*, int);
-void	nopout(Prog*);
-void	patch(Prog*, Prog*);
-Prog*	unpatch(Prog*);
-
-#pragma	varargck	type	"B"	Mpint*
-#pragma	varargck	type	"E"	int
-#pragma	varargck	type	"E"	uint
-#pragma	varargck	type	"F"	Mpflt*
-#pragma	varargck	type	"H"	NodeList*
-#pragma	varargck	type	"J"	Node*
-#pragma	varargck	type	"lL"	int32
-#pragma	varargck	type	"L"	int32
-#pragma	varargck	type	"N"	Node*
-#pragma	varargck	type	"lN"	Node*
-#pragma	varargck	type	"O"	int
-#pragma	varargck	type	"O"	uint
-#pragma	varargck	type	"Q"	Bits
-#pragma	varargck	type	"S"	Sym*
-#pragma	varargck	type	"lS"	LSym*
-#pragma	varargck	type	"T"	Type*
-#pragma	varargck	type	"lT"	Type*
-#pragma	varargck	type	"V"	Val*
-#pragma	varargck	type	"Z"	Strlit*
-
-/*
- *	racewalk.c
- */
-void	racewalk(Node *fn);
diff --git a/src/cmd/gc/go.y b/src/cmd/gc/go.y
deleted file mode 100644
index 68fccc1..0000000
--- a/src/cmd/gc/go.y
+++ /dev/null
@@ -1,2223 +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.
-
-/*
- * Go language grammar.
- *
- * The Go semicolon rules are:
- *
- *  1. all statements and declarations are terminated by semicolons.
- *  2. semicolons can be omitted before a closing ) or }.
- *  3. semicolons are inserted by the lexer before a newline
- *      following a specific list of tokens.
- *
- * Rules #1 and #2 are accomplished by writing the lists as
- * semicolon-separated lists with an optional trailing semicolon.
- * Rule #3 is implemented in yylex.
- */
-
-%{
-#include <u.h>
-#include <stdio.h>	/* if we don't, bison will, and go.h re-#defines getc */
-#include <libc.h>
-#include "go.h"
-
-static void fixlbrace(int);
-%}
-%union	{
-	Node*		node;
-	NodeList*		list;
-	Type*		type;
-	Sym*		sym;
-	struct	Val	val;
-	int		i;
-}
-
-// |sed 's/.*	//' |9 fmt -l1 |sort |9 fmt -l50 | sed 's/^/%xxx		/'
-
-%token	<val>	LLITERAL
-%token	<i>	LASOP LCOLAS
-%token	<sym>	LBREAK LCASE LCHAN LCONST LCONTINUE LDDD
-%token	<sym>	LDEFAULT LDEFER LELSE LFALL LFOR LFUNC LGO LGOTO
-%token	<sym>	LIF LIMPORT LINTERFACE LMAP LNAME
-%token	<sym>	LPACKAGE LRANGE LRETURN LSELECT LSTRUCT LSWITCH
-%token	<sym>	LTYPE LVAR
-
-%token		LANDAND LANDNOT LBODY LCOMM LDEC LEQ LGE LGT
-%token		LIGNORE LINC LLE LLSH LLT LNE LOROR LRSH
-
-%type	<i>	lbrace import_here
-%type	<sym>	sym packname
-%type	<val>	oliteral
-
-%type	<node>	stmt ntype
-%type	<node>	arg_type
-%type	<node>	case caseblock
-%type	<node>	compound_stmt dotname embed expr complitexpr bare_complitexpr
-%type	<node>	expr_or_type
-%type	<node>	fndcl hidden_fndcl fnliteral
-%type	<node>	for_body for_header for_stmt if_header if_stmt non_dcl_stmt
-%type	<node>	interfacedcl keyval labelname name
-%type	<node>	name_or_type non_expr_type
-%type	<node>	new_name dcl_name oexpr typedclname
-%type	<node>	onew_name
-%type	<node>	osimple_stmt pexpr pexpr_no_paren
-%type	<node>	pseudocall range_stmt select_stmt
-%type	<node>	simple_stmt
-%type	<node>	switch_stmt uexpr
-%type	<node>	xfndcl typedcl start_complit
-
-%type	<list>	xdcl fnbody fnres loop_body dcl_name_list
-%type	<list>	new_name_list expr_list keyval_list braced_keyval_list expr_or_type_list xdcl_list
-%type	<list>	oexpr_list caseblock_list elseif elseif_list else stmt_list oarg_type_list_ocomma arg_type_list
-%type	<list>	interfacedcl_list vardcl vardcl_list structdcl structdcl_list
-%type	<list>	common_dcl constdcl constdcl1 constdcl_list typedcl_list
-
-%type	<node>	convtype comptype dotdotdot
-%type	<node>	indcl interfacetype structtype ptrtype
-%type	<node>	recvchantype non_recvchantype othertype fnret_type fntype
-
-%type	<sym>	hidden_importsym hidden_pkg_importsym
-
-%type	<node>	hidden_constant hidden_literal hidden_funarg
-%type	<node>	hidden_interfacedcl hidden_structdcl
-
-%type	<list>	hidden_funres
-%type	<list>	ohidden_funres
-%type	<list>	hidden_funarg_list ohidden_funarg_list
-%type	<list>	hidden_interfacedcl_list ohidden_interfacedcl_list
-%type	<list>	hidden_structdcl_list ohidden_structdcl_list
-
-%type	<type>	hidden_type hidden_type_misc hidden_pkgtype
-%type	<type>	hidden_type_func
-%type	<type>	hidden_type_recv_chan hidden_type_non_recv_chan
-
-%left		LCOMM	/* outside the usual hierarchy; here for good error messages */
-
-%left		LOROR
-%left		LANDAND
-%left		LEQ LNE LLE LGE LLT LGT
-%left		'+' '-' '|' '^'
-%left		'*' '/' '%' '&' LLSH LRSH LANDNOT
-
-/*
- * manual override of shift/reduce conflicts.
- * the general form is that we assign a precedence
- * to the token being shifted and then introduce
- * NotToken with lower precedence or PreferToToken with higher
- * and annotate the reducing rule accordingly.
- */
-%left		NotPackage
-%left		LPACKAGE
-
-%left		NotParen
-%left		'('
-
-%left		')'
-%left		PreferToRightParen
-
-%error-verbose
-
-%%
-file:
-	loadsys
-	package
-	imports
-	xdcl_list
-	{
-		xtop = concat(xtop, $4);
-	}
-
-package:
-	%prec NotPackage
-	{
-		prevlineno = lineno;
-		yyerror("package statement must be first");
-		errorexit();
-	}
-|	LPACKAGE sym ';'
-	{
-		mkpackage($2->name);
-	}
-
-/*
- * this loads the definitions for the low-level runtime functions,
- * so that the compiler can generate calls to them,
- * but does not make the name "runtime" visible as a package.
- */
-loadsys:
-	{
-		importpkg = runtimepkg;
-
-		if(debug['A'])
-			cannedimports("runtime.builtin", "package runtime\n\n$$\n\n");
-		else
-			cannedimports("runtime.builtin", runtimeimport);
-		curio.importsafe = 1;
-	}
-	import_package
-	import_there
-	{
-		importpkg = nil;
-	}
-
-imports:
-|	imports import ';'
-
-import:
-	LIMPORT import_stmt
-|	LIMPORT '(' import_stmt_list osemi ')'
-|	LIMPORT '(' ')'
-
-import_stmt:
-	import_here import_package import_there
-	{
-		Pkg *ipkg;
-		Sym *my;
-		Node *pack;
-		
-		ipkg = importpkg;
-		my = importmyname;
-		importpkg = nil;
-		importmyname = S;
-
-		if(my == nil)
-			my = lookup(ipkg->name);
-
-		pack = nod(OPACK, N, N);
-		pack->sym = my;
-		pack->pkg = ipkg;
-		pack->lineno = $1;
-
-		if(my->name[0] == '.') {
-			importdot(ipkg, pack);
-			break;
-		}
-		if(strcmp(my->name, "init") == 0) {
-			yyerror("cannot import package as init - init must be a func");
-			break;
-		}
-		if(my->name[0] == '_' && my->name[1] == '\0')
-			break;
-		if(my->def) {
-			lineno = $1;
-			redeclare(my, "as imported package name");
-		}
-		my->def = pack;
-		my->lastlineno = $1;
-		my->block = 1;	// at top level
-	}
-|	import_here import_there
-	{
-		// When an invalid import path is passed to importfile,
-		// it calls yyerror and then sets up a fake import with
-		// no package statement. This allows us to test more
-		// than one invalid import statement in a single file.
-		if(nerrors == 0)
-			fatal("phase error in import");
-	}
-
-import_stmt_list:
-	import_stmt
-|	import_stmt_list ';' import_stmt
-
-import_here:
-	LLITERAL
-	{
-		// import with original name
-		$$ = parserline();
-		importmyname = S;
-		importfile(&$1, $$);
-	}
-|	sym LLITERAL
-	{
-		// import with given name
-		$$ = parserline();
-		importmyname = $1;
-		importfile(&$2, $$);
-	}
-|	'.' LLITERAL
-	{
-		// import into my name space
-		$$ = parserline();
-		importmyname = lookup(".");
-		importfile(&$2, $$);
-	}
-
-import_package:
-	LPACKAGE LNAME import_safety ';'
-	{
-		if(importpkg->name == nil) {
-			importpkg->name = $2->name;
-			pkglookup($2->name, nil)->npkg++;
-		} else if(strcmp(importpkg->name, $2->name) != 0)
-			yyerror("conflicting names %s and %s for package \"%Z\"", importpkg->name, $2->name, importpkg->path);
-		importpkg->direct = 1;
-		importpkg->safe = curio.importsafe;
-
-		if(safemode && !curio.importsafe)
-			yyerror("cannot import unsafe package \"%Z\"", importpkg->path);
-	}
-
-import_safety:
-|	LNAME
-	{
-		if(strcmp($1->name, "safe") == 0)
-			curio.importsafe = 1;
-	}
-
-import_there:
-	{
-		defercheckwidth();
-	}
-	hidden_import_list '$' '$'
-	{
-		resumecheckwidth();
-		unimportfile();
-	}
-
-/*
- * declarations
- */
-xdcl:
-	{
-		yyerror("empty top-level declaration");
-		$$ = nil;
-	}
-|	common_dcl
-|	xfndcl
-	{
-		$$ = list1($1);
-	}
-|	non_dcl_stmt
-	{
-		yyerror("non-declaration statement outside function body");
-		$$ = nil;
-	}
-|	error
-	{
-		$$ = nil;
-	}
-
-common_dcl:
-	LVAR vardcl
-	{
-		$$ = $2;
-	}
-|	LVAR '(' vardcl_list osemi ')'
-	{
-		$$ = $3;
-	}
-|	LVAR '(' ')'
-	{
-		$$ = nil;
-	}
-|	lconst constdcl
-	{
-		$$ = $2;
-		iota = -100000;
-		lastconst = nil;
-	}
-|	lconst '(' constdcl osemi ')'
-	{
-		$$ = $3;
-		iota = -100000;
-		lastconst = nil;
-	}
-|	lconst '(' constdcl ';' constdcl_list osemi ')'
-	{
-		$$ = concat($3, $5);
-		iota = -100000;
-		lastconst = nil;
-	}
-|	lconst '(' ')'
-	{
-		$$ = nil;
-		iota = -100000;
-	}
-|	LTYPE typedcl
-	{
-		$$ = list1($2);
-	}
-|	LTYPE '(' typedcl_list osemi ')'
-	{
-		$$ = $3;
-	}
-|	LTYPE '(' ')'
-	{
-		$$ = nil;
-	}
-
-lconst:
-	LCONST
-	{
-		iota = 0;
-	}
-
-vardcl:
-	dcl_name_list ntype
-	{
-		$$ = variter($1, $2, nil);
-	}
-|	dcl_name_list ntype '=' expr_list
-	{
-		$$ = variter($1, $2, $4);
-	}
-|	dcl_name_list '=' expr_list
-	{
-		$$ = variter($1, nil, $3);
-	}
-
-constdcl:
-	dcl_name_list ntype '=' expr_list
-	{
-		$$ = constiter($1, $2, $4);
-	}
-|	dcl_name_list '=' expr_list
-	{
-		$$ = constiter($1, N, $3);
-	}
-
-constdcl1:
-	constdcl
-|	dcl_name_list ntype
-	{
-		$$ = constiter($1, $2, nil);
-	}
-|	dcl_name_list
-	{
-		$$ = constiter($1, N, nil);
-	}
-
-typedclname:
-	sym
-	{
-		// different from dclname because the name
-		// becomes visible right here, not at the end
-		// of the declaration.
-		$$ = typedcl0($1);
-	}
-
-typedcl:
-	typedclname ntype
-	{
-		$$ = typedcl1($1, $2, 1);
-	}
-
-simple_stmt:
-	expr
-	{
-		$$ = $1;
-
-		// These nodes do not carry line numbers.
-		// Since a bare name used as an expression is an error,
-		// introduce a wrapper node to give the correct line.
-		switch($$->op) {
-		case ONAME:
-		case ONONAME:
-		case OTYPE:
-		case OPACK:
-		case OLITERAL:
-			$$ = nod(OPAREN, $$, N);
-			$$->implicit = 1;
-			break;
-		}
-	}
-|	expr LASOP expr
-	{
-		$$ = nod(OASOP, $1, $3);
-		$$->etype = $2;			// rathole to pass opcode
-	}
-|	expr_list '=' expr_list
-	{
-		if($1->next == nil && $3->next == nil) {
-			// simple
-			$$ = nod(OAS, $1->n, $3->n);
-			break;
-		}
-		// multiple
-		$$ = nod(OAS2, N, N);
-		$$->list = $1;
-		$$->rlist = $3;
-	}
-|	expr_list LCOLAS expr_list
-	{
-		if($3->n->op == OTYPESW) {
-			$$ = nod(OTYPESW, N, $3->n->right);
-			if($3->next != nil)
-				yyerror("expr.(type) must be alone in list");
-			if($1->next != nil)
-				yyerror("argument count mismatch: %d = %d", count($1), 1);
-			else if(($1->n->op != ONAME && $1->n->op != OTYPE && $1->n->op != ONONAME) || isblank($1->n))
-				yyerror("invalid variable name %N in type switch", $1->n);
-			else
-				$$->left = dclname($1->n->sym);  // it's a colas, so must not re-use an oldname.
-			break;
-		}
-		$$ = colas($1, $3, $2);
-	}
-|	expr LINC
-	{
-		$$ = nod(OASOP, $1, nodintconst(1));
-		$$->implicit = 1;
-		$$->etype = OADD;
-	}
-|	expr LDEC
-	{
-		$$ = nod(OASOP, $1, nodintconst(1));
-		$$->implicit = 1;
-		$$->etype = OSUB;
-	}
-
-case:
-	LCASE expr_or_type_list ':'
-	{
-		Node *n, *nn;
-
-		// will be converted to OCASE
-		// right will point to next case
-		// done in casebody()
-		markdcl();
-		$$ = nod(OXCASE, N, N);
-		$$->list = $2;
-		if(typesw != N && typesw->right != N && (n=typesw->right->left) != N) {
-			// type switch - declare variable
-			nn = newname(n->sym);
-			declare(nn, dclcontext);
-			$$->nname = nn;
-
-			// keep track of the instances for reporting unused
-			nn->defn = typesw->right;
-		}
-	}
-|	LCASE expr_or_type_list '=' expr ':'
-	{
-		Node *n;
-
-		// will be converted to OCASE
-		// right will point to next case
-		// done in casebody()
-		markdcl();
-		$$ = nod(OXCASE, N, N);
-		if($2->next == nil)
-			n = nod(OAS, $2->n, $4);
-		else {
-			n = nod(OAS2, N, N);
-			n->list = $2;
-			n->rlist = list1($4);
-		}
-		$$->list = list1(n);
-	}
-|	LCASE expr_or_type_list LCOLAS expr ':'
-	{
-		// will be converted to OCASE
-		// right will point to next case
-		// done in casebody()
-		markdcl();
-		$$ = nod(OXCASE, N, N);
-		$$->list = list1(colas($2, list1($4), $3));
-	}
-|	LDEFAULT ':'
-	{
-		Node *n, *nn;
-
-		markdcl();
-		$$ = nod(OXCASE, N, N);
-		if(typesw != N && typesw->right != N && (n=typesw->right->left) != N) {
-			// type switch - declare variable
-			nn = newname(n->sym);
-			declare(nn, dclcontext);
-			$$->nname = nn;
-
-			// keep track of the instances for reporting unused
-			nn->defn = typesw->right;
-		}
-	}
-
-compound_stmt:
-	'{'
-	{
-		markdcl();
-	}
-	stmt_list '}'
-	{
-		if($3 == nil)
-			$$ = nod(OEMPTY, N, N);
-		else
-			$$ = liststmt($3);
-		popdcl();
-	}
-
-caseblock:
-	case
-	{
-		// If the last token read by the lexer was consumed
-		// as part of the case, clear it (parser has cleared yychar).
-		// If the last token read by the lexer was the lookahead
-		// leave it alone (parser has it cached in yychar).
-		// This is so that the stmt_list action doesn't look at
-		// the case tokens if the stmt_list is empty.
-		yylast = yychar;
-		$1->xoffset = block;
-	}
-	stmt_list
-	{
-		int last;
-
-		// This is the only place in the language where a statement
-		// list is not allowed to drop the final semicolon, because
-		// it's the only place where a statement list is not followed 
-		// by a closing brace.  Handle the error for pedantry.
-
-		// Find the final token of the statement list.
-		// yylast is lookahead; yyprev is last of stmt_list
-		last = yyprev;
-
-		if(last > 0 && last != ';' && yychar != '}')
-			yyerror("missing statement after label");
-		$$ = $1;
-		$$->nbody = $3;
-		popdcl();
-	}
-
-caseblock_list:
-	{
-		$$ = nil;
-	}
-|	caseblock_list caseblock
-	{
-		$$ = list($1, $2);
-	}
-
-loop_body:
-	LBODY
-	{
-		markdcl();
-	}
-	stmt_list '}'
-	{
-		$$ = $3;
-		popdcl();
-	}
-
-range_stmt:
-	expr_list '=' LRANGE expr
-	{
-		$$ = nod(ORANGE, N, $4);
-		$$->list = $1;
-		$$->etype = 0;	// := flag
-	}
-|	expr_list LCOLAS LRANGE expr
-	{
-		$$ = nod(ORANGE, N, $4);
-		$$->list = $1;
-		$$->colas = 1;
-		colasdefn($1, $$);
-	}
-|	LRANGE expr
-	{
-		$$ = nod(ORANGE, N, $2);
-		$$->etype = 0; // := flag
-	}
-
-for_header:
-	osimple_stmt ';' osimple_stmt ';' osimple_stmt
-	{
-		// init ; test ; incr
-		if($5 != N && $5->colas != 0)
-			yyerror("cannot declare in the for-increment");
-		$$ = nod(OFOR, N, N);
-		if($1 != N)
-			$$->ninit = list1($1);
-		$$->ntest = $3;
-		$$->nincr = $5;
-	}
-|	osimple_stmt
-	{
-		// normal test
-		$$ = nod(OFOR, N, N);
-		$$->ntest = $1;
-	}
-|	range_stmt
-
-for_body:
-	for_header loop_body
-	{
-		$$ = $1;
-		$$->nbody = concat($$->nbody, $2);
-	}
-
-for_stmt:
-	LFOR
-	{
-		markdcl();
-	}
-	for_body
-	{
-		$$ = $3;
-		popdcl();
-	}
-
-if_header:
-	osimple_stmt
-	{
-		// test
-		$$ = nod(OIF, N, N);
-		$$->ntest = $1;
-	}
-|	osimple_stmt ';' osimple_stmt
-	{
-		// init ; test
-		$$ = nod(OIF, N, N);
-		if($1 != N)
-			$$->ninit = list1($1);
-		$$->ntest = $3;
-	}
-
-/* IF cond body (ELSE IF cond body)* (ELSE block)? */
-if_stmt:
-	LIF
-	{
-		markdcl();
-	}
-	if_header
-	{
-		if($3->ntest == N)
-			yyerror("missing condition in if statement");
-	}
-	loop_body
-	{
-		$3->nbody = $5;
-	}
-	elseif_list else
-	{
-		Node *n;
-		NodeList *nn;
-
-		$$ = $3;
-		n = $3;
-		popdcl();
-		for(nn = concat($7, $8); nn; nn = nn->next) {
-			if(nn->n->op == OIF)
-				popdcl();
-			n->nelse = list1(nn->n);
-			n = nn->n;
-		}
-	}
-
-elseif:
-	LELSE LIF 
-	{
-		markdcl();
-	}
-	if_header loop_body
-	{
-		if($4->ntest == N)
-			yyerror("missing condition in if statement");
-		$4->nbody = $5;
-		$$ = list1($4);
-	}
-
-elseif_list:
-	{
-		$$ = nil;
-	}
-|	elseif_list elseif
-	{
-		$$ = concat($1, $2);
-	}
-
-else:
-	{
-		$$ = nil;
-	}
-|	LELSE compound_stmt
-	{
-		NodeList *node;
-		
-		node = mal(sizeof *node);
-		node->n = $2;
-		node->end = node;
-		$$ = node;
-	}
-
-switch_stmt:
-	LSWITCH
-	{
-		markdcl();
-	}
-	if_header
-	{
-		Node *n;
-		n = $3->ntest;
-		if(n != N && n->op != OTYPESW)
-			n = N;
-		typesw = nod(OXXX, typesw, n);
-	}
-	LBODY caseblock_list '}'
-	{
-		$$ = $3;
-		$$->op = OSWITCH;
-		$$->list = $6;
-		typesw = typesw->left;
-		popdcl();
-	}
-
-select_stmt:
-	LSELECT
-	{
-		typesw = nod(OXXX, typesw, N);
-	}
-	LBODY caseblock_list '}'
-	{
-		$$ = nod(OSELECT, N, N);
-		$$->lineno = typesw->lineno;
-		$$->list = $4;
-		typesw = typesw->left;
-	}
-
-/*
- * expressions
- */
-expr:
-	uexpr
-|	expr LOROR expr
-	{
-		$$ = nod(OOROR, $1, $3);
-	}
-|	expr LANDAND expr
-	{
-		$$ = nod(OANDAND, $1, $3);
-	}
-|	expr LEQ expr
-	{
-		$$ = nod(OEQ, $1, $3);
-	}
-|	expr LNE expr
-	{
-		$$ = nod(ONE, $1, $3);
-	}
-|	expr LLT expr
-	{
-		$$ = nod(OLT, $1, $3);
-	}
-|	expr LLE expr
-	{
-		$$ = nod(OLE, $1, $3);
-	}
-|	expr LGE expr
-	{
-		$$ = nod(OGE, $1, $3);
-	}
-|	expr LGT expr
-	{
-		$$ = nod(OGT, $1, $3);
-	}
-|	expr '+' expr
-	{
-		$$ = nod(OADD, $1, $3);
-	}
-|	expr '-' expr
-	{
-		$$ = nod(OSUB, $1, $3);
-	}
-|	expr '|' expr
-	{
-		$$ = nod(OOR, $1, $3);
-	}
-|	expr '^' expr
-	{
-		$$ = nod(OXOR, $1, $3);
-	}
-|	expr '*' expr
-	{
-		$$ = nod(OMUL, $1, $3);
-	}
-|	expr '/' expr
-	{
-		$$ = nod(ODIV, $1, $3);
-	}
-|	expr '%' expr
-	{
-		$$ = nod(OMOD, $1, $3);
-	}
-|	expr '&' expr
-	{
-		$$ = nod(OAND, $1, $3);
-	}
-|	expr LANDNOT expr
-	{
-		$$ = nod(OANDNOT, $1, $3);
-	}
-|	expr LLSH expr
-	{
-		$$ = nod(OLSH, $1, $3);
-	}
-|	expr LRSH expr
-	{
-		$$ = nod(ORSH, $1, $3);
-	}
-	/* not an expression anymore, but left in so we can give a good error */
-|	expr LCOMM expr
-	{
-		$$ = nod(OSEND, $1, $3);
-	}
-
-uexpr:
-	pexpr
-|	'*' uexpr
-	{
-		$$ = nod(OIND, $2, N);
-	}
-|	'&' uexpr
-	{
-		if($2->op == OCOMPLIT) {
-			// Special case for &T{...}: turn into (*T){...}.
-			$$ = $2;
-			$$->right = nod(OIND, $$->right, N);
-			$$->right->implicit = 1;
-		} else {
-			$$ = nod(OADDR, $2, N);
-		}
-	}
-|	'+' uexpr
-	{
-		$$ = nod(OPLUS, $2, N);
-	}
-|	'-' uexpr
-	{
-		$$ = nod(OMINUS, $2, N);
-	}
-|	'!' uexpr
-	{
-		$$ = nod(ONOT, $2, N);
-	}
-|	'~' uexpr
-	{
-		yyerror("the bitwise complement operator is ^");
-		$$ = nod(OCOM, $2, N);
-	}
-|	'^' uexpr
-	{
-		$$ = nod(OCOM, $2, N);
-	}
-|	LCOMM uexpr
-	{
-		$$ = nod(ORECV, $2, N);
-	}
-
-/*
- * call-like statements that
- * can be preceded by 'defer' and 'go'
- */
-pseudocall:
-	pexpr '(' ')'
-	{
-		$$ = nod(OCALL, $1, N);
-	}
-|	pexpr '(' expr_or_type_list ocomma ')'
-	{
-		$$ = nod(OCALL, $1, N);
-		$$->list = $3;
-	}
-|	pexpr '(' expr_or_type_list LDDD ocomma ')'
-	{
-		$$ = nod(OCALL, $1, N);
-		$$->list = $3;
-		$$->isddd = 1;
-	}
-
-pexpr_no_paren:
-	LLITERAL
-	{
-		$$ = nodlit($1);
-	}
-|	name
-|	pexpr '.' sym
-	{
-		if($1->op == OPACK) {
-			Sym *s;
-			s = restrictlookup($3->name, $1->pkg);
-			$1->used = 1;
-			$$ = oldname(s);
-			break;
-		}
-		$$ = nod(OXDOT, $1, newname($3));
-	}
-|	pexpr '.' '(' expr_or_type ')'
-	{
-		$$ = nod(ODOTTYPE, $1, $4);
-	}
-|	pexpr '.' '(' LTYPE ')'
-	{
-		$$ = nod(OTYPESW, N, $1);
-	}
-|	pexpr '[' expr ']'
-	{
-		$$ = nod(OINDEX, $1, $3);
-	}
-|	pexpr '[' oexpr ':' oexpr ']'
-	{
-		$$ = nod(OSLICE, $1, nod(OKEY, $3, $5));
-	}
-|	pexpr '[' oexpr ':' oexpr ':' oexpr ']'
-	{
-		if($5 == N)
-			yyerror("middle index required in 3-index slice");
-		if($7 == N)
-			yyerror("final index required in 3-index slice");
-		$$ = nod(OSLICE3, $1, nod(OKEY, $3, nod(OKEY, $5, $7)));
-	}
-|	pseudocall
-|	convtype '(' expr ocomma ')'
-	{
-		// conversion
-		$$ = nod(OCALL, $1, N);
-		$$->list = list1($3);
-	}
-|	comptype lbrace start_complit braced_keyval_list '}'
-	{
-		$$ = $3;
-		$$->right = $1;
-		$$->list = $4;
-		fixlbrace($2);
-	}
-|	pexpr_no_paren '{' start_complit braced_keyval_list '}'
-	{
-		$$ = $3;
-		$$->right = $1;
-		$$->list = $4;
-	}
-|	'(' expr_or_type ')' '{' start_complit braced_keyval_list '}'
-	{
-		yyerror("cannot parenthesize type in composite literal");
-		$$ = $5;
-		$$->right = $2;
-		$$->list = $6;
-	}
-|	fnliteral
-
-start_complit:
-	{
-		// composite expression.
-		// make node early so we get the right line number.
-		$$ = nod(OCOMPLIT, N, N);
-	}
-
-keyval:
-	expr ':' complitexpr
-	{
-		$$ = nod(OKEY, $1, $3);
-	}
-
-bare_complitexpr:
-	expr
-	{
-		// These nodes do not carry line numbers.
-		// Since a composite literal commonly spans several lines,
-		// the line number on errors may be misleading.
-		// Introduce a wrapper node to give the correct line.
-		$$ = $1;
-		switch($$->op) {
-		case ONAME:
-		case ONONAME:
-		case OTYPE:
-		case OPACK:
-		case OLITERAL:
-			$$ = nod(OPAREN, $$, N);
-			$$->implicit = 1;
-		}
-	}
-|	'{' start_complit braced_keyval_list '}'
-	{
-		$$ = $2;
-		$$->list = $3;
-	}
-
-complitexpr:
-	expr
-|	'{' start_complit braced_keyval_list '}'
-	{
-		$$ = $2;
-		$$->list = $3;
-	}
-
-pexpr:
-	pexpr_no_paren
-|	'(' expr_or_type ')'
-	{
-		$$ = $2;
-		
-		// Need to know on lhs of := whether there are ( ).
-		// Don't bother with the OPAREN in other cases:
-		// it's just a waste of memory and time.
-		switch($$->op) {
-		case ONAME:
-		case ONONAME:
-		case OPACK:
-		case OTYPE:
-		case OLITERAL:
-		case OTYPESW:
-			$$ = nod(OPAREN, $$, N);
-		}
-	}
-
-expr_or_type:
-	expr
-|	non_expr_type	%prec PreferToRightParen
-
-name_or_type:
-	ntype
-
-lbrace:
-	LBODY
-	{
-		$$ = LBODY;
-	}
-|	'{'
-	{
-		$$ = '{';
-	}
-
-/*
- * names and types
- *	newname is used before declared
- *	oldname is used after declared
- */
-new_name:
-	sym
-	{
-		if($1 == S)
-			$$ = N;
-		else
-			$$ = newname($1);
-	}
-
-dcl_name:
-	sym
-	{
-		$$ = dclname($1);
-	}
-
-onew_name:
-	{
-		$$ = N;
-	}
-|	new_name
-
-sym:
-	LNAME
-	{
-		$$ = $1;
-		// during imports, unqualified non-exported identifiers are from builtinpkg
-		if(importpkg != nil && !exportname($1->name))
-			$$ = pkglookup($1->name, builtinpkg);
-	}
-|	hidden_importsym
-|	'?'
-	{
-		$$ = S;
-	}
-
-hidden_importsym:
-	'@' LLITERAL '.' LNAME
-	{
-		Pkg *p;
-
-		if($2.u.sval->len == 0)
-			p = importpkg;
-		else {
-			if(isbadimport($2.u.sval))
-				errorexit();
-			p = mkpkg($2.u.sval);
-		}
-		$$ = pkglookup($4->name, p);
-	}
-|	'@' LLITERAL '.' '?'
-	{
-		Pkg *p;
-
-		if($2.u.sval->len == 0)
-			p = importpkg;
-		else {
-			if(isbadimport($2.u.sval))
-				errorexit();
-			p = mkpkg($2.u.sval);
-		}
-		$$ = pkglookup("?", p);
-	}
-
-name:
-	sym	%prec NotParen
-	{
-		$$ = oldname($1);
-		if($$->pack != N)
-			$$->pack->used = 1;
-	}
-
-labelname:
-	new_name
-
-/*
- * to avoid parsing conflicts, type is split into
- *	channel types
- *	function types
- *	parenthesized types
- *	any other type
- * the type system makes additional restrictions,
- * but those are not implemented in the grammar.
- */
-dotdotdot:
-	LDDD
-	{
-		yyerror("final argument in variadic function missing type");
-		$$ = nod(ODDD, typenod(typ(TINTER)), N);
-	}
-|	LDDD ntype
-	{
-		$$ = nod(ODDD, $2, N);
-	}
-
-ntype:
-	recvchantype
-|	fntype
-|	othertype
-|	ptrtype
-|	dotname
-|	'(' ntype ')'
-	{
-		$$ = $2;
-	}
-
-non_expr_type:
-	recvchantype
-|	fntype
-|	othertype
-|	'*' non_expr_type
-	{
-		$$ = nod(OIND, $2, N);
-	}
-
-non_recvchantype:
-	fntype
-|	othertype
-|	ptrtype
-|	dotname
-|	'(' ntype ')'
-	{
-		$$ = $2;
-	}
-
-convtype:
-	fntype
-|	othertype
-
-comptype:
-	othertype
-
-fnret_type:
-	recvchantype
-|	fntype
-|	othertype
-|	ptrtype
-|	dotname
-
-dotname:
-	name
-|	name '.' sym
-	{
-		if($1->op == OPACK) {
-			Sym *s;
-			s = restrictlookup($3->name, $1->pkg);
-			$1->used = 1;
-			$$ = oldname(s);
-			break;
-		}
-		$$ = nod(OXDOT, $1, newname($3));
-	}
-
-othertype:
-	'[' oexpr ']' ntype
-	{
-		$$ = nod(OTARRAY, $2, $4);
-	}
-|	'[' LDDD ']' ntype
-	{
-		// array literal of nelem
-		$$ = nod(OTARRAY, nod(ODDD, N, N), $4);
-	}
-|	LCHAN non_recvchantype
-	{
-		$$ = nod(OTCHAN, $2, N);
-		$$->etype = Cboth;
-	}
-|	LCHAN LCOMM ntype
-	{
-		$$ = nod(OTCHAN, $3, N);
-		$$->etype = Csend;
-	}
-|	LMAP '[' ntype ']' ntype
-	{
-		$$ = nod(OTMAP, $3, $5);
-	}
-|	structtype
-|	interfacetype
-
-ptrtype:
-	'*' ntype
-	{
-		$$ = nod(OIND, $2, N);
-	}
-
-recvchantype:
-	LCOMM LCHAN ntype
-	{
-		$$ = nod(OTCHAN, $3, N);
-		$$->etype = Crecv;
-	}
-
-structtype:
-	LSTRUCT lbrace structdcl_list osemi '}'
-	{
-		$$ = nod(OTSTRUCT, N, N);
-		$$->list = $3;
-		fixlbrace($2);
-	}
-|	LSTRUCT lbrace '}'
-	{
-		$$ = nod(OTSTRUCT, N, N);
-		fixlbrace($2);
-	}
-
-interfacetype:
-	LINTERFACE lbrace interfacedcl_list osemi '}'
-	{
-		$$ = nod(OTINTER, N, N);
-		$$->list = $3;
-		fixlbrace($2);
-	}
-|	LINTERFACE lbrace '}'
-	{
-		$$ = nod(OTINTER, N, N);
-		fixlbrace($2);
-	}
-
-/*
- * function stuff
- * all in one place to show how crappy it all is
- */
-xfndcl:
-	LFUNC fndcl fnbody
-	{
-		$$ = $2;
-		if($$ == N)
-			break;
-		if(noescape && $3 != nil)
-			yyerror("can only use //go:noescape with external func implementations");
-		$$->nbody = $3;
-		$$->endlineno = lineno;
-		$$->noescape = noescape;
-		$$->nosplit = nosplit;
-		funcbody($$);
-	}
-
-fndcl:
-	sym '(' oarg_type_list_ocomma ')' fnres
-	{
-		Node *t;
-
-		$$ = N;
-		$3 = checkarglist($3, 1);
-
-		if(strcmp($1->name, "init") == 0) {
-			$1 = renameinit();
-			if($3 != nil || $5 != nil)
-				yyerror("func init must have no arguments and no return values");
-		}
-		if(strcmp(localpkg->name, "main") == 0 && strcmp($1->name, "main") == 0) {
-			if($3 != nil || $5 != nil)
-				yyerror("func main must have no arguments and no return values");
-		}
-
-		t = nod(OTFUNC, N, N);
-		t->list = $3;
-		t->rlist = $5;
-
-		$$ = nod(ODCLFUNC, N, N);
-		$$->nname = newname($1);
-		$$->nname->defn = $$;
-		$$->nname->ntype = t;		// TODO: check if nname already has an ntype
-		declare($$->nname, PFUNC);
-
-		funchdr($$);
-	}
-|	'(' oarg_type_list_ocomma ')' sym '(' oarg_type_list_ocomma ')' fnres
-	{
-		Node *rcvr, *t;
-
-		$$ = N;
-		$2 = checkarglist($2, 0);
-		$6 = checkarglist($6, 1);
-
-		if($2 == nil) {
-			yyerror("method has no receiver");
-			break;
-		}
-		if($2->next != nil) {
-			yyerror("method has multiple receivers");
-			break;
-		}
-		rcvr = $2->n;
-		if(rcvr->op != ODCLFIELD) {
-			yyerror("bad receiver in method");
-			break;
-		}
-
-		t = nod(OTFUNC, rcvr, N);
-		t->list = $6;
-		t->rlist = $8;
-
-		$$ = nod(ODCLFUNC, N, N);
-		$$->shortname = newname($4);
-		$$->nname = methodname1($$->shortname, rcvr->right);
-		$$->nname->defn = $$;
-		$$->nname->ntype = t;
-		$$->nname->nointerface = nointerface;
-		declare($$->nname, PFUNC);
-
-		funchdr($$);
-	}
-
-hidden_fndcl:
-	hidden_pkg_importsym '(' ohidden_funarg_list ')' ohidden_funres
-	{
-		Sym *s;
-		Type *t;
-
-		$$ = N;
-
-		s = $1;
-		t = functype(N, $3, $5);
-
-		importsym(s, ONAME);
-		if(s->def != N && s->def->op == ONAME) {
-			if(eqtype(t, s->def->type)) {
-				dclcontext = PDISCARD;  // since we skip funchdr below
-				break;
-			}
-			yyerror("inconsistent definition for func %S during import\n\t%T\n\t%T", s, s->def->type, t);
-		}
-
-		$$ = newname(s);
-		$$->type = t;
-		declare($$, PFUNC);
-
-		funchdr($$);
-	}
-|	'(' hidden_funarg_list ')' sym '(' ohidden_funarg_list ')' ohidden_funres
-	{
-		$$ = methodname1(newname($4), $2->n->right); 
-		$$->type = functype($2->n, $6, $8);
-
-		checkwidth($$->type);
-		addmethod($4, $$->type, 0, nointerface);
-		nointerface = 0;
-		funchdr($$);
-		
-		// inl.c's inlnode in on a dotmeth node expects to find the inlineable body as
-		// (dotmeth's type)->nname->inl, and dotmeth's type has been pulled
-		// out by typecheck's lookdot as this $$->ttype.  So by providing
-		// this back link here we avoid special casing there.
-		$$->type->nname = $$;
-	}
-
-fntype:
-	LFUNC '(' oarg_type_list_ocomma ')' fnres
-	{
-		$3 = checkarglist($3, 1);
-		$$ = nod(OTFUNC, N, N);
-		$$->list = $3;
-		$$->rlist = $5;
-	}
-
-fnbody:
-	{
-		$$ = nil;
-	}
-|	'{' stmt_list '}'
-	{
-		$$ = $2;
-		if($$ == nil)
-			$$ = list1(nod(OEMPTY, N, N));
-	}
-
-fnres:
-	%prec NotParen
-	{
-		$$ = nil;
-	}
-|	fnret_type
-	{
-		$$ = list1(nod(ODCLFIELD, N, $1));
-	}
-|	'(' oarg_type_list_ocomma ')'
-	{
-		$2 = checkarglist($2, 0);
-		$$ = $2;
-	}
-
-fnlitdcl:
-	fntype
-	{
-		closurehdr($1);
-	}
-
-fnliteral:
-	fnlitdcl lbrace stmt_list '}'
-	{
-		$$ = closurebody($3);
-		fixlbrace($2);
-	}
-|	fnlitdcl error
-	{
-		$$ = closurebody(nil);
-	}
-
-/*
- * lists of things
- * note that they are left recursive
- * to conserve yacc stack. they need to
- * be reversed to interpret correctly
- */
-xdcl_list:
-	{
-		$$ = nil;
-	}
-|	xdcl_list xdcl ';'
-	{
-		$$ = concat($1, $2);
-		if(nsyntaxerrors == 0)
-			testdclstack();
-		nointerface = 0;
-		noescape = 0;
-		nosplit = 0;
-	}
-
-vardcl_list:
-	vardcl
-|	vardcl_list ';' vardcl
-	{
-		$$ = concat($1, $3);
-	}
-
-constdcl_list:
-	constdcl1
-|	constdcl_list ';' constdcl1
-	{
-		$$ = concat($1, $3);
-	}
-
-typedcl_list:
-	typedcl
-	{
-		$$ = list1($1);
-	}
-|	typedcl_list ';' typedcl
-	{
-		$$ = list($1, $3);
-	}
-
-structdcl_list:
-	structdcl
-|	structdcl_list ';' structdcl
-	{
-		$$ = concat($1, $3);
-	}
-
-interfacedcl_list:
-	interfacedcl
-	{
-		$$ = list1($1);
-	}
-|	interfacedcl_list ';' interfacedcl
-	{
-		$$ = list($1, $3);
-	}
-
-structdcl:
-	new_name_list ntype oliteral
-	{
-		NodeList *l;
-
-		Node *n;
-		l = $1;
-		if(l == nil) {
-			// ? symbol, during import (list1(N) == nil)
-			n = $2;
-			if(n->op == OIND)
-				n = n->left;
-			n = embedded(n->sym, importpkg);
-			n->right = $2;
-			n->val = $3;
-			$$ = list1(n);
-			break;
-		}
-
-		for(l=$1; l; l=l->next) {
-			l->n = nod(ODCLFIELD, l->n, $2);
-			l->n->val = $3;
-		}
-	}
-|	embed oliteral
-	{
-		$1->val = $2;
-		$$ = list1($1);
-	}
-|	'(' embed ')' oliteral
-	{
-		$2->val = $4;
-		$$ = list1($2);
-		yyerror("cannot parenthesize embedded type");
-	}
-|	'*' embed oliteral
-	{
-		$2->right = nod(OIND, $2->right, N);
-		$2->val = $3;
-		$$ = list1($2);
-	}
-|	'(' '*' embed ')' oliteral
-	{
-		$3->right = nod(OIND, $3->right, N);
-		$3->val = $5;
-		$$ = list1($3);
-		yyerror("cannot parenthesize embedded type");
-	}
-|	'*' '(' embed ')' oliteral
-	{
-		$3->right = nod(OIND, $3->right, N);
-		$3->val = $5;
-		$$ = list1($3);
-		yyerror("cannot parenthesize embedded type");
-	}
-
-packname:
-	LNAME
-	{
-		Node *n;
-
-		$$ = $1;
-		n = oldname($1);
-		if(n->pack != N)
-			n->pack->used = 1;
-	}
-|	LNAME '.' sym
-	{
-		Pkg *pkg;
-
-		if($1->def == N || $1->def->op != OPACK) {
-			yyerror("%S is not a package", $1);
-			pkg = localpkg;
-		} else {
-			$1->def->used = 1;
-			pkg = $1->def->pkg;
-		}
-		$$ = restrictlookup($3->name, pkg);
-	}
-
-embed:
-	packname
-	{
-		$$ = embedded($1, localpkg);
-	}
-
-interfacedcl:
-	new_name indcl
-	{
-		$$ = nod(ODCLFIELD, $1, $2);
-		ifacedcl($$);
-	}
-|	packname
-	{
-		$$ = nod(ODCLFIELD, N, oldname($1));
-	}
-|	'(' packname ')'
-	{
-		$$ = nod(ODCLFIELD, N, oldname($2));
-		yyerror("cannot parenthesize embedded type");
-	}
-
-indcl:
-	'(' oarg_type_list_ocomma ')' fnres
-	{
-		// without func keyword
-		$2 = checkarglist($2, 1);
-		$$ = nod(OTFUNC, fakethis(), N);
-		$$->list = $2;
-		$$->rlist = $4;
-	}
-
-/*
- * function arguments.
- */
-arg_type:
-	name_or_type
-|	sym name_or_type
-	{
-		$$ = nod(ONONAME, N, N);
-		$$->sym = $1;
-		$$ = nod(OKEY, $$, $2);
-	}
-|	sym dotdotdot
-	{
-		$$ = nod(ONONAME, N, N);
-		$$->sym = $1;
-		$$ = nod(OKEY, $$, $2);
-	}
-|	dotdotdot
-
-arg_type_list:
-	arg_type
-	{
-		$$ = list1($1);
-	}
-|	arg_type_list ',' arg_type
-	{
-		$$ = list($1, $3);
-	}
-
-oarg_type_list_ocomma:
-	{
-		$$ = nil;
-	}
-|	arg_type_list ocomma
-	{
-		$$ = $1;
-	}
-
-/*
- * statement
- */
-stmt:
-	{
-		$$ = N;
-	}
-|	compound_stmt
-|	common_dcl
-	{
-		$$ = liststmt($1);
-	}
-|	non_dcl_stmt
-|	error
-	{
-		$$ = N;
-	}
-
-non_dcl_stmt:
-	simple_stmt
-|	for_stmt
-|	switch_stmt
-|	select_stmt
-|	if_stmt
-|	labelname ':'
-	{
-		$1 = nod(OLABEL, $1, N);
-		$1->sym = dclstack;  // context, for goto restrictions
-	}
-	stmt
-	{
-		NodeList *l;
-
-		$1->defn = $4;
-		l = list1($1);
-		if($4)
-			l = list(l, $4);
-		$$ = liststmt(l);
-	}
-|	LFALL
-	{
-		// will be converted to OFALL
-		$$ = nod(OXFALL, N, N);
-		$$->xoffset = block;
-	}
-|	LBREAK onew_name
-	{
-		$$ = nod(OBREAK, $2, N);
-	}
-|	LCONTINUE onew_name
-	{
-		$$ = nod(OCONTINUE, $2, N);
-	}
-|	LGO pseudocall
-	{
-		$$ = nod(OPROC, $2, N);
-	}
-|	LDEFER pseudocall
-	{
-		$$ = nod(ODEFER, $2, N);
-	}
-|	LGOTO new_name
-	{
-		$$ = nod(OGOTO, $2, N);
-		$$->sym = dclstack;  // context, for goto restrictions
-	}
-|	LRETURN oexpr_list
-	{
-		$$ = nod(ORETURN, N, N);
-		$$->list = $2;
-		if($$->list == nil && curfn != N) {
-			NodeList *l;
-
-			for(l=curfn->dcl; l; l=l->next) {
-				if(l->n->class == PPARAM)
-					continue;
-				if(l->n->class != PPARAMOUT)
-					break;
-				if(l->n->sym->def != l->n)
-					yyerror("%s is shadowed during return", l->n->sym->name);
-			}
-		}
-	}
-
-stmt_list:
-	stmt
-	{
-		$$ = nil;
-		if($1 != N)
-			$$ = list1($1);
-	}
-|	stmt_list ';' stmt
-	{
-		$$ = $1;
-		if($3 != N)
-			$$ = list($$, $3);
-	}
-
-new_name_list:
-	new_name
-	{
-		$$ = list1($1);
-	}
-|	new_name_list ',' new_name
-	{
-		$$ = list($1, $3);
-	}
-
-dcl_name_list:
-	dcl_name
-	{
-		$$ = list1($1);
-	}
-|	dcl_name_list ',' dcl_name
-	{
-		$$ = list($1, $3);
-	}
-
-expr_list:
-	expr
-	{
-		$$ = list1($1);
-	}
-|	expr_list ',' expr
-	{
-		$$ = list($1, $3);
-	}
-
-expr_or_type_list:
-	expr_or_type
-	{
-		$$ = list1($1);
-	}
-|	expr_or_type_list ',' expr_or_type
-	{
-		$$ = list($1, $3);
-	}
-
-/*
- * list of combo of keyval and val
- */
-keyval_list:
-	keyval
-	{
-		$$ = list1($1);
-	}
-|	bare_complitexpr
-	{
-		$$ = list1($1);
-	}
-|	keyval_list ',' keyval
-	{
-		$$ = list($1, $3);
-	}
-|	keyval_list ',' bare_complitexpr
-	{
-		$$ = list($1, $3);
-	}
-
-braced_keyval_list:
-	{
-		$$ = nil;
-	}
-|	keyval_list ocomma
-	{
-		$$ = $1;
-	}
-
-/*
- * optional things
- */
-osemi:
-|	';'
-
-ocomma:
-|	','
-
-oexpr:
-	{
-		$$ = N;
-	}
-|	expr
-
-oexpr_list:
-	{
-		$$ = nil;
-	}
-|	expr_list
-
-osimple_stmt:
-	{
-		$$ = N;
-	}
-|	simple_stmt
-
-ohidden_funarg_list:
-	{
-		$$ = nil;
-	}
-|	hidden_funarg_list
-
-ohidden_structdcl_list:
-	{
-		$$ = nil;
-	}
-|	hidden_structdcl_list
-
-ohidden_interfacedcl_list:
-	{
-		$$ = nil;
-	}
-|	hidden_interfacedcl_list
-
-oliteral:
-	{
-		$$.ctype = CTxxx;
-	}
-|	LLITERAL
-
-/*
- * import syntax from package header
- */
-hidden_import:
-	LIMPORT LNAME LLITERAL ';'
-	{
-		importimport($2, $3.u.sval);
-	}
-|	LVAR hidden_pkg_importsym hidden_type ';'
-	{
-		importvar($2, $3);
-	}
-|	LCONST hidden_pkg_importsym '=' hidden_constant ';'
-	{
-		importconst($2, types[TIDEAL], $4);
-	}
-|	LCONST hidden_pkg_importsym hidden_type '=' hidden_constant ';'
-	{
-		importconst($2, $3, $5);
-	}
-|	LTYPE hidden_pkgtype hidden_type ';'
-	{
-		importtype($2, $3);
-	}
-|	LFUNC hidden_fndcl fnbody ';'
-	{
-		if($2 == N) {
-			dclcontext = PEXTERN;  // since we skip the funcbody below
-			break;
-		}
-
-		$2->inl = $3;
-
-		funcbody($2);
-		importlist = list(importlist, $2);
-
-		if(debug['E']) {
-			print("import [%Z] func %lN \n", importpkg->path, $2);
-			if(debug['m'] > 2 && $2->inl)
-				print("inl body:%+H\n", $2->inl);
-		}
-	}
-
-hidden_pkg_importsym:
-	hidden_importsym
-	{
-		$$ = $1;
-		structpkg = $$->pkg;
-	}
-
-hidden_pkgtype:
-	hidden_pkg_importsym
-	{
-		$$ = pkgtype($1);
-		importsym($1, OTYPE);
-	}
-
-/*
- *  importing types
- */
-
-hidden_type:
-	hidden_type_misc
-|	hidden_type_recv_chan
-|	hidden_type_func
-
-hidden_type_non_recv_chan:
-	hidden_type_misc
-|	hidden_type_func
-
-hidden_type_misc:
-	hidden_importsym
-	{
-		$$ = pkgtype($1);
-	}
-|	LNAME
-	{
-		// predefined name like uint8
-		$1 = pkglookup($1->name, builtinpkg);
-		if($1->def == N || $1->def->op != OTYPE) {
-			yyerror("%s is not a type", $1->name);
-			$$ = T;
-		} else
-			$$ = $1->def->type;
-	}
-|	'[' ']' hidden_type
-	{
-		$$ = aindex(N, $3);
-	}
-|	'[' LLITERAL ']' hidden_type
-	{
-		$$ = aindex(nodlit($2), $4);
-	}
-|	LMAP '[' hidden_type ']' hidden_type
-	{
-		$$ = maptype($3, $5);
-	}
-|	LSTRUCT '{' ohidden_structdcl_list '}'
-	{
-		$$ = tostruct($3);
-	}
-|	LINTERFACE '{' ohidden_interfacedcl_list '}'
-	{
-		$$ = tointerface($3);
-	}
-|	'*' hidden_type
-	{
-		$$ = ptrto($2);
-	}
-|	LCHAN hidden_type_non_recv_chan
-	{
-		$$ = typ(TCHAN);
-		$$->type = $2;
-		$$->chan = Cboth;
-	}
-|	LCHAN '(' hidden_type_recv_chan ')'
-	{
-		$$ = typ(TCHAN);
-		$$->type = $3;
-		$$->chan = Cboth;
-	}
-|	LCHAN LCOMM hidden_type
-	{
-		$$ = typ(TCHAN);
-		$$->type = $3;
-		$$->chan = Csend;
-	}
-
-hidden_type_recv_chan:
-	LCOMM LCHAN hidden_type
-	{
-		$$ = typ(TCHAN);
-		$$->type = $3;
-		$$->chan = Crecv;
-	}
-
-hidden_type_func:
-	LFUNC '(' ohidden_funarg_list ')' ohidden_funres
-	{
-		$$ = functype(nil, $3, $5);
-	}
-
-hidden_funarg:
-	sym hidden_type oliteral
-	{
-		$$ = nod(ODCLFIELD, N, typenod($2));
-		if($1)
-			$$->left = newname($1);
-		$$->val = $3;
-	}
-|	sym LDDD hidden_type oliteral
-	{
-		Type *t;
-	
-		t = typ(TARRAY);
-		t->bound = -1;
-		t->type = $3;
-
-		$$ = nod(ODCLFIELD, N, typenod(t));
-		if($1)
-			$$->left = newname($1);
-		$$->isddd = 1;
-		$$->val = $4;
-	}
-
-hidden_structdcl:
-	sym hidden_type oliteral
-	{
-		Sym *s;
-		Pkg *p;
-
-		if($1 != S && strcmp($1->name, "?") != 0) {
-			$$ = nod(ODCLFIELD, newname($1), typenod($2));
-			$$->val = $3;
-		} else {
-			s = $2->sym;
-			if(s == S && isptr[$2->etype])
-				s = $2->type->sym;
-			p = importpkg;
-			if($1 != S)
-				p = $1->pkg;
-			$$ = embedded(s, p);
-			$$->right = typenod($2);
-			$$->val = $3;
-		}
-	}
-
-hidden_interfacedcl:
-	sym '(' ohidden_funarg_list ')' ohidden_funres
-	{
-		$$ = nod(ODCLFIELD, newname($1), typenod(functype(fakethis(), $3, $5)));
-	}
-|	hidden_type
-	{
-		$$ = nod(ODCLFIELD, N, typenod($1));
-	}
-
-ohidden_funres:
-	{
-		$$ = nil;
-	}
-|	hidden_funres
-
-hidden_funres:
-	'(' ohidden_funarg_list ')'
-	{
-		$$ = $2;
-	}
-|	hidden_type
-	{
-		$$ = list1(nod(ODCLFIELD, N, typenod($1)));
-	}
-
-/*
- *  importing constants
- */
-
-hidden_literal:
-	LLITERAL
-	{
-		$$ = nodlit($1);
-	}
-|	'-' LLITERAL
-	{
-		$$ = nodlit($2);
-		switch($$->val.ctype){
-		case CTINT:
-		case CTRUNE:
-			mpnegfix($$->val.u.xval);
-			break;
-		case CTFLT:
-			mpnegflt($$->val.u.fval);
-			break;
-		case CTCPLX:
-			mpnegflt(&$$->val.u.cval->real);
-			mpnegflt(&$$->val.u.cval->imag);
-			break;
-		default:
-			yyerror("bad negated constant");
-		}
-	}
-|	sym
-	{
-		$$ = oldname(pkglookup($1->name, builtinpkg));
-		if($$->op != OLITERAL)
-			yyerror("bad constant %S", $$->sym);
-	}
-
-hidden_constant:
-	hidden_literal
-|	'(' hidden_literal '+' hidden_literal ')'
-	{
-		if($2->val.ctype == CTRUNE && $4->val.ctype == CTINT) {
-			$$ = $2;
-			mpaddfixfix($2->val.u.xval, $4->val.u.xval, 0);
-			break;
-		}
-		$4->val.u.cval->real = $4->val.u.cval->imag;
-		mpmovecflt(&$4->val.u.cval->imag, 0.0);
-		$$ = nodcplxlit($2->val, $4->val);
-	}
-
-hidden_import_list:
-|	hidden_import_list hidden_import
-
-hidden_funarg_list:
-	hidden_funarg
-	{
-		$$ = list1($1);
-	}
-|	hidden_funarg_list ',' hidden_funarg
-	{
-		$$ = list($1, $3);
-	}
-
-hidden_structdcl_list:
-	hidden_structdcl
-	{
-		$$ = list1($1);
-	}
-|	hidden_structdcl_list ';' hidden_structdcl
-	{
-		$$ = list($1, $3);
-	}
-
-hidden_interfacedcl_list:
-	hidden_interfacedcl
-	{
-		$$ = list1($1);
-	}
-|	hidden_interfacedcl_list ';' hidden_interfacedcl
-	{
-		$$ = list($1, $3);
-	}
-
-%%
-
-static void
-fixlbrace(int lbr)
-{
-	// If the opening brace was an LBODY,
-	// set up for another one now that we're done.
-	// See comment in lex.c about loophack.
-	if(lbr == LBODY)
-		loophack = 1;
-}
-
diff --git a/src/cmd/gc/init.c b/src/cmd/gc/init.c
deleted file mode 100644
index 918d371..0000000
--- a/src/cmd/gc/init.c
+++ /dev/null
@@ -1,195 +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 <u.h>
-#include <libc.h>
-#include "go.h"
-
-/*
- * a function named init is a special case.
- * it is called by the initialization before
- * main is run. to make it unique within a
- * package and also uncallable, the name,
- * normally "pkg.init", is altered to "pkg.init·1".
- */
-Sym*
-renameinit(void)
-{
-	static int initgen;
-
-	snprint(namebuf, sizeof(namebuf), "init·%d", ++initgen);
-	return lookup(namebuf);
-}
-
-/*
- * hand-craft the following initialization code
- *	var initdone· uint8 				(1)
- *	func init()					(2)
- *		if initdone· != 0 {			(3)
- *			if initdone· == 2		(4)
- *				return
- *			throw();			(5)
- *		}
- *		initdone· = 1;				(6)
- *		// over all matching imported symbols
- *			<pkg>.init()			(7)
- *		{ <init stmts> }			(8)
- *		init·<n>() // if any			(9)
- *		initdone· = 2;				(10)
- *		return					(11)
- *	}
- */
-static int
-anyinit(NodeList *n)
-{
-	uint32 h;
-	Sym *s;
-	NodeList *l;
-
-	// are there any interesting init statements
-	for(l=n; l; l=l->next) {
-		switch(l->n->op) {
-		case ODCLFUNC:
-		case ODCLCONST:
-		case ODCLTYPE:
-		case OEMPTY:
-			break;
-		case OAS:
-			if(isblank(l->n->left) && candiscard(l->n->right))
-				break;
-			// fall through
-		default:
-			return 1;
-		}
-	}
-
-	// is this main
-	if(strcmp(localpkg->name, "main") == 0)
-		return 1;
-
-	// is there an explicit init function
-	snprint(namebuf, sizeof(namebuf), "init·1");
-	s = lookup(namebuf);
-	if(s->def != N)
-		return 1;
-
-	// are there any imported init functions
-	for(h=0; h<NHASH; h++)
-	for(s = hash[h]; s != S; s = s->link) {
-		if(s->name[0] != 'i' || strcmp(s->name, "init") != 0)
-			continue;
-		if(s->def == N)
-			continue;
-		return 1;
-	}
-
-	// then none
-	return 0;
-}
-
-void
-fninit(NodeList *n)
-{
-	int i;
-	Node *gatevar;
-	Node *a, *b, *fn;
-	NodeList *r;
-	uint32 h;
-	Sym *s, *initsym;
-
-	if(debug['A']) {
-		// sys.go or unsafe.go during compiler build
-		return;
-	}
-
-	n = initfix(n);
-	if(!anyinit(n))
-		return;
-
-	r = nil;
-
-	// (1)
-	snprint(namebuf, sizeof(namebuf), "initdone·");
-	gatevar = newname(lookup(namebuf));
-	addvar(gatevar, types[TUINT8], PEXTERN);
-
-	// (2)
-	maxarg = 0;
-	snprint(namebuf, sizeof(namebuf), "init");
-
-	fn = nod(ODCLFUNC, N, N);
-	initsym = lookup(namebuf);
-	fn->nname = newname(initsym);
-	fn->nname->defn = fn;
-	fn->nname->ntype = nod(OTFUNC, N, N);
-	declare(fn->nname, PFUNC);
-	funchdr(fn);
-
-	// (3)
-	a = nod(OIF, N, N);
-	a->ntest = nod(ONE, gatevar, nodintconst(0));
-	r = list(r, a);
-
-	// (4)
-	b = nod(OIF, N, N);
-	b->ntest = nod(OEQ, gatevar, nodintconst(2));
-	b->nbody = list1(nod(ORETURN, N, N));
-	a->nbody = list1(b);
-
-	// (5)
-	b = syslook("throwinit", 0);
-	b = nod(OCALL, b, N);
-	a->nbody = list(a->nbody, b);
-
-	// (6)
-	a = nod(OAS, gatevar, nodintconst(1));
-	r = list(r, a);
-
-	// (7)
-	for(h=0; h<NHASH; h++)
-	for(s = hash[h]; s != S; s = s->link) {
-		if(s->name[0] != 'i' || strcmp(s->name, "init") != 0)
-			continue;
-		if(s->def == N)
-			continue;
-		if(s == initsym)
-			continue;
-
-		// could check that it is fn of no args/returns
-		a = nod(OCALL, s->def, N);
-		r = list(r, a);
-	}
-
-	// (8)
-	r = concat(r, n);
-
-	// (9)
-	// could check that it is fn of no args/returns
-	for(i=1;; i++) {
-		snprint(namebuf, sizeof(namebuf), "init·%d", i);
-		s = lookup(namebuf);
-		if(s->def == N)
-			break;
-		a = nod(OCALL, s->def, N);
-		r = list(r, a);
-	}
-
-	// (10)
-	a = nod(OAS, gatevar, nodintconst(2));
-	r = list(r, a);
-
-	// (11)
-	a = nod(ORETURN, N, N);
-	r = list(r, a);
-	exportsym(fn->nname);
-
-	fn->nbody = r;
-	funcbody(fn);
-
-	curfn = fn;
-	typecheck(&fn, Etop);
-	typechecklist(r, Etop);
-	curfn = nil;
-	funccompile(fn, 0);
-}
diff --git a/src/cmd/gc/inl.c b/src/cmd/gc/inl.c
deleted file mode 100644
index 45e15bb..0000000
--- a/src/cmd/gc/inl.c
+++ /dev/null
@@ -1,986 +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.
-//
-// The inlining facility makes 2 passes: first caninl determines which
-// functions are suitable for inlining, and for those that are it
-// saves a copy of the body. Then inlcalls walks each function body to
-// expand calls to inlinable functions.
-//
-// The debug['l'] flag controls the agressiveness. Note that main() swaps level 0 and 1,
-// making 1 the default and -l disable.  -ll and more is useful to flush out bugs.
-// These additional levels (beyond -l) may be buggy and are not supported.
-//      0: disabled
-//      1: 40-nodes leaf functions, oneliners, lazy typechecking (default)
-//      2: early typechecking of all imported bodies 
-//      3: allow variadic functions
-//      4: allow non-leaf functions , (breaks runtime.Caller)
-//      5: transitive inlining
-//
-//  At some point this may get another default and become switch-offable with -N.
-//
-//  The debug['m'] flag enables diagnostic output.  a single -m is useful for verifying
-//  which calls get inlined or not, more is for debugging, and may go away at any point.
-//
-// TODO:
-//   - inline functions with ... args
-//   - handle T.meth(f()) with func f() (t T, arg, arg, )
-
-#include <u.h>
-#include <libc.h>
-#include "go.h"
-
-// Used by caninl.
-static Node*	inlcopy(Node *n);
-static NodeList* inlcopylist(NodeList *ll);
-static int	ishairy(Node *n, int *budget);
-static int	ishairylist(NodeList *ll, int *budget); 
-
-// Used by inlcalls
-static void	inlnodelist(NodeList *l);
-static void	inlnode(Node **np);
-static void	mkinlcall(Node **np, Node *fn, int isddd);
-static Node*	inlvar(Node *n);
-static Node*	retvar(Type *n, int i);
-static Node*	argvar(Type *n, int i);
-static Node*	newlabel(void);
-static Node*	inlsubst(Node *n);
-static NodeList* inlsubstlist(NodeList *l);
-
-static void	setlno(Node*, int);
-
-// Used during inlsubst[list]
-static Node *inlfn;		// function currently being inlined
-static Node *inlretlabel;	// target of the goto substituted in place of a return
-static NodeList *inlretvars;	// temp out variables
-
-// Get the function's package.  For ordinary functions it's on the ->sym, but for imported methods
-// the ->sym can be re-used in the local package, so peel it off the receiver's type.
-static Pkg*
-fnpkg(Node *fn)
-{
-	Type *rcvr;
-	
-	if(fn->type->thistuple) {
-		// method
-		rcvr = getthisx(fn->type)->type->type;
-		if(isptr[rcvr->etype])
-			rcvr = rcvr->type;
-		if(!rcvr->sym)
-			fatal("receiver with no sym: [%S] %lN  (%T)", fn->sym, fn, rcvr);
-		return rcvr->sym->pkg;
-	}
-	// non-method
-	return fn->sym->pkg;
-}
-
-// Lazy typechecking of imported bodies.  For local functions, caninl will set ->typecheck
-// because they're a copy of an already checked body. 
-void
-typecheckinl(Node *fn)
-{
-	Node *savefn;
-	Pkg *pkg;
-	int save_safemode, lno;
-
-	lno = setlineno(fn);
-
-	// typecheckinl is only for imported functions;
-	// their bodies may refer to unsafe as long as the package
-	// was marked safe during import (which was checked then).
-	// the ->inl of a local function has been typechecked before caninl copied it.
-	pkg = fnpkg(fn);
-	if (pkg == localpkg || pkg == nil)
-		return; // typecheckinl on local function
-
-	if (debug['m']>2)
-		print("typecheck import [%S] %lN { %#H }\n", fn->sym, fn, fn->inl);
-
-	save_safemode = safemode;
-	safemode = 0;
-
-	savefn = curfn;
-	curfn = fn;
-	typechecklist(fn->inl, Etop);
-	curfn = savefn;
-
-	safemode = save_safemode;
-
-	lineno = lno;
-}
-
-// Caninl determines whether fn is inlineable.
-// If so, caninl saves fn->nbody in fn->inl and substitutes it with a copy.
-// fn and ->nbody will already have been typechecked.
-void
-caninl(Node *fn)
-{
-	Node *savefn;
-	Type *t;
-	int budget;
-
-	if(fn->op != ODCLFUNC)
-		fatal("caninl %N", fn);
-	if(!fn->nname)
-		fatal("caninl no nname %+N", fn);
-
-	// If fn has no body (is defined outside of Go), cannot inline it.
-	if(fn->nbody == nil)
-		return;
-
-	if(fn->typecheck == 0)
-		fatal("caninl on non-typechecked function %N", fn);
-
-	// can't handle ... args yet
-	if(debug['l'] < 3)
-		for(t=fn->type->type->down->down->type; t; t=t->down)
-			if(t->isddd)
-				return;
-
-	budget = 40;  // allowed hairyness
-	if(ishairylist(fn->nbody, &budget))
-		return;
-
-	savefn = curfn;
-	curfn = fn;
-
-	fn->nname->inl = fn->nbody;
-	fn->nbody = inlcopylist(fn->nname->inl);
-	fn->nname->inldcl = inlcopylist(fn->nname->defn->dcl);
-
-	// 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)
-		print("%L: can inline %#N as: %#T { %#H }\n", fn->lineno, fn->nname, fn->type, fn->nname->inl);
-	else if(debug['m'])
-		print("%L: can inline %N\n", fn->lineno, fn->nname);
-
-	curfn = savefn;
-}
-
-// Look for anything we want to punt on.
-static int
-ishairylist(NodeList *ll, int* budget)
-{
-	for(;ll;ll=ll->next)
-		if(ishairy(ll->n, budget))
-			return 1;
-	return 0;
-}
-
-static int
-ishairy(Node *n, int *budget)
-{
-	if(!n)
-		return 0;
-
-	// Things that are too hairy, irrespective of the budget
-	switch(n->op) {
-	case OCALL:
-	case OCALLFUNC:
-	case OCALLINTER:
-	case OCALLMETH:
-	case OPANIC:
-	case ORECOVER:
-		if(debug['l'] < 4)
-			return 1;
-		break;
-
-	case OCLOSURE:
-	case OCALLPART:
-	case ORANGE:
-	case OFOR:
-	case OSELECT:
-	case OSWITCH:
-	case OPROC:
-	case ODEFER:
-	case ODCLTYPE:  // can't print yet
-	case ODCLCONST:  // can't print yet
-	case ORETJMP:
-		return 1;
-
-		break;
-	}
-
-	(*budget)--;
-
-	return  *budget < 0 ||
-		ishairy(n->left, budget) ||
-		ishairy(n->right, budget) ||
-		ishairylist(n->list, budget) ||
-		ishairylist(n->rlist, budget) ||
-		ishairylist(n->ninit, budget) ||
-		ishairy(n->ntest, budget) ||
-		ishairy(n->nincr, budget) ||
-		ishairylist(n->nbody, budget) ||
-		ishairylist(n->nelse, budget);
-}
-
-// Inlcopy and inlcopylist recursively copy the body of a function.
-// Any name-like node of non-local class is marked for re-export by adding it to
-// the exportlist.
-static NodeList*
-inlcopylist(NodeList *ll)
-{
-	NodeList *l;
-
-	l = nil;
-	for(; ll; ll=ll->next)
-		l = list(l, inlcopy(ll->n));
-	return l;
-}
-
-static Node*
-inlcopy(Node *n)
-{
-	Node *m;
-
-	if(n == N)
-		return N;
-
-	switch(n->op) {
-	case ONAME:
-	case OTYPE:
-	case OLITERAL:
-		return n;
-	}
-
-	m = nod(OXXX, N, N);
-	*m = *n;
-	m->inl = nil;
-	m->left	  = inlcopy(n->left);
-	m->right  = inlcopy(n->right);
-	m->list   = inlcopylist(n->list);
-	m->rlist  = inlcopylist(n->rlist);
-	m->ninit  = inlcopylist(n->ninit);
-	m->ntest  = inlcopy(n->ntest);
-	m->nincr  = inlcopy(n->nincr);
-	m->nbody  = inlcopylist(n->nbody);
-	m->nelse  = inlcopylist(n->nelse);
-
-	return m;
-}
-
-
-// Inlcalls/nodelist/node walks fn's statements and expressions and substitutes any
-// calls made to inlineable functions.  This is the external entry point.
-void
-inlcalls(Node *fn)
-{
-	Node *savefn;
-
-	savefn = curfn;
-	curfn = fn;
-	inlnode(&fn);
-	if(fn != curfn)
-		fatal("inlnode replaced curfn");
-	curfn = savefn;
-}
-
-// Turn an OINLCALL into a statement.
-static void
-inlconv2stmt(Node *n)
-{
-	n->op = OBLOCK;
-	// n->ninit stays
-	n->list = n->nbody;
-	n->nbody = nil;
-	n->rlist = nil;
-}
-
-// Turn an OINLCALL into a single valued expression.
-static void
-inlconv2expr(Node **np)
-{
-	Node *n, *r;
-	n = *np;
-	r = n->rlist->n;
-	addinit(&r, concat(n->ninit, n->nbody));
-	*np = r;
-}
-
-// Turn the rlist (with the return values) of the OINLCALL in
-// n into an expression list lumping the ninit and body
-// containing the inlined statements on the first list element so
-// order will be preserved Used in return, oas2func and call
-// statements.
-static NodeList*
-inlconv2list(Node *n)
-{
-	NodeList *l;
-
-	if(n->op != OINLCALL || n->rlist == nil)
-		fatal("inlconv2list %+N\n", n);
-	
-	l = n->rlist;
-	addinit(&l->n, concat(n->ninit, n->nbody));
-	return l;
-} 
- 
-static void
-inlnodelist(NodeList *l)
-{
-	for(; l; l=l->next)
-		inlnode(&l->n);
-}
-
-// inlnode recurses over the tree to find inlineable calls, which will
-// be turned into OINLCALLs by mkinlcall.  When the recursion comes
-// back up will examine left, right, list, rlist, ninit, ntest, nincr,
-// nbody and nelse and use one of the 4 inlconv/glue functions above
-// to turn the OINLCALL into an expression, a statement, or patch it
-// in to this nodes list or rlist as appropriate.
-// NOTE it makes no sense to pass the glue functions down the
-// recursion to the level where the OINLCALL gets created because they
-// have to edit /this/ n, so you'd have to push that one down as well,
-// but then you may as well do it here.  so this is cleaner and
-// shorter and less complicated.
-static void
-inlnode(Node **np)
-{
-	Node *n;
-	NodeList *l;
-	int lno;
-
-	if(*np == nil)
-		return;
-
-	n = *np;
-	
-	switch(n->op) {
-	case ODEFER:
-	case OPROC:
-		// inhibit inlining of their argument
-		switch(n->left->op) {
-		case OCALLFUNC:
-		case OCALLMETH:
-			n->left->etype = n->op;
-		}
-
-	case OCLOSURE:
-		// TODO do them here (or earlier),
-		// so escape analysis can avoid more heapmoves.
-		return;
-	}
-
-	lno = setlineno(n);
-
-	inlnodelist(n->ninit);
-	for(l=n->ninit; l; l=l->next)
-		if(l->n->op == OINLCALL)
-			inlconv2stmt(l->n);
-
-	inlnode(&n->left);
-	if(n->left && n->left->op == OINLCALL)
-		inlconv2expr(&n->left);
-
-	inlnode(&n->right);
-	if(n->right && n->right->op == OINLCALL)
-		inlconv2expr(&n->right);
-
-	inlnodelist(n->list);
-	switch(n->op) {
-	case OBLOCK:
-		for(l=n->list; l; l=l->next)
-			if(l->n->op == OINLCALL)
-				inlconv2stmt(l->n);
-		break;
-
-	case ORETURN:
-	case OCALLFUNC:
-	case OCALLMETH:
-	case OCALLINTER:
-	case OAPPEND:
-	case OCOMPLEX:
-		// if we just replaced arg in f(arg()) or return arg with an inlined call
-		// and arg returns multiple values, glue as list
-		if(count(n->list) == 1 && n->list->n->op == OINLCALL && count(n->list->n->rlist) > 1) {
-			n->list = inlconv2list(n->list->n);
-			break;
-		}
-
-		// fallthrough
-	default:
-		for(l=n->list; l; l=l->next)
-			if(l->n->op == OINLCALL)
-				inlconv2expr(&l->n);
-	}
-
-	inlnodelist(n->rlist);
-	switch(n->op) {
-	case OAS2FUNC:
-		if(n->rlist->n->op == OINLCALL) {
-			n->rlist = inlconv2list(n->rlist->n);
-			n->op = OAS2;
-			n->typecheck = 0;
-			typecheck(np, Etop);
-			break;
-		}
-
-		// fallthrough
-	default:
-		for(l=n->rlist; l; l=l->next)
-			if(l->n->op == OINLCALL)
-				inlconv2expr(&l->n);
-
-	}
-
-	inlnode(&n->ntest);
-	if(n->ntest && n->ntest->op == OINLCALL)
-		inlconv2expr(&n->ntest);
-
-	inlnode(&n->nincr);
-	if(n->nincr && n->nincr->op == OINLCALL)
-		inlconv2stmt(n->nincr);
-
-	inlnodelist(n->nbody);
-	for(l=n->nbody; l; l=l->next)
-		if(l->n->op == OINLCALL)
-			inlconv2stmt(l->n);
-
-	inlnodelist(n->nelse);
-	for(l=n->nelse; l; l=l->next)
-		if(l->n->op == OINLCALL)
-			inlconv2stmt(l->n);
-
-	// with all the branches out of the way, it is now time to
-	// transmogrify this node itself unless inhibited by the
-	// switch at the top of this function.
-	switch(n->op) {
-	case OCALLFUNC:
-	case OCALLMETH:
-		if (n->etype == OPROC || n->etype == ODEFER)
-			return;
-	}
-
-	switch(n->op) {
-	case OCALLFUNC:
-		if(debug['m']>3)
-			print("%L:call to func %+N\n", n->lineno, n->left);
-		if(n->left->inl)	// normal case
-			mkinlcall(np, n->left, n->isddd);
-		else if(n->left->op == ONAME && n->left->left && n->left->left->op == OTYPE && n->left->right &&  n->left->right->op == ONAME)  // methods called as functions
-			if(n->left->sym->def)
-				mkinlcall(np, n->left->sym->def, n->isddd);
-		break;
-
-	case OCALLMETH:
-		if(debug['m']>3)
-			print("%L:call to meth %lN\n", n->lineno, n->left->right);
-		// typecheck should have resolved ODOTMETH->type, whose nname points to the actual function.
-		if(n->left->type == T) 
-			fatal("no function type for [%p] %+N\n", n->left, n->left);
-
-		if(n->left->type->nname == N) 
-			fatal("no function definition for [%p] %+T\n", n->left->type, n->left->type);
-
-		mkinlcall(np, n->left->type->nname, n->isddd);
-
-		break;
-	}
-	
-	lineno = lno;
-}
-
-static void	mkinlcall1(Node **np, Node *fn, int isddd);
-
-static void
-mkinlcall(Node **np, Node *fn, int isddd)
-{
-	int save_safemode;
-	Pkg *pkg;
-
-	save_safemode = safemode;
-
-	// imported functions may refer to unsafe as long as the
-	// package was marked safe during import (already checked).
-	pkg = fnpkg(fn);
-	if(pkg != localpkg && pkg != nil)
-		safemode = 0;
-	mkinlcall1(np, fn, isddd);
-	safemode = save_safemode;
-}
-
-static Node*
-tinlvar(Type *t)
-{
-	if(t->nname && !isblank(t->nname)) {
-		if(!t->nname->inlvar)
-			fatal("missing inlvar for %N\n", t->nname);
-		return t->nname->inlvar;
-	}
-	typecheck(&nblank, Erv | Easgn);
-	return nblank;
-}
-
-static int inlgen;
-
-// if *np is a call, and fn is a function with an inlinable body, substitute *np with an OINLCALL.
-// On return ninit has the parameter assignments, the nbody is the
-// inlined function body and list, rlist contain the input, output
-// parameters.
-static void
-mkinlcall1(Node **np, Node *fn, int isddd)
-{
-	int i;
-	int chkargcount;
-	Node *n, *call, *saveinlfn, *as, *m;
-	NodeList *dcl, *ll, *ninit, *body;
-	Type *t;
-	// For variadic fn.
-	int variadic, varargcount, multiret;
-	Node *vararg;
-	NodeList *varargs;
-	Type *varargtype, *vararrtype;
-
-	if (fn->inl == nil)
-		return;
-
-	if (fn == curfn || fn->defn == curfn)
-		return;
-
-	if(debug['l']<2)
-		typecheckinl(fn);
-
-	n = *np;
-
-	// Bingo, we have a function node, and it has an inlineable body
-	if(debug['m']>1)
-		print("%L: inlining call to %S %#T { %#H }\n", n->lineno, fn->sym, fn->type, fn->inl);
-	else if(debug['m'])
-		print("%L: inlining call to %N\n", n->lineno, fn);
-
-	if(debug['m']>2)
-		print("%L: Before inlining: %+N\n", n->lineno, n);
-
-	saveinlfn = inlfn;
-	inlfn = fn;
-
-	ninit = n->ninit;
-
-//dumplist("ninit pre", ninit);
-
-	if(fn->defn) // local function
-		dcl = fn->inldcl;
-	else // imported function
-		dcl = fn->dcl;
-
-	inlretvars = nil;
-	i = 0;
-	// Make temp names to use instead of the originals
-	for(ll = dcl; ll; ll=ll->next) {
-		if(ll->n->class == PPARAMOUT)  // return values handled below.
-			continue;
-		if(ll->n->op == ONAME) {
-			ll->n->inlvar = inlvar(ll->n);
-			// Typecheck because inlvar is not necessarily a function parameter.
-			typecheck(&ll->n->inlvar, Erv);
-			if ((ll->n->class&~PHEAP) != PAUTO)
-				ninit = list(ninit, nod(ODCL, ll->n->inlvar, N));  // otherwise gen won't emit the allocations for heapallocs
-		}
-	}
-
-	// temporaries for return values.
-	for(t = getoutargx(fn->type)->type; t; t = t->down) {
-		if(t != T && t->nname != N && !isblank(t->nname)) {
-			m = inlvar(t->nname);
-			typecheck(&m, Erv);
-			t->nname->inlvar = m;
-		} else {
-			// anonymous return values, synthesize names for use in assignment that replaces return
-			m = retvar(t, i++);
-		}
-		ninit = list(ninit, nod(ODCL, m, N));
-		inlretvars = list(inlretvars, m);
-	}
-
-	// assign receiver.
-	if(fn->type->thistuple && n->left->op == ODOTMETH) {
-		// method call with a receiver.
-		t = getthisx(fn->type)->type;
-		if(t != T && t->nname != N && !isblank(t->nname) && !t->nname->inlvar)
-			fatal("missing inlvar for %N\n", t->nname);
-		if(!n->left->left)
-			fatal("method call without receiver: %+N", n);
-		if(t == T)
-			fatal("method call unknown receiver type: %+N", n);
-		as = nod(OAS, tinlvar(t), n->left->left);
-		if(as != N) {
-			typecheck(&as, Etop);
-			ninit = list(ninit, as);
-		}
-	}
-
-	// check if inlined function is variadic.
-	variadic = 0;
-	varargtype = T;
-	varargcount = 0;
-	for(t=fn->type->type->down->down->type; t; t=t->down) {
-		if(t->isddd) {
-			variadic = 1;
-			varargtype = t->type;
-		}
-	}
-	// but if argument is dotted too forget about variadicity.
-	if(variadic && isddd)
-		variadic = 0;
-
-	// check if argument is actually a returned tuple from call.
-	multiret = 0;
-	if(n->list && !n->list->next) {
-		switch(n->list->n->op) {
-		case OCALL:
-		case OCALLFUNC:
-		case OCALLINTER:
-		case OCALLMETH:
-			if(n->list->n->left->type->outtuple > 1)
-				multiret = n->list->n->left->type->outtuple-1;
-		}
-	}
-
-	if(variadic) {
-		varargcount = count(n->list) + multiret;
-		if(n->left->op != ODOTMETH)
-			varargcount -= fn->type->thistuple;
-		varargcount -= fn->type->intuple - 1;
-	}
-
-	// assign arguments to the parameters' temp names
-	as = nod(OAS2, N, N);
-	as->rlist = n->list;
-	ll = n->list;
-
-	// TODO: if len(nlist) == 1 but multiple args, check that n->list->n is a call?
-	if(fn->type->thistuple && n->left->op != ODOTMETH) {
-		// non-method call to method
-		if(!n->list)
-			fatal("non-method call to method without first arg: %+N", n);
-		// append receiver inlvar to LHS.
-		t = getthisx(fn->type)->type;
-		if(t != T && t->nname != N && !isblank(t->nname) && !t->nname->inlvar)
-			fatal("missing inlvar for %N\n", t->nname);
-		if(t == T)
-			fatal("method call unknown receiver type: %+N", n);
-		as->list = list(as->list, tinlvar(t));
-		ll = ll->next; // track argument count.
-	}
-
-	// append ordinary arguments to LHS.
-	chkargcount = n->list && n->list->next;
-	vararg = N;    // the slice argument to a variadic call
-	varargs = nil; // the list of LHS names to put in vararg.
-	if(!chkargcount) {
-		// 0 or 1 expression on RHS.
-		for(t = getinargx(fn->type)->type; t; t=t->down) {
-			if(variadic && t->isddd) {
-				vararg = tinlvar(t);
-				for(i=0; i<varargcount && ll; i++) {
-					m = argvar(varargtype, i);
-					varargs = list(varargs, m);
-					as->list = list(as->list, m);
-				}
-				break;
-			}
-			as->list = list(as->list, tinlvar(t));
-		}
-	} else {
-		// match arguments except final variadic (unless the call is dotted itself)
-		for(t = getinargx(fn->type)->type; t;) {
-			if(!ll)
-				break;
-			if(variadic && t->isddd)
-				break;
-			as->list = list(as->list, tinlvar(t));
-			t=t->down;
-			ll=ll->next;
-		}
-		// match varargcount arguments with variadic parameters.
-		if(variadic && t && t->isddd) {
-			vararg = tinlvar(t);
-			for(i=0; i<varargcount && ll; i++) {
-				m = argvar(varargtype, i);
-				varargs = list(varargs, m);
-				as->list = list(as->list, m);
-				ll=ll->next;
-			}
-			if(i==varargcount)
-				t=t->down;
-		}
-		if(ll || t)
-			fatal("arg count mismatch: %#T  vs %,H\n",  getinargx(fn->type), n->list);
-	}
-
-	if (as->rlist) {
-		typecheck(&as, Etop);
-		ninit = list(ninit, as);
-	}
-
-	// turn the variadic args into a slice.
-	if(variadic) {
-		as = nod(OAS, vararg, N);
-		if(!varargcount) {
-			as->right = nodnil();
-			as->right->type = varargtype;
-		} else {
-			vararrtype = typ(TARRAY);
-			vararrtype->type = varargtype->type;
-			vararrtype->bound = varargcount;
-
-			as->right = nod(OCOMPLIT, N, typenod(varargtype));
-			as->right->list = varargs;
-			as->right = nod(OSLICE, as->right, nod(OKEY, N, N));
-		}
-		typecheck(&as, Etop);
-		ninit = list(ninit, as);
-	}
-
-	// zero the outparams
-	for(ll = inlretvars; ll; ll=ll->next) {
-		as = nod(OAS, ll->n, N);
-		typecheck(&as, Etop);
-		ninit = list(ninit, as);
-	}
-
-	inlretlabel = newlabel();
-	inlgen++;
-	body = inlsubstlist(fn->inl);
-
-	body = list(body, nod(OGOTO, inlretlabel, N));	// avoid 'not used' when function doesnt have return
-	body = list(body, nod(OLABEL, inlretlabel, N));
-
-	typechecklist(body, Etop);
-//dumplist("ninit post", ninit);
-
-	call = nod(OINLCALL, N, N);
-	call->ninit = ninit;
-	call->nbody = body;
-	call->rlist = inlretvars;
-	call->type = n->type;
-	call->typecheck = 1;
-
-	setlno(call, n->lineno);
-//dumplist("call body", body);
-
-	*np = call;
-
-	inlfn =	saveinlfn;
-
-	// transitive inlining
-	// TODO do this pre-expansion on fn->inl directly.  requires
-	// either supporting exporting statemetns with complex ninits
-	// or saving inl and making inlinl
-	if(debug['l'] >= 5) {
-		body = fn->inl;
-		fn->inl = nil;	// prevent infinite recursion
-		inlnodelist(call->nbody);
-		for(ll=call->nbody; ll; ll=ll->next)
-			if(ll->n->op == OINLCALL)
-				inlconv2stmt(ll->n);
-		fn->inl = body;
-	}
-
-	if(debug['m']>2)
-		print("%L: After inlining %+N\n\n", n->lineno, *np);
-
-}
-
-// Every time we expand a function we generate a new set of tmpnames,
-// PAUTO's in the calling functions, and link them off of the
-// PPARAM's, PAUTOS and PPARAMOUTs of the called function. 
-static Node*
-inlvar(Node *var)
-{
-	Node *n;
-
-	if(debug['m']>3)
-		print("inlvar %+N\n", var);
-
-	n = newname(var->sym);
-	n->type = var->type;
-	n->class = PAUTO;
-	n->used = 1;
-	n->curfn = curfn;   // the calling function, not the called one
-	n->addrtaken = var->addrtaken;
-
-	// Esc pass wont run if we're inlining into a iface wrapper.
-	// Luckily, we can steal the results from the target func.
-	// If inlining a function defined in another package after
-	// escape analysis is done, treat all local vars as escaping.
-	// See issue 9537.
-	if(var->esc == EscHeap || (inl_nonlocal && var->op == ONAME))
-		addrescapes(n);
-
-	curfn->dcl = list(curfn->dcl, n);
-	return n;
-}
-
-// Synthesize a variable to store the inlined function's results in.
-static Node*
-retvar(Type *t, int i)
-{
-	Node *n;
-
-	snprint(namebuf, sizeof(namebuf), "~r%d", i);
-	n = newname(lookup(namebuf));
-	n->type = t->type;
-	n->class = PAUTO;
-	n->used = 1;
-	n->curfn = curfn;   // the calling function, not the called one
-	curfn->dcl = list(curfn->dcl, n);
-	return n;
-}
-
-// Synthesize a variable to store the inlined function's arguments
-// when they come from a multiple return call.
-static Node*
-argvar(Type *t, int i)
-{
-	Node *n;
-
-	snprint(namebuf, sizeof(namebuf), "~arg%d", i);
-	n = newname(lookup(namebuf));
-	n->type = t->type;
-	n->class = PAUTO;
-	n->used = 1;
-	n->curfn = curfn;   // the calling function, not the called one
-	curfn->dcl = list(curfn->dcl, n);
-	return n;
-}
-
-static Node*
-newlabel(void)
-{
-	Node *n;
-	static int label;
-	
-	label++;
-	snprint(namebuf, sizeof(namebuf), ".inlret%.6d", label);
-	n = newname(lookup(namebuf));
-	n->etype = 1;  // flag 'safe' for escape analysis (no backjumps)
-	return n;
-}
-
-// inlsubst and inlsubstlist recursively copy the body of the saved
-// pristine ->inl body of the function while substituting references
-// to input/output parameters with ones to the tmpnames, and
-// substituting returns with assignments to the output.
-static NodeList*
-inlsubstlist(NodeList *ll)
-{
-	NodeList *l;
-
-	l = nil;
-	for(; ll; ll=ll->next)
-		l = list(l, inlsubst(ll->n));
-	return l;
-}
-
-static Node*
-inlsubst(Node *n)
-{
-	char *p;
-	Node *m, *as;
-	NodeList *ll;
-
-	if(n == N)
-		return N;
-
-	switch(n->op) {
-	case ONAME:
-		if(n->inlvar) { // These will be set during inlnode
-			if (debug['m']>2)
-				print ("substituting name %+N  ->  %+N\n", n, n->inlvar);
-			return n->inlvar;
-		}
-		if (debug['m']>2)
-			print ("not substituting name %+N\n", n);
-		return n;
-
-	case OLITERAL:
-	case OTYPE:
-		return n;
-
-	case ORETURN:
-		// Since we don't handle bodies with closures, this return is guaranteed to belong to the current inlined function.
-
-//		dump("Return before substitution", n);
-		m = nod(OGOTO, inlretlabel, N);
-		m->ninit  = inlsubstlist(n->ninit);
-
-		if(inlretvars && n->list) {
-			as = nod(OAS2, N, N);
-			// shallow copy or OINLCALL->rlist will be the same list, and later walk and typecheck may clobber that.
-			for(ll=inlretvars; ll; ll=ll->next)
-				as->list = list(as->list, ll->n);
-			as->rlist = inlsubstlist(n->list);
-			typecheck(&as, Etop);
-			m->ninit = list(m->ninit, as);
-		}
-
-		typechecklist(m->ninit, Etop);
-		typecheck(&m, Etop);
-//		dump("Return after substitution", m);
-		return m;
-	
-	case OGOTO:
-	case OLABEL:
-		m = nod(OXXX, N, N);
-		*m = *n;
-		m->ninit = nil;
-		p = smprint("%s·%d", n->left->sym->name, inlgen);	
-		m->left = newname(lookup(p));
-		free(p);
-		return m;	
-	}
-
-
-	m = nod(OXXX, N, N);
-	*m = *n;
-	m->ninit = nil;
-	
-	if(n->op == OCLOSURE)
-		fatal("cannot inline function containing closure: %+N", n);
-
-	m->left	  = inlsubst(n->left);
-	m->right  = inlsubst(n->right);
-	m->list	  = inlsubstlist(n->list);
-	m->rlist  = inlsubstlist(n->rlist);
-	m->ninit  = concat(m->ninit, inlsubstlist(n->ninit));
-	m->ntest  = inlsubst(n->ntest);
-	m->nincr  = inlsubst(n->nincr);
-	m->nbody  = inlsubstlist(n->nbody);
-	m->nelse  = inlsubstlist(n->nelse);
-
-	return m;
-}
-
-// Plaster over linenumbers
-static void
-setlnolist(NodeList *ll, int lno)
-{
-	for(;ll;ll=ll->next)
-		setlno(ll->n, lno);
-}
-
-static void
-setlno(Node *n, int lno)
-{
-	if(!n)
-		return;
-
-	// don't clobber names, unless they're freshly synthesized
-	if(n->op != ONAME || n->lineno == 0)
-		n->lineno = lno;
-	
-	setlno(n->left, lno);
-	setlno(n->right, lno);
-	setlnolist(n->list, lno);
-	setlnolist(n->rlist, lno);
-	setlnolist(n->ninit, lno);
-	setlno(n->ntest, lno);
-	setlno(n->nincr, lno);
-	setlnolist(n->nbody, lno);
-	setlnolist(n->nelse, lno);
-}
diff --git a/src/cmd/gc/lex.c b/src/cmd/gc/lex.c
deleted file mode 100644
index 523ba37..0000000
--- a/src/cmd/gc/lex.c
+++ /dev/null
@@ -1,2414 +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	<u.h>
-#include	<libc.h>
-#include	"go.h"
-#include	"y.tab.h"
-#include	<ar.h>
-
-#undef	getc
-#undef	ungetc
-#define	getc	ccgetc
-#define	ungetc	ccungetc
-
-extern int yychar;
-int yyprev;
-int yylast;
-
-static void	lexinit(void);
-static void	lexinit1(void);
-static void	lexfini(void);
-static void	yytinit(void);
-static int	getc(void);
-static void	ungetc(int);
-static int32	getr(void);
-static int	escchar(int, int*, vlong*);
-static void	addidir(char*);
-static int	getlinepragma(void);
-static char *goos, *goarch, *goroot;
-
-#define	BOM	0xFEFF
-
-// Compiler experiments.
-// These are controlled by the GOEXPERIMENT environment
-// variable recorded when the compiler is built.
-static struct {
-	char *name;
-	int *val;
-} exper[] = {
-//	{"rune32", &rune32},
-	{"fieldtrack", &fieldtrack_enabled},
-	{"precisestack", &precisestack_enabled},
-	{nil, nil},
-};
-
-// Debug arguments.
-// These can be specified with the -d flag, as in "-d nil"
-// to set the debug_checknil variable. In general the list passed
-// to -d can be comma-separated.
-static struct {
-	char *name;
-	int *val;
-} debugtab[] = {
-	{"nil", &debug_checknil},
-	{nil, nil},
-};
-
-static void
-addexp(char *s)
-{
-	int i;
-
-	for(i=0; exper[i].name != nil; i++) {
-		if(strcmp(exper[i].name, s) == 0) {
-			*exper[i].val = 1;
-			return;
-		}
-	}
-	
-	print("unknown experiment %s\n", s);
-	exits("unknown experiment");
-}
-
-static void
-setexp(void)
-{
-	char *f[20];
-	int i, nf;
-
-	precisestack_enabled = 1; // on by default
-
-	// cmd/dist #defines GOEXPERIMENT for us.
-	nf = getfields(GOEXPERIMENT, f, nelem(f), 1, ",");
-	for(i=0; i<nf; i++)
-		addexp(f[i]);
-}
-
-char*
-expstring(void)
-{
-	int i;
-	static char buf[512];
-
-	strcpy(buf, "X");
-	for(i=0; exper[i].name != nil; i++)
-		if(*exper[i].val)
-			seprint(buf+strlen(buf), buf+sizeof buf, ",%s", exper[i].name);
-	if(strlen(buf) == 1)
-		strcpy(buf, "X,none");
-	buf[1] = ':';
-	return buf;
-}
-
-// Our own isdigit, isspace, isalpha, isalnum that take care 
-// of EOF and other out of range arguments.
-static int
-yy_isdigit(int c)
-{
-	return c >= 0 && c <= 0xFF && isdigit(c);
-}
-
-static int
-yy_isspace(int c)
-{
-	return c == ' ' || c == '\t' || c == '\n' || c == '\r';
-}
-
-static int
-yy_isalpha(int c)
-{
-	return c >= 0 && c <= 0xFF && isalpha(c);
-}
-
-static int
-yy_isalnum(int c)
-{
-	return c >= 0 && c <= 0xFF && isalnum(c);
-}
-
-// Disallow use of isdigit etc.
-#undef isdigit
-#undef isspace
-#undef isalpha
-#undef isalnum
-#define isdigit use_yy_isdigit_instead_of_isdigit
-#define isspace use_yy_isspace_instead_of_isspace
-#define isalpha use_yy_isalpha_instead_of_isalpha
-#define isalnum use_yy_isalnum_instead_of_isalnum
-
-#define	DBG	if(!debug['x']){}else print
-/*c2go void DBG(char*, ...); */
-
-enum
-{
-	EOF		= -1,
-};
-
-void
-usage(void)
-{
-	print("usage: %cg [options] file.go...\n", thechar);
-	flagprint(1);
-	exits("usage");
-}
-
-void
-fault(int s)
-{
-	USED(s);
-
-	// If we've already complained about things
-	// in the program, don't bother complaining
-	// about the seg fault too; let the user clean up
-	// the code and try again.
-	if(nsavederrors + nerrors > 0)
-		errorexit();
-	fatal("fault");
-}
-
-#ifdef	PLAN9
-void
-catcher(void *v, char *s)
-{
-	USED(v);
-
-	if(strncmp(s, "sys: trap: fault read", 21) == 0) {
-		if(nsavederrors + nerrors > 0)
-			errorexit();
-		fatal("fault");
-	}
-	noted(NDFLT);
-}
-#endif
-
-void
-doversion(void)
-{
-	char *p;
-
-	p = expstring();
-	if(strcmp(p, "X:none") == 0)
-		p = "";
-	print("%cg version %s%s%s\n", thechar, getgoversion(), *p ? " " : "", p);
-	exits(0);
-}
-
-int
-main(int argc, char *argv[])
-{
-	int i;
-	NodeList *l;
-	char *p;
-
-#ifdef	SIGBUS	
-	signal(SIGBUS, fault);
-	signal(SIGSEGV, fault);
-#endif
-
-#ifdef	PLAN9
-	notify(catcher);
-	// Tell the FPU to handle all exceptions.
-	setfcr(FPPDBL|FPRNR);
-#endif
-	// Allow GOARCH=thestring or GOARCH=thestringsuffix,
-	// but not other values.	
-	p = getgoarch();
-	if(strncmp(p, thestring, strlen(thestring)) != 0)
-		sysfatal("cannot use %cg with GOARCH=%s", thechar, p);
-	goarch = p;
-
-	linkarchinit();
-	ctxt = linknew(thelinkarch);
-	ctxt->diag = yyerror;
-	ctxt->bso = &bstdout;
-	Binit(&bstdout, 1, OWRITE);
-
-	localpkg = mkpkg(strlit(""));
-	localpkg->prefix = "\"\"";
-	
-	// pseudo-package, for scoping
-	builtinpkg = mkpkg(strlit("go.builtin"));
-
-	// pseudo-package, accessed by import "unsafe"
-	unsafepkg = mkpkg(strlit("unsafe"));
-	unsafepkg->name = "unsafe";
-
-	// real package, referred to by generated runtime calls
-	runtimepkg = mkpkg(strlit("runtime"));
-	runtimepkg->name = "runtime";
-
-	// pseudo-packages used in symbol tables
-	gostringpkg = mkpkg(strlit("go.string"));
-	gostringpkg->name = "go.string";
-	gostringpkg->prefix = "go.string";	// not go%2estring
-
-	itabpkg = mkpkg(strlit("go.itab"));
-	itabpkg->name = "go.itab";
-	itabpkg->prefix = "go.itab";	// not go%2eitab
-
-	weaktypepkg = mkpkg(strlit("go.weak.type"));
-	weaktypepkg->name = "go.weak.type";
-	weaktypepkg->prefix = "go.weak.type";  // not go%2eweak%2etype
-	
-	typelinkpkg = mkpkg(strlit("go.typelink"));
-	typelinkpkg->name = "go.typelink";
-	typelinkpkg->prefix = "go.typelink"; // not go%2etypelink
-
-	trackpkg = mkpkg(strlit("go.track"));
-	trackpkg->name = "go.track";
-	trackpkg->prefix = "go.track";  // not go%2etrack
-
-	typepkg = mkpkg(strlit("type"));
-	typepkg->name = "type";
-
-	goroot = getgoroot();
-	goos = getgoos();
-
-	nacl = strcmp(goos, "nacl") == 0;
-	if(nacl)
-		flag_largemodel = 1;
-
-	setexp();
-
-	outfile = nil;
-	flagcount("+", "compiling runtime", &compiling_runtime);
-	flagcount("%", "debug non-static initializers", &debug['%']);
-	flagcount("A", "for bootstrapping, allow 'any' type", &debug['A']);
-	flagcount("B", "disable bounds checking", &debug['B']);
-	flagstr("D", "path: set relative path for local imports", &localimport);
-	flagcount("E", "debug symbol export", &debug['E']);
-	flagfn1("I", "dir: add dir to import search path", addidir);
-	flagcount("K", "debug missing line numbers", &debug['K']);
-	flagcount("L", "use full (long) path in error messages", &debug['L']);
-	flagcount("M", "debug move generation", &debug['M']);
-	flagcount("N", "disable optimizations", &debug['N']);
-	flagcount("P", "debug peephole optimizer", &debug['P']);
-	flagcount("R", "debug register optimizer", &debug['R']);
-	flagcount("S", "print assembly listing", &debug['S']);
-	flagfn0("V", "print compiler version", doversion);
-	flagcount("W", "debug parse tree after type checking", &debug['W']);
-	flagcount("complete", "compiling complete package (no C or assembly)", &pure_go);
-	flagstr("d", "list: print debug information about items in list", &debugstr);
-	flagcount("e", "no limit on number of errors reported", &debug['e']);
-	flagcount("f", "debug stack frames", &debug['f']);
-	flagcount("g", "debug code generation", &debug['g']);
-	flagcount("h", "halt on error", &debug['h']);
-	flagcount("i", "debug line number stack", &debug['i']);
-	flagstr("installsuffix", "pkg directory suffix", &flag_installsuffix);
-	flagcount("j", "debug runtime-initialized variables", &debug['j']);
-	flagcount("l", "disable inlining", &debug['l']);
-	flagcount("live", "debug liveness analysis", &debuglive);
-	flagcount("m", "print optimization decisions", &debug['m']);
-	flagcount("nolocalimports", "reject local (relative) imports", &nolocalimports);
-	flagstr("o", "obj: set output file", &outfile);
-	flagstr("p", "path: set expected package import path", &myimportpath);
-	flagcount("pack", "write package file instead of object file", &writearchive);
-	flagcount("r", "debug generated wrappers", &debug['r']);
-	flagcount("race", "enable race detector", &flag_race);
-	flagcount("s", "warn about composite literals that can be simplified", &debug['s']);
-	flagstr("trimpath", "prefix: remove prefix from recorded source file paths", &ctxt->trimpath);
-	flagcount("u", "reject unsafe code", &safemode);
-	flagcount("v", "increase debug verbosity", &debug['v']);
-	flagcount("w", "debug type checking", &debug['w']);
-	use_writebarrier = 1;
-	flagcount("wb", "enable write barrier", &use_writebarrier);
-	flagcount("x", "debug lexer", &debug['x']);
-	flagcount("y", "debug declarations in canned imports (with -d)", &debug['y']);
-	if(thechar == '6')
-		flagcount("largemodel", "generate code that assumes a large memory model", &flag_largemodel);
-
-	flagparse(&argc, &argv, usage);
-	ctxt->debugasm = debug['S'];
-	ctxt->debugvlog = debug['v'];
-
-	if(argc < 1)
-		usage();
-
-	if(flag_race) {
-		racepkg = mkpkg(strlit("runtime/race"));
-		racepkg->name = "race";
-	}
-	
-	// parse -d argument
-	if(debugstr) {
-		char *f[100];
-		int i, j, nf;
-		
-		nf = getfields(debugstr, f, nelem(f), 1, ",");
-		for(i=0; i<nf; i++) {
-			for(j=0; debugtab[j].name != nil; j++) {
-				if(strcmp(debugtab[j].name, f[i]) == 0) {
-					*debugtab[j].val = 1;
-					break;
-				}
-			}
-			if(debugtab[j].name == nil)
-				sysfatal("unknown debug information -d '%s'\n", f[i]);
-		}
-	}
-
-	// enable inlining.  for now:
-	//	default: inlining on.  (debug['l'] == 1)
-	//	-l: inlining off  (debug['l'] == 0)
-	//	-ll, -lll: inlining on again, with extra debugging (debug['l'] > 1)
-	if(debug['l'] <= 1)
-		debug['l'] = 1 - debug['l'];
-
-	if(thechar == '8') {
-		p = getgo386();
-		if(strcmp(p, "387") == 0)
-			use_sse = 0;
-		else if(strcmp(p, "sse2") == 0)
-			use_sse = 1;
-		else
-			sysfatal("unsupported setting GO386=%s", p);
-	}
-
-	fmtinstallgo();
-	betypeinit();
-	if(widthptr == 0)
-		fatal("betypeinit failed");
-
-	lexinit();
-	typeinit();
-	lexinit1();
-	yytinit();
-
-	blockgen = 1;
-	dclcontext = PEXTERN;
-	nerrors = 0;
-	lexlineno = 1;
-
-	for(i=0; i<argc; i++) {
-		infile = argv[i];
-		linehist(infile, 0, 0);
-
-		curio.infile = infile;
-		curio.bin = Bopen(infile, OREAD);
-		if(curio.bin == nil) {
-			print("open %s: %r\n", infile);
-			errorexit();
-		}
-		curio.peekc = 0;
-		curio.peekc1 = 0;
-		curio.nlsemi = 0;
-		curio.eofnl = 0;
-		curio.last = 0;
-
-		// Skip initial BOM if present.
-		if(Bgetrune(curio.bin) != BOM)
-			Bungetrune(curio.bin);
-
-		block = 1;
-		iota = -1000000;
-
-		yyparse();
-		if(nsyntaxerrors != 0)
-			errorexit();
-
-		linehist(nil, 0, 0);
-		if(curio.bin != nil)
-			Bterm(curio.bin);
-	}
-	testdclstack();
-	mkpackage(localpkg->name);	// final import not used checks
-	lexfini();
-
-	typecheckok = 1;
-	if(debug['f'])
-		frame(1);
-
-	// Process top-level declarations in phases.
-
-	// Phase 1: const, type, and names and types of funcs.
-	//   This will gather all the information about types
-	//   and methods but doesn't depend on any of it.
-	defercheckwidth();
-	for(l=xtop; l; l=l->next)
-		if(l->n->op != ODCL && l->n->op != OAS)
-			typecheck(&l->n, Etop);
-
-	// Phase 2: Variable assignments.
-	//   To check interface assignments, depends on phase 1.
-	for(l=xtop; l; l=l->next)
-		if(l->n->op == ODCL || l->n->op == OAS)
-			typecheck(&l->n, Etop);
-	resumecheckwidth();
-
-	// Phase 3: Type check function bodies.
-	for(l=xtop; l; l=l->next) {
-		if(l->n->op == ODCLFUNC || l->n->op == OCLOSURE) {
-			curfn = l->n;
-			saveerrors();
-			typechecklist(l->n->nbody, Etop);
-			checkreturn(l->n);
-			if(nerrors != 0)
-				l->n->nbody = nil;  // type errors; do not compile
-		}
-	}
-
-	curfn = nil;
-	
-	if(nsavederrors+nerrors)
-		errorexit();
-
-	// Phase 4: Inlining
-	if(debug['l'] > 1) {
-		// Typecheck imported function bodies if debug['l'] > 1,
-		// otherwise lazily when used or re-exported.
-		for(l=importlist; l; l=l->next)
-			if (l->n->inl) {
-				saveerrors();
-				typecheckinl(l->n);
-			}
-		
-		if(nsavederrors+nerrors)
-			errorexit();
-	}
-
-	if(debug['l']) {
-		// Find functions that can be inlined and clone them before walk expands them.
-		for(l=xtop; l; l=l->next)
-			if(l->n->op == ODCLFUNC)
-				caninl(l->n);
-		
-		// Expand inlineable calls in all functions
-		for(l=xtop; l; l=l->next)
-			if(l->n->op == ODCLFUNC)
-				inlcalls(l->n);
-	}
-
-	// Phase 5: Escape analysis.
-	// Required for moving heap allocations onto stack,
-	// which in turn is required by the closure implementation,
-	// which stores the addresses of stack variables into the closure.
-	// If the closure does not escape, it needs to be on the stack
-	// or else the stack copier will not update it.
-	escapes(xtop);
-	
-	// Escape analysis moved escaped values off stack.
-	// Move large values off stack too.
-	movelarge(xtop);
-
-	// Phase 6: Compile top level functions.
-	for(l=xtop; l; l=l->next)
-		if(l->n->op == ODCLFUNC)
-			funccompile(l->n, 0);
-
-	if(nsavederrors+nerrors == 0)
-		fninit(xtop);
-
-	// Phase 7: Check external declarations.
-	for(l=externdcl; l; l=l->next)
-		if(l->n->op == ONAME)
-			typecheck(&l->n, Erv);
-
-	if(nerrors+nsavederrors)
-		errorexit();
-
-	dumpobj();
-
-	if(nerrors+nsavederrors)
-		errorexit();
-
-	flusherrors();
-	exits(0);
-	return 0;
-}
-
-void
-saveerrors(void)
-{
-	nsavederrors += nerrors;
-	nerrors = 0;
-}
-
-static int
-arsize(Biobuf *b, char *name)
-{
-	struct ar_hdr a;
-
-	if(Bread(b, a.name, sizeof(a.name)) != sizeof(a.name) ||
-	   Bread(b, a.date, sizeof(a.date)) != sizeof(a.date) ||
-	   Bread(b, a.uid, sizeof(a.uid)) != sizeof(a.uid) ||
-	   Bread(b, a.gid, sizeof(a.gid)) != sizeof(a.gid) ||
-	   Bread(b, a.mode, sizeof(a.mode)) != sizeof(a.mode) ||
-	   Bread(b, a.size, sizeof(a.size)) != sizeof(a.size) ||
-	   Bread(b, a.fmag, sizeof(a.fmag)) != sizeof(a.fmag))
-		return -1;
-
-	if(strncmp(a.name, name, strlen(name)) != 0)
-		return -1;
-
-	return atoi(a.size);
-}
-
-static int
-skiptopkgdef(Biobuf *b)
-{
-	char *p;
-	int sz;
-
-	/* archive header */
-	if((p = Brdline(b, '\n')) == nil)
-		return 0;
-	if(Blinelen(b) != 8)
-		return 0;
-	if(memcmp(p, "!<arch>\n", 8) != 0)
-		return 0;
-	/* symbol table may be first; skip it */
-	sz = arsize(b, "__.GOSYMDEF");
-	if(sz >= 0)
-		Bseek(b, sz, 1);
-	else
-		Bseek(b, 8, 0);
-	/* package export block is next */
-	sz = arsize(b, "__.PKGDEF");
-	if(sz <= 0)
-		return 0;
-	return 1;
-}
-
-static void
-addidir(char* dir)
-{
-	Idir** pp;
-
-	if(dir == nil)
-		return;
-
-	for(pp = &idirs; *pp != nil; pp = &(*pp)->link)
-		;
-	*pp = mal(sizeof(Idir));
-	(*pp)->link = nil;
-	(*pp)->dir = dir;
-}
-
-// is this path a local name?  begins with ./ or ../ or /
-static int
-islocalname(Strlit *name)
-{
-	if(name->len >= 1 && name->s[0] == '/')
-		return 1;
-	if(ctxt->windows && name->len >= 3 &&
-	   yy_isalpha(name->s[0]) && name->s[1] == ':' && name->s[2] == '/')
-	   	return 1;
-	if(name->len >= 2 && strncmp(name->s, "./", 2) == 0)
-		return 1;
-	if(name->len == 1 && strncmp(name->s, ".", 1) == 0)
-		return 1;
-	if(name->len >= 3 && strncmp(name->s, "../", 3) == 0)
-		return 1;
-	if(name->len == 2 && strncmp(name->s, "..", 2) == 0)
-		return 1;
-	return 0;
-}
-
-static int
-findpkg(Strlit *name)
-{
-	Idir *p;
-	char *q, *suffix, *suffixsep;
-
-	if(islocalname(name)) {
-		if(safemode || nolocalimports)
-			return 0;
-		// 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.
-		snprint(namebuf, sizeof(namebuf), "%Z.a", name);
-		if(access(namebuf, 0) >= 0)
-			return 1;
-		snprint(namebuf, sizeof(namebuf), "%Z.%c", name, thechar);
-		if(access(namebuf, 0) >= 0)
-			return 1;
-		return 0;
-	}
-
-	// local imports should be canonicalized already.
-	// don't want to see "encoding/../encoding/base64"
-	// as different from "encoding/base64".
-	q = mal(name->len+1);
-	memmove(q, name->s, name->len);
-	q[name->len] = '\0';
-	cleanname(q);
-	if(strlen(q) != name->len || memcmp(q, name->s, name->len) != 0) {
-		yyerror("non-canonical import path %Z (should be %s)", name, q);
-		return 0;
-	}
-
-	for(p = idirs; p != nil; p = p->link) {
-		snprint(namebuf, sizeof(namebuf), "%s/%Z.a", p->dir, name);
-		if(access(namebuf, 0) >= 0)
-			return 1;
-		snprint(namebuf, sizeof(namebuf), "%s/%Z.%c", p->dir, name, thechar);
-		if(access(namebuf, 0) >= 0)
-			return 1;
-	}
-	if(goroot != nil) {
-		suffix = "";
-		suffixsep = "";
-		if(flag_installsuffix != nil) {
-			suffixsep = "_";
-			suffix = flag_installsuffix;
-		} else if(flag_race) {
-			suffixsep = "_";
-			suffix = "race";
-		}
-		snprint(namebuf, sizeof(namebuf), "%s/pkg/%s_%s%s%s/%Z.a", goroot, goos, goarch, suffixsep, suffix, name);
-		if(access(namebuf, 0) >= 0)
-			return 1;
-		snprint(namebuf, sizeof(namebuf), "%s/pkg/%s_%s%s%s/%Z.%c", goroot, goos, goarch, suffixsep, suffix, name, thechar);
-		if(access(namebuf, 0) >= 0)
-			return 1;
-	}
-	return 0;
-}
-
-static void
-fakeimport(void)
-{
-	importpkg = mkpkg(strlit("fake"));
-	cannedimports("fake.6", "$$\n");
-}
-
-void
-importfile(Val *f, int line)
-{
-	Biobuf *imp;
-	char *file, *p, *q, *tag;
-	int32 c;
-	int len;
-	Strlit *path;
-	char *cleanbuf, *prefix;
-
-	USED(line);
-
-	if(f->ctype != CTSTR) {
-		yyerror("import statement not a string");
-		fakeimport();
-		return;
-	}
-
-	if(f->u.sval->len == 0) {
-		yyerror("import path is empty");
-		fakeimport();
-		return;
-	}
-
-	if(isbadimport(f->u.sval)) {
-		fakeimport();
-		return;
-	}
-
-	// The package name main is no longer reserved,
-	// 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(strcmp(f->u.sval->s, "main") == 0) {
-		yyerror("cannot import \"main\"");
-		errorexit();
-	}
-
-	if(myimportpath != nil && strcmp(f->u.sval->s, myimportpath) == 0) {
-		yyerror("import \"%Z\" while compiling that package (import cycle)", f->u.sval);
-		errorexit();
-	}
-
-	if(strcmp(f->u.sval->s, "unsafe") == 0) {
-		if(safemode) {
-			yyerror("cannot import package unsafe");
-			errorexit();
-		}
-		importpkg = mkpkg(f->u.sval);
-		cannedimports("unsafe.6", unsafeimport);
-		return;
-	}
-	
-	path = f->u.sval;
-	if(islocalname(path)) {
-		if(path->s[0] == '/') {
-			yyerror("import path cannot be absolute path");
-			fakeimport();
-			return;
-		}
-		prefix = ctxt->pathname;
-		if(localimport != nil)
-			prefix = localimport;
-		cleanbuf = mal(strlen(prefix) + strlen(path->s) + 2);
-		strcpy(cleanbuf, prefix);
-		strcat(cleanbuf, "/");
-		strcat(cleanbuf, path->s);
-		cleanname(cleanbuf);
-		path = strlit(cleanbuf);
-		
-		if(isbadimport(path)) {
-			fakeimport();
-			return;
-		}
-	}
-
-	if(!findpkg(path)) {
-		yyerror("can't find import: \"%Z\"", f->u.sval);
-		errorexit();
-	}
-	importpkg = mkpkg(path);
-
-	// If we already saw that package, feed a dummy statement
-	// to the lexer to avoid parsing export data twice.
-	if(importpkg->imported) {
-		file = strdup(namebuf);
-		tag = "";
-		if(importpkg->safe) {
-			tag = "safe";
-		}
-		p = smprint("package %s %s\n$$\n", importpkg->name, tag);
-		cannedimports(file, p);
-		return;
-	}
-	importpkg->imported = 1;
-
-	imp = Bopen(namebuf, OREAD);
-	if(imp == nil) {
-		yyerror("can't open import: \"%Z\": %r", f->u.sval);
-		errorexit();
-	}
-	file = strdup(namebuf);
-
-	len = strlen(namebuf);
-	if(len > 2 && namebuf[len-2] == '.' && namebuf[len-1] == 'a') {
-		if(!skiptopkgdef(imp)) {
-			yyerror("import %s: not a package file", file);
-			errorexit();
-		}
-	}
-	
-	// check object header
-	p = Brdstr(imp, '\n', 1);
-	if(strcmp(p, "empty archive") != 0) {
-		if(strncmp(p, "go object ", 10) != 0) {
-			yyerror("import %s: not a go object file", file);
-			errorexit();
-		}
-		q = smprint("%s %s %s %s", getgoos(), getgoarch(), getgoversion(), expstring());
-		if(strcmp(p+10, q) != 0) {
-			yyerror("import %s: object is [%s] expected [%s]", file, p+10, q);
-			errorexit();
-		}
-		free(q);
-	}
-
-	// assume files move (get installed)
-	// so don't record the full path.
-	linehist(file + len - path->len - 2, -1, 1);	// acts as #pragma lib
-
-	/*
-	 * position the input right
-	 * after $$ and return
-	 */
-	pushedio = curio;
-	curio.bin = imp;
-	curio.peekc = 0;
-	curio.peekc1 = 0;
-	curio.infile = file;
-	curio.nlsemi = 0;
-	typecheckok = 1;
-
-	for(;;) {
-		c = getc();
-		if(c == EOF)
-			break;
-		if(c != '$')
-			continue;
-		c = getc();
-		if(c == EOF)
-			break;
-		if(c != '$')
-			continue;
-		return;
-	}
-	yyerror("no import in \"%Z\"", f->u.sval);
-	unimportfile();
-}
-
-void
-unimportfile(void)
-{
-	if(curio.bin != nil) {
-		Bterm(curio.bin);
-		curio.bin = nil;
-	} else
-		lexlineno--;	// re correct sys.6 line number
-
-	curio = pushedio;
-	pushedio.bin = nil;
-	incannedimport = 0;
-	typecheckok = 0;
-}
-
-void
-cannedimports(char *file, char *cp)
-{
-	lexlineno++;		// if sys.6 is included on line 1,
-
-	pushedio = curio;
-	curio.bin = nil;
-	curio.peekc = 0;
-	curio.peekc1 = 0;
-	curio.infile = file;
-	curio.cp = cp;
-	curio.nlsemi = 0;
-	curio.importsafe = 0;
-
-	typecheckok = 1;
-	incannedimport = 1;
-}
-
-static int
-isfrog(int c)
-{
-	// complain about possibly invisible control characters
-	if(c < ' ') {
-		return !yy_isspace(c);	// exclude good white space
-	}
-	if(0x7f <= c && c <= 0xa0)	// DEL, unicode block including unbreakable space.
-		return 1;
-	return 0;
-}
-
-typedef struct Loophack Loophack;
-struct Loophack {
-	int v;
-	Loophack *next;
-};
-
-static int32
-_yylex(void)
-{
-	int c, c1, clen, escflag, ncp;
-	vlong v;
-	char *cp, *ep;
-	Rune rune;
-	Sym *s;
-	static Loophack *lstk;
-	Loophack *h;
-
-	prevlineno = lineno;
-
-l0:
-	c = getc();
-	if(yy_isspace(c)) {
-		if(c == '\n' && curio.nlsemi) {
-			ungetc(c);
-			DBG("lex: implicit semi\n");
-			return ';';
-		}
-		goto l0;
-	}
-
-	lineno = lexlineno;	/* start of token */
-
-	if(c >= Runeself) {
-		/* all multibyte runes are alpha */
-		cp = lexbuf;
-		ep = lexbuf+sizeof lexbuf;
-		goto talph;
-	}
-
-	if(yy_isalpha(c)) {
-		cp = lexbuf;
-		ep = lexbuf+sizeof lexbuf;
-		goto talph;
-	}
-
-	if(yy_isdigit(c))
-		goto tnum;
-
-	switch(c) {
-	case EOF:
-		lineno = prevlineno;
-		ungetc(EOF);
-		return -1;
-
-	case '_':
-		cp = lexbuf;
-		ep = lexbuf+sizeof lexbuf;
-		goto talph;
-
-	case '.':
-		c1 = getc();
-		if(yy_isdigit(c1)) {
-			cp = lexbuf;
-			ep = lexbuf+sizeof lexbuf;
-			*cp++ = c;
-			c = c1;
-			goto casedot;
-		}
-		if(c1 == '.') {
-			c1 = getc();
-			if(c1 == '.') {
-				c = LDDD;
-				goto lx;
-			}
-			ungetc(c1);
-			c1 = '.';
-		}
-		break;
-
-	case '"':
-		/* "..." */
-		strcpy(lexbuf, "\"<string>\"");
-		cp = mal(8);
-		clen = sizeof(int32);
-		ncp = 8;
-
-		for(;;) {
-			if(clen+UTFmax > ncp) {
-				cp = remal(cp, ncp, ncp);
-				ncp += ncp;
-			}
-			if(escchar('"', &escflag, &v))
-				break;
-			if(v < Runeself || escflag) {
-				cp[clen++] = v;
-			} else {
-				rune = v;
-				c = runelen(rune);
-				runetochar(cp+clen, &rune);
-				clen += c;
-			}
-		}
-		goto strlit;
-	
-	case '`':
-		/* `...` */
-		strcpy(lexbuf, "`<string>`");
-		cp = mal(8);
-		clen = sizeof(int32);
-		ncp = 8;
-
-		for(;;) {
-			if(clen+UTFmax > ncp) {
-				cp = remal(cp, ncp, ncp);
-				ncp += ncp;
-			}
-			c = getr();
-			if(c == '\r')
-				continue;
-			if(c == EOF) {
-				yyerror("eof in string");
-				break;
-			}
-			if(c == '`')
-				break;
-			rune = c;
-			clen += runetochar(cp+clen, &rune);
-		}
-
-	strlit:
-		*(int32*)cp = clen-sizeof(int32);	// length
-		do {
-			cp[clen++] = 0;
-		} while(clen & MAXALIGN);
-		yylval.val.u.sval = (Strlit*)cp;
-		yylval.val.ctype = CTSTR;
-		DBG("lex: string literal\n");
-		strcpy(litbuf, "string literal");
-		return LLITERAL;
-
-	case '\'':
-		/* '.' */
-		if(escchar('\'', &escflag, &v)) {
-			yyerror("empty character literal or unescaped ' in character literal");
-			v = '\'';
-		}
-		if(!escchar('\'', &escflag, &v)) {
-			yyerror("missing '");
-			ungetc(v);
-		}
-		yylval.val.u.xval = mal(sizeof(*yylval.val.u.xval));
-		mpmovecfix(yylval.val.u.xval, v);
-		yylval.val.ctype = CTRUNE;
-		DBG("lex: codepoint literal\n");
-		strcpy(litbuf, "string literal");
-		return LLITERAL;
-
-	case '/':
-		c1 = getc();
-		if(c1 == '*') {
-			int nl;
-			
-			nl = 0;
-			for(;;) {
-				c = getr();
-				if(c == '\n')
-					nl = 1;
-				while(c == '*') {
-					c = getr();
-					if(c == '/') {
-						if(nl)
-							ungetc('\n');
-						goto l0;
-					}
-					if(c == '\n')
-						nl = 1;
-				}
-				if(c == EOF) {
-					yyerror("eof in comment");
-					errorexit();
-				}
-			}
-		}
-		if(c1 == '/') {
-			c = getlinepragma();
-			for(;;) {
-				if(c == '\n' || c == EOF) {
-					ungetc(c);
-					goto l0;
-				}
-				c = getr();
-			}
-		}
-		if(c1 == '=') {
-			c = ODIV;
-			goto asop;
-		}
-		break;
-
-	case ':':
-		c1 = getc();
-		if(c1 == '=') {
-			c = LCOLAS;
-			yylval.i = lexlineno;
-			goto lx;
-		}
-		break;
-
-	case '*':
-		c1 = getc();
-		if(c1 == '=') {
-			c = OMUL;
-			goto asop;
-		}
-		break;
-
-	case '%':
-		c1 = getc();
-		if(c1 == '=') {
-			c = OMOD;
-			goto asop;
-		}
-		break;
-
-	case '+':
-		c1 = getc();
-		if(c1 == '+') {
-			c = LINC;
-			goto lx;
-		}
-		if(c1 == '=') {
-			c = OADD;
-			goto asop;
-		}
-		break;
-
-	case '-':
-		c1 = getc();
-		if(c1 == '-') {
-			c = LDEC;
-			goto lx;
-		}
-		if(c1 == '=') {
-			c = OSUB;
-			goto asop;
-		}
-		break;
-
-	case '>':
-		c1 = getc();
-		if(c1 == '>') {
-			c = LRSH;
-			c1 = getc();
-			if(c1 == '=') {
-				c = ORSH;
-				goto asop;
-			}
-			break;
-		}
-		if(c1 == '=') {
-			c = LGE;
-			goto lx;
-		}
-		c = LGT;
-		break;
-
-	case '<':
-		c1 = getc();
-		if(c1 == '<') {
-			c = LLSH;
-			c1 = getc();
-			if(c1 == '=') {
-				c = OLSH;
-				goto asop;
-			}
-			break;
-		}
-		if(c1 == '=') {
-			c = LLE;
-			goto lx;
-		}
-		if(c1 == '-') {
-			c = LCOMM;
-			goto lx;
-		}
-		c = LLT;
-		break;
-
-	case '=':
-		c1 = getc();
-		if(c1 == '=') {
-			c = LEQ;
-			goto lx;
-		}
-		break;
-
-	case '!':
-		c1 = getc();
-		if(c1 == '=') {
-			c = LNE;
-			goto lx;
-		}
-		break;
-
-	case '&':
-		c1 = getc();
-		if(c1 == '&') {
-			c = LANDAND;
-			goto lx;
-		}
-		if(c1 == '^') {
-			c = LANDNOT;
-			c1 = getc();
-			if(c1 == '=') {
-				c = OANDNOT;
-				goto asop;
-			}
-			break;
-		}
-		if(c1 == '=') {
-			c = OAND;
-			goto asop;
-		}
-		break;
-
-	case '|':
-		c1 = getc();
-		if(c1 == '|') {
-			c = LOROR;
-			goto lx;
-		}
-		if(c1 == '=') {
-			c = OOR;
-			goto asop;
-		}
-		break;
-
-	case '^':
-		c1 = getc();
-		if(c1 == '=') {
-			c = OXOR;
-			goto asop;
-		}
-		break;
-
-	/*
-	 * clumsy dance:
-	 * to implement rule that disallows
-	 *	if T{1}[0] { ... }
-	 * but allows
-	 * 	if (T{1}[0]) { ... }
-	 * the block bodies for if/for/switch/select
-	 * begin with an LBODY token, not '{'.
-	 *
-	 * when we see the keyword, the next
-	 * non-parenthesized '{' becomes an LBODY.
-	 * loophack is normally 0.
-	 * a keyword makes it go up to 1.
-	 * parens push loophack onto a stack and go back to 0.
-	 * a '{' with loophack == 1 becomes LBODY and disables loophack.
-	 *
-	 * i said it was clumsy.
-	 */
-	case '(':
-	case '[':
-		if(loophack || lstk != nil) {
-			h = malloc(sizeof *h);
-			if(h == nil) {
-				flusherrors();
-				yyerror("out of memory");
-				errorexit();
-			}
-			h->v = loophack;
-			h->next = lstk;
-			lstk = h;
-			loophack = 0;
-		}
-		goto lx;
-	case ')':
-	case ']':
-		if(lstk != nil) {
-			h = lstk;
-			loophack = h->v;
-			lstk = h->next;
-			free(h);
-		}
-		goto lx;
-	case '{':
-		if(loophack == 1) {
-			DBG("%L lex: LBODY\n", lexlineno);
-			loophack = 0;
-			return LBODY;
-		}
-		goto lx;
-
-	default:
-		goto lx;
-	}
-	ungetc(c1);
-
-lx:
-	if(c > 0xff)
-		DBG("%L lex: TOKEN %s\n", lexlineno, lexname(c));
-	else
-		DBG("%L lex: TOKEN '%c'\n", lexlineno, c);
-	if(isfrog(c)) {
-		yyerror("illegal character 0x%ux", c);
-		goto l0;
-	}
-	if(importpkg == nil && (c == '#' || c == '$' || c == '?' || c == '@' || c == '\\')) {
-		yyerror("%s: unexpected %c", "syntax error", c);
-		goto l0;
-	}
-	return c;
-
-asop:
-	yylval.i = c;	// rathole to hold which asop
-	DBG("lex: TOKEN ASOP %c\n", c);
-	return LASOP;
-
-talph:
-	/*
-	 * cp is set to lexbuf and some
-	 * prefix has been stored
-	 */
-	for(;;) {
-		if(cp+10 >= ep) {
-			yyerror("identifier too long");
-			errorexit();
-		}
-		if(c >= Runeself) {
-			ungetc(c);
-			rune = getr();
-			// 0xb7 · is used for internal names
-			if(!isalpharune(rune) && !isdigitrune(rune) && (importpkg == nil || rune != 0xb7))
-				yyerror("invalid identifier character U+%04x", rune);
-			cp += runetochar(cp, &rune);
-		} else if(!yy_isalnum(c) && c != '_')
-			break;
-		else
-			*cp++ = c;
-		c = getc();
-	}
-	*cp = 0;
-	ungetc(c);
-
-	s = lookup(lexbuf);
-	switch(s->lexical) {
-	case LIGNORE:
-		goto l0;
-
-	case LFOR:
-	case LIF:
-	case LSWITCH:
-	case LSELECT:
-		loophack = 1;	// see comment about loophack above
-		break;
-	}
-
-	DBG("lex: %S %s\n", s, lexname(s->lexical));
-	yylval.sym = s;
-	return s->lexical;
-
-tnum:
-	cp = lexbuf;
-	ep = lexbuf+sizeof lexbuf;
-	if(c != '0') {
-		for(;;) {
-			if(cp+10 >= ep) {
-				yyerror("identifier too long");
-				errorexit();
-			}
-			*cp++ = c;
-			c = getc();
-			if(yy_isdigit(c))
-				continue;
-			goto dc;
-		}
-	}
-	*cp++ = c;
-	c = getc();
-	if(c == 'x' || c == 'X') {
-		for(;;) {
-			if(cp+10 >= ep) {
-				yyerror("identifier too long");
-				errorexit();
-			}
-			*cp++ = c;
-			c = getc();
-			if(yy_isdigit(c))
-				continue;
-			if(c >= 'a' && c <= 'f')
-				continue;
-			if(c >= 'A' && c <= 'F')
-				continue;
-			if(cp == lexbuf+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(cp+10 >= ep) {
-			yyerror("identifier too long");
-			errorexit();
-		}
-		if(!yy_isdigit(c))
-			break;
-		if(c < '0' || c > '7')
-			c1 = 1;		// not octal
-		*cp++ = c;
-		c = getc();
-	}
-	if(c == '.')
-		goto casedot;
-	if(c == 'e' || c == 'E')
-		goto caseep;
-	if(c == 'i')
-		goto casei;
-	if(c1)
-		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 = 0;
-	ungetc(c);
-
-	yylval.val.u.xval = mal(sizeof(*yylval.val.u.xval));
-	mpatofix(yylval.val.u.xval, lexbuf);
-	if(yylval.val.u.xval->ovf) {
-		yyerror("overflow in constant");
-		mpmovecfix(yylval.val.u.xval, 0);
-	}
-	yylval.val.ctype = CTINT;
-	DBG("lex: integer literal\n");
-	strcpy(litbuf, "literal ");
-	strcat(litbuf, lexbuf);
-	return LLITERAL;
-
-casedot:
-	for(;;) {
-		if(cp+10 >= ep) {
-			yyerror("identifier too long");
-			errorexit();
-		}
-		*cp++ = c;
-		c = getc();
-		if(!yy_isdigit(c))
-			break;
-	}
-	if(c == 'i')
-		goto casei;
-	if(c != 'e' && c != 'E')
-		goto caseout;
-
-caseep:
-	*cp++ = c;
-	c = getc();
-	if(c == '+' || c == '-') {
-		*cp++ = c;
-		c = getc();
-	}
-	if(!yy_isdigit(c))
-		yyerror("malformed fp constant exponent");
-	while(yy_isdigit(c)) {
-		if(cp+10 >= ep) {
-			yyerror("identifier too long");
-			errorexit();
-		}
-		*cp++ = c;
-		c = getc();
-	}
-	if(c == 'i')
-		goto casei;
-	goto caseout;
-
-casei:
-	// imaginary constant
-	*cp = 0;
-	yylval.val.u.cval = mal(sizeof(*yylval.val.u.cval));
-	mpmovecflt(&yylval.val.u.cval->real, 0.0);
-	mpatoflt(&yylval.val.u.cval->imag, lexbuf);
-	if(yylval.val.u.cval->imag.val.ovf) {
-		yyerror("overflow in imaginary constant");
-		mpmovecflt(&yylval.val.u.cval->real, 0.0);
-	}
-	yylval.val.ctype = CTCPLX;
-	DBG("lex: imaginary literal\n");
-	strcpy(litbuf, "literal ");
-	strcat(litbuf, lexbuf);
-	return LLITERAL;
-
-caseout:
-	*cp = 0;
-	ungetc(c);
-
-	yylval.val.u.fval = mal(sizeof(*yylval.val.u.fval));
-	mpatoflt(yylval.val.u.fval, lexbuf);
-	if(yylval.val.u.fval->val.ovf) {
-		yyerror("overflow in float constant");
-		mpmovecflt(yylval.val.u.fval, 0.0);
-	}
-	yylval.val.ctype = CTFLT;
-	DBG("lex: floating literal\n");
-	strcpy(litbuf, "literal ");
-	strcat(litbuf, lexbuf);
-	return LLITERAL;
-}
-
-/*
- * read and interpret syntax that looks like
- * //line parse.y:15
- * as a discontinuity in sequential line numbers.
- * the next line of input comes from parse.y:15
- */
-static int
-getlinepragma(void)
-{
-	int i, c, n;
-	char *cp, *ep, *linep;
-	Hist *h;
-
-	c = getr();
-	if(c == 'g')
-		goto go;
-	if(c != 'l')	
-		goto out;
-	for(i=1; i<5; i++) {
-		c = getr();
-		if(c != "line "[i])
-			goto out;
-	}
-
-	cp = lexbuf;
-	ep = lexbuf+sizeof(lexbuf)-5;
-	linep = nil;
-	for(;;) {
-		c = getr();
-		if(c == EOF)
-			goto out;
-		if(c == '\n')
-			break;
-		if(c == ' ')
-			continue;
-		if(c == ':')
-			linep = cp;
-		if(cp < ep)
-			*cp++ = c;
-	}
-	*cp = 0;
-
-	if(linep == nil || linep >= ep)
-		goto out;
-	*linep++ = '\0';
-	n = 0;
-	for(cp=linep; *cp; cp++) {
-		if(*cp < '0' || *cp > '9')
-			goto out;
-		n = n*10 + *cp - '0';
-		if(n > 1e8) {
-			yyerror("line number out of range");
-			errorexit();
-		}
-	}
-	if(n <= 0)
-		goto out;
-
-	// try to avoid allocating file name over and over
-	for(h=ctxt->hist; h!=nil; h=h->link) {
-		if(h->name != nil && strcmp(h->name, lexbuf) == 0) {
-			linehist(h->name, n, 0);
-			goto out;
-		}
-	}
-	linehist(strdup(lexbuf), n, 0);
-	goto out;
-
-go:
-	cp = lexbuf;
-	ep = lexbuf+sizeof(lexbuf)-5;
-	*cp++ = 'g'; // already read
-	for(;;) {
-		c = getr();
-		if(c == EOF || c >= Runeself)
-			goto out;
-		if(c == '\n')
-			break;
-		if(cp < ep)
-			*cp++ = c;
-	}
-	*cp = 0;
-	ep = strchr(lexbuf, ' ');
-	if(ep != nil)
-		*ep = 0;
-
-	if(strcmp(lexbuf, "go:nointerface") == 0 && fieldtrack_enabled) {
-		nointerface = 1;
-		goto out;
-	}
-	if(strcmp(lexbuf, "go:noescape") == 0) {
-		noescape = 1;
-		goto out;
-	}
-	if(strcmp(lexbuf, "go:nosplit") == 0) {
-		nosplit = 1;
-		goto out;
-	}
-	
-out:
-	return c;
-}
-
-int32
-yylex(void)
-{
-	int lx;
-	
-	lx = _yylex();
-	
-	if(curio.nlsemi && lx == EOF) {
-		// Treat EOF as "end of line" for the purposes
-		// of inserting a semicolon.
-		lx = ';';
-	}
-
-	switch(lx) {
-	case LNAME:
-	case LLITERAL:
-	case LBREAK:
-	case LCONTINUE:
-	case LFALL:
-	case LRETURN:
-	case LINC:
-	case LDEC:
-	case ')':
-	case '}':
-	case ']':
-		curio.nlsemi = 1;
-		break;
-	default:
-		curio.nlsemi = 0;
-		break;
-	}
-
-	// Track last two tokens returned by yylex.
-	yyprev = yylast;
-	yylast = lx;
-	return lx;
-}
-
-static int
-getc(void)
-{
-	int c, c1, c2;
-
-	c = curio.peekc;
-	if(c != 0) {
-		curio.peekc = curio.peekc1;
-		curio.peekc1 = 0;
-		goto check;
-	}
-	
-	if(curio.bin == nil) {
-		c = *curio.cp & 0xff;
-		if(c != 0)
-			curio.cp++;
-	} else {
-	loop:
-		c = BGETC(curio.bin);
-		if(c == 0xef) {
-			c1 = BGETC(curio.bin);
-			c2 = BGETC(curio.bin);
-			if(c1 == 0xbb && c2 == 0xbf) {
-				yyerrorl(lexlineno, "Unicode (UTF-8) BOM in middle of file");
-				goto loop;
-			}
-			Bungetc(curio.bin);
-			Bungetc(curio.bin);
-		}
-	}
-
-check:
-	switch(c) {
-	case 0:
-		if(curio.bin != nil) {
-			yyerror("illegal NUL byte");
-			break;
-		}
-	case EOF:
-		// insert \n at EOF
-		if(curio.eofnl || curio.last == '\n')
-			return EOF;
-		curio.eofnl = 1;
-		c = '\n';
-	case '\n':
-		if(pushedio.bin == nil)
-			lexlineno++;
-		break;
-	}
-	curio.last = c;
-	return c;
-}
-
-static void
-ungetc(int c)
-{
-	curio.peekc1 = curio.peekc;
-	curio.peekc = c;
-	if(c == '\n' && pushedio.bin == nil)
-		lexlineno--;
-}
-
-static int32
-getr(void)
-{
-	int c, i;
-	char str[UTFmax+1];
-	Rune rune;
-
-	c = getc();
-	if(c < Runeself)
-		return c;
-	i = 0;
-	str[i++] = c;
-
-loop:
-	c = getc();
-	str[i++] = c;
-	if(!fullrune(str, i))
-		goto loop;
-	c = chartorune(&rune, str);
-	if(rune == Runeerror && c == 1) {
-		lineno = lexlineno;
-		yyerror("illegal UTF-8 sequence");
-		flusherrors();
-		print("\t");
-		for(c=0; c<i; c++)
-			print("%s%.2x", c > 0 ? " " : "", *(uchar*)(str+c));
-		print("\n");
-	}
-	return rune;
-}
-
-static int
-escchar(int e, int *escflg, vlong *val)
-{
-	int i, u, c;
-	vlong l;
-
-	*escflg = 0;
-
-	c = getr();
-	switch(c) {
-	case EOF:
-		yyerror("eof in string");
-		return 1;
-	case '\n':
-		yyerror("newline in string");
-		return 1;
-	case '\\':
-		break;
-	default:
-		if(c == e)
-			return 1;
-		*val = c;
-		return 0;
-	}
-
-	u = 0;
-	c = getr();
-	switch(c) {
-	case 'x':
-		*escflg = 1;	// it's a byte
-		i = 2;
-		goto hex;
-
-	case 'u':
-		i = 4;
-		u = 1;
-		goto hex;
-
-	case 'U':
-		i = 8;
-		u = 1;
-		goto hex;
-
-	case '0':
-	case '1':
-	case '2':
-	case '3':
-	case '4':
-	case '5':
-	case '6':
-	case '7':
-		*escflg = 1;	// it's a byte
-		goto oct;
-
-	case 'a': c = '\a'; break;
-	case 'b': c = '\b'; break;
-	case 'f': c = '\f'; break;
-	case 'n': c = '\n'; break;
-	case 'r': c = '\r'; break;
-	case 't': c = '\t'; break;
-	case 'v': c = '\v'; break;
-	case '\\': c = '\\'; break;
-
-	default:
-		if(c != e)
-			yyerror("unknown escape sequence: %c", c);
-	}
-	*val = c;
-	return 0;
-
-hex:
-	l = 0;
-	for(; i>0; i--) {
-		c = getc();
-		if(c >= '0' && c <= '9') {
-			l = l*16 + c-'0';
-			continue;
-		}
-		if(c >= 'a' && c <= 'f') {
-			l = l*16 + c-'a' + 10;
-			continue;
-		}
-		if(c >= 'A' && c <= 'F') {
-			l = l*16 + c-'A' + 10;
-			continue;
-		}
-		yyerror("non-hex character in escape sequence: %c", c);
-		ungetc(c);
-		break;
-	}
-	if(u && (l > Runemax || (0xd800 <= l && l < 0xe000))) {
-		yyerror("invalid Unicode code point in escape sequence: %#llx", l);
-		l = Runeerror;
-	}
-	*val = l;
-	return 0;
-
-oct:
-	l = c - '0';
-	for(i=2; i>0; i--) {
-		c = getc();
-		if(c >= '0' && c <= '7') {
-			l = l*8 + 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 0;
-}
-
-static	struct
-{
-	char*	name;
-	int	lexical;
-	int	etype;
-	int	op;
-} syms[] =
-{
-/*	name		lexical		etype		op
- */
-/* basic types */
-	{"int8",		LNAME,		TINT8,		OXXX},
-	{"int16",	LNAME,		TINT16,		OXXX},
-	{"int32",	LNAME,		TINT32,		OXXX},
-	{"int64",	LNAME,		TINT64,		OXXX},
-
-	{"uint8",	LNAME,		TUINT8,		OXXX},
-	{"uint16",	LNAME,		TUINT16,	OXXX},
-	{"uint32",	LNAME,		TUINT32,	OXXX},
-	{"uint64",	LNAME,		TUINT64,	OXXX},
-
-	{"float32",	LNAME,		TFLOAT32,	OXXX},
-	{"float64",	LNAME,		TFLOAT64,	OXXX},
-
-	{"complex64",	LNAME,		TCOMPLEX64,	OXXX},
-	{"complex128",	LNAME,		TCOMPLEX128,	OXXX},
-
-	{"bool",		LNAME,		TBOOL,		OXXX},
-	{"string",	LNAME,		TSTRING,	OXXX},
-
-	{"any",		LNAME,		TANY,		OXXX},
-
-	{"break",	LBREAK,		Txxx,		OXXX},
-	{"case",		LCASE,		Txxx,		OXXX},
-	{"chan",		LCHAN,		Txxx,		OXXX},
-	{"const",	LCONST,		Txxx,		OXXX},
-	{"continue",	LCONTINUE,	Txxx,		OXXX},
-	{"default",	LDEFAULT,	Txxx,		OXXX},
-	{"else",		LELSE,		Txxx,		OXXX},
-	{"defer",	LDEFER,		Txxx,		OXXX},
-	{"fallthrough",	LFALL,		Txxx,		OXXX},
-	{"for",		LFOR,		Txxx,		OXXX},
-	{"func",		LFUNC,		Txxx,		OXXX},
-	{"go",		LGO,		Txxx,		OXXX},
-	{"goto",		LGOTO,		Txxx,		OXXX},
-	{"if",		LIF,		Txxx,		OXXX},
-	{"import",	LIMPORT,	Txxx,		OXXX},
-	{"interface",	LINTERFACE,	Txxx,		OXXX},
-	{"map",		LMAP,		Txxx,		OXXX},
-	{"package",	LPACKAGE,	Txxx,		OXXX},
-	{"range",	LRANGE,		Txxx,		OXXX},
-	{"return",	LRETURN,	Txxx,		OXXX},
-	{"select",	LSELECT,	Txxx,		OXXX},
-	{"struct",	LSTRUCT,	Txxx,		OXXX},
-	{"switch",	LSWITCH,	Txxx,		OXXX},
-	{"type",		LTYPE,		Txxx,		OXXX},
-	{"var",		LVAR,		Txxx,		OXXX},
-
-	{"append",	LNAME,		Txxx,		OAPPEND},
-	{"cap",		LNAME,		Txxx,		OCAP},
-	{"close",	LNAME,		Txxx,		OCLOSE},
-	{"complex",	LNAME,		Txxx,		OCOMPLEX},
-	{"copy",		LNAME,		Txxx,		OCOPY},
-	{"delete",	LNAME,		Txxx,		ODELETE},
-	{"imag",		LNAME,		Txxx,		OIMAG},
-	{"len",		LNAME,		Txxx,		OLEN},
-	{"make",		LNAME,		Txxx,		OMAKE},
-	{"new",		LNAME,		Txxx,		ONEW},
-	{"panic",	LNAME,		Txxx,		OPANIC},
-	{"print",	LNAME,		Txxx,		OPRINT},
-	{"println",	LNAME,		Txxx,		OPRINTN},
-	{"real",		LNAME,		Txxx,		OREAL},
-	{"recover",	LNAME,		Txxx,		ORECOVER},
-
-	{"notwithstanding",		LIGNORE,	Txxx,		OXXX},
-	{"thetruthofthematter",		LIGNORE,	Txxx,		OXXX},
-	{"despiteallobjections",		LIGNORE,	Txxx,		OXXX},
-	{"whereas",			LIGNORE,	Txxx,		OXXX},
-	{"insofaras",			LIGNORE,	Txxx,		OXXX},
-};
-
-static void
-lexinit(void)
-{
-	int i, lex;
-	Sym *s, *s1;
-	Type *t;
-	int etype;
-	Val v;
-
-	/*
-	 * initialize basic types array
-	 * initialize known symbols
-	 */
-	for(i=0; i<nelem(syms); i++) {
-		lex = syms[i].lexical;
-		s = lookup(syms[i].name);
-		s->lexical = lex;
-
-		etype = syms[i].etype;
-		if(etype != Txxx) {
-			if(etype < 0 || etype >= nelem(types))
-				fatal("lexinit: %s bad etype", s->name);
-			s1 = pkglookup(syms[i].name, builtinpkg);
-			t = types[etype];
-			if(t == T) {
-				t = typ(etype);
-				t->sym = s1;
-
-				if(etype != TANY && etype != TSTRING)
-					dowidth(t);
-				types[etype] = t;
-			}
-			s1->lexical = LNAME;
-			s1->def = typenod(t);
-			continue;
-		}
-
-		etype = syms[i].op;
-		if(etype != OXXX) {
-			s1 = pkglookup(syms[i].name, builtinpkg);
-			s1->lexical = LNAME;
-			s1->def = nod(ONAME, N, N);
-			s1->def->sym = s1;
-			s1->def->etype = etype;
-			s1->def->builtin = 1;
-		}
-	}
-
-	// logically, the type of a string literal.
-	// types[TSTRING] is the named type string
-	// (the type of x in var x string or var x = "hello").
-	// this is the ideal form
-	// (the type of x in const x = "hello").
-	idealstring = typ(TSTRING);
-	idealbool = typ(TBOOL);
-
-	s = pkglookup("true", builtinpkg);
-	s->def = nodbool(1);
-	s->def->sym = lookup("true");
-	s->def->type = idealbool;
-
-	s = pkglookup("false", builtinpkg);
-	s->def = nodbool(0);
-	s->def->sym = lookup("false");
-	s->def->type = idealbool;
-
-	s = lookup("_");
-	s->block = -100;
-	s->def = nod(ONAME, N, N);
-	s->def->sym = s;
-	types[TBLANK] = typ(TBLANK);
-	s->def->type = types[TBLANK];
-	nblank = s->def;
-
-	s = pkglookup("_", builtinpkg);
-	s->block = -100;
-	s->def = nod(ONAME, N, N);
-	s->def->sym = s;
-	types[TBLANK] = typ(TBLANK);
-	s->def->type = types[TBLANK];
-
-	types[TNIL] = typ(TNIL);
-	s = pkglookup("nil", builtinpkg);
-	v.ctype = CTNIL;
-	s->def = nodlit(v);
-	s->def->sym = s;
-}
-
-static void
-lexinit1(void)
-{
-	Sym *s, *s1;
-	Type *t, *f, *rcvr, *in, *out;
-
-	// t = interface { Error() string }
-	rcvr = typ(TSTRUCT);
-	rcvr->type = typ(TFIELD);
-	rcvr->type->type = ptrto(typ(TSTRUCT));
-	rcvr->funarg = 1;
-	in = typ(TSTRUCT);
-	in->funarg = 1;
-	out = typ(TSTRUCT);
-	out->type = typ(TFIELD);
-	out->type->type = types[TSTRING];
-	out->funarg = 1;
-	f = typ(TFUNC);
-	*getthis(f) = rcvr;
-	*getoutarg(f) = out;
-	*getinarg(f) = in;
-	f->thistuple = 1;
-	f->intuple = 0;
-	f->outnamed = 0;
-	f->outtuple = 1;
-	t = typ(TINTER);
-	t->type = typ(TFIELD);
-	t->type->sym = lookup("Error");
-	t->type->type = f;
-
-	// error type
-	s = lookup("error");
-	s->lexical = LNAME;
-	s1 = pkglookup("error", builtinpkg);
-	errortype = t;
-	errortype->sym = s1;
-	s1->lexical = LNAME;
-	s1->def = typenod(errortype);
-
-	// byte alias
-	s = lookup("byte");
-	s->lexical = LNAME;
-	s1 = pkglookup("byte", builtinpkg);
-	bytetype = typ(TUINT8);
-	bytetype->sym = s1;
-	s1->lexical = LNAME;
-	s1->def = typenod(bytetype);
-
-	// rune alias
-	s = lookup("rune");
-	s->lexical = LNAME;
-	s1 = pkglookup("rune", builtinpkg);
-	runetype = typ(TINT32);
-	runetype->sym = s1;
-	s1->lexical = LNAME;
-	s1->def = typenod(runetype);
-}
-
-static void
-lexfini(void)
-{
-	Sym *s;
-	int lex, etype, i;
-	Val v;
-
-	for(i=0; i<nelem(syms); i++) {
-		lex = syms[i].lexical;
-		if(lex != LNAME)
-			continue;
-		s = lookup(syms[i].name);
-		s->lexical = lex;
-
-		etype = syms[i].etype;
-		if(etype != Txxx && (etype != TANY || debug['A']) && s->def == N) {
-			s->def = typenod(types[etype]);
-			s->origpkg = builtinpkg;
-		}
-
-		etype = syms[i].op;
-		if(etype != OXXX && s->def == N) {
-			s->def = nod(ONAME, N, N);
-			s->def->sym = s;
-			s->def->etype = etype;
-			s->def->builtin = 1;
-			s->origpkg = builtinpkg;
-		}
-	}
-
-	// backend-specific builtin types (e.g. int).
-	for(i=0; typedefs[i].name; i++) {
-		s = lookup(typedefs[i].name);
-		if(s->def == N) {
-			s->def = typenod(types[typedefs[i].etype]);
-			s->origpkg = builtinpkg;
-		}
-	}
-
-	// there's only so much table-driven we can handle.
-	// these are special cases.
-	s = lookup("byte");
-	if(s->def == N) {
-		s->def = typenod(bytetype);
-		s->origpkg = builtinpkg;
-	}
-
-	s = lookup("error");
-	if(s->def == N) {
-		s->def = typenod(errortype);
-		s->origpkg = builtinpkg;
-	}
-
-	s = lookup("rune");
-	if(s->def == N) {
-		s->def = typenod(runetype);
-		s->origpkg = builtinpkg;
-	}
-
-	s = lookup("nil");
-	if(s->def == N) {
-		v.ctype = CTNIL;
-		s->def = nodlit(v);
-		s->def->sym = s;
-		s->origpkg = builtinpkg;
-	}
-
-	s = lookup("iota");
-	if(s->def == N) {
-		s->def = nod(OIOTA, N, N);
-		s->def->sym = s;
-		s->origpkg = builtinpkg;
-	}
-
-	s = lookup("true");
-	if(s->def == N) {
-		s->def = nodbool(1);
-		s->def->sym = s;
-		s->origpkg = builtinpkg;
-	}
-
-	s = lookup("false");
-	if(s->def == N) {
-		s->def = nodbool(0);
-		s->def->sym = s;
-		s->origpkg = builtinpkg;
-	}
-
-	nodfp = nod(ONAME, N, N);
-	nodfp->type = types[TINT32];
-	nodfp->xoffset = 0;
-	nodfp->class = PPARAM;
-	nodfp->sym = lookup(".fp");
-}
-
-struct
-{
-	int	lex;
-	char*	name;
-} lexn[] =
-{
-	{LANDAND,	"ANDAND"},
-	{LANDNOT,	"ANDNOT"},
-	{LASOP,		"ASOP"},
-	{LBREAK,		"BREAK"},
-	{LCASE,		"CASE"},
-	{LCHAN,		"CHAN"},
-	{LCOLAS,		"COLAS"},
-	{LCOMM,		"<-"},
-	{LCONST,		"CONST"},
-	{LCONTINUE,	"CONTINUE"},
-	{LDDD,		"..."},
-	{LDEC,		"DEC"},
-	{LDEFAULT,	"DEFAULT"},
-	{LDEFER,		"DEFER"},
-	{LELSE,		"ELSE"},
-	{LEQ,		"EQ"},
-	{LFALL,		"FALL"},
-	{LFOR,		"FOR"},
-	{LFUNC,		"FUNC"},
-	{LGE,		"GE"},
-	{LGO,		"GO"},
-	{LGOTO,		"GOTO"},
-	{LGT,		"GT"},
-	{LIF,		"IF"},
-	{LIMPORT,	"IMPORT"},
-	{LINC,		"INC"},
-	{LINTERFACE,	"INTERFACE"},
-	{LLE,		"LE"},
-	{LLITERAL,	"LITERAL"},
-	{LLSH,		"LSH"},
-	{LLT,		"LT"},
-	{LMAP,		"MAP"},
-	{LNAME,		"NAME"},
-	{LNE,		"NE"},
-	{LOROR,		"OROR"},
-	{LPACKAGE,	"PACKAGE"},
-	{LRANGE,		"RANGE"},
-	{LRETURN,	"RETURN"},
-	{LRSH,		"RSH"},
-	{LSELECT,	"SELECT"},
-	{LSTRUCT,	"STRUCT"},
-	{LSWITCH,	"SWITCH"},
-	{LTYPE,		"TYPE"},
-	{LVAR,		"VAR"},
-};
-
-char*
-lexname(int lex)
-{
-	int i;
-	static char buf[100];
-
-	for(i=0; i<nelem(lexn); i++)
-		if(lexn[i].lex == lex)
-			return lexn[i].name;
-	snprint(buf, sizeof(buf), "LEX-%d", lex);
-	return buf;
-}
-
-struct
-{
-	char *have;
-	char *want;
-} yytfix[] =
-{
-	{"$end",	"EOF"},
-	{"LLITERAL",	"literal"},
-	{"LASOP",	"op="},
-	{"LBREAK",	"break"},
-	{"LCASE",	"case"},
-	{"LCHAN",	"chan"},
-	{"LCOLAS",	":="},
-	{"LCONST",	"const"},
-	{"LCONTINUE",	"continue"},
-	{"LDDD",	"..."},
-	{"LDEFAULT",	"default"},
-	{"LDEFER",	"defer"},
-	{"LELSE",	"else"},
-	{"LFALL",	"fallthrough"},
-	{"LFOR",	"for"},
-	{"LFUNC",	"func"},
-	{"LGO",	"go"},
-	{"LGOTO",	"goto"},
-	{"LIF",	"if"},
-	{"LIMPORT",	"import"},
-	{"LINTERFACE",	"interface"},
-	{"LMAP",	"map"},
-	{"LNAME",	"name"},
-	{"LPACKAGE",	"package"},
-	{"LRANGE",	"range"},
-	{"LRETURN",	"return"},
-	{"LSELECT",	"select"},
-	{"LSTRUCT",	"struct"},
-	{"LSWITCH",	"switch"},
-	{"LTYPE",	"type"},
-	{"LVAR",	"var"},
-	{"LANDAND",	"&&"},
-	{"LANDNOT",	"&^"},
-	{"LBODY",	"{"},
-	{"LCOMM",	"<-"},
-	{"LDEC",	"--"},
-	{"LINC",	"++"},
-	{"LEQ",	"=="},
-	{"LGE",	">="},
-	{"LGT",	">"},
-	{"LLE",	"<="},
-	{"LLT",	"<"},
-	{"LLSH",	"<<"},
-	{"LRSH",	">>"},
-	{"LOROR",	"||"},
-	{"LNE",	"!="},
-	
-	// spell out to avoid confusion with punctuation in error messages
-	{"';'",	"semicolon or newline"},
-	{"','",	"comma"},
-};
-
-static void
-yytinit(void)
-{
-	int i, j;
-	extern char *yytname[];
-	char *s, *t;
-
-	for(i=0; yytname[i] != nil; i++) {
-		s = yytname[i];
-		
-		if(strcmp(s, "LLITERAL") == 0) {
-			strcpy(litbuf, "literal");
-			yytname[i] = litbuf;
-			goto loop;
-		}
-		
-		// apply yytfix if possible
-		for(j=0; j<nelem(yytfix); j++) {
-			if(strcmp(s, yytfix[j].have) == 0) {
-				yytname[i] = yytfix[j].want;
-				goto loop;
-			}
-		}
-
-		// turn 'x' into x.
-		if(s[0] == '\'') {
-			t = strdup(s+1);
-			t[strlen(t)-1] = '\0';
-			yytname[i] = t;
-		}
-	loop:;
-	}		
-}
-
-static void
-pkgnotused(int lineno, Strlit *path, char *name)
-{
-	char *elem;
-	
-	// 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 = strrchr(path->s, '/');
-	if(elem != nil)
-		elem++;
-	else
-		elem = path->s;
-	if(name == nil || strcmp(elem, name) == 0)
-		yyerrorl(lineno, "imported and not used: \"%Z\"", path);
-	else
-		yyerrorl(lineno, "imported and not used: \"%Z\" as %s", path, name);
-}
-
-void
-mkpackage(char* pkgname)
-{
-	Sym *s;
-	int32 h;
-	char *p, *q;
-
-	if(localpkg->name == nil) {
-		if(strcmp(pkgname, "_") == 0)
-			yyerror("invalid package name _");
-		localpkg->name = pkgname;
-	} else {
-		if(strcmp(pkgname, localpkg->name) != 0)
-			yyerror("package %s; expected %s", pkgname, localpkg->name);
-		for(h=0; h<NHASH; h++) {
-			for(s = hash[h]; s != S; s = s->link) {
-				if(s->def == N || s->pkg != localpkg)
-					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)
-						pkgnotused(s->def->lineno, s->def->pkg->path, s->name);
-					s->def = N;
-					continue;
-				}
-				if(s->def->sym != s) {
-					// throw away top-level name left over
-					// from previous import . "x"
-					if(s->def->pack != N && !s->def->pack->used && !nsyntaxerrors) {
-						pkgnotused(s->def->pack->lineno, s->def->pack->pkg->path, nil);
-						s->def->pack->used = 1;
-					}
-					s->def = N;
-					continue;
-				}
-			}
-		}
-	}
-
-	if(outfile == nil) {
-		p = strrchr(infile, '/');
-		if(ctxt->windows) {
-			q = strrchr(infile, '\\');
-			if(q > p)
-				p = q;
-		}
-		if(p == nil)
-			p = infile;
-		else
-			p = p+1;
-		snprint(namebuf, sizeof(namebuf), "%s", p);
-		p = strrchr(namebuf, '.');
-		if(p != nil)
-			*p = 0;
-		outfile = smprint("%s.%c", namebuf, thechar);
-	}
-}
diff --git a/src/cmd/gc/md5.c b/src/cmd/gc/md5.c
deleted file mode 100644
index 46cb6b7..0000000
--- a/src/cmd/gc/md5.c
+++ /dev/null
@@ -1,302 +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.
-
-// 64-bit MD5 (does full MD5 but returns 64 bits only).
-// Translation of ../../crypto/md5/md5*.go.
-
-#include <u.h>
-#include <libc.h>
-#include "go.h"
-#include "md5.h"
-
-static int md5block(MD5 *dig, uchar *p, int nn);
-
-enum {
-	_Chunk = 64
-};
-
-#define _Init0 0x67452301
-#define _Init1 0xEFCDAB89
-#define _Init2 0x98BADCFE
-#define _Init3 0x10325476
-/*c2go
-enum {
-	_Init0 = 0x67452301,
-	_Init1 = 0xEFCDAB89,
-	_Init2 = 0x98BADCFE,
-	_Init3 = 0x10325476
-};
-*/
-	
-void
-md5reset(MD5 *d)
-{
-	d->s[0] = _Init0;
-	d->s[1] = _Init1;
-	d->s[2] = _Init2;
-	d->s[3] = _Init3;
-	d->nx = 0;
-	d->len = 0;
-}
-
-void
-md5write(MD5 *d, uchar *p, int nn)
-{
-	int i, n;
-
-	d->len += 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] = p[i];
-		d->nx += n;
-		if(d->nx == _Chunk) {
-			md5block(d, d->x, _Chunk);
-			d->nx = 0;
-		}
-		p += n;
-		nn -= n;
-	}
-	n = md5block(d, p, nn);
-	p += n;
-	nn -= n;
-	if(nn > 0) {
-		for(i=0; i<nn; i++)
-			d->x[i] = p[i];
-		d->nx = nn;
-	}
-}
-
-uint64
-md5sum(MD5 *d, uint64 *hi)
-{
-	uchar tmp[64];
-	int i;
-	uint64 len;
-
-	// Padding.  Add a 1 bit and 0 bits until 56 bytes mod 64.
-	len = d->len;
-	memset(tmp, 0, sizeof tmp);
-	tmp[0] = 0x80;
-	if(len%64 < 56)
-		md5write(d, tmp, 56-len%64);
-	else
-		md5write(d, tmp, 64+56-len%64);
-
-	// Length in bits.
-	len <<= 3;
-	for(i=0; i<8; i++)
-		tmp[i] = len>>(8*i);
-	md5write(d, tmp, 8);
-
-	if(d->nx != 0)
-		fatal("md5sum");
-
-	if(hi != nil)
-		*hi = d->s[2] | ((uint64)d->s[3]<<32);
-	return 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))).
-static uint32 table[64] = {
-	// 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,
-};
-
-static uint32 shift1[] = { 7, 12, 17, 22 };
-static uint32 shift2[] = { 5, 9, 14, 20 };
-static uint32 shift3[] = { 4, 11, 16, 23 };
-static uint32 shift4[] = { 6, 10, 15, 21 };
-
-static int
-md5block(MD5 *dig, uchar *p, int nn)
-{
-	uint32 a, b, c, d, aa, bb, cc, dd;
-	int i, j, n;
-	uint32 X[16];
-
-	a = dig->s[0];
-	b = dig->s[1];
-	c = dig->s[2];
-	d = dig->s[3];
-	n = 0;
-
-	while(nn >= _Chunk) {
-		aa = a;
-		bb = b;
-		cc = c;
-		dd = d;
-
-		for(i=0; i<16; i++) {
-			j = i*4;
-			X[i] = p[j] | (p[j+1]<<8) | (p[j+2]<<16) | ((uint32)p[j+3]<<24);
-		}
-
-		// Round 1.
-		for(i=0; i<16; i++) {
-			uint32 x, t, s, f;
-			x = i;
-			t = 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++) {
-			uint32 x, t, s, g;
-
-			x = (1+5*i)%16;
-			t = 16+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++) {
-			uint32 x, t, s, h;
-
-			x = (5+3*i)%16;
-			t = 32+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++) {
-			uint32 x, s, t, ii;
-
-			x = (7*i)%16;
-			s = shift4[i%4];
-			t = 48+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 += _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/gc/md5.h b/src/cmd/gc/md5.h
deleted file mode 100644
index 5a60106..0000000
--- a/src/cmd/gc/md5.h
+++ /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.
-
-typedef struct MD5 MD5;
-struct MD5
-{
-	uint32 s[4];
-	uchar x[64];
-	int nx;
-	uint64 len;
-};
-
-void md5reset(MD5*);
-void md5write(MD5*, uchar*, int);
-uint64 md5sum(MD5*, uint64*);
diff --git a/src/cmd/gc/mkbuiltin b/src/cmd/gc/mkbuiltin
deleted file mode 100755
index 1dab1c9..0000000
--- a/src/cmd/gc/mkbuiltin
+++ /dev/null
@@ -1,32 +0,0 @@
-#!/bin/sh
-# 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.
-
-# Generate builtin.c from $* (runtime.go and unsafe.go).
-# Run this after changing runtime.go and unsafe.go
-# or after changing the export metadata format in the compiler.
-# Either way, you need to have a working compiler binary first.
-
-set -e
-
-eval $(go tool dist env)
-if [ -z "$GOCHAR" ]; then
-	echo 'missing $GOCHAR - go tool dist failed?' 1>&2
-	exit 1
-fi
-
-GC=${GOCHAR}g
-gcc -o mkbuiltin1 mkbuiltin1.c
-rm -f _builtin.c
-echo "// AUTO-GENERATED by mkbuiltin; DO NOT EDIT" >>_builtin.c
-for i in runtime unsafe
-do
-	go tool $GC -A $i.go
-	O=$GOCHAR ./mkbuiltin1 $i >>_builtin.c
-done
-
-# If _builtin.c has changed vs builtin.c,
-# check in the new change.
-cmp -s _builtin.c builtin.c || cp _builtin.c builtin.c
-rm _builtin.c mkbuiltin1 unsafe.$GOCHAR runtime.$GOCHAR
diff --git a/src/cmd/gc/mkbuiltin1.c b/src/cmd/gc/mkbuiltin1.c
deleted file mode 100644
index 69027fd..0000000
--- a/src/cmd/gc/mkbuiltin1.c
+++ /dev/null
@@ -1,102 +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.
-
-// +build ignore
-
-// Compile .go file, import data from .6 file, and generate C string version.
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <stdarg.h>
-
-void esc(char*);
-void fatal(char*, ...);
-
-int
-main(int argc, char **argv)
-{
-	char *name;
-	FILE *fin;
-	char buf[1024], initfunc[1024], *p, *q;
-
-	if(argc != 2) {
-		fprintf(stderr, "usage: mkbuiltin1 sys\n");
-		fatal("in file $1.6 s/PACKAGE/$1/");
-	}
-
-	name = argv[1];
-	snprintf(initfunc, sizeof(initfunc), "init_%s_function", name);
-
-	snprintf(buf, sizeof(buf), "%s.%s", name, getenv("O"));
-	if((fin = fopen(buf, "r")) == NULL) {
-		fatal("open %s: %s", buf, strerror(errno));
-	}
-
-	// look for $$ that introduces imports
-	while(fgets(buf, sizeof buf, fin) != NULL)
-		if(strstr(buf, "$$"))
-			goto begin;
-	fatal("did not find beginning of imports");
-
-begin:
-	printf("char *%simport =\n", name);
-
-	// process imports, stopping at $$ that closes them
-	while(fgets(buf, sizeof buf, fin) != NULL) {
-		buf[strlen(buf)-1] = 0;	// chop \n
-		if(strstr(buf, "$$"))
-			goto end;
-
-		// chop leading white space
-		for(p=buf; *p==' ' || *p == '\t'; p++)
-			;
-
-		// cut out decl of init_$1_function - it doesn't exist
-		if(strstr(buf, initfunc))
-			continue;
-
-		// sys.go claims to be in package PACKAGE to avoid
-		// conflicts during "6g sys.go".  rename PACKAGE to $2.
-		printf("\t\"");
-		while((q = strstr(p, "PACKAGE")) != NULL) {
-			*q = 0;
-			esc(p);	// up to the substitution
-			printf("%s", name);	// the sub name
-			p = q+7;		// continue with rest
-		}
-
-		esc(p);
-		printf("\\n\"\n");
-	}
-	fatal("did not find end of imports");
-
-end:
-	printf("\t\"$$\\n\";\n");
-	return 0;
-}
-
-void
-esc(char *p)
-{
-	for(; *p; p++) {
-		if(*p == '\\' || *p == '\"')
-			printf("\\");
-		putchar(*p);
-	}
-}
-
-void
-fatal(char *msg, ...)
-{
-	va_list arg;
-	
-	va_start(arg, msg);
-	fprintf(stderr, "fatal: ");
-	vfprintf(stderr, msg, arg);
-	fprintf(stderr, "\n");
-	exit(2);
-}
diff --git a/src/cmd/gc/mkopnames b/src/cmd/gc/mkopnames
deleted file mode 100755
index d3f27e8..0000000
--- a/src/cmd/gc/mkopnames
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/bin/sh
-# 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.
-
-# Disable colored grep if user has it set to --color=always.
-# (Arguably user error.)
-export GREP_OPTIONS=""
-
-echo '// auto generated by mkopnames'
-echo 'static char*'
-echo 'opnames[] = '
-echo '{'
-sed -n '/OXXX/,/OEND/p' go.h |
-	cpp |
-	sed 's!//.*!!; /^#/d'  |
-	tr ' ' '\012' |
-	tr -d ' \011,' |
-	grep . |
-	sort |
-	grep -v '^OEND$' |
-	sed 's/O//; s/.*/	[O&] =	"&",/'
-echo '};'
-
diff --git a/src/cmd/gc/mparith1.c b/src/cmd/gc/mparith1.c
deleted file mode 100644
index d33a81e..0000000
--- a/src/cmd/gc/mparith1.c
+++ /dev/null
@@ -1,641 +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	<u.h>
-#include	<libc.h>
-#include	"go.h"
-
-/// uses arithmetic
-
-int
-mpcmpfixflt(Mpint *a, Mpflt *b)
-{
-	char buf[500];
-	Mpflt c;
-
-	snprint(buf, sizeof(buf), "%B", a);
-	mpatoflt(&c, buf);
-	return mpcmpfltflt(&c, b);
-}
-
-int
-mpcmpfltfix(Mpflt *a, Mpint *b)
-{
-	char buf[500];
-	Mpflt c;
-
-	snprint(buf, sizeof(buf), "%B", b);
-	mpatoflt(&c, buf);
-	return mpcmpfltflt(a, &c);
-}
-
-int
-mpcmpfixfix(Mpint *a, Mpint *b)
-{
-	Mpint c;
-
-	mpmovefixfix(&c, a);
-	mpsubfixfix(&c, b);
-	return mptestfix(&c);
-}
-
-int
-mpcmpfixc(Mpint *b, vlong c)
-{
-	Mpint c1;
-
-	mpmovecfix(&c1, c);
-	return mpcmpfixfix(b, &c1);
-}
-
-int
-mpcmpfltflt(Mpflt *a, Mpflt *b)
-{
-	Mpflt c;
-
-	mpmovefltflt(&c, a);
-	mpsubfltflt(&c, b);
-	return mptestflt(&c);
-}
-
-int
-mpcmpfltc(Mpflt *b, double c)
-{
-	Mpflt a;
-
-	mpmovecflt(&a, c);
-	return mpcmpfltflt(b, &a);
-}
-
-void
-mpsubfixfix(Mpint *a, Mpint *b)
-{
-	mpnegfix(a);
-	mpaddfixfix(a, b, 0);
-	mpnegfix(a);
-}
-
-void
-mpsubfltflt(Mpflt *a, Mpflt *b)
-{
-	mpnegflt(a);
-	mpaddfltflt(a, b);
-	mpnegflt(a);
-}
-
-void
-mpaddcfix(Mpint *a, vlong c)
-{
-	Mpint b;
-
-	mpmovecfix(&b, c);
-	mpaddfixfix(a, &b, 0);
-}
-
-void
-mpaddcflt(Mpflt *a, double c)
-{
-	Mpflt b;
-
-	mpmovecflt(&b, c);
-	mpaddfltflt(a, &b);
-}
-
-void
-mpmulcfix(Mpint *a, vlong c)
-{
-	Mpint b;
-
-	mpmovecfix(&b, c);
-	mpmulfixfix(a, &b);
-}
-
-void
-mpmulcflt(Mpflt *a, double c)
-{
-	Mpflt b;
-
-	mpmovecflt(&b, c);
-	mpmulfltflt(a, &b);
-}
-
-void
-mpdivfixfix(Mpint *a, Mpint *b)
-{
-	Mpint q, r;
-
-	mpdivmodfixfix(&q, &r, a, b);
-	mpmovefixfix(a, &q);
-}
-
-void
-mpmodfixfix(Mpint *a, Mpint *b)
-{
-	Mpint q, r;
-
-	mpdivmodfixfix(&q, &r, a, b);
-	mpmovefixfix(a, &r);
-}
-
-void
-mpcomfix(Mpint *a)
-{
-	Mpint b;
-
-	mpmovecfix(&b, 1);
-	mpnegfix(a);
-	mpsubfixfix(a, &b);
-}
-
-void
-mpmovefixflt(Mpflt *a, Mpint *b)
-{
-	a->val = *b;
-	a->exp = 0;
-	mpnorm(a);
-}
-
-// convert (truncate) b to a.
-// return -1 (but still convert) if b was non-integer.
-static int
-mpexactfltfix(Mpint *a, Mpflt *b)
-{
-	Mpflt f;
-
-	*a = b->val;
-	mpshiftfix(a, b->exp);
-	if(b->exp < 0) {
-		f.val = *a;
-		f.exp = 0;
-		mpnorm(&f);
-		if(mpcmpfltflt(b, &f) != 0)
-			return -1;
-	}
-	return 0;
-}
-
-int
-mpmovefltfix(Mpint *a, Mpflt *b)
-{
-	Mpflt f;
-	int i;
-
-	if(mpexactfltfix(a, b) == 0)
-		return 0;
-
-	// try rounding down a little
-	f = *b;
-	f.val.a[0] = 0;
-	if(mpexactfltfix(a, &f) == 0)
-		return 0;
-
-	// try rounding up a little
-	for(i=1; i<Mpprec; i++) {
-		f.val.a[i]++;
-		if(f.val.a[i] != Mpbase)
-			break;
-		f.val.a[i] = 0;
-	}
-	mpnorm(&f);
-	if(mpexactfltfix(a, &f) == 0)
-		return 0;
-
-	return -1;
-}
-
-void
-mpmovefixfix(Mpint *a, Mpint *b)
-{
-	*a = *b;
-}
-
-void
-mpmovefltflt(Mpflt *a, Mpflt *b)
-{
-	*a = *b;
-}
-
-static	double	tab[] = { 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7 };
-static void
-mppow10flt(Mpflt *a, int p)
-{
-	if(p < 0)
-		abort();
-	if(p < nelem(tab)) {
-		mpmovecflt(a, tab[p]);
-		return;
-	}
-	mppow10flt(a, p>>1);
-	mpmulfltflt(a, a);
-	if(p & 1)
-		mpmulcflt(a, 10);
-}
-
-static void
-mphextofix(Mpint *a, char *s, int n)
-{
-	char *hexdigitp, *end, c;
-	long d;
-	int bit;
-
-	while(*s == '0') {
-		s++;
-		n--;
-	}
-
-	// overflow
-	if(4*n > Mpscale*Mpprec) {
-		a->ovf = 1;
-		return;
-	}
-
-	end = s+n-1;
-	for(hexdigitp=end; hexdigitp>=s; hexdigitp--) {
-		c = *hexdigitp;
-		if(c >= '0' && c <= '9')
-			d = c-'0';
-		else if(c >= 'A' && c <= 'F')
-			d = c-'A'+10;
-		else
-			d = c-'a'+10;
-
-		bit = 4*(end - hexdigitp);
-		while(d > 0) {
-			if(d & 1)
-				a->a[bit/Mpscale] |= (long)1 << (bit%Mpscale);
-			bit++;
-			d = d >> 1;
-		}
-	}
-}
-
-//
-// floating point input
-// required syntax is [+-]d*[.]d*[e[+-]d*] or [+-]0xH*[e[+-]d*]
-//
-void
-mpatoflt(Mpflt *a, char *as)
-{
-	Mpflt b;
-	int dp, c, f, ef, ex, eb, base;
-	char *s, *start;
-
-	while(*as == ' ' || *as == '\t')
-		as++;
-
-	/* determine base */
-	s = as;
-	base = -1;
-	while(base == -1) {
-		switch(*s++) {
-		case '-':
-		case '+':
-			break;
-
-		case '0':
-			if(*s == 'x')
-				base = 16;
-			else
-				base = 10;
-			break;
-
-		default:
-			base = 10;
-		}
-	}
-
-	s = as;
-	dp = 0;		/* digits after decimal point */
-	f = 0;		/* sign */
-	ex = 0;		/* exponent */
-	eb = 0;		/* binary point */
-
-	mpmovecflt(a, 0.0);
-	if(base == 16) {
-		start = nil;
-		for(;;) {
-			c = *s;
-			if(c == '-') {
-				f = 1;
-				s++;
-			}
-			else if(c == '+') {
-				s++;
-			}
-			else if(c == '0' && s[1] == 'x') {
-				s += 2;
-				start = s;
-			}
-			else if((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) {
-				s++;
-			}
-			else {
-				break;
-			}
-		}
-		if(start == nil)
-			goto bad;
-
-		mphextofix(&a->val, start, s-start);
-		if(a->val.ovf)
-			goto bad;
-		a->exp = 0;
-		mpnorm(a);
-	}
-	for(;;) {
-		switch(c = *s++) {
-		default:
-			goto bad;
-
-		case '-':
-			f = 1;
-
-		case ' ':
-		case '\t':
-		case '+':
-			continue;
-
-		case '.':
-			if(base == 16)
-				goto bad;
-			dp = 1;
-			continue;
-
-		case '1':
-		case '2':
-		case '3':
-		case '4':
-		case '5':
-		case '6':
-		case '7':
-		case '8':
-		case '9':
-		case '0':
-			mpmulcflt(a, 10);
-			mpaddcflt(a, c-'0');
-			if(dp)
-				dp++;
-			continue;
-
-		case 'P':
-		case 'p':
-			eb = 1;
-
-		case 'E':
-		case 'e':
-			ex = 0;
-			ef = 0;
-			for(;;) {
-				c = *s++;
-				if(c == '+' || c == ' ' || c == '\t')
-					continue;
-				if(c == '-') {
-					ef = 1;
-					continue;
-				}
-				if(c >= '0' && c <= '9') {
-					ex = ex*10 + (c-'0');
-					if(ex > 1e8) {
-						yyerror("constant exponent out of range: %s", as);
-						errorexit();
-					}
-					continue;
-				}
-				break;
-			}
-			if(ef)
-				ex = -ex;
-
-		case 0:
-			break;
-		}
-		break;
-	}
-
-	if(eb) {
-		if(dp)
-			goto bad;
-		mpsetexp(a, a->exp+ex);
-		goto out;
-	}
-
-	if(dp)
-		dp--;
-	if(mpcmpfltc(a, 0.0) != 0) {
-		if(ex >= dp) {
-			mppow10flt(&b, ex-dp);
-			mpmulfltflt(a, &b);
-		} else {
-			// 4 approximates least_upper_bound(log2(10)).
-			if(dp-ex >= (1<<(8*sizeof(dp)-3)) || (short)(4*(dp-ex)) != 4*(dp-ex)) {
-				mpmovecflt(a, 0.0);
-			}
-			else {
-				mppow10flt(&b, dp-ex);
-				mpdivfltflt(a, &b);
-			}
-		}
-	}
-
-out:
-	if(f)
-		mpnegflt(a);
-	return;
-
-bad:
-	yyerror("constant too large: %s", as);
-	mpmovecflt(a, 0.0);
-}
-
-//
-// fixed point input
-// required syntax is [+-][0[x]]d*
-//
-void
-mpatofix(Mpint *a, char *as)
-{
-	int c, f;
-	char *s, *s0;
-
-	s = as;
-	f = 0;
-	mpmovecfix(a, 0);
-
-	c = *s++;
-	switch(c) {
-	case '-':
-		f = 1;
-
-	case '+':
-		c = *s++;
-		if(c != '0')
-			break;
-
-	case '0':
-		goto oct;
-	}
-
-	while(c) {
-		if(c >= '0' && c <= '9') {
-			mpmulcfix(a, 10);
-			mpaddcfix(a, c-'0');
-			c = *s++;
-			continue;
-		}
-		goto bad;
-	}
-	goto out;
-
-oct:
-	c = *s++;
-	if(c == 'x' || c == 'X')
-		goto hex;
-	while(c) {
-		if(c >= '0' && c <= '7') {
-			mpmulcfix(a, 8);
-			mpaddcfix(a, c-'0');
-			c = *s++;
-			continue;
-		}
-		goto bad;
-	}
-	goto out;
-
-hex:
-	s0 = s;
-	c = *s;
-	while(c) {
-		if((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) {
-			s++;
-			c = *s;
-			continue;
-		}
-		goto bad;
-	}
-	mphextofix(a, s0, s-s0);
-	if(a->ovf)
-		goto bad;
-
-out:
-	if(f)
-		mpnegfix(a);
-	return;
-
-bad:
-	yyerror("constant too large: %s", as);
-	mpmovecfix(a, 0);
-}
-
-int
-Bconv(Fmt *fp)
-{
-	char buf[500], *p;
-	Mpint *xval, q, r, ten, sixteen;
-	int f, digit;
-
-	xval = va_arg(fp->args, Mpint*);
-	mpmovefixfix(&q, xval);
-	f = 0;
-	if(mptestfix(&q) < 0) {
-		f = 1;
-		mpnegfix(&q);
-	}
-
-	p = &buf[sizeof(buf)];
-	*--p = 0;
-	if(fp->flags & FmtSharp) {
-		// Hexadecimal
-		mpmovecfix(&sixteen, 16);
-		for(;;) {
-			mpdivmodfixfix(&q, &r, &q, &sixteen);
-			digit = mpgetfix(&r);
-			if(digit < 10)
-				*--p = digit + '0';
-			else
-				*--p = digit - 10 + 'A';
-			if(mptestfix(&q) <= 0)
-				break;
-		}
-		*--p = 'x';
-		*--p = '0';
-	} else {
-		// Decimal
-		mpmovecfix(&ten, 10);
-		for(;;) {
-			mpdivmodfixfix(&q, &r, &q, &ten);
-			*--p = mpgetfix(&r) + '0';
-			if(mptestfix(&q) <= 0)
-				break;
-		}
-	}
-	if(f)
-		*--p = '-';
-	return fmtstrcpy(fp, p);
-}
-
-int
-Fconv(Fmt *fp)
-{
-	char buf[500];
-	Mpflt *fvp, fv;
-	double d, dexp;
-	int exp;
-
-	fvp = va_arg(fp->args, Mpflt*);
-	if(fp->flags & FmtSharp) {
-		// alternate form - decimal for error messages.
-		// for well in range, convert to double and use print's %g
-		exp = fvp->exp + sigfig(fvp)*Mpscale;
-		if(-900 < exp && exp < 900) {
-			d = mpgetflt(fvp);
-			if(d >= 0 && (fp->flags & FmtSign))
-				fmtprint(fp, "+");
-			return fmtprint(fp, "%g", d);
-		}
-		
-		// very out of range. compute decimal approximation by hand.
-		// decimal exponent
-		dexp = fvp->exp * 0.301029995663981195; // log_10(2)
-		exp = (int)dexp;
-		// decimal mantissa
-		fv = *fvp;
-		fv.val.neg = 0;
-		fv.exp = 0;
-		d = mpgetflt(&fv);
-		d *= pow(10, dexp-exp);
-		while(d >= 9.99995) {
-			d /= 10;
-			exp++;
-		}
-		if(fvp->val.neg)
-			fmtprint(fp, "-");
-		else if(fp->flags & FmtSign)
-			fmtprint(fp, "+");
-		return fmtprint(fp, "%.5fe+%d", d, exp);
-	}
-
-	if(sigfig(fvp) == 0) {
-		snprint(buf, sizeof(buf), "0p+0");
-		goto out;
-	}
-	fv = *fvp;
-
-	while(fv.val.a[0] == 0) {
-		mpshiftfix(&fv.val, -Mpscale);
-		fv.exp += Mpscale;
-	}
-	while((fv.val.a[0]&1) == 0) {
-		mpshiftfix(&fv.val, -1);
-		fv.exp += 1;
-	}
-
-	if(fv.exp >= 0) {
-		snprint(buf, sizeof(buf), "%#Bp+%d", &fv.val, fv.exp);
-		goto out;
-	}
-	snprint(buf, sizeof(buf), "%#Bp-%d", &fv.val, -fv.exp);
-
-out:
-	return fmtstrcpy(fp, buf);
-}
diff --git a/src/cmd/gc/mparith2.c b/src/cmd/gc/mparith2.c
deleted file mode 100644
index fd9f591..0000000
--- a/src/cmd/gc/mparith2.c
+++ /dev/null
@@ -1,716 +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	<u.h>
-#include	<libc.h>
-#include	"go.h"
-
-//
-// return the significant
-// words of the argument
-//
-static int
-mplen(Mpint *a)
-{
-	int i, n;
-	long *a1;
-
-	n = -1;
-	a1 = &a->a[0];
-	for(i=0; i<Mpprec; i++) {
-		if(*a1++ != 0)
-			n = i;
-	}
-	return n+1;
-}
-
-//
-// left shift mpint by one
-// ignores sign
-//
-static void
-mplsh(Mpint *a, int quiet)
-{
-	long *a1, x;
-	int i, c;
-
-	c = 0;
-	a1 = &a->a[0];
-	for(i=0; i<Mpprec; i++) {
-		x = (*a1 << 1) + c;
-		c = 0;
-		if(x >= Mpbase) {
-			x -= Mpbase;
-			c = 1;
-		}
-		*a1++ = x;
-	}
-	a->ovf = c;
-	if(a->ovf && !quiet)
-		yyerror("constant shift overflow");
-}
-
-//
-// left shift mpint by Mpscale
-// ignores sign
-//
-static void
-mplshw(Mpint *a, int quiet)
-{
-	long *a1;
-	int i;
-
-	a1 = &a->a[Mpprec-1];
-	if(*a1) {
-		a->ovf = 1;
-		if(!quiet)
-			yyerror("constant shift overflow");
-	}
-	for(i=1; i<Mpprec; i++) {
-		a1[0] = a1[-1];
-		a1--;
-	}
-	a1[0] = 0;
-}
-
-//
-// right shift mpint by one
-// ignores sign and overflow
-//
-static void
-mprsh(Mpint *a)
-{
-	long *a1, x, lo;
-	int i, c;
-
-	c = 0;
-	lo = a->a[0] & 1;
-	a1 = &a->a[Mpprec];
-	for(i=0; i<Mpprec; i++) {
-		x = *--a1;
-		*a1 = (x + c) >> 1;
-		c = 0;
-		if(x & 1)
-			c = Mpbase;
-	}
-	if(a->neg && lo != 0)
-		mpaddcfix(a, -1);
-}
-
-//
-// right shift mpint by Mpscale
-// ignores sign and overflow
-//
-static void
-mprshw(Mpint *a)
-{
-	long *a1, lo;
-	int i;
-
-	lo = a->a[0];
-	a1 = &a->a[0];
-	for(i=1; i<Mpprec; i++) {
-		a1[0] = a1[1];
-		a1++;
-	}
-	a1[0] = 0;
-	if(a->neg && lo != 0)
-		mpaddcfix(a, -1);
-}
-
-//
-// return the sign of (abs(a)-abs(b))
-//
-static int
-mpcmp(Mpint *a, Mpint *b)
-{
-	long x, *a1, *b1;
-	int i;
-
-	if(a->ovf || b->ovf) {
-		if(nsavederrors+nerrors == 0)
-			yyerror("ovf in cmp");
-		return 0;
-	}
-
-	a1 = &a->a[0] + Mpprec;
-	b1 = &b->a[0] + Mpprec;
-
-	for(i=0; i<Mpprec; i++) {
-		x = *--a1 - *--b1;
-		if(x > 0)
-			return +1;
-		if(x < 0)
-			return -1;
-	}
-	return 0;
-}
-
-//
-// negate a
-// ignore sign and ovf
-//
-static void
-mpneg(Mpint *a)
-{
-	long x, *a1;
-	int i, c;
-
-	a1 = &a->a[0];
-	c = 0;
-	for(i=0; i<Mpprec; i++) {
-		x = -*a1 -c;
-		c = 0;
-		if(x < 0) {
-			x += Mpbase;
-			c = 1;
-		}
-		*a1++ = x;
-	}
-}
-
-// shift left by s (or right by -s)
-void
-mpshiftfix(Mpint *a, int s)
-{
-	if(s >= 0) {
-		while(s >= Mpscale) {
-			mplshw(a, 0);
-			s -= Mpscale;
-		}
-		while(s > 0) {
-			mplsh(a, 0);
-			s--;
-		}
-	} else {
-		s = -s;
-		while(s >= Mpscale) {
-			mprshw(a);
-			s -= Mpscale;
-		}
-		while(s > 0) {
-			mprsh(a);
-			s--;
-		}
-	}
-}
-
-/// implements fix arihmetic
-
-void
-mpaddfixfix(Mpint *a, Mpint *b, int quiet)
-{
-	int i, c;
-	long x, *a1, *b1;
-
-	if(a->ovf || b->ovf) {
-		if(nsavederrors+nerrors == 0)
-			yyerror("ovf in mpaddxx");
-		a->ovf = 1;
-		return;
-	}
-
-	c = 0;
-	a1 = &a->a[0];
-	b1 = &b->a[0];
-	if(a->neg != b->neg)
-		goto sub;
-
-	// perform a+b
-	for(i=0; i<Mpprec; i++) {
-		x = *a1 + *b1++ + c;
-		c = 0;
-		if(x >= Mpbase) {
-			x -= Mpbase;
-			c = 1;
-		}
-		*a1++ = x;
-	}
-	a->ovf = c;
-	if(a->ovf && !quiet)
-		yyerror("constant addition overflow");
-
-	return;
-
-sub:
-	// perform a-b
-	switch(mpcmp(a, b)) {
-	case 0:
-		mpmovecfix(a, 0);
-		break;
-
-	case 1:
-		for(i=0; i<Mpprec; i++) {
-			x = *a1 - *b1++ - c;
-			c = 0;
-			if(x < 0) {
-				x += Mpbase;
-				c = 1;
-			}
-			*a1++ = x;
-		}
-		break;
-
-	case -1:
-		a->neg ^= 1;
-		for(i=0; i<Mpprec; i++) {
-			x = *b1++ - *a1 - c;
-			c = 0;
-			if(x < 0) {
-				x += Mpbase;
-				c = 1;
-			}
-			*a1++ = x;
-		}
-		break;
-	}
-}
-
-void
-mpmulfixfix(Mpint *a, Mpint *b)
-{
-
-	int i, j, na, nb;
-	long *a1, x;
-	Mpint s, q;
-
-	if(a->ovf || b->ovf) {
-		if(nsavederrors+nerrors == 0)
-			yyerror("ovf in mpmulfixfix");
-		a->ovf = 1;
-		return;
-	}
-
-	// pick the smaller
-	// to test for bits
-	na = mplen(a);
-	nb = mplen(b);
-	if(na > nb) {
-		mpmovefixfix(&s, a);
-		a1 = &b->a[0];
-		na = nb;
-	} else {
-		mpmovefixfix(&s, b);
-		a1 = &a->a[0];
-	}
-	s.neg = 0;
-
-	mpmovecfix(&q, 0);
-	for(i=0; i<na; i++) {
-		x = *a1++;
-		for(j=0; j<Mpscale; j++) {
-			if(x & 1) {
-				if(s.ovf) {
-					q.ovf = 1;
-					goto out;
-				}
-				mpaddfixfix(&q, &s, 1);
-				if(q.ovf)
-					goto out;
-			}
-			mplsh(&s, 1);
-			x >>= 1;
-		}
-	}
-
-out:
-	q.neg = a->neg ^ b->neg;
-	mpmovefixfix(a, &q);
-	if(a->ovf)
-		yyerror("constant multiplication overflow");
-}
-
-void
-mpmulfract(Mpint *a, Mpint *b)
-{
-
-	int i, j;
-	long *a1, x;
-	Mpint s, q;
-
-	if(a->ovf || b->ovf) {
-		if(nsavederrors+nerrors == 0)
-			yyerror("ovf in mpmulflt");
-		a->ovf = 1;
-		return;
-	}
-
-	mpmovefixfix(&s, b);
-	a1 = &a->a[Mpprec];
-	s.neg = 0;
-	mpmovecfix(&q, 0);
-
-	x = *--a1;
-	if(x != 0)
-		yyerror("mpmulfract not normal");
-
-	for(i=0; i<Mpprec-1; i++) {
-		x = *--a1;
-		if(x == 0) {
-			mprshw(&s);
-			continue;
-		}
-		for(j=0; j<Mpscale; j++) {
-			x <<= 1;
-			if(x & Mpbase)
-				mpaddfixfix(&q, &s, 1);
-			mprsh(&s);
-		}
-	}
-
-	q.neg = a->neg ^ b->neg;
-	mpmovefixfix(a, &q);
-	if(a->ovf)
-		yyerror("constant multiplication overflow");
-}
-
-void
-mporfixfix(Mpint *a, Mpint *b)
-{
-	int i;
-	long x, *a1, *b1;
-
-	x = 0;
-	if(a->ovf || b->ovf) {
-		if(nsavederrors+nerrors == 0)
-			yyerror("ovf in mporfixfix");
-		mpmovecfix(a, 0);
-		a->ovf = 1;
-		return;
-	}
-	if(a->neg) {
-		a->neg = 0;
-		mpneg(a);
-	}
-	if(b->neg)
-		mpneg(b);
-
-	a1 = &a->a[0];
-	b1 = &b->a[0];
-	for(i=0; i<Mpprec; i++) {
-		x = *a1 | *b1++;
-		*a1++ = x;
-	}
-
-	if(b->neg)
-		mpneg(b);
-	if(x & Mpsign) {
-		a->neg = 1;
-		mpneg(a);
-	}
-}
-
-void
-mpandfixfix(Mpint *a, Mpint *b)
-{
-	int i;
-	long x, *a1, *b1;
-
-	x = 0;
-	if(a->ovf || b->ovf) {
-		if(nsavederrors+nerrors == 0)
-			yyerror("ovf in mpandfixfix");
-		mpmovecfix(a, 0);
-		a->ovf = 1;
-		return;
-	}
-	if(a->neg) {
-		a->neg = 0;
-		mpneg(a);
-	}
-	if(b->neg)
-		mpneg(b);
-
-	a1 = &a->a[0];
-	b1 = &b->a[0];
-	for(i=0; i<Mpprec; i++) {
-		x = *a1 & *b1++;
-		*a1++ = x;
-	}
-
-	if(b->neg)
-		mpneg(b);
-	if(x & Mpsign) {
-		a->neg = 1;
-		mpneg(a);
-	}
-}
-
-void
-mpandnotfixfix(Mpint *a, Mpint *b)
-{
-	int i;
-	long x, *a1, *b1;
-
-	x = 0;
-	if(a->ovf || b->ovf) {
-		if(nsavederrors+nerrors == 0)
-			yyerror("ovf in mpandnotfixfix");
-		mpmovecfix(a, 0);
-		a->ovf = 1;
-		return;
-	}
-	if(a->neg) {
-		a->neg = 0;
-		mpneg(a);
-	}
-	if(b->neg)
-		mpneg(b);
-
-	a1 = &a->a[0];
-	b1 = &b->a[0];
-	for(i=0; i<Mpprec; i++) {
-		x = *a1 & ~*b1++;
-		*a1++ = x;
-	}
-
-	if(b->neg)
-		mpneg(b);
-	if(x & Mpsign) {
-		a->neg = 1;
-		mpneg(a);
-	}
-}
-
-void
-mpxorfixfix(Mpint *a, Mpint *b)
-{
-	int i;
-	long x, *a1, *b1;
-
-	x = 0;
-	if(a->ovf || b->ovf) {
-		if(nsavederrors+nerrors == 0)
-			yyerror("ovf in mporfixfix");
-		mpmovecfix(a, 0);
-		a->ovf = 1;
-		return;
-	}
-	if(a->neg) {
-		a->neg = 0;
-		mpneg(a);
-	}
-	if(b->neg)
-		mpneg(b);
-
-	a1 = &a->a[0];
-	b1 = &b->a[0];
-	for(i=0; i<Mpprec; i++) {
-		x = *a1 ^ *b1++;
-		*a1++ = x;
-	}
-
-	if(b->neg)
-		mpneg(b);
-	if(x & Mpsign) {
-		a->neg = 1;
-		mpneg(a);
-	}
-}
-
-void
-mplshfixfix(Mpint *a, Mpint *b)
-{
-	vlong s;
-
-	if(a->ovf || b->ovf) {
-		if(nsavederrors+nerrors == 0)
-			yyerror("ovf in mporfixfix");
-		mpmovecfix(a, 0);
-		a->ovf = 1;
-		return;
-	}
-	s = mpgetfix(b);
-	if(s < 0 || s >= Mpprec*Mpscale) {
-		yyerror("stupid shift: %lld", s);
-		mpmovecfix(a, 0);
-		return;
-	}
-
-	mpshiftfix(a, s);
-}
-
-void
-mprshfixfix(Mpint *a, Mpint *b)
-{
-	vlong s;
-
-	if(a->ovf || b->ovf) {
-		if(nsavederrors+nerrors == 0)
-			yyerror("ovf in mprshfixfix");
-		mpmovecfix(a, 0);
-		a->ovf = 1;
-		return;
-	}
-	s = mpgetfix(b);
-	if(s < 0 || s >= Mpprec*Mpscale) {
-		yyerror("stupid shift: %lld", s);
-		if(a->neg)
-			mpmovecfix(a, -1);
-		else
-			mpmovecfix(a, 0);
-		return;
-	}
-
-	mpshiftfix(a, -s);
-}
-
-void
-mpnegfix(Mpint *a)
-{
-	a->neg ^= 1;
-}
-
-vlong
-mpgetfix(Mpint *a)
-{
-	vlong v;
-
-	if(a->ovf) {
-		if(nsavederrors+nerrors == 0)
-			yyerror("constant overflow");
-		return 0;
-	}
-
-	v = (uvlong)a->a[0];
-	v |= (uvlong)a->a[1] << Mpscale;
-	v |= (uvlong)a->a[2] << (Mpscale+Mpscale);
-	if(a->neg)
-		v = -(uvlong)v;
-	return v;
-}
-
-void
-mpmovecfix(Mpint *a, vlong c)
-{
-	int i;
-	long *a1;
-	vlong x;
-
-	a->neg = 0;
-	a->ovf = 0;
-
-	x = c;
-	if(x < 0) {
-		a->neg = 1;
-		x = -(uvlong)x;
-	}
-
-	a1 = &a->a[0];
-	for(i=0; i<Mpprec; i++) {
-		*a1++ = x&Mpmask;
-		x >>= Mpscale;
-	}
-}
-
-void
-mpdivmodfixfix(Mpint *q, Mpint *r, Mpint *n, Mpint *d)
-{
-	int i, ns, ds;
-
-	ns = n->neg;
-	ds = d->neg;
-	n->neg = 0;
-	d->neg = 0;
-
-	mpmovefixfix(r, n);
-	mpmovecfix(q, 0);
-
-	// shift denominator until it
-	// is larger than numerator
-	for(i=0; i<Mpprec*Mpscale; i++) {
-		if(mpcmp(d, r) > 0)
-			break;
-		mplsh(d, 1);
-	}
-
-	// if it never happens
-	// denominator is probably zero
-	if(i >= Mpprec*Mpscale) {
-		q->ovf = 1;
-		r->ovf = 1;
-		n->neg = ns;
-		d->neg = ds;
-		yyerror("constant division overflow");
-		return;
-	}
-
-	// shift denominator back creating
-	// quotient a bit at a time
-	// when done the remaining numerator
-	// will be the remainder
-	for(; i>0; i--) {
-		mplsh(q, 1);
-		mprsh(d);
-		if(mpcmp(d, r) <= 0) {
-			mpaddcfix(q, 1);
-			mpsubfixfix(r, d);
-		}
-	}
-
-	n->neg = ns;
-	d->neg = ds;
-	r->neg = ns;
-	q->neg = ns^ds;
-}
-
-static int
-mpiszero(Mpint *a)
-{
-	long *a1;
-	int i;
-	a1 = &a->a[0] + Mpprec;
-	for(i=0; i<Mpprec; i++) {
-		if(*--a1 != 0)
-			return 0;
-	}
-	return 1;
-}
-
-void
-mpdivfract(Mpint *a, Mpint *b)
-{
-	Mpint n, d;
-	int i, j, neg;
-	long *a1, x;
-
-	mpmovefixfix(&n, a);	// numerator
-	mpmovefixfix(&d, b);	// denominator
-	a1 = &a->a[Mpprec];	// quotient
-
-	neg = n.neg ^ d.neg;
-	n.neg = 0;
-	d.neg = 0;
-	for(i=0; i<Mpprec; i++) {
-		x = 0;
-		for(j=0; j<Mpscale; j++) {
-			x <<= 1;
-			if(mpcmp(&d, &n) <= 0) {
-				if(!mpiszero(&d))
-					x |= 1;
-				mpsubfixfix(&n, &d);
-			}
-			mprsh(&d);
-		}
-		*--a1 = x;
-	}
-	a->neg = neg;
-}
-
-int
-mptestfix(Mpint *a)
-{
-	Mpint b;
-	int r;
-
-	mpmovecfix(&b, 0);
-	r = mpcmp(a, &b);
-	if(a->neg) {
-		if(r > 0)
-			return -1;
-		if(r < 0)
-			return +1;
-	}
-	return r;
-}
diff --git a/src/cmd/gc/mparith3.c b/src/cmd/gc/mparith3.c
deleted file mode 100644
index 6afd75c..0000000
--- a/src/cmd/gc/mparith3.c
+++ /dev/null
@@ -1,346 +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	<u.h>
-#include	<libc.h>
-#include	"go.h"
-
-/*
- * returns the leading non-zero
- * word of the number
- */
-int
-sigfig(Mpflt *a)
-{
-	int i;
-
-	for(i=Mpprec-1; i>=0; i--)
-		if(a->val.a[i] != 0)
-			break;
-//print("sigfig %d %d\n", i-z+1, z);
-	return i+1;
-}
-
-/*
- * sets the exponent.
- * a too large exponent is an error.
- * a too small exponent rounds the number to zero.
- */
-void
-mpsetexp(Mpflt *a, int exp) {
-	if((short)exp != exp) {
-		if(exp > 0) {
-			yyerror("float constant is too large");
-			a->exp = 0x7fff;
-		}
-		else {
-			mpmovecflt(a, 0);
-		}
-	}
-	else {
-		a->exp = exp;
-	}
-}
-
-/*
- * shifts the leading non-zero
- * word of the number to Mpnorm
- */
-void
-mpnorm(Mpflt *a)
-{
-	int s, os;
-	long x;
-
-	os = sigfig(a);
-	if(os == 0) {
-		// zero
-		a->exp = 0;
-		a->val.neg = 0;
-		return;
-	}
-
-	// this will normalize to the nearest word
-	x = a->val.a[os-1];
-	s = (Mpnorm-os) * Mpscale;
-
-	// further normalize to the nearest bit
-	for(;;) {
-		x <<= 1;
-		if(x & Mpbase)
-			break;
-		s++;
-		if(x == 0) {
-			// this error comes from trying to
-			// convert an Inf or something
-			// where the initial x=0x80000000
-			s = (Mpnorm-os) * Mpscale;
-			break;
-		}
-	}
-
-	mpshiftfix(&a->val, s);
-	mpsetexp(a, a->exp-s);
-}
-
-/// implements float arihmetic
-
-void
-mpaddfltflt(Mpflt *a, Mpflt *b)
-{
-	int sa, sb, s;
-	Mpflt c;
-
-	if(Mpdebug)
-		print("\n%F + %F", a, b);
-
-	sa = sigfig(a);
-	if(sa == 0) {
-		mpmovefltflt(a, b);
-		goto out;
-	}
-
-	sb = sigfig(b);
-	if(sb == 0)
-		goto out;
-
-	s = a->exp - b->exp;
-	if(s > 0) {
-		// a is larger, shift b right
-		mpmovefltflt(&c, b);
-		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);
-		mpsetexp(a, a->exp-s);
-		mpaddfixfix(&a->val, &b->val, 0);
-		goto out;
-	}
-	mpaddfixfix(&a->val, &b->val, 0);
-
-out:
-	mpnorm(a);
-	if(Mpdebug)
-		print(" = %F\n\n", a);
-}
-
-void
-mpmulfltflt(Mpflt *a, Mpflt *b)
-{
-	int sa, sb;
-
-	if(Mpdebug)
-		print("%F\n * %F\n", a, b);
-
-	sa = sigfig(a);
-	if(sa == 0) {
-		// zero
-		a->exp = 0;
-		a->val.neg = 0;
-		return;
-	}
-
-	sb = sigfig(b);
-	if(sb == 0) {
-		// zero
-		mpmovefltflt(a, b);
-		return;
-	}
-
-	mpmulfract(&a->val, &b->val);
-	mpsetexp(a, (a->exp + b->exp) + Mpscale*Mpprec - Mpscale - 1);
-
-	mpnorm(a);
-	if(Mpdebug)
-		print(" = %F\n\n", a);
-}
-
-void
-mpdivfltflt(Mpflt *a, Mpflt *b)
-{
-	int sa, sb;
-	Mpflt c;
-
-	if(Mpdebug)
-		print("%F\n / %F\n", a, b);
-
-	sb = sigfig(b);
-	if(sb == 0) {
-		// zero and ovfl
-		a->exp = 0;
-		a->val.neg = 0;
-		a->val.ovf = 1;
-		yyerror("constant division by zero");
-		return;
-	}
-
-	sa = sigfig(a);
-	if(sa == 0) {
-		// zero
-		a->exp = 0;
-		a->val.neg = 0;
-		return;
-	}
-
-	// adjust b to top
-	mpmovefltflt(&c, b);
-	mpshiftfix(&c.val, Mpscale);
-
-	// divide
-	mpdivfract(&a->val, &c.val);
-	mpsetexp(a, (a->exp-c.exp) - Mpscale*(Mpprec-1) + 1);
-
-	mpnorm(a);
-	if(Mpdebug)
-		print(" = %F\n\n", a);
-}
-
-static double
-mpgetfltN(Mpflt *a, int prec, int bias)
-{
-	int s, i, e, minexp;
-	uvlong v;
-	double f;
-
-	if(a->val.ovf && nsavederrors+nerrors == 0)
-		yyerror("mpgetflt ovf");
-
-	s = sigfig(a);
-	if(s == 0)
-		return 0;
-
-	if(s != Mpnorm) {
-		yyerror("mpgetflt norm");
-		mpnorm(a);
-	}
-
-	while((a->val.a[Mpnorm-1] & Mpsign) == 0) {
-		mpshiftfix(&a->val, 1);
-		mpsetexp(a, a->exp-1);	// can set 'a' to zero
-		s = sigfig(a);
-		if(s == 0)
-			return 0;
-	}
-
-	// pick up the mantissa, a rounding bit, and a tie-breaking bit in a uvlong
-	s = prec+2;
-	v = 0;
-	for(i=Mpnorm-1; s>=Mpscale; i--) {
-		v = (v<<Mpscale) | a->val.a[i];
-		s -= Mpscale;
-	}
-	if(s > 0) {
-		v = (v<<s) | (a->val.a[i]>>(Mpscale-s));
-		if((a->val.a[i]&((1<<(Mpscale-s))-1)) != 0)
-			v |= 1;
-		i--;
-	}
-	for(; i >= 0; i--) {
-		if(a->val.a[i] != 0)
-			v |= 1;
-	}
-
-	// gradual underflow
-	e = Mpnorm*Mpscale + a->exp - prec;
-	minexp = bias+1-prec+1;
-	if(e < minexp) {
-		s = minexp - e;
-		if(s > prec+1)
-			s = prec+1;
-		if((v & ((1ULL<<s)-1)) != 0)
-			v |= 1ULL<<s;
-		v >>= s;
-		e = minexp;
-	}
-	
-	// round to even
-	v |= (v&4)>>2;
-	v += v&1;
-	v >>= 2;
-
-	f = (double)(v);
-	f = ldexp(f, e);
-
-	if(a->val.neg)
-		f = -f;
-
-	return f;
-}
-
-double
-mpgetflt(Mpflt *a)
-{
-	return mpgetfltN(a, 53, -1023);
-}
-
-double
-mpgetflt32(Mpflt *a)
-{
-	return mpgetfltN(a, 24, -127);
-}
-
-void
-mpmovecflt(Mpflt *a, double c)
-{
-	int i;
-	double f;
-	long l;
-
-	if(Mpdebug)
-		print("\nconst %g", c);
-	mpmovecfix(&a->val, 0);
-	a->exp = 0;
-	if(c == 0)
-		goto out;
-	if(c < 0) {
-		a->val.neg = 1;
-		c = -c;
-	}
-
-	f = frexp(c, &i);
-	a->exp = i;
-
-	for(i=0; i<10; i++) {
-		f = f*Mpbase;
-		l = floor(f);
-		f = f - l;
-		a->exp -= Mpscale;
-		a->val.a[0] = l;
-		if(f == 0)
-			break;
-		mpshiftfix(&a->val, Mpscale);
-	}
-
-out:
-	mpnorm(a);
-	if(Mpdebug)
-		print(" = %F\n", a);
-}
-
-void
-mpnegflt(Mpflt *a)
-{
-	a->val.neg ^= 1;
-}
-
-int
-mptestflt(Mpflt *a)
-{
-	int s;
-
-	if(Mpdebug)
-		print("\n%F?", a);
-	s = sigfig(a);
-	if(s != 0) {
-		s = +1;
-		if(a->val.neg)
-			s = -1;
-	}
-	if(Mpdebug)
-		print(" = %d\n", s);
-	return s;
-}
diff --git a/src/cmd/gc/obj.c b/src/cmd/gc/obj.c
deleted file mode 100644
index b752a13..0000000
--- a/src/cmd/gc/obj.c
+++ /dev/null
@@ -1,284 +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 <u.h>
-#include <libc.h>
-#include "go.h"
-#include "../ld/textflag.h"
-
-/*
- * architecture-independent object file output
- */
-
-static	void	dumpglobls(void);
-
-enum
-{
-	ArhdrSize = 60
-};
-
-static void
-formathdr(char *arhdr, char *name, vlong size)
-{
-	snprint(arhdr, ArhdrSize, "%-16s%-12d%-6d%-6d%-8o%-10lld`",
-		name, 0, 0, 0, 0644, size);
-	arhdr[ArhdrSize-1] = '\n'; // overwrite \0 written by snprint
-}
-
-void
-dumpobj(void)
-{
-	NodeList *externs, *tmp;
-	char arhdr[ArhdrSize];
-	vlong startobj, size;
-	Sym *zero;
-
-	bout = Bopen(outfile, OWRITE);
-	if(bout == nil) {
-		flusherrors();
-		print("can't create %s: %r\n", outfile);
-		errorexit();
-	}
-
-	startobj = 0;
-	if(writearchive) {
-		Bwrite(bout, "!<arch>\n", 8);
-		memset(arhdr, 0, sizeof arhdr);
-		Bwrite(bout, arhdr, sizeof arhdr);
-		startobj = Boffset(bout);
-	}
-	Bprint(bout, "go object %s %s %s %s\n", getgoos(), getgoarch(), getgoversion(), expstring());
-	dumpexport();
-	
-	if(writearchive) {
-		Bflush(bout);
-		size = Boffset(bout) - startobj;
-		if(size&1)
-			Bputc(bout, 0);
-		Bseek(bout, startobj - ArhdrSize, 0);
-		formathdr(arhdr, "__.PKGDEF", size);
-		Bwrite(bout, arhdr, ArhdrSize);
-		Bflush(bout);
-
-		Bseek(bout, startobj + size + (size&1), 0);
-		memset(arhdr, 0, ArhdrSize);
-		Bwrite(bout, arhdr, ArhdrSize);
-		startobj = Boffset(bout);
-		Bprint(bout, "go object %s %s %s %s\n", getgoos(), getgoarch(), getgoversion(), expstring());
-	}
-
-	Bprint(bout, "\n!\n");
-
-	externs = nil;
-	if(externdcl != nil)
-		externs = externdcl->end;
-
-	dumpglobls();
-	dumptypestructs();
-
-	// Dump extra globals.
-	tmp = externdcl;
-	if(externs != nil)
-		externdcl = externs->next;
-	dumpglobls();
-	externdcl = tmp;
-
-	zero = pkglookup("zerovalue", runtimepkg);
-	ggloblsym(zero, zerosize, DUPOK|RODATA);
-
-	dumpdata();
-	writeobj(ctxt, bout);
-
-	if(writearchive) {
-		Bflush(bout);
-		size = Boffset(bout) - startobj;
-		if(size&1)
-			Bputc(bout, 0);
-		Bseek(bout, startobj - ArhdrSize, 0);
-		snprint(namebuf, sizeof namebuf, "_go_.%c", thechar);
-		formathdr(arhdr, namebuf, size);
-		Bwrite(bout, arhdr, ArhdrSize);
-	}
-	Bterm(bout);
-}
-
-static void
-dumpglobls(void)
-{
-	Node *n;
-	NodeList *l;
-
-	// add globals
-	for(l=externdcl; l; l=l->next) {
-		n = l->n;
-		if(n->op != ONAME)
-			continue;
-
-		if(n->type == T)
-			fatal("external %N nil type\n", n);
-		if(n->class == PFUNC)
-			continue;
-		if(n->sym->pkg != localpkg)
-			continue;
-		dowidth(n->type);
-
-		ggloblnod(n);
-	}
-	
-	for(l=funcsyms; l; l=l->next) {
-		n = l->n;
-		dsymptr(n->sym, 0, n->sym->def->shortname->sym, 0);
-		ggloblsym(n->sym, widthptr, DUPOK|RODATA);
-	}
-	
-	// Do not reprocess funcsyms on next dumpglobls call.
-	funcsyms = nil;
-}
-
-void
-Bputname(Biobuf *b, LSym *s)
-{
-	Bwrite(b, s->name, strlen(s->name)+1);
-}
-
-LSym*
-linksym(Sym *s)
-{
-	char *p;
-
-	if(s == nil)
-		return nil;
-	if(s->lsym != nil)
-		return s->lsym;
-	if(isblanksym(s))
-		s->lsym = linklookup(ctxt, "_", 0);
-	else {
-		p = smprint("%s.%s", s->pkg->prefix, s->name);
-		s->lsym = linklookup(ctxt, p, 0);
-		free(p);
-	}
-	return s->lsym;	
-}
-
-int
-duintxx(Sym *s, int off, uint64 v, int wid)
-{
-	// Update symbol data directly instead of generating a
-	// DATA instruction that liblink will have to interpret later.
-	// This reduces compilation time and memory usage.
-	off = rnd(off, wid);
-	return setuintxx(ctxt, linksym(s), off, v, wid);
-}
-
-int
-duint8(Sym *s, int off, uint8 v)
-{
-	return duintxx(s, off, v, 1);
-}
-
-int
-duint16(Sym *s, int off, uint16 v)
-{
-	return duintxx(s, off, v, 2);
-}
-
-int
-duint32(Sym *s, int off, uint32 v)
-{
-	return duintxx(s, off, v, 4);
-}
-
-int
-duint64(Sym *s, int off, uint64 v)
-{
-	return duintxx(s, off, v, 8);
-}
-
-int
-duintptr(Sym *s, int off, uint64 v)
-{
-	return duintxx(s, off, v, widthptr);
-}
-
-Sym*
-stringsym(char *s, int len)
-{
-	static int gen;
-	Sym *sym;
-	int off, n, m;
-	struct {
-		Strlit lit;
-		char buf[110];
-	} tmp;
-	Pkg *pkg;
-
-	if(len > 100) {
-		// huge strings are made static to avoid long names
-		snprint(namebuf, sizeof(namebuf), ".gostring.%d", ++gen);
-		pkg = localpkg;
-	} else {
-		// small strings get named by their contents,
-		// so that multiple modules using the same string
-		// can share it.
-		tmp.lit.len = len;
-		memmove(tmp.lit.s, s, len);
-		tmp.lit.s[len] = '\0';
-		snprint(namebuf, sizeof(namebuf), "\"%Z\"", &tmp.lit);
-		pkg = gostringpkg;
-	}
-	sym = pkglookup(namebuf, pkg);
-	
-	// SymUniq flag indicates that data is generated already
-	if(sym->flags & SymUniq)
-		return sym;
-	sym->flags |= SymUniq;
-	sym->def = newname(sym);
-
-	off = 0;
-	
-	// string header
-	off = dsymptr(sym, off, sym, widthptr+widthint);
-	off = duintxx(sym, off, len, widthint);
-	
-	// string data
-	for(n=0; n<len; n+=m) {
-		m = 8;
-		if(m > len-n)
-			m = len-n;
-		off = dsname(sym, off, s+n, m);
-	}
-	off = duint8(sym, off, 0);  // terminating NUL for runtime
-	off = (off+widthptr-1)&~(widthptr-1);  // round to pointer alignment
-	ggloblsym(sym, off, DUPOK|RODATA);
-
-	return sym;	
-}
-
-void
-slicebytes(Node *nam, char *s, int len)
-{
-	int off, n, m;
-	static int gen;
-	Sym *sym;
-
-	snprint(namebuf, sizeof(namebuf), ".gobytes.%d", ++gen);
-	sym = pkglookup(namebuf, localpkg);
-	sym->def = newname(sym);
-
-	off = 0;
-	for(n=0; n<len; n+=m) {
-		m = 8;
-		if(m > len-n)
-			m = len-n;
-		off = dsname(sym, off, s+n, m);
-	}
-	ggloblsym(sym, off, NOPTR);
-	
-	if(nam->op != ONAME)
-		fatal("slicebytes %N", nam);
-	off = nam->xoffset;
-	off = dsymptr(nam->sym, off, sym, 0);
-	off = duintxx(nam->sym, off, len, widthint);
-	duintxx(nam->sym, off, len, widthint);
-}
diff --git a/src/cmd/gc/order.c b/src/cmd/gc/order.c
deleted file mode 100644
index 76820fd..0000000
--- a/src/cmd/gc/order.c
+++ /dev/null
@@ -1,1101 +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.
-
-// Rewrite tree to use separate statements to enforce
-// order of evaluation.  Makes walk easier, because it
-// can (after this runs) reorder at will within an expression.
-//
-// Rewrite x op= y into x = x op y.
-//
-// Introduce temporaries as needed by runtime routines.
-// For example, the map runtime routines take the map key
-// by reference, so make sure all map keys are addressable
-// by copying them to temporaries as needed.
-// The same is true for channel operations.
-//
-// Arrange that map index expressions only appear in direct
-// assignments x = m[k] or m[k] = x, never in larger expressions.
-//
-// Arrange that receive expressions only appear in direct assignments
-// x = <-c or as standalone statements <-c, never in larger expressions.
-
-// TODO(rsc): The temporary introduction during multiple assignments
-// should be moved into this file, so that the temporaries can be cleaned
-// and so that conversions implicit in the OAS2FUNC and OAS2RECV
-// nodes can be made explicit and then have their temporaries cleaned.
-
-// TODO(rsc): Goto and multilevel break/continue can jump over
-// inserted VARKILL annotations. Work out a way to handle these.
-// The current implementation is safe, in that it will execute correctly.
-// But it won't reuse temporaries as aggressively as it might, and
-// it can result in unnecessary zeroing of those variables in the function
-// prologue.
-
-#include	<u.h>
-#include	<libc.h>
-#include	"go.h"
-
-// Order holds state during the ordering process.
-typedef struct Order Order;
-struct Order
-{
-	NodeList *out; // list of generated statements
-	NodeList *temp; // head of stack of temporary variables
-	NodeList *free; // free list of NodeList* structs (for use in temp)
-};
-
-static void	orderstmt(Node*, Order*);
-static void	orderstmtlist(NodeList*, Order*);
-static void	orderblock(NodeList **l);
-static void	orderexpr(Node**, Order*);
-static void orderexprinplace(Node**, Order*);
-static void	orderexprlist(NodeList*, Order*);
-static void	orderexprlistinplace(NodeList*, Order*);
-
-// Order rewrites fn->nbody to apply the ordering constraints
-// described in the comment at the top of the file.
-void
-order(Node *fn)
-{
-	orderblock(&fn->nbody);
-}
-
-// Ordertemp allocates a new temporary with the given type,
-// pushes it onto the temp stack, and returns it.
-// If clear is true, ordertemp emits code to zero the temporary.
-static Node*
-ordertemp(Type *t, Order *order, int clear)
-{
-	Node *var, *a;
-	NodeList *l;
-
-	var = temp(t);
-	if(clear) {
-		a = nod(OAS, var, N);
-		typecheck(&a, Etop);
-		order->out = list(order->out, a);
-	}
-	if((l = order->free) == nil)
-		l = mal(sizeof *l);
-	order->free = l->next;
-	l->next = order->temp;
-	l->n = var;
-	order->temp = l;
-	return var;
-}
-
-// Ordercopyexpr behaves like ordertemp but also emits
-// code to initialize the temporary to the value n.
-//
-// The clear argument is provided for use when the evaluation
-// of tmp = n turns into a function call that is passed a pointer
-// to the temporary as the output space. If the call blocks before
-// tmp has been written, the garbage collector will still treat the
-// temporary as live, so we must zero it before entering that call.
-// Today, this only happens for channel receive operations.
-// (The other candidate would be map access, but map access
-// returns a pointer to the result data instead of taking a pointer
-// to be filled in.)
-static Node*
-ordercopyexpr(Node *n, Type *t, Order *order, int clear)
-{
-	Node *a, *var;
-
-	var = ordertemp(t, order, clear);
-	a = nod(OAS, var, n);
-	typecheck(&a, Etop);
-	order->out = list(order->out, a);
-	return var;
-}
-
-// Ordercheapexpr returns a cheap version of n.
-// The definition of cheap is that n is a variable or constant.
-// If not, ordercheapexpr allocates a new tmp, emits tmp = n,
-// and then returns tmp.
-static Node*
-ordercheapexpr(Node *n, Order *order)
-{
-	switch(n->op) {
-	case ONAME:
-	case OLITERAL:
-		return n;
-	}
-	return ordercopyexpr(n, n->type, order, 0);
-}
-
-// Ordersafeexpr returns a safe version of n.
-// The definition of safe is that n can appear multiple times
-// without violating the semantics of the original program,
-// and that assigning to the safe version has the same effect
-// as assigning to the original n.
-//
-// The intended use is to apply to x when rewriting x += y into x = x + y.
-static Node*
-ordersafeexpr(Node *n, Order *order)
-{
-	Node *l, *r, *a;
-	
-	switch(n->op) {
-	default:
-		fatal("ordersafeexpr %O", n->op);
-
-	case ONAME:
-	case OLITERAL:
-		return n;
-
-	case ODOT:
-		l = ordersafeexpr(n->left, order);
-		if(l == n->left)
-			return n;
-		a = nod(OXXX, N, N);
-		*a = *n;
-		a->orig = a;
-		a->left = l;
-		typecheck(&a, Erv);
-		return a;
-
-	case ODOTPTR:
-	case OIND:
-		l = ordercheapexpr(n->left, order);
-		if(l == n->left)
-			return n;
-		a = nod(OXXX, N, N);
-		*a = *n;
-		a->orig = a;
-		a->left = l;
-		typecheck(&a, Erv);
-		return a;
-		
-	case OINDEX:
-	case OINDEXMAP:
-		if(isfixedarray(n->left->type))
-			l = ordersafeexpr(n->left, order);
-		else
-			l = ordercheapexpr(n->left, order);
-		r = ordercheapexpr(n->right, order);
-		if(l == n->left && r == n->right)
-			return n;
-		a = nod(OXXX, N, N);
-		*a = *n;
-		a->orig = a;
-		a->left = l;
-		a->right = r;
-		typecheck(&a, Erv);
-		return a;
-	}
-}		
-
-// Istemp reports whether n is a temporary variable.
-static int
-istemp(Node *n)
-{
-	if(n->op != ONAME)
-		return 0;
-	return strncmp(n->sym->name, "autotmp_", 8) == 0;
-}
-
-// Isaddrokay reports whether it is okay to pass n's address to runtime routines.
-// Taking the address of a variable makes the liveness and optimization analyses
-// lose track of where the variable's lifetime ends. To avoid hurting the analyses
-// of ordinary stack variables, those are not 'isaddrokay'. Temporaries are okay,
-// because we emit explicit VARKILL instructions marking the end of those
-// temporaries' lifetimes.
-static int
-isaddrokay(Node *n)
-{
-	return islvalue(n) && (n->op != ONAME || n->class == PEXTERN || istemp(n));
-}
-
-// Orderaddrtemp ensures that *np is okay to pass by address to runtime routines.
-// If the original argument *np is not okay, orderaddrtemp creates a tmp, emits
-// tmp = *np, and then sets *np to the tmp variable.
-static void
-orderaddrtemp(Node **np, Order *order)
-{
-	Node *n;
-	
-	n = *np;
-	if(isaddrokay(n))
-		return;
-	*np = ordercopyexpr(n, n->type, order, 0);
-}
-
-// Marktemp returns the top of the temporary variable stack.
-static NodeList*
-marktemp(Order *order)
-{
-	return order->temp;
-}
-
-// Poptemp pops temporaries off the stack until reaching the mark,
-// which must have been returned by marktemp.
-static void
-poptemp(NodeList *mark, Order *order)
-{
-	NodeList *l;
-
-	while((l = order->temp) != mark) {
-		order->temp = l->next;
-		l->next = order->free;
-		order->free = l;
-	}
-}
-
-// Cleantempnopop emits to *out VARKILL instructions for each temporary
-// above the mark on the temporary stack, but it does not pop them
-// from the stack.
-static void
-cleantempnopop(NodeList *mark, Order *order, NodeList **out)
-{
-	NodeList *l;
-	Node *kill;
-
-	for(l=order->temp; l != mark; l=l->next) {
-		kill = nod(OVARKILL, l->n, N);
-		typecheck(&kill, Etop);
-		*out = list(*out, kill);
-	}
-}
-
-// Cleantemp emits VARKILL instructions for each temporary above the
-// mark on the temporary stack and removes them from the stack.
-static void
-cleantemp(NodeList *top, Order *order)
-{
-	cleantempnopop(top, order, &order->out);
-	poptemp(top, order);
-}
-
-// Orderstmtlist orders each of the statements in the list.
-static void
-orderstmtlist(NodeList *l, Order *order)
-{
-	for(; l; l=l->next)
-		orderstmt(l->n, order);
-}
-
-// Orderblock orders the block of statements *l onto a new list,
-// and then replaces *l with that list.
-static void
-orderblock(NodeList **l)
-{
-	Order order;
-	NodeList *mark;
-	
-	memset(&order, 0, sizeof order);
-	mark = marktemp(&order);
-	orderstmtlist(*l, &order);
-	cleantemp(mark, &order);
-	*l = order.out;
-}
-
-// Orderexprinplace orders the side effects in *np and
-// leaves them as the init list of the final *np.
-static void
-orderexprinplace(Node **np, Order *outer)
-{
-	Node *n;
-	NodeList **lp;
-	Order order;
-	
-	n = *np;
-	memset(&order, 0, sizeof order);
-	orderexpr(&n, &order);
-	addinit(&n, order.out);
-	
-	// insert new temporaries from order
-	// at head of outer list.
-	lp = &order.temp;
-	while(*lp != nil)
-		lp = &(*lp)->next;
-	*lp = outer->temp;
-	outer->temp = order.temp;
-
-	*np = n;
-}
-
-// Orderstmtinplace orders the side effects of the single statement *np
-// and replaces it with the resulting statement list.
-void
-orderstmtinplace(Node **np)
-{
-	Node *n;
-	Order order;
-	NodeList *mark;
-	
-	n = *np;
-	memset(&order, 0, sizeof order);
-	mark = marktemp(&order);
-	orderstmt(n, &order);
-	cleantemp(mark, &order);
-	*np = liststmt(order.out);
-}
-
-// Orderinit moves n's init list to order->out.
-static void
-orderinit(Node *n, Order *order)
-{
-	orderstmtlist(n->ninit, order);
-	n->ninit = nil;
-}
-
-// Ismulticall reports whether the list l is f() for a multi-value function.
-// Such an f() could appear as the lone argument to a multi-arg function.
-static int
-ismulticall(NodeList *l)
-{
-	Node *n;
-	
-	// one arg only
-	if(l == nil || l->next != nil)
-		return 0;
-	n = l->n;
-	
-	// must be call
-	switch(n->op) {
-	default:
-		return 0;
-	case OCALLFUNC:
-	case OCALLMETH:
-	case OCALLINTER:
-		break;
-	}
-	
-	// call must return multiple values
-	return n->left->type->outtuple > 1;
-}
-
-// Copyret emits t1, t2, ... = n, where n is a function call,
-// and then returns the list t1, t2, ....
-static NodeList*
-copyret(Node *n, Order *order)
-{
-	Type *t;
-	Node *tmp, *as;
-	NodeList *l1, *l2;
-	Iter tl;
-	
-	if(n->type->etype != TSTRUCT || !n->type->funarg)
-		fatal("copyret %T %d", n->type, n->left->type->outtuple);
-
-	l1 = nil;
-	l2 = nil;
-	for(t=structfirst(&tl, &n->type); t; t=structnext(&tl)) {
-		tmp = temp(t->type);
-		l1 = list(l1, tmp);
-		l2 = list(l2, tmp);
-	}
-	
-	as = nod(OAS2, N, N);
-	as->list = l1;
-	as->rlist = list1(n);
-	typecheck(&as, Etop);
-	orderstmt(as, order);
-
-	return l2;
-}
-
-// Ordercallargs orders the list of call arguments *l.
-static void
-ordercallargs(NodeList **l, Order *order)
-{
-	if(ismulticall(*l)) {
-		// return f() where f() is multiple values.
-		*l = copyret((*l)->n, order);
-	} else {
-		orderexprlist(*l, order);
-	}
-}
-
-// Ordercall orders the call expression n.
-// n->op is OCALLMETH/OCALLFUNC/OCALLINTER or a builtin like OCOPY.
-static void
-ordercall(Node *n, Order *order)
-{
-	orderexpr(&n->left, order);
-	orderexpr(&n->right, order); // ODDDARG temp
-	ordercallargs(&n->list, order);
-}
-
-// Ordermapassign appends n to order->out, introducing temporaries
-// to make sure that all map assignments have the form m[k] = x,
-// where x is adressable.
-// (Orderexpr has already been called on n, so we know k is addressable.)
-//
-// If n is m[k] = x where x is not addressable, the rewrite is:
-//	tmp = x
-//	m[k] = tmp
-//
-// If n is the multiple assignment form ..., m[k], ... = ..., the rewrite is
-//	t1 = m
-//	t2 = k
-//	...., t3, ... = x
-//	t1[t2] = t3
-//
-// The temporaries t1, t2 are needed in case the ... being assigned
-// contain m or k. They are usually unnecessary, but in the unnecessary
-// cases they are also typically registerizable, so not much harm done.
-// And this only applies to the multiple-assignment form.
-// We could do a more precise analysis if needed, like in walk.c.
-//
-// Ordermapassign also inserts these temporaries if needed for
-// calling writebarrierfat with a pointer to n->right.
-static void
-ordermapassign(Node *n, Order *order)
-{
-	Node *m, *a;
-	NodeList *l;
-	NodeList *post;
-
-	switch(n->op) {
-	default:
-		fatal("ordermapassign %O", n->op);
-
-	case OAS:
-		order->out = list(order->out, n);
-		// We call writebarrierfat only for values > 4 pointers long. See walk.c.
-		if((n->left->op == OINDEXMAP || (needwritebarrier(n->left, n->right) && n->left->type->width > 4*widthptr)) && !isaddrokay(n->right)) {
-			m = n->left;
-			n->left = ordertemp(m->type, order, 0);
-			a = nod(OAS, m, n->left);
-			typecheck(&a, Etop);
-			order->out = list(order->out, a);
-		}
-		break;
-
-	case OAS2:
-	case OAS2DOTTYPE:
-	case OAS2MAPR:
-	case OAS2FUNC:
-		post = nil;
-		for(l=n->list; l != nil; l=l->next) {
-			if(l->n->op == OINDEXMAP) {
-				m = l->n;
-				if(!istemp(m->left))
-					m->left = ordercopyexpr(m->left, m->left->type, order, 0);
-				if(!istemp(m->right))
-					m->right = ordercopyexpr(m->right, m->right->type, order, 0);
-				l->n = ordertemp(m->type, order, 0);
-				a = nod(OAS, m, l->n);
-				typecheck(&a, Etop);
-				post = list(post, a);
-			}
-		}
-		order->out = list(order->out, n);
-		order->out = concat(order->out, post);
-		break;
-	}
-}
-
-// Orderstmt orders the statement n, appending to order->out.
-// Temporaries created during the statement are cleaned
-// up using VARKILL instructions as possible.
-static void
-orderstmt(Node *n, Order *order)
-{
-	int lno;
-	NodeList *l, *t, *t1;
-	Node *r, *tmp1, *tmp2, **np;
-	Type *ch;
-
-	if(n == N)
-		return;
-
-	lno = setlineno(n);
-
-	orderinit(n, order);
-
-	switch(n->op) {
-	default:
-		fatal("orderstmt %O", n->op);
-
-	case OVARKILL:
-		order->out = list(order->out, n);
-		break;
-
-	case OAS:
-	case OAS2:
-	case OAS2DOTTYPE:
-	case OCLOSE:
-	case OCOPY:
-	case OPRINT:
-	case OPRINTN:
-	case ORECOVER:
-	case ORECV:
-		t = marktemp(order);
-		orderexpr(&n->left, order);
-		orderexpr(&n->right, order);
-		orderexprlist(n->list, order);
-		orderexprlist(n->rlist, order);
-		switch(n->op) {
-		case OAS:
-		case OAS2:
-		case OAS2DOTTYPE:
-			ordermapassign(n, order);
-			break;
-		default:
-			order->out = list(order->out, n);
-			break;
-		}
-		cleantemp(t, order);
-		break;
-
-	case OASOP:
-		// Special: rewrite l op= r into l = l op r.
-		// This simplies quite a few operations;
-		// most important is that it lets us separate
-		// out map read from map write when l is
-		// a map index expression.
-		t = marktemp(order);
-		orderexpr(&n->left, order);
-		n->left = ordersafeexpr(n->left, order);
-		tmp1 = treecopy(n->left);
-		if(tmp1->op == OINDEXMAP)
-			tmp1->etype = 0; // now an rvalue not an lvalue
-		tmp1 = ordercopyexpr(tmp1, n->left->type, order, 0);
-		n->right = nod(n->etype, tmp1, n->right);
-		typecheck(&n->right, Erv);
-		orderexpr(&n->right, order);
-		n->etype = 0;
-		n->op = OAS;
-		ordermapassign(n, order);
-		cleantemp(t, order);
-		break;
-
-	case OAS2MAPR:
-		// Special: make sure key is addressable,
-		// and make sure OINDEXMAP is not copied out.
-		t = marktemp(order);
-		orderexprlist(n->list, order);
-		r = n->rlist->n;
-		orderexpr(&r->left, order);
-		orderexpr(&r->right, order);
-		// See case OINDEXMAP below.
-		if(r->right->op == OARRAYBYTESTR)
-			r->right->op = OARRAYBYTESTRTMP;
-		orderaddrtemp(&r->right, order);
-		ordermapassign(n, order);
-		cleantemp(t, order);
-		break;
-
-	case OAS2FUNC:
-		// Special: avoid copy of func call n->rlist->n.
-		t = marktemp(order);
-		orderexprlist(n->list, order);
-		ordercall(n->rlist->n, order);
-		ordermapassign(n, order);
-		cleantemp(t, order);
-		break;
-
-	case OAS2RECV:
-		// Special: avoid copy of receive.
-		// Use temporary variables to hold result,
-		// so that chanrecv can take address of temporary.
-		t = marktemp(order);
-		orderexprlist(n->list, order);
-		orderexpr(&n->rlist->n->left, order);  // arg to recv
-		ch = n->rlist->n->left->type;
-		tmp1 = ordertemp(ch->type, order, haspointers(ch->type));
-		if(!isblank(n->list->next->n))
-			tmp2 = ordertemp(n->list->next->n->type, order, 0);
-		else
-			tmp2 = ordertemp(types[TBOOL], order, 0);
-		order->out = list(order->out, n);
-		r = nod(OAS, n->list->n, tmp1);
-		typecheck(&r, Etop);
-		ordermapassign(r, order);
-		r = nod(OAS, n->list->next->n, tmp2);
-		typecheck(&r, Etop);
-		ordermapassign(r, order);
-		n->list = list(list1(tmp1), tmp2);
-		cleantemp(t, order);
-		break;
-
-	case OBLOCK:
-	case OEMPTY:
-		// Special: does not save n onto out.
-		orderstmtlist(n->list, order);
-		break;
-
-	case OBREAK:
-	case OCONTINUE:
-	case ODCL:
-	case ODCLCONST:
-	case ODCLTYPE:
-	case OFALL:
-	case OXFALL:
-	case OGOTO:
-	case OLABEL:
-	case ORETJMP:
-		// Special: n->left is not an expression; save as is.
-		order->out = list(order->out, n);
-		break;
-
-	case OCALLFUNC:
-	case OCALLINTER:
-	case OCALLMETH:
-		// Special: handle call arguments.
-		t = marktemp(order);
-		ordercall(n, order);
-		order->out = list(order->out, n);
-		cleantemp(t, order);
-		break;
-
-	case ODEFER:
-	case OPROC:
-		// Special: order arguments to inner call but not call itself.
-		t = marktemp(order);
-		switch(n->left->op) {
-		case ODELETE:
-			// Delete will take the address of the key.
-			// Copy key into new temp and do not clean it
-			// (it persists beyond the statement).
-			orderexprlist(n->left->list, order);
-			t1 = marktemp(order);
-			np = &n->left->list->next->n; // map key
-			*np = ordercopyexpr(*np, (*np)->type, order, 0);
-			poptemp(t1, order);
-			break;
-		default:
-			ordercall(n->left, order);
-			break;
-		}
-		order->out = list(order->out, n);
-		cleantemp(t, order);
-		break;
-
-	case ODELETE:
-		t = marktemp(order);
-		orderexpr(&n->list->n, order);
-		orderexpr(&n->list->next->n, order);
-		orderaddrtemp(&n->list->next->n, order); // map key
-		order->out = list(order->out, n);
-		cleantemp(t, order);
-		break;
-
-	case OFOR:
-		// Clean temporaries from condition evaluation at
-		// beginning of loop body and after for statement.
-		t = marktemp(order);
-		orderexprinplace(&n->ntest, order);
-		l = nil;
-		cleantempnopop(t, order, &l);
-		n->nbody = concat(l, n->nbody);
-		orderblock(&n->nbody);
-		orderstmtinplace(&n->nincr);
-		order->out = list(order->out, n);
-		cleantemp(t, order);
-		break;
-		
-	case OIF:
-		// Clean temporaries from condition at
-		// beginning of both branches.
-		t = marktemp(order);
-		orderexprinplace(&n->ntest, order);
-		l = nil;
-		cleantempnopop(t, order, &l);
-		n->nbody = concat(l, n->nbody);
-		l = nil;
-		cleantempnopop(t, order, &l);
-		n->nelse = concat(l, n->nelse);
-		poptemp(t, order);
-		orderblock(&n->nbody);
-		orderblock(&n->nelse);
-		order->out = list(order->out, n);
-		break;
-
-	case OPANIC:
-		// Special: argument will be converted to interface using convT2E
-		// so make sure it is an addressable temporary.
-		t = marktemp(order);
-		orderexpr(&n->left, order);
-		if(!isinter(n->left->type))
-			orderaddrtemp(&n->left, order);
-		order->out = list(order->out, n);
-		cleantemp(t, order);
-		break;
-
-	case ORANGE:
-		// n->right is the expression being ranged over.
-		// order it, and then make a copy if we need one.
-		// We almost always do, to ensure that we don't
-		// see any value changes made during the loop.
-		// Usually the copy is cheap (e.g., array pointer, chan, slice, string are all tiny).
-		// The exception is ranging over an array value (not a slice, not a pointer to array),
-		// which must make a copy to avoid seeing updates made during
-		// the range body. Ranging over an array value is uncommon though.
-		t = marktemp(order);
-		orderexpr(&n->right, order);
-		switch(n->type->etype) {
-		default:
-			fatal("orderstmt range %T", n->type);
-		case TARRAY:
-			if(count(n->list) < 2 || isblank(n->list->next->n)) {
-				// for i := range x will only use x once, to compute len(x).
-				// No need to copy it.
-				break;
-			}
-			// fall through
-		case TCHAN:
-		case TSTRING:
-			// chan, string, slice, array ranges use value multiple times.
-			// make copy.
-			r = n->right;
-			if(r->type->etype == TSTRING && r->type != types[TSTRING]) {
-				r = nod(OCONV, r, N);
-				r->type = types[TSTRING];
-				typecheck(&r, Erv);
-			}
-			n->right = ordercopyexpr(r, r->type, order, 0);
-			break;
-		case TMAP:
-			// copy the map value in case it is a map literal.
-			// TODO(rsc): Make tmp = literal expressions reuse tmp.
-			// For maps tmp is just one word so it hardly matters.
-			r = n->right;
-			n->right = ordercopyexpr(r, r->type, order, 0);
-			// n->alloc is the temp for the iterator.
-			n->alloc = ordertemp(types[TUINT8], order, 1);
-			break;
-		}
-		for(l=n->list; l; l=l->next)
-			orderexprinplace(&l->n, order);
-		orderblock(&n->nbody);
-		order->out = list(order->out, n);
-		cleantemp(t, order);
-		break;
-
-	case ORETURN:
-		ordercallargs(&n->list, order);
-		order->out = list(order->out, n);
-		break;
-	
-	case OSELECT:
-		// Special: clean case temporaries in each block entry.
-		// Select must enter one of its blocks, so there is no
-		// need for a cleaning at the end.
-		// Doubly special: evaluation order for select is stricter
-		// than ordinary expressions. Even something like p.c
-		// has to be hoisted into a temporary, so that it cannot be
-		// reordered after the channel evaluation for a different
-		// case (if p were nil, then the timing of the fault would
-		// give this away).
-		t = marktemp(order);
-		for(l=n->list; l; l=l->next) {
-			if(l->n->op != OXCASE)
-				fatal("order select case %O", l->n->op);
-			r = l->n->left;
-			setlineno(l->n);
-			// Append any new body prologue to ninit.
-			// The next loop will insert ninit into nbody.
-			if(l->n->ninit != nil)
-				fatal("order select ninit");
-			if(r != nil) {
-				switch(r->op) {
-				default:
-					yyerror("unknown op in select %O", r->op);
-					dump("select case", r);
-					break;
-
-				case OSELRECV:
-				case OSELRECV2:
-					// If this is case x := <-ch or case x, y := <-ch, the case has
-					// 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.
-					if(r->colas) {
-						t = r->ninit;
-						if(t != nil && t->n->op == ODCL && t->n->left == r->left)
-							t = t->next;
-						if(t != nil && t->n->op == ODCL && t->n->left == r->ntest)
-							t = t->next;
-						if(t == nil)
-							r->ninit = nil;
-					}
-					if(r->ninit != nil) {
-						yyerror("ninit on select recv");
-						dumplist("ninit", r->ninit);
-					}
-					// case x = <-c
-					// case x, ok = <-c
-					// r->left is x, r->ntest is ok, r->right is ORECV, r->right->left is c.
-					// r->left == N means 'case <-c'.
-					// c is always evaluated; x and ok are only evaluated when assigned.
-					orderexpr(&r->right->left, order);
-					if(r->right->left->op != ONAME)
-						r->right->left = ordercopyexpr(r->right->left, r->right->left->type, order, 0);
-
-					// Introduce temporary for receive and move actual copy into case body.
-					// avoids problems with target being addressed, as usual.
-					// NOTE: If we wanted to be clever, we could arrange for just one
-					// temporary per distinct type, sharing the temp among all receives
-					// with that temp. Similarly one ok bool could be shared among all
-					// the x,ok receives. Not worth doing until there's a clear need.
-					if(r->left != N && isblank(r->left))
-						r->left = N;
-					if(r->left != N) {
-						// use channel element type for temporary to avoid conversions,
-						// such as in case interfacevalue = <-intchan.
-						// the conversion happens in the OAS instead.
-						tmp1 = r->left;
-						if(r->colas) {
-							tmp2 = nod(ODCL, tmp1, N);
-							typecheck(&tmp2, Etop);
-							l->n->ninit = list(l->n->ninit, tmp2);
-						}
-						r->left = ordertemp(r->right->left->type->type, order, haspointers(r->right->left->type->type));
-						tmp2 = nod(OAS, tmp1, r->left);
-						typecheck(&tmp2, Etop);
-						l->n->ninit = list(l->n->ninit, tmp2);
-					}
-					if(r->ntest != N && isblank(r->ntest))
-						r->ntest = N;
-					if(r->ntest != N) {
-						tmp1 = r->ntest;
-						if(r->colas) {
-							tmp2 = nod(ODCL, tmp1, N);
-							typecheck(&tmp2, Etop);
-							l->n->ninit = list(l->n->ninit, tmp2);
-						}
-						r->ntest = ordertemp(tmp1->type, order, 0);
-						tmp2 = nod(OAS, tmp1, r->ntest);
-						typecheck(&tmp2, Etop);
-						l->n->ninit = list(l->n->ninit, tmp2);
-					}
-					orderblock(&l->n->ninit);
-					break;
-
-				case OSEND:
-					if(r->ninit != nil) {
-						yyerror("ninit on select send");
-						dumplist("ninit", r->ninit);
-					}
-					// case c <- x
-					// r->left is c, r->right is x, both are always evaluated.
-					orderexpr(&r->left, order);
-					if(!istemp(r->left))
-						r->left = ordercopyexpr(r->left, r->left->type, order, 0);
-					orderexpr(&r->right, order);
-					if(!istemp(r->right))
-						r->right = ordercopyexpr(r->right, r->right->type, order, 0);
-					break;
-				}
-			}
-			orderblock(&l->n->nbody);
-		}
-		// Now that we have accumulated all the temporaries, clean them.
-		// Also insert any ninit queued during the previous loop.
-		// (The temporary cleaning must follow that ninit work.)
-		for(l=n->list; l; l=l->next) {
-			cleantempnopop(t, order, &l->n->ninit);
-			l->n->nbody = concat(l->n->ninit, l->n->nbody);
-			l->n->ninit = nil;
-		}
-		order->out = list(order->out, n);
-		poptemp(t, order);
-		break;
-
-	case OSEND:
-		// Special: value being sent is passed as a pointer; make it addressable.
-		t = marktemp(order);
-		orderexpr(&n->left, order);
-		orderexpr(&n->right, order);
-		orderaddrtemp(&n->right, order);
-		order->out = list(order->out, n);
-		cleantemp(t, order);
-		break;
-
-	case OSWITCH:
-		// TODO(rsc): Clean temporaries more aggressively.
-		// Note that because walkswitch will rewrite some of the
-		// switch into a binary search, this is not as easy as it looks.
-		// (If we ran that code here we could invoke orderstmt on
-		// the if-else chain instead.)
-		// For now just clean all the temporaries at the end.
-		// In practice that's fine.
-		t = marktemp(order);
-		orderexpr(&n->ntest, order);
-		for(l=n->list; l; l=l->next) {
-			if(l->n->op != OXCASE)
-				fatal("order switch case %O", l->n->op);
-			orderexprlistinplace(l->n->list, order);
-			orderblock(&l->n->nbody);
-		}
-		order->out = list(order->out, n);
-		cleantemp(t, order);
-		break;
-	}
-	
-	lineno = lno;
-}
-
-// Orderexprlist orders the expression list l into order.
-static void
-orderexprlist(NodeList *l, Order *order)
-{
-	for(; l; l=l->next)
-		orderexpr(&l->n, order);
-}
-
-// Orderexprlist orders the expression list l but saves
-// the side effects on the individual expression ninit lists.
-static void
-orderexprlistinplace(NodeList *l, Order *order)
-{
-	for(; l; l=l->next)
-		orderexprinplace(&l->n, order);
-}
-
-// Orderexpr orders a single expression, appending side
-// effects to order->out as needed.
-static void
-orderexpr(Node **np, Order *order)
-{
-	Node *n;
-	NodeList *mark, *l;
-	Type *t;
-	int lno;
-
-	n = *np;
-	if(n == N)
-		return;
-
-	lno = setlineno(n);
-	orderinit(n, order);
-
-	switch(n->op) {
-	default:
-		orderexpr(&n->left, order);
-		orderexpr(&n->right, order);
-		orderexprlist(n->list, order);
-		orderexprlist(n->rlist, order);
-		break;
-	
-	case OADDSTR:
-		// Addition of strings turns into a function call.
-		// Allocate a temporary to hold the strings.
-		// Fewer than 5 strings use direct runtime helpers.
-		orderexprlist(n->list, order);
-		if(count(n->list) > 5) {
-			t = typ(TARRAY);
-			t->bound = count(n->list);
-			t->type = types[TSTRING];
-			n->alloc = ordertemp(t, order, 0);
-		}
-		break;
-
-	case OINDEXMAP:
-		// key must be addressable
-		orderexpr(&n->left, order);
-		orderexpr(&n->right, order);
-
-		// For x = m[string(k)] where k is []byte, the allocation of
-		// backing bytes for the string can be avoided by reusing
-		// the []byte backing array. This is a special case that it
-		// would be nice to handle more generally, but because
-		// there are no []byte-keyed maps, this specific case comes
-		// up in important cases in practice. See issue 3512.
-		// Nothing can change the []byte we are not copying before
-		// the map index, because the map access is going to
-		// be forced to happen immediately following this
-		// conversion (by the ordercopyexpr a few lines below).
-		if(n->etype == 0 && n->right->op == OARRAYBYTESTR)
-			n->right->op = OARRAYBYTESTRTMP;
-
-		orderaddrtemp(&n->right, order);
-		if(n->etype == 0) {
-			// use of value (not being assigned);
-			// make copy in temporary.
-			n = ordercopyexpr(n, n->type, order, 0);
-		}
-		break;
-	
-	case OCONVIFACE:
-		// concrete type (not interface) argument must be addressable
-		// temporary to pass to runtime.
-		orderexpr(&n->left, order);
-		if(!isinter(n->left->type))
-			orderaddrtemp(&n->left, order);
-		break;
-	
-	case OANDAND:
-	case 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 = nil;
-		cleantempnopop(mark, order, &l);
-		n->right->ninit = concat(l, n->right->ninit);
-		orderexprinplace(&n->right, order);
-		break;
-	
-	case OAPPEND:
-	case OCALLFUNC:
-	case OCALLINTER:
-	case OCALLMETH:
-	case OCAP:
-	case OCOMPLEX:
-	case OCOPY:
-	case OIMAG:
-	case OLEN:
-	case OMAKECHAN:
-	case OMAKEMAP:
-	case OMAKESLICE:
-	case ONEW:
-	case OREAL:
-	case ORECOVER:
-		ordercall(n, order);
-		n = ordercopyexpr(n, n->type, order, 0);
-		break;
-
-	case OCLOSURE:
-		if(n->noescape && n->cvars != nil)
-			n->alloc = ordertemp(types[TUINT8], order, 0); // walk will fill in correct type
-		break;
-
-	case OARRAYLIT:
-	case OCALLPART:
-		orderexpr(&n->left, order);
-		orderexpr(&n->right, order);
-		orderexprlist(n->list, order);
-		orderexprlist(n->rlist, order);
-		if(n->noescape)
-			n->alloc = ordertemp(types[TUINT8], order, 0); // walk will fill in correct type
-		break;
-
-	case ODDDARG:
-		if(n->noescape) {
-			// The ddd argument does not live beyond the call it is created for.
-			// Allocate a temporary that will be cleaned up when this statement
-			// completes. We could be more aggressive and try to arrange for it
-			// to be cleaned up when the call completes.
-			n->alloc = ordertemp(n->type->type, order, 0);
-		}
-		break;
-
-	case ORECV:
-		orderexpr(&n->left, order);
-		n = ordercopyexpr(n, n->type, order, 1);
-		break;
-
-	case OEQ:
-	case ONE:
-		orderexpr(&n->left, order);
-		orderexpr(&n->right, order);
-		t = n->left->type;
-		if(t->etype == TSTRUCT || isfixedarray(t)) {
-			// for complex comparisons, we need both args to be
-			// addressable so we can pass them to the runtime.
-			orderaddrtemp(&n->left, order);
-			orderaddrtemp(&n->right, order);
-		}
-		break;
-	}
-	
-	lineno = lno;
-
-	*np = n;
-}
diff --git a/src/cmd/gc/pgen.c b/src/cmd/gc/pgen.c
deleted file mode 100644
index 39028e3..0000000
--- a/src/cmd/gc/pgen.c
+++ /dev/null
@@ -1,539 +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.
-
-// "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	<u.h>
-#include	<libc.h>
-#include	"md5.h"
-#include	"gg.h"
-#include	"opt.h"
-#include	"../../runtime/funcdata.h"
-
-static void allocauto(Prog* p);
-static void emitptrargsmap(void);
-
-static Sym*
-makefuncdatasym(char *namefmt, int64 funcdatakind)
-{
-	Node nod;
-	Node *pnod;
-	Sym *sym;
-	static int32 nsym;
-
-	snprint(namebuf, sizeof(namebuf), namefmt, nsym++);
-	sym = lookup(namebuf);
-	pnod = newname(sym);
-	pnod->class = PEXTERN;
-	nodconst(&nod, types[TINT32], funcdatakind);
-	gins(AFUNCDATA, &nod, pnod);
-	return sym;
-}
-
-// gvardef inserts a VARDEF for n into the instruction stream.
-// VARDEF is an annotation for the liveness analysis, marking a place
-// where a complete initialization (definition) of a variable begins.
-// Since the liveness analysis can see initialization of single-word
-// variables quite easy, gvardef is usually only called for multi-word
-// or 'fat' variables, those satisfying isfat(n->type).
-// However, gvardef is also called when a non-fat variable is initialized
-// via a block move; the only time this happens is when you have
-//	return f()
-// for a function with multiple return values exactly matching the return
-// types of the current function.
-//
-// A 'VARDEF x' annotation in the instruction stream tells the liveness
-// analysis to behave as though the variable x is being initialized at that
-// point in the instruction stream. The VARDEF must appear before the
-// actual (multi-instruction) initialization, and it must also appear after
-// any uses of the previous value, if any. For example, if compiling:
-//
-//	x = x[1:]
-//
-// it is important to generate code like:
-//
-//	base, len, cap = pieces of x[1:]
-//	VARDEF x
-//	x = {base, len, cap}
-//
-// If instead the generated code looked like:
-//
-//	VARDEF x
-//	base, len, cap = pieces of x[1:]
-//	x = {base, len, cap}
-//
-// then the liveness analysis would decide the previous value of x was
-// unnecessary even though it is about to be used by the x[1:] computation.
-// Similarly, if the generated code looked like:
-//
-//	base, len, cap = pieces of x[1:]
-//	x = {base, len, cap}
-//	VARDEF x
-//
-// then the liveness analysis will not preserve the new value of x, because
-// the VARDEF appears to have "overwritten" it.
-//
-// VARDEF is a bit of a kludge to work around the fact that the instruction
-// stream is working on single-word values but the liveness analysis
-// wants to work on individual variables, which might be multi-word
-// aggregates. It might make sense at some point to look into letting
-// the liveness analysis work on single-word values as well, although
-// there are complications around interface values, slices, and strings,
-// all of which cannot be treated as individual words.
-//
-// VARKILL is the opposite of VARDEF: it marks a value as no longer needed,
-// even if its address has been taken. That is, a VARKILL annotation asserts
-// that its argument is certainly dead, for use when the liveness analysis
-// would not otherwise be able to deduce that fact.
-
-static void
-gvardefx(Node *n, int as)
-{
-	if(n == N)
-		fatal("gvardef nil");
-	if(n->op != ONAME) {
-		yyerror("gvardef %#O; %N", n->op, n);
-		return;
-	}
-	switch(n->class) {
-	case PAUTO:
-	case PPARAM:
-	case PPARAMOUT:
-		gins(as, N, n);
-	}
-}
-
-void
-gvardef(Node *n)
-{
-	gvardefx(n, AVARDEF);
-}
-
-void
-gvarkill(Node *n)
-{
-	gvardefx(n, AVARKILL);
-}
-
-static void
-removevardef(Prog *firstp)
-{
-	Prog *p;
-
-	for(p = firstp; p != P; p = p->link) {
-		while(p->link != P && (p->link->as == AVARDEF || p->link->as == AVARKILL))
-			p->link = p->link->link;
-		if(p->to.type == D_BRANCH)
-			while(p->to.u.branch != P && (p->to.u.branch->as == AVARDEF || p->to.u.branch->as == AVARKILL))
-				p->to.u.branch = p->to.u.branch->link;
-	}
-}
-
-static void
-gcsymdup(Sym *s)
-{
-	LSym *ls;
-	uint64 lo, hi;
-	
-	ls = linksym(s);
-	if(ls->nr > 0)
-		fatal("cannot rosymdup %s with relocations", ls->name);
-	MD5 d;
-	md5reset(&d);
-	md5write(&d, ls->p, ls->np);
-	lo = md5sum(&d, &hi);
-	ls->name = smprint("gclocals·%016llux%016llux", lo, hi);
-	ls->dupok = 1;
-}
-
-void
-compile(Node *fn)
-{
-	Plist *pl;
-	Node nod1, *n;
-	Prog *ptxt, *p;
-	int32 lno;
-	Type *t;
-	Iter save;
-	vlong oldstksize;
-	NodeList *l;
-	Sym *gcargs;
-	Sym *gclocals;
-
-	if(newproc == N) {
-		newproc = sysfunc("newproc");
-		deferproc = sysfunc("deferproc");
-		deferreturn = sysfunc("deferreturn");
-		panicindex = sysfunc("panicindex");
-		panicslice = sysfunc("panicslice");
-		throwreturn = sysfunc("throwreturn");
-	}
-
-	lno = setlineno(fn);
-
-	curfn = fn;
-	dowidth(curfn->type);
-
-	if(fn->nbody == nil) {
-		if(pure_go || strncmp(fn->nname->sym->name, "init·", 6) == 0) {
-			yyerror("missing function body", fn);
-			goto ret;
-		}
-		if(debug['A'])
-			goto ret;
-		emitptrargsmap();
-		goto ret;
-	}
-
-	saveerrors();
-
-	// set up domain for labels
-	clearlabels();
-
-	if(curfn->type->outnamed) {
-		// add clearing of the output parameters
-		t = structfirst(&save, getoutarg(curfn->type));
-		while(t != T) {
-			if(t->nname != N) {
-				n = nod(OAS, t->nname, N);
-				typecheck(&n, Etop);
-				curfn->nbody = concat(list1(n), curfn->nbody);
-			}
-			t = structnext(&save);
-		}
-	}
-	
-	order(curfn);
-	if(nerrors != 0)
-		goto ret;
-	
-	hasdefer = 0;
-	walk(curfn);
-	if(nerrors != 0)
-		goto ret;
-	if(flag_race)
-		racewalk(curfn);
-	if(nerrors != 0)
-		goto ret;
-
-	continpc = P;
-	breakpc = P;
-
-	pl = newplist();
-	pl->name = linksym(curfn->nname->sym);
-
-	setlineno(curfn);
-
-	nodconst(&nod1, types[TINT32], 0);
-	ptxt = gins(ATEXT, isblank(curfn->nname) ? N : curfn->nname, &nod1);
-	if(fn->dupok)
-		ptxt->TEXTFLAG |= DUPOK;
-	if(fn->wrapper)
-		ptxt->TEXTFLAG |= WRAPPER;
-	if(fn->needctxt)
-		ptxt->TEXTFLAG |= NEEDCTXT;
-	if(fn->nosplit)
-		ptxt->TEXTFLAG |= NOSPLIT;
-
-	// Clumsy but important.
-	// See test/recover.go for test cases and src/reflect/value.go
-	// for the actual functions being considered.
-	if(myimportpath != nil && strcmp(myimportpath, "reflect") == 0) {
-		if(strcmp(curfn->nname->sym->name, "callReflect") == 0 || strcmp(curfn->nname->sym->name, "callMethod") == 0)
-			ptxt->TEXTFLAG |= WRAPPER;
-	}	
-	
-	afunclit(&ptxt->from, curfn->nname);
-
-	ginit();
-
-	gcargs = makefuncdatasym("gcargs·%d", FUNCDATA_ArgsPointerMaps);
-	gclocals = makefuncdatasym("gclocals·%d", FUNCDATA_LocalsPointerMaps);
-
-	for(t=curfn->paramfld; t; t=t->down)
-		gtrack(tracksym(t->type));
-
-	for(l=fn->dcl; l; l=l->next) {
-		n = l->n;
-		if(n->op != ONAME) // might be OTYPE or OLITERAL
-			continue;
-		switch(n->class) {
-		case PAUTO:
-		case PPARAM:
-		case PPARAMOUT:
-			nodconst(&nod1, types[TUINTPTR], l->n->type->width);
-			p = gins(ATYPE, l->n, &nod1);
-			p->from.gotype = linksym(ngotype(l->n));
-			break;
-		}
-	}
-
-	genlist(curfn->enter);
-	genlist(curfn->nbody);
-	gclean();
-	checklabels();
-	if(nerrors != 0)
-		goto ret;
-	if(curfn->endlineno)
-		lineno = curfn->endlineno;
-
-	if(curfn->type->outtuple != 0)
-		ginscall(throwreturn, 0);
-
-	ginit();
-	// TODO: Determine when the final cgen_ret can be omitted. Perhaps always?
-	cgen_ret(nil);
-	if(hasdefer) {
-		// deferreturn pretends to have one uintptr argument.
-		// Reserve space for it so stack scanner is happy.
-		if(maxarg < widthptr)
-			maxarg = widthptr;
-	}
-	gclean();
-	if(nerrors != 0)
-		goto ret;
-
-	pc->as = ARET;	// overwrite AEND
-	pc->lineno = lineno;
-
-	fixjmp(ptxt);
-	if(!debug['N'] || debug['R'] || debug['P']) {
-		regopt(ptxt);
-		nilopt(ptxt);
-	}
-	expandchecks(ptxt);
-
-	oldstksize = stksize;
-	allocauto(ptxt);
-
-	if(0)
-		print("allocauto: %lld to %lld\n", oldstksize, (vlong)stksize);
-	USED(oldstksize);
-
-	setlineno(curfn);
-	if((int64)stksize+maxarg > (1ULL<<31)) {
-		yyerror("stack frame too large (>2GB)");
-		goto ret;
-	}
-
-	// Emit garbage collection symbols.
-	liveness(curfn, ptxt, gcargs, gclocals);
-	gcsymdup(gcargs);
-	gcsymdup(gclocals);
-
-	defframe(ptxt);
-
-	if(0)
-		frame(0);
-
-	// Remove leftover instrumentation from the instruction stream.
-	removevardef(ptxt);
-ret:
-	lineno = lno;
-}
-
-static void
-emitptrargsmap(void)
-{
-	int nptr, nbitmap, j, off;
-	vlong xoffset;
-	Bvec *bv;
-	Sym *sym;
-	
-	sym = lookup(smprint("%s.args_stackmap", curfn->nname->sym->name));
-
-	nptr = curfn->type->argwid / widthptr;
-	bv = bvalloc(nptr*2);
-	nbitmap = 1;
-	if(curfn->type->outtuple > 0)
-		nbitmap = 2;
-	off = duint32(sym, 0, nbitmap);
-	off = duint32(sym, off, bv->n);
-	if(curfn->type->thistuple > 0) {
-		xoffset = 0;
-		twobitwalktype1(getthisx(curfn->type), &xoffset, bv);
-	}
-	if(curfn->type->intuple > 0) {
-		xoffset = 0;
-		twobitwalktype1(getinargx(curfn->type), &xoffset, bv);
-	}
-	for(j = 0; j < bv->n; j += 32)
-		off = duint32(sym, off, bv->b[j/32]);
-	if(curfn->type->outtuple > 0) {
-		xoffset = 0;
-		twobitwalktype1(getoutargx(curfn->type), &xoffset, bv);
-		for(j = 0; j < bv->n; j += 32)
-			off = duint32(sym, off, bv->b[j/32]);
-	}
-	ggloblsym(sym, off, RODATA);
-	free(bv);
-}
-
-// Sort the list of stack variables. Autos after anything else,
-// within autos, unused after used, within used, things with
-// pointers first, zeroed things first, and then decreasing size.
-// Because autos are laid out in decreasing addresses
-// on the stack, pointers first, zeroed things first and decreasing size
-// really means, in memory, things with pointers needing zeroing at
-// the top of the stack and increasing in size.
-// Non-autos sort on offset.
-static int
-cmpstackvar(Node *a, Node *b)
-{
-	int ap, bp;
-
-	if (a->class != b->class)
-		return (a->class == PAUTO) ? +1 : -1;
-	if (a->class != PAUTO) {
-		if (a->xoffset < b->xoffset)
-			return -1;
-		if (a->xoffset > b->xoffset)
-			return +1;
-		return 0;
-	}
-	if ((a->used == 0) != (b->used == 0))
-		return b->used - a->used;
-
-	ap = haspointers(a->type);
-	bp = haspointers(b->type);
-	if(ap != bp)
-		return bp - ap;
-
-	ap = a->needzero;
-	bp = b->needzero;
-	if(ap != bp)
-		return bp - ap;
-
-	if(a->type->width < b->type->width)
-		return +1;
-	if(a->type->width > b->type->width)
-		return -1;
-
-	return strcmp(a->sym->name, b->sym->name);
-}
-
-// TODO(lvd) find out where the PAUTO/OLITERAL nodes come from.
-static void
-allocauto(Prog* ptxt)
-{
-	NodeList *ll;
-	Node* n;
-	vlong w;
-
-	stksize = 0;
-	stkptrsize = 0;
-
-	if(curfn->dcl == nil)
-		return;
-
-	// Mark the PAUTO's unused.
-	for(ll=curfn->dcl; ll != nil; ll=ll->next)
-		if (ll->n->class == PAUTO)
-			ll->n->used = 0;
-
-	markautoused(ptxt);
-
-	listsort(&curfn->dcl, cmpstackvar);
-
-	// Unused autos are at the end, chop 'em off.
-	ll = curfn->dcl;
-	n = ll->n;
-	if (n->class == PAUTO && n->op == ONAME && !n->used) {
-		// No locals used at all
-		curfn->dcl = nil;
-		fixautoused(ptxt);
-		return;
-	}
-
-	for(ll = curfn->dcl; ll->next != nil; ll=ll->next) {
-		n = ll->next->n;
-		if (n->class == PAUTO && n->op == ONAME && !n->used) {
-			ll->next = nil;
-			curfn->dcl->end = ll;
-			break;
-		}
-	}
-
-	// Reassign stack offsets of the locals that are still there.
-	for(ll = curfn->dcl; ll != nil; ll=ll->next) {
-		n = ll->n;
-		if (n->class != PAUTO || n->op != ONAME)
-			continue;
-
-		dowidth(n->type);
-		w = n->type->width;
-		if(w >= MAXWIDTH || w < 0)
-			fatal("bad width");
-		stksize += w;
-		stksize = rnd(stksize, n->type->align);
-		if(haspointers(n->type))
-			stkptrsize = stksize;
-		if(thechar == '5')
-			stksize = rnd(stksize, widthptr);
-		if(stksize >= (1ULL<<31)) {
-			setlineno(curfn);
-			yyerror("stack frame too large (>2GB)");
-		}
-		n->stkdelta = -stksize - n->xoffset;
-	}
-	stksize = rnd(stksize, widthreg);
-	stkptrsize = rnd(stkptrsize, widthreg);
-
-	fixautoused(ptxt);
-
-	// The debug information needs accurate offsets on the symbols.
-	for(ll = curfn->dcl; ll != nil; ll=ll->next) {
-		if (ll->n->class != PAUTO || ll->n->op != ONAME)
-			continue;
-		ll->n->xoffset += ll->n->stkdelta;
-		ll->n->stkdelta = 0;
-	}
-}
-
-static void movelargefn(Node*);
-
-void
-movelarge(NodeList *l)
-{
-	for(; l; l=l->next)
-		if(l->n->op == ODCLFUNC)
-			movelargefn(l->n);
-}
-
-static void
-movelargefn(Node *fn)
-{
-	NodeList *l;
-	Node *n;
-
-	for(l=fn->dcl; l != nil; l=l->next) {
-		n = l->n;
-		if(n->class == PAUTO && n->type != T && n->type->width > MaxStackVarSize)
-			addrescapes(n);
-	}
-}
-
-void
-cgen_checknil(Node *n)
-{
-	Node reg;
-
-	if(disable_checknil)
-		return;
-	// Ideally we wouldn't see any integer types here, but we do.
-	if(n->type == T || (!isptr[n->type->etype] && !isint[n->type->etype] && n->type->etype != TUNSAFEPTR)) {
-		dump("checknil", n);
-		fatal("bad checknil");
-	}
-	if((thechar == '5' && n->op != OREGISTER) || !n->addable || n->op == OLITERAL) {
-		regalloc(&reg, types[tptr], n);
-		cgen(n, &reg);
-		gins(ACHECKNIL, &reg, N);
-		regfree(&reg);
-		return;
-	}
-	gins(ACHECKNIL, n, N);
-}
diff --git a/src/cmd/gc/plive.c b/src/cmd/gc/plive.c
deleted file mode 100644
index 0feb2c7..0000000
--- a/src/cmd/gc/plive.c
+++ /dev/null
@@ -1,2017 +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.
-
-// 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.
-
-#include <u.h>
-#include <libc.h>
-#include "gg.h"
-#include "opt.h"
-#include "../ld/textflag.h"
-#include "../../runtime/funcdata.h"
-#include "../../runtime/mgc0.h"
-
-enum {
-	UNVISITED = 0,
-	VISITED = 1,
-};
-
-// An ordinary basic block.
-//
-// Instructions are threaded together in a doubly-linked list.  To iterate in
-// program order follow the link pointer from the first node and stop after the
-// last node has been visited
-//
-//   for(p = bb->first;; p = p->link) {
-//     ...
-//     if(p == bb->last)
-//       break;
-//   }
-//
-// To iterate in reverse program order by following the opt pointer from the
-// last node
-//
-//   for(p = bb->last; p != nil; p = p->opt) {
-//     ...
-//   }
-typedef struct BasicBlock BasicBlock;
-struct BasicBlock {
-	// An array of preceding blocks.  If the length of this array is 0 the
-	// block is probably the start block of the CFG.
-	Array *pred;
-
-	// An array out succeeding blocks.  If the length of this array is zero,
-	// the block probably ends in a return instruction.
-	Array *succ;
-
-	// First instruction in the block.  When part of a fully initialized
-	// control flow graph, the opt member will be nil.
-	Prog *first;
-
-	// Last instruction in the basic block.
-	Prog *last;
-
-	// The reverse post order number.  This value is initialized to -1 and
-	// will be replaced by a non-negative value when the CFG is constructed.
-	// After CFG construction, if rpo is -1 this block is unreachable.
-	int rpo;
-
-	// State to denote whether the block has been visited during a
-	// traversal.
-	int mark;
-	
-	// For use during livenessepilogue.
-	int lastbitmapindex;
-};
-
-// A collection of global state used by liveness analysis.
-typedef struct Liveness Liveness;
-struct Liveness {
-	// A pointer to the node corresponding to the function being analyzed.
-	Node *fn;
-
-	// A linked list of instructions for this function.
-	Prog *ptxt;
-
-	// A list of arguments and local variables in this function.
-	Array *vars;
-
-	// A list of basic blocks that are overlayed on the instruction list.
-	// The blocks are roughly in the same order as the instructions
-	// in the function (first block has TEXT instruction, and so on).
-	Array *cfg;
-
-	// Summary sets of block effects.
-	// The Bvec** is indexed by bb->rpo to yield a single Bvec*.
-	// That bit vector is indexed by variable number (same as lv->vars).
-	//
-	// 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)
-	//
-	// 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)
-	Bvec **uevar;
-	Bvec **varkill;
-	Bvec **livein;
-	Bvec **liveout;
-	Bvec **avarinit;
-	Bvec **avarinitany;
-	Bvec **avarinitall;
-
-	// An array with a bit vector for each safe point tracking live pointers
-	// in the arguments and locals area, indexed by bb->rpo.
-	Array *argslivepointers;
-	Array *livepointers;
-};
-
-static void*
-xmalloc(uintptr size)
-{
-	void *result;
-
-	result = malloc(size);
-	if(result == nil)
-		fatal("malloc failed");
-	return result;
-}
-
-// Constructs a new basic block containing a single instruction.
-static BasicBlock*
-newblock(Prog *prog)
-{
-	BasicBlock *result;
-
-	if(prog == nil)
-		fatal("newblock: prog cannot be nil");
-	result = xmalloc(sizeof(*result));
-	result->rpo = -1;
-	result->mark = UNVISITED;
-	result->first = prog;
-	result->last = prog;
-	result->pred = arraynew(2, sizeof(BasicBlock*));
-	result->succ = arraynew(2, sizeof(BasicBlock*));
-	return result;
-}
-
-// Frees a basic block and all of its leaf data structures.
-static void
-freeblock(BasicBlock *bb)
-{
-	if(bb == nil)
-		fatal("freeblock: cannot free nil");
-	arrayfree(bb->pred);
-	arrayfree(bb->succ);
-	free(bb);
-}
-
-// Adds an edge between two basic blocks by making from a predecessor of to and
-// to a successor of from.
-static void
-addedge(BasicBlock *from, BasicBlock *to)
-{
-	if(from == nil)
-		fatal("addedge: from is nil");
-	if(to == nil)
-		fatal("addedge: to is nil");
-	arrayadd(from->succ, &to);
-	arrayadd(to->pred, &from);
-}
-
-// Inserts prev before curr in the instruction
-// stream.  Any control flow, such as branches or fall throughs, that target the
-// existing instruction are adjusted to target the new instruction.
-static void
-splicebefore(Liveness *lv, BasicBlock *bb, Prog *prev, Prog *curr)
-{
-	Prog *next, tmp;
-
-	USED(lv);
-
-	// There may be other instructions pointing at curr,
-	// and we want them to now point at prev. Instead of
-	// trying to find all such instructions, swap the contents
-	// so that the problem becomes inserting next after curr.
-	// The "opt" field is the backward link in the linked list.
-
-	// Overwrite curr's data with prev, but keep the list links.
-	tmp = *curr;
-	*curr = *prev;
-	curr->opt = tmp.opt;
-	curr->link = tmp.link;
-	
-	// Overwrite prev (now next) with curr's old data.
-	next = prev;
-	*next = tmp;
-	next->opt = nil;
-	next->link = nil;
-
-	// Now insert next after curr.
-	next->link = curr->link;
-	next->opt = curr;
-	curr->link = next;
-	if(next->link && next->link->opt == curr)
-		next->link->opt = next;
-
-	if(bb->last == curr)
-		bb->last = next;
-}
-
-// A pretty printer for basic blocks.
-static void
-printblock(BasicBlock *bb)
-{
-	BasicBlock *pred;
-	BasicBlock *succ;
-	Prog *prog;
-	int i;
-
-	print("basic block %d\n", bb->rpo);
-	print("\tpred:");
-	for(i = 0; i < arraylength(bb->pred); i++) {
-		pred = *(BasicBlock**)arrayget(bb->pred, i);
-		print(" %d", pred->rpo);
-	}
-	print("\n");
-	print("\tsucc:");
-	for(i = 0; i < arraylength(bb->succ); i++) {
-		succ = *(BasicBlock**)arrayget(bb->succ, i);
-		print(" %d", succ->rpo);
-	}
-	print("\n");
-	print("\tprog:\n");
-	for(prog = bb->first;; prog=prog->link) {
-		print("\t\t%P\n", prog);
-		if(prog == bb->last)
-			break;
-	}
-}
-
-
-// Iterates over a basic block applying a callback to each instruction.  There
-// are two criteria for termination.  If the end of basic block is reached a
-// value of zero is returned.  If the callback returns a non-zero value, the
-// iteration is stopped and the value of the callback is returned.
-static int
-blockany(BasicBlock *bb, int (*callback)(Prog*))
-{
-	Prog *p;
-	int result;
-
-	for(p = bb->last; p != nil; p = p->opt) {
-		result = (*callback)(p);
-		if(result != 0)
-			return result;
-	}
-	return 0;
-}
-
-// Collects and returns and array of Node*s for functions arguments and local
-// variables.
-static Array*
-getvariables(Node *fn)
-{
-	Array *result;
-	NodeList *ll;
-
-	result = arraynew(0, sizeof(Node*));
-	for(ll = fn->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.
-			// For local variables, the bitmap only covers the stkptrsize
-			// bytes in the frame where variables containing pointers live.
-			// For arguments and results, the bitmap covers all variables,
-			// so we must include all the variables, even the ones without
-			// pointers.
-			//
-			// The Node.opt field is available for use by optimization passes.
-			// We use it to hold the index of the node in the variables array, plus 1
-			// (so that 0 means the Node is not in the variables array).
-			// Each pass should clear opt when done, but you never know,
-			// so clear them all ourselves too.
-			// The Node.curfn field is supposed to be set to the current function
-			// already, but for some compiler-introduced names it seems not to be,
-			// so fix that here.
-			// Later, when we want to find the index of a node in the variables list,
-			// we will check that n->curfn == curfn and n->opt > 0. Then n->opt - 1
-			// is the index in the variables list.
-			ll->n->opt = nil;
-			ll->n->curfn = curfn;
-			switch(ll->n->class) {
-			case PAUTO:
-				if(haspointers(ll->n->type)) {
-					ll->n->opt = (void*)(uintptr)(arraylength(result)+1);
-					arrayadd(result, &ll->n);
-				}
-				break;
-			case PPARAM:
-			case PPARAMOUT:
-				ll->n->opt = (void*)(uintptr)(arraylength(result)+1);
-				arrayadd(result, &ll->n);
-				break;
-			}
-		}
-	}
-	return result;
-}
-
-// A pretty printer for control flow graphs.  Takes an array of BasicBlock*s.
-static void
-printcfg(Array *cfg)
-{
-	BasicBlock *bb;
-	int32 i;
-
-	for(i = 0; i < arraylength(cfg); i++) {
-		bb = *(BasicBlock**)arrayget(cfg, i);
-		printblock(bb);
-	}
-}
-
-// Assigns a reverse post order number to each connected basic block using the
-// standard algorithm.  Unconnected blocks will not be affected.
-static void
-reversepostorder(BasicBlock *root, int32 *rpo)
-{
-	BasicBlock *bb;
-	int i;
-
-	root->mark = VISITED;
-	for(i = 0; i < arraylength(root->succ); i++) {
-		bb = *(BasicBlock**)arrayget(root->succ, i);
-		if(bb->mark == UNVISITED)
-			reversepostorder(bb, rpo);
-	}
-	*rpo -= 1;
-	root->rpo = *rpo;
-}
-
-// Comparison predicate used for sorting basic blocks by their rpo in ascending
-// order.
-static int
-blockrpocmp(const void *p1, const void *p2)
-{
-	BasicBlock *bb1;
-	BasicBlock *bb2;
-
-	bb1 = *(BasicBlock**)p1;
-	bb2 = *(BasicBlock**)p2;
-	if(bb1->rpo < bb2->rpo)
-		return -1;
-	if(bb1->rpo > bb2->rpo)
-		return 1;
-	return 0;
-}
-
-// A pattern matcher for call instructions.  Returns true when the instruction
-// is a call to a specific package qualified function name.
-static int
-iscall(Prog *prog, LSym *name)
-{
-	if(prog == nil)
-		fatal("iscall: prog is nil");
-	if(name == nil)
-		fatal("iscall: function name is nil");
-	if(prog->as != ACALL)
-		return 0;
-	return name == prog->to.sym;
-}
-
-// Returns true for instructions that call a runtime function implementing a
-// select communication clause.
-static int
-isselectcommcasecall(Prog *prog)
-{
-	static LSym* names[5];
-	int32 i;
-
-	if(names[0] == nil) {
-		names[0] = linksym(pkglookup("selectsend", runtimepkg));
-		names[1] = linksym(pkglookup("selectrecv", runtimepkg));
-		names[2] = linksym(pkglookup("selectrecv2", runtimepkg));
-		names[3] = linksym(pkglookup("selectdefault", runtimepkg));
-	}
-	for(i = 0; names[i] != nil; i++)
-		if(iscall(prog, names[i]))
-			return 1;
-	return 0;
-}
-
-// Returns true for call instructions that target runtime·newselect.
-static int
-isnewselect(Prog *prog)
-{
-	static LSym *sym;
-
-	if(sym == nil)
-		sym = linksym(pkglookup("newselect", runtimepkg));
-	return iscall(prog, sym);
-}
-
-// Returns true for call instructions that target runtime·selectgo.
-static int
-isselectgocall(Prog *prog)
-{
-	static LSym *sym;
-
-	if(sym == nil)
-		sym = linksym(pkglookup("selectgo", runtimepkg));
-	return iscall(prog, sym);
-}
-
-static int
-isdeferreturn(Prog *prog)
-{
-	static LSym *sym;
-
-	if(sym == nil)
-		sym = linksym(pkglookup("deferreturn", runtimepkg));
-	return iscall(prog, sym);
-}
-
-// Walk backwards from a runtime·selectgo call up to its immediately dominating
-// runtime·newselect call.  Any successor nodes of communication clause nodes
-// are implicit successors of the runtime·selectgo call node.  The goal of this
-// analysis is to add these missing edges to complete the control flow graph.
-static void
-addselectgosucc(BasicBlock *selectgo)
-{
-	BasicBlock *pred;
-	BasicBlock *succ;
-
-	pred = selectgo;
-	for(;;) {
-		if(arraylength(pred->pred) == 0)
-			fatal("selectgo does not have a newselect");
-		pred = *(BasicBlock**)arrayget(pred->pred, 0);
-		if(blockany(pred, isselectcommcasecall)) {
-			// A select comm case block should have exactly one
-			// successor.
-			if(arraylength(pred->succ) != 1)
-				fatal("select comm case has too many successors");
-			succ = *(BasicBlock**)arrayget(pred->succ, 0);
-			// Its successor should have exactly two successors.
-			// The drop through should flow to the selectgo block
-			// and the branch should lead to the select case
-			// statements block.
-			if(arraylength(succ->succ) != 2)
-				fatal("select comm case successor has too many successors");
-			// Add the block as a successor of the selectgo block.
-			addedge(selectgo, succ);
-		}
-		if(blockany(pred, isnewselect)) {
-			// Reached the matching newselect.
-			break;
-		}
-	}
-}
-
-// The entry point for the missing selectgo control flow algorithm.  Takes an
-// array of BasicBlock*s containing selectgo calls.
-static void
-fixselectgo(Array *selectgo)
-{
-	BasicBlock *bb;
-	int32 i;
-
-	for(i = 0; i < arraylength(selectgo); i++) {
-		bb = *(BasicBlock**)arrayget(selectgo, i);
-		addselectgosucc(bb);
-	}
-}
-
-// Constructs a control flow graph from a sequence of instructions.  This
-// procedure is complicated by various sources of implicit control flow that are
-// not accounted for using the standard cfg construction algorithm.  Returns an
-// array of BasicBlock*s in control flow graph form (basic blocks ordered by
-// their RPO number).
-static Array*
-newcfg(Prog *firstp)
-{
-	Prog *p;
-	Prog *prev;
-	BasicBlock *bb;
-	Array *cfg;
-	Array *selectgo;
-	int32 i;
-	int32 rpo;
-
-	// Reset the opt field of each prog to nil.  In the first and second
-	// passes, instructions that are labels temporarily use the opt field to
-	// point to their basic block.  In the third pass, the opt field reset
-	// to point to the predecessor of an instruction in its basic block.
-	for(p = firstp; p != P; p = p->link)
-		p->opt = nil;
-
-	// Allocate an array to remember where we have seen selectgo calls.
-	// These blocks will be revisited to add successor control flow edges.
-	selectgo = arraynew(0, sizeof(BasicBlock*));
-
-	// Loop through all instructions identifying branch targets
-	// and fall-throughs and allocate basic blocks.
-	cfg = arraynew(0, sizeof(BasicBlock*));
-	bb = newblock(firstp);
-	arrayadd(cfg, &bb);
-	for(p = firstp; p != P; p = p->link) {
-		if(p->to.type == D_BRANCH) {
-			if(p->to.u.branch == nil)
-				fatal("prog branch to nil");
-			if(p->to.u.branch->opt == nil) {
-				p->to.u.branch->opt = newblock(p->to.u.branch);
-				arrayadd(cfg, &p->to.u.branch->opt);
-			}
-			if(p->as != AJMP && p->link != nil && p->link->opt == nil) {
-				p->link->opt = newblock(p->link);
-				arrayadd(cfg, &p->link->opt);
-			}
-		} else if(isselectcommcasecall(p) || isselectgocall(p)) {
-			// Accommodate implicit selectgo control flow.
-			if(p->link->opt == nil) {
-				p->link->opt = newblock(p->link);
-				arrayadd(cfg, &p->link->opt);
-			}
-		}
-	}
-
-	// 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.
-	for(i = 0; i < arraylength(cfg); i++) {
-		bb = *(BasicBlock**)arrayget(cfg, i);
-		for(p = bb->last; p != nil; p = p->link) {
-			if(p->opt != nil && p != bb->last)
-				break;
-			bb->last = p;
-
-			// Stop before an unreachable RET, to avoid creating
-			// unreachable control flow nodes.
-			if(p->link != nil && p->link->as == ARET && p->link->mode == 1)
-				break;
-
-			// Collect basic blocks with selectgo calls.
-			if(isselectgocall(p))
-				arrayadd(selectgo, &bb);
-		}
-		if(bb->last->to.type == D_BRANCH)
-			addedge(bb, bb->last->to.u.branch->opt);
-		if(bb->last->link != nil) {
-			// Add a fall-through when the instruction is
-			// not an unconditional control transfer.
-			switch(bb->last->as) {
-			case AJMP:
-			case ARET:
-			case AUNDEF:
-				break;
-			default:
-				addedge(bb, bb->last->link->opt);
-			}
-		}
-	}
-
-	// Add back links so the instructions in a basic block can be traversed
-	// backward.  This is the final state of the instruction opt field.
-	for(i = 0; i < arraylength(cfg); i++) {
-		bb = *(BasicBlock**)arrayget(cfg, i);
-		p = bb->first;
-		prev = nil;
-		for(;;) {
-			p->opt = prev;
-			if(p == bb->last)
-				break;
-			prev = p;
-			p = p->link;
-		}
-	}
-
-	// Add missing successor edges to the selectgo blocks.
-	if(arraylength(selectgo))
-		fixselectgo(selectgo);
-	arrayfree(selectgo);
-
-	// Find a depth-first order and assign a depth-first number to
-	// all basic blocks.
-	for(i = 0; i < arraylength(cfg); i++) {
-		bb = *(BasicBlock**)arrayget(cfg, i);
-		bb->mark = UNVISITED;
-	}
-	bb = *(BasicBlock**)arrayget(cfg, 0);
-	rpo = arraylength(cfg);
-	reversepostorder(bb, &rpo);
-
-	// Sort the basic blocks by their depth first number.  The
-	// array is now a depth-first spanning tree with the first
-	// node being the root.
-	arraysort(cfg, blockrpocmp);
-	bb = *(BasicBlock**)arrayget(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.
-	if(bb->rpo == -1) {
-		print("newcfg: unreachable basic block for %P\n", bb->last);
-		printcfg(cfg);
-		fatal("newcfg: invalid control flow graph");
-	}
-
-	return cfg;
-}
-
-// Frees a control flow graph (an array of BasicBlock*s) and all of its leaf
-// data structures.
-static void
-freecfg(Array *cfg)
-{
-	BasicBlock *bb;
-	BasicBlock *bb0;
-	Prog *p;
-	int32 i;
-	int32 len;
-
-	len = arraylength(cfg);
-	if(len > 0) {
-		bb0 = *(BasicBlock**)arrayget(cfg, 0);
-		for(p = bb0->first; p != P; p = p->link) {
-			p->opt = nil;
-		}
-		for(i = 0; i < len; i++) {
-			bb = *(BasicBlock**)arrayget(cfg, i);
-			freeblock(bb);
-		}
-	}
-	arrayfree(cfg);
-}
-
-// Returns true if the node names a variable that is otherwise uninteresting to
-// the liveness computation.
-static int
-isfunny(Node *node)
-{
-	char *names[] = { ".fp", ".args", nil };
-	int i;
-
-	if(node->sym != nil && node->sym->name != nil)
-		for(i = 0; names[i] != nil; i++)
-			if(strcmp(node->sym->name, names[i]) == 0)
-				return 1;
-	return 0;
-}
-
-// Computes the effects of an instruction on a set of
-// variables.  The vars argument is an array of Node*s.
-//
-// The output vectors give bits for variables:
-//	uevar - used by this instruction
-//	varkill - killed by this instruction
-//		for variables without address taken, means variable was set
-//		for variables with address taken, means variable was marked dead
-//	avarinit - initialized or referred to by this instruction,
-//		only for variables with address taken but not escaping to heap
-//
-// The avarinit output serves as a signal that the data has been
-// initialized, because any use of a variable must come after its
-// initialization.
-static void
-progeffects(Prog *prog, Array *vars, Bvec *uevar, Bvec *varkill, Bvec *avarinit)
-{
-	ProgInfo info;
-	Addr *from;
-	Addr *to;
-	Node *node;
-	int32 i;
-	int32 pos;
-
-	bvresetall(uevar);
-	bvresetall(varkill);
-	bvresetall(avarinit);
-
-	proginfo(&info, prog);
-	if(prog->as == ARET) {
-		// Return instructions implicitly read all the arguments.  For
-		// the sake of correctness, out arguments must be read.  For the
-		// sake of backtrace quality, we read in arguments as well.
-		//
-		// A return instruction with a p->to is a tail return, which brings
-		// the stack pointer back up (if it ever went down) and then jumps
-		// to a new function entirely. That form of instruction must read
-		// all the parameters for correctness, and similarly it must not
-		// read the out arguments - they won't be set until the new
-		// function runs.
-		for(i = 0; i < arraylength(vars); i++) {
-			node = *(Node**)arrayget(vars, i);
-			switch(node->class & ~PHEAP) {
-			case PPARAM:
-				bvset(uevar, i);
-				break;
-			case PPARAMOUT:
-				// If the result had its address taken, it is being tracked
-				// by the avarinit code, which does not use uevar.
-				// If we added it to uevar too, we'd not see any kill
-				// and decide that the varible was live entry, which it is not.
-				// So only use uevar in the non-addrtaken case.
-				// The p->to.type == D_NONE limits the bvset to
-				// non-tail-call return instructions; see note above
-				// the for loop for details.
-				if(!node->addrtaken && prog->to.type == D_NONE)
-					bvset(uevar, i);
-				break;
-			}
-		}
-		return;
-	}
-	if(prog->as == ATEXT) {
-		// A text instruction marks the entry point to a function and
-		// the definition point of all in arguments.
-		for(i = 0; i < arraylength(vars); i++) {
-			node = *(Node**)arrayget(vars, i);
-			switch(node->class & ~PHEAP) {
-			case PPARAM:
-				if(node->addrtaken)
-					bvset(avarinit, i);
-				bvset(varkill, i);
-				break;
-			}
-		}
-		return;
-	}
-	if(info.flags & (LeftRead | LeftWrite | LeftAddr)) {
-		from = &prog->from;
-		if (from->node != nil && from->sym != nil && from->node->curfn == curfn) {
-			switch(from->node->class & ~PHEAP) {
-			case PAUTO:
-			case PPARAM:
-			case PPARAMOUT:
-				pos = (int)(uintptr)from->node->opt - 1; // index in vars
-				if(pos == -1)
-					goto Next;
-				if(pos >= arraylength(vars) || *(Node**)arrayget(vars, pos) != from->node)
-					fatal("bad bookkeeping in liveness %N %d", from->node, pos);
-				if(from->node->addrtaken) {
-					bvset(avarinit, pos);
-				} else {
-					if(info.flags & (LeftRead | LeftAddr))
-						bvset(uevar, pos);
-					if(info.flags & LeftWrite)
-						if(from->node != nil && !isfat(from->node->type))
-							bvset(varkill, pos);
-				}
-			}
-		}
-	}
-Next:
-	if(info.flags & (RightRead | RightWrite | RightAddr)) {
-		to = &prog->to;
-		if (to->node != nil && to->sym != nil && to->node->curfn == curfn) {
-			switch(to->node->class & ~PHEAP) {
-			case PAUTO:
-			case PPARAM:
-			case PPARAMOUT:
-				pos = (int)(uintptr)to->node->opt - 1; // index in vars
-				if(pos == -1)
-					goto Next1;
-				if(pos >= arraylength(vars) || *(Node**)arrayget(vars, pos) != to->node)
-					fatal("bad bookkeeping in liveness %N %d", to->node, pos);
-				if(to->node->addrtaken) {
-					if(prog->as != AVARKILL)
-						bvset(avarinit, pos);
-					if(prog->as == AVARDEF || prog->as == AVARKILL)
-						bvset(varkill, pos);
-				} else {
-					// RightRead is a read, obviously.
-					// RightAddr by itself is also implicitly a read.
-					//
-					// RightAddr|RightWrite means that the address is being taken
-					// but only so that the instruction can write to the value.
-					// 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) || (info.flags & (RightAddr|RightWrite)) == RightAddr)
-						bvset(uevar, pos);
-					if(info.flags & RightWrite)
-						if(to->node != nil && (!isfat(to->node->type) || prog->as == AVARDEF))
-							bvset(varkill, pos);
-				}
-			}
-		}
-	}
-Next1:;
-}
-
-// Constructs a new liveness structure used to hold the global state of the
-// liveness computation.  The cfg argument is an array of BasicBlock*s and the
-// vars argument is an array of Node*s.
-static Liveness*
-newliveness(Node *fn, Prog *ptxt, Array *cfg, Array *vars)
-{
-	Liveness *result;
-	int32 i;
-	int32 nblocks;
-	int32 nvars;
-
-	result = xmalloc(sizeof(*result));
-	result->fn = fn;
-	result->ptxt = ptxt;
-	result->cfg = cfg;
-	result->vars = vars;
-
-	nblocks = arraylength(cfg);
-	result->uevar = xmalloc(sizeof(Bvec*) * nblocks);
-	result->varkill = xmalloc(sizeof(Bvec*) * nblocks);
-	result->livein = xmalloc(sizeof(Bvec*) * nblocks);
-	result->liveout = xmalloc(sizeof(Bvec*) * nblocks);
-	result->avarinit = xmalloc(sizeof(Bvec*) * nblocks);
-	result->avarinitany = xmalloc(sizeof(Bvec*) * nblocks);
-	result->avarinitall = xmalloc(sizeof(Bvec*) * nblocks);
-
-	nvars = arraylength(vars);
-	for(i = 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);
-	}
-
-	result->livepointers = arraynew(0, sizeof(Bvec*));
-	result->argslivepointers = arraynew(0, sizeof(Bvec*));
-	return result;
-}
-
-// Frees the liveness structure and all of its leaf data structures.
-static void
-freeliveness(Liveness *lv)
-{
-	int32 i;
-
-	if(lv == nil)
-		fatal("freeliveness: cannot free nil");
-
-	for(i = 0; i < arraylength(lv->livepointers); i++)
-		free(*(Bvec**)arrayget(lv->livepointers, i));
-	arrayfree(lv->livepointers);
-
-	for(i = 0; i < arraylength(lv->argslivepointers); i++)
-		free(*(Bvec**)arrayget(lv->argslivepointers, i));
-	arrayfree(lv->argslivepointers);
-
-	for(i = 0; i < arraylength(lv->cfg); i++) {
-		free(lv->uevar[i]);
-		free(lv->varkill[i]);
-		free(lv->livein[i]);
-		free(lv->liveout[i]);
-		free(lv->avarinit[i]);
-		free(lv->avarinitany[i]);
-		free(lv->avarinitall[i]);
-	}
-
-	free(lv->uevar);
-	free(lv->varkill);
-	free(lv->livein);
-	free(lv->liveout);
-	free(lv->avarinit);
-	free(lv->avarinitany);
-	free(lv->avarinitall);
-
-	free(lv);
-}
-
-static void
-printeffects(Prog *p, Bvec *uevar, Bvec *varkill, Bvec *avarinit)
-{
-	print("effects of %P", p);
-	print("\nuevar: ");
-	bvprint(uevar);
-	print("\nvarkill: ");
-	bvprint(varkill);
-	print("\navarinit: ");
-	bvprint(avarinit);
-	print("\n");
-}
-
-// Pretty print a variable node.  Uses Pascal like conventions for pointers and
-// addresses to avoid confusing the C like conventions used in the node variable
-// names.
-static void
-printnode(Node *node)
-{
-	char *p;
-	char *a;
-
-	p = haspointers(node->type) ? "^" : "";
-	a = node->addrtaken ? "@" : "";
-	print(" %N%s%s", node, p, a);
-}
-
-// Pretty print a list of variables.  The vars argument is an array of Node*s.
-static void
-printvars(char *name, Bvec *bv, Array *vars)
-{
-	int32 i;
-
-	print("%s:", name);
-	for(i = 0; i < arraylength(vars); i++)
-		if(bvget(bv, i))
-			printnode(*(Node**)arrayget(vars, i));
-	print("\n");
-}
-
-// Prints a basic block annotated with the information computed by liveness
-// analysis.
-static void
-livenessprintblock(Liveness *lv, BasicBlock *bb)
-{
-	BasicBlock *pred;
-	BasicBlock *succ;
-	Prog *prog;
-	Bvec *live;
-	int i;
-	int32 pos;
-
-	print("basic block %d\n", bb->rpo);
-
-	print("\tpred:");
-	for(i = 0; i < arraylength(bb->pred); i++) {
-		pred = *(BasicBlock**)arrayget(bb->pred, i);
-		print(" %d", pred->rpo);
-	}
-	print("\n");
-
-	print("\tsucc:");
-	for(i = 0; i < arraylength(bb->succ); i++) {
-		succ = *(BasicBlock**)arrayget(bb->succ, i);
-		print(" %d", succ->rpo);
-	}
-	print("\n");
-
-	printvars("\tuevar", lv->uevar[bb->rpo], lv->vars);
-	printvars("\tvarkill", lv->varkill[bb->rpo], lv->vars);
-	printvars("\tlivein", lv->livein[bb->rpo], lv->vars);
-	printvars("\tliveout", lv->liveout[bb->rpo], lv->vars);
-	printvars("\tavarinit", lv->avarinit[bb->rpo], lv->vars);
-	printvars("\tavarinitany", lv->avarinitany[bb->rpo], lv->vars);
-	printvars("\tavarinitall", lv->avarinitall[bb->rpo], lv->vars);
-
-	print("\tprog:\n");
-	for(prog = bb->first;; prog = prog->link) {
-		print("\t\t%P", prog);
-		if(prog->as == APCDATA && prog->from.offset == PCDATA_StackMapIndex) {
-			pos = prog->to.offset;
-			live = *(Bvec**)arrayget(lv->livepointers, pos);
-			print(" ");
-			bvprint(live);
-		}
-		print("\n");
-		if(prog == bb->last)
-			break;
-	}
-}
-
-// Prints a control flow graph annotated with any information computed by
-// liveness analysis.
-static void
-livenessprintcfg(Liveness *lv)
-{
-	BasicBlock *bb;
-	int32 i;
-
-	for(i = 0; i < arraylength(lv->cfg); i++) {
-		bb = *(BasicBlock**)arrayget(lv->cfg, i);
-		livenessprintblock(lv, bb);
-	}
-}
-
-static void
-checkauto(Node *fn, Prog *p, Node *n)
-{
-	NodeList *l;
-
-	for(l = fn->dcl; l != nil; l = l->next)
-		if(l->n->op == ONAME && l->n->class == PAUTO && l->n == n)
-			return;
-
-	print("checkauto %N: %N (%p; class=%d) not found in %P\n", curfn, n, n, n->class, p);
-	for(l = fn->dcl; l != nil; l = l->next)
-		print("\t%N (%p; class=%d)\n", l->n, l->n, l->n->class);
-	yyerror("checkauto: invariant lost");
-}
-
-static void
-checkparam(Node *fn, Prog *p, Node *n)
-{
-	NodeList *l;
-	Node *a;
-	int class;
-
-	if(isfunny(n))
-		return;
-	for(l = fn->dcl; l != nil; l = l->next) {
-		a = l->n;
-		class = a->class & ~PHEAP;
-		if(a->op == ONAME && (class == PPARAM || class == PPARAMOUT) && a == n)
-			return;
-	}
-
-	print("checkparam %N: %N (%p; class=%d) not found in %P\n", curfn, n, n, n->class, p);
-	for(l = fn->dcl; l != nil; l = l->next)
-		print("\t%N (%p; class=%d)\n", l->n, l->n, l->n->class);
-	yyerror("checkparam: invariant lost");
-}
-
-static void
-checkprog(Node *fn, Prog *p)
-{
-	if(p->from.type == D_AUTO)
-		checkauto(fn, p, p->from.node);
-	if(p->from.type == D_PARAM)
-		checkparam(fn, p, p->from.node);
-	if(p->to.type == D_AUTO)
-		checkauto(fn, p, p->to.node);
-	if(p->to.type == D_PARAM)
-		checkparam(fn, p, p->to.node);
-}
-
-// Check instruction invariants.  We assume that the nodes corresponding to the
-// sources and destinations of memory operations will be declared in the
-// function.  This is not strictly true, as is the case for the so-called funny
-// nodes and there are special cases to skip over that stuff.  The analysis will
-// fail if this invariant blindly changes.
-static void
-checkptxt(Node *fn, Prog *firstp)
-{
-	Prog *p;
-
-	if(debuglive == 0)
-		return;
-
-	for(p = firstp; p != P; p = p->link) {
-		if(0)
-			print("analyzing '%P'\n", p);
-		switch(p->as) {
-		case ADATA:
-		case AGLOBL:
-		case ANAME:
-		case ASIGNAME:
-		case ATYPE:
-			continue;
-		}
-		checkprog(fn, p);
-	}
-}
-
-// NOTE: The bitmap for a specific type t should be cached in t after the first run
-// 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.
-void
-twobitwalktype1(Type *t, vlong *xoffset, Bvec *bv)
-{
-	vlong fieldoffset;
-	vlong i;
-	vlong o;
-	Type *t1;
-
-	if(t->align > 0 && (*xoffset & (t->align - 1)) != 0)
-		fatal("twobitwalktype1: invalid initial alignment, %T", t);
-
-	switch(t->etype) {
-	case TINT8:
-	case TUINT8:
-	case TINT16:
-	case TUINT16:
-	case TINT32:
-	case TUINT32:
-	case TINT64:
-	case TUINT64:
-	case TINT:
-	case TUINT:
-	case TUINTPTR:
-	case TBOOL:
-	case TFLOAT32:
-	case TFLOAT64:
-	case TCOMPLEX64:
-	case TCOMPLEX128:
-		for(i = 0; i < t->width; i++) {
-			bvset(bv, ((*xoffset + i) / widthptr) * BitsPerPointer); // 1 = live scalar
-		}
-		*xoffset += t->width;
-		break;
-
-	case TPTR32:
-	case TPTR64:
-	case TUNSAFEPTR:
-	case TFUNC:
-	case TCHAN:
-	case TMAP:
-		if((*xoffset & (widthptr-1)) != 0)
-			fatal("twobitwalktype1: invalid alignment, %T", t);
-		bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1); // 2 = live ptr
-		*xoffset += t->width;
-		break;
-
-	case TSTRING:
-		// struct { byte *str; intgo len; }
-		if((*xoffset & (widthptr-1)) != 0)
-			fatal("twobitwalktype1: invalid alignment, %T", t);
-		bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1); // 2 = live ptr in first slot
-		*xoffset += t->width;
-		break;
-
-	case TINTER:
-		// struct { Itab *tab;	union { void *ptr, uintptr val } data; }
-		// or, when isnilinter(t)==true:
-		// struct { Type *type; union { void *ptr, uintptr val } data; }
-		if((*xoffset & (widthptr-1)) != 0)
-			fatal("twobitwalktype1: invalid alignment, %T", t);
-		bvset(bv, ((*xoffset / widthptr) * BitsPerPointer) + 0);
-		bvset(bv, ((*xoffset / widthptr) * BitsPerPointer) + 1); // 3 = multiword
-		// next word contains 2 = Iface, 3 = Eface
-		if(isnilinter(t)) {
-			bvset(bv, ((*xoffset / widthptr) * BitsPerPointer) + 2);
-			bvset(bv, ((*xoffset / widthptr) * BitsPerPointer) + 3);
-		} else {
-			bvset(bv, ((*xoffset / widthptr) * BitsPerPointer) + 3);
-		}
-		*xoffset += t->width;
-		break;
-
-	case TARRAY:
-		// The value of t->bound is -1 for slices types and >0 for
-		// for fixed array types.  All other values are invalid.
-		if(t->bound < -1)
-			fatal("twobitwalktype1: invalid bound, %T", t);
-		if(isslice(t)) {
-			// struct { byte *array; uintgo len; uintgo cap; }
-			if((*xoffset & (widthptr-1)) != 0)
-				fatal("twobitwalktype1: invalid TARRAY alignment, %T", t);
-			bvset(bv, (*xoffset / widthptr) * BitsPerPointer + 1); // 2 = live ptr in first slot
-			*xoffset += t->width;
-		} else
-			for(i = 0; i < t->bound; i++)
-				twobitwalktype1(t->type, xoffset, bv);
-		break;
-
-	case TSTRUCT:
-		o = 0;
-		for(t1 = t->type; t1 != T; t1 = t1->down) {
-			fieldoffset = t1->width;
-			*xoffset += fieldoffset - o;
-			twobitwalktype1(t1->type, xoffset, bv);
-			o = fieldoffset + t1->type->width;
-		}
-		*xoffset += t->width - o;
-		break;
-
-	default:
-		fatal("twobitwalktype1: unexpected type, %T", t);
-	}
-}
-
-// Returns the number of words of local variables.
-static int32
-localswords(void)
-{
-	return stkptrsize / widthptr;
-}
-
-// Returns the number of words of in and out arguments.
-static int32
-argswords(void)
-{
-	return curfn->type->argwid / widthptr;
-}
-
-// 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.
-static void
-twobitlivepointermap(Liveness *lv, Bvec *liveout, Array *vars, Bvec *args, Bvec *locals)
-{
-	Node *node;
-	Type *thisargtype;
-	Type *inargtype;
-	vlong xoffset;
-	int32 i;
-
-	for(i = 0; (i = bvnext(liveout, i)) >= 0; i++) {
-		node = *(Node**)arrayget(vars, i);
-		switch(node->class) {
-		case PAUTO:
-			xoffset = node->xoffset + stkptrsize;
-			twobitwalktype1(node->type, &xoffset, locals);
-			break;
-		case PPARAM:
-		case PPARAMOUT:
-			xoffset = node->xoffset;
-			twobitwalktype1(node->type, &xoffset, args);
-			break;
-		}
-	}
-	
-	// The node list only contains declared names.
-	// If the receiver or arguments are unnamed, they will be omitted
-	// from the list above. Preserve those values - even though they are unused -
-	// in order to keep their addresses live for use in stack traces.
-	thisargtype = getthisx(lv->fn->type);
-	if(thisargtype != nil) {
-		xoffset = 0;
-		twobitwalktype1(thisargtype, &xoffset, args);
-	}
-	inargtype = getinargx(lv->fn->type);
-	if(inargtype != nil) {
-		xoffset = 0;
-		twobitwalktype1(inargtype, &xoffset, args);
-	}
-}
-
-// Construct a disembodied instruction.
-static Prog*
-unlinkedprog(int as)
-{
-	Prog *p;
-
-	p = mal(sizeof(*p));
-	clearp(p);
-	p->as = as;
-	return p;
-}
-
-// Construct a new PCDATA instruction associated with and for the purposes of
-// covering an existing instruction.
-static Prog*
-newpcdataprog(Prog *prog, int32 index)
-{
-	Node from, to;
-	Prog *pcdata;
-
-	nodconst(&from, types[TINT32], PCDATA_StackMapIndex);
-	nodconst(&to, types[TINT32], index);
-	pcdata = unlinkedprog(APCDATA);
-	pcdata->lineno = prog->lineno;
-	naddr(&from, &pcdata->from, 0);
-	naddr(&to, &pcdata->to, 0);
-	return pcdata;
-}
-
-// Returns true for instructions that are safe points that must be annotated
-// with liveness information.
-static int
-issafepoint(Prog *prog)
-{
-	return prog->as == ATEXT || prog->as == ACALL;
-}
-
-// Initializes the sets for solving the live variables.  Visits all the
-// instructions in each basic block to summarizes the information at each basic
-// block
-static void
-livenessprologue(Liveness *lv)
-{
-	BasicBlock *bb;
-	Bvec *uevar, *varkill, *avarinit;
-	Prog *p;
-	int32 i;
-	int32 nvars;
-
-	nvars = arraylength(lv->vars);
-	uevar = bvalloc(nvars);
-	varkill = bvalloc(nvars);
-	avarinit = bvalloc(nvars);
-	for(i = 0; i < arraylength(lv->cfg); i++) {
-		bb = *(BasicBlock**)arrayget(lv->cfg, i);
-		// Walk the block instructions backward and update the block
-		// effects with the each prog effects.
-		for(p = bb->last; p != nil; p = p->opt) {
-			progeffects(p, 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);			
-		}
-		// 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) {
-			progeffects(p, 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);
-			if(p == bb->last)
-				break;
-		}
-	}
-	free(uevar);
-	free(varkill);
-	free(avarinit);
-}
-
-// Solve the liveness dataflow equations.
-static void
-livenesssolve(Liveness *lv)
-{
-	BasicBlock *bb, *succ, *pred;
-	Bvec *newlivein, *newliveout, *any, *all;
-	int32 rpo, i, j, change;
-
-	// These temporary bitvectors exist to avoid successive allocations and
-	// frees within the loop.
-	newlivein = bvalloc(arraylength(lv->vars));
-	newliveout = bvalloc(arraylength(lv->vars));
-	any = bvalloc(arraylength(lv->vars));
-	all = bvalloc(arraylength(lv->vars));
-
-	// 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 = 0; i < arraylength(lv->cfg); i++) {
-		bb = *(BasicBlock**)arrayget(lv->cfg, i);
-		rpo = bb->rpo;
-		if(i == 0)
-			bvcopy(lv->avarinitall[rpo], lv->avarinit[rpo]);
-		else {
-			bvresetall(lv->avarinitall[rpo]);
-			bvnot(lv->avarinitall[rpo]);
-		}
-		bvcopy(lv->avarinitany[rpo], lv->avarinit[rpo]);
-	}
-
-	change = 1;
-	while(change != 0) {
-		change = 0;
-		for(i = 0; i < arraylength(lv->cfg); i++) {
-			bb = *(BasicBlock**)arrayget(lv->cfg, i);
-			rpo = bb->rpo;
-			bvresetall(any);
-			bvresetall(all);
-			for(j = 0; j < arraylength(bb->pred); j++) {
-				pred = *(BasicBlock**)arrayget(bb->pred, j);
-				if(j == 0) {
-					bvcopy(any, lv->avarinitany[pred->rpo]);
-					bvcopy(all, lv->avarinitall[pred->rpo]);
-				} else {
-					bvor(any, any, lv->avarinitany[pred->rpo]);
-					bvand(all, all, lv->avarinitall[pred->rpo]);
-				}
-			}
-			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])) {
-				change = 1;
-				bvcopy(lv->avarinitany[rpo], any);
-			}
-			if(bvcmp(all, lv->avarinitall[rpo])) {
-				change = 1;
-				bvcopy(lv->avarinitall[rpo], all);
-			}
-		}
-	}
-
-	// Iterate through the blocks in reverse round-robin fashion.  A work
-	// queue might be slightly faster.  As is, the number of iterations is
-	// so low that it hardly seems to be worth the complexity.
-	change = 1;
-	while(change != 0) {
-		change = 0;
-		// Walk blocks in the general direction of propagation.  This
-		// improves convergence.
-		for(i = arraylength(lv->cfg) - 1; i >= 0; 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 = *(BasicBlock**)arrayget(lv->cfg, i);
-			rpo = bb->rpo;
-			bvresetall(newliveout);
-			for(j = 0; j < arraylength(bb->succ); j++) {
-				succ = *(BasicBlock**)arrayget(bb->succ, j);
-				bvor(newliveout, newliveout, lv->livein[succ->rpo]);
-			}
-			if(bvcmp(lv->liveout[rpo], newliveout)) {
-				change = 1;
-				bvcopy(lv->liveout[rpo], newliveout);
-			}
-
-			// A variable is live on input to this block
-			// if it is live on output from this block and
-			// 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]);
-			bvor(lv->livein[rpo], newlivein, lv->uevar[rpo]);
-		}
-	}
-
-	free(newlivein);
-	free(newliveout);
-	free(any);
-	free(all);
-}
-
-// This function is slow but it is only used for generating debug prints.
-// Check whether n is marked live in args/locals.
-static int
-islive(Node *n, Bvec *args, Bvec *locals)
-{
-	int i;
-
-	switch(n->class) {
-	case PPARAM:
-	case PPARAMOUT:
-		for(i = 0; i < n->type->width/widthptr*BitsPerPointer; i++)
-			if(bvget(args, n->xoffset/widthptr*BitsPerPointer + i))
-				return 1;
-		break;
-	case PAUTO:
-		for(i = 0; i < n->type->width/widthptr*BitsPerPointer; i++)
-			if(bvget(locals, (n->xoffset + stkptrsize)/widthptr*BitsPerPointer + i))
-				return 1;
-		break;
-	}
-	return 0;
-}
-
-// Visits all instructions in a basic block and computes a bit vector of live
-// variables at each safe point locations.
-static void
-livenessepilogue(Liveness *lv)
-{
-	BasicBlock *bb, *pred;
-	Bvec *ambig, *livein, *liveout, *uevar, *varkill, *args, *locals, *avarinit, *any, *all;
-	Node *n;
-	Prog *p, *next;
-	int32 i, j, numlive, startmsg, nmsg, nvars, pos;
-	vlong xoffset;
-	char **msg;
-	Fmt fmt;
-
-	nvars = arraylength(lv->vars);
-	livein = bvalloc(nvars);
-	liveout = bvalloc(nvars);
-	uevar = bvalloc(nvars);
-	varkill = bvalloc(nvars);
-	avarinit = bvalloc(nvars);
-	any = bvalloc(nvars);
-	all = bvalloc(nvars);
-	ambig = bvalloc(localswords() * BitsPerPointer);
-	msg = nil;
-	nmsg = 0;
-	startmsg = 0;
-
-	for(i = 0; i < arraylength(lv->cfg); i++) {
-		bb = *(BasicBlock**)arrayget(lv->cfg, i);
-		
-		// Compute avarinitany and avarinitall for entry to block.
-		// This duplicates information known during livenesssolve
-		// but avoids storing two more vectors for each block.
-		bvresetall(any);
-		bvresetall(all);
-		for(j = 0; j < arraylength(bb->pred); j++) {
-			pred = *(BasicBlock**)arrayget(bb->pred, j);
-			if(j == 0) {
-				bvcopy(any, lv->avarinitany[pred->rpo]);
-				bvcopy(all, lv->avarinitall[pred->rpo]);
-			} else {
-				bvor(any, any, lv->avarinitany[pred->rpo]);
-				bvand(all, all, lv->avarinitall[pred->rpo]);
-			}
-		}
-
-		// Walk forward through the basic block instructions and
-		// allocate liveness maps for those instructions that need them.
-		// Seed the maps with information about the addrtaken variables.
-		for(p = bb->first;; p = p->link) {
-			progeffects(p, lv->vars, uevar, varkill, avarinit);
-			bvandnot(any, any, varkill);
-			bvandnot(all, all, varkill);
-			bvor(any, any, avarinit);
-			bvor(all, all, avarinit);
-
-			if(issafepoint(p)) {
-				// Annotate ambiguously live variables so that they can
-				// be zeroed at function entry.
-				// livein and liveout are dead here and used as temporaries.
-				// For now, only enabled when using GOEXPERIMENT=precisestack
-				// during make.bash / all.bash.
-				if(precisestack_enabled) {
-					bvresetall(livein);
-					bvandnot(liveout, any, all);
-					if(!bvisempty(liveout)) {
-						for(pos = 0; pos < liveout->n; pos++) {
-							if(!bvget(liveout, pos))
-								continue;
-							bvset(all, pos); // silence future warnings in this block
-							n = *(Node**)arrayget(lv->vars, pos);
-							if(!n->needzero) {
-								n->needzero = 1;
-								if(debuglive >= 1)
-									warnl(p->lineno, "%N: %lN is ambiguously live", curfn->nname, n);
-								// Record in 'ambiguous' bitmap.
-								xoffset = n->xoffset + stkptrsize;
-								twobitwalktype1(n->type, &xoffset, ambig);
-							}
-						}
-					}
-				}
-	
-				// Allocate a bit vector for each class and facet of
-				// value we are tracking.
-	
-				// Live stuff first.
-				args = bvalloc(argswords() * BitsPerPointer);
-				arrayadd(lv->argslivepointers, &args);
-				locals = bvalloc(localswords() * BitsPerPointer);
-				arrayadd(lv->livepointers, &locals);
-
-				if(debuglive >= 3) {
-					print("%P\n", p);
-					printvars("avarinitany", any, lv->vars);
-				}
-
-				// Record any values with an "address taken" reaching
-				// this code position as live. Must do now instead of below
-				// because the any/all calculation requires walking forward
-				// over the block (as this loop does), while the liveout
-				// requires walking backward (as the next loop does).
-				twobitlivepointermap(lv, any, lv->vars, args, locals);
-			}
-			
-			if(p == bb->last)
-				break;
-		}
-		bb->lastbitmapindex = arraylength(lv->livepointers) - 1;
-	}
-	
-	for(i = 0; i < arraylength(lv->cfg); i++) {
-		bb = *(BasicBlock**)arrayget(lv->cfg, i);
-		
-		if(debuglive >= 1 && strcmp(curfn->nname->sym->name, "init") != 0 && curfn->nname->sym->name[0] != '.') {
-			nmsg = arraylength(lv->livepointers);
-			startmsg = nmsg;
-			msg = xmalloc(nmsg*sizeof msg[0]);
-			for(j=0; j<nmsg; j++)
-				msg[j] = nil;
-		}
-
-		// walk backward, emit pcdata and populate the maps
-		pos = bb->lastbitmapindex;
-		if(pos < 0) {
-			// the first block we encounter should have the ATEXT so
-			// at no point should pos ever be less than zero.
-			fatal("livenessepilogue");
-		}
-
-		bvcopy(livein, lv->liveout[bb->rpo]);
-		for(p = bb->last; p != nil; p = next) {
-			next = p->opt; // splicebefore modifies p->opt
-			// Propagate liveness information
-			progeffects(p, lv->vars, uevar, varkill, avarinit);
-			bvcopy(liveout, livein);
-			bvandnot(livein, liveout, varkill);
-			bvor(livein, livein, uevar);
-			if(debuglive >= 3 && issafepoint(p)){
-				print("%P\n", p);
-				printvars("uevar", uevar, lv->vars);
-				printvars("varkill", varkill, lv->vars);
-				printvars("livein", livein, lv->vars);
-				printvars("liveout", liveout, lv->vars);
-			}
-			if(issafepoint(p)) {
-				// Found an interesting instruction, record the
-				// corresponding liveness information.  
-				
-				// Useful sanity check: on entry to the function,
-				// the only things that can possibly be live are the
-				// input parameters.
-				if(p->as == ATEXT) {
-					for(j = 0; j < liveout->n; j++) {
-						if(!bvget(liveout, j))
-							continue;
-						n = *(Node**)arrayget(lv->vars, j);
-						if(n->class != PPARAM)
-							yyerrorl(p->lineno, "internal error: %N %lN recorded as live on entry", curfn->nname, n);
-					}
-				}
-
-				// Record live pointers.
-				args = *(Bvec**)arrayget(lv->argslivepointers, pos);
-				locals = *(Bvec**)arrayget(lv->livepointers, pos);
-				twobitlivepointermap(lv, liveout, lv->vars, args, locals);
-				
-				// Ambiguously live variables are zeroed immediately after
-				// function entry. Mark them live for all the non-entry bitmaps
-				// so that GODEBUG=gcdead=1 mode does not poison them.
-				if(p->as == ACALL)
-					bvor(locals, locals, ambig);
-
-				// Show live pointer bitmaps.
-				// We're interpreting the args and locals bitmap instead of liveout so that we
-				// include the bits added by the avarinit logic in the
-				// previous loop.
-				if(msg != nil) {
-					fmtstrinit(&fmt);
-					fmtprint(&fmt, "%L: live at ", p->lineno);
-					if(p->as == ACALL && p->to.node)
-						fmtprint(&fmt, "call to %s:", p->to.node->sym->name);
-					else if(p->as == ACALL)
-						fmtprint(&fmt, "indirect call:");
-					else
-						fmtprint(&fmt, "entry to %s:", p->from.node->sym->name);
-					numlive = 0;
-					for(j = 0; j < arraylength(lv->vars); j++) {
-						n = *(Node**)arrayget(lv->vars, j);
-						if(islive(n, args, locals)) {
-							fmtprint(&fmt, " %N", n);
-							numlive++;
-						}
-					}
-					fmtprint(&fmt, "\n");
-					if(numlive == 0) // squelch message
-						free(fmtstrflush(&fmt));
-					else
-						msg[--startmsg] = fmtstrflush(&fmt);
-				}
-
-				// Only CALL instructions need a PCDATA annotation.
-				// The TEXT instruction annotation is implicit.
-				if(p->as == ACALL) {
-					if(isdeferreturn(p)) {
-						// runtime.deferreturn modifies its return address to return
-						// back to the CALL, not to the subsequent instruction.
-						// Because the return comes back one instruction early,
-						// the PCDATA must begin one instruction early too.
-						// The instruction before a call to deferreturn is always a
-						// no-op, to keep PC-specific data unambiguous.
-						splicebefore(lv, bb, newpcdataprog(p->opt, pos), p->opt);
-					} else {
-						splicebefore(lv, bb, newpcdataprog(p, pos), p);
-					}
-				}
-
-				pos--;
-			}
-		}
-		if(msg != nil) {
-			for(j=startmsg; j<nmsg; j++) 
-				if(msg[j] != nil)
-					print("%s", msg[j]);
-			free(msg);
-			msg = nil;
-			nmsg = 0;
-			startmsg = 0;
-		}
-	}
-
-	free(livein);
-	free(liveout);
-	free(uevar);
-	free(varkill);
-	free(avarinit);
-	free(any);
-	free(all);
-	free(ambig);
-	
-	flusherrors();
-}
-
-// FNV-1 hash function constants.
-#define H0 2166136261UL
-#define Hp 16777619UL
-/*c2go
-enum
-{
-	H0 = 2166136261,
-	Hp = 16777619,
-};
-*/
-
-static uint32
-hashbitmap(uint32 h, Bvec *bv)
-{
-	uchar *p, *ep;
-	
-	p = (uchar*)bv->b;
-	ep = p + 4*((bv->n+31)/32);
-	while(p < ep)
-		h = (h*Hp) ^ *p++;
-	return h;
-}
-
-// Compact liveness information by coalescing identical per-call-site bitmaps.
-// The merging only happens for a single function, not across the entire binary.
-//
-// There are actually two lists of bitmaps, one list for the local variables and one
-// list for the function arguments. Both lists are indexed by the same PCDATA
-// index, so the corresponding pairs must be considered together when
-// merging duplicates. The argument bitmaps change much less often during
-// function execution than the local variable bitmaps, so it is possible that
-// we could introduce a separate PCDATA index for arguments vs locals and
-// then compact the set of argument bitmaps separately from the set of
-// local variable bitmaps. As of 2014-04-02, doing this to the godoc binary
-// is actually a net loss: we save about 50k of argument bitmaps but the new
-// PCDATA tables cost about 100k. So for now we keep using a single index for
-// both bitmap lists.
-static void
-livenesscompact(Liveness *lv)
-{
-	int *table, *remap, i, j, n, tablesize, uniq;
-	uint32 h;
-	Bvec *local, *arg, *jlocal, *jarg;
-	Prog *p;
-
-	// Linear probing hash table of bitmaps seen so far.
-	// The hash table has 4n entries to keep the linear
-	// scan short. An entry of -1 indicates an empty slot.
-	n = arraylength(lv->livepointers);
-	tablesize = 4*n;
-	table = xmalloc(tablesize*sizeof table[0]);
-	memset(table, 0xff, tablesize*sizeof table[0]);
-	
-	// remap[i] = the new index of the old bit vector #i.
-	remap = xmalloc(n*sizeof remap[0]);
-	memset(remap, 0xff, n*sizeof remap[0]);
-	uniq = 0; // unique tables found so far
-
-	// Consider bit vectors in turn.
-	// If new, assign next number using uniq,
-	// 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.
-	for(i=0; i<n; i++) {
-		local = *(Bvec**)arrayget(lv->livepointers, i);
-		arg = *(Bvec**)arrayget(lv->argslivepointers, i);
-		h = hashbitmap(hashbitmap(H0, local), arg) % tablesize;
-
-		for(;;) {
-			j = table[h];
-			if(j < 0)
-				break;
-			jlocal = *(Bvec**)arrayget(lv->livepointers, j);
-			jarg = *(Bvec**)arrayget(lv->argslivepointers, j);
-			if(bvcmp(local, jlocal) == 0 && bvcmp(arg, jarg) == 0) {
-				free(local);
-				free(arg);
-				remap[i] = j;
-				goto Next;
-			}
-			if(++h == tablesize)
-				h = 0;
-		}
-		table[h] = uniq;
-		remap[i] = uniq;
-		*(Bvec**)arrayget(lv->livepointers, uniq) = local;
-		*(Bvec**)arrayget(lv->argslivepointers, uniq) = arg;
-		uniq++;
-	Next:;
-	}
-
-	// We've already reordered lv->livepointers[0:uniq]
-	// and lv->argslivepointers[0:uniq] and freed the bitmaps
-	// we don't need anymore. Clear the pointers later in the
-	// 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++) {
-		*(Bvec**)arrayget(lv->livepointers, j) = nil;
-		*(Bvec**)arrayget(lv->argslivepointers, j) = nil;
-	}
-	
-	// Rewrite PCDATA instructions to use new numbering.
-	for(p=lv->ptxt; p != P; p=p->link) {
-		if(p->as == APCDATA && p->from.offset == PCDATA_StackMapIndex) {
-			i = p->to.offset;
-			if(i >= 0)
-				p->to.offset = remap[i];
-		}
-	}
-
-	free(table);
-	free(remap);
-}
-
-static int
-printbitset(int printed, char *name, Array *vars, Bvec *bits)
-{
-	int i, started;
-	Node *n;
-
-	started = 0;	
-	for(i=0; i<arraylength(vars); i++) {
-		if(!bvget(bits, i))
-			continue;
-		if(!started) {
-			if(!printed)
-				print("\t");
-			else
-				print(" ");
-			started = 1;
-			printed = 1;
-			print("%s=", name);
-		} else {
-			print(",");
-		}
-		n = *(Node**)arrayget(vars, i);
-		print("%s", n->sym->name);
-	}
-	return printed;
-}
-
-// Prints the computed liveness information and inputs, for debugging.
-// This format synthesizes the information used during the multiple passes
-// into a single presentation.
-static void
-livenessprintdebug(Liveness *lv)
-{
-	int i, j, pcdata, printed;
-	BasicBlock *bb;
-	Prog *p;
-	Bvec *uevar, *varkill, *avarinit, *args, *locals;
-	Node *n;
-
-	print("liveness: %s\n", curfn->nname->sym->name);
-
-	uevar = bvalloc(arraylength(lv->vars));
-	varkill = bvalloc(arraylength(lv->vars));
-	avarinit = bvalloc(arraylength(lv->vars));
-
-	pcdata = 0;
-	for(i = 0; i < arraylength(lv->cfg); i++) {
-		if(i > 0)
-			print("\n");
-		bb = *(BasicBlock**)arrayget(lv->cfg, i);
-
-		// bb#0 pred=1,2 succ=3,4
-		print("bb#%d pred=", i);
-		for(j = 0; j < arraylength(bb->pred); j++) {
-			if(j > 0)
-				print(",");
-			print("%d", (*(BasicBlock**)arrayget(bb->pred, j))->rpo);
-		}
-		print(" succ=");
-		for(j = 0; j < arraylength(bb->succ); j++) {
-			if(j > 0)
-				print(",");
-			print("%d", (*(BasicBlock**)arrayget(bb->succ, j))->rpo);
-		}
-		print("\n");
-		
-		// initial settings
-		printed = 0;
-		printed = printbitset(printed, "uevar", lv->vars, lv->uevar[bb->rpo]);
-		printed = printbitset(printed, "livein", lv->vars, lv->livein[bb->rpo]);
-		if(printed)
-			print("\n");
-		
-		// program listing, with individual effects listed
-		for(p = bb->first;; p = p->link) {
-			print("%P\n", p);
-			if(p->as == APCDATA && p->from.offset == PCDATA_StackMapIndex)
-				pcdata = p->to.offset;
-			progeffects(p, lv->vars, uevar, varkill, avarinit);
-			printed = 0;
-			printed = printbitset(printed, "uevar", lv->vars, uevar);
-			printed = printbitset(printed, "varkill", lv->vars, varkill);
-			printed = printbitset(printed, "avarinit", lv->vars, avarinit);
-			if(printed)
-				print("\n");
-			if(issafepoint(p)) {
-				args = *(Bvec**)arrayget(lv->argslivepointers, pcdata);
-				locals = *(Bvec**)arrayget(lv->livepointers, pcdata);
-				print("\tlive=");
-				printed = 0;
-				for(j = 0; j < arraylength(lv->vars); j++) {
-					n = *(Node**)arrayget(lv->vars, j);
-					if(islive(n, args, locals)) {
-						if(printed++)
-							print(",");
-						print("%N", n);
-					}
-				}
-				print("\n");
-			}
-			if(p == bb->last)
-				break;
-		}
-		
-		// bb bitsets
-		print("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]);
-		if(printed)
-			print("\n");
-	}
-	print("\n");
-
-	free(uevar);
-	free(varkill);
-	free(avarinit);
-}
-
-// Dumps an array of bitmaps to a symbol as a sequence of uint32 values.  The
-// first word dumped is the total number of bitmaps.  The second word is the
-// 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.
-static void
-twobitwritesymbol(Array *arr, Sym *sym)
-{
-	Bvec *bv;
-	int off, i, j, len;
-	uint32 word;
-
-	len = arraylength(arr);
-	off = 0;
-	off += 4; // number of bitmaps, to fill in later
-	bv = *(Bvec**)arrayget(arr, 0);
-	off = duint32(sym, off, bv->n); // number of bits in each bitmap
-	for(i = 0; i < len; i++) {
-		// bitmap words
-		bv = *(Bvec**)arrayget(arr, i);
-		if(bv == nil)
-			break;
-		for(j = 0; j < bv->n; j += 32) {
-			word = bv->b[j/32];
-			// Runtime reads the bitmaps as byte arrays. Oblige.
-			off = duint8(sym, off, word);
-			off = duint8(sym, off, word>>8);
-			off = duint8(sym, off, word>>16);
-			off = duint8(sym, off, word>>24);
-		}
-	}
-	duint32(sym, 0, i); // number of bitmaps
-	ggloblsym(sym, off, RODATA);
-}
-
-static void
-printprog(Prog *p)
-{
-	while(p != nil) {
-		print("%P\n", p);
-		p = p->link;
-	}
-}
-
-// Entry pointer for liveness analysis.  Constructs a complete CFG, solves for
-// the liveness of pointer variables in the function, and emits a runtime data
-// structure read by the garbage collector.
-void
-liveness(Node *fn, Prog *firstp, Sym *argssym, Sym *livesym)
-{
-	Array *cfg, *vars;
-	Liveness *lv;
-	int debugdelta;
-	NodeList *l;
-
-	// Change name to dump debugging information only for a specific function.
-	debugdelta = 0;
-	if(strcmp(curfn->nname->sym->name, "!") == 0)
-		debugdelta = 2;
-	
-	debuglive += debugdelta;
-	if(debuglive >= 3) {
-		print("liveness: %s\n", curfn->nname->sym->name);
-		printprog(firstp);
-	}
-	checkptxt(fn, firstp);
-
-	// Construct the global liveness state.
-	cfg = newcfg(firstp);
-	if(debuglive >= 3)
-		printcfg(cfg);
-	vars = getvariables(fn);
-	lv = newliveness(fn, firstp, cfg, vars);
-
-	// Run the dataflow framework.
-	livenessprologue(lv);
-	if(debuglive >= 3)
-		livenessprintcfg(lv);
-	livenesssolve(lv);
-	if(debuglive >= 3)
-		livenessprintcfg(lv);
-	livenessepilogue(lv);
-	if(debuglive >= 3)
-		livenessprintcfg(lv);
-	livenesscompact(lv);
-
-	if(debuglive >= 2)
-		livenessprintdebug(lv);
-
-	// Emit the live pointer map data structures
-	twobitwritesymbol(lv->livepointers, livesym);
-	twobitwritesymbol(lv->argslivepointers, argssym);
-
-	// Free everything.
-	for(l=fn->dcl; l != nil; l = l->next)
-		if(l->n != N)
-			l->n->opt = nil;
-	freeliveness(lv);
-	arrayfree(vars);
-	freecfg(cfg);
-	
-	debuglive -= debugdelta;
-}
diff --git a/src/cmd/gc/popt.c b/src/cmd/gc/popt.c
deleted file mode 100644
index 993bb24..0000000
--- a/src/cmd/gc/popt.c
+++ /dev/null
@@ -1,1005 +0,0 @@
-// 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 at 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 at 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.
-
-// "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.
-
-#include	<u.h>
-#include	<libc.h>
-#include	"gg.h"
-#include	"opt.h"
-
-// p is a call instruction. Does the call fail to return?
-int
-noreturn(Prog *p)
-{
-	Sym *s;
-	int i;
-	static Sym*	symlist[10];
-
-	if(symlist[0] == S) {
-		symlist[0] = pkglookup("panicindex", runtimepkg);
-		symlist[1] = pkglookup("panicslice", runtimepkg);
-		symlist[2] = pkglookup("throwinit", runtimepkg);
-		symlist[3] = pkglookup("gopanic", runtimepkg);
-		symlist[4] = pkglookup("panicwrap", runtimepkg);
-		symlist[5] = pkglookup("throwreturn", runtimepkg);
-		symlist[6] = pkglookup("selectgo", runtimepkg);
-		symlist[7] = pkglookup("block", runtimepkg);
-	}
-
-	if(p->to.node == nil)
-		return 0;
-	s = p->to.node->sym;
-	if(s == S)
-		return 0;
-	for(i=0; symlist[i]!=S; i++)
-		if(s == symlist[i])
-			return 1;
-	return 0;
-}
-
-// JMP chasing and removal.
-//
-// The code generator depends on being able to write out jump
-// instructions that it can jump to now but fill in later.
-// the linker will resolve them nicely, but they make the code
-// longer and more difficult to follow during debugging.
-// Remove them.
-
-/* what instruction does a JMP to p eventually land on? */
-static Prog*
-chasejmp(Prog *p, int *jmploop)
-{
-	int n;
-
-	n = 0;
-	while(p != P && p->as == AJMP && p->to.type == D_BRANCH) {
-		if(++n > 10) {
-			*jmploop = 1;
-			break;
-		}
-		p = p->to.u.branch;
-	}
-	return p;
-}
-
-/*
- * reuse reg pointer for mark/sweep state.
- * leave reg==nil at end because alive==nil.
- */
-#define alive ((void*)0)
-#define dead ((void*)1)
-/*c2go
-extern void *alive;
-extern void *dead;
-*/
-
-/* mark all code reachable from firstp as alive */
-static void
-mark(Prog *firstp)
-{
-	Prog *p;
-	
-	for(p=firstp; p; p=p->link) {
-		if(p->opt != dead)
-			break;
-		p->opt = alive;
-		if(p->as != ACALL && p->to.type == D_BRANCH && p->to.u.branch)
-			mark(p->to.u.branch);
-		if(p->as == AJMP || p->as == ARET || p->as == AUNDEF)
-			break;
-	}
-}
-
-void
-fixjmp(Prog *firstp)
-{
-	int jmploop;
-	Prog *p, *last;
-	
-	if(debug['R'] && debug['v'])
-		print("\nfixjmp\n");
-
-	// pass 1: resolve jump to jump, mark all code as dead.
-	jmploop = 0;
-	for(p=firstp; p; p=p->link) {
-		if(debug['R'] && debug['v'])
-			print("%P\n", p);
-		if(p->as != ACALL && p->to.type == D_BRANCH && p->to.u.branch && p->to.u.branch->as == AJMP) {
-			p->to.u.branch = chasejmp(p->to.u.branch, &jmploop);
-			if(debug['R'] && debug['v'])
-				print("->%P\n", p);
-		}
-		p->opt = dead;
-	}
-	if(debug['R'] && debug['v'])
-		print("\n");
-
-	// pass 2: mark all reachable code alive
-	mark(firstp);
-	
-	// pass 3: delete dead code (mostly JMPs).
-	last = nil;
-	for(p=firstp; p; p=p->link) {
-		if(p->opt == dead) {
-			if(p->link == P && p->as == ARET && last && last->as != ARET) {
-				// This is the final ARET, and the code so far doesn't have one.
-				// Let it stay. The register allocator assumes that all live code in
-				// the function can be traversed by starting at all the RET instructions
-				// and following predecessor links. If we remove the final RET,
-				// this assumption will not hold in the case of an infinite loop
-				// at the end of a function.
-				// Keep the RET but mark it dead for the liveness analysis.
-				p->mode = 1;
-			} else {
-				if(debug['R'] && debug['v'])
-					print("del %P\n", p);
-				continue;
-			}
-		}
-		if(last)
-			last->link = p;
-		last = p;
-	}
-	last->link = P;
-	
-	// pass 4: elide JMP to next instruction.
-	// only safe if there are no jumps to JMPs anymore.
-	if(!jmploop) {
-		last = nil;
-		for(p=firstp; p; p=p->link) {
-			if(p->as == AJMP && p->to.type == D_BRANCH && p->to.u.branch == p->link) {
-				if(debug['R'] && debug['v'])
-					print("del %P\n", p);
-				continue;
-			}
-			if(last)
-				last->link = p;
-			last = p;
-		}
-		last->link = P;
-	}
-	
-	if(debug['R'] && debug['v']) {
-		print("\n");
-		for(p=firstp; p; p=p->link)
-			print("%P\n", p);
-		print("\n");
-	}
-}
-
-#undef alive
-#undef dead
-
-// Control flow analysis. The Flow structures hold predecessor and successor
-// information as well as basic loop analysis.
-//
-//	graph = flowstart(firstp, sizeof(Flow));
-//	... use flow graph ...
-//	flowend(graph); // free graph
-//
-// Typical uses of the flow graph are to iterate over all the flow-relevant instructions:
-//
-//	for(f = graph->start; f != nil; f = f->link)
-//
-// or, given an instruction f, to iterate over all the predecessors, which is
-// f->p1 and this list:
-//
-//	for(f2 = f->p2; f2 != nil; f2 = f2->p2link)
-//	
-// Often the Flow struct is embedded as the first field inside a larger struct S.
-// In that case casts are needed to convert Flow* to S* in many places but the
-// idea is the same. Pass sizeof(S) instead of sizeof(Flow) to flowstart.
-
-Graph*
-flowstart(Prog *firstp, int size)
-{
-	int nf;
-	Flow *f, *f1, *start, *last;
-	Graph *graph;
-	Prog *p;
-	ProgInfo info;
-
-	// Count and mark instructions to annotate.
-	nf = 0;
-	for(p = firstp; p != P; p = p->link) {
-		p->opt = nil; // should be already, but just in case
-		proginfo(&info, p);
-		if(info.flags & Skip)
-			continue;
-		p->opt = (void*)1;
-		nf++;
-	}
-	
-	if(nf == 0)
-		return nil;
-
-	if(nf >= 20000) {
-		// fatal("%S is too big (%d instructions)", curfn->nname->sym, nf);
-		return nil;
-	}
-
-	// Allocate annotations and assign to instructions.
-	graph = calloc(sizeof *graph + size*nf, 1);
-	if(graph == nil)
-		fatal("out of memory");
-	start = (Flow*)(graph+1);
-	last = nil;
-	f = start;
-	for(p = firstp; p != P; p = p->link) {
-		if(p->opt == nil)
-			continue;
-		p->opt = f;
-		f->prog = p;
-		if(last)
-			last->link = f;
-		last = f;
-		
-		f = (Flow*)((uchar*)f + size);
-	}
-
-	// Fill in pred/succ information.
-	for(f = start; f != nil; f = f->link) {
-		p = f->prog;
-		proginfo(&info, p);
-		if(!(info.flags & Break)) {
-			f1 = f->link;
-			f->s1 = f1;
-			f1->p1 = f;
-		}
-		if(p->to.type == D_BRANCH) {
-			if(p->to.u.branch == P)
-				fatal("pnil %P", p);
-			f1 = p->to.u.branch->opt;
-			if(f1 == nil)
-				fatal("fnil %P / %P", p, p->to.u.branch);
-			if(f1 == f) {
-				//fatal("self loop %P", p);
-				continue;
-			}
-			f->s2 = f1;
-			f->p2link = f1->p2;
-			f1->p2 = f;
-		}
-	}
-	
-	graph->start = start;
-	graph->num = nf;
-	return graph;
-}
-
-void
-flowend(Graph *graph)
-{
-	Flow *f;
-	
-	for(f = graph->start; f != nil; f = f->link)
-		f->prog->opt = nil;
-	free(graph);
-}
-
-/*
- * find looping structure
- *
- * 1) find reverse postordering
- * 2) find approximate dominators,
- *	the actual dominators if the flow graph is reducible
- *	otherwise, dominators plus some other non-dominators.
- *	See Matthew S. Hecht and Jeffrey D. Ullman,
- *	"Analysis of a Simple Algorithm for Global Data Flow Problems",
- *	Conf.  Record of ACM Symp. on Principles of Prog. Langs, Boston, Massachusetts,
- *	Oct. 1-3, 1973, pp.  207-217.
- * 3) find all nodes with a predecessor dominated by the current node.
- *	such a node is a loop head.
- *	recursively, all preds with a greater rpo number are in the loop
- */
-static int32
-postorder(Flow *r, Flow **rpo2r, int32 n)
-{
-	Flow *r1;
-
-	r->rpo = 1;
-	r1 = r->s1;
-	if(r1 && !r1->rpo)
-		n = postorder(r1, rpo2r, n);
-	r1 = r->s2;
-	if(r1 && !r1->rpo)
-		n = postorder(r1, rpo2r, n);
-	rpo2r[n] = r;
-	n++;
-	return n;
-}
-
-static int32
-rpolca(int32 *idom, int32 rpo1, int32 rpo2)
-{
-	int32 t;
-
-	if(rpo1 == -1)
-		return rpo2;
-	while(rpo1 != rpo2){
-		if(rpo1 > rpo2){
-			t = rpo2;
-			rpo2 = rpo1;
-			rpo1 = t;
-		}
-		while(rpo1 < rpo2){
-			t = idom[rpo2];
-			if(t >= rpo2)
-				fatal("bad idom");
-			rpo2 = t;
-		}
-	}
-	return rpo1;
-}
-
-static int
-doms(int32 *idom, int32 r, int32 s)
-{
-	while(s > r)
-		s = idom[s];
-	return s == r;
-}
-
-static int
-loophead(int32 *idom, Flow *r)
-{
-	int32 src;
-
-	src = r->rpo;
-	if(r->p1 != nil && doms(idom, src, r->p1->rpo))
-		return 1;
-	for(r = r->p2; r != nil; r = r->p2link)
-		if(doms(idom, src, r->rpo))
-			return 1;
-	return 0;
-}
-
-static void
-loopmark(Flow **rpo2r, int32 head, Flow *r)
-{
-	if(r->rpo < head || r->active == head)
-		return;
-	r->active = head;
-	r->loop += LOOP;
-	if(r->p1 != nil)
-		loopmark(rpo2r, head, r->p1);
-	for(r = r->p2; r != nil; r = r->p2link)
-		loopmark(rpo2r, head, r);
-}
-
-void
-flowrpo(Graph *g)
-{
-	Flow *r1;
-	int32 i, d, me, nr, *idom;
-	Flow **rpo2r;
-
-	free(g->rpo);
-	g->rpo = calloc(g->num*sizeof g->rpo[0], 1);
-	idom = calloc(g->num*sizeof idom[0], 1);
-	if(g->rpo == nil || idom == nil)
-		fatal("out of memory");
-
-	for(r1 = g->start; r1 != nil; r1 = r1->link)
-		r1->active = 0;
-
-	rpo2r = g->rpo;
-	d = postorder(g->start, rpo2r, 0);
-	nr = g->num;
-	if(d > nr)
-		fatal("too many reg nodes %d %d", d, nr);
-	nr = d;
-	for(i = 0; i < nr / 2; i++) {
-		r1 = rpo2r[i];
-		rpo2r[i] = rpo2r[nr - 1 - i];
-		rpo2r[nr - 1 - i] = r1;
-	}
-	for(i = 0; i < nr; i++)
-		rpo2r[i]->rpo = i;
-
-	idom[0] = 0;
-	for(i = 0; i < nr; i++) {
-		r1 = rpo2r[i];
-		me = r1->rpo;
-		d = -1;
-		// rpo2r[r->rpo] == r protects against considering dead code,
-		// which has r->rpo == 0.
-		if(r1->p1 != nil && rpo2r[r1->p1->rpo] == r1->p1 && r1->p1->rpo < me)
-			d = r1->p1->rpo;
-		for(r1 = r1->p2; r1 != nil; r1 = r1->p2link)
-			if(rpo2r[r1->rpo] == r1 && r1->rpo < me)
-				d = rpolca(idom, d, r1->rpo);
-		idom[i] = d;
-	}
-
-	for(i = 0; i < nr; i++) {
-		r1 = rpo2r[i];
-		r1->loop++;
-		if(r1->p2 != nil && loophead(idom, r1))
-			loopmark(rpo2r, i, r1);
-	}
-	free(idom);
-
-	for(r1 = g->start; r1 != nil; r1 = r1->link)
-		r1->active = 0;
-}
-
-Flow*
-uniqp(Flow *r)
-{
-	Flow *r1;
-
-	r1 = r->p1;
-	if(r1 == nil) {
-		r1 = r->p2;
-		if(r1 == nil || r1->p2link != nil)
-			return nil;
-	} else
-		if(r->p2 != nil)
-			return nil;
-	return r1;
-}
-
-Flow*
-uniqs(Flow *r)
-{
-	Flow *r1;
-
-	r1 = r->s1;
-	if(r1 == nil) {
-		r1 = r->s2;
-		if(r1 == nil)
-			return nil;
-	} else
-		if(r->s2 != nil)
-			return nil;
-	return r1;
-}
-
-// The compilers assume they can generate temporary variables
-// as needed to preserve the right semantics or simplify code
-// generation and the back end will still generate good code.
-// This results in a large number of ephemeral temporary variables.
-// Merge temps with non-overlapping lifetimes and equal types using the
-// greedy algorithm in Poletto and Sarkar, "Linear Scan Register Allocation",
-// ACM TOPLAS 1999.
-
-typedef struct TempVar TempVar;
-typedef struct TempFlow TempFlow;
-
-struct TempVar
-{
-	Node *node;
-	TempFlow *def; // definition of temp var
-	TempFlow *use; // use list, chained through TempFlow.uselink
-	TempVar *freelink; // next free temp in Type.opt list
-	TempVar *merge; // merge var with this one
-	vlong start; // smallest Prog.pc in live range
-	vlong end; // largest Prog.pc in live range
-	uchar addr; // address taken - no accurate end
-	uchar removed; // removed from program
-};
-
-struct TempFlow
-{
-	Flow	f;
-	TempFlow *uselink;
-};
-
-static int
-startcmp(const void *va, const void *vb)
-{
-	TempVar *a, *b;
-	
-	a = *(TempVar**)va;
-	b = *(TempVar**)vb;
-
-	if(a->start < b->start)
-		return -1;
-	if(a->start > b->start)
-		return +1;
-	return 0;
-}
-
-// Is n available for merging?
-static int
-canmerge(Node *n)
-{
-	return n->class == PAUTO && strncmp(n->sym->name, "autotmp", 7) == 0;
-}
-
-static void mergewalk(TempVar*, TempFlow*, uint32);
-static void varkillwalk(TempVar*, TempFlow*, uint32);
-
-void
-mergetemp(Prog *firstp)
-{
-	int i, j, nvar, ninuse, nfree, nkill;
-	TempVar *var, *v, *v1, **bystart, **inuse;
-	TempFlow *r;
-	NodeList *l, **lp;
-	Node *n;
-	Prog *p, *p1;
-	Type *t;
-	ProgInfo info, info1;
-	int32 gen;
-	Graph *g;
-
-	enum { Debug = 0 };
-
-	g = flowstart(firstp, sizeof(TempFlow));
-	if(g == nil)
-		return;
-	
-	// Build list of all mergeable variables.
-	nvar = 0;
-	for(l = curfn->dcl; l != nil; l = l->next)
-		if(canmerge(l->n))
-			nvar++;
-	
-	var = calloc(nvar*sizeof var[0], 1);
-	nvar = 0;
-	for(l = curfn->dcl; l != nil; l = l->next) {
-		n = l->n;
-		if(canmerge(n)) {
-			v = &var[nvar++];
-			n->opt = v;
-			v->node = n;
-		}
-	}
-	
-	// Build list of uses.
-	// 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!).
-	for(r = (TempFlow*)g->start; r != nil; r = (TempFlow*)r->f.link) {
-		p = r->f.prog;
-		proginfo(&info, p);
-
-		if(p->from.node != N && p->from.node->opt && p->to.node != N && p->to.node->opt)
-			fatal("double node %P", p);
-		if((n = p->from.node) != N && (v = n->opt) != nil ||
-		   (n = p->to.node) != N && (v = n->opt) != nil) {
-		   	if(v->def == nil)
-		   		v->def = r;
-			r->uselink = v->use;
-			v->use = r;
-			if(n == p->from.node && (info.flags & LeftAddr))
-				v->addr = 1;
-		}
-	}
-	
-	if(Debug > 1)
-		dumpit("before", g->start, 0);
-	
-	nkill = 0;
-
-	// Special case.
-	for(v = var; v < var+nvar; v++) {
-		if(v->addr)
-			continue;
-		// Used in only one instruction, which had better be a write.
-		if((r = v->use) != nil && r->uselink == nil) {
-			p = r->f.prog;
-			proginfo(&info, p);
-			if(p->to.node == v->node && (info.flags & RightWrite) && !(info.flags & RightRead)) {
-				p->as = ANOP;
-				p->to = zprog.to;
-				v->removed = 1;
-				if(Debug)
-					print("drop write-only %S\n", v->node->sym);
-			} else
-				fatal("temp used and not set: %P", p);
-			nkill++;
-			continue;
-		}
-		
-		// Written in one instruction, read in the next, otherwise unused,
-		// no jumps to the next instruction. Happens mainly in 386 compiler.
-		if((r = v->use) != nil && r->f.link == &r->uselink->f && r->uselink->uselink == nil && uniqp(r->f.link) == &r->f) {
-			p = r->f.prog;
-			proginfo(&info, p);
-			p1 = r->f.link->prog;
-			proginfo(&info1, p1);
-			enum {
-				SizeAny = SizeB | SizeW | SizeL | SizeQ | SizeF | SizeD,
-			};
-			if(p->from.node == v->node && p1->to.node == v->node && (info.flags & Move) &&
-			   !((info.flags|info1.flags) & (LeftAddr|RightAddr)) &&
-			   (info.flags & SizeAny) == (info1.flags & SizeAny)) {
-				p1->from = p->from;
-				excise(&r->f);
-				v->removed = 1;
-				if(Debug)
-					print("drop immediate-use %S\n", v->node->sym);
-			}
-			nkill++;
-			continue;
-		}			   
-	}
-
-	// Traverse live range of each variable to set start, end.
-	// Each flood uses a new value of gen so that we don't have
-	// to clear all the r->f.active words after each variable.
-	gen = 0;
-	for(v = var; v < var+nvar; v++) {
-		gen++;
-		for(r = v->use; r != nil; r = r->uselink)
-			mergewalk(v, r, gen);
-		if(v->addr) {
-			gen++;
-			for(r = v->use; r != nil; r = r->uselink)
-				varkillwalk(v, r, gen);
-		}
-	}
-
-	// Sort variables by start.
-	bystart = malloc(nvar*sizeof bystart[0]);
-	for(i=0; i<nvar; i++)
-		bystart[i] = &var[i];
-	qsort(bystart, nvar, sizeof bystart[0], startcmp);
-
-	// List of in-use variables, sorted by end, so that the ones that
-	// will last the longest are the earliest ones in the array.
-	// The tail inuse[nfree:] holds no-longer-used variables.
-	// In theory we should use a sorted tree so that insertions are
-	// guaranteed O(log n) and then the loop is guaranteed O(n log n).
-	// In practice, it doesn't really matter.
-	inuse = malloc(nvar*sizeof inuse[0]);
-	ninuse = 0;
-	nfree = nvar;
-	for(i=0; i<nvar; i++) {
-		v = bystart[i];
-		if(v->removed)
-			continue;
-
-		// Expire no longer in use.
-		while(ninuse > 0 && inuse[ninuse-1]->end < v->start) {
-			v1 = inuse[--ninuse];
-			inuse[--nfree] = v1;
-		}
-
-		// Find old temp to reuse if possible.
-		t = v->node->type;
-		for(j=nfree; j<nvar; j++) {
-			v1 = inuse[j];
-			// Require the types to match but also require the addrtaken bits to match.
-			// If a variable's address is taken, that disables registerization for the individual
-			// words of the variable (for example, the base,len,cap of a slice).
-			// We don't want to merge a non-addressed var with an addressed one and
-			// inhibit registerization of the former.
-			if(eqtype(t, v1->node->type) && v->node->addrtaken == v1->node->addrtaken) {
-				inuse[j] = inuse[nfree++];
-				if(v1->merge)
-					v->merge = v1->merge;
-				else
-					v->merge = v1;
-				nkill++;
-				break;
-			}
-		}
-
-		// Sort v into inuse.
-		j = ninuse++;
-		while(j > 0 && inuse[j-1]->end < v->end) {
-			inuse[j] = inuse[j-1];
-			j--;
-		}
-		inuse[j] = v;
-	}
-
-	if(Debug) {
-		print("%S [%d - %d]\n", curfn->nname->sym, nvar, nkill);
-		for(v=var; v<var+nvar; v++) {
-			print("var %#N %T %lld-%lld", v->node, v->node->type, v->start, v->end);
-			if(v->addr)
-				print(" addr=1");
-			if(v->removed)
-				print(" dead=1");
-			if(v->merge)
-				print(" merge %#N", v->merge->node);
-			if(v->start == v->end)
-				print(" %P", v->def->f.prog);
-			print("\n");
-		}
-	
-		if(Debug > 1)
-			dumpit("after", g->start, 0);
-	}
-
-	// Update node references to use merged temporaries.
-	for(r = (TempFlow*)g->start; r != nil; r = (TempFlow*)r->f.link) {
-		p = r->f.prog;
-		if((n = p->from.node) != N && (v = n->opt) != nil && v->merge != nil)
-			p->from.node = v->merge->node;
-		if((n = p->to.node) != N && (v = n->opt) != nil && v->merge != nil)
-			p->to.node = v->merge->node;
-	}
-
-	// Delete merged nodes from declaration list.
-	for(lp = &curfn->dcl; (l = *lp); ) {
-		curfn->dcl->end = l;
-		n = l->n;
-		v = n->opt;
-		if(v && (v->merge || v->removed)) {
-			*lp = l->next;
-			continue;
-		}
-		lp = &l->next;
-	}
-
-	// Clear aux structures.
-	for(v=var; v<var+nvar; v++)
-		v->node->opt = nil;
-	free(var);
-	free(bystart);
-	free(inuse);
-	flowend(g);
-}
-
-static void
-mergewalk(TempVar *v, TempFlow *r0, uint32 gen)
-{
-	Prog *p;
-	TempFlow *r1, *r, *r2;
-	
-	for(r1 = r0; r1 != nil; r1 = (TempFlow*)r1->f.p1) {
-		if(r1->f.active == gen)
-			break;
-		r1->f.active = gen;
-		p = r1->f.prog;
-		if(v->end < p->pc)
-			v->end = p->pc;
-		if(r1 == v->def) {
-			v->start = p->pc;
-			break;
-		}
-	}
-	
-	for(r = r0; r != r1; r = (TempFlow*)r->f.p1)
-		for(r2 = (TempFlow*)r->f.p2; r2 != nil; r2 = (TempFlow*)r2->f.p2link)
-			mergewalk(v, r2, gen);
-}
-
-static void
-varkillwalk(TempVar *v, TempFlow *r0, uint32 gen)
-{
-	Prog *p;
-	TempFlow *r1, *r;
-	
-	for(r1 = r0; r1 != nil; r1 = (TempFlow*)r1->f.s1) {
-		if(r1->f.active == gen)
-			break;
-		r1->f.active = gen;
-		p = r1->f.prog;
-		if(v->end < p->pc)
-			v->end = p->pc;
-		if(v->start > p->pc)
-			v->start = p->pc;
-		if(p->as == ARET || (p->as == AVARKILL && p->to.node == v->node))
-			break;
-	}
-	
-	for(r = r0; r != r1; r = (TempFlow*)r->f.s1)
-		varkillwalk(v, (TempFlow*)r->f.s2, gen);
-}
-
-// Eliminate redundant nil pointer checks.
-//
-// The code generation pass emits a CHECKNIL for every possibly nil pointer.
-// This pass removes a CHECKNIL if every predecessor path has already
-// checked this value for nil.
-//
-// Simple backwards flood from check to definition.
-// Run prog loop backward from end of program to beginning to avoid quadratic
-// behavior removing a run of checks.
-//
-// 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.
-	
-typedef struct NilVar NilVar;
-typedef struct NilFlow NilFlow;
-
-struct NilFlow {
-	Flow f;
-	int kill;
-};
-
-static void nilwalkback(NilFlow *rcheck);
-static void nilwalkfwd(NilFlow *rcheck);
-
-void
-nilopt(Prog *firstp)
-{
-	NilFlow *r;
-	Prog *p;
-	Graph *g;
-	int ncheck, nkill;
-
-	g = flowstart(firstp, sizeof(NilFlow));
-	if(g == nil)
-		return;
-
-	if(debug_checknil > 1 /* || strcmp(curfn->nname->sym->name, "f1") == 0 */)
-		dumpit("nilopt", g->start, 0);
-
-	ncheck = 0;
-	nkill = 0;
-	for(r = (NilFlow*)g->start; r != nil; r = (NilFlow*)r->f.link) {
-		p = r->f.prog;
-		if(p->as != ACHECKNIL || !regtyp(&p->from))
-			continue;
-		ncheck++;
-		if(stackaddr(&p->from)) {
-			if(debug_checknil && p->lineno > 1)
-				warnl(p->lineno, "removed nil check of SP address");
-			r->kill = 1;
-			continue;
-		}
-		nilwalkfwd(r);
-		if(r->kill) {
-			if(debug_checknil && p->lineno > 1)
-				warnl(p->lineno, "removed nil check before indirect");
-			continue;
-		}
-		nilwalkback(r);
-		if(r->kill) {
-			if(debug_checknil && p->lineno > 1)
-				warnl(p->lineno, "removed repeated nil check");
-			continue;
-		}
-	}
-	
-	for(r = (NilFlow*)g->start; r != nil; r = (NilFlow*)r->f.link) {
-		if(r->kill) {
-			nkill++;
-			excise(&r->f);
-		}
-	}
-
-	flowend(g);
-	
-	if(debug_checknil > 1)
-		print("%S: removed %d of %d nil checks\n", curfn->nname->sym, nkill, ncheck);
-}
-
-static void
-nilwalkback(NilFlow *rcheck)
-{
-	Prog *p;
-	ProgInfo info;
-	NilFlow *r;
-	
-	for(r = rcheck; r != nil; r = (NilFlow*)uniqp(&r->f)) {
-		p = r->f.prog;
-		proginfo(&info, p);
-		if((info.flags & RightWrite) && sameaddr(&p->to, &rcheck->f.prog->from)) {
-			// Found initialization of value we're checking for nil.
-			// without first finding the check, so this one is unchecked.
-			return;
-		}
-		if(r != rcheck && p->as == ACHECKNIL && sameaddr(&p->from, &rcheck->f.prog->from)) {
-			rcheck->kill = 1;
-			return;
-		}
-	}
-
-	// Here is a more complex version that scans backward across branches.
-	// It assumes rcheck->kill = 1 has been set on entry, and its job is to find a reason
-	// to keep the check (setting rcheck->kill = 0).
-	// It doesn't handle copying of aggregates as well as I would like,
-	// nor variables with their address taken,
-	// and it's too subtle to turn on this late in Go 1.2. Perhaps for Go 1.3.
-	/*
-	for(r1 = r0; r1 != nil; r1 = (NilFlow*)r1->f.p1) {
-		if(r1->f.active == gen)
-			break;
-		r1->f.active = gen;
-		p = r1->f.prog;
-		
-		// If same check, stop this loop but still check
-		// alternate predecessors up to this point.
-		if(r1 != rcheck && p->as == ACHECKNIL && sameaddr(&p->from, &rcheck->f.prog->from))
-			break;
-
-		proginfo(&info, p);
-		if((info.flags & RightWrite) && sameaddr(&p->to, &rcheck->f.prog->from)) {
-			// Found initialization of value we're checking for nil.
-			// without first finding the check, so this one is unchecked.
-			rcheck->kill = 0;
-			return;
-		}
-		
-		if(r1->f.p1 == nil && r1->f.p2 == nil) {
-			print("lost pred for %P\n", rcheck->f.prog);
-			for(r1=r0; r1!=nil; r1=(NilFlow*)r1->f.p1) {
-				proginfo(&info, r1->f.prog);
-				print("\t%P %d %d %D %D\n", r1->f.prog, info.flags&RightWrite, sameaddr(&r1->f.prog->to, &rcheck->f.prog->from), &r1->f.prog->to, &rcheck->f.prog->from);
-			}
-			fatal("lost pred trail");
-		}
-	}
-
-	for(r = r0; r != r1; r = (NilFlow*)r->f.p1)
-		for(r2 = (NilFlow*)r->f.p2; r2 != nil; r2 = (NilFlow*)r2->f.p2link)
-			nilwalkback(rcheck, r2, gen);
-	*/
-}
-
-static void
-nilwalkfwd(NilFlow *rcheck)
-{
-	NilFlow *r, *last;
-	Prog *p;
-	ProgInfo info;
-	
-	// 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
-	// that implicit check. Only consider this basic block to
-	// avoid problems like:
-	//	_ = *x // should panic
-	//	for {} // no writes but infinite loop may be considered visible
-	last = nil;
-	for(r = (NilFlow*)uniqs(&rcheck->f); r != nil; r = (NilFlow*)uniqs(&r->f)) {
-		p = r->f.prog;
-		proginfo(&info, p);
-		
-		if((info.flags & LeftRead) && smallindir(&p->from, &rcheck->f.prog->from)) {
-			rcheck->kill = 1;
-			return;
-		}
-		if((info.flags & (RightRead|RightWrite)) && smallindir(&p->to, &rcheck->f.prog->from)) {
-			rcheck->kill = 1;
-			return;
-		}
-		
-		// Stop if another nil check happens.
-		if(p->as == ACHECKNIL)
-			return;
-		// Stop if value is lost.
-		if((info.flags & RightWrite) && sameaddr(&p->to, &rcheck->f.prog->from))
-			return;
-		// Stop if memory write.
-		if((info.flags & RightWrite) && !regtyp(&p->to))
-			return;
-		// Stop if we jump backward.
-		// This test is valid because all the NilFlow* are pointers into
-		// a single contiguous array. We will need to add an explicit
-		// numbering when the code is converted to Go.
-		if(last != nil && r <= last)
-			return;
-		last = r;
-	}
-}
diff --git a/src/cmd/gc/popt.h b/src/cmd/gc/popt.h
deleted file mode 100644
index 8d5dfff..0000000
--- a/src/cmd/gc/popt.h
+++ /dev/null
@@ -1,46 +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.
-
-typedef struct Flow Flow;
-typedef struct Graph Graph;
-
-struct Flow {
-	Prog*	prog;   	// actual instruction
-	Flow*	p1;     	// predecessors of this instruction: p1,
-	Flow*	p2;     	// and then p2 linked though p2link.
-	Flow*	p2link;
-	Flow*	s1;     	// successors of this instruction (at most two: s1 and s2).
-	Flow*	s2;
-	Flow*	link;   	// next instruction in function code
-	
-	int32	active;	// usable by client
-
-	int32	rpo;		// reverse post ordering
-	uint16	loop;		// x5 for every loop
-	uchar	refset;		// diagnostic generated
-};
-
-struct Graph
-{
-	Flow*	start;
-	int	num;
-	
-	// After calling flowrpo, rpo lists the flow nodes in reverse postorder,
-	// and each non-dead Flow node f has g->rpo[f->rpo] == f.
-	Flow**	rpo;
-};
-
-void	fixjmp(Prog*);
-Graph*	flowstart(Prog*, int);
-void	flowrpo(Graph*);
-void	flowend(Graph*);
-void	mergetemp(Prog*);
-void	nilopt(Prog*);
-int	noreturn(Prog*);
-int	regtyp(Addr*);
-int	sameaddr(Addr*, Addr*);
-int	smallindir(Addr*, Addr*);
-int	stackaddr(Addr*);
-Flow*	uniqp(Flow*);
-Flow*	uniqs(Flow*);
diff --git a/src/cmd/gc/racewalk.c b/src/cmd/gc/racewalk.c
deleted file mode 100644
index c9e27fe..0000000
--- a/src/cmd/gc/racewalk.c
+++ /dev/null
@@ -1,664 +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.
-
-// The racewalk pass modifies the code tree for the function as follows:
-//
-// 1. It inserts a call to racefuncenter at the beginning of each function.
-// 2. It inserts a call to racefuncexit at the end of each function.
-// 3. It inserts a call to raceread before each memory read.
-// 4. It inserts a call to racewrite before each memory write.
-//
-// The rewriting is not yet complete. Certain nodes are not rewritten
-// but should be.
-
-#include <u.h>
-#include <libc.h>
-#include "go.h"
-
-// TODO(dvyukov): do not instrument initialization as writes:
-// a := make([]int, 10)
-
-static void racewalklist(NodeList *l, NodeList **init);
-static void racewalknode(Node **np, NodeList **init, int wr, int skip);
-static int callinstr(Node **n, NodeList **init, int wr, int skip);
-static Node* uintptraddr(Node *n);
-static void makeaddable(Node *n);
-static Node* basenod(Node *n);
-static void foreach(Node *n, void(*f)(Node*, void*), void *c);
-static void hascallspred(Node *n, void *c);
-static void appendinit(Node **np, NodeList *init);
-static Node* detachexpr(Node *n, NodeList **init);
-
-// Do not instrument the following packages at all,
-// at best instrumentation would cause infinite recursion.
-static const char *omit_pkgs[] = {"runtime", "runtime/race"};
-// Only insert racefuncenter/racefuncexit into the following packages.
-// Memory accesses in the packages are either uninteresting or will cause false positives.
-static const char *noinst_pkgs[] = {"sync", "sync/atomic"};
-
-static int
-ispkgin(const char **pkgs, int n)
-{
-	int i;
-
-	if(myimportpath) {
-		for(i=0; i<n; i++) {
-			if(strcmp(myimportpath, pkgs[i]) == 0)
-				return 1;
-		}
-	}
-	return 0;
-}
-
-static int
-isforkfunc(Node *fn)
-{
-	// Special case for syscall.forkAndExecInChild.
-	// In the child, this function must not acquire any locks, because
-	// they might have been locked at the time of the fork.  This means
-	// no rescheduling, no malloc calls, and no new stack segments.
-	// Race instrumentation does all of the above.
-	return myimportpath != nil && strcmp(myimportpath, "syscall") == 0 &&
-		strcmp(fn->nname->sym->name, "forkAndExecInChild") == 0;
-}
-
-void
-racewalk(Node *fn)
-{
-	Node *nd;
-	Node *nodpc;
-	char s[1024];
-
-	if(ispkgin(omit_pkgs, nelem(omit_pkgs)) || isforkfunc(fn))
-		return;
-
-	if(!ispkgin(noinst_pkgs, nelem(noinst_pkgs))) {
-		racewalklist(fn->nbody, nil);
-		// nothing interesting for race detector in fn->enter
-		racewalklist(fn->exit, nil);
-	}
-
-	// nodpc is the PC of the caller as extracted by
-	// getcallerpc. We use -widthptr(FP) for x86.
-	// BUG: this will not work on arm.
-	nodpc = nod(OXXX, nil, nil);
-	*nodpc = *nodfp;
-	nodpc->type = types[TUINTPTR];
-	nodpc->xoffset = -widthptr;
-	nd = mkcall("racefuncenter", T, nil, nodpc);
-	fn->enter = concat(list1(nd), fn->enter);
-	nd = mkcall("racefuncexit", T, nil);
-	fn->exit = list(fn->exit, nd);
-
-	if(debug['W']) {
-		snprint(s, sizeof(s), "after racewalk %S", fn->nname->sym);
-		dumplist(s, fn->nbody);
-		snprint(s, sizeof(s), "enter %S", fn->nname->sym);
-		dumplist(s, fn->enter);
-		snprint(s, sizeof(s), "exit %S", fn->nname->sym);
-		dumplist(s, fn->exit);
-	}
-}
-
-static void
-racewalklist(NodeList *l, NodeList **init)
-{
-	NodeList *instr;
-
-	for(; l; l = l->next) {
-		instr = nil;
-		racewalknode(&l->n, &instr, 0, 0);
-		if(init == nil)
-			l->n->ninit = concat(l->n->ninit, instr);
-		else
-			*init = concat(*init, instr);
-	}
-}
-
-// walkexpr and walkstmt combined
-// walks the tree and adds calls to the
-// instrumentation code to top-level (statement) nodes' init
-static void
-racewalknode(Node **np, NodeList **init, int wr, int skip)
-{
-	Node *n, *n1;
-	NodeList *l;
-	NodeList *fini;
-
-	n = *np;
-
-	if(n == N)
-		return;
-
-	if(debug['w'] > 1)
-		dump("racewalk-before", n);
-	setlineno(n);
-	if(init == nil)
-		fatal("racewalk: bad init list");
-	if(init == &n->ninit) {
-		// If init == &n->ninit and n->ninit is non-nil,
-		// racewalknode might append it to itself.
-		// nil it out and handle it separately before putting it back.
-		l = n->ninit;
-		n->ninit = nil;
-		racewalklist(l, nil);
-		racewalknode(&n, &l, wr, skip);  // recurse with nil n->ninit
-		appendinit(&n, l);
-		*np = n;
-		return;
-	}
-
-	racewalklist(n->ninit, nil);
-
-	switch(n->op) {
-	default:
-		fatal("racewalk: unknown node type %O", n->op);
-
-	case OASOP:
-	case OAS:
-	case OAS2:
-	case OAS2RECV:
-	case OAS2FUNC:
-	case OAS2MAPR:
-		racewalknode(&n->left, init, 1, 0);
-		racewalknode(&n->right, init, 0, 0);
-		goto ret;
-
-	case OCFUNC:
-	case OVARKILL:
-		// can't matter
-		goto ret;
-
-	case OBLOCK:
-		if(n->list == nil)
-			goto ret;
-
-		switch(n->list->n->op) {
-		case OCALLFUNC:
-		case OCALLMETH:
-		case OCALLINTER:
-			// Blocks are used for multiple return function calls.
-			// 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.
-			racewalknode(&n->list->n, &n->list->n->ninit, 0, 0);
-			fini = nil;
-			racewalklist(n->list->next, &fini);
-			n->list = concat(n->list, fini);
-			break;
-
-		default:
-			// Ordinary block, for loop initialization or inlined bodies.
-			racewalklist(n->list, nil);
-			break;
-		}
-		goto ret;
-
-	case ODEFER:
-		racewalknode(&n->left, init, 0, 0);
-		goto ret;
-
-	case OPROC:
-		racewalknode(&n->left, init, 0, 0);
-		goto ret;
-
-	case OCALLINTER:
-		racewalknode(&n->left, init, 0, 0);
-		goto ret;
-
-	case OCALLFUNC:
-		// Instrument dst argument of runtime.writebarrier* calls
-		// as we do not instrument runtime code.
-		if(n->left->sym != S && n->left->sym->pkg == runtimepkg && strncmp(n->left->sym->name, "writebarrier", 12) == 0) {
-			// Find the dst argument.
-			// The list can be reordered, so it's not necessary just the first or the second element.
-			for(l = n->list; l; l = l->next) {
-				if(strcmp(n->left->sym->name, "writebarrierfat") == 0) {
-					if(l->n->left->xoffset == widthptr)
-						break;
-				} else {
-					if(l->n->left->xoffset == 0)
-						break;
-				}
-			}
-			if(l == nil)
-				fatal("racewalk: writebarrier no arg");
-			if(l->n->right->op != OADDR)
-				fatal("racewalk: writebarrier bad arg");
-			callinstr(&l->n->right->left, init, 1, 0);
-		}
-		racewalknode(&n->left, init, 0, 0);
-		goto ret;
-
-	case ONOT:
-	case OMINUS:
-	case OPLUS:
-	case OREAL:
-	case OIMAG:
-	case OCOM:
-		racewalknode(&n->left, init, wr, 0);
-		goto ret;
-
-	case ODOTINTER:
-		racewalknode(&n->left, init, 0, 0);
-		goto ret;
-
-	case ODOT:
-		racewalknode(&n->left, init, 0, 1);
-		callinstr(&n, init, wr, skip);
-		goto ret;
-
-	case ODOTPTR: // dst = (*x).f with implicit *; otherwise it's ODOT+OIND
-		racewalknode(&n->left, init, 0, 0);
-		callinstr(&n, init, wr, skip);
-		goto ret;
-
-	case OIND: // *p
-		racewalknode(&n->left, init, 0, 0);
-		callinstr(&n, init, wr, skip);
-		goto ret;
-
-	case OSPTR:
-	case OLEN:
-	case OCAP:
-		racewalknode(&n->left, init, 0, 0);
-		if(istype(n->left->type, TMAP)) {
-			n1 = nod(OCONVNOP, n->left, N);
-			n1->type = ptrto(types[TUINT8]);
-			n1 = nod(OIND, n1, N);
-			typecheck(&n1, Erv);
-			callinstr(&n1, init, 0, skip);
-		}
-		goto ret;
-
-	case OLSH:
-	case ORSH:
-	case OLROT:
-	case OAND:
-	case OANDNOT:
-	case OOR:
-	case OXOR:
-	case OSUB:
-	case OMUL:
-	case OHMUL:
-	case OEQ:
-	case ONE:
-	case OLT:
-	case OLE:
-	case OGE:
-	case OGT:
-	case OADD:
-	case OCOMPLEX:
-		racewalknode(&n->left, init, wr, 0);
-		racewalknode(&n->right, init, wr, 0);
-		goto ret;
-
-	case OANDAND:
-	case OOROR:
-		racewalknode(&n->left, init, wr, 0);
-		// walk has ensured the node has moved to a location where
-		// side effects are safe.
-		// n->right may not be executed,
-		// so instrumentation goes to n->right->ninit, not init.
-		racewalknode(&n->right, &n->right->ninit, wr, 0);
-		goto ret;
-
-	case ONAME:
-		callinstr(&n, init, wr, skip);
-		goto ret;
-
-	case OCONV:
-		racewalknode(&n->left, init, wr, 0);
-		goto ret;
-
-	case OCONVNOP:
-		racewalknode(&n->left, init, wr, 0);
-		goto ret;
-
-	case ODIV:
-	case OMOD:
-		racewalknode(&n->left, init, wr, 0);
-		racewalknode(&n->right, init, wr, 0);
-		goto ret;
-
-	case OINDEX:
-		if(!isfixedarray(n->left->type))
-			racewalknode(&n->left, init, 0, 0);
-		else if(!islvalue(n->left)) {
-			// index of unaddressable array, like Map[k][i].
-			racewalknode(&n->left, init, wr, 0);
-			racewalknode(&n->right, init, 0, 0);
-			goto ret;
-		}
-		racewalknode(&n->right, init, 0, 0);
-		if(n->left->type->etype != TSTRING)
-			callinstr(&n, init, wr, skip);
-		goto ret;
-
-	case OSLICE:
-	case OSLICEARR:
-	case OSLICE3:
-	case OSLICE3ARR:
-		// Seems to only lead to double instrumentation.
-		//racewalknode(&n->left, init, 0, 0);
-		goto ret;
-
-	case OADDR:
-		racewalknode(&n->left, init, 0, 1);
-		goto ret;
-
-	case OEFACE:
-		racewalknode(&n->left, init, 0, 0);
-		racewalknode(&n->right, init, 0, 0);
-		goto ret;
-
-	case OITAB:
-		racewalknode(&n->left, init, 0, 0);
-		goto ret;
-
-	// should not appear in AST by now
-	case OSEND:
-	case ORECV:
-	case OCLOSE:
-	case ONEW:
-	case OXCASE:
-	case OXFALL:
-	case OCASE:
-	case OPANIC:
-	case ORECOVER:
-	case OCONVIFACE:
-	case OCMPIFACE:
-	case OMAKECHAN:
-	case OMAKEMAP:
-	case OMAKESLICE:
-	case OCALL:
-	case OCOPY:
-	case OAPPEND:
-	case ORUNESTR:
-	case OARRAYBYTESTR:
-	case OARRAYRUNESTR:
-	case OSTRARRAYBYTE:
-	case OSTRARRAYRUNE:
-	case OINDEXMAP:  // lowered to call
-	case OCMPSTR:
-	case OADDSTR:
-	case ODOTTYPE:
-	case ODOTTYPE2:
-	case OAS2DOTTYPE:
-	case OCALLPART: // lowered to PTRLIT
-	case OCLOSURE:  // lowered to PTRLIT
-	case ORANGE:    // lowered to ordinary for loop
-	case OARRAYLIT: // lowered to assignments
-	case OMAPLIT:
-	case OSTRUCTLIT:
-		yyerror("racewalk: %O must be lowered by now", n->op);
-		goto ret;
-
-	// impossible nodes: only appear in backend.
-	case ORROTC:
-	case OEXTEND:
-		yyerror("racewalk: %O cannot exist now", n->op);
-		goto ret;
-
-	// just do generic traversal
-	case OFOR:
-	case OIF:
-	case OCALLMETH:
-	case ORETURN:
-	case ORETJMP:
-	case OSWITCH:
-	case OSELECT:
-	case OEMPTY:
-	case OBREAK:
-	case OCONTINUE:
-	case OFALL:
-	case OGOTO:
-	case OLABEL:
-		goto ret;
-
-	// does not require instrumentation
-	case OPRINT:     // don't bother instrumenting it
-	case OPRINTN:    // don't bother instrumenting it
-	case OCHECKNIL: // always followed by a read.
-	case OPARAM:     // it appears only in fn->exit to copy heap params back
-	case OCLOSUREVAR:// immutable pointer to captured variable
-	case ODOTMETH:   // either part of CALLMETH or CALLPART (lowered to PTRLIT)
-	case OINDREG:    // at this stage, only n(SP) nodes from nodarg
-	case ODCL:       // declarations (without value) cannot be races
-	case ODCLCONST:
-	case ODCLTYPE:
-	case OTYPE:
-	case ONONAME:
-	case OLITERAL:
-	case OSLICESTR:  // always preceded by bounds checking, avoid double instrumentation.
-	case OTYPESW:    // ignored by code generation, do not instrument.
-		goto ret;
-	}
-
-ret:
-	if(n->op != OBLOCK)  // OBLOCK is handled above in a special way.
-		racewalklist(n->list, init);
-	if(n->ntest != N)
-		racewalknode(&n->ntest, &n->ntest->ninit, 0, 0);
-	if(n->nincr != N)
-		racewalknode(&n->nincr, &n->nincr->ninit, 0, 0);
-	racewalklist(n->nbody, nil);
-	racewalklist(n->nelse, nil);
-	racewalklist(n->rlist, nil);
-	*np = n;
-}
-
-static int
-isartificial(Node *n)
-{
-	// compiler-emitted artificial things that we do not want to instrument,
-	// cant' possibly participate in a data race.
-	if(n->op == ONAME && n->sym != S && n->sym->name != nil) {
-		if(strcmp(n->sym->name, "_") == 0)
-			return 1;
-		// autotmp's are always local
-		if(strncmp(n->sym->name, "autotmp_", sizeof("autotmp_")-1) == 0)
-			return 1;
-		// statictmp's are read-only
-		if(strncmp(n->sym->name, "statictmp_", sizeof("statictmp_")-1) == 0)
-			return 1;
-		// go.itab is accessed only by the compiler and runtime (assume safe)
-		if(n->sym->pkg && n->sym->pkg->name && strcmp(n->sym->pkg->name, "go.itab") == 0)
-			return 1;
-	}
-	return 0;
-}
-
-static int
-callinstr(Node **np, NodeList **init, int wr, int skip)
-{
-	Node *f, *b, *n;
-	Type *t;
-	int class, hascalls;
-
-	n = *np;
-	//print("callinstr for %+N [ %O ] etype=%E class=%d\n",
-	//	  n, n->op, n->type ? n->type->etype : -1, n->class);
-
-	if(skip || n->type == T || n->type->etype >= TIDEAL)
-		return 0;
-	t = n->type;
-	if(isartificial(n))
-		return 0;
-
-	b = basenod(n);
-	// it skips e.g. stores to ... parameter array
-	if(isartificial(b))
-		return 0;
-	class = b->class;
-	// BUG: we _may_ want to instrument PAUTO sometimes
-	// e.g. if we've got a local variable/method receiver
-	// that has got a pointer inside. Whether it points to
-	// the heap or not is impossible to know at compile time
-	if((class&PHEAP) || class == PPARAMREF || class == PEXTERN
-		|| b->op == OINDEX || b->op == ODOTPTR || b->op == OIND || b->op == OXDOT) {
-		hascalls = 0;
-		foreach(n, hascallspred, &hascalls);
-		if(hascalls) {
-			n = detachexpr(n, init);
-			*np = n;
-		}
-		n = treecopy(n);
-		makeaddable(n);
-		if(t->etype == TSTRUCT || isfixedarray(t)) {
-			f = mkcall(wr ? "racewriterange" : "racereadrange", T, init, uintptraddr(n),
-					nodintconst(t->width));
-		} else
-			f = mkcall(wr ? "racewrite" : "raceread", T, init, uintptraddr(n));
-		*init = list(*init, f);
-		return 1;
-	}
-	return 0;
-}
-
-// makeaddable returns a node whose memory location is the
-// same as n, but which is addressable in the Go language
-// sense.
-// This is different from functions like cheapexpr that may make
-// a copy of their argument.
-static void
-makeaddable(Node *n)
-{
-	// The arguments to uintptraddr technically have an address but
-	// may not be addressable in the Go sense: for example, in the case
-	// of T(v).Field where T is a struct type and v is
-	// an addressable value.
-	switch(n->op) {
-	case OINDEX:
-		if(isfixedarray(n->left->type))
-			makeaddable(n->left);
-		break;
-	case ODOT:
-	case OXDOT:
-		// Turn T(v).Field into v.Field
-		if(n->left->op == OCONVNOP)
-			n->left = n->left->left;
-		makeaddable(n->left);
-		break;
-	case ODOTPTR:
-	default:
-		// nothing to do
-		break;
-	}
-}
-
-static Node*
-uintptraddr(Node *n)
-{
-	Node *r;
-
-	r = nod(OADDR, n, N);
-	r->bounded = 1;
-	r = conv(r, types[TUNSAFEPTR]);
-	r = conv(r, types[TUINTPTR]);
-	return r;
-}
-
-// basenod returns the simplest child node of n pointing to the same
-// memory area.
-static Node*
-basenod(Node *n)
-{
-	for(;;) {
-		if(n->op == ODOT || n->op == OXDOT || n->op == OCONVNOP || n->op == OCONV || n->op == OPAREN) {
-			n = n->left;
-			continue;
-		}
-		if(n->op == OINDEX && isfixedarray(n->type)) {
-			n = n->left;
-			continue;
-		}
-		break;
-	}
-	return n;
-}
-
-static Node*
-detachexpr(Node *n, NodeList **init)
-{
-	Node *addr, *as, *ind, *l;
-
-	addr = nod(OADDR, n, N);
-	l = temp(ptrto(n->type));
-	as = nod(OAS, l, addr);
-	typecheck(&as, Etop);
-	walkexpr(&as, init);
-	*init = list(*init, as);
-	ind = nod(OIND, l, N);
-	typecheck(&ind, Erv);
-	walkexpr(&ind, init);
-	return ind;
-}
-
-static void
-foreachnode(Node *n, void(*f)(Node*, void*), void *c)
-{
-	if(n)
-		f(n, c);
-}
-
-static void
-foreachlist(NodeList *l, void(*f)(Node*, void*), void *c)
-{
-	for(; l; l = l->next)
-		foreachnode(l->n, f, c);
-}
-
-static void
-foreach(Node *n, void(*f)(Node*, void*), void *c)
-{
-	foreachlist(n->ninit, f, c);
-	foreachnode(n->left, f, c);
-	foreachnode(n->right, f, c);
-	foreachlist(n->list, f, c);
-	foreachnode(n->ntest, f, c);
-	foreachnode(n->nincr, f, c);
-	foreachlist(n->nbody, f, c);
-	foreachlist(n->nelse, f, c);
-	foreachlist(n->rlist, f, c);
-}
-
-static void
-hascallspred(Node *n, void *c)
-{
-	switch(n->op) {
-	case OCALL:
-	case OCALLFUNC:
-	case OCALLMETH:
-	case OCALLINTER:
-		(*(int*)c)++;
-	}
-}
-
-// appendinit is like addinit in subr.c
-// but appends rather than prepends.
-static void
-appendinit(Node **np, NodeList *init)
-{
-	Node *n;
-
-	if(init == nil)
-		return;
-
-	n = *np;
-	switch(n->op) {
-	case ONAME:
-	case OLITERAL:
-		// There may be multiple refs to this node;
-		// introduce OCONVNOP to hold init list.
-		n = nod(OCONVNOP, n, N);
-		n->type = n->left->type;
-		n->typecheck = 1;
-		*np = n;
-		break;
-	}
-	n->ninit = concat(n->ninit, init);
-	n->ullman = UINF;
-}
-
diff --git a/src/cmd/gc/range.c b/src/cmd/gc/range.c
deleted file mode 100644
index 4ed4528..0000000
--- a/src/cmd/gc/range.c
+++ /dev/null
@@ -1,296 +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.
-
-/*
- * range
- */
-
-#include <u.h>
-#include <libc.h>
-#include "go.h"
-
-void
-typecheckrange(Node *n)
-{
-	char *why;
-	Type *t, *t1, *t2;
-	Node *v1, *v2;
-	NodeList *ll;
-
-	// delicate little dance.  see typecheckas2
-	for(ll=n->list; ll; ll=ll->next)
-		if(ll->n->defn != n)
-			typecheck(&ll->n, Erv | Easgn);
-
-	typecheck(&n->right, Erv);
-	if((t = n->right->type) == T)
-		goto out;
-	if(isptr[t->etype] && isfixedarray(t->type))
-		t = t->type;
-	n->type = t;
-
-	switch(t->etype) {
-	default:
-		yyerror("cannot range over %lN", n->right);
-		goto out;
-
-	case TARRAY:
-		t1 = types[TINT];
-		t2 = t->type;
-		break;
-
-	case TMAP:
-		t1 = t->down;
-		t2 = t->type;
-		break;
-
-	case TCHAN:
-		if(!(t->chan & Crecv)) {
-			yyerror("invalid operation: range %N (receive from send-only type %T)", n->right, n->right->type);
-			goto out;
-		}
-		t1 = t->type;
-		t2 = nil;
-		if(count(n->list) == 2)
-			goto toomany;
-		break;
-
-	case TSTRING:
-		t1 = types[TINT];
-		t2 = runetype;
-		break;
-	}
-
-	if(count(n->list) > 2) {
-	toomany:
-		yyerror("too many variables in range");
-	}
-
-	v1 = N;
-	if(n->list)
-		v1 = n->list->n;
-	v2 = N;
-	if(n->list && n->list->next)
-		v2 = n->list->next->n;
-
-	// this is not only a optimization but also a requirement in the spec.
-	// "if the second iteration variable is the blank identifier, the range
-	// clause is equivalent to the same clause with only the first variable
-	// present."
-	if(isblank(v2)) {
-		if(v1 != N)
-			n->list = list1(v1);
-		v2 = N;
-	}
-
-	if(v1) {
-		if(v1->defn == n)
-			v1->type = t1;
-		else if(v1->type != T && assignop(t1, v1->type, &why) == 0)
-			yyerror("cannot assign type %T to %lN in range%s", t1, v1, why);
-	}
-	if(v2) {
-		if(v2->defn == n)
-			v2->type = t2;
-		else if(v2->type != T && assignop(t2, v2->type, &why) == 0)
-			yyerror("cannot assign type %T to %lN in range%s", t2, v2, why);
-	}
-
-out:
-	typechecklist(n->nbody, Etop);
-
-	// second half of dance
-	n->typecheck = 1;
-	for(ll=n->list; ll; ll=ll->next)
-		if(ll->n->typecheck == 0)
-			typecheck(&ll->n, Erv | Easgn);
-}
-
-void
-walkrange(Node *n)
-{
-	Node *ohv1, *hv1, *hv2;	// hidden (old) val 1, 2
-	Node *ha, *hit;	// hidden aggregate, iterator
-	Node *hn, *hp;	// hidden len, pointer
-	Node *hb;  // hidden bool
-	Node *a, *v1, *v2;	// not hidden aggregate, val 1, 2
-	Node *fn, *tmp;
-	Node *keyname, *valname;
-	Node *key, *val;
-	NodeList *body, *init;
-	Type *th, *t;
-	int lno;
-
-	t = n->type;
-	init = nil;
-
-	a = n->right;
-	lno = setlineno(a);
-
-	v1 = N;
-	if(n->list)
-		v1 = n->list->n;
-	v2 = N;
-	if(n->list && n->list->next && !isblank(n->list->next->n))
-		v2 = n->list->next->n;
-	// n->list has no meaning anymore, clear it
-	// to avoid erroneous processing by racewalk.
-	n->list = nil;
-	hv2 = N;
-
-	switch(t->etype) {
-	default:
-		fatal("walkrange");
-
-	case TARRAY:
-		// orderstmt arranged for a copy of the array/slice variable if needed.
-		ha = a;
-		hv1 = temp(types[TINT]);
-		hn = temp(types[TINT]);
-		hp = nil;
-
-		init = list(init, nod(OAS, hv1, N));
-		init = list(init, nod(OAS, hn, nod(OLEN, ha, N)));
-		if(v2) {
-			hp = temp(ptrto(n->type->type));
-			tmp = nod(OINDEX, ha, nodintconst(0));
-			tmp->bounded = 1;
-			init = list(init, nod(OAS, hp, nod(OADDR, tmp, N)));
-		}
-
-		n->ntest = nod(OLT, hv1, hn);
-		n->nincr = nod(OAS, hv1, nod(OADD, hv1, nodintconst(1)));
-		if(v1 == N)
-			body = nil;
-		else if(v2 == N)
-			body = list1(nod(OAS, v1, hv1));
-		else {
-			a = nod(OAS2, N, N);
-			a->list = list(list1(v1), v2);
-			a->rlist = list(list1(hv1), nod(OIND, hp, N));
-			body = list1(a);
-			
-			// Advance pointer as part of increment.
-			// We used to advance the pointer before executing the loop body,
-			// but doing so would make the pointer point past the end of the
-			// array during the final iteration, possibly causing another unrelated
-			// piece of memory not to be garbage collected until the loop finished.
-			// Advancing during the increment ensures that the pointer p only points
-			// pass the end of the array during the final "p++; i++; if(i >= len(x)) break;",
-			// after which p is dead, so it cannot confuse the collector.
-			tmp = nod(OADD, hp, nodintconst(t->type->width));
-			tmp->type = hp->type;
-			tmp->typecheck = 1;
-			tmp->right->type = types[tptr];
-			tmp->right->typecheck = 1;
-			a = nod(OAS, hp, tmp);
-			typecheck(&a, Etop);
-			n->nincr->ninit = list1(a);
-		}
-		break;
-
-	case TMAP:
-		// orderstmt allocated the iterator for us.
-		// we only use a once, so no copy needed.
-		ha = a;
-		th = hiter(t);
-		hit = n->alloc;
-		hit->type = th;
-		n->left = N;
-		keyname = newname(th->type->sym);  // depends on layout of iterator struct.  See reflect.c:hiter
-		valname = newname(th->type->down->sym); // ditto
-
-		fn = syslook("mapiterinit", 1);
-		argtype(fn, t->down);
-		argtype(fn, t->type);
-		argtype(fn, th);
-		init = list(init, mkcall1(fn, T, nil, typename(t), ha, nod(OADDR, hit, N)));
-		n->ntest = nod(ONE, nod(ODOT, hit, keyname), nodnil());
-
-		fn = syslook("mapiternext", 1);
-		argtype(fn, th);
-		n->nincr = mkcall1(fn, T, nil, nod(OADDR, hit, N));
-
-		key = nod(ODOT, hit, keyname);
-		key = nod(OIND, key, N);
-		if(v1 == N)
-			body = nil;
-		else if(v2 == N) {
-			body = list1(nod(OAS, v1, key));
-		} else {
-			val = nod(ODOT, hit, valname);
-			val = nod(OIND, val, N);
-			a = nod(OAS2, N, N);
-			a->list = list(list1(v1), v2);
-			a->rlist = list(list1(key), val);
-			body = list1(a);
-		}
-		break;
-
-	case TCHAN:
-		// orderstmt arranged for a copy of the channel variable.
-		ha = a;
-		n->ntest = N;
-		
-		hv1 = temp(t->type);
-		hv1->typecheck = 1;
-		if(haspointers(t->type))
-			init = list(init, nod(OAS, hv1, N));
-		hb = temp(types[TBOOL]);
-
-		n->ntest = nod(ONE, hb, nodbool(0));
-		a = nod(OAS2RECV, N, N);
-		a->typecheck = 1;
-		a->list = list(list1(hv1), hb);
-		a->rlist = list1(nod(ORECV, ha, N));
-		n->ntest->ninit = list1(a);
-		if(v1 == N)
-			body = nil;
-		else
-			body = list1(nod(OAS, v1, hv1));
-		break;
-
-	case TSTRING:
-		// orderstmt arranged for a copy of the string variable.
-		ha = a;
-
-		ohv1 = temp(types[TINT]);
-
-		hv1 = temp(types[TINT]);
-		init = list(init, nod(OAS, hv1, N));
-
-		if(v2 == N)
-			a = nod(OAS, hv1, mkcall("stringiter", types[TINT], nil, ha, hv1));
-		else {
-			hv2 = temp(runetype);
-			a = nod(OAS2, N, N);
-			a->list = list(list1(hv1), hv2);
-			fn = syslook("stringiter2", 0);
-			a->rlist = list1(mkcall1(fn, getoutargx(fn->type), nil, ha, hv1));
-		}
-		n->ntest = nod(ONE, hv1, nodintconst(0));
-		n->ntest->ninit = list(list1(nod(OAS, ohv1, hv1)), a);
-
-		
-		body = nil;
-		if(v1 != N)
-			body = list1(nod(OAS, v1, ohv1));
-		if(v2 != N)
-			body = list(body, nod(OAS, v2, hv2));
-		break;
-	}
-
-	n->op = OFOR;
-	typechecklist(init, Etop);
-	n->ninit = concat(n->ninit, init);
-	typechecklist(n->ntest->ninit, Etop);
-	typecheck(&n->ntest, Erv);
-	typecheck(&n->nincr, Etop);
-	typechecklist(body, Etop);
-	n->nbody = concat(body, n->nbody);
-	walkstmt(&n);
-	
-	lineno = lno;
-}
-
diff --git a/src/cmd/gc/reflect.c b/src/cmd/gc/reflect.c
deleted file mode 100644
index 8788a67..0000000
--- a/src/cmd/gc/reflect.c
+++ /dev/null
@@ -1,1577 +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 <u.h>
-#include <libc.h>
-#include "go.h"
-#include "../ld/textflag.h"
-#include "../../runtime/mgc0.h"
-#include "../../runtime/typekind.h"
-
-/*
- * runtime interface and reflection data structures
- */
-
-static	NodeList*	signatlist;
-static	Sym*	dtypesym(Type*);
-static	Sym*	weaktypesym(Type*);
-static	Sym*	dalgsym(Type*);
-static	int	usegcprog(Type*);
-static	void	gengcprog(Type*, Sym**, Sym**);
-static	void	gengcmask(Type*, uint8[16]);
-
-static int
-sigcmp(Sig *a, Sig *b)
-{
-	int i;
-
-	i = strcmp(a->name, b->name);
-	if(i != 0)
-		return i;
-	if(a->pkg == b->pkg)
-		return 0;
-	if(a->pkg == nil)
-		return -1;
-	if(b->pkg == nil)
-		return +1;
-	return strcmp(a->pkg->path->s, b->pkg->path->s);
-}
-
-static Sig*
-lsort(Sig *l, int(*f)(Sig*, Sig*))
-{
-	Sig *l1, *l2, *le;
-
-	if(l == 0 || l->link == 0)
-		return l;
-
-	l1 = l;
-	l2 = l;
-	for(;;) {
-		l2 = l2->link;
-		if(l2 == 0)
-			break;
-		l2 = l2->link;
-		if(l2 == 0)
-			break;
-		l1 = l1->link;
-	}
-
-	l2 = l1->link;
-	l1->link = 0;
-	l1 = lsort(l, f);
-	l2 = lsort(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 == 0) {
-			while(l2) {
-				le->link = l2;
-				le = l2;
-				l2 = l2->link;
-			}
-			le->link = 0;
-			break;
-		}
-		if(l2 == 0) {
-			while(l1) {
-				le->link = l1;
-				le = l1;
-				l1 = l1->link;
-			}
-			break;
-		}
-		if((*f)(l1, l2) < 0) {
-			le->link = l1;
-			le = l1;
-			l1 = l1->link;
-		} else {
-			le->link = l2;
-			le = l2;
-			l2 = l2->link;
-		}
-	}
-	le->link = 0;
-	return l;
-}
-
-// Builds a type respresenting a Bucket structure for
-// 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!
-enum {
-	BUCKETSIZE = 8,
-	MAXKEYSIZE = 128,
-	MAXVALSIZE = 128,
-};
-
-static Type*
-mapbucket(Type *t)
-{
-	Type *keytype, *valtype;
-	Type *bucket;
-	Type *overflowfield, *keysfield, *valuesfield;
-	int32 offset;
-
-	if(t->bucket != T)
-		return t->bucket;
-
-	keytype = t->down;
-	valtype = t->type;
-	dowidth(keytype);
-	dowidth(valtype);
-	if(keytype->width > MAXKEYSIZE)
-		keytype = ptrto(keytype);
-	if(valtype->width > MAXVALSIZE)
-		valtype = ptrto(valtype);
-
-	bucket = typ(TSTRUCT);
-	bucket->noalg = 1;
-
-	// The first field is: uint8 topbits[BUCKETSIZE].
-	// We don't need to encode it as GC doesn't care about it.
-	offset = BUCKETSIZE * 1;
-
-	keysfield = typ(TFIELD);
-	keysfield->type = typ(TARRAY);
-	keysfield->type->type = keytype;
-	keysfield->type->bound = BUCKETSIZE;
-	keysfield->type->width = BUCKETSIZE * keytype->width;
-	keysfield->width = offset;
-	keysfield->sym = mal(sizeof(Sym));
-	keysfield->sym->name = "keys";
-	offset += BUCKETSIZE * keytype->width;
-
-	valuesfield = typ(TFIELD);
-	valuesfield->type = typ(TARRAY);
-	valuesfield->type->type = valtype;
-	valuesfield->type->bound = BUCKETSIZE;
-	valuesfield->type->width = BUCKETSIZE * valtype->width;
-	valuesfield->width = offset;
-	valuesfield->sym = mal(sizeof(Sym));
-	valuesfield->sym->name = "values";
-	offset += BUCKETSIZE * valtype->width;
-
-	overflowfield = typ(TFIELD);
-	overflowfield->type = ptrto(bucket);
-	overflowfield->width = offset;         // "width" is offset in structure
-	overflowfield->sym = mal(sizeof(Sym)); // not important but needs to be set to give this type a name
-	overflowfield->sym->name = "overflow";
-	offset += widthptr;
-	
-	// Pad to the native integer alignment.
-	// This is usually the same as widthptr; the exception (as usual) is nacl/amd64.
-	if(widthreg > widthptr)
-		offset += widthreg - widthptr;
-
-	// link up fields
-	bucket->type = keysfield;
-	keysfield->down = valuesfield;
-	valuesfield->down = overflowfield;
-	overflowfield->down = T;
-
-	bucket->width = offset;
-	bucket->local = t->local;
-	t->bucket = bucket;
-	bucket->map = t;
-	return bucket;
-}
-
-// Builds a type respresenting a Hmap structure for
-// 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.go!
-static Type*
-hmap(Type *t)
-{
-	Type *h, *bucket;
-	Type *bucketsfield, *oldbucketsfield;
-	int32 offset;
-
-	if(t->hmap != T)
-		return t->hmap;
-
-	bucket = mapbucket(t);
-	h = typ(TSTRUCT);
-	h->noalg = 1;
-
-	offset = widthint; // count
-	offset += 4;       // flags
-	offset += 4;       // hash0
-	offset += 1;       // B
-	offset = (offset + widthptr - 1) / widthptr * widthptr;
-	
-	bucketsfield = typ(TFIELD);
-	bucketsfield->type = ptrto(bucket);
-	bucketsfield->width = offset;
-	bucketsfield->sym = mal(sizeof(Sym));
-	bucketsfield->sym->name = "buckets";
-	offset += widthptr;
-
-	oldbucketsfield = typ(TFIELD);
-	oldbucketsfield->type = ptrto(bucket);
-	oldbucketsfield->width = offset;
-	oldbucketsfield->sym = mal(sizeof(Sym));
-	oldbucketsfield->sym->name = "oldbuckets";
-	offset += widthptr;
-
-	offset += widthptr; // nevacuate (last field in Hmap)
-
-	// link up fields
-	h->type = bucketsfield;
-	bucketsfield->down = oldbucketsfield;
-	oldbucketsfield->down = T;
-
-	h->width = offset;
-	h->local = t->local;
-	t->hmap = h;
-	h->map = t;
-	return h;
-}
-
-Type*
-hiter(Type *t)
-{
-	int32 n, off;
-	Type *field[7];
-	Type *i;
-
-	if(t->hiter != T)
-		return t->hiter;
-
-	// build a struct:
-	// hash_iter {
-	//    key *Key
-	//    val *Value
-	//    t *MapType
-	//    h *Hmap
-	//    buckets *Bucket
-	//    bptr *Bucket
-	//    other [4]uintptr
-	// }
-	// must match ../../runtime/hashmap.c:hash_iter.
-	field[0] = typ(TFIELD);
-	field[0]->type = ptrto(t->down);
-	field[0]->sym = mal(sizeof(Sym));
-	field[0]->sym->name = "key";
-	
-	field[1] = typ(TFIELD);
-	field[1]->type = ptrto(t->type);
-	field[1]->sym = mal(sizeof(Sym));
-	field[1]->sym->name = "val";
-	
-	field[2] = typ(TFIELD);
-	field[2]->type = ptrto(types[TUINT8]); // TODO: is there a Type type?
-	field[2]->sym = mal(sizeof(Sym));
-	field[2]->sym->name = "t";
-	
-	field[3] = typ(TFIELD);
-	field[3]->type = ptrto(hmap(t));
-	field[3]->sym = mal(sizeof(Sym));
-	field[3]->sym->name = "h";
-	
-	field[4] = typ(TFIELD);
-	field[4]->type = ptrto(mapbucket(t));
-	field[4]->sym = mal(sizeof(Sym));
-	field[4]->sym->name = "buckets";
-	
-	field[5] = typ(TFIELD);
-	field[5]->type = ptrto(mapbucket(t));
-	field[5]->sym = mal(sizeof(Sym));
-	field[5]->sym->name = "bptr";
-	
-	// all other non-pointer fields
-	field[6] = typ(TFIELD);
-	field[6]->type = typ(TARRAY);
-	field[6]->type->type = types[TUINTPTR];
-	field[6]->type->bound = 4;
-	field[6]->type->width = 4 * widthptr;
-	field[6]->sym = mal(sizeof(Sym));
-	field[6]->sym->name = "other";
-	
-	// build iterator struct holding the above fields
-	i = typ(TSTRUCT);
-	i->noalg = 1;
-	i->type = field[0];
-	off = 0;
-	for(n = 0; n < 6; n++) {
-		field[n]->down = field[n+1];
-		field[n]->width = off;
-		off += field[n]->type->width;
-	}
-	field[6]->down = T;
-	off += field[6]->type->width;
-	if(off != 10 * widthptr)
-		yyerror("hash_iter size not correct %d %d", off, 10 * widthptr);
-	t->hiter = i;
-	i->map = t;
-	return i;
-}
-
-/*
- * f is method type, with receiver.
- * return function type, receiver as first argument (or not).
- */
-Type*
-methodfunc(Type *f, Type *receiver)
-{
-	NodeList *in, *out;
-	Node *d;
-	Type *t;
-
-	in = nil;
-	if(receiver) {
-		d = nod(ODCLFIELD, N, N);
-		d->type = receiver;
-		in = list(in, d);
-	}
-	for(t=getinargx(f)->type; t; t=t->down) {
-		d = nod(ODCLFIELD, N, N);
-		d->type = t->type;
-		d->isddd = t->isddd;
-		in = list(in, d);
-	}
-
-	out = nil;
-	for(t=getoutargx(f)->type; t; t=t->down) {
-		d = nod(ODCLFIELD, N, N);
-		d->type = t->type;
-		out = list(out, d);
-	}
-
-	t = functype(N, in, out);
-	if(f->nname) {
-		// Link to name of original method function.
-		t->nname = f->nname;
-	}
-	return t;
-}
-
-/*
- * return methods of non-interface type t, sorted by name.
- * generates stub functions as needed.
- */
-static Sig*
-methods(Type *t)
-{
-	Type *f, *mt, *it, *this;
-	Sig *a, *b;
-	Sym *method;
-
-	// method type
-	mt = methtype(t, 0);
-	if(mt == T)
-		return nil;
-	expandmeth(mt);
-
-	// type stored in interface word
-	it = t;
-	if(!isdirectiface(it))
-		it = ptrto(t);
-
-	// make list of methods for t,
-	// generating code if necessary.
-	a = nil;
-	for(f=mt->xmethod; f; f=f->down) {
-		if(f->etype != TFIELD)
-			fatal("methods: not field %T", f);
-		if (f->type->etype != TFUNC || f->type->thistuple == 0)
-			fatal("non-method on %T method %S %T\n", mt, f->sym, f);
-		if (!getthisx(f->type)->type)
-			fatal("receiver with no type on %T method %S %T\n", mt, f->sym, f);
-		if(f->nointerface)
-			continue;
-
-		method = f->sym;
-		if(method == nil)
-			continue;
-
-		// get receiver type for this particular method.
-		// if pointer receiver but non-pointer t and
-		// this is not an embedded pointer inside a struct,
-		// method does not apply.
-		this = getthisx(f->type)->type->type;
-		if(isptr[this->etype] && this->type == t)
-			continue;
-		if(isptr[this->etype] && !isptr[t->etype]
-		&& f->embedded != 2 && !isifacemethod(f->type))
-			continue;
-
-		b = mal(sizeof(*b));
-		b->link = a;
-		a = b;
-
-		a->name = method->name;
-		if(!exportname(method->name)) {
-			if(method->pkg == nil)
-				fatal("methods: missing package");
-			a->pkg = method->pkg;
-		}
-		a->isym = methodsym(method, it, 1);
-		a->tsym = methodsym(method, t, 0);
-		a->type = methodfunc(f->type, t);
-		a->mtype = methodfunc(f->type, nil);
-
-		if(!(a->isym->flags & SymSiggen)) {
-			a->isym->flags |= SymSiggen;
-			if(!eqtype(this, it) || this->width < types[tptr]->width) {
-				compiling_wrappers = 1;
-				genwrapper(it, f, a->isym, 1);
-				compiling_wrappers = 0;
-			}
-		}
-
-		if(!(a->tsym->flags & SymSiggen)) {
-			a->tsym->flags |= SymSiggen;
-			if(!eqtype(this, t)) {
-				compiling_wrappers = 1;
-				genwrapper(t, f, a->tsym, 0);
-				compiling_wrappers = 0;
-			}
-		}
-	}
-
-	return lsort(a, sigcmp);
-}
-
-/*
- * return methods of interface type t, sorted by name.
- */
-static Sig*
-imethods(Type *t)
-{
-	Sig *a, *all, *last;
-	Type *f;
-	Sym *method, *isym;
-
-	all = nil;
-	last = nil;
-	for(f=t->type; f; f=f->down) {
-		if(f->etype != TFIELD)
-			fatal("imethods: not field");
-		if(f->type->etype != TFUNC || f->sym == nil)
-			continue;
-		method = f->sym;
-		a = mal(sizeof(*a));
-		a->name = method->name;
-		if(!exportname(method->name)) {
-			if(method->pkg == nil)
-				fatal("imethods: missing package");
-			a->pkg = method->pkg;
-		}
-		a->mtype = f->type;
-		a->offset = 0;
-		a->type = methodfunc(f->type, nil);
-
-		if(last && sigcmp(last, a) >= 0)
-			fatal("sigcmp vs sortinter %s %s", last->name, a->name);
-		if(last == nil)
-			all = a;
-		else
-			last->link = a;
-		last = a;
-
-		// Compiler can only refer to wrappers for non-blank methods.
-		if(isblanksym(method))
-			continue;
-
-		// NOTE(rsc): Perhaps an oversight that
-		// IfaceType.Method is not in the reflect data.
-		// Generate the method body, so that compiled
-		// code can refer to it.
-		isym = methodsym(method, t, 0);
-		if(!(isym->flags & SymSiggen)) {
-			isym->flags |= SymSiggen;
-			genwrapper(t, f, isym, 0);
-		}
-	}
-	return all;
-}
-
-static void
-dimportpath(Pkg *p)
-{
-	static Pkg *gopkg;
-	char *nam;
-	Node *n;
-
-	if(p->pathsym != S)
-		return;
-
-	if(gopkg == nil) {
-		gopkg = mkpkg(strlit("go"));
-		gopkg->name = "go";
-	}
-	nam = smprint("importpath.%s.", p->prefix);
-
-	n = nod(ONAME, N, N);
-	n->sym = pkglookup(nam, gopkg);
-	free(nam);
-	n->class = PEXTERN;
-	n->xoffset = 0;
-	p->pathsym = n->sym;
-
-	gdatastring(n, p->path);
-	ggloblsym(n->sym, types[TSTRING]->width, DUPOK|RODATA);
-}
-
-static int
-dgopkgpath(Sym *s, int ot, Pkg *pkg)
-{
-	if(pkg == nil)
-		return dgostringptr(s, ot, nil);
-
-	// 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) {
-		static Sym *ns;
-
-		if(ns == nil)
-			ns = pkglookup("importpath.\"\".", mkpkg(strlit("go")));
-		return dsymptr(s, ot, ns, 0);
-	}
-
-	dimportpath(pkg);
-	return dsymptr(s, ot, pkg->pathsym, 0);
-}
-
-/*
- * uncommonType
- * ../../runtime/type.go:/uncommonType
- */
-static int
-dextratype(Sym *sym, int off, Type *t, int ptroff)
-{
-	int ot, n;
-	Sym *s;
-	Sig *a, *m;
-
-	m = methods(t);
-	if(t->sym == nil && m == nil)
-		return off;
-
-	// fill in *extraType pointer in header
-	off = rnd(off, widthptr);
-	dsymptr(sym, ptroff, sym, off);
-
-	n = 0;
-	for(a=m; a; a=a->link) {
-		dtypesym(a->type);
-		n++;
-	}
-
-	ot = off;
-	s = sym;
-	if(t->sym) {
-		ot = dgostringptr(s, ot, t->sym->name);
-		if(t != types[t->etype] && t != errortype)
-			ot = dgopkgpath(s, ot, t->sym->pkg);
-		else
-			ot = dgostringptr(s, ot, nil);
-	} else {
-		ot = dgostringptr(s, ot, nil);
-		ot = dgostringptr(s, ot, nil);
-	}
-
-	// slice header
-	ot = dsymptr(s, ot, s, ot + widthptr + 2*widthint);
-	ot = duintxx(s, ot, n, widthint);
-	ot = duintxx(s, ot, n, widthint);
-
-	// methods
-	for(a=m; a; a=a->link) {
-		// method
-		// ../../runtime/type.go:/method
-		ot = dgostringptr(s, ot, a->name);
-		ot = dgopkgpath(s, ot, a->pkg);
-		ot = dsymptr(s, ot, dtypesym(a->mtype), 0);
-		ot = dsymptr(s, ot, dtypesym(a->type), 0);
-		if(a->isym)
-			ot = dsymptr(s, ot, a->isym, 0);
-		else
-			ot = duintptr(s, ot, 0);
-		if(a->tsym)
-			ot = dsymptr(s, ot, a->tsym, 0);
-		else
-			ot = duintptr(s, ot, 0);
-	}
-
-	return ot;
-}
-
-static int
-kinds[] =
-{
-	[TINT]		= KindInt,
-	[TUINT]		= KindUint,
-	[TINT8]		= KindInt8,
-	[TUINT8]	= KindUint8,
-	[TINT16]	= KindInt16,
-	[TUINT16]	= KindUint16,
-	[TINT32]	= KindInt32,
-	[TUINT32]	= KindUint32,
-	[TINT64]	= KindInt64,
-	[TUINT64]	= KindUint64,
-	[TUINTPTR]	= KindUintptr,
-	[TFLOAT32]	= KindFloat32,
-	[TFLOAT64]	= KindFloat64,
-	[TBOOL]		= KindBool,
-	[TSTRING]		= KindString,
-	[TPTR32]		= KindPtr,
-	[TPTR64]		= KindPtr,
-	[TSTRUCT]	= KindStruct,
-	[TINTER]		= KindInterface,
-	[TCHAN]		= KindChan,
-	[TMAP]		= KindMap,
-	[TARRAY]		= KindArray,
-	[TFUNC]		= KindFunc,
-	[TCOMPLEX64]	= KindComplex64,
-	[TCOMPLEX128]	= KindComplex128,
-	[TUNSAFEPTR]	= KindUnsafePointer,
-};
-
-int
-haspointers(Type *t)
-{
-	Type *t1;
-	int ret;
-
-	if(t->haspointers != 0)
-		return t->haspointers - 1;
-
-	switch(t->etype) {
-	case TINT:
-	case TUINT:
-	case TINT8:
-	case TUINT8:
-	case TINT16:
-	case TUINT16:
-	case TINT32:
-	case TUINT32:
-	case TINT64:
-	case TUINT64:
-	case TUINTPTR:
-	case TFLOAT32:
-	case TFLOAT64:
-	case TCOMPLEX64:
-	case TCOMPLEX128:
-	case TBOOL:
-		ret = 0;
-		break;
-	case TARRAY:
-		if(t->bound < 0) {	// slice
-			ret = 1;
-			break;
-		}
-		if(t->bound == 0) {	// empty array
-			ret = 0;
-			break;
-		}
-		ret = haspointers(t->type);
-		break;
-	case TSTRUCT:
-		ret = 0;
-		for(t1=t->type; t1!=T; t1=t1->down) {
-			if(haspointers(t1->type)) {
-				ret = 1;
-				break;
-			}
-		}
-		break;
-	case TSTRING:
-	case TPTR32:
-	case TPTR64:
-	case TUNSAFEPTR:
-	case TINTER:
-	case TCHAN:
-	case TMAP:
-	case TFUNC:
-	default:
-		ret = 1;
-		break;
-	}
-	
-	t->haspointers = 1+ret;
-	return ret;
-}
-
-/*
- * commonType
- * ../../runtime/type.go:/commonType
- */
-static int
-dcommontype(Sym *s, int ot, Type *t)
-{
-	int i, alg, sizeofAlg, gcprog;
-	Sym *sptr, *algsym, *zero, *gcprog0, *gcprog1, *sbits;
-	uint8 gcmask[16];
-	static Sym *algarray;
-	uint64 x1, x2;
-	char *p;
-	
-	if(ot != 0)
-		fatal("dcommontype %d", ot);
-
-	sizeofAlg = 2*widthptr;
-	if(algarray == nil)
-		algarray = pkglookup("algarray", runtimepkg);
-	dowidth(t);
-	alg = algtype(t);
-	algsym = S;
-	if(alg < 0)
-		algsym = dalgsym(t);
-
-	if(t->sym != nil && !isptr[t->etype])
-		sptr = dtypesym(ptrto(t));
-	else
-		sptr = weaktypesym(ptrto(t));
-
-	// All (non-reflect-allocated) Types share the same zero object.
-	// Each place in the compiler where a pointer to the zero object
-	// might be returned by a runtime call (map access return value,
-	// 2-arg type cast) declares the size of the zerovalue it needs.
-	// The linker magically takes the max of all the sizes.
-	zero = pkglookup("zerovalue", runtimepkg);
-
-	// We use size 0 here so we get the pointer to the zero value,
-	// but don't allocate space for the zero value unless we need it.
-	// TODO: how do we get this symbol into bss?  We really want
-	// a read-only bss, but I don't think such a thing exists.
-
-	// ../../pkg/reflect/type.go:/^type.commonType
-	// actual type structure
-	//	type commonType struct {
-	//		size          uintptr
-	//		hash          uint32
-	//		_             uint8
-	//		align         uint8
-	//		fieldAlign    uint8
-	//		kind          uint8
-	//		alg           unsafe.Pointer
-	//		gc            unsafe.Pointer
-	//		string        *string
-	//		*extraType
-	//		ptrToThis     *Type
-	//		zero          unsafe.Pointer
-	//	}
-	ot = duintptr(s, ot, t->width);
-	ot = duint32(s, ot, typehash(t));
-	ot = duint8(s, ot, 0);	// unused
-
-	// runtime (and common sense) expects alignment to be a power of two.
-	i = t->align;
-	if(i == 0)
-		i = 1;
-	if((i&(i-1)) != 0)
-		fatal("invalid alignment %d for %T", t->align, t);
-	ot = duint8(s, ot, t->align);	// align
-	ot = duint8(s, ot, t->align);	// fieldAlign
-
-	gcprog = usegcprog(t);
-	i = kinds[t->etype];
-	if(t->etype == TARRAY && t->bound < 0)
-		i = KindSlice;
-	if(!haspointers(t))
-		i |= KindNoPointers;
-	if(isdirectiface(t))
-		i |= KindDirectIface;
-	if(gcprog)
-		i |= KindGCProg;
-	ot = duint8(s, ot, i);  // kind
-	if(alg >= 0)
-		ot = dsymptr(s, ot, algarray, alg*sizeofAlg);
-	else
-		ot = dsymptr(s, ot, algsym, 0);
-	// gc
-	if(gcprog) {
-		gengcprog(t, &gcprog0, &gcprog1);
-		if(gcprog0 != S)
-			ot = dsymptr(s, ot, gcprog0, 0);
-		else
-			ot = duintptr(s, ot, 0);
-		ot = dsymptr(s, ot, gcprog1, 0);
-	} else {
-		gengcmask(t, gcmask);
-		x1 = 0;
-		for(i=0; i<8; i++)
-			x1 = x1<<8 | gcmask[i];
-		if(widthptr == 4) {
-			p = smprint("gcbits.%#016llux", x1);
-		} else {
-			x2 = 0;
-			for(i=0; i<8; i++)
-				x2 = x2<<8 | gcmask[i+8];
-			p = smprint("gcbits.%#016llux%016llux", x1, x2);
-		}
-		sbits = pkglookup(p, runtimepkg);
-		if((sbits->flags & SymUniq) == 0) {
-			sbits->flags |= SymUniq;
-			for(i = 0; i < 2*widthptr; i++)
-				duint8(sbits, i, gcmask[i]);
-			ggloblsym(sbits, 2*widthptr, DUPOK|RODATA);
-		}
-		ot = dsymptr(s, ot, sbits, 0);
-		ot = duintptr(s, ot, 0);
-	}
-	p = smprint("%-uT", t);
-	//print("dcommontype: %s\n", p);
-	ot = dgostringptr(s, ot, p);	// string
-	free(p);
-
-	// skip pointer to extraType,
-	// which follows the rest of this type structure.
-	// caller will fill in if needed.
-	// otherwise linker will assume 0.
-	ot += widthptr;
-
-	ot = dsymptr(s, ot, sptr, 0);  // ptrto type
-	ot = dsymptr(s, ot, zero, 0);  // ptr to zero value
-	return ot;
-}
-
-Sym*
-typesym(Type *t)
-{
-	char *p;
-	Sym *s;
-
-	p = smprint("%-T", t);
-	s = pkglookup(p, typepkg);
-	//print("typesym: %s -> %+S\n", p, s);
-	free(p);
-	return s;
-}
-
-Sym*
-tracksym(Type *t)
-{
-	char *p;
-	Sym *s;
-
-	p = smprint("%-T.%s", t->outer, t->sym->name);
-	s = pkglookup(p, trackpkg);
-	free(p);
-	return s;
-}
-
-Sym*
-typelinksym(Type *t)
-{
-	char *p;
-	Sym *s;
-
-	// %-uT is what the generated Type's string field says.
-	// It uses (ambiguous) package names instead of import paths.
-	// %-T is the complete, unambiguous type name.
-	// We want the types to end up sorted by string field,
-	// so use that first in the name, and then add :%-T to
-	// 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 = smprint("%-uT/%-T", t, t);
-	s = pkglookup(p, typelinkpkg);
-	//print("typelinksym: %s -> %+S\n", p, s);
-	free(p);
-	return s;
-}
-
-Sym*
-typesymprefix(char *prefix, Type *t)
-{
-	char *p;
-	Sym *s;
-
-	p = smprint("%s.%-T", prefix, t);
-	s = pkglookup(p, typepkg);
-	//print("algsym: %s -> %+S\n", p, s);
-	free(p);
-	return s;
-}
-
-Sym*
-typenamesym(Type *t)
-{
-	Sym *s;
-	Node *n;
-
-	if(t == T || (isptr[t->etype] && t->type == T) || isideal(t))
-		fatal("typename %T", t);
-	s = typesym(t);
-	if(s->def == N) {
-		n = nod(ONAME, N, N);
-		n->sym = s;
-		n->type = types[TUINT8];
-		n->addable = 1;
-		n->ullman = 1;
-		n->class = PEXTERN;
-		n->xoffset = 0;
-		n->typecheck = 1;
-		s->def = n;
-
-		signatlist = list(signatlist, typenod(t));
-	}
-	return s->def->sym;
-}
-
-Node*
-typename(Type *t)
-{
-	Sym *s;
-	Node *n;
-
-	s = typenamesym(t);
-	n = nod(OADDR, s->def, N);
-	n->type = ptrto(s->def->type);
-	n->addable = 1;
-	n->ullman = 2;
-	n->typecheck = 1;
-	return n;
-}
-
-static Sym*
-weaktypesym(Type *t)
-{
-	char *p;
-	Sym *s;
-
-	p = smprint("%-T", t);
-	s = pkglookup(p, weaktypepkg);
-	//print("weaktypesym: %s -> %+S\n", p, s);
-	free(p);
-	return s;
-}
-
-static Sym*
-dtypesym(Type *t)
-{
-	int ot, xt, n, isddd, dupok;
-	Sym *s, *s1, *s2, *s3, *s4, *slink;
-	Sig *a, *m;
-	Type *t1, *tbase, *t2;
-
-	// 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.
-	if(t == bytetype || t == runetype)
-		t = types[t->etype];
-
-	if(isideal(t))
-		fatal("dtypesym %T", t);
-
-	s = typesym(t);
-	if(s->flags & SymSiggen)
-		return s;
-	s->flags |= SymSiggen;
-
-	// special case (look for runtime below):
-	// when compiling package runtime,
-	// emit the type structures for int, float, etc.
-	tbase = t;
-	if(isptr[t->etype] && t->sym == S && t->type->sym != S)
-		tbase = t->type;
-	dupok = 0;
-	if(tbase->sym == S)
-		dupok = DUPOK;
-
-	if(compiling_runtime &&
-			(tbase == types[tbase->etype] ||
-			tbase == bytetype ||
-			tbase == runetype ||
-			tbase == errortype)) { // int, float, etc
-		goto ok;
-	}
-
-	// named types from other files are defined only by those files
-	if(tbase->sym && !tbase->local)
-		return s;
-	if(isforw[tbase->etype])
-		return s;
-
-ok:
-	ot = 0;
-	xt = 0;
-	switch(t->etype) {
-	default:
-		ot = dcommontype(s, ot, t);
-		xt = ot - 3*widthptr;
-		break;
-
-	case TARRAY:
-		if(t->bound >= 0) {
-			// ../../runtime/type.go:/ArrayType
-			s1 = dtypesym(t->type);
-			t2 = typ(TARRAY);
-			t2->type = t->type;
-			t2->bound = -1;  // slice
-			s2 = dtypesym(t2);
-			ot = dcommontype(s, ot, t);
-			xt = ot - 3*widthptr;
-			ot = dsymptr(s, ot, s1, 0);
-			ot = dsymptr(s, ot, s2, 0);
-			ot = duintptr(s, ot, t->bound);
-		} else {
-			// ../../runtime/type.go:/SliceType
-			s1 = dtypesym(t->type);
-			ot = dcommontype(s, ot, t);
-			xt = ot - 3*widthptr;
-			ot = dsymptr(s, ot, s1, 0);
-		}
-		break;
-
-	case TCHAN:
-		// ../../runtime/type.go:/ChanType
-		s1 = dtypesym(t->type);
-		ot = dcommontype(s, ot, t);
-		xt = ot - 3*widthptr;
-		ot = dsymptr(s, ot, s1, 0);
-		ot = duintptr(s, ot, t->chan);
-		break;
-
-	case TFUNC:
-		for(t1=getthisx(t)->type; t1; t1=t1->down)
-			dtypesym(t1->type);
-		isddd = 0;
-		for(t1=getinargx(t)->type; t1; t1=t1->down) {
-			isddd = t1->isddd;
-			dtypesym(t1->type);
-		}
-		for(t1=getoutargx(t)->type; t1; t1=t1->down)
-			dtypesym(t1->type);
-
-		ot = dcommontype(s, ot, t);
-		xt = ot - 3*widthptr;
-		ot = duint8(s, ot, isddd);
-
-		// two slice headers: in and out.
-		ot = rnd(ot, widthptr);
-		ot = dsymptr(s, ot, s, ot+2*(widthptr+2*widthint));
-		n = t->thistuple + t->intuple;
-		ot = duintxx(s, ot, n, widthint);
-		ot = duintxx(s, ot, n, widthint);
-		ot = dsymptr(s, ot, s, ot+1*(widthptr+2*widthint)+n*widthptr);
-		ot = duintxx(s, ot, t->outtuple, widthint);
-		ot = duintxx(s, ot, t->outtuple, widthint);
-
-		// slice data
-		for(t1=getthisx(t)->type; t1; t1=t1->down, n++)
-			ot = dsymptr(s, ot, dtypesym(t1->type), 0);
-		for(t1=getinargx(t)->type; t1; t1=t1->down, n++)
-			ot = dsymptr(s, ot, dtypesym(t1->type), 0);
-		for(t1=getoutargx(t)->type; t1; t1=t1->down, n++)
-			ot = dsymptr(s, ot, dtypesym(t1->type), 0);
-		break;
-
-	case TINTER:
-		m = imethods(t);
-		n = 0;
-		for(a=m; a; a=a->link) {
-			dtypesym(a->type);
-			n++;
-		}
-
-		// ../../runtime/type.go:/InterfaceType
-		ot = dcommontype(s, ot, t);
-		xt = ot - 3*widthptr;
-		ot = dsymptr(s, ot, s, ot+widthptr+2*widthint);
-		ot = duintxx(s, ot, n, widthint);
-		ot = duintxx(s, ot, n, widthint);
-		for(a=m; a; a=a->link) {
-			// ../../runtime/type.go:/imethod
-			ot = dgostringptr(s, ot, a->name);
-			ot = dgopkgpath(s, ot, a->pkg);
-			ot = dsymptr(s, ot, dtypesym(a->type), 0);
-		}
-		break;
-
-	case TMAP:
-		// ../../runtime/type.go:/MapType
-		s1 = dtypesym(t->down);
-		s2 = dtypesym(t->type);
-		s3 = dtypesym(mapbucket(t));
-		s4 = dtypesym(hmap(t));
-		ot = dcommontype(s, ot, t);
-		xt = ot - 3*widthptr;
-		ot = dsymptr(s, ot, s1, 0);
-		ot = dsymptr(s, ot, s2, 0);
-		ot = dsymptr(s, ot, s3, 0);
-		ot = dsymptr(s, ot, s4, 0);
-		if(t->down->width > MAXKEYSIZE) {
-			ot = duint8(s, ot, widthptr);
-			ot = duint8(s, ot, 1); // indirect
-		} else {
-			ot = duint8(s, ot, t->down->width);
-			ot = duint8(s, ot, 0); // not indirect
-		}
-		if(t->type->width > MAXVALSIZE) {
-			ot = duint8(s, ot, widthptr);
-			ot = duint8(s, ot, 1); // indirect
-		} else {
-			ot = duint8(s, ot, t->type->width);
-			ot = duint8(s, ot, 0); // not indirect
-		}
-		ot = duint16(s, ot, mapbucket(t)->width);
-		break;
-
-	case TPTR32:
-	case TPTR64:
-		if(t->type->etype == TANY) {
-			// ../../runtime/type.go:/UnsafePointerType
-			ot = dcommontype(s, ot, t);
-			break;
-		}
-		// ../../runtime/type.go:/PtrType
-		s1 = dtypesym(t->type);
-		ot = dcommontype(s, ot, t);
-		xt = ot - 3*widthptr;
-		ot = dsymptr(s, ot, s1, 0);
-		break;
-
-	case TSTRUCT:
-		// ../../runtime/type.go:/StructType
-		// for security, only the exported fields.
-		n = 0;
-		for(t1=t->type; t1!=T; t1=t1->down) {
-			dtypesym(t1->type);
-			n++;
-		}
-		ot = dcommontype(s, ot, t);
-		xt = ot - 3*widthptr;
-		ot = dsymptr(s, ot, s, ot+widthptr+2*widthint);
-		ot = duintxx(s, ot, n, widthint);
-		ot = duintxx(s, ot, n, widthint);
-		for(t1=t->type; t1!=T; t1=t1->down) {
-			// ../../runtime/type.go:/structField
-			if(t1->sym && !t1->embedded) {
-				ot = dgostringptr(s, ot, t1->sym->name);
-				if(exportname(t1->sym->name))
-					ot = dgostringptr(s, ot, nil);
-				else
-					ot = dgopkgpath(s, ot, t1->sym->pkg);
-			} else {
-				ot = dgostringptr(s, ot, nil);
-				if(t1->type->sym != S && t1->type->sym->pkg == builtinpkg)
-					ot = dgopkgpath(s, ot, localpkg);
-				else
-					ot = dgostringptr(s, ot, nil);
-			}
-			ot = dsymptr(s, ot, dtypesym(t1->type), 0);
-			ot = dgostrlitptr(s, ot, t1->note);
-			ot = duintptr(s, ot, t1->width);	// field offset
-		}
-		break;
-	}
-	ot = dextratype(s, ot, t, xt);
-	ggloblsym(s, ot, dupok|RODATA);
-
-	// generate typelink.foo pointing at s = type.foo.
-	// The linker will leave a table of all the typelinks for
-	// types in the binary, so reflect can find them.
-	// We only need the link for unnamed composites that
-	// we want be able to find.
-	if(t->sym == S) {
-		switch(t->etype) {
-		case TARRAY:
-		case TCHAN:
-		case TMAP:
-			slink = typelinksym(t);
-			dsymptr(slink, 0, s, 0);
-			ggloblsym(slink, widthptr, dupok|RODATA);
-		}
-	}
-
-	return s;
-}
-
-void
-dumptypestructs(void)
-{
-	int i;
-	NodeList *l;
-	Node *n;
-	Type *t;
-	Pkg *p;
-
-	// copy types from externdcl list to signatlist
-	for(l=externdcl; l; l=l->next) {
-		n = l->n;
-		if(n->op != OTYPE)
-			continue;
-		signatlist = list(signatlist, n);
-	}
-
-	// process signatlist
-	for(l=signatlist; l; l=l->next) {
-		n = l->n;
-		if(n->op != OTYPE)
-			continue;
-		t = n->type;
-		dtypesym(t);
-		if(t->sym)
-			dtypesym(ptrto(t));
-	}
-
-	// generate import strings for imported packages
-	for(i=0; i<nelem(phash); i++)
-		for(p=phash[i]; p; p=p->link)
-			if(p->direct)
-				dimportpath(p);
-
-	// do basic types if compiling package runtime.
-	// they have to be in at least one package,
-	// and runtime is always loaded implicitly,
-	// so this is as good as any.
-	// another possible choice would be package main,
-	// but using runtime means fewer copies in .6 files.
-	if(compiling_runtime) {
-		for(i=1; i<=TBOOL; i++)
-			dtypesym(ptrto(types[i]));
-		dtypesym(ptrto(types[TSTRING]));
-		dtypesym(ptrto(types[TUNSAFEPTR]));
-
-		// emit type structs for error and func(error) string.
-		// The latter is the type of an auto-generated wrapper.
-		dtypesym(ptrto(errortype));
-		dtypesym(functype(nil,
-			list1(nod(ODCLFIELD, N, typenod(errortype))),
-			list1(nod(ODCLFIELD, N, typenod(types[TSTRING])))));
-
-		// add paths for runtime and main, which 6l imports implicitly.
-		dimportpath(runtimepkg);
-		if(flag_race)
-			dimportpath(racepkg);
-		dimportpath(mkpkg(strlit("main")));
-	}
-}
-
-static Sym*
-dalgsym(Type *t)
-{
-	int ot;
-	Sym *s, *hash, *hashfunc, *eq, *eqfunc;
-
-	// dalgsym is only called for a type that needs an algorithm table,
-	// which implies that the type is comparable (or else it would use ANOEQ).
-
-	s = typesymprefix(".alg", t);
-	hash = typesymprefix(".hash", t);
-	genhash(hash, t);
-	eq = typesymprefix(".eq", t);
-	geneq(eq, t);
-
-	// make Go funcs (closures) for calling hash and equal from Go
-	hashfunc = typesymprefix(".hashfunc", t);
-	dsymptr(hashfunc, 0, hash, 0);
-	ggloblsym(hashfunc, widthptr, DUPOK|RODATA);
-	eqfunc = typesymprefix(".eqfunc", t);
-	dsymptr(eqfunc, 0, eq, 0);
-	ggloblsym(eqfunc, widthptr, DUPOK|RODATA);
-
-	// ../../runtime/alg.go:/typeAlg
-	ot = 0;
-	ot = dsymptr(s, ot, hashfunc, 0);
-	ot = dsymptr(s, ot, eqfunc, 0);
-
-	ggloblsym(s, ot, DUPOK|RODATA);
-	return s;
-}
-
-static int
-usegcprog(Type *t)
-{
-	vlong size, nptr;
-
-	if(!haspointers(t))
-		return 0;
-	if(t->width == BADWIDTH)
-		dowidth(t);
-	// Calculate size of the unrolled GC mask.
-	nptr = (t->width+widthptr-1)/widthptr;
-	size = nptr;
-	if(size%2)
-		size *= 2;	// repeated
-	size = size*gcBits/8;	// 4 bits per word
-	// Decide whether to use unrolled GC mask or GC program.
-	// We could use a more elaborate condition, but this seems to work well in practice.
-	// For small objects GC program can't give significant reduction.
-	// While large objects usually contain arrays; and even if it don't
-	// the program uses 2-bits per word while mask uses 4-bits per word,
-	// so the program is still smaller.
-	return size > 2*widthptr;
-}
-
-// Generates sparse GC bitmask (4 bits per word).
-static void
-gengcmask(Type *t, uint8 gcmask[16])
-{
-	Bvec *vec;
-	vlong xoffset, nptr, i, j;
-	int  half, mw;
-	uint8 bits, *pos;
-
-	memset(gcmask, 0, 16);
-	if(!haspointers(t))
-		return;
-
-	// Generate compact mask as stacks use.
-	xoffset = 0;
-	vec = bvalloc(2*widthptr*8);
-	twobitwalktype1(t, &xoffset, vec);
-
-	// Unfold the mask for the GC bitmap format:
-	// 4 bits per word, 2 high bits encode pointer info.
-	pos = (uint8*)gcmask;
-	nptr = (t->width+widthptr-1)/widthptr;
-	half = 0;
-	mw = 0;
-	// If number of words is odd, repeat the mask.
-	// This makes simpler handling of arrays in runtime.
-	for(j=0; j<=(nptr%2); j++) {
-		for(i=0; i<nptr; i++) {
-			bits = bvget(vec, i*BitsPerPointer) | bvget(vec, i*BitsPerPointer+1)<<1;
-			// Some fake types (e.g. Hmap) has missing fileds.
-			// twobitwalktype1 generates BitsDead for that holes,
-			// replace BitsDead with BitsScalar.
-			if(!mw && bits == BitsDead)
-				bits = BitsScalar;
-			mw = !mw && bits == BitsMultiWord;
-			bits <<= 2;
-			if(half)
-				bits <<= 4;
-			*pos |= bits;
-			half = !half;
-			if(!half)
-				pos++;
-		}
-	}
-}
-
-// Helper object for generation of GC programs.
-typedef struct ProgGen ProgGen;
-struct ProgGen
-{
-	Sym*	s;
-	int32	datasize;
-	uint8	data[256/PointersPerByte];
-	vlong	ot;
-};
-
-static void
-proggeninit(ProgGen *g, Sym *s)
-{
-	g->s = s;
-	g->datasize = 0;
-	g->ot = 0;
-	memset(g->data, 0, sizeof(g->data));
-}
-
-static void
-proggenemit(ProgGen *g, uint8 v)
-{
-	g->ot = duint8(g->s, g->ot, v);
-}
-
-// Emits insData block from g->data.
-static void
-proggendataflush(ProgGen *g)
-{
-	int32 i, s;
-
-	if(g->datasize == 0)
-		return;
-	proggenemit(g, insData);
-	proggenemit(g, g->datasize);
-	s = (g->datasize + PointersPerByte - 1)/PointersPerByte;
-	for(i = 0; i < s; i++)
-		proggenemit(g, g->data[i]);
-	g->datasize = 0;
-	memset(g->data, 0, sizeof(g->data));
-}
-
-static void
-proggendata(ProgGen *g, uint8 d)
-{
-	g->data[g->datasize/PointersPerByte] |= d << ((g->datasize%PointersPerByte)*BitsPerPointer);
-	g->datasize++;
-	if(g->datasize == 255)
-		proggendataflush(g);
-}
-
-// Skip v bytes due to alignment, etc.
-static void
-proggenskip(ProgGen *g, vlong off, vlong v)
-{
-	vlong i;
-
-	for(i = off; i < off+v; i++) {
-		if((i%widthptr) == 0)
-			proggendata(g, BitsScalar);
-	}
-}
-
-// Emit insArray instruction.
-static void
-proggenarray(ProgGen *g, vlong len)
-{
-	int32 i;
-
-	proggendataflush(g);
-	proggenemit(g, insArray);
-	for(i = 0; i < widthptr; i++, len >>= 8)
-		proggenemit(g, len);
-}
-
-static void
-proggenarrayend(ProgGen *g)
-{
-	proggendataflush(g);
-	proggenemit(g, insArrayEnd);
-}
-
-static vlong
-proggenfini(ProgGen *g)
-{
-	proggendataflush(g);
-	proggenemit(g, insEnd);
-	return g->ot;
-}
-
-static void gengcprog1(ProgGen *g, Type *t, vlong *xoffset);
-
-// Generates GC program for large types.
-static void
-gengcprog(Type *t, Sym **pgc0, Sym **pgc1)
-{
-	Sym *gc0, *gc1;
-	vlong nptr, size, ot, xoffset;
-	ProgGen g;
-
-	nptr = (t->width+widthptr-1)/widthptr;
-	size = nptr;
-	if(size%2)
-		size *= 2;	// repeated twice
-	size = size*PointersPerByte/8;	// 4 bits per word
-	size++;	// unroll flag in the beginning, used by runtime (see runtime.markallocated)
-	// emity space in BSS for unrolled program
-	*pgc0 = S;
-	// Don't generate it if it's too large, runtime will unroll directly into GC bitmap.
-	if(size <= MaxGCMask) {
-		gc0 = typesymprefix(".gc", t);
-		ggloblsym(gc0, size, DUPOK|NOPTR);
-		*pgc0 = gc0;
-	}
-
-	// program in RODATA
-	gc1 = typesymprefix(".gcprog", t);
-	proggeninit(&g, gc1);
-	xoffset = 0;
-	gengcprog1(&g, t, &xoffset);
-	ot = proggenfini(&g);
-	ggloblsym(gc1, ot, DUPOK|RODATA);
-	*pgc1 = gc1;
-}
-
-// Recursively walks type t and writes GC program into g.
-static void
-gengcprog1(ProgGen *g, Type *t, vlong *xoffset)
-{
-	vlong fieldoffset, i, o, n;
-	Type *t1;
-
-	switch(t->etype) {
-	case TINT8:
-	case TUINT8:
-	case TINT16:
-	case TUINT16:
-	case TINT32:
-	case TUINT32:
-	case TINT64:
-	case TUINT64:
-	case TINT:
-	case TUINT:
-	case TUINTPTR:
-	case TBOOL:
-	case TFLOAT32:
-	case TFLOAT64:
-	case TCOMPLEX64:
-	case TCOMPLEX128:
-		proggenskip(g, *xoffset, t->width);
-		*xoffset += t->width;
-		break;
-	case TPTR32:
-	case TPTR64:
-	case TUNSAFEPTR:
-	case TFUNC:
-	case TCHAN:
-	case TMAP:
-		proggendata(g, BitsPointer);
-		*xoffset += t->width;
-		break;
-	case TSTRING:
-		proggendata(g, BitsPointer);
-		proggendata(g, BitsScalar);
-		*xoffset += t->width;
-		break;
-	case TINTER:
-		proggendata(g, BitsMultiWord);
-		if(isnilinter(t))
-			proggendata(g, BitsEface);
-		else
-			proggendata(g, BitsIface);
-		*xoffset += t->width;
-		break;
-	case TARRAY:
-		if(isslice(t)) {
-			proggendata(g, BitsPointer);
-			proggendata(g, BitsScalar);
-			proggendata(g, BitsScalar);
-		} else {
-			t1 = t->type;
-			if(t1->width == 0) {
-				// ignore
-			} if(t->bound <= 1 || t->bound*t1->width < 32*widthptr) {
-				for(i = 0; i < t->bound; i++)
-					gengcprog1(g, t1, xoffset);
-			} else if(!haspointers(t1)) {
-				n = t->width;
-				n -= -*xoffset&(widthptr-1); // skip to next ptr boundary
-				proggenarray(g, (n+widthptr-1)/widthptr);
-				proggendata(g, BitsScalar);
-				proggenarrayend(g);
-				*xoffset -= (n+widthptr-1)/widthptr*widthptr - t->width;
-			} else {
-				proggenarray(g, t->bound);
-				gengcprog1(g, t1, xoffset);
-				*xoffset += (t->bound-1)*t1->width;
-				proggenarrayend(g);
-			}
-		}
-		break;
-	case TSTRUCT:
-		o = 0;
-		for(t1 = t->type; t1 != T; t1 = t1->down) {
-			fieldoffset = t1->width;
-			proggenskip(g, *xoffset, fieldoffset - o);
-			*xoffset += fieldoffset - o;
-			gengcprog1(g, t1->type, xoffset);
-			o = fieldoffset + t1->type->width;
-		}
-		proggenskip(g, *xoffset, t->width - o);
-		*xoffset += t->width - o;
-		break;
-	default:
-		fatal("gengcprog1: unexpected type, %T", t);
-	}
-}
diff --git a/src/cmd/gc/runtime.go b/src/cmd/gc/runtime.go
deleted file mode 100644
index 0fb15c2..0000000
--- a/src/cmd/gc/runtime.go
+++ /dev/null
@@ -1,164 +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.
-
-// NOTE: If you change this file you must run "./mkbuiltin"
-// to update builtin.c.  This is not done automatically
-// to avoid depending on having a working compiler binary.
-
-// +build ignore
-
-package PACKAGE
-
-// emitted by compiler, not referred to by go programs
-
-func newobject(typ *byte) *any
-func panicindex()
-func panicslice()
-func panicdivide()
-func throwreturn()
-func throwinit()
-func panicwrap(string, string, string)
-
-func gopanic(interface{})
-func gorecover(*int32) interface{}
-
-func printbool(bool)
-func printfloat(float64)
-func printint(int64)
-func printhex(uint64)
-func printuint(uint64)
-func printcomplex(complex128)
-func printstring(string)
-func printpointer(any)
-func printiface(any)
-func printeface(any)
-func printslice(any)
-func printnl()
-func printsp()
-
-func concatstring2(string, string) string
-func concatstring3(string, string, string) string
-func concatstring4(string, string, string, string) string
-func concatstring5(string, string, string, string, string) string
-func concatstrings([]string) string
-
-func cmpstring(string, string) int
-func eqstring(string, string) bool
-func intstring(int64) string
-func slicebytetostring([]byte) string
-func slicebytetostringtmp([]byte) string
-func slicerunetostring([]rune) string
-func stringtoslicebyte(string) []byte
-func stringtoslicerune(string) []rune
-func stringiter(string, int) int
-func stringiter2(string, int) (retk int, retv rune)
-func slicecopy(to any, fr any, wid uintptr) int
-func slicestringcopy(to any, fr any) int
-
-// interface conversions
-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)
-
-// interface type assertions  x.(T)
-func assertE2E(typ *byte, iface any) (ret any)
-func assertE2E2(typ *byte, iface any) (ret any, ok bool)
-func assertE2I(typ *byte, iface any) (ret any)
-func assertE2I2(typ *byte, iface any) (ret any, ok bool)
-func assertE2T(typ *byte, iface any) (ret any)
-func assertE2T2(typ *byte, iface any) (ret any, ok bool)
-func assertI2E(typ *byte, iface any) (ret any)
-func assertI2E2(typ *byte, iface any) (ret any, ok bool)
-func assertI2I(typ *byte, iface any) (ret any)
-func assertI2I2(typ *byte, iface any) (ret any, ok bool)
-func assertI2T(typ *byte, iface any) (ret any)
-func assertI2T2(typ *byte, iface any) (ret any, ok bool)
-func assertI2TOK(typ *byte, iface any) (ok bool)
-func assertE2TOK(typ *byte, iface any) (ok bool)
-
-func ifaceeq(i1 any, i2 any) (ret bool)
-func efaceeq(i1 any, i2 any) (ret bool)
-func ifacethash(i1 any) (ret uint32)
-func efacethash(i1 any) (ret uint32)
-
-// *byte is really *runtime.Type
-func makemap(mapType *byte, hint int64) (hmap map[any]any)
-func mapaccess1(mapType *byte, hmap map[any]any, key *any) (val *any)
-func mapaccess1_fast32(mapType *byte, hmap map[any]any, key any) (val *any)
-func mapaccess1_fast64(mapType *byte, hmap map[any]any, key any) (val *any)
-func mapaccess1_faststr(mapType *byte, hmap map[any]any, key any) (val *any)
-func mapaccess2(mapType *byte, hmap map[any]any, key *any) (val *any, pres bool)
-func mapaccess2_fast32(mapType *byte, hmap map[any]any, key any) (val *any, pres bool)
-func mapaccess2_fast64(mapType *byte, hmap map[any]any, key any) (val *any, pres bool)
-func mapaccess2_faststr(mapType *byte, hmap map[any]any, key any) (val *any, pres bool)
-func mapassign1(mapType *byte, hmap map[any]any, key *any, val *any)
-func mapiterinit(mapType *byte, hmap map[any]any, hiter *any)
-func mapdelete(mapType *byte, hmap map[any]any, key *any)
-func mapiternext(hiter *any)
-
-// *byte is really *runtime.Type
-func makechan(chanType *byte, hint int64) (hchan chan any)
-func chanrecv1(chanType *byte, hchan <-chan any, elem *any)
-func chanrecv2(chanType *byte, hchan <-chan any, elem *any) bool
-func chansend1(chanType *byte, hchan chan<- any, elem *any)
-func closechan(hchan any)
-
-// *byte is really *runtime.Type
-func writebarrierptr(dst *any, src any)
-func writebarrierstring(dst *any, src any)
-func writebarrierslice(dst *any, src any)
-func writebarrieriface(dst *any, src any)
-
-// The unused *byte argument makes sure that src is 2-pointer-aligned,
-// which is the maximum alignment on NaCl amd64p32
-// (and possibly on 32-bit systems if we start 64-bit aligning uint64s).
-func writebarrierfat2(dst *any, _ *byte, src any)
-func writebarrierfat3(dst *any, _ *byte, src any)
-func writebarrierfat4(dst *any, _ *byte, src any)
-func writebarrierfat(typ *byte, dst *any, src *any)
-
-func selectnbsend(chanType *byte, hchan chan<- any, elem *any) bool
-func selectnbrecv(chanType *byte, elem *any, hchan <-chan any) bool
-func selectnbrecv2(chanType *byte, elem *any, received *bool, hchan <-chan any) bool
-
-func newselect(sel *byte, selsize int64, size int32)
-func selectsend(sel *byte, hchan chan<- any, elem *any) (selected bool)
-func selectrecv(sel *byte, hchan <-chan any, elem *any) (selected bool)
-func selectrecv2(sel *byte, hchan <-chan any, elem *any, received *bool) (selected bool)
-func selectdefault(sel *byte) (selected bool)
-func selectgo(sel *byte)
-func block()
-
-func makeslice(typ *byte, nel int64, cap int64) (ary []any)
-func growslice(typ *byte, old []any, n int64) (ary []any)
-func memmove(to *any, frm *any, length uintptr)
-
-func memequal(x, y *any, size uintptr) bool
-func memequal8(x, y *any, size uintptr) bool
-func memequal16(x, y *any, size uintptr) bool
-func memequal32(x, y *any, size uintptr) bool
-func memequal64(x, y *any, size uintptr) bool
-func memequal128(x, y *any, size uintptr) bool
-
-// only used on 32-bit
-func int64div(int64, int64) int64
-func uint64div(uint64, uint64) uint64
-func int64mod(int64, int64) int64
-func uint64mod(uint64, uint64) uint64
-func float64toint64(float64) int64
-func float64touint64(float64) uint64
-func int64tofloat64(int64) float64
-func uint64tofloat64(uint64) float64
-
-func complex128div(num complex128, den complex128) (quo complex128)
-
-// race detection
-func racefuncenter(uintptr)
-func racefuncexit()
-func raceread(uintptr)
-func racewrite(uintptr)
-func racereadrange(addr, size uintptr)
-func racewriterange(addr, size uintptr)
diff --git a/src/cmd/gc/select.c b/src/cmd/gc/select.c
deleted file mode 100644
index 965ad27..0000000
--- a/src/cmd/gc/select.c
+++ /dev/null
@@ -1,377 +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.
-
-/*
- * select
- */
-
-#include <u.h>
-#include <libc.h>
-#include "go.h"
-
-static Type* selecttype(int32 size);
-
-void
-typecheckselect(Node *sel)
-{
-	Node *ncase, *n, *def;
-	NodeList *l;
-	int lno, count;
-
-	def = nil;
-	lno = setlineno(sel);
-	count = 0;
-	typechecklist(sel->ninit, Etop);
-	for(l=sel->list; l; l=l->next) {
-		count++;
-		ncase = l->n;
-		setlineno(ncase);
-		if(ncase->op != OXCASE)
-			fatal("typecheckselect %O", ncase->op);
-
-		if(ncase->list == nil) {
-			// default
-			if(def != N)
-				yyerror("multiple defaults in select (first at %L)", def->lineno);
-			else
-				def = ncase;
-		} else if(ncase->list->next) {
-			yyerror("select cases cannot be lists");
-		} else {
-			n = typecheck(&ncase->list->n, Etop);
-			ncase->left = n;
-			ncase->list = nil;
-			setlineno(n);
-			switch(n->op) {
-			default:
-				yyerror("select case must be receive, send or assign recv");
-				break;
-
-			case OAS:
-				// convert x = <-c into OSELRECV(x, <-c).
-				// remove implicit conversions; the eventual assignment
-				// will reintroduce them.
-				if((n->right->op == OCONVNOP || n->right->op == OCONVIFACE) && n->right->implicit)
-					n->right = n->right->left;
-
-				if(n->right->op != ORECV) {
-					yyerror("select assignment must have receive on right hand side");
-					break;
-				}
-				n->op = OSELRECV;
-				break;
-
-			case OAS2RECV:
-				// convert x, ok = <-c into OSELRECV2(x, <-c) with ntest=ok
-				if(n->rlist->n->op != ORECV) {
-					yyerror("select assignment must have receive on right hand side");
-					break;
-				}
-				n->op = OSELRECV2;
-				n->left = n->list->n;
-				n->ntest = n->list->next->n;
-				n->list = nil;
-				n->right = n->rlist->n;
-				n->rlist = nil;
-				break;
-
-			case ORECV:
-				// convert <-c into OSELRECV(N, <-c)
-				n = nod(OSELRECV, N, n);
-				n->typecheck = 1;
-				ncase->left = n;
-				break;
-
-			case OSEND:
-				break;
-			}
-		}
-		typechecklist(ncase->nbody, Etop);
-	}
-	sel->xoffset = count;
-	lineno = lno;
-}
-
-void
-walkselect(Node *sel)
-{
-	int lno, i;
-	Node *n, *r, *a, *var, *selv, *cas, *dflt, *ch;
-	NodeList *l, *init;
-	
-	if(sel->list == nil && sel->xoffset != 0)
-		fatal("double walkselect");	// already rewrote
-	
-	lno = setlineno(sel);
-	i = count(sel->list);
-	
-	// optimization: zero-case select
-	if(i == 0) {
-		sel->nbody = list1(mkcall("block", nil, nil));
-		goto out;
-	}
-
-	// optimization: one-case select: single op.
-	// TODO(rsc): Reenable optimization once order.c can handle it.
-	// golang.org/issue/7672.
-	if(i == 1) {
-		cas = sel->list->n;
-		setlineno(cas);
-		l = cas->ninit;
-		if(cas->left != N) {  // not default:
-			n = cas->left;
-			l = concat(l, n->ninit);
-			n->ninit = nil;
-			switch(n->op) {
-			default:
-				fatal("select %O", n->op);
-
-			case OSEND:
-				// ok already
-				ch = n->left;
-				break;
-
-			case OSELRECV:
-				ch = n->right->left;
-			Selrecv1:
-				if(n->left == N)
-					n = n->right;
-				else
-					n->op = OAS;
-				break;
-			
-			case OSELRECV2:
-				ch = n->right->left;
-				if(n->ntest == N)
-					goto Selrecv1;
-				if(n->left == N) {
-					typecheck(&nblank, Erv | Easgn);
-					n->left = nblank;
-				}
-				n->op = OAS2;
-				n->list = list(list1(n->left), n->ntest);
-				n->rlist = list1(n->right);
-				n->right = N;
-				n->left = N;
-				n->ntest = N;
-				n->typecheck = 0;
-				typecheck(&n, Etop);
-				break;
-			}
-
-			// if ch == nil { block() }; n;
-			a = nod(OIF, N, N);
-			a->ntest = nod(OEQ, ch, nodnil());
-			a->nbody = list1(mkcall("block", nil, &l));
-			typecheck(&a, Etop);
-			l = list(l, a);
-			l = list(l, n);
-		}
-		l = concat(l, cas->nbody);
-		sel->nbody = l;
-		goto out;
-	}
-
-	// convert case value arguments to addresses.
-	// this rewrite is used by both the general code and the next optimization.
-	for(l=sel->list; l; l=l->next) {
-		cas = l->n;
-		setlineno(cas);
-		n = cas->left;
-		if(n == N)
-			continue;
-		switch(n->op) {
-		case OSEND:
-			n->right = nod(OADDR, n->right, N);
-			typecheck(&n->right, Erv);
-			break;
-		case OSELRECV:
-		case OSELRECV2:
-			if(n->op == OSELRECV2 && n->ntest == N)
-				n->op = OSELRECV;
-			if(n->op == OSELRECV2) {
-				n->ntest = nod(OADDR, n->ntest, N);
-				typecheck(&n->ntest, Erv);
-			}
-			if(n->left == N)
-				n->left = nodnil();
-			else {
-				n->left = nod(OADDR, n->left, N);
-				typecheck(&n->left, Erv);
-			}			
-			break;
-		}
-	}
-
-	// optimization: two-case select but one is default: single non-blocking op.
-	if(i == 2 && (sel->list->n->left == nil || sel->list->next->n->left == nil)) {
-		if(sel->list->n->left == nil) {
-			cas = sel->list->next->n;
-			dflt = sel->list->n;
-		} else {
-			dflt = sel->list->next->n;
-			cas = sel->list->n;
-		}
-		
-		n = cas->left;
-		setlineno(n);
-		r = nod(OIF, N, N);
-		r->ninit = cas->ninit;
-		switch(n->op) {
-		default:
-			fatal("select %O", n->op);
-
-		case OSEND:
-			// if selectnbsend(c, v) { body } else { default body }
-			ch = n->left;
-			r->ntest = mkcall1(chanfn("selectnbsend", 2, ch->type),
-					types[TBOOL], &r->ninit, typename(ch->type), ch, n->right);
-			break;
-			
-		case OSELRECV:
-			// if c != nil && selectnbrecv(&v, c) { body } else { default body }
-			r = nod(OIF, N, N);
-			r->ninit = cas->ninit;
-			ch = n->right->left;
-			r->ntest = mkcall1(chanfn("selectnbrecv", 2, ch->type),
-					types[TBOOL], &r->ninit, typename(ch->type), n->left, ch);
-			break;
-
-		case OSELRECV2:
-			// if c != nil && selectnbrecv2(&v, c) { body } else { default body }
-			r = nod(OIF, N, N);
-			r->ninit = cas->ninit;
-			ch = n->right->left;
-			r->ntest = mkcall1(chanfn("selectnbrecv2", 2, ch->type),
-					types[TBOOL], &r->ninit, typename(ch->type), n->left, n->ntest, ch);
-			break;
-		}
-		typecheck(&r->ntest, Erv);
-		r->nbody = cas->nbody;
-		r->nelse = concat(dflt->ninit, dflt->nbody);
-		sel->nbody = list1(r);
-		goto out;
-	}		
-
-	init = sel->ninit;
-	sel->ninit = nil;
-
-	// generate sel-struct
-	setlineno(sel);
-	selv = temp(selecttype(sel->xoffset));
-	r = nod(OAS, selv, N);
-	typecheck(&r, Etop);
-	init = list(init, r);
-	var = conv(conv(nod(OADDR, selv, N), types[TUNSAFEPTR]), ptrto(types[TUINT8]));
-	r = mkcall("newselect", T, nil, var, nodintconst(selv->type->width), nodintconst(sel->xoffset));
-	typecheck(&r, Etop);
-	init = list(init, r);
-
-	// register cases
-	for(l=sel->list; l; l=l->next) {
-		cas = l->n;
-		setlineno(cas);
-		n = cas->left;
-		r = nod(OIF, N, N);
-		r->ninit = cas->ninit;
-		cas->ninit = nil;
-		if(n != nil) {
-			r->ninit = concat(r->ninit, n->ninit);
-			n->ninit = nil;
-		}
-		if(n == nil) {
-			// selectdefault(sel *byte);
-			r->ntest = mkcall("selectdefault", types[TBOOL], &r->ninit, var);
-		} else {
-			switch(n->op) {
-			default:
-				fatal("select %O", n->op);
-	
-			case OSEND:
-				// selectsend(sel *byte, hchan *chan any, elem *any) (selected bool);
-				r->ntest = mkcall1(chanfn("selectsend", 2, n->left->type), types[TBOOL],
-					&r->ninit, var, n->left, n->right);
-				break;
-
-			case OSELRECV:
-				// selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool);
-				r->ntest = mkcall1(chanfn("selectrecv", 2, n->right->left->type), types[TBOOL],
-					&r->ninit, var, n->right->left, n->left);
-				break;
-
-			case OSELRECV2:
-				// selectrecv2(sel *byte, hchan *chan any, elem *any, received *bool) (selected bool);
-				r->ntest = mkcall1(chanfn("selectrecv2", 2, n->right->left->type), types[TBOOL],
-					&r->ninit, var, n->right->left, n->left, n->ntest);
-				break;
-			}
-		}
-		// selv is no longer alive after use.
-		r->nbody = list(r->nbody, nod(OVARKILL, selv, N));
-		r->nbody = concat(r->nbody, cas->nbody);
-		r->nbody = list(r->nbody, nod(OBREAK, N, N));
-		init = list(init, r);
-	}
-
-	// run the select
-	setlineno(sel);
-	init = list(init, mkcall("selectgo", T, nil, var));
-	sel->nbody = init;
-
-out:
-	sel->list = nil;
-	walkstmtlist(sel->nbody);
-	lineno = lno;
-}
-
-// Keep in sync with src/runtime/chan.h.
-static Type*
-selecttype(int32 size)
-{
-	Node *sel, *sudog, *scase, *arr;
-
-	// TODO(dvyukov): it's possible to generate SudoG and Scase only once
-	// and then cache; and also cache Select per size.
-	sudog = nod(OTSTRUCT, N, N);
-	sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("g")), typenod(ptrto(types[TUINT8]))));
-	sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("selectdone")), typenod(ptrto(types[TUINT8]))));
-	sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("link")), typenod(ptrto(types[TUINT8]))));
-	sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("prev")), typenod(ptrto(types[TUINT8]))));
-	sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("elem")), typenod(ptrto(types[TUINT8]))));
-	sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("releasetime")), typenod(types[TUINT64])));
-	sudog->list = list(sudog->list, nod(ODCLFIELD, newname(lookup("nrelease")), typenod(types[TINT32])));
-	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;
-
-	scase = nod(OTSTRUCT, N, N);
-	scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("elem")), typenod(ptrto(types[TUINT8]))));
-	scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("chan")), typenod(ptrto(types[TUINT8]))));
-	scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("pc")), typenod(types[TUINTPTR])));
-	scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("kind")), typenod(types[TUINT16])));
-	scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("so")), typenod(types[TUINT16])));
-	scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("receivedp")), typenod(ptrto(types[TUINT8]))));
-	scase->list = list(scase->list, nod(ODCLFIELD, newname(lookup("releasetime")), typenod(types[TUINT64])));
-	typecheck(&scase, Etype);
-	scase->type->noalg = 1;
-	scase->type->local = 1;
-
-	sel = nod(OTSTRUCT, N, N);
-	sel->list = list(sel->list, nod(ODCLFIELD, newname(lookup("tcase")), typenod(types[TUINT16])));
-	sel->list = list(sel->list, nod(ODCLFIELD, newname(lookup("ncase")), typenod(types[TUINT16])));
-	sel->list = list(sel->list, nod(ODCLFIELD, newname(lookup("pollorder")), typenod(ptrto(types[TUINT8]))));
-	sel->list = list(sel->list, nod(ODCLFIELD, newname(lookup("lockorder")), typenod(ptrto(types[TUINT8]))));
-	arr = nod(OTARRAY, nodintconst(size), scase);
-	sel->list = list(sel->list, nod(ODCLFIELD, newname(lookup("scase")), arr));
-	arr = nod(OTARRAY, nodintconst(size), typenod(ptrto(types[TUINT8])));
-	sel->list = list(sel->list, nod(ODCLFIELD, newname(lookup("lockorderarr")), arr));
-	arr = nod(OTARRAY, nodintconst(size), typenod(types[TUINT16]));
-	sel->list = list(sel->list, nod(ODCLFIELD, newname(lookup("pollorderarr")), arr));
-	typecheck(&sel, Etype);
-	sel->type->noalg = 1;
-	sel->type->local = 1;
-
-	return sel->type;
-}
diff --git a/src/cmd/gc/sinit.c b/src/cmd/gc/sinit.c
deleted file mode 100644
index 8ad7ae7..0000000
--- a/src/cmd/gc/sinit.c
+++ /dev/null
@@ -1,1505 +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.
-
-/*
- * static initialization
- */
-
-#include	<u.h>
-#include	<libc.h>
-#include	"go.h"
-
-enum
-{
-	InitNotStarted = 0,
-	InitDone = 1,
-	InitPending = 2,
-};
-
-static void initplan(Node*);
-static NodeList *initlist;
-static void init2(Node*, NodeList**);
-static void init2list(NodeList*, NodeList**);
-static int staticinit(Node*, NodeList**);
-static Node *staticname(Type*, int);
-
-// init1 walks the AST starting at n, and accumulates in out
-// the list of definitions needing init code in dependency order.
-static void
-init1(Node *n, NodeList **out)
-{
-	NodeList *l;
-	Node *nv;
-
-	if(n == N)
-		return;
-	init1(n->left, out);
-	init1(n->right, out);
-	for(l=n->list; l; l=l->next)
-		init1(l->n, out);
-
-	if(n->left && n->type && n->left->op == OTYPE && n->class == PFUNC) {
-		// Methods called as Type.Method(receiver, ...).
-		// Definitions for method expressions are stored in type->nname.
-		init1(n->type->nname, out);
-	}
-
-	if(n->op != ONAME)
-		return;
-	switch(n->class) {
-	case PEXTERN:
-	case PFUNC:
-		break;
-	default:
-		if(isblank(n) && n->curfn == N && n->defn != N && n->defn->initorder == InitNotStarted) {
-			// blank names initialization is part of init() but not
-			// when they are inside a function.
-			break;
-		}
-		return;
-	}
-
-	if(n->initorder == InitDone)
-		return;
-	if(n->initorder == InitPending) {
-		// Since mutually recursive sets of functions are allowed,
-		// we don't necessarily raise an error if n depends on a node
-		// which is already waiting for its dependencies to be visited.
-		//
-		// initlist contains a cycle of identifiers referring to each other.
-		// If this cycle contains a variable, then this variable refers to itself.
-		// Conversely, if there exists an initialization cycle involving
-		// a variable in the program, the tree walk will reach a cycle
-		// involving that variable.
-		if(n->class != PFUNC) {
-			nv = n;
-			goto foundinitloop;
-		}
-		for(l=initlist; l->n!=n; l=l->next) {
-			if(l->n->class != PFUNC) {
-				nv = l->n;
-				goto foundinitloop;
-			}
-		}
-		// The loop involves only functions, ok.
-		return;
-
-	foundinitloop:
-		// if there have already been errors printed,
-		// those errors probably confused us and
-		// there might not be a loop.  let the user
-		// fix those first.
-		flusherrors();
-		if(nerrors > 0)
-			errorexit();
-
-		// There is a loop involving nv. We know about
-		// n and initlist = n1 <- ... <- nv <- ... <- n <- ...
-		print("%L: initialization loop:\n", nv->lineno);
-		// Build back pointers in initlist.
-		for(l=initlist; l; l=l->next)
-			if(l->next != nil)
-				l->next->end = l;
-		// Print nv -> ... -> n1 -> n.
-		for(l=initlist; l->n!=nv; l=l->next);
-		for(; l; l=l->end)
-			print("\t%L %S refers to\n", l->n->lineno, l->n->sym);
-		// Print n -> ... -> nv.
-		for(l=initlist; l->n!=n; l=l->next);
-		for(; l->n != nv; l=l->end)
-			print("\t%L %S refers to\n", l->n->lineno, l->n->sym);
-		print("\t%L %S\n", nv->lineno, nv->sym);
-		errorexit();
-	}
-
-	// reached a new unvisited node.
-	n->initorder = InitPending;
-	l = malloc(sizeof *l);
-	if(l == nil) {
-		flusherrors();
-		yyerror("out of memory");
-		errorexit();
-	}
-	l->next = initlist;
-	l->n = n;
-	l->end = nil;
-	initlist = l;
-
-	// make sure that everything n depends on is initialized.
-	// n->defn is an assignment to n
-	if(n->defn != N) {
-		switch(n->defn->op) {
-		default:
-			goto bad;
-
-		case ODCLFUNC:
-			init2list(n->defn->nbody, out);
-			break;
-
-		case OAS:
-			if(n->defn->left != n)
-				goto bad;
-			if(isblank(n->defn->left) && candiscard(n->defn->right)) {
-				n->defn->op = OEMPTY;
-				n->defn->left = N;
-				n->defn->right = N;
-				break;
-			}
-
-			init2(n->defn->right, out);
-			if(debug['j'])
-				print("%S\n", n->sym);
-			if(isblank(n) || !staticinit(n, out)) {
-				if(debug['%'])
-					dump("nonstatic", n->defn);
-				*out = list(*out, n->defn);
-			}
-			break;
-
-		case OAS2FUNC:
-		case OAS2MAPR:
-		case OAS2DOTTYPE:
-		case OAS2RECV:
-			if(n->defn->initorder != InitNotStarted)
-				break;
-			n->defn->initorder = InitDone;
-			for(l=n->defn->rlist; l; l=l->next)
-				init1(l->n, out);
-			if(debug['%']) dump("nonstatic", n->defn);
-			*out = list(*out, n->defn);
-			break;
-		}
-	}
-	l = initlist;
-	initlist = l->next;
-	if(l->n != n)
-		fatal("bad initlist");
-	free(l);
-	n->initorder = InitDone;
-	return;
-
-bad:
-	dump("defn", n->defn);
-	fatal("init1: bad defn");
-}
-
-// recurse over n, doing init1 everywhere.
-static void
-init2(Node *n, NodeList **out)
-{
-	if(n == N || n->initorder == InitDone)
-		return;
-
-	if(n->op == ONAME && n->ninit)
-		fatal("name %S with ninit: %+N\n", n->sym, n);
-
-	init1(n, out);
-	init2(n->left, out);
-	init2(n->right, out);
-	init2(n->ntest, out);
-	init2list(n->ninit, out);
-	init2list(n->list, out);
-	init2list(n->rlist, out);
-	init2list(n->nbody, out);
-	init2list(n->nelse, out);
-	
-	if(n->op == OCLOSURE)
-		init2list(n->closure->nbody, out);
-	if(n->op == ODOTMETH || n->op == OCALLPART)
-		init2(n->type->nname, out);
-}
-
-static void
-init2list(NodeList *l, NodeList **out)
-{
-	for(; l; l=l->next)
-		init2(l->n, out);
-}
-
-static void
-initreorder(NodeList *l, NodeList **out)
-{
-	Node *n;
-
-	for(; l; l=l->next) {
-		n = l->n;
-		switch(n->op) {
-		case ODCLFUNC:
-		case ODCLCONST:
-		case ODCLTYPE:
-			continue;
-		}
-		initreorder(n->ninit, out);
-		n->ninit = nil;
-		init1(n, out);
-	}
-}
-
-// initfix computes initialization order for a list l of top-level
-// declarations and outputs the corresponding list of statements
-// to include in the init() function body.
-NodeList*
-initfix(NodeList *l)
-{
-	NodeList *lout;
-	int lno;
-
-	lout = nil;
-	lno = lineno;
-	initreorder(l, &lout);
-	lineno = lno;
-	return lout;
-}
-
-/*
- * compilation of top-level (static) assignments
- * into DATA statements if at all possible.
- */
-
-static int staticassign(Node*, Node*, NodeList**);
-
-static int
-staticinit(Node *n, NodeList **out)
-{
-	Node *l, *r;
-
-	if(n->op != ONAME || n->class != PEXTERN || n->defn == N || n->defn->op != OAS)
-		fatal("staticinit");
-
-	lineno = n->lineno;
-	l = n->defn->left;
-	r = n->defn->right;
-	return staticassign(l, r, out);
-}
-
-// like staticassign but we are copying an already
-// initialized value r.
-static int
-staticcopy(Node *l, Node *r, NodeList **out)
-{
-	int i;
-	InitEntry *e;
-	InitPlan *p;
-	Node *a, *ll, *rr, *orig, n1;
-
-	if(r->op != ONAME || r->class != PEXTERN || r->sym->pkg != localpkg)
-		return 0;
-	if(r->defn == N)	// probably zeroed but perhaps supplied externally and of unknown value
-		return 0;
-	if(r->defn->op != OAS)
-		return 0;
-	orig = r;
-	r = r->defn->right;
-	
-	switch(r->op) {
-	case ONAME:
-		if(staticcopy(l, r, out))
-			return 1;
-		*out = list(*out, nod(OAS, l, r));
-		return 1;
-	
-	case OLITERAL:
-		if(iszero(r))
-			return 1;
-		gdata(l, r, l->type->width);
-		return 1;
-
-	case OADDR:
-		switch(r->left->op) {
-		case ONAME:
-			gdata(l, r, l->type->width);
-			return 1;
-		}
-		break;
-	
-	case OPTRLIT:
-		switch(r->left->op) {
-		default:
-			//dump("not static addr", r);
-			break;
-		case OARRAYLIT:
-		case OSTRUCTLIT:
-		case OMAPLIT:
-			// copy pointer
-			gdata(l, nod(OADDR, r->nname, N), l->type->width);
-			return 1;
-		}
-		break;
-
-	case OARRAYLIT:
-		if(isslice(r->type)) {
-			// copy slice
-			a = r->nname;
-			n1 = *l;
-			n1.xoffset = l->xoffset + Array_array;
-			gdata(&n1, nod(OADDR, a, N), widthptr);
-			n1.xoffset = l->xoffset + Array_nel;
-			gdata(&n1, r->right, widthint);
-			n1.xoffset = l->xoffset + Array_cap;
-			gdata(&n1, r->right, widthint);
-			return 1;
-		}
-		// fall through
-	case OSTRUCTLIT:
-		p = r->initplan;
-		n1 = *l;
-		for(i=0; i<p->len; i++) {
-			e = &p->e[i];
-			n1.xoffset = l->xoffset + e->xoffset;
-			n1.type = e->expr->type;
-			if(e->expr->op == OLITERAL)
-				gdata(&n1, e->expr, n1.type->width);
-			else {
-				ll = nod(OXXX, N, N);
-				*ll = n1;
-				ll->orig = ll; // completely separate copy
-				if(!staticassign(ll, e->expr, out)) {
-					// Requires computation, but we're
-					// copying someone else's computation.
-					rr = nod(OXXX, N, N);
-					*rr = *orig;
-					rr->orig = rr; // completely separate copy
-					rr->type = ll->type;
-					rr->xoffset += e->xoffset;
-					*out = list(*out, nod(OAS, ll, rr));
-				}
-			}
-		}
-		return 1;
-	}
-	return 0;
-}
-
-static int
-staticassign(Node *l, Node *r, NodeList **out)
-{
-	Node *a, n1;
-	Type *ta;
-	InitPlan *p;
-	InitEntry *e;
-	int i;
-	Strlit *sval;
-	
-	switch(r->op) {
-	default:
-		//dump("not static", r);
-		break;
-	
-	case ONAME:
-		if(r->class == PEXTERN && r->sym->pkg == localpkg)
-			return staticcopy(l, r, out);
-		break;
-
-	case OLITERAL:
-		if(iszero(r))
-			return 1;
-		gdata(l, r, l->type->width);
-		return 1;
-
-	case OADDR:
-		switch(r->left->op) {
-		default:
-			//dump("not static addr", r);
-			break;
-
-		case ONAME:
-			gdata(l, r, l->type->width);
-			return 1;
-		}
-	
-	case OPTRLIT:
-		switch(r->left->op) {
-		default:
-			//dump("not static ptrlit", r);
-			break;
-
-		case OARRAYLIT:
-		case OMAPLIT:
-		case OSTRUCTLIT:
-			// Init pointer.
-			a = staticname(r->left->type, 1);
-			r->nname = a;
-			gdata(l, nod(OADDR, a, N), l->type->width);
-			// Init underlying literal.
-			if(!staticassign(a, r->left, out))
-				*out = list(*out, nod(OAS, a, r->left));
-			return 1;
-		}
-		break;
-
-	case OSTRARRAYBYTE:
-		if(l->class == PEXTERN && r->left->op == OLITERAL) {
-			sval = r->left->val.u.sval;
-			slicebytes(l, sval->s, sval->len);
-			return 1;
-		}
-		break;
-
-	case OARRAYLIT:
-		initplan(r);
-		if(isslice(r->type)) {
-			// Init slice.
-			ta = typ(TARRAY);
-			ta->type = r->type->type;
-			ta->bound = mpgetfix(r->right->val.u.xval);
-			a = staticname(ta, 1);
-			r->nname = a;
-			n1 = *l;
-			n1.xoffset = l->xoffset + Array_array;
-			gdata(&n1, nod(OADDR, a, N), widthptr);
-			n1.xoffset = l->xoffset + Array_nel;
-			gdata(&n1, r->right, widthint);
-			n1.xoffset = l->xoffset + Array_cap;
-			gdata(&n1, r->right, widthint);
-			// Fall through to init underlying array.
-			l = a;
-		}
-		// fall through
-	case OSTRUCTLIT:
-		initplan(r);
-		p = r->initplan;
-		n1 = *l;
-		for(i=0; i<p->len; i++) {
-			e = &p->e[i];
-			n1.xoffset = l->xoffset + e->xoffset;
-			n1.type = e->expr->type;
-			if(e->expr->op == OLITERAL)
-				gdata(&n1, e->expr, n1.type->width);
-			else {
-				a = nod(OXXX, N, N);
-				*a = n1;
-				a->orig = a; // completely separate copy
-				if(!staticassign(a, e->expr, out))
-					*out = list(*out, nod(OAS, a, e->expr));
-			}
-		}
-		return 1;
-
-	case OMAPLIT:
-		// TODO: Table-driven map insert.
-		break;
-	}
-	return 0;
-}
-
-/*
- * from here down is the walk analysis
- * of composite literals.
- * most of the work is to generate
- * data statements for the constant
- * part of the composite literal.
- */
-
-static	void	structlit(int ctxt, int pass, Node *n, Node *var, NodeList **init);
-static	void	arraylit(int ctxt, int pass, Node *n, Node *var, NodeList **init);
-static	void	slicelit(int ctxt, Node *n, Node *var, NodeList **init);
-static	void	maplit(int ctxt, Node *n, Node *var, NodeList **init);
-
-static Node*
-staticname(Type *t, int ctxt)
-{
-	Node *n;
-
-	snprint(namebuf, sizeof(namebuf), "statictmp_%.4d", statuniqgen);
-	statuniqgen++;
-	n = newname(lookup(namebuf));
-	if(!ctxt)
-		n->readonly = 1;
-	addvar(n, t, PEXTERN);
-	return n;
-}
-
-static int
-isliteral(Node *n)
-{
-	if(n->op == OLITERAL)
-		if(n->val.ctype != CTNIL)
-			return 1;
-	return 0;
-}
-
-static int
-simplename(Node *n)
-{
-	if(n->op != ONAME)
-		goto no;
-	if(!n->addable)
-		goto no;
-	if(n->class & PHEAP)
-		goto no;
-	if(n->class == PPARAMREF)
-		goto no;
-	return 1;
-
-no:
-	return 0;
-}
-
-static void
-litas(Node *l, Node *r, NodeList **init)
-{
-	Node *a;
-
-	a = nod(OAS, l, r);
-	typecheck(&a, Etop);
-	walkexpr(&a, init);
-	*init = list(*init, a);
-}
-
-enum
-{
-	MODEDYNAM	= 1,
-	MODECONST	= 2,
-};
-
-static int
-getdyn(Node *n, int top)
-{
-	NodeList *nl;
-	Node *value;
-	int mode;
-
-	mode = 0;
-	switch(n->op) {
-	default:
-		if(isliteral(n))
-			return MODECONST;
-		return MODEDYNAM;
-	case OARRAYLIT:
-		if(!top && n->type->bound < 0)
-			return MODEDYNAM;
-	case OSTRUCTLIT:
-		break;
-	}
-
-	for(nl=n->list; nl; nl=nl->next) {
-		value = nl->n->right;
-		mode |= getdyn(value, 0);
-		if(mode == (MODEDYNAM|MODECONST))
-			break;
-	}
-	return mode;
-}
-
-static void
-structlit(int ctxt, int pass, Node *n, Node *var, NodeList **init)
-{
-	Node *r, *a;
-	NodeList *nl;
-	Node *index, *value;
-
-	for(nl=n->list; nl; nl=nl->next) {
-		r = nl->n;
-		if(r->op != OKEY)
-			fatal("structlit: rhs not OKEY: %N", r);
-		index = r->left;
-		value = r->right;
-
-		switch(value->op) {
-		case OARRAYLIT:
-			if(value->type->bound < 0) {
-				if(pass == 1 && ctxt != 0) {
-					a = nod(ODOT, var, newname(index->sym));
-					slicelit(ctxt, value, a, init);
-				} else
-				if(pass == 2 && ctxt == 0) {
-					a = nod(ODOT, var, newname(index->sym));
-					slicelit(ctxt, value, a, init);
-				} else
-				if(pass == 3)
-					break;
-				continue;
-			}
-			a = nod(ODOT, var, newname(index->sym));
-			arraylit(ctxt, pass, value, a, init);
-			continue;
-
-		case OSTRUCTLIT:
-			a = nod(ODOT, var, newname(index->sym));
-			structlit(ctxt, pass, value, a, init);
-			continue;
-		}
-
-		if(isliteral(value)) {
-			if(pass == 2)
-				continue;
-		} else
-			if(pass == 1)
-				continue;
-
-		// build list of var.field = expr
-		a = nod(ODOT, var, newname(index->sym));
-		a = nod(OAS, a, value);
-		typecheck(&a, Etop);
-		if(pass == 1) {
-			walkexpr(&a, init);	// add any assignments in r to top
-			if(a->op != OAS)
-				fatal("structlit: not as");
-			a->dodata = 2;
-		} else {
-			orderstmtinplace(&a);
-			walkstmt(&a);
-		}
-		*init = list(*init, a);
-	}
-}
-
-static void
-arraylit(int ctxt, int pass, Node *n, Node *var, NodeList **init)
-{
-	Node *r, *a;
-	NodeList *l;
-	Node *index, *value;
-
-	for(l=n->list; l; l=l->next) {
-		r = l->n;
-		if(r->op != OKEY)
-			fatal("arraylit: rhs not OKEY: %N", r);
-		index = r->left;
-		value = r->right;
-
-		switch(value->op) {
-		case OARRAYLIT:
-			if(value->type->bound < 0) {
-				if(pass == 1 && ctxt != 0) {
-					a = nod(OINDEX, var, index);
-					slicelit(ctxt, value, a, init);
-				} else
-				if(pass == 2 && ctxt == 0) {
-					a = nod(OINDEX, var, index);
-					slicelit(ctxt, value, a, init);
-				} else
-				if(pass == 3)
-					break;
-				continue;
-			}
-			a = nod(OINDEX, var, index);
-			arraylit(ctxt, pass, value, a, init);
-			continue;
-
-		case OSTRUCTLIT:
-			a = nod(OINDEX, var, index);
-			structlit(ctxt, pass, value, a, init);
-			continue;
-		}
-
-		if(isliteral(index) && isliteral(value)) {
-			if(pass == 2)
-				continue;
-		} else
-			if(pass == 1)
-				continue;
-
-		// build list of var[index] = value
-		a = nod(OINDEX, var, index);
-		a = nod(OAS, a, value);
-		typecheck(&a, Etop);
-		if(pass == 1) {
-			walkexpr(&a, init);
-			if(a->op != OAS)
-				fatal("arraylit: not as");
-			a->dodata = 2;
-		} else {
-			orderstmtinplace(&a);
-			walkstmt(&a);
-		}
-		*init = list(*init, a);
-	}
-}
-
-static void
-slicelit(int ctxt, Node *n, Node *var, NodeList **init)
-{
-	Node *r, *a;
-	NodeList *l;
-	Type *t;
-	Node *vstat, *vauto;
-	Node *index, *value;
-	int mode;
-
-	// make an array type
-	t = shallow(n->type);
-	t->bound = mpgetfix(n->right->val.u.xval);
-	t->width = 0;
-	t->sym = nil;
-	t->haspointers = 0;
-	dowidth(t);
-
-	if(ctxt != 0) {
-		// put everything into static array
-		vstat = staticname(t, ctxt);
-		arraylit(ctxt, 1, n, vstat, init);
-		arraylit(ctxt, 2, n, vstat, init);
-
-		// copy static to slice
-		a = nod(OSLICE, vstat, nod(OKEY, N, N));
-		a = nod(OAS, var, a);
-		typecheck(&a, Etop);
-		a->dodata = 2;
-		*init = list(*init, a);
-		return;
-	}
-
-	// recipe for var = []t{...}
-	// 1. make a static array
-	//	var vstat [...]t
-	// 2. assign (data statements) the constant part
-	//	vstat = constpart{}
-	// 3. make an auto pointer to array and allocate heap to it
-	//	var vauto *[...]t = new([...]t)
-	// 4. copy the static array to the auto array
-	//	*vauto = vstat
-	// 5. assign slice of allocated heap to var
-	//	var = [0:]*auto
-	// 6. for each dynamic part assign to the slice
-	//	var[i] = dynamic part
-	//
-	// an optimization is done if there is no constant part
-	//	3. var vauto *[...]t = new([...]t)
-	//	5. var = [0:]*auto
-	//	6. var[i] = dynamic part
-
-	// if the literal contains constants,
-	// make static initialized array (1),(2)
-	vstat = N;
-	mode = getdyn(n, 1);
-	if(mode & MODECONST) {
-		vstat = staticname(t, ctxt);
-		arraylit(ctxt, 1, n, vstat, init);
-	}
-
-	// make new auto *array (3 declare)
-	vauto = temp(ptrto(t));
-
-	// set auto to point at new temp or heap (3 assign)
-	if(n->alloc != N) {
-		// temp allocated during order.c for dddarg
-		n->alloc->type = t;
-		if(vstat == N) {
-			a = nod(OAS, n->alloc, N);
-			typecheck(&a, Etop);
-			*init = list(*init, a);  // zero new temp
-		}
-		a = nod(OADDR, n->alloc, N);
-	} else if(n->esc == EscNone) {
-		a = temp(t);
-		if(vstat == N) {
-			a = nod(OAS, temp(t), N);
-			typecheck(&a, Etop);
-			*init = list(*init, a);  // zero new temp
-			a = a->left;
-		}
-		a = nod(OADDR, a, N);
-	} else {
-		a = nod(ONEW, N, N);
-		a->list = list1(typenod(t));
-	}
-	a = nod(OAS, vauto, a);
-	typecheck(&a, Etop);
-	walkexpr(&a, init);
-	*init = list(*init, a);
-
-	if(vstat != N) {
-		// copy static to heap (4)
-		a = nod(OIND, vauto, N);
-		a = nod(OAS, a, vstat);
-		typecheck(&a, Etop);
-		walkexpr(&a, init);
-		*init = list(*init, a);
-	}
-
-	// make slice out of heap (5)
-	a = nod(OAS, var, nod(OSLICE, vauto, nod(OKEY, N, N)));
-	typecheck(&a, Etop);
-	orderstmtinplace(&a);
-	walkstmt(&a);
-	*init = list(*init, a);
-
-	// put dynamics into slice (6)
-	for(l=n->list; l; l=l->next) {
-		r = l->n;
-		if(r->op != OKEY)
-			fatal("slicelit: rhs not OKEY: %N", r);
-		index = r->left;
-		value = r->right;
-		a = nod(OINDEX, var, index);
-		a->bounded = 1;
-		// TODO need to check bounds?
-
-		switch(value->op) {
-		case OARRAYLIT:
-			if(value->type->bound < 0)
-				break;
-			arraylit(ctxt, 2, value, a, init);
-			continue;
-
-		case OSTRUCTLIT:
-			structlit(ctxt, 2, value, a, init);
-			continue;
-		}
-
-		if(isliteral(index) && isliteral(value))
-			continue;
-
-		// build list of var[c] = expr
-		a = nod(OAS, a, value);
-		typecheck(&a, Etop);
-		orderstmtinplace(&a);
-		walkstmt(&a);
-		*init = list(*init, a);
-	}
-}
-
-static void
-maplit(int ctxt, Node *n, Node *var, NodeList **init)
-{
-	Node *r, *a;
-	NodeList *l;
-	int nerr;
-	int64 b;
-	Type *t, *tk, *tv, *t1;
-	Node *vstat, *index, *value, *key, *val;
-	Sym *syma, *symb;
-
-USED(ctxt);
-ctxt = 0;
-
-	// make the map var
-	nerr = nerrors;
-
-	a = nod(OMAKE, N, N);
-	a->list = list1(typenod(n->type));
-	litas(var, a, init);
-
-	// count the initializers
-	b = 0;
-	for(l=n->list; l; l=l->next) {
-		r = l->n;
-
-		if(r->op != OKEY)
-			fatal("maplit: rhs not OKEY: %N", r);
-		index = r->left;
-		value = r->right;
-
-		if(isliteral(index) && isliteral(value))
-			b++;
-	}
-
-	if(b != 0) {
-		// build type [count]struct { a Tindex, b Tvalue }
-		t = n->type;
-		tk = t->down;
-		tv = t->type;
-
-		symb = lookup("b");
-		t = typ(TFIELD);
-		t->type = tv;
-		t->sym = symb;
-
-		syma = lookup("a");
-		t1 = t;
-		t = typ(TFIELD);
-		t->type = tk;
-		t->sym = syma;
-		t->down = t1;
-
-		t1 = t;
-		t = typ(TSTRUCT);
-		t->type = t1;
-
-		t1 = t;
-		t = typ(TARRAY);
-		t->bound = b;
-		t->type = t1;
-
-		dowidth(t);
-
-		// make and initialize static array
-		vstat = staticname(t, ctxt);
-		b = 0;
-		for(l=n->list; l; l=l->next) {
-			r = l->n;
-
-			if(r->op != OKEY)
-				fatal("maplit: rhs not OKEY: %N", r);
-			index = r->left;
-			value = r->right;
-
-			if(isliteral(index) && isliteral(value)) {
-				// build vstat[b].a = key;
-				a = nodintconst(b);
-				a = nod(OINDEX, vstat, a);
-				a = nod(ODOT, a, newname(syma));
-				a = nod(OAS, a, index);
-				typecheck(&a, Etop);
-				walkexpr(&a, init);
-				a->dodata = 2;
-				*init = list(*init, a);
-
-				// build vstat[b].b = value;
-				a = nodintconst(b);
-				a = nod(OINDEX, vstat, a);
-				a = nod(ODOT, a, newname(symb));
-				a = nod(OAS, a, value);
-				typecheck(&a, Etop);
-				walkexpr(&a, init);
-				a->dodata = 2;
-				*init = list(*init, a);
-
-				b++;
-			}
-		}
-
-		// loop adding structure elements to map
-		// for i = 0; i < len(vstat); i++ {
-		//	map[vstat[i].a] = vstat[i].b
-		// }
-		index = temp(types[TINT]);
-
-		a = nod(OINDEX, vstat, index);
-		a->bounded = 1;
-		a = nod(ODOT, a, newname(symb));
-
-		r = nod(OINDEX, vstat, index);
-		r->bounded = 1;
-		r = nod(ODOT, r, newname(syma));
-		r = nod(OINDEX, var, r);
-
-		r = nod(OAS, r, a);
-
-		a = nod(OFOR, N, N);
-		a->nbody = list1(r);
-
-		a->ninit = list1(nod(OAS, index, nodintconst(0)));
-		a->ntest = nod(OLT, index, nodintconst(t->bound));
-		a->nincr = nod(OAS, index, nod(OADD, index, nodintconst(1)));
-
-		typecheck(&a, Etop);
-		walkstmt(&a);
-		*init = list(*init, a);
-	}
-
-	// put in dynamic entries one-at-a-time
-	key = nil;
-	val = nil;
-	for(l=n->list; l; l=l->next) {
-		r = l->n;
-
-		if(r->op != OKEY)
-			fatal("maplit: rhs not OKEY: %N", r);
-		index = r->left;
-		value = r->right;
-
-		if(isliteral(index) && isliteral(value))
-			continue;
-			
-		// build list of var[c] = expr.
-		// use temporary so that mapassign1 can have addressable key, val.
-		if(key == nil) {
-			key = temp(var->type->down);
-			val = temp(var->type->type);
-		}
-		a = nod(OAS, key, r->left);
-		typecheck(&a, Etop);
-		walkstmt(&a);
-		*init = list(*init, a);
-		a = nod(OAS, val, r->right);
-		typecheck(&a, Etop);
-		walkstmt(&a);
-		*init = list(*init, a);
-
-		a = nod(OAS, nod(OINDEX, var, key), val);
-		typecheck(&a, Etop);
-		walkstmt(&a);
-		*init = list(*init, a);
-
-		if(nerr != nerrors)
-			break;
-	}
-	
-	if(key != nil) {
-		a = nod(OVARKILL, key, N);
-		typecheck(&a, Etop);
-		*init = list(*init, a);
-		a = nod(OVARKILL, val, N);
-		typecheck(&a, Etop);
-		*init = list(*init, a);
-	}
-}
-
-void
-anylit(int ctxt, Node *n, Node *var, NodeList **init)
-{
-	Type *t;
-	Node *a, *vstat, *r;
-
-	t = n->type;
-	switch(n->op) {
-	default:
-		fatal("anylit: not lit");
-
-	case OPTRLIT:
-		if(!isptr[t->etype])
-			fatal("anylit: not ptr");
-
-		if(n->right != N) {
-			r = nod(OADDR, n->right, N);
-			typecheck(&r, Erv);
-		} else {
-			r = nod(ONEW, N, N);
-			r->typecheck = 1;
-			r->type = t;
-			r->esc = n->esc;
-		}
-		walkexpr(&r, init);
-		a = nod(OAS, var, r);
-
-		typecheck(&a, Etop);
-		*init = list(*init, a);
-
-		var = nod(OIND, var, N);
-		typecheck(&var, Erv | Easgn);
-		anylit(ctxt, n->left, var, init);
-		break;
-
-	case OSTRUCTLIT:
-		if(t->etype != TSTRUCT)
-			fatal("anylit: not struct");
-
-		if(simplename(var) && count(n->list) > 4) {
-
-			if(ctxt == 0) {
-				// lay out static data
-				vstat = staticname(t, ctxt);
-				structlit(ctxt, 1, n, vstat, init);
-
-				// copy static to var
-				a = nod(OAS, var, vstat);
-				typecheck(&a, Etop);
-				walkexpr(&a, init);
-				*init = list(*init, a);
-
-				// add expressions to automatic
-				structlit(ctxt, 2, n, var, init);
-				break;
-			}
-			structlit(ctxt, 1, n, var, init);
-			structlit(ctxt, 2, n, var, init);
-			break;
-		}
-
-		// initialize of not completely specified
-		if(simplename(var) || count(n->list) < structcount(t)) {
-			a = nod(OAS, var, N);
-			typecheck(&a, Etop);
-			walkexpr(&a, init);
-			*init = list(*init, a);
-		}
-		structlit(ctxt, 3, n, var, init);
-		break;
-
-	case OARRAYLIT:
-		if(t->etype != TARRAY)
-			fatal("anylit: not array");
-		if(t->bound < 0) {
-			slicelit(ctxt, n, var, init);
-			break;
-		}
-
-		if(simplename(var) && count(n->list) > 4) {
-
-			if(ctxt == 0) {
-				// lay out static data
-				vstat = staticname(t, ctxt);
-				arraylit(1, 1, n, vstat, init);
-
-				// copy static to automatic
-				a = nod(OAS, var, vstat);
-				typecheck(&a, Etop);
-				walkexpr(&a, init);
-				*init = list(*init, a);
-
-				// add expressions to automatic
-				arraylit(ctxt, 2, n, var, init);
-				break;
-			}
-			arraylit(ctxt, 1, n, var, init);
-			arraylit(ctxt, 2, n, var, init);
-			break;
-		}
-
-		// initialize of not completely specified
-		if(simplename(var) || count(n->list) < t->bound) {
-			a = nod(OAS, var, N);
-			typecheck(&a, Etop);
-			walkexpr(&a, init);
-			*init = list(*init, a);
-		}
-		arraylit(ctxt, 3, n, var, init);
-		break;
-
-	case OMAPLIT:
-		if(t->etype != TMAP)
-			fatal("anylit: not map");
-		maplit(ctxt, n, var, init);
-		break;
-	}
-}
-
-int
-oaslit(Node *n, NodeList **init)
-{
-	int ctxt;
-
-	if(n->left == N || n->right == N)
-		goto no;
-	if(n->left->type == T || n->right->type == T)
-		goto no;
-	if(!simplename(n->left))
-		goto no;
-	if(!eqtype(n->left->type, n->right->type))
-		goto no;
-
-	// context is init() function.
-	// implies generated data executed
-	// exactly once and not subject to races.
-	ctxt = 0;
-//	if(n->dodata == 1)
-//		ctxt = 1;
-
-	switch(n->right->op) {
-	default:
-		goto no;
-
-	case OSTRUCTLIT:
-	case OARRAYLIT:
-	case OMAPLIT:
-		if(vmatch1(n->left, n->right))
-			goto no;
-		anylit(ctxt, n->right, n->left, init);
-		break;
-	}
-	n->op = OEMPTY;
-	return 1;
-
-no:
-	// not a special composit literal assignment
-	return 0;
-}
-
-static int
-getlit(Node *lit)
-{
-	if(smallintconst(lit))
-		return mpgetfix(lit->val.u.xval);
-	return -1;
-}
-
-int
-stataddr(Node *nam, Node *n)
-{
-	int l;
-
-	if(n == N)
-		goto no;
-
-	switch(n->op) {
-
-	case ONAME:
-		*nam = *n;
-		return n->addable;
-
-	case ODOT:
-		if(!stataddr(nam, n->left))
-			break;
-		nam->xoffset += n->xoffset;
-		nam->type = n->type;
-		return 1;
-
-	case OINDEX:
-		if(n->left->type->bound < 0)
-			break;
-		if(!stataddr(nam, n->left))
-			break;
-		l = getlit(n->right);
-		if(l < 0)
-			break;
-		// Check for overflow.
-		if(n->type->width != 0 && MAXWIDTH/n->type->width <= l)
-			break;
- 		nam->xoffset += l*n->type->width;
-		nam->type = n->type;
-		return 1;
-	}
-
-no:
-	return 0;
-}
-
-int
-gen_as_init(Node *n)
-{
-	Node *nr, *nl;
-	Node nam, nod1;
-
-	if(n->dodata == 0)
-		goto no;
-
-	nr = n->right;
-	nl = n->left;
-	if(nr == N) {
-		if(!stataddr(&nam, nl))
-			goto no;
-		if(nam.class != PEXTERN)
-			goto no;
-		goto yes;
-	}
-
-	if(nr->type == T || !eqtype(nl->type, nr->type))
-		goto no;
-
-	if(!stataddr(&nam, nl))
-		goto no;
-
-	if(nam.class != PEXTERN)
-		goto no;
-
-	switch(nr->op) {
-	default:
-		goto no;
-
-	case OCONVNOP:
-		nr = nr->left;
-		if(nr == N || nr->op != OSLICEARR)
-			goto no;
-		// fall through
-	
-	case OSLICEARR:
-		if(nr->right->op == OKEY && nr->right->left == N && nr->right->right == N) {
-			nr = nr->left;
-			goto slice;
-		}
-		goto no;
-
-	case OLITERAL:
-		break;
-	}
-
-	switch(nr->type->etype) {
-	default:
-		goto no;
-
-	case TBOOL:
-	case TINT8:
-	case TUINT8:
-	case TINT16:
-	case TUINT16:
-	case TINT32:
-	case TUINT32:
-	case TINT64:
-	case TUINT64:
-	case TINT:
-	case TUINT:
-	case TUINTPTR:
-	case TPTR32:
-	case TPTR64:
-	case TFLOAT32:
-	case TFLOAT64:
-		gdata(&nam, nr, nr->type->width);
-		break;
-
-	case TCOMPLEX64:
-	case TCOMPLEX128:
-		gdatacomplex(&nam, nr->val.u.cval);
-		break;
-
-	case TSTRING:
-		gdatastring(&nam, nr->val.u.sval);
-		break;
-	}
-
-yes:
-	return 1;
-
-slice:
-	gused(N); // in case the data is the dest of a goto
-	nl = nr;
-	if(nr == N || nr->op != OADDR)
-		goto no;
-	nr = nr->left;
-	if(nr == N || nr->op != ONAME)
-		goto no;
-
-	// nr is the array being converted to a slice
-	if(nr->type == T || nr->type->etype != TARRAY || nr->type->bound < 0)
-		goto no;
-
-	nam.xoffset += Array_array;
-	gdata(&nam, nl, types[tptr]->width);
-
-	nam.xoffset += Array_nel-Array_array;
-	nodconst(&nod1, types[TINT], nr->type->bound);
-	gdata(&nam, &nod1, widthint);
-
-	nam.xoffset += Array_cap-Array_nel;
-	gdata(&nam, &nod1, widthint);
-
-	goto yes;
-
-no:
-	if(n->dodata == 2) {
-		dump("\ngen_as_init", n);
-		fatal("gen_as_init couldnt make data statement");
-	}
-	return 0;
-}
-
-static int isvaluelit(Node*);
-static InitEntry* entry(InitPlan*);
-static void addvalue(InitPlan*, vlong, Node*, Node*);
-
-static void
-initplan(Node *n)
-{
-	InitPlan *p;
-	Node *a;
-	NodeList *l;
-
-	if(n->initplan != nil)
-		return;
-	p = mal(sizeof *p);
-	n->initplan = p;
-	switch(n->op) {
-	default:
-		fatal("initplan");
-	case OARRAYLIT:
-		for(l=n->list; l; l=l->next) {
-			a = l->n;
-			if(a->op != OKEY || !smallintconst(a->left))
-				fatal("initplan arraylit");
-			addvalue(p, n->type->type->width*mpgetfix(a->left->val.u.xval), N, a->right);
-		}
-		break;
-	case OSTRUCTLIT:
-		for(l=n->list; l; l=l->next) {
-			a = l->n;
-			if(a->op != OKEY || a->left->type == T)
-				fatal("initplan structlit");
-			addvalue(p, a->left->type->width, N, a->right);
-		}
-		break;
-	case OMAPLIT:
-		for(l=n->list; l; l=l->next) {
-			a = l->n;
-			if(a->op != OKEY)
-				fatal("initplan maplit");
-			addvalue(p, -1, a->left, a->right);
-		}
-		break;
-	}
-}
-
-static void
-addvalue(InitPlan *p, vlong xoffset, Node *key, Node *n)
-{
-	int i;
-	InitPlan *q;
-	InitEntry *e;
-
-	USED(key);
-
-	// special case: zero can be dropped entirely
-	if(iszero(n)) {
-		p->zero += n->type->width;
-		return;
-	}
-	
-	// special case: inline struct and array (not slice) literals
-	if(isvaluelit(n)) {
-		initplan(n);
-		q = n->initplan;
-		for(i=0; i<q->len; i++) {
-			e = entry(p);
-			*e = q->e[i];
-			e->xoffset += xoffset;
-		}
-		return;
-	}
-	
-	// add to plan
-	if(n->op == OLITERAL)
-		p->lit += n->type->width;
-	else
-		p->expr += n->type->width;
-
-	e = entry(p);
-	e->xoffset = xoffset;
-	e->expr = n;
-}
-
-int
-iszero(Node *n)
-{
-	NodeList *l;
-
-	switch(n->op) {
-	case OLITERAL:
-		switch(n->val.ctype) {
-		default:
-			dump("unexpected literal", n);
-			fatal("iszero");
-	
-		case CTNIL:
-			return 1;
-		
-		case CTSTR:
-			return n->val.u.sval == nil || n->val.u.sval->len == 0;
-	
-		case CTBOOL:
-			return n->val.u.bval == 0;
-			
-		case CTINT:
-		case CTRUNE:
-			return mpcmpfixc(n->val.u.xval, 0) == 0;
-	
-		case CTFLT:
-			return mpcmpfltc(n->val.u.fval, 0) == 0;
-	
-		case CTCPLX:
-			return mpcmpfltc(&n->val.u.cval->real, 0) == 0 && mpcmpfltc(&n->val.u.cval->imag, 0) == 0;
-		}
-		break;
-	case OARRAYLIT:
-		if(isslice(n->type))
-			break;
-		// fall through
-	case OSTRUCTLIT:
-		for(l=n->list; l; l=l->next)
-			if(!iszero(l->n->right))
-				return 0;
-		return 1;
-	}
-	return 0;
-}
-
-static int
-isvaluelit(Node *n)
-{
-	return (n->op == OARRAYLIT && isfixedarray(n->type)) || n->op == OSTRUCTLIT;
-}
-
-static InitEntry*
-entry(InitPlan *p)
-{
-	if(p->len >= p->cap) {
-		if(p->cap == 0)
-			p->cap = 4;
-		else
-			p->cap *= 2;
-		p->e = realloc(p->e, p->cap*sizeof p->e[0]);
-		if(p->e == nil)
-			fatal("out of memory");
-	}
-	return &p->e[p->len++];
-}
diff --git a/src/cmd/gc/subr.c b/src/cmd/gc/subr.c
deleted file mode 100644
index 26153d3..0000000
--- a/src/cmd/gc/subr.c
+++ /dev/null
@@ -1,3849 +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	<u.h>
-#include	<libc.h>
-#include	"go.h"
-#include	"md5.h"
-#include	"y.tab.h"
-#include	"yerr.h"
-
-typedef struct Error Error;
-struct Error
-{
-	int lineno;
-	int seq;
-	char *msg;
-};
-static Error *err;
-static int nerr;
-static int merr;
-
-void
-errorexit(void)
-{
-	flusherrors();
-	if(outfile)
-		remove(outfile);
-	exits("error");
-}
-
-extern int yychar;
-int
-parserline(void)
-{
-	if(yychar != 0 && yychar != -2)	// parser has one symbol lookahead
-		return prevlineno;
-	return lineno;
-}
-
-static void
-adderr(int line, char *fmt, va_list arg)
-{
-	Fmt f;
-	Error *p;
-
-	fmtstrinit(&f);
-	fmtprint(&f, "%L: ", line);
-	fmtvprint(&f, fmt, arg);
-	fmtprint(&f, "\n");
-
-	if(nerr >= merr) {
-		if(merr == 0)
-			merr = 16;
-		else
-			merr *= 2;
-		p = realloc(err, merr*sizeof err[0]);
-		if(p == nil) {
-			merr = nerr;
-			flusherrors();
-			print("out of memory\n");
-			errorexit();
-		}
-		err = p;
-	}
-	err[nerr].seq = nerr;
-	err[nerr].lineno = line;
-	err[nerr].msg = fmtstrflush(&f);
-	nerr++;
-}
-
-static int
-errcmp(const void *va, const void *vb)
-{
-	Error *a, *b;
-
-	a = (Error*)va;
-	b = (Error*)vb;
-	if(a->lineno != b->lineno)
-		return a->lineno - b->lineno;
-	if(a->seq != b->seq)
-		return a->seq - b->seq;
-	return strcmp(a->msg, b->msg);
-}
-
-void
-flusherrors(void)
-{
-	int i;
-
-	Bflush(&bstdout);
-	if(nerr == 0)
-		return;
-	qsort(err, nerr, sizeof err[0], errcmp);
-	for(i=0; i<nerr; i++)
-		if(i==0 || strcmp(err[i].msg, err[i-1].msg) != 0)
-			print("%s", err[i].msg);
-	nerr = 0;
-}
-
-static void
-hcrash(void)
-{
-	if(debug['h']) {
-		flusherrors();
-		if(outfile)
-			remove(outfile);
-		*(volatile int*)0 = 0;
-	}
-}
-
-void
-yyerrorl(int line, char *fmt, ...)
-{
-	va_list arg;
-
-	va_start(arg, fmt);
-	adderr(line, fmt, arg);
-	va_end(arg);
-
-	hcrash();
-	nerrors++;
-	if(nsavederrors+nerrors >= 10 && !debug['e']) {
-		flusherrors();
-		print("%L: too many errors\n", line);
-		errorexit();
-	}
-}
-
-extern int yystate, yychar;
-
-void
-yyerror(char *fmt, ...)
-{
-	int i;
-	static int lastsyntax;
-	va_list arg;
-	char buf[512], *p;
-
-	if(strncmp(fmt, "syntax error", 12) == 0) {
-		nsyntaxerrors++;
-		
-		if(debug['x'])	
-			print("yyerror: yystate=%d yychar=%d\n", yystate, yychar);
-
-		// An unexpected EOF caused a syntax error. Use the previous
-		// line number since getc generated a fake newline character.
-		if(curio.eofnl)
-			lexlineno = prevlineno;
-
-		// only one syntax error per line
-		if(lastsyntax == lexlineno)
-			return;
-		lastsyntax = lexlineno;
-			
-		if(strstr(fmt, "{ or {") || strstr(fmt, " or ?") || strstr(fmt, " or @")) {
-			// The grammar has { and LBRACE but both show up as {.
-			// Rewrite syntax error referring to "{ or {" to say just "{".
-			strecpy(buf, buf+sizeof buf, fmt);
-			p = strstr(buf, "{ or {");
-			if(p)
-				memmove(p+1, p+6, strlen(p+6)+1);
-			
-			// The grammar has ? and @ but only for reading imports.
-			// Silence them in ordinary errors.
-			p = strstr(buf, " or ?");
-			if(p)
-				memmove(p, p+5, strlen(p+5)+1);
-			p = strstr(buf, " or @");
-			if(p)
-				memmove(p, p+5, strlen(p+5)+1);
-			fmt = buf;
-		}
-		
-		// look for parse state-specific errors in list (see go.errors).
-		for(i=0; i<nelem(yymsg); i++) {
-			if(yymsg[i].yystate == yystate && yymsg[i].yychar == yychar) {
-				yyerrorl(lexlineno, "syntax error: %s", yymsg[i].msg);
-				return;
-			}
-		}
-		
-		// plain "syntax error" gets "near foo" added
-		if(strcmp(fmt, "syntax error") == 0) {
-			yyerrorl(lexlineno, "syntax error near %s", lexbuf);
-			return;
-		}
-		
-		// if bison says "syntax error, more info"; print "syntax error: more info".
-		if(fmt[12] == ',') {
-			yyerrorl(lexlineno, "syntax error:%s", fmt+13);
-			return;
-		}
-
-		yyerrorl(lexlineno, "%s", fmt);
-		return;
-	}
-
-	va_start(arg, fmt);
-	adderr(parserline(), fmt, arg);
-	va_end(arg);
-
-	hcrash();
-	nerrors++;
-	if(nsavederrors+nerrors >= 10 && !debug['e']) {
-		flusherrors();
-		print("%L: too many errors\n", parserline());
-		errorexit();
-	}
-}
-
-void
-warn(char *fmt, ...)
-{
-	va_list arg;
-
-	va_start(arg, fmt);
-	adderr(parserline(), fmt, arg);
-	va_end(arg);
-
-	hcrash();
-}
-
-void
-warnl(int line, char *fmt, ...)
-{
-	va_list arg;
-
-	va_start(arg, fmt);
-	adderr(line, fmt, arg);
-	va_end(arg);
-	if(debug['m'])
-		flusherrors();
-}
-
-void
-fatal(char *fmt, ...)
-{
-	va_list arg;
-
-	flusherrors();
-
-	print("%L: internal compiler error: ", lineno);
-	va_start(arg, fmt);
-	vfprint(1, fmt, arg);
-	va_end(arg);
-	print("\n");
-	
-	// If this is a released compiler version, ask for a bug report.
-	if(strncmp(getgoversion(), "release", 7) == 0) {
-		print("\n");
-		print("Please file a bug report including a short program that triggers the error.\n");
-		print("http://code.google.com/p/go/issues/entry?template=compilerbug\n");
-	}
-	hcrash();
-	errorexit();
-}
-
-void
-linehist(char *file, int32 off, int relative)
-{
-	if(debug['i']) {
-		if(file != nil) {
-			if(off < 0)
-				print("pragma %s", file);
-			else
-			if(off > 0)
-				print("line %s", file);
-			else
-				print("import %s", file);
-		} else
-			print("end of import");
-		print(" at line %L\n", lexlineno);
-	}
-	
-	if(off < 0 && file[0] != '/' && !relative)
-		file = smprint("%s/%s", ctxt->pathname, file);
-	linklinehist(ctxt, lexlineno, file, off);
-}
-
-int32
-setlineno(Node *n)
-{
-	int32 lno;
-
-	lno = lineno;
-	if(n != N)
-	switch(n->op) {
-	case ONAME:
-	case OTYPE:
-	case OPACK:
-	case OLITERAL:
-		break;
-	default:
-		lineno = n->lineno;
-		if(lineno == 0) {
-			if(debug['K'])
-				warn("setlineno: line 0");
-			lineno = lno;
-		}
-	}
-	return lno;
-}
-
-uint32
-stringhash(char *p)
-{
-	uint32 h;
-	int c;
-
-	h = 0;
-	for(;;) {
-		c = *p++;
-		if(c == 0)
-			break;
-		h = h*PRIME1 + c;
-	}
-
-	if((int32)h < 0) {
-		h = -h;
-		if((int32)h < 0)
-			h = 0;
-	}
-	return h;
-}
-
-Sym*
-lookup(char *name)
-{
-	return pkglookup(name, localpkg);
-}
-
-Sym*
-pkglookup(char *name, Pkg *pkg)
-{
-	Sym *s;
-	uint32 h;
-	int c;
-
-	h = stringhash(name) % NHASH;
-	c = name[0];
-	for(s = hash[h]; s != S; s = s->link) {
-		if(s->name[0] != c || s->pkg != pkg)
-			continue;
-		if(strcmp(s->name, name) == 0)
-			return s;
-	}
-
-	s = mal(sizeof(*s));
-	s->name = mal(strlen(name)+1);
-	strcpy(s->name, name);
-
-	s->pkg = pkg;
-
-	s->link = hash[h];
-	hash[h] = s;
-	s->lexical = LNAME;
-
-	return s;
-}
-
-Sym*
-restrictlookup(char *name, Pkg *pkg)
-{
-	if(!exportname(name) && pkg != localpkg)
-		yyerror("cannot refer to unexported name %s.%s", pkg->name, name);
-	return pkglookup(name, pkg);
-}
-
-
-// find all the exported symbols in package opkg
-// and make them available in the current package
-void
-importdot(Pkg *opkg, Node *pack)
-{
-	Sym *s, *s1;
-	uint32 h;
-	int n;
-	char *pkgerror;
-
-	n = 0;
-	for(h=0; h<NHASH; h++) {
-		for(s = hash[h]; s != S; s = s->link) {
-			if(s->pkg != opkg)
-				continue;
-			if(s->def == N)
-				continue;
-			if(!exportname(s->name) || utfrune(s->name, 0xb7))	// 0xb7 = center dot
-				continue;
-			s1 = lookup(s->name);
-			if(s1->def != N) {
-				pkgerror = smprint("during import \"%Z\"", 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(pack->lineno, "imported and not used: \"%Z\"", opkg->path);
-	}
-}
-
-static void
-gethunk(void)
-{
-	char *h;
-	int32 nh;
-
-	nh = NHUNK;
-	if(thunk >= 10L*NHUNK)
-		nh = 10L*NHUNK;
-	h = (char*)malloc(nh);
-	if(h == nil) {
-		flusherrors();
-		yyerror("out of memory");
-		errorexit();
-	}
-	hunk = h;
-	nhunk = nh;
-	thunk += nh;
-}
-
-void*
-mal(int32 n)
-{
-	void *p;
-
-	if(n >= NHUNK) {
-		p = malloc(n);
-		if(p == nil) {
-			flusherrors();
-			yyerror("out of memory");
-			errorexit();
-		}
-		memset(p, 0, n);
-		return p;
-	}
-
-	while((uintptr)hunk & MAXALIGN) {
-		hunk++;
-		nhunk--;
-	}
-	if(nhunk < n)
-		gethunk();
-
-	p = hunk;
-	nhunk -= n;
-	hunk += n;
-	memset(p, 0, n);
-	return p;
-}
-
-void*
-remal(void *p, int32 on, int32 n)
-{
-	void *q;
-
-	q = (uchar*)p + on;
-	if(q != hunk || nhunk < n) {
-		if(on+n >= NHUNK) {
-			q = mal(on+n);
-			memmove(q, p, on);
-			return q;
-		}
-		if(nhunk < on+n)
-			gethunk();
-		memmove(hunk, p, on);
-		p = hunk;
-		hunk += on;
-		nhunk -= on;
-	}
-	hunk += n;
-	nhunk -= n;
-	return p;
-}
-
-Node*
-nod(int op, Node *nleft, Node *nright)
-{
-	Node *n;
-
-	n = mal(sizeof(*n));
-	n->op = op;
-	n->left = nleft;
-	n->right = nright;
-	n->lineno = parserline();
-	n->xoffset = BADWIDTH;
-	n->orig = n;
-	n->curfn = curfn;
-	return n;
-}
-
-void
-saveorignode(Node *n)
-{
-	Node *norig;
-
-	if(n->orig != N)
-		return;
-	norig = nod(n->op, N, N);
-	*norig = *n;
-	n->orig = norig;
-}
-
-// ispaddedfield reports whether the given field
-// is followed by padding. For the case where t is
-// the last field, total gives the size of the enclosing struct.
-static int
-ispaddedfield(Type *t, vlong total)
-{
-	if(t->etype != TFIELD)
-		fatal("ispaddedfield called non-field %T", t);
-	if(t->down == T)
-		return t->width + t->type->width != total;
-	return t->width + t->type->width != t->down->width;
-}
-
-int
-algtype1(Type *t, Type **bad)
-{
-	int a, ret;
-	Type *t1;
-	
-	if(bad)
-		*bad = T;
-	if(t->broke)
-		return AMEM;
-	if(t->noalg)
-		return ANOEQ;
-
-	switch(t->etype) {
-	case TANY:
-	case TFORW:
-		// will be defined later.
-		*bad = t;
-		return -1;
-
-	case TINT8:
-	case TUINT8:
-	case TINT16:
-	case TUINT16:
-	case TINT32:
-	case TUINT32:
-	case TINT64:
-	case TUINT64:
-	case TINT:
-	case TUINT:
-	case TUINTPTR:
-	case TBOOL:
-	case TPTR32:
-	case TPTR64:
-	case TCHAN:
-	case TUNSAFEPTR:
-		return AMEM;
-
-	case TFUNC:
-	case TMAP:
-		if(bad)
-			*bad = t;
-		return ANOEQ;
-
-	case TFLOAT32:
-		return AFLOAT32;
-
-	case TFLOAT64:
-		return AFLOAT64;
-
-	case TCOMPLEX64:
-		return ACPLX64;
-
-	case TCOMPLEX128:
-		return ACPLX128;
-
-	case TSTRING:
-		return ASTRING;
-	
-	case TINTER:
-		if(isnilinter(t))
-			return ANILINTER;
-		return AINTER;
-	
-	case TARRAY:
-		if(isslice(t)) {
-			if(bad)
-				*bad = t;
-			return ANOEQ;
-		}
-		a = algtype1(t->type, bad);
-		if(a == ANOEQ || a == AMEM) {
-			if(a == ANOEQ && bad)
-				*bad = t;
-			return a;
-		}
-		return -1;  // needs special compare
-
-	case TSTRUCT:
-		if(t->type != T && t->type->down == T && !isblanksym(t->type->sym)) {
-			// One-field struct is same as that one field alone.
-			return algtype1(t->type->type, bad);
-		}
-		ret = AMEM;
-		for(t1=t->type; t1!=T; t1=t1->down) {
-			// All fields must be comparable.
-			a = algtype1(t1->type, bad);
-			if(a == ANOEQ)
-				return ANOEQ;
-
-			// Blank fields, padded fields, fields with non-memory
-			// equality need special compare.
-			if(a != AMEM || isblanksym(t1->sym) || ispaddedfield(t1, t->width)) {
-				ret = -1;
-				continue;
-			}
-		}
-		return ret;
-	}
-
-	fatal("algtype1: unexpected type %T", t);
-	return 0;
-}
-
-int
-algtype(Type *t)
-{
-	int a;
-	
-	a = algtype1(t, nil);
-	if(a == AMEM || a == ANOEQ) {
-		if(isslice(t))
-			return ASLICE;
-		switch(t->width) {
-		case 0:
-			return a + AMEM0 - AMEM;
-		case 1:
-			return a + AMEM8 - AMEM;
-		case 2:
-			return a + AMEM16 - AMEM;
-		case 4:
-			return a + AMEM32 - AMEM;
-		case 8:
-			return a + AMEM64 - AMEM;
-		case 16:
-			return a + AMEM128 - AMEM;
-		}
-	}
-	return a;
-}
-
-Type*
-maptype(Type *key, Type *val)
-{
-	Type *t;
-	Type *bad;
-	int atype, mtype;
-
-	if(key != nil) {
-		atype = algtype1(key, &bad);
-		if(bad == T)
-			mtype = key->etype;
-		else
-			mtype = bad->etype;
-		switch(mtype) {
-		default:
-			if(atype == ANOEQ)
-				yyerror("invalid map key type %T", key);
-			break;
-		case TANY:
-			// will be resolved later.
-			break;
-		case TFORW:
-			// map[key] used during definition of key.
-			// postpone check until key is fully defined.
-			// if there are multiple uses of map[key]
-			// before key is fully defined, the error
-			// will only be printed for the first one.
-			// good enough.
-			if(key->maplineno == 0)
-				key->maplineno = lineno;
-			break;
-		}
-	}
-	t = typ(TMAP);
-	t->down = key;
-	t->type = val;
-	return t;
-}
-
-Type*
-typ(int et)
-{
-	Type *t;
-
-	t = mal(sizeof(*t));
-	t->etype = et;
-	t->width = BADWIDTH;
-	t->lineno = lineno;
-	t->orig = t;
-	return t;
-}
-
-static int
-methcmp(const void *va, const void *vb)
-{
-	Type *a, *b;
-	int i;
-	
-	a = *(Type**)va;
-	b = *(Type**)vb;
-	if(a->sym == S && b->sym == S)
-		return 0;
-	if(a->sym == S)
-		return -1;
-	if(b->sym == S)
-		return 1;
-	i = strcmp(a->sym->name, b->sym->name);
-	if(i != 0)
-		return i;
-	if(!exportname(a->sym->name)) {
-		i = strcmp(a->sym->pkg->path->s, b->sym->pkg->path->s);
-		if(i != 0)
-			return i;
-	}
-	return 0;
-}
-
-Type*
-sortinter(Type *t)
-{
-	Type *f;
-	int i;
-	Type **a;
-	
-	if(t->type == nil || t->type->down == nil)
-		return t;
-
-	i=0;
-	for(f=t->type; f; f=f->down)
-		i++;
-	a = mal(i*sizeof f);
-	i = 0;
-	for(f=t->type; f; f=f->down)
-		a[i++] = f;
-	qsort(a, i, sizeof a[0], methcmp);
-	while(i-- > 0) {
-		a[i]->down = f;
-		f = a[i];
-	}
-	t->type = f;
-	return t;
-}
-
-Node*
-nodintconst(int64 v)
-{
-	Node *c;
-
-	c = nod(OLITERAL, N, N);
-	c->addable = 1;
-	c->val.u.xval = mal(sizeof(*c->val.u.xval));
-	mpmovecfix(c->val.u.xval, v);
-	c->val.ctype = CTINT;
-	c->type = types[TIDEAL];
-	ullmancalc(c);
-	return c;
-}
-
-Node*
-nodfltconst(Mpflt* v)
-{
-	Node *c;
-
-	c = nod(OLITERAL, N, N);
-	c->addable = 1;
-	c->val.u.fval = mal(sizeof(*c->val.u.fval));
-	mpmovefltflt(c->val.u.fval, v);
-	c->val.ctype = CTFLT;
-	c->type = types[TIDEAL];
-	ullmancalc(c);
-	return c;
-}
-
-void
-nodconst(Node *n, Type *t, int64 v)
-{
-	memset(n, 0, sizeof(*n));
-	n->op = OLITERAL;
-	n->addable = 1;
-	ullmancalc(n);
-	n->val.u.xval = mal(sizeof(*n->val.u.xval));
-	mpmovecfix(n->val.u.xval, v);
-	n->val.ctype = CTINT;
-	n->type = t;
-
-	if(isfloat[t->etype])
-		fatal("nodconst: bad type %T", t);
-}
-
-Node*
-nodnil(void)
-{
-	Node *c;
-
-	c = nodintconst(0);
-	c->val.ctype = CTNIL;
-	c->type = types[TNIL];
-	return c;
-}
-
-Node*
-nodbool(int b)
-{
-	Node *c;
-
-	c = nodintconst(0);
-	c->val.ctype = CTBOOL;
-	c->val.u.bval = b;
-	c->type = idealbool;
-	return c;
-}
-
-Type*
-aindex(Node *b, Type *t)
-{
-	Type *r;
-	int64 bound;
-
-	bound = -1;	// open bound
-	typecheck(&b, Erv);
-	if(b != nil) {
-		switch(consttype(b)) {
-		default:
-			yyerror("array bound must be an integer expression");
-			break;
-		case CTINT:
-		case CTRUNE:
-			bound = mpgetfix(b->val.u.xval);
-			if(bound < 0)
-				yyerror("array bound must be non negative");
-			break;
-		}
-	}
-
-	// fixed array
-	r = typ(TARRAY);
-	r->type = t;
-	r->bound = bound;
-	return r;
-}
-
-Node*
-treecopy(Node *n)
-{
-	Node *m;
-
-	if(n == N)
-		return N;
-
-	switch(n->op) {
-	default:
-		m = nod(OXXX, N, N);
-		*m = *n;
-		m->orig = m;
-		m->left = treecopy(n->left);
-		m->right = treecopy(n->right);
-		m->list = listtreecopy(n->list);
-		if(m->defn)
-			abort();
-		break;
-
-	case ONONAME:
-		if(n->sym == lookup("iota")) {
-			// Not sure yet whether this is the real iota,
-			// but make a copy of the Node* just in case,
-			// so that all the copies of this const definition
-			// don't have the same iota value.
-			m = nod(OXXX, N, N);
-			*m = *n;
-			m->iota = iota;
-			break;
-		}
-		// fall through
-	case ONAME:
-	case OLITERAL:
-	case OTYPE:
-		m = n;
-		break;
-	}
-	return m;
-}
-
-
-int
-isnil(Node *n)
-{
-	if(n == N)
-		return 0;
-	if(n->op != OLITERAL)
-		return 0;
-	if(n->val.ctype != CTNIL)
-		return 0;
-	return 1;
-}
-
-int
-isptrto(Type *t, int et)
-{
-	if(t == T)
-		return 0;
-	if(!isptr[t->etype])
-		return 0;
-	t = t->type;
-	if(t == T)
-		return 0;
-	if(t->etype != et)
-		return 0;
-	return 1;
-}
-
-int
-istype(Type *t, int et)
-{
-	return t != T && t->etype == et;
-}
-
-int
-isfixedarray(Type *t)
-{
-	return t != T && t->etype == TARRAY && t->bound >= 0;
-}
-
-int
-isslice(Type *t)
-{
-	return t != T && t->etype == TARRAY && t->bound < 0;
-}
-
-int
-isblank(Node *n)
-{
-	if(n == N)
-		return 0;
-	return isblanksym(n->sym);
-}
-
-int
-isblanksym(Sym *s)
-{
-	char *p;
-
-	if(s == S)
-		return 0;
-	p = s->name;
-	if(p == nil)
-		return 0;
-	return p[0] == '_' && p[1] == '\0';
-}
-
-int
-isinter(Type *t)
-{
-	return t != T && t->etype == TINTER;
-}
-
-int
-isnilinter(Type *t)
-{
-	if(!isinter(t))
-		return 0;
-	if(t->type != T)
-		return 0;
-	return 1;
-}
-
-int
-isideal(Type *t)
-{
-	if(t == T)
-		return 0;
-	if(t == idealstring || t == idealbool)
-		return 1;
-	switch(t->etype) {
-	case TNIL:
-	case TIDEAL:
-		return 1;
-	}
-	return 0;
-}
-
-/*
- * given receiver of type t (t == r or t == *r)
- * return type to hang methods off (r).
- */
-Type*
-methtype(Type *t, int mustname)
-{
-	if(t == T)
-		return T;
-
-	// strip away pointer if it's there
-	if(isptr[t->etype]) {
-		if(t->sym != S)
-			return T;
-		t = t->type;
-		if(t == T)
-			return T;
-	}
-
-	// need a type name
-	if(t->sym == S && (mustname || t->etype != TSTRUCT))
-		return T;
-
-	// check types
-	if(!issimple[t->etype])
-	switch(t->etype) {
-	default:
-		return T;
-	case TSTRUCT:
-	case TARRAY:
-	case TMAP:
-	case TCHAN:
-	case TSTRING:
-	case TFUNC:
-		break;
-	}
-
-	return t;
-}
-
-int
-cplxsubtype(int et)
-{
-	switch(et) {
-	case TCOMPLEX64:
-		return TFLOAT32;
-	case TCOMPLEX128:
-		return TFLOAT64;
-	}
-	fatal("cplxsubtype: %E\n", et);
-	return 0;
-}
-
-static int
-eqnote(Strlit *a, Strlit *b)
-{
-	if(a == b)
-		return 1;
-	if(a == nil || b == nil)
-		return 0;
-	if(a->len != b->len)
-		return 0;
-	return memcmp(a->s, b->s, a->len) == 0;
-}
-
-typedef struct TypePairList TypePairList;
-struct TypePairList
-{
-	Type *t1;
-	Type *t2;
-	TypePairList *next;
-};
-
-static int
-onlist(TypePairList *l, Type *t1, Type *t2) 
-{
-	for(; l; l=l->next)
-		if((l->t1 == t1 && l->t2 == t2) || (l->t1 == t2 && l->t2 == t1))
-			return 1;
-	return 0;
-}
-
-static int eqtype1(Type*, Type*, TypePairList*);
-
-// Return 1 if t1 and t2 are identical, following the spec rules.
-//
-// Any cyclic type must go through a named type, and if one is
-// named, it is only identical to the other if they are the same
-// pointer (t1 == t2), so there's no chance of chasing cycles
-// ad infinitum, so no need for a depth counter.
-int
-eqtype(Type *t1, Type *t2)
-{
-	return eqtype1(t1, t2, nil);
-}
-
-static int
-eqtype1(Type *t1, Type *t2, TypePairList *assumed_equal)
-{
-	TypePairList l;
-
-	if(t1 == t2)
-		return 1;
-	if(t1 == T || t2 == T || t1->etype != t2->etype)
-		return 0;
-	if(t1->sym || t2->sym) {
-		// Special case: we keep byte and uint8 separate
-		// for error messages.  Treat them as equal.
-		switch(t1->etype) {
-		case TUINT8:
-			if((t1 == types[TUINT8] || t1 == bytetype) && (t2 == types[TUINT8] || t2 == bytetype))
-				return 1;
-			break;
-		case TINT:
-		case TINT32:
-			if((t1 == types[runetype->etype] || t1 == runetype) && (t2 == types[runetype->etype] || t2 == runetype))
-				return 1;
-			break;
-		}
-		return 0;
-	}
-
-	if(onlist(assumed_equal, t1, t2))
-		return 1;
-	l.next = assumed_equal;
-	l.t1 = t1;
-	l.t2 = t2;
-
-	switch(t1->etype) {
-	case TINTER:
-	case TSTRUCT:
-		for(t1=t1->type, t2=t2->type; t1 && t2; t1=t1->down, t2=t2->down) {
-			if(t1->etype != TFIELD || t2->etype != TFIELD)
-				fatal("struct/interface missing field: %T %T", t1, t2);
-			if(t1->sym != t2->sym || t1->embedded != t2->embedded || !eqtype1(t1->type, t2->type, &l) || !eqnote(t1->note, t2->note))
-				goto no;
-		}
-		if(t1 == T && t2 == T)
-			goto yes;
-		goto no;
-
-	case TFUNC:
-		// Loop over structs: receiver, in, out.
-		for(t1=t1->type, t2=t2->type; t1 && t2; t1=t1->down, t2=t2->down) {
-			Type *ta, *tb;
-
-			if(t1->etype != TSTRUCT || t2->etype != TSTRUCT)
-				fatal("func missing struct: %T %T", t1, t2);
-
-			// Loop over fields in structs, ignoring argument names.
-			for(ta=t1->type, tb=t2->type; ta && tb; ta=ta->down, tb=tb->down) {
-				if(ta->etype != TFIELD || tb->etype != TFIELD)
-					fatal("func struct missing field: %T %T", ta, tb);
-				if(ta->isddd != tb->isddd || !eqtype1(ta->type, tb->type, &l))
-					goto no;
-			}
-			if(ta != T || tb != T)
-				goto no;
-		}
-		if(t1 == T && t2 == T)
-			goto yes;
-		goto no;
-	
-	case TARRAY:
-		if(t1->bound != t2->bound)
-			goto no;
-		break;
-	
-	case TCHAN:
-		if(t1->chan != t2->chan)
-			goto no;
-		break;
-	}
-
-	if(eqtype1(t1->down, t2->down, &l) && eqtype1(t1->type, t2->type, &l))
-		goto yes;
-	goto no;
-
-yes:
-	return 1;
-
-no:
-	return 0;
-}
-
-// Are t1 and t2 equal struct types when field names are ignored?
-// For deciding whether the result struct from g can be copied
-// directly when compiling f(g()).
-int
-eqtypenoname(Type *t1, Type *t2)
-{
-	if(t1 == T || t2 == T || t1->etype != TSTRUCT || t2->etype != TSTRUCT)
-		return 0;
-
-	t1 = t1->type;
-	t2 = t2->type;
-	for(;;) {
-		if(!eqtype(t1, t2))
-			return 0;
-		if(t1 == T)
-			return 1;
-		t1 = t1->down;
-		t2 = t2->down;
-	}
-}
-
-// Is type src assignment compatible to type dst?
-// If so, return op code to use in conversion.
-// If not, return 0.
-int
-assignop(Type *src, Type *dst, char **why)
-{
-	Type *missing, *have;
-	int ptr;
-
-	if(why != nil)
-		*why = "";
-
-	// TODO(rsc,lvd): This behaves poorly in the presence of inlining.
-	// https://code.google.com/p/go/issues/detail?id=2795
-	if(safemode && importpkg == nil && src != T && src->etype == TUNSAFEPTR) {
-		yyerror("cannot use unsafe.Pointer");
-		errorexit();
-	}
-
-	if(src == dst)
-		return OCONVNOP;
-	if(src == T || dst == T || src->etype == TFORW || dst->etype == TFORW || src->orig == T || dst->orig == T)
-		return 0;
-
-	// 1. src type is identical to dst.
-	if(eqtype(src, dst))
-		return OCONVNOP;
-	
-	// 2. src and dst have identical underlying types
-	// and either src or dst is not a named type or
-	// both are empty interface types.
-	// For assignable but different non-empty interface types,
-	// we want to recompute the itab.
-	if(eqtype(src->orig, dst->orig) && (src->sym == S || dst->sym == S || isnilinter(src)))
-		return OCONVNOP;
-
-	// 3. dst is an interface type and src implements dst.
-	if(dst->etype == TINTER && src->etype != TNIL) {
-		if(implements(src, dst, &missing, &have, &ptr))
-			return OCONVIFACE;
-
-		// we'll have complained about this method anyway, suppress spurious messages.
-		if(have && have->sym == missing->sym && (have->type->broke || missing->type->broke))
-			return OCONVIFACE;
-
-		if(why != nil) {
-			if(isptrto(src, TINTER))
-				*why = smprint(":\n\t%T is pointer to interface, not interface", src);
-			else if(have && have->sym == missing->sym && have->nointerface)
-				*why = smprint(":\n\t%T does not implement %T (%S method is marked 'nointerface')",
-					src, dst, missing->sym);
-			else if(have && have->sym == missing->sym)
-				*why = smprint(":\n\t%T does not implement %T (wrong type for %S method)\n"
-					"\t\thave %S%hhT\n\t\twant %S%hhT", src, dst, missing->sym,
-					have->sym, have->type, missing->sym, missing->type);
-			else if(ptr)
-				*why = smprint(":\n\t%T does not implement %T (%S method has pointer receiver)",
-					src, dst, missing->sym);
-			else if(have)
-				*why = smprint(":\n\t%T does not implement %T (missing %S method)\n"
-					"\t\thave %S%hhT\n\t\twant %S%hhT", src, dst, missing->sym,
-					have->sym, have->type, missing->sym, missing->type);
-			else
-				*why = smprint(":\n\t%T does not implement %T (missing %S method)",
-					src, dst, missing->sym);
-		}
-		return 0;
-	}
-	if(isptrto(dst, TINTER)) {
-		if(why != nil)
-			*why = smprint(":\n\t%T is pointer to interface, not interface", dst);
-		return 0;
-	}
-	if(src->etype == TINTER && dst->etype != TBLANK) {
-		if(why != nil && implements(dst, src, &missing, &have, &ptr))
-			*why = ": need type assertion";
-		return 0;
-	}
-
-	// 4. src is a bidirectional channel value, dst is a channel type,
-	// src and dst have identical element types, and
-	// either src or dst is not a named type.
-	if(src->etype == TCHAN && src->chan == Cboth && dst->etype == TCHAN)
-	if(eqtype(src->type, dst->type) && (src->sym == S || dst->sym == S))
-		return OCONVNOP;
-
-	// 5. src is the predeclared identifier nil and dst is a nillable type.
-	if(src->etype == TNIL) {
-		switch(dst->etype) {
-		case TARRAY:
-			if(dst->bound != -100)	// not slice
-				break;
-		case TPTR32:
-		case TPTR64:
-		case TFUNC:
-		case TMAP:
-		case TCHAN:
-		case TINTER:
-			return OCONVNOP;
-		}
-	}
-
-	// 6. rule about untyped constants - already converted by defaultlit.
-	
-	// 7. Any typed value can be assigned to the blank identifier.
-	if(dst->etype == TBLANK)
-		return OCONVNOP;
-
-	return 0;
-}
-
-// Can we convert a value of type src to a value of type dst?
-// If so, return op code to use in conversion (maybe OCONVNOP).
-// If not, return 0.
-int
-convertop(Type *src, Type *dst, char **why)
-{
-	int op;
-	
-	if(why != nil)
-		*why = "";
-
-	if(src == dst)
-		return OCONVNOP;
-	if(src == T || dst == T)
-		return 0;
-	
-	// 1. src can be assigned to dst.
-	if((op = assignop(src, dst, why)) != 0)
-		return op;
-
-	// The rules for interfaces are no different in conversions
-	// than assignments.  If interfaces are involved, stop now
-	// with the good message from assignop.
-	// Otherwise clear the error.
-	if(src->etype == TINTER || dst->etype == TINTER)
-		return 0;
-	if(why != nil)
-		*why = "";
-
-	// 2. src and dst have identical underlying types.
-	if(eqtype(src->orig, dst->orig))
-		return OCONVNOP;
-	
-	// 3. src and dst are unnamed pointer types 
-	// and their base types have identical underlying types.
-	if(isptr[src->etype] && isptr[dst->etype] && src->sym == S && dst->sym == S)
-	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] || isfloat[src->etype]) && (isint[dst->etype] || isfloat[dst->etype])) {
-		if(simtype[src->etype] == simtype[dst->etype])
-			return OCONVNOP;
-		return OCONV;
-	}
-
-	// 5. src and dst are both complex types.
-	if(iscomplex[src->etype] && iscomplex[dst->etype]) {
-		if(simtype[src->etype] == simtype[dst->etype])
-			return OCONVNOP;
-		return OCONV;
-	}
-
-	// 6. src is an integer or has type []byte or []rune
-	// and dst is a string type.
-	if(isint[src->etype] && dst->etype == TSTRING)
-		return ORUNESTR;
-
-	if(isslice(src) && dst->etype == TSTRING) {
-		if(src->type->etype == bytetype->etype)
-			return OARRAYBYTESTR;
-		if(src->type->etype == runetype->etype)
-			return OARRAYRUNESTR;
-	}
-	
-	// 7. src is a string and dst is []byte or []rune.
-	// String to slice.
-	if(src->etype == TSTRING && isslice(dst)) {
-		if(dst->type->etype == bytetype->etype)
-			return OSTRARRAYBYTE;
-		if(dst->type->etype == runetype->etype)
-			return OSTRARRAYRUNE;
-	}
-	
-	// 8. src is a pointer or uintptr and dst is unsafe.Pointer.
-	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] || dst->etype == TUINTPTR))
-		return OCONVNOP;
-
-	return 0;
-}
-
-// Convert node n for assignment to type t.
-Node*
-assignconv(Node *n, Type *t, char *context)
-{
-	int op;
-	Node *r, *old;
-	char *why;
-	
-	if(n == N || n->type == T || n->type->broke)
-		return n;
-
-	if(t->etype == TBLANK && n->type->etype == TNIL)
-		yyerror("use of untyped nil");
-
-	old = n;
-	old->diag++;  // silence errors about n; we'll issue one below
-	defaultlit(&n, t);
-	old->diag--;
-	if(t->etype == TBLANK)
-		return n;
-
-	// Convert ideal bool from comparison to plain bool
-	// if the next step is non-bool (like interface{}).
-	if(n->type == idealbool && t->etype != TBOOL) {
-		if(n->op == ONAME || n->op == OLITERAL) {
-			r = nod(OCONVNOP, n, N);
-			r->type = types[TBOOL];
-			r->typecheck = 1;
-			r->implicit = 1;
-			n = r;
-		}
-	}
-
-	if(eqtype(n->type, t))
-		return n;
-
-	op = assignop(n->type, t, &why);
-	if(op == 0) {
-		yyerror("cannot use %lN as type %T in %s%s", n, t, context, why);
-		op = OCONV;
-	}
-
-	r = nod(op, n, N);
-	r->type = t;
-	r->typecheck = 1;
-	r->implicit = 1;
-	r->orig = n->orig;
-	return r;
-}
-
-static int
-subtype(Type **stp, Type *t, int d)
-{
-	Type *st;
-
-loop:
-	st = *stp;
-	if(st == T)
-		return 0;
-
-	d++;
-	if(d >= 10)
-		return 0;
-
-	switch(st->etype) {
-	default:
-		return 0;
-
-	case TPTR32:
-	case TPTR64:
-	case TCHAN:
-	case TARRAY:
-		stp = &st->type;
-		goto loop;
-
-	case TANY:
-		if(!st->copyany)
-			return 0;
-		*stp = t;
-		break;
-
-	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(subtype(&st->type->down->down, t, d))
-				break;
-			if(subtype(&st->type->down, t, d))
-				break;
-			return 0;
-		}
-		break;
-
-	case TSTRUCT:
-		for(st=st->type; st!=T; st=st->down)
-			if(subtype(&st->type, t, d))
-				return 1;
-		return 0;
-	}
-	return 1;
-}
-
-/*
- * Is this a 64-bit type?
- */
-int
-is64(Type *t)
-{
-	if(t == T)
-		return 0;
-	switch(simtype[t->etype]) {
-	case TINT64:
-	case TUINT64:
-	case TPTR64:
-		return 1;
-	}
-	return 0;
-}
-
-/*
- * Is a conversion between t1 and t2 a no-op?
- */
-int
-noconv(Type *t1, Type *t2)
-{
-	int e1, e2;
-
-	e1 = simtype[t1->etype];
-	e2 = simtype[t2->etype];
-
-	switch(e1) {
-	case TINT8:
-	case TUINT8:
-		return e2 == TINT8 || e2 == TUINT8;
-
-	case TINT16:
-	case TUINT16:
-		return e2 == TINT16 || e2 == TUINT16;
-
-	case TINT32:
-	case TUINT32:
-	case TPTR32:
-		return e2 == TINT32 || e2 == TUINT32 || e2 == TPTR32;
-
-	case TINT64:
-	case TUINT64:
-	case TPTR64:
-		return e2 == TINT64 || e2 == TUINT64 || e2 == TPTR64;
-
-	case TFLOAT32:
-		return e2 == TFLOAT32;
-
-	case TFLOAT64:
-		return e2 == TFLOAT64;
-	}
-	return 0;
-}
-
-void
-argtype(Node *on, Type *t)
-{
-	dowidth(t);
-	if(!subtype(&on->type, t, 0))
-		fatal("argtype: failed %N %T\n", on, t);
-}
-
-Type*
-shallow(Type *t)
-{
-	Type *nt;
-
-	if(t == T)
-		return T;
-	nt = typ(0);
-	*nt = *t;
-	if(t->orig == t)
-		nt->orig = nt;
-	return nt;
-}
-
-static Type*
-deep(Type *t)
-{
-	Type *nt, *xt;
-
-	if(t == T)
-		return T;
-
-	switch(t->etype) {
-	default:
-		nt = t;	// share from here down
-		break;
-
-	case TANY:
-		nt = shallow(t);
-		nt->copyany = 1;
-		break;
-
-	case TPTR32:
-	case TPTR64:
-	case TCHAN:
-	case TARRAY:
-		nt = shallow(t);
-		nt->type = deep(t->type);
-		break;
-
-	case TMAP:
-		nt = shallow(t);
-		nt->down = deep(t->down);
-		nt->type = deep(t->type);
-		break;
-
-	case TFUNC:
-		nt = shallow(t);
-		nt->type = deep(t->type);
-		nt->type->down = deep(t->type->down);
-		nt->type->down->down = deep(t->type->down->down);
-		break;
-
-	case TSTRUCT:
-		nt = shallow(t);
-		nt->type = shallow(t->type);
-		xt = nt->type;
-
-		for(t=t->type; t!=T; t=t->down) {
-			xt->type = deep(t->type);
-			xt->down = shallow(t->down);
-			xt = xt->down;
-		}
-		break;
-	}
-	return nt;
-}
-
-Node*
-syslook(char *name, int copy)
-{
-	Sym *s;
-	Node *n;
-
-	s = pkglookup(name, runtimepkg);
-	if(s == S || s->def == N)
-		fatal("syslook: can't find runtime.%s", name);
-
-	if(!copy)
-		return s->def;
-
-	n = nod(0, N, N);
-	*n = *s->def;
-	n->type = deep(s->def->type);
-
-	return n;
-}
-
-/*
- * compute a hash value for type t.
- * if t is a method type, ignore the receiver
- * so that the hash can be used in interface checks.
- * %T already contains
- * all the necessary logic to generate a representation
- * of the type that completely describes it.
- * using smprint here avoids duplicating that code.
- * using md5 here is overkill, but i got tired of
- * accidental collisions making the runtime think
- * two types are equal when they really aren't.
- */
-uint32
-typehash(Type *t)
-{
-	char *p;
-	MD5 d;
-
-	if(t->thistuple) {
-		// hide method receiver from Tpretty
-		t->thistuple = 0;
-		p = smprint("%-uT", t);
-		t->thistuple = 1;
-	} else
-		p = smprint("%-uT", t);
-	//print("typehash: %s\n", p);
-	md5reset(&d);
-	md5write(&d, (uchar*)p, strlen(p));
-	free(p);
-	return md5sum(&d, nil);
-}
-
-Type*
-ptrto(Type *t)
-{
-	Type *t1;
-
-	if(tptr == 0)
-		fatal("ptrto: no tptr");
-	t1 = typ(tptr);
-	t1->type = t;
-	t1->width = widthptr;
-	t1->align = widthptr;
-	return t1;
-}
-
-void
-frame(int context)
-{
-	char *p;
-	NodeList *l;
-	Node *n;
-	int flag;
-
-	p = "stack";
-	l = nil;
-	if(curfn)
-		l = curfn->dcl;
-	if(context) {
-		p = "external";
-		l = externdcl;
-	}
-
-	flag = 1;
-	for(; l; l=l->next) {
-		n = l->n;
-		switch(n->op) {
-		case ONAME:
-			if(flag)
-				print("--- %s frame ---\n", p);
-			print("%O %S G%d %T\n", n->op, n->sym, n->vargen, n->type);
-			flag = 0;
-			break;
-
-		case OTYPE:
-			if(flag)
-				print("--- %s frame ---\n", p);
-			print("%O %T\n", n->op, n->type);
-			flag = 0;
-			break;
-		}
-	}
-}
-
-/*
- * calculate sethi/ullman number
- * roughly how many registers needed to
- * compile a node. used to compile the
- * hardest side first to minimize registers.
- */
-void
-ullmancalc(Node *n)
-{
-	int ul, ur;
-
-	if(n == N)
-		return;
-
-	if(n->ninit != nil) {
-		ul = UINF;
-		goto out;
-	}
-
-	switch(n->op) {
-	case OREGISTER:
-	case OLITERAL:
-	case ONAME:
-		ul = 1;
-		if(n->class == PPARAMREF || (n->class & PHEAP))
-			ul++;
-		goto out;
-	case OCALL:
-	case OCALLFUNC:
-	case OCALLMETH:
-	case OCALLINTER:
-		ul = UINF;
-		goto out;
-	case OANDAND:
-	case OOROR:
-		// hard with race detector
-		if(flag_race) {
-			ul = UINF;
-			goto out;
-		}
-	}
-	ul = 1;
-	if(n->left != N)
-		ul = n->left->ullman;
-	ur = 1;
-	if(n->right != N)
-		ur = n->right->ullman;
-	if(ul == ur)
-		ul += 1;
-	if(ur > ul)
-		ul = ur;
-
-out:
-	if(ul > 200)
-		ul = 200; // clamp to uchar with room to grow
-	n->ullman = ul;
-}
-
-void
-badtype(int o, Type *tl, Type *tr)
-{
-	Fmt fmt;
-	char *s;
-	
-	fmtstrinit(&fmt);
-	if(tl != T)
-		fmtprint(&fmt, "\n	%T", tl);
-	if(tr != T)
-		fmtprint(&fmt, "\n	%T", tr);
-
-	// common mistake: *struct and *interface.
-	if(tl && tr && isptr[tl->etype] && isptr[tr->etype]) {
-		if(tl->type->etype == TSTRUCT && tr->type->etype == TINTER)
-			fmtprint(&fmt, "\n	(*struct vs *interface)");
-		else if(tl->type->etype == TINTER && tr->type->etype == TSTRUCT)
-			fmtprint(&fmt, "\n	(*interface vs *struct)");
-	}
-	s = fmtstrflush(&fmt);
-	yyerror("illegal types for operand: %O%s", o, s);
-}
-
-/*
- * iterator to walk a structure declaration
- */
-Type*
-structfirst(Iter *s, Type **nn)
-{
-	Type *n, *t;
-
-	n = *nn;
-	if(n == T)
-		goto bad;
-
-	switch(n->etype) {
-	default:
-		goto bad;
-
-	case TSTRUCT:
-	case TINTER:
-	case TFUNC:
-		break;
-	}
-
-	t = n->type;
-	if(t == T)
-		goto rnil;
-
-	if(t->etype != TFIELD)
-		fatal("structfirst: not field %T", t);
-
-	s->t = t;
-	return t;
-
-bad:
-	fatal("structfirst: not struct %T", n);
-
-rnil:
-	return T;
-}
-
-Type*
-structnext(Iter *s)
-{
-	Type *n, *t;
-
-	n = s->t;
-	t = n->down;
-	if(t == T)
-		goto rnil;
-
-	if(t->etype != TFIELD)
-		goto bad;
-
-	s->t = t;
-	return t;
-
-bad:
-	fatal("structnext: not struct %T", n);
-
-rnil:
-	return T;
-}
-
-/*
- * iterator to this and inargs in a function
- */
-Type*
-funcfirst(Iter *s, Type *t)
-{
-	Type *fp;
-
-	if(t == T)
-		goto bad;
-
-	if(t->etype != TFUNC)
-		goto bad;
-
-	s->tfunc = t;
-	s->done = 0;
-	fp = structfirst(s, getthis(t));
-	if(fp == T) {
-		s->done = 1;
-		fp = structfirst(s, getinarg(t));
-	}
-	return fp;
-
-bad:
-	fatal("funcfirst: not func %T", t);
-	return T;
-}
-
-Type*
-funcnext(Iter *s)
-{
-	Type *fp;
-
-	fp = structnext(s);
-	if(fp == T && !s->done) {
-		s->done = 1;
-		fp = structfirst(s, getinarg(s->tfunc));
-	}
-	return fp;
-}
-
-Type**
-getthis(Type *t)
-{
-	if(t->etype != TFUNC)
-		fatal("getthis: not a func %T", t);
-	return &t->type;
-}
-
-Type**
-getoutarg(Type *t)
-{
-	if(t->etype != TFUNC)
-		fatal("getoutarg: not a func %T", t);
-	return &t->type->down;
-}
-
-Type**
-getinarg(Type *t)
-{
-	if(t->etype != TFUNC)
-		fatal("getinarg: not a func %T", t);
-	return &t->type->down->down;
-}
-
-Type*
-getthisx(Type *t)
-{
-	return *getthis(t);
-}
-
-Type*
-getoutargx(Type *t)
-{
-	return *getoutarg(t);
-}
-
-Type*
-getinargx(Type *t)
-{
-	return *getinarg(t);
-}
-
-/*
- * return !(op)
- * eg == <=> !=
- */
-int
-brcom(int a)
-{
-	switch(a) {
-	case OEQ:	return ONE;
-	case ONE:	return OEQ;
-	case OLT:	return OGE;
-	case OGT:	return OLE;
-	case OLE:	return OGT;
-	case OGE:	return OLT;
-	}
-	fatal("brcom: no com for %A\n", a);
-	return a;
-}
-
-/*
- * return reverse(op)
- * eg a op b <=> b r(op) a
- */
-int
-brrev(int a)
-{
-	switch(a) {
-	case OEQ:	return OEQ;
-	case ONE:	return ONE;
-	case OLT:	return OGT;
-	case OGT:	return OLT;
-	case OLE:	return OGE;
-	case OGE:	return OLE;
-	}
-	fatal("brcom: no rev for %A\n", a);
-	return a;
-}
-
-/*
- * return side effect-free n, appending side effects to init.
- * result is assignable if n is.
- */
-Node*
-safeexpr(Node *n, NodeList **init)
-{
-	Node *l;
-	Node *r;
-	Node *a;
-
-	if(n == N)
-		return N;
-
-	if(n->ninit) {
-		walkstmtlist(n->ninit);
-		*init = concat(*init, n->ninit);
-		n->ninit = nil;
-	}
-
-	switch(n->op) {
-	case ONAME:
-	case OLITERAL:
-		return n;
-
-	case ODOT:
-		l = safeexpr(n->left, init);
-		if(l == n->left)
-			return n;
-		r = nod(OXXX, N, N);
-		*r = *n;
-		r->left = l;
-		typecheck(&r, Erv);
-		walkexpr(&r, init);
-		return r;
-
-	case ODOTPTR:
-	case OIND:
-		l = safeexpr(n->left, init);
-		if(l == n->left)
-			return n;
-		a = nod(OXXX, N, N);
-		*a = *n;
-		a->left = l;
-		walkexpr(&a, init);
-		return a;
-
-	case OINDEX:
-	case OINDEXMAP:
-		l = safeexpr(n->left, init);
-		r = safeexpr(n->right, init);
-		if(l == n->left && r == n->right)
-			return n;
-		a = nod(OXXX, N, N);
-		*a = *n;
-		a->left = l;
-		a->right = r;
-		walkexpr(&a, init);
-		return a;
-	}
-
-	// make a copy; must not be used as an lvalue
-	if(islvalue(n))
-		fatal("missing lvalue case in safeexpr: %N", n);
-	return cheapexpr(n, init);
-}
-
-Node*
-copyexpr(Node *n, Type *t, NodeList **init)
-{
-	Node *a, *l;
-	
-	l = temp(t);
-	a = nod(OAS, l, n);
-	typecheck(&a, Etop);
-	walkexpr(&a, init);
-	*init = list(*init, a);
-	return l;
-}
-
-/*
- * return side-effect free and cheap n, appending side effects to init.
- * result may not be assignable.
- */
-Node*
-cheapexpr(Node *n, NodeList **init)
-{
-	switch(n->op) {
-	case ONAME:
-	case OLITERAL:
-		return n;
-	}
-
-	return copyexpr(n, n->type, init);
-}
-
-/*
- * return n in a local variable of type t if it is not already.
- * the value is guaranteed not to change except by direct
- * assignment to it.
- */
-Node*
-localexpr(Node *n, Type *t, NodeList **init)
-{
-	if(n->op == ONAME && (!n->addrtaken || strncmp(n->sym->name, "autotmp_", 8) == 0) &&
-		(n->class == PAUTO || n->class == PPARAM || n->class == PPARAMOUT) &&
-		convertop(n->type, t, nil) == OCONVNOP)
-		return n;
-	
-	return copyexpr(n, t, init);
-}
-
-void
-setmaxarg(Type *t)
-{
-	int64 w;
-
-	dowidth(t);
-	w = t->argwid;
-	if(t->argwid >= MAXWIDTH)
-		fatal("bad argwid %T", t);
-	if(w > maxarg)
-		maxarg = w;
-}
-
-/*
- * unicode-aware case-insensitive strcmp
- */
-
-static int
-ucistrcmp(char *p, char *q)
-{
-	Rune rp, rq;
-
-	while(*p || *q) {
-		if(*p == 0)
-			return +1;
-		if(*q == 0)
-			return -1;
-		p += chartorune(&rp, p);
-		q += chartorune(&rq, q);
-		rp = tolowerrune(rp);
-		rq = tolowerrune(rq);
-		if(rp < rq)
-			return -1;
-		if(rp > rq)
-			return +1;
-	}
-	return 0;
-}
-
-/*
- * code to resolve elided DOTs
- * in embedded types
- */
-
-// search depth 0 --
-// return count of fields+methods
-// found with a given name
-static int
-lookdot0(Sym *s, Type *t, Type **save, int ignorecase)
-{
-	Type *f, *u;
-	int c;
-
-	u = t;
-	if(isptr[u->etype])
-		u = u->type;
-
-	c = 0;
-	if(u->etype == TSTRUCT || u->etype == TINTER) {
-		for(f=u->type; f!=T; f=f->down)
-			if(f->sym == s || (ignorecase && f->type->etype == TFUNC && f->type->thistuple > 0 && ucistrcmp(f->sym->name, s->name) == 0)) {
-				if(save)
-					*save = f;
-				c++;
-			}
-	}
-	u = methtype(t, 0);
-	if(u != T) {
-		for(f=u->method; f!=T; f=f->down)
-			if(f->embedded == 0 && (f->sym == s || (ignorecase && ucistrcmp(f->sym->name, s->name) == 0))) {
-				if(save)
-					*save = f;
-				c++;
-			}
-	}
-	return c;
-}
-
-// search depth d for field/method s --
-// return count of fields+methods
-// found at search depth.
-// answer is in dotlist array and
-// count of number of ways is returned.
-int
-adddot1(Sym *s, Type *t, int d, Type **save, int ignorecase)
-{
-	Type *f, *u;
-	int c, a;
-
-	if(t->trecur)
-		return 0;
-	t->trecur = 1;
-
-	if(d == 0) {
-		c = lookdot0(s, t, save, ignorecase);
-		goto out;
-	}
-
-	c = 0;
-	u = t;
-	if(isptr[u->etype])
-		u = u->type;
-	if(u->etype != TSTRUCT && u->etype != TINTER)
-		goto out;
-
-	d--;
-	for(f=u->type; f!=T; f=f->down) {
-		if(!f->embedded)
-			continue;
-		if(f->sym == S)
-			continue;
-		a = adddot1(s, f->type, d, save, ignorecase);
-		if(a != 0 && c == 0)
-			dotlist[d].field = f;
-		c += a;
-	}
-
-out:
-	t->trecur = 0;
-	return c;
-}
-
-// in T.field
-// find missing fields that
-// will give shortest unique addressing.
-// modify the tree with missing type names.
-Node*
-adddot(Node *n)
-{
-	Type *t;
-	Sym *s;
-	int c, d;
-
-	typecheck(&n->left, Etype|Erv);
-	n->diag |= n->left->diag;
-	t = n->left->type;
-	if(t == T)
-		goto ret;
-	
-	if(n->left->op == OTYPE)
-		goto ret;
-
-	if(n->right->op != ONAME)
-		goto ret;
-	s = n->right->sym;
-	if(s == S)
-		goto ret;
-
-	for(d=0; d<nelem(dotlist); d++) {
-		c = adddot1(s, t, d, nil, 0);
-		if(c > 0)
-			goto out;
-	}
-	goto ret;
-
-out:
-	if(c > 1) {
-		yyerror("ambiguous selector %N", n);
-		n->left = N;
-		return n;
-	}
-
-	// rebuild elided dots
-	for(c=d-1; c>=0; c--)
-		n->left = nod(ODOT, n->left, newname(dotlist[c].field->sym));
-ret:
-	return n;
-}
-
-
-/*
- * code to help generate trampoline
- * functions for methods on embedded
- * subtypes.
- * these are approx the same as
- * the corresponding adddot routines
- * except that they expect to be called
- * with unique tasks and they return
- * the actual methods.
- */
-
-typedef	struct	Symlink	Symlink;
-struct	Symlink
-{
-	Type*		field;
-	uchar		good;
-	uchar		followptr;
-	Symlink*	link;
-};
-static	Symlink*	slist;
-
-static void
-expand0(Type *t, int followptr)
-{
-	Type *f, *u;
-	Symlink *sl;
-
-	u = t;
-	if(isptr[u->etype]) {
-		followptr = 1;
-		u = u->type;
-	}
-
-	if(u->etype == TINTER) {
-		for(f=u->type; f!=T; f=f->down) {
-			if(f->sym->flags & SymUniq)
-				continue;
-			f->sym->flags |= SymUniq;
-			sl = mal(sizeof(*sl));
-			sl->field = f;
-			sl->link = slist;
-			sl->followptr = followptr;
-			slist = sl;
-		}
-		return;
-	}
-
-	u = methtype(t, 0);
-	if(u != T) {
-		for(f=u->method; f!=T; f=f->down) {
-			if(f->sym->flags & SymUniq)
-				continue;
-			f->sym->flags |= SymUniq;
-			sl = mal(sizeof(*sl));
-			sl->field = f;
-			sl->link = slist;
-			sl->followptr = followptr;
-			slist = sl;
-		}
-	}
-}
-
-static void
-expand1(Type *t, int d, int followptr)
-{
-	Type *f, *u;
-
-	if(t->trecur)
-		return;
-	if(d == 0)
-		return;
-	t->trecur = 1;
-
-	if(d != nelem(dotlist)-1)
-		expand0(t, followptr);
-
-	u = t;
-	if(isptr[u->etype]) {
-		followptr = 1;
-		u = u->type;
-	}
-	if(u->etype != TSTRUCT && u->etype != TINTER)
-		goto out;
-
-	for(f=u->type; f!=T; f=f->down) {
-		if(!f->embedded)
-			continue;
-		if(f->sym == S)
-			continue;
-		expand1(f->type, d-1, followptr);
-	}
-
-out:
-	t->trecur = 0;
-}
-
-void
-expandmeth(Type *t)
-{
-	Symlink *sl;
-	Type *f;
-	int c, d;
-
-	if(t == T || t->xmethod != nil)
-		return;
-
-	// mark top-level method symbols
-	// so that expand1 doesn't consider them.
-	for(f=t->method; f != nil; f=f->down)
-		f->sym->flags |= SymUniq;
-
-	// generate all reachable methods
-	slist = nil;
-	expand1(t, nelem(dotlist)-1, 0);
-
-	// check each method to be uniquely reachable
-	for(sl=slist; sl!=nil; sl=sl->link) {
-		sl->field->sym->flags &= ~SymUniq;
-		for(d=0; d<nelem(dotlist); d++) {
-			c = adddot1(sl->field->sym, t, d, &f, 0);
-			if(c == 0)
-				continue;
-			if(c == 1) {
-				// addot1 may have dug out arbitrary fields, we only want methods.
-				if(f->type->etype == TFUNC && f->type->thistuple > 0) {
-					sl->good = 1;
-					sl->field = f;
-				}
-			}
-			break;
-		}
-	}
-
-	for(f=t->method; f != nil; f=f->down)
-		f->sym->flags &= ~SymUniq;
-
-	t->xmethod = t->method;
-	for(sl=slist; sl!=nil; sl=sl->link) {
-		if(sl->good) {
-			// add it to the base type method list
-			f = typ(TFIELD);
-			*f = *sl->field;
-			f->embedded = 1;	// needs a trampoline
-			if(sl->followptr)
-				f->embedded = 2;
-			f->down = t->xmethod;
-			t->xmethod = f;
-		}
-	}
-}
-
-/*
- * Given funarg struct list, return list of ODCLFIELD Node fn args.
- */
-static NodeList*
-structargs(Type **tl, int mustname)
-{
-	Iter savet;
-	Node *a, *n;
-	NodeList *args;
-	Type *t;
-	char buf[100];
-	int gen;
-
-	args = nil;
-	gen = 0;
-	for(t = structfirst(&savet, tl); t != T; t = structnext(&savet)) {
-		n = N;
-		if(mustname && (t->sym == nil || strcmp(t->sym->name, "_") == 0)) {
-			// invent a name so that we can refer to it in the trampoline
-			snprint(buf, sizeof buf, ".anon%d", gen++);
-			n = newname(lookup(buf));
-		} else if(t->sym)
-			n = newname(t->sym);
-		a = nod(ODCLFIELD, n, typenod(t->type));
-		a->isddd = t->isddd;
-		if(n != N)
-			n->isddd = t->isddd;
-		args = list(args, a);
-	}
-	return args;
-}
-
-/*
- * Generate a wrapper function to convert from
- * a receiver of type T to a receiver of type U.
- * That is,
- *
- *	func (t T) M() {
- *		...
- *	}
- *
- * already exists; this function generates
- *
- *	func (u U) M() {
- *		u.M()
- *	}
- *
- * where the types T and U are such that u.M() is valid
- * and calls the T.M method.
- * The resulting function is for use in method tables.
- *
- *	rcvr - U
- *	method - M func (t T)(), a TFIELD type struct
- *	newnam - the eventual mangled name of this function
- */
-void
-genwrapper(Type *rcvr, Type *method, Sym *newnam, int iface)
-{
-	Node *this, *fn, *call, *n, *t, *pad, *dot, *as;
-	NodeList *l, *args, *in, *out;
-	Type *tpad, *methodrcvr;
-	int isddd;
-	Val v;
-	static int linehistdone = 0;
-
-	if(0 && debug['r'])
-		print("genwrapper rcvrtype=%T method=%T newnam=%S\n",
-			rcvr, method, newnam);
-
-	lexlineno++;
-	lineno = lexlineno;
-	if (linehistdone == 0) {
-		// All the wrappers can share the same linehist entry.
-		linehist("<autogenerated>", 0, 0);
-		linehistdone = 1;
-	}
-
-	dclcontext = PEXTERN;
-	markdcl();
-
-	this = nod(ODCLFIELD, newname(lookup(".this")), typenod(rcvr));
-	this->left->ntype = this->right;
-	in = structargs(getinarg(method->type), 1);
-	out = structargs(getoutarg(method->type), 0);
-
-	t = nod(OTFUNC, N, N);
-	l = list1(this);
-	if(iface && rcvr->width < types[tptr]->width) {
-		// Building method for interface table and receiver
-		// is smaller than the single pointer-sized word
-		// that the interface call will pass in.
-		// Add a dummy padding argument after the
-		// receiver to make up the difference.
-		tpad = typ(TARRAY);
-		tpad->type = types[TUINT8];
-		tpad->bound = types[tptr]->width - rcvr->width;
-		pad = nod(ODCLFIELD, newname(lookup(".pad")), typenod(tpad));
-		l = list(l, pad);
-	}
-	t->list = concat(l, in);
-	t->rlist = out;
-
-	fn = nod(ODCLFUNC, N, N);
-	fn->nname = newname(newnam);
-	fn->nname->defn = fn;
-	fn->nname->ntype = t;
-	declare(fn->nname, PFUNC);
-	funchdr(fn);
-
-	// arg list
-	args = nil;
-	isddd = 0;
-	for(l=in; l; l=l->next) {
-		args = list(args, l->n->left);
-		isddd = l->n->left->isddd;
-	}
-	
-	methodrcvr = getthisx(method->type)->type->type;
-
-	// generate nil pointer check for better error
-	if(isptr[rcvr->etype] && rcvr->type == methodrcvr) {
-		// generating wrapper from *T to T.
-		n = nod(OIF, N, N);
-		n->ntest = nod(OEQ, this->left, nodnil());
-		// these strings are already in the reflect tables,
-		// so no space cost to use them here.
-		l = nil;
-		v.ctype = CTSTR;
-		v.u.sval = strlit(rcvr->type->sym->pkg->name);  // package name
-		l = list(l, nodlit(v));
-		v.u.sval = strlit(rcvr->type->sym->name);  // type name
-		l = list(l, nodlit(v));
-		v.u.sval = strlit(method->sym->name);
-		l = list(l, nodlit(v));  // method name
-		call = nod(OCALL, syslook("panicwrap", 0), N);
-		call->list = l;
-		n->nbody = list1(call);
-		fn->nbody = list(fn->nbody, n);
-	}
-	
-	dot = adddot(nod(OXDOT, this->left, newname(method->sym)));
-	
-	// generate call
-	if(!flag_race && isptr[rcvr->etype] && isptr[methodrcvr->etype] && method->embedded && !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])
-			dot = nod(OADDR, dot, N);
-		as = nod(OAS, this->left, nod(OCONVNOP, dot, N));
-		as->right->type = rcvr;
-		fn->nbody = list(fn->nbody, as);
-		n = nod(ORETJMP, N, N);
-		n->left = newname(methodsym(method->sym, methodrcvr, 0));
-		fn->nbody = list(fn->nbody, n);
-	} else {
-		fn->wrapper = 1; // ignore frame for panic+recover matching
-		call = nod(OCALL, dot, N);
-		call->list = args;
-		call->isddd = isddd;
-		if(method->type->outtuple > 0) {
-			n = nod(ORETURN, N, N);
-			n->list = list1(call);
-			call = n;
-		}
-		fn->nbody = list(fn->nbody, call);
-	}
-
-	if(0 && debug['r'])
-		dumplist("genwrapper body", fn->nbody);
-
-	funcbody(fn);
-	curfn = fn;
-	// wrappers where T is anonymous (struct or interface) can be duplicated.
-	if(rcvr->etype == TSTRUCT ||
-		rcvr->etype == TINTER ||
-		isptr[rcvr->etype] && rcvr->type->etype == TSTRUCT)
-		fn->dupok = 1;
-	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)
-		inl_nonlocal = 1;
-
-	inlcalls(fn);
-
-	inl_nonlocal = 0;
-
-	curfn = nil;
-	funccompile(fn, 0);
-}
-
-static Node*
-hashmem(Type *t)
-{
-	Node *tfn, *n;
-	Sym *sym;
-	
-	sym = pkglookup("memhash", runtimepkg);
-
-	n = newname(sym);
-	n->class = PFUNC;
-	tfn = nod(OTFUNC, N, N);
-	tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(ptrto(t))));
-	tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
-	tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
-	tfn->rlist = list(tfn->rlist, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
-	typecheck(&tfn, Etype);
-	n->type = tfn->type;
-	return n;
-}
-
-static Node*
-hashfor(Type *t)
-{
-	int a;
-	Sym *sym;
-	Node *tfn, *n;
-
-	a = algtype1(t, nil);
-	switch(a) {
-	case AMEM:
-		return hashmem(t);
-	case AINTER:
-		sym = pkglookup("interhash", runtimepkg);
-		break;
-	case ANILINTER:
-		sym = pkglookup("nilinterhash", runtimepkg);
-		break;
-	case ASTRING:
-		sym = pkglookup("strhash", runtimepkg);
-		break;
-	case AFLOAT32:
-		sym = pkglookup("f32hash", runtimepkg);
-		break;
-	case AFLOAT64:
-		sym = pkglookup("f64hash", runtimepkg);
-		break;
-	case ACPLX64:
-		sym = pkglookup("c64hash", runtimepkg);
-		break;
-	case ACPLX128:
-		sym = pkglookup("c128hash", runtimepkg);
-		break;
-	default:
-		sym = typesymprefix(".hash", t);
-		break;
-	}
-
-	n = newname(sym);
-	n->class = PFUNC;
-	tfn = nod(OTFUNC, N, N);
-	tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(ptrto(t))));
-	tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
-	tfn->list = list(tfn->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
-	tfn->rlist = list(tfn->rlist, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
-	typecheck(&tfn, Etype);
-	n->type = tfn->type;
-	return n;
-}
-
-/*
- * Generate a helper function to compute the hash of a value of type t.
- */
-void
-genhash(Sym *sym, Type *t)
-{
-	Node *n, *fn, *np, *nh, *ni, *call, *nx, *na, *tfn, *r;
-	Node *hashel;
-	Type *first, *t1;
-	int old_safemode;
-	int64 size, mul, offend;
-
-	if(debug['r'])
-		print("genhash %S %T\n", sym, t);
-
-	lineno = 1;  // less confusing than end of input
-	dclcontext = PEXTERN;
-	markdcl();
-
-	// func sym(p *T, s uintptr, h uintptr) uintptr
-	fn = nod(ODCLFUNC, N, N);
-	fn->nname = newname(sym);
-	fn->nname->class = PFUNC;
-	tfn = nod(OTFUNC, N, N);
-	fn->nname->ntype = tfn;
-
-	n = nod(ODCLFIELD, newname(lookup("p")), typenod(ptrto(t)));
-	tfn->list = list(tfn->list, n);
-	np = n->left;
-	n = nod(ODCLFIELD, newname(lookup("s")), typenod(types[TUINTPTR]));
-	tfn->list = list(tfn->list, n);
-	n = nod(ODCLFIELD, newname(lookup("h")), typenod(types[TUINTPTR]));
-	tfn->list = list(tfn->list, n);
-	nh = n->left;
-	n = nod(ODCLFIELD, N, typenod(types[TUINTPTR])); // return value
-	tfn->rlist = list(tfn->rlist, n);
-
-	funchdr(fn);
-	typecheck(&fn->nname->ntype, Etype);
-
-	// genhash is only called for types that have equality but
-	// cannot be handled by the standard algorithms,
-	// so t must be either an array or a struct.
-	switch(t->etype) {
-	default:
-		fatal("genhash %T", t);
-	case TARRAY:
-		if(isslice(t))
-			fatal("genhash %T", t);
-		// An array of pure memory would be handled by the
-		// standard algorithm, so the element type must not be
-		// pure memory.
-		hashel = hashfor(t->type);
-		n = nod(ORANGE, N, nod(OIND, np, N));
-		ni = newname(lookup("i"));
-		ni->type = types[TINT];
-		n->list = list1(ni);
-		n->colas = 1;
-		colasdefn(n->list, n);
-		ni = n->list->n;
-
-		// TODO: with aeshash we don't need these shift/mul parts
-
-		// h = h<<3 | h>>61
-		n->nbody = list(n->nbody,
-			nod(OAS,
-			    nh,
-				nod(OOR,
-					nod(OLSH, nh, nodintconst(3)),
-					nod(ORSH, nh, nodintconst(widthptr*8-3)))));
-
-		// h *= mul
-		// Same multipliers as in runtime.memhash.
-		if(widthptr == 4)
-			mul = 3267000013LL;
-		else
-			mul = 23344194077549503LL;
-		n->nbody = list(n->nbody,
-			nod(OAS,
-				nh,
-				nod(OMUL, nh, nodintconst(mul))));
-
-		// h = hashel(&p[i], sizeof(p[i]), h)
-		call = nod(OCALL, hashel, N);
-		nx = nod(OINDEX, np, ni);
-		nx->bounded = 1;
-		na = nod(OADDR, nx, N);
-		na->etype = 1;  // no escape to heap
-		call->list = list(call->list, na);
-		call->list = list(call->list, nodintconst(t->type->width));
-		call->list = list(call->list, nh);
-		n->nbody = list(n->nbody, nod(OAS, nh, call));
-
-		fn->nbody = list(fn->nbody, n);
-		break;
-
-	case TSTRUCT:
-		// Walk the struct using memhash for runs of AMEM
-		// and calling specific hash functions for the others.
-		first = T;
-		offend = 0;
-		for(t1=t->type;; t1=t1->down) {
-			if(t1 != T && algtype1(t1->type, nil) == AMEM && !isblanksym(t1->sym)) {
-				offend = t1->width + t1->type->width;
-				if(first == T)
-					first = t1;
-				// If it's a memory field but it's padded, stop here.
-				if(ispaddedfield(t1, t->width))
-					t1 = t1->down;
-				else
-					continue;
-			}
-			// Run memhash for fields up to this one.
-			if(first != T) {
-				size = offend - first->width; // first->width is offset
-				hashel = hashmem(first->type);
-				// h = hashel(&p.first, size, h)
-				call = nod(OCALL, hashel, N);
-				nx = nod(OXDOT, np, newname(first->sym));  // TODO: fields from other packages?
-				na = nod(OADDR, nx, N);
-				na->etype = 1;  // no escape to heap
-				call->list = list(call->list, na);
-				call->list = list(call->list, nodintconst(size));
-				call->list = list(call->list, nh);
-				fn->nbody = list(fn->nbody, nod(OAS, nh, call));
-
-				first = T;
-			}
-			if(t1 == T)
-				break;
-			if(isblanksym(t1->sym))
-				continue;
-
-			// Run hash for this field.
-			hashel = hashfor(t1->type);
-			// h = hashel(&p.t1, size, h)
-			call = nod(OCALL, hashel, N);
-			nx = nod(OXDOT, np, newname(t1->sym));  // TODO: fields from other packages?
-			na = nod(OADDR, nx, N);
-			na->etype = 1;  // no escape to heap
-			call->list = list(call->list, na);
-			call->list = list(call->list, nodintconst(t1->type->width));
-			call->list = list(call->list, nh);
-			fn->nbody = list(fn->nbody, nod(OAS, nh, call));
-		}
-		break;
-	}
-	r = nod(ORETURN, N, N);
-	r->list = list(r->list, nh);
-	fn->nbody = list(fn->nbody, r);
-
-	if(debug['r'])
-		dumplist("genhash body", fn->nbody);
-
-	funcbody(fn);
-	curfn = fn;
-	fn->dupok = 1;
-	typecheck(&fn, Etop);
-	typechecklist(fn->nbody, Etop);
-	curfn = nil;
-
-	// Disable safemode while compiling this code: the code we
-	// generate internally can refer to unsafe.Pointer.
-	// In this case it can happen if we need to generate an ==
-	// for a struct containing a reflect.Value, which itself has
-	// an unexported field of type unsafe.Pointer.
-	old_safemode = safemode;
-	safemode = 0;
-	funccompile(fn, 0);
-	safemode = old_safemode;
-}
-
-// Return node for
-//	if p.field != q.field { return false }
-static Node*
-eqfield(Node *p, Node *q, Node *field)
-{
-	Node *nif, *nx, *ny, *r;
-
-	nx = nod(OXDOT, p, field);
-	ny = nod(OXDOT, q, field);
-	nif = nod(OIF, N, N);
-	nif->ntest = nod(ONE, nx, ny);
-	r = nod(ORETURN, N, N);
-	r->list = list(r->list, nodbool(0));
-	nif->nbody = list(nif->nbody, r);
-	return nif;
-}
-
-static Node*
-eqmemfunc(vlong size, Type *type)
-{
-	char buf[30];
-	Node *fn;
-
-	switch(size) {
-	default:
-		fn = syslook("memequal", 1);
-		break;
-	case 1:
-	case 2:
-	case 4:
-	case 8:
-	case 16:
-		snprint(buf, sizeof buf, "memequal%d", (int)size*8);
-		fn = syslook(buf, 1);
-		break;
-	}
-	argtype(fn, type);
-	argtype(fn, type);
-	return fn;
-}
-
-// Return node for
-//	if !memequal(&p.field, &q.field, size) { return false }
-static Node*
-eqmem(Node *p, Node *q, Node *field, vlong size)
-{
-	Node *nif, *nx, *ny, *call, *r;
-
-	nx = nod(OADDR, nod(OXDOT, p, field), N);
-	nx->etype = 1;  // does not escape
-	ny = nod(OADDR, nod(OXDOT, q, field), N);
-	ny->etype = 1;  // does not escape
-	typecheck(&nx, Erv);
-	typecheck(&ny, Erv);
-
-	call = nod(OCALL, eqmemfunc(size, nx->type->type), N);
-	call->list = list(call->list, nx);
-	call->list = list(call->list, ny);
-	call->list = list(call->list, nodintconst(size));
-
-	nif = nod(OIF, N, N);
-	nif->ninit = list(nif->ninit, call);
-	nif->ntest = nod(ONOT, call, N);
-	r = nod(ORETURN, N, N);
-	r->list = list(r->list, nodbool(0));
-	nif->nbody = list(nif->nbody, r);
-	return nif;
-}
-
-/*
- * Generate a helper function to check equality of two values of type t.
- */
-void
-geneq(Sym *sym, Type *t)
-{
-	Node *n, *fn, *np, *nq, *tfn, *nif, *ni, *nx, *ny, *nrange, *r;
-	Type *t1, *first;
-	int old_safemode;
-	int64 size;
-	int64 offend;
-
-	if(debug['r'])
-		print("geneq %S %T\n", sym, t);
-
-	lineno = 1;  // less confusing than end of input
-	dclcontext = PEXTERN;
-	markdcl();
-
-	// func sym(p, q *T, s uintptr) bool
-	fn = nod(ODCLFUNC, N, N);
-	fn->nname = newname(sym);
-	fn->nname->class = PFUNC;
-	tfn = nod(OTFUNC, N, N);
-	fn->nname->ntype = tfn;
-
-	n = nod(ODCLFIELD, newname(lookup("p")), typenod(ptrto(t)));
-	tfn->list = list(tfn->list, n);
-	np = n->left;
-	n = nod(ODCLFIELD, newname(lookup("q")), typenod(ptrto(t)));
-	tfn->list = list(tfn->list, n);
-	nq = n->left;
-	n = nod(ODCLFIELD, newname(lookup("s")), typenod(types[TUINTPTR]));
-	tfn->list = list(tfn->list, n);
-	n = nod(ODCLFIELD, N, typenod(types[TBOOL]));
-	tfn->rlist = list(tfn->rlist, n);
-
-	funchdr(fn);
-
-	// geneq is only called for types that have equality but
-	// cannot be handled by the standard algorithms,
-	// so t must be either an array or a struct.
-	switch(t->etype) {
-	default:
-		fatal("geneq %T", t);
-	case TARRAY:
-		if(isslice(t))
-			fatal("geneq %T", t);
-		// An array of pure memory would be handled by the
-		// standard memequal, so the element type must not be
-		// pure memory.  Even if we unrolled the range loop,
-		// each iteration would be a function call, so don't bother
-		// unrolling.
-		nrange = nod(ORANGE, N, nod(OIND, np, N));
-		ni = newname(lookup("i"));
-		ni->type = types[TINT];
-		nrange->list = list1(ni);
-		nrange->colas = 1;
-		colasdefn(nrange->list, nrange);
-		ni = nrange->list->n;
-		
-		// if p[i] != q[i] { return false }
-		nx = nod(OINDEX, np, ni);
-		nx->bounded = 1;
-		ny = nod(OINDEX, nq, ni);
-		ny->bounded = 1;
-
-		nif = nod(OIF, N, N);
-		nif->ntest = nod(ONE, nx, ny);
-		r = nod(ORETURN, N, N);
-		r->list = list(r->list, nodbool(0));
-		nif->nbody = list(nif->nbody, r);
-		nrange->nbody = list(nrange->nbody, nif);
-		fn->nbody = list(fn->nbody, nrange);
-		break;
-
-	case TSTRUCT:
-		// Walk the struct using memequal for runs of AMEM
-		// and calling specific equality tests for the others.
-		// Skip blank-named fields.
-		first = T;
-		offend = 0;
-		for(t1=t->type;; t1=t1->down) {
-			if(t1 != T && algtype1(t1->type, nil) == AMEM && !isblanksym(t1->sym)) {
-				offend = t1->width + t1->type->width;
-				if(first == T)
-					first = t1;
-				// If it's a memory field but it's padded, stop here.
-				if(ispaddedfield(t1, t->width))
-					t1 = t1->down;
-				else
-					continue;
-			}
-			// Run memequal for fields up to this one.
-			// TODO(rsc): All the calls to newname are wrong for
-			// cross-package unexported fields.
-			if(first != T) {
-				if(first->down == t1) {
-					fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym)));
-				} else if(first->down->down == t1) {
-					fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym)));
-					first = first->down;
-					if(!isblanksym(first->sym))
-						fn->nbody = list(fn->nbody, eqfield(np, nq, newname(first->sym)));
-				} else {
-					// More than two fields: use memequal.
-					size = offend - first->width; // first->width is offset
-					fn->nbody = list(fn->nbody, eqmem(np, nq, newname(first->sym), size));
-				}
-				first = T;
-			}
-			if(t1 == T)
-				break;
-			if(isblanksym(t1->sym))
-				continue;
-
-			// Check this field, which is not just memory.
-			fn->nbody = list(fn->nbody, eqfield(np, nq, newname(t1->sym)));
-		}
-
-		break;
-	}
-
-	// return true
-	r = nod(ORETURN, N, N);
-	r->list = list(r->list, nodbool(1));
-	fn->nbody = list(fn->nbody, r);
-
-	if(debug['r'])
-		dumplist("geneq body", fn->nbody);
-
-	funcbody(fn);
-	curfn = fn;
-	fn->dupok = 1;
-	typecheck(&fn, Etop);
-	typechecklist(fn->nbody, Etop);
-	curfn = nil;
-	
-	// Disable safemode while compiling this code: the code we
-	// generate internally can refer to unsafe.Pointer.
-	// In this case it can happen if we need to generate an ==
-	// for a struct containing a reflect.Value, which itself has
-	// an unexported field of type unsafe.Pointer.
-	old_safemode = safemode;
-	safemode = 0;
-	funccompile(fn, 0);
-	safemode = old_safemode;
-}
-
-static Type*
-ifacelookdot(Sym *s, Type *t, int *followptr, int ignorecase)
-{
-	int i, c, d;
-	Type *m;
-
-	*followptr = 0;
-
-	if(t == T)
-		return T;
-
-	for(d=0; d<nelem(dotlist); d++) {
-		c = adddot1(s, t, d, &m, ignorecase);
-		if(c > 1) {
-			yyerror("%T.%S is ambiguous", t, s);
-			return T;
-		}
-		if(c == 1) {
-			for(i=0; i<d; i++) {
-				if(isptr[dotlist[i].field->type->etype]) {
-					*followptr = 1;
-					break;
-				}
-			}
-			if(m->type->etype != TFUNC || m->type->thistuple == 0) {
-				yyerror("%T.%S is a field, not a method", t, s);
-				return T;
-			}
-			return m;
-		}
-	}
-	return T;
-}
-
-int
-implements(Type *t, Type *iface, Type **m, Type **samename, int *ptr)
-{
-	Type *t0, *im, *tm, *rcvr, *imtype;
-	int followptr;
-
-	t0 = t;
-	if(t == T)
-		return 0;
-
-	// if this is too slow,
-	// could sort these first
-	// and then do one loop.
-
-	if(t->etype == TINTER) {
-		for(im=iface->type; im; im=im->down) {
-			for(tm=t->type; tm; tm=tm->down) {
-				if(tm->sym == im->sym) {
-					if(eqtype(tm->type, im->type))
-						goto found;
-					*m = im;
-					*samename = tm;
-					*ptr = 0;
-					return 0;
-				}
-			}
-			*m = im;
-			*samename = nil;
-			*ptr = 0;
-			return 0;
-		found:;
-		}
-		return 1;
-	}
-
-	t = methtype(t, 0);
-	if(t != T)
-		expandmeth(t);
-	for(im=iface->type; im; im=im->down) {
-		imtype = methodfunc(im->type, 0);
-		tm = ifacelookdot(im->sym, t, &followptr, 0);
-		if(tm == T || tm->nointerface || !eqtype(methodfunc(tm->type, 0), imtype)) {
-			if(tm == T)
-				tm = ifacelookdot(im->sym, t, &followptr, 1);
-			*m = im;
-			*samename = tm;
-			*ptr = 0;
-			return 0;
-		}
-		// if pointer receiver in method,
-		// the method does not exist for value types.
-		rcvr = getthisx(tm->type)->type->type;
-		if(isptr[rcvr->etype] && !isptr[t0->etype] && !followptr && !isifacemethod(tm->type)) {
-			if(0 && debug['r'])
-				yyerror("interface pointer mismatch");
-
-			*m = im;
-			*samename = nil;
-			*ptr = 1;
-			return 0;
-		}
-	}
-	return 1;
-}
-
-/*
- * even simpler simtype; get rid of ptr, bool.
- * assuming that the front end has rejected
- * all the invalid conversions (like ptr -> bool)
- */
-int
-simsimtype(Type *t)
-{
-	int et;
-
-	if(t == 0)
-		return 0;
-
-	et = simtype[t->etype];
-	switch(et) {
-	case TPTR32:
-		et = TUINT32;
-		break;
-	case TPTR64:
-		et = TUINT64;
-		break;
-	case TBOOL:
-		et = TUINT8;
-		break;
-	}
-	return et;
-}
-
-NodeList*
-concat(NodeList *a, NodeList *b)
-{
-	if(a == nil)
-		return b;
-	if(b == nil)
-		return a;
-
-	a->end->next = b;
-	a->end = b->end;
-	b->end = nil;
-	return a;
-}
-
-NodeList*
-list1(Node *n)
-{
-	NodeList *l;
-
-	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 = (NodeList*)1;
-		return l;
-	}
-	l = mal(sizeof *l);
-	l->n = n;
-	l->end = l;
-	return l;
-}
-
-NodeList*
-list(NodeList *l, Node *n)
-{
-	return concat(l, list1(n));
-}
-
-void
-listsort(NodeList** l, int(*f)(Node*, Node*))
-{
-	NodeList *l1, *l2, *le;
-
-	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
-
-	while ((l1 != nil) && (l2 != nil)) {
-		while ((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 
-}
-
-NodeList*
-listtreecopy(NodeList *l)
-{
-	NodeList *out;
-
-	out = nil;
-	for(; l; l=l->next)
-		out = list(out, treecopy(l->n));
-	return out;
-}
-
-Node*
-liststmt(NodeList *l)
-{
-	Node *n;
-
-	n = nod(OBLOCK, N, N);
-	n->list = l;
-	if(l)
-		n->lineno = l->n->lineno;
-	return n;
-}
-
-/*
- * return nelem of list
- */
-int
-count(NodeList *l)
-{
-	vlong n;
-
-	n = 0;
-	for(; l; l=l->next)
-		n++;
-	if((int)n != n) { // Overflow.
-		yyerror("too many elements in list");
-	}
-	return n;
-}
-
-/*
- * return nelem of list
- */
-int
-structcount(Type *t)
-{
-	int v;
-	Iter s;
-
-	v = 0;
-	for(t = structfirst(&s, &t); t != T; t = structnext(&s))
-		v++;
-	return v;
-}
-
-/*
- * return power of 2 of the constant
- * operand. -1 if it is not a power of 2.
- * 1000+ if it is a -(power of 2)
- */
-int
-powtwo(Node *n)
-{
-	uvlong v, b;
-	int i;
-
-	if(n == N || n->op != OLITERAL || n->type == T)
-		goto no;
-	if(!isint[n->type->etype])
-		goto no;
-
-	v = mpgetfix(n->val.u.xval);
-	b = 1ULL;
-	for(i=0; i<64; i++) {
-		if(b == v)
-			return i;
-		b = b<<1;
-	}
-
-	if(!issigned[n->type->etype])
-		goto no;
-
-	v = -v;
-	b = 1ULL;
-	for(i=0; i<64; i++) {
-		if(b == v)
-			return i+1000;
-		b = b<<1;
-	}
-
-no:
-	return -1;
-}
-
-/*
- * return the unsigned type for
- * a signed integer type.
- * returns T if input is not a
- * signed integer type.
- */
-Type*
-tounsigned(Type *t)
-{
-
-	// this is types[et+1], but not sure
-	// that this relation is immutable
-	switch(t->etype) {
-	default:
-		print("tounsigned: unknown type %T\n", t);
-		t = T;
-		break;
-	case TINT:
-		t = types[TUINT];
-		break;
-	case TINT8:
-		t = types[TUINT8];
-		break;
-	case TINT16:
-		t = types[TUINT16];
-		break;
-	case TINT32:
-		t = types[TUINT32];
-		break;
-	case TINT64:
-		t = types[TUINT64];
-		break;
-	}
-	return t;
-}
-
-/*
- * magic number for signed division
- * see hacker's delight chapter 10
- */
-void
-smagic(Magic *m)
-{
-	int p;
-	uint64 ad, anc, delta, q1, r1, q2, r2, t;
-	uint64 mask, two31;
-
-	m->bad = 0;
-	switch(m->w) {
-	default:
-		m->bad = 1;
-		return;
-	case 8:
-		mask = 0xffLL;
-		break;
-	case 16:
-		mask = 0xffffLL;
-		break;
-	case 32:
-		mask = 0xffffffffLL;
-		break;
-	case 64:
-		mask = 0xffffffffffffffffULL;
-		break;
-	}
-	two31 = mask ^ (mask>>1);
-
-	p = m->w-1;
-	ad = m->sd;
-	if(m->sd < 0)
-		ad = -(uvlong)m->sd;
-
-	// bad denominators
-	if(ad == 0 || ad == 1 || ad == two31) {
-		m->bad = 1;
-		return;
-	}
-
-	t = two31;
-	ad &= mask;
-
-	anc = t - 1 - t%ad;
-	anc &= mask;
-
-	q1 = two31/anc;
-	r1 = two31 - q1*anc;
-	q1 &= mask;
-	r1 &= mask;
-
-	q2 = two31/ad;
-	r2 = two31 - q2*ad;
-	q2 &= mask;
-	r2 &= mask;
-
-	for(;;) {
-		p++;
-		q1 <<= 1;
-		r1 <<= 1;
-		q1 &= mask;
-		r1 &= mask;
-		if(r1 >= anc) {
-			q1++;
-			r1 -= anc;
-			q1 &= mask;
-			r1 &= mask;
-		}
-
-		q2 <<= 1;
-		r2 <<= 1;
-		q2 &= mask;
-		r2 &= mask;
-		if(r2 >= ad) {
-			q2++;
-			r2 -= ad;
-			q2 &= mask;
-			r2 &= mask;
-		}
-
-		delta = ad - r2;
-		delta &= mask;
-		if(q1 < delta || (q1 == delta && r1 == 0)) {
-			continue;
-		}
-		break;
-	}
-
-	m->sm = q2+1;
-	if(m->sm & two31)
-		m->sm |= ~mask;
-	m->s = p-m->w;
-}
-
-/*
- * magic number for unsigned division
- * see hacker's delight chapter 10
- */
-void
-umagic(Magic *m)
-{
-	int p;
-	uint64 nc, delta, q1, r1, q2, r2;
-	uint64 mask, two31;
-
-	m->bad = 0;
-	m->ua = 0;
-
-	switch(m->w) {
-	default:
-		m->bad = 1;
-		return;
-	case 8:
-		mask = 0xffLL;
-		break;
-	case 16:
-		mask = 0xffffLL;
-		break;
-	case 32:
-		mask = 0xffffffffLL;
-		break;
-	case 64:
-		mask = 0xffffffffffffffffULL;
-		break;
-	}
-	two31 = mask ^ (mask>>1);
-
-	m->ud &= mask;
-	if(m->ud == 0 || m->ud == two31) {
-		m->bad = 1;
-		return;
-	}
-	nc = mask - (-m->ud&mask)%m->ud;
-	p = m->w-1;
-
-	q1 = two31/nc;
-	r1 = two31 - q1*nc;
-	q1 &= mask;
-	r1 &= mask;
-
-	q2 = (two31-1) / m->ud;
-	r2 = (two31-1) - q2*m->ud;
-	q2 &= mask;
-	r2 &= mask;
-
-	for(;;) {
-		p++;
-		if(r1 >= nc-r1) {
-			q1 <<= 1;
-			q1++;
-			r1 <<= 1;
-			r1 -= nc;
-		} else {
-			q1 <<= 1;
-			r1 <<= 1;
-		}
-		q1 &= mask;
-		r1 &= mask;
-		if(r2+1 >= m->ud-r2) {
-			if(q2 >= two31-1) {
-				m->ua = 1;
-			}
-			q2 <<= 1;
-			q2++;
-			r2 <<= 1;
-			r2++;
-			r2 -= m->ud;
-		} else {
-			if(q2 >= two31) {
-				m->ua = 1;
-			}
-			q2 <<= 1;
-			r2 <<= 1;
-			r2++;
-		}
-		q2 &= mask;
-		r2 &= mask;
-
-		delta = m->ud - 1 - r2;
-		delta &= mask;
-
-		if(p < m->w+m->w)
-		if(q1 < delta || (q1 == delta && r1 == 0)) {
-			continue;
-		}
-		break;
-	}
-	m->um = q2+1;
-	m->s = p-m->w;
-}
-
-Sym*
-ngotype(Node *n)
-{
-	if(n->type != T)
-		return typenamesym(n->type);
-	return S;
-}
-
-/*
- * Convert raw string to the prefix that will be used in the symbol
- * table.  All control characters, space, '%' and '"', as well as
- * non-7-bit clean bytes turn into %xx.  The period needs escaping
- * only in the last segment of the path, and it makes for happier
- * users if we escape that as little as possible.
- *
- * If you edit this, edit ../ld/lib.c:/^pathtoprefix too.
- * If you edit this, edit ../../debug/goobj/read.go:/importPathToPrefix too.
- */
-static char*
-pathtoprefix(char *s)
-{
-	static char hex[] = "0123456789abcdef";
-	char *p, *r, *w, *l;
-	int n;
-
-	// find first character past the last slash, if any.
-	l = s;
-	for(r=s; *r; r++)
-		if(*r == '/')
-			l = r+1;
-
-	// check for chars that need escaping
-	n = 0;
-	for(r=s; *r; r++)
-		if(*r <= ' ' || (*r == '.' && r >= l) || *r == '%' || *r == '"' || *r >= 0x7f)
-			n++;
-
-	// quick exit
-	if(n == 0)
-		return s;
-
-	// escape
-	p = mal((r-s)+1+2*n);
-	for(r=s, w=p; *r; r++) {
-		if(*r <= ' ' || (*r == '.' && r >= l) || *r == '%' || *r == '"' || *r >= 0x7f) {
-			*w++ = '%';
-			*w++ = hex[(*r>>4)&0xF];
-			*w++ = hex[*r&0xF];
-		} else
-			*w++ = *r;
-	}
-	*w = '\0';
-	return p;
-}
-
-Pkg*
-mkpkg(Strlit *path)
-{
-	Pkg *p;
-	int h;
-
-	h = stringhash(path->s) & (nelem(phash)-1);
-	for(p=phash[h]; p; p=p->link)
-		if(p->path->len == path->len && memcmp(path->s, p->path->s, path->len) == 0)
-			return p;
-
-	p = mal(sizeof *p);
-	p->path = path;
-	p->prefix = pathtoprefix(path->s);
-	p->link = phash[h];
-	phash[h] = p;
-	return p;
-}
-
-Strlit*
-strlit(char *s)
-{
-	Strlit *t;
-	
-	t = mal(sizeof *t + strlen(s));
-	strcpy(t->s, s);
-	t->len = strlen(s);
-	return t;
-}
-
-void
-addinit(Node **np, NodeList *init)
-{
-	Node *n;
-	
-	if(init == nil)
-		return;
-
-	n = *np;
-	switch(n->op) {
-	case ONAME:
-	case OLITERAL:
-		// There may be multiple refs to this node;
-		// introduce OCONVNOP to hold init list.
-		n = nod(OCONVNOP, n, N);
-		n->type = n->left->type;
-		n->typecheck = 1;
-		*np = n;
-		break;
-	}
-	n->ninit = concat(init, n->ninit);
-	n->ullman = UINF;
-}
-
-static char* reservedimports[] = {
-	"go",
-	"type",
-};
-
-int
-isbadimport(Strlit *path)
-{
-	int i;
-	char *s;
-	Rune r;
-
-	if(strlen(path->s) != path->len) {
-		yyerror("import path contains NUL");
-		return 1;
-	}
-	
-	for(i=0; i<nelem(reservedimports); i++) {
-		if(strcmp(path->s, reservedimports[i]) == 0) {
-			yyerror("import path \"%s\" is reserved and cannot be used", path->s);
-			return 1;
-		}
-	}
-
-	s = path->s;
-	while(*s) {
-		s += chartorune(&r, s);
-		if(r == Runeerror) {
-			yyerror("import path contains invalid UTF-8 sequence: \"%Z\"", path);
-			return 1;
-		}
-		if(r < 0x20 || r == 0x7f) {
-			yyerror("import path contains control character: \"%Z\"", path);
-			return 1;
-		}
-		if(r == '\\') {
-			yyerror("import path contains backslash; use slash: \"%Z\"", path);
-			return 1;
-		}
-		if(isspacerune(r)) {
-			yyerror("import path contains space character: \"%Z\"", path);
-			return 1;
-		}
-		if(utfrune("!\"#$%&'()*,:;<=>?[]^`{|}", r)) {
-			yyerror("import path contains invalid character '%C': \"%Z\"", r, path);
-			return 1;
-		}
-	}
-	return 0;
-}
-
-void
-checknil(Node *x, NodeList **init)
-{
-	Node *n;
-	
-	if(isinter(x->type)) {
-		x = nod(OITAB, x, N);
-		typecheck(&x, Erv);
-	}
-	n = nod(OCHECKNIL, x, N);
-	n->typecheck = 1;
-	*init = list(*init, n);
-}
-
-/*
- * Can this type be stored directly in an interface word?
- */
-int
-isdirectiface(Type *t)
-{
-	// Setting IfacePointerOnly = 1 changes the
-	// interface representation so that the data word
-	// in an interface value must always be a pointer.
-	// Setting it to 0 uses the original representation,
-	// where the data word can hold a pointer or any
-	// non-pointer value no bigger than a pointer.
-	enum {
-		IfacePointerOnly = 1,
-	};
-
-	if(IfacePointerOnly) {
-		switch(t->etype) {
-		case TPTR32:
-		case TPTR64:
-		case TCHAN:
-		case TMAP:
-		case TFUNC:
-		case TUNSAFEPTR:
-			return 1;
-		case TARRAY:
-			// Array of 1 direct iface type can be direct.
-			return t->bound == 1 && isdirectiface(t->type);
-		case TSTRUCT:
-			// Struct with 1 field of direct iface type can be direct.
-			return t->type != T && t->type->down == T && isdirectiface(t->type->type);
-		}
-		return 0;
-	}
-	
-	dowidth(t);
-	return t->width <= widthptr;
-}
diff --git a/src/cmd/gc/swt.c b/src/cmd/gc/swt.c
deleted file mode 100644
index e1d8af8..0000000
--- a/src/cmd/gc/swt.c
+++ /dev/null
@@ -1,948 +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	<u.h>
-#include	<libc.h>
-#include	"go.h"
-
-enum
-{
-	Snorm		= 0,
-	Strue,
-	Sfalse,
-	Stype,
-
-	Tdefault,	// default case
-	Texprconst,	// normal constant case
-	Texprvar,	// normal variable case
-	Ttypenil,	// case nil
-	Ttypeconst,	// type hashes
-	Ttypevar,	// interface type
-
-	Ncase	= 4,	// count needed to split
-};
-
-typedef	struct	Case	Case;
-struct	Case
-{
-	Node*	node;		// points at case statement
-	uint32	hash;		// hash of a type switch
-	uint8	type;		// type of case
-	uint8	diag;		// suppress multiple diagnostics
-	uint16	ordinal;	// position in switch
-	Case*	link;		// linked list to link
-};
-#define	C	((Case*)nil)
-/*c2go Case *C; */
-
-void
-dumpcase(Case *c0)
-{
-	Case *c;
-
-	for(c=c0; c!=C; c=c->link) {
-		switch(c->type) {
-		case Tdefault:
-			print("case-default\n");
-			print("	ord=%d\n", c->ordinal);
-			break;
-		case Texprconst:
-			print("case-exprconst\n");
-			print("	ord=%d\n", c->ordinal);
-			break;
-		case Texprvar:
-			print("case-exprvar\n");
-			print("	ord=%d\n", c->ordinal);
-			print("	op=%O\n", c->node->left->op);
-			break;
-		case Ttypenil:
-			print("case-typenil\n");
-			print("	ord=%d\n", c->ordinal);
-			break;
-		case Ttypeconst:
-			print("case-typeconst\n");
-			print("	ord=%d\n", c->ordinal);
-			print("	hash=%ux\n", c->hash);
-			break;
-		case Ttypevar:
-			print("case-typevar\n");
-			print("	ord=%d\n", c->ordinal);
-			break;
-		default:
-			print("case-???\n");
-			print("	ord=%d\n", c->ordinal);
-			print("	op=%O\n", c->node->left->op);
-			print("	hash=%ux\n", c->hash);
-			break;
-		}
-	}
-	print("\n");
-}
-
-static int
-ordlcmp(Case *c1, Case *c2)
-{
-	// 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;
-}
-
-static int
-exprcmp(Case *c1, Case *c2)
-{
-	int ct, n;
-	Node *n1, *n2;
-
-	// 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 = n1->val.ctype;
-	if(ct != n2->val.ctype)
-		return ct - 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);
-		break;
-	case CTINT:
-	case CTRUNE:
-		n = mpcmpfixfix(n1->val.u.xval, n2->val.u.xval);
-		break;
-	case CTSTR:
-		n = cmpslit(n1, n2);
-		break;
-	}
-
-	return n;
-}
-
-static int
-typecmp(Case *c1, Case *c2)
-{
-
-	// 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;
-}
-
-static Case*
-csort(Case *l, int(*f)(Case*, Case*))
-{
-	Case *l1, *l2, *le;
-
-	if(l == C || l->link == C)
-		return l;
-
-	l1 = l;
-	l2 = l;
-	for(;;) {
-		l2 = l2->link;
-		if(l2 == C)
-			break;
-		l2 = l2->link;
-		if(l2 == C)
-			break;
-		l1 = l1->link;
-	}
-
-	l2 = l1->link;
-	l1->link = C;
-	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 == C) {
-			while(l2) {
-				le->link = l2;
-				le = l2;
-				l2 = l2->link;
-			}
-			le->link = C;
-			break;
-		}
-		if(l2 == C) {
-			while(l1) {
-				le->link = l1;
-				le = l1;
-				l1 = l1->link;
-			}
-			break;
-		}
-		if((*f)(l1, l2) < 0) {
-			le->link = l1;
-			le = l1;
-			l1 = l1->link;
-		} else {
-			le->link = l2;
-			le = l2;
-			l2 = l2->link;
-		}
-	}
-	le->link = C;
-	return l;
-}
-
-static Node*
-newlabel(void)
-{
-	static int label;
-
-	label++;
-	snprint(namebuf, sizeof(namebuf), "%.6d", label);
-	return newname(lookup(namebuf));
-}
-
-/*
- * build separate list of statements and cases
- * make labels between cases and statements
- * deal with fallthrough, break, unreachable statements
- */
-static void
-casebody(Node *sw, Node *typeswvar)
-{
-	Node *n, *c, *last;
-	Node *def;
-	NodeList *cas, *stat, *l, *lc;
-	Node *go, *br;
-	int32 lno, needvar;
-
-	if(sw->list == nil)
-		return;
-
-	lno = setlineno(sw);
-
-	cas = nil;	// cases
-	stat = nil;	// statements
-	def = N;	// defaults
-	br = nod(OBREAK, N, N);
-
-	for(l=sw->list; l; l=l->next) {
-		n = l->n;
-		setlineno(n);
-		if(n->op != OXCASE)
-			fatal("casebody %O", n->op);
-		n->op = OCASE;
-		needvar = count(n->list) != 1 || n->list->n->op == OLITERAL;
-
-		go = nod(OGOTO, newlabel(), N);
-		if(n->list == nil) {
-			if(def != N)
-				yyerror("more than one default case");
-			// reuse original default case
-			n->right = go;
-			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;
-			n->list = nil;
-			cas = list(cas, n);
-		} else {
-			// expand multi-valued cases
-			for(lc=n->list; lc; lc=lc->next) {
-				c = lc->n;
-				cas = list(cas, nod(OCASE, c, go));
-			}
-		}
-
-		stat = list(stat, nod(OLABEL, go->left, N));
-		if(typeswvar && needvar && n->nname != N) {
-			NodeList *l;
-
-			l = list1(nod(ODCL, n->nname, N));
-			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;
-		if(last->xoffset == n->xoffset && last->op == OXFALL) {
-			if(typeswvar) {
-				setlineno(last);
-				yyerror("cannot fallthrough in type switch");
-			}
-			if(l->next == nil) {
-				setlineno(last);
-				yyerror("cannot fallthrough final case in switch");
-			}
-			last->op = OFALL;
-		} else
-			stat = list(stat, br);
-	}
-
-	stat = list(stat, br);
-	if(def)
-		cas = list(cas, def);
-
-	sw->list = cas;
-	sw->nbody = stat;
-	lineno = lno;
-}
-
-static Case*
-mkcaselist(Node *sw, int arg)
-{
-	Node *n;
-	Case *c, *c1, *c2;
-	NodeList *l;
-	int ord;
-
-	c = C;
-	ord = 0;
-
-	for(l=sw->list; l; l=l->next) {
-		n = l->n;
-		c1 = mal(sizeof(*c1));
-		c1->link = c;
-		c = c1;
-
-		ord++;
-		if((uint16)ord != ord)
-			fatal("too many cases in switch");
-		c->ordinal = ord;
-		c->node = n;
-
-		if(n->left == N) {
-			c->type = Tdefault;
-			continue;
-		}
-
-		switch(arg) {
-		case Stype:
-			c->hash = 0;
-			if(n->left->op == OLITERAL) {
-				c->type = Ttypenil;
-				continue;
-			}
-			if(istype(n->left->type, TINTER)) {
-				c->type = Ttypevar;
-				continue;
-			}
-
-			c->hash = typehash(n->left->type);
-			c->type = Ttypeconst;
-			continue;
-
-		case Snorm:
-		case Strue:
-		case Sfalse:
-			c->type = Texprvar;
-			c->hash = typehash(n->left->type);
-			switch(consttype(n->left)) {
-			case CTFLT:
-			case CTINT:
-			case CTRUNE:
-			case CTSTR:
-				c->type = Texprconst;
-			}
-			continue;
-		}
-	}
-
-	if(c == C)
-		return C;
-
-	// sort by value and diagnose duplicate cases
-	switch(arg) {
-	case Stype:
-		c = csort(c, typecmp);
-		for(c1=c; c1!=C; c1=c1->link) {
-			for(c2=c1->link; c2!=C && c2->hash==c1->hash; c2=c2->link) {
-				if(c1->type == Ttypenil || c1->type == Tdefault)
-					break;
-				if(c2->type == Ttypenil || c2->type == Tdefault)
-					break;
-				if(!eqtype(c1->node->left->type, c2->node->left->type))
-					continue;
-				yyerrorl(c2->node->lineno, "duplicate case %T in type switch\n\tprevious case at %L", c2->node->left->type, c1->node->lineno);
-			}
-		}
-		break;
-	case Snorm:
-	case Strue:
-	case Sfalse:
-		c = csort(c, exprcmp);
-		for(c1=c; c1->link!=C; c1=c1->link) {
-			if(exprcmp(c1, c1->link) != 0)
-				continue;
-			setlineno(c1->link->node);
-			yyerror("duplicate case %N in switch\n\tprevious case at %L", c1->node->left, c1->node->lineno);
-		}
-		break;
-	}
-
-	// put list back in processing order
-	c = csort(c, ordlcmp);
-	return c;
-}
-
-static	Node*	exprname;
-
-static Node*
-exprbsw(Case *c0, int ncase, int arg)
-{
-	NodeList *cas;
-	Node *a, *n;
-	Case *c;
-	int i, half, lno;
-
-	cas = nil;
-	if(ncase < Ncase) {
-		for(i=0; i<ncase; i++) {
-			n = c0->node;
-			lno = setlineno(n);
-
-			if(assignop(n->left->type, exprname->type, nil) == OCONVIFACE ||
-			   assignop(exprname->type, n->left->type, nil) == OCONVIFACE)
-				goto snorm;
-
-			switch(arg) {
-			case Strue:
-				a = nod(OIF, N, N);
-				a->ntest = n->left;			// if val
-				a->nbody = list1(n->right);			// then goto l
-				break;
-
-			case Sfalse:
-				a = nod(OIF, N, N);
-				a->ntest = nod(ONOT, n->left, N);	// if !val
-				typecheck(&a->ntest, Erv);
-				a->nbody = list1(n->right);			// then goto l
-				break;
-
-			default:
-			snorm:
-				a = nod(OIF, N, N);
-				a->ntest = nod(OEQ, exprname, n->left);	// if name == val
-				typecheck(&a->ntest, Erv);
-				a->nbody = list1(n->right);			// then goto l
-				break;
-			}
-
-			cas = list(cas, a);
-			c0 = c0->link;
-			lineno = 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, N, N);
-	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.
- * rebulid case statements into if .. goto
- */
-static void
-exprswitch(Node *sw)
-{
-	Node *def;
-	NodeList *cas;
-	Node *a;
-	Case *c0, *c, *c1;
-	Type *t;
-	int arg, ncase;
-
-	casebody(sw, N);
-
-	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 == T)
-		return;
-
-	/*
-	 * convert the switch into OIF statements
-	 */
-	exprname = N;
-	cas = nil;
-	if(arg != Strue && arg != Sfalse) {
-		exprname = temp(sw->ntest->type);
-		cas = list1(nod(OAS, exprname, sw->ntest));
-		typechecklist(cas, Etop);
-	} else {
-		exprname = nodbool(arg == Strue);
-	}
-
-	c0 = mkcaselist(sw, arg);
-	if(c0 != C && c0->type == Tdefault) {
-		def = c0->node->right;
-		c0 = c0->link;
-	} else {
-		def = nod(OBREAK, N, N);
-	}
-
-loop:
-	if(c0 == C) {
-		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] || 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!=C; c=c->link) {
-		if(c->link->type != Texprconst)
-			break;
-		ncase++;
-	}
-
-	// break the chain at the count
-	c1 = c->link;
-	c->link = C;
-
-	// sort and compile constants
-	c0 = csort(c0, exprcmp);
-	a = exprbsw(c0, ncase, arg);
-	cas = list(cas, a);
-
-	c0 = c1;
-	goto loop;
-
-}
-
-static	Node*	hashname;
-static	Node*	facename;
-static	Node*	boolname;
-
-static Node*
-typeone(Node *t)
-{
-	NodeList *init;
-	Node *a, *b, *var;
-
-	var = t->nname;
-	init = nil;
-	if(var == N) {
-		typecheck(&nblank, Erv | Easgn);
-		var = nblank;
-	} else
-		init = list1(nod(ODCL, var, N));
-
-	a = nod(OAS2, N, N);
-	a->list = list(list1(var), boolname);	// var,bool =
-	b = nod(ODOTTYPE, facename, N);
-	b->type = t->left->type;		// interface.(type)
-	a->rlist = list1(b);
-	typecheck(&a, Etop);
-	init = list(init, a);
-
-	b = nod(OIF, N, N);
-	b->ntest = boolname;
-	b->nbody = list1(t->right);		// if bool { goto l }
-	a = liststmt(list(init, b));
-	return a;
-}
-
-static Node*
-typebsw(Case *c0, int ncase)
-{
-	NodeList *cas;
-	Node *a, *n;
-	Case *c;
-	int i, half;
-
-	cas = nil;
-
-	if(ncase < Ncase) {
-		for(i=0; i<ncase; i++) {
-			n = c0->node;
-			if(c0->type != Ttypeconst)
-				fatal("typebsw");
-			a = nod(OIF, N, N);
-			a->ntest = nod(OEQ, hashname, nodintconst(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, N, N);
-	a->ntest = nod(OLE, hashname, nodintconst(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
- */
-static void
-typeswitch(Node *sw)
-{
-	Node *def;
-	NodeList *cas, *hash;
-	Node *a, *n;
-	Case *c, *c0, *c1;
-	int ncase;
-	Type *t;
-	Val v;
-
-	if(sw->ntest == nil)
-		return;
-	if(sw->ntest->right == nil) {
-		setlineno(sw);
-		yyerror("type switch must have an assignment");
-		return;
-	}
-	walkexpr(&sw->ntest->right, &sw->ninit);
-	if(!istype(sw->ntest->right->type, TINTER)) {
-		yyerror("type switch must be on an interface");
-		return;
-	}
-	cas = nil;
-
-	/*
-	 * predeclare temporary variables
-	 * and the boolean var
-	 */
-	facename = temp(sw->ntest->right->type);
-	a = nod(OAS, facename, sw->ntest->right);
-	typecheck(&a, Etop);
-	cas = list(cas, a);
-
-	casebody(sw, facename);
-
-	boolname = temp(types[TBOOL]);
-	typecheck(&boolname, Erv);
-
-	hashname = temp(types[TUINT32]);
-	typecheck(&hashname, Erv);
-
-	t = sw->ntest->right->type;
-	if(isnilinter(t))
-		a = syslook("efacethash", 1);
-	else
-		a = syslook("ifacethash", 1);
-	argtype(a, t);
-	a = nod(OCALL, a, N);
-	a->list = list1(facename);
-	a = nod(OAS, hashname, a);
-	typecheck(&a, Etop);
-	cas = list(cas, a);
-
-	c0 = mkcaselist(sw, Stype);
-	if(c0 != C && c0->type == Tdefault) {
-		def = c0->node->right;
-		c0 = c0->link;
-	} else {
-		def = nod(OBREAK, N, N);
-	}
-	
-	/*
-	 * insert if statement into each case block
-	 */
-	for(c=c0; c!=C; c=c->link) {
-		n = c->node;
-		switch(c->type) {
-
-		case Ttypenil:
-			v.ctype = CTNIL;
-			a = nod(OIF, N, N);
-			a->ntest = nod(OEQ, facename, nodlit(v));
-			typecheck(&a->ntest, Erv);
-			a->nbody = list1(n->right);		// if i==nil { goto l }
-			n->right = a;
-			break;
-		
-		case Ttypevar:
-		case Ttypeconst:
-			n->right = typeone(n);
-			break;
-		}
-	}
-
-	/*
-	 * generate list of if statements, binary search for constant sequences
-	 */
-	while(c0 != C) {
-		if(c0->type != Ttypeconst) {
-			n = c0->node;
-			cas = list(cas, n->right);
-			c0=c0->link;
-			continue;
-		}
-		
-		// identify run of constants
-		c1 = c = c0;
-		while(c->link!=C && c->link->type==Ttypeconst)
-			c = c->link;
-		c0 = c->link;
-		c->link = nil;
-
-		// sort by hash
-		c1 = csort(c1, typecmp);
-		
-		// for debugging: linear search
-		if(0) {
-			for(c=c1; c!=C; c=c->link) {
-				n = c->node;
-				cas = list(cas, n->right);
-			}
-			continue;
-		}
-
-		// combine adjacent cases with the same hash
-		ncase = 0;
-		for(c=c1; c!=C; c=c->link) {
-			ncase++;
-			hash = list1(c->node->right);
-			while(c->link != C && c->link->hash == c->hash) {
-				hash = list(hash, c->link->node->right);
-				c->link = c->link->link;
-			}
-			c->node->right = liststmt(hash);
-		}
-		
-		// binary search among cases to narrow by hash
-		cas = list(cas, typebsw(c1, ncase));
-	}
-	if(nerrors == 0) {
-		cas = list(cas, def);
-		sw->nbody = concat(cas, sw->nbody);
-		sw->list = nil;
-		walkstmtlist(sw->nbody);
-	}
-}
-
-void
-walkswitch(Node *sw)
-{
-	/*
-	 * reorder the body into (OLIST, cases, statements)
-	 * cases have OGOTO into statements.
-	 * both have inserted OBREAK statements
-	 */
-	if(sw->ntest == N) {
-		sw->ntest = nodbool(1);
-		typecheck(&sw->ntest, Erv);
-	}
-
-	if(sw->ntest->op == OTYPESW) {
-		typeswitch(sw);
-//dump("sw", sw);
-		return;
-	}
-	exprswitch(sw);
-	// Discard old AST elements after a walk. They can confuse racewealk.
-	sw->ntest = nil;
-	sw->list = nil;
-}
-
-/*
- * type check switch statement
- */
-void
-typecheckswitch(Node *n)
-{
-	int top, lno, ptr;
-	char *nilonly;
-	Type *t, *badtype, *missing, *have;
-	NodeList *l, *ll;
-	Node *ncase, *nvar;
-	Node *def;
-
-	lno = lineno;
-	typechecklist(n->ninit, Etop);
-	nilonly = nil;
-
-	if(n->ntest != N && n->ntest->op == OTYPESW) {
-		// type switch
-		top = Etype;
-		typecheck(&n->ntest->right, Erv);
-		t = n->ntest->right->type;
-		if(t != T && t->etype != TINTER)
-			yyerror("cannot type switch on non-interface value %lN", n->ntest->right);
-	} else {
-		// value switch
-		top = Erv;
-		if(n->ntest) {
-			typecheck(&n->ntest, Erv);
-			defaultlit(&n->ntest, T);
-			t = n->ntest->type;
-		} else
-			t = types[TBOOL];
-		if(t) {
-			if(!okforeq[t->etype])
-				yyerror("cannot switch on %lN", n->ntest);
-			else if(t->etype == TARRAY && !isfixedarray(t))
-				nilonly = "slice";
-			else if(t->etype == TARRAY && isfixedarray(t) && algtype1(t, nil) == ANOEQ)
-				yyerror("cannot switch on %lN", n->ntest);
-			else if(t->etype == TSTRUCT && algtype1(t, &badtype) == ANOEQ)
-				yyerror("cannot switch on %lN (struct containing %T cannot be compared)", n->ntest, badtype);
-			else if(t->etype == TFUNC)
-				nilonly = "func";
-			else if(t->etype == TMAP)
-				nilonly = "map";
-		}
-	}
-	n->type = t;
-
-	def = N;
-	for(l=n->list; l; l=l->next) {
-		ncase = l->n;
-		setlineno(n);
-		if(ncase->list == nil) {
-			// default
-			if(def != N)
-				yyerror("multiple defaults in switch (first at %L)", def->lineno);
-			else
-				def = ncase;
-		} else {
-			for(ll=ncase->list; ll; ll=ll->next) {
-				setlineno(ll->n);
-				typecheck(&ll->n, Erv | Etype);
-				if(ll->n->type == T || t == T)
-					continue;
-				setlineno(ncase);
-				switch(top) {
-				case Erv:	// expression switch
-					defaultlit(&ll->n, t);
-					if(ll->n->op == OTYPE)
-						yyerror("type %T is not an expression", ll->n->type);
-					else if(ll->n->type != T && !assignop(ll->n->type, t, nil) && !assignop(t, ll->n->type, nil)) {
-						if(n->ntest)
-							yyerror("invalid case %N in switch on %N (mismatched types %T and %T)", ll->n, n->ntest, ll->n->type, t);
-						else
-							yyerror("invalid case %N in switch (mismatched types %T and bool)", ll->n, ll->n->type);
-					} else if(nilonly && !isconst(ll->n, CTNIL)) {
-						yyerror("invalid case %N in switch (can only compare %s %N to nil)", ll->n, nilonly, n->ntest);
-					}
-					break;
-				case Etype:	// type switch
-					if(ll->n->op == OLITERAL && istype(ll->n->type, TNIL)) {
-						;
-					} else if(ll->n->op != OTYPE && ll->n->type != T) {  // should this be ||?
-						yyerror("%lN is not a type", ll->n);
-						// 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 && !missing->broke && !have->broke)
-							yyerror("impossible type switch case: %lN cannot have dynamic type %T"
-								" (wrong type for %S method)\n\thave %S%hT\n\twant %S%hT",
-								n->ntest->right, ll->n->type, missing->sym, have->sym, have->type,
-								missing->sym, missing->type);
-						else if(!missing->broke)
-							yyerror("impossible type switch case: %lN cannot have dynamic type %T"
-								" (missing %S method)", n->ntest->right, ll->n->type, missing->sym);
-					}
-					break;
-				}
-			}
-		}
-		if(top == Etype && n->type != T) {
-			ll = ncase->list;
-			nvar = ncase->nname;
-			if(nvar != N) {
-				if(ll && ll->next == nil && ll->n->type != T && !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);
-				}
-			}
-		}
-		typechecklist(ncase->nbody, Etop);
-	}
-
-	lineno = lno;
-}
diff --git a/src/cmd/gc/typecheck.c b/src/cmd/gc/typecheck.c
deleted file mode 100644
index ce12f15..0000000
--- a/src/cmd/gc/typecheck.c
+++ /dev/null
@@ -1,3582 +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.
-
-/*
- * type check the whole tree of an expression.
- * calculates expression types.
- * evaluates compile time constants.
- * marks variables that escape the local frame.
- * rewrites n->op to be more specific in some cases.
- */
-
-#include <u.h>
-#include <libc.h>
-#include "go.h"
-
-static void	implicitstar(Node**);
-static int	onearg(Node*, char*, ...);
-static int	twoarg(Node*);
-static int	lookdot(Node*, Type*, int);
-static int	looktypedot(Node*, Type*, int);
-static void	typecheckaste(int, Node*, int, Type*, NodeList*, char*);
-static Type*	lookdot1(Node*, Sym *s, Type *t, Type *f, int);
-static int	nokeys(NodeList*);
-static void	typecheckcomplit(Node**);
-static void	typecheckas2(Node*);
-static void	typecheckas(Node*);
-static void	typecheckfunc(Node*);
-static void	checklvalue(Node*, char*);
-static void	checkassign(Node*);
-static void	checkassignlist(NodeList*);
-static void	stringtoarraylit(Node**);
-static Node*	resolve(Node*);
-static void	checkdefergo(Node*);
-static int	checkmake(Type*, char*, Node*);
-static int	checksliceindex(Node*, Node*, Type*);
-static int	checksliceconst(Node*, Node*);
-
-static	NodeList*	typecheckdefstack;
-
-/*
- * resolve ONONAME to definition, if any.
- */
-static Node*
-resolve(Node *n)
-{
-	Node *r;
-
-	if(n != N && n->op == ONONAME && n->sym != S && (r = n->sym->def) != N) {
-		if(r->op != OIOTA)
-			n = r;
-		else if(n->iota >= 0)
-			n = nodintconst(n->iota);
-	}
-	return n;
-}
-
-void
-typechecklist(NodeList *l, int top)
-{
-	for(; l; l=l->next)
-		typecheck(&l->n, top);
-}
-
-static char* _typekind[] = {
-	[TINT]		= "int",
-	[TUINT]		= "uint",
-	[TINT8]		= "int8",
-	[TUINT8]	= "uint8",
-	[TINT16]	= "int16",
-	[TUINT16]	= "uint16",
-	[TINT32]	= "int32",
-	[TUINT32]	= "uint32",
-	[TINT64]	= "int64",
-	[TUINT64]	= "uint64",
-	[TUINTPTR]	= "uintptr",
-	[TCOMPLEX64]	= "complex64",
-	[TCOMPLEX128]	= "complex128",
-	[TFLOAT32]	= "float32",
-	[TFLOAT64]	= "float64",
-	[TBOOL]		= "bool",
-	[TSTRING]	= "string",
-	[TPTR32]	= "pointer",
-	[TPTR64]	= "pointer",
-	[TUNSAFEPTR]	= "unsafe.Pointer",
-	[TSTRUCT]	= "struct",
-	[TINTER]	= "interface",
-	[TCHAN]		= "chan",
-	[TMAP]		= "map",
-	[TARRAY]	= "array",
-	[TFUNC]		= "func",
-	[TNIL]		= "nil",
-	[TIDEAL]	= "untyped number",
-};
-
-static char*
-typekind(Type *t)
-{
-	int et;
-	static char buf[50];
-	char *s;
-	
-	if(isslice(t))
-		return "slice";
-	et = t->etype;
-	if(0 <= et && et < nelem(_typekind) && (s=_typekind[et]) != nil)
-		return s;
-	snprint(buf, sizeof buf, "etype=%d", et);
-	return buf;
-}
-
-/*
- * sprint_depchain prints a dependency chain
- * of nodes into fmt.
- * It is used by typecheck in the case of OLITERAL nodes
- * to print constant definition loops.
- */
-static void
-sprint_depchain(Fmt *fmt, NodeList *stack, Node *cur, Node *first)
-{
-	NodeList *l;
-
-	for(l = stack; l; l=l->next) {
-		if(l->n->op == cur->op) {
-			if(l->n != first)
-				sprint_depchain(fmt, l->next, l->n, first);
-			fmtprint(fmt, "\n\t%L: %N uses %N", l->n->lineno, l->n, cur);
-			return;
-		}
-	}
-}
-
-/*
- * type check node *np.
- * replaces *np with a new pointer in some cases.
- * returns the final value of *np as a convenience.
- */
-static void typecheck1(Node **, int);
-Node*
-typecheck(Node **np, int top)
-{
-	Node *n;
-	int lno;
-	Fmt fmt;
-	NodeList *l;
-	static NodeList *tcstack, *tcfree;
-
-	// cannot type check until all the source has been parsed
-	if(!typecheckok)
-		fatal("early typecheck");
-
-	n = *np;
-	if(n == N)
-		return N;
-	
-	lno = setlineno(n);
-
-	// Skip over parens.
-	while(n->op == OPAREN)
-		n = n->left;
-
-	// Resolve definition of name and value of iota lazily.
-	n = resolve(n);
-
-	*np = n;
-
-	// Skip typecheck if already done.
-	// But re-typecheck ONAME/OTYPE/OLITERAL/OPACK node in case context has changed.
-	if(n->typecheck == 1) {
-		switch(n->op) {
-		case ONAME:
-		case OTYPE:
-		case OLITERAL:
-		case OPACK:
-			break;
-		default:
-			lineno = lno;
-			return n;
-		}
-	}
-
-	if(n->typecheck == 2) {
-		// Typechecking loop. Trying printing a meaningful message,
-		// otherwise a stack trace of typechecking.
-		switch(n->op) {
-		case ONAME:
-			// We can already diagnose variables used as types.
-			if((top & (Erv|Etype)) == Etype)
-				yyerror("%N is not a type", n);
-			break;
-		case OLITERAL:
-			if((top & (Erv|Etype)) == Etype) {
-				yyerror("%N is not a type", n);
-				break;
-			}
-			fmtstrinit(&fmt);
-			sprint_depchain(&fmt, tcstack, n, n);
-			yyerrorl(n->lineno, "constant definition loop%s", fmtstrflush(&fmt));
-			break;
-		}
-		if(nsavederrors+nerrors == 0) {
-			fmtstrinit(&fmt);
-			for(l=tcstack; l; l=l->next)
-				fmtprint(&fmt, "\n\t%L %N", l->n->lineno, l->n);
-			yyerror("typechecking loop involving %N%s", n, fmtstrflush(&fmt));
-		}
-		lineno = lno;
-		return n;
-	}
-	n->typecheck = 2;
-
-	if(tcfree != nil) {
-		l = tcfree;
-		tcfree = l->next;
-	} else
-		l = mal(sizeof *l);
-	l->next = tcstack;
-	l->n = n;
-	tcstack = l;
-
-	typecheck1(&n, top);
-	*np = n;
-	n->typecheck = 1;
-
-	if(tcstack != l)
-		fatal("typecheck stack out of sync");
-	tcstack = l->next;
-	l->next = tcfree;
-	tcfree = l;
-
-	lineno = lno;
-	return n;
-}
-
-/*
- * does n contain a call or receive operation?
- */
-static int callrecvlist(NodeList*);
-
-static int
-callrecv(Node *n)
-{
-	if(n == nil)
-		return 0;
-	
-	switch(n->op) {
-	case OCALL:
-	case OCALLMETH:
-	case OCALLINTER:
-	case OCALLFUNC:
-	case ORECV:
-	case OCAP:
-	case OLEN:
-	case OCOPY:
-	case ONEW:
-	case OAPPEND:
-	case ODELETE:
-		return 1;
-	}
-
-	return callrecv(n->left) ||
-		callrecv(n->right) ||
-		callrecv(n->ntest) ||
-		callrecv(n->nincr) ||
-		callrecvlist(n->ninit) ||
-		callrecvlist(n->nbody) ||
-		callrecvlist(n->nelse) ||
-		callrecvlist(n->list) ||
-		callrecvlist(n->rlist);
-}
-
-static int
-callrecvlist(NodeList *l)
-{
-	for(; l; l=l->next)
-		if(callrecv(l->n))
-			return 1;
-	return 0;
-}
-
-// indexlit implements typechecking of untyped values as
-// array/slice indexes. It is equivalent to defaultlit
-// except for constants of numerical kind, which are acceptable
-// whenever they can be represented by a value of type int.
-static void
-indexlit(Node **np)
-{
-	Node *n;
-
-	n = *np;
-	if(n == N || !isideal(n->type))
-		return;
-	switch(consttype(n)) {
-	case CTINT:
-	case CTRUNE:
-	case CTFLT:
-	case CTCPLX:
-		defaultlit(np, types[TINT]);
-		break;
-	}
-	defaultlit(np, T);
-}
-
-static void
-typecheck1(Node **np, int top)
-{
-	int et, aop, op, ptr;
-	Node *n, *l, *r, *lo, *mid, *hi;
-	NodeList *args;
-	int ok, ntop;
-	Type *t, *tp, *missing, *have, *badtype;
-	Val v;
-	char *why, *desc, descbuf[64];
-	vlong x;
-	
-	n = *np;
-
-	if(n->sym) {
-		if(n->op == ONAME && n->etype != 0 && !(top & Ecall)) {
-			yyerror("use of builtin %S not in function call", n->sym);
-			goto error;
-		}
-
-		typecheckdef(n);
-		if(n->op == ONONAME)
-			goto error;
-	}
-	*np = n;
-
-reswitch:
-	ok = 0;
-	switch(n->op) {
-	default:
-		// until typecheck is complete, do nothing.
-		dump("typecheck", n);
-		fatal("typecheck %O", n->op);
-
-	/*
-	 * names
-	 */
-	case OLITERAL:
-		ok |= Erv;
-		if(n->type == T && n->val.ctype == CTSTR)
-			n->type = idealstring;
-		goto ret;
-
-	case ONONAME:
-		ok |= Erv;
-		goto ret;
-
-	case ONAME:
-		if(n->etype != 0) {
-			ok |= Ecall;
-			goto ret;
-		}
-		if(!(top & Easgn)) {
-			// not a write to the variable
-			if(isblank(n)) {
-				yyerror("cannot use _ as value");
-				goto error;
-			}
-			n->used = 1;
-		}
-		if(!(top &Ecall) && isunsafebuiltin(n)) {
-			yyerror("%N is not an expression, must be called", n);
-			goto error;
-		}
-		ok |= Erv;
-		goto ret;
-
-	case OPACK:
-		yyerror("use of package %S without selector", n->sym);
-		goto error;
-
-	case ODDD:
-		break;
-
-	/*
-	 * types (OIND is with exprs)
-	 */
-	case OTYPE:
-		ok |= Etype;
-		if(n->type == T)
-			goto error;
-		break;
-	
-	case OTARRAY:
-		ok |= Etype;
-		t = typ(TARRAY);
-		l = n->left;
-		r = n->right;
-		if(l == nil) {
-			t->bound = -1;	// slice
-		} else if(l->op == ODDD) {
-			t->bound = -100;	// to be filled in
-			if(!(top&Ecomplit) && !n->diag) {
-				t->broke = 1;
-				n->diag = 1;
-				yyerror("use of [...] array outside of array literal");
-			}
-		} else {
-			l = typecheck(&n->left, Erv);
-			switch(consttype(l)) {
-			case CTINT:
-			case CTRUNE:
-				v = l->val;
-				break;
-			case CTFLT:
-				v = toint(l->val);
-				break;
-			default:
-				if(l->type != T && isint[l->type->etype] && l->op != OLITERAL)
-					yyerror("non-constant array bound %N", l);
-				else
-					yyerror("invalid array bound %N", l);
-				goto error;
-			}
-			t->bound = mpgetfix(v.u.xval);
-			if(doesoverflow(v, types[TINT])) {
-				yyerror("array bound is too large"); 
-				goto error;
-			} else if(t->bound < 0) {
-				yyerror("array bound must be non-negative");
-				goto error;
-			}
-		}
-		typecheck(&r, Etype);
-		if(r->type == T)
-			goto error;
-		t->type = r->type;
-		n->op = OTYPE;
-		n->type = t;
-		n->left = N;
-		n->right = N;
-		if(t->bound != -100)
-			checkwidth(t);
-		break;
-
-	case OTMAP:
-		ok |= Etype;
-		l = typecheck(&n->left, Etype);
-		r = typecheck(&n->right, Etype);
-		if(l->type == T || r->type == T)
-			goto error;
-		n->op = OTYPE;
-		n->type = maptype(l->type, r->type);
-		n->left = N;
-		n->right = N;
-		break;
-
-	case OTCHAN:
-		ok |= Etype;
-		l = typecheck(&n->left, Etype);
-		if(l->type == T)
-			goto error;
-		t = typ(TCHAN);
-		t->type = l->type;
-		t->chan = n->etype;
-		n->op = OTYPE;
-		n->type = t;
-		n->left = N;
-		n->etype = 0;
-		break;
-
-	case OTSTRUCT:
-		ok |= Etype;
-		n->op = OTYPE;
-		n->type = tostruct(n->list);
-		if(n->type == T || n->type->broke)
-			goto error;
-		n->list = nil;
-		break;
-
-	case OTINTER:
-		ok |= Etype;
-		n->op = OTYPE;
-		n->type = tointerface(n->list);
-		if(n->type == T)
-			goto error;
-		break;
-
-	case OTFUNC:
-		ok |= Etype;
-		n->op = OTYPE;
-		n->type = functype(n->left, n->list, n->rlist);
-		if(n->type == T)
-			goto error;
-		break;
-
-	/*
-	 * type or expr
-	 */
-	case OIND:
-		ntop = Erv | Etype;
-		if(!(top & Eaddr))  		// The *x in &*x is not an indirect.
-			ntop |= Eindir;
-		ntop |= top & Ecomplit;
-		l = typecheck(&n->left, ntop);
-		if((t = l->type) == T)
-			goto error;
-		if(l->op == OTYPE) {
-			ok |= Etype;
-			n->op = OTYPE;
-			n->type = ptrto(l->type);
-			n->left = N;
-			goto ret;
-		}
-		if(!isptr[t->etype]) {
-			if(top & (Erv | Etop)) {
-				yyerror("invalid indirect of %lN", n->left);
-				goto error;
-			}
-			goto ret;
-		}
-		ok |= Erv;
-		n->type = t->type;
-		goto ret;
-
-	/*
-	 * arithmetic exprs
-	 */
-	case OASOP:
-		ok |= Etop;
-		l = typecheck(&n->left, Erv);
-		checkassign(n->left);
-		r = typecheck(&n->right, Erv);
-		if(l->type == T || r->type == T)
-			goto error;
-		op = n->etype;
-		goto arith;
-
-	case OADD:
-	case OAND:
-	case OANDAND:
-	case OANDNOT:
-	case ODIV:
-	case OEQ:
-	case OGE:
-	case OGT:
-	case OLE:
-	case OLT:
-	case OLSH:
-	case ORSH:
-	case OMOD:
-	case OMUL:
-	case ONE:
-	case OOR:
-	case OOROR:
-	case OSUB:
-	case OXOR:
-		ok |= Erv;
-		l = typecheck(&n->left, Erv | (top & Eiota));
-		r = typecheck(&n->right, Erv | (top & Eiota));
-		if(l->type == T || r->type == T)
-			goto error;
-		op = n->op;
-	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 == T || r->type == T)
-			goto error;
-		t = l->type;
-		if(t->etype == TIDEAL)
-			t = r->type;
-		et = t->etype;
-		if(et == TIDEAL)
-			et = TINT;
-		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.
-			if(r->type->etype != TBLANK && (aop = assignop(l->type, r->type, nil)) != 0) {
-				if(isinter(r->type) && !isinter(l->type) && algtype1(l->type, nil) == ANOEQ) {
-					yyerror("invalid operation: %N (operator %O not defined on %s)", n, op, typekind(l->type));
-					goto error;
-				}
-				l = nod(aop, l, N);
-				l->type = r->type;
-				l->typecheck = 1;
-				n->left = l;
-				t = l->type;
-			} else if(l->type->etype != TBLANK && (aop = assignop(r->type, l->type, nil)) != 0) {
-				if(isinter(l->type) && !isinter(r->type) && algtype1(r->type, nil) == ANOEQ) {
-					yyerror("invalid operation: %N (operator %O not defined on %s)", n, op, typekind(r->type));
-					goto error;
-				}
-				r = nod(aop, r, N);
-				r->type = l->type;
-				r->typecheck = 1;
-				n->right = r;
-				t = r->type;
-			}
-			et = t->etype;
-		}
-		if(t->etype != TIDEAL && !eqtype(l->type, r->type)) {
-			defaultlit2(&l, &r, 1);
-			if(n->op == OASOP && n->implicit) {
-				yyerror("invalid operation: %N (non-numeric type %T)", n, l->type);
-				goto error;
-			}
-			yyerror("invalid operation: %N (mismatched types %T and %T)", n, l->type, r->type);
-			goto error;
-		}
-		if(!okfor[op][et]) {
-			yyerror("invalid operation: %N (operator %O not defined on %s)", n, op, 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: %N (%T cannot be compared)", n, l->type);
-			goto error;
-		}
-		if(isslice(l->type) && !isnil(l) && !isnil(r)) {
-			yyerror("invalid operation: %N (slice can only be compared to nil)", n);
-			goto error;
-		}
-		if(l->type->etype == TMAP && !isnil(l) && !isnil(r)) {
-			yyerror("invalid operation: %N (map can only be compared to nil)", n);
-			goto error;
-		}
-		if(l->type->etype == TFUNC && !isnil(l) && !isnil(r)) {
-			yyerror("invalid operation: %N (func can only be compared to nil)", n);
-			goto error;
-		}
-		if(l->type->etype == TSTRUCT && algtype1(l->type, &badtype) == ANOEQ) {
-			yyerror("invalid operation: %N (struct containing %T cannot be compared)", n, badtype);
-			goto error;
-		}
-		
-		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;
-			}
-		// non-comparison operators on ideal bools should make them lose their ideal-ness
-		} else 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 = N;
-				n->right = N;
-			}
-		}
-		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) {
-				// leave alone for back end
-			} else {
-				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] || issigned[t->etype]) {
-			yyerror("invalid operation: %N (shift count type %T, must be unsigned integer)", n, r->type);
-			goto error;
-		}
-		t = l->type;
-		if(t != T && t->etype != TIDEAL && !isint[t->etype]) {
-			yyerror("invalid operation: %N (shift of type %T)", n, t);
-			goto error;
-		}
-		// no defaultlit for left
-		// the outer context gives the type
-		n->type = l->type;
-		goto ret;
-
-	case OCOM:
-	case OMINUS:
-	case ONOT:
-	case OPLUS:
-		ok |= Erv;
-		l = typecheck(&n->left, Erv | (top & Eiota));
-		if((t = l->type) == T)
-			goto error;
-		if(!okfor[n->op][t->etype]) {
-			yyerror("invalid operation: %O %T", n->op, t);
-			goto error;
-		}
-		n->type = t;
-		goto ret;
-
-	/*
-	 * exprs
-	 */
-	case OADDR:
-		ok |= Erv;
-		typecheck(&n->left, Erv | Eaddr);
-		if(n->left->type == T)
-			goto error;
-		checklvalue(n->left, "take the address of");
-		r = outervalue(n->left);
-		for(l = n->left; l != r; l = l->left)
-			l->addrtaken = 1;
-		if(l->orig != l && l->op == ONAME)
-			fatal("found non-orig name node %N", l);
-		l->addrtaken = 1;
-		defaultlit(&n->left, T);
-		l = n->left;
-		if((t = l->type) == T)
-			goto error;
-		n->type = ptrto(t);
-		goto ret;
-
-	case OCOMPLIT:
-		ok |= Erv;
-		typecheckcomplit(&n);
-		if(n->type == T)
-			goto error;
-		goto ret;
-
-	case OXDOT:
-		n = adddot(n);
-		n->op = ODOT;
-		if(n->left == N)
-			goto error;
-		// fall through
-	case ODOT:
-		typecheck(&n->left, Erv|Etype);
-		defaultlit(&n->left, T);
-		if((t = n->left->type) == T)
-			goto error;
-		if(n->right->op != ONAME) {
-			yyerror("rhs of . must be a name");	// impossible
-			goto error;
-		}
-		r = n->right;
-
-		if(n->left->op == OTYPE) {
-			if(!looktypedot(n, t, 0)) {
-				if(looktypedot(n, t, 1))
-					yyerror("%N undefined (cannot refer to unexported method %S)", n, n->right->sym);
-				else
-					yyerror("%N undefined (type %T has no method %S)", n, t, n->right->sym);
-				goto error;
-			}
-			if(n->type->etype != TFUNC || n->type->thistuple != 1) {
-				yyerror("type %T has no method %hS", n->left->type, n->right->sym);
-				n->type = T;
-				goto error;
-			}
-			n->op = ONAME;
-			n->sym = n->right->sym;
-			n->type = methodfunc(n->type, n->left->type);
-			n->xoffset = 0;
-			n->class = PFUNC;
-			ok = Erv;
-			goto ret;
-		}
-		if(isptr[t->etype] && t->type->etype != TINTER) {
-			t = t->type;
-			if(t == T)
-				goto error;
-			n->op = ODOTPTR;
-			checkwidth(t);
-		}
-		if(isblank(n->right)) {
-			yyerror("cannot refer to blank field or method");
-			goto error;
-		}
-		if(!lookdot(n, t, 0)) {
-			if(lookdot(n, t, 1))
-				yyerror("%N undefined (cannot refer to unexported field or method %S)", n, n->right->sym);
-			else
-				yyerror("%N undefined (type %T has no field or method %S)", n, n->left->type, n->right->sym);
-			goto error;
-		}
-		switch(n->op) {
-		case ODOTINTER:
-		case ODOTMETH:
-			if(top&Ecall)
-				ok |= Ecall;
-			else {
-				typecheckpartialcall(n, r);
-				ok |= Erv;
-			}
-			break;
-		default:
-			ok |= Erv;
-			break;
-		}
-		goto ret;
-
-	case ODOTTYPE:
-		ok |= Erv;
-		typecheck(&n->left, Erv);
-		defaultlit(&n->left, T);
-		l = n->left;
-		if((t = l->type) == T)
-			goto error;
-		if(!isinter(t)) {
-			yyerror("invalid type assertion: %N (non-interface type %T on left)", n, t);
-			goto error;
-		}
-		if(n->right != N) {
-			typecheck(&n->right, Etype);
-			n->type = n->right->type;
-			n->right = N;
-			if(n->type == T)
-				goto error;
-		}
-		if(n->type != T && n->type->etype != TINTER)
-		if(!implements(n->type, t, &missing, &have, &ptr)) {
-			if(have && have->sym == missing->sym)
-				yyerror("impossible type assertion:\n\t%T does not implement %T (wrong type for %S method)\n"
-					"\t\thave %S%hhT\n\t\twant %S%hhT", n->type, t, missing->sym,
-					have->sym, have->type, missing->sym, missing->type);
-			else if(ptr)
-				yyerror("impossible type assertion:\n\t%T does not implement %T (%S method has pointer receiver)",
-					n->type, t, missing->sym);
-			else if(have)
-				yyerror("impossible type assertion:\n\t%T does not implement %T (missing %S method)\n"
-					"\t\thave %S%hhT\n\t\twant %S%hhT", n->type, t, missing->sym,
-					have->sym, have->type, missing->sym, missing->type);
-			else
-				yyerror("impossible type assertion:\n\t%T does not implement %T (missing %S method)",
-					n->type, t, missing->sym);
-			goto error;
-		}
-		goto ret;
-
-	case OINDEX:
-		ok |= Erv;
-		typecheck(&n->left, Erv);
-		defaultlit(&n->left, T);
-		implicitstar(&n->left);
-		l = n->left;
-		typecheck(&n->right, Erv);
-		r = n->right;
-		if((t = l->type) == T || r->type == T)
-			goto error;
-		switch(t->etype) {
-		default:
-			yyerror("invalid operation: %N (type %T does not support indexing)", n, t);
-			goto error;
-
-
-		case TSTRING:
-		case TARRAY:
-			indexlit(&n->right);
-			if(t->etype == TSTRING)
-				n->type = types[TUINT8];
-			else
-				n->type = t->type;
-			why = "string";
-			if(t->etype == TARRAY) {
-				if(isfixedarray(t))
-					why = "array";
-				else
-					why = "slice";
-			}
-			if(n->right->type != T && !isint[n->right->type->etype]) {
-				yyerror("non-integer %s index %N", why, n->right);
-				break;
-			}
-			if(isconst(n->right, CTINT)) {
-				x = mpgetfix(n->right->val.u.xval);
-				if(x < 0)
-					yyerror("invalid %s index %N (index must be non-negative)", why, n->right);
-				else if(isfixedarray(t) && t->bound > 0 && x >= t->bound)
-					yyerror("invalid array index %N (out of bounds for %d-element array)", n->right, t->bound);
-				else if(isconst(n->left, CTSTR) && x >= n->left->val.u.sval->len)
-					yyerror("invalid string index %N (out of bounds for %d-byte string)", n->right, n->left->val.u.sval->len);
-				else if(mpcmpfixfix(n->right->val.u.xval, maxintval[TINT]) > 0)
-					yyerror("invalid %s index %N (index too large)", why, n->right);
-			}
-			break;
-
-		case TMAP:
-			n->etype = 0;
-			defaultlit(&n->right, t->down);
-			if(n->right->type != T)
-				n->right = assignconv(n->right, t->down, "map index");
-			n->type = t->type;
-			n->op = OINDEXMAP;
-			break;
-		}
-		goto ret;
-
-	case ORECV:
-		ok |= Etop | Erv;
-		typecheck(&n->left, Erv);
-		defaultlit(&n->left, T);
-		l = n->left;
-		if((t = l->type) == T)
-			goto error;
-		if(t->etype != TCHAN) {
-			yyerror("invalid operation: %N (receive from non-chan type %T)", n, t);
-			goto error;
-		}
-		if(!(t->chan & Crecv)) {
-			yyerror("invalid operation: %N (receive from send-only type %T)", n, t);
-			goto error;
-		}
-		n->type = t->type;
-		goto ret;
-
-	case OSEND:
-		ok |= Etop;
-		l = typecheck(&n->left, Erv);
-		typecheck(&n->right, Erv);
-		defaultlit(&n->left, T);
-		l = n->left;
-		if((t = l->type) == T)
-			goto error;
-		if(t->etype != TCHAN) {
-			yyerror("invalid operation: %N (send to non-chan type %T)", n, t);
-			goto error;
-		}
-		if(!(t->chan & Csend)) {
-			yyerror("invalid operation: %N (send to receive-only type %T)", n, t);
-			goto error;
-		}
-		defaultlit(&n->right, t->type);
-		r = n->right;
-		if(r->type == T)
-			goto error;
-		n->right = assignconv(r, l->type->type, "send");
-		// TODO: more aggressive
-		n->etype = 0;
-		n->type = T;
-		goto ret;
-
-	case OSLICE:
-		ok |= Erv;
-		typecheck(&n->left, top);
-		typecheck(&n->right->left, Erv);
-		typecheck(&n->right->right, Erv);
-		defaultlit(&n->left, T);
-		indexlit(&n->right->left);
-		indexlit(&n->right->right);
-		l = n->left;
-		if(isfixedarray(l->type)) {
-			if(!islvalue(n->left)) {
-				yyerror("invalid operation %N (slice of unaddressable value)", n);
-				goto error;
-			}
-			n->left = nod(OADDR, n->left, N);
-			n->left->implicit = 1;
-			typecheck(&n->left, Erv);
-			l = n->left;
-		}
-		if((t = l->type) == T)
-			goto error;
-		tp = nil;
-		if(istype(t, TSTRING)) {
-			n->type = t;
-			n->op = OSLICESTR;
-		} else if(isptr[t->etype] && isfixedarray(t->type)) {
-			tp = t->type;
-			n->type = typ(TARRAY);
-			n->type->type = tp->type;
-			n->type->bound = -1;
-			dowidth(n->type);
-			n->op = OSLICEARR;
-		} else if(isslice(t)) {
-			n->type = t;
-		} else {
-			yyerror("cannot slice %N (type %T)", l, t);
-			goto error;
-		}
-		if((lo = n->right->left) != N && checksliceindex(l, lo, tp) < 0)
-			goto error;
-		if((hi = n->right->right) != N && checksliceindex(l, hi, tp) < 0)
-			goto error;
-		if(checksliceconst(lo, hi) < 0)
-			goto error;
-		goto ret;
-
-	case OSLICE3:
-		ok |= Erv;
-		typecheck(&n->left, top);
-		typecheck(&n->right->left, Erv);
-		typecheck(&n->right->right->left, Erv);
-		typecheck(&n->right->right->right, Erv);
-		defaultlit(&n->left, T);
-		indexlit(&n->right->left);
-		indexlit(&n->right->right->left);
-		indexlit(&n->right->right->right);
-		l = n->left;
-		if(isfixedarray(l->type)) {
-			if(!islvalue(n->left)) {
-				yyerror("invalid operation %N (slice of unaddressable value)", n);
-				goto error;
-			}
-			n->left = nod(OADDR, n->left, N);
-			n->left->implicit = 1;
-			typecheck(&n->left, Erv);
-			l = n->left;
-		}
-		if((t = l->type) == T)
-			goto error;
-		tp = nil;
-		if(istype(t, TSTRING)) {
-			yyerror("invalid operation %N (3-index slice of string)", n);
-			goto error;
-		}
-		if(isptr[t->etype] && isfixedarray(t->type)) {
-			tp = t->type;
-			n->type = typ(TARRAY);
-			n->type->type = tp->type;
-			n->type->bound = -1;
-			dowidth(n->type);
-			n->op = OSLICE3ARR;
-		} else if(isslice(t)) {
-			n->type = t;
-		} else {
-			yyerror("cannot slice %N (type %T)", l, t);
-			goto error;
-		}
-		if((lo = n->right->left) != N && checksliceindex(l, lo, tp) < 0)
-			goto error;
-		if((mid = n->right->right->left) != N && checksliceindex(l, mid, tp) < 0)
-			goto error;
-		if((hi = n->right->right->right) != N && checksliceindex(l, hi, tp) < 0)
-			goto error;
-		if(checksliceconst(lo, hi) < 0 || checksliceconst(lo, mid) < 0 || checksliceconst(mid, hi) < 0)
-			goto error;
-		goto ret;
-
-	/*
-	 * call and call like
-	 */
-	case OCALL:
-		l = n->left;
-		if(l->op == ONAME && (r = unsafenmagic(n)) != N) {
-			if(n->isddd)
-				yyerror("invalid use of ... with builtin %N", l);
-			n = r;
-			goto reswitch;
-		}
-		typecheck(&n->left, Erv | Etype | Ecall |(top&Eproc));
-		n->diag |= n->left->diag;
-		l = n->left;
-		if(l->op == ONAME && l->etype != 0) {
-			if(n->isddd && l->etype != OAPPEND)
-				yyerror("invalid use of ... with builtin %N", l);
-			// builtin: OLEN, OCAP, etc.
-			n->op = l->etype;
-			n->left = n->right;
-			n->right = N;
-			goto reswitch;
-		}
-		defaultlit(&n->left, T);
-		l = n->left;
-		if(l->op == OTYPE) {
-			if(n->isddd || l->type->bound == -100) {
-				if(!l->type->broke)
-					yyerror("invalid use of ... in type conversion", l);
-				n->diag = 1;
-			}
-			// pick off before type-checking arguments
-			ok |= Erv;
-			// turn CALL(type, arg) into CONV(arg) w/ type
-			n->left = N;
-			n->op = OCONV;
-			n->type = l->type;
-			if(onearg(n, "conversion to %T", l->type) < 0)
-				goto error;
-			goto doconv;
-		}
-
-		if(count(n->list) == 1 && !n->isddd)
-			typecheck(&n->list->n, Erv | Efnstruct);
-		else
-			typechecklist(n->list, Erv);
-		if((t = l->type) == T)
-			goto error;
-		checkwidth(t);
-
-		switch(l->op) {
-		case ODOTINTER:
-			n->op = OCALLINTER;
-			break;
-
-		case ODOTMETH:
-			n->op = OCALLMETH;
-			// typecheckaste was used here but there wasn't enough
-			// information further down the call chain to know if we
-			// were testing a method receiver for unexported fields.
-			// It isn't necessary, so just do a sanity check.
-			tp = getthisx(t)->type->type;
-			if(l->left == N || !eqtype(l->left->type, tp))
-				fatal("method receiver");
-			break;
-
-		default:
-			n->op = OCALLFUNC;
-			if(t->etype != TFUNC) {
-				yyerror("cannot call non-function %N (type %T)", l, t);
-				goto error;
-			}
-			break;
-		}
-		if(snprint(descbuf, sizeof descbuf, "argument to %N", n->left) < sizeof descbuf)
-			desc = descbuf;
-		else
-			desc = "function argument";
-		typecheckaste(OCALL, n->left, n->isddd, getinargx(t), n->list, desc);
-		ok |= Etop;
-		if(t->outtuple == 0)
-			goto ret;
-		ok |= Erv;
-		if(t->outtuple == 1) {
-			t = getoutargx(l->type)->type;
-			if(t == T)
-				goto error;
-			if(t->etype == TFIELD)
-				t = t->type;
-			n->type = t;
-			goto ret;
-		}
-		// multiple return
-		if(!(top & (Efnstruct | Etop))) {
-			yyerror("multiple-value %N() in single-value context", l);
-			goto ret;
-		}
-		n->type = getoutargx(l->type);
-		goto ret;
-
-	case OCAP:
-	case OLEN:
-	case OREAL:
-	case OIMAG:
-		ok |= Erv;
-		if(onearg(n, "%O", n->op) < 0)
-			goto error;
-		typecheck(&n->left, Erv);
-		defaultlit(&n->left, T);
-		implicitstar(&n->left);
-		l = n->left;
-		t = l->type;
-		if(t == T)
-			goto error;
-		switch(n->op) {
-		case OCAP:
-			if(!okforcap[t->etype])
-				goto badcall1;
-			break;
-		case OLEN:
-			if(!okforlen[t->etype])
-				goto badcall1;
-			break;
-		case OREAL:
-		case OIMAG:
-			if(!iscomplex[t->etype])
-				goto badcall1;
-			if(isconst(l, CTCPLX)){
-				r = n;
-				if(n->op == OREAL)
-					n = nodfltconst(&l->val.u.cval->real);
-				else
-					n = nodfltconst(&l->val.u.cval->imag);
-				n->orig = r;
-			}
-			n->type = types[cplxsubtype(t->etype)];
-			goto ret;
-		}
-		// might be constant
-		switch(t->etype) {
-		case TSTRING:
-			if(isconst(l, CTSTR)) {
-				r = nod(OXXX, N, N);
-				nodconst(r, types[TINT], l->val.u.sval->len);
-				r->orig = n;
-				n = r;
-			}
-			break;
-		case TARRAY:
-			if(t->bound < 0) // slice
-				break;
-			if(callrecv(l)) // has call or receive
-				break;
-			r = nod(OXXX, N, N);
-			nodconst(r, types[TINT], t->bound);
-			r->orig = n;
-			n = r;
-			break;
-		}
-		n->type = types[TINT];
-		goto ret;
-
-	case OCOMPLEX:
-		ok |= Erv;
-		if(count(n->list) == 1) {
-			typechecklist(n->list, Efnstruct);
-			t = n->list->n->left->type;
-			if(t->outtuple != 2) {
-				yyerror("invalid operation: complex expects two arguments, %N returns %d results", n->list->n, t->outtuple);
-				goto error;
-			}
-			t = n->list->n->type->type;
-			l = t->nname;
-			r = t->down->nname;
-		} else {
-			if(twoarg(n) < 0)
-				goto error;
-			l = typecheck(&n->left, Erv | (top & Eiota));
-			r = typecheck(&n->right, Erv | (top & Eiota));
-			if(l->type == T || r->type == T)
-				goto error;
-			defaultlit2(&l, &r, 0);
-			if(l->type == T || r->type == T)
-				goto error;
-			n->left = l;
-			n->right = r;
-		}
-		if(!eqtype(l->type, r->type)) {
-			yyerror("invalid operation: %N (mismatched types %T and %T)", n, l->type, r->type);
-			goto error;
-		}
-		switch(l->type->etype) {
-		default:
-			yyerror("invalid operation: %N (arguments have type %T, expected floating-point)", n, l->type, r->type);
-			goto error;
-		case TIDEAL:
-			t = types[TIDEAL];
-			break;
-		case TFLOAT32:
-			t = types[TCOMPLEX64];
-			break;
-		case TFLOAT64:
-			t = types[TCOMPLEX128];
-			break;
-		}
-		if(l->op == OLITERAL && r->op == OLITERAL) {
-			// make it a complex literal
-			r = nodcplxlit(l->val, r->val);
-			r->orig = n;
-			n = r;
-		}
-		n->type = t;
-		goto ret;
-
-	case OCLOSE:
-		if(onearg(n, "%O", n->op) < 0)
-			goto error;
-		typecheck(&n->left, Erv);
-		defaultlit(&n->left, T);
-		l = n->left;
-		if((t = l->type) == T)
-			goto error;
-		if(t->etype != TCHAN) {
-			yyerror("invalid operation: %N (non-chan type %T)", n, t);
-			goto error;
-		}
-		if(!(t->chan & Csend)) {
-			yyerror("invalid operation: %N (cannot close receive-only channel)", n);
-			goto error;
-		}
-		ok |= Etop;
-		goto ret;
-
-	case ODELETE:
-		args = n->list;
-		if(args == nil) {
-			yyerror("missing arguments to delete");
-			goto error;
-		}
-		if(args->next == nil) {
-			yyerror("missing second (key) argument to delete");
-			goto error;
-		}
-		if(args->next->next != nil) {
-			yyerror("too many arguments to delete");
-			goto error;
-		}
-		ok |= Etop;
-		typechecklist(args, Erv);
-		l = args->n;
-		r = args->next->n;
-		if(l->type != T && l->type->etype != TMAP) {
-			yyerror("first argument to delete must be map; have %lT", l->type);
-			goto error;
-		}
-		args->next->n = assignconv(r, l->type->down, "delete");
-		goto ret;
-
-	case OAPPEND:
-		ok |= Erv;
-		args = n->list;
-		if(args == nil) {
-			yyerror("missing arguments to append");
-			goto error;
-		}
-
-		if(count(args) == 1 && !n->isddd)
-			typecheck(&args->n, Erv | Efnstruct);
-		else
-			typechecklist(args, Erv);
-
-		if((t = args->n->type) == T)
-			goto error;
-
-		// Unpack multiple-return result before type-checking.
-		if(istype(t, TSTRUCT) && t->funarg) {
-			t = t->type;
-			if(istype(t, TFIELD))
-				t = t->type;
-		}
-
-		n->type = t;
-		if(!isslice(t)) {
-			if(isconst(args->n, CTNIL)) {
-				yyerror("first argument to append must be typed slice; have untyped nil", t);
-				goto error;
-			}
-			yyerror("first argument to append must be slice; have %lT", t);
-			goto error;
-		}
-
-		if(n->isddd) {
-			if(args->next == nil) {
-				yyerror("cannot use ... on first argument to append");
-				goto error;
-			}
-			if(args->next->next != nil) {
-				yyerror("too many arguments to append");
-				goto error;
-			}
-			if(istype(t->type, TUINT8) && istype(args->next->n->type, TSTRING)) {
-				defaultlit(&args->next->n, types[TSTRING]);
-				goto ret;
-			}
-			args->next->n = assignconv(args->next->n, t->orig, "append");
-			goto ret;
-		}
-		for(args=args->next; args != nil; args=args->next) {
-			if(args->n->type == T)
-				continue;
-			args->n = assignconv(args->n, t->type, "append");
-		}
-		goto ret;
-
-	case OCOPY:
-		ok |= Etop|Erv;
-		args = n->list;
-		if(args == nil || args->next == nil) {
-			yyerror("missing arguments to copy");
-			goto error;
-		}
-		if(args->next->next != nil) {
-			yyerror("too many arguments to copy");
-			goto error;
-		}
-		n->left = args->n;
-		n->right = args->next->n;
-		n->list = nil;
-		n->type = types[TINT];
-		typecheck(&n->left, Erv);
-		typecheck(&n->right, Erv);
-		if(n->left->type == T || n->right->type == T)
-			goto error;
-		defaultlit(&n->left, T);
-		defaultlit(&n->right, T);
-		if(n->left->type == T || n->right->type == T)
-			goto error;
-
-		// copy([]byte, string)
-		if(isslice(n->left->type) && n->right->type->etype == TSTRING) {
-			if(eqtype(n->left->type->type, bytetype))
-				goto ret;
-			yyerror("arguments to copy have different element types: %lT and string", n->left->type);
-			goto error;
-		}
-
-		if(!isslice(n->left->type) || !isslice(n->right->type)) {
-			if(!isslice(n->left->type) && !isslice(n->right->type))
-				yyerror("arguments to copy must be slices; have %lT, %lT", n->left->type, n->right->type);
-			else if(!isslice(n->left->type))
-				yyerror("first argument to copy should be slice; have %lT", n->left->type);
-			else
-				yyerror("second argument to copy should be slice or string; have %lT", n->right->type);
-			goto error;
-		}
-		if(!eqtype(n->left->type->type, n->right->type->type)) {
-			yyerror("arguments to copy have different element types: %lT and %lT", n->left->type, n->right->type);
-			goto error;
-		}
-		goto ret;
-
-	case OCONV:
-	doconv:
-		ok |= Erv;
-		saveorignode(n);
-		typecheck(&n->left, Erv | (top & (Eindir | Eiota)));
-		convlit1(&n->left, n->type, 1);
-		if((t = n->left->type) == T || n->type == T)
-			goto error;
-		if((n->op = convertop(t, n->type, &why)) == 0) {
-			if(!n->diag && !n->type->broke) {
-				yyerror("cannot convert %lN to type %T%s", n->left, n->type, why);
-				n->diag = 1;
-			}
-			n->op = OCONV;
-		}
-		switch(n->op) {
-		case OCONVNOP:
-			if(n->left->op == OLITERAL) {
-				r = nod(OXXX, N, N);
-				n->op = OCONV;
-				n->orig = r;
-				*r = *n;
-				n->op = OLITERAL;
-				n->val = n->left->val;
-			}
-			break;
-		case OSTRARRAYBYTE:
-			// do not use stringtoarraylit.
-			// generated code and compiler memory footprint is better without it.
-			break;
-		case OSTRARRAYRUNE:
-			if(n->left->op == OLITERAL)
-				stringtoarraylit(&n);
-			break;
-		}
-		goto ret;
-
-	case OMAKE:
-		ok |= Erv;
-		args = n->list;
-		if(args == nil) {
-			yyerror("missing argument to make");
-			goto error;
-		}
-		n->list = nil;
-		l = args->n;
-		args = args->next;
-		typecheck(&l, Etype);
-		if((t = l->type) == T)
-			goto error;
-
-		switch(t->etype) {
-		default:
-		badmake:
-			yyerror("cannot make type %T", t);
-			goto error;
-
-		case TARRAY:
-			if(!isslice(t))
-				goto badmake;
-			if(args == nil) {
-				yyerror("missing len argument to make(%T)", t);
-				goto error;
-			}
-			l = args->n;
-			args = args->next;
-			typecheck(&l, Erv);
-			r = N;
-			if(args != nil) {
-				r = args->n;
-				args = args->next;
-				typecheck(&r, Erv);
-			}
-			if(l->type == T || (r && r->type == T))
-				goto error;
-			et = checkmake(t, "len", l) < 0;
-			et |= r && checkmake(t, "cap", r) < 0;
-			if(et)
-				goto error;
-			if(isconst(l, CTINT) && r && isconst(r, CTINT) && mpcmpfixfix(l->val.u.xval, r->val.u.xval) > 0) {
-				yyerror("len larger than cap in make(%T)", t);
-				goto error;
-			}
-			n->left = l;
-			n->right = r;
-			n->op = OMAKESLICE;
-			break;
-
-		case TMAP:
-			if(args != nil) {
-				l = args->n;
-				args = args->next;
-				typecheck(&l, Erv);
-				defaultlit(&l, types[TINT]);
-				if(l->type == T)
-					goto error;
-				if(checkmake(t, "size", l) < 0)
-					goto error;
-				n->left = l;
-			} else
-				n->left = nodintconst(0);
-			n->op = OMAKEMAP;
-			break;
-
-		case TCHAN:
-			l = N;
-			if(args != nil) {
-				l = args->n;
-				args = args->next;
-				typecheck(&l, Erv);
-				defaultlit(&l, types[TINT]);
-				if(l->type == T)
-					goto error;
-				if(checkmake(t, "buffer", l) < 0)
-					goto error;
-				n->left = l;
-			} else
-				n->left = nodintconst(0);
-			n->op = OMAKECHAN;
-			break;
-		}
-		if(args != nil) {
-			yyerror("too many arguments to make(%T)", t);
-			n->op = OMAKE;
-			goto error;
-		}
-		n->type = t;
-		goto ret;
-
-	case ONEW:
-		ok |= Erv;
-		args = n->list;
-		if(args == nil) {
-			yyerror("missing argument to new");
-			goto error;
-		}
-		l = args->n;
-		typecheck(&l, Etype);
-		if((t = l->type) == T)
-			goto error;
-		if(args->next != nil) {
-			yyerror("too many arguments to new(%T)", t);
-			goto error;
-		}
-		n->left = l;
-		n->type = ptrto(t);
-		goto ret;
-
-	case OPRINT:
-	case OPRINTN:
-		ok |= Etop;
-		typechecklist(n->list, Erv | Eindir);  // Eindir: address does not escape
-		for(args=n->list; args; args=args->next) {
-			// Special case for print: int constant is int64, not int.
-			if(isconst(args->n, CTINT))
-				defaultlit(&args->n, types[TINT64]);
-			else
-				defaultlit(&args->n, T);
-		}
-		goto ret;
-
-	case OPANIC:
-		ok |= Etop;
-		if(onearg(n, "panic") < 0)
-			goto error;
-		typecheck(&n->left, Erv);
-		defaultlit(&n->left, types[TINTER]);
-		if(n->left->type == T)
-			goto error;
-		goto ret;
-	
-	case ORECOVER:
-		ok |= Erv|Etop;
-		if(n->list != nil) {
-			yyerror("too many arguments to recover");
-			goto error;
-		}
-		n->type = types[TINTER];
-		goto ret;
-
-	case OCLOSURE:
-		ok |= Erv;
-		typecheckclosure(n, top);
-		if(n->type == T)
-			goto error;
-		goto ret;
-	
-	case OITAB:
-		ok |= Erv;
-		typecheck(&n->left, Erv);
-		if((t = n->left->type) == T)
-			goto error;
-		if(t->etype != TINTER)
-			fatal("OITAB of %T", t);
-		n->type = ptrto(types[TUINTPTR]);
-		goto ret;
-
-	case OSPTR:
-		ok |= Erv;
-		typecheck(&n->left, Erv);
-		if((t = n->left->type) == T)
-			goto error;
-		if(!isslice(t) && t->etype != TSTRING)
-			fatal("OSPTR of %T", t);
-		if(t->etype == TSTRING)
-			n->type = ptrto(types[TUINT8]);
-		else
-			n->type = ptrto(t->type);
-		goto ret;
-
-	case OCLOSUREVAR:
-		ok |= Erv;
-		goto ret;
-	
-	case OCFUNC:
-		ok |= Erv;
-		typecheck(&n->left, Erv);
-		n->type = types[TUINTPTR];
-		goto ret;
-
-	case OCONVNOP:
-		ok |= Erv;
-		typecheck(&n->left, Erv);
-		goto ret;
-
-	/*
-	 * statements
-	 */
-	case OAS:
-		ok |= Etop;
-		typecheckas(n);
-		goto ret;
-
-	case OAS2:
-		ok |= Etop;
-		typecheckas2(n);
-		goto ret;
-
-	case OBREAK:
-	case OCONTINUE:
-	case ODCL:
-	case OEMPTY:
-	case OGOTO:
-	case OLABEL:
-	case OXFALL:
-	case OVARKILL:
-		ok |= Etop;
-		goto ret;
-
-	case ODEFER:
-		ok |= Etop;
-		typecheck(&n->left, Etop|Erv);
-		if(!n->left->diag)
-			checkdefergo(n);
-		goto ret;
-
-	case OPROC:
-		ok |= Etop;
-		typecheck(&n->left, Etop|Eproc|Erv);
-		checkdefergo(n);
-		goto ret;
-
-	case OFOR:
-		ok |= Etop;
-		typechecklist(n->ninit, Etop);
-		typecheck(&n->ntest, Erv);
-		if(n->ntest != N && (t = n->ntest->type) != T && t->etype != TBOOL)
-			yyerror("non-bool %lN used as for condition", n->ntest);
-		typecheck(&n->nincr, Etop);
-		typechecklist(n->nbody, Etop);
-		goto ret;
-
-	case OIF:
-		ok |= Etop;
-		typechecklist(n->ninit, Etop);
-		typecheck(&n->ntest, Erv);
-		if(n->ntest != N && (t = n->ntest->type) != T && t->etype != TBOOL)
-			yyerror("non-bool %lN used as if condition", n->ntest);
-		typechecklist(n->nbody, Etop);
-		typechecklist(n->nelse, Etop);
-		goto ret;
-
-	case ORETURN:
-		ok |= Etop;
-		if(count(n->list) == 1)
-			typechecklist(n->list, Erv | Efnstruct);
-		else
-			typechecklist(n->list, Erv);
-		if(curfn == N) {
-			yyerror("return outside function");
-			goto error;
-		}
-		if(curfn->type->outnamed && n->list == nil)
-			goto ret;
-		typecheckaste(ORETURN, nil, 0, getoutargx(curfn->type), n->list, "return argument");
-		goto ret;
-	
-	case ORETJMP:
-		ok |= Etop;
-		goto ret;
-
-	case OSELECT:
-		ok |= Etop;
-		typecheckselect(n);
-		goto ret;
-
-	case OSWITCH:
-		ok |= Etop;
-		typecheckswitch(n);
-		goto ret;
-
-	case ORANGE:
-		ok |= Etop;
-		typecheckrange(n);
-		goto ret;
-
-	case OTYPESW:
-		yyerror("use of .(type) outside type switch");
-		goto error;
-
-	case OXCASE:
-		ok |= Etop;
-		typechecklist(n->list, Erv);
-		typechecklist(n->nbody, Etop);
-		goto ret;
-
-	case ODCLFUNC:
-		ok |= Etop;
-		typecheckfunc(n);
-		goto ret;
-
-	case ODCLCONST:
-		ok |= Etop;
-		typecheck(&n->left, Erv);
-		goto ret;
-
-	case ODCLTYPE:
-		ok |= Etop;
-		typecheck(&n->left, Etype);
-		if(!incannedimport)
-			checkwidth(n->left->type);
-		goto ret;
-	}
-
-ret:
-	t = n->type;
-	if(t && !t->funarg && n->op != OTYPE) {
-		switch(t->etype) {
-		case TFUNC:	// might have TANY; wait until its called
-		case TANY:
-		case TFORW:
-		case TIDEAL:
-		case TNIL:
-		case TBLANK:
-			break;
-		default:
-			checkwidth(t);
-		}
-	}
-
-	if(safemode && !incannedimport && !importpkg && !compiling_wrappers && t && t->etype == TUNSAFEPTR)
-		yyerror("cannot use unsafe.Pointer");
-
-	evconst(n);
-	if(n->op == OTYPE && !(top & Etype)) {
-		yyerror("type %T is not an expression", n->type);
-		goto error;
-	}
-	if((top & (Erv|Etype)) == Etype && n->op != OTYPE) {
-		yyerror("%N is not a type", n);
-		goto error;
-	}
-	// TODO(rsc): simplify
-	if((top & (Ecall|Erv|Etype)) && !(top & Etop) && !(ok & (Erv|Etype|Ecall))) {
-		yyerror("%N used as value", n);
-		goto error;
-	}
-	if((top & Etop) && !(top & (Ecall|Erv|Etype)) && !(ok & Etop)) {
-		if(n->diag == 0) {
-			yyerror("%N evaluated but not used", n);
-			n->diag = 1;
-		}
-		goto error;
-	}
-
-	/* TODO
-	if(n->type == T)
-		fatal("typecheck nil type");
-	*/
-	goto out;
-
-badcall1:
-	yyerror("invalid argument %lN for %O", n->left, n->op);
-	goto error;
-
-error:
-	n->type = T;
-
-out:
-	*np = n;
-}
-
-static int
-checksliceindex(Node *l, Node *r, Type *tp)
-{
-	Type *t;
-
-	if((t = r->type) == T)
-		return -1;
-	if(!isint[t->etype]) {
-		yyerror("invalid slice index %N (type %T)", r, t);
-		return -1;
-	}
-	if(r->op == OLITERAL) {
-		if(mpgetfix(r->val.u.xval) < 0) {
-			yyerror("invalid slice index %N (index must be non-negative)", r);
-			return -1;
-		} else if(tp != nil && tp->bound > 0 && mpgetfix(r->val.u.xval) > tp->bound) {
-			yyerror("invalid slice index %N (out of bounds for %d-element array)", r, tp->bound);
-			return -1;
-		} else if(isconst(l, CTSTR) && mpgetfix(r->val.u.xval) > l->val.u.sval->len) {
-			yyerror("invalid slice index %N (out of bounds for %d-byte string)", r, l->val.u.sval->len);
-			return -1;
-		} else if(mpcmpfixfix(r->val.u.xval, maxintval[TINT]) > 0) {
-			yyerror("invalid slice index %N (index too large)", r);
-			return -1;
-		}
-	}
-	return 0;
-}
-
-static int
-checksliceconst(Node *lo, Node *hi)
-{
-	if(lo != N && hi != N && lo->op == OLITERAL && hi->op == OLITERAL
-	   && mpcmpfixfix(lo->val.u.xval, hi->val.u.xval) > 0) {
-		yyerror("invalid slice index: %N > %N", lo, hi);
-		return -1;
-	}
-	return 0;
-}
-
-static void
-checkdefergo(Node *n)
-{
-	char *what;
-	
-	what = "defer";
-	if(n->op == OPROC)
-		what = "go";
-
-	switch(n->left->op) {
-	case OCALLINTER:
-	case OCALLMETH:
-	case OCALLFUNC:
-	case OCLOSE:
-	case OCOPY:
-	case ODELETE:
-	case OPANIC:
-	case OPRINT:
-	case OPRINTN:
-	case ORECOVER:
-		// ok
-		break;
-	case OAPPEND:
-	case OCAP:
-	case OCOMPLEX:
-	case OIMAG:
-	case OLEN:
-	case OMAKE:
-	case OMAKESLICE:
-	case OMAKECHAN:
-	case OMAKEMAP:
-	case ONEW:
-	case OREAL:
-	case OLITERAL: // conversion or unsafe.Alignof, Offsetof, Sizeof
-		if(n->left->orig != N && n->left->orig->op == OCONV)
-			goto conv;
-		yyerror("%s discards result of %N", what, n->left);
-		break;
-	default:
-	conv:
-		// type is broken or missing, most likely a method call on a broken type
-		// we will warn about the broken type elsewhere. no need to emit a potentially confusing error
-		if(n->left->type == T || n->left->type->broke)
-			break;
-
-		if(!n->diag) {
-			// The syntax made sure it was a call, so this must be
-			// a conversion.
-			n->diag = 1;
-			yyerror("%s requires function call, not conversion", what);
-		}
-		break;
-	}
-}
-
-static void
-implicitstar(Node **nn)
-{
-	Type *t;
-	Node *n;
-
-	// insert implicit * if needed for fixed array
-	n = *nn;
-	t = n->type;
-	if(t == T || !isptr[t->etype])
-		return;
-	t = t->type;
-	if(t == T)
-		return;
-	if(!isfixedarray(t))
-		return;
-	n = nod(OIND, n, N);
-	n->implicit = 1;
-	typecheck(&n, Erv);
-	*nn = n;
-}
-
-static int
-onearg(Node *n, char *f, ...)
-{
-	va_list arg;
-	char *p;
-
-	if(n->left != N)
-		return 0;
-	if(n->list == nil) {
-		va_start(arg, f);
-		p = vsmprint(f, arg);
-		va_end(arg);
-		yyerror("missing argument to %s: %N", p, n);
-		return -1;
-	}
-	if(n->list->next != nil) {
-		va_start(arg, f);
-		p = vsmprint(f, arg);
-		va_end(arg);
-		yyerror("too many arguments to %s: %N", p, n);
-		n->left = n->list->n;
-		n->list = nil;
-		return -1;
-	}
-	n->left = n->list->n;
-	n->list = nil;
-	return 0;
-}
-
-static int
-twoarg(Node *n)
-{
-	if(n->left != N)
-		return 0;
-	if(n->list == nil) {
-		yyerror("missing argument to %O - %N", n->op, n);
-		return -1;
-	}
-	n->left = n->list->n;
-	if(n->list->next == nil) {
-		yyerror("missing argument to %O - %N", n->op, n);
-		n->list = nil;
-		return -1;
-	}
-	if(n->list->next->next != nil) {
-		yyerror("too many arguments to %O - %N", n->op, n);
-		n->list = nil;
-		return -1;
-	}
-	n->right = n->list->next->n;
-	n->list = nil;
-	return 0;
-}
-
-static Type*
-lookdot1(Node *errnode, Sym *s, Type *t, Type *f, int dostrcmp)
-{
-	Type *r;
-
-	r = T;
-	for(; f!=T; f=f->down) {
-		if(dostrcmp && strcmp(f->sym->name, s->name) == 0)
-			return f;
-		if(f->sym != s)
-			continue;
-		if(r != T) {
-			if(errnode)
-				yyerror("ambiguous selector %N", errnode);
-			else if(isptr[t->etype])
-				yyerror("ambiguous selector (%T).%S", t, s);
-			else
-				yyerror("ambiguous selector %T.%S", t, s);
-			break;
-		}
-		r = f;
-	}
-	return r;
-}
-
-static int
-looktypedot(Node *n, Type *t, int dostrcmp)
-{
-	Type *f1, *f2;
-	Sym *s;
-	
-	s = n->right->sym;
-
-	if(t->etype == TINTER) {
-		f1 = lookdot1(n, s, t, t->type, dostrcmp);
-		if(f1 == T)
-			return 0;
-
-		n->right = methodname(n->right, t);
-		n->xoffset = f1->width;
-		n->type = f1->type;
-		n->op = ODOTINTER;
-		return 1;
-	}
-
-	// Find the base type: methtype will fail if t
-	// is not of the form T or *T.
-	f2 = methtype(t, 0);
-	if(f2 == T)
-		return 0;
-
-	expandmeth(f2);
-	f2 = lookdot1(n, s, f2, f2->xmethod, dostrcmp);
-	if(f2 == T)
-		return 0;
-
-	// disallow T.m if m requires *T receiver
-	if(isptr[getthisx(f2->type)->type->type->etype]
-	&& !isptr[t->etype]
-	&& f2->embedded != 2
-	&& !isifacemethod(f2->type)) {
-		yyerror("invalid method expression %N (needs pointer receiver: (*%T).%hS)", n, t, f2->sym);
-		return 0;
-	}
-
-	n->right = methodname(n->right, t);
-	n->xoffset = f2->width;
-	n->type = f2->type;
-	n->op = ODOTMETH;
-	return 1;
-}
-
-static Type*
-derefall(Type* t)
-{
-	while(t && t->etype == tptr)
-		t = t->type;
-	return t;
-}
-
-static int
-lookdot(Node *n, Type *t, int dostrcmp)
-{
-	Type *f1, *f2, *tt, *rcvr;
-	Sym *s;
-
-	s = n->right->sym;
-
-	dowidth(t);
-	f1 = T;
-	if(t->etype == TSTRUCT || t->etype == TINTER)
-		f1 = lookdot1(n, s, t, t->type, dostrcmp);
-
-	f2 = T;
-	if(n->left->type == t || n->left->type->sym == S) {
-		f2 = methtype(t, 0);
-		if(f2 != T) {
-			// Use f2->method, not f2->xmethod: adddot has
-			// already inserted all the necessary embedded dots.
-			f2 = lookdot1(n, s, f2, f2->method, dostrcmp);
-		}
-	}
-
-	if(f1 != T) {
-		if(f2 != T)
-			yyerror("%S is both field and method",
-				n->right->sym);
-		if(f1->width == BADWIDTH)
-			fatal("lookdot badwidth %T %p", f1, f1);
-		n->xoffset = f1->width;
-		n->type = f1->type;
-		n->paramfld = f1;
-		if(t->etype == TINTER) {
-			if(isptr[n->left->type->etype]) {
-				n->left = nod(OIND, n->left, N);	// implicitstar
-				n->left->implicit = 1;
-				typecheck(&n->left, Erv);
-			}
-			n->op = ODOTINTER;
-		}
-		return 1;
-	}
-
-	if(f2 != T) {
-		tt = n->left->type;
-		dowidth(tt);
-		rcvr = getthisx(f2->type)->type->type;
-		if(!eqtype(rcvr, tt)) {
-			if(rcvr->etype == tptr && eqtype(rcvr->type, tt)) {
-				checklvalue(n->left, "call pointer method on");
-				n->left = nod(OADDR, n->left, N);
-				n->left->implicit = 1;
-				typecheck(&n->left, Etype|Erv);
-			} else if(tt->etype == tptr && rcvr->etype != tptr && eqtype(tt->type, rcvr)) {
-				n->left = nod(OIND, n->left, N);
-				n->left->implicit = 1;
-				typecheck(&n->left, Etype|Erv);
-			} else if(tt->etype == tptr && tt->type->etype == tptr && eqtype(derefall(tt), derefall(rcvr))) {
-				yyerror("calling method %N with receiver %lN requires explicit dereference", n->right, n->left);
-				while(tt->etype == tptr) {
-					// Stop one level early for method with pointer receiver.
-					if(rcvr->etype == tptr && tt->type->etype != tptr)
-						break;
-					n->left = nod(OIND, n->left, N);
-					n->left->implicit = 1;
-					typecheck(&n->left, Etype|Erv);
-					tt = tt->type;
-				}
-			} else {
-				fatal("method mismatch: %T for %T", rcvr, tt);
-			}
-		}
-		n->right = methodname(n->right, n->left->type);
-		n->xoffset = f2->width;
-		n->type = f2->type;
-//		print("lookdot found [%p] %T\n", f2->type, f2->type);
-		n->op = ODOTMETH;
-		return 1;
-	}
-
-	return 0;
-}
-
-static int
-nokeys(NodeList *l)
-{
-	for(; l; l=l->next)
-		if(l->n->op == OKEY)
-			return 0;
-	return 1;
-}
-
-static int
-hasddd(Type *t)
-{
-	Type *tl;
-
-	for(tl=t->type; tl; tl=tl->down) {
-		if(tl->isddd)
-			return 1;
-	}
-	return 0;
-}
-
-static int
-downcount(Type *t)
-{
-	Type *tl;
-	int n;
-
-	n = 0;
-	for(tl=t->type; tl; tl=tl->down) {
-		n++;
-	}
-	return n;
-}
-
-/*
- * typecheck assignment: type list = expression list
- */
-static void
-typecheckaste(int op, Node *call, int isddd, Type *tstruct, NodeList *nl, char *desc)
-{
-	Type *t, *tl, *tn;
-	Node *n;
-	int lno;
-	char *why;
-	int n1, n2;
-
-	lno = lineno;
-
-	if(tstruct->broke)
-		goto out;
-
-	n = N;
-	if(nl != nil && nl->next == nil && (n = nl->n)->type != T)
-	if(n->type->etype == TSTRUCT && n->type->funarg) {
-		if(!hasddd(tstruct)) {
-			n1 = downcount(tstruct);
-			n2 = downcount(n->type);
-			if(n2 > n1)
-				goto toomany;
-			if(n2 < n1)
-				goto notenough;
-		}
-		
-		tn = n->type->type;
-		for(tl=tstruct->type; tl; tl=tl->down) {
-			if(tl->isddd) {
-				for(; tn; tn=tn->down) {
-					if(assignop(tn->type, tl->type->type, &why) == 0) {
-						if(call != N)
-							yyerror("cannot use %T as type %T in argument to %N%s", tn->type, tl->type->type, call, why);
-						else
-							yyerror("cannot use %T as type %T in %s%s", tn->type, tl->type->type, desc, why);
-					}
-				}
-				goto out;
-			}
-			if(tn == T)
-				goto notenough;
-			if(assignop(tn->type, tl->type, &why) == 0) {
-				if(call != N)
-					yyerror("cannot use %T as type %T in argument to %N%s", tn->type, tl->type, call, why);
-				else
-					yyerror("cannot use %T as type %T in %s%s", tn->type, tl->type, desc, why);
-			}
-			tn = tn->down;
-		}
-		if(tn != T)
-			goto toomany;
-		goto out;
-	}
-
-	n1 = downcount(tstruct);
-	n2 = count(nl);
-	if(!hasddd(tstruct)) {
-		if(n2 > n1)
-			goto toomany;
-		if(n2 < n1)
-			goto notenough;
-	}
-	else {
-		if(!isddd) {
-			if(n2 < n1-1)
-				goto notenough;
-		} else {
-			if(n2 > n1)
-				goto toomany;
-			if(n2 < n1)
-				goto notenough;
-		}
-	}
-
-	for(tl=tstruct->type; tl; tl=tl->down) {
-		t = tl->type;
-		if(tl->isddd) {
-			if(isddd) {
-				if(nl == nil)
-					goto notenough;
-				if(nl->next != nil)
-					goto toomany;
-				n = nl->n;
-				setlineno(n);
-				if(n->type != T)
-					nl->n = assignconv(n, t, desc);
-				goto out;
-			}
-			for(; nl; nl=nl->next) {
-				n = nl->n;
-				setlineno(nl->n);
-				if(n->type != T)
-					nl->n = assignconv(n, t->type, desc);
-			}
-			goto out;
-		}
-		if(nl == nil)
-			goto notenough;
-		n = nl->n;
-		setlineno(n);
-		if(n->type != T)
-			nl->n = assignconv(n, t, desc);
-		nl = nl->next;
-	}
-	if(nl != nil)
-		goto toomany;
-	if(isddd) {
-		if(call != N)
-			yyerror("invalid use of ... in call to %N", call);
-		else
-			yyerror("invalid use of ... in %O", op);
-	}
-
-out:
-	lineno = lno;
-	return;
-
-notenough:
-	if(n == N || !n->diag) {
-		if(call != N)
-			yyerror("not enough arguments in call to %N", call);
-		else
-			yyerror("not enough arguments to %O", op);
-		if(n != N)
-			n->diag = 1;
-	}
-	goto out;
-
-toomany:
-	if(call != N)
-		yyerror("too many arguments in call to %N", call);
-	else
-		yyerror("too many arguments to %O", op);
-	goto out;
-}
-
-/*
- * type check composite
- */
-
-static void
-fielddup(Node *n, Node *hash[], ulong nhash)
-{
-	uint h;
-	char *s;
-	Node *a;
-
-	if(n->op != ONAME)
-		fatal("fielddup: not ONAME");
-	s = n->sym->name;
-	h = stringhash(s)%nhash;
-	for(a=hash[h]; a!=N; a=a->ntest) {
-		if(strcmp(a->sym->name, s) == 0) {
-			yyerror("duplicate field name in struct literal: %s", s);
-			return;
-		}
-	}
-	n->ntest = hash[h];
-	hash[h] = n;
-}
-
-static void
-keydup(Node *n, Node *hash[], ulong nhash)
-{
-	uint h;
-	ulong b;
-	double d;
-	int i;
-	Node *a, *orign;
-	Node cmp;
-	char *s;
-
-	orign = n;
-	if(n->op == OCONVIFACE)
-		n = n->left;
-	evconst(n);
-	if(n->op != OLITERAL)
-		return;	// we dont check variables
-
-	switch(n->val.ctype) {
-	default:	// unknown, bool, nil
-		b = 23;
-		break;
-	case CTINT:
-	case CTRUNE:
-		b = mpgetfix(n->val.u.xval);
-		break;
-	case CTFLT:
-		d = mpgetflt(n->val.u.fval);
-		s = (char*)&d;
-		b = 0;
-		for(i=sizeof(d); i>0; i--)
-			b = b*PRIME1 + *s++;
-		break;
-	case CTSTR:
-		b = 0;
-		s = n->val.u.sval->s;
-		for(i=n->val.u.sval->len; i>0; i--)
-			b = b*PRIME1 + *s++;
-		break;
-	}
-
-	h = b%nhash;
-	memset(&cmp, 0, sizeof(cmp));
-	for(a=hash[h]; a!=N; a=a->ntest) {
-		cmp.op = OEQ;
-		cmp.left = n;
-		b = 0;
-		if(a->op == OCONVIFACE && orign->op == OCONVIFACE) {
-			if(eqtype(a->left->type, n->type)) {
-				cmp.right = a->left;
-				evconst(&cmp);
-				b = cmp.val.u.bval;
-			}
-		} else if(eqtype(a->type, n->type)) {
-			cmp.right = a;
-			evconst(&cmp);
-			b = cmp.val.u.bval;
-		}
-		if(b) {
-			yyerror("duplicate key %N in map literal", n);
-			return;
-		}
-	}
-	orign->ntest = hash[h];
-	hash[h] = orign;
-}
-
-static void
-indexdup(Node *n, Node *hash[], ulong nhash)
-{
-	uint h;
-	Node *a;
-	ulong b, c;
-
-	if(n->op != OLITERAL)
-		fatal("indexdup: not OLITERAL");
-
-	b = mpgetfix(n->val.u.xval);
-	h = b%nhash;
-	for(a=hash[h]; a!=N; a=a->ntest) {
-		c = mpgetfix(a->val.u.xval);
-		if(b == c) {
-			yyerror("duplicate index in array literal: %ld", b);
-			return;
-		}
-	}
-	n->ntest = hash[h];
-	hash[h] = n;
-}
-
-static int
-prime(ulong h, ulong sr)
-{
-	ulong n;
-
-	for(n=3; n<=sr; n+=2)
-		if(h%n == 0)
-			return 0;
-	return 1;
-}
-
-static ulong
-inithash(Node *n, Node ***hash, Node **autohash, ulong nautohash)
-{
-	ulong h, sr;
-	NodeList *ll;
-	int i;
-
-	// count the number of entries
-	h = 0;
-	for(ll=n->list; ll; ll=ll->next)
-		h++;
-
-	// if the auto hash table is
-	// large enough use it.
-	if(h <= nautohash) {
-		*hash = autohash;
-		memset(*hash, 0, nautohash * sizeof(**hash));
-		return nautohash;
-	}
-
-	// make hash size odd and 12% larger than entries
-	h += h/8;
-	h |= 1;
-
-	// calculate sqrt of h
-	sr = h/2;
-	for(i=0; i<5; i++)
-		sr = (sr + h/sr)/2;
-
-	// check for primeality
-	while(!prime(h, sr))
-		h += 2;
-
-	// build and return a throw-away hash table
-	*hash = mal(h * sizeof(**hash));
-	memset(*hash, 0, h * sizeof(**hash));
-	return h;
-}
-
-static int
-iscomptype(Type *t)
-{
-	switch(t->etype) {
-	case TARRAY:
-	case TSTRUCT:
-	case TMAP:
-		return 1;
-	case TPTR32:
-	case TPTR64:
-		switch(t->type->etype) {
-		case TARRAY:
-		case TSTRUCT:
-		case TMAP:
-			return 1;
-		}
-		break;
-	}
-	return 0;
-}
-
-static void
-pushtype(Node *n, Type *t)
-{
-	if(n == N || n->op != OCOMPLIT || !iscomptype(t))
-		return;
-	
-	if(n->right == N) {
-		n->right = typenod(t);
-		n->implicit = 1;  // don't print
-		n->right->implicit = 1;  // * is okay
-	}
-	else if(debug['s']) {
-		typecheck(&n->right, Etype);
-		if(n->right->type != T && eqtype(n->right->type, t))
-			print("%lL: redundant type: %T\n", n->lineno, t);
-	}
-}
-
-static void
-typecheckcomplit(Node **np)
-{
-	int bad, i, nerr;
-	int64 len;
-	Node *l, *n, *norig, *r, **hash;
-	NodeList *ll;
-	Type *t, *f;
-	Sym *s, *s1;
-	int32 lno;
-	ulong nhash;
-	Node *autohash[101];
-
-	n = *np;
-	lno = lineno;
-
-	if(n->right == N) {
-		if(n->list != nil)
-			setlineno(n->list->n);
-		yyerror("missing type in composite literal");
-		goto error;
-	}
-
-	// Save original node (including n->right)
-	norig = nod(n->op, N, N);
-	*norig = *n;
-
-	setlineno(n->right);
-	l = typecheck(&n->right /* sic */, Etype|Ecomplit);
-	if((t = l->type) == T)
-		goto error;
-	nerr = nerrors;
-	n->type = t;
-
-	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) {
-			yyerror("invalid pointer type %T for composite literal (use &%T instead)", t, t->type);
-			goto error;
-		}
-		// Also, the underlying type must be a struct, map, slice, or array.
-		if(!iscomptype(t)) {
-			yyerror("invalid pointer type %T for composite literal", t);
-			goto error;
-		}
-		t = t->type;
-	}
-
-	switch(t->etype) {
-	default:
-		yyerror("invalid type for composite literal: %T", t);
-		n->type = T;
-		break;
-
-	case TARRAY:
-		nhash = inithash(n, &hash, autohash, nelem(autohash));
-
-		len = 0;
-		i = 0;
-		for(ll=n->list; ll; ll=ll->next) {
-			l = ll->n;
-			setlineno(l);
-			if(l->op != OKEY) {
-				l = nod(OKEY, nodintconst(i), l);
-				l->left->type = types[TINT];
-				l->left->typecheck = 1;
-				ll->n = l;
-			}
-
-			typecheck(&l->left, Erv);
-			evconst(l->left);
-			i = nonnegconst(l->left);
-			if(i < 0 && !l->left->diag) {
-				yyerror("array index must be non-negative integer constant");
-				l->left->diag = 1;
-				i = -(1<<30);	// stay negative for a while
-			}
-			if(i >= 0)
-				indexdup(l->left, hash, nhash);
-			i++;
-			if(i > len) {
-				len = i;
-				if(t->bound >= 0 && len > t->bound) {
-					setlineno(l);
-					yyerror("array index %lld out of bounds [0:%lld]", len-1, t->bound);
-					t->bound = -1;	// no more errors
-				}
-			}
-
-			r = l->right;
-			pushtype(r, t->type);
-			typecheck(&r, Erv);
-			defaultlit(&r, t->type);
-			l->right = assignconv(r, t->type, "array element");
-		}
-		if(t->bound == -100)
-			t->bound = len;
-		if(t->bound < 0)
-			n->right = nodintconst(len);
-		n->op = OARRAYLIT;
-		break;
-
-	case TMAP:
-		nhash = inithash(n, &hash, autohash, nelem(autohash));
-
-		for(ll=n->list; ll; ll=ll->next) {
-			l = ll->n;
-			setlineno(l);
-			if(l->op != OKEY) {
-				typecheck(&ll->n, Erv);
-				yyerror("missing key in map literal");
-				continue;
-			}
-
-			typecheck(&l->left, Erv);
-			defaultlit(&l->left, t->down);
-			l->left = assignconv(l->left, t->down, "map key");
-			if (l->left->op != OCONV)
-				keydup(l->left, hash, nhash);
-
-			r = l->right;
-			pushtype(r, t->type);
-			typecheck(&r, Erv);
-			defaultlit(&r, t->type);
-			l->right = assignconv(r, t->type, "map value");
-		}
-		n->op = OMAPLIT;
-		break;
-
-	case TSTRUCT:
-		bad = 0;
-		if(n->list != nil && nokeys(n->list)) {
-			// simple list of variables
-			f = t->type;
-			for(ll=n->list; ll; ll=ll->next) {
-				setlineno(ll->n);
-				typecheck(&ll->n, Erv);
-				if(f == nil) {
-					if(!bad++)
-						yyerror("too many values in struct initializer");
-					continue;
-				}
-				s = f->sym;
-				if(s != nil && !exportname(s->name) && s->pkg != localpkg)
-					yyerror("implicit assignment of unexported field '%s' in %T literal", s->name, t);
-				// No pushtype allowed here.  Must name fields for that.
-				ll->n = assignconv(ll->n, f->type, "field value");
-				ll->n = nod(OKEY, newname(f->sym), ll->n);
-				ll->n->left->type = f;
-				ll->n->left->typecheck = 1;
-				f = f->down;
-			}
-			if(f != nil)
-				yyerror("too few values in struct initializer");
-		} else {
-			nhash = inithash(n, &hash, autohash, nelem(autohash));
-
-			// keyed list
-			for(ll=n->list; ll; ll=ll->next) {
-				l = ll->n;
-				setlineno(l);
-				if(l->op != OKEY) {
-					if(!bad++)
-						yyerror("mixture of field:value and value initializers");
-					typecheck(&ll->n, Erv);
-					continue;
-				}
-				s = l->left->sym;
-				if(s == S) {
-					yyerror("invalid field name %N in struct initializer", l->left);
-					typecheck(&l->right, Erv);
-					continue;
-				}
-
-				// Sym might have resolved to name in other top-level
-				// package, because of import dot.  Redirect to correct sym
-				// before we do the lookup.
-				if(s->pkg != localpkg && exportname(s->name)) {
-					s1 = lookup(s->name);
-					if(s1->origpkg == s->pkg)
-						s = s1;
-				}
-				f = lookdot1(nil, s, t, t->type, 0);
-				if(f == nil) {
-					yyerror("unknown %T field '%S' in struct literal", t, s);
-					continue;
-				}
-				l->left = newname(s);
-				l->left->typecheck = 1;
-				l->left->type = f;
-				s = f->sym;
-				fielddup(newname(s), hash, nhash);
-				r = l->right;
-				// No pushtype allowed here.  Tried and rejected.
-				typecheck(&r, Erv);
-				l->right = assignconv(r, f->type, "field value");
-			}
-		}
-		n->op = OSTRUCTLIT;
-		break;
-	}
-	if(nerr != nerrors)
-		goto error;
-	
-	n->orig = norig;
-	if(isptr[n->type->etype]) {
-		n = nod(OPTRLIT, n, N);
-		n->typecheck = 1;
-		n->type = n->left->type;
-		n->left->type = t;
-		n->left->typecheck = 1;
-	}
-
-	n->orig = norig;
-	*np = n;
-	lineno = lno;
-	return;
-
-error:
-	n->type = T;
-	*np = n;
-	lineno = lno;
-}
-
-/*
- * lvalue etc
- */
-int
-islvalue(Node *n)
-{
-	switch(n->op) {
-	case OINDEX:
-		if(isfixedarray(n->left->type))
-			return islvalue(n->left);
-		if(n->left->type != T && n->left->type->etype == TSTRING)
-			return 0;
-		// fall through
-	case OIND:
-	case ODOTPTR:
-	case OCLOSUREVAR:
-		return 1;
-	case ODOT:
-		return islvalue(n->left);
-	case ONAME:
-		if(n->class == PFUNC)
-			return 0;
-		return 1;
-	}
-	return 0;
-}
-
-static void
-checklvalue(Node *n, char *verb)
-{
-	if(!islvalue(n))
-		yyerror("cannot %s %N", verb, n);
-}
-
-static void
-checkassign(Node *n)
-{
-	if(islvalue(n))
-		return;
-	if(n->op == OINDEXMAP) {
-		n->etype = 1;
-		return;
-	}
-
-	// have already complained about n being undefined
-	if(n->op == ONONAME)
-		return;
-
-	yyerror("cannot assign to %N", n);
-}
-
-static void
-checkassignlist(NodeList *l)
-{
-	for(; l; l=l->next)
-		checkassign(l->n);
-}
-
-// Check whether l and r are the same side effect-free expression,
-// so that it is safe to reuse one instead of computing both.
-static int
-samesafeexpr(Node *l, Node *r)
-{
-	if(l->op != r->op || !eqtype(l->type, r->type))
-		return 0;
-	
-	switch(l->op) {
-	case ONAME:
-	case OCLOSUREVAR:
-		return l == r;
-	
-	case ODOT:
-	case ODOTPTR:
-		return l->right != nil && r->right != nil && l->right->sym == r->right->sym && samesafeexpr(l->left, r->left);
-	
-	case OIND:
-		return samesafeexpr(l->left, r->left);
-	
-	case OINDEX:
-		return samesafeexpr(l->left, r->left) && samesafeexpr(l->right, r->right);
-	}
-	
-	return 0;
-}
-
-/*
- * type check assignment.
- * if this assignment is the definition of a var on the left side,
- * fill in the var's type.
- */
-
-static void
-typecheckas(Node *n)
-{
-	// delicate little dance.
-	// the definition of n may refer to this assignment
-	// as its definition, in which case it will call typecheckas.
-	// in that case, do not call typecheck back, or it will cycle.
-	// if the variable has a type (ntype) then typechecking
-	// will not look at defn, so it is okay (and desirable,
-	// so that the conversion below happens).
-	n->left = resolve(n->left);
-	if(n->left->defn != n || n->left->ntype)
-		typecheck(&n->left, Erv | Easgn);
-
-	checkassign(n->left);
-	typecheck(&n->right, Erv);
-	if(n->right && n->right->type != T) {
-		if(n->left->type != T)
-			n->right = assignconv(n->right, n->left->type, "assignment");
-	}
-	if(n->left->defn == n && n->left->ntype == N) {
-		defaultlit(&n->right, T);
-		n->left->type = n->right->type;
-	}
-
-	// second half of dance.
-	// now that right is done, typecheck the left
-	// just to get it over with.  see dance above.
-	n->typecheck = 1;
-	if(n->left->typecheck == 0)
-		typecheck(&n->left, Erv | Easgn);
-	
-	// Recognize slices being updated in place, for better code generation later.
-	// Don't rewrite if using race detector, to avoid needing to teach race detector
-	// about this optimization.
-	if(n->left && n->left->op != OINDEXMAP && n->right && !flag_race) {
-		switch(n->right->op) {
-		case OSLICE:
-		case OSLICE3:
-		case OSLICESTR:
-			// For x = x[0:y], x can be updated in place, without touching pointer.
-			if(samesafeexpr(n->left, n->right->left) && (n->right->right->left == N || iszero(n->right->right->left)))
-				n->right->reslice = 1;
-			break;
-		
-		case OAPPEND:
-			// For x = append(x, ...), x can be updated in place when there is capacity,
-			// without touching the pointer; otherwise the emitted code to growslice
-			// can take care of updating the pointer, and only in that case.
-			if(n->right->list != nil && samesafeexpr(n->left, n->right->list->n))
-				n->right->reslice = 1;
-			break;
-		}
-	}
-}
-
-static void
-checkassignto(Type *src, Node *dst)
-{
-	char *why;
-
-	if(assignop(src, dst->type, &why) == 0) {
-		yyerror("cannot assign %T to %lN in multiple assignment%s", src, dst, why);
-		return;
-	}
-}
-
-static void
-typecheckas2(Node *n)
-{
-	int cl, cr;
-	NodeList *ll, *lr;
-	Node *l, *r;
-	Iter s;
-	Type *t;
-
-	for(ll=n->list; ll; ll=ll->next) {
-		// delicate little dance.
-		ll->n = resolve(ll->n);
-		if(ll->n->defn != n || ll->n->ntype)
-			typecheck(&ll->n, Erv | Easgn);
-	}
-	cl = count(n->list);
-	cr = count(n->rlist);
-	checkassignlist(n->list);
-	if(cl > 1 && cr == 1)
-		typecheck(&n->rlist->n, Erv | Efnstruct);
-	else
-		typechecklist(n->rlist, Erv);
-
-	if(cl == cr) {
-		// easy
-		for(ll=n->list, lr=n->rlist; ll; ll=ll->next, lr=lr->next) {
-			if(ll->n->type != T && lr->n->type != T)
-				lr->n = assignconv(lr->n, ll->n->type, "assignment");
-			if(ll->n->defn == n && ll->n->ntype == N) {
-				defaultlit(&lr->n, T);
-				ll->n->type = lr->n->type;
-			}
-		}
-		goto out;
-	}
-
-
-	l = n->list->n;
-	r = n->rlist->n;
-
-	// m[i] = x, ok
-	if(cl == 1 && cr == 2 && l->op == OINDEXMAP) {
-		if(l->type == T)
-			goto out;
-		yyerror("assignment count mismatch: %d = %d (use delete)", cl, cr);
-		goto out;
-	}
-
-	// x,y,z = f()
-	if(cr == 1) {
-		if(r->type == T)
-			goto out;
-		switch(r->op) {
-		case OCALLMETH:
-		case OCALLINTER:
-		case OCALLFUNC:
-			if(r->type->etype != TSTRUCT || r->type->funarg == 0)
-				break;
-			cr = structcount(r->type);
-			if(cr != cl)
-				goto mismatch;
-			n->op = OAS2FUNC;
-			t = structfirst(&s, &r->type);
-			for(ll=n->list; ll; ll=ll->next) {
-				if(t->type != T && ll->n->type != T)
-					checkassignto(t->type, ll->n);
-				if(ll->n->defn == n && ll->n->ntype == N)
-					ll->n->type = t->type;
-				t = structnext(&s);
-			}
-			goto out;
-		}
-	}
-
-	// x, ok = y
-	if(cl == 2 && cr == 1) {
-		if(r->type == T)
-			goto out;
-		switch(r->op) {
-		case OINDEXMAP:
-			n->op = OAS2MAPR;
-			goto common;
-		case ORECV:
-			n->op = OAS2RECV;
-			goto common;
-		case ODOTTYPE:
-			n->op = OAS2DOTTYPE;
-			r->op = ODOTTYPE2;
-		common:
-			if(l->type != T)
-				checkassignto(r->type, l);
-			if(l->defn == n)
-				l->type = r->type;
-			l = n->list->next->n;
-			if(l->type != T && l->type->etype != TBOOL)
-				checkassignto(types[TBOOL], l);
-			if(l->defn == n && l->ntype == N)
-				l->type = types[TBOOL];
-			goto out;
-		}
-	}
-
-mismatch:
-	yyerror("assignment count mismatch: %d = %d", cl, cr);
-
-out:
-	// second half of dance
-	n->typecheck = 1;
-	for(ll=n->list; ll; ll=ll->next)
-		if(ll->n->typecheck == 0)
-			typecheck(&ll->n, Erv | Easgn);
-}
-
-/*
- * type check function definition
- */
-static void
-typecheckfunc(Node *n)
-{
-	Type *t, *rcvr;
-
-	typecheck(&n->nname, Erv | Easgn);
-	if((t = n->nname->type) == T)
-		return;
-	n->type = t;
-	t->nname = n->nname;
-	rcvr = getthisx(t)->type;
-	if(rcvr != nil && n->shortname != N && !isblank(n->shortname))
-		addmethod(n->shortname->sym, t, 1, n->nname->nointerface);
-}
-
-static void
-stringtoarraylit(Node **np)
-{
-	int32 i;
-	NodeList *l;
-	Strlit *s;
-	char *p, *ep;
-	Rune r;
-	Node *nn, *n;
-
-	n = *np;
-	if(n->left->op != OLITERAL || n->left->val.ctype != CTSTR)
-		fatal("stringtoarraylit %N", n);
-
-	s = n->left->val.u.sval;
-	l = nil;
-	p = s->s;
-	ep = s->s + s->len;
-	i = 0;
-	if(n->type->type->etype == TUINT8) {
-		// raw []byte
-		while(p < ep)
-			l = list(l, nod(OKEY, nodintconst(i++), nodintconst((uchar)*p++)));
-	} else {
-		// utf-8 []rune
-		while(p < ep) {
-			p += chartorune(&r, p);
-			l = list(l, nod(OKEY, nodintconst(i++), nodintconst(r)));
-		}
-	}
-	nn = nod(OCOMPLIT, N, typenod(n->type));
-	nn->list = l;
-	typecheck(&nn, Erv);
-	*np = nn;
-}
-
-
-static int ntypecheckdeftype;
-static NodeList *methodqueue;
-
-static void
-domethod(Node *n)
-{
-	Node *nt;
-	Type *t;
-
-	nt = n->type->nname;
-	typecheck(&nt, Etype);
-	if(nt->type == T) {
-		// type check failed; leave empty func
-		n->type->etype = TFUNC;
-		n->type->nod = N;
-		return;
-	}
-	
-	// If we have
-	//	type I interface {
-	//		M(_ int)
-	//	}
-	// then even though I.M looks like it doesn't care about the
-	// value of its argument, a specific implementation of I may
-	// care.  The _ would suppress the assignment to that argument
-	// while generating a call, so remove it.
-	for(t=getinargx(nt->type)->type; t; t=t->down) {
-		if(t->sym != nil && strcmp(t->sym->name, "_") == 0)
-			t->sym = nil;
-	}
-
-	*n->type = *nt->type;
-	n->type->nod = N;
-	checkwidth(n->type);
-}
-
-static NodeList *mapqueue;
-
-void
-copytype(Node *n, Type *t)
-{
-	int maplineno, embedlineno, lno;
-	NodeList *l;
-
-	if(t->etype == TFORW) {
-		// This type isn't computed yet; when it is, update n.
-		t->copyto = list(t->copyto, n);
-		return;
-	}
-
-	maplineno = n->type->maplineno;
-	embedlineno = n->type->embedlineno;
-
-	l = n->type->copyto;
-	*n->type = *t;
-
-	t = n->type;
-	t->sym = n->sym;
-	t->local = n->local;
-	t->vargen = n->vargen;
-	t->siggen = 0;
-	t->method = nil;
-	t->xmethod = nil;
-	t->nod = N;
-	t->printed = 0;
-	t->deferwidth = 0;
-	t->copyto = nil;
-	
-	// Update nodes waiting on this type.
-	for(; l; l=l->next)
-		copytype(l->n, t);
-
-	// Double-check use of type as embedded type.
-	lno = lineno;
-	if(embedlineno) {
-		lineno = embedlineno;
-		if(isptr[t->etype])
-			yyerror("embedded type cannot be a pointer");
-	}
-	lineno = lno;
-	
-	// Queue check for map until all the types are done settling.
-	if(maplineno) {
-		t->maplineno = maplineno;
-		mapqueue = list(mapqueue, n);
-	}
-}
-
-static void
-typecheckdeftype(Node *n)
-{
-	int lno;
-	Type *t;
-	NodeList *l;
-
-	ntypecheckdeftype++;
-	lno = lineno;
-	setlineno(n);
-	n->type->sym = n->sym;
-	n->typecheck = 1;
-	typecheck(&n->ntype, Etype);
-	if((t = n->ntype->type) == T) {
-		n->diag = 1;
-		n->type = T;
-		goto ret;
-	}
-	if(n->type == T) {
-		n->diag = 1;
-		goto ret;
-	}
-
-	// copy new type and clear fields
-	// that don't come along.
-	// anything zeroed here must be zeroed in
-	// typedcl2 too.
-	copytype(n, t);
-
-ret:
-	lineno = lno;
-
-	// if there are no type definitions going on, it's safe to
-	// try to resolve the method types for the interfaces
-	// we just read.
-	if(ntypecheckdeftype == 1) {
-		while((l = methodqueue) != nil) {
-			methodqueue = nil;
-			for(; l; l=l->next)
-				domethod(l->n);
-		}
-		for(l=mapqueue; l; l=l->next) {
-			lineno = l->n->type->maplineno;
-			maptype(l->n->type, types[TBOOL]);
-		}
-		lineno = lno;
-	}
-	ntypecheckdeftype--;
-}
-
-void
-queuemethod(Node *n)
-{
-	if(ntypecheckdeftype == 0) {
-		domethod(n);
-		return;
-	}
-	methodqueue = list(methodqueue, n);
-}
-
-Node*
-typecheckdef(Node *n)
-{
-	int lno, nerrors0;
-	Node *e;
-	Type *t;
-	NodeList *l;
-
-	lno = lineno;
-	setlineno(n);
-
-	if(n->op == ONONAME) {
-		if(!n->diag) {
-			n->diag = 1;
-			if(n->lineno != 0)
-				lineno = n->lineno;
-			yyerror("undefined: %S", n->sym);
-		}
-		return n;
-	}
-
-	if(n->walkdef == 1)
-		return n;
-
-	l = mal(sizeof *l);
-	l->n = n;
-	l->next = typecheckdefstack;
-	typecheckdefstack = l;
-
-	if(n->walkdef == 2) {
-		flusherrors();
-		print("typecheckdef loop:");
-		for(l=typecheckdefstack; l; l=l->next)
-			print(" %S", l->n->sym);
-		print("\n");
-		fatal("typecheckdef loop");
-	}
-	n->walkdef = 2;
-
-	if(n->type != T || n->sym == S)	// builtin or no name
-		goto ret;
-
-	switch(n->op) {
-	default:
-		fatal("typecheckdef %O", n->op);
-
-	case OGOTO:
-	case OLABEL:
-		// not really syms
-		break;
-
-	case OLITERAL:
-		if(n->ntype != N) {
-			typecheck(&n->ntype, Etype);
-			n->type = n->ntype->type;
-			n->ntype = N;
-			if(n->type == T) {
-				n->diag = 1;
-				goto ret;
-			}
-		}
-		e = n->defn;
-		n->defn = N;
-		if(e == N) {
-			lineno = n->lineno;
-			dump("typecheckdef nil defn", n);
-			yyerror("xxx");
-		}
-		typecheck(&e, Erv | Eiota);
-		if(isconst(e, CTNIL)) {
-			yyerror("const initializer cannot be nil");
-			goto ret;
-		}
-		if(e->type != T && e->op != OLITERAL || !isgoconst(e)) {
-			if(!e->diag) {
-				yyerror("const initializer %N is not a constant", e);
-				e->diag = 1;
-			}
-			goto ret;
-		}
-		t = n->type;
-		if(t != T) {
-			if(!okforconst[t->etype]) {
-				yyerror("invalid constant type %T", t);
-				goto ret;
-			}
-			if(!isideal(e->type) && !eqtype(t, e->type)) {
-				yyerror("cannot use %lN as type %T in const initializer", e, t);
-				goto ret;
-			}
-			convlit(&e, t);
-		}
-		n->val = e->val;
-		n->type = e->type;
-		break;
-
-	case ONAME:
-		if(n->ntype != N) {
-			typecheck(&n->ntype, Etype);
-			n->type = n->ntype->type;
-
-			if(n->type == T) {
-				n->diag = 1;
-				goto ret;
-			}
-		}
-		if(n->type != T)
-			break;
-		if(n->defn == N) {
-			if(n->etype != 0)	// like OPRINTN
-				break;
-			if(nsavederrors+nerrors > 0) {
-				// Can have undefined variables in x := foo
-				// that make x have an n->ndefn == nil.
-				// If there are other errors anyway, don't
-				// bother adding to the noise.
-				break;
-			}
-			fatal("var without type, init: %S", n->sym);
-		}
-		if(n->defn->op == ONAME) {
-			typecheck(&n->defn, Erv);
-			n->type = n->defn->type;
-			break;
-		}
-		typecheck(&n->defn, Etop);	// fills in n->type
-		break;
-
-	case OTYPE:
-		if(curfn)
-			defercheckwidth();
-		n->walkdef = 1;
-		n->type = typ(TFORW);
-		n->type->sym = n->sym;
-		nerrors0 = nerrors;
-		typecheckdeftype(n);
-		if(n->type->etype == TFORW && nerrors > nerrors0) {
-			// Something went wrong during type-checking,
-			// but it was reported. Silence future errors.
-			n->type->broke = 1;
-		}
-		if(curfn)
-			resumecheckwidth();
-		break;
-
-	case OPACK:
-		// nothing to see here
-		break;
-	}
-
-ret:
-	if(n->op != OLITERAL && n->type != T && isideal(n->type))
-		fatal("got %T for %N", n->type, n);
-	if(typecheckdefstack->n != n)
-		fatal("typecheckdefstack mismatch");
-	l = typecheckdefstack;
-	typecheckdefstack = l->next;
-
-	lineno = lno;
-	n->walkdef = 1;
-	return n;
-}
-
-static int
-checkmake(Type *t, char *arg, Node *n)
-{
-	if(n->op == OLITERAL) {
-		switch(n->val.ctype) {
-		case CTINT:
-		case CTRUNE:
-		case CTFLT:
-		case CTCPLX:
-			n->val = toint(n->val);
-			if(mpcmpfixc(n->val.u.xval, 0) < 0) {
-				yyerror("negative %s argument in make(%T)", arg, t);
-				return -1;
-			}
-			if(mpcmpfixfix(n->val.u.xval, maxintval[TINT]) > 0) {
-				yyerror("%s argument too large in make(%T)", arg, t);
-				return -1;
-			}
-			
-			// Delay defaultlit until after we've checked range, to avoid
-			// a redundant "constant NNN overflows int" error.
-			defaultlit(&n, types[TINT]);
-			return 0;
-		default:
-		       	break;
-		}
-	}
-
-	if(!isint[n->type->etype] && n->type->etype != TIDEAL) {
-		yyerror("non-integer %s argument in make(%T) - %T", arg, t, n->type);
-		return -1;
-	}
-
-	// Defaultlit still necessary for non-constant: n might be 1<<k.
-	defaultlit(&n, types[TINT]);
-
-	return 0;
-}
-
-static void	markbreaklist(NodeList*, Node*);
-
-static void
-markbreak(Node *n, Node *implicit)
-{
-	Label *lab;
-
-	if(n == N)
-		return;
-
-	switch(n->op) {
-	case OBREAK:
-		if(n->left == N) {
-			if(implicit)
-				implicit->hasbreak = 1;
-		} else {
-			lab = n->left->sym->label;
-			if(lab != L)
-				lab->def->hasbreak = 1;
-		}
-		break;
-	
-	case OFOR:
-	case OSWITCH:
-	case OTYPESW:
-	case OSELECT:
-	case ORANGE:
-		implicit = n;
-		// fall through
-	
-	default:
-		markbreak(n->left, implicit);
-		markbreak(n->right, implicit);
-		markbreak(n->ntest, implicit);
-		markbreak(n->nincr, implicit);
-		markbreaklist(n->ninit, implicit);
-		markbreaklist(n->nbody, implicit);
-		markbreaklist(n->nelse, implicit);
-		markbreaklist(n->list, implicit);
-		markbreaklist(n->rlist, implicit);
-		break;
-	}
-}
-
-static void
-markbreaklist(NodeList *l, Node *implicit)
-{
-	Node *n;
-	Label *lab;
-
-	for(; l; l=l->next) {
-		n = l->n;
-		if(n->op == OLABEL && l->next && n->defn == l->next->n) {
-			switch(n->defn->op) {
-			case OFOR:
-			case OSWITCH:
-			case OTYPESW:
-			case OSELECT:
-			case ORANGE:
-				lab = mal(sizeof *lab);
-				lab->def = n->defn;
-				n->left->sym->label = lab;
-				markbreak(n->defn, n->defn);
-				n->left->sym->label = L;
-				l = l->next;
-				continue;
-			}
-		}
-		markbreak(n, implicit);
-	}
-}
-
-static int
-isterminating(NodeList *l, int top)
-{
-	int def;
-	Node *n;
-
-	if(l == nil)
-		return 0;
-	if(top) {
-		while(l->next && l->n->op != OLABEL)
-			l = l->next;
-		markbreaklist(l, nil);
-	}
-	while(l->next)
-		l = l->next;
-	n = l->n;
-
-	if(n == N)
-		return 0;
-
-	switch(n->op) {
-	// NOTE: OLABEL is treated as a separate statement,
-	// not a separate prefix, so skipping to the last statement
-	// in the block handles the labeled statement case by
-	// skipping over the label. No case OLABEL here.
-
-	case OBLOCK:
-		return isterminating(n->list, 0);
-
-	case OGOTO:
-	case ORETURN:
-	case ORETJMP:
-	case OPANIC:
-	case OXFALL:
-		return 1;
-
-	case OFOR:
-		if(n->ntest != N)
-			return 0;
-		if(n->hasbreak)
-			return 0;
-		return 1;
-
-	case OIF:
-		return isterminating(n->nbody, 0) && isterminating(n->nelse, 0);
-
-	case OSWITCH:
-	case OTYPESW:
-	case OSELECT:
-		if(n->hasbreak)
-			return 0;
-		def = 0;
-		for(l=n->list; l; l=l->next) {
-			if(!isterminating(l->n->nbody, 0))
-				return 0;
-			if(l->n->list == nil) // default
-				def = 1;
-		}
-		if(n->op != OSELECT && !def)
-			return 0;
-		return 1;
-	}
-	
-	return 0;
-}
-
-void
-checkreturn(Node *fn)
-{
-	if(fn->type->outtuple && fn->nbody != nil)
-		if(!isterminating(fn->nbody, 1))
-			yyerrorl(fn->endlineno, "missing return at end of function");
-}
diff --git a/src/cmd/gc/unsafe.c b/src/cmd/gc/unsafe.c
deleted file mode 100644
index ff08c0e..0000000
--- a/src/cmd/gc/unsafe.c
+++ /dev/null
@@ -1,148 +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 <u.h>
-#include <libc.h>
-#include "go.h"
-
-/*
- * look for
- *	unsafe.Sizeof
- *	unsafe.Offsetof
- *	unsafe.Alignof
- * rewrite with a constant
- */
-Node*
-unsafenmagic(Node *nn)
-{
-	Node *r, *n, *base, *r1;
-	Sym *s;
-	Type *t, *tr;
-	vlong v;
-	Val val;
-	Node *fn;
-	NodeList *args;
-
-	fn = nn->left;
-	args = nn->list;
-
-	if(safemode || fn == N || fn->op != ONAME || (s = fn->sym) == S)
-		goto no;
-	if(s->pkg != unsafepkg)
-		goto no;
-
-	if(args == nil) {
-		yyerror("missing argument for %S", s);
-		goto no;
-	}
-	r = args->n;
-
-	if(strcmp(s->name, "Sizeof") == 0) {
-		typecheck(&r, Erv);
-		defaultlit(&r, T);
-		tr = r->type;
-		if(tr == T)
-			goto bad;
-		dowidth(tr);
-		v = tr->width;
-		goto yes;
-	}
-	if(strcmp(s->name, "Offsetof") == 0) {
-		// must be a selector.
-		if(r->op != OXDOT)
-			goto bad;
-		// Remember base of selector to find it back after dot insertion.
-		// Since r->left may be mutated by typechecking, check it explicitly
-		// first to track it correctly.
-		typecheck(&r->left, Erv);
-		base = r->left;
-		typecheck(&r, Erv);
-		switch(r->op) {
-		case ODOT:
-		case ODOTPTR:
-			break;
-		case OCALLPART:
-			yyerror("invalid expression %N: argument is a method value", nn);
-			v = 0;
-			goto ret;
-		default:
-			goto bad;
-		}
-		v = 0;
-		// add offsets for inserted dots.
-		for(r1=r; r1->left!=base; r1=r1->left) {
-			switch(r1->op) {
-			case ODOT:
-				v += r1->xoffset;
-				break;
-			case ODOTPTR:
-				yyerror("invalid expression %N: selector implies indirection of embedded %N", nn, r1->left);
-				goto ret;
-			default:
-				dump("unsafenmagic", r);
-				fatal("impossible %#O node after dot insertion", r1->op);
-				goto bad;
-			}
-		}
-		v += r1->xoffset;
-		goto yes;
-	}
-	if(strcmp(s->name, "Alignof") == 0) {
-		typecheck(&r, Erv);
-		defaultlit(&r, T);
-		tr = r->type;
-		if(tr == T)
-			goto bad;
-
-		// make struct { byte; T; }
-		t = typ(TSTRUCT);
-		t->type = typ(TFIELD);
-		t->type->type = types[TUINT8];
-		t->type->down = typ(TFIELD);
-		t->type->down->type = tr;
-		// compute struct widths
-		dowidth(t);
-
-		// the offset of T is its required alignment
-		v = t->type->down->width;
-		goto yes;
-	}
-
-no:
-	return N;
-
-bad:
-	yyerror("invalid expression %N", nn);
-	v = 0;
-	goto ret;
-
-yes:
-	if(args->next != nil)
-		yyerror("extra arguments for %S", s);
-ret:
-	// any side effects disappear; ignore init
-	val.ctype = CTINT;
-	val.u.xval = mal(sizeof(*n->val.u.xval));
-	mpmovecfix(val.u.xval, v);
-	n = nod(OLITERAL, N, N);
-	n->orig = nn;
-	n->val = val;
-	n->type = types[TUINTPTR];
-	nn->type = types[TUINTPTR];
-	return n;
-}
-
-int
-isunsafebuiltin(Node *n)
-{
-	if(n == N || n->op != ONAME || n->sym == S || n->sym->pkg != unsafepkg)
-		return 0;
-	if(strcmp(n->sym->name, "Sizeof") == 0)
-		return 1;
-	if(strcmp(n->sym->name, "Offsetof") == 0)
-		return 1;
-	if(strcmp(n->sym->name, "Alignof") == 0)
-		return 1;
-	return 0;
-}
diff --git a/src/cmd/gc/unsafe.go b/src/cmd/gc/unsafe.go
deleted file mode 100644
index c3c6278..0000000
--- a/src/cmd/gc/unsafe.go
+++ /dev/null
@@ -1,18 +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.
-
-// NOTE: If you change this file you must run "./mkbuiltin"
-// to update builtin.c.boot.  This is not done automatically
-// to avoid depending on having a working compiler binary.
-
-// +build ignore
-
-package PACKAGE
-
-type Pointer uintptr // not really; filled in by compiler
-
-// return types here are ignored; see unsafe.c
-func Offsetof(any) uintptr
-func Sizeof(any) uintptr
-func Alignof(any) uintptr
diff --git a/src/cmd/gc/walk.c b/src/cmd/gc/walk.c
deleted file mode 100644
index ff9b362..0000000
--- a/src/cmd/gc/walk.c
+++ /dev/null
@@ -1,3937 +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	<u.h>
-#include	<libc.h>
-#include	"go.h"
-#include	"../ld/textflag.h"
-
-static	Node*	walkprint(Node*, NodeList**);
-static	Node*	writebarrierfn(char*, Type*, Type*);
-static	Node*	applywritebarrier(Node*, NodeList**);
-static	Node*	mapfn(char*, Type*);
-static	Node*	mapfndel(char*, Type*);
-static	Node*	ascompatee1(int, Node*, Node*, NodeList**);
-static	NodeList*	ascompatee(int, NodeList*, NodeList*, NodeList**);
-static	NodeList*	ascompatet(int, NodeList*, Type**, int, NodeList**);
-static	NodeList*	ascompatte(int, Node*, int, Type**, NodeList*, int, NodeList**);
-static	Node*	convas(Node*, NodeList**);
-static	void	heapmoves(void);
-static	NodeList*	paramstoheap(Type **argin, int out);
-static	NodeList*	reorder1(NodeList*);
-static	NodeList*	reorder3(NodeList*);
-static	Node*	addstr(Node*, NodeList**);
-static	Node*	appendslice(Node*, NodeList**);
-static	Node*	append(Node*, NodeList**);
-static	Node*	copyany(Node*, NodeList**, int);
-static	Node*	sliceany(Node*, NodeList**);
-static	void	walkcompare(Node**, NodeList**);
-static	void	walkrotate(Node**);
-static	void	walkmul(Node**, NodeList**);
-static	void	walkdiv(Node**, NodeList**);
-static	int	bounded(Node*, int64);
-static	Mpint	mpzero;
-static	void	walkprintfunc(Node**, NodeList**);
-
-void
-walk(Node *fn)
-{
-	char s[50];
-	NodeList *l;
-	int lno;
-
-	curfn = fn;
-
-	if(debug['W']) {
-		snprint(s, sizeof(s), "\nbefore %S", curfn->nname->sym);
-		dumplist(s, curfn->nbody);
-	}
-
-	lno = lineno;
-
-	// 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; 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; l=l->next)
-		if(l->n->op == ONAME && (l->n->class&~PHEAP) == PAUTO && l->n->defn && l->n->defn->op == OTYPESW && l->n->used)
-			l->n->defn->left->used++;
-	
-	for(l=fn->dcl; l; 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 && l->n->defn->op == OTYPESW) {
-			if(l->n->defn->left->used)
-				continue;
-			lineno = l->n->defn->left->lineno;
-			yyerror("%S declared and not used", l->n->sym);
-			l->n->defn->left->used = 1; // suppress repeats
-		} else {
-			lineno = l->n->lineno;
-			yyerror("%S declared and not used", l->n->sym);
-		}
-	}	
-
-	lineno = lno;
-	if(nerrors != 0)
-		return;
-	walkstmtlist(curfn->nbody);
-	if(debug['W']) {
-		snprint(s, sizeof(s), "after walk %S", curfn->nname->sym);
-		dumplist(s, curfn->nbody);
-	}
-	heapmoves();
-	if(debug['W'] && curfn->enter != nil) {
-		snprint(s, sizeof(s), "enter %S", curfn->nname->sym);
-		dumplist(s, curfn->enter);
-	}
-}
-
-
-void
-walkstmtlist(NodeList *l)
-{
-	for(; l; l=l->next)
-		walkstmt(&l->n);
-}
-
-static int
-samelist(NodeList *a, NodeList *b)
-{
-	for(; a && b; a=a->next, b=b->next)
-		if(a->n != b->n)
-			return 0;
-	return a == b;
-}
-
-static int
-paramoutheap(Node *fn)
-{
-	NodeList *l;
-
-	for(l=fn->dcl; l; l=l->next) {
-		switch(l->n->class) {
-		case PPARAMOUT:
-		case PPARAMOUT|PHEAP:
-			return l->n->addrtaken;
-		case PAUTO:
-		case PAUTO|PHEAP:
-			// stop early - parameters are over
-			return 0;
-		}
-	}
-	return 0;
-}
-
-void
-walkstmt(Node **np)
-{
-	NodeList *init;
-	NodeList *ll, *rl;
-	int cl;
-	Node *n, *f;
-
-	n = *np;
-	if(n == N)
-		return;
-	if(n->dodata == 2) // don't walk, generated by anylit.
-		return;
-
-	setlineno(n);
-
-	walkstmtlist(n->ninit);
-
-	switch(n->op) {
-	default:
-		if(n->op == ONAME)
-			yyerror("%S is not a top level statement", n->sym);
-		else
-			yyerror("%O is not a top level statement", n->op);
-		dump("nottop", n);
-		break;
-
-	case OAS:
-	case OASOP:
-	case OAS2:
-	case OAS2DOTTYPE:
-	case OAS2RECV:
-	case OAS2FUNC:
-	case OAS2MAPR:
-	case OCLOSE:
-	case OCOPY:
-	case OCALLMETH:
-	case OCALLINTER:
-	case OCALL:
-	case OCALLFUNC:
-	case ODELETE:
-	case OSEND:
-	case OPRINT:
-	case OPRINTN:
-	case OPANIC:
-	case OEMPTY:
-	case ORECOVER:
-		if(n->typecheck == 0)
-			fatal("missing typecheck: %+N", n);
-		init = n->ninit;
-		n->ninit = nil;
-		walkexpr(&n, &init);
-		addinit(&n, init);
-		if((*np)->op == OCOPY && n->op == OCONVNOP)
-			n->op = OEMPTY; // don't leave plain values as statements.
-		break;
-
-	case ORECV:
-		// special case for a receive where we throw away
-		// the value received.
-		if(n->typecheck == 0)
-			fatal("missing typecheck: %+N", n);
-		init = n->ninit;
-		n->ninit = nil;
-
-		walkexpr(&n->left, &init);
-		n = mkcall1(chanfn("chanrecv1", 2, n->left->type), T, &init, typename(n->left->type), n->left, nodnil());
-		walkexpr(&n, &init);
-
-		addinit(&n, init);
-		break;
-
-	case OBREAK:
-	case ODCL:
-	case OCONTINUE:
-	case OFALL:
-	case OGOTO:
-	case OLABEL:
-	case ODCLCONST:
-	case ODCLTYPE:
-	case OCHECKNIL:
-	case OVARKILL:
-		break;
-
-	case OBLOCK:
-		walkstmtlist(n->list);
-		break;
-
-	case OXCASE:
-		yyerror("case statement out of place");
-		n->op = OCASE;
-	case OCASE:
-		walkstmt(&n->right);
-		break;
-
-	case ODEFER:
-		hasdefer = 1;
-		switch(n->left->op) {
-		case OPRINT:
-		case OPRINTN:
-			walkprintfunc(&n->left, &n->ninit);
-			break;
-		case OCOPY:
-			n->left = copyany(n->left, &n->ninit, 1);
-			break;
-		default:
-			walkexpr(&n->left, &n->ninit);
-			break;
-		}
-		break;
-
-	case OFOR:
-		if(n->ntest != N) {
-			walkstmtlist(n->ntest->ninit);
-			init = n->ntest->ninit;
-			n->ntest->ninit = nil;
-			walkexpr(&n->ntest, &init);
-			addinit(&n->ntest, init);
-		}
-		walkstmt(&n->nincr);
-		walkstmtlist(n->nbody);
-		break;
-
-	case OIF:
-		walkexpr(&n->ntest, &n->ninit);
-		walkstmtlist(n->nbody);
-		walkstmtlist(n->nelse);
-		break;
-
-	case OPROC:
-		switch(n->left->op) {
-		case OPRINT:
-		case OPRINTN:
-			walkprintfunc(&n->left, &n->ninit);
-			break;
-		case OCOPY:
-			n->left = copyany(n->left, &n->ninit, 1);
-			break;
-		default:
-			walkexpr(&n->left, &n->ninit);
-			break;
-		}
-		break;
-
-	case ORETURN:
-		walkexprlist(n->list, &n->ninit);
-		if(n->list == nil)
-			break;
-		if((curfn->type->outnamed && count(n->list) > 1) || paramoutheap(curfn)) {
-			// assign to the function out parameters,
-			// so that reorder3 can fix up conflicts
-			rl = nil;
-			for(ll=curfn->dcl; ll != nil; ll=ll->next) {
-				cl = ll->n->class & ~PHEAP;
-				if(cl == PAUTO)
-					break;
-				if(cl == PPARAMOUT)
-					rl = list(rl, ll->n);
-			}
-			if(samelist(rl, n->list)) {
-				// special return in disguise
-				n->list = nil;
-				break;
-			}
-			if(count(n->list) == 1 && count(rl) > 1) {
-				// OAS2FUNC in disguise
-				f = n->list->n;
-				if(f->op != OCALLFUNC && f->op != OCALLMETH && f->op != OCALLINTER)
-					fatal("expected return of call, have %N", f);
-				n->list = concat(list1(f), ascompatet(n->op, rl, &f->type, 0, &n->ninit));
-				break;
-			}
-
-			// move function calls out, to make reorder3's job easier.
-			walkexprlistsafe(n->list, &n->ninit);
-			ll = ascompatee(n->op, rl, n->list, &n->ninit);
-			n->list = reorder3(ll);
-			break;
-		}
-		ll = ascompatte(n->op, nil, 0, getoutarg(curfn->type), n->list, 1, &n->ninit);
-		n->list = ll;
-		break;
-
-	case ORETJMP:
-		break;
-
-	case OSELECT:
-		walkselect(n);
-		break;
-
-	case OSWITCH:
-		walkswitch(n);
-		break;
-
-	case ORANGE:
-		walkrange(n);
-		break;
-
-	case OXFALL:
-		yyerror("fallthrough statement out of place");
-		n->op = OFALL;
-		break;
-	}
-
-	if(n->op == ONAME)
-		fatal("walkstmt ended up with name: %+N", n);
-	
-	*np = n;
-}
-
-
-/*
- * walk the whole tree of the body of an
- * expression or simple statement.
- * the types expressions are calculated.
- * compile-time constants are evaluated.
- * complex side effects like statements are appended to init
- */
-
-void
-walkexprlist(NodeList *l, NodeList **init)
-{
-	for(; l; l=l->next)
-		walkexpr(&l->n, init);
-}
-
-void
-walkexprlistsafe(NodeList *l, NodeList **init)
-{
-	for(; l; l=l->next) {
-		l->n = safeexpr(l->n, init);
-		walkexpr(&l->n, init);
-	}
-}
-
-void
-walkexpr(Node **np, NodeList **init)
-{
-	Node *r, *l, *var, *a;
-	Node *map, *key;
-	NodeList *ll, *lr;
-	Type *t;
-	int et, old_safemode;
-	int64 v;
-	int32 lno;
-	Node *n, *fn, *n1, *n2;
-	Sym *sym;
-	char buf[100], *p;
-
-	n = *np;
-
-	if(n == N)
-		return;
-
-	if(init == &n->ninit) {
-		// not okay to use n->ninit when walking n,
-		// because we might replace n with some other node
-		// and would lose the init list.
-		fatal("walkexpr init == &n->ninit");
-	}
-
-	if(n->ninit != nil) {
-		walkstmtlist(n->ninit);
-		*init = concat(*init, n->ninit);
-		n->ninit = nil;
-	}
-
-	// annoying case - not typechecked
-	if(n->op == OKEY) {
-		walkexpr(&n->left, init);
-		walkexpr(&n->right, init);
-		return;
-	}
-
-	lno = setlineno(n);
-
-	if(debug['w'] > 1)
-		dump("walk-before", n);
-
-	if(n->typecheck != 1)
-		fatal("missed typecheck: %+N\n", n);
-
-	switch(n->op) {
-	default:
-		dump("walk", n);
-		fatal("walkexpr: switch 1 unknown op %+hN", n);
-		break;
-
-	case OTYPE:
-	case ONONAME:
-	case OINDREG:
-	case OEMPTY:
-		goto ret;
-
-	case ONOT:
-	case OMINUS:
-	case OPLUS:
-	case OCOM:
-	case OREAL:
-	case OIMAG:
-	case ODOTMETH:
-	case ODOTINTER:
-		walkexpr(&n->left, init);
-		goto ret;
-
-	case OIND:
-		walkexpr(&n->left, init);
-		goto ret;
-
-	case ODOT:
-		usefield(n);
-		walkexpr(&n->left, init);
-		goto ret;
-
-	case ODOTPTR:
-		usefield(n);
-		if(n->op == ODOTPTR && n->left->type->type->width == 0) {
-			// No actual copy will be generated, so emit an explicit nil check.
-			n->left = cheapexpr(n->left, init);
-			checknil(n->left, init);
-		}
-		walkexpr(&n->left, init);
-		goto ret;
-
-	case OEFACE:
-		walkexpr(&n->left, init);
-		walkexpr(&n->right, init);
-		goto ret;
-
-	case OSPTR:
-	case OITAB:
-		walkexpr(&n->left, init);
-		goto ret;
-
-	case OLEN:
-	case 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])
-			t = t->type;
-		if(isfixedarray(t)) {
-			safeexpr(n->left, init);
-			nodconst(n, n->type, t->bound);
-			n->typecheck = 1;
-		}
-		goto ret;
-
-	case OLSH:
-	case ORSH:
-		walkexpr(&n->left, init);
-		walkexpr(&n->right, init);
-		t = n->left->type;
-		n->bounded = bounded(n->right, 8*t->width);
-		if(debug['m'] && n->etype && !isconst(n->right, CTINT))
-			warn("shift bounds check elided");
-		goto ret;
-
-	case OAND:
-	case OSUB:
-	case OHMUL:
-	case OLT:
-	case OLE:
-	case OGE:
-	case OGT:
-	case OADD:
-	case OCOMPLEX:
-	case OLROT:
-		// Use results from call expression as arguments for complex.
-		if(n->op == OCOMPLEX && n->left == N && n->right == N) {
-			n->left = n->list->n;
-			n->right = n->list->next->n;
-		}
-		walkexpr(&n->left, init);
-		walkexpr(&n->right, init);
-		goto ret;
-
-	case OOR:
-	case OXOR:
-		walkexpr(&n->left, init);
-		walkexpr(&n->right, init);
-		walkrotate(&n);
-		goto ret;
-
-	case OEQ:
-	case ONE:
-		walkexpr(&n->left, init);
-		walkexpr(&n->right, init);
-		// Disable safemode while compiling this code: the code we
-		// generate internally can refer to unsafe.Pointer.
-		// In this case it can happen if we need to generate an ==
-		// for a struct containing a reflect.Value, which itself has
-		// an unexported field of type unsafe.Pointer.
-		old_safemode = safemode;
-		safemode = 0;
-		walkcompare(&n, init);
-		safemode = old_safemode;
-		goto ret;
-
-	case OANDAND:
-	case 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 = nil;
-		walkexpr(&n->right, &ll);
-		addinit(&n->right, ll);
-		goto ret;
-
-	case OPRINT:
-	case OPRINTN:
-		walkexprlist(n->list, init);
-		n = walkprint(n, init);
-		goto ret;
-
-	case OPANIC:
-		n = mkcall("gopanic", T, init, n->left);
-		goto ret;
-
-	case ORECOVER:
-		n = mkcall("gorecover", n->type, init, nod(OADDR, nodfp, N));
-		goto ret;
-
-	case OLITERAL:
-		n->addable = 1;
-		goto ret;
-
-	case OCLOSUREVAR:
-	case OCFUNC:
-		n->addable = 1;
-		goto ret;
-
-	case ONAME:
-		if(!(n->class & PHEAP) && n->class != PPARAMREF)
-			n->addable = 1;
-		goto ret;
-
-	case OCALLINTER:
-		t = n->left->type;
-		if(n->list && n->list->n->op == OAS)
-			goto ret;
-		walkexpr(&n->left, init);
-		walkexprlist(n->list, init);
-		ll = ascompatte(n->op, n, n->isddd, getinarg(t), n->list, 0, init);
-		n->list = reorder1(ll);
-		goto ret;
-
-	case OCALLFUNC:
-		t = n->left->type;
-		if(n->list && n->list->n->op == OAS)
-			goto ret;
-
-		walkexpr(&n->left, init);
-		walkexprlist(n->list, init);
-
-		ll = ascompatte(n->op, n, n->isddd, getinarg(t), n->list, 0, init);
-		n->list = reorder1(ll);
-		goto ret;
-
-	case OCALLMETH:
-		t = n->left->type;
-		if(n->list && n->list->n->op == OAS)
-			goto ret;
-		walkexpr(&n->left, init);
-		walkexprlist(n->list, init);
-		ll = ascompatte(n->op, n, 0, getthis(t), list1(n->left->left), 0, init);
-		lr = ascompatte(n->op, n, n->isddd, getinarg(t), n->list, 0, init);
-		ll = concat(ll, lr);
-		n->left->left = N;
-		ullmancalc(n->left);
-		n->list = reorder1(ll);
-		goto ret;
-
-	case OAS:
-		*init = concat(*init, n->ninit);
-		n->ninit = nil;
-
-		walkexpr(&n->left, init);
-		n->left = safeexpr(n->left, init);
-
-		if(oaslit(n, init))
-			goto ret;
-
-		if(n->right == N || iszero(n->right) && !flag_race)
-			goto ret;
-
-		switch(n->right->op) {
-		default:
-			walkexpr(&n->right, init);
-			break;
-		
-		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, N);
-			r = n->right->left; // the channel
-			n = mkcall1(chanfn("chanrecv1", 2, r->type), T, init, typename(r->type), r, n1);
-			walkexpr(&n, init);
-			goto ret;
-		}
-
-		if(n->left != N && n->right != N) {
-			r = convas(nod(OAS, n->left, n->right), init);
-			r->dodata = n->dodata;
-			n = r;
-			n = applywritebarrier(n, init);
-		}
-
-		goto ret;
-
-	case OAS2:
-		*init = concat(*init, n->ninit);
-		n->ninit = nil;
-		walkexprlistsafe(n->list, init);
-		walkexprlistsafe(n->rlist, init);
-		ll = ascompatee(OAS, n->list, n->rlist, init);
-		ll = reorder3(ll);
-		for(lr = ll; lr != nil; lr = lr->next)
-			lr->n = applywritebarrier(lr->n, init);
-		n = liststmt(ll);
-		goto ret;
-
-	case OAS2FUNC:
-		// a,b,... = fn()
-		*init = concat(*init, n->ninit);
-		n->ninit = nil;
-		r = n->rlist->n;
-		walkexprlistsafe(n->list, init);
-		walkexpr(&r, init);
-
-		ll = ascompatet(n->op, n->list, &r->type, 0, init);
-		for(lr = ll; lr != nil; lr = lr->next)
-			lr->n = applywritebarrier(lr->n, init);
-		n = liststmt(concat(list1(r), ll));
-		goto ret;
-
-	case OAS2RECV:
-		// x, y = <-c
-		// orderstmt made sure x is addressable.
-		*init = concat(*init, n->ninit);
-		n->ninit = nil;
-		r = n->rlist->n;
-		walkexprlistsafe(n->list, init);
-		walkexpr(&r->left, init);
-		if(isblank(n->list->n))
-			n1 = nodnil();
-		else
-			n1 = nod(OADDR, n->list->n, N);
-		n1->etype = 1; // addr does not escape
-		fn = chanfn("chanrecv2", 2, r->left->type);
-		r = mkcall1(fn, n->list->next->n->type, init, typename(r->left->type), r->left, n1);
-		n = nod(OAS, n->list->next->n, r);
-		typecheck(&n, Etop);
-		goto ret;
-
-	case OAS2MAPR:
-		// a,b = m[i];
-		*init = concat(*init, n->ninit);
-		n->ninit = nil;
-		r = n->rlist->n;
-		walkexprlistsafe(n->list, init);
-		walkexpr(&r->left, init);
-		walkexpr(&r->right, init);
-		t = r->left->type;
-		p = nil;
-		if(t->type->width <= 128) { // Check ../../runtime/hashmap.c:MAXVALUESIZE before changing.
-			switch(simsimtype(t->down)) {
-			case TINT32:
-			case TUINT32:
-				p = "mapaccess2_fast32";
-				break;
-			case TINT64:
-			case TUINT64:
-				p = "mapaccess2_fast64";
-				break;
-			case TSTRING:
-				p = "mapaccess2_faststr";
-				break;
-			}
-		}
-		if(p != nil) {
-			// fast versions take key by value
-			key = r->right;
-		} else {
-			// standard version takes key by reference
-			// orderexpr made sure key is addressable.
-			key = nod(OADDR, r->right, N);
-			p = "mapaccess2";
-		}
-
-		// from:
-		//   a,b = m[i]
-		// to:
-		//   var,b = mapaccess2*(t, m, i)
-		//   a = *var
-		a = n->list->n;
-		var = temp(ptrto(t->type));
-		var->typecheck = 1;
-		fn = mapfn(p, t);
-		r = mkcall1(fn, getoutargx(fn->type), init, typename(t), r->left, key);
-
-		// mapaccess2* returns a typed bool, but due to spec changes,
-		// the boolean result of i.(T) is now untyped so we make it the
-		// same type as the variable on the lhs.
-		if(!isblank(n->list->next->n))
-			r->type->type->down->type = n->list->next->n->type;
-		n->rlist = list1(r);
-		n->op = OAS2FUNC;
-		n->list->n = var;
-		walkexpr(&n, init);
-		*init = list(*init, n);
-		n = nod(OAS, a, nod(OIND, var, N));
-		typecheck(&n, Etop);
-		walkexpr(&n, init);
-		// mapaccess needs a zero value to be at least this big.
-		if(zerosize < t->type->width)
-			zerosize = t->type->width;
-		// TODO: ptr is always non-nil, so disable nil check for this OIND op.
-		goto ret;
-
-	case ODELETE:
-		*init = concat(*init, n->ninit);
-		n->ninit = nil;
-		map = n->list->n;
-		key = n->list->next->n;
-		walkexpr(&map, init);
-		walkexpr(&key, init);
-		// orderstmt made sure key is addressable.
-		key = nod(OADDR, key, N);
-		t = map->type;
-		n = mkcall1(mapfndel("mapdelete", t), T, init, typename(t), map, key);
-		goto ret;
-
-	case OAS2DOTTYPE:
-		// a,b = i.(T)
-		*init = concat(*init, n->ninit);
-		n->ninit = nil;
-		r = n->rlist->n;
-		walkexprlistsafe(n->list, init);
-		if(isblank(n->list->n) && !isinter(r->type)) {
-			strcpy(buf, "assert");
-			p = buf+strlen(buf);
-			if(isnilinter(r->left->type))
-				*p++ = 'E';
-			else
-				*p++ = 'I';
-			*p++ = '2';
-			*p++ = 'T';
-			*p++ = 'O';
-			*p++ = 'K';
-			*p = '\0';
-			
-			fn = syslook(buf, 1);
-
-			// runtime.assert(E|I)2TOK returns a typed bool, but due
-			// to spec changes, the boolean result of i.(T) is now untyped
-			// so we make it the same type as the variable on the lhs.
-			if(!isblank(n->list->next->n))
-				fn->type->type->down->type->type = n->list->next->n->type;
-			ll = list1(typename(r->type));
-			ll = list(ll, r->left);
-			argtype(fn, r->left->type);
-			n1 = nod(OCALL, fn, N);
-			n1->list = ll;
-			n = nod(OAS, n->list->next->n, n1);
-			typecheck(&n, Etop);
-			walkexpr(&n, init);
-			goto ret;
-		}
-
-		r->op = ODOTTYPE2;
-		walkexpr(&r, init);
-		ll = ascompatet(n->op, n->list, &r->type, 0, init);
-		n = liststmt(concat(list1(r), ll));
-		goto ret;
-
-	case ODOTTYPE:
-	case ODOTTYPE2:
-		// Build name of function: assertI2E2 etc.
-		strcpy(buf, "assert");
-		p = buf+strlen(buf);
-		if(isnilinter(n->left->type))
-			*p++ = 'E';
-		else
-			*p++ = 'I';
-		*p++ = '2';
-		if(isnilinter(n->type))
-			*p++ = 'E';
-		else if(isinter(n->type))
-			*p++ = 'I';
-		else
-			*p++ = 'T';
-		if(n->op == ODOTTYPE2)
-			*p++ = '2';
-		*p = '\0';
-
-		fn = syslook(buf, 1);
-		ll = list1(typename(n->type));
-		ll = list(ll, n->left);
-		argtype(fn, n->left->type);
-		argtype(fn, n->type);
-		n = nod(OCALL, fn, N);
-		n->list = ll;
-		typecheck(&n, Erv | Efnstruct);
-		walkexpr(&n, init);
-		goto ret;
-
-	case OCONVIFACE:
-		walkexpr(&n->left, init);
-
-		// Optimize convT2E as a two-word copy when T is uintptr-shaped.
-		if(isnilinter(n->type) && isdirectiface(n->left->type) && n->left->type->width == widthptr && isint[simsimtype(n->left->type)]) {
-			l = nod(OEFACE, typename(n->left->type), n->left);
-			l->type = n->type;
-			l->typecheck = n->typecheck;
-			n = l;
-			goto ret;
-		}
-
-		// Build name of function: convI2E etc.
-		// Not all names are possible
-		// (e.g., we'll never generate convE2E or convE2I).
-		strcpy(buf, "conv");
-		p = buf+strlen(buf);
-		if(isnilinter(n->left->type))
-			*p++ = 'E';
-		else if(isinter(n->left->type))
-			*p++ = 'I';
-		else
-			*p++ = 'T';
-		*p++ = '2';
-		if(isnilinter(n->type))
-			*p++ = 'E';
-		else
-			*p++ = 'I';
-		*p = '\0';
-
-		fn = syslook(buf, 1);
-		ll = nil;
-		if(!isinter(n->left->type))
-			ll = list(ll, typename(n->left->type));
-		if(!isnilinter(n->type))
-			ll = list(ll, typename(n->type));
-		if(!isinter(n->left->type) && !isnilinter(n->type)){
-			sym = pkglookup(smprint("%-T.%-T", n->left->type, n->type), itabpkg);
-			if(sym->def == N) {
-				l = nod(ONAME, N, N);
-				l->sym = sym;
-				l->type = ptrto(types[TUINT8]);
-				l->addable = 1;
-				l->class = PEXTERN;
-				l->xoffset = 0;
-				sym->def = l;
-				ggloblsym(sym, widthptr, DUPOK|NOPTR);
-			}
-			l = nod(OADDR, sym->def, N);
-			l->addable = 1;
-			ll = list(ll, l);
-
-			if(isdirectiface(n->left->type) && n->left->type->width == widthptr && isint[simsimtype(n->left->type)]) {
-				/* For pointer types, we can make a special form of optimization
-				 *
-				 * These statements are put onto the expression init list:
-				 * 	Itab *tab = atomicloadtype(&cache);
-				 * 	if(tab == nil)
-				 * 		tab = typ2Itab(type, itype, &cache);
-				 *
-				 * The CONVIFACE expression is replaced with this:
-				 * 	OEFACE{tab, ptr};
-				 */
-				l = temp(ptrto(types[TUINT8]));
-
-				n1 = nod(OAS, l, sym->def);
-				typecheck(&n1, Etop);
-				*init = list(*init, n1);
-
-				fn = syslook("typ2Itab", 1);
-				n1 = nod(OCALL, fn, N);
-				n1->list = ll;
-				typecheck(&n1, Erv);
-				walkexpr(&n1, init);
-
-				n2 = nod(OIF, N, N);
-				n2->ntest = nod(OEQ, l, nodnil());
-				n2->nbody = list1(nod(OAS, l, n1));
-				n2->likely = -1;
-				typecheck(&n2, Etop);
-				*init = list(*init, n2);
-
-				l = nod(OEFACE, l, n->left);
-				l->typecheck = n->typecheck; 
-				l->type = n->type;
-				n = l;
-				goto ret;
-			}
-		}
-		if(isinter(n->left->type)) {
-			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
-			// 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
-			// have to fall back on allocating a temp here.
-			if(islvalue(n->left))
-				ll = list(ll, nod(OADDR, n->left, N));
-			else
-				ll = list(ll, nod(OADDR, copyexpr(n->left, n->left->type, init), N));
-		}
-		argtype(fn, n->left->type);
-		argtype(fn, n->type);
-		dowidth(fn->type);
-		n = nod(OCALL, fn, N);
-		n->list = ll;
-		typecheck(&n, Erv);
-		walkexpr(&n, init);
-		goto ret;
-
-	case OCONV:
-	case OCONVNOP:
-		if(thechar == '5') {
-			if(isfloat[n->left->type->etype]) {
-				if(n->type->etype == TINT64) {
-					n = mkcall("float64toint64", n->type, init, conv(n->left, types[TFLOAT64]));
-					goto ret;
-				}
-				if(n->type->etype == TUINT64) {
-					n = mkcall("float64touint64", n->type, init, conv(n->left, types[TFLOAT64]));
-					goto ret;
-				}
-			}
-			if(isfloat[n->type->etype]) {
-				if(n->left->type->etype == TINT64) {
-					n = mkcall("int64tofloat64", n->type, init, conv(n->left, types[TINT64]));
-					goto ret;
-				}
-				if(n->left->type->etype == TUINT64) {
-					n = mkcall("uint64tofloat64", n->type, init, conv(n->left, types[TUINT64]));
-					goto ret;
-				}
-			}
-		}
-		walkexpr(&n->left, init);
-		goto ret;
-
-	case OANDNOT:
-		walkexpr(&n->left, init);
-		n->op = OAND;
-		n->right = nod(OCOM, n->right, N);
-		typecheck(&n->right, Erv);
-		walkexpr(&n->right, init);
-		goto ret;
-
-	case OMUL:
-		walkexpr(&n->left, init);
-		walkexpr(&n->right, init);
-		walkmul(&n, init);
-		goto ret;
-
-	case ODIV:
-	case OMOD:
-		walkexpr(&n->left, init);
-		walkexpr(&n->right, init);
-		/*
-		 * rewrite complex div into function call.
-		 */
-		et = n->left->type->etype;
-		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);
-			goto ret;
-		}
-		// Nothing to do for float divisions.
-		if(isfloat[et])
-			goto ret;
-
-		// Try rewriting as shifts or magic multiplies.
-		walkdiv(&n, init);
-
-		/*
-		 * rewrite 64-bit div and mod into function calls
-		 * on 32-bit architectures.
-		 */
-		switch(n->op) {
-		case OMOD:
-		case ODIV:
-			if(widthreg >= 8 || (et != TUINT64 && et != TINT64))
-				goto ret;
-			if(et == TINT64)
-				strcpy(namebuf, "int64");
-			else
-				strcpy(namebuf, "uint64");
-			if(n->op == ODIV)
-				strcat(namebuf, "div");
-			else
-				strcat(namebuf, "mod");
-			n = mkcall(namebuf, n->type, init,
-				conv(n->left, types[et]), conv(n->right, types[et]));
-			break;
-		default:
-			break;
-		}
-		goto ret;
-
-	case OINDEX:
-		walkexpr(&n->left, init);
-		// save the original node for bounds checking elision.
-		// If it was a ODIV/OMOD walk might rewrite it.
-		r = n->right;
-		walkexpr(&n->right, init);
-
-		// if range of type cannot exceed static array bound,
-		// disable bounds check.
-		if(n->bounded)
-			goto ret;
-		t = n->left->type;
-		if(t != T && isptr[t->etype])
-			t = t->type;
-		if(isfixedarray(t)) {
-			n->bounded = bounded(r, t->bound);
-			if(debug['m'] && n->bounded && !isconst(n->right, CTINT))
-				warn("index bounds check elided");
-			if(smallintconst(n->right) && !n->bounded)
-				yyerror("index out of bounds");
-		} else if(isconst(n->left, CTSTR)) {
-			n->bounded = bounded(r, n->left->val.u.sval->len);
-			if(debug['m'] && n->bounded && !isconst(n->right, CTINT))
-				warn("index bounds check elided");
-			if(smallintconst(n->right)) {
-				if(!n->bounded)
-					yyerror("index out of bounds");
-				else {
-					// replace "abc"[1] with 'b'.
-					// delayed until now because "abc"[1] is not
-					// an ideal constant.
-					v = mpgetfix(n->right->val.u.xval);
-					nodconst(n, n->type, n->left->val.u.sval->s[v]);
-					n->typecheck = 1;
-				}
-			}
-		}
-
-		if(isconst(n->right, CTINT))
-		if(mpcmpfixfix(n->right->val.u.xval, &mpzero) < 0 ||
-		   mpcmpfixfix(n->right->val.u.xval, maxintval[TINT]) > 0)
-			yyerror("index out of bounds");
-		goto ret;
-
-	case OINDEXMAP:
-		if(n->etype == 1)
-			goto ret;
-		walkexpr(&n->left, init);
-		walkexpr(&n->right, init);
-
-		t = n->left->type;
-		p = nil;
-		if(t->type->width <= 128) {  // Check ../../runtime/hashmap.c:MAXVALUESIZE before changing.
-			switch(simsimtype(t->down)) {
-			case TINT32:
-			case TUINT32:
-				p = "mapaccess1_fast32";
-				break;
-			case TINT64:
-			case TUINT64:
-				p = "mapaccess1_fast64";
-				break;
-			case TSTRING:
-				p = "mapaccess1_faststr";
-				break;
-			}
-		}
-		if(p != nil) {
-			// fast versions take key by value
-			key = n->right;
-		} else {
-			// standard version takes key by reference.
-			// orderexpr made sure key is addressable.
-			key = nod(OADDR, n->right, N);
-			p = "mapaccess1";
-		}
-		n = mkcall1(mapfn(p, t), ptrto(t->type), init, typename(t), n->left, key);
-		n = nod(OIND, n, N);
-		n->type = t->type;
-		n->typecheck = 1;
-		// mapaccess needs a zero value to be at least this big.
-		if(zerosize < t->type->width)
-			zerosize = t->type->width;
-		goto ret;
-
-	case ORECV:
-		fatal("walkexpr ORECV"); // should see inside OAS only
-
-	case OSLICE:
-		if(n->right != N && n->right->left == N && n->right->right == N) { // noop
-			walkexpr(&n->left, init);
-			n = n->left;
-			goto ret;
-		}
-		// fallthrough
-	case OSLICEARR:
-	case OSLICESTR:
-		if(n->right == N) // already processed
-			goto ret;
-
-		walkexpr(&n->left, init);
-		// cgen_slice can't handle string literals as source
-		// TODO the OINDEX case is a bug elsewhere that needs to be traced.  it causes a crash on ([2][]int{ ... })[1][lo:hi]
-		if((n->op == OSLICESTR && n->left->op == OLITERAL) || (n->left->op == OINDEX))
-			n->left = copyexpr(n->left, n->left->type, init);
-		else
-			n->left = safeexpr(n->left, init);
-		walkexpr(&n->right->left, init);
-		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
-		goto ret;
-	
-	case OSLICE3:
-	case OSLICE3ARR:
-		if(n->right == N) // already processed
-			goto ret;
-
-		walkexpr(&n->left, init);
-		// TODO the OINDEX case is a bug elsewhere that needs to be traced.  it causes a crash on ([2][]int{ ... })[1][lo:hi]
-		// TODO the comment on the previous line was copied from case OSLICE. it might not even be true.
-		if(n->left->op == OINDEX)
-			n->left = copyexpr(n->left, n->left->type, init);
-		else
-			n->left = safeexpr(n->left, init);
-		walkexpr(&n->right->left, init);
-		n->right->left = safeexpr(n->right->left, init);
-		walkexpr(&n->right->right->left, init);
-		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
-		goto ret;
-
-	case OADDR:
-		walkexpr(&n->left, init);
-		goto ret;
-
-	case ONEW:
-		if(n->esc == EscNone && n->type->type->width < (1<<16)) {
-			r = temp(n->type->type);
-			r = nod(OAS, r, N);  // zero temp
-			typecheck(&r, Etop);
-			*init = list(*init, r);
-			r = nod(OADDR, r->left, N);
-			typecheck(&r, Erv);
-			n = r;
-		} else {
-			n = callnew(n->type->type);
-		}
-		goto ret;
-
-	case OCMPSTR:
-		// If one argument to the comparison is an empty string,
-		// comparing the lengths instead will yield the same result
-		// without the function call.
-		if((isconst(n->left, CTSTR) && n->left->val.u.sval->len == 0) ||
-		   (isconst(n->right, CTSTR) && n->right->val.u.sval->len == 0)) {
-			r = nod(n->etype, nod(OLEN, n->left, N), nod(OLEN, n->right, N));
-			typecheck(&r, Erv);
-			walkexpr(&r, init);
-			r->type = n->type;
-			n = r;
-			goto ret;
-		}
-
-		// s + "badgerbadgerbadger" == "badgerbadgerbadger"
-		if((n->etype == OEQ || n->etype == ONE) &&
-		   isconst(n->right, CTSTR) &&
-		   n->left->op == OADDSTR && count(n->left->list) == 2 &&
-		   isconst(n->left->list->next->n, CTSTR) &&
-		   cmpslit(n->right, n->left->list->next->n) == 0) {
-			r = nod(n->etype, nod(OLEN, n->left->list->n, N), nodintconst(0));
-			typecheck(&r, Erv);
-			walkexpr(&r, init);
-			r->type = n->type;
-			n = r;
-			goto ret;
-		}
-
-		if(n->etype == OEQ || n->etype == ONE) {
-			// prepare for rewrite below
-			n->left = cheapexpr(n->left, init);
-			n->right = cheapexpr(n->right, init);
-
-			r = mkcall("eqstring", types[TBOOL], init,
-				conv(n->left, types[TSTRING]),
-				conv(n->right, types[TSTRING]));
-
-			// quick check of len before full compare for == or !=
-			if(n->etype == OEQ) {
-				// len(left) == len(right) && eqstring(left, right)
-				r = nod(OANDAND, nod(OEQ, nod(OLEN, n->left, N), nod(OLEN, n->right, N)), r);
-			} else {
-				// len(left) != len(right) || !eqstring(left, right)
-				r = nod(ONOT, r, N);
-				r = nod(OOROR, nod(ONE, nod(OLEN, n->left, N), nod(OLEN, n->right, N)), r);
-			}
-			typecheck(&r, Erv);
-			walkexpr(&r, nil);
-		} else {
-			// sys_cmpstring(s1, s2) :: 0
-			r = mkcall("cmpstring", types[TINT], init,
-				conv(n->left, types[TSTRING]),
-				conv(n->right, types[TSTRING]));
-			r = nod(n->etype, r, nodintconst(0));
-		}
-
-		typecheck(&r, Erv);
-		if(n->type->etype != TBOOL) fatal("cmp %T", n->type);
-		r->type = n->type;
-		n = r;
-		goto ret;
-
-	case OADDSTR:
-		n = addstr(n, init);
-		goto ret;
-	
-	case OAPPEND:
-		if(n->isddd)
-			n = appendslice(n, init); // also works for append(slice, string).
-		else
-			n = append(n, init);
-		goto ret;
-
-	case OCOPY:
-		n = copyany(n, init, flag_race);
-		goto ret;
-
-	case OCLOSE:
-		// cannot use chanfn - closechan takes any, not chan any
-		fn = syslook("closechan", 1);
-		argtype(fn, n->left->type);
-		n = mkcall1(fn, T, init, n->left);
-		goto ret;
-
-	case OMAKECHAN:
-		n = mkcall1(chanfn("makechan", 1, n->type), n->type, init,
-			typename(n->type),
-			conv(n->left, types[TINT64]));
-		goto ret;
-
-	case OMAKEMAP:
-		t = n->type;
-
-		fn = syslook("makemap", 1);
-		argtype(fn, t->down);	// any-1
-		argtype(fn, t->type);	// any-2
-
-		n = mkcall1(fn, n->type, init,
-			typename(n->type),
-			conv(n->left, types[TINT64]));
-		goto ret;
-
-	case OMAKESLICE:
-		l = n->left;
-		r = n->right;
-		if(r == nil)
-			l = r = safeexpr(l, init);
-		t = n->type;
-		if(n->esc == EscNone
-			&& smallintconst(l) && smallintconst(r)
-			&& (t->type->width == 0 || mpgetfix(r->val.u.xval) < (1ULL<<16) / t->type->width)) {
-			// var arr [r]T
-			// n = arr[:l]
-			t = aindex(r, t->type); // [r]T
-			var = temp(t);
-			a = nod(OAS, var, N); // zero temp
-			typecheck(&a, Etop);
-			*init = list(*init, a);
-			r = nod(OSLICE, var, nod(OKEY, N, l)); // arr[:l]
-			r = conv(r, n->type); // in case n->type is named.
-			typecheck(&r, Erv);
-			walkexpr(&r, init);
-			n = r;
-		} else {
-			// makeslice(t *Type, nel int64, max int64) (ary []any)
-			fn = syslook("makeslice", 1);
-			argtype(fn, t->type);			// any-1
-			n = mkcall1(fn, n->type, init,
-				typename(n->type),
-				conv(l, types[TINT64]),
-				conv(r, types[TINT64]));
-		}
-		goto ret;
-
-	case ORUNESTR:
-		// sys_intstring(v)
-		n = mkcall("intstring", n->type, init,
-			conv(n->left, types[TINT64]));
-		goto ret;
-
-	case OARRAYBYTESTR:
-		// slicebytetostring([]byte) string;
-		n = mkcall("slicebytetostring", n->type, init, n->left);
-		goto ret;
-
-	case OARRAYBYTESTRTMP:
-		// slicebytetostringtmp([]byte) string;
-		n = mkcall("slicebytetostringtmp", n->type, init, n->left);
-		goto ret;
-
-	case OARRAYRUNESTR:
-		// slicerunetostring([]rune) string;
-		n = mkcall("slicerunetostring", n->type, init, n->left);
-		goto ret;
-
-	case OSTRARRAYBYTE:
-		// stringtoslicebyte(string) []byte;
-		n = mkcall("stringtoslicebyte", n->type, init, conv(n->left, types[TSTRING]));
-		goto ret;
-
-	case OSTRARRAYRUNE:
-		// stringtoslicerune(string) []rune
-		n = mkcall("stringtoslicerune", n->type, init, n->left);
-		goto ret;
-
-	case OCMPIFACE:
-		// ifaceeq(i1 any-1, i2 any-2) (ret bool);
-		if(!eqtype(n->left->type, n->right->type))
-			fatal("ifaceeq %O %T %T", n->op, n->left->type, n->right->type);
-		if(isnilinter(n->left->type))
-			fn = syslook("efaceeq", 1);
-		else
-			fn = syslook("ifaceeq", 1);
-
-		n->right = cheapexpr(n->right, init);
-		n->left = cheapexpr(n->left, init);
-		argtype(fn, n->right->type);
-		argtype(fn, n->left->type);
-		r = mkcall1(fn, n->type, init, n->left, n->right);
-		if(n->etype == ONE)
-			r = nod(ONOT, r, N);
-		
-		// check itable/type before full compare.
-		if(n->etype == OEQ)
-			r = nod(OANDAND, nod(OEQ, nod(OITAB, n->left, N), nod(OITAB, n->right, N)), r);
-		else
-			r = nod(OOROR, nod(ONE, nod(OITAB, n->left, N), nod(OITAB, n->right, N)), r);
-		typecheck(&r, Erv);
-		walkexpr(&r, init);
-		r->type = n->type;
-		n = r;
-		goto ret;
-
-	case OARRAYLIT:
-	case OMAPLIT:
-	case OSTRUCTLIT:
-	case OPTRLIT:
-		var = temp(n->type);
-		anylit(0, n, var, init);
-		n = var;
-		goto ret;
-
-	case OSEND:
-		n1 = n->right;
-		n1 = assignconv(n1, n->left->type->type, "chan send");
-		walkexpr(&n1, init);
-		n1 = nod(OADDR, n1, N);
-		n = mkcall1(chanfn("chansend1", 2, n->left->type), T, init, typename(n->left->type), n->left, n1);
-		goto ret;
-
-	case OCLOSURE:
-		n = walkclosure(n, init);
-		goto ret;
-	
-	case OCALLPART:
-		n = walkpartialcall(n, init);
-		goto ret;
-	}
-	fatal("missing switch %O", n->op);
-
-ret:
-	// Expressions that are constant at run time but not
-	// considered const by the language spec are not turned into
-	// constants until walk. For example, if n is y%1 == 0, the
-	// walk of y%1 may have replaced it by 0.
-	// Check whether n with its updated args is itself now a constant.
-	t = n->type;
-	evconst(n);
-	n->type = t;
-	if(n->op == OLITERAL)
-		typecheck(&n, Erv);
-
-	ullmancalc(n);
-
-	if(debug['w'] && n != N)
-		dump("walk", n);
-
-	lineno = lno;
-	*np = n;
-}
-
-static Node*
-ascompatee1(int op, Node *l, Node *r, NodeList **init)
-{
-	Node *n;
-	USED(op);
-	
-	// convas will turn map assigns into function calls,
-	// making it impossible for reorder3 to work.
-	n = nod(OAS, l, r);
-	if(l->op == OINDEXMAP)
-		return n;
-
-	return convas(n, init);
-}
-
-static NodeList*
-ascompatee(int op, NodeList *nl, NodeList *nr, NodeList **init)
-{
-	NodeList *ll, *lr, *nn;
-
-	/*
-	 * check assign expression list to
-	 * a expression list. called in
-	 *	expr-list = expr-list
-	 */
-
-	// ensure order of evaluation for function calls
-	for(ll=nl; ll; ll=ll->next)
-		ll->n = safeexpr(ll->n, init);
-	for(lr=nr; lr; lr=lr->next)
-		lr->n = safeexpr(lr->n, init);
-
-	nn = nil;
-	for(ll=nl, lr=nr; ll && lr; ll=ll->next, lr=lr->next) {
-		// Do not generate 'x = x' during return. See issue 4014.
-		if(op == ORETURN && ll->n == lr->n)
-			continue;
-		nn = list(nn, ascompatee1(op, ll->n, lr->n, init));
-	}
-
-	// cannot happen: caller checked that lists had same length
-	if(ll || lr)
-		yyerror("error in shape across %+H %O %+H / %d %d [%s]", nl, op, nr, count(nl), count(nr), curfn->nname->sym->name);
-	return nn;
-}
-
-/*
- * l is an lv and rt is the type of an rv
- * return 1 if this implies a function call
- * evaluating the lv or a function call
- * in the conversion of the types
- */
-static int
-fncall(Node *l, Type *rt)
-{
-	Node r;
-
-	if(l->ullman >= UINF || l->op == OINDEXMAP)
-		return 1;
-	memset(&r, 0, sizeof r);
-	if(needwritebarrier(l, &r))
-		return 1;
-	if(eqtype(l->type, rt))
-		return 0;
-	return 1;
-}
-
-static NodeList*
-ascompatet(int op, NodeList *nl, Type **nr, int fp, NodeList **init)
-{
-	Node *l, *tmp, *a;
-	NodeList *ll;
-	Type *r;
-	Iter saver;
-	int ucount;
-	NodeList *nn, *mm;
-
-	USED(op);
-
-	/*
-	 * check assign type list to
-	 * a expression list. called in
-	 *	expr-list = func()
-	 */
-	r = structfirst(&saver, nr);
-	nn = nil;
-	mm = nil;
-	ucount = 0;
-	for(ll=nl; ll; ll=ll->next) {
-		if(r == T)
-			break;
-		l = ll->n;
-		if(isblank(l)) {
-			r = structnext(&saver);
-			continue;
-		}
-
-		// any lv that causes a fn call must be
-		// deferred until all the return arguments
-		// have been pulled from the output arguments
-		if(fncall(l, r->type)) {
-			tmp = temp(r->type);
-			typecheck(&tmp, Erv);
-			a = nod(OAS, l, tmp);
-			a = convas(a, init);
-			mm = list(mm, a);
-			l = tmp;
-		}
-
-		a = nod(OAS, l, nodarg(r, fp));
-		a = convas(a, init);
-		ullmancalc(a);
-		if(a->ullman >= UINF) {
-			dump("ascompatet ucount", a);
-			ucount++;
-		}
-		nn = list(nn, a);
-		r = structnext(&saver);
-	}
-
-	if(ll != nil || r != T)
-		yyerror("ascompatet: assignment count mismatch: %d = %d",
-			count(nl), structcount(*nr));
-
-	if(ucount)
-		fatal("ascompatet: too many function calls evaluating parameters");
-	return concat(nn, mm);
-}
-
- /*
- * package all the arguments that match a ... T parameter into a []T.
- */
-static NodeList*
-mkdotargslice(NodeList *lr0, NodeList *nn, Type *l, int fp, NodeList **init, Node *ddd)
-{
-	Node *a, *n;
-	Type *tslice;
-	int esc;
-	
-	esc = EscUnknown;
-	if(ddd != nil)
-		esc = ddd->esc;
-	
-	tslice = typ(TARRAY);
-	tslice->type = l->type->type;
-	tslice->bound = -1;
-
-	if(count(lr0) == 0) {
-		n = nodnil();
-		n->type = tslice;
-	} else {
-		n = nod(OCOMPLIT, N, typenod(tslice));
-		if(ddd != nil)
-			n->alloc = ddd->alloc; // temporary to use
-		n->list = lr0;
-		n->esc = esc;
-		typecheck(&n, Erv);
-		if(n->type == T)
-			fatal("mkdotargslice: typecheck failed");
-		walkexpr(&n, init);
-	}
-
-	a = nod(OAS, nodarg(l, fp), n);
-	nn = list(nn, convas(a, init));
-	return nn;
-}
-
-/*
- * helpers for shape errors
- */
-static char*
-dumptypes(Type **nl, char *what)
-{
-	int first;
-	Type *l;
-	Iter savel;
-	Fmt fmt;
-
-	fmtstrinit(&fmt);
-	fmtprint(&fmt, "\t");
-	first = 1;
-	for(l = structfirst(&savel, nl); l != T; l = structnext(&savel)) {
-		if(first)
-			first = 0;
-		else
-			fmtprint(&fmt, ", ");
-		fmtprint(&fmt, "%T", l);
-	}
-	if(first)
-		fmtprint(&fmt, "[no arguments %s]", what);
-	return fmtstrflush(&fmt);
-}
-
-static char*
-dumpnodetypes(NodeList *l, char *what)
-{
-	int first;
-	Node *r;
-	Fmt fmt;
-
-	fmtstrinit(&fmt);
-	fmtprint(&fmt, "\t");
-	first = 1;
-	for(; l; l=l->next) {
-		r = l->n;
-		if(first)
-			first = 0;
-		else
-			fmtprint(&fmt, ", ");
-		fmtprint(&fmt, "%T", r->type);
-	}
-	if(first)
-		fmtprint(&fmt, "[no arguments %s]", what);
-	return fmtstrflush(&fmt);
-}
-
-/*
- * check assign expression list to
- * a type list. called in
- *	return expr-list
- *	func(expr-list)
- */
-static NodeList*
-ascompatte(int op, Node *call, int isddd, Type **nl, NodeList *lr, int fp, NodeList **init)
-{
-	Type *l, *ll;
-	Node *r, *a;
-	NodeList *nn, *lr0, *alist;
-	Iter savel;
-	char *l1, *l2;
-
-	lr0 = lr;
-	l = structfirst(&savel, nl);
-	r = N;
-	if(lr)
-		r = lr->n;
-	nn = nil;
-
-	// f(g()) where g has multiple return values
-	if(r != N && lr->next == nil && r->type->etype == TSTRUCT && r->type->funarg) {
-		// optimization - can do block copy
-		if(eqtypenoname(r->type, *nl)) {
-			a = nodarg(*nl, fp);
-			r = nod(OCONVNOP, r, N);
-			r->type = a->type;
-			nn = list1(convas(nod(OAS, a, r), init));
-			goto ret;
-		}
-
-		// conversions involved.
-		// copy into temporaries.
-		alist = nil;
-		for(l=structfirst(&savel, &r->type); l; l=structnext(&savel)) {
-			a = temp(l->type);
-			alist = list(alist, a);
-		}
-		a = nod(OAS2, N, N);
-		a->list = alist;
-		a->rlist = lr;
-		typecheck(&a, Etop);
-		walkstmt(&a);
-		*init = list(*init, a);
-		lr = alist;
-		r = lr->n;
-		l = structfirst(&savel, nl);
-	}
-
-loop:
-	if(l != T && l->isddd) {
-		// the ddd parameter must be last
-		ll = structnext(&savel);
-		if(ll != T)
-			yyerror("... must be last argument");
-
-		// special case --
-		// only if we are assigning a single ddd
-		// argument to a ddd parameter then it is
-		// passed thru unencapsulated
-		if(r != N && lr->next == nil && isddd && eqtype(l->type, r->type)) {
-			a = nod(OAS, nodarg(l, fp), r);
-			a = convas(a, init);
-			nn = list(nn, a);
-			goto ret;
-		}
-
-		// normal case -- make a slice of all
-		// remaining arguments and pass it to
-		// the ddd parameter.
-		nn = mkdotargslice(lr, nn, l, fp, init, call->right);
-		goto ret;
-	}
-
-	if(l == T || r == N) {
-		if(l != T || r != N) {
-			l1 = dumptypes(nl, "expected");
-			l2 = dumpnodetypes(lr0, "given");
-			if(l != T)
-				yyerror("not enough arguments to %O\n%s\n%s", op, l1, l2);
-			else
-				yyerror("too many arguments to %O\n%s\n%s", op, l1, l2);
-		}
-		goto ret;
-	}
-
-	a = nod(OAS, nodarg(l, fp), r);
-	a = convas(a, init);
-	nn = list(nn, a);
-
-	l = structnext(&savel);
-	r = N;
-	lr = lr->next;
-	if(lr != nil)
-		r = lr->n;
-	goto loop;
-
-ret:
-	for(lr=nn; lr; lr=lr->next)
-		lr->n->typecheck = 1;
-	return nn;
-}
-
-// generate code for print
-static Node*
-walkprint(Node *nn, NodeList **init)
-{
-	Node *r;
-	Node *n;
-	NodeList *l, *all;
-	Node *on;
-	Type *t;
-	int notfirst, et, op;
-	NodeList *calls;
-
-	on = nil;
-	op = nn->op;
-	all = nn->list;
-	calls = nil;
-	notfirst = 0;
-
-	for(l=all; l; l=l->next) {
-		if(notfirst) {
-			calls = list(calls, mkcall("printsp", T, init));
-		}
-		notfirst = op == OPRINTN;
-
-		n = l->n;
-		if(n->op == OLITERAL) {
-			switch(n->val.ctype) {
-			case CTRUNE:
-				defaultlit(&n, runetype);
-				break;
-			case CTINT:
-				defaultlit(&n, types[TINT64]);
-				break;
-			case CTFLT:
-				defaultlit(&n, types[TFLOAT64]);
-				break;
-			}
-		}
-		if(n->op != OLITERAL && n->type && n->type->etype == TIDEAL)
-			defaultlit(&n, types[TINT64]);
-		defaultlit(&n, nil);
-		l->n = n;
-		if(n->type == T || n->type->etype == TFORW)
-			continue;
-
-		t = n->type;
-		et = n->type->etype;
-		if(isinter(n->type)) {
-			if(isnilinter(n->type))
-				on = syslook("printeface", 1);
-			else
-				on = syslook("printiface", 1);
-			argtype(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
-		} else if(isslice(n->type)) {
-			on = syslook("printslice", 1);
-			argtype(on, n->type);	// any-1
-		} else if(isint[et]) {
-			if(et == TUINT64) {
-				if((t->sym->pkg == runtimepkg || compiling_runtime) && strcmp(t->sym->name, "hex") == 0)
-					on = syslook("printhex", 0);
-				else
-					on = syslook("printuint", 0);
-			} else
-				on = syslook("printint", 0);
-		} else if(isfloat[et]) {
-			on = syslook("printfloat", 0);
-		} else if(iscomplex[et]) {
-			on = syslook("printcomplex", 0);
-		} else if(et == TBOOL) {
-			on = syslook("printbool", 0);
-		} else if(et == TSTRING) {
-			on = syslook("printstring", 0);
-		} else {
-			badtype(OPRINT, n->type, T);
-			continue;
-		}
-
-		t = *getinarg(on->type);
-		if(t != nil)
-			t = t->type;
-		if(t != nil)
-			t = t->type;
-
-		if(!eqtype(t, n->type)) {
-			n = nod(OCONV, n, N);
-			n->type = t;
-		}
-
-		r = nod(OCALL, on, N);
-		r->list = list1(n);
-		calls = list(calls, r);
-	}
-
-	if(op == OPRINTN)
-		calls = list(calls, mkcall("printnl", T, nil));
-	typechecklist(calls, Etop);
-	walkexprlist(calls, init);
-
-	r = nod(OEMPTY, N, N);
-	typecheck(&r, Etop);
-	walkexpr(&r, init);
-	r->ninit = calls;
-	return r;
-}
-
-Node*
-callnew(Type *t)
-{
-	Node *fn;
-
-	dowidth(t);
-	fn = syslook("newobject", 1);
-	argtype(fn, t);
-	return mkcall1(fn, ptrto(t), nil, typename(t));
-}
-
-static int
-isstack(Node *n)
-{
-	while(n->op == ODOT || n->op == OPAREN || n->op == OCONVNOP || n->op == OINDEX && isfixedarray(n->left->type))
-		n = n->left;
-	
-	switch(n->op) {
-	case OINDREG:
-		// OINDREG only ends up in walk if it's indirect of SP.
-		return 1;
-
-	case ONAME:
-		switch(n->class) {
-		case PAUTO:
-		case PPARAM:
-		case PPARAMOUT:
-			return 1;
-		}
-		break;
-	}
-	
-	return 0;
-}
-
-static int
-isglobal(Node *n)
-{
-	while(n->op == ODOT || n->op == OPAREN || n->op == OCONVNOP || n->op == OINDEX && isfixedarray(n->left->type))
-		n = n->left;
-	
-	switch(n->op) {
-	case ONAME:
-		switch(n->class) {
-		case PEXTERN:
-			return 1;
-		}
-		break;
-	}
-	
-	return 0;
-}
-
-// Do we need a write barrier for the assignment l = r?
-int
-needwritebarrier(Node *l, Node *r)
-{
-	if(!use_writebarrier)
-		return 0;
-
-	if(l == N || isblank(l))
-		return 0;
-
-	// No write barrier for write of non-pointers.
-	dowidth(l->type);
-	if(!haspointers(l->type))
-		return 0;
-
-	// No write barrier for write to stack.
-	if(isstack(l))
-		return 0;
-
-	// No write barrier for implicit or explicit zeroing.
-	if(r == N || iszero(r))
-		return 0;
-
-	// No write barrier for initialization to constant.
-	if(r->op == OLITERAL)
-		return 0;
-
-	// No write barrier for storing static (read-only) data.
-	if(r->op == ONAME && strncmp(r->sym->name, "statictmp_", 10) == 0)
-		return 0;
-
-	// No write barrier for storing address of stack values,
-	// which are guaranteed only to be written to the stack.
-	if(r->op == OADDR && isstack(r->left))
-		return 0;
-
-	// No write barrier for storing address of global, which
-	// is live no matter what.
-	if(r->op == OADDR && isglobal(r->left))
-		return 0;
-
-	// No write barrier for reslice: x = x[0:y] or x = append(x, ...).
-	// Both are compiled to modify x directly.
-	// In the case of append, a write barrier may still be needed
-	// if the underlying array grows, but the append code can
-	// 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) {
-		switch(r->op) {
-		case OSLICE:
-		case OSLICE3:
-		case OSLICESTR:
-		case OAPPEND:
-			break;
-		default:
-			dump("bad reslice-l", l);
-			dump("bad reslice-r", r);
-			break;
-		}
-		return 0;
-	}
-
-	// Otherwise, be conservative and use write barrier.
-	return 1;
-}
-
-// TODO(rsc): Perhaps componentgen should run before this.
-static Node*
-applywritebarrier(Node *n, NodeList **init)
-{
-	Node *l, *r;
-	Type *t;
-
-	if(n->left && n->right && needwritebarrier(n->left, n->right)) {
-		t = n->left->type;
-		l = nod(OADDR, n->left, N);
-		l->etype = 1; // addr does not escape
-		if(t->width == widthptr) {
-			n = mkcall1(writebarrierfn("writebarrierptr", t, n->right->type), T, init,
-				l, n->right);
-		} else if(t->etype == TSTRING) {
-			n = mkcall1(writebarrierfn("writebarrierstring", t, n->right->type), T, init,
-				l, n->right);
-		} else if(isslice(t)) {
-			n = mkcall1(writebarrierfn("writebarrierslice", t, n->right->type), T, init,
-				l, n->right);
-		} else if(isinter(t)) {
-			n = mkcall1(writebarrierfn("writebarrieriface", t, n->right->type), T, init,
-				l, n->right);
-		} else if(t->width == 2*widthptr) {
-			n = mkcall1(writebarrierfn("writebarrierfat2", t, n->right->type), T, init,
-				l, nodnil(), n->right);
-		} else if(t->width == 3*widthptr) {
-			n = mkcall1(writebarrierfn("writebarrierfat3", t, n->right->type), T, init,
-				l, nodnil(), n->right);
-		} else if(t->width == 4*widthptr) {
-			n = mkcall1(writebarrierfn("writebarrierfat4", t, n->right->type), T, init,
-				l, nodnil(), n->right);
-		} else {
-			r = n->right;
-			while(r->op == OCONVNOP)
-				r = r->left;
-			r = nod(OADDR, r, N);
-			r->etype = 1; // addr does not escape
-			//warnl(n->lineno, "writebarrierfat %T %N", t, r);
-			n = mkcall1(writebarrierfn("writebarrierfat", t, r->left->type), T, init,
-				typename(t), l, r);
-		}
-	}
-	return n;
-}
-
-static Node*
-convas(Node *n, NodeList **init)
-{
-	Type *lt, *rt;
-	Node *map, *key, *val;
-
-	if(n->op != OAS)
-		fatal("convas: not OAS %O", n->op);
-
-	n->typecheck = 1;
-
-	if(n->left == N || n->right == N)
-		goto out;
-
-	lt = n->left->type;
-	rt = n->right->type;
-	if(lt == T || rt == T)
-		goto out;
-
-	if(isblank(n->left)) {
-		defaultlit(&n->right, T);
-		goto out;
-	}
-
-	if(n->left->op == OINDEXMAP) {
-		map = n->left->left;
-		key = n->left->right;
-		val = n->right;
-		walkexpr(&map, init);
-		walkexpr(&key, init);
-		walkexpr(&val, init);
-		// orderexpr made sure key and val are addressable.
-		key = nod(OADDR, key, N);
-		val = nod(OADDR, val, N);
-		n = mkcall1(mapfn("mapassign1", map->type), T, init,
-			typename(map->type), map, key, val);
-		goto out;
-	}
-
-	if(!eqtype(lt, rt)) {
-		n->right = assignconv(n->right, lt, "assignment");
-		walkexpr(&n->right, init);
-	}
-
-out:
-	ullmancalc(n);
-	return n;
-}
-
-/*
- * from ascompat[te]
- * evaluating actual function arguments.
- *	f(a,b)
- * if there is exactly one function expr,
- * then it is done first. otherwise must
- * make temp variables
- */
-static NodeList*
-reorder1(NodeList *all)
-{
-	Node *f, *a, *n;
-	NodeList *l, *r, *g;
-	int c, d, t;
-
-	c = 0;	// function calls
-	t = 0;	// total parameters
-
-	for(l=all; l; l=l->next) {
-		n = l->n;
-		t++;
-		ullmancalc(n);
-		if(n->ullman >= UINF)
-			c++;
-	}
-	if(c == 0 || t == 1)
-		return all;
-
-	g = nil;	// fncalls assigned to tempnames
-	f = N;	// last fncall assigned to stack
-	r = nil;	// non fncalls and tempnames assigned to stack
-	d = 0;
-	for(l=all; l; l=l->next) {
-		n = l->n;
-		if(n->ullman < UINF) {
-			r = list(r, n);
-			continue;
-		}
-		d++;
-		if(d == c) {
-			f = n;
-			continue;
-		}
-
-		// make assignment of fncall to tempname
-		a = temp(n->right->type);
-		a = nod(OAS, a, n->right);
-		g = list(g, a);
-
-		// put normal arg assignment on list
-		// with fncall replaced by tempname
-		n->right = a->left;
-		r = list(r, n);
-	}
-
-	if(f != N)
-		g = list(g, f);
-	return concat(g, r);
-}
-
-static void reorder3save(Node**, NodeList*, NodeList*, NodeList**);
-static int aliased(Node*, NodeList*, NodeList*);
-
-/*
- * from ascompat[ee]
- *	a,b = c,d
- * simultaneous assignment. there cannot
- * be later use of an earlier lvalue.
- *
- * function calls have been removed.
- */
-static NodeList*
-reorder3(NodeList *all)
-{
-	NodeList *list, *early, *mapinit;
-	Node *l;
-
-	// If a needed expression may be affected by an
-	// earlier assignment, make an early copy of that
-	// expression and use the copy instead.
-	early = nil;
-	mapinit = nil;
-	for(list=all; list; list=list->next) {
-		l = list->n->left;
-
-		// Save subexpressions needed on left side.
-		// Drill through non-dereferences.
-		for(;;) {
-			if(l->op == ODOT || l->op == OPAREN) {
-				l = l->left;
-				continue;
-			}
-			if(l->op == OINDEX && isfixedarray(l->left->type)) {
-				reorder3save(&l->right, all, list, &early);
-				l = l->left;
-				continue;
-			}
-			break;
-		}
-		switch(l->op) {
-		default:
-			fatal("reorder3 unexpected lvalue %#O", l->op);
-		case ONAME:
-			break;
-		case OINDEX:
-		case OINDEXMAP:
-			reorder3save(&l->left, all, list, &early);
-			reorder3save(&l->right, all, list, &early);
-			if(l->op == OINDEXMAP)
-				list->n = convas(list->n, &mapinit);
-			break;
-		case OIND:
-		case ODOTPTR:
-			reorder3save(&l->left, all, list, &early);
-		}
-
-		// Save expression on right side.
-		reorder3save(&list->n->right, all, list, &early);
-	}
-
-	early = concat(mapinit, early);
-	return concat(early, all);
-}
-
-static int vmatch2(Node*, Node*);
-static int varexpr(Node*);
-
-/*
- * if the evaluation of *np would be affected by the 
- * assignments in all up to but not including stop,
- * copy into a temporary during *early and
- * replace *np with that temp.
- */
-static void
-reorder3save(Node **np, NodeList *all, NodeList *stop, NodeList **early)
-{
-	Node *n, *q;
-
-	n = *np;
-	if(!aliased(n, all, stop))
-		return;
-	
-	q = temp(n->type);
-	q = nod(OAS, q, n);
-	typecheck(&q, Etop);
-	*early = list(*early, q);
-	*np = q->left;
-}
-
-/*
- * what's the outer value that a write to n affects?
- * outer value means containing struct or array.
- */
-Node*
-outervalue(Node *n)
-{	
-	for(;;) {
-		if(n->op == ODOT || n->op == OPAREN) {
-			n = n->left;
-			continue;
-		}
-		if(n->op == OINDEX && isfixedarray(n->left->type)) {
-			n = n->left;
-			continue;
-		}
-		break;
-	}
-	return n;
-}
-
-/*
- * Is it possible that the computation of n might be
- * affected by writes in as up to but not including stop?
- */
-static int
-aliased(Node *n, NodeList *all, NodeList *stop)
-{
-	int memwrite, varwrite;
-	Node *a;
-	NodeList *l;
-
-	if(n == N)
-		return 0;
-
-	// Look for obvious aliasing: a variable being assigned
-	// during the all list and appearing in n.
-	// Also record whether there are any writes to main memory.
-	// Also record whether there are any writes to variables
-	// whose addresses have been taken.
-	memwrite = 0;
-	varwrite = 0;
-	for(l=all; l!=stop; l=l->next) {
-		a = outervalue(l->n->left);
-		if(a->op != ONAME) {
-			memwrite = 1;
-			continue;
-		}
-		switch(n->class) {
-		default:
-			varwrite = 1;
-			continue;
-		case PAUTO:
-		case PPARAM:
-		case PPARAMOUT:
-			if(n->addrtaken) {
-				varwrite = 1;
-				continue;
-			}
-			if(vmatch2(a, n)) {
-				// Direct hit.
-				return 1;
-			}
-		}
-	}
-
-	// The variables being written do not appear in n.
-	// However, n might refer to computed addresses
-	// that are being written.
-	
-	// If no computed addresses are affected by the writes, no aliasing.
-	if(!memwrite && !varwrite)
-		return 0;
-
-	// If n does not refer to computed addresses
-	// (that is, if n only refers to variables whose addresses
-	// have not been taken), no aliasing.
-	if(varexpr(n))
-		return 0;
-
-	// Otherwise, both the writes and n refer to computed memory addresses.
-	// Assume that they might conflict.
-	return 1;
-}
-
-/*
- * does the evaluation of n only refer to variables
- * whose addresses have not been taken?
- * (and no other memory)
- */
-static int
-varexpr(Node *n)
-{
-	if(n == N)
-		return 1;
-
-	switch(n->op) {
-	case OLITERAL:	
-		return 1;
-	case ONAME:
-		switch(n->class) {
-		case PAUTO:
-		case PPARAM:
-		case PPARAMOUT:
-			if(!n->addrtaken)
-				return 1;
-		}
-		return 0;
-
-	case OADD:
-	case OSUB:
-	case OOR:
-	case OXOR:
-	case OMUL:
-	case ODIV:
-	case OMOD:
-	case OLSH:
-	case ORSH:
-	case OAND:
-	case OANDNOT:
-	case OPLUS:
-	case OMINUS:
-	case OCOM:
-	case OPAREN:
-	case OANDAND:
-	case OOROR:
-	case ODOT:  // but not ODOTPTR
-	case OCONV:
-	case OCONVNOP:
-	case OCONVIFACE:
-	case ODOTTYPE:
-		return varexpr(n->left) && varexpr(n->right);
-	}
-
-	// Be conservative.
-	return 0;
-}
-
-/*
- * is the name l mentioned in r?
- */
-static int
-vmatch2(Node *l, Node *r)
-{
-	NodeList *ll;
-
-	if(r == N)
-		return 0;
-	switch(r->op) {
-	case ONAME:
-		// match each right given left
-		return l == r;
-	case OLITERAL:
-		return 0;
-	}
-	if(vmatch2(l, r->left))
-		return 1;
-	if(vmatch2(l, r->right))
-		return 1;
-	for(ll=r->list; ll; ll=ll->next)
-		if(vmatch2(l, ll->n))
-			return 1;
-	return 0;
-}
-
-/*
- * is any name mentioned in l also mentioned in r?
- * called by sinit.c
- */
-int
-vmatch1(Node *l, Node *r)
-{
-	NodeList *ll;
-
-	/*
-	 * isolate all left sides
-	 */
-	if(l == N || r == N)
-		return 0;
-	switch(l->op) {
-	case ONAME:
-		switch(l->class) {
-		case PPARAM:
-		case PPARAMREF:
-		case PAUTO:
-			break;
-		default:
-			// assignment to non-stack variable
-			// must be delayed if right has function calls.
-			if(r->ullman >= UINF)
-				return 1;
-			break;
-		}
-		return vmatch2(l, r);
-	case OLITERAL:
-		return 0;
-	}
-	if(vmatch1(l->left, r))
-		return 1;
-	if(vmatch1(l->right, r))
-		return 1;
-	for(ll=l->list; ll; ll=ll->next)
-		if(vmatch1(ll->n, r))
-			return 1;
-	return 0;
-}
-
-/*
- * walk through argin parameters.
- * generate and return code to allocate
- * copies of escaped parameters to the heap.
- */
-static NodeList*
-paramstoheap(Type **argin, int out)
-{
-	Type *t;
-	Iter savet;
-	Node *v;
-	NodeList *nn;
-
-	nn = nil;
-	for(t = structfirst(&savet, argin); t != T; t = structnext(&savet)) {
-		v = t->nname;
-		if(v && v->sym && v->sym->name[0] == '~' && v->sym->name[1] == 'r') // unnamed result
-			v = N;
-		// In precisestack mode, the garbage collector assumes results
-		// are always live, so zero them always.
-		if(out && (precisestack_enabled || (v == N && hasdefer))) {
-			// Defer might stop a panic and show the
-			// return values as they exist at the time of panic.
-			// Make sure to zero them on entry to the function.
-			nn = list(nn, nod(OAS, nodarg(t, 1), N));
-		}
-		if(v == N || !(v->class & PHEAP))
-			continue;
-
-		// generate allocation & copying code
-		if(compiling_runtime)
-			yyerror("%N escapes to heap, not allowed in runtime.", v);
-		if(v->alloc == nil)
-			v->alloc = callnew(v->type);
-		nn = list(nn, nod(OAS, v->heapaddr, v->alloc));
-		if((v->class & ~PHEAP) != PPARAMOUT)
-			nn = list(nn, nod(OAS, v, v->stackparam));
-	}
-	return nn;
-}
-
-/*
- * walk through argout parameters copying back to stack
- */
-static NodeList*
-returnsfromheap(Type **argin)
-{
-	Type *t;
-	Iter savet;
-	Node *v;
-	NodeList *nn;
-
-	nn = nil;
-	for(t = structfirst(&savet, argin); t != T; t = structnext(&savet)) {
-		v = t->nname;
-		if(v == N || v->class != (PHEAP|PPARAMOUT))
-			continue;
-		nn = list(nn, nod(OAS, v->stackparam, v));
-	}
-	return nn;
-}
-
-/*
- * take care of migrating any function in/out args
- * between the stack and the heap.  adds code to
- * curfn's before and after lists.
- */
-static void
-heapmoves(void)
-{
-	NodeList *nn;
-	int32 lno;
-
-	lno = lineno;
-	lineno = curfn->lineno;
-	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));
-	lineno = lno;
-}
-
-static Node*
-vmkcall(Node *fn, Type *t, NodeList **init, va_list va)
-{
-	int i, n;
-	Node *r;
-	NodeList *args;
-
-	if(fn->type == T || fn->type->etype != TFUNC)
-		fatal("mkcall %N %T", fn, fn->type);
-
-	args = nil;
-	n = fn->type->intuple;
-	for(i=0; i<n; i++)
-		args = list(args, va_arg(va, Node*));
-
-	r = nod(OCALL, fn, N);
-	r->list = args;
-	if(fn->type->outtuple > 0)
-		typecheck(&r, Erv | Efnstruct);
-	else
-		typecheck(&r, Etop);
-	walkexpr(&r, init);
-	r->type = t;
-	return r;
-}
-
-Node*
-mkcall(char *name, Type *t, NodeList **init, ...)
-{
-	Node *r;
-	va_list va;
-
-	va_start(va, init);
-	r = vmkcall(syslook(name, 0), t, init, va);
-	va_end(va);
-	return r;
-}
-
-Node*
-mkcall1(Node *fn, Type *t, NodeList **init, ...)
-{
-	Node *r;
-	va_list va;
-
-	va_start(va, init);
-	r = vmkcall(fn, t, init, va);
-	va_end(va);
-	return r;
-}
-
-Node*
-conv(Node *n, Type *t)
-{
-	if(eqtype(n->type, t))
-		return n;
-	n = nod(OCONV, n, N);
-	n->type = t;
-	typecheck(&n, Erv);
-	return n;
-}
-
-Node*
-chanfn(char *name, int n, Type *t)
-{
-	Node *fn;
-	int i;
-
-	if(t->etype != TCHAN)
-		fatal("chanfn %T", t);
-	fn = syslook(name, 1);
-	for(i=0; i<n; i++)
-		argtype(fn, t->type);
-	return fn;
-}
-
-static Node*
-mapfn(char *name, Type *t)
-{
-	Node *fn;
-
-	if(t->etype != TMAP)
-		fatal("mapfn %T", t);
-	fn = syslook(name, 1);
-	argtype(fn, t->down);
-	argtype(fn, t->type);
-	argtype(fn, t->down);
-	argtype(fn, t->type);
-	return fn;
-}
-
-static Node*
-mapfndel(char *name, Type *t)
-{
-	Node *fn;
-
-	if(t->etype != TMAP)
-		fatal("mapfn %T", t);
-	fn = syslook(name, 1);
-	argtype(fn, t->down);
-	argtype(fn, t->type);
-	argtype(fn, t->down);
-	return fn;
-}
-
-static Node*
-writebarrierfn(char *name, Type *l, Type *r)
-{
-	Node *fn;
-
-	fn = syslook(name, 1);
-	argtype(fn, l);
-	argtype(fn, r);
-	return fn;
-}
-
-static Node*
-addstr(Node *n, NodeList **init)
-{
-	Node *r, *cat, *slice;
-	NodeList *args, *l;
-	int c;
-	Type *t;
-
-	// orderexpr rewrote OADDSTR to have a list of strings.
-	c = count(n->list);
-	if(c < 2)
-		yyerror("addstr count %d too small", c);
-
-	// build list of string arguments
-	args = nil;
-	for(l=n->list; l != nil; l=l->next)
-		args = list(args, conv(l->n, types[TSTRING]));
-
-	if(c <= 5) {
-		// small numbers of strings use direct runtime helpers.
-		// note: orderexpr knows this cutoff too.
-		snprint(namebuf, sizeof(namebuf), "concatstring%d", c);
-	} else {
-		// large numbers of strings are passed to the runtime as a slice.
-		strcpy(namebuf, "concatstrings");
-		t = typ(TARRAY);
-		t->type = types[TSTRING];
-		t->bound = -1;
-		slice = nod(OCOMPLIT, N, typenod(t));
-		slice->alloc = n->alloc;
-		slice->list = args;
-		slice->esc = EscNone;
-		args = list1(slice);
-	}
-	cat = syslook(namebuf, 1);
-	r = nod(OCALL, cat, N);
-	r->list = args;
-	typecheck(&r, Erv);
-	walkexpr(&r, init);
-	r->type = n->type;
-
-	return r;
-}
-
-// expand append(l1, l2...) to
-//   init {
-//     s := l1
-//     if n := len(l1) + len(l2) - cap(s); n > 0 {
-//       s = growslice(s, n)
-//     }
-//     s = s[:len(l1)+len(l2)]
-//     memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T))
-//   }
-//   s
-//
-// l2 is allowed to be a string.
-static Node*
-appendslice(Node *n, NodeList **init)
-{
-	NodeList *l;
-	Node *l1, *l2, *nt, *nif, *fn;
-	Node *nptr1, *nptr2, *nwid;
-	Node *s;
-
-	walkexprlistsafe(n->list, init);
-
-	// walkexprlistsafe will leave OINDEX (s[n]) alone if both s
-	// and n are name or literal, but those may index the slice we're
-	// modifying here.  Fix explicitly.
-	for(l=n->list; l; l=l->next)
-		l->n = cheapexpr(l->n, init);
-
-	l1 = n->list->n;
-	l2 = n->list->next->n;
-
-	s = temp(l1->type); // var s []T
-	l = nil;
-	l = list(l, nod(OAS, s, l1)); // s = l1
-
-	nt = temp(types[TINT]);
-	nif = nod(OIF, N, N);
-	// n := len(s) + len(l2) - cap(s)
-	nif->ninit = list1(nod(OAS, nt,
-		nod(OSUB, nod(OADD, nod(OLEN, s, N), nod(OLEN, l2, N)), nod(OCAP, s, N))));
-	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);
-
-	// 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]))));
-
-	l = list(l, nif);
-
-	if(flag_race) {
-		// rely on runtime to instrument copy.
-		// copy(s[len(l1):len(l1)+len(l2)], l2)
-		nptr1 = nod(OSLICE, s, nod(OKEY,
-			nod(OLEN, l1, N),
-			nod(OADD, nod(OLEN, l1, N), nod(OLEN, l2, N))));
-		nptr1->etype = 1;
-		nptr2 = l2;
-		if(l2->type->etype == TSTRING)
-			fn = syslook("slicestringcopy", 1);
-		else
-			fn = syslook("slicecopy", 1);
-		argtype(fn, l1->type);
-		argtype(fn, l2->type);
-		nt = mkcall1(fn, types[TINT], &l,
-				nptr1, nptr2,
-				nodintconst(s->type->type->width));
-		l = list(l, nt);
-	} else {
-		// memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T))
-		nptr1 = nod(OINDEX, s, nod(OLEN, l1, N));
-		nptr1->bounded = 1;
-		nptr1 = nod(OADDR, nptr1, N);
-
-		nptr2 = nod(OSPTR, l2, N);
-
-		fn = syslook("memmove", 1);
-		argtype(fn, s->type->type);	// 1 old []any
-		argtype(fn, s->type->type);	// 2 ret []any
-
-		nwid = cheapexpr(conv(nod(OLEN, l2, N), types[TUINTPTR]), &l);
-		nwid = nod(OMUL, nwid, nodintconst(s->type->type->width));
-		nt = mkcall1(fn, T, &l, nptr1, nptr2, nwid);
-		l = list(l, nt);
-	}
-
-	// s = s[:len(l1)+len(l2)]
-	nt = nod(OADD, nod(OLEN, l1, N), nod(OLEN, l2, N));
-	nt = nod(OSLICE, s, nod(OKEY, N, nt));
-	nt->etype = 1;
-	l = list(l, nod(OAS, s, nt));
-
-	typechecklist(l, Etop);
-	walkstmtlist(l);
-	*init = concat(*init, l);
-	return s;
-}
-
-// expand append(src, a [, b]* ) to
-//
-//   init {
-//     s := src
-//     const argc = len(args) - 1
-//     if cap(s) - len(s) < argc {
-//	    s = growslice(s, argc)
-//     }
-//     n := len(s)
-//     s = s[:n+argc]
-//     s[n] = a
-//     s[n+1] = b
-//     ...
-//   }
-//   s
-static Node*
-append(Node *n, NodeList **init)
-{
-	NodeList *l, *a;
-	Node *nsrc, *ns, *nn, *na, *nx, *fn;
-	int argc;
-
-	walkexprlistsafe(n->list, init);
-
-	// walkexprlistsafe will leave OINDEX (s[n]) alone if both s
-	// and n are name or literal, but those may index the slice we're
-	// modifying here.  Fix explicitly.
-	for(l=n->list; l; l=l->next)
-		l->n = cheapexpr(l->n, init);
-
-	nsrc = n->list->n;
-
-	// Resolve slice type of multi-valued return.
-	if(istype(nsrc->type, TSTRUCT))
-		nsrc->type = nsrc->type->type->type;
-	argc = count(n->list) - 1;
-	if (argc < 1) {
-		return nsrc;
-	}
-
-	l = nil;
-
-	ns = temp(nsrc->type);
-	l = list(l, nod(OAS, ns, nsrc));  // s = src
-
-	na = nodintconst(argc);		// const argc
-	nx = nod(OIF, N, N);		// if cap(s) - len(s) < argc
-	nx->ntest = nod(OLT, nod(OSUB, nod(OCAP, ns, N), nod(OLEN, ns, N)), 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
-
-	nx->nbody = list1(nod(OAS, ns, mkcall1(fn,  ns->type, &nx->ninit,
-					       typename(ns->type),
-					       ns,
-					       conv(na, types[TINT64]))));
-	l = list(l, nx);
-
-	nn = temp(types[TINT]);
-	l = list(l, nod(OAS, nn, nod(OLEN, ns, N)));	 // n = len(s)
-
-	nx = nod(OSLICE, ns, nod(OKEY, N, nod(OADD, nn, na)));	 // ...s[:n+argc]
-	nx->etype = 1;
-	l = list(l, nod(OAS, ns, nx));			// s = s[:n+argc]
-
-	for (a = n->list->next;	 a != nil; a = a->next) {
-		nx = nod(OINDEX, ns, nn);		// s[n] ...
-		nx->bounded = 1;
-		l = list(l, nod(OAS, nx, a->n));	// s[n] = arg
-		if (a->next != nil)
-			l = list(l, nod(OAS, nn, nod(OADD, nn, nodintconst(1))));  // n = n + 1
-	}
-
-	typechecklist(l, Etop);
-	walkstmtlist(l);
-	*init = concat(*init, l);
-	return ns;
-}
-
-// Lower copy(a, b) to a memmove call or a runtime call.
-//
-// init {
-//   n := len(a)
-//   if n > len(b) { n = len(b) }
-//   memmove(a.ptr, b.ptr, n*sizeof(elem(a)))
-// }
-// n;
-//
-// Also works if b is a string.
-//
-static Node*
-copyany(Node *n, NodeList **init, int runtimecall)
-{
-	Node *nl, *nr, *nfrm, *nto, *nif, *nlen, *nwid, *fn;
-	NodeList *l;
-
-	if(runtimecall) {
-		if(n->right->type->etype == TSTRING)
-			fn = syslook("slicestringcopy", 1);
-		else
-			fn = syslook("slicecopy", 1);
-		argtype(fn, n->left->type);
-		argtype(fn, n->right->type);
-		return mkcall1(fn, n->type, init,
-				n->left, n->right,
-				nodintconst(n->left->type->type->width));
-	}
-	walkexpr(&n->left, init);
-	walkexpr(&n->right, init);
-	nl = temp(n->left->type);
-	nr = temp(n->right->type);
-	l = nil;
-	l = list(l, nod(OAS, nl, n->left));
-	l = list(l, nod(OAS, nr, n->right));
-
-	nfrm = nod(OSPTR, nr, N);
-	nto = nod(OSPTR, nl, N);
-
-	nlen = temp(types[TINT]);
-	// n = len(to)
-	l = list(l, nod(OAS, nlen, nod(OLEN, nl, N)));
-	// if n > len(frm) { n = len(frm) }
-	nif = nod(OIF, N, N);
-	nif->ntest = nod(OGT, nlen, nod(OLEN, nr, N));
-	nif->nbody = list(nif->nbody,
-		nod(OAS, nlen, nod(OLEN, nr, N)));
-	l = list(l, nif);
-
-	// Call memmove.
-	fn = syslook("memmove", 1);
-	argtype(fn, nl->type->type);
-	argtype(fn, 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));
-	l = list(l, mkcall1(fn, T, init, nto, nfrm, nwid));
-
-	typechecklist(l, Etop);
-	walkstmtlist(l);
-	*init = concat(*init, l);
-	return nlen;
-}
-
-// Generate frontend part for OSLICE[3][ARR|STR]
-// 
-static	Node*
-sliceany(Node* n, NodeList **init)
-{
-	int bounded, slice3;
-	Node *src, *lb, *hb, *cb, *bound, *chk, *chk0, *chk1, *chk2;
-	int64 lbv, hbv, cbv, bv, w;
-	Type *bt;
-
-//	print("before sliceany: %+N\n", n);
-
-	src = n->left;
-	lb = n->right->left;
-	slice3 = n->op == OSLICE3 || n->op == OSLICE3ARR;
-	if(slice3) {
-		hb = n->right->right->left;
-		cb = n->right->right->right;
-	} else {
-		hb = n->right->right;
-		cb = N;
-	}
-
-	bounded = n->etype;
-	
-	if(n->op == OSLICESTR)
-		bound = nod(OLEN, src, N);
-	else
-		bound = nod(OCAP, src, N);
-
-	typecheck(&bound, Erv);
-	walkexpr(&bound, init);  // if src is an array, bound will be a const now.
-
-	// static checks if possible
-	bv = 1LL<<50;
-	if(isconst(bound, CTINT)) {
-		if(!smallintconst(bound))
-			yyerror("array len too large");
-		else
-			bv = mpgetfix(bound->val.u.xval);
-	}
-
-	if(isconst(cb, CTINT)) {
-		cbv = mpgetfix(cb->val.u.xval);
-		if(cbv < 0 || cbv > bv)
-			yyerror("slice index out of bounds");
-	}
-	if(isconst(hb, CTINT)) {
-		hbv = mpgetfix(hb->val.u.xval);
-		if(hbv < 0 || hbv > bv)
-			yyerror("slice index out of bounds");
-	}
-	if(isconst(lb, CTINT)) {
-		lbv = mpgetfix(lb->val.u.xval);
-		if(lbv < 0 || lbv > bv) {
-			yyerror("slice index out of bounds");
-			lbv = -1;
-		}
-		if(lbv == 0)
-			lb = N;
-	}
-
-	// Checking src[lb:hb:cb] or src[lb:hb].
-	// if chk0 || chk1 || chk2 { panicslice() }
-	chk = N;
-	chk0 = N; // cap(src) < cb
-	chk1 = N; // cb < hb for src[lb:hb:cb]; cap(src) < hb for src[lb:hb]
-	chk2 = N; // hb < lb
-
-	// All comparisons are unsigned to avoid testing < 0.
-	bt = types[simtype[TUINT]];
-	if(cb != N && cb->type->width > 4)
-		bt = types[TUINT64];
-	if(hb != N && hb->type->width > 4)
-		bt = types[TUINT64];
-	if(lb != N && lb->type->width > 4)
-		bt = types[TUINT64];
-
-	bound = cheapexpr(conv(bound, bt), init);
-
-	if(cb != N) {
-		cb = cheapexpr(conv(cb, bt), init);
-		if(!bounded)
-			chk0 = nod(OLT, bound, cb);
-	} else if(slice3) {
-		// When we figure out what this means, implement it.
-		fatal("slice3 with cb == N"); // rejected by parser
-	}
-		
-	if(hb != N) {
-		hb = cheapexpr(conv(hb, bt), init);
-		if(!bounded) {
-			if(cb != N)
-				chk1 = nod(OLT, cb, hb);
-			else
-				chk1 = nod(OLT, bound, hb);
-		}
-	} else if(slice3) {
-		// When we figure out what this means, implement it.
-		fatal("slice3 with hb == N"); // rejected by parser
-	} else if(n->op == OSLICEARR) {
-		hb = bound;
-	} else {
-		hb = nod(OLEN, src, N);
-		typecheck(&hb, Erv);
-		walkexpr(&hb, init);
-		hb = cheapexpr(conv(hb, bt), init);
-	}
-
-	if(lb != N) {
-		lb = cheapexpr(conv(lb, bt), init);
-		if(!bounded)
-			chk2 = nod(OLT, hb, lb);  
-	}
-
-	if(chk0 != N || chk1 != N || chk2 != N) {
-		chk = nod(OIF, N, N);
-		chk->nbody = list1(mkcall("panicslice", T, init));
-		chk->likely = -1;
-		if(chk0 != N)
-			chk->ntest = chk0;
-		if(chk1 != N) {
-			if(chk->ntest == N)
-				chk->ntest = chk1;
-			else
-				chk->ntest = nod(OOROR, chk->ntest, chk1);
-		}
-		if(chk2 != N) {
-			if(chk->ntest == N)
-				chk->ntest = chk2;
-			else
-				chk->ntest = nod(OOROR, chk->ntest, chk2);
-		}
-		typecheck(&chk, Etop);
-		walkstmt(&chk);
-		*init = concat(*init, chk->ninit);
-		chk->ninit = nil;
-		*init = list(*init, chk);
-	}
-	
-	// prepare new cap, len and offs for backend cgen_slice
-	// cap = bound [ - lo ]
-	n->right = N;
-	n->list = nil;
-	if(!slice3)
-		cb = bound;
-	if(lb == N)
-		bound = conv(cb, types[simtype[TUINT]]);
-	else
-		bound = nod(OSUB, conv(cb, types[simtype[TUINT]]), conv(lb, types[simtype[TUINT]]));
-	typecheck(&bound, Erv);
-	walkexpr(&bound, init);
-	n->list = list(n->list, bound);
-
-	// len = hi [ - lo]
-	if(lb == N)
-		hb = conv(hb, types[simtype[TUINT]]);
-	else
-		hb = nod(OSUB, conv(hb, types[simtype[TUINT]]), conv(lb, types[simtype[TUINT]]));
-	typecheck(&hb, Erv);
-	walkexpr(&hb, init);
-	n->list = list(n->list, hb);
-
-	// offs = [width *] lo, but omit if zero
-	if(lb != N) {
-		if(n->op == OSLICESTR)
-			w = 1;
-		else
-			w = n->type->type->width;
-		lb = conv(lb, types[TUINTPTR]);
-		if(w > 1)
-			lb = nod(OMUL, nodintconst(w), lb);
-		typecheck(&lb, Erv);
-		walkexpr(&lb, init);
-		n->list = list(n->list, lb);
-	}
-
-//	print("after sliceany: %+N\n", n);
-
-	return n;
-}
-
-static Node*
-eqfor(Type *t)
-{
-	int a;
-	Node *n;
-	Node *ntype;
-	Sym *sym;
-
-	// Should only arrive here with large memory or
-	// a struct/array containing a non-memory field/element.
-	// Small memory is handled inline, and single non-memory
-	// is handled during type check (OCMPSTR etc).
-	a = algtype1(t, nil);
-	if(a != AMEM && a != -1)
-		fatal("eqfor %T", t);
-
-	if(a == AMEM) {
-		n = syslook("memequal", 1);
-		argtype(n, t);
-		argtype(n, t);
-		return n;
-	}
-
-	sym = typesymprefix(".eq", t);
-	n = newname(sym);
-	n->class = PFUNC;
-	ntype = nod(OTFUNC, N, N);
-	ntype->list = list(ntype->list, nod(ODCLFIELD, N, typenod(ptrto(t))));
-	ntype->list = list(ntype->list, nod(ODCLFIELD, N, typenod(ptrto(t))));
-	ntype->list = list(ntype->list, nod(ODCLFIELD, N, typenod(types[TUINTPTR])));
-	ntype->rlist = list(ntype->rlist, nod(ODCLFIELD, N, typenod(types[TBOOL])));
-	typecheck(&ntype, Etype);
-	n->type = ntype->type;
-	return n;
-}
-
-static int
-countfield(Type *t)
-{
-	Type *t1;
-	int n;
-	
-	n = 0;
-	for(t1=t->type; t1!=T; t1=t1->down)
-		n++;
-	return n;
-}
-
-static void
-walkcompare(Node **np, NodeList **init)
-{
-	Node *n, *l, *r, *call, *a, *li, *ri, *expr, *cmpl, *cmpr;
-	int andor, i;
-	Type *t, *t1;
-	
-	n = *np;
-	
-	// Must be comparison of array or struct.
-	// Otherwise back end handles it.
-	t = n->left->type;
-	switch(t->etype) {
-	default:
-		return;
-	case TARRAY:
-		if(isslice(t))
-			return;
-		break;
-	case TSTRUCT:
-		break;
-	}
-	
-	cmpl = n->left;
-	while(cmpl != N && cmpl->op == OCONVNOP)
-		cmpl = cmpl->left;
-	cmpr = n->right;
-	while(cmpr != N && cmpr->op == OCONVNOP)
-		cmpr = cmpr->left;
-	
-	if(!islvalue(cmpl) || !islvalue(cmpr)) {
-		fatal("arguments of comparison must be lvalues - %N %N", cmpl, cmpr);
-	}
-
-	l = temp(ptrto(t));
-	a = nod(OAS, l, nod(OADDR, cmpl, N));
-	a->right->etype = 1;  // addr does not escape
-	typecheck(&a, Etop);
-	*init = list(*init, a);
-
-	r = temp(ptrto(t));
-	a = nod(OAS, r, nod(OADDR, cmpr, N));
-	a->right->etype = 1;  // addr does not escape
-	typecheck(&a, Etop);
-	*init = list(*init, a);
-
-	expr = N;
-	andor = OANDAND;
-	if(n->op == ONE)
-		andor = OOROR;
-
-	if(t->etype == TARRAY &&
-		t->bound <= 4 &&
-		issimple[t->type->etype]) {
-		// Four or fewer elements of a basic type.
-		// Unroll comparisons.
-		for(i=0; i<t->bound; i++) {
-			li = nod(OINDEX, l, nodintconst(i));
-			ri = nod(OINDEX, r, nodintconst(i));
-			a = nod(n->op, li, ri);
-			if(expr == N)
-				expr = a;
-			else
-				expr = nod(andor, expr, a);
-		}
-		if(expr == N)
-			expr = nodbool(n->op == OEQ);
-		r = expr;
-		goto ret;
-	}
-
-	if(t->etype == TSTRUCT && countfield(t) <= 4) {
-		// Struct of four or fewer fields.
-		// Inline comparisons.
-		for(t1=t->type; t1; t1=t1->down) {
-			if(isblanksym(t1->sym))
-				continue;
-			li = nod(OXDOT, l, newname(t1->sym));
-			ri = nod(OXDOT, r, newname(t1->sym));
-			a = nod(n->op, li, ri);
-			if(expr == N)
-				expr = a;
-			else
-				expr = nod(andor, expr, a);
-		}
-		if(expr == N)
-			expr = nodbool(n->op == OEQ);
-		r = expr;
-		goto ret;
-	}
-
-	// Chose not to inline.  Call equality function directly.
-	call = nod(OCALL, eqfor(t), N);
-	call->list = list(call->list, l);
-	call->list = list(call->list, r);
-	call->list = list(call->list, nodintconst(t->width));
-	r = call;
-	if(n->op != OEQ)
-		r = nod(ONOT, r, N);
-	goto ret;
-
-ret:
-	typecheck(&r, Erv);
-	walkexpr(&r, init);
-	if(r->type != n->type) {
-		r = nod(OCONVNOP, r, N);
-		r->type = n->type;
-		r->typecheck = 1;
-	}
-	*np = r;
-	return;
-}
-
-static int
-samecheap(Node *a, Node *b)
-{
-	Node *ar, *br;
-	while(a != N && b != N && a->op == b->op) {
-		switch(a->op) {
-		default:
-			return 0;
-		case ONAME:
-			return a == b;
-		case ODOT:
-		case ODOTPTR:
-			ar = a->right;
-			br = b->right;
-			if(ar->op != ONAME || br->op != ONAME || ar->sym != br->sym)
-				return 0;
-			break;
-		case OINDEX:
-			ar = a->right;
-			br = b->right;
-			if(!isconst(ar, CTINT) || !isconst(br, CTINT) || mpcmpfixfix(ar->val.u.xval, br->val.u.xval) != 0)
-				return 0;
-			break;
-		}
-		a = a->left;
-		b = b->left;
-	}
-	return 0;
-}
-
-static void
-walkrotate(Node **np)
-{
-	int w, sl, sr, s;
-	Node *l, *r;
-	Node *n;
-	
-	n = *np;
-
-	// Want << | >> or >> | << or << ^ >> or >> ^ << on unsigned value.
-	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 == T || issigned[n->type->etype] ||
-	   l->op == r->op) {
-		return;
-	}
-
-	// Want same, side effect-free expression on lhs of both shifts.
-	if(!samecheap(l->left, r->left))
-		return;
-	
-	// Constants adding to width?
-	w = l->type->width * 8;
-	if(smallintconst(l->right) && smallintconst(r->right)) {
-		if((sl=mpgetfix(l->right->val.u.xval)) >= 0 && (sr=mpgetfix(r->right->val.u.xval)) >= 0 && sl+sr == w)
-			goto yes;
-		return;
-	}
-	
-	// TODO: Could allow s and 32-s if s is bounded (maybe s&31 and 32-s&31).
-	return;
-	
-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 = mpgetfix(n->right->val.u.xval);
-	if(s == 0 || s == w)
-		n = n->left;
-
-	*np = n;
-	return;
-}
-
-/*
- * walkmul rewrites integer multiplication by powers of two as shifts.
- */
-static void
-walkmul(Node **np, NodeList **init)
-{
-	Node *n, *nl, *nr;
-	int pow, neg, w;
-	
-	n = *np;
-	if(!isint[n->type->etype])
-		return;
-
-	if(n->right->op == OLITERAL) {
-		nl = n->left;
-		nr = n->right;
-	} else if(n->left->op == OLITERAL) {
-		nl = n->right;
-		nr = n->left;
-	} else
-		return;
-
-	neg = 0;
-
-	// x*0 is 0 (and side effects of x).
-	if(mpgetfix(nr->val.u.xval) == 0) {
-		cheapexpr(nl, init);
-		nodconst(n, n->type, 0);
-		goto ret;
-	}
-
-	// nr is a constant.
-	pow = powtwo(nr);
-	if(pow < 0)
-		return;
-	if(pow >= 1000) {
-		// negative power of 2, like -16
-		neg = 1;
-		pow -= 1000;
-	}
-
-	w = nl->type->width*8;
-	if(pow+1 >= w)// too big, shouldn't happen
-		return;
-
-	nl = cheapexpr(nl, init);
-
-	if(pow == 0) {
-		// x*1 is x
-		n = nl;
-		goto ret;
-	}
-	
-	n = nod(OLSH, nl, nodintconst(pow));
-
-ret:
-	if(neg)
-		n = nod(OMINUS, n, N);
-
-	typecheck(&n, Erv);
-	walkexpr(&n, init);
-	*np = n;
-}
-
-/*
- * walkdiv rewrites division by a constant as less expensive
- * operations.
- */
-static void
-walkdiv(Node **np, NodeList **init)
-{
-	Node *n, *nl, *nr, *nc;
-	Node *n1, *n2, *n3, *n4;
-	int pow; // if >= 0, nr is 1<<pow
-	int s; // 1 if nr is negative.
-	int w;
-	Type *twide;
-	Magic m;
-
-	n = *np;
-	if(n->right->op != OLITERAL)
-		return;
-	// nr is a constant.
-	nl = cheapexpr(n->left, init);
-	nr = n->right;
-
-	// special cases of mod/div
-	// by a constant
-	w = nl->type->width*8;
-	s = 0;
-	pow = powtwo(nr);
-	if(pow >= 1000) {
-		// negative power of 2
-		s = 1;
-		pow -= 1000;
-	}
-
-	if(pow+1 >= w) {
-		// divisor too large.
-		return;
-	}
-	if(pow < 0) {
-		goto divbymul;
-	}
-
-	switch(pow) {
-	case 0:
-		if(n->op == OMOD) {
-			// nl % 1 is zero.
-			nodconst(n, n->type, 0);
-		} else if(s) {
-			// divide by -1
-			n->op = OMINUS;
-			n->right = N;
-		} else {
-			// divide by 1
-			n = nl;
-		}
-		break;
-	default:
-		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,
-				// nl & (2^pow-1) is (nl+1)%2^pow - 1.
-				nc = nod(OXXX, N, N);
-				nodconst(nc, types[simtype[TUINT]], w-1);
-				n1 = nod(ORSH, nl, nc); // n1 = -1 iff nl < 0.
-				if(pow == 1) {
-					typecheck(&n1, Erv);
-					n1 = cheapexpr(n1, init);
-					// n = (nl+ε)&1 -ε where ε=1 iff nl<0.
-					n2 = nod(OSUB, nl, n1);
-					nc = nod(OXXX, N, N);
-					nodconst(nc, nl->type, 1);
-					n3 = nod(OAND, n2, nc);
-					n = nod(OADD, n3, n1);
-				} else {
-					// n = (nl+ε)&(nr-1) - ε where ε=2^pow-1 iff nl<0.
-					nc = nod(OXXX, N, N);
-					nodconst(nc, nl->type, (1LL<<pow)-1);
-					n2 = nod(OAND, n1, nc); // n2 = 2^pow-1 iff nl<0.
-					typecheck(&n2, Erv);
-					n2 = cheapexpr(n2, init);
-
-					n3 = nod(OADD, nl, n2);
-					n4 = nod(OAND, n3, nc);
-					n = nod(OSUB, n4, n2);
-				}
-				break;
-			} else {
-				// arithmetic right shift does not give the correct rounding.
-				// if nl >= 0, nl >> n == nl / nr
-				// if nl < 0, we want to add 2^n-1 first.
-				nc = nod(OXXX, N, N);
-				nodconst(nc, types[simtype[TUINT]], w-1);
-				n1 = nod(ORSH, nl, nc); // n1 = -1 iff nl < 0.
-				if(pow == 1) {
-					// nl+1 is nl-(-1)
-					n->left = nod(OSUB, nl, n1);
-				} else {
-					// Do a logical right right on -1 to keep pow bits.
-					nc = nod(OXXX, N, N);
-					nodconst(nc, types[simtype[TUINT]], w-pow);
-					n2 = nod(ORSH, conv(n1, tounsigned(nl->type)), nc);
-					n->left = nod(OADD, nl, conv(n2, nl->type));
-				}
-				// n = (nl + 2^pow-1) >> pow
-				n->op = ORSH;
-				nc = nod(OXXX, N, N);
-				nodconst(nc, types[simtype[TUINT]], pow);
-				n->right = nc;
-				n->typecheck = 0;
-			}
-			if(s)
-				n = nod(OMINUS, n, N);
-			break;
-		}
-		nc = nod(OXXX, N, N);
-		if(n->op == OMOD) {
-			// n = nl & (nr-1)
-			n->op = OAND;
-			nodconst(nc, nl->type, mpgetfix(nr->val.u.xval)-1);
-		} else {
-			// n = nl >> pow
-			n->op = ORSH;
-			nodconst(nc, types[simtype[TUINT]], pow);
-		}
-		n->typecheck = 0;
-		n->right = nc;
-		break;
-	}
-	goto ret;
-
-divbymul:
-	// try to do division by multiply by (2^w)/d
-	// see hacker's delight chapter 10
-	// TODO: support 64-bit magic multiply here.
-	m.w = w;
-	if(issigned[nl->type->etype]) {
-		m.sd = mpgetfix(nr->val.u.xval);
-		smagic(&m);
-	} else {
-		m.ud = mpgetfix(nr->val.u.xval);
-		umagic(&m);
-	}
-	if(m.bad)
-		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;
-
-	case TUINT8:
-	case TUINT16:
-	case TUINT32:
-		// n1 = nl * magic >> w (HMUL)
-		nc = nod(OXXX, N, N);
-		nodconst(nc, nl->type, m.um);
-		n1 = nod(OMUL, nl, nc);
-		typecheck(&n1, Erv);
-		n1->op = OHMUL;
-		if(m.ua) {
-			// Select a Go type with (at least) twice the width.
-			switch(simtype[nl->type->etype]) {
-			default:
-				return;
-			case TUINT8:
-			case TUINT16:
-				twide = types[TUINT32];
-				break;
-			case TUINT32:
-				twide = types[TUINT64];
-				break;
-			case TINT8:
-			case TINT16:
-				twide = types[TINT32];
-				break;
-			case TINT32:
-				twide = types[TINT64];
-				break;
-			}
-
-			// add numerator (might overflow).
-			// n2 = (n1 + nl)
-			n2 = nod(OADD, conv(n1, twide), conv(nl, twide));
-
-			// shift by m.s
-			nc = nod(OXXX, N, N);
-			nodconst(nc, types[TUINT], m.s);
-			n = conv(nod(ORSH, n2, nc), nl->type);
-		} else {
-			// n = n1 >> m.s
-			nc = nod(OXXX, N, N);
-			nodconst(nc, types[TUINT], m.s);
-			n = nod(ORSH, n1, nc);
-		}
-		break;
-
-	case TINT8:
-	case TINT16:
-	case TINT32:
-		// n1 = nl * magic >> w
-		nc = nod(OXXX, N, N);
-		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, N, N);
-		nodconst(nc, types[TUINT], m.s);
-		n2 = conv(nod(ORSH, n1, nc), nl->type);
-		// add 1 iff n1 is negative.
-		nc = nod(OXXX, N, N);
-		nodconst(nc, types[TUINT], 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, N);
-		break;
-	}
-	goto ret;
-
-longmod:
-	// 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;
-
-ret:
-	typecheck(&n, Erv);
-	walkexpr(&n, init);
-	*np = n;
-}
-
-// return 1 if integer n must be in range [0, max), 0 otherwise
-static int
-bounded(Node *n, int64 max)
-{
-	int64 v;
-	int32 bits;
-	int sign;
-
-	if(n->type == T || !isint[n->type->etype])
-		return 0;
-
-	sign = issigned[n->type->etype];
-	bits = 8*n->type->width;
-
-	if(smallintconst(n)) {
-		v = mpgetfix(n->val.u.xval);
-		return 0 <= v && v < max;
-	}
-
-	switch(n->op) {
-	case OAND:
-		v = -1;
-		if(smallintconst(n->left)) {
-			v = mpgetfix(n->left->val.u.xval);
-		} else if(smallintconst(n->right)) {
-			v = mpgetfix(n->right->val.u.xval);
-		}
-		if(0 <= v && v < max)
-			return 1;
-		break;
-
-	case OMOD:
-		if(!sign && smallintconst(n->right)) {
-			v = mpgetfix(n->right->val.u.xval);
-			if(0 <= v && v <= max)
-				return 1;
-		}
-		break;
-	
-	case ODIV:
-		if(!sign && smallintconst(n->right)) {
-			v = mpgetfix(n->right->val.u.xval);
-			while(bits > 0 && v >= 2) {
-				bits--;
-				v >>= 1;
-			}
-		}
-		break;
-	
-	case ORSH:
-		if(!sign && smallintconst(n->right)) {
-			v = mpgetfix(n->right->val.u.xval);
-			if(v > bits)
-				return 1;
-			bits -= v;
-		}
-		break;
-	}
-	
-	if(!sign && bits <= 62 && (1LL<<bits) <= max)
-		return 1;
-	
-	return 0;
-}
-
-void
-usefield(Node *n)
-{
-	Type *field, *l;
-
-	if(!fieldtrack_enabled)
-		return;
-
-	switch(n->op) {
-	default:
-		fatal("usefield %O", n->op);
-	case ODOT:
-	case ODOTPTR:
-		break;
-	}
-	
-	field = n->paramfld;
-	if(field == T)
-		fatal("usefield %T %S without paramfld", n->left->type, n->right->sym);
-	if(field->note == nil || strstr(field->note->s, "go:\"track\"") == nil)
-		return;
-
-	// dedup on list
-	if(field->lastfn == curfn)
-		return;
-	field->lastfn = curfn;
-	field->outer = n->left->type;
-	if(isptr[field->outer->etype])
-		field->outer = field->outer->type;
-	if(field->outer->sym == S)
-		yyerror("tracked field must be in named struct type");
-	if(!exportname(field->sym->name))
-		yyerror("tracked field must be exported (upper case)");
-
-	l = typ(0);
-	l->type = field;
-	l->down = curfn->paramfld;
-	curfn->paramfld = l;
-}
-
-static int
-candiscardlist(NodeList *l)
-{
-	for(; l; l=l->next)
-		if(!candiscard(l->n))
-			return 0;
-	return 1;
-}
-
-int
-candiscard(Node *n)
-{
-	if(n == N)
-		return 1;
-	
-	switch(n->op) {
-	default:
-		return 0;
-
-	case ONAME:
-	case ONONAME:
-	case OTYPE:
-	case OPACK:
-	case OLITERAL:
-	case OADD:
-	case OSUB:
-	case OOR:
-	case OXOR:
-	case OADDSTR:
-	case OADDR:
-	case OANDAND:
-	case OARRAYBYTESTR:
-	case OARRAYRUNESTR:
-	case OSTRARRAYBYTE:
-	case OSTRARRAYRUNE:
-	case OCAP:
-	case OCMPIFACE:
-	case OCMPSTR:
-	case OCOMPLIT:
-	case OMAPLIT:
-	case OSTRUCTLIT:
-	case OARRAYLIT:
-	case OPTRLIT:
-	case OCONV:
-	case OCONVIFACE:
-	case OCONVNOP:
-	case ODOT:
-	case OEQ:
-	case ONE:
-	case OLT:
-	case OLE:
-	case OGT:
-	case OGE:
-	case OKEY:
-	case OLEN:
-	case OMUL:
-	case OLSH:
-	case ORSH:
-	case OAND:
-	case OANDNOT:
-	case ONEW:
-	case ONOT:
-	case OCOM:
-	case OPLUS:
-	case OMINUS:
-	case OOROR:
-	case OPAREN:
-	case ORUNESTR:
-	case OREAL:
-	case OIMAG:
-	case OCOMPLEX:
-		// Discardable as long as the subpieces are.
-		break;
-
-	case ODIV:
-	case OMOD:
-		// Discardable as long as we know it's not division by zero.
-		if(isconst(n->right, CTINT) && mpcmpfixc(n->right->val.u.xval, 0) != 0)
-			break;
-		if(isconst(n->right, CTFLT) && mpcmpfltc(n->right->val.u.fval, 0) != 0)
-			break;
-		return 0;
-
-	case OMAKECHAN:
-	case OMAKEMAP:
-		// Discardable as long as we know it won't fail because of a bad size.
-		if(isconst(n->left, CTINT) && mpcmpfixc(n->left->val.u.xval, 0) == 0)
-			break;
-		return 0;
-	
-	case OMAKESLICE:
-		// Difficult to tell what sizes are okay.
-		return 0;		
-	}
-	
-	if(!candiscard(n->left) ||
-	   !candiscard(n->right) ||
-	   !candiscard(n->ntest) ||
-	   !candiscard(n->nincr) ||
-	   !candiscardlist(n->ninit) ||
-	   !candiscardlist(n->nbody) ||
-	   !candiscardlist(n->nelse) ||
-	   !candiscardlist(n->list) ||
-	   !candiscardlist(n->rlist)) {
-		return 0;
-	}
-	
-	return 1;
-}
-
-// rewrite
-//	print(x, y, z)
-// into
-//	func(a1, a2, a3) {
-//		print(a1, a2, a3)
-//	}(x, y, z)
-// and same for println.
-static void
-walkprintfunc(Node **np, NodeList **init)
-{
-	Node *n;
-	Node *a, *fn, *t, *oldfn;
-	NodeList *l, *printargs;
-	int num;
-	char buf[100];
-	static int prgen;
-	
-	n = *np;
-
-	if(n->ninit != nil) {
-		walkstmtlist(n->ninit);
-		*init = concat(*init, n->ninit);
-		n->ninit = nil;
-	}
-
-	t = nod(OTFUNC, N, N);
-	num = 0;
-	printargs = nil;
-	for(l=n->list; l != nil; l=l->next) {
-		snprint(buf, sizeof buf, "a%d", num++);
-		a = nod(ODCLFIELD, newname(lookup(buf)), typenod(l->n->type));
-		t->list = list(t->list, a);
-		printargs = list(printargs, a->left);
-	}
-
-	fn = nod(ODCLFUNC, N, N);
-	snprint(buf, sizeof buf, "print·%d", ++prgen);
-	fn->nname = newname(lookup(buf));
-	fn->nname->defn = fn;
-	fn->nname->ntype = t;
-	declare(fn->nname, PFUNC);
-
-	oldfn = curfn;
-	curfn = nil;
-	funchdr(fn);
-	
-	a = nod(n->op, N, N);
-	a->list = printargs;
-	typecheck(&a, Etop);
-	walkstmt(&a);
-	
-	fn->nbody = list1(a);
-
-	funcbody(fn);
-	
-	typecheck(&fn, Etop);
-	typechecklist(fn->nbody, Etop);
-	xtop = list(xtop, fn);
-	curfn = oldfn;
-
-	a = nod(OCALL, N, N);
-	a->left = fn->nname;
-	a->list = n->list;
-	typecheck(&a, Etop);
-	walkexpr(&a, init);
-	*np = a;
-}
diff --git a/src/cmd/gc/y.tab.c b/src/cmd/gc/y.tab.c
deleted file mode 100644
index f464126..0000000
--- a/src/cmd/gc/y.tab.c
+++ /dev/null
@@ -1,5132 +0,0 @@
-/* A Bison parser, made by GNU Bison 2.3.  */
-
-/* Skeleton implementation for Bison's Yacc-like parsers in C
-
-   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
-   Free Software Foundation, Inc.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
-   any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301, USA.  */
-
-/* As a special exception, you may create a larger work that contains
-   part or all of the Bison parser skeleton and distribute that work
-   under terms of your choice, so long as that work isn't itself a
-   parser generator using the skeleton or a modified version thereof
-   as a parser skeleton.  Alternatively, if you modify or redistribute
-   the parser skeleton itself, you may (at your option) remove this
-   special exception, which will cause the skeleton and the resulting
-   Bison output files to be licensed under the GNU General Public
-   License without this special exception.
-
-   This special exception was added by the Free Software Foundation in
-   version 2.2 of Bison.  */
-
-/* C LALR(1) parser skeleton written by Richard Stallman, by
-   simplifying the original so-called "semantic" parser.  */
-
-/* All symbols defined below should begin with yy or YY, to avoid
-   infringing on user name space.  This should be done even for local
-   variables, as they might otherwise be expanded by user macros.
-   There are some unavoidable exceptions within include files to
-   define necessary library symbols; they are noted "INFRINGES ON
-   USER NAME SPACE" below.  */
-
-/* Identify Bison output.  */
-#define YYBISON 1
-
-/* Bison version.  */
-#define YYBISON_VERSION "2.3"
-
-/* Skeleton name.  */
-#define YYSKELETON_NAME "yacc.c"
-
-/* Pure parsers.  */
-#define YYPURE 0
-
-/* Using locations.  */
-#define YYLSP_NEEDED 0
-
-
-
-/* Tokens.  */
-#ifndef YYTOKENTYPE
-# define YYTOKENTYPE
-   /* Put the tokens into the symbol table, so that GDB and other debuggers
-      know about them.  */
-   enum yytokentype {
-     LLITERAL = 258,
-     LASOP = 259,
-     LCOLAS = 260,
-     LBREAK = 261,
-     LCASE = 262,
-     LCHAN = 263,
-     LCONST = 264,
-     LCONTINUE = 265,
-     LDDD = 266,
-     LDEFAULT = 267,
-     LDEFER = 268,
-     LELSE = 269,
-     LFALL = 270,
-     LFOR = 271,
-     LFUNC = 272,
-     LGO = 273,
-     LGOTO = 274,
-     LIF = 275,
-     LIMPORT = 276,
-     LINTERFACE = 277,
-     LMAP = 278,
-     LNAME = 279,
-     LPACKAGE = 280,
-     LRANGE = 281,
-     LRETURN = 282,
-     LSELECT = 283,
-     LSTRUCT = 284,
-     LSWITCH = 285,
-     LTYPE = 286,
-     LVAR = 287,
-     LANDAND = 288,
-     LANDNOT = 289,
-     LBODY = 290,
-     LCOMM = 291,
-     LDEC = 292,
-     LEQ = 293,
-     LGE = 294,
-     LGT = 295,
-     LIGNORE = 296,
-     LINC = 297,
-     LLE = 298,
-     LLSH = 299,
-     LLT = 300,
-     LNE = 301,
-     LOROR = 302,
-     LRSH = 303,
-     NotPackage = 304,
-     NotParen = 305,
-     PreferToRightParen = 306
-   };
-#endif
-/* Tokens.  */
-#define LLITERAL 258
-#define LASOP 259
-#define LCOLAS 260
-#define LBREAK 261
-#define LCASE 262
-#define LCHAN 263
-#define LCONST 264
-#define LCONTINUE 265
-#define LDDD 266
-#define LDEFAULT 267
-#define LDEFER 268
-#define LELSE 269
-#define LFALL 270
-#define LFOR 271
-#define LFUNC 272
-#define LGO 273
-#define LGOTO 274
-#define LIF 275
-#define LIMPORT 276
-#define LINTERFACE 277
-#define LMAP 278
-#define LNAME 279
-#define LPACKAGE 280
-#define LRANGE 281
-#define LRETURN 282
-#define LSELECT 283
-#define LSTRUCT 284
-#define LSWITCH 285
-#define LTYPE 286
-#define LVAR 287
-#define LANDAND 288
-#define LANDNOT 289
-#define LBODY 290
-#define LCOMM 291
-#define LDEC 292
-#define LEQ 293
-#define LGE 294
-#define LGT 295
-#define LIGNORE 296
-#define LINC 297
-#define LLE 298
-#define LLSH 299
-#define LLT 300
-#define LNE 301
-#define LOROR 302
-#define LRSH 303
-#define NotPackage 304
-#define NotParen 305
-#define PreferToRightParen 306
-
-
-
-
-/* Copy the first part of user declarations.  */
-#line 20 "go.y"
-
-#include <u.h>
-#include <stdio.h>	/* if we don't, bison will, and go.h re-#defines getc */
-#include <libc.h>
-#include "go.h"
-
-static void fixlbrace(int);
-
-
-/* Enabling traces.  */
-#ifndef YYDEBUG
-# define YYDEBUG 0
-#endif
-
-/* Enabling verbose error messages.  */
-#ifdef YYERROR_VERBOSE
-# undef YYERROR_VERBOSE
-# define YYERROR_VERBOSE 1
-#else
-# define YYERROR_VERBOSE 1
-#endif
-
-/* Enabling the token table.  */
-#ifndef YYTOKEN_TABLE
-# define YYTOKEN_TABLE 0
-#endif
-
-#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-typedef union YYSTYPE
-#line 28 "go.y"
-{
-	Node*		node;
-	NodeList*		list;
-	Type*		type;
-	Sym*		sym;
-	struct	Val	val;
-	int		i;
-}
-/* Line 193 of yacc.c.  */
-#line 216 "y.tab.c"
-	YYSTYPE;
-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
-# define YYSTYPE_IS_DECLARED 1
-# define YYSTYPE_IS_TRIVIAL 1
-#endif
-
-
-
-/* Copy the second part of user declarations.  */
-
-
-/* Line 216 of yacc.c.  */
-#line 229 "y.tab.c"
-
-#ifdef short
-# undef short
-#endif
-
-#ifdef YYTYPE_UINT8
-typedef YYTYPE_UINT8 yytype_uint8;
-#else
-typedef unsigned char yytype_uint8;
-#endif
-
-#ifdef YYTYPE_INT8
-typedef YYTYPE_INT8 yytype_int8;
-#elif (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-typedef signed char yytype_int8;
-#else
-typedef short int yytype_int8;
-#endif
-
-#ifdef YYTYPE_UINT16
-typedef YYTYPE_UINT16 yytype_uint16;
-#else
-typedef unsigned short int yytype_uint16;
-#endif
-
-#ifdef YYTYPE_INT16
-typedef YYTYPE_INT16 yytype_int16;
-#else
-typedef short int yytype_int16;
-#endif
-
-#ifndef YYSIZE_T
-# ifdef __SIZE_TYPE__
-#  define YYSIZE_T __SIZE_TYPE__
-# elif defined size_t
-#  define YYSIZE_T size_t
-# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
-#  define YYSIZE_T size_t
-# else
-#  define YYSIZE_T unsigned int
-# endif
-#endif
-
-#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
-
-#ifndef YY_
-# if defined YYENABLE_NLS && YYENABLE_NLS
-#  if ENABLE_NLS
-#   include <libintl.h> /* INFRINGES ON USER NAME SPACE */
-#   define YY_(msgid) dgettext ("bison-runtime", msgid)
-#  endif
-# endif
-# ifndef YY_
-#  define YY_(msgid) msgid
-# endif
-#endif
-
-/* Suppress unused-variable warnings by "using" E.  */
-#if ! defined lint || defined __GNUC__
-# define YYUSE(e) ((void) (e))
-#else
-# define YYUSE(e) /* empty */
-#endif
-
-/* Identity function, used to suppress warnings about constant conditions.  */
-#ifndef lint
-# define YYID(n) (n)
-#else
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static int
-YYID (int i)
-#else
-static int
-YYID (i)
-    int i;
-#endif
-{
-  return i;
-}
-#endif
-
-#if ! defined yyoverflow || YYERROR_VERBOSE
-
-/* The parser invokes alloca or malloc; define the necessary symbols.  */
-
-# ifdef YYSTACK_USE_ALLOCA
-#  if YYSTACK_USE_ALLOCA
-#   ifdef __GNUC__
-#    define YYSTACK_ALLOC __builtin_alloca
-#   elif defined __BUILTIN_VA_ARG_INCR
-#    include <alloca.h> /* INFRINGES ON USER NAME SPACE */
-#   elif defined _AIX
-#    define YYSTACK_ALLOC __alloca
-#   elif defined _MSC_VER
-#    include <malloc.h> /* INFRINGES ON USER NAME SPACE */
-#    define alloca _alloca
-#   else
-#    define YYSTACK_ALLOC alloca
-#    if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-#     include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-#     ifndef _STDLIB_H
-#      define _STDLIB_H 1
-#     endif
-#    endif
-#   endif
-#  endif
-# endif
-
-# ifdef YYSTACK_ALLOC
-   /* Pacify GCC's `empty if-body' warning.  */
-#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
-#  ifndef YYSTACK_ALLOC_MAXIMUM
-    /* The OS might guarantee only one guard page at the bottom of the stack,
-       and a page size can be as small as 4096 bytes.  So we cannot safely
-       invoke alloca (N) if N exceeds 4096.  Use a slightly smaller number
-       to allow for a few compiler-allocated temporary stack slots.  */
-#   define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
-#  endif
-# else
-#  define YYSTACK_ALLOC YYMALLOC
-#  define YYSTACK_FREE YYFREE
-#  ifndef YYSTACK_ALLOC_MAXIMUM
-#   define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
-#  endif
-#  if (defined __cplusplus && ! defined _STDLIB_H \
-       && ! ((defined YYMALLOC || defined malloc) \
-	     && (defined YYFREE || defined free)))
-#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-#   ifndef _STDLIB_H
-#    define _STDLIB_H 1
-#   endif
-#  endif
-#  ifndef YYMALLOC
-#   define YYMALLOC malloc
-#   if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
-#   endif
-#  endif
-#  ifndef YYFREE
-#   define YYFREE free
-#   if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-void free (void *); /* INFRINGES ON USER NAME SPACE */
-#   endif
-#  endif
-# endif
-#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
-
-
-#if (! defined yyoverflow \
-     && (! defined __cplusplus \
-	 || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
-
-/* A type that is properly aligned for any stack member.  */
-union yyalloc
-{
-  yytype_int16 yyss;
-  YYSTYPE yyvs;
-  };
-
-/* The size of the maximum gap between one aligned stack and the next.  */
-# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
-
-/* The size of an array large to enough to hold all stacks, each with
-   N elements.  */
-# define YYSTACK_BYTES(N) \
-     ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
-      + YYSTACK_GAP_MAXIMUM)
-
-/* Copy COUNT objects from FROM to TO.  The source and destination do
-   not overlap.  */
-# ifndef YYCOPY
-#  if defined __GNUC__ && 1 < __GNUC__
-#   define YYCOPY(To, From, Count) \
-      __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
-#  else
-#   define YYCOPY(To, From, Count)		\
-      do					\
-	{					\
-	  YYSIZE_T yyi;				\
-	  for (yyi = 0; yyi < (Count); yyi++)	\
-	    (To)[yyi] = (From)[yyi];		\
-	}					\
-      while (YYID (0))
-#  endif
-# endif
-
-/* Relocate STACK from its old location to the new one.  The
-   local variables YYSIZE and YYSTACKSIZE give the old and new number of
-   elements in the stack, and YYPTR gives the new location of the
-   stack.  Advance YYPTR to a properly aligned location for the next
-   stack.  */
-# define YYSTACK_RELOCATE(Stack)					\
-    do									\
-      {									\
-	YYSIZE_T yynewbytes;						\
-	YYCOPY (&yyptr->Stack, Stack, yysize);				\
-	Stack = &yyptr->Stack;						\
-	yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
-	yyptr += yynewbytes / sizeof (*yyptr);				\
-      }									\
-    while (YYID (0))
-
-#endif
-
-/* YYFINAL -- State number of the termination state.  */
-#define YYFINAL  4
-/* YYLAST -- Last index in YYTABLE.  */
-#define YYLAST   2201
-
-/* YYNTOKENS -- Number of terminals.  */
-#define YYNTOKENS  76
-/* YYNNTS -- Number of nonterminals.  */
-#define YYNNTS  142
-/* YYNRULES -- Number of rules.  */
-#define YYNRULES  352
-/* YYNRULES -- Number of states.  */
-#define YYNSTATES  669
-
-/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
-#define YYUNDEFTOK  2
-#define YYMAXUTOK   306
-
-#define YYTRANSLATE(YYX)						\
-  ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
-
-/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX.  */
-static const yytype_uint8 yytranslate[] =
-{
-       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,    69,     2,     2,    64,    55,    56,     2,
-      59,    60,    53,    49,    75,    50,    63,    54,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,    66,    62,
-       2,    65,     2,    73,    74,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,    71,     2,    72,    52,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,    67,    51,    68,    70,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
-       5,     6,     7,     8,     9,    10,    11,    12,    13,    14,
-      15,    16,    17,    18,    19,    20,    21,    22,    23,    24,
-      25,    26,    27,    28,    29,    30,    31,    32,    33,    34,
-      35,    36,    37,    38,    39,    40,    41,    42,    43,    44,
-      45,    46,    47,    48,    57,    58,    61
-};
-
-#if YYDEBUG
-/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
-   YYRHS.  */
-static const yytype_uint16 yyprhs[] =
-{
-       0,     0,     3,     8,     9,    13,    14,    18,    19,    23,
-      26,    32,    36,    40,    43,    45,    49,    51,    54,    57,
-      62,    63,    65,    66,    71,    72,    74,    76,    78,    80,
-      83,    89,    93,    96,   102,   110,   114,   117,   123,   127,
-     129,   132,   137,   141,   146,   150,   152,   155,   157,   159,
-     162,   164,   168,   172,   176,   179,   182,   186,   192,   198,
-     201,   202,   207,   208,   212,   213,   216,   217,   222,   227,
-     232,   235,   241,   243,   245,   248,   249,   253,   255,   259,
-     260,   261,   262,   271,   272,   278,   279,   282,   283,   286,
-     287,   288,   296,   297,   303,   305,   309,   313,   317,   321,
-     325,   329,   333,   337,   341,   345,   349,   353,   357,   361,
-     365,   369,   373,   377,   381,   385,   387,   390,   393,   396,
-     399,   402,   405,   408,   411,   415,   421,   428,   430,   432,
-     436,   442,   448,   453,   460,   469,   471,   477,   483,   489,
-     497,   499,   500,   504,   506,   511,   513,   518,   520,   524,
-     526,   528,   530,   532,   534,   536,   538,   539,   541,   543,
-     545,   547,   552,   557,   559,   561,   563,   566,   568,   570,
-     572,   574,   576,   580,   582,   584,   586,   589,   591,   593,
-     595,   597,   601,   603,   605,   607,   609,   611,   613,   615,
-     617,   619,   623,   628,   633,   636,   640,   646,   648,   650,
-     653,   657,   663,   667,   673,   677,   681,   687,   696,   702,
-     711,   717,   718,   722,   723,   725,   729,   731,   736,   739,
-     740,   744,   746,   750,   752,   756,   758,   762,   764,   768,
-     770,   774,   778,   781,   786,   790,   796,   802,   804,   808,
-     810,   813,   815,   819,   824,   826,   829,   832,   834,   836,
-     840,   841,   844,   845,   847,   849,   851,   853,   855,   857,
-     859,   861,   863,   864,   869,   871,   874,   877,   880,   883,
-     886,   889,   891,   895,   897,   901,   903,   907,   909,   913,
-     915,   919,   921,   923,   927,   931,   932,   935,   936,   938,
-     939,   941,   942,   944,   945,   947,   948,   950,   951,   953,
-     954,   956,   957,   959,   960,   962,   967,   972,   978,   985,
-     990,   995,   997,   999,  1001,  1003,  1005,  1007,  1009,  1011,
-    1013,  1017,  1022,  1028,  1033,  1038,  1041,  1044,  1049,  1053,
-    1057,  1063,  1067,  1072,  1076,  1082,  1084,  1085,  1087,  1091,
-    1093,  1095,  1098,  1100,  1102,  1108,  1109,  1112,  1114,  1118,
-    1120,  1124,  1126
-};
-
-/* YYRHS -- A `-1'-separated list of the rules' RHS.  */
-static const yytype_int16 yyrhs[] =
-{
-      77,     0,    -1,    79,    78,    81,   166,    -1,    -1,    25,
-     141,    62,    -1,    -1,    80,    86,    88,    -1,    -1,    81,
-      82,    62,    -1,    21,    83,    -1,    21,    59,    84,   190,
-      60,    -1,    21,    59,    60,    -1,    85,    86,    88,    -1,
-      85,    88,    -1,    83,    -1,    84,    62,    83,    -1,     3,
-      -1,   141,     3,    -1,    63,     3,    -1,    25,    24,    87,
-      62,    -1,    -1,    24,    -1,    -1,    89,   214,    64,    64,
-      -1,    -1,    91,    -1,   158,    -1,   181,    -1,     1,    -1,
-      32,    93,    -1,    32,    59,   167,   190,    60,    -1,    32,
-      59,    60,    -1,    92,    94,    -1,    92,    59,    94,   190,
-      60,    -1,    92,    59,    94,    62,   168,   190,    60,    -1,
-      92,    59,    60,    -1,    31,    97,    -1,    31,    59,   169,
-     190,    60,    -1,    31,    59,    60,    -1,     9,    -1,   185,
-     146,    -1,   185,   146,    65,   186,    -1,   185,    65,   186,
-      -1,   185,   146,    65,   186,    -1,   185,    65,   186,    -1,
-      94,    -1,   185,   146,    -1,   185,    -1,   141,    -1,    96,
-     146,    -1,   126,    -1,   126,     4,   126,    -1,   186,    65,
-     186,    -1,   186,     5,   186,    -1,   126,    42,    -1,   126,
-      37,    -1,     7,   187,    66,    -1,     7,   187,    65,   126,
-      66,    -1,     7,   187,     5,   126,    66,    -1,    12,    66,
-      -1,    -1,    67,   101,   183,    68,    -1,    -1,    99,   103,
-     183,    -1,    -1,   104,   102,    -1,    -1,    35,   106,   183,
-      68,    -1,   186,    65,    26,   126,    -1,   186,     5,    26,
-     126,    -1,    26,   126,    -1,   194,    62,   194,    62,   194,
-      -1,   194,    -1,   107,    -1,   108,   105,    -1,    -1,    16,
-     111,   109,    -1,   194,    -1,   194,    62,   194,    -1,    -1,
-      -1,    -1,    20,   114,   112,   115,   105,   116,   119,   120,
-      -1,    -1,    14,    20,   118,   112,   105,    -1,    -1,   119,
-     117,    -1,    -1,    14,   100,    -1,    -1,    -1,    30,   122,
-     112,   123,    35,   104,    68,    -1,    -1,    28,   125,    35,
-     104,    68,    -1,   127,    -1,   126,    47,   126,    -1,   126,
-      33,   126,    -1,   126,    38,   126,    -1,   126,    46,   126,
-      -1,   126,    45,   126,    -1,   126,    43,   126,    -1,   126,
-      39,   126,    -1,   126,    40,   126,    -1,   126,    49,   126,
-      -1,   126,    50,   126,    -1,   126,    51,   126,    -1,   126,
-      52,   126,    -1,   126,    53,   126,    -1,   126,    54,   126,
-      -1,   126,    55,   126,    -1,   126,    56,   126,    -1,   126,
-      34,   126,    -1,   126,    44,   126,    -1,   126,    48,   126,
-      -1,   126,    36,   126,    -1,   134,    -1,    53,   127,    -1,
-      56,   127,    -1,    49,   127,    -1,    50,   127,    -1,    69,
-     127,    -1,    70,   127,    -1,    52,   127,    -1,    36,   127,
-      -1,   134,    59,    60,    -1,   134,    59,   187,   191,    60,
-      -1,   134,    59,   187,    11,   191,    60,    -1,     3,    -1,
-     143,    -1,   134,    63,   141,    -1,   134,    63,    59,   135,
-      60,    -1,   134,    63,    59,    31,    60,    -1,   134,    71,
-     126,    72,    -1,   134,    71,   192,    66,   192,    72,    -1,
-     134,    71,   192,    66,   192,    66,   192,    72,    -1,   128,
-      -1,   149,    59,   126,   191,    60,    -1,   150,   137,   130,
-     189,    68,    -1,   129,    67,   130,   189,    68,    -1,    59,
-     135,    60,    67,   130,   189,    68,    -1,   165,    -1,    -1,
-     126,    66,   133,    -1,   126,    -1,    67,   130,   189,    68,
-      -1,   126,    -1,    67,   130,   189,    68,    -1,   129,    -1,
-      59,   135,    60,    -1,   126,    -1,   147,    -1,   146,    -1,
-      35,    -1,    67,    -1,   141,    -1,   141,    -1,    -1,   138,
-      -1,    24,    -1,   142,    -1,    73,    -1,    74,     3,    63,
-      24,    -1,    74,     3,    63,    73,    -1,   141,    -1,   138,
-      -1,    11,    -1,    11,   146,    -1,   155,    -1,   161,    -1,
-     153,    -1,   154,    -1,   152,    -1,    59,   146,    60,    -1,
-     155,    -1,   161,    -1,   153,    -1,    53,   147,    -1,   161,
-      -1,   153,    -1,   154,    -1,   152,    -1,    59,   146,    60,
-      -1,   161,    -1,   153,    -1,   153,    -1,   155,    -1,   161,
-      -1,   153,    -1,   154,    -1,   152,    -1,   143,    -1,   143,
-      63,   141,    -1,    71,   192,    72,   146,    -1,    71,    11,
-      72,   146,    -1,     8,   148,    -1,     8,    36,   146,    -1,
-      23,    71,   146,    72,   146,    -1,   156,    -1,   157,    -1,
-      53,   146,    -1,    36,     8,   146,    -1,    29,   137,   170,
-     190,    68,    -1,    29,   137,    68,    -1,    22,   137,   171,
-     190,    68,    -1,    22,   137,    68,    -1,    17,   159,   162,
-      -1,   141,    59,   179,    60,   163,    -1,    59,   179,    60,
-     141,    59,   179,    60,   163,    -1,   200,    59,   195,    60,
-     210,    -1,    59,   215,    60,   141,    59,   195,    60,   210,
-      -1,    17,    59,   179,    60,   163,    -1,    -1,    67,   183,
-      68,    -1,    -1,   151,    -1,    59,   179,    60,    -1,   161,
-      -1,   164,   137,   183,    68,    -1,   164,     1,    -1,    -1,
-     166,    90,    62,    -1,    93,    -1,   167,    62,    93,    -1,
-      95,    -1,   168,    62,    95,    -1,    97,    -1,   169,    62,
-      97,    -1,   172,    -1,   170,    62,   172,    -1,   175,    -1,
-     171,    62,   175,    -1,   184,   146,   198,    -1,   174,   198,
-      -1,    59,   174,    60,   198,    -1,    53,   174,   198,    -1,
-      59,    53,   174,    60,   198,    -1,    53,    59,   174,    60,
-     198,    -1,    24,    -1,    24,    63,   141,    -1,   173,    -1,
-     138,   176,    -1,   173,    -1,    59,   173,    60,    -1,    59,
-     179,    60,   163,    -1,   136,    -1,   141,   136,    -1,   141,
-     145,    -1,   145,    -1,   177,    -1,   178,    75,   177,    -1,
-      -1,   178,   191,    -1,    -1,   100,    -1,    91,    -1,   181,
-      -1,     1,    -1,    98,    -1,   110,    -1,   121,    -1,   124,
-      -1,   113,    -1,    -1,   144,    66,   182,   180,    -1,    15,
-      -1,     6,   140,    -1,    10,   140,    -1,    18,   128,    -1,
-      13,   128,    -1,    19,   138,    -1,    27,   193,    -1,   180,
-      -1,   183,    62,   180,    -1,   138,    -1,   184,    75,   138,
-      -1,   139,    -1,   185,    75,   139,    -1,   126,    -1,   186,
-      75,   126,    -1,   135,    -1,   187,    75,   135,    -1,   131,
-      -1,   132,    -1,   188,    75,   131,    -1,   188,    75,   132,
-      -1,    -1,   188,   191,    -1,    -1,    62,    -1,    -1,    75,
-      -1,    -1,   126,    -1,    -1,   186,    -1,    -1,    98,    -1,
-      -1,   215,    -1,    -1,   216,    -1,    -1,   217,    -1,    -1,
-       3,    -1,    21,    24,     3,    62,    -1,    32,   200,   202,
-      62,    -1,     9,   200,    65,   213,    62,    -1,     9,   200,
-     202,    65,   213,    62,    -1,    31,   201,   202,    62,    -1,
-      17,   160,   162,    62,    -1,   142,    -1,   200,    -1,   204,
-      -1,   205,    -1,   206,    -1,   204,    -1,   206,    -1,   142,
-      -1,    24,    -1,    71,    72,   202,    -1,    71,     3,    72,
-     202,    -1,    23,    71,   202,    72,   202,    -1,    29,    67,
-     196,    68,    -1,    22,    67,   197,    68,    -1,    53,   202,
-      -1,     8,   203,    -1,     8,    59,   205,    60,    -1,     8,
-      36,   202,    -1,    36,     8,   202,    -1,    17,    59,   195,
-      60,   210,    -1,   141,   202,   198,    -1,   141,    11,   202,
-     198,    -1,   141,   202,   198,    -1,   141,    59,   195,    60,
-     210,    -1,   202,    -1,    -1,   211,    -1,    59,   195,    60,
-      -1,   202,    -1,     3,    -1,    50,     3,    -1,   141,    -1,
-     212,    -1,    59,   212,    49,   212,    60,    -1,    -1,   214,
-     199,    -1,   207,    -1,   215,    75,   207,    -1,   208,    -1,
-     216,    62,   208,    -1,   209,    -1,   217,    62,   209,    -1
-};
-
-/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
-static const yytype_uint16 yyrline[] =
-{
-       0,   124,   124,   133,   139,   150,   150,   165,   166,   169,
-     170,   171,   174,   211,   222,   223,   226,   233,   240,   249,
-     263,   264,   271,   271,   284,   288,   289,   293,   298,   304,
-     308,   312,   316,   322,   328,   334,   339,   343,   347,   353,
-     359,   363,   367,   373,   377,   383,   384,   388,   394,   403,
-     409,   427,   432,   444,   460,   466,   474,   494,   512,   521,
-     540,   539,   554,   553,   585,   588,   595,   594,   605,   611,
-     618,   625,   636,   642,   645,   653,   652,   663,   669,   681,
-     685,   690,   680,   711,   710,   723,   726,   732,   735,   747,
-     751,   746,   769,   768,   784,   785,   789,   793,   797,   801,
-     805,   809,   813,   817,   821,   825,   829,   833,   837,   841,
-     845,   849,   853,   857,   862,   868,   869,   873,   884,   888,
-     892,   896,   901,   905,   915,   919,   924,   932,   936,   937,
-     948,   952,   956,   960,   964,   972,   973,   979,   986,   992,
-     999,  1002,  1009,  1015,  1032,  1039,  1040,  1047,  1048,  1067,
-    1068,  1071,  1074,  1078,  1089,  1098,  1104,  1107,  1110,  1117,
-    1118,  1124,  1137,  1152,  1160,  1172,  1177,  1183,  1184,  1185,
-    1186,  1187,  1188,  1194,  1195,  1196,  1197,  1203,  1204,  1205,
-    1206,  1207,  1213,  1214,  1217,  1220,  1221,  1222,  1223,  1224,
-    1227,  1228,  1241,  1245,  1250,  1255,  1260,  1264,  1265,  1268,
-    1274,  1281,  1287,  1294,  1300,  1311,  1326,  1355,  1393,  1418,
-    1436,  1445,  1448,  1456,  1460,  1464,  1471,  1477,  1482,  1494,
-    1497,  1508,  1509,  1515,  1516,  1522,  1526,  1532,  1533,  1539,
-    1543,  1549,  1572,  1577,  1583,  1589,  1596,  1605,  1614,  1629,
-    1635,  1640,  1644,  1651,  1664,  1665,  1671,  1677,  1680,  1684,
-    1690,  1693,  1702,  1705,  1706,  1710,  1711,  1717,  1718,  1719,
-    1720,  1721,  1723,  1722,  1737,  1743,  1747,  1751,  1755,  1759,
-    1764,  1783,  1789,  1797,  1801,  1807,  1811,  1817,  1821,  1827,
-    1831,  1840,  1844,  1848,  1852,  1858,  1861,  1869,  1870,  1872,
-    1873,  1876,  1879,  1882,  1885,  1888,  1891,  1894,  1897,  1900,
-    1903,  1906,  1909,  1912,  1915,  1921,  1925,  1929,  1933,  1937,
-    1941,  1961,  1968,  1979,  1980,  1981,  1984,  1985,  1988,  1992,
-    2002,  2006,  2010,  2014,  2018,  2022,  2026,  2032,  2038,  2046,
-    2054,  2060,  2067,  2083,  2105,  2109,  2115,  2118,  2121,  2125,
-    2135,  2139,  2158,  2166,  2167,  2179,  2180,  2183,  2187,  2193,
-    2197,  2203,  2207
-};
-#endif
-
-#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
-/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
-   First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
-const char *yytname[] =
-{
-  "$end", "error", "$undefined", "LLITERAL", "LASOP", "LCOLAS", "LBREAK",
-  "LCASE", "LCHAN", "LCONST", "LCONTINUE", "LDDD", "LDEFAULT", "LDEFER",
-  "LELSE", "LFALL", "LFOR", "LFUNC", "LGO", "LGOTO", "LIF", "LIMPORT",
-  "LINTERFACE", "LMAP", "LNAME", "LPACKAGE", "LRANGE", "LRETURN",
-  "LSELECT", "LSTRUCT", "LSWITCH", "LTYPE", "LVAR", "LANDAND", "LANDNOT",
-  "LBODY", "LCOMM", "LDEC", "LEQ", "LGE", "LGT", "LIGNORE", "LINC", "LLE",
-  "LLSH", "LLT", "LNE", "LOROR", "LRSH", "'+'", "'-'", "'|'", "'^'", "'*'",
-  "'/'", "'%'", "'&'", "NotPackage", "NotParen", "'('", "')'",
-  "PreferToRightParen", "';'", "'.'", "'$'", "'='", "':'", "'{'", "'}'",
-  "'!'", "'~'", "'['", "']'", "'?'", "'@'", "','", "$accept", "file",
-  "package", "loadsys", "@1", "imports", "import", "import_stmt",
-  "import_stmt_list", "import_here", "import_package", "import_safety",
-  "import_there", "@2", "xdcl", "common_dcl", "lconst", "vardcl",
-  "constdcl", "constdcl1", "typedclname", "typedcl", "simple_stmt", "case",
-  "compound_stmt", "@3", "caseblock", "@4", "caseblock_list", "loop_body",
-  "@5", "range_stmt", "for_header", "for_body", "for_stmt", "@6",
-  "if_header", "if_stmt", "@7", "@8", "@9", "elseif", "@10", "elseif_list",
-  "else", "switch_stmt", "@11", "@12", "select_stmt", "@13", "expr",
-  "uexpr", "pseudocall", "pexpr_no_paren", "start_complit", "keyval",
-  "bare_complitexpr", "complitexpr", "pexpr", "expr_or_type",
-  "name_or_type", "lbrace", "new_name", "dcl_name", "onew_name", "sym",
-  "hidden_importsym", "name", "labelname", "dotdotdot", "ntype",
-  "non_expr_type", "non_recvchantype", "convtype", "comptype",
-  "fnret_type", "dotname", "othertype", "ptrtype", "recvchantype",
-  "structtype", "interfacetype", "xfndcl", "fndcl", "hidden_fndcl",
-  "fntype", "fnbody", "fnres", "fnlitdcl", "fnliteral", "xdcl_list",
-  "vardcl_list", "constdcl_list", "typedcl_list", "structdcl_list",
-  "interfacedcl_list", "structdcl", "packname", "embed", "interfacedcl",
-  "indcl", "arg_type", "arg_type_list", "oarg_type_list_ocomma", "stmt",
-  "non_dcl_stmt", "@14", "stmt_list", "new_name_list", "dcl_name_list",
-  "expr_list", "expr_or_type_list", "keyval_list", "braced_keyval_list",
-  "osemi", "ocomma", "oexpr", "oexpr_list", "osimple_stmt",
-  "ohidden_funarg_list", "ohidden_structdcl_list",
-  "ohidden_interfacedcl_list", "oliteral", "hidden_import",
-  "hidden_pkg_importsym", "hidden_pkgtype", "hidden_type",
-  "hidden_type_non_recv_chan", "hidden_type_misc", "hidden_type_recv_chan",
-  "hidden_type_func", "hidden_funarg", "hidden_structdcl",
-  "hidden_interfacedcl", "ohidden_funres", "hidden_funres",
-  "hidden_literal", "hidden_constant", "hidden_import_list",
-  "hidden_funarg_list", "hidden_structdcl_list",
-  "hidden_interfacedcl_list", 0
-};
-#endif
-
-# ifdef YYPRINT
-/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
-   token YYLEX-NUM.  */
-static const yytype_uint16 yytoknum[] =
-{
-       0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
-     265,   266,   267,   268,   269,   270,   271,   272,   273,   274,
-     275,   276,   277,   278,   279,   280,   281,   282,   283,   284,
-     285,   286,   287,   288,   289,   290,   291,   292,   293,   294,
-     295,   296,   297,   298,   299,   300,   301,   302,   303,    43,
-      45,   124,    94,    42,    47,    37,    38,   304,   305,    40,
-      41,   306,    59,    46,    36,    61,    58,   123,   125,    33,
-     126,    91,    93,    63,    64,    44
-};
-# endif
-
-/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
-static const yytype_uint8 yyr1[] =
-{
-       0,    76,    77,    78,    78,    80,    79,    81,    81,    82,
-      82,    82,    83,    83,    84,    84,    85,    85,    85,    86,
-      87,    87,    89,    88,    90,    90,    90,    90,    90,    91,
-      91,    91,    91,    91,    91,    91,    91,    91,    91,    92,
-      93,    93,    93,    94,    94,    95,    95,    95,    96,    97,
-      98,    98,    98,    98,    98,    98,    99,    99,    99,    99,
-     101,   100,   103,   102,   104,   104,   106,   105,   107,   107,
-     107,   108,   108,   108,   109,   111,   110,   112,   112,   114,
-     115,   116,   113,   118,   117,   119,   119,   120,   120,   122,
-     123,   121,   125,   124,   126,   126,   126,   126,   126,   126,
-     126,   126,   126,   126,   126,   126,   126,   126,   126,   126,
-     126,   126,   126,   126,   126,   127,   127,   127,   127,   127,
-     127,   127,   127,   127,   128,   128,   128,   129,   129,   129,
-     129,   129,   129,   129,   129,   129,   129,   129,   129,   129,
-     129,   130,   131,   132,   132,   133,   133,   134,   134,   135,
-     135,   136,   137,   137,   138,   139,   140,   140,   141,   141,
-     141,   142,   142,   143,   144,   145,   145,   146,   146,   146,
-     146,   146,   146,   147,   147,   147,   147,   148,   148,   148,
-     148,   148,   149,   149,   150,   151,   151,   151,   151,   151,
-     152,   152,   153,   153,   153,   153,   153,   153,   153,   154,
-     155,   156,   156,   157,   157,   158,   159,   159,   160,   160,
-     161,   162,   162,   163,   163,   163,   164,   165,   165,   166,
-     166,   167,   167,   168,   168,   169,   169,   170,   170,   171,
-     171,   172,   172,   172,   172,   172,   172,   173,   173,   174,
-     175,   175,   175,   176,   177,   177,   177,   177,   178,   178,
-     179,   179,   180,   180,   180,   180,   180,   181,   181,   181,
-     181,   181,   182,   181,   181,   181,   181,   181,   181,   181,
-     181,   183,   183,   184,   184,   185,   185,   186,   186,   187,
-     187,   188,   188,   188,   188,   189,   189,   190,   190,   191,
-     191,   192,   192,   193,   193,   194,   194,   195,   195,   196,
-     196,   197,   197,   198,   198,   199,   199,   199,   199,   199,
-     199,   200,   201,   202,   202,   202,   203,   203,   204,   204,
-     204,   204,   204,   204,   204,   204,   204,   204,   204,   205,
-     206,   207,   207,   208,   209,   209,   210,   210,   211,   211,
-     212,   212,   212,   213,   213,   214,   214,   215,   215,   216,
-     216,   217,   217
-};
-
-/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
-static const yytype_uint8 yyr2[] =
-{
-       0,     2,     4,     0,     3,     0,     3,     0,     3,     2,
-       5,     3,     3,     2,     1,     3,     1,     2,     2,     4,
-       0,     1,     0,     4,     0,     1,     1,     1,     1,     2,
-       5,     3,     2,     5,     7,     3,     2,     5,     3,     1,
-       2,     4,     3,     4,     3,     1,     2,     1,     1,     2,
-       1,     3,     3,     3,     2,     2,     3,     5,     5,     2,
-       0,     4,     0,     3,     0,     2,     0,     4,     4,     4,
-       2,     5,     1,     1,     2,     0,     3,     1,     3,     0,
-       0,     0,     8,     0,     5,     0,     2,     0,     2,     0,
-       0,     7,     0,     5,     1,     3,     3,     3,     3,     3,
-       3,     3,     3,     3,     3,     3,     3,     3,     3,     3,
-       3,     3,     3,     3,     3,     1,     2,     2,     2,     2,
-       2,     2,     2,     2,     3,     5,     6,     1,     1,     3,
-       5,     5,     4,     6,     8,     1,     5,     5,     5,     7,
-       1,     0,     3,     1,     4,     1,     4,     1,     3,     1,
-       1,     1,     1,     1,     1,     1,     0,     1,     1,     1,
-       1,     4,     4,     1,     1,     1,     2,     1,     1,     1,
-       1,     1,     3,     1,     1,     1,     2,     1,     1,     1,
-       1,     3,     1,     1,     1,     1,     1,     1,     1,     1,
-       1,     3,     4,     4,     2,     3,     5,     1,     1,     2,
-       3,     5,     3,     5,     3,     3,     5,     8,     5,     8,
-       5,     0,     3,     0,     1,     3,     1,     4,     2,     0,
-       3,     1,     3,     1,     3,     1,     3,     1,     3,     1,
-       3,     3,     2,     4,     3,     5,     5,     1,     3,     1,
-       2,     1,     3,     4,     1,     2,     2,     1,     1,     3,
-       0,     2,     0,     1,     1,     1,     1,     1,     1,     1,
-       1,     1,     0,     4,     1,     2,     2,     2,     2,     2,
-       2,     1,     3,     1,     3,     1,     3,     1,     3,     1,
-       3,     1,     1,     3,     3,     0,     2,     0,     1,     0,
-       1,     0,     1,     0,     1,     0,     1,     0,     1,     0,
-       1,     0,     1,     0,     1,     4,     4,     5,     6,     4,
-       4,     1,     1,     1,     1,     1,     1,     1,     1,     1,
-       3,     4,     5,     4,     4,     2,     2,     4,     3,     3,
-       5,     3,     4,     3,     5,     1,     0,     1,     3,     1,
-       1,     2,     1,     1,     5,     0,     2,     1,     3,     1,
-       3,     1,     3
-};
-
-/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state
-   STATE-NUM when YYTABLE doesn't specify something else to do.  Zero
-   means the default is an error.  */
-static const yytype_uint16 yydefact[] =
-{
-       5,     0,     3,     0,     1,     0,     7,     0,    22,   158,
-     160,     0,     0,   159,   219,    20,     6,   345,     0,     4,
-       0,     0,     0,    21,     0,     0,     0,    16,     0,     0,
-       9,    22,     0,     8,    28,   127,   156,     0,    39,   156,
-       0,   264,    75,     0,     0,     0,    79,     0,     0,   293,
-      92,     0,    89,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,   291,     0,    25,     0,   257,   258,
-     261,   259,   260,    50,    94,   135,   147,   115,   164,   163,
-     128,     0,     0,     0,   184,   197,   198,    26,   216,     0,
-     140,    27,     0,    19,     0,     0,     0,     0,     0,     0,
-     346,   161,   162,    11,    14,   287,    18,    22,    13,    17,
-     157,   265,   154,     0,     0,     0,     0,   163,   190,   194,
-     180,   178,   179,   177,   266,   135,     0,   295,   250,     0,
-     211,   135,   269,   295,   152,   153,     0,     0,   277,   294,
-     270,     0,     0,   295,     0,     0,    36,    48,     0,    29,
-     275,   155,     0,   123,   118,   119,   122,   116,   117,     0,
-       0,   149,     0,   150,   175,   173,   174,   120,   121,     0,
-     292,     0,   220,     0,    32,     0,     0,     0,     0,     0,
-      55,     0,     0,     0,    54,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,     0,   141,
-       0,     0,   291,   262,     0,   141,   218,     0,     0,     0,
-       0,   311,     0,     0,   211,     0,     0,   312,     0,     0,
-      23,   288,     0,    12,   250,     0,     0,   195,   171,   169,
-     170,   167,   168,   199,     0,     0,     0,   296,    73,     0,
-      76,     0,    72,   165,   244,   163,   247,   151,   248,   289,
-       0,   250,     0,   205,    80,    77,   158,     0,   204,     0,
-     287,   241,   229,     0,    64,     0,     0,   202,   273,   287,
-     227,   239,   303,     0,    90,    38,   225,   287,    49,    31,
-     221,   287,     0,     0,    40,     0,   176,   148,     0,     0,
-      35,   287,     0,     0,    51,    96,   111,   114,    97,   101,
-     102,   100,   112,    99,    98,    95,   113,   103,   104,   105,
-     106,   107,   108,   109,   110,   285,   124,   279,   289,     0,
-     129,   292,     0,     0,   289,   285,   256,    60,   254,   253,
-     271,   255,     0,    53,    52,   278,     0,     0,     0,     0,
-     319,     0,     0,     0,     0,     0,   318,     0,   313,   314,
-     315,     0,   347,     0,     0,   297,     0,     0,     0,    15,
-      10,     0,     0,     0,   181,   191,    70,    66,    74,     0,
-       0,   295,   166,   245,   246,   290,   251,   213,     0,     0,
-       0,   295,     0,   237,     0,   250,   240,   288,     0,     0,
-       0,     0,   303,     0,     0,   288,     0,   304,   232,     0,
-     303,     0,   288,     0,   288,     0,    42,   276,     0,     0,
-       0,   200,   171,   169,   170,   168,   141,   193,   192,   288,
-       0,    44,     0,   141,   143,   281,   282,   289,     0,   289,
-     290,     0,     0,     0,   132,   291,   263,   290,     0,     0,
-       0,     0,   217,     0,     0,   326,   316,   317,   297,   301,
-       0,   299,     0,   325,   340,     0,     0,   342,   343,     0,
-       0,     0,     0,     0,   303,     0,     0,   310,     0,   298,
-     305,   309,   306,   213,   172,     0,     0,     0,     0,   249,
-     250,   163,   214,   189,   187,   188,   185,   186,   210,   213,
-     212,    81,    78,   238,   242,     0,   230,   203,   196,     0,
-       0,    93,    62,    65,     0,   234,     0,   303,   228,   201,
-     274,   231,    64,   226,    37,   222,    30,    41,     0,   285,
-      45,   223,   287,    47,    33,    43,   285,     0,   290,   286,
-     138,     0,   280,   125,   131,   130,     0,   136,   137,     0,
-     272,   328,     0,     0,   319,     0,   318,     0,   335,   351,
-     302,     0,     0,     0,   349,   300,   329,   341,     0,   307,
-       0,   320,     0,   303,   331,     0,   348,   336,     0,    69,
-      68,   295,     0,   250,   206,    85,   213,     0,    59,     0,
-     303,   303,   233,     0,   172,     0,   288,     0,    46,     0,
-     141,   145,   142,   283,   284,   126,   291,   133,    61,   327,
-     336,   297,   324,     0,     0,   303,   323,     0,     0,   321,
-     308,   332,   297,   297,   339,   208,   337,    67,    71,   215,
-       0,    87,   243,     0,     0,    56,     0,    63,   236,   235,
-      91,   139,   224,    34,   144,   285,     0,   330,     0,   352,
-     322,   333,   350,     0,     0,     0,   213,     0,    86,    82,
-       0,     0,     0,   134,   336,   344,   336,   338,   207,    83,
-      88,    58,    57,   146,   334,   209,   295,     0,    84
-};
-
-/* YYDEFGOTO[NTERM-NUM].  */
-static const yytype_int16 yydefgoto[] =
-{
-      -1,     1,     6,     2,     3,    14,    21,    30,   105,    31,
-       8,    24,    16,    17,    65,   328,    67,   149,   520,   521,
-     145,   146,    68,   502,   329,   440,   503,   579,   390,   368,
-     475,   238,   239,   240,    69,   127,   254,    70,   133,   380,
-     575,   648,   666,   621,   649,    71,   143,   401,    72,   141,
-      73,    74,    75,    76,   315,   425,   426,   592,    77,   317,
-     244,   136,    78,   150,   111,   117,    13,    80,    81,   246,
-     247,   163,   119,    82,    83,   482,   228,    84,   230,   231,
-      85,    86,    87,   130,   214,    88,   253,   488,    89,    90,
-      22,   281,   522,   277,   269,   260,   270,   271,   272,   262,
-     386,   248,   249,   250,   330,   331,   323,   332,   273,   152,
-      92,   318,   427,   428,   222,   376,   171,   140,   255,   468,
-     553,   547,   398,   100,   212,   218,   614,   445,   348,   349,
-     350,   352,   554,   549,   615,   616,   458,   459,    25,   469,
-     555,   550
-};
-
-/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
-   STATE-NUM.  */
-#define YYPACT_NINF -473
-static const yytype_int16 yypact[] =
-{
-    -473,    65,    22,    49,  -473,   261,  -473,    64,  -473,  -473,
-    -473,    95,    52,  -473,   143,   145,  -473,  -473,   104,  -473,
-      68,   128,  1049,  -473,   142,   305,    16,  -473,    56,   204,
-    -473,    49,   220,  -473,  -473,  -473,   261,   974,  -473,   261,
-     562,  -473,  -473,   288,   562,   261,  -473,    14,   147,  1615,
-    -473,    14,  -473,   395,   401,  1615,  1615,  1615,  1615,  1615,
-    1615,  1658,  1615,  1615,   737,   168,  -473,   414,  -473,  -473,
-    -473,  -473,  -473,   649,  -473,  -473,   165,   122,  -473,   169,
-    -473,   177,   218,    14,   219,  -473,  -473,  -473,   235,    89,
-    -473,  -473,    34,  -473,   206,   124,   286,   206,   206,   260,
-    -473,  -473,  -473,  -473,  -473,   265,  -473,  -473,  -473,  -473,
-    -473,  -473,  -473,   270,  1803,  1803,  1803,  -473,   269,  -473,
-    -473,  -473,  -473,  -473,  -473,    39,   122,   882,  1777,   283,
-     277,   230,  -473,  1615,  -473,  -473,   292,  1803,  2097,   280,
-    -473,   332,   315,  1615,   215,  1803,  -473,  -473,   244,  -473,
-    -473,  -473,   949,  -473,  -473,  -473,  -473,  -473,  -473,  1701,
-    1658,  2097,   298,  -473,     9,  -473,    59,  -473,  -473,   303,
-    2097,   319,  -473,   330,  -473,  1744,  1615,  1615,  1615,  1615,
-    -473,  1615,  1615,  1615,  -473,  1615,  1615,  1615,  1615,  1615,
-    1615,  1615,  1615,  1615,  1615,  1615,  1615,  1615,  1615,  -473,
-    1297,   455,  1615,  -473,  1615,  -473,  -473,  1225,  1615,  1615,
-    1615,  -473,   594,   261,   277,   328,   403,  -473,  1308,  1308,
-    -473,   152,   352,  -473,  1777,   405,  1803,  -473,  -473,  -473,
-    -473,  -473,  -473,  -473,   354,   261,  1615,  -473,  -473,   382,
-    -473,    47,   360,  1803,  -473,  1777,  -473,  -473,  -473,   351,
-     367,  1777,  1225,  -473,  -473,   366,    84,   407,  -473,   374,
-     373,  -473,  -473,   372,  -473,   138,    42,  -473,  -473,   377,
-    -473,  -473,   442,  1769,  -473,  -473,  -473,   384,  -473,  -473,
-    -473,   389,  1615,   261,   391,  1830,  -473,   394,  1803,  1803,
-    -473,   409,  1615,   411,  2097,  1935,  -473,  2121,  1080,  1080,
-    1080,  1080,  -473,  1080,  1080,  2145,  -473,   503,   503,   503,
-     503,  -473,  -473,  -473,  -473,  1352,  -473,  -473,    27,  1407,
-    -473,  1995,   412,  1147,  1962,  1352,  -473,  -473,  -473,  -473,
-    -473,  -473,     7,   280,   280,  2097,   698,   418,   415,   413,
-    -473,   416,   477,  1308,   188,    31,  -473,   425,  -473,  -473,
-    -473,  1897,  -473,   221,   433,   261,   434,   436,   439,  -473,
-    -473,   432,  1803,   452,  -473,  -473,  2097,  -473,  -473,  1462,
-    1517,  1615,  -473,  -473,  -473,  1777,  -473,  1856,   453,    91,
-     382,  1615,   261,   454,   456,  1777,  -473,   475,   451,  1803,
-     133,   407,   442,   407,   460,   326,   462,  -473,  -473,   261,
-     442,   467,   261,   478,   261,   486,   280,  -473,  1615,  1864,
-    1803,  -473,    26,   248,   264,   430,  -473,  -473,  -473,   261,
-     492,   280,  1615,  -473,  2025,  -473,  -473,   485,   493,   487,
-    1658,   504,   506,   508,  -473,  1615,  -473,  -473,   512,   505,
-    1225,  1147,  -473,  1308,   517,  -473,  -473,  -473,   261,  1889,
-    1308,   261,  1308,  -473,  -473,   571,   155,  -473,  -473,   514,
-     509,  1308,   188,  1308,   442,   261,   261,  -473,   518,   507,
-    -473,  -473,  -473,  1856,  -473,  1225,  1615,  1615,   521,  -473,
-    1777,   528,  -473,  -473,  -473,  -473,  -473,  -473,  -473,  1856,
-    -473,  -473,  -473,  -473,  -473,   520,  -473,  -473,  -473,  1658,
-     522,  -473,  -473,  -473,   530,  -473,   532,   442,  -473,  -473,
-    -473,  -473,  -473,  -473,  -473,  -473,  -473,   280,   535,  1352,
-    -473,  -473,   536,  1744,  -473,   280,  1352,  1560,  1352,  -473,
-    -473,   539,  -473,  -473,  -473,  -473,   247,  -473,  -473,   308,
-    -473,  -473,   541,   543,   545,   546,   547,   544,  -473,  -473,
-     551,   548,  1308,   554,  -473,   557,  -473,  -473,   576,  -473,
-    1308,  -473,   564,   442,  -473,   568,  -473,  1923,   318,  2097,
-    2097,  1615,   569,  1777,  -473,  -473,  1856,   156,  -473,  1147,
-     442,   442,  -473,   243,   483,   563,   261,   577,   411,   570,
-    -473,  2097,  -473,  -473,  -473,  -473,  1615,  -473,  -473,  -473,
-    1923,   261,  -473,  1889,  1308,   442,  -473,   261,   155,  -473,
-    -473,  -473,   261,   261,  -473,  -473,  -473,  -473,  -473,  -473,
-     579,   627,  -473,  1615,  1615,  -473,  1658,   580,  -473,  -473,
-    -473,  -473,  -473,  -473,  -473,  1352,   572,  -473,   583,  -473,
-    -473,  -473,  -473,   585,   586,   590,  1856,    77,  -473,  -473,
-    2049,  2073,   584,  -473,  1923,  -473,  1923,  -473,  -473,  -473,
-    -473,  -473,  -473,  -473,  -473,  -473,  1615,   382,  -473
-};
-
-/* YYPGOTO[NTERM-NUM].  */
-static const yytype_int16 yypgoto[] =
-{
-    -473,  -473,  -473,  -473,  -473,  -473,  -473,   -12,  -473,  -473,
-     624,  -473,    -1,  -473,  -473,   635,  -473,  -137,   -48,    74,
-    -473,  -130,  -112,  -473,    11,  -473,  -473,  -473,   149,  -372,
-    -473,  -473,  -473,  -473,  -473,  -473,  -140,  -473,  -473,  -473,
-    -473,  -473,  -473,  -473,  -473,  -473,  -473,  -473,  -473,  -473,
-     662,   448,   257,  -473,  -196,   135,   139,  -473,   262,   -59,
-     424,   -16,    -3,   387,   632,   427,   313,    20,  -473,   428,
-     -89,   524,  -473,  -473,  -473,  -473,   -36,   -37,   -31,   -49,
-    -473,  -473,  -473,  -473,  -473,   -32,   458,  -472,  -473,  -473,
-    -473,  -473,  -473,  -473,  -473,  -473,   279,  -108,  -211,   290,
-    -473,   306,  -473,  -214,  -291,   658,  -473,  -230,  -473,   -63,
-      -6,   191,  -473,  -302,  -219,  -254,  -195,  -473,  -107,  -435,
-    -473,  -473,  -347,  -473,   323,  -473,    72,  -473,   371,   268,
-     380,   242,   102,   110,  -468,  -473,  -438,   255,  -473,   515,
-    -473,  -473
-};
-
-/* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
-   positive, shift that token.  If negative, reduce the rule which
-   number is the opposite.  If zero, do what YYDEFACT says.
-   If YYTABLE_NINF, syntax error.  */
-#define YYTABLE_NINF -278
-static const yytype_int16 yytable[] =
-{
-     121,   120,   162,   274,   175,   123,   122,   322,   491,   325,
-     361,   280,   165,   543,   276,   237,   104,   574,   558,   174,
-     242,   237,   379,   439,   164,   227,   233,   234,   261,   166,
-     108,   237,   436,   110,   460,   142,   110,   378,   429,   208,
-     101,   388,   132,   139,  -184,   505,  -268,     5,   263,   134,
-     396,  -268,   369,   511,   392,   394,   278,   118,   403,    27,
-    -216,  -180,   405,   284,   431,     4,   383,   205,  -183,   441,
-     438,    27,   420,   207,     7,   442,  -184,   229,   229,   229,
-       9,   135,   232,   232,   232,  -180,   293,  -237,    15,   102,
-     206,   229,     9,  -180,  -216,   393,   232,   659,    18,   209,
-     229,  -268,   430,   461,   622,   232,   223,  -268,   229,   210,
-     175,   165,   370,   232,    19,   229,   103,   564,  -182,    29,
-     232,   241,   210,   164,   134,   291,  -216,    28,   166,    10,
-      11,    29,   637,   259,   118,   118,   118,   363,   229,   268,
-     499,    10,    11,   232,   327,   500,  -237,   382,   118,   384,
-     540,   165,  -237,   441,   372,    27,   135,   118,   454,   490,
-     582,   623,   383,   164,    20,   118,   638,    26,   166,    23,
-     643,   495,   118,   529,   658,   531,     9,   644,   645,     9,
-     504,   200,   506,   213,   400,   201,   664,   229,   665,   229,
-      33,   454,   232,   202,   232,   118,   411,   391,    11,   417,
-     418,   501,   333,   334,    93,   455,   229,   106,   229,   359,
-     539,   232,     9,   232,   229,    29,   611,   585,   137,   232,
-     519,   624,   625,   109,   589,    10,    11,   526,    10,    11,
-     172,   626,   199,   628,   629,  -154,   229,  -267,   455,     9,
-     536,   232,  -267,   203,   118,   568,   118,   456,   413,   412,
-     499,   229,   229,   415,   414,   500,   232,   232,   641,   237,
-     433,    10,    11,   118,   478,   118,   572,   515,     9,   237,
-     165,   118,   513,   411,   492,   275,   406,   204,  -183,   261,
-      11,   465,   164,  -178,   347,     9,   421,   166,    10,    11,
-     357,   358,  -267,   118,  -182,   668,   466,   125,  -267,  -179,
-     498,   131,   126,   587,   279,   118,   126,  -178,   118,   118,
-     216,   630,     9,   596,    94,  -178,   256,    10,    11,   597,
-     227,   518,    95,  -179,   220,   229,    96,   221,   486,   224,
-     232,  -179,   235,   652,    10,    11,    97,    98,   229,   256,
-     484,   483,   251,   232,   252,   487,   485,   128,   229,   627,
-     256,   257,   229,   232,     9,   210,   523,   232,   287,   620,
-     258,    10,    11,   333,   334,    10,    11,   264,   265,    99,
-     441,   532,   229,   229,   266,   288,   598,   232,   232,   265,
-     441,   165,   118,   267,   259,   266,   617,   355,    10,    11,
-     290,   289,   268,   164,   635,   118,   510,   118,   166,    10,
-      11,   636,   517,    10,    11,   118,   356,   211,   211,   118,
-     211,   211,   360,   362,   364,   453,   525,   367,   215,     9,
-     217,   219,   371,   464,   486,     9,   375,   377,   381,   118,
-     118,   383,    12,   385,   588,   387,   484,   483,     9,   395,
-     486,   487,   485,   229,   389,   397,   402,    32,   232,    79,
-     165,   404,   484,   483,   144,    32,   408,   487,   485,   237,
-     148,   416,   164,   112,   618,  -177,   112,   166,    10,    11,
-     129,   419,   112,   173,    10,    11,   422,   448,   435,     9,
-     147,   151,   449,   451,   450,   452,   229,    10,    11,  -177,
-     462,   232,   473,   118,   151,   467,   470,  -177,   471,   256,
-     118,   472,   512,   153,   154,   155,   156,   157,   158,   118,
-     167,   168,   474,   489,   319,   541,   494,   382,  -181,   497,
-     507,   548,   551,   523,   556,   346,   667,   486,    10,    11,
-     509,   346,   346,   561,   257,   563,   229,   178,   514,   484,
-     483,   232,  -181,   118,   487,   485,   516,   186,    10,    11,
-    -181,   190,   524,   342,   237,   245,   195,   196,   197,   198,
-     528,   530,   437,   112,   533,    35,   534,   532,   535,   112,
-      37,   147,   537,   538,   557,   151,   559,   165,   567,   113,
-     576,   560,   466,   571,    47,    48,     9,   573,   578,   164,
-     580,    51,   581,   118,   166,   584,   118,   486,   586,   595,
-     151,   599,   336,   600,  -158,   601,  -159,   153,   157,   484,
-     483,   337,   602,   603,   487,   485,   338,   339,   340,   607,
-     604,    61,   606,   341,   605,   608,   610,   612,   320,   619,
-     342,   631,   609,    64,    79,    10,    11,   633,   634,   646,
-     351,   647,   441,   654,   653,   655,   656,   343,    32,   346,
-     657,   245,   663,   176,  -277,   107,   346,    66,   660,   344,
-     632,   583,   365,   593,   346,   345,   118,   594,    11,   373,
-     407,   124,   354,   374,   508,   548,   640,   496,   245,    79,
-      91,   479,   177,   178,   286,   179,   180,   181,   182,   183,
-     577,   184,   185,   186,   187,   188,   189,   190,   191,   192,
-     193,   194,   195,   196,   197,   198,   336,   446,   566,   642,
-     151,   138,   542,   639,  -277,   337,   447,   562,     0,     0,
-     338,   339,   340,   161,  -277,     0,   170,   341,   353,     0,
-       0,     0,     0,     0,   443,     0,     0,     0,     0,     0,
-      35,     0,     0,     0,     0,    37,     0,     0,   169,     0,
-      79,   343,     0,     0,   113,     0,   346,   444,     0,    47,
-      48,     9,   546,   346,     0,   346,    51,     0,     0,   345,
-       0,   457,    11,    55,   346,     0,   346,     0,     0,     0,
-       0,     0,   351,     0,     0,     0,    56,    57,     0,    58,
-      59,     0,     0,    60,     0,     0,    61,     0,     0,     0,
-       0,     0,   245,     0,   481,     0,    62,    63,    64,   493,
-      10,    11,   245,     0,   112,     0,     0,     0,     0,     0,
-       0,     0,   112,     0,     0,     0,   112,     0,     0,   147,
-       0,   151,     0,     0,     0,     0,     0,     0,   294,   295,
-     296,   297,     0,   298,   299,   300,   151,   301,   302,   303,
-     304,   305,   306,   307,   308,   309,   310,   311,   312,   313,
-     314,     0,   161,     0,   321,   346,   324,    79,    79,     0,
-     138,   138,   335,   346,     0,   351,   545,     0,   552,     0,
-     346,     0,     0,   457,     0,    35,     0,     0,     0,   457,
-      37,     0,   565,   351,     0,     0,     0,     0,   366,   113,
-       0,     0,    79,     0,    47,    48,     9,   245,   236,     0,
-       0,    51,     0,   346,     0,     0,   546,   346,    55,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,    56,    57,     0,    58,    59,     0,     0,    60,     0,
-       0,    61,     0,     0,   138,     0,     0,     0,     0,     0,
-       0,    62,    63,    64,   138,    10,    11,    37,     0,     0,
-       0,     0,     0,     0,     0,     0,   113,   346,     0,   346,
-       0,    47,    48,     9,     0,     0,     0,   424,    51,     0,
-       0,   161,    37,     0,     0,   225,     0,   424,     0,     0,
-       0,   113,     0,     0,     0,     0,    47,    48,     9,     0,
-     245,     0,   115,    51,     0,     0,    79,     0,   226,     0,
-     114,     0,     0,   151,   282,     0,     0,     0,     0,     0,
-      64,     0,    10,    11,   283,     0,     0,   115,   351,     0,
-     545,   138,   138,   116,   552,   457,     0,     0,     0,   351,
-     351,     0,     0,     0,     0,    64,     0,    10,    11,    -2,
-      34,     0,    35,     0,     0,    36,     0,    37,    38,    39,
-       0,     0,    40,     0,    41,    42,    43,    44,    45,    46,
-     138,    47,    48,     9,     0,     0,    49,    50,    51,    52,
-      53,    54,     0,     0,   138,    55,     0,     0,     0,     0,
-       0,     0,   161,     0,     0,     0,     0,   170,    56,    57,
-       0,    58,    59,     0,     0,    60,     0,     0,    61,     0,
-       0,   -24,     0,     0,   178,     0,     0,     0,    62,    63,
-      64,     0,    10,    11,   186,     0,     0,     0,   190,   191,
-     192,   193,   194,   195,   196,   197,   198,     0,   569,   570,
-       0,     0,     0,     0,     0,     0,     0,     0,   326,     0,
-      35,     0,     0,    36,  -252,    37,    38,    39,     0,  -252,
-      40,   161,    41,    42,   113,    44,    45,    46,     0,    47,
-      48,     9,     0,     0,    49,    50,    51,    52,    53,    54,
-       0,   424,     0,    55,     0,     0,     0,     0,   424,   591,
-     424,     0,     0,     0,     0,     0,    56,    57,     0,    58,
-      59,     0,     0,    60,     0,     0,    61,     0,     0,  -252,
-       0,     0,     0,     0,   327,  -252,    62,    63,    64,     0,
-      10,    11,     0,     0,     0,     0,   326,     0,    35,     0,
-       0,    36,     0,    37,    38,    39,     0,     0,    40,     0,
-      41,    42,   113,    44,    45,    46,     0,    47,    48,     9,
-       0,     0,    49,    50,    51,    52,    53,    54,   170,     0,
-       0,    55,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,    56,    57,     0,    58,    59,     0,
-       0,    60,     0,     0,    61,   650,   651,  -252,   161,     0,
-       0,     0,   327,  -252,    62,    63,    64,   424,    10,    11,
-      35,     0,     0,     0,     0,    37,     0,     0,     0,     0,
-       0,     0,     0,     0,   113,     0,   336,     0,     0,    47,
-      48,     9,     0,     0,     0,   337,    51,     0,     0,     0,
-     338,   339,   340,   159,     0,     0,     0,   341,     0,     0,
-       0,     0,     0,     0,   342,     0,    56,    57,     0,    58,
-     160,     0,     0,    60,     0,    35,    61,   316,     0,     0,
-      37,   343,     0,     0,     0,     0,    62,    63,    64,   113,
-      10,    11,     0,     0,    47,    48,     9,     0,     0,   345,
-       0,    51,    11,     0,     0,     0,     0,     0,    55,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,    56,    57,     0,    58,    59,     0,     0,    60,     0,
-      35,    61,     0,     0,     0,    37,     0,     0,     0,   423,
-       0,    62,    63,    64,   113,    10,    11,     0,     0,    47,
-      48,     9,     0,     0,     0,     0,    51,     0,   432,     0,
-       0,     0,     0,   159,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,    56,    57,     0,    58,
-     160,     0,     0,    60,     0,    35,    61,     0,     0,     0,
-      37,     0,     0,     0,     0,     0,    62,    63,    64,   113,
-      10,    11,     0,     0,    47,    48,     9,     0,   476,     0,
-       0,    51,     0,     0,     0,     0,     0,     0,    55,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,    56,    57,     0,    58,    59,     0,     0,    60,     0,
-      35,    61,     0,     0,     0,    37,     0,     0,     0,     0,
-       0,    62,    63,    64,   113,    10,    11,     0,     0,    47,
-      48,     9,     0,   477,     0,     0,    51,     0,     0,     0,
-       0,     0,     0,    55,     0,     0,     0,     0,     0,     0,
-       0,     0,     0,    35,     0,     0,    56,    57,    37,    58,
-      59,     0,     0,    60,     0,     0,    61,   113,     0,     0,
-       0,     0,    47,    48,     9,     0,    62,    63,    64,    51,
-      10,    11,     0,     0,     0,     0,    55,     0,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,     0,    56,
-      57,     0,    58,    59,     0,     0,    60,     0,    35,    61,
-       0,     0,     0,    37,     0,     0,     0,   590,     0,    62,
-      63,    64,   113,    10,    11,     0,     0,    47,    48,     9,
-       0,     0,     0,     0,    51,     0,     0,     0,     0,     0,
-       0,    55,     0,     0,     0,     0,     0,     0,     0,     0,
-       0,    35,     0,     0,    56,    57,    37,    58,    59,     0,
-       0,    60,     0,     0,    61,   113,     0,     0,     0,     0,
-      47,    48,     9,     0,    62,    63,    64,    51,    10,    11,
-       0,     0,     0,     0,   159,     0,     0,     0,     0,     0,
-       0,     0,     0,     0,    35,     0,     0,    56,    57,   285,
-      58,   160,     0,     0,    60,     0,     0,    61,   113,     0,
-       0,     0,     0,    47,    48,     9,     0,    62,    63,    64,
-      51,    10,    11,     0,     0,     0,     0,    55,     0,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,     0,     0,
-      56,    57,    37,    58,    59,     0,     0,    60,     0,     0,
-      61,   113,     0,     0,     0,     0,    47,    48,     9,     0,
-      62,    63,    64,    51,    10,    11,     0,    37,     0,     0,
-     225,     0,     0,     0,     0,    37,   113,     0,   243,     0,
-       0,    47,    48,     9,   113,     0,     0,   115,    51,    47,
-      48,     9,     0,   226,     0,   225,    51,     0,     0,   292,
-       0,    37,     0,   225,     0,    64,     0,    10,    11,   283,
-     113,     0,   115,     0,     0,    47,    48,     9,   226,     0,
-     115,     0,    51,     0,     0,     0,   226,     0,    37,   225,
-      64,     0,    10,    11,   399,     0,     0,   113,    64,     0,
-      10,    11,    47,    48,     9,     0,   115,     0,     0,    51,
-       0,     0,   226,     0,    37,     0,   409,     0,     0,     0,
-       0,     0,   285,   113,    64,     0,    10,    11,    47,    48,
-       9,   113,     0,   115,     0,    51,    47,    48,     9,   410,
-       0,     0,   225,    51,     0,     0,     0,   336,     0,     0,
-     225,    64,     0,    10,    11,   336,   337,     0,   463,   115,
-       0,   338,   339,   544,   337,   480,     0,   115,   341,   338,
-     339,   340,     0,   226,     0,   342,   341,    64,     0,    10,
-      11,   336,     0,   342,     0,    64,     0,    10,    11,     0,
-     337,     0,   343,     0,     0,   338,   339,   340,     0,     0,
-     343,     0,   341,     0,     0,     0,     0,     0,     0,   342,
-     345,     0,    10,    11,     0,     0,     0,     0,   345,   178,
-       0,    11,     0,   181,   182,   183,   343,     0,   185,   186,
-     187,   188,   613,   190,   191,   192,   193,   194,   195,   196,
-     197,   198,     0,     0,   345,   177,   178,    11,   179,     0,
-     181,   182,   183,     0,     0,   185,   186,   187,   188,   189,
-     190,   191,   192,   193,   194,   195,   196,   197,   198,     0,
-       0,     0,     0,     0,     0,     0,     0,     0,   177,   178,
-       0,   179,     0,   181,   182,   183,     0,   437,   185,   186,
-     187,   188,   189,   190,   191,   192,   193,   194,   195,   196,
-     197,   198,     0,     0,     0,     0,     0,     0,   177,   178,
-       0,   179,     0,   181,   182,   183,     0,   434,   185,   186,
-     187,   188,   189,   190,   191,   192,   193,   194,   195,   196,
-     197,   198,   177,   178,     0,   179,     0,   181,   182,   183,
-       0,   527,   185,   186,   187,   188,   189,   190,   191,   192,
-     193,   194,   195,   196,   197,   198,   177,   178,     0,   179,
-       0,   181,   182,   183,     0,   661,   185,   186,   187,   188,
-     189,   190,   191,   192,   193,   194,   195,   196,   197,   198,
-     177,   178,     0,   179,     0,   181,   182,   183,     0,   662,
-     185,   186,   187,   188,   189,   190,   191,   192,   193,   194,
-     195,   196,   197,   198,   177,   178,     0,     0,     0,   181,
-     182,   183,     0,     0,   185,   186,   187,   188,   189,   190,
-     191,   192,   193,   194,   195,   196,   197,   198,   177,   178,
-       0,     0,     0,   181,   182,   183,     0,     0,   185,   186,
-     187,   188,     0,   190,   191,   192,   193,   194,   195,   196,
-     197,   198
-};
-
-static const yytype_int16 yycheck[] =
-{
-      37,    37,    61,   143,    67,    37,    37,   202,   380,   205,
-     224,   148,    61,   448,   144,   127,    28,   489,   456,    67,
-     127,   133,   252,   325,    61,   114,   115,   116,   136,    61,
-      31,   143,   323,    36,     3,    51,    39,   251,    11,     5,
-      24,   260,    45,    49,    35,   392,     7,    25,   137,    35,
-     269,    12,     5,   400,   265,   266,   145,    37,   277,     3,
-       1,    35,   281,   152,   318,     0,    24,    83,    59,    62,
-     324,     3,   291,    89,    25,    68,    67,   114,   115,   116,
-      24,    67,   114,   115,   116,    59,   175,     3,    24,    73,
-       1,   128,    24,    67,    35,    53,   128,    20,     3,    65,
-     137,    62,    75,    72,   576,   137,   107,    68,   145,    75,
-     173,   160,    65,   145,    62,   152,    60,   464,    59,    63,
-     152,   127,    75,   160,    35,   173,    67,    59,   160,    73,
-      74,    63,   600,   136,   114,   115,   116,   226,   175,   142,
-       7,    73,    74,   175,    67,    12,    62,    63,   128,   257,
-     441,   200,    68,    62,   243,     3,    67,   137,     3,    68,
-     507,     5,    24,   200,    21,   145,   601,    63,   200,    24,
-     608,   385,   152,   427,   646,   429,    24,   612,   613,    24,
-     391,    59,   393,    59,   273,    63,   654,   224,   656,   226,
-      62,     3,   224,    71,   226,   175,   285,    59,    74,   288,
-     289,    68,   208,   209,    62,    50,   243,     3,   245,   221,
-     440,   243,    24,   245,   251,    63,   563,   519,    71,   251,
-     416,    65,    66,     3,   526,    73,    74,   423,    73,    74,
-      62,    75,    67,   580,   581,    66,   273,     7,    50,    24,
-     435,   273,    12,    66,   224,   475,   226,    59,   285,   285,
-       7,   288,   289,   285,   285,    12,   288,   289,   605,   371,
-     319,    73,    74,   243,   371,   245,   480,   404,    24,   381,
-     319,   251,   402,   362,   381,    60,   282,    59,    59,   387,
-      74,    60,   319,    35,   212,    24,   292,   319,    73,    74,
-     218,   219,    62,   273,    59,   667,    75,    40,    68,    35,
-     389,    44,    40,   522,    60,   285,    44,    59,   288,   289,
-      24,    68,    24,    66,     9,    67,    24,    73,    74,    72,
-     409,   410,    17,    59,    64,   362,    21,    62,   377,    59,
-     362,    67,    63,   635,    73,    74,    31,    32,   375,    24,
-     377,   377,    59,   375,    67,   377,   377,    59,   385,   579,
-      24,    59,   389,   385,    24,    75,   419,   389,    60,   573,
-      68,    73,    74,   369,   370,    73,    74,    35,    53,    64,
-      62,   430,   409,   410,    59,    72,    68,   409,   410,    53,
-      62,   430,   362,    68,   387,    59,    68,    59,    73,    74,
-      60,    72,   395,   430,   590,   375,   399,   377,   430,    73,
-      74,   596,   408,    73,    74,   385,     3,    94,    95,   389,
-      97,    98,    60,     8,    60,   343,   422,    35,    95,    24,
-      97,    98,    62,   351,   473,    24,    75,    60,    62,   409,
-     410,    24,     5,    59,   523,    62,   473,   473,    24,    62,
-     489,   473,   473,   480,    72,     3,    62,    20,   480,    22,
-     499,    62,   489,   489,    59,    28,    65,   489,   489,   571,
-      59,    67,   499,    36,   571,    35,    39,   499,    73,    74,
-      43,    62,    45,    59,    73,    74,    65,    59,    66,    24,
-      53,    54,    67,    67,    71,     8,   523,    73,    74,    59,
-      65,   523,    60,   473,    67,    62,    62,    67,    62,    24,
-     480,    62,    35,    55,    56,    57,    58,    59,    60,   489,
-      62,    63,    60,    60,    59,   443,    60,    63,    35,    68,
-      60,   449,   450,   586,   452,   212,   666,   576,    73,    74,
-      68,   218,   219,   461,    59,   463,   573,    34,    60,   576,
-     576,   573,    59,   523,   576,   576,    60,    44,    73,    74,
-      67,    48,    60,    36,   666,   128,    53,    54,    55,    56,
-      75,    68,    75,   136,    60,     3,    60,   626,    60,   142,
-       8,   144,    60,    68,     3,   148,    62,   626,    60,    17,
-      60,    72,    75,    62,    22,    23,    24,    59,    66,   626,
-      60,    29,    60,   573,   626,    60,   576,   646,    62,    60,
-     173,    60,     8,    60,    59,    59,    59,   159,   160,   646,
-     646,    17,    68,    62,   646,   646,    22,    23,    24,    62,
-      72,    59,    68,    29,   552,    49,    62,    59,   201,    60,
-      36,    68,   560,    71,   207,    73,    74,    60,    68,    60,
-     213,    14,    62,    60,    72,    60,    60,    53,   221,   336,
-      60,   224,    68,     4,     5,    31,   343,    22,   647,    65,
-     586,   512,   235,   528,   351,    71,   646,   528,    74,   245,
-     283,    39,   214,   245,   395,   603,   604,   387,   251,   252,
-      22,   375,    33,    34,   160,    36,    37,    38,    39,    40,
-     499,    42,    43,    44,    45,    46,    47,    48,    49,    50,
-      51,    52,    53,    54,    55,    56,     8,   336,   466,   607,
-     283,    49,   444,   603,    65,    17,   336,   462,    -1,    -1,
-      22,    23,    24,    61,    75,    -1,    64,    29,   213,    -1,
-      -1,    -1,    -1,    -1,    36,    -1,    -1,    -1,    -1,    -1,
-       3,    -1,    -1,    -1,    -1,     8,    -1,    -1,    11,    -1,
-     323,    53,    -1,    -1,    17,    -1,   443,    59,    -1,    22,
-      23,    24,   449,   450,    -1,   452,    29,    -1,    -1,    71,
-      -1,   344,    74,    36,   461,    -1,   463,    -1,    -1,    -1,
-      -1,    -1,   355,    -1,    -1,    -1,    49,    50,    -1,    52,
-      53,    -1,    -1,    56,    -1,    -1,    59,    -1,    -1,    -1,
-      -1,    -1,   375,    -1,   377,    -1,    69,    70,    71,   382,
-      73,    74,   385,    -1,   387,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,   395,    -1,    -1,    -1,   399,    -1,    -1,   402,
-      -1,   404,    -1,    -1,    -1,    -1,    -1,    -1,   176,   177,
-     178,   179,    -1,   181,   182,   183,   419,   185,   186,   187,
-     188,   189,   190,   191,   192,   193,   194,   195,   196,   197,
-     198,    -1,   200,    -1,   202,   552,   204,   440,   441,    -1,
-     208,   209,   210,   560,    -1,   448,   449,    -1,   451,    -1,
-     567,    -1,    -1,   456,    -1,     3,    -1,    -1,    -1,   462,
-       8,    -1,   465,   466,    -1,    -1,    -1,    -1,   236,    17,
-      -1,    -1,   475,    -1,    22,    23,    24,   480,    26,    -1,
-      -1,    29,    -1,   600,    -1,    -1,   603,   604,    36,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    49,    50,    -1,    52,    53,    -1,    -1,    56,    -1,
-      -1,    59,    -1,    -1,   282,    -1,    -1,    -1,    -1,    -1,
-      -1,    69,    70,    71,   292,    73,    74,     8,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    17,   654,    -1,   656,
-      -1,    22,    23,    24,    -1,    -1,    -1,   315,    29,    -1,
-      -1,   319,     8,    -1,    -1,    36,    -1,   325,    -1,    -1,
-      -1,    17,    -1,    -1,    -1,    -1,    22,    23,    24,    -1,
-     573,    -1,    53,    29,    -1,    -1,   579,    -1,    59,    -1,
-      36,    -1,    -1,   586,    65,    -1,    -1,    -1,    -1,    -1,
-      71,    -1,    73,    74,    75,    -1,    -1,    53,   601,    -1,
-     603,   369,   370,    59,   607,   608,    -1,    -1,    -1,   612,
-     613,    -1,    -1,    -1,    -1,    71,    -1,    73,    74,     0,
-       1,    -1,     3,    -1,    -1,     6,    -1,     8,     9,    10,
-      -1,    -1,    13,    -1,    15,    16,    17,    18,    19,    20,
-     408,    22,    23,    24,    -1,    -1,    27,    28,    29,    30,
-      31,    32,    -1,    -1,   422,    36,    -1,    -1,    -1,    -1,
-      -1,    -1,   430,    -1,    -1,    -1,    -1,   435,    49,    50,
-      -1,    52,    53,    -1,    -1,    56,    -1,    -1,    59,    -1,
-      -1,    62,    -1,    -1,    34,    -1,    -1,    -1,    69,    70,
-      71,    -1,    73,    74,    44,    -1,    -1,    -1,    48,    49,
-      50,    51,    52,    53,    54,    55,    56,    -1,   476,   477,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,     1,    -1,
-       3,    -1,    -1,     6,     7,     8,     9,    10,    -1,    12,
-      13,   499,    15,    16,    17,    18,    19,    20,    -1,    22,
-      23,    24,    -1,    -1,    27,    28,    29,    30,    31,    32,
-      -1,   519,    -1,    36,    -1,    -1,    -1,    -1,   526,   527,
-     528,    -1,    -1,    -1,    -1,    -1,    49,    50,    -1,    52,
-      53,    -1,    -1,    56,    -1,    -1,    59,    -1,    -1,    62,
-      -1,    -1,    -1,    -1,    67,    68,    69,    70,    71,    -1,
-      73,    74,    -1,    -1,    -1,    -1,     1,    -1,     3,    -1,
-      -1,     6,    -1,     8,     9,    10,    -1,    -1,    13,    -1,
-      15,    16,    17,    18,    19,    20,    -1,    22,    23,    24,
-      -1,    -1,    27,    28,    29,    30,    31,    32,   596,    -1,
-      -1,    36,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    49,    50,    -1,    52,    53,    -1,
-      -1,    56,    -1,    -1,    59,   623,   624,    62,   626,    -1,
-      -1,    -1,    67,    68,    69,    70,    71,   635,    73,    74,
-       3,    -1,    -1,    -1,    -1,     8,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    17,    -1,     8,    -1,    -1,    22,
-      23,    24,    -1,    -1,    -1,    17,    29,    -1,    -1,    -1,
-      22,    23,    24,    36,    -1,    -1,    -1,    29,    -1,    -1,
-      -1,    -1,    -1,    -1,    36,    -1,    49,    50,    -1,    52,
-      53,    -1,    -1,    56,    -1,     3,    59,    60,    -1,    -1,
-       8,    53,    -1,    -1,    -1,    -1,    69,    70,    71,    17,
-      73,    74,    -1,    -1,    22,    23,    24,    -1,    -1,    71,
-      -1,    29,    74,    -1,    -1,    -1,    -1,    -1,    36,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    49,    50,    -1,    52,    53,    -1,    -1,    56,    -1,
-       3,    59,    -1,    -1,    -1,     8,    -1,    -1,    -1,    67,
-      -1,    69,    70,    71,    17,    73,    74,    -1,    -1,    22,
-      23,    24,    -1,    -1,    -1,    -1,    29,    -1,    31,    -1,
-      -1,    -1,    -1,    36,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    49,    50,    -1,    52,
-      53,    -1,    -1,    56,    -1,     3,    59,    -1,    -1,    -1,
-       8,    -1,    -1,    -1,    -1,    -1,    69,    70,    71,    17,
-      73,    74,    -1,    -1,    22,    23,    24,    -1,    26,    -1,
-      -1,    29,    -1,    -1,    -1,    -1,    -1,    -1,    36,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    49,    50,    -1,    52,    53,    -1,    -1,    56,    -1,
-       3,    59,    -1,    -1,    -1,     8,    -1,    -1,    -1,    -1,
-      -1,    69,    70,    71,    17,    73,    74,    -1,    -1,    22,
-      23,    24,    -1,    26,    -1,    -1,    29,    -1,    -1,    -1,
-      -1,    -1,    -1,    36,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,     3,    -1,    -1,    49,    50,     8,    52,
-      53,    -1,    -1,    56,    -1,    -1,    59,    17,    -1,    -1,
-      -1,    -1,    22,    23,    24,    -1,    69,    70,    71,    29,
-      73,    74,    -1,    -1,    -1,    -1,    36,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    49,
-      50,    -1,    52,    53,    -1,    -1,    56,    -1,     3,    59,
-      -1,    -1,    -1,     8,    -1,    -1,    -1,    67,    -1,    69,
-      70,    71,    17,    73,    74,    -1,    -1,    22,    23,    24,
-      -1,    -1,    -1,    -1,    29,    -1,    -1,    -1,    -1,    -1,
-      -1,    36,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      -1,     3,    -1,    -1,    49,    50,     8,    52,    53,    -1,
-      -1,    56,    -1,    -1,    59,    17,    -1,    -1,    -1,    -1,
-      22,    23,    24,    -1,    69,    70,    71,    29,    73,    74,
-      -1,    -1,    -1,    -1,    36,    -1,    -1,    -1,    -1,    -1,
-      -1,    -1,    -1,    -1,     3,    -1,    -1,    49,    50,     8,
-      52,    53,    -1,    -1,    56,    -1,    -1,    59,    17,    -1,
-      -1,    -1,    -1,    22,    23,    24,    -1,    69,    70,    71,
-      29,    73,    74,    -1,    -1,    -1,    -1,    36,    -1,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
-      49,    50,     8,    52,    53,    -1,    -1,    56,    -1,    -1,
-      59,    17,    -1,    -1,    -1,    -1,    22,    23,    24,    -1,
-      69,    70,    71,    29,    73,    74,    -1,     8,    -1,    -1,
-      36,    -1,    -1,    -1,    -1,     8,    17,    -1,    11,    -1,
-      -1,    22,    23,    24,    17,    -1,    -1,    53,    29,    22,
-      23,    24,    -1,    59,    -1,    36,    29,    -1,    -1,    65,
-      -1,     8,    -1,    36,    -1,    71,    -1,    73,    74,    75,
-      17,    -1,    53,    -1,    -1,    22,    23,    24,    59,    -1,
-      53,    -1,    29,    -1,    -1,    -1,    59,    -1,     8,    36,
-      71,    -1,    73,    74,    75,    -1,    -1,    17,    71,    -1,
-      73,    74,    22,    23,    24,    -1,    53,    -1,    -1,    29,
-      -1,    -1,    59,    -1,     8,    -1,    36,    -1,    -1,    -1,
-      -1,    -1,     8,    17,    71,    -1,    73,    74,    22,    23,
-      24,    17,    -1,    53,    -1,    29,    22,    23,    24,    59,
-      -1,    -1,    36,    29,    -1,    -1,    -1,     8,    -1,    -1,
-      36,    71,    -1,    73,    74,     8,    17,    -1,    11,    53,
-      -1,    22,    23,    24,    17,    59,    -1,    53,    29,    22,
-      23,    24,    -1,    59,    -1,    36,    29,    71,    -1,    73,
-      74,     8,    -1,    36,    -1,    71,    -1,    73,    74,    -1,
-      17,    -1,    53,    -1,    -1,    22,    23,    24,    -1,    -1,
-      53,    -1,    29,    -1,    -1,    -1,    -1,    -1,    -1,    36,
-      71,    -1,    73,    74,    -1,    -1,    -1,    -1,    71,    34,
-      -1,    74,    -1,    38,    39,    40,    53,    -1,    43,    44,
-      45,    46,    59,    48,    49,    50,    51,    52,    53,    54,
-      55,    56,    -1,    -1,    71,    33,    34,    74,    36,    -1,
-      38,    39,    40,    -1,    -1,    43,    44,    45,    46,    47,
-      48,    49,    50,    51,    52,    53,    54,    55,    56,    -1,
-      -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    33,    34,
-      -1,    36,    -1,    38,    39,    40,    -1,    75,    43,    44,
-      45,    46,    47,    48,    49,    50,    51,    52,    53,    54,
-      55,    56,    -1,    -1,    -1,    -1,    -1,    -1,    33,    34,
-      -1,    36,    -1,    38,    39,    40,    -1,    72,    43,    44,
-      45,    46,    47,    48,    49,    50,    51,    52,    53,    54,
-      55,    56,    33,    34,    -1,    36,    -1,    38,    39,    40,
-      -1,    66,    43,    44,    45,    46,    47,    48,    49,    50,
-      51,    52,    53,    54,    55,    56,    33,    34,    -1,    36,
-      -1,    38,    39,    40,    -1,    66,    43,    44,    45,    46,
-      47,    48,    49,    50,    51,    52,    53,    54,    55,    56,
-      33,    34,    -1,    36,    -1,    38,    39,    40,    -1,    66,
-      43,    44,    45,    46,    47,    48,    49,    50,    51,    52,
-      53,    54,    55,    56,    33,    34,    -1,    -1,    -1,    38,
-      39,    40,    -1,    -1,    43,    44,    45,    46,    47,    48,
-      49,    50,    51,    52,    53,    54,    55,    56,    33,    34,
-      -1,    -1,    -1,    38,    39,    40,    -1,    -1,    43,    44,
-      45,    46,    -1,    48,    49,    50,    51,    52,    53,    54,
-      55,    56
-};
-
-/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
-   symbol of state STATE-NUM.  */
-static const yytype_uint8 yystos[] =
-{
-       0,    77,    79,    80,     0,    25,    78,    25,    86,    24,
-      73,    74,   141,   142,    81,    24,    88,    89,     3,    62,
-      21,    82,   166,    24,    87,   214,    63,     3,    59,    63,
-      83,    85,   141,    62,     1,     3,     6,     8,     9,    10,
-      13,    15,    16,    17,    18,    19,    20,    22,    23,    27,
-      28,    29,    30,    31,    32,    36,    49,    50,    52,    53,
-      56,    59,    69,    70,    71,    90,    91,    92,    98,   110,
-     113,   121,   124,   126,   127,   128,   129,   134,   138,   141,
-     143,   144,   149,   150,   153,   156,   157,   158,   161,   164,
-     165,   181,   186,    62,     9,    17,    21,    31,    32,    64,
-     199,    24,    73,    60,    83,    84,     3,    86,    88,     3,
-     138,   140,   141,    17,    36,    53,    59,   141,   143,   148,
-     152,   153,   154,   161,   140,   128,   134,   111,    59,   141,
-     159,   128,   138,   114,    35,    67,   137,    71,   126,   186,
-     193,   125,   137,   122,    59,    96,    97,   141,    59,    93,
-     139,   141,   185,   127,   127,   127,   127,   127,   127,    36,
-      53,   126,   135,   147,   153,   155,   161,   127,   127,    11,
-     126,   192,    62,    59,    94,   185,     4,    33,    34,    36,
-      37,    38,    39,    40,    42,    43,    44,    45,    46,    47,
-      48,    49,    50,    51,    52,    53,    54,    55,    56,    67,
-      59,    63,    71,    66,    59,   137,     1,   137,     5,    65,
-      75,   142,   200,    59,   160,   200,    24,   200,   201,   200,
-      64,    62,   190,    88,    59,    36,    59,   146,   152,   153,
-     154,   155,   161,   146,   146,    63,    26,    98,   107,   108,
-     109,   186,   194,    11,   136,   141,   145,   146,   177,   178,
-     179,    59,    67,   162,   112,   194,    24,    59,    68,   138,
-     171,   173,   175,   146,    35,    53,    59,    68,   138,   170,
-     172,   173,   174,   184,   112,    60,    97,   169,   146,    60,
-      93,   167,    65,    75,   146,     8,   147,    60,    72,    72,
-      60,    94,    65,   146,   126,   126,   126,   126,   126,   126,
-     126,   126,   126,   126,   126,   126,   126,   126,   126,   126,
-     126,   126,   126,   126,   126,   130,    60,   135,   187,    59,
-     141,   126,   192,   182,   126,   130,     1,    67,    91,   100,
-     180,   181,   183,   186,   186,   126,     8,    17,    22,    23,
-      24,    29,    36,    53,    65,    71,   142,   202,   204,   205,
-     206,   141,   207,   215,   162,    59,     3,   202,   202,    83,
-      60,   179,     8,   146,    60,   141,   126,    35,   105,     5,
-      65,    62,   146,   136,   145,    75,   191,    60,   179,   183,
-     115,    62,    63,    24,   173,    59,   176,    62,   190,    72,
-     104,    59,   174,    53,   174,    62,   190,     3,   198,    75,
-     146,   123,    62,   190,    62,   190,   186,   139,    65,    36,
-      59,   146,   152,   153,   154,   161,    67,   146,   146,    62,
-     190,   186,    65,    67,   126,   131,   132,   188,   189,    11,
-      75,   191,    31,   135,    72,    66,   180,    75,   191,   189,
-     101,    62,    68,    36,    59,   203,   204,   206,    59,    67,
-      71,    67,     8,   202,     3,    50,    59,   141,   212,   213,
-       3,    72,    65,    11,   202,    60,    75,    62,   195,   215,
-      62,    62,    62,    60,    60,   106,    26,    26,   194,   177,
-      59,   141,   151,   152,   153,   154,   155,   161,   163,    60,
-      68,   105,   194,   141,    60,   179,   175,    68,   146,     7,
-      12,    68,    99,   102,   174,   198,   174,    60,   172,    68,
-     138,   198,    35,    97,    60,    93,    60,   186,   146,   130,
-      94,    95,   168,   185,    60,   186,   130,    66,    75,   191,
-      68,   191,   135,    60,    60,    60,   192,    60,    68,   183,
-     180,   202,   205,   195,    24,   141,   142,   197,   202,   209,
-     217,   202,   141,   196,   208,   216,   202,     3,   212,    62,
-      72,   202,   213,   202,   198,   141,   207,    60,   183,   126,
-     126,    62,   179,    59,   163,   116,    60,   187,    66,   103,
-      60,    60,   198,   104,    60,   189,    62,   190,   146,   189,
-      67,   126,   133,   131,   132,    60,    66,    72,    68,    60,
-      60,    59,    68,    62,    72,   202,    68,    62,    49,   202,
-      62,   198,    59,    59,   202,   210,   211,    68,   194,    60,
-     179,   119,   163,     5,    65,    66,    75,   183,   198,   198,
-      68,    68,    95,    60,    68,   130,   192,   210,   195,   209,
-     202,   198,   208,   212,   195,   195,    60,    14,   117,   120,
-     126,   126,   189,    72,    60,    60,    60,    60,   163,    20,
-     100,    66,    66,    68,   210,   210,   118,   112,   105
-};
-
-#define yyerrok		(yyerrstatus = 0)
-#define yyclearin	(yychar = YYEMPTY)
-#define YYEMPTY		(-2)
-#define YYEOF		0
-
-#define YYACCEPT	goto yyacceptlab
-#define YYABORT		goto yyabortlab
-#define YYERROR		goto yyerrorlab
-
-
-/* Like YYERROR except do call yyerror.  This remains here temporarily
-   to ease the transition to the new meaning of YYERROR, for GCC.
-   Once GCC version 2 has supplanted version 1, this can go.  */
-
-#define YYFAIL		goto yyerrlab
-
-#define YYRECOVERING()  (!!yyerrstatus)
-
-#define YYBACKUP(Token, Value)					\
-do								\
-  if (yychar == YYEMPTY && yylen == 1)				\
-    {								\
-      yychar = (Token);						\
-      yylval = (Value);						\
-      yytoken = YYTRANSLATE (yychar);				\
-      YYPOPSTACK (1);						\
-      goto yybackup;						\
-    }								\
-  else								\
-    {								\
-      yyerror (YY_("syntax error: cannot back up")); \
-      YYERROR;							\
-    }								\
-while (YYID (0))
-
-
-#define YYTERROR	1
-#define YYERRCODE	256
-
-
-/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
-   If N is 0, then set CURRENT to the empty location which ends
-   the previous symbol: RHS[0] (always defined).  */
-
-#define YYRHSLOC(Rhs, K) ((Rhs)[K])
-#ifndef YYLLOC_DEFAULT
-# define YYLLOC_DEFAULT(Current, Rhs, N)				\
-    do									\
-      if (YYID (N))                                                    \
-	{								\
-	  (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;	\
-	  (Current).first_column = YYRHSLOC (Rhs, 1).first_column;	\
-	  (Current).last_line    = YYRHSLOC (Rhs, N).last_line;		\
-	  (Current).last_column  = YYRHSLOC (Rhs, N).last_column;	\
-	}								\
-      else								\
-	{								\
-	  (Current).first_line   = (Current).last_line   =		\
-	    YYRHSLOC (Rhs, 0).last_line;				\
-	  (Current).first_column = (Current).last_column =		\
-	    YYRHSLOC (Rhs, 0).last_column;				\
-	}								\
-    while (YYID (0))
-#endif
-
-
-/* YY_LOCATION_PRINT -- Print the location on the stream.
-   This macro was not mandated originally: define only if we know
-   we won't break user code: when these are the locations we know.  */
-
-#ifndef YY_LOCATION_PRINT
-# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL
-#  define YY_LOCATION_PRINT(File, Loc)			\
-     fprintf (File, "%d.%d-%d.%d",			\
-	      (Loc).first_line, (Loc).first_column,	\
-	      (Loc).last_line,  (Loc).last_column)
-# else
-#  define YY_LOCATION_PRINT(File, Loc) ((void) 0)
-# endif
-#endif
-
-
-/* YYLEX -- calling `yylex' with the right arguments.  */
-
-#ifdef YYLEX_PARAM
-# define YYLEX yylex (YYLEX_PARAM)
-#else
-# define YYLEX yylex ()
-#endif
-
-/* Enable debugging if requested.  */
-#if YYDEBUG
-
-# ifndef YYFPRINTF
-#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
-#  define YYFPRINTF fprintf
-# endif
-
-# define YYDPRINTF(Args)			\
-do {						\
-  if (yydebug)					\
-    YYFPRINTF Args;				\
-} while (YYID (0))
-
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location)			  \
-do {									  \
-  if (yydebug)								  \
-    {									  \
-      YYFPRINTF (stderr, "%s ", Title);					  \
-      yy_symbol_print (stderr,						  \
-		  Type, Value); \
-      YYFPRINTF (stderr, "\n");						  \
-    }									  \
-} while (YYID (0))
-
-
-/*--------------------------------.
-| Print this symbol on YYOUTPUT.  |
-`--------------------------------*/
-
-/*ARGSUSED*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static void
-yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
-#else
-static void
-yy_symbol_value_print (yyoutput, yytype, yyvaluep)
-    FILE *yyoutput;
-    int yytype;
-    YYSTYPE const * const yyvaluep;
-#endif
-{
-  if (!yyvaluep)
-    return;
-# ifdef YYPRINT
-  if (yytype < YYNTOKENS)
-    YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
-# else
-  YYUSE (yyoutput);
-# endif
-  switch (yytype)
-    {
-      default:
-	break;
-    }
-}
-
-
-/*--------------------------------.
-| Print this symbol on YYOUTPUT.  |
-`--------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static void
-yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
-#else
-static void
-yy_symbol_print (yyoutput, yytype, yyvaluep)
-    FILE *yyoutput;
-    int yytype;
-    YYSTYPE const * const yyvaluep;
-#endif
-{
-  if (yytype < YYNTOKENS)
-    YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
-  else
-    YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
-
-  yy_symbol_value_print (yyoutput, yytype, yyvaluep);
-  YYFPRINTF (yyoutput, ")");
-}
-
-/*------------------------------------------------------------------.
-| yy_stack_print -- Print the state stack from its BOTTOM up to its |
-| TOP (included).                                                   |
-`------------------------------------------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static void
-yy_stack_print (yytype_int16 *bottom, yytype_int16 *top)
-#else
-static void
-yy_stack_print (bottom, top)
-    yytype_int16 *bottom;
-    yytype_int16 *top;
-#endif
-{
-  YYFPRINTF (stderr, "Stack now");
-  for (; bottom <= top; ++bottom)
-    YYFPRINTF (stderr, " %d", *bottom);
-  YYFPRINTF (stderr, "\n");
-}
-
-# define YY_STACK_PRINT(Bottom, Top)				\
-do {								\
-  if (yydebug)							\
-    yy_stack_print ((Bottom), (Top));				\
-} while (YYID (0))
-
-
-/*------------------------------------------------.
-| Report that the YYRULE is going to be reduced.  |
-`------------------------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static void
-yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
-#else
-static void
-yy_reduce_print (yyvsp, yyrule)
-    YYSTYPE *yyvsp;
-    int yyrule;
-#endif
-{
-  int yynrhs = yyr2[yyrule];
-  int yyi;
-  unsigned long int yylno = yyrline[yyrule];
-  YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
-	     yyrule - 1, yylno);
-  /* The symbols being reduced.  */
-  for (yyi = 0; yyi < yynrhs; yyi++)
-    {
-      fprintf (stderr, "   $%d = ", yyi + 1);
-      yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
-		       &(yyvsp[(yyi + 1) - (yynrhs)])
-		       		       );
-      fprintf (stderr, "\n");
-    }
-}
-
-# define YY_REDUCE_PRINT(Rule)		\
-do {					\
-  if (yydebug)				\
-    yy_reduce_print (yyvsp, Rule); \
-} while (YYID (0))
-
-/* Nonzero means print parse trace.  It is left uninitialized so that
-   multiple parsers can coexist.  */
-int yydebug;
-#else /* !YYDEBUG */
-# define YYDPRINTF(Args)
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
-# define YY_STACK_PRINT(Bottom, Top)
-# define YY_REDUCE_PRINT(Rule)
-#endif /* !YYDEBUG */
-
-
-/* YYINITDEPTH -- initial size of the parser's stacks.  */
-#ifndef	YYINITDEPTH
-# define YYINITDEPTH 200
-#endif
-
-/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
-   if the built-in stack extension method is used).
-
-   Do not make this value too large; the results are undefined if
-   YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
-   evaluated with infinite-precision integer arithmetic.  */
-
-#ifndef YYMAXDEPTH
-# define YYMAXDEPTH 10000
-#endif
-
-

-
-#if YYERROR_VERBOSE
-
-# ifndef yystrlen
-#  if defined __GLIBC__ && defined _STRING_H
-#   define yystrlen strlen
-#  else
-/* Return the length of YYSTR.  */
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static YYSIZE_T
-yystrlen (const char *yystr)
-#else
-static YYSIZE_T
-yystrlen (yystr)
-    const char *yystr;
-#endif
-{
-  YYSIZE_T yylen;
-  for (yylen = 0; yystr[yylen]; yylen++)
-    continue;
-  return yylen;
-}
-#  endif
-# endif
-
-# ifndef yystpcpy
-#  if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
-#   define yystpcpy stpcpy
-#  else
-/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
-   YYDEST.  */
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static char *
-yystpcpy (char *yydest, const char *yysrc)
-#else
-static char *
-yystpcpy (yydest, yysrc)
-    char *yydest;
-    const char *yysrc;
-#endif
-{
-  char *yyd = yydest;
-  const char *yys = yysrc;
-
-  while ((*yyd++ = *yys++) != '\0')
-    continue;
-
-  return yyd - 1;
-}
-#  endif
-# endif
-
-# ifndef yytnamerr
-/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
-   quotes and backslashes, so that it's suitable for yyerror.  The
-   heuristic is that double-quoting is unnecessary unless the string
-   contains an apostrophe, a comma, or backslash (other than
-   backslash-backslash).  YYSTR is taken from yytname.  If YYRES is
-   null, do not copy; instead, return the length of what the result
-   would have been.  */
-static YYSIZE_T
-yytnamerr (char *yyres, const char *yystr)
-{
-  if (*yystr == '"')
-    {
-      YYSIZE_T yyn = 0;
-      char const *yyp = yystr;
-
-      for (;;)
-	switch (*++yyp)
-	  {
-	  case '\'':
-	  case ',':
-	    goto do_not_strip_quotes;
-
-	  case '\\':
-	    if (*++yyp != '\\')
-	      goto do_not_strip_quotes;
-	    /* Fall through.  */
-	  default:
-	    if (yyres)
-	      yyres[yyn] = *yyp;
-	    yyn++;
-	    break;
-
-	  case '"':
-	    if (yyres)
-	      yyres[yyn] = '\0';
-	    return yyn;
-	  }
-    do_not_strip_quotes: ;
-    }
-
-  if (! yyres)
-    return yystrlen (yystr);
-
-  return yystpcpy (yyres, yystr) - yyres;
-}
-# endif
-
-/* Copy into YYRESULT an error message about the unexpected token
-   YYCHAR while in state YYSTATE.  Return the number of bytes copied,
-   including the terminating null byte.  If YYRESULT is null, do not
-   copy anything; just return the number of bytes that would be
-   copied.  As a special case, return 0 if an ordinary "syntax error"
-   message will do.  Return YYSIZE_MAXIMUM if overflow occurs during
-   size calculation.  */
-static YYSIZE_T
-yysyntax_error (char *yyresult, int yystate, int yychar)
-{
-  int yyn = yypact[yystate];
-
-  if (! (YYPACT_NINF < yyn && yyn <= YYLAST))
-    return 0;
-  else
-    {
-      int yytype = YYTRANSLATE (yychar);
-      YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]);
-      YYSIZE_T yysize = yysize0;
-      YYSIZE_T yysize1;
-      int yysize_overflow = 0;
-      enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
-      char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
-      int yyx;
-
-# if 0
-      /* This is so xgettext sees the translatable formats that are
-	 constructed on the fly.  */
-      YY_("syntax error, unexpected %s");
-      YY_("syntax error, unexpected %s, expecting %s");
-      YY_("syntax error, unexpected %s, expecting %s or %s");
-      YY_("syntax error, unexpected %s, expecting %s or %s or %s");
-      YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s");
-# endif
-      char *yyfmt;
-      char const *yyf;
-      static char const yyunexpected[] = "syntax error, unexpected %s";
-      static char const yyexpecting[] = ", expecting %s";
-      static char const yyor[] = " or %s";
-      char yyformat[sizeof yyunexpected
-		    + sizeof yyexpecting - 1
-		    + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2)
-		       * (sizeof yyor - 1))];
-      char const *yyprefix = yyexpecting;
-
-      /* Start YYX at -YYN if negative to avoid negative indexes in
-	 YYCHECK.  */
-      int yyxbegin = yyn < 0 ? -yyn : 0;
-
-      /* Stay within bounds of both yycheck and yytname.  */
-      int yychecklim = YYLAST - yyn + 1;
-      int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
-      int yycount = 1;
-
-      yyarg[0] = yytname[yytype];
-      yyfmt = yystpcpy (yyformat, yyunexpected);
-
-      for (yyx = yyxbegin; yyx < yyxend; ++yyx)
-	if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR)
-	  {
-	    if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
-	      {
-		yycount = 1;
-		yysize = yysize0;
-		yyformat[sizeof yyunexpected - 1] = '\0';
-		break;
-	      }
-	    yyarg[yycount++] = yytname[yyx];
-	    yysize1 = yysize + yytnamerr (0, yytname[yyx]);
-	    yysize_overflow |= (yysize1 < yysize);
-	    yysize = yysize1;
-	    yyfmt = yystpcpy (yyfmt, yyprefix);
-	    yyprefix = yyor;
-	  }
-
-      yyf = YY_(yyformat);
-      yysize1 = yysize + yystrlen (yyf);
-      yysize_overflow |= (yysize1 < yysize);
-      yysize = yysize1;
-
-      if (yysize_overflow)
-	return YYSIZE_MAXIMUM;
-
-      if (yyresult)
-	{
-	  /* Avoid sprintf, as that infringes on the user's name space.
-	     Don't have undefined behavior even if the translation
-	     produced a string with the wrong number of "%s"s.  */
-	  char *yyp = yyresult;
-	  int yyi = 0;
-	  while ((*yyp = *yyf) != '\0')
-	    {
-	      if (*yyp == '%' && yyf[1] == 's' && yyi < yycount)
-		{
-		  yyp += yytnamerr (yyp, yyarg[yyi++]);
-		  yyf += 2;
-		}
-	      else
-		{
-		  yyp++;
-		  yyf++;
-		}
-	    }
-	}
-      return yysize;
-    }
-}
-#endif /* YYERROR_VERBOSE */
-

-
-/*-----------------------------------------------.
-| Release the memory associated to this symbol.  |
-`-----------------------------------------------*/
-
-/*ARGSUSED*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static void
-yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
-#else
-static void
-yydestruct (yymsg, yytype, yyvaluep)
-    const char *yymsg;
-    int yytype;
-    YYSTYPE *yyvaluep;
-#endif
-{
-  YYUSE (yyvaluep);
-
-  if (!yymsg)
-    yymsg = "Deleting";
-  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
-
-  switch (yytype)
-    {
-
-      default:
-	break;
-    }
-}
-

-
-/* Prevent warnings from -Wmissing-prototypes.  */
-
-#ifdef YYPARSE_PARAM
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void *YYPARSE_PARAM);
-#else
-int yyparse ();
-#endif
-#else /* ! YYPARSE_PARAM */
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void);
-#else
-int yyparse ();
-#endif
-#endif /* ! YYPARSE_PARAM */
-
-
-
-/* The look-ahead symbol.  */
-int yychar, yystate;
-
-/* The semantic value of the look-ahead symbol.  */
-YYSTYPE yylval;
-
-/* Number of syntax errors so far.  */
-int yynerrs;
-
-
-
-/*----------.
-| yyparse.  |
-`----------*/
-
-#ifdef YYPARSE_PARAM
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-int
-yyparse (void *YYPARSE_PARAM)
-#else
-int
-yyparse (YYPARSE_PARAM)
-    void *YYPARSE_PARAM;
-#endif
-#else /* ! YYPARSE_PARAM */
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-int
-yyparse (void)
-#else
-int
-yyparse ()
-
-#endif
-#endif
-{
-  
-  int yyn;
-  int yyresult;
-  /* Number of tokens to shift before error messages enabled.  */
-  int yyerrstatus;
-  /* Look-ahead token as an internal (translated) token number.  */
-  int yytoken = 0;
-#if YYERROR_VERBOSE
-  /* Buffer for error messages, and its allocated size.  */
-  char yymsgbuf[128];
-  char *yymsg = yymsgbuf;
-  YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
-#endif
-
-  /* Three stacks and their tools:
-     `yyss': related to states,
-     `yyvs': related to semantic values,
-     `yyls': related to locations.
-
-     Refer to the stacks thru separate pointers, to allow yyoverflow
-     to reallocate them elsewhere.  */
-
-  /* The state stack.  */
-  yytype_int16 yyssa[YYINITDEPTH];
-  yytype_int16 *yyss = yyssa;
-  yytype_int16 *yyssp;
-
-  /* The semantic value stack.  */
-  YYSTYPE yyvsa[YYINITDEPTH];
-  YYSTYPE *yyvs = yyvsa;
-  YYSTYPE *yyvsp;
-
-
-
-#define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N))
-
-  YYSIZE_T yystacksize = YYINITDEPTH;
-
-  /* The variables used to return semantic value and location from the
-     action routines.  */
-  YYSTYPE yyval;
-
-
-  /* The number of symbols on the RHS of the reduced rule.
-     Keep to zero when no symbol should be popped.  */
-  int yylen = 0;
-
-  YYDPRINTF ((stderr, "Starting parse\n"));
-
-  yystate = 0;
-  yyerrstatus = 0;
-  yynerrs = 0;
-  yychar = YYEMPTY;		/* Cause a token to be read.  */
-
-  /* Initialize stack pointers.
-     Waste one element of value and location stack
-     so that they stay on the same level as the state stack.
-     The wasted elements are never initialized.  */
-
-  yyssp = yyss;
-  yyvsp = yyvs;
-
-  goto yysetstate;
-
-/*------------------------------------------------------------.
-| yynewstate -- Push a new state, which is found in yystate.  |
-`------------------------------------------------------------*/
- yynewstate:
-  /* In all cases, when you get here, the value and location stacks
-     have just been pushed.  So pushing a state here evens the stacks.  */
-  yyssp++;
-
- yysetstate:
-  *yyssp = yystate;
-
-  if (yyss + yystacksize - 1 <= yyssp)
-    {
-      /* Get the current used size of the three stacks, in elements.  */
-      YYSIZE_T yysize = yyssp - yyss + 1;
-
-#ifdef yyoverflow
-      {
-	/* Give user a chance to reallocate the stack.  Use copies of
-	   these so that the &'s don't force the real ones into
-	   memory.  */
-	YYSTYPE *yyvs1 = yyvs;
-	yytype_int16 *yyss1 = yyss;
-
-
-	/* Each stack pointer address is followed by the size of the
-	   data in use in that stack, in bytes.  This used to be a
-	   conditional around just the two extra args, but that might
-	   be undefined if yyoverflow is a macro.  */
-	yyoverflow (YY_("memory exhausted"),
-		    &yyss1, yysize * sizeof (*yyssp),
-		    &yyvs1, yysize * sizeof (*yyvsp),
-
-		    &yystacksize);
-
-	yyss = yyss1;
-	yyvs = yyvs1;
-      }
-#else /* no yyoverflow */
-# ifndef YYSTACK_RELOCATE
-      goto yyexhaustedlab;
-# else
-      /* Extend the stack our own way.  */
-      if (YYMAXDEPTH <= yystacksize)
-	goto yyexhaustedlab;
-      yystacksize *= 2;
-      if (YYMAXDEPTH < yystacksize)
-	yystacksize = YYMAXDEPTH;
-
-      {
-	yytype_int16 *yyss1 = yyss;
-	union yyalloc *yyptr =
-	  (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
-	if (! yyptr)
-	  goto yyexhaustedlab;
-	YYSTACK_RELOCATE (yyss);
-	YYSTACK_RELOCATE (yyvs);
-
-#  undef YYSTACK_RELOCATE
-	if (yyss1 != yyssa)
-	  YYSTACK_FREE (yyss1);
-      }
-# endif
-#endif /* no yyoverflow */
-
-      yyssp = yyss + yysize - 1;
-      yyvsp = yyvs + yysize - 1;
-
-
-      YYDPRINTF ((stderr, "Stack size increased to %lu\n",
-		  (unsigned long int) yystacksize));
-
-      if (yyss + yystacksize - 1 <= yyssp)
-	YYABORT;
-    }
-
-  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
-
-  goto yybackup;
-
-/*-----------.
-| yybackup.  |
-`-----------*/
-yybackup:
-
-  /* Do appropriate processing given the current state.  Read a
-     look-ahead token if we need one and don't already have one.  */
-
-  /* First try to decide what to do without reference to look-ahead token.  */
-  yyn = yypact[yystate];
-  if (yyn == YYPACT_NINF)
-    goto yydefault;
-
-  /* Not known => get a look-ahead token if don't already have one.  */
-
-  /* YYCHAR is either YYEMPTY or YYEOF or a valid look-ahead symbol.  */
-  if (yychar == YYEMPTY)
-    {
-      YYDPRINTF ((stderr, "Reading a token: "));
-      yychar = YYLEX;
-    }
-
-  if (yychar <= YYEOF)
-    {
-      yychar = yytoken = YYEOF;
-      YYDPRINTF ((stderr, "Now at end of input.\n"));
-    }
-  else
-    {
-      yytoken = YYTRANSLATE (yychar);
-      YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
-    }
-
-  /* If the proper action on seeing token YYTOKEN is to reduce or to
-     detect an error, take that action.  */
-  yyn += yytoken;
-  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
-    goto yydefault;
-  yyn = yytable[yyn];
-  if (yyn <= 0)
-    {
-      if (yyn == 0 || yyn == YYTABLE_NINF)
-	goto yyerrlab;
-      yyn = -yyn;
-      goto yyreduce;
-    }
-
-  if (yyn == YYFINAL)
-    YYACCEPT;
-
-  /* Count tokens shifted since error; after three, turn off error
-     status.  */
-  if (yyerrstatus)
-    yyerrstatus--;
-
-  /* Shift the look-ahead token.  */
-  YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
-
-  /* Discard the shifted token unless it is eof.  */
-  if (yychar != YYEOF)
-    yychar = YYEMPTY;
-
-  yystate = yyn;
-  *++yyvsp = yylval;
-
-  goto yynewstate;
-
-
-/*-----------------------------------------------------------.
-| yydefault -- do the default action for the current state.  |
-`-----------------------------------------------------------*/
-yydefault:
-  yyn = yydefact[yystate];
-  if (yyn == 0)
-    goto yyerrlab;
-  goto yyreduce;
-
-
-/*-----------------------------.
-| yyreduce -- Do a reduction.  |
-`-----------------------------*/
-yyreduce:
-  /* yyn is the number of a rule to reduce with.  */
-  yylen = yyr2[yyn];
-
-  /* If YYLEN is nonzero, implement the default value of the action:
-     `$$ = $1'.
-
-     Otherwise, the following line sets YYVAL to garbage.
-     This behavior is undocumented and Bison
-     users should not rely upon it.  Assigning to YYVAL
-     unconditionally makes the parser a bit smaller, and it avoids a
-     GCC warning that YYVAL may be used uninitialized.  */
-  yyval = yyvsp[1-yylen];
-
-
-  YY_REDUCE_PRINT (yyn);
-  switch (yyn)
-    {
-        case 2:
-#line 128 "go.y"
-    {
-		xtop = concat(xtop, (yyvsp[(4) - (4)].list));
-	}
-    break;
-
-  case 3:
-#line 134 "go.y"
-    {
-		prevlineno = lineno;
-		yyerror("package statement must be first");
-		errorexit();
-	}
-    break;
-
-  case 4:
-#line 140 "go.y"
-    {
-		mkpackage((yyvsp[(2) - (3)].sym)->name);
-	}
-    break;
-
-  case 5:
-#line 150 "go.y"
-    {
-		importpkg = runtimepkg;
-
-		if(debug['A'])
-			cannedimports("runtime.builtin", "package runtime\n\n$$\n\n");
-		else
-			cannedimports("runtime.builtin", runtimeimport);
-		curio.importsafe = 1;
-	}
-    break;
-
-  case 6:
-#line 161 "go.y"
-    {
-		importpkg = nil;
-	}
-    break;
-
-  case 12:
-#line 175 "go.y"
-    {
-		Pkg *ipkg;
-		Sym *my;
-		Node *pack;
-		
-		ipkg = importpkg;
-		my = importmyname;
-		importpkg = nil;
-		importmyname = S;
-
-		if(my == nil)
-			my = lookup(ipkg->name);
-
-		pack = nod(OPACK, N, N);
-		pack->sym = my;
-		pack->pkg = ipkg;
-		pack->lineno = (yyvsp[(1) - (3)].i);
-
-		if(my->name[0] == '.') {
-			importdot(ipkg, pack);
-			break;
-		}
-		if(strcmp(my->name, "init") == 0) {
-			yyerror("cannot import package as init - init must be a func");
-			break;
-		}
-		if(my->name[0] == '_' && my->name[1] == '\0')
-			break;
-		if(my->def) {
-			lineno = (yyvsp[(1) - (3)].i);
-			redeclare(my, "as imported package name");
-		}
-		my->def = pack;
-		my->lastlineno = (yyvsp[(1) - (3)].i);
-		my->block = 1;	// at top level
-	}
-    break;
-
-  case 13:
-#line 212 "go.y"
-    {
-		// When an invalid import path is passed to importfile,
-		// it calls yyerror and then sets up a fake import with
-		// no package statement. This allows us to test more
-		// than one invalid import statement in a single file.
-		if(nerrors == 0)
-			fatal("phase error in import");
-	}
-    break;
-
-  case 16:
-#line 227 "go.y"
-    {
-		// import with original name
-		(yyval.i) = parserline();
-		importmyname = S;
-		importfile(&(yyvsp[(1) - (1)].val), (yyval.i));
-	}
-    break;
-
-  case 17:
-#line 234 "go.y"
-    {
-		// import with given name
-		(yyval.i) = parserline();
-		importmyname = (yyvsp[(1) - (2)].sym);
-		importfile(&(yyvsp[(2) - (2)].val), (yyval.i));
-	}
-    break;
-
-  case 18:
-#line 241 "go.y"
-    {
-		// import into my name space
-		(yyval.i) = parserline();
-		importmyname = lookup(".");
-		importfile(&(yyvsp[(2) - (2)].val), (yyval.i));
-	}
-    break;
-
-  case 19:
-#line 250 "go.y"
-    {
-		if(importpkg->name == nil) {
-			importpkg->name = (yyvsp[(2) - (4)].sym)->name;
-			pkglookup((yyvsp[(2) - (4)].sym)->name, nil)->npkg++;
-		} else if(strcmp(importpkg->name, (yyvsp[(2) - (4)].sym)->name) != 0)
-			yyerror("conflicting names %s and %s for package \"%Z\"", importpkg->name, (yyvsp[(2) - (4)].sym)->name, importpkg->path);
-		importpkg->direct = 1;
-		importpkg->safe = curio.importsafe;
-
-		if(safemode && !curio.importsafe)
-			yyerror("cannot import unsafe package \"%Z\"", importpkg->path);
-	}
-    break;
-
-  case 21:
-#line 265 "go.y"
-    {
-		if(strcmp((yyvsp[(1) - (1)].sym)->name, "safe") == 0)
-			curio.importsafe = 1;
-	}
-    break;
-
-  case 22:
-#line 271 "go.y"
-    {
-		defercheckwidth();
-	}
-    break;
-
-  case 23:
-#line 275 "go.y"
-    {
-		resumecheckwidth();
-		unimportfile();
-	}
-    break;
-
-  case 24:
-#line 284 "go.y"
-    {
-		yyerror("empty top-level declaration");
-		(yyval.list) = nil;
-	}
-    break;
-
-  case 26:
-#line 290 "go.y"
-    {
-		(yyval.list) = list1((yyvsp[(1) - (1)].node));
-	}
-    break;
-
-  case 27:
-#line 294 "go.y"
-    {
-		yyerror("non-declaration statement outside function body");
-		(yyval.list) = nil;
-	}
-    break;
-
-  case 28:
-#line 299 "go.y"
-    {
-		(yyval.list) = nil;
-	}
-    break;
-
-  case 29:
-#line 305 "go.y"
-    {
-		(yyval.list) = (yyvsp[(2) - (2)].list);
-	}
-    break;
-
-  case 30:
-#line 309 "go.y"
-    {
-		(yyval.list) = (yyvsp[(3) - (5)].list);
-	}
-    break;
-
-  case 31:
-#line 313 "go.y"
-    {
-		(yyval.list) = nil;
-	}
-    break;
-
-  case 32:
-#line 317 "go.y"
-    {
-		(yyval.list) = (yyvsp[(2) - (2)].list);
-		iota = -100000;
-		lastconst = nil;
-	}
-    break;
-
-  case 33:
-#line 323 "go.y"
-    {
-		(yyval.list) = (yyvsp[(3) - (5)].list);
-		iota = -100000;
-		lastconst = nil;
-	}
-    break;
-
-  case 34:
-#line 329 "go.y"
-    {
-		(yyval.list) = concat((yyvsp[(3) - (7)].list), (yyvsp[(5) - (7)].list));
-		iota = -100000;
-		lastconst = nil;
-	}
-    break;
-
-  case 35:
-#line 335 "go.y"
-    {
-		(yyval.list) = nil;
-		iota = -100000;
-	}
-    break;
-
-  case 36:
-#line 340 "go.y"
-    {
-		(yyval.list) = list1((yyvsp[(2) - (2)].node));
-	}
-    break;
-
-  case 37:
-#line 344 "go.y"
-    {
-		(yyval.list) = (yyvsp[(3) - (5)].list);
-	}
-    break;
-
-  case 38:
-#line 348 "go.y"
-    {
-		(yyval.list) = nil;
-	}
-    break;
-
-  case 39:
-#line 354 "go.y"
-    {
-		iota = 0;
-	}
-    break;
-
-  case 40:
-#line 360 "go.y"
-    {
-		(yyval.list) = variter((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node), nil);
-	}
-    break;
-
-  case 41:
-#line 364 "go.y"
-    {
-		(yyval.list) = variter((yyvsp[(1) - (4)].list), (yyvsp[(2) - (4)].node), (yyvsp[(4) - (4)].list));
-	}
-    break;
-
-  case 42:
-#line 368 "go.y"
-    {
-		(yyval.list) = variter((yyvsp[(1) - (3)].list), nil, (yyvsp[(3) - (3)].list));
-	}
-    break;
-
-  case 43:
-#line 374 "go.y"
-    {
-		(yyval.list) = constiter((yyvsp[(1) - (4)].list), (yyvsp[(2) - (4)].node), (yyvsp[(4) - (4)].list));
-	}
-    break;
-
-  case 44:
-#line 378 "go.y"
-    {
-		(yyval.list) = constiter((yyvsp[(1) - (3)].list), N, (yyvsp[(3) - (3)].list));
-	}
-    break;
-
-  case 46:
-#line 385 "go.y"
-    {
-		(yyval.list) = constiter((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node), nil);
-	}
-    break;
-
-  case 47:
-#line 389 "go.y"
-    {
-		(yyval.list) = constiter((yyvsp[(1) - (1)].list), N, nil);
-	}
-    break;
-
-  case 48:
-#line 395 "go.y"
-    {
-		// different from dclname because the name
-		// becomes visible right here, not at the end
-		// of the declaration.
-		(yyval.node) = typedcl0((yyvsp[(1) - (1)].sym));
-	}
-    break;
-
-  case 49:
-#line 404 "go.y"
-    {
-		(yyval.node) = typedcl1((yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node), 1);
-	}
-    break;
-
-  case 50:
-#line 410 "go.y"
-    {
-		(yyval.node) = (yyvsp[(1) - (1)].node);
-
-		// These nodes do not carry line numbers.
-		// Since a bare name used as an expression is an error,
-		// introduce a wrapper node to give the correct line.
-		switch((yyval.node)->op) {
-		case ONAME:
-		case ONONAME:
-		case OTYPE:
-		case OPACK:
-		case OLITERAL:
-			(yyval.node) = nod(OPAREN, (yyval.node), N);
-			(yyval.node)->implicit = 1;
-			break;
-		}
-	}
-    break;
-
-  case 51:
-#line 428 "go.y"
-    {
-		(yyval.node) = nod(OASOP, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-		(yyval.node)->etype = (yyvsp[(2) - (3)].i);			// rathole to pass opcode
-	}
-    break;
-
-  case 52:
-#line 433 "go.y"
-    {
-		if((yyvsp[(1) - (3)].list)->next == nil && (yyvsp[(3) - (3)].list)->next == nil) {
-			// simple
-			(yyval.node) = nod(OAS, (yyvsp[(1) - (3)].list)->n, (yyvsp[(3) - (3)].list)->n);
-			break;
-		}
-		// multiple
-		(yyval.node) = nod(OAS2, N, N);
-		(yyval.node)->list = (yyvsp[(1) - (3)].list);
-		(yyval.node)->rlist = (yyvsp[(3) - (3)].list);
-	}
-    break;
-
-  case 53:
-#line 445 "go.y"
-    {
-		if((yyvsp[(3) - (3)].list)->n->op == OTYPESW) {
-			(yyval.node) = nod(OTYPESW, N, (yyvsp[(3) - (3)].list)->n->right);
-			if((yyvsp[(3) - (3)].list)->next != nil)
-				yyerror("expr.(type) must be alone in list");
-			if((yyvsp[(1) - (3)].list)->next != nil)
-				yyerror("argument count mismatch: %d = %d", count((yyvsp[(1) - (3)].list)), 1);
-			else if(((yyvsp[(1) - (3)].list)->n->op != ONAME && (yyvsp[(1) - (3)].list)->n->op != OTYPE && (yyvsp[(1) - (3)].list)->n->op != ONONAME) || isblank((yyvsp[(1) - (3)].list)->n))
-				yyerror("invalid variable name %N in type switch", (yyvsp[(1) - (3)].list)->n);
-			else
-				(yyval.node)->left = dclname((yyvsp[(1) - (3)].list)->n->sym);  // it's a colas, so must not re-use an oldname.
-			break;
-		}
-		(yyval.node) = colas((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list), (yyvsp[(2) - (3)].i));
-	}
-    break;
-
-  case 54:
-#line 461 "go.y"
-    {
-		(yyval.node) = nod(OASOP, (yyvsp[(1) - (2)].node), nodintconst(1));
-		(yyval.node)->implicit = 1;
-		(yyval.node)->etype = OADD;
-	}
-    break;
-
-  case 55:
-#line 467 "go.y"
-    {
-		(yyval.node) = nod(OASOP, (yyvsp[(1) - (2)].node), nodintconst(1));
-		(yyval.node)->implicit = 1;
-		(yyval.node)->etype = OSUB;
-	}
-    break;
-
-  case 56:
-#line 475 "go.y"
-    {
-		Node *n, *nn;
-
-		// will be converted to OCASE
-		// right will point to next case
-		// done in casebody()
-		markdcl();
-		(yyval.node) = nod(OXCASE, N, N);
-		(yyval.node)->list = (yyvsp[(2) - (3)].list);
-		if(typesw != N && typesw->right != N && (n=typesw->right->left) != N) {
-			// type switch - declare variable
-			nn = newname(n->sym);
-			declare(nn, dclcontext);
-			(yyval.node)->nname = nn;
-
-			// keep track of the instances for reporting unused
-			nn->defn = typesw->right;
-		}
-	}
-    break;
-
-  case 57:
-#line 495 "go.y"
-    {
-		Node *n;
-
-		// will be converted to OCASE
-		// right will point to next case
-		// done in casebody()
-		markdcl();
-		(yyval.node) = nod(OXCASE, N, N);
-		if((yyvsp[(2) - (5)].list)->next == nil)
-			n = nod(OAS, (yyvsp[(2) - (5)].list)->n, (yyvsp[(4) - (5)].node));
-		else {
-			n = nod(OAS2, N, N);
-			n->list = (yyvsp[(2) - (5)].list);
-			n->rlist = list1((yyvsp[(4) - (5)].node));
-		}
-		(yyval.node)->list = list1(n);
-	}
-    break;
-
-  case 58:
-#line 513 "go.y"
-    {
-		// will be converted to OCASE
-		// right will point to next case
-		// done in casebody()
-		markdcl();
-		(yyval.node) = nod(OXCASE, N, N);
-		(yyval.node)->list = list1(colas((yyvsp[(2) - (5)].list), list1((yyvsp[(4) - (5)].node)), (yyvsp[(3) - (5)].i)));
-	}
-    break;
-
-  case 59:
-#line 522 "go.y"
-    {
-		Node *n, *nn;
-
-		markdcl();
-		(yyval.node) = nod(OXCASE, N, N);
-		if(typesw != N && typesw->right != N && (n=typesw->right->left) != N) {
-			// type switch - declare variable
-			nn = newname(n->sym);
-			declare(nn, dclcontext);
-			(yyval.node)->nname = nn;
-
-			// keep track of the instances for reporting unused
-			nn->defn = typesw->right;
-		}
-	}
-    break;
-
-  case 60:
-#line 540 "go.y"
-    {
-		markdcl();
-	}
-    break;
-
-  case 61:
-#line 544 "go.y"
-    {
-		if((yyvsp[(3) - (4)].list) == nil)
-			(yyval.node) = nod(OEMPTY, N, N);
-		else
-			(yyval.node) = liststmt((yyvsp[(3) - (4)].list));
-		popdcl();
-	}
-    break;
-
-  case 62:
-#line 554 "go.y"
-    {
-		// If the last token read by the lexer was consumed
-		// as part of the case, clear it (parser has cleared yychar).
-		// If the last token read by the lexer was the lookahead
-		// leave it alone (parser has it cached in yychar).
-		// This is so that the stmt_list action doesn't look at
-		// the case tokens if the stmt_list is empty.
-		yylast = yychar;
-		(yyvsp[(1) - (1)].node)->xoffset = block;
-	}
-    break;
-
-  case 63:
-#line 565 "go.y"
-    {
-		int last;
-
-		// This is the only place in the language where a statement
-		// list is not allowed to drop the final semicolon, because
-		// it's the only place where a statement list is not followed 
-		// by a closing brace.  Handle the error for pedantry.
-
-		// Find the final token of the statement list.
-		// yylast is lookahead; yyprev is last of stmt_list
-		last = yyprev;
-
-		if(last > 0 && last != ';' && yychar != '}')
-			yyerror("missing statement after label");
-		(yyval.node) = (yyvsp[(1) - (3)].node);
-		(yyval.node)->nbody = (yyvsp[(3) - (3)].list);
-		popdcl();
-	}
-    break;
-
-  case 64:
-#line 585 "go.y"
-    {
-		(yyval.list) = nil;
-	}
-    break;
-
-  case 65:
-#line 589 "go.y"
-    {
-		(yyval.list) = list((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].node));
-	}
-    break;
-
-  case 66:
-#line 595 "go.y"
-    {
-		markdcl();
-	}
-    break;
-
-  case 67:
-#line 599 "go.y"
-    {
-		(yyval.list) = (yyvsp[(3) - (4)].list);
-		popdcl();
-	}
-    break;
-
-  case 68:
-#line 606 "go.y"
-    {
-		(yyval.node) = nod(ORANGE, N, (yyvsp[(4) - (4)].node));
-		(yyval.node)->list = (yyvsp[(1) - (4)].list);
-		(yyval.node)->etype = 0;	// := flag
-	}
-    break;
-
-  case 69:
-#line 612 "go.y"
-    {
-		(yyval.node) = nod(ORANGE, N, (yyvsp[(4) - (4)].node));
-		(yyval.node)->list = (yyvsp[(1) - (4)].list);
-		(yyval.node)->colas = 1;
-		colasdefn((yyvsp[(1) - (4)].list), (yyval.node));
-	}
-    break;
-
-  case 70:
-#line 619 "go.y"
-    {
-		(yyval.node) = nod(ORANGE, N, (yyvsp[(2) - (2)].node));
-		(yyval.node)->etype = 0; // := flag
-	}
-    break;
-
-  case 71:
-#line 626 "go.y"
-    {
-		// init ; test ; incr
-		if((yyvsp[(5) - (5)].node) != N && (yyvsp[(5) - (5)].node)->colas != 0)
-			yyerror("cannot declare in the for-increment");
-		(yyval.node) = nod(OFOR, N, N);
-		if((yyvsp[(1) - (5)].node) != N)
-			(yyval.node)->ninit = list1((yyvsp[(1) - (5)].node));
-		(yyval.node)->ntest = (yyvsp[(3) - (5)].node);
-		(yyval.node)->nincr = (yyvsp[(5) - (5)].node);
-	}
-    break;
-
-  case 72:
-#line 637 "go.y"
-    {
-		// normal test
-		(yyval.node) = nod(OFOR, N, N);
-		(yyval.node)->ntest = (yyvsp[(1) - (1)].node);
-	}
-    break;
-
-  case 74:
-#line 646 "go.y"
-    {
-		(yyval.node) = (yyvsp[(1) - (2)].node);
-		(yyval.node)->nbody = concat((yyval.node)->nbody, (yyvsp[(2) - (2)].list));
-	}
-    break;
-
-  case 75:
-#line 653 "go.y"
-    {
-		markdcl();
-	}
-    break;
-
-  case 76:
-#line 657 "go.y"
-    {
-		(yyval.node) = (yyvsp[(3) - (3)].node);
-		popdcl();
-	}
-    break;
-
-  case 77:
-#line 664 "go.y"
-    {
-		// test
-		(yyval.node) = nod(OIF, N, N);
-		(yyval.node)->ntest = (yyvsp[(1) - (1)].node);
-	}
-    break;
-
-  case 78:
-#line 670 "go.y"
-    {
-		// init ; test
-		(yyval.node) = nod(OIF, N, N);
-		if((yyvsp[(1) - (3)].node) != N)
-			(yyval.node)->ninit = list1((yyvsp[(1) - (3)].node));
-		(yyval.node)->ntest = (yyvsp[(3) - (3)].node);
-	}
-    break;
-
-  case 79:
-#line 681 "go.y"
-    {
-		markdcl();
-	}
-    break;
-
-  case 80:
-#line 685 "go.y"
-    {
-		if((yyvsp[(3) - (3)].node)->ntest == N)
-			yyerror("missing condition in if statement");
-	}
-    break;
-
-  case 81:
-#line 690 "go.y"
-    {
-		(yyvsp[(3) - (5)].node)->nbody = (yyvsp[(5) - (5)].list);
-	}
-    break;
-
-  case 82:
-#line 694 "go.y"
-    {
-		Node *n;
-		NodeList *nn;
-
-		(yyval.node) = (yyvsp[(3) - (8)].node);
-		n = (yyvsp[(3) - (8)].node);
-		popdcl();
-		for(nn = concat((yyvsp[(7) - (8)].list), (yyvsp[(8) - (8)].list)); nn; nn = nn->next) {
-			if(nn->n->op == OIF)
-				popdcl();
-			n->nelse = list1(nn->n);
-			n = nn->n;
-		}
-	}
-    break;
-
-  case 83:
-#line 711 "go.y"
-    {
-		markdcl();
-	}
-    break;
-
-  case 84:
-#line 715 "go.y"
-    {
-		if((yyvsp[(4) - (5)].node)->ntest == N)
-			yyerror("missing condition in if statement");
-		(yyvsp[(4) - (5)].node)->nbody = (yyvsp[(5) - (5)].list);
-		(yyval.list) = list1((yyvsp[(4) - (5)].node));
-	}
-    break;
-
-  case 85:
-#line 723 "go.y"
-    {
-		(yyval.list) = nil;
-	}
-    break;
-
-  case 86:
-#line 727 "go.y"
-    {
-		(yyval.list) = concat((yyvsp[(1) - (2)].list), (yyvsp[(2) - (2)].list));
-	}
-    break;
-
-  case 87:
-#line 732 "go.y"
-    {
-		(yyval.list) = nil;
-	}
-    break;
-
-  case 88:
-#line 736 "go.y"
-    {
-		NodeList *node;
-		
-		node = mal(sizeof *node);
-		node->n = (yyvsp[(2) - (2)].node);
-		node->end = node;
-		(yyval.list) = node;
-	}
-    break;
-
-  case 89:
-#line 747 "go.y"
-    {
-		markdcl();
-	}
-    break;
-
-  case 90:
-#line 751 "go.y"
-    {
-		Node *n;
-		n = (yyvsp[(3) - (3)].node)->ntest;
-		if(n != N && n->op != OTYPESW)
-			n = N;
-		typesw = nod(OXXX, typesw, n);
-	}
-    break;
-
-  case 91:
-#line 759 "go.y"
-    {
-		(yyval.node) = (yyvsp[(3) - (7)].node);
-		(yyval.node)->op = OSWITCH;
-		(yyval.node)->list = (yyvsp[(6) - (7)].list);
-		typesw = typesw->left;
-		popdcl();
-	}
-    break;
-
-  case 92:
-#line 769 "go.y"
-    {
-		typesw = nod(OXXX, typesw, N);
-	}
-    break;
-
-  case 93:
-#line 773 "go.y"
-    {
-		(yyval.node) = nod(OSELECT, N, N);
-		(yyval.node)->lineno = typesw->lineno;
-		(yyval.node)->list = (yyvsp[(4) - (5)].list);
-		typesw = typesw->left;
-	}
-    break;
-
-  case 95:
-#line 786 "go.y"
-    {
-		(yyval.node) = nod(OOROR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 96:
-#line 790 "go.y"
-    {
-		(yyval.node) = nod(OANDAND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 97:
-#line 794 "go.y"
-    {
-		(yyval.node) = nod(OEQ, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 98:
-#line 798 "go.y"
-    {
-		(yyval.node) = nod(ONE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 99:
-#line 802 "go.y"
-    {
-		(yyval.node) = nod(OLT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 100:
-#line 806 "go.y"
-    {
-		(yyval.node) = nod(OLE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 101:
-#line 810 "go.y"
-    {
-		(yyval.node) = nod(OGE, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 102:
-#line 814 "go.y"
-    {
-		(yyval.node) = nod(OGT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 103:
-#line 818 "go.y"
-    {
-		(yyval.node) = nod(OADD, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 104:
-#line 822 "go.y"
-    {
-		(yyval.node) = nod(OSUB, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 105:
-#line 826 "go.y"
-    {
-		(yyval.node) = nod(OOR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 106:
-#line 830 "go.y"
-    {
-		(yyval.node) = nod(OXOR, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 107:
-#line 834 "go.y"
-    {
-		(yyval.node) = nod(OMUL, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 108:
-#line 838 "go.y"
-    {
-		(yyval.node) = nod(ODIV, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 109:
-#line 842 "go.y"
-    {
-		(yyval.node) = nod(OMOD, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 110:
-#line 846 "go.y"
-    {
-		(yyval.node) = nod(OAND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 111:
-#line 850 "go.y"
-    {
-		(yyval.node) = nod(OANDNOT, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 112:
-#line 854 "go.y"
-    {
-		(yyval.node) = nod(OLSH, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 113:
-#line 858 "go.y"
-    {
-		(yyval.node) = nod(ORSH, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 114:
-#line 863 "go.y"
-    {
-		(yyval.node) = nod(OSEND, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 116:
-#line 870 "go.y"
-    {
-		(yyval.node) = nod(OIND, (yyvsp[(2) - (2)].node), N);
-	}
-    break;
-
-  case 117:
-#line 874 "go.y"
-    {
-		if((yyvsp[(2) - (2)].node)->op == OCOMPLIT) {
-			// Special case for &T{...}: turn into (*T){...}.
-			(yyval.node) = (yyvsp[(2) - (2)].node);
-			(yyval.node)->right = nod(OIND, (yyval.node)->right, N);
-			(yyval.node)->right->implicit = 1;
-		} else {
-			(yyval.node) = nod(OADDR, (yyvsp[(2) - (2)].node), N);
-		}
-	}
-    break;
-
-  case 118:
-#line 885 "go.y"
-    {
-		(yyval.node) = nod(OPLUS, (yyvsp[(2) - (2)].node), N);
-	}
-    break;
-
-  case 119:
-#line 889 "go.y"
-    {
-		(yyval.node) = nod(OMINUS, (yyvsp[(2) - (2)].node), N);
-	}
-    break;
-
-  case 120:
-#line 893 "go.y"
-    {
-		(yyval.node) = nod(ONOT, (yyvsp[(2) - (2)].node), N);
-	}
-    break;
-
-  case 121:
-#line 897 "go.y"
-    {
-		yyerror("the bitwise complement operator is ^");
-		(yyval.node) = nod(OCOM, (yyvsp[(2) - (2)].node), N);
-	}
-    break;
-
-  case 122:
-#line 902 "go.y"
-    {
-		(yyval.node) = nod(OCOM, (yyvsp[(2) - (2)].node), N);
-	}
-    break;
-
-  case 123:
-#line 906 "go.y"
-    {
-		(yyval.node) = nod(ORECV, (yyvsp[(2) - (2)].node), N);
-	}
-    break;
-
-  case 124:
-#line 916 "go.y"
-    {
-		(yyval.node) = nod(OCALL, (yyvsp[(1) - (3)].node), N);
-	}
-    break;
-
-  case 125:
-#line 920 "go.y"
-    {
-		(yyval.node) = nod(OCALL, (yyvsp[(1) - (5)].node), N);
-		(yyval.node)->list = (yyvsp[(3) - (5)].list);
-	}
-    break;
-
-  case 126:
-#line 925 "go.y"
-    {
-		(yyval.node) = nod(OCALL, (yyvsp[(1) - (6)].node), N);
-		(yyval.node)->list = (yyvsp[(3) - (6)].list);
-		(yyval.node)->isddd = 1;
-	}
-    break;
-
-  case 127:
-#line 933 "go.y"
-    {
-		(yyval.node) = nodlit((yyvsp[(1) - (1)].val));
-	}
-    break;
-
-  case 129:
-#line 938 "go.y"
-    {
-		if((yyvsp[(1) - (3)].node)->op == OPACK) {
-			Sym *s;
-			s = restrictlookup((yyvsp[(3) - (3)].sym)->name, (yyvsp[(1) - (3)].node)->pkg);
-			(yyvsp[(1) - (3)].node)->used = 1;
-			(yyval.node) = oldname(s);
-			break;
-		}
-		(yyval.node) = nod(OXDOT, (yyvsp[(1) - (3)].node), newname((yyvsp[(3) - (3)].sym)));
-	}
-    break;
-
-  case 130:
-#line 949 "go.y"
-    {
-		(yyval.node) = nod(ODOTTYPE, (yyvsp[(1) - (5)].node), (yyvsp[(4) - (5)].node));
-	}
-    break;
-
-  case 131:
-#line 953 "go.y"
-    {
-		(yyval.node) = nod(OTYPESW, N, (yyvsp[(1) - (5)].node));
-	}
-    break;
-
-  case 132:
-#line 957 "go.y"
-    {
-		(yyval.node) = nod(OINDEX, (yyvsp[(1) - (4)].node), (yyvsp[(3) - (4)].node));
-	}
-    break;
-
-  case 133:
-#line 961 "go.y"
-    {
-		(yyval.node) = nod(OSLICE, (yyvsp[(1) - (6)].node), nod(OKEY, (yyvsp[(3) - (6)].node), (yyvsp[(5) - (6)].node)));
-	}
-    break;
-
-  case 134:
-#line 965 "go.y"
-    {
-		if((yyvsp[(5) - (8)].node) == N)
-			yyerror("middle index required in 3-index slice");
-		if((yyvsp[(7) - (8)].node) == N)
-			yyerror("final index required in 3-index slice");
-		(yyval.node) = nod(OSLICE3, (yyvsp[(1) - (8)].node), nod(OKEY, (yyvsp[(3) - (8)].node), nod(OKEY, (yyvsp[(5) - (8)].node), (yyvsp[(7) - (8)].node))));
-	}
-    break;
-
-  case 136:
-#line 974 "go.y"
-    {
-		// conversion
-		(yyval.node) = nod(OCALL, (yyvsp[(1) - (5)].node), N);
-		(yyval.node)->list = list1((yyvsp[(3) - (5)].node));
-	}
-    break;
-
-  case 137:
-#line 980 "go.y"
-    {
-		(yyval.node) = (yyvsp[(3) - (5)].node);
-		(yyval.node)->right = (yyvsp[(1) - (5)].node);
-		(yyval.node)->list = (yyvsp[(4) - (5)].list);
-		fixlbrace((yyvsp[(2) - (5)].i));
-	}
-    break;
-
-  case 138:
-#line 987 "go.y"
-    {
-		(yyval.node) = (yyvsp[(3) - (5)].node);
-		(yyval.node)->right = (yyvsp[(1) - (5)].node);
-		(yyval.node)->list = (yyvsp[(4) - (5)].list);
-	}
-    break;
-
-  case 139:
-#line 993 "go.y"
-    {
-		yyerror("cannot parenthesize type in composite literal");
-		(yyval.node) = (yyvsp[(5) - (7)].node);
-		(yyval.node)->right = (yyvsp[(2) - (7)].node);
-		(yyval.node)->list = (yyvsp[(6) - (7)].list);
-	}
-    break;
-
-  case 141:
-#line 1002 "go.y"
-    {
-		// composite expression.
-		// make node early so we get the right line number.
-		(yyval.node) = nod(OCOMPLIT, N, N);
-	}
-    break;
-
-  case 142:
-#line 1010 "go.y"
-    {
-		(yyval.node) = nod(OKEY, (yyvsp[(1) - (3)].node), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 143:
-#line 1016 "go.y"
-    {
-		// These nodes do not carry line numbers.
-		// Since a composite literal commonly spans several lines,
-		// the line number on errors may be misleading.
-		// Introduce a wrapper node to give the correct line.
-		(yyval.node) = (yyvsp[(1) - (1)].node);
-		switch((yyval.node)->op) {
-		case ONAME:
-		case ONONAME:
-		case OTYPE:
-		case OPACK:
-		case OLITERAL:
-			(yyval.node) = nod(OPAREN, (yyval.node), N);
-			(yyval.node)->implicit = 1;
-		}
-	}
-    break;
-
-  case 144:
-#line 1033 "go.y"
-    {
-		(yyval.node) = (yyvsp[(2) - (4)].node);
-		(yyval.node)->list = (yyvsp[(3) - (4)].list);
-	}
-    break;
-
-  case 146:
-#line 1041 "go.y"
-    {
-		(yyval.node) = (yyvsp[(2) - (4)].node);
-		(yyval.node)->list = (yyvsp[(3) - (4)].list);
-	}
-    break;
-
-  case 148:
-#line 1049 "go.y"
-    {
-		(yyval.node) = (yyvsp[(2) - (3)].node);
-		
-		// Need to know on lhs of := whether there are ( ).
-		// Don't bother with the OPAREN in other cases:
-		// it's just a waste of memory and time.
-		switch((yyval.node)->op) {
-		case ONAME:
-		case ONONAME:
-		case OPACK:
-		case OTYPE:
-		case OLITERAL:
-		case OTYPESW:
-			(yyval.node) = nod(OPAREN, (yyval.node), N);
-		}
-	}
-    break;
-
-  case 152:
-#line 1075 "go.y"
-    {
-		(yyval.i) = LBODY;
-	}
-    break;
-
-  case 153:
-#line 1079 "go.y"
-    {
-		(yyval.i) = '{';
-	}
-    break;
-
-  case 154:
-#line 1090 "go.y"
-    {
-		if((yyvsp[(1) - (1)].sym) == S)
-			(yyval.node) = N;
-		else
-			(yyval.node) = newname((yyvsp[(1) - (1)].sym));
-	}
-    break;
-
-  case 155:
-#line 1099 "go.y"
-    {
-		(yyval.node) = dclname((yyvsp[(1) - (1)].sym));
-	}
-    break;
-
-  case 156:
-#line 1104 "go.y"
-    {
-		(yyval.node) = N;
-	}
-    break;
-
-  case 158:
-#line 1111 "go.y"
-    {
-		(yyval.sym) = (yyvsp[(1) - (1)].sym);
-		// during imports, unqualified non-exported identifiers are from builtinpkg
-		if(importpkg != nil && !exportname((yyvsp[(1) - (1)].sym)->name))
-			(yyval.sym) = pkglookup((yyvsp[(1) - (1)].sym)->name, builtinpkg);
-	}
-    break;
-
-  case 160:
-#line 1119 "go.y"
-    {
-		(yyval.sym) = S;
-	}
-    break;
-
-  case 161:
-#line 1125 "go.y"
-    {
-		Pkg *p;
-
-		if((yyvsp[(2) - (4)].val).u.sval->len == 0)
-			p = importpkg;
-		else {
-			if(isbadimport((yyvsp[(2) - (4)].val).u.sval))
-				errorexit();
-			p = mkpkg((yyvsp[(2) - (4)].val).u.sval);
-		}
-		(yyval.sym) = pkglookup((yyvsp[(4) - (4)].sym)->name, p);
-	}
-    break;
-
-  case 162:
-#line 1138 "go.y"
-    {
-		Pkg *p;
-
-		if((yyvsp[(2) - (4)].val).u.sval->len == 0)
-			p = importpkg;
-		else {
-			if(isbadimport((yyvsp[(2) - (4)].val).u.sval))
-				errorexit();
-			p = mkpkg((yyvsp[(2) - (4)].val).u.sval);
-		}
-		(yyval.sym) = pkglookup("?", p);
-	}
-    break;
-
-  case 163:
-#line 1153 "go.y"
-    {
-		(yyval.node) = oldname((yyvsp[(1) - (1)].sym));
-		if((yyval.node)->pack != N)
-			(yyval.node)->pack->used = 1;
-	}
-    break;
-
-  case 165:
-#line 1173 "go.y"
-    {
-		yyerror("final argument in variadic function missing type");
-		(yyval.node) = nod(ODDD, typenod(typ(TINTER)), N);
-	}
-    break;
-
-  case 166:
-#line 1178 "go.y"
-    {
-		(yyval.node) = nod(ODDD, (yyvsp[(2) - (2)].node), N);
-	}
-    break;
-
-  case 172:
-#line 1189 "go.y"
-    {
-		(yyval.node) = (yyvsp[(2) - (3)].node);
-	}
-    break;
-
-  case 176:
-#line 1198 "go.y"
-    {
-		(yyval.node) = nod(OIND, (yyvsp[(2) - (2)].node), N);
-	}
-    break;
-
-  case 181:
-#line 1208 "go.y"
-    {
-		(yyval.node) = (yyvsp[(2) - (3)].node);
-	}
-    break;
-
-  case 191:
-#line 1229 "go.y"
-    {
-		if((yyvsp[(1) - (3)].node)->op == OPACK) {
-			Sym *s;
-			s = restrictlookup((yyvsp[(3) - (3)].sym)->name, (yyvsp[(1) - (3)].node)->pkg);
-			(yyvsp[(1) - (3)].node)->used = 1;
-			(yyval.node) = oldname(s);
-			break;
-		}
-		(yyval.node) = nod(OXDOT, (yyvsp[(1) - (3)].node), newname((yyvsp[(3) - (3)].sym)));
-	}
-    break;
-
-  case 192:
-#line 1242 "go.y"
-    {
-		(yyval.node) = nod(OTARRAY, (yyvsp[(2) - (4)].node), (yyvsp[(4) - (4)].node));
-	}
-    break;
-
-  case 193:
-#line 1246 "go.y"
-    {
-		// array literal of nelem
-		(yyval.node) = nod(OTARRAY, nod(ODDD, N, N), (yyvsp[(4) - (4)].node));
-	}
-    break;
-
-  case 194:
-#line 1251 "go.y"
-    {
-		(yyval.node) = nod(OTCHAN, (yyvsp[(2) - (2)].node), N);
-		(yyval.node)->etype = Cboth;
-	}
-    break;
-
-  case 195:
-#line 1256 "go.y"
-    {
-		(yyval.node) = nod(OTCHAN, (yyvsp[(3) - (3)].node), N);
-		(yyval.node)->etype = Csend;
-	}
-    break;
-
-  case 196:
-#line 1261 "go.y"
-    {
-		(yyval.node) = nod(OTMAP, (yyvsp[(3) - (5)].node), (yyvsp[(5) - (5)].node));
-	}
-    break;
-
-  case 199:
-#line 1269 "go.y"
-    {
-		(yyval.node) = nod(OIND, (yyvsp[(2) - (2)].node), N);
-	}
-    break;
-
-  case 200:
-#line 1275 "go.y"
-    {
-		(yyval.node) = nod(OTCHAN, (yyvsp[(3) - (3)].node), N);
-		(yyval.node)->etype = Crecv;
-	}
-    break;
-
-  case 201:
-#line 1282 "go.y"
-    {
-		(yyval.node) = nod(OTSTRUCT, N, N);
-		(yyval.node)->list = (yyvsp[(3) - (5)].list);
-		fixlbrace((yyvsp[(2) - (5)].i));
-	}
-    break;
-
-  case 202:
-#line 1288 "go.y"
-    {
-		(yyval.node) = nod(OTSTRUCT, N, N);
-		fixlbrace((yyvsp[(2) - (3)].i));
-	}
-    break;
-
-  case 203:
-#line 1295 "go.y"
-    {
-		(yyval.node) = nod(OTINTER, N, N);
-		(yyval.node)->list = (yyvsp[(3) - (5)].list);
-		fixlbrace((yyvsp[(2) - (5)].i));
-	}
-    break;
-
-  case 204:
-#line 1301 "go.y"
-    {
-		(yyval.node) = nod(OTINTER, N, N);
-		fixlbrace((yyvsp[(2) - (3)].i));
-	}
-    break;
-
-  case 205:
-#line 1312 "go.y"
-    {
-		(yyval.node) = (yyvsp[(2) - (3)].node);
-		if((yyval.node) == N)
-			break;
-		if(noescape && (yyvsp[(3) - (3)].list) != nil)
-			yyerror("can only use //go:noescape with external func implementations");
-		(yyval.node)->nbody = (yyvsp[(3) - (3)].list);
-		(yyval.node)->endlineno = lineno;
-		(yyval.node)->noescape = noescape;
-		(yyval.node)->nosplit = nosplit;
-		funcbody((yyval.node));
-	}
-    break;
-
-  case 206:
-#line 1327 "go.y"
-    {
-		Node *t;
-
-		(yyval.node) = N;
-		(yyvsp[(3) - (5)].list) = checkarglist((yyvsp[(3) - (5)].list), 1);
-
-		if(strcmp((yyvsp[(1) - (5)].sym)->name, "init") == 0) {
-			(yyvsp[(1) - (5)].sym) = renameinit();
-			if((yyvsp[(3) - (5)].list) != nil || (yyvsp[(5) - (5)].list) != nil)
-				yyerror("func init must have no arguments and no return values");
-		}
-		if(strcmp(localpkg->name, "main") == 0 && strcmp((yyvsp[(1) - (5)].sym)->name, "main") == 0) {
-			if((yyvsp[(3) - (5)].list) != nil || (yyvsp[(5) - (5)].list) != nil)
-				yyerror("func main must have no arguments and no return values");
-		}
-
-		t = nod(OTFUNC, N, N);
-		t->list = (yyvsp[(3) - (5)].list);
-		t->rlist = (yyvsp[(5) - (5)].list);
-
-		(yyval.node) = nod(ODCLFUNC, N, N);
-		(yyval.node)->nname = newname((yyvsp[(1) - (5)].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);
-
-		funchdr((yyval.node));
-	}
-    break;
-
-  case 207:
-#line 1356 "go.y"
-    {
-		Node *rcvr, *t;
-
-		(yyval.node) = N;
-		(yyvsp[(2) - (8)].list) = checkarglist((yyvsp[(2) - (8)].list), 0);
-		(yyvsp[(6) - (8)].list) = checkarglist((yyvsp[(6) - (8)].list), 1);
-
-		if((yyvsp[(2) - (8)].list) == nil) {
-			yyerror("method has no receiver");
-			break;
-		}
-		if((yyvsp[(2) - (8)].list)->next != nil) {
-			yyerror("method has multiple receivers");
-			break;
-		}
-		rcvr = (yyvsp[(2) - (8)].list)->n;
-		if(rcvr->op != ODCLFIELD) {
-			yyerror("bad receiver in method");
-			break;
-		}
-
-		t = nod(OTFUNC, rcvr, N);
-		t->list = (yyvsp[(6) - (8)].list);
-		t->rlist = (yyvsp[(8) - (8)].list);
-
-		(yyval.node) = nod(ODCLFUNC, N, N);
-		(yyval.node)->shortname = newname((yyvsp[(4) - (8)].sym));
-		(yyval.node)->nname = methodname1((yyval.node)->shortname, rcvr->right);
-		(yyval.node)->nname->defn = (yyval.node);
-		(yyval.node)->nname->ntype = t;
-		(yyval.node)->nname->nointerface = nointerface;
-		declare((yyval.node)->nname, PFUNC);
-
-		funchdr((yyval.node));
-	}
-    break;
-
-  case 208:
-#line 1394 "go.y"
-    {
-		Sym *s;
-		Type *t;
-
-		(yyval.node) = N;
-
-		s = (yyvsp[(1) - (5)].sym);
-		t = functype(N, (yyvsp[(3) - (5)].list), (yyvsp[(5) - (5)].list));
-
-		importsym(s, ONAME);
-		if(s->def != N && s->def->op == ONAME) {
-			if(eqtype(t, s->def->type)) {
-				dclcontext = PDISCARD;  // since we skip funchdr below
-				break;
-			}
-			yyerror("inconsistent definition for func %S during import\n\t%T\n\t%T", s, s->def->type, t);
-		}
-
-		(yyval.node) = newname(s);
-		(yyval.node)->type = t;
-		declare((yyval.node), PFUNC);
-
-		funchdr((yyval.node));
-	}
-    break;
-
-  case 209:
-#line 1419 "go.y"
-    {
-		(yyval.node) = methodname1(newname((yyvsp[(4) - (8)].sym)), (yyvsp[(2) - (8)].list)->n->right); 
-		(yyval.node)->type = functype((yyvsp[(2) - (8)].list)->n, (yyvsp[(6) - (8)].list), (yyvsp[(8) - (8)].list));
-
-		checkwidth((yyval.node)->type);
-		addmethod((yyvsp[(4) - (8)].sym), (yyval.node)->type, 0, nointerface);
-		nointerface = 0;
-		funchdr((yyval.node));
-		
-		// inl.c's inlnode in on a dotmeth node expects to find the inlineable body as
-		// (dotmeth's type)->nname->inl, and dotmeth's type has been pulled
-		// out by typecheck's lookdot as this $$->ttype.  So by providing
-		// this back link here we avoid special casing there.
-		(yyval.node)->type->nname = (yyval.node);
-	}
-    break;
-
-  case 210:
-#line 1437 "go.y"
-    {
-		(yyvsp[(3) - (5)].list) = checkarglist((yyvsp[(3) - (5)].list), 1);
-		(yyval.node) = nod(OTFUNC, N, N);
-		(yyval.node)->list = (yyvsp[(3) - (5)].list);
-		(yyval.node)->rlist = (yyvsp[(5) - (5)].list);
-	}
-    break;
-
-  case 211:
-#line 1445 "go.y"
-    {
-		(yyval.list) = nil;
-	}
-    break;
-
-  case 212:
-#line 1449 "go.y"
-    {
-		(yyval.list) = (yyvsp[(2) - (3)].list);
-		if((yyval.list) == nil)
-			(yyval.list) = list1(nod(OEMPTY, N, N));
-	}
-    break;
-
-  case 213:
-#line 1457 "go.y"
-    {
-		(yyval.list) = nil;
-	}
-    break;
-
-  case 214:
-#line 1461 "go.y"
-    {
-		(yyval.list) = list1(nod(ODCLFIELD, N, (yyvsp[(1) - (1)].node)));
-	}
-    break;
-
-  case 215:
-#line 1465 "go.y"
-    {
-		(yyvsp[(2) - (3)].list) = checkarglist((yyvsp[(2) - (3)].list), 0);
-		(yyval.list) = (yyvsp[(2) - (3)].list);
-	}
-    break;
-
-  case 216:
-#line 1472 "go.y"
-    {
-		closurehdr((yyvsp[(1) - (1)].node));
-	}
-    break;
-
-  case 217:
-#line 1478 "go.y"
-    {
-		(yyval.node) = closurebody((yyvsp[(3) - (4)].list));
-		fixlbrace((yyvsp[(2) - (4)].i));
-	}
-    break;
-
-  case 218:
-#line 1483 "go.y"
-    {
-		(yyval.node) = closurebody(nil);
-	}
-    break;
-
-  case 219:
-#line 1494 "go.y"
-    {
-		(yyval.list) = nil;
-	}
-    break;
-
-  case 220:
-#line 1498 "go.y"
-    {
-		(yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(2) - (3)].list));
-		if(nsyntaxerrors == 0)
-			testdclstack();
-		nointerface = 0;
-		noescape = 0;
-		nosplit = 0;
-	}
-    break;
-
-  case 222:
-#line 1510 "go.y"
-    {
-		(yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list));
-	}
-    break;
-
-  case 224:
-#line 1517 "go.y"
-    {
-		(yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list));
-	}
-    break;
-
-  case 225:
-#line 1523 "go.y"
-    {
-		(yyval.list) = list1((yyvsp[(1) - (1)].node));
-	}
-    break;
-
-  case 226:
-#line 1527 "go.y"
-    {
-		(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 228:
-#line 1534 "go.y"
-    {
-		(yyval.list) = concat((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].list));
-	}
-    break;
-
-  case 229:
-#line 1540 "go.y"
-    {
-		(yyval.list) = list1((yyvsp[(1) - (1)].node));
-	}
-    break;
-
-  case 230:
-#line 1544 "go.y"
-    {
-		(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 231:
-#line 1550 "go.y"
-    {
-		NodeList *l;
-
-		Node *n;
-		l = (yyvsp[(1) - (3)].list);
-		if(l == nil) {
-			// ? symbol, during import (list1(N) == nil)
-			n = (yyvsp[(2) - (3)].node);
-			if(n->op == OIND)
-				n = n->left;
-			n = embedded(n->sym, importpkg);
-			n->right = (yyvsp[(2) - (3)].node);
-			n->val = (yyvsp[(3) - (3)].val);
-			(yyval.list) = list1(n);
-			break;
-		}
-
-		for(l=(yyvsp[(1) - (3)].list); l; l=l->next) {
-			l->n = nod(ODCLFIELD, l->n, (yyvsp[(2) - (3)].node));
-			l->n->val = (yyvsp[(3) - (3)].val);
-		}
-	}
-    break;
-
-  case 232:
-#line 1573 "go.y"
-    {
-		(yyvsp[(1) - (2)].node)->val = (yyvsp[(2) - (2)].val);
-		(yyval.list) = list1((yyvsp[(1) - (2)].node));
-	}
-    break;
-
-  case 233:
-#line 1578 "go.y"
-    {
-		(yyvsp[(2) - (4)].node)->val = (yyvsp[(4) - (4)].val);
-		(yyval.list) = list1((yyvsp[(2) - (4)].node));
-		yyerror("cannot parenthesize embedded type");
-	}
-    break;
-
-  case 234:
-#line 1584 "go.y"
-    {
-		(yyvsp[(2) - (3)].node)->right = nod(OIND, (yyvsp[(2) - (3)].node)->right, N);
-		(yyvsp[(2) - (3)].node)->val = (yyvsp[(3) - (3)].val);
-		(yyval.list) = list1((yyvsp[(2) - (3)].node));
-	}
-    break;
-
-  case 235:
-#line 1590 "go.y"
-    {
-		(yyvsp[(3) - (5)].node)->right = nod(OIND, (yyvsp[(3) - (5)].node)->right, N);
-		(yyvsp[(3) - (5)].node)->val = (yyvsp[(5) - (5)].val);
-		(yyval.list) = list1((yyvsp[(3) - (5)].node));
-		yyerror("cannot parenthesize embedded type");
-	}
-    break;
-
-  case 236:
-#line 1597 "go.y"
-    {
-		(yyvsp[(3) - (5)].node)->right = nod(OIND, (yyvsp[(3) - (5)].node)->right, N);
-		(yyvsp[(3) - (5)].node)->val = (yyvsp[(5) - (5)].val);
-		(yyval.list) = list1((yyvsp[(3) - (5)].node));
-		yyerror("cannot parenthesize embedded type");
-	}
-    break;
-
-  case 237:
-#line 1606 "go.y"
-    {
-		Node *n;
-
-		(yyval.sym) = (yyvsp[(1) - (1)].sym);
-		n = oldname((yyvsp[(1) - (1)].sym));
-		if(n->pack != N)
-			n->pack->used = 1;
-	}
-    break;
-
-  case 238:
-#line 1615 "go.y"
-    {
-		Pkg *pkg;
-
-		if((yyvsp[(1) - (3)].sym)->def == N || (yyvsp[(1) - (3)].sym)->def->op != OPACK) {
-			yyerror("%S is not a package", (yyvsp[(1) - (3)].sym));
-			pkg = localpkg;
-		} else {
-			(yyvsp[(1) - (3)].sym)->def->used = 1;
-			pkg = (yyvsp[(1) - (3)].sym)->def->pkg;
-		}
-		(yyval.sym) = restrictlookup((yyvsp[(3) - (3)].sym)->name, pkg);
-	}
-    break;
-
-  case 239:
-#line 1630 "go.y"
-    {
-		(yyval.node) = embedded((yyvsp[(1) - (1)].sym), localpkg);
-	}
-    break;
-
-  case 240:
-#line 1636 "go.y"
-    {
-		(yyval.node) = nod(ODCLFIELD, (yyvsp[(1) - (2)].node), (yyvsp[(2) - (2)].node));
-		ifacedcl((yyval.node));
-	}
-    break;
-
-  case 241:
-#line 1641 "go.y"
-    {
-		(yyval.node) = nod(ODCLFIELD, N, oldname((yyvsp[(1) - (1)].sym)));
-	}
-    break;
-
-  case 242:
-#line 1645 "go.y"
-    {
-		(yyval.node) = nod(ODCLFIELD, N, oldname((yyvsp[(2) - (3)].sym)));
-		yyerror("cannot parenthesize embedded type");
-	}
-    break;
-
-  case 243:
-#line 1652 "go.y"
-    {
-		// without func keyword
-		(yyvsp[(2) - (4)].list) = checkarglist((yyvsp[(2) - (4)].list), 1);
-		(yyval.node) = nod(OTFUNC, fakethis(), N);
-		(yyval.node)->list = (yyvsp[(2) - (4)].list);
-		(yyval.node)->rlist = (yyvsp[(4) - (4)].list);
-	}
-    break;
-
-  case 245:
-#line 1666 "go.y"
-    {
-		(yyval.node) = nod(ONONAME, N, N);
-		(yyval.node)->sym = (yyvsp[(1) - (2)].sym);
-		(yyval.node) = nod(OKEY, (yyval.node), (yyvsp[(2) - (2)].node));
-	}
-    break;
-
-  case 246:
-#line 1672 "go.y"
-    {
-		(yyval.node) = nod(ONONAME, N, N);
-		(yyval.node)->sym = (yyvsp[(1) - (2)].sym);
-		(yyval.node) = nod(OKEY, (yyval.node), (yyvsp[(2) - (2)].node));
-	}
-    break;
-
-  case 248:
-#line 1681 "go.y"
-    {
-		(yyval.list) = list1((yyvsp[(1) - (1)].node));
-	}
-    break;
-
-  case 249:
-#line 1685 "go.y"
-    {
-		(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 250:
-#line 1690 "go.y"
-    {
-		(yyval.list) = nil;
-	}
-    break;
-
-  case 251:
-#line 1694 "go.y"
-    {
-		(yyval.list) = (yyvsp[(1) - (2)].list);
-	}
-    break;
-
-  case 252:
-#line 1702 "go.y"
-    {
-		(yyval.node) = N;
-	}
-    break;
-
-  case 254:
-#line 1707 "go.y"
-    {
-		(yyval.node) = liststmt((yyvsp[(1) - (1)].list));
-	}
-    break;
-
-  case 256:
-#line 1712 "go.y"
-    {
-		(yyval.node) = N;
-	}
-    break;
-
-  case 262:
-#line 1723 "go.y"
-    {
-		(yyvsp[(1) - (2)].node) = nod(OLABEL, (yyvsp[(1) - (2)].node), N);
-		(yyvsp[(1) - (2)].node)->sym = dclstack;  // context, for goto restrictions
-	}
-    break;
-
-  case 263:
-#line 1728 "go.y"
-    {
-		NodeList *l;
-
-		(yyvsp[(1) - (4)].node)->defn = (yyvsp[(4) - (4)].node);
-		l = list1((yyvsp[(1) - (4)].node));
-		if((yyvsp[(4) - (4)].node))
-			l = list(l, (yyvsp[(4) - (4)].node));
-		(yyval.node) = liststmt(l);
-	}
-    break;
-
-  case 264:
-#line 1738 "go.y"
-    {
-		// will be converted to OFALL
-		(yyval.node) = nod(OXFALL, N, N);
-		(yyval.node)->xoffset = block;
-	}
-    break;
-
-  case 265:
-#line 1744 "go.y"
-    {
-		(yyval.node) = nod(OBREAK, (yyvsp[(2) - (2)].node), N);
-	}
-    break;
-
-  case 266:
-#line 1748 "go.y"
-    {
-		(yyval.node) = nod(OCONTINUE, (yyvsp[(2) - (2)].node), N);
-	}
-    break;
-
-  case 267:
-#line 1752 "go.y"
-    {
-		(yyval.node) = nod(OPROC, (yyvsp[(2) - (2)].node), N);
-	}
-    break;
-
-  case 268:
-#line 1756 "go.y"
-    {
-		(yyval.node) = nod(ODEFER, (yyvsp[(2) - (2)].node), N);
-	}
-    break;
-
-  case 269:
-#line 1760 "go.y"
-    {
-		(yyval.node) = nod(OGOTO, (yyvsp[(2) - (2)].node), N);
-		(yyval.node)->sym = dclstack;  // context, for goto restrictions
-	}
-    break;
-
-  case 270:
-#line 1765 "go.y"
-    {
-		(yyval.node) = nod(ORETURN, N, N);
-		(yyval.node)->list = (yyvsp[(2) - (2)].list);
-		if((yyval.node)->list == nil && curfn != N) {
-			NodeList *l;
-
-			for(l=curfn->dcl; l; l=l->next) {
-				if(l->n->class == PPARAM)
-					continue;
-				if(l->n->class != PPARAMOUT)
-					break;
-				if(l->n->sym->def != l->n)
-					yyerror("%s is shadowed during return", l->n->sym->name);
-			}
-		}
-	}
-    break;
-
-  case 271:
-#line 1784 "go.y"
-    {
-		(yyval.list) = nil;
-		if((yyvsp[(1) - (1)].node) != N)
-			(yyval.list) = list1((yyvsp[(1) - (1)].node));
-	}
-    break;
-
-  case 272:
-#line 1790 "go.y"
-    {
-		(yyval.list) = (yyvsp[(1) - (3)].list);
-		if((yyvsp[(3) - (3)].node) != N)
-			(yyval.list) = list((yyval.list), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 273:
-#line 1798 "go.y"
-    {
-		(yyval.list) = list1((yyvsp[(1) - (1)].node));
-	}
-    break;
-
-  case 274:
-#line 1802 "go.y"
-    {
-		(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 275:
-#line 1808 "go.y"
-    {
-		(yyval.list) = list1((yyvsp[(1) - (1)].node));
-	}
-    break;
-
-  case 276:
-#line 1812 "go.y"
-    {
-		(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 277:
-#line 1818 "go.y"
-    {
-		(yyval.list) = list1((yyvsp[(1) - (1)].node));
-	}
-    break;
-
-  case 278:
-#line 1822 "go.y"
-    {
-		(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 279:
-#line 1828 "go.y"
-    {
-		(yyval.list) = list1((yyvsp[(1) - (1)].node));
-	}
-    break;
-
-  case 280:
-#line 1832 "go.y"
-    {
-		(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 281:
-#line 1841 "go.y"
-    {
-		(yyval.list) = list1((yyvsp[(1) - (1)].node));
-	}
-    break;
-
-  case 282:
-#line 1845 "go.y"
-    {
-		(yyval.list) = list1((yyvsp[(1) - (1)].node));
-	}
-    break;
-
-  case 283:
-#line 1849 "go.y"
-    {
-		(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 284:
-#line 1853 "go.y"
-    {
-		(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 285:
-#line 1858 "go.y"
-    {
-		(yyval.list) = nil;
-	}
-    break;
-
-  case 286:
-#line 1862 "go.y"
-    {
-		(yyval.list) = (yyvsp[(1) - (2)].list);
-	}
-    break;
-
-  case 291:
-#line 1876 "go.y"
-    {
-		(yyval.node) = N;
-	}
-    break;
-
-  case 293:
-#line 1882 "go.y"
-    {
-		(yyval.list) = nil;
-	}
-    break;
-
-  case 295:
-#line 1888 "go.y"
-    {
-		(yyval.node) = N;
-	}
-    break;
-
-  case 297:
-#line 1894 "go.y"
-    {
-		(yyval.list) = nil;
-	}
-    break;
-
-  case 299:
-#line 1900 "go.y"
-    {
-		(yyval.list) = nil;
-	}
-    break;
-
-  case 301:
-#line 1906 "go.y"
-    {
-		(yyval.list) = nil;
-	}
-    break;
-
-  case 303:
-#line 1912 "go.y"
-    {
-		(yyval.val).ctype = CTxxx;
-	}
-    break;
-
-  case 305:
-#line 1922 "go.y"
-    {
-		importimport((yyvsp[(2) - (4)].sym), (yyvsp[(3) - (4)].val).u.sval);
-	}
-    break;
-
-  case 306:
-#line 1926 "go.y"
-    {
-		importvar((yyvsp[(2) - (4)].sym), (yyvsp[(3) - (4)].type));
-	}
-    break;
-
-  case 307:
-#line 1930 "go.y"
-    {
-		importconst((yyvsp[(2) - (5)].sym), types[TIDEAL], (yyvsp[(4) - (5)].node));
-	}
-    break;
-
-  case 308:
-#line 1934 "go.y"
-    {
-		importconst((yyvsp[(2) - (6)].sym), (yyvsp[(3) - (6)].type), (yyvsp[(5) - (6)].node));
-	}
-    break;
-
-  case 309:
-#line 1938 "go.y"
-    {
-		importtype((yyvsp[(2) - (4)].type), (yyvsp[(3) - (4)].type));
-	}
-    break;
-
-  case 310:
-#line 1942 "go.y"
-    {
-		if((yyvsp[(2) - (4)].node) == N) {
-			dclcontext = PEXTERN;  // since we skip the funcbody below
-			break;
-		}
-
-		(yyvsp[(2) - (4)].node)->inl = (yyvsp[(3) - (4)].list);
-
-		funcbody((yyvsp[(2) - (4)].node));
-		importlist = list(importlist, (yyvsp[(2) - (4)].node));
-
-		if(debug['E']) {
-			print("import [%Z] func %lN \n", importpkg->path, (yyvsp[(2) - (4)].node));
-			if(debug['m'] > 2 && (yyvsp[(2) - (4)].node)->inl)
-				print("inl body:%+H\n", (yyvsp[(2) - (4)].node)->inl);
-		}
-	}
-    break;
-
-  case 311:
-#line 1962 "go.y"
-    {
-		(yyval.sym) = (yyvsp[(1) - (1)].sym);
-		structpkg = (yyval.sym)->pkg;
-	}
-    break;
-
-  case 312:
-#line 1969 "go.y"
-    {
-		(yyval.type) = pkgtype((yyvsp[(1) - (1)].sym));
-		importsym((yyvsp[(1) - (1)].sym), OTYPE);
-	}
-    break;
-
-  case 318:
-#line 1989 "go.y"
-    {
-		(yyval.type) = pkgtype((yyvsp[(1) - (1)].sym));
-	}
-    break;
-
-  case 319:
-#line 1993 "go.y"
-    {
-		// predefined name like uint8
-		(yyvsp[(1) - (1)].sym) = pkglookup((yyvsp[(1) - (1)].sym)->name, builtinpkg);
-		if((yyvsp[(1) - (1)].sym)->def == N || (yyvsp[(1) - (1)].sym)->def->op != OTYPE) {
-			yyerror("%s is not a type", (yyvsp[(1) - (1)].sym)->name);
-			(yyval.type) = T;
-		} else
-			(yyval.type) = (yyvsp[(1) - (1)].sym)->def->type;
-	}
-    break;
-
-  case 320:
-#line 2003 "go.y"
-    {
-		(yyval.type) = aindex(N, (yyvsp[(3) - (3)].type));
-	}
-    break;
-
-  case 321:
-#line 2007 "go.y"
-    {
-		(yyval.type) = aindex(nodlit((yyvsp[(2) - (4)].val)), (yyvsp[(4) - (4)].type));
-	}
-    break;
-
-  case 322:
-#line 2011 "go.y"
-    {
-		(yyval.type) = maptype((yyvsp[(3) - (5)].type), (yyvsp[(5) - (5)].type));
-	}
-    break;
-
-  case 323:
-#line 2015 "go.y"
-    {
-		(yyval.type) = tostruct((yyvsp[(3) - (4)].list));
-	}
-    break;
-
-  case 324:
-#line 2019 "go.y"
-    {
-		(yyval.type) = tointerface((yyvsp[(3) - (4)].list));
-	}
-    break;
-
-  case 325:
-#line 2023 "go.y"
-    {
-		(yyval.type) = ptrto((yyvsp[(2) - (2)].type));
-	}
-    break;
-
-  case 326:
-#line 2027 "go.y"
-    {
-		(yyval.type) = typ(TCHAN);
-		(yyval.type)->type = (yyvsp[(2) - (2)].type);
-		(yyval.type)->chan = Cboth;
-	}
-    break;
-
-  case 327:
-#line 2033 "go.y"
-    {
-		(yyval.type) = typ(TCHAN);
-		(yyval.type)->type = (yyvsp[(3) - (4)].type);
-		(yyval.type)->chan = Cboth;
-	}
-    break;
-
-  case 328:
-#line 2039 "go.y"
-    {
-		(yyval.type) = typ(TCHAN);
-		(yyval.type)->type = (yyvsp[(3) - (3)].type);
-		(yyval.type)->chan = Csend;
-	}
-    break;
-
-  case 329:
-#line 2047 "go.y"
-    {
-		(yyval.type) = typ(TCHAN);
-		(yyval.type)->type = (yyvsp[(3) - (3)].type);
-		(yyval.type)->chan = Crecv;
-	}
-    break;
-
-  case 330:
-#line 2055 "go.y"
-    {
-		(yyval.type) = functype(nil, (yyvsp[(3) - (5)].list), (yyvsp[(5) - (5)].list));
-	}
-    break;
-
-  case 331:
-#line 2061 "go.y"
-    {
-		(yyval.node) = nod(ODCLFIELD, N, typenod((yyvsp[(2) - (3)].type)));
-		if((yyvsp[(1) - (3)].sym))
-			(yyval.node)->left = newname((yyvsp[(1) - (3)].sym));
-		(yyval.node)->val = (yyvsp[(3) - (3)].val);
-	}
-    break;
-
-  case 332:
-#line 2068 "go.y"
-    {
-		Type *t;
-	
-		t = typ(TARRAY);
-		t->bound = -1;
-		t->type = (yyvsp[(3) - (4)].type);
-
-		(yyval.node) = nod(ODCLFIELD, N, typenod(t));
-		if((yyvsp[(1) - (4)].sym))
-			(yyval.node)->left = newname((yyvsp[(1) - (4)].sym));
-		(yyval.node)->isddd = 1;
-		(yyval.node)->val = (yyvsp[(4) - (4)].val);
-	}
-    break;
-
-  case 333:
-#line 2084 "go.y"
-    {
-		Sym *s;
-		Pkg *p;
-
-		if((yyvsp[(1) - (3)].sym) != S && strcmp((yyvsp[(1) - (3)].sym)->name, "?") != 0) {
-			(yyval.node) = nod(ODCLFIELD, newname((yyvsp[(1) - (3)].sym)), typenod((yyvsp[(2) - (3)].type)));
-			(yyval.node)->val = (yyvsp[(3) - (3)].val);
-		} else {
-			s = (yyvsp[(2) - (3)].type)->sym;
-			if(s == S && isptr[(yyvsp[(2) - (3)].type)->etype])
-				s = (yyvsp[(2) - (3)].type)->type->sym;
-			p = importpkg;
-			if((yyvsp[(1) - (3)].sym) != S)
-				p = (yyvsp[(1) - (3)].sym)->pkg;
-			(yyval.node) = embedded(s, p);
-			(yyval.node)->right = typenod((yyvsp[(2) - (3)].type));
-			(yyval.node)->val = (yyvsp[(3) - (3)].val);
-		}
-	}
-    break;
-
-  case 334:
-#line 2106 "go.y"
-    {
-		(yyval.node) = nod(ODCLFIELD, newname((yyvsp[(1) - (5)].sym)), typenod(functype(fakethis(), (yyvsp[(3) - (5)].list), (yyvsp[(5) - (5)].list))));
-	}
-    break;
-
-  case 335:
-#line 2110 "go.y"
-    {
-		(yyval.node) = nod(ODCLFIELD, N, typenod((yyvsp[(1) - (1)].type)));
-	}
-    break;
-
-  case 336:
-#line 2115 "go.y"
-    {
-		(yyval.list) = nil;
-	}
-    break;
-
-  case 338:
-#line 2122 "go.y"
-    {
-		(yyval.list) = (yyvsp[(2) - (3)].list);
-	}
-    break;
-
-  case 339:
-#line 2126 "go.y"
-    {
-		(yyval.list) = list1(nod(ODCLFIELD, N, typenod((yyvsp[(1) - (1)].type))));
-	}
-    break;
-
-  case 340:
-#line 2136 "go.y"
-    {
-		(yyval.node) = nodlit((yyvsp[(1) - (1)].val));
-	}
-    break;
-
-  case 341:
-#line 2140 "go.y"
-    {
-		(yyval.node) = nodlit((yyvsp[(2) - (2)].val));
-		switch((yyval.node)->val.ctype){
-		case CTINT:
-		case CTRUNE:
-			mpnegfix((yyval.node)->val.u.xval);
-			break;
-		case CTFLT:
-			mpnegflt((yyval.node)->val.u.fval);
-			break;
-		case CTCPLX:
-			mpnegflt(&(yyval.node)->val.u.cval->real);
-			mpnegflt(&(yyval.node)->val.u.cval->imag);
-			break;
-		default:
-			yyerror("bad negated constant");
-		}
-	}
-    break;
-
-  case 342:
-#line 2159 "go.y"
-    {
-		(yyval.node) = oldname(pkglookup((yyvsp[(1) - (1)].sym)->name, builtinpkg));
-		if((yyval.node)->op != OLITERAL)
-			yyerror("bad constant %S", (yyval.node)->sym);
-	}
-    break;
-
-  case 344:
-#line 2168 "go.y"
-    {
-		if((yyvsp[(2) - (5)].node)->val.ctype == CTRUNE && (yyvsp[(4) - (5)].node)->val.ctype == CTINT) {
-			(yyval.node) = (yyvsp[(2) - (5)].node);
-			mpaddfixfix((yyvsp[(2) - (5)].node)->val.u.xval, (yyvsp[(4) - (5)].node)->val.u.xval, 0);
-			break;
-		}
-		(yyvsp[(4) - (5)].node)->val.u.cval->real = (yyvsp[(4) - (5)].node)->val.u.cval->imag;
-		mpmovecflt(&(yyvsp[(4) - (5)].node)->val.u.cval->imag, 0.0);
-		(yyval.node) = nodcplxlit((yyvsp[(2) - (5)].node)->val, (yyvsp[(4) - (5)].node)->val);
-	}
-    break;
-
-  case 347:
-#line 2184 "go.y"
-    {
-		(yyval.list) = list1((yyvsp[(1) - (1)].node));
-	}
-    break;
-
-  case 348:
-#line 2188 "go.y"
-    {
-		(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 349:
-#line 2194 "go.y"
-    {
-		(yyval.list) = list1((yyvsp[(1) - (1)].node));
-	}
-    break;
-
-  case 350:
-#line 2198 "go.y"
-    {
-		(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-  case 351:
-#line 2204 "go.y"
-    {
-		(yyval.list) = list1((yyvsp[(1) - (1)].node));
-	}
-    break;
-
-  case 352:
-#line 2208 "go.y"
-    {
-		(yyval.list) = list((yyvsp[(1) - (3)].list), (yyvsp[(3) - (3)].node));
-	}
-    break;
-
-
-/* Line 1267 of yacc.c.  */
-#line 4907 "y.tab.c"
-      default: break;
-    }
-  YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
-
-  YYPOPSTACK (yylen);
-  yylen = 0;
-  YY_STACK_PRINT (yyss, yyssp);
-
-  *++yyvsp = yyval;
-
-
-  /* Now `shift' the result of the reduction.  Determine what state
-     that goes to, based on the state we popped back to and the rule
-     number reduced by.  */
-
-  yyn = yyr1[yyn];
-
-  yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
-  if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
-    yystate = yytable[yystate];
-  else
-    yystate = yydefgoto[yyn - YYNTOKENS];
-
-  goto yynewstate;
-
-
-/*------------------------------------.
-| yyerrlab -- here on detecting error |
-`------------------------------------*/
-yyerrlab:
-  /* If not already recovering from an error, report this error.  */
-  if (!yyerrstatus)
-    {
-      ++yynerrs;
-#if ! YYERROR_VERBOSE
-      yyerror (YY_("syntax error"));
-#else
-      {
-	YYSIZE_T yysize = yysyntax_error (0, yystate, yychar);
-	if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM)
-	  {
-	    YYSIZE_T yyalloc = 2 * yysize;
-	    if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM))
-	      yyalloc = YYSTACK_ALLOC_MAXIMUM;
-	    if (yymsg != yymsgbuf)
-	      YYSTACK_FREE (yymsg);
-	    yymsg = (char *) YYSTACK_ALLOC (yyalloc);
-	    if (yymsg)
-	      yymsg_alloc = yyalloc;
-	    else
-	      {
-		yymsg = yymsgbuf;
-		yymsg_alloc = sizeof yymsgbuf;
-	      }
-	  }
-
-	if (0 < yysize && yysize <= yymsg_alloc)
-	  {
-	    (void) yysyntax_error (yymsg, yystate, yychar);
-	    yyerror (yymsg);
-	  }
-	else
-	  {
-	    yyerror (YY_("syntax error"));
-	    if (yysize != 0)
-	      goto yyexhaustedlab;
-	  }
-      }
-#endif
-    }
-
-
-
-  if (yyerrstatus == 3)
-    {
-      /* If just tried and failed to reuse look-ahead token after an
-	 error, discard it.  */
-
-      if (yychar <= YYEOF)
-	{
-	  /* Return failure if at end of input.  */
-	  if (yychar == YYEOF)
-	    YYABORT;
-	}
-      else
-	{
-	  yydestruct ("Error: discarding",
-		      yytoken, &yylval);
-	  yychar = YYEMPTY;
-	}
-    }
-
-  /* Else will try to reuse look-ahead token after shifting the error
-     token.  */
-  goto yyerrlab1;
-
-
-/*---------------------------------------------------.
-| yyerrorlab -- error raised explicitly by YYERROR.  |
-`---------------------------------------------------*/
-yyerrorlab:
-
-  /* Pacify compilers like GCC when the user code never invokes
-     YYERROR and the label yyerrorlab therefore never appears in user
-     code.  */
-  if (/*CONSTCOND*/ 0)
-     goto yyerrorlab;
-
-  /* Do not reclaim the symbols of the rule which action triggered
-     this YYERROR.  */
-  YYPOPSTACK (yylen);
-  yylen = 0;
-  YY_STACK_PRINT (yyss, yyssp);
-  yystate = *yyssp;
-  goto yyerrlab1;
-
-
-/*-------------------------------------------------------------.
-| yyerrlab1 -- common code for both syntax error and YYERROR.  |
-`-------------------------------------------------------------*/
-yyerrlab1:
-  yyerrstatus = 3;	/* Each real token shifted decrements this.  */
-
-  for (;;)
-    {
-      yyn = yypact[yystate];
-      if (yyn != YYPACT_NINF)
-	{
-	  yyn += YYTERROR;
-	  if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
-	    {
-	      yyn = yytable[yyn];
-	      if (0 < yyn)
-		break;
-	    }
-	}
-
-      /* Pop the current state because it cannot handle the error token.  */
-      if (yyssp == yyss)
-	YYABORT;
-
-
-      yydestruct ("Error: popping",
-		  yystos[yystate], yyvsp);
-      YYPOPSTACK (1);
-      yystate = *yyssp;
-      YY_STACK_PRINT (yyss, yyssp);
-    }
-
-  if (yyn == YYFINAL)
-    YYACCEPT;
-
-  *++yyvsp = yylval;
-
-
-  /* Shift the error token.  */
-  YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
-
-  yystate = yyn;
-  goto yynewstate;
-
-
-/*-------------------------------------.
-| yyacceptlab -- YYACCEPT comes here.  |
-`-------------------------------------*/
-yyacceptlab:
-  yyresult = 0;
-  goto yyreturn;
-
-/*-----------------------------------.
-| yyabortlab -- YYABORT comes here.  |
-`-----------------------------------*/
-yyabortlab:
-  yyresult = 1;
-  goto yyreturn;
-
-#ifndef yyoverflow
-/*-------------------------------------------------.
-| yyexhaustedlab -- memory exhaustion comes here.  |
-`-------------------------------------------------*/
-yyexhaustedlab:
-  yyerror (YY_("memory exhausted"));
-  yyresult = 2;
-  /* Fall through.  */
-#endif
-
-yyreturn:
-  if (yychar != YYEOF && yychar != YYEMPTY)
-     yydestruct ("Cleanup: discarding lookahead",
-		 yytoken, &yylval);
-  /* Do not reclaim the symbols of the rule which action triggered
-     this YYABORT or YYACCEPT.  */
-  YYPOPSTACK (yylen);
-  YY_STACK_PRINT (yyss, yyssp);
-  while (yyssp != yyss)
-    {
-      yydestruct ("Cleanup: popping",
-		  yystos[*yyssp], yyvsp);
-      YYPOPSTACK (1);
-    }
-#ifndef yyoverflow
-  if (yyss != yyssa)
-    YYSTACK_FREE (yyss);
-#endif
-#if YYERROR_VERBOSE
-  if (yymsg != yymsgbuf)
-    YYSTACK_FREE (yymsg);
-#endif
-  /* Make sure YYID is used.  */
-  return YYID (yyresult);
-}
-
-
-#line 2212 "go.y"
-
-
-static void
-fixlbrace(int lbr)
-{
-	// If the opening brace was an LBODY,
-	// set up for another one now that we're done.
-	// See comment in lex.c about loophack.
-	if(lbr == LBODY)
-		loophack = 1;
-}
-
-
diff --git a/src/cmd/gc/y.tab.h b/src/cmd/gc/y.tab.h
deleted file mode 100644
index d01fbe1..0000000
--- a/src/cmd/gc/y.tab.h
+++ /dev/null
@@ -1,167 +0,0 @@
-/* A Bison parser, made by GNU Bison 2.3.  */
-
-/* Skeleton interface for Bison's Yacc-like parsers in C
-
-   Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
-   Free Software Foundation, Inc.
-
-   This program is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2, or (at your option)
-   any later version.
-
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301, USA.  */
-
-/* As a special exception, you may create a larger work that contains
-   part or all of the Bison parser skeleton and distribute that work
-   under terms of your choice, so long as that work isn't itself a
-   parser generator using the skeleton or a modified version thereof
-   as a parser skeleton.  Alternatively, if you modify or redistribute
-   the parser skeleton itself, you may (at your option) remove this
-   special exception, which will cause the skeleton and the resulting
-   Bison output files to be licensed under the GNU General Public
-   License without this special exception.
-
-   This special exception was added by the Free Software Foundation in
-   version 2.2 of Bison.  */
-
-/* Tokens.  */
-#ifndef YYTOKENTYPE
-# define YYTOKENTYPE
-   /* Put the tokens into the symbol table, so that GDB and other debuggers
-      know about them.  */
-   enum yytokentype {
-     LLITERAL = 258,
-     LASOP = 259,
-     LCOLAS = 260,
-     LBREAK = 261,
-     LCASE = 262,
-     LCHAN = 263,
-     LCONST = 264,
-     LCONTINUE = 265,
-     LDDD = 266,
-     LDEFAULT = 267,
-     LDEFER = 268,
-     LELSE = 269,
-     LFALL = 270,
-     LFOR = 271,
-     LFUNC = 272,
-     LGO = 273,
-     LGOTO = 274,
-     LIF = 275,
-     LIMPORT = 276,
-     LINTERFACE = 277,
-     LMAP = 278,
-     LNAME = 279,
-     LPACKAGE = 280,
-     LRANGE = 281,
-     LRETURN = 282,
-     LSELECT = 283,
-     LSTRUCT = 284,
-     LSWITCH = 285,
-     LTYPE = 286,
-     LVAR = 287,
-     LANDAND = 288,
-     LANDNOT = 289,
-     LBODY = 290,
-     LCOMM = 291,
-     LDEC = 292,
-     LEQ = 293,
-     LGE = 294,
-     LGT = 295,
-     LIGNORE = 296,
-     LINC = 297,
-     LLE = 298,
-     LLSH = 299,
-     LLT = 300,
-     LNE = 301,
-     LOROR = 302,
-     LRSH = 303,
-     NotPackage = 304,
-     NotParen = 305,
-     PreferToRightParen = 306
-   };
-#endif
-/* Tokens.  */
-#define LLITERAL 258
-#define LASOP 259
-#define LCOLAS 260
-#define LBREAK 261
-#define LCASE 262
-#define LCHAN 263
-#define LCONST 264
-#define LCONTINUE 265
-#define LDDD 266
-#define LDEFAULT 267
-#define LDEFER 268
-#define LELSE 269
-#define LFALL 270
-#define LFOR 271
-#define LFUNC 272
-#define LGO 273
-#define LGOTO 274
-#define LIF 275
-#define LIMPORT 276
-#define LINTERFACE 277
-#define LMAP 278
-#define LNAME 279
-#define LPACKAGE 280
-#define LRANGE 281
-#define LRETURN 282
-#define LSELECT 283
-#define LSTRUCT 284
-#define LSWITCH 285
-#define LTYPE 286
-#define LVAR 287
-#define LANDAND 288
-#define LANDNOT 289
-#define LBODY 290
-#define LCOMM 291
-#define LDEC 292
-#define LEQ 293
-#define LGE 294
-#define LGT 295
-#define LIGNORE 296
-#define LINC 297
-#define LLE 298
-#define LLSH 299
-#define LLT 300
-#define LNE 301
-#define LOROR 302
-#define LRSH 303
-#define NotPackage 304
-#define NotParen 305
-#define PreferToRightParen 306
-
-
-
-
-#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-typedef union YYSTYPE
-#line 28 "go.y"
-{
-	Node*		node;
-	NodeList*		list;
-	Type*		type;
-	Sym*		sym;
-	struct	Val	val;
-	int		i;
-}
-/* Line 1529 of yacc.c.  */
-#line 160 "y.tab.h"
-	YYSTYPE;
-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
-# define YYSTYPE_IS_DECLARED 1
-# define YYSTYPE_IS_TRIVIAL 1
-#endif
-
-extern YYSTYPE yylval;
-
diff --git a/src/cmd/gc/yerr.h b/src/cmd/gc/yerr.h
deleted file mode 100644
index d0dd639..0000000
--- a/src/cmd/gc/yerr.h
+++ /dev/null
@@ -1,79 +0,0 @@
-// Copyright 2010 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.
-
-// Example-based syntax error messages.
-// See bisonerrors, Makefile, go.y.
-
-static struct {
-	int yystate;
-	int yychar;
-	char *msg;
-} yymsg[] = {
-	// Each line of the form % token list
-	// is converted by bisonerrors into the yystate and yychar caused
-	// by that token list.
-
-	{222, ',',
-	"unexpected comma during import block"},
-
-	{32, ';',
-	"missing import path; require quoted string"},
-
-	{380, ';',
-	"missing { after if clause"},
-
-	{401, ';',
-	"missing { after switch clause"},
-
-	{239, ';',
-	"missing { after for clause"},
-
-	{478, LBODY,
-	"missing { after for clause"},
-
-	{22, '{',
-	"unexpected semicolon or newline before {"},
-
-	{145, ';',
-	"unexpected semicolon or newline in type declaration"},
-
-	{37, '}',
-	"unexpected } in channel type"},
-	
-	{37, ')',
-	"unexpected ) in channel type"},
-	
-	{37, ',',
-	"unexpected comma in channel type"},
-
-	{441, LELSE,
-	"unexpected semicolon or newline before else"},
-
-	{259, ',',
-	"name list not allowed in interface type"},
-
-	{239, LVAR,
-	"var declaration not allowed in for initializer"},
-
-	{65, '{',
-	"unexpected { at end of statement"},
-
-	{379, '{',
-	"unexpected { at end of statement"},
-	
-	{126, ';',
-	"argument to go/defer must be function call"},
-	
-	{428, ';',
-	"need trailing comma before newline in composite literal"},
-	
-	{439, ';',
-	"need trailing comma before newline in composite literal"},
-	
-	{113, LNAME,
-	"nested func not allowed"},
-
-	{647, ';',
-	"else must be followed by if or statement block"}
-};
diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go
new file mode 100644
index 0000000..1134997
--- /dev/null
+++ b/src/cmd/go/alldocs.go
@@ -0,0 +1,1481 @@
+// 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.
+
+// DO NOT EDIT THIS FILE. GENERATED BY mkalldocs.sh.
+// Edit the documentation in other files and rerun mkalldocs.sh to generate this one.
+
+/*
+Go is a tool for managing Go source code.
+
+Usage:
+
+	go command [arguments]
+
+The commands are:
+
+	build       compile packages and dependencies
+	clean       remove object files
+	doc         show documentation for package or symbol
+	env         print Go environment information
+	fix         run go tool fix on packages
+	fmt         run gofmt on package sources
+	generate    generate Go files by processing source
+	get         download and install packages and dependencies
+	install     compile and install packages and dependencies
+	list        list packages
+	run         compile and run Go program
+	test        test packages
+	tool        run specified go tool
+	version     print Go version
+	vet         run go tool vet on packages
+
+Use "go help [command]" for more information about a command.
+
+Additional help topics:
+
+	c           calling between Go and C
+	buildmode   description of build modes
+	filetype    file types
+	gopath      GOPATH environment variable
+	environment environment variables
+	importpath  import path syntax
+	packages    description of package lists
+	testflag    description of testing flags
+	testfunc    description of testing functions
+
+Use "go help [topic]" for more information about that topic.
+
+
+Compile packages and dependencies
+
+Usage:
+
+	go build [-o output] [-i] [build flags] [packages]
+
+Build compiles the packages named by the import paths,
+along with their dependencies, but it does not install the results.
+
+If the arguments to build are a list of .go files, build treats
+them as a list of source files specifying a single package.
+
+When compiling a single main package, build writes
+the resulting executable to an output file named after
+the first source file ('go build ed.go rx.go' writes 'ed' or 'ed.exe')
+or the source code directory ('go build unix/sam' writes 'sam' or 'sam.exe').
+The '.exe' suffix is added when writing a Windows executable.
+
+When compiling multiple packages or a single non-main package,
+build compiles the packages but discards the resulting object,
+serving only as a check that the packages can be built.
+
+The -o flag, only allowed when compiling a single package,
+forces build to write the resulting executable or object
+to the named output file, instead of the default behavior described
+in the last two paragraphs.
+
+The -i flag installs the packages that are dependencies of the target.
+
+The build flags are shared by the build, clean, get, install, list, run,
+and test commands:
+
+	-a
+		force rebuilding of packages that are already up-to-date.
+	-n
+		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, 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.
+	-v
+		print the names of packages as they are compiled.
+	-work
+		print the name of the temporary work directory and
+		do not delete it when exiting.
+	-x
+		print the commands.
+
+	-asmflags 'flag list'
+		arguments to pass on each go tool asm invocation.
+	-buildmode mode
+		build mode to use. See 'go help buildmode' for more.
+	-compiler name
+		name of compiler to use, as in runtime.Compiler (gccgo or gc).
+	-gccgoflags 'arg list'
+		arguments to pass on each gccgo compiler/linker invocation.
+	-gcflags 'arg list'
+		arguments to pass on each go tool compile invocation.
+	-installsuffix suffix
+		a suffix to use in the name of the package installation directory,
+		in order to keep output separate from default builds.
+		If using the -race flag, the install suffix is automatically set to race
+		or, if set explicitly, has _race appended to it.  Using a -buildmode
+		option that requires non-default compile flags has a similar effect.
+	-ldflags 'flag list'
+		arguments to pass on each go tool link invocation.
+	-linkshared
+		link against shared libraries previously created with
+		-buildmode=shared
+	-pkgdir dir
+		install and load all packages from dir instead of the usual locations.
+		For example, when building with a non-standard configuration,
+		use -pkgdir to keep generated packages in a separate location.
+	-tags 'tag list'
+		a list of build tags to consider satisfied during the build.
+		For more information about build tags, see the description of
+		build constraints in the documentation for the go/build package.
+	-toolexec 'cmd args'
+		a program to use to invoke toolchain programs like vet and asm.
+		For example, instead of running asm, the go command will run
+		'cmd args /path/to/asm <arguments for asm>'.
+
+The list flags accept a space-separated list of strings. To embed spaces
+in an element in the list, surround it with either single or double quotes.
+
+For more about specifying packages, see 'go help packages'.
+For more about where packages and binaries are installed,
+run 'go help gopath'.
+For more about calling between Go and C/C++, run 'go help c'.
+
+Note: Build adheres to certain conventions such as those described
+by 'go help gopath'. Not all projects can follow these conventions,
+however. Installations that have their own conventions or that use
+a separate software build system may choose to use lower-level
+invocations such as 'go tool compile' and 'go tool link' to avoid
+some of the overheads and design decisions of the build tool.
+
+See also: go install, go get, go clean.
+
+
+Remove object files
+
+Usage:
+
+	go clean [-i] [-r] [-n] [-x] [build flags] [packages]
+
+Clean removes object files from package source directories.
+The go command builds most objects in a temporary directory,
+so go clean is mainly concerned with object files left by other
+tools or by manual invocations of go build.
+
+Specifically, clean removes the following files from each of the
+source directories corresponding to the import paths:
+
+	_obj/            old object directory, left from Makefiles
+	_test/           old test directory, left from Makefiles
+	_testmain.go     old gotest file, left from Makefiles
+	test.out         old test log, left from Makefiles
+	build.out        old test log, left from Makefiles
+	*.[568ao]        object files, left from Makefiles
+
+	DIR(.exe)        from go build
+	DIR.test(.exe)   from go test -c
+	MAINFILE(.exe)   from go build MAINFILE.go
+	*.so             from SWIG
+
+In the list, DIR represents the final path element of the
+directory, and MAINFILE is the base name of any Go source
+file in the directory that is not included when building
+the package.
+
+The -i flag causes clean to remove the corresponding installed
+archive or binary (what 'go install' would create).
+
+The -n flag causes clean to print the remove commands it would execute,
+but not run them.
+
+The -r flag causes clean to be applied recursively to all the
+dependencies of the packages named by the import paths.
+
+The -x flag causes clean to print remove commands as it executes them.
+
+For more about build flags, see 'go help build'.
+
+For more about specifying packages, see 'go help packages'.
+
+
+Show documentation for package or symbol
+
+Usage:
+
+	go doc [-u] [-c] [package|[package.]symbol[.method]]
+
+Doc prints the documentation comments associated with the item identified by its
+arguments (a package, const, func, type, var, or method) followed by a one-line
+summary of each of the first-level items "under" that item (package-level
+declarations for a package, methods for a type, etc.).
+
+Doc accepts zero, one, or two arguments.
+
+Given no arguments, that is, when run as
+
+	go doc
+
+it prints the package documentation for the package in the current directory.
+If the package is a command (package main), the exported symbols of the package
+are elided from the presentation unless the -cmd flag is provided.
+
+When run with one argument, the argument is treated as a Go-syntax-like
+representation of the item to be documented. What the argument selects depends
+on what is installed in GOROOT and GOPATH, as well as the form of the argument,
+which is schematically one of these:
+
+	go doc <pkg>
+	go doc <sym>[.<method>]
+	go doc [<pkg>].<sym>[.<method>]
+
+The first item in this list matched by the argument is the one whose
+documentation is printed. (See the examples below.) For packages, the order of
+scanning is determined lexically, but the GOROOT tree is always scanned before
+GOPATH.
+
+If there is no package specified or matched, the package in the current
+directory is selected, so "go doc Foo" shows the documentation for symbol Foo in
+the current package.
+
+The package path must be either a qualified path or a proper suffix of a
+path. The go tool's usual package mechanism does not apply: package path
+elements like . and ... are not implemented by go doc.
+
+When run with two arguments, the first must be a full package path (not just a
+suffix), and the second is a symbol or symbol and method; this is similar to the
+syntax accepted by godoc:
+
+	go doc <pkg> <sym>[.<method>]
+
+In all forms, when matching symbols, lower-case letters in the argument match
+either case but upper-case letters match exactly. This means that there may be
+multiple matches of a lower-case argument in a package if different symbols have
+different cases. If this occurs, documentation for all matches is printed.
+
+Examples:
+	go doc
+		Show documentation for current package.
+	go doc Foo
+		Show documentation for Foo in the current package.
+		(Foo starts with a capital letter so it cannot match
+		a package path.)
+	go doc encoding/json
+		Show documentation for the encoding/json package.
+	go doc json
+		Shorthand for encoding/json.
+	go doc json.Number (or go doc json.number)
+		Show documentation and method summary for json.Number.
+	go doc json.Number.Int64 (or go doc json.number.int64)
+		Show documentation for json.Number's Int64 method.
+	go doc cmd/doc
+		Show package docs for the doc command.
+	go doc -cmd cmd/doc
+		Show package docs and exported symbols within the doc command.
+	go doc template.new
+		Show documentation for html/template's New function.
+		(html/template is lexically before text/template)
+	go doc text/template.new # One argument
+		Show documentation for text/template's New function.
+	go doc text/template new # Two arguments
+		Show documentation for text/template's New function.
+
+Flags:
+	-c
+		Respect case when matching symbols.
+	-cmd
+		Treat a command (package main) like a regular package.
+		Otherwise package main's exported symbols are hidden
+		when showing the package's top-level documentation.
+	-u
+		Show documentation for unexported as well as exported
+		symbols and methods.
+
+
+Print Go environment information
+
+Usage:
+
+	go env [var ...]
+
+Env prints Go environment information.
+
+By default env prints information as a shell script
+(on Windows, a batch file).  If one or more variable
+names is given as arguments,  env prints the value of
+each named variable on its own line.
+
+
+Run go tool fix on packages
+
+Usage:
+
+	go fix [packages]
+
+Fix runs the Go fix command on the packages named by the import paths.
+
+For more about fix, see 'go doc cmd/fix'.
+For more about specifying packages, see 'go help packages'.
+
+To run fix with specific options, run 'go tool fix'.
+
+See also: go fmt, go vet.
+
+
+Run gofmt on package sources
+
+Usage:
+
+	go fmt [-n] [-x] [packages]
+
+Fmt runs the command 'gofmt -l -w' on the packages named
+by the import paths.  It prints the names of the files that are modified.
+
+For more about gofmt, see 'go doc cmd/gofmt'.
+For more about specifying packages, see 'go help packages'.
+
+The -n flag prints commands that would be executed.
+The -x flag prints commands as they are executed.
+
+To run gofmt with specific options, run gofmt itself.
+
+See also: go fix, go vet.
+
+
+Generate Go files by processing source
+
+Usage:
+
+	go generate [-run regexp] [file.go... | packages]
+
+Generate runs commands described by directives within existing
+files. Those commands can run any process but the intent is to
+create or update Go source files, for instance by running yacc.
+
+Go generate is never run automatically by go build, go get, go test,
+and so on. It must be run explicitly.
+
+Go generate scans the file for directives, which are lines of
+the form,
+
+	//go:generate command argument...
+
+(note: no leading spaces and no space in "//go") where command
+is the generator to be run, corresponding to an executable file
+that can be run locally. It must either be in the shell path
+(gofmt), a fully qualified path (/usr/you/bin/mytool), or a
+command alias, described below.
+
+Note that go generate does not parse the file, so lines that look
+like directives in comments or multiline strings will be treated
+as directives.
+
+The arguments to the directive are space-separated tokens or
+double-quoted strings passed to the generator as individual
+arguments when it is run.
+
+Quoted strings use Go syntax and are evaluated before execution; a
+quoted string appears as a single argument to the generator.
+
+Go generate sets several variables when it runs the generator:
+
+	$GOARCH
+		The execution architecture (arm, amd64, etc.)
+	$GOOS
+		The execution operating system (linux, windows, etc.)
+	$GOFILE
+		The base name of the file.
+	$GOLINE
+		The line number of the directive in the source 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
+line.
+
+As a last step before running the command, any invocations of any
+environment variables with alphanumeric names, such as $GOFILE or
+$HOME, are expanded throughout the command line. The syntax for
+variable expansion is $NAME on all operating systems.  Due to the
+order of evaluation, variables are expanded even inside quoted
+strings. If the variable NAME is not set, $NAME expands to the
+empty string.
+
+A directive of the form,
+
+	//go:generate -command xxx args...
+
+specifies, for the remainder of this source file only, that the
+string xxx represents the command identified by the arguments. This
+can be used to create aliases or to handle multiword generators.
+For example,
+
+	//go:generate -command yacc go tool yacc
+
+specifies that the command "yacc" represents the generator
+"go tool yacc".
+
+Generate processes packages in the order given on the command line,
+one at a time. If the command line lists .go files, they are treated
+as a single package. Within a package, generate processes the
+source files in a package in file name order, one at a time. Within
+a source file, generate runs generators in the order they appear
+in the file, one at a time.
+
+If any generator returns an error exit status, "go generate" skips
+all further processing for that package.
+
+The generator is run in the package's source directory.
+
+Go generate accepts one specific flag:
+
+	-run=""
+		if non-empty, specifies a regular expression to select
+		directives whose full original source text (excluding
+		any trailing spaces and final newline) matches the
+		expression.
+
+It also accepts the standard build flags -v, -n, and -x.
+The -v flag prints the names of packages and files as they are
+processed.
+The -n flag prints commands that would be executed.
+The -x flag prints commands as they are executed.
+
+For more about specifying packages, see 'go help packages'.
+
+
+Download and install packages and dependencies
+
+Usage:
+
+	go get [-d] [-f] [-fix] [-insecure] [-t] [-u] [build flags] [packages]
+
+Get downloads and installs the packages named by the import paths,
+along with their dependencies.
+
+The -d flag instructs get to stop after downloading the packages; that is,
+it instructs get not to install the packages.
+
+The -f flag, valid only when -u is set, forces get -u not to verify that
+each package has been checked out from the source control repository
+implied by its import path. This can be useful if the source is a local fork
+of the original.
+
+The -fix flag instructs get to run the fix tool on the downloaded packages
+before resolving dependencies or building the code.
+
+The -insecure flag permits fetching from repositories and resolving
+custom domains using insecure schemes such as HTTP. Use with caution.
+
+The -t flag instructs get to also download the packages required to build
+the tests for the specified packages.
+
+The -u flag instructs get to use the network to update the named packages
+and their dependencies.  By default, get uses the network to check out
+missing packages but does not use it to look for updates to existing packages.
+
+Get also accepts build flags to control the installation. See 'go help build'.
+
+When checking out or updating a package, get looks for a branch or tag
+that matches the locally installed version of Go. The most important
+rule is that if the local installation is running version "go1", get
+searches for a branch or tag named "go1". If no such version exists it
+retrieves the most recent version of the package.
+
+If the vendoring experiment is enabled (see 'go help gopath'),
+then when go get checks out or updates a Git repository,
+it also updates any git submodules referenced by the repository.
+
+For more about specifying packages, see 'go help packages'.
+
+For more about how 'go get' finds source code to
+download, see 'go help importpath'.
+
+See also: go build, go install, go clean.
+
+
+Compile and install packages and dependencies
+
+Usage:
+
+	go install [build flags] [packages]
+
+Install compiles and installs the packages named by the import paths,
+along with their dependencies.
+
+For more about the build flags, see 'go help build'.
+For more about specifying packages, see 'go help packages'.
+
+See also: go build, go get, go clean.
+
+
+List packages
+
+Usage:
+
+	go list [-e] [-f format] [-json] [build flags] [packages]
+
+List lists the packages named by the import paths, one per line.
+
+The default output shows the package import path:
+
+    bytes
+    encoding/json
+    github.com/gorilla/mux
+    golang.org/x/net/html
+
+The -f flag specifies an alternate format for the list, using the
+syntax of package template.  The default output is equivalent to -f
+'{{.ImportPath}}'. The struct being passed to the template is:
+
+    type Package struct {
+        Dir           string // directory containing package sources
+        ImportPath    string // import path of package in dir
+        ImportComment string // path in import comment on package statement
+        Name          string // package name
+        Doc           string // package documentation string
+        Target        string // install path
+        Shlib         string // the shared library that contains this package (only set when -linkshared)
+        Goroot        bool   // is this package in the Go root?
+        Standard      bool   // is this package part of the standard Go library?
+        Stale         bool   // would 'go install' do anything for this package?
+        Root          string // Go root or Go path dir containing this package
+
+        // Source files
+        GoFiles        []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
+        CgoFiles       []string // .go sources files that import "C"
+        IgnoredGoFiles []string // .go sources ignored due to build constraints
+        CFiles         []string // .c source files
+        CXXFiles       []string // .cc, .cxx and .cpp source files
+        MFiles         []string // .m source files
+        HFiles         []string // .h, .hh, .hpp and .hxx source files
+        SFiles         []string // .s source files
+        SwigFiles      []string // .swig files
+        SwigCXXFiles   []string // .swigcxx files
+        SysoFiles      []string // .syso object files to add to archive
+
+        // Cgo directives
+        CgoCFLAGS    []string // cgo: flags for C compiler
+        CgoCPPFLAGS  []string // cgo: flags for C preprocessor
+        CgoCXXFLAGS  []string // cgo: flags for C++ compiler
+        CgoLDFLAGS   []string // cgo: flags for linker
+        CgoPkgConfig []string // cgo: pkg-config names
+
+        // Dependency information
+        Imports []string // import paths used by this package
+        Deps    []string // all (recursively) imported dependencies
+
+        // Error information
+        Incomplete bool            // this package or a dependency has an error
+        Error      *PackageError   // error loading package
+        DepsErrors []*PackageError // errors loading dependencies
+
+        TestGoFiles  []string // _test.go files in package
+        TestImports  []string // imports from TestGoFiles
+        XTestGoFiles []string // _test.go files outside package
+        XTestImports []string // imports from XTestGoFiles
+    }
+
+The template function "join" calls strings.Join.
+
+The template function "context" returns the build context, defined as:
+
+	type Context struct {
+		GOARCH        string   // target architecture
+		GOOS          string   // target operating system
+		GOROOT        string   // Go root
+		GOPATH        string   // Go path
+		CgoEnabled    bool     // whether cgo can be used
+		UseAllFiles   bool     // use files regardless of +build lines, file names
+		Compiler      string   // compiler to assume when computing target paths
+		BuildTags     []string // build constraints to match in +build lines
+		ReleaseTags   []string // releases the current release is compatible with
+		InstallSuffix string   // suffix to use in the name of the install dir
+	}
+
+For more information about the meaning of these fields see the documentation
+for the go/build package's Context type.
+
+The -json flag causes the package data to be printed in JSON format
+instead of using the template format.
+
+The -e flag changes the handling of erroneous packages, those that
+cannot be found or are malformed.  By default, the list command
+prints an error to standard error for each erroneous package and
+omits the packages from consideration during the usual printing.
+With the -e flag, the list command never prints errors to standard
+error and instead processes the erroneous packages with the usual
+printing.  Erroneous packages will have a non-empty ImportPath and
+a non-nil Error field; other information may or may not be missing
+(zeroed).
+
+For more about build flags, see 'go help build'.
+
+For more about specifying packages, see 'go help packages'.
+
+
+Compile and run Go program
+
+Usage:
+
+	go run [build flags] [-exec xprog] gofiles... [arguments...]
+
+Run compiles and runs the main package comprising the named Go source files.
+A Go source file is defined to be a file ending in a literal ".go" suffix.
+
+By default, 'go run' runs the compiled binary directly: 'a.out arguments...'.
+If the -exec flag is given, 'go run' invokes the binary using xprog:
+	'xprog a.out arguments...'.
+If the -exec flag is not given, GOOS or GOARCH is different from the system
+default, and a program named go_$GOOS_$GOARCH_exec can be found
+on the current search path, 'go run' invokes the binary using that program,
+for example 'go_nacl_386_exec a.out arguments...'. This allows execution of
+cross-compiled programs when a simulator or other execution method is
+available.
+
+For more about build flags, see 'go help build'.
+
+See also: go build.
+
+
+Test packages
+
+Usage:
+
+	go test [-c] [-i] [build and test flags] [packages] [flags for test binary]
+
+'Go test' automates testing the packages named by the import paths.
+It prints a summary of the test results in the format:
+
+	ok   archive/tar   0.011s
+	FAIL archive/zip   0.022s
+	ok   compress/gzip 0.033s
+	...
+
+followed by detailed output for each failed package.
+
+'Go test' recompiles each package along with any files with names matching
+the file pattern "*_test.go".
+Files whose names begin with "_" (including "_test.go") or "." are ignored.
+These additional files can contain test functions, benchmark functions, and
+example functions.  See 'go help testfunc' for more.
+Each listed package causes the execution of a separate test binary.
+
+Test files that declare a package with the suffix "_test" will be compiled as a
+separate package, and then linked and run with the main test binary.
+
+By default, go test needs no arguments.  It compiles and tests the package
+with source in the current directory, including tests, and runs the tests.
+
+The package is built in a temporary directory so it does not interfere with the
+non-test installation.
+
+In addition to the build flags, the flags handled by 'go test' itself are:
+
+	-c
+		Compile the test binary to pkg.test but do not run it
+		(where pkg is the last element of the package's import path).
+		The file name can be changed with the -o flag.
+
+	-exec xprog
+	    Run the test binary using xprog. The behavior is the same as
+	    in 'go run'. See 'go help run' for details.
+
+	-i
+	    Install packages that are dependencies of the test.
+	    Do not run the test.
+
+	-o file
+		Compile the test binary to the named file.
+		The test still runs (unless -c or -i is specified).
+
+The test binary also accepts flags that control execution of the test; these
+flags are also accessible by 'go test'. See 'go help testflag' for details.
+
+If the test binary needs any other flags, they should be presented after the
+package names. The go tool treats as a flag the first argument that begins with
+a minus sign that it does not recognize itself; that argument and all subsequent
+arguments are passed as arguments to the test binary.
+
+For more about build flags, see 'go help build'.
+For more about specifying packages, see 'go help packages'.
+
+See also: go build, go vet.
+
+
+Run specified go tool
+
+Usage:
+
+	go tool [-n] command [args...]
+
+Tool runs the go tool command identified by the arguments.
+With no arguments it prints the list of known tools.
+
+The -n flag causes tool to print the command that would be
+executed but not execute it.
+
+For more about each tool command, see 'go tool command -h'.
+
+
+Print Go version
+
+Usage:
+
+	go version
+
+Version prints the Go version, as reported by runtime.Version.
+
+
+Run go tool vet on packages
+
+Usage:
+
+	go vet [-n] [-x] [build flags] [packages]
+
+Vet runs the Go vet command on the packages named by the import paths.
+
+For more about vet, see 'go doc cmd/vet'.
+For more about specifying packages, see 'go help packages'.
+
+To run the vet tool with specific options, run 'go tool vet'.
+
+The -n flag prints commands that would be executed.
+The -x flag prints commands as they are executed.
+
+For more about build flags, see 'go help build'.
+
+See also: go fmt, go fix.
+
+
+Calling between Go and C
+
+There are two different ways to call between Go and C/C++ code.
+
+The first is the cgo tool, which is part of the Go distribution.  For
+information on how to use it see the cgo documentation (go doc cmd/cgo).
+
+The second is the SWIG program, which is a general tool for
+interfacing between languages.  For information on SWIG see
+http://swig.org/.  When running go build, any file with a .swig
+extension will be passed to SWIG.  Any file with a .swigcxx extension
+will be passed to SWIG with the -c++ option.
+
+When either cgo or SWIG is used, go build will pass any .c, .m, .s,
+or .S files to the C compiler, and any .cc, .cpp, .cxx files to the C++
+compiler.  The CC or CXX environment variables may be set to determine
+the C or C++ compiler, respectively, to use.
+
+
+Description of build modes
+
+The 'go build' and 'go install' commands take a -buildmode argument which
+indicates which kind of object file is to be built. Currently supported values
+are:
+
+	-buildmode=archive
+		Build the listed non-main packages into .a files. Packages named
+		main are ignored.
+
+	-buildmode=c-archive
+		Build the listed main package, plus all packages it imports,
+		into a C archive file. The only callable symbols will be those
+		functions exported using a cgo //export comment. Requires
+		exactly one main package to be listed.
+
+	-buildmode=c-shared
+		Build the listed main packages, plus all packages that they
+		import, into C shared libraries. The only callable symbols will
+		be those functions exported using a cgo //export comment.
+		Non-main packages are ignored.
+
+	-buildmode=default
+		Listed main packages are built into executables and listed
+		non-main packages are built into .a files (the default
+		behavior).
+
+	-buildmode=shared
+		Combine all the listed non-main packages into a single shared
+		library that will be used when building with the -linkshared
+		option. Packages named main are ignored.
+
+	-buildmode=exe
+		Build the listed main packages and everything they import into
+		executables. Packages not named main are ignored.
+
+
+File types
+
+The go command examines the contents of a restricted set of files
+in each directory. It identifies which files to examine based on
+the extension of the file name. These extensions are:
+
+	.go
+		Go source files.
+	.c, .h
+		C source files.
+		If the package uses cgo or SWIG, these will be compiled with the
+		OS-native compiler (typically gcc); otherwise they will
+		trigger an error.
+	.cc, .cpp, .cxx, .hh, .hpp, .hxx
+		C++ source files. Only useful with cgo or SWIG, and always
+		compiled with the OS-native compiler.
+	.m
+		Objective-C source files. Only useful with cgo, and always
+		compiled with the OS-native compiler.
+	.s, .S
+		Assembler source files.
+		If the package uses cgo or SWIG, these will be assembled with the
+		OS-native assembler (typically gcc (sic)); otherwise they
+		will be assembled with the Go assembler.
+	.swig, .swigcxx
+		SWIG definition files.
+	.syso
+		System object files.
+
+Files of each of these types except .syso may contain build
+constraints, but the go command stops scanning for build constraints
+at the first item in the file that is not a blank line or //-style
+line comment.
+
+
+GOPATH environment variable
+
+The Go path is used to resolve import statements.
+It is implemented by and documented in the go/build package.
+
+The GOPATH environment variable lists places to look for Go code.
+On Unix, the value is a colon-separated string.
+On Windows, the value is a semicolon-separated string.
+On Plan 9, the value is a list.
+
+GOPATH must be set to get, build and install packages outside the
+standard Go tree.
+
+Each directory listed in GOPATH must have a prescribed structure:
+
+The src directory holds source code.  The path below src
+determines the import path or executable name.
+
+The pkg directory holds installed package objects.
+As in the Go tree, each target operating system and
+architecture pair has its own subdirectory of pkg
+(pkg/GOOS_GOARCH).
+
+If DIR is a directory listed in the GOPATH, a package with
+source in DIR/src/foo/bar can be imported as "foo/bar" and
+has its compiled form installed to "DIR/pkg/GOOS_GOARCH/foo/bar.a".
+
+The bin directory holds compiled commands.
+Each command is named for its source directory, but only
+the final element, not the entire path.  That is, the
+command with source in DIR/src/foo/quux is installed into
+DIR/bin/quux, not DIR/bin/foo/quux.  The "foo/" prefix is stripped
+so that you can add DIR/bin to your PATH to get at the
+installed commands.  If the GOBIN environment variable is
+set, commands are installed to the directory it names instead
+of DIR/bin.
+
+Here's an example directory layout:
+
+    GOPATH=/home/user/gocode
+
+    /home/user/gocode/
+        src/
+            foo/
+                bar/               (go code in package bar)
+                    x.go
+                quux/              (go code in package main)
+                    y.go
+        bin/
+            quux                   (installed command)
+        pkg/
+            linux_amd64/
+                foo/
+                    bar.a          (installed package object)
+
+Go searches each directory listed in GOPATH to find source code,
+but new packages are always downloaded into the first directory
+in the list.
+
+See https://golang.org/doc/code.html for an example.
+
+Internal Directories
+
+Code in or below a directory named "internal" is importable only
+by code in the directory tree rooted at the parent of "internal".
+Here's an extended version of the directory layout above:
+
+    /home/user/gocode/
+        src/
+            crash/
+                bang/              (go code in package bang)
+                    b.go
+            foo/                   (go code in package foo)
+                f.go
+                bar/               (go code in package bar)
+                    x.go
+                internal/
+                    baz/           (go code in package baz)
+                        z.go
+                quux/              (go code in package main)
+                    y.go
+
+
+The code in z.go is imported as "foo/internal/baz", but that
+import statement can only appear in source files in the subtree
+rooted at foo. The source files foo/f.go, foo/bar/x.go, and
+foo/quux/y.go can all import "foo/internal/baz", but the source file
+crash/bang/b.go cannot.
+
+See https://golang.org/s/go14internal for details.
+
+Vendor Directories
+
+Go 1.5 includes experimental support for using local copies
+of external dependencies to satisfy imports of those dependencies,
+often referred to as vendoring. Setting the environment variable
+GO15VENDOREXPERIMENT=1 enables that experimental support.
+
+When the vendor experiment is enabled,
+code below a directory named "vendor" is importable only
+by code in the directory tree rooted at the parent of "vendor",
+and only using an import path that omits the prefix up to and
+including the vendor element.
+
+Here's the example from the previous section,
+but with the "internal" directory renamed to "vendor"
+and a new foo/vendor/crash/bang directory added:
+
+    /home/user/gocode/
+        src/
+            crash/
+                bang/              (go code in package bang)
+                    b.go
+            foo/                   (go code in package foo)
+                f.go
+                bar/               (go code in package bar)
+                    x.go
+                vendor/
+                    crash/
+                        bang/      (go code in package bang)
+                            b.go
+                    baz/           (go code in package baz)
+                        z.go
+                quux/              (go code in package main)
+                    y.go
+
+The same visibility rules apply as for internal, but the code
+in z.go is imported as "baz", not as "foo/vendor/baz".
+
+Code in vendor directories deeper in the source tree shadows
+code in higher directories. Within the subtree rooted at foo, an import
+of "crash/bang" resolves to "foo/vendor/crash/bang", not the
+top-level "crash/bang".
+
+Code in vendor directories is not subject to import path
+checking (see 'go help importpath').
+
+When the vendor experiment is enabled, 'go get' checks out
+submodules when checking out or updating a git repository
+(see 'go help get').
+
+The vendoring semantics are an experiment, and they may change
+in future releases. Once settled, they will be on by default.
+
+See https://golang.org/s/go15vendor for details.
+
+
+Environment variables
+
+The go command, and the tools it invokes, examine a few different
+environment variables. For many of these, you can see the default
+value of on your system by running 'go env NAME', where NAME is the
+name of the variable.
+
+General-purpose environment variables:
+
+	GCCGO
+		The gccgo command to run for 'go build -compiler=gccgo'.
+	GOARCH
+		The architecture, or processor, for which to compile code.
+		Examples are amd64, 386, arm, ppc64.
+	GOBIN
+		The directory where 'go install' will install a command.
+	GOOS
+		The operating system for which to compile code.
+		Examples are linux, darwin, windows, netbsd.
+	GOPATH
+		See 'go help gopath'.
+	GORACE
+		Options for the race detector.
+		See https://golang.org/doc/articles/race_detector.html.
+	GOROOT
+		The root of the go tree.
+
+Environment variables for use with cgo:
+
+	CC
+		The command to use to compile C code.
+	CGO_ENABLED
+		Whether the cgo command is supported.  Either 0 or 1.
+	CGO_CFLAGS
+		Flags that cgo will pass to the compiler when compiling
+		C code.
+	CGO_CPPFLAGS
+		Flags that cgo will pass to the compiler when compiling
+		C or C++ code.
+	CGO_CXXFLAGS
+		Flags that cgo will pass to the compiler when compiling
+		C++ code.
+	CGO_LDFLAGS
+		Flags that cgo will pass to the compiler when linking.
+	CXX
+		The command to use to compile C++ code.
+
+Architecture-specific environment variables:
+
+	GOARM
+		For GOARCH=arm, the ARM architecture for which to compile.
+		Valid values are 5, 6, 7.
+	GO386
+		For GOARCH=386, the floating point instruction set.
+		Valid values are 387, sse2.
+
+Special-purpose environment variables:
+
+	GOROOT_FINAL
+		The root of the installed Go tree, when it is
+		installed in a location other than where it is built.
+		File names in stack traces are rewritten from GOROOT to
+		GOROOT_FINAL.
+	GO15VENDOREXPERIMENT
+		Set to 1 to enable the Go 1.5 vendoring experiment.
+	GO_EXTLINK_ENABLED
+		Whether the linker should use external linking mode
+		when using -linkmode=auto with code that uses cgo.
+		Set to 0 to disable external linking mode, 1 to enable it.
+
+
+Import path syntax
+
+An import path (see 'go help packages') denotes a package
+stored in the local file system.  In general, an import path denotes
+either a standard package (such as "unicode/utf8") or a package
+found in one of the work spaces (see 'go help gopath').
+
+Relative import paths
+
+An import path beginning with ./ or ../ is called a relative path.
+The toolchain supports relative import paths as a shortcut in two ways.
+
+First, a relative path can be used as a shorthand on the command line.
+If you are working in the directory containing the code imported as
+"unicode" and want to run the tests for "unicode/utf8", you can type
+"go test ./utf8" instead of needing to specify the full path.
+Similarly, in the reverse situation, "go test .." will test "unicode" from
+the "unicode/utf8" directory. Relative patterns are also allowed, like
+"go test ./..." to test all subdirectories. See 'go help packages' for details
+on the pattern syntax.
+
+Second, if you are compiling a Go program not in a work space,
+you can use a relative path in an import statement in that program
+to refer to nearby code also not in a work space.
+This makes it easy to experiment with small multipackage programs
+outside of the usual work spaces, but such programs cannot be
+installed with "go install" (there is no work space in which to install them),
+so they are rebuilt from scratch each time they are built.
+To avoid ambiguity, Go programs cannot use relative import paths
+within a work space.
+
+Remote import paths
+
+Certain import paths also
+describe how to obtain the source code for the package using
+a revision control system.
+
+A few common code hosting sites have special syntax:
+
+	Bitbucket (Git, Mercurial)
+
+		import "bitbucket.org/user/project"
+		import "bitbucket.org/user/project/sub/directory"
+
+	GitHub (Git)
+
+		import "github.com/user/project"
+		import "github.com/user/project/sub/directory"
+
+	Google Code Project Hosting (Git, Mercurial, Subversion)
+
+		import "code.google.com/p/project"
+		import "code.google.com/p/project/sub/directory"
+
+		import "code.google.com/p/project.subrepository"
+		import "code.google.com/p/project.subrepository/sub/directory"
+
+	Launchpad (Bazaar)
+
+		import "launchpad.net/project"
+		import "launchpad.net/project/series"
+		import "launchpad.net/project/series/sub/directory"
+
+		import "launchpad.net/~user/project/branch"
+		import "launchpad.net/~user/project/branch/sub/directory"
+
+	IBM DevOps Services (Git)
+
+		import "hub.jazz.net/git/user/project"
+		import "hub.jazz.net/git/user/project/sub/directory"
+
+For code hosted on other servers, import paths may either be qualified
+with the version control type, or the go tool can dynamically fetch
+the import path over https/http and discover where the code resides
+from a <meta> tag in the HTML.
+
+To declare the code location, an import path of the form
+
+	repository.vcs/path
+
+specifies the given repository, with or without the .vcs suffix,
+using the named version control system, and then the path inside
+that repository.  The supported version control systems are:
+
+	Bazaar      .bzr
+	Git         .git
+	Mercurial   .hg
+	Subversion  .svn
+
+For example,
+
+	import "example.org/user/foo.hg"
+
+denotes the root directory of the Mercurial repository at
+example.org/user/foo or foo.hg, and
+
+	import "example.org/repo.git/foo/bar"
+
+denotes the foo/bar directory of the Git repository at
+example.org/repo or repo.git.
+
+When a version control system supports multiple protocols,
+each is tried in turn when downloading.  For example, a Git
+download tries https://, then git+ssh://.
+
+If the import path is not a known code hosting site and also lacks a
+version control qualifier, the go tool attempts to fetch the import
+over https/http and looks for a <meta> tag in the document's HTML
+<head>.
+
+The meta tag has the form:
+
+	<meta name="go-import" content="import-prefix vcs repo-root">
+
+The import-prefix is the import path corresponding to the repository
+root. It must be a prefix or an exact match of the package being
+fetched with "go get". If it's not an exact match, another http
+request is made at the prefix to verify the <meta> tags match.
+
+The meta tag should appear as early in the file as possible.
+In particular, it should appear before any raw JavaScript or CSS,
+to avoid confusing the go command's restricted parser.
+
+The vcs is one of "git", "hg", "svn", etc,
+
+The repo-root is the root of the version control system
+containing a scheme and not containing a .vcs qualifier.
+
+For example,
+
+	import "example.org/pkg/foo"
+
+will result in the following requests:
+
+	https://example.org/pkg/foo?go-get=1 (preferred)
+	http://example.org/pkg/foo?go-get=1  (fallback, only with -insecure)
+
+If that page contains the meta tag
+
+	<meta name="go-import" content="example.org git https://code.org/r/p/exproj">
+
+the go tool will verify that https://example.org/?go-get=1 contains the
+same meta tag and then git clone https://code.org/r/p/exproj into
+GOPATH/src/example.org.
+
+New downloaded packages are written to the first directory
+listed in the GOPATH environment variable (see 'go help gopath').
+
+The go command attempts to download the version of the
+package appropriate for the Go release being used.
+Run 'go help get' for more.
+
+Import path checking
+
+When the custom import path feature described above redirects to a
+known code hosting site, each of the resulting packages has two possible
+import paths, using the custom domain or the known hosting site.
+
+A package statement is said to have an "import comment" if it is immediately
+followed (before the next newline) by a comment of one of these two forms:
+
+	package math // import "path"
+	package math /* import "path" * /
+
+The go command will refuse to install a package with an import comment
+unless it is being referred to by that import path. In this way, import comments
+let package authors make sure the custom import path is used and not a
+direct path to the underlying code hosting site.
+
+If the vendoring experiment is enabled (see 'go help gopath'),
+then import path checking is disabled for code found within vendor trees.
+This makes it possible to copy code into alternate locations in vendor trees
+without needing to update import comments.
+
+See https://golang.org/s/go14customimport for details.
+
+
+Description of package lists
+
+Many commands apply to a set of packages:
+
+	go action [packages]
+
+Usually, [packages] is a list of import paths.
+
+An import path that is a rooted path or that begins with
+a . or .. element is interpreted as a file system path and
+denotes the package in that directory.
+
+Otherwise, the import path P denotes the package found in
+the directory DIR/src/P for some DIR listed in the GOPATH
+environment variable (see 'go help gopath').
+
+If no import paths are given, the action applies to the
+package in the current directory.
+
+There are four reserved names for paths that should not be used
+for packages to be built with the go tool:
+
+- "main" denotes the top-level package in a stand-alone executable.
+
+- "all" expands to all package directories found in all the GOPATH
+trees. For example, 'go list all' lists all the packages on the local
+system.
+
+- "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
+directories found in the GOPATH trees with names matching the
+patterns.  As a special case, x/... matches x as well as x's subdirectories.
+For example, net/... expands to net and packages in its subdirectories.
+
+An import path can also name a package to be downloaded from
+a remote repository.  Run 'go help importpath' for details.
+
+Every package in a program must have a unique import path.
+By convention, this is arranged by starting each path with a
+unique prefix that belongs to you.  For example, paths used
+internally at Google all begin with 'google', and paths
+denoting remote repositories begin with the path to the code,
+such as 'github.com/user/repo'.
+
+As a special case, if the package list is a list of .go files from a
+single directory, the command is applied to a single synthesized
+package made up of exactly those files, ignoring any build constraints
+in those files and ignoring any other files in the directory.
+
+Directory and file names that begin with "." or "_" are ignored
+by the go tool, as are directories named "testdata".
+
+
+Description of testing flags
+
+The 'go test' command takes both flags that apply to 'go test' itself
+and flags that apply to the resulting test binary.
+
+Several of the flags control profiling and write an execution profile
+suitable for "go tool pprof"; run "go tool pprof -h" for more
+information.  The --alloc_space, --alloc_objects, and --show_bytes
+options of pprof control how the information is presented.
+
+The following flags are recognized by the 'go test' command and
+control the execution of any test:
+
+	-bench regexp
+	    Run benchmarks matching the regular expression.
+	    By default, no benchmarks run. To run all benchmarks,
+	    use '-bench .' or '-bench=.'.
+
+	-benchmem
+	    Print memory allocation statistics for benchmarks.
+
+	-benchtime t
+	    Run enough iterations of each benchmark to take t, specified
+	    as a time.Duration (for example, -benchtime 1h30s).
+	    The default is 1 second (1s).
+
+	-blockprofile block.out
+	    Write a goroutine blocking profile to the specified file
+	    when all tests are complete.
+	    Writes test binary as -c would.
+
+	-blockprofilerate n
+	    Control the detail provided in goroutine blocking profiles by
+	    calling runtime.SetBlockProfileRate with n.
+	    See 'go doc runtime.SetBlockProfileRate'.
+	    The profiler aims to sample, on average, one blocking event every
+	    n nanoseconds the program spends blocked.  By default,
+	    if -test.blockprofile is set without this flag, all blocking events
+	    are recorded, equivalent to -test.blockprofilerate=1.
+
+	-count n
+	    Run each test and benchmark n times (default 1).
+	    If -cpu is set, run n times for each GOMAXPROCS value.
+	    Examples are always run once.
+
+	-cover
+	    Enable coverage analysis.
+
+	-covermode set,count,atomic
+	    Set the mode for coverage analysis for the package[s]
+	    being tested. The default is "set" unless -race is enabled,
+	    in which case it is "atomic".
+	    The values:
+		set: bool: does this statement run?
+		count: int: how many times does this statement run?
+		atomic: int: count, but correct in multithreaded tests;
+			significantly more expensive.
+	    Sets -cover.
+
+	-coverpkg pkg1,pkg2,pkg3
+	    Apply coverage analysis in each test to the given list of packages.
+	    The default is for each test to analyze only the package being tested.
+	    Packages are specified as import paths.
+	    Sets -cover.
+
+	-coverprofile cover.out
+	    Write a coverage profile to the file after all tests have passed.
+	    Sets -cover.
+
+	-cpu 1,2,4
+	    Specify a list of GOMAXPROCS values for which the tests or
+	    benchmarks should be executed.  The default is the current value
+	    of GOMAXPROCS.
+
+	-cpuprofile cpu.out
+	    Write a CPU profile to the specified file before exiting.
+	    Writes test binary as -c would.
+
+	-memprofile mem.out
+	    Write a memory profile to the file after all tests have passed.
+	    Writes test binary as -c would.
+
+	-memprofilerate n
+	    Enable more precise (and expensive) memory profiles by setting
+	    runtime.MemProfileRate.  See 'go doc runtime.MemProfileRate'.
+	    To profile all memory allocations, use -test.memprofilerate=1
+	    and pass --alloc_space flag to the pprof tool.
+
+	-outputdir directory
+	    Place output files from profiling in the specified directory,
+	    by default the directory in which "go test" is running.
+
+	-parallel n
+	    Allow parallel execution of test functions that call t.Parallel.
+	    The value of this flag is the maximum number of tests to run
+	    simultaneously; by default, it is set to the value of GOMAXPROCS.
+
+	-run regexp
+	    Run only those tests and examples matching the regular
+	    expression.
+
+	-short
+	    Tell long-running tests to shorten their run time.
+	    It is off by default but set during all.bash so that installing
+	    the Go tree can run a sanity check but not spend time running
+	    exhaustive tests.
+
+	-timeout t
+	    If a test runs longer than t, panic.
+	    The default is 10 minutes (10m).
+
+	-trace trace.out
+	    Write an execution trace to the specified file before exiting.
+	    Writes test binary as -c would.
+
+	-v
+	    Verbose output: log all tests as they are run. Also print all
+	    text from Log and Logf calls even if the test succeeds.
+
+The test binary, called pkg.test where pkg is the name of the
+directory containing the package sources, can be invoked directly
+after building it with 'go test -c'. When invoking the test binary
+directly, each of the standard flag names must be prefixed with 'test.',
+as in -test.run=TestMyFunc or -test.v.
+
+When running 'go test', flags not listed above are passed through
+unaltered. For instance, the command
+
+	go test -x -v -cpuprofile=prof.out -dir=testdata -update
+
+will compile the test binary and then run it as
+
+	pkg.test -test.v -test.cpuprofile=prof.out -dir=testdata -update
+
+The test flags that generate profiles (other than for coverage) also
+leave the test binary in pkg.test for use when analyzing the profiles.
+
+Flags not recognized by 'go test' must be placed after any specified packages.
+
+
+Description of testing functions
+
+The 'go test' command expects to find test, benchmark, and example functions
+in the "*_test.go" files corresponding to the package under test.
+
+A test function is one named TestXXX (where XXX is any alphanumeric string
+not starting with a lower case letter) and should have the signature,
+
+	func TestXXX(t *testing.T) { ... }
+
+A benchmark function is one named BenchmarkXXX and should have the signature,
+
+	func BenchmarkXXX(b *testing.B) { ... }
+
+An example function is similar to a test function but, instead of using
+*testing.T to report success or failure, prints output to os.Stdout.
+That output is compared against the function's "Output:" comment, which
+must be the last comment in the function body (see example below). An
+example with no such comment, or with no text after "Output:" is compiled
+but not executed.
+
+Godoc displays the body of ExampleXXX to demonstrate the use
+of the function, constant, or variable XXX.  An example of a method M with
+receiver type T or *T is named ExampleT_M.  There may be multiple examples
+for a given function, constant, or variable, distinguished by a trailing _xxx,
+where xxx is a suffix not beginning with an upper case letter.
+
+Here is an example of an example:
+
+	func ExamplePrintln() {
+		Println("The output of\nthis example.")
+		// Output: The output of
+		// this example.
+	}
+
+The entire test file is presented as the example when it contains a single
+example function, at least one other function, type, variable, or constant
+declaration, and no test or benchmark functions.
+
+See the documentation of the testing package for more information.
+
+
+*/
+package main
diff --git a/src/cmd/go/bootstrap.go b/src/cmd/go/bootstrap.go
index dc7ed5f..1686df7 100644
--- a/src/cmd/go/bootstrap.go
+++ b/src/cmd/go/bootstrap.go
@@ -17,11 +17,19 @@ import (
 
 var errHTTP = errors.New("no http in bootstrap go command")
 
+type httpError struct {
+	statusCode int
+}
+
+func (e *httpError) Error() string {
+	panic("unreachable")
+}
+
 func httpGET(url string) ([]byte, error) {
 	return nil, errHTTP
 }
 
-func httpsOrHTTP(importPath string) (string, io.ReadCloser, error) {
+func httpsOrHTTP(importPath string, security securityMode) (string, io.ReadCloser, error) {
 	return "", nil, errHTTP
 }
 
diff --git a/src/cmd/go/build.go b/src/cmd/go/build.go
index 1dd4314..0b14725 100644
--- a/src/cmd/go/build.go
+++ b/src/cmd/go/build.go
@@ -8,6 +8,7 @@ import (
 	"bufio"
 	"bytes"
 	"container/heap"
+	"debug/elf"
 	"errors"
 	"flag"
 	"fmt"
@@ -34,21 +35,23 @@ var cmdBuild = &Command{
 Build compiles the packages named by the import paths,
 along with their dependencies, but it does not install the results.
 
-If the arguments are a list of .go files, build treats them as a list
-of source files specifying a single package.
+If the arguments to build are a list of .go files, build treats
+them as a list of source files specifying a single package.
 
-When the command line specifies a single main package,
-build writes the resulting executable to output.
-Otherwise build compiles the packages but discards the results,
+When compiling a single main package, build writes
+the resulting executable to an output file named after
+the first source file ('go build ed.go rx.go' writes 'ed' or 'ed.exe')
+or the source code directory ('go build unix/sam' writes 'sam' or 'sam.exe').
+The '.exe' suffix is added when writing a Windows executable.
+
+When compiling multiple packages or a single non-main package,
+build compiles the packages but discards the resulting object,
 serving only as a check that the packages can be built.
 
-The -o flag specifies the output file name. If not specified, the
-output file name depends on the arguments and derives from the name
-of the package, such as p.a for package p, unless p is 'main'. If
-the package is main and file names are provided, the file name
-derives from the first file name mentioned, such as f1 for 'go build
-f1.go f2.go'; with no files provided ('go build'), the output file
-name is the base name of the containing directory.
+The -o flag, only allowed when compiling a single package,
+forces build to write the resulting executable or object
+to the named output file, instead of the default behavior described
+in the last two paragraphs.
 
 The -i flag installs the packages that are dependencies of the target.
 
@@ -57,12 +60,12 @@ and test commands:
 
 	-a
 		force rebuilding of packages that are already up-to-date.
-		In Go releases, does not apply to the standard library.
 	-n
 		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.
@@ -74,33 +77,54 @@ and test commands:
 	-x
 		print the commands.
 
-	-ccflags 'arg list'
-		arguments to pass on each 5c, 6c, or 8c compiler invocation.
+	-asmflags 'flag list'
+		arguments to pass on each go tool asm invocation.
+	-buildmode mode
+		build mode to use. See 'go help buildmode' for more.
 	-compiler name
 		name of compiler to use, as in runtime.Compiler (gccgo or gc).
 	-gccgoflags 'arg list'
 		arguments to pass on each gccgo compiler/linker invocation.
 	-gcflags 'arg list'
-		arguments to pass on each 5g, 6g, or 8g compiler invocation.
+		arguments to pass on each go tool compile invocation.
 	-installsuffix suffix
 		a suffix to use in the name of the package installation directory,
 		in order to keep output separate from default builds.
 		If using the -race flag, the install suffix is automatically set to race
-		or, if set explicitly, has _race appended to it.
+		or, if set explicitly, has _race appended to it.  Using a -buildmode
+		option that requires non-default compile flags has a similar effect.
 	-ldflags 'flag list'
-		arguments to pass on each 5l, 6l, or 8l linker invocation.
+		arguments to pass on each go tool link invocation.
+	-linkshared
+		link against shared libraries previously created with
+		-buildmode=shared
+	-pkgdir dir
+		install and load all packages from dir instead of the usual locations.
+		For example, when building with a non-standard configuration,
+		use -pkgdir to keep generated packages in a separate location.
 	-tags 'tag list'
 		a list of build tags to consider satisfied during the build.
 		For more information about build tags, see the description of
 		build constraints in the documentation for the go/build package.
+	-toolexec 'cmd args'
+		a program to use to invoke toolchain programs like vet and asm.
+		For example, instead of running asm, the go command will run
+		'cmd args /path/to/asm <arguments for asm>'.
 
 The list flags accept a space-separated list of strings. To embed spaces
 in an element in the list, surround it with either single or double quotes.
 
 For more about specifying packages, see 'go help packages'.
 For more about where packages and binaries are installed,
-run 'go help gopath'.  For more about calling between Go and C/C++,
-run 'go help c'.
+run 'go help gopath'.
+For more about calling between Go and C/C++, run 'go help c'.
+
+Note: Build adheres to certain conventions such as those described
+by 'go help gopath'. Not all projects can follow these conventions,
+however. Installations that have their own conventions or that use
+a separate software build system may choose to use lower-level
+invocations such as 'go tool compile' and 'go tool link' to avoid
+some of the overheads and design decisions of the build tool.
 
 See also: go install, go get, go clean.
 	`,
@@ -115,6 +139,17 @@ func init() {
 
 	addBuildFlags(cmdBuild)
 	addBuildFlags(cmdInstall)
+
+	if buildContext.GOOS == "darwin" {
+		switch buildContext.GOARCH {
+		case "arm", "arm64":
+			// darwin/arm cannot run multiple tests simultaneously.
+			// Parallelism is limited in go_darwin_arm_exec, but
+			// also needs to be limited here so go test std does not
+			// timeout tests that waiting to run.
+			buildP = 1
+		}
+	}
 }
 
 // Flags set by multiple commands.
@@ -126,14 +161,19 @@ var buildX bool               // -x flag
 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 buildCcflags []string    // -ccflags flag
 var buildLdflags []string    // -ldflags flag
 var buildGccgoflags []string // -gccgoflags flag
 var buildRace bool           // -race flag
+var buildToolExec []string   // -toolexec flag
+var buildBuildmode string    // -buildmode flag
+var buildLinkshared bool     // -linkshared flag
+var buildPkgdir string       // -pkgdir flag
 
 var buildContext = build.Default
 var buildToolchain toolchain = noToolchain{}
+var ldBuildmode string
 
 // buildCompiler implements flag.Var.
 // It implements Set by updating both
@@ -169,21 +209,25 @@ func init() {
 // addBuildFlags adds the flags common to the build, clean, get,
 // install, list, run, and test commands.
 func addBuildFlags(cmd *Command) {
-	// NOTE: If you add flags here, also add them to testflag.go.
 	cmd.Flag.BoolVar(&buildA, "a", false, "")
 	cmd.Flag.BoolVar(&buildN, "n", false, "")
 	cmd.Flag.IntVar(&buildP, "p", buildP, "")
-	cmd.Flag.StringVar(&buildContext.InstallSuffix, "installsuffix", "", "")
 	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(buildCompiler{}, "compiler", "")
+	cmd.Flag.StringVar(&buildBuildmode, "buildmode", "default", "")
 	cmd.Flag.Var((*stringsFlag)(&buildGcflags), "gcflags", "")
-	cmd.Flag.Var((*stringsFlag)(&buildCcflags), "ccflags", "")
-	cmd.Flag.Var((*stringsFlag)(&buildLdflags), "ldflags", "")
 	cmd.Flag.Var((*stringsFlag)(&buildGccgoflags), "gccgoflags", "")
-	cmd.Flag.Var((*stringsFlag)(&buildContext.BuildTags), "tags", "")
-	cmd.Flag.Var(buildCompiler{}, "compiler", "")
+	cmd.Flag.StringVar(&buildContext.InstallSuffix, "installsuffix", "", "")
+	cmd.Flag.Var((*stringsFlag)(&buildLdflags), "ldflags", "")
+	cmd.Flag.BoolVar(&buildLinkshared, "linkshared", false, "")
+	cmd.Flag.StringVar(&buildPkgdir, "pkgdir", "", "")
 	cmd.Flag.BoolVar(&buildRace, "race", false, "")
+	cmd.Flag.Var((*stringsFlag)(&buildContext.BuildTags), "tags", "")
+	cmd.Flag.Var((*stringsFlag)(&buildToolExec), "toolexec", "")
+	cmd.Flag.BoolVar(&buildWork, "work", false, "")
 }
 
 func addBuildFlagsNX(cmd *Command) {
@@ -258,8 +302,113 @@ func (v *stringsFlag) String() string {
 	return "<stringsFlag>"
 }
 
+func pkgsMain(pkgs []*Package) (res []*Package) {
+	for _, p := range pkgs {
+		if p.Name == "main" {
+			res = append(res, p)
+		}
+	}
+	return res
+}
+
+func pkgsNotMain(pkgs []*Package) (res []*Package) {
+	for _, p := range pkgs {
+		if p.Name != "main" {
+			res = append(res, p)
+		}
+	}
+	return res
+}
+
+var pkgsFilter = func(pkgs []*Package) []*Package { return pkgs }
+
+func buildModeInit() {
+	_, gccgo := buildToolchain.(gccgoToolchain)
+	var codegenArg string
+	platform := goos + "/" + goarch
+	switch buildBuildmode {
+	case "archive":
+		pkgsFilter = pkgsNotMain
+	case "c-archive":
+		pkgsFilter = func(p []*Package) []*Package {
+			if len(p) != 1 || p[0].Name != "main" {
+				fatalf("-buildmode=c-archive requires exactly one main package")
+			}
+			return p
+		}
+		exeSuffix = ".a"
+		ldBuildmode = "c-archive"
+	case "c-shared":
+		pkgsFilter = pkgsMain
+		if gccgo {
+			codegenArg = "-fPIC"
+		} else {
+			switch platform {
+			case "linux/amd64":
+				codegenArg = "-shared"
+			case "linux/arm":
+				buildAsmflags = append(buildAsmflags, "-shared")
+			case "darwin/amd64":
+			case "android/arm":
+			default:
+				fatalf("-buildmode=c-shared not supported on %s\n", platform)
+			}
+		}
+		ldBuildmode = "c-shared"
+	case "default":
+		ldBuildmode = "exe"
+	case "exe":
+		pkgsFilter = pkgsMain
+		ldBuildmode = "exe"
+	case "shared":
+		pkgsFilter = pkgsNotMain
+		if gccgo {
+			codegenArg = "-fPIC"
+		} else {
+			switch platform {
+			case "linux/amd64":
+			default:
+				fatalf("-buildmode=shared not supported on %s\n", platform)
+			}
+			codegenArg = "-dynlink"
+		}
+		if *buildO != "" {
+			fatalf("-buildmode=shared and -o not supported together")
+		}
+		ldBuildmode = "shared"
+	default:
+		fatalf("buildmode=%s not supported", buildBuildmode)
+	}
+	if buildLinkshared {
+		if gccgo {
+			codegenArg = "-fPIC"
+		} else {
+			if platform != "linux/amd64" {
+				fmt.Fprintf(os.Stderr, "go %s: -linkshared is only supported on linux/amd64\n", flag.Args()[0])
+				os.Exit(2)
+			}
+			codegenArg = "-dynlink"
+			// TODO(mwhudson): remove -w when that gets fixed in linker.
+			buildLdflags = append(buildLdflags, "-linkshared", "-w")
+		}
+	}
+	if codegenArg != "" {
+		if gccgo {
+			buildGccgoflags = append(buildGccgoflags, codegenArg)
+		} else {
+			buildAsmflags = append(buildAsmflags, codegenArg)
+			buildGcflags = append(buildGcflags, codegenArg)
+		}
+		if buildContext.InstallSuffix != "" {
+			buildContext.InstallSuffix += "_"
+		}
+		buildContext.InstallSuffix += codegenArg[1:]
+	}
+}
+
 func runBuild(cmd *Command, args []string) {
 	raceInit()
+	buildModeInit()
 	var b builder
 	b.init()
 
@@ -297,16 +446,21 @@ func runBuild(cmd *Command, args []string) {
 			fatalf("no packages to build")
 		}
 		p := pkgs[0]
-		p.target = "" // must build - not up to date
+		p.target = *buildO
+		p.Stale = true // must build - not up to date
 		a := b.action(modeInstall, depMode, p)
-		a.target = *buildO
 		b.do(a)
 		return
 	}
 
-	a := &action{}
-	for _, p := range packages(args) {
-		a.deps = append(a.deps, b.action(modeBuild, depMode, p))
+	var a *action
+	if buildBuildmode == "shared" {
+		a = b.libaction(libname(args), pkgsFilter(packages(args)), modeBuild, depMode)
+	} else {
+		a = &action{}
+		for _, p := range pkgsFilter(packages(args)) {
+			a.deps = append(a.deps, b.action(modeBuild, depMode, p))
+		}
 	}
 	b.do(a)
 }
@@ -325,18 +479,47 @@ See also: go build, go get, go clean.
 	`,
 }
 
+// libname returns the filename to use for the shared library when using
+// -buildmode=shared.  The rules we use are:
+//  1) Drop any trailing "/..."s if present
+//  2) Change / to -
+//  3) Join arguments with ,
+// So std -> libstd.so
+//    a b/... -> liba,b.so
+//    gopkg.in/tomb.v2 -> libgopkg.in-tomb.v2.so
+func libname(args []string) string {
+	var libname string
+	for _, arg := range args {
+		arg = strings.TrimSuffix(arg, "/...")
+		arg = strings.Replace(arg, "/", "-", -1)
+		if libname == "" {
+			libname = arg
+		} else {
+			libname += "," + arg
+		}
+	}
+	// TODO(mwhudson): Needs to change for platforms that use different naming
+	// conventions...
+	return "lib" + libname + ".so"
+}
+
 func runInstall(cmd *Command, args []string) {
 	raceInit()
-	pkgs := packagesForBuild(args)
+	buildModeInit()
+	pkgs := pkgsFilter(packagesForBuild(args))
 
 	for _, p := range pkgs {
 		if p.Target == "" && (!p.Standard || p.ImportPath != "unsafe") {
-			if p.cmdline {
+			switch {
+			case p.gobinSubdir:
+				errorf("go install: cannot install cross-compiled binaries when GOBIN is set")
+			case p.cmdline:
 				errorf("go install: no install location for .go files listed on command line (GOBIN not set)")
-			} else if p.ConflictDir != "" {
+			case p.ConflictDir != "":
 				errorf("go install: no install location for %s: hidden by %s", p.Dir, p.ConflictDir)
-			} else {
-				errorf("go install: no install location for directory %s outside GOPATH", p.Dir)
+			default:
+				errorf("go install: no install location for directory %s outside GOPATH\n"+
+					"\tFor more details see: go help gopath", p.Dir)
 			}
 		}
 	}
@@ -344,18 +527,68 @@ func runInstall(cmd *Command, args []string) {
 
 	var b builder
 	b.init()
-	a := &action{}
-	for _, p := range pkgs {
-		a.deps = append(a.deps, b.action(modeInstall, modeInstall, p))
+	var a *action
+	if buildBuildmode == "shared" {
+		a = b.libaction(libname(args), pkgs, modeInstall, modeInstall)
+	} else {
+		a = &action{}
+		var tools []*action
+		for _, p := range pkgs {
+			// If p is a tool, delay the installation until the end of the build.
+			// This avoids installing assemblers/compilers that are being executed
+			// by other steps in the build.
+			// cmd/cgo is handled specially in b.action, so that we can
+			// both build and use it in the same 'go install'.
+			action := b.action(modeInstall, modeInstall, p)
+			if goTools[p.ImportPath] == toTool && p.ImportPath != "cmd/cgo" {
+				a.deps = append(a.deps, action.deps...)
+				action.deps = append(action.deps, a)
+				tools = append(tools, action)
+				continue
+			}
+			a.deps = append(a.deps, action)
+		}
+		if len(tools) > 0 {
+			a = &action{
+				deps: tools,
+			}
+		}
 	}
 	b.do(a)
+	exitIfErrors()
+
+	// Success. If this command is 'go install' with no arguments
+	// and the current directory (the implicit argument) is a command,
+	// remove any leftover command binary from a previous 'go build'.
+	// The binary is installed; it's not needed here anymore.
+	// And worse it might be a stale copy, which you don't want to find
+	// instead of the installed one if $PATH contains dot.
+	// One way to view this behavior is that it is as if 'go install' first
+	// runs 'go build' and the moves the generated file to the install dir.
+	// See issue 9645.
+	if len(args) == 0 && len(pkgs) == 1 && pkgs[0].Name == "main" {
+		// Compute file 'go build' would have created.
+		// If it exists and is an executable file, remove it.
+		_, targ := filepath.Split(pkgs[0].ImportPath)
+		targ += exeSuffix
+		if filepath.Join(pkgs[0].Dir, targ) != pkgs[0].Target { // maybe $GOBIN is the current directory
+			fi, err := os.Stat(targ)
+			if err == nil {
+				m := fi.Mode()
+				if m.IsRegular() {
+					if m&0111 != 0 || goos == "windows" { // windows never sets executable bit
+						os.Remove(targ)
+					}
+				}
+			}
+		}
+	}
 }
 
 // Global build parameters (used during package load)
 var (
 	goarch    string
 	goos      string
-	archChar  string
 	exeSuffix string
 )
 
@@ -365,16 +598,6 @@ func init() {
 	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 = ""
-	}
 }
 
 // A builder holds global state about a build.
@@ -421,8 +644,9 @@ type action struct {
 
 // cacheKey is the key for the action cache.
 type cacheKey struct {
-	mode buildMode
-	p    *Package
+	mode  buildMode
+	p     *Package
+	shlib string
 }
 
 // buildMode specifies the build mode:
@@ -497,6 +721,9 @@ func goFilesPackage(gofiles []string) *Package {
 			fatalf("%s is a directory, should be a Go file", file)
 		}
 		dir1, _ := filepath.Split(file)
+		if dir1 == "" {
+			dir1 = "./"
+		}
 		if dir == "" {
 			dir = dir1
 		} else if dir != dir1 {
@@ -533,11 +760,8 @@ func goFilesPackage(gofiles []string) *Package {
 		if gobin != "" {
 			pkg.target = filepath.Join(gobin, exe)
 		}
-	} else {
-		if *buildO == "" {
-			*buildO = pkg.Name + ".a"
-		}
 	}
+
 	pkg.Target = pkg.target
 	pkg.Stale = true
 
@@ -545,24 +769,88 @@ func goFilesPackage(gofiles []string) *Package {
 	return pkg
 }
 
+// readpkglist returns the list of packages that were built into the shared library
+// at shlibpath. For the native toolchain this list is stored, newline separated, in
+// an ELF note with name "Go\x00\x00" and type 1. For GCCGO it is extracted from the
+// .go_export section.
+func readpkglist(shlibpath string) (pkgs []*Package) {
+	var stk importStack
+	if _, gccgo := buildToolchain.(gccgoToolchain); gccgo {
+		f, _ := elf.Open(shlibpath)
+		sect := f.Section(".go_export")
+		data, _ := sect.Data()
+		scanner := bufio.NewScanner(bytes.NewBuffer(data))
+		for scanner.Scan() {
+			t := scanner.Text()
+			if strings.HasPrefix(t, "pkgpath ") {
+				t = strings.TrimPrefix(t, "pkgpath ")
+				t = strings.TrimSuffix(t, ";")
+				pkgs = append(pkgs, loadPackage(t, &stk))
+			}
+		}
+	} else {
+		pkglistbytes, err := readELFNote(shlibpath, "Go\x00\x00", 1)
+		if err != nil {
+			fatalf("readELFNote failed: %v", err)
+		}
+		scanner := bufio.NewScanner(bytes.NewBuffer(pkglistbytes))
+		for scanner.Scan() {
+			t := scanner.Text()
+			pkgs = append(pkgs, loadPackage(t, &stk))
+		}
+	}
+	return
+}
+
 // action returns the action for applying the given operation (mode) to the package.
 // depMode is the action to use when building dependencies.
+// action never looks for p in a shared library.
 func (b *builder) action(mode buildMode, depMode buildMode, p *Package) *action {
-	key := cacheKey{mode, p}
+	return b.action1(mode, depMode, p, false)
+}
+
+// action1 returns the action for applying the given operation (mode) to the package.
+// depMode is the action to use when building dependencies.
+// action1 will look for p in a shared library if lookshared is true.
+func (b *builder) action1(mode buildMode, depMode buildMode, p *Package, lookshared bool) *action {
+	shlib := ""
+	if lookshared {
+		shlib = p.Shlib
+	}
+	key := cacheKey{mode, p, shlib}
+
 	a := b.actionCache[key]
 	if a != nil {
 		return a
 	}
+	if shlib != "" {
+		key2 := cacheKey{modeInstall, nil, shlib}
+		a = b.actionCache[key2]
+		if a != nil {
+			b.actionCache[key] = a
+			return a
+		}
+		pkgs := readpkglist(shlib)
+		a = b.libaction(filepath.Base(shlib), pkgs, modeInstall, depMode)
+		b.actionCache[key2] = a
+		b.actionCache[key] = a
+		return a
+	}
 
 	a = &action{p: p, pkgdir: p.build.PkgRoot}
 	if p.pkgdir != "" { // overrides p.t
 		a.pkgdir = p.pkgdir
 	}
-
 	b.actionCache[key] = a
 
 	for _, p1 := range p.imports {
-		a.deps = append(a.deps, b.action(depMode, depMode, p1))
+		ls := buildLinkshared
+		// If p1 is part of the same shared library as p, we need the action
+		// that builds p here, not the shared libary or we get action loops.
+		if p1.Shlib == p.Shlib {
+			ls = false
+		}
+		a.deps = append(a.deps, b.action1(depMode, depMode, p1, ls))
 	}
 
 	// If we are not doing a cross-build, then record the binary we'll
@@ -571,7 +859,7 @@ func (b *builder) action(mode buildMode, depMode buildMode, p *Package) *action
 	// a package is using it.  If this is a cross-build, then the cgo we
 	// are writing is not the cgo we need to use.
 	if goos == runtime.GOOS && goarch == runtime.GOARCH && !buildRace {
-		if len(p.CgoFiles) > 0 || p.Standard && p.ImportPath == "runtime/cgo" {
+		if (len(p.CgoFiles) > 0 || p.Standard && p.ImportPath == "runtime/cgo") && !buildLinkshared && buildBuildmode != "shared" {
 			var stk importStack
 			p1 := loadPackage("cmd/cgo", &stk)
 			if p1.Error != nil {
@@ -618,8 +906,22 @@ func (b *builder) action(mode buildMode, depMode buildMode, p *Package) *action
 	switch mode {
 	case modeInstall:
 		a.f = (*builder).install
-		a.deps = []*action{b.action(modeBuild, depMode, p)}
+		a.deps = []*action{b.action1(modeBuild, depMode, p, lookshared)}
 		a.target = a.p.target
+
+		// Install header for cgo in c-archive and c-shared modes.
+		if p.usesCgo() && (buildBuildmode == "c-archive" || buildBuildmode == "c-shared") {
+			ah := &action{
+				p:      a.p,
+				deps:   []*action{a.deps[0]},
+				f:      (*builder).installHeader,
+				pkgdir: a.pkgdir,
+				objdir: a.objdir,
+				target: a.target[:len(a.target)-len(filepath.Ext(a.target))] + ".h",
+			}
+			a.deps = append(a.deps, ah)
+		}
+
 	case modeBuild:
 		a.f = (*builder).build
 		a.target = a.objpkg
@@ -634,6 +936,13 @@ func (b *builder) action(mode buildMode, depMode buildMode, p *Package) *action
 			name := "a.out"
 			if p.exeName != "" {
 				name = p.exeName
+			} else if goos == "darwin" && buildBuildmode == "c-shared" && p.target != "" {
+				// On OS X, the linker output name gets recorded in the
+				// shared library's LC_ID_DYLIB load command.
+				// The code invoking the linker knows to pass only the final
+				// path element. Arrange that the path element matches what
+				// we'll install it as; otherwise the library is only loadable as "a.out".
+				_, name = filepath.Split(p.target)
 			}
 			a.target = a.objdir + filepath.Join("exe", name) + exeSuffix
 		}
@@ -642,6 +951,100 @@ func (b *builder) action(mode buildMode, depMode buildMode, p *Package) *action
 	return a
 }
 
+func (b *builder) libaction(libname string, pkgs []*Package, mode, depMode buildMode) *action {
+	a := &action{}
+	if mode == modeBuild {
+		a.f = (*builder).linkShared
+		a.target = filepath.Join(b.work, libname)
+		for _, p := range pkgs {
+			if p.target == "" {
+				continue
+			}
+			a.deps = append(a.deps, b.action(depMode, depMode, p))
+		}
+	} else if mode == modeInstall {
+		// Currently build mode shared forces external linking mode, and
+		// external linking mode forces an import of runtime/cgo. So if it
+		// was not passed on the command line and it is not present in
+		// another shared library, add it here.
+		seencgo := false
+		_, gccgo := buildToolchain.(gccgoToolchain)
+		if !gccgo {
+			for _, p := range pkgs {
+				seencgo = seencgo || (p.Standard && p.ImportPath == "runtime/cgo")
+			}
+			if !seencgo {
+				var stk importStack
+				p := loadPackage("runtime/cgo", &stk)
+				if p.Error != nil {
+					fatalf("load runtime/cgo: %v", p.Error)
+				}
+				computeStale(p)
+				// If runtime/cgo is in another shared library, then that's
+				// also the shared library that contains runtime, so
+				// something will depend on it and so runtime/cgo's staleness
+				// will be checked when processing that library.
+				if p.Shlib == "" || p.Shlib == libname {
+					pkgs = append([]*Package{}, pkgs...)
+					pkgs = append(pkgs, p)
+				}
+			}
+		}
+
+		// Figure out where the library will go.
+		var libdir string
+		for _, p := range pkgs {
+			plibdir := p.build.PkgTargetRoot
+			if gccgo {
+				plibdir = filepath.Join(plibdir, "shlibs")
+			}
+			if libdir == "" {
+				libdir = plibdir
+			} else if libdir != plibdir {
+				fatalf("multiple roots %s & %s", libdir, plibdir)
+			}
+		}
+		a.target = filepath.Join(libdir, libname)
+
+		// Now we can check whether we need to rebuild it.
+		stale := false
+		var built time.Time
+		if fi, err := os.Stat(a.target); err == nil {
+			built = fi.ModTime()
+		}
+		for _, p := range pkgs {
+			if p.target == "" {
+				continue
+			}
+			stale = stale || p.Stale
+			lstat, err := os.Stat(p.target)
+			if err != nil || lstat.ModTime().After(built) {
+				stale = true
+			}
+			a.deps = append(a.deps, b.action(depMode, depMode, p))
+		}
+
+		if stale {
+			a.f = (*builder).install
+			buildAction := b.libaction(libname, pkgs, modeBuild, depMode)
+			a.deps = []*action{buildAction}
+			for _, p := range pkgs {
+				if p.target == "" {
+					continue
+				}
+				shlibnameaction := &action{}
+				shlibnameaction.f = (*builder).installShlibname
+				shlibnameaction.target = p.target[:len(p.target)-2] + ".shlibname"
+				a.deps = append(a.deps, shlibnameaction)
+				shlibnameaction.deps = append(shlibnameaction.deps, buildAction)
+			}
+		}
+	} else {
+		fatalf("unregonized mode %v", mode)
+	}
+	return a
+}
+
 // actionList returns the list of actions in the dag rooted at root
 // as visited in a depth-first post-order traversal.
 func actionList(root *action) []*action {
@@ -662,6 +1065,31 @@ func actionList(root *action) []*action {
 	return all
 }
 
+// allArchiveActions returns a list of the archive dependencies of root.
+// This is needed because if package p depends on package q that is in libr.so, the
+// action graph looks like p->libr.so->q and so just scanning through p's
+// dependencies does not find the import dir for q.
+func allArchiveActions(root *action) []*action {
+	seen := map[*action]bool{}
+	r := []*action{}
+	var walk func(*action)
+	walk = func(a *action) {
+		if seen[a] {
+			return
+		}
+		seen[a] = true
+		if strings.HasSuffix(a.target, ".so") || a == root {
+			for _, a1 := range a.deps {
+				walk(a1)
+			}
+		} else if strings.HasSuffix(a.target, ".a") {
+			r = append(r, a)
+		}
+	}
+	walk(root)
+	return r
+}
+
 // do runs the action graph rooted at root.
 func (b *builder) do(root *action) {
 	// Build list of all actions, assigning depth-first post-order priority.
@@ -782,9 +1210,7 @@ func hasString(strings []string, s string) bool {
 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, ","))
@@ -813,7 +1239,8 @@ func (b *builder) build(a *action) (err error) {
 	}
 
 	if a.p.Standard && a.p.ImportPath == "runtime" && buildContext.Compiler == "gc" &&
-		!hasString(a.p.HFiles, "zasm_"+buildContext.GOOS+"_"+buildContext.GOARCH+".h") {
+		(!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())
 	}
 
@@ -831,19 +1258,35 @@ func (b *builder) build(a *action) (err error) {
 		}
 	}
 
-	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.
@@ -872,31 +1315,7 @@ func (b *builder) build(a *action) (err error) {
 		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
 		}
@@ -938,10 +1357,10 @@ func (b *builder) build(a *action) (err error) {
 	}
 
 	// Prepare Go import path list.
-	inc := b.includeArgs("-I", a.deps)
+	inc := b.includeArgs("-I", allArchiveActions(a))
 
 	// Compile Go.
-	ofile, out, err := buildToolchain.gc(b, a.p, a.objpkg, obj, inc, gofiles)
+	ofile, out, err := buildToolchain.gc(b, a.p, a.objpkg, obj, len(sfiles) > 0, inc, gofiles)
 	if len(out) > 0 {
 		b.showOutput(a.p.Dir, a.p.ImportPath, b.processOutput(out))
 		if err != nil {
@@ -966,29 +1385,24 @@ func (b *builder) build(a *action) (err error) {
 		switch {
 		case strings.HasSuffix(name, _goos_goarch):
 			targ := file[:len(name)-len(_goos_goarch)] + "_GOOS_GOARCH." + ext
-			if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0644); err != nil {
+			if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0644, true); err != nil {
 				return err
 			}
 		case strings.HasSuffix(name, _goarch):
 			targ := file[:len(name)-len(_goarch)] + "_GOARCH." + ext
-			if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0644); err != nil {
+			if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0644, true); err != nil {
 				return err
 			}
 		case strings.HasSuffix(name, _goos):
 			targ := file[:len(name)-len(_goos)] + "_GOOS." + ext
-			if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0644); err != nil {
+			if err := b.copyFile(a, obj+targ, filepath.Join(a.p.Dir, file), 0644, true); err != nil {
 				return err
 			}
 		}
 	}
 
-	objExt := archChar
-	if _, ok := buildToolchain.(gccgoToolchain); ok {
-		objExt = "o"
-	}
-
 	for _, file := range cfiles {
-		out := file[:len(file)-len(".c")] + "." + objExt
+		out := file[:len(file)-len(".c")] + ".o"
 		if err := buildToolchain.cc(b, a.p, obj, obj+out, file); err != nil {
 			return err
 		}
@@ -997,7 +1411,7 @@ func (b *builder) build(a *action) (err error) {
 
 	// Assemble .s files.
 	for _, file := range sfiles {
-		out := file[:len(file)-len(".s")] + "." + objExt
+		out := file[:len(file)-len(".s")] + ".o"
 		if err := buildToolchain.asm(b, a.p, obj, obj+out, file); err != nil {
 			return err
 		}
@@ -1007,7 +1421,7 @@ func (b *builder) build(a *action) (err error) {
 	// NOTE(rsc): On Windows, it is critically important that the
 	// gcc-compiled objects (cgoObjects) be listed after the ordinary
 	// objects in the archive.  I do not know why this is.
-	// http://golang.org/issue/2601
+	// https://golang.org/issue/2601
 	objects = append(objects, cgoObjects...)
 
 	// Add system object files.
@@ -1032,7 +1446,7 @@ func (b *builder) build(a *action) (err error) {
 		// linker needs the whole dependency tree.
 		all := actionList(a)
 		all = all[:len(all)-1] // drop a
-		if err := buildToolchain.ld(b, a.p, a.target, all, a.objpkg, objects); err != nil {
+		if err := buildToolchain.ld(b, a, a.target, all, a.objpkg, objects); err != nil {
 			return err
 		}
 	}
@@ -1068,6 +1482,24 @@ func (b *builder) getPkgConfigFlags(p *Package) (cflags, ldflags []string, err e
 	return
 }
 
+func (b *builder) installShlibname(a *action) error {
+	a1 := a.deps[0]
+	err := ioutil.WriteFile(a.target, []byte(filepath.Base(a1.target)+"\n"), 0644)
+	if err != nil {
+		return err
+	}
+	if buildX {
+		b.showcmd("", "echo '%s' > %s # internal", filepath.Base(a1.target), a.target)
+	}
+	return nil
+}
+
+func (b *builder) linkShared(a *action) (err error) {
+	allactions := actionList(a)
+	allactions = allactions[:len(allactions)-1]
+	return buildToolchain.ldShared(b, a.deps, a.target, allactions)
+}
+
 // install is the action for installing a single package or executable.
 func (b *builder) install(a *action) (err error) {
 	defer func() {
@@ -1078,7 +1510,11 @@ func (b *builder) install(a *action) (err error) {
 	a1 := a.deps[0]
 	perm := os.FileMode(0644)
 	if a1.link {
-		perm = 0755
+		switch buildBuildmode {
+		case "c-archive", "c-shared":
+		default:
+			perm = 0755
+		}
 	}
 
 	// make target directory
@@ -1098,7 +1534,7 @@ func (b *builder) install(a *action) (err error) {
 		defer os.Remove(a1.target)
 	}
 
-	return b.moveOrCopyFile(a, a.target, a1.target, perm)
+	return b.moveOrCopyFile(a, a.target, a1.target, perm, false)
 }
 
 // includeArgs returns the -I or -L directory list for access
@@ -1115,6 +1551,9 @@ func (b *builder) includeArgs(flag string, all []*action) []string {
 	// This is the $WORK/my/package/_test directory for the
 	// package being built, so there are few of these.
 	for _, a1 := range all {
+		if a1.p == nil {
+			continue
+		}
 		if dir := a1.pkgdir; dir != a1.p.build.PkgRoot && !incMap[dir] {
 			incMap[dir] = true
 			inc = append(inc, flag, dir)
@@ -1127,17 +1566,12 @@ func (b *builder) includeArgs(flag string, all []*action) []string {
 
 	// Finally, look in the installed package directories for each action.
 	for _, a1 := range all {
+		if a1.p == nil {
+			continue
+		}
 		if dir := a1.pkgdir; dir == a1.p.build.PkgRoot && !incMap[dir] {
 			incMap[dir] = true
-			if _, ok := buildToolchain.(gccgoToolchain); ok {
-				dir = filepath.Join(dir, "gccgo_"+goos+"_"+goarch)
-			} else {
-				dir = filepath.Join(dir, goos+"_"+goarch)
-				if buildContext.InstallSuffix != "" {
-					dir += "_" + buildContext.InstallSuffix
-				}
-			}
-			inc = append(inc, flag, dir)
+			inc = append(inc, flag, a1.p.build.PkgTargetRoot)
 		}
 	}
 
@@ -1145,7 +1579,7 @@ func (b *builder) includeArgs(flag string, all []*action) []string {
 }
 
 // moveOrCopyFile is like 'mv src dst' or 'cp src dst'.
-func (b *builder) moveOrCopyFile(a *action, dst, src string, perm os.FileMode) error {
+func (b *builder) moveOrCopyFile(a *action, dst, src string, perm os.FileMode, force bool) error {
 	if buildN {
 		b.showcmd("", "mv %s %s", src, dst)
 		return nil
@@ -1162,11 +1596,11 @@ func (b *builder) moveOrCopyFile(a *action, dst, src string, perm os.FileMode) e
 		}
 	}
 
-	return b.copyFile(a, dst, src, perm)
+	return b.copyFile(a, dst, src, perm, force)
 }
 
 // copyFile is like 'cp src dst'.
-func (b *builder) copyFile(a *action, dst, src string, perm os.FileMode) error {
+func (b *builder) copyFile(a *action, dst, src string, perm os.FileMode, force bool) error {
 	if buildN || buildX {
 		b.showcmd("", "cp %s %s", src, dst)
 		if buildN {
@@ -1187,7 +1621,7 @@ func (b *builder) copyFile(a *action, dst, src string, perm os.FileMode) error {
 		if fi.IsDir() {
 			return fmt.Errorf("build output %q already exists and is a directory", dst)
 		}
-		if !isObject(dst) {
+		if !force && !isObject(dst) {
 			return fmt.Errorf("build output %q already exists and is not an object file", dst)
 		}
 	}
@@ -1224,10 +1658,30 @@ func (b *builder) copyFile(a *action, dst, src string, perm os.FileMode) error {
 	return nil
 }
 
+// Install the cgo export header file, if there is one.
+func (b *builder) installHeader(a *action) error {
+	src := a.objdir + "_cgo_install.h"
+	if _, err := os.Stat(src); os.IsNotExist(err) {
+		// If the file does not exist, there are no exported
+		// functions, and we do not install anything.
+		return nil
+	}
+
+	dir, _ := filepath.Split(a.target)
+	if dir != "" {
+		if err := b.mkdir(dir); err != nil {
+			return err
+		}
+	}
+
+	return b.moveOrCopyFile(a, a.target, src, 0644, true)
+}
+
 // cover runs, in effect,
 //	go tool cover -mode=b.coverMode -var="varName" -o dst.go src.go
 func (b *builder) cover(a *action, dst, src string, perm os.FileMode, varName string) error {
 	return b.run(a.objdir, "cover "+a.p.ImportPath, nil,
+		buildToolExec,
 		tool("cover"),
 		"-mode", a.p.coverMode,
 		"-var", varName,
@@ -1236,15 +1690,15 @@ func (b *builder) cover(a *action, dst, src string, perm os.FileMode, varName st
 }
 
 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 {
@@ -1425,7 +1879,7 @@ func (b *builder) runOut(dir string, desc string, env []string, cmdargs ...inter
 		cmd.Stdout = &buf
 		cmd.Stderr = &buf
 		cmd.Dir = dir
-		cmd.Env = mergeEnvLists(env, envForDir(cmd.Dir))
+		cmd.Env = mergeEnvLists(env, envForDir(cmd.Dir, os.Environ()))
 		err := cmd.Run()
 
 		// cmd.Run will fail on Unix if some other process has the binary
@@ -1467,7 +1921,7 @@ func (b *builder) runOut(dir string, desc string, env []string, cmdargs ...inter
 		// Sleeping when we observe the race seems to be the most reliable
 		// option we have.
 		//
-		// http://golang.org/issue/3001
+		// https://golang.org/issue/3001
 		//
 		if err != nil && nbusy < 3 && strings.Contains(err.Error(), "text file busy") {
 			time.Sleep(100 * time.Millisecond << uint(nbusy))
@@ -1550,7 +2004,7 @@ type toolchain interface {
 	// gc runs the compiler in a specific directory on a set of files
 	// and returns the name of the generated output file.
 	// The compiler runs in the directory dir.
-	gc(b *builder, p *Package, archive, obj string, importArgs []string, gofiles []string) (ofile string, out []byte, err error)
+	gc(b *builder, p *Package, archive, obj string, asmhdr bool, importArgs []string, gofiles []string) (ofile string, out []byte, err error)
 	// cc runs the toolchain's C compiler in a directory on a C file
 	// to produce an output file.
 	cc(b *builder, p *Package, objdir, ofile, cfile string) error
@@ -1563,8 +2017,10 @@ type toolchain interface {
 	// an archive from a set of object files.
 	// typically it is run in the object directory.
 	pack(b *builder, p *Package, objDir, afile string, ofiles []string) error
-	// ld runs the linker to create a package starting at mainpkg.
-	ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error
+	// ld runs the linker to create an executable starting at mainpkg.
+	ld(b *builder, root *action, out string, allactions []*action, mainpkg string, ofiles []string) error
+	// ldShared runs the linker to create a shared library containing the pkgs built by toplevelactions
+	ldShared(b *builder, toplevelactions []*action, out string, allactions []*action) error
 
 	compiler() string
 	linker() string
@@ -1587,7 +2043,7 @@ func (noToolchain) linker() string {
 	return ""
 }
 
-func (noToolchain) gc(b *builder, p *Package, archive, obj string, importArgs []string, gofiles []string) (ofile string, out []byte, err error) {
+func (noToolchain) gc(b *builder, p *Package, archive, obj string, asmhdr bool, importArgs []string, gofiles []string) (ofile string, out []byte, err error) {
 	return "", nil, noCompiler()
 }
 
@@ -1604,7 +2060,11 @@ func (noToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles []s
 	return noCompiler()
 }
 
-func (noToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error {
+func (noToolchain) ld(b *builder, root *action, out string, allactions []*action, mainpkg string, ofiles []string) error {
+	return noCompiler()
+}
+
+func (noToolchain) ldShared(b *builder, toplevelactions []*action, out string, allactions []*action) error {
 	return noCompiler()
 }
 
@@ -1616,24 +2076,27 @@ func (noToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error
 type gcToolchain struct{}
 
 func (gcToolchain) compiler() string {
-	return tool(archChar + "g")
+	return tool("compile")
 }
 
 func (gcToolchain) linker() string {
-	return tool(archChar + "l")
+	return tool("link")
 }
 
-func (gcToolchain) gc(b *builder, p *Package, archive, obj string, importArgs []string, gofiles []string) (ofile string, output []byte, err error) {
+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_.o"
 		ofile = obj + out
 	}
 
 	gcargs := []string{"-p", p.ImportPath}
+	if p.Name == "main" {
+		gcargs[1] = "main"
+	}
 	if p.Standard && p.ImportPath == "runtime" {
-		// runtime compiles with a special 6g flag to emit
+		// runtime compiles with a special gc flag to emit
 		// additional reflect type data.
 		gcargs = append(gcargs, "-+")
 	}
@@ -1655,24 +2118,68 @@ func (gcToolchain) gc(b *builder, p *Package, archive, obj string, importArgs []
 	if buildContext.InstallSuffix != "" {
 		gcargs = append(gcargs, "-installsuffix", buildContext.InstallSuffix)
 	}
+	if p.buildID != "" {
+		gcargs = append(gcargs, "-buildid", p.buildID)
+	}
+
+	for _, path := range p.Imports {
+		if i := strings.LastIndex(path, "/vendor/"); i >= 0 {
+			gcargs = append(gcargs, "-importmap", path[i+len("/vendor/"):]+"="+path)
+		} else if strings.HasPrefix(path, "vendor/") {
+			gcargs = append(gcargs, "-importmap", path[len("vendor/"):]+"="+path)
+		}
+	}
 
-	args := stringList(tool(archChar+"g"), "-o", ofile, "-trimpath", b.work, buildGcflags, gcargs, "-D", p.localPrefix, importArgs)
+	args := []interface{}{buildToolExec, tool("compile"), "-o", ofile, "-trimpath", b.work, buildGcflags, gcargs, "-D", p.localPrefix, importArgs}
 	if ofile == archive {
 		args = append(args, "-pack")
 	}
+	if asmhdr {
+		args = append(args, "-asmhdr", obj+"go_asm.h")
+	}
 	for _, f := range gofiles {
 		args = append(args, mkAbs(p.Dir, f))
 	}
 
-	output, err = b.runOut(p.Dir, p.ImportPath, nil, args)
+	output, err = b.runOut(p.Dir, p.ImportPath, nil, args...)
 	return ofile, output, err
 }
 
 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)
-	return b.run(p.Dir, p.ImportPath, nil, tool(archChar+"a"), "-trimpath", b.work, "-I", obj, "-I", inc, "-o", ofile, "-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
+	}
+	return nil
+}
+
+// toolVerify checks that the command line args writes the same output file
+// if run using newTool instead.
+// Unused now but kept around for future use.
+func toolVerify(b *builder, p *Package, newTool string, ofile string, args []interface{}) error {
+	newArgs := make([]interface{}, len(args))
+	copy(newArgs, args)
+	newArgs[1] = tool(newTool)
+	newArgs[3] = ofile + ".new" // x.6 becomes x.6.new
+	if err := b.run(p.Dir, p.ImportPath, nil, newArgs...); err != nil {
+		return err
+	}
+	data1, err := ioutil.ReadFile(ofile)
+	if err != nil {
+		return err
+	}
+	data2, err := ioutil.ReadFile(ofile + ".new")
+	if err != nil {
+		return err
+	}
+	if !bytes.Equal(data1, data2) {
+		return fmt.Errorf("%s and %s produced different output files:\n%s\n%s", filepath.Base(args[1].(string)), newTool, strings.Join(stringList(args...), " "), strings.Join(stringList(newArgs...), " "))
+	}
+	os.Remove(ofile + ".new")
+	return nil
 }
 
 func (gcToolchain) pkgpath(basedir string, p *Package) string {
@@ -1711,7 +2218,7 @@ func (gcToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles []s
 
 	// Need actual pack.
 	cmdline[0] = tool("pack")
-	return b.run(p.Dir, p.ImportPath, nil, cmdline)
+	return b.run(p.Dir, p.ImportPath, nil, buildToolExec, cmdline)
 }
 
 func packInternal(b *builder, afile string, ofiles []string) error {
@@ -1764,21 +2271,49 @@ func packInternal(b *builder, afile string, ofiles []string) error {
 	return dst.Close()
 }
 
-func (gcToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error {
+// setextld sets the appropriate linker flags for the specified compiler.
+func setextld(ldflags []string, compiler []string) []string {
+	for _, f := range ldflags {
+		if f == "-extld" || strings.HasPrefix(f, "-extld=") {
+			// don't override -extld if supplied
+			return ldflags
+		}
+	}
+	ldflags = append(ldflags, "-extld="+compiler[0])
+	if len(compiler) > 1 {
+		extldflags := false
+		add := strings.Join(compiler[1:], " ")
+		for i, f := range ldflags {
+			if f == "-extldflags" && i+1 < len(ldflags) {
+				ldflags[i+1] = add + " " + ldflags[i+1]
+				extldflags = true
+				break
+			} else if strings.HasPrefix(f, "-extldflags=") {
+				ldflags[i] = "-extldflags=" + add + " " + ldflags[i][len("-extldflags="):]
+				extldflags = true
+				break
+			}
+		}
+		if !extldflags {
+			ldflags = append(ldflags, "-extldflags="+add)
+		}
+	}
+	return ldflags
+}
+
+func (gcToolchain) ld(b *builder, root *action, out string, allactions []*action, mainpkg string, ofiles []string) error {
 	importArgs := b.includeArgs("-L", allactions)
-	cxx := len(p.CXXFiles) > 0
+	cxx := len(root.p.CXXFiles) > 0 || len(root.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
 		}
 	}
-	ldflags := buildLdflags
-	// Limit slice capacity so that concurrent appends do not race on the shared array.
-	ldflags = ldflags[:len(ldflags):len(ldflags)]
+	var ldflags []string
 	if buildContext.InstallSuffix != "" {
 		ldflags = append(ldflags, "-installsuffix", buildContext.InstallSuffix)
 	}
-	if p.omitDWARF {
+	if root.p.omitDWARF {
 		ldflags = append(ldflags, "-w")
 	}
 
@@ -1786,56 +2321,67 @@ func (gcToolchain) ld(b *builder, p *Package, out string, allactions []*action,
 	// appropriate linker. In case of C++ code, use the compiler named
 	// by the CXX environment variable or defaultCXX if CXX is not set.
 	// Else, use the CC environment variable and defaultCC as fallback.
-	extld := false
-	for _, f := range ldflags {
-		if f == "-extld" || strings.HasPrefix(f, "-extld=") {
-			extld = true
-			break
+	var compiler []string
+	if cxx {
+		compiler = envList("CXX", defaultCXX)
+	} else {
+		compiler = envList("CC", defaultCC)
+	}
+	ldflags = setextld(ldflags, compiler)
+	ldflags = append(ldflags, "-buildmode="+ldBuildmode)
+	if root.p.buildID != "" {
+		ldflags = append(ldflags, "-buildid="+root.p.buildID)
+	}
+	ldflags = append(ldflags, buildLdflags...)
+
+	// On OS X when using external linking to build a shared library,
+	// the argument passed here to -o ends up recorded in the final
+	// shared library in the LC_ID_DYLIB load command.
+	// To avoid putting the temporary output directory name there
+	// (and making the resulting shared library useless),
+	// run the link in the output directory so that -o can name
+	// just the final path element.
+	dir := "."
+	if goos == "darwin" && buildBuildmode == "c-shared" {
+		dir, out = filepath.Split(out)
+	}
+
+	return b.run(dir, root.p.ImportPath, nil, buildToolExec, tool("link"), "-o", out, importArgs, ldflags, mainpkg)
+}
+
+func (gcToolchain) ldShared(b *builder, toplevelactions []*action, out string, allactions []*action) error {
+	importArgs := b.includeArgs("-L", allactions)
+	ldflags := []string{"-installsuffix", buildContext.InstallSuffix}
+	ldflags = append(ldflags, "-buildmode=shared")
+	ldflags = append(ldflags, buildLdflags...)
+	cxx := false
+	for _, a := range allactions {
+		if a.p != nil && (len(a.p.CXXFiles) > 0 || len(a.p.SwigCXXFiles) > 0) {
+			cxx = true
 		}
 	}
-	if !extld {
-		var compiler []string
-		if cxx {
-			compiler = envList("CXX", defaultCXX)
-		} else {
-			compiler = envList("CC", defaultCC)
-		}
-		ldflags = append(ldflags, "-extld="+compiler[0])
-		if len(compiler) > 1 {
-			extldflags := false
-			add := strings.Join(compiler[1:], " ")
-			for i, f := range ldflags {
-				if f == "-extldflags" && i+1 < len(ldflags) {
-					ldflags[i+1] = add + " " + ldflags[i+1]
-					extldflags = true
-					break
-				} else if strings.HasPrefix(f, "-extldflags=") {
-					ldflags[i] = "-extldflags=" + add + " " + ldflags[i][len("-extldflags="):]
-					extldflags = true
-					break
-				}
-			}
-			if !extldflags {
-				ldflags = append(ldflags, "-extldflags="+add)
-			}
+	// If the user has not specified the -extld option, then specify the
+	// appropriate linker. In case of C++ code, use the compiler named
+	// by the CXX environment variable or defaultCXX if CXX is not set.
+	// Else, use the CC environment variable and defaultCC as fallback.
+	var compiler []string
+	if cxx {
+		compiler = envList("CXX", defaultCXX)
+	} else {
+		compiler = envList("CC", defaultCC)
+	}
+	ldflags = setextld(ldflags, compiler)
+	for _, d := range toplevelactions {
+		if !strings.HasSuffix(d.target, ".a") { // omit unsafe etc and actions for other shared libraries
+			continue
 		}
+		ldflags = append(ldflags, d.p.ImportPath+"="+d.target)
 	}
-	return b.run(".", p.ImportPath, nil, tool(archChar+"l"), "-o", out, importArgs, ldflags, mainpkg)
+	return b.run(".", out, nil, buildToolExec, tool("link"), "-o", out, importArgs, ldflags)
 }
 
 func (gcToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
-	inc := filepath.Join(goroot, "pkg", fmt.Sprintf("%s_%s", goos, goarch))
-	cfile = mkAbs(p.Dir, cfile)
-	warn := []string{"-w"}
-	if p.usesSwig() {
-		// When using SWIG, this compiler is only used to
-		// compile the C files generated by SWIG.
-		// We don't want warnings.
-		// See issue 9065 for details.
-		warn = nil
-	}
-	args := stringList(tool(archChar+"c"), "-F", "-V", warn, "-trimpath", b.work, "-I", objdir, "-I", inc, "-o", ofile, buildCcflags, "-D", "GOOS_"+goos, "-D", "GOARCH_"+goarch, cfile)
-	return b.run(p.Dir, p.ImportPath, nil, args)
+	return fmt.Errorf("%s: C source files not supported without cgo", mkAbs(p.Dir, cfile))
 }
 
 // The Gccgo toolchain.
@@ -1859,7 +2405,7 @@ func (gccgoToolchain) linker() string {
 	return gccgoBin
 }
 
-func (gccgoToolchain) gc(b *builder, p *Package, archive, obj string, 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"}
@@ -1870,7 +2416,7 @@ func (gccgoToolchain) gc(b *builder, p *Package, archive, obj string, importArgs
 	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))
 	}
@@ -1879,14 +2425,15 @@ func (gccgoToolchain) gc(b *builder, p *Package, archive, obj string, importArgs
 	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 = tools.maybePIC(defs)
 	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 {
@@ -1904,27 +2451,49 @@ func (gccgoToolchain) pack(b *builder, p *Package, objDir, afile string, ofiles
 	return b.run(p.Dir, p.ImportPath, nil, "ar", "cru", mkAbs(objDir, afile), absOfiles)
 }
 
-func (tools gccgoToolchain) ld(b *builder, p *Package, out string, allactions []*action, mainpkg string, ofiles []string) error {
+func (tools gccgoToolchain) ld(b *builder, root *action, 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{}
+	shlibs := []string{}
+	xfiles := []string{}
 	ldflags := b.gccArchArgs()
 	cgoldflags := []string{}
 	usesCgo := false
-	cxx := len(p.CXXFiles) > 0
-	objc := len(p.MFiles) > 0
-
-	// 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.Standard {
-			if a.p != nil && !apackagesSeen[a.p] {
+	cxx := len(root.p.CXXFiles) > 0 || len(root.p.SwigCXXFiles) > 0
+	objc := len(root.p.MFiles) > 0
+
+	actionsSeen := make(map[*action]bool)
+	// Make a pre-order depth-first traversal of the action graph, taking note of
+	// whether a shared library action has been seen on the way to an action (the
+	// construction of the graph means that if any path to a node passes through
+	// a shared library action, they all do).
+	var walk func(a *action, seenShlib bool)
+	walk = func(a *action, seenShlib bool) {
+		if actionsSeen[a] {
+			return
+		}
+		actionsSeen[a] = true
+		if a.p != nil && !seenShlib {
+			if a.p.Standard {
+				return
+			}
+			// We record the target of the first time we see a .a file
+			// for a package to make sure that we prefer the 'install'
+			// rather than the 'build' location (which may not exist any
+			// more). We still need to traverse the dependencies of the
+			// build action though so saying
+			// if apackagesSeen[a.p] { return }
+			// doesn't work.
+			if !apackagesSeen[a.p] {
 				apackagesSeen[a.p] = true
-				if a.p.fake {
+				if a.p.fake && a.p.external {
+					// external _tests, if present must come before
+					// internal _tests. Store these on a separate 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 {
@@ -1932,53 +2501,182 @@ func (tools gccgoToolchain) ld(b *builder, p *Package, out string, allactions []
 				}
 			}
 		}
+		if strings.HasSuffix(a.target, ".so") {
+			shlibs = append(shlibs, a.target)
+			seenShlib = true
+		}
+		for _, a1 := range a.deps {
+			walk(a1, seenShlib)
+		}
+	}
+	for _, a1 := range root.deps {
+		walk(a1, false)
 	}
+	afiles = append(xfiles, afiles...)
 
 	for _, a := range allactions {
-		if a.p != nil {
+		// Gather CgoLDFLAGS, but not from standard packages.
+		// The go tool can dig up runtime/cgo from GOROOT and
+		// think that it should use its CgoLDFLAGS, but gccgo
+		// doesn't use runtime/cgo.
+		if a.p == nil {
+			continue
+		}
+		if !a.p.Standard {
 			cgoldflags = append(cgoldflags, a.p.CgoLDFLAGS...)
-			if len(a.p.CgoFiles) > 0 {
-				usesCgo = true
-			}
-			if a.p.usesSwig() {
-				usesCgo = true
-			}
-			if len(a.p.CXXFiles) > 0 {
-				cxx = true
-			}
-			if len(a.p.MFiles) > 0 {
-				objc = true
-			}
 		}
+		if len(a.p.CgoFiles) > 0 {
+			usesCgo = true
+		}
+		if a.p.usesSwig() {
+			usesCgo = true
+		}
+		if len(a.p.CXXFiles) > 0 || len(a.p.SwigCXXFiles) > 0 {
+			cxx = true
+		}
+		if len(a.p.MFiles) > 0 {
+			objc = true
+		}
+	}
+
+	switch ldBuildmode {
+	case "c-archive", "c-shared":
+		ldflags = append(ldflags, "-Wl,--whole-archive")
 	}
+
 	ldflags = append(ldflags, afiles...)
+
+	switch ldBuildmode {
+	case "c-archive", "c-shared":
+		ldflags = append(ldflags, "-Wl,--no-whole-archive")
+	}
+
 	ldflags = append(ldflags, cgoldflags...)
 	ldflags = append(ldflags, envList("CGO_LDFLAGS", "")...)
-	ldflags = append(ldflags, p.CgoLDFLAGS...)
-	if usesCgo && goos == "linux" {
-		ldflags = append(ldflags, "-Wl,-E")
+	ldflags = append(ldflags, root.p.CgoLDFLAGS...)
+
+	ldflags = stringList("-Wl,-(", ldflags, "-Wl,-)")
+
+	for _, shlib := range shlibs {
+		ldflags = append(
+			ldflags,
+			"-L"+filepath.Dir(shlib),
+			"-Wl,-rpath="+filepath.Dir(shlib),
+			"-l"+strings.TrimSuffix(
+				strings.TrimPrefix(filepath.Base(shlib), "lib"),
+				".so"))
 	}
-	if cxx {
-		ldflags = append(ldflags, "-lstdc++")
+
+	var realOut string
+	switch ldBuildmode {
+	case "exe":
+		if usesCgo && goos == "linux" {
+			ldflags = append(ldflags, "-Wl,-E")
+		}
+
+	case "c-archive":
+		// Link the Go files into a single .o, and also link
+		// in -lgolibbegin.
+		//
+		// We need to use --whole-archive with -lgolibbegin
+		// because it doesn't define any symbols that will
+		// cause the contents to be pulled in; it's just
+		// initialization code.
+		//
+		// The user remains responsible for linking against
+		// -lgo -lpthread -lm in the final link.  We can't use
+		// -r to pick them up because we can't combine
+		// split-stack and non-split-stack code in a single -r
+		// link, and libgo picks up non-split-stack code from
+		// libffi.
+		ldflags = append(ldflags, "-Wl,-r", "-nostdlib", "-Wl,--whole-archive", "-lgolibbegin", "-Wl,--no-whole-archive")
+
+		// We are creating an object file, so we don't want a build ID.
+		ldflags = b.disableBuildID(ldflags)
+
+		realOut = out
+		out = out + ".o"
+
+	case "c-shared":
+		ldflags = append(ldflags, "-shared", "-nostdlib", "-Wl,--whole-archive", "-lgolibbegin", "-Wl,--no-whole-archive", "-lgo", "-lgcc_s", "-lgcc")
+
+	default:
+		fatalf("-buildmode=%s not supported for gccgo", ldBuildmode)
+	}
+
+	switch ldBuildmode {
+	case "exe", "c-shared":
+		if cxx {
+			ldflags = append(ldflags, "-lstdc++")
+		}
+		if objc {
+			ldflags = append(ldflags, "-lobjc")
+		}
 	}
-	if objc {
-		ldflags = append(ldflags, "-lobjc")
+
+	if err := b.run(".", root.p.ImportPath, nil, tools.linker(), "-o", out, ofiles, ldflags, buildGccgoflags); err != nil {
+		return err
+	}
+
+	switch ldBuildmode {
+	case "c-archive":
+		if err := b.run(".", root.p.ImportPath, nil, "ar", "rc", realOut, out); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+func (tools gccgoToolchain) ldShared(b *builder, toplevelactions []*action, out string, allactions []*action) error {
+	args := []string{"-o", out, "-shared", "-nostdlib", "-zdefs", "-Wl,--whole-archive"}
+	for _, a := range toplevelactions {
+		args = append(args, a.target)
+	}
+	args = append(args, "-Wl,--no-whole-archive", "-shared", "-nostdlib", "-lgo", "-lgcc_s", "-lgcc", "-lc")
+	shlibs := []string{}
+	for _, a := range allactions {
+		if strings.HasSuffix(a.target, ".so") {
+			shlibs = append(shlibs, a.target)
+		}
 	}
-	return b.run(".", p.ImportPath, nil, gccgoName, "-o", out, ofiles, "-Wl,-(", ldflags, "-Wl,-)", buildGccgoflags)
+	for _, shlib := range shlibs {
+		args = append(
+			args,
+			"-L"+filepath.Dir(shlib),
+			"-Wl,-rpath="+filepath.Dir(shlib),
+			"-l"+strings.TrimSuffix(
+				strings.TrimPrefix(filepath.Base(shlib), "lib"),
+				".so"))
+	}
+	return b.run(".", out, nil, tools.linker(), args, buildGccgoflags)
 }
 
-func (gccgoToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
-	inc := filepath.Join(goroot, "pkg", fmt.Sprintf("%s_%s", goos, goarch))
+func (tools gccgoToolchain) cc(b *builder, p *Package, objdir, ofile, cfile string) error {
+	inc := filepath.Join(goroot, "pkg", "include")
 	cfile = mkAbs(p.Dir, cfile)
 	defs := []string{"-D", "GOOS_" + goos, "-D", "GOARCH_" + goarch}
 	defs = append(defs, b.gccArchArgs()...)
 	if pkgpath := gccgoCleanPkgpath(p); pkgpath != "" {
 		defs = append(defs, `-D`, `GOPKGPATH="`+pkgpath+`"`)
 	}
+	switch goarch {
+	case "386", "amd64":
+		defs = append(defs, "-fsplit-stack")
+	}
+	defs = tools.maybePIC(defs)
 	return b.run(p.Dir, p.ImportPath, nil, envList("CC", defaultCC), "-Wall", "-g",
 		"-I", objdir, "-I", inc, "-o", ofile, defs, "-c", cfile)
 }
 
+// maybePIC adds -fPIC to the list of arguments if needed.
+func (tools gccgoToolchain) maybePIC(args []string) []string {
+	switch buildBuildmode {
+	case "c-shared", "shared":
+		args = append(args, "-fPIC")
+	}
+	return args
+}
+
 func gccgoPkgpath(p *Package) string {
 	if p.build.IsCommand() && !p.forceLibrary {
 		return ""
@@ -2054,7 +2752,7 @@ func (b *builder) ccompile(p *Package, out string, flags []string, file string,
 // 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)
@@ -2113,7 +2811,7 @@ func (b *builder) ccompilerCmd(envvar, defcmd, objdir string) []string {
 
 	// On OS X, some of the compilers behave as if -fno-common
 	// is always set, and the Mach-O linker in 6l/8l assumes this.
-	// See http://golang.org/issue/3253.
+	// See https://golang.org/issue/3253.
 	if goos == "darwin" {
 		a = append(a, "-fno-common")
 	}
@@ -2123,12 +2821,12 @@ func (b *builder) ccompilerCmd(envvar, defcmd, objdir string) []string {
 
 // 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
@@ -2166,7 +2864,7 @@ var (
 	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...)
@@ -2183,7 +2881,7 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, gccfi
 	// 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")
@@ -2193,8 +2891,6 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, gccfi
 	cgoflags := []string{}
 	// TODO: make cgo not depend on $GOARCH?
 
-	objExt := archChar
-
 	if p.Standard && p.ImportPath == "runtime/cgo" {
 		cgoflags = append(cgoflags, "-import_runtime_cgo=false")
 	}
@@ -2213,23 +2909,38 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, gccfi
 	}
 
 	if _, ok := buildToolchain.(gccgoToolchain); ok {
+		switch goarch {
+		case "386", "amd64":
+			cgoCFLAGS = append(cgoCFLAGS, "-fsplit-stack")
+		}
 		cgoflags = append(cgoflags, "-gccgo")
 		if pkgpath := gccgoPkgpath(p); pkgpath != "" {
 			cgoflags = append(cgoflags, "-gccgopkgpath="+pkgpath)
 		}
-		objExt = "o"
 	}
-	if err := b.run(p.Dir, p.ImportPath, cgoenv, cgoExe, "-objdir", obj, cgoflags, "--", cgoCPPFLAGS, cgoexeCFLAGS, p.CgoFiles); err != nil {
+
+	switch buildBuildmode {
+	case "c-archive", "c-shared":
+		// Tell cgo that if there are any exported functions
+		// it should generate a header file that C code can
+		// #include.
+		cgoflags = append(cgoflags, "-exportheader="+obj+"_cgo_install.h")
+	}
+
+	if err := b.run(p.Dir, p.ImportPath, cgoenv, buildToolExec, cgoExe, "-objdir", obj, "-importpath", p.ImportPath, cgoflags, "--", cgoCPPFLAGS, cgoexeCFLAGS, cgofiles); err != nil {
 		return nil, nil, err
 	}
 	outGo = append(outGo, gofiles...)
 
 	// cc _cgo_defun.c
-	defunObj := obj + "_cgo_defun." + objExt
-	if err := buildToolchain.cc(b, p, obj, defunObj, defunC); err != nil {
-		return nil, nil, err
+	_, gccgo := buildToolchain.(gccgoToolchain)
+	if gccgo {
+		defunObj := obj + "_cgo_defun.o"
+		if err := buildToolchain.cc(b, p, obj, defunObj, defunC); err != nil {
+			return nil, nil, err
+		}
+		outObj = append(outObj, defunObj)
 	}
-	outObj = append(outObj, defunObj)
 
 	// gcc
 	var linkobj []string
@@ -2343,20 +3054,15 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, gccfi
 	}
 
 	// cgo -dynimport
-	importC := obj + "_cgo_import.c"
+	importGo := obj + "_cgo_import.go"
 	cgoflags = []string{}
 	if p.Standard && p.ImportPath == "runtime/cgo" {
 		cgoflags = append(cgoflags, "-dynlinker") // record path to dynamic linker
 	}
-	if err := b.run(p.Dir, p.ImportPath, nil, cgoExe, "-objdir", obj, "-dynimport", dynobj, "-dynout", importC, cgoflags); err != nil {
-		return nil, nil, err
-	}
-
-	// cc _cgo_import.ARCH
-	importObj := obj + "_cgo_import." + objExt
-	if err := buildToolchain.cc(b, p, obj, importObj, importC); err != nil {
+	if err := b.run(p.Dir, p.ImportPath, nil, buildToolExec, cgoExe, "-objdir", obj, "-dynpackage", p.Name, "-dynimport", dynobj, "-dynout", importGo, cgoflags); err != nil {
 		return nil, nil, err
 	}
+	outGo = append(outGo, importGo)
 
 	ofile := obj + "_all.o"
 	var gccObjs, nonGccObjs []string
@@ -2369,19 +3075,8 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, gccfi
 	}
 	ldflags := stringList(bareLDFLAGS, "-Wl,-r", "-nostdlib", staticLibs)
 
-	// Some systems, such as Ubuntu, always add --build-id to
-	// every link, but we don't want a build ID since we are
-	// producing an object file.  On some of those system a plain
-	// -r (not -Wl,-r) will turn off --build-id, but clang 3.0
-	// doesn't support a plain -r.  I don't know how to turn off
-	// --build-id when using clang other than passing a trailing
-	// --build-id=none.  So that is what we do, but only on
-	// systems likely to support it, which is to say, systems that
-	// normally use gold or the GNU linker.
-	switch goos {
-	case "android", "dragonfly", "linux", "netbsd":
-		ldflags = append(ldflags, "-Wl,--build-id=none")
-	}
+	// We are creating an object file, so we don't want a build ID.
+	ldflags = b.disableBuildID(ldflags)
 
 	if err := b.gccld(p, ofile, ldflags, gccObjs); err != nil {
 		return nil, nil, err
@@ -2389,8 +3084,8 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, gccfi
 
 	// NOTE(rsc): The importObj is a 5c/6c/8c object and on Windows
 	// must be processed before the gcc-generated objects.
-	// Put it first.  http://golang.org/issue/2601
-	outObj = stringList(importObj, nonGccObjs, ofile)
+	// Put it first.  https://golang.org/issue/2601
+	outObj = stringList(nonGccObjs, ofile)
 
 	return outGo, outObj, nil
 }
@@ -2398,77 +3093,41 @@ func (b *builder) cgo(p *Package, cgoExe, obj string, pcCFLAGS, pcLDFLAGS, gccfi
 // 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.
@@ -2482,20 +3141,51 @@ func (b *builder) swigDoVersionCheck() error {
 	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
 }
 
@@ -2526,14 +3216,14 @@ func (b *builder) swigIntSize(obj string) (intsize string, err error) {
 
 	p := goFilesPackage(srcs)
 
-	if _, _, e := buildToolchain.gc(b, p, "", obj, nil, srcs); e != nil {
+	if _, _, e := buildToolchain.gc(b, p, "", obj, false, nil, srcs); e != nil {
 		return "32", nil
 	}
 	return "64", nil
 }
 
 // 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 {
@@ -2548,7 +3238,6 @@ func (b *builder) swigOne(p *Package, file, obj string, pcCFLAGS []string, cxx b
 	}
 	base := file[:len(file)-n]
 	goFile := base + ".go"
-	cBase := base + "_gc."
 	gccBase := base + "_wrap."
 	gccExt := "c"
 	if cxx {
@@ -2560,6 +3249,7 @@ func (b *builder) swigOne(p *Package, file, obj string, pcCFLAGS []string, cxx b
 	// swig
 	args := []string{
 		"-go",
+		"-cgo",
 		"-intgosize", intgosize,
 		"-module", base,
 		"-o", obj + gccBase + gccExt,
@@ -2582,39 +3272,40 @@ func (b *builder) swigOne(p *Package, file, obj string, pcCFLAGS []string, cxx b
 		args = append(args, "-c++")
 	}
 
-	if out, err := b.runOut(p.Dir, p.ImportPath, nil, "swig", args, file); err != nil {
+	out, err := b.runOut(p.Dir, p.ImportPath, nil, "swig", args, file)
+	if 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
+			b.showOutput(p.Dir, p.ImportPath, b.processOutput(out)) // swig error
+			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
-		}
+	if len(out) > 0 {
+		b.showOutput(p.Dir, p.ImportPath, b.processOutput(out)) // swig warning
 	}
 
-	// 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, obj + gccBase + gccExt, nil
+}
 
-	return obj + goFile, cObj, gccObj, nil
+// disableBuildID adjusts a linker command line to avoid creating a
+// build ID when creating an object file rather than an executable or
+// shared library.  Some systems, such as Ubuntu, always add
+// --build-id to every link, but we don't want a build ID when we are
+// producing an object file.  On some of those system a plain -r (not
+// -Wl,-r) will turn off --build-id, but clang 3.0 doesn't support a
+// plain -r.  I don't know how to turn off --build-id when using clang
+// other than passing a trailing --build-id=none.  So that is what we
+// do, but only on systems likely to support it, which is to say,
+// systems that normally use gold or the GNU linker.
+func (b *builder) disableBuildID(ldflags []string) []string {
+	switch goos {
+	case "android", "dragonfly", "linux", "netbsd":
+		ldflags = append(ldflags, "-Wl,--build-id=none")
+	}
+	return ldflags
 }
 
 // An actionQueue is a priority queue of actions.
@@ -2650,7 +3341,6 @@ func raceInit() {
 	}
 	buildGcflags = append(buildGcflags, "-race")
 	buildLdflags = append(buildLdflags, "-race")
-	buildCcflags = append(buildCcflags, "-D", "RACE")
 	if buildContext.InstallSuffix != "" {
 		buildContext.InstallSuffix += "_"
 	}
diff --git a/src/cmd/go/doc.go b/src/cmd/go/doc.go
index 7191ee0..4a07dfe 100644
--- a/src/cmd/go/doc.go
+++ b/src/cmd/go/doc.go
@@ -1,1131 +1,103 @@
-// Copyright 2011 The Go Authors.  All rights reserved.
+// 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.
 
-// DO NOT EDIT THIS FILE. GENERATED BY mkdoc.sh.
-// Edit the documentation in other files and rerun mkdoc.sh to generate this one.
-
-/*
-Go is a tool for managing Go source code.
-
-Usage:
-
-	go command [arguments]
-
-The commands are:
-
-    build       compile packages and dependencies
-    clean       remove object files
-    env         print Go environment information
-    fix         run go tool fix on packages
-    fmt         run gofmt on package sources
-    generate    generate Go files by processing source
-    get         download and install packages and dependencies
-    install     compile and install packages and dependencies
-    list        list packages
-    run         compile and run Go program
-    test        test packages
-    tool        run specified go tool
-    version     print Go version
-    vet         run go tool vet on packages
-
-Use "go help [command]" for more information about a command.
-
-Additional help topics:
-
-    c           calling between Go and C
-    filetype    file types
-    gopath      GOPATH environment variable
-    importpath  import path syntax
-    packages    description of package lists
-    testflag    description of testing flags
-    testfunc    description of testing functions
-
-Use "go help [topic]" for more information about that topic.
-
-
-Compile packages and dependencies
-
-Usage:
-
-	go build [-o output] [-i] [build flags] [packages]
-
-Build compiles the packages named by the import paths,
-along with their dependencies, but it does not install the results.
-
-If the arguments are a list of .go files, build treats them as a list
-of source files specifying a single package.
-
-When the command line specifies a single main package,
-build writes the resulting executable to output.
-Otherwise build compiles the packages but discards the results,
-serving only as a check that the packages can be built.
-
-The -o flag specifies the output file name. If not specified, the
-output file name depends on the arguments and derives from the name
-of the package, such as p.a for package p, unless p is 'main'. If
-the package is main and file names are provided, the file name
-derives from the first file name mentioned, such as f1 for 'go build
-f1.go f2.go'; with no files provided ('go build'), the output file
-name is the base name of the containing directory.
-
-The -i flag installs the packages that are dependencies of the target.
-
-The build flags are shared by the build, clean, get, install, list, run,
-and test commands:
-
-	-a
-		force rebuilding of packages that are already up-to-date.
-		In Go releases, does not apply to the standard library.
-	-n
-		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.
-	-race
-		enable data race detection.
-		Supported only on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64.
-	-v
-		print the names of packages as they are compiled.
-	-work
-		print the name of the temporary work directory and
-		do not delete it when exiting.
-	-x
-		print the commands.
-
-	-ccflags 'arg list'
-		arguments to pass on each 5c, 6c, or 8c compiler invocation.
-	-compiler name
-		name of compiler to use, as in runtime.Compiler (gccgo or gc).
-	-gccgoflags 'arg list'
-		arguments to pass on each gccgo compiler/linker invocation.
-	-gcflags 'arg list'
-		arguments to pass on each 5g, 6g, or 8g compiler invocation.
-	-installsuffix suffix
-		a suffix to use in the name of the package installation directory,
-		in order to keep output separate from default builds.
-		If using the -race flag, the install suffix is automatically set to race
-		or, if set explicitly, has _race appended to it.
-	-ldflags 'flag list'
-		arguments to pass on each 5l, 6l, or 8l linker 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
-		build constraints in the documentation for the go/build package.
-
-The list flags accept a space-separated list of strings. To embed spaces
-in an element in the list, surround it with either single or double quotes.
-
-For more about specifying packages, see 'go help packages'.
-For more about where packages and binaries are installed,
-run 'go help gopath'.  For more about calling between Go and C/C++,
-run 'go help c'.
-
-See also: go install, go get, go clean.
-
-
-Remove object files
-
-Usage:
-
-	go clean [-i] [-r] [-n] [-x] [build flags] [packages]
-
-Clean removes object files from package source directories.
-The go command builds most objects in a temporary directory,
-so go clean is mainly concerned with object files left by other
-tools or by manual invocations of go build.
-
-Specifically, clean removes the following files from each of the
-source directories corresponding to the import paths:
-
-	_obj/            old object directory, left from Makefiles
-	_test/           old test directory, left from Makefiles
-	_testmain.go     old gotest file, left from Makefiles
-	test.out         old test log, left from Makefiles
-	build.out        old test log, left from Makefiles
-	*.[568ao]        object files, left from Makefiles
-
-	DIR(.exe)        from go build
-	DIR.test(.exe)   from go test -c
-	MAINFILE(.exe)   from go build MAINFILE.go
-	*.so             from SWIG
-
-In the list, DIR represents the final path element of the
-directory, and MAINFILE is the base name of any Go source
-file in the directory that is not included when building
-the package.
-
-The -i flag causes clean to remove the corresponding installed
-archive or binary (what 'go install' would create).
-
-The -n flag causes clean to print the remove commands it would execute,
-but not run them.
-
-The -r flag causes clean to be applied recursively to all the
-dependencies of the packages named by the import paths.
-
-The -x flag causes clean to print remove commands as it executes them.
-
-For more about build flags, see 'go help build'.
-
-For more about specifying packages, see 'go help packages'.
-
-
-Print Go environment information
-
-Usage:
-
-	go env [var ...]
-
-Env prints Go environment information.
-
-By default env prints information as a shell script
-(on Windows, a batch file).  If one or more variable
-names is given as arguments,  env prints the value of
-each named variable on its own line.
-
-
-Run go tool fix on packages
-
-Usage:
-
-	go fix [packages]
-
-Fix runs the Go fix command on the packages named by the import paths.
-
-For more about fix, see 'godoc fix'.
-For more about specifying packages, see 'go help packages'.
-
-To run fix with specific options, run 'go tool fix'.
-
-See also: go fmt, go vet.
-
-
-Run gofmt on package sources
-
-Usage:
-
-	go fmt [-n] [-x] [packages]
-
-Fmt runs the command 'gofmt -l -w' on the packages named
-by the import paths.  It prints the names of the files that are modified.
-
-For more about gofmt, see 'godoc gofmt'.
-For more about specifying packages, see 'go help packages'.
-
-The -n flag prints commands that would be executed.
-The -x flag prints commands as they are executed.
-
-To run gofmt with specific options, run gofmt itself.
-
-See also: go fix, go vet.
-
-
-Generate Go files by processing source
-
-Usage:
-
-	go generate [-run regexp] [file.go... | packages]
-
-Generate runs commands described by directives within existing
-files. Those commands can run any process but the intent is to
-create or update Go source files, for instance by running yacc.
-
-Go generate is never run automatically by go build, go get, go test,
-and so on. It must be run explicitly.
-
-Go generate scans the file for directives, which are lines of
-the form,
-
-	//go:generate command argument...
-
-(note: no leading spaces and no space in "//go") where command
-is the generator to be run, corresponding to an executable file
-that can be run locally. It must either be in the shell path
-(gofmt), a fully qualified path (/usr/you/bin/mytool), or a
-command alias, described below.
-
-Note that go generate does not parse the file, so lines that look
-like directives in comments or multiline strings will be treated
-as directives.
-
-The arguments to the directive are space-separated tokens or
-double-quoted strings passed to the generator as individual
-arguments when it is run.
-
-Quoted strings use Go syntax and are evaluated before execution; a
-quoted string appears as a single argument to the generator.
-
-Go generate sets several variables when it runs the generator:
-
-	$GOARCH
-		The execution architecture (arm, amd64, etc.)
-	$GOOS
-		The execution operating system (linux, windows, etc.)
-	$GOFILE
-		The base name of the file.
-	$GOPACKAGE
-		The name of the package of the file containing the directive.
-
-Other than variable substitution and quoted-string evaluation, no
-special processing such as "globbing" is performed on the command
-line.
-
-As a last step before running the command, any invocations of any
-environment variables with alphanumeric names, such as $GOFILE or
-$HOME, are expanded throughout the command line. The syntax for
-variable expansion is $NAME on all operating systems.  Due to the
-order of evaluation, variables are expanded even inside quoted
-strings. If the variable NAME is not set, $NAME expands to the
-empty string.
-
-A directive of the form,
-
-	//go:generate -command xxx args...
-
-specifies, for the remainder of this source file only, that the
-string xxx represents the command identified by the arguments. This
-can be used to create aliases or to handle multiword generators.
-For example,
-
-	//go:generate -command yacc go tool yacc
-
-specifies that the command "yacc" represents the generator
-"go tool yacc".
-
-Generate processes packages in the order given on the command line,
-one at a time. If the command line lists .go files, they are treated
-as a single package. Within a package, generate processes the
-source files in a package in file name order, one at a time. Within
-a source file, generate runs generators in the order they appear
-in the file, one at a time.
-
-If any generator returns an error exit status, "go generate" skips
-all further processing for that package.
-
-The generator is run in the package's source directory.
-
-Go generate accepts one specific flag:
-
-	-run=""
-		TODO: This flag is unimplemented.
-		if non-empty, specifies a regular expression to
-		select directives whose command matches the expression.
-
-It also accepts the standard build flags -v, -n, and -x.
-The -v flag prints the names of packages and files as they are
-processed.
-The -n flag prints commands that would be executed.
-The -x flag prints commands as they are executed.
-
-For more about specifying packages, see 'go help packages'.
-
-
-Download and install packages and dependencies
-
-Usage:
-
-	go get [-d] [-f] [-fix] [-t] [-u] [build flags] [packages]
-
-Get downloads and installs the packages named by the import paths,
-along with their dependencies.
-
-The -d flag instructs get to stop after downloading the packages; that is,
-it instructs get not to install the packages.
-
-The -f flag, valid only when -u is set, forces get -u not to verify that
-each package has been checked out from the source control repository
-implied by its import path. This can be useful if the source is a local fork
-of the original.
-
-The -fix flag instructs get to run the fix tool on the downloaded packages
-before resolving dependencies or building the code.
-
-The -t flag instructs get to also download the packages required to build
-the tests for the specified packages.
-
-The -u flag instructs get to use the network to update the named packages
-and their dependencies.  By default, get uses the network to check out
-missing packages but does not use it to look for updates to existing packages.
-
-Get also accepts build flags to control the installation. See 'go help build'.
-
-When checking out or updating a package, get looks for a branch or tag
-that matches the locally installed version of Go. The most important
-rule is that if the local installation is running version "go1", get
-searches for a branch or tag named "go1". If no such version exists it
-retrieves the most recent version of the package.
-
-For more about specifying packages, see 'go help packages'.
-
-For more about how 'go get' finds source code to
-download, see 'go help importpath'.
-
-See also: go build, go install, go clean.
-
-
-Compile and install packages and dependencies
-
-Usage:
-
-	go install [build flags] [packages]
-
-Install compiles and installs the packages named by the import paths,
-along with their dependencies.
-
-For more about the build flags, see 'go help build'.
-For more about specifying packages, see 'go help packages'.
-
-See also: go build, go get, go clean.
-
-
-List packages
-
-Usage:
-
-	go list [-e] [-f format] [-json] [build flags] [packages]
-
-List lists the packages named by the import paths, one per line.
-
-The default output shows the package import path:
-
-    code.google.com/p/google-api-go-client/books/v1
-    code.google.com/p/goauth2/oauth
-    code.google.com/p/sqlite
-
-The -f flag specifies an alternate format for the list, using the
-syntax of package template.  The default output is equivalent to -f
-'{{.ImportPath}}'. The struct being passed to the template is:
-
-    type Package struct {
-        Dir           string // directory containing package sources
-        ImportPath    string // import path of package in dir
-        ImportComment string // path in import comment on package statement
-        Name          string // package name
-        Doc           string // package documentation string
-        Target        string // install path
-        Goroot        bool   // is this package in the Go root?
-        Standard      bool   // is this package part of the standard Go library?
-        Stale         bool   // would 'go install' do anything for this package?
-        Root          string // Go root or Go path dir containing this package
-
-        // Source files
-        GoFiles        []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
-        CgoFiles       []string // .go sources files that import "C"
-        IgnoredGoFiles []string // .go sources ignored due to build constraints
-        CFiles         []string // .c source files
-        CXXFiles       []string // .cc, .cxx and .cpp source files
-        MFiles         []string // .m source files
-        HFiles         []string // .h, .hh, .hpp and .hxx source files
-        SFiles         []string // .s source files
-        SwigFiles      []string // .swig files
-        SwigCXXFiles   []string // .swigcxx files
-        SysoFiles      []string // .syso object files to add to archive
-
-        // Cgo directives
-        CgoCFLAGS    []string // cgo: flags for C compiler
-        CgoCPPFLAGS  []string // cgo: flags for C preprocessor
-        CgoCXXFLAGS  []string // cgo: flags for C++ compiler
-        CgoLDFLAGS   []string // cgo: flags for linker
-        CgoPkgConfig []string // cgo: pkg-config names
-
-        // Dependency information
-        Imports []string // import paths used by this package
-        Deps    []string // all (recursively) imported dependencies
-
-        // Error information
-        Incomplete bool            // this package or a dependency has an error
-        Error      *PackageError   // error loading package
-        DepsErrors []*PackageError // errors loading dependencies
-
-        TestGoFiles  []string // _test.go files in package
-        TestImports  []string // imports from TestGoFiles
-        XTestGoFiles []string // _test.go files outside package
-        XTestImports []string // imports from XTestGoFiles
-    }
-
-The template function "join" calls strings.Join.
-
-The template function "context" returns the build context, defined as:
-
-	type Context struct {
-		GOARCH        string   // target architecture
-		GOOS          string   // target operating system
-		GOROOT        string   // Go root
-		GOPATH        string   // Go path
-		CgoEnabled    bool     // whether cgo can be used
-		UseAllFiles   bool     // use files regardless of +build lines, file names
-		Compiler      string   // compiler to assume when computing target paths
-		BuildTags     []string // build constraints to match in +build lines
-		ReleaseTags   []string // releases the current release is compatible with
-		InstallSuffix string   // suffix to use in the name of the install dir
-	}
-
-For more information about the meaning of these fields see the documentation
-for the go/build package's Context type.
-
-The -json flag causes the package data to be printed in JSON format
-instead of using the template format.
-
-The -e flag changes the handling of erroneous packages, those that
-cannot be found or are malformed.  By default, the list command
-prints an error to standard error for each erroneous package and
-omits the packages from consideration during the usual printing.
-With the -e flag, the list command never prints errors to standard
-error and instead processes the erroneous packages with the usual
-printing.  Erroneous packages will have a non-empty ImportPath and
-a non-nil Error field; other information may or may not be missing
-(zeroed).
-
-For more about build flags, see 'go help build'.
-
-For more about specifying packages, see 'go help packages'.
-
-
-Compile and run Go program
-
-Usage:
-
-	go run [build flags] [-exec xprog] gofiles... [arguments...]
-
-Run compiles and runs the main package comprising the named Go source files.
-A Go source file is defined to be a file ending in a literal ".go" suffix.
-
-By default, 'go run' runs the compiled binary directly: 'a.out arguments...'.
-If the -exec flag is given, 'go run' invokes the binary using xprog: 'xprog a.out arguments...'.
-If the -exec flag is not given, GOOS or GOARCH is different from the system
-default, and a program named go_$GOOS_$GOARCH_exec can be found
-on the current search path, 'go run' invokes the binary using that program,
-for example 'go_nacl_386_exec a.out arguments...'. This allows execution of
-cross-compiled programs when a simulator or other execution method is
-available.
-
-For more about build flags, see 'go help build'.
-
-See also: go build.
-
-
-Test packages
-
-Usage:
-
-	go test [-c] [-i] [build and test flags] [packages] [flags for test binary]
-
-'Go test' automates testing the packages named by the import paths.
-It prints a summary of the test results in the format:
-
-	ok   archive/tar   0.011s
-	FAIL archive/zip   0.022s
-	ok   compress/gzip 0.033s
-	...
-
-followed by detailed output for each failed package.
-
-'Go test' recompiles each package along with any files with names matching
-the file pattern "*_test.go".
-Files whose names begin with "_" (including "_test.go") or "." are ignored.
-These additional files can contain test functions, benchmark functions, and
-example functions.  See 'go help testfunc' for more.
-Each listed package causes the execution of a separate test binary.
-
-Test files that declare a package with the suffix "_test" will be compiled as a
-separate package, and then linked and run with the main test binary.
-
-By default, go test needs no arguments.  It compiles and tests the package
-with source in the current directory, including tests, and runs the tests.
-
-The package is built in a temporary directory so it does not interfere with the
-non-test installation.
-
-In addition to the build flags, the flags handled by 'go test' itself are:
+package main
 
+var cmdDoc = &Command{
+	Run:         runDoc,
+	UsageLine:   "doc [-u] [-c] [package|[package.]symbol[.method]]",
+	CustomFlags: true,
+	Short:       "show documentation for package or symbol",
+	Long: `
+Doc prints the documentation comments associated with the item identified by its
+arguments (a package, const, func, type, var, or method) followed by a one-line
+summary of each of the first-level items "under" that item (package-level
+declarations for a package, methods for a type, etc.).
+
+Doc accepts zero, one, or two arguments.
+
+Given no arguments, that is, when run as
+
+	go doc
+
+it prints the package documentation for the package in the current directory.
+If the package is a command (package main), the exported symbols of the package
+are elided from the presentation unless the -cmd flag is provided.
+
+When run with one argument, the argument is treated as a Go-syntax-like
+representation of the item to be documented. What the argument selects depends
+on what is installed in GOROOT and GOPATH, as well as the form of the argument,
+which is schematically one of these:
+
+	go doc <pkg>
+	go doc <sym>[.<method>]
+	go doc [<pkg>].<sym>[.<method>]
+
+The first item in this list matched by the argument is the one whose
+documentation is printed. (See the examples below.) For packages, the order of
+scanning is determined lexically, but the GOROOT tree is always scanned before
+GOPATH.
+
+If there is no package specified or matched, the package in the current
+directory is selected, so "go doc Foo" shows the documentation for symbol Foo in
+the current package.
+
+The package path must be either a qualified path or a proper suffix of a
+path. The go tool's usual package mechanism does not apply: package path
+elements like . and ... are not implemented by go doc.
+
+When run with two arguments, the first must be a full package path (not just a
+suffix), and the second is a symbol or symbol and method; this is similar to the
+syntax accepted by godoc:
+
+	go doc <pkg> <sym>[.<method>]
+
+In all forms, when matching symbols, lower-case letters in the argument match
+either case but upper-case letters match exactly. This means that there may be
+multiple matches of a lower-case argument in a package if different symbols have
+different cases. If this occurs, documentation for all matches is printed.
+
+Examples:
+	go doc
+		Show documentation for current package.
+	go doc Foo
+		Show documentation for Foo in the current package.
+		(Foo starts with a capital letter so it cannot match
+		a package path.)
+	go doc encoding/json
+		Show documentation for the encoding/json package.
+	go doc json
+		Shorthand for encoding/json.
+	go doc json.Number (or go doc json.number)
+		Show documentation and method summary for json.Number.
+	go doc json.Number.Int64 (or go doc json.number.int64)
+		Show documentation for json.Number's Int64 method.
+	go doc cmd/doc
+		Show package docs for the doc command.
+	go doc -cmd cmd/doc
+		Show package docs and exported symbols within the doc command.
+	go doc template.new
+		Show documentation for html/template's New function.
+		(html/template is lexically before text/template)
+	go doc text/template.new # One argument
+		Show documentation for text/template's New function.
+	go doc text/template new # Two arguments
+		Show documentation for text/template's New function.
+
+Flags:
 	-c
-		Compile the test binary to pkg.test but do not run it
-		(where pkg is the last element of the package's import path).
-		The file name can be changed with the -o flag.
-
-	-exec xprog
-	    Run the test binary using xprog. The behavior is the same as
-	    in 'go run'. See 'go help run' for details.
-
-	-i
-	    Install packages that are dependencies of the test.
-	    Do not run the test.
-
-	-o file
-		Compile the test binary to the named file.
-		The test still runs (unless -c or -i is specified).
-
-
-The test binary also accepts flags that control execution of the test; these
-flags are also accessible by 'go test'.  See 'go help testflag' for details.
-
-If the test binary needs any other flags, they should be presented after the
-package names. The go tool treats as a flag the first argument that begins with
-a minus sign that it does not recognize itself; that argument and all subsequent
-arguments are passed as arguments to the test binary.
-
-For more about build flags, see 'go help build'.
-For more about specifying packages, see 'go help packages'.
-
-See also: go build, go vet.
-
-
-Run specified go tool
-
-Usage:
-
-	go tool [-n] command [args...]
-
-Tool runs the go tool command identified by the arguments.
-With no arguments it prints the list of known tools.
-
-The -n flag causes tool to print the command that would be
-executed but not execute it.
-
-For more about each tool command, see 'go tool command -h'.
-
-
-Print Go version
-
-Usage:
-
-	go version
-
-Version prints the Go version, as reported by runtime.Version.
-
-
-Run go tool vet on packages
-
-Usage:
-
-	go vet [-n] [-x] [packages]
-
-Vet runs the Go vet command on the packages named by the import paths.
-
-For more about vet, see 'godoc golang.org/x/tools/cmd/vet'.
-For more about specifying packages, see 'go help packages'.
-
-To run the vet tool with specific options, run 'go tool vet'.
-
-The -n flag prints commands that would be executed.
-The -x flag prints commands as they are executed.
-
-See also: go fmt, go fix.
-
-
-Calling between Go and C
-
-There are two different ways to call between Go and C/C++ code.
-
-The first is the cgo tool, which is part of the Go distribution.  For
-information on how to use it see the cgo documentation (godoc cmd/cgo).
-
-The second is the SWIG program, which is a general tool for
-interfacing between languages.  For information on SWIG see
-http://swig.org/.  When running go build, any file with a .swig
-extension will be passed to SWIG.  Any file with a .swigcxx extension
-will be passed to SWIG with the -c++ option.
-
-When either cgo or SWIG is used, go build will pass any .c, .m, .s,
-or .S files to the C compiler, and any .cc, .cpp, .cxx files to the C++
-compiler.  The CC or CXX environment variables may be set to determine
-the C or C++ compiler, respectively, to use.
-
-
-File types
-
-The go command examines the contents of a restricted set of files
-in each directory. It identifies which files to examine based on
-the extension of the file name. These extensions are:
-
-	.go
-		Go source files.
-	.c, .h
-		C source files.
-		If the package uses cgo, these will be compiled with the
-		OS-native compiler (typically gcc); otherwise they will be
-		compiled with the Go-specific support compiler,
-		5c, 6c, or 8c, etc. as appropriate.
-	.cc, .cpp, .cxx, .hh, .hpp, .hxx
-		C++ source files. Only useful with cgo or SWIG, and always
-		compiled with the OS-native compiler.
-	.m
-		Objective-C source files. Only useful with cgo, and always
-		compiled with the OS-native compiler.
-	.s, .S
-		Assembler source files.
-		If the package uses cgo, these will be assembled with the
-		OS-native assembler (typically gcc (sic)); otherwise they
-		will be assembled with the Go-specific support assembler,
-		5a, 6a, or 8a, etc., as appropriate.
-	.swig, .swigcxx
-		SWIG definition files.
-	.syso
-		System object files.
-
-Files of each of these types except .syso may contain build
-constraints, but the go command stops scanning for build constraints
-at the first item in the file that is not a blank line or //-style
-line comment.
-
-
-GOPATH environment variable
-
-The Go path is used to resolve import statements.
-It is implemented by and documented in the go/build package.
-
-The GOPATH environment variable lists places to look for Go code.
-On Unix, the value is a colon-separated string.
-On Windows, the value is a semicolon-separated string.
-On Plan 9, the value is a list.
-
-GOPATH must be set to get, build and install packages outside the
-standard Go tree.
-
-Each directory listed in GOPATH must have a prescribed structure:
-
-The src/ directory holds source code.  The path below 'src'
-determines the import path or executable name.
-
-The pkg/ directory holds installed package objects.
-As in the Go tree, each target operating system and
-architecture pair has its own subdirectory of pkg
-(pkg/GOOS_GOARCH).
-
-If DIR is a directory listed in the GOPATH, a package with
-source in DIR/src/foo/bar can be imported as "foo/bar" and
-has its compiled form installed to "DIR/pkg/GOOS_GOARCH/foo/bar.a".
-
-The bin/ directory holds compiled commands.
-Each command is named for its source directory, but only
-the final element, not the entire path.  That is, the
-command with source in DIR/src/foo/quux is installed into
-DIR/bin/quux, not DIR/bin/foo/quux.  The foo/ is stripped
-so that you can add DIR/bin to your PATH to get at the
-installed commands.  If the GOBIN environment variable is
-set, commands are installed to the directory it names instead
-of DIR/bin.
-
-Here's an example directory layout:
-
-    GOPATH=/home/user/gocode
-
-    /home/user/gocode/
-        src/
-            foo/
-                bar/               (go code in package bar)
-                    x.go
-                quux/              (go code in package main)
-                    y.go
-        bin/
-            quux                   (installed command)
-        pkg/
-            linux_amd64/
-                foo/
-                    bar.a          (installed package object)
-
-Go searches each directory listed in GOPATH to find source code,
-but new packages are always downloaded into the first directory
-in the list.
-
-
-Import path syntax
-
-An import path (see 'go help packages') denotes a package
-stored in the local file system.  In general, an import path denotes
-either a standard package (such as "unicode/utf8") or a package
-found in one of the work spaces (see 'go help gopath').
-
-Relative import paths
-
-An import path beginning with ./ or ../ is called a relative path.
-The toolchain supports relative import paths as a shortcut in two ways.
-
-First, a relative path can be used as a shorthand on the command line.
-If you are working in the directory containing the code imported as
-"unicode" and want to run the tests for "unicode/utf8", you can type
-"go test ./utf8" instead of needing to specify the full path.
-Similarly, in the reverse situation, "go test .." will test "unicode" from
-the "unicode/utf8" directory. Relative patterns are also allowed, like
-"go test ./..." to test all subdirectories. See 'go help packages' for details
-on the pattern syntax.
-
-Second, if you are compiling a Go program not in a work space,
-you can use a relative path in an import statement in that program
-to refer to nearby code also not in a work space.
-This makes it easy to experiment with small multipackage programs
-outside of the usual work spaces, but such programs cannot be
-installed with "go install" (there is no work space in which to install them),
-so they are rebuilt from scratch each time they are built.
-To avoid ambiguity, Go programs cannot use relative import paths
-within a work space.
-
-Remote import paths
-
-Certain import paths also
-describe how to obtain the source code for the package using
-a revision control system.
-
-A few common code hosting sites have special syntax:
-
-	Bitbucket (Git, Mercurial)
-
-		import "bitbucket.org/user/project"
-		import "bitbucket.org/user/project/sub/directory"
-
-	GitHub (Git)
-
-		import "github.com/user/project"
-		import "github.com/user/project/sub/directory"
-
-	Google Code Project Hosting (Git, Mercurial, Subversion)
-
-		import "code.google.com/p/project"
-		import "code.google.com/p/project/sub/directory"
-
-		import "code.google.com/p/project.subrepository"
-		import "code.google.com/p/project.subrepository/sub/directory"
-
-	Launchpad (Bazaar)
-
-		import "launchpad.net/project"
-		import "launchpad.net/project/series"
-		import "launchpad.net/project/series/sub/directory"
-
-		import "launchpad.net/~user/project/branch"
-		import "launchpad.net/~user/project/branch/sub/directory"
-
-	IBM DevOps Services (Git)
-
-		import "hub.jazz.net/git/user/project"
-		import "hub.jazz.net/git/user/project/sub/directory"
-
-For code hosted on other servers, import paths may either be qualified
-with the version control type, or the go tool can dynamically fetch
-the import path over https/http and discover where the code resides
-from a <meta> tag in the HTML.
-
-To declare the code location, an import path of the form
-
-	repository.vcs/path
-
-specifies the given repository, with or without the .vcs suffix,
-using the named version control system, and then the path inside
-that repository.  The supported version control systems are:
-
-	Bazaar      .bzr
-	Git         .git
-	Mercurial   .hg
-	Subversion  .svn
-
-For example,
-
-	import "example.org/user/foo.hg"
-
-denotes the root directory of the Mercurial repository at
-example.org/user/foo or foo.hg, and
-
-	import "example.org/repo.git/foo/bar"
-
-denotes the foo/bar directory of the Git repository at
-example.org/repo or repo.git.
-
-When a version control system supports multiple protocols,
-each is tried in turn when downloading.  For example, a Git
-download tries git://, then https://, then http://.
-
-If the import path is not a known code hosting site and also lacks a
-version control qualifier, the go tool attempts to fetch the import
-over https/http and looks for a <meta> tag in the document's HTML
-<head>.
-
-The meta tag has the form:
-
-	<meta name="go-import" content="import-prefix vcs repo-root">
-
-The import-prefix is the import path corresponding to the repository
-root. It must be a prefix or an exact match of the package being
-fetched with "go get". If it's not an exact match, another http
-request is made at the prefix to verify the <meta> tags match.
-
-The vcs is one of "git", "hg", "svn", etc,
-
-The repo-root is the root of the version control system
-containing a scheme and not containing a .vcs qualifier.
-
-For example,
-
-	import "example.org/pkg/foo"
-
-will result in the following request(s):
-
-	https://example.org/pkg/foo?go-get=1 (preferred)
-	http://example.org/pkg/foo?go-get=1  (fallback)
-
-If that page contains the meta tag
-
-	<meta name="go-import" content="example.org git https://code.org/r/p/exproj">
-
-the go tool will verify that https://example.org/?go-get=1 contains the
-same meta tag and then git clone https://code.org/r/p/exproj into
-GOPATH/src/example.org.
-
-New downloaded packages are written to the first directory
-listed in the GOPATH environment variable (see 'go help gopath').
-
-The go command attempts to download the version of the
-package appropriate for the Go release being used.
-Run 'go help get' for more.
-
-Import path checking
-
-When the custom import path feature described above redirects to a
-known code hosting site, each of the resulting packages has two possible
-import paths, using the custom domain or the known hosting site.
-
-A package statement is said to have an "import comment" if it is immediately
-followed (before the next newline) by a comment of one of these two forms:
-
-	package math // import "path"
-	package math /* import "path" * /
-
-The go command will refuse to install a package with an import comment
-unless it is being referred to by that import path. In this way, import comments
-let package authors make sure the custom import path is used and not a
-direct path to the underlying code hosting site.
-
-See https://golang.org/s/go14customimport for details.
-
-
-Description of package lists
-
-Many commands apply to a set of packages:
-
-	go action [packages]
-
-Usually, [packages] is a list of import paths.
-
-An import path that is a rooted path or that begins with
-a . or .. element is interpreted as a file system path and
-denotes the package in that directory.
-
-Otherwise, the import path P denotes the package found in
-the directory DIR/src/P for some DIR listed in the GOPATH
-environment variable (see 'go help gopath').
-
-If no import paths are given, the action applies to the
-package in the current directory.
-
-There are three reserved names for paths that should not be used
-for packages to be built with the go tool:
-
-- "main" denotes the top-level package in a stand-alone executable.
-
-- "all" expands to all package directories found in all the GOPATH
-trees. For example, 'go list all' lists all the packages on the local
-system.
-
-- "std" is like all but expands to just the packages in the standard
-Go library.
-
-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
-directories found in the GOPATH trees with names matching the
-patterns.  As a special case, x/... matches x as well as x's subdirectories.
-For example, net/... expands to net and packages in its subdirectories.
-
-An import path can also name a package to be downloaded from
-a remote repository.  Run 'go help importpath' for details.
-
-Every package in a program must have a unique import path.
-By convention, this is arranged by starting each path with a
-unique prefix that belongs to you.  For example, paths used
-internally at Google all begin with 'google', and paths
-denoting remote repositories begin with the path to the code,
-such as 'code.google.com/p/project'.
-
-As a special case, if the package list is a list of .go files from a
-single directory, the command is applied to a single synthesized
-package made up of exactly those files, ignoring any build constraints
-in those files and ignoring any other files in the directory.
-
-Directory and file names that begin with "." or "_" are ignored
-by the go tool, as are directories named "testdata".
-
-
-Description of testing flags
-
-The 'go test' command takes both flags that apply to 'go test' itself
-and flags that apply to the resulting test binary.
-
-Several of the flags control profiling and write an execution profile
-suitable for "go tool pprof"; run "go tool pprof help" for more
-information.  The --alloc_space, --alloc_objects, and --show_bytes
-options of pprof control how the information is presented.
-
-The following flags are recognized by the 'go test' command and
-control the execution of any test:
-
-	-bench regexp
-	    Run benchmarks matching the regular expression.
-	    By default, no benchmarks run. To run all benchmarks,
-	    use '-bench .' or '-bench=.'.
-
-	-benchmem
-	    Print memory allocation statistics for benchmarks.
-
-	-benchtime t
-	    Run enough iterations of each benchmark to take t, specified
-	    as a time.Duration (for example, -benchtime 1h30s).
-	    The default is 1 second (1s).
-
-	-blockprofile block.out
-	    Write a goroutine blocking profile to the specified file
-	    when all tests are complete.
-	    Writes test binary as -c would.
-
-	-blockprofilerate n
-	    Control the detail provided in goroutine blocking profiles by
-	    calling runtime.SetBlockProfileRate with n.
-	    See 'godoc runtime SetBlockProfileRate'.
-	    The profiler aims to sample, on average, one blocking event every
-	    n nanoseconds the program spends blocked.  By default,
-	    if -test.blockprofile is set without this flag, all blocking events
-	    are recorded, equivalent to -test.blockprofilerate=1.
-
-	-cover
-	    Enable coverage analysis.
-
-	-covermode set,count,atomic
-	    Set the mode for coverage analysis for the package[s]
-	    being tested. The default is "set" unless -race is enabled,
-	    in which case it is "atomic".
-	    The values:
-		set: bool: does this statement run?
-		count: int: how many times does this statement run?
-		atomic: int: count, but correct in multithreaded tests;
-			significantly more expensive.
-	    Sets -cover.
-
-	-coverpkg pkg1,pkg2,pkg3
-	    Apply coverage analysis in each test to the given list of packages.
-	    The default is for each test to analyze only the package being tested.
-	    Packages are specified as import paths.
-	    Sets -cover.
-
-	-coverprofile cover.out
-	    Write a coverage profile to the file after all tests have passed.
-	    Sets -cover.
-
-	-cpu 1,2,4
-	    Specify a list of GOMAXPROCS values for which the tests or
-	    benchmarks should be executed.  The default is the current value
-	    of GOMAXPROCS.
-
-	-cpuprofile cpu.out
-	    Write a CPU profile to the specified file before exiting.
-	    Writes test binary as -c would.
-
-	-memprofile mem.out
-	    Write a memory profile to the file after all tests have passed.
-	    Writes test binary as -c would.
-
-	-memprofilerate n
-	    Enable more precise (and expensive) memory profiles by setting
-	    runtime.MemProfileRate.  See 'godoc runtime MemProfileRate'.
-	    To profile all memory allocations, use -test.memprofilerate=1
-	    and pass --alloc_space flag to the pprof tool.
-
-	-outputdir directory
-	    Place output files from profiling in the specified directory,
-	    by default the directory in which "go test" is running.
-
-	-parallel n
-	    Allow parallel execution of test functions that call t.Parallel.
-	    The value of this flag is the maximum number of tests to run
-	    simultaneously; by default, it is set to the value of GOMAXPROCS.
-
-	-run regexp
-	    Run only those tests and examples matching the regular
-	    expression.
-
-	-short
-	    Tell long-running tests to shorten their run time.
-	    It is off by default but set during all.bash so that installing
-	    the Go tree can run a sanity check but not spend time running
-	    exhaustive tests.
-
-	-timeout t
-	    If a test runs longer than t, panic.
-
-	-v
-	    Verbose output: log all tests as they are run. Also print all
-	    text from Log and Logf calls even if the test succeeds.
-
-The test binary, called pkg.test where pkg is the name of the
-directory containing the package sources, can be invoked directly
-after building it with 'go test -c'. When invoking the test binary
-directly, each of the standard flag names must be prefixed with 'test.',
-as in -test.run=TestMyFunc or -test.v.
-
-When running 'go test', flags not listed above are passed through
-unaltered. For instance, the command
-
-	go test -x -v -cpuprofile=prof.out -dir=testdata -update
-
-will compile the test binary and then run it as
-
-	pkg.test -test.v -test.cpuprofile=prof.out -dir=testdata -update
-
-The test flags that generate profiles (other than for coverage) also
-leave the test binary in pkg.test for use when analyzing the profiles.
-
-Flags not recognized by 'go test' must be placed after any specified packages.
-
-
-Description of testing functions
-
-The 'go test' command expects to find test, benchmark, and example functions
-in the "*_test.go" files corresponding to the package under test.
-
-A test function is one named TestXXX (where XXX is any alphanumeric string
-not starting with a lower case letter) and should have the signature,
-
-	func TestXXX(t *testing.T) { ... }
-
-A benchmark function is one named BenchmarkXXX and should have the signature,
-
-	func BenchmarkXXX(b *testing.B) { ... }
-
-An example function is similar to a test function but, instead of using
-*testing.T to report success or failure, prints output to os.Stdout.
-That output is compared against the function's "Output:" comment, which
-must be the last comment in the function body (see example below). An
-example with no such comment, or with no text after "Output:" is compiled
-but not executed.
-
-Godoc displays the body of ExampleXXX to demonstrate the use
-of the function, constant, or variable XXX.  An example of a method M with
-receiver type T or *T is named ExampleT_M.  There may be multiple examples
-for a given function, constant, or variable, distinguished by a trailing _xxx,
-where xxx is a suffix not beginning with an upper case letter.
-
-Here is an example of an example:
-
-	func ExamplePrintln() {
-		Println("The output of\nthis example.")
-		// Output: The output of
-		// this example.
-	}
-
-The entire test file is presented as the example when it contains a single
-example function, at least one other function, type, variable, or constant
-declaration, and no test or benchmark functions.
-
-See the documentation of the testing package for more information.
-
-
-*/
-package main
+		Respect case when matching symbols.
+	-cmd
+		Treat a command (package main) like a regular package.
+		Otherwise package main's exported symbols are hidden
+		when showing the package's top-level documentation.
+	-u
+		Show documentation for unexported as well as exported
+		symbols and methods.
+`,
+}
+
+func runDoc(cmd *Command, args []string) {
+	run(buildToolExec, tool("doc"), args)
+}
diff --git a/src/cmd/go/env.go b/src/cmd/go/env.go
index 26d37df..600acca 100644
--- a/src/cmd/go/env.go
+++ b/src/cmd/go/env.go
@@ -36,7 +36,6 @@ func mkEnv() []envVar {
 	env := []envVar{
 		{"GOARCH", goarch},
 		{"GOBIN", gobin},
-		{"GOCHAR", archChar},
 		{"GOEXE", exeSuffix},
 		{"GOHOSTARCH", runtime.GOARCH},
 		{"GOHOSTOS", runtime.GOOS},
@@ -45,6 +44,7 @@ func mkEnv() []envVar {
 		{"GORACE", os.Getenv("GORACE")},
 		{"GOROOT", goroot},
 		{"GOTOOLDIR", toolDir},
+		{"GO15VENDOREXPERIMENT", os.Getenv("GO15VENDOREXPERIMENT")},
 
 		// disable escape codes in clang errors
 		{"TERM", "dumb"},
diff --git a/src/cmd/go/fix.go b/src/cmd/go/fix.go
index 8736cce..94fd22e 100644
--- a/src/cmd/go/fix.go
+++ b/src/cmd/go/fix.go
@@ -11,7 +11,7 @@ var cmdFix = &Command{
 	Long: `
 Fix runs the Go fix command on the packages named by the import paths.
 
-For more about fix, see 'godoc fix'.
+For more about fix, see 'go doc cmd/fix'.
 For more about specifying packages, see 'go help packages'.
 
 To run fix with specific options, run 'go tool fix'.
@@ -25,6 +25,6 @@ func runFix(cmd *Command, args []string) {
 		// Use pkg.gofiles instead of pkg.Dir so that
 		// the command only applies to this package,
 		// not to packages in subdirectories.
-		run(stringList(tool("fix"), relPaths(pkg.allgofiles)))
+		run(stringList(buildToolExec, tool("fix"), relPaths(pkg.allgofiles)))
 	}
 }
diff --git a/src/cmd/go/fmt.go b/src/cmd/go/fmt.go
index 65dc3ca..57c02ad 100644
--- a/src/cmd/go/fmt.go
+++ b/src/cmd/go/fmt.go
@@ -4,6 +4,11 @@
 
 package main
 
+import (
+	"os"
+	"path/filepath"
+)
+
 func init() {
 	addBuildFlagsNX(cmdFmt)
 }
@@ -16,7 +21,7 @@ var cmdFmt = &Command{
 Fmt runs the command 'gofmt -l -w' on the packages named
 by the import paths.  It prints the names of the files that are modified.
 
-For more about gofmt, see 'godoc gofmt'.
+For more about gofmt, see 'go doc cmd/gofmt'.
 For more about specifying packages, see 'go help packages'.
 
 The -n flag prints commands that would be executed.
@@ -29,10 +34,31 @@ See also: go fix, go vet.
 }
 
 func runFmt(cmd *Command, args []string) {
+	gofmt := gofmtPath()
 	for _, pkg := range packages(args) {
 		// Use pkg.gofiles instead of pkg.Dir so that
 		// the command only applies to this package,
 		// not to packages in subdirectories.
-		run(stringList("gofmt", "-l", "-w", relPaths(pkg.allgofiles)))
+		run(stringList(gofmt, "-l", "-w", relPaths(pkg.allgofiles)))
 	}
 }
+
+func gofmtPath() string {
+	gofmt := "gofmt"
+	if toolIsWindows {
+		gofmt += toolWindowsExtension
+	}
+
+	gofmtPath := filepath.Join(gobin, gofmt)
+	if _, err := os.Stat(gofmtPath); err == nil {
+		return gofmtPath
+	}
+
+	gofmtPath = filepath.Join(goroot, "bin", gofmt)
+	if _, err := os.Stat(gofmtPath); err == nil {
+		return gofmtPath
+	}
+
+	// fallback to looking for gofmt in $PATH
+	return "gofmt"
+}
diff --git a/src/cmd/go/generate.go b/src/cmd/go/generate.go
index 3c0af87..efdc229 100644
--- a/src/cmd/go/generate.go
+++ b/src/cmd/go/generate.go
@@ -13,11 +13,11 @@ import (
 	"os"
 	"os/exec"
 	"path/filepath"
+	"regexp"
 	"runtime"
 	"strconv"
 	"strings"
 	"unicode"
-	"unicode/utf8"
 )
 
 var cmdGenerate = &Command{
@@ -62,8 +62,12 @@ Go generate sets several variables when it runs the generator:
 		The execution operating system (linux, windows, etc.)
 	$GOFILE
 		The base name of the file.
+	$GOLINE
+		The line number of the directive in the source 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
@@ -106,9 +110,10 @@ The generator is run in the package's source directory.
 Go generate accepts one specific flag:
 
 	-run=""
-		TODO: This flag is unimplemented.
-		if non-empty, specifies a regular expression to
-		select directives whose command matches the expression.
+		if non-empty, specifies a regular expression to select
+		directives whose full original source text (excluding
+		any trailing spaces and final newline) matches the
+		expression.
 
 It also accepts the standard build flags -v, -n, and -x.
 The -v flag prints the names of packages and files as they are
@@ -120,7 +125,10 @@ For more about specifying packages, see 'go help packages'.
 	`,
 }
 
-var generateRunFlag string // generate -run flag
+var (
+	generateRunFlag string         // generate -run flag
+	generateRunRE   *regexp.Regexp // compiled expression for -run
+)
 
 func init() {
 	addBuildFlags(cmdGenerate)
@@ -128,6 +136,13 @@ func init() {
 }
 
 func runGenerate(cmd *Command, args []string) {
+	if generateRunFlag != "" {
+		var err error
+		generateRunRE, err = regexp.Compile(generateRunFlag)
+		if err != nil {
+			log.Fatalf("generate: %s", err)
+		}
+	}
 	// Even if the arguments are .go files, this loop suffices.
 	for _, pkg := range packages(args) {
 		for _, file := range pkg.gofiles {
@@ -163,7 +178,7 @@ type Generator struct {
 	file     string // base name of file.
 	pkg      string
 	commands map[string][]string
-	lineNum  int
+	lineNum  int // current line number.
 }
 
 // run runs the generators in the current file.
@@ -221,6 +236,11 @@ func (g *Generator) run() (ok bool) {
 		if !isGoGenerate(buf) {
 			continue
 		}
+		if generateRunFlag != "" {
+			if !generateRunRE.Match(bytes.TrimSpace(buf)) {
+				continue
+			}
+		}
 
 		words := g.split(string(buf))
 		if len(words) == 0 {
@@ -306,7 +326,7 @@ Words:
 	}
 	// Substitute environment variables.
 	for i, word := range words {
-		words[i] = g.expandEnv(word)
+		words[i] = os.Expand(word, g.expandVar)
 	}
 	return words
 }
@@ -322,38 +342,25 @@ func (g *Generator) errorf(format string, args ...interface{}) {
 	panic(stop)
 }
 
-// expandEnv expands any $XXX invocations in word.
-func (g *Generator) expandEnv(word string) string {
-	if !strings.ContainsRune(word, '$') {
-		return word
-	}
-	var buf bytes.Buffer
-	var w int
-	var r rune
-	for i := 0; i < len(word); i += w {
-		r, w = utf8.DecodeRuneInString(word[i:])
-		if r != '$' {
-			buf.WriteRune(r)
-			continue
-		}
-		w += g.identLength(word[i+w:])
-		envVar := word[i+1 : i+w]
-		var sub string
-		switch envVar {
-		case "GOARCH":
-			sub = runtime.GOARCH
-		case "GOOS":
-			sub = runtime.GOOS
-		case "GOFILE":
-			sub = g.file
-		case "GOPACKAGE":
-			sub = g.pkg
-		default:
-			sub = os.Getenv(envVar)
-		}
-		buf.WriteString(sub)
+// expandVar expands the $XXX invocation in word. It is called
+// by os.Expand.
+func (g *Generator) expandVar(word string) string {
+	switch word {
+	case "GOARCH":
+		return buildContext.GOARCH
+	case "GOOS":
+		return buildContext.GOOS
+	case "GOFILE":
+		return g.file
+	case "GOLINE":
+		return fmt.Sprint(g.lineNum)
+	case "GOPACKAGE":
+		return g.pkg
+	case "DOLLAR":
+		return "$"
+	default:
+		return os.Getenv(word)
 	}
-	return buf.String()
 }
 
 // identLength returns the length of the identifier beginning the string.
@@ -395,7 +402,7 @@ func (g *Generator) exec(words []string) {
 		"GOFILE=" + g.file,
 		"GOPACKAGE=" + g.pkg,
 	}
-	cmd.Env = mergeEnvLists(env, os.Environ())
+	cmd.Env = mergeEnvLists(env, origEnv)
 	err := cmd.Run()
 	if err != nil {
 		g.errorf("running %q: %s", words[0], err)
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 @@ var splitTests = []splitTest{
 	{"$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 50e0ca9..e95201a 100644
--- a/src/cmd/go/get.go
+++ b/src/cmd/go/get.go
@@ -16,7 +16,7 @@ import (
 )
 
 var cmdGet = &Command{
-	UsageLine: "get [-d] [-f] [-fix] [-t] [-u] [build flags] [packages]",
+	UsageLine: "get [-d] [-f] [-fix] [-insecure] [-t] [-u] [build flags] [packages]",
 	Short:     "download and install packages and dependencies",
 	Long: `
 Get downloads and installs the packages named by the import paths,
@@ -33,6 +33,9 @@ of the original.
 The -fix flag instructs get to run the fix tool on the downloaded packages
 before resolving dependencies or building the code.
 
+The -insecure flag permits fetching from repositories and resolving
+custom domains using insecure schemes such as HTTP. Use with caution.
+
 The -t flag instructs get to also download the packages required to build
 the tests for the specified packages.
 
@@ -48,6 +51,10 @@ rule is that if the local installation is running version "go1", get
 searches for a branch or tag named "go1". If no such version exists it
 retrieves the most recent version of the package.
 
+If the vendoring experiment is enabled (see 'go help gopath'),
+then when go get checks out or updates a Git repository,
+it also updates any git submodules referenced by the repository.
+
 For more about specifying packages, see 'go help packages'.
 
 For more about how 'go get' finds source code to
@@ -62,6 +69,7 @@ var getF = cmdGet.Flag.Bool("f", false, "")
 var getT = cmdGet.Flag.Bool("t", false, "")
 var getU = cmdGet.Flag.Bool("u", false, "")
 var getFix = cmdGet.Flag.Bool("fix", false, "")
+var getInsecure = cmdGet.Flag.Bool("insecure", false, "")
 
 func init() {
 	addBuildFlags(cmdGet)
@@ -73,10 +81,20 @@ func runGet(cmd *Command, args []string) {
 		fatalf("go get: cannot use -f flag without -u")
 	}
 
+	// Disable any prompting for passwords by Git.
+	// Only has an effect for 2.3.0 or later, but avoiding
+	// the prompt in earlier versions is just too hard.
+	// See golang.org/issue/9341.
+	os.Setenv("GIT_TERMINAL_PROMPT", "0")
+
 	// Phase 1.  Download/update.
 	var stk importStack
+	mode := 0
+	if *getT {
+		mode |= getTestDeps
+	}
 	for _, arg := range downloadPaths(args) {
-		download(arg, &stk, *getT)
+		download(arg, nil, &stk, mode)
 	}
 	exitIfErrors()
 
@@ -92,12 +110,13 @@ func runGet(cmd *Command, args []string) {
 	}
 
 	args = importPaths(args)
+	packagesForBuild(args)
 
 	// Phase 3.  Install.
 	if *getD {
 		// Download only.
 		// Check delayed until now so that importPaths
-		// has a chance to print errors.
+		// and packagesForBuild have a chance to print errors.
 		return
 	}
 
@@ -148,13 +167,30 @@ var downloadRootCache = map[string]bool{}
 
 // download runs the download half of the get command
 // for the package named by the argument.
-func download(arg string, stk *importStack, getTestDeps bool) {
-	p := loadPackage(arg, stk)
+func download(arg string, parent *Package, stk *importStack, mode int) {
+	load := func(path string, mode int) *Package {
+		if parent == nil {
+			return loadPackage(path, stk)
+		}
+		return loadImport(path, parent.Dir, parent, stk, nil, mode)
+	}
+
+	p := load(arg, mode)
 	if p.Error != nil && p.Error.hard {
 		errorf("%s", p.Error)
 		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
@@ -163,7 +199,7 @@ func download(arg string, stk *importStack, getTestDeps bool) {
 	// Only process each package once.
 	// (Unless we're fetching test dependencies for this package,
 	// in which case we want to process it again.)
-	if downloadCache[arg] && !getTestDeps {
+	if downloadCache[arg] && mode&getTestDeps == 0 {
 		return
 	}
 	downloadCache[arg] = true
@@ -175,7 +211,7 @@ func download(arg string, stk *importStack, getTestDeps bool) {
 	// Download if the package is missing, or update if we're using -u.
 	if p.Dir == "" || *getU {
 		// The actual download.
-		stk.push(p.ImportPath)
+		stk.push(arg)
 		err := downloadPackage(p)
 		if err != nil {
 			errorf("%s", &PackageError{ImportStack: stk.copy(), Err: err.Error()})
@@ -183,6 +219,17 @@ func download(arg string, stk *importStack, getTestDeps bool) {
 			return
 		}
 
+		// Warn that code.google.com is shutting down.  We
+		// issue the warning here because this is where we
+		// have the import stack.
+		if strings.HasPrefix(p.ImportPath, "code.google.com") {
+			fmt.Fprintf(os.Stderr, "warning: code.google.com is shutting down; import path %v will stop working\n", p.ImportPath)
+			if len(*stk) > 1 {
+				fmt.Fprintf(os.Stderr, "warning: package %v\n", strings.Join(*stk, "\n\timports "))
+			}
+		}
+		stk.pop()
+
 		args := []string{arg}
 		// If the argument has a wildcard in it, re-evaluate the wildcard.
 		// We delay this until after reloadPackage so that the old entry
@@ -208,9 +255,10 @@ func download(arg string, stk *importStack, getTestDeps bool) {
 
 		pkgs = pkgs[:0]
 		for _, arg := range args {
-			stk.push(arg)
-			p := loadPackage(arg, stk)
-			stk.pop()
+			// Note: load calls loadPackage or loadImport,
+			// which push arg onto stk already.
+			// Do not push here too, or else stk will say arg imports arg.
+			p := load(arg, mode)
 			if p.Error != nil {
 				errorf("%s", p.Error)
 				continue
@@ -223,7 +271,7 @@ func download(arg string, stk *importStack, getTestDeps bool) {
 	// due to wildcard expansion.
 	for _, p := range pkgs {
 		if *getFix {
-			run(stringList(tool("fix"), relPaths(p.allgofiles)))
+			run(buildToolExec, stringList(tool("fix"), relPaths(p.allgofiles)))
 
 			// The imports might have changed, so reload again.
 			p = reloadPackage(arg, stk)
@@ -240,18 +288,31 @@ func download(arg string, stk *importStack, getTestDeps bool) {
 		}
 
 		// Process dependencies, now that we know what they are.
-		for _, dep := range p.deps {
+		for _, path := range p.Imports {
+			if path == "C" {
+				continue
+			}
 			// Don't get test dependencies recursively.
-			download(dep.ImportPath, stk, false)
+			// Imports is already vendor-expanded.
+			download(path, p, stk, 0)
 		}
-		if getTestDeps {
+		if mode&getTestDeps != 0 {
 			// Process test dependencies when -t is specified.
 			// (Don't get test dependencies for test dependencies.)
+			// We pass useVendor here because p.load does not
+			// vendor-expand TestImports and XTestImports.
+			// The call to loadImport inside download needs to do that.
 			for _, path := range p.TestImports {
-				download(path, stk, false)
+				if path == "C" {
+					continue
+				}
+				download(path, p, stk, useVendor)
 			}
 			for _, path := range p.XTestImports {
-				download(path, stk, false)
+				if path == "C" {
+					continue
+				}
+				download(path, p, stk, useVendor)
 			}
 		}
 
@@ -269,6 +330,12 @@ func downloadPackage(p *Package) error {
 		repo, rootPath string
 		err            error
 	)
+
+	security := secure
+	if *getInsecure {
+		security = insecure
+	}
+
 	if p.build.SrcRoot != "" {
 		// Directory exists.  Look for checkout along path to src.
 		vcs, rootPath, err = vcsForDir(p)
@@ -278,10 +345,15 @@ func downloadPackage(p *Package) error {
 		repo = "<local>" // should be unused; make distinctive
 
 		// Double-check where it came from.
-		if *getU && vcs.remoteRepo != nil && !*getF {
+		if *getU && vcs.remoteRepo != nil {
 			dir := filepath.Join(p.build.SrcRoot, rootPath)
-			if remote, err := vcs.remoteRepo(vcs, dir); err == nil {
-				if rr, err := repoRootForImportPath(p.ImportPath); err == nil {
+			remote, err := vcs.remoteRepo(vcs, dir)
+			if err != nil {
+				return err
+			}
+			repo = remote
+			if !*getF {
+				if rr, err := repoRootForImportPath(p.ImportPath, security); err == nil {
 					repo := rr.repo
 					if rr.vcs.resolveRepo != nil {
 						resolved, err := rr.vcs.resolveRepo(rr.vcs, dir, repo)
@@ -289,7 +361,7 @@ func downloadPackage(p *Package) error {
 							repo = resolved
 						}
 					}
-					if remote != repo {
+					if remote != repo && p.ImportComment != "" {
 						return fmt.Errorf("%s is a custom import path for %s, but %s is checked out from %s", rr.root, repo, dir, remote)
 					}
 				}
@@ -298,12 +370,15 @@ func downloadPackage(p *Package) error {
 	} else {
 		// Analyze the import path to determine the version control system,
 		// repository, and the import path for the root of the repository.
-		rr, err := repoRootForImportPath(p.ImportPath)
+		rr, err := repoRootForImportPath(p.ImportPath, security)
 		if err != nil {
 			return err
 		}
 		vcs, repo, rootPath = rr.vcs, rr.repo, rr.root
 	}
+	if !vcs.isSecure(repo) && !*getInsecure {
+		return fmt.Errorf("cannot download, %v uses insecure protocol", repo)
+	}
 
 	if p.build.SrcRoot == "" {
 		// Package not found.  Put in first directory of $GOPATH.
diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go
new file mode 100644
index 0000000..77b2628
--- /dev/null
+++ b/src/cmd/go/go_test.go
@@ -0,0 +1,2389 @@
+// 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_test
+
+import (
+	"bytes"
+	"flag"
+	"fmt"
+	"go/build"
+	"go/format"
+	"internal/testenv"
+	"io"
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"regexp"
+	"runtime"
+	"strconv"
+	"strings"
+	"testing"
+	"time"
+)
+
+var (
+	canRun  = true  // whether we can run go or ./testgo
+	canRace = false // whether we can run the race detector
+	canCgo  = false // whether we can use cgo
+
+	exeSuffix string // ".exe" on Windows
+
+	builder             = testenv.Builder()
+	skipExternalBuilder = false // skip external tests on this builder
+)
+
+func init() {
+	switch runtime.GOOS {
+	case "android", "nacl":
+		canRun = false
+	case "darwin":
+		switch runtime.GOARCH {
+		case "arm", "arm64":
+			canRun = false
+		}
+	}
+
+	if strings.HasPrefix(builder+"-", "freebsd-arm-") {
+		skipExternalBuilder = true
+		canRun = false
+	}
+
+	switch runtime.GOOS {
+	case "windows":
+		exeSuffix = ".exe"
+	}
+}
+
+// The TestMain function creates a go command for testing purposes and
+// deletes it after the tests have been run.
+func TestMain(m *testing.M) {
+	flag.Parse()
+
+	if canRun {
+		out, err := exec.Command("go", "build", "-tags", "testgo", "-o", "testgo"+exeSuffix).CombinedOutput()
+		if err != nil {
+			fmt.Fprintf(os.Stderr, "building testgo failed: %v\n%s", err, out)
+			os.Exit(2)
+		}
+
+		if out, err := exec.Command("./testgo"+exeSuffix, "env", "CGO_ENABLED").Output(); err != nil {
+			fmt.Fprintf(os.Stderr, "running testgo failed: %v\n", err)
+			canRun = false
+		} else {
+			canCgo, err = strconv.ParseBool(strings.TrimSpace(string(out)))
+			if err != nil {
+				fmt.Fprintf(os.Stderr, "can't parse go env CGO_ENABLED output: %v\n", strings.TrimSpace(string(out)))
+			}
+		}
+
+		switch runtime.GOOS {
+		case "linux", "darwin", "freebsd", "windows":
+			canRace = canCgo && runtime.GOARCH == "amd64"
+		}
+
+		measureTick("./testgo" + exeSuffix)
+	}
+
+	// Don't let these environment variables confuse the test.
+	os.Unsetenv("GOBIN")
+	os.Unsetenv("GOPATH")
+
+	r := m.Run()
+
+	if canRun {
+		os.Remove("testgo" + exeSuffix)
+	}
+
+	os.Exit(r)
+}
+
+// The length of an mtime tick on this system.  This is an estimate of
+// how long we need to sleep to ensure that the mtime of two files is
+// different.
+var mtimeTick time.Duration
+
+// measureTick sets mtimeTick by looking at the rounding of the mtime
+// of a file.
+func measureTick(path string) {
+	st, err := os.Stat(path)
+	if err != nil {
+		// Default to one second, the most conservative value.
+		mtimeTick = time.Second
+		return
+	}
+	mtime := st.ModTime()
+	t := time.Microsecond
+	for mtime.Round(t).Equal(mtime) && t < time.Second {
+		t *= 10
+	}
+	mtimeTick = t
+}
+
+// Manage a single run of the testgo binary.
+type testgoData struct {
+	t              *testing.T
+	temps          []string
+	wd             string
+	env            []string
+	tempdir        string
+	ran            bool
+	inParallel     bool
+	stdout, stderr bytes.Buffer
+}
+
+// testgo sets up for a test that runs testgo.
+func testgo(t *testing.T) *testgoData {
+	testenv.MustHaveGoBuild(t)
+
+	if skipExternalBuilder {
+		t.Skip("skipping external tests on %s builder", builder)
+	}
+
+	return &testgoData{t: t}
+}
+
+// must gives a fatal error if err is not nil.
+func (tg *testgoData) must(err error) {
+	if err != nil {
+		tg.t.Fatal(err)
+	}
+}
+
+// check gives a test non-fatal error if err is not nil.
+func (tg *testgoData) check(err error) {
+	if err != nil {
+		tg.t.Error(err)
+	}
+}
+
+// parallel runs the test in parallel by calling t.Parallel.
+func (tg *testgoData) parallel() {
+	if tg.ran {
+		tg.t.Fatal("internal testsuite error: call to parallel after run")
+	}
+	if tg.wd != "" {
+		tg.t.Fatal("internal testsuite error: call to parallel after cd")
+	}
+	for _, e := range tg.env {
+		if strings.HasPrefix(e, "GOROOT=") || strings.HasPrefix(e, "GOPATH=") || strings.HasPrefix(e, "GOBIN=") {
+			val := e[strings.Index(e, "=")+1:]
+			if strings.HasPrefix(val, "testdata") || strings.HasPrefix(val, "./testdata") {
+				tg.t.Fatalf("internal testsuite error: call to parallel with testdata in environment (%s)", e)
+			}
+		}
+	}
+	tg.inParallel = true
+	tg.t.Parallel()
+}
+
+// pwd returns the current directory.
+func (tg *testgoData) pwd() string {
+	wd, err := os.Getwd()
+	if err != nil {
+		tg.t.Fatalf("could not get working directory: %v", err)
+	}
+	return wd
+}
+
+// cd changes the current directory to the named directory.  Note that
+// using this means that the test must not be run in parallel with any
+// other tests.
+func (tg *testgoData) cd(dir string) {
+	if tg.inParallel {
+		tg.t.Fatal("internal testsuite error: changing directory when running in parallel")
+	}
+	if tg.wd == "" {
+		tg.wd = tg.pwd()
+	}
+	abs, err := filepath.Abs(dir)
+	tg.must(os.Chdir(dir))
+	if err == nil {
+		tg.setenv("PWD", abs)
+	}
+}
+
+// sleep sleeps for one tick, where a tick is a conservative estimate
+// of how long it takes for a file modification to get a different
+// mtime.
+func (tg *testgoData) sleep() {
+	time.Sleep(mtimeTick)
+}
+
+// setenv sets an environment variable to use when running the test go
+// command.
+func (tg *testgoData) setenv(name, val string) {
+	if tg.inParallel && (name == "GOROOT" || name == "GOPATH" || name == "GOBIN") && (strings.HasPrefix(val, "testdata") || strings.HasPrefix(val, "./testdata")) {
+		tg.t.Fatalf("internal testsuite error: call to setenv with testdata (%s=%s) after parallel", name, val)
+	}
+	tg.unsetenv(name)
+	tg.env = append(tg.env, name+"="+val)
+}
+
+// unsetenv removes an environment variable.
+func (tg *testgoData) unsetenv(name string) {
+	if tg.env == nil {
+		tg.env = append([]string(nil), os.Environ()...)
+	}
+	for i, v := range tg.env {
+		if strings.HasPrefix(v, name+"=") {
+			tg.env = append(tg.env[:i], tg.env[i+1:]...)
+			break
+		}
+	}
+}
+
+// doRun runs the test go command, recording stdout and stderr and
+// returning exit status.
+func (tg *testgoData) doRun(args []string) error {
+	if !canRun {
+		panic("testgoData.doRun called but canRun false")
+	}
+	if tg.inParallel {
+		for _, arg := range args {
+			if strings.HasPrefix(arg, "testdata") || strings.HasPrefix(arg, "./testdata") {
+				tg.t.Fatal("internal testsuite error: parallel run using testdata")
+			}
+		}
+	}
+	tg.t.Logf("running testgo %v", args)
+	var prog string
+	if tg.wd == "" {
+		prog = "./testgo" + exeSuffix
+	} else {
+		prog = filepath.Join(tg.wd, "testgo"+exeSuffix)
+	}
+	cmd := exec.Command(prog, args...)
+	tg.stdout.Reset()
+	tg.stderr.Reset()
+	cmd.Stdout = &tg.stdout
+	cmd.Stderr = &tg.stderr
+	cmd.Env = tg.env
+	status := cmd.Run()
+	if tg.stdout.Len() > 0 {
+		tg.t.Log("standard output:")
+		tg.t.Log(tg.stdout.String())
+	}
+	if tg.stderr.Len() > 0 {
+		tg.t.Log("standard error:")
+		tg.t.Log(tg.stderr.String())
+	}
+	tg.ran = true
+	return status
+}
+
+// run runs the test go command, and expects it to succeed.
+func (tg *testgoData) run(args ...string) {
+	if status := tg.doRun(args); status != nil {
+		tg.t.Logf("go %v failed unexpectedly: %v", args, status)
+		tg.t.FailNow()
+	}
+}
+
+// runFail runs the test go command, and expects it to fail.
+func (tg *testgoData) runFail(args ...string) {
+	if status := tg.doRun(args); status == nil {
+		tg.t.Fatal("testgo succeeded unexpectedly")
+	} else {
+		tg.t.Log("testgo failed as expected:", status)
+	}
+}
+
+// runGit runs a git command, and expects it to succeed.
+func (tg *testgoData) runGit(dir string, args ...string) {
+	cmd := exec.Command("git", args...)
+	tg.stdout.Reset()
+	tg.stderr.Reset()
+	cmd.Stdout = &tg.stdout
+	cmd.Stderr = &tg.stderr
+	cmd.Dir = dir
+	cmd.Env = tg.env
+	status := cmd.Run()
+	if tg.stdout.Len() > 0 {
+		tg.t.Log("git standard output:")
+		tg.t.Log(tg.stdout.String())
+	}
+	if tg.stderr.Len() > 0 {
+		tg.t.Log("git standard error:")
+		tg.t.Log(tg.stderr.String())
+	}
+	if status != nil {
+		tg.t.Logf("git %v failed unexpectedly: %v", args, status)
+		tg.t.FailNow()
+	}
+}
+
+// getStdout returns standard output of the testgo run as a string.
+func (tg *testgoData) getStdout() string {
+	if !tg.ran {
+		tg.t.Fatal("internal testsuite error: stdout called before run")
+	}
+	return tg.stdout.String()
+}
+
+// getStderr returns standard error of the testgo run as a string.
+func (tg *testgoData) getStderr() string {
+	if !tg.ran {
+		tg.t.Fatal("internal testsuite error: stdout called before run")
+	}
+	return tg.stderr.String()
+}
+
+// doGrepMatch looks for a regular expression in a buffer, and returns
+// whether it is found.  The regular expression is matched against
+// each line separately, as with the grep command.
+func (tg *testgoData) doGrepMatch(match string, b *bytes.Buffer) bool {
+	if !tg.ran {
+		tg.t.Fatal("internal testsuite error: grep called before run")
+	}
+	re := regexp.MustCompile(match)
+	for _, ln := range bytes.Split(b.Bytes(), []byte{'\n'}) {
+		if re.Match(ln) {
+			return true
+		}
+	}
+	return false
+}
+
+// doGrep looks for a regular expression in a buffer and fails if it
+// is not found.  The name argument is the name of the output we are
+// searching, "output" or "error".  The msg argument is logged on
+// failure.
+func (tg *testgoData) doGrep(match string, b *bytes.Buffer, name, msg string) {
+	if !tg.doGrepMatch(match, b) {
+		tg.t.Log(msg)
+		tg.t.Logf("pattern %v not found in standard %s", match, name)
+		tg.t.FailNow()
+	}
+}
+
+// grepStdout looks for a regular expression in the test run's
+// standard output and fails, logging msg, if it is not found.
+func (tg *testgoData) grepStdout(match, msg string) {
+	tg.doGrep(match, &tg.stdout, "output", msg)
+}
+
+// grepStderr looks for a regular expression in the test run's
+// standard error and fails, logging msg, if it is not found.
+func (tg *testgoData) grepStderr(match, msg string) {
+	tg.doGrep(match, &tg.stderr, "error", msg)
+}
+
+// grepBoth looks for a regular expression in the test run's standard
+// output or stand error and fails, logging msg, if it is not found.
+func (tg *testgoData) grepBoth(match, msg string) {
+	if !tg.doGrepMatch(match, &tg.stdout) && !tg.doGrepMatch(match, &tg.stderr) {
+		tg.t.Log(msg)
+		tg.t.Logf("pattern %v not found in standard output or standard error", match)
+		tg.t.FailNow()
+	}
+}
+
+// doGrepNot looks for a regular expression in a buffer and fails if
+// it is found.  The name and msg arguments are as for doGrep.
+func (tg *testgoData) doGrepNot(match string, b *bytes.Buffer, name, msg string) {
+	if tg.doGrepMatch(match, b) {
+		tg.t.Log(msg)
+		tg.t.Logf("pattern %v found unexpectedly in standard %s", match, name)
+		tg.t.FailNow()
+	}
+}
+
+// grepStdoutNot looks for a regular expression in the test run's
+// standard output and fails, logging msg, if it is found.
+func (tg *testgoData) grepStdoutNot(match, msg string) {
+	tg.doGrepNot(match, &tg.stdout, "output", msg)
+}
+
+// grepStderrNot looks for a regular expression in the test run's
+// standard error and fails, logging msg, if it is found.
+func (tg *testgoData) grepStderrNot(match, msg string) {
+	tg.doGrepNot(match, &tg.stderr, "error", msg)
+}
+
+// grepBothNot looks for a regular expression in the test run's
+// standard output or stand error and fails, logging msg, if it is
+// found.
+func (tg *testgoData) grepBothNot(match, msg string) {
+	if tg.doGrepMatch(match, &tg.stdout) || tg.doGrepMatch(match, &tg.stderr) {
+		tg.t.Log(msg)
+		tg.t.Fatalf("pattern %v found unexpectedly in standard output or standard error", match)
+	}
+}
+
+// doGrepCount counts the number of times a regexp is seen in a buffer.
+func (tg *testgoData) doGrepCount(match string, b *bytes.Buffer) int {
+	if !tg.ran {
+		tg.t.Fatal("internal testsuite error: doGrepCount called before run")
+	}
+	re := regexp.MustCompile(match)
+	c := 0
+	for _, ln := range bytes.Split(b.Bytes(), []byte{'\n'}) {
+		if re.Match(ln) {
+			c++
+		}
+	}
+	return c
+}
+
+// grepCountStdout returns the number of times a regexp is seen in
+// standard output.
+func (tg *testgoData) grepCountStdout(match string) int {
+	return tg.doGrepCount(match, &tg.stdout)
+}
+
+// grepCountStderr returns the number of times a regexp is seen in
+// standard error.
+func (tg *testgoData) grepCountStderr(match string) int {
+	return tg.doGrepCount(match, &tg.stderr)
+}
+
+// grepCountBoth returns the number of times a regexp is seen in both
+// standard output and standard error.
+func (tg *testgoData) grepCountBoth(match string) int {
+	return tg.doGrepCount(match, &tg.stdout) + tg.doGrepCount(match, &tg.stderr)
+}
+
+// creatingTemp records that the test plans to create a temporary file
+// or directory.  If the file or directory exists already, it will be
+// removed.  When the test completes, the file or directory will be
+// removed if it exists.
+func (tg *testgoData) creatingTemp(path string) {
+	if filepath.IsAbs(path) && !strings.HasPrefix(path, tg.tempdir) {
+		tg.t.Fatal("internal testsuite error: creatingTemp(%q) with absolute path not in temporary directory", path)
+	}
+	// If we have changed the working directory, make sure we have
+	// an absolute path, because we are going to change directory
+	// back before we remove the temporary.
+	if tg.wd != "" && !filepath.IsAbs(path) {
+		path = filepath.Join(tg.pwd(), path)
+	}
+	tg.must(os.RemoveAll(path))
+	tg.temps = append(tg.temps, path)
+}
+
+// makeTempdir makes a temporary directory for a run of testgo.  If
+// the temporary directory was already created, this does nothing.
+func (tg *testgoData) makeTempdir() {
+	if tg.tempdir == "" {
+		var err error
+		tg.tempdir, err = ioutil.TempDir("", "gotest")
+		tg.must(err)
+	}
+}
+
+// tempFile adds a temporary file for a run of testgo.
+func (tg *testgoData) tempFile(path, contents string) {
+	tg.makeTempdir()
+	tg.must(os.MkdirAll(filepath.Join(tg.tempdir, filepath.Dir(path)), 0755))
+	bytes := []byte(contents)
+	if strings.HasSuffix(path, ".go") {
+		formatted, err := format.Source(bytes)
+		if err == nil {
+			bytes = formatted
+		}
+	}
+	tg.must(ioutil.WriteFile(filepath.Join(tg.tempdir, path), bytes, 0644))
+}
+
+// tempDir adds a temporary directory for a run of testgo.
+func (tg *testgoData) tempDir(path string) {
+	tg.makeTempdir()
+	if err := os.MkdirAll(filepath.Join(tg.tempdir, path), 0755); err != nil && !os.IsExist(err) {
+		tg.t.Fatal(err)
+	}
+}
+
+// path returns the absolute pathname to file with the temporary
+// directory.
+func (tg *testgoData) path(name string) string {
+	if tg.tempdir == "" {
+		tg.t.Fatalf("internal testsuite error: path(%q) with no tempdir", name)
+	}
+	if name == "." {
+		return tg.tempdir
+	}
+	return filepath.Join(tg.tempdir, name)
+}
+
+// mustNotExist fails if path exists.
+func (tg *testgoData) mustNotExist(path string) {
+	if _, err := os.Stat(path); err == nil || !os.IsNotExist(err) {
+		tg.t.Fatalf("%s exists but should not (%v)", path, err)
+	}
+}
+
+// wantExecutable fails with msg if path is not executable.
+func (tg *testgoData) wantExecutable(path, msg string) {
+	if st, err := os.Stat(path); err != nil {
+		if !os.IsNotExist(err) {
+			tg.t.Log(err)
+		}
+		tg.t.Fatal(msg)
+	} else {
+		if runtime.GOOS != "windows" && st.Mode()&0111 == 0 {
+			tg.t.Fatalf("binary %s exists but is not executable", path)
+		}
+	}
+}
+
+// wantArchive fails if path is not an archive.
+func (tg *testgoData) wantArchive(path string) {
+	f, err := os.Open(path)
+	if err != nil {
+		tg.t.Fatal(err)
+	}
+	buf := make([]byte, 100)
+	io.ReadFull(f, buf)
+	f.Close()
+	if !bytes.HasPrefix(buf, []byte("!<arch>\n")) {
+		tg.t.Fatalf("file %s exists but is not an archive", path)
+	}
+}
+
+// isStale returns whether pkg is stale.
+func (tg *testgoData) isStale(pkg string) bool {
+	tg.run("list", "-f", "{{.Stale}}", pkg)
+	switch v := strings.TrimSpace(tg.getStdout()); v {
+	case "true":
+		return true
+	case "false":
+		return false
+	default:
+		tg.t.Fatalf("unexpected output checking staleness of package %v: %v", pkg, v)
+		panic("unreachable")
+	}
+}
+
+// wantStale fails with msg if pkg is not stale.
+func (tg *testgoData) wantStale(pkg, msg string) {
+	if !tg.isStale(pkg) {
+		tg.t.Fatal(msg)
+	}
+}
+
+// wantNotStale fails with msg if pkg is stale.
+func (tg *testgoData) wantNotStale(pkg, msg string) {
+	if tg.isStale(pkg) {
+		tg.t.Fatal(msg)
+	}
+}
+
+// cleanup cleans up a test that runs testgo.
+func (tg *testgoData) cleanup() {
+	if tg.wd != "" {
+		if err := os.Chdir(tg.wd); err != nil {
+			// We are unlikely to be able to continue.
+			fmt.Fprintln(os.Stderr, "could not restore working directory, crashing:", err)
+			os.Exit(2)
+		}
+	}
+	for _, path := range tg.temps {
+		tg.check(os.RemoveAll(path))
+	}
+	if tg.tempdir != "" {
+		tg.check(os.RemoveAll(tg.tempdir))
+	}
+}
+
+// resetReadOnlyFlagAll resets windows read-only flag
+// set on path and any children it contains.
+// The flag is set by git and has to be removed.
+// os.Remove refuses to remove files with read-only flag set.
+func (tg *testgoData) resetReadOnlyFlagAll(path string) {
+	fi, err := os.Stat(path)
+	if err != nil {
+		tg.t.Fatalf("resetReadOnlyFlagAll(%q) failed: %v", path, err)
+	}
+	if !fi.IsDir() {
+		err := os.Chmod(path, 0666)
+		if err != nil {
+			tg.t.Fatalf("resetReadOnlyFlagAll(%q) failed: %v", path, err)
+		}
+	}
+	fd, err := os.Open(path)
+	if err != nil {
+		tg.t.Fatalf("resetReadOnlyFlagAll(%q) failed: %v", path, err)
+	}
+	defer fd.Close()
+	names, _ := fd.Readdirnames(-1)
+	for _, name := range names {
+		tg.resetReadOnlyFlagAll(path + string(filepath.Separator) + name)
+	}
+}
+
+// failSSH puts an ssh executable in the PATH that always fails.
+// This is to stub out uses of ssh by go get.
+func (tg *testgoData) failSSH() {
+	wd, err := os.Getwd()
+	if err != nil {
+		tg.t.Fatal(err)
+	}
+	fail := filepath.Join(wd, "testdata/failssh")
+	tg.setenv("PATH", fmt.Sprintf("%v%c%v", fail, filepath.ListSeparator, os.Getenv("PATH")))
+}
+
+func TestFileLineInErrorMessages(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.parallel()
+	tg.tempFile("err.go", `package main; import "bar"`)
+	path := tg.path("err.go")
+	tg.runFail("run", path)
+	shortPath := path
+	if rel, err := filepath.Rel(tg.pwd(), path); err == nil && len(rel) < len(path) {
+		shortPath = rel
+	}
+	tg.grepStderr("^"+regexp.QuoteMeta(shortPath)+":", "missing file:line in error message")
+}
+
+func TestProgramNameInCrashMessages(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.parallel()
+	tg.tempFile("triv.go", `package main; func main() {}`)
+	tg.runFail("build", "-ldflags", "-crash_for_testing", tg.path("triv.go"))
+	tg.grepStderr(`[/\\]tool[/\\].*[/\\]link`, "missing linker name in error message")
+}
+
+func TestBrokenTestsWithoutTestFunctionsAllFail(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.runFail("test", "./testdata/src/badtest/...")
+	tg.grepBothNot("^ok", "test passed unexpectedly")
+	tg.grepBoth("FAIL.*badtest/badexec", "test did not run everything")
+	tg.grepBoth("FAIL.*badtest/badsyntax", "test did not run everything")
+	tg.grepBoth("FAIL.*badtest/badvar", "test did not run everything")
+}
+
+func TestGoBuildDashAInDevBranch(t *testing.T) {
+	if testing.Short() {
+		t.Skip("don't rebuild the standard library in short mode")
+	}
+
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.run("install", "math") // should be up to date already but just in case
+	tg.setenv("TESTGO_IS_GO_RELEASE", "0")
+	tg.run("build", "-v", "-a", "math")
+	tg.grepStderr("runtime", "testgo build -a math in dev branch DID NOT build runtime, but should have")
+}
+
+func TestGoBuilDashAInReleaseBranch(t *testing.T) {
+	if testing.Short() {
+		t.Skip("don't rebuild the standard library in short mode")
+	}
+
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.run("install", "math") // should be up to date already but just in case
+	tg.setenv("TESTGO_IS_GO_RELEASE", "1")
+	tg.run("build", "-v", "-a", "math")
+	tg.grepStderr("runtime", "testgo build -a math in dev branch did not build runtime, but should have")
+}
+
+func TestGoInstallCleansUpAfterGoBuild(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.tempFile("src/mycmd/main.go", `package main; func main(){}`)
+	tg.setenv("GOPATH", tg.path("."))
+	tg.cd(tg.path("src/mycmd"))
+
+	doesNotExist := func(file, msg string) {
+		if _, err := os.Stat(file); err == nil {
+			t.Fatal(msg)
+		} else if !os.IsNotExist(err) {
+			t.Fatal(msg, "error:", err)
+		}
+	}
+
+	tg.run("build")
+	tg.wantExecutable("mycmd"+exeSuffix, "testgo build did not write command binary")
+	tg.run("install")
+	doesNotExist("mycmd"+exeSuffix, "testgo install did not remove command binary")
+	tg.run("build")
+	tg.wantExecutable("mycmd"+exeSuffix, "testgo build did not write command binary (second time)")
+	// Running install with arguments does not remove the target,
+	// even in the same directory.
+	tg.run("install", "mycmd")
+	tg.wantExecutable("mycmd"+exeSuffix, "testgo install mycmd removed command binary when run in mycmd")
+	tg.run("build")
+	tg.wantExecutable("mycmd"+exeSuffix, "testgo build did not write command binary (third time)")
+	// And especially not outside the directory.
+	tg.cd(tg.path("."))
+	if data, err := ioutil.ReadFile("src/mycmd/mycmd" + exeSuffix); err != nil {
+		t.Fatal("could not read file:", err)
+	} else {
+		if err := ioutil.WriteFile("mycmd"+exeSuffix, data, 0555); err != nil {
+			t.Fatal("could not write file:", err)
+		}
+	}
+	tg.run("install", "mycmd")
+	tg.wantExecutable("src/mycmd/mycmd"+exeSuffix, "testgo install mycmd removed command binary from its source dir when run outside mycmd")
+	tg.wantExecutable("mycmd"+exeSuffix, "testgo install mycmd removed command binary from current dir when run outside mycmd")
+}
+
+func TestGoInstallRebuildsStalePackagesInOtherGOPATH(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.parallel()
+	tg.tempFile("d1/src/p1/p1.go", `package p1
+		import "p2"
+		func F() { p2.F() }`)
+	tg.tempFile("d2/src/p2/p2.go", `package p2
+		func F() {}`)
+	sep := string(filepath.ListSeparator)
+	tg.setenv("GOPATH", tg.path("d1")+sep+tg.path("d2"))
+	tg.run("install", "p1")
+	tg.wantNotStale("p1", "./testgo list mypkg claims p1 is stale, incorrectly")
+	tg.wantNotStale("p2", "./testgo list mypkg claims p2 is stale, incorrectly")
+	tg.sleep()
+	if f, err := os.OpenFile(tg.path("d2/src/p2/p2.go"), os.O_WRONLY|os.O_APPEND, 0); err != nil {
+		t.Fatal(err)
+	} else if _, err = f.WriteString(`func G() {}`); err != nil {
+		t.Fatal(err)
+	} else {
+		tg.must(f.Close())
+	}
+	tg.wantStale("p2", "./testgo list mypkg claims p2 is NOT stale, incorrectly")
+	tg.wantStale("p1", "./testgo list mypkg claims p1 is NOT stale, incorrectly")
+
+	tg.run("install", "p1")
+	tg.wantNotStale("p2", "./testgo list mypkg claims p2 is stale after reinstall, incorrectly")
+	tg.wantNotStale("p1", "./testgo list mypkg claims p1 is stale after reinstall, incorrectly")
+}
+
+func TestGoInstallDetectsRemovedFiles(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.parallel()
+	tg.tempFile("src/mypkg/x.go", `package mypkg`)
+	tg.tempFile("src/mypkg/y.go", `package mypkg`)
+	tg.tempFile("src/mypkg/z.go", `// +build missingtag
+
+		package mypkg`)
+	tg.setenv("GOPATH", tg.path("."))
+	tg.run("install", "mypkg")
+	tg.wantNotStale("mypkg", "./testgo list mypkg claims mypkg is stale, incorrectly")
+	// z.go was not part of the build; removing it is okay.
+	tg.must(os.Remove(tg.path("src/mypkg/z.go")))
+	tg.wantNotStale("mypkg", "./testgo list mypkg claims mypkg is stale after removing z.go; should not be stale")
+	// y.go was part of the package; removing it should be detected.
+	tg.must(os.Remove(tg.path("src/mypkg/y.go")))
+	tg.wantStale("mypkg", "./testgo list mypkg claims mypkg is NOT stale after removing y.go; should be stale")
+}
+
+func TestGoInstallErrorOnCrossCompileToBin(t *testing.T) {
+	if testing.Short() {
+		t.Skip("don't install into GOROOT in short mode")
+	}
+
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.tempFile("src/mycmd/x.go", `package main
+		func main() {}`)
+	tg.setenv("GOPATH", tg.path("."))
+	tg.cd(tg.path("src/mycmd"))
+
+	tg.run("build", "mycmd")
+
+	goarch := "386"
+	if runtime.GOARCH == "386" {
+		goarch = "amd64"
+	}
+	tg.setenv("GOOS", "linux")
+	tg.setenv("GOARCH", goarch)
+	tg.run("install", "mycmd")
+	tg.setenv("GOBIN", tg.path("."))
+	tg.runFail("install", "mycmd")
+	tg.run("install", "cmd/pack")
+}
+
+func TestGoInstallDetectsRemovedFilesInPackageMain(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.parallel()
+	tg.tempFile("src/mycmd/x.go", `package main
+		func main() {}`)
+	tg.tempFile("src/mycmd/y.go", `package main`)
+	tg.tempFile("src/mycmd/z.go", `// +build missingtag
+
+		package main`)
+	tg.setenv("GOPATH", tg.path("."))
+	tg.run("install", "mycmd")
+	tg.wantNotStale("mycmd", "./testgo list mypkg claims mycmd is stale, incorrectly")
+	// z.go was not part of the build; removing it is okay.
+	tg.must(os.Remove(tg.path("src/mycmd/z.go")))
+	tg.wantNotStale("mycmd", "./testgo list mycmd claims mycmd is stale after removing z.go; should not be stale")
+	// y.go was part of the package; removing it should be detected.
+	tg.must(os.Remove(tg.path("src/mycmd/y.go")))
+	tg.wantStale("mycmd", "./testgo list mycmd claims mycmd is NOT stale after removing y.go; should be stale")
+}
+
+func testLocalRun(tg *testgoData, exepath, local, match string) {
+	out, err := exec.Command(exepath).Output()
+	if err != nil {
+		tg.t.Fatalf("error running %v: %v", exepath, err)
+	}
+	if !regexp.MustCompile(match).Match(out) {
+		tg.t.Log(string(out))
+		tg.t.Errorf("testdata/%s/easy.go did not generate expected output", local)
+	}
+}
+
+func testLocalEasy(tg *testgoData, local string) {
+	exepath := "./easy" + exeSuffix
+	tg.creatingTemp(exepath)
+	tg.run("build", "-o", exepath, filepath.Join("testdata", local, "easy.go"))
+	testLocalRun(tg, exepath, local, `(?m)^easysub\.Hello`)
+}
+
+func testLocalEasySub(tg *testgoData, local string) {
+	exepath := "./easysub" + exeSuffix
+	tg.creatingTemp(exepath)
+	tg.run("build", "-o", exepath, filepath.Join("testdata", local, "easysub", "main.go"))
+	testLocalRun(tg, exepath, local, `(?m)^easysub\.Hello`)
+}
+
+func testLocalHard(tg *testgoData, local string) {
+	exepath := "./hard" + exeSuffix
+	tg.creatingTemp(exepath)
+	tg.run("build", "-o", exepath, filepath.Join("testdata", local, "hard.go"))
+	testLocalRun(tg, exepath, local, `(?m)^sub\.Hello`)
+}
+
+func testLocalInstall(tg *testgoData, local string) {
+	tg.runFail("install", filepath.Join("testdata", local, "easy.go"))
+}
+
+func TestLocalImportsEasy(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	testLocalEasy(tg, "local")
+}
+
+func TestLocalImportsEasySub(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	testLocalEasySub(tg, "local")
+}
+
+func TestLocalImportsHard(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	testLocalHard(tg, "local")
+}
+
+func TestLocalImportsGoInstallShouldFail(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	testLocalInstall(tg, "local")
+}
+
+const badDirName = `#$%:, &()*;<=>?\^{}`
+
+func copyBad(tg *testgoData) {
+	if runtime.GOOS == "windows" {
+		tg.t.Skipf("skipping test because %q is an invalid directory name", badDirName)
+	}
+
+	tg.must(filepath.Walk("testdata/local",
+		func(path string, info os.FileInfo, err error) error {
+			if err != nil {
+				return err
+			}
+			if info.IsDir() {
+				return nil
+			}
+			var data []byte
+			data, err = ioutil.ReadFile(path)
+			if err != nil {
+				return err
+			}
+			newpath := strings.Replace(path, "local", badDirName, 1)
+			tg.tempFile(newpath, string(data))
+			return nil
+		}))
+	tg.cd(tg.path("."))
+}
+
+func TestBadImportsEasy(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	copyBad(tg)
+	testLocalEasy(tg, badDirName)
+}
+
+func TestBadImportsEasySub(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	copyBad(tg)
+	testLocalEasySub(tg, badDirName)
+}
+
+func TestBadImportsHard(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	copyBad(tg)
+	testLocalHard(tg, badDirName)
+}
+
+func TestBadImportsGoInstallShouldFail(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	copyBad(tg)
+	testLocalInstall(tg, badDirName)
+}
+
+func TestInternalPackagesInGOROOTAreRespected(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.runFail("build", "-v", "./testdata/testinternal")
+	tg.grepBoth("use of internal package not allowed", "wrong error message for testdata/testinternal")
+}
+
+func TestInternalPackagesOutsideGOROOTAreRespected(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.runFail("build", "-v", "./testdata/testinternal2")
+	tg.grepBoth("use of internal package not allowed", "wrote error message for testdata/testinternal2")
+}
+
+func testMove(t *testing.T, vcs, url, base, config string) {
+	testenv.MustHaveExternalNetwork(t)
+
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.parallel()
+	tg.tempDir("src")
+	tg.setenv("GOPATH", tg.path("."))
+	tg.run("get", "-d", url)
+	tg.run("get", "-d", "-u", url)
+	switch vcs {
+	case "svn":
+		// SVN doesn't believe in text files so we can't just edit the config.
+		// Check out a different repo into the wrong place.
+		tg.must(os.RemoveAll(tg.path("src/code.google.com/p/rsc-svn")))
+		tg.run("get", "-d", "-u", "code.google.com/p/rsc-svn2/trunk")
+		tg.must(os.Rename(tg.path("src/code.google.com/p/rsc-svn2"), tg.path("src/code.google.com/p/rsc-svn")))
+	default:
+		path := tg.path(filepath.Join("src", config))
+		data, err := ioutil.ReadFile(path)
+		tg.must(err)
+		data = bytes.Replace(data, []byte(base), []byte(base+"XXX"), -1)
+		tg.must(ioutil.WriteFile(path, data, 0644))
+	}
+	if vcs == "git" {
+		// git will ask for a username and password when we
+		// run go get -d -f -u.  An empty username and
+		// password will work.  Prevent asking by setting
+		// GIT_ASKPASS.
+		tg.creatingTemp("sink" + exeSuffix)
+		tg.tempFile("src/sink/sink.go", `package main; func main() {}`)
+		tg.run("build", "-o", "sink"+exeSuffix, "sink")
+		tg.setenv("GIT_ASKPASS", filepath.Join(tg.pwd(), "sink"+exeSuffix))
+	}
+	tg.runFail("get", "-d", "-u", url)
+	tg.grepStderr("is a custom import path for", "go get -d -u "+url+" failed for wrong reason")
+	tg.runFail("get", "-d", "-f", "-u", url)
+	tg.grepStderr("validating server certificate|not found", "go get -d -f -u "+url+" failed for wrong reason")
+}
+
+func TestInternalPackageErrorsAreHandled(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.run("list", "./testdata/testinternal3")
+}
+
+func TestInternalCache(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata/testinternal4"))
+	tg.runFail("build", "p")
+	tg.grepStderr("internal", "did not fail to build p")
+}
+
+func TestMoveGit(t *testing.T) {
+	testMove(t, "git", "rsc.io/pdf", "pdf", "rsc.io/pdf/.git/config")
+}
+
+// TODO(rsc): Set up a test case on bitbucket for hg.
+// func TestMoveHG(t *testing.T) {
+// 	testMove(t, "hg", "rsc.io/x86/x86asm", "x86", "rsc.io/x86/.hg/hgrc")
+// }
+
+// TODO(rsc): Set up a test case on SourceForge (?) for svn.
+// func testMoveSVN(t *testing.T) {
+//	testMove(t, "svn", "code.google.com/p/rsc-svn/trunk", "-", "-")
+// }
+
+func TestImportCommandMatch(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata/importcom"))
+	tg.run("build", "./testdata/importcom/works.go")
+}
+
+func TestImportCommentMismatch(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata/importcom"))
+	tg.runFail("build", "./testdata/importcom/wrongplace.go")
+	tg.grepStderr(`wrongplace expects import "my/x"`, "go build did not mention incorrect import")
+}
+
+func TestImportCommentSyntaxError(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata/importcom"))
+	tg.runFail("build", "./testdata/importcom/bad.go")
+	tg.grepStderr("cannot parse import comment", "go build did not mention syntax error")
+}
+
+func TestImportCommentConflict(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata/importcom"))
+	tg.runFail("build", "./testdata/importcom/conflict.go")
+	tg.grepStderr("found import comments", "go build did not mention comment conflict")
+}
+
+// cmd/go: custom import path checking should not apply to github.com/xxx/yyy.
+func TestIssue10952(t *testing.T) {
+	testenv.MustHaveExternalNetwork(t)
+
+	if _, err := exec.LookPath("git"); err != nil {
+		t.Skip("skipping because git binary not found")
+	}
+
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.parallel()
+	tg.tempDir("src")
+	tg.setenv("GOPATH", tg.path("."))
+	const importPath = "github.com/zombiezen/go-get-issue-10952"
+	tg.run("get", "-d", "-u", importPath)
+	repoDir := tg.path("src/" + importPath)
+	defer tg.resetReadOnlyFlagAll(repoDir)
+	tg.runGit(repoDir, "remote", "set-url", "origin", "https://"+importPath+".git")
+	tg.run("get", "-d", "-u", importPath)
+}
+
+func TestDisallowedCSourceFiles(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+	tg.runFail("build", "badc")
+	tg.grepStderr("C source files not allowed", "go test did not say C source files not allowed")
+}
+
+func TestErrorMessageForSyntaxErrorInTestGoFileSaysFAIL(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+	tg.runFail("test", "syntaxerror")
+	tg.grepStderr("FAIL", "go test did not say FAIL")
+}
+
+func TestWildcardsDoNotLookInUselessDirectories(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+	tg.runFail("list", "...")
+	tg.grepBoth("badpkg", "go list ... failure does not mention badpkg")
+	tg.run("list", "m...")
+}
+
+func TestRelativeImportsGoTest(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.run("test", "./testdata/testimport")
+}
+
+func TestRelativeImportsGoTestDashI(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.run("test", "-i", "./testdata/testimport")
+}
+
+func TestRelativeImportsInCommandLinePackage(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	files, err := filepath.Glob("./testdata/testimport/*.go")
+	tg.must(err)
+	tg.run(append([]string{"test"}, files...)...)
+}
+
+func TestVersionControlErrorMessageIncludesCorrectDirectory(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata/shadow/root1"))
+	tg.runFail("get", "-u", "foo")
+
+	// TODO(iant): We should not have to use strconv.Quote here.
+	// The code in vcs.go should be changed so that it is not required.
+	quoted := strconv.Quote(filepath.Join("testdata", "shadow", "root1", "src", "foo"))
+	quoted = quoted[1 : len(quoted)-1]
+
+	tg.grepStderr(regexp.QuoteMeta(quoted), "go get -u error does not mention shadow/root1/src/foo")
+}
+
+func TestInstallFailsWithNoBuildableFiles(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+	tg.setenv("CGO_ENABLED", "0")
+	tg.runFail("install", "cgotest")
+	tg.grepStderr("no buildable Go source files", "go install cgotest did not report 'no buildable Go Source files'")
+}
+
+// Test that without $GOBIN set, binaries get installed
+// into the GOPATH bin directory.
+func TestInstallIntoGOPATH(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.creatingTemp("testdata/bin/go-cmd-test" + exeSuffix)
+	tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+	tg.run("install", "go-cmd-test")
+	tg.wantExecutable("testdata/bin/go-cmd-test"+exeSuffix, "go install go-cmd-test did not write to testdata/bin/go-cmd-test")
+}
+
+func TestPackageMainTestImportsArchiveNotBinary(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	gobin := filepath.Join(tg.pwd(), "testdata", "bin")
+	tg.creatingTemp(gobin)
+	tg.setenv("GOBIN", gobin)
+	tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+	tg.must(os.Chtimes("./testdata/src/main_test/m.go", time.Now(), time.Now()))
+	tg.sleep()
+	tg.run("test", "main_test")
+	tg.run("install", "main_test")
+	tg.wantNotStale("main_test", "after go install, main listed as stale")
+	tg.run("test", "main_test")
+}
+
+// With $GOBIN set, binaries get installed to $GOBIN.
+func TestInstallIntoGOBIN(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	gobin := filepath.Join(tg.pwd(), "testdata", "bin1")
+	tg.creatingTemp(gobin)
+	tg.setenv("GOBIN", gobin)
+	tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+	tg.run("install", "go-cmd-test")
+	tg.wantExecutable("testdata/bin1/go-cmd-test"+exeSuffix, "go install go-cmd-test did not write to testdata/bin1/go-cmd-test")
+}
+
+// Issue 11065
+func TestInstallToCurrentDirectoryCreatesExecutable(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	pkg := filepath.Join(tg.pwd(), "testdata", "src", "go-cmd-test")
+	tg.creatingTemp(filepath.Join(pkg, "go-cmd-test"+exeSuffix))
+	tg.setenv("GOBIN", pkg)
+	tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+	tg.cd(pkg)
+	tg.run("install")
+	tg.wantExecutable("go-cmd-test"+exeSuffix, "go install did not write to current directory")
+}
+
+// Without $GOBIN set, installing a program outside $GOPATH should fail
+// (there is nowhere to install it).
+func TestInstallWithoutDestinationFails(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.runFail("install", "testdata/src/go-cmd-test/helloworld.go")
+	tg.grepStderr("no install location for .go files listed on command line", "wrong error")
+}
+
+// With $GOBIN set, should install there.
+func TestInstallToGOBINCommandLinePackage(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	gobin := filepath.Join(tg.pwd(), "testdata", "bin1")
+	tg.creatingTemp(gobin)
+	tg.setenv("GOBIN", gobin)
+	tg.run("install", "testdata/src/go-cmd-test/helloworld.go")
+	tg.wantExecutable("testdata/bin1/helloworld"+exeSuffix, "go install testdata/src/go-cmd-test/helloworld.go did not write testdata/bin1/helloworld")
+}
+
+func TestGodocInstalls(t *testing.T) {
+	testenv.MustHaveExternalNetwork(t)
+
+	// godoc installs into GOBIN
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.parallel()
+	tg.tempDir("gobin")
+	tg.setenv("GOPATH", tg.path("."))
+	tg.setenv("GOBIN", tg.path("gobin"))
+	tg.run("get", "golang.org/x/tools/cmd/godoc")
+	tg.wantExecutable(tg.path("gobin/godoc"), "did not install godoc to $GOBIN")
+	tg.unsetenv("GOBIN")
+
+	// godoc installs into GOROOT
+	goroot := runtime.GOROOT()
+	tg.setenv("GOROOT", goroot)
+	tg.check(os.RemoveAll(filepath.Join(goroot, "bin", "godoc")))
+	tg.run("install", "golang.org/x/tools/cmd/godoc")
+	tg.wantExecutable(filepath.Join(goroot, "bin", "godoc"), "did not install godoc to $GOROOT/bin")
+}
+
+func TestGoGetNonPkg(t *testing.T) {
+	testenv.MustHaveExternalNetwork(t)
+
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.tempDir("gobin")
+	tg.setenv("GOPATH", tg.path("."))
+	tg.setenv("GOBIN", tg.path("gobin"))
+	tg.runFail("get", "-d", "golang.org/x/tools")
+	tg.grepStderr("golang.org/x/tools: no buildable Go source files", "missing error")
+	tg.runFail("get", "-d", "-u", "golang.org/x/tools")
+	tg.grepStderr("golang.org/x/tools: no buildable Go source files", "missing error")
+	tg.runFail("get", "-d", "golang.org/x/tools")
+	tg.grepStderr("golang.org/x/tools: no buildable Go source files", "missing error")
+}
+
+func TestInstalls(t *testing.T) {
+	if testing.Short() {
+		t.Skip("don't install into GOROOT in short mode")
+	}
+
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.parallel()
+	tg.tempDir("gobin")
+	tg.setenv("GOPATH", tg.path("."))
+	goroot := runtime.GOROOT()
+	tg.setenv("GOROOT", goroot)
+
+	// cmd/fix installs into tool
+	tg.run("env", "GOOS")
+	goos := strings.TrimSpace(tg.getStdout())
+	tg.setenv("GOOS", goos)
+	tg.run("env", "GOARCH")
+	goarch := strings.TrimSpace(tg.getStdout())
+	tg.setenv("GOARCH", goarch)
+	fixbin := filepath.Join(goroot, "pkg", "tool", goos+"_"+goarch, "fix") + exeSuffix
+	tg.must(os.RemoveAll(fixbin))
+	tg.run("install", "cmd/fix")
+	tg.wantExecutable(fixbin, "did not install cmd/fix to $GOROOT/pkg/tool")
+	tg.must(os.Remove(fixbin))
+	tg.setenv("GOBIN", tg.path("gobin"))
+	tg.run("install", "cmd/fix")
+	tg.wantExecutable(fixbin, "did not install cmd/fix to $GOROOT/pkg/tool with $GOBIN set")
+	tg.unsetenv("GOBIN")
+
+	// gopath program installs into GOBIN
+	tg.tempFile("src/progname/p.go", `package main; func main() {}`)
+	tg.setenv("GOBIN", tg.path("gobin"))
+	tg.run("install", "progname")
+	tg.unsetenv("GOBIN")
+	tg.wantExecutable(tg.path("gobin/progname")+exeSuffix, "did not install progname to $GOBIN/progname")
+
+	// gopath program installs into GOPATH/bin
+	tg.run("install", "progname")
+	tg.wantExecutable(tg.path("bin/progname")+exeSuffix, "did not install progname to $GOPATH/bin/progname")
+}
+
+func TestRejectRelativeDotPathInGOPATHCommandLinePackage(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.setenv("GOPATH", ".")
+	tg.runFail("build", "testdata/src/go-cmd-test/helloworld.go")
+	tg.grepStderr("GOPATH entry is relative", "expected an error message rejecting relative GOPATH entries")
+}
+
+func TestRejectRelativePathsInGOPATH(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	sep := string(filepath.ListSeparator)
+	tg.setenv("GOPATH", sep+filepath.Join(tg.pwd(), "testdata")+sep+".")
+	tg.runFail("build", "go-cmd-test")
+	tg.grepStderr("GOPATH entry is relative", "expected an error message rejecting relative GOPATH entries")
+}
+
+func TestRejectRelativePathsInGOPATHCommandLinePackage(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.setenv("GOPATH", "testdata")
+	tg.runFail("build", "testdata/src/go-cmd-test/helloworld.go")
+	tg.grepStderr("GOPATH entry is relative", "expected an error message rejecting relative GOPATH entries")
+}
+
+// Issue 4104.
+func TestGoTestWithPackageListedMultipleTimes(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.parallel()
+	tg.run("test", "errors", "errors", "errors", "errors", "errors")
+	if strings.Index(strings.TrimSpace(tg.getStdout()), "\n") != -1 {
+		t.Error("go test errors errors errors errors errors tested the same package multiple times")
+	}
+}
+
+func TestGoListHasAConsistentOrder(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.run("list", "std")
+	first := tg.getStdout()
+	tg.run("list", "std")
+	if first != tg.getStdout() {
+		t.Error("go list std ordering is inconsistent")
+	}
+}
+
+func TestGoListStdDoesNotIncludeCommands(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.run("list", "std")
+	tg.grepStdoutNot("cmd/", "go list std shows commands")
+}
+
+func TestGoListCmdOnlyShowsCommands(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.run("list", "cmd")
+	out := strings.TrimSpace(tg.getStdout())
+	for _, line := range strings.Split(out, "\n") {
+		if strings.Index(line, "cmd/") == -1 {
+			t.Error("go list cmd shows non-commands")
+			break
+		}
+	}
+}
+
+// Issue 4096. Validate the output of unsuccessful go install foo/quxx.
+func TestUnsuccessfulGoInstallShouldMentionMissingPackage(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.runFail("install", "foo/quxx")
+	if tg.grepCountBoth(`cannot find package "foo/quxx" in any of`) != 1 {
+		t.Error(`go install foo/quxx expected error: .*cannot find package "foo/quxx" in any of`)
+	}
+}
+
+func TestGOROOTSearchFailureReporting(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.runFail("install", "foo/quxx")
+	if tg.grepCountBoth(regexp.QuoteMeta(filepath.Join("foo", "quxx"))+` \(from \$GOROOT\)$`) != 1 {
+		t.Error(`go install foo/quxx expected error: .*foo/quxx (from $GOROOT)`)
+	}
+}
+
+func TestMultipleGOPATHEntriesReportedSeparately(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	sep := string(filepath.ListSeparator)
+	tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata", "a")+sep+filepath.Join(tg.pwd(), "testdata", "b"))
+	tg.runFail("install", "foo/quxx")
+	if tg.grepCountBoth(`testdata[/\\].[/\\]src[/\\]foo[/\\]quxx`) != 2 {
+		t.Error(`go install foo/quxx expected error: .*testdata/a/src/foo/quxx (from $GOPATH)\n.*testdata/b/src/foo/quxx`)
+	}
+}
+
+// Test (from $GOPATH) annotation is reported for the first GOPATH entry,
+func TestMentionGOPATHInFirstGOPATHEntry(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	sep := string(filepath.ListSeparator)
+	tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata", "a")+sep+filepath.Join(tg.pwd(), "testdata", "b"))
+	tg.runFail("install", "foo/quxx")
+	if tg.grepCountBoth(regexp.QuoteMeta(filepath.Join("testdata", "a", "src", "foo", "quxx"))+` \(from \$GOPATH\)$`) != 1 {
+		t.Error(`go install foo/quxx expected error: .*testdata/a/src/foo/quxx (from $GOPATH)`)
+	}
+}
+
+// but not on the second.
+func TestMentionGOPATHNotOnSecondEntry(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	sep := string(filepath.ListSeparator)
+	tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata", "a")+sep+filepath.Join(tg.pwd(), "testdata", "b"))
+	tg.runFail("install", "foo/quxx")
+	if tg.grepCountBoth(regexp.QuoteMeta(filepath.Join("testdata", "b", "src", "foo", "quxx"))+`$`) != 1 {
+		t.Error(`go install foo/quxx expected error: .*testdata/b/src/foo/quxx`)
+	}
+}
+
+// Test missing GOPATH is reported.
+func TestMissingGOPATHIsReported(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.setenv("GOPATH", "")
+	tg.runFail("install", "foo/quxx")
+	if tg.grepCountBoth(`\(\$GOPATH not set\)$`) != 1 {
+		t.Error(`go install foo/quxx expected error: ($GOPATH not set)`)
+	}
+}
+
+// Issue 4186.  go get cannot be used to download packages to $GOROOT.
+// Test that without GOPATH set, go get should fail.
+func TestWithoutGOPATHGoGetFails(t *testing.T) {
+	testenv.MustHaveExternalNetwork(t)
+
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.parallel()
+	tg.tempDir("src")
+	tg.setenv("GOPATH", "")
+	tg.setenv("GOROOT", tg.path("."))
+	tg.runFail("get", "-d", "golang.org/x/codereview/cmd/hgpatch")
+}
+
+// Test that with GOPATH=$GOROOT, go get should fail.
+func TestWithGOPATHEqualsGOROOTGoGetFails(t *testing.T) {
+	testenv.MustHaveExternalNetwork(t)
+
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.parallel()
+	tg.tempDir("src")
+	tg.setenv("GOPATH", tg.path("."))
+	tg.setenv("GOROOT", tg.path("."))
+	tg.runFail("get", "-d", "golang.org/x/codereview/cmd/hgpatch")
+}
+
+func TestLdflagsArgumentsWithSpacesIssue3941(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.parallel()
+	tg.tempFile("main.go", `package main
+		var extern string
+		func main() {
+			println(extern)
+		}`)
+	tg.run("run", "-ldflags", `-X main.extern "hello world"`, tg.path("main.go"))
+	tg.grepStderr("^hello world", `ldflags -X main.extern 'hello world' failed`)
+}
+
+func TestGoTestCpuprofileLeavesBinaryBehind(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.makeTempdir()
+	tg.cd(tg.path("."))
+	tg.run("test", "-cpuprofile", "errors.prof", "errors")
+	tg.wantExecutable("errors.test"+exeSuffix, "go test -cpuprofile did not create errors.test")
+}
+
+func TestGoTestCpuprofileDashOControlsBinaryLocation(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.makeTempdir()
+	tg.cd(tg.path("."))
+	tg.run("test", "-cpuprofile", "errors.prof", "-o", "myerrors.test"+exeSuffix, "errors")
+	tg.wantExecutable("myerrors.test"+exeSuffix, "go test -cpuprofile -o myerrors.test did not create myerrors.test")
+}
+
+func TestGoTestDashCDashOControlsBinaryLocation(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.parallel()
+	tg.makeTempdir()
+	tg.run("test", "-c", "-o", tg.path("myerrors.test"+exeSuffix), "errors")
+	tg.wantExecutable(tg.path("myerrors.test"+exeSuffix), "go test -c -o myerrors.test did not create myerrors.test")
+}
+
+func TestGoTestDashOWritesBinary(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.parallel()
+	tg.makeTempdir()
+	tg.run("test", "-o", tg.path("myerrors.test"+exeSuffix), "errors")
+	tg.wantExecutable(tg.path("myerrors.test"+exeSuffix), "go test -o myerrors.test did not create myerrors.test")
+}
+
+// Issue 4568.
+func TestSymlinksDoNotConfuseGoList(t *testing.T) {
+	switch runtime.GOOS {
+	case "plan9", "windows":
+		t.Skipf("skipping symlink test on %s", runtime.GOOS)
+	}
+
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.tempDir("src")
+	tg.must(os.Symlink(tg.path("."), tg.path("src/dir1")))
+	tg.tempFile("src/dir1/p.go", "package p")
+	tg.setenv("GOPATH", tg.path("."))
+	tg.cd(tg.path("src"))
+	tg.run("list", "-f", "{{.Root}}", "dir1")
+	if strings.TrimSpace(tg.getStdout()) != tg.path(".") {
+		t.Error("confused by symlinks")
+	}
+}
+
+// Issue 4515.
+func TestInstallWithTags(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.parallel()
+	tg.tempDir("bin")
+	tg.tempFile("src/example/a/main.go", `package main
+		func main() {}`)
+	tg.tempFile("src/example/b/main.go", `// +build mytag
+
+		package main
+		func main() {}`)
+	tg.setenv("GOPATH", tg.path("."))
+	tg.run("install", "-tags", "mytag", "example/a", "example/b")
+	tg.wantExecutable(tg.path("bin/a"+exeSuffix), "go install example/a example/b did not install binaries")
+	tg.wantExecutable(tg.path("bin/b"+exeSuffix), "go install example/a example/b did not install binaries")
+	tg.must(os.Remove(tg.path("bin/a" + exeSuffix)))
+	tg.must(os.Remove(tg.path("bin/b" + exeSuffix)))
+	tg.run("install", "-tags", "mytag", "example/...")
+	tg.wantExecutable(tg.path("bin/a"+exeSuffix), "go install example/... did not install binaries")
+	tg.wantExecutable(tg.path("bin/b"+exeSuffix), "go install example/... did not install binaries")
+	tg.run("list", "-tags", "mytag", "example/b...")
+	if strings.TrimSpace(tg.getStdout()) != "example/b" {
+		t.Error("go list example/b did not find example/b")
+	}
+}
+
+// Issue 4773
+func TestCaseCollisions(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.parallel()
+	tg.tempDir("src/example/a/pkg")
+	tg.tempDir("src/example/a/Pkg")
+	tg.tempDir("src/example/b")
+	tg.setenv("GOPATH", tg.path("."))
+	tg.tempFile("src/example/a/a.go", `package p
+		import (
+			_ "example/a/pkg"
+			_ "example/a/Pkg"
+		)`)
+	tg.tempFile("src/example/a/pkg/pkg.go", `package pkg`)
+	tg.tempFile("src/example/a/Pkg/pkg.go", `package pkg`)
+	tg.runFail("list", "example/a")
+	tg.grepStderr("case-insensitive import collision", "go list example/a did not report import collision")
+	tg.tempFile("src/example/b/file.go", `package b`)
+	tg.tempFile("src/example/b/FILE.go", `package b`)
+	f, err := os.Open(tg.path("src/example/b"))
+	tg.must(err)
+	names, err := f.Readdirnames(0)
+	tg.must(err)
+	tg.check(f.Close())
+	args := []string{"list"}
+	if len(names) == 2 {
+		// case-sensitive file system, let directory read find both files
+		args = append(args, "example/b")
+	} else {
+		// case-insensitive file system, list files explicitly on command line
+		args = append(args, tg.path("src/example/b/file.go"), tg.path("src/example/b/FILE.go"))
+	}
+	tg.runFail(args...)
+	tg.grepStderr("case-insensitive file name collision", "go list example/b did not report file name collision")
+}
+
+// Issue 8181.
+func TestGoGetDashTIssue8181(t *testing.T) {
+	if testing.Short() {
+		t.Skip("skipping test that uses network in short mode")
+	}
+
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.parallel()
+	tg.makeTempdir()
+	tg.setenv("GOPATH", tg.path("."))
+	tg.run("get", "-v", "-t", "github.com/rsc/go-get-issue-8181/a", "github.com/rsc/go-get-issue-8181/b")
+	tg.run("list", "...")
+	tg.grepStdout("x/build/cmd/cl", "missing expected x/build/cmd/cl")
+}
+
+func TestIssue11307(t *testing.T) {
+	// go get -u was not working except in checkout directory
+	if testing.Short() {
+		t.Skip("skipping test that uses network in short mode")
+	}
+
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.parallel()
+	tg.makeTempdir()
+	tg.setenv("GOPATH", tg.path("."))
+	tg.run("get", "github.com/rsc/go-get-issue-11307")
+	tg.run("get", "-u", "github.com/rsc/go-get-issue-11307") // was failing
+}
+
+func TestShadowingLogic(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	pwd := tg.pwd()
+	sep := string(filepath.ListSeparator)
+	tg.setenv("GOPATH", filepath.Join(pwd, "testdata", "shadow", "root1")+sep+filepath.Join(pwd, "testdata", "shadow", "root2"))
+
+	// The math in root1 is not "math" because the standard math is.
+	tg.run("list", "-f", "({{.ImportPath}}) ({{.ConflictDir}})", "./testdata/shadow/root1/src/math")
+	pwdForwardSlash := strings.Replace(pwd, string(os.PathSeparator), "/", -1)
+	if !strings.HasPrefix(pwdForwardSlash, "/") {
+		pwdForwardSlash = "/" + pwdForwardSlash
+	}
+	// The output will have makeImportValid applies, but we only
+	// bother to deal with characters we might reasonably see.
+	pwdForwardSlash = strings.Replace(pwdForwardSlash, ":", "_", -1)
+	want := "(_" + pwdForwardSlash + "/testdata/shadow/root1/src/math) (" + filepath.Join(runtime.GOROOT(), "src", "math") + ")"
+	if strings.TrimSpace(tg.getStdout()) != want {
+		t.Error("shadowed math is not shadowed; looking for", want)
+	}
+
+	// The foo in root1 is "foo".
+	tg.run("list", "-f", "({{.ImportPath}}) ({{.ConflictDir}})", "./testdata/shadow/root1/src/foo")
+	if strings.TrimSpace(tg.getStdout()) != "(foo) ()" {
+		t.Error("unshadowed foo is shadowed")
+	}
+
+	// The foo in root2 is not "foo" because the foo in root1 got there first.
+	tg.run("list", "-f", "({{.ImportPath}}) ({{.ConflictDir}})", "./testdata/shadow/root2/src/foo")
+	want = "(_" + pwdForwardSlash + "/testdata/shadow/root2/src/foo) (" + filepath.Join(pwd, "testdata", "shadow", "root1", "src", "foo") + ")"
+	if strings.TrimSpace(tg.getStdout()) != want {
+		t.Error("shadowed foo is not shadowed; looking for", want)
+	}
+
+	// The error for go install should mention the conflicting directory.
+	tg.runFail("install", "./testdata/shadow/root2/src/foo")
+	want = "go install: no install location for " + filepath.Join(pwd, "testdata", "shadow", "root2", "src", "foo") + ": hidden by " + filepath.Join(pwd, "testdata", "shadow", "root1", "src", "foo")
+	if strings.TrimSpace(tg.getStderr()) != want {
+		t.Error("wrong shadowed install error; looking for", want)
+	}
+}
+
+// Only succeeds if source order is preserved.
+func TestSourceFileNameOrderPreserved(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.run("test", "testdata/example1_test.go", "testdata/example2_test.go")
+}
+
+// Check that coverage analysis works at all.
+// Don't worry about the exact numbers but require not 0.0%.
+func checkCoverage(tg *testgoData, data string) {
+	if regexp.MustCompile(`[^0-9]0\.0%`).MatchString(data) {
+		tg.t.Error("some coverage results are 0.0%")
+	}
+	tg.t.Log(data)
+}
+
+func TestCoverageRuns(t *testing.T) {
+	if testing.Short() {
+		t.Skip("don't build libraries for coverage in short mode")
+	}
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.run("test", "-short", "-coverpkg=strings", "strings", "regexp")
+	data := tg.getStdout() + tg.getStderr()
+	tg.run("test", "-short", "-cover", "strings", "math", "regexp")
+	data += tg.getStdout() + tg.getStderr()
+	checkCoverage(tg, data)
+}
+
+// Check that coverage analysis uses set mode.
+func TestCoverageUsesSetMode(t *testing.T) {
+	if testing.Short() {
+		t.Skip("don't build libraries for coverage in short mode")
+	}
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.creatingTemp("testdata/cover.out")
+	tg.run("test", "-short", "-cover", "encoding/binary", "-coverprofile=testdata/cover.out")
+	data := tg.getStdout() + tg.getStderr()
+	if out, err := ioutil.ReadFile("testdata/cover.out"); err != nil {
+		t.Error(err)
+	} else {
+		if !bytes.Contains(out, []byte("mode: set")) {
+			t.Error("missing mode: set")
+		}
+	}
+	checkCoverage(tg, data)
+}
+
+func TestCoverageUsesAtomicModeForRace(t *testing.T) {
+	if testing.Short() {
+		t.Skip("don't build libraries for coverage in short mode")
+	}
+	if !canRace {
+		t.Skip("skipping because race detector not supported")
+	}
+
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.creatingTemp("testdata/cover.out")
+	tg.run("test", "-short", "-race", "-cover", "encoding/binary", "-coverprofile=testdata/cover.out")
+	data := tg.getStdout() + tg.getStderr()
+	if out, err := ioutil.ReadFile("testdata/cover.out"); err != nil {
+		t.Error(err)
+	} else {
+		if !bytes.Contains(out, []byte("mode: atomic")) {
+			t.Error("missing mode: atomic")
+		}
+	}
+	checkCoverage(tg, data)
+}
+
+func TestCoverageUsesActualSettingToOverrideEvenForRace(t *testing.T) {
+	if testing.Short() {
+		t.Skip("don't build libraries for coverage in short mode")
+	}
+	if !canRace {
+		t.Skip("skipping because race detector not supported")
+	}
+
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.creatingTemp("testdata/cover.out")
+	tg.run("test", "-short", "-race", "-cover", "encoding/binary", "-covermode=count", "-coverprofile=testdata/cover.out")
+	data := tg.getStdout() + tg.getStderr()
+	if out, err := ioutil.ReadFile("testdata/cover.out"); err != nil {
+		t.Error(err)
+	} else {
+		if !bytes.Contains(out, []byte("mode: count")) {
+			t.Error("missing mode: count")
+		}
+	}
+	checkCoverage(tg, data)
+}
+
+func TestCoverageWithCgo(t *testing.T) {
+	if !canCgo {
+		t.Skip("skipping because cgo not enabled")
+	}
+
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.run("test", "-short", "-cover", "./testdata/cgocover")
+	data := tg.getStdout() + tg.getStderr()
+	checkCoverage(tg, data)
+}
+
+func TestCgoDependsOnSyscall(t *testing.T) {
+	if testing.Short() {
+		t.Skip("skipping test that removes $GOROOT/pkg/*_race in short mode")
+	}
+	if !canCgo {
+		t.Skip("skipping because cgo not enabled")
+	}
+	if !canRace {
+		t.Skip("skipping because race detector not supported")
+	}
+
+	tg := testgo(t)
+	defer tg.cleanup()
+	files, err := filepath.Glob(filepath.Join(runtime.GOROOT(), "pkg", "*_race"))
+	tg.must(err)
+	for _, file := range files {
+		tg.check(os.RemoveAll(file))
+	}
+	tg.tempFile("src/foo/foo.go", `
+		package foo
+		//#include <stdio.h>
+		import "C"`)
+	tg.setenv("GOPATH", tg.path("."))
+	tg.run("build", "-race", "foo")
+}
+
+func TestCgoShowsFullPathNames(t *testing.T) {
+	if !canCgo {
+		t.Skip("skipping because cgo not enabled")
+	}
+
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.parallel()
+	tg.tempFile("src/x/y/dirname/foo.go", `
+		package foo
+		import "C"
+		func f() {`)
+	tg.setenv("GOPATH", tg.path("."))
+	tg.runFail("build", "x/y/dirname")
+	tg.grepBoth("x/y/dirname", "error did not use full path")
+}
+
+func TestCgoHandlesWlORIGIN(t *testing.T) {
+	if !canCgo {
+		t.Skip("skipping because cgo not enabled")
+	}
+
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.parallel()
+	tg.tempFile("src/origin/origin.go", `package origin
+		// #cgo !darwin LDFLAGS: -Wl,-rpath -Wl,$ORIGIN
+		// void f(void) {}
+		import "C"
+		func f() { C.f() }`)
+	tg.setenv("GOPATH", tg.path("."))
+	tg.run("build", "origin")
+}
+
+// "go test -c -test.bench=XXX errors" should not hang
+func TestIssue6480(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.makeTempdir()
+	tg.cd(tg.path("."))
+	tg.run("test", "-c", "-test.bench=XXX", "errors")
+}
+
+// cmd/cgo: undefined reference when linking a C-library using gccgo
+func TestIssue7573(t *testing.T) {
+	if _, err := exec.LookPath("gccgo"); err != nil {
+		t.Skip("skipping because no gccgo compiler found")
+	}
+
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.parallel()
+	tg.tempFile("src/cgoref/cgoref.go", `
+package main
+// #cgo LDFLAGS: -L alibpath -lalib
+// void f(void) {}
+import "C"
+
+func main() { C.f() }`)
+	tg.setenv("GOPATH", tg.path("."))
+	tg.run("build", "-n", "-compiler", "gccgo", "cgoref")
+	tg.grepStderr(`gccgo.*\-L alibpath \-lalib`, `no Go-inline "#cgo LDFLAGS:" ("-L alibpath -lalib") passed to gccgo linking stage`)
+}
+
+func TestListTemplateCanUseContextFunction(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.run("list", "-f", "GOARCH: {{context.GOARCH}}")
+}
+
+// cmd/go: "go test" should fail if package does not build
+func TestIssue7108(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+	tg.runFail("test", "notest")
+}
+
+// cmd/go: go test -a foo does not rebuild regexp.
+func TestIssue6844(t *testing.T) {
+	if testing.Short() {
+		t.Skip("don't rebuild the standard libary in short mode")
+	}
+
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.creatingTemp("deps.test" + exeSuffix)
+	tg.run("test", "-x", "-a", "-c", "testdata/dep_test.go")
+	tg.grepStderr("regexp", "go test -x -a -c testdata/dep-test.go did not rebuild regexp")
+}
+
+func TestBuildDashIInstallsDependencies(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.parallel()
+	tg.tempFile("src/x/y/foo/foo.go", `package foo
+		func F() {}`)
+	tg.tempFile("src/x/y/bar/bar.go", `package bar
+		import "x/y/foo"
+		func F() { foo.F() }`)
+	tg.setenv("GOPATH", tg.path("."))
+
+	checkbar := func(desc string) {
+		tg.sleep()
+		tg.must(os.Chtimes(tg.path("src/x/y/foo/foo.go"), time.Now(), time.Now()))
+		tg.sleep()
+		tg.run("build", "-v", "-i", "x/y/bar")
+		tg.grepBoth("x/y/foo", "first build -i "+desc+" did not build x/y/foo")
+		tg.run("build", "-v", "-i", "x/y/bar")
+		tg.grepBothNot("x/y/foo", "second build -i "+desc+" built x/y/foo")
+	}
+	checkbar("pkg")
+	tg.creatingTemp("bar" + exeSuffix)
+	tg.tempFile("src/x/y/bar/bar.go", `package main
+		import "x/y/foo"
+		func main() { foo.F() }`)
+	checkbar("cmd")
+}
+
+func TestGoBuildInTestOnlyDirectoryFailsWithAGoodError(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.runFail("build", "./testdata/testonly")
+	tg.grepStderr("no buildable Go", "go build ./testdata/testonly produced unexpected error")
+}
+
+func TestGoTestDetectsTestOnlyImportCycles(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+	tg.runFail("test", "-c", "testcycle/p3")
+	tg.grepStderr("import cycle not allowed in test", "go test testcycle/p3 produced unexpected error")
+
+	tg.runFail("test", "-c", "testcycle/q1")
+	tg.grepStderr("import cycle not allowed in test", "go test testcycle/q1 produced unexpected error")
+}
+
+func TestGoTestFooTestWorks(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.run("test", "testdata/standalone_test.go")
+}
+
+func TestGoTestXtestonlyWorks(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+	tg.run("clean", "-i", "xtestonly")
+	tg.run("test", "xtestonly")
+}
+
+func TestGoTestBuildsAnXtestContainingOnlyNonRunnableExamples(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.run("test", "-v", "./testdata/norunexample")
+	tg.grepStdout("File with non-runnable example was built.", "file with non-runnable example was not built")
+}
+
+func TestGoGenerateHandlesSimpleCommand(t *testing.T) {
+	if runtime.GOOS == "windows" {
+		t.Skip("skipping because windows has no echo command")
+	}
+
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.run("generate", "./testdata/generate/test1.go")
+	tg.grepStdout("Success", "go generate ./testdata/generate/test1.go generated wrong output")
+}
+
+func TestGoGenerateHandlesCommandAlias(t *testing.T) {
+	if runtime.GOOS == "windows" {
+		t.Skip("skipping because windows has no echo command")
+	}
+
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.run("generate", "./testdata/generate/test2.go")
+	tg.grepStdout("Now is the time for all good men", "go generate ./testdata/generate/test2.go generated wrong output")
+}
+
+func TestGoGenerateVariableSubstitution(t *testing.T) {
+	if runtime.GOOS == "windows" {
+		t.Skip("skipping because windows has no echo command")
+	}
+
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.run("generate", "./testdata/generate/test3.go")
+	tg.grepStdout(runtime.GOARCH+" test3.go:7 pabc xyzp/test3.go/123", "go generate ./testdata/generate/test3.go generated wrong output")
+}
+
+func TestGoGenerateRunFlag(t *testing.T) {
+	if runtime.GOOS == "windows" {
+		t.Skip("skipping because windows has no echo command")
+	}
+
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.run("generate", "-run", "y.s", "./testdata/generate/test4.go")
+	tg.grepStdout("yes", "go generate -run yes ./testdata/generate/test4.go did not select yes")
+	tg.grepStdoutNot("no", "go generate -run yes ./testdata/generate/test4.go selected no")
+}
+
+func TestGoGetCustomDomainWildcard(t *testing.T) {
+	testenv.MustHaveExternalNetwork(t)
+
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.makeTempdir()
+	tg.setenv("GOPATH", tg.path("."))
+	tg.run("get", "-u", "rsc.io/pdf/...")
+	tg.wantExecutable(tg.path("bin/pdfpasswd"+exeSuffix), "did not build rsc/io/pdf/pdfpasswd")
+}
+
+func TestGoGetInternalWildcard(t *testing.T) {
+	testenv.MustHaveExternalNetwork(t)
+
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.makeTempdir()
+	tg.setenv("GOPATH", tg.path("."))
+	// used to fail with errors about internal packages
+	tg.run("get", "github.com/rsc/go-get-issue-11960/...")
+}
+
+func TestGoVetWithExternalTests(t *testing.T) {
+	testenv.MustHaveExternalNetwork(t)
+
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.makeTempdir()
+	tg.setenv("GOPATH", tg.path("."))
+	tg.run("get", "golang.org/x/tools/cmd/vet")
+	tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+	tg.runFail("vet", "vetpkg")
+	tg.grepBoth("missing argument for Printf", "go vet vetpkg did not find missing argument for Printf")
+}
+
+func TestGoVetWithTags(t *testing.T) {
+	testenv.MustHaveExternalNetwork(t)
+
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.makeTempdir()
+	tg.setenv("GOPATH", tg.path("."))
+	tg.run("get", "golang.org/x/tools/cmd/vet")
+	tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+	tg.runFail("vet", "-tags", "tagtest", "vetpkg")
+	tg.grepBoth(`c\.go.*wrong number of args for format`, "go get vetpkg did not run scan tagged file")
+}
+
+// Issue 9767.
+func TestGoGetRscIoToolstash(t *testing.T) {
+	testenv.MustHaveExternalNetwork(t)
+
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.tempDir("src/rsc.io")
+	tg.setenv("GOPATH", tg.path("."))
+	tg.cd(tg.path("src/rsc.io"))
+	tg.run("get", "./toolstash")
+}
+
+// Test that you can not import a main package.
+func TestIssue4210(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.tempFile("src/x/main.go", `package main
+		var X int
+		func main() {}`)
+	tg.tempFile("src/y/main.go", `package main
+		import "fmt"
+		import xmain "x"
+		func main() {
+			fmt.Println(xmain.X)
+		}`)
+	tg.setenv("GOPATH", tg.path("."))
+	tg.runFail("build", "y")
+	tg.grepBoth("is a program", `did not find expected error message ("is a program")`)
+}
+
+func TestGoGetInsecure(t *testing.T) {
+	testenv.MustHaveExternalNetwork(t)
+
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.makeTempdir()
+	tg.setenv("GOPATH", tg.path("."))
+	tg.failSSH()
+
+	const repo = "wh3rd.net/git.git"
+
+	// Try go get -d of HTTP-only repo (should fail).
+	tg.runFail("get", "-d", repo)
+
+	// Try again with -insecure (should succeed).
+	tg.run("get", "-d", "-insecure", repo)
+
+	// Try updating without -insecure (should fail).
+	tg.runFail("get", "-d", "-u", "-f", repo)
+}
+
+func TestGoGetUpdateInsecure(t *testing.T) {
+	testenv.MustHaveExternalNetwork(t)
+
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.makeTempdir()
+	tg.setenv("GOPATH", tg.path("."))
+
+	const repo = "github.com/golang/example"
+
+	// Clone the repo via HTTP manually.
+	cmd := exec.Command("git", "clone", "-q", "http://"+repo, tg.path("src/"+repo))
+	if out, err := cmd.CombinedOutput(); err != nil {
+		t.Fatalf("cloning %v repo: %v\n%s", repo, err, out)
+	}
+
+	// Update without -insecure should fail.
+	// Update with -insecure should succeed.
+	// We need -f to ignore import comments.
+	const pkg = repo + "/hello"
+	tg.runFail("get", "-d", "-u", "-f", pkg)
+	tg.run("get", "-d", "-u", "-f", "-insecure", pkg)
+}
+
+func TestGoGetInsecureCustomDomain(t *testing.T) {
+	testenv.MustHaveExternalNetwork(t)
+
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.makeTempdir()
+	tg.setenv("GOPATH", tg.path("."))
+
+	const repo = "wh3rd.net/repo"
+	tg.runFail("get", "-d", repo)
+	tg.run("get", "-d", "-insecure", repo)
+}
+
+func TestIssue10193(t *testing.T) {
+	testenv.MustHaveExternalNetwork(t)
+
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.parallel()
+	tg.tempDir("src")
+	tg.setenv("GOPATH", tg.path("."))
+	tg.runFail("get", "code.google.com/p/rsc/pdf")
+	tg.grepStderr("is shutting down", "missed warning about code.google.com")
+}
+
+func TestGoRunDirs(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.cd("testdata/rundir")
+	tg.runFail("run", "x.go", "sub/sub.go")
+	tg.grepStderr("named files must all be in one directory; have ./ and sub/", "wrong output")
+	tg.runFail("run", "sub/sub.go", "x.go")
+	tg.grepStderr("named files must all be in one directory; have sub/ and ./", "wrong output")
+}
+
+func TestGoInstallPkgdir(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.makeTempdir()
+	pkg := tg.path(".")
+	tg.run("install", "-pkgdir", pkg, "errors")
+	_, err := os.Stat(filepath.Join(pkg, "errors.a"))
+	tg.must(err)
+	_, err = os.Stat(filepath.Join(pkg, "runtime.a"))
+	tg.must(err)
+}
+
+func TestGoTestRaceInstallCgo(t *testing.T) {
+	switch sys := runtime.GOOS + "/" + runtime.GOARCH; sys {
+	case "darwin/amd64", "freebsd/amd64", "linux/amd64", "windows/amd64":
+		// ok
+	default:
+		t.Skip("no race detector on %s", sys)
+	}
+
+	if !build.Default.CgoEnabled {
+		t.Skip("no race detector without cgo")
+	}
+
+	// golang.org/issue/10500.
+	// This used to install a race-enabled cgo.
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.run("tool", "-n", "cgo")
+	cgo := strings.TrimSpace(tg.stdout.String())
+	old, err := os.Stat(cgo)
+	tg.must(err)
+	tg.run("test", "-race", "-i", "runtime/race")
+	new, err := os.Stat(cgo)
+	tg.must(err)
+	if new.ModTime() != old.ModTime() {
+		t.Fatalf("go test -i runtime/race reinstalled cmd/cgo")
+	}
+}
+
+func TestGoTestImportErrorStack(t *testing.T) {
+	const out = `package testdep/p1 (test)
+	imports testdep/p2
+	imports testdep/p3: no buildable Go source files`
+
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+	tg.runFail("test", "testdep/p1")
+	if !strings.Contains(tg.stderr.String(), out) {
+		t.Fatal("did not give full import stack:\n\n%s", tg.stderr.String())
+	}
+}
+
+func TestGoGetUpdate(t *testing.T) {
+	// golang.org/issue/9224.
+	// The recursive updating was trying to walk to
+	// former dependencies, not current ones.
+
+	testenv.MustHaveExternalNetwork(t)
+
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.makeTempdir()
+	tg.setenv("GOPATH", tg.path("."))
+
+	rewind := func() {
+		tg.run("get", "github.com/rsc/go-get-issue-9224-cmd")
+		cmd := exec.Command("git", "reset", "--hard", "HEAD~")
+		cmd.Dir = tg.path("src/github.com/rsc/go-get-issue-9224-lib")
+		out, err := cmd.CombinedOutput()
+		if err != nil {
+			t.Fatalf("git: %v\n%s", err, out)
+		}
+	}
+
+	rewind()
+	tg.run("get", "-u", "github.com/rsc/go-get-issue-9224-cmd")
+
+	// Again with -d -u.
+	rewind()
+	tg.run("get", "-d", "-u", "github.com/rsc/go-get-issue-9224-cmd")
+}
+
+func TestGoGetDomainRoot(t *testing.T) {
+	// golang.org/issue/9357.
+	// go get foo.io (not foo.io/subdir) was not working consistently.
+
+	testenv.MustHaveExternalNetwork(t)
+
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.makeTempdir()
+	tg.setenv("GOPATH", tg.path("."))
+
+	// go-get-issue-9357.appspot.com is running
+	// the code at github.com/rsc/go-get-issue-9357,
+	// a trivial Go on App Engine app that serves a
+	// <meta> tag for the domain root.
+	tg.run("get", "-d", "go-get-issue-9357.appspot.com")
+	tg.run("get", "go-get-issue-9357.appspot.com")
+	tg.run("get", "-u", "go-get-issue-9357.appspot.com")
+
+	tg.must(os.RemoveAll(tg.path("src/go-get-issue-9357.appspot.com")))
+	tg.run("get", "go-get-issue-9357.appspot.com")
+
+	tg.must(os.RemoveAll(tg.path("src/go-get-issue-9357.appspot.com")))
+	tg.run("get", "-u", "go-get-issue-9357.appspot.com")
+}
+
+func TestGoInstallShadowedGOPATH(t *testing.T) {
+	// golang.org/issue/3652.
+	// go get foo.io (not foo.io/subdir) was not working consistently.
+
+	testenv.MustHaveExternalNetwork(t)
+
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.makeTempdir()
+	tg.setenv("GOPATH", tg.path("gopath1")+string(filepath.ListSeparator)+tg.path("gopath2"))
+
+	tg.tempDir("gopath1/src/test")
+	tg.tempDir("gopath2/src/test")
+	tg.tempFile("gopath2/src/test/main.go", "package main\nfunc main(){}\n")
+
+	tg.cd(tg.path("gopath2/src/test"))
+	tg.runFail("install")
+	tg.grepStderr("no install location for.*gopath2.src.test: hidden by .*gopath1.src.test", "missing error")
+}
+
+func TestIssue11709(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.tempFile("run.go", `
+		package main
+		import "os"
+		func main() {
+			if os.Getenv("TERM") != "" {
+				os.Exit(1)
+			}
+		}`)
+	tg.unsetenv("TERM")
+	tg.run("run", tg.path("run.go"))
+}
+
+func TestIssue12096(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.tempFile("test_test.go", `
+		package main
+		import ("os"; "testing")
+		func TestEnv(t *testing.T) {
+			if os.Getenv("TERM") != "" {
+				t.Fatal("TERM is set")
+			}
+		}`)
+	tg.unsetenv("TERM")
+	tg.run("test", tg.path("test_test.go"))
+}
+
+func TestGoBuildOutput(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+
+	tg.makeTempdir()
+	tg.cd(tg.path("."))
+
+	nonExeSuffix := ".exe"
+	if exeSuffix == ".exe" {
+		nonExeSuffix = ""
+	}
+
+	tg.tempFile("x.go", "package main\nfunc main(){}\n")
+	tg.run("build", "x.go")
+	tg.wantExecutable("x"+exeSuffix, "go build x.go did not write x"+exeSuffix)
+	tg.must(os.Remove(tg.path("x" + exeSuffix)))
+	tg.mustNotExist("x" + nonExeSuffix)
+
+	tg.run("build", "-o", "myprog", "x.go")
+	tg.mustNotExist("x")
+	tg.mustNotExist("x.exe")
+	tg.wantExecutable("myprog", "go build -o myprog x.go did not write myprog")
+	tg.mustNotExist("myprog.exe")
+
+	tg.tempFile("p.go", "package p\n")
+	tg.run("build", "p.go")
+	tg.mustNotExist("p")
+	tg.mustNotExist("p.a")
+	tg.mustNotExist("p.o")
+	tg.mustNotExist("p.exe")
+
+	tg.run("build", "-o", "p.a", "p.go")
+	tg.wantArchive("p.a")
+
+	tg.run("build", "cmd/gofmt")
+	tg.wantExecutable("gofmt"+exeSuffix, "go build cmd/gofmt did not write gofmt"+exeSuffix)
+	tg.must(os.Remove(tg.path("gofmt" + exeSuffix)))
+	tg.mustNotExist("gofmt" + nonExeSuffix)
+
+	tg.run("build", "-o", "mygofmt", "cmd/gofmt")
+	tg.wantExecutable("mygofmt", "go build -o mygofmt cmd/gofmt did not write mygofmt")
+	tg.mustNotExist("mygofmt.exe")
+	tg.mustNotExist("gofmt")
+	tg.mustNotExist("gofmt.exe")
+
+	tg.run("build", "sync/atomic")
+	tg.mustNotExist("atomic")
+	tg.mustNotExist("atomic.exe")
+
+	tg.run("build", "-o", "myatomic.a", "sync/atomic")
+	tg.wantArchive("myatomic.a")
+	tg.mustNotExist("atomic")
+	tg.mustNotExist("atomic.a")
+	tg.mustNotExist("atomic.exe")
+
+	tg.runFail("build", "-o", "whatever", "cmd/gofmt", "sync/atomic")
+	tg.grepStderr("multiple packages", "did not reject -o with multiple packages")
+}
+
+func TestGoBuildARM(t *testing.T) {
+	if testing.Short() {
+		t.Skip("skipping cross-compile in short mode")
+	}
+
+	tg := testgo(t)
+	defer tg.cleanup()
+
+	tg.makeTempdir()
+	tg.cd(tg.path("."))
+
+	tg.setenv("GOARCH", "arm")
+	tg.setenv("GOOS", "linux")
+	tg.setenv("GOARM", "5")
+	tg.tempFile("hello.go", `package main
+		func main() {}`)
+	tg.run("build", "hello.go")
+	tg.grepStderrNot("unable to find math.a", "did not build math.a correctly")
+}
diff --git a/src/cmd/go/help.go b/src/cmd/go/help.go
index c590fdb..5dff267 100644
--- a/src/cmd/go/help.go
+++ b/src/cmd/go/help.go
@@ -11,7 +11,7 @@ var helpC = &Command{
 There are two different ways to call between Go and C/C++ code.
 
 The first is the cgo tool, which is part of the Go distribution.  For
-information on how to use it see the cgo documentation (godoc cmd/cgo).
+information on how to use it see the cgo documentation (go doc cmd/cgo).
 
 The second is the SWIG program, which is a general tool for
 interfacing between languages.  For information on SWIG see
@@ -47,7 +47,7 @@ environment variable (see 'go help gopath').
 If no import paths are given, the action applies to the
 package in the current directory.
 
-There are three reserved names for paths that should not be used
+There are four reserved names for paths that should not be used
 for packages to be built with the go tool:
 
 - "main" denotes the top-level package in a stand-alone executable.
@@ -59,6 +59,9 @@ system.
 - "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
@@ -74,7 +77,7 @@ By convention, this is arranged by starting each path with a
 unique prefix that belongs to you.  For example, paths used
 internally at Google all begin with 'google', and paths
 denoting remote repositories begin with the path to the code,
-such as 'code.google.com/p/project'.
+such as 'github.com/user/repo'.
 
 As a special case, if the package list is a list of .go files from a
 single directory, the command is applied to a single synthesized
@@ -192,7 +195,7 @@ example.org/repo or repo.git.
 
 When a version control system supports multiple protocols,
 each is tried in turn when downloading.  For example, a Git
-download tries git://, then https://, then http://.
+download tries https://, then git+ssh://.
 
 If the import path is not a known code hosting site and also lacks a
 version control qualifier, the go tool attempts to fetch the import
@@ -208,6 +211,10 @@ root. It must be a prefix or an exact match of the package being
 fetched with "go get". If it's not an exact match, another http
 request is made at the prefix to verify the <meta> tags match.
 
+The meta tag should appear as early in the file as possible.
+In particular, it should appear before any raw JavaScript or CSS,
+to avoid confusing the go command's restricted parser.
+
 The vcs is one of "git", "hg", "svn", etc,
 
 The repo-root is the root of the version control system
@@ -217,10 +224,10 @@ For example,
 
 	import "example.org/pkg/foo"
 
-will result in the following request(s):
+will result in the following requests:
 
 	https://example.org/pkg/foo?go-get=1 (preferred)
-	http://example.org/pkg/foo?go-get=1  (fallback)
+	http://example.org/pkg/foo?go-get=1  (fallback, only with -insecure)
 
 If that page contains the meta tag
 
@@ -254,6 +261,11 @@ unless it is being referred to by that import path. In this way, import comments
 let package authors make sure the custom import path is used and not a
 direct path to the underlying code hosting site.
 
+If the vendoring experiment is enabled (see 'go help gopath'),
+then import path checking is disabled for code found within vendor trees.
+This makes it possible to copy code into alternate locations in vendor trees
+without needing to update import comments.
+
 See https://golang.org/s/go14customimport for details.
 	`,
 }
@@ -275,10 +287,10 @@ standard Go tree.
 
 Each directory listed in GOPATH must have a prescribed structure:
 
-The src/ directory holds source code.  The path below 'src'
+The src directory holds source code.  The path below src
 determines the import path or executable name.
 
-The pkg/ directory holds installed package objects.
+The pkg directory holds installed package objects.
 As in the Go tree, each target operating system and
 architecture pair has its own subdirectory of pkg
 (pkg/GOOS_GOARCH).
@@ -287,11 +299,11 @@ If DIR is a directory listed in the GOPATH, a package with
 source in DIR/src/foo/bar can be imported as "foo/bar" and
 has its compiled form installed to "DIR/pkg/GOOS_GOARCH/foo/bar.a".
 
-The bin/ directory holds compiled commands.
+The bin directory holds compiled commands.
 Each command is named for its source directory, but only
 the final element, not the entire path.  That is, the
 command with source in DIR/src/foo/quux is installed into
-DIR/bin/quux, not DIR/bin/foo/quux.  The foo/ is stripped
+DIR/bin/quux, not DIR/bin/foo/quux.  The "foo/" prefix is stripped
 so that you can add DIR/bin to your PATH to get at the
 installed commands.  If the GOBIN environment variable is
 set, commands are installed to the directory it names instead
@@ -318,6 +330,168 @@ Here's an example directory layout:
 Go searches each directory listed in GOPATH to find source code,
 but new packages are always downloaded into the first directory
 in the list.
+
+See https://golang.org/doc/code.html for an example.
+
+Internal Directories
+
+Code in or below a directory named "internal" is importable only
+by code in the directory tree rooted at the parent of "internal".
+Here's an extended version of the directory layout above:
+
+    /home/user/gocode/
+        src/
+            crash/
+                bang/              (go code in package bang)
+                    b.go
+            foo/                   (go code in package foo)
+                f.go
+                bar/               (go code in package bar)
+                    x.go
+                internal/
+                    baz/           (go code in package baz)
+                        z.go
+                quux/              (go code in package main)
+                    y.go
+
+
+The code in z.go is imported as "foo/internal/baz", but that
+import statement can only appear in source files in the subtree
+rooted at foo. The source files foo/f.go, foo/bar/x.go, and
+foo/quux/y.go can all import "foo/internal/baz", but the source file
+crash/bang/b.go cannot.
+
+See https://golang.org/s/go14internal for details.
+
+Vendor Directories
+
+Go 1.5 includes experimental support for using local copies
+of external dependencies to satisfy imports of those dependencies,
+often referred to as vendoring. Setting the environment variable
+GO15VENDOREXPERIMENT=1 enables that experimental support.
+
+When the vendor experiment is enabled,
+code below a directory named "vendor" is importable only
+by code in the directory tree rooted at the parent of "vendor",
+and only using an import path that omits the prefix up to and
+including the vendor element.
+
+Here's the example from the previous section,
+but with the "internal" directory renamed to "vendor"
+and a new foo/vendor/crash/bang directory added:
+
+    /home/user/gocode/
+        src/
+            crash/
+                bang/              (go code in package bang)
+                    b.go
+            foo/                   (go code in package foo)
+                f.go
+                bar/               (go code in package bar)
+                    x.go
+                vendor/
+                    crash/
+                        bang/      (go code in package bang)
+                            b.go
+                    baz/           (go code in package baz)
+                        z.go
+                quux/              (go code in package main)
+                    y.go
+
+The same visibility rules apply as for internal, but the code
+in z.go is imported as "baz", not as "foo/vendor/baz".
+
+Code in vendor directories deeper in the source tree shadows
+code in higher directories. Within the subtree rooted at foo, an import
+of "crash/bang" resolves to "foo/vendor/crash/bang", not the
+top-level "crash/bang".
+
+Code in vendor directories is not subject to import path
+checking (see 'go help importpath').
+
+When the vendor experiment is enabled, 'go get' checks out
+submodules when checking out or updating a git repository
+(see 'go help get').
+
+The vendoring semantics are an experiment, and they may change
+in future releases. Once settled, they will be on by default.
+
+See https://golang.org/s/go15vendor for details.
+	`,
+}
+
+var helpEnvironment = &Command{
+	UsageLine: "environment",
+	Short:     "environment variables",
+	Long: `
+
+The go command, and the tools it invokes, examine a few different
+environment variables. For many of these, you can see the default
+value of on your system by running 'go env NAME', where NAME is the
+name of the variable.
+
+General-purpose environment variables:
+
+	GCCGO
+		The gccgo command to run for 'go build -compiler=gccgo'.
+	GOARCH
+		The architecture, or processor, for which to compile code.
+		Examples are amd64, 386, arm, ppc64.
+	GOBIN
+		The directory where 'go install' will install a command.
+	GOOS
+		The operating system for which to compile code.
+		Examples are linux, darwin, windows, netbsd.
+	GOPATH
+		See 'go help gopath'.
+	GORACE
+		Options for the race detector.
+		See https://golang.org/doc/articles/race_detector.html.
+	GOROOT
+		The root of the go tree.
+
+Environment variables for use with cgo:
+
+	CC
+		The command to use to compile C code.
+	CGO_ENABLED
+		Whether the cgo command is supported.  Either 0 or 1.
+	CGO_CFLAGS
+		Flags that cgo will pass to the compiler when compiling
+		C code.
+	CGO_CPPFLAGS
+		Flags that cgo will pass to the compiler when compiling
+		C or C++ code.
+	CGO_CXXFLAGS
+		Flags that cgo will pass to the compiler when compiling
+		C++ code.
+	CGO_LDFLAGS
+		Flags that cgo will pass to the compiler when linking.
+	CXX
+		The command to use to compile C++ code.
+
+Architecture-specific environment variables:
+
+	GOARM
+		For GOARCH=arm, the ARM architecture for which to compile.
+		Valid values are 5, 6, 7.
+	GO386
+		For GOARCH=386, the floating point instruction set.
+		Valid values are 387, sse2.
+
+Special-purpose environment variables:
+
+	GOROOT_FINAL
+		The root of the installed Go tree, when it is
+		installed in a location other than where it is built.
+		File names in stack traces are rewritten from GOROOT to
+		GOROOT_FINAL.
+	GO15VENDOREXPERIMENT
+		Set to 1 to enable the Go 1.5 vendoring experiment.
+	GO_EXTLINK_ENABLED
+		Whether the linker should use external linking mode
+		when using -linkmode=auto with code that uses cgo.
+		Set to 0 to disable external linking mode, 1 to enable it.
 	`,
 }
 
@@ -333,10 +507,9 @@ the extension of the file name. These extensions are:
 		Go source files.
 	.c, .h
 		C source files.
-		If the package uses cgo, these will be compiled with the
-		OS-native compiler (typically gcc); otherwise they will be
-		compiled with the Go-specific support compiler,
-		5c, 6c, or 8c, etc. as appropriate.
+		If the package uses cgo or SWIG, these will be compiled with the
+		OS-native compiler (typically gcc); otherwise they will
+		trigger an error.
 	.cc, .cpp, .cxx, .hh, .hpp, .hxx
 		C++ source files. Only useful with cgo or SWIG, and always
 		compiled with the OS-native compiler.
@@ -345,10 +518,9 @@ the extension of the file name. These extensions are:
 		compiled with the OS-native compiler.
 	.s, .S
 		Assembler source files.
-		If the package uses cgo, these will be assembled with the
+		If the package uses cgo or SWIG, these will be assembled with the
 		OS-native assembler (typically gcc (sic)); otherwise they
-		will be assembled with the Go-specific support assembler,
-		5a, 6a, or 8a, etc., as appropriate.
+		will be assembled with the Go assembler.
 	.swig, .swigcxx
 		SWIG definition files.
 	.syso
@@ -360,3 +532,43 @@ at the first item in the file that is not a blank line or //-style
 line comment.
 	`,
 }
+
+var helpBuildmode = &Command{
+	UsageLine: "buildmode",
+	Short:     "description of build modes",
+	Long: `
+The 'go build' and 'go install' commands take a -buildmode argument which
+indicates which kind of object file is to be built. Currently supported values
+are:
+
+	-buildmode=archive
+		Build the listed non-main packages into .a files. Packages named
+		main are ignored.
+
+	-buildmode=c-archive
+		Build the listed main package, plus all packages it imports,
+		into a C archive file. The only callable symbols will be those
+		functions exported using a cgo //export comment. Requires
+		exactly one main package to be listed.
+
+	-buildmode=c-shared
+		Build the listed main packages, plus all packages that they
+		import, into C shared libraries. The only callable symbols will
+		be those functions exported using a cgo //export comment.
+		Non-main packages are ignored.
+
+	-buildmode=default
+		Listed main packages are built into executables and listed
+		non-main packages are built into .a files (the default
+		behavior).
+
+	-buildmode=shared
+		Combine all the listed non-main packages into a single shared
+		library that will be used when building with the -linkshared
+		option. Packages named main are ignored.
+
+	-buildmode=exe
+		Build the listed main packages and everything they import into
+		executables. Packages not named main are ignored.
+`,
+}
diff --git a/src/cmd/go/http.go b/src/cmd/go/http.go
index 107b820..7979c41 100644
--- a/src/cmd/go/http.go
+++ b/src/cmd/go/http.go
@@ -18,11 +18,25 @@ import (
 	"log"
 	"net/http"
 	"net/url"
+	"time"
 )
 
 // httpClient is the default HTTP client, but a variable so it can be
 // changed by tests, without modifying http.DefaultClient.
 var httpClient = http.DefaultClient
+var impatientHTTPClient = &http.Client{
+	Timeout: time.Duration(5 * time.Second),
+}
+
+type httpError struct {
+	status     string
+	statusCode int
+	url        string
+}
+
+func (e *httpError) Error() string {
+	return fmt.Sprintf("%s: %s", e.url, e.status)
+}
 
 // httpGET returns the data from an HTTP GET request for the given URL.
 func httpGET(url string) ([]byte, error) {
@@ -32,7 +46,9 @@ func httpGET(url string) ([]byte, error) {
 	}
 	defer resp.Body.Close()
 	if resp.StatusCode != 200 {
-		return nil, fmt.Errorf("%s: %s", url, resp.Status)
+		err := &httpError{status: resp.Status, statusCode: resp.StatusCode, url: url}
+
+		return nil, err
 	}
 	b, err := ioutil.ReadAll(resp.Body)
 	if err != nil {
@@ -43,7 +59,7 @@ func httpGET(url string) ([]byte, error) {
 
 // httpsOrHTTP returns the body of either the importPath's
 // https resource or, if unavailable, the http resource.
-func httpsOrHTTP(importPath string) (urlStr string, body io.ReadCloser, err error) {
+func httpsOrHTTP(importPath string, security securityMode) (urlStr string, body io.ReadCloser, err error) {
 	fetch := func(scheme string) (urlStr string, res *http.Response, err error) {
 		u, err := url.Parse(scheme + "://" + importPath)
 		if err != nil {
@@ -54,7 +70,11 @@ func httpsOrHTTP(importPath string) (urlStr string, body io.ReadCloser, err erro
 		if buildV {
 			log.Printf("Fetching %s", urlStr)
 		}
-		res, err = httpClient.Get(urlStr)
+		if security == insecure && scheme == "https" { // fail earlier
+			res, err = impatientHTTPClient.Get(urlStr)
+		} else {
+			res, err = httpClient.Get(urlStr)
+		}
 		return
 	}
 	closeBody := func(res *http.Response) {
@@ -72,7 +92,9 @@ func httpsOrHTTP(importPath string) (urlStr string, body io.ReadCloser, err erro
 			}
 		}
 		closeBody(res)
-		urlStr, res, err = fetch("http")
+		if security == insecure {
+			urlStr, res, err = fetch("http")
+		}
 	}
 	if err != nil {
 		closeBody(res)
diff --git a/src/cmd/go/list.go b/src/cmd/go/list.go
index fbf9616..35c7cc4 100644
--- a/src/cmd/go/list.go
+++ b/src/cmd/go/list.go
@@ -21,9 +21,10 @@ List lists the packages named by the import paths, one per line.
 
 The default output shows the package import path:
 
-    code.google.com/p/google-api-go-client/books/v1
-    code.google.com/p/goauth2/oauth
-    code.google.com/p/sqlite
+    bytes
+    encoding/json
+    github.com/gorilla/mux
+    golang.org/x/net/html
 
 The -f flag specifies an alternate format for the list, using the
 syntax of package template.  The default output is equivalent to -f
@@ -36,6 +37,7 @@ syntax of package template.  The default output is equivalent to -f
         Name          string // package name
         Doc           string // package documentation string
         Target        string // install path
+        Shlib         string // the shared library that contains this package (only set when -linkshared)
         Goroot        bool   // is this package in the Go root?
         Standard      bool   // is this package part of the standard Go library?
         Stale         bool   // would 'go install' do anything for this package?
@@ -126,6 +128,7 @@ var listJson = cmdList.Flag.Bool("json", false, "")
 var nl = []byte{'\n'}
 
 func runList(cmd *Command, args []string) {
+	buildModeInit()
 	out := newTrackingWriter(os.Stdout)
 	defer out.w.Flush()
 
@@ -173,6 +176,10 @@ func runList(cmd *Command, args []string) {
 	}
 
 	for _, pkg := range load(args) {
+		// Show vendor-expanded paths in listing
+		pkg.TestImports = pkg.vendored(pkg.TestImports)
+		pkg.XTestImports = pkg.vendored(pkg.XTestImports)
+
 		do(pkg)
 	}
 }
diff --git a/src/cmd/go/main.go b/src/cmd/go/main.go
index 9691f39..8ebde89 100644
--- a/src/cmd/go/main.go
+++ b/src/cmd/go/main.go
@@ -5,6 +5,7 @@
 package main
 
 import (
+	"bufio"
 	"bytes"
 	"flag"
 	"fmt"
@@ -76,6 +77,7 @@ func (c *Command) Runnable() bool {
 var commands = []*Command{
 	cmdBuild,
 	cmdClean,
+	cmdDoc,
 	cmdEnv,
 	cmdFix,
 	cmdFmt,
@@ -90,8 +92,10 @@ var commands = []*Command{
 	cmdVet,
 
 	helpC,
+	helpBuildmode,
 	helpFileType,
 	helpGopath,
+	helpEnvironment,
 	helpImportPath,
 	helpPackages,
 	helpTestflag,
@@ -109,6 +113,8 @@ func setExitStatus(n int) {
 	exitMu.Unlock()
 }
 
+var origEnv []string
+
 func main() {
 	_ = go11tag
 	flag.Usage = usage
@@ -139,7 +145,7 @@ func main() {
 				fmt.Fprintf(os.Stderr, "go: GOPATH entry cannot start with shell metacharacter '~': %q\n", p)
 				os.Exit(2)
 			}
-			if build.IsLocalImport(p) {
+			if !filepath.IsAbs(p) {
 				fmt.Fprintf(os.Stderr, "go: GOPATH entry is relative; must be absolute path: %q.\nRun 'go help gopath' for usage.\n", p)
 				os.Exit(2)
 			}
@@ -151,8 +157,20 @@ func main() {
 		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.
+	origEnv = os.Environ()
+	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.Run != nil {
+		if cmd.Name() == args[0] && cmd.Runnable() {
 			cmd.Flag.Usage = func() { cmd.Usage() }
 			if cmd.CustomFlags {
 				args = args[1:]
@@ -179,13 +197,13 @@ Usage:
 
 The commands are:
 {{range .}}{{if .Runnable}}
-    {{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
+	{{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
 
 Use "go help [command]" for more information about a command.
 
 Additional help topics:
 {{range .}}{{if not .Runnable}}
-    {{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
+	{{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
 
 Use "go help [topic]" for more information about that topic.
 
@@ -200,8 +218,8 @@ var documentationTemplate = `// Copyright 2011 The Go Authors.  All rights reser
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// DO NOT EDIT THIS FILE. GENERATED BY mkdoc.sh.
-// Edit the documentation in other files and rerun mkdoc.sh to generate this one.
+// DO NOT EDIT THIS FILE. GENERATED BY mkalldocs.sh.
+// Edit the documentation in other files and rerun mkalldocs.sh to generate this one.
 
 /*
 {{range .}}{{if .Short}}{{.Short | capitalize}}
@@ -217,12 +235,35 @@ var documentationTemplate = `// Copyright 2011 The Go Authors.  All rights reser
 package main
 `
 
+// An errWriter wraps a writer, recording whether a write error occurred.
+type errWriter struct {
+	w   io.Writer
+	err error
+}
+
+func (w *errWriter) Write(b []byte) (int, error) {
+	n, err := w.w.Write(b)
+	if err != nil {
+		w.err = err
+	}
+	return n, err
+}
+
 // tmpl executes the given template text on data, writing the result to w.
 func tmpl(w io.Writer, text string, data interface{}) {
 	t := template.New("top")
 	t.Funcs(template.FuncMap{"trim": strings.TrimSpace, "capitalize": capitalize})
 	template.Must(t.Parse(text))
-	if err := t.Execute(w, data); err != nil {
+	ew := &errWriter{w: w}
+	err := t.Execute(ew, data)
+	if ew.err != nil {
+		// I/O error writing. Ignore write on closed pipe.
+		if strings.Contains(ew.err.Error(), "pipe") {
+			os.Exit(1)
+		}
+		fatalf("writing output: %v", ew.err)
+	}
+	if err != nil {
 		panic(err)
 	}
 }
@@ -236,13 +277,17 @@ func capitalize(s string) string {
 }
 
 func printUsage(w io.Writer) {
-	tmpl(w, usageTemplate, commands)
+	bw := bufio.NewWriter(w)
+	tmpl(bw, usageTemplate, commands)
+	bw.Flush()
 }
 
 func usage() {
 	// special case "go test -h"
 	if len(os.Args) > 1 && os.Args[1] == "test" {
-		help([]string{"testflag"})
+		os.Stdout.WriteString(testUsage + "\n\n" +
+			strings.TrimSpace(testFlag1) + "\n\n" +
+			strings.TrimSpace(testFlag2) + "\n")
 		os.Exit(2)
 	}
 	printUsage(os.Stderr)
@@ -308,7 +353,7 @@ func importPathsNoDotExpansion(args []string) []string {
 		} else {
 			a = path.Clean(a)
 		}
-		if a == "all" || a == "std" {
+		if a == "all" || a == "std" || a == "cmd" {
 			out = append(out, allPackages(a)...)
 			continue
 		}
@@ -401,11 +446,10 @@ func runOut(dir string, cmdargs ...interface{}) []byte {
 // The environment is the current process's environment
 // but with an updated $PWD, so that an os.Getwd in the
 // child will be faster.
-func envForDir(dir string) []string {
-	env := os.Environ()
+func envForDir(dir string, base []string) []string {
 	// Internally we only use rooted paths, so dir is rooted.
 	// Even if dir is not rooted, no harm done.
-	return mergeEnvLists([]string{"PWD=" + dir}, env)
+	return mergeEnvLists([]string{"PWD=" + dir}, base)
 }
 
 // mergeEnvLists merges the two environment lists such that
@@ -458,6 +502,28 @@ func hasPathPrefix(s, prefix string) bool {
 	}
 }
 
+// hasFilePathPrefix reports whether the filesystem path s begins with the
+// elements in prefix.
+func hasFilePathPrefix(s, prefix string) bool {
+	sv := strings.ToUpper(filepath.VolumeName(s))
+	pv := strings.ToUpper(filepath.VolumeName(prefix))
+	s = s[len(sv):]
+	prefix = prefix[len(pv):]
+	switch {
+	default:
+		return false
+	case sv != pv:
+		return false
+	case len(s) == len(prefix):
+		return s == prefix
+	case len(s) > len(prefix):
+		if prefix != "" && prefix[len(prefix)-1] == filepath.Separator {
+			return strings.HasPrefix(s, prefix)
+		}
+		return s[len(prefix)] == filepath.Separator && s[:len(prefix)] == prefix
+	}
+}
+
 // treeCanMatchPattern(pattern)(name) reports whether
 // name or children of name can possibly match pattern.
 // Pattern is the same limited glob accepted by matchPattern.
@@ -475,8 +541,8 @@ func treeCanMatchPattern(pattern string) func(name string) bool {
 
 // allPackages returns all the packages that can be found
 // under the $GOPATH directories and $GOROOT matching pattern.
-// The pattern is either "all" (all packages), "std" (standard packages)
-// or a path including "...".
+// The pattern is either "all" (all packages), "std" (standard packages),
+// "cmd" (standard commands), or a path including "...".
 func allPackages(pattern string) []string {
 	pkgs := matchPackages(pattern)
 	if len(pkgs) == 0 {
@@ -488,7 +554,7 @@ func allPackages(pattern string) []string {
 func matchPackages(pattern string) []string {
 	match := func(string) bool { return true }
 	treeCanMatch := func(string) bool { return true }
-	if pattern != "all" && pattern != "std" {
+	if pattern != "all" && pattern != "std" && pattern != "cmd" {
 		match = matchPattern(pattern)
 		treeCanMatch = treeCanMatchPattern(pattern)
 	}
@@ -501,47 +567,16 @@ func matchPackages(pattern string) []string {
 	}
 	var pkgs []string
 
-	// Commands
-	cmd := filepath.Join(goroot, "src/cmd") + string(filepath.Separator)
-	filepath.Walk(cmd, func(path string, fi os.FileInfo, err error) error {
-		if err != nil || !fi.IsDir() || path == cmd {
-			return nil
-		}
-		name := path[len(cmd):]
-		if !treeCanMatch(name) {
-			return filepath.SkipDir
-		}
-		// Commands are all in cmd/, not in subdirectories.
-		if strings.Contains(name, string(filepath.Separator)) {
-			return filepath.SkipDir
-		}
-
-		// We use, e.g., cmd/gofmt as the pseudo import path for gofmt.
-		name = "cmd/" + name
-		if have[name] {
-			return nil
-		}
-		have[name] = true
-		if !match(name) {
-			return nil
-		}
-		_, err = buildContext.ImportDir(path, 0)
-		if err != nil {
-			if _, noGo := err.(*build.NoGoError); !noGo {
-				log.Print(err)
-			}
-			return nil
-		}
-		pkgs = append(pkgs, name)
-		return nil
-	})
-
 	for _, src := range buildContext.SrcDirs() {
-		if pattern == "std" && src != gorootSrc {
+		if (pattern == "std" || pattern == "cmd") && src != gorootSrc {
 			continue
 		}
 		src = filepath.Clean(src) + string(filepath.Separator)
-		filepath.Walk(src, func(path string, fi os.FileInfo, err error) error {
+		root := src
+		if pattern == "cmd" {
+			root += "cmd" + string(filepath.Separator)
+		}
+		filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
 			if err != nil || !fi.IsDir() || path == src {
 				return nil
 			}
@@ -553,7 +588,10 @@ func matchPackages(pattern string) []string {
 			}
 
 			name := filepath.ToSlash(path[len(src):])
-			if pattern == "std" && strings.Contains(name, ".") {
+			if pattern == "std" && (strings.Contains(name, ".") || name == "cmd") {
+				// The name "std" is only the standard library.
+				// If the name has a dot, assume it's a domain name for go get,
+				// and if the name is cmd, it's the root of the command tree.
 				return filepath.SkipDir
 			}
 			if !treeCanMatch(name) {
@@ -659,7 +697,7 @@ func stringList(args ...interface{}) []string {
 		case string:
 			x = append(x, arg)
 		default:
-			panic("stringList: invalid argument")
+			panic("stringList: invalid argument of type " + fmt.Sprintf("%T", arg))
 		}
 	}
 	return x
diff --git a/src/cmd/go/mkalldocs.sh b/src/cmd/go/mkalldocs.sh
new file mode 100755
index 0000000..74e3125
--- /dev/null
+++ b/src/cmd/go/mkalldocs.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+# 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.
+
+set -e
+
+go build -o go.latest
+./go.latest help documentation | sed 's; \*/; * /;' >alldocs.go
+gofmt -w alldocs.go
+rm go.latest
+
diff --git a/src/cmd/go/mkdoc.sh b/src/cmd/go/mkdoc.sh
deleted file mode 100755
index e15e880..0000000
--- a/src/cmd/go/mkdoc.sh
+++ /dev/null
@@ -1,9 +0,0 @@
-#!/bin/sh
-# 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.
-
-go install # So the next line will produce updated documentation.
-go help documentation | sed 's; \*/; * /;' >doc.go
-gofmt -w doc.go
-
diff --git a/src/cmd/go/note.go b/src/cmd/go/note.go
new file mode 100644
index 0000000..97e1865
--- /dev/null
+++ b/src/cmd/go/note.go
@@ -0,0 +1,116 @@
+// 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"
+	"debug/elf"
+	"encoding/binary"
+	"fmt"
+	"io"
+	"os"
+)
+
+func readAligned4(r io.Reader, sz int32) ([]byte, error) {
+	full := (sz + 3) &^ 3
+	data := make([]byte, full)
+	_, err := io.ReadFull(r, data)
+	if err != nil {
+		return nil, err
+	}
+	data = data[:sz]
+	return data, nil
+}
+
+func readELFNote(filename, name string, typ int32) ([]byte, error) {
+	f, err := elf.Open(filename)
+	if err != nil {
+		return nil, err
+	}
+	for _, sect := range f.Sections {
+		if sect.Type != elf.SHT_NOTE {
+			continue
+		}
+		r := sect.Open()
+		for {
+			var namesize, descsize, noteType int32
+			err = binary.Read(r, f.ByteOrder, &namesize)
+			if err != nil {
+				if err == io.EOF {
+					break
+				}
+				return nil, fmt.Errorf("read namesize failed: %v", err)
+			}
+			err = binary.Read(r, f.ByteOrder, &descsize)
+			if err != nil {
+				return nil, fmt.Errorf("read descsize failed: %v", err)
+			}
+			err = binary.Read(r, f.ByteOrder, &noteType)
+			if err != nil {
+				return nil, fmt.Errorf("read type failed: %v", err)
+			}
+			noteName, err := readAligned4(r, namesize)
+			if err != nil {
+				return nil, fmt.Errorf("read name failed: %v", err)
+			}
+			desc, err := readAligned4(r, descsize)
+			if err != nil {
+				return nil, fmt.Errorf("read desc failed: %v", err)
+			}
+			if name == string(noteName) && typ == noteType {
+				return desc, nil
+			}
+		}
+	}
+	return nil, nil
+}
+
+var elfGoNote = []byte("Go\x00\x00")
+
+// readELFGoBuildID the Go build ID string from an ELF binary.
+// The Go build ID is stored in a note described by an ELF PT_NOTE prog header.
+// The caller has already opened filename, to get f, and read the first 4 kB out, in data.
+func readELFGoBuildID(filename string, f *os.File, data []byte) (buildid string, err error) {
+	// Assume the note content is in the first 4 kB, already read.
+	// Rewrite the ELF header to set shnum to 0, so that we can pass
+	// the data to elf.NewFile and it will decode the Prog list but not
+	// try to read the section headers and the string table from disk.
+	// That's a waste of I/O when all we care about is the Prog list
+	// and the one ELF note.
+	switch elf.Class(data[elf.EI_CLASS]) {
+	case elf.ELFCLASS32:
+		data[48] = 0
+		data[49] = 0
+	case elf.ELFCLASS64:
+		data[60] = 0
+		data[61] = 0
+	}
+
+	const elfGoBuildIDTag = 4
+
+	ef, err := elf.NewFile(bytes.NewReader(data))
+	if err != nil {
+		return "", &os.PathError{Path: filename, Op: "parse", Err: err}
+	}
+	for _, p := range ef.Progs {
+		if p.Type != elf.PT_NOTE || p.Off >= uint64(len(data)) || p.Off+p.Filesz >= uint64(len(data)) || p.Filesz < 16 {
+			continue
+		}
+
+		note := data[p.Off : p.Off+p.Filesz]
+		nameSize := ef.ByteOrder.Uint32(note)
+		valSize := ef.ByteOrder.Uint32(note[4:])
+		tag := ef.ByteOrder.Uint32(note[8:])
+		name := note[12:16]
+		if nameSize != 4 || 16+valSize > uint32(len(note)) || tag != elfGoBuildIDTag || !bytes.Equal(name, elfGoNote) {
+			continue
+		}
+
+		return string(note[16 : 16+valSize]), nil
+	}
+
+	// No note. Treat as successful but build ID empty.
+	return "", nil
+}
diff --git a/src/cmd/go/note_test.go b/src/cmd/go/note_test.go
new file mode 100644
index 0000000..3d64451
--- /dev/null
+++ b/src/cmd/go/note_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.
+
+package main_test
+
+import (
+	main "cmd/go"
+	"runtime"
+	"testing"
+)
+
+func TestNoteReading(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.tempFile("hello.go", `package main; func main() { print("hello, world\n") }`)
+	const buildID = "TestNoteReading-Build-ID"
+	tg.run("build", "-ldflags", "-buildid="+buildID, "-o", tg.path("hello.exe"), tg.path("hello.go"))
+	id, err := main.ReadBuildIDFromBinary(tg.path("hello.exe"))
+	if err != nil {
+		t.Fatalf("reading build ID from hello binary: %v", err)
+	}
+	if id != buildID {
+		t.Fatalf("buildID in hello binary = %q, want %q", id, buildID)
+	}
+
+	if runtime.GOOS == "linux" && runtime.GOARCH == "ppc64le" {
+		t.Skipf("skipping - golang.org/issue/11184")
+	}
+
+	switch runtime.GOOS {
+	case "plan9":
+		// no external linking
+		t.Logf("no external linking - skipping linkmode=external test")
+
+	case "solaris":
+		t.Logf("skipping - golang.org/issue/12178")
+
+	default:
+		tg.run("build", "-ldflags", "-buildid="+buildID+" -linkmode=external", "-o", tg.path("hello.exe"), tg.path("hello.go"))
+		id, err := main.ReadBuildIDFromBinary(tg.path("hello.exe"))
+		if err != nil {
+			t.Fatalf("reading build ID from hello binary (linkmode=external): %v", err)
+		}
+		if id != buildID {
+			t.Fatalf("buildID in hello binary = %q, want %q (linkmode=external)", id, buildID)
+		}
+	}
+}
diff --git a/src/cmd/go/pkg.go b/src/cmd/go/pkg.go
index b71feb7..c481794 100644
--- a/src/cmd/go/pkg.go
+++ b/src/cmd/go/pkg.go
@@ -6,18 +6,21 @@ package main
 
 import (
 	"bytes"
+	"crypto/sha1"
 	"errors"
 	"fmt"
 	"go/build"
 	"go/scanner"
 	"go/token"
+	"io"
+	"io/ioutil"
 	"os"
 	pathpkg "path"
 	"path/filepath"
 	"runtime"
 	"sort"
+	"strconv"
 	"strings"
-	"time"
 	"unicode"
 )
 
@@ -32,6 +35,7 @@ type Package struct {
 	Name          string `json:",omitempty"` // package name
 	Doc           string `json:",omitempty"` // package documentation string
 	Target        string `json:",omitempty"` // install path
+	Shlib         string `json:",omitempty"` // the shared library that contains this package (only set when -linkshared)
 	Goroot        bool   `json:",omitempty"` // is this package found in the Go root?
 	Standard      bool   `json:",omitempty"` // is this package part of the standard Go library?
 	Stale         bool   `json:",omitempty"` // would 'go install' do anything for this package?
@@ -83,6 +87,7 @@ type Package struct {
 	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
@@ -92,6 +97,35 @@ type Package struct {
 	coverMode    string               // preprocess Go source files with the coverage tool in this mode
 	coverVars    map[string]*CoverVar // variables created by coverage analysis
 	omitDWARF    bool                 // tell linker not to write DWARF information
+	buildID      string               // expected build ID for generated package
+	gobinSubdir  bool                 // install target would be subdir of GOBIN
+}
+
+// vendored returns the vendor-resolved version of imports,
+// which should be p.TestImports or p.XTestImports, NOT p.Imports.
+// The imports in p.TestImports and p.XTestImports are not recursively
+// loaded during the initial load of p, so they list the imports found in
+// the source file, but most processing should be over the vendor-resolved
+// import paths. We do this resolution lazily both to avoid file system work
+// and because the eventual real load of the test imports (during 'go test')
+// can produce better error messages if it starts with the original paths.
+// The initial load of p loads all the non-test imports and rewrites
+// the vendored paths, so nothing should ever call p.vendored(p.Imports).
+func (p *Package) vendored(imports []string) []string {
+	if len(imports) > 0 && len(p.Imports) > 0 && &imports[0] == &p.Imports[0] {
+		panic("internal error: p.vendored(p.Imports) called")
+	}
+	seen := make(map[string]bool)
+	var all []string
+	for _, path := range imports {
+		path, _ = vendoredImportPath(p, path)
+		if !seen[path] {
+			seen[path] = true
+			all = append(all, path)
+		}
+	}
+	sort.Strings(all)
+	return all
 }
 
 // CoverVar holds the name of the generated coverage variables targeting the named file.
@@ -103,6 +137,13 @@ type CoverVar struct {
 func (p *Package) copyBuild(pp *build.Package) {
 	p.build = pp
 
+	if pp.PkgTargetRoot != "" && buildPkgdir != "" {
+		old := pp.PkgTargetRoot
+		pp.PkgRoot = buildPkgdir
+		pp.PkgTargetRoot = buildPkgdir
+		pp.PkgObj = filepath.Join(buildPkgdir, strings.TrimPrefix(pp.PkgObj, old))
+	}
+
 	p.Dir = pp.Dir
 	p.ImportPath = pp.ImportPath
 	p.ImportComment = pp.ImportComment
@@ -176,7 +217,7 @@ func (s *importStack) copy() []string {
 	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 {
@@ -209,6 +250,12 @@ func reloadPackage(arg string, stk *importStack) *Package {
 	return loadPackage(arg, stk)
 }
 
+// The Go 1.5 vendoring experiment is enabled by setting GO15VENDOREXPERIMENT=1.
+// The variable is obnoxiously long so that years from now when people find it in
+// their profiles and wonder what it does, there is some chance that a web search
+// might answer the question.
+var go15VendorExperiment = os.Getenv("GO15VENDOREXPERIMENT") == "1"
+
 // dirToImportPath returns the pseudo-import path we use for a package
 // outside the Go path.  It begins with _/ and then contains the full path
 // to the directory.  If the package lives in c:\home\gopher\my\pkg then
@@ -229,11 +276,29 @@ func makeImportValid(r rune) rune {
 	return r
 }
 
+// Mode flags for loadImport and download (in get.go).
+const (
+	// useVendor means that loadImport should do vendor expansion
+	// (provided the vendoring experiment is enabled).
+	// That is, useVendor means that the import path came from
+	// a source file and has not been vendor-expanded yet.
+	// Every import path should be loaded initially with useVendor,
+	// and then the expanded version (with the /vendor/ in it) gets
+	// recorded as the canonical import path. At that point, future loads
+	// of that package must not pass useVendor, because
+	// disallowVendor will reject direct use of paths containing /vendor/.
+	useVendor = 1 << iota
+
+	// getTestDeps is for download (part of "go get") and indicates
+	// that test dependencies should be fetched too.
+	getTestDeps
+)
+
 // loadImport scans the directory named by path, which must be an import path,
 // but possibly a local import path (an absolute file system path or one beginning
 // with ./ or ../).  A local relative path is interpreted relative to srcDir.
 // It returns a *Package describing the package found in that directory.
-func loadImport(path string, srcDir string, stk *importStack, importPos []token.Position) *Package {
+func loadImport(path, srcDir string, parent *Package, stk *importStack, importPos []token.Position, mode int) *Package {
 	stk.push(path)
 	defer stk.pop()
 
@@ -241,15 +306,27 @@ func loadImport(path string, srcDir string, stk *importStack, importPos []token.
 	// For a local import the identifier is the pseudo-import path
 	// we create from the full directory to the package.
 	// Otherwise it is the usual import path.
+	// For vendored imports, it is the expanded form.
 	importPath := path
+	origPath := path
 	isLocal := build.IsLocalImport(path)
+	var vendorSearch []string
 	if isLocal {
 		importPath = dirToImportPath(filepath.Join(srcDir, path))
+	} else if mode&useVendor != 0 {
+		path, vendorSearch = vendoredImportPath(parent, path)
+		importPath = path
 	}
+
 	if p := packageCache[importPath]; p != nil {
 		if perr := disallowInternal(srcDir, p, stk); perr != p {
 			return perr
 		}
+		if mode&useVendor != 0 {
+			if perr := disallowVendor(srcDir, origPath, p, stk); perr != p {
+				return perr
+			}
+		}
 		return reusePackage(p, stk)
 	}
 
@@ -265,11 +342,34 @@ func loadImport(path string, srcDir string, stk *importStack, importPos []token.
 	// TODO: After Go 1, decide when to pass build.AllowBinary here.
 	// See issue 3268 for mistakes to avoid.
 	bp, err := buildContext.Import(path, srcDir, build.ImportComment)
+
+	// If we got an error from go/build about package not found,
+	// it contains the directories from $GOROOT and $GOPATH that
+	// were searched. Add to that message the vendor directories
+	// that were searched.
+	if err != nil && len(vendorSearch) > 0 {
+		// NOTE(rsc): The direct text manipulation here is fairly awful,
+		// but it avoids defining new go/build API (an exported error type)
+		// late in the Go 1.5 release cycle. If this turns out to be a more general
+		// problem we could define a real error type when the decision can be
+		// considered more carefully.
+		text := err.Error()
+		if strings.Contains(text, "cannot find package \"") && strings.Contains(text, "\" in any of:\n\t") {
+			old := strings.SplitAfter(text, "\n")
+			lines := []string{old[0]}
+			for _, dir := range vendorSearch {
+				lines = append(lines, "\t"+dir+" (vendor tree)\n")
+			}
+			lines = append(lines, old[1:]...)
+			err = errors.New(strings.Join(lines, ""))
+		}
+	}
 	bp.ImportPath = importPath
 	if gobin != "" {
 		bp.BinDir = gobin
 	}
-	if err == nil && !isLocal && bp.ImportComment != "" && bp.ImportComment != path {
+	if err == nil && !isLocal && bp.ImportComment != "" && bp.ImportComment != path &&
+		(!go15VendorExperiment || (!strings.Contains(path, "/vendor/") && !strings.HasPrefix(path, "vendor/"))) {
 		err = fmt.Errorf("code in directory %s expects import %q", bp.Dir, bp.ImportComment)
 	}
 	p.load(stk, bp, err)
@@ -282,10 +382,83 @@ func loadImport(path string, srcDir string, stk *importStack, importPos []token.
 	if perr := disallowInternal(srcDir, p, stk); perr != p {
 		return perr
 	}
+	if mode&useVendor != 0 {
+		if perr := disallowVendor(srcDir, origPath, p, stk); perr != p {
+			return perr
+		}
+	}
 
 	return p
 }
 
+var isDirCache = map[string]bool{}
+
+func isDir(path string) bool {
+	result, ok := isDirCache[path]
+	if ok {
+		return result
+	}
+
+	fi, err := os.Stat(path)
+	result = err == nil && fi.IsDir()
+	isDirCache[path] = result
+	return result
+}
+
+// vendoredImportPath returns the expansion of path when it appears in parent.
+// If parent is x/y/z, then path might expand to x/y/z/vendor/path, x/y/vendor/path,
+// x/vendor/path, vendor/path, or else stay x/y/z if none of those exist.
+// vendoredImportPath returns the expanded path or, if no expansion is found, the original.
+// If no expansion is found, vendoredImportPath also returns a list of vendor directories
+// it searched along the way, to help prepare a useful error message should path turn
+// out not to exist.
+func vendoredImportPath(parent *Package, path string) (found string, searched []string) {
+	if parent == nil || parent.Root == "" || !go15VendorExperiment {
+		return path, nil
+	}
+	dir := filepath.Clean(parent.Dir)
+	root := filepath.Join(parent.Root, "src")
+	if !hasFilePathPrefix(dir, root) || len(dir) <= len(root) || dir[len(root)] != filepath.Separator {
+		fatalf("invalid vendoredImportPath: dir=%q root=%q separator=%q", dir, root, string(filepath.Separator))
+	}
+	vpath := "vendor/" + path
+	for i := len(dir); i >= len(root); i-- {
+		if i < len(dir) && dir[i] != filepath.Separator {
+			continue
+		}
+		// Note: checking for the vendor directory before checking
+		// for the vendor/path directory helps us hit the
+		// isDir cache more often. It also helps us prepare a more useful
+		// list of places we looked, to report when an import is not found.
+		if !isDir(filepath.Join(dir[:i], "vendor")) {
+			continue
+		}
+		targ := filepath.Join(dir[:i], vpath)
+		if isDir(targ) {
+			// We started with parent's dir c:\gopath\src\foo\bar\baz\quux\xyzzy.
+			// We know the import path for parent's dir.
+			// We chopped off some number of path elements and
+			// added vendor\path to produce c:\gopath\src\foo\bar\baz\vendor\path.
+			// Now we want to know the import path for that directory.
+			// Construct it by chopping the same number of path elements
+			// (actually the same number of bytes) from parent's import path
+			// and then append /vendor/path.
+			chopped := len(dir) - i
+			if chopped == len(parent.ImportPath)+1 {
+				// We walked up from c:\gopath\src\foo\bar
+				// and found c:\gopath\src\vendor\path.
+				// We chopped \foo\bar (length 8) but the import path is "foo/bar" (length 7).
+				// Use "vendor/path" without any prefix.
+				return vpath, nil
+			}
+			return parent.ImportPath[:len(parent.ImportPath)-chopped] + "/" + vpath, nil
+		}
+		// Note the existence of a vendor directory in case path is not found anywhere.
+		searched = append(searched, targ)
+	}
+	return path, searched
+}
+
 // reusePackage reuses package p to satisfy the import at the top
 // of the import stack stk.  If this use causes an import loop,
 // reusePackage updates p's error information to record the loop.
@@ -319,11 +492,9 @@ func disallowInternal(srcDir string, p *Package, stk *importStack) *Package {
 	// An import of a path containing the element “internal”
 	// is disallowed if the importing code is outside the tree
 	// rooted at the parent of the “internal” directory.
-	//
-	// ... For Go 1.4, we will implement the rule first for $GOROOT, but not $GOPATH.
 
-	// Only applies to $GOROOT.
-	if !p.Standard {
+	// There was an error loading the package; stop here.
+	if p.Error != nil {
 		return p
 	}
 
@@ -380,6 +551,105 @@ func findInternal(path string) (index int, ok bool) {
 	return 0, false
 }
 
+// disallowVendor checks that srcDir is allowed to import p as path.
+// If the import is allowed, disallowVendor returns the original package p.
+// If not, it returns a new package containing just an appropriate error.
+func disallowVendor(srcDir, path string, p *Package, stk *importStack) *Package {
+	if !go15VendorExperiment {
+		return p
+	}
+
+	// The stack includes p.ImportPath.
+	// If that's the only thing on the stack, we started
+	// with a name given on the command line, not an
+	// import. Anything listed on the command line is fine.
+	if len(*stk) == 1 {
+		return p
+	}
+
+	if perr := disallowVendorVisibility(srcDir, p, stk); perr != p {
+		return perr
+	}
+
+	// Paths like x/vendor/y must be imported as y, never as x/vendor/y.
+	if i, ok := findVendor(path); ok {
+		perr := *p
+		perr.Error = &PackageError{
+			ImportStack: stk.copy(),
+			Err:         "must be imported as " + path[i+len("vendor/"):],
+		}
+		perr.Incomplete = true
+		return &perr
+	}
+
+	return p
+}
+
+// disallowVendorVisibility checks that srcDir is allowed to import p.
+// The rules are the same as for /internal/ except that a path ending in /vendor
+// is not subject to the rules, only subdirectories of vendor.
+// This allows people to have packages and commands named vendor,
+// for maximal compatibility with existing source trees.
+func disallowVendorVisibility(srcDir string, p *Package, stk *importStack) *Package {
+	// The stack includes p.ImportPath.
+	// If that's the only thing on the stack, we started
+	// with a name given on the command line, not an
+	// import. Anything listed on the command line is fine.
+	if len(*stk) == 1 {
+		return p
+	}
+
+	// Check for "vendor" element.
+	i, ok := findVendor(p.ImportPath)
+	if !ok {
+		return p
+	}
+
+	// Vendor is present.
+	// Map import path back to directory corresponding to parent of vendor.
+	if i > 0 {
+		i-- // rewind over slash in ".../vendor"
+	}
+	truncateTo := i + len(p.Dir) - len(p.ImportPath)
+	if truncateTo < 0 || len(p.Dir) < truncateTo {
+		return p
+	}
+	parent := p.Dir[:truncateTo]
+	if hasPathPrefix(filepath.ToSlash(srcDir), filepath.ToSlash(parent)) {
+		return p
+	}
+
+	// Vendor is present, and srcDir is outside parent's tree. Not allowed.
+	perr := *p
+	perr.Error = &PackageError{
+		ImportStack: stk.copy(),
+		Err:         "use of vendored package not allowed",
+	}
+	perr.Incomplete = true
+	return &perr
+}
+
+// findVendor looks for the last non-terminating "vendor" path element in the given import path.
+// If there isn't one, findVendor returns ok=false.
+// Otherwise, findInternal returns ok=true and the index of the "vendor".
+//
+// Note that terminating "vendor" elements don't count: "x/vendor" is its own package,
+// not the vendored copy of an import "" (the empty import path).
+// This will allow people to have packages or commands named vendor.
+// This may help reduce breakage, or it may just be confusing. We'll see.
+func findVendor(path string) (index int, ok bool) {
+	// Two cases, depending on internal at start of string or not.
+	// The order matters: we must return the index of the final element,
+	// because the final one is where the effective import path starts.
+	switch {
+	case strings.Contains(path, "/vendor/"):
+		return strings.LastIndex(path, "/vendor/") + 1, true
+	case strings.HasPrefix(path, "vendor/"):
+		return 0, true
+	}
+	return 0, false
+}
+
 type targetDir int
 
 const (
@@ -393,17 +663,23 @@ const (
 var goTools = map[string]targetDir{
 	"cmd/addr2line":                        toTool,
 	"cmd/api":                              toTool,
+	"cmd/asm":                              toTool,
+	"cmd/compile":                          toTool,
 	"cmd/cgo":                              toTool,
+	"cmd/cover":                            toTool,
+	"cmd/dist":                             toTool,
+	"cmd/doc":                              toTool,
 	"cmd/fix":                              toTool,
 	"cmd/link":                             toTool,
+	"cmd/newlink":                          toTool,
 	"cmd/nm":                               toTool,
 	"cmd/objdump":                          toTool,
 	"cmd/pack":                             toTool,
 	"cmd/pprof":                            toTool,
+	"cmd/trace":                            toTool,
+	"cmd/vet":                              toTool,
 	"cmd/yacc":                             toTool,
-	"golang.org/x/tools/cmd/cover":         toTool,
 	"golang.org/x/tools/cmd/godoc":         toBin,
-	"golang.org/x/tools/cmd/vet":           toTool,
 	"code.google.com/p/go.tools/cmd/cover": stalePath,
 	"code.google.com/p/go.tools/cmd/godoc": stalePath,
 	"code.google.com/p/go.tools/cmd/vet":   stalePath,
@@ -466,7 +742,15 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
 		return p
 	}
 
-	if p.Name == "main" {
+	useBindir := p.Name == "main"
+	if !p.Standard {
+		switch buildBuildmode {
+		case "c-archive", "c-shared":
+			useBindir = false
+		}
+	}
+
+	if useBindir {
 		// Report an error when the old code.google.com/p/go.tools paths are used.
 		if goTools[p.ImportPath] == stalePath {
 			newPath := strings.Replace(p.ImportPath, "code.google.com/p/go.", "golang.org/x/", 1)
@@ -488,6 +772,11 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
 		} else if p.build.BinDir != "" {
 			// Install to GOBIN or bin of GOPATH entry.
 			p.target = filepath.Join(p.build.BinDir, elem)
+			if !p.Goroot && strings.Contains(elem, "/") && gobin != "" {
+				// Do not create $GOBIN/goos_goarch/elem.
+				p.target = ""
+				p.gobinSubdir = true
+			}
 		}
 		if goTools[p.ImportPath] == toTool {
 			// This is for 'go tool'.
@@ -503,6 +792,21 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
 		p.target = ""
 	} else {
 		p.target = p.build.PkgObj
+		if buildLinkshared {
+			shlibnamefile := p.target[:len(p.target)-2] + ".shlibname"
+			shlib, err := ioutil.ReadFile(shlibnamefile)
+			if err == nil {
+				libname := strings.TrimSpace(string(shlib))
+				if buildContext.Compiler == "gccgo" {
+					p.Shlib = filepath.Join(p.build.PkgTargetRoot, "shlibs", libname)
+				} else {
+					p.Shlib = filepath.Join(p.build.PkgTargetRoot, libname)
+
+				}
+			} else if !os.IsNotExist(err) {
+				fatalf("unexpected error reading %s: %v", shlibnamefile, err)
+			}
+		}
 	}
 
 	importPaths := p.Imports
@@ -516,6 +820,14 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
 	if len(p.CgoFiles) > 0 && (!p.Standard || !cgoSyscallExclude[p.ImportPath]) {
 		importPaths = append(importPaths, "syscall")
 	}
+
+	// Currently build mode c-shared, or -linkshared, forces
+	// external linking mode, and external linking mode forces an
+	// import of runtime/cgo.
+	if p.Name == "main" && !p.Goroot && (buildBuildmode == "c-shared" || buildLinkshared) {
+		importPaths = append(importPaths, "runtime/cgo")
+	}
+
 	// Everything depends on runtime, except runtime and unsafe.
 	if !p.Standard || (p.ImportPath != "runtime" && p.ImportPath != "unsafe") {
 		importPaths = append(importPaths, "runtime")
@@ -524,6 +836,10 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
 		if buildRace && (!p.Standard || !raceExclude[p.ImportPath]) {
 			importPaths = append(importPaths, "runtime/race")
 		}
+		// On ARM with GOARM=5, everything depends on math for the link.
+		if p.Name == "main" && goarch == "arm" {
+			importPaths = append(importPaths, "math")
+		}
 	}
 
 	// Build list of full paths to all Go files in the package,
@@ -581,7 +897,17 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
 		if path == "C" {
 			continue
 		}
-		p1 := loadImport(path, p.Dir, stk, p.build.ImportPos[path])
+		p1 := loadImport(path, p.Dir, p, stk, p.build.ImportPos[path], useVendor)
+		if p1.Name == "main" {
+			p.Error = &PackageError{
+				ImportStack: stk.copy(),
+				Err:         fmt.Sprintf("import %q is a program, not an importable package", path),
+			}
+			pos := p.build.ImportPos[path]
+			if len(pos) > 0 {
+				p.Error.Pos = pos[0].String()
+			}
+		}
 		if p1.local {
 			if !p.local && p.Error == nil {
 				p.Error = &PackageError{
@@ -593,13 +919,21 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
 					p.Error.Pos = pos[0].String()
 				}
 			}
-			path = p1.ImportPath
-			importPaths[i] = path
+		}
+		path = p1.ImportPath
+		importPaths[i] = path
+		if i < len(p.Imports) {
+			p.Imports[i] = path
 		}
 		deps[path] = p1
 		imports = append(imports, p1)
 		for _, dep := range p1.deps {
-			deps[dep.ImportPath] = dep
+			// The same import path could produce an error or not,
+			// depending on what tries to import it.
+			// Prefer to record entries with errors, so we can report them.
+			if deps[dep.ImportPath] == nil || dep.Error != nil {
+				deps[dep.ImportPath] = dep
+			}
 		}
 		if p1.Incomplete {
 			p.Incomplete = true
@@ -629,12 +963,11 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
 	}
 	p.Target = p.target
 
-	// Check for C code compiled with Plan 9 C compiler.
-	// No longer allowed except in runtime and runtime/cgo, for now.
-	if len(p.CFiles) > 0 && !p.usesCgo() && (!p.Standard || p.ImportPath != "runtime") {
+	// The gc toolchain only permits C source files with cgo.
+	if len(p.CFiles) > 0 && !p.usesCgo() && !p.usesSwig() && buildContext.Compiler == "gc" {
 		p.Error = &PackageError{
 			ImportStack: stk.copy(),
-			Err:         fmt.Sprintf("C source files not allowed when not using cgo: %s", strings.Join(p.CFiles, " ")),
+			Err:         fmt.Sprintf("C source files not allowed when not using cgo or SWIG: %s", strings.Join(p.CFiles, " ")),
 		}
 		return p
 	}
@@ -652,6 +985,7 @@ func (p *Package) load(stk *importStack, bp *build.Package, err error) *Package
 		}
 	}
 
+	computeBuildID(p)
 	return p
 }
 
@@ -690,13 +1024,8 @@ func packageList(roots []*Package) []*Package {
 // computeStale computes the Stale flag in the package dag that starts
 // at the named pkgs (command-line arguments).
 func computeStale(pkgs ...*Package) {
-	topRoot := map[string]bool{}
-	for _, p := range pkgs {
-		topRoot[p.Root] = true
-	}
-
 	for _, p := range packageList(pkgs) {
-		p.Stale = isStale(p, topRoot)
+		p.Stale = isStale(p)
 	}
 }
 
@@ -706,8 +1035,269 @@ func computeStale(pkgs ...*Package) {
 // inspecting the version.
 var isGoRelease = strings.HasPrefix(runtime.Version(), "go1")
 
+// isStale and computeBuildID
+//
+// Theory of Operation
+//
+// There is an installed copy of the package (or binary).
+// Can we reuse the installed copy, or do we need to build a new one?
+//
+// We can use the installed copy if it matches what we'd get
+// by building a new one. The hard part is predicting that without
+// actually running a build.
+//
+// To start, we must know the set of inputs to the build process that can
+// affect the generated output. At a minimum, that includes the source
+// files for the package and also any compiled packages imported by those
+// source files. The *Package has these, and we use them. One might also
+// argue for including in the input set: the build tags, whether the race
+// detector is in use, the target operating system and architecture, the
+// compiler and linker binaries being used, the additional flags being
+// passed to those, the cgo binary being used, the additional flags cgo
+// passes to the host C compiler, the host C compiler being used, the set
+// of host C include files and installed C libraries, and so on.
+// We include some but not all of this information.
+//
+// Once we have decided on a set of inputs, we must next decide how to
+// tell whether the content of that set has changed since the last build
+// of p. If there have been no changes, then we assume a new build would
+// produce the same result and reuse the installed package or binary.
+// But if there have been changes, then we assume a new build might not
+// produce the same result, so we rebuild.
+//
+// There are two common ways to decide whether the content of the set has
+// changed: modification times and content hashes. We use a mixture of both.
+//
+// The use of modification times (mtimes) was pioneered by make:
+// assuming that a file's mtime is an accurate record of when that file was last written,
+// and assuming that the modification time of an installed package or
+// binary is the time that it was built, if the mtimes of the inputs
+// predate the mtime of the installed object, then the build of that
+// object saw those versions of the files, and therefore a rebuild using
+// those same versions would produce the same object. In contrast, if any
+// mtime of an input is newer than the mtime of the installed object, a
+// change has occurred since the build, and the build should be redone.
+//
+// Modification times are attractive because the logic is easy to
+// understand and the file system maintains the mtimes automatically
+// (less work for us). Unfortunately, there are a variety of ways in
+// which the mtime approach fails to detect a change and reuses a stale
+// object file incorrectly. (Making the opposite mistake, rebuilding
+// unnecessarily, is only a performance problem and not a correctness
+// problem, so we ignore that one.)
+//
+// As a warmup, one problem is that to be perfectly precise, we need to
+// compare the input mtimes against the time at the beginning of the
+// build, but the object file time is the time at the end of the build.
+// If an input file changes after being read but before the object is
+// written, the next build will see an object newer than the input and
+// will incorrectly decide that the object is up to date. We make no
+// attempt to detect or solve this problem.
+//
+// Another problem is that due to file system imprecision, an input and
+// output that are actually ordered in time have the same mtime.
+// This typically happens on file systems with 1-second (or, worse,
+// 2-second) mtime granularity and with automated scripts that write an
+// input and then immediately run a build, or vice versa. If an input and
+// an output have the same mtime, the conservative behavior is to treat
+// the output as out-of-date and rebuild. This can cause one or more
+// spurious rebuilds, but only for 1 second, until the object finally has
+// an mtime later than the input.
+//
+// Another problem is that binary distributions often set the mtime on
+// all files to the same time. If the distribution includes both inputs
+// and cached build outputs, the conservative solution to the previous
+// problem will cause unnecessary rebuilds. Worse, in such a binary
+// distribution, those rebuilds might not even have permission to update
+// the cached build output. To avoid these write errors, if an input and
+// output have the same mtime, we assume the output is up-to-date.
+// This is the opposite of what the previous problem would have us do,
+// but binary distributions are more common than instances of the
+// previous problem.
+//
+// A variant of the last problem is that some binary distributions do not
+// set the mtime on all files to the same time. Instead they let the file
+// system record mtimes as the distribution is unpacked. If the outputs
+// are unpacked before the inputs, they'll be older and a build will try
+// to rebuild them. That rebuild might hit the same write errors as in
+// the last scenario. We don't make any attempt to solve this, and we
+// haven't had many reports of it. Perhaps the only time this happens is
+// when people manually unpack the distribution, and most of the time
+// that's done as the same user who will be using it, so an initial
+// rebuild on first use succeeds quietly.
+//
+// More generally, people and programs change mtimes on files. The last
+// few problems were specific examples of this, but it's a general problem.
+// For example, instead of a binary distribution, copying a home
+// directory from one directory or machine to another might copy files
+// but not preserve mtimes. If the inputs are new than the outputs on the
+// first machine but copied first, they end up older than the outputs on
+// the second machine.
+//
+// Because many other build systems have the same sensitivity to mtimes,
+// most programs manipulating source code take pains not to break the
+// mtime assumptions. For example, Git does not set the mtime of files
+// during a checkout operation, even when checking out an old version of
+// the code. This decision was made specifically to work well with
+// mtime-based build systems.
+//
+// The killer problem, though, for mtime-based build systems is that the
+// build only has access to the mtimes of the inputs that still exist.
+// If it is possible to remove an input without changing any other inputs,
+// a later build will think the object is up-to-date when it is not.
+// This happens for Go because a package is made up of all source
+// files in a directory. If a source file is removed, there is no newer
+// mtime available recording that fact. The mtime on the directory could
+// be used, but it also changes when unrelated files are added to or
+// removed from the directory, so including the directory mtime would
+// cause unnecessary rebuilds, possibly many. It would also exacerbate
+// the problems mentioned earlier, since even programs that are careful
+// to maintain mtimes on files rarely maintain mtimes on directories.
+//
+// A variant of the last problem is when the inputs change for other
+// reasons. For example, Go 1.4 and Go 1.5 both install $GOPATH/src/mypkg
+// into the same target, $GOPATH/pkg/$GOOS_$GOARCH/mypkg.a.
+// If Go 1.4 has built mypkg into mypkg.a, a build using Go 1.5 must
+// rebuild mypkg.a, but from mtimes alone mypkg.a looks up-to-date.
+// If Go 1.5 has just been installed, perhaps the compiler will have a
+// newer mtime; since the compiler is considered an input, that would
+// trigger a rebuild. But only once, and only the last Go 1.4 build of
+// mypkg.a happened before Go 1.5 was installed. If a user has the two
+// versions installed in different locations and flips back and forth,
+// mtimes alone cannot tell what to do. Changing the toolchain is
+// changing the set of inputs, without affecting any mtimes.
+//
+// To detect the set of inputs changing, we turn away from mtimes and to
+// an explicit data comparison. Specifically, we build a list of the
+// inputs to the build, compute its SHA1 hash, and record that as the
+// ``build ID'' in the generated object. At the next build, we can
+// recompute the buid ID and compare it to the one in the generated
+// object. If they differ, the list of inputs has changed, so the object
+// is out of date and must be rebuilt.
+//
+// Because this build ID is computed before the build begins, the
+// comparison does not have the race that mtime comparison does.
+//
+// Making the build sensitive to changes in other state is
+// straightforward: include the state in the build ID hash, and if it
+// changes, so does the build ID, triggering a rebuild.
+//
+// To detect changes in toolchain, we include the toolchain version in
+// the build ID hash for package runtime, and then we include the build
+// IDs of all imported packages in the build ID for p.
+//
+// It is natural to think about including build tags in the build ID, but
+// the naive approach of just dumping the tags into the hash would cause
+// spurious rebuilds. For example, 'go install' and 'go install -tags neverusedtag'
+// produce the same binaries (assuming neverusedtag is never used).
+// A more precise approach would be to include only tags that have an
+// effect on the build. But the effect of a tag on the build is to
+// include or exclude a file from the compilation, and that file list is
+// already in the build ID hash. So the build ID is already tag-sensitive
+// in a perfectly precise way. So we do NOT explicitly add build tags to
+// the build ID hash.
+//
+// We do not include as part of the build ID the operating system,
+// architecture, or whether the race detector is enabled, even though all
+// three have an effect on the output, because that information is used
+// to decide the install location. Binaries for linux and binaries for
+// darwin are written to different directory trees; including that
+// information in the build ID is unnecessary (although it would be
+// harmless).
+//
+// TODO(rsc): Investigate the cost of putting source file content into
+// the build ID hash as a replacement for the use of mtimes. Using the
+// file content would avoid all the mtime problems, but it does require
+// reading all the source files, something we avoid today (we read the
+// beginning to find the build tags and the imports, but we stop as soon
+// as we see the import block is over). If the package is stale, the compiler
+// is going to read the files anyway. But if the package is up-to-date, the
+// read is overhead.
+//
+// TODO(rsc): Investigate the complexity of making the build more
+// precise about when individual results are needed. To be fully precise,
+// there are two results of a compilation: the entire .a file used by the link
+// and the subpiece used by later compilations (__.PKGDEF only).
+// If a rebuild is needed but produces the previous __.PKGDEF, then
+// no more recompilation due to the rebuilt package is needed, only
+// relinking. To date, there is nothing in the Go command to express this.
+//
+// Special Cases
+//
+// When the go command makes the wrong build decision and does not
+// rebuild something it should, users fall back to adding the -a flag.
+// Any common use of the -a flag should be considered prima facie evidence
+// that isStale is returning an incorrect false result in some important case.
+// Bugs reported in the behavior of -a itself should prompt the question
+// ``Why is -a being used at all? What bug does that indicate?''
+//
+// There is a long history of changes to isStale to try to make -a into a
+// suitable workaround for bugs in the mtime-based decisions.
+// It is worth recording that history to inform (and, as much as possible, deter) future changes.
+//
+// (1) Before the build IDs were introduced, building with alternate tags
+// would happily reuse installed objects built without those tags.
+// For example, "go build -tags netgo myprog.go" would use the installed
+// copy of package net, even if that copy had been built without netgo.
+// (The netgo tag controls whether package net uses cgo or pure Go for
+// functionality such as name resolution.)
+// Using the installed non-netgo package defeats the purpose.
+//
+// Users worked around this with "go build -tags netgo -a myprog.go".
+//
+// Build IDs have made that workaround unnecessary:
+// "go build -tags netgo myprog.go"
+// cannot use a non-netgo copy of package net.
+//
+// (2) Before the build IDs were introduced, building with different toolchains,
+// especially changing between toolchains, tried to reuse objects stored in
+// $GOPATH/pkg, resulting in link-time errors about object file mismatches.
+//
+// Users worked around this with "go install -a ./...".
+//
+// Build IDs have made that workaround unnecessary:
+// "go install ./..." will rebuild any objects it finds that were built against
+// a different toolchain.
+//
+// (3) The common use of "go install -a ./..." led to reports of problems
+// when the -a forced the rebuild of the standard library, which for some
+// users was not writable. Because we didn't understand that the real
+// problem was the bug -a was working around, we changed -a not to
+// apply to the standard library.
+//
+// (4) The common use of "go build -tags netgo -a myprog.go" broke
+// when we changed -a not to apply to the standard library, because
+// if go build doesn't rebuild package net, it uses the non-netgo version.
+//
+// Users worked around this with "go build -tags netgo -installsuffix barf myprog.go".
+// The -installsuffix here is making the go command look for packages
+// in pkg/$GOOS_$GOARCH_barf instead of pkg/$GOOS_$GOARCH.
+// Since the former presumably doesn't exist, go build decides to rebuild
+// everything, including the standard library. Since go build doesn't
+// install anything it builds, nothing is ever written to pkg/$GOOS_$GOARCH_barf,
+// so repeated invocations continue to work.
+//
+// If the use of -a wasn't a red flag, the use of -installsuffix to point to
+// a non-existent directory in a command that installs nothing should
+// have been.
+//
+// (5) Now that (1) and (2) no longer need -a, we have removed the kludge
+// introduced in (3): once again, -a means ``rebuild everything,'' not
+// ``rebuild everything except the standard library.'' Only Go 1.4 had
+// the restricted meaning.
+//
+// In addition to these cases trying to trigger rebuilds, there are
+// special cases trying NOT to trigger rebuilds. The main one is that for
+// a variety of reasons (see above), the install process for a Go release
+// cannot be relied upon to set the mtimes such that the go command will
+// think the standard library is up to date. So the mtime evidence is
+// ignored for the standard library if we find ourselves in a release
+// version of Go. Build ID-based staleness checks still apply to the
+// standard library, even in release versions. This makes
+// 'go build -tags netgo' work, among other things.
+
 // isStale reports whether package p needs to be rebuilt.
-func isStale(p *Package, topRoot map[string]bool) bool {
+func isStale(p *Package) bool {
 	if p.Standard && (p.ImportPath == "unsafe" || buildContext.Compiler == "gccgo") {
 		// fake, builtin package
 		return false
@@ -726,28 +1316,68 @@ func isStale(p *Package, topRoot map[string]bool) bool {
 		return false
 	}
 
-	// If we are running a release copy of Go, do not rebuild the standard packages.
-	// They may not be writable anyway, but they are certainly not changing.
-	// This makes 'go build -a' skip the standard packages when using an official release.
-	// See issue 4106 and issue 8290.
-	pkgBuildA := buildA
-	if p.Standard && isGoRelease {
-		pkgBuildA = false
+	// If the -a flag is given, rebuild everything.
+	if buildA {
+		return true
 	}
 
-	if pkgBuildA || p.target == "" || p.Stale {
+	// If there's no install target or it's already marked stale, we have to rebuild.
+	if p.target == "" || p.Stale {
 		return true
 	}
 
 	// Package is stale if completely unbuilt.
-	var built time.Time
-	if fi, err := os.Stat(p.target); err == nil {
-		built = fi.ModTime()
+	fi, err := os.Stat(p.target)
+	if err != nil {
+		return true
 	}
-	if built.IsZero() {
+
+	// Package is stale if the expected build ID differs from the
+	// recorded build ID. This catches changes like a source file
+	// being removed from a package directory. See issue 3895.
+	// It also catches changes in build tags that affect the set of
+	// files being compiled. See issue 9369.
+	// It also catches changes in toolchain, like when flipping between
+	// two versions of Go compiling a single GOPATH.
+	// See issue 8290 and issue 10702.
+	targetBuildID, err := readBuildID(p)
+	if err == nil && targetBuildID != p.buildID {
 		return true
 	}
 
+	// Package is stale if a dependency is.
+	for _, p1 := range p.deps {
+		if p1.Stale {
+			return true
+		}
+	}
+
+	// The checks above are content-based staleness.
+	// We assume they are always accurate.
+	//
+	// The checks below are mtime-based staleness.
+	// We hope they are accurate, but we know that they fail in the case of
+	// prebuilt Go installations that don't preserve the build mtimes
+	// (for example, if the pkg/ mtimes are before the src/ mtimes).
+	// See the large comment above isStale for details.
+
+	// If we are running a release copy of Go and didn't find a content-based
+	// reason to rebuild the standard packages, do not rebuild them.
+	// They may not be writable anyway, but they are certainly not changing.
+	// This makes 'go build' skip the standard packages when
+	// using an official release, even when the mtimes have been changed.
+	// See issue 3036, issue 3149, issue 4106, issue 8290.
+	// (If a change to a release tree must be made by hand, the way to force the
+	// install is to run make.bash, which will remove the old package archives
+	// before rebuilding.)
+	if p.Standard && isGoRelease {
+		return false
+	}
+
+	// Time-based staleness.
+
+	built := fi.ModTime()
+
 	olderThan := func(file string) bool {
 		fi, err := os.Stat(file)
 		return err != nil || fi.ModTime().After(built)
@@ -755,7 +1385,7 @@ func isStale(p *Package, topRoot map[string]bool) bool {
 
 	// Package is stale if a dependency is, or if a dependency is newer.
 	for _, p1 := range p.deps {
-		if p1.Stale || p1.target != "" && olderThan(p1.target) {
+		if p1.target != "" && olderThan(p1.target) {
 			return true
 		}
 	}
@@ -767,8 +1397,12 @@ func isStale(p *Package, topRoot map[string]bool) bool {
 	// back-dated, as some binary distributions may do, but it does handle
 	// a very common case.
 	// See issue 3036.
-	// Assume code in $GOROOT is up to date, since it may not be writeable.
-	// See issue 4106.
+	// Exclude $GOROOT, under the assumption that people working on
+	// the compiler may want to control when everything gets rebuilt,
+	// and people updating the Go repository will run make.bash or all.bash
+	// and get a full rebuild anyway.
+	// Excluding $GOROOT used to also fix issue 4106, but that's now
+	// taken care of above (at least when the installed Go is a released version).
 	if p.Root != goroot {
 		if olderThan(buildToolchain.compiler()) {
 			return true
@@ -778,19 +1412,43 @@ func isStale(p *Package, topRoot map[string]bool) bool {
 		}
 	}
 
-	// Have installed copy, probably built using current compilers,
-	// and built after its imported packages.  The only reason now
-	// that we'd have to rebuild it is if the sources were newer than
-	// the package.   If a package p is not in the same tree as any
-	// package named on the command-line, assume it is up-to-date
-	// no matter what the modification times on the source files indicate.
-	// This avoids rebuilding $GOROOT packages when people are
-	// working outside the Go root, and it effectively makes each tree
-	// listed in $GOPATH a separate compilation world.
-	// See issue 3149.
-	if p.Root != "" && !topRoot[p.Root] {
-		return false
-	}
+	// Note: Until Go 1.5, we had an additional shortcut here.
+	// We built a list of the workspace roots ($GOROOT, each $GOPATH)
+	// containing targets directly named on the command line,
+	// and if p were not in any of those, it would be treated as up-to-date
+	// as long as it is built. The goal was to avoid rebuilding a system-installed
+	// $GOROOT, unless something from $GOROOT were explicitly named
+	// on the command line (like go install math).
+	// That's now handled by the isGoRelease clause above.
+	// The other effect of the shortcut was to isolate different entries in
+	// $GOPATH from each other. This had the unfortunate effect that
+	// if you had (say), GOPATH listing two entries, one for commands
+	// and one for libraries, and you did a 'git pull' in the library one
+	// and then tried 'go install commands/...', it would build the new libraries
+	// during the first build (because they wouldn't have been installed at all)
+	// but then subsequent builds would not rebuild the libraries, even if the
+	// mtimes indicate they are stale, because the different GOPATH entries
+	// were treated differently. This behavior was confusing when using
+	// non-trivial GOPATHs, which were particularly common with some
+	// code management conventions, like the original godep.
+	// Since the $GOROOT case (the original motivation) is handled separately,
+	// we no longer put a barrier between the different $GOPATH entries.
+	//
+	// One implication of this is that if there is a system directory for
+	// non-standard Go packages that is included in $GOPATH, the mtimes
+	// on those compiled packages must be no earlier than the mtimes
+	// on the source files. Since most distributions use the same mtime
+	// for all files in a tree, they will be unaffected. People using plain
+	// tar x to extract system-installed packages will need to adjust mtimes,
+	// but it's better to force them to get the mtimes right than to ignore
+	// the mtimes and thereby do the wrong thing in common use cases.
+	//
+	// So there is no GOPATH vs GOPATH shortcut here anymore.
+	//
+	// If something needs to come back here, we could try writing a dummy
+	// file with a random name to the $GOPATH/pkg directory (and removing it)
+	// to test for write access, and then skip GOPATH roots we don't have write
+	// access to. But hopefully we can just use the mtimes always.
 
 	srcs := stringList(p.GoFiles, p.CFiles, p.CXXFiles, p.MFiles, p.HFiles, p.SFiles, p.CgoFiles, p.SysoFiles, p.SwigFiles, p.SwigCXXFiles)
 	for _, src := range srcs {
@@ -802,6 +1460,53 @@ func isStale(p *Package, topRoot map[string]bool) bool {
 	return false
 }
 
+// computeBuildID computes the build ID for p, leaving it in p.buildID.
+// Build ID is a hash of the information we want to detect changes in.
+// See the long comment in isStale for details.
+func computeBuildID(p *Package) {
+	h := sha1.New()
+
+	// Include the list of files compiled as part of the package.
+	// This lets us detect removed files. See issue 3895.
+	inputFiles := stringList(
+		p.GoFiles,
+		p.CgoFiles,
+		p.CFiles,
+		p.CXXFiles,
+		p.MFiles,
+		p.HFiles,
+		p.SFiles,
+		p.SysoFiles,
+		p.SwigFiles,
+		p.SwigCXXFiles,
+	)
+	for _, file := range inputFiles {
+		fmt.Fprintf(h, "file %s\n", file)
+	}
+
+	// Include the content of runtime/zversion.go in the hash
+	// for package runtime. This will give package runtime a
+	// different build ID in each Go release.
+	if p.Standard && p.ImportPath == "runtime" {
+		data, _ := ioutil.ReadFile(filepath.Join(p.Dir, "zversion.go"))
+		fmt.Fprintf(h, "zversion %q\n", string(data))
+	}
+
+	// Include the build IDs of any dependencies in the hash.
+	// This, combined with the runtime/zversion content,
+	// will cause packages to have different build IDs when
+	// compiled with different Go releases.
+	// This helps the go command know to recompile when
+	// people use the same GOPATH but switch between
+	// different Go releases. See issue 10702.
+	// This is also a better fix for issue 8290.
+	for _, p1 := range p.deps {
+		fmt.Fprintf(h, "dep %s %s\n", p1.ImportPath, p1.buildID)
+	}
+
+	p.buildID = fmt.Sprintf("%x", h.Sum(nil))
+}
+
 var cwd, _ = os.Getwd()
 
 var cmdCache = map[string]*Package{}
@@ -864,7 +1569,7 @@ func loadPackage(arg string, stk *importStack) *Package {
 		}
 	}
 
-	return loadImport(arg, cwd, stk, nil)
+	return loadImport(arg, cwd, nil, stk, nil, 0)
 }
 
 // packages returns the packages named by the
@@ -934,6 +1639,23 @@ func packagesForBuild(args []string) []*Package {
 		}
 	}
 	exitIfErrors()
+
+	// Check for duplicate loads of the same package.
+	// That should be impossible, but if it does happen then
+	// we end up trying to build the same package twice,
+	// usually in parallel overwriting the same files,
+	// which doesn't work very well.
+	seen := map[string]bool{}
+	reported := map[string]bool{}
+	for _, pkg := range packageList(pkgs) {
+		if seen[pkg.ImportPath] && !reported[pkg.ImportPath] {
+			reported[pkg.ImportPath] = true
+			errorf("internal error: duplicate loads of %s", pkg.ImportPath)
+		}
+		seen[pkg.ImportPath] = true
+	}
+	exitIfErrors()
+
 	return pkgs
 }
 
@@ -959,3 +1681,170 @@ func hasSubdir(root, dir string) (rel string, ok bool) {
 	}
 	return filepath.ToSlash(dir[len(root):]), true
 }
+
+var (
+	errBuildIDToolchain = fmt.Errorf("build ID only supported in gc toolchain")
+	errBuildIDMalformed = fmt.Errorf("malformed object file")
+	errBuildIDUnknown   = fmt.Errorf("lost build ID")
+)
+
+var (
+	bangArch = []byte("!<arch>")
+	pkgdef   = []byte("__.PKGDEF")
+	goobject = []byte("go object ")
+	buildid  = []byte("build id ")
+)
+
+// readBuildID reads the build ID from an archive or binary.
+// It only supports the gc toolchain.
+// Other toolchain maintainers should adjust this function.
+func readBuildID(p *Package) (id string, err error) {
+	if buildToolchain != (gcToolchain{}) {
+		return "", errBuildIDToolchain
+	}
+
+	// For commands, read build ID directly from binary.
+	if p.Name == "main" {
+		return ReadBuildIDFromBinary(p.Target)
+	}
+
+	// Otherwise, we expect to have an archive (.a) file,
+	// and we can read the build ID from the Go export data.
+	if !strings.HasSuffix(p.Target, ".a") {
+		return "", &os.PathError{Op: "parse", Path: p.Target, Err: errBuildIDUnknown}
+	}
+
+	// Read just enough of the target to fetch the build ID.
+	// The archive is expected to look like:
+	//
+	//	!<arch>
+	//	__.PKGDEF       0           0     0     644     7955      `
+	//	go object darwin amd64 devel X:none
+	//	build id "b41e5c45250e25c9fd5e9f9a1de7857ea0d41224"
+	//
+	// The variable-sized strings are GOOS, GOARCH, and the experiment list (X:none).
+	// Reading the first 1024 bytes should be plenty.
+	f, err := os.Open(p.Target)
+	if err != nil {
+		return "", err
+	}
+	data := make([]byte, 1024)
+	n, err := io.ReadFull(f, data)
+	f.Close()
+
+	if err != nil && n == 0 {
+		return "", err
+	}
+
+	bad := func() (string, error) {
+		return "", &os.PathError{Op: "parse", Path: p.Target, Err: errBuildIDMalformed}
+	}
+
+	// Archive header.
+	for i := 0; ; i++ { // returns during i==3
+		j := bytes.IndexByte(data, '\n')
+		if j < 0 {
+			return bad()
+		}
+		line := data[:j]
+		data = data[j+1:]
+		switch i {
+		case 0:
+			if !bytes.Equal(line, bangArch) {
+				return bad()
+			}
+		case 1:
+			if !bytes.HasPrefix(line, pkgdef) {
+				return bad()
+			}
+		case 2:
+			if !bytes.HasPrefix(line, goobject) {
+				return bad()
+			}
+		case 3:
+			if !bytes.HasPrefix(line, buildid) {
+				// Found the object header, just doesn't have a build id line.
+				// Treat as successful, with empty build id.
+				return "", nil
+			}
+			id, err := strconv.Unquote(string(line[len(buildid):]))
+			if err != nil {
+				return bad()
+			}
+			return id, nil
+		}
+	}
+}
+
+var (
+	goBuildPrefix = []byte("\xff Go build ID: \"")
+	goBuildEnd    = []byte("\"\n \xff")
+
+	elfPrefix = []byte("\x7fELF")
+)
+
+// ReadBuildIDFromBinary reads the build ID from a binary.
+//
+// ELF binaries store the build ID in a proper PT_NOTE section.
+//
+// Other binary formats are not so flexible. For those, the linker
+// stores the build ID as non-instruction bytes at the very beginning
+// of the text segment, which should appear near the beginning
+// of the file. This is clumsy but fairly portable. Custom locations
+// can be added for other binary types as needed, like we did for ELF.
+func ReadBuildIDFromBinary(filename string) (id string, err error) {
+	if filename == "" {
+		return "", &os.PathError{Op: "parse", Path: filename, Err: errBuildIDUnknown}
+	}
+
+	// Read the first 16 kB of the binary file.
+	// That should be enough to find the build ID.
+	// In ELF files, the build ID is in the leading headers,
+	// which are typically less than 4 kB, not to mention 16 kB.
+	// On other systems, we're trying to read enough that
+	// we get the beginning of the text segment in the read.
+	// The offset where the text segment begins in a hello
+	// world compiled for each different object format today:
+	//
+	//	Plan 9: 0x20
+	//	Windows: 0x600
+	//	Mach-O: 0x2000
+	//
+	f, err := os.Open(filename)
+	if err != nil {
+		return "", err
+	}
+	defer f.Close()
+
+	data := make([]byte, 16*1024)
+	_, err = io.ReadFull(f, data)
+	if err == io.ErrUnexpectedEOF {
+		err = nil
+	}
+	if err != nil {
+		return "", err
+	}
+
+	if bytes.HasPrefix(data, elfPrefix) {
+		return readELFGoBuildID(filename, f, data)
+	}
+
+	i := bytes.Index(data, goBuildPrefix)
+	if i < 0 {
+		// Missing. Treat as successful but build ID empty.
+		return "", nil
+	}
+
+	j := bytes.Index(data[i+len(goBuildPrefix):], goBuildEnd)
+	if j < 0 {
+		return "", &os.PathError{Op: "parse", Path: filename, Err: errBuildIDMalformed}
+	}
+
+	quoted := data[i+len(goBuildPrefix)-1 : i+len(goBuildPrefix)+j+1]
+	id, err = strconv.Unquote(string(quoted))
+	if err != nil {
+		return "", &os.PathError{Op: "parse", Path: filename, Err: errBuildIDMalformed}
+	}
+
+	return id, nil
+}
diff --git a/src/cmd/go/run.go b/src/cmd/go/run.go
index ef8aa95..f6da373 100644
--- a/src/cmd/go/run.go
+++ b/src/cmd/go/run.go
@@ -37,7 +37,8 @@ Run compiles and runs the main package comprising the named Go source files.
 A Go source file is defined to be a file ending in a literal ".go" suffix.
 
 By default, 'go run' runs the compiled binary directly: 'a.out arguments...'.
-If the -exec flag is given, 'go run' invokes the binary using xprog: 'xprog a.out arguments...'.
+If the -exec flag is given, 'go run' invokes the binary using xprog:
+	'xprog a.out arguments...'.
 If the -exec flag is not given, GOOS or GOARCH is different from the system
 default, and a program named go_$GOOS_$GOARCH_exec can be found
 on the current search path, 'go run' invokes the binary using that program,
@@ -64,6 +65,7 @@ func printStderr(args ...interface{}) (int, error) {
 
 func runRun(cmd *Command, args []string) {
 	raceInit()
+	buildModeInit()
 	var b builder
 	b.init()
 	b.print = printStderr
@@ -136,6 +138,7 @@ func runStdin(cmdline []string) {
 	cmd.Stdin = os.Stdin
 	cmd.Stdout = os.Stdout
 	cmd.Stderr = os.Stderr
+	cmd.Env = origEnv
 	startSigHandlers()
 	if err := cmd.Run(); err != nil {
 		errorf("%v", err)
diff --git a/src/cmd/go/script b/src/cmd/go/script
deleted file mode 100755
index 340a7e8..0000000
--- a/src/cmd/go/script
+++ /dev/null
@@ -1,23 +0,0 @@
-#!/bin/sh
-
-x() {
-	echo '--- ' "$@"
-	"$@"
-	echo '---'
-	echo
-}
-
-x go help
-x go help build
-x go help clean
-x go help install
-x go help fix
-x go help fmt
-x go help get
-x go help list
-x go help test
-x go help version
-x go help vet
-x go help gopath
-x go help importpath
-x go help remote
diff --git a/src/cmd/go/script.txt b/src/cmd/go/script.txt
deleted file mode 100644
index a672146..0000000
--- a/src/cmd/go/script.txt
+++ /dev/null
@@ -1,352 +0,0 @@
----  go help
-usage: go command [arguments]
-
-go manages Go source code.
-
-The commands are:
-
-    build       compile and install packages and dependencies
-    clean       remove intermediate objects
-    fix         run gofix on packages
-    fmt         run gofmt -w on packages
-    get         download and install packages and dependencies
-    install     install packages and dependencies
-    list        list packages
-    test        test packages
-    version     print Go version
-    vet         run govet on packages
-
-Use "go help [command]" for more information about a command.
-
-Additional help topics:
-
-    gopath      GOPATH environment variable
-    importpath  description of import paths
-    remote      remote import path syntax
-
-Use "go help [topic]" for more information about that topic.
-
----
-
----  go help build
-usage: go build [-n] [-v] [importpath...]
-
-Build compiles the packages named by the import paths,
-along with their dependencies, but it does not install the results.
-
-The -n flag prints the commands but does not run them.
-The -v flag prints the commands.
-
-For more about import paths, see 'go help importpath'.
-
-See also: go install, go get, go clean.
----
-
----  go help clean
-usage: go clean [-nuke] [importpath...]
-
-Clean removes intermediate object files generated during
-the compilation of the packages named by the import paths,
-but by default it does not remove the installed package binaries.
-
-The -nuke flag causes clean to remove the installed package binaries too.
-
-TODO: Clean does not clean dependencies of the packages.
-
-For more about import paths, see 'go help importpath'.
----
-
----  go help install
-usage: go install [-n] [-v] [importpath...]
-
-Install compiles and installs the packages named by the import paths,
-along with their dependencies.
-
-The -n flag prints the commands but does not run them.
-The -v flag prints the commands.
-
-For more about import paths, see 'go help importpath'.
-
-See also: go build, go get, go clean.
----
-
----  go help fix
-usage: go fix [importpath...]
-
-Fix runs the gofix command on the packages named by the import paths.
-
-For more about gofix, see 'godoc gofix'.
-For more about import paths, see 'go help importpath'.
-
-To run gofix with specific options, run gofix itself.
-
-See also: go fmt, go vet.
----
-
----  go help fmt
-usage: go fmt [importpath...]
-
-Fmt runs the command 'gofmt -w' on the packages named by the import paths.
-
-For more about gofmt, see 'godoc gofmt'.
-For more about import paths, see 'go help importpath'.
-
-To run gofmt with specific options, run gofmt itself.
-
-See also: go fix, go vet.
----
-
----  go help get
-usage: go get [importpath...]
-
-Get downloads and installs the packages named by the import paths,
-along with their dependencies.
-
-After downloading the code, 'go get' looks for a tag beginning
-with "go." that corresponds to the local Go version.
-For Go "release.r58" it looks for a tag named "go.r58".
-For "weekly.2011-06-03" it looks for "go.weekly.2011-06-03".
-If the specific "go.X" tag is not found, it uses the latest earlier
-version it can find.  Otherwise, it uses the default version for
-the version control system: HEAD for git, tip for Mercurial,
-and so on.
-
-TODO: Explain versions better.
-
-For more about import paths, see 'go help importpath'.
-
-For more about how 'go get' finds source code to
-download, see 'go help remote'.
-
-See also: go build, go install, go clean.
----
-
----  go help list
-usage: go list [-f format] [-json] [importpath...]
-
-List lists the packages named by the import paths.
-
-The default output shows the package name and file system location:
-
-    books /home/you/src/google-api-go-client.googlecode.com/hg/books/v1
-    oauth /home/you/src/goauth2.googlecode.com/hg/oauth
-    sqlite /home/you/src/gosqlite.googlecode.com/hg/sqlite
-
-The -f flag specifies an alternate format for the list,
-using the syntax of package template.  The default output
-is equivalent to -f '{{.Name}} {{.Dir}}'  The struct
-being passed to the template is:
-
-    type Package struct {
-        Name string         // package name
-        Doc string          // package documentation string
-        GoFiles []string    // names of Go source files in package
-        ImportPath string   // import path denoting package
-        Imports []string    // import paths used by this package
-        Deps []string       // all (recursively) imported dependencies
-        Dir string          // directory containing package sources
-        Version string      // version of installed package
-    }
-
-The -json flag causes the package data to be printed in JSON format.
-
-For more about import paths, see 'go help importpath'.
----
-
----  go help test
-usage: go test [importpath...]
-
-Test runs gotest to test the packages named by the import paths.
-It prints a summary of the test results in the format:
-
-	test archive/tar
-	FAIL archive/zip
-	test compress/gzip
-	...
-
-followed by gotest output for each failed package.
-
-For more about import paths, see 'go help importpath'.
-
-See also: go build, go compile, go vet.
----
-
----  go help version
-usage: go version
-
-Version prints the Go version, as reported by runtime.Version.
----
-
----  go help vet
-usage: go vet [importpath...]
-
-Vet runs the govet command on the packages named by the import paths.
-
-For more about govet, see 'godoc govet'.
-For more about import paths, see 'go help importpath'.
-
-To run govet with specific options, run govet itself.
-
-See also: go fmt, go fix.
----
-
----  go help gopath
-The GOPATH environment variable lists places to look for Go code.
-On Unix, the value is a colon-separated string.
-On Windows, the value is a semicolon-separated string.
-On Plan 9, the value is a list.
-
-GOPATH must be set to build and install packages outside the
-standard Go tree.
-
-Each directory listed in GOPATH must have a prescribed structure:
-
-The src/ directory holds source code.  The path below 'src'
-determines the import path or executable name.
-
-The pkg/ directory holds installed package objects.
-As in the Go tree, each target operating system and
-architecture pair has its own subdirectory of pkg
-(pkg/GOOS_GOARCH).
-
-If DIR is a directory listed in the GOPATH, a package with
-source in DIR/src/foo/bar can be imported as "foo/bar" and
-has its compiled form installed to "DIR/pkg/GOOS_GOARCH/foo/bar.a".
-
-The bin/ directory holds compiled commands.
-Each command is named for its source directory, but only
-the final element, not the entire path.  That is, the
-command with source in DIR/src/foo/quux is installed into
-DIR/bin/quux, not DIR/bin/foo/quux.  The foo/ is stripped
-so that you can add DIR/bin to your PATH to get at the
-installed commands.
-
-Here's an example directory layout:
-
-    GOPATH=/home/user/gocode
-
-    /home/user/gocode/
-        src/
-            foo/
-                bar/               (go code in package bar)
-                    x.go
-                quux/              (go code in package main)
-                    y.go
-        bin/
-            quux                   (installed command)
-		pkg/
-		    linux_amd64/
-		        foo/
-		            bar.a          (installed package object)
-
-Go searches each directory listed in GOPATH to find source code,
-but new packages are always downloaded into the first directory 
-in the list.
----
-
----  go help importpath
-Many commands apply to a set of packages named by import paths:
-
-	go action [importpath...]
-
-An import path that is a rooted path or that begins with
-a . or .. element is interpreted as a file system path and
-denotes the package in that directory.
-
-Otherwise, the import path P denotes the package found in
-the directory DIR/src/P for some DIR listed in the GOPATH
-environment variable (see 'go help gopath'). 
-
-If no import paths are given, the action applies to the
-package in the current directory.
-
-The special import path "all" expands to all package directories
-found in all the GOPATH trees.  For example, 'go list all' 
-lists all the packages on the local system.
-
-An import path can also name a package to be downloaded from
-a remote repository.  Run 'go help remote' for details.
-
-Every package in a program must have a unique import path.
-By convention, this is arranged by starting each path with a
-unique prefix that belongs to you.  For example, paths used
-internally at Google all begin with 'google', and paths
-denoting remote repositories begin with the path to the code,
-such as 'project.googlecode.com/'.
----
-
----  go help remote
-An import path (see 'go help importpath') denotes a package
-stored in the local file system.  Certain import paths also
-describe how to obtain the source code for the package using
-a revision control system.
-
-A few common code hosting sites have special syntax:
-
-	BitBucket (Mercurial)
-
-		import "bitbucket.org/user/project"
-		import "bitbucket.org/user/project/sub/directory"
-
-	GitHub (Git)
-
-		import "github.com/user/project"
-		import "github.com/user/project/sub/directory"
-
-	Google Code Project Hosting (Git, Mercurial, Subversion)
-
-		import "project.googlecode.com/git"
-		import "project.googlecode.com/git/sub/directory"
-
-		import "project.googlecode.com/hg"
-		import "project.googlecode.com/hg/sub/directory"
-
-		import "project.googlecode.com/svn/trunk"
-		import "project.googlecode.com/svn/trunk/sub/directory"
-
-	Launchpad (Bazaar)
-
-		import "launchpad.net/project"
-		import "launchpad.net/project/series"
-		import "launchpad.net/project/series/sub/directory"
-
-		import "launchpad.net/~user/project/branch"
-		import "launchpad.net/~user/project/branch/sub/directory"
-
-For code hosted on other servers, an import path of the form
-
-	repository.vcs/path
-
-specifies the given repository, with or without the .vcs suffix,
-using the named version control system, and then the path inside
-that repository.  The supported version control systems are:
-
-	Bazaar      .bzr
-	Git         .git
-	Mercurial   .hg
-	Subversion  .svn
-
-For example,
-
-	import "example.org/user/foo.hg"
-
-denotes the root directory of the Mercurial repository at
-example.org/user/foo or foo.hg, and
-
-	import "example.org/repo.git/foo/bar"
-
-denotes the foo/bar directory of the Git repository at
-example.com/repo or repo.git.
-
-When a version control system supports multiple protocols,
-each is tried in turn when downloading.  For example, a Git
-download tries git://, then https://, then http://.
-
-New downloaded packages are written to the first directory
-listed in the GOPATH environment variable (see 'go help gopath').
-
-The go command attempts to download the version of the
-package appropriate for the Go release being used.
-Run 'go help install' for more.
----
-
diff --git a/src/cmd/go/test.bash b/src/cmd/go/test.bash
deleted file mode 100755
index e0f066f..0000000
--- a/src/cmd/go/test.bash
+++ /dev/null
@@ -1,1123 +0,0 @@
-#!/bin/bash
-# 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.
-
-set -e
-go build -tags testgo -o testgo
-go() {
-	echo TEST ERROR: ran go, not testgo: go "$@" >&2
-	exit 2
-}
-
-started=false
-testdesc=""
-nl="
-"
-TEST() {
-	if $started; then
-		stop
-	fi
-	echo TEST: "$@"
-	testdesc="$@"
-	started=true
-	ok=true
-}
-stop() {
-	if ! $started; then
-		echo TEST ERROR: stop missing start >&2
-		exit 2
-	fi
-	started=false
-	if $ok; then
-		echo PASS
-	else
-		echo FAIL
-		testfail="$testfail	$testdesc$nl"
-		allok=false
-	fi
-}
-
-ok=true
-allok=true
-
-unset GOBIN
-unset GOPATH
-unset GOROOT
-
-TEST 'file:line in error messages'
-# Test that error messages have file:line information at beginning of
-# the line. Also test issue 4917: that the error is on stderr.
-d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
-fn=$d/err.go
-echo "package main" > $fn
-echo 'import "bar"' >> $fn
-./testgo run $fn 2>$d/err.out || true
-if ! grep -q "^$fn:" $d/err.out; then
-	echo "missing file:line in error message"
-	cat $d/err.out
-	ok=false
-fi
-rm -r $d
-
-TEST 'program name in crash messages'
-linker=$(./testgo env GOCHAR)l
-d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
-./testgo build -ldflags -crash_for_testing $(./testgo env GOROOT)/test/helloworld.go 2>$d/err.out || true
-if ! grep -q "/tool/.*/$linker" $d/err.out; then
-	echo "missing linker name in error message"
-	cat $d/err.out
-	ok=false
-fi
-rm -r $d
-
-TEST broken tests without Test functions all fail
-d=$(mktemp -d -t testgoXXX)
-./testgo test ./testdata/src/badtest/... >$d/err 2>&1 || true
-if grep -q '^ok' $d/err; then
-	echo test passed unexpectedly:
-	grep '^ok' $d/err
-	ok=false
-elif ! grep -q 'FAIL.*badtest/badexec' $d/err || ! grep -q 'FAIL.*badtest/badsyntax' $d/err || ! grep -q 'FAIL.*badtest/badvar' $d/err; then
-	echo test did not run everything
-	cat $d/err
-	ok=false
-fi
-rm -rf $d
-
-TEST 'go build -a in dev branch'
-./testgo install math || ok=false # should be up to date already but just in case
-d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
-if ! TESTGO_IS_GO_RELEASE=0 ./testgo build -v -a math 2>$d/err.out; then
-	cat $d/err.out
-	ok=false
-elif ! grep -q runtime $d/err.out; then
-	echo "testgo build -a math in dev branch DID NOT build runtime, but should have"
-	cat $d/err.out
-	ok=false
-fi
-rm -r $d
-
-TEST 'go build -a in release branch'
-./testgo install math || ok=false # should be up to date already but just in case
-d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
-if ! TESTGO_IS_GO_RELEASE=1 ./testgo build -v -a math 2>$d/err.out; then
-	cat $d/err.out
-	ok=false
-elif grep -q runtime $d/err.out; then
-	echo "testgo build -a math in dev branch DID build runtime, but should NOT have"
-	cat $d/err.out
-	ok=false
-fi
-rm -r $d
-
-# Test local (./) imports.
-testlocal() {
-	local="$1"
-	TEST local imports $2 '(easy)'
-	./testgo build -o hello "testdata/$local/easy.go" || ok=false
-	./hello >hello.out || ok=false
-	if ! grep -q '^easysub\.Hello' hello.out; then
-		echo "testdata/$local/easy.go did not generate expected output"
-		cat hello.out
-		ok=false
-	fi
-	
-	TEST local imports $2 '(easysub)'
-	./testgo build -o hello "testdata/$local/easysub/main.go" || ok=false
-	./hello >hello.out || ok=false
-	if ! grep -q '^easysub\.Hello' hello.out; then
-		echo "testdata/$local/easysub/main.go did not generate expected output"
-		cat hello.out
-		ok=false
-	fi
-	
-	TEST local imports $2 '(hard)'
-	./testgo build -o hello "testdata/$local/hard.go" || ok=false
-	./hello >hello.out || ok=false
-	if ! grep -q '^sub\.Hello' hello.out || ! grep -q '^subsub\.Hello' hello.out ; then
-		echo "testdata/$local/hard.go did not generate expected output"
-		cat hello.out
-		ok=false
-	fi
-	
-	rm -f hello.out hello
-	
-	# Test that go install x.go fails.
-	TEST local imports $2 '(go install should fail)'
-	if ./testgo install "testdata/$local/easy.go" >/dev/null 2>&1; then
-		echo "go install testdata/$local/easy.go succeeded"
-		ok=false
-	fi
-}
-
-# Test local imports
-testlocal local ''
-
-# Test local imports again, with bad characters in the directory name.
-bad='#$%:, &()*;<=>?\^{}'
-rm -rf "testdata/$bad"
-cp -R testdata/local "testdata/$bad"
-testlocal "$bad" 'with bad characters in path'
-rm -rf "testdata/$bad"
-
-TEST 'internal packages in $GOROOT are respected'
-if ./testgo build -v ./testdata/testinternal >testdata/std.out 2>&1; then
-	echo "go build ./testdata/testinternal succeeded incorrectly"
-	ok=false
-elif ! grep 'use of internal package not allowed' testdata/std.out >/dev/null; then
-	echo "wrong error message for testdata/testinternal"
-	cat std.out
-	ok=false
-fi
-
-TEST 'internal packages outside $GOROOT are not respected'
-if ! ./testgo build -v ./testdata/testinternal2; then
-	echo "go build ./testdata/testinternal2 failed"
-	ok=false
-fi
-
-# Test that 'go get -u' reports moved packages.
-testmove() {
-	vcs=$1
-	url=$2
-	base=$3
-	config=$4
-
-	TEST go get -u notices $vcs package that moved
-	d=$(mktemp -d -t testgoXXX)
-	mkdir -p $d/src
-	if ! GOPATH=$d ./testgo get -d $url; then
-		echo 'go get -d $url failed'
-		ok=false
-	elif ! GOPATH=$d ./testgo get -d -u $url; then
-		echo 'go get -d -u $url failed'
-		ok=false
-	else
-		set +e
-		case "$vcs" in
-		svn)
-			# SVN doesn't believe in text files so we can't just edit the config.
-			# Check out a different repo into the wrong place.
-			rm -rf $d/src/code.google.com/p/rsc-svn
-			GOPATH=$d ./testgo get -d -u code.google.com/p/rsc-svn2/trunk
-			mv $d/src/code.google.com/p/rsc-svn2 $d/src/code.google.com/p/rsc-svn
-			;;
-		*)
-			echo '1,$s;'"$base"';'"$base"'XXX;
-w
-q' | ed $d/src/$config >/dev/null 2>&1
-		esac
-		set -e
-
-		if GOPATH=$d ./testgo get -d -u $url 2>$d/err; then
-			echo "go get -d -u $url succeeded with wrong remote repo"
-			cat $d/err
-			ok=false
-		elif ! grep 'should be from' $d/err >/dev/null; then
-			echo "go get -d -u $url failed for wrong reason"
-			cat $d/err
-			ok=false
-		fi
-		
-		if GOPATH=$d ./testgo get -d -f -u $url 2>$d/err; then
-			echo "go get -d -u $url succeeded with wrong remote repo"
-			cat $d/err
-			ok=false
-		elif ! egrep -i 'validating server certificate|not found' $d/err >/dev/null; then
-			echo "go get -d -f -u $url failed for wrong reason"
-			cat $d/err
-			ok=false
-		fi
-	fi
-	rm -rf $d
-}
-
-testmove hg rsc.io/x86/x86asm x86 rsc.io/x86/.hg/hgrc
-testmove git rsc.io/pdf pdf rsc.io/pdf/.git/config
-testmove svn code.google.com/p/rsc-svn/trunk - -
-
-export GOPATH=$(pwd)/testdata/importcom
-TEST 'import comment - match'
-if ! ./testgo build ./testdata/importcom/works.go; then
-	echo 'go build ./testdata/importcom/works.go failed'
-	ok=false
-fi
-TEST 'import comment - mismatch'
-if ./testgo build ./testdata/importcom/wrongplace.go 2>testdata/err; then
-	echo 'go build ./testdata/importcom/wrongplace.go suceeded'
-	ok=false
-elif ! grep 'wrongplace expects import "my/x"' testdata/err >/dev/null; then
-	echo 'go build did not mention incorrect import:'
-	cat testdata/err
-	ok=false
-fi
-TEST 'import comment - syntax error'
-if ./testgo build ./testdata/importcom/bad.go 2>testdata/err; then
-	echo 'go build ./testdata/importcom/bad.go suceeded'
-	ok=false
-elif ! grep 'cannot parse import comment' testdata/err >/dev/null; then
-	echo 'go build did not mention syntax error:'
-	cat testdata/err
-	ok=false
-fi
-TEST 'import comment - conflict'
-if ./testgo build ./testdata/importcom/conflict.go 2>testdata/err; then
-	echo 'go build ./testdata/importcom/conflict.go suceeded'
-	ok=false
-elif ! grep 'found import comments' testdata/err >/dev/null; then
-	echo 'go build did not mention comment conflict:'
-	cat testdata/err
-	ok=false
-fi
-rm -f ./testdata/err
-unset GOPATH
-
-export GOPATH=$(pwd)/testdata/src
-TEST disallowed C source files
-export GOPATH=$(pwd)/testdata
-if ./testgo build badc 2>testdata/err; then
-	echo 'go build badc succeeded'
-	ok=false
-elif ! grep 'C source files not allowed' testdata/err >/dev/null; then
-	echo 'go test did not say C source files not allowed:'
-	cat testdata/err
-	ok=false
-fi
-rm -f ./testdata/err
-unset GOPATH
-
-TEST error message for syntax error in test go file says FAIL
-export GOPATH=$(pwd)/testdata
-if ./testgo test syntaxerror 2>testdata/err; then
-	echo 'go test syntaxerror succeeded'
-	ok=false
-elif ! grep FAIL testdata/err >/dev/null; then
-	echo 'go test did not say FAIL:'
-	cat testdata/err
-	ok=false
-fi
-rm -f ./testdata/err
-unset GOPATH
-
-TEST wildcards do not look in useless directories
-export GOPATH=$(pwd)/testdata
-if ./testgo list ... >testdata/err 2>&1; then
-	echo "go list ... succeeded"
-	ok=false
-elif ! grep badpkg testdata/err >/dev/null; then
-	echo "go list ... failure does not mention badpkg"
-	cat testdata/err
-	ok=false
-elif ! ./testgo list m... >testdata/err 2>&1; then
-	echo "go list m... failed"
-	ok=false
-fi
-rm -rf ./testdata/err
-unset GOPATH
-
-# Test tests with relative imports.
-TEST relative imports '(go test)'
-if ! ./testgo test ./testdata/testimport; then
-	echo "go test ./testdata/testimport failed"
-	ok=false
-fi
-
-# Test installation with relative imports.
-TEST relative imports '(go test -i)'
-if ! ./testgo test -i ./testdata/testimport; then
-    echo "go test -i ./testdata/testimport failed"
-    ok=false
-fi
-
-# Test tests with relative imports in packages synthesized
-# from Go files named on the command line.
-TEST relative imports in command-line package
-if ! ./testgo test ./testdata/testimport/*.go; then
-	echo "go test ./testdata/testimport/*.go failed"
-	ok=false
-fi
-
-TEST version control error message includes correct directory
-export GOPATH=$(pwd)/testdata/shadow/root1
-if ./testgo get -u foo 2>testdata/err; then
-	echo "go get -u foo succeeded unexpectedly"
-	ok=false
-elif ! grep testdata/shadow/root1/src/foo testdata/err >/dev/null; then
-	echo "go get -u error does not mention shadow/root1/src/foo:"
-	cat testdata/err
-	ok=false
-fi
-unset GOPATH
-
-TEST go install fails with no buildable files
-export GOPATH=$(pwd)/testdata
-export CGO_ENABLED=0
-if ./testgo install cgotest 2>testdata/err; then
-	echo "go install cgotest succeeded unexpectedly"
-elif ! grep 'no buildable Go source files' testdata/err >/dev/null; then
-	echo "go install cgotest did not report 'no buildable Go source files'"
-	cat testdata/err
-	ok=false
-fi
-unset CGO_ENABLED
-unset GOPATH
-
-# Test that without $GOBIN set, binaries get installed
-# into the GOPATH bin directory.
-TEST install into GOPATH
-rm -rf testdata/bin
-if ! GOPATH=$(pwd)/testdata ./testgo install go-cmd-test; then
-	echo "go install go-cmd-test failed"
-	ok=false
-elif ! test -x testdata/bin/go-cmd-test; then
-	echo "go install go-cmd-test did not write to testdata/bin/go-cmd-test"
-	ok=false
-fi
-
-TEST package main_test imports archive not binary
-export GOBIN=$(pwd)/testdata/bin
-mkdir -p $GOBIN
-export GOPATH=$(pwd)/testdata
-touch ./testdata/src/main_test/m.go
-if ! ./testgo test main_test; then
-	echo "go test main_test failed without install"
-	ok=false
-elif ! ./testgo install main_test; then
-	echo "go test main_test failed"
-	ok=false
-elif [ "$(./testgo list -f '{{.Stale}}' main_test)" != false ]; then
-	echo "after go install, main listed as stale"
-	ok=false
-elif ! ./testgo test main_test; then
-	echo "go test main_test failed after install"
-	ok=false
-fi
-rm -rf $GOBIN
-unset GOBIN
-
-# And with $GOBIN set, binaries get installed to $GOBIN.
-TEST install into GOBIN
-if ! GOBIN=$(pwd)/testdata/bin1 GOPATH=$(pwd)/testdata ./testgo install go-cmd-test; then
-	echo "go install go-cmd-test failed"
-	ok=false
-elif ! test -x testdata/bin1/go-cmd-test; then
-	echo "go install go-cmd-test did not write to testdata/bin1/go-cmd-test"
-	ok=false
-fi
-
-# Without $GOBIN set, installing a program outside $GOPATH should fail
-# (there is nowhere to install it).
-TEST install without destination fails
-if ./testgo install testdata/src/go-cmd-test/helloworld.go 2>testdata/err; then
-	echo "go install testdata/src/go-cmd-test/helloworld.go should have failed, did not"
-	ok=false
-elif ! grep 'no install location for .go files listed on command line' testdata/err; then
-	echo "wrong error:"
-	cat testdata/err
-	ok=false
-fi
-rm -f testdata/err
-
-# With $GOBIN set, should install there.
-TEST install to GOBIN '(command-line package)'
-if ! GOBIN=$(pwd)/testdata/bin1 ./testgo install testdata/src/go-cmd-test/helloworld.go; then
-	echo "go install testdata/src/go-cmd-test/helloworld.go failed"
-	ok=false
-elif ! test -x testdata/bin1/helloworld; then
-	echo "go install testdata/src/go-cmd-test/helloworld.go did not write testdata/bin1/helloworld"
-	ok=false
-fi
-
-TEST godoc installs into GOBIN
-d=$(mktemp -d -t testgoXXX)
-export GOPATH=$d
-mkdir $d/gobin
-GOBIN=$d/gobin ./testgo get golang.org/x/tools/cmd/godoc || ok=false
-if [ ! -x $d/gobin/godoc ]; then
-	echo did not install godoc to '$GOBIN'
-	GOBIN=$d/gobin ./testgo list -f 'Target: {{.Target}}' golang.org/x/tools/cmd/godoc || true
-	ok=false
-fi
-
-TEST godoc installs into GOROOT
-GOROOT=$(./testgo env GOROOT)
-rm -f $GOROOT/bin/godoc
-./testgo install golang.org/x/tools/cmd/godoc || ok=false
-if [ ! -x $GOROOT/bin/godoc ]; then
-	echo did not install godoc to '$GOROOT/bin'
-	./testgo list -f 'Target: {{.Target}}' golang.org/x/tools/cmd/godoc || true
-	ok=false
-fi
-
-TEST cmd/fix installs into tool
-GOOS=$(./testgo env GOOS)
-GOARCH=$(./testgo env GOARCH)
-rm -f $GOROOT/pkg/tool/${GOOS}_${GOARCH}/fix
-./testgo install cmd/fix || ok=false
-if [ ! -x $GOROOT/pkg/tool/${GOOS}_${GOARCH}/fix ]; then
-	echo 'did not install cmd/fix to $GOROOT/pkg/tool'
-	GOBIN=$d/gobin ./testgo list -f 'Target: {{.Target}}' cmd/fix || true
-	ok=false
-fi
-rm -f $GOROOT/pkg/tool/${GOOS}_${GOARCH}/fix
-GOBIN=$d/gobin ./testgo install cmd/fix || ok=false
-if [ ! -x $GOROOT/pkg/tool/${GOOS}_${GOARCH}/fix ]; then
-	echo 'did not install cmd/fix to $GOROOT/pkg/tool with $GOBIN set'
-	GOBIN=$d/gobin ./testgo list -f 'Target: {{.Target}}' cmd/fix || true
-	ok=false
-fi
-
-TEST gopath program installs into GOBIN
-mkdir $d/src/progname
-echo 'package main; func main() {}' >$d/src/progname/p.go
-GOBIN=$d/gobin ./testgo install progname || ok=false
-if [ ! -x $d/gobin/progname ]; then
-	echo 'did not install progname to $GOBIN/progname'
-	./testgo list -f 'Target: {{.Target}}' cmd/api || true
-	ok=false
-fi
-rm -f $d/gobin/progname $d/bin/progname
-
-TEST gopath program installs into GOPATH/bin
-./testgo install progname || ok=false
-if [ ! -x $d/bin/progname ]; then
-	echo 'did not install progname to $GOPATH/bin/progname'
-	./testgo list -f 'Target: {{.Target}}' progname || true
-	ok=false
-fi
-
-unset GOPATH
-rm -rf $d
-
-# Reject relative paths in GOPATH.
-TEST reject relative paths in GOPATH '(command-line package)'
-if GOPATH=. ./testgo build testdata/src/go-cmd-test/helloworld.go; then
-    echo 'GOPATH="." go build should have failed, did not'
-    ok=false
-fi
-
-TEST reject relative paths in GOPATH 
-if GOPATH=:$(pwd)/testdata:. ./testgo build go-cmd-test; then
-    echo 'GOPATH=":$(pwd)/testdata:." go build should have failed, did not'
-    ok=false
-fi
-
-# issue 4104
-TEST go test with package listed multiple times
-if [ $(./testgo test fmt fmt fmt fmt fmt | wc -l) -ne 1 ] ; then
-    echo 'go test fmt fmt fmt fmt fmt tested the same package multiple times'
-    ok=false
-fi
-
-# ensure that output of 'go list' is consistent between runs
-TEST go list is consistent
-./testgo list std > test_std.list || ok=false
-if ! ./testgo list std | cmp -s test_std.list - ; then
-	echo "go list std ordering is inconsistent"
-	ok=false
-fi
-rm -f test_std.list
-
-# issue 4096. Validate the output of unsuccessful go install foo/quxx 
-TEST unsuccessful go install should mention missing package
-if [ $(./testgo install 'foo/quxx' 2>&1 | grep -c 'cannot find package "foo/quxx" in any of') -ne 1 ] ; then
-	echo 'go install foo/quxx expected error: .*cannot find package "foo/quxx" in any of'
-	ok=false
-fi 
-# test GOROOT search failure is reported
-TEST GOROOT search failure reporting
-if [ $(./testgo install 'foo/quxx' 2>&1 | egrep -c 'foo/quxx \(from \$GOROOT\)$') -ne 1 ] ; then
-        echo 'go install foo/quxx expected error: .*foo/quxx (from $GOROOT)'
-        ok=false
-fi
-# test multiple GOPATH entries are reported separately
-TEST multiple GOPATH entries reported separately
-if [ $(GOPATH=$(pwd)/testdata/a:$(pwd)/testdata/b ./testgo install 'foo/quxx' 2>&1 | egrep -c 'testdata/./src/foo/quxx') -ne 2 ] ; then
-        echo 'go install foo/quxx expected error: .*testdata/a/src/foo/quxx (from $GOPATH)\n.*testdata/b/src/foo/quxx'
-        ok=false
-fi
-# test (from $GOPATH) annotation is reported for the first GOPATH entry
-TEST mention GOPATH in first GOPATH entry
-if [ $(GOPATH=$(pwd)/testdata/a:$(pwd)/testdata/b ./testgo install 'foo/quxx' 2>&1 | egrep -c 'testdata/a/src/foo/quxx \(from \$GOPATH\)$') -ne 1 ] ; then
-        echo 'go install foo/quxx expected error: .*testdata/a/src/foo/quxx (from $GOPATH)'
-        ok=false
-fi
-# but not on the second
-TEST but not the second entry
-if [ $(GOPATH=$(pwd)/testdata/a:$(pwd)/testdata/b ./testgo install 'foo/quxx' 2>&1 | egrep -c 'testdata/b/src/foo/quxx$') -ne 1 ] ; then
-        echo 'go install foo/quxx expected error: .*testdata/b/src/foo/quxx'
-        ok=false
-fi
-# test missing GOPATH is reported
-TEST missing GOPATH is reported
-if [ $(GOPATH= ./testgo install 'foo/quxx' 2>&1 | egrep -c '\(\$GOPATH not set\)$') -ne 1 ] ; then
-        echo 'go install foo/quxx expected error: ($GOPATH not set)'
-        ok=false
-fi
-
-# issue 4186. go get cannot be used to download packages to $GOROOT
-# Test that without GOPATH set, go get should fail
-TEST without GOPATH, go get fails
-d=$(mktemp -d -t testgoXXX)
-mkdir -p $d/src
-if GOPATH= GOROOT=$d ./testgo get -d golang.org/x/codereview/cmd/hgpatch ; then 
-	echo 'go get golang.org/x/codereview/cmd/hgpatch should not succeed with $GOPATH unset'
-	ok=false
-fi	
-rm -rf $d
-
-# Test that with GOPATH=$GOROOT, go get should fail
-TEST with GOPATH=GOROOT, go get fails
-d=$(mktemp -d -t testgoXXX)
-mkdir -p $d/src
-if GOPATH=$d GOROOT=$d ./testgo get -d golang.org/x/codereview/cmd/hgpatch ; then
-        echo 'go get golang.org/x/codereview/cmd/hgpatch should not succeed with GOPATH=$GOROOT'
-        ok=false
-fi
-rm -rf $d
-
-TEST ldflags arguments with spaces '(issue 3941)'
-d=$(mktemp -d -t testgoXXX)
-cat >$d/main.go<<EOF
-package main
-var extern string
-func main() {
-	println(extern)
-}
-EOF
-./testgo run -ldflags '-X main.extern "hello world"' $d/main.go 2>hello.out || ok=false
-if ! grep -q '^hello world' hello.out; then
-	echo "ldflags -X main.extern 'hello world' failed. Output:"
-	cat hello.out
-	ok=false
-fi
-rm -rf $d hello.out
-
-TEST go test -cpuprofile leaves binary behind
-./testgo test -cpuprofile strings.prof strings || ok=false
-if [ ! -x strings.test ]; then
-	echo "go test -cpuprofile did not create strings.test"
-	ok=false
-fi
-rm -f strings.prof strings.test
-
-TEST go test -cpuprofile -o controls binary location
-./testgo test -cpuprofile strings.prof -o mystrings.test strings || ok=false
-if [ ! -x mystrings.test ]; then
-	echo "go test -cpuprofile -o mystrings.test did not create mystrings.test"
-	ok=false
-fi
-rm -f strings.prof mystrings.test
-
-TEST go test -c -o controls binary location
-./testgo test -c -o mystrings.test strings || ok=false
-if [ ! -x mystrings.test ]; then
-	echo "go test -c -o mystrings.test did not create mystrings.test"
-	ok=false
-fi
-rm -f mystrings.test
-
-TEST go test -o writes binary
-./testgo test -o mystrings.test strings || ok=false
-if [ ! -x mystrings.test ]; then
-	echo "go test -o mystrings.test did not create mystrings.test"
-	ok=false
-fi
-rm -f mystrings.test
-
-TEST symlinks do not confuse go list '(issue 4568)'
-old=$(pwd)
-tmp=$(cd /tmp && pwd -P)
-d=$(TMPDIR=$tmp mktemp -d -t testgoXXX)
-mkdir -p $d/src
-(
-	ln -s $d $d/src/dir1
-	cd $d/src
-	echo package p >dir1/p.go
-	export GOPATH=$d
-	if [ "$($old/testgo list -f '{{.Root}}' dir1)" != "$d" ]; then
-		echo Confused by symlinks.
-		echo "Package in current directory $(pwd) should have Root $d"
-		env|grep WD
-		$old/testgo list -json . dir1
-		touch $d/failed
-	fi		
-)
-if [ -f $d/failed ]; then
-	ok=false
-fi
-rm -rf $d
-
-TEST 'install with tags (issue 4515)'
-d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
-mkdir -p $d/src/example/a $d/src/example/b $d/bin
-cat >$d/src/example/a/main.go <<EOF
-package main
-func main() {}
-EOF
-cat >$d/src/example/b/main.go <<EOF
-// +build mytag
-
-package main
-func main() {}
-EOF
-GOPATH=$d ./testgo install -tags mytag example/a example/b || ok=false
-if [ ! -x $d/bin/a -o ! -x $d/bin/b ]; then
-	echo go install example/a example/b did not install binaries
-	ok=false
-fi
-rm -f $d/bin/*
-GOPATH=$d ./testgo install -tags mytag example/... || ok=false
-if [ ! -x $d/bin/a -o ! -x $d/bin/b ]; then
-	echo go install example/... did not install binaries
-	ok=false
-fi
-rm -f $d/bin/*go
-export GOPATH=$d
-if [ "$(./testgo list -tags mytag example/b...)" != "example/b" ]; then
-	echo go list example/b did not find example/b
-	ok=false
-fi
-unset GOPATH
-rm -rf $d
-
-TEST case collisions '(issue 4773)'
-d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
-export GOPATH=$d
-mkdir -p $d/src/example/{a/pkg,a/Pkg,b}
-cat >$d/src/example/a/a.go <<EOF
-package p
-import (
-	_ "example/a/pkg"
-	_ "example/a/Pkg"
-)
-EOF
-cat >$d/src/example/a/pkg/pkg.go <<EOF
-package pkg
-EOF
-cat >$d/src/example/a/Pkg/pkg.go <<EOF
-package pkg
-EOF
-if ./testgo list example/a 2>$d/out; then
-	echo go list example/a should have failed, did not.
-	ok=false
-elif ! grep "case-insensitive import collision" $d/out >/dev/null; then
-	echo go list example/a did not report import collision.
-	ok=false
-fi
-cat >$d/src/example/b/file.go <<EOF
-package b
-EOF
-cat >$d/src/example/b/FILE.go <<EOF
-package b
-EOF
-if [ $(ls $d/src/example/b | wc -l) = 2 ]; then
-	# case-sensitive file system, let directory read find both files
-	args="example/b"
-else
-	# case-insensitive file system, list files explicitly on command line.
-	args="$d/src/example/b/file.go $d/src/example/b/FILE.go"
-fi
-if ./testgo list $args 2>$d/out; then
-	echo go list example/b should have failed, did not.
-	ok=false
-elif ! grep "case-insensitive file name collision" $d/out >/dev/null; then
-	echo go list example/b did not report file name collision.
-	ok=false
-fi
-
-TEST go get cover
-./testgo get golang.org/x/tools/cmd/cover || ok=false
-
-unset GOPATH
-rm -rf $d
-
-TEST go get -t "code.google.com/p/go-get-issue-8181/{a,b}"
-d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
-export GOPATH=$d
-if ./testgo get -t code.google.com/p/go-get-issue-8181/{a,b}; then
-	./testgo list ... | grep go.tools/godoc > /dev/null || ok=false
-else
-	ok=false
-fi
-unset GOPATH
-rm -rf $d
-
-TEST shadowing logic
-export GOPATH=$(pwd)/testdata/shadow/root1:$(pwd)/testdata/shadow/root2
-
-# The math in root1 is not "math" because the standard math is.
-set +e
-cdir=$(./testgo list -f '({{.ImportPath}}) ({{.ConflictDir}})' ./testdata/shadow/root1/src/math)
-set -e
-if [ "$cdir" != "(_$(pwd)/testdata/shadow/root1/src/math) ($GOROOT/src/math)" ]; then
-	echo shadowed math is not shadowed: "$cdir"
-	ok=false
-fi
-
-# The foo in root1 is "foo".
-set +e
-cdir=$(./testgo list -f '({{.ImportPath}}) ({{.ConflictDir}})' ./testdata/shadow/root1/src/foo)
-set -e
-if [ "$cdir" != "(foo) ()" ]; then
-	echo unshadowed foo is shadowed: "$cdir"
-	ok=false
-fi
-
-# The foo in root2 is not "foo" because the foo in root1 got there first.
-set +e
-cdir=$(./testgo list -f '({{.ImportPath}}) ({{.ConflictDir}})' ./testdata/shadow/root2/src/foo)
-set -e
-if [ "$cdir" != "(_$(pwd)/testdata/shadow/root2/src/foo) ($(pwd)/testdata/shadow/root1/src/foo)" ]; then
-	echo shadowed foo is not shadowed: "$cdir"
-	ok=false
-fi
-
-# The error for go install should mention the conflicting directory.
-set +e
-err=$(./testgo install ./testdata/shadow/root2/src/foo 2>&1)
-set -e
-if [ "$err" != "go install: no install location for $(pwd)/testdata/shadow/root2/src/foo: hidden by $(pwd)/testdata/shadow/root1/src/foo" ]; then
-	echo wrong shadowed install error: "$err"
-	ok=false
-fi
-
-# Only succeeds if source order is preserved.
-TEST source file name order preserved
-./testgo test testdata/example[12]_test.go || ok=false
-
-# Check that coverage analysis works at all.
-# Don't worry about the exact numbers but require not 0.0%.
-checkcoverage() {
-	if grep '[^0-9]0\.0%' testdata/cover.txt >/dev/null; then
-		echo 'some coverage results are 0.0%'
-		ok=false
-	fi
-	cat testdata/cover.txt
-	rm -f testdata/cover.txt
-}
-	
-TEST coverage runs
-./testgo test -short -coverpkg=strings strings regexp >testdata/cover.txt 2>&1 || ok=false
-./testgo test -short -cover strings math regexp >>testdata/cover.txt 2>&1 || ok=false
-checkcoverage
-
-# Check that coverage analysis uses set mode.
-TEST coverage uses set mode
-if ./testgo test -short -cover encoding/binary -coverprofile=testdata/cover.out >testdata/cover.txt 2>&1; then
-	if ! grep -q 'mode: set' testdata/cover.out; then
-		ok=false
-	fi
-	checkcoverage
-else
-	ok=false
-fi
-rm -f testdata/cover.out testdata/cover.txt
-
-TEST coverage uses atomic mode for -race.
-if ./testgo test -short -race -cover encoding/binary -coverprofile=testdata/cover.out >testdata/cover.txt 2>&1; then
-	if ! grep -q 'mode: atomic' testdata/cover.out; then
-		ok=false
-	fi
-	checkcoverage
-else
-	ok=false
-fi
-rm -f testdata/cover.out
-
-TEST coverage uses actual setting to override even for -race.
-if ./testgo test -short -race -cover encoding/binary -covermode=count -coverprofile=testdata/cover.out >testdata/cover.txt 2>&1; then
-	if ! grep -q 'mode: count' testdata/cover.out; then
-		ok=false
-	fi
-	checkcoverage
-else
-	ok=false
-fi
-rm -f testdata/cover.out
-
-TEST coverage with cgo
-d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
-./testgo test -short -cover ./testdata/cgocover >testdata/cover.txt 2>&1 || ok=false
-checkcoverage
-
-TEST cgo depends on syscall
-rm -rf $GOROOT/pkg/*_race
-d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
-export GOPATH=$d
-mkdir -p $d/src/foo
-echo '
-package foo
-//#include <stdio.h>
-import "C"
-' >$d/src/foo/foo.go
-./testgo build -race foo || ok=false
-rm -rf $d
-unset GOPATH
-
-TEST cgo shows full path names
-d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
-export GOPATH=$d
-mkdir -p $d/src/x/y/dirname
-echo '
-package foo
-import "C"
-func f() {
-' >$d/src/x/y/dirname/foo.go
-if ./testgo build x/y/dirname >$d/err 2>&1; then
-	echo build succeeded unexpectedly.
-	ok=false
-elif ! grep x/y/dirname $d/err >/dev/null; then
-	echo error did not use full path.
-	cat $d/err
-	ok=false
-fi
-rm -rf $d
-unset GOPATH
-
-TEST 'cgo handles -Wl,$ORIGIN'
-d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
-export GOPATH=$d
-mkdir -p $d/src/origin
-echo '
-package origin
-// #cgo !darwin LDFLAGS: -Wl,-rpath -Wl,$ORIGIN
-// void f(void) {}
-import "C"
-
-func f() { C.f() }
-' >$d/src/origin/origin.go
-if ! ./testgo build origin; then
-	echo build failed
-	ok=false
-fi
-rm -rf $d
-unset GOPATH
-
-TEST 'Issue 6480: "go test -c -test.bench=XXX fmt" should not hang'
-if ! ./testgo test -c -test.bench=XXX fmt; then
-	echo build test failed
-	ok=false
-fi
-rm -f fmt.test
-
-TEST 'Issue 7573: cmd/cgo: undefined reference when linking a C-library using gccgo'
-d=$(mktemp -d -t testgoXXX)
-export GOPATH=$d
-mkdir -p $d/src/cgoref
-ldflags="-L alibpath -lalib"
-echo "
-package main
-// #cgo LDFLAGS: $ldflags
-// void f(void) {}
-import \"C\"
-
-func main() { C.f() }
-" >$d/src/cgoref/cgoref.go
-go_cmds="$(./testgo build -n -compiler gccgo cgoref 2>&1 1>/dev/null)"
-ldflags_count="$(echo "$go_cmds" | egrep -c "^gccgo.*$(echo $ldflags | sed -e 's/-/\\-/g')" || true)"
-if [ "$ldflags_count" -lt 1 ]; then
-	echo "No Go-inline "#cgo LDFLAGS:" (\"$ldflags\") passed to gccgo linking stage."
-	ok=false
-fi
-rm -rf $d
-unset ldflags_count
-unset go_cmds
-unset ldflags
-unset GOPATH
-
-TEST list template can use context function
-if ! ./testgo list -f "GOARCH: {{context.GOARCH}}"; then 
-	echo unable to use context in list template
-	ok=false
-fi
-
-TEST 'Issue 7108: cmd/go: "go test" should fail if package does not build'
-export GOPATH=$(pwd)/testdata
-if ./testgo test notest >/dev/null 2>&1; then
-	echo 'go test notest succeeded, but should fail'
-	ok=false
-fi
-unset GOPATH
-
-TEST 'Issue 6844: cmd/go: go test -a foo does not rebuild regexp'
-if ! ./testgo test -x -a -c testdata/dep_test.go 2>deplist; then
-	echo "go test -x -a -c testdata/dep_test.go failed"
-	ok=false
-elif ! grep -q regexp deplist; then
-	echo "go test -x -a -c testdata/dep_test.go did not rebuild regexp"
-	ok=false
-fi
-rm -f deplist
-rm -f deps.test
-
-TEST list template can use context function
-if ! ./testgo list -f "GOARCH: {{context.GOARCH}}"; then 
-	echo unable to use context in list template
-	ok=false
-fi
-
-TEST build -i installs dependencies
-d=$(TMPDIR=/var/tmp mktemp -d -t testgoXXX)
-export GOPATH=$d
-mkdir -p $d/src/x/y/foo $d/src/x/y/bar
-echo '
-package foo
-func F() {}
-' >$d/src/x/y/foo/foo.go
-checkbar() {
-	desc="$1"
-	sleep 1
-	touch $d/src/x/y/foo/foo.go
-	if ! ./testgo build -v -i x/y/bar &> $d/err; then
-		echo build -i "$1" failed
-		cat $d/err
-		ok=false
-	elif ! grep x/y/foo $d/err >/dev/null; then
-		echo first build -i "$1" did not build x/y/foo
-		cat $d/err
-		ok=false
-	fi
-	if ! ./testgo build -v -i x/y/bar &> $d/err; then
-		echo second build -i "$1" failed
-		cat $d/err
-		ok=false
-	elif grep x/y/foo $d/err >/dev/null; then
-		echo second build -i "$1" built x/y/foo
-		cat $d/err
-		ok=false
-	fi
-}
-
-echo '
-package bar
-import "x/y/foo"
-func F() { foo.F() }
-' >$d/src/x/y/bar/bar.go
-checkbar pkg
-
-TEST build -i installs dependencies for command
-echo '
-package main
-import "x/y/foo"
-func main() { foo.F() }
-' >$d/src/x/y/bar/bar.go
-checkbar cmd
-
-rm -rf $d bar
-unset GOPATH
-
-TEST 'go build in test-only directory fails with a good error'
-if ./testgo build ./testdata/testonly 2>testdata/err.out; then
-	echo "go build ./testdata/testonly succeeded, should have failed"
-	ok=false
-elif ! grep 'no buildable Go' testdata/err.out >/dev/null; then
-	echo "go build ./testdata/testonly produced unexpected error:"
-	cat testdata/err.out
-	ok=false
-fi
-rm -f testdata/err.out
-
-TEST 'go test detects test-only import cycles'
-export GOPATH=$(pwd)/testdata
-if ./testgo test -c testcycle/p3 2>testdata/err.out; then
-	echo "go test testcycle/p3 succeeded, should have failed"
-	ok=false
-elif ! grep 'import cycle not allowed in test' testdata/err.out >/dev/null; then
-	echo "go test testcycle/p3 produced unexpected error:"
-	cat testdata/err.out
-	ok=false
-fi
-rm -f testdata/err.out
-unset GOPATH
-
-TEST 'go test foo_test.go works'
-if ! ./testgo test testdata/standalone_test.go; then
-	echo "go test testdata/standalone_test.go failed"
-	ok=false
-fi
-
-TEST 'go test xtestonly works'
-export GOPATH=$(pwd)/testdata
-./testgo clean -i xtestonly || ok=false
-if ! ./testgo test xtestonly >/dev/null; then
-	echo "go test xtestonly failed"
-	ok=false
-fi
-unset GOPATH
-
-TEST 'go test builds an xtest containing only non-runnable examples'
-if ! ./testgo test -v ./testdata/norunexample > testdata/std.out; then
-	echo "go test ./testdata/norunexample failed"
-	ok=false
-elif ! grep 'File with non-runnable example was built.' testdata/std.out > /dev/null; then
-	echo "file with non-runnable example was not built"
-	ok=false
-fi
-
-TEST 'go generate handles simple command'
-if ! ./testgo generate ./testdata/generate/test1.go > testdata/std.out; then
-	echo "go test ./testdata/generate/test1.go failed to run"
-	ok=false
-elif ! grep 'Success' testdata/std.out > /dev/null; then
-	echo "go test ./testdata/generate/test1.go generated wrong output"
-	ok=false
-fi
-
-TEST 'go generate handles command alias'
-if ! ./testgo generate ./testdata/generate/test2.go > testdata/std.out; then
-	echo "go test ./testdata/generate/test2.go failed to run"
-	ok=false
-elif ! grep 'Now is the time for all good men' testdata/std.out > /dev/null; then
-	echo "go test ./testdata/generate/test2.go generated wrong output"
-	ok=false
-fi
-
-TEST 'go generate variable substitution'
-if ! ./testgo generate ./testdata/generate/test3.go > testdata/std.out; then
-	echo "go test ./testdata/generate/test3.go failed to run"
-	ok=false
-elif ! grep "$GOARCH test3.go p xyzp/test3.go/123" testdata/std.out > /dev/null; then
-	echo "go test ./testdata/generate/test3.go generated wrong output"
-	ok=false
-fi
-
-TEST go get works with vanity wildcards
-d=$(mktemp -d -t testgoXXX)
-export GOPATH=$d
-if ! ./testgo get -u rsc.io/pdf/...; then
-	ok=false
-elif [ ! -x $d/bin/pdfpasswd ]; then
-	echo did not build rsc.io/pdf/pdfpasswd
-	ok=false
-fi
-unset GOPATH
-rm -rf $d
-
-TEST go vet with external tests
-d=$(mktemp -d -t testgoXXX)
-export GOPATH=$(pwd)/testdata
-if ./testgo vet vetpkg >$d/err 2>&1; then
-	echo "go vet vetpkg passes incorrectly"
-	ok=false
-elif ! grep -q 'missing argument for Printf' $d/err; then
-	echo "go vet vetpkg did not find missing argument for Printf"
-	cat $d/err
-	ok=false
-fi
-unset GOPATH
-rm -rf $d
-
-# clean up
-if $started; then stop; fi
-rm -rf testdata/bin testdata/bin1
-rm -f testgo
-
-if $allok; then
-	echo PASS
-else
-	echo FAIL:
-	echo "$testfail"
-	exit 1
-fi
diff --git a/src/cmd/go/test.go b/src/cmd/go/test.go
index c81e406..ba1ab82 100644
--- a/src/cmd/go/test.go
+++ b/src/cmd/go/test.go
@@ -33,9 +33,11 @@ func init() {
 	cmdTest.Run = runTest
 }
 
+const testUsage = "test [-c] [-i] [build and test flags] [packages] [flags for test binary]"
+
 var cmdTest = &Command{
 	CustomFlags: true,
-	UsageLine:   "test [-c] [-i] [build and test flags] [packages] [flags for test binary]",
+	UsageLine:   testUsage,
 	Short:       "test packages",
 	Long: `
 'Go test' automates testing the packages named by the import paths.
@@ -64,6 +66,21 @@ with source in the current directory, including tests, and runs the tests.
 The package is built in a temporary directory so it does not interfere with the
 non-test installation.
 
+` + strings.TrimSpace(testFlag1) + ` See 'go help testflag' for details.
+
+If the test binary needs any other flags, they should be presented after the
+package names. The go tool treats as a flag the first argument that begins with
+a minus sign that it does not recognize itself; that argument and all subsequent
+arguments are passed as arguments to the test binary.
+
+For more about build flags, see 'go help build'.
+For more about specifying packages, see 'go help packages'.
+
+See also: go build, go vet.
+`,
+}
+
+const testFlag1 = `
 In addition to the build flags, the flags handled by 'go test' itself are:
 
 	-c
@@ -83,21 +100,9 @@ In addition to the build flags, the flags handled by 'go test' itself are:
 		Compile the test binary to the named file.
 		The test still runs (unless -c or -i is specified).
 
-
 The test binary also accepts flags that control execution of the test; these
-flags are also accessible by 'go test'.  See 'go help testflag' for details.
-
-If the test binary needs any other flags, they should be presented after the
-package names. The go tool treats as a flag the first argument that begins with
-a minus sign that it does not recognize itself; that argument and all subsequent
-arguments are passed as arguments to the test binary.
-
-For more about build flags, see 'go help build'.
-For more about specifying packages, see 'go help packages'.
-
-See also: go build, go vet.
-`,
-}
+flags are also accessible by 'go test'.
+`
 
 var helpTestflag = &Command{
 	UsageLine: "testflag",
@@ -107,13 +112,18 @@ The 'go test' command takes both flags that apply to 'go test' itself
 and flags that apply to the resulting test binary.
 
 Several of the flags control profiling and write an execution profile
-suitable for "go tool pprof"; run "go tool pprof help" for more
+suitable for "go tool pprof"; run "go tool pprof -h" for more
 information.  The --alloc_space, --alloc_objects, and --show_bytes
 options of pprof control how the information is presented.
 
 The following flags are recognized by the 'go test' command and
 control the execution of any test:
 
+	` + strings.TrimSpace(testFlag2) + `
+`,
+}
+
+const testFlag2 = `
 	-bench regexp
 	    Run benchmarks matching the regular expression.
 	    By default, no benchmarks run. To run all benchmarks,
@@ -135,12 +145,17 @@ control the execution of any test:
 	-blockprofilerate n
 	    Control the detail provided in goroutine blocking profiles by
 	    calling runtime.SetBlockProfileRate with n.
-	    See 'godoc runtime SetBlockProfileRate'.
+	    See 'go doc runtime.SetBlockProfileRate'.
 	    The profiler aims to sample, on average, one blocking event every
 	    n nanoseconds the program spends blocked.  By default,
 	    if -test.blockprofile is set without this flag, all blocking events
 	    are recorded, equivalent to -test.blockprofilerate=1.
 
+	-count n
+	    Run each test and benchmark n times (default 1).
+	    If -cpu is set, run n times for each GOMAXPROCS value.
+	    Examples are always run once.
+
 	-cover
 	    Enable coverage analysis.
 
@@ -180,7 +195,7 @@ control the execution of any test:
 
 	-memprofilerate n
 	    Enable more precise (and expensive) memory profiles by setting
-	    runtime.MemProfileRate.  See 'godoc runtime MemProfileRate'.
+	    runtime.MemProfileRate.  See 'go doc runtime.MemProfileRate'.
 	    To profile all memory allocations, use -test.memprofilerate=1
 	    and pass --alloc_space flag to the pprof tool.
 
@@ -205,6 +220,11 @@ control the execution of any test:
 
 	-timeout t
 	    If a test runs longer than t, panic.
+	    The default is 10 minutes (10m).
+
+	-trace trace.out
+	    Write an execution trace to the specified file before exiting.
+	    Writes test binary as -c would.
 
 	-v
 	    Verbose output: log all tests as they are run. Also print all
@@ -229,8 +249,7 @@ The test flags that generate profiles (other than for coverage) also
 leave the test binary in pkg.test for use when analyzing the profiles.
 
 Flags not recognized by 'go test' must be placed after any specified packages.
-`,
-}
+`
 
 var helpTestfunc = &Command{
 	UsageLine: "testfunc",
@@ -310,6 +329,7 @@ func runTest(cmd *Command, args []string) {
 	findExecCmd() // initialize cached result
 
 	raceInit()
+	buildModeInit()
 	pkgs := packagesForBuild(pkgArgs)
 	if len(pkgs) == 0 {
 		fatalf("no packages to test")
@@ -342,11 +362,11 @@ func runTest(cmd *Command, args []string) {
 	// been given on the command line (implicit current directory)
 	// or when benchmarking.
 	// Also stream if we're showing output anyway with a
-	// single package under test.  In that case, streaming the
-	// output produces the same result as not streaming,
-	// just more immediately.
+	// single package under test or if parallelism is set to 1.
+	// In these cases, streaming the output produces the same result
+	// as not streaming, just more immediately.
 	testStreamOutput = len(pkgArgs) == 0 || testBench ||
-		(len(pkgs) <= 1 && testShowPass)
+		(testShowPass && (len(pkgs) == 1 || buildP == 1))
 
 	var b builder
 	b.init()
@@ -364,10 +384,10 @@ func runTest(cmd *Command, args []string) {
 			for _, path := range p.Imports {
 				deps[path] = true
 			}
-			for _, path := range p.TestImports {
+			for _, path := range p.vendored(p.TestImports) {
 				deps[path] = true
 			}
-			for _, path := range p.XTestImports {
+			for _, path := range p.vendored(p.XTestImports) {
 				deps[path] = true
 			}
 		}
@@ -376,7 +396,7 @@ func runTest(cmd *Command, args []string) {
 		if deps["C"] {
 			delete(deps, "C")
 			deps["runtime/cgo"] = true
-			if buildContext.GOOS == runtime.GOOS && buildContext.GOARCH == runtime.GOARCH {
+			if goos == runtime.GOOS && goarch == runtime.GOARCH && !buildRace {
 				deps["cmd/cgo"] = true
 			}
 		}
@@ -425,6 +445,10 @@ func runTest(cmd *Command, args []string) {
 
 		// Mark all the coverage packages for rebuilding with coverage.
 		for _, p := range testCoverPkgs {
+			// There is nothing to cover in package unsafe; it comes from the compiler.
+			if p.ImportPath == "unsafe" {
+				continue
+			}
 			p.Stale = true // rebuild
 			p.fake = true  // do not warn about rebuild
 			p.coverMode = testCoverMode
@@ -559,12 +583,17 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
 	var imports, ximports []*Package
 	var stk importStack
 	stk.push(p.ImportPath + " (test)")
-	for _, path := range p.TestImports {
-		p1 := loadImport(path, p.Dir, &stk, p.build.TestImportPos[path])
+	for i, path := range p.TestImports {
+		p1 := loadImport(path, p.Dir, p, &stk, p.build.TestImportPos[path], useVendor)
 		if p1.Error != nil {
 			return nil, nil, nil, p1.Error
 		}
-		if contains(p1.Deps, p.ImportPath) {
+		if len(p1.DepsErrors) > 0 {
+			err := p1.DepsErrors[0]
+			err.Pos = "" // show full import stack
+			return nil, nil, nil, err
+		}
+		if contains(p1.Deps, p.ImportPath) || p1.ImportPath == p.ImportPath {
 			// Same error that loadPackage returns (via reusePackage) in pkg.go.
 			// Can't change that code, because that code is only for loading the
 			// non-test copy of a package.
@@ -575,21 +604,28 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
 			}
 			return nil, nil, nil, err
 		}
+		p.TestImports[i] = p1.ImportPath
 		imports = append(imports, p1)
 	}
 	stk.pop()
 	stk.push(p.ImportPath + "_test")
 	pxtestNeedsPtest := false
-	for _, path := range p.XTestImports {
-		if path == p.ImportPath {
-			pxtestNeedsPtest = true
-			continue
-		}
-		p1 := loadImport(path, p.Dir, &stk, p.build.XTestImportPos[path])
+	for i, path := range p.XTestImports {
+		p1 := loadImport(path, p.Dir, p, &stk, p.build.XTestImportPos[path], useVendor)
 		if p1.Error != nil {
 			return nil, nil, nil, p1.Error
 		}
-		ximports = append(ximports, p1)
+		if len(p1.DepsErrors) > 0 {
+			err := p1.DepsErrors[0]
+			err.Pos = "" // show full import stack
+			return nil, nil, nil, err
+		}
+		if p1.ImportPath == p.ImportPath {
+			pxtestNeedsPtest = true
+		} else {
+			ximports = append(ximports, p1)
+		}
+		p.XTestImports[i] = p1.ImportPath
 	}
 	stk.pop()
 
@@ -683,10 +719,11 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
 			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)
@@ -713,7 +750,7 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
 		if dep == ptest.ImportPath {
 			pmain.imports = append(pmain.imports, ptest)
 		} else {
-			p1 := loadImport(dep, "", &stk, nil)
+			p1 := loadImport(dep, "", nil, &stk, nil, 0)
 			if p1.Error != nil {
 				return nil, nil, nil, p1.Error
 			}
@@ -768,6 +805,12 @@ func (b *builder) test(p *Package) (buildAction, runAction, printAction *action,
 		recompileForTest(pmain, p, ptest, testDir)
 	}
 
+	if buildContext.GOOS == "darwin" {
+		if buildContext.GOARCH == "arm" || buildContext.GOARCH == "arm64" {
+			t.NeedCgo = true
+		}
+	}
+
 	for _, cp := range pmain.imports {
 		if len(cp.coverVars) > 0 {
 			t.Cover = append(t.Cover, coverInfo{cp, cp.coverVars})
@@ -984,7 +1027,7 @@ func (b *builder) runTest(a *action) error {
 
 	cmd := exec.Command(args[0], args[1:]...)
 	cmd.Dir = a.p.Dir
-	cmd.Env = envForDir(cmd.Dir)
+	cmd.Env = envForDir(cmd.Dir, origEnv)
 	var buf bytes.Buffer
 	if testStreamOutput {
 		cmd.Stdout = os.Stdout
@@ -1203,6 +1246,7 @@ type testFuncs struct {
 	NeedTest    bool
 	ImportXtest bool
 	NeedXtest   bool
+	NeedCgo     bool
 	Cover       []coverInfo
 }
 
@@ -1306,6 +1350,10 @@ import (
 {{range $i, $p := .Cover}}
 	_cover{{$i}} {{$p.Package.ImportPath | printf "%q"}}
 {{end}}
+
+{{if .NeedCgo}}
+	_ "runtime/cgo"
+{{end}}
 )
 
 var tests = []testing.InternalTest{
diff --git a/src/cmd/go/testdata/failssh/ssh b/src/cmd/go/testdata/failssh/ssh
new file mode 100755
index 0000000..ecdbef9
--- /dev/null
+++ b/src/cmd/go/testdata/failssh/ssh
@@ -0,0 +1,2 @@
+#!/bin/sh
+exit 1
diff --git a/src/cmd/go/testdata/generate/test3.go b/src/cmd/go/testdata/generate/test3.go
index 41ffb7e..3d6a8a5 100644
--- a/src/cmd/go/testdata/generate/test3.go
+++ b/src/cmd/go/testdata/generate/test3.go
@@ -4,6 +4,6 @@
 
 // Test go generate variable substitution.
 
-//go:generate echo $GOARCH $GOFILE $GOPACKAGE xyz$GOPACKAGE/$GOFILE/123
+//go:generate echo $GOARCH $GOFILE:$GOLINE ${GOPACKAGE}abc xyz$GOPACKAGE/$GOFILE/123
 
 package p
diff --git a/src/cmd/go/testdata/generate/test4.go b/src/cmd/go/testdata/generate/test4.go
new file mode 100644
index 0000000..a7631c4
--- /dev/null
+++ b/src/cmd/go/testdata/generate/test4.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.
+
+// Test -run flag
+
+//go:generate echo oh yes my man
+//go:generate echo no, no, a thousand times no
+
+package p
diff --git a/src/cmd/go/testdata/rundir/sub/sub.go b/src/cmd/go/testdata/rundir/sub/sub.go
new file mode 100644
index 0000000..06ab7d0
--- /dev/null
+++ b/src/cmd/go/testdata/rundir/sub/sub.go
@@ -0,0 +1 @@
+package main
diff --git a/src/cmd/go/testdata/rundir/x.go b/src/cmd/go/testdata/rundir/x.go
new file mode 100644
index 0000000..06ab7d0
--- /dev/null
+++ b/src/cmd/go/testdata/rundir/x.go
@@ -0,0 +1 @@
+package main
diff --git a/src/cmd/go/testdata/src/testcycle/q1/q1.go b/src/cmd/go/testdata/src/testcycle/q1/q1.go
new file mode 100644
index 0000000..7a471f0
--- /dev/null
+++ b/src/cmd/go/testdata/src/testcycle/q1/q1.go
@@ -0,0 +1 @@
+package q1
diff --git a/src/cmd/go/testdata/src/testcycle/q1/q1_test.go b/src/cmd/go/testdata/src/testcycle/q1/q1_test.go
new file mode 100644
index 0000000..ca81bd2
--- /dev/null
+++ b/src/cmd/go/testdata/src/testcycle/q1/q1_test.go
@@ -0,0 +1,6 @@
+package q1
+
+import "testing"
+import _ "testcycle/q1"
+
+func Test(t *testing.T) {}
diff --git a/src/cmd/go/testdata/src/testdep/p1/p1.go b/src/cmd/go/testdata/src/testdep/p1/p1.go
new file mode 100644
index 0000000..a457035
--- /dev/null
+++ b/src/cmd/go/testdata/src/testdep/p1/p1.go
@@ -0,0 +1 @@
+package p1
diff --git a/src/cmd/go/testdata/src/testdep/p1/p1_test.go b/src/cmd/go/testdata/src/testdep/p1/p1_test.go
new file mode 100644
index 0000000..8be7533
--- /dev/null
+++ b/src/cmd/go/testdata/src/testdep/p1/p1_test.go
@@ -0,0 +1,3 @@
+package p1
+
+import _ "testdep/p2"
diff --git a/src/cmd/go/testdata/src/testdep/p2/p2.go b/src/cmd/go/testdata/src/testdep/p2/p2.go
new file mode 100644
index 0000000..15ba2ea
--- /dev/null
+++ b/src/cmd/go/testdata/src/testdep/p2/p2.go
@@ -0,0 +1,3 @@
+package p2
+
+import _ "testdep/p3"
diff --git a/src/cmd/go/testdata/src/testdep/p3/p3.go b/src/cmd/go/testdata/src/testdep/p3/p3.go
new file mode 100644
index 0000000..0219e7f
--- /dev/null
+++ b/src/cmd/go/testdata/src/testdep/p3/p3.go
@@ -0,0 +1,3 @@
+// +build ignore
+
+package ignored
diff --git a/src/cmd/go/testdata/src/vend/bad.go b/src/cmd/go/testdata/src/vend/bad.go
new file mode 100644
index 0000000..57cc595
--- /dev/null
+++ b/src/cmd/go/testdata/src/vend/bad.go
@@ -0,0 +1,3 @@
+package vend
+
+import _ "r"
diff --git a/src/cmd/go/testdata/src/vend/good.go b/src/cmd/go/testdata/src/vend/good.go
new file mode 100644
index 0000000..952ada3
--- /dev/null
+++ b/src/cmd/go/testdata/src/vend/good.go
@@ -0,0 +1,3 @@
+package vend
+
+import _ "p"
diff --git a/src/cmd/go/testdata/src/vend/hello/hello.go b/src/cmd/go/testdata/src/vend/hello/hello.go
new file mode 100644
index 0000000..41dc03e
--- /dev/null
+++ b/src/cmd/go/testdata/src/vend/hello/hello.go
@@ -0,0 +1,10 @@
+package main
+
+import (
+	"fmt"
+	"strings" // really ../vendor/strings
+)
+
+func main() {
+	fmt.Printf("%s\n", strings.Msg)
+}
diff --git a/src/cmd/go/testdata/src/vend/hello/hello_test.go b/src/cmd/go/testdata/src/vend/hello/hello_test.go
new file mode 100644
index 0000000..5e72ada
--- /dev/null
+++ b/src/cmd/go/testdata/src/vend/hello/hello_test.go
@@ -0,0 +1,12 @@
+package main
+
+import (
+	"strings" // really ../vendor/strings
+	"testing"
+)
+
+func TestMsgInternal(t *testing.T) {
+	if strings.Msg != "hello, world" {
+		t.Fatal("unexpected msg: %v", strings.Msg)
+	}
+}
diff --git a/src/cmd/go/testdata/src/vend/hello/hellox_test.go b/src/cmd/go/testdata/src/vend/hello/hellox_test.go
new file mode 100644
index 0000000..96e6049
--- /dev/null
+++ b/src/cmd/go/testdata/src/vend/hello/hellox_test.go
@@ -0,0 +1,12 @@
+package main_test
+
+import (
+	"strings" // really ../vendor/strings
+	"testing"
+)
+
+func TestMsgExternal(t *testing.T) {
+	if strings.Msg != "hello, world" {
+		t.Fatal("unexpected msg: %v", strings.Msg)
+	}
+}
diff --git a/src/cmd/go/testdata/src/vend/subdir/bad.go b/src/cmd/go/testdata/src/vend/subdir/bad.go
new file mode 100644
index 0000000..d0ddaac
--- /dev/null
+++ b/src/cmd/go/testdata/src/vend/subdir/bad.go
@@ -0,0 +1,3 @@
+package subdir
+
+import _ "r"
diff --git a/src/cmd/go/testdata/src/vend/subdir/good.go b/src/cmd/go/testdata/src/vend/subdir/good.go
new file mode 100644
index 0000000..edd0454
--- /dev/null
+++ b/src/cmd/go/testdata/src/vend/subdir/good.go
@@ -0,0 +1,3 @@
+package subdir
+
+import _ "p"
diff --git a/src/cmd/go/testdata/src/vend/vendor/p/p.go b/src/cmd/go/testdata/src/vend/vendor/p/p.go
new file mode 100644
index 0000000..c89cd18
--- /dev/null
+++ b/src/cmd/go/testdata/src/vend/vendor/p/p.go
@@ -0,0 +1 @@
+package p
diff --git a/src/cmd/go/testdata/src/vend/vendor/q/q.go b/src/cmd/go/testdata/src/vend/vendor/q/q.go
new file mode 100644
index 0000000..946e6d9
--- /dev/null
+++ b/src/cmd/go/testdata/src/vend/vendor/q/q.go
@@ -0,0 +1 @@
+package q
diff --git a/src/cmd/go/testdata/src/vend/vendor/strings/msg.go b/src/cmd/go/testdata/src/vend/vendor/strings/msg.go
new file mode 100644
index 0000000..438126b
--- /dev/null
+++ b/src/cmd/go/testdata/src/vend/vendor/strings/msg.go
@@ -0,0 +1,3 @@
+package strings
+
+var Msg = "hello, world"
diff --git a/src/cmd/go/testdata/src/vend/x/invalid/invalid.go b/src/cmd/go/testdata/src/vend/x/invalid/invalid.go
new file mode 100644
index 0000000..e250d5b
--- /dev/null
+++ b/src/cmd/go/testdata/src/vend/x/invalid/invalid.go
@@ -0,0 +1,3 @@
+package invalid
+
+import "vend/x/invalid/vendor/foo"
diff --git a/src/cmd/go/testdata/src/vend/x/vendor/p/p.go b/src/cmd/go/testdata/src/vend/x/vendor/p/p.go
new file mode 100644
index 0000000..c89cd18
--- /dev/null
+++ b/src/cmd/go/testdata/src/vend/x/vendor/p/p.go
@@ -0,0 +1 @@
+package p
diff --git a/src/cmd/go/testdata/src/vend/x/vendor/p/p/p.go b/src/cmd/go/testdata/src/vend/x/vendor/p/p/p.go
new file mode 100644
index 0000000..e12e12c
--- /dev/null
+++ b/src/cmd/go/testdata/src/vend/x/vendor/p/p/p.go
@@ -0,0 +1,3 @@
+package p
+
+import _ "notfound"
diff --git a/src/cmd/go/testdata/src/vend/x/vendor/r/r.go b/src/cmd/go/testdata/src/vend/x/vendor/r/r.go
new file mode 100644
index 0000000..838c177
--- /dev/null
+++ b/src/cmd/go/testdata/src/vend/x/vendor/r/r.go
@@ -0,0 +1 @@
+package r
diff --git a/src/cmd/go/testdata/src/vend/x/x.go b/src/cmd/go/testdata/src/vend/x/x.go
new file mode 100644
index 0000000..ae526eb
--- /dev/null
+++ b/src/cmd/go/testdata/src/vend/x/x.go
@@ -0,0 +1,5 @@
+package x
+
+import _ "p"
+import _ "q"
+import _ "r"
diff --git a/src/cmd/go/testdata/src/vetpkg/c.go b/src/cmd/go/testdata/src/vetpkg/c.go
new file mode 100644
index 0000000..ef5648f
--- /dev/null
+++ b/src/cmd/go/testdata/src/vetpkg/c.go
@@ -0,0 +1,9 @@
+// +build tagtest
+
+package p
+
+import "fmt"
+
+func g() {
+	fmt.Printf("%d", 3, 4)
+}
diff --git a/src/cmd/go/testdata/testinternal3/t.go b/src/cmd/go/testdata/testinternal3/t.go
new file mode 100644
index 0000000..8576a4b
--- /dev/null
+++ b/src/cmd/go/testdata/testinternal3/t.go
@@ -0,0 +1,3 @@
+package t
+
+import _ "internal/does-not-exist"
diff --git a/src/cmd/go/testdata/testinternal4/src/p/p.go b/src/cmd/go/testdata/testinternal4/src/p/p.go
new file mode 100644
index 0000000..6bdee27
--- /dev/null
+++ b/src/cmd/go/testdata/testinternal4/src/p/p.go
@@ -0,0 +1,6 @@
+package p
+
+import (
+	_ "q/internal/x"
+	_ "q/j"
+)
diff --git a/src/cmd/go/testdata/testinternal4/src/q/internal/x/x.go b/src/cmd/go/testdata/testinternal4/src/q/internal/x/x.go
new file mode 100644
index 0000000..823aafd
--- /dev/null
+++ b/src/cmd/go/testdata/testinternal4/src/q/internal/x/x.go
@@ -0,0 +1 @@
+package x
diff --git a/src/cmd/go/testdata/testinternal4/src/q/j/j.go b/src/cmd/go/testdata/testinternal4/src/q/j/j.go
new file mode 100644
index 0000000..9f07543
--- /dev/null
+++ b/src/cmd/go/testdata/testinternal4/src/q/j/j.go
@@ -0,0 +1,3 @@
+package j
+
+import _ "q/internal/x"
diff --git a/src/cmd/go/testdata/testvendor/src/p/p.go b/src/cmd/go/testdata/testvendor/src/p/p.go
new file mode 100644
index 0000000..e740715
--- /dev/null
+++ b/src/cmd/go/testdata/testvendor/src/p/p.go
@@ -0,0 +1,6 @@
+package p
+
+import (
+	_ "q/y"
+	_ "q/z"
+)
diff --git a/src/cmd/go/testdata/testvendor/src/q/vendor/x/x.go b/src/cmd/go/testdata/testvendor/src/q/vendor/x/x.go
new file mode 100644
index 0000000..823aafd
--- /dev/null
+++ b/src/cmd/go/testdata/testvendor/src/q/vendor/x/x.go
@@ -0,0 +1 @@
+package x
diff --git a/src/cmd/go/testdata/testvendor/src/q/y/y.go b/src/cmd/go/testdata/testvendor/src/q/y/y.go
new file mode 100644
index 0000000..4f84223
--- /dev/null
+++ b/src/cmd/go/testdata/testvendor/src/q/y/y.go
@@ -0,0 +1,3 @@
+package y
+
+import _ "x"
diff --git a/src/cmd/go/testdata/testvendor/src/q/z/z.go b/src/cmd/go/testdata/testvendor/src/q/z/z.go
new file mode 100644
index 0000000..a8d4924
--- /dev/null
+++ b/src/cmd/go/testdata/testvendor/src/q/z/z.go
@@ -0,0 +1,3 @@
+package z
+
+import _ "q/vendor/x"
diff --git a/src/cmd/go/testdata/testvendor2/src/p/p.go b/src/cmd/go/testdata/testvendor2/src/p/p.go
new file mode 100644
index 0000000..220b2b2
--- /dev/null
+++ b/src/cmd/go/testdata/testvendor2/src/p/p.go
@@ -0,0 +1,3 @@
+package p
+
+import "x"
diff --git a/src/cmd/go/testdata/testvendor2/vendor/x/x.go b/src/cmd/go/testdata/testvendor2/vendor/x/x.go
new file mode 100644
index 0000000..823aafd
--- /dev/null
+++ b/src/cmd/go/testdata/testvendor2/vendor/x/x.go
@@ -0,0 +1 @@
+package x
diff --git a/src/cmd/go/testflag.go b/src/cmd/go/testflag.go
index 6da74b9..1f3e3d3 100644
--- a/src/cmd/go/testflag.go
+++ b/src/cmd/go/testflag.go
@@ -5,6 +5,7 @@
 package main
 
 import (
+	"flag"
 	"fmt"
 	"os"
 	"strconv"
@@ -16,46 +17,11 @@ import (
 // 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
-  -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
 	boolVar    *bool
+	flagValue  flag.Value
 	passToTest bool // pass to Test
 	multiOK    bool // OK to have multiple instances
 	present    bool // flag has been seen
@@ -65,32 +31,18 @@ type testFlagSpec struct {
 var testFlagDefn = []*testFlagSpec{
 	// local.
 	{name: "c", boolVar: &testC},
+	{name: "i", boolVar: &buildI},
+	{name: "o"},
 	{name: "cover", boolVar: &testCover},
+	{name: "covermode"},
 	{name: "coverpkg"},
-	{name: "o"},
-
-	// build flags.
-	{name: "a", boolVar: &buildA},
-	{name: "n", boolVar: &buildN},
-	{name: "p"},
-	{name: "x", boolVar: &buildX},
-	{name: "i", boolVar: &buildI},
-	{name: "work", boolVar: &buildWork},
-	{name: "ccflags"},
-	{name: "gcflags"},
 	{name: "exec"},
-	{name: "ldflags"},
-	{name: "gccgoflags"},
-	{name: "tags"},
-	{name: "compiler"},
-	{name: "race", boolVar: &buildRace},
-	{name: "installsuffix"},
 
 	// passed to 6.out, adding a "test." prefix to the name if necessary: -v becomes -test.v.
 	{name: "bench", passToTest: true},
 	{name: "benchmem", boolVar: new(bool), passToTest: true},
 	{name: "benchtime", passToTest: true},
-	{name: "covermode"},
+	{name: "count", passToTest: true},
 	{name: "coverprofile", passToTest: true},
 	{name: "cpu", passToTest: true},
 	{name: "cpuprofile", passToTest: true},
@@ -103,9 +55,26 @@ var testFlagDefn = []*testFlagSpec{
 	{name: "run", passToTest: true},
 	{name: "short", boolVar: new(bool), passToTest: true},
 	{name: "timeout", passToTest: true},
+	{name: "trace", passToTest: true},
 	{name: "v", boolVar: &testV, passToTest: true},
 }
 
+// add build flags to testFlagDefn
+func init() {
+	var cmd Command
+	addBuildFlags(&cmd)
+	cmd.Flag.VisitAll(func(f *flag.Flag) {
+		if f.Name == "v" {
+			// test overrides the build -v flag
+			return
+		}
+		testFlagDefn = append(testFlagDefn, &testFlagSpec{
+			name:      f.Name,
+			flagValue: f.Value,
+		})
+	})
+}
+
 // testFlags processes the command line, grabbing -x and -c, rewriting known flags
 // to have "test" before them, and reading the command line for the 6.out.
 // Unfortunately for us, we need to do our own flag processing because go test
@@ -148,73 +117,55 @@ func testFlags(args []string) (packageNames, passToTest []string) {
 			passToTest = append(passToTest, args[i])
 			continue
 		}
-		var err error
-		switch f.name {
-		// bool flags.
-		case "a", "c", "i", "n", "x", "v", "race", "cover", "work":
-			setBoolFlag(f.boolVar, value)
-		case "o":
-			testO = value
-			testNeedBinary = true
-		case "p":
-			setIntFlag(&buildP, value)
-		case "exec":
-			execCmd, err = splitQuotedFields(value)
-			if err != nil {
+		if f.flagValue != nil {
+			if err := f.flagValue.Set(value); err != nil {
 				fatalf("invalid flag argument for -%s: %v", f.name, err)
 			}
-		case "ccflags":
-			buildCcflags, err = splitQuotedFields(value)
-			if err != nil {
-				fatalf("invalid flag argument for -%s: %v", f.name, err)
-			}
-		case "gcflags":
-			buildGcflags, err = splitQuotedFields(value)
-			if err != nil {
-				fatalf("invalid flag argument for -%s: %v", f.name, err)
-			}
-		case "ldflags":
-			buildLdflags, err = splitQuotedFields(value)
-			if err != nil {
-				fatalf("invalid flag argument for -%s: %v", f.name, err)
-			}
-		case "gccgoflags":
-			buildGccgoflags, err = splitQuotedFields(value)
-			if err != nil {
-				fatalf("invalid flag argument for -%s: %v", f.name, err)
-			}
-		case "tags":
-			buildContext.BuildTags = strings.Fields(value)
-		case "compiler":
-			buildCompiler{}.Set(value)
-		case "bench":
-			// record that we saw the flag; don't care about the value
-			testBench = true
-		case "timeout":
-			testTimeout = value
-		case "blockprofile", "cpuprofile", "memprofile":
-			testProfile = true
-			testNeedBinary = true
-		case "coverpkg":
-			testCover = true
-			if value == "" {
-				testCoverPaths = nil
-			} else {
-				testCoverPaths = strings.Split(value, ",")
-			}
-		case "coverprofile":
-			testCover = true
-			testProfile = true
-		case "covermode":
-			switch value {
-			case "set", "count", "atomic":
-				testCoverMode = value
-			default:
-				fatalf("invalid flag argument for -cover: %q", value)
+		} else {
+			// Test-only flags.
+			// Arguably should be handled by f.flagValue, but aren't.
+			var err error
+			switch f.name {
+			// bool flags.
+			case "c", "i", "v", "cover":
+				setBoolFlag(f.boolVar, value)
+			case "o":
+				testO = value
+				testNeedBinary = true
+			case "exec":
+				execCmd, err = splitQuotedFields(value)
+				if err != nil {
+					fatalf("invalid flag argument for -%s: %v", f.name, err)
+				}
+			case "bench":
+				// record that we saw the flag; don't care about the value
+				testBench = true
+			case "timeout":
+				testTimeout = value
+			case "blockprofile", "cpuprofile", "memprofile", "trace":
+				testProfile = true
+				testNeedBinary = true
+			case "coverpkg":
+				testCover = true
+				if value == "" {
+					testCoverPaths = nil
+				} else {
+					testCoverPaths = strings.Split(value, ",")
+				}
+			case "coverprofile":
+				testCover = true
+				testProfile = true
+			case "covermode":
+				switch value {
+				case "set", "count", "atomic":
+					testCoverMode = value
+				default:
+					fatalf("invalid flag argument for -covermode: %q", value)
+				}
+				testCover = true
+			case "outputdir":
+				outputDir = value
 			}
-			testCover = true
-		case "outputdir":
-			outputDir = value
 		}
 		if extraWord {
 			i++
@@ -267,7 +218,7 @@ func testFlag(args []string, i int) (f *testFlagSpec, value string, extra bool)
 	for _, f = range testFlagDefn {
 		if name == f.name {
 			// Booleans are special because they have modes -x, -x=true, -x=false.
-			if f.boolVar != nil {
+			if f.boolVar != nil || isBoolFlag(f.flagValue) {
 				if equals < 0 { // otherwise, it's been set and will be verified in setBoolFlag
 					value = "true"
 				} else {
@@ -294,6 +245,17 @@ func testFlag(args []string, i int) (f *testFlagSpec, value string, extra bool)
 	return
 }
 
+// isBoolFlag reports whether v is a bool flag.
+func isBoolFlag(v flag.Value) bool {
+	vv, ok := v.(interface {
+		IsBoolFlag() bool
+	})
+	if ok {
+		return vv.IsBoolFlag()
+	}
+	return false
+}
+
 // setBoolFlag sets the addressed boolean to the value.
 func setBoolFlag(flag *bool, value string) {
 	x, err := strconv.ParseBool(value)
diff --git a/src/cmd/go/tool.go b/src/cmd/go/tool.go
index 3f11c3e..937ca1f 100644
--- a/src/cmd/go/tool.go
+++ b/src/cmd/go/tool.go
@@ -50,6 +50,9 @@ func tool(toolName string) string {
 	if toolIsWindows {
 		toolPath += toolWindowsExtension
 	}
+	if len(buildToolExec) > 0 {
+		return toolPath
+	}
 	// Give a nice message if there is no tool with that name.
 	if _, err := os.Stat(toolPath); err != nil {
 		if isInGoToolsRepo(toolName) {
@@ -64,10 +67,6 @@ func tool(toolName string) string {
 }
 
 func isInGoToolsRepo(toolName string) bool {
-	switch toolName {
-	case "cover", "vet":
-		return true
-	}
 	return false
 }
 
@@ -92,7 +91,11 @@ func runTool(cmd *Command, args []string) {
 		return
 	}
 	if toolN {
-		fmt.Printf("%s %s\n", toolPath, strings.Join(args[1:], " "))
+		cmd := toolPath
+		if len(args) > 1 {
+			cmd += " " + strings.Join(args[1:], " ")
+		}
+		fmt.Printf("%s\n", cmd)
 		return
 	}
 	toolCmd := &exec.Cmd{
@@ -101,6 +104,8 @@ func runTool(cmd *Command, args []string) {
 		Stdin:  os.Stdin,
 		Stdout: os.Stdout,
 		Stderr: os.Stderr,
+		// Set $GOROOT, mainly for go tool dist.
+		Env: mergeEnvLists([]string{"GOROOT=" + goroot}, os.Environ()),
 	}
 	err := toolCmd.Run()
 	if err != nil {
diff --git a/src/cmd/go/vcs.go b/src/cmd/go/vcs.go
index 1cac613..28a7540 100644
--- a/src/cmd/go/vcs.go
+++ b/src/cmd/go/vcs.go
@@ -9,12 +9,15 @@ import (
 	"encoding/json"
 	"errors"
 	"fmt"
+	"internal/singleflight"
 	"log"
+	"net/url"
 	"os"
 	"os/exec"
 	"path/filepath"
 	"regexp"
 	"strings"
+	"sync"
 )
 
 // A vcsCmd describes how to use a version control system
@@ -23,13 +26,13 @@ type vcsCmd struct {
 	name string
 	cmd  string // name of binary to invoke command
 
-	createCmd   string // command to download a fresh copy of a repository
-	downloadCmd string // command to download updates into an existing repository
+	createCmd   []string // commands to download a fresh copy of a repository
+	downloadCmd []string // commands to download updates into an existing repository
 
 	tagCmd         []tagCmd // commands to list tags
 	tagLookupCmd   []tagCmd // commands to lookup tags before running tagSyncCmd
-	tagSyncCmd     string   // command to sync to specific tag
-	tagSyncDefault string   // command to sync to default tag
+	tagSyncCmd     []string // commands to sync to specific tag
+	tagSyncDefault []string // commands to sync to default tag
 
 	scheme  []string
 	pingCmd string
@@ -38,6 +41,23 @@ type vcsCmd struct {
 	resolveRepo func(v *vcsCmd, rootDir, remoteRepo string) (realRepo string, err error)
 }
 
+var isSecureScheme = map[string]bool{
+	"https":   true,
+	"git+ssh": true,
+	"bzr+ssh": true,
+	"svn+ssh": true,
+	"ssh":     true,
+}
+
+func (v *vcsCmd) isSecure(repo string) bool {
+	u, err := url.Parse(repo)
+	if err != nil {
+		// If repo is not a URL, it's not secure.
+		return false
+	}
+	return isSecureScheme[u.Scheme]
+}
+
 // A tagCmd describes a command to list available tags
 // that can be passed to tagSyncCmd.
 type tagCmd struct {
@@ -69,8 +89,8 @@ var vcsHg = &vcsCmd{
 	name: "Mercurial",
 	cmd:  "hg",
 
-	createCmd:   "clone -U {repo} {dir}",
-	downloadCmd: "pull",
+	createCmd:   []string{"clone -U {repo} {dir}"},
+	downloadCmd: []string{"pull"},
 
 	// We allow both tag and branch names as 'tags'
 	// for selecting a version.  This lets people have
@@ -81,8 +101,8 @@ var vcsHg = &vcsCmd{
 		{"tags", `^(\S+)`},
 		{"branches", `^(\S+)`},
 	},
-	tagSyncCmd:     "update -r {tag}",
-	tagSyncDefault: "update default",
+	tagSyncCmd:     []string{"update -r {tag}"},
+	tagSyncDefault: []string{"update default"},
 
 	scheme:     []string{"https", "http", "ssh"},
 	pingCmd:    "identify {scheme}://{repo}",
@@ -102,8 +122,8 @@ var vcsGit = &vcsCmd{
 	name: "Git",
 	cmd:  "git",
 
-	createCmd:   "clone {repo} {dir}",
-	downloadCmd: "pull --ff-only",
+	createCmd:   []string{"clone {repo} {dir}", "--git-dir={dir}/.git submodule update --init --recursive"},
+	downloadCmd: []string{"pull --ff-only", "submodule update --init --recursive"},
 
 	tagCmd: []tagCmd{
 		// tags/xxx matches a git tag named xxx
@@ -113,41 +133,64 @@ var vcsGit = &vcsCmd{
 	tagLookupCmd: []tagCmd{
 		{"show-ref tags/{tag} origin/{tag}", `((?:tags|origin)/\S+)$`},
 	},
-	tagSyncCmd:     "checkout {tag}",
-	tagSyncDefault: "checkout master",
-
-	scheme:     []string{"git", "https", "http", "git+ssh"},
+	tagSyncCmd: []string{"checkout {tag}", "submodule update --init --recursive"},
+	// both createCmd and downloadCmd update the working dir.
+	// No need to do more here. We used to 'checkout master'
+	// but that doesn't work if the default branch is not named master.
+	// See golang.org/issue/9032.
+	tagSyncDefault: []string{"checkout master", "submodule update --init --recursive"},
+
+	scheme:     []string{"git", "https", "http", "git+ssh", "ssh"},
 	pingCmd:    "ls-remote {scheme}://{repo}",
 	remoteRepo: gitRemoteRepo,
 }
 
+// scpSyntaxRe matches the SCP-like addresses used by Git to access
+// repositories by SSH.
+var scpSyntaxRe = regexp.MustCompile(`^([a-zA-Z0-9_]+)@([a-zA-Z0-9._-]+):(.*)$`)
+
 func gitRemoteRepo(vcsGit *vcsCmd, rootDir string) (remoteRepo string, err error) {
-	outb, err := vcsGit.runOutput(rootDir, "remote -v")
+	cmd := "config remote.origin.url"
+	errParse := errors.New("unable to parse output of git " + cmd)
+	errRemoteOriginNotFound := errors.New("remote origin not found")
+	outb, err := vcsGit.run1(rootDir, cmd, nil, false)
 	if err != nil {
+		// if it doesn't output any message, it means the config argument is correct,
+		// but the config value itself doesn't exist
+		if outb != nil && len(outb) == 0 {
+			return "", errRemoteOriginNotFound
+		}
 		return "", err
 	}
-	out := string(outb)
-
-	// Expect:
-	// origin	https://github.com/rsc/pdf (fetch)
-	// origin	https://github.com/rsc/pdf (push)
-	// use first line only.
-
-	if !strings.HasPrefix(out, "origin\t") {
-		return "", fmt.Errorf("unable to parse output of git remote -v")
-	}
-	out = strings.TrimPrefix(out, "origin\t")
-	i := strings.Index(out, "\n")
-	if i < 0 {
-		return "", fmt.Errorf("unable to parse output of git remote -v")
+	out := strings.TrimSpace(string(outb))
+
+	var repoURL *url.URL
+	if m := scpSyntaxRe.FindStringSubmatch(out); m != nil {
+		// Match SCP-like syntax and convert it to a URL.
+		// Eg, "git at github.com:user/repo" becomes
+		// "ssh://git@github.com/user/repo".
+		repoURL = &url.URL{
+			Scheme:  "ssh",
+			User:    url.User(m[1]),
+			Host:    m[2],
+			RawPath: m[3],
+		}
+	} else {
+		repoURL, err = url.Parse(out)
+		if err != nil {
+			return "", err
+		}
 	}
-	out = out[:i]
-	i = strings.LastIndex(out, " ")
-	if i < 0 {
-		return "", fmt.Errorf("unable to parse output of git remote -v")
+
+	// Iterate over insecure schemes too, because this function simply
+	// reports the state of the repo. If we can't see insecure schemes then
+	// we can't report the actual repo URL.
+	for _, s := range vcsGit.scheme {
+		if repoURL.Scheme == s {
+			return repoURL.String(), nil
+		}
 	}
-	out = out[:i]
-	return strings.TrimSpace(string(out)), nil
+	return "", errParse
 }
 
 // vcsBzr describes how to use Bazaar.
@@ -155,15 +198,15 @@ var vcsBzr = &vcsCmd{
 	name: "Bazaar",
 	cmd:  "bzr",
 
-	createCmd: "branch {repo} {dir}",
+	createCmd: []string{"branch {repo} {dir}"},
 
 	// Without --overwrite bzr will not pull tags that changed.
 	// Replace by --overwrite-tags after http://pad.lv/681792 goes in.
-	downloadCmd: "pull --overwrite",
+	downloadCmd: []string{"pull --overwrite"},
 
 	tagCmd:         []tagCmd{{"tags", `^(\S+)`}},
-	tagSyncCmd:     "update -r {tag}",
-	tagSyncDefault: "update -r revno:-1",
+	tagSyncCmd:     []string{"update -r {tag}"},
+	tagSyncDefault: []string{"update -r revno:-1"},
 
 	scheme:      []string{"https", "http", "bzr", "bzr+ssh"},
 	pingCmd:     "info {scheme}://{repo}",
@@ -217,8 +260,8 @@ var vcsSvn = &vcsCmd{
 	name: "Subversion",
 	cmd:  "svn",
 
-	createCmd:   "checkout {repo} {dir}",
-	downloadCmd: "update",
+	createCmd:   []string{"checkout {repo} {dir}"},
+	downloadCmd: []string{"update"},
 
 	// There is no tag command in subversion.
 	// The branch information is all in the path names.
@@ -294,14 +337,14 @@ func (v *vcsCmd) run1(dir string, cmdline string, keyval []string, verbose bool)
 	_, err := exec.LookPath(v.cmd)
 	if err != nil {
 		fmt.Fprintf(os.Stderr,
-			"go: missing %s command. See http://golang.org/s/gogetcmd\n",
+			"go: missing %s command. See https://golang.org/s/gogetcmd\n",
 			v.name)
 		return nil, err
 	}
 
 	cmd := exec.Command(v.cmd, args...)
 	cmd.Dir = dir
-	cmd.Env = envForDir(cmd.Dir)
+	cmd.Env = envForDir(cmd.Dir, os.Environ())
 	if buildX {
 		fmt.Printf("cd %s\n", dir)
 		fmt.Printf("%s %s\n", v.cmd, strings.Join(args, " "))
@@ -316,7 +359,7 @@ func (v *vcsCmd) run1(dir string, cmdline string, keyval []string, verbose bool)
 			fmt.Fprintf(os.Stderr, "# cd %s; %s %s\n", dir, v.cmd, strings.Join(args, " "))
 			os.Stderr.Write(out)
 		}
-		return nil, err
+		return out, err
 	}
 	return out, nil
 }
@@ -329,7 +372,15 @@ func (v *vcsCmd) ping(scheme, repo string) error {
 // create creates a new copy of repo in dir.
 // The parent of dir must exist; dir must not.
 func (v *vcsCmd) create(dir, repo string) error {
-	return v.run(".", v.createCmd, "dir", dir, "repo", repo)
+	for _, cmd := range v.createCmd {
+		if !go15VendorExperiment && strings.Contains(cmd, "submodule") {
+			continue
+		}
+		if err := v.run(".", cmd, "dir", dir, "repo", repo); err != nil {
+			return err
+		}
+	}
+	return nil
 }
 
 // download downloads any new changes for the repo in dir.
@@ -337,7 +388,15 @@ func (v *vcsCmd) download(dir string) error {
 	if err := v.fixDetachedHead(dir); err != nil {
 		return err
 	}
-	return v.run(dir, v.downloadCmd)
+	for _, cmd := range v.downloadCmd {
+		if !go15VendorExperiment && strings.Contains(cmd, "submodule") {
+			continue
+		}
+		if err := v.run(dir, cmd); err != nil {
+			return err
+		}
+	}
+	return nil
 }
 
 // fixDetachedHead switches a Git repository in dir from a detached head to the master branch.
@@ -383,7 +442,7 @@ func (v *vcsCmd) tags(dir string) ([]string, error) {
 // tagSync syncs the repo in dir to the named tag,
 // which either is a tag returned by tags or is v.tagDefault.
 func (v *vcsCmd) tagSync(dir, tag string) error {
-	if v.tagSyncCmd == "" {
+	if v.tagSyncCmd == nil {
 		return nil
 	}
 	if tag != "" {
@@ -400,10 +459,28 @@ func (v *vcsCmd) tagSync(dir, tag string) error {
 			}
 		}
 	}
-	if tag == "" && v.tagSyncDefault != "" {
-		return v.run(dir, v.tagSyncDefault)
+
+	if tag == "" && v.tagSyncDefault != nil {
+		for _, cmd := range v.tagSyncDefault {
+			if !go15VendorExperiment && strings.Contains(cmd, "submodule") {
+				continue
+			}
+			if err := v.run(dir, cmd); err != nil {
+				return err
+			}
+		}
+		return nil
+	}
+
+	for _, cmd := range v.tagSyncCmd {
+		if !go15VendorExperiment && strings.Contains(cmd, "submodule") {
+			continue
+		}
+		if err := v.run(dir, cmd, "tag", tag); err != nil {
+			return err
+		}
 	}
-	return v.run(dir, v.tagSyncCmd, "tag", tag)
+	return nil
 }
 
 // A vcsPath describes how to convert an import path into a
@@ -467,10 +544,20 @@ type repoRoot struct {
 
 var httpPrefixRE = regexp.MustCompile(`^https?:`)
 
+// securityMode specifies whether a function should make network
+// calls using insecure transports (eg, plain text HTTP).
+// The zero value is "secure".
+type securityMode int
+
+const (
+	secure securityMode = iota
+	insecure
+)
+
 // repoRootForImportPath analyzes importPath to determine the
 // version control system, and code repository to use.
-func repoRootForImportPath(importPath string) (*repoRoot, error) {
-	rr, err := repoRootForImportPathStatic(importPath, "")
+func repoRootForImportPath(importPath string, security securityMode) (*repoRoot, error) {
+	rr, err := repoRootFromVCSPaths(importPath, "", security, vcsPaths)
 	if err == errUnknownSite {
 		// If there are wildcards, look up the thing before the wildcard,
 		// hoping it applies to the wildcarded parts too.
@@ -479,7 +566,7 @@ func repoRootForImportPath(importPath string) (*repoRoot, error) {
 		if i := strings.Index(lookup, "/.../"); i >= 0 {
 			lookup = lookup[:i]
 		}
-		rr, err = repoRootForImportDynamic(lookup)
+		rr, err = repoRootForImportDynamic(lookup, security)
 
 		// repoRootForImportDynamic returns error detail
 		// that is irrelevant if the user didn't intend to use a
@@ -492,6 +579,13 @@ func repoRootForImportPath(importPath string) (*repoRoot, error) {
 			err = fmt.Errorf("unrecognized import path %q", importPath)
 		}
 	}
+	if err != nil {
+		rr1, err1 := repoRootFromVCSPaths(importPath, "", security, vcsPathsAfterDynamic)
+		if err1 == nil {
+			rr = rr1
+			err = nil
+		}
+	}
 
 	if err == nil && strings.Contains(importPath, "...") && strings.Contains(rr.root, "...") {
 		// Do not allow wildcards in the repo root.
@@ -503,13 +597,10 @@ func repoRootForImportPath(importPath string) (*repoRoot, error) {
 
 var errUnknownSite = errors.New("dynamic lookup required to find mapping")
 
-// repoRootForImportPathStatic attempts to map importPath to a
-// repoRoot using the commonly-used VCS hosting sites in vcsPaths
-// (github.com/user/dir), or from a fully-qualified importPath already
-// containing its VCS type (foo.com/repo.git/dir)
-//
+// repoRootFromVCSPaths attempts to map importPath to a repoRoot
+// using the mappings defined in vcsPaths.
 // If scheme is non-empty, that scheme is forced.
-func repoRootForImportPathStatic(importPath, scheme string) (*repoRoot, error) {
+func repoRootFromVCSPaths(importPath, scheme string, security securityMode, vcsPaths []*vcsPath) (*repoRoot, error) {
 	// A common error is to use https://packagepath because that's what
 	// hg and git require. Diagnose this helpfully.
 	if loc := httpPrefixRE.FindStringIndex(importPath); loc != nil {
@@ -559,6 +650,9 @@ func repoRootForImportPathStatic(importPath, scheme string) (*repoRoot, error) {
 				match["repo"] = scheme + "://" + match["repo"]
 			} else {
 				for _, scheme := range vcs.scheme {
+					if security == secure && !isSecureScheme[scheme] {
+						continue
+					}
 					if vcs.ping(scheme, match["repo"]) == nil {
 						match["repo"] = scheme + "://" + match["repo"]
 						break
@@ -579,26 +673,31 @@ func repoRootForImportPathStatic(importPath, scheme string) (*repoRoot, error) {
 // repoRootForImportDynamic finds a *repoRoot for a custom domain that's not
 // statically known by repoRootForImportPathStatic.
 //
-// This handles "vanity import paths" like "name.tld/pkg/foo".
-func repoRootForImportDynamic(importPath string) (*repoRoot, error) {
+// This handles custom import paths like "name.tld/pkg/foo" or just "name.tld".
+func repoRootForImportDynamic(importPath string, security securityMode) (*repoRoot, error) {
 	slash := strings.Index(importPath, "/")
 	if slash < 0 {
-		return nil, errors.New("import path does not contain a slash")
+		slash = len(importPath)
 	}
 	host := importPath[:slash]
 	if !strings.Contains(host, ".") {
 		return nil, errors.New("import path does not begin with hostname")
 	}
-	urlStr, body, err := httpsOrHTTP(importPath)
+	urlStr, body, err := httpsOrHTTP(importPath, security)
 	if err != nil {
-		return nil, fmt.Errorf("http/https fetch: %v", err)
+		msg := "https fetch: %v"
+		if security == insecure {
+			msg = "http/" + msg
+		}
+		return nil, fmt.Errorf(msg, err)
 	}
 	defer body.Close()
 	imports, err := parseMetaGoImports(body)
 	if err != nil {
 		return nil, fmt.Errorf("parsing %s: %v", importPath, err)
 	}
-	metaImport, err := matchGoImport(imports, importPath)
+	// Find the matched meta import.
+	mmi, err := matchGoImport(imports, importPath)
 	if err != nil {
 		if err != errNoMatch {
 			return nil, fmt.Errorf("parse %s: %v", urlStr, err)
@@ -606,7 +705,7 @@ func repoRootForImportDynamic(importPath string) (*repoRoot, error) {
 		return nil, fmt.Errorf("parse %s: no go-import meta tags", urlStr)
 	}
 	if buildV {
-		log.Printf("get %q: found meta tag %#v at %s", importPath, metaImport, urlStr)
+		log.Printf("get %q: found meta tag %#v at %s", importPath, mmi, urlStr)
 	}
 	// If the import was "uni.edu/bob/project", which said the
 	// prefix was "uni.edu" and the RepoRoot was "evilroot.com",
@@ -614,42 +713,89 @@ func repoRootForImportDynamic(importPath string) (*repoRoot, error) {
 	// "uni.edu" yet (possibly overwriting/preempting another
 	// non-evil student).  Instead, first verify the root and see
 	// if it matches Bob's claim.
-	if metaImport.Prefix != importPath {
+	if mmi.Prefix != importPath {
 		if buildV {
 			log.Printf("get %q: verifying non-authoritative meta tag", importPath)
 		}
 		urlStr0 := urlStr
-		urlStr, body, err = httpsOrHTTP(metaImport.Prefix)
+		var imports []metaImport
+		urlStr, imports, err = metaImportsForPrefix(mmi.Prefix, security)
 		if err != nil {
-			return nil, fmt.Errorf("fetch %s: %v", urlStr, err)
-		}
-		imports, err := parseMetaGoImports(body)
-		if err != nil {
-			return nil, fmt.Errorf("parsing %s: %v", importPath, err)
-		}
-		if len(imports) == 0 {
-			return nil, fmt.Errorf("fetch %s: no go-import meta tag", urlStr)
+			return nil, err
 		}
 		metaImport2, err := matchGoImport(imports, importPath)
-		if err != nil || metaImport != metaImport2 {
-			return nil, fmt.Errorf("%s and %s disagree about go-import for %s", urlStr0, urlStr, metaImport.Prefix)
+		if err != nil || mmi != metaImport2 {
+			return nil, fmt.Errorf("%s and %s disagree about go-import for %s", urlStr0, urlStr, mmi.Prefix)
 		}
 	}
 
-	if !strings.Contains(metaImport.RepoRoot, "://") {
-		return nil, fmt.Errorf("%s: invalid repo root %q; no scheme", urlStr, metaImport.RepoRoot)
+	if !strings.Contains(mmi.RepoRoot, "://") {
+		return nil, fmt.Errorf("%s: invalid repo root %q; no scheme", urlStr, mmi.RepoRoot)
 	}
 	rr := &repoRoot{
-		vcs:  vcsByCmd(metaImport.VCS),
-		repo: metaImport.RepoRoot,
-		root: metaImport.Prefix,
+		vcs:  vcsByCmd(mmi.VCS),
+		repo: mmi.RepoRoot,
+		root: mmi.Prefix,
 	}
 	if rr.vcs == nil {
-		return nil, fmt.Errorf("%s: unknown vcs %q", urlStr, metaImport.VCS)
+		return nil, fmt.Errorf("%s: unknown vcs %q", urlStr, mmi.VCS)
 	}
 	return rr, nil
 }
 
+var fetchGroup singleflight.Group
+var (
+	fetchCacheMu sync.Mutex
+	fetchCache   = map[string]fetchResult{} // key is metaImportsForPrefix's importPrefix
+)
+
+// metaImportsForPrefix takes a package's root import path as declared in a <meta> tag
+// and returns its HTML discovery URL and the parsed metaImport lines
+// found on the page.
+//
+// The importPath is of the form "golang.org/x/tools".
+// It is an error if no imports are found.
+// urlStr will still be valid if err != nil.
+// The returned urlStr will be of the form "https://golang.org/x/tools?go-get=1"
+func metaImportsForPrefix(importPrefix string, security securityMode) (urlStr string, imports []metaImport, err error) {
+	setCache := func(res fetchResult) (fetchResult, error) {
+		fetchCacheMu.Lock()
+		defer fetchCacheMu.Unlock()
+		fetchCache[importPrefix] = res
+		return res, nil
+	}
+
+	resi, _, _ := fetchGroup.Do(importPrefix, func() (resi interface{}, err error) {
+		fetchCacheMu.Lock()
+		if res, ok := fetchCache[importPrefix]; ok {
+			fetchCacheMu.Unlock()
+			return res, nil
+		}
+		fetchCacheMu.Unlock()
+
+		urlStr, body, err := httpsOrHTTP(importPrefix, security)
+		if err != nil {
+			return setCache(fetchResult{urlStr: urlStr, err: fmt.Errorf("fetch %s: %v", urlStr, err)})
+		}
+		imports, err := parseMetaGoImports(body)
+		if err != nil {
+			return setCache(fetchResult{urlStr: urlStr, err: fmt.Errorf("parsing %s: %v", urlStr, err)})
+		}
+		if len(imports) == 0 {
+			err = fmt.Errorf("fetch %s: no go-import meta tag", urlStr)
+		}
+		return setCache(fetchResult{urlStr: urlStr, imports: imports, err: err})
+	})
+	res := resi.(fetchResult)
+	return res.urlStr, res.imports, res.err
+}
+
+type fetchResult struct {
+	urlStr  string // e.g. "https://foo.com/x/bar?go-get=1"
+	imports []metaImport
+	err     error
+}
+
 // metaImport represents the parsed <meta name="go-import"
 // content="prefix vcs reporoot" /> tags from HTML files.
 type metaImport struct {
@@ -689,7 +835,10 @@ func expand(match map[string]string, s string) string {
 	return s
 }
 
-// vcsPaths lists the known vcs paths.
+// vcsPaths defines the meaning of import paths referring to
+// commonly-used VCS hosting sites (github.com/user/dir)
+// and import paths referring to a fully-qualified importPath
+// containing a VCS type (foo.com/repo.git/dir)
 var vcsPaths = []*vcsPath{
 	// Google Code - new syntax
 	{
@@ -722,15 +871,6 @@ var vcsPaths = []*vcsPath{
 		check:  bitbucketVCS,
 	},
 
-	// Launchpad
-	{
-		prefix: "launchpad.net/",
-		re:     `^(?P<root>launchpad\.net/((?P<project>[A-Za-z0-9_.\-]+)(?P<series>/[A-Za-z0-9_.\-]+)?|~[A-Za-z0-9_.\-]+/(\+junk|[A-Za-z0-9_.\-]+)/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`,
-		vcs:    "bzr",
-		repo:   "https://{root}",
-		check:  launchpadVCS,
-	},
-
 	// IBM DevOps Services (JazzHub)
 	{
 		prefix: "hub.jazz.net/git",
@@ -740,13 +880,37 @@ var vcsPaths = []*vcsPath{
 		check:  noVCSSuffix,
 	},
 
+	// Git at Apache
+	{
+		prefix: "git.apache.org",
+		re:     `^(?P<root>git.apache.org/[a-z0-9_.\-]+\.git)(/[A-Za-z0-9_.\-]+)*$`,
+		vcs:    "git",
+		repo:   "https://{root}",
+	},
+
 	// General syntax for any server.
+	// Must be last.
 	{
 		re:   `^(?P<root>(?P<repo>([a-z0-9.\-]+\.)+[a-z0-9.\-]+(:[0-9]+)?/[A-Za-z0-9_.\-/]*?)\.(?P<vcs>bzr|git|hg|svn))(/[A-Za-z0-9_.\-]+)*$`,
 		ping: true,
 	},
 }
 
+// vcsPathsAfterDynamic gives additional vcsPaths entries
+// to try after the dynamic HTML check.
+// This gives those sites a chance to introduce <meta> tags
+// as part of a graceful transition away from the hard-coded logic.
+var vcsPathsAfterDynamic = []*vcsPath{
+	// Launchpad. See golang.org/issue/11436.
+	{
+		prefix: "launchpad.net/",
+		re:     `^(?P<root>launchpad\.net/((?P<project>[A-Za-z0-9_.\-]+)(?P<series>/[A-Za-z0-9_.\-]+)?|~[A-Za-z0-9_.\-]+/(\+junk|[A-Za-z0-9_.\-]+)/[A-Za-z0-9_.\-]+))(/[A-Za-z0-9_.\-]+)*$`,
+		vcs:    "bzr",
+		repo:   "https://{root}",
+		check:  launchpadVCS,
+	},
+}
+
 func init() {
 	// fill in cached regexps.
 	// Doing this eagerly discovers invalid regexp syntax
@@ -754,6 +918,9 @@ func init() {
 	for _, srv := range vcsPaths {
 		srv.regexp = regexp.MustCompile(srv.re)
 	}
+	for _, srv := range vcsPathsAfterDynamic {
+		srv.regexp = regexp.MustCompile(srv.re)
+	}
 }
 
 // noVCSSuffix checks that the repository name does not
@@ -821,10 +988,25 @@ func bitbucketVCS(match map[string]string) error {
 	url := expand(match, "https://api.bitbucket.org/1.0/repositories/{bitname}")
 	data, err := httpGET(url)
 	if err != nil {
-		return err
-	}
-	if err := json.Unmarshal(data, &resp); err != nil {
-		return fmt.Errorf("decoding %s: %v", url, err)
+		if httpErr, ok := err.(*httpError); ok && httpErr.statusCode == 403 {
+			// this may be a private repository. If so, attempt to determine which
+			// VCS it uses. See issue 5375.
+			root := match["root"]
+			for _, vcs := range []string{"git", "hg"} {
+				if vcsByCmd(vcs).ping("https", root) == nil {
+					resp.SCM = vcs
+					break
+				}
+			}
+		}
+
+		if resp.SCM == "" {
+			return err
+		}
+	} else {
+		if err := json.Unmarshal(data, &resp); err != nil {
+			return fmt.Errorf("decoding %s: %v", url, err)
+		}
 	}
 
 	if vcsByCmd(resp.SCM) != nil {
diff --git a/src/cmd/go/vcs_test.go b/src/cmd/go/vcs_test.go
index 14d681b..f5d5e4f 100644
--- a/src/cmd/go/vcs_test.go
+++ b/src/cmd/go/vcs_test.go
@@ -5,20 +5,15 @@
 package main
 
 import (
-	"runtime"
+	"internal/testenv"
 	"testing"
 )
 
 // Test that RepoRootForImportPath creates the correct RepoRoot for a given importPath.
 // TODO(cmang): Add tests for SVN and BZR.
 func TestRepoRootForImportPath(t *testing.T) {
-	if testing.Short() {
-		t.Skip("skipping test to avoid external network")
-	}
-	switch runtime.GOOS {
-	case "nacl", "android":
-		t.Skipf("no networking available on %s", runtime.GOOS)
-	}
+	testenv.MustHaveExternalNetwork(t)
+
 	tests := []struct {
 		path string
 		want *repoRoot
@@ -101,10 +96,34 @@ func TestRepoRootForImportPath(t *testing.T) {
 			"hub.jazz.net/git/USER/pkgname",
 			nil,
 		},
+		// Spaces are not valid in package name
+		{
+			"git.apache.org/package name/path/to/lib",
+			nil,
+		},
+		// Should have ".git" suffix
+		{
+			"git.apache.org/package-name/path/to/lib",
+			nil,
+		},
+		{
+			"git.apache.org/package-name.git",
+			&repoRoot{
+				vcs:  vcsGit,
+				repo: "https://git.apache.org/package-name.git",
+			},
+		},
+		{
+			"git.apache.org/package-name_2.x.git/path/to/lib",
+			&repoRoot{
+				vcs:  vcsGit,
+				repo: "https://git.apache.org/package-name_2.x.git",
+			},
+		},
 	}
 
 	for _, test := range tests {
-		got, err := repoRootForImportPath(test.path)
+		got, err := repoRootForImportPath(test.path, secure)
 		want := test.want
 
 		if want == nil {
@@ -122,3 +141,35 @@ func TestRepoRootForImportPath(t *testing.T) {
 		}
 	}
 }
+
+func TestIsSecure(t *testing.T) {
+	tests := []struct {
+		vcs    *vcsCmd
+		url    string
+		secure bool
+	}{
+		{vcsGit, "http://example.com/foo.git", false},
+		{vcsGit, "https://example.com/foo.git", true},
+		{vcsBzr, "http://example.com/foo.bzr", false},
+		{vcsBzr, "https://example.com/foo.bzr", true},
+		{vcsSvn, "http://example.com/svn", false},
+		{vcsSvn, "https://example.com/svn", true},
+		{vcsHg, "http://example.com/foo.hg", false},
+		{vcsHg, "https://example.com/foo.hg", true},
+		{vcsGit, "ssh://user@example.com/foo.git", true},
+		{vcsGit, "user at server:path/to/repo.git", false},
+		{vcsGit, "user at server:", false},
+		{vcsGit, "server:repo.git", false},
+		{vcsGit, "server:path/to/repo.git", false},
+		{vcsGit, "example.com:path/to/repo.git", false},
+		{vcsGit, "path/that/contains/a:colon/repo.git", false},
+		{vcsHg, "ssh://user@example.com/path/to/repo.hg", true},
+	}
+
+	for _, test := range tests {
+		secure := test.vcs.isSecure(test.url)
+		if secure != test.secure {
+			t.Errorf("%s isSecure(%q) = %t; want %t", test.vcs, test.url, secure, test.secure)
+		}
+	}
+}
diff --git a/src/cmd/go/vendor_test.go b/src/cmd/go/vendor_test.go
new file mode 100644
index 0000000..1e8cf9c
--- /dev/null
+++ b/src/cmd/go/vendor_test.go
@@ -0,0 +1,258 @@
+// 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.
+
+// Tests for vendoring semantics.
+
+package main_test
+
+import (
+	"bytes"
+	"fmt"
+	"internal/testenv"
+	"path/filepath"
+	"regexp"
+	"strings"
+	"testing"
+)
+
+func TestVendorImports(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+	tg.setenv("GO15VENDOREXPERIMENT", "1")
+	tg.run("list", "-f", "{{.ImportPath}} {{.Imports}}", "vend/...")
+	want := `
+		vend [vend/vendor/p r]
+		vend/hello [fmt vend/vendor/strings]
+		vend/subdir [vend/vendor/p r]
+		vend/vendor/p []
+		vend/vendor/q []
+		vend/vendor/strings []
+		vend/x [vend/x/vendor/p vend/vendor/q vend/x/vendor/r]
+		vend/x/invalid [vend/x/invalid/vendor/foo]
+		vend/x/vendor/p []
+		vend/x/vendor/p/p [notfound]
+		vend/x/vendor/r []
+	`
+	want = strings.Replace(want+"\t", "\n\t\t", "\n", -1)
+	want = strings.TrimPrefix(want, "\n")
+
+	have := tg.stdout.String()
+
+	if have != want {
+		t.Errorf("incorrect go list output:\n%s", diffSortedOutputs(have, want))
+	}
+}
+
+func TestVendorRun(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+	tg.setenv("GO15VENDOREXPERIMENT", "1")
+	tg.cd(filepath.Join(tg.pwd(), "testdata/src/vend/hello"))
+	tg.run("run", "hello.go")
+	tg.grepStdout("hello, world", "missing hello world output")
+}
+
+func TestVendorGOPATH(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	changeVolume := func(s string, f func(s string) string) string {
+		vol := filepath.VolumeName(s)
+		return f(vol) + s[len(vol):]
+	}
+	gopath := changeVolume(filepath.Join(tg.pwd(), "testdata"), strings.ToLower)
+	tg.setenv("GOPATH", gopath)
+	tg.setenv("GO15VENDOREXPERIMENT", "1")
+	cd := changeVolume(filepath.Join(tg.pwd(), "testdata/src/vend/hello"), strings.ToUpper)
+	tg.cd(cd)
+	tg.run("run", "hello.go")
+	tg.grepStdout("hello, world", "missing hello world output")
+}
+
+func TestVendorTest(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+	tg.setenv("GO15VENDOREXPERIMENT", "1")
+	tg.cd(filepath.Join(tg.pwd(), "testdata/src/vend/hello"))
+	tg.run("test", "-v")
+	tg.grepStdout("TestMsgInternal", "missing use in internal test")
+	tg.grepStdout("TestMsgExternal", "missing use in external test")
+}
+
+func TestVendorInvalid(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+	tg.setenv("GO15VENDOREXPERIMENT", "1")
+
+	tg.runFail("build", "vend/x/invalid")
+	tg.grepStderr("must be imported as foo", "missing vendor import error")
+}
+
+func TestVendorImportError(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata"))
+	tg.setenv("GO15VENDOREXPERIMENT", "1")
+
+	tg.runFail("build", "vend/x/vendor/p/p")
+
+	re := regexp.MustCompile(`cannot find package "notfound" in any of:
+	.*[\\/]testdata[\\/]src[\\/]vend[\\/]x[\\/]vendor[\\/]notfound \(vendor tree\)
+	.*[\\/]testdata[\\/]src[\\/]vend[\\/]vendor[\\/]notfound \(vendor tree\)
+	.*[\\/]src[\\/]notfound \(from \$GOROOT\)
+	.*[\\/]testdata[\\/]src[\\/]notfound \(from \$GOPATH\)`)
+
+	if !re.MatchString(tg.stderr.String()) {
+		t.Errorf("did not find expected search list in error text")
+	}
+}
+
+// diffSortedOutput prepares a diff of the already sorted outputs haveText and wantText.
+// The diff shows common lines prefixed by a tab, lines present only in haveText
+// prefixed by "unexpected: ", and lines present only in wantText prefixed by "missing: ".
+func diffSortedOutputs(haveText, wantText string) string {
+	var diff bytes.Buffer
+	have := splitLines(haveText)
+	want := splitLines(wantText)
+	for len(have) > 0 || len(want) > 0 {
+		if len(want) == 0 || len(have) > 0 && have[0] < want[0] {
+			fmt.Fprintf(&diff, "unexpected: %s\n", have[0])
+			have = have[1:]
+			continue
+		}
+		if len(have) == 0 || len(want) > 0 && want[0] < have[0] {
+			fmt.Fprintf(&diff, "missing: %s\n", want[0])
+			want = want[1:]
+			continue
+		}
+		fmt.Fprintf(&diff, "\t%s\n", want[0])
+		want = want[1:]
+		have = have[1:]
+	}
+	return diff.String()
+}
+
+func splitLines(s string) []string {
+	x := strings.Split(s, "\n")
+	if x[len(x)-1] == "" {
+		x = x[:len(x)-1]
+	}
+	return x
+}
+
+func TestVendorGet(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.tempFile("src/v/m.go", `
+		package main
+		import ("fmt"; "vendor.org/p")
+		func main() {
+			fmt.Println(p.C)
+		}`)
+	tg.tempFile("src/v/m_test.go", `
+		package main
+		import ("fmt"; "testing"; "vendor.org/p")
+		func TestNothing(t *testing.T) {
+			fmt.Println(p.C)
+		}`)
+	tg.tempFile("src/v/vendor/vendor.org/p/p.go", `
+		package p
+		const C = 1`)
+	tg.setenv("GOPATH", tg.path("."))
+	tg.setenv("GO15VENDOREXPERIMENT", "1")
+	tg.cd(tg.path("src/v"))
+	tg.run("run", "m.go")
+	tg.run("test")
+	tg.run("list", "-f", "{{.Imports}}")
+	tg.grepStdout("v/vendor/vendor.org/p", "import not in vendor directory")
+	tg.run("list", "-f", "{{.TestImports}}")
+	tg.grepStdout("v/vendor/vendor.org/p", "test import not in vendor directory")
+	tg.run("get")
+	tg.run("get", "-t")
+}
+
+func TestVendorGetUpdate(t *testing.T) {
+	testenv.MustHaveExternalNetwork(t)
+
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.makeTempdir()
+	tg.setenv("GOPATH", tg.path("."))
+	tg.setenv("GO15VENDOREXPERIMENT", "1")
+	tg.run("get", "github.com/rsc/go-get-issue-11864")
+	tg.run("get", "-u", "github.com/rsc/go-get-issue-11864")
+}
+
+func TestVendorCache(t *testing.T) {
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata/testvendor"))
+	tg.setenv("GO15VENDOREXPERIMENT", "1")
+	tg.runFail("build", "p")
+	tg.grepStderr("must be imported as x", "did not fail to build p")
+}
+
+func TestVendorTest2(t *testing.T) {
+	testenv.MustHaveExternalNetwork(t)
+
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.makeTempdir()
+	tg.setenv("GOPATH", tg.path("."))
+	tg.setenv("GO15VENDOREXPERIMENT", "1")
+	tg.run("get", "github.com/rsc/go-get-issue-11864")
+
+	// build -i should work
+	tg.run("build", "-i", "github.com/rsc/go-get-issue-11864")
+	tg.run("build", "-i", "github.com/rsc/go-get-issue-11864/t")
+
+	// test -i should work like build -i (golang.org/issue/11988)
+	tg.run("test", "-i", "github.com/rsc/go-get-issue-11864")
+	tg.run("test", "-i", "github.com/rsc/go-get-issue-11864/t")
+
+	// test should work too
+	tg.run("test", "github.com/rsc/go-get-issue-11864")
+	tg.run("test", "github.com/rsc/go-get-issue-11864/t")
+
+	// external tests should observe internal test exports (golang.org/issue/11977)
+	tg.run("test", "github.com/rsc/go-get-issue-11864/vendor/vendor.org/tx2")
+}
+
+func TestVendorList(t *testing.T) {
+	testenv.MustHaveExternalNetwork(t)
+
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.makeTempdir()
+	tg.setenv("GOPATH", tg.path("."))
+	tg.setenv("GO15VENDOREXPERIMENT", "1")
+	tg.run("get", "github.com/rsc/go-get-issue-11864")
+
+	tg.run("list", "-f", `{{join .TestImports "\n"}}`, "github.com/rsc/go-get-issue-11864/t")
+	tg.grepStdout("go-get-issue-11864/vendor/vendor.org/p", "did not find vendor-expanded p")
+
+	tg.run("list", "-f", `{{join .XTestImports "\n"}}`, "github.com/rsc/go-get-issue-11864/tx")
+	tg.grepStdout("go-get-issue-11864/vendor/vendor.org/p", "did not find vendor-expanded p")
+
+	tg.run("list", "-f", `{{join .XTestImports "\n"}}`, "github.com/rsc/go-get-issue-11864/vendor/vendor.org/tx2")
+	tg.grepStdout("go-get-issue-11864/vendor/vendor.org/tx2", "did not find vendor-expanded tx2")
+
+	tg.run("list", "-f", `{{join .XTestImports "\n"}}`, "github.com/rsc/go-get-issue-11864/vendor/vendor.org/tx3")
+	tg.grepStdout("go-get-issue-11864/vendor/vendor.org/tx3", "did not find vendor-expanded tx3")
+}
+
+func TestVendor12156(t *testing.T) {
+	// Former index out of range panic.
+	tg := testgo(t)
+	defer tg.cleanup()
+	tg.setenv("GOPATH", filepath.Join(tg.pwd(), "testdata/testvendor2"))
+	tg.setenv("GO15VENDOREXPERIMENT", "1")
+	tg.cd(filepath.Join(tg.pwd(), "testdata/testvendor2/src/p"))
+	tg.runFail("build", "p.go")
+	tg.grepStderrNot("panic", "panicked")
+	tg.grepStderr(`cannot find package "x"`, "wrong error")
+}
diff --git a/src/cmd/go/vet.go b/src/cmd/go/vet.go
index 02ff54b..81b978e 100644
--- a/src/cmd/go/vet.go
+++ b/src/cmd/go/vet.go
@@ -7,17 +7,17 @@ package main
 import "path/filepath"
 
 func init() {
-	addBuildFlagsNX(cmdVet)
+	addBuildFlags(cmdVet)
 }
 
 var cmdVet = &Command{
 	Run:       runVet,
-	UsageLine: "vet [-n] [-x] [packages]",
+	UsageLine: "vet [-n] [-x] [build flags] [packages]",
 	Short:     "run go tool vet on packages",
 	Long: `
 Vet runs the Go vet command on the packages named by the import paths.
 
-For more about vet, see 'godoc golang.org/x/tools/cmd/vet'.
+For more about vet, see 'go doc cmd/vet'.
 For more about specifying packages, see 'go help packages'.
 
 To run the vet tool with specific options, run 'go tool vet'.
@@ -25,6 +25,8 @@ To run the vet tool with specific options, run 'go tool vet'.
 The -n flag prints commands that would be executed.
 The -x flag prints commands as they are executed.
 
+For more about build flags, see 'go help build'.
+
 See also: go fmt, go fix.
 	`,
 }
@@ -46,5 +48,5 @@ func runVetFiles(p *Package, files []string) {
 	for i := range files {
 		files[i] = filepath.Join(p.Dir, files[i])
 	}
-	run(tool("vet"), relPaths(files))
+	run(buildToolExec, tool("vet"), relPaths(files))
 }
diff --git a/src/cmd/gofmt/doc.go b/src/cmd/gofmt/doc.go
index 3fc0439..9d0cd32 100644
--- a/src/cmd/gofmt/doc.go
+++ b/src/cmd/gofmt/doc.go
@@ -87,6 +87,13 @@ When invoked with -s gofmt will make the following source transformations where
 		for x, _ = range v {...}
 	will be simplified to:
 		for x = range v {...}
+
+	A range of the form:
+		for _ = range v {...}
+	will be simplified to:
+		for range v {...}
+
+This may result in changes that are incompatible with earlier versions of Go.
 */
 package main
 
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 @@ import (
 	"go/printer"
 	"go/scanner"
 	"go/token"
+	"internal/format"
 	"io"
 	"io/ioutil"
 	"os"
@@ -87,7 +88,7 @@ func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error
 		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 @@ func processFile(filename string, in io.Reader, out io.Writer, stdin bool) error
 		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 @@ func diff(b1, b2 []byte) (data []byte, err error) {
 	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 @@ import (
 	"go/ast"
 	"go/printer"
 	"go/token"
+	"internal/format"
 	"io"
 	"os"
 	"path/filepath"
@@ -32,7 +33,7 @@ var (
 )
 
 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 @@ func testFile(t *testing.T, b1, b2 *bytes.Buffer, filename string) {
 
 	// 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 @@ func isWildcard(s string) bool {
 	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/gcprog/gcprog.go b/src/cmd/internal/gcprog/gcprog.go
new file mode 100644
index 0000000..5845f7d
--- /dev/null
+++ b/src/cmd/internal/gcprog/gcprog.go
@@ -0,0 +1,298 @@
+// 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 gcprog implements an encoder for packed GC pointer bitmaps,
+// known as GC programs.
+//
+// Program Format
+//
+// The GC program encodes a sequence of 0 and 1 bits indicating scalar or pointer words in an object.
+// The encoding is a simple Lempel-Ziv program, with codes to emit literal bits and to repeat the
+// last n bits c times.
+//
+// The possible codes are:
+//
+//	00000000: stop
+//	0nnnnnnn: emit n bits copied from the next (n+7)/8 bytes, least significant bit first
+//	10000000 n c: repeat the previous n bits c times; n, c are varints
+//	1nnnnnnn c: repeat the previous n bits c times; c is a varint
+//
+// The numbers n and c, when they follow a code, are encoded as varints
+// using the same encoding as encoding/binary's Uvarint.
+//
+package gcprog
+
+import (
+	"fmt"
+	"io"
+)
+
+const progMaxLiteral = 127 // maximum n for literal n bit code
+
+// A Writer is an encoder for GC programs.
+//
+// The typical use of a Writer is to call Init, maybe call Debug,
+// make a sequence of Ptr, Advance, Repeat, and Append calls
+// to describe the data type, and then finally call End.
+type Writer struct {
+	writeByte func(byte)
+	symoff    int
+	index     int64
+	b         [progMaxLiteral]byte
+	nb        int
+	debug     io.Writer
+	debugBuf  []byte
+}
+
+// Init initializes w to write a new GC program
+// by calling writeByte for each byte in the program.
+func (w *Writer) Init(writeByte func(byte)) {
+	w.writeByte = writeByte
+}
+
+// Debug causes the writer to print a debugging trace to out
+// during future calls to methods like Ptr, Advance, and End.
+// It also enables debugging checks during the encoding.
+func (w *Writer) Debug(out io.Writer) {
+	w.debug = out
+}
+
+// BitIndex returns the number of bits written to the bit stream so far.
+func (w *Writer) BitIndex() int64 {
+	return w.index
+}
+
+// byte writes the byte x to the output.
+func (w *Writer) byte(x byte) {
+	if w.debug != nil {
+		w.debugBuf = append(w.debugBuf, x)
+	}
+	w.writeByte(x)
+}
+
+// End marks the end of the program, writing any remaining bytes.
+func (w *Writer) End() {
+	w.flushlit()
+	w.byte(0)
+	if w.debug != nil {
+		index := progbits(w.debugBuf)
+		if index != w.index {
+			println("gcprog: End wrote program for", index, "bits, but current index is", w.index)
+			panic("gcprog: out of sync")
+		}
+	}
+}
+
+// Ptr emits a 1 into the bit stream at the given bit index.
+// that is, it records that the index'th word in the object memory is a pointer.
+// Any bits between the current index and the new index
+// are set to zero, meaning the corresponding words are scalars.
+func (w *Writer) Ptr(index int64) {
+	if index < w.index {
+		println("gcprog: Ptr at index", index, "but current index is", w.index)
+		panic("gcprog: invalid Ptr index")
+	}
+	w.ZeroUntil(index)
+	if w.debug != nil {
+		fmt.Fprintf(w.debug, "gcprog: ptr at %d\n", index)
+	}
+	w.lit(1)
+}
+
+// ShouldRepeat reports whether it would be worthwhile to
+// use a Repeat to describe c elements of n bits each,
+// compared to just emitting c copies of the n-bit description.
+func (w *Writer) ShouldRepeat(n, c int64) bool {
+	// Should we lay out the bits directly instead of
+	// encoding them as a repetition? Certainly if count==1,
+	// since there's nothing to repeat, but also if the total
+	// size of the plain pointer bits for the type will fit in
+	// 4 or fewer bytes, since using a repetition will require
+	// flushing the current bits plus at least one byte for
+	// the repeat size and one for the repeat count.
+	return c > 1 && c*n > 4*8
+}
+
+// Repeat emits an instruction to repeat the description
+// of the last n words c times (including the initial description, c+1 times in total).
+func (w *Writer) Repeat(n, c int64) {
+	if n == 0 || c == 0 {
+		return
+	}
+	w.flushlit()
+	if w.debug != nil {
+		fmt.Fprintf(w.debug, "gcprog: repeat %d × %d\n", n, c)
+	}
+	if n < 128 {
+		w.byte(0x80 | byte(n))
+	} else {
+		w.byte(0x80)
+		w.varint(n)
+	}
+	w.varint(c)
+	w.index += n * c
+}
+
+// ZeroUntil adds zeros to the bit stream until reaching the given index;
+// that is, it records that the words from the most recent pointer until
+// the index'th word are scalars.
+// ZeroUntil is usually called in preparation for a call to Repeat, Append, or End.
+func (w *Writer) ZeroUntil(index int64) {
+	if index < w.index {
+		println("gcprog: Advance", index, "but index is", w.index)
+		panic("gcprog: invalid Advance index")
+	}
+	skip := (index - w.index)
+	if skip == 0 {
+		return
+	}
+	if skip < 4*8 {
+		if w.debug != nil {
+			fmt.Fprintf(w.debug, "gcprog: advance to %d by literals\n", index)
+		}
+		for i := int64(0); i < skip; i++ {
+			w.lit(0)
+		}
+		return
+	}
+
+	if w.debug != nil {
+		fmt.Fprintf(w.debug, "gcprog: advance to %d by repeat\n", index)
+	}
+	w.lit(0)
+	w.flushlit()
+	w.Repeat(1, skip-1)
+}
+
+// Append emits the given GC program into the current output.
+// The caller asserts that the program emits n bits (describes n words),
+// and Append panics if that is not true.
+func (w *Writer) Append(prog []byte, n int64) {
+	w.flushlit()
+	if w.debug != nil {
+		fmt.Fprintf(w.debug, "gcprog: append prog for %d ptrs\n", n)
+		fmt.Fprintf(w.debug, "\t")
+	}
+	n1 := progbits(prog)
+	if n1 != n {
+		panic("gcprog: wrong bit count in append")
+	}
+	// The last byte of the prog terminates the program.
+	// Don't emit that, or else our own program will end.
+	for i, x := range prog[:len(prog)-1] {
+		if w.debug != nil {
+			if i > 0 {
+				fmt.Fprintf(w.debug, " ")
+			}
+			fmt.Fprintf(w.debug, "%02x", x)
+		}
+		w.byte(x)
+	}
+	if w.debug != nil {
+		fmt.Fprintf(w.debug, "\n")
+	}
+	w.index += n
+}
+
+// progbits returns the length of the bit stream encoded by the program p.
+func progbits(p []byte) int64 {
+	var n int64
+	for len(p) > 0 {
+		x := p[0]
+		p = p[1:]
+		if x == 0 {
+			break
+		}
+		if x&0x80 == 0 {
+			count := x &^ 0x80
+			n += int64(count)
+			p = p[(count+7)/8:]
+			continue
+		}
+		nbit := int64(x &^ 0x80)
+		if nbit == 0 {
+			nbit, p = readvarint(p)
+		}
+		var count int64
+		count, p = readvarint(p)
+		n += nbit * count
+	}
+	if len(p) > 0 {
+		println("gcprog: found end instruction after", n, "ptrs, with", len(p), "bytes remaining")
+		panic("gcprog: extra data at end of program")
+	}
+	return n
+}
+
+// readvarint reads a varint from p, returning the value and the remainder of p.
+func readvarint(p []byte) (int64, []byte) {
+	var v int64
+	var nb uint
+	for {
+		c := p[0]
+		p = p[1:]
+		v |= int64(c&^0x80) << nb
+		nb += 7
+		if c&0x80 == 0 {
+			break
+		}
+	}
+	return v, p
+}
+
+// lit adds a single literal bit to w.
+func (w *Writer) lit(x byte) {
+	if w.nb == progMaxLiteral {
+		w.flushlit()
+	}
+	w.b[w.nb] = x
+	w.nb++
+	w.index++
+}
+
+// varint emits the varint encoding of x.
+func (w *Writer) varint(x int64) {
+	if x < 0 {
+		panic("gcprog: negative varint")
+	}
+	for x >= 0x80 {
+		w.byte(byte(0x80 | x))
+		x >>= 7
+	}
+	w.byte(byte(x))
+}
+
+// flushlit flushes any pending literal bits.
+func (w *Writer) flushlit() {
+	if w.nb == 0 {
+		return
+	}
+	if w.debug != nil {
+		fmt.Fprintf(w.debug, "gcprog: flush %d literals\n", w.nb)
+		fmt.Fprintf(w.debug, "\t%v\n", w.b[:w.nb])
+		fmt.Fprintf(w.debug, "\t%02x", byte(w.nb))
+	}
+	w.byte(byte(w.nb))
+	var bits uint8
+	for i := 0; i < w.nb; i++ {
+		bits |= w.b[i] << uint(i%8)
+		if (i+1)%8 == 0 {
+			if w.debug != nil {
+				fmt.Fprintf(w.debug, " %02x", bits)
+			}
+			w.byte(bits)
+			bits = 0
+		}
+	}
+	if w.nb%8 != 0 {
+		if w.debug != nil {
+			fmt.Fprintf(w.debug, " %02x", bits)
+		}
+		w.byte(bits)
+	}
+	if w.debug != nil {
+		fmt.Fprintf(w.debug, "\n")
+	}
+	w.nb = 0
+}
diff --git a/src/cmd/internal/goobj/read.go b/src/cmd/internal/goobj/read.go
index 79a83e5..1b0c964 100644
--- a/src/cmd/internal/goobj/read.go
+++ b/src/cmd/internal/goobj/read.go
@@ -12,6 +12,7 @@ package goobj
 import (
 	"bufio"
 	"bytes"
+	"cmd/internal/obj"
 	"errors"
 	"fmt"
 	"io"
@@ -31,45 +32,46 @@ const (
 	_ SymKind = iota
 
 	// readonly, executable
-	STEXT
-	SELFRXSECT
+	STEXT      SymKind = obj.STEXT
+	SELFRXSECT SymKind = obj.SELFRXSECT
 
 	// readonly, non-executable
-	STYPE
-	SSTRING
-	SGOSTRING
-	SGOFUNC
-	SRODATA
-	SFUNCTAB
-	STYPELINK
-	SSYMTAB // TODO: move to unmapped section
-	SPCLNTAB
-	SELFROSECT
+	STYPE      SymKind = obj.STYPE
+	SSTRING    SymKind = obj.SSTRING
+	SGOSTRING  SymKind = obj.SGOSTRING
+	SGOFUNC    SymKind = obj.SGOFUNC
+	SRODATA    SymKind = obj.SRODATA
+	SFUNCTAB   SymKind = obj.SFUNCTAB
+	STYPELINK  SymKind = obj.STYPELINK
+	SSYMTAB    SymKind = obj.SSYMTAB // TODO: move to unmapped section
+	SPCLNTAB   SymKind = obj.SPCLNTAB
+	SELFROSECT SymKind = obj.SELFROSECT
 
 	// writable, non-executable
-	SMACHOPLT
-	SELFSECT
-	SMACHO // Mach-O __nl_symbol_ptr
-	SMACHOGOT
-	SNOPTRDATA
-	SINITARR
-	SDATA
-	SWINDOWS
-	SBSS
-	SNOPTRBSS
-	STLSBSS
+	SMACHOPLT  SymKind = obj.SMACHOPLT
+	SELFSECT   SymKind = obj.SELFSECT
+	SMACHO     SymKind = obj.SMACHO // Mach-O __nl_symbol_ptr
+	SMACHOGOT  SymKind = obj.SMACHOGOT
+	SWINDOWS   SymKind = obj.SWINDOWS
+	SELFGOT    SymKind = obj.SELFGOT
+	SNOPTRDATA SymKind = obj.SNOPTRDATA
+	SINITARR   SymKind = obj.SINITARR
+	SDATA      SymKind = obj.SDATA
+	SBSS       SymKind = obj.SBSS
+	SNOPTRBSS  SymKind = obj.SNOPTRBSS
+	STLSBSS    SymKind = obj.STLSBSS
 
 	// not mapped
-	SXREF
-	SMACHOSYMSTR
-	SMACHOSYMTAB
-	SMACHOINDIRECTPLT
-	SMACHOINDIRECTGOT
-	SFILE
-	SFILEPATH
-	SCONST
-	SDYNIMPORT
-	SHOSTOBJ
+	SXREF             SymKind = obj.SXREF
+	SMACHOSYMSTR      SymKind = obj.SMACHOSYMSTR
+	SMACHOSYMTAB      SymKind = obj.SMACHOSYMTAB
+	SMACHOINDIRECTPLT SymKind = obj.SMACHOINDIRECTPLT
+	SMACHOINDIRECTGOT SymKind = obj.SMACHOINDIRECTGOT
+	SFILE             SymKind = obj.SFILE
+	SFILEPATH         SymKind = obj.SFILEPATH
+	SCONST            SymKind = obj.SCONST
+	SDYNIMPORT        SymKind = obj.SDYNIMPORT
+	SHOSTOBJ          SymKind = obj.SHOSTOBJ
 )
 
 var symKindStrings = []string{
diff --git a/src/cmd/internal/obj/ar.go b/src/cmd/internal/obj/ar.go
new file mode 100644
index 0000000..7cbeafd
--- /dev/null
+++ b/src/cmd/internal/obj/ar.go
@@ -0,0 +1,45 @@
+// 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 obj
+
+// Inferno utils/include/ar.h
+// http://code.google.com/p/inferno-os/source/browse/utils/include/ar.h
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
+
+type ar_hdr struct {
+	name string
+	date string
+	uid  string
+	gid  string
+	mode string
+	size string
+	fmag string
+}
diff --git a/src/cmd/internal/obj/arm/a.out.go b/src/cmd/internal/obj/arm/a.out.go
new file mode 100644
index 0000000..1cb561d
--- /dev/null
+++ b/src/cmd/internal/obj/arm/a.out.go
@@ -0,0 +1,328 @@
+// Inferno utils/5c/5.out.h
+// http://code.google.com/p/inferno-os/source/browse/utils/5c/5.out.h
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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 arm
+
+import "cmd/internal/obj"
+
+//go:generate go run ../stringer.go -i $GOFILE -o anames.go -p arm
+
+const (
+	NSNAME = 8
+	NSYM   = 50
+	NREG   = 16
+)
+
+/* -1 disables use of REGARG */
+const (
+	REGARG = -1
+)
+
+const (
+	REG_R0 = obj.RBaseARM + iota // must be 16-aligned
+	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_F0 // must be 16-aligned
+	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_FPSR // must be 2-aligned
+	REG_FPCR
+
+	REG_CPSR // must be 2-aligned
+	REG_SPSR
+
+	MAXREG
+	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
+	/* compiler allocates register variables F0 up */
+	/* compiler allocates external registers F7 down */
+	FREGRET = REG_F0
+	FREGEXT = REG_F7
+	FREGTMP = REG_F15
+)
+
+const (
+	C_NONE = iota
+	C_REG
+	C_REGREG
+	C_REGREG2
+	C_REGLIST
+	C_SHIFT
+	C_FREG
+	C_PSR
+	C_FCR
+
+	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  /* 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 /* both nil and R */
+	C_LOREG
+
+	C_PC
+	C_SP
+	C_HREG
+
+	C_ADDR /* reference to relocatable address */
+	C_TEXTSIZE
+
+	C_GOK
+
+	C_NCLASS /* must be the last */
+)
+
+const (
+	AAND = obj.ABaseARM + obj.A_ARCHSPECIFIC + iota
+	AEOR
+	ASUB
+	ARSB
+	AADD
+	AADC
+	ASBC
+	ARSC
+	ATST
+	ATEQ
+	ACMP
+	ACMN
+	AORR
+	ABIC
+
+	AMVN
+
+	/*
+	 * Do not reorder or fragment the conditional branch
+	 * opcodes, or the predication code will break
+	 */
+	ABEQ
+	ABNE
+	ABCS
+	ABHS
+	ABCC
+	ABLO
+	ABMI
+	ABPL
+	ABVS
+	ABVC
+	ABHI
+	ABLS
+	ABGE
+	ABLT
+	ABGT
+	ABLE
+
+	AMOVWD
+	AMOVWF
+	AMOVDW
+	AMOVFW
+	AMOVFD
+	AMOVDF
+	AMOVF
+	AMOVD
+
+	ACMPF
+	ACMPD
+	AADDF
+	AADDD
+	ASUBF
+	ASUBD
+	AMULF
+	AMULD
+	ADIVF
+	ADIVD
+	ASQRTF
+	ASQRTD
+	AABSF
+	AABSD
+
+	ASRL
+	ASRA
+	ASLL
+	AMULU
+	ADIVU
+	AMUL
+	ADIV
+	AMOD
+	AMODU
+
+	AMOVB
+	AMOVBS
+	AMOVBU
+	AMOVH
+	AMOVHS
+	AMOVHU
+	AMOVW
+	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 // 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 /* 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
+	C_SCOND_LO   = 3 ^ C_SCOND_XOR
+	C_SCOND_MI   = 4 ^ C_SCOND_XOR
+	C_SCOND_PL   = 5 ^ C_SCOND_XOR
+	C_SCOND_VS   = 6 ^ C_SCOND_XOR
+	C_SCOND_VC   = 7 ^ C_SCOND_XOR
+	C_SCOND_HI   = 8 ^ C_SCOND_XOR
+	C_SCOND_LS   = 9 ^ C_SCOND_XOR
+	C_SCOND_GE   = 10 ^ C_SCOND_XOR
+	C_SCOND_LT   = 11 ^ C_SCOND_XOR
+	C_SCOND_GT   = 12 ^ C_SCOND_XOR
+	C_SCOND_LE   = 13 ^ C_SCOND_XOR
+	C_SCOND_NONE = 14 ^ C_SCOND_XOR
+	C_SCOND_NV   = 15 ^ C_SCOND_XOR
+
+	/* 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..1a924f0
--- /dev/null
+++ b/src/cmd/internal/obj/arm/anames.go
@@ -0,0 +1,108 @@
+// Generated by stringer -i a.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
new file mode 100644
index 0000000..2e3a1f9
--- /dev/null
+++ b/src/cmd/internal/obj/arm/anames5.go
@@ -0,0 +1,70 @@
+// 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 arm
+
+var cnames5 = []string{
+	"NONE",
+	"REG",
+	"REGREG",
+	"REGREG2",
+	"SHIFT",
+	"FREG",
+	"PSR",
+	"FCR",
+	"RCON",
+	"NCON",
+	"SCON",
+	"LCON",
+	"LCONADDR",
+	"ZFCON",
+	"SFCON",
+	"LFCON",
+	"RACON",
+	"LACON",
+	"SBRA",
+	"LBRA",
+	"HAUTO",
+	"FAUTO",
+	"HFAUTO",
+	"SAUTO",
+	"LAUTO",
+	"HOREG",
+	"FOREG",
+	"HFOREG",
+	"SOREG",
+	"ROREG",
+	"SROREG",
+	"LOREG",
+	"PC",
+	"SP",
+	"HREG",
+	"ADDR",
+	"TEXTSIZE",
+	"GOK",
+	"NCLASS",
+	"SCOND = (1<<4)-1",
+	"SBIT = 1<<4",
+	"PBIT = 1<<5",
+	"WBIT = 1<<6",
+	"FBIT = 1<<7",
+	"UBIT = 1<<7",
+	"SCOND_XOR = 14",
+	"SCOND_EQ = 0 ^ C_SCOND_XOR",
+	"SCOND_NE = 1 ^ C_SCOND_XOR",
+	"SCOND_HS = 2 ^ C_SCOND_XOR",
+	"SCOND_LO = 3 ^ C_SCOND_XOR",
+	"SCOND_MI = 4 ^ C_SCOND_XOR",
+	"SCOND_PL = 5 ^ C_SCOND_XOR",
+	"SCOND_VS = 6 ^ C_SCOND_XOR",
+	"SCOND_VC = 7 ^ C_SCOND_XOR",
+	"SCOND_HI = 8 ^ C_SCOND_XOR",
+	"SCOND_LS = 9 ^ C_SCOND_XOR",
+	"SCOND_GE = 10 ^ C_SCOND_XOR",
+	"SCOND_LT = 11 ^ C_SCOND_XOR",
+	"SCOND_GT = 12 ^ C_SCOND_XOR",
+	"SCOND_LE = 13 ^ C_SCOND_XOR",
+	"SCOND_NONE = 14 ^ C_SCOND_XOR",
+	"SCOND_NV = 15 ^ C_SCOND_XOR",
+}
diff --git a/src/cmd/internal/obj/arm/asm5.go b/src/cmd/internal/obj/arm/asm5.go
new file mode 100644
index 0000000..610637c
--- /dev/null
+++ b/src/cmd/internal/obj/arm/asm5.go
@@ -0,0 +1,2855 @@
+// Inferno utils/5l/span.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5l/span.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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 arm
+
+import (
+	"cmd/internal/obj"
+	"fmt"
+	"log"
+	"math"
+	"sort"
+)
+
+type Optab struct {
+	as       uint16
+	a1       uint8
+	a2       int8
+	a3       uint8
+	type_    uint8
+	size     int8
+	param    int16
+	flag     int8
+	pcrelsiz uint8
+}
+
+type Oprang struct {
+	start []Optab
+	stop  []Optab
+}
+
+type Opcross [32][2][32]uint8
+
+const (
+	LFROM  = 1 << 0
+	LTO    = 1 << 1
+	LPOOL  = 1 << 2
+	LPCREL = 1 << 3
+)
+
+var optab = []Optab{
+	/* struct Optab:
+	OPCODE,	from, prog->reg, to,		 type,size,param,flag */
+	Optab{obj.ATEXT, C_ADDR, C_NONE, C_TEXTSIZE, 0, 0, 0, 0, 0},
+	Optab{AADD, C_REG, C_REG, C_REG, 1, 4, 0, 0, 0},
+	Optab{AADD, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0},
+	Optab{AMOVW, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0},
+	Optab{AMVN, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0},
+	Optab{ACMP, C_REG, C_REG, C_NONE, 1, 4, 0, 0, 0},
+	Optab{AADD, C_RCON, C_REG, C_REG, 2, 4, 0, 0, 0},
+	Optab{AADD, C_RCON, C_NONE, C_REG, 2, 4, 0, 0, 0},
+	Optab{AMOVW, C_RCON, C_NONE, C_REG, 2, 4, 0, 0, 0},
+	Optab{AMVN, C_RCON, C_NONE, C_REG, 2, 4, 0, 0, 0},
+	Optab{ACMP, C_RCON, C_REG, C_NONE, 2, 4, 0, 0, 0},
+	Optab{AADD, C_SHIFT, C_REG, C_REG, 3, 4, 0, 0, 0},
+	Optab{AADD, C_SHIFT, C_NONE, C_REG, 3, 4, 0, 0, 0},
+	Optab{AMVN, C_SHIFT, C_NONE, C_REG, 3, 4, 0, 0, 0},
+	Optab{ACMP, C_SHIFT, C_REG, C_NONE, 3, 4, 0, 0, 0},
+	Optab{AMOVW, C_RACON, C_NONE, C_REG, 4, 4, REGSP, 0, 0},
+	Optab{AB, C_NONE, C_NONE, C_SBRA, 5, 4, 0, LPOOL, 0},
+	Optab{ABL, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0},
+	Optab{ABX, C_NONE, C_NONE, C_SBRA, 74, 20, 0, 0, 0},
+	Optab{ABEQ, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0},
+	Optab{ABEQ, C_RCON, C_NONE, C_SBRA, 5, 4, 0, 0, 0}, // prediction hinted form, hint ignored
+
+	Optab{AB, C_NONE, C_NONE, C_ROREG, 6, 4, 0, LPOOL, 0},
+	Optab{ABL, C_NONE, C_NONE, C_ROREG, 7, 4, 0, 0, 0},
+	Optab{ABL, C_REG, C_NONE, C_ROREG, 7, 4, 0, 0, 0},
+	Optab{ABX, C_NONE, C_NONE, C_ROREG, 75, 12, 0, 0, 0},
+	Optab{ABXRET, C_NONE, C_NONE, C_ROREG, 76, 4, 0, 0, 0},
+	Optab{ASLL, C_RCON, C_REG, C_REG, 8, 4, 0, 0, 0},
+	Optab{ASLL, C_RCON, C_NONE, C_REG, 8, 4, 0, 0, 0},
+	Optab{ASLL, C_REG, C_NONE, C_REG, 9, 4, 0, 0, 0},
+	Optab{ASLL, C_REG, C_REG, C_REG, 9, 4, 0, 0, 0},
+	Optab{ASWI, C_NONE, C_NONE, C_NONE, 10, 4, 0, 0, 0},
+	Optab{ASWI, C_NONE, C_NONE, C_LOREG, 10, 4, 0, 0, 0},
+	Optab{ASWI, C_NONE, C_NONE, C_LCON, 10, 4, 0, 0, 0},
+	Optab{AWORD, C_NONE, C_NONE, C_LCON, 11, 4, 0, 0, 0},
+	Optab{AWORD, C_NONE, C_NONE, C_LCONADDR, 11, 4, 0, 0, 0},
+	Optab{AWORD, C_NONE, C_NONE, C_ADDR, 11, 4, 0, 0, 0},
+	Optab{AMOVW, C_NCON, C_NONE, C_REG, 12, 4, 0, 0, 0},
+	Optab{AMOVW, C_LCON, C_NONE, C_REG, 12, 4, 0, LFROM, 0},
+	Optab{AMOVW, C_LCONADDR, C_NONE, C_REG, 12, 4, 0, LFROM | LPCREL, 4},
+	Optab{AADD, C_NCON, C_REG, C_REG, 13, 8, 0, 0, 0},
+	Optab{AADD, C_NCON, C_NONE, C_REG, 13, 8, 0, 0, 0},
+	Optab{AMVN, C_NCON, C_NONE, C_REG, 13, 8, 0, 0, 0},
+	Optab{ACMP, C_NCON, C_REG, C_NONE, 13, 8, 0, 0, 0},
+	Optab{AADD, C_LCON, C_REG, C_REG, 13, 8, 0, LFROM, 0},
+	Optab{AADD, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM, 0},
+	Optab{AMVN, C_LCON, C_NONE, C_REG, 13, 8, 0, LFROM, 0},
+	Optab{ACMP, C_LCON, C_REG, C_NONE, 13, 8, 0, LFROM, 0},
+	Optab{AMOVB, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0},
+	Optab{AMOVBS, C_REG, C_NONE, C_REG, 14, 8, 0, 0, 0},
+	Optab{AMOVBU, C_REG, C_NONE, C_REG, 58, 4, 0, 0, 0},
+	Optab{AMOVH, C_REG, C_NONE, C_REG, 1, 4, 0, 0, 0},
+	Optab{AMOVHS, C_REG, C_NONE, C_REG, 14, 8, 0, 0, 0},
+	Optab{AMOVHU, C_REG, C_NONE, C_REG, 14, 8, 0, 0, 0},
+	Optab{AMUL, C_REG, C_REG, C_REG, 15, 4, 0, 0, 0},
+	Optab{AMUL, C_REG, C_NONE, C_REG, 15, 4, 0, 0, 0},
+	Optab{ADIV, C_REG, C_REG, C_REG, 16, 4, 0, 0, 0},
+	Optab{ADIV, C_REG, C_NONE, C_REG, 16, 4, 0, 0, 0},
+	Optab{AMULL, C_REG, C_REG, C_REGREG, 17, 4, 0, 0, 0},
+	Optab{AMULA, C_REG, C_REG, C_REGREG2, 17, 4, 0, 0, 0},
+	Optab{AMOVW, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP, 0, 0},
+	Optab{AMOVW, C_REG, C_NONE, C_SOREG, 20, 4, 0, 0, 0},
+	Optab{AMOVB, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP, 0, 0},
+	Optab{AMOVB, C_REG, C_NONE, C_SOREG, 20, 4, 0, 0, 0},
+	Optab{AMOVBS, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP, 0, 0},
+	Optab{AMOVBS, C_REG, C_NONE, C_SOREG, 20, 4, 0, 0, 0},
+	Optab{AMOVBU, C_REG, C_NONE, C_SAUTO, 20, 4, REGSP, 0, 0},
+	Optab{AMOVBU, C_REG, C_NONE, C_SOREG, 20, 4, 0, 0, 0},
+	Optab{AMOVW, C_SAUTO, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
+	Optab{AMOVW, C_SOREG, C_NONE, C_REG, 21, 4, 0, 0, 0},
+	Optab{AMOVBU, C_SAUTO, C_NONE, C_REG, 21, 4, REGSP, 0, 0},
+	Optab{AMOVBU, C_SOREG, C_NONE, C_REG, 21, 4, 0, 0, 0},
+	Optab{AMOVW, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0},
+	Optab{AMOVW, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO, 0},
+	Optab{AMOVW, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4},
+	Optab{AMOVB, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0},
+	Optab{AMOVB, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO, 0},
+	Optab{AMOVB, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4},
+	Optab{AMOVBS, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0},
+	Optab{AMOVBS, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO, 0},
+	Optab{AMOVBS, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4},
+	Optab{AMOVBU, C_REG, C_NONE, C_LAUTO, 30, 8, REGSP, LTO, 0},
+	Optab{AMOVBU, C_REG, C_NONE, C_LOREG, 30, 8, 0, LTO, 0},
+	Optab{AMOVBU, C_REG, C_NONE, C_ADDR, 64, 8, 0, LTO | LPCREL, 4},
+	Optab{AMOVW, C_LAUTO, C_NONE, C_REG, 31, 8, REGSP, LFROM, 0},
+	Optab{AMOVW, C_LOREG, C_NONE, C_REG, 31, 8, 0, LFROM, 0},
+	Optab{AMOVW, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM | LPCREL, 4},
+	Optab{AMOVBU, C_LAUTO, C_NONE, C_REG, 31, 8, REGSP, LFROM, 0},
+	Optab{AMOVBU, C_LOREG, C_NONE, C_REG, 31, 8, 0, LFROM, 0},
+	Optab{AMOVBU, C_ADDR, C_NONE, C_REG, 65, 8, 0, LFROM | LPCREL, 4},
+	Optab{AMOVW, C_LACON, C_NONE, C_REG, 34, 8, REGSP, LFROM, 0},
+	Optab{AMOVW, C_PSR, C_NONE, C_REG, 35, 4, 0, 0, 0},
+	Optab{AMOVW, C_REG, C_NONE, C_PSR, 36, 4, 0, 0, 0},
+	Optab{AMOVW, C_RCON, C_NONE, C_PSR, 37, 4, 0, 0, 0},
+	Optab{AMOVM, C_REGLIST, C_NONE, C_SOREG, 38, 4, 0, 0, 0},
+	Optab{AMOVM, C_SOREG, C_NONE, C_REGLIST, 39, 4, 0, 0, 0},
+	Optab{ASWPW, C_SOREG, C_REG, C_REG, 40, 4, 0, 0, 0},
+	Optab{ARFE, C_NONE, C_NONE, C_NONE, 41, 4, 0, 0, 0},
+	Optab{AMOVF, C_FREG, C_NONE, C_FAUTO, 50, 4, REGSP, 0, 0},
+	Optab{AMOVF, C_FREG, C_NONE, C_FOREG, 50, 4, 0, 0, 0},
+	Optab{AMOVF, C_FAUTO, C_NONE, C_FREG, 51, 4, REGSP, 0, 0},
+	Optab{AMOVF, C_FOREG, C_NONE, C_FREG, 51, 4, 0, 0, 0},
+	Optab{AMOVF, C_FREG, C_NONE, C_LAUTO, 52, 12, REGSP, LTO, 0},
+	Optab{AMOVF, C_FREG, C_NONE, C_LOREG, 52, 12, 0, LTO, 0},
+	Optab{AMOVF, C_LAUTO, C_NONE, C_FREG, 53, 12, REGSP, LFROM, 0},
+	Optab{AMOVF, C_LOREG, C_NONE, C_FREG, 53, 12, 0, LFROM, 0},
+	Optab{AMOVF, C_FREG, C_NONE, C_ADDR, 68, 8, 0, LTO | LPCREL, 4},
+	Optab{AMOVF, C_ADDR, C_NONE, C_FREG, 69, 8, 0, LFROM | LPCREL, 4},
+	Optab{AADDF, C_FREG, C_NONE, C_FREG, 54, 4, 0, 0, 0},
+	Optab{AADDF, C_FREG, C_REG, C_FREG, 54, 4, 0, 0, 0},
+	Optab{AMOVF, C_FREG, C_NONE, C_FREG, 54, 4, 0, 0, 0},
+	Optab{AMOVW, C_REG, C_NONE, C_FCR, 56, 4, 0, 0, 0},
+	Optab{AMOVW, C_FCR, C_NONE, C_REG, 57, 4, 0, 0, 0},
+	Optab{AMOVW, C_SHIFT, C_NONE, C_REG, 59, 4, 0, 0, 0},
+	Optab{AMOVBU, C_SHIFT, C_NONE, C_REG, 59, 4, 0, 0, 0},
+	Optab{AMOVB, C_SHIFT, C_NONE, C_REG, 60, 4, 0, 0, 0},
+	Optab{AMOVBS, C_SHIFT, C_NONE, C_REG, 60, 4, 0, 0, 0},
+	Optab{AMOVW, C_REG, C_NONE, C_SHIFT, 61, 4, 0, 0, 0},
+	Optab{AMOVB, C_REG, C_NONE, C_SHIFT, 61, 4, 0, 0, 0},
+	Optab{AMOVBS, C_REG, C_NONE, C_SHIFT, 61, 4, 0, 0, 0},
+	Optab{AMOVBU, C_REG, C_NONE, C_SHIFT, 61, 4, 0, 0, 0},
+	Optab{ACASE, C_REG, C_NONE, C_NONE, 62, 4, 0, LPCREL, 8},
+	Optab{ABCASE, C_NONE, C_NONE, C_SBRA, 63, 4, 0, LPCREL, 0},
+	Optab{AMOVH, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0, 0},
+	Optab{AMOVH, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0, 0},
+	Optab{AMOVHS, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0, 0},
+	Optab{AMOVHS, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0, 0},
+	Optab{AMOVHU, C_REG, C_NONE, C_HAUTO, 70, 4, REGSP, 0, 0},
+	Optab{AMOVHU, C_REG, C_NONE, C_HOREG, 70, 4, 0, 0, 0},
+	Optab{AMOVB, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0},
+	Optab{AMOVB, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0},
+	Optab{AMOVBS, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0},
+	Optab{AMOVBS, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0},
+	Optab{AMOVH, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0},
+	Optab{AMOVH, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0},
+	Optab{AMOVHS, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0},
+	Optab{AMOVHS, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0},
+	Optab{AMOVHU, C_HAUTO, C_NONE, C_REG, 71, 4, REGSP, 0, 0},
+	Optab{AMOVHU, C_HOREG, C_NONE, C_REG, 71, 4, 0, 0, 0},
+	Optab{AMOVH, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO, 0},
+	Optab{AMOVH, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO, 0},
+	Optab{AMOVH, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4},
+	Optab{AMOVHS, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO, 0},
+	Optab{AMOVHS, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO, 0},
+	Optab{AMOVHS, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4},
+	Optab{AMOVHU, C_REG, C_NONE, C_LAUTO, 72, 8, REGSP, LTO, 0},
+	Optab{AMOVHU, C_REG, C_NONE, C_LOREG, 72, 8, 0, LTO, 0},
+	Optab{AMOVHU, C_REG, C_NONE, C_ADDR, 94, 8, 0, LTO | LPCREL, 4},
+	Optab{AMOVB, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0},
+	Optab{AMOVB, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0},
+	Optab{AMOVB, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4},
+	Optab{AMOVBS, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0},
+	Optab{AMOVBS, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0},
+	Optab{AMOVBS, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4},
+	Optab{AMOVH, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0},
+	Optab{AMOVH, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0},
+	Optab{AMOVH, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4},
+	Optab{AMOVHS, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0},
+	Optab{AMOVHS, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0},
+	Optab{AMOVHS, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4},
+	Optab{AMOVHU, C_LAUTO, C_NONE, C_REG, 73, 8, REGSP, LFROM, 0},
+	Optab{AMOVHU, C_LOREG, C_NONE, C_REG, 73, 8, 0, LFROM, 0},
+	Optab{AMOVHU, C_ADDR, C_NONE, C_REG, 93, 8, 0, LFROM | LPCREL, 4},
+	Optab{ALDREX, C_SOREG, C_NONE, C_REG, 77, 4, 0, 0, 0},
+	Optab{ASTREX, C_SOREG, C_REG, C_REG, 78, 4, 0, 0, 0},
+	Optab{AMOVF, C_ZFCON, C_NONE, C_FREG, 80, 8, 0, 0, 0},
+	Optab{AMOVF, C_SFCON, C_NONE, C_FREG, 81, 4, 0, 0, 0},
+	Optab{ACMPF, C_FREG, C_REG, C_NONE, 82, 8, 0, 0, 0},
+	Optab{ACMPF, C_FREG, C_NONE, C_NONE, 83, 8, 0, 0, 0},
+	Optab{AMOVFW, C_FREG, C_NONE, C_FREG, 84, 4, 0, 0, 0},
+	Optab{AMOVWF, C_FREG, C_NONE, C_FREG, 85, 4, 0, 0, 0},
+	Optab{AMOVFW, C_FREG, C_NONE, C_REG, 86, 8, 0, 0, 0},
+	Optab{AMOVWF, C_REG, C_NONE, C_FREG, 87, 8, 0, 0, 0},
+	Optab{AMOVW, C_REG, C_NONE, C_FREG, 88, 4, 0, 0, 0},
+	Optab{AMOVW, C_FREG, C_NONE, C_REG, 89, 4, 0, 0, 0},
+	Optab{ATST, C_REG, C_NONE, C_NONE, 90, 4, 0, 0, 0},
+	Optab{ALDREXD, C_SOREG, C_NONE, C_REG, 91, 4, 0, 0, 0},
+	Optab{ASTREXD, C_SOREG, C_REG, C_REG, 92, 4, 0, 0, 0},
+	Optab{APLD, C_SOREG, C_NONE, C_NONE, 95, 4, 0, 0, 0},
+	Optab{obj.AUNDEF, C_NONE, C_NONE, C_NONE, 96, 4, 0, 0, 0},
+	Optab{ACLZ, C_REG, C_NONE, C_REG, 97, 4, 0, 0, 0},
+	Optab{AMULWT, C_REG, C_REG, C_REG, 98, 4, 0, 0, 0},
+	Optab{AMULAWT, C_REG, C_REG, C_REGREG2, 99, 4, 0, 0, 0},
+	Optab{obj.AUSEFIELD, C_ADDR, C_NONE, C_NONE, 0, 0, 0, 0, 0},
+	Optab{obj.APCDATA, C_LCON, C_NONE, C_LCON, 0, 0, 0, 0, 0},
+	Optab{obj.AFUNCDATA, C_LCON, C_NONE, C_ADDR, 0, 0, 0, 0, 0},
+	Optab{obj.ANOP, C_NONE, C_NONE, C_NONE, 0, 0, 0, 0, 0},
+	Optab{obj.ADUFFZERO, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0}, // same as ABL
+	Optab{obj.ADUFFCOPY, C_NONE, C_NONE, C_SBRA, 5, 4, 0, 0, 0}, // same as ABL
+
+	Optab{ADATABUNDLE, C_NONE, C_NONE, C_NONE, 100, 4, 0, 0, 0},
+	Optab{ADATABUNDLEEND, C_NONE, C_NONE, C_NONE, 100, 0, 0, 0, 0},
+	Optab{obj.AXXX, C_NONE, C_NONE, C_NONE, 0, 4, 0, 0, 0},
+}
+
+var pool struct {
+	start uint32
+	size  uint32
+	extra uint32
+}
+
+var oprange [ALAST & obj.AMask]Oprang
+
+var xcmp [C_GOK + 1][C_GOK + 1]uint8
+
+var deferreturn *obj.LSym
+
+/* size of a case statement including jump table */
+func casesz(ctxt *obj.Link, p *obj.Prog) int32 {
+	var jt int = 0
+	var n int32 = 0
+	var o *Optab
+
+	for ; p != nil; p = p.Link {
+		if p.As == ABCASE {
+			jt = 1
+		} else if jt != 0 {
+			break
+		}
+		o = oplook(ctxt, p)
+		n += int32(o.size)
+	}
+
+	return n
+}
+
+// Note about encoding: Prog.scond holds the condition encoding,
+// but XOR'ed with C_SCOND_XOR, so that C_SCOND_NONE == 0.
+// The code that shifts the value << 28 has the responsibility
+// for XORing with C_SCOND_XOR too.
+
+// asmoutnacl assembles the instruction p. It replaces asmout for NaCl.
+// It returns the total number of bytes put in out, and it can change
+// p->pc if extra padding is necessary.
+// 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 {
+	size := int(o.size)
+
+	// instruction specific
+	switch p.As {
+	default:
+		if out != nil {
+			asmout(ctxt, p, o, out)
+		}
+
+	case ADATABUNDLE, // align to 16-byte boundary
+		ADATABUNDLEEND: // zero width instruction, just to align next instruction to 16-byte boundary
+		p.Pc = (p.Pc + 15) &^ 15
+
+		if out != nil {
+			asmout(ctxt, p, o, out)
+		}
+
+	case obj.AUNDEF,
+		APLD:
+		size = 4
+		if out != nil {
+			switch p.As {
+			case obj.AUNDEF:
+				out[0] = 0xe7fedef0 // NACL_INSTR_ARM_ABORT_NOW (UDF #0xEDE0)
+
+			case APLD:
+				out[0] = 0xe1a01001 // (MOVW R1, R1)
+			}
+		}
+
+	case AB, ABL:
+		if p.To.Type != obj.TYPE_MEM {
+			if out != nil {
+				asmout(ctxt, p, o, out)
+			}
+		} else {
+			if p.To.Offset != 0 || size != 4 || p.To.Reg > REG_R15 || p.To.Reg < REG_R0 {
+				ctxt.Diag("unsupported instruction: %v", p)
+			}
+			if p.Pc&15 == 12 {
+				p.Pc += 4
+			}
+			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
+				} else { // ABL
+					out[1] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x012fff30 | (uint32(p.To.Reg)&15)<<0 // BLX Rx
+				}
+			}
+
+			size = 8
+		}
+
+		// align the last instruction (the actual BL) to the last instruction in a bundle
+		if p.As == ABL {
+			if deferreturn == nil {
+				deferreturn = obj.Linklookup(ctxt, "runtime.deferreturn", 0)
+			}
+			if p.To.Sym == deferreturn {
+				p.Pc = ((int64(origPC) + 15) &^ 15) + 16 - int64(size)
+			} else {
+				p.Pc += (16 - ((p.Pc + int64(size)) & 15)) & 15
+			}
+		}
+
+	case ALDREX,
+		ALDREXD,
+		AMOVB,
+		AMOVBS,
+		AMOVBU,
+		AMOVD,
+		AMOVF,
+		AMOVH,
+		AMOVHS,
+		AMOVHU,
+		AMOVM,
+		AMOVW,
+		ASTREX,
+		ASTREXD:
+		if p.To.Type == obj.TYPE_REG && p.To.Reg == REG_R15 && p.From.Reg == REG_R13 { // MOVW.W x(R13), PC
+			if out != nil {
+				asmout(ctxt, p, o, out)
+			}
+			if size == 4 {
+				if out != nil {
+					// Note: 5c and 5g reg.c know that DIV/MOD smashes R12
+					// so that this return instruction expansion is valid.
+					out[0] = out[0] &^ 0x3000                                         // change PC to R12
+					out[1] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x03ccc13f // BIC $0xc000000f, R12
+					out[2] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x012fff1c // BX R12
+				}
+
+				size += 8
+				if (p.Pc+int64(size))&15 == 4 {
+					p.Pc += 4
+				}
+				break
+			} else {
+				// if the instruction used more than 4 bytes, then it must have used a very large
+				// offset to update R13, so we need to additionally mask R13.
+				if out != nil {
+					out[size/4-1] &^= 0x3000                                                 // change PC to R12
+					out[size/4] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x03cdd103   // BIC $0xc0000000, R13
+					out[size/4+1] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x03ccc13f // BIC $0xc000000f, R12
+					out[size/4+2] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x012fff1c // BX R12
+				}
+
+				// p->pc+size is only ok at 4 or 12 mod 16.
+				if (p.Pc+int64(size))%8 == 0 {
+					p.Pc += 4
+				}
+				size += 12
+				break
+			}
+		}
+
+		if p.To.Type == obj.TYPE_REG && p.To.Reg == REG_R15 {
+			ctxt.Diag("unsupported instruction (move to another register and use indirect jump instead): %v", p)
+		}
+
+		if p.To.Type == obj.TYPE_MEM && p.To.Reg == REG_R13 && (p.Scond&C_WBIT != 0) && size > 4 {
+			// function prolog with very large frame size: MOVW.W R14,-100004(R13)
+			// split it into two instructions:
+			// 	ADD $-100004, R13
+			// 	MOVW R14, 0(R13)
+			q := ctxt.NewProg()
+
+			p.Scond &^= C_WBIT
+			*q = *p
+			a := &p.To
+			var a2 *obj.Addr
+			if p.To.Type == obj.TYPE_MEM {
+				a2 = &q.To
+			} else {
+				a2 = &q.From
+			}
+			obj.Nocache(q)
+			obj.Nocache(p)
+
+			// insert q after p
+			q.Link = p.Link
+
+			p.Link = q
+			q.Pcond = nil
+
+			// make p into ADD $X, R13
+			p.As = AADD
+
+			p.From = *a
+			p.From.Reg = 0
+			p.From.Type = obj.TYPE_CONST
+			p.To = obj.Addr{}
+			p.To.Type = obj.TYPE_REG
+			p.To.Reg = REG_R13
+
+			// make q into p but load/store from 0(R13)
+			q.Spadj = 0
+
+			*a2 = obj.Addr{}
+			a2.Type = obj.TYPE_MEM
+			a2.Reg = REG_R13
+			a2.Sym = nil
+			a2.Offset = 0
+			size = int(oplook(ctxt, p).size)
+			break
+		}
+
+		if (p.To.Type == obj.TYPE_MEM && p.To.Reg != REG_R9) || // MOVW Rx, X(Ry), y != 9
+			(p.From.Type == obj.TYPE_MEM && p.From.Reg != REG_R9) { // MOVW X(Rx), Ry, x != 9
+			var a *obj.Addr
+			if p.To.Type == obj.TYPE_MEM {
+				a = &p.To
+			} else {
+				a = &p.From
+			}
+			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 {
+					if out != nil {
+						asmout(ctxt, p, o, out)
+					}
+				} else {
+					if out != nil {
+						out[0] = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x03c00103 | (uint32(reg)&15)<<16 | (uint32(reg)&15)<<12 // BIC $0xc0000000, Rx
+					}
+					if p.Pc&15 == 12 {
+						p.Pc += 4
+					}
+					size += 4
+					if out != nil {
+						asmout(ctxt, p, o, out[1:])
+					}
+				}
+
+				break
+			} else {
+				// if a load/store instruction takes more than 1 word to implement, then
+				// we need to separate the instruction into two:
+				// 1. explicitly load the address into R11.
+				// 2. load/store from R11.
+				// This won't handle .W/.P, so we should reject such code.
+				if p.Scond&(C_PBIT|C_WBIT) != 0 {
+					ctxt.Diag("unsupported instruction (.P/.W): %v", p)
+				}
+				q := ctxt.NewProg()
+				*q = *p
+				var a2 *obj.Addr
+				if p.To.Type == obj.TYPE_MEM {
+					a2 = &q.To
+				} else {
+					a2 = &q.From
+				}
+				obj.Nocache(q)
+				obj.Nocache(p)
+
+				// insert q after p
+				q.Link = p.Link
+
+				p.Link = q
+				q.Pcond = nil
+
+				// make p into MOVW $X(R), R11
+				p.As = AMOVW
+
+				p.From = *a
+				p.From.Type = obj.TYPE_ADDR
+				p.To = obj.Addr{}
+				p.To.Type = obj.TYPE_REG
+				p.To.Reg = REG_R11
+
+				// make q into p but load/store from 0(R11)
+				*a2 = obj.Addr{}
+
+				a2.Type = obj.TYPE_MEM
+				a2.Reg = REG_R11
+				a2.Sym = nil
+				a2.Offset = 0
+				size = int(oplook(ctxt, p).size)
+				break
+			}
+		} else if out != nil {
+			asmout(ctxt, p, o, out)
+		}
+	}
+
+	// destination register specific
+	if p.To.Type == obj.TYPE_REG {
+		switch p.To.Reg {
+		case REG_R9:
+			ctxt.Diag("invalid instruction, cannot write to R9: %v", p)
+
+		case REG_R13:
+			if out != nil {
+				out[size/4] = 0xe3cdd103 // BIC $0xc0000000, R13
+			}
+			if (p.Pc+int64(size))&15 == 0 {
+				p.Pc += 4
+			}
+			size += 4
+		}
+	}
+
+	return size
+}
+
+func span5(ctxt *obj.Link, cursym *obj.LSym) {
+	var p *obj.Prog
+	var op *obj.Prog
+
+	p = cursym.Text
+	if p == nil || p.Link == nil { // handle external functions and ELF section symbols
+		return
+	}
+
+	if oprange[AAND&obj.AMask].start == nil {
+		buildop(ctxt)
+	}
+
+	ctxt.Cursym = cursym
+
+	ctxt.Autosize = int32(p.To.Offset + 4)
+	c := int32(0)
+
+	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
+				continue
+			}
+
+			// can't happen: blitrl is not nil, but checkpool didn't flushpool
+			ctxt.Diag("internal inconsistency")
+
+			break
+		}
+
+		ctxt.Curp = p
+		p.Pc = int64(c)
+		o = oplook(ctxt, p)
+		if ctxt.Headtype != obj.Hnacl {
+			m = int(o.size)
+		} else {
+			m = asmoutnacl(ctxt, c, p, o, nil)
+			c = int32(p.Pc)     // asmoutnacl might change pc for alignment
+			o = oplook(ctxt, p) // asmoutnacl might change p in rare cases
+		}
+
+		if m%4 != 0 || p.Pc%4 != 0 {
+			ctxt.Diag("!pc invalid: %v size=%d", p, m)
+		}
+
+		// must check literal pool here in case p generates many instructions
+		if ctxt.Blitrl != nil {
+			i = m
+			if p.As == ACASE {
+				i = int(casesz(ctxt, p))
+			}
+			if checkpool(ctxt, op, i) {
+				p = op
+				continue
+			}
+		}
+
+		if m == 0 && (p.As != obj.AFUNCDATA && p.As != obj.APCDATA && p.As != ADATABUNDLEEND && p.As != obj.ANOP) {
+			ctxt.Diag("zero-width instruction\n%v", p)
+			continue
+		}
+
+		switch o.flag & (LFROM | LTO | LPOOL) {
+		case LFROM:
+			addpool(ctxt, p, &p.From)
+
+		case LTO:
+			addpool(ctxt, p, &p.To)
+
+		case LPOOL:
+			if p.Scond&C_SCOND == C_SCOND_NONE {
+				flushpool(ctxt, p, 0, 0)
+			}
+		}
+
+		if p.As == AMOVW && p.To.Type == obj.TYPE_REG && p.To.Reg == REGPC && p.Scond&C_SCOND == C_SCOND_NONE {
+			flushpool(ctxt, p, 0, 0)
+		}
+		c += int32(m)
+	}
+
+	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.
+	 */
+	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())
+		}
+		bflag = 0
+		c = 0
+		times++
+		cursym.Text.Pc = 0 // force re-layout the code.
+		for p = cursym.Text; p != nil; p = p.Link {
+			ctxt.Curp = p
+			o = oplook(ctxt, p)
+			if int64(c) > p.Pc {
+				p.Pc = int64(c)
+			}
+
+			/* very large branches
+			if(o->type == 6 && p->pcond) {
+				otxt = p->pcond->pc - c;
+				if(otxt < 0)
+					otxt = -otxt;
+				if(otxt >= (1L<<17) - 10) {
+					q = emallocz(sizeof(Prog));
+					q->link = p->link;
+					p->link = q;
+					q->as = AB;
+					q->to.type = TYPE_BRANCH;
+					q->pcond = p->pcond;
+					p->pcond = q;
+					q = emallocz(sizeof(Prog));
+					q->link = p->link;
+					p->link = q;
+					q->as = AB;
+					q->to.type = TYPE_BRANCH;
+					q->pcond = q->link->link;
+					bflag = 1;
+				}
+			}
+			*/
+			opc = int32(p.Pc)
+
+			if ctxt.Headtype != obj.Hnacl {
+				m = int(o.size)
+			} else {
+				m = asmoutnacl(ctxt, c, p, o, nil)
+			}
+			if p.Pc != int64(opc) {
+				bflag = 1
+			}
+
+			//print("%v pc changed %d to %d in iter. %d\n", p, opc, (int32)p->pc, times);
+			c = int32(p.Pc + int64(m))
+
+			if m%4 != 0 || p.Pc%4 != 0 {
+				ctxt.Diag("pc invalid: %v size=%d", p, m)
+			}
+
+			if m/4 > len(out) {
+				ctxt.Diag("instruction size too large: %d > %d", m/4, len(out))
+			}
+			if m == 0 && (p.As != obj.AFUNCDATA && p.As != obj.APCDATA && p.As != ADATABUNDLEEND && p.As != obj.ANOP) {
+				if p.As == obj.ATEXT {
+					ctxt.Autosize = int32(p.To.Offset + 4)
+					continue
+				}
+
+				ctxt.Diag("zero-width instruction\n%v", p)
+				continue
+			}
+		}
+
+		cursym.Size = int64(c)
+		if bflag == 0 {
+			break
+		}
+	}
+
+	if c%4 != 0 {
+		ctxt.Diag("sym->size=%d, invalid", c)
+	}
+
+	/*
+	 * lay out the code.  all the pc-relative code references,
+	 * even cross-function, are resolved now;
+	 * only data references need to be relocated.
+	 * with more work we could leave cross-function
+	 * code references to be relocated too, and then
+	 * perhaps we'd be able to parallelize the span loop above.
+	 */
+	if ctxt.Tlsg == nil {
+		ctxt.Tlsg = obj.Linklookup(ctxt, "runtime.tlsg", 0)
+	}
+
+	p = cursym.Text
+	ctxt.Autosize = int32(p.To.Offset + 4)
+	obj.Symgrow(ctxt, cursym, cursym.Size)
+
+	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
+		o = oplook(ctxt, p)
+		opc = int32(p.Pc)
+		if ctxt.Headtype != obj.Hnacl {
+			asmout(ctxt, p, o, out[:])
+			m = int(o.size)
+		} else {
+			m = asmoutnacl(ctxt, c, p, o, out[:])
+			if int64(opc) != p.Pc {
+				ctxt.Diag("asmoutnacl broken: pc changed (%d->%d) in last stage: %v", opc, int32(p.Pc), p)
+			}
+		}
+
+		if m%4 != 0 || p.Pc%4 != 0 {
+			ctxt.Diag("final stage: pc invalid: %v size=%d", p, m)
+		}
+
+		if int64(c) > p.Pc {
+			ctxt.Diag("PC padding invalid: want %#d, has %#d: %v", p.Pc, c, p)
+		}
+		for int64(c) != p.Pc {
+			// emit 0xe1a00000 (MOVW R0, R0)
+			bp[0] = 0x00
+			bp = bp[1:]
+
+			bp[0] = 0x00
+			bp = bp[1:]
+			bp[0] = 0xa0
+			bp = bp[1:]
+			bp[0] = 0xe1
+			bp = bp[1:]
+			c += 4
+		}
+
+		for i = 0; i < m/4; i++ {
+			v = int(out[i])
+			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)
+			bp = bp[1:]
+		}
+
+		c += int32(m)
+	}
+}
+
+/*
+ * when the first reference to the literal pool threatens
+ * to go out of range of a 12-bit PC-relative offset,
+ * drop the pool now, and branch round it.
+ * this happens only in extended basic blocks that exceed 4k.
+ */
+func checkpool(ctxt *obj.Link, p *obj.Prog, sz int) bool {
+	if pool.size >= 0xff0 || immaddr(int32((p.Pc+int64(sz)+4)+4+int64(12+pool.size)-int64(pool.start+8))) == 0 {
+		return flushpool(ctxt, p, 1, 0)
+	} else if p.Link == nil {
+		return flushpool(ctxt, p, 2, 0)
+	}
+	return false
+}
+
+func flushpool(ctxt *obj.Link, p *obj.Prog, skip int, force int) bool {
+	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.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 force == 0 && (p.Pc+int64(12+pool.size)-int64(pool.start) < 2048) { // 12 take into account the maximum nacl literal pool alignment padding size
+			return false
+		}
+		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.As = ADATABUNDLEEND
+			ctxt.Elitrl.Link = q
+			ctxt.Elitrl = q
+		}
+
+		// The line number for constant pool entries doesn't really matter.
+		// We set it to the line number of the preceding instruction so that
+		// there are no deltas to encode in the pc-line tables.
+		for q := ctxt.Blitrl; q != nil; q = q.Link {
+			q.Lineno = p.Lineno
+		}
+
+		ctxt.Elitrl.Link = p.Link
+		p.Link = ctxt.Blitrl
+
+		ctxt.Blitrl = nil /* BUG: should refer back to values until out-of-range */
+		ctxt.Elitrl = nil
+		pool.size = 0
+		pool.start = 0
+		pool.extra = 0
+		return true
+	}
+
+	return false
+}
+
+func addpool(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) {
+	var t obj.Prog
+
+	c := aclass(ctxt, a)
+
+	t.Ctxt = ctxt
+	t.As = AWORD
+
+	switch c {
+	default:
+		t.To.Offset = a.Offset
+		t.To.Sym = a.Sym
+		t.To.Type = a.Type
+		t.To.Name = a.Name
+
+		if ctxt.Flag_shared != 0 && t.To.Sym != nil {
+			t.Rel = p
+		}
+
+	case C_SROREG,
+		C_LOREG,
+		C_ROREG,
+		C_FOREG,
+		C_SOREG,
+		C_HOREG,
+		C_FAUTO,
+		C_SAUTO,
+		C_LAUTO,
+		C_LACON:
+		t.To.Type = obj.TYPE_CONST
+		t.To.Offset = ctxt.Instoffset
+	}
+
+	if t.Rel == nil {
+		for q := ctxt.Blitrl; q != nil; q = q.Link { /* could hash on t.t0.offset */
+			if q.Rel == nil && q.To == t.To {
+				p.Pcond = q
+				return
+			}
+		}
+	}
+
+	if ctxt.Headtype == obj.Hnacl && pool.size%16 == 0 {
+		// start a new data bundle
+		q := ctxt.NewProg()
+		q.As = ADATABUNDLE
+		q.Pc = int64(pool.size)
+		pool.size += 4
+		if ctxt.Blitrl == nil {
+			ctxt.Blitrl = q
+			pool.start = uint32(p.Pc)
+		} else {
+			ctxt.Elitrl.Link = q
+		}
+
+		ctxt.Elitrl = q
+	}
+
+	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 += 4
+
+	p.Pcond = q
+}
+
+func regoff(ctxt *obj.Link, a *obj.Addr) int32 {
+	ctxt.Instoffset = 0
+	aclass(ctxt, a)
+	return int32(ctxt.Instoffset)
+}
+
+func immrot(v uint32) int32 {
+	for i := 0; i < 16; i++ {
+		if v&^0xff == 0 {
+			return int32(uint32(int32(i)<<8) | v | 1<<25)
+		}
+		v = v<<2 | v>>30
+	}
+
+	return 0
+}
+
+func immaddr(v int32) int32 {
+	if v >= 0 && v <= 0xfff {
+		return v&0xfff | 1<<24 | 1<<23 /* pre indexing */ /* pre indexing, up */
+	}
+	if v >= -0xfff && v < 0 {
+		return -v&0xfff | 1<<24 /* pre indexing */
+	}
+	return 0
+}
+
+func immfloat(v int32) bool {
+	return v&0xC03 == 0 /* offset will fit in floating-point load/store */
+}
+
+func immhalf(v int32) bool {
+	if v >= 0 && v <= 0xff {
+		return v|1<<24|1<<23 != 0 /* pre indexing */ /* pre indexing, up */
+	}
+	if v >= -0xff && v < 0 {
+		return -v&0xff|1<<24 != 0 /* pre indexing */
+	}
+	return false
+}
+
+func aclass(ctxt *obj.Link, a *obj.Addr) int {
+	switch a.Type {
+	case obj.TYPE_NONE:
+		return C_NONE
+
+	case obj.TYPE_REG:
+		if REG_R0 <= a.Reg && a.Reg <= REG_R15 {
+			return C_REG
+		}
+		if REG_F0 <= a.Reg && a.Reg <= REG_F15 {
+			return C_FREG
+		}
+		if a.Reg == REG_FPSR || a.Reg == REG_FPCR {
+			return C_FCR
+		}
+		if a.Reg == REG_CPSR || a.Reg == REG_SPSR {
+			return C_PSR
+		}
+		return C_GOK
+
+	case obj.TYPE_REGREG:
+		return C_REGREG
+
+	case obj.TYPE_REGREG2:
+		return C_REGREG2
+
+	case obj.TYPE_REGLIST:
+		return C_REGLIST
+
+	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 || a.Sym.Name == "" {
+				fmt.Printf("null sym external\n")
+				return C_GOK
+			}
+
+			ctxt.Instoffset = 0 // s.b. unused but just in case
+			return C_ADDR
+
+		case obj.NAME_AUTO:
+			ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset
+			t := int(immaddr(int32(ctxt.Instoffset)))
+			if t != 0 {
+				if immhalf(int32(ctxt.Instoffset)) {
+					if immfloat(int32(t)) {
+						return C_HFAUTO
+					}
+					return C_HAUTO
+				}
+
+				if immfloat(int32(t)) {
+					return C_FAUTO
+				}
+				return C_SAUTO
+			}
+
+			return C_LAUTO
+
+		case obj.NAME_PARAM:
+			ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset + 4
+			t := int(immaddr(int32(ctxt.Instoffset)))
+			if t != 0 {
+				if immhalf(int32(ctxt.Instoffset)) {
+					if immfloat(int32(t)) {
+						return C_HFAUTO
+					}
+					return C_HAUTO
+				}
+
+				if immfloat(int32(t)) {
+					return C_FAUTO
+				}
+				return C_SAUTO
+			}
+
+			return C_LAUTO
+
+		case obj.TYPE_NONE:
+			ctxt.Instoffset = a.Offset
+			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)) {
+						return C_HFOREG
+					}
+					return C_HOREG
+				}
+
+				if immfloat(int32(t)) {
+					return C_FOREG /* n.b. that it will also satisfy immrot */
+				}
+				t := int(immrot(uint32(ctxt.Instoffset)))
+				if t != 0 {
+					return C_SROREG
+				}
+				if immhalf(int32(ctxt.Instoffset)) {
+					return C_HOREG
+				}
+				return C_SOREG
+			}
+
+			t = int(immrot(uint32(ctxt.Instoffset)))
+			if t != 0 {
+				return C_ROREG
+			}
+			return C_LOREG
+		}
+
+		return C_GOK
+
+	case obj.TYPE_FCONST:
+		if chipzero5(ctxt, a.Val.(float64)) >= 0 {
+			return C_ZFCON
+		}
+		if chipfloat5(ctxt, a.Val.(float64)) >= 0 {
+			return C_SFCON
+		}
+		return C_LFCON
+
+	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 {
+				return aconsize(ctxt)
+			}
+
+			t := int(immrot(uint32(ctxt.Instoffset)))
+			if t != 0 {
+				return C_RCON
+			}
+			t = int(immrot(^uint32(ctxt.Instoffset)))
+			if t != 0 {
+				return C_NCON
+			}
+			return C_LCON
+
+		case obj.NAME_EXTERN,
+			obj.NAME_STATIC:
+			s := a.Sym
+			if s == nil {
+				break
+			}
+			ctxt.Instoffset = 0 // s.b. unused but just in case
+			return C_LCONADDR
+
+		case obj.NAME_AUTO:
+			ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset
+			return aconsize(ctxt)
+
+		case obj.NAME_PARAM:
+			ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset + 4
+			return aconsize(ctxt)
+		}
+
+		return C_GOK
+
+	case obj.TYPE_BRANCH:
+		return C_SBRA
+	}
+
+	return C_GOK
+}
+
+func aconsize(ctxt *obj.Link) int {
+	t := int(immrot(uint32(ctxt.Instoffset)))
+	if t != 0 {
+		return C_RACON
+	}
+	return C_LACON
+}
+
+func prasm(p *obj.Prog) {
+	fmt.Printf("%v\n", p)
+}
+
+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 = C_REG
+	}
+	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", 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][:]
+	for ; -cap(o) < -cap(e); o = o[1:] {
+		if int(o[0].a2) == a2 {
+			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)
+	ctxt.Diag("from %d %d to %d %d\n", p.From.Type, p.From.Name, p.To.Type, p.To.Name)
+	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_LCON:
+		if b == C_RCON || b == C_NCON {
+			return true
+		}
+
+	case C_LACON:
+		if b == C_RACON {
+			return true
+		}
+
+	case C_LFCON:
+		if b == C_ZFCON || b == C_SFCON {
+			return true
+		}
+
+	case C_HFAUTO:
+		return b == C_HAUTO || b == C_FAUTO
+
+	case C_FAUTO, C_HAUTO:
+		return b == C_HFAUTO
+
+	case C_SAUTO:
+		return cmp(C_HFAUTO, b)
+
+	case C_LAUTO:
+		return cmp(C_SAUTO, b)
+
+	case C_HFOREG:
+		return b == C_HOREG || b == C_FOREG
+
+	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:
+		return b == C_SROREG || cmp(C_HFOREG, b)
+
+	case C_LOREG:
+		return cmp(C_SROREG, b)
+
+	case C_LBRA:
+		if b == C_SBRA {
+			return true
+		}
+
+	case C_HREG:
+		return cmp(C_SP, b) || cmp(C_PC, b)
+	}
+
+	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
+	}
+	return false
+}
+
+func opset(a, b0 uint16) {
+	oprange[a&obj.AMask] = oprange[b0]
+}
+
+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++ {
+		if optab[n].flag&LPCREL != 0 {
+			if ctxt.Flag_shared != 0 {
+				optab[n].size += int8(optab[n].pcrelsiz)
+			} else {
+				optab[n].flag &^= LPCREL
+			}
+		}
+	}
+
+	sort.Sort(ocmp(optab[:n]))
+	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[r0].stop = optab[i:]
+		i--
+
+		switch r {
+		default:
+			ctxt.Diag("unknown op in build: %v", obj.Aconv(int(r)))
+			log.Fatalf("bad code")
+
+		case AADD:
+			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:
+			opset(ATEQ, r0)
+			opset(ACMN, r0)
+
+		case AMVN:
+			break
+
+		case ABEQ:
+			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:
+			opset(ASRL, r0)
+			opset(ASRA, r0)
+
+		case AMUL:
+			opset(AMULU, r0)
+
+		case ADIV:
+			opset(AMOD, r0)
+			opset(AMODU, r0)
+			opset(ADIVU, r0)
+
+		case AMOVW,
+			AMOVB,
+			AMOVBS,
+			AMOVBU,
+			AMOVH,
+			AMOVHS,
+			AMOVHU:
+			break
+
+		case ASWPW:
+			opset(ASWPBU, r0)
+
+		case AB,
+			ABL,
+			ABX,
+			ABXRET,
+			obj.ADUFFZERO,
+			obj.ADUFFCOPY,
+			ASWI,
+			AWORD,
+			AMOVM,
+			ARFE,
+			obj.ATEXT,
+			obj.AUSEFIELD,
+			ACASE,
+			ABCASE,
+			obj.ATYPE:
+			break
+
+		case AADDF:
+			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:
+			opset(ACMPD, r0)
+
+		case AMOVF:
+			opset(AMOVD, r0)
+
+		case AMOVFW:
+			opset(AMOVDW, r0)
+
+		case AMOVWF:
+			opset(AMOVWD, r0)
+
+		case AMULL:
+			opset(AMULAL, r0)
+			opset(AMULLU, r0)
+			opset(AMULALU, r0)
+
+		case AMULWT:
+			opset(AMULWB, r0)
+
+		case AMULAWT:
+			opset(AMULAWB, r0)
+
+		case AMULA,
+			ALDREX,
+			ASTREX,
+			ALDREXD,
+			ASTREXD,
+			ATST,
+			APLD,
+			obj.AUNDEF,
+			ACLZ,
+			obj.AFUNCDATA,
+			obj.APCDATA,
+			obj.ANOP,
+			ADATABUNDLE,
+			ADATABUNDLEEND:
+			break
+		}
+	}
+}
+
+func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
+	ctxt.Printp = p
+	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_)
+	}
+	switch o.type_ {
+	default:
+		ctxt.Diag("unknown asm %d", o.type_)
+		prasm(p)
+
+	case 0: /* pseudo ops */
+		if false { /*debug['G']*/
+			fmt.Printf("%x: %s: arm\n", uint32(p.Pc), p.From.Sym.Name)
+		}
+
+	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)
+		if p.To.Type == obj.TYPE_NONE {
+			rt = 0
+		}
+		if p.As == AMOVB || p.As == AMOVH || p.As == AMOVW || p.As == AMVN {
+			r = 0
+		} else if r == 0 {
+			r = rt
+		}
+		o1 |= (uint32(rf)&15)<<0 | (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
+
+	case 2: /* movbu $I,[R],R */
+		aclass(ctxt, &p.From)
+
+		o1 = oprrr(ctxt, int(p.As), int(p.Scond))
+		o1 |= uint32(immrot(uint32(ctxt.Instoffset)))
+		rt := int(p.To.Reg)
+		r := int(p.Reg)
+		if p.To.Type == obj.TYPE_NONE {
+			rt = 0
+		}
+		if p.As == AMOVW || p.As == AMVN {
+			r = 0
+		} else if r == 0 {
+			r = rt
+		}
+		o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
+
+	case 3: /* add R<<[IR],[R],R */
+		o1 = mov(ctxt, p)
+
+	case 4: /* add $I,[R],R */
+		aclass(ctxt, &p.From)
+
+		o1 = oprrr(ctxt, AADD, int(p.Scond))
+		o1 |= uint32(immrot(uint32(ctxt.Instoffset)))
+		r := int(p.From.Reg)
+		if r == 0 {
+			r = int(o.param)
+		}
+		o1 |= (uint32(r) & 15) << 16
+		o1 |= (uint32(p.To.Reg) & 15) << 12
+
+	case 5: /* bra s */
+		o1 = opbra(ctxt, int(p.As), int(p.Scond))
+
+		v := int32(-8)
+		if p.To.Sym != nil {
+			rel := obj.Addrel(ctxt.Cursym)
+			rel.Off = int32(ctxt.Pc)
+			rel.Siz = 4
+			rel.Sym = p.To.Sym
+			v += int32(p.To.Offset)
+			rel.Add = int64(o1) | (int64(v)>>2)&0xffffff
+			rel.Type = obj.R_CALLARM
+			break
+		}
+
+		if p.Pcond != nil {
+			v = int32((p.Pcond.Pc - ctxt.Pc) - 8)
+		}
+		o1 |= (uint32(v) >> 2) & 0xffffff
+
+	case 6: /* b ,O(R) -> add $O,R,PC */
+		aclass(ctxt, &p.To)
+
+		o1 = oprrr(ctxt, AADD, int(p.Scond))
+		o1 |= uint32(immrot(uint32(ctxt.Instoffset)))
+		o1 |= (uint32(p.To.Reg) & 15) << 16
+		o1 |= (REGPC & 15) << 12
+
+	case 7: /* bl (R) -> blx R */
+		aclass(ctxt, &p.To)
+
+		if ctxt.Instoffset != 0 {
+			ctxt.Diag("%v: doesn't support BL offset(REG) where offset != 0", p)
+		}
+		o1 = oprrr(ctxt, ABL, int(p.Scond))
+		o1 |= (uint32(p.To.Reg) & 15) << 0
+		rel := obj.Addrel(ctxt.Cursym)
+		rel.Off = int32(ctxt.Pc)
+		rel.Siz = 0
+		rel.Type = obj.R_CALLIND
+
+	case 8: /* sll $c,[R],R -> mov (R<<$c),R */
+		aclass(ctxt, &p.From)
+
+		o1 = oprrr(ctxt, int(p.As), int(p.Scond))
+		r := int(p.Reg)
+		if r == 0 {
+			r = int(p.To.Reg)
+		}
+		o1 |= (uint32(r) & 15) << 0
+		o1 |= uint32((ctxt.Instoffset & 31) << 7)
+		o1 |= (uint32(p.To.Reg) & 15) << 12
+
+	case 9: /* sll R,[R],R -> mov (R<<R),R */
+		o1 = oprrr(ctxt, int(p.As), int(p.Scond))
+
+		r := int(p.Reg)
+		if r == 0 {
+			r = int(p.To.Reg)
+		}
+		o1 |= (uint32(r) & 15) << 0
+		o1 |= (uint32(p.From.Reg)&15)<<8 | 1<<4
+		o1 |= (uint32(p.To.Reg) & 15) << 12
+
+	case 10: /* swi [$con] */
+		o1 = oprrr(ctxt, int(p.As), int(p.Scond))
+
+		if p.To.Type != obj.TYPE_NONE {
+			aclass(ctxt, &p.To)
+			o1 |= uint32(ctxt.Instoffset & 0xffffff)
+		}
+
+	case 11: /* word */
+		aclass(ctxt, &p.To)
+
+		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
+
+			// runtime.tlsg is special.
+			// Its "address" is the offset from the TLS thread pointer
+			// to the thread-local g and m pointers.
+			// Emit a TLS relocation instead of a standard one if its
+			// type is not explicitly set by runtime. This assumes that
+			// all references to runtime.tlsg should be accompanied with
+			// its type declaration if necessary.
+			if rel.Sym == ctxt.Tlsg && ctxt.Tlsg.Type == 0 {
+				rel.Type = obj.R_TLS
+				if ctxt.Flag_shared != 0 {
+					rel.Add += ctxt.Pc - p.Rel.Pc - 8 - int64(rel.Siz)
+				}
+			} else if ctxt.Flag_shared != 0 {
+				rel.Type = obj.R_PCREL
+				rel.Add += ctxt.Pc - p.Rel.Pc - 8
+			} else {
+				rel.Type = obj.R_ADDR
+			}
+			o1 = 0
+		}
+
+	case 12: /* movw $lcon, reg */
+		o1 = omvl(ctxt, p, &p.From, int(p.To.Reg))
+
+		if o.flag&LPCREL != 0 {
+			o2 = oprrr(ctxt, AADD, int(p.Scond)) | (uint32(p.To.Reg)&15)<<0 | (REGPC&15)<<16 | (uint32(p.To.Reg)&15)<<12
+		}
+
+	case 13: /* op $lcon, [R], R */
+		o1 = omvl(ctxt, p, &p.From, REGTMP)
+
+		if o1 == 0 {
+			break
+		}
+		o2 = oprrr(ctxt, int(p.As), int(p.Scond))
+		o2 |= REGTMP & 15
+		r := int(p.Reg)
+		if p.As == AMOVW || p.As == AMVN {
+			r = 0
+		} else if r == 0 {
+			r = int(p.To.Reg)
+		}
+		o2 |= (uint32(r) & 15) << 16
+		if p.To.Type != obj.TYPE_NONE {
+			o2 |= (uint32(p.To.Reg) & 15) << 12
+		}
+
+	case 14: /* movb/movbu/movh/movhu R,R */
+		o1 = oprrr(ctxt, ASLL, int(p.Scond))
+
+		if p.As == AMOVBU || p.As == AMOVHU {
+			o2 = oprrr(ctxt, ASRL, int(p.Scond))
+		} else {
+			o2 = oprrr(ctxt, ASRA, int(p.Scond))
+		}
+
+		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 {
+			o1 |= 24 << 7
+			o2 |= 24 << 7
+		} else {
+			o1 |= 16 << 7
+			o2 |= 16 << 7
+		}
+
+	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)
+		if r == 0 {
+			r = rt
+		}
+		if rt == r {
+			r = rf
+			rf = rt
+		}
+
+		if false {
+			if rt == r || rf == REGPC&15 || r == REGPC&15 || rt == REGPC&15 {
+				ctxt.Diag("bad registers in MUL")
+				prasm(p)
+			}
+		}
+
+		o1 |= (uint32(rf)&15)<<8 | (uint32(r)&15)<<0 | (uint32(rt)&15)<<16
+
+	case 16: /* div r,[r,]r */
+		o1 = 0xf << 28
+
+		o2 = 0
+
+	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)
+		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)
+		if r == 0 {
+			r = int(o.param)
+		}
+		o1 = osr(ctxt, int(p.As), int(p.From.Reg), int32(ctxt.Instoffset), r, int(p.Scond))
+
+	case 21: /* mov/movbu O(R),R -> lr */
+		aclass(ctxt, &p.From)
+
+		r := int(p.From.Reg)
+		if r == 0 {
+			r = int(o.param)
+		}
+		o1 = olr(ctxt, int32(ctxt.Instoffset), r, int(p.To.Reg), int(p.Scond))
+		if p.As != AMOVW {
+			o1 |= 1 << 22
+		}
+
+	case 30: /* mov/movb/movbu R,L(R) */
+		o1 = omvl(ctxt, p, &p.To, REGTMP)
+
+		if o1 == 0 {
+			break
+		}
+		r := int(p.To.Reg)
+		if r == 0 {
+			r = int(o.param)
+		}
+		o2 = osrr(ctxt, int(p.From.Reg), REGTMP&15, r, int(p.Scond))
+		if p.As != AMOVW {
+			o2 |= 1 << 22
+		}
+
+	case 31: /* mov/movbu L(R),R -> lr[b] */
+		o1 = omvl(ctxt, p, &p.From, REGTMP)
+
+		if o1 == 0 {
+			break
+		}
+		r := int(p.From.Reg)
+		if r == 0 {
+			r = int(o.param)
+		}
+		o2 = olrr(ctxt, REGTMP&15, r, int(p.To.Reg), int(p.Scond))
+		if p.As == AMOVBU || p.As == AMOVBS || p.As == AMOVB {
+			o2 |= 1 << 22
+		}
+
+	case 34: /* mov $lacon,R */
+		o1 = omvl(ctxt, p, &p.From, REGTMP)
+
+		if o1 == 0 {
+			break
+		}
+
+		o2 = oprrr(ctxt, AADD, int(p.Scond))
+		o2 |= REGTMP & 15
+		r := int(p.From.Reg)
+		if r == 0 {
+			r = int(o.param)
+		}
+		o2 |= (uint32(r) & 15) << 16
+		if p.To.Type != obj.TYPE_NONE {
+			o2 |= (uint32(p.To.Reg) & 15) << 12
+		}
+
+	case 35: /* mov PSR,R */
+		o1 = 2<<23 | 0xf<<16 | 0<<0
+
+		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
+		o1 |= (uint32(p.From.Reg) & 1) << 22
+		o1 |= (uint32(p.To.Reg) & 15) << 12
+
+	case 36: /* mov R,PSR */
+		o1 = 2<<23 | 0x29f<<12 | 0<<4
+
+		if p.Scond&C_FBIT != 0 {
+			o1 ^= 0x010 << 12
+		}
+		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
+		o1 |= (uint32(p.To.Reg) & 1) << 22
+		o1 |= (uint32(p.From.Reg) & 15) << 0
+
+	case 37: /* mov $con,PSR */
+		aclass(ctxt, &p.From)
+
+		o1 = 2<<23 | 0x29f<<12 | 0<<4
+		if p.Scond&C_FBIT != 0 {
+			o1 ^= 0x010 << 12
+		}
+		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
+		o1 |= uint32(immrot(uint32(ctxt.Instoffset)))
+		o1 |= (uint32(p.To.Reg) & 1) << 22
+		o1 |= (uint32(p.From.Reg) & 15) << 0
+
+	case 38, 39:
+		switch o.type_ {
+		case 38: /* movm $con,oreg -> stm */
+			o1 = 0x4 << 25
+
+			o1 |= uint32(p.From.Offset & 0xffff)
+			o1 |= (uint32(p.To.Reg) & 15) << 16
+			aclass(ctxt, &p.To)
+
+		case 39: /* movm oreg,$con -> ldm */
+			o1 = 0x4<<25 | 1<<20
+
+			o1 |= uint32(p.To.Offset & 0xffff)
+			o1 |= (uint32(p.From.Reg) & 15) << 16
+			aclass(ctxt, &p.From)
+		}
+
+		if ctxt.Instoffset != 0 {
+			ctxt.Diag("offset must be zero in MOVM; %v", p)
+		}
+		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
+		if p.Scond&C_PBIT != 0 {
+			o1 |= 1 << 24
+		}
+		if p.Scond&C_UBIT != 0 {
+			o1 |= 1 << 23
+		}
+		if p.Scond&C_SBIT != 0 {
+			o1 |= 1 << 22
+		}
+		if p.Scond&C_WBIT != 0 {
+			o1 |= 1 << 21
+		}
+
+	case 40: /* swp oreg,reg,reg */
+		aclass(ctxt, &p.From)
+
+		if ctxt.Instoffset != 0 {
+			ctxt.Diag("offset must be zero in SWP")
+		}
+		o1 = 0x2<<23 | 0x9<<4
+		if p.As != ASWPW {
+			o1 |= 1 << 22
+		}
+		o1 |= (uint32(p.From.Reg) & 15) << 16
+		o1 |= (uint32(p.Reg) & 15) << 0
+		o1 |= (uint32(p.To.Reg) & 15) << 12
+		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
+
+	case 41: /* rfe -> movm.s.w.u 0(r13),[r15] */
+		o1 = 0xe8fd8000
+
+	case 50: /* floating point store */
+		v := regoff(ctxt, &p.To)
+
+		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)
+
+		r := int(p.From.Reg)
+		if r == 0 {
+			r = int(o.param)
+		}
+		o1 = ofsr(ctxt, int(p.As), int(p.To.Reg), v, r, int(p.Scond), p) | 1<<20
+
+	case 52: /* floating point store, int32 offset UGLY */
+		o1 = omvl(ctxt, p, &p.To, REGTMP)
+
+		if o1 == 0 {
+			break
+		}
+		r := int(p.To.Reg)
+		if r == 0 {
+			r = int(o.param)
+		}
+		o2 = oprrr(ctxt, AADD, int(p.Scond)) | (REGTMP&15)<<12 | (REGTMP&15)<<16 | (uint32(r)&15)<<0
+		o3 = ofsr(ctxt, int(p.As), int(p.From.Reg), 0, REGTMP, int(p.Scond), p)
+
+	case 53: /* floating point load, int32 offset UGLY */
+		o1 = omvl(ctxt, p, &p.From, REGTMP)
+
+		if o1 == 0 {
+			break
+		}
+		r := int(p.From.Reg)
+		if r == 0 {
+			r = int(o.param)
+		}
+		o2 = oprrr(ctxt, AADD, int(p.Scond)) | (REGTMP&15)<<12 | (REGTMP&15)<<16 | (uint32(r)&15)<<0
+		o3 = ofsr(ctxt, int(p.As), int(p.To.Reg), 0, (REGTMP&15), int(p.Scond), p) | 1<<20
+
+	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)
+		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 {
+				r = 0
+			}
+		}
+
+		o1 |= (uint32(rf)&15)<<0 | (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
+
+	case 56: /* move to FP[CS]R */
+		o1 = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0xe<<24 | 1<<8 | 1<<4
+
+		o1 |= ((uint32(p.To.Reg)&1)+1)<<21 | (uint32(p.From.Reg)&15)<<12
+
+	case 57: /* move from FP[CS]R */
+		o1 = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0xe<<24 | 1<<8 | 1<<4
+
+		o1 |= ((uint32(p.From.Reg)&1)+1)<<21 | (uint32(p.To.Reg)&15)<<12 | 1<<20
+
+	case 58: /* movbu R,R */
+		o1 = oprrr(ctxt, AAND, int(p.Scond))
+
+		o1 |= uint32(immrot(0xff))
+		rt := int(p.To.Reg)
+		r := int(p.From.Reg)
+		if p.To.Type == obj.TYPE_NONE {
+			rt = 0
+		}
+		if r == 0 {
+			r = rt
+		}
+		o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
+
+	case 59: /* movw/bu R<<I(R),R -> ldr indexed */
+		if p.From.Reg == 0 {
+			if p.As != AMOVW {
+				ctxt.Diag("byte MOV from shifter operand")
+			}
+			o1 = mov(ctxt, p)
+			break
+		}
+
+		if p.From.Offset&(1<<4) != 0 {
+			ctxt.Diag("bad shift in LDR")
+		}
+		o1 = olrr(ctxt, int(p.From.Offset), int(p.From.Reg), int(p.To.Reg), int(p.Scond))
+		if p.As == AMOVBU {
+			o1 |= 1 << 22
+		}
+
+	case 60: /* movb R(R),R -> ldrsb indexed */
+		if p.From.Reg == 0 {
+			ctxt.Diag("byte MOV from shifter operand")
+			o1 = mov(ctxt, p)
+			break
+		}
+
+		if p.From.Offset&(^0xf) != 0 {
+			ctxt.Diag("bad shift in LDRSB")
+		}
+		o1 = olhrr(ctxt, int(p.From.Offset), int(p.From.Reg), int(p.To.Reg), int(p.Scond))
+		o1 ^= 1<<5 | 1<<6
+
+	case 61: /* movw/b/bu R,R<<[IR](R) -> str indexed */
+		if p.To.Reg == 0 {
+			ctxt.Diag("MOV to shifter operand")
+		}
+		o1 = osrr(ctxt, int(p.From.Reg), int(p.To.Offset), int(p.To.Reg), int(p.Scond))
+		if p.As == AMOVB || p.As == AMOVBS || p.As == AMOVBU {
+			o1 |= 1 << 22
+		}
+
+	case 62: /* case R -> movw	R<<2(PC),PC */
+		if o.flag&LPCREL != 0 {
+			o1 = oprrr(ctxt, AADD, int(p.Scond)) | uint32(immrot(1)) | (uint32(p.From.Reg)&15)<<16 | (REGTMP&15)<<12
+			o2 = olrr(ctxt, REGTMP&15, REGPC, REGTMP, int(p.Scond))
+			o2 |= 2 << 7
+			o3 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGPC&15)<<12
+		} else {
+			o1 = olrr(ctxt, int(p.From.Reg)&15, REGPC, REGPC, int(p.Scond))
+			o1 |= 2 << 7
+		}
+
+	case 63: /* bcase */
+		if p.Pcond != nil {
+			rel := obj.Addrel(ctxt.Cursym)
+			rel.Off = int32(ctxt.Pc)
+			rel.Siz = 4
+			if p.To.Sym != nil && p.To.Sym.Type != 0 {
+				rel.Sym = p.To.Sym
+				rel.Add = p.To.Offset
+			} else {
+				rel.Sym = ctxt.Cursym
+				rel.Add = p.Pcond.Pc
+			}
+
+			if o.flag&LPCREL != 0 {
+				rel.Type = obj.R_PCREL
+				rel.Add += ctxt.Pc - p.Rel.Pc - 16 + int64(rel.Siz)
+			} else {
+				rel.Type = obj.R_ADDR
+			}
+			o1 = 0
+		}
+
+		/* reloc ops */
+	case 64: /* mov/movb/movbu R,addr */
+		o1 = omvl(ctxt, p, &p.To, REGTMP)
+
+		if o1 == 0 {
+			break
+		}
+		o2 = osr(ctxt, int(p.As), int(p.From.Reg), 0, REGTMP, int(p.Scond))
+		if o.flag&LPCREL != 0 {
+			o3 = o2
+			o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
+		}
+
+	case 65: /* mov/movbu addr,R */
+		o1 = omvl(ctxt, p, &p.From, REGTMP)
+
+		if o1 == 0 {
+			break
+		}
+		o2 = olr(ctxt, 0, REGTMP, int(p.To.Reg), int(p.Scond))
+		if p.As == AMOVBU || p.As == AMOVBS || p.As == AMOVB {
+			o2 |= 1 << 22
+		}
+		if o.flag&LPCREL != 0 {
+			o3 = o2
+			o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
+		}
+
+	case 68: /* floating point store -> ADDR */
+		o1 = omvl(ctxt, p, &p.To, REGTMP)
+
+		if o1 == 0 {
+			break
+		}
+		o2 = ofsr(ctxt, int(p.As), int(p.From.Reg), 0, REGTMP, int(p.Scond), p)
+		if o.flag&LPCREL != 0 {
+			o3 = o2
+			o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
+		}
+
+	case 69: /* floating point load <- ADDR */
+		o1 = omvl(ctxt, p, &p.From, REGTMP)
+
+		if o1 == 0 {
+			break
+		}
+		o2 = ofsr(ctxt, int(p.As), int(p.To.Reg), 0, (REGTMP&15), int(p.Scond), p) | 1<<20
+		if o.flag&LPCREL != 0 {
+			o3 = o2
+			o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
+		}
+
+		/* ArmV4 ops: */
+	case 70: /* movh/movhu R,O(R) -> strh */
+		aclass(ctxt, &p.To)
+
+		r := int(p.To.Reg)
+		if r == 0 {
+			r = int(o.param)
+		}
+		o1 = oshr(ctxt, int(p.From.Reg), int32(ctxt.Instoffset), r, int(p.Scond))
+
+	case 71: /* movb/movh/movhu O(R),R -> ldrsb/ldrsh/ldrh */
+		aclass(ctxt, &p.From)
+
+		r := int(p.From.Reg)
+		if r == 0 {
+			r = int(o.param)
+		}
+		o1 = olhr(ctxt, int32(ctxt.Instoffset), r, int(p.To.Reg), int(p.Scond))
+		if p.As == AMOVB || p.As == AMOVBS {
+			o1 ^= 1<<5 | 1<<6
+		} else if p.As == AMOVH || p.As == AMOVHS {
+			o1 ^= (1 << 6)
+		}
+
+	case 72: /* movh/movhu R,L(R) -> strh */
+		o1 = omvl(ctxt, p, &p.To, REGTMP)
+
+		if o1 == 0 {
+			break
+		}
+		r := int(p.To.Reg)
+		if r == 0 {
+			r = int(o.param)
+		}
+		o2 = oshrr(ctxt, int(p.From.Reg), REGTMP&15, r, int(p.Scond))
+
+	case 73: /* movb/movh/movhu L(R),R -> ldrsb/ldrsh/ldrh */
+		o1 = omvl(ctxt, p, &p.From, REGTMP)
+
+		if o1 == 0 {
+			break
+		}
+		r := int(p.From.Reg)
+		if r == 0 {
+			r = int(o.param)
+		}
+		o2 = olhrr(ctxt, REGTMP&15, r, int(p.To.Reg), int(p.Scond))
+		if p.As == AMOVB || p.As == AMOVBS {
+			o2 ^= 1<<5 | 1<<6
+		} else if p.As == AMOVH || p.As == AMOVHS {
+			o2 ^= (1 << 6)
+		}
+
+	case 74: /* bx $I */
+		ctxt.Diag("ABX $I")
+
+	case 75: /* bx O(R) */
+		aclass(ctxt, &p.To)
+
+		if ctxt.Instoffset != 0 {
+			ctxt.Diag("non-zero offset in ABX")
+		}
+
+		/*
+			o1 = 	oprrr(ctxt, AADD, p->scond) | immrot(0) | ((REGPC&15)<<16) | ((REGLINK&15)<<12);	// mov PC, LR
+			o2 = (((p->scond&C_SCOND) ^ C_SCOND_XOR)<<28) | (0x12fff<<8) | (1<<4) | ((p->to.reg&15) << 0);		// BX R
+		*/
+		// p->to.reg may be REGLINK
+		o1 = oprrr(ctxt, AADD, int(p.Scond))
+
+		o1 |= uint32(immrot(uint32(ctxt.Instoffset)))
+		o1 |= (uint32(p.To.Reg) & 15) << 16
+		o1 |= (REGTMP & 15) << 12
+		o2 = oprrr(ctxt, AADD, int(p.Scond)) | uint32(immrot(0)) | (REGPC&15)<<16 | (REGLINK&15)<<12 // mov PC, LR
+		o3 = ((uint32(p.Scond)&C_SCOND)^C_SCOND_XOR)<<28 | 0x12fff<<8 | 1<<4 | REGTMP&15             // BX Rtmp
+
+	case 76: /* bx O(R) when returning from fn*/
+		ctxt.Diag("ABXRET")
+
+	case 77: /* ldrex oreg,reg */
+		aclass(ctxt, &p.From)
+
+		if ctxt.Instoffset != 0 {
+			ctxt.Diag("offset must be zero in LDREX")
+		}
+		o1 = 0x19<<20 | 0xf9f
+		o1 |= (uint32(p.From.Reg) & 15) << 16
+		o1 |= (uint32(p.To.Reg) & 15) << 12
+		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
+
+	case 78: /* strex reg,oreg,reg */
+		aclass(ctxt, &p.From)
+
+		if ctxt.Instoffset != 0 {
+			ctxt.Diag("offset must be zero in STREX")
+		}
+		o1 = 0x18<<20 | 0xf90
+		o1 |= (uint32(p.From.Reg) & 15) << 16
+		o1 |= (uint32(p.Reg) & 15) << 0
+		o1 |= (uint32(p.To.Reg) & 15) << 12
+		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
+
+	case 80: /* fmov zfcon,freg */
+		if p.As == AMOVD {
+			o1 = 0xeeb00b00 // VMOV imm 64
+			o2 = oprrr(ctxt, ASUBD, int(p.Scond))
+		} else {
+			o1 = 0x0eb00a00 // VMOV imm 32
+			o2 = oprrr(ctxt, ASUBF, int(p.Scond))
+		}
+
+		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
+
+		o1 |= (uint32(r) & 15) << 12
+		o1 |= (uint32(v) & 0xf) << 0
+		o1 |= (uint32(v) & 0xf0) << 12
+
+		// subf r,r,r
+		o2 |= (uint32(r)&15)<<0 | (uint32(r)&15)<<16 | (uint32(r)&15)<<12
+
+	case 81: /* fmov sfcon,freg */
+		o1 = 0x0eb00a00 // VMOV imm 32
+		if p.As == AMOVD {
+			o1 = 0xeeb00b00 // VMOV imm 64
+		}
+		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
+		o1 |= (uint32(p.To.Reg) & 15) << 12
+		v := int32(chipfloat5(ctxt, p.From.Val.(float64)))
+		o1 |= (uint32(v) & 0xf) << 0
+		o1 |= (uint32(v) & 0xf0) << 12
+
+	case 82: /* fcmp freg,freg, */
+		o1 = oprrr(ctxt, int(p.As), int(p.Scond))
+
+		o1 |= (uint32(p.Reg)&15)<<12 | (uint32(p.From.Reg)&15)<<0
+		o2 = 0x0ef1fa10 // VMRS R15
+		o2 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
+
+	case 83: /* fcmp freg,, */
+		o1 = oprrr(ctxt, int(p.As), int(p.Scond))
+
+		o1 |= (uint32(p.From.Reg)&15)<<12 | 1<<16
+		o2 = 0x0ef1fa10 // VMRS R15
+		o2 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
+
+	case 84: /* movfw freg,freg - truncate float-to-fix */
+		o1 = oprrr(ctxt, int(p.As), int(p.Scond))
+
+		o1 |= (uint32(p.From.Reg) & 15) << 0
+		o1 |= (uint32(p.To.Reg) & 15) << 12
+
+	case 85: /* movwf freg,freg - fix-to-float */
+		o1 = oprrr(ctxt, int(p.As), int(p.Scond))
+
+		o1 |= (uint32(p.From.Reg) & 15) << 0
+		o1 |= (uint32(p.To.Reg) & 15) << 12
+
+		// macro for movfw freg,FTMP; movw FTMP,reg
+	case 86: /* movfw freg,reg - truncate float-to-fix */
+		o1 = oprrr(ctxt, int(p.As), int(p.Scond))
+
+		o1 |= (uint32(p.From.Reg) & 15) << 0
+		o1 |= (FREGTMP & 15) << 12
+		o2 = oprrr(ctxt, AMOVFW+ALAST, int(p.Scond))
+		o2 |= (FREGTMP & 15) << 16
+		o2 |= (uint32(p.To.Reg) & 15) << 12
+
+		// macro for movw reg,FTMP; movwf FTMP,freg
+	case 87: /* movwf reg,freg - fix-to-float */
+		o1 = oprrr(ctxt, AMOVWF+ALAST, int(p.Scond))
+
+		o1 |= (uint32(p.From.Reg) & 15) << 12
+		o1 |= (FREGTMP & 15) << 16
+		o2 = oprrr(ctxt, int(p.As), int(p.Scond))
+		o2 |= (FREGTMP & 15) << 0
+		o2 |= (uint32(p.To.Reg) & 15) << 12
+
+	case 88: /* movw reg,freg  */
+		o1 = oprrr(ctxt, AMOVWF+ALAST, int(p.Scond))
+
+		o1 |= (uint32(p.From.Reg) & 15) << 12
+		o1 |= (uint32(p.To.Reg) & 15) << 16
+
+	case 89: /* movw freg,reg  */
+		o1 = oprrr(ctxt, AMOVFW+ALAST, int(p.Scond))
+
+		o1 |= (uint32(p.From.Reg) & 15) << 16
+		o1 |= (uint32(p.To.Reg) & 15) << 12
+
+	case 90: /* tst reg  */
+		o1 = oprrr(ctxt, ACMP+ALAST, int(p.Scond))
+
+		o1 |= (uint32(p.From.Reg) & 15) << 16
+
+	case 91: /* ldrexd oreg,reg */
+		aclass(ctxt, &p.From)
+
+		if ctxt.Instoffset != 0 {
+			ctxt.Diag("offset must be zero in LDREX")
+		}
+		o1 = 0x1b<<20 | 0xf9f
+		o1 |= (uint32(p.From.Reg) & 15) << 16
+		o1 |= (uint32(p.To.Reg) & 15) << 12
+		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
+
+	case 92: /* strexd reg,oreg,reg */
+		aclass(ctxt, &p.From)
+
+		if ctxt.Instoffset != 0 {
+			ctxt.Diag("offset must be zero in STREX")
+		}
+		o1 = 0x1a<<20 | 0xf90
+		o1 |= (uint32(p.From.Reg) & 15) << 16
+		o1 |= (uint32(p.Reg) & 15) << 0
+		o1 |= (uint32(p.To.Reg) & 15) << 12
+		o1 |= ((uint32(p.Scond) & C_SCOND) ^ C_SCOND_XOR) << 28
+
+	case 93: /* movb/movh/movhu addr,R -> ldrsb/ldrsh/ldrh */
+		o1 = omvl(ctxt, p, &p.From, REGTMP)
+
+		if o1 == 0 {
+			break
+		}
+		o2 = olhr(ctxt, 0, REGTMP, int(p.To.Reg), int(p.Scond))
+		if p.As == AMOVB || p.As == AMOVBS {
+			o2 ^= 1<<5 | 1<<6
+		} else if p.As == AMOVH || p.As == AMOVHS {
+			o2 ^= (1 << 6)
+		}
+		if o.flag&LPCREL != 0 {
+			o3 = o2
+			o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
+		}
+
+	case 94: /* movh/movhu R,addr -> strh */
+		o1 = omvl(ctxt, p, &p.To, REGTMP)
+
+		if o1 == 0 {
+			break
+		}
+		o2 = oshr(ctxt, int(p.From.Reg), 0, REGTMP, int(p.Scond))
+		if o.flag&LPCREL != 0 {
+			o3 = o2
+			o2 = oprrr(ctxt, AADD, int(p.Scond)) | REGTMP&15 | (REGPC&15)<<16 | (REGTMP&15)<<12
+		}
+
+	case 95: /* PLD off(reg) */
+		o1 = 0xf5d0f000
+
+		o1 |= (uint32(p.From.Reg) & 15) << 16
+		if p.From.Offset < 0 {
+			o1 &^= (1 << 23)
+			o1 |= uint32((-p.From.Offset) & 0xfff)
+		} else {
+			o1 |= uint32(p.From.Offset & 0xfff)
+		}
+
+		// 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
+	// 0xf7fabcfd which is guaranteed to raise undefined instruction
+	// exception.
+	case 96: /* UNDEF */
+		o1 = 0xf7fabcfd
+
+	case 97: /* CLZ Rm, Rd */
+		o1 = oprrr(ctxt, int(p.As), int(p.Scond))
+
+		o1 |= (uint32(p.To.Reg) & 15) << 12
+		o1 |= (uint32(p.From.Reg) & 15) << 0
+
+	case 98: /* MULW{T,B} Rs, Rm, Rd */
+		o1 = oprrr(ctxt, int(p.As), int(p.Scond))
+
+		o1 |= (uint32(p.To.Reg) & 15) << 16
+		o1 |= (uint32(p.From.Reg) & 15) << 8
+		o1 |= (uint32(p.Reg) & 15) << 0
+
+	case 99: /* MULAW{T,B} Rs, Rm, Rn, Rd */
+		o1 = oprrr(ctxt, int(p.As), int(p.Scond))
+
+		o1 |= (uint32(p.To.Reg) & 15) << 12
+		o1 |= (uint32(p.From.Reg) & 15) << 8
+		o1 |= (uint32(p.Reg) & 15) << 0
+		o1 |= uint32((p.To.Offset & 15) << 16)
+
+		// DATABUNDLE: BKPT $0x5be0, signify the start of NaCl data bundle;
+	// DATABUNDLEEND: zero width alignment marker
+	case 100:
+		if p.As == ADATABUNDLE {
+			o1 = 0xe125be70
+		}
+	}
+
+	out[0] = o1
+	out[1] = o2
+	out[2] = o3
+	out[3] = o4
+	out[4] = o5
+	out[5] = o6
+	return
+}
+
+func mov(ctxt *obj.Link, p *obj.Prog) uint32 {
+	aclass(ctxt, &p.From)
+	o1 := oprrr(ctxt, int(p.As), int(p.Scond))
+	o1 |= uint32(p.From.Offset)
+	rt := int(p.To.Reg)
+	if p.To.Type == obj.TYPE_NONE {
+		rt = 0
+	}
+	r := int(p.Reg)
+	if p.As == AMOVW || p.As == AMVN {
+		r = 0
+	} else if r == 0 {
+		r = rt
+	}
+	o1 |= (uint32(r)&15)<<16 | (uint32(rt)&15)<<12
+	return o1
+}
+
+func oprrr(ctxt *obj.Link, a int, sc int) uint32 {
+	o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
+	if sc&C_SBIT != 0 {
+		o |= 1 << 20
+	}
+	if sc&(C_PBIT|C_WBIT) != 0 {
+		ctxt.Diag(".nil/.W on dp instruction")
+	}
+	switch a {
+	case AMULU, AMUL:
+		return o | 0x0<<21 | 0x9<<4
+	case AMULA:
+		return o | 0x1<<21 | 0x9<<4
+	case AMULLU:
+		return o | 0x4<<21 | 0x9<<4
+	case AMULL:
+		return o | 0x6<<21 | 0x9<<4
+	case AMULALU:
+		return o | 0x5<<21 | 0x9<<4
+	case AMULAL:
+		return o | 0x7<<21 | 0x9<<4
+	case AAND:
+		return o | 0x0<<21
+	case AEOR:
+		return o | 0x1<<21
+	case ASUB:
+		return o | 0x2<<21
+	case ARSB:
+		return o | 0x3<<21
+	case AADD:
+		return o | 0x4<<21
+	case AADC:
+		return o | 0x5<<21
+	case ASBC:
+		return o | 0x6<<21
+	case ARSC:
+		return o | 0x7<<21
+	case ATST:
+		return o | 0x8<<21 | 1<<20
+	case ATEQ:
+		return o | 0x9<<21 | 1<<20
+	case ACMP:
+		return o | 0xa<<21 | 1<<20
+	case ACMN:
+		return o | 0xb<<21 | 1<<20
+	case AORR:
+		return o | 0xc<<21
+
+	case AMOVB, AMOVH, AMOVW:
+		return o | 0xd<<21
+	case ABIC:
+		return o | 0xe<<21
+	case AMVN:
+		return o | 0xf<<21
+	case ASLL:
+		return o | 0xd<<21 | 0<<5
+	case ASRL:
+		return o | 0xd<<21 | 1<<5
+	case ASRA:
+		return o | 0xd<<21 | 2<<5
+	case ASWI:
+		return o | 0xf<<24
+
+	case AADDD:
+		return o | 0xe<<24 | 0x3<<20 | 0xb<<8 | 0<<4
+	case AADDF:
+		return o | 0xe<<24 | 0x3<<20 | 0xa<<8 | 0<<4
+	case ASUBD:
+		return o | 0xe<<24 | 0x3<<20 | 0xb<<8 | 4<<4
+	case ASUBF:
+		return o | 0xe<<24 | 0x3<<20 | 0xa<<8 | 4<<4
+	case AMULD:
+		return o | 0xe<<24 | 0x2<<20 | 0xb<<8 | 0<<4
+	case AMULF:
+		return o | 0xe<<24 | 0x2<<20 | 0xa<<8 | 0<<4
+	case ADIVD:
+		return o | 0xe<<24 | 0x8<<20 | 0xb<<8 | 0<<4
+	case ADIVF:
+		return o | 0xe<<24 | 0x8<<20 | 0xa<<8 | 0<<4
+	case ASQRTD:
+		return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xb<<8 | 0xc<<4
+	case ASQRTF:
+		return o | 0xe<<24 | 0xb<<20 | 1<<16 | 0xa<<8 | 0xc<<4
+	case AABSD:
+		return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xb<<8 | 0xc<<4
+	case AABSF:
+		return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xa<<8 | 0xc<<4
+	case ACMPD:
+		return o | 0xe<<24 | 0xb<<20 | 4<<16 | 0xb<<8 | 0xc<<4
+	case ACMPF:
+		return o | 0xe<<24 | 0xb<<20 | 4<<16 | 0xa<<8 | 0xc<<4
+
+	case AMOVF:
+		return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xa<<8 | 4<<4
+	case AMOVD:
+		return o | 0xe<<24 | 0xb<<20 | 0<<16 | 0xb<<8 | 4<<4
+
+	case AMOVDF:
+		return o | 0xe<<24 | 0xb<<20 | 7<<16 | 0xa<<8 | 0xc<<4 | 1<<8 // dtof
+	case AMOVFD:
+		return o | 0xe<<24 | 0xb<<20 | 7<<16 | 0xa<<8 | 0xc<<4 | 0<<8 // dtof
+
+	case AMOVWF:
+		if sc&C_UBIT == 0 {
+			o |= 1 << 7 /* signed */
+		}
+		return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 0<<18 | 0<<8 // toint, double
+
+	case AMOVWD:
+		if sc&C_UBIT == 0 {
+			o |= 1 << 7 /* signed */
+		}
+		return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 0<<18 | 1<<8 // toint, double
+
+	case AMOVFW:
+		if sc&C_UBIT == 0 {
+			o |= 1 << 16 /* signed */
+		}
+		return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 1<<18 | 0<<8 | 1<<7 // toint, double, trunc
+
+	case AMOVDW:
+		if sc&C_UBIT == 0 {
+			o |= 1 << 16 /* signed */
+		}
+		return o | 0xe<<24 | 0xb<<20 | 8<<16 | 0xa<<8 | 4<<4 | 1<<18 | 1<<8 | 1<<7 // toint, double, trunc
+
+	case AMOVWF + ALAST: // copy WtoF
+		return o | 0xe<<24 | 0x0<<20 | 0xb<<8 | 1<<4
+
+	case AMOVFW + ALAST: // copy FtoW
+		return o | 0xe<<24 | 0x1<<20 | 0xb<<8 | 1<<4
+
+	case ACMP + ALAST: // cmp imm
+		return o | 0x3<<24 | 0x5<<20
+
+		// CLZ doesn't support .nil
+	case ACLZ:
+		return o&(0xf<<28) | 0x16f<<16 | 0xf1<<4
+
+	case AMULWT:
+		return o&(0xf<<28) | 0x12<<20 | 0xe<<4
+
+	case AMULWB:
+		return o&(0xf<<28) | 0x12<<20 | 0xa<<4
+
+	case AMULAWT:
+		return o&(0xf<<28) | 0x12<<20 | 0xc<<4
+
+	case AMULAWB:
+		return o&(0xf<<28) | 0x12<<20 | 0x8<<4
+
+	case ABL: // BLX REG
+		return o&(0xf<<28) | 0x12fff3<<4
+	}
+
+	ctxt.Diag("bad rrr %d", a)
+	prasm(ctxt.Curp)
+	return 0
+}
+
+func opbra(ctxt *obj.Link, a int, sc int) uint32 {
+	if sc&(C_SBIT|C_PBIT|C_WBIT) != 0 {
+		ctxt.Diag(".nil/.nil/.W on bra instruction")
+	}
+	sc &= C_SCOND
+	sc ^= C_SCOND_XOR
+	if a == ABL || a == obj.ADUFFZERO || a == obj.ADUFFCOPY {
+		return uint32(sc)<<28 | 0x5<<25 | 0x1<<24
+	}
+	if sc != 0xe {
+		ctxt.Diag(".COND on bcond instruction")
+	}
+	switch a {
+	case ABEQ:
+		return 0x0<<28 | 0x5<<25
+	case ABNE:
+		return 0x1<<28 | 0x5<<25
+	case ABCS:
+		return 0x2<<28 | 0x5<<25
+	case ABHS:
+		return 0x2<<28 | 0x5<<25
+	case ABCC:
+		return 0x3<<28 | 0x5<<25
+	case ABLO:
+		return 0x3<<28 | 0x5<<25
+	case ABMI:
+		return 0x4<<28 | 0x5<<25
+	case ABPL:
+		return 0x5<<28 | 0x5<<25
+	case ABVS:
+		return 0x6<<28 | 0x5<<25
+	case ABVC:
+		return 0x7<<28 | 0x5<<25
+	case ABHI:
+		return 0x8<<28 | 0x5<<25
+	case ABLS:
+		return 0x9<<28 | 0x5<<25
+	case ABGE:
+		return 0xa<<28 | 0x5<<25
+	case ABLT:
+		return 0xb<<28 | 0x5<<25
+	case ABGT:
+		return 0xc<<28 | 0x5<<25
+	case ABLE:
+		return 0xd<<28 | 0x5<<25
+	case AB:
+		return 0xe<<28 | 0x5<<25
+	}
+
+	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 {
+	if sc&C_SBIT != 0 {
+		ctxt.Diag(".nil on LDR/STR instruction")
+	}
+	o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
+	if sc&C_PBIT == 0 {
+		o |= 1 << 24
+	}
+	if sc&C_UBIT == 0 {
+		o |= 1 << 23
+	}
+	if sc&C_WBIT != 0 {
+		o |= 1 << 21
+	}
+	o |= 1<<26 | 1<<20
+	if v < 0 {
+		if sc&C_UBIT != 0 {
+			ctxt.Diag(".U on neg offset")
+		}
+		v = -v
+		o ^= 1 << 23
+	}
+
+	if v >= 1<<12 || v < 0 {
+		ctxt.Diag("literal span too large: %d (R%d)\n%v", v, b, ctxt.Printp)
+	}
+	o |= uint32(v)
+	o |= (uint32(b) & 15) << 16
+	o |= (uint32(r) & 15) << 12
+	return o
+}
+
+func olhr(ctxt *obj.Link, v int32, b int, r int, sc int) uint32 {
+	if sc&C_SBIT != 0 {
+		ctxt.Diag(".nil on LDRH/STRH instruction")
+	}
+	o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
+	if sc&C_PBIT == 0 {
+		o |= 1 << 24
+	}
+	if sc&C_WBIT != 0 {
+		o |= 1 << 21
+	}
+	o |= 1<<23 | 1<<20 | 0xb<<4
+	if v < 0 {
+		v = -v
+		o ^= 1 << 23
+	}
+
+	if v >= 1<<8 || v < 0 {
+		ctxt.Diag("literal span too large: %d (R%d)\n%v", v, b, ctxt.Printp)
+	}
+	o |= uint32(v)&0xf | (uint32(v)>>4)<<8 | 1<<22
+	o |= (uint32(b) & 15) << 16
+	o |= (uint32(r) & 15) << 12
+	return o
+}
+
+func osr(ctxt *obj.Link, a int, r int, v int32, b int, sc int) uint32 {
+	o := olr(ctxt, v, b, r, sc) ^ (1 << 20)
+	if a != AMOVW {
+		o |= 1 << 22
+	}
+	return o
+}
+
+func oshr(ctxt *obj.Link, r int, v int32, b int, sc int) uint32 {
+	o := olhr(ctxt, v, b, r, sc) ^ (1 << 20)
+	return o
+}
+
+func osrr(ctxt *obj.Link, r int, i int, b int, sc int) uint32 {
+	return olr(ctxt, int32(i), b, r, sc) ^ (1<<25 | 1<<20)
+}
+
+func oshrr(ctxt *obj.Link, r int, i int, b int, sc int) uint32 {
+	return olhr(ctxt, int32(i), b, r, sc) ^ (1<<22 | 1<<20)
+}
+
+func olrr(ctxt *obj.Link, i int, b int, r int, sc int) uint32 {
+	return olr(ctxt, int32(i), b, r, sc) ^ (1 << 25)
+}
+
+func olhrr(ctxt *obj.Link, i int, b int, r int, sc int) uint32 {
+	return olhr(ctxt, int32(i), b, r, sc) ^ (1 << 22)
+}
+
+func ofsr(ctxt *obj.Link, a int, r int, v int32, b int, sc int, p *obj.Prog) uint32 {
+	if sc&C_SBIT != 0 {
+		ctxt.Diag(".nil on FLDR/FSTR instruction")
+	}
+	o := ((uint32(sc) & C_SCOND) ^ C_SCOND_XOR) << 28
+	if sc&C_PBIT == 0 {
+		o |= 1 << 24
+	}
+	if sc&C_WBIT != 0 {
+		o |= 1 << 21
+	}
+	o |= 6<<25 | 1<<24 | 1<<23 | 10<<8
+	if v < 0 {
+		v = -v
+		o ^= 1 << 23
+	}
+
+	if v&3 != 0 {
+		ctxt.Diag("odd offset for floating point op: %d\n%v", v, p)
+	} else if v >= 1<<10 || v < 0 {
+		ctxt.Diag("literal span too large: %d\n%v", v, p)
+	}
+	o |= (uint32(v) >> 2) & 0xFF
+	o |= (uint32(b) & 15) << 16
+	o |= (uint32(r) & 15) << 12
+
+	switch a {
+	default:
+		ctxt.Diag("bad fst %v", obj.Aconv(a))
+		fallthrough
+
+	case AMOVD:
+		o |= 1 << 8
+		fallthrough
+
+	case AMOVF:
+		break
+	}
+
+	return o
+}
+
+func omvl(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, dr int) uint32 {
+	var o1 uint32
+	if p.Pcond == nil {
+		aclass(ctxt, a)
+		v := immrot(^uint32(ctxt.Instoffset))
+		if v == 0 {
+			ctxt.Diag("missing literal")
+			prasm(p)
+			return 0
+		}
+
+		o1 = oprrr(ctxt, AMVN, int(p.Scond)&C_SCOND)
+		o1 |= uint32(v)
+		o1 |= (uint32(dr) & 15) << 12
+	} else {
+		v := int32(p.Pcond.Pc - p.Pc - 8)
+		o1 = olr(ctxt, v, REGPC, dr, int(p.Scond)&C_SCOND)
+	}
+
+	return o1
+}
+
+func chipzero5(ctxt *obj.Link, e float64) int {
+	// We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions.
+	if ctxt.Goarm < 7 || e != 0 {
+		return -1
+	}
+	return 0
+}
+
+func chipfloat5(ctxt *obj.Link, e float64) int {
+	// We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions.
+	if ctxt.Goarm < 7 {
+		return -1
+	}
+
+	ei := math.Float64bits(e)
+	l := uint32(ei)
+	h := uint32(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
+}
diff --git a/src/cmd/internal/obj/arm/list5.go b/src/cmd/internal/obj/arm/list5.go
new file mode 100644
index 0000000..bb2ac20
--- /dev/null
+++ b/src/cmd/internal/obj/arm/list5.go
@@ -0,0 +1,83 @@
+// Inferno utils/5c/list.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5c/list.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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 arm
+
+import (
+	"cmd/internal/obj"
+	"fmt"
+)
+
+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)
+	}
+	if REG_F0 <= r && r <= REG_F15 {
+		return fmt.Sprintf("F%d", r-REG_F0)
+	}
+
+	switch r {
+	case REG_FPSR:
+		return "FPSR"
+
+	case REG_FPCR:
+		return "FPCR"
+
+	case REG_CPSR:
+		return "CPSR"
+
+	case REG_SPSR:
+		return "SPSR"
+	}
+
+	return fmt.Sprintf("Rgok(%d)", r-obj.RBaseARM)
+}
+
+func DRconv(a int) string {
+	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
new file mode 100644
index 0000000..3ecf6bc
--- /dev/null
+++ b/src/cmd/internal/obj/arm/obj5.go
@@ -0,0 +1,1020 @@
+// Derived from Inferno utils/5c/swt.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5c/swt.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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 arm
+
+import (
+	"cmd/internal/obj"
+	"encoding/binary"
+	"fmt"
+	"log"
+	"math"
+)
+
+var progedit_tlsfallback *obj.LSym
+
+func progedit(ctxt *obj.Link, p *obj.Prog) {
+	p.From.Class = 0
+	p.To.Class = 0
+
+	// Rewrite B/BL to symbol as TYPE_BRANCH.
+	switch p.As {
+	case AB,
+		ABL,
+		obj.ADUFFZERO,
+		obj.ADUFFCOPY:
+		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
+		}
+	}
+
+	// Replace TLS register fetches on older ARM procesors.
+	switch p.As {
+	// Treat MRC 15, 0, <reg>, C13, C0, 3 specially.
+	case AMRC:
+		if p.To.Offset&0xffff0fff == 0xee1d0f70 {
+			// Because the instruction might be rewriten to a BL which returns in R0
+			// the register must be zero.
+			if p.To.Offset&0xf000 != 0 {
+				ctxt.Diag("%v: TLS MRC instruction must write to R0 as it might get translated into a BL instruction", p.Line())
+			}
+
+			if ctxt.Goarm < 7 {
+				// Replace it with BL runtime.read_tls_fallback(SB) for ARM CPUs that lack the tls extension.
+				if progedit_tlsfallback == nil {
+					progedit_tlsfallback = obj.Linklookup(ctxt, "runtime.read_tls_fallback", 0)
+				}
+
+				// MOVW	LR, R11
+				p.As = AMOVW
+
+				p.From.Type = obj.TYPE_REG
+				p.From.Reg = REGLINK
+				p.To.Type = obj.TYPE_REG
+				p.To.Reg = REGTMP
+
+				// BL	runtime.read_tls_fallback(SB)
+				p = obj.Appendp(ctxt, p)
+
+				p.As = ABL
+				p.To.Type = obj.TYPE_BRANCH
+				p.To.Sym = progedit_tlsfallback
+				p.To.Offset = 0
+
+				// MOVW	R11, LR
+				p = obj.Appendp(ctxt, p)
+
+				p.As = AMOVW
+				p.From.Type = obj.TYPE_REG
+				p.From.Reg = REGTMP
+				p.To.Type = obj.TYPE_REG
+				p.To.Reg = REGLINK
+				break
+			}
+		}
+
+		// Otherwise, MRC/MCR instructions need no further treatment.
+		p.As = AWORD
+	}
+
+	// Rewrite float constants to values stored in memory.
+	switch p.As {
+	case AMOVF:
+		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)
+			p.From.Type = obj.TYPE_MEM
+			p.From.Sym = s
+			p.From.Name = obj.NAME_EXTERN
+			p.From.Offset = 0
+		}
+
+	case AMOVD:
+		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)
+			p.From.Type = obj.TYPE_MEM
+			p.From.Sym = s
+			p.From.Name = obj.NAME_EXTERN
+			p.From.Offset = 0
+		}
+	}
+
+	if ctxt.Flag_shared != 0 {
+		// Shared libraries use R_ARM_TLS_IE32 instead of
+		// R_ARM_TLS_LE32, replacing the link time constant TLS offset in
+		// runtime.tlsg with an address to a GOT entry containing the
+		// offset. Rewrite $runtime.tlsg(SB) to runtime.tlsg(SB) to
+		// compensate.
+		if ctxt.Tlsg == nil {
+			ctxt.Tlsg = obj.Linklookup(ctxt, "runtime.tlsg", 0)
+		}
+
+		if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && p.From.Sym == ctxt.Tlsg {
+			p.From.Type = obj.TYPE_MEM
+		}
+		if p.To.Type == obj.TYPE_ADDR && p.To.Name == obj.NAME_EXTERN && p.To.Sym == ctxt.Tlsg {
+			p.To.Type = obj.TYPE_MEM
+		}
+	}
+}
+
+// Prog.mark
+const (
+	FOLL  = 1 << 0
+	LABEL = 1 << 1
+	LEAF  = 1 << 2
+)
+
+func linkcase(casep *obj.Prog) {
+	for p := casep; p != nil; p = p.Link {
+		if p.As == ABCASE {
+			for ; p != nil && p.As == ABCASE; p = p.Link {
+				p.Rel = casep
+			}
+			break
+		}
+	}
+}
+
+func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
+	autosize := int32(0)
+
+	ctxt.Cursym = cursym
+
+	if cursym.Text == nil || cursym.Text.Link == nil {
+		return
+	}
+
+	softfloat(ctxt, cursym)
+
+	p := cursym.Text
+	autoffset := int32(p.To.Offset)
+	if autoffset < 0 {
+		autoffset = 0
+	}
+	cursym.Locals = autoffset
+	cursym.Args = p.To.Val.(int32)
+
+	if ctxt.Debugzerostack != 0 {
+		if autoffset != 0 && p.From3.Offset&obj.NOSPLIT == 0 {
+			// MOVW $4(R13), R1
+			p = obj.Appendp(ctxt, p)
+
+			p.As = AMOVW
+			p.From.Type = obj.TYPE_ADDR
+			p.From.Reg = REG_R13
+			p.From.Offset = 4
+			p.To.Type = obj.TYPE_REG
+			p.To.Reg = REG_R1
+
+			// MOVW $n(R13), R2
+			p = obj.Appendp(ctxt, p)
+
+			p.As = AMOVW
+			p.From.Type = obj.TYPE_ADDR
+			p.From.Reg = REG_R13
+			p.From.Offset = 4 + int64(autoffset)
+			p.To.Type = obj.TYPE_REG
+			p.To.Reg = REG_R2
+
+			// MOVW $0, R3
+			p = obj.Appendp(ctxt, p)
+
+			p.As = AMOVW
+			p.From.Type = obj.TYPE_CONST
+			p.From.Offset = 0
+			p.To.Type = obj.TYPE_REG
+			p.To.Reg = REG_R3
+
+			// L:
+			//	MOVW.nil R3, 0(R1) +4
+			//	CMP R1, R2
+			//	BNE L
+			pl := obj.Appendp(ctxt, p)
+			p := pl
+
+			p.As = AMOVW
+			p.From.Type = obj.TYPE_REG
+			p.From.Reg = REG_R3
+			p.To.Type = obj.TYPE_MEM
+			p.To.Reg = REG_R1
+			p.To.Offset = 4
+			p.Scond |= C_PBIT
+
+			p = obj.Appendp(ctxt, p)
+			p.As = ACMP
+			p.From.Type = obj.TYPE_REG
+			p.From.Reg = REG_R1
+			p.Reg = REG_R2
+
+			p = obj.Appendp(ctxt, p)
+			p.As = ABNE
+			p.To.Type = obj.TYPE_BRANCH
+			p.Pcond = pl
+		}
+	}
+
+	/*
+	 * find leaf subroutines
+	 * strip NOPs
+	 * expand RET
+	 * expand BECOME pseudo
+	 */
+	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 {
+				linkcase(p)
+			}
+
+		case obj.ATEXT:
+			p.Mark |= LEAF
+
+		case obj.ARET:
+			break
+
+		case ADIV, ADIVU, AMOD, AMODU:
+			q = p
+			if ctxt.Sym_div == nil {
+				initdiv(ctxt)
+			}
+			cursym.Text.Mark &^= LEAF
+			continue
+
+		case obj.ANOP:
+			q1 = p.Link
+			q.Link = q1 /* q is non-nop */
+			if q1 != nil {
+				q1.Mark |= p.Mark
+			}
+			continue
+
+		case ABL,
+			ABX,
+			obj.ADUFFZERO,
+			obj.ADUFFCOPY:
+			cursym.Text.Mark &^= LEAF
+			fallthrough
+
+		case ABCASE,
+			AB,
+			ABEQ,
+			ABNE,
+			ABCS,
+			ABHS,
+			ABCC,
+			ABLO,
+			ABMI,
+			ABPL,
+			ABVS,
+			ABVC,
+			ABHI,
+			ABLS,
+			ABGE,
+			ABLT,
+			ABGT,
+			ABLE:
+			q1 = p.Pcond
+			if q1 != nil {
+				for q1.As == obj.ANOP {
+					q1 = q1.Link
+					p.Pcond = q1
+				}
+			}
+		}
+
+		q = p
+	}
+
+	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:
+			autosize = int32(p.To.Offset + 4)
+			if autosize <= 4 {
+				if cursym.Text.Mark&LEAF != 0 {
+					p.To.Offset = -4
+					autosize = 0
+				}
+			}
+
+			if autosize == 0 && cursym.Text.Mark&LEAF == 0 {
+				if ctxt.Debugvlog != 0 {
+					fmt.Fprintf(ctxt.Bso, "save suppressed in: %s\n", cursym.Name)
+					ctxt.Bso.Flush()
+				}
+
+				cursym.Text.Mark |= LEAF
+			}
+
+			if cursym.Text.Mark&LEAF != 0 {
+				cursym.Leaf = 1
+				if autosize == 0 {
+					break
+				}
+			}
+
+			if p.From3.Offset&obj.NOSPLIT == 0 {
+				p = stacksplit(ctxt, p, autosize) // emit split check
+			}
+
+			// MOVW.W		R14,$-autosize(SP)
+			p = obj.Appendp(ctxt, p)
+
+			p.As = AMOVW
+			p.Scond |= C_WBIT
+			p.From.Type = obj.TYPE_REG
+			p.From.Reg = REGLINK
+			p.To.Type = obj.TYPE_MEM
+			p.To.Offset = int64(-autosize)
+			p.To.Reg = REGSP
+			p.Spadj = autosize
+
+			if cursym.Text.From3.Offset&obj.WRAPPER != 0 {
+				// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
+				//
+				//	MOVW g_panic(g), R1
+				//	CMP $0, R1
+				//	B.EQ end
+				//	MOVW panic_argp(R1), R2
+				//	ADD $(autosize+4), R13, R3
+				//	CMP R2, R3
+				//	B.NE end
+				//	ADD $4, R13, R4
+				//	MOVW R4, panic_argp(R1)
+				// end:
+				//	NOP
+				//
+				// The NOP is needed to give the jumps somewhere to land.
+				// It is a liblink NOP, not an ARM NOP: it encodes to 0 instruction bytes.
+
+				p = obj.Appendp(ctxt, p)
+
+				p.As = AMOVW
+				p.From.Type = obj.TYPE_MEM
+				p.From.Reg = REGG
+				p.From.Offset = 4 * int64(ctxt.Arch.Ptrsize) // G.panic
+				p.To.Type = obj.TYPE_REG
+				p.To.Reg = REG_R1
+
+				p = obj.Appendp(ctxt, p)
+				p.As = ACMP
+				p.From.Type = obj.TYPE_CONST
+				p.From.Offset = 0
+				p.Reg = REG_R1
+
+				p = obj.Appendp(ctxt, p)
+				p.As = ABEQ
+				p.To.Type = obj.TYPE_BRANCH
+				p1 = p
+
+				p = obj.Appendp(ctxt, p)
+				p.As = AMOVW
+				p.From.Type = obj.TYPE_MEM
+				p.From.Reg = REG_R1
+				p.From.Offset = 0 // Panic.argp
+				p.To.Type = obj.TYPE_REG
+				p.To.Reg = REG_R2
+
+				p = obj.Appendp(ctxt, p)
+				p.As = AADD
+				p.From.Type = obj.TYPE_CONST
+				p.From.Offset = int64(autosize) + 4
+				p.Reg = REG_R13
+				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_R2
+				p.Reg = REG_R3
+
+				p = obj.Appendp(ctxt, p)
+				p.As = ABNE
+				p.To.Type = obj.TYPE_BRANCH
+				p2 = p
+
+				p = obj.Appendp(ctxt, p)
+				p.As = AADD
+				p.From.Type = obj.TYPE_CONST
+				p.From.Offset = 4
+				p.Reg = REG_R13
+				p.To.Type = obj.TYPE_REG
+				p.To.Reg = REG_R4
+
+				p = obj.Appendp(ctxt, p)
+				p.As = AMOVW
+				p.From.Type = obj.TYPE_REG
+				p.From.Reg = REG_R4
+				p.To.Type = obj.TYPE_MEM
+				p.To.Reg = REG_R1
+				p.To.Offset = 0 // Panic.argp
+
+				p = obj.Appendp(ctxt, p)
+
+				p.As = obj.ANOP
+				p1.Pcond = p
+				p2.Pcond = p
+			}
+
+		case obj.ARET:
+			obj.Nocache(p)
+			if cursym.Text.Mark&LEAF != 0 {
+				if autosize == 0 {
+					p.As = AB
+					p.From = obj.Addr{}
+					if p.To.Sym != nil { // retjmp
+						p.To.Type = obj.TYPE_BRANCH
+					} else {
+						p.To.Type = obj.TYPE_MEM
+						p.To.Offset = 0
+						p.To.Reg = REGLINK
+					}
+
+					break
+				}
+			}
+
+			p.As = AMOVW
+			p.Scond |= C_PBIT
+			p.From.Type = obj.TYPE_MEM
+			p.From.Offset = int64(autosize)
+			p.From.Reg = REGSP
+			p.To.Type = obj.TYPE_REG
+			p.To.Reg = REGPC
+
+			// If there are instructions following
+			// this ARET, they come from a branch
+			// with the same stackframe, so no spadj.
+			if p.To.Sym != nil { // retjmp
+				p.To.Reg = REGLINK
+				q2 = obj.Appendp(ctxt, p)
+				q2.As = AB
+				q2.To.Type = obj.TYPE_BRANCH
+				q2.To.Sym = p.To.Sym
+				p.To.Sym = nil
+				p = q2
+			}
+
+		case AADD:
+			if p.From.Type == obj.TYPE_CONST && p.From.Reg == 0 && p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP {
+				p.Spadj = int32(-p.From.Offset)
+			}
+
+		case ASUB:
+			if p.From.Type == obj.TYPE_CONST && p.From.Reg == 0 && p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP {
+				p.Spadj = int32(p.From.Offset)
+			}
+
+		case ADIV, ADIVU, AMOD, AMODU:
+			if cursym.Text.From3.Offset&obj.NOSPLIT != 0 {
+				ctxt.Diag("cannot divide in NOSPLIT function")
+			}
+			if ctxt.Debugdivmod != 0 {
+				break
+			}
+			if p.From.Type != obj.TYPE_REG {
+				break
+			}
+			if p.To.Type != obj.TYPE_REG {
+				break
+			}
+
+			// Make copy because we overwrite p below.
+			q1 := *p
+			if q1.Reg == REGTMP || q1.Reg == 0 && q1.To.Reg == REGTMP {
+				ctxt.Diag("div already using REGTMP: %v", p)
+			}
+
+			/* MOV m(g),REGTMP */
+			p.As = AMOVW
+			p.Lineno = q1.Lineno
+			p.From.Type = obj.TYPE_MEM
+			p.From.Reg = REGG
+			p.From.Offset = 6 * 4 // offset of g.m
+			p.Reg = 0
+			p.To.Type = obj.TYPE_REG
+			p.To.Reg = REGTMP
+
+			/* MOV a,m_divmod(REGTMP) */
+			p = obj.Appendp(ctxt, p)
+			p.As = AMOVW
+			p.Lineno = q1.Lineno
+			p.From.Type = obj.TYPE_REG
+			p.From.Reg = q1.From.Reg
+			p.To.Type = obj.TYPE_MEM
+			p.To.Reg = REGTMP
+			p.To.Offset = 8 * 4 // offset of m.divmod
+
+			/* MOV b,REGTMP */
+			p = obj.Appendp(ctxt, p)
+			p.As = AMOVW
+			p.Lineno = q1.Lineno
+			p.From.Type = obj.TYPE_REG
+			p.From.Reg = q1.Reg
+			if q1.Reg == 0 {
+				p.From.Reg = q1.To.Reg
+			}
+			p.To.Type = obj.TYPE_REG
+			p.To.Reg = REGTMP
+			p.To.Offset = 0
+
+			/* CALL appropriate */
+			p = obj.Appendp(ctxt, p)
+			p.As = ABL
+			p.Lineno = q1.Lineno
+			p.To.Type = obj.TYPE_BRANCH
+			switch o {
+			case ADIV:
+				p.To.Sym = ctxt.Sym_div
+
+			case ADIVU:
+				p.To.Sym = ctxt.Sym_divu
+
+			case AMOD:
+				p.To.Sym = ctxt.Sym_mod
+
+			case AMODU:
+				p.To.Sym = ctxt.Sym_modu
+			}
+
+			/* MOV REGTMP, b */
+			p = obj.Appendp(ctxt, p)
+			p.As = AMOVW
+			p.Lineno = q1.Lineno
+			p.From.Type = obj.TYPE_REG
+			p.From.Reg = REGTMP
+			p.From.Offset = 0
+			p.To.Type = obj.TYPE_REG
+			p.To.Reg = q1.To.Reg
+
+		case AMOVW:
+			if (p.Scond&C_WBIT != 0) && p.To.Type == obj.TYPE_MEM && p.To.Reg == REGSP {
+				p.Spadj = int32(-p.To.Offset)
+			}
+			if (p.Scond&C_PBIT != 0) && p.From.Type == obj.TYPE_MEM && p.From.Reg == REGSP && p.To.Reg != REGPC {
+				p.Spadj = int32(-p.From.Offset)
+			}
+			if p.From.Type == obj.TYPE_ADDR && p.From.Reg == REGSP && p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP {
+				p.Spadj = int32(-p.From.Offset)
+			}
+		}
+	}
+}
+
+func isfloatreg(a *obj.Addr) bool {
+	return a.Type == obj.TYPE_REG && REG_F0 <= a.Reg && a.Reg <= REG_F15
+}
+
+func softfloat(ctxt *obj.Link, cursym *obj.LSym) {
+	if ctxt.Goarm > 5 {
+		return
+	}
+
+	symsfloat := obj.Linklookup(ctxt, "_sfloat", 0)
+
+	wasfloat := 0
+	for p := cursym.Text; p != nil; p = p.Link {
+		if p.Pcond != nil {
+			p.Pcond.Mark |= LABEL
+		}
+	}
+	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) {
+				goto soft
+			}
+			goto notsoft
+
+		case AMOVWD,
+			AMOVWF,
+			AMOVDW,
+			AMOVFW,
+			AMOVFD,
+			AMOVDF,
+			AMOVF,
+			AMOVD,
+			ACMPF,
+			ACMPD,
+			AADDF,
+			AADDD,
+			ASUBF,
+			ASUBD,
+			AMULF,
+			AMULD,
+			ADIVF,
+			ADIVD,
+			ASQRTF,
+			ASQRTD,
+			AABSF,
+			AABSD:
+			goto soft
+
+		default:
+			goto notsoft
+		}
+
+	soft:
+		if wasfloat == 0 || (p.Mark&LABEL != 0) {
+			next = ctxt.NewProg()
+			*next = *p
+
+			// BL _sfloat(SB)
+			*p = obj.Prog{}
+			p.Ctxt = ctxt
+			p.Link = next
+			p.As = ABL
+			p.To.Type = obj.TYPE_BRANCH
+			p.To.Sym = symsfloat
+			p.Lineno = next.Lineno
+
+			p = next
+			wasfloat = 1
+		}
+
+		continue
+
+	notsoft:
+		wasfloat = 0
+	}
+}
+
+func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
+	// MOVW			g_stackguard(g), R1
+	p = obj.Appendp(ctxt, p)
+
+	p.As = AMOVW
+	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
+
+	if framesize <= obj.StackSmall {
+		// small stack: SP < stackguard
+		//	CMP	stackguard, SP
+		p = obj.Appendp(ctxt, p)
+
+		p.As = ACMP
+		p.From.Type = obj.TYPE_REG
+		p.From.Reg = REG_R1
+		p.Reg = REGSP
+	} else if framesize <= obj.StackBig {
+		// large stack: SP-framesize < stackguard-StackSmall
+		//	MOVW $-framesize(SP), R2
+		//	CMP stackguard, R2
+		p = obj.Appendp(ctxt, p)
+
+		p.As = AMOVW
+		p.From.Type = obj.TYPE_ADDR
+		p.From.Reg = REGSP
+		p.From.Offset = int64(-framesize)
+		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
+		//	MOVW.NE $StackGuard(SP), R2
+		//	SUB.NE R1, R2
+		//	MOVW.NE $(framesize+(StackGuard-StackSmall)), R3
+		//	CMP.NE R3, R2
+		p = obj.Appendp(ctxt, p)
+
+		p.As = ACMP
+		p.From.Type = obj.TYPE_CONST
+		p.From.Offset = int64(uint32(obj.StackPreempt & (1<<32 - 1)))
+		p.Reg = REG_R1
+
+		p = obj.Appendp(ctxt, p)
+		p.As = AMOVW
+		p.From.Type = obj.TYPE_ADDR
+		p.From.Reg = REGSP
+		p.From.Offset = obj.StackGuard
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = REG_R2
+		p.Scond = C_SCOND_NE
+
+		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.Scond = C_SCOND_NE
+
+		p = obj.Appendp(ctxt, p)
+		p.As = AMOVW
+		p.From.Type = obj.TYPE_ADDR
+		p.From.Offset = int64(framesize) + (obj.StackGuard - obj.StackSmall)
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = REG_R3
+		p.Scond = C_SCOND_NE
+
+		p = obj.Appendp(ctxt, p)
+		p.As = ACMP
+		p.From.Type = obj.TYPE_REG
+		p.From.Reg = REG_R3
+		p.Reg = REG_R2
+		p.Scond = C_SCOND_NE
+	}
+
+	// BLS call-to-morestack
+	bls := obj.Appendp(ctxt, p)
+	bls.As = ABLS
+	bls.To.Type = obj.TYPE_BRANCH
+
+	var last *obj.Prog
+	for last = ctxt.Cursym.Text; last.Link != nil; last = last.Link {
+	}
+
+	// MOVW	LR, R3
+	movw := obj.Appendp(ctxt, last)
+	movw.As = AMOVW
+	movw.From.Type = obj.TYPE_REG
+	movw.From.Reg = REGLINK
+	movw.To.Type = obj.TYPE_REG
+	movw.To.Reg = REG_R3
+
+	bls.Pcond = movw
+
+	// BL runtime.morestack
+	call := obj.Appendp(ctxt, movw)
+	call.As = obj.ACALL
+	call.To.Type = obj.TYPE_BRANCH
+	morestack := "runtime.morestack"
+	switch {
+	case ctxt.Cursym.Cfunc != 0:
+		morestack = "runtime.morestackc"
+	case ctxt.Cursym.Text.From3.Offset&obj.NEEDCTXT == 0:
+		morestack = "runtime.morestack_noctxt"
+	}
+	call.To.Sym = obj.Linklookup(ctxt, morestack, 0)
+
+	// B start
+	b := obj.Appendp(ctxt, call)
+	b.As = obj.AJMP
+	b.To.Type = obj.TYPE_BRANCH
+	b.Pcond = ctxt.Cursym.Text.Link
+
+	return bls
+}
+
+func initdiv(ctxt *obj.Link) {
+	if ctxt.Sym_div != nil {
+		return
+	}
+	ctxt.Sym_div = obj.Linklookup(ctxt, "_div", 0)
+	ctxt.Sym_divu = obj.Linklookup(ctxt, "_divu", 0)
+	ctxt.Sym_mod = obj.Linklookup(ctxt, "_mod", 0)
+	ctxt.Sym_modu = obj.Linklookup(ctxt, "_modu", 0)
+}
+
+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 && q.As != obj.ATEXT {
+			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 && q.Scond == C_SCOND_NONE) || a == ARFE || a == obj.AUNDEF {
+				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("can't 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 && q.Scond == C_SCOND_NONE) || a == ARFE || a == obj.AUNDEF {
+					return
+				}
+				r.As = ABNE
+				if a == ABNE {
+					r.As = ABEQ
+				}
+				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("can't 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 && p.Scond == C_SCOND_NONE) || a == ARFE || a == obj.AUNDEF {
+		return
+	}
+
+	if p.Pcond != nil {
+		if a != ABL && a != ABX && 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
+}
+
+var unaryDst = map[int]bool{
+	ASWI:  true,
+	AWORD: true,
+}
+
+var Linkarm = obj.LinkArch{
+	ByteOrder:  binary.LittleEndian,
+	Name:       "arm",
+	Thechar:    '5',
+	Preprocess: preprocess,
+	Assemble:   span5,
+	Follow:     follow,
+	Progedit:   progedit,
+	UnaryDst:   unaryDst,
+	Minlc:      4,
+	Ptrsize:    4,
+	Regsize:    4,
+}
diff --git a/src/cmd/internal/obj/arm64/a.out.go b/src/cmd/internal/obj/arm64/a.out.go
new file mode 100644
index 0000000..67b37aa
--- /dev/null
+++ b/src/cmd/internal/obj/arm64/a.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 at 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 at 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..2845418
--- /dev/null
+++ b/src/cmd/internal/obj/arm64/anames.go
@@ -0,0 +1,379 @@
+// Generated by stringer -i a.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..ab0f7ae
--- /dev/null
+++ b/src/cmd/internal/obj/arm64/asm7.go
@@ -0,0 +1,4158 @@
+// 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 at 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 at 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},
+	{AMOVW, C_VCONADDR, C_NONE, C_REG, 68, 8, 0, 0, 0},
+	{AMOVD, C_VCON, C_NONE, C_REG, 12, 4, 0, LFROM, 0},
+	{AMOVD, C_VCONADDR, C_NONE, C_REG, 68, 8, 0, 0, 0},
+	{AMOVB, C_REG, C_NONE, C_ADDR, 64, 12, 0, 0, 0},
+	{AMOVBU, C_REG, C_NONE, C_ADDR, 64, 12, 0, 0, 0},
+	{AMOVH, C_REG, C_NONE, C_ADDR, 64, 12, 0, 0, 0},
+	{AMOVW, C_REG, C_NONE, C_ADDR, 64, 12, 0, 0, 0},
+	{AMOVD, C_REG, C_NONE, C_ADDR, 64, 12, 0, 0, 0},
+	{AMOVB, C_ADDR, C_NONE, C_REG, 65, 12, 0, 0, 0},
+	{AMOVBU, C_ADDR, C_NONE, C_REG, 65, 12, 0, 0, 0},
+	{AMOVH, C_ADDR, C_NONE, C_REG, 65, 12, 0, 0, 0},
+	{AMOVW, C_ADDR, C_NONE, C_REG, 65, 12, 0, 0, 0},
+	{AMOVD, C_ADDR, C_NONE, C_REG, 65, 12, 0, 0, 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, 12, 0, 0, 0},
+	{AFMOVS, C_ADDR, C_NONE, C_FREG, 65, 12, 0, 0, 0},
+	{AFMOVD, C_FREG, C_NONE, C_ADDR, 64, 12, 0, 0, 0},
+	{AFMOVD, C_ADDR, C_NONE, C_FREG, 65, 12, 0, 0, 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
+		}
+
+		// The line number for constant pool entries doesn't really matter.
+		// We set it to the line number of the preceding instruction so that
+		// there are no deltas to encode in the pc-line tables.
+		for q := ctxt.Blitrl; q != nil; q = q.Link {
+			q.Lineno = p.Lineno
+		}
+
+		ctxt.Elitrl.Link = p.Link
+		p.Link = ctxt.Blitrl
+
+		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 obj.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 obj.Bool2int(v <= 0xFFF)
+}
+
+func isbitcon(v uint64) int {
+	/*  fancy bimm32 or bimm64? */
+	// TODO(aram):
+	return 0
+	// return obj.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:
+		return cmp(C_LCON, b)
+
+	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.From3Type() == 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.From3Type() == obj.TYPE_NONE {
+				/* CINC/CINV/CNEG */
+				rf = r
+
+				cond ^= 1
+			} else {
+				rf = int(p.From3.Reg) /* CSEL */
+			}
+		} else {
+			/* CSET */
+			if p.From3Type() != obj.TYPE_NONE {
+				ctxt.Diag("invalid combination\n%v", p)
+			}
+			rf = REGZERO
+			r = rf
+			cond ^= 1
+		}
+
+		rt := int(p.To.Reg)
+		o1 |= (uint32(rf&31) << 16) | (uint32(cond&31) << 12) | (uint32(r&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 := obj.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.From3Type() != 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 == nil || p.From3.Reg < REG_F0 || p.From3.Reg > REG_F31 {
+			ctxt.Diag("illegal FCCMP\n%v", p)
+			break
+		}
+		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.RegTo2 != obj.REG_NONE {
+			o1 |= uint32(p.RegTo2&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 -> adrp + add + movT R, (REGTMP) */
+		o1 = ADR(1, 0, REGTMP)
+		o2 = opirr(ctxt, AADD) | REGTMP&31<<5 | REGTMP&31
+		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_ADDRARM64
+		o3 = olsr12u(ctxt, int32(opstr12(ctxt, int(p.As))), 0, REGTMP, int(p.From.Reg))
+
+	case 65: /* movT addr,R -> adrp + add + movT (REGTMP), R */
+		o1 = ADR(1, 0, REGTMP)
+		o2 = opirr(ctxt, AADD) | REGTMP&31<<5 | REGTMP&31
+		rel := obj.Addrel(ctxt.Cursym)
+		rel.Off = int32(ctxt.Pc)
+		rel.Siz = 8
+		rel.Sym = p.From.Sym
+		rel.Add = p.From.Offset
+		rel.Type = obj.R_ADDRARM64
+		o3 = 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))
+
+	case 68: /* movT $vconaddr(SB), reg -> adrp + add + reloc */
+		if p.As == AMOVW {
+			ctxt.Diag("invalid load of 32-bit address: %v", p)
+		}
+		o1 = ADR(1, 0, uint32(p.To.Reg))
+		o2 = opirr(ctxt, AADD) | uint32(p.To.Reg&31)<<5 | uint32(p.To.Reg&31)
+		rel := obj.Addrel(ctxt.Cursym)
+		rel.Off = int32(ctxt.Pc)
+		rel.Siz = 8
+		rel.Sym = p.From.Sym
+		rel.Add = p.From.Offset
+		rel.Type = obj.R_ADDRARM64
+
+	// 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 at 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 at 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..f43ce03
--- /dev/null
+++ b/src/cmd/internal/obj/arm64/obj7.go
@@ -0,0 +1,836 @@
+// 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 at 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 at 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) *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
+	}
+
+	// BLS	do-morestack
+	bls := obj.Appendp(ctxt, p)
+	bls.As = ABLS
+	bls.To.Type = obj.TYPE_BRANCH
+
+	var last *obj.Prog
+	for last = ctxt.Cursym.Text; last.Link != nil; last = last.Link {
+	}
+
+	// MOV	LR, R3
+	movlr := obj.Appendp(ctxt, last)
+	movlr.As = AMOVD
+	movlr.From.Type = obj.TYPE_REG
+	movlr.From.Reg = REGLINK
+	movlr.To.Type = obj.TYPE_REG
+	movlr.To.Reg = REG_R3
+	if q != nil {
+		q.Pcond = movlr
+	}
+	bls.Pcond = movlr
+
+	debug := movlr
+	if false {
+		debug = obj.Appendp(ctxt, debug)
+		debug.As = AMOVD
+		debug.From.Type = obj.TYPE_CONST
+		debug.From.Offset = int64(framesize)
+		debug.To.Type = obj.TYPE_REG
+		debug.To.Reg = REGTMP
+	}
+
+	// BL	runtime.morestack(SB)
+	call := obj.Appendp(ctxt, debug)
+	call.As = ABL
+	call.To.Type = obj.TYPE_BRANCH
+	morestack := "runtime.morestack"
+	switch {
+	case ctxt.Cursym.Cfunc != 0:
+		morestack = "runtime.morestackc"
+	case ctxt.Cursym.Text.From3.Offset&obj.NEEDCTXT == 0:
+		morestack = "runtime.morestack_noctxt"
+	}
+	call.To.Sym = obj.Linklookup(ctxt, morestack, 0)
+
+	// B	start
+	jmp := obj.Appendp(ctxt, call)
+	jmp.As = AB
+	jmp.To.Type = obj.TYPE_BRANCH
+	jmp.Pcond = ctxt.Cursym.Text.Link
+
+	// placeholder for bls's jump target
+	// p = obj.Appendp(ctxt, p)
+	// p.As = obj.ANOP
+
+	return bls
+}
+
+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) {
+	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
+	 */
+	ctxt.Bso.Flush()
+	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
+	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 {
+				// The frame includes an LR.
+				// If the frame size is 8, it's only an LR,
+				// so there's no potential for breaking references to
+				// local variables by growing the frame size,
+				// because there are no local variables.
+				// But otherwise, if there is a non-empty locals section,
+				// the author of the code is responsible for making sure
+				// that the frame size is 8 mod 16.
+				if ctxt.Autosize == 8 {
+					ctxt.Autosize += 8
+					cursym.Locals += 8
+				} else {
+					ctxt.Diag("%v: unaligned frame size %d - must be 8 mod 16 (or 0)", p, ctxt.Autosize-8)
+				}
+			}
+			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)
+				}
+				ctxt.Bso.Flush()
+				cursym.Text.Mark |= LEAF
+			}
+
+			if !(p.From3.Offset&obj.NOSPLIT != 0) {
+				p = stacksplit(ctxt, p, ctxt.Autosize) // 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.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,
+	ASVC:   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/data.go b/src/cmd/internal/obj/data.go
new file mode 100644
index 0000000..6e01e6e
--- /dev/null
+++ b/src/cmd/internal/obj/data.go
@@ -0,0 +1,268 @@
+// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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 obj
+
+import (
+	"log"
+	"math"
+)
+
+func mangle(file string) {
+	log.Fatalf("%s: mangled input file", file)
+}
+
+func Symgrow(ctxt *Link, s *LSym, lsiz int64) {
+	siz := int(lsiz)
+	if int64(siz) != lsiz {
+		log.Fatalf("Symgrow size %d too long", lsiz)
+	}
+	if len(s.P) >= siz {
+		return
+	}
+	for cap(s.P) < siz {
+		s.P = append(s.P[:cap(s.P)], 0)
+	}
+	s.P = s.P[:siz]
+}
+
+func savedata(ctxt *Link, s *LSym, p *Prog, pn string) {
+	off := int32(p.From.Offset)
+	siz := int32(p.From3.Offset)
+	if off < 0 || siz < 0 || off >= 1<<30 || siz >= 100 {
+		mangle(pn)
+	}
+	if ctxt.Enforce_data_order != 0 && off < int32(len(s.P)) {
+		ctxt.Diag("data out of order (already have %d)\n%v", len(s.P), p)
+	}
+	Symgrow(ctxt, s, int64(off+siz))
+
+	switch int(p.To.Type) {
+	default:
+		ctxt.Diag("bad data: %v", p)
+
+	case TYPE_FCONST:
+		switch siz {
+		default:
+			ctxt.Diag("unexpected %d-byte floating point constant", siz)
+
+		case 4:
+			flt := math.Float32bits(float32(p.To.Val.(float64)))
+			ctxt.Arch.ByteOrder.PutUint32(s.P[off:], flt)
+
+		case 8:
+			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.Val.(string))
+
+	case TYPE_CONST, TYPE_ADDR:
+		if p.To.Sym != nil || int(p.To.Type) == TYPE_ADDR {
+			r := Addrel(s)
+			r.Off = off
+			r.Siz = uint8(siz)
+			r.Sym = p.To.Sym
+			r.Type = R_ADDR
+			r.Add = p.To.Offset
+			break
+		}
+		o := p.To.Offset
+		switch siz {
+		default:
+			ctxt.Diag("unexpected %d-byte integer constant", siz)
+		case 1:
+			s.P[off] = byte(o)
+		case 2:
+			ctxt.Arch.ByteOrder.PutUint16(s.P[off:], uint16(o))
+		case 4:
+			ctxt.Arch.ByteOrder.PutUint32(s.P[off:], uint32(o))
+		case 8:
+			ctxt.Arch.ByteOrder.PutUint64(s.P[off:], uint64(o))
+		}
+	}
+}
+
+func Addrel(s *LSym) *Reloc {
+	s.R = append(s.R, Reloc{})
+	return &s.R[len(s.R)-1]
+}
+
+func Setuintxx(ctxt *Link, s *LSym, off int64, v uint64, wid int64) int64 {
+	if s.Type == 0 {
+		s.Type = SDATA
+	}
+	if s.Size < off+wid {
+		s.Size = off + wid
+		Symgrow(ctxt, s, s.Size)
+	}
+
+	switch wid {
+	case 1:
+		s.P[off] = uint8(v)
+	case 2:
+		ctxt.Arch.ByteOrder.PutUint16(s.P[off:], uint16(v))
+	case 4:
+		ctxt.Arch.ByteOrder.PutUint32(s.P[off:], uint32(v))
+	case 8:
+		ctxt.Arch.ByteOrder.PutUint64(s.P[off:], uint64(v))
+	}
+
+	return off + wid
+}
+
+func adduintxx(ctxt *Link, s *LSym, v uint64, wid int) int64 {
+	off := s.Size
+	Setuintxx(ctxt, s, off, v, int64(wid))
+	return off
+}
+
+func adduint8(ctxt *Link, s *LSym, v uint8) int64 {
+	return adduintxx(ctxt, s, uint64(v), 1)
+}
+
+func adduint16(ctxt *Link, s *LSym, v uint16) int64 {
+	return adduintxx(ctxt, s, uint64(v), 2)
+}
+
+func Adduint32(ctxt *Link, s *LSym, v uint32) int64 {
+	return adduintxx(ctxt, s, uint64(v), 4)
+}
+
+func Adduint64(ctxt *Link, s *LSym, v uint64) int64 {
+	return adduintxx(ctxt, s, v, 8)
+}
+
+func setuint8(ctxt *Link, s *LSym, r int64, v uint8) int64 {
+	return Setuintxx(ctxt, s, r, uint64(v), 1)
+}
+
+func setuint16(ctxt *Link, s *LSym, r int64, v uint16) int64 {
+	return Setuintxx(ctxt, s, r, uint64(v), 2)
+}
+
+func setuint32(ctxt *Link, s *LSym, r int64, v uint32) int64 {
+	return Setuintxx(ctxt, s, r, uint64(v), 4)
+}
+
+func setuint64(ctxt *Link, s *LSym, r int64, v uint64) int64 {
+	return Setuintxx(ctxt, s, r, v, 8)
+}
+
+func addaddrplus(ctxt *Link, s *LSym, t *LSym, add int64) int64 {
+	if s.Type == 0 {
+		s.Type = SDATA
+	}
+	i := s.Size
+	s.Size += int64(ctxt.Arch.Ptrsize)
+	Symgrow(ctxt, s, s.Size)
+	r := Addrel(s)
+	r.Sym = t
+	r.Off = int32(i)
+	r.Siz = uint8(ctxt.Arch.Ptrsize)
+	r.Type = R_ADDR
+	r.Add = add
+	return i + int64(r.Siz)
+}
+
+func addpcrelplus(ctxt *Link, s *LSym, t *LSym, add int64) int64 {
+	if s.Type == 0 {
+		s.Type = SDATA
+	}
+	i := s.Size
+	s.Size += 4
+	Symgrow(ctxt, s, s.Size)
+	r := Addrel(s)
+	r.Sym = t
+	r.Off = int32(i)
+	r.Add = add
+	r.Type = R_PCREL
+	r.Siz = 4
+	return i + int64(r.Siz)
+}
+
+func addaddr(ctxt *Link, s *LSym, t *LSym) int64 {
+	return addaddrplus(ctxt, s, t, 0)
+}
+
+func setaddrplus(ctxt *Link, s *LSym, off int64, t *LSym, add int64) int64 {
+	if s.Type == 0 {
+		s.Type = SDATA
+	}
+	if off+int64(ctxt.Arch.Ptrsize) > s.Size {
+		s.Size = off + int64(ctxt.Arch.Ptrsize)
+		Symgrow(ctxt, s, s.Size)
+	}
+
+	r := Addrel(s)
+	r.Sym = t
+	r.Off = int32(off)
+	r.Siz = uint8(ctxt.Arch.Ptrsize)
+	r.Type = R_ADDR
+	r.Add = add
+	return off + int64(r.Siz)
+}
+
+func setaddr(ctxt *Link, s *LSym, off int64, t *LSym) int64 {
+	return setaddrplus(ctxt, s, off, t, 0)
+}
+
+func addsize(ctxt *Link, s *LSym, t *LSym) int64 {
+	if s.Type == 0 {
+		s.Type = SDATA
+	}
+	i := s.Size
+	s.Size += int64(ctxt.Arch.Ptrsize)
+	Symgrow(ctxt, s, s.Size)
+	r := Addrel(s)
+	r.Sym = t
+	r.Off = int32(i)
+	r.Siz = uint8(ctxt.Arch.Ptrsize)
+	r.Type = R_SIZE
+	return i + int64(r.Siz)
+}
+
+func addaddrplus4(ctxt *Link, s *LSym, t *LSym, add int64) int64 {
+	if s.Type == 0 {
+		s.Type = SDATA
+	}
+	i := s.Size
+	s.Size += 4
+	Symgrow(ctxt, s, s.Size)
+	r := Addrel(s)
+	r.Sym = t
+	r.Off = int32(i)
+	r.Siz = 4
+	r.Type = R_ADDR
+	r.Add = add
+	return i + int64(r.Siz)
+}
diff --git a/src/cmd/internal/obj/flag.go b/src/cmd/internal/obj/flag.go
new file mode 100644
index 0000000..0664f5c
--- /dev/null
+++ b/src/cmd/internal/obj/flag.go
@@ -0,0 +1,120 @@
+// 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 (
+	"flag"
+	"fmt"
+	"os"
+	"strconv"
+)
+
+func Flagfn2(string, string, func(string, string)) { panic("flag") }
+
+func Flagcount(name, usage string, val *int) {
+	flag.Var((*count)(val), name, usage)
+}
+
+func Flagint32(name, usage string, val *int32) {
+	flag.Var((*int32Value)(val), name, usage)
+}
+
+func Flagint64(name, usage string, val *int64) {
+	flag.Int64Var(val, name, *val, usage)
+}
+
+func Flagstr(name, usage string, val *string) {
+	flag.StringVar(val, name, *val, usage)
+}
+
+func Flagfn0(name, usage string, f func()) {
+	flag.Var(fn0(f), name, usage)
+}
+
+func Flagfn1(name, usage string, f func(string)) {
+	flag.Var(fn1(f), name, usage)
+}
+
+func Flagprint(fd int) {
+	if fd == 1 {
+		flag.CommandLine.SetOutput(os.Stdout)
+	}
+	flag.PrintDefaults()
+}
+
+func Flagparse(usage func()) {
+	flag.Usage = usage
+	flag.Parse()
+}
+
+// count is a flag.Value that is like a flag.Bool and a flag.Int.
+// If used as -name, it increments the count, but -name=x sets the count.
+// Used for verbose flag -v.
+type count int
+
+func (c *count) String() string {
+	return fmt.Sprint(int(*c))
+}
+
+func (c *count) Set(s string) error {
+	switch s {
+	case "true":
+		*c++
+	case "false":
+		*c = 0
+	default:
+		n, err := strconv.Atoi(s)
+		if err != nil {
+			return fmt.Errorf("invalid count %q", s)
+		}
+		*c = count(n)
+	}
+	return nil
+}
+
+func (c *count) IsBoolFlag() bool {
+	return true
+}
+
+type int32Value int32
+
+func newIntValue(val int32, p *int32) *int32Value {
+	*p = val
+	return (*int32Value)(p)
+}
+
+func (i *int32Value) Set(s string) error {
+	v, err := strconv.ParseInt(s, 0, 64)
+	*i = int32Value(v)
+	return err
+}
+
+func (i *int32Value) Get() interface{} { return int32(*i) }
+
+func (i *int32Value) String() string { return fmt.Sprint(*i) }
+
+type fn0 func()
+
+func (f fn0) Set(s string) error {
+	f()
+	return nil
+}
+
+func (f fn0) Get() interface{} { return nil }
+
+func (f fn0) String() string { return "" }
+
+func (f fn0) IsBoolFlag() bool {
+	return true
+}
+
+type fn1 func(string)
+
+func (f fn1) Set(s string) error {
+	f(s)
+	return nil
+}
+
+func (f fn1) String() string { return "" }
diff --git a/src/cmd/internal/obj/fmt.go b/src/cmd/internal/obj/fmt.go
new file mode 100644
index 0000000..1268f42
--- /dev/null
+++ b/src/cmd/internal/obj/fmt.go
@@ -0,0 +1,34 @@
+/*
+ * 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 obj
+
+const (
+	FmtWidth = 1 << iota
+	FmtLeft
+	FmtPrec
+	FmtSharp
+	FmtSpace
+	FmtSign
+	FmtApost
+	FmtZero
+	FmtUnsigned
+	FmtShort
+	FmtLong
+	FmtVLong
+	FmtComma
+	FmtByte
+	FmtLDouble
+	FmtFlag
+)
diff --git a/src/cmd/internal/obj/funcdata.go b/src/cmd/internal/obj/funcdata.go
new file mode 100644
index 0000000..44cba7a
--- /dev/null
+++ b/src/cmd/internal/obj/funcdata.go
@@ -0,0 +1,79 @@
+// Inferno utils/5c/list.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5c/list.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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 obj
+
+// 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.
+
+// This file defines the IDs for PCDATA and FUNCDATA instructions
+// in Go binaries. It is included by assembly sources, so it must
+// be written using #defines.
+//
+// The Go compiler also #includes this file, for now.
+//
+// symtab.go also contains a copy of these constants.
+
+// Pseudo-assembly statements.
+
+// GO_ARGS, GO_RESULTS_INITIALIZED, and NO_LOCAL_POINTERS are macros
+// that communicate to the runtime information about the location and liveness
+// of pointers in an assembly function's arguments, results, and stack frame.
+// This communication is only required in assembly functions that make calls
+// to other functions that might be preempted or grow the stack.
+// NOSPLIT functions that make no calls do not need to use these macros.
+
+// GO_ARGS indicates that the Go prototype for this assembly function
+// defines the pointer map for the function's arguments.
+// GO_ARGS should be the first instruction in a function that uses it.
+// It can be omitted if there are no arguments at all.
+// GO_ARGS is inserted implicitly by the linker for any function
+// that also has a Go prototype and therefore is usually not necessary
+// to write explicitly.
+
+// GO_RESULTS_INITIALIZED indicates that the assembly function
+// has initialized the stack space for its results and that those results
+// should be considered live for the remainder of the function.
+
+// NO_LOCAL_POINTERS indicates that the assembly function stores
+// no pointers to heap objects in its local stack variables.
+
+// ArgsSizeUnknown is set in Func.argsize to mark all functions
+// whose argument size is unknown (C vararg functions, and
+// assembly code without an explicit specification).
+// This value is generated by the compiler, assembler, or linker.
+const (
+	PCDATA_StackMapIndex       = 0
+	FUNCDATA_ArgsPointerMaps   = 0
+	FUNCDATA_LocalsPointerMaps = 1
+	FUNCDATA_DeadValueMaps     = 2
+	ArgsSizeUnknown            = -0x80000000
+)
diff --git a/src/cmd/internal/obj/go.go b/src/cmd/internal/obj/go.go
new file mode 100644
index 0000000..3e6cd21
--- /dev/null
+++ b/src/cmd/internal/obj/go.go
@@ -0,0 +1,83 @@
+// 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 obj
+
+import (
+	"fmt"
+	"os"
+	"strings"
+)
+
+// go-specific code shared across loaders (5l, 6l, 8l).
+
+var (
+	Framepointer_enabled int
+	Fieldtrack_enabled   int
+)
+
+// Toolchain experiments.
+// These are controlled by the GOEXPERIMENT environment
+// variable recorded when the toolchain is built.
+// This list is also known to cmd/gc.
+var exper = []struct {
+	name string
+	val  *int
+}{
+	{"fieldtrack", &Fieldtrack_enabled},
+	{"framepointer", &Framepointer_enabled},
+}
+
+func addexp(s string) {
+	for i := 0; i < len(exper); i++ {
+		if exper[i].name == s {
+			if exper[i].val != nil {
+				*exper[i].val = 1
+			}
+			return
+		}
+	}
+
+	fmt.Printf("unknown experiment %s\n", s)
+	os.Exit(2)
+}
+
+func init() {
+	for _, f := range strings.Split(goexperiment, ",") {
+		if f != "" {
+			addexp(f)
+		}
+	}
+}
+
+func Nopout(p *Prog) {
+	p.As = ANOP
+	p.Scond = 0
+	p.From = Addr{}
+	p.From3 = nil
+	p.Reg = 0
+	p.To = Addr{}
+}
+
+func Nocache(p *Prog) {
+	p.Optab = 0
+	p.From.Class = 0
+	if p.From3 != nil {
+		p.From3.Class = 0
+	}
+	p.To.Class = 0
+}
+
+func Expstring() string {
+	buf := "X"
+	for i := range exper {
+		if *exper[i].val != 0 {
+			buf += "," + exper[i].name
+		}
+	}
+	if buf == "X" {
+		buf += ",none"
+	}
+	return "X:" + buf[2:]
+}
diff --git a/src/cmd/internal/obj/ld.go b/src/cmd/internal/obj/ld.go
new file mode 100644
index 0000000..4d2e429
--- /dev/null
+++ b/src/cmd/internal/obj/ld.go
@@ -0,0 +1,92 @@
+// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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 obj
+
+/*
+ * add library to library list.
+ *	srcref: src file referring to package
+ *	objref: object file referring to package
+ *	file: object file, e.g., /home/rsc/go/pkg/container/vector.a
+ *	pkg: package import path, e.g. container/vector
+ */
+
+const (
+	LOG = 5
+)
+
+func mkfwd(sym *LSym) {
+	var dwn [LOG]int32
+	var cnt [LOG]int32
+	var lst [LOG]*Prog
+
+	for i := 0; i < LOG; i++ {
+		if i == 0 {
+			cnt[i] = 1
+		} else {
+			cnt[i] = LOG * cnt[i-1]
+		}
+		dwn[i] = 1
+		lst[i] = nil
+	}
+
+	i := 0
+	for p := sym.Text; p != nil && p.Link != nil; p = p.Link {
+		i--
+		if i < 0 {
+			i = LOG - 1
+		}
+		p.Forwd = nil
+		dwn[i]--
+		if dwn[i] <= 0 {
+			dwn[i] = cnt[i]
+			if lst[i] != nil {
+				lst[i].Forwd = p
+			}
+			lst[i] = p
+		}
+	}
+}
+
+func Copyp(ctxt *Link, q *Prog) *Prog {
+	p := ctxt.NewProg()
+	*p = *q
+	return p
+}
+
+func Appendp(ctxt *Link, q *Prog) *Prog {
+	p := ctxt.NewProg()
+	p.Link = q.Link
+	q.Link = p
+	p.Lineno = q.Lineno
+	p.Mode = q.Mode
+	return p
+}
diff --git a/src/cmd/internal/obj/libc.go b/src/cmd/internal/obj/libc.go
new file mode 100644
index 0000000..b200b26
--- /dev/null
+++ b/src/cmd/internal/obj/libc.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.
+
+package obj
+
+const (
+	AEXIST = 0
+	BOM    = 0xFEFF
+)
+
+var GOEXPERIMENT string
diff --git a/src/cmd/internal/obj/line_test.go b/src/cmd/internal/obj/line_test.go
new file mode 100644
index 0000000..5486f0d
--- /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)
+
+	ctxt.LineHist.Push(1, "a.c")
+	ctxt.LineHist.Push(3, "a.h")
+	ctxt.LineHist.Pop(5)
+	ctxt.LineHist.Update(7, "linedir", 2)
+	ctxt.LineHist.Pop(9)
+	ctxt.LineHist.Push(11, "b.c")
+	ctxt.LineHist.Pop(13)
+
+	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
new file mode 100644
index 0000000..688c278
--- /dev/null
+++ b/src/cmd/internal/obj/link.go
@@ -0,0 +1,569 @@
+// Derived from Inferno utils/6l/l.h and related files.
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/l.h
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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 obj
+
+import "encoding/binary"
+
+// An Addr is an argument to an instruction.
+// The general forms and their encodings are:
+//
+//	sym±offset(symkind)(reg)(index*scale)
+//		Memory reference at address &sym(symkind) + offset + reg + index*scale.
+//		Any of sym(symkind), ±offset, (reg), (index*scale), and *scale can be omitted.
+//		If (reg) and *scale are both omitted, the resulting expression (index) is parsed as (reg).
+//		To force a parsing as index*scale, write (index*1).
+//		Encoding:
+//			type = TYPE_MEM
+//			name = symkind (NAME_AUTO, ...) or 0 (NAME_NONE)
+//			sym = sym
+//			offset = ±offset
+//			reg = reg (REG_*)
+//			index = index (REG_*)
+//			scale = scale (1, 2, 4, 8)
+//
+//	$<mem>
+//		Effective address of memory reference <mem>, defined above.
+//		Encoding: same as memory reference, but type = TYPE_ADDR.
+//
+//	$<±integer value>
+//		This is a special case of $<mem>, in which only ±offset is present.
+//		It has a separate type for easy recognition.
+//		Encoding:
+//			type = TYPE_CONST
+//			offset = ±integer value
+//
+//	*<mem>
+//		Indirect reference through memory reference <mem>, defined above.
+//		Only used on x86 for CALL/JMP *sym(SB), which calls/jumps to a function
+//		pointer stored in the data word sym(SB), not a function named sym(SB).
+//		Encoding: same as above, but type = TYPE_INDIR.
+//
+//	$*$<mem>
+//		No longer used.
+//		On machines with actual SB registers, $*$<mem> forced the
+//		instruction encoding to use a full 32-bit constant, never a
+//		reference relative to SB.
+//
+//	$<floating point literal>
+//		Floating point constant value.
+//		Encoding:
+//			type = TYPE_FCONST
+//			val = floating point value
+//
+//	$<string literal, up to 8 chars>
+//		String literal value (raw bytes used for DATA instruction).
+//		Encoding:
+//			type = TYPE_SCONST
+//			val = string
+//
+//	<register name>
+//		Any register: integer, floating point, control, segment, and so on.
+//		If looking for specific register kind, must check type and reg value range.
+//		Encoding:
+//			type = TYPE_REG
+//			reg = reg (REG_*)
+//
+//	x(PC)
+//		Encoding:
+//			type = TYPE_BRANCH
+//			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.
+//		In this form, x and y are integer literals only, not arbitrary expressions.
+//		This avoids parsing ambiguities due to the use of - as a separator.
+//		The ± are optional.
+//		If the final argument to TEXT omits the -±y, the encoding should still
+//		use TYPE_TEXTSIZE (not TYPE_CONST), with u.argsize = ArgsSizeUnknown.
+//		Encoding:
+//			type = TYPE_TEXTSIZE
+//			offset = x
+//			val = int32(y)
+//
+//	reg<<shift, reg>>shift, reg->shift, reg@>shift
+//		Shifted register value, for ARM.
+//		In this form, reg must be a register and shift can be a register or an integer constant.
+//		Encoding:
+//			type = TYPE_SHIFT
+//			offset = (reg&15) | shifttype<<5 | count
+//			shifttype = 0, 1, 2, 3 for <<, >>, ->, @>
+//			count = (reg&15)<<8 | 1<<4 for a register shift count, (n&31)<<7 for an integer constant.
+//
+//	(reg, reg)
+//		A destination register pair. When used as the last argument of an instruction,
+//		this form makes clear that both registers are destinations.
+//		Encoding:
+//			type = TYPE_REGREG
+//			reg = first register
+//			offset = second register
+//
+//	[reg, reg, reg-reg]
+//		Register list for ARM.
+//		Encoding:
+//			type = TYPE_REGLIST
+//			offset = bit mask of registers in list; R0 is low bit.
+//
+//	reg, reg
+//		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
+	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
+	NAME_EXTERN
+	NAME_STATIC
+	NAME_AUTO
+	NAME_PARAM
+	// A reference to name at GOT(SB) is a reference to the entry in the global offset
+	// table for 'name'.
+	NAME_GOTREF
+)
+
+const (
+	TYPE_NONE = 0
+)
+
+const (
+	TYPE_BRANCH = 5 + iota
+	TYPE_TEXTSIZE
+	TYPE_MEM
+	TYPE_CONST
+	TYPE_FCONST
+	TYPE_SCONST
+	TYPE_REG
+	TYPE_ADDR
+	TYPE_SHIFT
+	TYPE_REGREG
+	TYPE_REGREG2
+	TYPE_INDIR
+	TYPE_REGLIST
+)
+
+// 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 // optional
+	To     Addr
+	Opt    interface{}
+	Forwd  *Prog
+	Pcond  *Prog
+	Rel    *Prog // Source of forward jumps on x86; pcrel on arm
+	Pc     int64
+	Lineno int32
+	Spadj  int32
+	As     int16
+	Reg    int16
+	RegTo2 int16 // 2nd register output operand
+	Mark   uint16
+	Optab  uint16
+	Scond  uint8
+	Back   uint8
+	Ft     uint8
+	Tt     uint8
+	Isize  uint8
+	Mode   int8
+
+	Info ProgInfo
+}
+
+// From3Type returns From3.Type, or TYPE_NONE when From3 is nil.
+func (p *Prog) From3Type() int16 {
+	if p.From3 == nil {
+		return TYPE_NONE
+	}
+	return p.From3.Type
+}
+
+// From3Offset returns From3.Offset, or 0 when From3 is nil.
+func (p *Prog) From3Offset() int64 {
+	if p.From3 == nil {
+		return 0
+	}
+	return p.From3.Offset
+}
+
+// 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
+	ACHECKNIL
+	ADATA
+	ADUFFCOPY
+	ADUFFZERO
+	AEND
+	AFUNCDATA
+	AGLOBL
+	AJMP
+	ANOP
+	APCDATA
+	ARET
+	ATEXT
+	ATYPE
+	AUNDEF
+	AUSEFIELD
+	AVARDEF
+	AVARKILL
+	A_ARCHSPECIFIC
+)
+
+// An LSym is the sort of symbol that is written to an object file.
+type LSym struct {
+	Name      string
+	Type      int16
+	Version   int16
+	Dupok     uint8
+	Cfunc     uint8
+	Nosplit   uint8
+	Leaf      uint8
+	Seenglobl uint8
+	Onlist    uint8
+	// Local means make the symbol local even when compiling Go code to reference Go
+	// symbols in other shared libraries, as in this mode symbols are global by
+	// default. "local" here means in the sense of the dynamic linker, i.e. not
+	// visible outside of the module (shared library or executable) that contains its
+	// definition. (When not compiling to support Go shared libraries, all symbols are
+	// local in this sense unless there is a cgo_export_* directive).
+	Local  bool
+	Args   int32
+	Locals int32
+	Value  int64
+	Size   int64
+	Next   *LSym
+	Gotype *LSym
+	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 (
+	Sxxx = iota
+	STEXT
+	SELFRXSECT
+	STYPE
+	SSTRING
+	SGOSTRING
+	SGOFUNC
+	SGCBITS
+	SRODATA
+	SFUNCTAB
+	STYPELINK
+	SSYMTAB
+	SPCLNTAB
+	SELFROSECT
+	SMACHOPLT
+	SELFSECT
+	SMACHO
+	SMACHOGOT
+	SWINDOWS
+	SELFGOT
+	SNOPTRDATA
+	SINITARR
+	SDATA
+	SBSS
+	SNOPTRBSS
+	STLSBSS
+	SXREF
+	SMACHOSYMSTR
+	SMACHOSYMTAB
+	SMACHOINDIRECTPLT
+	SMACHOINDIRECTGOT
+	SFILE
+	SFILEPATH
+	SCONST
+	SDYNIMPORT
+	SHOSTOBJ
+	SSUB       = 1 << 8
+	SMASK      = SSUB - 1
+	SHIDDEN    = 1 << 9
+	SCONTAINER = 1 << 10 // has a sub-symbol
+)
+
+type Reloc struct {
+	Off  int32
+	Siz  uint8
+	Type int32
+	Add  int64
+	Sym  *LSym
+}
+
+// Reloc.type
+const (
+	R_ADDR = 1 + iota
+	R_ADDRPOWER
+	R_ADDRARM64
+	R_SIZE
+	R_CALL
+	R_CALLARM
+	R_CALLARM64
+	R_CALLIND
+	R_CALLPOWER
+	R_CONST
+	R_PCREL
+	// R_TLS (only used on arm currently, and not on android and darwin where tlsg is
+	// a regular variable) resolves to data needed to access the thread-local g. It is
+	// interpreted differently depending on toolchain flags to implement either the
+	// "local exec" or "inital exec" model for tls access.
+	// TODO(mwhudson): change to use R_TLS_LE or R_TLS_IE as appropriate, not having
+	// R_TLS do double duty.
+	R_TLS
+	// R_TLS_LE (only used on 386 and amd64 currently) resolves to the offset of the
+	// thread-local g from the thread local base and is used to implement the "local
+	// exec" model for tls access (r.Sym is not set by the compiler for this case but
+	// is set to Tlsg in the linker when externally linking).
+	R_TLS_LE
+	// R_TLS_IE (only used on 386 and amd64 currently) resolves to the PC-relative
+	// offset to a GOT slot containing the offset the thread-local g from the thread
+	// local base and is used to implemented the "initial exec" model for tls access
+	// (r.Sym is not set by the compiler for this case but is set to Tlsg in the
+	// linker when externally linking).
+	R_TLS_IE
+	R_GOTOFF
+	R_PLT0
+	R_PLT1
+	R_PLT2
+	R_USEFIELD
+	R_POWER_TOC
+	R_GOTPCREL
+)
+
+type Auto struct {
+	Asym    *LSym
+	Link    *Auto
+	Aoffset int32
+	Name    int16
+	Gotype  *LSym
+}
+
+// Auto.name
+const (
+	A_AUTO = 1 + iota
+	A_PARAM
+)
+
+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.
+const (
+	HistVersion = 1
+)
+
+// 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 {
+	Goarm              int32
+	Headtype           int
+	Arch               *LinkArch
+	Debugasm           int32
+	Debugvlog          int32
+	Debugzerostack     int32
+	Debugdivmod        int32
+	Debugpcln          int32
+	Flag_shared        int32
+	Flag_dynlink       bool
+	Bso                *Biobuf
+	Pathname           string
+	Windows            int32
+	Goroot             string
+	Goroot_final       string
+	Enforce_data_order int32
+	Hash               map[SymVer]*LSym
+	LineHist           LineHist
+	Imports            []string
+	Plist              *Plist
+	Plast              *Plist
+	Sym_div            *LSym
+	Sym_divu           *LSym
+	Sym_mod            *LSym
+	Sym_modu           *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
+	Tlsoffset          int
+	Diag               func(string, ...interface{})
+	Mode               int
+	Cursym             *LSym
+	Version            int
+	Textp              *LSym
+	Etextp             *LSym
+}
+
+type SymVer struct {
+	Name    string
+	Version int // TODO: make int16 to match LSym.Version?
+}
+
+// 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 (
+	Hunknown = 0 + iota
+	Hdarwin
+	Hdragonfly
+	Helf
+	Hfreebsd
+	Hlinux
+	Hnacl
+	Hnetbsd
+	Hopenbsd
+	Hplan9
+	Hsolaris
+	Hwindows
+)
+
+type Plist struct {
+	Name    *LSym
+	Firstpc *Prog
+	Recur   int
+	Link    *Plist
+}
+
+/*
+ * start a new Prog list.
+ */
+func Linknewplist(ctxt *Link) *Plist {
+	pl := new(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
new file mode 100644
index 0000000..a385d60
--- /dev/null
+++ b/src/cmd/internal/obj/mgc0.go
@@ -0,0 +1,30 @@
+// 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 obj
+
+// 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.
+
+// 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.
+
+const (
+	InsData = 1 + iota
+	InsArray
+	InsArrayEnd
+	InsEnd
+	MaxGCMask = 65536
+)
diff --git a/src/cmd/internal/obj/obj.go b/src/cmd/internal/obj/obj.go
new file mode 100644
index 0000000..af3290d
--- /dev/null
+++ b/src/cmd/internal/obj/obj.go
@@ -0,0 +1,283 @@
+// 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 obj
+
+import (
+	"fmt"
+	"path/filepath"
+	"sort"
+	"strings"
+)
+
+// 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
+}
+
+// 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)
+	}
+
+	// Remove leading TrimPathPrefix, or else rewrite $GOROOT to $GOROOT_FINAL.
+	if h.TrimPathPrefix != "" && hasPathPrefix(abs, h.TrimPathPrefix) {
+		if abs == h.TrimPathPrefix {
+			abs = ""
+		} else {
+			abs = abs[len(h.TrimPathPrefix)+1:]
+		}
+	} else if h.GOROOT_FINAL != "" && h.GOROOT_FINAL != h.GOROOT && hasPathPrefix(abs, h.GOROOT) {
+		abs = h.GOROOT_FINAL + abs[len(h.GOROOT):]
+	}
+	if abs == "" {
+		abs = "??"
+	}
+	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.
+// 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
+	for i = 0; i < len(t); i++ {
+		cs := int(s[i])
+		ct := int(t[i])
+		if 'A' <= cs && cs <= 'Z' {
+			cs += 'a' - 'A'
+		}
+		if 'A' <= ct && ct <= 'Z' {
+			ct += 'a' - 'A'
+		}
+		if cs == '\\' {
+			cs = '/'
+		}
+		if ct == '\\' {
+			ct = '/'
+		}
+		if cs != ct {
+			return false
+		}
+	}
+	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
+}
+
+// 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, lineno int32, f **LSym, l *int32) {
+	stk := ctxt.LineHist.At(int(lineno))
+	if stk == nil || stk.AbsFile == "" {
+		*f = Linklookup(ctxt, "??", HistVersion)
+		*l = 0
+		return
+	}
+	if stk.Sym == nil {
+		stk.Sym = Linklookup(ctxt, stk.AbsFile, HistVersion)
+	}
+	*f = stk.Sym
+	*l = int32(stk.fileLineAt(int(lineno)))
+}
+
+func Linkprfile(ctxt *Link, line int) {
+	fmt.Printf("%s ", ctxt.LineHist.LineString(line))
+}
diff --git a/src/cmd/internal/obj/objfile.go b/src/cmd/internal/obj/objfile.go
new file mode 100644
index 0000000..c5f4820
--- /dev/null
+++ b/src/cmd/internal/obj/objfile.go
@@ -0,0 +1,523 @@
+// 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.
+
+// 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 (
+	"fmt"
+	"log"
+	"path/filepath"
+	"strings"
+)
+
+var outfile string
+
+// The Go and C compilers, and the assembler, call writeobj to write
+// out a Go object file.  The linker does not call this; the linker
+// does not write out object files.
+func Writeobjdirect(ctxt *Link, b *Biobuf) {
+	var flag int
+	var s *LSym
+	var p *Prog
+	var plink *Prog
+	var a *Auto
+
+	// 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.
+	var text *LSym
+
+	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 {
+				fmt.Printf("obj: %v\n", p)
+			}
+			plink = p.Link
+			p.Link = nil
+
+			if p.As == AEND {
+				continue
+			}
+
+			if p.As == ATYPE {
+				// Assume each TYPE instruction describes
+				// a different local variable or parameter,
+				// so no dedup.
+				// Using only the TYPE instructions means
+				// that we discard location information about local variables
+				// in C and assembly functions; that information is inferred
+				// from ordinary references, because there are no TYPE
+				// instructions there. Without the type information, gdb can't
+				// use the locations, so we don't bother to save them.
+				// If something else could use them, we could arrange to
+				// preserve them.
+				if curtext == nil {
+					continue
+				}
+				a = new(Auto)
+				a.Asym = p.From.Sym
+				a.Aoffset = int32(p.From.Offset)
+				a.Name = int16(p.From.Name)
+				a.Gotype = p.From.Gotype
+				a.Link = curtext.Autom
+				curtext.Autom = a
+				continue
+			}
+
+			if p.As == AGLOBL {
+				s = p.From.Sym
+				tmp6 := s.Seenglobl
+				s.Seenglobl++
+				if tmp6 != 0 {
+					fmt.Printf("duplicate %v\n", p)
+				}
+				if s.Onlist != 0 {
+					log.Fatalf("symbol %s listed multiple times", s.Name)
+				}
+				s.Onlist = 1
+				if data == nil {
+					data = s
+				} else {
+					edata.Next = s
+				}
+				s.Next = nil
+				s.Size = p.To.Offset
+				if s.Type == 0 || s.Type == SXREF {
+					s.Type = SBSS
+				}
+				flag = int(p.From3.Offset)
+				if flag&DUPOK != 0 {
+					s.Dupok = 1
+				}
+				if flag&RODATA != 0 {
+					s.Type = SRODATA
+				} else if flag&NOPTR != 0 {
+					s.Type = SNOPTRBSS
+				}
+				edata = s
+				continue
+			}
+
+			if p.As == ADATA {
+				savedata(ctxt, p.From.Sym, p, "<input>")
+				continue
+			}
+
+			if p.As == ATEXT {
+				s = p.From.Sym
+				if s == nil {
+					// func _() { }
+					curtext = nil
+
+					continue
+				}
+
+				if s.Text != nil {
+					log.Fatalf("duplicate TEXT for %s", s.Name)
+				}
+				if s.Onlist != 0 {
+					log.Fatalf("symbol %s listed multiple times", s.Name)
+				}
+				s.Onlist = 1
+				if text == nil {
+					text = s
+				} else {
+					etext.Next = s
+				}
+				etext = s
+				flag = int(p.From3Offset())
+				if flag&DUPOK != 0 {
+					s.Dupok = 1
+				}
+				if flag&NOSPLIT != 0 {
+					s.Nosplit = 1
+				}
+				s.Next = nil
+				s.Type = STEXT
+				s.Text = p
+				s.Etext = p
+				curtext = s
+				continue
+			}
+
+			if p.As == AFUNCDATA {
+				// Rewrite reference to go_args_stackmap(SB) to the Go-provided declaration information.
+				if curtext == nil { // func _() {}
+					continue
+				}
+				if p.To.Sym.Name == "go_args_stackmap" {
+					if p.From.Type != TYPE_CONST || p.From.Offset != FUNCDATA_ArgsPointerMaps {
+						ctxt.Diag("FUNCDATA use of go_args_stackmap(SB) without FUNCDATA_ArgsPointerMaps")
+					}
+					p.To.Sym = Linklookup(ctxt, fmt.Sprintf("%s.args_stackmap", curtext.Name), int(curtext.Version))
+				}
+			}
+
+			if curtext == nil {
+				continue
+			}
+			s = curtext
+			s.Etext.Link = p
+			s.Etext = p
+		}
+	}
+
+	// Add reference to Go arguments for C or assembly functions without them.
+	var found int
+	for s := text; s != nil; s = s.Next {
+		if !strings.HasPrefix(s.Name, "\"\".") {
+			continue
+		}
+		found = 0
+		for p = s.Text; p != nil; p = p.Link {
+			if p.As == AFUNCDATA && p.From.Type == TYPE_CONST && p.From.Offset == FUNCDATA_ArgsPointerMaps {
+				found = 1
+				break
+			}
+		}
+
+		if found == 0 {
+			p = Appendp(ctxt, s.Text)
+			p.As = AFUNCDATA
+			p.From.Type = TYPE_CONST
+			p.From.Offset = FUNCDATA_ArgsPointerMaps
+			p.To.Type = TYPE_MEM
+			p.To.Name = NAME_EXTERN
+			p.To.Sym = Linklookup(ctxt, fmt.Sprintf("%s.args_stackmap", s.Name), int(s.Version))
+		}
+	}
+
+	// Turn functions into machine code images.
+	for s := text; s != nil; s = s.Next {
+		mkfwd(s)
+		linkpatch(ctxt, s)
+		ctxt.Arch.Follow(ctxt, s)
+		ctxt.Arch.Preprocess(ctxt, s)
+		ctxt.Arch.Assemble(ctxt, s)
+		linkpcln(ctxt, s)
+	}
+
+	// Emit header.
+	Bputc(b, 0)
+
+	Bputc(b, 0)
+	fmt.Fprintf(b, "go13ld")
+	Bputc(b, 1) // version
+
+	// Emit autolib.
+	for _, pkg := range ctxt.Imports {
+		wrstring(b, pkg)
+	}
+	wrstring(b, "")
+
+	// Emit symbols.
+	for s := text; s != nil; s = s.Next {
+		writesym(ctxt, b, s)
+	}
+	for s := data; s != nil; s = s.Next {
+		writesym(ctxt, b, s)
+	}
+
+	// Emit footer.
+	Bputc(b, 0xff)
+
+	Bputc(b, 0xff)
+	fmt.Fprintf(b, "go13ld")
+}
+
+func writesym(ctxt *Link, b *Biobuf, s *LSym) {
+	if ctxt.Debugasm != 0 {
+		fmt.Fprintf(ctxt.Bso, "%s ", s.Name)
+		if s.Version != 0 {
+			fmt.Fprintf(ctxt.Bso, "v=%d ", s.Version)
+		}
+		if s.Type != 0 {
+			fmt.Fprintf(ctxt.Bso, "t=%d ", s.Type)
+		}
+		if s.Dupok != 0 {
+			fmt.Fprintf(ctxt.Bso, "dupok ")
+		}
+		if s.Cfunc != 0 {
+			fmt.Fprintf(ctxt.Bso, "cfunc ")
+		}
+		if s.Nosplit != 0 {
+			fmt.Fprintf(ctxt.Bso, "nosplit ")
+		}
+		fmt.Fprintf(ctxt.Bso, "size=%d value=%d", int64(s.Size), int64(s.Value))
+		if s.Type == STEXT {
+			fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x", uint64(s.Args), uint64(s.Locals))
+			if s.Leaf != 0 {
+				fmt.Fprintf(ctxt.Bso, " leaf")
+			}
+		}
+
+		fmt.Fprintf(ctxt.Bso, "\n")
+		for p := s.Text; p != nil; p = p.Link {
+			fmt.Fprintf(ctxt.Bso, "\t%#04x %v\n", uint(int(p.Pc)), 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])
+			}
+			for ; j < i+16; j++ {
+				fmt.Fprintf(ctxt.Bso, "   ")
+			}
+			fmt.Fprintf(ctxt.Bso, "  ")
+			for j = i; j < i+16 && j < len(s.P); j++ {
+				c = int(s.P[j])
+				if ' ' <= c && c <= 0x7e {
+					fmt.Fprintf(ctxt.Bso, "%c", c)
+				} else {
+					fmt.Fprintf(ctxt.Bso, ".")
+				}
+			}
+
+			fmt.Fprintf(ctxt.Bso, "\n")
+			i += 16
+		}
+
+		var r *Reloc
+		var name string
+		for i := 0; i < len(s.R); i++ {
+			r = &s.R[i]
+			name = ""
+			if r.Sym != nil {
+				name = r.Sym.Name
+			}
+			if ctxt.Arch.Thechar == '5' || ctxt.Arch.Thechar == '9' {
+				fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%x\n", int(r.Off), r.Siz, r.Type, name, uint64(int64(r.Add)))
+			} else {
+				fmt.Fprintf(ctxt.Bso, "\trel %d+%d t=%d %s+%d\n", int(r.Off), r.Siz, r.Type, name, int64(r.Add))
+			}
+		}
+	}
+
+	Bputc(b, 0xfe)
+	wrint(b, int64(s.Type))
+	wrstring(b, s.Name)
+	wrint(b, int64(s.Version))
+	flags := int64(s.Dupok)
+	if s.Local {
+		flags |= 2
+	}
+	wrint(b, flags)
+	wrint(b, s.Size)
+	wrsym(b, s.Gotype)
+	wrdata(b, s.P)
+
+	wrint(b, int64(len(s.R)))
+	var r *Reloc
+	for i := 0; i < len(s.R); i++ {
+		r = &s.R[i]
+		wrint(b, int64(r.Off))
+		wrint(b, int64(r.Siz))
+		wrint(b, int64(r.Type))
+		wrint(b, r.Add)
+		wrint(b, 0) // Xadd, ignored
+		wrsym(b, r.Sym)
+		wrsym(b, nil) // Xsym, ignored
+	}
+
+	if s.Type == STEXT {
+		wrint(b, int64(s.Args))
+		wrint(b, int64(s.Locals))
+		wrint(b, int64(s.Nosplit))
+		wrint(b, int64(s.Leaf)|int64(s.Cfunc)<<1)
+		n := 0
+		for a := s.Autom; a != nil; a = a.Link {
+			n++
+		}
+		wrint(b, int64(n))
+		for a := s.Autom; a != nil; a = a.Link {
+			wrsym(b, a.Asym)
+			wrint(b, int64(a.Aoffset))
+			if a.Name == NAME_AUTO {
+				wrint(b, A_AUTO)
+			} else if a.Name == NAME_PARAM {
+				wrint(b, A_PARAM)
+			} else {
+				log.Fatalf("%s: invalid local variable type %d", s.Name, a.Name)
+			}
+			wrsym(b, a.Gotype)
+		}
+
+		pc := s.Pcln
+		wrdata(b, pc.Pcsp.P)
+		wrdata(b, pc.Pcfile.P)
+		wrdata(b, pc.Pcline.P)
+		wrint(b, int64(len(pc.Pcdata)))
+		for i := 0; i < len(pc.Pcdata); i++ {
+			wrdata(b, pc.Pcdata[i].P)
+		}
+		wrint(b, int64(len(pc.Funcdataoff)))
+		for i := 0; i < len(pc.Funcdataoff); i++ {
+			wrsym(b, pc.Funcdata[i])
+		}
+		for i := 0; i < len(pc.Funcdataoff); i++ {
+			wrint(b, pc.Funcdataoff[i])
+		}
+		wrint(b, int64(len(pc.File)))
+		for i := 0; i < len(pc.File); i++ {
+			wrpathsym(ctxt, b, pc.File[i])
+		}
+	}
+}
+
+// Reusable buffer to avoid allocations.
+// This buffer was responsible for 15% of gc's allocations.
+var varintbuf [10]uint8
+
+func wrint(b *Biobuf, sval int64) {
+	var v uint64
+	uv := (uint64(sval) << 1) ^ uint64(int64(sval>>63))
+	p := varintbuf[:]
+	for v = uv; v >= 0x80; v >>= 7 {
+		p[0] = uint8(v | 0x80)
+		p = p[1:]
+	}
+	p[0] = uint8(v)
+	p = p[1:]
+	b.Write(varintbuf[:len(varintbuf)-len(p)])
+}
+
+func wrstring(b *Biobuf, s string) {
+	wrint(b, int64(len(s)))
+	b.w.WriteString(s)
+}
+
+// wrpath writes a path just like a string, but on windows, it
+// translates '\\' to '/' in the process.
+func wrpath(ctxt *Link, b *Biobuf, p string) {
+	wrstring(b, filepath.ToSlash(p))
+}
+
+func wrdata(b *Biobuf, v []byte) {
+	wrint(b, int64(len(v)))
+	b.Write(v)
+}
+
+func wrpathsym(ctxt *Link, b *Biobuf, s *LSym) {
+	if s == nil {
+		wrint(b, 0)
+		wrint(b, 0)
+		return
+	}
+
+	wrpath(ctxt, b, s.Name)
+	wrint(b, int64(s.Version))
+}
+
+func wrsym(b *Biobuf, s *LSym) {
+	if s == nil {
+		wrint(b, 0)
+		wrint(b, 0)
+		return
+	}
+
+	wrstring(b, s.Name)
+	wrint(b, int64(s.Version))
+}
diff --git a/src/cmd/internal/obj/pass.go b/src/cmd/internal/obj/pass.go
new file mode 100644
index 0000000..b92dfe2
--- /dev/null
+++ b/src/cmd/internal/obj/pass.go
@@ -0,0 +1,216 @@
+// Inferno utils/6l/pass.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/pass.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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 obj
+
+// Code and data passes.
+
+func Brchain(ctxt *Link, p *Prog) *Prog {
+	for i := 0; i < 20; i++ {
+		if p == nil || p.As != AJMP || p.Pcond == nil {
+			return p
+		}
+		p = p.Pcond
+	}
+
+	return nil
+}
+
+func brloop(ctxt *Link, p *Prog) *Prog {
+	var q *Prog
+
+	c := 0
+	for q = p; q != nil; q = q.Pcond {
+		if q.As != AJMP || q.Pcond == nil {
+			break
+		}
+		c++
+		if c >= 5000 {
+			return nil
+		}
+	}
+
+	return q
+}
+
+func checkaddr(ctxt *Link, p *Prog, a *Addr) {
+	// Check expected encoding, especially TYPE_CONST vs TYPE_ADDR.
+	switch a.Type {
+	case TYPE_NONE:
+		return
+
+	case TYPE_BRANCH:
+		if a.Reg != 0 || a.Index != 0 || a.Scale != 0 || a.Name != 0 {
+			break
+		}
+		return
+
+	case TYPE_TEXTSIZE:
+		if a.Reg != 0 || a.Index != 0 || a.Scale != 0 || a.Name != 0 {
+			break
+		}
+		return
+
+		//if(a->u.bits != 0)
+	//	break;
+	case TYPE_MEM:
+		return
+
+		// TODO(rsc): After fixing SHRQ, check a->index != 0 too.
+	case TYPE_CONST:
+		if a.Name != 0 || a.Sym != nil || a.Reg != 0 {
+			ctxt.Diag("argument is TYPE_CONST, should be TYPE_ADDR, in %v", p)
+			return
+		}
+
+		if a.Reg != 0 || a.Scale != 0 || a.Name != 0 || a.Sym != nil || a.Val != nil {
+			break
+		}
+		return
+
+	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
+		}
+		return
+
+	// TODO(rsc): After fixing PINSRQ, check a->offset != 0 too.
+	// TODO(rsc): After fixing SHRQ, check a->index != 0 too.
+	case TYPE_REG:
+		if a.Scale != 0 || a.Name != 0 || a.Sym != nil {
+			break
+		}
+		return
+
+	case TYPE_ADDR:
+		if a.Val != nil {
+			break
+		}
+		if a.Reg == 0 && a.Index == 0 && a.Scale == 0 && a.Name == 0 && a.Sym == nil {
+			ctxt.Diag("argument is TYPE_ADDR, should be TYPE_CONST, in %v", p)
+		}
+		return
+
+	case TYPE_SHIFT:
+		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.Val != nil {
+			break
+		}
+		return
+
+	case TYPE_REGREG2:
+		return
+
+	case TYPE_REGLIST:
+		return
+
+	// 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.Val != nil {
+			break
+		}
+		return
+	}
+
+	ctxt.Diag("invalid encoding for argument %v", p)
+}
+
+func linkpatch(ctxt *Link, sym *LSym) {
+	var c int32
+	var name string
+	var q *Prog
+
+	ctxt.Cursym = sym
+
+	for p := sym.Text; p != nil; p = p.Link {
+		checkaddr(ctxt, p, &p.From)
+		if p.From3 != nil {
+			checkaddr(ctxt, p, p.From3)
+		}
+		checkaddr(ctxt, p, &p.To)
+
+		if ctxt.Arch.Progedit != nil {
+			ctxt.Arch.Progedit(ctxt, p)
+		}
+		if p.To.Type != TYPE_BRANCH {
+			continue
+		}
+		if p.To.Val != nil {
+			// TODO: Remove To.Val.(*Prog) in favor of p->pcond.
+			p.Pcond = p.To.Val.(*Prog)
+			continue
+		}
+
+		if p.To.Sym != nil {
+			continue
+		}
+		c = int32(p.To.Offset)
+		for q = sym.Text; q != nil; {
+			if int64(c) == q.Pc {
+				break
+			}
+			if q.Forwd != nil && int64(c) >= q.Forwd.Pc {
+				q = q.Forwd
+			} else {
+				q = q.Link
+			}
+		}
+
+		if q == nil {
+			name = "<nil>"
+			if p.To.Sym != nil {
+				name = p.To.Sym.Name
+			}
+			ctxt.Diag("branch out of range (%#x)\n%v [%s]", uint32(c), p, name)
+			p.To.Type = TYPE_NONE
+		}
+
+		p.To.Val = q
+		p.Pcond = q
+	}
+
+	for p := sym.Text; p != nil; p = p.Link {
+		p.Mark = 0 /* initialization for follow */
+		if p.Pcond != nil {
+			p.Pcond = brloop(ctxt, p.Pcond)
+			if p.Pcond != nil {
+				if p.To.Type == TYPE_BRANCH {
+					p.To.Offset = p.Pcond.Pc
+				}
+			}
+		}
+	}
+}
diff --git a/src/cmd/internal/obj/pcln.go b/src/cmd/internal/obj/pcln.go
new file mode 100644
index 0000000..91c9293
--- /dev/null
+++ b/src/cmd/internal/obj/pcln.go
@@ -0,0 +1,338 @@
+// 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 obj
+
+import (
+	"fmt"
+	"log"
+)
+
+func addvarint(ctxt *Link, d *Pcdata, val uint32) {
+	var v uint32
+	for v = val; v >= 0x80; v >>= 7 {
+		d.P = append(d.P, uint8(v|0x80))
+	}
+	d.P = append(d.P, uint8(v))
+}
+
+// funcpctab writes to dst a pc-value table mapping the code in func to the values
+// returned by valfunc parameterized by arg. The invocation of valfunc to update the
+// current value is, for each p,
+//
+//	val = valfunc(func, val, p, 0, arg);
+//	record val as value at p->pc;
+//	val = valfunc(func, val, p, 1, arg);
+//
+// where func is the function, val is the current value, p is the instruction being
+// considered, and arg can be used to further parameterize valfunc.
+func funcpctab(ctxt *Link, dst *Pcdata, func_ *LSym, desc string, valfunc func(*Link, *LSym, int32, *Prog, int32, interface{}) int32, arg interface{}) {
+	// To debug a specific function, uncomment second line and change name.
+	dbg := 0
+
+	//dbg = strcmp(func->name, "main.main") == 0;
+	//dbg = strcmp(desc, "pctofile") == 0;
+
+	ctxt.Debugpcln += int32(dbg)
+
+	dst.P = dst.P[:0]
+
+	if ctxt.Debugpcln != 0 {
+		fmt.Fprintf(ctxt.Bso, "funcpctab %s [valfunc=%s]\n", func_.Name, desc)
+	}
+
+	val := int32(-1)
+	oldval := val
+	if func_.Text == nil {
+		ctxt.Debugpcln -= int32(dbg)
+		return
+	}
+
+	pc := func_.Text.Pc
+
+	if ctxt.Debugpcln != 0 {
+		fmt.Fprintf(ctxt.Bso, "%6x %6d %v\n", uint64(pc), val, func_.Text)
+	}
+
+	started := int32(0)
+	var delta uint32
+	for p := func_.Text; p != nil; p = p.Link {
+		// Update val. If it's not changing, keep going.
+		val = valfunc(ctxt, func_, val, p, 0, arg)
+
+		if val == oldval && started != 0 {
+			val = valfunc(ctxt, func_, val, p, 1, arg)
+			if ctxt.Debugpcln != 0 {
+				fmt.Fprintf(ctxt.Bso, "%6x %6s %v\n", uint64(int64(p.Pc)), "", p)
+			}
+			continue
+		}
+
+		// If the pc of the next instruction is the same as the
+		// pc of this instruction, this instruction is not a real
+		// instruction. Keep going, so that we only emit a delta
+		// for a true instruction boundary in the program.
+		if p.Link != nil && p.Link.Pc == p.Pc {
+			val = valfunc(ctxt, func_, val, p, 1, arg)
+			if ctxt.Debugpcln != 0 {
+				fmt.Fprintf(ctxt.Bso, "%6x %6s %v\n", uint64(int64(p.Pc)), "", p)
+			}
+			continue
+		}
+
+		// The table is a sequence of (value, pc) pairs, where each
+		// pair states that the given value is in effect from the current position
+		// up to the given pc, which becomes the new current position.
+		// To generate the table as we scan over the program instructions,
+		// we emit a "(value" when pc == func->value, and then
+		// each time we observe a change in value we emit ", pc) (value".
+		// When the scan is over, we emit the closing ", pc)".
+		//
+		// The table is delta-encoded. The value deltas are signed and
+		// transmitted in zig-zag form, where a complement bit is placed in bit 0,
+		// and the pc deltas are unsigned. Both kinds of deltas are sent
+		// as variable-length little-endian base-128 integers,
+		// where the 0x80 bit indicates that the integer continues.
+
+		if ctxt.Debugpcln != 0 {
+			fmt.Fprintf(ctxt.Bso, "%6x %6d %v\n", uint64(int64(p.Pc)), val, p)
+		}
+
+		if started != 0 {
+			addvarint(ctxt, dst, uint32((p.Pc-pc)/int64(ctxt.Arch.Minlc)))
+			pc = p.Pc
+		}
+
+		delta = uint32(val) - uint32(oldval)
+		if delta>>31 != 0 {
+			delta = 1 | ^(delta << 1)
+		} else {
+			delta <<= 1
+		}
+		addvarint(ctxt, dst, delta)
+		oldval = val
+		started = 1
+		val = valfunc(ctxt, func_, val, p, 1, arg)
+	}
+
+	if started != 0 {
+		if ctxt.Debugpcln != 0 {
+			fmt.Fprintf(ctxt.Bso, "%6x done\n", uint64(int64(func_.Text.Pc)+func_.Size))
+		}
+		addvarint(ctxt, dst, uint32((func_.Value+func_.Size-pc)/int64(ctxt.Arch.Minlc)))
+		addvarint(ctxt, dst, 0) // terminator
+	}
+
+	if ctxt.Debugpcln != 0 {
+		fmt.Fprintf(ctxt.Bso, "wrote %d bytes to %p\n", len(dst.P), dst)
+		for i := 0; i < len(dst.P); i++ {
+			fmt.Fprintf(ctxt.Bso, " %02x", dst.P[i])
+		}
+		fmt.Fprintf(ctxt.Bso, "\n")
+	}
+
+	ctxt.Debugpcln -= int32(dbg)
+}
+
+// pctofileline computes either the file number (arg == 0)
+// or the line number (arg == 1) to use at p.
+// Because p->lineno applies to p, phase == 0 (before p)
+// takes care of the update.
+func pctofileline(ctxt *Link, sym *LSym, oldval int32, p *Prog, phase int32, arg interface{}) int32 {
+	if p.As == ATEXT || p.As == ANOP || p.As == AUSEFIELD || p.Lineno == 0 || phase == 1 {
+		return oldval
+	}
+	var l int32
+	var f *LSym
+	linkgetline(ctxt, p.Lineno, &f, &l)
+	if f == nil {
+		//	print("getline failed for %s %v\n", ctxt->cursym->name, p);
+		return oldval
+	}
+
+	if arg == nil {
+		return l
+	}
+	pcln := arg.(*Pcln)
+
+	if f == pcln.Lastfile {
+		return int32(pcln.Lastindex)
+	}
+
+	var i int32
+	for i = 0; i < int32(len(pcln.File)); i++ {
+		file := pcln.File[i]
+		if file == f {
+			pcln.Lastfile = f
+			pcln.Lastindex = int(i)
+			return int32(i)
+		}
+	}
+	pcln.File = append(pcln.File, f)
+	pcln.Lastfile = f
+	pcln.Lastindex = int(i)
+	return i
+}
+
+// pctospadj computes the sp adjustment in effect.
+// It is oldval plus any adjustment made by p itself.
+// The adjustment by p takes effect only after p, so we
+// apply the change during phase == 1.
+func pctospadj(ctxt *Link, sym *LSym, oldval int32, p *Prog, phase int32, arg interface{}) int32 {
+	if oldval == -1 { // starting
+		oldval = 0
+	}
+	if phase == 0 {
+		return oldval
+	}
+	if oldval+p.Spadj < -10000 || oldval+p.Spadj > 1100000000 {
+		ctxt.Diag("overflow in spadj: %d + %d = %d", oldval, p.Spadj, oldval+p.Spadj)
+		log.Fatalf("bad code")
+	}
+
+	return oldval + p.Spadj
+}
+
+// pctopcdata computes the pcdata value in effect at p.
+// A PCDATA instruction sets the value in effect at future
+// non-PCDATA instructions.
+// Since PCDATA instructions have no width in the final code,
+// it does not matter which phase we use for the update.
+func pctopcdata(ctxt *Link, sym *LSym, oldval int32, p *Prog, phase int32, arg interface{}) int32 {
+	if phase == 0 || p.As != APCDATA || p.From.Offset != int64(arg.(uint32)) {
+		return oldval
+	}
+	if int64(int32(p.To.Offset)) != p.To.Offset {
+		ctxt.Diag("overflow in PCDATA instruction: %v", p)
+		log.Fatalf("bad code")
+	}
+
+	return int32(p.To.Offset)
+}
+
+func linkpcln(ctxt *Link, cursym *LSym) {
+	ctxt.Cursym = cursym
+
+	pcln := new(Pcln)
+	cursym.Pcln = pcln
+
+	npcdata := 0
+	nfuncdata := 0
+	for p := cursym.Text; p != nil; p = p.Link {
+		if p.As == APCDATA && p.From.Offset >= int64(npcdata) {
+			npcdata = int(p.From.Offset + 1)
+		}
+		if p.As == AFUNCDATA && p.From.Offset >= int64(nfuncdata) {
+			nfuncdata = int(p.From.Offset + 1)
+		}
+	}
+
+	pcln.Pcdata = make([]Pcdata, npcdata)
+	pcln.Pcdata = pcln.Pcdata[:npcdata]
+	pcln.Funcdata = make([]*LSym, nfuncdata)
+	pcln.Funcdataoff = make([]int64, nfuncdata)
+	pcln.Funcdataoff = pcln.Funcdataoff[:nfuncdata]
+
+	funcpctab(ctxt, &pcln.Pcsp, cursym, "pctospadj", pctospadj, nil)
+	funcpctab(ctxt, &pcln.Pcfile, cursym, "pctofile", pctofileline, pcln)
+	funcpctab(ctxt, &pcln.Pcline, cursym, "pctoline", pctofileline, nil)
+
+	// tabulate which pc and func data we have.
+	havepc := make([]uint32, (npcdata+31)/32)
+	havefunc := make([]uint32, (nfuncdata+31)/32)
+	for p := cursym.Text; p != nil; p = p.Link {
+		if p.As == AFUNCDATA {
+			if (havefunc[p.From.Offset/32]>>uint64(p.From.Offset%32))&1 != 0 {
+				ctxt.Diag("multiple definitions for FUNCDATA $%d", p.From.Offset)
+			}
+			havefunc[p.From.Offset/32] |= 1 << uint64(p.From.Offset%32)
+		}
+
+		if p.As == APCDATA {
+			havepc[p.From.Offset/32] |= 1 << uint64(p.From.Offset%32)
+		}
+	}
+
+	// pcdata.
+	for i := 0; i < npcdata; i++ {
+		if (havepc[i/32]>>uint(i%32))&1 == 0 {
+			continue
+		}
+		funcpctab(ctxt, &pcln.Pcdata[i], cursym, "pctopcdata", pctopcdata, interface{}(uint32(i)))
+	}
+
+	// funcdata
+	if nfuncdata > 0 {
+		var i int
+		for p := cursym.Text; p != nil; p = p.Link {
+			if p.As == AFUNCDATA {
+				i = int(p.From.Offset)
+				pcln.Funcdataoff[i] = p.To.Offset
+				if p.To.Type != TYPE_CONST {
+					// TODO: Dedup.
+					//funcdata_bytes += p->to.sym->size;
+					pcln.Funcdata[i] = p.To.Sym
+				}
+			}
+		}
+	}
+}
+
+// iteration over encoded pcdata tables.
+
+func getvarint(pp *[]byte) uint32 {
+	v := uint32(0)
+	p := *pp
+	for shift := 0; ; shift += 7 {
+		v |= uint32(p[0]&0x7F) << uint(shift)
+		tmp7 := p
+		p = p[1:]
+		if tmp7[0]&0x80 == 0 {
+			break
+		}
+	}
+
+	*pp = p
+	return v
+}
+
+func pciternext(it *Pciter) {
+	it.pc = it.nextpc
+	if it.done != 0 {
+		return
+	}
+	if -cap(it.p) >= -cap(it.d.P[len(it.d.P):]) {
+		it.done = 1
+		return
+	}
+
+	// value delta
+	v := getvarint(&it.p)
+
+	if v == 0 && it.start == 0 {
+		it.done = 1
+		return
+	}
+
+	it.start = 0
+	dv := int32(v>>1) ^ (int32(v<<31) >> 31)
+	it.value += dv
+
+	// pc delta
+	v = getvarint(&it.p)
+
+	it.nextpc = it.pc + v*it.pcscale
+}
+
+func pciterinit(ctxt *Link, it *Pciter, d *Pcdata) {
+	it.d = *d
+	it.p = it.d.P
+	it.pc = 0
+	it.nextpc = 0
+	it.value = -1
+	it.start = 1
+	it.done = 0
+	it.pcscale = uint32(ctxt.Arch.Minlc)
+	pciternext(it)
+}
diff --git a/src/cmd/internal/obj/ppc64/a.out.go b/src/cmd/internal/obj/ppc64/a.out.go
new file mode 100644
index 0000000..3028b6c
--- /dev/null
+++ b/src/cmd/internal/obj/ppc64/a.out.go
@@ -0,0 +1,538 @@
+// cmd/9c/9.out.h from Vita Nuova.
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
+
+package ppc64
+
+import "cmd/internal/obj"
+
+//go:generate go run ../stringer.go -i $GOFILE -o anames.go -p ppc64
+
+/*
+ * powerpc 64
+ */
+const (
+	NSNAME = 8
+	NSYM   = 50
+	NREG   = 32 /* number of general registers */
+	NFREG  = 32 /* number of floating point registers */
+)
+
+const (
+	REG_R0 = obj.RBasePPC64 + 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
+
+	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
+
+	REG_CR0
+	REG_CR1
+	REG_CR2
+	REG_CR3
+	REG_CR4
+	REG_CR5
+	REG_CR6
+	REG_CR7
+
+	REG_MSR
+	REG_FPSCR
+	REG_CR
+
+	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      /* -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 /* external registers allocated from here down */
+	REGG     = REG_R30 /* G */
+	REGTMP   = REG_R31 /* used by the linker */
+	FREGRET  = REG_F0
+	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 */
+)
+
+/*
+ * GENERAL:
+ *
+ * compiler allocates R3 up as temps
+ * compiler allocates register variables R7-R27
+ * compiler allocates external registers R30 down
+ *
+ * compiler allocates register variables F17-F26
+ * compiler allocates external registers F26 down
+ */
+const (
+	BIG = 32768 - 8
+)
+
+const (
+	/* mark flags */
+	LABEL   = 1 << 0
+	LEAF    = 1 << 1
+	FLOAT   = 1 << 2
+	BRANCH  = 1 << 3
+	LOAD    = 1 << 4
+	FCMP    = 1 << 5
+	SYNC    = 1 << 6
+	LIST    = 1 << 7
+	FOLL    = 1 << 8
+	NOSCHED = 1 << 9
+)
+
+const (
+	C_NONE = iota
+	C_REG
+	C_FREG
+	C_CREG
+	C_SPR /* special processor register */
+	C_ZCON
+	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 /* $n(REG) where int16 < n <= int32 */
+	C_LECON
+	C_DACON /* $n(REG) where int32 < n */
+	C_SBRA
+	C_LBRA
+	C_SAUTO
+	C_LAUTO
+	C_SEXT
+	C_LEXT
+	C_ZOREG
+	C_SOREG
+	C_LOREG
+	C_FPSCR
+	C_MSR
+	C_XER
+	C_LR
+	C_CTR
+	C_ANY
+	C_GOK
+	C_ADDR
+	C_TEXTSIZE
+
+	C_NCLASS /* must be the last */
+)
+
+const (
+	AADD = obj.ABasePPC64 + obj.A_ARCHSPECIFIC + iota
+	AADDCC
+	AADDV
+	AADDVCC
+	AADDC
+	AADDCCC
+	AADDCV
+	AADDCVCC
+	AADDME
+	AADDMECC
+	AADDMEVCC
+	AADDMEV
+	AADDE
+	AADDECC
+	AADDEVCC
+	AADDEV
+	AADDZE
+	AADDZECC
+	AADDZEVCC
+	AADDZEV
+	AAND
+	AANDCC
+	AANDN
+	AANDNCC
+	ABC
+	ABCL
+	ABEQ
+	ABGE
+	ABGT
+	ABLE
+	ABLT
+	ABNE
+	ABVC
+	ABVS
+	ACMP
+	ACMPU
+	ACNTLZW
+	ACNTLZWCC
+	ACRAND
+	ACRANDN
+	ACREQV
+	ACRNAND
+	ACRNOR
+	ACROR
+	ACRORN
+	ACRXOR
+	ADIVW
+	ADIVWCC
+	ADIVWVCC
+	ADIVWV
+	ADIVWU
+	ADIVWUCC
+	ADIVWUVCC
+	ADIVWUV
+	AEQV
+	AEQVCC
+	AEXTSB
+	AEXTSBCC
+	AEXTSH
+	AEXTSHCC
+	AFABS
+	AFABSCC
+	AFADD
+	AFADDCC
+	AFADDS
+	AFADDSCC
+	AFCMPO
+	AFCMPU
+	AFCTIW
+	AFCTIWCC
+	AFCTIWZ
+	AFCTIWZCC
+	AFDIV
+	AFDIVCC
+	AFDIVS
+	AFDIVSCC
+	AFMADD
+	AFMADDCC
+	AFMADDS
+	AFMADDSCC
+	AFMOVD
+	AFMOVDCC
+	AFMOVDU
+	AFMOVS
+	AFMOVSU
+	AFMSUB
+	AFMSUBCC
+	AFMSUBS
+	AFMSUBSCC
+	AFMUL
+	AFMULCC
+	AFMULS
+	AFMULSCC
+	AFNABS
+	AFNABSCC
+	AFNEG
+	AFNEGCC
+	AFNMADD
+	AFNMADDCC
+	AFNMADDS
+	AFNMADDSCC
+	AFNMSUB
+	AFNMSUBCC
+	AFNMSUBS
+	AFNMSUBSCC
+	AFRSP
+	AFRSPCC
+	AFSUB
+	AFSUBCC
+	AFSUBS
+	AFSUBSCC
+	AMOVMW
+	ALSW
+	ALWAR
+	AMOVWBR
+	AMOVB
+	AMOVBU
+	AMOVBZ
+	AMOVBZU
+	AMOVH
+	AMOVHBR
+	AMOVHU
+	AMOVHZ
+	AMOVHZU
+	AMOVW
+	AMOVWU
+	AMOVFL
+	AMOVCRFS
+	AMTFSB0
+	AMTFSB0CC
+	AMTFSB1
+	AMTFSB1CC
+	AMULHW
+	AMULHWCC
+	AMULHWU
+	AMULHWUCC
+	AMULLW
+	AMULLWCC
+	AMULLWVCC
+	AMULLWV
+	ANAND
+	ANANDCC
+	ANEG
+	ANEGCC
+	ANEGVCC
+	ANEGV
+	ANOR
+	ANORCC
+	AOR
+	AORCC
+	AORN
+	AORNCC
+	AREM
+	AREMCC
+	AREMV
+	AREMVCC
+	AREMU
+	AREMUCC
+	AREMUV
+	AREMUVCC
+	ARFI
+	ARLWMI
+	ARLWMICC
+	ARLWNM
+	ARLWNMCC
+	ASLW
+	ASLWCC
+	ASRW
+	ASRAW
+	ASRAWCC
+	ASRWCC
+	ASTSW
+	ASTWCCC
+	ASUB
+	ASUBCC
+	ASUBVCC
+	ASUBC
+	ASUBCCC
+	ASUBCV
+	ASUBCVCC
+	ASUBME
+	ASUBMECC
+	ASUBMEVCC
+	ASUBMEV
+	ASUBV
+	ASUBE
+	ASUBECC
+	ASUBEV
+	ASUBEVCC
+	ASUBZE
+	ASUBZECC
+	ASUBZEVCC
+	ASUBZEV
+	ASYNC
+	AXOR
+	AXORCC
+
+	ADCBF
+	ADCBI
+	ADCBST
+	ADCBT
+	ADCBTST
+	ADCBZ
+	AECIWX
+	AECOWX
+	AEIEIO
+	AICBI
+	AISYNC
+	APTESYNC
+	ATLBIE
+	ATLBIEL
+	ATLBSYNC
+	ATW
+
+	ASYSCALL
+	AWORD
+
+	ARFCI
+
+	/* optional on 32-bit */
+	AFRES
+	AFRESCC
+	AFRSQRTE
+	AFRSQRTECC
+	AFSEL
+	AFSELCC
+	AFSQRT
+	AFSQRTCC
+	AFSQRTS
+	AFSQRTSCC
+
+	/* 64-bit */
+
+	ACNTLZD
+	ACNTLZDCC
+	ACMPW /* CMP with L=0 */
+	ACMPWU
+	ADIVD
+	ADIVDCC
+	ADIVDVCC
+	ADIVDV
+	ADIVDU
+	ADIVDUCC
+	ADIVDUVCC
+	ADIVDUV
+	AEXTSW
+	AEXTSWCC
+	/* AFCFIW; AFCFIWCC */
+	AFCFID
+	AFCFIDCC
+	AFCTID
+	AFCTIDCC
+	AFCTIDZ
+	AFCTIDZCC
+	ALDAR
+	AMOVD
+	AMOVDU
+	AMOVWZ
+	AMOVWZU
+	AMULHD
+	AMULHDCC
+	AMULHDU
+	AMULHDUCC
+	AMULLD
+	AMULLDCC
+	AMULLDVCC
+	AMULLDV
+	ARFID
+	ARLDMI
+	ARLDMICC
+	ARLDC
+	ARLDCCC
+	ARLDCR
+	ARLDCRCC
+	ARLDCL
+	ARLDCLCC
+	ASLBIA
+	ASLBIE
+	ASLBMFEE
+	ASLBMFEV
+	ASLBMTE
+	ASLD
+	ASLDCC
+	ASRD
+	ASRAD
+	ASRADCC
+	ASRDCC
+	ASTDCCC
+	ATD
+
+	/* 64-bit pseudo operation */
+	ADWORD
+	AREMD
+	AREMDCC
+	AREMDV
+	AREMDVCC
+	AREMDU
+	AREMDUCC
+	AREMDUV
+	AREMDUVCC
+
+	/* more 64-bit operations */
+	AHRFID
+
+	ALAST
+
+	// aliases
+	ABR = obj.AJMP
+	ABL = obj.ACALL
+)
diff --git a/src/cmd/internal/obj/ppc64/anames.go b/src/cmd/internal/obj/ppc64/anames.go
new file mode 100644
index 0000000..1ae7a52
--- /dev/null
+++ b/src/cmd/internal/obj/ppc64/anames.go
@@ -0,0 +1,300 @@
+// Generated by stringer -i a.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
new file mode 100644
index 0000000..b48e516
--- /dev/null
+++ b/src/cmd/internal/obj/ppc64/anames9.go
@@ -0,0 +1,40 @@
+package ppc64
+
+var cnames9 = []string{
+	"NONE",
+	"REG",
+	"FREG",
+	"CREG",
+	"SPR",
+	"ZCON",
+	"SCON",
+	"UCON",
+	"ADDCON",
+	"ANDCON",
+	"LCON",
+	"DCON",
+	"SACON",
+	"SECON",
+	"LACON",
+	"LECON",
+	"DACON",
+	"SBRA",
+	"LBRA",
+	"SAUTO",
+	"LAUTO",
+	"SEXT",
+	"LEXT",
+	"ZOREG",
+	"SOREG",
+	"LOREG",
+	"FPSCR",
+	"MSR",
+	"XER",
+	"LR",
+	"CTR",
+	"ANY",
+	"GOK",
+	"ADDR",
+	"TEXTSIZE",
+	"NCLASS",
+}
diff --git a/src/cmd/internal/obj/ppc64/asm9.go b/src/cmd/internal/obj/ppc64/asm9.go
new file mode 100644
index 0000000..2955a00
--- /dev/null
+++ b/src/cmd/internal/obj/ppc64/asm9.go
@@ -0,0 +1,3247 @@
+// cmd/9l/optab.c, cmd/9l/asmout.c from Vita Nuova.
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
+
+package ppc64
+
+import (
+	"cmd/internal/obj"
+	"encoding/binary"
+	"fmt"
+	"log"
+	"sort"
+)
+
+// Instruction layout.
+
+const (
+	FuncAlign = 8
+)
+
+const (
+	r0iszero = 1
+)
+
+type Optab struct {
+	as    int16
+	a1    uint8
+	a2    uint8
+	a3    uint8
+	a4    uint8
+	type_ int8
+	size  int8
+	param int16
+}
+
+var optab = []Optab{
+	Optab{obj.ATEXT, C_LEXT, C_NONE, C_NONE, C_TEXTSIZE, 0, 0, 0},
+	Optab{obj.ATEXT, C_LEXT, C_NONE, C_LCON, C_TEXTSIZE, 0, 0, 0},
+	Optab{obj.ATEXT, C_ADDR, C_NONE, C_NONE, C_TEXTSIZE, 0, 0, 0},
+	Optab{obj.ATEXT, C_ADDR, C_NONE, C_LCON, C_TEXTSIZE, 0, 0, 0},
+	/* move register */
+	Optab{AMOVD, C_REG, C_NONE, C_NONE, C_REG, 1, 4, 0},
+	Optab{AMOVB, C_REG, C_NONE, C_NONE, C_REG, 12, 4, 0},
+	Optab{AMOVBZ, C_REG, C_NONE, C_NONE, C_REG, 13, 4, 0},
+	Optab{AMOVW, C_REG, C_NONE, C_NONE, C_REG, 12, 4, 0},
+	Optab{AMOVWZ, C_REG, C_NONE, C_NONE, C_REG, 13, 4, 0},
+	Optab{AADD, C_REG, C_REG, C_NONE, C_REG, 2, 4, 0},
+	Optab{AADD, C_REG, C_NONE, C_NONE, C_REG, 2, 4, 0},
+	Optab{AADD, C_ADDCON, C_REG, C_NONE, C_REG, 4, 4, 0},
+	Optab{AADD, C_ADDCON, C_NONE, C_NONE, C_REG, 4, 4, 0},
+	Optab{AADD, C_UCON, C_REG, C_NONE, C_REG, 20, 4, 0},
+	Optab{AADD, C_UCON, C_NONE, C_NONE, C_REG, 20, 4, 0},
+	Optab{AADD, C_LCON, C_REG, C_NONE, C_REG, 22, 12, 0},
+	Optab{AADD, C_LCON, C_NONE, C_NONE, C_REG, 22, 12, 0},
+	Optab{AADDC, C_REG, C_REG, C_NONE, C_REG, 2, 4, 0},
+	Optab{AADDC, C_REG, C_NONE, C_NONE, C_REG, 2, 4, 0},
+	Optab{AADDC, C_ADDCON, C_REG, C_NONE, C_REG, 4, 4, 0},
+	Optab{AADDC, C_ADDCON, C_NONE, C_NONE, C_REG, 4, 4, 0},
+	Optab{AADDC, C_LCON, C_REG, C_NONE, C_REG, 22, 12, 0},
+	Optab{AADDC, C_LCON, C_NONE, C_NONE, C_REG, 22, 12, 0},
+	Optab{AAND, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0}, /* logical, no literal */
+	Optab{AAND, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0},
+	Optab{AANDCC, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0},
+	Optab{AANDCC, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0},
+	Optab{AANDCC, C_ANDCON, C_NONE, C_NONE, C_REG, 58, 4, 0},
+	Optab{AANDCC, C_ANDCON, C_REG, C_NONE, C_REG, 58, 4, 0},
+	Optab{AANDCC, C_UCON, C_NONE, C_NONE, C_REG, 59, 4, 0},
+	Optab{AANDCC, C_UCON, C_REG, C_NONE, C_REG, 59, 4, 0},
+	Optab{AANDCC, C_LCON, C_NONE, C_NONE, C_REG, 23, 12, 0},
+	Optab{AANDCC, C_LCON, C_REG, C_NONE, C_REG, 23, 12, 0},
+	Optab{AMULLW, C_REG, C_REG, C_NONE, C_REG, 2, 4, 0},
+	Optab{AMULLW, C_REG, C_NONE, C_NONE, C_REG, 2, 4, 0},
+	Optab{AMULLW, C_ADDCON, C_REG, C_NONE, C_REG, 4, 4, 0},
+	Optab{AMULLW, C_ADDCON, C_NONE, C_NONE, C_REG, 4, 4, 0},
+	Optab{AMULLW, C_ANDCON, C_REG, C_NONE, C_REG, 4, 4, 0},
+	Optab{AMULLW, C_ANDCON, C_NONE, C_NONE, C_REG, 4, 4, 0},
+	Optab{AMULLW, C_LCON, C_REG, C_NONE, C_REG, 22, 12, 0},
+	Optab{AMULLW, C_LCON, C_NONE, C_NONE, C_REG, 22, 12, 0},
+	Optab{ASUBC, C_REG, C_REG, C_NONE, C_REG, 10, 4, 0},
+	Optab{ASUBC, C_REG, C_NONE, C_NONE, C_REG, 10, 4, 0},
+	Optab{ASUBC, C_REG, C_NONE, C_ADDCON, C_REG, 27, 4, 0},
+	Optab{ASUBC, C_REG, C_NONE, C_LCON, C_REG, 28, 12, 0},
+	Optab{AOR, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0}, /* logical, literal not cc (or/xor) */
+	Optab{AOR, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0},
+	Optab{AOR, C_ANDCON, C_NONE, C_NONE, C_REG, 58, 4, 0},
+	Optab{AOR, C_ANDCON, C_REG, C_NONE, C_REG, 58, 4, 0},
+	Optab{AOR, C_UCON, C_NONE, C_NONE, C_REG, 59, 4, 0},
+	Optab{AOR, C_UCON, C_REG, C_NONE, C_REG, 59, 4, 0},
+	Optab{AOR, C_LCON, C_NONE, C_NONE, C_REG, 23, 12, 0},
+	Optab{AOR, C_LCON, C_REG, C_NONE, C_REG, 23, 12, 0},
+	Optab{ADIVW, C_REG, C_REG, C_NONE, C_REG, 2, 4, 0}, /* op r1[,r2],r3 */
+	Optab{ADIVW, C_REG, C_NONE, C_NONE, C_REG, 2, 4, 0},
+	Optab{ASUB, C_REG, C_REG, C_NONE, C_REG, 10, 4, 0}, /* op r2[,r1],r3 */
+	Optab{ASUB, C_REG, C_NONE, C_NONE, C_REG, 10, 4, 0},
+	Optab{ASLW, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0},
+	Optab{ASLW, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0},
+	Optab{ASLD, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0},
+	Optab{ASLD, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0},
+	Optab{ASLD, C_SCON, C_REG, C_NONE, C_REG, 25, 4, 0},
+	Optab{ASLD, C_SCON, C_NONE, C_NONE, C_REG, 25, 4, 0},
+	Optab{ASLW, C_SCON, C_REG, C_NONE, C_REG, 57, 4, 0},
+	Optab{ASLW, C_SCON, C_NONE, C_NONE, C_REG, 57, 4, 0},
+	Optab{ASRAW, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0},
+	Optab{ASRAW, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0},
+	Optab{ASRAW, C_SCON, C_REG, C_NONE, C_REG, 56, 4, 0},
+	Optab{ASRAW, C_SCON, C_NONE, C_NONE, C_REG, 56, 4, 0},
+	Optab{ASRAD, C_REG, C_NONE, C_NONE, C_REG, 6, 4, 0},
+	Optab{ASRAD, C_REG, C_REG, C_NONE, C_REG, 6, 4, 0},
+	Optab{ASRAD, C_SCON, C_REG, C_NONE, C_REG, 56, 4, 0},
+	Optab{ASRAD, C_SCON, C_NONE, C_NONE, C_REG, 56, 4, 0},
+	Optab{ARLWMI, C_SCON, C_REG, C_LCON, C_REG, 62, 4, 0},
+	Optab{ARLWMI, C_REG, C_REG, C_LCON, C_REG, 63, 4, 0},
+	Optab{ARLDMI, C_SCON, C_REG, C_LCON, C_REG, 30, 4, 0},
+	Optab{ARLDC, C_SCON, C_REG, C_LCON, C_REG, 29, 4, 0},
+	Optab{ARLDCL, C_SCON, C_REG, C_LCON, C_REG, 29, 4, 0},
+	Optab{ARLDCL, C_REG, C_REG, C_LCON, C_REG, 14, 4, 0},
+	Optab{ARLDCL, C_REG, C_NONE, C_LCON, C_REG, 14, 4, 0},
+	Optab{AFADD, C_FREG, C_NONE, C_NONE, C_FREG, 2, 4, 0},
+	Optab{AFADD, C_FREG, C_REG, C_NONE, C_FREG, 2, 4, 0},
+	Optab{AFABS, C_FREG, C_NONE, C_NONE, C_FREG, 33, 4, 0},
+	Optab{AFABS, C_NONE, C_NONE, C_NONE, C_FREG, 33, 4, 0},
+	Optab{AFMOVD, C_FREG, C_NONE, C_NONE, C_FREG, 33, 4, 0},
+	Optab{AFMADD, C_FREG, C_REG, C_FREG, C_FREG, 34, 4, 0},
+	Optab{AFMUL, C_FREG, C_NONE, C_NONE, C_FREG, 32, 4, 0},
+	Optab{AFMUL, C_FREG, C_REG, C_NONE, C_FREG, 32, 4, 0},
+
+	/* store, short offset */
+	Optab{AMOVD, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO},
+	Optab{AMOVW, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO},
+	Optab{AMOVWZ, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO},
+	Optab{AMOVBZ, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO},
+	Optab{AMOVBZU, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO},
+	Optab{AMOVB, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO},
+	Optab{AMOVBU, C_REG, C_REG, C_NONE, C_ZOREG, 7, 4, REGZERO},
+	Optab{AMOVD, C_REG, C_NONE, C_NONE, C_SEXT, 7, 4, REGSB},
+	Optab{AMOVW, C_REG, C_NONE, C_NONE, C_SEXT, 7, 4, REGSB},
+	Optab{AMOVWZ, C_REG, C_NONE, C_NONE, C_SEXT, 7, 4, REGSB},
+	Optab{AMOVBZ, C_REG, C_NONE, C_NONE, C_SEXT, 7, 4, REGSB},
+	Optab{AMOVB, C_REG, C_NONE, C_NONE, C_SEXT, 7, 4, REGSB},
+	Optab{AMOVD, C_REG, C_NONE, C_NONE, C_SAUTO, 7, 4, REGSP},
+	Optab{AMOVW, C_REG, C_NONE, C_NONE, C_SAUTO, 7, 4, REGSP},
+	Optab{AMOVWZ, C_REG, C_NONE, C_NONE, C_SAUTO, 7, 4, REGSP},
+	Optab{AMOVBZ, C_REG, C_NONE, C_NONE, C_SAUTO, 7, 4, REGSP},
+	Optab{AMOVB, C_REG, C_NONE, C_NONE, C_SAUTO, 7, 4, REGSP},
+	Optab{AMOVD, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO},
+	Optab{AMOVW, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO},
+	Optab{AMOVWZ, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO},
+	Optab{AMOVBZ, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO},
+	Optab{AMOVBZU, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO},
+	Optab{AMOVB, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO},
+	Optab{AMOVBU, C_REG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO},
+
+	/* load, short offset */
+	Optab{AMOVD, C_ZOREG, C_REG, C_NONE, C_REG, 8, 4, REGZERO},
+	Optab{AMOVW, C_ZOREG, C_REG, C_NONE, C_REG, 8, 4, REGZERO},
+	Optab{AMOVWZ, C_ZOREG, C_REG, C_NONE, C_REG, 8, 4, REGZERO},
+	Optab{AMOVBZ, C_ZOREG, C_REG, C_NONE, C_REG, 8, 4, REGZERO},
+	Optab{AMOVBZU, C_ZOREG, C_REG, C_NONE, C_REG, 8, 4, REGZERO},
+	Optab{AMOVB, C_ZOREG, C_REG, C_NONE, C_REG, 9, 8, REGZERO},
+	Optab{AMOVBU, C_ZOREG, C_REG, C_NONE, C_REG, 9, 8, REGZERO},
+	Optab{AMOVD, C_SEXT, C_NONE, C_NONE, C_REG, 8, 4, REGSB},
+	Optab{AMOVW, C_SEXT, C_NONE, C_NONE, C_REG, 8, 4, REGSB},
+	Optab{AMOVWZ, C_SEXT, C_NONE, C_NONE, C_REG, 8, 4, REGSB},
+	Optab{AMOVBZ, C_SEXT, C_NONE, C_NONE, C_REG, 8, 4, REGSB},
+	Optab{AMOVB, C_SEXT, C_NONE, C_NONE, C_REG, 9, 8, REGSB},
+	Optab{AMOVD, C_SAUTO, C_NONE, C_NONE, C_REG, 8, 4, REGSP},
+	Optab{AMOVW, C_SAUTO, C_NONE, C_NONE, C_REG, 8, 4, REGSP},
+	Optab{AMOVWZ, C_SAUTO, C_NONE, C_NONE, C_REG, 8, 4, REGSP},
+	Optab{AMOVBZ, C_SAUTO, C_NONE, C_NONE, C_REG, 8, 4, REGSP},
+	Optab{AMOVB, C_SAUTO, C_NONE, C_NONE, C_REG, 9, 8, REGSP},
+	Optab{AMOVD, C_SOREG, C_NONE, C_NONE, C_REG, 8, 4, REGZERO},
+	Optab{AMOVW, C_SOREG, C_NONE, C_NONE, C_REG, 8, 4, REGZERO},
+	Optab{AMOVWZ, C_SOREG, C_NONE, C_NONE, C_REG, 8, 4, REGZERO},
+	Optab{AMOVBZ, C_SOREG, C_NONE, C_NONE, C_REG, 8, 4, REGZERO},
+	Optab{AMOVBZU, C_SOREG, C_NONE, C_NONE, C_REG, 8, 4, REGZERO},
+	Optab{AMOVB, C_SOREG, C_NONE, C_NONE, C_REG, 9, 8, REGZERO},
+	Optab{AMOVBU, C_SOREG, C_NONE, C_NONE, C_REG, 9, 8, REGZERO},
+
+	/* store, long offset */
+	Optab{AMOVD, C_REG, C_NONE, C_NONE, C_LEXT, 35, 8, REGSB},
+	Optab{AMOVW, C_REG, C_NONE, C_NONE, C_LEXT, 35, 8, REGSB},
+	Optab{AMOVWZ, C_REG, C_NONE, C_NONE, C_LEXT, 35, 8, REGSB},
+	Optab{AMOVBZ, C_REG, C_NONE, C_NONE, C_LEXT, 35, 8, REGSB},
+	Optab{AMOVB, C_REG, C_NONE, C_NONE, C_LEXT, 35, 8, REGSB},
+	Optab{AMOVD, C_REG, C_NONE, C_NONE, C_LAUTO, 35, 8, REGSP},
+	Optab{AMOVW, C_REG, C_NONE, C_NONE, C_LAUTO, 35, 8, REGSP},
+	Optab{AMOVWZ, C_REG, C_NONE, C_NONE, C_LAUTO, 35, 8, REGSP},
+	Optab{AMOVBZ, C_REG, C_NONE, C_NONE, C_LAUTO, 35, 8, REGSP},
+	Optab{AMOVB, C_REG, C_NONE, C_NONE, C_LAUTO, 35, 8, REGSP},
+	Optab{AMOVD, C_REG, C_NONE, C_NONE, C_LOREG, 35, 8, REGZERO},
+	Optab{AMOVW, C_REG, C_NONE, C_NONE, C_LOREG, 35, 8, REGZERO},
+	Optab{AMOVWZ, C_REG, C_NONE, C_NONE, C_LOREG, 35, 8, REGZERO},
+	Optab{AMOVBZ, C_REG, C_NONE, C_NONE, C_LOREG, 35, 8, REGZERO},
+	Optab{AMOVB, C_REG, C_NONE, C_NONE, C_LOREG, 35, 8, REGZERO},
+	Optab{AMOVD, C_REG, C_NONE, C_NONE, C_ADDR, 74, 8, 0},
+	Optab{AMOVW, C_REG, C_NONE, C_NONE, C_ADDR, 74, 8, 0},
+	Optab{AMOVWZ, C_REG, C_NONE, C_NONE, C_ADDR, 74, 8, 0},
+	Optab{AMOVBZ, C_REG, C_NONE, C_NONE, C_ADDR, 74, 8, 0},
+	Optab{AMOVB, C_REG, C_NONE, C_NONE, C_ADDR, 74, 8, 0},
+
+	/* load, long offset */
+	Optab{AMOVD, C_LEXT, C_NONE, C_NONE, C_REG, 36, 8, REGSB},
+	Optab{AMOVW, C_LEXT, C_NONE, C_NONE, C_REG, 36, 8, REGSB},
+	Optab{AMOVWZ, C_LEXT, C_NONE, C_NONE, C_REG, 36, 8, REGSB},
+	Optab{AMOVBZ, C_LEXT, C_NONE, C_NONE, C_REG, 36, 8, REGSB},
+	Optab{AMOVB, C_LEXT, C_NONE, C_NONE, C_REG, 37, 12, REGSB},
+	Optab{AMOVD, C_LAUTO, C_NONE, C_NONE, C_REG, 36, 8, REGSP},
+	Optab{AMOVW, C_LAUTO, C_NONE, C_NONE, C_REG, 36, 8, REGSP},
+	Optab{AMOVWZ, C_LAUTO, C_NONE, C_NONE, C_REG, 36, 8, REGSP},
+	Optab{AMOVBZ, C_LAUTO, C_NONE, C_NONE, C_REG, 36, 8, REGSP},
+	Optab{AMOVB, C_LAUTO, C_NONE, C_NONE, C_REG, 37, 12, REGSP},
+	Optab{AMOVD, C_LOREG, C_NONE, C_NONE, C_REG, 36, 8, REGZERO},
+	Optab{AMOVW, C_LOREG, C_NONE, C_NONE, C_REG, 36, 8, REGZERO},
+	Optab{AMOVWZ, C_LOREG, C_NONE, C_NONE, C_REG, 36, 8, REGZERO},
+	Optab{AMOVBZ, C_LOREG, C_NONE, C_NONE, C_REG, 36, 8, REGZERO},
+	Optab{AMOVB, C_LOREG, C_NONE, C_NONE, C_REG, 37, 12, REGZERO},
+	Optab{AMOVD, C_ADDR, C_NONE, C_NONE, C_REG, 75, 8, 0},
+	Optab{AMOVW, C_ADDR, C_NONE, C_NONE, C_REG, 75, 8, 0},
+	Optab{AMOVWZ, C_ADDR, C_NONE, C_NONE, C_REG, 75, 8, 0},
+	Optab{AMOVBZ, C_ADDR, C_NONE, C_NONE, C_REG, 75, 8, 0},
+	Optab{AMOVB, C_ADDR, C_NONE, C_NONE, C_REG, 76, 12, 0},
+
+	/* load constant */
+	Optab{AMOVD, C_SECON, C_NONE, C_NONE, C_REG, 3, 4, REGSB},
+	Optab{AMOVD, C_SACON, C_NONE, C_NONE, C_REG, 3, 4, REGSP},
+	Optab{AMOVD, C_LECON, C_NONE, C_NONE, C_REG, 26, 8, REGSB},
+	Optab{AMOVD, C_LACON, C_NONE, C_NONE, C_REG, 26, 8, REGSP},
+	Optab{AMOVD, C_ADDCON, C_NONE, C_NONE, C_REG, 3, 4, REGZERO},
+	Optab{AMOVW, C_SECON, C_NONE, C_NONE, C_REG, 3, 4, REGSB}, /* TO DO: check */
+	Optab{AMOVW, C_SACON, C_NONE, C_NONE, C_REG, 3, 4, REGSP},
+	Optab{AMOVW, C_LECON, C_NONE, C_NONE, C_REG, 26, 8, REGSB},
+	Optab{AMOVW, C_LACON, C_NONE, C_NONE, C_REG, 26, 8, REGSP},
+	Optab{AMOVW, C_ADDCON, C_NONE, C_NONE, C_REG, 3, 4, REGZERO},
+	Optab{AMOVWZ, C_SECON, C_NONE, C_NONE, C_REG, 3, 4, REGSB}, /* TO DO: check */
+	Optab{AMOVWZ, C_SACON, C_NONE, C_NONE, C_REG, 3, 4, REGSP},
+	Optab{AMOVWZ, C_LECON, C_NONE, C_NONE, C_REG, 26, 8, REGSB},
+	Optab{AMOVWZ, C_LACON, C_NONE, C_NONE, C_REG, 26, 8, REGSP},
+	Optab{AMOVWZ, C_ADDCON, C_NONE, C_NONE, C_REG, 3, 4, REGZERO},
+
+	/* load unsigned/long constants (TO DO: check) */
+	Optab{AMOVD, C_UCON, C_NONE, C_NONE, C_REG, 3, 4, REGZERO},
+	Optab{AMOVD, C_LCON, C_NONE, C_NONE, C_REG, 19, 8, 0},
+	Optab{AMOVW, C_UCON, C_NONE, C_NONE, C_REG, 3, 4, REGZERO},
+	Optab{AMOVW, C_LCON, C_NONE, C_NONE, C_REG, 19, 8, 0},
+	Optab{AMOVWZ, C_UCON, C_NONE, C_NONE, C_REG, 3, 4, REGZERO},
+	Optab{AMOVWZ, C_LCON, C_NONE, C_NONE, C_REG, 19, 8, 0},
+	Optab{AMOVHBR, C_ZOREG, C_REG, C_NONE, C_REG, 45, 4, 0},
+	Optab{AMOVHBR, C_ZOREG, C_NONE, C_NONE, C_REG, 45, 4, 0},
+	Optab{AMOVHBR, C_REG, C_REG, C_NONE, C_ZOREG, 44, 4, 0},
+	Optab{AMOVHBR, C_REG, C_NONE, C_NONE, C_ZOREG, 44, 4, 0},
+	Optab{ASYSCALL, C_NONE, C_NONE, C_NONE, C_NONE, 5, 4, 0},
+	Optab{ASYSCALL, C_REG, C_NONE, C_NONE, C_NONE, 77, 12, 0},
+	Optab{ASYSCALL, C_SCON, C_NONE, C_NONE, C_NONE, 77, 12, 0},
+	Optab{ABEQ, C_NONE, C_NONE, C_NONE, C_SBRA, 16, 4, 0},
+	Optab{ABEQ, C_CREG, C_NONE, C_NONE, C_SBRA, 16, 4, 0},
+	Optab{ABR, C_NONE, C_NONE, C_NONE, C_LBRA, 11, 4, 0},
+	Optab{ABC, C_SCON, C_REG, C_NONE, C_SBRA, 16, 4, 0},
+	Optab{ABC, C_SCON, C_REG, C_NONE, C_LBRA, 17, 4, 0},
+	Optab{ABR, C_NONE, C_NONE, C_NONE, C_LR, 18, 4, 0},
+	Optab{ABR, C_NONE, C_NONE, C_NONE, C_CTR, 18, 4, 0},
+	Optab{ABR, C_REG, C_NONE, C_NONE, C_CTR, 18, 4, 0},
+	Optab{ABR, C_NONE, C_NONE, C_NONE, C_ZOREG, 15, 8, 0},
+	Optab{ABC, C_NONE, C_REG, C_NONE, C_LR, 18, 4, 0},
+	Optab{ABC, C_NONE, C_REG, C_NONE, C_CTR, 18, 4, 0},
+	Optab{ABC, C_SCON, C_REG, C_NONE, C_LR, 18, 4, 0},
+	Optab{ABC, C_SCON, C_REG, C_NONE, C_CTR, 18, 4, 0},
+	Optab{ABC, C_NONE, C_NONE, C_NONE, C_ZOREG, 15, 8, 0},
+	Optab{AFMOVD, C_SEXT, C_NONE, C_NONE, C_FREG, 8, 4, REGSB},
+	Optab{AFMOVD, C_SAUTO, C_NONE, C_NONE, C_FREG, 8, 4, REGSP},
+	Optab{AFMOVD, C_SOREG, C_NONE, C_NONE, C_FREG, 8, 4, REGZERO},
+	Optab{AFMOVD, C_LEXT, C_NONE, C_NONE, C_FREG, 36, 8, REGSB},
+	Optab{AFMOVD, C_LAUTO, C_NONE, C_NONE, C_FREG, 36, 8, REGSP},
+	Optab{AFMOVD, C_LOREG, C_NONE, C_NONE, C_FREG, 36, 8, REGZERO},
+	Optab{AFMOVD, C_ADDR, C_NONE, C_NONE, C_FREG, 75, 8, 0},
+	Optab{AFMOVD, C_FREG, C_NONE, C_NONE, C_SEXT, 7, 4, REGSB},
+	Optab{AFMOVD, C_FREG, C_NONE, C_NONE, C_SAUTO, 7, 4, REGSP},
+	Optab{AFMOVD, C_FREG, C_NONE, C_NONE, C_SOREG, 7, 4, REGZERO},
+	Optab{AFMOVD, C_FREG, C_NONE, C_NONE, C_LEXT, 35, 8, REGSB},
+	Optab{AFMOVD, C_FREG, C_NONE, C_NONE, C_LAUTO, 35, 8, REGSP},
+	Optab{AFMOVD, C_FREG, C_NONE, C_NONE, C_LOREG, 35, 8, REGZERO},
+	Optab{AFMOVD, C_FREG, C_NONE, C_NONE, C_ADDR, 74, 8, 0},
+	Optab{ASYNC, C_NONE, C_NONE, C_NONE, C_NONE, 46, 4, 0},
+	Optab{AWORD, C_LCON, C_NONE, C_NONE, C_NONE, 40, 4, 0},
+	Optab{ADWORD, C_LCON, C_NONE, C_NONE, C_NONE, 31, 8, 0},
+	Optab{ADWORD, C_DCON, C_NONE, C_NONE, C_NONE, 31, 8, 0},
+	Optab{AADDME, C_REG, C_NONE, C_NONE, C_REG, 47, 4, 0},
+	Optab{AEXTSB, C_REG, C_NONE, C_NONE, C_REG, 48, 4, 0},
+	Optab{AEXTSB, C_NONE, C_NONE, C_NONE, C_REG, 48, 4, 0},
+	Optab{ANEG, C_REG, C_NONE, C_NONE, C_REG, 47, 4, 0},
+	Optab{ANEG, C_NONE, C_NONE, C_NONE, C_REG, 47, 4, 0},
+	Optab{AREM, C_REG, C_NONE, C_NONE, C_REG, 50, 12, 0},
+	Optab{AREM, C_REG, C_REG, C_NONE, C_REG, 50, 12, 0},
+	Optab{AREMU, C_REG, C_NONE, C_NONE, C_REG, 50, 16, 0},
+	Optab{AREMU, C_REG, C_REG, C_NONE, C_REG, 50, 16, 0},
+	Optab{AREMD, C_REG, C_NONE, C_NONE, C_REG, 51, 12, 0},
+	Optab{AREMD, C_REG, C_REG, C_NONE, C_REG, 51, 12, 0},
+	Optab{AREMDU, C_REG, C_NONE, C_NONE, C_REG, 51, 12, 0},
+	Optab{AREMDU, C_REG, C_REG, C_NONE, C_REG, 51, 12, 0},
+	Optab{AMTFSB0, C_SCON, C_NONE, C_NONE, C_NONE, 52, 4, 0},
+	Optab{AMOVFL, C_FPSCR, C_NONE, C_NONE, C_FREG, 53, 4, 0},
+	Optab{AMOVFL, C_FREG, C_NONE, C_NONE, C_FPSCR, 64, 4, 0},
+	Optab{AMOVFL, C_FREG, C_NONE, C_LCON, C_FPSCR, 64, 4, 0},
+	Optab{AMOVFL, C_LCON, C_NONE, C_NONE, C_FPSCR, 65, 4, 0},
+	Optab{AMOVD, C_MSR, C_NONE, C_NONE, C_REG, 54, 4, 0},  /* mfmsr */
+	Optab{AMOVD, C_REG, C_NONE, C_NONE, C_MSR, 54, 4, 0},  /* mtmsrd */
+	Optab{AMOVWZ, C_REG, C_NONE, C_NONE, C_MSR, 54, 4, 0}, /* mtmsr */
+
+	/* 64-bit special registers */
+	Optab{AMOVD, C_REG, C_NONE, C_NONE, C_SPR, 66, 4, 0},
+	Optab{AMOVD, C_REG, C_NONE, C_NONE, C_LR, 66, 4, 0},
+	Optab{AMOVD, C_REG, C_NONE, C_NONE, C_CTR, 66, 4, 0},
+	Optab{AMOVD, C_REG, C_NONE, C_NONE, C_XER, 66, 4, 0},
+	Optab{AMOVD, C_SPR, C_NONE, C_NONE, C_REG, 66, 4, 0},
+	Optab{AMOVD, C_LR, C_NONE, C_NONE, C_REG, 66, 4, 0},
+	Optab{AMOVD, C_CTR, C_NONE, C_NONE, C_REG, 66, 4, 0},
+	Optab{AMOVD, C_XER, C_NONE, C_NONE, C_REG, 66, 4, 0},
+
+	/* 32-bit special registers (gloss over sign-extension or not?) */
+	Optab{AMOVW, C_REG, C_NONE, C_NONE, C_SPR, 66, 4, 0},
+	Optab{AMOVW, C_REG, C_NONE, C_NONE, C_CTR, 66, 4, 0},
+	Optab{AMOVW, C_REG, C_NONE, C_NONE, C_XER, 66, 4, 0},
+	Optab{AMOVW, C_SPR, C_NONE, C_NONE, C_REG, 66, 4, 0},
+	Optab{AMOVW, C_XER, C_NONE, C_NONE, C_REG, 66, 4, 0},
+	Optab{AMOVWZ, C_REG, C_NONE, C_NONE, C_SPR, 66, 4, 0},
+	Optab{AMOVWZ, C_REG, C_NONE, C_NONE, C_CTR, 66, 4, 0},
+	Optab{AMOVWZ, C_REG, C_NONE, C_NONE, C_XER, 66, 4, 0},
+	Optab{AMOVWZ, C_SPR, C_NONE, C_NONE, C_REG, 66, 4, 0},
+	Optab{AMOVWZ, C_XER, C_NONE, C_NONE, C_REG, 66, 4, 0},
+	Optab{AMOVFL, C_FPSCR, C_NONE, C_NONE, C_CREG, 73, 4, 0},
+	Optab{AMOVFL, C_CREG, C_NONE, C_NONE, C_CREG, 67, 4, 0},
+	Optab{AMOVW, C_CREG, C_NONE, C_NONE, C_REG, 68, 4, 0},
+	Optab{AMOVWZ, C_CREG, C_NONE, C_NONE, C_REG, 68, 4, 0},
+	Optab{AMOVFL, C_REG, C_NONE, C_LCON, C_CREG, 69, 4, 0},
+	Optab{AMOVFL, C_REG, C_NONE, C_NONE, C_CREG, 69, 4, 0},
+	Optab{AMOVW, C_REG, C_NONE, C_NONE, C_CREG, 69, 4, 0},
+	Optab{AMOVWZ, C_REG, C_NONE, C_NONE, C_CREG, 69, 4, 0},
+	Optab{ACMP, C_REG, C_NONE, C_NONE, C_REG, 70, 4, 0},
+	Optab{ACMP, C_REG, C_REG, C_NONE, C_REG, 70, 4, 0},
+	Optab{ACMP, C_REG, C_NONE, C_NONE, C_ADDCON, 71, 4, 0},
+	Optab{ACMP, C_REG, C_REG, C_NONE, C_ADDCON, 71, 4, 0},
+	Optab{ACMPU, C_REG, C_NONE, C_NONE, C_REG, 70, 4, 0},
+	Optab{ACMPU, C_REG, C_REG, C_NONE, C_REG, 70, 4, 0},
+	Optab{ACMPU, C_REG, C_NONE, C_NONE, C_ANDCON, 71, 4, 0},
+	Optab{ACMPU, C_REG, C_REG, C_NONE, C_ANDCON, 71, 4, 0},
+	Optab{AFCMPO, C_FREG, C_NONE, C_NONE, C_FREG, 70, 4, 0},
+	Optab{AFCMPO, C_FREG, C_REG, C_NONE, C_FREG, 70, 4, 0},
+	Optab{ATW, C_LCON, C_REG, C_NONE, C_REG, 60, 4, 0},
+	Optab{ATW, C_LCON, C_REG, C_NONE, C_ADDCON, 61, 4, 0},
+	Optab{ADCBF, C_ZOREG, C_NONE, C_NONE, C_NONE, 43, 4, 0},
+	Optab{ADCBF, C_ZOREG, C_REG, C_NONE, C_NONE, 43, 4, 0},
+	Optab{AECOWX, C_REG, C_REG, C_NONE, C_ZOREG, 44, 4, 0},
+	Optab{AECIWX, C_ZOREG, C_REG, C_NONE, C_REG, 45, 4, 0},
+	Optab{AECOWX, C_REG, C_NONE, C_NONE, C_ZOREG, 44, 4, 0},
+	Optab{AECIWX, C_ZOREG, C_NONE, C_NONE, C_REG, 45, 4, 0},
+	Optab{AEIEIO, C_NONE, C_NONE, C_NONE, C_NONE, 46, 4, 0},
+	Optab{ATLBIE, C_REG, C_NONE, C_NONE, C_NONE, 49, 4, 0},
+	Optab{ATLBIE, C_SCON, C_NONE, C_NONE, C_REG, 49, 4, 0},
+	Optab{ASLBMFEE, C_REG, C_NONE, C_NONE, C_REG, 55, 4, 0},
+	Optab{ASLBMTE, C_REG, C_NONE, C_NONE, C_REG, 55, 4, 0},
+	Optab{ASTSW, C_REG, C_NONE, C_NONE, C_ZOREG, 44, 4, 0},
+	Optab{ASTSW, C_REG, C_NONE, C_LCON, C_ZOREG, 41, 4, 0},
+	Optab{ALSW, C_ZOREG, C_NONE, C_NONE, C_REG, 45, 4, 0},
+	Optab{ALSW, C_ZOREG, C_NONE, C_LCON, C_REG, 42, 4, 0},
+	Optab{obj.AUNDEF, C_NONE, C_NONE, C_NONE, C_NONE, 78, 4, 0},
+	Optab{obj.AUSEFIELD, C_ADDR, C_NONE, C_NONE, C_NONE, 0, 0, 0},
+	Optab{obj.APCDATA, C_LCON, C_NONE, C_NONE, C_LCON, 0, 0, 0},
+	Optab{obj.AFUNCDATA, C_SCON, C_NONE, C_NONE, C_ADDR, 0, 0, 0},
+	Optab{obj.ANOP, C_NONE, C_NONE, C_NONE, C_NONE, 0, 0, 0},
+	Optab{obj.ADUFFZERO, C_NONE, C_NONE, C_NONE, C_LBRA, 11, 4, 0}, // same as ABR/ABL
+	Optab{obj.ADUFFCOPY, C_NONE, C_NONE, C_NONE, C_LBRA, 11, 4, 0}, // same as ABR/ABL
+
+	Optab{obj.AXXX, C_NONE, C_NONE, C_NONE, C_NONE, 0, 4, 0},
+}
+
+type Oprang struct {
+	start []Optab
+	stop  []Optab
+}
+
+var oprange [ALAST & obj.AMask]Oprang
+
+var xcmp [C_NCLASS][C_NCLASS]uint8
+
+func span9(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 + 8)
+
+	if oprange[AANDN&obj.AMask].start == nil {
+		buildop(ctxt)
+	}
+
+	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
+		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
+		}
+
+		c += int64(m)
+	}
+
+	cursym.Size = 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.
+	 */
+	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())
+		}
+		bflag = 0
+		c = 0
+		for p = cursym.Text.Link; p != nil; p = p.Link {
+			p.Pc = c
+			o = oplook(ctxt, p)
+
+			// very large conditional branches
+			if (o.type_ == 16 || o.type_ == 17) && p.Pcond != nil {
+				otxt = p.Pcond.Pc - c
+				if otxt < -(1<<15)+10 || otxt >= (1<<15)-10 {
+					q = ctxt.NewProg()
+					q.Link = p.Link
+					p.Link = q
+					q.As = ABR
+					q.To.Type = obj.TYPE_BRANCH
+					q.Pcond = p.Pcond
+					p.Pcond = q
+					q = ctxt.NewProg()
+					q.Link = p.Link
+					p.Link = q
+					q.As = ABR
+					q.To.Type = obj.TYPE_BRANCH
+					q.Pcond = q.Link.Link
+
+					//addnop(p->link);
+					//addnop(p);
+					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 += int64(m)
+		}
+
+		cursym.Size = c
+	}
+
+	c += -c & (FuncAlign - 1)
+	cursym.Size = 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
+	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)
+		if int(o.size) > 4*len(out) {
+			log.Fatalf("out array in span9 is too small, need at least %d for %v", o.size/4, p)
+		}
+		asmout(ctxt, p, o, out[:])
+		for i = 0; i < int32(o.size/4); i++ {
+			ctxt.Arch.ByteOrder.PutUint32(bp, out[i])
+			bp = bp[4:]
+		}
+	}
+}
+
+func isint32(v int64) bool {
+	return int64(int32(v)) == v
+}
+
+func isuint32(v uint64) bool {
+	return uint64(uint32(v)) == v
+}
+
+func aclass(ctxt *obj.Link, a *obj.Addr) int {
+	switch a.Type {
+	case obj.TYPE_NONE:
+		return C_NONE
+
+	case obj.TYPE_REG:
+		if REG_R0 <= a.Reg && a.Reg <= REG_R31 {
+			return C_REG
+		}
+		if REG_F0 <= a.Reg && a.Reg <= REG_F31 {
+			return C_FREG
+		}
+		if REG_CR0 <= a.Reg && a.Reg <= REG_CR7 || a.Reg == REG_CR {
+			return C_CREG
+		}
+		if REG_SPR0 <= a.Reg && a.Reg <= REG_SPR0+1023 {
+			switch a.Reg {
+			case REG_LR:
+				return C_LR
+
+			case REG_XER:
+				return C_XER
+
+			case REG_CTR:
+				return C_CTR
+			}
+
+			return C_SPR
+		}
+
+		if REG_DCR0 <= a.Reg && a.Reg <= REG_DCR0+1023 {
+			return C_SPR
+		}
+		if a.Reg == REG_FPSCR {
+			return C_FPSCR
+		}
+		if a.Reg == REG_MSR {
+			return C_MSR
+		}
+		return C_GOK
+
+	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
+			if ctxt.Instoffset >= -BIG && ctxt.Instoffset < BIG {
+				return C_SAUTO
+			}
+			return C_LAUTO
+
+		case obj.NAME_PARAM:
+			ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset + 8
+			if ctxt.Instoffset >= -BIG && ctxt.Instoffset < BIG {
+				return C_SAUTO
+			}
+			return C_LAUTO
+
+		case obj.NAME_NONE:
+			ctxt.Instoffset = a.Offset
+			if ctxt.Instoffset == 0 {
+				return C_ZOREG
+			}
+			if ctxt.Instoffset >= -BIG && ctxt.Instoffset < BIG {
+				return C_SOREG
+			}
+			return C_LOREG
+		}
+
+		return C_GOK
+
+	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 {
+				if -BIG <= ctxt.Instoffset && ctxt.Instoffset <= BIG {
+					return C_SACON
+				}
+				if isint32(ctxt.Instoffset) {
+					return C_LACON
+				}
+				return C_DACON
+			}
+
+			goto consize
+
+		case obj.NAME_EXTERN,
+			obj.NAME_STATIC:
+			s := a.Sym
+			if s == nil {
+				break
+			}
+			if s.Type == obj.SCONST {
+				ctxt.Instoffset = s.Value + a.Offset
+				goto consize
+			}
+
+			ctxt.Instoffset = s.Value + a.Offset
+
+			/* not sure why this barfs */
+			return C_LCON
+
+		case obj.NAME_AUTO:
+			ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset
+			if ctxt.Instoffset >= -BIG && ctxt.Instoffset < BIG {
+				return C_SACON
+			}
+			return C_LACON
+
+		case obj.NAME_PARAM:
+			ctxt.Instoffset = int64(ctxt.Autosize) + a.Offset + 8
+			if ctxt.Instoffset >= -BIG && ctxt.Instoffset < BIG {
+				return C_SACON
+			}
+			return C_LACON
+		}
+
+		return C_GOK
+
+	consize:
+		if ctxt.Instoffset >= 0 {
+			if ctxt.Instoffset == 0 {
+				return C_ZCON
+			}
+			if ctxt.Instoffset <= 0x7fff {
+				return C_SCON
+			}
+			if ctxt.Instoffset <= 0xffff {
+				return C_ANDCON
+			}
+			if ctxt.Instoffset&0xffff == 0 && isuint32(uint64(ctxt.Instoffset)) { /* && (instoffset & (1<<31)) == 0) */
+				return C_UCON
+			}
+			if isint32(ctxt.Instoffset) || isuint32(uint64(ctxt.Instoffset)) {
+				return C_LCON
+			}
+			return C_DCON
+		}
+
+		if ctxt.Instoffset >= -0x8000 {
+			return C_ADDCON
+		}
+		if ctxt.Instoffset&0xffff == 0 && isint32(ctxt.Instoffset) {
+			return C_UCON
+		}
+		if isint32(ctxt.Instoffset) {
+			return C_LCON
+		}
+		return C_DCON
+
+	case obj.TYPE_BRANCH:
+		return C_SBRA
+	}
+
+	return C_GOK
+}
+
+func prasm(p *obj.Prog) {
+	fmt.Printf("%v\n", p)
+}
+
+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 := C_NONE + 1
+	if p.From3 != nil {
+		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)
+	if a4 == 0 {
+		a4 = aclass(ctxt, &p.To) + 1
+		p.To.Class = int8(a4)
+	}
+
+	a4--
+	a2 := C_NONE
+	if p.Reg != 0 {
+		a2 = C_REG
+	}
+
+	//print("oplook %v %d %d %d %d\n", p, a1, a2, a3, a4);
+	r0 := p.As & obj.AMask
+
+	o := oprange[r0].start
+	if o == nil {
+		o = oprange[r0].stop /* just generate an error */
+	}
+	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 {
+				if c3[o[0].a3] != 0 {
+					if c4[o[0].a4] != 0 {
+						p.Optab = uint16((-cap(o) + cap(optab)) + 1)
+						return &o[0]
+					}
+				}
+			}
+		}
+	}
+
+	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
+	}
+	return &o[0]
+}
+
+func cmp(a int, b int) bool {
+	if a == b {
+		return true
+	}
+	switch a {
+	case C_LCON:
+		if b == C_ZCON || b == C_SCON || b == C_UCON || b == C_ADDCON || b == C_ANDCON {
+			return true
+		}
+
+	case C_ADDCON:
+		if b == C_ZCON || b == C_SCON {
+			return true
+		}
+
+	case C_ANDCON:
+		if b == C_ZCON || b == C_SCON {
+			return true
+		}
+
+	case C_SPR:
+		if b == C_LR || b == C_XER || b == C_CTR {
+			return true
+		}
+
+	case C_UCON:
+		if b == C_ZCON {
+			return true
+		}
+
+	case C_SCON:
+		if b == C_ZCON {
+			return true
+		}
+
+	case C_LACON:
+		if b == C_SACON {
+			return true
+		}
+
+	case C_LBRA:
+		if b == C_SBRA {
+			return true
+		}
+
+	case C_LEXT:
+		if b == C_SEXT {
+			return true
+		}
+
+	case C_LAUTO:
+		if b == C_SAUTO {
+			return true
+		}
+
+	case C_REG:
+		if b == C_ZCON {
+			return r0iszero != 0 /*TypeKind(100016)*/
+		}
+
+	case C_LOREG:
+		if b == C_ZOREG || b == C_SOREG {
+			return true
+		}
+
+	case C_SOREG:
+		if b == C_ZOREG {
+			return true
+		}
+
+	case C_ANY:
+		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.a4) - int(p2.a4)
+	if n != 0 {
+		return n < 0
+	}
+	return false
+}
+func opset(a, b0 int16) {
+	oprange[a&obj.AMask] = oprange[b0]
+}
+
+func buildop(ctxt *obj.Link) {
+	var n int
+
+	for i := 0; i < C_NCLASS; i++ {
+		for n = 0; n < C_NCLASS; n++ {
+			if cmp(n, i) {
+				xcmp[i][n] = 1
+			}
+		}
+	}
+	for n = 0; optab[n].as != obj.AXXX; n++ {
+	}
+	sort.Sort(ocmp(optab[:n]))
+	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[r0].stop = optab[i:]
+		i--
+
+		switch r {
+		default:
+			ctxt.Diag("unknown op in build: %v", obj.Aconv(int(r)))
+			log.Fatalf("bad code")
+
+		case ADCBF: /* unary indexed: op (b+a); op (b) */
+			opset(ADCBI, r0)
+
+			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) */
+			opset(ASTWCCC, r0)
+
+			opset(ASTDCCC, r0)
+
+		case AREM: /* macro */
+			opset(AREMCC, r0)
+
+			opset(AREMV, r0)
+			opset(AREMVCC, r0)
+
+		case AREMU:
+			opset(AREMU, r0)
+			opset(AREMUCC, r0)
+			opset(AREMUV, r0)
+			opset(AREMUVCC, r0)
+
+		case AREMD:
+			opset(AREMDCC, r0)
+			opset(AREMDV, r0)
+			opset(AREMDVCC, r0)
+
+		case AREMDU:
+			opset(AREMDU, r0)
+			opset(AREMDUCC, r0)
+			opset(AREMDUV, r0)
+			opset(AREMDUVCC, r0)
+
+		case ADIVW: /* op Rb[,Ra],Rd */
+			opset(AMULHW, r0)
+
+			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 */
+			opset(AMOVH, r0)
+
+			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 */
+			opset(AMOVHU, r0)
+
+			opset(AMOVHZU, r0)
+			opset(AMOVWU, r0)
+			opset(AMOVWZU, r0)
+			opset(AMOVDU, r0)
+			opset(AMOVMW, r0)
+
+		case AAND: /* logical op Rb,Rs,Ra; no literal */
+			opset(AANDN, r0)
+
+			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 */
+			opset(AADDMECC, r0)
+
+			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:
+			opset(AADDCCC, r0)
+
+		case ABEQ:
+			opset(ABGE, r0)
+			opset(ABGT, r0)
+			opset(ABLE, r0)
+			opset(ABLT, r0)
+			opset(ABNE, r0)
+			opset(ABVC, r0)
+			opset(ABVS, r0)
+
+		case ABR:
+			opset(ABL, r0)
+
+		case ABC:
+			opset(ABCL, r0)
+
+		case AEXTSB: /* op Rs, Ra */
+			opset(AEXTSBCC, r0)
+
+			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 */
+			opset(AFABSCC, r0)
+
+			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:
+			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:
+			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:
+			opset(AFMULS, r0)
+			opset(AFMULCC, r0)
+			opset(AFMULSCC, r0)
+
+		case AFCMPO:
+			opset(AFCMPU, r0)
+
+		case AMTFSB0:
+			opset(AMTFSB0CC, r0)
+			opset(AMTFSB1, r0)
+			opset(AMTFSB1CC, r0)
+
+		case ANEG: /* op [Ra,] Rd */
+			opset(ANEGCC, r0)
+
+			opset(ANEGV, r0)
+			opset(ANEGVCC, r0)
+
+		case AOR: /* or/xor Rb,Rs,Ra; ori/xori $uimm,Rs,Ra; oris/xoris $uimm,Rs,Ra */
+			opset(AXOR, r0)
+
+		case ASLW:
+			opset(ASLWCC, r0)
+			opset(ASRW, r0)
+			opset(ASRWCC, r0)
+
+		case ASLD:
+			opset(ASLDCC, r0)
+			opset(ASRD, r0)
+			opset(ASRDCC, r0)
+
+		case ASRAW: /* sraw Rb,Rs,Ra; srawi sh,Rs,Ra */
+			opset(ASRAWCC, r0)
+
+		case ASRAD: /* sraw Rb,Rs,Ra; srawi sh,Rs,Ra */
+			opset(ASRADCC, r0)
+
+		case ASUB: /* SUB Ra,Rb,Rd => subf Rd,ra,rb */
+			opset(ASUB, r0)
+
+			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:
+			opset(AISYNC, r0)
+			opset(APTESYNC, r0)
+			opset(ATLBSYNC, r0)
+
+		case ARLWMI:
+			opset(ARLWMICC, r0)
+			opset(ARLWNM, r0)
+			opset(ARLWNMCC, r0)
+
+		case ARLDMI:
+			opset(ARLDMICC, r0)
+
+		case ARLDC:
+			opset(ARLDCCC, r0)
+
+		case ARLDCL:
+			opset(ARLDCR, r0)
+			opset(ARLDCLCC, r0)
+			opset(ARLDCRCC, r0)
+
+		case AFMOVD:
+			opset(AFMOVDCC, r0)
+			opset(AFMOVDU, r0)
+			opset(AFMOVS, r0)
+			opset(AFMOVSU, r0)
+
+		case AECIWX:
+			opset(ALWAR, r0)
+			opset(ALDAR, r0)
+
+		case ASYSCALL: /* just the op; flow of control */
+			opset(ARFI, r0)
+
+			opset(ARFCI, r0)
+			opset(ARFID, r0)
+			opset(AHRFID, r0)
+
+		case AMOVHBR:
+			opset(AMOVWBR, r0)
+
+		case ASLBMFEE:
+			opset(ASLBMFEV, r0)
+
+		case ATW:
+			opset(ATD, r0)
+
+		case ATLBIE:
+			opset(ASLBIE, r0)
+			opset(ATLBIEL, r0)
+
+		case AEIEIO:
+			opset(ASLBIA, r0)
+
+		case ACMP:
+			opset(ACMPW, r0)
+
+		case ACMPU:
+			opset(ACMPWU, r0)
+
+		case AADD,
+			AANDCC, /* and. Rb,Rs,Ra; andi. $uimm,Rs,Ra; andis. $uimm,Rs,Ra */
+			ALSW,
+			AMOVW,
+			/* load/store/move word with sign extension; special 32-bit move; move 32-bit literals */
+			AMOVWZ, /* load/store/move word with zero extension; move 32-bit literals  */
+			AMOVD,  /* load/store/move 64-bit values, including 32-bit literals with/without sign-extension */
+			AMOVB,  /* macro: move byte with sign extension */
+			AMOVBU, /* macro: move byte with sign extension & update */
+			AMOVFL,
+			AMULLW,
+			/* op $s[,r2],r3; op r1[,r2],r3; no cc/v */
+			ASUBC, /* op r1,$s,r3; op r1[,r2],r3 */
+			ASTSW,
+			ASLBMTE,
+			AWORD,
+			ADWORD,
+			obj.ANOP,
+			obj.ATEXT,
+			obj.AUNDEF,
+			obj.AUSEFIELD,
+			obj.AFUNCDATA,
+			obj.APCDATA,
+			obj.ADUFFZERO,
+			obj.ADUFFCOPY:
+			break
+		}
+	}
+}
+
+func OPVCC(o uint32, xo uint32, oe uint32, rc uint32) uint32 {
+	return o<<26 | xo<<1 | oe<<10 | rc&1
+}
+
+func OPCC(o uint32, xo uint32, rc uint32) uint32 {
+	return OPVCC(o, xo, 0, rc)
+}
+
+func OP(o uint32, xo uint32) uint32 {
+	return OPVCC(o, xo, 0, 0)
+}
+
+/* the order is dest, a/s, b/imm for both arithmetic and logical operations */
+func AOP_RRR(op uint32, d uint32, a uint32, b uint32) uint32 {
+	return op | (d&31)<<21 | (a&31)<<16 | (b&31)<<11
+}
+
+func AOP_IRR(op uint32, d uint32, a uint32, simm uint32) uint32 {
+	return op | (d&31)<<21 | (a&31)<<16 | simm&0xFFFF
+}
+
+func LOP_RRR(op uint32, a uint32, s uint32, b uint32) uint32 {
+	return op | (s&31)<<21 | (a&31)<<16 | (b&31)<<11
+}
+
+func LOP_IRR(op uint32, a uint32, s uint32, uimm uint32) uint32 {
+	return op | (s&31)<<21 | (a&31)<<16 | uimm&0xFFFF
+}
+
+func OP_BR(op uint32, li uint32, aa uint32) uint32 {
+	return op | li&0x03FFFFFC | aa<<1
+}
+
+func OP_BC(op uint32, bo uint32, bi uint32, bd uint32, aa uint32) uint32 {
+	return op | (bo&0x1F)<<21 | (bi&0x1F)<<16 | bd&0xFFFC | aa<<1
+}
+
+func OP_BCR(op uint32, bo uint32, bi uint32) uint32 {
+	return op | (bo&0x1F)<<21 | (bi&0x1F)<<16
+}
+
+func OP_RLW(op uint32, a uint32, s uint32, sh uint32, mb uint32, me uint32) uint32 {
+	return op | (s&31)<<21 | (a&31)<<16 | (sh&31)<<11 | (mb&31)<<6 | (me&31)<<1
+}
+
+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
+	OP_ANDI   = 28<<26 | 0<<1 | 0<<10 | 0
+	OP_EXTSB  = 31<<26 | 954<<1 | 0<<10 | 0
+	OP_EXTSH  = 31<<26 | 922<<1 | 0<<10 | 0
+	OP_EXTSW  = 31<<26 | 986<<1 | 0<<10 | 0
+	OP_MCRF   = 19<<26 | 0<<1 | 0<<10 | 0
+	OP_MCRFS  = 63<<26 | 64<<1 | 0<<10 | 0
+	OP_MCRXR  = 31<<26 | 512<<1 | 0<<10 | 0
+	OP_MFCR   = 31<<26 | 19<<1 | 0<<10 | 0
+	OP_MFFS   = 63<<26 | 583<<1 | 0<<10 | 0
+	OP_MFMSR  = 31<<26 | 83<<1 | 0<<10 | 0
+	OP_MFSPR  = 31<<26 | 339<<1 | 0<<10 | 0
+	OP_MFSR   = 31<<26 | 595<<1 | 0<<10 | 0
+	OP_MFSRIN = 31<<26 | 659<<1 | 0<<10 | 0
+	OP_MTCRF  = 31<<26 | 144<<1 | 0<<10 | 0
+	OP_MTFSF  = 63<<26 | 711<<1 | 0<<10 | 0
+	OP_MTFSFI = 63<<26 | 134<<1 | 0<<10 | 0
+	OP_MTMSR  = 31<<26 | 146<<1 | 0<<10 | 0
+	OP_MTMSRD = 31<<26 | 178<<1 | 0<<10 | 0
+	OP_MTSPR  = 31<<26 | 467<<1 | 0<<10 | 0
+	OP_MTSR   = 31<<26 | 210<<1 | 0<<10 | 0
+	OP_MTSRIN = 31<<26 | 242<<1 | 0<<10 | 0
+	OP_MULLW  = 31<<26 | 235<<1 | 0<<10 | 0
+	OP_MULLD  = 31<<26 | 233<<1 | 0<<10 | 0
+	OP_OR     = 31<<26 | 444<<1 | 0<<10 | 0
+	OP_ORI    = 24<<26 | 0<<1 | 0<<10 | 0
+	OP_ORIS   = 25<<26 | 0<<1 | 0<<10 | 0
+	OP_RLWINM = 21<<26 | 0<<1 | 0<<10 | 0
+	OP_SUBF   = 31<<26 | 40<<1 | 0<<10 | 0
+	OP_RLDIC  = 30<<26 | 4<<1 | 0<<10 | 0
+	OP_RLDICR = 30<<26 | 2<<1 | 0<<10 | 0
+	OP_RLDICL = 30<<26 | 0<<1 | 0<<10 | 0
+)
+
+func oclass(a *obj.Addr) int {
+	return int(a.Class) - 1
+}
+
+// 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) {
+	rel := obj.Addrel(ctxt.Cursym)
+	rel.Off = int32(ctxt.Pc)
+	rel.Siz = 8
+	rel.Sym = s
+	rel.Add = int64(uint64(*o1)<<32 | uint64(uint32(*o2)))
+	rel.Type = obj.R_ADDRPOWER
+}
+
+/*
+ * 32-bit masks
+ */
+func getmask(m []byte, v uint32) bool {
+	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])
+			m[0] = m[1] + 1
+			m[1] = byte(i - 1)
+			return true
+		}
+
+		return false
+	}
+
+	for i := 0; i < 32; i++ {
+		if v&(1<<uint(31-i)) != 0 {
+			m[0] = byte(i)
+			for {
+				m[1] = byte(i)
+				i++
+				if i >= 32 || v&(1<<uint(31-i)) == 0 {
+					break
+				}
+			}
+
+			for ; i < 32; i++ {
+				if v&(1<<uint(31-i)) != 0 {
+					return false
+				}
+			}
+			return true
+		}
+	}
+
+	return false
+}
+
+func maskgen(ctxt *obj.Link, p *obj.Prog, m []byte, v uint32) {
+	if !getmask(m, v) {
+		ctxt.Diag("cannot generate mask #%x\n%v", v, p)
+	}
+}
+
+/*
+ * 64-bit masks (rldic etc)
+ */
+func getmask64(m []byte, v uint64) bool {
+	m[1] = 0
+	m[0] = m[1]
+	for i := 0; i < 64; i++ {
+		if v&(uint64(1)<<uint(63-i)) != 0 {
+			m[0] = byte(i)
+			for {
+				m[1] = byte(i)
+				i++
+				if i >= 64 || v&(uint64(1)<<uint(63-i)) == 0 {
+					break
+				}
+			}
+
+			for ; i < 64; i++ {
+				if v&(uint64(1)<<uint(63-i)) != 0 {
+					return false
+				}
+			}
+			return true
+		}
+	}
+
+	return false
+}
+
+func maskgen64(ctxt *obj.Link, p *obj.Prog, m []byte, v uint64) {
+	if !getmask64(m, v) {
+		ctxt.Diag("cannot generate mask #%x\n%v", v, p)
+	}
+}
+
+func loadu32(r int, d int64) uint32 {
+	v := int32(d >> 16)
+	if isuint32(uint64(d)) {
+		return LOP_IRR(OP_ORIS, uint32(r), REGZERO, uint32(v))
+	}
+	return AOP_IRR(OP_ADDIS, uint32(r), REGZERO, uint32(v))
+}
+
+func high16adjusted(d int32) uint16 {
+	if d&0x8000 != 0 {
+		return uint16((d >> 16) + 1)
+	}
+	return uint16(d >> 16)
+}
+
+func asmout(ctxt *obj.Link, p *obj.Prog, o *Optab, out []uint32) {
+	o1 := uint32(0)
+	o2 := uint32(0)
+	o3 := uint32(0)
+	o4 := uint32(0)
+	o5 := uint32(0)
+
+	//print("%v => case %d\n", p, o->type);
+	switch o.type_ {
+	default:
+		ctxt.Diag("unknown type %d", o.type_)
+		prasm(p)
+
+	case 0: /* pseudo ops */
+		break
+
+	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)
+			if r0iszero != 0 /*TypeKind(100016)*/ && v != 0 {
+				//nerrors--;
+				ctxt.Diag("literal operation on R0\n%v", p)
+			}
+
+			o1 = LOP_IRR(OP_ADDI, REGZERO, REGZERO, uint32(v))
+			break
+		}
+
+		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)
+
+		if r == 0 {
+			r = int(p.To.Reg)
+		}
+		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)
+
+		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
+		if o.a1 == C_UCON {
+			if d&0xffff != 0 {
+				log.Fatalf("invalid handling of %v", p)
+			}
+			v >>= 16
+			if r == REGZERO && isuint32(uint64(d)) {
+				o1 = LOP_IRR(OP_ORIS, uint32(p.To.Reg), REGZERO, uint32(v))
+				break
+			}
+
+			a = OP_ADDIS
+		} else {
+			if int64(int16(d)) != d {
+				log.Fatalf("invalid handling of %v", p)
+			}
+		}
+
+		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)
+
+		r := int(p.Reg)
+		if r == 0 {
+			r = int(p.To.Reg)
+		}
+		if r0iszero != 0 /*TypeKind(100016)*/ && p.To.Reg == 0 {
+			ctxt.Diag("literal operation on R0\n%v", p)
+		}
+		if int32(int16(v)) != v {
+			log.Fatalf("mishandled instruction %v", p)
+		}
+		o1 = AOP_IRR(uint32(opirr(ctxt, int(p.As))), uint32(p.To.Reg), uint32(r), uint32(v))
+
+	case 5: /* syscall */
+		o1 = uint32(oprrr(ctxt, int(p.As)))
+
+	case 6: /* logical op Rb,[Rs,]Ra; no literal */
+		r := int(p.Reg)
+
+		if r == 0 {
+			r = int(p.To.Reg)
+		}
+		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)
+
+		if r == 0 {
+			r = int(o.param)
+		}
+		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.To.Index), uint32(r))
+		} else {
+			if int32(int16(v)) != v {
+				log.Fatalf("mishandled instruction %v", p)
+			}
+			o1 = AOP_IRR(uint32(opstore(ctxt, int(p.As))), uint32(p.From.Reg), uint32(r), uint32(v))
+		}
+
+	case 8: /* mov soreg, r ==> lbz/lhz/lwz o(r) */
+		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.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.From.Index), uint32(r))
+		} else {
+			if int32(int16(v)) != v {
+				log.Fatalf("mishandled instruction %v", p)
+			}
+			o1 = AOP_IRR(uint32(opload(ctxt, int(p.As))), uint32(p.To.Reg), uint32(r), uint32(v))
+		}
+
+	case 9: /* movb soreg, r ==> lbz o(r),r2; extsb r2,r2 */
+		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.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.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)
+
+		if r == 0 {
+			r = int(p.To.Reg)
+		}
+		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 := int32(0)
+
+		if p.Pcond != nil {
+			v = int32(p.Pcond.Pc - p.Pc)
+			if v&03 != 0 {
+				ctxt.Diag("odd branch target address\n%v", p)
+				v &^= 03
+			}
+
+			if v < -(1<<25) || v >= 1<<24 {
+				ctxt.Diag("branch too far\n%v", p)
+			}
+		}
+
+		o1 = OP_BR(uint32(opirr(ctxt, int(p.As))), uint32(v), 0)
+		if p.To.Sym != nil {
+			rel := obj.Addrel(ctxt.Cursym)
+			rel.Off = int32(ctxt.Pc)
+			rel.Siz = 4
+			rel.Sym = p.To.Sym
+			v += int32(p.To.Offset)
+			if v&03 != 0 {
+				ctxt.Diag("odd branch target address\n%v", p)
+				v &^= 03
+			}
+
+			rel.Add = int64(v)
+			rel.Type = obj.R_CALLPOWER
+		}
+
+	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)
+			if r0iszero != 0 /*TypeKind(100016)*/ && v != 0 {
+				ctxt.Diag("literal operation on R0\n%v", p)
+			}
+
+			o1 = LOP_IRR(OP_ADDI, REGZERO, REGZERO, uint32(v))
+			break
+		}
+
+		if p.As == AMOVW {
+			o1 = LOP_RRR(OP_EXTSW, uint32(p.To.Reg), uint32(p.From.Reg), 0)
+		} else {
+			o1 = LOP_RRR(OP_EXTSB, uint32(p.To.Reg), uint32(p.From.Reg), 0)
+		}
+
+	case 13: /* mov[bhw]z r,r; uses rlwinm not andi. to avoid changing CC */
+		if p.As == AMOVBZ {
+			o1 = OP_RLW(OP_RLWINM, uint32(p.To.Reg), uint32(p.From.Reg), 0, 24, 31)
+		} else if p.As == AMOVH {
+			o1 = LOP_RRR(OP_EXTSH, uint32(p.To.Reg), uint32(p.From.Reg), 0)
+		} else if p.As == AMOVHZ {
+			o1 = OP_RLW(OP_RLWINM, uint32(p.To.Reg), uint32(p.From.Reg), 0, 16, 31)
+		} else if p.As == AMOVWZ {
+			o1 = OP_RLW(OP_RLDIC, uint32(p.To.Reg), uint32(p.From.Reg), 0, 0, 0) | 1<<5 /* MB=32 */
+		} else {
+			ctxt.Diag("internal: bad mov[bhw]z\n%v", p)
+		}
+
+	case 14: /* rldc[lr] Rb,Rs,$mask,Ra -- left, right give different masks */
+		r := int(p.Reg)
+
+		if r == 0 {
+			r = int(p.To.Reg)
+		}
+		d := vregoff(ctxt, p.From3)
+		var mask [2]uint8
+		maskgen64(ctxt, p, mask[:], uint64(d))
+		var a int
+		switch p.As {
+		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:
+			a = int(mask[1]) /* ME */
+			if mask[0] != 0 {
+				ctxt.Diag("invalid mask for rotate: %x (start != 0)\n%v", uint64(d), p)
+			}
+
+		default:
+			ctxt.Diag("unexpected op in rldc case\n%v", p)
+			a = 0
+		}
+
+		o1 = LOP_RRR(uint32(oprrr(ctxt, int(p.As))), uint32(p.To.Reg), uint32(r), uint32(p.From.Reg))
+		o1 |= (uint32(a) & 31) << 6
+		if a&0x20 != 0 {
+			o1 |= 1 << 5 /* mb[5] is top bit */
+		}
+
+	case 17, /* bc bo,bi,lbra (same for now) */
+		16: /* bc bo,bi,sbra */
+		a := 0
+
+		if p.From.Type == obj.TYPE_CONST {
+			a = int(regoff(ctxt, &p.From))
+		}
+		r := int(p.Reg)
+		if r == 0 {
+			r = 0
+		}
+		v := int32(0)
+		if p.Pcond != nil {
+			v = int32(p.Pcond.Pc - p.Pc)
+		}
+		if v&03 != 0 {
+			ctxt.Diag("odd branch target address\n%v", p)
+			v &^= 03
+		}
+
+		if v < -(1<<16) || v >= 1<<15 {
+			ctxt.Diag("branch too far\n%v", p)
+		}
+		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 */
+		}
+		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(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)
+		if r == 0 {
+			r = 0
+		}
+		switch oclass(&p.To) {
+		case C_CTR:
+			o1 = OPVCC(19, 528, 0, 0)
+
+		case C_LR:
+			o1 = OPVCC(19, 16, 0, 0)
+
+		default:
+			ctxt.Diag("bad optab entry (18): %d\n%v", p.To.Class, p)
+			v = 0
+		}
+
+		if p.As == ABL || p.As == ABCL {
+			o1 |= 1
+		}
+		o1 = OP_BCR(o1, uint32(v), uint32(r))
+
+	case 19: /* mov $lcon,r ==> cau+or */
+		d := vregoff(ctxt, &p.From)
+
+		if p.From.Sym == nil {
+			o1 = loadu32(int(p.To.Reg), d)
+			o2 = LOP_IRR(OP_ORI, uint32(p.To.Reg), uint32(p.To.Reg), uint32(int32(d)))
+		} else {
+			o1 = AOP_IRR(OP_ADDIS, REGTMP, REGZERO, uint32(high16adjusted(int32(d))))
+			o2 = AOP_IRR(OP_ADDI, uint32(p.To.Reg), REGTMP, uint32(d))
+			addaddrreloc(ctxt, p.From.Sym, &o1, &o2)
+		}
+
+	//if(dlm) reloc(&p->from, p->pc, 0);
+
+	case 20: /* add $ucon,,r */
+		v := regoff(ctxt, &p.From)
+
+		r := int(p.Reg)
+		if r == 0 {
+			r = int(p.To.Reg)
+		}
+		if p.As == AADD && (r0iszero == 0 /*TypeKind(100016)*/ && p.Reg == 0 || r0iszero != 0 /*TypeKind(100016)*/ && p.To.Reg == 0) {
+			ctxt.Diag("literal operation on R0\n%v", p)
+		}
+		o1 = AOP_IRR(uint32(opirr(ctxt, int(p.As)+ALAST)), uint32(p.To.Reg), uint32(r), uint32(v)>>16)
+
+	case 22: /* add $lcon,r1,r2 ==> cau+or+add */ /* could do add/sub more efficiently */
+		if p.To.Reg == REGTMP || p.Reg == REGTMP {
+			ctxt.Diag("cant synthesize large constant\n%v", p)
+		}
+		d := vregoff(ctxt, &p.From)
+		o1 = loadu32(REGTMP, d)
+		o2 = LOP_IRR(OP_ORI, REGTMP, REGTMP, uint32(int32(d)))
+		r := int(p.Reg)
+		if r == 0 {
+			r = int(p.To.Reg)
+		}
+		o3 = AOP_RRR(uint32(oprrr(ctxt, int(p.As))), uint32(p.To.Reg), REGTMP, uint32(r))
+		if p.From.Sym != nil {
+			ctxt.Diag("%v is not supported", p)
+		}
+
+	//if(dlm) reloc(&p->from, p->pc, 0);
+
+	case 23: /* and $lcon,r1,r2 ==> cau+or+and */ /* masks could be done using rlnm etc. */
+		if p.To.Reg == REGTMP || p.Reg == REGTMP {
+			ctxt.Diag("cant synthesize large constant\n%v", p)
+		}
+		d := vregoff(ctxt, &p.From)
+		o1 = loadu32(REGTMP, d)
+		o2 = LOP_IRR(OP_ORI, REGTMP, REGTMP, uint32(int32(d)))
+		r := int(p.Reg)
+		if r == 0 {
+			r = int(p.To.Reg)
+		}
+		o3 = LOP_RRR(uint32(oprrr(ctxt, int(p.As))), uint32(p.To.Reg), REGTMP, uint32(r))
+		if p.From.Sym != nil {
+			ctxt.Diag("%v is not supported", p)
+		}
+
+		//if(dlm) reloc(&p->from, p->pc, 0);
+
+		/*24*/
+	case 25:
+		/* sld[.] $sh,rS,rA -> rldicr[.] $sh,rS,mask(0,63-sh),rA; srd[.] -> rldicl */
+		v := regoff(ctxt, &p.From)
+
+		if v < 0 {
+			v = 0
+		} else if v > 63 {
+			v = 63
+		}
+		r := int(p.Reg)
+		if r == 0 {
+			r = int(p.To.Reg)
+		}
+		var a int
+		switch p.As {
+		case ASLD, ASLDCC:
+			a = int(63 - v)
+			o1 = OP_RLDICR
+
+		case ASRD, ASRDCC:
+			a = int(v)
+			v = 64 - v
+			o1 = OP_RLDICL
+
+		default:
+			ctxt.Diag("unexpected op in sldi case\n%v", p)
+			a = 0
+			o1 = 0
+		}
+
+		o1 = AOP_RRR(o1, uint32(r), uint32(p.To.Reg), (uint32(v) & 0x1F))
+		o1 |= (uint32(a) & 31) << 6
+		if v&0x20 != 0 {
+			o1 |= 1 << 1
+		}
+		if a&0x20 != 0 {
+			o1 |= 1 << 5 /* mb[5] is top bit */
+		}
+		if p.As == ASLDCC || p.As == ASRDCC {
+			o1 |= 1 /* Rc */
+		}
+
+	case 26: /* mov $lsext/auto/oreg,,r2 ==> addis+addi */
+		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)
+		if r == 0 {
+			r = int(o.param)
+		}
+		o1 = AOP_IRR(OP_ADDIS, REGTMP, uint32(r), uint32(high16adjusted(v)))
+		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)
+
+		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)
+		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)
+		if p.From.Sym != nil {
+			ctxt.Diag("%v is not supported", p)
+		}
+
+	//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)
+
+		d := vregoff(ctxt, p.From3)
+		var mask [2]uint8
+		maskgen64(ctxt, p, mask[:], uint64(d))
+		var a int
+		switch p.As {
+		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:
+			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:
+			a = int(mask[1]) /* ME */
+			if mask[0] != 0 {
+				ctxt.Diag("invalid mask for shift: %x (shift %d)\n%v", uint64(d), v, p)
+			}
+
+		default:
+			ctxt.Diag("unexpected op in rldic case\n%v", p)
+			a = 0
+		}
+
+		o1 = AOP_RRR(uint32(opirr(ctxt, int(p.As))), uint32(p.Reg), uint32(p.To.Reg), (uint32(v) & 0x1F))
+		o1 |= (uint32(a) & 31) << 6
+		if v&0x20 != 0 {
+			o1 |= 1 << 1
+		}
+		if a&0x20 != 0 {
+			o1 |= 1 << 5 /* mb[5] is top bit */
+		}
+
+	case 30: /* rldimi $sh,s,$mask,a */
+		v := regoff(ctxt, &p.From)
+
+		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)
+		}
+		o1 = AOP_RRR(uint32(opirr(ctxt, int(p.As))), uint32(p.Reg), uint32(p.To.Reg), (uint32(v) & 0x1F))
+		o1 |= (uint32(mask[0]) & 31) << 6
+		if v&0x20 != 0 {
+			o1 |= 1 << 1
+		}
+		if mask[0]&0x20 != 0 {
+			o1 |= 1 << 5 /* mb[5] is top bit */
+		}
+
+	case 31: /* dword */
+		d := vregoff(ctxt, &p.From)
+
+		if ctxt.Arch.ByteOrder == binary.BigEndian {
+			o1 = uint32(d >> 32)
+			o2 = uint32(d)
+		} else {
+			o1 = uint32(d)
+			o2 = uint32(d >> 32)
+		}
+
+		if p.From.Sym != nil {
+			rel := obj.Addrel(ctxt.Cursym)
+			rel.Off = int32(ctxt.Pc)
+			rel.Siz = 8
+			rel.Sym = p.From.Sym
+			rel.Add = p.From.Offset
+			rel.Type = obj.R_ADDR
+			o2 = 0
+			o1 = o2
+		}
+
+	case 32: /* fmul frc,fra,frd */
+		r := int(p.Reg)
+
+		if r == 0 {
+			r = int(p.To.Reg)
+		}
+		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)
+
+		if oclass(&p.From) == C_NONE {
+			r = int(p.To.Reg)
+		}
+		o1 = AOP_RRR(uint32(oprrr(ctxt, int(p.As))), uint32(p.To.Reg), 0, uint32(r))
+
+	case 34: /* FMADDx fra,frb,frc,frd (d=a*b+c); FSELx a<0? (d=b): (d=c) */
+		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)
+
+		r := int(p.To.Reg)
+		if r == 0 {
+			r = int(o.param)
+		}
+		o1 = AOP_IRR(OP_ADDIS, REGTMP, uint32(r), uint32(high16adjusted(v)))
+		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)
+
+		r := int(p.From.Reg)
+		if r == 0 {
+			r = int(o.param)
+		}
+		o1 = AOP_IRR(OP_ADDIS, REGTMP, uint32(r), uint32(high16adjusted(v)))
+		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)
+
+		r := int(p.From.Reg)
+		if r == 0 {
+			r = int(o.param)
+		}
+		o1 = AOP_IRR(OP_ADDIS, REGTMP, uint32(r), uint32(high16adjusted(v)))
+		o2 = AOP_IRR(uint32(opload(ctxt, int(p.As))), uint32(p.To.Reg), REGTMP, uint32(v))
+		o3 = LOP_RRR(OP_EXTSB, uint32(p.To.Reg), uint32(p.To.Reg), 0)
+
+	case 40: /* word */
+		o1 = uint32(regoff(ctxt, &p.From))
+
+	case 41: /* stswi */
+		o1 = AOP_RRR(uint32(opirr(ctxt, int(p.As))), uint32(p.From.Reg), uint32(p.To.Reg), 0) | (uint32(regoff(ctxt, p.From3))&0x7F)<<11
+
+	case 42: /* lswi */
+		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) */
+		o1 = AOP_RRR(uint32(oprrr(ctxt, int(p.As))), 0, uint32(p.From.Index), uint32(p.From.Reg))
+
+	case 44: /* indexed store */
+		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 */
+		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)
+
+		if r == 0 {
+			r = int(p.To.Reg)
+		}
+		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)
+
+		if r == 0 {
+			r = int(p.To.Reg)
+		}
+		o1 = LOP_RRR(uint32(oprrr(ctxt, int(p.As))), uint32(p.To.Reg), uint32(r), 0)
+
+	case 49: /* op Rb; op $n, Rb */
+		if p.From.Type != obj.TYPE_REG { /* tlbie $L, rB */
+			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)
+
+		if r == 0 {
+			r = int(p.To.Reg)
+		}
+		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))
+		if p.As == AREMU {
+			o4 = o3
+
+			/* Clear top 32 bits */
+			o3 = OP_RLW(OP_RLDIC, REGTMP, REGTMP, 0, 0, 0) | 1<<5
+		}
+
+	case 51: /* remd[u] r1[,r2],r3 */
+		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 */
+		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
+
+		o1 = AOP_RRR(uint32(oprrr(ctxt, int(p.As))), uint32(v), 0, 0)
+
+	case 53: /* mffsX ,fr1 */
+		o1 = AOP_RRR(OP_MFFS, uint32(p.To.Reg), 0, 0)
+
+	case 54: /* mov msr,r1; mov r1, msr*/
+		if oclass(&p.From) == C_REG {
+			if p.As == AMOVD {
+				o1 = AOP_RRR(OP_MTMSRD, uint32(p.From.Reg), 0, 0)
+			} else {
+				o1 = AOP_RRR(OP_MTMSR, uint32(p.From.Reg), 0, 0)
+			}
+		} else {
+			o1 = AOP_RRR(OP_MFMSR, uint32(p.To.Reg), 0, 0)
+		}
+
+	case 55: /* op Rb, Rd */
+		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)
+
+		r := int(p.Reg)
+		if r == 0 {
+			r = int(p.To.Reg)
+		}
+		o1 = AOP_RRR(uint32(opirr(ctxt, int(p.As))), uint32(r), uint32(p.To.Reg), uint32(v)&31)
+		if p.As == ASRAD && (v&0x20 != 0) {
+			o1 |= 1 << 1 /* mb[5] */
+		}
+
+	case 57: /* slw $sh,[s,]a -> rlwinm ... */
+		v := regoff(ctxt, &p.From)
+
+		r := int(p.Reg)
+		if r == 0 {
+			r = int(p.To.Reg)
+		}
+
+		/*
+			 * Let user (gs) shoot himself in the foot.
+			 * qc has already complained.
+			 *
+			if(v < 0 || v > 31)
+				ctxt->diag("illegal shift %ld\n%v", v, p);
+		*/
+		if v < 0 {
+			v = 0
+		} 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
+			v = 32 - v
+		} else {
+			mask[0] = 0
+			mask[1] = uint8(31 - v)
+		}
+
+		o1 = OP_RLW(OP_RLWINM, uint32(p.To.Reg), uint32(r), uint32(v), uint32(mask[0]), uint32(mask[1]))
+		if p.As == ASLWCC || p.As == ASRWCC {
+			o1 |= 1 /* Rc */
+		}
+
+	case 58: /* logical $andcon,[s],a */
+		v := regoff(ctxt, &p.From)
+
+		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)
+
+		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)
+
+		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)
+
+		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)
+
+		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.From3Type() != obj.TYPE_NONE {
+			v = regoff(ctxt, p.From3) & 255
+		} else {
+			v = 255
+		}
+		o1 = OP_MTFSF | uint32(v)<<17 | uint32(p.From.Reg)<<11
+
+	case 65: /* MOVFL $imm,FPSCR(n) => mtfsfi crfd,imm */
+		if p.To.Reg == 0 {
+			ctxt.Diag("must specify FPSCR(n)\n%v", p)
+		}
+		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)
+			if REG_DCR0 <= v && v <= REG_DCR0+1023 {
+				o1 = OPVCC(31, 451, 0, 0) /* mtdcr */
+			} else {
+				o1 = OPVCC(31, 467, 0, 0) /* mtspr */
+			}
+		} else {
+			r = int(p.To.Reg)
+			v = int32(p.From.Reg)
+			if REG_DCR0 <= v && v <= REG_DCR0+1023 {
+				o1 = OPVCC(31, 323, 0, 0) /* mfdcr */
+			} else {
+				o1 = OPVCC(31, 339, 0, 0) /* mfspr */
+			}
+		}
+
+		o1 = AOP_RRR(o1, uint32(r), 0, 0) | (uint32(v)&0x1f)<<16 | ((uint32(v)>>5)&0x1f)<<11
+
+	case 67: /* mcrf crfD,crfS */
+		if p.From.Type != obj.TYPE_REG || p.From.Reg < REG_CR0 || REG_CR7 < p.From.Reg || p.To.Type != obj.TYPE_REG || p.To.Reg < REG_CR0 || REG_CR7 < p.To.Reg {
+			ctxt.Diag("illegal CR field number\n%v", p)
+		}
+		o1 = AOP_RRR(OP_MCRF, ((uint32(p.To.Reg) & 7) << 2), ((uint32(p.From.Reg) & 7) << 2), 0)
+
+	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 := 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.From3Type() != obj.TYPE_NONE {
+			if p.To.Reg != 0 {
+				ctxt.Diag("can't use both mask and CR(n)\n%v", p)
+			}
+			v = regoff(ctxt, p.From3) & 0xff
+		} else {
+			if p.To.Reg == 0 {
+				v = 0xff /* CR */
+			} else {
+				v = 1 << uint(7-(p.To.Reg&7)) /* CR(n) */
+			}
+		}
+
+		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 {
+			r = (int(p.Reg) & 7) << 2
+		}
+		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 {
+			r = (int(p.Reg) & 7) << 2
+		}
+		o1 = AOP_RRR(uint32(opirr(ctxt, int(p.As))), uint32(r), uint32(p.From.Reg), 0) | uint32(regoff(ctxt, &p.To))&0xffff
+
+	case 72: /* slbmte (Rb+Rs -> slb[Rb]) -> Rs, Rb */
+		o1 = AOP_RRR(uint32(oprrr(ctxt, int(p.As))), uint32(p.From.Reg), 0, uint32(p.To.Reg))
+
+	case 73: /* mcrfs crfD,crfS */
+		if p.From.Type != obj.TYPE_REG || p.From.Reg != REG_FPSCR || p.To.Type != obj.TYPE_REG || p.To.Reg < REG_CR0 || REG_CR7 < p.To.Reg {
+			ctxt.Diag("illegal FPSCR/CR field number\n%v", p)
+		}
+		o1 = AOP_RRR(OP_MCRFS, ((uint32(p.To.Reg) & 7) << 2), ((0 & 7) << 2), 0)
+
+	case 77: /* syscall $scon, syscall Rx */
+		if p.From.Type == obj.TYPE_CONST {
+			if p.From.Offset > BIG || p.From.Offset < -BIG {
+				ctxt.Diag("illegal syscall, sysnum too large: %v", p)
+			}
+			o1 = AOP_IRR(OP_ADDI, REGZERO, REGZERO, uint32(p.From.Offset))
+		} else if p.From.Type == obj.TYPE_REG {
+			o1 = LOP_RRR(OP_OR, REGZERO, uint32(p.From.Reg), uint32(p.From.Reg))
+		} else {
+			ctxt.Diag("illegal syscall: %v", p)
+			o1 = 0x7fe00008 // trap always
+		}
+
+		o2 = uint32(oprrr(ctxt, int(p.As)))
+		o3 = AOP_RRR(uint32(oprrr(ctxt, AXOR)), REGZERO, REGZERO, REGZERO) // XOR R0, R0
+
+	case 78: /* undef */
+		o1 = 0 /* "An instruction consisting entirely of binary 0s is guaranteed
+		   always to be an illegal instruction."  */
+
+		/* relocation operations */
+	case 74:
+		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))
+		addaddrreloc(ctxt, p.To.Sym, &o1, &o2)
+
+	//if(dlm) reloc(&p->to, p->pc, 1);
+
+	case 75:
+		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)
+
+	//if(dlm) reloc(&p->from, p->pc, 1);
+
+	case 76:
+		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)
+		o3 = LOP_RRR(OP_EXTSB, uint32(p.To.Reg), uint32(p.To.Reg), 0)
+
+		//if(dlm) reloc(&p->from, p->pc, 1);
+
+	}
+
+	out[0] = o1
+	out[1] = o2
+	out[2] = o3
+	out[3] = o4
+	out[4] = o5
+	return
+}
+
+func vregoff(ctxt *obj.Link, a *obj.Addr) int64 {
+	ctxt.Instoffset = 0
+	if a != nil {
+		aclass(ctxt, a)
+	}
+	return ctxt.Instoffset
+}
+
+func regoff(ctxt *obj.Link, a *obj.Addr) int32 {
+	return int32(vregoff(ctxt, a))
+}
+
+func oprrr(ctxt *obj.Link, a int) int32 {
+	switch a {
+	case AADD:
+		return int32(OPVCC(31, 266, 0, 0))
+	case AADDCC:
+		return int32(OPVCC(31, 266, 0, 1))
+	case AADDV:
+		return int32(OPVCC(31, 266, 1, 0))
+	case AADDVCC:
+		return int32(OPVCC(31, 266, 1, 1))
+	case AADDC:
+		return int32(OPVCC(31, 10, 0, 0))
+	case AADDCCC:
+		return int32(OPVCC(31, 10, 0, 1))
+	case AADDCV:
+		return int32(OPVCC(31, 10, 1, 0))
+	case AADDCVCC:
+		return int32(OPVCC(31, 10, 1, 1))
+	case AADDE:
+		return int32(OPVCC(31, 138, 0, 0))
+	case AADDECC:
+		return int32(OPVCC(31, 138, 0, 1))
+	case AADDEV:
+		return int32(OPVCC(31, 138, 1, 0))
+	case AADDEVCC:
+		return int32(OPVCC(31, 138, 1, 1))
+	case AADDME:
+		return int32(OPVCC(31, 234, 0, 0))
+	case AADDMECC:
+		return int32(OPVCC(31, 234, 0, 1))
+	case AADDMEV:
+		return int32(OPVCC(31, 234, 1, 0))
+	case AADDMEVCC:
+		return int32(OPVCC(31, 234, 1, 1))
+	case AADDZE:
+		return int32(OPVCC(31, 202, 0, 0))
+	case AADDZECC:
+		return int32(OPVCC(31, 202, 0, 1))
+	case AADDZEV:
+		return int32(OPVCC(31, 202, 1, 0))
+	case AADDZEVCC:
+		return int32(OPVCC(31, 202, 1, 1))
+
+	case AAND:
+		return int32(OPVCC(31, 28, 0, 0))
+	case AANDCC:
+		return int32(OPVCC(31, 28, 0, 1))
+	case AANDN:
+		return int32(OPVCC(31, 60, 0, 0))
+	case AANDNCC:
+		return int32(OPVCC(31, 60, 0, 1))
+
+	case ACMP:
+		return int32(OPVCC(31, 0, 0, 0) | 1<<21) /* L=1 */
+	case ACMPU:
+		return int32(OPVCC(31, 32, 0, 0) | 1<<21)
+	case ACMPW:
+		return int32(OPVCC(31, 0, 0, 0)) /* L=0 */
+	case ACMPWU:
+		return int32(OPVCC(31, 32, 0, 0))
+
+	case ACNTLZW:
+		return int32(OPVCC(31, 26, 0, 0))
+	case ACNTLZWCC:
+		return int32(OPVCC(31, 26, 0, 1))
+	case ACNTLZD:
+		return int32(OPVCC(31, 58, 0, 0))
+	case ACNTLZDCC:
+		return int32(OPVCC(31, 58, 0, 1))
+
+	case ACRAND:
+		return int32(OPVCC(19, 257, 0, 0))
+	case ACRANDN:
+		return int32(OPVCC(19, 129, 0, 0))
+	case ACREQV:
+		return int32(OPVCC(19, 289, 0, 0))
+	case ACRNAND:
+		return int32(OPVCC(19, 225, 0, 0))
+	case ACRNOR:
+		return int32(OPVCC(19, 33, 0, 0))
+	case ACROR:
+		return int32(OPVCC(19, 449, 0, 0))
+	case ACRORN:
+		return int32(OPVCC(19, 417, 0, 0))
+	case ACRXOR:
+		return int32(OPVCC(19, 193, 0, 0))
+
+	case ADCBF:
+		return int32(OPVCC(31, 86, 0, 0))
+	case ADCBI:
+		return int32(OPVCC(31, 470, 0, 0))
+	case ADCBST:
+		return int32(OPVCC(31, 54, 0, 0))
+	case ADCBT:
+		return int32(OPVCC(31, 278, 0, 0))
+	case ADCBTST:
+		return int32(OPVCC(31, 246, 0, 0))
+	case ADCBZ:
+		return int32(OPVCC(31, 1014, 0, 0))
+
+	case AREM, ADIVW:
+		return int32(OPVCC(31, 491, 0, 0))
+
+	case AREMCC, ADIVWCC:
+		return int32(OPVCC(31, 491, 0, 1))
+
+	case AREMV, ADIVWV:
+		return int32(OPVCC(31, 491, 1, 0))
+
+	case AREMVCC, ADIVWVCC:
+		return int32(OPVCC(31, 491, 1, 1))
+
+	case AREMU, ADIVWU:
+		return int32(OPVCC(31, 459, 0, 0))
+
+	case AREMUCC, ADIVWUCC:
+		return int32(OPVCC(31, 459, 0, 1))
+
+	case AREMUV, ADIVWUV:
+		return int32(OPVCC(31, 459, 1, 0))
+
+	case AREMUVCC, ADIVWUVCC:
+		return int32(OPVCC(31, 459, 1, 1))
+
+	case AREMD, ADIVD:
+		return int32(OPVCC(31, 489, 0, 0))
+
+	case AREMDCC, ADIVDCC:
+		return int32(OPVCC(31, 489, 0, 1))
+
+	case AREMDV, ADIVDV:
+		return int32(OPVCC(31, 489, 1, 0))
+
+	case AREMDVCC, ADIVDVCC:
+		return int32(OPVCC(31, 489, 1, 1))
+
+	case AREMDU, ADIVDU:
+		return int32(OPVCC(31, 457, 0, 0))
+
+	case AREMDUCC, ADIVDUCC:
+		return int32(OPVCC(31, 457, 0, 1))
+
+	case AREMDUV, ADIVDUV:
+		return int32(OPVCC(31, 457, 1, 0))
+
+	case AREMDUVCC, ADIVDUVCC:
+		return int32(OPVCC(31, 457, 1, 1))
+
+	case AEIEIO:
+		return int32(OPVCC(31, 854, 0, 0))
+
+	case AEQV:
+		return int32(OPVCC(31, 284, 0, 0))
+	case AEQVCC:
+		return int32(OPVCC(31, 284, 0, 1))
+
+	case AEXTSB:
+		return int32(OPVCC(31, 954, 0, 0))
+	case AEXTSBCC:
+		return int32(OPVCC(31, 954, 0, 1))
+	case AEXTSH:
+		return int32(OPVCC(31, 922, 0, 0))
+	case AEXTSHCC:
+		return int32(OPVCC(31, 922, 0, 1))
+	case AEXTSW:
+		return int32(OPVCC(31, 986, 0, 0))
+	case AEXTSWCC:
+		return int32(OPVCC(31, 986, 0, 1))
+
+	case AFABS:
+		return int32(OPVCC(63, 264, 0, 0))
+	case AFABSCC:
+		return int32(OPVCC(63, 264, 0, 1))
+	case AFADD:
+		return int32(OPVCC(63, 21, 0, 0))
+	case AFADDCC:
+		return int32(OPVCC(63, 21, 0, 1))
+	case AFADDS:
+		return int32(OPVCC(59, 21, 0, 0))
+	case AFADDSCC:
+		return int32(OPVCC(59, 21, 0, 1))
+	case AFCMPO:
+		return int32(OPVCC(63, 32, 0, 0))
+	case AFCMPU:
+		return int32(OPVCC(63, 0, 0, 0))
+	case AFCFID:
+		return int32(OPVCC(63, 846, 0, 0))
+	case AFCFIDCC:
+		return int32(OPVCC(63, 846, 0, 1))
+	case AFCTIW:
+		return int32(OPVCC(63, 14, 0, 0))
+	case AFCTIWCC:
+		return int32(OPVCC(63, 14, 0, 1))
+	case AFCTIWZ:
+		return int32(OPVCC(63, 15, 0, 0))
+	case AFCTIWZCC:
+		return int32(OPVCC(63, 15, 0, 1))
+	case AFCTID:
+		return int32(OPVCC(63, 814, 0, 0))
+	case AFCTIDCC:
+		return int32(OPVCC(63, 814, 0, 1))
+	case AFCTIDZ:
+		return int32(OPVCC(63, 815, 0, 0))
+	case AFCTIDZCC:
+		return int32(OPVCC(63, 815, 0, 1))
+	case AFDIV:
+		return int32(OPVCC(63, 18, 0, 0))
+	case AFDIVCC:
+		return int32(OPVCC(63, 18, 0, 1))
+	case AFDIVS:
+		return int32(OPVCC(59, 18, 0, 0))
+	case AFDIVSCC:
+		return int32(OPVCC(59, 18, 0, 1))
+	case AFMADD:
+		return int32(OPVCC(63, 29, 0, 0))
+	case AFMADDCC:
+		return int32(OPVCC(63, 29, 0, 1))
+	case AFMADDS:
+		return int32(OPVCC(59, 29, 0, 0))
+	case AFMADDSCC:
+		return int32(OPVCC(59, 29, 0, 1))
+
+	case AFMOVS, AFMOVD:
+		return int32(OPVCC(63, 72, 0, 0)) /* load */
+	case AFMOVDCC:
+		return int32(OPVCC(63, 72, 0, 1))
+	case AFMSUB:
+		return int32(OPVCC(63, 28, 0, 0))
+	case AFMSUBCC:
+		return int32(OPVCC(63, 28, 0, 1))
+	case AFMSUBS:
+		return int32(OPVCC(59, 28, 0, 0))
+	case AFMSUBSCC:
+		return int32(OPVCC(59, 28, 0, 1))
+	case AFMUL:
+		return int32(OPVCC(63, 25, 0, 0))
+	case AFMULCC:
+		return int32(OPVCC(63, 25, 0, 1))
+	case AFMULS:
+		return int32(OPVCC(59, 25, 0, 0))
+	case AFMULSCC:
+		return int32(OPVCC(59, 25, 0, 1))
+	case AFNABS:
+		return int32(OPVCC(63, 136, 0, 0))
+	case AFNABSCC:
+		return int32(OPVCC(63, 136, 0, 1))
+	case AFNEG:
+		return int32(OPVCC(63, 40, 0, 0))
+	case AFNEGCC:
+		return int32(OPVCC(63, 40, 0, 1))
+	case AFNMADD:
+		return int32(OPVCC(63, 31, 0, 0))
+	case AFNMADDCC:
+		return int32(OPVCC(63, 31, 0, 1))
+	case AFNMADDS:
+		return int32(OPVCC(59, 31, 0, 0))
+	case AFNMADDSCC:
+		return int32(OPVCC(59, 31, 0, 1))
+	case AFNMSUB:
+		return int32(OPVCC(63, 30, 0, 0))
+	case AFNMSUBCC:
+		return int32(OPVCC(63, 30, 0, 1))
+	case AFNMSUBS:
+		return int32(OPVCC(59, 30, 0, 0))
+	case AFNMSUBSCC:
+		return int32(OPVCC(59, 30, 0, 1))
+	case AFRES:
+		return int32(OPVCC(59, 24, 0, 0))
+	case AFRESCC:
+		return int32(OPVCC(59, 24, 0, 1))
+	case AFRSP:
+		return int32(OPVCC(63, 12, 0, 0))
+	case AFRSPCC:
+		return int32(OPVCC(63, 12, 0, 1))
+	case AFRSQRTE:
+		return int32(OPVCC(63, 26, 0, 0))
+	case AFRSQRTECC:
+		return int32(OPVCC(63, 26, 0, 1))
+	case AFSEL:
+		return int32(OPVCC(63, 23, 0, 0))
+	case AFSELCC:
+		return int32(OPVCC(63, 23, 0, 1))
+	case AFSQRT:
+		return int32(OPVCC(63, 22, 0, 0))
+	case AFSQRTCC:
+		return int32(OPVCC(63, 22, 0, 1))
+	case AFSQRTS:
+		return int32(OPVCC(59, 22, 0, 0))
+	case AFSQRTSCC:
+		return int32(OPVCC(59, 22, 0, 1))
+	case AFSUB:
+		return int32(OPVCC(63, 20, 0, 0))
+	case AFSUBCC:
+		return int32(OPVCC(63, 20, 0, 1))
+	case AFSUBS:
+		return int32(OPVCC(59, 20, 0, 0))
+	case AFSUBSCC:
+		return int32(OPVCC(59, 20, 0, 1))
+
+	case AICBI:
+		return int32(OPVCC(31, 982, 0, 0))
+	case AISYNC:
+		return int32(OPVCC(19, 150, 0, 0))
+
+	case AMTFSB0:
+		return int32(OPVCC(63, 70, 0, 0))
+	case AMTFSB0CC:
+		return int32(OPVCC(63, 70, 0, 1))
+	case AMTFSB1:
+		return int32(OPVCC(63, 38, 0, 0))
+	case AMTFSB1CC:
+		return int32(OPVCC(63, 38, 0, 1))
+
+	case AMULHW:
+		return int32(OPVCC(31, 75, 0, 0))
+	case AMULHWCC:
+		return int32(OPVCC(31, 75, 0, 1))
+	case AMULHWU:
+		return int32(OPVCC(31, 11, 0, 0))
+	case AMULHWUCC:
+		return int32(OPVCC(31, 11, 0, 1))
+	case AMULLW:
+		return int32(OPVCC(31, 235, 0, 0))
+	case AMULLWCC:
+		return int32(OPVCC(31, 235, 0, 1))
+	case AMULLWV:
+		return int32(OPVCC(31, 235, 1, 0))
+	case AMULLWVCC:
+		return int32(OPVCC(31, 235, 1, 1))
+
+	case AMULHD:
+		return int32(OPVCC(31, 73, 0, 0))
+	case AMULHDCC:
+		return int32(OPVCC(31, 73, 0, 1))
+	case AMULHDU:
+		return int32(OPVCC(31, 9, 0, 0))
+	case AMULHDUCC:
+		return int32(OPVCC(31, 9, 0, 1))
+	case AMULLD:
+		return int32(OPVCC(31, 233, 0, 0))
+	case AMULLDCC:
+		return int32(OPVCC(31, 233, 0, 1))
+	case AMULLDV:
+		return int32(OPVCC(31, 233, 1, 0))
+	case AMULLDVCC:
+		return int32(OPVCC(31, 233, 1, 1))
+
+	case ANAND:
+		return int32(OPVCC(31, 476, 0, 0))
+	case ANANDCC:
+		return int32(OPVCC(31, 476, 0, 1))
+	case ANEG:
+		return int32(OPVCC(31, 104, 0, 0))
+	case ANEGCC:
+		return int32(OPVCC(31, 104, 0, 1))
+	case ANEGV:
+		return int32(OPVCC(31, 104, 1, 0))
+	case ANEGVCC:
+		return int32(OPVCC(31, 104, 1, 1))
+	case ANOR:
+		return int32(OPVCC(31, 124, 0, 0))
+	case ANORCC:
+		return int32(OPVCC(31, 124, 0, 1))
+	case AOR:
+		return int32(OPVCC(31, 444, 0, 0))
+	case AORCC:
+		return int32(OPVCC(31, 444, 0, 1))
+	case AORN:
+		return int32(OPVCC(31, 412, 0, 0))
+	case AORNCC:
+		return int32(OPVCC(31, 412, 0, 1))
+
+	case ARFI:
+		return int32(OPVCC(19, 50, 0, 0))
+	case ARFCI:
+		return int32(OPVCC(19, 51, 0, 0))
+	case ARFID:
+		return int32(OPVCC(19, 18, 0, 0))
+	case AHRFID:
+		return int32(OPVCC(19, 274, 0, 0))
+
+	case ARLWMI:
+		return int32(OPVCC(20, 0, 0, 0))
+	case ARLWMICC:
+		return int32(OPVCC(20, 0, 0, 1))
+	case ARLWNM:
+		return int32(OPVCC(23, 0, 0, 0))
+	case ARLWNMCC:
+		return int32(OPVCC(23, 0, 0, 1))
+
+	case ARLDCL:
+		return int32(OPVCC(30, 8, 0, 0))
+	case ARLDCR:
+		return int32(OPVCC(30, 9, 0, 0))
+
+	case ASYSCALL:
+		return int32(OPVCC(17, 1, 0, 0))
+
+	case ASLW:
+		return int32(OPVCC(31, 24, 0, 0))
+	case ASLWCC:
+		return int32(OPVCC(31, 24, 0, 1))
+	case ASLD:
+		return int32(OPVCC(31, 27, 0, 0))
+	case ASLDCC:
+		return int32(OPVCC(31, 27, 0, 1))
+
+	case ASRAW:
+		return int32(OPVCC(31, 792, 0, 0))
+	case ASRAWCC:
+		return int32(OPVCC(31, 792, 0, 1))
+	case ASRAD:
+		return int32(OPVCC(31, 794, 0, 0))
+	case ASRADCC:
+		return int32(OPVCC(31, 794, 0, 1))
+
+	case ASRW:
+		return int32(OPVCC(31, 536, 0, 0))
+	case ASRWCC:
+		return int32(OPVCC(31, 536, 0, 1))
+	case ASRD:
+		return int32(OPVCC(31, 539, 0, 0))
+	case ASRDCC:
+		return int32(OPVCC(31, 539, 0, 1))
+
+	case ASUB:
+		return int32(OPVCC(31, 40, 0, 0))
+	case ASUBCC:
+		return int32(OPVCC(31, 40, 0, 1))
+	case ASUBV:
+		return int32(OPVCC(31, 40, 1, 0))
+	case ASUBVCC:
+		return int32(OPVCC(31, 40, 1, 1))
+	case ASUBC:
+		return int32(OPVCC(31, 8, 0, 0))
+	case ASUBCCC:
+		return int32(OPVCC(31, 8, 0, 1))
+	case ASUBCV:
+		return int32(OPVCC(31, 8, 1, 0))
+	case ASUBCVCC:
+		return int32(OPVCC(31, 8, 1, 1))
+	case ASUBE:
+		return int32(OPVCC(31, 136, 0, 0))
+	case ASUBECC:
+		return int32(OPVCC(31, 136, 0, 1))
+	case ASUBEV:
+		return int32(OPVCC(31, 136, 1, 0))
+	case ASUBEVCC:
+		return int32(OPVCC(31, 136, 1, 1))
+	case ASUBME:
+		return int32(OPVCC(31, 232, 0, 0))
+	case ASUBMECC:
+		return int32(OPVCC(31, 232, 0, 1))
+	case ASUBMEV:
+		return int32(OPVCC(31, 232, 1, 0))
+	case ASUBMEVCC:
+		return int32(OPVCC(31, 232, 1, 1))
+	case ASUBZE:
+		return int32(OPVCC(31, 200, 0, 0))
+	case ASUBZECC:
+		return int32(OPVCC(31, 200, 0, 1))
+	case ASUBZEV:
+		return int32(OPVCC(31, 200, 1, 0))
+	case ASUBZEVCC:
+		return int32(OPVCC(31, 200, 1, 1))
+
+	case ASYNC:
+		return int32(OPVCC(31, 598, 0, 0))
+	case APTESYNC:
+		return int32(OPVCC(31, 598, 0, 0) | 2<<21)
+
+	case ATLBIE:
+		return int32(OPVCC(31, 306, 0, 0))
+	case ATLBIEL:
+		return int32(OPVCC(31, 274, 0, 0))
+	case ATLBSYNC:
+		return int32(OPVCC(31, 566, 0, 0))
+	case ASLBIA:
+		return int32(OPVCC(31, 498, 0, 0))
+	case ASLBIE:
+		return int32(OPVCC(31, 434, 0, 0))
+	case ASLBMFEE:
+		return int32(OPVCC(31, 915, 0, 0))
+	case ASLBMFEV:
+		return int32(OPVCC(31, 851, 0, 0))
+	case ASLBMTE:
+		return int32(OPVCC(31, 402, 0, 0))
+
+	case ATW:
+		return int32(OPVCC(31, 4, 0, 0))
+	case ATD:
+		return int32(OPVCC(31, 68, 0, 0))
+
+	case AXOR:
+		return int32(OPVCC(31, 316, 0, 0))
+	case AXORCC:
+		return int32(OPVCC(31, 316, 0, 1))
+	}
+
+	ctxt.Diag("bad r/r opcode %v", obj.Aconv(a))
+	return 0
+}
+
+func opirr(ctxt *obj.Link, a int) int32 {
+	switch a {
+	case AADD:
+		return int32(OPVCC(14, 0, 0, 0))
+	case AADDC:
+		return int32(OPVCC(12, 0, 0, 0))
+	case AADDCCC:
+		return int32(OPVCC(13, 0, 0, 0))
+	case AADD + ALAST:
+		return int32(OPVCC(15, 0, 0, 0)) /* ADDIS/CAU */
+
+	case AANDCC:
+		return int32(OPVCC(28, 0, 0, 0))
+	case AANDCC + ALAST:
+		return int32(OPVCC(29, 0, 0, 0)) /* ANDIS./ANDIU. */
+
+	case ABR:
+		return int32(OPVCC(18, 0, 0, 0))
+	case ABL:
+		return int32(OPVCC(18, 0, 0, 0) | 1)
+	case obj.ADUFFZERO:
+		return int32(OPVCC(18, 0, 0, 0) | 1)
+	case obj.ADUFFCOPY:
+		return int32(OPVCC(18, 0, 0, 0) | 1)
+	case ABC:
+		return int32(OPVCC(16, 0, 0, 0))
+	case ABCL:
+		return int32(OPVCC(16, 0, 0, 0) | 1)
+
+	case ABEQ:
+		return int32(AOP_RRR(16<<26, 12, 2, 0))
+	case ABGE:
+		return int32(AOP_RRR(16<<26, 4, 0, 0))
+	case ABGT:
+		return int32(AOP_RRR(16<<26, 12, 1, 0))
+	case ABLE:
+		return int32(AOP_RRR(16<<26, 4, 1, 0))
+	case ABLT:
+		return int32(AOP_RRR(16<<26, 12, 0, 0))
+	case ABNE:
+		return int32(AOP_RRR(16<<26, 4, 2, 0))
+	case ABVC:
+		return int32(AOP_RRR(16<<26, 4, 3, 0))
+	case ABVS:
+		return int32(AOP_RRR(16<<26, 12, 3, 0))
+
+	case ACMP:
+		return int32(OPVCC(11, 0, 0, 0) | 1<<21) /* L=1 */
+	case ACMPU:
+		return int32(OPVCC(10, 0, 0, 0) | 1<<21)
+	case ACMPW:
+		return int32(OPVCC(11, 0, 0, 0)) /* L=0 */
+	case ACMPWU:
+		return int32(OPVCC(10, 0, 0, 0))
+	case ALSW:
+		return int32(OPVCC(31, 597, 0, 0))
+
+	case AMULLW:
+		return int32(OPVCC(7, 0, 0, 0))
+
+	case AOR:
+		return int32(OPVCC(24, 0, 0, 0))
+	case AOR + ALAST:
+		return int32(OPVCC(25, 0, 0, 0)) /* ORIS/ORIU */
+
+	case ARLWMI:
+		return int32(OPVCC(20, 0, 0, 0)) /* rlwimi */
+	case ARLWMICC:
+		return int32(OPVCC(20, 0, 0, 1))
+	case ARLDMI:
+		return int32(OPVCC(30, 0, 0, 0) | 3<<2) /* rldimi */
+	case ARLDMICC:
+		return int32(OPVCC(30, 0, 0, 1) | 3<<2)
+
+	case ARLWNM:
+		return int32(OPVCC(21, 0, 0, 0)) /* rlwinm */
+	case ARLWNMCC:
+		return int32(OPVCC(21, 0, 0, 1))
+
+	case ARLDCL:
+		return int32(OPVCC(30, 0, 0, 0)) /* rldicl */
+	case ARLDCLCC:
+		return int32(OPVCC(30, 0, 0, 1))
+	case ARLDCR:
+		return int32(OPVCC(30, 1, 0, 0)) /* rldicr */
+	case ARLDCRCC:
+		return int32(OPVCC(30, 1, 0, 1))
+	case ARLDC:
+		return int32(OPVCC(30, 0, 0, 0) | 2<<2)
+	case ARLDCCC:
+		return int32(OPVCC(30, 0, 0, 1) | 2<<2)
+
+	case ASRAW:
+		return int32(OPVCC(31, 824, 0, 0))
+	case ASRAWCC:
+		return int32(OPVCC(31, 824, 0, 1))
+	case ASRAD:
+		return int32(OPVCC(31, (413 << 1), 0, 0))
+	case ASRADCC:
+		return int32(OPVCC(31, (413 << 1), 0, 1))
+
+	case ASTSW:
+		return int32(OPVCC(31, 725, 0, 0))
+
+	case ASUBC:
+		return int32(OPVCC(8, 0, 0, 0))
+
+	case ATW:
+		return int32(OPVCC(3, 0, 0, 0))
+	case ATD:
+		return int32(OPVCC(2, 0, 0, 0))
+
+	case AXOR:
+		return int32(OPVCC(26, 0, 0, 0)) /* XORIL */
+	case AXOR + ALAST:
+		return int32(OPVCC(27, 0, 0, 0)) /* XORIU */
+	}
+
+	ctxt.Diag("bad opcode i/r %v", obj.Aconv(a))
+	return 0
+}
+
+/*
+ * load o(a),d
+ */
+func opload(ctxt *obj.Link, a int) int32 {
+	switch a {
+	case AMOVD:
+		return int32(OPVCC(58, 0, 0, 0)) /* ld */
+	case AMOVDU:
+		return int32(OPVCC(58, 0, 0, 1)) /* ldu */
+	case AMOVWZ:
+		return int32(OPVCC(32, 0, 0, 0)) /* lwz */
+	case AMOVWZU:
+		return int32(OPVCC(33, 0, 0, 0)) /* lwzu */
+	case AMOVW:
+		return int32(OPVCC(58, 0, 0, 0) | 1<<1) /* lwa */
+
+		/* no AMOVWU */
+	case AMOVB, AMOVBZ:
+		return int32(OPVCC(34, 0, 0, 0))
+		/* load */
+
+	case AMOVBU, AMOVBZU:
+		return int32(OPVCC(35, 0, 0, 0))
+	case AFMOVD:
+		return int32(OPVCC(50, 0, 0, 0))
+	case AFMOVDU:
+		return int32(OPVCC(51, 0, 0, 0))
+	case AFMOVS:
+		return int32(OPVCC(48, 0, 0, 0))
+	case AFMOVSU:
+		return int32(OPVCC(49, 0, 0, 0))
+	case AMOVH:
+		return int32(OPVCC(42, 0, 0, 0))
+	case AMOVHU:
+		return int32(OPVCC(43, 0, 0, 0))
+	case AMOVHZ:
+		return int32(OPVCC(40, 0, 0, 0))
+	case AMOVHZU:
+		return int32(OPVCC(41, 0, 0, 0))
+	case AMOVMW:
+		return int32(OPVCC(46, 0, 0, 0)) /* lmw */
+	}
+
+	ctxt.Diag("bad load opcode %v", obj.Aconv(a))
+	return 0
+}
+
+/*
+ * indexed load a(b),d
+ */
+func oploadx(ctxt *obj.Link, a int) int32 {
+	switch a {
+	case AMOVWZ:
+		return int32(OPVCC(31, 23, 0, 0)) /* lwzx */
+	case AMOVWZU:
+		return int32(OPVCC(31, 55, 0, 0)) /* lwzux */
+	case AMOVW:
+		return int32(OPVCC(31, 341, 0, 0)) /* lwax */
+	case AMOVWU:
+		return int32(OPVCC(31, 373, 0, 0)) /* lwaux */
+
+	case AMOVB, AMOVBZ:
+		return int32(OPVCC(31, 87, 0, 0)) /* lbzx */
+
+	case AMOVBU, AMOVBZU:
+		return int32(OPVCC(31, 119, 0, 0)) /* lbzux */
+	case AFMOVD:
+		return int32(OPVCC(31, 599, 0, 0)) /* lfdx */
+	case AFMOVDU:
+		return int32(OPVCC(31, 631, 0, 0)) /*  lfdux */
+	case AFMOVS:
+		return int32(OPVCC(31, 535, 0, 0)) /* lfsx */
+	case AFMOVSU:
+		return int32(OPVCC(31, 567, 0, 0)) /* lfsux */
+	case AMOVH:
+		return int32(OPVCC(31, 343, 0, 0)) /* lhax */
+	case AMOVHU:
+		return int32(OPVCC(31, 375, 0, 0)) /* lhaux */
+	case AMOVHBR:
+		return int32(OPVCC(31, 790, 0, 0)) /* lhbrx */
+	case AMOVWBR:
+		return int32(OPVCC(31, 534, 0, 0)) /* lwbrx */
+	case AMOVHZ:
+		return int32(OPVCC(31, 279, 0, 0)) /* lhzx */
+	case AMOVHZU:
+		return int32(OPVCC(31, 311, 0, 0)) /* lhzux */
+	case AECIWX:
+		return int32(OPVCC(31, 310, 0, 0)) /* eciwx */
+	case ALWAR:
+		return int32(OPVCC(31, 20, 0, 0)) /* lwarx */
+	case ALDAR:
+		return int32(OPVCC(31, 84, 0, 0))
+	case ALSW:
+		return int32(OPVCC(31, 533, 0, 0)) /* lswx */
+	case AMOVD:
+		return int32(OPVCC(31, 21, 0, 0)) /* ldx */
+	case AMOVDU:
+		return int32(OPVCC(31, 53, 0, 0)) /* ldux */
+	}
+
+	ctxt.Diag("bad loadx opcode %v", obj.Aconv(a))
+	return 0
+}
+
+/*
+ * store s,o(d)
+ */
+func opstore(ctxt *obj.Link, a int) int32 {
+	switch a {
+	case AMOVB, AMOVBZ:
+		return int32(OPVCC(38, 0, 0, 0)) /* stb */
+
+	case AMOVBU, AMOVBZU:
+		return int32(OPVCC(39, 0, 0, 0)) /* stbu */
+	case AFMOVD:
+		return int32(OPVCC(54, 0, 0, 0)) /* stfd */
+	case AFMOVDU:
+		return int32(OPVCC(55, 0, 0, 0)) /* stfdu */
+	case AFMOVS:
+		return int32(OPVCC(52, 0, 0, 0)) /* stfs */
+	case AFMOVSU:
+		return int32(OPVCC(53, 0, 0, 0)) /* stfsu */
+
+	case AMOVHZ, AMOVH:
+		return int32(OPVCC(44, 0, 0, 0)) /* sth */
+
+	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:
+		return int32(OPVCC(36, 0, 0, 0)) /* stw */
+
+	case AMOVWZU, AMOVWU:
+		return int32(OPVCC(37, 0, 0, 0)) /* stwu */
+	case AMOVD:
+		return int32(OPVCC(62, 0, 0, 0)) /* std */
+	case AMOVDU:
+		return int32(OPVCC(62, 0, 0, 1)) /* stdu */
+	}
+
+	ctxt.Diag("unknown store opcode %v", obj.Aconv(a))
+	return 0
+}
+
+/*
+ * indexed store s,a(b)
+ */
+func opstorex(ctxt *obj.Link, a int) int32 {
+	switch a {
+	case AMOVB, AMOVBZ:
+		return int32(OPVCC(31, 215, 0, 0)) /* stbx */
+
+	case AMOVBU, AMOVBZU:
+		return int32(OPVCC(31, 247, 0, 0)) /* stbux */
+	case AFMOVD:
+		return int32(OPVCC(31, 727, 0, 0)) /* stfdx */
+	case AFMOVDU:
+		return int32(OPVCC(31, 759, 0, 0)) /* stfdux */
+	case AFMOVS:
+		return int32(OPVCC(31, 663, 0, 0)) /* stfsx */
+	case AFMOVSU:
+		return int32(OPVCC(31, 695, 0, 0)) /* stfsux */
+
+	case AMOVHZ, AMOVH:
+		return int32(OPVCC(31, 407, 0, 0)) /* sthx */
+	case AMOVHBR:
+		return int32(OPVCC(31, 918, 0, 0)) /* sthbrx */
+
+	case AMOVHZU, AMOVHU:
+		return int32(OPVCC(31, 439, 0, 0)) /* sthux */
+
+	case AMOVWZ, AMOVW:
+		return int32(OPVCC(31, 151, 0, 0)) /* stwx */
+
+	case AMOVWZU, AMOVWU:
+		return int32(OPVCC(31, 183, 0, 0)) /* stwux */
+	case ASTSW:
+		return int32(OPVCC(31, 661, 0, 0)) /* stswx */
+	case AMOVWBR:
+		return int32(OPVCC(31, 662, 0, 0)) /* stwbrx */
+	case ASTWCCC:
+		return int32(OPVCC(31, 150, 0, 1)) /* stwcx. */
+	case ASTDCCC:
+		return int32(OPVCC(31, 214, 0, 1)) /* stwdx. */
+	case AECOWX:
+		return int32(OPVCC(31, 438, 0, 0)) /* ecowx */
+	case AMOVD:
+		return int32(OPVCC(31, 149, 0, 0)) /* stdx */
+	case AMOVDU:
+		return int32(OPVCC(31, 181, 0, 0)) /* stdux */
+	}
+
+	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
new file mode 100644
index 0000000..4cdcfbc
--- /dev/null
+++ b/src/cmd/internal/obj/ppc64/list9.go
@@ -0,0 +1,98 @@
+// cmd/9l/list.c from Vita Nuova.
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
+
+package ppc64
+
+import (
+	"cmd/internal/obj"
+	"fmt"
+)
+
+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)
+	}
+	if REG_F0 <= r && r <= REG_F31 {
+		return fmt.Sprintf("F%d", r-REG_F0)
+	}
+	if REG_CR0 <= r && r <= REG_CR7 {
+		return fmt.Sprintf("CR%d", r-REG_CR0)
+	}
+	if r == REG_CR {
+		return "CR"
+	}
+	if REG_SPR0 <= r && r <= REG_SPR0+1023 {
+		switch r {
+		case REG_XER:
+			return "XER"
+
+		case REG_LR:
+			return "LR"
+
+		case REG_CTR:
+			return "CTR"
+		}
+
+		return fmt.Sprintf("SPR(%d)", r-REG_SPR0)
+	}
+
+	if REG_DCR0 <= r && r <= REG_DCR0+1023 {
+		return fmt.Sprintf("DCR(%d)", r-REG_DCR0)
+	}
+	if r == REG_FPSCR {
+		return "FPSCR"
+	}
+	if r == REG_MSR {
+		return "MSR"
+	}
+
+	return fmt.Sprintf("Rgok(%d)", r-obj.RBasePPC64)
+}
+
+func DRconv(a int) string {
+	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
new file mode 100644
index 0000000..1eddc6f
--- /dev/null
+++ b/src/cmd/internal/obj/ppc64/obj9.go
@@ -0,0 +1,968 @@
+// cmd/9l/noop.c, cmd/9l/pass.c, cmd/9l/span.c from Vita Nuova.
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
+
+package ppc64
+
+import (
+	"cmd/internal/obj"
+	"encoding/binary"
+	"fmt"
+	"math"
+)
+
+func progedit(ctxt *obj.Link, p *obj.Prog) {
+	p.From.Class = 0
+	p.To.Class = 0
+
+	// Rewrite BR/BL to symbol as TYPE_BRANCH.
+	switch p.As {
+	case ABR,
+		ABL,
+		obj.ARET,
+		obj.ADUFFZERO,
+		obj.ADUFFCOPY:
+		if p.To.Sym != nil {
+			p.To.Type = obj.TYPE_BRANCH
+		}
+	}
+
+	// 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", 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", 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
+		}
+
+		// 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)
+			s.Size = 8
+			p.From.Type = obj.TYPE_MEM
+			p.From.Sym = s
+			p.From.Name = obj.NAME_EXTERN
+			p.From.Offset = 0
+		}
+	}
+
+	// Rewrite SUB constants into ADD.
+	switch p.As {
+	case ASUBC:
+		if p.From.Type == obj.TYPE_CONST {
+			p.From.Offset = -p.From.Offset
+			p.As = AADDC
+		}
+
+	case ASUBCCC:
+		if p.From.Type == obj.TYPE_CONST {
+			p.From.Offset = -p.From.Offset
+			p.As = AADDCCC
+		}
+
+	case ASUB:
+		if p.From.Type == obj.TYPE_CONST {
+			p.From.Offset = -p.From.Offset
+			p.As = AADD
+		}
+	}
+}
+
+func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
+	// TODO(minux): add morestack short-cuts with small fixed frame-size.
+	ctxt.Cursym = cursym
+
+	if cursym.Text == nil || cursym.Text.Link == nil {
+		return
+	}
+
+	p := cursym.Text
+	textstksiz := p.To.Offset
+
+	cursym.Args = p.To.Val.(int32)
+	cursym.Locals = int32(textstksiz)
+
+	/*
+	 * find leaf subroutines
+	 * strip NOPs
+	 * expand RET
+	 * expand BECOME pseudo
+	 */
+	if ctxt.Debugvlog != 0 {
+		fmt.Fprintf(ctxt.Bso, "%5.2f noops\n", obj.Cputime())
+	}
+	ctxt.Bso.Flush()
+
+	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:
+			q = p
+
+			p.Mark |= LABEL | LEAF | SYNC
+			if p.Link != nil {
+				p.Link.Mark |= LABEL
+			}
+
+		case ANOR:
+			q = p
+			if p.To.Type == obj.TYPE_REG {
+				if p.To.Reg == REGZERO {
+					p.Mark |= LABEL | SYNC
+				}
+			}
+
+		case ALWAR,
+			ASTWCCC,
+			AECIWX,
+			AECOWX,
+			AEIEIO,
+			AICBI,
+			AISYNC,
+			ATLBIE,
+			ATLBIEL,
+			ASLBIA,
+			ASLBIE,
+			ASLBMFEE,
+			ASLBMFEV,
+			ASLBMTE,
+			ADCBF,
+			ADCBI,
+			ADCBST,
+			ADCBT,
+			ADCBTST,
+			ADCBZ,
+			ASYNC,
+			ATLBSYNC,
+			APTESYNC,
+			ATW,
+			AWORD,
+			ARFI,
+			ARFCI,
+			ARFID,
+			AHRFID:
+			q = p
+			p.Mark |= LABEL | SYNC
+			continue
+
+		case AMOVW, AMOVWZ, AMOVD:
+			q = p
+			if p.From.Reg >= REG_SPECIAL || p.To.Reg >= REG_SPECIAL {
+				p.Mark |= LABEL | SYNC
+			}
+			continue
+
+		case AFABS,
+			AFABSCC,
+			AFADD,
+			AFADDCC,
+			AFCTIW,
+			AFCTIWCC,
+			AFCTIWZ,
+			AFCTIWZCC,
+			AFDIV,
+			AFDIVCC,
+			AFMADD,
+			AFMADDCC,
+			AFMOVD,
+			AFMOVDU,
+			/* case AFMOVDS: */
+			AFMOVS,
+			AFMOVSU,
+
+			/* case AFMOVSD: */
+			AFMSUB,
+			AFMSUBCC,
+			AFMUL,
+			AFMULCC,
+			AFNABS,
+			AFNABSCC,
+			AFNEG,
+			AFNEGCC,
+			AFNMADD,
+			AFNMADDCC,
+			AFNMSUB,
+			AFNMSUBCC,
+			AFRSP,
+			AFRSPCC,
+			AFSUB,
+			AFSUBCC:
+			q = p
+
+			p.Mark |= FLOAT
+			continue
+
+		case ABL,
+			ABCL,
+			obj.ADUFFZERO,
+			obj.ADUFFCOPY:
+			cursym.Text.Mark &^= LEAF
+			fallthrough
+
+		case ABC,
+			ABEQ,
+			ABGE,
+			ABGT,
+			ABLE,
+			ABLT,
+			ABNE,
+			ABR,
+			ABVC,
+			ABVS:
+			p.Mark |= BRANCH
+			q = p
+			q1 = p.Pcond
+			if q1 != nil {
+				for q1.As == obj.ANOP {
+					q1 = q1.Link
+					p.Pcond = q1
+				}
+
+				if q1.Mark&LEAF == 0 {
+					q1.Mark |= LABEL
+				}
+			} else {
+				p.Mark |= LABEL
+			}
+			q1 = p.Link
+			if q1 != nil {
+				q1.Mark |= LABEL
+			}
+			continue
+
+		case AFCMPO, AFCMPU:
+			q = p
+			p.Mark |= FCMP | FLOAT
+			continue
+
+		case obj.ARET:
+			q = p
+			if p.Link != nil {
+				p.Link.Mark |= LABEL
+			}
+			continue
+
+		case obj.ANOP:
+			q1 = p.Link
+			q.Link = q1 /* q is non-nop */
+			q1.Mark |= p.Mark
+			continue
+
+		default:
+			q = p
+			continue
+		}
+	}
+
+	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:
+			mov = AMOVD
+			aoffset = 0
+			autosize = int32(textstksiz + 8)
+			if (p.Mark&LEAF != 0) && autosize <= 8 {
+				autosize = 0
+			} else if autosize&4 != 0 {
+				autosize += 4
+			}
+			p.To.Offset = int64(autosize) - 8
+
+			if p.From3.Offset&obj.NOSPLIT == 0 {
+				p = stacksplit(ctxt, p, autosize) // emit split check
+			}
+
+			q = p
+
+			if autosize != 0 {
+				/* use MOVDU to adjust R1 when saving R31, if autosize is small */
+				if cursym.Text.Mark&LEAF == 0 && autosize >= -BIG && autosize <= BIG {
+					mov = AMOVDU
+					aoffset = int(-autosize)
+				} else {
+					q = obj.Appendp(ctxt, p)
+					q.As = AADD
+					q.Lineno = p.Lineno
+					q.From.Type = obj.TYPE_CONST
+					q.From.Offset = int64(-autosize)
+					q.To.Type = obj.TYPE_REG
+					q.To.Reg = REGSP
+					q.Spadj = +autosize
+				}
+			} else if cursym.Text.Mark&LEAF == 0 {
+				if ctxt.Debugvlog != 0 {
+					fmt.Fprintf(ctxt.Bso, "save suppressed in: %s\n", cursym.Name)
+					ctxt.Bso.Flush()
+				}
+
+				cursym.Text.Mark |= LEAF
+			}
+
+			if cursym.Text.Mark&LEAF != 0 {
+				cursym.Leaf = 1
+				break
+			}
+
+			q = obj.Appendp(ctxt, q)
+			q.As = AMOVD
+			q.Lineno = p.Lineno
+			q.From.Type = obj.TYPE_REG
+			q.From.Reg = REG_LR
+			q.To.Type = obj.TYPE_REG
+			q.To.Reg = REGTMP
+
+			q = obj.Appendp(ctxt, q)
+			q.As = int16(mov)
+			q.Lineno = p.Lineno
+			q.From.Type = obj.TYPE_REG
+			q.From.Reg = REGTMP
+			q.To.Type = obj.TYPE_MEM
+			q.To.Offset = int64(aoffset)
+			q.To.Reg = REGSP
+			if q.As == AMOVDU {
+				q.Spadj = int32(-aoffset)
+			}
+
+			if cursym.Text.From3.Offset&obj.WRAPPER != 0 {
+				// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
+				//
+				//	MOVD g_panic(g), R3
+				//	CMP R0, R3
+				//	BEQ end
+				//	MOVD panic_argp(R3), R4
+				//	ADD $(autosize+8), R1, R5
+				//	CMP R4, R5
+				//	BNE end
+				//	ADD $8, R1, R6
+				//	MOVD R6, panic_argp(R3)
+				// end:
+				//	NOP
+				//
+				// The NOP is needed to give the jumps somewhere to land.
+				// It is a liblink NOP, not a ppc64 NOP: it encodes to 0 instruction bytes.
+
+				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_R3
+
+				q = obj.Appendp(ctxt, q)
+				q.As = ACMP
+				q.From.Type = obj.TYPE_REG
+				q.From.Reg = REG_R0
+				q.To.Type = obj.TYPE_REG
+				q.To.Reg = REG_R3
+
+				q = obj.Appendp(ctxt, q)
+				q.As = ABEQ
+				q.To.Type = obj.TYPE_BRANCH
+				p1 = q
+
+				q = obj.Appendp(ctxt, q)
+				q.As = AMOVD
+				q.From.Type = obj.TYPE_MEM
+				q.From.Reg = REG_R3
+				q.From.Offset = 0 // Panic.argp
+				q.To.Type = obj.TYPE_REG
+				q.To.Reg = REG_R4
+
+				q = obj.Appendp(ctxt, q)
+				q.As = AADD
+				q.From.Type = obj.TYPE_CONST
+				q.From.Offset = int64(autosize) + 8
+				q.Reg = REGSP
+				q.To.Type = obj.TYPE_REG
+				q.To.Reg = REG_R5
+
+				q = obj.Appendp(ctxt, q)
+				q.As = ACMP
+				q.From.Type = obj.TYPE_REG
+				q.From.Reg = REG_R4
+				q.To.Type = obj.TYPE_REG
+				q.To.Reg = REG_R5
+
+				q = obj.Appendp(ctxt, q)
+				q.As = ABNE
+				q.To.Type = obj.TYPE_BRANCH
+				p2 = 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_R6
+
+				q = obj.Appendp(ctxt, q)
+				q.As = AMOVD
+				q.From.Type = obj.TYPE_REG
+				q.From.Reg = REG_R6
+				q.To.Type = obj.TYPE_MEM
+				q.To.Reg = REG_R3
+				q.To.Offset = 0 // Panic.argp
+
+				q = obj.Appendp(ctxt, q)
+
+				q.As = obj.ANOP
+				p1.Pcond = q
+				p2.Pcond = q
+			}
+
+		case obj.ARET:
+			if p.From.Type == obj.TYPE_CONST {
+				ctxt.Diag("using BECOME (%v) is not supported!", p)
+				break
+			}
+
+			if p.To.Sym != nil { // retjmp
+				p.As = ABR
+				p.To.Type = obj.TYPE_BRANCH
+				break
+			}
+
+			if cursym.Text.Mark&LEAF != 0 {
+				if autosize == 0 {
+					p.As = ABR
+					p.From = obj.Addr{}
+					p.To.Type = obj.TYPE_REG
+					p.To.Reg = REG_LR
+					p.Mark |= BRANCH
+					break
+				}
+
+				p.As = AADD
+				p.From.Type = obj.TYPE_CONST
+				p.From.Offset = int64(autosize)
+				p.To.Type = obj.TYPE_REG
+				p.To.Reg = REGSP
+				p.Spadj = -autosize
+
+				q = ctxt.NewProg()
+				q.As = ABR
+				q.Lineno = p.Lineno
+				q.To.Type = obj.TYPE_REG
+				q.To.Reg = REG_LR
+				q.Mark |= BRANCH
+				q.Spadj = +autosize
+
+				q.Link = p.Link
+				p.Link = q
+				break
+			}
+
+			p.As = AMOVD
+			p.From.Type = obj.TYPE_MEM
+			p.From.Offset = 0
+			p.From.Reg = REGSP
+			p.To.Type = obj.TYPE_REG
+			p.To.Reg = REGTMP
+
+			q = ctxt.NewProg()
+			q.As = AMOVD
+			q.Lineno = p.Lineno
+			q.From.Type = obj.TYPE_REG
+			q.From.Reg = REGTMP
+			q.To.Type = obj.TYPE_REG
+			q.To.Reg = REG_LR
+
+			q.Link = p.Link
+			p.Link = q
+			p = q
+
+			if false {
+				// Debug bad returns
+				q = ctxt.NewProg()
+
+				q.As = AMOVD
+				q.Lineno = p.Lineno
+				q.From.Type = obj.TYPE_MEM
+				q.From.Offset = 0
+				q.From.Reg = REGTMP
+				q.To.Type = obj.TYPE_REG
+				q.To.Reg = REGTMP
+
+				q.Link = p.Link
+				p.Link = q
+				p = q
+			}
+
+			if autosize != 0 {
+				q = ctxt.NewProg()
+				q.As = AADD
+				q.Lineno = p.Lineno
+				q.From.Type = obj.TYPE_CONST
+				q.From.Offset = int64(autosize)
+				q.To.Type = obj.TYPE_REG
+				q.To.Reg = REGSP
+				q.Spadj = -autosize
+
+				q.Link = p.Link
+				p.Link = q
+			}
+
+			q1 = ctxt.NewProg()
+			q1.As = ABR
+			q1.Lineno = p.Lineno
+			q1.To.Type = obj.TYPE_REG
+			q1.To.Reg = REG_LR
+			q1.Mark |= BRANCH
+			q1.Spadj = +autosize
+
+			q1.Link = q.Link
+			q.Link = q1
+
+		case AADD:
+			if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST {
+				p.Spadj = int32(-p.From.Offset)
+			}
+		}
+	}
+}
+
+/*
+// instruction scheduling
+	if(debug['Q'] == 0)
+		return;
+
+	curtext = nil;
+	q = nil;	// p - 1
+	q1 = firstp;	// top of block
+	o = 0;		// count of instructions
+	for(p = firstp; p != nil; p = p1) {
+		p1 = p->link;
+		o++;
+		if(p->mark & NOSCHED){
+			if(q1 != p){
+				sched(q1, q);
+			}
+			for(; p != nil; p = p->link){
+				if(!(p->mark & NOSCHED))
+					break;
+				q = p;
+			}
+			p1 = p;
+			q1 = p;
+			o = 0;
+			continue;
+		}
+		if(p->mark & (LABEL|SYNC)) {
+			if(q1 != p)
+				sched(q1, q);
+			q1 = p;
+			o = 1;
+		}
+		if(p->mark & (BRANCH|SYNC)) {
+			sched(q1, p);
+			q1 = p1;
+			o = 0;
+		}
+		if(o >= NSCHED) {
+			sched(q1, p);
+			q1 = p1;
+			o = 0;
+		}
+		q = p;
+	}
+*/
+func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32) *obj.Prog {
+	// MOVD	g_stackguard(g), R3
+	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_R3
+
+	var q *obj.Prog
+	if framesize <= obj.StackSmall {
+		// small stack: SP < stackguard
+		//	CMP	stackguard, SP
+		p = obj.Appendp(ctxt, p)
+
+		p.As = ACMPU
+		p.From.Type = obj.TYPE_REG
+		p.From.Reg = REG_R3
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = REGSP
+	} else if framesize <= obj.StackBig {
+		// large stack: SP-framesize < stackguard-StackSmall
+		//	ADD $-framesize, SP, R4
+		//	CMP stackguard, R4
+		p = obj.Appendp(ctxt, p)
+
+		p.As = AADD
+		p.From.Type = obj.TYPE_CONST
+		p.From.Offset = int64(-framesize)
+		p.Reg = REGSP
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = REG_R4
+
+		p = obj.Appendp(ctxt, p)
+		p.As = ACMPU
+		p.From.Type = obj.TYPE_REG
+		p.From.Reg = REG_R3
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = REG_R4
+	} 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.
+		//	// stackguard is R3
+		//	CMP	R3, $StackPreempt
+		//	BEQ	label-of-call-to-morestack
+		//	ADD	$StackGuard, SP, R4
+		//	SUB	R3, R4
+		//	MOVD	$(framesize+(StackGuard-StackSmall)), R31
+		//	CMPU	R31, R4
+		p = obj.Appendp(ctxt, p)
+
+		p.As = ACMP
+		p.From.Type = obj.TYPE_REG
+		p.From.Reg = REG_R3
+		p.To.Type = obj.TYPE_CONST
+		p.To.Offset = obj.StackPreempt
+
+		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_R4
+
+		p = obj.Appendp(ctxt, p)
+		p.As = ASUB
+		p.From.Type = obj.TYPE_REG
+		p.From.Reg = REG_R3
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = REG_R4
+
+		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 = REGTMP
+
+		p = obj.Appendp(ctxt, p)
+		p.As = ACMPU
+		p.From.Type = obj.TYPE_REG
+		p.From.Reg = REGTMP
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = REG_R4
+	}
+
+	// q1: BLT	done
+	p = obj.Appendp(ctxt, p)
+	q1 := p
+
+	p.As = ABLT
+	p.To.Type = obj.TYPE_BRANCH
+
+	// MOVD	LR, R5
+	p = obj.Appendp(ctxt, p)
+
+	p.As = AMOVD
+	p.From.Type = obj.TYPE_REG
+	p.From.Reg = REG_LR
+	p.To.Type = obj.TYPE_REG
+	p.To.Reg = REG_R5
+	if q != nil {
+		q.Pcond = p
+	}
+
+	// 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 if ctxt.Cursym.Text.From3.Offset&obj.NEEDCTXT == 0 {
+		p.To.Sym = obj.Linklookup(ctxt, "runtime.morestack_noctxt", 0)
+	} else {
+		p.To.Sym = obj.Linklookup(ctxt, "runtime.morestack", 0)
+	}
+
+	// BR	start
+	p = obj.Appendp(ctxt, p)
+
+	p.As = ABR
+	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 // zero-width place holder
+	q1.Pcond = p
+
+	return p
+}
+
+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 ABGE:
+		return ABLT
+	case ABLT:
+		return ABGE
+
+	case ABGT:
+		return ABLE
+	case ABLE:
+		return ABGT
+
+	case ABVC:
+		return ABVS
+	case ABVS:
+		return ABVC
+	}
+
+	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 b int
+	var i int
+
+loop:
+	if p == nil {
+		return
+	}
+	a = int(p.As)
+	if a == ABR {
+		q = p.Pcond
+		if (p.Mark&NOSCHED != 0) || q != nil && (q.Mark&NOSCHED != 0) {
+			p.Mark |= FOLL
+			(*last).Link = p
+			*last = p
+			p = p.Link
+			xfol(ctxt, p, last)
+			p = q
+			if p != nil && p.Mark&FOLL == 0 {
+				goto loop
+			}
+			return
+		}
+
+		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.Mark&NOSCHED != 0) {
+				break
+			}
+			b = 0 /* set */
+			a = int(q.As)
+			if a == obj.ANOP {
+				i--
+				continue
+			}
+
+			if a == ABR || a == obj.ARET || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID {
+				goto copy
+			}
+			if q.Pcond == nil || (q.Pcond.Mark&FOLL != 0) {
+				continue
+			}
+			b = relinv(a)
+			if b == 0 {
+				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 == ABR || a == obj.ARET || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID {
+					return
+				}
+				r.As = int16(b)
+				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 = ABR
+		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 == ABR || a == obj.ARET || a == ARFI || a == ARFCI || a == ARFID || a == AHRFID {
+		if p.Mark&NOSCHED != 0 {
+			p = p.Link
+			goto loop
+		}
+
+		return
+	}
+
+	if p.Pcond != nil {
+		if a != ABL && p.Link != nil {
+			xfol(ctxt, p.Link, last)
+			p = p.Pcond
+			if p == nil || (p.Mark&FOLL != 0) {
+				return
+			}
+			goto loop
+		}
+	}
+
+	p = p.Link
+	goto loop
+}
+
+var Linkppc64 = obj.LinkArch{
+	ByteOrder:  binary.BigEndian,
+	Name:       "ppc64",
+	Thechar:    '9',
+	Preprocess: preprocess,
+	Assemble:   span9,
+	Follow:     follow,
+	Progedit:   progedit,
+	Minlc:      4,
+	Ptrsize:    8,
+	Regsize:    8,
+}
+
+var Linkppc64le = obj.LinkArch{
+	ByteOrder:  binary.LittleEndian,
+	Name:       "ppc64le",
+	Thechar:    '9',
+	Preprocess: preprocess,
+	Assemble:   span9,
+	Follow:     follow,
+	Progedit:   progedit,
+	Minlc:      4,
+	Ptrsize:    8,
+	Regsize:    8,
+}
diff --git a/src/cmd/internal/obj/stack.go b/src/cmd/internal/obj/stack.go
new file mode 100644
index 0000000..87698b3
--- /dev/null
+++ b/src/cmd/internal/obj/stack.go
@@ -0,0 +1,51 @@
+// 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.
+
+// Inferno utils/5l/span.c
+// http://code.google.com/p/inferno-os/source/browse/utils/5l/span.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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 obj
+
+// For the linkers. Must match Go definitions.
+// TODO(rsc): Share Go definitions with linkers directly.
+
+const (
+	STACKSYSTEM = 0
+	StackSystem = STACKSYSTEM
+	StackBig    = 4096
+	StackGuard  = 640*stackGuardMultiplier + StackSystem
+	StackSmall  = 128
+	StackLimit  = StackGuard - StackSystem - StackSmall
+)
+
+const (
+	StackPreempt = -1314 // 0xfff...fade
+)
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
new file mode 100644
index 0000000..37bb40b
--- /dev/null
+++ b/src/cmd/internal/obj/sym.go
@@ -0,0 +1,213 @@
+// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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 obj
+
+import (
+	"log"
+	"os"
+	"path/filepath"
+	"runtime"
+	"strconv"
+)
+
+var headers = []struct {
+	name string
+	val  int
+}{
+	{"darwin", Hdarwin},
+	{"dragonfly", Hdragonfly},
+	{"elf", Helf},
+	{"freebsd", Hfreebsd},
+	{"linux", Hlinux},
+	{"android", Hlinux}, // must be after "linux" entry or else headstr(Hlinux) == "android"
+	{"nacl", Hnacl},
+	{"netbsd", Hnetbsd},
+	{"openbsd", Hopenbsd},
+	{"plan9", Hplan9},
+	{"solaris", Hsolaris},
+	{"windows", Hwindows},
+	{"windowsgui", Hwindows},
+}
+
+func headtype(name string) int {
+	for i := 0; i < len(headers); i++ {
+		if name == headers[i].name {
+			return headers[i].val
+		}
+	}
+	return -1
+}
+
+func Headstr(v int) string {
+	for i := 0; i < len(headers); i++ {
+		if v == headers[i].val {
+			return headers[i].name
+		}
+	}
+	return strconv.Itoa(v)
+}
+
+func Linknew(arch *LinkArch) *Link {
+	ctxt := new(Link)
+	ctxt.Hash = make(map[SymVer]*LSym)
+	ctxt.Arch = arch
+	ctxt.Version = HistVersion
+	ctxt.Goroot = Getgoroot()
+	ctxt.Goroot_final = os.Getenv("GOROOT_FINAL")
+	if runtime.GOOS == "windows" {
+		// TODO(rsc): Remove ctxt.Windows and let callers use runtime.GOOS.
+		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())
+	}
+
+	// Record thread-local storage offset.
+	// TODO(rsc): Move tlsoffset back into the linker.
+	switch ctxt.Headtype {
+	default:
+		log.Fatalf("unknown thread-local storage offset for %s", Headstr(ctxt.Headtype))
+
+	case Hplan9, Hwindows:
+		break
+
+		/*
+		 * ELF uses TLS offset negative from FS.
+		 * Translate 0(FS) and 8(FS) into -16(FS) and -8(FS).
+		 * Known to low-level assembly in package runtime and runtime/cgo.
+		 */
+	case Hlinux,
+		Hfreebsd,
+		Hnetbsd,
+		Hopenbsd,
+		Hdragonfly,
+		Hsolaris:
+		ctxt.Tlsoffset = -1 * ctxt.Arch.Ptrsize
+
+	case Hnacl:
+		switch ctxt.Arch.Thechar {
+		default:
+			log.Fatalf("unknown thread-local storage offset for nacl/%s", ctxt.Arch.Name)
+
+		case '5':
+			ctxt.Tlsoffset = 0
+
+		case '6':
+			ctxt.Tlsoffset = 0
+
+		case '8':
+			ctxt.Tlsoffset = -8
+		}
+
+		/*
+		 * OS X system constants - offset from 0(GS) to our TLS.
+		 * Explained in ../../runtime/cgo/gcc_darwin_*.c.
+		 */
+	case Hdarwin:
+		switch ctxt.Arch.Thechar {
+		default:
+			log.Fatalf("unknown thread-local storage offset for darwin/%s", ctxt.Arch.Name)
+
+		case '5':
+			ctxt.Tlsoffset = 0 // dummy value, not needed
+
+		case '6':
+			ctxt.Tlsoffset = 0x8a0
+
+		case '7':
+			ctxt.Tlsoffset = 0 // dummy value, not needed
+
+		case '8':
+			ctxt.Tlsoffset = 0x468
+		}
+	}
+
+	// On arm, record goarm.
+	if ctxt.Arch.Thechar == '5' {
+		p := Getgoarm()
+		if p != "" {
+			ctxt.Goarm = int32(Atoi(p))
+		} else {
+			ctxt.Goarm = 6
+		}
+	}
+
+	return ctxt
+}
+
+func _lookup(ctxt *Link, symb string, v int, create bool) *LSym {
+	s := ctxt.Hash[SymVer{symb, v}]
+	if s != nil || !create {
+		return s
+	}
+
+	s = &LSym{
+		Name:    symb,
+		Type:    0,
+		Version: int16(v),
+		Value:   0,
+		Size:    0,
+	}
+	ctxt.Hash[SymVer{symb, v}] = s
+
+	return s
+}
+
+func Linklookup(ctxt *Link, name string, v int) *LSym {
+	return _lookup(ctxt, name, v, true)
+}
+
+// read-only lookup
+func linkrlookup(ctxt *Link, name string, v int) *LSym {
+	return _lookup(ctxt, name, v, false)
+}
+
+func Linksymfmt(s *LSym) string {
+	if s == nil {
+		return "<nil>"
+	}
+	return s.Name
+}
diff --git a/src/cmd/internal/obj/textflag.go b/src/cmd/internal/obj/textflag.go
new file mode 100644
index 0000000..dbd1bc8
--- /dev/null
+++ b/src/cmd/internal/obj/textflag.go
@@ -0,0 +1,38 @@
+// 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.
+
+// This file defines flags attached to various functions
+// and data objects.  The compilers, assemblers, and linker must
+// all agree on these values.
+
+package obj
+
+const (
+	// Don't profile the marked routine.
+	//
+	// Deprecated: Not implemented, do not use.
+	NOPROF = 1
+
+	// It is ok for the linker to get multiple of these symbols.  It will
+	// pick one of the duplicates to use.
+	DUPOK = 2
+
+	// Don't insert stack check preamble.
+	NOSPLIT = 4
+
+	// Put this data in a read-only section.
+	RODATA = 8
+
+	// This data contains no pointers.
+	NOPTR = 16
+
+	// This is a wrapper function and should not count as disabling 'recover'.
+	WRAPPER = 32
+
+	// This function uses its incoming context register.
+	NEEDCTXT = 64
+
+	// When passed to ggloblsym, causes Local to be set to true on the LSym it creates.
+	LOCAL = 128
+)
diff --git a/src/cmd/internal/obj/typekind.go b/src/cmd/internal/obj/typekind.go
new file mode 100644
index 0000000..2193271
--- /dev/null
+++ b/src/cmd/internal/obj/typekind.go
@@ -0,0 +1,41 @@
+// 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.
+
+package obj
+
+// Must match runtime and reflect.
+// Included by cmd/gc.
+
+const (
+	KindBool = 1 + iota
+	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
+	KindNoPointers  = 1 << 7
+	KindMask        = (1 << 5) - 1
+)
diff --git a/src/cmd/internal/obj/util.go b/src/cmd/internal/obj/util.go
new file mode 100644
index 0000000..3c3fc88
--- /dev/null
+++ b/src/cmd/internal/obj/util.go
@@ -0,0 +1,645 @@
+// 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 (
+	"bufio"
+	"bytes"
+	"fmt"
+	"io"
+	"log"
+	"os"
+	"strconv"
+	"strings"
+	"time"
+)
+
+const REG_NONE = 0
+
+var start time.Time
+
+func Cputime() float64 {
+	if start.IsZero() {
+		start = time.Now()
+	}
+	return time.Since(start).Seconds()
+}
+
+type Biobuf struct {
+	f       *os.File
+	r       *bufio.Reader
+	w       *bufio.Writer
+	linelen int
+}
+
+func Bopenw(name string) (*Biobuf, error) {
+	f, err := os.Create(name)
+	if err != nil {
+		return nil, err
+	}
+	return &Biobuf{f: f, w: bufio.NewWriter(f)}, nil
+}
+
+func Bopenr(name string) (*Biobuf, error) {
+	f, err := os.Open(name)
+	if err != nil {
+		return nil, err
+	}
+	return &Biobuf{f: f, r: bufio.NewReader(f)}, nil
+}
+
+func Binitw(w io.Writer) *Biobuf {
+	return &Biobuf{w: bufio.NewWriter(w)}
+}
+
+func (b *Biobuf) Write(p []byte) (int, error) {
+	return b.w.Write(p)
+}
+
+func Bwritestring(b *Biobuf, p string) (int, error) {
+	return b.w.WriteString(p)
+}
+
+func Bseek(b *Biobuf, offset int64, whence int) int64 {
+	if b.w != nil {
+		if err := b.w.Flush(); err != nil {
+			log.Fatalf("writing output: %v", err)
+		}
+	} else if b.r != nil {
+		if whence == 1 {
+			offset -= int64(b.r.Buffered())
+		}
+	}
+	off, err := b.f.Seek(offset, whence)
+	if err != nil {
+		log.Fatalf("seeking in output: %v", err)
+	}
+	if b.r != nil {
+		b.r.Reset(b.f)
+	}
+	return off
+}
+
+func Boffset(b *Biobuf) int64 {
+	if b.w != nil {
+		if err := b.w.Flush(); err != nil {
+			log.Fatalf("writing output: %v", err)
+		}
+	}
+	off, err := b.f.Seek(0, 1)
+	if err != nil {
+		log.Fatalf("seeking in output [0, 1]: %v", err)
+	}
+	if b.r != nil {
+		off -= int64(b.r.Buffered())
+	}
+	return off
+}
+
+func (b *Biobuf) Flush() error {
+	return b.w.Flush()
+}
+
+func Bputc(b *Biobuf, c byte) {
+	b.w.WriteByte(c)
+}
+
+const Beof = -1
+
+func Bread(b *Biobuf, p []byte) int {
+	n, err := io.ReadFull(b.r, p)
+	if n == 0 {
+		if err != nil && err != io.EOF {
+			n = -1
+		}
+	}
+	return n
+}
+
+func Bgetc(b *Biobuf) int {
+	c, err := b.r.ReadByte()
+	if err != nil {
+		return -1
+	}
+	return int(c)
+}
+
+func Bgetrune(b *Biobuf) int {
+	r, _, err := b.r.ReadRune()
+	if err != nil {
+		return -1
+	}
+	return int(r)
+}
+
+func Bungetrune(b *Biobuf) {
+	b.r.UnreadRune()
+}
+
+func (b *Biobuf) Read(p []byte) (int, error) {
+	return b.r.Read(p)
+}
+
+func (b *Biobuf) Peek(n int) ([]byte, error) {
+	return b.r.Peek(n)
+}
+
+func Brdline(b *Biobuf, delim int) string {
+	s, err := b.r.ReadBytes(byte(delim))
+	if err != nil {
+		log.Fatalf("reading input: %v", err)
+	}
+	b.linelen = len(s)
+	return string(s)
+}
+
+func Brdstr(b *Biobuf, delim int, cut int) string {
+	s, err := b.r.ReadString(byte(delim))
+	if err != nil {
+		log.Fatalf("reading input: %v", err)
+	}
+	if len(s) > 0 && cut > 0 {
+		s = s[:len(s)-1]
+	}
+	return s
+}
+
+func Access(name string, mode int) int {
+	if mode != 0 {
+		panic("bad access")
+	}
+	_, err := os.Stat(name)
+	if err != nil {
+		return -1
+	}
+	return 0
+}
+
+func Blinelen(b *Biobuf) int {
+	return b.linelen
+}
+
+func Bterm(b *Biobuf) error {
+	var err error
+	if b.w != nil {
+		err = b.w.Flush()
+	}
+	err1 := b.f.Close()
+	if err == nil {
+		err = err1
+	}
+	return err
+}
+
+func envOr(key, value string) string {
+	if x := os.Getenv(key); x != "" {
+		return x
+	}
+	return value
+}
+
+func Getgoroot() string {
+	return envOr("GOROOT", defaultGOROOT)
+}
+
+func Getgoarch() string {
+	return envOr("GOARCH", defaultGOARCH)
+}
+
+func Getgoos() string {
+	return envOr("GOOS", defaultGOOS)
+}
+
+func Getgoarm() string {
+	switch v := envOr("GOARM", defaultGOARM); v {
+	case "5", "6", "7":
+		return v
+	}
+	// Fail here, rather than validate at multiple call sites.
+	log.Fatalf("Invalid GOARM value. Must be 5, 6, or 7.")
+	panic("unreachable")
+}
+
+func Getgo386() string {
+	// Validated by cmd/compile.
+	return envOr("GO386", defaultGO386)
+}
+
+func Getgoextlinkenabled() string {
+	return envOr("GO_EXTLINK_ENABLED", defaultGO_EXTLINK_ENABLED)
+}
+
+func Getgoversion() string {
+	return version
+}
+
+func Atoi(s string) int {
+	i, _ := strconv.Atoi(s)
+	return i
+}
+
+func (p *Prog) Line() string {
+	return p.Ctxt.LineHist.LineString(int(p.Lineno))
+}
+
+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>"
+	}
+
+	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.From3Type() != 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.RegTo2 != REG_NONE {
+		fmt.Fprintf(&buf, "%s%v", sep, Rconv(int(p.RegTo2)))
+	}
+	return buf.String()
+}
+
+func (ctxt *Link) NewProg() *Prog {
+	p := new(Prog) // should be the only call to this; all others should use ctxt.NewProg
+	p.Ctxt = ctxt
+	return p
+}
+
+func (ctxt *Link) Line(n int) string {
+	return ctxt.LineHist.LineString(n)
+}
+
+func Getcallerpc(interface{}) uintptr {
+	return 1
+}
+
+func (ctxt *Link) Dconv(a *Addr) string {
+	return Dconv(nil, a)
+}
+
+func Dconv(p *Prog, a *Addr) string {
+	var str string
+
+	switch a.Type {
+	default:
+		str = fmt.Sprintf("type=%d", a.Type)
+
+	case TYPE_NONE:
+		str = ""
+		if a.Name != NAME_NONE || a.Reg != 0 || a.Sym != nil {
+			str = fmt.Sprintf("%v(%v)(NONE)", Mconv(a), Rconv(int(a.Reg)))
+		}
+
+	case TYPE_REG:
+		// TODO(rsc): This special case is for x86 instructions like
+		//	PINSRQ	CX,$1,X6
+		// where the $1 is included in the p->to Addr.
+		// Move into a new field.
+		if a.Offset != 0 {
+			str = fmt.Sprintf("$%d,%v", a.Offset, Rconv(int(a.Reg)))
+			break
+		}
+
+		str = Rconv(int(a.Reg))
+		if a.Name != TYPE_NONE || a.Sym != nil {
+			str = fmt.Sprintf("%v(%v)(REG)", Mconv(a), Rconv(int(a.Reg)))
+		}
+
+	case TYPE_BRANCH:
+		if a.Sym != nil {
+			str = fmt.Sprintf("%s(SB)", a.Sym.Name)
+		} else if p != nil && p.Pcond != nil {
+			str = fmt.Sprint(p.Pcond.Pc)
+		} else if a.Val != nil {
+			str = fmt.Sprint(a.Val.(*Prog).Pc)
+		} else {
+			str = fmt.Sprintf("%d(PC)", a.Offset)
+		}
+
+	case TYPE_INDIR:
+		str = fmt.Sprintf("*%s", Mconv(a))
+
+	case TYPE_MEM:
+		str = Mconv(a)
+		if a.Index != REG_NONE {
+			str += fmt.Sprintf("(%v*%d)", Rconv(int(a.Index)), int(a.Scale))
+		}
+
+	case TYPE_CONST:
+		if a.Reg != 0 {
+			str = fmt.Sprintf("$%v(%v)", Mconv(a), Rconv(int(a.Reg)))
+		} else {
+			str = fmt.Sprintf("$%v", Mconv(a))
+		}
+
+	case TYPE_TEXTSIZE:
+		if a.Val.(int32) == ArgsSizeUnknown {
+			str = fmt.Sprintf("$%d", a.Offset)
+		} else {
+			str = fmt.Sprintf("$%d-%d", a.Offset, a.Val.(int32))
+		}
+
+	case TYPE_FCONST:
+		str = fmt.Sprintf("%.17g", a.Val.(float64))
+		// Make sure 1 prints as 1.0
+		if !strings.ContainsAny(str, ".e") {
+			str += ".0"
+		}
+		str = fmt.Sprintf("$(%s)", str)
+
+	case TYPE_SCONST:
+		str = fmt.Sprintf("$%q", a.Val.(string))
+
+	case TYPE_ADDR:
+		str = fmt.Sprintf("$%s", Mconv(a))
+
+	case TYPE_SHIFT:
+		v := int(a.Offset)
+		op := string("<<>>->@>"[((v>>5)&3)<<1:])
+		if v&(1<<4) != 0 {
+			str = fmt.Sprintf("R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15)
+		} else {
+			str = fmt.Sprintf("R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31)
+		}
+		if a.Reg != 0 {
+			str += fmt.Sprintf("(%v)", Rconv(int(a.Reg)))
+		}
+
+	case TYPE_REGREG:
+		str = fmt.Sprintf("(%v, %v)", Rconv(int(a.Reg)), Rconv(int(a.Offset)))
+
+	case TYPE_REGREG2:
+		str = fmt.Sprintf("%v, %v", Rconv(int(a.Reg)), Rconv(int(a.Offset)))
+
+	case TYPE_REGLIST:
+		str = regListConv(int(a.Offset))
+	}
+
+	return str
+}
+
+func Mconv(a *Addr) string {
+	var str string
+
+	switch a.Name {
+	default:
+		str = fmt.Sprintf("name=%d", a.Name)
+
+	case NAME_NONE:
+		switch {
+		case a.Reg == REG_NONE:
+			str = fmt.Sprint(a.Offset)
+		case a.Offset == 0:
+			str = fmt.Sprintf("(%v)", Rconv(int(a.Reg)))
+		case a.Offset != 0:
+			str = fmt.Sprintf("%d(%v)", a.Offset, Rconv(int(a.Reg)))
+		}
+
+	case NAME_EXTERN:
+		str = fmt.Sprintf("%s%s(SB)", a.Sym.Name, offConv(a.Offset))
+
+	case NAME_GOTREF:
+		str = fmt.Sprintf("%s%s at GOT(SB)", a.Sym.Name, offConv(a.Offset))
+
+	case NAME_STATIC:
+		str = fmt.Sprintf("%s<>%s(SB)", a.Sym.Name, offConv(a.Offset))
+
+	case NAME_AUTO:
+		if a.Sym != nil {
+			str = fmt.Sprintf("%s%s(SP)", a.Sym.Name, offConv(a.Offset))
+		} else {
+			str = fmt.Sprintf("%s(SP)", offConv(a.Offset))
+		}
+
+	case NAME_PARAM:
+		if a.Sym != nil {
+			str = fmt.Sprintf("%s%s(FP)", a.Sym.Name, offConv(a.Offset))
+		} else {
+			str = fmt.Sprintf("%s(FP)", offConv(a.Offset))
+		}
+	}
+	return str
+}
+
+func offConv(off int64) string {
+	if off == 0 {
+		return ""
+	}
+	return fmt.Sprintf("%+d", off)
+}
+
+type regSet struct {
+	lo    int
+	hi    int
+	Rconv func(int) string
+}
+
+// Few enough architectures that a linear scan is fastest.
+// Not even worth sorting.
+var regSpace []regSet
+
+/*
+	Each architecture defines a register space as a unique
+	integer range.
+	Here is the list of architectures and the base of their register spaces.
+*/
+
+const (
+	// Because of masking operations in the encodings, each register
+	// space should start at 0 modulo some power of 2.
+	RBase386   = 1 * 1024
+	RBaseAMD64 = 2 * 1024
+	RBaseARM   = 3 * 1024
+	RBasePPC64 = 4 * 1024 // range [4k, 8k)
+	RBaseARM64 = 8 * 1024 // range [8k, 12k)
+)
+
+// RegisterRegister binds a pretty-printer (Rconv) for register
+// numbers to a given register number range.  Lo is inclusive,
+// hi exclusive (valid registers are lo through hi-1).
+func RegisterRegister(lo, hi int, Rconv func(int) string) {
+	regSpace = append(regSpace, regSet{lo, hi, Rconv})
+}
+
+func Rconv(reg int) string {
+	if reg == REG_NONE {
+		return "NONE"
+	}
+	for i := range regSpace {
+		rs := &regSpace[i]
+		if rs.lo <= reg && reg < rs.hi {
+			return rs.Rconv(reg)
+		}
+	}
+	return fmt.Sprintf("R???%d", reg)
+}
+
+func regListConv(list int) string {
+	str := ""
+
+	for i := 0; i < 16; i++ { // TODO: 16 is ARM-specific.
+		if list&(1<<uint(i)) != 0 {
+			if str == "" {
+				str += "["
+			} else {
+				str += ","
+			}
+			// This is ARM-specific; R10 is g.
+			if i == 10 {
+				str += "g"
+			} else {
+				str += fmt.Sprintf("R%d", i)
+			}
+		}
+	}
+
+	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",
+}
+
+func Bool2int(b bool) int {
+	if b {
+		return 1
+	}
+	return 0
+}
diff --git a/src/cmd/internal/obj/x86/a.out.go b/src/cmd/internal/obj/x86/a.out.go
new file mode 100644
index 0000000..c7f46e1
--- /dev/null
+++ b/src/cmd/internal/obj/x86/a.out.go
@@ -0,0 +1,910 @@
+// Inferno utils/6c/6.out.h
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/6.out.h
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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 x86
+
+import "cmd/internal/obj"
+
+//go:generate go run ../stringer.go -i $GOFILE -o anames.go -p x86
+
+/*
+ *	amd64
+ */
+const (
+	AAAA = obj.ABaseAMD64 + 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
+	ADECQ
+	ADECW
+	ADIVB
+	ADIVL
+	ADIVW
+	AENTER
+	AHLT
+	AIDIVB
+	AIDIVL
+	AIDIVW
+	AIMULB
+	AIMULL
+	AIMULW
+	AINB
+	AINL
+	AINW
+	AINCB
+	AINCL
+	AINCQ
+	AINCW
+	AINSB
+	AINSL
+	AINSW
+	AINT
+	AINTO
+	AIRETL
+	AIRETW
+	AJCC
+	AJCS
+	AJCXZL
+	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
+	AMOVBLSX
+	AMOVBLZX
+	AMOVBQSX
+	AMOVBQZX
+	AMOVBWSX
+	AMOVBWZX
+	AMOVWLSX
+	AMOVWLZX
+	AMOVWQSX
+	AMOVWQZX
+	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
+	AFCOML
+	AFCOMLP
+	AFCOMW
+	AFCOMWP
+	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
+	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
+
+	// extra 32-bit operations
+	ACMPXCHGB
+	ACMPXCHGL
+	ACMPXCHGW
+	ACMPXCHG8B
+	ACPUID
+	AINVD
+	AINVLPG
+	ALFENCE
+	AMFENCE
+	AMOVNTIL
+	ARDMSR
+	ARDPMC
+	ARDTSC
+	ARSM
+	ASFENCE
+	ASYSRET
+	AWBINVD
+	AWRMSR
+	AXADDB
+	AXADDL
+	AXADDW
+
+	// conditional move
+	ACMOVLCC
+	ACMOVLCS
+	ACMOVLEQ
+	ACMOVLGE
+	ACMOVLGT
+	ACMOVLHI
+	ACMOVLLE
+	ACMOVLLS
+	ACMOVLLT
+	ACMOVLMI
+	ACMOVLNE
+	ACMOVLOC
+	ACMOVLOS
+	ACMOVLPC
+	ACMOVLPL
+	ACMOVLPS
+	ACMOVQCC
+	ACMOVQCS
+	ACMOVQEQ
+	ACMOVQGE
+	ACMOVQGT
+	ACMOVQHI
+	ACMOVQLE
+	ACMOVQLS
+	ACMOVQLT
+	ACMOVQMI
+	ACMOVQNE
+	ACMOVQOC
+	ACMOVQOS
+	ACMOVQPC
+	ACMOVQPL
+	ACMOVQPS
+	ACMOVWCC
+	ACMOVWCS
+	ACMOVWEQ
+	ACMOVWGE
+	ACMOVWGT
+	ACMOVWHI
+	ACMOVWLE
+	ACMOVWLS
+	ACMOVWLT
+	ACMOVWMI
+	ACMOVWNE
+	ACMOVWOC
+	ACMOVWOS
+	ACMOVWPC
+	ACMOVWPL
+	ACMOVWPS
+
+	// 64-bit
+	AADCQ
+	AADDQ
+	AANDQ
+	ABSFQ
+	ABSRQ
+	ABTCQ
+	ABTQ
+	ABTRQ
+	ABTSQ
+	ACMPQ
+	ACMPSQ
+	ACMPXCHGQ
+	ACQO
+	ADIVQ
+	AIDIVQ
+	AIMULQ
+	AIRETQ
+	AJCXZQ
+	ALEAQ
+	ALEAVEQ
+	ALODSQ
+	AMOVQ
+	AMOVLQSX
+	AMOVLQZX
+	AMOVNTIQ
+	AMOVSQ
+	AMULQ
+	ANEGQ
+	ANOTQ
+	AORQ
+	APOPFQ
+	APOPQ
+	APUSHFQ
+	APUSHQ
+	ARCLQ
+	ARCRQ
+	AROLQ
+	ARORQ
+	AQUAD
+	ASALQ
+	ASARQ
+	ASBBQ
+	ASCASQ
+	ASHLQ
+	ASHRQ
+	ASTOSQ
+	ASUBQ
+	ATESTQ
+	AXADDQ
+	AXCHGQ
+	AXORQ
+
+	// media
+	AADDPD
+	AADDPS
+	AADDSD
+	AADDSS
+	AANDNPD
+	AANDNPS
+	AANDPD
+	AANDPS
+	ACMPPD
+	ACMPPS
+	ACMPSD
+	ACMPSS
+	ACOMISD
+	ACOMISS
+	ACVTPD2PL
+	ACVTPD2PS
+	ACVTPL2PD
+	ACVTPL2PS
+	ACVTPS2PD
+	ACVTPS2PL
+	ACVTSD2SL
+	ACVTSD2SQ
+	ACVTSD2SS
+	ACVTSL2SD
+	ACVTSL2SS
+	ACVTSQ2SD
+	ACVTSQ2SS
+	ACVTSS2SD
+	ACVTSS2SL
+	ACVTSS2SQ
+	ACVTTPD2PL
+	ACVTTPS2PL
+	ACVTTSD2SL
+	ACVTTSD2SQ
+	ACVTTSS2SL
+	ACVTTSS2SQ
+	ADIVPD
+	ADIVPS
+	ADIVSD
+	ADIVSS
+	AEMMS
+	AFXRSTOR
+	AFXRSTOR64
+	AFXSAVE
+	AFXSAVE64
+	ALDMXCSR
+	AMASKMOVOU
+	AMASKMOVQ
+	AMAXPD
+	AMAXPS
+	AMAXSD
+	AMAXSS
+	AMINPD
+	AMINPS
+	AMINSD
+	AMINSS
+	AMOVAPD
+	AMOVAPS
+	AMOVOU
+	AMOVHLPS
+	AMOVHPD
+	AMOVHPS
+	AMOVLHPS
+	AMOVLPD
+	AMOVLPS
+	AMOVMSKPD
+	AMOVMSKPS
+	AMOVNTO
+	AMOVNTPD
+	AMOVNTPS
+	AMOVNTQ
+	AMOVO
+	AMOVQOZX
+	AMOVSD
+	AMOVSS
+	AMOVUPD
+	AMOVUPS
+	AMULPD
+	AMULPS
+	AMULSD
+	AMULSS
+	AORPD
+	AORPS
+	APACKSSLW
+	APACKSSWB
+	APACKUSWB
+	APADDB
+	APADDL
+	APADDQ
+	APADDSB
+	APADDSW
+	APADDUSB
+	APADDUSW
+	APADDW
+	APANDB
+	APANDL
+	APANDSB
+	APANDSW
+	APANDUSB
+	APANDUSW
+	APANDW
+	APAND
+	APANDN
+	APAVGB
+	APAVGW
+	APCMPEQB
+	APCMPEQL
+	APCMPEQW
+	APCMPGTB
+	APCMPGTL
+	APCMPGTW
+	APEXTRW
+	APFACC
+	APFADD
+	APFCMPEQ
+	APFCMPGE
+	APFCMPGT
+	APFMAX
+	APFMIN
+	APFMUL
+	APFNACC
+	APFPNACC
+	APFRCP
+	APFRCPIT1
+	APFRCPI2T
+	APFRSQIT1
+	APFRSQRT
+	APFSUB
+	APFSUBR
+	APINSRW
+	APINSRD
+	APINSRQ
+	APMADDWL
+	APMAXSW
+	APMAXUB
+	APMINSW
+	APMINUB
+	APMOVMSKB
+	APMULHRW
+	APMULHUW
+	APMULHW
+	APMULLW
+	APMULULQ
+	APOR
+	APSADBW
+	APSHUFHW
+	APSHUFL
+	APSHUFLW
+	APSHUFW
+	APSHUFB
+	APSLLO
+	APSLLL
+	APSLLQ
+	APSLLW
+	APSRAL
+	APSRAW
+	APSRLO
+	APSRLL
+	APSRLQ
+	APSRLW
+	APSUBB
+	APSUBL
+	APSUBQ
+	APSUBSB
+	APSUBSW
+	APSUBUSB
+	APSUBUSW
+	APSUBW
+	APSWAPL
+	APUNPCKHBW
+	APUNPCKHLQ
+	APUNPCKHQDQ
+	APUNPCKHWL
+	APUNPCKLBW
+	APUNPCKLLQ
+	APUNPCKLQDQ
+	APUNPCKLWL
+	APXOR
+	ARCPPS
+	ARCPSS
+	ARSQRTPS
+	ARSQRTSS
+	ASHUFPD
+	ASHUFPS
+	ASQRTPD
+	ASQRTPS
+	ASQRTSD
+	ASQRTSS
+	ASTMXCSR
+	ASUBPD
+	ASUBPS
+	ASUBSD
+	ASUBSS
+	AUCOMISD
+	AUCOMISS
+	AUNPCKHPD
+	AUNPCKHPS
+	AUNPCKLPD
+	AUNPCKLPS
+	AXORPD
+	AXORPS
+
+	APF2IW
+	APF2IL
+	API2FW
+	API2FL
+	ARETFW
+	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
+)
+
+const (
+	REG_AL = obj.RBaseAMD64 + iota
+	REG_CL
+	REG_DL
+	REG_BL
+	REG_SPB
+	REG_BPB
+	REG_SIB
+	REG_DIB
+	REG_R8B
+	REG_R9B
+	REG_R10B
+	REG_R11B
+	REG_R12B
+	REG_R13B
+	REG_R14B
+	REG_R15B
+
+	REG_AX
+	REG_CX
+	REG_DX
+	REG_BX
+	REG_SP
+	REG_BP
+	REG_SI
+	REG_DI
+	REG_R8
+	REG_R9
+	REG_R10
+	REG_R11
+	REG_R12
+	REG_R13
+	REG_R14
+	REG_R15
+
+	REG_AH
+	REG_CH
+	REG_DH
+	REG_BH
+
+	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
+	REG_X4
+	REG_X5
+	REG_X6
+	REG_X7
+	REG_X8
+	REG_X9
+	REG_X10
+	REG_X11
+	REG_X12
+	REG_X13
+	REG_X14
+	REG_X15
+
+	REG_CS
+	REG_SS
+	REG_DS
+	REG_ES
+	REG_FS
+	REG_GS
+
+	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     /* 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
+	T_FCONST = 1 << 3
+	T_SYM    = 1 << 4
+	T_SCONST = 1 << 5
+	T_64     = 1 << 6
+	T_GOTYPE = 1 << 7
+)
diff --git a/src/cmd/internal/obj/x86/anames.go b/src/cmd/internal/obj/x86/anames.go
new file mode 100644
index 0000000..7f7708c
--- /dev/null
+++ b/src/cmd/internal/obj/x86/anames.go
@@ -0,0 +1,696 @@
+// Generated by stringer -i a.out.go -o anames.go -p x86
+// Do not edit.
+
+package x86
+
+import "cmd/internal/obj"
+
+var Anames = []string{
+	obj.A_ARCHSPECIFIC: "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",
+	"DECQ",
+	"DECW",
+	"DIVB",
+	"DIVL",
+	"DIVW",
+	"ENTER",
+	"HLT",
+	"IDIVB",
+	"IDIVL",
+	"IDIVW",
+	"IMULB",
+	"IMULL",
+	"IMULW",
+	"INB",
+	"INL",
+	"INW",
+	"INCB",
+	"INCL",
+	"INCQ",
+	"INCW",
+	"INSB",
+	"INSL",
+	"INSW",
+	"INT",
+	"INTO",
+	"IRETL",
+	"IRETW",
+	"JCC",
+	"JCS",
+	"JCXZL",
+	"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",
+	"MOVBLSX",
+	"MOVBLZX",
+	"MOVBQSX",
+	"MOVBQZX",
+	"MOVBWSX",
+	"MOVBWZX",
+	"MOVWLSX",
+	"MOVWLZX",
+	"MOVWQSX",
+	"MOVWQZX",
+	"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",
+	"FCOML",
+	"FCOMLP",
+	"FCOMW",
+	"FCOMWP",
+	"FUCOM",
+	"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",
+	"INVD",
+	"INVLPG",
+	"LFENCE",
+	"MFENCE",
+	"MOVNTIL",
+	"RDMSR",
+	"RDPMC",
+	"RDTSC",
+	"RSM",
+	"SFENCE",
+	"SYSRET",
+	"WBINVD",
+	"WRMSR",
+	"XADDB",
+	"XADDL",
+	"XADDW",
+	"CMOVLCC",
+	"CMOVLCS",
+	"CMOVLEQ",
+	"CMOVLGE",
+	"CMOVLGT",
+	"CMOVLHI",
+	"CMOVLLE",
+	"CMOVLLS",
+	"CMOVLLT",
+	"CMOVLMI",
+	"CMOVLNE",
+	"CMOVLOC",
+	"CMOVLOS",
+	"CMOVLPC",
+	"CMOVLPL",
+	"CMOVLPS",
+	"CMOVQCC",
+	"CMOVQCS",
+	"CMOVQEQ",
+	"CMOVQGE",
+	"CMOVQGT",
+	"CMOVQHI",
+	"CMOVQLE",
+	"CMOVQLS",
+	"CMOVQLT",
+	"CMOVQMI",
+	"CMOVQNE",
+	"CMOVQOC",
+	"CMOVQOS",
+	"CMOVQPC",
+	"CMOVQPL",
+	"CMOVQPS",
+	"CMOVWCC",
+	"CMOVWCS",
+	"CMOVWEQ",
+	"CMOVWGE",
+	"CMOVWGT",
+	"CMOVWHI",
+	"CMOVWLE",
+	"CMOVWLS",
+	"CMOVWLT",
+	"CMOVWMI",
+	"CMOVWNE",
+	"CMOVWOC",
+	"CMOVWOS",
+	"CMOVWPC",
+	"CMOVWPL",
+	"CMOVWPS",
+	"ADCQ",
+	"ADDQ",
+	"ANDQ",
+	"BSFQ",
+	"BSRQ",
+	"BTCQ",
+	"BTQ",
+	"BTRQ",
+	"BTSQ",
+	"CMPQ",
+	"CMPSQ",
+	"CMPXCHGQ",
+	"CQO",
+	"DIVQ",
+	"IDIVQ",
+	"IMULQ",
+	"IRETQ",
+	"JCXZQ",
+	"LEAQ",
+	"LEAVEQ",
+	"LODSQ",
+	"MOVQ",
+	"MOVLQSX",
+	"MOVLQZX",
+	"MOVNTIQ",
+	"MOVSQ",
+	"MULQ",
+	"NEGQ",
+	"NOTQ",
+	"ORQ",
+	"POPFQ",
+	"POPQ",
+	"PUSHFQ",
+	"PUSHQ",
+	"RCLQ",
+	"RCRQ",
+	"ROLQ",
+	"RORQ",
+	"QUAD",
+	"SALQ",
+	"SARQ",
+	"SBBQ",
+	"SCASQ",
+	"SHLQ",
+	"SHRQ",
+	"STOSQ",
+	"SUBQ",
+	"TESTQ",
+	"XADDQ",
+	"XCHGQ",
+	"XORQ",
+	"ADDPD",
+	"ADDPS",
+	"ADDSD",
+	"ADDSS",
+	"ANDNPD",
+	"ANDNPS",
+	"ANDPD",
+	"ANDPS",
+	"CMPPD",
+	"CMPPS",
+	"CMPSD",
+	"CMPSS",
+	"COMISD",
+	"COMISS",
+	"CVTPD2PL",
+	"CVTPD2PS",
+	"CVTPL2PD",
+	"CVTPL2PS",
+	"CVTPS2PD",
+	"CVTPS2PL",
+	"CVTSD2SL",
+	"CVTSD2SQ",
+	"CVTSD2SS",
+	"CVTSL2SD",
+	"CVTSL2SS",
+	"CVTSQ2SD",
+	"CVTSQ2SS",
+	"CVTSS2SD",
+	"CVTSS2SL",
+	"CVTSS2SQ",
+	"CVTTPD2PL",
+	"CVTTPS2PL",
+	"CVTTSD2SL",
+	"CVTTSD2SQ",
+	"CVTTSS2SL",
+	"CVTTSS2SQ",
+	"DIVPD",
+	"DIVPS",
+	"DIVSD",
+	"DIVSS",
+	"EMMS",
+	"FXRSTOR",
+	"FXRSTOR64",
+	"FXSAVE",
+	"FXSAVE64",
+	"LDMXCSR",
+	"MASKMOVOU",
+	"MASKMOVQ",
+	"MAXPD",
+	"MAXPS",
+	"MAXSD",
+	"MAXSS",
+	"MINPD",
+	"MINPS",
+	"MINSD",
+	"MINSS",
+	"MOVAPD",
+	"MOVAPS",
+	"MOVOU",
+	"MOVHLPS",
+	"MOVHPD",
+	"MOVHPS",
+	"MOVLHPS",
+	"MOVLPD",
+	"MOVLPS",
+	"MOVMSKPD",
+	"MOVMSKPS",
+	"MOVNTO",
+	"MOVNTPD",
+	"MOVNTPS",
+	"MOVNTQ",
+	"MOVO",
+	"MOVQOZX",
+	"MOVSD",
+	"MOVSS",
+	"MOVUPD",
+	"MOVUPS",
+	"MULPD",
+	"MULPS",
+	"MULSD",
+	"MULSS",
+	"ORPD",
+	"ORPS",
+	"PACKSSLW",
+	"PACKSSWB",
+	"PACKUSWB",
+	"PADDB",
+	"PADDL",
+	"PADDQ",
+	"PADDSB",
+	"PADDSW",
+	"PADDUSB",
+	"PADDUSW",
+	"PADDW",
+	"PANDB",
+	"PANDL",
+	"PANDSB",
+	"PANDSW",
+	"PANDUSB",
+	"PANDUSW",
+	"PANDW",
+	"PAND",
+	"PANDN",
+	"PAVGB",
+	"PAVGW",
+	"PCMPEQB",
+	"PCMPEQL",
+	"PCMPEQW",
+	"PCMPGTB",
+	"PCMPGTL",
+	"PCMPGTW",
+	"PEXTRW",
+	"PFACC",
+	"PFADD",
+	"PFCMPEQ",
+	"PFCMPGE",
+	"PFCMPGT",
+	"PFMAX",
+	"PFMIN",
+	"PFMUL",
+	"PFNACC",
+	"PFPNACC",
+	"PFRCP",
+	"PFRCPIT1",
+	"PFRCPI2T",
+	"PFRSQIT1",
+	"PFRSQRT",
+	"PFSUB",
+	"PFSUBR",
+	"PINSRW",
+	"PINSRD",
+	"PINSRQ",
+	"PMADDWL",
+	"PMAXSW",
+	"PMAXUB",
+	"PMINSW",
+	"PMINUB",
+	"PMOVMSKB",
+	"PMULHRW",
+	"PMULHUW",
+	"PMULHW",
+	"PMULLW",
+	"PMULULQ",
+	"POR",
+	"PSADBW",
+	"PSHUFHW",
+	"PSHUFL",
+	"PSHUFLW",
+	"PSHUFW",
+	"PSHUFB",
+	"PSLLO",
+	"PSLLL",
+	"PSLLQ",
+	"PSLLW",
+	"PSRAL",
+	"PSRAW",
+	"PSRLO",
+	"PSRLL",
+	"PSRLQ",
+	"PSRLW",
+	"PSUBB",
+	"PSUBL",
+	"PSUBQ",
+	"PSUBSB",
+	"PSUBSW",
+	"PSUBUSB",
+	"PSUBUSW",
+	"PSUBW",
+	"PSWAPL",
+	"PUNPCKHBW",
+	"PUNPCKHLQ",
+	"PUNPCKHQDQ",
+	"PUNPCKHWL",
+	"PUNPCKLBW",
+	"PUNPCKLLQ",
+	"PUNPCKLQDQ",
+	"PUNPCKLWL",
+	"PXOR",
+	"RCPPS",
+	"RCPSS",
+	"RSQRTPS",
+	"RSQRTSS",
+	"SHUFPD",
+	"SHUFPS",
+	"SQRTPD",
+	"SQRTPS",
+	"SQRTSD",
+	"SQRTSS",
+	"STMXCSR",
+	"SUBPD",
+	"SUBPS",
+	"SUBSD",
+	"SUBSS",
+	"UCOMISD",
+	"UCOMISS",
+	"UNPCKHPD",
+	"UNPCKHPS",
+	"UNPCKLPD",
+	"UNPCKLPS",
+	"XORPD",
+	"XORPS",
+	"PF2IW",
+	"PF2IL",
+	"PI2FW",
+	"PI2FL",
+	"RETFW",
+	"RETFL",
+	"RETFQ",
+	"SWAPGS",
+	"MODE",
+	"CRC32B",
+	"CRC32Q",
+	"IMUL3Q",
+	"PREFETCHT0",
+	"PREFETCHT1",
+	"PREFETCHT2",
+	"PREFETCHNTA",
+	"MOVQL",
+	"BSWAPL",
+	"BSWAPQ",
+	"AESENC",
+	"AESENCLAST",
+	"AESDEC",
+	"AESDECLAST",
+	"AESIMC",
+	"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
new file mode 100644
index 0000000..7a69dc8
--- /dev/null
+++ b/src/cmd/internal/obj/x86/asm6.go
@@ -0,0 +1,4380 @@
+// Inferno utils/6l/span.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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 x86
+
+import (
+	"cmd/internal/obj"
+	"fmt"
+	"log"
+	"strings"
+)
+
+// Instruction layout.
+
+const (
+	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
+)
+
+type Optab struct {
+	as     int16
+	ytab   []ytab
+	prefix uint8
+	op     [23]uint8
+}
+
+type ytab struct {
+	from    uint8
+	from3   uint8
+	to      uint8
+	zcase   uint8
+	zoffset uint8
+}
+
+type Movtab struct {
+	as   int16
+	ft   uint8
+	f3t  uint8
+	tt   uint8
+	code uint8
+	op   [4]uint8
+}
+
+const (
+	Yxxx = iota
+	Ynone
+	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
+	Yiauto
+	Yal
+	Ycl
+	Yax
+	Ycx
+	Yrb
+	Yrl
+	Yrl32 // Yrl on 32-bit system
+	Yrf
+	Yf0
+	Yrx
+	Ymb
+	Yml
+	Ym
+	Ybr
+	Ycs
+	Yss
+	Yds
+	Yes
+	Yfs
+	Ygs
+	Ygdtr
+	Yidtr
+	Yldtr
+	Ymsw
+	Ytask
+	Ycr0
+	Ycr1
+	Ycr2
+	Ycr3
+	Ycr4
+	Ycr5
+	Ycr6
+	Ycr7
+	Ycr8
+	Ydr0
+	Ydr1
+	Ydr2
+	Ydr3
+	Ydr4
+	Ydr5
+	Ydr6
+	Ydr7
+	Ytr0
+	Ytr1
+	Ytr2
+	Ytr3
+	Ytr4
+	Ytr5
+	Ytr6
+	Ytr7
+	Ymr
+	Ymm
+	Yxr
+	Yxm
+	Ytls
+	Ytextsize
+	Yindir
+	Ymax
+)
+
+const (
+	Zxxx = iota
+	Zlit
+	Zlitm_r
+	Z_rp
+	Zbr
+	Zcall
+	Zcallcon
+	Zcallduff
+	Zcallind
+	Zcallindreg
+	Zib_
+	Zib_rp
+	Zibo_m
+	Zibo_m_xm
+	Zil_
+	Zil_rp
+	Ziq_rp
+	Zilo_m
+	Ziqo_m
+	Zjmp
+	Zjmpcon
+	Zloop
+	Zo_iw
+	Zm_o
+	Zm_r
+	Zm2_r
+	Zm_r_xm
+	Zm_r_i_xm
+	Zm_r_3d
+	Zm_r_xm_nr
+	Zr_m_xm_nr
+	Zibm_r /* mmx1,mmx2/mem64,imm8 */
+	Zmb_r
+	Zaut_r
+	Zo_m
+	Zo_m64
+	Zpseudo
+	Zr_m
+	Zr_m_xm
+	Zrp_
+	Z_ib
+	Z_il
+	Zm_ibo
+	Zm_ilo
+	Zib_rr
+	Zil_rr
+	Zclr
+	Zbyte
+	Zmax
+)
+
+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
+
+var reg [MAXREG]int
+
+var regrex [MAXREG + 1]int
+
+var ynone = []ytab{
+	{Ynone, Ynone, Ynone, Zlit, 1},
+}
+
+var ysahf = []ytab{
+	{Ynone, Ynone, Ynone, Zlit, 2},
+	{Ynone, Ynone, Ynone, Zlit, 1},
+}
+
+var ytext = []ytab{
+	{Ymb, Ynone, Ytextsize, Zpseudo, 0},
+	{Ymb, Yi32, Ytextsize, Zpseudo, 1},
+}
+
+var ynop = []ytab{
+	{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, Ynone, Ym, Zpseudo, 0},
+}
+
+var ypcdata = []ytab{
+	{Yi32, Ynone, Yi32, Zpseudo, 0},
+}
+
+var yxorb = []ytab{
+	{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, 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, 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, Ynone, Ymb, Zo_m, 2},
+}
+
+var yincw = []ytab{
+	{Ynone, Ynone, Yml, Zo_m, 2},
+}
+
+var yincl = []ytab{
+	{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, 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, 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, Ynone, Ymb, Zo_m, 2},
+	{Yi32, Ynone, Ymb, Zibo_m, 2},
+	{Ycx, Ynone, Ymb, Zo_m, 2},
+}
+
+var yshl = []ytab{
+	{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, 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, 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, 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, Ynone, Zm_o, 2},
+}
+
+var ybtl = []ytab{
+	{Yi8, Ynone, Yml, Zibo_m, 2},
+	{Yrl, Ynone, Yml, Zr_m, 1},
+}
+
+var ymovw = []ytab{
+	{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, 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, Ynone, Zo_iw, 1},
+	{Yi32, Ynone, Ynone, Zo_iw, 1},
+}
+
+var ymovq = []ytab{
+	// 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, Ynone, Yrl, Zm_r, 1},
+}
+
+var yrl_m = []ytab{
+	{Yrl, Ynone, Ym, Zr_m, 1},
+}
+
+var ymb_rl = []ytab{
+	{Ymb, Ynone, Yrl, Zmb_r, 1},
+}
+
+var yml_rl = []ytab{
+	{Yml, Ynone, Yrl, Zm_r, 1},
+}
+
+var yrl_ml = []ytab{
+	{Yrl, Ynone, Yml, Zr_m, 1},
+}
+
+var yml_mb = []ytab{
+	{Yrb, Ynone, Ymb, Zr_m, 1},
+	{Ymb, Ynone, Yrb, Zm_r, 1},
+}
+
+var yrb_mb = []ytab{
+	{Yrb, Ynone, Ymb, Zr_m, 1},
+}
+
+var yxchg = []ytab{
+	{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, Ynone, Zm_o, 2},
+}
+
+var ydivb = []ytab{
+	{Ymb, Ynone, Ynone, Zm_o, 2},
+}
+
+var yimul = []ytab{
+	{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{
+	{Yi8, Yml, Yrl, Zibm_r, 2},
+}
+
+var ybyte = []ytab{
+	{Yi64, Ynone, Ynone, Zbyte, 1},
+}
+
+var yin = []ytab{
+	{Yi32, Ynone, Ynone, Zib_, 1},
+	{Ynone, Ynone, Ynone, Zlit, 1},
+}
+
+var yint = []ytab{
+	{Yi32, Ynone, Ynone, Zib_, 1},
+}
+
+var ypushl = []ytab{
+	{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, Ynone, Yrl, Z_rp, 1},
+	{Ynone, Ynone, Ym, Zo_m, 2},
+}
+
+var ybswap = []ytab{
+	{Ynone, Ynone, Yrl, Z_rp, 2},
+}
+
+var yscond = []ytab{
+	{Ynone, Ynone, Ymb, Zo_m, 2},
+}
+
+var yjcond = []ytab{
+	{Ynone, Ynone, Ybr, Zbr, 0},
+	{Yi0, Ynone, Ybr, Zbr, 0},
+	{Yi1, Ynone, Ybr, Zbr, 1},
+}
+
+var yloop = []ytab{
+	{Ynone, Ynone, Ybr, Zloop, 1},
+}
+
+var ycall = []ytab{
+	{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, Ynone, Yi32, Zcallduff, 1},
+}
+
+var yjmp = []ytab{
+	{Ynone, Ynone, Yml, Zo_m64, 2},
+	{Ynone, Ynone, Ybr, Zjmp, 0},
+	{Ynone, Ynone, Yi32, Zjmpcon, 1},
+}
+
+var yfmvd = []ytab{
+	{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, Ynone, Ym, Zo_m, 2},
+	{Yf0, Ynone, Yrf, Zo_m, 2},
+}
+
+var yfmvf = []ytab{
+	{Ym, Ynone, Yf0, Zm_o, 2},
+	{Yf0, Ynone, Ym, Zo_m, 2},
+}
+
+var yfmvx = []ytab{
+	{Ym, Ynone, Yf0, Zm_o, 2},
+}
+
+var yfmvp = []ytab{
+	{Yf0, Ynone, Ym, Zo_m, 2},
+}
+
+var yfcmv = []ytab{
+	{Yrf, Ynone, Yf0, Zm_o, 2},
+}
+
+var yfadd = []ytab{
+	{Ym, Ynone, Yf0, Zm_o, 2},
+	{Yrf, Ynone, Yf0, Zm_o, 2},
+	{Yf0, Ynone, Yrf, Zo_m, 2},
+}
+
+var yfaddp = []ytab{
+	{Yf0, Ynone, Yrf, Zo_m, 2},
+}
+
+var yfxch = []ytab{
+	{Yf0, Ynone, Yrf, Zo_m, 2},
+	{Yrf, Ynone, Yf0, Zm_o, 2},
+}
+
+var ycompp = []ytab{
+	{Yf0, Ynone, Yrf, Zo_m, 2}, /* botch is really f0,f1 */
+}
+
+var ystsw = []ytab{
+	{Ynone, Ynone, Ym, Zo_m, 2},
+	{Ynone, Ynone, Yax, Zlit, 1},
+}
+
+var ystcw = []ytab{
+	{Ynone, Ynone, Ym, Zo_m, 2},
+	{Ym, Ynone, Ynone, Zm_o, 2},
+}
+
+var ysvrs = []ytab{
+	{Ynone, Ynone, Ym, Zo_m, 2},
+	{Ym, Ynone, Ynone, Zm_o, 2},
+}
+
+var ymm = []ytab{
+	{Ymm, Ynone, Ymr, Zm_r_xm, 1},
+	{Yxm, Ynone, Yxr, Zm_r_xm, 2},
+}
+
+var yxm = []ytab{
+	{Yxm, Ynone, Yxr, Zm_r_xm, 1},
+}
+
+var yxcvm1 = []ytab{
+	{Yxm, Ynone, Yxr, Zm_r_xm, 2},
+	{Yxm, Ynone, Ymr, Zm_r_xm, 2},
+}
+
+var yxcvm2 = []ytab{
+	{Yxm, Ynone, Yxr, Zm_r_xm, 2},
+	{Ymm, Ynone, Yxr, Zm_r_xm, 2},
+}
+
+/*
+var yxmq = []ytab{
+	{Yxm, Ynone, Yxr, Zm_r_xm, 2},
+}
+*/
+
+var yxr = []ytab{
+	{Yxr, Ynone, Yxr, Zm_r_xm, 1},
+}
+
+var yxr_ml = []ytab{
+	{Yxr, Ynone, Yml, Zr_m_xm, 1},
+}
+
+var ymr = []ytab{
+	{Ymr, Ynone, Ymr, Zm_r, 1},
+}
+
+var ymr_ml = []ytab{
+	{Ymr, Ynone, Yml, Zr_m_xm, 1},
+}
+
+var yxcmp = []ytab{
+	{Yxm, Ynone, Yxr, Zm_r_xm, 1},
+}
+
+var yxcmpi = []ytab{
+	{Yxm, Yxr, Yi8, Zm_r_i_xm, 2},
+}
+
+var yxmov = []ytab{
+	{Yxm, Ynone, Yxr, Zm_r_xm, 1},
+	{Yxr, Ynone, Yxm, Zr_m_xm, 1},
+}
+
+var yxcvfl = []ytab{
+	{Yxm, Ynone, Yrl, Zm_r_xm, 1},
+}
+
+var yxcvlf = []ytab{
+	{Yml, Ynone, Yxr, Zm_r_xm, 1},
+}
+
+var yxcvfq = []ytab{
+	{Yxm, Ynone, Yrl, Zm_r_xm, 2},
+}
+
+var yxcvqf = []ytab{
+	{Yml, Ynone, Yxr, Zm_r_xm, 2},
+}
+
+var yps = []ytab{
+	{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, Ynone, Yrl, Zm_r, 1},
+}
+
+var ymfp = []ytab{
+	{Ymm, Ynone, Ymr, Zm_r_3d, 1},
+}
+
+var ymrxr = []ytab{
+	{Ymr, Ynone, Yxr, Zm_r, 1},
+	{Yxm, Ynone, Yxr, Zm_r_xm, 1},
+}
+
+var ymshuf = []ytab{
+	{Yi8, Ymm, Ymr, Zibm_r, 2},
+}
+
+var ymshufb = []ytab{
+	{Yxm, Ynone, Yxr, Zm2_r, 2},
+}
+
+var yxshuf = []ytab{
+	{Yu8, Yxm, Yxr, Zibm_r, 2},
+}
+
+var yextrw = []ytab{
+	{Yu8, Yxr, Yrl, Zibm_r, 2},
+}
+
+var yinsrw = []ytab{
+	{Yu8, Yml, Yxr, Zibm_r, 2},
+}
+
+var yinsr = []ytab{
+	{Yu8, Ymm, Yxr, Zibm_r, 3},
+}
+
+var ypsdq = []ytab{
+	{Yi8, Ynone, Yxr, Zibo_m, 2},
+}
+
+var ymskb = []ytab{
+	{Yxr, Ynone, Yrl, Zm_r_xm, 2},
+	{Ymr, Ynone, Yrl, Zm_r_xm, 1},
+}
+
+var ycrc32l = []ytab{
+	{Yml, Ynone, Yrl, Zlitm_r, 0},
+}
+
+var yprefetch = []ytab{
+	{Ym, Ynone, Ynone, Zm_o, 2},
+}
+
+var yaes = []ytab{
+	{Yxm, Ynone, Yxr, Zlitm_r, 2},
+}
+
+var yaes2 = []ytab{
+	{Yu8, Yxm, Yxr, Zibm_r, 2},
+}
+
+/*
+ * You are doasm, holding in your hand a Prog* with p->as set to, say, ACRC32,
+ * and p->from and p->to as operands (Addr*).  The linker scans optab to find
+ * the entry with the given p->as and then looks through the ytable for that
+ * instruction (the second field in the optab struct) for a line whose first
+ * two values match the Ytypes of the p->from and p->to operands.  The function
+ * oclass in span.c computes the specific Ytype of an operand and then the set
+ * of more general Ytypes that it satisfies is implied by the ycover table, set
+ * up in instinit.  For example, oclass distinguishes the constants 0 and 1
+ * from the more general 8-bit constants, but instinit says
+ *
+ *        ycover[Yi0*Ymax + Ys32] = 1;
+ *        ycover[Yi1*Ymax + Ys32] = 1;
+ *        ycover[Yi8*Ymax + Ys32] = 1;
+ *
+ * which means that Yi0, Yi1, and Yi8 all count as Ys32 (signed 32)
+ * if that's what an instruction can handle.
+ *
+ * In parallel with the scan through the ytable for the appropriate line, there
+ * is a z pointer that starts out pointing at the strange magic byte list in
+ * the Optab struct.  With each step past a non-matching ytable line, z
+ * advances by the 4th entry in the line.  When a matching line is found, that
+ * z pointer has the extra data to use in laying down the instruction bytes.
+ * The actual bytes laid down are a function of the 3rd entry in the line (that
+ * is, the Ztype) and the z bytes.
+ *
+ * For example, let's look at AADDL.  The optab line says:
+ *        { AADDL,        yaddl,  Px, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
+ *
+ * and yaddl says
+ *        uchar   yaddl[] =
+ *        {
+ *                Yi8,    Yml,    Zibo_m, 2,
+ *                Yi32,   Yax,    Zil_,   1,
+ *                Yi32,   Yml,    Zilo_m, 2,
+ *                Yrl,    Yml,    Zr_m,   1,
+ *                Yml,    Yrl,    Zm_r,   1,
+ *                0
+ *        };
+ *
+ * so there are 5 possible types of ADDL instruction that can be laid down, and
+ * possible states used to lay them down (Ztype and z pointer, assuming z
+ * points at {0x83,(00),0x05,0x81,(00),0x01,0x03}) are:
+ *
+ *        Yi8, Yml -> Zibo_m, z (0x83, 00)
+ *        Yi32, Yax -> Zil_, z+2 (0x05)
+ *        Yi32, Yml -> Zilo_m, z+2+1 (0x81, 0x00)
+ *        Yrl, Yml -> Zr_m, z+2+1+2 (0x01)
+ *        Yml, Yrl -> Zm_r, z+2+1+2+1 (0x03)
+ *
+ * The Pconstant in the optab line controls the prefix bytes to emit.  That's
+ * relatively straightforward as this program goes.
+ *
+ * The switch on t[2] in doasm implements the various Z cases.  Zibo_m, for
+ * example, is an opcode byte (z[0]) then an asmando (which is some kind of
+ * encoded addressing mode for the Yml arg), and then a single immediate byte.
+ * Zilo_m is the same but a long (32-bit) immediate.
+ */
+var optab =
+/*	as, ytab, andproto, opcode */
+[]Optab{
+	Optab{obj.AXXX, nil, 0, [23]uint8{}},
+	Optab{AAAA, ynone, P32, [23]uint8{0x37}},
+	Optab{AAAD, ynone, P32, [23]uint8{0xd5, 0x0a}},
+	Optab{AAAM, ynone, P32, [23]uint8{0xd4, 0x0a}},
+	Optab{AAAS, ynone, P32, [23]uint8{0x3f}},
+	Optab{AADCB, yxorb, Pb, [23]uint8{0x14, 0x80, 02, 0x10, 0x10}},
+	Optab{AADCL, yxorl, Px, [23]uint8{0x83, 02, 0x15, 0x81, 02, 0x11, 0x13}},
+	Optab{AADCQ, yxorl, Pw, [23]uint8{0x83, 02, 0x15, 0x81, 02, 0x11, 0x13}},
+	Optab{AADCW, yxorl, Pe, [23]uint8{0x83, 02, 0x15, 0x81, 02, 0x11, 0x13}},
+	Optab{AADDB, yxorb, Pb, [23]uint8{0x04, 0x80, 00, 0x00, 0x02}},
+	Optab{AADDL, yaddl, Px, [23]uint8{0x83, 00, 0x05, 0x81, 00, 0x01, 0x03}},
+	Optab{AADDPD, yxm, Pq, [23]uint8{0x58}},
+	Optab{AADDPS, yxm, Pm, [23]uint8{0x58}},
+	Optab{AADDQ, yaddl, Pw, [23]uint8{0x83, 00, 0x05, 0x81, 00, 0x01, 0x03}},
+	Optab{AADDSD, yxm, Pf2, [23]uint8{0x58}},
+	Optab{AADDSS, yxm, Pf3, [23]uint8{0x58}},
+	Optab{AADDW, yaddl, Pe, [23]uint8{0x83, 00, 0x05, 0x81, 00, 0x01, 0x03}},
+	Optab{AADJSP, nil, 0, [23]uint8{}},
+	Optab{AANDB, yxorb, Pb, [23]uint8{0x24, 0x80, 04, 0x20, 0x22}},
+	Optab{AANDL, yxorl, Px, [23]uint8{0x83, 04, 0x25, 0x81, 04, 0x21, 0x23}},
+	Optab{AANDNPD, yxm, Pq, [23]uint8{0x55}},
+	Optab{AANDNPS, yxm, Pm, [23]uint8{0x55}},
+	Optab{AANDPD, yxm, Pq, [23]uint8{0x54}},
+	Optab{AANDPS, yxm, Pq, [23]uint8{0x54}},
+	Optab{AANDQ, yxorl, Pw, [23]uint8{0x83, 04, 0x25, 0x81, 04, 0x21, 0x23}},
+	Optab{AANDW, yxorl, Pe, [23]uint8{0x83, 04, 0x25, 0x81, 04, 0x21, 0x23}},
+	Optab{AARPL, yrl_ml, P32, [23]uint8{0x63}},
+	Optab{ABOUNDL, yrl_m, P32, [23]uint8{0x62}},
+	Optab{ABOUNDW, yrl_m, Pe, [23]uint8{0x62}},
+	Optab{ABSFL, yml_rl, Pm, [23]uint8{0xbc}},
+	Optab{ABSFQ, yml_rl, Pw, [23]uint8{0x0f, 0xbc}},
+	Optab{ABSFW, yml_rl, Pq, [23]uint8{0xbc}},
+	Optab{ABSRL, yml_rl, Pm, [23]uint8{0xbd}},
+	Optab{ABSRQ, yml_rl, Pw, [23]uint8{0x0f, 0xbd}},
+	Optab{ABSRW, yml_rl, Pq, [23]uint8{0xbd}},
+	Optab{ABSWAPL, ybswap, Px, [23]uint8{0x0f, 0xc8}},
+	Optab{ABSWAPQ, ybswap, Pw, [23]uint8{0x0f, 0xc8}},
+	Optab{ABTCL, ybtl, Pm, [23]uint8{0xba, 07, 0xbb}},
+	Optab{ABTCQ, ybtl, Pw, [23]uint8{0x0f, 0xba, 07, 0x0f, 0xbb}},
+	Optab{ABTCW, ybtl, Pq, [23]uint8{0xba, 07, 0xbb}},
+	Optab{ABTL, ybtl, Pm, [23]uint8{0xba, 04, 0xa3}},
+	Optab{ABTQ, ybtl, Pw, [23]uint8{0x0f, 0xba, 04, 0x0f, 0xa3}},
+	Optab{ABTRL, ybtl, Pm, [23]uint8{0xba, 06, 0xb3}},
+	Optab{ABTRQ, ybtl, Pw, [23]uint8{0x0f, 0xba, 06, 0x0f, 0xb3}},
+	Optab{ABTRW, ybtl, Pq, [23]uint8{0xba, 06, 0xb3}},
+	Optab{ABTSL, ybtl, Pm, [23]uint8{0xba, 05, 0xab}},
+	Optab{ABTSQ, ybtl, Pw, [23]uint8{0x0f, 0xba, 05, 0x0f, 0xab}},
+	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, 0xff, 0x15, 0xe8}},
+	Optab{ACDQ, ynone, Px, [23]uint8{0x99}},
+	Optab{ACLC, ynone, Px, [23]uint8{0xf8}},
+	Optab{ACLD, ynone, Px, [23]uint8{0xfc}},
+	Optab{ACLI, ynone, Px, [23]uint8{0xfa}},
+	Optab{ACLTS, ynone, Pm, [23]uint8{0x06}},
+	Optab{ACMC, ynone, Px, [23]uint8{0xf5}},
+	Optab{ACMOVLCC, yml_rl, Pm, [23]uint8{0x43}},
+	Optab{ACMOVLCS, yml_rl, Pm, [23]uint8{0x42}},
+	Optab{ACMOVLEQ, yml_rl, Pm, [23]uint8{0x44}},
+	Optab{ACMOVLGE, yml_rl, Pm, [23]uint8{0x4d}},
+	Optab{ACMOVLGT, yml_rl, Pm, [23]uint8{0x4f}},
+	Optab{ACMOVLHI, yml_rl, Pm, [23]uint8{0x47}},
+	Optab{ACMOVLLE, yml_rl, Pm, [23]uint8{0x4e}},
+	Optab{ACMOVLLS, yml_rl, Pm, [23]uint8{0x46}},
+	Optab{ACMOVLLT, yml_rl, Pm, [23]uint8{0x4c}},
+	Optab{ACMOVLMI, yml_rl, Pm, [23]uint8{0x48}},
+	Optab{ACMOVLNE, yml_rl, Pm, [23]uint8{0x45}},
+	Optab{ACMOVLOC, yml_rl, Pm, [23]uint8{0x41}},
+	Optab{ACMOVLOS, yml_rl, Pm, [23]uint8{0x40}},
+	Optab{ACMOVLPC, yml_rl, Pm, [23]uint8{0x4b}},
+	Optab{ACMOVLPL, yml_rl, Pm, [23]uint8{0x49}},
+	Optab{ACMOVLPS, yml_rl, Pm, [23]uint8{0x4a}},
+	Optab{ACMOVQCC, yml_rl, Pw, [23]uint8{0x0f, 0x43}},
+	Optab{ACMOVQCS, yml_rl, Pw, [23]uint8{0x0f, 0x42}},
+	Optab{ACMOVQEQ, yml_rl, Pw, [23]uint8{0x0f, 0x44}},
+	Optab{ACMOVQGE, yml_rl, Pw, [23]uint8{0x0f, 0x4d}},
+	Optab{ACMOVQGT, yml_rl, Pw, [23]uint8{0x0f, 0x4f}},
+	Optab{ACMOVQHI, yml_rl, Pw, [23]uint8{0x0f, 0x47}},
+	Optab{ACMOVQLE, yml_rl, Pw, [23]uint8{0x0f, 0x4e}},
+	Optab{ACMOVQLS, yml_rl, Pw, [23]uint8{0x0f, 0x46}},
+	Optab{ACMOVQLT, yml_rl, Pw, [23]uint8{0x0f, 0x4c}},
+	Optab{ACMOVQMI, yml_rl, Pw, [23]uint8{0x0f, 0x48}},
+	Optab{ACMOVQNE, yml_rl, Pw, [23]uint8{0x0f, 0x45}},
+	Optab{ACMOVQOC, yml_rl, Pw, [23]uint8{0x0f, 0x41}},
+	Optab{ACMOVQOS, yml_rl, Pw, [23]uint8{0x0f, 0x40}},
+	Optab{ACMOVQPC, yml_rl, Pw, [23]uint8{0x0f, 0x4b}},
+	Optab{ACMOVQPL, yml_rl, Pw, [23]uint8{0x0f, 0x49}},
+	Optab{ACMOVQPS, yml_rl, Pw, [23]uint8{0x0f, 0x4a}},
+	Optab{ACMOVWCC, yml_rl, Pq, [23]uint8{0x43}},
+	Optab{ACMOVWCS, yml_rl, Pq, [23]uint8{0x42}},
+	Optab{ACMOVWEQ, yml_rl, Pq, [23]uint8{0x44}},
+	Optab{ACMOVWGE, yml_rl, Pq, [23]uint8{0x4d}},
+	Optab{ACMOVWGT, yml_rl, Pq, [23]uint8{0x4f}},
+	Optab{ACMOVWHI, yml_rl, Pq, [23]uint8{0x47}},
+	Optab{ACMOVWLE, yml_rl, Pq, [23]uint8{0x4e}},
+	Optab{ACMOVWLS, yml_rl, Pq, [23]uint8{0x46}},
+	Optab{ACMOVWLT, yml_rl, Pq, [23]uint8{0x4c}},
+	Optab{ACMOVWMI, yml_rl, Pq, [23]uint8{0x48}},
+	Optab{ACMOVWNE, yml_rl, Pq, [23]uint8{0x45}},
+	Optab{ACMOVWOC, yml_rl, Pq, [23]uint8{0x41}},
+	Optab{ACMOVWOS, yml_rl, Pq, [23]uint8{0x40}},
+	Optab{ACMOVWPC, yml_rl, Pq, [23]uint8{0x4b}},
+	Optab{ACMOVWPL, yml_rl, Pq, [23]uint8{0x49}},
+	Optab{ACMOVWPS, yml_rl, Pq, [23]uint8{0x4a}},
+	Optab{ACMPB, ycmpb, Pb, [23]uint8{0x3c, 0x80, 07, 0x38, 0x3a}},
+	Optab{ACMPL, ycmpl, Px, [23]uint8{0x83, 07, 0x3d, 0x81, 07, 0x39, 0x3b}},
+	Optab{ACMPPD, yxcmpi, Px, [23]uint8{Pe, 0xc2}},
+	Optab{ACMPPS, yxcmpi, Pm, [23]uint8{0xc2, 0}},
+	Optab{ACMPQ, ycmpl, Pw, [23]uint8{0x83, 07, 0x3d, 0x81, 07, 0x39, 0x3b}},
+	Optab{ACMPSB, ynone, Pb, [23]uint8{0xa6}},
+	Optab{ACMPSD, yxcmpi, Px, [23]uint8{Pf2, 0xc2}},
+	Optab{ACMPSL, ynone, Px, [23]uint8{0xa7}},
+	Optab{ACMPSQ, ynone, Pw, [23]uint8{0xa7}},
+	Optab{ACMPSS, yxcmpi, Px, [23]uint8{Pf3, 0xc2}},
+	Optab{ACMPSW, ynone, Pe, [23]uint8{0xa7}},
+	Optab{ACMPW, ycmpl, Pe, [23]uint8{0x83, 07, 0x3d, 0x81, 07, 0x39, 0x3b}},
+	Optab{ACOMISD, yxcmp, Pe, [23]uint8{0x2f}},
+	Optab{ACOMISS, yxcmp, Pm, [23]uint8{0x2f}},
+	Optab{ACPUID, ynone, Pm, [23]uint8{0xa2}},
+	Optab{ACVTPL2PD, yxcvm2, Px, [23]uint8{Pf3, 0xe6, Pe, 0x2a}},
+	Optab{ACVTPL2PS, yxcvm2, Pm, [23]uint8{0x5b, 0, 0x2a, 0}},
+	Optab{ACVTPD2PL, yxcvm1, Px, [23]uint8{Pf2, 0xe6, Pe, 0x2d}},
+	Optab{ACVTPD2PS, yxm, Pe, [23]uint8{0x5a}},
+	Optab{ACVTPS2PL, yxcvm1, Px, [23]uint8{Pe, 0x5b, Pm, 0x2d}},
+	Optab{ACVTPS2PD, yxm, Pm, [23]uint8{0x5a}},
+	Optab{API2FW, ymfp, Px, [23]uint8{0x0c}},
+	Optab{ACVTSD2SL, yxcvfl, Pf2, [23]uint8{0x2d}},
+	Optab{ACVTSD2SQ, yxcvfq, Pw, [23]uint8{Pf2, 0x2d}},
+	Optab{ACVTSD2SS, yxm, Pf2, [23]uint8{0x5a}},
+	Optab{ACVTSL2SD, yxcvlf, Pf2, [23]uint8{0x2a}},
+	Optab{ACVTSQ2SD, yxcvqf, Pw, [23]uint8{Pf2, 0x2a}},
+	Optab{ACVTSL2SS, yxcvlf, Pf3, [23]uint8{0x2a}},
+	Optab{ACVTSQ2SS, yxcvqf, Pw, [23]uint8{Pf3, 0x2a}},
+	Optab{ACVTSS2SD, yxm, Pf3, [23]uint8{0x5a}},
+	Optab{ACVTSS2SL, yxcvfl, Pf3, [23]uint8{0x2d}},
+	Optab{ACVTSS2SQ, yxcvfq, Pw, [23]uint8{Pf3, 0x2d}},
+	Optab{ACVTTPD2PL, yxcvm1, Px, [23]uint8{Pe, 0xe6, Pe, 0x2c}},
+	Optab{ACVTTPS2PL, yxcvm1, Px, [23]uint8{Pf3, 0x5b, Pm, 0x2c}},
+	Optab{ACVTTSD2SL, yxcvfl, Pf2, [23]uint8{0x2c}},
+	Optab{ACVTTSD2SQ, yxcvfq, Pw, [23]uint8{Pf2, 0x2c}},
+	Optab{ACVTTSS2SL, yxcvfl, Pf3, [23]uint8{0x2c}},
+	Optab{ACVTTSS2SQ, yxcvfq, Pw, [23]uint8{Pf3, 0x2c}},
+	Optab{ACWD, ynone, Pe, [23]uint8{0x99}},
+	Optab{ACQO, ynone, Pw, [23]uint8{0x99}},
+	Optab{ADAA, ynone, P32, [23]uint8{0x27}},
+	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, 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}},
+	Optab{ADIVPD, yxm, Pe, [23]uint8{0x5e}},
+	Optab{ADIVPS, yxm, Pm, [23]uint8{0x5e}},
+	Optab{ADIVQ, ydivl, Pw, [23]uint8{0xf7, 06}},
+	Optab{ADIVSD, yxm, Pf2, [23]uint8{0x5e}},
+	Optab{ADIVSS, yxm, Pf3, [23]uint8{0x5e}},
+	Optab{ADIVW, ydivl, Pe, [23]uint8{0xf7, 06}},
+	Optab{AEMMS, ynone, Pm, [23]uint8{0x77}},
+	Optab{AENTER, nil, 0, [23]uint8{}}, /* botch */
+	Optab{AFXRSTOR, ysvrs, Pm, [23]uint8{0xae, 01, 0xae, 01}},
+	Optab{AFXSAVE, ysvrs, Pm, [23]uint8{0xae, 00, 0xae, 00}},
+	Optab{AFXRSTOR64, ysvrs, Pw, [23]uint8{0x0f, 0xae, 01, 0x0f, 0xae, 01}},
+	Optab{AFXSAVE64, ysvrs, Pw, [23]uint8{0x0f, 0xae, 00, 0x0f, 0xae, 00}},
+	Optab{obj.AGLOBL, nil, 0, [23]uint8{}},
+	Optab{AHLT, ynone, Px, [23]uint8{0xf4}},
+	Optab{AIDIVB, ydivb, Pb, [23]uint8{0xf6, 07}},
+	Optab{AIDIVL, ydivl, Px, [23]uint8{0xf7, 07}},
+	Optab{AIDIVQ, ydivl, Pw, [23]uint8{0xf7, 07}},
+	Optab{AIDIVW, ydivl, Pe, [23]uint8{0xf7, 07}},
+	Optab{AIMULB, ydivb, Pb, [23]uint8{0xf6, 05}},
+	Optab{AIMULL, yimul, Px, [23]uint8{0xf7, 05, 0x6b, 0x69, Pm, 0xaf}},
+	Optab{AIMULQ, yimul, Pw, [23]uint8{0xf7, 05, 0x6b, 0x69, Pm, 0xaf}},
+	Optab{AIMULW, yimul, Pe, [23]uint8{0xf7, 05, 0x6b, 0x69, Pm, 0xaf}},
+	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, 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}},
+	Optab{AINSL, ynone, Px, [23]uint8{0x6d}},
+	Optab{AINSW, ynone, Pe, [23]uint8{0x6d}},
+	Optab{AINT, yint, Px, [23]uint8{0xcd}},
+	Optab{AINTO, ynone, P32, [23]uint8{0xce}},
+	Optab{AINW, yin, Pe, [23]uint8{0xe5, 0xed}},
+	Optab{AIRETL, ynone, Px, [23]uint8{0xcf}},
+	Optab{AIRETQ, ynone, Pw, [23]uint8{0xcf}},
+	Optab{AIRETW, ynone, Pe, [23]uint8{0xcf}},
+	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}},
+	Optab{AJGT, yjcond, Px, [23]uint8{0x7f, 0x8f}},
+	Optab{AJHI, yjcond, Px, [23]uint8{0x77, 0x87}},
+	Optab{AJLE, yjcond, Px, [23]uint8{0x7e, 0x8e}},
+	Optab{AJLS, yjcond, Px, [23]uint8{0x76, 0x86}},
+	Optab{AJLT, yjcond, Px, [23]uint8{0x7c, 0x8c}},
+	Optab{AJMI, yjcond, Px, [23]uint8{0x78, 0x88}},
+	Optab{obj.AJMP, yjmp, Px, [23]uint8{0xff, 04, 0xeb, 0xe9}},
+	Optab{AJNE, yjcond, Px, [23]uint8{0x75, 0x85}},
+	Optab{AJOC, yjcond, Px, [23]uint8{0x71, 0x81, 00}},
+	Optab{AJOS, yjcond, Px, [23]uint8{0x70, 0x80, 00}},
+	Optab{AJPC, yjcond, Px, [23]uint8{0x7b, 0x8b}},
+	Optab{AJPL, yjcond, Px, [23]uint8{0x79, 0x89}},
+	Optab{AJPS, yjcond, Px, [23]uint8{0x7a, 0x8a}},
+	Optab{ALAHF, ynone, Px, [23]uint8{0x9f}},
+	Optab{ALARL, yml_rl, Pm, [23]uint8{0x02}},
+	Optab{ALARW, yml_rl, Pq, [23]uint8{0x02}},
+	Optab{ALDMXCSR, ysvrs, Pm, [23]uint8{0xae, 02, 0xae, 02}},
+	Optab{ALEAL, ym_rl, Px, [23]uint8{0x8d}},
+	Optab{ALEAQ, ym_rl, Pw, [23]uint8{0x8d}},
+	Optab{ALEAVEL, ynone, P32, [23]uint8{0xc9}},
+	Optab{ALEAVEQ, ynone, Py, [23]uint8{0xc9}},
+	Optab{ALEAVEW, ynone, Pe, [23]uint8{0xc9}},
+	Optab{ALEAW, ym_rl, Pe, [23]uint8{0x8d}},
+	Optab{ALOCK, ynone, Px, [23]uint8{0xf0}},
+	Optab{ALODSB, ynone, Pb, [23]uint8{0xac}},
+	Optab{ALODSL, ynone, Px, [23]uint8{0xad}},
+	Optab{ALODSQ, ynone, Pw, [23]uint8{0xad}},
+	Optab{ALODSW, ynone, Pe, [23]uint8{0xad}},
+	Optab{ALONG, ybyte, Px, [23]uint8{4}},
+	Optab{ALOOP, yloop, Px, [23]uint8{0xe2}},
+	Optab{ALOOPEQ, yloop, Px, [23]uint8{0xe1}},
+	Optab{ALOOPNE, yloop, Px, [23]uint8{0xe0}},
+	Optab{ALSLL, yml_rl, Pm, [23]uint8{0x03}},
+	Optab{ALSLW, yml_rl, Pq, [23]uint8{0x03}},
+	Optab{AMASKMOVOU, yxr, Pe, [23]uint8{0xf7}},
+	Optab{AMASKMOVQ, ymr, Pm, [23]uint8{0xf7}},
+	Optab{AMAXPD, yxm, Pe, [23]uint8{0x5f}},
+	Optab{AMAXPS, yxm, Pm, [23]uint8{0x5f}},
+	Optab{AMAXSD, yxm, Pf2, [23]uint8{0x5f}},
+	Optab{AMAXSS, yxm, Pf3, [23]uint8{0x5f}},
+	Optab{AMINPD, yxm, Pe, [23]uint8{0x5d}},
+	Optab{AMINPS, yxm, Pm, [23]uint8{0x5d}},
+	Optab{AMINSD, yxm, Pf2, [23]uint8{0x5d}},
+	Optab{AMINSS, yxm, Pf3, [23]uint8{0x5d}},
+	Optab{AMOVAPD, yxmov, Pe, [23]uint8{0x28, 0x29}},
+	Optab{AMOVAPS, yxmov, Pm, [23]uint8{0x28, 0x29}},
+	Optab{AMOVB, ymovb, Pb, [23]uint8{0x88, 0x8a, 0xb0, 0xc6, 00}},
+	Optab{AMOVBLSX, ymb_rl, Pm, [23]uint8{0xbe}},
+	Optab{AMOVBLZX, ymb_rl, Pm, [23]uint8{0xb6}},
+	Optab{AMOVBQSX, ymb_rl, Pw, [23]uint8{0x0f, 0xbe}},
+	Optab{AMOVBQZX, ymb_rl, Pm, [23]uint8{0xb6}},
+	Optab{AMOVBWSX, ymb_rl, Pq, [23]uint8{0xbe}},
+	Optab{AMOVBWZX, ymb_rl, Pq, [23]uint8{0xb6}},
+	Optab{AMOVO, yxmov, Pe, [23]uint8{0x6f, 0x7f}},
+	Optab{AMOVOU, yxmov, Pf3, [23]uint8{0x6f, 0x7f}},
+	Optab{AMOVHLPS, yxr, Pm, [23]uint8{0x12}},
+	Optab{AMOVHPD, yxmov, Pe, [23]uint8{0x16, 0x17}},
+	Optab{AMOVHPS, yxmov, Pm, [23]uint8{0x16, 0x17}},
+	Optab{AMOVL, ymovl, Px, [23]uint8{0x89, 0x8b, 0x31, 0xb8, 0xc7, 00, 0x6e, 0x7e, Pe, 0x6e, Pe, 0x7e, 0}},
+	Optab{AMOVLHPS, yxr, Pm, [23]uint8{0x16}},
+	Optab{AMOVLPD, yxmov, Pe, [23]uint8{0x12, 0x13}},
+	Optab{AMOVLPS, yxmov, Pm, [23]uint8{0x12, 0x13}},
+	Optab{AMOVLQSX, yml_rl, Pw, [23]uint8{0x63}},
+	Optab{AMOVLQZX, yml_rl, Px, [23]uint8{0x8b}},
+	Optab{AMOVMSKPD, yxrrl, Pq, [23]uint8{0x50}},
+	Optab{AMOVMSKPS, yxrrl, Pm, [23]uint8{0x50}},
+	Optab{AMOVNTO, yxr_ml, Pe, [23]uint8{0xe7}},
+	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, 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}},
+	Optab{AMOVSL, ynone, Px, [23]uint8{0xa5}},
+	Optab{AMOVSQ, ynone, Pw, [23]uint8{0xa5}},
+	Optab{AMOVSS, yxmov, Pf3, [23]uint8{0x10, 0x11}},
+	Optab{AMOVSW, ynone, Pe, [23]uint8{0xa5}},
+	Optab{AMOVUPD, yxmov, Pe, [23]uint8{0x10, 0x11}},
+	Optab{AMOVUPS, yxmov, Pm, [23]uint8{0x10, 0x11}},
+	Optab{AMOVW, ymovw, Pe, [23]uint8{0x89, 0x8b, 0x31, 0xb8, 0xc7, 00, 0}},
+	Optab{AMOVWLSX, yml_rl, Pm, [23]uint8{0xbf}},
+	Optab{AMOVWLZX, yml_rl, Pm, [23]uint8{0xb7}},
+	Optab{AMOVWQSX, yml_rl, Pw, [23]uint8{0x0f, 0xbf}},
+	Optab{AMOVWQZX, yml_rl, Pw, [23]uint8{0x0f, 0xb7}},
+	Optab{AMULB, ydivb, Pb, [23]uint8{0xf6, 04}},
+	Optab{AMULL, ydivl, Px, [23]uint8{0xf7, 04}},
+	Optab{AMULPD, yxm, Pe, [23]uint8{0x59}},
+	Optab{AMULPS, yxm, Ym, [23]uint8{0x59}},
+	Optab{AMULQ, ydivl, Pw, [23]uint8{0xf7, 04}},
+	Optab{AMULSD, yxm, Pf2, [23]uint8{0x59}},
+	Optab{AMULSS, yxm, Pf3, [23]uint8{0x59}},
+	Optab{AMULW, ydivl, Pe, [23]uint8{0xf7, 04}},
+	Optab{ANEGB, yscond, Pb, [23]uint8{0xf6, 03}},
+	Optab{ANEGL, yscond, Px, [23]uint8{0xf7, 03}},
+	Optab{ANEGQ, yscond, Pw, [23]uint8{0xf7, 03}},
+	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}}, // 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}},
+	Optab{AORL, yxorl, Px, [23]uint8{0x83, 01, 0x0d, 0x81, 01, 0x09, 0x0b}},
+	Optab{AORPD, yxm, Pq, [23]uint8{0x56}},
+	Optab{AORPS, yxm, Pm, [23]uint8{0x56}},
+	Optab{AORQ, yxorl, Pw, [23]uint8{0x83, 01, 0x0d, 0x81, 01, 0x09, 0x0b}},
+	Optab{AORW, yxorl, Pe, [23]uint8{0x83, 01, 0x0d, 0x81, 01, 0x09, 0x0b}},
+	Optab{AOUTB, yin, Pb, [23]uint8{0xe6, 0xee}},
+	Optab{AOUTL, yin, Px, [23]uint8{0xe7, 0xef}},
+	Optab{AOUTSB, ynone, Pb, [23]uint8{0x6e}},
+	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, 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, 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, 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}},
+	Optab{API2FL, ymfp, Px, [23]uint8{0x0d}},
+	Optab{APFACC, ymfp, Px, [23]uint8{0xae}},
+	Optab{APFADD, ymfp, Px, [23]uint8{0x9e}},
+	Optab{APFCMPEQ, ymfp, Px, [23]uint8{0xb0}},
+	Optab{APFCMPGE, ymfp, Px, [23]uint8{0x90}},
+	Optab{APFCMPGT, ymfp, Px, [23]uint8{0xa0}},
+	Optab{APFMAX, ymfp, Px, [23]uint8{0xa4}},
+	Optab{APFMIN, ymfp, Px, [23]uint8{0x94}},
+	Optab{APFMUL, ymfp, Px, [23]uint8{0xb4}},
+	Optab{APFNACC, ymfp, Px, [23]uint8{0x8a}},
+	Optab{APFPNACC, ymfp, Px, [23]uint8{0x8e}},
+	Optab{APFRCP, ymfp, Px, [23]uint8{0x96}},
+	Optab{APFRCPIT1, ymfp, Px, [23]uint8{0xa6}},
+	Optab{APFRCPI2T, ymfp, Px, [23]uint8{0xb6}},
+	Optab{APFRSQIT1, ymfp, Px, [23]uint8{0xa7}},
+	Optab{APFRSQRT, ymfp, Px, [23]uint8{0x97}},
+	Optab{APFSUB, ymfp, Px, [23]uint8{0x9a}},
+	Optab{APFSUBR, ymfp, Px, [23]uint8{0xaa}},
+	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, 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, 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}},
+	Optab{APOPFQ, ynone, Py, [23]uint8{0x9d}},
+	Optab{APOPFW, ynone, Pe, [23]uint8{0x9d}},
+	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, 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}},
+	Optab{APSHUFLW, yxshuf, Pf2, [23]uint8{0x70, 00}},
+	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, 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, 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}},
+	Optab{APSUBSB, yxm, Pe, [23]uint8{0xe8}},
+	Optab{APSUBSW, yxm, Pe, [23]uint8{0xe9}},
+	Optab{APSUBUSB, yxm, Pe, [23]uint8{0xd8}},
+	Optab{APSUBUSW, yxm, Pe, [23]uint8{0xd9}},
+	Optab{APSUBW, yxm, Pe, [23]uint8{0xf9}},
+	Optab{APSWAPL, ymfp, Px, [23]uint8{0xbb}},
+	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, 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, 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}},
+	Optab{APUSHFQ, ynone, Py, [23]uint8{0x9c}},
+	Optab{APUSHFW, ynone, Pe, [23]uint8{0x9c}},
+	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, 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}},
+	Optab{ARCLQ, yshl, Pw, [23]uint8{0xd1, 02, 0xc1, 02, 0xd3, 02, 0xd3, 02}},
+	Optab{ARCLW, yshl, Pe, [23]uint8{0xd1, 02, 0xc1, 02, 0xd3, 02, 0xd3, 02}},
+	Optab{ARCPPS, yxm, Pm, [23]uint8{0x53}},
+	Optab{ARCPSS, yxm, Pf3, [23]uint8{0x53}},
+	Optab{ARCRB, yshb, Pb, [23]uint8{0xd0, 03, 0xc0, 03, 0xd2, 03}},
+	Optab{ARCRL, yshl, Px, [23]uint8{0xd1, 03, 0xc1, 03, 0xd3, 03, 0xd3, 03}},
+	Optab{ARCRQ, yshl, Pw, [23]uint8{0xd1, 03, 0xc1, 03, 0xd3, 03, 0xd3, 03}},
+	Optab{ARCRW, yshl, Pe, [23]uint8{0xd1, 03, 0xc1, 03, 0xd3, 03, 0xd3, 03}},
+	Optab{AREP, ynone, Px, [23]uint8{0xf3}},
+	Optab{AREPN, ynone, Px, [23]uint8{0xf2}},
+	Optab{obj.ARET, ynone, Px, [23]uint8{0xc3}},
+	Optab{ARETFW, yret, Pe, [23]uint8{0xcb, 0xca}},
+	Optab{ARETFL, yret, Px, [23]uint8{0xcb, 0xca}},
+	Optab{ARETFQ, yret, Pw, [23]uint8{0xcb, 0xca}},
+	Optab{AROLB, yshb, Pb, [23]uint8{0xd0, 00, 0xc0, 00, 0xd2, 00}},
+	Optab{AROLL, yshl, Px, [23]uint8{0xd1, 00, 0xc1, 00, 0xd3, 00, 0xd3, 00}},
+	Optab{AROLQ, yshl, Pw, [23]uint8{0xd1, 00, 0xc1, 00, 0xd3, 00, 0xd3, 00}},
+	Optab{AROLW, yshl, Pe, [23]uint8{0xd1, 00, 0xc1, 00, 0xd3, 00, 0xd3, 00}},
+	Optab{ARORB, yshb, Pb, [23]uint8{0xd0, 01, 0xc0, 01, 0xd2, 01}},
+	Optab{ARORL, yshl, Px, [23]uint8{0xd1, 01, 0xc1, 01, 0xd3, 01, 0xd3, 01}},
+	Optab{ARORQ, yshl, Pw, [23]uint8{0xd1, 01, 0xc1, 01, 0xd3, 01, 0xd3, 01}},
+	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, 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}},
+	Optab{ASALW, yshl, Pe, [23]uint8{0xd1, 04, 0xc1, 04, 0xd3, 04, 0xd3, 04}},
+	Optab{ASARB, yshb, Pb, [23]uint8{0xd0, 07, 0xc0, 07, 0xd2, 07}},
+	Optab{ASARL, yshl, Px, [23]uint8{0xd1, 07, 0xc1, 07, 0xd3, 07, 0xd3, 07}},
+	Optab{ASARQ, yshl, Pw, [23]uint8{0xd1, 07, 0xc1, 07, 0xd3, 07, 0xd3, 07}},
+	Optab{ASARW, yshl, Pe, [23]uint8{0xd1, 07, 0xc1, 07, 0xd3, 07, 0xd3, 07}},
+	Optab{ASBBB, yxorb, Pb, [23]uint8{0x1c, 0x80, 03, 0x18, 0x1a}},
+	Optab{ASBBL, yxorl, Px, [23]uint8{0x83, 03, 0x1d, 0x81, 03, 0x19, 0x1b}},
+	Optab{ASBBQ, yxorl, Pw, [23]uint8{0x83, 03, 0x1d, 0x81, 03, 0x19, 0x1b}},
+	Optab{ASBBW, yxorl, Pe, [23]uint8{0x83, 03, 0x1d, 0x81, 03, 0x19, 0x1b}},
+	Optab{ASCASB, ynone, Pb, [23]uint8{0xae}},
+	Optab{ASCASL, ynone, Px, [23]uint8{0xaf}},
+	Optab{ASCASQ, ynone, Pw, [23]uint8{0xaf}},
+	Optab{ASCASW, ynone, Pe, [23]uint8{0xaf}},
+	Optab{ASETCC, yscond, Pb, [23]uint8{0x0f, 0x93, 00}},
+	Optab{ASETCS, yscond, Pb, [23]uint8{0x0f, 0x92, 00}},
+	Optab{ASETEQ, yscond, Pb, [23]uint8{0x0f, 0x94, 00}},
+	Optab{ASETGE, yscond, Pb, [23]uint8{0x0f, 0x9d, 00}},
+	Optab{ASETGT, yscond, Pb, [23]uint8{0x0f, 0x9f, 00}},
+	Optab{ASETHI, yscond, Pb, [23]uint8{0x0f, 0x97, 00}},
+	Optab{ASETLE, yscond, Pb, [23]uint8{0x0f, 0x9e, 00}},
+	Optab{ASETLS, yscond, Pb, [23]uint8{0x0f, 0x96, 00}},
+	Optab{ASETLT, yscond, Pb, [23]uint8{0x0f, 0x9c, 00}},
+	Optab{ASETMI, yscond, Pb, [23]uint8{0x0f, 0x98, 00}},
+	Optab{ASETNE, yscond, Pb, [23]uint8{0x0f, 0x95, 00}},
+	Optab{ASETOC, yscond, Pb, [23]uint8{0x0f, 0x91, 00}},
+	Optab{ASETOS, yscond, Pb, [23]uint8{0x0f, 0x90, 00}},
+	Optab{ASETPC, yscond, Pb, [23]uint8{0x0f, 0x9b, 00}},
+	Optab{ASETPL, yscond, Pb, [23]uint8{0x0f, 0x99, 00}},
+	Optab{ASETPS, yscond, Pb, [23]uint8{0x0f, 0x9a, 00}},
+	Optab{ASHLB, yshb, Pb, [23]uint8{0xd0, 04, 0xc0, 04, 0xd2, 04}},
+	Optab{ASHLL, yshl, Px, [23]uint8{0xd1, 04, 0xc1, 04, 0xd3, 04, 0xd3, 04}},
+	Optab{ASHLQ, yshl, Pw, [23]uint8{0xd1, 04, 0xc1, 04, 0xd3, 04, 0xd3, 04}},
+	Optab{ASHLW, yshl, Pe, [23]uint8{0xd1, 04, 0xc1, 04, 0xd3, 04, 0xd3, 04}},
+	Optab{ASHRB, yshb, Pb, [23]uint8{0xd0, 05, 0xc0, 05, 0xd2, 05}},
+	Optab{ASHRL, yshl, Px, [23]uint8{0xd1, 05, 0xc1, 05, 0xd3, 05, 0xd3, 05}},
+	Optab{ASHRQ, yshl, Pw, [23]uint8{0xd1, 05, 0xc1, 05, 0xd3, 05, 0xd3, 05}},
+	Optab{ASHRW, yshl, Pe, [23]uint8{0xd1, 05, 0xc1, 05, 0xd3, 05, 0xd3, 05}},
+	Optab{ASHUFPD, yxshuf, Pq, [23]uint8{0xc6, 00}},
+	Optab{ASHUFPS, yxshuf, Pm, [23]uint8{0xc6, 00}},
+	Optab{ASQRTPD, yxm, Pe, [23]uint8{0x51}},
+	Optab{ASQRTPS, yxm, Pm, [23]uint8{0x51}},
+	Optab{ASQRTSD, yxm, Pf2, [23]uint8{0x51}},
+	Optab{ASQRTSS, yxm, Pf3, [23]uint8{0x51}},
+	Optab{ASTC, ynone, Px, [23]uint8{0xf9}},
+	Optab{ASTD, ynone, Px, [23]uint8{0xfd}},
+	Optab{ASTI, ynone, Px, [23]uint8{0xfb}},
+	Optab{ASTMXCSR, ysvrs, Pm, [23]uint8{0xae, 03, 0xae, 03}},
+	Optab{ASTOSB, ynone, Pb, [23]uint8{0xaa}},
+	Optab{ASTOSL, ynone, Px, [23]uint8{0xab}},
+	Optab{ASTOSQ, ynone, Pw, [23]uint8{0xab}},
+	Optab{ASTOSW, ynone, Pe, [23]uint8{0xab}},
+	Optab{ASUBB, yxorb, Pb, [23]uint8{0x2c, 0x80, 05, 0x28, 0x2a}},
+	Optab{ASUBL, yaddl, Px, [23]uint8{0x83, 05, 0x2d, 0x81, 05, 0x29, 0x2b}},
+	Optab{ASUBPD, yxm, Pe, [23]uint8{0x5c}},
+	Optab{ASUBPS, yxm, Pm, [23]uint8{0x5c}},
+	Optab{ASUBQ, yaddl, Pw, [23]uint8{0x83, 05, 0x2d, 0x81, 05, 0x29, 0x2b}},
+	Optab{ASUBSD, yxm, Pf2, [23]uint8{0x5c}},
+	Optab{ASUBSS, yxm, Pf3, [23]uint8{0x5c}},
+	Optab{ASUBW, yaddl, Pe, [23]uint8{0x83, 05, 0x2d, 0x81, 05, 0x29, 0x2b}},
+	Optab{ASWAPGS, ynone, Pm, [23]uint8{0x01, 0xf8}},
+	Optab{ASYSCALL, ynone, Px, [23]uint8{0x0f, 0x05}}, /* fast syscall */
+	Optab{ATESTB, ytestb, Pb, [23]uint8{0xa8, 0xf6, 00, 0x84, 0x84}},
+	Optab{ATESTL, ytestl, Px, [23]uint8{0xa9, 0xf7, 00, 0x85, 0x85}},
+	Optab{ATESTQ, ytestl, Pw, [23]uint8{0xa9, 0xf7, 00, 0x85, 0x85}},
+	Optab{ATESTW, ytestl, Pe, [23]uint8{0xa9, 0xf7, 00, 0x85, 0x85}},
+	Optab{obj.ATEXT, ytext, Px, [23]uint8{}},
+	Optab{AUCOMISD, yxcmp, Pe, [23]uint8{0x2e}},
+	Optab{AUCOMISS, yxcmp, Pm, [23]uint8{0x2e}},
+	Optab{AUNPCKHPD, yxm, Pe, [23]uint8{0x15}},
+	Optab{AUNPCKHPS, yxm, Pm, [23]uint8{0x15}},
+	Optab{AUNPCKLPD, yxm, Pe, [23]uint8{0x14}},
+	Optab{AUNPCKLPS, yxm, Pm, [23]uint8{0x14}},
+	Optab{AVERR, ydivl, Pm, [23]uint8{0x00, 04}},
+	Optab{AVERW, ydivl, Pm, [23]uint8{0x00, 05}},
+	Optab{AWAIT, ynone, Px, [23]uint8{0x9b}},
+	Optab{AWORD, ybyte, Px, [23]uint8{2}},
+	Optab{AXCHGB, yml_mb, Pb, [23]uint8{0x86, 0x86}},
+	Optab{AXCHGL, yxchg, Px, [23]uint8{0x90, 0x90, 0x87, 0x87}},
+	Optab{AXCHGQ, yxchg, Pw, [23]uint8{0x90, 0x90, 0x87, 0x87}},
+	Optab{AXCHGW, yxchg, Pe, [23]uint8{0x90, 0x90, 0x87, 0x87}},
+	Optab{AXLAT, ynone, Px, [23]uint8{0xd7}},
+	Optab{AXORB, yxorb, Pb, [23]uint8{0x34, 0x80, 06, 0x30, 0x32}},
+	Optab{AXORL, yxorl, Px, [23]uint8{0x83, 06, 0x35, 0x81, 06, 0x31, 0x33}},
+	Optab{AXORPD, yxm, Pe, [23]uint8{0x57}},
+	Optab{AXORPS, yxm, Pm, [23]uint8{0x57}},
+	Optab{AXORQ, yxorl, Pw, [23]uint8{0x83, 06, 0x35, 0x81, 06, 0x31, 0x33}},
+	Optab{AXORW, yxorl, Pe, [23]uint8{0x83, 06, 0x35, 0x81, 06, 0x31, 0x33}},
+	Optab{AFMOVB, yfmvx, Px, [23]uint8{0xdf, 04}},
+	Optab{AFMOVBP, yfmvp, Px, [23]uint8{0xdf, 06}},
+	Optab{AFMOVD, yfmvd, Px, [23]uint8{0xdd, 00, 0xdd, 02, 0xd9, 00, 0xdd, 02}},
+	Optab{AFMOVDP, yfmvdp, Px, [23]uint8{0xdd, 03, 0xdd, 03}},
+	Optab{AFMOVF, yfmvf, Px, [23]uint8{0xd9, 00, 0xd9, 02}},
+	Optab{AFMOVFP, yfmvp, Px, [23]uint8{0xd9, 03}},
+	Optab{AFMOVL, yfmvf, Px, [23]uint8{0xdb, 00, 0xdb, 02}},
+	Optab{AFMOVLP, yfmvp, Px, [23]uint8{0xdb, 03}},
+	Optab{AFMOVV, yfmvx, Px, [23]uint8{0xdf, 05}},
+	Optab{AFMOVVP, yfmvp, Px, [23]uint8{0xdf, 07}},
+	Optab{AFMOVW, yfmvf, Px, [23]uint8{0xdf, 00, 0xdf, 02}},
+	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 */
+	Optab{AFCOMDP, yfadd, Px, [23]uint8{0xdc, 03, 0xd8, 03, 0xdc, 03}}, /* botch */
+	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}},
+	Optab{AFADDW, yfmvx, Px, [23]uint8{0xde, 00}},
+	Optab{AFADDL, yfmvx, Px, [23]uint8{0xda, 00}},
+	Optab{AFADDF, yfmvx, Px, [23]uint8{0xd8, 00}},
+	Optab{AFADDD, yfadd, Px, [23]uint8{0xdc, 00, 0xd8, 00, 0xdc, 00}},
+	Optab{AFMULDP, yfaddp, Px, [23]uint8{0xde, 01}},
+	Optab{AFMULW, yfmvx, Px, [23]uint8{0xde, 01}},
+	Optab{AFMULL, yfmvx, Px, [23]uint8{0xda, 01}},
+	Optab{AFMULF, yfmvx, Px, [23]uint8{0xd8, 01}},
+	Optab{AFMULD, yfadd, Px, [23]uint8{0xdc, 01, 0xd8, 01, 0xdc, 01}},
+	Optab{AFSUBDP, yfaddp, Px, [23]uint8{0xde, 05}},
+	Optab{AFSUBW, yfmvx, Px, [23]uint8{0xde, 04}},
+	Optab{AFSUBL, yfmvx, Px, [23]uint8{0xda, 04}},
+	Optab{AFSUBF, yfmvx, Px, [23]uint8{0xd8, 04}},
+	Optab{AFSUBD, yfadd, Px, [23]uint8{0xdc, 04, 0xd8, 04, 0xdc, 05}},
+	Optab{AFSUBRDP, yfaddp, Px, [23]uint8{0xde, 04}},
+	Optab{AFSUBRW, yfmvx, Px, [23]uint8{0xde, 05}},
+	Optab{AFSUBRL, yfmvx, Px, [23]uint8{0xda, 05}},
+	Optab{AFSUBRF, yfmvx, Px, [23]uint8{0xd8, 05}},
+	Optab{AFSUBRD, yfadd, Px, [23]uint8{0xdc, 05, 0xd8, 05, 0xdc, 04}},
+	Optab{AFDIVDP, yfaddp, Px, [23]uint8{0xde, 07}},
+	Optab{AFDIVW, yfmvx, Px, [23]uint8{0xde, 06}},
+	Optab{AFDIVL, yfmvx, Px, [23]uint8{0xda, 06}},
+	Optab{AFDIVF, yfmvx, Px, [23]uint8{0xd8, 06}},
+	Optab{AFDIVD, yfadd, Px, [23]uint8{0xdc, 06, 0xd8, 06, 0xdc, 07}},
+	Optab{AFDIVRDP, yfaddp, Px, [23]uint8{0xde, 06}},
+	Optab{AFDIVRW, yfmvx, Px, [23]uint8{0xde, 07}},
+	Optab{AFDIVRL, yfmvx, Px, [23]uint8{0xda, 07}},
+	Optab{AFDIVRF, yfmvx, Px, [23]uint8{0xd8, 07}},
+	Optab{AFDIVRD, yfadd, Px, [23]uint8{0xdc, 07, 0xd8, 07, 0xdc, 06}},
+	Optab{AFXCHD, yfxch, Px, [23]uint8{0xd9, 01, 0xd9, 01}},
+	Optab{AFFREE, nil, 0, [23]uint8{}},
+	Optab{AFLDCW, ystcw, Px, [23]uint8{0xd9, 05, 0xd9, 05}},
+	Optab{AFLDENV, ystcw, Px, [23]uint8{0xd9, 04, 0xd9, 04}},
+	Optab{AFRSTOR, ysvrs, Px, [23]uint8{0xdd, 04, 0xdd, 04}},
+	Optab{AFSAVE, ysvrs, Px, [23]uint8{0xdd, 06, 0xdd, 06}},
+	Optab{AFSTCW, ystcw, Px, [23]uint8{0xd9, 07, 0xd9, 07}},
+	Optab{AFSTENV, ystcw, Px, [23]uint8{0xd9, 06, 0xd9, 06}},
+	Optab{AFSTSW, ystsw, Px, [23]uint8{0xdd, 07, 0xdf, 0xe0}},
+	Optab{AF2XM1, ynone, Px, [23]uint8{0xd9, 0xf0}},
+	Optab{AFABS, ynone, Px, [23]uint8{0xd9, 0xe1}},
+	Optab{AFCHS, ynone, Px, [23]uint8{0xd9, 0xe0}},
+	Optab{AFCLEX, ynone, Px, [23]uint8{0xdb, 0xe2}},
+	Optab{AFCOS, ynone, Px, [23]uint8{0xd9, 0xff}},
+	Optab{AFDECSTP, ynone, Px, [23]uint8{0xd9, 0xf6}},
+	Optab{AFINCSTP, ynone, Px, [23]uint8{0xd9, 0xf7}},
+	Optab{AFINIT, ynone, Px, [23]uint8{0xdb, 0xe3}},
+	Optab{AFLD1, ynone, Px, [23]uint8{0xd9, 0xe8}},
+	Optab{AFLDL2E, ynone, Px, [23]uint8{0xd9, 0xea}},
+	Optab{AFLDL2T, ynone, Px, [23]uint8{0xd9, 0xe9}},
+	Optab{AFLDLG2, ynone, Px, [23]uint8{0xd9, 0xec}},
+	Optab{AFLDLN2, ynone, Px, [23]uint8{0xd9, 0xed}},
+	Optab{AFLDPI, ynone, Px, [23]uint8{0xd9, 0xeb}},
+	Optab{AFLDZ, ynone, Px, [23]uint8{0xd9, 0xee}},
+	Optab{AFNOP, ynone, Px, [23]uint8{0xd9, 0xd0}},
+	Optab{AFPATAN, ynone, Px, [23]uint8{0xd9, 0xf3}},
+	Optab{AFPREM, ynone, Px, [23]uint8{0xd9, 0xf8}},
+	Optab{AFPREM1, ynone, Px, [23]uint8{0xd9, 0xf5}},
+	Optab{AFPTAN, ynone, Px, [23]uint8{0xd9, 0xf2}},
+	Optab{AFRNDINT, ynone, Px, [23]uint8{0xd9, 0xfc}},
+	Optab{AFSCALE, ynone, Px, [23]uint8{0xd9, 0xfd}},
+	Optab{AFSIN, ynone, Px, [23]uint8{0xd9, 0xfe}},
+	Optab{AFSINCOS, ynone, Px, [23]uint8{0xd9, 0xfb}},
+	Optab{AFSQRT, ynone, Px, [23]uint8{0xd9, 0xfa}},
+	Optab{AFTST, ynone, Px, [23]uint8{0xd9, 0xe4}},
+	Optab{AFXAM, ynone, Px, [23]uint8{0xd9, 0xe5}},
+	Optab{AFXTRACT, ynone, Px, [23]uint8{0xd9, 0xf4}},
+	Optab{AFYL2X, ynone, Px, [23]uint8{0xd9, 0xf1}},
+	Optab{AFYL2XP1, ynone, Px, [23]uint8{0xd9, 0xf9}},
+	Optab{ACMPXCHGB, yrb_mb, Pb, [23]uint8{0x0f, 0xb0}},
+	Optab{ACMPXCHGL, yrl_ml, Px, [23]uint8{0x0f, 0xb1}},
+	Optab{ACMPXCHGW, yrl_ml, Pe, [23]uint8{0x0f, 0xb1}},
+	Optab{ACMPXCHGQ, yrl_ml, Pw, [23]uint8{0x0f, 0xb1}},
+	Optab{ACMPXCHG8B, yscond, Pm, [23]uint8{0xc7, 01}},
+	Optab{AINVD, ynone, Pm, [23]uint8{0x08}},
+	Optab{AINVLPG, ymbs, Pm, [23]uint8{0x01, 07}},
+	Optab{ALFENCE, ynone, Pm, [23]uint8{0xae, 0xe8}},
+	Optab{AMFENCE, ynone, Pm, [23]uint8{0xae, 0xf0}},
+	Optab{AMOVNTIL, yrl_ml, Pm, [23]uint8{0xc3}},
+	Optab{AMOVNTIQ, yrl_ml, Pw, [23]uint8{0x0f, 0xc3}},
+	Optab{ARDMSR, ynone, Pm, [23]uint8{0x32}},
+	Optab{ARDPMC, ynone, Pm, [23]uint8{0x33}},
+	Optab{ARDTSC, ynone, Pm, [23]uint8{0x31}},
+	Optab{ARSM, ynone, Pm, [23]uint8{0xaa}},
+	Optab{ASFENCE, ynone, Pm, [23]uint8{0xae, 0xf8}},
+	Optab{ASYSRET, ynone, Pm, [23]uint8{0x07}},
+	Optab{AWBINVD, ynone, Pm, [23]uint8{0x09}},
+	Optab{AWRMSR, ynone, Pm, [23]uint8{0x30}},
+	Optab{AXADDB, yrb_mb, Pb, [23]uint8{0x0f, 0xc0}},
+	Optab{AXADDL, yrl_ml, Px, [23]uint8{0x0f, 0xc1}},
+	Optab{AXADDQ, yrl_ml, Pw, [23]uint8{0x0f, 0xc1}},
+	Optab{AXADDW, yrl_ml, Pe, [23]uint8{0x0f, 0xc1}},
+	Optab{ACRC32B, ycrc32l, Px, [23]uint8{0xf2, 0x0f, 0x38, 0xf0, 0}},
+	Optab{ACRC32Q, ycrc32l, Pw, [23]uint8{0xf2, 0x0f, 0x38, 0xf1, 0}},
+	Optab{APREFETCHT0, yprefetch, Pm, [23]uint8{0x18, 01}},
+	Optab{APREFETCHT1, yprefetch, Pm, [23]uint8{0x18, 02}},
+	Optab{APREFETCHT2, yprefetch, Pm, [23]uint8{0x18, 03}},
+	Optab{APREFETCHNTA, yprefetch, Pm, [23]uint8{0x18, 00}},
+	Optab{AMOVQL, yrl_ml, Px, [23]uint8{0x89}},
+	Optab{obj.AUNDEF, ynone, Px, [23]uint8{0x0f, 0x0b}},
+	Optab{AAESENC, yaes, Pq, [23]uint8{0x38, 0xdc, 0}},
+	Optab{AAESENCLAST, yaes, Pq, [23]uint8{0x38, 0xdd, 0}},
+	Optab{AAESDEC, yaes, Pq, [23]uint8{0x38, 0xde, 0}},
+	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, 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{}},
+	Optab{obj.AFUNCDATA, yfuncdata, Px, [23]uint8{0, 0}},
+	Optab{obj.APCDATA, ypcdata, Px, [23]uint8{0, 0}},
+	Optab{obj.ACHECKNIL, nil, 0, [23]uint8{}},
+	Optab{obj.AVARDEF, nil, 0, [23]uint8{}},
+	Optab{obj.AVARKILL, nil, 0, [23]uint8{}},
+	Optab{obj.ADUFFCOPY, yduff, Px, [23]uint8{0xe8}},
+	Optab{obj.ADUFFZERO, yduff, Px, [23]uint8{0xe8}},
+	Optab{obj.AEND, nil, 0, [23]uint8{}},
+	Optab{0, nil, 0, [23]uint8{}},
+}
+
+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.
+// It does not seem to be necessary for any other systems. This is probably working
+// around a Solaris-specific bug that should be fixed differently, but we don't know
+// what that bug is. And this does fix it.
+func isextern(s *obj.LSym) bool {
+	// All the Solaris dynamic imports from libc.so begin with "libc_".
+	return strings.HasPrefix(s.Name, "libc_")
+}
+
+// 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 spadjop(ctxt *obj.Link, p *obj.Prog, l int, q int) int {
+	if p.Mode != 64 || ctxt.Arch.Ptrsize == 4 {
+		return l
+	}
+	return q
+}
+
+func span6(ctxt *obj.Link, s *obj.LSym) {
+	ctxt.Cursym = s
+
+	if s.P != nil {
+		return
+	}
+
+	if ycover[0] == 0 {
+		instinit()
+	}
+
+	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
+			}
+		}
+		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 = int16(spadjop(ctxt, p, AADDL, AADDQ))
+			if v < 0 {
+				p.As = int16(spadjop(ctxt, p, ASUBL, ASUBQ))
+				v = -v
+				p.From.Offset = int64(v)
+			}
+
+			if v == 0 {
+				p.As = obj.ANOP
+			}
+		}
+	}
+
+	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) {
+			p.Back |= 1 // backward jump
+			q.Back |= 4 // loop head
+		}
+
+		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 = int16(spadjop(ctxt, p, AADDL, AADDQ))
+			if v < 0 {
+				p.As = int16(spadjop(ctxt, p, ASUBL, ASUBQ))
+				v = -v
+				p.From.Offset = int64(v)
+			}
+
+			if v == 0 {
+				p.As = obj.ANOP
+			}
+		}
+	}
+
+	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++ {
+			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 || p.As == AREPN) && 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)
+				}
+			}
+
+			if (p.Back&4 != 0) && c&(LoopAlign-1) != 0 {
+				// pad with NOPs
+				v = -c & (LoopAlign - 1)
+
+				if v <= MaxLoopPad {
+					obj.Symgrow(ctxt, s, int64(c)+int64(v))
+					fillnop(s.P[c:], int(v))
+					c += v
+				}
+			}
+
+			p.Pc = int64(c)
+
+			// process forward jumps to p
+			for q = p.Rel; 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 == AJCXZL {
+						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.Rel = 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("loop")
+		}
+		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)
+		var i int
+		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++ {
+			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 c int
+
+	for i := 1; optab[i].as != 0; i++ {
+		c = int(optab[i].as)
+		if opindex[c&obj.AMask] != nil {
+			log.Fatalf("phase error in optab: %d (%v)", i, obj.Aconv(c))
+		}
+		opindex[c&obj.AMask] = &optab[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
+
+	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[Yrl*Ymax+Yrb] = 1 // but not Yrl32
+
+	ycover[Ycl*Ymax+Ycx] = 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[Yrl32*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[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++ {
+		reg[i] = -1
+		if i >= REG_AL && i <= REG_R15B {
+			reg[i] = (i - REG_AL) & 7
+			if i >= REG_SPB && i <= REG_DIB {
+				regrex[i] = 0x40
+			}
+			if i >= REG_R8B && i <= REG_R15B {
+				regrex[i] = Rxr | Rxx | Rxb
+			}
+		}
+
+		if i >= REG_AH && i <= REG_BH {
+			reg[i] = 4 + ((i - REG_AH) & 7)
+		}
+		if i >= REG_AX && i <= REG_R15 {
+			reg[i] = (i - REG_AX) & 7
+			if i >= REG_R8 {
+				regrex[i] = Rxr | Rxx | Rxb
+			}
+		}
+
+		if i >= REG_F0 && i <= REG_F0+7 {
+			reg[i] = (i - REG_F0) & 7
+		}
+		if i >= REG_M0 && i <= REG_M0+7 {
+			reg[i] = (i - REG_M0) & 7
+		}
+		if i >= REG_X0 && i <= REG_X0+15 {
+			reg[i] = (i - REG_X0) & 7
+			if i >= REG_X0+8 {
+				regrex[i] = Rxr | Rxx | Rxb
+			}
+		}
+
+		if i >= REG_CR+8 && i <= REG_CR+15 {
+			regrex[i] = Rxr
+		}
+	}
+}
+
+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:
+			return 0x2e
+
+		case REG_DS:
+			return 0x3e
+
+		case REG_ES:
+			return 0x26
+
+		case REG_FS:
+			return 0x64
+
+		case REG_GS:
+			return 0x65
+
+		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.Hnetbsd,
+				obj.Hopenbsd,
+				obj.Hsolaris:
+				return 0x64 // FS
+
+			case obj.Hdarwin:
+				return 0x65 // GS
+			}
+		}
+	}
+
+	if p.Mode == 32 {
+		return 0
+	}
+
+	switch a.Index {
+	case REG_CS:
+		return 0x2e
+
+	case REG_DS:
+		return 0x3e
+
+	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
+
+	case REG_GS:
+		return 0x65
+	}
+
+	return 0
+}
+
+func oclass(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) int {
+	switch a.Type {
+	case obj.TYPE_NONE:
+		return Ynone
+
+	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
+
+	case obj.TYPE_ADDR:
+		switch a.Name {
+		case obj.NAME_EXTERN,
+			obj.NAME_GOTREF,
+			obj.NAME_STATIC:
+			if a.Sym != nil && isextern(a.Sym) || p.Mode == 32 {
+				return Yi32
+			}
+			return Yiauto // use pc-relative addressing
+
+		case obj.NAME_AUTO,
+			obj.NAME_PARAM:
+			return Yiauto
+		}
+
+		// TODO(rsc): 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 := 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
+		}
+		if p.Mode == 32 {
+			return Yi32
+		}
+		l := int32(v)
+		if int64(l) == v {
+			return Ys32 /* can sign extend */
+		}
+		if v>>32 == 0 {
+			return Yi32 /* unsigned */
+		}
+		return Yi64
+
+	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_SPB:
+		*/
+	case REG_BPB,
+		REG_SIB,
+		REG_DIB,
+		REG_R8B,
+		REG_R9B,
+		REG_R10B,
+		REG_R11B,
+		REG_R12B,
+		REG_R13B,
+		REG_R14B,
+		REG_R15B:
+		if ctxt.Asmode != 64 {
+			return Yxxx
+		}
+		fallthrough
+
+	case REG_DL,
+		REG_BL,
+		REG_AH,
+		REG_CH,
+		REG_DH,
+		REG_BH:
+		return Yrb
+
+	case REG_CL:
+		return Ycl
+
+	case REG_CX:
+		return Ycx
+
+	case REG_DX, REG_BX:
+		return Yrx
+
+	case REG_R8, /* not really Yrl */
+		REG_R9,
+		REG_R10,
+		REG_R11,
+		REG_R12,
+		REG_R13,
+		REG_R14,
+		REG_R15:
+		if ctxt.Asmode != 64 {
+			return Yxxx
+		}
+		fallthrough
+
+	case REG_SP, REG_BP, REG_SI, REG_DI:
+		if p.Mode == 32 {
+			return Yrl32
+		}
+		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_M0 + 0,
+		REG_M0 + 1,
+		REG_M0 + 2,
+		REG_M0 + 3,
+		REG_M0 + 4,
+		REG_M0 + 5,
+		REG_M0 + 6,
+		REG_M0 + 7:
+		return Ymr
+
+	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,
+		REG_X0 + 8,
+		REG_X0 + 9,
+		REG_X0 + 10,
+		REG_X0 + 11,
+		REG_X0 + 12,
+		REG_X0 + 13,
+		REG_X0 + 14,
+		REG_X0 + 15:
+		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_CR + 8:
+		return Ycr8
+
+	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 REG_NONE:
+		i = 4 << 3
+		goto bas
+
+	case REG_R8,
+		REG_R9,
+		REG_R10,
+		REG_R11,
+		REG_R12,
+		REG_R13,
+		REG_R14,
+		REG_R15:
+		if ctxt.Asmode != 64 {
+			goto bad
+		}
+		fallthrough
+
+	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_R8,
+		REG_R9,
+		REG_R10,
+		REG_R11,
+		REG_R12,
+		REG_R13,
+		REG_R14,
+		REG_R15:
+		if ctxt.Asmode != 64 {
+			goto bad
+		}
+		fallthrough
+
+	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 rel obj.Reloc
+
+	v := 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 put8(ctxt *obj.Link, v int64) {
+	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[4] = byte(v >> 32)
+	ctxt.Andptr[5] = byte(v >> 40)
+	ctxt.Andptr[6] = byte(v >> 48)
+	ctxt.Andptr[7] = byte(v >> 56)
+	ctxt.Andptr = ctxt.Andptr[8:]
+}
+
+/*
+static void
+relput8(Prog *p, Addr *a)
+{
+	vlong v;
+	Reloc rel, *r;
+
+	v = vaddr(ctxt, p, a, &rel);
+	if(rel.siz != 0) {
+		r = addrel(ctxt->cursym);
+		*r = rel;
+		r->siz = 8;
+		r->off = p->pc + ctxt->andptr - ctxt->and;
+	}
+	put8(ctxt, v);
+}
+*/
+func vaddr(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, r *obj.Reloc) int64 {
+	if r != nil {
+		*r = obj.Reloc{}
+	}
+
+	switch a.Name {
+	case obj.NAME_STATIC,
+		obj.NAME_GOTREF,
+		obj.NAME_EXTERN:
+		s := a.Sym
+		if r == nil {
+			ctxt.Diag("need reloc for %v", obj.Dconv(p, a))
+			log.Fatalf("reloc")
+		}
+
+		if a.Name == obj.NAME_GOTREF {
+			r.Siz = 4
+			r.Type = obj.R_GOTPCREL
+		} else if isextern(s) || p.Mode != 64 {
+			r.Siz = 4
+			r.Type = obj.R_ADDR
+		} else {
+			r.Siz = 4
+			r.Type = obj.R_PCREL
+		}
+
+		r.Off = -1 // caller must fill in
+		r.Sym = s
+		r.Add = a.Offset
+
+		return 0
+	}
+
+	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("reloc")
+		}
+
+		r.Type = obj.R_TLS_LE
+		r.Siz = 4
+		r.Off = -1 // caller must fill in
+		r.Add = a.Offset
+		return 0
+	}
+
+	return a.Offset
+}
+
+func asmandsz(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, r int, rex int, m64 int) {
+	var base int
+	var rel obj.Reloc
+
+	rex &= 0x40 | Rxr
+	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_X0+15 < 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:]
+		ctxt.Rexflag |= regrex[a.Reg]&(0x40|Rxb) | rex
+		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_GOTREF,
+			obj.NAME_STATIC:
+			if !isextern(a.Sym) && p.Mode == 64 {
+				goto bad
+			}
+			base = REG_NONE
+			v = int32(vaddr(ctxt, p, a, &rel))
+
+		case obj.NAME_AUTO,
+			obj.NAME_PARAM:
+			base = REG_SP
+		}
+
+		ctxt.Rexflag |= regrex[int(a.Index)]&Rxx | regrex[base]&Rxb | rex
+		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 && base != REG_R13 {
+			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_GOTREF,
+		obj.NAME_EXTERN:
+		if a.Sym == nil {
+			ctxt.Diag("bad addr: %v", p)
+		}
+		base = REG_NONE
+		v = int32(vaddr(ctxt, p, a, &rel))
+
+	case obj.NAME_AUTO,
+		obj.NAME_PARAM:
+		base = REG_SP
+	}
+
+	if base == REG_TLS {
+		v = int32(vaddr(ctxt, p, a, &rel))
+	}
+
+	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 || a.Name == obj.NAME_GOTREF) || p.Mode != 64 {
+			if a.Name == obj.NAME_GOTREF && (a.Offset != 0 || a.Index != 0 || a.Scale != 0) {
+				ctxt.Diag("%v has offset against gotref", p)
+			}
+			ctxt.Andptr[0] = byte(0<<6 | 5<<0 | r<<3)
+			ctxt.Andptr = ctxt.Andptr[1:]
+			goto putrelv
+		}
+
+		/* temporary */
+		ctxt.Andptr[0] = byte(0<<6 | 4<<0 | r<<3)
+		ctxt.Andptr = ctxt.Andptr[1:] /* sib present */
+		ctxt.Andptr[0] = 0<<6 | 4<<3 | 5<<0
+		ctxt.Andptr = ctxt.Andptr[1:] /* DS:d32 */
+		goto putrelv
+	}
+
+	if base == REG_SP || base == REG_R12 {
+		if v == 0 {
+			ctxt.Andptr[0] = byte(0<<6 | reg[base]<<0 | r<<3)
+			ctxt.Andptr = ctxt.Andptr[1:]
+			asmidx(ctxt, int(a.Scale), REG_NONE, base)
+			return
+		}
+
+		if v >= -128 && v < 128 {
+			ctxt.Andptr[0] = byte(1<<6 | reg[base]<<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 | reg[base]<<0 | r<<3)
+		ctxt.Andptr = ctxt.Andptr[1:]
+		asmidx(ctxt, int(a.Scale), REG_NONE, base)
+		goto putrelv
+	}
+
+	if REG_AX <= base && base <= REG_R15 {
+		if a.Index == REG_TLS && ctxt.Flag_shared == 0 {
+			rel = obj.Reloc{}
+			rel.Type = obj.R_TLS_LE
+			rel.Siz = 4
+			rel.Sym = nil
+			rel.Add = int64(v)
+			v = 0
+		}
+
+		if v == 0 && rel.Siz == 0 && base != REG_BP && base != REG_R13 {
+			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 {
+		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
+}
+
+func asmand(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, ra *obj.Addr) {
+	asmandsz(ctxt, p, a, reg[ra.Reg], regrex[ra.Reg], 0)
+}
+
+func asmando(ctxt *obj.Link, p *obj.Prog, a *obj.Addr, o int) {
+	asmandsz(ctxt, p, a, o, 0, 0)
+}
+
+func bytereg(a *obj.Addr, t *uint8) {
+	if a.Type == obj.TYPE_REG && a.Index == REG_NONE && (REG_AX <= a.Reg && a.Reg <= REG_R15) {
+		a.Reg += REG_AL - REG_AX
+		*t = 0
+	}
+}
+
+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, 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, 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, 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, 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, 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, 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, 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, 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, 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, Ynone, Ytask, 4, [4]uint8{0x0f, 0x00, 3, 0}},
+	Movtab{AMOVW, Ytask, Ynone, Yml, 3, [4]uint8{0x0f, 0x00, 1, 0}},
+
+	/* 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, 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{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:
+		return true
+	}
+
+	if a.Index == REG_AX {
+		return true
+	}
+	return false
+}
+
+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
+}
+
+var bpduff1 = []byte{
+	0x48, 0x89, 0x6c, 0x24, 0xf0, // MOVQ BP, -16(SP)
+	0x48, 0x8d, 0x6c, 0x24, 0xf0, // LEAQ -16(SP), BP
+}
+
+var bpduff2 = []byte{
+	0x48, 0x8b, 0x6d, 0x00, // MOVQ 0(BP), BP
+}
+
+func doasm(ctxt *obj.Link, p *obj.Prog) {
+	ctxt.Curp = p // TODO
+
+	o := opindex[p.As&obj.AMask]
+
+	if o == nil {
+		ctxt.Diag("asmins: missing op %v", p)
+		return
+	}
+
+	pre := prefixof(ctxt, p, &p.From)
+	if pre != 0 {
+		ctxt.Andptr[0] = byte(pre)
+		ctxt.Andptr = ctxt.Andptr[1:]
+	}
+	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 = new(obj.Addr)
+		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.From3Type() == obj.TYPE_NONE {
+			p.From3 = new(obj.Addr)
+			*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.From3Type() == obj.TYPE_NONE {
+			p.From3 = new(obj.Addr)
+			*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.Tt == 0 {
+		p.Tt = uint8(oclass(ctxt, p, &p.To))
+	}
+
+	ft := int(p.Ft) * Ymax
+	f3t := Ynone * Ymax
+	if p.From3 != nil {
+		f3t = oclass(ctxt, p, p.From3) * Ymax
+	}
+	tt := int(p.Tt) * Ymax
+
+	xo := obj.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:]
+
+				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:]
+
+				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:]
+
+				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 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 */
+				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)
+				}
+
+			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 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)
+				}
+
+			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)
+				}
+			}
+
+			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])
+			}
+
+			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, &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(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 %v\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 %v\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 %v\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 yt.zcase == Zcallduff && ctxt.Flag_dynlink {
+					ctxt.Diag("directly calling duff when dynamically linking Go")
+				}
+
+				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.Rel
+
+				q.Rel = 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)
+							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
+	}
+	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 && 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 at 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 {
+		/*
+		 * 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.
+		 */
+		pp := *p
+
+		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.
+				ctxt.Andptr[0] = 0x87
+				ctxt.Andptr = ctxt.Andptr[1:] /* xchg lhs,bx */
+				asmando(ctxt, p, &p.From, reg[REG_BX])
+				subreg(&pp, z, REG_BX)
+				doasm(ctxt, &pp)
+				ctxt.Andptr[0] = 0x87
+				ctxt.Andptr = ctxt.Andptr[1:] /* xchg lhs,bx */
+				asmando(ctxt, p, &p.From, reg[REG_BX])
+			} 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 {
+			// 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 */
+				asmando(ctxt, p, &p.To, reg[REG_BX])
+				subreg(&pp, z, REG_BX)
+				doasm(ctxt, &pp)
+				ctxt.Andptr[0] = 0x87
+				ctxt.Andptr = ctxt.Andptr[1:] /* xchg rhs,bx */
+				asmando(ctxt, p, &p.To, reg[REG_BX])
+			} 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 ft=%d tt=%d %v %d %d", p.Ft, p.Tt, p, oclass(ctxt, p, &p.From), oclass(ctxt, p, &p.To))
+	return
+}
+
+// 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
+
+	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 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{
+	0x5e, // POPL SI
+	// 0x8b, 0x7d, 0x00, // MOVL (BP), DI - catch return to invalid address, for debugging
+	0x83,
+	0xe6,
+	0xe0, // ANDL $~31, SI
+	0x4c,
+	0x01,
+	0xfe, // ADDQ R15, SI
+	0xff,
+	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
+
+var naclmovs = []uint8{
+	0x89,
+	0xf6, // MOVL SI, SI
+	0x49,
+	0x8d,
+	0x34,
+	0x37, // LEAQ (R15)(SI*1), SI
+	0x89,
+	0xff, // MOVL DI, DI
+	0x49,
+	0x8d,
+	0x3c,
+	0x3f, // LEAQ (R15)(DI*1), DI
+}
+
+var naclstos = []uint8{
+	0x89,
+	0xff, // MOVL DI, DI
+	0x49,
+	0x8d,
+	0x3c,
+	0x3f, // LEAQ (R15)(DI*1), DI
+}
+
+func nacltrunc(ctxt *obj.Link, reg int) {
+	if reg >= REG_R8 {
+		ctxt.Andptr[0] = 0x45
+		ctxt.Andptr = ctxt.Andptr[1:]
+	}
+	reg = (reg - REG_AX) & 7
+	ctxt.Andptr[0] = 0x89
+	ctxt.Andptr = ctxt.Andptr[1:]
+	ctxt.Andptr[0] = byte(3<<6 | reg<<3 | reg)
+	ctxt.Andptr = ctxt.Andptr[1:]
+}
+
+func asmins(ctxt *obj.Link, p *obj.Prog) {
+	ctxt.Andptr = ctxt.And[:]
+	ctxt.Asmode = int(p.Mode)
+
+	if p.As == obj.AUSEFIELD {
+		r := obj.Addrel(ctxt.Cursym)
+		r.Off = 0
+		r.Siz = 0
+		r.Sym = p.From.Sym
+		r.Type = obj.R_USEFIELD
+		return
+	}
+
+	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
+		}
+
+		if p.As == AREPN {
+			ctxt.Repn++
+			return
+		}
+
+		if p.As == ALOCK {
+			ctxt.Lock++
+			return
+		}
+
+		if p.As != ALEAQ && p.As != ALEAL {
+			if p.From.Index != obj.TYPE_NONE && p.From.Scale > 0 {
+				nacltrunc(ctxt, int(p.From.Index))
+			}
+			if p.To.Index != obj.TYPE_NONE && p.To.Scale > 0 {
+				nacltrunc(ctxt, int(p.To.Index))
+			}
+		}
+
+		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 {
+				// ANDL $~31, reg
+				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:]
+
+				// ADDQ R15, reg
+				ctxt.Andptr[0] = 0x4c
+				ctxt.Andptr = ctxt.Andptr[1:]
+
+				ctxt.Andptr[0] = 0x01
+				ctxt.Andptr = ctxt.Andptr[1:]
+				ctxt.Andptr[0] = byte(0xf8 | (p.To.Reg - REG_AX))
+				ctxt.Andptr = ctxt.Andptr[1:]
+			}
+
+			if p.To.Type == obj.TYPE_REG && REG_R8 <= p.To.Reg && p.To.Reg <= REG_R15 {
+				// ANDL $~31, reg
+				ctxt.Andptr[0] = 0x41
+				ctxt.Andptr = ctxt.Andptr[1:]
+
+				ctxt.Andptr[0] = 0x83
+				ctxt.Andptr = ctxt.Andptr[1:]
+				ctxt.Andptr[0] = byte(0xe0 | (p.To.Reg - REG_R8))
+				ctxt.Andptr = ctxt.Andptr[1:]
+				ctxt.Andptr[0] = 0xe0
+				ctxt.Andptr = ctxt.Andptr[1:]
+
+				// ADDQ R15, reg
+				ctxt.Andptr[0] = 0x4d
+				ctxt.Andptr = ctxt.Andptr[1:]
+
+				ctxt.Andptr[0] = 0x01
+				ctxt.Andptr = ctxt.Andptr[1:]
+				ctxt.Andptr[0] = byte(0xf8 | (p.To.Reg - REG_R8))
+				ctxt.Andptr = ctxt.Andptr[1:]
+			}
+
+		case AINT:
+			ctxt.Andptr[0] = 0xf4
+			ctxt.Andptr = ctxt.Andptr[1:]
+			return
+
+		case ASCASB,
+			ASCASW,
+			ASCASL,
+			ASCASQ,
+			ASTOSB,
+			ASTOSW,
+			ASTOSL,
+			ASTOSQ:
+			copy(ctxt.Andptr, naclstos)
+			ctxt.Andptr = ctxt.Andptr[len(naclstos):]
+
+		case AMOVSB, AMOVSW, AMOVSL, AMOVSQ:
+			copy(ctxt.Andptr, naclmovs)
+			ctxt.Andptr = ctxt.Andptr[len(naclmovs):]
+		}
+
+		if ctxt.Rep != 0 {
+			ctxt.Andptr[0] = 0xf3
+			ctxt.Andptr = ctxt.Andptr[1:]
+			ctxt.Rep = 0
+		}
+
+		if ctxt.Repn != 0 {
+			ctxt.Andptr[0] = 0xf2
+			ctxt.Andptr = ctxt.Andptr[1:]
+			ctxt.Repn = 0
+		}
+
+		if ctxt.Lock != 0 {
+			ctxt.Andptr[0] = 0xf0
+			ctxt.Andptr = ctxt.Andptr[1:]
+			ctxt.Lock = 0
+		}
+	}
+
+	ctxt.Rexflag = 0
+	and0 := ctxt.Andptr
+	ctxt.Asmode = int(p.Mode)
+	doasm(ctxt, p)
+	if ctxt.Rexflag != 0 {
+		/*
+		 * as befits the whole approach of the architecture,
+		 * the rex prefix must appear before the first opcode byte
+		 * (and thus after any 66/67/f2/f3/26/2e/3e prefix bytes, but
+		 * before the 0f opcode escape!), or it might be ignored.
+		 * note that the handbook often misleadingly shows 66/f2/f3 in `opcode'.
+		 */
+		if p.Mode != 64 {
+			ctxt.Diag("asmins: illegal in mode %d: %v (%d %d)", p.Mode, p, p.Ft, p.Tt)
+		}
+		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 {
+				break
+			}
+		}
+
+		copy(and0[np+1:], and0[np:n])
+		and0[np] = byte(0x40 | ctxt.Rexflag)
+		ctxt.Andptr = ctxt.Andptr[1:]
+	}
+
+	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
+		}
+		if ctxt.Rexflag != 0 {
+			r.Off++
+		}
+		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 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)
+			ctxt.Andptr = ctxt.Andptr[len(naclspfix):]
+
+		case REG_BP:
+			copy(ctxt.Andptr, naclbpfix)
+			ctxt.Andptr = ctxt.Andptr[len(naclbpfix):]
+		}
+	}
+}
diff --git a/src/cmd/internal/obj/x86/list6.go b/src/cmd/internal/obj/x86/list6.go
new file mode 100644
index 0000000..fc79b90
--- /dev/null
+++ b/src/cmd/internal/obj/x86/list6.go
@@ -0,0 +1,164 @@
+// Inferno utils/6c/list.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6c/list.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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 x86
+
+import (
+	"cmd/internal/obj"
+	"fmt"
+)
+
+var Register = []string{
+	"AL", /* [D_AL] */
+	"CL",
+	"DL",
+	"BL",
+	"SPB",
+	"BPB",
+	"SIB",
+	"DIB",
+	"R8B",
+	"R9B",
+	"R10B",
+	"R11B",
+	"R12B",
+	"R13B",
+	"R14B",
+	"R15B",
+	"AX", /* [D_AX] */
+	"CX",
+	"DX",
+	"BX",
+	"SP",
+	"BP",
+	"SI",
+	"DI",
+	"R8",
+	"R9",
+	"R10",
+	"R11",
+	"R12",
+	"R13",
+	"R14",
+	"R15",
+	"AH",
+	"CH",
+	"DH",
+	"BH",
+	"F0", /* [D_F0] */
+	"F1",
+	"F2",
+	"F3",
+	"F4",
+	"F5",
+	"F6",
+	"F7",
+	"M0",
+	"M1",
+	"M2",
+	"M3",
+	"M4",
+	"M5",
+	"M6",
+	"M7",
+	"X0",
+	"X1",
+	"X2",
+	"X3",
+	"X4",
+	"X5",
+	"X6",
+	"X7",
+	"X8",
+	"X9",
+	"X10",
+	"X11",
+	"X12",
+	"X13",
+	"X14",
+	"X15",
+	"CS", /* [D_CS] */
+	"SS",
+	"DS",
+	"ES",
+	"FS",
+	"GS",
+	"GDTR", /* [D_GDTR] */
+	"IDTR", /* [D_IDTR] */
+	"LDTR", /* [D_LDTR] */
+	"MSW",  /* [D_MSW] */
+	"TASK", /* [D_TASK] */
+	"CR0",  /* [D_CR] */
+	"CR1",
+	"CR2",
+	"CR3",
+	"CR4",
+	"CR5",
+	"CR6",
+	"CR7",
+	"CR8",
+	"CR9",
+	"CR10",
+	"CR11",
+	"CR12",
+	"CR13",
+	"CR14",
+	"CR15",
+	"DR0", /* [D_DR] */
+	"DR1",
+	"DR2",
+	"DR3",
+	"DR4",
+	"DR5",
+	"DR6",
+	"DR7",
+	"TR0", /* [D_TR] */
+	"TR1",
+	"TR2",
+	"TR3",
+	"TR4",
+	"TR5",
+	"TR6",
+	"TR7",
+	"TLS",    /* [D_TLS] */
+	"MAXREG", /* [MAXREG] */
+}
+
+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 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
new file mode 100644
index 0000000..fa9c474
--- /dev/null
+++ b/src/cmd/internal/obj/x86/obj6.go
@@ -0,0 +1,1330 @@
+// Inferno utils/6l/pass.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/pass.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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 x86
+
+import (
+	"cmd/internal/obj"
+	"encoding/binary"
+	"fmt"
+	"log"
+	"math"
+)
+
+func canuse1insntls(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) {
+	// 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
+	// can only be loaded into another register:
+	//
+	//         MOVQ TLS, AX
+	//
+	// An offset from the thread-local storage base is written off(reg)(TLS*1).
+	// Semantically it is off(reg), but the (TLS*1) annotation marks this as
+	// indexing from the loaded TLS base. This emits a relocation so that
+	// if the linker needs to adjust the offset, it can. For example:
+	//
+	//         MOVQ TLS, AX
+	//         MOVQ 0(AX)(TLS*1), CX // load g into CX
+	//
+	// On systems that support direct access to the TLS memory, this
+	// pair of instructions can be reduced to a direct TLS memory reference:
+	//
+	//         MOVQ 0(TLS), CX // load g into CX
+	//
+	// The 2-instruction and 1-instruction forms correspond to the two code
+	// sequences for loading a TLS variable in the local exec model given in "ELF
+	// Handling For Thread-Local Storage".
+	//
+	// We apply this rewrite on systems that support the 1-instruction form.
+	// The decision is made using only the operating system and the -shared flag,
+	// not the link mode. If some link modes on a particular operating system
+	// require the 2-instruction form, then all builds for that operating system
+	// will use the 2-instruction form, so that the link mode decision can be
+	// delayed to link time.
+	//
+	// In this way, all supported systems use identical instructions to
+	// access TLS, and they are rewritten appropriately first here in
+	// liblink and then finally using relocations in the linker.
+	//
+	// When -shared is passed, we leave the code in the 2-instruction form but
+	// assemble (and relocate) them in different ways to generate the initial
+	// exec code sequence. It's a bit of a fluke that this is possible without
+	// rewriting the instructions more comprehensively, and it only does because
+	// we only support a single TLS variable (g).
+
+	if canuse1insntls(ctxt) {
+		// Reduce 2-instruction sequence to 1-instruction sequence.
+		// Sequences like
+		//	MOVQ TLS, BX
+		//	... off(BX)(TLS*1) ...
+		// become
+		//	NOP
+		//	... off(TLS) ...
+		//
+		// TODO(rsc): Remove the Hsolaris special case. It exists only to
+		// guarantee we are producing byte-identical binaries as before this code.
+		// But it should be unnecessary.
+		if (p.As == AMOVQ || 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_R15 && ctxt.Headtype != obj.Hsolaris {
+			obj.Nopout(p)
+		}
+		if p.From.Type == obj.TYPE_MEM && p.From.Index == REG_TLS && REG_AX <= p.From.Reg && p.From.Reg <= REG_R15 {
+			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_R15 {
+			p.To.Reg = REG_TLS
+			p.To.Scale = 0
+			p.To.Index = REG_NONE
+		}
+	} else {
+		// load_g_cx, below, always inserts the 1-instruction sequence. Rewrite it
+		// as the 2-instruction sequence if necessary.
+		//	MOVQ 0(TLS), BX
+		// becomes
+		//	MOVQ TLS, BX
+		//	MOVQ 0(BX)(TLS*1), BX
+		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.As = p.As
+			q.From = p.From
+			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.Hwindows && p.Mode == 64 || 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 0 to $0 in 3rd argment to CMPPS etc.
+	// That's what the tables expect.
+	switch p.As {
+	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
+		}
+	}
+
+	// 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 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 {
+		if p.From3 != nil {
+			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.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
+					break
+				}
+			}
+		}
+		fallthrough
+
+	case AFMOVF,
+		AFADDF,
+		AFSUBF,
+		AFSUBRF,
+		AFMULF,
+		AFDIVF,
+		AFDIVRF,
+		AFCOMF,
+		AFCOMFP,
+		AADDSS,
+		ASUBSS,
+		AMULSS,
+		ADIVSS,
+		ACOMISS,
+		AUCOMISS:
+		if p.From.Type == obj.TYPE_FCONST {
+			f32 := float32(p.From.Val.(float64))
+			i32 := math.Float32bits(f32)
+			literal := fmt.Sprintf("$f32.%08x", i32)
+			s := obj.Linklookup(ctxt, literal, 0)
+			p.From.Type = obj.TYPE_MEM
+			p.From.Name = obj.NAME_EXTERN
+			p.From.Sym = s
+			p.From.Sym.Local = true
+			p.From.Offset = 0
+		}
+
+	case AMOVSD:
+		// Convert AMOVSD $(0), Xx to AXORPS Xx, Xx
+		if p.From.Type == obj.TYPE_FCONST {
+			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
+					break
+				}
+			}
+		}
+		fallthrough
+
+	case AFMOVD,
+		AFADDD,
+		AFSUBD,
+		AFSUBRD,
+		AFMULD,
+		AFDIVD,
+		AFDIVRD,
+		AFCOMD,
+		AFCOMDP,
+		AADDSD,
+		ASUBSD,
+		AMULSD,
+		ADIVSD,
+		ACOMISD,
+		AUCOMISD:
+		if p.From.Type == obj.TYPE_FCONST {
+			i64 := math.Float64bits(p.From.Val.(float64))
+			literal := fmt.Sprintf("$f64.%016x", i64)
+			s := obj.Linklookup(ctxt, literal, 0)
+			p.From.Type = obj.TYPE_MEM
+			p.From.Name = obj.NAME_EXTERN
+			p.From.Sym = s
+			p.From.Sym.Local = true
+			p.From.Offset = 0
+		}
+	}
+
+	if ctxt.Flag_dynlink && (p.As == obj.ADUFFCOPY || p.As == obj.ADUFFZERO) {
+		var sym *obj.LSym
+		if p.As == obj.ADUFFZERO {
+			sym = obj.Linklookup(ctxt, "runtime.duffzero", 0)
+		} else {
+			sym = obj.Linklookup(ctxt, "runtime.duffcopy", 0)
+		}
+		offset := p.To.Offset
+		p.As = AMOVQ
+		p.From.Type = obj.TYPE_MEM
+		p.From.Name = obj.NAME_GOTREF
+		p.From.Sym = sym
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = REG_R15
+		p.To.Offset = 0
+		p.To.Sym = nil
+		p1 := obj.Appendp(ctxt, p)
+		p1.As = AADDQ
+		p1.From.Type = obj.TYPE_CONST
+		p1.From.Offset = offset
+		p1.To.Type = obj.TYPE_REG
+		p1.To.Reg = REG_R15
+		p2 := obj.Appendp(ctxt, p1)
+		p2.As = obj.ACALL
+		p2.To.Type = obj.TYPE_REG
+		p2.To.Reg = REG_R15
+	}
+
+	if ctxt.Flag_dynlink {
+		if p.As == ALEAQ && p.From.Type == obj.TYPE_MEM && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local {
+			p.As = AMOVQ
+			p.From.Type = obj.TYPE_ADDR
+		}
+		if p.From.Type == obj.TYPE_ADDR && p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local {
+			if p.As != AMOVQ {
+				ctxt.Diag("do not know how to handle TYPE_ADDR in %v with -dynlink", p)
+			}
+			if p.To.Type != obj.TYPE_REG {
+				ctxt.Diag("do not know how to handle LEAQ-type insn to non-register in %v with -dynlink", p)
+			}
+			p.From.Type = obj.TYPE_MEM
+			p.From.Name = obj.NAME_GOTREF
+			if p.From.Offset != 0 {
+				q := obj.Appendp(ctxt, p)
+				q.As = AADDQ
+				q.From.Type = obj.TYPE_CONST
+				q.From.Offset = p.From.Offset
+				q.To = p.To
+				p.From.Offset = 0
+			}
+		}
+		if p.From3 != nil && p.From3.Name == obj.NAME_EXTERN {
+			ctxt.Diag("don't know how to handle %v with -dynlink", p)
+		}
+		var source *obj.Addr
+		if p.From.Name == obj.NAME_EXTERN && !p.From.Sym.Local {
+			if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local {
+				ctxt.Diag("cannot handle NAME_EXTERN on both sides in %v with -dynlink", p)
+			}
+			source = &p.From
+		} else if p.To.Name == obj.NAME_EXTERN && !p.To.Sym.Local {
+			source = &p.To
+		} else {
+			return
+		}
+		if p.As == obj.ATEXT || p.As == obj.AFUNCDATA || p.As == obj.ACALL || p.As == obj.ARET || p.As == obj.AJMP {
+			return
+		}
+		if source.Type != obj.TYPE_MEM {
+			ctxt.Diag("don't know how to handle %v with -dynlink", p)
+		}
+		p1 := obj.Appendp(ctxt, p)
+		p2 := obj.Appendp(ctxt, p1)
+
+		p1.As = AMOVQ
+		p1.From.Type = obj.TYPE_MEM
+		p1.From.Sym = source.Sym
+		p1.From.Name = obj.NAME_GOTREF
+		p1.To.Type = obj.TYPE_REG
+		p1.To.Reg = REG_R15
+
+		p2.As = p.As
+		p2.From = p.From
+		p2.To = p.To
+		if p.From.Name == obj.NAME_EXTERN {
+			p2.From.Reg = REG_R15
+			p2.From.Name = obj.NAME_NONE
+			p2.From.Sym = nil
+		} else if p.To.Name == obj.NAME_EXTERN {
+			p2.To.Reg = REG_R15
+			p2.To.Name = obj.NAME_NONE
+			p2.To.Sym = nil
+		} else {
+			return
+		}
+		l := p.Link
+		l2 := p2.Link
+		*p = *p1
+		*p1 = *p2
+		p.Link = l
+		p1.Link = l2
+	}
+}
+
+func nacladdr(ctxt *obj.Link, p *obj.Prog, a *obj.Addr) {
+	if p.As == ALEAL || p.As == ALEAQ {
+		return
+	}
+
+	if a.Reg == REG_BP {
+		ctxt.Diag("invalid address: %v", p)
+		return
+	}
+
+	if a.Reg == REG_TLS {
+		a.Reg = REG_BP
+	}
+	if a.Type == obj.TYPE_MEM && a.Name == obj.NAME_NONE {
+		switch a.Reg {
+		// all ok
+		case REG_BP, REG_SP, REG_R15:
+			break
+
+		default:
+			if a.Index != REG_NONE {
+				ctxt.Diag("invalid address %v", p)
+			}
+			a.Index = a.Reg
+			if a.Index != REG_NONE {
+				a.Scale = 1
+			}
+			a.Reg = REG_R15
+		}
+	}
+}
+
+func preprocess(ctxt *obj.Link, cursym *obj.LSym) {
+	if ctxt.Tlsg == nil {
+		ctxt.Tlsg = obj.Linklookup(ctxt, "runtime.tlsg", 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
+	}
+
+	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.
+		bpsize = ctxt.Arch.Ptrsize
+
+		autoffset += int32(bpsize)
+		p.To.Offset += int64(bpsize)
+	} else {
+		bpsize = 0
+	}
+
+	textarg := int64(p.To.Val.(int32))
+	cursym.Args = int32(textarg)
+	cursym.Locals = int32(p.To.Offset)
+
+	// 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.From3Offset()&obj.NOSPLIT == 0 {
+		for q := p; q != nil; q = q.Link {
+			if q.As == obj.ACALL {
+				goto noleaf
+			}
+			if (q.As == obj.ADUFFCOPY || q.As == obj.ADUFFZERO) && autoffset >= obj.StackSmall-8 {
+				goto noleaf
+			}
+		}
+
+		p.From3.Offset |= obj.NOSPLIT
+	noleaf:
+	}
+
+	if p.From3Offset()&obj.NOSPLIT == 0 || p.From3Offset()&obj.WRAPPER != 0 {
+		p = obj.Appendp(ctxt, p)
+		p = load_g_cx(ctxt, p) // load g into CX
+	}
+
+	if cursym.Text.From3Offset()&obj.NOSPLIT == 0 {
+		p = stacksplit(ctxt, p, autoffset, int32(textarg)) // emit split check
+	}
+
+	if autoffset != 0 {
+		if autoffset%int32(ctxt.Arch.Regsize) != 0 {
+			ctxt.Diag("unaligned stack size %d", autoffset)
+		}
+		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)
+	}
+
+	deltasp := autoffset
+
+	if bpsize > 0 {
+		// Save caller's BP
+		p = obj.Appendp(ctxt, p)
+
+		p.As = AMOVQ
+		p.From.Type = obj.TYPE_REG
+		p.From.Reg = REG_BP
+		p.To.Type = obj.TYPE_MEM
+		p.To.Reg = REG_SP
+		p.To.Scale = 1
+		p.To.Offset = int64(autoffset) - int64(bpsize)
+
+		// Move current frame to BP
+		p = obj.Appendp(ctxt, p)
+
+		p.As = ALEAQ
+		p.From.Type = obj.TYPE_MEM
+		p.From.Reg = REG_SP
+		p.From.Scale = 1
+		p.From.Offset = int64(autoffset) - int64(bpsize)
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = REG_BP
+	}
+
+	if cursym.Text.From3Offset()&obj.WRAPPER != 0 {
+		// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
+		//
+		//	MOVQ g_panic(CX), BX
+		//	TESTQ BX, BX
+		//	JEQ end
+		//	LEAQ (autoffset+8)(SP), DI
+		//	CMPQ panic_argp(BX), DI
+		//	JNE end
+		//	MOVQ 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 = AMOVQ
+		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
+		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
+		p.From.Type = obj.TYPE_REG
+		p.From.Reg = REG_BX
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = REG_BX
+		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
+
+		p = obj.Appendp(ctxt, p)
+		p.As = ALEAQ
+		p.From.Type = obj.TYPE_MEM
+		p.From.Reg = REG_SP
+		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 || p.Mode == 32 {
+			p.As = ALEAL
+		}
+
+		p = obj.Appendp(ctxt, p)
+		p.As = ACMPQ
+		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
+		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
+
+		p = obj.Appendp(ctxt, p)
+		p.As = AMOVQ
+		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
+		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
+		p1.Pcond = p
+		p2.Pcond = p
+	}
+
+	if ctxt.Debugzerostack != 0 && autoffset != 0 && cursym.Text.From3.Offset&obj.NOSPLIT == 0 {
+		// 6l -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 = AMOVQ
+		p.From.Type = obj.TYPE_REG
+		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) / 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
+		p.From.Type = obj.TYPE_CONST
+		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)
+		if a == obj.NAME_AUTO {
+			p.From.Offset += int64(deltasp) - int64(bpsize)
+		}
+		if a == obj.NAME_PARAM {
+			p.From.Offset += int64(deltasp) + int64(pcsize)
+		}
+		if p.From3 != nil {
+			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)
+		}
+		if a == obj.NAME_PARAM {
+			p.To.Offset += int64(deltasp) + int64(pcsize)
+		}
+
+		switch p.As {
+		default:
+			continue
+
+		case APUSHL, APUSHFL:
+			deltasp += 4
+			p.Spadj = 4
+			continue
+
+		case APUSHQ, APUSHFQ:
+			deltasp += 8
+			p.Spadj = 8
+			continue
+
+		case APUSHW, APUSHFW:
+			deltasp += 2
+			p.Spadj = 2
+			continue
+
+		case APOPL, APOPFL:
+			deltasp -= 4
+			p.Spadj = -4
+			continue
+
+		case APOPQ, APOPFQ:
+			deltasp -= 8
+			p.Spadj = -8
+			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 {
+			if bpsize > 0 {
+				// Restore caller's BP
+				p.As = AMOVQ
+
+				p.From.Type = obj.TYPE_MEM
+				p.From.Reg = REG_SP
+				p.From.Scale = 1
+				p.From.Offset = int64(autoffset) - int64(bpsize)
+				p.To.Type = obj.TYPE_REG
+				p.To.Reg = REG_BP
+				p = obj.Appendp(ctxt, p)
+			}
+
+			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
+		}
+	}
+}
+
+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
+		a.Scale = 1
+		return
+	}
+
+	a.Type = obj.TYPE_MEM
+	a.Reg = REG_CX
+}
+
+// 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 {
+	p.As = AMOVQ
+	if ctxt.Arch.Ptrsize == 4 {
+		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.
+func stacksplit(ctxt *obj.Link, p *obj.Prog, framesize int32, textarg int32) *obj.Prog {
+	cmp := ACMPQ
+	lea := ALEAQ
+	mov := AMOVQ
+	sub := ASUBQ
+
+	if ctxt.Headtype == obj.Hnacl || p.Mode == 32 {
+		cmp = ACMPL
+		lea = ALEAL
+		mov = AMOVL
+		sub = ASUBL
+	}
+
+	var q1 *obj.Prog
+	if framesize <= obj.StackSmall {
+		// small stack: SP <= stackguard
+		//	CMPQ SP, stackguard
+		p = obj.Appendp(ctxt, p)
+
+		p.As = int16(cmp)
+		p.From.Type = obj.TYPE_REG
+		p.From.Reg = REG_SP
+		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
+		}
+	} else if framesize <= obj.StackBig {
+		// large stack: SP-framesize <= stackguard-StackSmall
+		//	LEAQ -xxx(SP), AX
+		//	CMPQ AX, stackguard
+		p = obj.Appendp(ctxt, p)
+
+		p.As = int16(lea)
+		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 = int16(cmp)
+		p.From.Type = obj.TYPE_REG
+		p.From.Reg = REG_AX
+		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
+		}
+	} 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.
+		//	MOVQ	stackguard, CX
+		//	CMPQ	CX, $StackPreempt
+		//	JEQ	label-of-call-to-morestack
+		//	LEAQ	StackGuard(SP), AX
+		//	SUBQ	CX, AX
+		//	CMPQ	AX, $(framesize+(StackGuard-StackSmall))
+
+		p = obj.Appendp(ctxt, p)
+
+		p.As = int16(mov)
+		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
+		}
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = REG_SI
+
+		p = obj.Appendp(ctxt, p)
+		p.As = int16(cmp)
+		p.From.Type = obj.TYPE_REG
+		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
+		p.To.Type = obj.TYPE_BRANCH
+		q1 = p
+
+		p = obj.Appendp(ctxt, p)
+		p.As = int16(lea)
+		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 = int16(sub)
+		p.From.Type = obj.TYPE_REG
+		p.From.Reg = REG_SI
+		p.To.Type = obj.TYPE_REG
+		p.To.Reg = REG_AX
+
+		p = obj.Appendp(ctxt, p)
+		p.As = int16(cmp)
+		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
+	jls := obj.Appendp(ctxt, p)
+	jls.As = AJLS
+	jls.To.Type = obj.TYPE_BRANCH
+
+	var last *obj.Prog
+	for last = ctxt.Cursym.Text; last.Link != nil; last = last.Link {
+	}
+
+	call := obj.Appendp(ctxt, last)
+	call.Lineno = ctxt.Cursym.Text.Lineno
+	call.Mode = ctxt.Cursym.Text.Mode
+	call.As = obj.ACALL
+	call.To.Type = obj.TYPE_BRANCH
+	morestack := "runtime.morestack"
+	switch {
+	case ctxt.Cursym.Cfunc != 0:
+		morestack = "runtime.morestackc"
+	case ctxt.Cursym.Text.From3Offset()&obj.NEEDCTXT == 0:
+		morestack = "runtime.morestack_noctxt"
+	}
+	call.To.Sym = obj.Linklookup(ctxt, morestack, 0)
+
+	jmp := obj.Appendp(ctxt, call)
+	jmp.As = obj.AJMP
+	jmp.To.Type = obj.TYPE_BRANCH
+	jmp.Pcond = ctxt.Cursym.Text.Link
+
+	jls.Pcond = call
+	if q1 != nil {
+		q1.Pcond = call
+	}
+
+	return jls
+}
+
+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 nofollow(a int) bool {
+	switch a {
+	case obj.AJMP,
+		obj.ARET,
+		AIRETL,
+		AIRETQ,
+		AIRETW,
+		ARETFL,
+		ARETFQ,
+		ARETFW,
+		obj.AUNDEF:
+		return true
+	}
+
+	return false
+}
+
+func pushpop(a int) bool {
+	switch a {
+	case APUSHL,
+		APUSHFL,
+		APUSHQ,
+		APUSHFQ,
+		APUSHW,
+		APUSHFW,
+		APOPL,
+		APOPFL,
+		APOPQ,
+		APOPFQ,
+		APOPW,
+		APOPFW:
+		return true
+	}
+
+	return false
+}
+
+func relinv(a int16) int16 {
+	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", obj.Aconv(int(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; i, q = i+1, 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 = relinv(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 = relinv(int16(a))
+
+				q = p.Link
+				p.Link = p.Pcond
+				p.Pcond = q
+			}
+		} else {
+			q = p.Link
+			if q.Mark != 0 {
+				if a != ALOOP {
+					p.As = relinv(int16(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 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{
+	ByteOrder:  binary.LittleEndian,
+	Name:       "amd64",
+	Thechar:    '6',
+	Preprocess: preprocess,
+	Assemble:   span6,
+	Follow:     follow,
+	Progedit:   progedit,
+	UnaryDst:   unaryDst,
+	Minlc:      1,
+	Ptrsize:    8,
+	Regsize:    8,
+}
+
+var Linkamd64p32 = obj.LinkArch{
+	ByteOrder:  binary.LittleEndian,
+	Name:       "amd64p32",
+	Thechar:    '6',
+	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/internal/obj/x86/obj6_test.go b/src/cmd/internal/obj/x86/obj6_test.go
new file mode 100644
index 0000000..6302107
--- /dev/null
+++ b/src/cmd/internal/obj/x86/obj6_test.go
@@ -0,0 +1,170 @@
+package x86_test
+
+import (
+	"bufio"
+	"bytes"
+	"fmt"
+	"go/build"
+	"internal/testenv"
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"regexp"
+	"strconv"
+	"strings"
+	"testing"
+)
+
+const testdata = `
+MOVQ AX, AX -> MOVQ AX, AX
+
+LEAQ name(SB), AX -> MOVQ name at GOT(SB), AX
+LEAQ name+10(SB), AX -> MOVQ name at GOT(SB), AX; ADDQ $10, AX
+MOVQ $name(SB), AX -> MOVQ name at GOT(SB), AX
+MOVQ $name+10(SB), AX -> MOVQ name at GOT(SB), AX; ADDQ $10, AX
+
+MOVQ name(SB), AX -> MOVQ name at GOT(SB), R15; MOVQ (R15), AX
+MOVQ name+10(SB), AX -> MOVQ name at GOT(SB), R15; MOVQ 10(R15), AX
+
+CMPQ name(SB), $0 -> MOVQ name at GOT(SB), R15; CMPQ (R15), $0
+
+MOVQ $1, name(SB) -> MOVQ name at GOT(SB), R15; MOVQ $1, (R15)
+MOVQ $1, name+10(SB) -> MOVQ name at GOT(SB), R15; MOVQ $1, 10(R15)
+`
+
+type ParsedTestData struct {
+	input              string
+	marks              []int
+	marker_to_input    map[int][]string
+	marker_to_expected map[int][]string
+	marker_to_output   map[int][]string
+}
+
+const marker_start = 1234
+
+func parseTestData(t *testing.T) *ParsedTestData {
+	r := &ParsedTestData{}
+	scanner := bufio.NewScanner(strings.NewReader(testdata))
+	r.marker_to_input = make(map[int][]string)
+	r.marker_to_expected = make(map[int][]string)
+	marker := marker_start
+	input_insns := []string{}
+	for scanner.Scan() {
+		line := scanner.Text()
+		if len(strings.TrimSpace(line)) == 0 {
+			continue
+		}
+		parts := strings.Split(line, "->")
+		if len(parts) != 2 {
+			t.Fatalf("malformed line %v", line)
+		}
+		r.marks = append(r.marks, marker)
+		marker_insn := fmt.Sprintf("MOVQ $%d, AX", marker)
+		input_insns = append(input_insns, marker_insn)
+		for _, input_insn := range strings.Split(parts[0], ";") {
+			input_insns = append(input_insns, input_insn)
+			r.marker_to_input[marker] = append(r.marker_to_input[marker], normalize(input_insn))
+		}
+		for _, expected_insn := range strings.Split(parts[1], ";") {
+			r.marker_to_expected[marker] = append(r.marker_to_expected[marker], normalize(expected_insn))
+		}
+		marker++
+	}
+	r.input = "TEXT ·foo(SB),$0\n" + strings.Join(input_insns, "\n") + "\n"
+	return r
+}
+
+var spaces_re *regexp.Regexp = regexp.MustCompile("\\s+")
+var marker_re *regexp.Regexp = regexp.MustCompile("MOVQ \\$([0-9]+), AX")
+
+func normalize(s string) string {
+	return spaces_re.ReplaceAllLiteralString(strings.TrimSpace(s), " ")
+}
+
+func asmOutput(t *testing.T, s string) []byte {
+	tmpdir, err := ioutil.TempDir("", "progedittest")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(tmpdir)
+	tmpfile, err := os.Create(filepath.Join(tmpdir, "input.s"))
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer tmpfile.Close()
+	_, err = tmpfile.WriteString(s)
+	if err != nil {
+		t.Fatal(err)
+	}
+	gofolder := filepath.Join(build.Default.GOROOT, "bin")
+	if gobin := os.Getenv("GOBIN"); len(gobin) != 0 {
+		gofolder = gobin
+	}
+
+	cmd := exec.Command(
+		filepath.Join(gofolder, "go"), "tool", "asm", "-S", "-dynlink",
+		"-o", filepath.Join(tmpdir, "output.6"), tmpfile.Name())
+
+	var env []string
+	for _, v := range os.Environ() {
+		if !strings.HasPrefix(v, "GOARCH=") {
+			env = append(env, v)
+		}
+	}
+	cmd.Env = append(env, "GOARCH=amd64")
+	asmout, err := cmd.CombinedOutput()
+	if err != nil {
+		t.Fatalf("error %s output %s", err, asmout)
+	}
+	return asmout
+}
+
+func parseOutput(t *testing.T, td *ParsedTestData, asmout []byte) {
+	scanner := bufio.NewScanner(bytes.NewReader(asmout))
+	marker := regexp.MustCompile("MOVQ \\$([0-9]+), AX")
+	mark := -1
+	td.marker_to_output = make(map[int][]string)
+	for scanner.Scan() {
+		line := scanner.Text()
+		if line[0] != '\t' {
+			continue
+		}
+		parts := strings.SplitN(line, "\t", 3)
+		if len(parts) != 3 {
+			continue
+		}
+		n := normalize(parts[2])
+		mark_matches := marker.FindStringSubmatch(n)
+		if mark_matches != nil {
+			mark, _ = strconv.Atoi(mark_matches[1])
+			if _, ok := td.marker_to_input[mark]; !ok {
+				t.Fatalf("unexpected marker %d", mark)
+			}
+		} else if mark != -1 {
+			td.marker_to_output[mark] = append(td.marker_to_output[mark], n)
+		}
+	}
+}
+
+func TestDynlink(t *testing.T) {
+	testenv.MustHaveGoBuild(t)
+
+	testdata := parseTestData(t)
+	asmout := asmOutput(t, testdata.input)
+	parseOutput(t, testdata, asmout)
+	for _, m := range testdata.marks {
+		i := strings.Join(testdata.marker_to_input[m], "; ")
+		o := strings.Join(testdata.marker_to_output[m], "; ")
+		e := strings.Join(testdata.marker_to_expected[m], "; ")
+		if o != e {
+			if o == i {
+				t.Errorf("%s was unchanged; should have become %s", i, e)
+			} else {
+				t.Errorf("%s became %s; should have become %s", i, o, e)
+			}
+		} else if i != e {
+			t.Logf("%s correctly became %s", i, o)
+		}
+	}
+}
diff --git a/src/cmd/internal/objfile/disasm.go b/src/cmd/internal/objfile/disasm.go
index 1a339c3..9838ce2 100644
--- a/src/cmd/internal/objfile/disasm.go
+++ b/src/cmd/internal/objfile/disasm.go
@@ -240,9 +240,9 @@ var disasms = map[string]disasmFunc{
 }
 
 var byteOrders = map[string]binary.ByteOrder{
-	"386":       binary.LittleEndian,
-	"amd64":     binary.LittleEndian,
-	"arm":       binary.LittleEndian,
-	"power64":   binary.BigEndian,
-	"power64le": binary.LittleEndian,
+	"386":     binary.LittleEndian,
+	"amd64":   binary.LittleEndian,
+	"arm":     binary.LittleEndian,
+	"ppc64":   binary.BigEndian,
+	"ppc64le": binary.LittleEndian,
 }
diff --git a/src/cmd/internal/objfile/elf.go b/src/cmd/internal/objfile/elf.go
index 17755b8..305706d 100644
--- a/src/cmd/internal/objfile/elf.go
+++ b/src/cmd/internal/objfile/elf.go
@@ -98,7 +98,7 @@ func (f *elfFile) goarch() string {
 	case elf.EM_ARM:
 		return "arm"
 	case elf.EM_PPC64:
-		return "power64"
+		return "ppc64"
 	}
 	return ""
 }
diff --git a/src/cmd/internal/objfile/macho.go b/src/cmd/internal/objfile/macho.go
index 7dd84a3..7371c0d 100644
--- a/src/cmd/internal/objfile/macho.go
+++ b/src/cmd/internal/objfile/macho.go
@@ -13,6 +13,8 @@ import (
 	"sort"
 )
 
+const stabTypeMask = 0xe0
+
 type machoFile struct {
 	macho *macho.File
 }
@@ -34,12 +36,19 @@ func (f *machoFile) symbols() ([]Sym, error) {
 	// We infer the size of a symbol by looking at where the next symbol begins.
 	var addrs []uint64
 	for _, s := range f.macho.Symtab.Syms {
-		addrs = append(addrs, s.Value)
+		// Skip stab debug info.
+		if s.Type&stabTypeMask == 0 {
+			addrs = append(addrs, s.Value)
+		}
 	}
 	sort.Sort(uint64s(addrs))
 
 	var syms []Sym
 	for _, s := range f.macho.Symtab.Syms {
+		if s.Type&stabTypeMask != 0 {
+			// Skip stab debug info.
+			continue
+		}
 		sym := Sym{Name: s.Name, Addr: s.Value, Code: '?'}
 		i := sort.Search(len(addrs), func(x int) bool { return addrs[x] > s.Value })
 		if i < len(addrs) {
@@ -104,7 +113,7 @@ func (f *machoFile) goarch() string {
 	case macho.CpuArm:
 		return "arm"
 	case macho.CpuPpc64:
-		return "power64"
+		return "ppc64"
 	}
 	return ""
 }
diff --git a/src/cmd/internal/rsc.io/arm/armasm/ext_test.go b/src/cmd/internal/rsc.io/arm/armasm/ext_test.go
index b0bd855..aa87cf9 100644
--- a/src/cmd/internal/rsc.io/arm/armasm/ext_test.go
+++ b/src/cmd/internal/rsc.io/arm/armasm/ext_test.go
@@ -216,7 +216,7 @@ func writeInst(generate func(func([]byte))) (file string, f *os.File, size int,
 
 var zeros = []byte{0, 0, 0, 0}
 
-// pad pads the code sequenc with pops.
+// pad pads the code sequence with pops.
 func pad(enc []byte) []byte {
 	if len(enc) < 4 {
 		enc = append(enc[:len(enc):len(enc)], zeros[:4-len(enc)]...)
diff --git a/src/cmd/internal/rsc.io/x86/x86asm/ext_test.go b/src/cmd/internal/rsc.io/x86/x86asm/ext_test.go
index f65d6b2..bb56c0d 100644
--- a/src/cmd/internal/rsc.io/x86/x86asm/ext_test.go
+++ b/src/cmd/internal/rsc.io/x86/x86asm/ext_test.go
@@ -225,7 +225,7 @@ var pops = []byte{
 	0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f, 0x5f,
 }
 
-// pad pads the code sequenc with pops.
+// pad pads the code sequence with pops.
 func pad(enc []byte) []byte {
 	return append(enc[:len(enc):len(enc)], pops...)
 }
diff --git a/src/cmd/ld/data.c b/src/cmd/ld/data.c
deleted file mode 100644
index 6184754..0000000
--- a/src/cmd/ld/data.c
+++ /dev/null
@@ -1,1397 +0,0 @@
-// 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 at 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 at 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.
-
-// Data layout and relocation.
-
-#include	"l.h"
-#include	"../ld/lib.h"
-#include	"../ld/elf.h"
-#include	"../ld/macho.h"
-#include	"../ld/pe.h"
-#include	"../../runtime/mgc0.h"
-
-void	dynreloc(void);
-
-/*
- * divide-and-conquer list-link
- * sort of LSym* structures.
- * Used for the data block.
- */
-int
-datcmp(LSym *s1, LSym *s2)
-{
-	if(s1->type != s2->type)
-		return (int)s1->type - (int)s2->type;
-	if(s1->size != s2->size) {
-		if(s1->size < s2->size)
-			return -1;
-		return +1;
-	}
-	return strcmp(s1->name, s2->name);
-}
-
-LSym*
-listsort(LSym *l, int (*cmp)(LSym*, LSym*), int off)
-{
-	LSym *l1, *l2, *le;
-	#define NEXT(l) (*(LSym**)((char*)(l)+off))
-
-	if(l == 0 || NEXT(l) == 0)
-		return l;
-
-	l1 = l;
-	l2 = l;
-	for(;;) {
-		l2 = NEXT(l2);
-		if(l2 == 0)
-			break;
-		l2 = NEXT(l2);
-		if(l2 == 0)
-			break;
-		l1 = NEXT(l1);
-	}
-
-	l2 = NEXT(l1);
-	NEXT(l1) = 0;
-	l1 = listsort(l, cmp, off);
-	l2 = listsort(l2, cmp, off);
-
-	/* set up lead element */
-	if(cmp(l1, l2) < 0) {
-		l = l1;
-		l1 = NEXT(l1);
-	} else {
-		l = l2;
-		l2 = NEXT(l2);
-	}
-	le = l;
-
-	for(;;) {
-		if(l1 == 0) {
-			while(l2) {
-				NEXT(le) = l2;
-				le = l2;
-				l2 = NEXT(l2);
-			}
-			NEXT(le) = 0;
-			break;
-		}
-		if(l2 == 0) {
-			while(l1) {
-				NEXT(le) = l1;
-				le = l1;
-				l1 = NEXT(l1);
-			}
-			break;
-		}
-		if(cmp(l1, l2) < 0) {
-			NEXT(le) = l1;
-			le = l1;
-			l1 = NEXT(l1);
-		} else {
-			NEXT(le) = l2;
-			le = l2;
-			l2 = NEXT(l2);
-		}
-	}
-	NEXT(le) = 0;
-	return l;
-	
-	#undef NEXT
-}
-
-void
-relocsym(LSym *s)
-{
-	Reloc *r;
-	LSym *rs;
-	int32 i, off, siz, fl;
-	vlong o;
-	uchar *cast;
-
-	ctxt->cursym = s;
-	for(r=s->r; r<s->r+s->nr; r++) {
-		r->done = 1;
-		off = r->off;
-		siz = r->siz;
-		if(off < 0 || off+siz > s->np) {
-			diag("%s: invalid relocation %d+%d not in [%d,%d)", s->name, off, siz, 0, s->np);
-			continue;
-		}
-		if(r->sym != S && ((r->sym->type & (SMASK | SHIDDEN)) == 0 || (r->sym->type & SMASK) == SXREF)) {
-			diag("%s: not defined", r->sym->name);
-			continue;
-		}
-		if(r->type >= 256)
-			continue;
-		if(r->siz == 0) // informational relocation - no work to do
-			continue;
-
-		// Solaris needs the ability to reference dynimport symbols.
-		if(HEADTYPE != Hsolaris && r->sym != S && r->sym->type == SDYNIMPORT)
-			diag("unhandled relocation for %s (type %d rtype %d)", r->sym->name, r->sym->type, r->type);
-		if(r->sym != S && r->sym->type != STLSBSS && !r->sym->reachable)
-			diag("unreachable sym in relocation: %s %s", s->name, r->sym->name);
-
-		// Android emulates runtime.tlsg as a regular variable.
-		if (r->type == R_TLS && strcmp(goos, "android") == 0)
-			r->type = R_ADDR;
-
-		switch(r->type) {
-		default:
-			o = 0;
-			if(archreloc(r, s, &o) < 0)
-				diag("unknown reloc %d", r->type);
-			break;
-		case R_TLS:
-			if(linkmode == LinkInternal && iself && thechar == '5') {
-				// On ELF ARM, the thread pointer is 8 bytes before
-				// the start of the thread-local data block, so add 8
-				// to the actual TLS offset (r->sym->value).
-				// This 8 seems to be a fundamental constant of
-				// ELF on ARM (or maybe Glibc on ARM); it is not
-				// related to the fact that our own TLS storage happens
-				// to take up 8 bytes.
-				o = 8 + r->sym->value;
-				break;
-			}
-			r->done = 0;
-			o = 0;
-			if(thechar != '6')
-				o = r->add;
-			break;
-		case R_TLS_LE:
-			if(linkmode == LinkExternal && iself && HEADTYPE != Hopenbsd) {
-				r->done = 0;
-				r->sym = ctxt->tlsg;
-				r->xsym = ctxt->tlsg;
-				r->xadd = r->add;
-				o = 0;
-				if(thechar != '6')
-					o = r->add;
-				break;
-			}
-			o = ctxt->tlsoffset + r->add;
-			break;
-
-		case R_TLS_IE:
-			if(linkmode == LinkExternal && iself && HEADTYPE != Hopenbsd) {
-				r->done = 0;
-				r->sym = ctxt->tlsg;
-				r->xsym = ctxt->tlsg;
-				r->xadd = r->add;
-				o = 0;
-				if(thechar != '6')
-					o = r->add;
-				break;
-			}
-			if(iself || ctxt->headtype == Hplan9)
-				o = ctxt->tlsoffset + r->add;
-			else if(ctxt->headtype == Hwindows)
-				o = r->add;
-			else
-				sysfatal("unexpected R_TLS_IE relocation for %s", headstr(ctxt->headtype));
-			break;
-		case R_ADDR:
-			if(linkmode == LinkExternal && r->sym->type != SCONST) {
-				r->done = 0;
-
-				// set up addend for eventual relocation via outer symbol.
-				rs = r->sym;
-				r->xadd = r->add;
-				while(rs->outer != nil) {
-					r->xadd += symaddr(rs) - symaddr(rs->outer);
-					rs = rs->outer;
-				}
-				if(rs->type != SHOSTOBJ && rs->type != SDYNIMPORT && rs->sect == nil)
-					diag("missing section for %s", rs->name);
-				r->xsym = rs;
-
-				o = r->xadd;
-				if(iself) {
-					if(thechar == '6')
-						o = 0;
-				} else if(HEADTYPE == Hdarwin) {
-					if(rs->type != SHOSTOBJ)
-						o += symaddr(rs);
-				} else {
-					diag("unhandled pcrel relocation for %s", headstring);
-				}
-				break;
-			}
-			o = symaddr(r->sym) + r->add;
-
-			// On amd64, 4-byte offsets will be sign-extended, so it is impossible to
-			// access more than 2GB of static data; fail at link time is better than
-			// fail at runtime. See http://golang.org/issue/7980.
-			// Instead of special casing only amd64, we treat this as an error on all
-			// 64-bit architectures so as to be future-proof.
-			if((int32)o < 0 && PtrSize > 4 && siz == 4) {
-				diag("non-pc-relative relocation address is too big: %#llux", o);
-				errorexit();
-			}
-			break;
-		case R_CALL:
-		case R_PCREL:
-			// r->sym can be null when CALL $(constant) is transformed from absolute PC to relative PC call.
-			if(linkmode == LinkExternal && r->sym && r->sym->type != SCONST && r->sym->sect != ctxt->cursym->sect) {
-				r->done = 0;
-
-				// set up addend for eventual relocation via outer symbol.
-				rs = r->sym;
-				r->xadd = r->add;
-				while(rs->outer != nil) {
-					r->xadd += symaddr(rs) - symaddr(rs->outer);
-					rs = rs->outer;
-				}
-				r->xadd -= r->siz; // relative to address after the relocated chunk
-				if(rs->type != SHOSTOBJ && rs->type != SDYNIMPORT && rs->sect == nil)
-					diag("missing section for %s", rs->name);
-				r->xsym = rs;
-
-				o = r->xadd;
-				if(iself) {
-					if(thechar == '6')
-						o = 0;
-				} else if(HEADTYPE == Hdarwin) {
-					if(r->type == R_CALL) {
-						if(rs->type != SHOSTOBJ)
-							o += symaddr(rs) - rs->sect->vaddr;
-						o -= r->off; // relative to section offset, not symbol
-					} else {
-						o += r->siz;
-					}
-				} else {
-					diag("unhandled pcrel relocation for %s", headstring);
-				}
-				break;
-			}
-			o = 0;
-			if(r->sym)
-				o += symaddr(r->sym);
-			// NOTE: The (int32) cast on the next line works around a bug in Plan 9's 8c
-			// compiler. The expression s->value + r->off + r->siz is int32 + int32 +
-			// uchar, and Plan 9 8c incorrectly treats the expression as type uint32
-			// instead of int32, causing incorrect values when sign extended for adding
-			// to o. The bug only occurs on Plan 9, because this C program is compiled by
-			// the standard host compiler (gcc on most other systems).
-			o += r->add - (s->value + r->off + (int32)r->siz);
-			break;
-		case R_SIZE:
-			o = r->sym->size + r->add;
-			break;
-		}
-//print("relocate %s %#llux (%#llux+%#llux, size %d) => %s %#llux +%#llx [%llx]\n", s->name, (uvlong)(s->value+off), (uvlong)s->value, (uvlong)r->off, r->siz, r->sym ? r->sym->name : "<nil>", (uvlong)symaddr(r->sym), (vlong)r->add, (vlong)o);
-		switch(siz) {
-		default:
-			ctxt->cursym = s;
-			diag("bad reloc size %#ux for %s", siz, r->sym->name);
-		case 1:
-			// TODO(rsc): Remove.
-			s->p[off] = (int8)o;
-			break;
-		case 4:
-			if(r->type == R_PCREL || r->type == R_CALL) {
-				if(o != (int32)o)
-					diag("pc-relative relocation address is too big: %#llx", o);
-			} else {
-				if(o != (int32)o && o != (uint32)o)
-					diag("non-pc-relative relocation address is too big: %#llux", o);
-			}
-			fl = o;
-			cast = (uchar*)&fl;
-			for(i=0; i<4; i++)
-				s->p[off+i] = cast[inuxi4[i]];
-			break;
-		case 8:
-			cast = (uchar*)&o;
-			for(i=0; i<8; i++)
-				s->p[off+i] = cast[inuxi8[i]];
-			break;
-		}
-	}
-}
-
-void
-reloc(void)
-{
-	LSym *s;
-
-	if(debug['v'])
-		Bprint(&bso, "%5.2f reloc\n", cputime());
-	Bflush(&bso);
-
-	for(s=ctxt->textp; s!=S; s=s->next)
-		relocsym(s);
-	for(s=datap; s!=S; s=s->next)
-		relocsym(s);
-}
-
-void
-dynrelocsym(LSym *s)
-{
-	Reloc *r;
-
-	if(HEADTYPE == Hwindows) {
-		LSym *rel, *targ;
-
-		rel = linklookup(ctxt, ".rel", 0);
-		if(s == rel)
-			return;
-		for(r=s->r; r<s->r+s->nr; r++) {
-			targ = r->sym;
-			if(targ == nil)
-				continue;
-			if(!targ->reachable)
-				diag("internal inconsistency: dynamic symbol %s is not reachable.", targ->name);
-			if(r->sym->plt == -2 && r->sym->got != -2) { // make dynimport JMP table for PE object files.
-				targ->plt = rel->size;
-				r->sym = rel;
-				r->add = targ->plt;
-
-				// jmp *addr
-				if(thechar == '8') {
-					adduint8(ctxt, rel, 0xff);
-					adduint8(ctxt, rel, 0x25);
-					addaddr(ctxt, rel, targ);
-					adduint8(ctxt, rel, 0x90);
-					adduint8(ctxt, rel, 0x90);
-				} else {
-					adduint8(ctxt, rel, 0xff);
-					adduint8(ctxt, rel, 0x24);
-					adduint8(ctxt, rel, 0x25);
-					addaddrplus4(ctxt, rel, targ, 0);
-					adduint8(ctxt, rel, 0x90);
-				}
-			} else if(r->sym->plt >= 0) {
-				r->sym = rel;
-				r->add = targ->plt;
-			}
-		}
-		return;
-	}
-
-	for(r=s->r; r<s->r+s->nr; r++) {
-		if(r->sym != S && r->sym->type == SDYNIMPORT || r->type >= 256) {
-			if(r->sym != S && !r->sym->reachable)
-				diag("internal inconsistency: dynamic symbol %s is not reachable.", r->sym->name);
-			adddynrel(s, r);
-		}
-	}
-}
-
-void
-dynreloc(void)
-{
-	LSym *s;
-
-	// -d suppresses dynamic loader format, so we may as well not
-	// compute these sections or mark their symbols as reachable.
-	if(debug['d'] && HEADTYPE != Hwindows)
-		return;
-	if(debug['v'])
-		Bprint(&bso, "%5.2f reloc\n", cputime());
-	Bflush(&bso);
-
-	for(s=ctxt->textp; s!=S; s=s->next)
-		dynrelocsym(s);
-	for(s=datap; s!=S; s=s->next)
-		dynrelocsym(s);
-	if(iself)
-		elfdynhash();
-}
-
-static void
-blk(LSym *start, int64 addr, int64 size)
-{
-	LSym *sym;
-	int64 eaddr;
-	uchar *p, *ep;
-
-	for(sym = start; sym != nil; sym = sym->next)
-		if(!(sym->type&SSUB) && sym->value >= addr)
-			break;
-
-	eaddr = addr+size;
-	for(; sym != nil; sym = sym->next) {
-		if(sym->type&SSUB)
-			continue;
-		if(sym->value >= eaddr)
-			break;
-		if(sym->value < addr) {
-			diag("phase error: addr=%#llx but sym=%#llx type=%d", (vlong)addr, (vlong)sym->value, sym->type);
-			errorexit();
-		}
-		ctxt->cursym = sym;
-		for(; addr < sym->value; addr++)
-			cput(0);
-		p = sym->p;
-		ep = p + sym->np;
-		while(p < ep)
-			cput(*p++);
-		addr += sym->np;
-		for(; addr < sym->value+sym->size; addr++)
-			cput(0);
-		if(addr != sym->value+sym->size) {
-			diag("phase error: addr=%#llx value+size=%#llx", (vlong)addr, (vlong)sym->value+sym->size);
-			errorexit();
-		}
-	}
-
-	for(; addr < eaddr; addr++)
-		cput(0);
-	cflush();
-}
-
-void
-codeblk(int64 addr, int64 size)
-{
-	LSym *sym;
-	int64 eaddr, n;
-	uchar *q;
-
-	if(debug['a'])
-		Bprint(&bso, "codeblk [%#x,%#x) at offset %#llx\n", addr, addr+size, cpos());
-
-	blk(ctxt->textp, addr, size);
-
-	/* again for printing */
-	if(!debug['a'])
-		return;
-
-	for(sym = ctxt->textp; sym != nil; sym = sym->next) {
-		if(!sym->reachable)
-			continue;
-		if(sym->value >= addr)
-			break;
-	}
-
-	eaddr = addr + size;
-	for(; sym != nil; sym = sym->next) {
-		if(!sym->reachable)
-			continue;
-		if(sym->value >= eaddr)
-			break;
-
-		if(addr < sym->value) {
-			Bprint(&bso, "%-20s %.8llux|", "_", (vlong)addr);
-			for(; addr < sym->value; addr++)
-				Bprint(&bso, " %.2ux", 0);
-			Bprint(&bso, "\n");
-		}
-
-		Bprint(&bso, "%.6llux\t%-20s\n", (vlong)addr, sym->name);
-		n = sym->size;
-		q = sym->p;
-
-		while(n >= 16) {
-			Bprint(&bso, "%.6ux\t%-20.16I\n", addr, q);
-			addr += 16;
-			q += 16;
-			n -= 16;
-		}
-		if(n > 0)
-			Bprint(&bso, "%.6ux\t%-20.*I\n", addr, (int)n, q);
-		addr += n;
-	}
-
-	if(addr < eaddr) {
-		Bprint(&bso, "%-20s %.8llux|", "_", (vlong)addr);
-		for(; addr < eaddr; addr++)
-			Bprint(&bso, " %.2ux", 0);
-	}
-	Bflush(&bso);
-}
-
-void
-datblk(int64 addr, int64 size)
-{
-	LSym *sym;
-	int64 i, eaddr;
-	uchar *p, *ep;
-	char *typ, *rsname;
-	Reloc *r;
-
-	if(debug['a'])
-		Bprint(&bso, "datblk [%#x,%#x) at offset %#llx\n", addr, addr+size, cpos());
-
-	blk(datap, addr, size);
-
-	/* again for printing */
-	if(!debug['a'])
-		return;
-
-	for(sym = datap; sym != nil; sym = sym->next)
-		if(sym->value >= addr)
-			break;
-
-	eaddr = addr + size;
-	for(; sym != nil; sym = sym->next) {
-		if(sym->value >= eaddr)
-			break;
-		if(addr < sym->value) {
-			Bprint(&bso, "\t%.8ux| 00 ...\n", addr);
-			addr = sym->value;
-		}
-		Bprint(&bso, "%s\n\t%.8ux|", sym->name, (uint)addr);
-		p = sym->p;
-		ep = p + sym->np;
-		while(p < ep) {
-			if(p > sym->p && (int)(p-sym->p)%16 == 0)
-				Bprint(&bso, "\n\t%.8ux|", (uint)(addr+(p-sym->p)));
-			Bprint(&bso, " %.2ux", *p++);
-		}
-		addr += sym->np;
-		for(; addr < sym->value+sym->size; addr++)
-			Bprint(&bso, " %.2ux", 0);
-		Bprint(&bso, "\n");
-		
-		if(linkmode == LinkExternal) {
-			for(i=0; i<sym->nr; i++) {
-				r = &sym->r[i];
-				rsname = "";
-				if(r->sym)
-					rsname = r->sym->name;
-				typ = "?";
-				switch(r->type) {
-				case R_ADDR:
-					typ = "addr";
-					break;
-				case R_PCREL:
-					typ = "pcrel";
-					break;
-				case R_CALL:
-					typ = "call";
-					break;
-				}
-				Bprint(&bso, "\treloc %.8ux/%d %s %s+%#llx [%#llx]\n",
-					(uint)(sym->value+r->off), r->siz, typ, rsname, (vlong)r->add, (vlong)(r->sym->value+r->add));
-			}
-		}				
-	}
-
-	if(addr < eaddr)
-		Bprint(&bso, "\t%.8ux| 00 ...\n", (uint)addr);
-	Bprint(&bso, "\t%.8ux|\n", (uint)eaddr);
-}
-
-void
-strnput(char *s, int n)
-{
-	for(; n > 0 && *s; s++) {
-		cput(*s);
-		n--;
-	}
-	while(n > 0) {
-		cput(0);
-		n--;
-	}
-}
-
-void
-addstrdata(char *name, char *value)
-{
-	LSym *s, *sp;
-	char *p;
-	uchar reachable;
-
-	p = smprint("%s.str", name);
-	sp = linklookup(ctxt, p, 0);
-	free(p);
-	addstring(sp, value);
-	sp->type = SRODATA;
-
-	s = linklookup(ctxt, name, 0);
-	s->size = 0;
-	s->dupok = 1;
-	reachable = s->reachable;
-	addaddr(ctxt, s, sp);
-	adduintxx(ctxt, s, strlen(value), PtrSize);
-
-	// addstring, addaddr, etc., mark the symbols as reachable.
-	// In this case that is not necessarily true, so stick to what
-	// we know before entering this function.
-	s->reachable = reachable;
-	sp->reachable = reachable;
-}
-
-vlong
-addstring(LSym *s, char *str)
-{
-	int n;
-	int32 r;
-
-	if(s->type == 0)
-		s->type = SNOPTRDATA;
-	s->reachable = 1;
-	r = s->size;
-	n = strlen(str)+1;
-	if(strcmp(s->name, ".shstrtab") == 0)
-		elfsetstring(str, r);
-	symgrow(ctxt, s, r+n);
-	memmove(s->p+r, str, n);
-	s->size += n;
-	return r;
-}
-
-void
-dosymtype(void)
-{
-	LSym *s;
-
-	for(s = ctxt->allsym; s != nil; s = s->allsym) {
-		if(s->np > 0) {
-			if(s->type == SBSS)
-				s->type = SDATA;
-			if(s->type == SNOPTRBSS)
-				s->type = SNOPTRDATA;
-		}
-	}
-}
-
-static int32
-symalign(LSym *s)
-{
-	int32 align;
-
-	if(s->align != 0)
-		return s->align;
-
-	align = MaxAlign;
-	while(align > s->size && align > 1)
-		align >>= 1;
-	if(align < s->align)
-		align = s->align;
-	return align;
-}
-	
-static vlong
-aligndatsize(vlong datsize, LSym *s)
-{
-	return rnd(datsize, symalign(s));
-}
-
-// maxalign returns the maximum required alignment for
-// the list of symbols s; the list stops when s->type exceeds type.
-static int32
-maxalign(LSym *s, int type)
-{
-	int32 align, max;
-	
-	max = 0;
-	for(; s != S && s->type <= type; s = s->next) {
-		align = symalign(s);
-		if(max < align)
-			max = align;
-	}
-	return max;
-}
-
-// Helper object for building GC type programs.
-typedef struct ProgGen ProgGen;
-struct ProgGen
-{
-	LSym*	s;
-	int32	datasize;
-	uint8	data[256/PointersPerByte];
-	vlong	pos;
-};
-
-static void
-proggeninit(ProgGen *g, LSym *s)
-{
-	g->s = s;
-	g->datasize = 0;
-	g->pos = 0;
-	memset(g->data, 0, sizeof(g->data));
-}
-
-static void
-proggenemit(ProgGen *g, uint8 v)
-{
-	adduint8(ctxt, g->s, v);
-}
-
-// Writes insData block from g->data.
-static void
-proggendataflush(ProgGen *g)
-{
-	int32 i, s;
-
-	if(g->datasize == 0)
-		return;
-	proggenemit(g, insData);
-	proggenemit(g, g->datasize);
-	s = (g->datasize + PointersPerByte - 1)/PointersPerByte;
-	for(i = 0; i < s; i++)
-		proggenemit(g, g->data[i]);
-	g->datasize = 0;
-	memset(g->data, 0, sizeof(g->data));
-}
-
-static void
-proggendata(ProgGen *g, uint8 d)
-{
-	g->data[g->datasize/PointersPerByte] |= d << ((g->datasize%PointersPerByte)*BitsPerPointer);
-	g->datasize++;
-	if(g->datasize == 255)
-		proggendataflush(g);
-}
-
-// Skip v bytes due to alignment, etc.
-static void
-proggenskip(ProgGen *g, vlong off, vlong v)
-{
-	vlong i;
-
-	for(i = off; i < off+v; i++) {
-		if((i%PtrSize) == 0)
-			proggendata(g, BitsScalar);
-	}
-}
-
-// Emit insArray instruction.
-static void
-proggenarray(ProgGen *g, vlong len)
-{
-	int32 i;
-
-	proggendataflush(g);
-	proggenemit(g, insArray);
-	for(i = 0; i < PtrSize; i++, len >>= 8)
-		proggenemit(g, len);
-}
-
-static void
-proggenarrayend(ProgGen *g)
-{
-	proggendataflush(g);
-	proggenemit(g, insArrayEnd);
-}
-
-static void
-proggenfini(ProgGen *g, vlong size)
-{
-	proggenskip(g, g->pos, size - g->pos);
-	proggendataflush(g);
-	proggenemit(g, insEnd);
-}
-
-
-// This function generates GC pointer info for global variables.
-static void
-proggenaddsym(ProgGen *g, LSym *s)
-{
-	LSym *gcprog;
-	uint8 *mask;
-	vlong i, size;
-
-	if(s->size == 0)
-		return;
-
-	// Skip alignment hole from the previous symbol.
-	proggenskip(g, g->pos, s->value - g->pos);
-	g->pos += s->value - g->pos;
-
-	// The test for names beginning with . here is meant
-	// to keep .dynamic and .dynsym from turning up as
-	// conservative symbols. They should be marked SELFSECT
-	// and not SDATA, but sometimes that doesn't happen.
-	// Leave debugging the SDATA issue for the Go rewrite.
-
-	if(s->gotype == nil && s->size >= PtrSize && s->name[0] != '.') {
-		// conservative scan
-		diag("missing Go type information for global symbol: %s size %d", s->name, (int)s->size);
-		if((s->size%PtrSize) || (g->pos%PtrSize))
-			diag("proggenaddsym: unaligned conservative symbol %s: size=%lld pos=%lld",
-				s->name, s->size, g->pos);
-		size = (s->size+PtrSize-1)/PtrSize*PtrSize;
-		if(size < 32*PtrSize) {
-			// Emit small symbols as data.
-			for(i = 0; i < size/PtrSize; i++)
-				proggendata(g, BitsPointer);
-		} else {
-			// Emit large symbols as array.
-			proggenarray(g, size/PtrSize);
-			proggendata(g, BitsPointer);
-			proggenarrayend(g);
-		}
-		g->pos = s->value + size;
-	} else if(s->gotype == nil || decodetype_noptr(s->gotype) || s->size < PtrSize || s->name[0] == '.') {
-		// no scan
-		if(s->size < 32*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++) {
-				if((i%PtrSize) == 0)
-					proggendata(g, BitsScalar);
-			}
-		} else {
-			// Emit large symbols as array.
-			if((s->size%PtrSize) || (g->pos%PtrSize))
-				diag("proggenaddsym: unaligned noscan symbol %s: size=%lld pos=%lld",
-					s->name, s->size, g->pos);
-			proggenarray(g, s->size/PtrSize);
-			proggendata(g, BitsScalar);
-			proggenarrayend(g);
-		}
-		g->pos = s->value + s->size;
-	} else if(decodetype_usegcprog(s->gotype)) {
-		// gc program, copy directly
-		proggendataflush(g);
-		gcprog = decodetype_gcprog(s->gotype);
-		size = decodetype_size(s->gotype);
-		if((size%PtrSize) || (g->pos%PtrSize))
-			diag("proggenaddsym: unaligned gcprog symbol %s: size=%lld pos=%lld",
-				s->name, s->size, g->pos);
-		for(i = 0; i < gcprog->np-1; i++)
-			proggenemit(g, gcprog->p[i]);
-		g->pos = s->value + size;
-	} else {
-		// gc mask, it's small so emit as data
-		mask = decodetype_gcmask(s->gotype);
-		size = decodetype_size(s->gotype);
-		if((size%PtrSize) || (g->pos%PtrSize))
-			diag("proggenaddsym: unaligned gcmask symbol %s: size=%lld pos=%lld",
-				s->name, s->size, g->pos);
-		for(i = 0; i < size; i += PtrSize)
-			proggendata(g, (mask[i/PtrSize/2]>>((i/PtrSize%2)*4+2))&BitsMask);
-		g->pos = s->value + size;
-	}
-}
-
-void
-growdatsize(vlong *datsizep, LSym *s)
-{
-	vlong datsize;
-	
-	datsize = *datsizep;
-	if(s->size < 0)
-		diag("negative size (datsize = %lld, s->size = %lld)", datsize, s->size);
-	if(datsize + s->size < datsize)
-		diag("symbol too large (datsize = %lld, s->size = %lld)", datsize, s->size);
-	*datsizep = datsize + s->size;
-}
-
-void
-dodata(void)
-{
-	int32 n;
-	vlong datsize;
-	Section *sect;
-	Segment *segro;
-	LSym *s, *last, **l;
-	LSym *gcdata, *gcbss;
-	ProgGen gen;
-
-	if(debug['v'])
-		Bprint(&bso, "%5.2f dodata\n", cputime());
-	Bflush(&bso);
-
-	last = nil;
-	datap = nil;
-
-	for(s=ctxt->allsym; s!=S; s=s->allsym) {
-		if(!s->reachable || s->special)
-			continue;
-		if(STEXT < s->type && s->type < SXREF) {
-			if(s->onlist)
-				sysfatal("symbol %s listed multiple times", s->name);
-			s->onlist = 1;
-			if(last == nil)
-				datap = s;
-			else
-				last->next = s;
-			s->next = nil;
-			last = s;
-		}
-	}
-
-	for(s = datap; s != nil; s = s->next) {
-		if(s->np > s->size)
-			diag("%s: initialize bounds (%lld < %d)",
-				s->name, (vlong)s->size, s->np);
-	}
-
-
-	/*
-	 * now that we have the datap list, but before we start
-	 * to assign addresses, record all the necessary
-	 * dynamic relocations.  these will grow the relocation
-	 * symbol, which is itself data.
-	 *
-	 * on darwin, we need the symbol table numbers for dynreloc.
-	 */
-	if(HEADTYPE == Hdarwin)
-		machosymorder();
-	dynreloc();
-
-	/* some symbols may no longer belong in datap (Mach-O) */
-	for(l=&datap; (s=*l) != nil; ) {
-		if(s->type <= STEXT || SXREF <= s->type)
-			*l = s->next;
-		else
-			l = &s->next;
-	}
-	*l = nil;
-
-	datap = listsort(datap, datcmp, offsetof(LSym, next));
-
-	/*
-	 * allocate sections.  list is sorted by type,
-	 * so we can just walk it for each piece we want to emit.
-	 * segdata is processed before segtext, because we need
-	 * to see all symbols in the .data and .bss sections in order
-	 * to generate garbage collection information.
-	 */
-
-	/* begin segdata */
-
-	/* skip symbols belonging to segtext */
-	s = datap;
-	for(; s != nil && s->type < SELFSECT; s = s->next)
-		;
-
-	/* writable ELF sections */
-	datsize = 0;
-	for(; s != nil && s->type < SNOPTRDATA; s = s->next) {
-		sect = addsection(&segdata, s->name, 06);
-		sect->align = symalign(s);
-		datsize = rnd(datsize, sect->align);
-		sect->vaddr = datsize;
-		s->sect = sect;
-		s->type = SDATA;
-		s->value = datsize - sect->vaddr;
-		growdatsize(&datsize, s);
-		sect->len = datsize - sect->vaddr;
-	}
-
-	/* pointer-free data */
-	sect = addsection(&segdata, ".noptrdata", 06);
-	sect->align = maxalign(s, SINITARR-1);
-	datsize = rnd(datsize, sect->align);
-	sect->vaddr = datsize;
-	linklookup(ctxt, "runtime.noptrdata", 0)->sect = sect;
-	linklookup(ctxt, "runtime.enoptrdata", 0)->sect = sect;
-	for(; s != nil && s->type < SINITARR; s = s->next) {
-		datsize = aligndatsize(datsize, s);
-		s->sect = sect;
-		s->type = SDATA;
-		s->value = datsize - sect->vaddr;
-		growdatsize(&datsize, s);
-	}
-	sect->len = datsize - sect->vaddr;
-
-	/* shared library initializer */
-	if(flag_shared) {
-		sect = addsection(&segdata, ".init_array", 06);
-		sect->align = maxalign(s, SINITARR);
-		datsize = rnd(datsize, sect->align);
-		sect->vaddr = datsize;
-		for(; s != nil && s->type == SINITARR; s = s->next) {
-			datsize = aligndatsize(datsize, s);
-			s->sect = sect;
-			s->value = datsize - sect->vaddr;
-			growdatsize(&datsize, s);
-		}
-		sect->len = datsize - sect->vaddr;
-	}
-
-	/* data */
-	sect = addsection(&segdata, ".data", 06);
-	sect->align = maxalign(s, SBSS-1);
-	datsize = rnd(datsize, sect->align);
-	sect->vaddr = datsize;
-	linklookup(ctxt, "runtime.data", 0)->sect = sect;
-	linklookup(ctxt, "runtime.edata", 0)->sect = sect;
-	gcdata = linklookup(ctxt, "runtime.gcdata", 0);
-	proggeninit(&gen, gcdata);
-	for(; s != nil && s->type < SBSS; s = s->next) {
-		if(s->type == SINITARR) {
-			ctxt->cursym = s;
-			diag("unexpected symbol type %d", s->type);
-		}
-		s->sect = sect;
-		s->type = SDATA;
-		datsize = aligndatsize(datsize, s);
-		s->value = datsize - sect->vaddr;
-		proggenaddsym(&gen, s);  // gc
-		growdatsize(&datsize, s);
-	}
-	sect->len = datsize - sect->vaddr;
-	proggenfini(&gen, sect->len);  // gc
-
-	/* bss */
-	sect = addsection(&segdata, ".bss", 06);
-	sect->align = maxalign(s, SNOPTRBSS-1);
-	datsize = rnd(datsize, sect->align);
-	sect->vaddr = datsize;
-	linklookup(ctxt, "runtime.bss", 0)->sect = sect;
-	linklookup(ctxt, "runtime.ebss", 0)->sect = sect;
-	gcbss = linklookup(ctxt, "runtime.gcbss", 0);
-	proggeninit(&gen, gcbss);
-	for(; s != nil && s->type < SNOPTRBSS; s = s->next) {
-		s->sect = sect;
-		datsize = aligndatsize(datsize, s);
-		s->value = datsize - sect->vaddr;
-		proggenaddsym(&gen, s);  // gc
-		growdatsize(&datsize, s);
-	}
-	sect->len = datsize - sect->vaddr;
-	proggenfini(&gen, sect->len);  // gc
-
-	/* pointer-free bss */
-	sect = addsection(&segdata, ".noptrbss", 06);
-	sect->align = maxalign(s, SNOPTRBSS);
-	datsize = rnd(datsize, sect->align);
-	sect->vaddr = datsize;
-	linklookup(ctxt, "runtime.noptrbss", 0)->sect = sect;
-	linklookup(ctxt, "runtime.enoptrbss", 0)->sect = sect;
-	for(; s != nil && s->type == SNOPTRBSS; s = s->next) {
-		datsize = aligndatsize(datsize, s);
-		s->sect = sect;
-		s->value = datsize - sect->vaddr;
-		growdatsize(&datsize, s);
-	}
-	sect->len = datsize - sect->vaddr;
-	linklookup(ctxt, "runtime.end", 0)->sect = sect;
-
-	// 6g uses 4-byte relocation offsets, so the entire segment must fit in 32 bits.
-	if(datsize != (uint32)datsize) {
-		diag("data or bss segment too large");
-	}
-	
-	if(iself && linkmode == LinkExternal && s != nil && s->type == STLSBSS && HEADTYPE != Hopenbsd) {
-		sect = addsection(&segdata, ".tbss", 06);
-		sect->align = PtrSize;
-		sect->vaddr = 0;
-		datsize = 0;
-		for(; s != nil && s->type == STLSBSS; s = s->next) {
-			datsize = aligndatsize(datsize, s);
-			s->sect = sect;
-			s->value = datsize - sect->vaddr;
-			growdatsize(&datsize, s);
-		}
-		sect->len = datsize;
-	} else {
-		// Might be internal linking but still using cgo.
-		// In that case, the only possible STLSBSS symbol is runtime.tlsg.
-		// Give it offset 0, because it's the only thing here.
-		if(s != nil && s->type == STLSBSS && strcmp(s->name, "runtime.tlsg") == 0) {
-			s->value = 0;
-			s = s->next;
-		}
-	}
-	
-	if(s != nil) {
-		ctxt->cursym = nil;
-		diag("unexpected symbol type %d for %s", s->type, s->name);
-	}
-
-	/*
-	 * We finished data, begin read-only data.
-	 * Not all systems support a separate read-only non-executable data section.
-	 * ELF systems do.
-	 * OS X and Plan 9 do not.
-	 * Windows PE may, but if so we have not implemented it.
-	 * And if we're using external linking mode, the point is moot,
-	 * since it's not our decision; that code expects the sections in
-	 * segtext.
-	 */
-	if(iself && linkmode == LinkInternal)
-		segro = &segrodata;
-	else
-		segro = &segtext;
-
-	s = datap;
-	
-	datsize = 0;
-	
-	/* read-only executable ELF, Mach-O sections */
-	for(; s != nil && s->type < STYPE; s = s->next) {
-		sect = addsection(&segtext, s->name, 04);
-		sect->align = symalign(s);
-		datsize = rnd(datsize, sect->align);
-		sect->vaddr = datsize;
-		s->sect = sect;
-		s->type = SRODATA;
-		s->value = datsize - sect->vaddr;
-		growdatsize(&datsize, s);
-		sect->len = datsize - sect->vaddr;
-	}
-
-	/* read-only data */
-	sect = addsection(segro, ".rodata", 04);
-	sect->align = maxalign(s, STYPELINK-1);
-	datsize = rnd(datsize, sect->align);
-	sect->vaddr = 0;
-	linklookup(ctxt, "runtime.rodata", 0)->sect = sect;
-	linklookup(ctxt, "runtime.erodata", 0)->sect = sect;
-	for(; s != nil && s->type < STYPELINK; s = s->next) {
-		datsize = aligndatsize(datsize, s);
-		s->sect = sect;
-		s->type = SRODATA;
-		s->value = datsize - sect->vaddr;
-		growdatsize(&datsize, s);
-	}
-	sect->len = datsize - sect->vaddr;
-
-	/* typelink */
-	sect = addsection(segro, ".typelink", 04);
-	sect->align = maxalign(s, STYPELINK);
-	datsize = rnd(datsize, sect->align);
-	sect->vaddr = datsize;
-	linklookup(ctxt, "runtime.typelink", 0)->sect = sect;
-	linklookup(ctxt, "runtime.etypelink", 0)->sect = sect;
-	for(; s != nil && s->type == STYPELINK; s = s->next) {
-		datsize = aligndatsize(datsize, s);
-		s->sect = sect;
-		s->type = SRODATA;
-		s->value = datsize - sect->vaddr;
-		growdatsize(&datsize, s);
-	}
-	sect->len = datsize - sect->vaddr;
-
-	/* gosymtab */
-	sect = addsection(segro, ".gosymtab", 04);
-	sect->align = maxalign(s, SPCLNTAB-1);
-	datsize = rnd(datsize, sect->align);
-	sect->vaddr = datsize;
-	linklookup(ctxt, "runtime.symtab", 0)->sect = sect;
-	linklookup(ctxt, "runtime.esymtab", 0)->sect = sect;
-	for(; s != nil && s->type < SPCLNTAB; s = s->next) {
-		datsize = aligndatsize(datsize, s);
-		s->sect = sect;
-		s->type = SRODATA;
-		s->value = datsize - sect->vaddr;
-		growdatsize(&datsize, s);
-	}
-	sect->len = datsize - sect->vaddr;
-
-	/* gopclntab */
-	sect = addsection(segro, ".gopclntab", 04);
-	sect->align = maxalign(s, SELFROSECT-1);
-	datsize = rnd(datsize, sect->align);
-	sect->vaddr = datsize;
-	linklookup(ctxt, "runtime.pclntab", 0)->sect = sect;
-	linklookup(ctxt, "runtime.epclntab", 0)->sect = sect;
-	for(; s != nil && s->type < SELFROSECT; s = s->next) {
-		datsize = aligndatsize(datsize, s);
-		s->sect = sect;
-		s->type = SRODATA;
-		s->value = datsize - sect->vaddr;
-		growdatsize(&datsize, s);
-	}
-	sect->len = datsize - sect->vaddr;
-
-	/* read-only ELF, Mach-O sections */
-	for(; s != nil && s->type < SELFSECT; s = s->next) {
-		sect = addsection(segro, s->name, 04);
-		sect->align = symalign(s);
-		datsize = rnd(datsize, sect->align);
-		sect->vaddr = datsize;
-		s->sect = sect;
-		s->type = SRODATA;
-		s->value = datsize - sect->vaddr;
-		growdatsize(&datsize, s);
-		sect->len = datsize - sect->vaddr;
-	}
-
-	// 6g uses 4-byte relocation offsets, so the entire segment must fit in 32 bits.
-	if(datsize != (uint32)datsize) {
-		diag("read-only data segment too large");
-	}
-	
-	/* number the sections */
-	n = 1;
-	for(sect = segtext.sect; sect != nil; sect = sect->next)
-		sect->extnum = n++;
-	for(sect = segrodata.sect; sect != nil; sect = sect->next)
-		sect->extnum = n++;
-	for(sect = segdata.sect; sect != nil; sect = sect->next)
-		sect->extnum = n++;
-}
-
-// assign addresses to text
-void
-textaddress(void)
-{
-	uvlong va;
-	Section *sect;
-	LSym *sym, *sub;
-
-	addsection(&segtext, ".text", 05);
-
-	// 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->align = funcalign;
-	linklookup(ctxt, "runtime.text", 0)->sect = sect;
-	linklookup(ctxt, "runtime.etext", 0)->sect = sect;
-	va = INITTEXT;
-	sect->vaddr = va;
-	for(sym = ctxt->textp; sym != nil; sym = sym->next) {
-		sym->sect = sect;
-		if(sym->type & SSUB)
-			continue;
-		if(sym->align != 0)
-			va = rnd(va, sym->align);
-		else
-			va = rnd(va, funcalign);
-		sym->value = 0;
-		for(sub = sym; sub != S; sub = sub->sub)
-			sub->value += va;
-		if(sym->size == 0 && sym->sub != S)
-			ctxt->cursym = sym;
-		va += sym->size;
-	}
-	sect->len = va - sect->vaddr;
-}
-
-// assign addresses
-void
-address(void)
-{
-	Section *s, *text, *data, *rodata, *symtab, *pclntab, *noptr, *bss, *noptrbss;
-	Section *typelink;
-	LSym *sym, *sub;
-	uvlong va;
-	vlong vlen;
-
-	va = INITTEXT;
-	segtext.rwx = 05;
-	segtext.vaddr = va;
-	segtext.fileoff = HEADR;
-	for(s=segtext.sect; s != nil; s=s->next) {
-		va = rnd(va, s->align);
-		s->vaddr = va;
-		va += s->len;
-	}
-	segtext.len = va - INITTEXT;
-	segtext.filelen = segtext.len;
-	if(HEADTYPE == Hnacl)
-		va += 32; // room for the "halt sled"
-
-	if(segrodata.sect != nil) {
-		// align to page boundary so as not to mix
-		// rodata and executable text.
-		va = rnd(va, INITRND);
-
-		segrodata.rwx = 04;
-		segrodata.vaddr = va;
-		segrodata.fileoff = va - segtext.vaddr + segtext.fileoff;
-		segrodata.filelen = 0;
-		for(s=segrodata.sect; s != nil; s=s->next) {
-			va = rnd(va, s->align);
-			s->vaddr = va;
-			va += s->len;
-		}
-		segrodata.len = va - segrodata.vaddr;
-		segrodata.filelen = segrodata.len;
-	}
-
-	va = rnd(va, INITRND);
-	segdata.rwx = 06;
-	segdata.vaddr = va;
-	segdata.fileoff = va - segtext.vaddr + segtext.fileoff;
-	segdata.filelen = 0;
-	if(HEADTYPE == Hwindows)
-		segdata.fileoff = segtext.fileoff + rnd(segtext.len, PEFILEALIGN);
-	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) {
-		vlen = s->len;
-		if(s->next)
-			vlen = s->next->vaddr - s->vaddr;
-		s->vaddr = va;
-		va += vlen;
-		segdata.len = va - segdata.vaddr;
-		if(strcmp(s->name, ".data") == 0)
-			data = s;
-		if(strcmp(s->name, ".noptrdata") == 0)
-			noptr = s;
-		if(strcmp(s->name, ".bss") == 0)
-			bss = s;
-		if(strcmp(s->name, ".noptrbss") == 0)
-			noptrbss = s;
-	}
-	segdata.filelen = bss->vaddr - segdata.vaddr;
-
-	text = segtext.sect;
-	if(segrodata.sect)
-		rodata = segrodata.sect;
-	else
-		rodata = text->next;
-	typelink = rodata->next;
-	symtab = typelink->next;
-	pclntab = symtab->next;
-
-	for(sym = datap; sym != nil; sym = sym->next) {
-		ctxt->cursym = sym;
-		if(sym->sect != nil)
-			sym->value += sym->sect->vaddr;
-		for(sub = sym->sub; sub != nil; sub = sub->sub)
-			sub->value += sym->value;
-	}
-
-	xdefine("runtime.text", STEXT, text->vaddr);
-	xdefine("runtime.etext", STEXT, text->vaddr + text->len);
-	xdefine("runtime.rodata", SRODATA, rodata->vaddr);
-	xdefine("runtime.erodata", SRODATA, rodata->vaddr + rodata->len);
-	xdefine("runtime.typelink", SRODATA, typelink->vaddr);
-	xdefine("runtime.etypelink", SRODATA, typelink->vaddr + typelink->len);
-
-	sym = linklookup(ctxt, "runtime.gcdata", 0);
-	xdefine("runtime.egcdata", SRODATA, symaddr(sym) + sym->size);
-	linklookup(ctxt, "runtime.egcdata", 0)->sect = sym->sect;
-
-	sym = linklookup(ctxt, "runtime.gcbss", 0);
-	xdefine("runtime.egcbss", SRODATA, symaddr(sym) + sym->size);
-	linklookup(ctxt, "runtime.egcbss", 0)->sect = sym->sect;
-
-	xdefine("runtime.symtab", SRODATA, symtab->vaddr);
-	xdefine("runtime.esymtab", SRODATA, symtab->vaddr + symtab->len);
-	xdefine("runtime.pclntab", SRODATA, pclntab->vaddr);
-	xdefine("runtime.epclntab", SRODATA, pclntab->vaddr + pclntab->len);
-	xdefine("runtime.noptrdata", SNOPTRDATA, noptr->vaddr);
-	xdefine("runtime.enoptrdata", SNOPTRDATA, noptr->vaddr + noptr->len);
-	xdefine("runtime.bss", SBSS, bss->vaddr);
-	xdefine("runtime.ebss", SBSS, bss->vaddr + bss->len);
-	xdefine("runtime.data", SDATA, data->vaddr);
-	xdefine("runtime.edata", SDATA, data->vaddr + data->len);
-	xdefine("runtime.noptrbss", SNOPTRBSS, noptrbss->vaddr);
-	xdefine("runtime.enoptrbss", SNOPTRBSS, noptrbss->vaddr + noptrbss->len);
-	xdefine("runtime.end", SBSS, segdata.vaddr + segdata.len);
-}
diff --git a/src/cmd/ld/decodesym.c b/src/cmd/ld/decodesym.c
deleted file mode 100644
index 037263d..0000000
--- a/src/cmd/ld/decodesym.c
+++ /dev/null
@@ -1,248 +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.
-
-#include	"l.h"
-#include	"lib.h"
-#include	"../../runtime/typekind.h"
-
-// Decoding the type.* symbols.	 This has to be in sync with
-// ../../runtime/type.go, or more specificaly, with what
-// ../gc/reflect.c stuffs in these.
-
-static Reloc*
-decode_reloc(LSym *s, int32 off)
-{
-	int i;
-
-	for (i = 0; i < s->nr; i++)
-		if (s->r[i].off == off)
-			return s->r + i;
-	return nil;
-}
-
-static LSym*
-decode_reloc_sym(LSym *s, int32 off)
-{
-	Reloc *r;
-
-	r = decode_reloc(s,off);
-	if (r == nil)
-		return nil;
-	return r->sym;
-}
-
-static uvlong
-decode_inuxi(uchar* p, int sz)
-{
-	uint64 v;
-	uint32 l;
-	uchar *cast, *inuxi;
-	int i;
-
-	v = l = 0;
-	cast = nil;
-	inuxi = nil;
-	switch (sz) {
-	case 2:
-		cast = (uchar*)&l;
-		inuxi = inuxi2;
-		break;
-	case 4:
-		cast = (uchar*)&l;
-		inuxi = inuxi4;
-		break;
-	case 8:
-		cast = (uchar*)&v;
-		inuxi = inuxi8;
-		break;
-	default:
-		diag("dwarf: decode inuxi %d", sz);
-		errorexit();
-	}
-	for (i = 0; i < sz; i++)
-		cast[inuxi[i]] = p[i];
-	if (sz == 8)
-		return v;
-	return l;
-}
-
-static int
-commonsize(void)
-{
-	return 8*PtrSize + 8;
-}
-
-// Type.commonType.kind
-uint8
-decodetype_kind(LSym *s)
-{
-	return s->p[1*PtrSize + 7] & KindMask;	//  0x13 / 0x1f
-}
-
-// Type.commonType.kind
-uint8
-decodetype_noptr(LSym *s)
-{
-	return s->p[1*PtrSize + 7] & KindNoPointers;	//  0x13 / 0x1f
-}
-
-// Type.commonType.kind
-uint8
-decodetype_usegcprog(LSym *s)
-{
-	return s->p[1*PtrSize + 7] & KindGCProg;	//  0x13 / 0x1f
-}
-
-// Type.commonType.size
-vlong
-decodetype_size(LSym *s)
-{
-	return decode_inuxi(s->p, PtrSize);	 // 0x8 / 0x10
-}
-
-// Type.commonType.gc
-LSym*
-decodetype_gcprog(LSym *s)
-{
-	return decode_reloc_sym(s, 1*PtrSize + 8 + 2*PtrSize);
-}
-
-uint8*
-decodetype_gcmask(LSym *s)
-{
-	LSym *mask;
-	
-	mask = decode_reloc_sym(s, 1*PtrSize + 8 + 1*PtrSize);
-	return mask->p;
-}
-
-// Type.ArrayType.elem and Type.SliceType.Elem
-LSym*
-decodetype_arrayelem(LSym *s)
-{
-	return decode_reloc_sym(s, commonsize());	// 0x1c / 0x30
-}
-
-vlong
-decodetype_arraylen(LSym *s)
-{
-	return decode_inuxi(s->p + commonsize()+2*PtrSize, PtrSize);
-}
-
-// Type.PtrType.elem
-LSym*
-decodetype_ptrelem(LSym *s)
-{
-	return decode_reloc_sym(s, commonsize());	// 0x1c / 0x30
-}
-
-// Type.MapType.key, elem
-LSym*
-decodetype_mapkey(LSym *s)
-{
-	return decode_reloc_sym(s, commonsize());	// 0x1c / 0x30
-}
-
-LSym*
-decodetype_mapvalue(LSym *s)
-{
-	return decode_reloc_sym(s, commonsize()+PtrSize);	// 0x20 / 0x38
-}
-
-// Type.ChanType.elem
-LSym*
-decodetype_chanelem(LSym *s)
-{
-	return decode_reloc_sym(s, commonsize());	// 0x1c / 0x30
-}
-
-// Type.FuncType.dotdotdot
-int
-decodetype_funcdotdotdot(LSym *s)
-{
-	return s->p[commonsize()];
-}
-
-// Type.FuncType.in.len
-int
-decodetype_funcincount(LSym *s)
-{
-	return decode_inuxi(s->p + commonsize()+2*PtrSize, IntSize);
-}
-
-int
-decodetype_funcoutcount(LSym *s)
-{
-	return decode_inuxi(s->p + commonsize()+3*PtrSize + 2*IntSize, IntSize);
-}
-
-LSym*
-decodetype_funcintype(LSym *s, int i)
-{
-	Reloc *r;
-
-	r = decode_reloc(s, commonsize() + PtrSize);
-	if (r == nil)
-		return nil;
-	return decode_reloc_sym(r->sym, r->add + i * PtrSize);
-}
-
-LSym*
-decodetype_funcouttype(LSym *s, int i)
-{
-	Reloc *r;
-
-	r = decode_reloc(s, commonsize() + 2*PtrSize + 2*IntSize);
-	if (r == nil)
-		return nil;
-	return decode_reloc_sym(r->sym, r->add + i * PtrSize);
-}
-
-// Type.StructType.fields.Slice::len
-int
-decodetype_structfieldcount(LSym *s)
-{
-	return decode_inuxi(s->p + commonsize() + PtrSize, IntSize);
-}
-
-static int
-structfieldsize(void)
-{
-	return 5*PtrSize;
-}
-
-// Type.StructType.fields[]-> name, typ and offset.
-char*
-decodetype_structfieldname(LSym *s, int i)
-{
-	Reloc *r;
-
-	// go.string."foo"  0x28 / 0x40
-	s = decode_reloc_sym(s, commonsize() + PtrSize + 2*IntSize + i*structfieldsize());
-	if (s == nil)			// embedded structs have a nil name.
-		return nil;
-	r = decode_reloc(s, 0);		// s has a pointer to the string data at offset 0
-	if (r == nil)			// shouldn't happen.
-		return nil;
-	return (char*) r->sym->p + r->add;	// the c-string
-}
-
-LSym*
-decodetype_structfieldtype(LSym *s, int i)
-{
-	return decode_reloc_sym(s, commonsize() + PtrSize + 2*IntSize + i*structfieldsize() + 2*PtrSize);
-}
-
-vlong
-decodetype_structfieldoffs(LSym *s, int i)
-{
-	return decode_inuxi(s->p + commonsize() + PtrSize + 2*IntSize + i*structfieldsize() + 4*PtrSize, IntSize);
-}
-
-// InterfaceTYpe.methods.len
-vlong
-decodetype_ifacemethodcount(LSym *s)
-{
-	return decode_inuxi(s->p + commonsize() + PtrSize, IntSize);
-}
diff --git a/src/cmd/ld/doc.go b/src/cmd/ld/doc.go
deleted file mode 100644
index 5b5833d..0000000
--- a/src/cmd/ld/doc.go
+++ /dev/null
@@ -1,100 +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.
-
-// +build ignore
-
-/*
-
-Ld is the portable code for a modified version of the Plan 9 linker.  The original is documented at
-
-	http://plan9.bell-labs.com/magic/man2html/1/8l
-
-It reads object files (.5, .6, or .8 files) and writes a binary named for the
-architecture (5.out, 6.out, 8.out) by default (if $GOOS is windows, a .exe suffix
-will be appended).
-
-Major changes include:
-	- support for ELF, Mach-O and PE binary files
-	- support for segmented stacks (this feature is implemented here, not in the compilers).
-
-Original options are listed on the manual page linked above.
-
-Usage:
-	go tool 6l [flags] mainObj
-Substitute 6l with 8l or 5l as appropriate.
-
-Options new in this version:
-
-	-d
-		Elide the dynamic linking header.  With this option, the binary
-		is statically linked and does not refer to a dynamic linker.  Without this option
-		(the default), the binary's contents are identical but it is loaded with a dynamic
-		linker. This flag cannot be used when $GOOS is windows.
-	-H darwin     (only in 6l/8l)
-		Write Apple Mach-O binaries (default when $GOOS is darwin)
-	-H dragonfly  (only in 6l/8l)
-		Write DragonFly ELF binaries (default when $GOOS is dragonfly)
-	-H linux
-		Write Linux ELF binaries (default when $GOOS is linux)
-	-H freebsd
-		Write FreeBSD ELF binaries (default when $GOOS is freebsd)
-	-H netbsd
-		Write NetBSD ELF binaries (default when $GOOS is netbsd)
-	-H openbsd    (only in 6l/8l)
-		Write OpenBSD ELF binaries (default when $GOOS is openbsd)
-	-H solaris    (only in 6l)
-		Write Solaris ELF binaries (default when $GOOS is solaris)
-	-H windows    (only in 6l/8l)
-		Write Windows PE32+ Console binaries (default when $GOOS is windows)
-	-H windowsgui (only in 6l/8l)
-		Write Windows PE32+ GUI binaries
-	-I interpreter
-		Set the ELF dynamic linker to use.
-	-L dir1 -L dir2
-		Search for libraries (package files) in dir1, dir2, etc.
-		The default is the single location $GOROOT/pkg/$GOOS_$GOARCH.
-	-r dir1:dir2:...
-		Set the dynamic linker search path when using ELF.
-	-s
-		Omit the symbol table and debug information.
-	-V
-		Print the linker version.
-	-w
-		Omit the DWARF symbol table.
-	-X symbol value
-		Set the value of a string variable. The symbol name
-		should be of the form importpath.name, as displayed
-		in the symbol table printed by "go tool nm".
-	-race
-		Link with race detection libraries.
-	-B value
-		Add a NT_GNU_BUILD_ID note when using ELF.  The value
-		should start with 0x and be an even number of hex digits.
-	-Z
-		Zero stack on function entry. This is expensive but it might
-		be useful in cases where you are suffering from false positives
-		during garbage collection and are willing to trade the CPU time
-		for getting rid of the false positives.
-		NOTE: it only eliminates false positives caused by other function
-		calls, not false positives caused by dead temporaries stored in
-		the current function call.
-	-linkmode argument
-		Set the linkmode.  The argument must be one of
-		internal, external, or auto.  The default is auto.
-		This sets the linking mode as described in
-		../cgo/doc.go.
-	-tmpdir dir
-		Set the location to use for any temporary files.  The
-		default is a newly created directory that is removed
-		after the linker completes.  Temporary files are only
-		used in external linking mode.
-	-extld name
-		Set the name of the external linker to use in external
-		linking mode.  The default is "gcc".
-	-extldflags flags
-		Set space-separated trailing flags to pass to the
-		external linker in external linking mode.  The default
-		is to not pass any additional trailing flags.
-*/
-package main
diff --git a/src/cmd/ld/dwarf.c b/src/cmd/ld/dwarf.c
deleted file mode 100644
index dfe515c..0000000
--- a/src/cmd/ld/dwarf.c
+++ /dev/null
@@ -1,2466 +0,0 @@
-// Copyright 2010 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.
-
-// 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
-//
-#include	"l.h"
-#include	"lib.h"
-#include	"../ld/dwarf.h"
-#include	"../ld/dwarf_defs.h"
-#include	"../ld/elf.h"
-#include	"../ld/macho.h"
-#include	"../ld/pe.h"
-#include	"../../runtime/typekind.h"
-
-/*
- * Offsets and sizes of the debug_* sections in the cout file.
- */
-
-static vlong abbrevo;
-static vlong abbrevsize;
-static LSym*  abbrevsym;
-static vlong abbrevsympos;
-static vlong lineo;
-static vlong linesize;
-static LSym*  linesym;
-static vlong linesympos;
-static vlong infoo;	// also the base for DWDie->offs and reference attributes.
-static vlong infosize;
-static LSym*  infosym;
-static vlong infosympos;
-static vlong frameo;
-static vlong framesize;
-static LSym*  framesym;
-static vlong framesympos;
-static vlong pubnameso;
-static vlong pubnamessize;
-static vlong pubtypeso;
-static vlong pubtypessize;
-static vlong arangeso;
-static vlong arangessize;
-static vlong gdbscripto;
-static vlong gdbscriptsize;
-
-static LSym *infosec;
-static vlong inforeloco;
-static vlong inforelocsize;
-
-static LSym *arangessec;
-static vlong arangesreloco;
-static vlong arangesrelocsize;
-
-static LSym *linesec;
-static vlong linereloco;
-static vlong linerelocsize;
-
-static LSym *framesec;
-static vlong framereloco;
-static vlong framerelocsize;
-
-static char  gdbscript[1024];
-
-/*
- *  Basic I/O
- */
-
-static void
-addrput(vlong addr)
-{
-	switch(PtrSize) {
-	case 4:
-		LPUT(addr);
-		break;
-	case 8:
-		VPUT(addr);
-		break;
-	}
-}
-
-static int
-uleb128enc(uvlong v, char* dst)
-{
-	uint8 c, len;
-
-	len = 0;
-	do {
-		c = v & 0x7f;
-		v >>= 7;
-		if (v)
-			c |= 0x80;
-		if (dst)
-			*dst++ = c;
-		len++;
-	} while (c & 0x80);
-	return len;
-};
-
-static int
-sleb128enc(vlong v, char *dst)
-{
-	uint8 c, s, len;
-
-	len = 0;
-	do {
-		c = v & 0x7f;
-		s = v & 0x40;
-		v >>= 7;
-		if ((v != -1 || !s) && (v != 0 || s))
-			c |= 0x80;
-		if (dst)
-			*dst++ = c;
-		len++;
-	} while(c & 0x80);
-	return len;
-}
-
-static void
-uleb128put(vlong v)
-{
-	char buf[10];
-	strnput(buf, uleb128enc(v, buf));
-}
-
-static void
-sleb128put(vlong v)
-{
-	char buf[10];
-	strnput(buf, sleb128enc(v, buf));
-}
-
-/*
- * Defining Abbrevs.  This is hardcoded, and there will be
- * only a handful of them.  The DWARF spec places no restriction on
- * the ordering of attributes in the Abbrevs and DIEs, and we will
- * always write them out in the order of declaration in the abbrev.
- */
-typedef struct DWAttrForm DWAttrForm;
-struct DWAttrForm {
-	uint16 attr;
-	uint8 form;
-};
-
-// Go-specific type attributes.
-enum {
-	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.
-// Keep in sync with ispubname() and ispubtype() below.
-// ispubtype considers >= NULLTYPE public
-enum
-{
-	DW_ABRV_NULL,
-	DW_ABRV_COMPUNIT,
-	DW_ABRV_FUNCTION,
-	DW_ABRV_VARIABLE,
-	DW_ABRV_AUTO,
-	DW_ABRV_PARAM,
-	DW_ABRV_STRUCTFIELD,
-	DW_ABRV_FUNCTYPEPARAM,
-	DW_ABRV_DOTDOTDOT,
-	DW_ABRV_ARRAYRANGE,
-	DW_ABRV_NULLTYPE,
-	DW_ABRV_BASETYPE,
-	DW_ABRV_ARRAYTYPE,
-	DW_ABRV_CHANTYPE,
-	DW_ABRV_FUNCTYPE,
-	DW_ABRV_IFACETYPE,
-	DW_ABRV_MAPTYPE,
-	DW_ABRV_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,
-	DW_ABRV_TYPEDECL,
-	DW_NABRV
-};
-
-typedef struct DWAbbrev DWAbbrev;
-static struct DWAbbrev {
-	uint8 tag;
-	uint8 children;
-	DWAttrForm attr[30];
-} abbrevs[DW_NABRV] = {
-	/* The mandatory DW_ABRV_NULL entry. */
-	{ 0 },
-	/* COMPUNIT */
-	{
-		DW_TAG_compile_unit, DW_CHILDREN_yes,
-		DW_AT_name,	 DW_FORM_string,
-		DW_AT_language,	 DW_FORM_data1,
-		DW_AT_low_pc,	 DW_FORM_addr,
-		DW_AT_high_pc,	 DW_FORM_addr,
-		DW_AT_stmt_list, DW_FORM_data4,
-		0, 0
-	},
-	/* FUNCTION */
-	{
-		DW_TAG_subprogram, DW_CHILDREN_yes,
-		DW_AT_name,	 DW_FORM_string,
-		DW_AT_low_pc,	 DW_FORM_addr,
-		DW_AT_high_pc,	 DW_FORM_addr,
-		DW_AT_external,	 DW_FORM_flag,
-		0, 0
-	},
-	/* VARIABLE */
-	{
-		DW_TAG_variable, DW_CHILDREN_no,
-		DW_AT_name,	 DW_FORM_string,
-		DW_AT_location,	 DW_FORM_block1,
-		DW_AT_type,	 DW_FORM_ref_addr,
-		DW_AT_external,	 DW_FORM_flag,
-		0, 0
-	},
-	/* AUTO */
-	{
-		DW_TAG_variable, DW_CHILDREN_no,
-		DW_AT_name,	 DW_FORM_string,
-		DW_AT_location,	 DW_FORM_block1,
-		DW_AT_type,	 DW_FORM_ref_addr,
-		0, 0
-	},
-	/* PARAM */
-	{
-		DW_TAG_formal_parameter, DW_CHILDREN_no,
-		DW_AT_name,	 DW_FORM_string,
-		DW_AT_location,	 DW_FORM_block1,
-		DW_AT_type,	 DW_FORM_ref_addr,
-		0, 0
-	},
-	/* STRUCTFIELD */
-	{
-		DW_TAG_member,	DW_CHILDREN_no,
-		DW_AT_name,	DW_FORM_string,
-		DW_AT_data_member_location, DW_FORM_block1,
-		DW_AT_type,	 DW_FORM_ref_addr,
-		0, 0
-	},
-	/* FUNCTYPEPARAM */
-	{
-		DW_TAG_formal_parameter, DW_CHILDREN_no,
-		// No name!
-		DW_AT_type,	 DW_FORM_ref_addr,
-		0, 0
-	},
-
-	/* DOTDOTDOT */
-	{
-		DW_TAG_unspecified_parameters, DW_CHILDREN_no,
-		0, 0
-	},
-	/* ARRAYRANGE */
-	{
-		DW_TAG_subrange_type, DW_CHILDREN_no,
-		// No name!
-		DW_AT_type,	 DW_FORM_ref_addr,
-		DW_AT_count, DW_FORM_udata,
-		0, 0
-	},
-
-	// Below here are the types considered public by ispubtype
-	/* NULLTYPE */
-	{
-		DW_TAG_unspecified_type, DW_CHILDREN_no,
-		DW_AT_name,	DW_FORM_string,
-		0, 0
-	},
-	/* BASETYPE */
-	{
-		DW_TAG_base_type, DW_CHILDREN_no,
-		DW_AT_name,	 DW_FORM_string,
-		DW_AT_encoding,	 DW_FORM_data1,
-		DW_AT_byte_size, DW_FORM_data1,
-		DW_AT_go_kind, DW_FORM_data1,
-		0, 0
-	},
-	/* ARRAYTYPE */
-	// child is subrange with upper bound
-	{
-		DW_TAG_array_type, DW_CHILDREN_yes,
-		DW_AT_name,	DW_FORM_string,
-		DW_AT_type,	DW_FORM_ref_addr,
-		DW_AT_byte_size, DW_FORM_udata,
-		DW_AT_go_kind, DW_FORM_data1,
-		0, 0
-	},
-
-	/* CHANTYPE */
-	{
-		DW_TAG_typedef, DW_CHILDREN_no,
-		DW_AT_name,	DW_FORM_string,
-		DW_AT_type,	DW_FORM_ref_addr,
-		DW_AT_go_kind, DW_FORM_data1,
-		DW_AT_go_elem, DW_FORM_ref_addr,
-		0, 0
-	},
-
-	/* FUNCTYPE */
-	{
-		DW_TAG_subroutine_type, DW_CHILDREN_yes,
-		DW_AT_name,	DW_FORM_string,
-//		DW_AT_type,	DW_FORM_ref_addr,
-		DW_AT_go_kind, DW_FORM_data1,
-		0, 0
-	},
-
-	/* IFACETYPE */
-	{
-		DW_TAG_typedef, DW_CHILDREN_yes,
-		DW_AT_name,	 DW_FORM_string,
-		DW_AT_type,	DW_FORM_ref_addr,
-		DW_AT_go_kind, DW_FORM_data1,
-		0, 0
-	},
-
-	/* MAPTYPE */
-	{
-		DW_TAG_typedef, DW_CHILDREN_no,
-		DW_AT_name,	DW_FORM_string,
-		DW_AT_type,	DW_FORM_ref_addr,
-		DW_AT_go_kind, DW_FORM_data1,
-		DW_AT_go_key, DW_FORM_ref_addr,
-		DW_AT_go_elem, DW_FORM_ref_addr,
-		0, 0
-	},
-
-	/* PTRTYPE */
-	{
-		DW_TAG_pointer_type, DW_CHILDREN_no,
-		DW_AT_name,	DW_FORM_string,
-		DW_AT_type,	DW_FORM_ref_addr,
-		DW_AT_go_kind, DW_FORM_data1,
-		0, 0
-	},
-	/* BARE_PTRTYPE */
-	{
-		DW_TAG_pointer_type, DW_CHILDREN_no,
-		DW_AT_name,	DW_FORM_string,
-		0, 0
-	},
-
-	/* SLICETYPE */
-	{
-		DW_TAG_structure_type, DW_CHILDREN_yes,
-		DW_AT_name,	DW_FORM_string,
-		DW_AT_byte_size, DW_FORM_udata,
-		DW_AT_go_kind, DW_FORM_data1,
-		DW_AT_go_elem, DW_FORM_ref_addr,
-		0, 0
-	},
-
-	/* STRINGTYPE */
-	{
-		DW_TAG_structure_type, DW_CHILDREN_yes,
-		DW_AT_name,	DW_FORM_string,
-		DW_AT_byte_size, DW_FORM_udata,
-		DW_AT_go_kind, DW_FORM_data1,
-		0, 0
-	},
-
-	/* STRUCTTYPE */
-	{
-		DW_TAG_structure_type, DW_CHILDREN_yes,
-		DW_AT_name,	DW_FORM_string,
-		DW_AT_byte_size, DW_FORM_udata,
-		DW_AT_go_kind, DW_FORM_data1,
-		0, 0
-	},
-
-	/* TYPEDECL */
-	{
-		DW_TAG_typedef, DW_CHILDREN_no,
-		DW_AT_name,	DW_FORM_string,
-		DW_AT_type,	DW_FORM_ref_addr,
-		0, 0
-	},
-};
-
-static void
-writeabbrev(void)
-{
-	int i, j;
-	DWAttrForm *f;
-
-	abbrevo = cpos();
-	for (i = 1; i < DW_NABRV; i++) {
-		// See section 7.5.3
-		uleb128put(i);
-		uleb128put(abbrevs[i].tag);
-		cput(abbrevs[i].children);
-		for(j=0; j<nelem(abbrevs[i].attr); j++) {
-			f = &abbrevs[i].attr[j];
-			uleb128put(f->attr);
-			uleb128put(f->form);
-			if(f->attr == 0)
-				break;
-		}
-	}
-	cput(0);
-	abbrevsize = cpos() - abbrevo;
-}
-
-/*
- * Debugging Information Entries and their attributes.
- */
-
-enum
-{
-	HASHSIZE = 107
-};
-
-static uint32
-hashstr(char* s)
-{
-	uint32 h;
-
-	h = 0;
-	while (*s)
-		h = h+h+h + *s++;
-	return h % HASHSIZE;
-}
-
-// For DW_CLS_string and _block, value should contain the length, and
-// data the data, for _reference, value is 0 and data is a DWDie* to
-// the referenced instance, for all others, value is the whole thing
-// and data is null.
-
-typedef struct DWAttr DWAttr;
-struct DWAttr {
-	DWAttr *link;
-	uint16 atr;  // DW_AT_
-	uint8 cls;  // DW_CLS_
-	vlong value;
-	char *data;
-};
-
-typedef struct DWDie DWDie;
-struct DWDie {
-	int abbrev;
-	DWDie *link;
-	DWDie *child;
-	DWAttr *attr;
-	// offset into .debug_info section, i.e relative to
-	// infoo. only valid after call to putdie()
-	vlong offs;
-	DWDie **hash;  // optional index of children by name, enabled by mkindex()
-	DWDie *hlink;  // bucket chain in parent's index
-};
-
-/*
- * Root DIEs for compilation units, types and global variables.
- */
-
-static DWDie dwroot;
-static DWDie dwtypes;
-static DWDie dwglobals;
-
-static DWAttr*
-newattr(DWDie *die, uint16 attr, int cls, vlong value, char *data)
-{
-	DWAttr *a;
-
-	a = mal(sizeof *a);
-	a->link = die->attr;
-	die->attr = a;
-	a->atr = attr;
-	a->cls = cls;
-	a->value = value;
-	a->data = data;
-	return a;
-}
-
-// Each DIE (except the root ones) has at least 1 attribute: its
-// name. getattr moves the desired one to the front so
-// frequently searched ones are found faster.
-static DWAttr*
-getattr(DWDie *die, uint16 attr)
-{
-	DWAttr *a, *b;
-
-	if (die->attr->atr == attr)
-		return die->attr;
-
-	a = die->attr;
-	b = a->link;
-	while (b != nil) {
-		if (b->atr == attr) {
-			a->link = b->link;
-			b->link = die->attr;
-			die->attr = b;
-			return b;
-		}
-		a = b;
-		b = b->link;
-	}
-	return nil;
-}
-
-// Every DIE has at least a DW_AT_name attribute (but it will only be
-// written out if it is listed in the abbrev).	If its parent is
-// keeping an index, the new DIE will be inserted there.
-static DWDie*
-newdie(DWDie *parent, int abbrev, char *name)
-{
-	DWDie *die;
-	int h;
-
-	die = mal(sizeof *die);
-	die->abbrev = abbrev;
-	die->link = parent->child;
-	parent->child = die;
-
-	newattr(die, DW_AT_name, DW_CLS_STRING, strlen(name), name);
-
-	if (parent->hash) {
-		h = hashstr(name);
-		die->hlink = parent->hash[h];
-		parent->hash[h] = die;
-	}
-
-	return die;
-}
-
-static void
-mkindex(DWDie *die)
-{
-	die->hash = mal(HASHSIZE * sizeof(DWDie*));
-}
-
-static DWDie*
-walktypedef(DWDie *die)
-{
-	DWAttr *attr;
-
-	// Resolve typedef if present.
-	if (die->abbrev == DW_ABRV_TYPEDECL) {
-		for (attr = die->attr; attr; attr = attr->link) {
-			if (attr->atr == DW_AT_type && attr->cls == DW_CLS_REFERENCE && attr->data != nil) {
-				return (DWDie*)attr->data;
-			}
-		}
-	}
-	return die;
-}
-
-// Find child by AT_name using hashtable if available or linear scan
-// if not.
-static DWDie*
-find(DWDie *die, char* name)
-{
-	DWDie *a, *b, *die2;
-	int h;
-
-top:
-	if (die->hash == nil) {
-		for (a = die->child; a != nil; a = a->link)
-			if (strcmp(name, getattr(a, DW_AT_name)->data) == 0)
-				return a;
-		goto notfound;
-	}
-
-	h = hashstr(name);
-	a = die->hash[h];
-
-	if (a == nil)
-		goto notfound;
-
-
-	if (strcmp(name, getattr(a, DW_AT_name)->data) == 0)
-		return a;
-
-	// Move found ones to head of the list.
-	b = a->hlink;
-	while (b != nil) {
-		if (strcmp(name, getattr(b, DW_AT_name)->data) == 0) {
-			a->hlink = b->hlink;
-			b->hlink = die->hash[h];
-			die->hash[h] = b;
-			return b;
-		}
-		a = b;
-		b = b->hlink;
-	}
-
-notfound:
-	die2 = walktypedef(die);
-	if(die2 != die) {
-		die = die2;
-		goto top;
-	}
-
-	return nil;
-}
-
-static DWDie*
-find_or_diag(DWDie *die, char* name)
-{
-	DWDie *r;
-	r = find(die, name);
-	if (r == nil) {
-		diag("dwarf find: %s %p has no %s", getattr(die, DW_AT_name)->data, die, name);
-		errorexit();
-	}
-	return r;
-}
-
-static void
-adddwarfrel(LSym* sec, LSym* sym, vlong offsetbase, int siz, vlong addend)
-{
-	Reloc *r;
-
-	r = addrel(sec);
-	r->sym = sym;
-	r->xsym = sym;
-	r->off = cpos() - offsetbase;
-	r->siz = siz;
-	r->type = R_ADDR;
-	r->add = addend;
-	r->xadd = addend;
-	if(iself && thechar == '6')
-		addend = 0;
-	switch(siz) {
-	case 4:
-		LPUT(addend);
-		break;
-	case 8:
-		VPUT(addend);
-		break;
-	default:
-		diag("bad size in adddwarfrel");
-		break;
-	}
-}
-
-static DWAttr*
-newrefattr(DWDie *die, uint16 attr, DWDie* ref)
-{
-	if (ref == nil)
-		return nil;
-	return newattr(die, attr, DW_CLS_REFERENCE, 0, (char*)ref);
-}
-
-static int fwdcount;
-
-static void
-putattr(int abbrev, int form, int cls, vlong value, char *data)
-{
-	vlong off;
-
-	switch(form) {
-	case DW_FORM_addr:	// address
-		if(linkmode == LinkExternal) {
-			value -= ((LSym*)data)->value;
-			adddwarfrel(infosec, (LSym*)data, infoo, PtrSize, value);
-			break;
-		}
-		addrput(value);
-		break;
-
-	case DW_FORM_block1:	// block
-		if(cls == DW_CLS_ADDRESS) {
-			cput(1+PtrSize);
-			cput(DW_OP_addr);
-			if(linkmode == LinkExternal) {
-				value -= ((LSym*)data)->value;
-				adddwarfrel(infosec, (LSym*)data, infoo, PtrSize, value);
-				break;
-			}
-			addrput(value);
-			break;
-		}
-		value &= 0xff;
-		cput(value);
-		while(value--)
-			cput(*data++);
-		break;
-
-	case DW_FORM_block2:	// block
-		value &= 0xffff;
-		WPUT(value);
-		while(value--)
-			cput(*data++);
-		break;
-
-	case DW_FORM_block4:	// block
-		value &= 0xffffffff;
-		LPUT(value);
-		while(value--)
-			cput(*data++);
-		break;
-
-	case DW_FORM_block:	// block
-		uleb128put(value);
-		while(value--)
-			cput(*data++);
-		break;
-
-	case DW_FORM_data1:	// constant
-		cput(value);
-		break;
-
-	case DW_FORM_data2:	// constant
-		WPUT(value);
-		break;
-
-	case DW_FORM_data4:	// constant, {line,loclist,mac,rangelist}ptr
-		if(linkmode == LinkExternal && cls == DW_CLS_PTR) {
-			adddwarfrel(infosec, linesym, infoo, 4, value);
-			break;
-		}
-		LPUT(value);
-		break;
-
-	case DW_FORM_data8:	// constant, {line,loclist,mac,rangelist}ptr
-		VPUT(value);
-		break;
-
-	case DW_FORM_sdata:	// constant
-		sleb128put(value);
-		break;
-
-	case DW_FORM_udata:	// constant
-		uleb128put(value);
-		break;
-
-	case DW_FORM_string:	// string
-		strnput(data, value+1);
-		break;
-
-	case DW_FORM_flag:	// flag
-		cput(value?1:0);
-		break;
-
-	case DW_FORM_ref_addr:	// reference to a DIE in the .info section
-		// In DWARF 2 (which is what we claim to generate),
-		// the ref_addr is the same size as a normal address.
-		// In DWARF 3 it is always 32 bits, unless emitting a large
-		// (> 4 GB of debug info aka "64-bit") unit, which we don't implement.
-		if (data == nil) {
-			diag("dwarf: null reference in %d", abbrev);
-			if(PtrSize == 8)
-				VPUT(0); // invalid dwarf, gdb will complain.
-			else
-				LPUT(0); // invalid dwarf, gdb will complain.
-		} else {
-			off = ((DWDie*)data)->offs;
-			if (off == 0)
-				fwdcount++;
-			if(linkmode == LinkExternal) {
-				adddwarfrel(infosec, infosym, infoo, PtrSize, off);
-				break;
-			}
-			addrput(off);
-		}
-		break;
-
-	case DW_FORM_ref1:	// reference within the compilation unit
-	case DW_FORM_ref2:	// reference
-	case DW_FORM_ref4:	// reference
-	case DW_FORM_ref8:	// reference
-	case DW_FORM_ref_udata:	// reference
-
-	case DW_FORM_strp:	// string
-	case DW_FORM_indirect:	// (see Section 7.5.3)
-	default:
-		diag("dwarf: unsupported attribute form %d / class %d", form, cls);
-		errorexit();
-	}
-}
-
-// 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.
-static void
-putattrs(int abbrev, DWAttr* attr)
-{
-	DWAttrForm* af;
-	DWAttr *ap;
-
-	for(af = abbrevs[abbrev].attr; af->attr; af++) {
-		for(ap=attr; ap; ap=ap->link) {
-			if(ap->atr == af->attr) {
-				putattr(abbrev, af->form,
-					ap->cls,
-					ap->value,
-					ap->data);
-				goto done;
-			}
-		}
-		putattr(abbrev, af->form, 0, 0, nil);
-	done:;
-	}
-}
-
-static void putdie(DWDie* die);
-
-static void
-putdies(DWDie* die)
-{
-	for(; die; die = die->link)
-		putdie(die);
-}
-
-static void
-putdie(DWDie* die)
-{
-	die->offs = cpos() - infoo;
-	uleb128put(die->abbrev);
-	putattrs(die->abbrev, die->attr);
-	if (abbrevs[die->abbrev].children) {
-		putdies(die->child);
-		cput(0);
-	}
-}
-
-static void
-reverselist(DWDie** list)
-{
-	DWDie *curr, *prev;
-
-	curr = *list;
-	prev = nil;
-	while(curr != nil) {
-		DWDie* next = curr->link;
-		curr->link = prev;
-		prev = curr;
-		curr = next;
-	}
-	*list = prev;
-}
-
-static void
-reversetree(DWDie** list)
-{
-	 DWDie *die;
-
-	 reverselist(list);
-	 for (die = *list; die != nil; die = die->link)
-		 if (abbrevs[die->abbrev].children)
-			 reversetree(&die->child);
-}
-
-static void
-newmemberoffsetattr(DWDie *die, int32 offs)
-{
-	char block[10];
-	int i;
-
-	i = 0;
-	block[i++] = DW_OP_plus_uconst;
-	i += uleb128enc(offs, block+i);
-	newattr(die, DW_AT_data_member_location, DW_CLS_BLOCK, i, mal(i));
-	memmove(die->attr->data, block, i);
-}
-
-// GDB doesn't like DW_FORM_addr for DW_AT_location, so emit a
-// location expression that evals to a const.
-static void
-newabslocexprattr(DWDie *die, vlong addr, LSym *sym)
-{
-	newattr(die, DW_AT_location, DW_CLS_ADDRESS, addr, (char*)sym);
-}
-
-static DWDie* defptrto(DWDie *dwtype);	// below
-
-// Lookup predefined types
-static LSym*
-lookup_or_diag(char *n)
-{
-	LSym *s;
-
-	s = linkrlookup(ctxt, n, 0);
-	if (s == nil || s->size == 0) {
-		diag("dwarf: missing type: %s", n);
-		errorexit();
-	}
-	return s;
-}
-
-static void
-dotypedef(DWDie *parent, char *name, DWDie *def)
-{
-	DWDie *die;
-
-	// Only emit typedefs for real names.
-	if(strncmp(name, "map[", 4) == 0)
-		return;
-	if(strncmp(name, "struct {", 8) == 0)
-		return;
-	if(strncmp(name, "chan ", 5) == 0)
-		return;
-	if(*name == '[' || *name == '*')
-		return;
-	if(def == nil)
-		diag("dwarf: bad def in dotypedef");
-
-	// The typedef entry must be created after the def,
-	// 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);
-	newrefattr(die, DW_AT_type, def);
-}
-
-// Define gotype, for composite ones recurse into constituents.
-static DWDie*
-defgotype(LSym *gotype)
-{
-	DWDie *die, *fld;
-	LSym *s;
-	char *name, *f;
-	uint8 kind;
-	vlong bytesize;
-	int i, nfields;
-
-	if (gotype == nil)
-		return find_or_diag(&dwtypes, "<unspecified>");
-
-	if (strncmp("type.", gotype->name, 5) != 0) {
-		diag("dwarf: type name doesn't start with \".type\": %s", gotype->name);
-		return find_or_diag(&dwtypes, "<unspecified>");
-	}
-	name = gotype->name + 5;  // could also decode from Type.string
-
-	die = find(&dwtypes, name);
-	if (die != nil)
-		return die;
-
-	if (0 && debug['v'] > 2)
-		print("new type: %Y\n", gotype);
-
-	kind = decodetype_kind(gotype);
-	bytesize = decodetype_size(gotype);
-
-	switch (kind) {
-	case KindBool:
-		die = newdie(&dwtypes, DW_ABRV_BASETYPE, name);
-		newattr(die, DW_AT_encoding,  DW_CLS_CONSTANT, DW_ATE_boolean, 0);
-		newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
-		break;
-
-	case KindInt:
-	case KindInt8:
-	case KindInt16:
-	case KindInt32:
-	case KindInt64:
-		die = newdie(&dwtypes, DW_ABRV_BASETYPE, name);
-		newattr(die, DW_AT_encoding,  DW_CLS_CONSTANT, DW_ATE_signed, 0);
-		newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
-		break;
-
-	case KindUint:
-	case KindUint8:
-	case KindUint16:
-	case KindUint32:
-	case KindUint64:
-	case KindUintptr:
-		die = newdie(&dwtypes, DW_ABRV_BASETYPE, name);
-		newattr(die, DW_AT_encoding,  DW_CLS_CONSTANT, DW_ATE_unsigned, 0);
-		newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
-		break;
-
-	case KindFloat32:
-	case KindFloat64:
-		die = newdie(&dwtypes, DW_ABRV_BASETYPE, name);
-		newattr(die, DW_AT_encoding,  DW_CLS_CONSTANT, DW_ATE_float, 0);
-		newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
-		break;
-
-	case KindComplex64:
-	case KindComplex128:
-		die = newdie(&dwtypes, DW_ABRV_BASETYPE, name);
-		newattr(die, DW_AT_encoding,  DW_CLS_CONSTANT, DW_ATE_complex_float, 0);
-		newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
-		break;
-
-	case KindArray:
-		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);
-		newrefattr(die, DW_AT_type, defgotype(s));
-		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);
-		newrefattr(fld, DW_AT_type, find_or_diag(&dwtypes, "uintptr"));
-		break;
-
-	case KindChan:
-		die = newdie(&dwtypes, DW_ABRV_CHANTYPE, name);
-		newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
-		s = decodetype_chanelem(gotype);
-		newrefattr(die, DW_AT_go_elem, defgotype(s));
-		break;
-
-	case 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++) {
-			s = decodetype_funcintype(gotype, i);
-			fld = newdie(die, DW_ABRV_FUNCTYPEPARAM, s->name+5);
-			newrefattr(fld, DW_AT_type, defgotype(s));
-		}
-		if (decodetype_funcdotdotdot(gotype))
-			newdie(die, DW_ABRV_DOTDOTDOT, "...");
-		nfields = decodetype_funcoutcount(gotype);
-		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)));
-		}
-		break;
-
-	case KindInterface:
-		die = newdie(&dwtypes, DW_ABRV_IFACETYPE, name);
-		dotypedef(&dwtypes, name, die);
-		newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
-		nfields = decodetype_ifacemethodcount(gotype);
-		if (nfields == 0)
-			s = lookup_or_diag("type.runtime.eface");
-		else
-			s = lookup_or_diag("type.runtime.iface");
-		newrefattr(die, DW_AT_type, defgotype(s));
-		break;
-
-	case KindMap:
-		die = newdie(&dwtypes, DW_ABRV_MAPTYPE, name);
-		s = decodetype_mapkey(gotype);
-		newrefattr(die, DW_AT_go_key, defgotype(s));
-		s = decodetype_mapvalue(gotype);
-		newrefattr(die, DW_AT_go_elem, defgotype(s));
-		break;
-
-	case KindPtr:
-		die = newdie(&dwtypes, DW_ABRV_PTRTYPE, name);
-		dotypedef(&dwtypes, name, die);
-		s = decodetype_ptrelem(gotype);
-		newrefattr(die, DW_AT_type, defgotype(s));
-		break;
-
-	case 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);
-		newrefattr(die, DW_AT_go_elem, defgotype(s));
-		break;
-
-	case KindString:
-		die = newdie(&dwtypes, DW_ABRV_STRINGTYPE, name);
-		newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0);
-		break;
-
-	case KindStruct:
-		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++) {
-			f = decodetype_structfieldname(gotype, i);
-			s = decodetype_structfieldtype(gotype, i);
-			if (f == nil)
-				f = s->name + 5;	 // skip "type."
-			fld = newdie(die, DW_ABRV_STRUCTFIELD, f);
-			newrefattr(fld, DW_AT_type, defgotype(s));
-			newmemberoffsetattr(fld, decodetype_structfieldoffs(gotype, i));
-		}
-		break;
-
-	case KindUnsafePointer:
-		die = newdie(&dwtypes, DW_ABRV_BARE_PTRTYPE, name);
-		break;
-
-	default:
-		diag("dwarf: definition of unknown kind %d: %s", kind, gotype->name);
-		die = newdie(&dwtypes, DW_ABRV_TYPEDECL, name);
-		newrefattr(die, DW_AT_type, find_or_diag(&dwtypes, "<unspecified>"));
-	}
-
-	newattr(die, DW_AT_go_kind, DW_CLS_CONSTANT, kind, 0);
-
-	return die;
-}
-
-// Find or construct *T given T.
-static DWDie*
-defptrto(DWDie *dwtype)
-{
-	char ptrname[1024];
-	DWDie *die;
-
-	snprint(ptrname, sizeof ptrname, "*%s", getattr(dwtype, DW_AT_name)->data);
-	die = find(&dwtypes, ptrname);
-	if (die == nil) {
-		die = newdie(&dwtypes, DW_ABRV_PTRTYPE,
-			     strcpy(mal(strlen(ptrname)+1), ptrname));
-		newrefattr(die, DW_AT_type, dwtype);
-	}
-	return die;
-}
-
-// Copies src's children into dst. Copies attributes by value.
-// DWAttr.data is copied as pointer only.  If except is one of
-// the top-level children, it will not be copied.
-static void
-copychildrenexcept(DWDie *dst, DWDie *src, DWDie *except)
-{
-	DWDie *c;
-	DWAttr *a;
-
-	for (src = src->child; src != nil; src = src->link) {
-		if(src == except)
-			continue;
-		c = newdie(dst, src->abbrev, getattr(src, DW_AT_name)->data);
-		for (a = src->attr; a != nil; a = a->link)
-			newattr(c, a->atr, a->cls, a->value, a->data);
-		copychildrenexcept(c, src, nil);
-	}
-	reverselist(&dst->child);
-}
-static void
-copychildren(DWDie *dst, DWDie *src)
-{
-	copychildrenexcept(dst, src, nil);
-}
-
-// Search children (assumed to have DW_TAG_member) for the one named
-// field and set its DW_AT_type to dwtype
-static void
-substitutetype(DWDie *structdie, char *field, DWDie* dwtype)
-{
-	DWDie *child;
-	DWAttr *a;
-
-	child = find_or_diag(structdie, field);
-	if (child == nil)
-		return;
-
-	a = getattr(child, DW_AT_type);
-	if (a != nil)
-		a->data = (char*) dwtype;
-	else
-		newrefattr(child, DW_AT_type, dwtype);
-}
-
-static void
-synthesizestringtypes(DWDie* die)
-{
-	DWDie *prototype;
-
-	prototype = walktypedef(defgotype(lookup_or_diag("type.runtime._string")));
-	if (prototype == nil)
-		return;
-
-	for (; die != nil; die = die->link) {
-		if (die->abbrev != DW_ABRV_STRINGTYPE)
-			continue;
-		copychildren(die, prototype);
-	}
-}
-
-static void
-synthesizeslicetypes(DWDie *die)
-{
-	DWDie *prototype, *elem;
-
-	prototype = walktypedef(defgotype(lookup_or_diag("type.runtime.slice")));
-	if (prototype == nil)
-		return;
-
-	for (; die != nil; die = die->link) {
-		if (die->abbrev != DW_ABRV_SLICETYPE)
-			continue;
-		copychildren(die, prototype);
-		elem = (DWDie*) getattr(die, DW_AT_go_elem)->data;
-		substitutetype(die, "array", defptrto(elem));
-	}
-}
-
-static char*
-mkinternaltypename(char *base, char *arg1, char *arg2)
-{
-	char buf[1024];
-	char *n;
-
-	if (arg2 == nil)
-		snprint(buf, sizeof buf, "%s<%s>", base, arg1);
-	else
-		snprint(buf, sizeof buf, "%s<%s,%s>", base, arg1, arg2);
-	n = mal(strlen(buf) + 1);
-	memmove(n, buf, strlen(buf));
-	return n;
-}
-
-// synthesizemaptypes is way too closely married to runtime/hashmap.c
-enum {
-	MaxKeySize = 128,
-	MaxValSize = 128,
-	BucketSize = 8,
-};
-
-static void
-synthesizemaptypes(DWDie *die)
-{
-
-	DWDie *hash, *bucket, *dwh, *dwhk, *dwhv, *dwhb, *keytype, *valtype, *fld;
-	int indirect_key, indirect_val;
-	int keysize, valsize;
-	DWAttr *a;
-
-	hash		= walktypedef(defgotype(lookup_or_diag("type.runtime.hmap")));
-	bucket		= walktypedef(defgotype(lookup_or_diag("type.runtime.bmap")));
-
-	if (hash == nil)
-		return;
-
-	for (; die != nil; die = die->link) {
-		if (die->abbrev != DW_ABRV_MAPTYPE)
-			continue;
-
-		keytype = walktypedef((DWDie*) getattr(die, DW_AT_go_key)->data);
-		valtype = walktypedef((DWDie*) getattr(die, DW_AT_go_elem)->data);
-
-		// compute size info like hashmap.c does.
-		a = getattr(keytype, DW_AT_byte_size);
-		keysize = a ? a->value : PtrSize;  // We don't store size with Pointers
-		a = getattr(valtype, DW_AT_byte_size);
-		valsize = a ? a->value : PtrSize;
-		indirect_key = 0;
-		indirect_val = 0;
-		if(keysize > MaxKeySize) {
-			keysize = PtrSize;
-			indirect_key = 1;
-		}
-		if(valsize > MaxValSize) {
-			valsize = PtrSize;
-			indirect_val = 1;
-		}
-
-		// Construct type to represent an array of BucketSize keys
-		dwhk = newdie(&dwtypes, DW_ABRV_ARRAYTYPE,
-			      mkinternaltypename("[]key",
-						 getattr(keytype, DW_AT_name)->data, nil));
-		newattr(dwhk, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize * keysize, 0);
-		newrefattr(dwhk, DW_AT_type, indirect_key ? defptrto(keytype) : keytype);
-		fld = newdie(dwhk, DW_ABRV_ARRAYRANGE, "size");
-		newattr(fld, DW_AT_count, DW_CLS_CONSTANT, BucketSize, 0);
-		newrefattr(fld, DW_AT_type, find_or_diag(&dwtypes, "uintptr"));
-		
-		// Construct type to represent an array of BucketSize values
-		dwhv = newdie(&dwtypes, DW_ABRV_ARRAYTYPE, 
-			      mkinternaltypename("[]val",
-						 getattr(valtype, DW_AT_name)->data, nil));
-		newattr(dwhv, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize * valsize, 0);
-		newrefattr(dwhv, DW_AT_type, indirect_val ? defptrto(valtype) : valtype);
-		fld = newdie(dwhv, DW_ABRV_ARRAYRANGE, "size");
-		newattr(fld, DW_AT_count, DW_CLS_CONSTANT, BucketSize, 0);
-		newrefattr(fld, DW_AT_type, find_or_diag(&dwtypes, "uintptr"));
-
-		// Construct bucket<K,V>
-		dwhb = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
-			      mkinternaltypename("bucket",
-						 getattr(keytype, DW_AT_name)->data,
-						 getattr(valtype, DW_AT_name)->data));
-		// Copy over all fields except the field "data" from the generic bucket.
-		// "data" will be replaced with keys/values below.
-		copychildrenexcept(dwhb, bucket, find(bucket, "data"));
-		
-		fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "keys");
-		newrefattr(fld, DW_AT_type, dwhk);
-		newmemberoffsetattr(fld, BucketSize);
-		fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "values");
-		newrefattr(fld, DW_AT_type, dwhv);
-		newmemberoffsetattr(fld, BucketSize + BucketSize * keysize);
-		fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "overflow");
-		newrefattr(fld, DW_AT_type, defptrto(dwhb));
-		newmemberoffsetattr(fld, BucketSize + BucketSize * (keysize + valsize));
-		if(RegSize > PtrSize) {
-			fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "pad");
-			newrefattr(fld, DW_AT_type, find_or_diag(&dwtypes, "uintptr"));
-			newmemberoffsetattr(fld, BucketSize + BucketSize * (keysize + valsize) + PtrSize);
-		}
-		newattr(dwhb, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize + BucketSize * keysize + BucketSize * valsize + RegSize, 0);
-
-		// Construct hash<K,V>
-		dwh = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
-			mkinternaltypename("hash",
-				getattr(keytype, DW_AT_name)->data,
-				getattr(valtype, DW_AT_name)->data));
-		copychildren(dwh, hash);
-		substitutetype(dwh, "buckets", defptrto(dwhb));
-		substitutetype(dwh, "oldbuckets", defptrto(dwhb));
-		newattr(dwh, DW_AT_byte_size, DW_CLS_CONSTANT,
-			getattr(hash, DW_AT_byte_size)->value, nil);
-
-		// make map type a pointer to hash<K,V>
-		newrefattr(die, DW_AT_type, defptrto(dwh));
-	}
-}
-
-static void
-synthesizechantypes(DWDie *die)
-{
-	DWDie *sudog, *waitq, *hchan,
-		*dws, *dww, *dwh, *elemtype;
-	DWAttr *a;
-	int elemsize, sudogsize;
-
-	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 = getattr(sudog, DW_AT_byte_size)->value;
-
-	for (; die != nil; die = die->link) {
-		if (die->abbrev != DW_ABRV_CHANTYPE)
-			continue;
-		elemtype = (DWDie*) getattr(die, DW_AT_go_elem)->data;
-		a = getattr(elemtype, DW_AT_byte_size);
-		elemsize = a ? a->value : PtrSize;
-
-		// sudog<T>
-		dws = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
-			mkinternaltypename("sudog",
-				getattr(elemtype, DW_AT_name)->data, nil));
-		copychildren(dws, sudog);
-		substitutetype(dws, "elem", elemtype);
-		newattr(dws, DW_AT_byte_size, DW_CLS_CONSTANT,
-			sudogsize + (elemsize > 8 ? elemsize - 8 : 0), nil);
-
-		// waitq<T>
-		dww = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
-			mkinternaltypename("waitq", getattr(elemtype, DW_AT_name)->data, nil));
-		copychildren(dww, waitq);
-		substitutetype(dww, "first", defptrto(dws));
-		substitutetype(dww, "last",  defptrto(dws));
-		newattr(dww, DW_AT_byte_size, DW_CLS_CONSTANT,
-			getattr(waitq, DW_AT_byte_size)->value, nil);
-
-		// hchan<T>
-		dwh = newdie(&dwtypes, DW_ABRV_STRUCTTYPE,
-			mkinternaltypename("hchan", getattr(elemtype, DW_AT_name)->data, nil));
-		copychildren(dwh, hchan);
-		substitutetype(dwh, "recvq", dww);
-		substitutetype(dwh, "sendq", dww);
-		newattr(dwh, DW_AT_byte_size, DW_CLS_CONSTANT,
-			getattr(hchan, DW_AT_byte_size)->value, nil);
-
-		newrefattr(die, DW_AT_type, defptrto(dwh));
-	}
-}
-
-// For use with pass.c::genasmsym
-static void
-defdwsymb(LSym* sym, char *s, int t, vlong v, vlong size, int ver, LSym *gotype)
-{
-	DWDie *dv, *dt;
-
-	USED(size);
-	if (strncmp(s, "go.string.", 10) == 0)
-		return;
-
-	if (strncmp(s, "type.", 5) == 0 && strcmp(s, "type.*") != 0 && strncmp(s, "type..", 6) != 0) {
-		defgotype(sym);
-		return;
-	}
-
-	dv = nil;
-
-	switch (t) {
-	default:
-		return;
-	case 'd':
-	case 'b':
-	case 'D':
-	case 'B':
-		dv = newdie(&dwglobals, DW_ABRV_VARIABLE, s);
-		newabslocexprattr(dv, v, sym);
-		if (ver == 0)
-			newattr(dv, DW_AT_external, DW_CLS_FLAG, 1, 0);
-		// fallthrough
-	case 'a':
-	case 'p':
-		dt = defgotype(gotype);
-	}
-
-	if (dv != nil)
-		newrefattr(dv, DW_AT_type, dt);
-}
-
-static void
-movetomodule(DWDie *parent)
-{
-	DWDie *die;
-
-	die = dwroot.child->child;
-	while(die->link != nil)
-		die = die->link;
-	die->link = parent->child;
-}
-
-// If the pcln table contains runtime/string.goc, use that to set gdbscript path.
-static void
-finddebugruntimepath(LSym *s)
-{
-	int i;
-	char *p;
-	LSym *f;
-	
-	if(gdbscript[0] != '\0')
-		return;
-
-	for(i=0; i<s->pcln->nfile; i++) {
-		f = s->pcln->file[i];
-		if((p = strstr(f->name, "runtime/string.goc")) != nil) {
-			*p = '\0';
-			snprint(gdbscript, sizeof gdbscript, "%sruntime/runtime-gdb.py", f->name);
-			*p = 'r';
-			break;
-		}
-	}
-}
-
-/*
- * Generate short opcodes when possible, long ones when necessary.
- * See section 6.2.5
- */
-
-enum {
-	LINE_BASE = -1,
-	LINE_RANGE = 4,
-	OPCODE_BASE = 10
-};
-
-static void
-putpclcdelta(vlong delta_pc, vlong delta_lc)
-{
-	if (LINE_BASE <= delta_lc && delta_lc < LINE_BASE+LINE_RANGE) {
-		vlong opcode = OPCODE_BASE + (delta_lc - LINE_BASE) + (LINE_RANGE * delta_pc);
-		if (OPCODE_BASE <= opcode && opcode < 256) {
-			cput(opcode);
-			return;
-		}
-	}
-
-	if (delta_pc) {
-		cput(DW_LNS_advance_pc);
-		sleb128put(delta_pc);
-	}
-
-	cput(DW_LNS_advance_line);
-	sleb128put(delta_lc);
-	cput(DW_LNS_copy);
-}
-
-static void
-newcfaoffsetattr(DWDie *die, int32 offs)
-{
-	char block[10];
-	int i;
-
-	i = 0;
-
-	block[i++] = DW_OP_call_frame_cfa;
-	if (offs != 0) {
-		block[i++] = DW_OP_consts;
-		i += sleb128enc(offs, block+i);
-		block[i++] = DW_OP_plus;
-	}
-	newattr(die, DW_AT_location, DW_CLS_BLOCK, i, mal(i));
-	memmove(die->attr->data, block, i);
-}
-
-static char*
-mkvarname(char* name, int da)
-{
-	char buf[1024];
-	char *n;
-
-	snprint(buf, sizeof buf, "%s#%d", name, da);
-	n = mal(strlen(buf) + 1);
-	memmove(n, buf, strlen(buf));
-	return n;
-}
-
-/*
- * Walk prog table, emit line program and build DIE tree.
- */
-
-// flush previous compilation unit.
-static void
-flushunit(DWDie *dwinfo, vlong pc, LSym *pcsym, vlong unitstart, int32 header_length)
-{
-	vlong here;
-
-	if (dwinfo != nil && pc != 0) {
-		newattr(dwinfo, DW_AT_high_pc, DW_CLS_ADDRESS, pc+1, (char*)pcsym);
-	}
-
-	if (unitstart >= 0) {
-		cput(0);  // start extended opcode
-		uleb128put(1);
-		cput(DW_LNE_end_sequence);
-
-		here = cpos();
-		cseek(unitstart);
-		LPUT(here - unitstart - sizeof(int32));	 // unit_length
-		WPUT(2);  // dwarf version
-		LPUT(header_length); // header length starting here
-		cseek(here);
-	}
-}
-
-static void
-writelines(void)
-{
-	LSym *s, *epcs;
-	Auto *a;
-	vlong unitstart, headerend, offs;
-	vlong pc, epc;
-	int i, lang, da, dt, line, file;
-	DWDie *dwinfo, *dwfunc, *dwvar, **dws;
-	DWDie *varhash[HASHSIZE];
-	char *n, *nn;
-	Pciter pcfile, pcline;
-	LSym **files, *f;
-
-	if(linesec == S)
-		linesec = linklookup(ctxt, ".dwarfline", 0);
-	linesec->nr = 0;
-
-	unitstart = -1;
-	headerend = -1;
-	epc = 0;
-	epcs = S;
-	lineo = cpos();
-	dwinfo = nil;
-	
-	flushunit(dwinfo, epc, epcs, unitstart, headerend - unitstart - 10);
-	unitstart = cpos();
-	
-	lang = DW_LANG_Go;
-	
-	s = ctxt->textp;
-
-	dwinfo = newdie(&dwroot, DW_ABRV_COMPUNIT, estrdup("go"));
-	newattr(dwinfo, DW_AT_language, DW_CLS_CONSTANT,lang, 0);
-	newattr(dwinfo, DW_AT_stmt_list, DW_CLS_PTR, unitstart - lineo, 0);
-	newattr(dwinfo, DW_AT_low_pc, DW_CLS_ADDRESS, s->value, (char*)s);
-
-	// Write .debug_line Line Number Program Header (sec 6.2.4)
-	// Fields marked with (*) must be changed for 64-bit dwarf
-	LPUT(0);   // unit_length (*), will be filled in by flushunit.
-	WPUT(2);   // dwarf version (appendix F)
-	LPUT(0);   // header_length (*), filled in by flushunit.
-	// cpos == unitstart + 4 + 2 + 4
-	cput(1);   // minimum_instruction_length
-	cput(1);   // default_is_stmt
-	cput(LINE_BASE);     // line_base
-	cput(LINE_RANGE);    // line_range
-	cput(OPCODE_BASE);   // opcode_base
-	cput(0);   // standard_opcode_lengths[1]
-	cput(1);   // standard_opcode_lengths[2]
-	cput(1);   // standard_opcode_lengths[3]
-	cput(1);   // standard_opcode_lengths[4]
-	cput(1);   // standard_opcode_lengths[5]
-	cput(0);   // standard_opcode_lengths[6]
-	cput(0);   // standard_opcode_lengths[7]
-	cput(0);   // standard_opcode_lengths[8]
-	cput(1);   // standard_opcode_lengths[9]
-	cput(0);   // include_directories  (empty)
-
-	files = emallocz(ctxt->nhistfile*sizeof files[0]);
-	for(f = ctxt->filesyms; f != nil; f = f->next)
-		files[f->value-1] = f;
-
-	for(i=0; i<ctxt->nhistfile; i++) {
-		strnput(files[i]->name, strlen(files[i]->name) + 4);
-		// 4 zeros: the string termination + 3 fields.
-	}
-
-	cput(0);   // terminate file_names.
-	headerend = cpos();
-
-	cput(0);  // start extended opcode
-	uleb128put(1 + PtrSize);
-	cput(DW_LNE_set_address);
-
-	pc = s->value;
-	line = 1;
-	file = 1;
-	if(linkmode == LinkExternal)
-		adddwarfrel(linesec, s, lineo, PtrSize, 0);
-	else
-		addrput(pc);
-
-	for(ctxt->cursym = ctxt->textp; ctxt->cursym != nil; ctxt->cursym = ctxt->cursym->next) {
-		s = ctxt->cursym;
-
-		dwfunc = newdie(dwinfo, DW_ABRV_FUNCTION, s->name);
-		newattr(dwfunc, DW_AT_low_pc, DW_CLS_ADDRESS, s->value, (char*)s);
-		epc = s->value + s->size;
-		epcs = s;
-		newattr(dwfunc, DW_AT_high_pc, DW_CLS_ADDRESS, epc, (char*)s);
-		if (s->version == 0)
-			newattr(dwfunc, DW_AT_external, DW_CLS_FLAG, 1, 0);
-
-		if(s->pcln == nil)
-			continue;
-
-		finddebugruntimepath(s);
-
-		pciterinit(ctxt, &pcfile, &s->pcln->pcfile);
-		pciterinit(ctxt, &pcline, &s->pcln->pcline);
-		epc = pc;
-		while(!pcfile.done && !pcline.done) {
-			if(epc - s->value >= pcfile.nextpc) {
-				pciternext(&pcfile);
-				continue;
-			}
-			if(epc - s->value >= pcline.nextpc) {
-				pciternext(&pcline);
-				continue;
-			}
-
-			if(file != pcfile.value) {
-				cput(DW_LNS_set_file);
-				uleb128put(pcfile.value);
-				file = pcfile.value;
-			}
-			putpclcdelta(s->value + pcline.pc - pc, pcline.value - line);
-
-			pc = s->value + pcline.pc;
-			line = pcline.value;
-			if(pcfile.nextpc < pcline.nextpc)
-				epc = pcfile.nextpc;
-			else
-				epc = pcline.nextpc;
-			epc += s->value;
-		}
-
-		da = 0;
-		dwfunc->hash = varhash;	 // enable indexing of children by name
-		memset(varhash, 0, sizeof varhash);
-		for(a = s->autom; a; a = a->link) {
-			switch (a->type) {
-			case A_AUTO:
-				dt = DW_ABRV_AUTO;
-				offs = a->aoffset - PtrSize;
-				break;
-			case A_PARAM:
-				dt = DW_ABRV_PARAM;
-				offs = a->aoffset;
-				break;
-			default:
-				continue;
-			}
-			if (strstr(a->asym->name, ".autotmp_"))
-				continue;
-			if (find(dwfunc, a->asym->name) != nil)
-				n = mkvarname(a->asym->name, da);
-			else
-				n = a->asym->name;
-			// Drop the package prefix from locals and arguments.
-			nn = strrchr(n, '.');
-			if (nn)
-				n = nn + 1;
-
-			dwvar = newdie(dwfunc, dt, n);
-			newcfaoffsetattr(dwvar, offs);
-			newrefattr(dwvar, DW_AT_type, defgotype(a->gotype));
-
-			// push dwvar down dwfunc->child to preserve order
-			newattr(dwvar, DW_AT_internal_location, DW_CLS_CONSTANT, offs, nil);
-			dwfunc->child = dwvar->link;  // take dwvar out from the top of the list
-			for (dws = &dwfunc->child; *dws != nil; dws = &(*dws)->link)
-				if (offs > getattr(*dws, DW_AT_internal_location)->value)
-					break;
-			dwvar->link = *dws;
-			*dws = dwvar;
-
-			da++;
-		}
-
-		dwfunc->hash = nil;
-	}
-
-	flushunit(dwinfo, epc, epcs, unitstart, headerend - unitstart - 10);
-	linesize = cpos() - lineo;
-}
-
-/*
- *  Emit .debug_frame
- */
-enum
-{
-	CIERESERVE = 16,
-	DATAALIGNMENTFACTOR = -4,	// TODO -PtrSize?
-	FAKERETURNCOLUMN = 16		// TODO gdb6 doesn't like > 15?
-};
-
-static void
-putpccfadelta(vlong deltapc, vlong cfa)
-{
-	cput(DW_CFA_def_cfa_offset_sf);
-	sleb128put(cfa / DATAALIGNMENTFACTOR);
-
-	if (deltapc < 0x40) {
-		cput(DW_CFA_advance_loc + deltapc);
-	} else if (deltapc < 0x100) {
-		cput(DW_CFA_advance_loc1);
-		cput(deltapc);
-	} else if (deltapc < 0x10000) {
-		cput(DW_CFA_advance_loc2);
-		WPUT(deltapc);
-	} else {
-		cput(DW_CFA_advance_loc4);
-		LPUT(deltapc);
-	}
-}
-
-static void
-writeframes(void)
-{
-	LSym *s;
-	vlong fdeo, fdesize, pad;
-	Pciter pcsp;
-	uint32 nextpc;
-
-	if(framesec == S)
-		framesec = linklookup(ctxt, ".dwarfframe", 0);
-	framesec->nr = 0;
-	frameo = cpos();
-
-	// Emit the CIE, Section 6.4.1
-	LPUT(CIERESERVE);	// initial length, must be multiple of PtrSize
-	LPUT(0xffffffff);	// cid.
-	cput(3);		// dwarf version (appendix F)
-	cput(0);		// augmentation ""
-	uleb128put(1);		// code_alignment_factor
-	sleb128put(DATAALIGNMENTFACTOR); // guess
-	uleb128put(FAKERETURNCOLUMN);	// return_address_register
-
-	cput(DW_CFA_def_cfa);
-	uleb128put(DWARFREGSP);	// register SP (**ABI-dependent, defined in l.h)
-	uleb128put(PtrSize);	// offset
-
-	cput(DW_CFA_offset + FAKERETURNCOLUMN);	 // return address
-	uleb128put(-PtrSize / DATAALIGNMENTFACTOR);  // at cfa - x*4
-
-	// 4 is to exclude the length field.
-	pad = CIERESERVE + frameo + 4 - cpos();
-	if (pad < 0) {
-		diag("dwarf: CIERESERVE too small by %lld bytes.", -pad);
-		errorexit();
-	}
-	strnput("", pad);
-
-	for(ctxt->cursym = ctxt->textp; ctxt->cursym != nil; ctxt->cursym = ctxt->cursym->next) {
-		s = ctxt->cursym;
-		if(s->pcln == nil)
-			continue;
-
-		fdeo = cpos();
-		// Emit a FDE, Section 6.4.1, starting wit a placeholder.
-		LPUT(0);	// length, must be multiple of PtrSize
-		LPUT(0);	// Pointer to the CIE above, at offset 0
-		addrput(0);	// initial location
-		addrput(0);	// address range
-
-		for(pciterinit(ctxt, &pcsp, &s->pcln->pcsp); !pcsp.done; pciternext(&pcsp)) {
-			nextpc = pcsp.nextpc;
-			// pciterinit goes up to the end of the function,
-			// but DWARF expects us to stop just before the end.
-			if(nextpc == s->size) {
-				nextpc--;
-				if(nextpc < pcsp.pc)
-					continue;
-			}
-			putpccfadelta(nextpc - pcsp.pc, PtrSize + pcsp.value);
-		}
-
-		fdesize = cpos() - fdeo - 4;	// exclude the length field.
-		pad = rnd(fdesize, PtrSize) - fdesize;
-		strnput("", pad);
-		fdesize += pad;
-
-		// Emit the FDE header for real, Section 6.4.1.
-		cseek(fdeo);
-		LPUT(fdesize);
-		if(linkmode == LinkExternal) {
-			adddwarfrel(framesec, framesym, frameo, 4, 0);
-			adddwarfrel(framesec, s, frameo, PtrSize, 0);
-		}
-		else {
-			LPUT(0);
-			addrput(s->value);
-		}
-		addrput(s->size);
-		cseek(fdeo + 4 + fdesize);
-	}
-
-	cflush();
-	framesize = cpos() - frameo;
-}
-
-/*
- *  Walk DWarfDebugInfoEntries, and emit .debug_info
- */
-enum
-{
-	COMPUNITHEADERSIZE = 4+2+4+1
-};
-
-static void
-writeinfo(void)
-{
-	DWDie *compunit;
-	vlong unitstart, here;
-
-	fwdcount = 0;
-	if (infosec == S)
-		infosec = linklookup(ctxt, ".dwarfinfo", 0);
-	infosec->nr = 0;
-
-	if(arangessec == S)
-		arangessec = linklookup(ctxt, ".dwarfaranges", 0);
-	arangessec->nr = 0;
-
-	for (compunit = dwroot.child; compunit; compunit = compunit->link) {
-		unitstart = cpos();
-
-		// Write .debug_info Compilation Unit Header (sec 7.5.1)
-		// Fields marked with (*) must be changed for 64-bit dwarf
-		// This must match COMPUNITHEADERSIZE above.
-		LPUT(0);	// unit_length (*), will be filled in later.
-		WPUT(2);	// dwarf version (appendix F)
-
-		// debug_abbrev_offset (*)
-		if(linkmode == LinkExternal)
-			adddwarfrel(infosec, abbrevsym, infoo, 4, 0);
-		else
-			LPUT(0);
-
-		cput(PtrSize);	// address_size
-
-		putdie(compunit);
-
-		here = cpos();
-		cseek(unitstart);
-		LPUT(here - unitstart - 4);	// exclude the length field.
-		cseek(here);
-	}
-	cflush();
-}
-
-/*
- *  Emit .debug_pubnames/_types.  _info must have been written before,
- *  because we need die->offs and infoo/infosize;
- */
-static int
-ispubname(DWDie *die)
-{
-	DWAttr *a;
-
-	switch(die->abbrev) {
-	case DW_ABRV_FUNCTION:
-	case DW_ABRV_VARIABLE:
-		a = getattr(die, DW_AT_external);
-		return a && a->value;
-	}
-	return 0;
-}
-
-static int
-ispubtype(DWDie *die)
-{
-	return die->abbrev >= DW_ABRV_NULLTYPE;
-}
-
-static vlong
-writepub(int (*ispub)(DWDie*))
-{
-	DWDie *compunit, *die;
-	DWAttr *dwa;
-	vlong unitstart, unitend, sectionstart, here;
-
-	sectionstart = cpos();
-
-	for (compunit = dwroot.child; compunit != nil; compunit = compunit->link) {
-		unitstart = compunit->offs - COMPUNITHEADERSIZE;
-		if (compunit->link != nil)
-			unitend = compunit->link->offs - COMPUNITHEADERSIZE;
-		else
-			unitend = infoo + infosize;
-
-		// Write .debug_pubnames/types	Header (sec 6.1.1)
-		LPUT(0);			// unit_length (*), will be filled in later.
-		WPUT(2);			// dwarf version (appendix F)
-		LPUT(unitstart);		// debug_info_offset (of the Comp unit Header)
-		LPUT(unitend - unitstart);	// debug_info_length
-
-		for (die = compunit->child; die != nil; die = die->link) {
-			if (!ispub(die)) continue;
-			LPUT(die->offs - unitstart);
-			dwa = getattr(die, DW_AT_name);
-			strnput(dwa->data, dwa->value + 1);
-		}
-		LPUT(0);
-
-		here = cpos();
-		cseek(sectionstart);
-		LPUT(here - sectionstart - 4);	// exclude the length field.
-		cseek(here);
-
-	}
-
-	return sectionstart;
-}
-
-/*
- *  emit .debug_aranges.  _info must have been written before,
- *  because we need die->offs of dw_globals.
- */
-static vlong
-writearanges(void)
-{
-	DWDie *compunit;
-	DWAttr *b, *e;
-	int headersize;
-	vlong sectionstart;
-	vlong value;
-
-	sectionstart = cpos();
-	headersize = rnd(4+2+4+1+1, PtrSize);  // don't count unit_length field itself
-
-	for (compunit = dwroot.child; compunit != nil; compunit = compunit->link) {
-		b = getattr(compunit,  DW_AT_low_pc);
-		if (b == nil)
-			continue;
-		e = getattr(compunit,  DW_AT_high_pc);
-		if (e == nil)
-			continue;
-
-		// Write .debug_aranges	 Header + entry	 (sec 6.1.2)
-		LPUT(headersize + 4*PtrSize - 4);	// unit_length (*)
-		WPUT(2);	// dwarf version (appendix F)
-
-		value = compunit->offs - COMPUNITHEADERSIZE;	// debug_info_offset
-		if(linkmode == LinkExternal)
-			adddwarfrel(arangessec, infosym, sectionstart, 4, value);
-		else
-			LPUT(value);
-
-		cput(PtrSize);	// address_size
-		cput(0);	// segment_size
-		strnput("", headersize - (4+2+4+1+1));	// align to PtrSize
-
-		if(linkmode == LinkExternal)
-			adddwarfrel(arangessec, (LSym*)b->data, sectionstart, PtrSize, b->value-((LSym*)b->data)->value);
-		else
-			addrput(b->value);
-
-		addrput(e->value - b->value);
-		addrput(0);
-		addrput(0);
-	}
-	cflush();
-	return sectionstart;
-}
-
-static vlong
-writegdbscript(void)
-{
-	vlong sectionstart;
-
-	sectionstart = cpos();
-
-	if (gdbscript[0]) {
-		cput(1);  // magic 1 byte?
-		strnput(gdbscript, strlen(gdbscript)+1);
-		cflush();
-	}
-	return sectionstart;
-}
-
-static void
-align(vlong size)
-{
-	if(HEADTYPE == Hwindows) // Only Windows PE need section align.
-		strnput("", rnd(size, PEFILEALIGN) - size);
-}
-
-static vlong
-writedwarfreloc(LSym* s)
-{
-	int i;
-	vlong start;
-	Reloc *r;
-	
-	start = cpos();
-	for(r = s->r; r < s->r+s->nr; r++) {
-		if(iself)
-			i = elfreloc1(r, r->off);
-		else if(HEADTYPE == Hdarwin)
-			i = machoreloc1(r, r->off);
-		else
-			i = -1;
-		if(i < 0)
-			diag("unsupported obj reloc %d/%d to %s", r->type, r->siz, r->sym->name);
-	}
-	return start;
-}
-
-/*
- * This is the main entry point for generating dwarf.  After emitting
- * the mandatory debug_abbrev section, it calls writelines() to set up
- * the per-compilation unit part of the DIE tree, while simultaneously
- * emitting the debug_line section.  When the final tree contains
- * forward references, it will write the debug_info section in 2
- * passes.
- *
- */
-void
-dwarfemitdebugsections(void)
-{
-	vlong infoe;
-	DWDie* die;
-
-	if(debug['w'])  // disable dwarf
-		return;
-
-	if(linkmode == LinkExternal && !iself)
-		return;
-
-	// For diagnostic messages.
-	newattr(&dwtypes, DW_AT_name, DW_CLS_STRING, strlen("dwtypes"), "dwtypes");
-
-	mkindex(&dwroot);
-	mkindex(&dwtypes);
-	mkindex(&dwglobals);
-
-	// Some types that must exist to define other ones.
-	newdie(&dwtypes, DW_ABRV_NULLTYPE, "<unspecified>");
-	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
-	newattr(die, DW_AT_encoding,  DW_CLS_CONSTANT, DW_ATE_unsigned, 0);
-	newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, PtrSize, 0);
-	newattr(die, DW_AT_go_kind, DW_CLS_CONSTANT, KindUintptr, 0);
-
-	// Needed by the prettyprinter code for interface inspection.
-	defgotype(lookup_or_diag("type.runtime._type"));
-	defgotype(lookup_or_diag("type.runtime.interfacetype"));
-	defgotype(lookup_or_diag("type.runtime.itab"));
-
-	genasmsym(defdwsymb);
-
-	writeabbrev();
-	align(abbrevsize);
-	writelines();
-	align(linesize);
-	writeframes();
-	align(framesize);
-
-	synthesizestringtypes(dwtypes.child);
-	synthesizeslicetypes(dwtypes.child);
-	synthesizemaptypes(dwtypes.child);
-	synthesizechantypes(dwtypes.child);
-
-	reversetree(&dwroot.child);
-	reversetree(&dwtypes.child);
-	reversetree(&dwglobals.child);
-
-	movetomodule(&dwtypes);
-	movetomodule(&dwglobals);
-
-	infoo = cpos();
-	writeinfo();
-	infoe = cpos();
-	pubnameso = infoe;
-	pubtypeso = infoe;
-	arangeso = infoe;
-	gdbscripto = infoe;
-
-	if (fwdcount > 0) {
-		if (debug['v'])
-			Bprint(&bso, "%5.2f dwarf pass 2.\n", cputime());
-		cseek(infoo);
-		writeinfo();
-		if (fwdcount > 0) {
-			diag("dwarf: unresolved references after first dwarf info pass");
-			errorexit();
-		}
-		if (infoe != cpos()) {
-			diag("dwarf: inconsistent second dwarf info pass");
-			errorexit();
-		}
-	}
-	infosize = infoe - infoo;
-	align(infosize);
-
-	pubnameso  = writepub(ispubname);
-	pubnamessize  = cpos() - pubnameso;
-	align(pubnamessize);
-
-	pubtypeso  = writepub(ispubtype);
-	pubtypessize  = cpos() - pubtypeso;
-	align(pubtypessize);
-
-	arangeso   = writearanges();
-	arangessize   = cpos() - arangeso;
-	align(arangessize);
-
-	gdbscripto = writegdbscript();
-	gdbscriptsize = cpos() - gdbscripto;
-	align(gdbscriptsize);
-
-	while(cpos()&7)
-		cput(0);
-	inforeloco = writedwarfreloc(infosec);
-	inforelocsize = cpos() - inforeloco;
-	align(inforelocsize);
-
-	arangesreloco = writedwarfreloc(arangessec);
-	arangesrelocsize = cpos() - arangesreloco;
-	align(arangesrelocsize);
-
-	linereloco = writedwarfreloc(linesec);
-	linerelocsize = cpos() - linereloco;
-	align(linerelocsize);
-
-	framereloco = writedwarfreloc(framesec);
-	framerelocsize = cpos() - framereloco;
-	align(framerelocsize);
-}
-
-/*
- *  Elf.
- */
-enum
-{
-	ElfStrDebugAbbrev,
-	ElfStrDebugAranges,
-	ElfStrDebugFrame,
-	ElfStrDebugInfo,
-	ElfStrDebugLine,
-	ElfStrDebugLoc,
-	ElfStrDebugMacinfo,
-	ElfStrDebugPubNames,
-	ElfStrDebugPubTypes,
-	ElfStrDebugRanges,
-	ElfStrDebugStr,
-	ElfStrGDBScripts,
-	ElfStrRelDebugInfo,
-	ElfStrRelDebugAranges,
-	ElfStrRelDebugLine,
-	ElfStrRelDebugFrame,
-	NElfStrDbg
-};
-
-vlong elfstrdbg[NElfStrDbg];
-
-void
-dwarfaddshstrings(LSym *shstrtab)
-{
-	if(debug['w'])  // disable dwarf
-		return;
-
-	elfstrdbg[ElfStrDebugAbbrev]   = addstring(shstrtab, ".debug_abbrev");
-	elfstrdbg[ElfStrDebugAranges]  = addstring(shstrtab, ".debug_aranges");
-	elfstrdbg[ElfStrDebugFrame]    = addstring(shstrtab, ".debug_frame");
-	elfstrdbg[ElfStrDebugInfo]     = addstring(shstrtab, ".debug_info");
-	elfstrdbg[ElfStrDebugLine]     = addstring(shstrtab, ".debug_line");
-	elfstrdbg[ElfStrDebugLoc]      = addstring(shstrtab, ".debug_loc");
-	elfstrdbg[ElfStrDebugMacinfo]  = addstring(shstrtab, ".debug_macinfo");
-	elfstrdbg[ElfStrDebugPubNames] = addstring(shstrtab, ".debug_pubnames");
-	elfstrdbg[ElfStrDebugPubTypes] = addstring(shstrtab, ".debug_pubtypes");
-	elfstrdbg[ElfStrDebugRanges]   = addstring(shstrtab, ".debug_ranges");
-	elfstrdbg[ElfStrDebugStr]      = addstring(shstrtab, ".debug_str");
-	elfstrdbg[ElfStrGDBScripts]    = addstring(shstrtab, ".debug_gdb_scripts");
-	if(linkmode == LinkExternal) {
-		if(thechar == '6') {
-			elfstrdbg[ElfStrRelDebugInfo] = addstring(shstrtab, ".rela.debug_info");
-			elfstrdbg[ElfStrRelDebugAranges] = addstring(shstrtab, ".rela.debug_aranges");
-			elfstrdbg[ElfStrRelDebugLine] = addstring(shstrtab, ".rela.debug_line");
-			elfstrdbg[ElfStrRelDebugFrame] = addstring(shstrtab, ".rela.debug_frame");
-		} else {
-			elfstrdbg[ElfStrRelDebugInfo] = addstring(shstrtab, ".rel.debug_info");
-			elfstrdbg[ElfStrRelDebugAranges] = addstring(shstrtab, ".rel.debug_aranges");
-			elfstrdbg[ElfStrRelDebugLine] = addstring(shstrtab, ".rel.debug_line");
-			elfstrdbg[ElfStrRelDebugFrame] = addstring(shstrtab, ".rel.debug_frame");
-		}
-
-		infosym = linklookup(ctxt, ".debug_info", 0);
-		infosym->hide = 1;
-
-		abbrevsym = linklookup(ctxt, ".debug_abbrev", 0);
-		abbrevsym->hide = 1;
-
-		linesym = linklookup(ctxt, ".debug_line", 0);
-		linesym->hide = 1;
-
-		framesym = linklookup(ctxt, ".debug_frame", 0);
-		framesym->hide = 1;
-	}
-}
-
-// Add section symbols for DWARF debug info.  This is called before
-// dwarfaddelfheaders.
-void
-dwarfaddelfsectionsyms()
-{
-	if(infosym != nil) {
-		infosympos = cpos();
-		putelfsectionsym(infosym, 0);
-	}
-	if(abbrevsym != nil) {
-		abbrevsympos = cpos();
-		putelfsectionsym(abbrevsym, 0);
-	}
-	if(linesym != nil) {
-		linesympos = cpos();
-		putelfsectionsym(linesym, 0);
-	}
-	if(framesym != nil) {
-		framesympos = cpos();
-		putelfsectionsym(framesym, 0);
-	}
-}
-
-static void
-dwarfaddelfrelocheader(int elfstr, ElfShdr *shdata, vlong off, vlong size)
-{
-	ElfShdr *sh;
-
-	sh = newElfShdr(elfstrdbg[elfstr]);
-	if(thechar == '6') {
-		sh->type = SHT_RELA;
-	} else {
-		sh->type = SHT_REL;
-	}
-	sh->entsize = PtrSize*(2+(sh->type==SHT_RELA));
-	sh->link = elfshname(".symtab")->shnum;
-	sh->info = shdata->shnum;
-	sh->off = off;
-	sh->size = size;
-	sh->addralign = PtrSize;
-	
-}
-
-void
-dwarfaddelfheaders(void)
-{
-	ElfShdr *sh, *shinfo, *sharanges, *shline, *shframe;
-
-	if(debug['w'])  // disable dwarf
-		return;
-
-	sh = newElfShdr(elfstrdbg[ElfStrDebugAbbrev]);
-	sh->type = SHT_PROGBITS;
-	sh->off = abbrevo;
-	sh->size = abbrevsize;
-	sh->addralign = 1;
-	if(abbrevsympos > 0)
-		putelfsymshndx(abbrevsympos, sh->shnum);
-
-	sh = newElfShdr(elfstrdbg[ElfStrDebugLine]);
-	sh->type = SHT_PROGBITS;
-	sh->off = lineo;
-	sh->size = linesize;
-	sh->addralign = 1;
-	if(linesympos > 0)
-		putelfsymshndx(linesympos, sh->shnum);
-	shline = sh;
-
-	sh = newElfShdr(elfstrdbg[ElfStrDebugFrame]);
-	sh->type = SHT_PROGBITS;
-	sh->off = frameo;
-	sh->size = framesize;
-	sh->addralign = 1;
-	if(framesympos > 0)
-		putelfsymshndx(framesympos, sh->shnum);
-	shframe = sh;
-
-	sh = newElfShdr(elfstrdbg[ElfStrDebugInfo]);
-	sh->type = SHT_PROGBITS;
-	sh->off = infoo;
-	sh->size = infosize;
-	sh->addralign = 1;
-	if(infosympos > 0)
-		putelfsymshndx(infosympos, sh->shnum);
-	shinfo = sh;
-
-	if (pubnamessize > 0) {
-		sh = newElfShdr(elfstrdbg[ElfStrDebugPubNames]);
-		sh->type = SHT_PROGBITS;
-		sh->off = pubnameso;
-		sh->size = pubnamessize;
-		sh->addralign = 1;
-	}
-
-	if (pubtypessize > 0) {
-		sh = newElfShdr(elfstrdbg[ElfStrDebugPubTypes]);
-		sh->type = SHT_PROGBITS;
-		sh->off = pubtypeso;
-		sh->size = pubtypessize;
-		sh->addralign = 1;
-	}
-
-	sharanges = nil;
-	if (arangessize) {
-		sh = newElfShdr(elfstrdbg[ElfStrDebugAranges]);
-		sh->type = SHT_PROGBITS;
-		sh->off = arangeso;
-		sh->size = arangessize;
-		sh->addralign = 1;
-		sharanges = sh;
-	}
-
-	if (gdbscriptsize) {
-		sh = newElfShdr(elfstrdbg[ElfStrGDBScripts]);
-		sh->type = SHT_PROGBITS;
-		sh->off = gdbscripto;
-		sh->size = gdbscriptsize;
-		sh->addralign = 1;
-	}
-
-	if(inforelocsize)
-		dwarfaddelfrelocheader(ElfStrRelDebugInfo, shinfo, inforeloco, inforelocsize);
-
-	if(arangesrelocsize)
-		dwarfaddelfrelocheader(ElfStrRelDebugAranges, sharanges, arangesreloco, arangesrelocsize);
-
-	if(linerelocsize)
-		dwarfaddelfrelocheader(ElfStrRelDebugLine, shline, linereloco, linerelocsize);
-
-	if(framerelocsize)
-		dwarfaddelfrelocheader(ElfStrRelDebugFrame, shframe, framereloco, framerelocsize);
-}
-
-/*
- * Macho
- */
-void
-dwarfaddmachoheaders(void)
-{
-	MachoSect *msect;
-	MachoSeg *ms;
-	vlong fakestart;
-	int nsect;
-
-	if(debug['w'])  // 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;
-
-	nsect = 4;
-	if (pubnamessize  > 0)
-		nsect++;
-	if (pubtypessize  > 0)
-		nsect++;
-	if (arangessize	  > 0)
-		nsect++;
-	if (gdbscriptsize > 0)
-		nsect++;
-
-	ms = newMachoSeg("__DWARF", nsect);
-	ms->fileoffset = fakestart;
-	ms->filesize = abbrevo-fakestart;
-	ms->vaddr = ms->fileoffset + segdata.vaddr - segdata.fileoff;
-
-	msect = newMachoSect(ms, "__debug_abbrev", "__DWARF");
-	msect->off = abbrevo;
-	msect->size = abbrevsize;
-	msect->addr = msect->off + segdata.vaddr - segdata.fileoff;
-	ms->filesize += msect->size;
-
-	msect = newMachoSect(ms, "__debug_line", "__DWARF");
-	msect->off = lineo;
-	msect->size = linesize;
-	msect->addr = msect->off + segdata.vaddr - segdata.fileoff;
-	ms->filesize += msect->size;
-
-	msect = newMachoSect(ms, "__debug_frame", "__DWARF");
-	msect->off = frameo;
-	msect->size = framesize;
-	msect->addr = msect->off + segdata.vaddr - segdata.fileoff;
-	ms->filesize += msect->size;
-
-	msect = newMachoSect(ms, "__debug_info", "__DWARF");
-	msect->off = infoo;
-	msect->size = infosize;
-	msect->addr = msect->off + segdata.vaddr - segdata.fileoff;
-	ms->filesize += msect->size;
-
-	if (pubnamessize > 0) {
-		msect = newMachoSect(ms, "__debug_pubnames", "__DWARF");
-		msect->off = pubnameso;
-		msect->size = pubnamessize;
-		msect->addr = msect->off + segdata.vaddr - segdata.fileoff;
-		ms->filesize += msect->size;
-	}
-
-	if (pubtypessize > 0) {
-		msect = newMachoSect(ms, "__debug_pubtypes", "__DWARF");
-		msect->off = pubtypeso;
-		msect->size = pubtypessize;
-		msect->addr = msect->off + segdata.vaddr - segdata.fileoff;
-		ms->filesize += msect->size;
-	}
-
-	if (arangessize > 0) {
-		msect = newMachoSect(ms, "__debug_aranges", "__DWARF");
-		msect->off = arangeso;
-		msect->size = arangessize;
-		msect->addr = msect->off + segdata.vaddr - segdata.fileoff;
-		ms->filesize += msect->size;
-	}
-
-	// TODO(lvd) fix gdb/python to load MachO (16 char section name limit)
-	if (gdbscriptsize > 0) {
-		msect = newMachoSect(ms, "__debug_gdb_scripts", "__DWARF");
-		msect->off = gdbscripto;
-		msect->size = gdbscriptsize;
-		msect->addr = msect->off + segdata.vaddr - segdata.fileoff;
-		ms->filesize += msect->size;
-	}
-}
-
-/*
- * Windows PE
- */
-void
-dwarfaddpeheaders(void)
-{
-	if(debug['w'])  // disable dwarf
-		return;
-
-	newPEDWARFSection(".debug_abbrev", abbrevsize);
-	newPEDWARFSection(".debug_line", linesize);
-	newPEDWARFSection(".debug_frame", framesize);
-	newPEDWARFSection(".debug_info", infosize);
-	newPEDWARFSection(".debug_pubnames", pubnamessize);
-	newPEDWARFSection(".debug_pubtypes", pubtypessize);
-	newPEDWARFSection(".debug_aranges", arangessize);
-	newPEDWARFSection(".debug_gdb_scripts", gdbscriptsize);
-}
diff --git a/src/cmd/ld/dwarf.h b/src/cmd/ld/dwarf.h
deleted file mode 100644
index 32db36d..0000000
--- a/src/cmd/ld/dwarf.h
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2010 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.
-
-/*
- * Emit debug_abbrevs, debug_info and debug_line sections to current
- * offset in cout.
- */
-void dwarfemitdebugsections(void);
-
-/*
- * Add the dwarf section names to the ELF
- * s[ection]h[eader]str[ing]tab.  Prerequisite for
- * dwarfaddelfheaders().
- */
-void dwarfaddshstrings(LSym *shstrtab);
-
-/*
- * Add section headers pointing to the sections emitted in
- * dwarfemitdebugsections.
- */
-void dwarfaddelfheaders(void);
-void dwarfaddmachoheaders(void);
-void dwarfaddpeheaders(void);
diff --git a/src/cmd/ld/dwarf_defs.h b/src/cmd/ld/dwarf_defs.h
deleted file mode 100644
index 93e99ff..0000000
--- a/src/cmd/ld/dwarf_defs.h
+++ /dev/null
@@ -1,504 +0,0 @@
-// Copyright 2010 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.
-
-// Cut, pasted, tr-and-awk'ed from tables in
-// http://dwarfstd.org/doc/Dwarf3.pdf
-
-// Table 18
-enum
-{
-	DW_TAG_array_type = 0x01,
-	DW_TAG_class_type = 0x02,
-	DW_TAG_entry_point = 0x03,
-	DW_TAG_enumeration_type = 0x04,
-	DW_TAG_formal_parameter = 0x05,
-	DW_TAG_imported_declaration = 0x08,
-	DW_TAG_label = 0x0a,
-	DW_TAG_lexical_block = 0x0b,
-	DW_TAG_member = 0x0d,
-	DW_TAG_pointer_type = 0x0f,
-	DW_TAG_reference_type = 0x10,
-	DW_TAG_compile_unit = 0x11,
-	DW_TAG_string_type = 0x12,
-	DW_TAG_structure_type = 0x13,
-	DW_TAG_subroutine_type = 0x15,
-	DW_TAG_typedef = 0x16,
-	DW_TAG_union_type = 0x17,
-	DW_TAG_unspecified_parameters = 0x18,
-	DW_TAG_variant = 0x19,
-	DW_TAG_common_block = 0x1a,
-	DW_TAG_common_inclusion = 0x1b,
-	DW_TAG_inheritance = 0x1c,
-	DW_TAG_inlined_subroutine = 0x1d,
-	DW_TAG_module = 0x1e,
-	DW_TAG_ptr_to_member_type = 0x1f,
-	DW_TAG_set_type = 0x20,
-	DW_TAG_subrange_type = 0x21,
-	DW_TAG_with_stmt = 0x22,
-	DW_TAG_access_declaration = 0x23,
-	DW_TAG_base_type = 0x24,
-	DW_TAG_catch_block = 0x25,
-	DW_TAG_const_type = 0x26,
-	DW_TAG_constant = 0x27,
-	DW_TAG_enumerator = 0x28,
-	DW_TAG_file_type = 0x29,
-	DW_TAG_friend = 0x2a,
-	DW_TAG_namelist = 0x2b,
-	DW_TAG_namelist_item = 0x2c,
-	DW_TAG_packed_type = 0x2d,
-	DW_TAG_subprogram = 0x2e,
-	DW_TAG_template_type_parameter = 0x2f,
-	DW_TAG_template_value_parameter = 0x30,
-	DW_TAG_thrown_type = 0x31,
-	DW_TAG_try_block = 0x32,
-	DW_TAG_variant_part = 0x33,
-	DW_TAG_variable = 0x34,
-	DW_TAG_volatile_type = 0x35,
-	// 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
-enum
-{
-	DW_CHILDREN_no = 0x00,
-	DW_CHILDREN_yes = 0x01,
-};
-
-// Not from the spec, but logicaly belongs here
-enum
-{
-	DW_CLS_ADDRESS = 0x01,
-	DW_CLS_BLOCK,
-	DW_CLS_CONSTANT,
-	DW_CLS_FLAG,
-	DW_CLS_PTR,	// lineptr, loclistptr, macptr, rangelistptr
-	DW_CLS_REFERENCE,
-	DW_CLS_ADDRLOC,
-	DW_CLS_STRING
-};
-
-// Table 20
-enum
-{
-	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
-enum
-{
-	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)
-enum
-{
-	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,
-};
-
-// Table 25
-enum
-{
-	DW_ATE_address = 0x01,
-	DW_ATE_boolean = 0x02,
-	DW_ATE_complex_float = 0x03,
-	DW_ATE_float = 0x04,
-	DW_ATE_signed = 0x05,
-	DW_ATE_signed_char = 0x06,
-	DW_ATE_unsigned = 0x07,
-	DW_ATE_unsigned_char = 0x08,
-	DW_ATE_imaginary_float = 0x09,
-	DW_ATE_packed_decimal = 0x0a,
-	DW_ATE_numeric_string = 0x0b,
-	DW_ATE_edited = 0x0c,
-	DW_ATE_signed_fixed = 0x0d,
-	DW_ATE_unsigned_fixed = 0x0e,
-	DW_ATE_decimal_float = 0x0f,
-	DW_ATE_lo_user = 0x80,
-	DW_ATE_hi_user = 0xff,
-};
-
-// Table 26
-enum
-{
-	DW_DS_unsigned = 0x01,
-	DW_DS_leading_overpunch = 0x02,
-	DW_DS_trailing_overpunch = 0x03,
-	DW_DS_leading_separate = 0x04,
-	DW_DS_trailing_separate = 0x05,
-};
-
-// Table 27
-enum
-{
-	DW_END_default = 0x00,
-	DW_END_big = 0x01,
-	DW_END_little = 0x02,
-	DW_END_lo_user = 0x40,
-	DW_END_hi_user = 0xff,
-};
-
-// Table 28
-enum
-{
-	DW_ACCESS_public = 0x01,
-	DW_ACCESS_protected = 0x02,
-	DW_ACCESS_private = 0x03,
-};
-
-// Table 29
-enum
-{
-	DW_VIS_local = 0x01,
-	DW_VIS_exported = 0x02,
-	DW_VIS_qualified = 0x03,
-};
-
-// Table 30
-enum
-{
-	DW_VIRTUALITY_none = 0x00,
-	DW_VIRTUALITY_virtual = 0x01,
-	DW_VIRTUALITY_pure_virtual = 0x02,
-};
-
-// Table 31
-enum
-{
-	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,
-	DW_LANG_Fortran95 = 0x000e,
-	DW_LANG_PLI = 0x000f,
-	DW_LANG_ObjC = 0x0010,
-	DW_LANG_ObjC_plus_plus = 0x0011,
-	DW_LANG_UPC = 0x0012,
-	DW_LANG_D = 0x0013,
-	// Dwarf4
-	DW_LANG_Python = 0x0014,
-	// Dwarf5
-	DW_LANG_Go = 0x0016,
-
-	DW_LANG_lo_user = 0x8000,
-	DW_LANG_hi_user = 0xffff,
-};
-
-// Table 32
-enum
-{
-	DW_ID_case_sensitive = 0x00,
-	DW_ID_up_case = 0x01,
-	DW_ID_down_case = 0x02,
-	DW_ID_case_insensitive = 0x03,
-};
-
-// Table 33
-enum
-{
-	DW_CC_normal = 0x01,
-	DW_CC_program = 0x02,
-	DW_CC_nocall = 0x03,
-	DW_CC_lo_user = 0x40,
-	DW_CC_hi_user = 0xff,
-};
-
-// Table 34
-enum
-{
-	DW_INL_not_inlined = 0x00,
-	DW_INL_inlined = 0x01,
-	DW_INL_declared_not_inlined = 0x02,
-	DW_INL_declared_inlined = 0x03,
-};
-
-// Table 35
-enum
-{
-	DW_ORD_row_major = 0x00,
-	DW_ORD_col_major = 0x01,
-};
-
-// Table 36
-enum
-{
-	DW_DSC_label = 0x00,
-	DW_DSC_range = 0x01,
-};
-
-// Table 37
-enum
-{
-	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,
-};
-
-// Table 38
-enum
-{
-	DW_LNE_end_sequence = 0x01,
-	DW_LNE_set_address = 0x02,
-	DW_LNE_define_file = 0x03,
-	DW_LNE_lo_user = 0x80,
-	DW_LNE_hi_user = 0xff,
-};
-
-// Table 39
-enum
-{
-	DW_MACINFO_define = 0x01,
-	DW_MACINFO_undef = 0x02,
-	DW_MACINFO_start_file = 0x03,
-	DW_MACINFO_end_file = 0x04,
-	DW_MACINFO_vendor_ext = 0xff,
-};
-
-// Table 40.
-enum
-{					// 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/ld/elf.c b/src/cmd/ld/elf.c
deleted file mode 100644
index 3196961..0000000
--- a/src/cmd/ld/elf.c
+++ /dev/null
@@ -1,1526 +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	"l.h"
-#include	"lib.h"
-#include	"../ld/elf.h"
-
-/*
- * We use the 64-bit data structures on both 32- and 64-bit machines
- * in order to write the code just once.  The 64-bit data structure is
- * written in the 32-bit format on the 32-bit machines.
- */
-#define	NSECT	48
-
-int	iself;
-
-static	int	elf64;
-static	ElfEhdr	hdr;
-static	ElfPhdr	*phdr[NSECT];
-static	ElfShdr	*shdr[NSECT];
-static	char	*interp;
-
-typedef struct Elfstring Elfstring;
-struct Elfstring
-{
-	char *s;
-	int off;
-};
-
-static Elfstring elfstr[100];
-static int nelfstr;
-
-static char buildinfo[32];
-
-/*
- Initialize the global variable that describes the ELF header. It will be updated as
- we write section and prog headers.
- */
-void
-elfinit(void)
-{
-	iself = 1;
-
-	switch(thechar) {
-	// 64-bit architectures
-	case '6':
-		elf64 = 1;
-		hdr.phoff = ELF64HDRSIZE;	/* Must be be ELF64HDRSIZE: first PHdr must follow ELF header */
-		hdr.shoff = ELF64HDRSIZE;	/* Will move as we add PHeaders */
-		hdr.ehsize = ELF64HDRSIZE;	/* Must be ELF64HDRSIZE */
-		hdr.phentsize = ELF64PHDRSIZE;	/* Must be ELF64PHDRSIZE */
-		hdr.shentsize = ELF64SHDRSIZE;	/* Must be ELF64SHDRSIZE */
-		break;
-
-	// 32-bit architectures
-	case '5':
-		// we use EABI on both linux/arm and freebsd/arm.
-		if(HEADTYPE == Hlinux || HEADTYPE == Hfreebsd)
-			hdr.flags = 0x5000002; // has entry point, Version5 EABI
-		// fallthrough
-	default:
-		hdr.phoff = ELF32HDRSIZE;	/* Must be be ELF32HDRSIZE: first PHdr must follow ELF header */
-		hdr.shoff = ELF32HDRSIZE;	/* Will move as we add PHeaders */
-		hdr.ehsize = ELF32HDRSIZE;	/* Must be ELF32HDRSIZE */
-		hdr.phentsize = ELF32PHDRSIZE;	/* Must be ELF32PHDRSIZE */
-		hdr.shentsize = ELF32SHDRSIZE;	/* Must be ELF32SHDRSIZE */
-	}
-}
-
-void
-elf64phdr(ElfPhdr *e)
-{
-	LPUT(e->type);
-	LPUT(e->flags);
-	VPUT(e->off);
-	VPUT(e->vaddr);
-	VPUT(e->paddr);
-	VPUT(e->filesz);
-	VPUT(e->memsz);
-	VPUT(e->align);
-}
-
-void
-elf32phdr(ElfPhdr *e)
-{
-	int frag;
-	
-	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 = e->vaddr&(e->align-1);
-		e->off -= frag;
-		e->vaddr -= frag;
-		e->paddr -= frag;
-		e->filesz += frag;
-		e->memsz += frag;
-	}
-	LPUT(e->type);
-	LPUT(e->off);
-	LPUT(e->vaddr);
-	LPUT(e->paddr);
-	LPUT(e->filesz);
-	LPUT(e->memsz);
-	LPUT(e->flags);
-	LPUT(e->align);
-}
-
-void
-elf64shdr(ElfShdr *e)
-{
-	LPUT(e->name);
-	LPUT(e->type);
-	VPUT(e->flags);
-	VPUT(e->addr);
-	VPUT(e->off);
-	VPUT(e->size);
-	LPUT(e->link);
-	LPUT(e->info);
-	VPUT(e->addralign);
-	VPUT(e->entsize);
-}
-
-void
-elf32shdr(ElfShdr *e)
-{
-	LPUT(e->name);
-	LPUT(e->type);
-	LPUT(e->flags);
-	LPUT(e->addr);
-	LPUT(e->off);
-	LPUT(e->size);
-	LPUT(e->link);
-	LPUT(e->info);
-	LPUT(e->addralign);
-	LPUT(e->entsize);
-}
-
-uint32
-elfwriteshdrs(void)
-{
-	int i;
-
-	if (elf64) {
-		for (i = 0; i < hdr.shnum; i++)
-			elf64shdr(shdr[i]);
-		return hdr.shnum * ELF64SHDRSIZE;
-	}
-	for (i = 0; i < hdr.shnum; i++)
-		elf32shdr(shdr[i]);
-	return hdr.shnum * ELF32SHDRSIZE;
-}
-
-void
-elfsetstring(char *s, int off)
-{
-	if(nelfstr >= nelem(elfstr)) {
-		diag("too many elf strings");
-		errorexit();
-	}
-	elfstr[nelfstr].s = s;
-	elfstr[nelfstr].off = off;
-	nelfstr++;
-}
-
-uint32
-elfwritephdrs(void)
-{
-	int i;
-
-	if (elf64) {
-		for (i = 0; i < hdr.phnum; i++)
-			elf64phdr(phdr[i]);
-		return hdr.phnum * ELF64PHDRSIZE;
-	}
-	for (i = 0; i < hdr.phnum; i++)
-		elf32phdr(phdr[i]);
-	return hdr.phnum * ELF32PHDRSIZE;
-}
-
-ElfPhdr*
-newElfPhdr(void)
-{
-	ElfPhdr *e;
-
-	e = mal(sizeof *e);
-	if (hdr.phnum >= NSECT)
-		diag("too many phdrs");
-	else
-		phdr[hdr.phnum++] = e;
-	if (elf64)
-		hdr.shoff += ELF64PHDRSIZE;
-	else
-		hdr.shoff += ELF32PHDRSIZE;
-	return e;
-}
-
-ElfShdr*
-newElfShdr(vlong name)
-{
-	ElfShdr *e;
-
-	e = mal(sizeof *e);
-	e->name = name;
-	e->shnum = hdr.shnum;
-	if (hdr.shnum >= NSECT) {
-		diag("too many shdrs");
-	} else {
-		shdr[hdr.shnum++] = e;
-	}
-	return e;
-}
-
-ElfEhdr*
-getElfEhdr(void)
-{
-	return &hdr;
-}
-
-uint32
-elf64writehdr(void)
-{
-	int i;
-
-	for (i = 0; i < EI_NIDENT; i++)
-		cput(hdr.ident[i]);
-	WPUT(hdr.type);
-	WPUT(hdr.machine);
-	LPUT(hdr.version);
-	VPUT(hdr.entry);
-	VPUT(hdr.phoff);
-	VPUT(hdr.shoff);
-	LPUT(hdr.flags);
-	WPUT(hdr.ehsize);
-	WPUT(hdr.phentsize);
-	WPUT(hdr.phnum);
-	WPUT(hdr.shentsize);
-	WPUT(hdr.shnum);
-	WPUT(hdr.shstrndx);
-	return ELF64HDRSIZE;
-}
-
-uint32
-elf32writehdr(void)
-{
-	int i;
-
-	for (i = 0; i < EI_NIDENT; i++)
-		cput(hdr.ident[i]);
-	WPUT(hdr.type);
-	WPUT(hdr.machine);
-	LPUT(hdr.version);
-	LPUT(hdr.entry);
-	LPUT(hdr.phoff);
-	LPUT(hdr.shoff);
-	LPUT(hdr.flags);
-	WPUT(hdr.ehsize);
-	WPUT(hdr.phentsize);
-	WPUT(hdr.phnum);
-	WPUT(hdr.shentsize);
-	WPUT(hdr.shnum);
-	WPUT(hdr.shstrndx);
-	return ELF32HDRSIZE;
-}
-
-uint32
-elfwritehdr(void)
-{
-	if(elf64)
-		return elf64writehdr();
-	return elf32writehdr();
-}
-
-/* Taken directly from the definition document for ELF64 */
-uint32
-elfhash(uchar *name)
-{
-	uint32 h = 0, g;
-	while (*name) {
-		h = (h << 4) + *name++;
-		if (g = h & 0xf0000000)
-			h ^= g >> 24;
-		h &= 0x0fffffff;
-	}
-	return h;
-}
-
-void
-elfwritedynent(LSym *s, int tag, uint64 val)
-{
-	if(elf64) {
-		adduint64(ctxt, s, tag);
-		adduint64(ctxt, s, val);
-	} else {
-		adduint32(ctxt, s, tag);
-		adduint32(ctxt, s, val);
-	}
-}
-
-void
-elfwritedynentsym(LSym *s, int tag, LSym *t)
-{
-	if(elf64)
-		adduint64(ctxt, s, tag);
-	else
-		adduint32(ctxt, s, tag);
-	addaddr(ctxt, s, t);
-}
-
-void
-elfwritedynentsymsize(LSym *s, int tag, LSym *t)
-{
-	if(elf64)
-		adduint64(ctxt, s, tag);
-	else
-		adduint32(ctxt, s, tag);
-	addsize(ctxt, s, t);
-}
-
-int
-elfinterp(ElfShdr *sh, uint64 startva, uint64 resoff, char *p)
-{
-	int n;
-
-	interp = p;
-	n = strlen(interp)+1;
-	sh->addr = startva + resoff - n;
-	sh->off = resoff - n;
-	sh->size = n;
-
-	return n;
-}
-
-int
-elfwriteinterp(void)
-{
-	ElfShdr *sh;
-	
-	sh = elfshname(".interp");
-	cseek(sh->off);
-	cwrite(interp, sh->size);
-	return sh->size;
-}
-
-int
-elfnote(ElfShdr *sh, uint64 startva, uint64 resoff, int sz)
-{
-	uint64 n;
-
-	n = sizeof(Elf_Note) + sz + resoff % 4;
-
-	sh->type = SHT_NOTE;
-	sh->flags = SHF_ALLOC;
-	sh->addralign = 4;
-	sh->addr = startva + resoff - n;
-	sh->off = resoff - n;
-	sh->size = n - resoff % 4;
-
-	return n;
-}
-
-ElfShdr *
-elfwritenotehdr(char *str, uint32 namesz, uint32 descsz, uint32 tag)
-{
-	ElfShdr *sh;
-	
-	sh = elfshname(str);
-
-	// Write Elf_Note header.
-	cseek(sh->off);
-	LPUT(namesz);
-	LPUT(descsz);
-	LPUT(tag);
-
-	return sh;
-}
-
-// NetBSD Signature (as per sys/exec_elf.h)
-#define ELF_NOTE_NETBSD_NAMESZ		7
-#define ELF_NOTE_NETBSD_DESCSZ		4
-#define ELF_NOTE_NETBSD_TAG		1
-#define ELF_NOTE_NETBSD_NAME		"NetBSD\0\0"
-#define ELF_NOTE_NETBSD_VERSION		599000000	/* NetBSD 5.99 */
-
-int
-elfnetbsdsig(ElfShdr *sh, uint64 startva, uint64 resoff)
-{
-	int n;
-
-	n = rnd(ELF_NOTE_NETBSD_NAMESZ, 4) + rnd(ELF_NOTE_NETBSD_DESCSZ, 4);
-	return elfnote(sh, startva, resoff, n);
-}
-
-int
-elfwritenetbsdsig(void)
-{
-	ElfShdr *sh;
-
-	// Write Elf_Note header.
-	sh = elfwritenotehdr(".note.netbsd.ident", ELF_NOTE_NETBSD_NAMESZ, ELF_NOTE_NETBSD_DESCSZ, ELF_NOTE_NETBSD_TAG);
-	if(sh == nil)
-		return 0;
-
-	// Followed by NetBSD string and version.
-	cwrite(ELF_NOTE_NETBSD_NAME, ELF_NOTE_NETBSD_NAMESZ + 1);
-	LPUT(ELF_NOTE_NETBSD_VERSION);
-
-	return sh->size;
-}
-
-// OpenBSD Signature
-#define ELF_NOTE_OPENBSD_NAMESZ		8
-#define ELF_NOTE_OPENBSD_DESCSZ		4
-#define ELF_NOTE_OPENBSD_TAG		1
-#define ELF_NOTE_OPENBSD_NAME		"OpenBSD\0"
-#define ELF_NOTE_OPENBSD_VERSION	0
-
-int
-elfopenbsdsig(ElfShdr *sh, uint64 startva, uint64 resoff)
-{
-	int n;
-
-	n = ELF_NOTE_OPENBSD_NAMESZ + ELF_NOTE_OPENBSD_DESCSZ;
-	return elfnote(sh, startva, resoff, n);
-}
-
-int
-elfwriteopenbsdsig(void)
-{
-	ElfShdr *sh;
-
-	// Write Elf_Note header.
-	sh = elfwritenotehdr(".note.openbsd.ident", ELF_NOTE_OPENBSD_NAMESZ, ELF_NOTE_OPENBSD_DESCSZ, ELF_NOTE_OPENBSD_TAG);
-	if(sh == nil)
-		return 0;
-
-	// Followed by OpenBSD string and version.
-	cwrite(ELF_NOTE_OPENBSD_NAME, ELF_NOTE_OPENBSD_NAMESZ);
-	LPUT(ELF_NOTE_OPENBSD_VERSION);
-
-	return sh->size;
-}
-
-void
-addbuildinfo(char *val)
-{
-	char *ov;
-	int i, b, j;
-
-	if(val[0] != '0' || val[1] != 'x') {
-		fprint(2, "%s: -B argument must start with 0x: %s\n", argv0, val);
-		exits("usage");
-	}
-	ov = val;
-	val += 2;
-	i = 0;
-	while(*val != '\0') {
-		if(val[1] == '\0') {
-			fprint(2, "%s: -B argument must have even number of digits: %s\n", argv0, ov);
-			exits("usage");
-		}
-		b = 0;
-		for(j = 0; j < 2; j++, val++) {
-			b *= 16;
-		  	if(*val >= '0' && *val <= '9')
-				b += *val - '0';
-			else if(*val >= 'a' && *val <= 'f')
-				b += *val - 'a' + 10;
-			else if(*val >= 'A' && *val <= 'F')
-				b += *val - 'A' + 10;
-			else {
-				fprint(2, "%s: -B argument contains invalid hex digit %c: %s\n", argv0, *val, ov);
-				exits("usage");
-			}
-		}
-		if(i >= nelem(buildinfo)) {
-			fprint(2, "%s: -B option too long (max %d digits): %s\n", argv0, (int)nelem(buildinfo), ov);
-			exits("usage");
-		}
-		buildinfo[i++] = b;
-	}
-	buildinfolen = i;
-}
-
-// Build info note
-#define ELF_NOTE_BUILDINFO_NAMESZ	4
-#define ELF_NOTE_BUILDINFO_TAG		3
-#define ELF_NOTE_BUILDINFO_NAME		"GNU\0"
-
-int
-elfbuildinfo(ElfShdr *sh, uint64 startva, uint64 resoff)
-{
-	int n;
-
-	n = ELF_NOTE_BUILDINFO_NAMESZ + rnd(buildinfolen, 4);
-	return elfnote(sh, startva, resoff, n);
-}
-
-int
-elfwritebuildinfo(void)
-{
-	ElfShdr *sh;
-
-	sh = elfwritenotehdr(".note.gnu.build-id", ELF_NOTE_BUILDINFO_NAMESZ, buildinfolen, ELF_NOTE_BUILDINFO_TAG);
-	if(sh == nil)
-		return 0;
-
-	cwrite(ELF_NOTE_BUILDINFO_NAME, ELF_NOTE_BUILDINFO_NAMESZ);
-	cwrite(buildinfo, buildinfolen);
-	cwrite("\0\0\0", rnd(buildinfolen, 4) - buildinfolen);
-
-	return sh->size;
-}
-
-extern int nelfsym;
-int elfverneed;
-
-typedef struct Elfaux Elfaux;
-typedef struct Elflib Elflib;
-
-struct Elflib
-{
-	Elflib *next;
-	Elfaux *aux;
-	char *file;
-};
-
-struct Elfaux
-{
-	Elfaux *next;
-	int num;
-	char *vers;
-};
-
-Elfaux*
-addelflib(Elflib **list, char *file, char *vers)
-{
-	Elflib *lib;
-	Elfaux *aux;
-	
-	for(lib=*list; lib; lib=lib->next)
-		if(strcmp(lib->file, file) == 0)
-			goto havelib;
-	lib = mal(sizeof *lib);
-	lib->next = *list;
-	lib->file = file;
-	*list = lib;
-havelib:
-	for(aux=lib->aux; aux; aux=aux->next)
-		if(strcmp(aux->vers, vers) == 0)
-			goto haveaux;
-	aux = mal(sizeof *aux);
-	aux->next = lib->aux;
-	aux->vers = vers;
-	lib->aux = aux;
-haveaux:
-	return aux;
-}
-
-void
-elfdynhash(void)
-{
-	LSym *s, *sy, *dynstr;
-	int i, j, nbucket, b, nfile;
-	uint32 hc, *chain, *buckets;
-	int nsym;
-	char *name;
-	Elfaux **need;
-	Elflib *needlib;
-	Elflib *l;
-	Elfaux *x;
-	
-	if(!iself)
-		return;
-
-	nsym = nelfsym;
-	s = linklookup(ctxt, ".hash", 0);
-	s->type = SELFROSECT;
-	s->reachable = 1;
-
-	i = nsym;
-	nbucket = 1;
-	while(i > 0) {
-		++nbucket;
-		i >>= 1;
-	}
-
-	needlib = nil;
-	need = malloc(nsym * sizeof need[0]);
-	chain = malloc(nsym * sizeof chain[0]);
-	buckets = malloc(nbucket * sizeof buckets[0]);
-	if(need == nil || chain == nil || buckets == nil) {
-		ctxt->cursym = nil;
-		diag("out of memory");
-		errorexit();
-	}
-	memset(need, 0, nsym * sizeof need[0]);
-	memset(chain, 0, nsym * sizeof chain[0]);
-	memset(buckets, 0, nbucket * sizeof buckets[0]);
-	for(sy=ctxt->allsym; sy!=S; sy=sy->allsym) {
-		if (sy->dynid <= 0)
-			continue;
-
-		if(sy->dynimpvers)
-			need[sy->dynid] = addelflib(&needlib, sy->dynimplib, sy->dynimpvers);
-
-		name = sy->extname;
-		hc = elfhash((uchar*)name);
-
-		b = hc % nbucket;
-		chain[sy->dynid] = buckets[b];
-		buckets[b] = sy->dynid;
-	}
-
-	adduint32(ctxt, s, nbucket);
-	adduint32(ctxt, s, nsym);
-	for(i = 0; i<nbucket; i++)
-		adduint32(ctxt, s, buckets[i]);
-	for(i = 0; i<nsym; i++)
-		adduint32(ctxt, s, chain[i]);
-
-	free(chain);
-	free(buckets);
-	
-	// version symbols
-	dynstr = linklookup(ctxt, ".dynstr", 0);
-	s = linklookup(ctxt, ".gnu.version_r", 0);
-	i = 2;
-	nfile = 0;
-	for(l=needlib; l; l=l->next) {
-		nfile++;
-		// header
-		adduint16(ctxt, s, 1);  // table version
-		j = 0;
-		for(x=l->aux; x; x=x->next)
-			j++;
-		adduint16(ctxt, s, j);	// aux count
-		adduint32(ctxt, s, addstring(dynstr, l->file));  // file string offset
-		adduint32(ctxt, s, 16);  // offset from header to first aux
-		if(l->next)
-			adduint32(ctxt, s, 16+j*16);  // offset from this header to next
-		else
-			adduint32(ctxt, s, 0);
-		
-		for(x=l->aux; x; x=x->next) {
-			x->num = i++;
-			// aux struct
-			adduint32(ctxt, s, elfhash((uchar*)x->vers));  // hash
-			adduint16(ctxt, s, 0);  // flags
-			adduint16(ctxt, s, x->num);  // other - index we refer to this by
-			adduint32(ctxt, s, addstring(dynstr, x->vers));  // version string offset
-			if(x->next)
-				adduint32(ctxt, s, 16);  // offset from this aux to next
-			else
-				adduint32(ctxt, s, 0);
-		}
-	}
-
-	// version references
-	s = linklookup(ctxt, ".gnu.version", 0);
-	for(i=0; i<nsym; i++) {
-		if(i == 0)
-			adduint16(ctxt, s, 0); // first entry - no symbol
-		else if(need[i] == nil)
-			adduint16(ctxt, s, 1); // global
-		else
-			adduint16(ctxt, s, need[i]->num);
-	}
-
-	free(need);
-
-	s = linklookup(ctxt, ".dynamic", 0);
-	elfverneed = nfile;
-	if(elfverneed) {
-		elfwritedynentsym(s, DT_VERNEED, linklookup(ctxt, ".gnu.version_r", 0));
-		elfwritedynent(s, DT_VERNEEDNUM, nfile);
-		elfwritedynentsym(s, DT_VERSYM, linklookup(ctxt, ".gnu.version", 0));
-	}
-
-	if(thechar == '6') {
-		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);
-		if(sy->size > 0) {
-			elfwritedynent(s, DT_PLTREL, DT_REL);
-			elfwritedynentsymsize(s, DT_PLTRELSZ, sy);
-			elfwritedynentsym(s, DT_JMPREL, sy);
-		}
-	}
-
-	elfwritedynent(s, DT_NULL, 0);
-}
-
-ElfPhdr*
-elfphload(Segment *seg)
-{
-	ElfPhdr *ph;
-	
-	ph = newElfPhdr();
-	ph->type = PT_LOAD;
-	if(seg->rwx & 4)
-		ph->flags |= PF_R;
-	if(seg->rwx & 2)
-		ph->flags |= PF_W;
-	if(seg->rwx & 1)
-		ph->flags |= PF_X;
-	ph->vaddr = seg->vaddr;
-	ph->paddr = seg->vaddr;
-	ph->memsz = seg->len;
-	ph->off = seg->fileoff;
-	ph->filesz = seg->filelen;
-	ph->align = INITRND;
-	
-	return ph;
-}
-
-ElfShdr*
-elfshname(char *name)
-{
-	int i, off;
-	ElfShdr *sh;
-	
-	for(i=0; i<nelfstr; i++) {
-		if(strcmp(name, elfstr[i].s) == 0) {
-			off = elfstr[i].off;
-			goto found;
-		}
-	}
-	diag("cannot find elf name %s", name);
-	errorexit();
-	return nil;
-
-found:
-	for(i=0; i<hdr.shnum; i++) {
-		sh = shdr[i];
-		if(sh->name == off)
-			return sh;
-	}
-	
-	sh = newElfShdr(off);
-	return sh;
-}
-
-ElfShdr*
-elfshalloc(Section *sect)
-{
-	ElfShdr *sh;
-	
-	sh = elfshname(sect->name);
-	sect->elfsect = sh;
-	return sh;
-}
-
-ElfShdr*
-elfshbits(Section *sect)
-{
-	ElfShdr *sh;
-	
-	sh = elfshalloc(sect);
-	if(sh->type > 0)
-		return sh;
-
-	if(sect->vaddr < sect->seg->vaddr + sect->seg->filelen)
-		sh->type = SHT_PROGBITS;
-	else
-		sh->type = SHT_NOBITS;
-	sh->flags = SHF_ALLOC;
-	if(sect->rwx & 1)
-		sh->flags |= SHF_EXECINSTR;
-	if(sect->rwx & 2)
-		sh->flags |= SHF_WRITE;
-	if(strcmp(sect->name, ".tbss") == 0) {
-		if(strcmp(goos, "android") != 0)
-			sh->flags |= SHF_TLS; // no TLS on android
-		sh->type = SHT_NOBITS;
-	}
-	if(linkmode != LinkExternal)
-		sh->addr = sect->vaddr;
-	sh->addralign = sect->align;
-	sh->size = sect->len;
-	sh->off = sect->seg->fileoff + sect->vaddr - sect->seg->vaddr;
-
-	return sh;
-}
-
-ElfShdr*
-elfshreloc(Section *sect)
-{
-	int typ;
-	ElfShdr *sh;
-	char *prefix;
-	char buf[100];
-	
-	// If main section is SHT_NOBITS, nothing to relocate.
-	// Also nothing to relocate in .shstrtab.
-	if(sect->vaddr >= sect->seg->vaddr + sect->seg->filelen)
-		return nil;
-	if(strcmp(sect->name, ".shstrtab") == 0 || strcmp(sect->name, ".tbss") == 0)
-		return nil;
-
-	if(thechar == '6') {
-		prefix = ".rela";
-		typ = SHT_RELA;
-	} else {
-		prefix = ".rel";
-		typ = SHT_REL;
-	}
-
-	snprint(buf, sizeof buf, "%s%s", prefix, sect->name);
-	sh = elfshname(buf);
-	sh->type = typ;
-	sh->entsize = RegSize*(2+(typ==SHT_RELA));
-	sh->link = elfshname(".symtab")->shnum;
-	sh->info = sect->elfsect->shnum;
-	sh->off = sect->reloff;
-	sh->size = sect->rellen;
-	sh->addralign = RegSize;
-	return sh;
-}
-
-void
-elfrelocsect(Section *sect, LSym *first)
-{
-	LSym *sym;
-	int32 eaddr;
-	Reloc *r;
-
-	// If main section is SHT_NOBITS, nothing to relocate.
-	// Also nothing to relocate in .shstrtab.
-	if(sect->vaddr >= sect->seg->vaddr + sect->seg->filelen)
-		return;
-	if(strcmp(sect->name, ".shstrtab") == 0)
-		return;
-
-	sect->reloff = cpos();
-	for(sym = first; sym != nil; sym = sym->next) {
-		if(!sym->reachable)
-			continue;
-		if(sym->value >= sect->vaddr)
-			break;
-	}
-	
-	eaddr = sect->vaddr + sect->len;
-	for(; sym != nil; sym = sym->next) {
-		if(!sym->reachable)
-			continue;
-		if(sym->value >= eaddr)
-			break;
-		ctxt->cursym = sym;
-		
-		for(r = sym->r; r < sym->r+sym->nr; r++) {
-			if(r->done)
-				continue;
-			if(r->xsym == nil) {
-				diag("missing xsym in relocation");
-				continue;
-			}
-			if(r->xsym->elfsym == 0)
-				diag("reloc %d to non-elf symbol %s (outer=%s) %d", r->type, r->sym->name, r->xsym->name, r->sym->type);
-			if(elfreloc1(r, sym->value+r->off - sect->vaddr) < 0)
-				diag("unsupported obj reloc %d/%d to %s", r->type, r->siz, r->sym->name);
-		}
-	}
-		
-	sect->rellen = cpos() - sect->reloff;
-}	
-	
-void
-elfemitreloc(void)
-{
-	Section *sect;
-
-	while(cpos()&7)
-		cput(0);
-
-	elfrelocsect(segtext.sect, ctxt->textp);
-	for(sect=segtext.sect->next; sect!=nil; sect=sect->next)
-		elfrelocsect(sect, datap);	
-	for(sect=segrodata.sect; sect!=nil; sect=sect->next)
-		elfrelocsect(sect, datap);	
-	for(sect=segdata.sect; sect!=nil; sect=sect->next)
-		elfrelocsect(sect, datap);	
-}
-
-void
-doelf(void)
-{
-	LSym *s, *shstrtab, *dynstr;
-
-	if(!iself)
-		return;
-
-	/* predefine strings we need for section headers */
-	shstrtab = linklookup(ctxt, ".shstrtab", 0);
-	shstrtab->type = SELFROSECT;
-	shstrtab->reachable = 1;
-
-	addstring(shstrtab, "");
-	addstring(shstrtab, ".text");
-	addstring(shstrtab, ".noptrdata");
-	addstring(shstrtab, ".data");
-	addstring(shstrtab, ".bss");
-	addstring(shstrtab, ".noptrbss");
-	// generate .tbss section (except for OpenBSD where it's not supported)
-	// for dynamic internal linker or external linking, so that various
-	// binutils could correctly calculate PT_TLS size.
-	// see http://golang.org/issue/5200.
-	if(HEADTYPE != Hopenbsd)
-	if(!debug['d'] || linkmode == LinkExternal)
-		addstring(shstrtab, ".tbss");
-	if(HEADTYPE == Hnetbsd)
-		addstring(shstrtab, ".note.netbsd.ident");
-	if(HEADTYPE == Hopenbsd)
-		addstring(shstrtab, ".note.openbsd.ident");
-	if(buildinfolen > 0)
-		addstring(shstrtab, ".note.gnu.build-id");
-	addstring(shstrtab, ".elfdata");
-	addstring(shstrtab, ".rodata");
-	addstring(shstrtab, ".typelink");
-	addstring(shstrtab, ".gosymtab");
-	addstring(shstrtab, ".gopclntab");
-	
-	if(linkmode == LinkExternal) {
-		debug_s = debug['s'];
-		debug['s'] = 0;
-		debug['d'] = 1;
-
-		if(thechar == '6') {
-			addstring(shstrtab, ".rela.text");
-			addstring(shstrtab, ".rela.rodata");
-			addstring(shstrtab, ".rela.typelink");
-			addstring(shstrtab, ".rela.gosymtab");
-			addstring(shstrtab, ".rela.gopclntab");
-			addstring(shstrtab, ".rela.noptrdata");
-			addstring(shstrtab, ".rela.data");
-		} else {
-			addstring(shstrtab, ".rel.text");
-			addstring(shstrtab, ".rel.rodata");
-			addstring(shstrtab, ".rel.typelink");
-			addstring(shstrtab, ".rel.gosymtab");
-			addstring(shstrtab, ".rel.gopclntab");
-			addstring(shstrtab, ".rel.noptrdata");
-			addstring(shstrtab, ".rel.data");
-		}
-		// add a .note.GNU-stack section to mark the stack as non-executable
-		addstring(shstrtab, ".note.GNU-stack");
-	}
-
-	if(flag_shared) {
-		addstring(shstrtab, ".init_array");
-		if(thechar == '6')
-			addstring(shstrtab, ".rela.init_array");
-		else
-			addstring(shstrtab, ".rel.init_array");
-	}
-
-	if(!debug['s']) {
-		addstring(shstrtab, ".symtab");
-		addstring(shstrtab, ".strtab");
-		dwarfaddshstrings(shstrtab);
-	}
-	addstring(shstrtab, ".shstrtab");
-
-	if(!debug['d']) {	/* -d suppresses dynamic loader format */
-		addstring(shstrtab, ".interp");
-		addstring(shstrtab, ".hash");
-		addstring(shstrtab, ".got");
-		addstring(shstrtab, ".got.plt");
-		addstring(shstrtab, ".dynamic");
-		addstring(shstrtab, ".dynsym");
-		addstring(shstrtab, ".dynstr");
-		if(thechar == '6') {
-			addstring(shstrtab, ".rela");
-			addstring(shstrtab, ".rela.plt");
-		} else {
-			addstring(shstrtab, ".rel");
-			addstring(shstrtab, ".rel.plt");
-		}
-		addstring(shstrtab, ".plt");
-		addstring(shstrtab, ".gnu.version");
-		addstring(shstrtab, ".gnu.version_r");
-
-		/* dynamic symbol table - first entry all zeros */
-		s = linklookup(ctxt, ".dynsym", 0);
-		s->type = SELFROSECT;
-		s->reachable = 1;
-		if(thechar == '6')
-			s->size += ELF64SYMSIZE;
-		else
-			s->size += ELF32SYMSIZE;
-
-		/* dynamic string table */
-		s = linklookup(ctxt, ".dynstr", 0);
-		s->type = SELFROSECT;
-		s->reachable = 1;
-		if(s->size == 0)
-			addstring(s, "");
-		dynstr = s;
-
-		/* relocation table */
-		if(thechar == '6')
-			s = linklookup(ctxt, ".rela", 0);
-		else
-			s = linklookup(ctxt, ".rel", 0);
-		s->reachable = 1;
-		s->type = SELFROSECT;
-
-		/* global offset table */
-		s = linklookup(ctxt, ".got", 0);
-		s->reachable = 1;
-		s->type = SELFSECT; // writable
-
-		/* hash */
-		s = linklookup(ctxt, ".hash", 0);
-		s->reachable = 1;
-		s->type = SELFROSECT;
-
-		s = linklookup(ctxt, ".got.plt", 0);
-		s->reachable = 1;
-		s->type = SELFSECT; // writable
-
-		s = linklookup(ctxt, ".plt", 0);
-		s->reachable = 1;
-		s->type = SELFRXSECT;
-		
-		elfsetupplt();
-		
-		if(thechar == '6')
-			s = linklookup(ctxt, ".rela.plt", 0);
-		else
-			s = linklookup(ctxt, ".rel.plt", 0);
-		s->reachable = 1;
-		s->type = SELFROSECT;
-		
-		s = linklookup(ctxt, ".gnu.version", 0);
-		s->reachable = 1;
-		s->type = SELFROSECT;
-		
-		s = linklookup(ctxt, ".gnu.version_r", 0);
-		s->reachable = 1;
-		s->type = SELFROSECT;
-
-		/* define dynamic elf table */
-		s = linklookup(ctxt, ".dynamic", 0);
-		s->reachable = 1;
-		s->type = SELFSECT; // writable
-
-		/*
-		 * .dynamic table
-		 */
-		elfwritedynentsym(s, DT_HASH, linklookup(ctxt, ".hash", 0));
-		elfwritedynentsym(s, DT_SYMTAB, linklookup(ctxt, ".dynsym", 0));
-		if(thechar == '6')
-			elfwritedynent(s, DT_SYMENT, ELF64SYMSIZE);
-		else
-			elfwritedynent(s, DT_SYMENT, ELF32SYMSIZE);
-		elfwritedynentsym(s, DT_STRTAB, linklookup(ctxt, ".dynstr", 0));
-		elfwritedynentsymsize(s, DT_STRSZ, linklookup(ctxt, ".dynstr", 0));
-		if(thechar == '6') {
-			elfwritedynentsym(s, DT_RELA, linklookup(ctxt, ".rela", 0));
-			elfwritedynentsymsize(s, DT_RELASZ, linklookup(ctxt, ".rela", 0));
-			elfwritedynent(s, DT_RELAENT, ELF64RELASIZE);
-		} else {
-			elfwritedynentsym(s, DT_REL, linklookup(ctxt, ".rel", 0));
-			elfwritedynentsymsize(s, DT_RELSZ, linklookup(ctxt, ".rel", 0));
-			elfwritedynent(s, DT_RELENT, ELF32RELSIZE);
-		}
-		if(rpath)
-			elfwritedynent(s, DT_RUNPATH, addstring(dynstr, rpath));
-		
-		elfwritedynentsym(s, DT_PLTGOT, linklookup(ctxt, ".got.plt", 0));
-
-		// Solaris dynamic linker can't handle an empty .rela.plt if
-		// DT_JMPREL is emitted so we have to defer generation of DT_PLTREL,
-		// DT_PLTRELSZ, and DT_JMPREL dynamic entries until after we know the
-		// size of .rel(a).plt section.
-		elfwritedynent(s, DT_DEBUG, 0);
-
-		// Do not write DT_NULL.  elfdynhash will finish it.
-	}
-}
-
-void
-shsym(ElfShdr *sh, LSym *s)
-{
-	vlong addr;
-	addr = symaddr(s);
-	if(sh->flags&SHF_ALLOC)
-		sh->addr = addr;
-	sh->off = datoff(addr);
-	sh->size = s->size;
-}
-
-void
-phsh(ElfPhdr *ph, ElfShdr *sh)
-{
-	ph->vaddr = sh->addr;
-	ph->paddr = ph->vaddr;
-	ph->off = sh->off;
-	ph->filesz = sh->size;
-	ph->memsz = sh->size;
-	ph->align = sh->addralign;
-}
-
-void
-asmbelfsetup(void)
-{
-	Section *sect;
-
-	/* This null SHdr must appear before all others */
-	elfshname("");
-	
-	for(sect=segtext.sect; sect!=nil; sect=sect->next)
-		elfshalloc(sect);
-	for(sect=segrodata.sect; sect!=nil; sect=sect->next)
-		elfshalloc(sect);
-	for(sect=segdata.sect; sect!=nil; sect=sect->next)
-		elfshalloc(sect);
-}
-
-void
-asmbelf(vlong symo)
-{
-	vlong a, o;
-	vlong startva, resoff;
-	ElfEhdr *eh;
-	ElfPhdr *ph, *pph, *pnote;
-	ElfShdr *sh;
-	Section *sect;
-
-	eh = getElfEhdr();
-	switch(thechar) {
-	default:
-		diag("unknown architecture in asmbelf");
-		errorexit();
-	case '5':
-		eh->machine = EM_ARM;
-		break;
-	case '6':
-		eh->machine = EM_X86_64;
-		break;
-	case '8':
-		eh->machine = EM_386;
-		break;
-	}
-
-	startva = INITTEXT - HEADR;
-	resoff = ELFRESERVE;
-	
-	pph = nil;
-	if(linkmode == LinkExternal) {
-		/* skip program headers */
-		eh->phoff = 0;
-		eh->phentsize = 0;
-		goto elfobj;
-	}
-
-	/* program header info */
-	pph = newElfPhdr();
-	pph->type = PT_PHDR;
-	pph->flags = PF_R;
-	pph->off = eh->ehsize;
-	pph->vaddr = INITTEXT - HEADR + pph->off;
-	pph->paddr = INITTEXT - HEADR + pph->off;
-	pph->align = INITRND;
-
-	/*
-	 * PHDR must be in a loaded segment. Adjust the text
-	 * segment boundaries downwards to include it.
-	 * Except on NaCl where it must not be loaded.
-	 */
-	if(HEADTYPE != Hnacl) {
-		o = segtext.vaddr - pph->vaddr;
-		segtext.vaddr -= o;
-		segtext.len += o;
-		o = segtext.fileoff - pph->off;
-		segtext.fileoff -= o;
-		segtext.filelen += o;
-	}
-
-	if(!debug['d']) {
-		/* interpreter */
-		sh = elfshname(".interp");
-		sh->type = SHT_PROGBITS;
-		sh->flags = SHF_ALLOC;
-		sh->addralign = 1;
-		if(interpreter == nil) {
-			switch(HEADTYPE) {
-			case Hlinux:
-				interpreter = linuxdynld;
-				break;
-			case Hfreebsd:
-				interpreter = freebsddynld;
-				break;
-			case Hnetbsd:
-				interpreter = netbsddynld;
-				break;
-			case Hopenbsd:
-				interpreter = openbsddynld;
-				break;
-			case Hdragonfly:
-				interpreter = dragonflydynld;
-				break;
-			case Hsolaris:
-				interpreter = solarisdynld;
-				break;
-			}
-		}
-		resoff -= elfinterp(sh, startva, resoff, interpreter);
-
-		ph = newElfPhdr();
-		ph->type = PT_INTERP;
-		ph->flags = PF_R;
-		phsh(ph, sh);
-	}
-
-	pnote = nil;
-	if(HEADTYPE == Hnetbsd || HEADTYPE == Hopenbsd) {
-		sh = nil;
-		switch(HEADTYPE) {
-		case Hnetbsd:
-			sh = elfshname(".note.netbsd.ident");
-			resoff -= elfnetbsdsig(sh, startva, resoff);
-			break;
-		case Hopenbsd:
-			sh = elfshname(".note.openbsd.ident");
-			resoff -= elfopenbsdsig(sh, startva, resoff);
-			break;
-		}
-
-		pnote = newElfPhdr();
-		pnote->type = PT_NOTE;
-		pnote->flags = PF_R;
-		phsh(pnote, sh);
-	}
-
-	if(buildinfolen > 0) {
-		sh = elfshname(".note.gnu.build-id");
-		resoff -= elfbuildinfo(sh, startva, resoff);
-
-		if(pnote == nil) {
-			pnote = newElfPhdr();
-			pnote->type = PT_NOTE;
-			pnote->flags = PF_R;
-		}
-		phsh(pnote, sh);
-	}
-
-	// Additions to the reserved area must be above this line.
-	USED(resoff);
-
-	elfphload(&segtext);
-	if(segrodata.sect != nil)
-		elfphload(&segrodata);
-	elfphload(&segdata);
-
-	/* Dynamic linking sections */
-	if(!debug['d']) {	/* -d suppresses dynamic loader format */
-		sh = elfshname(".dynsym");
-		sh->type = SHT_DYNSYM;
-		sh->flags = SHF_ALLOC;
-		if(elf64)
-			sh->entsize = ELF64SYMSIZE;
-		else
-			sh->entsize = ELF32SYMSIZE;
-		sh->addralign = RegSize;
-		sh->link = elfshname(".dynstr")->shnum;
-		// sh->info = index of first non-local symbol (number of local symbols)
-		shsym(sh, linklookup(ctxt, ".dynsym", 0));
-
-		sh = elfshname(".dynstr");
-		sh->type = SHT_STRTAB;
-		sh->flags = SHF_ALLOC;
-		sh->addralign = 1;
-		shsym(sh, linklookup(ctxt, ".dynstr", 0));
-
-		if(elfverneed) {
-			sh = elfshname(".gnu.version");
-			sh->type = SHT_GNU_VERSYM;
-			sh->flags = SHF_ALLOC;
-			sh->addralign = 2;
-			sh->link = elfshname(".dynsym")->shnum;
-			sh->entsize = 2;
-			shsym(sh, linklookup(ctxt, ".gnu.version", 0));
-			
-			sh = elfshname(".gnu.version_r");
-			sh->type = SHT_GNU_VERNEED;
-			sh->flags = SHF_ALLOC;
-			sh->addralign = RegSize;
-			sh->info = elfverneed;
-			sh->link = elfshname(".dynstr")->shnum;
-			shsym(sh, linklookup(ctxt, ".gnu.version_r", 0));
-		}
-
-		switch(eh->machine) {
-		case EM_X86_64:
-			sh = elfshname(".rela.plt");
-			sh->type = SHT_RELA;
-			sh->flags = SHF_ALLOC;
-			sh->entsize = ELF64RELASIZE;
-			sh->addralign = RegSize;
-			sh->link = elfshname(".dynsym")->shnum;
-			sh->info = elfshname(".plt")->shnum;
-			shsym(sh, linklookup(ctxt, ".rela.plt", 0));
-
-			sh = elfshname(".rela");
-			sh->type = SHT_RELA;
-			sh->flags = SHF_ALLOC;
-			sh->entsize = ELF64RELASIZE;
-			sh->addralign = 8;
-			sh->link = elfshname(".dynsym")->shnum;
-			shsym(sh, linklookup(ctxt, ".rela", 0));
-			break;
-		
-		default:
-			sh = elfshname(".rel.plt");
-			sh->type = SHT_REL;
-			sh->flags = SHF_ALLOC;
-			sh->entsize = ELF32RELSIZE;
-			sh->link = elfshname(".dynsym")->shnum;
-			shsym(sh, linklookup(ctxt, ".rel.plt", 0));
-
-			sh = elfshname(".rel");
-			sh->type = SHT_REL;
-			sh->flags = SHF_ALLOC;
-			sh->entsize = ELF32RELSIZE;
-			sh->addralign = 4;
-			sh->link = elfshname(".dynsym")->shnum;
-			shsym(sh, linklookup(ctxt, ".rel", 0));
-			break;
-		}
-
-		sh = elfshname(".plt");
-		sh->type = SHT_PROGBITS;
-		sh->flags = SHF_ALLOC+SHF_EXECINSTR;
-		if(eh->machine == EM_X86_64)
-			sh->entsize = 16;
-		else
-			sh->entsize = 4;
-		sh->addralign = 4;
-		shsym(sh, linklookup(ctxt, ".plt", 0));
-
-		sh = elfshname(".got");
-		sh->type = SHT_PROGBITS;
-		sh->flags = SHF_ALLOC+SHF_WRITE;
-		sh->entsize = RegSize;
-		sh->addralign = RegSize;
-		shsym(sh, linklookup(ctxt, ".got", 0));
-
-		sh = elfshname(".got.plt");
-		sh->type = SHT_PROGBITS;
-		sh->flags = SHF_ALLOC+SHF_WRITE;
-		sh->entsize = RegSize;
-		sh->addralign = RegSize;
-		shsym(sh, linklookup(ctxt, ".got.plt", 0));
-		
-		sh = elfshname(".hash");
-		sh->type = SHT_HASH;
-		sh->flags = SHF_ALLOC;
-		sh->entsize = 4;
-		sh->addralign = RegSize;
-		sh->link = elfshname(".dynsym")->shnum;
-		shsym(sh, linklookup(ctxt, ".hash", 0));
-
-		/* sh and PT_DYNAMIC for .dynamic section */
-		sh = elfshname(".dynamic");
-		sh->type = SHT_DYNAMIC;
-		sh->flags = SHF_ALLOC+SHF_WRITE;
-		sh->entsize = 2*RegSize;
-		sh->addralign = RegSize;
-		sh->link = elfshname(".dynstr")->shnum;
-		shsym(sh, linklookup(ctxt, ".dynamic", 0));
-		ph = newElfPhdr();
-		ph->type = PT_DYNAMIC;
-		ph->flags = PF_R + PF_W;
-		phsh(ph, sh);
-		
-		/*
-		 * Thread-local storage segment (really just size).
-		 */
-		// Do not emit PT_TLS for OpenBSD since ld.so(1) does
-		// not currently support it. This is handled
-		// appropriately in runtime/cgo.
-		if(ctxt->tlsoffset != 0 && HEADTYPE != Hopenbsd) {
-			ph = newElfPhdr();
-			ph->type = PT_TLS;
-			ph->flags = PF_R;
-			ph->memsz = -ctxt->tlsoffset;
-			ph->align = RegSize;
-		}
-	}
-
-	if(HEADTYPE == Hlinux) {
-		ph = newElfPhdr();
-		ph->type = PT_GNU_STACK;
-		ph->flags = PF_W+PF_R;
-		ph->align = RegSize;
-		
-		ph = newElfPhdr();
-		ph->type = PT_PAX_FLAGS;
-		ph->flags = 0x2a00; // mprotect, randexec, emutramp disabled
-		ph->align = RegSize;
-	}
-
-elfobj:
-	sh = elfshname(".shstrtab");
-	sh->type = SHT_STRTAB;
-	sh->addralign = 1;
-	shsym(sh, linklookup(ctxt, ".shstrtab", 0));
-	eh->shstrndx = sh->shnum;
-
-	// put these sections early in the list
-	if(!debug['s']) {
-		elfshname(".symtab");
-		elfshname(".strtab");
-	}
-
-	for(sect=segtext.sect; sect!=nil; sect=sect->next)
-		elfshbits(sect);
-	for(sect=segrodata.sect; sect!=nil; sect=sect->next)
-		elfshbits(sect);
-	for(sect=segdata.sect; sect!=nil; sect=sect->next)
-		elfshbits(sect);
-
-	if(linkmode == LinkExternal) {
-		for(sect=segtext.sect; sect!=nil; sect=sect->next)
-			elfshreloc(sect);
-		for(sect=segrodata.sect; sect!=nil; sect=sect->next)
-			elfshreloc(sect);
-		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->type = SHT_PROGBITS;
-		sh->addralign = 1;
-		sh->flags = 0;
-	}
-
-	// generate .tbss section for dynamic internal linking (except for OpenBSD)
-	// external linking generates .tbss in data.c
-	if(linkmode == LinkInternal && !debug['d'] && HEADTYPE != Hopenbsd) {
-		sh = elfshname(".tbss");
-		sh->type = SHT_NOBITS;
-		sh->addralign = RegSize;
-		sh->size = -ctxt->tlsoffset;
-		sh->flags = SHF_ALLOC | SHF_TLS | SHF_WRITE;
-	}
-
-	if(!debug['s']) {
-		sh = elfshname(".symtab");
-		sh->type = SHT_SYMTAB;
-		sh->off = symo;
-		sh->size = symsize;
-		sh->addralign = RegSize;
-		sh->entsize = 8+2*RegSize;
-		sh->link = elfshname(".strtab")->shnum;
-		sh->info = elfglobalsymndx;
-
-		sh = elfshname(".strtab");
-		sh->type = SHT_STRTAB;
-		sh->off = symo+symsize;
-		sh->size = elfstrsize;
-		sh->addralign = 1;
-
-		dwarfaddelfheaders();
-	}
-
-	/* Main header */
-	eh->ident[EI_MAG0] = '\177';
-	eh->ident[EI_MAG1] = 'E';
-	eh->ident[EI_MAG2] = 'L';
-	eh->ident[EI_MAG3] = 'F';
-	if(HEADTYPE == Hfreebsd)
-		eh->ident[EI_OSABI] = ELFOSABI_FREEBSD;
-	else if(HEADTYPE == Hnetbsd)
-		eh->ident[EI_OSABI] = ELFOSABI_NETBSD;
-	else if(HEADTYPE == Hopenbsd)
-		eh->ident[EI_OSABI] = ELFOSABI_OPENBSD;
-	else if(HEADTYPE == Hdragonfly)
-		eh->ident[EI_OSABI] = ELFOSABI_NONE;
-	if(elf64)
-		eh->ident[EI_CLASS] = ELFCLASS64;
-	else
-		eh->ident[EI_CLASS] = ELFCLASS32;
-	eh->ident[EI_DATA] = ELFDATA2LSB;
-	eh->ident[EI_VERSION] = EV_CURRENT;
-
-	if(linkmode == LinkExternal)
-		eh->type = ET_REL;
-	else
-		eh->type = ET_EXEC;
-
-	if(linkmode != LinkExternal)
-		eh->entry = entryvalue();
-
-	eh->version = EV_CURRENT;
-
-	if(pph != nil) {
-		pph->filesz = eh->phnum * eh->phentsize;
-		pph->memsz = pph->filesz;
-	}
-
-	cseek(0);
-	a = 0;
-	a += elfwritehdr();
-	a += elfwritephdrs();
-	a += elfwriteshdrs();
-	if(!debug['d'])
-		a += elfwriteinterp();
-	if(linkmode != LinkExternal) {
-		if(HEADTYPE == Hnetbsd)
-			a += elfwritenetbsdsig();
-		if(HEADTYPE == Hopenbsd)
-			a += elfwriteopenbsdsig();
-		if(buildinfolen > 0)
-			a += elfwritebuildinfo();
-	}
-	if(a > ELFRESERVE)	
-		diag("ELFRESERVE too small: %lld > %d", a, ELFRESERVE);
-}
diff --git a/src/cmd/ld/elf.h b/src/cmd/ld/elf.h
deleted file mode 100644
index e84d996..0000000
--- a/src/cmd/ld/elf.h
+++ /dev/null
@@ -1,1027 +0,0 @@
-/*
- * Derived from:
- * $FreeBSD: src/sys/sys/elf32.h,v 1.8.14.1 2005/12/30 22:13:58 marcel Exp $
- * $FreeBSD: src/sys/sys/elf64.h,v 1.10.14.1 2005/12/30 22:13:58 marcel Exp $
- * $FreeBSD: src/sys/sys/elf_common.h,v 1.15.8.1 2005/12/30 22:13:58 marcel Exp $
- * $FreeBSD: src/sys/alpha/include/elf.h,v 1.14 2003/09/25 01:10:22 peter Exp $
- * $FreeBSD: src/sys/amd64/include/elf.h,v 1.18 2004/08/03 08:21:48 dfr Exp $
- * $FreeBSD: src/sys/arm/include/elf.h,v 1.5.2.1 2006/06/30 21:42:52 cognet Exp $
- * $FreeBSD: src/sys/i386/include/elf.h,v 1.16 2004/08/02 19:12:17 dfr Exp $
- * $FreeBSD: src/sys/powerpc/include/elf.h,v 1.7 2004/11/02 09:47:01 ssouhlal Exp $
- * $FreeBSD: src/sys/sparc64/include/elf.h,v 1.12 2003/09/25 01:10:26 peter Exp $
- *
- * Copyright (c) 1996-1998 John D. Polstra.  All rights reserved.
- * Copyright (c) 2001 David E. O'Brien
- * Portions Copyright 2009 The Go Authors.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- */
-
-/*
- * ELF definitions that are independent of architecture or word size.
- */
-
-/*
- * Note header.  The ".note" section contains an array of notes.  Each
- * begins with this header, aligned to a word boundary.  Immediately
- * following the note header is n_namesz bytes of name, padded to the
- * next word boundary.  Then comes n_descsz bytes of descriptor, again
- * padded to a word boundary.  The values of n_namesz and n_descsz do
- * not include the padding.
- */
-
-typedef struct {
-	uint32	n_namesz;	/* Length of name. */
-	uint32	n_descsz;	/* Length of descriptor. */
-	uint32	n_type;		/* Type of this note. */
-} Elf_Note;
-
-/* Indexes into the e_ident array.  Keep synced with
-   http://www.sco.com/developer/gabi/ch4.eheader.html */
-#define EI_MAG0		0	/* Magic number, byte 0. */
-#define EI_MAG1		1	/* Magic number, byte 1. */
-#define EI_MAG2		2	/* Magic number, byte 2. */
-#define EI_MAG3		3	/* Magic number, byte 3. */
-#define EI_CLASS	4	/* Class of machine. */
-#define EI_DATA		5	/* Data format. */
-#define EI_VERSION	6	/* ELF format version. */
-#define EI_OSABI	7	/* Operating system / ABI identification */
-#define EI_ABIVERSION	8	/* ABI version */
-#define OLD_EI_BRAND	8	/* Start of architecture identification. */
-#define EI_PAD		9	/* Start of padding (per SVR4 ABI). */
-#define EI_NIDENT	16	/* Size of e_ident array. */
-
-/* Values for the magic number bytes. */
-#define ELFMAG0		0x7f
-#define ELFMAG1		'E'
-#define ELFMAG2		'L'
-#define ELFMAG3		'F'
-#define ELFMAG		"\177ELF"	/* magic string */
-#define SELFMAG		4		/* magic string size */
-
-/* Values for e_ident[EI_VERSION] and e_version. */
-#define EV_NONE		0
-#define EV_CURRENT	1
-
-/* Values for e_ident[EI_CLASS]. */
-#define ELFCLASSNONE	0	/* Unknown class. */
-#define ELFCLASS32	1	/* 32-bit architecture. */
-#define ELFCLASS64	2	/* 64-bit architecture. */
-
-/* Values for e_ident[EI_DATA]. */
-#define ELFDATANONE	0	/* Unknown data format. */
-#define ELFDATA2LSB	1	/* 2's complement little-endian. */
-#define ELFDATA2MSB	2	/* 2's complement big-endian. */
-
-/* Values for e_ident[EI_OSABI]. */
-#define ELFOSABI_NONE		0	/* UNIX System V ABI */
-#define ELFOSABI_HPUX		1	/* HP-UX operating system */
-#define ELFOSABI_NETBSD		2	/* NetBSD */
-#define ELFOSABI_LINUX		3	/* GNU/Linux */
-#define ELFOSABI_HURD		4	/* GNU/Hurd */
-#define ELFOSABI_86OPEN		5	/* 86Open common IA32 ABI */
-#define ELFOSABI_SOLARIS	6	/* Solaris */
-#define ELFOSABI_AIX		7	/* AIX */
-#define ELFOSABI_IRIX		8	/* IRIX */
-#define ELFOSABI_FREEBSD	9	/* FreeBSD */
-#define ELFOSABI_TRU64		10	/* TRU64 UNIX */
-#define ELFOSABI_MODESTO	11	/* Novell Modesto */
-#define ELFOSABI_OPENBSD	12	/* OpenBSD */
-#define ELFOSABI_OPENVMS	13	/* Open VMS */
-#define ELFOSABI_NSK		14	/* HP Non-Stop Kernel */
-#define ELFOSABI_ARM		97	/* ARM */
-#define ELFOSABI_STANDALONE	255	/* Standalone (embedded) application */
-
-#define ELFOSABI_SYSV		ELFOSABI_NONE	/* symbol used in old spec */
-#define ELFOSABI_MONTEREY	ELFOSABI_AIX	/* Monterey */
-
-/* e_ident */
-#define IS_ELF(ehdr)	((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \
-			 (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \
-			 (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \
-			 (ehdr).e_ident[EI_MAG3] == ELFMAG3)
-
-/* Values for e_type. */
-#define ET_NONE		0	/* Unknown type. */
-#define ET_REL		1	/* Relocatable. */
-#define ET_EXEC		2	/* Executable. */
-#define ET_DYN		3	/* Shared object. */
-#define ET_CORE		4	/* Core file. */
-#define ET_LOOS		0xfe00	/* First operating system specific. */
-#define ET_HIOS		0xfeff	/* Last operating system-specific. */
-#define ET_LOPROC	0xff00	/* First processor-specific. */
-#define ET_HIPROC	0xffff	/* Last processor-specific. */
-
-/* Values for e_machine. */
-#define EM_NONE		0	/* Unknown machine. */
-#define EM_M32		1	/* AT&T WE32100. */
-#define EM_SPARC	2	/* Sun SPARC. */
-#define EM_386		3	/* Intel i386. */
-#define EM_68K		4	/* Motorola 68000. */
-#define EM_88K		5	/* Motorola 88000. */
-#define EM_860		7	/* Intel i860. */
-#define EM_MIPS		8	/* MIPS R3000 Big-Endian only. */
-#define EM_S370		9	/* IBM System/370. */
-#define EM_MIPS_RS3_LE	10	/* MIPS R3000 Little-Endian. */
-#define EM_PARISC	15	/* HP PA-RISC. */
-#define EM_VPP500	17	/* Fujitsu VPP500. */
-#define EM_SPARC32PLUS	18	/* SPARC v8plus. */
-#define EM_960		19	/* Intel 80960. */
-#define EM_PPC		20	/* PowerPC 32-bit. */
-#define EM_PPC64	21	/* PowerPC 64-bit. */
-#define EM_S390		22	/* IBM System/390. */
-#define EM_V800		36	/* NEC V800. */
-#define EM_FR20		37	/* Fujitsu FR20. */
-#define EM_RH32		38	/* TRW RH-32. */
-#define EM_RCE		39	/* Motorola RCE. */
-#define EM_ARM		40	/* ARM. */
-#define EM_SH		42	/* Hitachi SH. */
-#define EM_SPARCV9	43	/* SPARC v9 64-bit. */
-#define EM_TRICORE	44	/* Siemens TriCore embedded processor. */
-#define EM_ARC		45	/* Argonaut RISC Core. */
-#define EM_H8_300	46	/* Hitachi H8/300. */
-#define EM_H8_300H	47	/* Hitachi H8/300H. */
-#define EM_H8S		48	/* Hitachi H8S. */
-#define EM_H8_500	49	/* Hitachi H8/500. */
-#define EM_IA_64	50	/* Intel IA-64 Processor. */
-#define EM_MIPS_X	51	/* Stanford MIPS-X. */
-#define EM_COLDFIRE	52	/* Motorola ColdFire. */
-#define EM_68HC12	53	/* Motorola M68HC12. */
-#define EM_MMA		54	/* Fujitsu MMA. */
-#define EM_PCP		55	/* Siemens PCP. */
-#define EM_NCPU		56	/* Sony nCPU. */
-#define EM_NDR1		57	/* Denso NDR1 microprocessor. */
-#define EM_STARCORE	58	/* Motorola Star*Core processor. */
-#define EM_ME16		59	/* Toyota ME16 processor. */
-#define EM_ST100	60	/* STMicroelectronics ST100 processor. */
-#define EM_TINYJ	61	/* Advanced Logic Corp. TinyJ processor. */
-#define EM_X86_64	62	/* Advanced Micro Devices x86-64 */
-
-/* Non-standard or deprecated. */
-#define EM_486		6	/* Intel i486. */
-#define EM_MIPS_RS4_BE	10	/* MIPS R4000 Big-Endian */
-#define EM_ALPHA_STD	41	/* Digital Alpha (standard value). */
-#define EM_ALPHA	0x9026	/* Alpha (written in the absence of an ABI) */
-
-/* Special section indexes. */
-#define SHN_UNDEF	     0		/* Undefined, missing, irrelevant. */
-#define SHN_LORESERVE	0xff00		/* First of reserved range. */
-#define SHN_LOPROC	0xff00		/* First processor-specific. */
-#define SHN_HIPROC	0xff1f		/* Last processor-specific. */
-#define SHN_LOOS	0xff20		/* First operating system-specific. */
-#define SHN_HIOS	0xff3f		/* Last operating system-specific. */
-#define SHN_ABS		0xfff1		/* Absolute values. */
-#define SHN_COMMON	0xfff2		/* Common data. */
-#define SHN_XINDEX	0xffff		/* Escape -- index stored elsewhere. */
-#define SHN_HIRESERVE	0xffff		/* Last of reserved range. */
-
-/* sh_type */
-#define SHT_NULL		0	/* inactive */
-#define SHT_PROGBITS		1	/* program defined information */
-#define SHT_SYMTAB		2	/* symbol table section */
-#define SHT_STRTAB		3	/* string table section */
-#define SHT_RELA		4	/* relocation section with addends */
-#define SHT_HASH		5	/* symbol hash table section */
-#define SHT_DYNAMIC		6	/* dynamic section */
-#define SHT_NOTE		7	/* note section */
-#define SHT_NOBITS		8	/* no space section */
-#define SHT_REL			9	/* relocation section - no addends */
-#define SHT_SHLIB		10	/* reserved - purpose unknown */
-#define SHT_DYNSYM		11	/* dynamic symbol table section */
-#define SHT_INIT_ARRAY		14	/* Initialization function pointers. */
-#define SHT_FINI_ARRAY		15	/* Termination function pointers. */
-#define SHT_PREINIT_ARRAY	16	/* Pre-initialization function ptrs. */
-#define SHT_GROUP		17	/* Section group. */
-#define SHT_SYMTAB_SHNDX	18	/* Section indexes (see SHN_XINDEX). */
-#define SHT_LOOS	0x60000000	/* First of OS specific semantics */
-#define SHT_HIOS	0x6fffffff	/* Last of OS specific semantics */
-#define SHT_GNU_VERDEF	0x6ffffffd
-#define SHT_GNU_VERNEED	0x6ffffffe
-#define SHT_GNU_VERSYM	0x6fffffff
-#define SHT_LOPROC	0x70000000	/* reserved range for processor */
-#define SHT_HIPROC	0x7fffffff	/* specific section header types */
-#define SHT_LOUSER	0x80000000	/* reserved range for application */
-#define SHT_HIUSER	0xffffffff	/* specific indexes */
-
-/* Flags for sh_flags. */
-#define SHF_WRITE		0x1	/* Section contains writable data. */
-#define SHF_ALLOC		0x2	/* Section occupies memory. */
-#define SHF_EXECINSTR		0x4	/* Section contains instructions. */
-#define SHF_MERGE		0x10	/* Section may be merged. */
-#define SHF_STRINGS		0x20	/* Section contains strings. */
-#define SHF_INFO_LINK		0x40	/* sh_info holds section index. */
-#define SHF_LINK_ORDER		0x80	/* Special ordering requirements. */
-#define SHF_OS_NONCONFORMING	0x100	/* OS-specific processing required. */
-#define SHF_GROUP		0x200	/* Member of section group. */
-#define SHF_TLS			0x400	/* Section contains TLS data. */
-#define SHF_MASKOS	0x0ff00000	/* OS-specific semantics. */
-#define SHF_MASKPROC	0xf0000000	/* Processor-specific semantics. */
-
-/* Values for p_type. */
-#define PT_NULL		0	/* Unused entry. */
-#define PT_LOAD		1	/* Loadable segment. */
-#define PT_DYNAMIC	2	/* Dynamic linking information segment. */
-#define PT_INTERP	3	/* Pathname of interpreter. */
-#define PT_NOTE		4	/* Auxiliary information. */
-#define PT_SHLIB	5	/* Reserved (not used). */
-#define PT_PHDR		6	/* Location of program header itself. */
-#define PT_TLS		7	/* Thread local storage segment */
-#define PT_LOOS		0x60000000	/* First OS-specific. */
-#define PT_HIOS		0x6fffffff	/* Last OS-specific. */
-#define PT_LOPROC	0x70000000	/* First processor-specific type. */
-#define PT_HIPROC	0x7fffffff	/* Last processor-specific type. */
-#define PT_GNU_STACK	0x6474e551
-#define PT_PAX_FLAGS	0x65041580
-
-/* Values for p_flags. */
-#define PF_X		0x1		/* Executable. */
-#define PF_W		0x2		/* Writable. */
-#define PF_R		0x4		/* Readable. */
-#define PF_MASKOS	0x0ff00000	/* Operating system-specific. */
-#define PF_MASKPROC	0xf0000000	/* Processor-specific. */
-
-/* Values for d_tag. */
-#define DT_NULL		0	/* Terminating entry. */
-/* String table offset of a needed shared library. */
-#define DT_NEEDED	1
-#define DT_PLTRELSZ	2	/* Total size in bytes of PLT relocations. */
-#define DT_PLTGOT	3	/* Processor-dependent address. */
-#define DT_HASH		4	/* Address of symbol hash table. */
-#define DT_STRTAB	5	/* Address of string table. */
-#define DT_SYMTAB	6	/* Address of symbol table. */
-#define DT_RELA		7	/* Address of ElfNN_Rela relocations. */
-#define DT_RELASZ	8	/* Total size of ElfNN_Rela relocations. */
-#define DT_RELAENT	9	/* Size of each ElfNN_Rela relocation entry. */
-#define DT_STRSZ	10	/* Size of string table. */
-#define DT_SYMENT	11	/* Size of each symbol table entry. */
-#define DT_INIT		12	/* Address of initialization function. */
-#define DT_FINI		13	/* Address of finalization function. */
-/* String table offset of shared object name. */
-#define DT_SONAME	14
-#define DT_RPATH	15	/* String table offset of library path. [sup] */
-#define DT_SYMBOLIC	16	/* Indicates "symbolic" linking. [sup] */
-#define DT_REL		17	/* Address of ElfNN_Rel relocations. */
-#define DT_RELSZ	18	/* Total size of ElfNN_Rel relocations. */
-#define DT_RELENT	19	/* Size of each ElfNN_Rel relocation. */
-#define DT_PLTREL	20	/* Type of relocation used for PLT. */
-#define DT_DEBUG	21	/* Reserved (not used). */
-/* Indicates there may be relocations in non-writable segments. [sup] */
-#define DT_TEXTREL	22
-#define DT_JMPREL	23	/* Address of PLT relocations. */
-#define	DT_BIND_NOW	24	/* [sup] */
-/* Address of the array of pointers to initialization functions */
-#define	DT_INIT_ARRAY	25
-/* Address of the array of pointers to termination functions */
-#define	DT_FINI_ARRAY	26
-/* Size in bytes of the array of initialization functions. */
-#define	DT_INIT_ARRAYSZ	27
-/* Size in bytes of the array of terminationfunctions. */
-#define	DT_FINI_ARRAYSZ	28
-/* String table offset of a null-terminated library search path string. */
-#define	DT_RUNPATH	29
-#define	DT_FLAGS	30	/* Object specific flag values. */
-/*	Values greater than or equal to DT_ENCODING and less than
-	DT_LOOS follow the rules for the interpretation of the d_un
-	union as follows: even == 'd_ptr', even == 'd_val' or none */
-#define	DT_ENCODING	32
-/* Address of the array of pointers to pre-initialization functions. */
-#define	DT_PREINIT_ARRAY 32
-/* Size in bytes of the array of pre-initialization functions. */
-#define	DT_PREINIT_ARRAYSZ 33
-#define	DT_LOOS		0x6000000d	/* First OS-specific */
-#define	DT_HIOS		0x6ffff000	/* Last OS-specific */
-#define	DT_LOPROC	0x70000000	/* First processor-specific type. */
-#define	DT_HIPROC	0x7fffffff	/* Last processor-specific type. */
-
-#define	DT_VERNEED	0x6ffffffe
-#define	DT_VERNEEDNUM	0x6fffffff
-#define	DT_VERSYM	0x6ffffff0
-
-/* Values for DT_FLAGS */
-/*	Indicates that the object being loaded may make reference to
-	the $ORIGIN substitution string */
-#define	DF_ORIGIN	0x0001
-#define	DF_SYMBOLIC	0x0002	/* Indicates "symbolic" linking. */
-/* Indicates there may be relocations in non-writable segments. */
-#define	DF_TEXTREL	0x0004
-/*	Indicates that the dynamic linker should process all
-	relocations for the object containing this entry before
-	transferring control to the program.  */
-#define	DF_BIND_NOW	0x0008
-/*	Indicates that the shared object or executable contains code
-	using a static thread-local storage scheme.  */
-#define	DF_STATIC_TLS	0x0010
-
-/* Values for n_type.  Used in core files. */
-#define NT_PRSTATUS	1	/* Process status. */
-#define NT_FPREGSET	2	/* Floating point registers. */
-#define NT_PRPSINFO	3	/* Process state info. */
-
-/* Symbol Binding - ELFNN_ST_BIND - st_info */
-#define STB_LOCAL	0	/* Local symbol */
-#define STB_GLOBAL	1	/* Global symbol */
-#define STB_WEAK	2	/* like global - lower precedence */
-#define STB_LOOS	10	/* Reserved range for operating system */
-#define STB_HIOS	12	/*   specific semantics. */
-#define STB_LOPROC	13	/* reserved range for processor */
-#define STB_HIPROC	15	/*   specific semantics. */
-
-/* Symbol type - ELFNN_ST_TYPE - st_info */
-#define STT_NOTYPE	0	/* Unspecified type. */
-#define STT_OBJECT	1	/* Data object. */
-#define STT_FUNC	2	/* Function. */
-#define STT_SECTION	3	/* Section. */
-#define STT_FILE	4	/* Source file. */
-#define STT_COMMON	5	/* Uninitialized common block. */
-#define STT_TLS		6	/* TLS object. */
-#define STT_LOOS	10	/* Reserved range for operating system */
-#define STT_HIOS	12	/*   specific semantics. */
-#define STT_LOPROC	13	/* reserved range for processor */
-#define STT_HIPROC	15	/*   specific semantics. */
-
-/* Symbol visibility - ELFNN_ST_VISIBILITY - st_other */
-#define STV_DEFAULT	0x0	/* Default visibility (see binding). */
-#define STV_INTERNAL	0x1	/* Special meaning in relocatable objects. */
-#define STV_HIDDEN	0x2	/* Not visible. */
-#define STV_PROTECTED	0x3	/* Visible but not preemptible. */
-
-/* Special symbol table indexes. */
-#define STN_UNDEF	0	/* Undefined symbol index. */
-
-/*
- * ELF definitions common to all 32-bit architectures.
- */
-
-typedef uint32	Elf32_Addr;
-typedef uint16	Elf32_Half;
-typedef uint32	Elf32_Off;
-typedef int32		Elf32_Sword;
-typedef uint32	Elf32_Word;
-
-typedef Elf32_Word	Elf32_Hashelt;
-
-/* Non-standard class-dependent datatype used for abstraction. */
-typedef Elf32_Word	Elf32_Size;
-typedef Elf32_Sword	Elf32_Ssize;
-
-/*
- * ELF header.
- */
-
-typedef struct {
-	unsigned char	ident[EI_NIDENT];	/* File identification. */
-	Elf32_Half	type;		/* File type. */
-	Elf32_Half	machine;	/* Machine architecture. */
-	Elf32_Word	version;	/* ELF format version. */
-	Elf32_Addr	entry;	/* Entry point. */
-	Elf32_Off	phoff;	/* Program header file offset. */
-	Elf32_Off	shoff;	/* Section header file offset. */
-	Elf32_Word	flags;	/* Architecture-specific flags. */
-	Elf32_Half	ehsize;	/* Size of ELF header in bytes. */
-	Elf32_Half	phentsize;	/* Size of program header entry. */
-	Elf32_Half	phnum;	/* Number of program header entries. */
-	Elf32_Half	shentsize;	/* Size of section header entry. */
-	Elf32_Half	shnum;	/* Number of section header entries. */
-	Elf32_Half	shstrndx;	/* Section name strings section. */
-} Elf32_Ehdr;
-
-/*
- * Section header.
- */
-
-typedef struct {
-	Elf32_Word	name;	/* Section name (index into the
-					   section header string table). */
-	Elf32_Word	type;	/* Section type. */
-	Elf32_Word	flags;	/* Section flags. */
-	Elf32_Addr	vaddr;	/* Address in memory image. */
-	Elf32_Off	off;	/* Offset in file. */
-	Elf32_Word	size;	/* Size in bytes. */
-	Elf32_Word	link;	/* Index of a related section. */
-	Elf32_Word	info;	/* Depends on section type. */
-	Elf32_Word	addralign;	/* Alignment in bytes. */
-	Elf32_Word	entsize;	/* Size of each entry in section. */
-} Elf32_Shdr;
-
-/*
- * Program header.
- */
-
-typedef struct {
-	Elf32_Word	type;		/* Entry type. */
-	Elf32_Off	off;	/* File offset of contents. */
-	Elf32_Addr	vaddr;	/* Virtual address in memory image. */
-	Elf32_Addr	paddr;	/* Physical address (not used). */
-	Elf32_Word	filesz;	/* Size of contents in file. */
-	Elf32_Word	memsz;	/* Size of contents in memory. */
-	Elf32_Word	flags;	/* Access permission flags. */
-	Elf32_Word	align;	/* Alignment in memory and file. */
-} Elf32_Phdr;
-
-/*
- * Dynamic structure.  The ".dynamic" section contains an array of them.
- */
-
-typedef struct {
-	Elf32_Sword	d_tag;		/* Entry type. */
-	union {
-		Elf32_Word	d_val;	/* Integer value. */
-		Elf32_Addr	d_ptr;	/* Address value. */
-	} d_un;
-} Elf32_Dyn;
-
-/*
- * Relocation entries.
- */
-
-/* Relocations that don't need an addend field. */
-typedef struct {
-	Elf32_Addr	off;	/* Location to be relocated. */
-	Elf32_Word	info;		/* Relocation type and symbol index. */
-} Elf32_Rel;
-
-/* Relocations that need an addend field. */
-typedef struct {
-	Elf32_Addr	off;	/* Location to be relocated. */
-	Elf32_Word	info;		/* Relocation type and symbol index. */
-	Elf32_Sword	addend;	/* Addend. */
-} Elf32_Rela;
-
-/* Macros for accessing the fields of r_info. */
-#define ELF32_R_SYM(info)	((info) >> 8)
-#define ELF32_R_TYPE(info)	((unsigned char)(info))
-
-/* Macro for constructing r_info from field values. */
-#define ELF32_R_INFO(sym, type)	(((sym) << 8) + (unsigned char)(type))
-
-/*
- * Relocation types.
- */
-
-#define	R_X86_64_NONE	0	/* No relocation. */
-#define	R_X86_64_64	1	/* Add 64 bit symbol value. */
-#define	R_X86_64_PC32	2	/* PC-relative 32 bit signed sym value. */
-#define	R_X86_64_GOT32	3	/* PC-relative 32 bit GOT offset. */
-#define	R_X86_64_PLT32	4	/* PC-relative 32 bit PLT offset. */
-#define	R_X86_64_COPY	5	/* Copy data from shared object. */
-#define	R_X86_64_GLOB_DAT 6	/* Set GOT entry to data address. */
-#define	R_X86_64_JMP_SLOT 7	/* Set GOT entry to code address. */
-#define	R_X86_64_RELATIVE 8	/* Add load address of shared object. */
-#define	R_X86_64_GOTPCREL 9	/* Add 32 bit signed pcrel offset to GOT. */
-#define	R_X86_64_32	10	/* Add 32 bit zero extended symbol value */
-#define	R_X86_64_32S	11	/* Add 32 bit sign extended symbol value */
-#define	R_X86_64_16	12	/* Add 16 bit zero extended symbol value */
-#define	R_X86_64_PC16	13	/* Add 16 bit signed extended pc relative symbol value */
-#define	R_X86_64_8	14	/* Add 8 bit zero extended symbol value */
-#define	R_X86_64_PC8	15	/* Add 8 bit signed extended pc relative symbol value */
-#define	R_X86_64_DTPMOD64 16	/* ID of module containing symbol */
-#define	R_X86_64_DTPOFF64 17	/* Offset in TLS block */
-#define	R_X86_64_TPOFF64 18	/* Offset in static TLS block */
-#define	R_X86_64_TLSGD	19	/* PC relative offset to GD GOT entry */
-#define	R_X86_64_TLSLD	20	/* PC relative offset to LD GOT entry */
-#define	R_X86_64_DTPOFF32 21	/* Offset in TLS block */
-#define	R_X86_64_GOTTPOFF 22	/* PC relative offset to IE GOT entry */
-#define	R_X86_64_TPOFF32 23	/* Offset in static TLS block */
-
-#define	R_X86_64_COUNT	24	/* Count of defined relocation types. */
-
-
-#define	R_ALPHA_NONE		0	/* No reloc */
-#define	R_ALPHA_REFLONG		1	/* Direct 32 bit */
-#define	R_ALPHA_REFQUAD		2	/* Direct 64 bit */
-#define	R_ALPHA_GPREL32		3	/* GP relative 32 bit */
-#define	R_ALPHA_LITERAL		4	/* GP relative 16 bit w/optimization */
-#define	R_ALPHA_LITUSE		5	/* Optimization hint for LITERAL */
-#define	R_ALPHA_GPDISP		6	/* Add displacement to GP */
-#define	R_ALPHA_BRADDR		7	/* PC+4 relative 23 bit shifted */
-#define	R_ALPHA_HINT		8	/* PC+4 relative 16 bit shifted */
-#define	R_ALPHA_SREL16		9	/* PC relative 16 bit */
-#define	R_ALPHA_SREL32		10	/* PC relative 32 bit */
-#define	R_ALPHA_SREL64		11	/* PC relative 64 bit */
-#define	R_ALPHA_OP_PUSH		12	/* OP stack push */
-#define	R_ALPHA_OP_STORE	13	/* OP stack pop and store */
-#define	R_ALPHA_OP_PSUB		14	/* OP stack subtract */
-#define	R_ALPHA_OP_PRSHIFT	15	/* OP stack right shift */
-#define	R_ALPHA_GPVALUE		16
-#define	R_ALPHA_GPRELHIGH	17
-#define	R_ALPHA_GPRELLOW	18
-#define	R_ALPHA_IMMED_GP_16	19
-#define	R_ALPHA_IMMED_GP_HI32	20
-#define	R_ALPHA_IMMED_SCN_HI32	21
-#define	R_ALPHA_IMMED_BR_HI32	22
-#define	R_ALPHA_IMMED_LO32	23
-#define	R_ALPHA_COPY		24	/* Copy symbol at runtime */
-#define	R_ALPHA_GLOB_DAT	25	/* Create GOT entry */
-#define	R_ALPHA_JMP_SLOT	26	/* Create PLT entry */
-#define	R_ALPHA_RELATIVE	27	/* Adjust by program base */
-
-#define	R_ALPHA_COUNT		28
-
-
-#define	R_ARM_NONE		0	/* No relocation. */
-#define	R_ARM_PC24		1
-#define	R_ARM_ABS32		2
-#define	R_ARM_REL32		3
-#define	R_ARM_PC13		4
-#define	R_ARM_ABS16		5
-#define	R_ARM_ABS12		6
-#define	R_ARM_THM_ABS5		7
-#define	R_ARM_ABS8		8
-#define	R_ARM_SBREL32		9
-#define	R_ARM_THM_PC22		10
-#define	R_ARM_THM_PC8		11
-#define	R_ARM_AMP_VCALL9	12
-#define	R_ARM_SWI24		13
-#define	R_ARM_THM_SWI8		14
-#define	R_ARM_XPC25		15
-#define	R_ARM_THM_XPC22		16
-#define	R_ARM_COPY		20	/* Copy data from shared object. */
-#define	R_ARM_GLOB_DAT		21	/* Set GOT entry to data address. */
-#define	R_ARM_JUMP_SLOT		22	/* Set GOT entry to code address. */
-#define	R_ARM_RELATIVE		23	/* Add load address of shared object. */
-#define	R_ARM_GOTOFF		24	/* Add GOT-relative symbol address. */
-#define	R_ARM_GOTPC		25	/* Add PC-relative GOT table address. */
-#define	R_ARM_GOT32		26	/* Add PC-relative GOT offset. */
-#define	R_ARM_PLT32		27	/* Add PC-relative PLT offset. */
-#define	R_ARM_CALL		28
-#define	R_ARM_JUMP24	29
-#define	R_ARM_V4BX		40
-#define	R_ARM_GOT_PREL		96
-#define	R_ARM_GNU_VTENTRY	100
-#define	R_ARM_GNU_VTINHERIT	101
-#define	R_ARM_TLS_IE32		107
-#define	R_ARM_TLS_LE32		108
-#define	R_ARM_RSBREL32		250
-#define	R_ARM_THM_RPC22		251
-#define	R_ARM_RREL32		252
-#define	R_ARM_RABS32		253
-#define	R_ARM_RPC24		254
-#define	R_ARM_RBASE		255
-
-#define	R_ARM_COUNT		38	/* Count of defined relocation types. */
-
-
-#define	R_386_NONE	0	/* No relocation. */
-#define	R_386_32	1	/* Add symbol value. */
-#define	R_386_PC32	2	/* Add PC-relative symbol value. */
-#define	R_386_GOT32	3	/* Add PC-relative GOT offset. */
-#define	R_386_PLT32	4	/* Add PC-relative PLT offset. */
-#define	R_386_COPY	5	/* Copy data from shared object. */
-#define	R_386_GLOB_DAT	6	/* Set GOT entry to data address. */
-#define	R_386_JMP_SLOT	7	/* Set GOT entry to code address. */
-#define	R_386_RELATIVE	8	/* Add load address of shared object. */
-#define	R_386_GOTOFF	9	/* Add GOT-relative symbol address. */
-#define	R_386_GOTPC	10	/* Add PC-relative GOT table address. */
-#define	R_386_TLS_TPOFF	14	/* Negative offset in static TLS block */
-#define	R_386_TLS_IE	15	/* Absolute address of GOT for -ve static TLS */
-#define	R_386_TLS_GOTIE	16	/* GOT entry for negative static TLS block */
-#define	R_386_TLS_LE	17	/* Negative offset relative to static TLS */
-#define	R_386_TLS_GD	18	/* 32 bit offset to GOT (index,off) pair */
-#define	R_386_TLS_LDM	19	/* 32 bit offset to GOT (index,zero) pair */
-#define	R_386_TLS_GD_32	24	/* 32 bit offset to GOT (index,off) pair */
-#define	R_386_TLS_GD_PUSH 25	/* pushl instruction for Sun ABI GD sequence */
-#define	R_386_TLS_GD_CALL 26	/* call instruction for Sun ABI GD sequence */
-#define	R_386_TLS_GD_POP 27	/* popl instruction for Sun ABI GD sequence */
-#define	R_386_TLS_LDM_32 28	/* 32 bit offset to GOT (index,zero) pair */
-#define	R_386_TLS_LDM_PUSH 29	/* pushl instruction for Sun ABI LD sequence */
-#define	R_386_TLS_LDM_CALL 30	/* call instruction for Sun ABI LD sequence */
-#define	R_386_TLS_LDM_POP 31	/* popl instruction for Sun ABI LD sequence */
-#define	R_386_TLS_LDO_32 32	/* 32 bit offset from start of TLS block */
-#define	R_386_TLS_IE_32	33	/* 32 bit offset to GOT static TLS offset entry */
-#define	R_386_TLS_LE_32	34	/* 32 bit offset within static TLS block */
-#define	R_386_TLS_DTPMOD32 35	/* GOT entry containing TLS index */
-#define	R_386_TLS_DTPOFF32 36	/* GOT entry containing TLS offset */
-#define	R_386_TLS_TPOFF32 37	/* GOT entry of -ve static TLS offset */
-
-#define	R_386_COUNT	38	/* Count of defined relocation types. */
-
-#define	R_PPC_NONE		0	/* No relocation. */
-#define	R_PPC_ADDR32		1
-#define	R_PPC_ADDR24		2
-#define	R_PPC_ADDR16		3
-#define	R_PPC_ADDR16_LO		4
-#define	R_PPC_ADDR16_HI		5
-#define	R_PPC_ADDR16_HA		6
-#define	R_PPC_ADDR14		7
-#define	R_PPC_ADDR14_BRTAKEN	8
-#define	R_PPC_ADDR14_BRNTAKEN	9
-#define	R_PPC_REL24		10
-#define	R_PPC_REL14		11
-#define	R_PPC_REL14_BRTAKEN	12
-#define	R_PPC_REL14_BRNTAKEN	13
-#define	R_PPC_GOT16		14
-#define	R_PPC_GOT16_LO		15
-#define	R_PPC_GOT16_HI		16
-#define	R_PPC_GOT16_HA		17
-#define	R_PPC_PLTREL24		18
-#define	R_PPC_COPY		19
-#define	R_PPC_GLOB_DAT		20
-#define	R_PPC_JMP_SLOT		21
-#define	R_PPC_RELATIVE		22
-#define	R_PPC_LOCAL24PC		23
-#define	R_PPC_UADDR32		24
-#define	R_PPC_UADDR16		25
-#define	R_PPC_REL32		26
-#define	R_PPC_PLT32		27
-#define	R_PPC_PLTREL32		28
-#define	R_PPC_PLT16_LO		29
-#define	R_PPC_PLT16_HI		30
-#define	R_PPC_PLT16_HA		31
-#define	R_PPC_SDAREL16		32
-#define	R_PPC_SECTOFF		33
-#define	R_PPC_SECTOFF_LO	34
-#define	R_PPC_SECTOFF_HI	35
-#define	R_PPC_SECTOFF_HA	36
-
-#define	R_PPC_COUNT		37	/* Count of defined relocation types. */
-
-#define R_PPC_TLS		67
-#define R_PPC_DTPMOD32		68
-#define R_PPC_TPREL16		69
-#define R_PPC_TPREL16_LO	70
-#define R_PPC_TPREL16_HI	71
-#define R_PPC_TPREL16_HA	72
-#define R_PPC_TPREL32		73
-#define R_PPC_DTPREL16		74
-#define R_PPC_DTPREL16_LO	75
-#define R_PPC_DTPREL16_HI	76
-#define R_PPC_DTPREL16_HA	77
-#define R_PPC_DTPREL32		78
-#define R_PPC_GOT_TLSGD16	79
-#define R_PPC_GOT_TLSGD16_LO	80
-#define R_PPC_GOT_TLSGD16_HI	81
-#define R_PPC_GOT_TLSGD16_HA	82
-#define R_PPC_GOT_TLSLD16	83
-#define R_PPC_GOT_TLSLD16_LO	84
-#define R_PPC_GOT_TLSLD16_HI	85
-#define R_PPC_GOT_TLSLD16_HA	86
-#define R_PPC_GOT_TPREL16	87
-#define R_PPC_GOT_TPREL16_LO	88
-#define R_PPC_GOT_TPREL16_HI	89
-#define R_PPC_GOT_TPREL16_HA	90
-
-#define	R_PPC_EMB_NADDR32	101
-#define	R_PPC_EMB_NADDR16	102
-#define	R_PPC_EMB_NADDR16_LO	103
-#define	R_PPC_EMB_NADDR16_HI	104
-#define	R_PPC_EMB_NADDR16_HA	105
-#define	R_PPC_EMB_SDAI16	106
-#define	R_PPC_EMB_SDA2I16	107
-#define	R_PPC_EMB_SDA2REL	108
-#define	R_PPC_EMB_SDA21		109
-#define	R_PPC_EMB_MRKREF	110
-#define	R_PPC_EMB_RELSEC16	111
-#define	R_PPC_EMB_RELST_LO	112
-#define	R_PPC_EMB_RELST_HI	113
-#define	R_PPC_EMB_RELST_HA	114
-#define	R_PPC_EMB_BIT_FLD	115
-#define	R_PPC_EMB_RELSDA	116
-
-					/* Count of defined relocation types. */
-#define	R_PPC_EMB_COUNT		(R_PPC_EMB_RELSDA - R_PPC_EMB_NADDR32 + 1)
-
-
-#define R_SPARC_NONE		0
-#define R_SPARC_8		1
-#define R_SPARC_16		2
-#define R_SPARC_32		3
-#define R_SPARC_DISP8		4
-#define R_SPARC_DISP16		5
-#define R_SPARC_DISP32		6
-#define R_SPARC_WDISP30		7
-#define R_SPARC_WDISP22		8
-#define R_SPARC_HI22		9
-#define R_SPARC_22		10
-#define R_SPARC_13		11
-#define R_SPARC_LO10		12
-#define R_SPARC_GOT10		13
-#define R_SPARC_GOT13		14
-#define R_SPARC_GOT22		15
-#define R_SPARC_PC10		16
-#define R_SPARC_PC22		17
-#define R_SPARC_WPLT30		18
-#define R_SPARC_COPY		19
-#define R_SPARC_GLOB_DAT	20
-#define R_SPARC_JMP_SLOT	21
-#define R_SPARC_RELATIVE	22
-#define R_SPARC_UA32		23
-#define R_SPARC_PLT32		24
-#define R_SPARC_HIPLT22		25
-#define R_SPARC_LOPLT10		26
-#define R_SPARC_PCPLT32		27
-#define R_SPARC_PCPLT22		28
-#define R_SPARC_PCPLT10		29
-#define R_SPARC_10		30
-#define R_SPARC_11		31
-#define R_SPARC_64		32
-#define R_SPARC_OLO10		33
-#define R_SPARC_HH22		34
-#define R_SPARC_HM10		35
-#define R_SPARC_LM22		36
-#define R_SPARC_PC_HH22		37
-#define R_SPARC_PC_HM10		38
-#define R_SPARC_PC_LM22		39
-#define R_SPARC_WDISP16		40
-#define R_SPARC_WDISP19		41
-#define R_SPARC_GLOB_JMP	42
-#define R_SPARC_7		43
-#define R_SPARC_5		44
-#define R_SPARC_6		45
-#define	R_SPARC_DISP64		46
-#define	R_SPARC_PLT64		47
-#define	R_SPARC_HIX22		48
-#define	R_SPARC_LOX10		49
-#define	R_SPARC_H44		50
-#define	R_SPARC_M44		51
-#define	R_SPARC_L44		52
-#define	R_SPARC_REGISTER	53
-#define	R_SPARC_UA64		54
-#define	R_SPARC_UA16		55
-
-
-/*
- * Magic number for the elf trampoline, chosen wisely to be an immediate
- * value.
- */
-#define ARM_MAGIC_TRAMP_NUMBER	0x5c000003
-
-
-/*
- * Symbol table entries.
- */
-
-typedef struct {
-	Elf32_Word	name;	/* String table index of name. */
-	Elf32_Addr	value;	/* Symbol value. */
-	Elf32_Word	size;	/* Size of associated object. */
-	unsigned char	info;	/* Type and binding information. */
-	unsigned char	other;	/* Reserved (not used). */
-	Elf32_Half	shndx;	/* Section index of symbol. */
-} Elf32_Sym;
-
-/* Macros for accessing the fields of st_info. */
-#define ELF32_ST_BIND(info)		((info) >> 4)
-#define ELF32_ST_TYPE(info)		((info) & 0xf)
-
-/* Macro for constructing st_info from field values. */
-#define ELF32_ST_INFO(bind, type)	(((bind) << 4) + ((type) & 0xf))
-
-/* Macro for accessing the fields of st_other. */
-#define ELF32_ST_VISIBILITY(oth)	((oth) & 0x3)
-
-/*
- * ELF definitions common to all 64-bit architectures.
- */
-
-typedef uint64	Elf64_Addr;
-typedef uint16	Elf64_Half;
-typedef uint64	Elf64_Off;
-typedef int32		Elf64_Sword;
-typedef int64		Elf64_Sxword;
-typedef uint32	Elf64_Word;
-typedef uint64	Elf64_Xword;
-
-/*
- * Types of dynamic symbol hash table bucket and chain elements.
- *
- * This is inconsistent among 64 bit architectures, so a machine dependent
- * typedef is required.
- */
-
-#ifdef __alpha__
-typedef Elf64_Off	Elf64_Hashelt;
-#else
-typedef Elf64_Word	Elf64_Hashelt;
-#endif
-
-/* Non-standard class-dependent datatype used for abstraction. */
-typedef Elf64_Xword	Elf64_Size;
-typedef Elf64_Sxword	Elf64_Ssize;
-
-/*
- * ELF header.
- */
-
-typedef struct {
-	unsigned char	ident[EI_NIDENT];	/* File identification. */
-	Elf64_Half	type;		/* File type. */
-	Elf64_Half	machine;	/* Machine architecture. */
-	Elf64_Word	version;	/* ELF format version. */
-	Elf64_Addr	entry;	/* Entry point. */
-	Elf64_Off	phoff;	/* Program header file offset. */
-	Elf64_Off	shoff;	/* Section header file offset. */
-	Elf64_Word	flags;	/* Architecture-specific flags. */
-	Elf64_Half	ehsize;	/* Size of ELF header in bytes. */
-	Elf64_Half	phentsize;	/* Size of program header entry. */
-	Elf64_Half	phnum;	/* Number of program header entries. */
-	Elf64_Half	shentsize;	/* Size of section header entry. */
-	Elf64_Half	shnum;	/* Number of section header entries. */
-	Elf64_Half	shstrndx;	/* Section name strings section. */
-} Elf64_Ehdr;
-
-/*
- * Section header.
- */
-
-typedef struct Elf64_Shdr Elf64_Shdr;
-struct Elf64_Shdr {
-	Elf64_Word	name;	/* Section name (index into the
-					   section header string table). */
-	Elf64_Word	type;	/* Section type. */
-	Elf64_Xword	flags;	/* Section flags. */
-	Elf64_Addr	addr;	/* Address in memory image. */
-	Elf64_Off	off;	/* Offset in file. */
-	Elf64_Xword	size;	/* Size in bytes. */
-	Elf64_Word	link;	/* Index of a related section. */
-	Elf64_Word	info;	/* Depends on section type. */
-	Elf64_Xword	addralign;	/* Alignment in bytes. */
-	Elf64_Xword	entsize;	/* Size of each entry in section. */
-	
-	int	shnum;  /* section number, not stored on disk */
-	LSym*	secsym; /* section symbol, if needed; not on disk */
-};
-
-/*
- * Program header.
- */
-
-typedef struct {
-	Elf64_Word	type;		/* Entry type. */
-	Elf64_Word	flags;	/* Access permission flags. */
-	Elf64_Off	off;	/* File offset of contents. */
-	Elf64_Addr	vaddr;	/* Virtual address in memory image. */
-	Elf64_Addr	paddr;	/* Physical address (not used). */
-	Elf64_Xword	filesz;	/* Size of contents in file. */
-	Elf64_Xword	memsz;	/* Size of contents in memory. */
-	Elf64_Xword	align;	/* Alignment in memory and file. */
-} Elf64_Phdr;
-
-/*
- * Dynamic structure.  The ".dynamic" section contains an array of them.
- */
-
-typedef struct {
-	Elf64_Sxword	d_tag;		/* Entry type. */
-	union {
-		Elf64_Xword	d_val;	/* Integer value. */
-		Elf64_Addr	d_ptr;	/* Address value. */
-	} d_un;
-} Elf64_Dyn;
-
-/*
- * Relocation entries.
- */
-
-/* Relocations that don't need an addend field. */
-typedef struct {
-	Elf64_Addr	off;	/* Location to be relocated. */
-	Elf64_Xword	info;		/* Relocation type and symbol index. */
-} Elf64_Rel;
-
-/* Relocations that need an addend field. */
-typedef struct {
-	Elf64_Addr	off;	/* Location to be relocated. */
-	Elf64_Xword	info;		/* Relocation type and symbol index. */
-	Elf64_Sxword	addend;	/* Addend. */
-} Elf64_Rela;
-
-/* Macros for accessing the fields of r_info. */
-#define ELF64_R_SYM(info)	((info) >> 32)
-#define ELF64_R_TYPE(info)	((info) & 0xffffffffL)
-
-/* Macro for constructing r_info from field values. */
-#define ELF64_R_INFO(sym, type)	((((uint64)(sym)) << 32) + (((uint64)(type)) & 0xffffffffULL))
-
-/*
- * Symbol table entries.
- */
-
-typedef struct {
-	Elf64_Word	name;	/* String table index of name. */
-	unsigned char	info;	/* Type and binding information. */
-	unsigned char	other;	/* Reserved (not used). */
-	Elf64_Half	shndx;	/* Section index of symbol. */
-	Elf64_Addr	value;	/* Symbol value. */
-	Elf64_Xword	size;	/* Size of associated object. */
-} Elf64_Sym;
-
-/* Macros for accessing the fields of st_info. */
-#define ELF64_ST_BIND(info)		((info) >> 4)
-#define ELF64_ST_TYPE(info)		((info) & 0xf)
-
-/* Macro for constructing st_info from field values. */
-#define ELF64_ST_INFO(bind, type)	(((bind) << 4) + ((type) & 0xf))
-
-/* Macro for accessing the fields of st_other. */
-#define ELF64_ST_VISIBILITY(oth)	((oth) & 0x3)
-
-/*
- * Go linker interface
- */
-
-#define	ELF64HDRSIZE	64
-#define	ELF64PHDRSIZE	56
-#define	ELF64SHDRSIZE	64
-#define	ELF64RELSIZE	16
-#define	ELF64RELASIZE	24
-#define	ELF64SYMSIZE	sizeof(Elf64_Sym)
-
-#define	ELF32HDRSIZE	sizeof(Elf32_Ehdr)
-#define	ELF32PHDRSIZE	sizeof(Elf32_Phdr)
-#define	ELF32SHDRSIZE	sizeof(Elf32_Shdr)
-#define	ELF32SYMSIZE	sizeof(Elf32_Sym)
-#define	ELF32RELSIZE	8
-
-/*
- * The interface uses the 64-bit structures always,
- * to avoid code duplication.  The writers know how to
- * marshal a 32-bit representation from the 64-bit structure.
- */
-typedef Elf64_Ehdr ElfEhdr;
-typedef Elf64_Shdr ElfShdr;
-typedef Elf64_Phdr ElfPhdr;
-
-void	elfinit(void);
-ElfEhdr	*getElfEhdr(void);
-ElfShdr	*newElfShdr(vlong);
-ElfPhdr	*newElfPhdr(void);
-uint32	elfwritehdr(void);
-uint32	elfwritephdrs(void);
-uint32	elfwriteshdrs(void);
-void	elfwritedynent(LSym*, int, uint64);
-void	elfwritedynentsym(LSym*, int, LSym*);
-void	elfwritedynentsymsize(LSym*, int, LSym*);
-uint32	elfhash(uchar*);
-uint64	startelf(void);
-uint64	endelf(void);
-extern	int	numelfphdr;
-extern	int	numelfshdr;
-extern	int	iself;
-extern	int	elfverneed;
-int	elfinterp(ElfShdr*, uint64, uint64, char*);
-int	elfwriteinterp(void);
-int	elfnetbsdsig(ElfShdr*, uint64, uint64);
-int	elfwritenetbsdsig(void);
-int	elfopenbsdsig(ElfShdr*, uint64, uint64);
-int	elfwriteopenbsdsig(void);
-void	addbuildinfo(char*);
-int	elfbuildinfo(ElfShdr*, uint64, uint64);
-int	elfwritebuildinfo(void);
-void	elfdynhash(void);
-ElfPhdr* elfphload(Segment*);
-ElfShdr* elfshbits(Section*);
-ElfShdr* elfshalloc(Section*);
-ElfShdr* elfshname(char*);
-ElfShdr* elfshreloc(Section*);
-void	elfsetstring(char*, int);
-void	elfaddverneed(LSym*);
-void	elfemitreloc(void);
-void	shsym(ElfShdr*, LSym*);
-void	phsh(ElfPhdr*, ElfShdr*);
-void	doelf(void);
-void	elfsetupplt(void);
-void	dwarfaddshstrings(LSym*);
-void	dwarfaddelfsectionsyms(void);
-void	dwarfaddelfheaders(void);
-void	asmbelf(vlong symo);
-void	asmbelfsetup(void);
-extern char linuxdynld[];
-extern char freebsddynld[];
-extern char netbsddynld[];
-extern char openbsddynld[];
-extern char dragonflydynld[];
-extern char solarisdynld[];
-int	elfreloc1(Reloc*, vlong sectoff);
-void	putelfsectionsyms(void);
-
-EXTERN	int	elfstrsize;
-EXTERN	char*	elfstrdat;
-EXTERN	int	buildinfolen;
-
-/*
- * Total amount of space to reserve at the start of the file
- * for Header, PHeaders, SHeaders, and interp.
- * May waste some.
- * On FreeBSD, cannot be larger than a page.
- */
-#define	ELFRESERVE	3072
diff --git a/src/cmd/ld/go.c b/src/cmd/ld/go.c
deleted file mode 100644
index 9c296b7..0000000
--- a/src/cmd/ld/go.c
+++ /dev/null
@@ -1,861 +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.
-
-// go-specific code shared across loaders (5l, 6l, 8l).
-
-#include	"l.h"
-#include	"../ld/lib.h"
-
-// accumulate all type information from .6 files.
-// check for inconsistencies.
-
-// TODO:
-//	generate debugging section in binary.
-//	once the dust settles, try to move some code to
-//		libmach, so that other linkers and ar can share.
-
-/*
- *	package import data
- */
-typedef struct Import Import;
-struct Import
-{
-	Import *hash;	// next in hash table
-	char *prefix;	// "type", "var", "func", "const"
-	char *name;
-	char *def;
-	char *file;
-};
-enum {
-	NIHASH = 1024
-};
-static Import *ihash[NIHASH];
-static int nimport;
-static void imported(char *pkg, char *import);
-
-static int
-hashstr(char *name)
-{
-	uint32 h;
-	char *cp;
-
-	h = 0;
-	for(cp = name; *cp; h += *cp++)
-		h *= 1119;
-	h &= 0xffffff;
-	return h;
-}
-
-static Import *
-ilookup(char *name)
-{
-	int h;
-	Import *x;
-
-	h = hashstr(name) % NIHASH;
-	for(x=ihash[h]; x; x=x->hash)
-		if(x->name[0] == name[0] && strcmp(x->name, name) == 0)
-			return x;
-	x = mal(sizeof *x);
-	x->name = estrdup(name);
-	x->hash = ihash[h];
-	ihash[h] = x;
-	nimport++;
-	return x;
-}
-
-static void loadpkgdata(char*, char*, char*, int);
-static void loadcgo(char*, char*, char*, int);
-static int parsemethod(char**, char*, char**);
-static int parsepkgdata(char*, char*, char**, char*, char**, char**, char**);
-
-void
-ldpkg(Biobuf *f, char *pkg, int64 len, char *filename, int whence)
-{
-	char *data, *p0, *p1, *name;
-
-	if(debug['g'])
-		return;
-
-	if((int)len != len) {
-		fprint(2, "%s: too much pkg data in %s\n", argv0, filename);
-		if(debug['u'])
-			errorexit();
-		return;
-	}
-	data = mal(len+1);
-	if(Bread(f, data, len) != len) {
-		fprint(2, "%s: short pkg read %s\n", argv0, filename);
-		if(debug['u'])
-			errorexit();
-		return;
-	}
-	data[len] = '\0';
-
-	// first \n$$ marks beginning of exports - skip rest of line
-	p0 = strstr(data, "\n$$");
-	if(p0 == nil) {
-		if(debug['u'] && whence != ArchiveObj) {
-			fprint(2, "%s: cannot find export data in %s\n", argv0, filename);
-			errorexit();
-		}
-		return;
-	}
-	p0 += 3;
-	while(*p0 != '\n' && *p0 != '\0')
-		p0++;
-
-	// second marks end of exports / beginning of local data
-	p1 = strstr(p0, "\n$$");
-	if(p1 == nil) {
-		fprint(2, "%s: cannot find end of exports in %s\n", argv0, filename);
-		if(debug['u'])
-			errorexit();
-		return;
-	}
-	while(p0 < p1 && (*p0 == ' ' || *p0 == '\t' || *p0 == '\n'))
-		p0++;
-	if(p0 < p1) {
-		if(strncmp(p0, "package ", 8) != 0) {
-			fprint(2, "%s: bad package section in %s - %s\n", argv0, filename, p0);
-			if(debug['u'])
-				errorexit();
-			return;
-		}
-		p0 += 8;
-		while(p0 < p1 && (*p0 == ' ' || *p0 == '\t' || *p0 == '\n'))
-			p0++;
-		name = p0;
-		while(p0 < p1 && *p0 != ' ' && *p0 != '\t' && *p0 != '\n')
-			p0++;
-		if(debug['u'] && whence != ArchiveObj &&
-		   (p0+6 > p1 || memcmp(p0, " safe\n", 6) != 0)) {
-			fprint(2, "%s: load of unsafe package %s\n", argv0, filename);
-			nerrors++;
-			errorexit();
-		}
-		if(p0 < p1) {
-			if(*p0 == '\n')
-				*p0++ = '\0';
-			else {
-				*p0++ = '\0';
-				while(p0 < p1 && *p0++ != '\n')
-					;
-			}
-		}
-		if(strcmp(pkg, "main") == 0 && strcmp(name, "main") != 0) {
-			fprint(2, "%s: %s: not package main (package %s)\n", argv0, filename, name);
-			nerrors++;
-			errorexit();
-		}
-		loadpkgdata(filename, pkg, p0, p1 - p0);
-	}
-	
-	// __.PKGDEF has no cgo section - those are in the C compiler-generated object files.
-	if(whence == Pkgdef)
-		return;
-
-	// look for cgo section
-	p0 = strstr(p1, "\n$$  // cgo");
-	if(p0 != nil) {
-		p0 = strchr(p0+1, '\n');
-		if(p0 == nil) {
-			fprint(2, "%s: found $$ // cgo but no newline in %s\n", argv0, filename);
-			if(debug['u'])
-				errorexit();
-			return;
-		}
-		p1 = strstr(p0, "\n$$");
-		if(p1 == nil)
-			p1 = strstr(p0, "\n!\n");
-		if(p1 == nil) {
-			fprint(2, "%s: cannot find end of // cgo section in %s\n", argv0, filename);
-			if(debug['u'])
-				errorexit();
-			return;
-		}
-		loadcgo(filename, pkg, p0 + 1, p1 - (p0+1));
-	}
-}
-
-static void
-loadpkgdata(char *file, char *pkg, char *data, int len)
-{
-	char *p, *ep, *prefix, *name, *def;
-	Import *x;
-
-	file = estrdup(file);
-	p = data;
-	ep = data + len;
-	while(parsepkgdata(file, pkg, &p, ep, &prefix, &name, &def) > 0) {
-		x = ilookup(name);
-		if(x->prefix == nil) {
-			x->prefix = prefix;
-			x->def = estrdup(def);
-			x->file = file;
-		} else if(strcmp(x->prefix, prefix) != 0) {
-			fprint(2, "%s: conflicting definitions for %s\n", argv0, name);
-			fprint(2, "%s:\t%s %s ...\n", x->file, x->prefix, name);
-			fprint(2, "%s:\t%s %s ...\n", file, prefix, name);
-			nerrors++;
-		} else if(strcmp(x->def, def) != 0) {
-			fprint(2, "%s: conflicting definitions for %s\n", argv0, name);
-			fprint(2, "%s:\t%s %s %s\n", x->file, x->prefix, name, x->def);
-			fprint(2, "%s:\t%s %s %s\n", file, prefix, name, def);
-			nerrors++;
-		}
-		free(name);
-		free(def);
-	}
-	free(file);
-}
-
-static int
-parsepkgdata(char *file, char *pkg, char **pp, char *ep, char **prefixp, char **namep, char **defp)
-{
-	char *p, *prefix, *name, *def, *edef, *meth;
-	int n, inquote;
-
-	// skip white space
-	p = *pp;
-loop:
-	while(p < ep && (*p == ' ' || *p == '\t' || *p == '\n'))
-		p++;
-	if(p == ep || strncmp(p, "$$\n", 3) == 0)
-		return 0;
-
-	// prefix: (var|type|func|const)
-	prefix = p;
-	if(p + 7 > ep)
-		return -1;
-	if(strncmp(p, "var ", 4) == 0)
-		p += 4;
-	else if(strncmp(p, "type ", 5) == 0)
-		p += 5;
-	else if(strncmp(p, "func ", 5) == 0)
-		p += 5;
-	else if(strncmp(p, "const ", 6) == 0)
-		p += 6;
-	else if(strncmp(p, "import ", 7) == 0) {
-		p += 7;
-		while(p < ep && *p != ' ')
-			p++;
-		p++;
-		name = p;
-		while(p < ep && *p != '\n')
-			p++;
-		if(p >= ep) {
-			fprint(2, "%s: %s: confused in import line\n", argv0, file);
-			nerrors++;
-			return -1;
-		}
-		*p++ = '\0';
-		imported(pkg, name);
-		goto loop;
-	}
-	else {
-		fprint(2, "%s: %s: confused in pkg data near <<%.40s>>\n", argv0, file, prefix);
-		nerrors++;
-		return -1;
-	}
-	p[-1] = '\0';
-
-	// name: a.b followed by space
-	name = p;
-	inquote = 0;
-	while(p < ep) {
-		if (*p == ' ' && !inquote)
-			break;
-
-		if(*p == '\\')
-			p++;
-		else if(*p == '"')
-			inquote = !inquote;
-
-		p++;
-	}
-
-	if(p >= ep)
-		return -1;
-	*p++ = '\0';
-
-	// def: free form to new line
-	def = p;
-	while(p < ep && *p != '\n')
-		p++;
-	if(p >= ep)
-		return -1;
-	edef = p;
-	*p++ = '\0';
-
-	// include methods on successive lines in def of named type
-	while(parsemethod(&p, ep, &meth) > 0) {
-		*edef++ = '\n';	// overwrites '\0'
-		if(edef+1 > meth) {
-			// We want to indent methods with a single \t.
-			// 6g puts at least one char of indent before all method defs,
-			// so there will be room for the \t.  If the method def wasn't
-			// indented we could do something more complicated,
-			// but for now just diagnose the problem and assume
-			// 6g will keep indenting for us.
-			fprint(2, "%s: %s: expected methods to be indented %p %p %.10s\n", argv0,
-				file, edef, meth, meth);
-			nerrors++;
-			return -1;
-		}
-		*edef++ = '\t';
-		n = strlen(meth);
-		memmove(edef, meth, n);
-		edef += n;
-	}
-
-	name = expandpkg(name, pkg);
-	def = expandpkg(def, pkg);
-
-	// done
-	*pp = p;
-	*prefixp = prefix;
-	*namep = name;
-	*defp = def;
-	return 1;
-}
-
-static int
-parsemethod(char **pp, char *ep, char **methp)
-{
-	char *p;
-
-	// skip white space
-	p = *pp;
-	while(p < ep && (*p == ' ' || *p == '\t'))
-		p++;
-	if(p == ep)
-		return 0;
-
-	// might be a comment about the method
-	if(p + 2 < ep && strncmp(p, "//", 2) == 0)
-		goto useline;
-	
-	// if it says "func (", it's a method
-	if(p + 6 < ep && strncmp(p, "func (", 6) == 0)
-		goto useline;
-	return 0;
-
-useline:
-	// definition to end of line
-	*methp = p;
-	while(p < ep && *p != '\n')
-		p++;
-	if(p >= ep) {
-		fprint(2, "%s: lost end of line in method definition\n", argv0);
-		*pp = ep;
-		return -1;
-	}
-	*p++ = '\0';
-	*pp = p;
-	return 1;
-}
-
-static void
-loadcgo(char *file, char *pkg, char *p, int n)
-{
-	char *pend, *next, *p0, *q;
-	char *f[10], *local, *remote, *lib;
-	int nf;
-	LSym *s;
-
-	USED(file);
-	pend = p + n;
-	p0 = nil;
-	for(; p<pend; p=next) {
-		next = strchr(p, '\n');
-		if(next == nil)
-			next = "";
-		else
-			*next++ = '\0';
-
-		free(p0);
-		p0 = estrdup(p); // save for error message
-		nf = tokenize(p, f, nelem(f));
-		
-		if(strcmp(f[0], "cgo_import_dynamic") == 0) {
-			if(nf < 2 || nf > 4)
-				goto err;
-			
-			local = f[1];
-			remote = local;
-			if(nf > 2)
-				remote = f[2];
-			lib = "";
-			if(nf > 3)
-				lib = f[3];
-			
-			if(debug['d']) {
-				fprint(2, "%s: %s: cannot use dynamic imports with -d flag\n", argv0, file);
-				nerrors++;
-				return;
-			}
-		
-			if(strcmp(local, "_") == 0 && strcmp(remote, "_") == 0) {
-				// allow #pragma dynimport _ _ "foo.so"
-				// to force a link of foo.so.
-				havedynamic = 1;
-				adddynlib(lib);
-				continue;
-			}
-
-			local = expandpkg(local, pkg);
-			q = strchr(remote, '#');
-			if(q)
-				*q++ = '\0';
-			s = linklookup(ctxt, local, 0);
-			if(local != f[1])
-				free(local);
-			if(s->type == 0 || s->type == SXREF || s->type == SHOSTOBJ) {
-				s->dynimplib = lib;
-				s->extname = remote;
-				s->dynimpvers = q;
-				if(s->type != SHOSTOBJ)
-					s->type = SDYNIMPORT;
-				havedynamic = 1;
-			}
-			continue;
-		}
-		
-		if(strcmp(f[0], "cgo_import_static") == 0) {
-			if(nf != 2)
-				goto err;
-			local = f[1];
-			s = linklookup(ctxt, local, 0);
-			s->type = SHOSTOBJ;
-			s->size = 0;
-			continue;
-		}
-
-		if(strcmp(f[0], "cgo_export_static") == 0 || strcmp(f[0], "cgo_export_dynamic") == 0) {
-			// TODO: Remove once we know Windows is okay.
-			if(strcmp(f[0], "cgo_export_static") == 0 && HEADTYPE == Hwindows)
-				continue;
-
-			if(nf < 2 || nf > 3)
-				goto err;
-			local = f[1];
-			if(nf > 2)
-				remote = f[2];
-			else
-				remote = local;
-			local = expandpkg(local, pkg);
-			s = linklookup(ctxt, local, 0);
-
-			if(flag_shared && s == linklookup(ctxt, "main", 0))
-				continue;
-
-			// export overrides import, for openbsd/cgo.
-			// see issue 4878.
-			if(s->dynimplib != nil) {
-				s->dynimplib = nil;
-				s->extname = nil;
-				s->dynimpvers = nil;
-				s->type = 0;
-			}
-
-			if(s->cgoexport == 0) {
-				s->extname = remote;
-				if(ndynexp%32 == 0)
-					dynexp = erealloc(dynexp, (ndynexp+32)*sizeof dynexp[0]);
-				dynexp[ndynexp++] = s;
-			} else if(strcmp(s->extname, remote) != 0) {
-				fprint(2, "%s: conflicting cgo_export directives: %s as %s and %s\n", argv0, s->name, s->extname, remote);
-				nerrors++;
-				return;
-			}
-			if(strcmp(f[0], "cgo_export_static") == 0)
-				s->cgoexport |= CgoExportStatic;
-			else
-				s->cgoexport |= CgoExportDynamic;
-			if(local != f[1])
-				free(local);
-			continue;
-		}
-		
-		if(strcmp(f[0], "cgo_dynamic_linker") == 0) {
-			if(nf != 2)
-				goto err;
-			
-			if(!debug['I']) { // not overridden by command line
-				if(interpreter != nil && strcmp(interpreter, f[1]) != 0) {
-					fprint(2, "%s: conflict dynlinker: %s and %s\n", argv0, interpreter, f[1]);
-					nerrors++;
-					return;
-				}
-				free(interpreter);
-				interpreter = estrdup(f[1]);
-			}
-			continue;
-		}
-		
-		if(strcmp(f[0], "cgo_ldflag") == 0) {
-			if(nf != 2)
-				goto err;
-			if(nldflag%32 == 0)
-				ldflag = erealloc(ldflag, (nldflag+32)*sizeof ldflag[0]);
-			ldflag[nldflag++] = estrdup(f[1]);
-			continue;
-		}
-	}
-	free(p0);
-	return;
-
-err:
-	fprint(2, "%s: %s: invalid dynimport line: %s\n", argv0, file, p0);
-	nerrors++;
-}
-
-static LSym *markq;
-static LSym *emarkq;
-
-static void
-mark1(LSym *s, LSym *parent)
-{
-	if(s == S || s->reachable)
-		return;
-	if(strncmp(s->name, "go.weak.", 8) == 0)
-		return;
-	s->reachable = 1;
-	s->reachparent = parent;
-	if(markq == nil)
-		markq = s;
-	else
-		emarkq->queue = s;
-	emarkq = s;
-}
-
-void
-mark(LSym *s)
-{
-	mark1(s, nil);
-}
-
-static void
-markflood(void)
-{
-	Auto *a;
-	LSym *s;
-	int i;
-	
-	for(s=markq; s!=S; s=s->queue) {
-		if(s->type == STEXT) {
-			if(debug['v'] > 1)
-				Bprint(&bso, "marktext %s\n", s->name);
-			for(a=s->autom; a; a=a->link)
-				mark1(a->gotype, s);
-		}
-		for(i=0; i<s->nr; i++)
-			mark1(s->r[i].sym, s);
-		if(s->pcln) {
-			for(i=0; i<s->pcln->nfuncdata; i++)
-				mark1(s->pcln->funcdata[i], s);
-		}
-		mark1(s->gotype, s);
-		mark1(s->sub, s);
-		mark1(s->outer, s);
-	}
-}
-
-static char*
-markextra[] =
-{
-	"runtime.morestack",
-	"runtime.morestackx",
-
-	"runtime.morestack00",
-	"runtime.morestack10",
-	"runtime.morestack01",
-	"runtime.morestack11",
-
-	"runtime.morestack8",
-	"runtime.morestack16",
-	"runtime.morestack24",
-	"runtime.morestack32",
-	"runtime.morestack40",
-	"runtime.morestack48",
-	
-	// on arm, lock in the div/mod helpers too
-	"_div",
-	"_divu",
-	"_mod",
-	"_modu",
-};
-
-void
-deadcode(void)
-{
-	int i;
-	LSym *s, *last, *p;
-	Fmt fmt;
-
-	if(debug['v'])
-		Bprint(&bso, "%5.2f deadcode\n", cputime());
-
-	mark(linklookup(ctxt, INITENTRY, 0));
-	for(i=0; i<nelem(markextra); i++)
-		mark(linklookup(ctxt, markextra[i], 0));
-
-	for(i=0; i<ndynexp; i++)
-		mark(dynexp[i]);
-
-	markflood();
-	
-	// keep each beginning with 'typelink.' if the symbol it points at is being kept.
-	for(s = ctxt->allsym; s != S; s = s->allsym) {
-		if(strncmp(s->name, "go.typelink.", 12) == 0)
-			s->reachable = s->nr==1 && s->r[0].sym->reachable;
-	}
-
-	// remove dead text but keep file information (z symbols).
-	last = nil;
-	for(s = ctxt->textp; s != nil; s = s->next) {
-		if(!s->reachable)
-			continue;
-		// NOTE: Removing s from old textp and adding to new, shorter textp.
-		if(last == nil)
-			ctxt->textp = s;
-		else
-			last->next = s;
-		last = s;
-	}
-	if(last == nil)
-		ctxt->textp = nil;
-	else
-		last->next = nil;
-	
-	for(s = ctxt->allsym; s != S; s = s->allsym)
-		if(strncmp(s->name, "go.weak.", 8) == 0) {
-			s->special = 1;  // do not lay out in data segment
-			s->reachable = 1;
-			s->hide = 1;
-		}
-	
-	// record field tracking references
-	fmtstrinit(&fmt);
-	for(s = ctxt->allsym; s != S; s = s->allsym) {
-		if(strncmp(s->name, "go.track.", 9) == 0) {
-			s->special = 1;  // do not lay out in data segment
-			s->hide = 1;
-			if(s->reachable) {
-				fmtprint(&fmt, "%s", s->name+9);
-				for(p=s->reachparent; p; p=p->reachparent)
-					fmtprint(&fmt, "\t%s", p->name);
-				fmtprint(&fmt, "\n");
-			}
-			s->type = SCONST;
-			s->value = 0;
-		}
-	}
-	if(tracksym == nil)
-		return;
-	s = linklookup(ctxt, tracksym, 0);
-	if(!s->reachable)
-		return;
-	addstrdata(tracksym, fmtstrflush(&fmt));
-}
-
-void
-doweak(void)
-{
-	LSym *s, *t;
-
-	// resolve weak references only if
-	// target symbol will be in binary anyway.
-	for(s = ctxt->allsym; s != S; s = s->allsym) {
-		if(strncmp(s->name, "go.weak.", 8) == 0) {
-			t = linkrlookup(ctxt, s->name+8, s->version);
-			if(t && t->type != 0 && t->reachable) {
-				s->value = t->value;
-				s->type = t->type;
-				s->outer = t;
-			} else {
-				s->type = SCONST;
-				s->value = 0;
-			}
-			continue;
-		}
-	}
-}
-
-void
-addexport(void)
-{
-	int i;
-	
-	if(HEADTYPE == Hdarwin)
-		return;
-
-	for(i=0; i<ndynexp; i++)
-		adddynsym(ctxt, dynexp[i]);
-}
-
-/* %Z from gc, for quoting import paths */
-int
-Zconv(Fmt *fp)
-{
-	Rune r;
-	char *s, *se;
-	int n;
-
-	s = va_arg(fp->args, char*);
-	if(s == nil)
-		return fmtstrcpy(fp, "<nil>");
-
-	se = s + strlen(s);
-
-	// NOTE: Keep in sync with ../gc/go.c:/^Zconv.
-	while(s < se) {
-		n = chartorune(&r, s);
-		s += n;
-		switch(r) {
-		case Runeerror:
-			if(n == 1) {
-				fmtprint(fp, "\\x%02x", (uchar)*(s-1));
-				break;
-			}
-			// fall through
-		default:
-			if(r < ' ') {
-				fmtprint(fp, "\\x%02x", r);
-				break;
-			}
-			fmtrune(fp, r);
-			break;
-		case '\t':
-			fmtstrcpy(fp, "\\t");
-			break;
-		case '\n':
-			fmtstrcpy(fp, "\\n");
-			break;
-		case '\"':
-		case '\\':
-			fmtrune(fp, '\\');
-			fmtrune(fp, r);
-			break;
-		case 0xFEFF: // BOM, basically disallowed in source code
-			fmtstrcpy(fp, "\\uFEFF");
-			break;
-		}
-	}
-	return 0;
-}
-
-
-typedef struct Pkg Pkg;
-struct Pkg
-{
-	uchar mark;
-	uchar checked;
-	Pkg *next;
-	char *path;
-	Pkg **impby;
-	int nimpby;
-	int mimpby;
-	Pkg *all;
-};
-
-static Pkg *phash[1024];
-static Pkg *pkgall;
-
-static Pkg*
-getpkg(char *path)
-{
-	Pkg *p;
-	int h;
-	
-	h = hashstr(path) % nelem(phash);
-	for(p=phash[h]; p; p=p->next)
-		if(strcmp(p->path, path) == 0)
-			return p;
-	p = mal(sizeof *p);
-	p->path = estrdup(path);
-	p->next = phash[h];
-	phash[h] = p;
-	p->all = pkgall;
-	pkgall = p;
-	return p;
-}
-
-static void
-imported(char *pkg, char *import)
-{
-	Pkg *p, *i;
-	
-	// everyone imports runtime, even runtime.
-	if(strcmp(import, "\"runtime\"") == 0)
-		return;
-
-	pkg = smprint("\"%Z\"", pkg);  // turn pkg path into quoted form, freed below
-	p = getpkg(pkg);
-	i = getpkg(import);
-	if(i->nimpby >= i->mimpby) {
-		i->mimpby *= 2;
-		if(i->mimpby == 0)
-			i->mimpby = 16;
-		i->impby = erealloc(i->impby, i->mimpby*sizeof i->impby[0]);
-	}
-	i->impby[i->nimpby++] = p;
-	free(pkg);
-}
-
-static Pkg*
-cycle(Pkg *p)
-{
-	int i;
-	Pkg *bad;
-
-	if(p->checked)
-		return 0;
-
-	if(p->mark) {
-		nerrors++;
-		print("import cycle:\n");
-		print("\t%s\n", p->path);
-		return p;
-	}
-	p->mark = 1;
-	for(i=0; i<p->nimpby; i++) {
-		if((bad = cycle(p->impby[i])) != nil) {
-			p->mark = 0;
-			p->checked = 1;
-			print("\timports %s\n", p->path);
-			if(bad == p)
-				return nil;
-			return bad;
-		}
-	}
-	p->checked = 1;
-	p->mark = 0;
-	return 0;
-}
-
-void
-importcycles(void)
-{
-	Pkg *p;
-	
-	for(p=pkgall; p; p=p->all)
-		cycle(p);
-}
-
-void
-setlinkmode(char *arg)
-{
-	if(strcmp(arg, "internal") == 0)
-		linkmode = LinkInternal;
-	else if(strcmp(arg, "external") == 0)
-		linkmode = LinkExternal;
-	else if(strcmp(arg, "auto") == 0)
-		linkmode = LinkAuto;
-	else {
-		fprint(2, "unknown link mode -linkmode %s\n", arg);
-		errorexit();
-	}
-}
diff --git a/src/cmd/ld/ldelf.c b/src/cmd/ld/ldelf.c
deleted file mode 100644
index dd5fa0d..0000000
--- a/src/cmd/ld/ldelf.c
+++ /dev/null
@@ -1,905 +0,0 @@
-/*
-Derived from Plan 9 from User Space's src/libmach/elf.h, elf.c
-http://code.swtch.com/plan9port/src/tip/src/libmach/
-
-	Copyright © 2004 Russ Cox.
-	Portions Copyright © 2008-2010 Google Inc.
-	Portions Copyright © 2010 The Go Authors.
-
-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.
-*/
-
-#include	"l.h"
-#include	"lib.h"
-#include	"../ld/elf.h"
-
-enum
-{
-	ElfClassNone = 0,
-	ElfClass32,
-	ElfClass64,
-
-	ElfDataNone = 0,
-	ElfDataLsb,
-	ElfDataMsb,
-
-	ElfTypeNone = 0,
-	ElfTypeRelocatable,
-	ElfTypeExecutable,
-	ElfTypeSharedObject,
-	ElfTypeCore,
-	/* 0xFF00 - 0xFFFF reserved for processor-specific types */
-
-	ElfMachNone = 0,
-	ElfMach32100,		/* AT&T WE 32100 */
-	ElfMachSparc,		/* SPARC */
-	ElfMach386,		/* Intel 80386 */
-	ElfMach68000,		/* Motorola 68000 */
-	ElfMach88000,		/* Motorola 88000 */
-	ElfMach486,		/* Intel 80486, no longer used */
-	ElfMach860,		/* Intel 80860 */
-	ElfMachMips,		/* MIPS RS3000 */
-	ElfMachS370,		/* IBM System/370 */
-	ElfMachMipsLe,	/* MIPS RS3000 LE */
-	ElfMachParisc = 15,		/* HP PA RISC */
-	ElfMachVpp500 = 17,	/* Fujitsu VPP500 */
-	ElfMachSparc32Plus,	/* SPARC V8+ */
-	ElfMach960,		/* Intel 80960 */
-	ElfMachPower,		/* PowerPC */
-	ElfMachPower64,	/* PowerPC 64 */
-	ElfMachS390,		/* IBM System/390 */
-	ElfMachV800 = 36,	/* NEC V800 */
-	ElfMachFr20,		/* Fujitsu FR20 */
-	ElfMachRh32,		/* TRW RH-32 */
-	ElfMachRce,		/* Motorola RCE */
-	ElfMachArm,		/* ARM */
-	ElfMachAlpha,		/* Digital Alpha */
-	ElfMachSH,		/* Hitachi SH */
-	ElfMachSparc9,		/* SPARC V9 */
-	ElfMachAmd64 = 62,
-	/* and the list goes on... */
-
-	ElfAbiNone = 0,
-	ElfAbiSystemV = 0,	/* [sic] */
-	ElfAbiHPUX,
-	ElfAbiNetBSD,
-	ElfAbiLinux,
-	ElfAbiSolaris = 6,
-	ElfAbiAix,
-	ElfAbiIrix,
-	ElfAbiFreeBSD,
-	ElfAbiTru64,
-	ElfAbiModesto,
-	ElfAbiOpenBSD,
-	ElfAbiARM = 97,
-	ElfAbiEmbedded = 255,
-
-	/* some of sections 0xFF00 - 0xFFFF reserved for various things */
-	ElfSectNone = 0,
-	ElfSectProgbits,
-	ElfSectSymtab,
-	ElfSectStrtab,
-	ElfSectRela,
-	ElfSectHash,
-	ElfSectDynamic,
-	ElfSectNote,
-	ElfSectNobits,
-	ElfSectRel,
-	ElfSectShlib,
-	ElfSectDynsym,
-
-	ElfSectFlagWrite = 0x1,
-	ElfSectFlagAlloc = 0x2,
-	ElfSectFlagExec = 0x4,
-	/* 0xF0000000 are reserved for processor specific */
-
-	ElfSymBindLocal = 0,
-	ElfSymBindGlobal,
-	ElfSymBindWeak,
-	/* 13-15 reserved */
-
-	ElfSymTypeNone = 0,
-	ElfSymTypeObject,
-	ElfSymTypeFunc,
-	ElfSymTypeSection,
-	ElfSymTypeFile,
-	/* 13-15 reserved */
-
-	ElfSymShnNone = 0,
-	ElfSymShnAbs = 0xFFF1,
-	ElfSymShnCommon = 0xFFF2,
-	/* 0xFF00-0xFF1F reserved for processors */
-	/* 0xFF20-0xFF3F reserved for operating systems */
-
-	ElfProgNone = 0,
-	ElfProgLoad,
-	ElfProgDynamic,
-	ElfProgInterp,
-	ElfProgNote,
-	ElfProgShlib,
-	ElfProgPhdr,
-
-	ElfProgFlagExec = 0x1,
-	ElfProgFlagWrite = 0x2,
-	ElfProgFlagRead = 0x4,
-
-	ElfNotePrStatus = 1,
-	ElfNotePrFpreg = 2,
-	ElfNotePrPsinfo = 3,
-	ElfNotePrTaskstruct = 4,
-	ElfNotePrAuxv = 6,
-	ElfNotePrXfpreg = 0x46e62b7f	/* for gdb/386 */
-};
-
-typedef struct ElfHdrBytes ElfHdrBytes;
-typedef struct ElfSectBytes ElfSectBytes;
-typedef struct ElfProgBytes ElfProgBytes;
-typedef struct ElfSymBytes ElfSymBytes;
-
-typedef struct ElfHdrBytes64 ElfHdrBytes64;
-typedef struct ElfSectBytes64 ElfSectBytes64;
-typedef struct ElfProgBytes64 ElfProgBytes64;
-typedef struct ElfSymBytes64 ElfSymBytes64;
-
-struct ElfHdrBytes
-{
-	uchar	ident[16];
-	uchar	type[2];
-	uchar	machine[2];
-	uchar	version[4];
-	uchar	entry[4];
-	uchar	phoff[4];
-	uchar	shoff[4];
-	uchar	flags[4];
-	uchar	ehsize[2];
-	uchar	phentsize[2];
-	uchar	phnum[2];
-	uchar	shentsize[2];
-	uchar	shnum[2];
-	uchar	shstrndx[2];
-};
-
-struct ElfHdrBytes64
-{
-	uchar	ident[16];
-	uchar	type[2];
-	uchar	machine[2];
-	uchar	version[4];
-	uchar	entry[8];
-	uchar	phoff[8];
-	uchar	shoff[8];
-	uchar	flags[4];
-	uchar	ehsize[2];
-	uchar	phentsize[2];
-	uchar	phnum[2];
-	uchar	shentsize[2];
-	uchar	shnum[2];
-	uchar	shstrndx[2];
-};
-
-struct ElfSectBytes
-{
-	uchar	name[4];
-	uchar	type[4];
-	uchar	flags[4];
-	uchar	addr[4];
-	uchar	off[4];
-	uchar	size[4];
-	uchar	link[4];
-	uchar	info[4];
-	uchar	align[4];
-	uchar	entsize[4];
-};
-
-struct ElfSectBytes64
-{
-	uchar	name[4];
-	uchar	type[4];
-	uchar	flags[8];
-	uchar	addr[8];
-	uchar	off[8];
-	uchar	size[8];
-	uchar	link[4];
-	uchar	info[4];
-	uchar	align[8];
-	uchar	entsize[8];
-};
-
-struct ElfSymBytes
-{
-	uchar	name[4];
-	uchar	value[4];
-	uchar	size[4];
-	uchar	info;	/* top4: bind, bottom4: type */
-	uchar	other;
-	uchar	shndx[2];
-};
-
-struct ElfSymBytes64
-{
-	uchar	name[4];
-	uchar	info;	/* top4: bind, bottom4: type */
-	uchar	other;
-	uchar	shndx[2];
-	uchar	value[8];
-	uchar	size[8];
-};
-
-typedef struct ElfSect ElfSect;
-typedef struct ElfObj ElfObj;
-typedef struct ElfSym ElfSym;
-
-struct ElfSect
-{
-	char		*name;
-	uint32	type;
-	uint64	flags;
-	uint64	addr;
-	uint64	off;
-	uint64	size;
-	uint32	link;
-	uint32	info;
-	uint64	align;
-	uint64	entsize;
-	uchar	*base;
-	LSym	*sym;
-};
-
-struct ElfObj
-{
-	Biobuf	*f;
-	int64	base;	// offset in f where ELF begins
-	int64	len;		// length of ELF
-	int	is64;
-	char	*name;
-
-	Endian	*e;
-	ElfSect	*sect;
-	uint		nsect;
-	char		*shstrtab;
-	int		nsymtab;
-	ElfSect	*symtab;
-	ElfSect	*symstr;
-
-	uint32	type;
-	uint32	machine;
-	uint32	version;
-	uint64	entry;
-	uint64	phoff;
-	uint64	shoff;
-	uint32	flags;
-	uint32	ehsize;
-	uint32	phentsize;
-	uint32	phnum;
-	uint32	shentsize;
-	uint32	shnum;
-	uint32	shstrndx;
-};
-
-struct ElfSym
-{
-	char*	name;
-	uint64	value;
-	uint64	size;
-	uchar	bind;
-	uchar	type;
-	uchar	other;
-	uint16	shndx;
-	LSym*	sym;
-};
-
-uchar ElfMagic[4] = { 0x7F, 'E', 'L', 'F' };
-
-static ElfSect*	section(ElfObj*, char*);
-static int	map(ElfObj*, ElfSect*);
-static int	readsym(ElfObj*, int i, ElfSym*, int);
-static int	reltype(char*, int, uchar*);
-
-int
-valuecmp(LSym *a, LSym *b)
-{
-	if(a->value < b->value)
-		return -1;
-	if(a->value > b->value)
-		return +1;
-	return 0;
-}
-
-void
-ldelf(Biobuf *f, char *pkg, int64 len, char *pn)
-{
-	int32 base;
-	uint64 add, info;
-	char *name;
-	int i, j, rela, is64, n;
-	uchar hdrbuf[64];
-	uchar *p;
-	ElfHdrBytes *hdr;
-	ElfObj *obj;
-	ElfSect *sect, *rsect;
-	ElfSym sym;
-	Endian *e;
-	Reloc *r, *rp;
-	LSym *s;
-	LSym **symbols;
-
-	symbols = nil;
-
-	if(debug['v'])
-		Bprint(&bso, "%5.2f ldelf %s\n", cputime(), pn);
-
-	ctxt->version++;
-	base = Boffset(f);
-
-	if(Bread(f, hdrbuf, sizeof hdrbuf) != sizeof hdrbuf)
-		goto bad;
-	hdr = (ElfHdrBytes*)hdrbuf;
-	if(memcmp(hdr->ident, ElfMagic, 4) != 0)
-		goto bad;
-	switch(hdr->ident[5]) {
-	case ElfDataLsb:
-		e = ≤
-		break;
-	case ElfDataMsb:
-		e = &be;
-		break;
-	default:
-		goto bad;
-	}
-
-	// read header
-	obj = mal(sizeof *obj);
-	obj->e = e;
-	obj->f = f;
-	obj->base = base;
-	obj->len = len;
-	obj->name = pn;
-	
-	is64 = 0;
-	if(hdr->ident[4] == ElfClass64) {
-		ElfHdrBytes64* hdr;
-
-		is64 = 1;
-		hdr = (ElfHdrBytes64*)hdrbuf;
-		obj->type = e->e16(hdr->type);
-		obj->machine = e->e16(hdr->machine);
-		obj->version = e->e32(hdr->version);
-		obj->phoff = e->e64(hdr->phoff);
-		obj->shoff = e->e64(hdr->shoff);
-		obj->flags = e->e32(hdr->flags);
-		obj->ehsize = e->e16(hdr->ehsize);
-		obj->phentsize = e->e16(hdr->phentsize);
-		obj->phnum = e->e16(hdr->phnum);
-		obj->shentsize = e->e16(hdr->shentsize);
-		obj->shnum = e->e16(hdr->shnum);
-		obj->shstrndx = e->e16(hdr->shstrndx);
-	} else {
-		obj->type = e->e16(hdr->type);
-		obj->machine = e->e16(hdr->machine);
-		obj->version = e->e32(hdr->version);
-		obj->entry = e->e32(hdr->entry);
-		obj->phoff = e->e32(hdr->phoff);
-		obj->shoff = e->e32(hdr->shoff);
-		obj->flags = e->e32(hdr->flags);
-		obj->ehsize = e->e16(hdr->ehsize);
-		obj->phentsize = e->e16(hdr->phentsize);
-		obj->phnum = e->e16(hdr->phnum);
-		obj->shentsize = e->e16(hdr->shentsize);
-		obj->shnum = e->e16(hdr->shnum);
-		obj->shstrndx = e->e16(hdr->shstrndx);
-	}
-	obj->is64 = is64;
-	
-	if(hdr->ident[6] != obj->version)
-		goto bad;
-
-	if(e->e16(hdr->type) != ElfTypeRelocatable) {
-		diag("%s: elf but not elf relocatable object", pn);
-		return;
-	}
-
-	switch(thechar) {
-	default:
-		diag("%s: elf %s unimplemented", pn, thestring);
-		return;
-	case '5':
-		if(e != &le || obj->machine != ElfMachArm || hdr->ident[4] != ElfClass32) {
-			diag("%s: elf object but not arm", pn);
-			return;
-		}
-		break;
-	case '6':
-		if(e != &le || obj->machine != ElfMachAmd64 || hdr->ident[4] != ElfClass64) {
-			diag("%s: elf object but not amd64", pn);
-			return;
-		}
-		break;
-	case '8':
-		if(e != &le || obj->machine != ElfMach386 || hdr->ident[4] != ElfClass32) {
-			diag("%s: elf object but not 386", pn);
-			return;
-		}
-		break;
-	}
-
-	// load section list into memory.
-	obj->sect = mal(obj->shnum*sizeof obj->sect[0]);
-	obj->nsect = obj->shnum;
-	for(i=0; i<obj->nsect; i++) {
-		if(Bseek(f, base+obj->shoff+i*obj->shentsize, 0) < 0)
-			goto bad;
-		sect = &obj->sect[i];
-		if(is64) {
-			ElfSectBytes64 b;
-
-			werrstr("short read");
-			if(Bread(f, &b, sizeof b) != sizeof b)
-				goto bad;
-
-			sect->name = (char*)(uintptr)e->e32(b.name);
-			sect->type = e->e32(b.type);
-			sect->flags = e->e64(b.flags);
-			sect->addr = e->e64(b.addr);
-			sect->off = e->e64(b.off);
-			sect->size = e->e64(b.size);
-			sect->link = e->e32(b.link);
-			sect->info = e->e32(b.info);
-			sect->align = e->e64(b.align);
-			sect->entsize = e->e64(b.entsize);
-		} else {
-			ElfSectBytes b;
-
-			werrstr("short read");
-			if(Bread(f, &b, sizeof b) != sizeof b)
-				goto bad;
-		
-			sect->name = (char*)(uintptr)e->e32(b.name);
-			sect->type = e->e32(b.type);
-			sect->flags = e->e32(b.flags);
-			sect->addr = e->e32(b.addr);
-			sect->off = e->e32(b.off);
-			sect->size = e->e32(b.size);
-			sect->link = e->e32(b.link);
-			sect->info = e->e32(b.info);
-			sect->align = e->e32(b.align);
-			sect->entsize = e->e32(b.entsize);
-		}
-	}
-
-	// read section string table and translate names
-	if(obj->shstrndx >= obj->nsect) {
-		werrstr("shstrndx out of range %d >= %d", obj->shstrndx, obj->nsect);
-		goto bad;
-	}
-	sect = &obj->sect[obj->shstrndx];
-	if(map(obj, sect) < 0)
-		goto bad;
-	for(i=0; i<obj->nsect; i++)
-		if(obj->sect[i].name != nil)
-			obj->sect[i].name = (char*)sect->base + (uintptr)obj->sect[i].name;
-	
-	// load string table for symbols into memory.
-	obj->symtab = section(obj, ".symtab");
-	if(obj->symtab == nil) {
-		// our work is done here - no symbols means nothing can refer to this file
-		return;
-	}
-	if(obj->symtab->link <= 0 || obj->symtab->link >= obj->nsect) {
-		diag("%s: elf object has symbol table with invalid string table link", pn);
-		return;
-	}
-	obj->symstr = &obj->sect[obj->symtab->link];
-	if(is64)
-		obj->nsymtab = obj->symtab->size / sizeof(ElfSymBytes64);
-	else
-		obj->nsymtab = obj->symtab->size / sizeof(ElfSymBytes);
-	
-	if(map(obj, obj->symtab) < 0)
-		goto bad;
-	if(map(obj, obj->symstr) < 0)
-		goto bad;
-
-	// load text and data segments into memory.
-	// they are not as small as the section lists, but we'll need
-	// the memory anyway for the symbol images, so we might
-	// as well use one large chunk.
-	
-	// create symbols for mapped sections
-	for(i=0; i<obj->nsect; i++) {
-		sect = &obj->sect[i];
-		if((sect->type != ElfSectProgbits && sect->type != ElfSectNobits) || !(sect->flags&ElfSectFlagAlloc))
-			continue;
-		if(sect->type != ElfSectNobits && map(obj, sect) < 0)
-			goto bad;
-		
-		name = smprint("%s(%s)", pkg, sect->name);
-		s = linklookup(ctxt, name, ctxt->version);
-		free(name);
-		switch((int)sect->flags&(ElfSectFlagAlloc|ElfSectFlagWrite|ElfSectFlagExec)) {
-		default:
-			werrstr("unexpected flags for ELF section %s", sect->name);
-			goto bad;
-		case ElfSectFlagAlloc:
-			s->type = SRODATA;
-			break;
-		case ElfSectFlagAlloc + ElfSectFlagWrite:
-			if(sect->type == ElfSectNobits)
-				s->type = SNOPTRBSS;
-			else
-				s->type = SNOPTRDATA;
-			break;
-		case ElfSectFlagAlloc + ElfSectFlagExec:
-			s->type = STEXT;
-			break;
-		}
-		if(sect->type == ElfSectProgbits) {
-			s->p = sect->base;
-			s->np = sect->size;
-		}
-		s->size = sect->size;
-		s->align = sect->align;
-		sect->sym = s;
-	}
-
-	// enter sub-symbols into symbol table.
-	// symbol 0 is the null symbol.
-	symbols = malloc(obj->nsymtab * sizeof(symbols[0]));
-	if(symbols == nil) {
-		diag("out of memory");
-		errorexit();
-	}
-	for(i=1; i<obj->nsymtab; i++) {
-		if(readsym(obj, i, &sym, 1) < 0)
-			goto bad;
-		symbols[i] = sym.sym;
-		if(sym.type != ElfSymTypeFunc && sym.type != ElfSymTypeObject && sym.type != ElfSymTypeNone)
-			continue;
-		if(sym.shndx == ElfSymShnCommon) {
-			s = sym.sym;
-			if(s->size < sym.size)
-				s->size = sym.size;
-			if(s->type == 0 || s->type == SXREF)
-				s->type = SNOPTRBSS;
-			continue;
-		}
-		if(sym.shndx >= obj->nsect || sym.shndx == 0)
-			continue;
-		// even when we pass needSym == 1 to readsym, it might still return nil to skip some unwanted symbols
-		if(sym.sym == S)
-			continue;
-		sect = obj->sect+sym.shndx;
-		if(sect->sym == nil) {
-			if(strncmp(sym.name, ".Linfo_string", 13) == 0) // clang does this
-				continue;
-			diag("%s: sym#%d: ignoring %s in section %d (type %d)", pn, i, sym.name, sym.shndx, sym.type);
-			continue;
-		}
-		s = sym.sym;
-		if(s->outer != S) {
-			if(s->dupok)
-				continue;
-			diag("%s: duplicate symbol reference: %s in both %s and %s", pn, s->name, s->outer->name, sect->sym->name);
-			errorexit();
-		}
-		s->sub = sect->sym->sub;
-		sect->sym->sub = s;
-		s->type = sect->sym->type | (s->type&~SMASK) | SSUB;
-		if(!(s->cgoexport & CgoExportDynamic))
-			s->dynimplib = nil;  // satisfy dynimport
-		s->value = sym.value;
-		s->size = sym.size;
-		s->outer = sect->sym;
-		if(sect->sym->type == STEXT) {
-			if(s->external && !s->dupok)
-					diag("%s: duplicate definition of %s", pn, s->name);
-			s->external = 1;
-		}
-	}
-	
-	// Sort outer lists by address, adding to textp.
-	// This keeps textp in increasing address order.
-	for(i=0; i<obj->nsect; i++) {
-		s = obj->sect[i].sym;
-		if(s == S)
-			continue;
-		if(s->sub)
-			s->sub = listsort(s->sub, valuecmp, offsetof(LSym, sub));
-		if(s->type == STEXT) {
-			if(s->onlist)
-				sysfatal("symbol %s listed multiple times", s->name);
-			s->onlist = 1;
-			if(ctxt->etextp)
-				ctxt->etextp->next = s;
-			else
-				ctxt->textp = s;
-			ctxt->etextp = s;
-			for(s = s->sub; s != S; s = s->sub) {
-				if(s->onlist)
-					sysfatal("symbol %s listed multiple times", s->name);
-				s->onlist = 1;
-				ctxt->etextp->next = s;
-				ctxt->etextp = s;
-			}
-		}
-	}
-
-	// load relocations
-	for(i=0; i<obj->nsect; i++) {
-		rsect = &obj->sect[i];
-		if(rsect->type != ElfSectRela && rsect->type != ElfSectRel)
-			continue;
-		if(rsect->info >= obj->nsect || obj->sect[rsect->info].base == nil)
-			continue;
-		sect = &obj->sect[rsect->info];
-		if(map(obj, rsect) < 0)
-			goto bad;
-		rela = rsect->type == ElfSectRela;
-		n = rsect->size/(4+4*is64)/(2+rela);
-		r = mal(n*sizeof r[0]);
-		p = rsect->base;
-		for(j=0; j<n; j++) {
-			add = 0;
-			rp = &r[j];
-			if(is64) {
-				// 64-bit rel/rela
-				rp->off = e->e64(p);
-				p += 8;
-				info = e->e64(p);
-				p += 8;
-				if(rela) {
-					add = e->e64(p);
-					p += 8;
-				}
-			} else {
-				// 32-bit rel/rela
-				rp->off = e->e32(p);
-				p += 4;
-				info = e->e32(p);
-				info = info>>8<<32 | (info&0xff);	// convert to 64-bit info
-				p += 4;
-				if(rela) {
-					add = e->e32(p);
-					p += 4;
-				}
-			}
-			if((info & 0xffffffff) == 0) { // skip R_*_NONE relocation
-				j--;
-				n--;
-				continue;
-			}
-			if((info >> 32) == 0) { // absolute relocation, don't bother reading the null symbol
-				rp->sym = S;
-			} else {
-				if(readsym(obj, info>>32, &sym, 0) < 0)
-					goto bad;
-				sym.sym = symbols[info>>32];
-				if(sym.sym == nil) {
-					werrstr("%s#%d: reloc of invalid sym #%d %s shndx=%d type=%d",
-						sect->sym->name, j, (int)(info>>32), sym.name, sym.shndx, sym.type);
-					goto bad;
-				}
-				rp->sym = sym.sym;
-			}
-			rp->type = reltype(pn, (uint32)info, &rp->siz);
-			if(rela)
-				rp->add = add;
-			else {
-				// load addend from image
-				if(rp->siz == 4)
-					rp->add = e->e32(sect->base+rp->off);
-				else if(rp->siz == 8)
-					rp->add = e->e64(sect->base+rp->off);
-				else
-					diag("invalid rela size %d", rp->siz);
-			}
-			if(rp->siz == 4)
-				rp->add = (int32)rp->add;
-			//print("rel %s %d %d %s %#llx\n", sect->sym->name, rp->type, rp->siz, rp->sym->name, rp->add);
-		}
-		qsort(r, n, sizeof r[0], rbyoff);	// just in case
-		
-		s = sect->sym;
-		s->r = r;
-		s->nr = n;
-	}
-	free(symbols);
-
-	return;
-
-bad:
-	diag("%s: malformed elf file: %r", pn);
-	free(symbols);
-}
-
-static ElfSect*
-section(ElfObj *obj, char *name)
-{
-	int i;
-	
-	for(i=0; i<obj->nsect; i++)
-		if(obj->sect[i].name && name && strcmp(obj->sect[i].name, name) == 0)
-			return &obj->sect[i];
-	return nil;
-}
-
-static int
-map(ElfObj *obj, ElfSect *sect)
-{
-	if(sect->base != nil)
-		return 0;
-
-	if(sect->off+sect->size > obj->len) {
-		werrstr("elf section past end of file");
-		return -1;
-	}
-
-	sect->base = mal(sect->size);
-	werrstr("short read");
-	if(Bseek(obj->f, obj->base+sect->off, 0) < 0 || Bread(obj->f, sect->base, sect->size) != sect->size)
-		return -1;
-	
-	return 0;
-}
-
-static int
-readsym(ElfObj *obj, int i, ElfSym *sym, int needSym)
-{
-	LSym *s;
-
-	if(i >= obj->nsymtab || i < 0) {
-		werrstr("invalid elf symbol index");
-		return -1;
-	}
-	if(i == 0) {
-		diag("readym: read null symbol!");
-	}
-
-	if(obj->is64) {
-		ElfSymBytes64 *b;
-		
-		b = (ElfSymBytes64*)(obj->symtab->base + i*sizeof *b);
-		sym->name = (char*)obj->symstr->base + obj->e->e32(b->name);
-		sym->value = obj->e->e64(b->value);
-		sym->size = obj->e->e64(b->size);
-		sym->shndx = obj->e->e16(b->shndx);
-		sym->bind = b->info>>4;
-		sym->type = b->info&0xf;
-		sym->other = b->other;
-	} else {
-		ElfSymBytes *b;
-		
-		b = (ElfSymBytes*)(obj->symtab->base + i*sizeof *b);
-		sym->name = (char*)obj->symstr->base + obj->e->e32(b->name);
-		sym->value = obj->e->e32(b->value);
-		sym->size = obj->e->e32(b->size);
-		sym->shndx = obj->e->e16(b->shndx);
-		sym->bind = b->info>>4;
-		sym->type = b->info&0xf;
-		sym->other = b->other;
-	}
-
-	s = nil;
-	if(strcmp(sym->name, "_GLOBAL_OFFSET_TABLE_") == 0)
-		sym->name = ".got";
-	switch(sym->type) {
-	case ElfSymTypeSection:
-		s = obj->sect[sym->shndx].sym;
-		break;
-	case ElfSymTypeObject:
-	case ElfSymTypeFunc:
-	case ElfSymTypeNone:
-		switch(sym->bind) {
-		case ElfSymBindGlobal:
-			if(needSym) {
-				s = linklookup(ctxt, sym->name, 0);
-				// for global scoped hidden symbols we should insert it into
-				// symbol hash table, but mark them as hidden.
-				// __i686.get_pc_thunk.bx is allowed to be duplicated, to
-				// workaround that we set dupok.
-				// TODO(minux): correctly handle __i686.get_pc_thunk.bx without
-				// set dupok generally. See http://codereview.appspot.com/5823055/
-				// comment #5 for details.
-				if(s && sym->other == 2) {
-					s->type |= SHIDDEN;
-					s->dupok = 1;
-				}
-			}
-			break;
-		case ElfSymBindLocal:
-			if(!(thechar == '5' && (strncmp(sym->name, "$a", 2) == 0 || strncmp(sym->name, "$d", 2) == 0))) // binutils for arm generate these mapping symbols, ignore these
-				if(needSym) {
-					// local names and hidden visiblity global names are unique
-					// and should only reference by its index, not name, so we
-					// don't bother to add them into hash table
-					s = linknewsym(ctxt, sym->name, ctxt->version);
-					s->type |= SHIDDEN;
-				}
-			break;
-		case ElfSymBindWeak:
-			if(needSym) {
-				s = linknewsym(ctxt, sym->name, 0);
-				if(sym->other == 2)
-					s->type |= SHIDDEN;
-			}
-			break;
-		default:
-			werrstr("%s: invalid symbol binding %d", sym->name, sym->bind);
-			return -1;
-		}
-		break;
-	}
-	if(s != nil && s->type == 0 && sym->type != ElfSymTypeSection)
-		s->type = SXREF;
-	sym->sym = s;
-
-	return 0;
-}
-
-int
-rbyoff(const void *va, const void *vb)
-{
-	Reloc *a, *b;
-	
-	a = (Reloc*)va;
-	b = (Reloc*)vb;
-	if(a->off < b->off)
-		return -1;
-	if(a->off > b->off)
-		return +1;
-	return 0;
-}
-
-#define R(x, y) ((x)|((y)<<24))
-
-static int
-reltype(char *pn, int elftype, uchar *siz)
-{
-	switch(R(thechar, elftype)) {
-	default:
-		diag("%s: unknown relocation type %d; compiled without -fpic?", pn, elftype);
-	case R('5', R_ARM_ABS32):
-	case R('5', R_ARM_GOT32):
-	case R('5', R_ARM_PLT32):
-	case R('5', R_ARM_GOTOFF):
-	case R('5', R_ARM_GOTPC):
-	case R('5', R_ARM_THM_PC22):
-	case R('5', R_ARM_REL32):
-	case R('5', R_ARM_CALL):
-	case R('5', R_ARM_V4BX):
-	case R('5', R_ARM_GOT_PREL):
-	case R('5', R_ARM_PC24):
-	case R('5', R_ARM_JUMP24):
-	case R('6', R_X86_64_PC32):
-	case R('6', R_X86_64_PLT32):
-	case R('6', R_X86_64_GOTPCREL):
-	case R('8', R_386_32):
-	case R('8', R_386_PC32):
-	case R('8', R_386_GOT32):
-	case R('8', R_386_PLT32):
-	case R('8', R_386_GOTOFF):
-	case R('8', R_386_GOTPC):
-		*siz = 4;
-		break;
-	case R('6', R_X86_64_64):
-		*siz = 8;
-		break;
-	}
-
-	return 256+elftype;
-}
diff --git a/src/cmd/ld/ldmacho.c b/src/cmd/ld/ldmacho.c
deleted file mode 100644
index 71cfa63..0000000
--- a/src/cmd/ld/ldmacho.c
+++ /dev/null
@@ -1,850 +0,0 @@
-/*
-Derived from Plan 9 from User Space's src/libmach/elf.h, elf.c
-http://code.swtch.com/plan9port/src/tip/src/libmach/
-
-	Copyright © 2004 Russ Cox.
-	Portions Copyright © 2008-2010 Google Inc.
-	Portions Copyright © 2010 The Go Authors.
-
-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.
-*/
-
-#include	"l.h"
-#include	"lib.h"
-
-enum {
-	MACHO_FAKE_GOTPCREL = 100,	// from macho.h
-	
-	N_EXT = 0x01,
-	N_TYPE = 0x1e,
-	N_STAB = 0xe0,
-};
-
-typedef struct MachoObj MachoObj;
-typedef struct MachoCmd MachoCmd;
-typedef struct MachoSeg MachoSeg;
-typedef struct MachoSect MachoSect;
-typedef struct MachoRel MachoRel;
-typedef struct MachoSymtab MachoSymtab;
-typedef struct MachoSym MachoSym;
-typedef struct MachoDysymtab MachoDysymtab;
-
-enum
-{
-	MachoCpuVax = 1,
-	MachoCpu68000 = 6,
-	MachoCpu386 = 7,
-	MachoCpuAmd64 = 0x1000007,
-	MachoCpuMips = 8,
-	MachoCpu98000 = 10,
-	MachoCpuHppa = 11,
-	MachoCpuArm = 12,
-	MachoCpu88000 = 13,
-	MachoCpuSparc = 14,
-	MachoCpu860 = 15,
-	MachoCpuAlpha = 16,
-	MachoCpuPower = 18,
-
-	MachoCmdSegment = 1,
-	MachoCmdSymtab = 2,
-	MachoCmdSymseg = 3,
-	MachoCmdThread = 4,
-	MachoCmdDysymtab = 11,
-	MachoCmdSegment64 = 25,
-
-	MachoFileObject = 1,
-	MachoFileExecutable = 2,
-	MachoFileFvmlib = 3,
-	MachoFileCore = 4,
-	MachoFilePreload = 5,
-};
-
-struct MachoSeg
-{
-	char name[16+1];
-	uint64 vmaddr;
-	uint64 vmsize;
-	uint32 fileoff;
-	uint32 filesz;
-	uint32 maxprot;
-	uint32 initprot;
-	uint32 nsect;
-	uint32 flags;
-	MachoSect *sect;
-};
-
-struct MachoSect
-{
-	char	name[16+1];
-	char	segname[16+1];
-	uint64 addr;
-	uint64 size;
-	uint32 off;
-	uint32 align;
-	uint32 reloff;
-	uint32 nreloc;
-	uint32 flags;
-	uint32 res1;
-	uint32 res2;
-	LSym *sym;
-	
-	MachoRel *rel;
-};
-
-struct MachoRel
-{
-	uint32 addr;
-	uint32 symnum;
-	uint8 pcrel;
-	uint8 length;
-	uint8 extrn;
-	uint8 type;
-	uint8 scattered;
-	uint32 value;
-};
-
-struct MachoSymtab
-{
-	uint32 symoff;
-	uint32 nsym;
-	uint32 stroff;
-	uint32 strsize;
-	
-	char *str;
-	MachoSym *sym;
-};
-
-struct MachoSym
-{
-	char *name;
-	uint8 type;
-	uint8 sectnum;
-	uint16 desc;
-	char kind;
-	uint64 value;
-	LSym *sym;
-};
-
-struct MachoDysymtab
-{
-	uint32 ilocalsym;
-	uint32 nlocalsym;
-	uint32 iextdefsym;
-	uint32 nextdefsym;
-	uint32 iundefsym;
-	uint32 nundefsym;
-	uint32 tocoff;
-	uint32 ntoc;
-	uint32 modtaboff;
-	uint32 nmodtab;
-	uint32 extrefsymoff;
-	uint32 nextrefsyms;
-	uint32 indirectsymoff;
-	uint32 nindirectsyms;
-	uint32 extreloff;
-	uint32 nextrel;
-	uint32 locreloff;
-	uint32 nlocrel;
-	uint32 *indir;
-};
-
-struct MachoCmd
-{
-	int type;
-	uint32 off;
-	uint32 size;
-	MachoSeg seg;
-	MachoSymtab sym;
-	MachoDysymtab dsym;
-};
-
-struct MachoObj
-{
-	Biobuf	*f;
-	int64	base;	// off in f where Mach-O begins
-	int64	len;		// length of Mach-O
-	int is64;
-	char	*name;
-
-	Endian	*e;
-	uint cputype;
-	uint subcputype;
-	uint32 filetype;
-	uint32 flags;
-	MachoCmd *cmd;
-	uint ncmd;
-};
-
-static int
-unpackcmd(uchar *p, MachoObj *m, MachoCmd *c, uint type, uint sz)
-{
-	uint32 (*e4)(uchar*);
-	uint64 (*e8)(uchar*);
-	MachoSect *s;
-	int i;
-
-	e4 = m->e->e32;
-	e8 = m->e->e64;
-
-	c->type = type;
-	c->size = sz;
-	switch(type){
-	default:
-		return -1;
-	case MachoCmdSegment:
-		if(sz < 56)
-			return -1;
-		strecpy(c->seg.name, c->seg.name+sizeof c->seg.name, (char*)p+8);
-		c->seg.vmaddr = e4(p+24);
-		c->seg.vmsize = e4(p+28);
-		c->seg.fileoff = e4(p+32);
-		c->seg.filesz = e4(p+36);
-		c->seg.maxprot = e4(p+40);
-		c->seg.initprot = e4(p+44);
-		c->seg.nsect = e4(p+48);
-		c->seg.flags = e4(p+52);
-		c->seg.sect = mal(c->seg.nsect * sizeof c->seg.sect[0]);
-		if(sz < 56+c->seg.nsect*68)
-			return -1;
-		p += 56;
-		for(i=0; i<c->seg.nsect; i++) {
-			s = &c->seg.sect[i];
-			strecpy(s->name, s->name+sizeof s->name, (char*)p+0);
-			strecpy(s->segname, s->segname+sizeof s->segname, (char*)p+16);
-			s->addr = e4(p+32);
-			s->size = e4(p+36);
-			s->off = e4(p+40);
-			s->align = e4(p+44);
-			s->reloff = e4(p+48);
-			s->nreloc = e4(p+52);
-			s->flags = e4(p+56);
-			s->res1 = e4(p+60);
-			s->res2 = e4(p+64);
-			p += 68;
-		}
-		break;
-	case MachoCmdSegment64:
-		if(sz < 72)
-			return -1;
-		strecpy(c->seg.name, c->seg.name+sizeof c->seg.name, (char*)p+8);
-		c->seg.vmaddr = e8(p+24);
-		c->seg.vmsize = e8(p+32);
-		c->seg.fileoff = e8(p+40);
-		c->seg.filesz = e8(p+48);
-		c->seg.maxprot = e4(p+56);
-		c->seg.initprot = e4(p+60);
-		c->seg.nsect = e4(p+64);
-		c->seg.flags = e4(p+68);
-		c->seg.sect = mal(c->seg.nsect * sizeof c->seg.sect[0]);
-		if(sz < 72+c->seg.nsect*80)
-			return -1;
-		p += 72;
-		for(i=0; i<c->seg.nsect; i++) {
-			s = &c->seg.sect[i];
-			strecpy(s->name, s->name+sizeof s->name, (char*)p+0);
-			strecpy(s->segname, s->segname+sizeof s->segname, (char*)p+16);
-			s->addr = e8(p+32);
-			s->size = e8(p+40);
-			s->off = e4(p+48);
-			s->align = e4(p+52);
-			s->reloff = e4(p+56);
-			s->nreloc = e4(p+60);
-			s->flags = e4(p+64);
-			s->res1 = e4(p+68);
-			s->res2 = e4(p+72);
-			// p+76 is reserved
-			p += 80;
-		}
-		break;
-	case MachoCmdSymtab:
-		if(sz < 24)
-			return -1;
-		c->sym.symoff = e4(p+8);
-		c->sym.nsym = e4(p+12);
-		c->sym.stroff = e4(p+16);
-		c->sym.strsize = e4(p+20);
-		break;
-	case MachoCmdDysymtab:
-		if(sz < 80)
-			return -1;
-		c->dsym.ilocalsym = e4(p+8);
-		c->dsym.nlocalsym = e4(p+12);
-		c->dsym.iextdefsym = e4(p+16);
-		c->dsym.nextdefsym = e4(p+20);
-		c->dsym.iundefsym = e4(p+24);
-		c->dsym.nundefsym = e4(p+28);
-		c->dsym.tocoff = e4(p+32);
-		c->dsym.ntoc = e4(p+36);
-		c->dsym.modtaboff = e4(p+40);
-		c->dsym.nmodtab = e4(p+44);
-		c->dsym.extrefsymoff = e4(p+48);
-		c->dsym.nextrefsyms = e4(p+52);
-		c->dsym.indirectsymoff = e4(p+56);
-		c->dsym.nindirectsyms = e4(p+60);
-		c->dsym.extreloff = e4(p+64);
-		c->dsym.nextrel = e4(p+68);
-		c->dsym.locreloff = e4(p+72);
-		c->dsym.nlocrel = e4(p+76);
-		break;
-	}
-	return 0;
-}
-
-static int
-macholoadrel(MachoObj *m, MachoSect *sect)
-{
-	MachoRel *rel, *r;
-	uchar *buf, *p;
-	int i, n;
-	uint32 v;
-	
-	if(sect->rel != nil || sect->nreloc == 0)
-		return 0;
-	rel = mal(sect->nreloc * sizeof r[0]);
-	n = sect->nreloc * 8;
-	buf = mal(n);
-	if(Bseek(m->f, m->base + sect->reloff, 0) < 0 || Bread(m->f, buf, n) != n)
-		return -1;
-	for(i=0; i<sect->nreloc; i++) {
-		r = &rel[i];
-		p = buf+i*8;
-		r->addr = m->e->e32(p);
-		
-		// TODO(rsc): Wrong interpretation for big-endian bitfields?
-		if(r->addr & 0x80000000) {
-			// scatterbrained relocation
-			r->scattered = 1;
-			v = r->addr >> 24;
-			r->addr &= 0xFFFFFF;
-			r->type = v & 0xF;
-			v >>= 4;
-			r->length = 1<<(v&3);
-			v >>= 2;
-			r->pcrel = v & 1;
-			r->value = m->e->e32(p+4);
-		} else {
-			v = m->e->e32(p+4);
-			r->symnum = v & 0xFFFFFF;
-			v >>= 24;
-			r->pcrel = v&1;
-			v >>= 1;
-			r->length = 1<<(v&3);
-			v >>= 2;
-			r->extrn = v&1;
-			v >>= 1;
-			r->type = v;
-		}
-	}
-	sect->rel = rel;
-	return 0;
-}
-
-static int
-macholoaddsym(MachoObj *m, MachoDysymtab *d)
-{
-	uchar *p;
-	int i, n;
-	
-	n = d->nindirectsyms;
-	
-	p = mal(n*4);
-	if(Bseek(m->f, m->base + d->indirectsymoff, 0) < 0 || Bread(m->f, p, n*4) != n*4)
-		return -1;
-	
-	d->indir = (uint32*)p;
-	for(i=0; i<n; i++)
-		d->indir[i] = m->e->e32(p+4*i);
-	return 0;
-}
-
-static int 
-macholoadsym(MachoObj *m, MachoSymtab *symtab)
-{
-	char *strbuf;
-	uchar *symbuf, *p;
-	int i, n, symsize;
-	MachoSym *sym, *s;
-	uint32 v;
-
-	if(symtab->sym != nil)
-		return 0;
-
-	strbuf = mal(symtab->strsize);
-	if(Bseek(m->f, m->base + symtab->stroff, 0) < 0 || Bread(m->f, strbuf, symtab->strsize) != symtab->strsize)
-		return -1;
-	
-	symsize = 12;
-	if(m->is64)
-		symsize = 16;
-	n = symtab->nsym * symsize;
-	symbuf = mal(n);
-	if(Bseek(m->f, m->base + symtab->symoff, 0) < 0 || Bread(m->f, symbuf, n) != n)
-		return -1;
-	sym = mal(symtab->nsym * sizeof sym[0]);
-	p = symbuf;
-	for(i=0; i<symtab->nsym; i++) {
-		s = &sym[i];
-		v = m->e->e32(p);
-		if(v >= symtab->strsize)
-			return -1;
-		s->name = strbuf + v;
-		s->type = p[4];
-		s->sectnum = p[5];
-		s->desc = m->e->e16(p+6);
-		if(m->is64)
-			s->value = m->e->e64(p+8);
-		else
-			s->value = m->e->e32(p+8);
-		p += symsize;
-	}
-	symtab->str = strbuf;
-	symtab->sym = sym;
-	return 0;
-}
-
-void
-ldmacho(Biobuf *f, char *pkg, int64 len, char *pn)
-{
-	int i, j, is64;
-	uint64 secaddr;
-	uchar hdr[7*4], *cmdp;
-	uchar tmp[4];
-	uchar *dat;
-	ulong ncmd, cmdsz, ty, sz, off;
-	MachoObj *m;
-	Endian *e;
-	int64 base;
-	MachoSect *sect;
-	MachoRel *rel;
-	LSym *s, *s1, *outer;
-	MachoCmd *c;
-	MachoSymtab *symtab;
-	MachoDysymtab *dsymtab;
-	MachoSym *sym;
-	Reloc *r, *rp;
-	char *name;
-
-	ctxt->version++;
-	base = Boffset(f);
-	if(Bread(f, hdr, sizeof hdr) != sizeof hdr)
-		goto bad;
-
-	if((be.e32(hdr)&~1) == 0xFEEDFACE){
-		e = &be;
-	}else if((le.e32(hdr)&~1) == 0xFEEDFACE){
-		e = ≤
-	}else{
-		werrstr("bad magic - not mach-o file");
-		goto bad;
-	}
-
-	is64 = e->e32(hdr) == 0xFEEDFACF;
-	ncmd = e->e32(hdr+4*4);
-	cmdsz = e->e32(hdr+5*4);
-	if(ncmd > 0x10000 || cmdsz >= 0x01000000){
-		werrstr("implausible mach-o header ncmd=%lud cmdsz=%lud", ncmd, cmdsz);
-		goto bad;
-	}
-	if(is64)
-		Bread(f, tmp, 4);	// skip reserved word in header
-
-	m = mal(sizeof(*m)+ncmd*sizeof(MachoCmd)+cmdsz);
-	m->f = f;
-	m->e = e;
-	m->cputype = e->e32(hdr+1*4);
-	m->subcputype = e->e32(hdr+2*4);
-	m->filetype = e->e32(hdr+3*4);
-	m->ncmd = ncmd;
-	m->flags = e->e32(hdr+6*4);
-	m->is64 = is64;
-	m->base = base;
-	m->len = len;
-	m->name = pn;
-	
-	switch(thechar) {
-	default:
-		diag("%s: mach-o %s unimplemented", pn, thestring);
-		return;
-	case '6':
-		if(e != &le || m->cputype != MachoCpuAmd64) {
-			diag("%s: mach-o object but not amd64", pn);
-			return;
-		}
-		break;
-	case '8':
-		if(e != &le || m->cputype != MachoCpu386) {
-			diag("%s: mach-o object but not 386", pn);
-			return;
-		}
-		break;
-	}
-
-	m->cmd = (MachoCmd*)(m+1);
-	off = sizeof hdr;
-	cmdp = (uchar*)(m->cmd+ncmd);
-	if(Bread(f, cmdp, cmdsz) != cmdsz){
-		werrstr("reading cmds: %r");
-		goto bad;
-	}
-
-	// read and parse load commands
-	c = nil;
-	symtab = nil;
-	dsymtab = nil;
-	USED(dsymtab);
-	for(i=0; i<ncmd; i++){
-		ty = e->e32(cmdp);
-		sz = e->e32(cmdp+4);
-		m->cmd[i].off = off;
-		unpackcmd(cmdp, m, &m->cmd[i], ty, sz);
-		cmdp += sz;
-		off += sz;
-		if(ty == MachoCmdSymtab) {
-			if(symtab != nil) {
-				werrstr("multiple symbol tables");
-				goto bad;
-			}
-			symtab = &m->cmd[i].sym;
-			macholoadsym(m, symtab);
-		}
-		if(ty == MachoCmdDysymtab) {
-			dsymtab = &m->cmd[i].dsym;
-			macholoaddsym(m, dsymtab);
-		}
-		if((is64 && ty == MachoCmdSegment64) || (!is64 && ty == MachoCmdSegment)) {
-			if(c != nil) {
-				werrstr("multiple load commands");
-				goto bad;
-			}
-			c = &m->cmd[i];
-		}
-	}
-
-	// load text and data segments into memory.
-	// they are not as small as the load commands, but we'll need
-	// the memory anyway for the symbol images, so we might
-	// as well use one large chunk.
-	if(c == nil) {
-		werrstr("no load command");
-		goto bad;
-	}
-	if(symtab == nil) {
-		// our work is done here - no symbols means nothing can refer to this file
-		return;
-	}
-
-	if(c->seg.fileoff+c->seg.filesz >= len) {
-		werrstr("load segment out of range");
-		goto bad;
-	}
-
-	dat = mal(c->seg.filesz);
-	if(Bseek(f, m->base + c->seg.fileoff, 0) < 0 || Bread(f, dat, c->seg.filesz) != c->seg.filesz) {
-		werrstr("cannot load object data: %r");
-		goto bad;
-	}
-	
-	for(i=0; i<c->seg.nsect; i++) {
-		sect = &c->seg.sect[i];
-		if(strcmp(sect->segname, "__TEXT") != 0 && strcmp(sect->segname, "__DATA") != 0)
-			continue;
-		if(strcmp(sect->name, "__eh_frame") == 0)
-			continue;
-		name = smprint("%s(%s/%s)", pkg, sect->segname, sect->name);
-		s = linklookup(ctxt, name, ctxt->version);
-		if(s->type != 0) {
-			werrstr("duplicate %s/%s", sect->segname, sect->name);
-			goto bad;
-		}
-		free(name);
-
-		s->np = sect->size;
-		s->size = s->np;
-		if((sect->flags & 0xff) == 1) // S_ZEROFILL
-			s->p = mal(s->size);
-		else {
-			s->p = dat + sect->addr - c->seg.vmaddr;
-		}
-		
-		if(strcmp(sect->segname, "__TEXT") == 0) {
-			if(strcmp(sect->name, "__text") == 0)
-				s->type = STEXT;
-			else
-				s->type = SRODATA;
-		} else {
-			if (strcmp(sect->name, "__bss") == 0) {
-				s->type = SNOPTRBSS;
-				s->np = 0;
-			} else
-				s->type = SNOPTRDATA;
-		}
-		sect->sym = s;
-	}
-	
-	// enter sub-symbols into symbol table.
-	// have to guess sizes from next symbol.
-	for(i=0; i<symtab->nsym; i++) {
-		int v;
-		sym = &symtab->sym[i];
-		if(sym->type&N_STAB)
-			continue;
-		// TODO: check sym->type against outer->type.
-		name = sym->name;
-		if(name[0] == '_' && name[1] != '\0')
-			name++;
-		v = 0;
-		if(!(sym->type&N_EXT))
-			v = ctxt->version;
-		s = linklookup(ctxt, name, v);
-		if(!(sym->type&N_EXT))
-			s->dupok = 1;
-		sym->sym = s;
-		if(sym->sectnum == 0)	// undefined
-			continue;
-		if(sym->sectnum > c->seg.nsect) {
-			werrstr("reference to invalid section %d", sym->sectnum);
-			goto bad;
-		}
-		sect = &c->seg.sect[sym->sectnum-1];
-		outer = sect->sym;
-		if(outer == nil) {
-			werrstr("reference to invalid section %s/%s", sect->segname, sect->name);
-			continue;
-		}
-		if(s->outer != S) {
-			if(s->dupok)
-				continue;
-			diag("%s: duplicate symbol reference: %s in both %s and %s", pn, s->name, s->outer->name, sect->sym->name);
-			errorexit();
-		}
-		s->type = outer->type | SSUB;
-		s->sub = outer->sub;
-		outer->sub = s;
-		s->outer = outer;
-		s->value = sym->value - sect->addr;
-		if(!(s->cgoexport & CgoExportDynamic))
-			s->dynimplib = nil;	// satisfy dynimport
-		if(outer->type == STEXT) {
-			if(s->external && !s->dupok)
-				diag("%s: duplicate definition of %s", pn, s->name);
-			s->external = 1;
-		}
-		sym->sym = s;
-	}
-
-	// Sort outer lists by address, adding to textp.
-	// This keeps textp in increasing address order.
-	for(i=0; i<c->seg.nsect; i++) {
-		sect = &c->seg.sect[i];
-		if((s = sect->sym) == S)
-			continue;
-		if(s->sub) {
-			s->sub = listsort(s->sub, valuecmp, offsetof(LSym, sub));
-			
-			// assign sizes, now that we know symbols in sorted order.
-			for(s1 = s->sub; s1 != S; s1 = s1->sub) {
-				if(s1->sub)
-					s1->size = s1->sub->value - s1->value;
-				else
-					s1->size = s->value + s->size - s1->value;
-			}
-		}
-		if(s->type == STEXT) {
-			if(s->onlist)
-				sysfatal("symbol %s listed multiple times", s->name);
-			s->onlist = 1;
-			if(ctxt->etextp)
-				ctxt->etextp->next = s;
-			else
-				ctxt->textp = s;
-			ctxt->etextp = s;
-			for(s1 = s->sub; s1 != S; s1 = s1->sub) {
-				if(s1->onlist)
-					sysfatal("symbol %s listed multiple times", s1->name);
-				s1->onlist = 1;
-				ctxt->etextp->next = s1;
-				ctxt->etextp = s1;
-			}
-		}
-	}
-
-	// load relocations
-	for(i=0; i<c->seg.nsect; i++) {
-		sect = &c->seg.sect[i];
-		if((s = sect->sym) == S)
-			continue;
-		macholoadrel(m, sect);
-		if(sect->rel == nil)
-			continue;
-		r = mal(sect->nreloc*sizeof r[0]);
-		rp = r;
-		rel = sect->rel;
-		for(j=0; j<sect->nreloc; j++, rel++) {
-			if(rel->scattered) {
-				int k;
-				MachoSect *ks;
-
-				if(thechar != '8') {
-					// mach-o only uses scattered relocation on 32-bit platforms
-					diag("unexpected scattered relocation");
-					continue;
-				}
-
-				// on 386, rewrite scattered 4/1 relocation and some
-				// scattered 2/1 relocation into the pseudo-pc-relative
-				// reference that it is.
-				// assume that the second in the pair is in this section
-				// and use that as the pc-relative base.
-				if(j+1 >= sect->nreloc) {
-					werrstr("unsupported scattered relocation %d", (int)rel->type);
-					goto bad;
-				}
-				if(!(rel+1)->scattered || (rel+1)->type != 1 ||
-				   (rel->type != 4 && rel->type != 2) ||
-				   (rel+1)->value < sect->addr || (rel+1)->value >= sect->addr+sect->size) {
-					werrstr("unsupported scattered relocation %d/%d", (int)rel->type, (int)(rel+1)->type);
-					goto bad;
-				}
-
-				rp->siz = rel->length;
-				rp->off = rel->addr;
-				
-				// NOTE(rsc): I haven't worked out why (really when)
-				// we should ignore the addend on a
-				// scattered relocation, but it seems that the
-				// common case is we ignore it.
-				// It's likely that this is not strictly correct
-				// and that the math should look something
-				// like the non-scattered case below.
-				rp->add = 0;
-				
-				// want to make it pc-relative aka relative to rp->off+4
-				// but the scatter asks for relative to off = (rel+1)->value - sect->addr.
-				// adjust rp->add accordingly.
-				rp->type = R_PCREL;
-				rp->add += (rp->off+4) - ((rel+1)->value - sect->addr);
-				
-				// now consider the desired symbol.
-				// find the section where it lives.
-				for(k=0; k<c->seg.nsect; k++) {
-					ks = &c->seg.sect[k];
-					if(ks->addr <= rel->value && rel->value < ks->addr+ks->size)
-						goto foundk;
-				}
-				werrstr("unsupported scattered relocation: invalid address %#ux", rel->addr);
-				goto bad;
-			foundk:
-				if(ks->sym != S) {
-					rp->sym = ks->sym;
-					rp->add += rel->value - ks->addr;
-				} else if(strcmp(ks->segname, "__IMPORT") == 0 && strcmp(ks->name, "__pointers") == 0) {
-					// 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 = ks->res1 + (rel->value - ks->addr) / 4;
-					// load indirect table for __pointers
-					// fetch symbol number
-					if(dsymtab == nil || k < 0 || k >= dsymtab->nindirectsyms || dsymtab->indir == nil) {
-						werrstr("invalid scattered relocation: indirect symbol reference out of range");
-						goto bad;
-					}
-					k = dsymtab->indir[k];
-					if(k < 0 || k >= symtab->nsym) {
-						werrstr("invalid scattered relocation: symbol reference out of range");
-						goto bad;
-					}
-					rp->sym = symtab->sym[k].sym;
-				} else {
-					werrstr("unsupported scattered relocation: reference to %s/%s", ks->segname, ks->name);
-					goto bad;
-				}
-				rp++;
-				// skip #1 of 2 rel; continue skips #2 of 2.
-				rel++;
-				j++;
-				continue;
-			}
-
-			rp->siz = rel->length;
-			rp->type = 512 + (rel->type<<1) + rel->pcrel;
-			rp->off = rel->addr;
-
-			// Handle X86_64_RELOC_SIGNED referencing a section (rel->extrn == 0).
-			if (thechar == '6' && rel->extrn == 0 && rel->type == 1) {
-				// Calculate the addend as the offset into the section.
-				//
-				// The rip-relative offset stored in the object file is encoded
-				// as follows:
-				//    
-				//    movsd	0x00000360(%rip),%xmm0
-				//
-				// To get the absolute address of the value this rip-relative address is pointing
-				// to, we must add the address of the next instruction to it. This is done by
-				// taking the address of the relocation and adding 4 to it (since the rip-relative
-				// offset can at most be 32 bits long).  To calculate the offset into the section the
-				// relocation is referencing, we subtract the vaddr of the start of the referenced
-				// section found in the original object file.
-				//
-				// [For future reference, see Darwin's /usr/include/mach-o/x86_64/reloc.h]
-				secaddr = c->seg.sect[rel->symnum-1].addr;
-				rp->add = (int32)e->e32(s->p+rp->off) + rp->off + 4 - secaddr;
-			} else
-				rp->add = (int32)e->e32(s->p+rp->off);
-
-			// For i386 Mach-O PC-relative, the addend is written such that
-			// it *is* the PC being subtracted.  Use that to make
-			// it match our version of PC-relative.
-			if(rel->pcrel && thechar == '8')
-				rp->add += rp->off+rp->siz;
-			if(!rel->extrn) {
-				if(rel->symnum < 1 || rel->symnum > c->seg.nsect) {
-					werrstr("invalid relocation: section reference out of range %d vs %d", rel->symnum, c->seg.nsect);
-					goto bad;
-				}
-				rp->sym = c->seg.sect[rel->symnum-1].sym;
-				if(rp->sym == nil) {
-					werrstr("invalid relocation: %s", c->seg.sect[rel->symnum-1].name);
-					goto bad;
-				}
-				// References to symbols in other sections
-				// include that information in the addend.
-				// We only care about the delta from the 
-				// section base.
-				if(thechar == '8')
-					rp->add -= c->seg.sect[rel->symnum-1].addr;
-			} else {
-				if(rel->symnum >= symtab->nsym) {
-					werrstr("invalid relocation: symbol reference out of range");
-					goto bad;
-				}
-				rp->sym = symtab->sym[rel->symnum].sym;
-			}
-			rp++;
-		}			
-		qsort(r, rp - r, sizeof r[0], rbyoff);
-		s->r = r;
-		s->nr = rp - r;
-	}
-	return;
-
-bad:
-	diag("%s: malformed mach-o file: %r", pn);
-}
diff --git a/src/cmd/ld/ldpe.c b/src/cmd/ld/ldpe.c
deleted file mode 100644
index 4f5e51f..0000000
--- a/src/cmd/ld/ldpe.c
+++ /dev/null
@@ -1,499 +0,0 @@
-// Copyright 2010 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	"l.h"
-#include	"lib.h"
-#include	"../ld/pe.h"
-
-#define IMAGE_SCN_MEM_DISCARDABLE 0x2000000
-
-#define IMAGE_SYM_UNDEFINED	0
-#define IMAGE_SYM_ABSOLUTE (-1)
-#define IMAGE_SYM_DEBUG	(-2)
-#define IMAGE_SYM_TYPE_NULL 0
-#define IMAGE_SYM_TYPE_VOID 1
-#define IMAGE_SYM_TYPE_CHAR 2
-#define IMAGE_SYM_TYPE_SHORT 3
-#define IMAGE_SYM_TYPE_INT 4
-#define IMAGE_SYM_TYPE_LONG 5
-#define IMAGE_SYM_TYPE_FLOAT 6
-#define IMAGE_SYM_TYPE_DOUBLE 7
-#define IMAGE_SYM_TYPE_STRUCT 8
-#define IMAGE_SYM_TYPE_UNION 9
-#define IMAGE_SYM_TYPE_ENUM 10
-#define IMAGE_SYM_TYPE_MOE 11
-#define IMAGE_SYM_TYPE_BYTE 12
-#define IMAGE_SYM_TYPE_WORD 13
-#define IMAGE_SYM_TYPE_UINT 14
-#define IMAGE_SYM_TYPE_DWORD 15
-#define IMAGE_SYM_TYPE_PCODE 32768
-#define IMAGE_SYM_DTYPE_NULL 0
-#define IMAGE_SYM_DTYPE_POINTER 0x10
-#define IMAGE_SYM_DTYPE_FUNCTION 0x20
-#define IMAGE_SYM_DTYPE_ARRAY 0x30
-#define IMAGE_SYM_CLASS_END_OF_FUNCTION	(-1)
-#define IMAGE_SYM_CLASS_NULL 0
-#define IMAGE_SYM_CLASS_AUTOMATIC 1
-#define IMAGE_SYM_CLASS_EXTERNAL 2
-#define IMAGE_SYM_CLASS_STATIC 3
-#define IMAGE_SYM_CLASS_REGISTER 4
-#define IMAGE_SYM_CLASS_EXTERNAL_DEF 5
-#define IMAGE_SYM_CLASS_LABEL 6
-#define IMAGE_SYM_CLASS_UNDEFINED_LABEL 7
-#define IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 8
-#define IMAGE_SYM_CLASS_ARGUMENT 9
-#define IMAGE_SYM_CLASS_STRUCT_TAG 10
-#define IMAGE_SYM_CLASS_MEMBER_OF_UNION 11
-#define IMAGE_SYM_CLASS_UNION_TAG 12
-#define IMAGE_SYM_CLASS_TYPE_DEFINITION 13
-#define IMAGE_SYM_CLASS_UNDEFINED_STATIC 14
-#define IMAGE_SYM_CLASS_ENUM_TAG 15
-#define IMAGE_SYM_CLASS_MEMBER_OF_ENUM 16
-#define IMAGE_SYM_CLASS_REGISTER_PARAM 17
-#define IMAGE_SYM_CLASS_BIT_FIELD 18
-#define IMAGE_SYM_CLASS_FAR_EXTERNAL 68 /* Not in PECOFF v8 spec */
-#define IMAGE_SYM_CLASS_BLOCK 100
-#define IMAGE_SYM_CLASS_FUNCTION 101
-#define IMAGE_SYM_CLASS_END_OF_STRUCT 102
-#define IMAGE_SYM_CLASS_FILE 103
-#define IMAGE_SYM_CLASS_SECTION 104
-#define IMAGE_SYM_CLASS_WEAK_EXTERNAL 105
-#define IMAGE_SYM_CLASS_CLR_TOKEN 107
-
-#define IMAGE_REL_I386_ABSOLUTE	0x0000
-#define IMAGE_REL_I386_DIR16	0x0001
-#define IMAGE_REL_I386_REL16	0x0002
-#define IMAGE_REL_I386_DIR32	0x0006
-#define IMAGE_REL_I386_DIR32NB	0x0007
-#define IMAGE_REL_I386_SEG12	0x0009
-#define IMAGE_REL_I386_SECTION	0x000A
-#define IMAGE_REL_I386_SECREL	0x000B
-#define IMAGE_REL_I386_TOKEN	0x000C
-#define IMAGE_REL_I386_SECREL7	0x000D
-#define IMAGE_REL_I386_REL32	0x0014
-
-#define IMAGE_REL_AMD64_ABSOLUTE 0x0000
-#define IMAGE_REL_AMD64_ADDR64 0x0001 // R_X86_64_64
-#define IMAGE_REL_AMD64_ADDR32 0x0002 // R_X86_64_PC32
-#define IMAGE_REL_AMD64_ADDR32NB 0x0003
-#define IMAGE_REL_AMD64_REL32 0x0004 
-#define IMAGE_REL_AMD64_REL32_1 0x0005
-#define IMAGE_REL_AMD64_REL32_2 0x0006
-#define IMAGE_REL_AMD64_REL32_3 0x0007
-#define IMAGE_REL_AMD64_REL32_4 0x0008
-#define IMAGE_REL_AMD64_REL32_5 0x0009
-#define IMAGE_REL_AMD64_SECTION 0x000A
-#define IMAGE_REL_AMD64_SECREL 0x000B
-#define IMAGE_REL_AMD64_SECREL7 0x000C
-#define IMAGE_REL_AMD64_TOKEN 0x000D
-#define IMAGE_REL_AMD64_SREL32 0x000E
-#define IMAGE_REL_AMD64_PAIR 0x000F
-#define IMAGE_REL_AMD64_SSPAN32 0x0010
-
-typedef struct PeSym PeSym;
-typedef struct PeSect PeSect;
-typedef struct PeObj PeObj;
-
-struct PeSym {
-	char* name;
-	uint32 value;
-	uint16 sectnum;
-	uint16 type;
-	uint8 sclass;
-	uint8 aux;
-	LSym* sym;
-};
-
-struct PeSect {
-	char* name;
-	uchar* base;
-	uint64 size;
-	LSym* sym;
-	IMAGE_SECTION_HEADER sh;
-};
-
-struct PeObj {
-	Biobuf	*f;
-	char	*name;
-	uint32 base;
-	
-	PeSect	*sect;
-	uint	nsect;
-	PeSym	*pesym;
-	uint npesym;
-	
-	IMAGE_FILE_HEADER fh;
-	char* snames;
-};
-
-static int map(PeObj *obj, PeSect *sect);
-static int issect(PeSym *s);
-static int readsym(PeObj *obj, int i, PeSym **sym);
-
-void
-ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
-{
-	char *name;
-	int32 base;
-	uint32 l;
-	int i, j, numaux;
-	PeObj *obj;
-	PeSect *sect, *rsect;
-	IMAGE_SECTION_HEADER sh;
-	uchar symbuf[18];
-	LSym *s;
-	Reloc *r, *rp;
-	PeSym *sym;
-
-	USED(len);
-	if(debug['v'])
-		Bprint(&bso, "%5.2f ldpe %s\n", cputime(), pn);
-	
-	sect = nil;
-	ctxt->version++;
-	base = Boffset(f);
-	
-	obj = mal(sizeof *obj);
-	obj->f = f;
-	obj->base = base;
-	obj->name = pn;
-	// read header
-	if(Bread(f, &obj->fh, sizeof obj->fh) != sizeof obj->fh)
-		goto bad;
-	// load section list
-	obj->sect = mal(obj->fh.NumberOfSections*sizeof obj->sect[0]);
-	obj->nsect = obj->fh.NumberOfSections;
-	for(i=0; i < obj->fh.NumberOfSections; i++) {
-		if(Bread(f, &obj->sect[i].sh, sizeof sh) != sizeof sh)
-			goto bad;
-		obj->sect[i].size = obj->sect[i].sh.SizeOfRawData;
-		obj->sect[i].name = (char*)obj->sect[i].sh.Name;
-		// TODO return error if found .cormeta
-	}
-	// load string table
-	Bseek(f, base+obj->fh.PointerToSymbolTable+sizeof(symbuf)*obj->fh.NumberOfSymbols, 0);
-	if(Bread(f, symbuf, 4) != 4) 
-		goto bad;
-	l = le32(symbuf);
-	obj->snames = mal(l);
-	Bseek(f, base+obj->fh.PointerToSymbolTable+sizeof(symbuf)*obj->fh.NumberOfSymbols, 0);
-	if(Bread(f, obj->snames, l) != l)
-		goto bad;
-	// rewrite section names if they start with /
-	for(i=0; i < obj->fh.NumberOfSections; i++) {
-		if(obj->sect[i].name == nil)
-			continue;
-		if(obj->sect[i].name[0] != '/')
-			continue;
-		l = atoi(obj->sect[i].name + 1);
-		obj->sect[i].name = (char*)&obj->snames[l];
-	}
-	// read symbols
-	obj->pesym = mal(obj->fh.NumberOfSymbols*sizeof obj->pesym[0]);
-	obj->npesym = obj->fh.NumberOfSymbols;
-	Bseek(f, base+obj->fh.PointerToSymbolTable, 0);
-	for(i=0; i<obj->fh.NumberOfSymbols; i+=numaux+1) {
-		Bseek(f, base+obj->fh.PointerToSymbolTable+sizeof(symbuf)*i, 0);
-		if(Bread(f, symbuf, sizeof symbuf) != sizeof symbuf)
-			goto bad;
-		
-		if((symbuf[0] == 0) && (symbuf[1] == 0) &&
-			 (symbuf[2] == 0) && (symbuf[3] == 0)) {
-			l = le32(&symbuf[4]);
-			obj->pesym[i].name = (char*)&obj->snames[l];
-		} else { // sym name length <= 8
-			obj->pesym[i].name = mal(9);
-			strncpy(obj->pesym[i].name, (char*)symbuf, 8);
-			obj->pesym[i].name[8] = 0;
-		}
-		obj->pesym[i].value = le32(&symbuf[8]);
-		obj->pesym[i].sectnum = le16(&symbuf[12]);
-		obj->pesym[i].sclass = symbuf[16];
-		obj->pesym[i].aux = symbuf[17];
-		obj->pesym[i].type = le16(&symbuf[14]);
-		numaux = obj->pesym[i].aux; 
-		if (numaux < 0) 
-			numaux = 0;
-	}
-	// create symbols for mapped sections
-	for(i=0; i<obj->nsect; i++) {
-		sect = &obj->sect[i];
-		if(sect->sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE)
-			continue;
-
-		if((sect->sh.Characteristics&(IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_CNT_UNINITIALIZED_DATA)) == 0) {
-			// This has been seen for .idata sections, which we
-			// want to ignore.  See issues 5106 and 5273.
-			continue;
-		}
-
-		if(map(obj, sect) < 0)
-			goto bad;
-		
-		name = smprint("%s(%s)", pkg, sect->name);
-		s = linklookup(ctxt, name, ctxt->version);
-		free(name);
-		switch(sect->sh.Characteristics&(IMAGE_SCN_CNT_UNINITIALIZED_DATA|IMAGE_SCN_CNT_INITIALIZED_DATA|
-			IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE|IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_EXECUTE)) {
-			case IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ: //.rdata
-				s->type = SRODATA;
-				break;
-			case IMAGE_SCN_CNT_UNINITIALIZED_DATA|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE: //.bss
-				s->type = SNOPTRBSS;
-				break;
-			case IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE: //.data
-				s->type = SNOPTRDATA;
-				break;
-			case IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ: //.text
-				s->type = STEXT;
-				break;
-			default:
-				werrstr("unexpected flags %#08ux for PE section %s", sect->sh.Characteristics, sect->name);
-				goto bad;
-		}
-		s->p = sect->base;
-		s->np = sect->size;
-		s->size = sect->size;
-		sect->sym = s;
-		if(strcmp(sect->name, ".rsrc") == 0)
-			setpersrc(sect->sym);
-	}
-	
-	// load relocations
-	for(i=0; i<obj->nsect; i++) {
-		rsect = &obj->sect[i];
-		if(rsect->sym == 0 || rsect->sh.NumberOfRelocations == 0)
-			continue;
-		if(rsect->sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE)
-			continue;
-		if((sect->sh.Characteristics&(IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_CNT_UNINITIALIZED_DATA)) == 0) {
-			// This has been seen for .idata sections, which we
-			// want to ignore.  See issues 5106 and 5273.
-			continue;
-		}
-		r = mal(rsect->sh.NumberOfRelocations*sizeof r[0]);
-		Bseek(f, obj->base+rsect->sh.PointerToRelocations, 0);
-		for(j=0; j<rsect->sh.NumberOfRelocations; j++) {
-			rp = &r[j];
-			if(Bread(f, symbuf, 10) != 10)
-				goto bad;
-			
-			uint32 rva, symindex;
-			uint16 type;
-			rva = le32(&symbuf[0]);
-			symindex = le32(&symbuf[4]);
-			type = le16(&symbuf[8]);
-			if(readsym(obj, symindex, &sym) < 0)
-				goto bad;
-			if(sym->sym == nil) {
-				werrstr("reloc of invalid sym %s idx=%d type=%d", sym->name, symindex, sym->type);
-				goto bad;
-			}
-			rp->sym = sym->sym;
-			rp->siz = 4;
-			rp->off = rva;
-			switch(type) {
-				default:
-					diag("%s: unknown relocation type %d;", pn, type);
-				case IMAGE_REL_I386_REL32:
-				case IMAGE_REL_AMD64_REL32:
-				case IMAGE_REL_AMD64_ADDR32: // R_X86_64_PC32
-				case IMAGE_REL_AMD64_ADDR32NB:
-					rp->type = R_PCREL;
-					rp->add = (int32)le32(rsect->base+rp->off);
-					break;
-				case IMAGE_REL_I386_DIR32NB:
-				case IMAGE_REL_I386_DIR32:
-					rp->type = R_ADDR;
-					// load addend from image
-					rp->add = (int32)le32(rsect->base+rp->off);
-					break;
-				case IMAGE_REL_AMD64_ADDR64: // R_X86_64_64
-					rp->siz = 8;
-					rp->type = R_ADDR;
-					// load addend from image
-					rp->add = le64(rsect->base+rp->off);
-					break;
-			}
-			// ld -r could generate multiple section symbols for the
-			// same section but with different values, we have to take
-			// that into account
-			if(issect(&obj->pesym[symindex]))
-				rp->add += obj->pesym[symindex].value;
-		}
-		qsort(r, rsect->sh.NumberOfRelocations, sizeof r[0], rbyoff);
-		
-		s = rsect->sym;
-		s->r = r;
-		s->nr = rsect->sh.NumberOfRelocations;
-	}
-
-	// enter sub-symbols into symbol table.
-	for(i=0; i<obj->npesym; i++) {
-		if(obj->pesym[i].name == 0)
-			continue;
-		if(issect(&obj->pesym[i]))
-			continue;
-		if(obj->pesym[i].sectnum > 0) {
-			sect = &obj->sect[obj->pesym[i].sectnum-1];
-			if(sect->sym == 0)
-				continue;
-		}
-		if(readsym(obj, i, &sym) < 0)
-			goto bad;
-	
-		s = sym->sym;
-		if(sym->sectnum == 0) {// extern
-			if(s->type == SDYNIMPORT)
-				s->plt = -2; // flag for dynimport in PE object files.
-			if (s->type == SXREF && sym->value > 0) {// global data
-				s->type = SNOPTRDATA;
-				s->size = sym->value;
-			}
-			continue;
-		} else if (sym->sectnum > 0) {
-			sect = &obj->sect[sym->sectnum-1];
-			if(sect->sym == 0)
-				diag("%s: %s sym == 0!", pn, s->name);
-		} else {
-			diag("%s: %s sectnum < 0!", pn, s->name);
-		}
-
-		if(sect == nil) 
-			return;
-
-		if(s->outer != S) {
-			if(s->dupok)
-				continue;
-			diag("%s: duplicate symbol reference: %s in both %s and %s", pn, s->name, s->outer->name, sect->sym->name);
-			errorexit();
-		}
-		s->sub = sect->sym->sub;
-		sect->sym->sub = s;
-		s->type = sect->sym->type | SSUB;
-		s->value = sym->value;
-		s->size = 4;
-		s->outer = sect->sym;
-		if(sect->sym->type == STEXT) {
-			if(s->external && !s->dupok)
-				diag("%s: duplicate definition of %s", pn, s->name);
-			s->external = 1;
-		}
-	}
-
-	// Sort outer lists by address, adding to textp.
-	// This keeps textp in increasing address order.
-	for(i=0; i<obj->nsect; i++) {
-		s = obj->sect[i].sym;
-		if(s == S)
-			continue;
-		if(s->sub)
-			s->sub = listsort(s->sub, valuecmp, offsetof(LSym, sub));
-		if(s->type == STEXT) {
-			if(s->onlist)
-				sysfatal("symbol %s listed multiple times", s->name);
-			s->onlist = 1;
-			if(ctxt->etextp)
-				ctxt->etextp->next = s;
-			else
-				ctxt->textp = s;
-			ctxt->etextp = s;
-			for(s = s->sub; s != S; s = s->sub) {
-				if(s->onlist)
-					sysfatal("symbol %s listed multiple times", s->name);
-				s->onlist = 1;
-				ctxt->etextp->next = s;
-				ctxt->etextp = s;
-			}
-		}
-	}
-
-	return;
-bad:
-	diag("%s: malformed pe file: %r", pn);
-}
-
-static int
-map(PeObj *obj, PeSect *sect)
-{
-	if(sect->base != nil)
-		return 0;
-
-	sect->base = mal(sect->sh.SizeOfRawData);
-	if(sect->sh.PointerToRawData == 0) // .bss doesn't have data in object file
-		return 0;
-	werrstr("short read");
-	if(Bseek(obj->f, obj->base+sect->sh.PointerToRawData, 0) < 0 || 
-			Bread(obj->f, sect->base, sect->sh.SizeOfRawData) != sect->sh.SizeOfRawData)
-		return -1;
-	
-	return 0;
-}
-
-static int
-issect(PeSym *s)
-{
-	return s->sclass == IMAGE_SYM_CLASS_STATIC && s->type == 0 && s->name[0] == '.';
-}
-
-static int
-readsym(PeObj *obj, int i, PeSym **y)
-{
-	LSym *s;
-	PeSym *sym;
-	char *name, *p;
-
-	if(i >= obj->npesym || i < 0) {
-		werrstr("invalid pe symbol index");
-		return -1;
-	}
-
-	sym = &obj->pesym[i];
-	*y = sym;
-	
-	if(issect(sym))
-		name = obj->sect[sym->sectnum-1].sym->name;
-	else {
-		name = sym->name;
-		if(strncmp(name, "__imp_", 6) == 0)
-			name = &name[6]; // __imp_Name => Name
-		if(thechar == '8' && name[0] == '_')
-			name = &name[1]; // _Name => Name
-	}
-	// remove last @XXX
-	p = strchr(name, '@');
-	if(p)
-		*p = 0;
-	
-	switch(sym->type) {
-	default:
-		werrstr("%s: invalid symbol type %d", sym->name, sym->type);
-		return -1;
-	case IMAGE_SYM_DTYPE_FUNCTION:
-	case IMAGE_SYM_DTYPE_NULL:
-		switch(sym->sclass) {
-		case IMAGE_SYM_CLASS_EXTERNAL: //global
-			s = linklookup(ctxt, name, 0);
-			break;
-		case IMAGE_SYM_CLASS_NULL:
-		case IMAGE_SYM_CLASS_STATIC:
-		case IMAGE_SYM_CLASS_LABEL:
-			s = linklookup(ctxt, name, ctxt->version);
-			s->dupok = 1;
-			break;
-		default:
-			werrstr("%s: invalid symbol binding %d", sym->name, sym->sclass);
-			return -1;
-		}
-		break;
-	}
-
-	if(s != nil && s->type == 0 && !(sym->sclass == IMAGE_SYM_CLASS_STATIC && sym->value == 0))
-		s->type = SXREF;
-	if(strncmp(sym->name, "__imp_", 6) == 0)
-		s->got = -2; // flag for __imp_
-	sym->sym = s;
-
-	return 0;
-}
diff --git a/src/cmd/ld/lib.c b/src/cmd/ld/lib.c
deleted file mode 100644
index f889aba..0000000
--- a/src/cmd/ld/lib.c
+++ /dev/null
@@ -1,1617 +0,0 @@
-// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include	"l.h"
-#include	"lib.h"
-#include	"../ld/elf.h"
-#include	"../ld/dwarf.h"
-#include	"../../runtime/stack.h"
-#include	"../../runtime/funcdata.h"
-
-#include	<ar.h>
-#if !(defined(_WIN32) || defined(PLAN9))
-#include	<sys/stat.h>
-#endif
-
-enum
-{
-	// Whether to assume that the external linker is "gold"
-	// (http://sourceware.org/ml/binutils/2008-03/msg00162.html).
-	AssumeGoldLinker = 0,
-};
-
-int iconv(Fmt*);
-
-char	symname[]	= SYMDEF;
-char	pkgname[]	= "__.PKGDEF";
-static int	cout = -1;
-
-extern int	version;
-
-// 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.
-static int	externalobj = 0;
-
-static	void	hostlinksetup(void);
-
-char*	goroot;
-char*	goarch;
-char*	goos;
-char*	theline;
-
-void
-Lflag(char *arg)
-{
-	char **p;
-
-	if(ctxt->nlibdir >= ctxt->maxlibdir) {
-		if (ctxt->maxlibdir == 0)
-			ctxt->maxlibdir = 8;
-		else
-			ctxt->maxlibdir *= 2;
-		p = erealloc(ctxt->libdir, ctxt->maxlibdir * sizeof(*p));
-		ctxt->libdir = p;
-	}
-	ctxt->libdir[ctxt->nlibdir++] = arg;
-}
-
-/*
- * Unix doesn't like it when we write to a running (or, sometimes,
- * recently run) binary, so remove the output file before writing it.
- * On Windows 7, remove() can force a subsequent create() to fail.
- * S_ISREG() does not exist on Plan 9.
- */
-static void
-mayberemoveoutfile(void) 
-{
-#if !(defined(_WIN32) || defined(PLAN9))
-	struct stat st;
-	if(lstat(outfile, &st) == 0 && !S_ISREG(st.st_mode))
-		return;
-#endif
-	remove(outfile);
-}
-
-void
-libinit(void)
-{
-	char *suffix, *suffixsep;
-
-	funcalign = FuncAlign;
-	fmtinstall('i', iconv);
-	fmtinstall('Y', Yconv);
-	fmtinstall('Z', Zconv);
-	mywhatsys();	// get goroot, goarch, goos
-
-	// add goroot to the end of the libdir list.
-	suffix = "";
-	suffixsep = "";
-	if(flag_installsuffix != nil) {
-		suffixsep = "_";
-		suffix = flag_installsuffix;
-	} else if(flag_race) {
-		suffixsep = "_";
-		suffix = "race";
-	}
-	Lflag(smprint("%s/pkg/%s_%s%s%s", goroot, goos, goarch, suffixsep, suffix));
-
-	mayberemoveoutfile();
-	cout = create(outfile, 1, 0775);
-	if(cout < 0) {
-		diag("cannot create %s: %r", outfile);
-		errorexit();
-	}
-
-	if(INITENTRY == nil) {
-		INITENTRY = mal(strlen(goarch)+strlen(goos)+20);
-		if(!flag_shared) {
-			sprint(INITENTRY, "_rt0_%s_%s", goarch, goos);
-		} else {
-			sprint(INITENTRY, "_rt0_%s_%s_lib", goarch, goos);
-		}
-	}
-	linklookup(ctxt, INITENTRY, 0)->type = SXREF;
-}
-
-void
-errorexit(void)
-{
-	if(cout >= 0) {
-		// For rmtemp run at atexit time on Windows.
-		close(cout);
-	}
-	if(nerrors) {
-		if(cout >= 0)
-			mayberemoveoutfile();
-		exits("error");
-	}
-	exits(0);
-}
-
-void
-loadinternal(char *name)
-{
-	char pname[1024];
-	int i, found;
-
-	found = 0;
-	for(i=0; i<ctxt->nlibdir; i++) {
-		snprint(pname, sizeof pname, "%s/%s.a", ctxt->libdir[i], name);
-		if(debug['v'])
-			Bprint(&bso, "searching for %s.a in %s\n", name, pname);
-		if(access(pname, AEXIST) >= 0) {
-			addlibpath(ctxt, "internal", "internal", pname, name);
-			found = 1;
-			break;
-		}
-	}
-	if(!found)
-		Bprint(&bso, "warning: unable to find %s.a\n", name);
-}
-
-void
-loadlib(void)
-{
-	int i, w, x;
-	LSym *s, *tlsg;
-	char* cgostrsym;
-
-	if(flag_shared) {
-		s = linklookup(ctxt, "runtime.islibrary", 0);
-		s->dupok = 1;
-		adduint8(ctxt, s, 1);
-	}
-
-	loadinternal("runtime");
-	if(thechar == '5')
-		loadinternal("math");
-	if(flag_race)
-		loadinternal("runtime/race");
-
-	for(i=0; i<ctxt->libraryp; i++) {
-		if(debug['v'] > 1)
-			Bprint(&bso, "%5.2f autolib: %s (from %s)\n", cputime(), ctxt->library[i].file, ctxt->library[i].objref);
-		iscgo |= strcmp(ctxt->library[i].pkg, "runtime/cgo") == 0;
-		objfile(ctxt->library[i].file, ctxt->library[i].pkg);
-	}
-	
-	if(linkmode == LinkExternal && !iscgo) {
-		// This indicates a user requested -linkmode=external.
-		// The startup code uses an import of runtime/cgo to decide
-		// whether to initialize the TLS.  So give it one.  This could
-		// be handled differently but it's an unusual case.
-		loadinternal("runtime/cgo");
-		if(i < ctxt->libraryp)
-			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 = 1;
-
-		// 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 = 1;
-			addstrdata(cgostrsym, "runtime/cgo");
-		}
-	}
-
-	if(linkmode == LinkAuto) {
-		if(iscgo && externalobj)
-			linkmode = LinkExternal;
-		else
-			linkmode = LinkInternal;
-
-		// Force external linking for android.
-		if(strcmp(goos, "android") == 0)
-			linkmode = LinkExternal;
-	}
-
-	if(linkmode == LinkInternal) {
-		// Drop all the cgo_import_static declarations.
-		// Turns out we won't be needing them.
-		for(s = ctxt->allsym; s != S; s = s->allsym)
-			if(s->type == SHOSTOBJ) {
-				// If a symbol was marked both
-				// cgo_import_static and cgo_import_dynamic,
-				// then we want to make it cgo_import_dynamic
-				// now.
-				if(s->extname != nil && s->dynimplib != nil && s->cgoexport == 0) {
-					s->type = SDYNIMPORT;
-				} else
-					s->type = 0;
-			}
-	}
-	
-	tlsg = linklookup(ctxt, "runtime.tlsg", 0);
-	tlsg->type = STLSBSS;
-	tlsg->size = PtrSize;
-	tlsg->hide = 1;
-	tlsg->reachable = 1;
-	ctxt->tlsg = tlsg;
-
-	// Now that we know the link mode, trim the dynexp list.
-	x = CgoExportDynamic;
-	if(linkmode == LinkExternal)
-		x = CgoExportStatic;
-	w = 0;
-	for(i=0; i<ndynexp; i++)
-		if(dynexp[i]->cgoexport & x)
-			dynexp[w++] = dynexp[i];
-	ndynexp = w;
-	
-	// In internal link mode, read the host object files.
-	if(linkmode == LinkInternal)
-		hostobjs();
-	else
-		hostlinksetup();
-
-	// We've loaded all the code now.
-	// If there are no dynamic libraries needed, gcc disables dynamic linking.
-	// Because of this, glibc's dynamic ELF loader occasionally (like in version 2.13)
-	// assumes that a dynamic binary always refers to at least one dynamic library.
-	// Rather than be a source of test cases for glibc, disable dynamic linking
-	// the same way that gcc would.
-	//
-	// Exception: on OS X, programs such as Shark only work with dynamic
-	// binaries, so leave it enabled on OS X (Mach-O) binaries.
-	// Also leave it enabled on Solaris which doesn't support
-	// statically linked binaries.
-	if(!flag_shared && !havedynamic && HEADTYPE != Hdarwin && HEADTYPE != Hsolaris)
-		debug['d'] = 1;
-	
-	importcycles();
-}
-
-/*
- * look for the next file in an archive.
- * adapted from libmach.
- */
-static vlong
-nextar(Biobuf *bp, vlong off, struct ar_hdr *a)
-{
-	int r;
-	int32 arsize;
-	char *buf;
-
-	if (off&01)
-		off++;
-	Bseek(bp, off, 0);
-	buf = Brdline(bp, '\n');
-	r = Blinelen(bp);
-	if(buf == nil) {
-		if(r == 0)
-			return 0;
-		return -1;
-	}
-	if(r != SAR_HDR)
-		return -1;
-	memmove(a, buf, SAR_HDR);
-	if(strncmp(a->fmag, ARFMAG, sizeof a->fmag))
-		return -1;
-	arsize = strtol(a->size, 0, 0);
-	if (arsize&1)
-		arsize++;
-	return arsize + r;
-}
-
-void
-objfile(char *file, char *pkg)
-{
-	vlong off, l;
-	Biobuf *f;
-	char magbuf[SARMAG];
-	char pname[150];
-	struct ar_hdr arhdr;
-
-	pkg = smprint("%i", pkg);
-
-	if(debug['v'] > 1)
-		Bprint(&bso, "%5.2f ldobj: %s (%s)\n", cputime(), file, pkg);
-	Bflush(&bso);
-	f = Bopen(file, 0);
-	if(f == nil) {
-		diag("cannot open file: %s", file);
-		errorexit();
-	}
-	l = Bread(f, magbuf, SARMAG);
-	if(l != SARMAG || strncmp(magbuf, ARMAG, SARMAG)){
-		/* load it as a regular file */
-		l = Bseek(f, 0L, 2);
-		Bseek(f, 0L, 0);
-		ldobj(f, pkg, l, file, file, FileObj);
-		Bterm(f);
-		free(pkg);
-		return;
-	}
-	
-	/* skip over optional __.GOSYMDEF and process __.PKGDEF */
-	off = Boffset(f);
-	l = nextar(f, off, &arhdr);
-	if(l <= 0) {
-		diag("%s: short read on archive file symbol header", file);
-		goto out;
-	}
-	if(strncmp(arhdr.name, symname, strlen(symname)) == 0) {
-		off += l;
-		l = nextar(f, off, &arhdr);
-		if(l <= 0) {
-			diag("%s: short read on archive file symbol header", file);
-			goto out;
-		}
-	}
-
-	if(strncmp(arhdr.name, pkgname, strlen(pkgname))) {
-		diag("%s: cannot find package header", file);
-		goto out;
-	}
-	off += l;
-
-	if(debug['u'])
-		ldpkg(f, pkg, atolwhex(arhdr.size), file, Pkgdef);
-
-	/*
-	 * load all the object files from the archive now.
-	 * this gives us sequential file access and keeps us
-	 * from needing to come back later to pick up more
-	 * objects.  it breaks the usual C archive model, but
-	 * this is Go, not C.  the common case in Go is that
-	 * we need to load all the objects, and then we throw away
-	 * the individual symbols that are unused.
-	 *
-	 * loading every object will also make it possible to
-	 * load foreign objects not referenced by __.GOSYMDEF.
-	 */
-	for(;;) {
-		l = nextar(f, off, &arhdr);
-		if(l == 0)
-			break;
-		if(l < 0) {
-			diag("%s: malformed archive", file);
-			goto out;
-		}
-		off += l;
-
-		l = SARNAME;
-		while(l > 0 && arhdr.name[l-1] == ' ')
-			l--;
-		snprint(pname, sizeof pname, "%s(%.*s)", file, utfnlen(arhdr.name, l), arhdr.name);
-		l = atolwhex(arhdr.size);
-		ldobj(f, pkg, l, pname, file, ArchiveObj);
-	}
-
-out:
-	Bterm(f);
-	free(pkg);
-}
-
-static void
-dowrite(int fd, char *p, int n)
-{
-	int m;
-	
-	while(n > 0) {
-		m = write(fd, p, n);
-		if(m <= 0) {
-			ctxt->cursym = S;
-			diag("write error: %r");
-			errorexit();
-		}
-		n -= m;
-		p += m;
-	}
-}
-
-typedef struct Hostobj Hostobj;
-
-struct Hostobj
-{
-	void (*ld)(Biobuf*, char*, int64, char*);
-	char *pkg;
-	char *pn;
-	char *file;
-	int64 off;
-	int64 len;
-};
-
-Hostobj *hostobj;
-int nhostobj;
-int mhostobj;
-
-// These packages can use internal linking mode.
-// Others trigger external mode.
-const char *internalpkg[] = {
-	"crypto/x509",
-	"net",
-	"os/user",
-	"runtime/cgo",
-	"runtime/race"
-};
-
-void
-ldhostobj(void (*ld)(Biobuf*, char*, int64, char*), Biobuf *f, char *pkg, int64 len, char *pn, char *file)
-{
-	int i, isinternal;
-	Hostobj *h;
-
-	isinternal = 0;
-	for(i=0; i<nelem(internalpkg); i++) {
-		if(strcmp(pkg, internalpkg[i]) == 0) {
-			isinternal = 1;
-			break;
-		}
-	}
-
-	// DragonFly declares errno with __thread, which results in a symbol
-	// type of R_386_TLS_GD or R_X86_64_TLSGD. The Go linker does not
-	// currently know how to handle TLS relocations, hence we have to
-	// force external linking for any libraries that link in code that
-	// uses errno. This can be removed if the Go linker ever supports
-	// these relocation types.
-	if(HEADTYPE == Hdragonfly)
-	if(strcmp(pkg, "net") == 0 || strcmp(pkg, "os/user") == 0)
-		isinternal = 0;
-
-	if(!isinternal)
-		externalobj = 1;
-
-	if(nhostobj >= mhostobj) {
-		if(mhostobj == 0)
-			mhostobj = 16;
-		else
-			mhostobj *= 2;
-		hostobj = erealloc(hostobj, mhostobj*sizeof hostobj[0]);
-	}
-	h = &hostobj[nhostobj++];
-	h->ld = ld;
-	h->pkg = estrdup(pkg);
-	h->pn = estrdup(pn);
-	h->file = estrdup(file);
-	h->off = Boffset(f);
-	h->len = len;
-}
-
-void
-hostobjs(void)
-{
-	int i;
-	Biobuf *f;
-	Hostobj *h;
-	
-	for(i=0; i<nhostobj; i++) {
-		h = &hostobj[i];
-		f = Bopen(h->file, OREAD);
-		if(f == nil) {
-			ctxt->cursym = S;
-			diag("cannot reopen %s: %r", h->pn);
-			errorexit();
-		}
-		Bseek(f, h->off, 0);
-		h->ld(f, h->pkg, h->len, h->pn);
-		Bterm(f);
-	}
-}
-
-// provided by lib9
-int runcmd(char**);
-char* mktempdir(void);
-void removeall(char*);
-
-static void
-rmtemp(void)
-{
-	removeall(tmpdir);
-}
-
-static void
-hostlinksetup(void)
-{
-	char *p;
-
-	if(linkmode != LinkExternal)
-		return;
-
-	// create temporary directory and arrange cleanup
-	if(tmpdir == nil) {
-		tmpdir = mktempdir();
-		atexit(rmtemp);
-	}
-
-	// change our output to temporary object file
-	close(cout);
-	p = smprint("%s/go.o", tmpdir);
-	cout = create(p, 1, 0775);
-	if(cout < 0) {
-		diag("cannot create %s: %r", p);
-		errorexit();
-	}
-	free(p);
-}
-
-void
-hostlink(void)
-{
-	char *p, **argv;
-	int c, i, w, n, argc, len;
-	Hostobj *h;
-	Biobuf *f;
-	static char buf[64<<10];
-
-	if(linkmode != LinkExternal || nerrors > 0)
-		return;
-
-	c = 0;
-	p = extldflags;
-	while(p != nil) {
-		while(*p == ' ')
-			p++;
-		if(*p == '\0')
-			break;
-		c++;
-		p = strchr(p + 1, ' ');
-	}
-
-	argv = malloc((14+nhostobj+nldflag+c)*sizeof argv[0]);
-	argc = 0;
-	if(extld == nil)
-		extld = "gcc";
-	argv[argc++] = extld;
-	switch(thechar){
-	case '8':
-		argv[argc++] = "-m32";
-		break;
-	case '6':
-		argv[argc++] = "-m64";
-		break;
-	case '5':
-		argv[argc++] = "-marm";
-		break;
-	}
-	if(!debug['s'] && !debug_s) {
-		argv[argc++] = "-gdwarf-2"; 
-	} else {
-		argv[argc++] = "-s";
-	}
-	if(HEADTYPE == Hdarwin)
-		argv[argc++] = "-Wl,-no_pie,-pagezero_size,4000000";
-	if(HEADTYPE == Hopenbsd)
-		argv[argc++] = "-Wl,-nopie";
-	
-	if(iself && AssumeGoldLinker)
-		argv[argc++] = "-Wl,--rosegment";
-
-	if(flag_shared) {
-		argv[argc++] = "-Wl,-Bsymbolic";
-		argv[argc++] = "-shared";
-	}
-	argv[argc++] = "-o";
-	argv[argc++] = outfile;
-	
-	if(rpath)
-		argv[argc++] = smprint("-Wl,-rpath,%s", rpath);
-
-	// Force global symbols to be exported for dlopen, etc.
-	if(iself)
-		argv[argc++] = "-rdynamic";
-
-	if(strstr(argv[0], "clang") != nil)
-		argv[argc++] = "-Qunused-arguments";
-
-	// already wrote main object file
-	// copy host objects to temporary directory
-	for(i=0; i<nhostobj; i++) {
-		h = &hostobj[i];
-		f = Bopen(h->file, OREAD);
-		if(f == nil) {
-			ctxt->cursym = S;
-			diag("cannot reopen %s: %r", h->pn);
-			errorexit();
-		}
-		Bseek(f, h->off, 0);
-		p = smprint("%s/%06d.o", tmpdir, i);
-		argv[argc++] = p;
-		w = create(p, 1, 0775);
-		if(w < 0) {
-			ctxt->cursym = S;
-			diag("cannot create %s: %r", p);
-			errorexit();
-		}
-		len = h->len;
-		while(len > 0 && (n = Bread(f, buf, sizeof buf)) > 0){
-			if(n > len)
-				n = len;
-			dowrite(w, buf, n);
-			len -= n;
-		}
-		if(close(w) < 0) {
-			ctxt->cursym = S;
-			diag("cannot write %s: %r", p);
-			errorexit();
-		}
-		Bterm(f);
-	}
-	
-	argv[argc++] = smprint("%s/go.o", tmpdir);
-	for(i=0; i<nldflag; i++)
-		argv[argc++] = ldflag[i];
-
-	p = extldflags;
-	while(p != nil) {
-		while(*p == ' ')
-			*p++ = '\0';
-		if(*p == '\0')
-			break;
-		argv[argc++] = p;
-
-		// clang, unlike GCC, passes -rdynamic to the linker
-		// even when linking with -static, causing a linker
-		// error when using GNU ld.  So take out -rdynamic if
-		// we added it.  We do it in this order, rather than
-		// only adding -rdynamic later, so that -extldflags
-		// can override -rdynamic without using -static.
-		if(iself && strncmp(p, "-static", 7) == 0 && (p[7]==' ' || p[7]=='\0')) {
-			for(i=0; i<argc; i++) {
-				if(strcmp(argv[i], "-rdynamic") == 0)
-					argv[i] = "-static";
-			}
-		}
-
-		p = strchr(p + 1, ' ');
-	}
-
-	argv[argc] = nil;
-
-	quotefmtinstall();
-	if(debug['v']) {
-		Bprint(&bso, "host link:");
-		for(i=0; i<argc; i++)
-			Bprint(&bso, " %q", argv[i]);
-		Bprint(&bso, "\n");
-		Bflush(&bso);
-	}
-
-	if(runcmd(argv) < 0) {
-		ctxt->cursym = S;
-		diag("%s: running %s failed: %r", argv0, argv[0]);
-		errorexit();
-	}
-}
-
-void
-ldobj(Biobuf *f, char *pkg, int64 len, char *pn, char *file, int whence)
-{
-	char *line;
-	int n, c1, c2, c3, c4;
-	uint32 magic;
-	vlong import0, import1, eof;
-	char *t;
-
-	eof = Boffset(f) + len;
-
-	pn = estrdup(pn);
-
-	c1 = BGETC(f);
-	c2 = BGETC(f);
-	c3 = BGETC(f);
-	c4 = BGETC(f);
-	Bungetc(f);
-	Bungetc(f);
-	Bungetc(f);
-	Bungetc(f);
-
-	magic = c1<<24 | c2<<16 | c3<<8 | c4;
-	if(magic == 0x7f454c46) {	// \x7F E L F
-		ldhostobj(ldelf, f, pkg, len, pn, file);
-		return;
-	}
-	if((magic&~1) == 0xfeedface || (magic&~0x01000000) == 0xcefaedfe) {
-		ldhostobj(ldmacho, f, pkg, len, pn, file);
-		return;
-	}
-	if(c1 == 0x4c && c2 == 0x01 || c1 == 0x64 && c2 == 0x86) {
-		ldhostobj(ldpe, f, pkg, len, pn, file);
-		return;
-	}
-
-	/* check the header */
-	line = Brdline(f, '\n');
-	if(line == nil) {
-		if(Blinelen(f) > 0) {
-			diag("%s: not an object file", pn);
-			return;
-		}
-		goto eof;
-	}
-	n = Blinelen(f) - 1;
-	line[n] = '\0';
-	if(strncmp(line, "go object ", 10) != 0) {
-		if(strlen(pn) > 3 && strcmp(pn+strlen(pn)-3, ".go") == 0) {
-			print("%cl: input %s is not .%c file (use %cg to compile .go files)\n", thechar, pn, thechar, thechar);
-			errorexit();
-		}
-		if(strcmp(line, thestring) == 0) {
-			// old header format: just $GOOS
-			diag("%s: stale object file", pn);
-			return;
-		}
-		diag("%s: not an object file", pn);
-		free(pn);
-		return;
-	}
-	
-	// First, check that the basic goos, goarch, and version match.
-	t = smprint("%s %s %s ", goos, getgoarch(), getgoversion());
-	line[n] = ' ';
-	if(strncmp(line+10, t, strlen(t)) != 0 && !debug['f']) {
-		line[n] = '\0';
-		diag("%s: object is [%s] expected [%s]", pn, line+10, t);
-		free(t);
-		free(pn);
-		return;
-	}
-	
-	// Second, check that longer lines match each other exactly,
-	// so that the Go compiler and write additional information
-	// that must be the same from run to run.
-	line[n] = '\0';
-	if(n-10 > strlen(t)) {
-		if(theline == nil)
-			theline = estrdup(line+10);
-		else if(strcmp(theline, line+10) != 0) {
-			line[n] = '\0';
-			diag("%s: object is [%s] expected [%s]", pn, line+10, theline);
-			free(t);
-			free(pn);
-			return;
-		}
-	}
-	free(t);
-	line[n] = '\n';
-
-	/* skip over exports and other info -- ends with \n!\n */
-	import0 = Boffset(f);
-	c1 = '\n';	// the last line ended in \n
-	c2 = BGETC(f);
-	c3 = BGETC(f);
-	while(c1 != '\n' || c2 != '!' || c3 != '\n') {
-		c1 = c2;
-		c2 = c3;
-		c3 = BGETC(f);
-		if(c3 == Beof)
-			goto eof;
-	}
-	import1 = Boffset(f);
-
-	Bseek(f, import0, 0);
-	ldpkg(f, pkg, import1 - import0 - 2, pn, whence);	// -2 for !\n
-	Bseek(f, import1, 0);
-
-	ldobjfile(ctxt, f, pkg, eof - Boffset(f), pn);
-	free(pn);
-	return;
-
-eof:
-	diag("truncated object file: %s", pn);
-	free(pn);
-}
-
-void
-zerosig(char *sp)
-{
-	LSym *s;
-
-	s = linklookup(ctxt, sp, 0);
-	s->sig = 0;
-}
-
-void
-mywhatsys(void)
-{
-	goroot = getgoroot();
-	goos = getgoos();
-	goarch = getgoarch();
-
-	if(strncmp(goarch, thestring, strlen(thestring)) != 0)
-		sysfatal("cannot use %cc with GOARCH=%s", thechar, goarch);
-}
-
-int
-pathchar(void)
-{
-	return '/';
-}
-
-static	uchar*	hunk;
-static	uint32	nhunk;
-#define	NHUNK	(10UL<<20)
-
-void*
-mal(uint32 n)
-{
-	void *v;
-
-	n = (n+7)&~7;
-	if(n > NHUNK) {
-		v = malloc(n);
-		if(v == nil) {
-			diag("out of memory");
-			errorexit();
-		}
-		memset(v, 0, n);
-		return v;
-	}
-	if(n > nhunk) {
-		hunk = malloc(NHUNK);
-		if(hunk == nil) {
-			diag("out of memory");
-			errorexit();
-		}
-		nhunk = NHUNK;
-	}
-
-	v = hunk;
-	nhunk -= n;
-	hunk += n;
-
-	memset(v, 0, n);
-	return v;
-}
-
-void
-unmal(void *v, uint32 n)
-{
-	n = (n+7)&~7;
-	if(hunk - n == v) {
-		hunk -= n;
-		nhunk += n;
-	}
-}
-
-// Copied from ../gc/subr.c:/^pathtoprefix; must stay in sync.
-/*
- * Convert raw string to the prefix that will be used in the symbol table.
- * Invalid bytes turn into %xx.	 Right now the only bytes that need
- * escaping are %, ., and ", but we escape all control characters too.
- *
- * If you edit this, edit ../gc/subr.c:/^pathtoprefix too.
- * If you edit this, edit ../../debug/goobj/read.go:/importPathToPrefix too.
- */
-static char*
-pathtoprefix(char *s)
-{
-	static char hex[] = "0123456789abcdef";
-	char *p, *r, *w, *l;
-	int n;
-
-	// find first character past the last slash, if any.
-	l = s;
-	for(r=s; *r; r++)
-		if(*r == '/')
-			l = r+1;
-
-	// check for chars that need escaping
-	n = 0;
-	for(r=s; *r; r++)
-		if(*r <= ' ' || (*r == '.' && r >= l) || *r == '%' || *r == '"' || *r >= 0x7f)
-			n++;
-
-	// quick exit
-	if(n == 0)
-		return s;
-
-	// escape
-	p = mal((r-s)+1+2*n);
-	for(r=s, w=p; *r; r++) {
-		if(*r <= ' ' || (*r == '.' && r >= l) || *r == '%' || *r == '"' || *r >= 0x7f) {
-			*w++ = '%';
-			*w++ = hex[(*r>>4)&0xF];
-			*w++ = hex[*r&0xF];
-		} else
-			*w++ = *r;
-	}
-	*w = '\0';
-	return p;
-}
-
-int
-iconv(Fmt *fp)
-{
-	char *p;
-
-	p = va_arg(fp->args, char*);
-	if(p == nil) {
-		fmtstrcpy(fp, "<nil>");
-		return 0;
-	}
-	p = pathtoprefix(p);
-	fmtstrcpy(fp, p);
-	return 0;
-}
-
-Section*
-addsection(Segment *seg, char *name, int rwx)
-{
-	Section **l;
-	Section *sect;
-	
-	for(l=&seg->sect; *l; l=&(*l)->next)
-		;
-	sect = mal(sizeof *sect);
-	sect->rwx = rwx;
-	sect->name = name;
-	sect->seg = seg;
-	sect->align = PtrSize; // everything is at least pointer-aligned
-	*l = sect;
-	return sect;
-}
-
-uint16
-le16(uchar *b)
-{
-	return b[0] | b[1]<<8;
-}
-
-uint32
-le32(uchar *b)
-{
-	return b[0] | b[1]<<8 | b[2]<<16 | (uint32)b[3]<<24;
-}
-
-uint64
-le64(uchar *b)
-{
-	return le32(b) | (uint64)le32(b+4)<<32;
-}
-
-uint16
-be16(uchar *b)
-{
-	return b[0]<<8 | b[1];
-}
-
-uint32
-be32(uchar *b)
-{
-	return (uint32)b[0]<<24 | b[1]<<16 | b[2]<<8 | b[3];
-}
-
-uint64
-be64(uchar *b)
-{
-	return (uvlong)be32(b)<<32 | be32(b+4);
-}
-
-Endian be = { be16, be32, be64 };
-Endian le = { le16, le32, le64 };
-
-typedef struct Chain Chain;
-struct Chain
-{
-	LSym *sym;
-	Chain *up;
-	int limit;  // limit on entry to sym
-};
-
-static int stkcheck(Chain*, int);
-static void stkprint(Chain*, int);
-static void stkbroke(Chain*, int);
-static LSym *morestack;
-static LSym *newstack;
-
-enum
-{
-	HasLinkRegister = (thechar == '5'),
-};
-
-// TODO: Record enough information in new object files to
-// allow stack checks here.
-
-static int
-callsize(void)
-{
-	if(thechar == '5')
-		return 0;
-	return RegSize;
-}
-
-void
-dostkcheck(void)
-{
-	Chain ch;
-	LSym *s;
-	
-	morestack = linklookup(ctxt, "runtime.morestack", 0);
-	newstack = linklookup(ctxt, "runtime.newstack", 0);
-
-	// Every splitting function ensures that there are at least StackLimit
-	// bytes available below SP when the splitting prologue finishes.
-	// If the splitting function calls F, then F begins execution with
-	// at least StackLimit - callsize() bytes available.
-	// Check that every function behaves correctly with this amount
-	// of stack, following direct calls in order to piece together chains
-	// of non-splitting functions.
-	ch.up = nil;
-	ch.limit = StackLimit - callsize();
-
-	// 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) {
-		// 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.
-		if(strcmp(s->name, "runtime.racesymbolizethunk") == 0)
-			continue;
-
-		if(s->nosplit) {
-		ctxt->cursym = s;
-		ch.sym = s;
-		stkcheck(&ch, 0);
-	}
-	}
-	for(s = ctxt->textp; s != nil; s = s->next) {
-		if(!s->nosplit) {
-		ctxt->cursym = s;
-		ch.sym = s;
-		stkcheck(&ch, 0);
-	}
-}
-}
-
-static int
-stkcheck(Chain *up, int depth)
-{
-	Chain ch, ch1;
-	LSym *s;
-	int limit;
-	Reloc *r, *endr;
-	Pciter pcsp;
-	
-	limit = up->limit;
-	s = up->sym;
-	
-	// Don't duplicate work: only need to consider each
-	// function at top of safe zone once.
-	if(limit == StackLimit-callsize()) {
-		if(s->stkcheck)
-		return 0;
-		s->stkcheck = 1;
-	}
-	
-	if(depth > 100) {
-		diag("nosplit stack check too deep");
-		stkbroke(up, 0);
-		return -1;
-	}
-
-	if(s->external || s->pcln == nil) {
-		// external function.
-		// should never be called directly.
-		// only diagnose the direct caller.
-		if(depth == 1 && s->type != SXREF)
-			diag("call to external function %s", s->name);
-		return -1;
-	}
-
-	if(limit < 0) {
-		stkbroke(up, limit);
-		return -1;
-	}
-
-	// morestack looks like it calls functions,
-	// but it switches the stack pointer first.
-	if(s == morestack)
-		return 0;
-
-	ch.up = up;
-	
-	// Walk through sp adjustments in function, consuming relocs.
-	r = s->r;
-	endr = r + s->nr;
-	for(pciterinit(ctxt, &pcsp, &s->pcln->pcsp); !pcsp.done; pciternext(&pcsp)) {
-		// pcsp.value is in effect for [pcsp.pc, pcsp.nextpc).
-
-		// Check stack size in effect for this span.
-		if(limit - pcsp.value < 0) {
-			stkbroke(up, limit - pcsp.value);
-			return -1;
-		}
-
-		// Process calls in this span.
-		for(; r < endr && r->off < pcsp.nextpc; r++) {
-			switch(r->type) {
-			case R_CALL:
-			case R_CALLARM:
-				// Direct call.
-				ch.limit = limit - pcsp.value - callsize();
-				ch.sym = r->sym;
-				if(stkcheck(&ch, depth+1) < 0)
-					return -1;
-
-				// If this is a call to morestack, we've just raised our limit back
-				// to StackLimit beyond the frame size.
-				if(strncmp(r->sym->name, "runtime.morestack", 17) == 0) {
-					limit = StackLimit + s->locals;
-					if(thechar == '5')
-						limit += 4; // saved LR
-				}
-				break;
-
-			case R_CALLIND:
-				// Indirect call.  Assume it is a call to a splitting function,
-				// so we have to make sure it can call morestack.
-				// Arrange the data structures to report both calls, so that
-				// if there is an error, stkprint shows all the steps involved.
-				ch.limit = limit - pcsp.value - callsize();
-				ch.sym = nil;
-				ch1.limit = ch.limit - callsize(); // for morestack in called prologue
-				ch1.up = &ch;
-				ch1.sym = morestack;
-				if(stkcheck(&ch1, depth+2) < 0)
-					return -1;
-				break;
-			}
-		}
-		}
-		
-	return 0;
-}
-
-static void
-stkbroke(Chain *ch, int limit)
-{
-	diag("nosplit stack overflow");
-	stkprint(ch, limit);
-}
-
-static void
-stkprint(Chain *ch, int limit)
-{
-	char *name;
-
-	if(ch->sym)
-		name = ch->sym->name;
-	else
-		name = "function pointer";
-
-	if(ch->up == nil) {
-		// top of chain.  ch->sym != nil.
-		if(ch->sym->nosplit)
-			print("\t%d\tassumed on entry to %s\n", ch->limit, name);
-		else
-			print("\t%d\tguaranteed after split check in %s\n", ch->limit, name);
-	} else {
-		stkprint(ch->up, ch->limit + (!HasLinkRegister)*PtrSize);
-		if(!HasLinkRegister)
-			print("\t%d\ton entry to %s\n", ch->limit, name);
-	}
-	if(ch->limit != limit)
-		print("\t%d\tafter %s uses %d\n", limit, name, ch->limit - limit);
-}
-
-int
-Yconv(Fmt *fp)
-{
-	LSym *s;
-	Fmt fmt;
-	int i;
-	char *str;
-
-	s = va_arg(fp->args, LSym*);
-	if (s == S) {
-		fmtprint(fp, "<nil>");
-	} else {
-		fmtstrinit(&fmt);
-		fmtprint(&fmt, "%s @0x%08llx [%lld]", s->name, (vlong)s->value, (vlong)s->size);
-		for (i = 0; i < s->size; i++) {
-			if (!(i%8)) fmtprint(&fmt,  "\n\t0x%04x ", i);
-			fmtprint(&fmt, "%02x ", s->p[i]);
-		}
-		fmtprint(&fmt, "\n");
-		for (i = 0; i < s->nr; i++) {
-			fmtprint(&fmt, "\t0x%04x[%x] %d %s[%llx]\n",
-			      s->r[i].off,
-			      s->r[i].siz,
-			      s->r[i].type,
-			      s->r[i].sym->name,
-			      (vlong)s->r[i].add);
-		}
-		str = fmtstrflush(&fmt);
-		fmtstrcpy(fp, str);
-		free(str);
-	}
-
-	return 0;
-}
-
-vlong coutpos;
-
-void
-cflush(void)
-{
-	int n;
-
-	if(cbpmax < cbp)
-		cbpmax = cbp;
-	n = cbpmax - buf.cbuf;
-	dowrite(cout, buf.cbuf, n);
-	coutpos += n;
-	cbp = buf.cbuf;
-	cbc = sizeof(buf.cbuf);
-	cbpmax = cbp;
-}
-
-vlong
-cpos(void)
-{
-	return coutpos + cbp - buf.cbuf;
-}
-
-void
-cseek(vlong p)
-{
-	vlong start;
-	int delta;
-
-	if(cbpmax < cbp)
-		cbpmax = cbp;
-	start = coutpos;
-	if(start <= p && p <= start+(cbpmax - buf.cbuf)) {
-//print("cseek %lld in [%lld,%lld] (%lld)\n", p, start, start+sizeof(buf.cbuf), cpos());
-		delta = p - (start + cbp - buf.cbuf);
-		cbp += delta;
-		cbc -= delta;
-//print("now at %lld\n", cpos());
-		return;
-	}
-
-	cflush();
-	seek(cout, p, 0);
-	coutpos = p;
-}
-
-void
-cwrite(void *buf, int n)
-{
-	cflush();
-	if(n <= 0)
-		return;
-	dowrite(cout, buf, n);
-	coutpos += n;
-}
-
-void
-usage(void)
-{
-	fprint(2, "usage: %cl [options] main.%c\n", thechar, thechar);
-	flagprint(2);
-	exits("usage");
-}
-
-void
-setheadtype(char *s)
-{
-	int h;
-	
-	h = headtype(s);
-	if(h < 0) {
-		fprint(2, "unknown header type -H %s\n", s);
-		errorexit();
-	}
-	headstring = s;
-	HEADTYPE = headtype(s);
-}
-
-void
-setinterp(char *s)
-{
-	debug['I'] = 1; // denote cmdline interpreter override
-	interpreter = s;
-}
-
-void
-doversion(void)
-{
-	print("%cl version %s\n", thechar, getgoversion());
-	errorexit();
-}
-
-void
-genasmsym(void (*put)(LSym*, char*, int, vlong, vlong, int, LSym*))
-{
-	Auto *a;
-	LSym *s;
-	int32 off;
-
-	// 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);
-	if(s->type == STEXT)
-		put(s, s->name, 'T', s->value, s->size, s->version, 0);
-	s = linklookup(ctxt, "runtime.etext", 0);
-	if(s->type == STEXT)
-		put(s, s->name, 'T', s->value, s->size, s->version, 0);
-
-	for(s=ctxt->allsym; s!=S; s=s->allsym) {
-		if(s->hide || (s->name[0] == '.' && s->version == 0 && strcmp(s->name, ".rathole") != 0))
-			continue;
-		switch(s->type&SMASK) {
-		case SCONST:
-		case SRODATA:
-		case SSYMTAB:
-		case SPCLNTAB:
-		case SDATA:
-		case SNOPTRDATA:
-		case SELFROSECT:
-		case SMACHOGOT:
-		case STYPE:
-		case SSTRING:
-		case SGOSTRING:
-		case SWINDOWS:
-			if(!s->reachable)
-				continue;
-			put(s, s->name, 'D', symaddr(s), s->size, s->version, s->gotype);
-			continue;
-
-		case SBSS:
-		case SNOPTRBSS:
-			if(!s->reachable)
-				continue;
-			if(s->np > 0)
-				diag("%s should not be bss (size=%d type=%d special=%d)", s->name, (int)s->np, s->type, s->special);
-			put(s, s->name, 'B', symaddr(s), s->size, s->version, s->gotype);
-			continue;
-
-		case SFILE:
-			put(nil, s->name, 'f', s->value, 0, s->version, 0);
-			continue;
-		}
-	}
-
-	for(s = ctxt->textp; s != nil; s = s->next) {
-		put(s, s->name, 'T', s->value, s->size, s->version, s->gotype);
-
-		// NOTE(ality): acid can't produce a stack trace without .frame symbols
-		put(nil, ".frame", 'm', s->locals+PtrSize, 0, 0, 0);
-
-		for(a=s->autom; a; a=a->link) {
-			// Emit a or p according to actual offset, even if label is wrong.
-			// This avoids negative offsets, which cannot be encoded.
-			if(a->type != A_AUTO && a->type != A_PARAM)
-				continue;
-			
-			// compute offset relative to FP
-			if(a->type == A_PARAM)
-				off = a->aoffset;
-			else
-				off = a->aoffset - PtrSize;
-			
-			// FP
-			if(off >= 0) {
-				put(nil, a->asym->name, 'p', off, 0, 0, a->gotype);
-				continue;
-			}
-			
-			// SP
-			if(off <= -PtrSize) {
-				put(nil, a->asym->name, 'a', -(off+PtrSize), 0, 0, a->gotype);
-				continue;
-			}
-			
-			// Otherwise, off is addressing the saved program counter.
-			// Something underhanded is going on. Say nothing.
-		}
-	}
-	if(debug['v'] || debug['n'])
-		Bprint(&bso, "%5.2f symsize = %ud\n", cputime(), symsize);
-	Bflush(&bso);
-}
-
-vlong
-symaddr(LSym *s)
-{
-	if(!s->reachable)
-		diag("unreachable symbol in symaddr - %s", s->name);
-	return s->value;
-}
-
-void
-xdefine(char *p, int t, vlong v)
-{
-	LSym *s;
-
-	s = linklookup(ctxt, p, 0);
-	s->type = t;
-	s->value = v;
-	s->reachable = 1;
-	s->special = 1;
-}
-
-vlong
-datoff(vlong addr)
-{
-	if(addr >= segdata.vaddr)
-		return addr - segdata.vaddr + segdata.fileoff;
-	if(addr >= segtext.vaddr)
-		return addr - segtext.vaddr + segtext.fileoff;
-	diag("datoff %#llx", addr);
-	return 0;
-}
-
-vlong
-entryvalue(void)
-{
-	char *a;
-	LSym *s;
-
-	a = INITENTRY;
-	if(*a >= '0' && *a <= '9')
-		return atolwhex(a);
-	s = linklookup(ctxt, a, 0);
-	if(s->type == 0)
-		return INITTEXT;
-	if(s->type != STEXT)
-		diag("entry not text: %s", s->name);
-	return s->value;
-}
-
-static void
-undefsym(LSym *s)
-{
-	int i;
-	Reloc *r;
-
-	ctxt->cursym = s;
-	for(i=0; i<s->nr; i++) {
-		r = &s->r[i];
-		if(r->sym == nil) // happens for some external ARM relocs
-			continue;
-		if(r->sym->type == Sxxx || r->sym->type == SXREF)
-			diag("undefined: %s", r->sym->name);
-		if(!r->sym->reachable)
-			diag("use of unreachable symbol: %s", r->sym->name);
-	}
-}
-
-void
-undef(void)
-{
-	LSym *s;
-	
-	for(s = ctxt->textp; s != nil; s = s->next)
-		undefsym(s);
-	for(s = datap; s != nil; s = s->next)
-		undefsym(s);
-	if(nerrors > 0)
-		errorexit();
-}
-
-void
-callgraph(void)
-{
-	LSym *s;
-	Reloc *r;
-	int i;
-
-	if(!debug['c'])
-		return;
-
-	for(s = ctxt->textp; s != nil; s = s->next) {
-		for(i=0; i<s->nr; i++) {
-			r = &s->r[i];
-			if(r->sym == nil)
-				continue;
-			if((r->type == R_CALL || r->type == R_CALLARM) && r->sym->type == STEXT)
-				Bprint(&bso, "%s calls %s\n", s->name, r->sym->name);
-		}
-	}
-}
-
-void
-diag(char *fmt, ...)
-{
-	char buf[1024], *tn, *sep;
-	va_list arg;
-
-	tn = "";
-	sep = "";
-	if(ctxt->cursym != S) {
-		tn = ctxt->cursym->name;
-		sep = ": ";
-	}
-	va_start(arg, fmt);
-	vseprint(buf, buf+sizeof(buf), fmt, arg);
-	va_end(arg);
-	print("%s%s%s\n", tn, sep, buf);
-
-	nerrors++;
-	if(nerrors > 20) {
-		print("too many errors\n");
-		errorexit();
-	}
-}
-
-void
-checkgo(void)
-{
-	LSym *s;
-	Reloc *r;
-	int i;
-	int changed;
-	
-	if(!debug['C'])
-		return;
-	
-	// TODO(rsc,khr): Eventually we want to get to no Go-called C functions at all,
-	// which would simplify this logic quite a bit.
-
-	// Mark every Go-called C function with cfunc=2, recursively.
-	do {
-		changed = 0;
-		for(s = ctxt->textp; s != nil; s = s->next) {
-			if(s->cfunc == 0 || (s->cfunc == 2 && s->nosplit)) {
-				for(i=0; i<s->nr; i++) {
-					r = &s->r[i];
-					if(r->sym == nil)
-						continue;
-					if((r->type == R_CALL || r->type == R_CALLARM) && r->sym->type == STEXT) {
-						if(r->sym->cfunc == 1) {
-							changed = 1;
-							r->sym->cfunc = 2;
-						}
-					}
-				}
-			}
-		}
-	}while(changed);
-
-	// 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) {
-		if(s->cfunc == 0 || (s->cfunc == 2 && s->nosplit)) {
-			for(i=0; i<s->nr; i++) {
-				r = &s->r[i];
-				if(r->sym == nil)
-					continue;
-				if((r->type == R_CALL || r->type == R_CALLARM) && r->sym->type == STEXT) {
-					if(s->cfunc == 0 && r->sym->cfunc == 2 && !r->sym->nosplit)
-						print("Go %s calls C %s\n", s->name, r->sym->name);
-					else if(s->cfunc == 2 && s->nosplit && !r->sym->nosplit)
-						print("Go calls C %s calls %s\n", s->name, r->sym->name);
-				}
-			}
-		}
-	}
-}
diff --git a/src/cmd/ld/lib.h b/src/cmd/ld/lib.h
deleted file mode 100644
index 067ffa0..0000000
--- a/src/cmd/ld/lib.h
+++ /dev/null
@@ -1,289 +0,0 @@
-// Derived from Inferno utils/6l/l.h
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/l.h
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-// Terrible but standard terminology.
-// A segment describes a block of file to load into memory.
-// A section further describes the pieces of that block for
-// use in debuggers and such.
-
-enum {
-	MAXIO		= 8192,
-};
-
-typedef struct Segment Segment;
-typedef struct Section Section;
-
-struct Segment
-{
-	uchar	rwx;		// permission as usual unix bits (5 = r-x etc)
-	uvlong	vaddr;	// virtual address
-	uvlong	len;		// length in memory
-	uvlong	fileoff;	// file offset
-	uvlong	filelen;	// length on disk
-	Section*	sect;
-};
-
-#pragma incomplete struct Elf64_Shdr
-
-struct Section
-{
-	uchar	rwx;
-	int16	extnum;
-	int32	align;
-	char	*name;
-	uvlong	vaddr;
-	uvlong	len;
-	Section	*next;	// in segment list
-	Segment	*seg;
-	struct Elf64_Shdr *elfsect;
-	uvlong	reloff;
-	uvlong	rellen;
-};
-
-extern	char	symname[];
-
-EXTERN	char*	INITENTRY;
-extern	char*	thestring;
-extern	LinkArch*	thelinkarch;
-EXTERN	char*	outfile;
-EXTERN	int	ndynexp;
-EXTERN	LSym**	dynexp;
-EXTERN	int	nldflag;
-EXTERN	char**	ldflag;
-EXTERN	int	havedynamic;
-EXTERN	int	funcalign;
-EXTERN	int	iscgo;
-EXTERN	int	elfglobalsymndx;
-EXTERN	char*	flag_installsuffix;
-EXTERN	int	flag_race;
-EXTERN	int flag_shared;
-EXTERN	char*	tracksym;
-EXTERN	char*	interpreter;
-EXTERN	char*	tmpdir;
-EXTERN	char*	extld;
-EXTERN	char*	extldflags;
-EXTERN	int	debug_s; // backup old value of debug['s']
-EXTERN	Link*	ctxt;
-EXTERN	int32	HEADR;
-EXTERN	int32	HEADTYPE;
-EXTERN	int32	INITRND;
-EXTERN	int64	INITTEXT;
-EXTERN	int64	INITDAT;
-EXTERN	char*	INITENTRY;		/* entry point */
-EXTERN	char*	noname;
-EXTERN	char*	paramspace;
-EXTERN	int	nerrors;
-
-EXTERN	int	linkmode;
-EXTERN	int64	liveness;
-
-// for dynexport field of LSym
-enum
-{
-	CgoExportDynamic = 1<<0,
-	CgoExportStatic = 1<<1,
-};
-
-EXTERN	Segment	segtext;
-EXTERN	Segment	segrodata;
-EXTERN	Segment	segdata;
-EXTERN	Segment	segdwarf;
-
-typedef struct Endian Endian;
-struct Endian
-{
-	uint16	(*e16)(uchar*);
-	uint32	(*e32)(uchar*);
-	uint64	(*e64)(uchar*);
-};
-
-extern Endian be, le;
-
-/* set by call to mywhatsys() */
-extern	char*	goroot;
-extern	char*	goarch;
-extern	char*	goos;
-
-/* whence for ldpkg */
-enum {
-	FileObj = 0,
-	ArchiveObj,
-	Pkgdef
-};
-
-typedef struct Header Header;
-struct Header {
-	char *name;
-	int val;
-};
-
-EXTERN	char*	headstring;
-extern	Header	headers[];
-
-#pragma	varargck	type	"Y"	LSym*
-#pragma	varargck	type	"Z"	char*
-#pragma	varargck	type	"i"	char*
-
-// buffered output
-
-EXTERN	Biobuf	bso;
-
-EXTERN struct
-{
-	char	cbuf[MAXIO];	/* output buffer */
-} buf;
-
-EXTERN	int	cbc;
-EXTERN	char*	cbp;
-EXTERN	char*	cbpmax;
-
-#define	cput(c)\
-	{ *cbp++ = c;\
-	if(--cbc <= 0)\
-		cflush(); }
-
-void	Lflag(char *arg);
-int	Yconv(Fmt *fp);
-int	Zconv(Fmt *fp);
-void	addexport(void);
-void	address(void);
-Section*addsection(Segment *seg, char *name, int rwx);
-void	addstrdata(char *name, char *value);
-vlong	addstring(LSym *s, char *str);
-void	asmelfsym(void);
-void	asmplan9sym(void);
-uint16	be16(uchar *b);
-uint32	be32(uchar *b);
-uint64	be64(uchar *b);
-void	callgraph(void);
-void	checkgo(void);
-void	cflush(void);
-void	codeblk(int64 addr, int64 size);
-vlong	cpos(void);
-void	cseek(vlong p);
-void	cwrite(void *buf, int n);
-void	datblk(int64 addr, int64 size);
-int	datcmp(LSym *s1, LSym *s2);
-vlong	datoff(vlong addr);
-void	deadcode(void);
-LSym*	decodetype_arrayelem(LSym *s);
-vlong	decodetype_arraylen(LSym *s);
-LSym*	decodetype_chanelem(LSym *s);
-int	decodetype_funcdotdotdot(LSym *s);
-int	decodetype_funcincount(LSym *s);
-LSym*	decodetype_funcintype(LSym *s, int i);
-int	decodetype_funcoutcount(LSym *s);
-LSym*	decodetype_funcouttype(LSym *s, int i);
-LSym*	decodetype_gcprog(LSym *s);
-uint8*	decodetype_gcmask(LSym *s);
-vlong	decodetype_ifacemethodcount(LSym *s);
-uint8	decodetype_kind(LSym *s);
-uint8	decodetype_noptr(LSym *s);
-uint8	decodetype_usegcprog(LSym *s);
-LSym*	decodetype_mapkey(LSym *s);
-LSym*	decodetype_mapvalue(LSym *s);
-LSym*	decodetype_ptrelem(LSym *s);
-vlong	decodetype_size(LSym *s);
-int	decodetype_structfieldcount(LSym *s);
-char*	decodetype_structfieldname(LSym *s, int i);
-vlong	decodetype_structfieldoffs(LSym *s, int i);
-LSym*	decodetype_structfieldtype(LSym *s, int i);
-void	dodata(void);
-void	dostkcheck(void);
-void	dostkoff(void);
-void	dosymtype(void);
-void	doversion(void);
-void	doweak(void);
-void	dynreloc(void);
-void	dynrelocsym(LSym *s);
-vlong	entryvalue(void);
-void	errorexit(void);
-void	follow(void);
-void	genasmsym(void (*put)(LSym*, char*, int, vlong, vlong, int, LSym*));
-void	growdatsize(vlong *datsizep, LSym *s);
-char*	headstr(int v);
-int	headtype(char *name);
-void	hostlink(void);
-void	hostobjs(void);
-int	iconv(Fmt *fp);
-void	importcycles(void);
-void	linkarchinit(void);
-void	ldelf(Biobuf *f, char *pkg, int64 len, char *pn);
-void	ldhostobj(void (*ld)(Biobuf*, char*, int64, char*), Biobuf *f, char *pkg, int64 len, char *pn, char *file);
-void	ldmacho(Biobuf *f, char *pkg, int64 len, char *pn);
-void	ldobj(Biobuf *f, char *pkg, int64 len, char *pn, char *file, int whence);
-void	ldpe(Biobuf *f, char *pkg, int64 len, char *pn);
-void	ldpkg(Biobuf *f, char *pkg, int64 len, char *filename, int whence);
-uint16	le16(uchar *b);
-uint32	le32(uchar *b);
-uint64	le64(uchar *b);
-void	libinit(void);
-LSym*	listsort(LSym *l, int (*cmp)(LSym*, LSym*), int off);
-void	loadinternal(char *name);
-void	loadlib(void);
-void	lputb(int32 l);
-void	lputl(int32 l);
-void*	mal(uint32 n);
-void	mark(LSym *s);
-void	mywhatsys(void);
-struct ar_hdr;
-void	objfile(char *file, char *pkg);
-void	patch(void);
-int	pathchar(void);
-void	pcln(void);
-void	pclntab(void);
-void	putelfsectionsym(LSym* s, int shndx);
-void	putelfsymshndx(vlong sympos, int shndx);
-void	putsymb(LSym *s, char *name, int t, vlong v, vlong size, int ver, LSym *typ);
-int	rbyoff(const void *va, const void *vb);
-void	reloc(void);
-void	relocsym(LSym *s);
-void	setheadtype(char *s);
-void	setinterp(char *s);
-void	setlinkmode(char *arg);
-void	span(void);
-void	strnput(char *s, int n);
-vlong	symaddr(LSym *s);
-void	symtab(void);
-void	textaddress(void);
-void	undef(void);
-void	unmal(void *v, uint32 n);
-void	usage(void);
-void	vputb(uint64 v);
-int	valuecmp(LSym *a, LSym *b);
-void	vputl(uint64 v);
-void	wputb(ushort w);
-void	wputl(ushort w);
-void	xdefine(char *p, int t, vlong v);
-void	zerosig(char *sp);
-void	archinit(void);
-void	diag(char *fmt, ...);
-
-#pragma	varargck	argpos	diag	1
diff --git a/src/cmd/ld/macho.c b/src/cmd/ld/macho.c
deleted file mode 100644
index fe7e10e..0000000
--- a/src/cmd/ld/macho.c
+++ /dev/null
@@ -1,769 +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.
-
-// Mach-O file writing
-// http://developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html
-
-#include "l.h"
-#include "../ld/dwarf.h"
-#include "../ld/lib.h"
-#include "../ld/macho.h"
-
-static	int	macho64;
-static	MachoHdr	hdr;
-static	MachoLoad	*load;
-static	MachoSeg	seg[16];
-static	int	nload, mload, nseg, ndebug, nsect;
-
-enum
-{
-	SymKindLocal = 0,
-	SymKindExtdef,
-	SymKindUndef,
-	NumSymKind
-};
-
-static	int nkind[NumSymKind];
-static	LSym** sortsym;
-static	int	nsortsym;
-
-// Amount of space left for adding load commands
-// that refer to dynamic libraries.  Because these have
-// to go in the Mach-O header, we can't just pick a
-// "big enough" header size.  The initial header is 
-// one page, the non-dynamic library stuff takes
-// up about 1300 bytes; we overestimate that as 2k.
-static	int	load_budget = INITIAL_MACHO_HEADR - 2*1024;
-
-static	void	machodysymtab(void);
-
-void
-machoinit(void)
-{
-	switch(thechar) {
-	// 64-bit architectures
-	case '6':
-		macho64 = 1;
-		break;
-
-	// 32-bit architectures
-	default:
-		break;
-	}
-}
-
-MachoHdr*
-getMachoHdr(void)
-{
-	return &hdr;
-}
-
-MachoLoad*
-newMachoLoad(uint32 type, uint32 ndata)
-{
-	MachoLoad *l;
-
-	if(nload >= mload) {
-		if(mload == 0)
-			mload = 1;
-		else
-			mload *= 2;
-		load = erealloc(load, mload*sizeof load[0]);
-	}
-
-	if(macho64 && (ndata & 1))
-		ndata++;
-	
-	l = &load[nload++];
-	l->type = type;
-	l->ndata = ndata;
-	l->data = mal(ndata*4);
-	return l;
-}
-
-MachoSeg*
-newMachoSeg(char *name, int msect)
-{
-	MachoSeg *s;
-
-	if(nseg >= nelem(seg)) {
-		diag("too many segs");
-		errorexit();
-	}
-	s = &seg[nseg++];
-	s->name = name;
-	s->msect = msect;
-	s->sect = mal(msect*sizeof s->sect[0]);
-	return s;
-}
-
-MachoSect*
-newMachoSect(MachoSeg *seg, char *name, char *segname)
-{
-	MachoSect *s;
-
-	if(seg->nsect >= seg->msect) {
-		diag("too many sects in segment %s", seg->name);
-		errorexit();
-	}
-	s = &seg->sect[seg->nsect++];
-	s->name = name;
-	s->segname = segname;
-	nsect++;
-	return s;
-}
-
-// Generic linking code.
-
-static char **dylib;
-static int ndylib;
-
-static vlong linkoff;
-
-int
-machowrite(void)
-{
-	vlong o1;
-	int loadsize;
-	int i, j;
-	MachoSeg *s;
-	MachoSect *t;
-	MachoLoad *l;
-
-	o1 = cpos();
-
-	loadsize = 4*4*ndebug;
-	for(i=0; i<nload; i++)
-		loadsize += 4*(load[i].ndata+2);
-	if(macho64) {
-		loadsize += 18*4*nseg;
-		loadsize += 20*4*nsect;
-	} else {
-		loadsize += 14*4*nseg;
-		loadsize += 17*4*nsect;
-	}
-
-	if(macho64)
-		LPUT(0xfeedfacf);
-	else
-		LPUT(0xfeedface);
-	LPUT(hdr.cpu);
-	LPUT(hdr.subcpu);
-	if(linkmode == LinkExternal)
-		LPUT(1);	/* file type - mach object */
-	else
-		LPUT(2);	/* file type - mach executable */
-	LPUT(nload+nseg+ndebug);
-	LPUT(loadsize);
-	LPUT(1);	/* flags - no undefines */
-	if(macho64)
-		LPUT(0);	/* reserved */
-
-	for(i=0; i<nseg; i++) {
-		s = &seg[i];
-		if(macho64) {
-			LPUT(25);	/* segment 64 */
-			LPUT(72+80*s->nsect);
-			strnput(s->name, 16);
-			VPUT(s->vaddr);
-			VPUT(s->vsize);
-			VPUT(s->fileoffset);
-			VPUT(s->filesize);
-			LPUT(s->prot1);
-			LPUT(s->prot2);
-			LPUT(s->nsect);
-			LPUT(s->flag);
-		} else {
-			LPUT(1);	/* segment 32 */
-			LPUT(56+68*s->nsect);
-			strnput(s->name, 16);
-			LPUT(s->vaddr);
-			LPUT(s->vsize);
-			LPUT(s->fileoffset);
-			LPUT(s->filesize);
-			LPUT(s->prot1);
-			LPUT(s->prot2);
-			LPUT(s->nsect);
-			LPUT(s->flag);
-		}
-		for(j=0; j<s->nsect; j++) {
-			t = &s->sect[j];
-			if(macho64) {
-				strnput(t->name, 16);
-				strnput(t->segname, 16);
-				VPUT(t->addr);
-				VPUT(t->size);
-				LPUT(t->off);
-				LPUT(t->align);
-				LPUT(t->reloc);
-				LPUT(t->nreloc);
-				LPUT(t->flag);
-				LPUT(t->res1);	/* reserved */
-				LPUT(t->res2);	/* reserved */
-				LPUT(0);	/* reserved */
-			} else {
-				strnput(t->name, 16);
-				strnput(t->segname, 16);
-				LPUT(t->addr);
-				LPUT(t->size);
-				LPUT(t->off);
-				LPUT(t->align);
-				LPUT(t->reloc);
-				LPUT(t->nreloc);
-				LPUT(t->flag);
-				LPUT(t->res1);	/* reserved */
-				LPUT(t->res2);	/* reserved */
-			}
-		}
-	}
-
-	for(i=0; i<nload; i++) {
-		l = &load[i];
-		LPUT(l->type);
-		LPUT(4*(l->ndata+2));
-		for(j=0; j<l->ndata; j++)
-			LPUT(l->data[j]);
-	}
-
-	return cpos() - o1;
-}
-
-void
-domacho(void)
-{
-	LSym *s;
-
-	if(debug['d'])
-		return;
-
-	// empirically, string table must begin with " \x00".
-	s = linklookup(ctxt, ".machosymstr", 0);
-	s->type = SMACHOSYMSTR;
-	s->reachable = 1;
-	adduint8(ctxt, s, ' ');
-	adduint8(ctxt, s, '\0');
-	
-	s = linklookup(ctxt, ".machosymtab", 0);
-	s->type = SMACHOSYMTAB;
-	s->reachable = 1;
-	
-	if(linkmode != LinkExternal) {
-		s = linklookup(ctxt, ".plt", 0);	// will be __symbol_stub
-		s->type = SMACHOPLT;
-		s->reachable = 1;
-	
-		s = linklookup(ctxt, ".got", 0);	// will be __nl_symbol_ptr
-		s->type = SMACHOGOT;
-		s->reachable = 1;
-		s->align = 4;
-	
-		s = linklookup(ctxt, ".linkedit.plt", 0);	// indirect table for .plt
-		s->type = SMACHOINDIRECTPLT;
-		s->reachable = 1;
-	
-		s = linklookup(ctxt, ".linkedit.got", 0);	// indirect table for .got
-		s->type = SMACHOINDIRECTGOT;
-		s->reachable = 1;
-	}
-}
-
-void
-machoadddynlib(char *lib)
-{
-	// Will need to store the library name rounded up
-	// and 24 bytes of header metadata.  If not enough
-	// space, grab another page of initial space at the
-	// beginning of the output file.
-	load_budget -= (strlen(lib)+7)/8*8 + 24;
-	if(load_budget < 0) {
-		HEADR += 4096;
-		INITTEXT += 4096;
-		load_budget += 4096;
-	}
-
-	if(ndylib%32 == 0)
-		dylib = erealloc(dylib, (ndylib+32)*sizeof dylib[0]);
-	dylib[ndylib++] = lib;
-}
-
-static void
-machoshbits(MachoSeg *mseg, Section *sect, char *segname)
-{
-	MachoSect *msect;
-	char buf[40];
-	char *p;
-	
-	snprint(buf, sizeof buf, "__%s", sect->name+1);
-	for(p=buf; *p; p++)
-		if(*p == '.')
-			*p = '_';
-
-	msect = newMachoSect(mseg, estrdup(buf), segname);
-	if(sect->rellen > 0) {
-		msect->reloc = sect->reloff;
-		msect->nreloc = sect->rellen / 8;
-	}
-
-	while(1<<msect->align < sect->align)
-		msect->align++;
-	msect->addr = sect->vaddr;
-	msect->size = sect->len;
-	
-	if(sect->vaddr < sect->seg->vaddr + sect->seg->filelen) {
-		// data in file
-		if(sect->len > sect->seg->vaddr + sect->seg->filelen - sect->vaddr)
-			diag("macho cannot represent section %s crossing data and bss", sect->name);
-		msect->off = sect->seg->fileoff + sect->vaddr - sect->seg->vaddr;
-	} else {
-		// zero fill
-		msect->off = 0;
-		msect->flag |= 1;
-	}
-
-	if(sect->rwx & 1)
-		msect->flag |= 0x400; /* has instructions */
-	
-	if(strcmp(sect->name, ".plt") == 0) {
-		msect->name = "__symbol_stub1";
-		msect->flag = 0x80000408; /* only instructions, code, symbol stubs */
-		msect->res1 = 0;//nkind[SymKindLocal];
-		msect->res2 = 6;
-	}
-
-	if(strcmp(sect->name, ".got") == 0) {
-		msect->name = "__nl_symbol_ptr";
-		msect->flag = 6;	/* section with nonlazy symbol pointers */
-		msect->res1 = linklookup(ctxt, ".linkedit.plt", 0)->size / 4;	/* offset into indirect symbol table */
-	}
-}
-
-void
-asmbmacho(void)
-{
-	vlong v, w;
-	vlong va;
-	int a, i;
-	MachoHdr *mh;
-	MachoSeg *ms;
-	MachoLoad *ml;
-	Section *sect;
-
-	/* apple MACH */
-	va = INITTEXT - HEADR;
-	mh = getMachoHdr();
-	switch(thechar){
-	default:
-		diag("unknown mach architecture");
-		errorexit();
-	case '6':
-		mh->cpu = MACHO_CPU_AMD64;
-		mh->subcpu = MACHO_SUBCPU_X86;
-		break;
-	case '8':
-		mh->cpu = MACHO_CPU_386;
-		mh->subcpu = MACHO_SUBCPU_X86;
-		break;
-	}
-	
-	ms = nil;
-	if(linkmode == LinkExternal) {
-		/* segment for entire file */
-		ms = newMachoSeg("", 40);
-		ms->fileoffset = segtext.fileoff;
-		ms->filesize = segdata.fileoff + segdata.filelen - segtext.fileoff;
-	}
-
-	/* segment for zero page */
-	if(linkmode != LinkExternal) {
-		ms = newMachoSeg("__PAGEZERO", 0);
-		ms->vsize = va;
-	}
-
-	/* text */
-	v = rnd(HEADR+segtext.len, INITRND);
-	if(linkmode != LinkExternal) {
-		ms = newMachoSeg("__TEXT", 20);
-		ms->vaddr = va;
-		ms->vsize = v;
-		ms->fileoffset = 0;
-		ms->filesize = v;
-		ms->prot1 = 7;
-		ms->prot2 = 5;
-	}
-
-	for(sect=segtext.sect; sect!=nil; sect=sect->next)
-		machoshbits(ms, sect, "__TEXT");
-
-	/* data */
-	if(linkmode != LinkExternal) {
-		w = segdata.len;
-		ms = newMachoSeg("__DATA", 20);
-		ms->vaddr = va+v;
-		ms->vsize = w;
-		ms->fileoffset = v;
-		ms->filesize = segdata.filelen;
-		ms->prot1 = 3;
-		ms->prot2 = 3;
-	}
-
-	for(sect=segdata.sect; sect!=nil; sect=sect->next)
-		machoshbits(ms, sect, "__DATA");
-
-	if(linkmode != LinkExternal) {
-		switch(thechar) {
-		default:
-			diag("unknown macho architecture");
-			errorexit();
-		case '6':
-			ml = newMachoLoad(5, 42+2);	/* unix thread */
-			ml->data[0] = 4;	/* thread type */
-			ml->data[1] = 42;	/* word count */
-			ml->data[2+32] = entryvalue();	/* start pc */
-			ml->data[2+32+1] = entryvalue()>>16>>16;	// hide >>32 for 8l
-			break;
-		case '8':
-			ml = newMachoLoad(5, 16+2);	/* unix thread */
-			ml->data[0] = 1;	/* thread type */
-			ml->data[1] = 16;	/* word count */
-			ml->data[2+10] = entryvalue();	/* start pc */
-			break;
-		}
-	}
-	
-	if(!debug['d']) {
-		LSym *s1, *s2, *s3, *s4;
-
-		// must match domacholink below
-		s1 = linklookup(ctxt, ".machosymtab", 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->vaddr = va+v+rnd(segdata.len, INITRND);
-			ms->vsize = s1->size + s2->size + s3->size + s4->size;
-			ms->fileoffset = linkoff;
-			ms->filesize = ms->vsize;
-			ms->prot1 = 7;
-			ms->prot2 = 3;
-		}
-
-		ml = newMachoLoad(2, 4);	/* LC_SYMTAB */
-		ml->data[0] = linkoff;	/* symoff */
-		ml->data[1] = nsortsym;	/* nsyms */
-		ml->data[2] = linkoff + s1->size + s2->size + s3->size;	/* stroff */
-		ml->data[3] = s4->size;	/* strsize */
-
-		machodysymtab();
-
-		if(linkmode != LinkExternal) {
-			ml = newMachoLoad(14, 6);	/* LC_LOAD_DYLINKER */
-			ml->data[0] = 12;	/* offset to string */
-			strcpy((char*)&ml->data[1], "/usr/lib/dyld");
-	
-			for(i=0; i<ndylib; i++) {
-				ml = newMachoLoad(12, 4+(strlen(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 */
-				ml->data[2] = 0;	/* version */
-				ml->data[3] = 0;	/* compatibility version */
-				strcpy((char*)&ml->data[4], dylib[i]);
-			}
-		}
-	}
-
-	// TODO: dwarf headers go in ms too
-	if(!debug['s'] && linkmode != LinkExternal)
-		dwarfaddmachoheaders();
-
-	a = machowrite();
-	if(a > HEADR)
-		diag("HEADR too small: %d > %d", a, HEADR);
-}
-
-static int
-symkind(LSym *s)
-{
-	if(s->type == SDYNIMPORT)
-		return SymKindUndef;
-	if(s->cgoexport)
-		return SymKindExtdef;
-	return SymKindLocal;
-}
-
-static void
-addsym(LSym *s, char *name, int type, vlong addr, vlong size, int ver, LSym *gotype)
-{
-	USED(name);
-	USED(addr);
-	USED(size);
-	USED(ver);
-	USED(gotype);
-
-	if(s == nil)
-		return;
-
-	switch(type) {
-	default:
-		return;
-	case 'D':
-	case 'B':
-	case 'T':
-		break;
-	}
-	
-	if(sortsym) {
-		sortsym[nsortsym] = s;
-		nkind[symkind(s)]++;
-	}
-	nsortsym++;
-}
-	
-static int
-scmp(const void *p1, const void *p2)
-{
-	LSym *s1, *s2;
-	int k1, k2;
-
-	s1 = *(LSym**)p1;
-	s2 = *(LSym**)p2;
-	
-	k1 = symkind(s1);
-	k2 = symkind(s2);
-	if(k1 != k2)
-		return k1 - k2;
-
-	return strcmp(s1->extname, s2->extname);
-}
-
-static void
-machogenasmsym(void (*put)(LSym*, char*, int, vlong, vlong, int, LSym*))
-{
-	LSym *s;
-
-	genasmsym(put);
-	for(s=ctxt->allsym; s; s=s->allsym)
-		if(s->type == SDYNIMPORT || s->type == SHOSTOBJ)
-		if(s->reachable)
-			put(s, nil, 'D', 0, 0, 0, nil);
-}
-			
-void
-machosymorder(void)
-{
-	int i;
-
-	// 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<ndynexp; i++)
-		dynexp[i]->reachable = 1;
-	machogenasmsym(addsym);
-	sortsym = mal(nsortsym * sizeof sortsym[0]);
-	nsortsym = 0;
-	machogenasmsym(addsym);
-	qsort(sortsym, nsortsym, sizeof sortsym[0], scmp);
-	for(i=0; i<nsortsym; i++)
-		sortsym[i]->dynid = i;
-}
-
-static void
-machosymtab(void)
-{
-	int i;
-	LSym *symtab, *symstr, *s, *o;
-	char *p;
-
-	symtab = linklookup(ctxt, ".machosymtab", 0);
-	symstr = linklookup(ctxt, ".machosymstr", 0);
-
-	for(i=0; i<nsortsym; i++) {
-		s = sortsym[i];
-		adduint32(ctxt, symtab, symstr->size);
-		
-		// Only add _ to C symbols. Go symbols have dot in the name.
-		if(strstr(s->extname, ".") == nil)
-			adduint8(ctxt, symstr, '_');
-		// replace "·" as ".", because DTrace cannot handle it.
-		if(strstr(s->extname, "·") == nil) {
-			addstring(symstr, s->extname);
-		} else {
-			for(p = s->extname; *p; p++) {
-				if((uchar)*p == 0xc2 && (uchar)*(p+1) == 0xb7) {
-					adduint8(ctxt, symstr, '.');
-					p++;
-				} else {
-					adduint8(ctxt, symstr, *p);
-				}
-			}
-			adduint8(ctxt, symstr, '\0');
-		}
-		if(s->type == SDYNIMPORT || s->type == SHOSTOBJ) {
-			adduint8(ctxt, symtab, 0x01); // type N_EXT, external symbol
-			adduint8(ctxt, symtab, 0); // no section
-			adduint16(ctxt, symtab, 0); // desc
-			adduintxx(ctxt, symtab, 0, PtrSize); // no value
-		} else {
-			if(s->cgoexport)
-				adduint8(ctxt, symtab, 0x0f);
-			else
-				adduint8(ctxt, symtab, 0x0e);
-			o = s;
-			while(o->outer != nil)
-				o = o->outer;
-			if(o->sect == nil) {
-				diag("missing section for %s", s->name);
-				adduint8(ctxt, symtab, 0);
-			} else
-				adduint8(ctxt, symtab, o->sect->extnum);
-			adduint16(ctxt, symtab, 0); // desc
-			adduintxx(ctxt, symtab, symaddr(s), PtrSize);
-		}
-	}
-}
-
-static void
-machodysymtab(void)
-{
-	int n;
-	MachoLoad *ml;
-	LSym *s1, *s2, *s3;
-
-	ml = newMachoLoad(11, 18);	/* LC_DYSYMTAB */
-
-	n = 0;
-	ml->data[0] = n;	/* ilocalsym */
-	ml->data[1] = nkind[SymKindLocal];	/* nlocalsym */
-	n += nkind[SymKindLocal];
-
-	ml->data[2] = n;	/* iextdefsym */
-	ml->data[3] = nkind[SymKindExtdef];	/* nextdefsym */
-	n += nkind[SymKindExtdef];
-
-	ml->data[4] = n;	/* iundefsym */
-	ml->data[5] = nkind[SymKindUndef];	/* nundefsym */
-
-	ml->data[6] = 0;	/* tocoffset */
-	ml->data[7] = 0;	/* ntoc */
-	ml->data[8] = 0;	/* modtaboff */
-	ml->data[9] = 0;	/* nmodtab */
-	ml->data[10] = 0;	/* extrefsymoff */
-	ml->data[11] = 0;	/* nextrefsyms */
-
-	// must match domacholink below
-	s1 = linklookup(ctxt, ".machosymtab", 0);
-	s2 = linklookup(ctxt, ".linkedit.plt", 0);
-	s3 = linklookup(ctxt, ".linkedit.got", 0);
-	ml->data[12] = linkoff + s1->size;	/* indirectsymoff */
-	ml->data[13] = (s2->size + s3->size) / 4;	/* nindirectsyms */
-
-	ml->data[14] = 0;	/* extreloff */
-	ml->data[15] = 0;	/* nextrel */
-	ml->data[16] = 0;	/* locreloff */
-	ml->data[17] = 0;	/* nlocrel */
-}
-
-vlong
-domacholink(void)
-{
-	int size;
-	LSym *s1, *s2, *s3, *s4;
-
-	machosymtab();
-
-	// write data that will be linkedit section
-	s1 = linklookup(ctxt, ".machosymtab", 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
-	// to be code signed correctly.
-	//
-	// Apple's codesign_allocate (a helper utility for
-	// the codesign utility) can do this fine itself if
-	// it is run on a dynamic Mach-O binary.  However,
-	// when it is run on a pure (non-cgo) Go binary, where
-	// the linkedit section is mostly empty, it fails to
-	// account for the extra padding that it itself adds
-	// when adding the LC_CODE_SIGNATURE load command
-	// (which must be aligned on a 16-byte boundary).
-	//
-	// By forcing the linkedit section to end on a 16-byte
-	// boundary, codesign_allocate will not need to apply
-	// any alignment padding itself, working around the
-	// issue.
-	while(s4->size%16)
-		adduint8(ctxt, s4, 0);
-	
-	size = s1->size + s2->size + s3->size + s4->size;
-
-	if(size > 0) {
-		linkoff = rnd(HEADR+segtext.len, INITRND) + rnd(segdata.filelen, INITRND) + rnd(segdwarf.filelen, INITRND);
-		cseek(linkoff);
-
-		cwrite(s1->p, s1->size);
-		cwrite(s2->p, s2->size);
-		cwrite(s3->p, s3->size);
-		cwrite(s4->p, s4->size);
-	}
-
-	return rnd(size, INITRND);
-}
-
-
-void
-machorelocsect(Section *sect, LSym *first)
-{
-	LSym *sym;
-	int32 eaddr;
-	Reloc *r;
-
-	// If main section has no bits, nothing to relocate.
-	if(sect->vaddr >= sect->seg->vaddr + sect->seg->filelen)
-		return;
-	
-	sect->reloff = cpos();
-	for(sym = first; sym != nil; sym = sym->next) {
-		if(!sym->reachable)
-			continue;
-		if(sym->value >= sect->vaddr)
-			break;
-	}
-	
-	eaddr = sect->vaddr + sect->len;
-	for(; sym != nil; sym = sym->next) {
-		if(!sym->reachable)
-			continue;
-		if(sym->value >= eaddr)
-			break;
-		ctxt->cursym = sym;
-		
-		for(r = sym->r; r < sym->r+sym->nr; r++) {
-			if(r->done)
-				continue;
-			if(machoreloc1(r, sym->value+r->off - sect->vaddr) < 0)
-				diag("unsupported obj reloc %d/%d to %s", r->type, r->siz, r->sym->name);
-		}
-	}
-		
-	sect->rellen = cpos() - sect->reloff;
-}
-
-void
-machoemitreloc(void)
-{
-	Section *sect;
-
-	while(cpos()&7)
-		cput(0);
-
-	machorelocsect(segtext.sect, ctxt->textp);
-	for(sect=segtext.sect->next; sect!=nil; sect=sect->next)
-		machorelocsect(sect, datap);	
-	for(sect=segdata.sect; sect!=nil; sect=sect->next)
-		machorelocsect(sect, datap);	
-}
diff --git a/src/cmd/ld/macho.h b/src/cmd/ld/macho.h
deleted file mode 100644
index d759f4b..0000000
--- a/src/cmd/ld/macho.h
+++ /dev/null
@@ -1,91 +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.
-
-typedef struct MachoHdr MachoHdr;
-struct MachoHdr {
-	uint32	cpu;
-	uint32	subcpu;
-};
-
-typedef struct MachoSect MachoSect;
-struct MachoSect {
-	char*	name;
-	char*	segname;
-	uint64	addr;
-	uint64	size;
-	uint32	off;
-	uint32	align;
-	uint32	reloc;
-	uint32	nreloc;
-	uint32	flag;
-	uint32	res1;
-	uint32	res2;
-};
-
-typedef struct MachoSeg MachoSeg;
-struct MachoSeg {
-	char*	name;
-	uint64	vsize;
-	uint64	vaddr;
-	uint64	fileoffset;
-	uint64	filesize;
-	uint32	prot1;
-	uint32	prot2;
-	uint32	nsect;
-	uint32	msect;
-	MachoSect	*sect;
-	uint32	flag;
-};
-
-typedef struct MachoLoad MachoLoad;
-struct MachoLoad {
-	uint32	type;
-	uint32	ndata;
-	uint32	*data;
-};
-
-MachoHdr*	getMachoHdr(void);
-MachoSeg*	newMachoSeg(char*, int);
-MachoSect*	newMachoSect(MachoSeg*, char*, char*);
-MachoLoad*	newMachoLoad(uint32, uint32);
-int	machowrite(void);
-void	machoinit(void);
-void	machosymorder(void);
-void	machoemitreloc(void);
-int	machoreloc1(Reloc*, vlong);
-
-/*
- * Total amount of space to reserve at the start of the file
- * for Header, PHeaders, and SHeaders.
- * May waste some.
- */
-#define	INITIAL_MACHO_HEADR	4*1024
-
-enum {
-	MACHO_CPU_AMD64 = (1<<24)|7,
-	MACHO_CPU_386 = 7,
-	MACHO_SUBCPU_X86 = 3,
-
-	MACHO32SYMSIZE = 12,
-	MACHO64SYMSIZE = 16,
-	
-	MACHO_X86_64_RELOC_UNSIGNED = 0,
-	MACHO_X86_64_RELOC_SIGNED = 1,
-	MACHO_X86_64_RELOC_BRANCH = 2,
-	MACHO_X86_64_RELOC_GOT_LOAD = 3,
-	MACHO_X86_64_RELOC_GOT = 4,
-	MACHO_X86_64_RELOC_SUBTRACTOR = 5,
-	MACHO_X86_64_RELOC_SIGNED_1 = 6,
-	MACHO_X86_64_RELOC_SIGNED_2 = 7,
-	MACHO_X86_64_RELOC_SIGNED_4 = 8,
-	
-	MACHO_GENERIC_RELOC_VANILLA = 0,
-	
-	MACHO_FAKE_GOTPCREL = 100,
-};
-
-void	domacho(void);
-vlong	domacholink(void);
-void	asmbmacho(void);
-void	machoadddynlib(char*);
diff --git a/src/cmd/ld/pcln.c b/src/cmd/ld/pcln.c
deleted file mode 100644
index 69671c0..0000000
--- a/src/cmd/ld/pcln.c
+++ /dev/null
@@ -1,244 +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.
-
-#include	"l.h"
-#include	"lib.h"
-#include	"../../runtime/funcdata.h"
-
-static void
-addvarint(Pcdata *d, uint32 val)
-{
-	int32 n;
-	uint32 v;
-	uchar *p;
-
-	n = 0;
-	for(v = val; v >= 0x80; v >>= 7)
-		n++;
-	n++;
-
-	if(d->n + n > d->m) {
-		d->m = (d->n + n)*2;
-		d->p = erealloc(d->p, d->m);
-	}
-
-	p = d->p + d->n;
-	for(v = val; v >= 0x80; v >>= 7)
-		*p++ = v | 0x80;
-	*p = v;
-	d->n += n;
-}
-
-static int32
-addpctab(LSym *ftab, int32 off, Pcdata *d)
-{
-	int32 start;
-	
-	start = ftab->np;
-	symgrow(ctxt, ftab, start + d->n);
-	memmove(ftab->p + start, d->p, d->n);
-	
-	return setuint32(ctxt, ftab, off, start);
-}
-
-static int32
-ftabaddstring(LSym *ftab, char *s)
-{
-	int32 n, start;
-	
-	n = strlen(s)+1;
-	start = ftab->np;
-	symgrow(ctxt, ftab, start+n+1);
-	strcpy((char*)ftab->p + start, s);
-	return start;
-}
-
-static void
-renumberfiles(Link *ctxt, LSym **files, int nfiles, Pcdata *d)
-{
-	int i;
-	LSym *f;
-	Pcdata out;
-	Pciter it;
-	uint32 v;
-	int32 oldval, newval, val, dv;
-	
-	// Give files numbers.
-	for(i=0; i<nfiles; i++) {
-		f = files[i];
-		if(f->type != SFILEPATH) {
-			f->value = ++ctxt->nhistfile;
-			f->type = SFILEPATH;
-			f->next = ctxt->filesyms;
-			ctxt->filesyms = f;
-		}
-	}
-
-	newval = -1;
-	memset(&out, 0, sizeof out);
-
-	for(pciterinit(ctxt, &it, d); !it.done; pciternext(&it)) {
-		// value delta
-		oldval = it.value;
-		if(oldval == -1)
-			val = -1;
-		else {	
-			if(oldval < 0 || oldval >= nfiles)
-				sysfatal("bad pcdata %d", oldval);
-			val = files[oldval]->value;
-		}
-		dv = val - newval;
-		newval = val;
-		v = ((uint32)dv<<1) ^ (uint32)(int32)(dv>>31);
-		addvarint(&out, v);
-
-		// pc delta
-		addvarint(&out, (it.nextpc - it.pc) / it.pcscale);
-	}
-	
-	// terminating value delta
-	addvarint(&out, 0);
-
-	free(d->p);
-	*d = out;	
-}
-
-
-// pclntab initializes the pclntab symbol with
-// runtime function and file name information.
-void
-pclntab(void)
-{
-	int32 i, nfunc, start, funcstart;
-	LSym *ftab, *s;
-	int32 off, end, frameptrsize;
-	int64 funcdata_bytes;
-	Pcln *pcln;
-	Pciter it;
-	static Pcln zpcln;
-	
-	funcdata_bytes = 0;
-	ftab = linklookup(ctxt, "runtime.pclntab", 0);
-	ftab->type = SPCLNTAB;
-	ftab->reachable = 1;
-
-	// See golang.org/s/go12symtab for the format. Briefly:
-	//	8-byte header
-	//	nfunc [PtrSize bytes]
-	//	function table, alternating PC and offset to func struct [each entry PtrSize bytes]
-	//	end PC [PtrSize bytes]
-	//	offset to file table [4 bytes]
-	nfunc = 0;
-	for(ctxt->cursym = ctxt->textp; ctxt->cursym != nil; ctxt->cursym = ctxt->cursym->next)
-		nfunc++;
-	symgrow(ctxt, ftab, 8+PtrSize+nfunc*2*PtrSize+PtrSize+4);
-	setuint32(ctxt, ftab, 0, 0xfffffffb);
-	setuint8(ctxt, ftab, 6, MINLC);
-	setuint8(ctxt, ftab, 7, PtrSize);
-	setuintxx(ctxt, ftab, 8, nfunc, PtrSize);
-
-	nfunc = 0;
-	for(ctxt->cursym = ctxt->textp; ctxt->cursym != nil; ctxt->cursym = ctxt->cursym->next, nfunc++) {
-		pcln = ctxt->cursym->pcln;
-		if(pcln == nil)
-			pcln = &zpcln;
-	
-		funcstart = ftab->np;
-		funcstart += -ftab->np & (PtrSize-1);
-
-		setaddr(ctxt, ftab, 8+PtrSize+nfunc*2*PtrSize, ctxt->cursym);
-		setuintxx(ctxt, ftab, 8+PtrSize+nfunc*2*PtrSize+PtrSize, funcstart, PtrSize);
-
-		// fixed size of struct, checked below
-		off = funcstart;
-		end = funcstart + PtrSize + 3*4 + 5*4 + pcln->npcdata*4 + pcln->nfuncdata*PtrSize;
-		if(pcln->nfuncdata > 0 && (end&(PtrSize-1)))
-			end += 4;
-		symgrow(ctxt, ftab, end);
-
-		// entry uintptr
-		off = setaddr(ctxt, ftab, off, ctxt->cursym);
-
-		// name int32
-		off = setuint32(ctxt, ftab, off, ftabaddstring(ftab, ctxt->cursym->name));
-		
-		// args int32
-		// TODO: Move into funcinfo.
-		off = setuint32(ctxt, ftab, off, 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 = PtrSize;
-		if(ctxt->cursym->leaf)
-			frameptrsize = 0;
-		off = setuint32(ctxt, ftab, off, ctxt->cursym->locals + frameptrsize);
-		
-		if(pcln != &zpcln) {
-			renumberfiles(ctxt, pcln->file, pcln->nfile, &pcln->pcfile);
-			if(0) {
-				// Sanity check the new numbering
-				for(pciterinit(ctxt, &it, &pcln->pcfile); !it.done; pciternext(&it)) {
-					if(it.value < 1 || it.value > ctxt->nhistfile) {
-						diag("bad file number in pcfile: %d not in range [1, %d]\n", it.value, ctxt->nhistfile);
-						errorexit();
-					}
-				}
-			}
-		}
-
-		// pcdata
-		off = addpctab(ftab, off, &pcln->pcsp);
-		off = addpctab(ftab, off, &pcln->pcfile);
-		off = addpctab(ftab, off, &pcln->pcline);
-		off = setuint32(ctxt, ftab, off, pcln->npcdata);
-		off = setuint32(ctxt, ftab, off, pcln->nfuncdata);
-		for(i=0; i<pcln->npcdata; i++)
-			off = addpctab(ftab, off, &pcln->pcdata[i]);
-
-		// funcdata, must be pointer-aligned and we're only int32-aligned.
-		// Missing funcdata will be 0 (nil pointer).
-		if(pcln->nfuncdata > 0) {
-			if(off&(PtrSize-1))
-				off += 4;
-			for(i=0; i<pcln->nfuncdata; i++) {
-				if(pcln->funcdata[i] == nil)
-					setuintxx(ctxt, ftab, off+PtrSize*i, pcln->funcdataoff[i], PtrSize);
-				else {
-					// TODO: Dedup.
-					funcdata_bytes += pcln->funcdata[i]->size;
-					setaddrplus(ctxt, ftab, off+PtrSize*i, pcln->funcdata[i], pcln->funcdataoff[i]);
-				}
-			}
-			off += pcln->nfuncdata*PtrSize;
-		}
-
-		if(off != end) {
-			diag("bad math in functab: funcstart=%d off=%d but end=%d (npcdata=%d nfuncdata=%d ptrsize=%d)", funcstart, off, end, pcln->npcdata, pcln->nfuncdata, PtrSize);
-			errorexit();
-		}
-	
-		// Final entry of table is just end pc.
-		if(ctxt->cursym->next == nil)
-			setaddrplus(ctxt, ftab, 8+PtrSize+(nfunc+1)*2*PtrSize, ctxt->cursym, ctxt->cursym->size);
-	}
-	
-	// Start file table.
-	start = ftab->np;
-	start += -ftab->np & (PtrSize-1);
-	setuint32(ctxt, ftab, 8+PtrSize+nfunc*2*PtrSize+PtrSize, start);
-
-	symgrow(ctxt, ftab, start+(ctxt->nhistfile+1)*4);
-	setuint32(ctxt, ftab, start, ctxt->nhistfile);
-	for(s = ctxt->filesyms; s != S; s = s->next)
-		setuint32(ctxt, ftab, start + s->value*4, ftabaddstring(ftab, s->name));
-
-	ftab->size = ftab->np;
-	
-	if(debug['v'])
-		Bprint(&bso, "%5.2f pclntab=%lld bytes, funcdata total %lld bytes\n", cputime(), (vlong)ftab->size, (vlong)funcdata_bytes);
-}	
diff --git a/src/cmd/ld/pe.c b/src/cmd/ld/pe.c
deleted file mode 100644
index c26cd52..0000000
--- a/src/cmd/ld/pe.c
+++ /dev/null
@@ -1,712 +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.
-
-// PE (Portable Executable) file writing
-// http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx
-
-#include "l.h"
-#include "../ld/lib.h"
-#include "../ld/pe.h"
-#include "../ld/dwarf.h"
-
-// DOS stub that prints out
-// "This program cannot be run in DOS mode."
-static char dosstub[] =
-{
-	0x4d, 0x5a, 0x90, 0x00, 0x03, 0x00, 0x04, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
-	0x8b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-	0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
-	0x0e, 0x1f, 0xba, 0x0e, 0x00, 0xb4, 0x09, 0xcd,
-	0x21, 0xb8, 0x01, 0x4c, 0xcd, 0x21, 0x54, 0x68,
-	0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72,
-	0x61, 0x6d, 0x20, 0x63, 0x61, 0x6e, 0x6e, 0x6f,
-	0x74, 0x20, 0x62, 0x65, 0x20, 0x72, 0x75, 0x6e,
-	0x20, 0x69, 0x6e, 0x20, 0x44, 0x4f, 0x53, 0x20,
-	0x6d, 0x6f, 0x64, 0x65, 0x2e, 0x0d, 0x0d, 0x0a,
-	0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-static LSym *rsrcsym;
-
-static char* strtbl;
-static int strtblnextoff;
-static int strtblsize;
-
-int32 PESECTHEADR;
-int32 PEFILEHEADR;
-
-static int pe64;
-static int nsect;
-static int nextsectoff;
-static int nextfileoff;
-static int textsect;
-static int datasect;
-
-static IMAGE_FILE_HEADER fh;
-static IMAGE_OPTIONAL_HEADER oh;
-static PE64_IMAGE_OPTIONAL_HEADER oh64;
-static IMAGE_SECTION_HEADER sh[16];
-static IMAGE_DATA_DIRECTORY* dd;
-
-#define	set(n, v)	(pe64 ? (oh64.n = v) : (oh.n = v))
-#define	put(v)		(pe64 ? vputl(v) : lputl(v))
-
-typedef struct Imp Imp;
-struct Imp {
-	LSym* s;
-	uvlong off;
-	Imp* next;
-};
-
-typedef struct Dll Dll;
-struct Dll {
-	char* name;
-	uvlong nameoff;
-	uvlong thunkoff;
-	Imp* ms;
-	Dll* next;
-};
-
-static Dll* dr;
-
-static LSym *dexport[1024];
-static int nexport;
-
-typedef struct COFFSym COFFSym;
-struct COFFSym
-{
-	LSym* sym;
-	int strtbloff;
-	int sect;
-	vlong value;
-};
-
-static COFFSym* coffsym;
-static int ncoffsym;
-
-static IMAGE_SECTION_HEADER*
-addpesection(char *name, int sectsize, int filesize)
-{
-	IMAGE_SECTION_HEADER *h;
-
-	if(nsect == 16) {
-		diag("too many sections");
-		errorexit();
-	}
-	h = &sh[nsect++];
-	strncpy((char*)h->Name, name, sizeof(h->Name));
-	h->VirtualSize = sectsize;
-	h->VirtualAddress = nextsectoff;
-	nextsectoff = rnd(nextsectoff+sectsize, PESECTALIGN);
-	h->PointerToRawData = nextfileoff;
-	if(filesize > 0) {
-		h->SizeOfRawData = rnd(filesize, PEFILEALIGN);
-		nextfileoff += h->SizeOfRawData;
-	}
-	return h;
-}
-
-static void
-chksectoff(IMAGE_SECTION_HEADER *h, vlong off)
-{
-	if(off != h->PointerToRawData) {
-		diag("%s.PointerToRawData = %#llux, want %#llux", (char *)h->Name, (vlong)h->PointerToRawData, off);
-		errorexit();
-	}
-}
-
-static void
-chksectseg(IMAGE_SECTION_HEADER *h, Segment *s)
-{
-	if(s->vaddr-PEBASE != h->VirtualAddress) {
-		diag("%s.VirtualAddress = %#llux, want %#llux", (char *)h->Name, (vlong)h->VirtualAddress, (vlong)(s->vaddr-PEBASE));
-		errorexit();
-	}
-	if(s->fileoff != h->PointerToRawData) {
-		diag("%s.PointerToRawData = %#llux, want %#llux", (char *)h->Name, (vlong)h->PointerToRawData, (vlong)(s->fileoff));
-		errorexit();
-	}
-}
-
-void
-peinit(void)
-{
-	int32 l;
-
-	switch(thechar) {
-	// 64-bit architectures
-	case '6':
-		pe64 = 1;
-		l = sizeof(oh64);
-		dd = oh64.DataDirectory;
-		break;
-	// 32-bit architectures
-	default:
-		l = sizeof(oh);
-		dd = oh.DataDirectory;
-		break;
-	}
-	
-	PEFILEHEADR = rnd(sizeof(dosstub)+sizeof(fh)+l+sizeof(sh), PEFILEALIGN);
-	PESECTHEADR = rnd(PEFILEHEADR, PESECTALIGN);
-	nextsectoff = PESECTHEADR;
-	nextfileoff = PEFILEHEADR;
-
-	// some mingw libs depend on this symbol, for example, FindPESectionByName
-	xdefine("__image_base__", SDATA, PEBASE);
-	xdefine("_image_base__", SDATA, PEBASE);
-}
-
-static void
-pewrite(void)
-{
-	cseek(0);
-	cwrite(dosstub, sizeof dosstub);
-	strnput("PE", 4);
-	// TODO: This code should not assume that the
-	// memory representation is little-endian or
-	// that the structs are packed identically to
-	// their file representation.
-	cwrite(&fh, sizeof fh);
-	if(pe64)
-		cwrite(&oh64, sizeof oh64);
-	else
-		cwrite(&oh, sizeof oh);
-	cwrite(sh, nsect * sizeof sh[0]);
-}
-
-static void
-strput(char *s)
-{
-	int n;
-
-	for(n=0; *s; n++)
-		cput(*s++);
-	cput('\0');
-	n++;
-	// string must be padded to even size
-	if(n%2)
-		cput('\0');
-}
-
-static Dll* 
-initdynimport(void)
-{
-	Imp *m;
-	Dll *d;
-	LSym *s, *dynamic;
-
-	dr = nil;
-	m = nil;
-	for(s = ctxt->allsym; s != S; s = s->allsym) {
-		if(!s->reachable || s->type != SDYNIMPORT)
-			continue;
-		for(d = dr; d != nil; d = d->next) {
-			if(strcmp(d->name,s->dynimplib) == 0) {
-				m = mal(sizeof *m);
-				break;
-			}
-		}
-		if(d == nil) {
-			d = mal(sizeof *d);
-			d->name = s->dynimplib;
-			d->next = dr;
-			dr = d;
-			m = mal(sizeof *m);
-		}
-		m->s = s;
-		m->next = d->ms;
-		d->ms = m;
-	}
-	
-	dynamic = linklookup(ctxt, ".windynamic", 0);
-	dynamic->reachable = 1;
-	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 += PtrSize;
-		}
-		dynamic->size += PtrSize;
-	}
-		
-	return dr;
-}
-
-static void
-addimports(IMAGE_SECTION_HEADER *datsect)
-{
-	IMAGE_SECTION_HEADER *isect;
-	uvlong n, oftbase, ftbase;
-	vlong startoff, endoff;
-	Imp *m;
-	Dll *d;
-	LSym* dynamic;
-	
-	startoff = cpos();
-	dynamic = linklookup(ctxt, ".windynamic", 0);
-
-	// skip import descriptor table (will write it later)
-	n = 0;
-	for(d = dr; d != nil; d = d->next)
-		n++;
-	cseek(startoff + sizeof(IMAGE_IMPORT_DESCRIPTOR) * (n + 1));
-
-	// write dll names
-	for(d = dr; d != nil; d = d->next) {
-		d->nameoff = cpos() - startoff;
-		strput(d->name);
-	}
-
-	// write function names
-	for(d = dr; d != nil; d = d->next) {
-		for(m = d->ms; m != nil; m = m->next) {
-			m->off = nextsectoff + cpos() - startoff;
-			wputl(0); // hint
-			strput(m->s->extname);
-		}
-	}
-	
-	// write OriginalFirstThunks
-	oftbase = cpos() - startoff;
-	n = cpos();
-	for(d = dr; d != nil; d = d->next) {
-		d->thunkoff = cpos() - n;
-		for(m = d->ms; m != nil; m = m->next)
-			put(m->off);
-		put(0);
-	}
-
-	// add pe section and pad it at the end
-	n = cpos() - startoff;
-	isect = addpesection(".idata", n, n);
-	isect->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA|
-		IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
-	chksectoff(isect, startoff);
-	strnput("", isect->SizeOfRawData - n);
-	endoff = cpos();
-
-	// write FirstThunks (allocated in .data section)
-	ftbase = dynamic->value - datsect->VirtualAddress - PEBASE;
-	cseek(datsect->PointerToRawData + ftbase);
-	for(d = dr; d != nil; d = d->next) {
-		for(m = d->ms; m != nil; m = m->next)
-			put(m->off);
-		put(0);
-	}
-	
-	// finally write import descriptor table
-	cseek(startoff);
-	for(d = dr; d != nil; d = d->next) {
-		lputl(isect->VirtualAddress + oftbase + d->thunkoff);
-		lputl(0);
-		lputl(0);
-		lputl(isect->VirtualAddress + d->nameoff);
-		lputl(datsect->VirtualAddress + ftbase + d->thunkoff);
-	}
-	lputl(0); //end
-	lputl(0);
-	lputl(0);
-	lputl(0);
-	lputl(0);
-	
-	// update data directory
-	dd[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = isect->VirtualAddress;
-	dd[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = isect->VirtualSize;
-	dd[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = dynamic->value - PEBASE;
-	dd[IMAGE_DIRECTORY_ENTRY_IAT].Size = dynamic->size;
-
-	cseek(endoff);
-}
-
-static int
-scmp(const void *p1, const void *p2)
-{
-	LSym *s1, *s2;
-
-	s1 = *(LSym**)p1;
-	s2 = *(LSym**)p2;
-	return strcmp(s1->extname, s2->extname);
-}
-
-static void
-initdynexport(void)
-{
-	LSym *s;
-	
-	nexport = 0;
-	for(s = ctxt->allsym; s != S; s = s->allsym) {
-		if(!s->reachable || !(s->cgoexport & CgoExportDynamic))
-			continue;
-		if(nexport+1 > sizeof(dexport)/sizeof(dexport[0])) {
-			diag("pe dynexport table is full");
-			errorexit();
-		}
-		
-		dexport[nexport] = s;
-		nexport++;
-	}
-	
-	qsort(dexport, nexport, sizeof dexport[0], scmp);
-}
-
-void
-addexports(void)
-{
-	IMAGE_SECTION_HEADER *sect;
-	IMAGE_EXPORT_DIRECTORY e;
-	int size, i, va, va_name, va_addr, va_na, v;
-
-	size = sizeof e + 10*nexport + strlen(outfile) + 1;
-	for(i=0; i<nexport; i++)
-		size += strlen(dexport[i]->extname) + 1;
-	
-	if (nexport == 0)
-		return;
-		
-	sect = addpesection(".edata", size, size);
-	sect->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ;
-	chksectoff(sect, cpos());
-	va = sect->VirtualAddress;
-	dd[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress = va;
-	dd[IMAGE_DIRECTORY_ENTRY_EXPORT].Size = sect->VirtualSize;
-
-	va_name = va + sizeof e + nexport*4;
-	va_addr = va + sizeof e;
-	va_na = va + sizeof e + nexport*8;
-
-	e.Characteristics = 0;
-	e.MajorVersion = 0;
-	e.MinorVersion = 0;
-	e.NumberOfFunctions = nexport;
-	e.NumberOfNames = nexport;
-	e.Name = va + sizeof e + nexport*10; // Program names.
-	e.Base = 1;
-	e.AddressOfFunctions = va_addr;
-	e.AddressOfNames = va_name;
-	e.AddressOfNameOrdinals = va_na;
-	// put IMAGE_EXPORT_DIRECTORY
-	for (i=0; i<sizeof(e); i++)
-		cput(((char*)&e)[i]);
-	// put EXPORT Address Table
-	for(i=0; i<nexport; i++)
-		lputl(dexport[i]->value - PEBASE);		
-	// put EXPORT Name Pointer Table
-	v = e.Name + strlen(outfile)+1;
-	for(i=0; i<nexport; i++) {
-		lputl(v);
-		v += strlen(dexport[i]->extname)+1;
-	}
-	// put EXPORT Ordinal Table
-	for(i=0; i<nexport; i++)
-		wputl(i);
-	// put Names
-	strnput(outfile, strlen(outfile)+1);
-	for(i=0; i<nexport; i++)
-		strnput(dexport[i]->extname, strlen(dexport[i]->extname)+1);
-	strnput("", sect->SizeOfRawData - size);
-}
-
-void
-dope(void)
-{
-	LSym *rel;
-
-	/* relocation table */
-	rel = linklookup(ctxt, ".rel", 0);
-	rel->reachable = 1;
-	rel->type = SELFROSECT;
-
-	initdynimport();
-	initdynexport();
-}
-
-static int
-strtbladd(char *name)
-{
-	int newsize, thisoff;
-
-	newsize = strtblnextoff + strlen(name) + 1;
-	if(newsize > strtblsize) {
-		strtblsize = 2 * (newsize + (1<<18));
-		strtbl = realloc(strtbl, strtblsize);
-	}
-	thisoff = strtblnextoff+4; // first string starts at offset=4
-	strcpy(&strtbl[strtblnextoff], name);
-	strtblnextoff += strlen(name);
-	strtbl[strtblnextoff] = 0;
-	strtblnextoff++;
-	return thisoff;
-}
-
-/*
- * For more than 8 characters section names, name contains a slash (/) that is 
- * followed by an ASCII representation of a decimal number that is an offset into 
- * the string table. 
- * reference: pecoff_v8.docx Page 24.
- * <http://www.microsoft.com/whdc/system/platform/firmware/PECOFFdwn.mspx>
- */
-IMAGE_SECTION_HEADER*
-newPEDWARFSection(char *name, vlong size)
-{
-	IMAGE_SECTION_HEADER *h;
-	char s[8];
-	int off;
-
-	if(size == 0)
-		return nil;
-
-	off = strtbladd(name);
-	sprint(s, "/%d\0", off);
-	h = addpesection(s, size, size);
-	h->Characteristics = IMAGE_SCN_MEM_READ|
-		IMAGE_SCN_MEM_DISCARDABLE;
-
-	return h;
-}
-
-static void
-addsym(LSym *s, char *name, int type, vlong addr, vlong size, int ver, LSym *gotype)
-{
-	COFFSym *cs;
-	USED(name);
-	USED(addr);
-	USED(size);
-	USED(ver);
-	USED(gotype);
-
-	if(s == nil)
-		return;
-
-	if(s->sect == nil)
-		return;
-
-	switch(type) {
-	default:
-		return;
-	case 'D':
-	case 'B':
-	case 'T':
-		break;
-	}
-
-	if(coffsym) {
-		cs = &coffsym[ncoffsym];
-		cs->sym = s;
-		if(strlen(s->name) > 8)
-			cs->strtbloff = strtbladd(s->name);
-		if(s->value >= segdata.vaddr) {
-			cs->value = s->value - segdata.vaddr;
-			cs->sect = datasect;
-		} else if(s->value >= segtext.vaddr) {
-			cs->value = s->value - segtext.vaddr;
-			cs->sect = textsect;
-		} else {
-			cs->value = 0;
-			cs->sect = 0;
-			diag("addsym %#llx", addr);
-		}
-	}
-	ncoffsym++;
-}
-
-static void
-addsymtable(void)
-{
-	IMAGE_SECTION_HEADER *h;
-	int i, size;
-	COFFSym *s;
-
-	if(!debug['s']) {
-		genasmsym(addsym);
-		coffsym = mal(ncoffsym * sizeof coffsym[0]);
-		ncoffsym = 0;
-		genasmsym(addsym);
-	}
-
-	size = strtblnextoff + 4 + 18*ncoffsym;
-	h = addpesection(".symtab", size, size);
-	h->Characteristics = IMAGE_SCN_MEM_READ|
-		IMAGE_SCN_MEM_DISCARDABLE;
-	chksectoff(h, cpos());
-	fh.PointerToSymbolTable = cpos();
-	fh.NumberOfSymbols = ncoffsym;
-	
-	// put COFF symbol table
-	for (i=0; i<ncoffsym; i++) {
-		s = &coffsym[i];
-		if(s->strtbloff == 0)
-			strnput(s->sym->name, 8);
-		else {
-			lputl(0);
-			lputl(s->strtbloff);
-		}
-		lputl(s->value);
-		wputl(s->sect);
-		wputl(0x0308);  // "array of structs"
-		cput(2);        // storage class: external
-		cput(0);        // no aux entries
-	}
-
-	// put COFF string table
-	lputl(strtblnextoff + 4);
-	for (i=0; i<strtblnextoff; i++)
-		cput(strtbl[i]);
-	strnput("", h->SizeOfRawData - size);
-}
-
-void
-setpersrc(LSym *sym)
-{
-	if(rsrcsym != nil)
-		diag("too many .rsrc sections");
-	
-	rsrcsym = sym;
-}
-
-void
-addpersrc(void)
-{
-	IMAGE_SECTION_HEADER *h;
-	uchar *p;
-	uint32 val;
-	Reloc *r;
-
-	if(rsrcsym == nil)
-		return;
-	
-	h = addpesection(".rsrc", rsrcsym->size, rsrcsym->size);
-	h->Characteristics = IMAGE_SCN_MEM_READ|
-		IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_INITIALIZED_DATA;
-	chksectoff(h, cpos());
-	// relocation
-	for(r=rsrcsym->r; r<rsrcsym->r+rsrcsym->nr; r++) {
-		p = rsrcsym->p + r->off;
-		val = h->VirtualAddress + r->add;
-		// 32-bit little-endian
-		p[0] = val;
-		p[1] = val>>8;
-		p[2] = val>>16;
-		p[3] = val>>24;
-	}
-	cwrite(rsrcsym->p, rsrcsym->size);
-	strnput("", h->SizeOfRawData - rsrcsym->size);
-
-	// update data directory
-	dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = h->VirtualAddress;
-	dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = h->VirtualSize;
-}
-
-void
-asmbpe(void)
-{
-	IMAGE_SECTION_HEADER *t, *d;
-
-	switch(thechar) {
-	default:
-		diag("unknown PE architecture");
-		errorexit();
-	case '6':
-		fh.Machine = IMAGE_FILE_MACHINE_AMD64;
-		break;
-	case '8':
-		fh.Machine = IMAGE_FILE_MACHINE_I386;
-		break;
-	}
-
-	t = addpesection(".text", segtext.len, segtext.len);
-	t->Characteristics = IMAGE_SCN_CNT_CODE|
-		IMAGE_SCN_CNT_INITIALIZED_DATA|
-		IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ;
-	chksectseg(t, &segtext);
-	textsect = nsect;
-
-	d = addpesection(".data", segdata.len, segdata.filelen);
-	d->Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA|
-		IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE;
-	chksectseg(d, &segdata);
-	datasect = nsect;
-
-	if(!debug['s'])
-		dwarfaddpeheaders();
-
-	cseek(nextfileoff);
-	addimports(d);
-	addexports();
-	addsymtable();
-	addpersrc();
-
-	fh.NumberOfSections = nsect;
-	fh.TimeDateStamp = time(0);
-	fh.Characteristics = IMAGE_FILE_RELOCS_STRIPPED|
-		IMAGE_FILE_EXECUTABLE_IMAGE|IMAGE_FILE_DEBUG_STRIPPED;
-	if (pe64) {
-		fh.SizeOfOptionalHeader = sizeof(oh64);
-		fh.Characteristics |= IMAGE_FILE_LARGE_ADDRESS_AWARE;
-		set(Magic, 0x20b);	// PE32+
-	} else {
-		fh.SizeOfOptionalHeader = sizeof(oh);
-		fh.Characteristics |= IMAGE_FILE_32BIT_MACHINE;
-		set(Magic, 0x10b);	// PE32
-		oh.BaseOfData = d->VirtualAddress;
-	}
-	set(MajorLinkerVersion, 3);
-	set(MinorLinkerVersion, 0);
-	set(SizeOfCode, t->SizeOfRawData);
-	set(SizeOfInitializedData, d->SizeOfRawData);
-	set(SizeOfUninitializedData, 0);
-	set(AddressOfEntryPoint, entryvalue()-PEBASE);
-	set(BaseOfCode, t->VirtualAddress);
-	set(ImageBase, PEBASE);
-	set(SectionAlignment, PESECTALIGN);
-	set(FileAlignment, PEFILEALIGN);
-	set(MajorOperatingSystemVersion, 4);
-	set(MinorOperatingSystemVersion, 0);
-	set(MajorImageVersion, 1);
-	set(MinorImageVersion, 0);
-	set(MajorSubsystemVersion, 4);
-	set(MinorSubsystemVersion, 0);
-	set(SizeOfImage, nextsectoff);
-	set(SizeOfHeaders, PEFILEHEADR);
-	if(strcmp(headstring, "windowsgui") == 0)
-		set(Subsystem, IMAGE_SUBSYSTEM_WINDOWS_GUI);
-	else
-		set(Subsystem, IMAGE_SUBSYSTEM_WINDOWS_CUI);
-
-	// Disable stack growth as we don't want Windows to
-	// fiddle with the thread stack limits, which we set
-	// ourselves to circumvent the stack checks in the
-	// Windows exception dispatcher.
-	// Commit size must be strictly less than reserve
-	// size otherwise reserve will be rounded up to a
-	// larger size, as verified with VMMap.
-
-	// Go code would be OK with 64k stacks, but we need larger stacks for cgo.
-	// That default stack reserve size affects only the main thread,
-	// for other threads we specify stack size in runtime explicitly
-	// (runtime knows whether cgo is enabled or not).
-	// If you change stack reserve sizes here,
-	// change STACKSIZE in runtime/cgo/gcc_windows_{386,amd64}.c as well.
-	if(!iscgo) {
-		set(SizeOfStackReserve, 0x00010000);
-		set(SizeOfStackCommit, 0x0000ffff);
-	} else {
-		set(SizeOfStackReserve, pe64 ? 0x00200000 : 0x00100000);
-		// account for 2 guard pages
-		set(SizeOfStackCommit, (pe64 ? 0x00200000 : 0x00100000) - 0x2000);
-	}
-	set(SizeOfHeapReserve, 0x00100000);
-	set(SizeOfHeapCommit, 0x00001000);
-	set(NumberOfRvaAndSizes, 16);
-
-	pewrite();
-}
diff --git a/src/cmd/ld/pe.h b/src/cmd/ld/pe.h
deleted file mode 100644
index 03ed8d8..0000000
--- a/src/cmd/ld/pe.h
+++ /dev/null
@@ -1,179 +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.
-
-typedef struct {
-	uint16 Machine;
-	uint16 NumberOfSections;
-	uint32 TimeDateStamp;
-	uint32 PointerToSymbolTable;
-	uint32 NumberOfSymbols;
-	uint16 SizeOfOptionalHeader;
-	uint16 Characteristics;
-} IMAGE_FILE_HEADER;
-
-typedef struct {
-	uint32 VirtualAddress;
-	uint32 Size;
-} IMAGE_DATA_DIRECTORY;
-
-typedef struct {
-	uint16 Magic;
-	uint8  MajorLinkerVersion;
-	uint8  MinorLinkerVersion;
-	uint32 SizeOfCode;
-	uint32 SizeOfInitializedData;
-	uint32 SizeOfUninitializedData;
-	uint32 AddressOfEntryPoint;
-	uint32 BaseOfCode;
-	uint32 BaseOfData;
-	uint32 ImageBase;
-	uint32 SectionAlignment;
-	uint32 FileAlignment;
-	uint16 MajorOperatingSystemVersion;
-	uint16 MinorOperatingSystemVersion;
-	uint16 MajorImageVersion;
-	uint16 MinorImageVersion;
-	uint16 MajorSubsystemVersion;
-	uint16 MinorSubsystemVersion;
-	uint32 Win32VersionValue;
-	uint32 SizeOfImage;
-	uint32 SizeOfHeaders;
-	uint32 CheckSum;
-	uint16 Subsystem;
-	uint16 DllCharacteristics;
-	uint32 SizeOfStackReserve;
-	uint32 SizeOfStackCommit;
-	uint32 SizeOfHeapReserve;
-	uint32 SizeOfHeapCommit;
-	uint32 LoaderFlags;
-	uint32 NumberOfRvaAndSizes;
-	IMAGE_DATA_DIRECTORY DataDirectory[16];
-} IMAGE_OPTIONAL_HEADER;
-
-typedef struct {
-	uint8  Name[8];
-	uint32 VirtualSize;
-	uint32 VirtualAddress;
-	uint32 SizeOfRawData;
-	uint32 PointerToRawData;
-	uint32 PointerToRelocations;
-	uint32 PointerToLineNumbers;
-	uint16 NumberOfRelocations;
-	uint16 NumberOfLineNumbers;
-	uint32 Characteristics;
-} IMAGE_SECTION_HEADER;
-
-typedef struct {
-	uint32 OriginalFirstThunk;
-	uint32 TimeDateStamp;
-	uint32 ForwarderChain;
-	uint32 Name;
-	uint32 FirstThunk;
-} IMAGE_IMPORT_DESCRIPTOR;
-
-typedef struct _IMAGE_EXPORT_DIRECTORY {
-	uint32 Characteristics;
-	uint32 TimeDateStamp;
-	uint16 MajorVersion;
-	uint16 MinorVersion;
-	uint32 Name;
-	uint32 Base;
-	uint32 NumberOfFunctions;
-	uint32 NumberOfNames;
-	uint32 AddressOfFunctions;
-	uint32 AddressOfNames;
-	uint32 AddressOfNameOrdinals;
-} IMAGE_EXPORT_DIRECTORY;
-
-#define PEBASE		0x00400000
-// SectionAlignment must be greater than or equal to FileAlignment.
-// The default is the page size for the architecture.
-#define 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.
-#define PEFILEALIGN	(2<<8)
-extern	int32	PESECTHEADR;
-extern	int32	PEFILEHEADR;
-
-enum {
-	IMAGE_FILE_MACHINE_I386 = 0x14c,
-	IMAGE_FILE_MACHINE_AMD64 = 0x8664,
-
-	IMAGE_FILE_RELOCS_STRIPPED = 0x0001,
-	IMAGE_FILE_EXECUTABLE_IMAGE = 0x0002,
-	IMAGE_FILE_LARGE_ADDRESS_AWARE = 0x0020,
-	IMAGE_FILE_32BIT_MACHINE = 0x0100,
-	IMAGE_FILE_DEBUG_STRIPPED = 0x0200,
-
-	IMAGE_SCN_CNT_CODE = 0x00000020,
-	IMAGE_SCN_CNT_INITIALIZED_DATA = 0x00000040,
-	IMAGE_SCN_CNT_UNINITIALIZED_DATA = 0x00000080,
-	IMAGE_SCN_MEM_EXECUTE = 0x20000000,
-	IMAGE_SCN_MEM_READ = 0x40000000,
-	IMAGE_SCN_MEM_WRITE = 0x80000000,
-	IMAGE_SCN_MEM_DISCARDABLE = 0x2000000,
-
-	IMAGE_DIRECTORY_ENTRY_EXPORT = 0,
-	IMAGE_DIRECTORY_ENTRY_IMPORT = 1,
-	IMAGE_DIRECTORY_ENTRY_RESOURCE = 2,
-	IMAGE_DIRECTORY_ENTRY_EXCEPTION = 3,
-	IMAGE_DIRECTORY_ENTRY_SECURITY = 4,
-	IMAGE_DIRECTORY_ENTRY_BASERELOC = 5,
-	IMAGE_DIRECTORY_ENTRY_DEBUG = 6,
-	IMAGE_DIRECTORY_ENTRY_COPYRIGHT = 7,
-	IMAGE_DIRECTORY_ENTRY_ARCHITECTURE = 7,
-	IMAGE_DIRECTORY_ENTRY_GLOBALPTR = 8,
-	IMAGE_DIRECTORY_ENTRY_TLS = 9,
-	IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG = 10,
-	IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT = 11,
-	IMAGE_DIRECTORY_ENTRY_IAT = 12,
-	IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT = 13,
-	IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR = 14,
-
-	IMAGE_SUBSYSTEM_WINDOWS_GUI = 2,
-	IMAGE_SUBSYSTEM_WINDOWS_CUI = 3,
-};
-
-void peinit(void);
-void asmbpe(void);
-void dope(void);
-
-IMAGE_SECTION_HEADER* newPEDWARFSection(char *name, vlong size);
-
-// X64
-typedef struct {
-	uint16 Magic;
-	uint8  MajorLinkerVersion;
-	uint8  MinorLinkerVersion;
-	uint32 SizeOfCode;
-	uint32 SizeOfInitializedData;
-	uint32 SizeOfUninitializedData;
-	uint32 AddressOfEntryPoint;
-	uint32 BaseOfCode;
-	uint64 ImageBase;
-	uint32 SectionAlignment;
-	uint32 FileAlignment;
-	uint16 MajorOperatingSystemVersion;
-	uint16 MinorOperatingSystemVersion;
-	uint16 MajorImageVersion;
-	uint16 MinorImageVersion;
-	uint16 MajorSubsystemVersion;
-	uint16 MinorSubsystemVersion;
-	uint32 Win32VersionValue;
-	uint32 SizeOfImage;
-	uint32 SizeOfHeaders;
-	uint32 CheckSum;
-	uint16 Subsystem;
-	uint16 DllCharacteristics;
-	uint64 SizeOfStackReserve;
-	uint64 SizeOfStackCommit;
-	uint64 SizeOfHeapReserve;
-	uint64 SizeOfHeapCommit;
-	uint32 LoaderFlags;
-	uint32 NumberOfRvaAndSizes;
-	IMAGE_DATA_DIRECTORY DataDirectory[16];
-} PE64_IMAGE_OPTIONAL_HEADER;
-
-void setpersrc(LSym *sym);
diff --git a/src/cmd/ld/pobj.c b/src/cmd/ld/pobj.c
deleted file mode 100644
index 63460df..0000000
--- a/src/cmd/ld/pobj.c
+++ /dev/null
@@ -1,207 +0,0 @@
-// Inferno utils/6l/obj.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-// Reading object files.
-
-#define	EXTERN
-#include	"l.h"
-#include	"../ld/lib.h"
-#include	"../ld/elf.h"
-#include	"../ld/macho.h"
-#include	"../ld/dwarf.h"
-#include	"../ld/pe.h"
-#include	<ar.h>
-
-char	*noname		= "<none>";
-char*	paramspace	= "FP";
-
-void
-main(int argc, char *argv[])
-{
-	int i;
-
-	linkarchinit();
-	ctxt = linknew(thelinkarch);
-	ctxt->thechar = thechar;
-	ctxt->thestring = thestring;
-	ctxt->diag = diag;
-	ctxt->bso = &bso;
-
-	Binit(&bso, 1, OWRITE);
-	listinit();
-	memset(debug, 0, sizeof(debug));
-	nerrors = 0;
-	outfile = nil;
-	HEADTYPE = -1;
-	INITTEXT = -1;
-	INITDAT = -1;
-	INITRND = -1;
-	INITENTRY = 0;
-	linkmode = LinkAuto;
-	
-	// For testing behavior of go command when tools crash.
-	// Undocumented, not in standard flag parser to avoid
-	// exposing in usage message.
-	for(i=1; i<argc; i++)
-		if(strcmp(argv[i], "-crash_for_testing") == 0)
-			*(volatile int*)0 = 0;
-	
-	if(thechar == '5' && ctxt->goarm == 5)
-		debug['F'] = 1;
-
-	flagcount("1", "use alternate profiling code", &debug['1']);
-	if(thechar == '6')
-		flagcount("8", "assume 64-bit addresses", &debug['8']);
-	flagfn1("B", "info: define ELF NT_GNU_BUILD_ID note", addbuildinfo);
-	flagcount("C", "check Go calls to C code", &debug['C']);
-	flagint64("D", "addr: data address", &INITDAT);
-	flagstr("E", "sym: entry symbol", &INITENTRY);
-	if(thechar == '5')
-		flagcount("G", "debug pseudo-ops", &debug['G']);
-	flagfn1("I", "interp: set ELF interp", setinterp);
-	flagfn1("L", "dir: add dir to library path", Lflag);
-	flagfn1("H", "head: header type", setheadtype);
-	flagcount("K", "add stack underflow checks", &debug['K']);
-	if(thechar == '5')
-		flagcount("M", "disable software div/mod", &debug['M']);
-	flagcount("O", "print pc-line tables", &debug['O']);
-	flagcount("Q", "debug byte-register code gen", &debug['Q']);
-	if(thechar == '5')
-		flagcount("P", "debug code generation", &debug['P']);
-	flagint32("R", "rnd: address rounding", &INITRND);
-	flagcount("S", "check type signatures", &debug['S']);
-	flagint64("T", "addr: text address", &INITTEXT);
-	flagfn0("V", "print version and exit", doversion);
-	flagcount("W", "disassemble input", &debug['W']);
-	flagfn2("X", "name value: define string data", addstrdata);
-	flagcount("Z", "clear stack frame on entry", &debug['Z']);
-	flagcount("a", "disassemble output", &debug['a']);
-	flagcount("c", "dump call graph", &debug['c']);
-	flagcount("d", "disable dynamic executable", &debug['d']);
-	flagstr("extld", "ld: linker to run in external mode", &extld);
-	flagstr("extldflags", "ldflags: flags for external linker", &extldflags);
-	flagcount("f", "ignore version mismatch", &debug['f']);
-	flagcount("g", "disable go package data checks", &debug['g']);
-	flagstr("installsuffix", "suffix: pkg directory suffix", &flag_installsuffix);
-	flagstr("k", "sym: set field tracking symbol", &tracksym);
-	flagfn1("linkmode", "mode: set link mode (internal, external, auto)", setlinkmode);
-	flagcount("n", "dump symbol table", &debug['n']);
-	flagstr("o", "outfile: set output file", &outfile);
-	flagstr("r", "dir1:dir2:...: set ELF dynamic linker search path", &rpath);
-	flagcount("race", "enable race detector", &flag_race);
-	flagcount("s", "disable symbol table", &debug['s']);
-	if(thechar == '5' || thechar == '6')
-		flagcount("shared", "generate shared object (implies -linkmode external)", &flag_shared);
-	flagstr("tmpdir", "dir: leave temporary files in this directory", &tmpdir);
-	flagcount("u", "reject unsafe packages", &debug['u']);
-	flagcount("v", "print link trace", &debug['v']);
-	flagcount("w", "disable DWARF generation", &debug['w']);
-	
-	flagparse(&argc, &argv, usage);
-	ctxt->bso = &bso;
-	ctxt->debugdivmod = debug['M'];
-	ctxt->debugfloat = debug['F'];
-	ctxt->debughist = debug['O'];
-	ctxt->debugpcln = debug['O'];
-	ctxt->debugread = debug['W'];
-	ctxt->debugstack = debug['K'];
-	ctxt->debugvlog = debug['v'];
-
-	if(argc != 1)
-		usage();
-
-	if(outfile == nil) {
-		if(HEADTYPE == Hwindows)
-			outfile = smprint("%c.out.exe", thechar);
-		else
-			outfile = smprint("%c.out", thechar);
-	}
-	libinit(); // creates outfile
-
-	if(HEADTYPE == -1)
-		HEADTYPE = headtype(goos);
-	ctxt->headtype = HEADTYPE;
-	if(headstring == nil)
-		headstring = headstr(HEADTYPE);
-
-	archinit();
-	ctxt->debugfloat = debug['F'];
-
-	if(debug['v'])
-		Bprint(&bso, "HEADER = -H%d -T0x%llux -D0x%llux -R0x%ux\n",
-			HEADTYPE, INITTEXT, INITDAT, INITRND);
-	Bflush(&bso);
-
-	cbp = buf.cbuf;
-	cbc = sizeof(buf.cbuf);
-
-	addlibpath(ctxt, "command line", "command line", argv[0], "main");
-	loadlib();
-	
-	if(thechar == '5') {
-		// mark some functions that are only referenced after linker code editing
-		if(debug['F'])
-			mark(linkrlookup(ctxt, "_sfloat", 0));
-		mark(linklookup(ctxt, "runtime.read_tls_fallback", 0));
-	}
-
-	checkgo();
-	deadcode();
-	callgraph();
-	paramspace = "SP";	/* (FP) now (SP) on output */
-
-	doelf();
-	if(HEADTYPE == Hdarwin)
-		domacho();
-	dostkcheck();
-	if(HEADTYPE == Hwindows)
-		dope();
-	addexport();
-	textaddress();
-	pclntab();
-	symtab();
-	dodata();
-	address();
-	doweak();
-	reloc();
-	asmb();
-	undef();
-	hostlink();
-	if(debug['v']) {
-		Bprint(&bso, "%5.2f cpu time\n", cputime());
-		Bprint(&bso, "%d symbols\n", ctxt->nsymbol);
-		Bprint(&bso, "%d sizeof adr\n", sizeof(Addr));
-		Bprint(&bso, "%d sizeof prog\n", sizeof(Prog));
-		Bprint(&bso, "%lld liveness data\n", liveness);
-	}
-	Bflush(&bso);
-
-	errorexit();
-}
diff --git a/src/cmd/ld/symtab.c b/src/cmd/ld/symtab.c
deleted file mode 100644
index 156270c..0000000
--- a/src/cmd/ld/symtab.c
+++ /dev/null
@@ -1,441 +0,0 @@
-// Inferno utils/6l/span.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-// Symbol table.
-
-#include	"l.h"
-#include	"../ld/lib.h"
-#include	"../ld/elf.h"
-
-static int maxelfstr;
-
-static int
-putelfstr(char *s)
-{
-	int off, n;
-	char *p, *q;
-
-	if(elfstrsize == 0 && s[0] != 0) {
-		// first entry must be empty string
-		putelfstr("");
-	}
-
-	n = strlen(s)+1;
-	if(elfstrsize+n > maxelfstr) {
-		maxelfstr = 2*(elfstrsize+n+(1<<20));
-		elfstrdat = realloc(elfstrdat, maxelfstr);
-	}
-	off = elfstrsize;
-	elfstrsize += n;
-	memmove(elfstrdat+off, s, n);
-	// replace "·" as ".", because DTrace cannot handle it.
-	p = strstr(s, "·");
-	if(p != nil) {
-		p = q = elfstrdat+off;
-		while (*q != '\0') {
-			if((uchar)*q == 0xc2 && (uchar)*(q+1) == 0xb7) {
-				q += 2;
-				*p++ = '.';
-				elfstrsize--;
-			} else {
-				*p++ = *q++;
-			}
-		}
-		*p = '\0';
-	}
-	return off;
-}
-
-static void
-putelfsyment(int off, vlong addr, vlong size, int info, int shndx, int other)
-{
-	switch(thechar) {
-	case '6':
-		LPUT(off);
-		cput(info);
-		cput(other);
-		WPUT(shndx);
-		VPUT(addr);
-		VPUT(size);
-		symsize += ELF64SYMSIZE;
-		break;
-	default:
-		LPUT(off);
-		LPUT(addr);
-		LPUT(size);
-		cput(info);
-		cput(other);
-		WPUT(shndx);
-		symsize += ELF32SYMSIZE;
-		break;
-	}
-}
-
-static int numelfsym = 1; // 0 is reserved
-static int elfbind;
-
-static void
-putelfsym(LSym *x, char *s, int t, vlong addr, vlong size, int ver, LSym *go)
-{
-	int bind, type, off;
-	LSym *xo;
-
-	USED(go);
-	switch(t) {
-	default:
-		return;
-	case 'T':
-		type = STT_FUNC;
-		break;
-	case 'D':
-		type = STT_OBJECT;
-		break;
-	case 'B':
-		type = STT_OBJECT;
-		break;
-	}
-	xo = x;
-	while(xo->outer != nil)
-		xo = xo->outer;
-	if(xo->sect == nil) {
-		ctxt->cursym = x;
-		diag("missing section in putelfsym");
-		return;
-	}
-	if(xo->sect->elfsect == nil) {
-		ctxt->cursym = x;
-		diag("missing ELF section in putelfsym");
-		return;
-	}
-
-	// One pass for each binding: STB_LOCAL, STB_GLOBAL,
-	// maybe one day STB_WEAK.
-	bind = STB_GLOBAL;
-	if(ver || (x->type & SHIDDEN))
-		bind = STB_LOCAL;
-
-	// In external linking mode, we have to invoke gcc with -rdynamic
-	// 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))
-		bind = STB_LOCAL;
-
-	if(bind != elfbind)
-		return;
-
-	off = putelfstr(s);
-	if(linkmode == LinkExternal)
-		addr -= xo->sect->vaddr;
-	putelfsyment(off, addr, size, (bind<<4)|(type&0xf), xo->sect->elfsect->shnum, (x->type & SHIDDEN) ? 2 : 0);
-	x->elfsym = numelfsym++;
-}
-
-void
-putelfsectionsym(LSym* s, int shndx)
-{
-	putelfsyment(0, 0, 0, (STB_LOCAL<<4)|STT_SECTION, shndx, 0);
-	s->elfsym = numelfsym++;
-}
-
-void
-putelfsymshndx(vlong sympos, int shndx)
-{
-	vlong here;
-
-	here = cpos();
-	switch(thechar) {
-	case '6':
-		cseek(sympos+6);
-		break;
-	default:
-		cseek(sympos+14);
-		break;
-	}
-	WPUT(shndx);
-	cseek(here);
-}
-
-void
-asmelfsym(void)
-{
-	LSym *s;
-	char *name;
-
-	// the first symbol entry is reserved
-	putelfsyment(0, 0, 0, (STB_LOCAL<<4)|STT_NOTYPE, 0, 0);
-
-	dwarfaddelfsectionsyms();
-
-	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 (strcmp(goos, "android") == 0) {
-			// Android emulates runtime.tlsg as a regular variable.
-			putelfsyment(putelfstr(s->name), 0, s->size, (STB_LOCAL<<4)|STT_OBJECT, s->sect->elfsect->shnum, 0);
-		} else {
-			putelfsyment(putelfstr(s->name), 0, s->size, (STB_LOCAL<<4)|STT_TLS, s->sect->elfsect->shnum, 0);
-		}
-		s->elfsym = numelfsym++;
-	}
-
-	elfbind = STB_GLOBAL;
-	elfglobalsymndx = numelfsym;
-	genasmsym(putelfsym);
-	
-	for(s=ctxt->allsym; s!=S; 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 = numelfsym++;
-	}
-}
-
-static void
-putplan9sym(LSym *x, char *s, int t, vlong addr, vlong size, int ver, LSym *go)
-{
-	int i, l;
-
-	USED(go);
-	USED(ver);
-	USED(size);
-	USED(x);
-	switch(t) {
-	case 'T':
-	case 'L':
-	case 'D':
-	case 'B':
-		if(ver)
-			t += 'a' - 'A';
-	case 'a':
-	case 'p':
-	case 'f':
-	case 'z':
-	case 'Z':
-	case 'm':
-		l = 4;
-		if(HEADTYPE == Hplan9 && thechar == '6' && !debug['8']) {
-			lputb(addr>>32);
-			l = 8;
-		}
-		lputb(addr);
-		cput(t+0x80); /* 0x80 is variable length */
-
-		if(t == 'z' || t == 'Z') {
-			cput(s[0]);
-			for(i=1; s[i] != 0 || s[i+1] != 0; i += 2) {
-				cput(s[i]);
-				cput(s[i+1]);
-			}
-			cput(0);
-			cput(0);
-			i++;
-		} else {
-			/* skip the '<' in filenames */
-			if(t == 'f')
-				s++;
-			for(i=0; s[i]; i++)
-				cput(s[i]);
-			cput(0);
-		}
-		symsize += l + 1 + i + 1;
-		break;
-	default:
-		return;
-	};
-}
-
-void
-asmplan9sym(void)
-{
-	genasmsym(putplan9sym);
-}
-
-static LSym *symt;
-
-void
-wputl(ushort w)
-{
-	cput(w);
-	cput(w>>8);
-}
-
-void
-wputb(ushort w)
-{
-	cput(w>>8);
-	cput(w);
-}
-
-void
-lputb(int32 l)
-{
-	cput(l>>24);
-	cput(l>>16);
-	cput(l>>8);
-	cput(l);
-}
-
-void
-lputl(int32 l)
-{
-	cput(l);
-	cput(l>>8);
-	cput(l>>16);
-	cput(l>>24);
-}
-
-void
-vputb(uint64 v)
-{
-	lputb(v>>32);
-	lputb(v);
-}
-
-void
-vputl(uint64 v)
-{
-	lputl(v);
-	lputl(v >> 32);
-}
-
-void
-symtab(void)
-{
-	LSym *s, *symtype, *symtypelink, *symgostring, *symgofunc;
-
-	dosymtype();
-
-	// Define these so that they'll get put into the symbol table.
-	// data.c:/^address will provide the actual values.
-	xdefine("runtime.text", STEXT, 0);
-	xdefine("runtime.etext", STEXT, 0);
-	xdefine("runtime.typelink", SRODATA, 0);
-	xdefine("runtime.etypelink", SRODATA, 0);
-	xdefine("runtime.rodata", SRODATA, 0);
-	xdefine("runtime.erodata", SRODATA, 0);
-	xdefine("runtime.noptrdata", SNOPTRDATA, 0);
-	xdefine("runtime.enoptrdata", SNOPTRDATA, 0);
-	xdefine("runtime.data", SDATA, 0);
-	xdefine("runtime.edata", SDATA, 0);
-	xdefine("runtime.bss", SBSS, 0);
-	xdefine("runtime.ebss", SBSS, 0);
-	xdefine("runtime.noptrbss", SNOPTRBSS, 0);
-	xdefine("runtime.enoptrbss", SNOPTRBSS, 0);
-	xdefine("runtime.end", SBSS, 0);
-	xdefine("runtime.epclntab", SRODATA, 0);
-	xdefine("runtime.esymtab", SRODATA, 0);
-
-	// garbage collection symbols
-	s = linklookup(ctxt, "runtime.gcdata", 0);
-	s->type = SRODATA;
-	s->size = 0;
-	s->reachable = 1;
-	xdefine("runtime.egcdata", SRODATA, 0);
-
-	s = linklookup(ctxt, "runtime.gcbss", 0);
-	s->type = SRODATA;
-	s->size = 0;
-	s->reachable = 1;
-	xdefine("runtime.egcbss", SRODATA, 0);
-
-	// pseudo-symbols to mark locations of type, string, and go string data.
-	s = linklookup(ctxt, "type.*", 0);
-	s->type = STYPE;
-	s->size = 0;
-	s->reachable = 1;
-	symtype = s;
-
-	s = linklookup(ctxt, "go.string.*", 0);
-	s->type = SGOSTRING;
-	s->size = 0;
-	s->reachable = 1;
-	symgostring = s;
-	
-	s = linklookup(ctxt, "go.func.*", 0);
-	s->type = SGOFUNC;
-	s->size = 0;
-	s->reachable = 1;
-	symgofunc = s;
-	
-	symtypelink = linklookup(ctxt, "runtime.typelink", 0);
-
-	symt = linklookup(ctxt, "runtime.symtab", 0);
-	symt->type = SSYMTAB;
-	symt->size = 0;
-	symt->reachable = 1;
-
-	// assign specific types so that they sort together.
-	// 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 != S; s = s->allsym) {
-		if(!s->reachable || s->special || s->type != SRODATA)
-			continue;
-		if(strncmp(s->name, "type.", 5) == 0) {
-			s->type = STYPE;
-			s->hide = 1;
-			s->outer = symtype;
-		}
-		if(strncmp(s->name, "go.typelink.", 12) == 0) {
-			s->type = STYPELINK;
-			s->hide = 1;
-			s->outer = symtypelink;
-		}
-		if(strncmp(s->name, "go.string.", 10) == 0) {
-			s->type = SGOSTRING;
-			s->hide = 1;
-			s->outer = symgostring;
-		}
-		if(strncmp(s->name, "go.func.", 8) == 0) {
-			s->type = SGOFUNC;
-			s->hide = 1;
-			s->outer = symgofunc;
-		}
-		if(strncmp(s->name, "gcargs.", 7) == 0 || strncmp(s->name, "gclocals.", 9) == 0 || strncmp(s->name, "gclocals·", 10) == 0) {
-			s->type = SGOFUNC;
-			s->hide = 1;
-			s->outer = symgofunc;
-			s->align = 4;
-			liveness += (s->size+s->align-1)&~(s->align-1);
-		}
-	}
-}
diff --git a/src/cmd/ld/textflag.h b/src/cmd/ld/textflag.h
deleted file mode 100644
index 0ee8b5f..0000000
--- a/src/cmd/ld/textflag.h
+++ /dev/null
@@ -1,36 +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.
-
-// This file defines flags attached to various functions
-// and data objects.  The compilers, assemblers, and linker must
-// all agree on these values.
-
-// Don't profile the marked routine.  This flag is deprecated.
-#define NOPROF	1
-// It is ok for the linker to get multiple of these symbols.  It will
-// pick one of the duplicates to use.
-#define DUPOK	2
-// Don't insert stack check preamble.
-#define NOSPLIT	4
-// Put this data in a read-only section.
-#define RODATA	8
-// This data contains no pointers.
-#define NOPTR	16
-// This is a wrapper function and should not count as disabling 'recover'.
-#define WRAPPER 32
-// This function uses its incoming context register.
-#define NEEDCTXT 64
-
-/*c2go
-enum
-{
-	NOPROF = 1,
-	DUPOK = 2,
-	NOSPLIT = 4,
-	RODATA = 8,
-	NOPTR = 16,
-	WRAPPER = 32,
-	NEEDCTXT = 64,
-};
-*/
diff --git a/src/cmd/link/doc.go b/src/cmd/link/doc.go
new file mode 100644
index 0000000..479988e
--- /dev/null
+++ b/src/cmd/link/doc.go
@@ -0,0 +1,93 @@
+// 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.
+
+/*
+Link, typically invoked as ``go tool link,'' reads the Go archive or object
+for a package main, along with its dependencies, and combines them
+into an executable binary.
+
+Command Line
+
+Usage:
+
+	go tool link [flags] main.a
+
+Flags:
+
+	-B note
+		Add an ELF_NT_GNU_BUILD_ID note when using ELF.
+		The value should start with 0x and be an even number of hex digits.
+	-D address
+		Set data segment address.
+	-E entry
+		Set entry symbol name.
+	-H type
+		Set executable format type.
+		The default format is inferred from GOOS and GOARCH.
+		On Windows, -H windowsgui writes a "GUI binary" instead of a "console binary."
+	-I interpreter
+		Set the ELF dynamic linker to use.
+	-L dir1 -L dir2
+		Search for imported packages in dir1, dir2, etc,
+		after consulting $GOROOT/pkg/$GOOS_$GOARCH.
+	-R quantum
+		Set address rounding quantum.
+	-T address
+		Set text segment address.
+	-V
+		Print the linker version and exit.
+	-X importpath.name=value
+		Set the value of the string variable in importpath named name to value.
+		Note that before Go 1.5 this option took two separate arguments.
+		Now it takes one argument split on the first = sign.
+	-buildmode mode
+		Set build mode (default exe).
+	-cpuprofile file
+		Write CPU profile to file.
+	-d
+		Disable generation of dynamic executables.
+		The emitted code is the same in either case; the option
+		controls only whether a dynamic header is included.
+		The dynamic header is on by default, even without any
+		references to dynamic libraries, because many common
+		system tools now assume the presence of the header.
+	-extld linker
+		Set the external linker (default "clang" or "gcc").
+	-extldflags flags
+		Set space-separated flags to pass to the external linker.
+	-f
+		Ignore version mismatch in the linked archives.
+	-g
+		Disable Go package data checks.
+	-installsuffix suffix
+		Look for packages in $GOROOT/pkg/$GOOS_$GOARCH_suffix
+		instead of $GOROOT/pkg/$GOOS_$GOARCH.
+	-linkmode mode
+		Set link mode (internal, external, auto).
+		This sets the linking mode as described in cmd/cgo/doc.go.
+	-linkshared
+		Link against installed Go shared libraries (experimental).
+	-memprofile file
+		Write memory profile to file.
+	-memprofilerate rate
+		Set runtime.MemProfileRate to rate.
+	-o file
+		Write output to file (default a.out, or a.out.exe on Windows).
+	-r dir1:dir2:...
+		Set the ELF dynamic linker search path.
+	-race
+		Link with race detection libraries.
+	-s
+		Omit the symbol table and debug information.
+	-shared
+		Generated shared object (implies -linkmode external; experimental).
+	-tmpdir dir
+		Write temporary files to dir.
+		Temporary files are only used in external linking mode.
+	-v
+		Print trace of linker operations.
+	-w
+		Omit the DWARF symbol table.
+*/
+package main
diff --git a/src/cmd/link/internal/amd64/asm.go b/src/cmd/link/internal/amd64/asm.go
new file mode 100644
index 0000000..74ec9dd
--- /dev/null
+++ b/src/cmd/link/internal/amd64/asm.go
@@ -0,0 +1,817 @@
+// 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 at 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 at 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 amd64
+
+import (
+	"cmd/internal/obj"
+	"cmd/link/internal/ld"
+	"debug/elf"
+	"fmt"
+	"log"
+)
+
+func PADDR(x uint32) uint32 {
+	return x &^ 0x80000000
+}
+
+var zeroes string
+
+func Addcall(ctxt *ld.Link, s *ld.LSym, t *ld.LSym) int64 {
+	s.Reachable = true
+	i := s.Size
+	s.Size += 4
+	ld.Symgrow(ctxt, s, s.Size)
+	r := ld.Addrel(s)
+	r.Sym = t
+	r.Off = int32(i)
+	r.Type = obj.R_CALL
+	r.Siz = 4
+	return i + int64(r.Siz)
+}
+
+func gentext() {
+	if !ld.DynlinkingGo() {
+		return
+	}
+	addmoduledata := ld.Linklookup(ld.Ctxt, "runtime.addmoduledata", 0)
+	if addmoduledata.Type == obj.STEXT {
+		// we're linking a module containing the runtime -> no need for
+		// an init function
+		return
+	}
+	addmoduledata.Reachable = true
+	initfunc := ld.Linklookup(ld.Ctxt, "go.link.addmoduledata", 0)
+	initfunc.Type = obj.STEXT
+	initfunc.Local = true
+	initfunc.Reachable = true
+	o := func(op ...uint8) {
+		for _, op1 := range op {
+			ld.Adduint8(ld.Ctxt, initfunc, op1)
+		}
+	}
+	// 0000000000000000 <local.dso_init>:
+	//    0:	48 8d 3d 00 00 00 00 	lea    0x0(%rip),%rdi        # 7 <local.dso_init+0x7>
+	// 			3: R_X86_64_PC32	runtime.firstmoduledata-0x4
+	o(0x48, 0x8d, 0x3d)
+	ld.Addpcrelplus(ld.Ctxt, initfunc, ld.Linklookup(ld.Ctxt, "runtime.firstmoduledata", 0), 0)
+	//    7:	e8 00 00 00 00       	callq  c <local.dso_init+0xc>
+	// 			8: R_X86_64_PLT32	runtime.addmoduledata-0x4
+	o(0xe8)
+	Addcall(ld.Ctxt, initfunc, addmoduledata)
+	//    c:	c3                   	retq
+	o(0xc3)
+	if ld.Ctxt.Etextp != nil {
+		ld.Ctxt.Etextp.Next = initfunc
+	} else {
+		ld.Ctxt.Textp = initfunc
+	}
+	ld.Ctxt.Etextp = initfunc
+	initarray_entry := ld.Linklookup(ld.Ctxt, "go.link.addmoduledatainit", 0)
+	initarray_entry.Reachable = true
+	initarray_entry.Local = true
+	initarray_entry.Type = obj.SINITARR
+	ld.Addaddr(ld.Ctxt, initarray_entry, initfunc)
+}
+
+func adddynrela(rela *ld.LSym, s *ld.LSym, r *ld.Reloc) {
+	ld.Addaddrplus(ld.Ctxt, rela, s, int64(r.Off))
+	ld.Adduint64(ld.Ctxt, rela, ld.R_X86_64_RELATIVE)
+	ld.Addaddrplus(ld.Ctxt, rela, r.Sym, r.Add) // Addend
+}
+
+func adddynrel(s *ld.LSym, r *ld.Reloc) {
+	targ := r.Sym
+	ld.Ctxt.Cursym = s
+
+	switch r.Type {
+	default:
+		if r.Type >= 256 {
+			ld.Diag("unexpected relocation type %d", r.Type)
+			return
+		}
+
+		// Handle relocations found in ELF object files.
+	case 256 + ld.R_X86_64_PC32:
+		if targ.Type == obj.SDYNIMPORT {
+			ld.Diag("unexpected R_X86_64_PC32 relocation for dynamic symbol %s", targ.Name)
+		}
+		if targ.Type == 0 || targ.Type == obj.SXREF {
+			ld.Diag("unknown symbol %s in pcrel", targ.Name)
+		}
+		r.Type = obj.R_PCREL
+		r.Add += 4
+		return
+
+	case 256 + ld.R_X86_64_PLT32:
+		r.Type = obj.R_PCREL
+		r.Add += 4
+		if targ.Type == obj.SDYNIMPORT {
+			addpltsym(targ)
+			r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
+			r.Add += int64(targ.Plt)
+		}
+
+		return
+
+	case 256 + ld.R_X86_64_GOTPCREL:
+		if targ.Type != obj.SDYNIMPORT {
+			// have symbol
+			if r.Off >= 2 && s.P[r.Off-2] == 0x8b {
+				// turn MOVQ of GOT entry into LEAQ of symbol itself
+				s.P[r.Off-2] = 0x8d
+
+				r.Type = obj.R_PCREL
+				r.Add += 4
+				return
+			}
+		}
+
+		// fall back to using GOT and hope for the best (CMOV*)
+		// TODO: just needs relocation, no need to put in .dynsym
+		addgotsym(targ)
+
+		r.Type = obj.R_PCREL
+		r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
+		r.Add += 4
+		r.Add += int64(targ.Got)
+		return
+
+	case 256 + ld.R_X86_64_64:
+		if targ.Type == obj.SDYNIMPORT {
+			ld.Diag("unexpected R_X86_64_64 relocation for dynamic symbol %s", targ.Name)
+		}
+		r.Type = obj.R_ADDR
+		return
+
+	// 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 = obj.R_ADDR
+
+		if targ.Type == obj.SDYNIMPORT {
+			ld.Diag("unexpected reloc for dynamic symbol %s", targ.Name)
+		}
+		return
+
+	case 512 + ld.MACHO_X86_64_RELOC_BRANCH*2 + 1:
+		if targ.Type == obj.SDYNIMPORT {
+			addpltsym(targ)
+			r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
+			r.Add = int64(targ.Plt)
+			r.Type = obj.R_PCREL
+			return
+		}
+		fallthrough
+
+		// fall through
+	case 512 + ld.MACHO_X86_64_RELOC_UNSIGNED*2 + 1,
+		512 + ld.MACHO_X86_64_RELOC_SIGNED*2 + 1,
+		512 + ld.MACHO_X86_64_RELOC_SIGNED_1*2 + 1,
+		512 + ld.MACHO_X86_64_RELOC_SIGNED_2*2 + 1,
+		512 + ld.MACHO_X86_64_RELOC_SIGNED_4*2 + 1:
+		r.Type = obj.R_PCREL
+
+		if targ.Type == obj.SDYNIMPORT {
+			ld.Diag("unexpected pc-relative reloc for dynamic symbol %s", targ.Name)
+		}
+		return
+
+	case 512 + ld.MACHO_X86_64_RELOC_GOT_LOAD*2 + 1:
+		if targ.Type != obj.SDYNIMPORT {
+			// have symbol
+			// turn MOVQ of GOT entry into LEAQ of symbol itself
+			if r.Off < 2 || s.P[r.Off-2] != 0x8b {
+				ld.Diag("unexpected GOT_LOAD reloc for non-dynamic symbol %s", targ.Name)
+				return
+			}
+
+			s.P[r.Off-2] = 0x8d
+			r.Type = obj.R_PCREL
+			return
+		}
+		fallthrough
+
+		// fall through
+	case 512 + ld.MACHO_X86_64_RELOC_GOT*2 + 1:
+		if targ.Type != obj.SDYNIMPORT {
+			ld.Diag("unexpected GOT reloc for non-dynamic symbol %s", targ.Name)
+		}
+		addgotsym(targ)
+		r.Type = obj.R_PCREL
+		r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
+		r.Add += int64(targ.Got)
+		return
+	}
+
+	// Handle references to ELF symbols from our own object files.
+	if targ.Type != obj.SDYNIMPORT {
+		return
+	}
+
+	switch r.Type {
+	case obj.R_CALL,
+		obj.R_PCREL:
+		if ld.HEADTYPE == obj.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 obj.R_ADDR:
+		if s.Type == obj.STEXT && ld.Iself {
+			if ld.HEADTYPE == obj.Hsolaris {
+				addpltsym(targ)
+				r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
+				r.Add += int64(targ.Plt)
+				return
+			}
+			// The code is asking for the address of an external
+			// function.  We provide it with the address of the
+			// correspondent GOT symbol.
+			addgotsym(targ)
+
+			r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
+			r.Add += int64(targ.Got)
+			return
+		}
+
+		if s.Type != obj.SDATA {
+			break
+		}
+		if ld.Iself {
+			ld.Adddynsym(ld.Ctxt, targ)
+			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))
+			} else {
+				ld.Adduint64(ld.Ctxt, rela, ld.ELF64_R_INFO(uint32(targ.Dynid), ld.R_X86_64_32))
+			}
+			ld.Adduint64(ld.Ctxt, rela, uint64(r.Add))
+			r.Type = 256 // ignore during relocsym
+			return
+		}
+
+		if ld.HEADTYPE == obj.Hdarwin && s.Size == int64(ld.Thearch.Ptrsize) && r.Off == 0 {
+			// Mach-O relocations are a royal pain to lay out.
+			// They use a compact stateful bytecode representation
+			// that is too much bother to deal with.
+			// Instead, interpret the C declaration
+			//	void *_Cvar_stderr = &stderr;
+			// as making _Cvar_stderr the name of a GOT entry
+			// for stderr.  This is separate from the usual GOT entry,
+			// just in case the C code assigns to the variable,
+			// and of course it only works for single pointers,
+			// but we only need to support cgo and that's all it needs.
+			ld.Adddynsym(ld.Ctxt, targ)
+
+			got := ld.Linklookup(ld.Ctxt, ".got", 0)
+			s.Type = got.Type | obj.SSUB
+			s.Outer = got
+			s.Sub = got.Sub
+			got.Sub = s
+			s.Value = got.Size
+			ld.Adduint64(ld.Ctxt, got, 0)
+			ld.Adduint32(ld.Ctxt, ld.Linklookup(ld.Ctxt, ".linkedit.got", 0), uint32(targ.Dynid))
+			r.Type = 256 // ignore during relocsym
+			return
+		}
+
+		if ld.HEADTYPE == obj.Hwindows {
+			// nothing to do, the relocation will be laid out in pereloc1
+			return
+		}
+	}
+
+	ld.Ctxt.Cursym = s
+	ld.Diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ.Name, r.Type, targ.Type)
+}
+
+func elfreloc1(r *ld.Reloc, sectoff int64) int {
+	ld.Thearch.Vput(uint64(sectoff))
+
+	elfsym := r.Xsym.Elfsym
+	switch r.Type {
+	default:
+		return -1
+
+	case obj.R_ADDR:
+		if r.Siz == 4 {
+			ld.Thearch.Vput(ld.R_X86_64_32 | uint64(elfsym)<<32)
+		} else if r.Siz == 8 {
+			ld.Thearch.Vput(ld.R_X86_64_64 | uint64(elfsym)<<32)
+		} else {
+			return -1
+		}
+
+	case obj.R_TLS_LE:
+		if r.Siz == 4 {
+			ld.Thearch.Vput(ld.R_X86_64_TPOFF32 | uint64(elfsym)<<32)
+		} else {
+			return -1
+		}
+
+	case obj.R_TLS_IE:
+		if r.Siz == 4 {
+			ld.Thearch.Vput(ld.R_X86_64_GOTTPOFF | uint64(elfsym)<<32)
+		} else {
+			return -1
+		}
+
+	case obj.R_CALL:
+		if r.Siz == 4 {
+			if r.Xsym.Type == obj.SDYNIMPORT {
+				if ld.DynlinkingGo() {
+					ld.Thearch.Vput(ld.R_X86_64_PLT32 | uint64(elfsym)<<32)
+				} else {
+					ld.Thearch.Vput(ld.R_X86_64_GOTPCREL | uint64(elfsym)<<32)
+				}
+			} else {
+				ld.Thearch.Vput(ld.R_X86_64_PC32 | uint64(elfsym)<<32)
+			}
+		} else {
+			return -1
+		}
+
+	case obj.R_PCREL:
+		if r.Siz == 4 {
+			if r.Xsym.Type == obj.SDYNIMPORT && r.Xsym.ElfType == elf.STT_FUNC {
+				ld.Thearch.Vput(ld.R_X86_64_PLT32 | uint64(elfsym)<<32)
+			} else {
+				ld.Thearch.Vput(ld.R_X86_64_PC32 | uint64(elfsym)<<32)
+			}
+		} else {
+			return -1
+		}
+
+	case obj.R_GOTPCREL:
+		if r.Siz == 4 {
+			ld.Thearch.Vput(ld.R_X86_64_GOTPCREL | uint64(elfsym)<<32)
+		} else {
+			return -1
+		}
+	}
+
+	ld.Thearch.Vput(uint64(r.Xadd))
+	return 0
+}
+
+func machoreloc1(r *ld.Reloc, sectoff int64) int {
+	var v uint32
+
+	rs := r.Xsym
+
+	if rs.Type == obj.SHOSTOBJ || r.Type == obj.R_PCREL {
+		if rs.Dynid < 0 {
+			ld.Diag("reloc %d to non-macho symbol %s type=%d", r.Type, rs.Name, rs.Type)
+			return -1
+		}
+
+		v = uint32(rs.Dynid)
+		v |= 1 << 27 // external relocation
+	} else {
+		v = uint32(rs.Sect.Extnum)
+		if v == 0 {
+			ld.Diag("reloc %d to symbol %s in non-macho section %s type=%d", r.Type, rs.Name, rs.Sect.Name, rs.Type)
+			return -1
+		}
+	}
+
+	switch r.Type {
+	default:
+		return -1
+
+	case obj.R_ADDR:
+		v |= ld.MACHO_X86_64_RELOC_UNSIGNED << 28
+
+	case obj.R_CALL:
+		v |= 1 << 24 // pc-relative bit
+		v |= ld.MACHO_X86_64_RELOC_BRANCH << 28
+
+		// NOTE: Only works with 'external' relocation. Forced above.
+	case obj.R_PCREL:
+		v |= 1 << 24 // pc-relative bit
+		v |= ld.MACHO_X86_64_RELOC_SIGNED << 28
+	}
+
+	switch r.Siz {
+	default:
+		return -1
+
+	case 1:
+		v |= 0 << 25
+
+	case 2:
+		v |= 1 << 25
+
+	case 4:
+		v |= 2 << 25
+
+	case 8:
+		v |= 3 << 25
+	}
+
+	ld.Thearch.Lput(uint32(sectoff))
+	ld.Thearch.Lput(v)
+	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 obj.R_ADDR:
+		if r.Siz == 8 {
+			v = ld.IMAGE_REL_AMD64_ADDR64
+		} else {
+			v = ld.IMAGE_REL_AMD64_ADDR32
+		}
+
+	case obj.R_CALL,
+		obj.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
+}
+
+func archrelocvariant(r *ld.Reloc, s *ld.LSym, t int64) int64 {
+	log.Fatalf("unexpected relocation variant")
+	return t
+}
+
+func elfsetupplt() {
+	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)
+
+		ld.Adduint8(ld.Ctxt, plt, 0x35)
+		ld.Addpcrelplus(ld.Ctxt, plt, got, 8)
+
+		// jmpq got+16(IP)
+		ld.Adduint8(ld.Ctxt, plt, 0xff)
+
+		ld.Adduint8(ld.Ctxt, plt, 0x25)
+		ld.Addpcrelplus(ld.Ctxt, plt, got, 16)
+
+		// nopl 0(AX)
+		ld.Adduint32(ld.Ctxt, plt, 0x00401f0f)
+
+		// assume got->size == 0 too
+		ld.Addaddrplus(ld.Ctxt, got, ld.Linklookup(ld.Ctxt, ".dynamic", 0), 0)
+
+		ld.Adduint64(ld.Ctxt, got, 0)
+		ld.Adduint64(ld.Ctxt, got, 0)
+	}
+}
+
+func addpltsym(s *ld.LSym) {
+	if s.Plt >= 0 {
+		return
+	}
+
+	ld.Adddynsym(ld.Ctxt, s)
+
+	if ld.Iself {
+		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()
+		}
+
+		// jmpq *got+size(IP)
+		ld.Adduint8(ld.Ctxt, plt, 0xff)
+
+		ld.Adduint8(ld.Ctxt, plt, 0x25)
+		ld.Addpcrelplus(ld.Ctxt, plt, got, got.Size)
+
+		// add to got: pointer to current pos in plt
+		ld.Addaddrplus(ld.Ctxt, got, plt, plt.Size)
+
+		// pushq $x
+		ld.Adduint8(ld.Ctxt, plt, 0x68)
+
+		ld.Adduint32(ld.Ctxt, plt, uint32((got.Size-24-8)/8))
+
+		// jmpq .plt
+		ld.Adduint8(ld.Ctxt, plt, 0xe9)
+
+		ld.Adduint32(ld.Ctxt, plt, uint32(-(plt.Size + 4)))
+
+		// rela
+		ld.Addaddrplus(ld.Ctxt, rela, got, got.Size-8)
+
+		ld.Adduint64(ld.Ctxt, rela, ld.ELF64_R_INFO(uint32(s.Dynid), ld.R_X86_64_JMP_SLOT))
+		ld.Adduint64(ld.Ctxt, rela, 0)
+
+		s.Plt = int32(plt.Size - 16)
+	} else if ld.HEADTYPE == obj.Hdarwin {
+		// To do lazy symbol lookup right, we're supposed
+		// to tell the dynamic loader which library each
+		// symbol comes from and format the link info
+		// section just so.  I'm too lazy (ha!) to do that
+		// so for now we'll just use non-lazy pointers,
+		// which don't need to be told which library to use.
+		//
+		// http://networkpx.blogspot.com/2009/09/about-lcdyldinfoonly-command.html
+		// has details about what we're avoiding.
+
+		addgotsym(s)
+		plt := ld.Linklookup(ld.Ctxt, ".plt", 0)
+
+		ld.Adduint32(ld.Ctxt, ld.Linklookup(ld.Ctxt, ".linkedit.plt", 0), uint32(s.Dynid))
+
+		// jmpq *got+size(IP)
+		s.Plt = int32(plt.Size)
+
+		ld.Adduint8(ld.Ctxt, plt, 0xff)
+		ld.Adduint8(ld.Ctxt, plt, 0x25)
+		ld.Addpcrelplus(ld.Ctxt, plt, ld.Linklookup(ld.Ctxt, ".got", 0), int64(s.Got))
+	} else {
+		ld.Diag("addpltsym: unsupported binary format")
+	}
+}
+
+func addgotsym(s *ld.LSym) {
+	if s.Got >= 0 {
+		return
+	}
+
+	ld.Adddynsym(ld.Ctxt, s)
+	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)
+		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)
+	} else if ld.HEADTYPE == obj.Hdarwin {
+		ld.Adduint32(ld.Ctxt, ld.Linklookup(ld.Ctxt, ".linkedit.got", 0), uint32(s.Dynid))
+	} else {
+		ld.Diag("addgotsym: unsupported binary format")
+	}
+}
+
+func asmb() {
+	if ld.Debug['v'] != 0 {
+		fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
+	}
+	ld.Bso.Flush()
+
+	if ld.Debug['v'] != 0 {
+		fmt.Fprintf(&ld.Bso, "%5.2f codeblk\n", obj.Cputime())
+	}
+	ld.Bso.Flush()
+
+	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.Bso.Flush()
+
+		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.Bso.Flush()
+
+	ld.Cseek(int64(ld.Segdata.Fileoff))
+	ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
+
+	machlink := int64(0)
+	if ld.HEADTYPE == obj.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))
+		ld.Cseek(dwarfoff)
+
+		ld.Segdwarf.Fileoff = uint64(ld.Cpos())
+		ld.Dwarfemitdebugsections()
+		ld.Segdwarf.Filelen = uint64(ld.Cpos()) - ld.Segdwarf.Fileoff
+
+		machlink = ld.Domacholink()
+	}
+
+	switch ld.HEADTYPE {
+	default:
+		ld.Diag("unknown header type %d", ld.HEADTYPE)
+		fallthrough
+
+	case obj.Hplan9,
+		obj.Helf:
+		break
+
+	case obj.Hdarwin:
+		ld.Debug['8'] = 1 /* 64-bit addresses */
+
+	case obj.Hlinux,
+		obj.Hfreebsd,
+		obj.Hnetbsd,
+		obj.Hopenbsd,
+		obj.Hdragonfly,
+		obj.Hsolaris:
+		ld.Debug['8'] = 1 /* 64-bit addresses */
+
+	case obj.Hnacl,
+		obj.Hwindows:
+		break
+	}
+
+	ld.Symsize = 0
+	ld.Spsize = 0
+	ld.Lcsize = 0
+	symo := int64(0)
+	if ld.Debug['s'] == 0 {
+		if ld.Debug['v'] != 0 {
+			fmt.Fprintf(&ld.Bso, "%5.2f sym\n", obj.Cputime())
+		}
+		ld.Bso.Flush()
+		switch ld.HEADTYPE {
+		default:
+		case obj.Hplan9,
+			obj.Helf:
+			ld.Debug['s'] = 1
+			symo = int64(ld.Segdata.Fileoff + ld.Segdata.Filelen)
+
+		case obj.Hdarwin:
+			symo = int64(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(ld.INITRND))) + uint64(machlink))
+
+		case obj.Hlinux,
+			obj.Hfreebsd,
+			obj.Hnetbsd,
+			obj.Hopenbsd,
+			obj.Hdragonfly,
+			obj.Hsolaris,
+			obj.Hnacl:
+			symo = int64(ld.Segdata.Fileoff + ld.Segdata.Filelen)
+			symo = ld.Rnd(symo, int64(ld.INITRND))
+
+		case obj.Hwindows:
+			symo = int64(ld.Segdata.Fileoff + ld.Segdata.Filelen)
+			symo = ld.Rnd(symo, ld.PEFILEALIGN)
+		}
+
+		ld.Cseek(symo)
+		switch ld.HEADTYPE {
+		default:
+			if ld.Iself {
+				ld.Cseek(symo)
+				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 obj.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()
+			}
+
+		case obj.Hwindows:
+			if ld.Debug['v'] != 0 {
+				fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
+			}
+
+			ld.Dwarfemitdebugsections()
+
+		case obj.Hdarwin:
+			if ld.Linkmode == ld.LinkExternal {
+				ld.Machoemitreloc()
+			}
+		}
+	}
+
+	if ld.Debug['v'] != 0 {
+		fmt.Fprintf(&ld.Bso, "%5.2f headr\n", obj.Cputime())
+	}
+	ld.Bso.Flush()
+	ld.Cseek(0)
+	switch ld.HEADTYPE {
+	default:
+	case obj.Hplan9: /* plan9 */
+		magic := int32(4*26*26 + 7)
+
+		magic |= 0x00008000                  /* fat header */
+		ld.Lputb(uint32(magic))              /* magic */
+		ld.Lputb(uint32(ld.Segtext.Filelen)) /* sizes */
+		ld.Lputb(uint32(ld.Segdata.Filelen))
+		ld.Lputb(uint32(ld.Segdata.Length - ld.Segdata.Filelen))
+		ld.Lputb(uint32(ld.Symsize)) /* nsyms */
+		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 */
+		ld.Vputb(uint64(vl))        /* va of entry */
+
+	case obj.Hdarwin:
+		ld.Asmbmacho()
+
+	case obj.Hlinux,
+		obj.Hfreebsd,
+		obj.Hnetbsd,
+		obj.Hopenbsd,
+		obj.Hdragonfly,
+		obj.Hsolaris,
+		obj.Hnacl:
+		ld.Asmbelf(symo)
+
+	case obj.Hwindows:
+		ld.Asmbpe()
+	}
+
+	ld.Cflush()
+}
diff --git a/src/cmd/link/internal/amd64/l.go b/src/cmd/link/internal/amd64/l.go
new file mode 100644
index 0000000..2537419
--- /dev/null
+++ b/src/cmd/link/internal/amd64/l.go
@@ -0,0 +1,47 @@
+// Inferno utils/6l/l.h
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/l.h
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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 amd64
+
+const (
+	thechar   = '6'
+	MaxAlign  = 32 // max data alignment
+	FuncAlign = 16
+)
+
+const (
+	MINLC = 1
+)
+
+/* Used by ../internal/ld/dwarf.go */
+const (
+	DWARFREGSP = 7
+	DWARFREGLR = 16
+)
diff --git a/src/cmd/link/internal/amd64/obj.go b/src/cmd/link/internal/amd64/obj.go
new file mode 100644
index 0000000..1aa4422
--- /dev/null
+++ b/src/cmd/link/internal/amd64/obj.go
@@ -0,0 +1,214 @@
+// Inferno utils/6l/obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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 amd64
+
+import (
+	"cmd/internal/obj"
+	"cmd/link/internal/ld"
+	"fmt"
+	"log"
+)
+
+// Reading object files.
+
+func Main() {
+	linkarchinit()
+	ld.Ldmain()
+}
+
+func linkarchinit() {
+	ld.Thestring = "amd64"
+	ld.Thelinkarch = &ld.Linkamd64
+	if obj.Getgoarch() == "amd64p32" {
+		ld.Thelinkarch = &ld.Linkamd64p32
+	}
+
+	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.Dwarfreglr = DWARFREGLR
+
+	ld.Thearch.Adddynrel = adddynrel
+	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.PEreloc1 = pereloc1
+	ld.Thearch.Lput = ld.Lputl
+	ld.Thearch.Wput = ld.Wputl
+	ld.Thearch.Vput = ld.Vputl
+
+	ld.Thearch.Linuxdynld = "/lib64/ld-linux-x86-64.so.2"
+	ld.Thearch.Freebsddynld = "/libexec/ld-elf.so.1"
+	ld.Thearch.Openbsddynld = "/usr/libexec/ld.so"
+	ld.Thearch.Netbsddynld = "/libexec/ld.elf_so"
+	ld.Thearch.Dragonflydynld = "/usr/libexec/ld-elf.so.2"
+	ld.Thearch.Solarisdynld = "/lib/amd64/ld.so.1"
+}
+
+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
+	}
+
+	if ld.Buildmode == ld.BuildmodeCArchive || ld.Buildmode == ld.BuildmodeCShared || ld.DynlinkingGo() {
+		ld.Linkmode = ld.LinkExternal
+	}
+
+	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)))
+		}
+
+	case obj.Hdarwin,
+		obj.Hdragonfly,
+		obj.Hfreebsd,
+		obj.Hlinux,
+		obj.Hnacl,
+		obj.Hnetbsd,
+		obj.Hopenbsd,
+		obj.Hsolaris,
+		obj.Hwindows:
+		break
+	}
+
+	switch ld.HEADTYPE {
+	default:
+		ld.Exitf("unknown -H option: %v", ld.HEADTYPE)
+
+	case obj.Hplan9: /* plan 9 */
+		ld.HEADR = 32 + 8
+
+		if ld.INITTEXT == -1 {
+			ld.INITTEXT = 0x200000 + int64(ld.HEADR)
+		}
+		if ld.INITDAT == -1 {
+			ld.INITDAT = 0
+		}
+		if ld.INITRND == -1 {
+			ld.INITRND = 0x200000
+		}
+
+	case obj.Helf: /* elf32 executable */
+		ld.HEADR = int32(ld.Rnd(52+3*32, 16))
+
+		if ld.INITTEXT == -1 {
+			ld.INITTEXT = 0x80110000
+		}
+		if ld.INITDAT == -1 {
+			ld.INITDAT = 0
+		}
+		if ld.INITRND == -1 {
+			ld.INITRND = 4096
+		}
+
+	case obj.Hdarwin: /* apple MACH */
+		ld.Machoinit()
+
+		ld.HEADR = ld.INITIAL_MACHO_HEADR
+		if ld.INITRND == -1 {
+			ld.INITRND = 4096
+		}
+		if ld.INITTEXT == -1 {
+			ld.INITTEXT = 4096 + int64(ld.HEADR)
+		}
+		if ld.INITDAT == -1 {
+			ld.INITDAT = 0
+		}
+
+	case obj.Hlinux, /* elf64 executable */
+		obj.Hfreebsd,   /* freebsd */
+		obj.Hnetbsd,    /* netbsd */
+		obj.Hopenbsd,   /* openbsd */
+		obj.Hdragonfly, /* dragonfly */
+		obj.Hsolaris:   /* solaris */
+		ld.Elfinit()
+
+		ld.HEADR = ld.ELFRESERVE
+		if ld.INITTEXT == -1 {
+			ld.INITTEXT = (1 << 22) + int64(ld.HEADR)
+		}
+		if ld.INITDAT == -1 {
+			ld.INITDAT = 0
+		}
+		if ld.INITRND == -1 {
+			ld.INITRND = 4096
+		}
+
+	case obj.Hnacl:
+		ld.Elfinit()
+		ld.Debug['w']++ // disable dwarf, which gets confused and is useless anyway
+		ld.HEADR = 0x10000
+		ld.Funcalign = 32
+		if ld.INITTEXT == -1 {
+			ld.INITTEXT = 0x20000
+		}
+		if ld.INITDAT == -1 {
+			ld.INITDAT = 0
+		}
+		if ld.INITRND == -1 {
+			ld.INITRND = 0x10000
+		}
+
+	case obj.Hwindows: /* PE executable */
+		ld.Peinit()
+
+		ld.HEADR = ld.PEFILEHEADR
+		if ld.INITTEXT == -1 {
+			ld.INITTEXT = ld.PEBASE + int64(ld.PESECTHEADR)
+		}
+		if ld.INITDAT == -1 {
+			ld.INITDAT = 0
+		}
+		if ld.INITRND == -1 {
+			ld.INITRND = ld.PESECTALIGN
+		}
+	}
+
+	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/link/internal/amd64/z.go b/src/cmd/link/internal/amd64/z.go
new file mode 100644
index 0000000..f70035b
--- /dev/null
+++ b/src/cmd/link/internal/amd64/z.go
@@ -0,0 +1 @@
+package amd64
diff --git a/src/cmd/link/internal/arm/asm.go b/src/cmd/link/internal/arm/asm.go
new file mode 100644
index 0000000..a0e31a3
--- /dev/null
+++ b/src/cmd/link/internal/arm/asm.go
@@ -0,0 +1,651 @@
+// 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 at 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 at 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 arm
+
+import (
+	"cmd/internal/obj"
+	"cmd/link/internal/ld"
+	"fmt"
+	"log"
+)
+
+func gentext() {
+}
+
+// Preserve highest 8 bits of a, and do addition to lower 24-bit
+// of a and b; used to adjust ARM branch intruction's target
+func braddoff(a int32, b int32) int32 {
+	return int32((uint32(a))&0xff000000 | 0x00ffffff&uint32(a+b))
+}
+
+func adddynrela(rel *ld.LSym, s *ld.LSym, r *ld.Reloc) {
+	ld.Addaddrplus(ld.Ctxt, rel, s, int64(r.Off))
+	ld.Adduint32(ld.Ctxt, rel, ld.R_ARM_RELATIVE)
+}
+
+func adddynrel(s *ld.LSym, r *ld.Reloc) {
+	targ := r.Sym
+	ld.Ctxt.Cursym = s
+
+	switch r.Type {
+	default:
+		if r.Type >= 256 {
+			ld.Diag("unexpected relocation type %d", r.Type)
+			return
+		}
+
+		// Handle relocations found in ELF object files.
+	case 256 + ld.R_ARM_PLT32:
+		r.Type = obj.R_CALLARM
+
+		if targ.Type == obj.SDYNIMPORT {
+			addpltsym(ld.Ctxt, targ)
+			r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
+			r.Add = int64(braddoff(int32(r.Add), targ.Plt/4))
+		}
+
+		return
+
+	case 256 + ld.R_ARM_THM_PC22: // R_ARM_THM_CALL
+		ld.Exitf("R_ARM_THM_CALL, are you using -marm?")
+		return
+
+	case 256 + ld.R_ARM_GOT32: // R_ARM_GOT_BREL
+		if targ.Type != obj.SDYNIMPORT {
+			addgotsyminternal(ld.Ctxt, targ)
+		} else {
+			addgotsym(ld.Ctxt, targ)
+		}
+
+		r.Type = obj.R_CONST // write r->add during relocsym
+		r.Sym = nil
+		r.Add += int64(targ.Got)
+		return
+
+	case 256 + ld.R_ARM_GOT_PREL: // GOT(nil) + A - nil
+		if targ.Type != obj.SDYNIMPORT {
+			addgotsyminternal(ld.Ctxt, targ)
+		} else {
+			addgotsym(ld.Ctxt, targ)
+		}
+
+		r.Type = obj.R_PCREL
+		r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
+		r.Add += int64(targ.Got) + 4
+		return
+
+	case 256 + ld.R_ARM_GOTOFF: // R_ARM_GOTOFF32
+		r.Type = obj.R_GOTOFF
+
+		return
+
+	case 256 + ld.R_ARM_GOTPC: // R_ARM_BASE_PREL
+		r.Type = obj.R_PCREL
+
+		r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
+		r.Add += 4
+		return
+
+	case 256 + ld.R_ARM_CALL:
+		r.Type = obj.R_CALLARM
+		if targ.Type == obj.SDYNIMPORT {
+			addpltsym(ld.Ctxt, targ)
+			r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
+			r.Add = int64(braddoff(int32(r.Add), targ.Plt/4))
+		}
+
+		return
+
+	case 256 + ld.R_ARM_REL32: // R_ARM_REL32
+		r.Type = obj.R_PCREL
+
+		r.Add += 4
+		return
+
+	case 256 + ld.R_ARM_ABS32:
+		if targ.Type == obj.SDYNIMPORT {
+			ld.Diag("unexpected R_ARM_ABS32 relocation for dynamic symbol %s", targ.Name)
+		}
+		r.Type = obj.R_ADDR
+		return
+
+		// we can just ignore this, because we are targeting ARM V5+ anyway
+	case 256 + ld.R_ARM_V4BX:
+		if r.Sym != nil {
+			// R_ARM_V4BX is ABS relocation, so this symbol is a dummy symbol, ignore it
+			r.Sym.Type = 0
+		}
+
+		r.Sym = nil
+		return
+
+	case 256 + ld.R_ARM_PC24,
+		256 + ld.R_ARM_JUMP24:
+		r.Type = obj.R_CALLARM
+		if targ.Type == obj.SDYNIMPORT {
+			addpltsym(ld.Ctxt, targ)
+			r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
+			r.Add = int64(braddoff(int32(r.Add), targ.Plt/4))
+		}
+
+		return
+	}
+
+	// Handle references to ELF symbols from our own object files.
+	if targ.Type != obj.SDYNIMPORT {
+		return
+	}
+
+	switch r.Type {
+	case obj.R_CALLARM:
+		addpltsym(ld.Ctxt, targ)
+		r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
+		r.Add = int64(targ.Plt)
+		return
+
+	case obj.R_ADDR:
+		if s.Type != obj.SDATA {
+			break
+		}
+		if ld.Iself {
+			ld.Adddynsym(ld.Ctxt, targ)
+			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 dynamic reloc
+			r.Type = obj.R_CONST                                                               // write r->add during relocsym
+			r.Sym = nil
+			return
+		}
+	}
+
+	ld.Ctxt.Cursym = s
+	ld.Diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ.Name, r.Type, targ.Type)
+}
+
+func elfreloc1(r *ld.Reloc, sectoff int64) int {
+	ld.Thearch.Lput(uint32(sectoff))
+
+	elfsym := r.Xsym.Elfsym
+	switch r.Type {
+	default:
+		return -1
+
+	case obj.R_ADDR:
+		if r.Siz == 4 {
+			ld.Thearch.Lput(ld.R_ARM_ABS32 | uint32(elfsym)<<8)
+		} else {
+			return -1
+		}
+
+	case obj.R_PCREL:
+		if r.Siz == 4 {
+			ld.Thearch.Lput(ld.R_ARM_REL32 | uint32(elfsym)<<8)
+		} else {
+			return -1
+		}
+
+	case obj.R_CALLARM:
+		if r.Siz == 4 {
+			if r.Add&0xff000000 == 0xeb000000 { // BL
+				ld.Thearch.Lput(ld.R_ARM_CALL | uint32(elfsym)<<8)
+			} else {
+				ld.Thearch.Lput(ld.R_ARM_JUMP24 | uint32(elfsym)<<8)
+			}
+		} else {
+			return -1
+		}
+
+	case obj.R_TLS:
+		if r.Siz == 4 {
+			if ld.Buildmode == ld.BuildmodeCShared {
+				ld.Thearch.Lput(ld.R_ARM_TLS_IE32 | uint32(elfsym)<<8)
+			} else {
+				ld.Thearch.Lput(ld.R_ARM_TLS_LE32 | uint32(elfsym)<<8)
+			}
+		} else {
+			return -1
+		}
+	}
+
+	return 0
+}
+
+func elfsetupplt() {
+	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)
+
+		// ldr lr, [pc, #4]
+		ld.Adduint32(ld.Ctxt, plt, 0xe59fe004)
+
+		// add lr, pc, lr
+		ld.Adduint32(ld.Ctxt, plt, 0xe08fe00e)
+
+		// ldr pc, [lr, #8]!
+		ld.Adduint32(ld.Ctxt, plt, 0xe5bef008)
+
+		// .word &GLOBAL_OFFSET_TABLE[0] - .
+		ld.Addpcrelplus(ld.Ctxt, plt, got, 4)
+
+		// the first .plt entry requires 3 .plt.got entries
+		ld.Adduint32(ld.Ctxt, got, 0)
+
+		ld.Adduint32(ld.Ctxt, got, 0)
+		ld.Adduint32(ld.Ctxt, got, 0)
+	}
+}
+
+func machoreloc1(r *ld.Reloc, sectoff int64) int {
+	var v uint32
+
+	rs := r.Xsym
+
+	if rs.Type == obj.SHOSTOBJ || r.Type == obj.R_CALLARM {
+		if rs.Dynid < 0 {
+			ld.Diag("reloc %d to non-macho symbol %s type=%d", r.Type, rs.Name, rs.Type)
+			return -1
+		}
+
+		v = uint32(rs.Dynid)
+		v |= 1 << 27 // external relocation
+	} else {
+		v = uint32(rs.Sect.Extnum)
+		if v == 0 {
+			ld.Diag("reloc %d to symbol %s in non-macho section %s type=%d", r.Type, rs.Name, rs.Sect.Name, rs.Type)
+			return -1
+		}
+	}
+
+	switch r.Type {
+	default:
+		return -1
+
+	case obj.R_ADDR:
+		v |= ld.MACHO_GENERIC_RELOC_VANILLA << 28
+
+	case obj.R_CALLARM:
+		v |= 1 << 24 // pc-relative bit
+		v |= ld.MACHO_ARM_RELOC_BR24 << 28
+	}
+
+	switch r.Siz {
+	default:
+		return -1
+
+	case 1:
+		v |= 0 << 25
+
+	case 2:
+		v |= 1 << 25
+
+	case 4:
+		v |= 2 << 25
+
+	case 8:
+		v |= 3 << 25
+	}
+
+	ld.Thearch.Lput(uint32(sectoff))
+	ld.Thearch.Lput(v)
+	return 0
+}
+
+func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
+	if ld.Linkmode == ld.LinkExternal {
+		switch r.Type {
+		case obj.R_CALLARM:
+			r.Done = 0
+
+			// set up addend for eventual relocation via outer symbol.
+			rs := r.Sym
+
+			r.Xadd = r.Add
+			if r.Xadd&0x800000 != 0 {
+				r.Xadd |= ^0xffffff
+			}
+			r.Xadd *= 4
+			for rs.Outer != nil {
+				r.Xadd += ld.Symaddr(rs) - ld.Symaddr(rs.Outer)
+				rs = rs.Outer
+			}
+
+			if rs.Type != obj.SHOSTOBJ && rs.Sect == nil {
+				ld.Diag("missing section for %s", rs.Name)
+			}
+			r.Xsym = rs
+
+			// ld64 for arm seems to want the symbol table to contain offset
+			// into the section rather than pseudo virtual address that contains
+			// the section load address.
+			// we need to compensate that by removing the instruction's address
+			// from addend.
+			if ld.HEADTYPE == obj.Hdarwin {
+				r.Xadd -= ld.Symaddr(s) + int64(r.Off)
+			}
+
+			*val = int64(braddoff(int32(0xff000000&uint32(r.Add)), int32(0xffffff&uint32(r.Xadd/4))))
+			return 0
+		}
+
+		return -1
+	}
+
+	switch r.Type {
+	case obj.R_CONST:
+		*val = r.Add
+		return 0
+
+	case obj.R_GOTOFF:
+		*val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got", 0))
+		return 0
+
+		// The following three arch specific relocations are only for generation of
+	// Linux/ARM ELF's PLT entry (3 assembler instruction)
+	case obj.R_PLT0: // add ip, pc, #0xXX00000
+		if ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got.plt", 0)) < ld.Symaddr(ld.Linklookup(ld.Ctxt, ".plt", 0)) {
+			ld.Diag(".got.plt should be placed after .plt section.")
+		}
+		*val = 0xe28fc600 + (0xff & (int64(uint32(ld.Symaddr(r.Sym)-(ld.Symaddr(ld.Linklookup(ld.Ctxt, ".plt", 0))+int64(r.Off))+r.Add)) >> 20))
+		return 0
+
+	case obj.R_PLT1: // add ip, ip, #0xYY000
+		*val = 0xe28cca00 + (0xff & (int64(uint32(ld.Symaddr(r.Sym)-(ld.Symaddr(ld.Linklookup(ld.Ctxt, ".plt", 0))+int64(r.Off))+r.Add+4)) >> 12))
+
+		return 0
+
+	case obj.R_PLT2: // ldr pc, [ip, #0xZZZ]!
+		*val = 0xe5bcf000 + (0xfff & int64(uint32(ld.Symaddr(r.Sym)-(ld.Symaddr(ld.Linklookup(ld.Ctxt, ".plt", 0))+int64(r.Off))+r.Add+8)))
+
+		return 0
+
+	case obj.R_CALLARM: // bl XXXXXX or b YYYYYY
+		*val = int64(braddoff(int32(0xff000000&uint32(r.Add)), int32(0xffffff&uint32((ld.Symaddr(r.Sym)+int64((uint32(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 t
+}
+
+func addpltreloc(ctxt *ld.Link, plt *ld.LSym, got *ld.LSym, sym *ld.LSym, typ int) *ld.Reloc {
+	r := ld.Addrel(plt)
+	r.Sym = got
+	r.Off = int32(plt.Size)
+	r.Siz = 4
+	r.Type = int32(typ)
+	r.Add = int64(sym.Got) - 8
+
+	plt.Reachable = true
+	plt.Size += 4
+	ld.Symgrow(ctxt, plt, plt.Size)
+
+	return r
+}
+
+func addpltsym(ctxt *ld.Link, s *ld.LSym) {
+	if s.Plt >= 0 {
+		return
+	}
+
+	ld.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)
+		if plt.Size == 0 {
+			elfsetupplt()
+		}
+
+		// .got entry
+		s.Got = int32(got.Size)
+
+		// In theory, all GOT should point to the first PLT entry,
+		// Linux/ARM's dynamic linker will do that for us, but FreeBSD/ARM's
+		// dynamic linker won't, so we'd better do it ourselves.
+		ld.Addaddrplus(ctxt, got, plt, 0)
+
+		// .plt entry, this depends on the .got entry
+		s.Plt = int32(plt.Size)
+
+		addpltreloc(ctxt, plt, got, s, obj.R_PLT0) // add lr, pc, #0xXX00000
+		addpltreloc(ctxt, plt, got, s, obj.R_PLT1) // add lr, lr, #0xYY000
+		addpltreloc(ctxt, plt, got, s, obj.R_PLT2) // ldr pc, [lr, #0xZZZ]!
+
+		// rel
+		ld.Addaddrplus(ctxt, rel, got, int64(s.Got))
+
+		ld.Adduint32(ctxt, rel, ld.ELF32_R_INFO(uint32(s.Dynid), ld.R_ARM_JUMP_SLOT))
+	} else {
+		ld.Diag("addpltsym: unsupported binary format")
+	}
+}
+
+func addgotsyminternal(ctxt *ld.Link, s *ld.LSym) {
+	if s.Got >= 0 {
+		return
+	}
+
+	got := ld.Linklookup(ctxt, ".got", 0)
+	s.Got = int32(got.Size)
+
+	ld.Addaddrplus(ctxt, got, s, 0)
+
+	if ld.Iself {
+	} else {
+		ld.Diag("addgotsyminternal: unsupported binary format")
+	}
+}
+
+func addgotsym(ctxt *ld.Link, s *ld.LSym) {
+	if s.Got >= 0 {
+		return
+	}
+
+	ld.Adddynsym(ctxt, s)
+	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)
+		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 {
+		ld.Diag("addgotsym: unsupported binary format")
+	}
+}
+
+func asmb() {
+	if ld.Debug['v'] != 0 {
+		fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
+	}
+	ld.Bso.Flush()
+
+	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.Bso.Flush()
+
+		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.Bso.Flush()
+
+	ld.Cseek(int64(ld.Segdata.Fileoff))
+	ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
+
+	machlink := uint32(0)
+	if ld.HEADTYPE == obj.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)))
+		ld.Cseek(int64(dwarfoff))
+
+		ld.Segdwarf.Fileoff = uint64(ld.Cpos())
+		ld.Dwarfemitdebugsections()
+		ld.Segdwarf.Filelen = uint64(ld.Cpos()) - ld.Segdwarf.Fileoff
+
+		machlink = uint32(ld.Domacholink())
+	}
+
+	/* 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.Bso.Flush()
+		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 obj.Hplan9:
+			symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
+
+		case obj.Hdarwin:
+			symo = uint32(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(ld.INITRND))) + uint64(machlink))
+		}
+
+		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 obj.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()
+			}
+
+		case obj.Hdarwin:
+			if ld.Linkmode == ld.LinkExternal {
+				ld.Machoemitreloc()
+			}
+		}
+	}
+
+	ld.Ctxt.Cursym = nil
+	if ld.Debug['v'] != 0 {
+		fmt.Fprintf(&ld.Bso, "%5.2f header\n", obj.Cputime())
+	}
+	ld.Bso.Flush()
+	ld.Cseek(0)
+	switch ld.HEADTYPE {
+	default:
+	case obj.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 obj.Hlinux,
+		obj.Hfreebsd,
+		obj.Hnetbsd,
+		obj.Hopenbsd,
+		obj.Hnacl:
+		ld.Asmbelf(int64(symo))
+
+	case obj.Hdarwin:
+		ld.Asmbmacho()
+	}
+
+	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/link/internal/arm/l.go b/src/cmd/link/internal/arm/l.go
new file mode 100644
index 0000000..4973772
--- /dev/null
+++ b/src/cmd/link/internal/arm/l.go
@@ -0,0 +1,79 @@
+// 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 at 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 at 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 arm
+
+// Writing object files.
+
+// Inferno utils/5l/l.h
+// http://code.google.com/p/inferno-os/source/browse/utils/5l/l.h
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
+
+const (
+	thechar   = '5'
+	PtrSize   = 4
+	IntSize   = 4
+	RegSize   = 4
+	MaxAlign  = 8 // max data alignment
+	FuncAlign = 4 // single-instruction alignment
+	MINLC     = 4
+)
+
+/* Used by ../internal/ld/dwarf.go */
+const (
+	DWARFREGSP = 13
+	DWARFREGLR = 14
+)
diff --git a/src/cmd/link/internal/arm/obj.go b/src/cmd/link/internal/arm/obj.go
new file mode 100644
index 0000000..14fe7a6
--- /dev/null
+++ b/src/cmd/link/internal/arm/obj.go
@@ -0,0 +1,178 @@
+// 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 at 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 at 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 arm
+
+import (
+	"cmd/internal/obj"
+	"cmd/link/internal/ld"
+	"fmt"
+	"log"
+)
+
+// Reading object files.
+
+func Main() {
+	linkarchinit()
+	ld.Ldmain()
+}
+
+func linkarchinit() {
+	ld.Thestring = "arm"
+	ld.Thelinkarch = &ld.Linkarm
+
+	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.Dwarfreglr = DWARFREGLR
+
+	ld.Thearch.Adddynrel = adddynrel
+	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.so.3" // 2 for OABI, 3 for EABI
+	ld.Thearch.Freebsddynld = "/usr/libexec/ld-elf.so.1"
+	ld.Thearch.Openbsddynld = "/usr/libexec/ld.so"
+	ld.Thearch.Netbsddynld = "/libexec/ld.elf_so"
+	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)))
+		}
+
+	case obj.Hlinux,
+		obj.Hfreebsd,
+		obj.Hnacl,
+		obj.Hdarwin:
+		break
+	}
+
+	switch ld.HEADTYPE {
+	default:
+		ld.Exitf("unknown -H option: %v", ld.HEADTYPE)
+
+	case obj.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 obj.Hlinux, /* arm elf */
+		obj.Hfreebsd,
+		obj.Hnetbsd,
+		obj.Hopenbsd:
+		ld.Debug['d'] = 0
+		// with dynamic linking
+		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 = 4096
+		}
+
+	case obj.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
+		}
+
+	case obj.Hdarwin: /* apple MACH */
+		ld.Debug['w'] = 1 // disable DWARF generataion
+		ld.Machoinit()
+		ld.HEADR = ld.INITIAL_MACHO_HEADR
+		if ld.INITTEXT == -1 {
+			ld.INITTEXT = 4096 + int64(ld.HEADR)
+		}
+		if ld.INITDAT == -1 {
+			ld.INITDAT = 0
+		}
+		if ld.INITRND == -1 {
+			ld.INITRND = 4096
+		}
+	}
+
+	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))
+	}
+
+	// embed goarm to runtime.goarm
+	s := ld.Linklookup(ld.Ctxt, "runtime.goarm", 0)
+
+	s.Type = obj.SRODATA
+	ld.Adduint8(ld.Ctxt, s, uint8(ld.Ctxt.Goarm))
+}
diff --git a/src/cmd/link/internal/arm64/asm.go b/src/cmd/link/internal/arm64/asm.go
new file mode 100644
index 0000000..3aebd8a
--- /dev/null
+++ b/src/cmd/link/internal/arm64/asm.go
@@ -0,0 +1,435 @@
+// 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 at 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 at 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"
+	"cmd/link/internal/ld"
+	"encoding/binary"
+	"fmt"
+	"log"
+)
+
+func gentext() {}
+
+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 {
+	ld.Thearch.Vput(uint64(sectoff))
+
+	elfsym := r.Xsym.Elfsym
+	switch r.Type {
+	default:
+		return -1
+
+	case obj.R_ADDR:
+		switch r.Siz {
+		case 4:
+			ld.Thearch.Vput(ld.R_AARCH64_ABS32 | uint64(elfsym)<<32)
+		case 8:
+			ld.Thearch.Vput(ld.R_AARCH64_ABS64 | uint64(elfsym)<<32)
+		default:
+			return -1
+		}
+
+	case obj.R_ADDRARM64:
+		// two relocations: R_AARCH64_ADR_PREL_PG_HI21 and R_AARCH64_ADD_ABS_LO12_NC
+		ld.Thearch.Vput(ld.R_AARCH64_ADR_PREL_PG_HI21 | uint64(elfsym)<<32)
+		ld.Thearch.Vput(uint64(r.Xadd))
+		ld.Thearch.Vput(uint64(sectoff + 4))
+		ld.Thearch.Vput(ld.R_AARCH64_ADD_ABS_LO12_NC | uint64(elfsym)<<32)
+
+	case obj.R_CALLARM64:
+		if r.Siz != 4 {
+			return -1
+		}
+		ld.Thearch.Vput(ld.R_AARCH64_CALL26 | uint64(elfsym)<<32)
+
+	}
+	ld.Thearch.Vput(uint64(r.Xadd))
+
+	return 0
+}
+
+func elfsetupplt() {
+	// TODO(aram)
+	return
+}
+
+func machoreloc1(r *ld.Reloc, sectoff int64) int {
+	var v uint32
+
+	rs := r.Xsym
+
+	// ld64 has a bug handling MACHO_ARM64_RELOC_UNSIGNED with !extern relocation.
+	// see cmd/internal/ld/data.go for details. The workarond is that don't use !extern
+	// UNSIGNED relocation at all.
+	if rs.Type == obj.SHOSTOBJ || r.Type == obj.R_CALLARM64 || r.Type == obj.R_ADDRARM64 || r.Type == obj.R_ADDR {
+		if rs.Dynid < 0 {
+			ld.Diag("reloc %d to non-macho symbol %s type=%d", r.Type, rs.Name, rs.Type)
+			return -1
+		}
+
+		v = uint32(rs.Dynid)
+		v |= 1 << 27 // external relocation
+	} else {
+		v = uint32(rs.Sect.Extnum)
+		if v == 0 {
+			ld.Diag("reloc %d to symbol %s in non-macho section %s type=%d", r.Type, rs.Name, rs.Sect.Name, rs.Type)
+			return -1
+		}
+	}
+
+	switch r.Type {
+	default:
+		return -1
+
+	case obj.R_ADDR:
+		v |= ld.MACHO_ARM64_RELOC_UNSIGNED << 28
+
+	case obj.R_CALLARM64:
+		if r.Xadd != 0 {
+			ld.Diag("ld64 doesn't allow BR26 reloc with non-zero addend: %s+%d", rs.Name, r.Xadd)
+		}
+
+		v |= 1 << 24 // pc-relative bit
+		v |= ld.MACHO_ARM64_RELOC_BRANCH26 << 28
+
+	case obj.R_ADDRARM64:
+		r.Siz = 4
+		// Two relocation entries: MACHO_ARM64_RELOC_PAGEOFF12 MACHO_ARM64_RELOC_PAGE21
+		// if r.Xadd is non-zero, add two MACHO_ARM64_RELOC_ADDEND.
+		if r.Xadd != 0 {
+			ld.Thearch.Lput(uint32(sectoff + 4))
+			ld.Thearch.Lput((ld.MACHO_ARM64_RELOC_ADDEND << 28) | (2 << 25) | uint32(r.Xadd&0xffffff))
+		}
+		ld.Thearch.Lput(uint32(sectoff + 4))
+		ld.Thearch.Lput(v | (ld.MACHO_ARM64_RELOC_PAGEOFF12 << 28) | (2 << 25))
+		if r.Xadd != 0 {
+			ld.Thearch.Lput(uint32(sectoff))
+			ld.Thearch.Lput((ld.MACHO_ARM64_RELOC_ADDEND << 28) | (2 << 25) | uint32(r.Xadd&0xffffff))
+		}
+		v |= 1 << 24 // pc-relative bit
+		v |= ld.MACHO_ARM64_RELOC_PAGE21 << 28
+	}
+
+	switch r.Siz {
+	default:
+		return -1
+
+	case 1:
+		v |= 0 << 25
+
+	case 2:
+		v |= 1 << 25
+
+	case 4:
+		v |= 2 << 25
+
+	case 8:
+		v |= 3 << 25
+	}
+
+	ld.Thearch.Lput(uint32(sectoff))
+	ld.Thearch.Lput(v)
+	return 0
+}
+
+func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
+	if ld.Linkmode == ld.LinkExternal {
+		switch r.Type {
+		default:
+			return -1
+
+		case obj.R_ADDRARM64:
+			r.Done = 0
+
+			// set up addend for eventual relocation via outer symbol.
+			rs := r.Sym
+			r.Xadd = r.Add
+			for rs.Outer != nil {
+				r.Xadd += ld.Symaddr(rs) - ld.Symaddr(rs.Outer)
+				rs = rs.Outer
+			}
+
+			if rs.Type != obj.SHOSTOBJ && rs.Sect == nil {
+				ld.Diag("missing section for %s", rs.Name)
+			}
+			r.Xsym = rs
+
+			// the first instruction is always at the lower address, this is endian neutral;
+			// but note that o0 and o1 should still use the target endian.
+			o0 := ld.Thelinkarch.ByteOrder.Uint32(s.P[r.Off : r.Off+4])
+			o1 := ld.Thelinkarch.ByteOrder.Uint32(s.P[r.Off+4 : r.Off+8])
+
+			// Note: ld64 currently has a bug that any non-zero addend for BR26 relocation
+			// will make the linking fail because it thinks the code is not PIC even though
+			// the BR26 relocation should be fully resolved at link time.
+			// That is the reason why the next if block is disabled. When the bug in ld64
+			// is fixed, we can enable this block and also enable duff's device in cmd/7g.
+			if false && ld.HEADTYPE == obj.Hdarwin {
+				// Mach-O wants the addend to be encoded in the instruction
+				// Note that although Mach-O supports ARM64_RELOC_ADDEND, it
+				// can only encode 24-bit of signed addend, but the instructions
+				// supports 33-bit of signed addend, so we always encode the
+				// addend in place.
+				o0 |= (uint32((r.Xadd>>12)&3) << 29) | (uint32((r.Xadd>>12>>2)&0x7ffff) << 5)
+				o1 |= uint32(r.Xadd&0xfff) << 10
+				r.Xadd = 0
+			}
+
+			// when laid out, the instruction order must always be o1, o2.
+			if ld.Ctxt.Arch.ByteOrder == binary.BigEndian {
+				*val = int64(o0)<<32 | int64(o1)
+			} else {
+				*val = int64(o1)<<32 | int64(o0)
+			}
+
+			return 0
+
+		case obj.R_CALLARM64:
+			r.Done = 0
+			r.Xsym = r.Sym
+			*val = int64(0xfc000000 & uint32(r.Add))
+			r.Xadd = int64((uint32(r.Add) &^ 0xfc000000) * 4)
+			r.Add = 0
+			return 0
+		}
+	}
+
+	switch r.Type {
+	case obj.R_CONST:
+		*val = r.Add
+		return 0
+
+	case obj.R_GOTOFF:
+		*val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got", 0))
+		return 0
+
+	case obj.R_ADDRARM64:
+		t := ld.Symaddr(r.Sym) + r.Add - ((s.Value + int64(r.Off)) &^ 0xfff)
+		if t >= 1<<32 || t < -1<<32 {
+			ld.Diag("program too large, address relocation distance = %d", t)
+		}
+
+		// the first instruction is always at the lower address, this is endian neutral;
+		// but note that o0 and o1 should still use the target endian.
+		o0 := ld.Thelinkarch.ByteOrder.Uint32(s.P[r.Off : r.Off+4])
+		o1 := ld.Thelinkarch.ByteOrder.Uint32(s.P[r.Off+4 : r.Off+8])
+
+		o0 |= (uint32((t>>12)&3) << 29) | (uint32((t>>12>>2)&0x7ffff) << 5)
+		o1 |= uint32(t&0xfff) << 10
+
+		// when laid out, the instruction order must always be o1, o2.
+		if ld.Ctxt.Arch.ByteOrder == binary.BigEndian {
+			*val = int64(o0)<<32 | int64(o1)
+		} else {
+			*val = int64(o1)<<32 | int64(o0)
+		}
+		return 0
+
+	case obj.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 asmb() {
+	if ld.Debug['v'] != 0 {
+		fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
+	}
+	ld.Bso.Flush()
+
+	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.Bso.Flush()
+
+		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.Bso.Flush()
+
+	ld.Cseek(int64(ld.Segdata.Fileoff))
+	ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
+
+	machlink := uint32(0)
+	if ld.HEADTYPE == obj.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)))
+		ld.Cseek(int64(dwarfoff))
+
+		ld.Segdwarf.Fileoff = uint64(ld.Cpos())
+		ld.Dwarfemitdebugsections()
+		ld.Segdwarf.Filelen = uint64(ld.Cpos()) - ld.Segdwarf.Fileoff
+
+		machlink = uint32(ld.Domacholink())
+	}
+
+	/* 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.Bso.Flush()
+		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 obj.Hplan9:
+			symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
+
+		case obj.Hdarwin:
+			symo = uint32(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(ld.INITRND))) + uint64(machlink))
+		}
+
+		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 obj.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()
+			}
+
+		case obj.Hdarwin:
+			if ld.Linkmode == ld.LinkExternal {
+				ld.Machoemitreloc()
+			}
+		}
+	}
+
+	ld.Ctxt.Cursym = nil
+	if ld.Debug['v'] != 0 {
+		fmt.Fprintf(&ld.Bso, "%5.2f header\n", obj.Cputime())
+	}
+	ld.Bso.Flush()
+	ld.Cseek(0)
+	switch ld.HEADTYPE {
+	default:
+	case obj.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 obj.Hlinux,
+		obj.Hfreebsd,
+		obj.Hnetbsd,
+		obj.Hopenbsd,
+		obj.Hnacl:
+		ld.Asmbelf(int64(symo))
+
+	case obj.Hdarwin:
+		ld.Asmbmacho()
+	}
+
+	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/link/internal/arm64/l.go b/src/cmd/link/internal/arm64/l.go
new file mode 100644
index 0000000..8d0d57e
--- /dev/null
+++ b/src/cmd/link/internal/arm64/l.go
@@ -0,0 +1,78 @@
+// 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 at 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 at 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
+
+// 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 at 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 at 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 ../internal/ld/dwarf.go */
+const (
+	DWARFREGSP = 31
+	DWARFREGLR = 30
+)
diff --git a/src/cmd/link/internal/arm64/obj.go b/src/cmd/link/internal/arm64/obj.go
new file mode 100644
index 0000000..56f5815
--- /dev/null
+++ b/src/cmd/link/internal/arm64/obj.go
@@ -0,0 +1,169 @@
+// 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 at 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 at 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"
+	"cmd/link/internal/ld"
+	"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.Dwarfreglr = DWARFREGLR
+
+	ld.Thearch.Adddynrel = adddynrel
+	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
+	}
+
+	// Darwin/arm64 only supports external linking
+	if ld.HEADTYPE == obj.Hdarwin {
+		ld.Linkmode = ld.LinkExternal
+	}
+
+	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)))
+		}
+	case obj.Hlinux, obj.Hdarwin:
+		break
+	}
+
+	switch ld.HEADTYPE {
+	default:
+		ld.Exitf("unknown -H option: %v", ld.HEADTYPE)
+
+	case obj.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 obj.Hlinux: /* arm64 elf */
+		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 obj.Hdarwin: /* apple MACH */
+		ld.Debug['w'] = 1 // disable DWARF generation
+		ld.Machoinit()
+		ld.HEADR = ld.INITIAL_MACHO_HEADR
+		if ld.INITTEXT == -1 {
+			ld.INITTEXT = 4096 + int64(ld.HEADR)
+		}
+		if ld.INITDAT == -1 {
+			ld.INITDAT = 0
+		}
+		if ld.INITRND == -1 {
+			ld.INITRND = 4096
+		}
+
+	case obj.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/link/internal/ld/ar.go b/src/cmd/link/internal/ld/ar.go
new file mode 100644
index 0000000..0e59016
--- /dev/null
+++ b/src/cmd/link/internal/ld/ar.go
@@ -0,0 +1,52 @@
+// Inferno utils/include/ar.h
+// http://code.google.com/p/inferno-os/source/browse/utils/include/ar.h
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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 ld
+
+const (
+	SARMAG  = 8
+	SARNAME = 16
+	SAR_HDR = 16 + 44
+)
+
+const (
+	ARMAG  = "!<arch>\n"
+	ARFMAG = "`\n"
+)
+
+type ArHdr struct {
+	name string
+	date string
+	uid  string
+	gid  string
+	mode string
+	size string
+	fmag string
+}
diff --git a/src/cmd/link/internal/ld/arch.go b/src/cmd/link/internal/ld/arch.go
new file mode 100644
index 0000000..1b8e1b1
--- /dev/null
+++ b/src/cmd/link/internal/ld/arch.go
@@ -0,0 +1,70 @@
+// 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 ld
+
+import "encoding/binary"
+
+var Linkarm = LinkArch{
+	ByteOrder: binary.LittleEndian,
+	Name:      "arm",
+	Thechar:   '5',
+	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',
+	Minlc:     1,
+	Ptrsize:   8,
+	Regsize:   8,
+}
+
+var Linkamd64p32 = LinkArch{
+	ByteOrder: binary.LittleEndian,
+	Name:      "amd64p32",
+	Thechar:   '6',
+	Minlc:     1,
+	Ptrsize:   4,
+	Regsize:   8,
+}
+
+var Link386 = LinkArch{
+	ByteOrder: binary.LittleEndian,
+	Name:      "386",
+	Thechar:   '8',
+	Minlc:     1,
+	Ptrsize:   4,
+	Regsize:   4,
+}
+
+var Linkppc64 = LinkArch{
+	ByteOrder: binary.BigEndian,
+	Name:      "ppc64",
+	Thechar:   '9',
+	Minlc:     4,
+	Ptrsize:   8,
+	Regsize:   8,
+}
+
+var Linkppc64le = LinkArch{
+	ByteOrder: binary.LittleEndian,
+	Name:      "ppc64le",
+	Thechar:   '9',
+	Minlc:     4,
+	Ptrsize:   8,
+	Regsize:   8,
+}
diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go
new file mode 100644
index 0000000..55b12e5
--- /dev/null
+++ b/src/cmd/link/internal/ld/data.go
@@ -0,0 +1,1764 @@
+// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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 ld
+
+import (
+	"cmd/internal/gcprog"
+	"cmd/internal/obj"
+	"fmt"
+	"log"
+	"os"
+	"strconv"
+	"strings"
+)
+
+func Symgrow(ctxt *Link, s *LSym, siz int64) {
+	if int64(int(siz)) != siz {
+		log.Fatalf("symgrow size %d too long", siz)
+	}
+	if int64(len(s.P)) >= siz {
+		return
+	}
+	for cap(s.P) < int(siz) {
+		s.P = append(s.P[:len(s.P)], 0)
+	}
+	s.P = s.P[:siz]
+}
+
+func Addrel(s *LSym) *Reloc {
+	s.R = append(s.R, Reloc{})
+	return &s.R[len(s.R)-1]
+}
+
+func setuintxx(ctxt *Link, s *LSym, off int64, v uint64, wid int64) int64 {
+	if s.Type == 0 {
+		s.Type = obj.SDATA
+	}
+	s.Reachable = true
+	if s.Size < off+wid {
+		s.Size = off + wid
+		Symgrow(ctxt, s, s.Size)
+	}
+
+	switch wid {
+	case 1:
+		s.P[off] = uint8(v)
+	case 2:
+		ctxt.Arch.ByteOrder.PutUint16(s.P[off:], uint16(v))
+	case 4:
+		ctxt.Arch.ByteOrder.PutUint32(s.P[off:], uint32(v))
+	case 8:
+		ctxt.Arch.ByteOrder.PutUint64(s.P[off:], uint64(v))
+	}
+
+	return off + wid
+}
+
+func adduintxx(ctxt *Link, s *LSym, v uint64, wid int) int64 {
+	off := s.Size
+	setuintxx(ctxt, s, off, v, int64(wid))
+	return off
+}
+
+func Adduint8(ctxt *Link, s *LSym, v uint8) int64 {
+	return adduintxx(ctxt, s, uint64(v), 1)
+}
+
+func Adduint16(ctxt *Link, s *LSym, v uint16) int64 {
+	return adduintxx(ctxt, s, uint64(v), 2)
+}
+
+func Adduint32(ctxt *Link, s *LSym, v uint32) int64 {
+	return adduintxx(ctxt, s, uint64(v), 4)
+}
+
+func Adduint64(ctxt *Link, s *LSym, v uint64) int64 {
+	return adduintxx(ctxt, s, v, 8)
+}
+
+func adduint(ctxt *Link, s *LSym, v uint64) int64 {
+	return adduintxx(ctxt, s, v, Thearch.Intsize)
+}
+
+func setuint8(ctxt *Link, s *LSym, r int64, v uint8) int64 {
+	return setuintxx(ctxt, s, r, uint64(v), 1)
+}
+
+func setuint32(ctxt *Link, s *LSym, r int64, v uint32) int64 {
+	return setuintxx(ctxt, s, r, uint64(v), 4)
+}
+
+func Addaddrplus(ctxt *Link, s *LSym, t *LSym, add int64) int64 {
+	if s.Type == 0 {
+		s.Type = obj.SDATA
+	}
+	s.Reachable = true
+	i := s.Size
+	s.Size += int64(ctxt.Arch.Ptrsize)
+	Symgrow(ctxt, s, s.Size)
+	r := Addrel(s)
+	r.Sym = t
+	r.Off = int32(i)
+	r.Siz = uint8(ctxt.Arch.Ptrsize)
+	r.Type = obj.R_ADDR
+	r.Add = add
+	return i + int64(r.Siz)
+}
+
+func Addpcrelplus(ctxt *Link, s *LSym, t *LSym, add int64) int64 {
+	if s.Type == 0 {
+		s.Type = obj.SDATA
+	}
+	s.Reachable = true
+	i := s.Size
+	s.Size += 4
+	Symgrow(ctxt, s, s.Size)
+	r := Addrel(s)
+	r.Sym = t
+	r.Off = int32(i)
+	r.Add = add
+	r.Type = obj.R_PCREL
+	r.Siz = 4
+	return i + int64(r.Siz)
+}
+
+func Addaddr(ctxt *Link, s *LSym, t *LSym) int64 {
+	return Addaddrplus(ctxt, s, t, 0)
+}
+
+func setaddrplus(ctxt *Link, s *LSym, off int64, t *LSym, add int64) int64 {
+	if s.Type == 0 {
+		s.Type = obj.SDATA
+	}
+	s.Reachable = true
+	if off+int64(ctxt.Arch.Ptrsize) > s.Size {
+		s.Size = off + int64(ctxt.Arch.Ptrsize)
+		Symgrow(ctxt, s, s.Size)
+	}
+
+	r := Addrel(s)
+	r.Sym = t
+	r.Off = int32(off)
+	r.Siz = uint8(ctxt.Arch.Ptrsize)
+	r.Type = obj.R_ADDR
+	r.Add = add
+	return off + int64(r.Siz)
+}
+
+func setaddr(ctxt *Link, s *LSym, off int64, t *LSym) int64 {
+	return setaddrplus(ctxt, s, off, t, 0)
+}
+
+func addsize(ctxt *Link, s *LSym, t *LSym) int64 {
+	if s.Type == 0 {
+		s.Type = obj.SDATA
+	}
+	s.Reachable = true
+	i := s.Size
+	s.Size += int64(ctxt.Arch.Ptrsize)
+	Symgrow(ctxt, s, s.Size)
+	r := Addrel(s)
+	r.Sym = t
+	r.Off = int32(i)
+	r.Siz = uint8(ctxt.Arch.Ptrsize)
+	r.Type = obj.R_SIZE
+	return i + int64(r.Siz)
+}
+
+func addaddrplus4(ctxt *Link, s *LSym, t *LSym, add int64) int64 {
+	if s.Type == 0 {
+		s.Type = obj.SDATA
+	}
+	s.Reachable = true
+	i := s.Size
+	s.Size += 4
+	Symgrow(ctxt, s, s.Size)
+	r := Addrel(s)
+	r.Sym = t
+	r.Off = int32(i)
+	r.Siz = 4
+	r.Type = obj.R_ADDR
+	r.Add = add
+	return i + int64(r.Siz)
+}
+
+/*
+ * divide-and-conquer list-link
+ * sort of LSym* structures.
+ * Used for the data block.
+ */
+func datcmp(s1 *LSym, s2 *LSym) int {
+	if s1.Type != s2.Type {
+		return int(s1.Type) - int(s2.Type)
+	}
+
+	// For ppc64, we want to interleave the .got and .toc sections
+	// from input files.  Both are type SELFGOT, so in that case
+	// fall through to the name comparison (conveniently, .got
+	// sorts before .toc).
+	if s1.Type != obj.SELFGOT && s1.Size != s2.Size {
+		if s1.Size < s2.Size {
+			return -1
+		}
+		return +1
+	}
+
+	return stringsCompare(s1.Name, s2.Name)
+}
+
+func listnextp(s *LSym) **LSym {
+	return &s.Next
+}
+
+func listsubp(s *LSym) **LSym {
+	return &s.Sub
+}
+
+func listsort(l *LSym, cmp func(*LSym, *LSym) int, nextp func(*LSym) **LSym) *LSym {
+	if l == nil || *nextp(l) == nil {
+		return l
+	}
+
+	l1 := l
+	l2 := l
+	for {
+		l2 = *nextp(l2)
+		if l2 == nil {
+			break
+		}
+		l2 = *nextp(l2)
+		if l2 == nil {
+			break
+		}
+		l1 = *nextp(l1)
+	}
+
+	l2 = *nextp(l1)
+	*nextp(l1) = nil
+	l1 = listsort(l, cmp, nextp)
+	l2 = listsort(l2, cmp, nextp)
+
+	/* set up lead element */
+	if cmp(l1, l2) < 0 {
+		l = l1
+		l1 = *nextp(l1)
+	} else {
+		l = l2
+		l2 = *nextp(l2)
+	}
+
+	le := l
+
+	for {
+		if l1 == nil {
+			for l2 != nil {
+				*nextp(le) = l2
+				le = l2
+				l2 = *nextp(l2)
+			}
+
+			*nextp(le) = nil
+			break
+		}
+
+		if l2 == nil {
+			for l1 != nil {
+				*nextp(le) = l1
+				le = l1
+				l1 = *nextp(l1)
+			}
+
+			break
+		}
+
+		if cmp(l1, l2) < 0 {
+			*nextp(le) = l1
+			le = l1
+			l1 = *nextp(l1)
+		} else {
+			*nextp(le) = l2
+			le = l2
+			l2 = *nextp(l2)
+		}
+	}
+
+	*nextp(le) = nil
+	return l
+}
+
+func relocsym(s *LSym) {
+	var r *Reloc
+	var rs *LSym
+	var i16 int16
+	var off int32
+	var siz int32
+	var fl int32
+	var o int64
+
+	Ctxt.Cursym = s
+	for ri := int32(0); ri < int32(len(s.R)); ri++ {
+		r = &s.R[ri]
+		r.Done = 1
+		off = r.Off
+		siz = int32(r.Siz)
+		if off < 0 || off+siz > int32(len(s.P)) {
+			Diag("%s: invalid relocation %d+%d not in [%d,%d)", s.Name, off, siz, 0, len(s.P))
+			continue
+		}
+
+		if r.Sym != nil && (r.Sym.Type&(obj.SMASK|obj.SHIDDEN) == 0 || r.Sym.Type&obj.SMASK == obj.SXREF) {
+			// When putting the runtime but not main into a shared library
+			// these symbols are undefined and that's OK.
+			if Buildmode == BuildmodeShared && (r.Sym.Name == "main.main" || r.Sym.Name == "main.init") {
+				r.Sym.Type = obj.SDYNIMPORT
+			} else {
+				Diag("%s: not defined", r.Sym.Name)
+				continue
+			}
+		}
+
+		if r.Type >= 256 {
+			continue
+		}
+		if r.Siz == 0 { // informational relocation - no work to do
+			continue
+		}
+
+		// We need to be able to reference dynimport symbols when linking against
+		// shared libraries, and Solaris needs it always
+		if HEADTYPE != obj.Hsolaris && r.Sym != nil && r.Sym.Type == obj.SDYNIMPORT && !DynlinkingGo() {
+			Diag("unhandled relocation for %s (type %d rtype %d)", r.Sym.Name, r.Sym.Type, r.Type)
+		}
+		if r.Sym != nil && r.Sym.Type != obj.STLSBSS && !r.Sym.Reachable {
+			Diag("unreachable sym in relocation: %s %s", s.Name, r.Sym.Name)
+		}
+
+		// Android emulates runtime.tlsg as a regular variable.
+		if r.Type == obj.R_TLS && goos == "android" {
+			r.Type = obj.R_ADDR
+		}
+
+		switch r.Type {
+		default:
+			o = 0
+			if Thearch.Archreloc(r, s, &o) < 0 {
+				Diag("unknown reloc %d", r.Type)
+			}
+
+		case obj.R_TLS:
+			if Linkmode == LinkExternal && Iself && HEADTYPE != obj.Hopenbsd {
+				r.Done = 0
+				r.Sym = Ctxt.Tlsg
+				r.Xsym = Ctxt.Tlsg
+				r.Xadd = r.Add
+				o = r.Add
+				break
+			}
+			if Linkmode == LinkInternal && Iself && Thearch.Thechar == '5' {
+				// On ELF ARM, the thread pointer is 8 bytes before
+				// the start of the thread-local data block, so add 8
+				// to the actual TLS offset (r->sym->value).
+				// This 8 seems to be a fundamental constant of
+				// ELF on ARM (or maybe Glibc on ARM); it is not
+				// related to the fact that our own TLS storage happens
+				// to take up 8 bytes.
+				o = 8 + r.Sym.Value
+
+				break
+			}
+
+			r.Done = 0
+			o = 0
+			if Thearch.Thechar != '6' {
+				o = r.Add
+			}
+
+		case obj.R_TLS_LE:
+			if Linkmode == LinkExternal && Iself && HEADTYPE != obj.Hopenbsd {
+				r.Done = 0
+				r.Sym = Ctxt.Tlsg
+				r.Xsym = Ctxt.Tlsg
+				r.Xadd = r.Add
+				o = 0
+				if Thearch.Thechar != '6' {
+					o = r.Add
+				}
+				break
+			}
+
+			if Iself || Ctxt.Headtype == obj.Hplan9 || Ctxt.Headtype == obj.Hdarwin {
+				o = int64(Ctxt.Tlsoffset) + r.Add
+			} else if Ctxt.Headtype == obj.Hwindows {
+				o = r.Add
+			} else {
+				log.Fatalf("unexpected R_TLS_LE relocation for %s", Headstr(Ctxt.Headtype))
+			}
+
+		case obj.R_TLS_IE:
+			if Linkmode == LinkExternal && Iself && HEADTYPE != obj.Hopenbsd {
+				r.Done = 0
+				r.Sym = Ctxt.Tlsg
+				r.Xsym = Ctxt.Tlsg
+				r.Xadd = r.Add
+				o = 0
+				if Thearch.Thechar != '6' {
+					o = r.Add
+				}
+				break
+			}
+			log.Fatalf("cannot handle R_TLS_IE when linking internally")
+
+		case obj.R_ADDR:
+			if Linkmode == LinkExternal && r.Sym.Type != obj.SCONST {
+				r.Done = 0
+
+				// set up addend for eventual relocation via outer symbol.
+				rs = r.Sym
+
+				r.Xadd = r.Add
+				for rs.Outer != nil {
+					r.Xadd += Symaddr(rs) - Symaddr(rs.Outer)
+					rs = rs.Outer
+				}
+
+				if rs.Type != obj.SHOSTOBJ && rs.Type != obj.SDYNIMPORT && rs.Sect == nil {
+					Diag("missing section for %s", rs.Name)
+				}
+				r.Xsym = rs
+
+				o = r.Xadd
+				if Iself {
+					if Thearch.Thechar == '6' {
+						o = 0
+					}
+				} else if HEADTYPE == obj.Hdarwin {
+					// ld64 for arm64 has a bug where if the address pointed to by o exists in the
+					// symbol table (dynid >= 0), or is inside a symbol that exists in the symbol
+					// table, then it will add o twice into the relocated value.
+					// The workaround is that on arm64 don't ever add symaddr to o and always use
+					// extern relocation by requiring rs->dynid >= 0.
+					if rs.Type != obj.SHOSTOBJ {
+						if Thearch.Thechar == '7' && rs.Dynid < 0 {
+							Diag("R_ADDR reloc to %s+%d is not supported on darwin/arm64", rs.Name, o)
+						}
+						if Thearch.Thechar != '7' {
+							o += Symaddr(rs)
+						}
+					}
+				} else if HEADTYPE == obj.Hwindows {
+					// nothing to do
+				} else {
+					Diag("unhandled pcrel relocation for %s", headstring)
+				}
+
+				break
+			}
+
+			o = Symaddr(r.Sym) + r.Add
+
+			// On amd64, 4-byte offsets will be sign-extended, so it is impossible to
+			// access more than 2GB of static data; fail at link time is better than
+			// fail at runtime. See https://golang.org/issue/7980.
+			// Instead of special casing only amd64, we treat this as an error on all
+			// 64-bit architectures so as to be future-proof.
+			if int32(o) < 0 && Thearch.Ptrsize > 4 && siz == 4 {
+				Diag("non-pc-relative relocation address is too big: %#x (%#x + %#x)", uint64(o), Symaddr(r.Sym), r.Add)
+				errorexit()
+			}
+
+			// r->sym can be null when CALL $(constant) is transformed from absolute PC to relative PC call.
+		case obj.R_CALL, obj.R_GOTPCREL, obj.R_PCREL:
+			if Linkmode == LinkExternal && r.Sym != nil && r.Sym.Type != obj.SCONST && (r.Sym.Sect != Ctxt.Cursym.Sect || r.Type == obj.R_GOTPCREL) {
+				r.Done = 0
+
+				// set up addend for eventual relocation via outer symbol.
+				rs = r.Sym
+
+				r.Xadd = r.Add
+				for rs.Outer != nil {
+					r.Xadd += Symaddr(rs) - Symaddr(rs.Outer)
+					rs = rs.Outer
+				}
+
+				r.Xadd -= int64(r.Siz) // relative to address after the relocated chunk
+				if rs.Type != obj.SHOSTOBJ && rs.Type != obj.SDYNIMPORT && rs.Sect == nil {
+					Diag("missing section for %s", rs.Name)
+				}
+				r.Xsym = rs
+
+				o = r.Xadd
+				if Iself {
+					if Thearch.Thechar == '6' {
+						o = 0
+					}
+				} else if HEADTYPE == obj.Hdarwin {
+					if r.Type == obj.R_CALL {
+						if rs.Type != obj.SHOSTOBJ {
+							o += int64(uint64(Symaddr(rs)) - rs.Sect.Vaddr)
+						}
+						o -= int64(r.Off) // relative to section offset, not symbol
+					} else {
+						o += int64(r.Siz)
+					}
+				} else if HEADTYPE == obj.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.Vaddr - PEBASE)
+				} else {
+					Diag("unhandled pcrel relocation for %s", headstring)
+				}
+
+				break
+			}
+
+			o = 0
+			if r.Sym != nil {
+				o += Symaddr(r.Sym)
+			}
+
+			// NOTE: The (int32) cast on the next line works around a bug in Plan 9's 8c
+			// compiler. The expression s->value + r->off + r->siz is int32 + int32 +
+			// uchar, and Plan 9 8c incorrectly treats the expression as type uint32
+			// instead of int32, causing incorrect values when sign extended for adding
+			// to o. The bug only occurs on Plan 9, because this C program is compiled by
+			// the standard host compiler (gcc on most other systems).
+			o += r.Add - (s.Value + int64(r.Off) + int64(int32(r.Siz)))
+
+		case obj.R_SIZE:
+			o = r.Sym.Size + r.Add
+		}
+
+		if r.Variant != RV_NONE {
+			o = Thearch.Archrelocvariant(r, s, o)
+		}
+
+		if false {
+			nam := "<nil>"
+			if r.Sym != nil {
+				nam = r.Sym.Name
+			}
+			fmt.Printf("relocate %s %#x (%#x+%#x, size %d) => %s %#x +%#x [type %d/%d, %x]\n", s.Name, s.Value+int64(off), s.Value, r.Off, r.Siz, nam, Symaddr(r.Sym), r.Add, r.Type, r.Variant, o)
+		}
+		switch siz {
+		default:
+			Ctxt.Cursym = s
+			Diag("bad reloc size %#x for %s", uint32(siz), r.Sym.Name)
+			fallthrough
+
+			// TODO(rsc): Remove.
+		case 1:
+			s.P[off] = byte(int8(o))
+
+		case 2:
+			if o != int64(int16(o)) {
+				Diag("relocation address is too big: %#x", o)
+			}
+			i16 = int16(o)
+			Ctxt.Arch.ByteOrder.PutUint16(s.P[off:], uint16(i16))
+
+		case 4:
+			if r.Type == obj.R_PCREL || r.Type == obj.R_CALL {
+				if o != int64(int32(o)) {
+					Diag("pc-relative relocation address is too big: %#x", o)
+				}
+			} else {
+				if o != int64(int32(o)) && o != int64(uint32(o)) {
+					Diag("non-pc-relative relocation address is too big: %#x", uint64(o))
+				}
+			}
+
+			fl = int32(o)
+			Ctxt.Arch.ByteOrder.PutUint32(s.P[off:], uint32(fl))
+
+		case 8:
+			Ctxt.Arch.ByteOrder.PutUint64(s.P[off:], uint64(o))
+		}
+	}
+}
+
+func reloc() {
+	if Debug['v'] != 0 {
+		fmt.Fprintf(&Bso, "%5.2f reloc\n", obj.Cputime())
+	}
+	Bso.Flush()
+
+	for s := Ctxt.Textp; s != nil; s = s.Next {
+		relocsym(s)
+	}
+	for s := datap; s != nil; s = s.Next {
+		relocsym(s)
+	}
+}
+
+func dynrelocsym(s *LSym) {
+	if HEADTYPE == obj.Hwindows && Linkmode != LinkExternal {
+		rel := Linklookup(Ctxt, ".rel", 0)
+		if s == rel {
+			return
+		}
+		var r *Reloc
+		var targ *LSym
+		for ri := 0; ri < len(s.R); ri++ {
+			r = &s.R[ri]
+			targ = r.Sym
+			if targ == nil {
+				continue
+			}
+			if !targ.Reachable {
+				Diag("internal inconsistency: dynamic symbol %s is not reachable.", targ.Name)
+			}
+			if r.Sym.Plt == -2 && r.Sym.Got != -2 { // make dynimport JMP table for PE object files.
+				targ.Plt = int32(rel.Size)
+				r.Sym = rel
+				r.Add = int64(targ.Plt)
+
+				// jmp *addr
+				if Thearch.Thechar == '8' {
+					Adduint8(Ctxt, rel, 0xff)
+					Adduint8(Ctxt, rel, 0x25)
+					Addaddr(Ctxt, rel, targ)
+					Adduint8(Ctxt, rel, 0x90)
+					Adduint8(Ctxt, rel, 0x90)
+				} else {
+					Adduint8(Ctxt, rel, 0xff)
+					Adduint8(Ctxt, rel, 0x24)
+					Adduint8(Ctxt, rel, 0x25)
+					addaddrplus4(Ctxt, rel, targ, 0)
+					Adduint8(Ctxt, rel, 0x90)
+				}
+			} else if r.Sym.Plt >= 0 {
+				r.Sym = rel
+				r.Add = int64(targ.Plt)
+			}
+		}
+
+		return
+	}
+
+	var r *Reloc
+	for ri := 0; ri < len(s.R); ri++ {
+		r = &s.R[ri]
+		if r.Sym != nil && r.Sym.Type == obj.SDYNIMPORT || r.Type >= 256 {
+			if r.Sym != nil && !r.Sym.Reachable {
+				Diag("internal inconsistency: dynamic symbol %s is not reachable.", r.Sym.Name)
+			}
+			Thearch.Adddynrel(s, r)
+		}
+	}
+}
+
+func dynreloc() {
+	// -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 != obj.Hwindows {
+		return
+	}
+	if Debug['v'] != 0 {
+		fmt.Fprintf(&Bso, "%5.2f reloc\n", obj.Cputime())
+	}
+	Bso.Flush()
+
+	for s := Ctxt.Textp; s != nil; s = s.Next {
+		dynrelocsym(s)
+	}
+	for s := datap; s != nil; s = s.Next {
+		dynrelocsym(s)
+	}
+	if Iself {
+		elfdynhash()
+	}
+}
+
+func blk(start *LSym, addr int64, size int64) {
+	var sym *LSym
+
+	for sym = start; sym != nil; sym = sym.Next {
+		if sym.Type&obj.SSUB == 0 && sym.Value >= addr {
+			break
+		}
+	}
+
+	eaddr := addr + size
+	var ep []byte
+	var p []byte
+	for ; sym != nil; sym = sym.Next {
+		if sym.Type&obj.SSUB != 0 {
+			continue
+		}
+		if sym.Value >= eaddr {
+			break
+		}
+		Ctxt.Cursym = sym
+		if sym.Value < addr {
+			Diag("phase error: addr=%#x but sym=%#x type=%d", int64(addr), int64(sym.Value), sym.Type)
+			errorexit()
+		}
+
+		for ; addr < sym.Value; addr++ {
+			Cput(0)
+		}
+		p = sym.P
+		ep = p[len(sym.P):]
+		for -cap(p) < -cap(ep) {
+			Cput(uint8(p[0]))
+			p = p[1:]
+		}
+		addr += int64(len(sym.P))
+		for ; addr < sym.Value+sym.Size; addr++ {
+			Cput(0)
+		}
+		if addr != sym.Value+sym.Size {
+			Diag("phase error: addr=%#x value+size=%#x", int64(addr), int64(sym.Value)+sym.Size)
+			errorexit()
+		}
+
+		if sym.Value+sym.Size >= eaddr {
+			break
+		}
+	}
+
+	for ; addr < eaddr; addr++ {
+		Cput(0)
+	}
+	Cflush()
+}
+
+func Codeblk(addr int64, size int64) {
+	if Debug['a'] != 0 {
+		fmt.Fprintf(&Bso, "codeblk [%#x,%#x) at offset %#x\n", addr, addr+size, Cpos())
+	}
+
+	blk(Ctxt.Textp, addr, size)
+
+	/* again for printing */
+	if Debug['a'] == 0 {
+		return
+	}
+
+	var sym *LSym
+	for sym = Ctxt.Textp; sym != nil; sym = sym.Next {
+		if !sym.Reachable {
+			continue
+		}
+		if sym.Value >= addr {
+			break
+		}
+	}
+
+	eaddr := addr + size
+	var q []byte
+	for ; sym != nil; sym = sym.Next {
+		if !sym.Reachable {
+			continue
+		}
+		if sym.Value >= eaddr {
+			break
+		}
+
+		if addr < sym.Value {
+			fmt.Fprintf(&Bso, "%-20s %.8x|", "_", uint64(int64(addr)))
+			for ; addr < sym.Value; addr++ {
+				fmt.Fprintf(&Bso, " %.2x", 0)
+			}
+			fmt.Fprintf(&Bso, "\n")
+		}
+
+		fmt.Fprintf(&Bso, "%.6x\t%-20s\n", uint64(int64(addr)), sym.Name)
+		q = sym.P
+
+		for len(q) >= 16 {
+			fmt.Fprintf(&Bso, "%.6x\t% x\n", uint64(addr), q[:16])
+			addr += 16
+			q = q[16:]
+		}
+
+		if len(q) > 0 {
+			fmt.Fprintf(&Bso, "%.6x\t% x\n", uint64(addr), q)
+			addr += int64(len(q))
+		}
+	}
+
+	if addr < eaddr {
+		fmt.Fprintf(&Bso, "%-20s %.8x|", "_", uint64(int64(addr)))
+		for ; addr < eaddr; addr++ {
+			fmt.Fprintf(&Bso, " %.2x", 0)
+		}
+	}
+
+	Bso.Flush()
+}
+
+func Datblk(addr int64, size int64) {
+	if Debug['a'] != 0 {
+		fmt.Fprintf(&Bso, "datblk [%#x,%#x) at offset %#x\n", addr, addr+size, Cpos())
+	}
+
+	blk(datap, addr, size)
+
+	/* again for printing */
+	if Debug['a'] == 0 {
+		return
+	}
+
+	var sym *LSym
+	for sym = datap; sym != nil; sym = sym.Next {
+		if sym.Value >= addr {
+			break
+		}
+	}
+
+	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
+		}
+		if addr < sym.Value {
+			fmt.Fprintf(&Bso, "\t%.8x| 00 ...\n", uint64(addr))
+			addr = sym.Value
+		}
+
+		fmt.Fprintf(&Bso, "%s\n\t%.8x|", sym.Name, uint(addr))
+		p = sym.P
+		ep = p[len(sym.P):]
+		for -cap(p) < -cap(ep) {
+			if -cap(p) > -cap(sym.P) && int(-cap(p)+cap(sym.P))%16 == 0 {
+				fmt.Fprintf(&Bso, "\n\t%.8x|", uint(addr+int64(-cap(p)+cap(sym.P))))
+			}
+			fmt.Fprintf(&Bso, " %.2x", p[0])
+			p = p[1:]
+		}
+
+		addr += int64(len(sym.P))
+		for ; addr < sym.Value+sym.Size; addr++ {
+			fmt.Fprintf(&Bso, " %.2x", 0)
+		}
+		fmt.Fprintf(&Bso, "\n")
+
+		if Linkmode == LinkExternal {
+			for i = 0; i < int64(len(sym.R)); i++ {
+				r = &sym.R[i]
+				rsname = ""
+				if r.Sym != nil {
+					rsname = r.Sym.Name
+				}
+				typ = "?"
+				switch r.Type {
+				case obj.R_ADDR:
+					typ = "addr"
+
+				case obj.R_PCREL:
+					typ = "pcrel"
+
+				case obj.R_CALL:
+					typ = "call"
+				}
+
+				fmt.Fprintf(&Bso, "\treloc %.8x/%d %s %s+%#x [%#x]\n", uint(sym.Value+int64(r.Off)), r.Siz, typ, rsname, int64(r.Add), int64(r.Sym.Value+r.Add))
+			}
+		}
+	}
+
+	if addr < eaddr {
+		fmt.Fprintf(&Bso, "\t%.8x| 00 ...\n", uint(addr))
+	}
+	fmt.Fprintf(&Bso, "\t%.8x|\n", uint(eaddr))
+}
+
+func strnput(s string, n int) {
+	for ; n > 0 && s != ""; s = s[1:] {
+		Cput(uint8(s[0]))
+		n--
+	}
+
+	for n > 0 {
+		Cput(0)
+		n--
+	}
+}
+
+var strdata []*LSym
+
+func addstrdata1(arg string) {
+	i := strings.Index(arg, "=")
+	if i < 0 {
+		Exitf("-X flag requires argument of the form importpath.name=value")
+	}
+	addstrdata(arg[:i], arg[i+1:])
+}
+
+func addstrdata(name string, value string) {
+	p := fmt.Sprintf("%s.str", name)
+	sp := Linklookup(Ctxt, p, 0)
+
+	Addstring(sp, value)
+	sp.Type = obj.SRODATA
+
+	s := Linklookup(Ctxt, name, 0)
+	s.Size = 0
+	s.Dupok = 1
+	reachable := s.Reachable
+	Addaddr(Ctxt, s, sp)
+	adduintxx(Ctxt, s, uint64(len(value)), Thearch.Ptrsize)
+
+	// addstring, addaddr, etc., mark the symbols as reachable.
+	// In this case that is not necessarily true, so stick to what
+	// we know before entering this function.
+	s.Reachable = reachable
+
+	strdata = append(strdata, s)
+
+	sp.Reachable = reachable
+}
+
+func checkstrdata() {
+	for _, s := range strdata {
+		if s.Type == obj.STEXT {
+			Diag("cannot use -X with text symbol %s", s.Name)
+		} else if s.Gotype != nil && s.Gotype.Name != "type.string" {
+			Diag("cannot use -X with non-string symbol %s", s.Name)
+		}
+	}
+}
+
+func Addstring(s *LSym, str string) int64 {
+	if s.Type == 0 {
+		s.Type = obj.SNOPTRDATA
+	}
+	s.Reachable = true
+	r := int32(s.Size)
+	n := len(str) + 1
+	if s.Name == ".shstrtab" {
+		elfsetstring(str, int(r))
+	}
+	Symgrow(Ctxt, s, int64(r)+int64(n))
+	copy(s.P[r:], str)
+	s.P[int(r)+len(str)] = 0
+	s.Size += int64(n)
+	return int64(r)
+}
+
+// addgostring adds str, as a Go string value, to s. symname is the name of the
+// symbol used to define the string data and must be unique per linked object.
+func addgostring(s *LSym, symname, str string) {
+	sym := Linklookup(Ctxt, symname, 0)
+	if sym.Type != obj.Sxxx {
+		Diag("duplicate symname in addgostring: %s", symname)
+	}
+	sym.Reachable = true
+	sym.Local = true
+	sym.Type = obj.SRODATA
+	sym.Size = int64(len(str))
+	sym.P = []byte(str)
+	Addaddr(Ctxt, s, sym)
+	adduint(Ctxt, s, uint64(len(str)))
+}
+
+func addinitarrdata(s *LSym) {
+	p := s.Name + ".ptr"
+	sp := Linklookup(Ctxt, p, 0)
+	sp.Type = obj.SINITARR
+	sp.Size = 0
+	sp.Dupok = 1
+	Addaddr(Ctxt, sp, s)
+}
+
+func dosymtype() {
+	for s := Ctxt.Allsym; s != nil; s = s.Allsym {
+		if len(s.P) > 0 {
+			if s.Type == obj.SBSS {
+				s.Type = obj.SDATA
+			}
+			if s.Type == obj.SNOPTRBSS {
+				s.Type = obj.SNOPTRDATA
+			}
+		}
+		// Create a new entry in the .init_array section that points to the
+		// library initializer function.
+		switch Buildmode {
+		case BuildmodeCArchive, BuildmodeCShared:
+			if s.Name == INITENTRY {
+				addinitarrdata(s)
+			}
+		}
+	}
+}
+
+func symalign(s *LSym) int32 {
+	if s.Align != 0 {
+		return s.Align
+	}
+
+	align := int32(Thearch.Maxalign)
+	for int64(align) > s.Size && align > 1 {
+		align >>= 1
+	}
+	if align < s.Align {
+		align = s.Align
+	}
+	return align
+}
+
+func aligndatsize(datsize int64, s *LSym) int64 {
+	return Rnd(datsize, int64(symalign(s)))
+}
+
+// maxalign returns the maximum required alignment for
+// the list of symbols s; the list stops when s->type exceeds type.
+func maxalign(s *LSym, type_ int) int32 {
+	var align int32
+
+	max := int32(0)
+	for ; s != nil && int(s.Type) <= type_; s = s.Next {
+		align = symalign(s)
+		if max < align {
+			max = align
+		}
+	}
+
+	return max
+}
+
+const debugGCProg = false
+
+type GCProg struct {
+	sym *LSym
+	w   gcprog.Writer
+}
+
+func (p *GCProg) Init(name string) {
+	p.sym = Linklookup(Ctxt, name, 0)
+	p.w.Init(p.writeByte)
+	if debugGCProg {
+		fmt.Fprintf(os.Stderr, "ld: start GCProg %s\n", name)
+		p.w.Debug(os.Stderr)
+	}
+}
+
+func (p *GCProg) writeByte(x byte) {
+	Adduint8(Ctxt, p.sym, x)
+}
+
+func (p *GCProg) End(size int64) {
+	p.w.ZeroUntil(size / int64(Thearch.Ptrsize))
+	p.w.End()
+	if debugGCProg {
+		fmt.Fprintf(os.Stderr, "ld: end GCProg\n")
+	}
+}
+
+func (p *GCProg) AddSym(s *LSym) {
+	typ := s.Gotype
+	// Things without pointers should be in SNOPTRDATA or SNOPTRBSS;
+	// everything we see should have pointers and should therefore have a type.
+	if typ == nil {
+		Diag("missing Go type information for global symbol: %s size %d", s.Name, int(s.Size))
+		return
+	}
+
+	ptrsize := int64(Thearch.Ptrsize)
+	nptr := decodetype_ptrdata(typ) / ptrsize
+
+	if debugGCProg {
+		fmt.Fprintf(os.Stderr, "gcprog sym: %s at %d (ptr=%d+%d)\n", s.Name, s.Value, s.Value/ptrsize, nptr)
+	}
+
+	if decodetype_usegcprog(typ) == 0 {
+		// Copy pointers from mask into program.
+		mask := decodetype_gcmask(typ)
+		for i := int64(0); i < nptr; i++ {
+			if (mask[i/8]>>uint(i%8))&1 != 0 {
+				p.w.Ptr(s.Value/ptrsize + i)
+			}
+		}
+		return
+	}
+
+	// Copy program.
+	prog := decodetype_gcprog(typ)
+	p.w.ZeroUntil(s.Value / ptrsize)
+	p.w.Append(prog[4:], nptr)
+}
+
+func growdatsize(datsizep *int64, s *LSym) {
+	datsize := *datsizep
+	const cutoff int64 = 2e9 // 2 GB (or so; looks better in errors than 2^31)
+	switch {
+	case s.Size < 0:
+		Diag("%s: negative size (%d bytes)", s.Name, s.Size)
+	case s.Size > cutoff:
+		Diag("%s: symbol too large (%d bytes)", s.Name, s.Size)
+	case datsize <= cutoff && datsize+s.Size > cutoff:
+		Diag("%s: too much data (over %d bytes)", s.Name, cutoff)
+	}
+	*datsizep = datsize + s.Size
+}
+
+func dodata() {
+	if Debug['v'] != 0 {
+		fmt.Fprintf(&Bso, "%5.2f dodata\n", obj.Cputime())
+	}
+	Bso.Flush()
+
+	var last *LSym
+	datap = nil
+
+	for s := Ctxt.Allsym; s != nil; s = s.Allsym {
+		if !s.Reachable || s.Special != 0 {
+			continue
+		}
+		if obj.STEXT < s.Type && s.Type < obj.SXREF {
+			if s.Onlist != 0 {
+				log.Fatalf("symbol %s listed multiple times", s.Name)
+			}
+			s.Onlist = 1
+			if last == nil {
+				datap = s
+			} else {
+				last.Next = s
+			}
+			s.Next = nil
+			last = s
+		}
+	}
+
+	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))
+		}
+	}
+
+	/*
+	 * now that we have the datap list, but before we start
+	 * to assign addresses, record all the necessary
+	 * dynamic relocations.  these will grow the relocation
+	 * symbol, which is itself data.
+	 *
+	 * on darwin, we need the symbol table numbers for dynreloc.
+	 */
+	if HEADTYPE == obj.Hdarwin {
+		machosymorder()
+	}
+	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 {
+			break
+		}
+
+		if s.Type <= obj.STEXT || obj.SXREF <= s.Type {
+			*l = s.Next
+		} else {
+			l = &s.Next
+		}
+	}
+
+	*l = nil
+
+	datap = listsort(datap, datcmp, listnextp)
+
+	if Iself {
+		// Make .rela and .rela.plt contiguous, the ELF ABI requires this
+		// and Solaris actually cares.
+		var relplt *LSym
+		for l = &datap; *l != nil; l = &(*l).Next {
+			if (*l).Name == ".rel.plt" || (*l).Name == ".rela.plt" {
+				relplt = (*l)
+				*l = (*l).Next
+				break
+			}
+		}
+		if relplt != nil {
+			for s = datap; s != nil; s = s.Next {
+				if s.Name == ".rel" || s.Name == ".rela" {
+					relplt.Next = s.Next
+					s.Next = relplt
+				}
+			}
+		}
+	}
+
+	/*
+	 * allocate sections.  list is sorted by type,
+	 * so we can just walk it for each piece we want to emit.
+	 * segdata is processed before segtext, because we need
+	 * to see all symbols in the .data and .bss sections in order
+	 * to generate garbage collection information.
+	 */
+
+	/* begin segdata */
+
+	/* skip symbols belonging to segtext */
+	s = datap
+
+	for ; s != nil && s.Type < obj.SELFSECT; s = s.Next {
+	}
+
+	/* writable ELF sections */
+	datsize := int64(0)
+
+	var sect *Section
+	for ; s != nil && s.Type < obj.SELFGOT; s = s.Next {
+		sect = addsection(&Segdata, s.Name, 06)
+		sect.Align = symalign(s)
+		datsize = Rnd(datsize, int64(sect.Align))
+		sect.Vaddr = uint64(datsize)
+		s.Sect = sect
+		s.Type = obj.SDATA
+		s.Value = int64(uint64(datsize) - sect.Vaddr)
+		growdatsize(&datsize, s)
+		sect.Length = uint64(datsize) - sect.Vaddr
+	}
+
+	/* .got (and .toc on ppc64) */
+	if s.Type == obj.SELFGOT {
+		sect := addsection(&Segdata, ".got", 06)
+		sect.Align = maxalign(s, obj.SELFGOT)
+		datsize = Rnd(datsize, int64(sect.Align))
+		sect.Vaddr = uint64(datsize)
+		var toc *LSym
+		for ; s != nil && s.Type == obj.SELFGOT; s = s.Next {
+			datsize = aligndatsize(datsize, s)
+			s.Sect = sect
+			s.Type = obj.SDATA
+			s.Value = int64(uint64(datsize) - sect.Vaddr)
+
+			// Resolve .TOC. symbol for this object file (ppc64)
+			toc = Linkrlookup(Ctxt, ".TOC.", int(s.Version))
+
+			if toc != nil {
+				toc.Sect = sect
+				toc.Outer = s
+				toc.Sub = s.Sub
+				s.Sub = toc
+
+				toc.Value = 0x8000
+			}
+
+			growdatsize(&datsize, s)
+		}
+
+		sect.Length = uint64(datsize) - sect.Vaddr
+	}
+
+	/* pointer-free data */
+	sect = addsection(&Segdata, ".noptrdata", 06)
+
+	sect.Align = maxalign(s, obj.SINITARR-1)
+	datsize = Rnd(datsize, int64(sect.Align))
+	sect.Vaddr = uint64(datsize)
+	Linklookup(Ctxt, "runtime.noptrdata", 0).Sect = sect
+	Linklookup(Ctxt, "runtime.enoptrdata", 0).Sect = sect
+	for ; s != nil && s.Type < obj.SINITARR; s = s.Next {
+		datsize = aligndatsize(datsize, s)
+		s.Sect = sect
+		s.Type = obj.SDATA
+		s.Value = int64(uint64(datsize) - sect.Vaddr)
+		growdatsize(&datsize, s)
+	}
+
+	sect.Length = uint64(datsize) - sect.Vaddr
+
+	hasinitarr := Linkshared
+
+	/* shared library initializer */
+	switch Buildmode {
+	case BuildmodeCArchive, BuildmodeCShared, BuildmodeShared:
+		hasinitarr = true
+	}
+
+	if hasinitarr {
+		sect := addsection(&Segdata, ".init_array", 06)
+		sect.Align = maxalign(s, obj.SINITARR)
+		datsize = Rnd(datsize, int64(sect.Align))
+		sect.Vaddr = uint64(datsize)
+		for ; s != nil && s.Type == obj.SINITARR; s = s.Next {
+			datsize = aligndatsize(datsize, s)
+			s.Sect = sect
+			s.Value = int64(uint64(datsize) - sect.Vaddr)
+			growdatsize(&datsize, s)
+		}
+
+		sect.Length = uint64(datsize) - sect.Vaddr
+	}
+
+	/* data */
+	sect = addsection(&Segdata, ".data", 06)
+	sect.Align = maxalign(s, obj.SBSS-1)
+	datsize = Rnd(datsize, int64(sect.Align))
+	sect.Vaddr = uint64(datsize)
+	Linklookup(Ctxt, "runtime.data", 0).Sect = sect
+	Linklookup(Ctxt, "runtime.edata", 0).Sect = sect
+	var gc GCProg
+	gc.Init("runtime.gcdata")
+	for ; s != nil && s.Type < obj.SBSS; s = s.Next {
+		if s.Type == obj.SINITARR {
+			Ctxt.Cursym = s
+			Diag("unexpected symbol type %d", s.Type)
+		}
+
+		s.Sect = sect
+		s.Type = obj.SDATA
+		datsize = aligndatsize(datsize, s)
+		s.Value = int64(uint64(datsize) - sect.Vaddr)
+		gc.AddSym(s)
+		growdatsize(&datsize, s)
+	}
+	sect.Length = uint64(datsize) - sect.Vaddr
+	gc.End(int64(sect.Length))
+
+	/* bss */
+	sect = addsection(&Segdata, ".bss", 06)
+	sect.Align = maxalign(s, obj.SNOPTRBSS-1)
+	datsize = Rnd(datsize, int64(sect.Align))
+	sect.Vaddr = uint64(datsize)
+	Linklookup(Ctxt, "runtime.bss", 0).Sect = sect
+	Linklookup(Ctxt, "runtime.ebss", 0).Sect = sect
+	gc = GCProg{}
+	gc.Init("runtime.gcbss")
+	for ; s != nil && s.Type < obj.SNOPTRBSS; s = s.Next {
+		s.Sect = sect
+		datsize = aligndatsize(datsize, s)
+		s.Value = int64(uint64(datsize) - sect.Vaddr)
+		gc.AddSym(s)
+		growdatsize(&datsize, s)
+	}
+	sect.Length = uint64(datsize) - sect.Vaddr
+	gc.End(int64(sect.Length))
+
+	/* pointer-free bss */
+	sect = addsection(&Segdata, ".noptrbss", 06)
+
+	sect.Align = maxalign(s, obj.SNOPTRBSS)
+	datsize = Rnd(datsize, int64(sect.Align))
+	sect.Vaddr = uint64(datsize)
+	Linklookup(Ctxt, "runtime.noptrbss", 0).Sect = sect
+	Linklookup(Ctxt, "runtime.enoptrbss", 0).Sect = sect
+	for ; s != nil && s.Type == obj.SNOPTRBSS; s = s.Next {
+		datsize = aligndatsize(datsize, s)
+		s.Sect = sect
+		s.Value = int64(uint64(datsize) - sect.Vaddr)
+		growdatsize(&datsize, s)
+	}
+
+	sect.Length = uint64(datsize) - sect.Vaddr
+	Linklookup(Ctxt, "runtime.end", 0).Sect = sect
+
+	// 6g uses 4-byte relocation offsets, so the entire segment must fit in 32 bits.
+	if datsize != int64(uint32(datsize)) {
+		Diag("data or bss segment too large")
+	}
+
+	if Iself && Linkmode == LinkExternal && s != nil && s.Type == obj.STLSBSS && HEADTYPE != obj.Hopenbsd {
+		sect := addsection(&Segdata, ".tbss", 06)
+		sect.Align = int32(Thearch.Ptrsize)
+		sect.Vaddr = 0
+		datsize = 0
+		for ; s != nil && s.Type == obj.STLSBSS; s = s.Next {
+			datsize = aligndatsize(datsize, s)
+			s.Sect = sect
+			s.Value = int64(uint64(datsize) - sect.Vaddr)
+			growdatsize(&datsize, s)
+		}
+
+		sect.Length = uint64(datsize)
+	} else {
+		// Might be internal linking but still using cgo.
+		// In that case, the only possible STLSBSS symbol is runtime.tlsg.
+		// Give it offset 0, because it's the only thing here.
+		if s != nil && s.Type == obj.STLSBSS && s.Name == "runtime.tlsg" {
+			s.Value = 0
+			s = s.Next
+		}
+	}
+
+	if s != nil {
+		Ctxt.Cursym = nil
+		Diag("unexpected symbol type %d for %s", s.Type, s.Name)
+	}
+
+	/*
+	 * We finished data, begin read-only data.
+	 * Not all systems support a separate read-only non-executable data section.
+	 * ELF systems do.
+	 * OS X and Plan 9 do not.
+	 * Windows PE may, but if so we have not implemented it.
+	 * And if we're using external linking mode, the point is moot,
+	 * since it's not our decision; that code expects the sections in
+	 * segtext.
+	 */
+	var segro *Segment
+	if Iself && Linkmode == LinkInternal {
+		segro = &Segrodata
+	} else {
+		segro = &Segtext
+	}
+
+	s = datap
+
+	datsize = 0
+
+	/* read-only executable ELF, Mach-O sections */
+	for ; s != nil && s.Type < obj.STYPE; s = s.Next {
+		sect = addsection(&Segtext, s.Name, 04)
+		sect.Align = symalign(s)
+		datsize = Rnd(datsize, int64(sect.Align))
+		sect.Vaddr = uint64(datsize)
+		s.Sect = sect
+		s.Type = obj.SRODATA
+		s.Value = int64(uint64(datsize) - sect.Vaddr)
+		growdatsize(&datsize, s)
+		sect.Length = uint64(datsize) - sect.Vaddr
+	}
+
+	/* read-only data */
+	sect = addsection(segro, ".rodata", 04)
+
+	sect.Align = maxalign(s, obj.STYPELINK-1)
+	datsize = Rnd(datsize, int64(sect.Align))
+	sect.Vaddr = 0
+	Linklookup(Ctxt, "runtime.rodata", 0).Sect = sect
+	Linklookup(Ctxt, "runtime.erodata", 0).Sect = sect
+	for ; s != nil && s.Type < obj.STYPELINK; s = s.Next {
+		datsize = aligndatsize(datsize, s)
+		s.Sect = sect
+		s.Type = obj.SRODATA
+		s.Value = int64(uint64(datsize) - sect.Vaddr)
+		growdatsize(&datsize, s)
+	}
+
+	sect.Length = uint64(datsize) - sect.Vaddr
+
+	/* typelink */
+	sect = addsection(segro, ".typelink", 04)
+
+	sect.Align = maxalign(s, obj.STYPELINK)
+	datsize = Rnd(datsize, int64(sect.Align))
+	sect.Vaddr = uint64(datsize)
+	Linklookup(Ctxt, "runtime.typelink", 0).Sect = sect
+	Linklookup(Ctxt, "runtime.etypelink", 0).Sect = sect
+	for ; s != nil && s.Type == obj.STYPELINK; s = s.Next {
+		datsize = aligndatsize(datsize, s)
+		s.Sect = sect
+		s.Type = obj.SRODATA
+		s.Value = int64(uint64(datsize) - sect.Vaddr)
+		growdatsize(&datsize, s)
+	}
+
+	sect.Length = uint64(datsize) - sect.Vaddr
+
+	/* gosymtab */
+	sect = addsection(segro, ".gosymtab", 04)
+
+	sect.Align = maxalign(s, obj.SPCLNTAB-1)
+	datsize = Rnd(datsize, int64(sect.Align))
+	sect.Vaddr = uint64(datsize)
+	Linklookup(Ctxt, "runtime.symtab", 0).Sect = sect
+	Linklookup(Ctxt, "runtime.esymtab", 0).Sect = sect
+	for ; s != nil && s.Type < obj.SPCLNTAB; s = s.Next {
+		datsize = aligndatsize(datsize, s)
+		s.Sect = sect
+		s.Type = obj.SRODATA
+		s.Value = int64(uint64(datsize) - sect.Vaddr)
+		growdatsize(&datsize, s)
+	}
+
+	sect.Length = uint64(datsize) - sect.Vaddr
+
+	/* gopclntab */
+	sect = addsection(segro, ".gopclntab", 04)
+
+	sect.Align = maxalign(s, obj.SELFROSECT-1)
+	datsize = Rnd(datsize, int64(sect.Align))
+	sect.Vaddr = uint64(datsize)
+	Linklookup(Ctxt, "runtime.pclntab", 0).Sect = sect
+	Linklookup(Ctxt, "runtime.epclntab", 0).Sect = sect
+	for ; s != nil && s.Type < obj.SELFROSECT; s = s.Next {
+		datsize = aligndatsize(datsize, s)
+		s.Sect = sect
+		s.Type = obj.SRODATA
+		s.Value = int64(uint64(datsize) - sect.Vaddr)
+		growdatsize(&datsize, s)
+	}
+
+	sect.Length = uint64(datsize) - sect.Vaddr
+
+	/* read-only ELF, Mach-O sections */
+	for ; s != nil && s.Type < obj.SELFSECT; s = s.Next {
+		sect = addsection(segro, s.Name, 04)
+		sect.Align = symalign(s)
+		datsize = Rnd(datsize, int64(sect.Align))
+		sect.Vaddr = uint64(datsize)
+		s.Sect = sect
+		s.Type = obj.SRODATA
+		s.Value = int64(uint64(datsize) - sect.Vaddr)
+		growdatsize(&datsize, s)
+		sect.Length = uint64(datsize) - sect.Vaddr
+	}
+
+	// 6g uses 4-byte relocation offsets, so the entire segment must fit in 32 bits.
+	if datsize != int64(uint32(datsize)) {
+		Diag("read-only data segment too large")
+	}
+
+	/* number the sections */
+	n := int32(1)
+
+	for sect := Segtext.Sect; sect != nil; sect = sect.Next {
+		sect.Extnum = int16(n)
+		n++
+	}
+	for sect := Segrodata.Sect; sect != nil; sect = sect.Next {
+		sect.Extnum = int16(n)
+		n++
+	}
+	for sect := Segdata.Sect; sect != nil; sect = sect.Next {
+		sect.Extnum = int16(n)
+		n++
+	}
+}
+
+// Add buildid to beginning of text segment, on non-ELF systems.
+// Non-ELF binary formats are not always flexible enough to
+// give us a place to put the Go build ID. On those systems, we put it
+// at the very beginning of the text segment.
+// This ``header'' is read by cmd/go.
+func textbuildid() {
+	if Iself || buildid == "" {
+		return
+	}
+
+	sym := Linklookup(Ctxt, "go.buildid", 0)
+	sym.Reachable = true
+	// The \xff is invalid UTF-8, meant to make it less likely
+	// to find one of these accidentally.
+	data := "\xff Go build ID: " + strconv.Quote(buildid) + "\n \xff"
+	sym.Type = obj.STEXT
+	sym.P = []byte(data)
+	sym.Size = int64(len(sym.P))
+
+	sym.Next = Ctxt.Textp
+	Ctxt.Textp = sym
+}
+
+// assign addresses to text
+func textaddress() {
+	var sub *LSym
+
+	addsection(&Segtext, ".text", 05)
+
+	// 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.Align = int32(Funcalign)
+	Linklookup(Ctxt, "runtime.text", 0).Sect = sect
+	Linklookup(Ctxt, "runtime.etext", 0).Sect = sect
+	va := uint64(INITTEXT)
+	sect.Vaddr = va
+	for sym := Ctxt.Textp; sym != nil; sym = sym.Next {
+		sym.Sect = sect
+		if sym.Type&obj.SSUB != 0 {
+			continue
+		}
+		if sym.Align != 0 {
+			va = uint64(Rnd(int64(va), int64(sym.Align)))
+		} else {
+			va = uint64(Rnd(int64(va), int64(Funcalign)))
+		}
+		sym.Value = 0
+		for sub = sym; sub != nil; sub = sub.Sub {
+			sub.Value += int64(va)
+		}
+		if sym.Size == 0 && sym.Sub != nil {
+			Ctxt.Cursym = sym
+		}
+		if sym.Size < MINFUNC {
+			va += MINFUNC // spacing required for findfunctab
+		} else {
+			va += uint64(sym.Size)
+		}
+	}
+
+	sect.Length = va - sect.Vaddr
+}
+
+// assign addresses
+func address() {
+	va := uint64(INITTEXT)
+	Segtext.Rwx = 05
+	Segtext.Vaddr = va
+	Segtext.Fileoff = uint64(HEADR)
+	for s := Segtext.Sect; s != nil; s = s.Next {
+		va = uint64(Rnd(int64(va), int64(s.Align)))
+		s.Vaddr = va
+		va += s.Length
+	}
+
+	Segtext.Length = va - uint64(INITTEXT)
+	Segtext.Filelen = Segtext.Length
+	if HEADTYPE == obj.Hnacl {
+		va += 32 // room for the "halt sled"
+	}
+
+	if Segrodata.Sect != nil {
+		// align to page boundary so as not to mix
+		// rodata and executable text.
+		va = uint64(Rnd(int64(va), int64(INITRND)))
+
+		Segrodata.Rwx = 04
+		Segrodata.Vaddr = va
+		Segrodata.Fileoff = va - Segtext.Vaddr + Segtext.Fileoff
+		Segrodata.Filelen = 0
+		for s := Segrodata.Sect; s != nil; s = s.Next {
+			va = uint64(Rnd(int64(va), int64(s.Align)))
+			s.Vaddr = va
+			va += s.Length
+		}
+
+		Segrodata.Length = va - Segrodata.Vaddr
+		Segrodata.Filelen = Segrodata.Length
+	}
+
+	va = uint64(Rnd(int64(va), int64(INITRND)))
+	Segdata.Rwx = 06
+	Segdata.Vaddr = va
+	Segdata.Fileoff = va - Segtext.Vaddr + Segtext.Fileoff
+	Segdata.Filelen = 0
+	if HEADTYPE == obj.Hwindows {
+		Segdata.Fileoff = Segtext.Fileoff + uint64(Rnd(int64(Segtext.Length), PEFILEALIGN))
+	}
+	if HEADTYPE == obj.Hplan9 {
+		Segdata.Fileoff = Segtext.Fileoff + Segtext.Filelen
+	}
+	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)
+		}
+		s.Vaddr = va
+		va += uint64(vlen)
+		Segdata.Length = va - Segdata.Vaddr
+		if s.Name == ".data" {
+			data = s
+		}
+		if s.Name == ".noptrdata" {
+			noptr = s
+		}
+		if s.Name == ".bss" {
+			bss = s
+		}
+		if s.Name == ".noptrbss" {
+			noptrbss = s
+		}
+	}
+
+	Segdata.Filelen = bss.Vaddr - Segdata.Vaddr
+
+	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
+
+	var sub *LSym
+	for sym := datap; sym != nil; sym = sym.Next {
+		Ctxt.Cursym = sym
+		if sym.Sect != nil {
+			sym.Value += int64(sym.Sect.Vaddr)
+		}
+		for sub = sym.Sub; sub != nil; sub = sub.Sub {
+			sub.Value += sym.Value
+		}
+	}
+
+	if Buildmode == BuildmodeShared {
+		s := Linklookup(Ctxt, "go.link.abihashbytes", 0)
+		sectSym := Linklookup(Ctxt, ".note.go.abihash", 0)
+		s.Sect = sectSym.Sect
+		s.Value = int64(sectSym.Sect.Vaddr + 16)
+	}
+
+	xdefine("runtime.text", obj.STEXT, int64(text.Vaddr))
+	xdefine("runtime.etext", obj.STEXT, int64(text.Vaddr+text.Length))
+	xdefine("runtime.rodata", obj.SRODATA, int64(rodata.Vaddr))
+	xdefine("runtime.erodata", obj.SRODATA, int64(rodata.Vaddr+rodata.Length))
+	xdefine("runtime.typelink", obj.SRODATA, int64(typelink.Vaddr))
+	xdefine("runtime.etypelink", obj.SRODATA, int64(typelink.Vaddr+typelink.Length))
+
+	sym := Linklookup(Ctxt, "runtime.gcdata", 0)
+	sym.Local = true
+	xdefine("runtime.egcdata", obj.SRODATA, Symaddr(sym)+sym.Size)
+	Linklookup(Ctxt, "runtime.egcdata", 0).Sect = sym.Sect
+
+	sym = Linklookup(Ctxt, "runtime.gcbss", 0)
+	sym.Local = true
+	xdefine("runtime.egcbss", obj.SRODATA, Symaddr(sym)+sym.Size)
+	Linklookup(Ctxt, "runtime.egcbss", 0).Sect = sym.Sect
+
+	xdefine("runtime.symtab", obj.SRODATA, int64(symtab.Vaddr))
+	xdefine("runtime.esymtab", obj.SRODATA, int64(symtab.Vaddr+symtab.Length))
+	xdefine("runtime.pclntab", obj.SRODATA, int64(pclntab.Vaddr))
+	xdefine("runtime.epclntab", obj.SRODATA, int64(pclntab.Vaddr+pclntab.Length))
+	xdefine("runtime.noptrdata", obj.SNOPTRDATA, int64(noptr.Vaddr))
+	xdefine("runtime.enoptrdata", obj.SNOPTRDATA, int64(noptr.Vaddr+noptr.Length))
+	xdefine("runtime.bss", obj.SBSS, int64(bss.Vaddr))
+	xdefine("runtime.ebss", obj.SBSS, int64(bss.Vaddr+bss.Length))
+	xdefine("runtime.data", obj.SDATA, int64(data.Vaddr))
+	xdefine("runtime.edata", obj.SDATA, int64(data.Vaddr+data.Length))
+	xdefine("runtime.noptrbss", obj.SNOPTRBSS, int64(noptrbss.Vaddr))
+	xdefine("runtime.enoptrbss", obj.SNOPTRBSS, int64(noptrbss.Vaddr+noptrbss.Length))
+	xdefine("runtime.end", obj.SBSS, int64(Segdata.Vaddr+Segdata.Length))
+}
diff --git a/src/cmd/link/internal/ld/decodesym.go b/src/cmd/link/internal/ld/decodesym.go
new file mode 100644
index 0000000..c1cf4d7
--- /dev/null
+++ b/src/cmd/link/internal/ld/decodesym.go
@@ -0,0 +1,226 @@
+// 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.
+
+package ld
+
+import (
+	"cmd/internal/obj"
+	"debug/elf"
+)
+
+// Decoding the type.* symbols.	 This has to be in sync with
+// ../../runtime/type.go, or more specifically, with what
+// ../gc/reflect.c stuffs in these.
+
+func decode_reloc(s *LSym, off int32) *Reloc {
+	for i := 0; i < len(s.R); i++ {
+		if s.R[i].Off == off {
+			return &s.R[i:][0]
+		}
+	}
+	return nil
+}
+
+func decode_reloc_sym(s *LSym, off int32) *LSym {
+	r := decode_reloc(s, off)
+	if r == nil {
+		return nil
+	}
+	return r.Sym
+}
+
+func decode_inuxi(p []byte, sz int) uint64 {
+	switch sz {
+	case 2:
+		return uint64(Ctxt.Arch.ByteOrder.Uint16(p))
+	case 4:
+		return uint64(Ctxt.Arch.ByteOrder.Uint32(p))
+	case 8:
+		return Ctxt.Arch.ByteOrder.Uint64(p)
+	default:
+		Exitf("dwarf: decode inuxi %d", sz)
+		panic("unreachable")
+	}
+}
+
+// commonsize returns the size of the common prefix for all type
+// structures (runtime._type).
+func commonsize() int {
+	return 8*Thearch.Ptrsize + 8
+}
+
+// Type.commonType.kind
+func decodetype_kind(s *LSym) uint8 {
+	return uint8(s.P[2*Thearch.Ptrsize+7] & obj.KindMask) //  0x13 / 0x1f
+}
+
+// Type.commonType.kind
+func decodetype_noptr(s *LSym) uint8 {
+	return uint8(s.P[2*Thearch.Ptrsize+7] & obj.KindNoPointers) //  0x13 / 0x1f
+}
+
+// Type.commonType.kind
+func decodetype_usegcprog(s *LSym) uint8 {
+	return uint8(s.P[2*Thearch.Ptrsize+7] & obj.KindGCProg) //  0x13 / 0x1f
+}
+
+// Type.commonType.size
+func decodetype_size(s *LSym) int64 {
+	return int64(decode_inuxi(s.P, Thearch.Ptrsize)) // 0x8 / 0x10
+}
+
+// Type.commonType.ptrdata
+func decodetype_ptrdata(s *LSym) int64 {
+	return int64(decode_inuxi(s.P[Thearch.Ptrsize:], Thearch.Ptrsize)) // 0x8 / 0x10
+}
+
+// Find the elf.Section of a given shared library that contains a given address.
+func findShlibSection(path string, addr uint64) *elf.Section {
+	for _, shlib := range Ctxt.Shlibs {
+		if shlib.Path == path {
+			for _, sect := range shlib.File.Sections {
+				if sect.Addr <= addr && addr <= sect.Addr+sect.Size {
+					return sect
+				}
+			}
+		}
+	}
+	return nil
+}
+
+// Type.commonType.gc
+func decodetype_gcprog(s *LSym) []byte {
+	if s.Type == obj.SDYNIMPORT {
+		addr := decodetype_gcprog_shlib(s)
+		sect := findShlibSection(s.File, addr)
+		if sect != nil {
+			// A gcprog is a 4-byte uint32 indicating length, followed by
+			// the actual program.
+			progsize := make([]byte, 4)
+			sect.ReadAt(progsize, int64(addr-sect.Addr))
+			progbytes := make([]byte, Ctxt.Arch.ByteOrder.Uint32(progsize))
+			sect.ReadAt(progbytes, int64(addr-sect.Addr+4))
+			return append(progsize, progbytes...)
+		}
+		Exitf("cannot find gcprog for %s", s.Name)
+		return nil
+	}
+	return decode_reloc_sym(s, 2*int32(Thearch.Ptrsize)+8+1*int32(Thearch.Ptrsize)).P
+}
+
+func decodetype_gcprog_shlib(s *LSym) uint64 {
+	return decode_inuxi(s.P[2*int32(Thearch.Ptrsize)+8+1*int32(Thearch.Ptrsize):], Thearch.Ptrsize)
+}
+
+func decodetype_gcmask(s *LSym) []byte {
+	if s.Type == obj.SDYNIMPORT {
+		addr := decodetype_gcprog_shlib(s)
+		ptrdata := decodetype_ptrdata(s)
+		sect := findShlibSection(s.File, addr)
+		if sect != nil {
+			r := make([]byte, ptrdata/int64(Thearch.Ptrsize))
+			sect.ReadAt(r, int64(addr-sect.Addr))
+			return r
+		}
+		Exitf("cannot find gcmask for %s", s.Name)
+		return nil
+	}
+	mask := decode_reloc_sym(s, 2*int32(Thearch.Ptrsize)+8+1*int32(Thearch.Ptrsize))
+	return mask.P
+}
+
+// Type.ArrayType.elem and Type.SliceType.Elem
+func decodetype_arrayelem(s *LSym) *LSym {
+	return decode_reloc_sym(s, int32(commonsize())) // 0x1c / 0x30
+}
+
+func decodetype_arraylen(s *LSym) int64 {
+	return int64(decode_inuxi(s.P[commonsize()+2*Thearch.Ptrsize:], Thearch.Ptrsize))
+}
+
+// Type.PtrType.elem
+func decodetype_ptrelem(s *LSym) *LSym {
+	return decode_reloc_sym(s, int32(commonsize())) // 0x1c / 0x30
+}
+
+// Type.MapType.key, elem
+func decodetype_mapkey(s *LSym) *LSym {
+	return decode_reloc_sym(s, int32(commonsize())) // 0x1c / 0x30
+}
+
+func decodetype_mapvalue(s *LSym) *LSym {
+	return decode_reloc_sym(s, int32(commonsize())+int32(Thearch.Ptrsize)) // 0x20 / 0x38
+}
+
+// Type.ChanType.elem
+func decodetype_chanelem(s *LSym) *LSym {
+	return decode_reloc_sym(s, int32(commonsize())) // 0x1c / 0x30
+}
+
+// Type.FuncType.dotdotdot
+func decodetype_funcdotdotdot(s *LSym) int {
+	return int(s.P[commonsize()])
+}
+
+// Type.FuncType.in.length
+func decodetype_funcincount(s *LSym) int {
+	return int(decode_inuxi(s.P[commonsize()+2*Thearch.Ptrsize:], Thearch.Intsize))
+}
+
+func decodetype_funcoutcount(s *LSym) int {
+	return int(decode_inuxi(s.P[commonsize()+3*Thearch.Ptrsize+2*Thearch.Intsize:], Thearch.Intsize))
+}
+
+func decodetype_funcintype(s *LSym, i int) *LSym {
+	r := decode_reloc(s, int32(commonsize())+int32(Thearch.Ptrsize))
+	if r == nil {
+		return nil
+	}
+	return decode_reloc_sym(r.Sym, int32(r.Add+int64(int32(i)*int32(Thearch.Ptrsize))))
+}
+
+func decodetype_funcouttype(s *LSym, i int) *LSym {
+	r := decode_reloc(s, int32(commonsize())+2*int32(Thearch.Ptrsize)+2*int32(Thearch.Intsize))
+	if r == nil {
+		return nil
+	}
+	return decode_reloc_sym(r.Sym, int32(r.Add+int64(int32(i)*int32(Thearch.Ptrsize))))
+}
+
+// Type.StructType.fields.Slice::length
+func decodetype_structfieldcount(s *LSym) int {
+	return int(decode_inuxi(s.P[commonsize()+Thearch.Ptrsize:], Thearch.Intsize))
+}
+
+func structfieldsize() int {
+	return 5 * Thearch.Ptrsize
+}
+
+// Type.StructType.fields[]-> name, typ and offset.
+func decodetype_structfieldname(s *LSym, i int) string {
+	// 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.
+		return ""
+	}
+	return cstring(r.Sym.P[r.Add:])
+}
+
+func decodetype_structfieldtype(s *LSym, i int) *LSym {
+	return decode_reloc_sym(s, int32(commonsize())+int32(Thearch.Ptrsize)+2*int32(Thearch.Intsize)+int32(i)*int32(structfieldsize())+2*int32(Thearch.Ptrsize))
+}
+
+func decodetype_structfieldoffs(s *LSym, i int) int64 {
+	return int64(decode_inuxi(s.P[commonsize()+Thearch.Ptrsize+2*Thearch.Intsize+i*structfieldsize()+4*Thearch.Ptrsize:], Thearch.Intsize))
+}
+
+// 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/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go
new file mode 100644
index 0000000..41d820d
--- /dev/null
+++ b/src/cmd/link/internal/ld/dwarf.go
@@ -0,0 +1,2624 @@
+// Copyright 2010 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.
+
+// 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 (
+	"cmd/internal/obj"
+	"fmt"
+	"os"
+	"strings"
+)
+
+/*
+ * Offsets and sizes of the debug_* sections in the cout file.
+ */
+var abbrevo int64
+
+var abbrevsize int64
+
+var abbrevsym *LSym
+
+var abbrevsympos int64
+
+var lineo int64
+
+var linesize int64
+
+var linesym *LSym
+
+var linesympos int64
+
+var infoo int64 // also the base for DWDie->offs and reference attributes.
+
+var infosize int64
+
+var infosym *LSym
+
+var infosympos int64
+
+var frameo int64
+
+var framesize int64
+
+var framesym *LSym
+
+var framesympos int64
+
+var pubnameso int64
+
+var pubnamessize int64
+
+var pubtypeso int64
+
+var pubtypessize int64
+
+var arangeso int64
+
+var arangessize int64
+
+var gdbscripto int64
+
+var gdbscriptsize int64
+
+var infosec *LSym
+
+var inforeloco int64
+
+var inforelocsize int64
+
+var arangessec *LSym
+
+var arangesreloco int64
+
+var arangesrelocsize int64
+
+var linesec *LSym
+
+var linereloco int64
+
+var linerelocsize int64
+
+var framesec *LSym
+
+var framereloco int64
+
+var framerelocsize int64
+
+var gdbscript string
+
+/*
+ *  Basic I/O
+ */
+func addrput(addr int64) {
+	switch Thearch.Ptrsize {
+	case 4:
+		Thearch.Lput(uint32(addr))
+
+	case 8:
+		Thearch.Vput(uint64(addr))
+	}
+}
+
+func uleb128enc(v uint64, dst []byte) int {
+	var c uint8
+
+	length := uint8(0)
+	for {
+		c = uint8(v & 0x7f)
+		v >>= 7
+		if v != 0 {
+			c |= 0x80
+		}
+		if dst != nil {
+			dst[0] = byte(c)
+			dst = dst[1:]
+		}
+		length++
+		if c&0x80 == 0 {
+			break
+		}
+	}
+
+	return int(length)
+}
+
+func sleb128enc(v int64, dst []byte) int {
+	var c uint8
+	var s uint8
+
+	length := uint8(0)
+	for {
+		c = uint8(v & 0x7f)
+		s = uint8(v & 0x40)
+		v >>= 7
+		if (v != -1 || s == 0) && (v != 0 || s != 0) {
+			c |= 0x80
+		}
+		if dst != nil {
+			dst[0] = byte(c)
+			dst = dst[1:]
+		}
+		length++
+		if c&0x80 == 0 {
+			break
+		}
+	}
+
+	return int(length)
+}
+
+var encbuf [10]byte
+
+func uleb128put(v int64) {
+	n := uleb128enc(uint64(v), encbuf[:])
+	Cwrite(encbuf[:n])
+}
+
+func sleb128put(v int64) {
+	n := sleb128enc(v, encbuf[:])
+	Cwrite(encbuf[:n])
+}
+
+/*
+ * Defining Abbrevs.  This is hardcoded, and there will be
+ * only a handful of them.  The DWARF spec places no restriction on
+ * the ordering of attributes in the Abbrevs and DIEs, and we will
+ * always write them out in the order of declaration in the abbrev.
+ */
+type DWAttrForm struct {
+	attr uint16
+	form uint8
+}
+
+// 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 // params and locals; not emitted
+)
+
+// Index into the abbrevs table below.
+// Keep in sync with ispubname() and ispubtype() below.
+// ispubtype considers >= NULLTYPE public
+const (
+	DW_ABRV_NULL = iota
+	DW_ABRV_COMPUNIT
+	DW_ABRV_FUNCTION
+	DW_ABRV_VARIABLE
+	DW_ABRV_AUTO
+	DW_ABRV_PARAM
+	DW_ABRV_STRUCTFIELD
+	DW_ABRV_FUNCTYPEPARAM
+	DW_ABRV_DOTDOTDOT
+	DW_ABRV_ARRAYRANGE
+	DW_ABRV_NULLTYPE
+	DW_ABRV_BASETYPE
+	DW_ABRV_ARRAYTYPE
+	DW_ABRV_CHANTYPE
+	DW_ABRV_FUNCTYPE
+	DW_ABRV_IFACETYPE
+	DW_ABRV_MAPTYPE
+	DW_ABRV_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
+	DW_ABRV_TYPEDECL
+	DW_NABRV
+)
+
+type DWAbbrev struct {
+	tag      uint8
+	children uint8
+	attr     []DWAttrForm
+}
+
+var abbrevs = [DW_NABRV]DWAbbrev{
+	/* The mandatory DW_ABRV_NULL entry. */
+	{0, 0, []DWAttrForm{}},
+
+	/* COMPUNIT */
+	{
+		DW_TAG_compile_unit,
+		DW_CHILDREN_yes,
+		[]DWAttrForm{
+			{DW_AT_name, DW_FORM_string},
+			{DW_AT_language, DW_FORM_data1},
+			{DW_AT_low_pc, DW_FORM_addr},
+			{DW_AT_high_pc, DW_FORM_addr},
+			{DW_AT_stmt_list, DW_FORM_data4},
+			{DW_AT_comp_dir, DW_FORM_string},
+		},
+	},
+
+	/* FUNCTION */
+	{
+		DW_TAG_subprogram,
+		DW_CHILDREN_yes,
+		[]DWAttrForm{
+			{DW_AT_name, DW_FORM_string},
+			{DW_AT_low_pc, DW_FORM_addr},
+			{DW_AT_high_pc, DW_FORM_addr},
+			{DW_AT_external, DW_FORM_flag},
+		},
+	},
+
+	/* VARIABLE */
+	{
+		DW_TAG_variable,
+		DW_CHILDREN_no,
+		[]DWAttrForm{
+			{DW_AT_name, DW_FORM_string},
+			{DW_AT_location, DW_FORM_block1},
+			{DW_AT_type, DW_FORM_ref_addr},
+			{DW_AT_external, DW_FORM_flag},
+		},
+	},
+
+	/* AUTO */
+	{
+		DW_TAG_variable,
+		DW_CHILDREN_no,
+		[]DWAttrForm{
+			{DW_AT_name, DW_FORM_string},
+			{DW_AT_location, DW_FORM_block1},
+			{DW_AT_type, DW_FORM_ref_addr},
+		},
+	},
+
+	/* PARAM */
+	{
+		DW_TAG_formal_parameter,
+		DW_CHILDREN_no,
+		[]DWAttrForm{
+			{DW_AT_name, DW_FORM_string},
+			{DW_AT_location, DW_FORM_block1},
+			{DW_AT_type, DW_FORM_ref_addr},
+		},
+	},
+
+	/* STRUCTFIELD */
+	{
+		DW_TAG_member,
+		DW_CHILDREN_no,
+		[]DWAttrForm{
+			{DW_AT_name, DW_FORM_string},
+			{DW_AT_data_member_location, DW_FORM_block1},
+			{DW_AT_type, DW_FORM_ref_addr},
+		},
+	},
+
+	/* FUNCTYPEPARAM */
+	{
+		DW_TAG_formal_parameter,
+		DW_CHILDREN_no,
+
+		// No name!
+		[]DWAttrForm{
+			{DW_AT_type, DW_FORM_ref_addr},
+		},
+	},
+
+	/* DOTDOTDOT */
+	{
+		DW_TAG_unspecified_parameters,
+		DW_CHILDREN_no,
+		[]DWAttrForm{},
+	},
+
+	/* ARRAYRANGE */
+	{
+		DW_TAG_subrange_type,
+		DW_CHILDREN_no,
+
+		// No name!
+		[]DWAttrForm{
+			{DW_AT_type, DW_FORM_ref_addr},
+			{DW_AT_count, DW_FORM_udata},
+		},
+	},
+
+	// Below here are the types considered public by ispubtype
+	/* NULLTYPE */
+	{
+		DW_TAG_unspecified_type,
+		DW_CHILDREN_no,
+		[]DWAttrForm{
+			{DW_AT_name, DW_FORM_string},
+		},
+	},
+
+	/* BASETYPE */
+	{
+		DW_TAG_base_type,
+		DW_CHILDREN_no,
+		[]DWAttrForm{
+			{DW_AT_name, DW_FORM_string},
+			{DW_AT_encoding, DW_FORM_data1},
+			{DW_AT_byte_size, DW_FORM_data1},
+			{DW_AT_go_kind, DW_FORM_data1},
+		},
+	},
+
+	/* ARRAYTYPE */
+	// child is subrange with upper bound
+	{
+		DW_TAG_array_type,
+		DW_CHILDREN_yes,
+		[]DWAttrForm{
+			{DW_AT_name, DW_FORM_string},
+			{DW_AT_type, DW_FORM_ref_addr},
+			{DW_AT_byte_size, DW_FORM_udata},
+			{DW_AT_go_kind, DW_FORM_data1},
+		},
+	},
+
+	/* CHANTYPE */
+	{
+		DW_TAG_typedef,
+		DW_CHILDREN_no,
+		[]DWAttrForm{
+			{DW_AT_name, DW_FORM_string},
+			{DW_AT_type, DW_FORM_ref_addr},
+			{DW_AT_go_kind, DW_FORM_data1},
+			{DW_AT_go_elem, DW_FORM_ref_addr},
+		},
+	},
+
+	/* FUNCTYPE */
+	{
+		DW_TAG_subroutine_type,
+		DW_CHILDREN_yes,
+		[]DWAttrForm{
+			{DW_AT_name, DW_FORM_string},
+			// {DW_AT_type,	DW_FORM_ref_addr},
+			{DW_AT_go_kind, DW_FORM_data1},
+		},
+	},
+
+	/* IFACETYPE */
+	{
+		DW_TAG_typedef,
+		DW_CHILDREN_yes,
+		[]DWAttrForm{
+			{DW_AT_name, DW_FORM_string},
+			{DW_AT_type, DW_FORM_ref_addr},
+			{DW_AT_go_kind, DW_FORM_data1},
+		},
+	},
+
+	/* MAPTYPE */
+	{
+		DW_TAG_typedef,
+		DW_CHILDREN_no,
+		[]DWAttrForm{
+			{DW_AT_name, DW_FORM_string},
+			{DW_AT_type, DW_FORM_ref_addr},
+			{DW_AT_go_kind, DW_FORM_data1},
+			{DW_AT_go_key, DW_FORM_ref_addr},
+			{DW_AT_go_elem, DW_FORM_ref_addr},
+		},
+	},
+
+	/* PTRTYPE */
+	{
+		DW_TAG_pointer_type,
+		DW_CHILDREN_no,
+		[]DWAttrForm{
+			{DW_AT_name, DW_FORM_string},
+			{DW_AT_type, DW_FORM_ref_addr},
+			{DW_AT_go_kind, DW_FORM_data1},
+		},
+	},
+
+	/* BARE_PTRTYPE */
+	{
+		DW_TAG_pointer_type,
+		DW_CHILDREN_no,
+		[]DWAttrForm{
+			{DW_AT_name, DW_FORM_string},
+		},
+	},
+
+	/* SLICETYPE */
+	{
+		DW_TAG_structure_type,
+		DW_CHILDREN_yes,
+		[]DWAttrForm{
+			{DW_AT_name, DW_FORM_string},
+			{DW_AT_byte_size, DW_FORM_udata},
+			{DW_AT_go_kind, DW_FORM_data1},
+			{DW_AT_go_elem, DW_FORM_ref_addr},
+		},
+	},
+
+	/* STRINGTYPE */
+	{
+		DW_TAG_structure_type,
+		DW_CHILDREN_yes,
+		[]DWAttrForm{
+			{DW_AT_name, DW_FORM_string},
+			{DW_AT_byte_size, DW_FORM_udata},
+			{DW_AT_go_kind, DW_FORM_data1},
+		},
+	},
+
+	/* STRUCTTYPE */
+	{
+		DW_TAG_structure_type,
+		DW_CHILDREN_yes,
+		[]DWAttrForm{
+			{DW_AT_name, DW_FORM_string},
+			{DW_AT_byte_size, DW_FORM_udata},
+			{DW_AT_go_kind, DW_FORM_data1},
+		},
+	},
+
+	/* TYPEDECL */
+	{
+		DW_TAG_typedef,
+		DW_CHILDREN_no,
+		[]DWAttrForm{
+			{DW_AT_name, DW_FORM_string},
+			{DW_AT_type, DW_FORM_ref_addr},
+		},
+	},
+}
+
+func writeabbrev() {
+	abbrevo = Cpos()
+	for i := 1; i < DW_NABRV; i++ {
+		// See section 7.5.3
+		uleb128put(int64(i))
+
+		uleb128put(int64(abbrevs[i].tag))
+		Cput(abbrevs[i].children)
+		for _, f := range abbrevs[i].attr {
+			uleb128put(int64(f.attr))
+			uleb128put(int64(f.form))
+		}
+		uleb128put(0)
+		uleb128put(0)
+	}
+
+	Cput(0)
+	abbrevsize = Cpos() - abbrevo
+}
+
+/*
+ * Debugging Information Entries and their attributes.
+ */
+const (
+	HASHSIZE = 107
+)
+
+func dwarfhashstr(s string) uint32 {
+	h := uint32(0)
+	for s != "" {
+		h = h + h + h + uint32(s[0])
+		s = s[1:]
+	}
+	return h % HASHSIZE
+}
+
+// For DW_CLS_string and _block, value should contain the length, and
+// data the data, for _reference, value is 0 and data is a DWDie* to
+// the referenced instance, for all others, value is the whole thing
+// and data is null.
+
+type DWAttr struct {
+	link  *DWAttr
+	atr   uint16 // DW_AT_
+	cls   uint8  // DW_CLS_
+	value int64
+	data  interface{}
+}
+
+type DWDie struct {
+	abbrev int
+	link   *DWDie
+	child  *DWDie
+	attr   *DWAttr
+	// 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
+}
+
+/*
+ * Root DIEs for compilation units, types and global variables.
+ */
+var dwroot DWDie
+
+var dwtypes DWDie
+
+var dwglobals DWDie
+
+func newattr(die *DWDie, attr uint16, cls int, value int64, data interface{}) *DWAttr {
+	a := new(DWAttr)
+	a.link = die.attr
+	die.attr = a
+	a.atr = attr
+	a.cls = uint8(cls)
+	a.value = value
+	a.data = data
+	return a
+}
+
+// Each DIE (except the root ones) has at least 1 attribute: its
+// name. getattr moves the desired one to the front so
+// frequently searched ones are found faster.
+func getattr(die *DWDie, attr uint16) *DWAttr {
+	if die.attr.atr == attr {
+		return die.attr
+	}
+
+	a := die.attr
+	b := a.link
+	for b != nil {
+		if b.atr == attr {
+			a.link = b.link
+			b.link = die.attr
+			die.attr = b
+			return b
+		}
+
+		a = b
+		b = b.link
+	}
+
+	return nil
+}
+
+// Every DIE has at least a DW_AT_name attribute (but it will only be
+// 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 {
+	die := new(DWDie)
+	die.abbrev = abbrev
+	die.link = parent.child
+	parent.child = die
+
+	newattr(die, DW_AT_name, DW_CLS_STRING, int64(len(name)), name)
+
+	if parent.hash != nil {
+		h := int(dwarfhashstr(name))
+		die.hlink = parent.hash[h]
+		parent.hash[h] = die
+	}
+
+	return die
+}
+
+func mkindex(die *DWDie) {
+	die.hash = make([]*DWDie, HASHSIZE)
+}
+
+func walktypedef(die *DWDie) *DWDie {
+	// Resolve typedef if present.
+	if die.abbrev == DW_ABRV_TYPEDECL {
+		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)
+			}
+		}
+	}
+
+	return die
+}
+
+// Find child by AT_name using hashtable if available or linear scan
+// if not.
+func find(die *DWDie, name string) *DWDie {
+	var a *DWDie
+	var b *DWDie
+	var die2 *DWDie
+	var h int
+
+top:
+	if die.hash == nil {
+		for a = die.child; a != nil; a = a.link {
+			if name == getattr(a, DW_AT_name).data {
+				return a
+			}
+		}
+		goto notfound
+	}
+
+	h = int(dwarfhashstr(name))
+	a = die.hash[h]
+
+	if a == nil {
+		goto notfound
+	}
+
+	if name == getattr(a, DW_AT_name).data {
+		return a
+	}
+
+	// Move found ones to head of the list.
+	b = a.hlink
+
+	for b != nil {
+		if name == getattr(b, DW_AT_name).data {
+			a.hlink = b.hlink
+			b.hlink = die.hash[h]
+			die.hash[h] = b
+			return b
+		}
+
+		a = b
+		b = b.hlink
+	}
+
+notfound:
+	die2 = walktypedef(die)
+	if die2 != die {
+		die = die2
+		goto top
+	}
+
+	return nil
+}
+
+func mustFind(die *DWDie, name string) *DWDie {
+	r := find(die, name)
+	if r == nil {
+		Exitf("dwarf find: %s %p has no %s", getattr(die, DW_AT_name).data, die, name)
+	}
+	return r
+}
+
+func adddwarfrel(sec *LSym, sym *LSym, offsetbase int64, siz int, addend int64) {
+	r := Addrel(sec)
+	r.Sym = sym
+	r.Xsym = sym
+	r.Off = int32(Cpos() - offsetbase)
+	r.Siz = uint8(siz)
+	r.Type = obj.R_ADDR
+	r.Add = addend
+	r.Xadd = addend
+	if Iself && Thearch.Thechar == '6' {
+		addend = 0
+	}
+	if HEADTYPE == obj.Hdarwin {
+		addend += sym.Value
+	}
+	switch siz {
+	case 4:
+		Thearch.Lput(uint32(addend))
+
+	case 8:
+		Thearch.Vput(uint64(addend))
+
+	default:
+		Diag("bad size in adddwarfrel")
+	}
+}
+
+func newrefattr(die *DWDie, attr uint16, ref *DWDie) *DWAttr {
+	if ref == nil {
+		return nil
+	}
+	return newattr(die, attr, DW_CLS_REFERENCE, 0, ref)
+}
+
+var fwdcount int
+
+func putattr(abbrev int, form int, cls int, value int64, data interface{}) {
+	switch form {
+	case DW_FORM_addr: // address
+		if Linkmode == LinkExternal {
+			value -= (data.(*LSym)).Value
+			adddwarfrel(infosec, data.(*LSym), infoo, Thearch.Ptrsize, value)
+			break
+		}
+
+		addrput(value)
+
+	case DW_FORM_block1: // block
+		if cls == DW_CLS_ADDRESS {
+			Cput(uint8(1 + Thearch.Ptrsize))
+			Cput(DW_OP_addr)
+			if Linkmode == LinkExternal {
+				value -= (data.(*LSym)).Value
+				adddwarfrel(infosec, data.(*LSym), infoo, Thearch.Ptrsize, value)
+				break
+			}
+
+			addrput(value)
+			break
+		}
+
+		value &= 0xff
+		Cput(uint8(value))
+		p := data.([]byte)
+		for i := 0; int64(i) < value; i++ {
+			Cput(uint8(p[i]))
+		}
+
+	case DW_FORM_block2: // block
+		value &= 0xffff
+
+		Thearch.Wput(uint16(value))
+		p := data.([]byte)
+		for i := 0; int64(i) < value; i++ {
+			Cput(uint8(p[i]))
+		}
+
+	case DW_FORM_block4: // block
+		value &= 0xffffffff
+
+		Thearch.Lput(uint32(value))
+		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++ {
+			Cput(uint8(p[i]))
+		}
+
+	case DW_FORM_data1: // constant
+		Cput(uint8(value))
+
+	case DW_FORM_data2: // constant
+		Thearch.Wput(uint16(value))
+
+	case DW_FORM_data4: // constant, {line,loclist,mac,rangelist}ptr
+		if Linkmode == LinkExternal && cls == DW_CLS_PTR {
+			adddwarfrel(infosec, linesym, infoo, 4, value)
+			break
+		}
+
+		Thearch.Lput(uint32(value))
+
+	case DW_FORM_data8: // constant, {line,loclist,mac,rangelist}ptr
+		Thearch.Vput(uint64(value))
+
+	case DW_FORM_sdata: // constant
+		sleb128put(value)
+
+	case DW_FORM_udata: // constant
+		uleb128put(value)
+
+	case DW_FORM_string: // string
+		strnput(data.(string), int(value+1))
+
+	case DW_FORM_flag: // flag
+		if value != 0 {
+			Cput(1)
+		} else {
+			Cput(0)
+		}
+
+		// In DWARF 2 (which is what we claim to generate),
+	// the ref_addr is the same size as a normal address.
+	// In DWARF 3 it is always 32 bits, unless emitting a large
+	// (> 4 GB of debug info aka "64-bit") unit, which we don't implement.
+	case DW_FORM_ref_addr: // reference to a DIE in the .info section
+		if data == nil {
+			Diag("dwarf: null reference in %d", abbrev)
+			if Thearch.Ptrsize == 8 {
+				Thearch.Vput(0) // invalid dwarf, gdb will complain.
+			} else {
+				Thearch.Lput(0) // invalid dwarf, gdb will complain.
+			}
+		} else {
+			off := (data.(*DWDie)).offs
+			if off == 0 {
+				fwdcount++
+			}
+			if Linkmode == LinkExternal {
+				adddwarfrel(infosec, infosym, infoo, Thearch.Ptrsize, off)
+				break
+			}
+
+			addrput(off)
+		}
+
+	case DW_FORM_ref1, // reference within the compilation unit
+		DW_FORM_ref2,      // reference
+		DW_FORM_ref4,      // reference
+		DW_FORM_ref8,      // reference
+		DW_FORM_ref_udata, // reference
+
+		DW_FORM_strp,     // string
+		DW_FORM_indirect: // (see Section 7.5.3)
+		fallthrough
+	default:
+		Exitf("dwarf: unsupported attribute form %d / class %d", form, cls)
+	}
+}
+
+// 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) {
+Outer:
+	for _, f := range abbrevs[abbrev].attr {
+		for ap := attr; ap != nil; ap = ap.link {
+			if ap.atr == f.attr {
+				putattr(abbrev, int(f.form), int(ap.cls), ap.value, ap.data)
+				continue Outer
+			}
+		}
+
+		putattr(abbrev, int(f.form), 0, 0, nil)
+	}
+}
+
+func putdies(die *DWDie) {
+	for ; die != nil; die = die.link {
+		putdie(die)
+	}
+}
+
+func putdie(die *DWDie) {
+	die.offs = Cpos() - infoo
+	uleb128put(int64(die.abbrev))
+	putattrs(die.abbrev, die.attr)
+	if abbrevs[die.abbrev].children != 0 {
+		putdies(die.child)
+		Cput(0)
+	}
+}
+
+func reverselist(list **DWDie) {
+	curr := *list
+	var prev *DWDie
+	for curr != nil {
+		var next *DWDie = curr.link
+		curr.link = prev
+		prev = curr
+		curr = next
+	}
+
+	*list = prev
+}
+
+func reversetree(list **DWDie) {
+	reverselist(list)
+	for die := *list; die != nil; die = die.link {
+		if abbrevs[die.abbrev].children != 0 {
+			reversetree(&die.child)
+		}
+	}
+}
+
+func newmemberoffsetattr(die *DWDie, offs int32) {
+	var block [20]byte
+
+	i := 0
+	block[i] = DW_OP_plus_uconst
+	i++
+	i += uleb128enc(uint64(offs), block[i:])
+	newattr(die, DW_AT_data_member_location, DW_CLS_BLOCK, int64(i), block[:i])
+}
+
+// GDB doesn't like DW_FORM_addr for DW_AT_location, so emit a
+// location expression that evals to a const.
+func newabslocexprattr(die *DWDie, addr int64, sym *LSym) {
+	newattr(die, DW_AT_location, DW_CLS_ADDRESS, addr, sym)
+	// below
+}
+
+// Lookup predefined types
+func lookup_or_diag(n string) *LSym {
+	s := Linkrlookup(Ctxt, n, 0)
+	if s == nil || s.Size == 0 {
+		Exitf("dwarf: missing type: %s", n)
+	}
+
+	return s
+}
+
+func dotypedef(parent *DWDie, name string, def *DWDie) {
+	// Only emit typedefs for real names.
+	if strings.HasPrefix(name, "map[") {
+		return
+	}
+	if strings.HasPrefix(name, "struct {") {
+		return
+	}
+	if strings.HasPrefix(name, "chan ") {
+		return
+	}
+	if name[0] == '[' || name[0] == '*' {
+		return
+	}
+	if def == nil {
+		Diag("dwarf: bad def in dotypedef")
+	}
+
+	// The typedef entry must be created after the def,
+	// 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)
+
+	newrefattr(die, DW_AT_type, def)
+}
+
+// Define gotype, for composite ones recurse into constituents.
+func defgotype(gotype *LSym) *DWDie {
+	if gotype == nil {
+		return mustFind(&dwtypes, "<unspecified>")
+	}
+
+	if !strings.HasPrefix(gotype.Name, "type.") {
+		Diag("dwarf: type name doesn't start with \".type\": %s", gotype.Name)
+		return mustFind(&dwtypes, "<unspecified>")
+	}
+
+	name := gotype.Name[5:] // could also decode from Type.string
+
+	die := find(&dwtypes, name)
+
+	if die != nil {
+		return die
+	}
+
+	if false && Debug['v'] > 2 {
+		fmt.Printf("new type: %v\n", gotype)
+	}
+
+	kind := decodetype_kind(gotype)
+	bytesize := decodetype_size(gotype)
+
+	switch kind {
+	case obj.KindBool:
+		die = newdie(&dwtypes, DW_ABRV_BASETYPE, name)
+		newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_boolean, 0)
+		newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
+
+	case obj.KindInt,
+		obj.KindInt8,
+		obj.KindInt16,
+		obj.KindInt32,
+		obj.KindInt64:
+		die = newdie(&dwtypes, DW_ABRV_BASETYPE, name)
+		newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_signed, 0)
+		newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
+
+	case obj.KindUint,
+		obj.KindUint8,
+		obj.KindUint16,
+		obj.KindUint32,
+		obj.KindUint64,
+		obj.KindUintptr:
+		die = newdie(&dwtypes, DW_ABRV_BASETYPE, name)
+		newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_unsigned, 0)
+		newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
+
+	case obj.KindFloat32,
+		obj.KindFloat64:
+		die = newdie(&dwtypes, DW_ABRV_BASETYPE, name)
+		newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_float, 0)
+		newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
+
+	case obj.KindComplex64,
+		obj.KindComplex128:
+		die = newdie(&dwtypes, DW_ABRV_BASETYPE, name)
+		newattr(die, DW_AT_encoding, DW_CLS_CONSTANT, DW_ATE_complex_float, 0)
+		newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
+
+	case obj.KindArray:
+		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)
+		newrefattr(die, DW_AT_type, defgotype(s))
+		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)
+
+		newrefattr(fld, DW_AT_type, mustFind(&dwtypes, "uintptr"))
+
+	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)
+		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, mustFind(&dwtypes, "void"))
+		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))
+		}
+
+		if decodetype_funcdotdotdot(gotype) != 0 {
+			newdie(die, DW_ABRV_DOTDOTDOT, "...")
+		}
+		nfields = decodetype_funcoutcount(gotype)
+		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)))
+		}
+
+	case obj.KindInterface:
+		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))
+		var s *LSym
+		if nfields == 0 {
+			s = lookup_or_diag("type.runtime.eface")
+		} else {
+			s = lookup_or_diag("type.runtime.iface")
+		}
+		newrefattr(die, DW_AT_type, defgotype(s))
+
+	case obj.KindMap:
+		die = newdie(&dwtypes, DW_ABRV_MAPTYPE, name)
+		s := decodetype_mapkey(gotype)
+		newrefattr(die, DW_AT_go_key, defgotype(s))
+		s = decodetype_mapvalue(gotype)
+		newrefattr(die, DW_AT_go_elem, defgotype(s))
+
+	case obj.KindPtr:
+		die = newdie(&dwtypes, DW_ABRV_PTRTYPE, name)
+		dotypedef(&dwtypes, name, die)
+		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)
+		newrefattr(die, DW_AT_go_elem, defgotype(s))
+
+	case obj.KindString:
+		die = newdie(&dwtypes, DW_ABRV_STRINGTYPE, name)
+		newattr(die, DW_AT_byte_size, DW_CLS_CONSTANT, bytesize, 0)
+
+	case obj.KindStruct:
+		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)
+		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 == "" {
+				f = s.Name[5:] // skip "type."
+			}
+			fld = newdie(die, DW_ABRV_STRUCTFIELD, f)
+			newrefattr(fld, DW_AT_type, defgotype(s))
+			newmemberoffsetattr(fld, int32(decodetype_structfieldoffs(gotype, i)))
+		}
+
+	case obj.KindUnsafePointer:
+		die = newdie(&dwtypes, DW_ABRV_BARE_PTRTYPE, name)
+
+	default:
+		Diag("dwarf: definition of unknown kind %d: %s", kind, gotype.Name)
+		die = newdie(&dwtypes, DW_ABRV_TYPEDECL, name)
+		newrefattr(die, DW_AT_type, mustFind(&dwtypes, "<unspecified>"))
+	}
+
+	newattr(die, DW_AT_go_kind, DW_CLS_CONSTANT, int64(kind), 0)
+
+	return die
+}
+
+// Find or construct *T given T.
+func defptrto(dwtype *DWDie) *DWDie {
+	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)
+	}
+
+	return die
+}
+
+// Copies src's children into dst. Copies attributes by value.
+// DWAttr.data is copied as pointer only.  If except is one of
+// the top-level children, it will not be copied.
+func copychildrenexcept(dst *DWDie, src *DWDie, except *DWDie) {
+	var c *DWDie
+	var a *DWAttr
+
+	for src = src.child; src != nil; src = src.link {
+		if src == except {
+			continue
+		}
+		c = newdie(dst, src.abbrev, getattr(src, DW_AT_name).data.(string))
+		for a = src.attr; a != nil; a = a.link {
+			newattr(c, a.atr, int(a.cls), a.value, a.data)
+		}
+		copychildrenexcept(c, src, nil)
+	}
+
+	reverselist(&dst.child)
+}
+
+func copychildren(dst *DWDie, src *DWDie) {
+	copychildrenexcept(dst, src, nil)
+}
+
+// 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) {
+	child := mustFind(structdie, field)
+	if child == nil {
+		return
+	}
+
+	a := getattr(child, DW_AT_type)
+	if a != nil {
+		a.data = dwtype
+	} else {
+		newrefattr(child, DW_AT_type, dwtype)
+	}
+}
+
+func synthesizestringtypes(die *DWDie) {
+	prototype := walktypedef(defgotype(lookup_or_diag("type.runtime._string")))
+	if prototype == nil {
+		return
+	}
+
+	for ; die != nil; die = die.link {
+		if die.abbrev != DW_ABRV_STRINGTYPE {
+			continue
+		}
+		copychildren(die, prototype)
+	}
+}
+
+func synthesizeslicetypes(die *DWDie) {
+	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
+		}
+		copychildren(die, prototype)
+		elem = getattr(die, DW_AT_go_elem).data.(*DWDie)
+		substitutetype(die, "array", defptrto(elem))
+	}
+}
+
+func mkinternaltypename(base string, arg1 string, arg2 string) string {
+	var buf string
+
+	if arg2 == "" {
+		buf = fmt.Sprintf("%s<%s>", base, arg1)
+	} else {
+		buf = fmt.Sprintf("%s<%s,%s>", base, arg1, arg2)
+	}
+	n := buf
+	return n
+}
+
+// synthesizemaptypes is way too closely married to runtime/hashmap.c
+const (
+	MaxKeySize = 128
+	MaxValSize = 128
+	BucketSize = 8
+)
+
+func synthesizemaptypes(die *DWDie) {
+	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
+		}
+
+		keytype = walktypedef(getattr(die, DW_AT_go_key).data.(*DWDie))
+		valtype = walktypedef(getattr(die, DW_AT_go_elem).data.(*DWDie))
+
+		// compute size info like hashmap.c does.
+		a = getattr(keytype, DW_AT_byte_size)
+
+		if a != nil {
+			keysize = int(a.value)
+		} else {
+			keysize = Thearch.Ptrsize
+		}
+		a = getattr(valtype, DW_AT_byte_size)
+		if a != nil {
+			valsize = int(a.value)
+		} else {
+			valsize = Thearch.Ptrsize
+		}
+		indirect_key = 0
+		indirect_val = 0
+		if keysize > MaxKeySize {
+			keysize = Thearch.Ptrsize
+			indirect_key = 1
+		}
+
+		if valsize > MaxValSize {
+			valsize = Thearch.Ptrsize
+			indirect_val = 1
+		}
+
+		// Construct type to represent an array of BucketSize keys
+		dwhk = newdie(&dwtypes, DW_ABRV_ARRAYTYPE, mkinternaltypename("[]key", getattr(keytype, DW_AT_name).data.(string), ""))
+
+		newattr(dwhk, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize*int64(keysize), 0)
+		t = keytype
+		if indirect_key != 0 {
+			t = defptrto(keytype)
+		}
+		newrefattr(dwhk, DW_AT_type, t)
+		fld = newdie(dwhk, DW_ABRV_ARRAYRANGE, "size")
+		newattr(fld, DW_AT_count, DW_CLS_CONSTANT, BucketSize, 0)
+		newrefattr(fld, DW_AT_type, mustFind(&dwtypes, "uintptr"))
+
+		// Construct type to represent an array of BucketSize values
+		dwhv = newdie(&dwtypes, DW_ABRV_ARRAYTYPE, mkinternaltypename("[]val", getattr(valtype, DW_AT_name).data.(string), ""))
+
+		newattr(dwhv, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize*int64(valsize), 0)
+		t = valtype
+		if indirect_val != 0 {
+			t = defptrto(valtype)
+		}
+		newrefattr(dwhv, DW_AT_type, t)
+		fld = newdie(dwhv, DW_ABRV_ARRAYRANGE, "size")
+		newattr(fld, DW_AT_count, DW_CLS_CONSTANT, BucketSize, 0)
+		newrefattr(fld, DW_AT_type, mustFind(&dwtypes, "uintptr"))
+
+		// Construct bucket<K,V>
+		dwhb = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, mkinternaltypename("bucket", getattr(keytype, DW_AT_name).data.(string), getattr(valtype, DW_AT_name).data.(string)))
+
+		// Copy over all fields except the field "data" from the generic bucket.
+		// "data" will be replaced with keys/values below.
+		copychildrenexcept(dwhb, bucket, find(bucket, "data"))
+
+		fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "keys")
+		newrefattr(fld, DW_AT_type, dwhk)
+		newmemberoffsetattr(fld, BucketSize)
+		fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "values")
+		newrefattr(fld, DW_AT_type, dwhv)
+		newmemberoffsetattr(fld, BucketSize+BucketSize*int32(keysize))
+		fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "overflow")
+		newrefattr(fld, DW_AT_type, defptrto(dwhb))
+		newmemberoffsetattr(fld, BucketSize+BucketSize*(int32(keysize)+int32(valsize)))
+		if Thearch.Regsize > Thearch.Ptrsize {
+			fld = newdie(dwhb, DW_ABRV_STRUCTFIELD, "pad")
+			newrefattr(fld, DW_AT_type, mustFind(&dwtypes, "uintptr"))
+			newmemberoffsetattr(fld, BucketSize+BucketSize*(int32(keysize)+int32(valsize))+int32(Thearch.Ptrsize))
+		}
+
+		newattr(dwhb, DW_AT_byte_size, DW_CLS_CONSTANT, BucketSize+BucketSize*int64(keysize)+BucketSize*int64(valsize)+int64(Thearch.Regsize), 0)
+
+		// Construct hash<K,V>
+		dwh = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, mkinternaltypename("hash", getattr(keytype, DW_AT_name).data.(string), getattr(valtype, DW_AT_name).data.(string)))
+
+		copychildren(dwh, hash)
+		substitutetype(dwh, "buckets", defptrto(dwhb))
+		substitutetype(dwh, "oldbuckets", defptrto(dwhb))
+		newattr(dwh, DW_AT_byte_size, DW_CLS_CONSTANT, getattr(hash, DW_AT_byte_size).value, nil)
+
+		// make map type a pointer to hash<K,V>
+		newrefattr(die, DW_AT_type, defptrto(dwh))
+	}
+}
+
+func synthesizechantypes(die *DWDie) {
+	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)
+
+	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
+		}
+		elemtype = getattr(die, DW_AT_go_elem).data.(*DWDie)
+		a = getattr(elemtype, DW_AT_byte_size)
+		if a != nil {
+			elemsize = int(a.value)
+		} else {
+			elemsize = Thearch.Ptrsize
+		}
+
+		// sudog<T>
+		dws = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, mkinternaltypename("sudog", getattr(elemtype, DW_AT_name).data.(string), ""))
+
+		copychildren(dws, sudog)
+		substitutetype(dws, "elem", elemtype)
+		if elemsize > 8 {
+			elemsize -= 8
+		} else {
+			elemsize = 0
+		}
+		newattr(dws, DW_AT_byte_size, DW_CLS_CONSTANT, int64(sudogsize)+int64(elemsize), nil)
+
+		// waitq<T>
+		dww = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, mkinternaltypename("waitq", getattr(elemtype, DW_AT_name).data.(string), ""))
+
+		copychildren(dww, waitq)
+		substitutetype(dww, "first", defptrto(dws))
+		substitutetype(dww, "last", defptrto(dws))
+		newattr(dww, DW_AT_byte_size, DW_CLS_CONSTANT, getattr(waitq, DW_AT_byte_size).value, nil)
+
+		// hchan<T>
+		dwh = newdie(&dwtypes, DW_ABRV_STRUCTTYPE, mkinternaltypename("hchan", getattr(elemtype, DW_AT_name).data.(string), ""))
+
+		copychildren(dwh, hchan)
+		substitutetype(dwh, "recvq", dww)
+		substitutetype(dwh, "sendq", dww)
+		newattr(dwh, DW_AT_byte_size, DW_CLS_CONSTANT, getattr(hchan, DW_AT_byte_size).value, nil)
+
+		newrefattr(die, DW_AT_type, defptrto(dwh))
+	}
+}
+
+// For use with pass.c::genasmsym
+func defdwsymb(sym *LSym, s string, t int, v int64, size int64, ver int, gotype *LSym) {
+	if strings.HasPrefix(s, "go.string.") {
+		return
+	}
+	if strings.HasPrefix(s, "runtime.gcbits.") {
+		return
+	}
+
+	if strings.HasPrefix(s, "type.") && s != "type.*" && !strings.HasPrefix(s, "type..") {
+		defgotype(sym)
+		return
+	}
+
+	var dv *DWDie
+
+	var dt *DWDie
+	switch t {
+	default:
+		return
+
+	case 'd', 'b', 'D', 'B':
+		dv = newdie(&dwglobals, DW_ABRV_VARIABLE, s)
+		newabslocexprattr(dv, v, sym)
+		if ver == 0 {
+			newattr(dv, DW_AT_external, DW_CLS_FLAG, 1, 0)
+		}
+		fallthrough
+
+	case 'a', 'p':
+		dt = defgotype(gotype)
+	}
+
+	if dv != nil {
+		newrefattr(dv, DW_AT_type, dt)
+	}
+}
+
+func movetomodule(parent *DWDie) {
+	die := dwroot.child.child
+	for die.link != nil {
+		die = die.link
+	}
+	die.link = parent.child
+}
+
+// If the pcln table contains runtime/runtime.go, use that to set gdbscript path.
+func finddebugruntimepath(s *LSym) {
+	if gdbscript != "" {
+		return
+	}
+
+	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 {
+			gdbscript = f.Name[:i] + "runtime/runtime-gdb.py"
+			break
+		}
+	}
+}
+
+/*
+ * Generate short opcodes when possible, long ones when necessary.
+ * See section 6.2.5
+ */
+const (
+	LINE_BASE   = -1
+	LINE_RANGE  = 4
+	OPCODE_BASE = 10
+)
+
+func putpclcdelta(delta_pc int64, delta_lc int64) {
+	if LINE_BASE <= delta_lc && delta_lc < LINE_BASE+LINE_RANGE {
+		var opcode int64 = OPCODE_BASE + (delta_lc - LINE_BASE) + (LINE_RANGE * delta_pc)
+		if OPCODE_BASE <= opcode && opcode < 256 {
+			Cput(uint8(opcode))
+			return
+		}
+	}
+
+	if delta_pc != 0 {
+		Cput(DW_LNS_advance_pc)
+		sleb128put(delta_pc)
+	}
+
+	Cput(DW_LNS_advance_line)
+	sleb128put(delta_lc)
+	Cput(DW_LNS_copy)
+}
+
+func newcfaoffsetattr(die *DWDie, offs int32) {
+	var block [20]byte
+
+	i := 0
+
+	block[i] = DW_OP_call_frame_cfa
+	i++
+	if offs != 0 {
+		block[i] = DW_OP_consts
+		i++
+		i += sleb128enc(int64(offs), block[i:])
+		block[i] = DW_OP_plus
+		i++
+	}
+
+	newattr(die, DW_AT_location, DW_CLS_BLOCK, int64(i), block[:i])
+}
+
+func mkvarname(name string, da int) string {
+	buf := fmt.Sprintf("%s#%d", name, da)
+	n := buf
+	return n
+}
+
+/*
+ * Walk prog table, emit line program and build DIE tree.
+ */
+
+// flush previous compilation unit.
+func flushunit(dwinfo *DWDie, pc int64, pcsym *LSym, unitstart int64, header_length int32) {
+	if dwinfo != nil && pc != 0 {
+		newattr(dwinfo, DW_AT_high_pc, DW_CLS_ADDRESS, pc+1, pcsym)
+	}
+
+	if unitstart >= 0 {
+		Cput(0) // start extended opcode
+		uleb128put(1)
+		Cput(DW_LNE_end_sequence)
+
+		here := Cpos()
+		Cseek(unitstart)
+		Thearch.Lput(uint32(here - unitstart - 4)) // unit_length
+		Thearch.Wput(2)                            // dwarf version
+		Thearch.Lput(uint32(header_length))        // header length starting here
+		Cseek(here)
+	}
+}
+
+func getCompilationDir() string {
+	if dir, err := os.Getwd(); err == nil {
+		return dir
+	}
+	return "/"
+}
+
+func writelines() {
+	if linesec == nil {
+		linesec = Linklookup(Ctxt, ".dwarfline", 0)
+	}
+	linesec.R = linesec.R[:0]
+
+	unitstart := int64(-1)
+	headerend := int64(-1)
+	epc := int64(0)
+	var epcs *LSym
+	lineo = Cpos()
+	var dwinfo *DWDie
+
+	flushunit(dwinfo, epc, epcs, unitstart, int32(headerend-unitstart-10))
+	unitstart = Cpos()
+
+	lang := DW_LANG_Go
+
+	s := Ctxt.Textp
+
+	dwinfo = newdie(&dwroot, DW_ABRV_COMPUNIT, "go")
+	newattr(dwinfo, DW_AT_language, DW_CLS_CONSTANT, int64(lang), 0)
+	newattr(dwinfo, DW_AT_stmt_list, DW_CLS_PTR, unitstart-lineo, 0)
+	newattr(dwinfo, DW_AT_low_pc, DW_CLS_ADDRESS, s.Value, s)
+	// OS X linker requires compilation dir or absolute path in comp unit name to output debug info.
+	compDir := getCompilationDir()
+	newattr(dwinfo, DW_AT_comp_dir, DW_CLS_STRING, int64(len(compDir)), compDir)
+
+	// Write .debug_line Line Number Program Header (sec 6.2.4)
+	// Fields marked with (*) must be changed for 64-bit dwarf
+	Thearch.Lput(0) // unit_length (*), will be filled in by flushunit.
+	Thearch.Wput(2) // dwarf version (appendix F)
+	Thearch.Lput(0) // header_length (*), filled in by flushunit.
+
+	// cpos == unitstart + 4 + 2 + 4
+	Cput(1)                // minimum_instruction_length
+	Cput(1)                // default_is_stmt
+	Cput(LINE_BASE & 0xFF) // line_base
+	Cput(LINE_RANGE)       // line_range
+	Cput(OPCODE_BASE)      // opcode_base
+	Cput(0)                // standard_opcode_lengths[1]
+	Cput(1)                // standard_opcode_lengths[2]
+	Cput(1)                // standard_opcode_lengths[3]
+	Cput(1)                // standard_opcode_lengths[4]
+	Cput(1)                // standard_opcode_lengths[5]
+	Cput(0)                // standard_opcode_lengths[6]
+	Cput(0)                // standard_opcode_lengths[7]
+	Cput(0)                // standard_opcode_lengths[8]
+	Cput(1)                // standard_opcode_lengths[9]
+	Cput(0)                // include_directories  (empty)
+
+	files := make([]*LSym, Ctxt.Nhistfile)
+
+	for f := Ctxt.Filesyms; f != nil; f = f.Next {
+		files[f.Value-1] = f
+	}
+
+	for i := 0; int32(i) < Ctxt.Nhistfile; i++ {
+		strnput(files[i].Name, len(files[i].Name)+4)
+	}
+
+	// 4 zeros: the string termination + 3 fields.
+	Cput(0)
+	// terminate file_names.
+	headerend = Cpos()
+
+	Cput(0) // start extended opcode
+	uleb128put(1 + int64(Thearch.Ptrsize))
+	Cput(DW_LNE_set_address)
+
+	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
+
+		dwfunc = newdie(dwinfo, DW_ABRV_FUNCTION, s.Name)
+		newattr(dwfunc, DW_AT_low_pc, DW_CLS_ADDRESS, s.Value, s)
+		epc = s.Value + s.Size
+		epcs = s
+		newattr(dwfunc, DW_AT_high_pc, DW_CLS_ADDRESS, epc, s)
+		if s.Version == 0 {
+			newattr(dwfunc, DW_AT_external, DW_CLS_FLAG, 1, 0)
+		}
+
+		if s.Pcln == nil {
+			continue
+		}
+
+		finddebugruntimepath(s)
+
+		pciterinit(Ctxt, &pcfile, &s.Pcln.Pcfile)
+		pciterinit(Ctxt, &pcline, &s.Pcln.Pcline)
+		epc = pc
+		for pcfile.done == 0 && pcline.done == 0 {
+			if epc-s.Value >= int64(pcfile.nextpc) {
+				pciternext(&pcfile)
+				continue
+			}
+
+			if epc-s.Value >= int64(pcline.nextpc) {
+				pciternext(&pcline)
+				continue
+			}
+
+			if int32(file) != pcfile.value {
+				Cput(DW_LNS_set_file)
+				uleb128put(int64(pcfile.value))
+				file = int(pcfile.value)
+			}
+
+			putpclcdelta(s.Value+int64(pcline.pc)-pc, int64(pcline.value)-int64(line))
+
+			pc = s.Value + int64(pcline.pc)
+			line = int(pcline.value)
+			if pcfile.nextpc < pcline.nextpc {
+				epc = int64(pcfile.nextpc)
+			} else {
+				epc = int64(pcline.nextpc)
+			}
+			epc += s.Value
+		}
+
+		da = 0
+		dwfunc.hash = varhash[:] // enable indexing of children by name
+		varhash = [HASHSIZE]*DWDie{}
+		for a = s.Autom; a != nil; a = a.Link {
+			switch a.Name {
+			case obj.A_AUTO:
+				dt = DW_ABRV_AUTO
+				offs = int64(a.Aoffset)
+				if !haslinkregister() {
+					offs -= int64(Thearch.Ptrsize)
+				}
+
+			case obj.A_PARAM:
+				dt = DW_ABRV_PARAM
+				offs = int64(a.Aoffset)
+				if haslinkregister() {
+					offs += int64(Thearch.Ptrsize)
+				}
+
+			default:
+				continue
+			}
+
+			if strings.Contains(a.Asym.Name, ".autotmp_") {
+				continue
+			}
+			if find(dwfunc, a.Asym.Name) != nil {
+				n = mkvarname(a.Asym.Name, da)
+			} else {
+				n = a.Asym.Name
+			}
+
+			// Drop the package prefix from locals and arguments.
+			_ = nn
+			if i := strings.LastIndex(n, "."); i >= 0 {
+				n = n[i+1:]
+			}
+
+			dwvar = newdie(dwfunc, dt, n)
+			newcfaoffsetattr(dwvar, int32(offs))
+			newrefattr(dwvar, DW_AT_type, defgotype(a.Gotype))
+
+			// push dwvar down dwfunc->child to preserve order
+			newattr(dwvar, DW_AT_internal_location, DW_CLS_CONSTANT, offs, nil)
+
+			dwfunc.child = dwvar.link // take dwvar out from the top of the list
+			for dws = &dwfunc.child; *dws != nil; dws = &(*dws).link {
+				if offs > getattr(*dws, DW_AT_internal_location).value {
+					break
+				}
+			}
+			dwvar.link = *dws
+			*dws = dwvar
+
+			da++
+		}
+
+		dwfunc.hash = nil
+	}
+
+	flushunit(dwinfo, epc, epcs, unitstart, int32(headerend-unitstart-10))
+	linesize = Cpos() - lineo
+}
+
+/*
+ *  Emit .debug_frame
+ */
+const (
+	CIERESERVE          = 16
+	DATAALIGNMENTFACTOR = -4
+)
+
+func putpccfadelta(deltapc int64, cfa int64) {
+	Cput(DW_CFA_def_cfa_offset_sf)
+	sleb128put(cfa / DATAALIGNMENTFACTOR)
+
+	if deltapc < 0x40 {
+		Cput(uint8(DW_CFA_advance_loc + deltapc))
+	} else if deltapc < 0x100 {
+		Cput(DW_CFA_advance_loc1)
+		Cput(uint8(deltapc))
+	} else if deltapc < 0x10000 {
+		Cput(DW_CFA_advance_loc2)
+		Thearch.Wput(uint16(deltapc))
+	} else {
+		Cput(DW_CFA_advance_loc4)
+		Thearch.Lput(uint32(deltapc))
+	}
+}
+
+func writeframes() {
+	if framesec == nil {
+		framesec = Linklookup(Ctxt, ".dwarfframe", 0)
+	}
+	framesec.R = framesec.R[:0]
+	frameo = Cpos()
+
+	// Emit the CIE, Section 6.4.1
+	Thearch.Lput(CIERESERVE)              // initial length, must be multiple of thearch.ptrsize
+	Thearch.Lput(0xffffffff)              // cid.
+	Cput(3)                               // dwarf version (appendix F)
+	Cput(0)                               // augmentation ""
+	uleb128put(1)                         // code_alignment_factor
+	sleb128put(DATAALIGNMENTFACTOR)       // guess
+	uleb128put(int64(Thearch.Dwarfreglr)) // return_address_register
+
+	Cput(DW_CFA_def_cfa)
+
+	uleb128put(int64(Thearch.Dwarfregsp)) // register SP (**ABI-dependent, defined in l.h)
+	if haslinkregister() {
+		uleb128put(int64(0)) // offset
+	} else {
+		uleb128put(int64(Thearch.Ptrsize)) // offset
+	}
+
+	Cput(DW_CFA_offset_extended)
+	uleb128put(int64(Thearch.Dwarfreglr)) // return address
+	if haslinkregister() {
+		uleb128put(int64(0) / DATAALIGNMENTFACTOR) // at cfa - 0
+	} else {
+		uleb128put(int64(-Thearch.Ptrsize) / DATAALIGNMENTFACTOR) // at cfa - x*4
+	}
+
+	// 4 is to exclude the length field.
+	pad := CIERESERVE + frameo + 4 - Cpos()
+
+	if pad < 0 {
+		Exitf("dwarf: CIERESERVE too small by %d bytes.", -pad)
+	}
+
+	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 {
+			continue
+		}
+
+		fdeo = Cpos()
+
+		// Emit a FDE, Section 6.4.1, starting wit a placeholder.
+		Thearch.Lput(0) // length, must be multiple of thearch.ptrsize
+		Thearch.Lput(0) // Pointer to the CIE above, at offset 0
+		addrput(0)      // initial location
+		addrput(0)      // address range
+
+		for pciterinit(Ctxt, &pcsp, &s.Pcln.Pcsp); pcsp.done == 0; pciternext(&pcsp) {
+			nextpc = pcsp.nextpc
+
+			// pciterinit goes up to the end of the function,
+			// but DWARF expects us to stop just before the end.
+			if int64(nextpc) == s.Size {
+				nextpc--
+				if nextpc < pcsp.pc {
+					continue
+				}
+			}
+
+			if haslinkregister() {
+				putpccfadelta(int64(nextpc)-int64(pcsp.pc), int64(pcsp.value))
+			} else {
+				putpccfadelta(int64(nextpc)-int64(pcsp.pc), int64(Thearch.Ptrsize)+int64(pcsp.value))
+			}
+		}
+
+		fdesize = Cpos() - fdeo - 4 // exclude the length field.
+		pad = Rnd(fdesize, int64(Thearch.Ptrsize)) - fdesize
+		strnput("", int(pad))
+		fdesize += pad
+
+		// Emit the FDE header for real, Section 6.4.1.
+		Cseek(fdeo)
+
+		Thearch.Lput(uint32(fdesize))
+		if Linkmode == LinkExternal {
+			adddwarfrel(framesec, framesym, frameo, 4, 0)
+			adddwarfrel(framesec, s, frameo, Thearch.Ptrsize, 0)
+		} else {
+			Thearch.Lput(0)
+			addrput(s.Value)
+		}
+
+		addrput(s.Size)
+		Cseek(fdeo + 4 + fdesize)
+	}
+
+	Cflush()
+	framesize = Cpos() - frameo
+}
+
+/*
+ *  Walk DWarfDebugInfoEntries, and emit .debug_info
+ */
+const (
+	COMPUNITHEADERSIZE = 4 + 2 + 4 + 1
+)
+
+func writeinfo() {
+	fwdcount = 0
+	if infosec == nil {
+		infosec = Linklookup(Ctxt, ".dwarfinfo", 0)
+	}
+	infosec.R = infosec.R[:0]
+
+	if arangessec == nil {
+		arangessec = Linklookup(Ctxt, ".dwarfaranges", 0)
+	}
+	arangessec.R = arangessec.R[:0]
+
+	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)
+		// Fields marked with (*) must be changed for 64-bit dwarf
+		// This must match COMPUNITHEADERSIZE above.
+		Thearch.Lput(0) // unit_length (*), will be filled in later.
+		Thearch.Wput(2) // dwarf version (appendix F)
+
+		// debug_abbrev_offset (*)
+		if Linkmode == LinkExternal {
+			adddwarfrel(infosec, abbrevsym, infoo, 4, 0)
+		} else {
+			Thearch.Lput(0)
+		}
+
+		Cput(uint8(Thearch.Ptrsize)) // address_size
+
+		putdie(compunit)
+
+		here = Cpos()
+		Cseek(unitstart)
+		Thearch.Lput(uint32(here - unitstart - 4)) // exclude the length field.
+		Cseek(here)
+	}
+
+	Cflush()
+}
+
+/*
+ *  Emit .debug_pubnames/_types.  _info must have been written before,
+ *  because we need die->offs and infoo/infosize;
+ */
+func ispubname(die *DWDie) bool {
+	switch die.abbrev {
+	case DW_ABRV_FUNCTION, DW_ABRV_VARIABLE:
+		a := getattr(die, DW_AT_external)
+		return a != nil && a.value != 0
+	}
+
+	return false
+}
+
+func ispubtype(die *DWDie) bool {
+	return die.abbrev >= DW_ABRV_NULLTYPE
+}
+
+func writepub(ispub func(*DWDie) bool) int64 {
+	var die *DWDie
+	var dwa *DWAttr
+	var unitstart int64
+	var unitend int64
+	var here int64
+
+	sectionstart := Cpos()
+
+	for compunit := dwroot.child; compunit != nil; compunit = compunit.link {
+		unitstart = compunit.offs - COMPUNITHEADERSIZE
+		if compunit.link != nil {
+			unitend = compunit.link.offs - COMPUNITHEADERSIZE
+		} else {
+			unitend = infoo + infosize
+		}
+
+		// Write .debug_pubnames/types	Header (sec 6.1.1)
+		Thearch.Lput(0)                           // unit_length (*), will be filled in later.
+		Thearch.Wput(2)                           // dwarf version (appendix F)
+		Thearch.Lput(uint32(unitstart))           // debug_info_offset (of the Comp unit Header)
+		Thearch.Lput(uint32(unitend - unitstart)) // debug_info_length
+
+		for die = compunit.child; die != nil; die = die.link {
+			if !ispub(die) {
+				continue
+			}
+			Thearch.Lput(uint32(die.offs - unitstart))
+			dwa = getattr(die, DW_AT_name)
+			strnput(dwa.data.(string), int(dwa.value+1))
+		}
+
+		Thearch.Lput(0)
+
+		here = Cpos()
+		Cseek(sectionstart)
+		Thearch.Lput(uint32(here - sectionstart - 4)) // exclude the length field.
+		Cseek(here)
+	}
+
+	return sectionstart
+}
+
+/*
+ *  emit .debug_aranges.  _info must have been written before,
+ *  because we need die->offs of dw_globals.
+ */
+func writearanges() int64 {
+	var b *DWAttr
+	var e *DWAttr
+	var value int64
+
+	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 {
+		b = getattr(compunit, DW_AT_low_pc)
+		if b == nil {
+			continue
+		}
+		e = getattr(compunit, DW_AT_high_pc)
+		if e == nil {
+			continue
+		}
+
+		// Write .debug_aranges	 Header + entry	 (sec 6.1.2)
+		Thearch.Lput(uint32(headersize) + 4*uint32(Thearch.Ptrsize) - 4) // unit_length (*)
+		Thearch.Wput(2)                                                  // dwarf version (appendix F)
+
+		value = compunit.offs - COMPUNITHEADERSIZE // debug_info_offset
+		if Linkmode == LinkExternal {
+			adddwarfrel(arangessec, infosym, sectionstart, 4, value)
+		} else {
+			Thearch.Lput(uint32(value))
+		}
+
+		Cput(uint8(Thearch.Ptrsize))        // address_size
+		Cput(0)                             // segment_size
+		strnput("", headersize-(4+2+4+1+1)) // align to thearch.ptrsize
+
+		if Linkmode == LinkExternal {
+			adddwarfrel(arangessec, b.data.(*LSym), sectionstart, Thearch.Ptrsize, b.value-(b.data.(*LSym)).Value)
+		} else {
+			addrput(b.value)
+		}
+
+		addrput(e.value - b.value)
+		addrput(0)
+		addrput(0)
+	}
+
+	Cflush()
+	return sectionstart
+}
+
+func writegdbscript() int64 {
+	sectionstart := Cpos()
+
+	if gdbscript != "" {
+		Cput(1) // magic 1 byte?
+		strnput(gdbscript, len(gdbscript)+1)
+		Cflush()
+	}
+
+	return sectionstart
+}
+
+func align(size int64) {
+	if HEADTYPE == obj.Hwindows { // Only Windows PE need section align.
+		strnput("", int(Rnd(size, PEFILEALIGN)-size))
+	}
+}
+
+func writedwarfreloc(s *LSym) int64 {
+	var i int
+	var r *Reloc
+
+	start := Cpos()
+	for ri := 0; ri < len(s.R); ri++ {
+		r = &s.R[ri]
+		if Iself {
+			i = Thearch.Elfreloc1(r, int64(r.Off))
+		} else if HEADTYPE == obj.Hdarwin {
+			i = Thearch.Machoreloc1(r, int64(r.Off))
+		} else {
+			i = -1
+		}
+		if i < 0 {
+			Diag("unsupported obj reloc %d/%d to %s", r.Type, r.Siz, r.Sym.Name)
+		}
+	}
+
+	return start
+}
+
+func addmachodwarfsect(prev *Section, name string) *Section {
+	sect := addsection(&Segdwarf, name, 04)
+	sect.Extnum = prev.Extnum + 1
+	sym := Linklookup(Ctxt, name, 0)
+	sym.Sect = sect
+	return sect
+}
+
+/*
+ * This is the main entry point for generating dwarf.  After emitting
+ * the mandatory debug_abbrev section, it calls writelines() to set up
+ * the per-compilation unit part of the DIE tree, while simultaneously
+ * emitting the debug_line section.  When the final tree contains
+ * forward references, it will write the debug_info section in 2
+ * passes.
+ *
+ */
+func Dwarfemitdebugsections() {
+	if Debug['w'] != 0 { // disable dwarf
+		return
+	}
+
+	if Linkmode == LinkExternal {
+		if !Iself && HEADTYPE != obj.Hdarwin {
+			return
+		}
+		if HEADTYPE == obj.Hdarwin {
+			sect := Segdata.Sect
+			// find the last section.
+			for sect.Next != nil {
+				sect = sect.Next
+			}
+			sect = addmachodwarfsect(sect, ".debug_abbrev")
+			sect = addmachodwarfsect(sect, ".debug_line")
+			sect = addmachodwarfsect(sect, ".debug_frame")
+			sect = addmachodwarfsect(sect, ".debug_info")
+
+			infosym = Linklookup(Ctxt, ".debug_info", 0)
+			infosym.Hide = 1
+
+			abbrevsym = Linklookup(Ctxt, ".debug_abbrev", 0)
+			abbrevsym.Hide = 1
+
+			linesym = Linklookup(Ctxt, ".debug_line", 0)
+			linesym.Hide = 1
+
+			framesym = Linklookup(Ctxt, ".debug_frame", 0)
+			framesym.Hide = 1
+		}
+	}
+
+	// For diagnostic messages.
+	newattr(&dwtypes, DW_AT_name, DW_CLS_STRING, int64(len("dwtypes")), "dwtypes")
+
+	mkindex(&dwroot)
+	mkindex(&dwtypes)
+	mkindex(&dwglobals)
+
+	// Some types that must exist to define other ones.
+	newdie(&dwtypes, DW_ABRV_NULLTYPE, "<unspecified>")
+
+	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
+	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)
+
+	// Needed by the prettyprinter code for interface inspection.
+	defgotype(lookup_or_diag("type.runtime._type"))
+
+	defgotype(lookup_or_diag("type.runtime.interfacetype"))
+	defgotype(lookup_or_diag("type.runtime.itab"))
+
+	genasmsym(defdwsymb)
+
+	writeabbrev()
+	align(abbrevsize)
+	writelines()
+	align(linesize)
+	writeframes()
+	align(framesize)
+
+	synthesizestringtypes(dwtypes.child)
+	synthesizeslicetypes(dwtypes.child)
+	synthesizemaptypes(dwtypes.child)
+	synthesizechantypes(dwtypes.child)
+
+	reversetree(&dwroot.child)
+	reversetree(&dwtypes.child)
+	reversetree(&dwglobals.child)
+
+	movetomodule(&dwtypes)
+	movetomodule(&dwglobals)
+
+	infoo = Cpos()
+	writeinfo()
+	infoe := Cpos()
+	pubnameso = infoe
+	pubtypeso = infoe
+	arangeso = infoe
+	gdbscripto = infoe
+
+	if fwdcount > 0 {
+		if Debug['v'] != 0 {
+			fmt.Fprintf(&Bso, "%5.2f dwarf pass 2.\n", obj.Cputime())
+		}
+		Cseek(infoo)
+		writeinfo()
+		if fwdcount > 0 {
+			Exitf("dwarf: unresolved references after first dwarf info pass")
+		}
+
+		if infoe != Cpos() {
+			Exitf("dwarf: inconsistent second dwarf info pass")
+		}
+	}
+
+	infosize = infoe - infoo
+	align(infosize)
+
+	pubnameso = writepub(ispubname)
+	pubnamessize = Cpos() - pubnameso
+	align(pubnamessize)
+
+	pubtypeso = writepub(ispubtype)
+	pubtypessize = Cpos() - pubtypeso
+	align(pubtypessize)
+
+	arangeso = writearanges()
+	arangessize = Cpos() - arangeso
+	align(arangessize)
+
+	gdbscripto = writegdbscript()
+	gdbscriptsize = Cpos() - gdbscripto
+	align(gdbscriptsize)
+
+	for Cpos()&7 != 0 {
+		Cput(0)
+	}
+	if HEADTYPE != obj.Hdarwin {
+		dwarfemitreloc()
+	}
+}
+
+func dwarfemitreloc() {
+	if Debug['w'] != 0 { // disable dwarf
+		return
+	}
+	inforeloco = writedwarfreloc(infosec)
+	inforelocsize = Cpos() - inforeloco
+	align(inforelocsize)
+
+	arangesreloco = writedwarfreloc(arangessec)
+	arangesrelocsize = Cpos() - arangesreloco
+	align(arangesrelocsize)
+
+	linereloco = writedwarfreloc(linesec)
+	linerelocsize = Cpos() - linereloco
+	align(linerelocsize)
+
+	framereloco = writedwarfreloc(framesec)
+	framerelocsize = Cpos() - framereloco
+	align(framerelocsize)
+}
+
+/*
+ *  Elf.
+ */
+const (
+	ElfStrDebugAbbrev = iota
+	ElfStrDebugAranges
+	ElfStrDebugFrame
+	ElfStrDebugInfo
+	ElfStrDebugLine
+	ElfStrDebugLoc
+	ElfStrDebugMacinfo
+	ElfStrDebugPubNames
+	ElfStrDebugPubTypes
+	ElfStrDebugRanges
+	ElfStrDebugStr
+	ElfStrGDBScripts
+	ElfStrRelDebugInfo
+	ElfStrRelDebugAranges
+	ElfStrRelDebugLine
+	ElfStrRelDebugFrame
+	NElfStrDbg
+)
+
+var elfstrdbg [NElfStrDbg]int64
+
+func dwarfaddshstrings(shstrtab *LSym) {
+	if Debug['w'] != 0 { // disable dwarf
+		return
+	}
+
+	elfstrdbg[ElfStrDebugAbbrev] = Addstring(shstrtab, ".debug_abbrev")
+	elfstrdbg[ElfStrDebugAranges] = Addstring(shstrtab, ".debug_aranges")
+	elfstrdbg[ElfStrDebugFrame] = Addstring(shstrtab, ".debug_frame")
+	elfstrdbg[ElfStrDebugInfo] = Addstring(shstrtab, ".debug_info")
+	elfstrdbg[ElfStrDebugLine] = Addstring(shstrtab, ".debug_line")
+	elfstrdbg[ElfStrDebugLoc] = Addstring(shstrtab, ".debug_loc")
+	elfstrdbg[ElfStrDebugMacinfo] = Addstring(shstrtab, ".debug_macinfo")
+	elfstrdbg[ElfStrDebugPubNames] = Addstring(shstrtab, ".debug_pubnames")
+	elfstrdbg[ElfStrDebugPubTypes] = Addstring(shstrtab, ".debug_pubtypes")
+	elfstrdbg[ElfStrDebugRanges] = Addstring(shstrtab, ".debug_ranges")
+	elfstrdbg[ElfStrDebugStr] = Addstring(shstrtab, ".debug_str")
+	elfstrdbg[ElfStrGDBScripts] = Addstring(shstrtab, ".debug_gdb_scripts")
+	if Linkmode == LinkExternal {
+		switch Thearch.Thechar {
+		case '6', '7', '9':
+			elfstrdbg[ElfStrRelDebugInfo] = Addstring(shstrtab, ".rela.debug_info")
+			elfstrdbg[ElfStrRelDebugAranges] = Addstring(shstrtab, ".rela.debug_aranges")
+			elfstrdbg[ElfStrRelDebugLine] = Addstring(shstrtab, ".rela.debug_line")
+			elfstrdbg[ElfStrRelDebugFrame] = Addstring(shstrtab, ".rela.debug_frame")
+		default:
+			elfstrdbg[ElfStrRelDebugInfo] = Addstring(shstrtab, ".rel.debug_info")
+			elfstrdbg[ElfStrRelDebugAranges] = Addstring(shstrtab, ".rel.debug_aranges")
+			elfstrdbg[ElfStrRelDebugLine] = Addstring(shstrtab, ".rel.debug_line")
+			elfstrdbg[ElfStrRelDebugFrame] = Addstring(shstrtab, ".rel.debug_frame")
+		}
+
+		infosym = Linklookup(Ctxt, ".debug_info", 0)
+		infosym.Hide = 1
+
+		abbrevsym = Linklookup(Ctxt, ".debug_abbrev", 0)
+		abbrevsym.Hide = 1
+
+		linesym = Linklookup(Ctxt, ".debug_line", 0)
+		linesym.Hide = 1
+
+		framesym = Linklookup(Ctxt, ".debug_frame", 0)
+		framesym.Hide = 1
+	}
+}
+
+// Add section symbols for DWARF debug info.  This is called before
+// dwarfaddelfheaders.
+func dwarfaddelfsectionsyms() {
+	if infosym != nil {
+		infosympos = Cpos()
+		putelfsectionsym(infosym, 0)
+	}
+
+	if abbrevsym != nil {
+		abbrevsympos = Cpos()
+		putelfsectionsym(abbrevsym, 0)
+	}
+
+	if linesym != nil {
+		linesympos = Cpos()
+		putelfsectionsym(linesym, 0)
+	}
+
+	if framesym != nil {
+		framesympos = Cpos()
+		putelfsectionsym(framesym, 0)
+	}
+}
+
+func dwarfaddelfrelocheader(elfstr int, shdata *ElfShdr, off int64, size int64) {
+	sh := newElfShdr(elfstrdbg[elfstr])
+	switch Thearch.Thechar {
+	case '6', '7', '9':
+		sh.type_ = SHT_RELA
+	default:
+		sh.type_ = SHT_REL
+	}
+
+	sh.entsize = uint64(Thearch.Ptrsize) * 2
+	if sh.type_ == SHT_RELA {
+		sh.entsize += uint64(Thearch.Ptrsize)
+	}
+	sh.link = uint32(elfshname(".symtab").shnum)
+	sh.info = uint32(shdata.shnum)
+	sh.off = uint64(off)
+	sh.size = uint64(size)
+	sh.addralign = uint64(Thearch.Ptrsize)
+}
+
+func dwarfaddelfheaders() {
+	if Debug['w'] != 0 { // disable dwarf
+		return
+	}
+
+	sh := newElfShdr(elfstrdbg[ElfStrDebugAbbrev])
+	sh.type_ = SHT_PROGBITS
+	sh.off = uint64(abbrevo)
+	sh.size = uint64(abbrevsize)
+	sh.addralign = 1
+	if abbrevsympos > 0 {
+		putelfsymshndx(abbrevsympos, sh.shnum)
+	}
+
+	sh = newElfShdr(elfstrdbg[ElfStrDebugLine])
+	sh.type_ = SHT_PROGBITS
+	sh.off = uint64(lineo)
+	sh.size = uint64(linesize)
+	sh.addralign = 1
+	if linesympos > 0 {
+		putelfsymshndx(linesympos, sh.shnum)
+	}
+	shline := sh
+
+	sh = newElfShdr(elfstrdbg[ElfStrDebugFrame])
+	sh.type_ = SHT_PROGBITS
+	sh.off = uint64(frameo)
+	sh.size = uint64(framesize)
+	sh.addralign = 1
+	if framesympos > 0 {
+		putelfsymshndx(framesympos, sh.shnum)
+	}
+	shframe := sh
+
+	sh = newElfShdr(elfstrdbg[ElfStrDebugInfo])
+	sh.type_ = SHT_PROGBITS
+	sh.off = uint64(infoo)
+	sh.size = uint64(infosize)
+	sh.addralign = 1
+	if infosympos > 0 {
+		putelfsymshndx(infosympos, sh.shnum)
+	}
+	shinfo := sh
+
+	if pubnamessize > 0 {
+		sh := newElfShdr(elfstrdbg[ElfStrDebugPubNames])
+		sh.type_ = SHT_PROGBITS
+		sh.off = uint64(pubnameso)
+		sh.size = uint64(pubnamessize)
+		sh.addralign = 1
+	}
+
+	if pubtypessize > 0 {
+		sh := newElfShdr(elfstrdbg[ElfStrDebugPubTypes])
+		sh.type_ = SHT_PROGBITS
+		sh.off = uint64(pubtypeso)
+		sh.size = uint64(pubtypessize)
+		sh.addralign = 1
+	}
+
+	var sharanges *ElfShdr
+	if arangessize != 0 {
+		sh := newElfShdr(elfstrdbg[ElfStrDebugAranges])
+		sh.type_ = SHT_PROGBITS
+		sh.off = uint64(arangeso)
+		sh.size = uint64(arangessize)
+		sh.addralign = 1
+		sharanges = sh
+	}
+
+	if gdbscriptsize != 0 {
+		sh := newElfShdr(elfstrdbg[ElfStrGDBScripts])
+		sh.type_ = SHT_PROGBITS
+		sh.off = uint64(gdbscripto)
+		sh.size = uint64(gdbscriptsize)
+		sh.addralign = 1
+	}
+
+	if inforelocsize != 0 {
+		dwarfaddelfrelocheader(ElfStrRelDebugInfo, shinfo, inforeloco, inforelocsize)
+	}
+
+	if arangesrelocsize != 0 {
+		dwarfaddelfrelocheader(ElfStrRelDebugAranges, sharanges, arangesreloco, arangesrelocsize)
+	}
+
+	if linerelocsize != 0 {
+		dwarfaddelfrelocheader(ElfStrRelDebugLine, shline, linereloco, linerelocsize)
+	}
+
+	if framerelocsize != 0 {
+		dwarfaddelfrelocheader(ElfStrRelDebugFrame, shframe, framereloco, framerelocsize)
+	}
+}
+
+/*
+ * Macho
+ */
+func dwarfaddmachoheaders(ms *MachoSeg) {
+	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 := Rnd(int64(Segdwarf.Fileoff), 0x1000)
+	addr := Segdata.Vaddr + Segdata.Length
+
+	nsect := 4
+	if pubnamessize > 0 {
+		nsect++
+	}
+	if pubtypessize > 0 {
+		nsect++
+	}
+	if arangessize > 0 {
+		nsect++
+	}
+	if gdbscriptsize > 0 {
+		nsect++
+	}
+
+	if Linkmode != LinkExternal {
+		ms = newMachoSeg("__DWARF", nsect)
+		ms.fileoffset = uint64(fakestart)
+		ms.filesize = Segdwarf.Filelen
+		ms.vaddr = addr
+	}
+
+	msect := newMachoSect(ms, "__debug_abbrev", "__DWARF")
+	msect.off = uint32(abbrevo)
+	msect.size = uint64(abbrevsize)
+	msect.addr = addr
+	addr += msect.size
+	msect.flag = 0x02000000
+	if abbrevsym != nil {
+		abbrevsym.Value = int64(msect.addr)
+	}
+
+	msect = newMachoSect(ms, "__debug_line", "__DWARF")
+	msect.off = uint32(lineo)
+	msect.size = uint64(linesize)
+	msect.addr = addr
+	addr += msect.size
+	msect.flag = 0x02000000
+	if linesym != nil {
+		linesym.Value = int64(msect.addr)
+	}
+	if linerelocsize > 0 {
+		msect.nreloc = uint32(len(linesec.R))
+		msect.reloc = uint32(linereloco)
+	}
+
+	msect = newMachoSect(ms, "__debug_frame", "__DWARF")
+	msect.off = uint32(frameo)
+	msect.size = uint64(framesize)
+	msect.addr = addr
+	addr += msect.size
+	msect.flag = 0x02000000
+	if framesym != nil {
+		framesym.Value = int64(msect.addr)
+	}
+	if framerelocsize > 0 {
+		msect.nreloc = uint32(len(framesec.R))
+		msect.reloc = uint32(framereloco)
+	}
+
+	msect = newMachoSect(ms, "__debug_info", "__DWARF")
+	msect.off = uint32(infoo)
+	msect.size = uint64(infosize)
+	msect.addr = addr
+	addr += msect.size
+	msect.flag = 0x02000000
+	if infosym != nil {
+		infosym.Value = int64(msect.addr)
+	}
+	if inforelocsize > 0 {
+		msect.nreloc = uint32(len(infosec.R))
+		msect.reloc = uint32(inforeloco)
+	}
+
+	if pubnamessize > 0 {
+		msect := newMachoSect(ms, "__debug_pubnames", "__DWARF")
+		msect.off = uint32(pubnameso)
+		msect.size = uint64(pubnamessize)
+		msect.addr = addr
+		addr += msect.size
+		msect.flag = 0x02000000
+	}
+
+	if pubtypessize > 0 {
+		msect := newMachoSect(ms, "__debug_pubtypes", "__DWARF")
+		msect.off = uint32(pubtypeso)
+		msect.size = uint64(pubtypessize)
+		msect.addr = addr
+		addr += msect.size
+		msect.flag = 0x02000000
+	}
+
+	if arangessize > 0 {
+		msect := newMachoSect(ms, "__debug_aranges", "__DWARF")
+		msect.off = uint32(arangeso)
+		msect.size = uint64(arangessize)
+		msect.addr = addr
+		addr += msect.size
+		msect.flag = 0x02000000
+		if arangesrelocsize > 0 {
+			msect.nreloc = uint32(len(arangessec.R))
+			msect.reloc = uint32(arangesreloco)
+		}
+	}
+
+	// TODO(lvd) fix gdb/python to load MachO (16 char section name limit)
+	if gdbscriptsize > 0 {
+		msect := newMachoSect(ms, "__debug_gdb_scripts", "__DWARF")
+		msect.off = uint32(gdbscripto)
+		msect.size = uint64(gdbscriptsize)
+		msect.addr = addr
+		addr += msect.size
+		msect.flag = 0x02000000
+	}
+}
+
+/*
+ * Windows PE
+ */
+func dwarfaddpeheaders() {
+	if Debug['w'] != 0 { // disable dwarf
+		return
+	}
+
+	newPEDWARFSection(".debug_abbrev", abbrevsize)
+	newPEDWARFSection(".debug_line", linesize)
+	newPEDWARFSection(".debug_frame", framesize)
+	newPEDWARFSection(".debug_info", infosize)
+	newPEDWARFSection(".debug_pubnames", pubnamessize)
+	newPEDWARFSection(".debug_pubtypes", pubtypessize)
+	newPEDWARFSection(".debug_aranges", arangessize)
+	newPEDWARFSection(".debug_gdb_scripts", gdbscriptsize)
+}
diff --git a/src/cmd/link/internal/ld/dwarf_defs.go b/src/cmd/link/internal/ld/dwarf_defs.go
new file mode 100644
index 0000000..61389d9
--- /dev/null
+++ b/src/cmd/link/internal/ld/dwarf_defs.go
@@ -0,0 +1,516 @@
+// Copyright 2010 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 ld
+
+// 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 'obj.i' you mean.
+//   - file:line info for variables
+//   - make strings a typedef so prettyprinters can see the underlying string type
+//
+// Copyright 2010 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.
+
+/*
+ * Emit debug_abbrevs, debug_info and debug_line sections to current
+ * offset in cout.
+ */
+
+/*
+ * Add the dwarf section names to the ELF
+ * s[ection]h[eader]str[ing]tab.  Prerequisite for
+ * dwarfaddelfheaders().
+ */
+
+/*
+ * Add section headers pointing to the sections emitted in
+ * dwarfemitdebugsections.
+ */
+// Copyright 2010 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.
+
+// Cut, pasted, tr-and-awk'ed from tables in
+// http://dwarfstd.org/doc/Dwarf3.pdf
+
+// Table 18
+const (
+	DW_TAG_array_type               = 0x01
+	DW_TAG_class_type               = 0x02
+	DW_TAG_entry_point              = 0x03
+	DW_TAG_enumeration_type         = 0x04
+	DW_TAG_formal_parameter         = 0x05
+	DW_TAG_imported_declaration     = 0x08
+	DW_TAG_label                    = 0x0a
+	DW_TAG_lexical_block            = 0x0b
+	DW_TAG_member                   = 0x0d
+	DW_TAG_pointer_type             = 0x0f
+	DW_TAG_reference_type           = 0x10
+	DW_TAG_compile_unit             = 0x11
+	DW_TAG_string_type              = 0x12
+	DW_TAG_structure_type           = 0x13
+	DW_TAG_subroutine_type          = 0x15
+	DW_TAG_typedef                  = 0x16
+	DW_TAG_union_type               = 0x17
+	DW_TAG_unspecified_parameters   = 0x18
+	DW_TAG_variant                  = 0x19
+	DW_TAG_common_block             = 0x1a
+	DW_TAG_common_inclusion         = 0x1b
+	DW_TAG_inheritance              = 0x1c
+	DW_TAG_inlined_subroutine       = 0x1d
+	DW_TAG_module                   = 0x1e
+	DW_TAG_ptr_to_member_type       = 0x1f
+	DW_TAG_set_type                 = 0x20
+	DW_TAG_subrange_type            = 0x21
+	DW_TAG_with_stmt                = 0x22
+	DW_TAG_access_declaration       = 0x23
+	DW_TAG_base_type                = 0x24
+	DW_TAG_catch_block              = 0x25
+	DW_TAG_const_type               = 0x26
+	DW_TAG_constant                 = 0x27
+	DW_TAG_enumerator               = 0x28
+	DW_TAG_file_type                = 0x29
+	DW_TAG_friend                   = 0x2a
+	DW_TAG_namelist                 = 0x2b
+	DW_TAG_namelist_item            = 0x2c
+	DW_TAG_packed_type              = 0x2d
+	DW_TAG_subprogram               = 0x2e
+	DW_TAG_template_type_parameter  = 0x2f
+	DW_TAG_template_value_parameter = 0x30
+	DW_TAG_thrown_type              = 0x31
+	DW_TAG_try_block                = 0x32
+	DW_TAG_variant_part             = 0x33
+	DW_TAG_variable                 = 0x34
+	DW_TAG_volatile_type            = 0x35
+	// 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
+const (
+	DW_CHILDREN_no  = 0x00
+	DW_CHILDREN_yes = 0x01
+)
+
+// Not from the spec, but logicaly belongs here
+const (
+	DW_CLS_ADDRESS = 0x01 + iota
+	DW_CLS_BLOCK
+	DW_CLS_CONSTANT
+	DW_CLS_FLAG
+	DW_CLS_PTR // lineptr, loclistptr, macptr, rangelistptr
+	DW_CLS_REFERENCE
+	DW_CLS_ADDRLOC
+	DW_CLS_STRING
+)
+
+// Table 20
+const (
+	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 // 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 // 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
+)
+
+// Table 25
+const (
+	DW_ATE_address         = 0x01
+	DW_ATE_boolean         = 0x02
+	DW_ATE_complex_float   = 0x03
+	DW_ATE_float           = 0x04
+	DW_ATE_signed          = 0x05
+	DW_ATE_signed_char     = 0x06
+	DW_ATE_unsigned        = 0x07
+	DW_ATE_unsigned_char   = 0x08
+	DW_ATE_imaginary_float = 0x09
+	DW_ATE_packed_decimal  = 0x0a
+	DW_ATE_numeric_string  = 0x0b
+	DW_ATE_edited          = 0x0c
+	DW_ATE_signed_fixed    = 0x0d
+	DW_ATE_unsigned_fixed  = 0x0e
+	DW_ATE_decimal_float   = 0x0f
+	DW_ATE_lo_user         = 0x80
+	DW_ATE_hi_user         = 0xff
+)
+
+// Table 26
+const (
+	DW_DS_unsigned           = 0x01
+	DW_DS_leading_overpunch  = 0x02
+	DW_DS_trailing_overpunch = 0x03
+	DW_DS_leading_separate   = 0x04
+	DW_DS_trailing_separate  = 0x05
+)
+
+// Table 27
+const (
+	DW_END_default = 0x00
+	DW_END_big     = 0x01
+	DW_END_little  = 0x02
+	DW_END_lo_user = 0x40
+	DW_END_hi_user = 0xff
+)
+
+// Table 28
+const (
+	DW_ACCESS_public    = 0x01
+	DW_ACCESS_protected = 0x02
+	DW_ACCESS_private   = 0x03
+)
+
+// Table 29
+const (
+	DW_VIS_local     = 0x01
+	DW_VIS_exported  = 0x02
+	DW_VIS_qualified = 0x03
+)
+
+// Table 30
+const (
+	DW_VIRTUALITY_none         = 0x00
+	DW_VIRTUALITY_virtual      = 0x01
+	DW_VIRTUALITY_pure_virtual = 0x02
+)
+
+// 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
+	// Dwarf3
+	DW_LANG_Java           = 0x000b
+	DW_LANG_C99            = 0x000c
+	DW_LANG_Ada95          = 0x000d
+	DW_LANG_Fortran95      = 0x000e
+	DW_LANG_PLI            = 0x000f
+	DW_LANG_ObjC           = 0x0010
+	DW_LANG_ObjC_plus_plus = 0x0011
+	DW_LANG_UPC            = 0x0012
+	DW_LANG_D              = 0x0013
+	// Dwarf4
+	DW_LANG_Python = 0x0014
+	// Dwarf5
+	DW_LANG_Go = 0x0016
+
+	DW_LANG_lo_user = 0x8000
+	DW_LANG_hi_user = 0xffff
+)
+
+// Table 32
+const (
+	DW_ID_case_sensitive   = 0x00
+	DW_ID_up_case          = 0x01
+	DW_ID_down_case        = 0x02
+	DW_ID_case_insensitive = 0x03
+)
+
+// Table 33
+const (
+	DW_CC_normal  = 0x01
+	DW_CC_program = 0x02
+	DW_CC_nocall  = 0x03
+	DW_CC_lo_user = 0x40
+	DW_CC_hi_user = 0xff
+)
+
+// Table 34
+const (
+	DW_INL_not_inlined          = 0x00
+	DW_INL_inlined              = 0x01
+	DW_INL_declared_not_inlined = 0x02
+	DW_INL_declared_inlined     = 0x03
+)
+
+// Table 35
+const (
+	DW_ORD_row_major = 0x00
+	DW_ORD_col_major = 0x01
+)
+
+// Table 36
+const (
+	DW_DSC_label = 0x00
+	DW_DSC_range = 0x01
+)
+
+// 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
+	// Dwarf3
+	DW_LNS_set_prologue_end   = 0x0a
+	DW_LNS_set_epilogue_begin = 0x0b
+	DW_LNS_set_isa            = 0x0c
+)
+
+// Table 38
+const (
+	DW_LNE_end_sequence = 0x01
+	DW_LNE_set_address  = 0x02
+	DW_LNE_define_file  = 0x03
+	DW_LNE_lo_user      = 0x80
+	DW_LNE_hi_user      = 0xff
+)
+
+// Table 39
+const (
+	DW_MACINFO_define     = 0x01
+	DW_MACINFO_undef      = 0x02
+	DW_MACINFO_start_file = 0x03
+	DW_MACINFO_end_file   = 0x04
+	DW_MACINFO_vendor_ext = 0xff
+)
+
+// Table 40.
+const (
+	// 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/link/internal/ld/elf.go b/src/cmd/link/internal/ld/elf.go
new file mode 100644
index 0000000..508f055
--- /dev/null
+++ b/src/cmd/link/internal/ld/elf.go
@@ -0,0 +1,2595 @@
+// 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 ld
+
+import (
+	"cmd/internal/obj"
+	"crypto/sha1"
+	"encoding/binary"
+	"fmt"
+	"path/filepath"
+	"sort"
+	"strings"
+)
+
+/*
+ * Derived from:
+ * $FreeBSD: src/sys/sys/elf32.h,v 1.8.14.1 2005/12/30 22:13:58 marcel Exp $
+ * $FreeBSD: src/sys/sys/elf64.h,v 1.10.14.1 2005/12/30 22:13:58 marcel Exp $
+ * $FreeBSD: src/sys/sys/elf_common.h,v 1.15.8.1 2005/12/30 22:13:58 marcel Exp $
+ * $FreeBSD: src/sys/alpha/include/elf.h,v 1.14 2003/09/25 01:10:22 peter Exp $
+ * $FreeBSD: src/sys/amd64/include/elf.h,v 1.18 2004/08/03 08:21:48 dfr Exp $
+ * $FreeBSD: src/sys/arm/include/elf.h,v 1.5.2.1 2006/06/30 21:42:52 cognet Exp $
+ * $FreeBSD: src/sys/i386/include/elf.h,v 1.16 2004/08/02 19:12:17 dfr Exp $
+ * $FreeBSD: src/sys/powerpc/include/elf.h,v 1.7 2004/11/02 09:47:01 ssouhlal Exp $
+ * $FreeBSD: src/sys/sparc64/include/elf.h,v 1.12 2003/09/25 01:10:26 peter Exp $
+ *
+ * Copyright (c) 1996-1998 John D. Polstra.  All rights reserved.
+ * Copyright (c) 2001 David E. O'Brien
+ * Portions Copyright 2009 The Go Authors.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+/*
+ * ELF definitions that are independent of architecture or word size.
+ */
+
+/*
+ * Note header.  The ".note" section contains an array of notes.  Each
+ * begins with this header, aligned to a word boundary.  Immediately
+ * following the note header is n_namesz bytes of name, padded to the
+ * next word boundary.  Then comes n_descsz bytes of descriptor, again
+ * padded to a word boundary.  The values of n_namesz and n_descsz do
+ * not include the padding.
+ */
+type Elf_Note struct {
+	n_namesz uint32
+	n_descsz uint32
+	n_type   uint32
+}
+
+const (
+	EI_MAG0              = 0
+	EI_MAG1              = 1
+	EI_MAG2              = 2
+	EI_MAG3              = 3
+	EI_CLASS             = 4
+	EI_DATA              = 5
+	EI_VERSION           = 6
+	EI_OSABI             = 7
+	EI_ABIVERSION        = 8
+	OLD_EI_BRAND         = 8
+	EI_PAD               = 9
+	EI_NIDENT            = 16
+	ELFMAG0              = 0x7f
+	ELFMAG1              = 'E'
+	ELFMAG2              = 'L'
+	ELFMAG3              = 'F'
+	SELFMAG              = 4
+	EV_NONE              = 0
+	EV_CURRENT           = 1
+	ELFCLASSNONE         = 0
+	ELFCLASS32           = 1
+	ELFCLASS64           = 2
+	ELFDATANONE          = 0
+	ELFDATA2LSB          = 1
+	ELFDATA2MSB          = 2
+	ELFOSABI_NONE        = 0
+	ELFOSABI_HPUX        = 1
+	ELFOSABI_NETBSD      = 2
+	ELFOSABI_LINUX       = 3
+	ELFOSABI_HURD        = 4
+	ELFOSABI_86OPEN      = 5
+	ELFOSABI_SOLARIS     = 6
+	ELFOSABI_AIX         = 7
+	ELFOSABI_IRIX        = 8
+	ELFOSABI_FREEBSD     = 9
+	ELFOSABI_TRU64       = 10
+	ELFOSABI_MODESTO     = 11
+	ELFOSABI_OPENBSD     = 12
+	ELFOSABI_OPENVMS     = 13
+	ELFOSABI_NSK         = 14
+	ELFOSABI_ARM         = 97
+	ELFOSABI_STANDALONE  = 255
+	ELFOSABI_SYSV        = ELFOSABI_NONE
+	ELFOSABI_MONTEREY    = ELFOSABI_AIX
+	ET_NONE              = 0
+	ET_REL               = 1
+	ET_EXEC              = 2
+	ET_DYN               = 3
+	ET_CORE              = 4
+	ET_LOOS              = 0xfe00
+	ET_HIOS              = 0xfeff
+	ET_LOPROC            = 0xff00
+	ET_HIPROC            = 0xffff
+	EM_NONE              = 0
+	EM_M32               = 1
+	EM_SPARC             = 2
+	EM_386               = 3
+	EM_68K               = 4
+	EM_88K               = 5
+	EM_860               = 7
+	EM_MIPS              = 8
+	EM_S370              = 9
+	EM_MIPS_RS3_LE       = 10
+	EM_PARISC            = 15
+	EM_VPP500            = 17
+	EM_SPARC32PLUS       = 18
+	EM_960               = 19
+	EM_PPC               = 20
+	EM_PPC64             = 21
+	EM_S390              = 22
+	EM_V800              = 36
+	EM_FR20              = 37
+	EM_RH32              = 38
+	EM_RCE               = 39
+	EM_ARM               = 40
+	EM_SH                = 42
+	EM_SPARCV9           = 43
+	EM_TRICORE           = 44
+	EM_ARC               = 45
+	EM_H8_300            = 46
+	EM_H8_300H           = 47
+	EM_H8S               = 48
+	EM_H8_500            = 49
+	EM_IA_64             = 50
+	EM_MIPS_X            = 51
+	EM_COLDFIRE          = 52
+	EM_68HC12            = 53
+	EM_MMA               = 54
+	EM_PCP               = 55
+	EM_NCPU              = 56
+	EM_NDR1              = 57
+	EM_STARCORE          = 58
+	EM_ME16              = 59
+	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
+	EM_ALPHA             = 0x9026
+	SHN_UNDEF            = 0
+	SHN_LORESERVE        = 0xff00
+	SHN_LOPROC           = 0xff00
+	SHN_HIPROC           = 0xff1f
+	SHN_LOOS             = 0xff20
+	SHN_HIOS             = 0xff3f
+	SHN_ABS              = 0xfff1
+	SHN_COMMON           = 0xfff2
+	SHN_XINDEX           = 0xffff
+	SHN_HIRESERVE        = 0xffff
+	SHT_NULL             = 0
+	SHT_PROGBITS         = 1
+	SHT_SYMTAB           = 2
+	SHT_STRTAB           = 3
+	SHT_RELA             = 4
+	SHT_HASH             = 5
+	SHT_DYNAMIC          = 6
+	SHT_NOTE             = 7
+	SHT_NOBITS           = 8
+	SHT_REL              = 9
+	SHT_SHLIB            = 10
+	SHT_DYNSYM           = 11
+	SHT_INIT_ARRAY       = 14
+	SHT_FINI_ARRAY       = 15
+	SHT_PREINIT_ARRAY    = 16
+	SHT_GROUP            = 17
+	SHT_SYMTAB_SHNDX     = 18
+	SHT_LOOS             = 0x60000000
+	SHT_HIOS             = 0x6fffffff
+	SHT_GNU_VERDEF       = 0x6ffffffd
+	SHT_GNU_VERNEED      = 0x6ffffffe
+	SHT_GNU_VERSYM       = 0x6fffffff
+	SHT_LOPROC           = 0x70000000
+	SHT_HIPROC           = 0x7fffffff
+	SHT_LOUSER           = 0x80000000
+	SHT_HIUSER           = 0xffffffff
+	SHF_WRITE            = 0x1
+	SHF_ALLOC            = 0x2
+	SHF_EXECINSTR        = 0x4
+	SHF_MERGE            = 0x10
+	SHF_STRINGS          = 0x20
+	SHF_INFO_LINK        = 0x40
+	SHF_LINK_ORDER       = 0x80
+	SHF_OS_NONCONFORMING = 0x100
+	SHF_GROUP            = 0x200
+	SHF_TLS              = 0x400
+	SHF_MASKOS           = 0x0ff00000
+	SHF_MASKPROC         = 0xf0000000
+	PT_NULL              = 0
+	PT_LOAD              = 1
+	PT_DYNAMIC           = 2
+	PT_INTERP            = 3
+	PT_NOTE              = 4
+	PT_SHLIB             = 5
+	PT_PHDR              = 6
+	PT_TLS               = 7
+	PT_LOOS              = 0x60000000
+	PT_HIOS              = 0x6fffffff
+	PT_LOPROC            = 0x70000000
+	PT_HIPROC            = 0x7fffffff
+	PT_GNU_STACK         = 0x6474e551
+	PT_PAX_FLAGS         = 0x65041580
+	PF_X                 = 0x1
+	PF_W                 = 0x2
+	PF_R                 = 0x4
+	PF_MASKOS            = 0x0ff00000
+	PF_MASKPROC          = 0xf0000000
+	DT_NULL              = 0
+	DT_NEEDED            = 1
+	DT_PLTRELSZ          = 2
+	DT_PLTGOT            = 3
+	DT_HASH              = 4
+	DT_STRTAB            = 5
+	DT_SYMTAB            = 6
+	DT_RELA              = 7
+	DT_RELASZ            = 8
+	DT_RELAENT           = 9
+	DT_STRSZ             = 10
+	DT_SYMENT            = 11
+	DT_INIT              = 12
+	DT_FINI              = 13
+	DT_SONAME            = 14
+	DT_RPATH             = 15
+	DT_SYMBOLIC          = 16
+	DT_REL               = 17
+	DT_RELSZ             = 18
+	DT_RELENT            = 19
+	DT_PLTREL            = 20
+	DT_DEBUG             = 21
+	DT_TEXTREL           = 22
+	DT_JMPREL            = 23
+	DT_BIND_NOW          = 24
+	DT_INIT_ARRAY        = 25
+	DT_FINI_ARRAY        = 26
+	DT_INIT_ARRAYSZ      = 27
+	DT_FINI_ARRAYSZ      = 28
+	DT_RUNPATH           = 29
+	DT_FLAGS             = 30
+	DT_ENCODING          = 32
+	DT_PREINIT_ARRAY     = 32
+	DT_PREINIT_ARRAYSZ   = 33
+	DT_LOOS              = 0x6000000d
+	DT_HIOS              = 0x6ffff000
+	DT_LOPROC            = 0x70000000
+	DT_HIPROC            = 0x7fffffff
+	DT_VERNEED           = 0x6ffffffe
+	DT_VERNEEDNUM        = 0x6fffffff
+	DT_VERSYM            = 0x6ffffff0
+	DT_PPC64_GLINK       = DT_LOPROC + 0
+	DT_PPC64_OPT         = DT_LOPROC + 3
+	DF_ORIGIN            = 0x0001
+	DF_SYMBOLIC          = 0x0002
+	DF_TEXTREL           = 0x0004
+	DF_BIND_NOW          = 0x0008
+	DF_STATIC_TLS        = 0x0010
+	NT_PRSTATUS          = 1
+	NT_FPREGSET          = 2
+	NT_PRPSINFO          = 3
+	STB_LOCAL            = 0
+	STB_GLOBAL           = 1
+	STB_WEAK             = 2
+	STB_LOOS             = 10
+	STB_HIOS             = 12
+	STB_LOPROC           = 13
+	STB_HIPROC           = 15
+	STT_NOTYPE           = 0
+	STT_OBJECT           = 1
+	STT_FUNC             = 2
+	STT_SECTION          = 3
+	STT_FILE             = 4
+	STT_COMMON           = 5
+	STT_TLS              = 6
+	STT_LOOS             = 10
+	STT_HIOS             = 12
+	STT_LOPROC           = 13
+	STT_HIPROC           = 15
+	STV_DEFAULT          = 0x0
+	STV_INTERNAL         = 0x1
+	STV_HIDDEN           = 0x2
+	STV_PROTECTED        = 0x3
+	STN_UNDEF            = 0
+)
+
+/* For accessing the fields of r_info. */
+
+/* For constructing r_info from field values. */
+
+/*
+ * Relocation types.
+ */
+const (
+	R_X86_64_NONE              = 0
+	R_X86_64_64                = 1
+	R_X86_64_PC32              = 2
+	R_X86_64_GOT32             = 3
+	R_X86_64_PLT32             = 4
+	R_X86_64_COPY              = 5
+	R_X86_64_GLOB_DAT          = 6
+	R_X86_64_JMP_SLOT          = 7
+	R_X86_64_RELATIVE          = 8
+	R_X86_64_GOTPCREL          = 9
+	R_X86_64_32                = 10
+	R_X86_64_32S               = 11
+	R_X86_64_16                = 12
+	R_X86_64_PC16              = 13
+	R_X86_64_8                 = 14
+	R_X86_64_PC8               = 15
+	R_X86_64_DTPMOD64          = 16
+	R_X86_64_DTPOFF64          = 17
+	R_X86_64_TPOFF64           = 18
+	R_X86_64_TLSGD             = 19
+	R_X86_64_TLSLD             = 20
+	R_X86_64_DTPOFF32          = 21
+	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_AARCH64_ADR_PREL_PG_HI21 = 275
+	R_AARCH64_ADD_ABS_LO12_NC  = 277
+	R_ALPHA_NONE               = 0
+	R_ALPHA_REFLONG            = 1
+	R_ALPHA_REFQUAD            = 2
+	R_ALPHA_GPREL32            = 3
+	R_ALPHA_LITERAL            = 4
+	R_ALPHA_LITUSE             = 5
+	R_ALPHA_GPDISP             = 6
+	R_ALPHA_BRADDR             = 7
+	R_ALPHA_HINT               = 8
+	R_ALPHA_SREL16             = 9
+	R_ALPHA_SREL32             = 10
+	R_ALPHA_SREL64             = 11
+	R_ALPHA_OP_PUSH            = 12
+	R_ALPHA_OP_STORE           = 13
+	R_ALPHA_OP_PSUB            = 14
+	R_ALPHA_OP_PRSHIFT         = 15
+	R_ALPHA_GPVALUE            = 16
+	R_ALPHA_GPRELHIGH          = 17
+	R_ALPHA_GPRELLOW           = 18
+	R_ALPHA_IMMED_GP_16        = 19
+	R_ALPHA_IMMED_GP_HI32      = 20
+	R_ALPHA_IMMED_SCN_HI32     = 21
+	R_ALPHA_IMMED_BR_HI32      = 22
+	R_ALPHA_IMMED_LO32         = 23
+	R_ALPHA_COPY               = 24
+	R_ALPHA_GLOB_DAT           = 25
+	R_ALPHA_JMP_SLOT           = 26
+	R_ALPHA_RELATIVE           = 27
+	R_ALPHA_COUNT              = 28
+	R_ARM_NONE                 = 0
+	R_ARM_PC24                 = 1
+	R_ARM_ABS32                = 2
+	R_ARM_REL32                = 3
+	R_ARM_PC13                 = 4
+	R_ARM_ABS16                = 5
+	R_ARM_ABS12                = 6
+	R_ARM_THM_ABS5             = 7
+	R_ARM_ABS8                 = 8
+	R_ARM_SBREL32              = 9
+	R_ARM_THM_PC22             = 10
+	R_ARM_THM_PC8              = 11
+	R_ARM_AMP_VCALL9           = 12
+	R_ARM_SWI24                = 13
+	R_ARM_THM_SWI8             = 14
+	R_ARM_XPC25                = 15
+	R_ARM_THM_XPC22            = 16
+	R_ARM_COPY                 = 20
+	R_ARM_GLOB_DAT             = 21
+	R_ARM_JUMP_SLOT            = 22
+	R_ARM_RELATIVE             = 23
+	R_ARM_GOTOFF               = 24
+	R_ARM_GOTPC                = 25
+	R_ARM_GOT32                = 26
+	R_ARM_PLT32                = 27
+	R_ARM_CALL                 = 28
+	R_ARM_JUMP24               = 29
+	R_ARM_V4BX                 = 40
+	R_ARM_GOT_PREL             = 96
+	R_ARM_GNU_VTENTRY          = 100
+	R_ARM_GNU_VTINHERIT        = 101
+	R_ARM_TLS_IE32             = 107
+	R_ARM_TLS_LE32             = 108
+	R_ARM_RSBREL32             = 250
+	R_ARM_THM_RPC22            = 251
+	R_ARM_RREL32               = 252
+	R_ARM_RABS32               = 253
+	R_ARM_RPC24                = 254
+	R_ARM_RBASE                = 255
+	R_ARM_COUNT                = 38
+	R_386_NONE                 = 0
+	R_386_32                   = 1
+	R_386_PC32                 = 2
+	R_386_GOT32                = 3
+	R_386_PLT32                = 4
+	R_386_COPY                 = 5
+	R_386_GLOB_DAT             = 6
+	R_386_JMP_SLOT             = 7
+	R_386_RELATIVE             = 8
+	R_386_GOTOFF               = 9
+	R_386_GOTPC                = 10
+	R_386_TLS_TPOFF            = 14
+	R_386_TLS_IE               = 15
+	R_386_TLS_GOTIE            = 16
+	R_386_TLS_LE               = 17
+	R_386_TLS_GD               = 18
+	R_386_TLS_LDM              = 19
+	R_386_TLS_GD_32            = 24
+	R_386_TLS_GD_PUSH          = 25
+	R_386_TLS_GD_CALL          = 26
+	R_386_TLS_GD_POP           = 27
+	R_386_TLS_LDM_32           = 28
+	R_386_TLS_LDM_PUSH         = 29
+	R_386_TLS_LDM_CALL         = 30
+	R_386_TLS_LDM_POP          = 31
+	R_386_TLS_LDO_32           = 32
+	R_386_TLS_IE_32            = 33
+	R_386_TLS_LE_32            = 34
+	R_386_TLS_DTPMOD32         = 35
+	R_386_TLS_DTPOFF32         = 36
+	R_386_TLS_TPOFF32          = 37
+	R_386_COUNT                = 38
+	R_PPC_NONE                 = 0
+	R_PPC_ADDR32               = 1
+	R_PPC_ADDR24               = 2
+	R_PPC_ADDR16               = 3
+	R_PPC_ADDR16_LO            = 4
+	R_PPC_ADDR16_HI            = 5
+	R_PPC_ADDR16_HA            = 6
+	R_PPC_ADDR14               = 7
+	R_PPC_ADDR14_BRTAKEN       = 8
+	R_PPC_ADDR14_BRNTAKEN      = 9
+	R_PPC_REL24                = 10
+	R_PPC_REL14                = 11
+	R_PPC_REL14_BRTAKEN        = 12
+	R_PPC_REL14_BRNTAKEN       = 13
+	R_PPC_GOT16                = 14
+	R_PPC_GOT16_LO             = 15
+	R_PPC_GOT16_HI             = 16
+	R_PPC_GOT16_HA             = 17
+	R_PPC_PLTREL24             = 18
+	R_PPC_COPY                 = 19
+	R_PPC_GLOB_DAT             = 20
+	R_PPC_JMP_SLOT             = 21
+	R_PPC_RELATIVE             = 22
+	R_PPC_LOCAL24PC            = 23
+	R_PPC_UADDR32              = 24
+	R_PPC_UADDR16              = 25
+	R_PPC_REL32                = 26
+	R_PPC_PLT32                = 27
+	R_PPC_PLTREL32             = 28
+	R_PPC_PLT16_LO             = 29
+	R_PPC_PLT16_HI             = 30
+	R_PPC_PLT16_HA             = 31
+	R_PPC_SDAREL16             = 32
+	R_PPC_SECTOFF              = 33
+	R_PPC_SECTOFF_LO           = 34
+	R_PPC_SECTOFF_HI           = 35
+	R_PPC_SECTOFF_HA           = 36
+	R_PPC_COUNT                = 37
+	R_PPC_TLS                  = 67
+	R_PPC_DTPMOD32             = 68
+	R_PPC_TPREL16              = 69
+	R_PPC_TPREL16_LO           = 70
+	R_PPC_TPREL16_HI           = 71
+	R_PPC_TPREL16_HA           = 72
+	R_PPC_TPREL32              = 73
+	R_PPC_DTPREL16             = 74
+	R_PPC_DTPREL16_LO          = 75
+	R_PPC_DTPREL16_HI          = 76
+	R_PPC_DTPREL16_HA          = 77
+	R_PPC_DTPREL32             = 78
+	R_PPC_GOT_TLSGD16          = 79
+	R_PPC_GOT_TLSGD16_LO       = 80
+	R_PPC_GOT_TLSGD16_HI       = 81
+	R_PPC_GOT_TLSGD16_HA       = 82
+	R_PPC_GOT_TLSLD16          = 83
+	R_PPC_GOT_TLSLD16_LO       = 84
+	R_PPC_GOT_TLSLD16_HI       = 85
+	R_PPC_GOT_TLSLD16_HA       = 86
+	R_PPC_GOT_TPREL16          = 87
+	R_PPC_GOT_TPREL16_LO       = 88
+	R_PPC_GOT_TPREL16_HI       = 89
+	R_PPC_GOT_TPREL16_HA       = 90
+	R_PPC_EMB_NADDR32          = 101
+	R_PPC_EMB_NADDR16          = 102
+	R_PPC_EMB_NADDR16_LO       = 103
+	R_PPC_EMB_NADDR16_HI       = 104
+	R_PPC_EMB_NADDR16_HA       = 105
+	R_PPC_EMB_SDAI16           = 106
+	R_PPC_EMB_SDA2I16          = 107
+	R_PPC_EMB_SDA2REL          = 108
+	R_PPC_EMB_SDA21            = 109
+	R_PPC_EMB_MRKREF           = 110
+	R_PPC_EMB_RELSEC16         = 111
+	R_PPC_EMB_RELST_LO         = 112
+	R_PPC_EMB_RELST_HI         = 113
+	R_PPC_EMB_RELST_HA         = 114
+	R_PPC_EMB_BIT_FLD          = 115
+	R_PPC_EMB_RELSDA           = 116
+	R_PPC_EMB_COUNT            = R_PPC_EMB_RELSDA - R_PPC_EMB_NADDR32 + 1
+	R_PPC64_REL24              = R_PPC_REL24
+	R_PPC64_JMP_SLOT           = R_PPC_JMP_SLOT
+	R_PPC64_ADDR64             = 38
+	R_PPC64_TOC16              = 47
+	R_PPC64_TOC16_LO           = 48
+	R_PPC64_TOC16_HI           = 49
+	R_PPC64_TOC16_HA           = 50
+	R_PPC64_TOC16_DS           = 63
+	R_PPC64_TOC16_LO_DS        = 64
+	R_PPC64_REL16_LO           = 250
+	R_PPC64_REL16_HI           = 251
+	R_PPC64_REL16_HA           = 252
+	R_SPARC_NONE               = 0
+	R_SPARC_8                  = 1
+	R_SPARC_16                 = 2
+	R_SPARC_32                 = 3
+	R_SPARC_DISP8              = 4
+	R_SPARC_DISP16             = 5
+	R_SPARC_DISP32             = 6
+	R_SPARC_WDISP30            = 7
+	R_SPARC_WDISP22            = 8
+	R_SPARC_HI22               = 9
+	R_SPARC_22                 = 10
+	R_SPARC_13                 = 11
+	R_SPARC_LO10               = 12
+	R_SPARC_GOT10              = 13
+	R_SPARC_GOT13              = 14
+	R_SPARC_GOT22              = 15
+	R_SPARC_PC10               = 16
+	R_SPARC_PC22               = 17
+	R_SPARC_WPLT30             = 18
+	R_SPARC_COPY               = 19
+	R_SPARC_GLOB_DAT           = 20
+	R_SPARC_JMP_SLOT           = 21
+	R_SPARC_RELATIVE           = 22
+	R_SPARC_UA32               = 23
+	R_SPARC_PLT32              = 24
+	R_SPARC_HIPLT22            = 25
+	R_SPARC_LOPLT10            = 26
+	R_SPARC_PCPLT32            = 27
+	R_SPARC_PCPLT22            = 28
+	R_SPARC_PCPLT10            = 29
+	R_SPARC_10                 = 30
+	R_SPARC_11                 = 31
+	R_SPARC_64                 = 32
+	R_SPARC_OLO10              = 33
+	R_SPARC_HH22               = 34
+	R_SPARC_HM10               = 35
+	R_SPARC_LM22               = 36
+	R_SPARC_PC_HH22            = 37
+	R_SPARC_PC_HM10            = 38
+	R_SPARC_PC_LM22            = 39
+	R_SPARC_WDISP16            = 40
+	R_SPARC_WDISP19            = 41
+	R_SPARC_GLOB_JMP           = 42
+	R_SPARC_7                  = 43
+	R_SPARC_5                  = 44
+	R_SPARC_6                  = 45
+	R_SPARC_DISP64             = 46
+	R_SPARC_PLT64              = 47
+	R_SPARC_HIX22              = 48
+	R_SPARC_LOX10              = 49
+	R_SPARC_H44                = 50
+	R_SPARC_M44                = 51
+	R_SPARC_L44                = 52
+	R_SPARC_REGISTER           = 53
+	R_SPARC_UA64               = 54
+	R_SPARC_UA16               = 55
+	ARM_MAGIC_TRAMP_NUMBER     = 0x5c000003
+)
+
+/*
+ * Symbol table entries.
+ */
+
+/* For accessing the fields of st_info. */
+
+/* For constructing st_info from field values. */
+
+/* For accessing the fields of st_other. */
+
+/*
+ * ELF header.
+ */
+type ElfEhdr struct {
+	ident     [EI_NIDENT]uint8
+	type_     uint16
+	machine   uint16
+	version   uint32
+	entry     uint64
+	phoff     uint64
+	shoff     uint64
+	flags     uint32
+	ehsize    uint16
+	phentsize uint16
+	phnum     uint16
+	shentsize uint16
+	shnum     uint16
+	shstrndx  uint16
+}
+
+/*
+ * Section header.
+ */
+type ElfShdr struct {
+	name      uint32
+	type_     uint32
+	flags     uint64
+	addr      uint64
+	off       uint64
+	size      uint64
+	link      uint32
+	info      uint32
+	addralign uint64
+	entsize   uint64
+	shnum     int
+	secsym    *LSym
+}
+
+/*
+ * Program header.
+ */
+type ElfPhdr struct {
+	type_  uint32
+	flags  uint32
+	off    uint64
+	vaddr  uint64
+	paddr  uint64
+	filesz uint64
+	memsz  uint64
+	align  uint64
+}
+
+/* For accessing the fields of r_info. */
+
+/* For constructing r_info from field values. */
+
+/*
+ * Symbol table entries.
+ */
+
+/* For accessing the fields of st_info. */
+
+/* For constructing st_info from field values. */
+
+/* For accessing the fields of st_other. */
+
+/*
+ * Go linker interface
+ */
+const (
+	ELF64HDRSIZE  = 64
+	ELF64PHDRSIZE = 56
+	ELF64SHDRSIZE = 64
+	ELF64RELSIZE  = 16
+	ELF64RELASIZE = 24
+	ELF64SYMSIZE  = 24
+	ELF32HDRSIZE  = 52
+	ELF32PHDRSIZE = 32
+	ELF32SHDRSIZE = 40
+	ELF32SYMSIZE  = 16
+	ELF32RELSIZE  = 8
+)
+
+/*
+ * The interface uses the 64-bit structures always,
+ * to avoid code duplication.  The writers know how to
+ * marshal a 32-bit representation from the 64-bit structure.
+ */
+
+var Elfstrdat []byte
+
+/*
+ * Total amount of space to reserve at the start of the file
+ * for Header, PHeaders, SHeaders, and interp.
+ * May waste some.
+ * On FreeBSD, cannot be larger than a page.
+ */
+const (
+	ELFRESERVE = 4096
+)
+
+/*
+ * We use the 64-bit data structures on both 32- and 64-bit machines
+ * in order to write the code just once.  The 64-bit data structure is
+ * written in the 32-bit format on the 32-bit machines.
+ */
+const (
+	NSECT = 48
+)
+
+var Iself bool
+
+var Nelfsym int = 1
+
+var elf64 bool
+
+var ehdr ElfEhdr
+
+var phdr [NSECT]*ElfPhdr
+
+var shdr [NSECT]*ElfShdr
+
+var interp string
+
+type Elfstring struct {
+	s   string
+	off int
+}
+
+var elfstr [100]Elfstring
+
+var nelfstr int
+
+var buildinfo []byte
+
+/*
+ Initialize the global variable that describes the ELF header. It will be updated as
+ we write section and prog headers.
+*/
+func Elfinit() {
+	Iself = true
+
+	switch Thearch.Thechar {
+	// 64-bit architectures
+	case '9':
+		if Ctxt.Arch.ByteOrder == binary.BigEndian {
+			ehdr.flags = 1 /* Version 1 ABI */
+		} else {
+			ehdr.flags = 2 /* Version 2 ABI */
+		}
+		fallthrough
+
+	case '6', '7':
+		elf64 = true
+
+		ehdr.phoff = ELF64HDRSIZE      /* Must be be ELF64HDRSIZE: first PHdr must follow ELF header */
+		ehdr.shoff = ELF64HDRSIZE      /* Will move as we add PHeaders */
+		ehdr.ehsize = ELF64HDRSIZE     /* Must be ELF64HDRSIZE */
+		ehdr.phentsize = ELF64PHDRSIZE /* Must be ELF64PHDRSIZE */
+		ehdr.shentsize = ELF64SHDRSIZE /* Must be ELF64SHDRSIZE */
+
+		// 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 == obj.Hlinux || HEADTYPE == obj.Hfreebsd {
+			ehdr.flags = 0x5000002 // has entry point, Version5 EABI
+		}
+		fallthrough
+
+	default:
+		ehdr.phoff = ELF32HDRSIZE
+		/* Must be be ELF32HDRSIZE: first PHdr must follow ELF header */
+		ehdr.shoff = ELF32HDRSIZE      /* Will move as we add PHeaders */
+		ehdr.ehsize = ELF32HDRSIZE     /* Must be ELF32HDRSIZE */
+		ehdr.phentsize = ELF32PHDRSIZE /* Must be ELF32PHDRSIZE */
+		ehdr.shentsize = ELF32SHDRSIZE /* Must be ELF32SHDRSIZE */
+	}
+}
+
+func elf64phdr(e *ElfPhdr) {
+	Thearch.Lput(e.type_)
+	Thearch.Lput(e.flags)
+	Thearch.Vput(e.off)
+	Thearch.Vput(e.vaddr)
+	Thearch.Vput(e.paddr)
+	Thearch.Vput(e.filesz)
+	Thearch.Vput(e.memsz)
+	Thearch.Vput(e.align)
+}
+
+func elf32phdr(e *ElfPhdr) {
+	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))
+
+		e.off -= uint64(frag)
+		e.vaddr -= uint64(frag)
+		e.paddr -= uint64(frag)
+		e.filesz += uint64(frag)
+		e.memsz += uint64(frag)
+	}
+
+	Thearch.Lput(e.type_)
+	Thearch.Lput(uint32(e.off))
+	Thearch.Lput(uint32(e.vaddr))
+	Thearch.Lput(uint32(e.paddr))
+	Thearch.Lput(uint32(e.filesz))
+	Thearch.Lput(uint32(e.memsz))
+	Thearch.Lput(e.flags)
+	Thearch.Lput(uint32(e.align))
+}
+
+func elf64shdr(e *ElfShdr) {
+	Thearch.Lput(e.name)
+	Thearch.Lput(e.type_)
+	Thearch.Vput(e.flags)
+	Thearch.Vput(e.addr)
+	Thearch.Vput(e.off)
+	Thearch.Vput(e.size)
+	Thearch.Lput(e.link)
+	Thearch.Lput(e.info)
+	Thearch.Vput(e.addralign)
+	Thearch.Vput(e.entsize)
+}
+
+func elf32shdr(e *ElfShdr) {
+	Thearch.Lput(e.name)
+	Thearch.Lput(e.type_)
+	Thearch.Lput(uint32(e.flags))
+	Thearch.Lput(uint32(e.addr))
+	Thearch.Lput(uint32(e.off))
+	Thearch.Lput(uint32(e.size))
+	Thearch.Lput(e.link)
+	Thearch.Lput(e.info)
+	Thearch.Lput(uint32(e.addralign))
+	Thearch.Lput(uint32(e.entsize))
+}
+
+func elfwriteshdrs() uint32 {
+	if elf64 {
+		for i := 0; i < int(ehdr.shnum); i++ {
+			elf64shdr(shdr[i])
+		}
+		return uint32(ehdr.shnum) * ELF64SHDRSIZE
+	}
+
+	for i := 0; i < int(ehdr.shnum); i++ {
+		elf32shdr(shdr[i])
+	}
+	return uint32(ehdr.shnum) * ELF32SHDRSIZE
+}
+
+func elfsetstring(s string, off int) {
+	if nelfstr >= len(elfstr) {
+		Diag("too many elf strings")
+		errorexit()
+	}
+
+	elfstr[nelfstr].s = s
+	elfstr[nelfstr].off = off
+	nelfstr++
+}
+
+func elfwritephdrs() uint32 {
+	if elf64 {
+		for i := 0; i < int(ehdr.phnum); i++ {
+			elf64phdr(phdr[i])
+		}
+		return uint32(ehdr.phnum) * ELF64PHDRSIZE
+	}
+
+	for i := 0; i < int(ehdr.phnum); i++ {
+		elf32phdr(phdr[i])
+	}
+	return uint32(ehdr.phnum) * ELF32PHDRSIZE
+}
+
+func newElfPhdr() *ElfPhdr {
+	e := new(ElfPhdr)
+	if ehdr.phnum >= NSECT {
+		Diag("too many phdrs")
+	} else {
+		phdr[ehdr.phnum] = e
+		ehdr.phnum++
+	}
+	if elf64 {
+		ehdr.shoff += ELF64PHDRSIZE
+	} else {
+		ehdr.shoff += ELF32PHDRSIZE
+	}
+	return e
+}
+
+func newElfShdr(name int64) *ElfShdr {
+	e := new(ElfShdr)
+	e.name = uint32(name)
+	e.shnum = int(ehdr.shnum)
+	if ehdr.shnum >= NSECT {
+		Diag("too many shdrs")
+	} else {
+		shdr[ehdr.shnum] = e
+		ehdr.shnum++
+	}
+
+	return e
+}
+
+func getElfEhdr() *ElfEhdr {
+	return &ehdr
+}
+
+func elf64writehdr() uint32 {
+	for i := 0; i < EI_NIDENT; i++ {
+		Cput(ehdr.ident[i])
+	}
+	Thearch.Wput(ehdr.type_)
+	Thearch.Wput(ehdr.machine)
+	Thearch.Lput(ehdr.version)
+	Thearch.Vput(ehdr.entry)
+	Thearch.Vput(ehdr.phoff)
+	Thearch.Vput(ehdr.shoff)
+	Thearch.Lput(ehdr.flags)
+	Thearch.Wput(ehdr.ehsize)
+	Thearch.Wput(ehdr.phentsize)
+	Thearch.Wput(ehdr.phnum)
+	Thearch.Wput(ehdr.shentsize)
+	Thearch.Wput(ehdr.shnum)
+	Thearch.Wput(ehdr.shstrndx)
+	return ELF64HDRSIZE
+}
+
+func elf32writehdr() uint32 {
+	for i := 0; i < EI_NIDENT; i++ {
+		Cput(ehdr.ident[i])
+	}
+	Thearch.Wput(ehdr.type_)
+	Thearch.Wput(ehdr.machine)
+	Thearch.Lput(ehdr.version)
+	Thearch.Lput(uint32(ehdr.entry))
+	Thearch.Lput(uint32(ehdr.phoff))
+	Thearch.Lput(uint32(ehdr.shoff))
+	Thearch.Lput(ehdr.flags)
+	Thearch.Wput(ehdr.ehsize)
+	Thearch.Wput(ehdr.phentsize)
+	Thearch.Wput(ehdr.phnum)
+	Thearch.Wput(ehdr.shentsize)
+	Thearch.Wput(ehdr.shnum)
+	Thearch.Wput(ehdr.shstrndx)
+	return ELF32HDRSIZE
+}
+
+func elfwritehdr() uint32 {
+	if elf64 {
+		return elf64writehdr()
+	}
+	return elf32writehdr()
+}
+
+/* Taken directly from the definition document for ELF64 */
+func elfhash(name []byte) uint32 {
+	var h uint32 = 0
+	var g uint32
+	for len(name) != 0 {
+		h = (h << 4) + uint32(name[0])
+		name = name[1:]
+		g = h & 0xf0000000
+		if g != 0 {
+			h ^= g >> 24
+		}
+		h &= 0x0fffffff
+	}
+
+	return h
+}
+
+func Elfwritedynent(s *LSym, tag int, val uint64) {
+	if elf64 {
+		Adduint64(Ctxt, s, uint64(tag))
+		Adduint64(Ctxt, s, val)
+	} else {
+		Adduint32(Ctxt, s, uint32(tag))
+		Adduint32(Ctxt, s, uint32(val))
+	}
+}
+
+func elfwritedynentsym(s *LSym, tag int, t *LSym) {
+	Elfwritedynentsymplus(s, tag, t, 0)
+}
+
+func Elfwritedynentsymplus(s *LSym, tag int, t *LSym, add int64) {
+	if elf64 {
+		Adduint64(Ctxt, s, uint64(tag))
+	} else {
+		Adduint32(Ctxt, s, uint32(tag))
+	}
+	Addaddrplus(Ctxt, s, t, add)
+}
+
+func elfwritedynentsymsize(s *LSym, tag int, t *LSym) {
+	if elf64 {
+		Adduint64(Ctxt, s, uint64(tag))
+	} else {
+		Adduint32(Ctxt, s, uint32(tag))
+	}
+	addsize(Ctxt, s, t)
+}
+
+func elfinterp(sh *ElfShdr, startva uint64, resoff uint64, p string) int {
+	interp = p
+	n := len(interp) + 1
+	sh.addr = startva + resoff - uint64(n)
+	sh.off = resoff - uint64(n)
+	sh.size = uint64(n)
+
+	return n
+}
+
+func elfwriteinterp() int {
+	sh := elfshname(".interp")
+	Cseek(int64(sh.off))
+	coutbuf.WriteString(interp)
+	Cput(0)
+	return int(sh.size)
+}
+
+func elfnote(sh *ElfShdr, startva uint64, resoff uint64, sz int, alloc bool) int {
+	n := 3*4 + uint64(sz) + resoff%4
+
+	sh.type_ = SHT_NOTE
+	if alloc {
+		sh.flags = SHF_ALLOC
+	}
+	sh.addralign = 4
+	sh.addr = startva + resoff - n
+	sh.off = resoff - n
+	sh.size = n - resoff%4
+
+	return int(n)
+}
+
+func elfwritenotehdr(str string, namesz uint32, descsz uint32, tag uint32) *ElfShdr {
+	sh := elfshname(str)
+
+	// Write Elf_Note header.
+	Cseek(int64(sh.off))
+
+	Thearch.Lput(namesz)
+	Thearch.Lput(descsz)
+	Thearch.Lput(tag)
+
+	return sh
+}
+
+// NetBSD Signature (as per sys/exec_elf.h)
+const (
+	ELF_NOTE_NETBSD_NAMESZ  = 7
+	ELF_NOTE_NETBSD_DESCSZ  = 4
+	ELF_NOTE_NETBSD_TAG     = 1
+	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 {
+	n := int(Rnd(ELF_NOTE_NETBSD_NAMESZ, 4) + Rnd(ELF_NOTE_NETBSD_DESCSZ, 4))
+	return elfnote(sh, startva, resoff, n, true)
+}
+
+func elfwritenetbsdsig() int {
+	// Write Elf_Note header.
+	sh := elfwritenotehdr(".note.netbsd.ident", ELF_NOTE_NETBSD_NAMESZ, ELF_NOTE_NETBSD_DESCSZ, ELF_NOTE_NETBSD_TAG)
+
+	if sh == nil {
+		return 0
+	}
+
+	// Followed by NetBSD string and version.
+	Cwrite(ELF_NOTE_NETBSD_NAME)
+	Cput(0)
+
+	Thearch.Lput(ELF_NOTE_NETBSD_VERSION)
+
+	return int(sh.size)
+}
+
+// OpenBSD Signature
+const (
+	ELF_NOTE_OPENBSD_NAMESZ  = 8
+	ELF_NOTE_OPENBSD_DESCSZ  = 4
+	ELF_NOTE_OPENBSD_TAG     = 1
+	ELF_NOTE_OPENBSD_VERSION = 0
+)
+
+var ELF_NOTE_OPENBSD_NAME = []byte("OpenBSD\x00")
+
+func elfopenbsdsig(sh *ElfShdr, startva uint64, resoff uint64) int {
+	n := ELF_NOTE_OPENBSD_NAMESZ + ELF_NOTE_OPENBSD_DESCSZ
+	return elfnote(sh, startva, resoff, n, true)
+}
+
+func elfwriteopenbsdsig() int {
+	// Write Elf_Note header.
+	sh := elfwritenotehdr(".note.openbsd.ident", ELF_NOTE_OPENBSD_NAMESZ, ELF_NOTE_OPENBSD_DESCSZ, ELF_NOTE_OPENBSD_TAG)
+
+	if sh == nil {
+		return 0
+	}
+
+	// Followed by OpenBSD string and version.
+	Cwrite(ELF_NOTE_OPENBSD_NAME)
+
+	Thearch.Lput(ELF_NOTE_OPENBSD_VERSION)
+
+	return int(sh.size)
+}
+
+func addbuildinfo(val string) {
+	var j int
+
+	if val[0] != '0' || val[1] != 'x' {
+		Exitf("-B argument must start with 0x: %s", val)
+	}
+
+	ov := val
+	val = val[2:]
+	i := 0
+	var b int
+	for val != "" {
+		if len(val) == 1 {
+			Exitf("-B argument must have even number of digits: %s", ov)
+		}
+
+		b = 0
+		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'
+			} else if val[0] >= 'a' && val[0] <= 'f' {
+				b += int(val[0]) - 'a' + 10
+			} else if val[0] >= 'A' && val[0] <= 'F' {
+				b += int(val[0]) - 'A' + 10
+			} else {
+				Exitf("-B argument contains invalid hex digit %c: %s", val[0], ov)
+			}
+		}
+
+		const maxLen = 32
+		if i >= maxLen {
+			Exitf("-B option too long (max %d digits): %s", maxLen, ov)
+		}
+
+		buildinfo = append(buildinfo, uint8(b))
+		i++
+	}
+
+	buildinfo = buildinfo[:i]
+}
+
+// Build info note
+const (
+	ELF_NOTE_BUILDINFO_NAMESZ = 4
+	ELF_NOTE_BUILDINFO_TAG    = 3
+)
+
+var ELF_NOTE_BUILDINFO_NAME = []byte("GNU\x00")
+
+func elfbuildinfo(sh *ElfShdr, startva uint64, resoff uint64) int {
+	n := int(ELF_NOTE_BUILDINFO_NAMESZ + Rnd(int64(len(buildinfo)), 4))
+	return elfnote(sh, startva, resoff, n, true)
+}
+
+func elfgobuildid(sh *ElfShdr, startva uint64, resoff uint64) int {
+	n := len(ELF_NOTE_GO_NAME) + int(Rnd(int64(len(buildid)), 4))
+	return elfnote(sh, startva, resoff, n, true)
+}
+
+func elfwritebuildinfo() int {
+	sh := elfwritenotehdr(".note.gnu.build-id", ELF_NOTE_BUILDINFO_NAMESZ, uint32(len(buildinfo)), ELF_NOTE_BUILDINFO_TAG)
+	if sh == nil {
+		return 0
+	}
+
+	Cwrite(ELF_NOTE_BUILDINFO_NAME)
+	Cwrite(buildinfo)
+	var zero = make([]byte, 4)
+	Cwrite(zero[:int(Rnd(int64(len(buildinfo)), 4)-int64(len(buildinfo)))])
+
+	return int(sh.size)
+}
+
+func elfwritegobuildid() int {
+	sh := elfwritenotehdr(".note.go.buildid", uint32(len(ELF_NOTE_GO_NAME)), uint32(len(buildid)), ELF_NOTE_GOBUILDID_TAG)
+	if sh == nil {
+		return 0
+	}
+
+	Cwrite(ELF_NOTE_GO_NAME)
+	Cwrite([]byte(buildid))
+	var zero = make([]byte, 4)
+	Cwrite(zero[:int(Rnd(int64(len(buildid)), 4)-int64(len(buildid)))])
+
+	return int(sh.size)
+}
+
+// Go specific notes
+const (
+	ELF_NOTE_GOPKGLIST_TAG = 1
+	ELF_NOTE_GOABIHASH_TAG = 2
+	ELF_NOTE_GODEPS_TAG    = 3
+	ELF_NOTE_GOBUILDID_TAG = 4
+)
+
+var ELF_NOTE_GO_NAME = []byte("Go\x00\x00")
+
+var elfverneed int
+
+type Elfaux struct {
+	next *Elfaux
+	num  int
+	vers string
+}
+
+type Elflib struct {
+	next *Elflib
+	aux  *Elfaux
+	file string
+}
+
+func addelflib(list **Elflib, file string, vers string) *Elfaux {
+	var lib *Elflib
+
+	for lib = *list; lib != nil; lib = lib.next {
+		if lib.file == file {
+			goto havelib
+		}
+	}
+	lib = new(Elflib)
+	lib.next = *list
+	lib.file = file
+	*list = lib
+
+havelib:
+	for aux := lib.aux; aux != nil; aux = aux.next {
+		if aux.vers == vers {
+			return aux
+		}
+	}
+	aux := new(Elfaux)
+	aux.next = lib.aux
+	aux.vers = vers
+	lib.aux = aux
+
+	return aux
+}
+
+func elfdynhash() {
+	if !Iself {
+		return
+	}
+
+	nsym := Nelfsym
+	s := Linklookup(Ctxt, ".hash", 0)
+	s.Type = obj.SELFROSECT
+	s.Reachable = true
+
+	i := nsym
+	nbucket := 1
+	for i > 0 {
+		nbucket++
+		i >>= 1
+	}
+
+	var needlib *Elflib
+	need := make([]*Elfaux, nsym)
+	chain := make([]uint32, nsym)
+	buckets := make([]uint32, nbucket)
+
+	var b int
+	var hc uint32
+	var name string
+	for sy := Ctxt.Allsym; sy != nil; sy = sy.Allsym {
+		if sy.Dynid <= 0 {
+			continue
+		}
+
+		if sy.Dynimpvers != "" {
+			need[sy.Dynid] = addelflib(&needlib, sy.Dynimplib, sy.Dynimpvers)
+		}
+
+		name = sy.Extname
+		hc = elfhash([]byte(name))
+
+		b = int(hc % uint32(nbucket))
+		chain[sy.Dynid] = buckets[b]
+		buckets[b] = uint32(sy.Dynid)
+	}
+
+	Adduint32(Ctxt, s, uint32(nbucket))
+	Adduint32(Ctxt, s, uint32(nsym))
+	for i := 0; i < nbucket; i++ {
+		Adduint32(Ctxt, s, buckets[i])
+	}
+	for i := 0; i < nsym; i++ {
+		Adduint32(Ctxt, s, chain[i])
+	}
+
+	// version symbols
+	dynstr := Linklookup(Ctxt, ".dynstr", 0)
+
+	s = Linklookup(Ctxt, ".gnu.version_r", 0)
+	i = 2
+	nfile := 0
+	var j int
+	var x *Elfaux
+	for l := needlib; l != nil; l = l.next {
+		nfile++
+
+		// header
+		Adduint16(Ctxt, s, 1) // table version
+		j = 0
+		for x = l.aux; x != nil; x = x.next {
+			j++
+		}
+		Adduint16(Ctxt, s, uint16(j))                         // aux count
+		Adduint32(Ctxt, s, uint32(Addstring(dynstr, l.file))) // file string offset
+		Adduint32(Ctxt, s, 16)                                // offset from header to first aux
+		if l.next != nil {
+			Adduint32(Ctxt, s, 16+uint32(j)*16) // offset from this header to next
+		} else {
+			Adduint32(Ctxt, s, 0)
+		}
+
+		for x = l.aux; x != nil; x = x.next {
+			x.num = i
+			i++
+
+			// aux struct
+			Adduint32(Ctxt, s, elfhash([]byte(x.vers)))           // hash
+			Adduint16(Ctxt, s, 0)                                 // flags
+			Adduint16(Ctxt, s, uint16(x.num))                     // other - index we refer to this by
+			Adduint32(Ctxt, s, uint32(Addstring(dynstr, x.vers))) // version string offset
+			if x.next != nil {
+				Adduint32(Ctxt, s, 16) // offset from this aux to next
+			} else {
+				Adduint32(Ctxt, s, 0)
+			}
+		}
+	}
+
+	// version references
+	s = Linklookup(Ctxt, ".gnu.version", 0)
+
+	for i := 0; i < nsym; i++ {
+		if i == 0 {
+			Adduint16(Ctxt, s, 0) // first entry - no symbol
+		} else if need[i] == nil {
+			Adduint16(Ctxt, s, 1) // global
+		} else {
+			Adduint16(Ctxt, s, uint16(need[i].num))
+		}
+	}
+
+	s = Linklookup(Ctxt, ".dynamic", 0)
+	elfverneed = nfile
+	if elfverneed != 0 {
+		elfwritedynentsym(s, DT_VERNEED, Linklookup(Ctxt, ".gnu.version_r", 0))
+		Elfwritedynent(s, DT_VERNEEDNUM, uint64(nfile))
+		elfwritedynentsym(s, DT_VERSYM, Linklookup(Ctxt, ".gnu.version", 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)
+		}
+	default:
+		sy := Linklookup(Ctxt, ".rel.plt", 0)
+		if sy.Size > 0 {
+			Elfwritedynent(s, DT_PLTREL, DT_REL)
+			elfwritedynentsymsize(s, DT_PLTRELSZ, sy)
+			elfwritedynentsym(s, DT_JMPREL, sy)
+		}
+	}
+
+	Elfwritedynent(s, DT_NULL, 0)
+}
+
+func elfphload(seg *Segment) *ElfPhdr {
+	ph := newElfPhdr()
+	ph.type_ = PT_LOAD
+	if seg.Rwx&4 != 0 {
+		ph.flags |= PF_R
+	}
+	if seg.Rwx&2 != 0 {
+		ph.flags |= PF_W
+	}
+	if seg.Rwx&1 != 0 {
+		ph.flags |= PF_X
+	}
+	ph.vaddr = seg.Vaddr
+	ph.paddr = seg.Vaddr
+	ph.memsz = seg.Length
+	ph.off = seg.Fileoff
+	ph.filesz = seg.Filelen
+	ph.align = uint64(INITRND)
+
+	return ph
+}
+
+func elfshname(name string) *ElfShdr {
+	var off int
+	var sh *ElfShdr
+
+	for i := 0; i < nelfstr; i++ {
+		if name == elfstr[i].s {
+			off = elfstr[i].off
+			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
+}
+
+func elfshalloc(sect *Section) *ElfShdr {
+	sh := elfshname(sect.Name)
+	sect.Elfsect = sh
+	return sh
+}
+
+func elfshbits(sect *Section) *ElfShdr {
+	sh := elfshalloc(sect)
+	// If this section has already been set up as a note, we assume type_ and
+	// flags are already correct, but the other fields still need filling in.
+	if sh.type_ == SHT_NOTE {
+		if Linkmode != LinkExternal {
+			// TODO(mwhudson): the approach here will work OK when
+			// linking internally for notes that we want to be included
+			// in a loadable segment (e.g. the abihash note) but not for
+			// notes that we do not want to be mapped (e.g. the package
+			// list note). The real fix is probably to define new values
+			// for LSym.Type corresponding to mapped and unmapped notes
+			// and handle them in dodata().
+			Diag("sh.type_ == SHT_NOTE in elfshbits when linking internally")
+		}
+		sh.addralign = uint64(sect.Align)
+		sh.size = sect.Length
+		sh.off = sect.Seg.Fileoff + sect.Vaddr - sect.Seg.Vaddr
+		return sh
+	}
+	if sh.type_ > 0 {
+		return sh
+	}
+
+	if sect.Vaddr < sect.Seg.Vaddr+sect.Seg.Filelen {
+		sh.type_ = SHT_PROGBITS
+	} else {
+		sh.type_ = SHT_NOBITS
+	}
+	sh.flags = SHF_ALLOC
+	if sect.Rwx&1 != 0 {
+		sh.flags |= SHF_EXECINSTR
+	}
+	if sect.Rwx&2 != 0 {
+		sh.flags |= SHF_WRITE
+	}
+	if sect.Name == ".tbss" {
+		if goos != "android" {
+			sh.flags |= SHF_TLS // no TLS on android
+		}
+		sh.type_ = SHT_NOBITS
+	}
+
+	if Linkmode != LinkExternal {
+		sh.addr = sect.Vaddr
+	}
+	sh.addralign = uint64(sect.Align)
+	sh.size = sect.Length
+	sh.off = sect.Seg.Fileoff + sect.Vaddr - sect.Seg.Vaddr
+
+	return sh
+}
+
+func elfshreloc(sect *Section) *ElfShdr {
+	// If main section is SHT_NOBITS, nothing to relocate.
+	// Also nothing to relocate in .shstrtab or notes.
+	if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
+		return nil
+	}
+	if sect.Name == ".shstrtab" || sect.Name == ".tbss" {
+		return nil
+	}
+	if sect.Elfsect.type_ == SHT_NOTE {
+		return nil
+	}
+
+	var prefix string
+	var typ int
+	switch Thearch.Thechar {
+	case '6', '7', '9':
+		prefix = ".rela"
+		typ = SHT_RELA
+	default:
+		prefix = ".rel"
+		typ = SHT_REL
+	}
+
+	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 {
+		sh.entsize += uint64(Thearch.Regsize)
+	}
+	sh.link = uint32(elfshname(".symtab").shnum)
+	sh.info = uint32(sect.Elfsect.shnum)
+	sh.off = sect.Reloff
+	sh.size = sect.Rellen
+	sh.addralign = uint64(Thearch.Regsize)
+	return sh
+}
+
+func elfrelocsect(sect *Section, first *LSym) {
+	// If main section is SHT_NOBITS, nothing to relocate.
+	// Also nothing to relocate in .shstrtab.
+	if sect.Vaddr >= sect.Seg.Vaddr+sect.Seg.Filelen {
+		return
+	}
+	if sect.Name == ".shstrtab" {
+		return
+	}
+
+	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.Elfsym == 0 {
+				Diag("reloc %d to non-elf symbol %s (outer=%s) %d", r.Type, r.Sym.Name, r.Xsym.Name, r.Sym.Type)
+			}
+			if Thearch.Elfreloc1(r, int64(uint64(sym.Value+int64(r.Off))-sect.Vaddr)) < 0 {
+				Diag("unsupported obj reloc %d/%d to %s", r.Type, r.Siz, r.Sym.Name)
+			}
+		}
+	}
+
+	sect.Rellen = uint64(Cpos()) - sect.Reloff
+}
+
+func Elfemitreloc() {
+	for Cpos()&7 != 0 {
+		Cput(0)
+	}
+
+	elfrelocsect(Segtext.Sect, Ctxt.Textp)
+	for sect := Segtext.Sect.Next; sect != nil; sect = sect.Next {
+		elfrelocsect(sect, datap)
+	}
+	for sect := Segrodata.Sect; sect != nil; sect = sect.Next {
+		elfrelocsect(sect, datap)
+	}
+	for sect := Segdata.Sect; sect != nil; sect = sect.Next {
+		elfrelocsect(sect, datap)
+	}
+}
+
+func addgonote(sectionName string, tag uint32, desc []byte) {
+	s := Linklookup(Ctxt, sectionName, 0)
+	s.Reachable = true
+	s.Type = obj.SELFROSECT
+	// namesz
+	Adduint32(Ctxt, s, uint32(len(ELF_NOTE_GO_NAME)))
+	// descsz
+	Adduint32(Ctxt, s, uint32(len(desc)))
+	// tag
+	Adduint32(Ctxt, s, tag)
+	// name + padding
+	s.P = append(s.P, ELF_NOTE_GO_NAME...)
+	for len(s.P)%4 != 0 {
+		s.P = append(s.P, 0)
+	}
+	// desc + padding
+	s.P = append(s.P, desc...)
+	for len(s.P)%4 != 0 {
+		s.P = append(s.P, 0)
+	}
+	s.Size = int64(len(s.P))
+}
+
+func doelf() {
+	if !Iself {
+		return
+	}
+
+	/* predefine strings we need for section headers */
+	shstrtab := Linklookup(Ctxt, ".shstrtab", 0)
+
+	shstrtab.Type = obj.SELFROSECT
+	shstrtab.Reachable = true
+
+	Addstring(shstrtab, "")
+	Addstring(shstrtab, ".text")
+	Addstring(shstrtab, ".noptrdata")
+	Addstring(shstrtab, ".data")
+	Addstring(shstrtab, ".bss")
+	Addstring(shstrtab, ".noptrbss")
+
+	// generate .tbss section (except for OpenBSD where it's not supported)
+	// for dynamic internal linker or external linking, so that various
+	// binutils could correctly calculate PT_TLS size.
+	// see https://golang.org/issue/5200.
+	if HEADTYPE != obj.Hopenbsd {
+		if Debug['d'] == 0 || Linkmode == LinkExternal {
+			Addstring(shstrtab, ".tbss")
+		}
+	}
+	if HEADTYPE == obj.Hnetbsd {
+		Addstring(shstrtab, ".note.netbsd.ident")
+	}
+	if HEADTYPE == obj.Hopenbsd {
+		Addstring(shstrtab, ".note.openbsd.ident")
+	}
+	if len(buildinfo) > 0 {
+		Addstring(shstrtab, ".note.gnu.build-id")
+	}
+	if buildid != "" {
+		Addstring(shstrtab, ".note.go.buildid")
+	}
+	Addstring(shstrtab, ".elfdata")
+	Addstring(shstrtab, ".rodata")
+	Addstring(shstrtab, ".typelink")
+	Addstring(shstrtab, ".gosymtab")
+	Addstring(shstrtab, ".gopclntab")
+
+	if Linkmode == LinkExternal {
+		Debug['d'] = 1
+
+		switch Thearch.Thechar {
+		case '6', '7', '9':
+			Addstring(shstrtab, ".rela.text")
+			Addstring(shstrtab, ".rela.rodata")
+			Addstring(shstrtab, ".rela.typelink")
+			Addstring(shstrtab, ".rela.gosymtab")
+			Addstring(shstrtab, ".rela.gopclntab")
+			Addstring(shstrtab, ".rela.noptrdata")
+			Addstring(shstrtab, ".rela.data")
+
+		default:
+			Addstring(shstrtab, ".rel.text")
+			Addstring(shstrtab, ".rel.rodata")
+			Addstring(shstrtab, ".rel.typelink")
+			Addstring(shstrtab, ".rel.gosymtab")
+			Addstring(shstrtab, ".rel.gopclntab")
+			Addstring(shstrtab, ".rel.noptrdata")
+			Addstring(shstrtab, ".rel.data")
+		}
+
+		// add a .note.GNU-stack section to mark the stack as non-executable
+		Addstring(shstrtab, ".note.GNU-stack")
+
+		if Buildmode == BuildmodeShared {
+			Addstring(shstrtab, ".note.go.abihash")
+			Addstring(shstrtab, ".note.go.pkg-list")
+			Addstring(shstrtab, ".note.go.deps")
+		}
+
+		if buildid != "" {
+			Addstring(shstrtab, ".note.go.buildid")
+		}
+	}
+
+	hasinitarr := Linkshared
+
+	/* shared library initializer */
+	switch Buildmode {
+	case BuildmodeCArchive, BuildmodeCShared, BuildmodeShared:
+		hasinitarr = true
+	}
+
+	if hasinitarr {
+		Addstring(shstrtab, ".init_array")
+		switch Thearch.Thechar {
+		case '6', '7', '9':
+			Addstring(shstrtab, ".rela.init_array")
+		default:
+			Addstring(shstrtab, ".rel.init_array")
+		}
+	}
+
+	if Debug['s'] == 0 {
+		Addstring(shstrtab, ".symtab")
+		Addstring(shstrtab, ".strtab")
+		dwarfaddshstrings(shstrtab)
+	}
+
+	Addstring(shstrtab, ".shstrtab")
+
+	if Debug['d'] == 0 { /* -d suppresses dynamic loader format */
+		Addstring(shstrtab, ".interp")
+		Addstring(shstrtab, ".hash")
+		Addstring(shstrtab, ".got")
+		if Thearch.Thechar == '9' {
+			Addstring(shstrtab, ".glink")
+		}
+		Addstring(shstrtab, ".got.plt")
+		Addstring(shstrtab, ".dynamic")
+		Addstring(shstrtab, ".dynsym")
+		Addstring(shstrtab, ".dynstr")
+		switch Thearch.Thechar {
+		case '6', '7', '9':
+			Addstring(shstrtab, ".rela")
+			Addstring(shstrtab, ".rela.plt")
+		default:
+			Addstring(shstrtab, ".rel")
+			Addstring(shstrtab, ".rel.plt")
+		}
+
+		Addstring(shstrtab, ".plt")
+		Addstring(shstrtab, ".gnu.version")
+		Addstring(shstrtab, ".gnu.version_r")
+
+		/* dynamic symbol table - first entry all zeros */
+		s := Linklookup(Ctxt, ".dynsym", 0)
+
+		s.Type = obj.SELFROSECT
+		s.Reachable = true
+		switch Thearch.Thechar {
+		case '6', '7', '9':
+			s.Size += ELF64SYMSIZE
+		default:
+			s.Size += ELF32SYMSIZE
+		}
+
+		/* dynamic string table */
+		s = Linklookup(Ctxt, ".dynstr", 0)
+
+		s.Type = obj.SELFROSECT
+		s.Reachable = true
+		if s.Size == 0 {
+			Addstring(s, "")
+		}
+		dynstr := s
+
+		/* relocation table */
+		switch Thearch.Thechar {
+		case '6', '7', '9':
+			s = Linklookup(Ctxt, ".rela", 0)
+		default:
+			s = Linklookup(Ctxt, ".rel", 0)
+		}
+		s.Reachable = true
+		s.Type = obj.SELFROSECT
+
+		/* global offset table */
+		s = Linklookup(Ctxt, ".got", 0)
+
+		s.Reachable = true
+		s.Type = obj.SELFGOT // writable
+
+		/* ppc64 glink resolver */
+		if Thearch.Thechar == '9' {
+			s := Linklookup(Ctxt, ".glink", 0)
+			s.Reachable = true
+			s.Type = obj.SELFRXSECT
+		}
+
+		/* hash */
+		s = Linklookup(Ctxt, ".hash", 0)
+
+		s.Reachable = true
+		s.Type = obj.SELFROSECT
+
+		s = Linklookup(Ctxt, ".got.plt", 0)
+		s.Reachable = true
+		s.Type = obj.SELFSECT // writable
+
+		s = Linklookup(Ctxt, ".plt", 0)
+
+		s.Reachable = true
+		if Thearch.Thechar == '9' {
+			// In the ppc64 ABI, .plt is a data section
+			// written by the dynamic linker.
+			s.Type = obj.SELFSECT
+		} else {
+			s.Type = obj.SELFRXSECT
+		}
+
+		Thearch.Elfsetupplt()
+
+		switch Thearch.Thechar {
+		case '6', '7', '9':
+			s = Linklookup(Ctxt, ".rela.plt", 0)
+		default:
+			s = Linklookup(Ctxt, ".rel.plt", 0)
+		}
+		s.Reachable = true
+		s.Type = obj.SELFROSECT
+
+		s = Linklookup(Ctxt, ".gnu.version", 0)
+		s.Reachable = true
+		s.Type = obj.SELFROSECT
+
+		s = Linklookup(Ctxt, ".gnu.version_r", 0)
+		s.Reachable = true
+		s.Type = obj.SELFROSECT
+
+		/* define dynamic elf table */
+		s = Linklookup(Ctxt, ".dynamic", 0)
+
+		s.Reachable = true
+		s.Type = obj.SELFSECT // writable
+
+		/*
+		 * .dynamic table
+		 */
+		elfwritedynentsym(s, DT_HASH, Linklookup(Ctxt, ".hash", 0))
+
+		elfwritedynentsym(s, DT_SYMTAB, Linklookup(Ctxt, ".dynsym", 0))
+		switch Thearch.Thechar {
+		case '6', '7', '9':
+			Elfwritedynent(s, DT_SYMENT, ELF64SYMSIZE)
+		default:
+			Elfwritedynent(s, DT_SYMENT, ELF32SYMSIZE)
+		}
+		elfwritedynentsym(s, DT_STRTAB, Linklookup(Ctxt, ".dynstr", 0))
+		elfwritedynentsymsize(s, DT_STRSZ, Linklookup(Ctxt, ".dynstr", 0))
+		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)
+		default:
+			elfwritedynentsym(s, DT_REL, Linklookup(Ctxt, ".rel", 0))
+			elfwritedynentsymsize(s, DT_RELSZ, Linklookup(Ctxt, ".rel", 0))
+			Elfwritedynent(s, DT_RELENT, ELF32RELSIZE)
+		}
+
+		if rpath.val != "" {
+			Elfwritedynent(s, DT_RUNPATH, uint64(Addstring(dynstr, rpath.val)))
+		}
+
+		if Thearch.Thechar == '9' {
+			elfwritedynentsym(s, DT_PLTGOT, Linklookup(Ctxt, ".plt", 0))
+		} else {
+			elfwritedynentsym(s, DT_PLTGOT, Linklookup(Ctxt, ".got.plt", 0))
+		}
+
+		if Thearch.Thechar == '9' {
+			Elfwritedynent(s, DT_PPC64_OPT, 0)
+		}
+
+		// Solaris dynamic linker can't handle an empty .rela.plt if
+		// DT_JMPREL is emitted so we have to defer generation of DT_PLTREL,
+		// DT_PLTRELSZ, and DT_JMPREL dynamic entries until after we know the
+		// size of .rel(a).plt section.
+		Elfwritedynent(s, DT_DEBUG, 0)
+	}
+
+	if Buildmode == BuildmodeShared {
+		// The go.link.abihashbytes symbol will be pointed at the appropriate
+		// part of the .note.go.abihash section in data.go:func address().
+		s := Linklookup(Ctxt, "go.link.abihashbytes", 0)
+		s.Local = true
+		s.Type = obj.SRODATA
+		s.Special = 1
+		s.Reachable = true
+		s.Size = int64(sha1.Size)
+
+		sort.Sort(byPkg(Ctxt.Library))
+		h := sha1.New()
+		for _, l := range Ctxt.Library {
+			h.Write(l.hash)
+		}
+		addgonote(".note.go.abihash", ELF_NOTE_GOABIHASH_TAG, h.Sum([]byte{}))
+		addgonote(".note.go.pkg-list", ELF_NOTE_GOPKGLIST_TAG, []byte(pkglistfornote))
+		var deplist []string
+		for _, shlib := range Ctxt.Shlibs {
+			deplist = append(deplist, filepath.Base(shlib.Path))
+		}
+		addgonote(".note.go.deps", ELF_NOTE_GODEPS_TAG, []byte(strings.Join(deplist, "\n")))
+	}
+
+	if Linkmode == LinkExternal && buildid != "" {
+		addgonote(".note.go.buildid", ELF_NOTE_GOBUILDID_TAG, []byte(buildid))
+	}
+}
+
+// Do not write DT_NULL.  elfdynhash will finish it.
+func shsym(sh *ElfShdr, s *LSym) {
+	addr := Symaddr(s)
+	if sh.flags&SHF_ALLOC != 0 {
+		sh.addr = uint64(addr)
+	}
+	sh.off = uint64(datoff(addr))
+	sh.size = uint64(s.Size)
+}
+
+func phsh(ph *ElfPhdr, sh *ElfShdr) {
+	ph.vaddr = sh.addr
+	ph.paddr = ph.vaddr
+	ph.off = sh.off
+	ph.filesz = sh.size
+	ph.memsz = sh.size
+	ph.align = sh.addralign
+}
+
+func Asmbelfsetup() {
+	/* This null SHdr must appear before all others */
+	elfshname("")
+
+	for sect := Segtext.Sect; sect != nil; sect = sect.Next {
+		elfshalloc(sect)
+	}
+	for sect := Segrodata.Sect; sect != nil; sect = sect.Next {
+		elfshalloc(sect)
+	}
+	for sect := Segdata.Sect; sect != nil; sect = sect.Next {
+		elfshalloc(sect)
+	}
+}
+
+func Asmbelf(symo int64) {
+	eh := getElfEhdr()
+	switch Thearch.Thechar {
+	default:
+		Exitf("unknown architecture in asmbelf: %v", Thearch.Thechar)
+	case '5':
+		eh.machine = EM_ARM
+	case '6':
+		eh.machine = EM_X86_64
+	case '7':
+		eh.machine = EM_AARCH64
+	case '8':
+		eh.machine = EM_386
+	case '9':
+		eh.machine = EM_PPC64
+	}
+
+	elfreserve := int64(ELFRESERVE)
+	startva := INITTEXT - int64(HEADR)
+	resoff := elfreserve
+
+	var pph *ElfPhdr
+	var pnote *ElfPhdr
+	if Linkmode == LinkExternal {
+		/* skip program headers */
+		eh.phoff = 0
+
+		eh.phentsize = 0
+
+		if Buildmode == BuildmodeShared {
+			sh := elfshname(".note.go.pkg-list")
+			sh.type_ = SHT_NOTE
+			sh = elfshname(".note.go.abihash")
+			sh.type_ = SHT_NOTE
+			sh.flags = SHF_ALLOC
+			sh = elfshname(".note.go.deps")
+			sh.type_ = SHT_NOTE
+		}
+
+		if buildid != "" {
+			sh := elfshname(".note.go.buildid")
+			sh.type_ = SHT_NOTE
+			sh.flags = SHF_ALLOC
+		}
+
+		goto elfobj
+	}
+
+	/* program header info */
+	pph = newElfPhdr()
+
+	pph.type_ = PT_PHDR
+	pph.flags = PF_R
+	pph.off = uint64(eh.ehsize)
+	pph.vaddr = uint64(INITTEXT) - uint64(HEADR) + pph.off
+	pph.paddr = uint64(INITTEXT) - uint64(HEADR) + pph.off
+	pph.align = uint64(INITRND)
+
+	/*
+	 * PHDR must be in a loaded segment. Adjust the text
+	 * segment boundaries downwards to include it.
+	 * Except on NaCl where it must not be loaded.
+	 */
+	if HEADTYPE != obj.Hnacl {
+		o := int64(Segtext.Vaddr - pph.vaddr)
+		Segtext.Vaddr -= uint64(o)
+		Segtext.Length += uint64(o)
+		o = int64(Segtext.Fileoff - pph.off)
+		Segtext.Fileoff -= uint64(o)
+		Segtext.Filelen += uint64(o)
+	}
+
+	if Debug['d'] == 0 { /* -d suppresses dynamic loader format */
+		/* interpreter */
+		sh := elfshname(".interp")
+
+		sh.type_ = SHT_PROGBITS
+		sh.flags = SHF_ALLOC
+		sh.addralign = 1
+		if interpreter == "" {
+			switch HEADTYPE {
+			case obj.Hlinux:
+				interpreter = Thearch.Linuxdynld
+
+			case obj.Hfreebsd:
+				interpreter = Thearch.Freebsddynld
+
+			case obj.Hnetbsd:
+				interpreter = Thearch.Netbsddynld
+
+			case obj.Hopenbsd:
+				interpreter = Thearch.Openbsddynld
+
+			case obj.Hdragonfly:
+				interpreter = Thearch.Dragonflydynld
+
+			case obj.Hsolaris:
+				interpreter = Thearch.Solarisdynld
+			}
+		}
+
+		resoff -= int64(elfinterp(sh, uint64(startva), uint64(resoff), interpreter))
+
+		ph := newElfPhdr()
+		ph.type_ = PT_INTERP
+		ph.flags = PF_R
+		phsh(ph, sh)
+	}
+
+	pnote = nil
+	if HEADTYPE == obj.Hnetbsd || HEADTYPE == obj.Hopenbsd {
+		var sh *ElfShdr
+		switch HEADTYPE {
+		case obj.Hnetbsd:
+			sh = elfshname(".note.netbsd.ident")
+			resoff -= int64(elfnetbsdsig(sh, uint64(startva), uint64(resoff)))
+
+		case obj.Hopenbsd:
+			sh = elfshname(".note.openbsd.ident")
+			resoff -= int64(elfopenbsdsig(sh, uint64(startva), uint64(resoff)))
+		}
+
+		pnote = newElfPhdr()
+		pnote.type_ = PT_NOTE
+		pnote.flags = PF_R
+		phsh(pnote, sh)
+	}
+
+	if len(buildinfo) > 0 {
+		sh := elfshname(".note.gnu.build-id")
+		resoff -= int64(elfbuildinfo(sh, uint64(startva), uint64(resoff)))
+
+		if pnote == nil {
+			pnote = newElfPhdr()
+			pnote.type_ = PT_NOTE
+			pnote.flags = PF_R
+		}
+
+		phsh(pnote, sh)
+	}
+
+	if buildid != "" {
+		sh := elfshname(".note.go.buildid")
+		resoff -= int64(elfgobuildid(sh, uint64(startva), uint64(resoff)))
+
+		pnote := newElfPhdr()
+		pnote.type_ = PT_NOTE
+		pnote.flags = PF_R
+		phsh(pnote, sh)
+	}
+
+	// Additions to the reserved area must be above this line.
+
+	elfphload(&Segtext)
+	if Segrodata.Sect != nil {
+		elfphload(&Segrodata)
+	}
+	elfphload(&Segdata)
+
+	/* Dynamic linking sections */
+	if Debug['d'] == 0 {
+		sh := elfshname(".dynsym")
+		sh.type_ = SHT_DYNSYM
+		sh.flags = SHF_ALLOC
+		if elf64 {
+			sh.entsize = ELF64SYMSIZE
+		} else {
+			sh.entsize = ELF32SYMSIZE
+		}
+		sh.addralign = uint64(Thearch.Regsize)
+		sh.link = uint32(elfshname(".dynstr").shnum)
+
+		// sh->info = index of first non-local symbol (number of local symbols)
+		shsym(sh, Linklookup(Ctxt, ".dynsym", 0))
+
+		sh = elfshname(".dynstr")
+		sh.type_ = SHT_STRTAB
+		sh.flags = SHF_ALLOC
+		sh.addralign = 1
+		shsym(sh, Linklookup(Ctxt, ".dynstr", 0))
+
+		if elfverneed != 0 {
+			sh := elfshname(".gnu.version")
+			sh.type_ = SHT_GNU_VERSYM
+			sh.flags = SHF_ALLOC
+			sh.addralign = 2
+			sh.link = uint32(elfshname(".dynsym").shnum)
+			sh.entsize = 2
+			shsym(sh, Linklookup(Ctxt, ".gnu.version", 0))
+
+			sh = elfshname(".gnu.version_r")
+			sh.type_ = SHT_GNU_VERNEED
+			sh.flags = SHF_ALLOC
+			sh.addralign = uint64(Thearch.Regsize)
+			sh.info = uint32(elfverneed)
+			sh.link = uint32(elfshname(".dynstr").shnum)
+			shsym(sh, Linklookup(Ctxt, ".gnu.version_r", 0))
+		}
+
+		switch eh.machine {
+		case EM_X86_64, EM_PPC64, EM_AARCH64:
+			sh := elfshname(".rela.plt")
+			sh.type_ = SHT_RELA
+			sh.flags = SHF_ALLOC
+			sh.entsize = ELF64RELASIZE
+			sh.addralign = uint64(Thearch.Regsize)
+			sh.link = uint32(elfshname(".dynsym").shnum)
+			sh.info = uint32(elfshname(".plt").shnum)
+			shsym(sh, Linklookup(Ctxt, ".rela.plt", 0))
+
+			sh = elfshname(".rela")
+			sh.type_ = SHT_RELA
+			sh.flags = SHF_ALLOC
+			sh.entsize = ELF64RELASIZE
+			sh.addralign = 8
+			sh.link = uint32(elfshname(".dynsym").shnum)
+			shsym(sh, Linklookup(Ctxt, ".rela", 0))
+
+		default:
+			sh := elfshname(".rel.plt")
+			sh.type_ = SHT_REL
+			sh.flags = SHF_ALLOC
+			sh.entsize = ELF32RELSIZE
+			sh.addralign = 4
+			sh.link = uint32(elfshname(".dynsym").shnum)
+			shsym(sh, Linklookup(Ctxt, ".rel.plt", 0))
+
+			sh = elfshname(".rel")
+			sh.type_ = SHT_REL
+			sh.flags = SHF_ALLOC
+			sh.entsize = ELF32RELSIZE
+			sh.addralign = 4
+			sh.link = uint32(elfshname(".dynsym").shnum)
+			shsym(sh, Linklookup(Ctxt, ".rel", 0))
+		}
+
+		if eh.machine == EM_PPC64 {
+			sh := elfshname(".glink")
+			sh.type_ = SHT_PROGBITS
+			sh.flags = SHF_ALLOC + SHF_EXECINSTR
+			sh.addralign = 4
+			shsym(sh, Linklookup(Ctxt, ".glink", 0))
+		}
+
+		sh = elfshname(".plt")
+		sh.type_ = SHT_PROGBITS
+		sh.flags = SHF_ALLOC + SHF_EXECINSTR
+		if eh.machine == EM_X86_64 {
+			sh.entsize = 16
+		} else if eh.machine == EM_PPC64 {
+			// On ppc64, this is just a table of addresses
+			// filled by the dynamic linker
+			sh.type_ = SHT_NOBITS
+
+			sh.flags = SHF_ALLOC + SHF_WRITE
+			sh.entsize = 8
+		} else {
+			sh.entsize = 4
+		}
+		sh.addralign = sh.entsize
+		shsym(sh, Linklookup(Ctxt, ".plt", 0))
+
+		// 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.type_ = SHT_PROGBITS
+			sh.flags = SHF_ALLOC + SHF_WRITE
+			sh.entsize = uint64(Thearch.Regsize)
+			sh.addralign = uint64(Thearch.Regsize)
+			shsym(sh, Linklookup(Ctxt, ".got", 0))
+
+			sh = elfshname(".got.plt")
+			sh.type_ = SHT_PROGBITS
+			sh.flags = SHF_ALLOC + SHF_WRITE
+			sh.entsize = uint64(Thearch.Regsize)
+			sh.addralign = uint64(Thearch.Regsize)
+			shsym(sh, Linklookup(Ctxt, ".got.plt", 0))
+		}
+
+		sh = elfshname(".hash")
+		sh.type_ = SHT_HASH
+		sh.flags = SHF_ALLOC
+		sh.entsize = 4
+		sh.addralign = uint64(Thearch.Regsize)
+		sh.link = uint32(elfshname(".dynsym").shnum)
+		shsym(sh, Linklookup(Ctxt, ".hash", 0))
+
+		/* sh and PT_DYNAMIC for .dynamic section */
+		sh = elfshname(".dynamic")
+
+		sh.type_ = SHT_DYNAMIC
+		sh.flags = SHF_ALLOC + SHF_WRITE
+		sh.entsize = 2 * uint64(Thearch.Regsize)
+		sh.addralign = uint64(Thearch.Regsize)
+		sh.link = uint32(elfshname(".dynstr").shnum)
+		shsym(sh, Linklookup(Ctxt, ".dynamic", 0))
+		ph := newElfPhdr()
+		ph.type_ = PT_DYNAMIC
+		ph.flags = PF_R + PF_W
+		phsh(ph, sh)
+
+		/*
+		 * Thread-local storage segment (really just size).
+		 */
+		// Do not emit PT_TLS for OpenBSD since ld.so(1) does
+		// not currently support it. This is handled
+		// appropriately in runtime/cgo.
+		if Ctxt.Tlsoffset != 0 && HEADTYPE != obj.Hopenbsd {
+			ph := newElfPhdr()
+			ph.type_ = PT_TLS
+			ph.flags = PF_R
+			ph.memsz = uint64(-Ctxt.Tlsoffset)
+			ph.align = uint64(Thearch.Regsize)
+		}
+	}
+
+	if HEADTYPE == obj.Hlinux {
+		ph := newElfPhdr()
+		ph.type_ = PT_GNU_STACK
+		ph.flags = PF_W + PF_R
+		ph.align = uint64(Thearch.Regsize)
+
+		ph = newElfPhdr()
+		ph.type_ = PT_PAX_FLAGS
+		ph.flags = 0x2a00 // mprotect, randexec, emutramp disabled
+		ph.align = uint64(Thearch.Regsize)
+	}
+
+elfobj:
+	sh := elfshname(".shstrtab")
+	sh.type_ = SHT_STRTAB
+	sh.addralign = 1
+	shsym(sh, Linklookup(Ctxt, ".shstrtab", 0))
+	eh.shstrndx = uint16(sh.shnum)
+
+	// put these sections early in the list
+	if Debug['s'] == 0 {
+		elfshname(".symtab")
+		elfshname(".strtab")
+	}
+
+	for sect := Segtext.Sect; sect != nil; sect = sect.Next {
+		elfshbits(sect)
+	}
+	for sect := Segrodata.Sect; sect != nil; sect = sect.Next {
+		elfshbits(sect)
+	}
+	for sect := Segdata.Sect; sect != nil; sect = sect.Next {
+		elfshbits(sect)
+	}
+
+	if Linkmode == LinkExternal {
+		for sect := Segtext.Sect; sect != nil; sect = sect.Next {
+			elfshreloc(sect)
+		}
+		for sect := Segrodata.Sect; sect != nil; sect = sect.Next {
+			elfshreloc(sect)
+		}
+		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.type_ = SHT_PROGBITS
+		sh.addralign = 1
+		sh.flags = 0
+	}
+
+	// generate .tbss section for dynamic internal linking (except for OpenBSD)
+	// external linking generates .tbss in data.c
+	if Linkmode == LinkInternal && Debug['d'] == 0 && HEADTYPE != obj.Hopenbsd {
+		sh := elfshname(".tbss")
+		sh.type_ = SHT_NOBITS
+		sh.addralign = uint64(Thearch.Regsize)
+		sh.size = uint64(-Ctxt.Tlsoffset)
+		sh.flags = SHF_ALLOC | SHF_TLS | SHF_WRITE
+	}
+
+	if Debug['s'] == 0 {
+		sh := elfshname(".symtab")
+		sh.type_ = SHT_SYMTAB
+		sh.off = uint64(symo)
+		sh.size = uint64(Symsize)
+		sh.addralign = uint64(Thearch.Regsize)
+		sh.entsize = 8 + 2*uint64(Thearch.Regsize)
+		sh.link = uint32(elfshname(".strtab").shnum)
+		sh.info = uint32(elfglobalsymndx)
+
+		sh = elfshname(".strtab")
+		sh.type_ = SHT_STRTAB
+		sh.off = uint64(symo) + uint64(Symsize)
+		sh.size = uint64(len(Elfstrdat))
+		sh.addralign = 1
+
+		dwarfaddelfheaders()
+	}
+
+	/* Main header */
+	eh.ident[EI_MAG0] = '\177'
+
+	eh.ident[EI_MAG1] = 'E'
+	eh.ident[EI_MAG2] = 'L'
+	eh.ident[EI_MAG3] = 'F'
+	if HEADTYPE == obj.Hfreebsd {
+		eh.ident[EI_OSABI] = ELFOSABI_FREEBSD
+	} else if HEADTYPE == obj.Hnetbsd {
+		eh.ident[EI_OSABI] = ELFOSABI_NETBSD
+	} else if HEADTYPE == obj.Hopenbsd {
+		eh.ident[EI_OSABI] = ELFOSABI_OPENBSD
+	} else if HEADTYPE == obj.Hdragonfly {
+		eh.ident[EI_OSABI] = ELFOSABI_NONE
+	}
+	if elf64 {
+		eh.ident[EI_CLASS] = ELFCLASS64
+	} else {
+		eh.ident[EI_CLASS] = ELFCLASS32
+	}
+	if Ctxt.Arch.ByteOrder == binary.BigEndian {
+		eh.ident[EI_DATA] = ELFDATA2MSB
+	} else {
+		eh.ident[EI_DATA] = ELFDATA2LSB
+	}
+	eh.ident[EI_VERSION] = EV_CURRENT
+
+	if Linkmode == LinkExternal {
+		eh.type_ = ET_REL
+	} else {
+		eh.type_ = ET_EXEC
+	}
+
+	if Linkmode != LinkExternal {
+		eh.entry = uint64(Entryvalue())
+	}
+
+	eh.version = EV_CURRENT
+
+	if pph != nil {
+		pph.filesz = uint64(eh.phnum) * uint64(eh.phentsize)
+		pph.memsz = pph.filesz
+	}
+
+	Cseek(0)
+	a := int64(0)
+	a += int64(elfwritehdr())
+	a += int64(elfwritephdrs())
+	a += int64(elfwriteshdrs())
+	if Debug['d'] == 0 {
+		a += int64(elfwriteinterp())
+	}
+	if Linkmode != LinkExternal {
+		if HEADTYPE == obj.Hnetbsd {
+			a += int64(elfwritenetbsdsig())
+		}
+		if HEADTYPE == obj.Hopenbsd {
+			a += int64(elfwriteopenbsdsig())
+		}
+		if len(buildinfo) > 0 {
+			a += int64(elfwritebuildinfo())
+		}
+		if buildid != "" {
+			a += int64(elfwritegobuildid())
+		}
+	}
+
+	if a > elfreserve {
+		Diag("ELFRESERVE too small: %d > %d", a, elfreserve)
+	}
+}
+
+func Elfadddynsym(ctxt *Link, s *LSym) {
+	if elf64 {
+		s.Dynid = int32(Nelfsym)
+		Nelfsym++
+
+		d := Linklookup(ctxt, ".dynsym", 0)
+
+		name := s.Extname
+		Adduint32(ctxt, d, uint32(Addstring(Linklookup(ctxt, ".dynstr", 0), name)))
+
+		/* type */
+		t := STB_GLOBAL << 4
+
+		if s.Cgoexport != 0 && s.Type&obj.SMASK == obj.STEXT {
+			t |= STT_FUNC
+		} else {
+			t |= STT_OBJECT
+		}
+		Adduint8(ctxt, d, uint8(t))
+
+		/* reserved */
+		Adduint8(ctxt, d, 0)
+
+		/* section where symbol is defined */
+		if s.Type == obj.SDYNIMPORT {
+			Adduint16(ctxt, d, SHN_UNDEF)
+		} else {
+			Adduint16(ctxt, d, 1)
+		}
+
+		/* value */
+		if s.Type == obj.SDYNIMPORT {
+			Adduint64(ctxt, d, 0)
+		} else {
+			Addaddr(ctxt, d, s)
+		}
+
+		/* size of object */
+		Adduint64(ctxt, d, uint64(s.Size))
+
+		if Thearch.Thechar == '6' && s.Cgoexport&CgoExportDynamic == 0 && s.Dynimplib != "" && !seenlib[s.Dynimplib] {
+			Elfwritedynent(Linklookup(ctxt, ".dynamic", 0), DT_NEEDED, uint64(Addstring(Linklookup(ctxt, ".dynstr", 0), s.Dynimplib)))
+		}
+	} else {
+		s.Dynid = int32(Nelfsym)
+		Nelfsym++
+
+		d := Linklookup(ctxt, ".dynsym", 0)
+
+		/* name */
+		name := s.Extname
+
+		Adduint32(ctxt, d, uint32(Addstring(Linklookup(ctxt, ".dynstr", 0), name)))
+
+		/* value */
+		if s.Type == obj.SDYNIMPORT {
+			Adduint32(ctxt, d, 0)
+		} else {
+			Addaddr(ctxt, d, s)
+		}
+
+		/* size */
+		Adduint32(ctxt, d, 0)
+
+		/* type */
+		t := STB_GLOBAL << 4
+
+		// TODO(mwhudson): presumably the behaviour should actually be the same on both arm and 386.
+		if Thearch.Thechar == '8' && s.Cgoexport != 0 && s.Type&obj.SMASK == obj.STEXT {
+			t |= STT_FUNC
+		} else if Thearch.Thechar == '5' && s.Cgoexport&CgoExportDynamic != 0 && s.Type&obj.SMASK == obj.STEXT {
+			t |= STT_FUNC
+		} else {
+			t |= STT_OBJECT
+		}
+		Adduint8(ctxt, d, uint8(t))
+		Adduint8(ctxt, d, 0)
+
+		/* shndx */
+		if s.Type == obj.SDYNIMPORT {
+			Adduint16(ctxt, d, SHN_UNDEF)
+		} else {
+			Adduint16(ctxt, d, 1)
+		}
+	}
+}
+
+func ELF32_R_SYM(info uint32) uint32 {
+	return info >> 8
+}
+
+func ELF32_R_TYPE(info uint32) uint32 {
+	return uint32(uint8(info))
+}
+
+func ELF32_R_INFO(sym uint32, type_ uint32) uint32 {
+	return sym<<8 | type_
+}
+
+func ELF32_ST_BIND(info uint8) uint8 {
+	return info >> 4
+}
+
+func ELF32_ST_TYPE(info uint8) uint8 {
+	return info & 0xf
+}
+
+func ELF32_ST_INFO(bind uint8, type_ uint8) uint8 {
+	return bind<<4 | type_&0xf
+}
+
+func ELF32_ST_VISIBILITY(oth uint8) uint8 {
+	return oth & 3
+}
+
+func ELF64_R_SYM(info uint64) uint32 {
+	return uint32(info >> 32)
+}
+
+func ELF64_R_TYPE(info uint64) uint32 {
+	return uint32(info)
+}
+
+func ELF64_R_INFO(sym uint32, type_ uint32) uint64 {
+	return uint64(sym)<<32 | uint64(type_)
+}
+
+func ELF64_ST_BIND(info uint8) uint8 {
+	return info >> 4
+}
+
+func ELF64_ST_TYPE(info uint8) uint8 {
+	return info & 0xf
+}
+
+func ELF64_ST_INFO(bind uint8, type_ uint8) uint8 {
+	return bind<<4 | type_&0xf
+}
+
+func ELF64_ST_VISIBILITY(oth uint8) uint8 {
+	return oth & 3
+}
diff --git a/src/cmd/link/internal/ld/go.go b/src/cmd/link/internal/ld/go.go
new file mode 100644
index 0000000..80a6c6e
--- /dev/null
+++ b/src/cmd/link/internal/ld/go.go
@@ -0,0 +1,869 @@
+// 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.
+
+// go-specific code shared across loaders (5l, 6l, 8l).
+
+package ld
+
+import (
+	"bytes"
+	"cmd/internal/obj"
+	"fmt"
+	"os"
+	"strconv"
+	"strings"
+)
+
+// go-specific code shared across loaders (5l, 6l, 8l).
+
+// replace all "". with pkg.
+func expandpkg(t0 string, pkg string) string {
+	return strings.Replace(t0, `"".`, pkg+".", -1)
+}
+
+// accumulate all type information from .6 files.
+// check for inconsistencies.
+
+// TODO:
+//	generate debugging section in binary.
+//	once the dust settles, try to move some code to
+//		libmach, so that other linkers and ar can share.
+
+/*
+ *	package import data
+ */
+type Import struct {
+	prefix string // "type", "var", "func", "const"
+	name   string
+	def    string
+	file   string
+}
+
+// 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{}
+
+func lookupImport(name string) *Import {
+	if x, ok := importmap[name]; ok {
+		return x
+	}
+	x := &Import{name: name}
+	importmap[name] = x
+	return x
+}
+
+func ldpkg(f *obj.Biobuf, pkg string, length int64, filename string, whence int) {
+	var p0, p1 int
+
+	if Debug['g'] != 0 {
+		return
+	}
+
+	if int64(int(length)) != length {
+		fmt.Fprintf(os.Stderr, "%s: too much pkg data in %s\n", os.Args[0], filename)
+		if Debug['u'] != 0 {
+			errorexit()
+		}
+		return
+	}
+
+	bdata := make([]byte, length)
+	if int64(obj.Bread(f, bdata)) != length {
+		fmt.Fprintf(os.Stderr, "%s: short pkg read %s\n", os.Args[0], filename)
+		if Debug['u'] != 0 {
+			errorexit()
+		}
+		return
+	}
+	data := string(bdata)
+
+	// first \n$$ marks beginning of exports - skip rest of line
+	p0 = strings.Index(data, "\n$$")
+	if p0 < 0 {
+		if Debug['u'] != 0 && whence != ArchiveObj {
+			Exitf("cannot find export data in %s", filename)
+		}
+		return
+	}
+
+	p0 += 3
+	for p0 < len(data) && data[p0] != '\n' {
+		p0++
+	}
+
+	// second marks end of exports / beginning of local data
+	p1 = strings.Index(data[p0:], "\n$$")
+	if p1 < 0 {
+		fmt.Fprintf(os.Stderr, "%s: cannot find end of exports in %s\n", os.Args[0], filename)
+		if Debug['u'] != 0 {
+			errorexit()
+		}
+		return
+	}
+	p1 += p0
+
+	for p0 < p1 && (data[p0] == ' ' || data[p0] == '\t' || data[p0] == '\n') {
+		p0++
+	}
+	if p0 < p1 {
+		if !strings.HasPrefix(data[p0:], "package ") {
+			fmt.Fprintf(os.Stderr, "%s: bad package section in %s - %.20s\n", os.Args[0], filename, data[p0:])
+			if Debug['u'] != 0 {
+				errorexit()
+			}
+			return
+		}
+
+		p0 += 8
+		for p0 < p1 && (data[p0] == ' ' || data[p0] == '\t' || data[p0] == '\n') {
+			p0++
+		}
+		pname := p0
+		for p0 < p1 && data[p0] != ' ' && data[p0] != '\t' && data[p0] != '\n' {
+			p0++
+		}
+		if Debug['u'] != 0 && whence != ArchiveObj && (p0+6 > p1 || !strings.HasPrefix(data[p0:], " safe\n")) {
+			Exitf("load of unsafe package %s", filename)
+		}
+
+		name := data[pname:p0]
+		for p0 < p1 && data[p0] != '\n' {
+			p0++
+		}
+		if p0 < p1 {
+			p0++
+		}
+
+		if pkg == "main" && name != "main" {
+			Exitf("%s: not package main (package %s)", filename, name)
+		}
+
+		loadpkgdata(filename, pkg, data[p0:p1])
+	}
+
+	// __.PKGDEF has no cgo section - those are in the C compiler-generated object files.
+	if whence == Pkgdef {
+		return
+	}
+
+	// look for cgo section
+	p0 = strings.Index(data[p1:], "\n$$  // cgo")
+	if p0 >= 0 {
+		p0 += p1
+		i := strings.IndexByte(data[p0+1:], '\n')
+		if i < 0 {
+			fmt.Fprintf(os.Stderr, "%s: found $$ // cgo but no newline in %s\n", os.Args[0], filename)
+			if Debug['u'] != 0 {
+				errorexit()
+			}
+			return
+		}
+		p0 += 1 + i
+
+		p1 = strings.Index(data[p0:], "\n$$")
+		if p1 < 0 {
+			p1 = strings.Index(data[p0:], "\n!\n")
+		}
+		if p1 < 0 {
+			fmt.Fprintf(os.Stderr, "%s: cannot find end of // cgo section in %s\n", os.Args[0], filename)
+			if Debug['u'] != 0 {
+				errorexit()
+			}
+			return
+		}
+		p1 += p0
+
+		loadcgo(filename, pkg, data[p0:p1])
+	}
+}
+
+func loadpkgdata(file string, pkg string, data string) {
+	var prefix string
+	var name string
+	var def string
+
+	p := data
+	for parsepkgdata(file, pkg, &p, &prefix, &name, &def) > 0 {
+		x := lookupImport(name)
+		if x.prefix == "" {
+			x.prefix = prefix
+			x.def = def
+			x.file = file
+		} else if x.prefix != prefix {
+			fmt.Fprintf(os.Stderr, "%s: conflicting definitions for %s\n", os.Args[0], name)
+			fmt.Fprintf(os.Stderr, "%s:\t%s %s ...\n", x.file, x.prefix, name)
+			fmt.Fprintf(os.Stderr, "%s:\t%s %s ...\n", file, prefix, name)
+			nerrors++
+		} else if x.def != def {
+			fmt.Fprintf(os.Stderr, "%s: conflicting definitions for %s\n", os.Args[0], name)
+			fmt.Fprintf(os.Stderr, "%s:\t%s %s %s\n", x.file, x.prefix, name, x.def)
+			fmt.Fprintf(os.Stderr, "%s:\t%s %s %s\n", file, prefix, name, def)
+			nerrors++
+		}
+	}
+}
+
+func parsepkgdata(file string, pkg string, pp *string, prefixp *string, namep *string, defp *string) int {
+	// skip white space
+	p := *pp
+
+loop:
+	for len(p) > 0 && (p[0] == ' ' || p[0] == '\t' || p[0] == '\n') {
+		p = p[1:]
+	}
+	if len(p) == 0 || strings.HasPrefix(p, "$$\n") {
+		return 0
+	}
+
+	// prefix: (var|type|func|const)
+	prefix := p
+
+	if len(p) < 7 {
+		return -1
+	}
+	if strings.HasPrefix(p, "var ") {
+		p = p[4:]
+	} else if strings.HasPrefix(p, "type ") {
+		p = p[5:]
+	} else if strings.HasPrefix(p, "func ") {
+		p = p[5:]
+	} else if strings.HasPrefix(p, "const ") {
+		p = p[6:]
+	} else if strings.HasPrefix(p, "import ") {
+		p = p[7:]
+		for len(p) > 0 && p[0] != ' ' {
+			p = p[1:]
+		}
+		p = p[1:]
+		line := p
+		for len(p) > 0 && p[0] != '\n' {
+			p = p[1:]
+		}
+		if len(p) == 0 {
+			fmt.Fprintf(os.Stderr, "%s: %s: confused in import line\n", os.Args[0], file)
+			nerrors++
+			return -1
+		}
+		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, path)
+		goto loop
+	} else {
+		fmt.Fprintf(os.Stderr, "%s: %s: confused in pkg data near <<%.40s>>\n", os.Args[0], file, prefix)
+		nerrors++
+		return -1
+	}
+
+	prefix = prefix[:len(prefix)-len(p)-1]
+
+	// name: a.b followed by space
+	name := p
+
+	inquote := false
+	for len(p) > 0 {
+		if p[0] == ' ' && !inquote {
+			break
+		}
+
+		if p[0] == '\\' {
+			p = p[1:]
+		} else if p[0] == '"' {
+			inquote = !inquote
+		}
+
+		p = p[1:]
+	}
+
+	if len(p) == 0 {
+		return -1
+	}
+	name = name[:len(name)-len(p)]
+	p = p[1:]
+
+	// def: free form to new line
+	def := p
+
+	for len(p) > 0 && p[0] != '\n' {
+		p = p[1:]
+	}
+	if len(p) == 0 {
+		return -1
+	}
+	def = def[:len(def)-len(p)]
+	var defbuf *bytes.Buffer
+	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)
+			defbuf.WriteString(def)
+		}
+		defbuf.WriteString("\n\t")
+		defbuf.WriteString(meth)
+	}
+	if defbuf != nil {
+		def = defbuf.String()
+	}
+
+	name = expandpkg(name, pkg)
+	def = expandpkg(def, pkg)
+
+	// done
+	*pp = p
+
+	*prefixp = prefix
+	*namep = name
+	*defp = def
+	return 1
+}
+
+func parsemethod(pp *string, methp *string) int {
+	// skip white space
+	p := *pp
+
+	for len(p) > 0 && (p[0] == ' ' || p[0] == '\t') {
+		p = p[1:]
+	}
+	if len(p) == 0 {
+		return 0
+	}
+
+	// might be a comment about the method
+	if strings.HasPrefix(p, "//") {
+		goto useline
+	}
+
+	// if it says "func (", it's a method
+	if strings.HasPrefix(p, "func (") {
+		goto useline
+	}
+	return 0
+
+	// definition to end of line
+useline:
+	*methp = p
+
+	for len(p) > 0 && p[0] != '\n' {
+		p = p[1:]
+	}
+	if len(p) == 0 {
+		fmt.Fprintf(os.Stderr, "%s: lost end of line in method definition\n", os.Args[0])
+		*pp = ""
+		return -1
+	}
+
+	*methp = (*methp)[:len(*methp)-len(p)]
+	*pp = p[1:]
+	return 1
+}
+
+func loadcgo(file string, pkg string, p string) {
+	var next string
+	var q string
+	var f []string
+	var local string
+	var remote string
+	var lib string
+	var s *LSym
+
+	p0 := ""
+	for ; p != ""; p = next {
+		if i := strings.Index(p, "\n"); i >= 0 {
+			p, next = p[:i], p[i+1:]
+		} else {
+			next = ""
+		}
+
+		p0 = p // save for error message
+		f = tokenize(p)
+		if len(f) == 0 {
+			continue
+		}
+
+		if f[0] == "cgo_import_dynamic" {
+			if len(f) < 2 || len(f) > 4 {
+				goto err
+			}
+
+			local = f[1]
+			remote = local
+			if len(f) > 2 {
+				remote = f[2]
+			}
+			lib = ""
+			if len(f) > 3 {
+				lib = f[3]
+			}
+
+			if Debug['d'] != 0 {
+				fmt.Fprintf(os.Stderr, "%s: %s: cannot use dynamic imports with -d flag\n", os.Args[0], file)
+				nerrors++
+				return
+			}
+
+			if local == "_" && remote == "_" {
+				// allow #pragma dynimport _ _ "foo.so"
+				// to force a link of foo.so.
+				havedynamic = 1
+
+				if HEADTYPE == obj.Hdarwin {
+					Machoadddynlib(lib)
+				} else {
+					dynlib = append(dynlib, lib)
+				}
+				continue
+			}
+
+			local = expandpkg(local, pkg)
+			q = ""
+			if i := strings.Index(remote, "#"); i >= 0 {
+				remote, q = remote[:i], remote[i+1:]
+			}
+			s = Linklookup(Ctxt, local, 0)
+			if local != f[1] {
+			}
+			if s.Type == 0 || s.Type == obj.SXREF || s.Type == obj.SHOSTOBJ {
+				s.Dynimplib = lib
+				s.Extname = remote
+				s.Dynimpvers = q
+				if s.Type != obj.SHOSTOBJ {
+					s.Type = obj.SDYNIMPORT
+				}
+				havedynamic = 1
+			}
+
+			continue
+		}
+
+		if f[0] == "cgo_import_static" {
+			if len(f) != 2 {
+				goto err
+			}
+			local = f[1]
+			s = Linklookup(Ctxt, local, 0)
+			s.Type = obj.SHOSTOBJ
+			s.Size = 0
+			continue
+		}
+
+		if f[0] == "cgo_export_static" || f[0] == "cgo_export_dynamic" {
+			if len(f) < 2 || len(f) > 3 {
+				goto err
+			}
+			local = f[1]
+			if len(f) > 2 {
+				remote = f[2]
+			} else {
+				remote = local
+			}
+			local = expandpkg(local, pkg)
+			s = Linklookup(Ctxt, local, 0)
+
+			switch Buildmode {
+			case BuildmodeCShared, BuildmodeCArchive:
+				if s == Linklookup(Ctxt, "main", 0) {
+					continue
+				}
+			}
+
+			// export overrides import, for openbsd/cgo.
+			// see issue 4878.
+			if s.Dynimplib != "" {
+				s.Dynimplib = ""
+				s.Extname = ""
+				s.Dynimpvers = ""
+				s.Type = 0
+			}
+
+			if s.Cgoexport == 0 {
+				s.Extname = remote
+				dynexp = append(dynexp, s)
+			} else if s.Extname != remote {
+				fmt.Fprintf(os.Stderr, "%s: conflicting cgo_export directives: %s as %s and %s\n", os.Args[0], s.Name, s.Extname, remote)
+				nerrors++
+				return
+			}
+
+			if f[0] == "cgo_export_static" {
+				s.Cgoexport |= CgoExportStatic
+			} else {
+				s.Cgoexport |= CgoExportDynamic
+			}
+			if local != f[1] {
+			}
+			continue
+		}
+
+		if f[0] == "cgo_dynamic_linker" {
+			if len(f) != 2 {
+				goto err
+			}
+
+			if Debug['I'] == 0 {
+				if interpreter != "" && interpreter != f[1] {
+					fmt.Fprintf(os.Stderr, "%s: conflict dynlinker: %s and %s\n", os.Args[0], interpreter, f[1])
+					nerrors++
+					return
+				}
+
+				interpreter = f[1]
+			}
+
+			continue
+		}
+
+		if f[0] == "cgo_ldflag" {
+			if len(f) != 2 {
+				goto err
+			}
+			ldflag = append(ldflag, f[1])
+			continue
+		}
+	}
+
+	return
+
+err:
+	fmt.Fprintf(os.Stderr, "%s: %s: invalid dynimport line: %s\n", os.Args[0], file, p0)
+	nerrors++
+}
+
+var seenlib = make(map[string]bool)
+
+func adddynlib(lib string) {
+	if seenlib[lib] || Linkmode == LinkExternal {
+		return
+	}
+	seenlib[lib] = true
+
+	if Iself {
+		s := Linklookup(Ctxt, ".dynstr", 0)
+		if s.Size == 0 {
+			Addstring(s, "")
+		}
+		Elfwritedynent(Linklookup(Ctxt, ".dynamic", 0), DT_NEEDED, uint64(Addstring(s, lib)))
+	} else {
+		Diag("adddynlib: unsupported binary format")
+	}
+}
+
+func Adddynsym(ctxt *Link, s *LSym) {
+	if s.Dynid >= 0 || Linkmode == LinkExternal {
+		return
+	}
+
+	if Iself {
+		Elfadddynsym(ctxt, s)
+	} else if HEADTYPE == obj.Hdarwin {
+		Diag("adddynsym: missed symbol %s (%s)", s.Name, s.Extname)
+	} else if HEADTYPE == obj.Hwindows {
+		// already taken care of
+	} else {
+		Diag("adddynsym: unsupported binary format")
+	}
+}
+
+var markq *LSym
+
+var emarkq *LSym
+
+func mark1(s *LSym, parent *LSym) {
+	if s == nil || s.Reachable {
+		return
+	}
+	if strings.HasPrefix(s.Name, "go.weak.") {
+		return
+	}
+	s.Reachable = true
+	s.Reachparent = parent
+	if markq == nil {
+		markq = s
+	} else {
+		emarkq.Queue = s
+	}
+	emarkq = s
+}
+
+func mark(s *LSym) {
+	mark1(s, nil)
+}
+
+func markflood() {
+	var a *Auto
+	var i int
+
+	for s := markq; s != nil; s = s.Queue {
+		if s.Type == obj.STEXT {
+			if Debug['v'] > 1 {
+				fmt.Fprintf(&Bso, "marktext %s\n", s.Name)
+			}
+			for a = s.Autom; a != nil; a = a.Link {
+				mark1(a.Gotype, s)
+			}
+		}
+
+		for i = 0; i < len(s.R); i++ {
+			mark1(s.R[i].Sym, s)
+		}
+		if s.Pcln != nil {
+			for i = 0; i < s.Pcln.Nfuncdata; i++ {
+				mark1(s.Pcln.Funcdata[i], s)
+			}
+		}
+
+		mark1(s.Gotype, s)
+		mark1(s.Sub, s)
+		mark1(s.Outer, s)
+	}
+}
+
+var markextra = []string{
+	"runtime.morestack",
+	"runtime.morestackx",
+	"runtime.morestack00",
+	"runtime.morestack10",
+	"runtime.morestack01",
+	"runtime.morestack11",
+	"runtime.morestack8",
+	"runtime.morestack16",
+	"runtime.morestack24",
+	"runtime.morestack32",
+	"runtime.morestack40",
+	"runtime.morestack48",
+	// on arm, lock in the div/mod helpers too
+	"_div",
+	"_divu",
+	"_mod",
+	"_modu",
+}
+
+func deadcode() {
+	if Debug['v'] != 0 {
+		fmt.Fprintf(&Bso, "%5.2f deadcode\n", obj.Cputime())
+	}
+
+	if Buildmode == BuildmodeShared {
+		// Mark all symbols defined in this library as reachable when
+		// building a shared library.
+		for s := Ctxt.Allsym; s != nil; s = s.Allsym {
+			if s.Type != 0 && s.Type != obj.SDYNIMPORT {
+				mark(s)
+			}
+		}
+		markflood()
+	} else {
+		mark(Linklookup(Ctxt, INITENTRY, 0))
+		if Linkshared && Buildmode == BuildmodeExe {
+			mark(Linkrlookup(Ctxt, "main.main", 0))
+			mark(Linkrlookup(Ctxt, "main.init", 0))
+		}
+		for i := 0; i < len(markextra); i++ {
+			mark(Linklookup(Ctxt, markextra[i], 0))
+		}
+
+		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 {
+			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).
+		var last *LSym
+
+		for s := Ctxt.Textp; s != nil; s = s.Next {
+			if !s.Reachable {
+				continue
+			}
+
+			// NOTE: Removing s from old textp and adding to new, shorter textp.
+			if last == nil {
+				Ctxt.Textp = s
+			} else {
+				last.Next = s
+			}
+			last = s
+		}
+
+		if last == nil {
+			Ctxt.Textp = nil
+			Ctxt.Etextp = nil
+		} else {
+			last.Next = nil
+			Ctxt.Etextp = last
+		}
+	}
+
+	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
+			s.Hide = 1
+		}
+	}
+
+	// record field tracking references
+	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 {
+				buf.WriteString(s.Name[9:])
+				for p = s.Reachparent; p != nil; p = p.Reachparent {
+					buf.WriteString("\t")
+					buf.WriteString(p.Name)
+				}
+				buf.WriteString("\n")
+			}
+
+			s.Type = obj.SCONST
+			s.Value = 0
+		}
+	}
+
+	if tracksym == "" {
+		return
+	}
+	s := Linklookup(Ctxt, tracksym, 0)
+	if !s.Reachable {
+		return
+	}
+	addstrdata(tracksym, buf.String())
+}
+
+func doweak() {
+	var t *LSym
+
+	// resolve weak references only if
+	// target symbol will be in binary anyway.
+	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 {
+				s.Value = t.Value
+				s.Type = t.Type
+				s.Outer = t
+			} else {
+				s.Type = obj.SCONST
+				s.Value = 0
+			}
+
+			continue
+		}
+	}
+}
+
+func addexport() {
+	if HEADTYPE == obj.Hdarwin {
+		return
+	}
+
+	for _, exp := range dynexp {
+		Adddynsym(Ctxt, exp)
+	}
+	for _, lib := range dynlib {
+		adddynlib(lib)
+	}
+}
+
+type Pkg struct {
+	mark    bool
+	checked bool
+	path    string
+	impby   []*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{}
+
+	pkgall []*Pkg
+)
+
+func lookupPkg(path string) *Pkg {
+	if p, ok := pkgmap[path]; ok {
+		return p
+	}
+	p := &Pkg{path: path}
+	pkgmap[path] = p
+	pkgall = append(pkgall, p)
+	return p
+}
+
+// imported records that package pkg imports package imp.
+func imported(pkg, imp string) {
+	// everyone imports runtime, even runtime.
+	if imp == "runtime" {
+		return
+	}
+
+	p := lookupPkg(pkg)
+	i := lookupPkg(imp)
+	i.impby = append(i.impby, p)
+}
+
+func (p *Pkg) cycle() *Pkg {
+	if p.checked {
+		return nil
+	}
+
+	if p.mark {
+		nerrors++
+		fmt.Printf("import cycle:\n")
+		fmt.Printf("\t%s\n", p.path)
+		return p
+	}
+
+	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
+			}
+			return bad
+		}
+	}
+
+	p.checked = true
+	p.mark = false
+	return nil
+}
+
+func importcycles() {
+	for _, p := range pkgall {
+		p.cycle()
+	}
+}
+
+func setlinkmode(arg string) {
+	if arg == "internal" {
+		Linkmode = LinkInternal
+	} else if arg == "external" {
+		Linkmode = LinkExternal
+	} else if arg == "auto" {
+		Linkmode = LinkAuto
+	} else {
+		Exitf("unknown link mode -linkmode %s", arg)
+	}
+}
diff --git a/src/cmd/link/internal/ld/ld.go b/src/cmd/link/internal/ld/ld.go
new file mode 100644
index 0000000..1068bdd
--- /dev/null
+++ b/src/cmd/link/internal/ld/ld.go
@@ -0,0 +1,130 @@
+// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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 ld
+
+import (
+	"cmd/internal/obj"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"path"
+	"strconv"
+	"strings"
+)
+
+func addlib(ctxt *Link, src string, obj string, pathname string) {
+	name := path.Clean(pathname)
+
+	// runtime.a -> runtime, runtime.6 -> runtime
+	pkg := name
+	if len(pkg) >= 2 && pkg[len(pkg)-2] == '.' {
+		pkg = pkg[:len(pkg)-2]
+	}
+
+	// already loaded?
+	for i := 0; i < len(ctxt.Library); i++ {
+		if ctxt.Library[i].Pkg == pkg {
+			return
+		}
+	}
+
+	var pname string
+	isshlib := false
+	if (ctxt.Windows == 0 && strings.HasPrefix(name, "/")) || (ctxt.Windows != 0 && len(name) >= 2 && name[1] == ':') {
+		pname = name
+	} else {
+		// try dot, -L "libdir", and then goroot.
+		for _, dir := range ctxt.Libdir {
+			if Linkshared {
+				pname = dir + "/" + pkg + ".shlibname"
+				if _, err := os.Stat(pname); err == nil {
+					isshlib = true
+					break
+				}
+			}
+			pname = dir + "/" + name
+			if _, err := os.Stat(pname); err == nil {
+				break
+			}
+		}
+	}
+
+	pname = path.Clean(pname)
+
+	if ctxt.Debugvlog > 1 && ctxt.Bso != nil {
+		fmt.Fprintf(ctxt.Bso, "%5.2f addlib: %s %s pulls in %s isshlib %v\n", elapsed(), obj, src, pname, isshlib)
+	}
+
+	if isshlib {
+		addlibpath(ctxt, src, obj, "", pkg, pname)
+	} else {
+		addlibpath(ctxt, src, obj, pname, pkg, "")
+	}
+}
+
+/*
+ * add library to library list.
+ *	srcref: src file referring to package
+ *	objref: object file referring to package
+ *	file: object file, e.g., /home/rsc/go/pkg/container/vector.a
+ *	pkg: package import path, e.g. container/vector
+ */
+func addlibpath(ctxt *Link, srcref string, objref string, file string, pkg string, shlibnamefile string) {
+	for i := 0; i < len(ctxt.Library); i++ {
+		if pkg == ctxt.Library[i].Pkg {
+			return
+		}
+	}
+
+	if ctxt.Debugvlog > 1 && ctxt.Bso != nil {
+		fmt.Fprintf(ctxt.Bso, "%5.2f addlibpath: srcref: %s objref: %s file: %s pkg: %s shlibnamefile: %s\n", obj.Cputime(), srcref, objref, file, pkg, shlibnamefile)
+	}
+
+	ctxt.Library = append(ctxt.Library, &Library{})
+	l := ctxt.Library[len(ctxt.Library)-1]
+	l.Objref = objref
+	l.Srcref = srcref
+	l.File = file
+	l.Pkg = pkg
+	if shlibnamefile != "" {
+		shlibbytes, err := ioutil.ReadFile(shlibnamefile)
+		if err != nil {
+			Diag("cannot read %s: %v", shlibnamefile, err)
+		}
+		l.Shlib = strings.TrimSpace(string(shlibbytes))
+	}
+}
+
+func atolwhex(s string) int64 {
+	n, _ := strconv.ParseInt(s, 0, 64)
+	return n
+}
diff --git a/src/cmd/link/internal/ld/ldelf.go b/src/cmd/link/internal/ld/ldelf.go
new file mode 100644
index 0000000..3efdb75
--- /dev/null
+++ b/src/cmd/link/internal/ld/ldelf.go
@@ -0,0 +1,1019 @@
+package ld
+
+import (
+	"bytes"
+	"cmd/internal/obj"
+	"encoding/binary"
+	"fmt"
+	"log"
+	"sort"
+	"strings"
+)
+
+/*
+Derived from Plan 9 from User Space's src/libmach/elf.h, elf.c
+http://code.swtch.com/plan9port/src/tip/src/libmach/
+
+	Copyright © 2004 Russ Cox.
+	Portions Copyright © 2008-2010 Google Inc.
+	Portions Copyright © 2010 The Go Authors.
+
+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 (
+	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
+)
+
+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
+)
+
+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
+)
+
+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
+	ElfNotePrTaskstruct = 4
+	ElfNotePrAuxv       = 6
+	ElfNotePrXfpreg     = 0x46e62b7f
+)
+
+type ElfHdrBytes struct {
+	Ident     [16]uint8
+	Type      [2]uint8
+	Machine   [2]uint8
+	Version   [4]uint8
+	Entry     [4]uint8
+	Phoff     [4]uint8
+	Shoff     [4]uint8
+	Flags     [4]uint8
+	Ehsize    [2]uint8
+	Phentsize [2]uint8
+	Phnum     [2]uint8
+	Shentsize [2]uint8
+	Shnum     [2]uint8
+	Shstrndx  [2]uint8
+}
+
+type ElfSectBytes struct {
+	Name    [4]uint8
+	Type    [4]uint8
+	Flags   [4]uint8
+	Addr    [4]uint8
+	Off     [4]uint8
+	Size    [4]uint8
+	Link    [4]uint8
+	Info    [4]uint8
+	Align   [4]uint8
+	Entsize [4]uint8
+}
+
+type ElfProgBytes struct {
+}
+
+type ElfSymBytes struct {
+	Name  [4]uint8
+	Value [4]uint8
+	Size  [4]uint8
+	Info  uint8
+	Other uint8
+	Shndx [2]uint8
+}
+
+type ElfHdrBytes64 struct {
+	Ident     [16]uint8
+	Type      [2]uint8
+	Machine   [2]uint8
+	Version   [4]uint8
+	Entry     [8]uint8
+	Phoff     [8]uint8
+	Shoff     [8]uint8
+	Flags     [4]uint8
+	Ehsize    [2]uint8
+	Phentsize [2]uint8
+	Phnum     [2]uint8
+	Shentsize [2]uint8
+	Shnum     [2]uint8
+	Shstrndx  [2]uint8
+}
+
+type ElfSectBytes64 struct {
+	Name    [4]uint8
+	Type    [4]uint8
+	Flags   [8]uint8
+	Addr    [8]uint8
+	Off     [8]uint8
+	Size    [8]uint8
+	Link    [4]uint8
+	Info    [4]uint8
+	Align   [8]uint8
+	Entsize [8]uint8
+}
+
+type ElfProgBytes64 struct {
+}
+
+type ElfSymBytes64 struct {
+	Name  [4]uint8
+	Info  uint8
+	Other uint8
+	Shndx [2]uint8
+	Value [8]uint8
+	Size  [8]uint8
+}
+
+type ElfSect struct {
+	name    string
+	nameoff uint32
+	type_   uint32
+	flags   uint64
+	addr    uint64
+	off     uint64
+	size    uint64
+	link    uint32
+	info    uint32
+	align   uint64
+	entsize uint64
+	base    []byte
+	sym     *LSym
+}
+
+type ElfObj struct {
+	f         *obj.Biobuf
+	base      int64 // offset in f where ELF begins
+	length    int64 // length of ELF
+	is64      int
+	name      string
+	e         binary.ByteOrder
+	sect      []ElfSect
+	nsect     uint
+	shstrtab  string
+	nsymtab   int
+	symtab    *ElfSect
+	symstr    *ElfSect
+	type_     uint32
+	machine   uint32
+	version   uint32
+	entry     uint64
+	phoff     uint64
+	shoff     uint64
+	flags     uint32
+	ehsize    uint32
+	phentsize uint32
+	phnum     uint32
+	shentsize uint32
+	shnum     uint32
+	shstrndx  uint32
+}
+
+type ElfSym struct {
+	name  string
+	value uint64
+	size  uint64
+	bind  uint8
+	type_ uint8
+	other uint8
+	shndx uint16
+	sym   *LSym
+}
+
+var ElfMagic = [4]uint8{0x7F, 'E', 'L', 'F'}
+
+func valuecmp(a *LSym, b *LSym) int {
+	if a.Value < b.Value {
+		return -1
+	}
+	if a.Value > b.Value {
+		return +1
+	}
+	return 0
+}
+
+func ldelf(f *obj.Biobuf, pkg string, length int64, pn string) {
+	if Debug['v'] != 0 {
+		fmt.Fprintf(&Bso, "%5.2f ldelf %s\n", obj.Cputime(), pn)
+	}
+
+	Ctxt.Version++
+	base := int32(obj.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 obj.Bread(f, hdrbuf[:]) != len(hdrbuf) {
+		goto bad
+	}
+	hdr = new(ElfHdrBytes)
+	binary.Read(bytes.NewReader(hdrbuf[:]), binary.BigEndian, hdr) // only byte arrays; byte order doesn't matter
+	if string(hdr.Ident[:4]) != "\x7FELF" {
+		goto bad
+	}
+	switch hdr.Ident[5] {
+	case ElfDataLsb:
+		e = binary.LittleEndian
+
+	case ElfDataMsb:
+		e = binary.BigEndian
+
+	default:
+		goto bad
+	}
+
+	// read header
+	elfobj = new(ElfObj)
+
+	elfobj.e = e
+	elfobj.f = f
+	elfobj.base = int64(base)
+	elfobj.length = length
+	elfobj.name = pn
+
+	is64 = 0
+	if hdr.Ident[4] == ElfClass64 {
+		is64 = 1
+		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[:]))
+		elfobj.version = e.Uint32(hdr.Version[:])
+		elfobj.phoff = e.Uint64(hdr.Phoff[:])
+		elfobj.shoff = e.Uint64(hdr.Shoff[:])
+		elfobj.flags = e.Uint32(hdr.Flags[:])
+		elfobj.ehsize = uint32(e.Uint16(hdr.Ehsize[:]))
+		elfobj.phentsize = uint32(e.Uint16(hdr.Phentsize[:]))
+		elfobj.phnum = uint32(e.Uint16(hdr.Phnum[:]))
+		elfobj.shentsize = uint32(e.Uint16(hdr.Shentsize[:]))
+		elfobj.shnum = uint32(e.Uint16(hdr.Shnum[:]))
+		elfobj.shstrndx = uint32(e.Uint16(hdr.Shstrndx[:]))
+	} else {
+		elfobj.type_ = uint32(e.Uint16(hdr.Type[:]))
+		elfobj.machine = uint32(e.Uint16(hdr.Machine[:]))
+		elfobj.version = e.Uint32(hdr.Version[:])
+		elfobj.entry = uint64(e.Uint32(hdr.Entry[:]))
+		elfobj.phoff = uint64(e.Uint32(hdr.Phoff[:]))
+		elfobj.shoff = uint64(e.Uint32(hdr.Shoff[:]))
+		elfobj.flags = e.Uint32(hdr.Flags[:])
+		elfobj.ehsize = uint32(e.Uint16(hdr.Ehsize[:]))
+		elfobj.phentsize = uint32(e.Uint16(hdr.Phentsize[:]))
+		elfobj.phnum = uint32(e.Uint16(hdr.Phnum[:]))
+		elfobj.shentsize = uint32(e.Uint16(hdr.Shentsize[:]))
+		elfobj.shnum = uint32(e.Uint16(hdr.Shnum[:]))
+		elfobj.shstrndx = uint32(e.Uint16(hdr.Shstrndx[:]))
+	}
+
+	elfobj.is64 = is64
+
+	if uint32(hdr.Ident[6]) != elfobj.version {
+		goto bad
+	}
+
+	if e.Uint16(hdr.Type[:]) != ElfTypeRelocatable {
+		Diag("%s: elf but not elf relocatable object", pn)
+		return
+	}
+
+	switch Thearch.Thechar {
+	default:
+		Diag("%s: elf %s unimplemented", pn, Thestring)
+		return
+
+	case '5':
+		if e != binary.LittleEndian || elfobj.machine != ElfMachArm || hdr.Ident[4] != ElfClass32 {
+			Diag("%s: elf object but not arm", pn)
+			return
+		}
+
+	case '6':
+		if e != binary.LittleEndian || elfobj.machine != ElfMachAmd64 || hdr.Ident[4] != ElfClass64 {
+			Diag("%s: elf object but not amd64", pn)
+			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)
+			return
+		}
+
+	case '9':
+		if elfobj.machine != ElfMachPower64 || hdr.Ident[4] != ElfClass64 {
+			Diag("%s: elf object but not ppc64", pn)
+			return
+		}
+	}
+
+	// load section list into memory.
+	elfobj.sect = make([]ElfSect, elfobj.shnum)
+
+	elfobj.nsect = uint(elfobj.shnum)
+	for i := 0; uint(i) < elfobj.nsect; i++ {
+		if obj.Bseek(f, int64(uint64(base)+elfobj.shoff+uint64(int64(i)*int64(elfobj.shentsize))), 0) < 0 {
+			goto bad
+		}
+		sect = &elfobj.sect[i]
+		if is64 != 0 {
+			var b ElfSectBytes64
+
+			if err = binary.Read(f, e, &b); err != nil {
+				goto bad
+			}
+
+			sect.nameoff = uint32(e.Uint32(b.Name[:]))
+			sect.type_ = e.Uint32(b.Type[:])
+			sect.flags = e.Uint64(b.Flags[:])
+			sect.addr = e.Uint64(b.Addr[:])
+			sect.off = e.Uint64(b.Off[:])
+			sect.size = e.Uint64(b.Size[:])
+			sect.link = e.Uint32(b.Link[:])
+			sect.info = e.Uint32(b.Info[:])
+			sect.align = e.Uint64(b.Align[:])
+			sect.entsize = e.Uint64(b.Entsize[:])
+		} else {
+			var b ElfSectBytes
+
+			if err = binary.Read(f, e, &b); err != nil {
+				goto bad
+			}
+
+			sect.nameoff = uint32(e.Uint32(b.Name[:]))
+			sect.type_ = e.Uint32(b.Type[:])
+			sect.flags = uint64(e.Uint32(b.Flags[:]))
+			sect.addr = uint64(e.Uint32(b.Addr[:]))
+			sect.off = uint64(e.Uint32(b.Off[:]))
+			sect.size = uint64(e.Uint32(b.Size[:]))
+			sect.link = e.Uint32(b.Link[:])
+			sect.info = e.Uint32(b.Info[:])
+			sect.align = uint64(e.Uint32(b.Align[:]))
+			sect.entsize = uint64(e.Uint32(b.Entsize[:]))
+		}
+	}
+
+	// read section string table and translate names
+	if elfobj.shstrndx >= uint32(elfobj.nsect) {
+		err = fmt.Errorf("shstrndx out of range %d >= %d", elfobj.shstrndx, elfobj.nsect)
+		goto bad
+	}
+
+	sect = &elfobj.sect[elfobj.shstrndx]
+	if err = elfmap(elfobj, sect); err != nil {
+		goto bad
+	}
+	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:])
+		}
+	}
+
+	// load string table for symbols into memory.
+	elfobj.symtab = section(elfobj, ".symtab")
+
+	if elfobj.symtab == nil {
+		// our work is done here - no symbols means nothing can refer to this file
+		return
+	}
+
+	if elfobj.symtab.link <= 0 || elfobj.symtab.link >= uint32(elfobj.nsect) {
+		Diag("%s: elf object has symbol table with invalid string table link", pn)
+		return
+	}
+
+	elfobj.symstr = &elfobj.sect[elfobj.symtab.link]
+	if is64 != 0 {
+		elfobj.nsymtab = int(elfobj.symtab.size / ELF64SYMSIZE)
+	} else {
+		elfobj.nsymtab = int(elfobj.symtab.size / ELF32SYMSIZE)
+	}
+
+	if err = elfmap(elfobj, elfobj.symtab); err != nil {
+		goto bad
+	}
+	if err = elfmap(elfobj, elfobj.symstr); err != nil {
+		goto bad
+	}
+
+	// load text and data segments into memory.
+	// they are not as small as the section lists, but we'll need
+	// the memory anyway for the symbol images, so we might
+	// as well use one large chunk.
+
+	// create symbols for elfmapped sections
+	for i := 0; uint(i) < elfobj.nsect; i++ {
+		sect = &elfobj.sect[i]
+		if (sect.type_ != ElfSectProgbits && sect.type_ != ElfSectNobits) || sect.flags&ElfSectFlagAlloc == 0 {
+			continue
+		}
+		if sect.type_ != ElfSectNobits {
+			if err = elfmap(elfobj, sect); err != nil {
+				goto bad
+			}
+		}
+
+		name = fmt.Sprintf("%s(%s)", pkg, sect.name)
+		s = Linklookup(Ctxt, name, Ctxt.Version)
+
+		switch int(sect.flags) & (ElfSectFlagAlloc | ElfSectFlagWrite | ElfSectFlagExec) {
+		default:
+			err = fmt.Errorf("unexpected flags for ELF section %s", sect.name)
+			goto bad
+
+		case ElfSectFlagAlloc:
+			s.Type = obj.SRODATA
+
+		case ElfSectFlagAlloc + ElfSectFlagWrite:
+			if sect.type_ == ElfSectNobits {
+				s.Type = obj.SNOPTRBSS
+			} else {
+				s.Type = obj.SNOPTRDATA
+			}
+
+		case ElfSectFlagAlloc + ElfSectFlagExec:
+			s.Type = obj.STEXT
+		}
+
+		if sect.name == ".got" || sect.name == ".toc" {
+			s.Type = obj.SELFGOT
+		}
+		if sect.type_ == ElfSectProgbits {
+			s.P = sect.base
+			s.P = s.P[:sect.size]
+		}
+
+		s.Size = int64(sect.size)
+		s.Align = int32(sect.align)
+		sect.sym = s
+	}
+
+	// enter sub-symbols into symbol table.
+	// symbol 0 is the null symbol.
+	symbols = make([]*LSym, elfobj.nsymtab)
+
+	for i := 1; i < elfobj.nsymtab; i++ {
+		if err = readelfsym(elfobj, i, &sym, 1); err != nil {
+			goto bad
+		}
+		symbols[i] = sym.sym
+		if sym.type_ != ElfSymTypeFunc && sym.type_ != ElfSymTypeObject && sym.type_ != ElfSymTypeNone {
+			continue
+		}
+		if sym.shndx == ElfSymShnCommon {
+			s = sym.sym
+			if uint64(s.Size) < sym.size {
+				s.Size = int64(sym.size)
+			}
+			if s.Type == 0 || s.Type == obj.SXREF {
+				s.Type = obj.SNOPTRBSS
+			}
+			continue
+		}
+
+		if uint(sym.shndx) >= elfobj.nsect || sym.shndx == 0 {
+			continue
+		}
+
+		// even when we pass needSym == 1 to readelfsym, it might still return nil to skip some unwanted symbols
+		if sym.sym == nil {
+			continue
+		}
+		sect = &elfobj.sect[sym.shndx:][0]
+		if sect.sym == nil {
+			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_)
+			continue
+		}
+
+		s = sym.sym
+		if s.Outer != nil {
+			if s.Dupok != 0 {
+				continue
+			}
+			Exitf("%s: duplicate symbol reference: %s in both %s and %s", pn, s.Name, s.Outer.Name, sect.sym.Name)
+		}
+
+		s.Sub = sect.sym.Sub
+		sect.sym.Sub = s
+		s.Type = sect.sym.Type | s.Type&^obj.SMASK | obj.SSUB
+		if s.Cgoexport&CgoExportDynamic == 0 {
+			s.Dynimplib = "" // satisfy dynimport
+		}
+		s.Value = int64(sym.value)
+		s.Size = int64(sym.size)
+		s.Outer = sect.sym
+		if sect.sym.Type == obj.STEXT {
+			if s.External != 0 && s.Dupok == 0 {
+				Diag("%s: duplicate definition of %s", pn, s.Name)
+			}
+			s.External = 1
+		}
+
+		if elfobj.machine == ElfMachPower64 {
+			flag = int(sym.other) >> 5
+			if 2 <= flag && flag <= 6 {
+				s.Localentry = 1 << uint(flag-2)
+			} else if flag == 7 {
+				Diag("%s: invalid sym.other 0x%x for %s", pn, sym.other, s.Name)
+			}
+		}
+	}
+
+	// Sort outer lists by address, adding to textp.
+	// This keeps textp in increasing address order.
+	for i := 0; uint(i) < elfobj.nsect; i++ {
+		s = elfobj.sect[i].sym
+		if s == nil {
+			continue
+		}
+		if s.Sub != nil {
+			s.Sub = listsort(s.Sub, valuecmp, listsubp)
+		}
+		if s.Type == obj.STEXT {
+			if s.Onlist != 0 {
+				log.Fatalf("symbol %s listed multiple times", s.Name)
+			}
+			s.Onlist = 1
+			if Ctxt.Etextp != nil {
+				Ctxt.Etextp.Next = s
+			} else {
+				Ctxt.Textp = s
+			}
+			Ctxt.Etextp = s
+			for s = s.Sub; s != nil; s = s.Sub {
+				if s.Onlist != 0 {
+					log.Fatalf("symbol %s listed multiple times", s.Name)
+				}
+				s.Onlist = 1
+				Ctxt.Etextp.Next = s
+				Ctxt.Etextp = s
+			}
+		}
+	}
+
+	// load relocations
+	for i := 0; uint(i) < elfobj.nsect; i++ {
+		rsect = &elfobj.sect[i]
+		if rsect.type_ != ElfSectRela && rsect.type_ != ElfSectRel {
+			continue
+		}
+		if rsect.info >= uint32(elfobj.nsect) || elfobj.sect[rsect.info].base == nil {
+			continue
+		}
+		sect = &elfobj.sect[rsect.info]
+		if err = elfmap(elfobj, rsect); err != nil {
+			goto bad
+		}
+		rela = 0
+		if rsect.type_ == ElfSectRela {
+			rela = 1
+		}
+		n = int(rsect.size / uint64(4+4*is64) / uint64(2+rela))
+		r = make([]Reloc, n)
+		p = rsect.base
+		for j = 0; j < n; j++ {
+			add = 0
+			rp = &r[j]
+			if is64 != 0 {
+				// 64-bit rel/rela
+				rp.Off = int32(e.Uint64(p))
+
+				p = p[8:]
+				info = e.Uint64(p)
+				p = p[8:]
+				if rela != 0 {
+					add = e.Uint64(p)
+					p = p[8:]
+				}
+			} else {
+				// 32-bit rel/rela
+				rp.Off = int32(e.Uint32(p))
+
+				p = p[4:]
+				info = uint64(e.Uint32(p))
+				info = info>>8<<32 | info&0xff // convert to 64-bit info
+				p = p[4:]
+				if rela != 0 {
+					add = uint64(e.Uint32(p))
+					p = p[4:]
+				}
+			}
+
+			if info&0xffffffff == 0 { // skip R_*_NONE relocation
+				j--
+				n--
+				continue
+			}
+
+			if info>>32 == 0 { // absolute relocation, don't bother reading the null symbol
+				rp.Sym = nil
+			} else {
+				if err = readelfsym(elfobj, int(info>>32), &sym, 0); err != nil {
+					goto bad
+				}
+				sym.sym = symbols[info>>32]
+				if sym.sym == nil {
+					err = fmt.Errorf("%s#%d: reloc of invalid sym #%d %s shndx=%d type=%d", sect.sym.Name, j, int(info>>32), sym.name, sym.shndx, sym.type_)
+					goto bad
+				}
+
+				rp.Sym = sym.sym
+			}
+
+			rp.Type = int32(reltype(pn, int(uint32(info)), &rp.Siz))
+			if rela != 0 {
+				rp.Add = int64(add)
+			} else {
+				// load addend from image
+				if rp.Siz == 4 {
+					rp.Add = int64(e.Uint32(sect.base[rp.Off:]))
+				} else if rp.Siz == 8 {
+					rp.Add = int64(e.Uint64(sect.base[rp.Off:]))
+				} else {
+					Diag("invalid rela size %d", rp.Siz)
+				}
+			}
+
+			if rp.Siz == 2 {
+				rp.Add = int64(int16(rp.Add))
+			}
+			if rp.Siz == 4 {
+				rp.Add = int64(int32(rp.Add))
+			}
+		}
+
+		//print("rel %s %d %d %s %#llx\n", sect->sym->name, rp->type, rp->siz, rp->sym->name, rp->add);
+		sort.Sort(rbyoff(r[:n]))
+		// just in case
+
+		s = sect.sym
+		s.R = r
+		s.R = s.R[:n]
+	}
+
+	return
+
+bad:
+	Diag("%s: malformed elf file: %v", pn, err)
+}
+
+func section(elfobj *ElfObj, name string) *ElfSect {
+	for i := 0; uint(i) < elfobj.nsect; i++ {
+		if elfobj.sect[i].name != "" && name != "" && elfobj.sect[i].name == name {
+			return &elfobj.sect[i]
+		}
+	}
+	return nil
+}
+
+func elfmap(elfobj *ElfObj, sect *ElfSect) (err error) {
+	if sect.base != nil {
+		return nil
+	}
+
+	if sect.off+sect.size > uint64(elfobj.length) {
+		err = fmt.Errorf("elf section past end of file")
+		return err
+	}
+
+	sect.base = make([]byte, sect.size)
+	err = fmt.Errorf("short read")
+	if obj.Bseek(elfobj.f, int64(uint64(elfobj.base)+sect.off), 0) < 0 || obj.Bread(elfobj.f, sect.base) != len(sect.base) {
+		return err
+	}
+
+	return nil
+}
+
+func readelfsym(elfobj *ElfObj, i int, sym *ElfSym, needSym int) (err error) {
+	if i >= elfobj.nsymtab || i < 0 {
+		err = fmt.Errorf("invalid elf symbol index")
+		return err
+	}
+
+	if i == 0 {
+		Diag("readym: read null symbol!")
+	}
+
+	if elfobj.is64 != 0 {
+		b := new(ElfSymBytes64)
+		binary.Read(bytes.NewReader(elfobj.symtab.base[i*ELF64SYMSIZE:(i+1)*ELF64SYMSIZE]), elfobj.e, b)
+		sym.name = cstring(elfobj.symstr.base[elfobj.e.Uint32(b.Name[:]):])
+		sym.value = elfobj.e.Uint64(b.Value[:])
+		sym.size = elfobj.e.Uint64(b.Size[:])
+		sym.shndx = elfobj.e.Uint16(b.Shndx[:])
+		sym.bind = b.Info >> 4
+		sym.type_ = b.Info & 0xf
+		sym.other = b.Other
+	} else {
+		b := new(ElfSymBytes)
+		binary.Read(bytes.NewReader(elfobj.symtab.base[i*ELF32SYMSIZE:(i+1)*ELF32SYMSIZE]), elfobj.e, b)
+		sym.name = cstring(elfobj.symstr.base[elfobj.e.Uint32(b.Name[:]):])
+		sym.value = uint64(elfobj.e.Uint32(b.Value[:]))
+		sym.size = uint64(elfobj.e.Uint32(b.Size[:]))
+		sym.shndx = elfobj.e.Uint16(b.Shndx[:])
+		sym.bind = b.Info >> 4
+		sym.type_ = b.Info & 0xf
+		sym.other = b.Other
+	}
+
+	var s *LSym
+	if sym.name == "_GLOBAL_OFFSET_TABLE_" {
+		sym.name = ".got"
+	}
+	if sym.name == ".TOC." {
+		// Magic symbol on ppc64.  Will be set to this object
+		// file's .got+0x8000.
+		sym.bind = ElfSymBindLocal
+	}
+
+	switch sym.type_ {
+	case ElfSymTypeSection:
+		s = elfobj.sect[sym.shndx].sym
+
+	case ElfSymTypeObject, ElfSymTypeFunc, ElfSymTypeNone:
+		switch sym.bind {
+		case ElfSymBindGlobal:
+			if needSym != 0 {
+				s = Linklookup(Ctxt, sym.name, 0)
+
+				// for global scoped hidden symbols we should insert it into
+				// symbol hash table, but mark them as hidden.
+				// __i686.get_pc_thunk.bx is allowed to be duplicated, to
+				// workaround that we set dupok.
+				// TODO(minux): correctly handle __i686.get_pc_thunk.bx without
+				// set dupok generally. See http://codereview.appspot.com/5823055/
+				// comment #5 for details.
+				if s != nil && sym.other == 2 {
+					s.Type |= obj.SHIDDEN
+					s.Dupok = 1
+				}
+			}
+
+		case ElfSymBindLocal:
+			if Thearch.Thechar == '5' && (strings.HasPrefix(sym.name, "$a") || strings.HasPrefix(sym.name, "$d")) {
+				// binutils for arm generate these mapping
+				// symbols, ignore these
+				break
+			}
+
+			if sym.name == ".TOC." {
+				// We need to be able to look this up,
+				// so put it in the hash table.
+				if needSym != 0 {
+					s = Linklookup(Ctxt, sym.name, Ctxt.Version)
+					s.Type |= obj.SHIDDEN
+				}
+
+				break
+			}
+
+			if needSym != 0 {
+				// local names and hidden visiblity global names are unique
+				// and should only reference by its index, not name, so we
+				// don't bother to add them into hash table
+				s = linknewsym(Ctxt, sym.name, Ctxt.Version)
+
+				s.Type |= obj.SHIDDEN
+			}
+
+		case ElfSymBindWeak:
+			if needSym != 0 {
+				s = linknewsym(Ctxt, sym.name, 0)
+				if sym.other == 2 {
+					s.Type |= obj.SHIDDEN
+				}
+			}
+
+		default:
+			err = fmt.Errorf("%s: invalid symbol binding %d", sym.name, sym.bind)
+			return err
+		}
+	}
+
+	if s != nil && s.Type == 0 && sym.type_ != ElfSymTypeSection {
+		s.Type = obj.SXREF
+	}
+	sym.sym = s
+
+	return nil
+}
+
+type rbyoff []Reloc
+
+func (x rbyoff) Len() int {
+	return len(x)
+}
+
+func (x rbyoff) Swap(i, j int) {
+	x[i], x[j] = x[j], x[i]
+}
+
+func (x rbyoff) Less(i, j int) bool {
+	a := &x[i]
+	b := &x[j]
+	if a.Off < b.Off {
+		return true
+	}
+	if a.Off > b.Off {
+		return false
+	}
+	return false
+}
+
+func reltype(pn string, elftype int, siz *uint8) int {
+	switch uint32(Thearch.Thechar) | uint32(elftype)<<24 {
+	default:
+		Diag("%s: unknown relocation type %d; compiled without -fpic?", pn, elftype)
+		fallthrough
+
+	case '9' | R_PPC64_TOC16<<24,
+		'9' | R_PPC64_TOC16_LO<<24,
+		'9' | R_PPC64_TOC16_HI<<24,
+		'9' | R_PPC64_TOC16_HA<<24,
+		'9' | R_PPC64_TOC16_DS<<24,
+		'9' | R_PPC64_TOC16_LO_DS<<24,
+		'9' | R_PPC64_REL16_LO<<24,
+		'9' | R_PPC64_REL16_HI<<24,
+		'9' | R_PPC64_REL16_HA<<24:
+		*siz = 2
+
+	case '5' | R_ARM_ABS32<<24,
+		'5' | R_ARM_GOT32<<24,
+		'5' | R_ARM_PLT32<<24,
+		'5' | R_ARM_GOTOFF<<24,
+		'5' | R_ARM_GOTPC<<24,
+		'5' | R_ARM_THM_PC22<<24,
+		'5' | R_ARM_REL32<<24,
+		'5' | R_ARM_CALL<<24,
+		'5' | R_ARM_V4BX<<24,
+		'5' | R_ARM_GOT_PREL<<24,
+		'5' | R_ARM_PC24<<24,
+		'5' | R_ARM_JUMP24<<24,
+		'6' | R_X86_64_PC32<<24,
+		'6' | R_X86_64_PLT32<<24,
+		'6' | R_X86_64_GOTPCREL<<24,
+		'8' | R_386_32<<24,
+		'8' | R_386_PC32<<24,
+		'8' | R_386_GOT32<<24,
+		'8' | R_386_PLT32<<24,
+		'8' | R_386_GOTOFF<<24,
+		'8' | R_386_GOTPC<<24,
+		'9' | R_PPC64_REL24<<24:
+		*siz = 4
+
+	case '6' | R_X86_64_64<<24,
+		'9' | R_PPC64_ADDR64<<24:
+		*siz = 8
+	}
+
+	return 256 + elftype
+}
diff --git a/src/cmd/link/internal/ld/ldmacho.go b/src/cmd/link/internal/ld/ldmacho.go
new file mode 100644
index 0000000..2abfa33
--- /dev/null
+++ b/src/cmd/link/internal/ld/ldmacho.go
@@ -0,0 +1,893 @@
+package ld
+
+import (
+	"cmd/internal/obj"
+	"encoding/binary"
+	"fmt"
+	"log"
+	"sort"
+)
+
+/*
+Derived from Plan 9 from User Space's src/libmach/elf.h, elf.c
+http://code.swtch.com/plan9port/src/tip/src/libmach/
+
+	Copyright © 2004 Russ Cox.
+	Portions Copyright © 2008-2010 Google Inc.
+	Portions Copyright © 2010 The Go Authors.
+
+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 (
+	N_EXT  = 0x01
+	N_TYPE = 0x1e
+	N_STAB = 0xe0
+)
+
+type LdMachoObj struct {
+	f          *obj.Biobuf
+	base       int64 // off in f where Mach-O begins
+	length     int64 // length of Mach-O
+	is64       bool
+	name       string
+	e          binary.ByteOrder
+	cputype    uint
+	subcputype uint
+	filetype   uint32
+	flags      uint32
+	cmd        []LdMachoCmd
+	ncmd       uint
+}
+
+type LdMachoCmd struct {
+	type_ int
+	off   uint32
+	size  uint32
+	seg   LdMachoSeg
+	sym   LdMachoSymtab
+	dsym  LdMachoDysymtab
+}
+
+type LdMachoSeg struct {
+	name     string
+	vmaddr   uint64
+	vmsize   uint64
+	fileoff  uint32
+	filesz   uint32
+	maxprot  uint32
+	initprot uint32
+	nsect    uint32
+	flags    uint32
+	sect     []LdMachoSect
+}
+
+type LdMachoSect struct {
+	name    string
+	segname string
+	addr    uint64
+	size    uint64
+	off     uint32
+	align   uint32
+	reloff  uint32
+	nreloc  uint32
+	flags   uint32
+	res1    uint32
+	res2    uint32
+	sym     *LSym
+	rel     []LdMachoRel
+}
+
+type LdMachoRel struct {
+	addr      uint32
+	symnum    uint32
+	pcrel     uint8
+	length    uint8
+	extrn     uint8
+	type_     uint8
+	scattered uint8
+	value     uint32
+}
+
+type LdMachoSymtab struct {
+	symoff  uint32
+	nsym    uint32
+	stroff  uint32
+	strsize uint32
+	str     []byte
+	sym     []LdMachoSym
+}
+
+type LdMachoSym struct {
+	name    string
+	type_   uint8
+	sectnum uint8
+	desc    uint16
+	kind    int8
+	value   uint64
+	sym     *LSym
+}
+
+type LdMachoDysymtab struct {
+	ilocalsym      uint32
+	nlocalsym      uint32
+	iextdefsym     uint32
+	nextdefsym     uint32
+	iundefsym      uint32
+	nundefsym      uint32
+	tocoff         uint32
+	ntoc           uint32
+	modtaboff      uint32
+	nmodtab        uint32
+	extrefsymoff   uint32
+	nextrefsyms    uint32
+	indirectsymoff uint32
+	nindirectsyms  uint32
+	extreloff      uint32
+	nextrel        uint32
+	locreloff      uint32
+	nlocrel        uint32
+	indir          []uint32
+}
+
+const (
+	LdMachoCpuVax         = 1
+	LdMachoCpu68000       = 6
+	LdMachoCpu386         = 7
+	LdMachoCpuAmd64       = 0x1000007
+	LdMachoCpuMips        = 8
+	LdMachoCpu98000       = 10
+	LdMachoCpuHppa        = 11
+	LdMachoCpuArm         = 12
+	LdMachoCpu88000       = 13
+	LdMachoCpuSparc       = 14
+	LdMachoCpu860         = 15
+	LdMachoCpuAlpha       = 16
+	LdMachoCpuPower       = 18
+	LdMachoCmdSegment     = 1
+	LdMachoCmdSymtab      = 2
+	LdMachoCmdSymseg      = 3
+	LdMachoCmdThread      = 4
+	LdMachoCmdDysymtab    = 11
+	LdMachoCmdSegment64   = 25
+	LdMachoFileObject     = 1
+	LdMachoFileExecutable = 2
+	LdMachoFileFvmlib     = 3
+	LdMachoFileCore       = 4
+	LdMachoFilePreload    = 5
+)
+
+func unpackcmd(p []byte, m *LdMachoObj, c *LdMachoCmd, type_ uint, sz uint) int {
+	e4 := m.e.Uint32
+	e8 := m.e.Uint64
+
+	c.type_ = int(type_)
+	c.size = uint32(sz)
+	switch type_ {
+	default:
+		return -1
+
+	case LdMachoCmdSegment:
+		if sz < 56 {
+			return -1
+		}
+		c.seg.name = cstring(p[8:24])
+		c.seg.vmaddr = uint64(e4(p[24:]))
+		c.seg.vmsize = uint64(e4(p[28:]))
+		c.seg.fileoff = e4(p[32:])
+		c.seg.filesz = e4(p[36:])
+		c.seg.maxprot = e4(p[40:])
+		c.seg.initprot = e4(p[44:])
+		c.seg.nsect = e4(p[48:])
+		c.seg.flags = e4(p[52:])
+		c.seg.sect = make([]LdMachoSect, c.seg.nsect)
+		if uint32(sz) < 56+c.seg.nsect*68 {
+			return -1
+		}
+		p = p[56:]
+		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])
+			s.addr = uint64(e4(p[32:]))
+			s.size = uint64(e4(p[36:]))
+			s.off = e4(p[40:])
+			s.align = e4(p[44:])
+			s.reloff = e4(p[48:])
+			s.nreloc = e4(p[52:])
+			s.flags = e4(p[56:])
+			s.res1 = e4(p[60:])
+			s.res2 = e4(p[64:])
+			p = p[68:]
+		}
+
+	case LdMachoCmdSegment64:
+		if sz < 72 {
+			return -1
+		}
+		c.seg.name = cstring(p[8:24])
+		c.seg.vmaddr = e8(p[24:])
+		c.seg.vmsize = e8(p[32:])
+		c.seg.fileoff = uint32(e8(p[40:]))
+		c.seg.filesz = uint32(e8(p[48:]))
+		c.seg.maxprot = e4(p[56:])
+		c.seg.initprot = e4(p[60:])
+		c.seg.nsect = e4(p[64:])
+		c.seg.flags = e4(p[68:])
+		c.seg.sect = make([]LdMachoSect, c.seg.nsect)
+		if uint32(sz) < 72+c.seg.nsect*80 {
+			return -1
+		}
+		p = p[72:]
+		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])
+			s.addr = e8(p[32:])
+			s.size = e8(p[40:])
+			s.off = e4(p[48:])
+			s.align = e4(p[52:])
+			s.reloff = e4(p[56:])
+			s.nreloc = e4(p[60:])
+			s.flags = e4(p[64:])
+			s.res1 = e4(p[68:])
+			s.res2 = e4(p[72:])
+
+			// p+76 is reserved
+			p = p[80:]
+		}
+
+	case LdMachoCmdSymtab:
+		if sz < 24 {
+			return -1
+		}
+		c.sym.symoff = e4(p[8:])
+		c.sym.nsym = e4(p[12:])
+		c.sym.stroff = e4(p[16:])
+		c.sym.strsize = e4(p[20:])
+
+	case LdMachoCmdDysymtab:
+		if sz < 80 {
+			return -1
+		}
+		c.dsym.ilocalsym = e4(p[8:])
+		c.dsym.nlocalsym = e4(p[12:])
+		c.dsym.iextdefsym = e4(p[16:])
+		c.dsym.nextdefsym = e4(p[20:])
+		c.dsym.iundefsym = e4(p[24:])
+		c.dsym.nundefsym = e4(p[28:])
+		c.dsym.tocoff = e4(p[32:])
+		c.dsym.ntoc = e4(p[36:])
+		c.dsym.modtaboff = e4(p[40:])
+		c.dsym.nmodtab = e4(p[44:])
+		c.dsym.extrefsymoff = e4(p[48:])
+		c.dsym.nextrefsyms = e4(p[52:])
+		c.dsym.indirectsymoff = e4(p[56:])
+		c.dsym.nindirectsyms = e4(p[60:])
+		c.dsym.extreloff = e4(p[64:])
+		c.dsym.nextrel = e4(p[68:])
+		c.dsym.locreloff = e4(p[72:])
+		c.dsym.nlocrel = e4(p[76:])
+	}
+
+	return 0
+}
+
+func macholoadrel(m *LdMachoObj, sect *LdMachoSect) int {
+	if sect.rel != nil || sect.nreloc == 0 {
+		return 0
+	}
+	rel := make([]LdMachoRel, sect.nreloc)
+	n := int(sect.nreloc * 8)
+	buf := make([]byte, n)
+	if obj.Bseek(m.f, m.base+int64(sect.reloff), 0) < 0 || obj.Bread(m.f, buf) != n {
+		return -1
+	}
+	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)
+
+		// TODO(rsc): Wrong interpretation for big-endian bitfields?
+		if r.addr&0x80000000 != 0 {
+			// scatterbrained relocation
+			r.scattered = 1
+
+			v = r.addr >> 24
+			r.addr &= 0xFFFFFF
+			r.type_ = uint8(v & 0xF)
+			v >>= 4
+			r.length = 1 << (v & 3)
+			v >>= 2
+			r.pcrel = uint8(v & 1)
+			r.value = m.e.Uint32(p[4:])
+		} else {
+			v = m.e.Uint32(p[4:])
+			r.symnum = v & 0xFFFFFF
+			v >>= 24
+			r.pcrel = uint8(v & 1)
+			v >>= 1
+			r.length = 1 << (v & 3)
+			v >>= 2
+			r.extrn = uint8(v & 1)
+			v >>= 1
+			r.type_ = uint8(v)
+		}
+	}
+
+	sect.rel = rel
+	return 0
+}
+
+func macholoaddsym(m *LdMachoObj, d *LdMachoDysymtab) int {
+	n := int(d.nindirectsyms)
+
+	p := make([]byte, n*4)
+	if obj.Bseek(m.f, m.base+int64(d.indirectsymoff), 0) < 0 || obj.Bread(m.f, p) != len(p) {
+		return -1
+	}
+
+	d.indir = make([]uint32, n)
+	for i := 0; i < n; i++ {
+		d.indir[i] = m.e.Uint32(p[4*i:])
+	}
+	return 0
+}
+
+func macholoadsym(m *LdMachoObj, symtab *LdMachoSymtab) int {
+	if symtab.sym != nil {
+		return 0
+	}
+
+	strbuf := make([]byte, symtab.strsize)
+	if obj.Bseek(m.f, m.base+int64(symtab.stroff), 0) < 0 || obj.Bread(m.f, strbuf) != len(strbuf) {
+		return -1
+	}
+
+	symsize := 12
+	if m.is64 {
+		symsize = 16
+	}
+	n := int(symtab.nsym * uint32(symsize))
+	symbuf := make([]byte, n)
+	if obj.Bseek(m.f, m.base+int64(symtab.symoff), 0) < 0 || obj.Bread(m.f, symbuf) != len(symbuf) {
+		return -1
+	}
+	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 {
+			return -1
+		}
+		s.name = cstring(strbuf[v:])
+		s.type_ = uint8(p[4])
+		s.sectnum = uint8(p[5])
+		s.desc = m.e.Uint16(p[6:])
+		if m.is64 {
+			s.value = m.e.Uint64(p[8:])
+		} else {
+			s.value = uint64(m.e.Uint32(p[8:]))
+		}
+		p = p[symsize:]
+	}
+
+	symtab.str = strbuf
+	symtab.sym = sym
+	return 0
+}
+
+func ldmacho(f *obj.Biobuf, pkg string, length int64, pn string) {
+	var err error
+	var j int
+	var is64 bool
+	var secaddr uint64
+	var hdr [7 * 4]uint8
+	var cmdp []byte
+	var dat []byte
+	var ncmd uint32
+	var cmdsz uint32
+	var ty uint32
+	var sz uint32
+	var off uint32
+	var m *LdMachoObj
+	var e binary.ByteOrder
+	var sect *LdMachoSect
+	var rel *LdMachoRel
+	var rpi int
+	var s *LSym
+	var s1 *LSym
+	var outer *LSym
+	var c *LdMachoCmd
+	var symtab *LdMachoSymtab
+	var dsymtab *LdMachoDysymtab
+	var sym *LdMachoSym
+	var r []Reloc
+	var rp *Reloc
+	var name string
+
+	Ctxt.Version++
+	base := obj.Boffset(f)
+	if obj.Bread(f, hdr[:]) != len(hdr) {
+		goto bad
+	}
+
+	if binary.BigEndian.Uint32(hdr[:])&^1 == 0xFEEDFACE {
+		e = binary.BigEndian
+	} else if binary.LittleEndian.Uint32(hdr[:])&^1 == 0xFEEDFACE {
+		e = binary.LittleEndian
+	} else {
+		err = fmt.Errorf("bad magic - not mach-o file")
+		goto bad
+	}
+
+	is64 = e.Uint32(hdr[:]) == 0xFEEDFACF
+	ncmd = e.Uint32([]byte(hdr[4*4:]))
+	cmdsz = e.Uint32([]byte(hdr[5*4:]))
+	if ncmd > 0x10000 || cmdsz >= 0x01000000 {
+		err = fmt.Errorf("implausible mach-o header ncmd=%d cmdsz=%d", ncmd, cmdsz)
+		goto bad
+	}
+
+	if is64 {
+		var tmp [4]uint8
+		obj.Bread(f, tmp[:4]) // skip reserved word in header
+	}
+
+	m = new(LdMachoObj)
+
+	m.f = f
+	m.e = e
+	m.cputype = uint(e.Uint32([]byte(hdr[1*4:])))
+	m.subcputype = uint(e.Uint32([]byte(hdr[2*4:])))
+	m.filetype = e.Uint32([]byte(hdr[3*4:]))
+	m.ncmd = uint(ncmd)
+	m.flags = e.Uint32([]byte(hdr[6*4:]))
+	m.is64 = is64
+	m.base = base
+	m.length = length
+	m.name = pn
+
+	switch Thearch.Thechar {
+	default:
+		Diag("%s: mach-o %s unimplemented", pn, Thestring)
+		return
+
+	case '6':
+		if e != binary.LittleEndian || m.cputype != LdMachoCpuAmd64 {
+			Diag("%s: mach-o object but not amd64", pn)
+			return
+		}
+
+	case '8':
+		if e != binary.LittleEndian || m.cputype != LdMachoCpu386 {
+			Diag("%s: mach-o object but not 386", pn)
+			return
+		}
+	}
+
+	m.cmd = make([]LdMachoCmd, ncmd)
+	off = uint32(len(hdr))
+	cmdp = make([]byte, cmdsz)
+	if obj.Bread(f, cmdp) != len(cmdp) {
+		err = fmt.Errorf("reading cmds: %v", err)
+		goto bad
+	}
+
+	// read and parse load commands
+	c = nil
+
+	symtab = nil
+	dsymtab = nil
+
+	for i := 0; uint32(i) < ncmd; i++ {
+		ty = e.Uint32(cmdp)
+		sz = e.Uint32(cmdp[4:])
+		m.cmd[i].off = off
+		unpackcmd(cmdp, m, &m.cmd[i], uint(ty), uint(sz))
+		cmdp = cmdp[sz:]
+		off += sz
+		if ty == LdMachoCmdSymtab {
+			if symtab != nil {
+				err = fmt.Errorf("multiple symbol tables")
+				goto bad
+			}
+
+			symtab = &m.cmd[i].sym
+			macholoadsym(m, symtab)
+		}
+
+		if ty == LdMachoCmdDysymtab {
+			dsymtab = &m.cmd[i].dsym
+			macholoaddsym(m, dsymtab)
+		}
+
+		if (is64 && ty == LdMachoCmdSegment64) || (!is64 && ty == LdMachoCmdSegment) {
+			if c != nil {
+				err = fmt.Errorf("multiple load commands")
+				goto bad
+			}
+
+			c = &m.cmd[i]
+		}
+	}
+
+	// load text and data segments into memory.
+	// they are not as small as the load commands, but we'll need
+	// the memory anyway for the symbol images, so we might
+	// as well use one large chunk.
+	if c == nil {
+		err = fmt.Errorf("no load command")
+		goto bad
+	}
+
+	if symtab == nil {
+		// our work is done here - no symbols means nothing can refer to this file
+		return
+	}
+
+	if int64(c.seg.fileoff+c.seg.filesz) >= length {
+		err = fmt.Errorf("load segment out of range")
+		goto bad
+	}
+
+	dat = make([]byte, c.seg.filesz)
+	if obj.Bseek(f, m.base+int64(c.seg.fileoff), 0) < 0 || obj.Bread(f, dat) != len(dat) {
+		err = fmt.Errorf("cannot load object data: %v", err)
+		goto bad
+	}
+
+	for i := 0; uint32(i) < c.seg.nsect; i++ {
+		sect = &c.seg.sect[i]
+		if sect.segname != "__TEXT" && sect.segname != "__DATA" {
+			continue
+		}
+		if sect.name == "__eh_frame" {
+			continue
+		}
+		name = fmt.Sprintf("%s(%s/%s)", pkg, sect.segname, sect.name)
+		s = Linklookup(Ctxt, name, Ctxt.Version)
+		if s.Type != 0 {
+			err = fmt.Errorf("duplicate %s/%s", sect.segname, sect.name)
+			goto bad
+		}
+
+		if sect.flags&0xff == 1 { // S_ZEROFILL
+			s.P = make([]byte, sect.size)
+		} else {
+			s.P = dat[sect.addr-c.seg.vmaddr:][:sect.size]
+		}
+		s.Size = int64(len(s.P))
+
+		if sect.segname == "__TEXT" {
+			if sect.name == "__text" {
+				s.Type = obj.STEXT
+			} else {
+				s.Type = obj.SRODATA
+			}
+		} else {
+			if sect.name == "__bss" {
+				s.Type = obj.SNOPTRBSS
+				s.P = s.P[:0]
+			} else {
+				s.Type = obj.SNOPTRDATA
+			}
+		}
+
+		sect.sym = s
+	}
+
+	// enter sub-symbols into symbol table.
+	// have to guess sizes from next symbol.
+	for i := 0; uint32(i) < symtab.nsym; i++ {
+		sym = &symtab.sym[i]
+		if sym.type_&N_STAB != 0 {
+			continue
+		}
+
+		// TODO: check sym->type against outer->type.
+		name = sym.name
+
+		if name[0] == '_' && name[1] != '\x00' {
+			name = name[1:]
+		}
+		v := 0
+		if sym.type_&N_EXT == 0 {
+			v = Ctxt.Version
+		}
+		s = Linklookup(Ctxt, name, v)
+		if sym.type_&N_EXT == 0 {
+			s.Dupok = 1
+		}
+		sym.sym = s
+		if sym.sectnum == 0 { // undefined
+			continue
+		}
+		if uint32(sym.sectnum) > c.seg.nsect {
+			err = fmt.Errorf("reference to invalid section %d", sym.sectnum)
+			goto bad
+		}
+
+		sect = &c.seg.sect[sym.sectnum-1]
+		outer = sect.sym
+		if outer == nil {
+			err = fmt.Errorf("reference to invalid section %s/%s", sect.segname, sect.name)
+			continue
+		}
+
+		if s.Outer != nil {
+			if s.Dupok != 0 {
+				continue
+			}
+			Exitf("%s: duplicate symbol reference: %s in both %s and %s", pn, s.Name, s.Outer.Name, sect.sym.Name)
+		}
+
+		s.Type = outer.Type | obj.SSUB
+		s.Sub = outer.Sub
+		outer.Sub = s
+		s.Outer = outer
+		s.Value = int64(sym.value - sect.addr)
+		if s.Cgoexport&CgoExportDynamic == 0 {
+			s.Dynimplib = "" // satisfy dynimport
+		}
+		if outer.Type == obj.STEXT {
+			if s.External != 0 && s.Dupok == 0 {
+				Diag("%s: duplicate definition of %s", pn, s.Name)
+			}
+			s.External = 1
+		}
+
+		sym.sym = s
+	}
+
+	// Sort outer lists by address, adding to textp.
+	// This keeps textp in increasing address order.
+	for i := 0; uint32(i) < c.seg.nsect; i++ {
+		sect = &c.seg.sect[i]
+		s = sect.sym
+		if s == nil {
+			continue
+		}
+		if s.Sub != nil {
+			s.Sub = listsort(s.Sub, valuecmp, listsubp)
+
+			// assign sizes, now that we know symbols in sorted order.
+			for s1 = s.Sub; s1 != nil; s1 = s1.Sub {
+				if s1.Sub != nil {
+					s1.Size = s1.Sub.Value - s1.Value
+				} else {
+					s1.Size = s.Value + s.Size - s1.Value
+				}
+			}
+		}
+
+		if s.Type == obj.STEXT {
+			if s.Onlist != 0 {
+				log.Fatalf("symbol %s listed multiple times", s.Name)
+			}
+			s.Onlist = 1
+			if Ctxt.Etextp != nil {
+				Ctxt.Etextp.Next = s
+			} else {
+				Ctxt.Textp = s
+			}
+			Ctxt.Etextp = s
+			for s1 = s.Sub; s1 != nil; s1 = s1.Sub {
+				if s1.Onlist != 0 {
+					log.Fatalf("symbol %s listed multiple times", s1.Name)
+				}
+				s1.Onlist = 1
+				Ctxt.Etextp.Next = s1
+				Ctxt.Etextp = s1
+			}
+		}
+	}
+
+	// load relocations
+	for i := 0; uint32(i) < c.seg.nsect; i++ {
+		sect = &c.seg.sect[i]
+		s = sect.sym
+		if s == nil {
+			continue
+		}
+		macholoadrel(m, sect)
+		if sect.rel == nil {
+			continue
+		}
+		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 {
+				if Thearch.Thechar != '8' {
+					// mach-o only uses scattered relocation on 32-bit platforms
+					Diag("unexpected scattered relocation")
+
+					continue
+				}
+
+				// on 386, rewrite scattered 4/1 relocation and some
+				// scattered 2/1 relocation into the pseudo-pc-relative
+				// reference that it is.
+				// assume that the second in the pair is in this section
+				// and use that as the pc-relative base.
+				if uint32(j+1) >= sect.nreloc {
+					err = fmt.Errorf("unsupported scattered relocation %d", int(rel.type_))
+					goto bad
+				}
+
+				if sect.rel[j+1].scattered == 0 || sect.rel[j+1].type_ != 1 || (rel.type_ != 4 && rel.type_ != 2) || uint64(sect.rel[j+1].value) < sect.addr || uint64(sect.rel[j+1].value) >= sect.addr+sect.size {
+					err = fmt.Errorf("unsupported scattered relocation %d/%d", int(rel.type_), int(sect.rel[j+1].type_))
+					goto bad
+				}
+
+				rp.Siz = rel.length
+				rp.Off = int32(rel.addr)
+
+				// NOTE(rsc): I haven't worked out why (really when)
+				// we should ignore the addend on a
+				// scattered relocation, but it seems that the
+				// common case is we ignore it.
+				// It's likely that this is not strictly correct
+				// and that the math should look something
+				// like the non-scattered case below.
+				rp.Add = 0
+
+				// want to make it pc-relative aka relative to rp->off+4
+				// but the scatter asks for relative to off = sect->rel[j+1].value - sect->addr.
+				// adjust rp->add accordingly.
+				rp.Type = obj.R_PCREL
+
+				rp.Add += int64(uint64(int64(rp.Off)+4) - (uint64(sect.rel[j+1].value) - sect.addr))
+
+				// now consider the desired symbol.
+				// find the section where it lives.
+				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 {
+						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
+
+			}
+
+			rp.Siz = rel.length
+			rp.Type = 512 + (int32(rel.type_) << 1) + int32(rel.pcrel)
+			rp.Off = int32(rel.addr)
+
+			// Handle X86_64_RELOC_SIGNED referencing a section (rel->extrn == 0).
+			if Thearch.Thechar == '6' && rel.extrn == 0 && rel.type_ == 1 {
+				// Calculate the addend as the offset into the section.
+				//
+				// The rip-relative offset stored in the object file is encoded
+				// as follows:
+				//
+				//    movsd	0x00000360(%rip),%xmm0
+				//
+				// To get the absolute address of the value this rip-relative address is pointing
+				// to, we must add the address of the next instruction to it. This is done by
+				// taking the address of the relocation and adding 4 to it (since the rip-relative
+				// offset can at most be 32 bits long).  To calculate the offset into the section the
+				// relocation is referencing, we subtract the vaddr of the start of the referenced
+				// section found in the original object file.
+				//
+				// [For future reference, see Darwin's /usr/include/mach-o/x86_64/reloc.h]
+				secaddr = c.seg.sect[rel.symnum-1].addr
+
+				rp.Add = int64(uint64(int64(int32(e.Uint32(s.P[rp.Off:])))+int64(rp.Off)+4) - secaddr)
+			} else {
+				rp.Add = int64(int32(e.Uint32(s.P[rp.Off:])))
+			}
+
+			// For i386 Mach-O PC-relative, the addend is written such that
+			// it *is* the PC being subtracted.  Use that to make
+			// it match our version of PC-relative.
+			if rel.pcrel != 0 && Thearch.Thechar == '8' {
+				rp.Add += int64(rp.Off) + int64(rp.Siz)
+			}
+			if rel.extrn == 0 {
+				if rel.symnum < 1 || rel.symnum > c.seg.nsect {
+					err = fmt.Errorf("invalid relocation: section reference out of range %d vs %d", rel.symnum, c.seg.nsect)
+					goto bad
+				}
+
+				rp.Sym = c.seg.sect[rel.symnum-1].sym
+				if rp.Sym == nil {
+					err = fmt.Errorf("invalid relocation: %s", c.seg.sect[rel.symnum-1].name)
+					goto bad
+				}
+
+				// References to symbols in other sections
+				// include that information in the addend.
+				// We only care about the delta from the
+				// section base.
+				if Thearch.Thechar == '8' {
+					rp.Add -= int64(c.seg.sect[rel.symnum-1].addr)
+				}
+			} else {
+				if rel.symnum >= symtab.nsym {
+					err = fmt.Errorf("invalid relocation: symbol reference out of range")
+					goto bad
+				}
+
+				rp.Sym = symtab.sym[rel.symnum].sym
+			}
+
+			rpi++
+		}
+
+		sort.Sort(rbyoff(r[:rpi]))
+		s.R = r
+		s.R = s.R[:rpi]
+	}
+
+	return
+
+bad:
+	Diag("%s: malformed mach-o file: %v", pn, err)
+}
diff --git a/src/cmd/link/internal/ld/ldpe.go b/src/cmd/link/internal/ld/ldpe.go
new file mode 100644
index 0000000..b98cf02
--- /dev/null
+++ b/src/cmd/link/internal/ld/ldpe.go
@@ -0,0 +1,534 @@
+// Copyright 2010 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 ld
+
+import (
+	"cmd/internal/obj"
+	"encoding/binary"
+	"fmt"
+	"log"
+	"sort"
+	"strings"
+)
+
+const (
+	IMAGE_SYM_UNDEFINED              = 0
+	IMAGE_SYM_ABSOLUTE               = -1
+	IMAGE_SYM_DEBUG                  = -2
+	IMAGE_SYM_TYPE_NULL              = 0
+	IMAGE_SYM_TYPE_VOID              = 1
+	IMAGE_SYM_TYPE_CHAR              = 2
+	IMAGE_SYM_TYPE_SHORT             = 3
+	IMAGE_SYM_TYPE_INT               = 4
+	IMAGE_SYM_TYPE_LONG              = 5
+	IMAGE_SYM_TYPE_FLOAT             = 6
+	IMAGE_SYM_TYPE_DOUBLE            = 7
+	IMAGE_SYM_TYPE_STRUCT            = 8
+	IMAGE_SYM_TYPE_UNION             = 9
+	IMAGE_SYM_TYPE_ENUM              = 10
+	IMAGE_SYM_TYPE_MOE               = 11
+	IMAGE_SYM_TYPE_BYTE              = 12
+	IMAGE_SYM_TYPE_WORD              = 13
+	IMAGE_SYM_TYPE_UINT              = 14
+	IMAGE_SYM_TYPE_DWORD             = 15
+	IMAGE_SYM_TYPE_PCODE             = 32768
+	IMAGE_SYM_DTYPE_NULL             = 0
+	IMAGE_SYM_DTYPE_POINTER          = 0x10
+	IMAGE_SYM_DTYPE_FUNCTION         = 0x20
+	IMAGE_SYM_DTYPE_ARRAY            = 0x30
+	IMAGE_SYM_CLASS_END_OF_FUNCTION  = -1
+	IMAGE_SYM_CLASS_NULL             = 0
+	IMAGE_SYM_CLASS_AUTOMATIC        = 1
+	IMAGE_SYM_CLASS_EXTERNAL         = 2
+	IMAGE_SYM_CLASS_STATIC           = 3
+	IMAGE_SYM_CLASS_REGISTER         = 4
+	IMAGE_SYM_CLASS_EXTERNAL_DEF     = 5
+	IMAGE_SYM_CLASS_LABEL            = 6
+	IMAGE_SYM_CLASS_UNDEFINED_LABEL  = 7
+	IMAGE_SYM_CLASS_MEMBER_OF_STRUCT = 8
+	IMAGE_SYM_CLASS_ARGUMENT         = 9
+	IMAGE_SYM_CLASS_STRUCT_TAG       = 10
+	IMAGE_SYM_CLASS_MEMBER_OF_UNION  = 11
+	IMAGE_SYM_CLASS_UNION_TAG        = 12
+	IMAGE_SYM_CLASS_TYPE_DEFINITION  = 13
+	IMAGE_SYM_CLASS_UNDEFINED_STATIC = 14
+	IMAGE_SYM_CLASS_ENUM_TAG         = 15
+	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 /* Not in PECOFF v8 spec */
+	IMAGE_SYM_CLASS_BLOCK            = 100
+	IMAGE_SYM_CLASS_FUNCTION         = 101
+	IMAGE_SYM_CLASS_END_OF_STRUCT    = 102
+	IMAGE_SYM_CLASS_FILE             = 103
+	IMAGE_SYM_CLASS_SECTION          = 104
+	IMAGE_SYM_CLASS_WEAK_EXTERNAL    = 105
+	IMAGE_SYM_CLASS_CLR_TOKEN        = 107
+	IMAGE_REL_I386_ABSOLUTE          = 0x0000
+	IMAGE_REL_I386_DIR16             = 0x0001
+	IMAGE_REL_I386_REL16             = 0x0002
+	IMAGE_REL_I386_DIR32             = 0x0006
+	IMAGE_REL_I386_DIR32NB           = 0x0007
+	IMAGE_REL_I386_SEG12             = 0x0009
+	IMAGE_REL_I386_SECTION           = 0x000A
+	IMAGE_REL_I386_SECREL            = 0x000B
+	IMAGE_REL_I386_TOKEN             = 0x000C
+	IMAGE_REL_I386_SECREL7           = 0x000D
+	IMAGE_REL_I386_REL32             = 0x0014
+	IMAGE_REL_AMD64_ABSOLUTE         = 0x0000
+	IMAGE_REL_AMD64_ADDR64           = 0x0001
+	IMAGE_REL_AMD64_ADDR32           = 0x0002
+	IMAGE_REL_AMD64_ADDR32NB         = 0x0003
+	IMAGE_REL_AMD64_REL32            = 0x0004
+	IMAGE_REL_AMD64_REL32_1          = 0x0005
+	IMAGE_REL_AMD64_REL32_2          = 0x0006
+	IMAGE_REL_AMD64_REL32_3          = 0x0007
+	IMAGE_REL_AMD64_REL32_4          = 0x0008
+	IMAGE_REL_AMD64_REL32_5          = 0x0009
+	IMAGE_REL_AMD64_SECTION          = 0x000A
+	IMAGE_REL_AMD64_SECREL           = 0x000B
+	IMAGE_REL_AMD64_SECREL7          = 0x000C
+	IMAGE_REL_AMD64_TOKEN            = 0x000D
+	IMAGE_REL_AMD64_SREL32           = 0x000E
+	IMAGE_REL_AMD64_PAIR             = 0x000F
+	IMAGE_REL_AMD64_SSPAN32          = 0x0010
+)
+
+type PeSym struct {
+	name    string
+	value   uint32
+	sectnum uint16
+	type_   uint16
+	sclass  uint8
+	aux     uint8
+	sym     *LSym
+}
+
+type PeSect struct {
+	name string
+	base []byte
+	size uint64
+	sym  *LSym
+	sh   IMAGE_SECTION_HEADER
+}
+
+type PeObj struct {
+	f      *obj.Biobuf
+	name   string
+	base   uint32
+	sect   []PeSect
+	nsect  uint
+	pesym  []PeSym
+	npesym uint
+	fh     IMAGE_FILE_HEADER
+	snames []byte
+}
+
+func ldpe(f *obj.Biobuf, pkg string, length int64, pn string) {
+	if Debug['v'] != 0 {
+		fmt.Fprintf(&Bso, "%5.2f ldpe %s\n", obj.Cputime(), pn)
+	}
+
+	var sect *PeSect
+	Ctxt.Version++
+	base := int32(obj.Boffset(f))
+
+	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
+	}
+
+	// load section list
+	peobj.sect = make([]PeSect, peobj.fh.NumberOfSections)
+
+	peobj.nsect = uint(peobj.fh.NumberOfSections)
+	for i := 0; i < int(peobj.fh.NumberOfSections); i++ {
+		if err = binary.Read(f, binary.LittleEndian, &peobj.sect[i].sh); err != nil {
+			goto bad
+		}
+		peobj.sect[i].size = uint64(peobj.sect[i].sh.SizeOfRawData)
+		peobj.sect[i].name = cstring(peobj.sect[i].sh.Name[:])
+	}
+
+	// TODO return error if found .cormeta
+
+	// load string table
+	obj.Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(peobj.fh.NumberOfSymbols), 0)
+
+	if obj.Bread(f, symbuf[:4]) != 4 {
+		goto bad
+	}
+	l = Le32(symbuf[:])
+	peobj.snames = make([]byte, l)
+	obj.Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(peobj.fh.NumberOfSymbols), 0)
+	if obj.Bread(f, peobj.snames) != len(peobj.snames) {
+		goto bad
+	}
+
+	// rewrite section names if they start with /
+	for i := 0; i < int(peobj.fh.NumberOfSections); i++ {
+		if peobj.sect[i].name == "" {
+			continue
+		}
+		if peobj.sect[i].name[0] != '/' {
+			continue
+		}
+		l = uint32(obj.Atoi(peobj.sect[i].name[1:]))
+		peobj.sect[i].name = cstring(peobj.snames[l:])
+	}
+
+	// read symbols
+	peobj.pesym = make([]PeSym, peobj.fh.NumberOfSymbols)
+
+	peobj.npesym = uint(peobj.fh.NumberOfSymbols)
+	obj.Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable), 0)
+	for i := 0; uint32(i) < peobj.fh.NumberOfSymbols; i += numaux + 1 {
+		obj.Bseek(f, int64(base)+int64(peobj.fh.PointerToSymbolTable)+int64(len(symbuf))*int64(i), 0)
+		if obj.Bread(f, symbuf[:]) != len(symbuf) {
+			goto bad
+		}
+
+		if (symbuf[0] == 0) && (symbuf[1] == 0) && (symbuf[2] == 0) && (symbuf[3] == 0) {
+			l = Le32(symbuf[4:])
+			peobj.pesym[i].name = cstring(peobj.snames[l:]) // sym name length <= 8
+		} else {
+			peobj.pesym[i].name = cstring(symbuf[:8])
+		}
+
+		peobj.pesym[i].value = Le32(symbuf[8:])
+		peobj.pesym[i].sectnum = Le16(symbuf[12:])
+		peobj.pesym[i].sclass = symbuf[16]
+		peobj.pesym[i].aux = symbuf[17]
+		peobj.pesym[i].type_ = Le16(symbuf[14:])
+		numaux = int(peobj.pesym[i].aux)
+		if numaux < 0 {
+			numaux = 0
+		}
+	}
+
+	// create symbols for mapped sections
+	for i := 0; uint(i) < peobj.nsect; i++ {
+		sect = &peobj.sect[i]
+		if sect.sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE != 0 {
+			continue
+		}
+
+		if sect.sh.Characteristics&(IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_CNT_UNINITIALIZED_DATA) == 0 {
+			// This has been seen for .idata sections, which we
+			// want to ignore.  See issues 5106 and 5273.
+			continue
+		}
+
+		if pemap(peobj, sect) < 0 {
+			goto bad
+		}
+
+		name = fmt.Sprintf("%s(%s)", pkg, sect.name)
+		s = Linklookup(Ctxt, name, Ctxt.Version)
+
+		switch sect.sh.Characteristics & (IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE) {
+		case IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ: //.rdata
+			s.Type = obj.SRODATA
+
+		case IMAGE_SCN_CNT_UNINITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE: //.bss
+			s.Type = obj.SNOPTRBSS
+
+		case IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE: //.data
+			s.Type = obj.SNOPTRDATA
+
+		case IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ: //.text
+			s.Type = obj.STEXT
+
+		default:
+			err = fmt.Errorf("unexpected flags %#06x for PE section %s", sect.sh.Characteristics, sect.name)
+			goto bad
+		}
+
+		s.P = sect.base
+		s.P = s.P[:sect.size]
+		s.Size = int64(sect.size)
+		sect.sym = s
+		if sect.name == ".rsrc" {
+			setpersrc(sect.sym)
+		}
+	}
+
+	// load relocations
+	for i := 0; uint(i) < peobj.nsect; i++ {
+		rsect = &peobj.sect[i]
+		if rsect.sym == nil || rsect.sh.NumberOfRelocations == 0 {
+			continue
+		}
+		if rsect.sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE != 0 {
+			continue
+		}
+		if sect.sh.Characteristics&(IMAGE_SCN_CNT_CODE|IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_CNT_UNINITIALIZED_DATA) == 0 {
+			// This has been seen for .idata sections, which we
+			// want to ignore.  See issues 5106 and 5273.
+			continue
+		}
+
+		r = make([]Reloc, rsect.sh.NumberOfRelocations)
+		obj.Bseek(f, int64(peobj.base)+int64(rsect.sh.PointerToRelocations), 0)
+		for j = 0; j < int(rsect.sh.NumberOfRelocations); j++ {
+			rp = &r[j]
+			if obj.Bread(f, symbuf[:10]) != 10 {
+				goto bad
+			}
+			rva := Le32(symbuf[0:])
+			symindex := Le32(symbuf[4:])
+			type_ := Le16(symbuf[8:])
+			if err = readpesym(peobj, int(symindex), &sym); err != nil {
+				goto bad
+			}
+			if sym.sym == nil {
+				err = fmt.Errorf("reloc of invalid sym %s idx=%d type=%d", sym.name, symindex, sym.type_)
+				goto bad
+			}
+
+			rp.Sym = sym.sym
+			rp.Siz = 4
+			rp.Off = int32(rva)
+			switch type_ {
+			default:
+				Diag("%s: unknown relocation type %d;", pn, type_)
+				fallthrough
+
+			case IMAGE_REL_I386_REL32, IMAGE_REL_AMD64_REL32,
+				IMAGE_REL_AMD64_ADDR32, // R_X86_64_PC32
+				IMAGE_REL_AMD64_ADDR32NB:
+				rp.Type = obj.R_PCREL
+
+				rp.Add = int64(int32(Le32(rsect.base[rp.Off:])))
+
+			case IMAGE_REL_I386_DIR32NB, IMAGE_REL_I386_DIR32:
+				rp.Type = obj.R_ADDR
+
+				// load addend from image
+				rp.Add = int64(int32(Le32(rsect.base[rp.Off:])))
+
+			case IMAGE_REL_AMD64_ADDR64: // R_X86_64_64
+				rp.Siz = 8
+
+				rp.Type = obj.R_ADDR
+
+				// load addend from image
+				rp.Add = int64(Le64(rsect.base[rp.Off:]))
+			}
+
+			// ld -r could generate multiple section symbols for the
+			// same section but with different values, we have to take
+			// that into account
+			if issect(&peobj.pesym[symindex]) {
+				rp.Add += int64(peobj.pesym[symindex].value)
+			}
+		}
+
+		sort.Sort(rbyoff(r[:rsect.sh.NumberOfRelocations]))
+
+		s = rsect.sym
+		s.R = r
+		s.R = s.R[:rsect.sh.NumberOfRelocations]
+	}
+
+	// enter sub-symbols into symbol table.
+	for i := 0; uint(i) < peobj.npesym; i++ {
+		if peobj.pesym[i].name == "" {
+			continue
+		}
+		if issect(&peobj.pesym[i]) {
+			continue
+		}
+		if uint(peobj.pesym[i].sectnum) > peobj.nsect {
+			continue
+		}
+		if peobj.pesym[i].sectnum > 0 {
+			sect = &peobj.sect[peobj.pesym[i].sectnum-1]
+			if sect.sym == nil {
+				continue
+			}
+		}
+
+		if err = readpesym(peobj, i, &sym); err != nil {
+			goto bad
+		}
+
+		s = sym.sym
+		if sym.sectnum == 0 { // extern
+			if s.Type == obj.SDYNIMPORT {
+				s.Plt = -2 // flag for dynimport in PE object files.
+			}
+			if s.Type == obj.SXREF && sym.value > 0 { // global data
+				s.Type = obj.SNOPTRDATA
+				s.Size = int64(sym.value)
+			}
+
+			continue
+		} else if sym.sectnum > 0 && uint(sym.sectnum) <= peobj.nsect {
+			sect = &peobj.sect[sym.sectnum-1]
+			if sect.sym == nil {
+				Diag("%s: %s sym == 0!", pn, s.Name)
+			}
+		} else {
+			Diag("%s: %s sectnum < 0!", pn, s.Name)
+		}
+
+		if sect == nil {
+			return
+		}
+
+		if s.Outer != nil {
+			if s.Dupok != 0 {
+				continue
+			}
+			Exitf("%s: duplicate symbol reference: %s in both %s and %s", pn, s.Name, s.Outer.Name, sect.sym.Name)
+		}
+
+		s.Sub = sect.sym.Sub
+		sect.sym.Sub = s
+		s.Type = sect.sym.Type | obj.SSUB
+		s.Value = int64(sym.value)
+		s.Size = 4
+		s.Outer = sect.sym
+		if sect.sym.Type == obj.STEXT {
+			if s.External != 0 && s.Dupok == 0 {
+				Diag("%s: duplicate definition of %s", pn, s.Name)
+			}
+			s.External = 1
+		}
+	}
+
+	// Sort outer lists by address, adding to textp.
+	// This keeps textp in increasing address order.
+	for i := 0; uint(i) < peobj.nsect; i++ {
+		s = peobj.sect[i].sym
+		if s == nil {
+			continue
+		}
+		if s.Sub != nil {
+			s.Sub = listsort(s.Sub, valuecmp, listsubp)
+		}
+		if s.Type == obj.STEXT {
+			if s.Onlist != 0 {
+				log.Fatalf("symbol %s listed multiple times", s.Name)
+			}
+			s.Onlist = 1
+			if Ctxt.Etextp != nil {
+				Ctxt.Etextp.Next = s
+			} else {
+				Ctxt.Textp = s
+			}
+			Ctxt.Etextp = s
+			for s = s.Sub; s != nil; s = s.Sub {
+				if s.Onlist != 0 {
+					log.Fatalf("symbol %s listed multiple times", s.Name)
+				}
+				s.Onlist = 1
+				Ctxt.Etextp.Next = s
+				Ctxt.Etextp = s
+			}
+		}
+	}
+
+	return
+
+bad:
+	Diag("%s: malformed pe file: %v", pn, err)
+}
+
+func pemap(peobj *PeObj, sect *PeSect) int {
+	if sect.base != nil {
+		return 0
+	}
+
+	sect.base = make([]byte, sect.sh.SizeOfRawData)
+	if sect.sh.PointerToRawData == 0 { // .bss doesn't have data in object file
+		return 0
+	}
+	if obj.Bseek(peobj.f, int64(peobj.base)+int64(sect.sh.PointerToRawData), 0) < 0 || obj.Bread(peobj.f, sect.base) != len(sect.base) {
+		return -1
+	}
+
+	return 0
+}
+
+func issect(s *PeSym) bool {
+	return s.sclass == IMAGE_SYM_CLASS_STATIC && s.type_ == 0 && s.name[0] == '.'
+}
+
+func readpesym(peobj *PeObj, i int, y **PeSym) (err error) {
+	if uint(i) >= peobj.npesym || i < 0 {
+		err = fmt.Errorf("invalid pe symbol index")
+		return err
+	}
+
+	sym := &peobj.pesym[i]
+	*y = sym
+
+	var name string
+	if issect(sym) {
+		name = peobj.sect[sym.sectnum-1].sym.Name
+	} else {
+		name = sym.name
+		if strings.HasPrefix(name, "__imp_") {
+			name = name[6:] // __imp_Name => Name
+		}
+		if Thearch.Thechar == '8' && name[0] == '_' {
+			name = name[1:] // _Name => Name
+		}
+	}
+
+	// remove last @XXX
+	if i := strings.LastIndex(name, "@"); i >= 0 {
+		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:
+		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:
+			s = Linklookup(Ctxt, name, Ctxt.Version)
+			s.Dupok = 1
+
+		default:
+			err = fmt.Errorf("%s: invalid symbol binding %d", sym.name, sym.sclass)
+			return err
+		}
+	}
+
+	if s != nil && s.Type == 0 && (sym.sclass != IMAGE_SYM_CLASS_STATIC || sym.value != 0) {
+		s.Type = obj.SXREF
+	}
+	if strings.HasPrefix(sym.name, "__imp_") {
+		s.Got = -2 // flag for __imp_
+	}
+	sym.sym = s
+
+	return nil
+}
diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go
new file mode 100644
index 0000000..8ccbec9
--- /dev/null
+++ b/src/cmd/link/internal/ld/lib.go
@@ -0,0 +1,2049 @@
+// 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 at 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 at 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 ld
+
+import (
+	"bufio"
+	"bytes"
+	"cmd/internal/obj"
+	"crypto/sha1"
+	"debug/elf"
+	"encoding/binary"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"log"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"runtime"
+	"strings"
+)
+
+// Data layout and relocation.
+
+// Derived from Inferno utils/6l/l.h
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/l.h
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
+
+type Arch struct {
+	Thechar          int
+	Ptrsize          int
+	Intsize          int
+	Regsize          int
+	Funcalign        int
+	Maxalign         int
+	Minlc            int
+	Dwarfregsp       int
+	Dwarfreglr       int
+	Linuxdynld       string
+	Freebsddynld     string
+	Netbsddynld      string
+	Openbsddynld     string
+	Dragonflydynld   string
+	Solarisdynld     string
+	Adddynrel        func(*LSym, *Reloc)
+	Archinit         func()
+	Archreloc        func(*Reloc, *LSym, *int64) int
+	Archrelocvariant func(*Reloc, *LSym, int64) int64
+	Asmb             func()
+	Elfreloc1        func(*Reloc, int64) int
+	Elfsetupplt      func()
+	Gentext          func()
+	Machoreloc1      func(*Reloc, int64) int
+	PEreloc1         func(*Reloc, int64) bool
+	Lput             func(uint32)
+	Wput             func(uint16)
+	Vput             func(uint64)
+}
+
+type Rpath struct {
+	set bool
+	val string
+}
+
+func (r *Rpath) Set(val string) error {
+	r.set = true
+	r.val = val
+	return nil
+}
+
+func (r *Rpath) String() string {
+	return r.val
+}
+
+var (
+	Thearch Arch
+	datap   *LSym
+	Debug   [128]int
+	Lcsize  int32
+	rpath   Rpath
+	Spsize  int32
+	Symsize int32
+)
+
+// Terrible but standard terminology.
+// A segment describes a block of file to load into memory.
+// A section further describes the pieces of that block for
+// use in debuggers and such.
+
+const (
+	MAXIO   = 8192
+	MINFUNC = 16 // minimum size for a function
+)
+
+type Segment struct {
+	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
+}
+
+type Section struct {
+	Rwx     uint8
+	Extnum  int16
+	Align   int32
+	Name    string
+	Vaddr   uint64
+	Length  uint64
+	Next    *Section
+	Seg     *Segment
+	Elfsect *ElfShdr
+	Reloff  uint64
+	Rellen  uint64
+}
+
+// DynlinkingGo returns whether we are producing Go code that can live
+// in separate shared libraries linked together at runtime.
+func DynlinkingGo() bool {
+	return Buildmode == BuildmodeShared || Linkshared
+}
+
+var (
+	Thestring          string
+	Thelinkarch        *LinkArch
+	outfile            string
+	dynexp             []*LSym
+	dynlib             []string
+	ldflag             []string
+	havedynamic        int
+	Funcalign          int
+	iscgo              bool
+	elfglobalsymndx    int
+	flag_installsuffix string
+	flag_race          int
+	Buildmode          BuildMode
+	Linkshared         bool
+	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 (
+	CgoExportDynamic = 1 << 0
+	CgoExportStatic  = 1 << 1
+)
+
+var (
+	Segtext   Segment
+	Segrodata Segment
+	Segdata   Segment
+	Segdwarf  Segment
+)
+
+/* set by call to mywhatsys() */
+
+/* whence for ldpkg */
+const (
+	FileObj = 0 + iota
+	ArchiveObj
+	Pkgdef
+)
+
+var (
+	headstring string
+	// buffered output
+	Bso obj.Biobuf
+)
+
+var coutbuf struct {
+	*bufio.Writer
+	f *os.File
+}
+
+const (
+	// Whether to assume that the external linker is "gold"
+	// (http://sourceware.org/ml/binutils/2008-03/msg00162.html).
+	AssumeGoldLinker = 0
+)
+
+const (
+	symname = "__.GOSYMDEF"
+	pkgname = "__.PKGDEF"
+)
+
+var (
+	// 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)
+}
+
+// A BuildMode indicates the sort of object we are building:
+//   "exe": build a main package and everything it imports into an executable.
+//   "c-shared": build a main package, plus all packages that it imports, into a
+//     single C shared library. The only callable symbols will be those functions
+//     marked as exported.
+//   "shared": combine all packages passed on the command line, and their
+//     dependencies, into a single shared library that will be used when
+//     building with the -linkshared option.
+type BuildMode uint8
+
+const (
+	BuildmodeUnset BuildMode = iota
+	BuildmodeExe
+	BuildmodeCArchive
+	BuildmodeCShared
+	BuildmodeShared
+)
+
+func (mode *BuildMode) Set(s string) error {
+	goos := obj.Getgoos()
+	goarch := obj.Getgoarch()
+	badmode := func() error {
+		return fmt.Errorf("buildmode %s not supported on %s/%s", s, goos, goarch)
+	}
+	switch s {
+	default:
+		return fmt.Errorf("invalid buildmode: %q", s)
+	case "exe":
+		*mode = BuildmodeExe
+	case "c-archive":
+		switch goos {
+		case "darwin", "linux":
+		default:
+			return badmode()
+		}
+		*mode = BuildmodeCArchive
+	case "c-shared":
+		if goarch != "amd64" && goarch != "arm" {
+			return badmode()
+		}
+		*mode = BuildmodeCShared
+	case "shared":
+		if goos != "linux" || goarch != "amd64" {
+			return badmode()
+		}
+		*mode = BuildmodeShared
+	}
+	return nil
+}
+
+func (mode *BuildMode) String() string {
+	switch *mode {
+	case BuildmodeUnset:
+		return "" // avoid showing a default in usage message
+	case BuildmodeExe:
+		return "exe"
+	case BuildmodeCArchive:
+		return "c-archive"
+	case BuildmodeCShared:
+		return "c-shared"
+	case BuildmodeShared:
+		return "shared"
+	}
+	return fmt.Sprintf("BuildMode(%d)", uint8(*mode))
+}
+
+/*
+ * Unix doesn't like it when we write to a running (or, sometimes,
+ * recently run) binary, so remove the output file before writing it.
+ * On Windows 7, remove() can force a subsequent create() to fail.
+ * S_ISREG() does not exist on Plan 9.
+ */
+func mayberemoveoutfile() {
+	if fi, err := os.Lstat(outfile); err == nil && !fi.Mode().IsRegular() {
+		return
+	}
+	os.Remove(outfile)
+}
+
+func libinit() {
+	Funcalign = Thearch.Funcalign
+	mywhatsys() // get goroot, goarch, goos
+
+	// add goroot to the end of the libdir list.
+	suffix := ""
+
+	suffixsep := ""
+	if flag_installsuffix != "" {
+		suffixsep = "_"
+		suffix = flag_installsuffix
+	} else if flag_race != 0 {
+		suffixsep = "_"
+		suffix = "race"
+	}
+
+	Lflag(fmt.Sprintf("%s/pkg/%s_%s%s%s", goroot, goos, goarch, suffixsep, suffix))
+
+	mayberemoveoutfile()
+	f, err := os.OpenFile(outfile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0775)
+	if err != nil {
+		Exitf("cannot create %s: %v", outfile, err)
+	}
+
+	coutbuf.Writer = bufio.NewWriter(f)
+	coutbuf.f = f
+
+	if INITENTRY == "" {
+		switch Buildmode {
+		case BuildmodeCShared, BuildmodeCArchive:
+			INITENTRY = fmt.Sprintf("_rt0_%s_%s_lib", goarch, goos)
+		case BuildmodeExe:
+			INITENTRY = fmt.Sprintf("_rt0_%s_%s", goarch, goos)
+		case BuildmodeShared:
+			// No INITENTRY for -buildmode=shared
+		default:
+			Diag("unknown INITENTRY for buildmode %v", Buildmode)
+		}
+	}
+
+	if !DynlinkingGo() {
+		Linklookup(Ctxt, INITENTRY, 0).Type = obj.SXREF
+	}
+}
+
+func Exitf(format string, a ...interface{}) {
+	fmt.Fprintf(os.Stderr, os.Args[0]+": "+format+"\n", a...)
+	if coutbuf.f != nil {
+		coutbuf.f.Close()
+		mayberemoveoutfile()
+	}
+	Exit(2)
+}
+
+func errorexit() {
+	if coutbuf.f != nil {
+		if nerrors != 0 {
+			Cflush()
+		}
+		// For rmtemp run at atexit time on Windows.
+		if err := coutbuf.f.Close(); err != nil {
+			Exitf("close: %v", err)
+		}
+	}
+
+	if nerrors != 0 {
+		if coutbuf.f != nil {
+			mayberemoveoutfile()
+		}
+		Exit(2)
+	}
+
+	Exit(0)
+}
+
+func loadinternal(name string) {
+	found := 0
+	for i := 0; i < len(Ctxt.Libdir); i++ {
+		if Linkshared {
+			shlibname := fmt.Sprintf("%s/%s.shlibname", Ctxt.Libdir[i], name)
+			if Debug['v'] != 0 {
+				fmt.Fprintf(&Bso, "searching for %s.a in %s\n", name, shlibname)
+			}
+			if obj.Access(shlibname, obj.AEXIST) >= 0 {
+				addlibpath(Ctxt, "internal", "internal", "", name, shlibname)
+				found = 1
+				break
+			}
+		}
+		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)
+		}
+		if obj.Access(pname, obj.AEXIST) >= 0 {
+			addlibpath(Ctxt, "internal", "internal", pname, name, "")
+			found = 1
+			break
+		}
+	}
+
+	if found == 0 {
+		fmt.Fprintf(&Bso, "warning: unable to find %s.a\n", name)
+	}
+}
+
+func loadlib() {
+	switch Buildmode {
+	case BuildmodeCShared:
+		s := Linklookup(Ctxt, "runtime.islibrary", 0)
+		s.Dupok = 1
+		Adduint8(Ctxt, s, 1)
+	case BuildmodeCArchive:
+		s := Linklookup(Ctxt, "runtime.isarchive", 0)
+		s.Dupok = 1
+		Adduint8(Ctxt, s, 1)
+	}
+
+	loadinternal("runtime")
+	if Thearch.Thechar == '5' {
+		loadinternal("math")
+	}
+	if flag_race != 0 {
+		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)
+		}
+		iscgo = iscgo || Ctxt.Library[i].Pkg == "runtime/cgo"
+		if Ctxt.Library[i].Shlib != "" {
+			ldshlibsyms(Ctxt.Library[i].Shlib)
+		} else {
+			objfile(Ctxt.Library[i])
+		}
+	}
+
+	if Linkmode == LinkAuto {
+		if iscgo && externalobj {
+			Linkmode = LinkExternal
+		} else {
+			Linkmode = LinkInternal
+		}
+
+		// Force external linking for android.
+		if goos == "android" {
+			Linkmode = LinkExternal
+		}
+
+		// cgo on Darwin must use external linking
+		// we can always use external linking, but then there will be circular
+		// dependency problems when compiling natively (external linking requires
+		// runtime/cgo, runtime/cgo requires cmd/cgo, but cmd/cgo needs to be
+		// compiled using external linking.)
+		if (Thearch.Thechar == '5' || Thearch.Thechar == '7') && HEADTYPE == obj.Hdarwin && iscgo {
+			Linkmode = LinkExternal
+		}
+	}
+
+	// cmd/7l doesn't support cgo internal linking
+	// This is https://golang.org/issue/10373.
+	if iscgo && goarch == "arm64" {
+		Linkmode = LinkExternal
+	}
+
+	if Linkmode == LinkExternal && !iscgo {
+		// This indicates a user requested -linkmode=external.
+		// The startup code uses an import of runtime/cgo to decide
+		// whether to initialize the TLS.  So give it one.  This could
+		// be handled differently but it's an unusual case.
+		loadinternal("runtime/cgo")
+
+		if i < len(Ctxt.Library) {
+			if Ctxt.Library[i].Shlib != "" {
+				ldshlibsyms(Ctxt.Library[i].Shlib)
+			} else {
+				if DynlinkingGo() {
+					Exitf("cannot implicitly include runtime/cgo in a shared library")
+				}
+				objfile(Ctxt.Library[i])
+			}
+		}
+	}
+
+	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 {
+			if s.Type == obj.SHOSTOBJ {
+				// If a symbol was marked both
+				// cgo_import_static and cgo_import_dynamic,
+				// then we want to make it cgo_import_dynamic
+				// now.
+				if s.Extname != "" && s.Dynimplib != "" && s.Cgoexport == 0 {
+					s.Type = obj.SDYNIMPORT
+				} else {
+					s.Type = 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
+	// to be a real variable.
+	//
+	// TODO(crawshaw): android should require leaving the tlsg->type
+	// alone (as the runtime-provided SNOPTRBSS) just like darwin/arm.
+	// But some other part of the linker is expecting STLSBSS.
+	if tlsg.Type != obj.SDYNIMPORT && (goos != "darwin" || Thearch.Thechar != '5') {
+		tlsg.Type = obj.STLSBSS
+	}
+	tlsg.Size = int64(Thearch.Ptrsize)
+	tlsg.Reachable = true
+	Ctxt.Tlsg = tlsg
+
+	// Now that we know the link mode, trim the dynexp list.
+	x := CgoExportDynamic
+
+	if Linkmode == LinkExternal {
+		x = CgoExportStatic
+	}
+	w := 0
+	for i := 0; i < len(dynexp); i++ {
+		if int(dynexp[i].Cgoexport)&x != 0 {
+			dynexp[w] = dynexp[i]
+			w++
+		}
+	}
+	dynexp = dynexp[:w]
+
+	// In internal link mode, read the host object files.
+	if Linkmode == LinkInternal {
+		hostobjs()
+	} else {
+		hostlinksetup()
+	}
+
+	// We've loaded all the code now.
+	// If there are no dynamic libraries needed, gcc disables dynamic linking.
+	// Because of this, glibc's dynamic ELF loader occasionally (like in version 2.13)
+	// assumes that a dynamic binary always refers to at least one dynamic library.
+	// Rather than be a source of test cases for glibc, disable dynamic linking
+	// the same way that gcc would.
+	//
+	// Exception: on OS X, programs such as Shark only work with dynamic
+	// binaries, so leave it enabled on OS X (Mach-O) binaries.
+	// Also leave it enabled on Solaris which doesn't support
+	// statically linked binaries.
+	if Buildmode == BuildmodeExe && havedynamic == 0 && HEADTYPE != obj.Hdarwin && HEADTYPE != obj.Hsolaris {
+		Debug['d'] = 1
+	}
+
+	importcycles()
+}
+
+/*
+ * look for the next file in an archive.
+ * adapted from libmach.
+ */
+func nextar(bp *obj.Biobuf, off int64, a *ArHdr) int64 {
+	if off&1 != 0 {
+		off++
+	}
+	obj.Bseek(bp, off, 0)
+	buf := make([]byte, SAR_HDR)
+	if n := obj.Bread(bp, buf); n < len(buf) {
+		if n >= 0 {
+			return 0
+		}
+		return -1
+	}
+
+	a.name = artrim(buf[0:16])
+	a.date = artrim(buf[16:28])
+	a.uid = artrim(buf[28:34])
+	a.gid = artrim(buf[34:40])
+	a.mode = artrim(buf[40:48])
+	a.size = artrim(buf[48:58])
+	a.fmag = artrim(buf[58:60])
+
+	arsize := atolwhex(a.size)
+	if arsize&1 != 0 {
+		arsize++
+	}
+	return int64(arsize) + SAR_HDR
+}
+
+func objfile(lib *Library) {
+	pkg := pathtoprefix(lib.Pkg)
+
+	if Debug['v'] > 1 {
+		fmt.Fprintf(&Bso, "%5.2f ldobj: %s (%s)\n", obj.Cputime(), lib.File, pkg)
+	}
+	Bso.Flush()
+	var err error
+	var f *obj.Biobuf
+	f, err = obj.Bopenr(lib.File)
+	if err != nil {
+		Exitf("cannot open file %s: %v", lib.File, err)
+	}
+
+	magbuf := make([]byte, len(ARMAG))
+	if obj.Bread(f, magbuf) != len(magbuf) || !strings.HasPrefix(string(magbuf), ARMAG) {
+		/* load it as a regular file */
+		l := obj.Bseek(f, 0, 2)
+
+		obj.Bseek(f, 0, 0)
+		ldobj(f, pkg, l, lib.File, lib.File, FileObj)
+		obj.Bterm(f)
+
+		return
+	}
+
+	/* skip over optional __.GOSYMDEF and process __.PKGDEF */
+	off := obj.Boffset(f)
+
+	var arhdr ArHdr
+	l := nextar(f, off, &arhdr)
+	var pname string
+	if l <= 0 {
+		Diag("%s: short read on archive file symbol header", lib.File)
+		goto out
+	}
+
+	if strings.HasPrefix(arhdr.name, symname) {
+		off += l
+		l = nextar(f, off, &arhdr)
+		if l <= 0 {
+			Diag("%s: short read on archive file symbol header", lib.File)
+			goto out
+		}
+	}
+
+	if !strings.HasPrefix(arhdr.name, pkgname) {
+		Diag("%s: cannot find package header", lib.File)
+		goto out
+	}
+
+	if Buildmode == BuildmodeShared {
+		before := obj.Boffset(f)
+		pkgdefBytes := make([]byte, atolwhex(arhdr.size))
+		obj.Bread(f, pkgdefBytes)
+		hash := sha1.Sum(pkgdefBytes)
+		lib.hash = hash[:]
+		obj.Bseek(f, before, 0)
+	}
+
+	off += l
+
+	if Debug['u'] != 0 {
+		ldpkg(f, pkg, atolwhex(arhdr.size), lib.File, Pkgdef)
+	}
+
+	/*
+	 * load all the object files from the archive now.
+	 * this gives us sequential file access and keeps us
+	 * from needing to come back later to pick up more
+	 * objects.  it breaks the usual C archive model, but
+	 * this is Go, not C.  the common case in Go is that
+	 * we need to load all the objects, and then we throw away
+	 * the individual symbols that are unused.
+	 *
+	 * loading every object will also make it possible to
+	 * load foreign objects not referenced by __.GOSYMDEF.
+	 */
+	for {
+		l = nextar(f, off, &arhdr)
+		if l == 0 {
+			break
+		}
+		if l < 0 {
+			Exitf("%s: malformed archive", lib.File)
+		}
+
+		off += l
+
+		pname = fmt.Sprintf("%s(%s)", lib.File, arhdr.name)
+		l = atolwhex(arhdr.size)
+		ldobj(f, pkg, l, pname, lib.File, ArchiveObj)
+	}
+
+out:
+	obj.Bterm(f)
+}
+
+type Hostobj struct {
+	ld     func(*obj.Biobuf, string, int64, string)
+	pkg    string
+	pn     string
+	file   string
+	off    int64
+	length int64
+}
+
+var hostobj []Hostobj
+
+// These packages can use internal linking mode.
+// Others trigger external mode.
+var internalpkg = []string{
+	"crypto/x509",
+	"net",
+	"os/user",
+	"runtime/cgo",
+	"runtime/race",
+}
+
+func ldhostobj(ld func(*obj.Biobuf, string, int64, string), f *obj.Biobuf, pkg string, length int64, pn string, file string) {
+	isinternal := false
+	for i := 0; i < len(internalpkg); i++ {
+		if pkg == internalpkg[i] {
+			isinternal = true
+			break
+		}
+	}
+
+	// DragonFly declares errno with __thread, which results in a symbol
+	// type of R_386_TLS_GD or R_X86_64_TLSGD. The Go linker does not
+	// currently know how to handle TLS relocations, hence we have to
+	// force external linking for any libraries that link in code that
+	// uses errno. This can be removed if the Go linker ever supports
+	// these relocation types.
+	if HEADTYPE == obj.Hdragonfly {
+		if pkg == "net" || pkg == "os/user" {
+			isinternal = false
+		}
+	}
+
+	if !isinternal {
+		externalobj = true
+	}
+
+	hostobj = append(hostobj, Hostobj{})
+	h := &hostobj[len(hostobj)-1]
+	h.ld = ld
+	h.pkg = pkg
+	h.pn = pn
+	h.file = file
+	h.off = obj.Boffset(f)
+	h.length = length
+}
+
+func hostobjs() {
+	var f *obj.Biobuf
+	var h *Hostobj
+
+	for i := 0; i < len(hostobj); i++ {
+		h = &hostobj[i]
+		var err error
+		f, err = obj.Bopenr(h.file)
+		if f == nil {
+			Exitf("cannot reopen %s: %v", h.pn, err)
+		}
+
+		obj.Bseek(f, h.off, 0)
+		h.ld(f, h.pkg, h.length, h.pn)
+		obj.Bterm(f)
+	}
+}
+
+// provided by lib9
+
+func rmtemp() {
+	os.RemoveAll(tmpdir)
+}
+
+func hostlinksetup() {
+	if Linkmode != LinkExternal {
+		return
+	}
+
+	// For external link, record that we need to tell the external linker -s,
+	// and turn off -s internally: the external linker needs the symbol
+	// information for its final link.
+	debug_s = Debug['s']
+	Debug['s'] = 0
+
+	// create temporary directory and arrange cleanup
+	if tmpdir == "" {
+		dir, err := ioutil.TempDir("", "go-link-")
+		if err != nil {
+			log.Fatal(err)
+		}
+		tmpdir = dir
+		AtExit(rmtemp)
+	}
+
+	// change our output to temporary object file
+	coutbuf.f.Close()
+	mayberemoveoutfile()
+
+	p := fmt.Sprintf("%s/go.o", tmpdir)
+	var err error
+	f, err := os.OpenFile(p, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0775)
+	if err != nil {
+		Exitf("cannot create %s: %v", p, err)
+	}
+
+	coutbuf.Writer = bufio.NewWriter(f)
+	coutbuf.f = f
+}
+
+// hostobjCopy creates a copy of the object files in hostobj in a
+// temporary directory.
+func hostobjCopy() (paths []string) {
+	for i, h := range hostobj {
+		f, err := os.Open(h.file)
+		if err != nil {
+			Exitf("cannot reopen %s: %v", h.pn, err)
+		}
+		if _, err := f.Seek(h.off, 0); err != nil {
+			Exitf("cannot seek %s: %v", h.pn, err)
+		}
+
+		p := fmt.Sprintf("%s/%06d.o", tmpdir, i)
+		paths = append(paths, p)
+		w, err := os.Create(p)
+		if err != nil {
+			Exitf("cannot create %s: %v", p, err)
+		}
+		if _, err := io.CopyN(w, f, h.length); err != nil {
+			Exitf("cannot write %s: %v", p, err)
+		}
+		if err := w.Close(); err != nil {
+			Exitf("cannot close %s: %v", p, err)
+		}
+	}
+	return paths
+}
+
+// archive builds a .a archive from the hostobj object files.
+func archive() {
+	if Buildmode != BuildmodeCArchive {
+		return
+	}
+
+	mayberemoveoutfile()
+	argv := []string{"ar", "-q", "-c", "-s", outfile}
+	argv = append(argv, hostobjCopy()...)
+	argv = append(argv, fmt.Sprintf("%s/go.o", tmpdir))
+
+	if Debug['v'] != 0 {
+		fmt.Fprintf(&Bso, "archive: %s\n", strings.Join(argv, " "))
+		Bso.Flush()
+	}
+
+	if out, err := exec.Command(argv[0], argv[1:]...).CombinedOutput(); err != nil {
+		Exitf("running %s failed: %v\n%s", argv[0], err, out)
+	}
+}
+
+func hostlink() {
+	if Linkmode != LinkExternal || nerrors > 0 {
+		return
+	}
+	if Buildmode == BuildmodeCArchive {
+		return
+	}
+
+	if extld == "" {
+		extld = "gcc"
+	}
+
+	var argv []string
+	argv = append(argv, extld)
+	switch Thearch.Thechar {
+	case '8':
+		argv = append(argv, "-m32")
+
+	case '6', '9':
+		argv = append(argv, "-m64")
+
+	case '5':
+		argv = append(argv, "-marm")
+
+	case '7':
+		// nothing needed
+	}
+
+	if Debug['s'] == 0 && debug_s == 0 {
+		argv = append(argv, "-gdwarf-2")
+	} else {
+		argv = append(argv, "-s")
+	}
+
+	if HEADTYPE == obj.Hdarwin {
+		argv = append(argv, "-Wl,-no_pie,-headerpad,1144")
+	}
+	if HEADTYPE == obj.Hopenbsd {
+		argv = append(argv, "-Wl,-nopie")
+	}
+	if HEADTYPE == obj.Hwindows {
+		if headstring == "windowsgui" {
+			argv = append(argv, "-mwindows")
+		} else {
+			argv = append(argv, "-mconsole")
+		}
+	}
+
+	if Iself && AssumeGoldLinker != 0 /*TypeKind(100016)*/ {
+		argv = append(argv, "-Wl,--rosegment")
+	}
+
+	switch Buildmode {
+	case BuildmodeExe:
+		if HEADTYPE == obj.Hdarwin {
+			argv = append(argv, "-Wl,-pagezero_size,4000000")
+		}
+	case BuildmodeCShared:
+		if HEADTYPE == obj.Hdarwin {
+			argv = append(argv, "-dynamiclib")
+		} else {
+			argv = append(argv, "-Wl,-Bsymbolic")
+			argv = append(argv, "-shared")
+		}
+	case BuildmodeShared:
+		// TODO(mwhudson): unless you do this, dynamic relocations fill
+		// out the findfunctab table and for some reason shared libraries
+		// and the executable both define a main function and putting the
+		// address of executable's main into the shared libraries
+		// findfunctab violates the assumptions of the runtime.  TBH, I
+		// think we may well end up wanting to use -Bsymbolic here
+		// anyway.
+		argv = append(argv, "-Wl,-Bsymbolic-functions")
+		argv = append(argv, "-shared")
+	}
+
+	if Linkshared && Iself {
+		// We force all symbol resolution to be done at program startup
+		// because lazy PLT resolution can use large amounts of stack at
+		// times we cannot allow it to do so.
+		argv = append(argv, "-Wl,-znow")
+	}
+
+	if Iself && len(buildinfo) > 0 {
+		argv = append(argv, fmt.Sprintf("-Wl,--build-id=0x%x", buildinfo))
+	}
+
+	// On Windows, given -o foo, GCC will append ".exe" to produce
+	// "foo.exe".  We have decided that we want to honor the -o
+	// option.  To make this work, we append a '.' so that GCC
+	// will decide that the file already has an extension.  We
+	// only want to do this when producing a Windows output file
+	// on a Windows host.
+	outopt := outfile
+	if goos == "windows" && runtime.GOOS == "windows" && filepath.Ext(outopt) == "" {
+		outopt += "."
+	}
+	argv = append(argv, "-o")
+	argv = append(argv, outopt)
+
+	if rpath.val != "" {
+		argv = append(argv, fmt.Sprintf("-Wl,-rpath,%s", rpath.val))
+	}
+
+	// Force global symbols to be exported for dlopen, etc.
+	if Iself {
+		argv = append(argv, "-rdynamic")
+	}
+
+	if strings.Contains(argv[0], "clang") {
+		argv = append(argv, "-Qunused-arguments")
+	}
+
+	argv = append(argv, hostobjCopy()...)
+	argv = append(argv, fmt.Sprintf("%s/go.o", tmpdir))
+
+	if Linkshared {
+		seenDirs := make(map[string]bool)
+		seenLibs := make(map[string]bool)
+		addshlib := func(path string) {
+			dir, base := filepath.Split(path)
+			if !seenDirs[dir] {
+				argv = append(argv, "-L"+dir)
+				if !rpath.set {
+					argv = append(argv, "-Wl,-rpath="+dir)
+				}
+				seenDirs[dir] = true
+			}
+			base = strings.TrimSuffix(base, ".so")
+			base = strings.TrimPrefix(base, "lib")
+			if !seenLibs[base] {
+				argv = append(argv, "-l"+base)
+				seenLibs[base] = true
+			}
+		}
+		for _, shlib := range Ctxt.Shlibs {
+			addshlib(shlib.Path)
+			for _, dep := range shlib.Deps {
+				if dep == "" {
+					continue
+				}
+				libpath := findshlib(dep)
+				if libpath != "" {
+					addshlib(libpath)
+				}
+			}
+		}
+	}
+
+	argv = append(argv, ldflag...)
+
+	for _, p := range strings.Fields(extldflags) {
+		argv = append(argv, p)
+
+		// clang, unlike GCC, passes -rdynamic to the linker
+		// even when linking with -static, causing a linker
+		// error when using GNU ld.  So take out -rdynamic if
+		// we added it.  We do it in this order, rather than
+		// only adding -rdynamic later, so that -extldflags
+		// can override -rdynamic without using -static.
+		if Iself && p == "-static" {
+			for i := range argv {
+				if argv[i] == "-rdynamic" {
+					argv[i] = "-static"
+				}
+			}
+		}
+	}
+	if HEADTYPE == obj.Hwindows {
+		argv = append(argv, peimporteddlls()...)
+	}
+
+	if Debug['v'] != 0 {
+		fmt.Fprintf(&Bso, "host link:")
+		for _, v := range argv {
+			fmt.Fprintf(&Bso, " %q", v)
+		}
+		fmt.Fprintf(&Bso, "\n")
+		Bso.Flush()
+	}
+
+	if out, err := exec.Command(argv[0], argv[1:]...).CombinedOutput(); err != nil {
+		Exitf("running %s failed: %v\n%s", argv[0], err, out)
+	} else if Debug['v'] != 0 && len(out) > 0 {
+		fmt.Fprintf(&Bso, "%s", out)
+		Bso.Flush()
+	}
+
+	if Debug['s'] == 0 && debug_s == 0 && HEADTYPE == obj.Hdarwin {
+		// Skip combining dwarf on arm.
+		if Thearch.Thechar != '5' && Thearch.Thechar != '7' {
+			dsym := fmt.Sprintf("%s/go.dwarf", tmpdir)
+			if out, err := exec.Command("dsymutil", "-f", outfile, "-o", dsym).CombinedOutput(); err != nil {
+				Ctxt.Cursym = nil
+				Exitf("%s: running dsymutil failed: %v\n%s", os.Args[0], err, out)
+			}
+			// For os.Rename to work reliably, must be in same directory as outfile.
+			combinedOutput := outfile + "~"
+			if err := machoCombineDwarf(outfile, dsym, combinedOutput); err != nil {
+				Ctxt.Cursym = nil
+				Exitf("%s: combining dwarf failed: %v", os.Args[0], err)
+			}
+			os.Remove(outfile)
+			if err := os.Rename(combinedOutput, outfile); err != nil {
+				Ctxt.Cursym = nil
+				Exitf("%s: %v", os.Args[0], err)
+			}
+		}
+	}
+}
+
+func ldobj(f *obj.Biobuf, pkg string, length int64, pn string, file string, whence int) {
+	eof := obj.Boffset(f) + length
+
+	start := obj.Boffset(f)
+	c1 := obj.Bgetc(f)
+	c2 := obj.Bgetc(f)
+	c3 := obj.Bgetc(f)
+	c4 := obj.Bgetc(f)
+	obj.Bseek(f, start, 0)
+
+	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
+	}
+
+	if magic&^1 == 0xfeedface || magic&^0x01000000 == 0xcefaedfe {
+		ldhostobj(ldmacho, f, pkg, length, pn, file)
+		return
+	}
+
+	if c1 == 0x4c && c2 == 0x01 || c1 == 0x64 && c2 == 0x86 {
+		ldhostobj(ldpe, f, pkg, length, pn, file)
+		return
+	}
+
+	/* check the header */
+	line := obj.Brdline(f, '\n')
+	if line == "" {
+		if obj.Blinelen(f) > 0 {
+			Diag("%s: not an object file", pn)
+			return
+		}
+		Diag("truncated object file: %s", pn)
+		return
+	}
+
+	if !strings.HasPrefix(line, "go object ") {
+		if strings.HasSuffix(pn, ".go") {
+			Exitf("%cl: input %s is not .%c file (use %cg to compile .go files)", Thearch.Thechar, pn, Thearch.Thechar, Thearch.Thechar)
+		}
+
+		if line == Thestring {
+			// old header format: just $GOOS
+			Diag("%s: stale object file", pn)
+			return
+		}
+
+		Diag("%s: not an object file", pn)
+		return
+	}
+
+	// First, check that the basic goos, goarch, and version match.
+	t := fmt.Sprintf("%s %s %s ", goos, obj.Getgoarch(), obj.Getgoversion())
+
+	line = strings.TrimRight(line, "\n")
+	if !strings.HasPrefix(line[10:]+" ", t) && Debug['f'] == 0 {
+		Diag("%s: object is [%s] expected [%s]", pn, line[10:], t)
+		return
+	}
+
+	// Second, check that longer lines match each other exactly,
+	// so that the Go compiler and write additional information
+	// that must be the same from run to run.
+	if len(line) >= len(t)+10 {
+		if theline == "" {
+			theline = line[10:]
+		} else if theline != line[10:] {
+			Diag("%s: object is [%s] expected [%s]", pn, line[10:], theline)
+			return
+		}
+	}
+
+	/* skip over exports and other info -- ends with \n!\n */
+	import0 := obj.Boffset(f)
+
+	c1 = '\n' // the last line ended in \n
+	c2 = obj.Bgetc(f)
+	c3 = obj.Bgetc(f)
+	for c1 != '\n' || c2 != '!' || c3 != '\n' {
+		c1 = c2
+		c2 = c3
+		c3 = obj.Bgetc(f)
+		if c3 == obj.Beof {
+			Diag("truncated object file: %s", pn)
+			return
+		}
+	}
+
+	import1 := obj.Boffset(f)
+
+	obj.Bseek(f, import0, 0)
+	ldpkg(f, pkg, import1-import0-2, pn, whence) // -2 for !\n
+	obj.Bseek(f, import1, 0)
+
+	ldobjfile(Ctxt, f, pkg, eof-obj.Boffset(f), pn)
+}
+
+func readelfsymboldata(f *elf.File, sym *elf.Symbol) []byte {
+	data := make([]byte, sym.Size)
+	sect := f.Sections[sym.Section]
+	if sect.Type != elf.SHT_PROGBITS && sect.Type != elf.SHT_NOTE {
+		Diag("reading %s from non-data section", sym.Name)
+	}
+	n, err := sect.ReadAt(data, int64(sym.Value-sect.Addr))
+	if uint64(n) != sym.Size {
+		Diag("reading contents of %s: %v", sym.Name, err)
+	}
+	return data
+}
+
+func readwithpad(r io.Reader, sz int32) ([]byte, error) {
+	data := make([]byte, Rnd(int64(sz), 4))
+	_, err := io.ReadFull(r, data)
+	if err != nil {
+		return nil, err
+	}
+	data = data[:sz]
+	return data, nil
+}
+
+func readnote(f *elf.File, name []byte, typ int32) ([]byte, error) {
+	for _, sect := range f.Sections {
+		if sect.Type != elf.SHT_NOTE {
+			continue
+		}
+		r := sect.Open()
+		for {
+			var namesize, descsize, noteType int32
+			err := binary.Read(r, f.ByteOrder, &namesize)
+			if err != nil {
+				if err == io.EOF {
+					break
+				}
+				return nil, fmt.Errorf("read namesize failed:", err)
+			}
+			err = binary.Read(r, f.ByteOrder, &descsize)
+			if err != nil {
+				return nil, fmt.Errorf("read descsize failed:", err)
+			}
+			err = binary.Read(r, f.ByteOrder, &noteType)
+			if err != nil {
+				return nil, fmt.Errorf("read type failed:", err)
+			}
+			noteName, err := readwithpad(r, namesize)
+			if err != nil {
+				return nil, fmt.Errorf("read name failed:", err)
+			}
+			desc, err := readwithpad(r, descsize)
+			if err != nil {
+				return nil, fmt.Errorf("read desc failed:", err)
+			}
+			if string(name) == string(noteName) && typ == noteType {
+				return desc, nil
+			}
+		}
+	}
+	return nil, nil
+}
+
+func findshlib(shlib string) string {
+	for _, libdir := range Ctxt.Libdir {
+		libpath := filepath.Join(libdir, shlib)
+		if _, err := os.Stat(libpath); err == nil {
+			return libpath
+		}
+	}
+	Diag("cannot find shared library: %s", shlib)
+	return ""
+}
+
+func ldshlibsyms(shlib string) {
+	libpath := findshlib(shlib)
+	if libpath == "" {
+		return
+	}
+	for _, processedlib := range Ctxt.Shlibs {
+		if processedlib.Path == libpath {
+			return
+		}
+	}
+	if Ctxt.Debugvlog > 1 && Ctxt.Bso != nil {
+		fmt.Fprintf(Ctxt.Bso, "%5.2f ldshlibsyms: found library with name %s at %s\n", obj.Cputime(), shlib, libpath)
+		Ctxt.Bso.Flush()
+	}
+
+	f, err := elf.Open(libpath)
+	if err != nil {
+		Diag("cannot open shared library: %s", libpath)
+		return
+	}
+
+	hash, err := readnote(f, ELF_NOTE_GO_NAME, ELF_NOTE_GOABIHASH_TAG)
+	if err != nil {
+		Diag("cannot read ABI hash from shared library %s: %v", libpath, err)
+		return
+	}
+
+	depsbytes, err := readnote(f, ELF_NOTE_GO_NAME, ELF_NOTE_GODEPS_TAG)
+	if err != nil {
+		Diag("cannot read dep list from shared library %s: %v", libpath, err)
+		return
+	}
+	deps := strings.Split(string(depsbytes), "\n")
+
+	syms, err := f.DynamicSymbols()
+	if err != nil {
+		Diag("cannot read symbols from shared library: %s", libpath)
+		return
+	}
+	for _, elfsym := range syms {
+		if elf.ST_TYPE(elfsym.Info) == elf.STT_NOTYPE || elf.ST_TYPE(elfsym.Info) == elf.STT_SECTION {
+			continue
+		}
+		lsym := Linklookup(Ctxt, elfsym.Name, 0)
+		if lsym.Type != 0 && lsym.Type != obj.SDYNIMPORT && lsym.Dupok == 0 {
+			if (lsym.Type != obj.SBSS && lsym.Type != obj.SNOPTRBSS) || len(lsym.R) != 0 || len(lsym.P) != 0 || f.Sections[elfsym.Section].Type != elf.SHT_NOBITS {
+				Diag("Found duplicate symbol %s reading from %s, first found in %s", elfsym.Name, shlib, lsym.File)
+			}
+			if lsym.Size > int64(elfsym.Size) {
+				// If the existing symbol is a BSS value that is
+				// larger than the one read from the shared library,
+				// keep references to that.  Conversely, if the
+				// version from the shared libray is larger, we want
+				// to make all references be to that.
+				continue
+			}
+		}
+		lsym.Type = obj.SDYNIMPORT
+		lsym.ElfType = elf.ST_TYPE(elfsym.Info)
+		lsym.Size = int64(elfsym.Size)
+		if elfsym.Section != elf.SHN_UNDEF {
+			// Set .File for the library that actually defines the symbol.
+			lsym.File = libpath
+			// The decodetype_* functions in decodetype.go need access to
+			// the type data.
+			if strings.HasPrefix(lsym.Name, "type.") && !strings.HasPrefix(lsym.Name, "type..") {
+				lsym.P = readelfsymboldata(f, &elfsym)
+			}
+		}
+	}
+
+	// We might have overwritten some functions above (this tends to happen for the
+	// autogenerated type equality/hashing functions) and we don't want to generated
+	// pcln table entries for these any more so unstitch them from the Textp linked
+	// list.
+	var last *LSym
+
+	for s := Ctxt.Textp; s != nil; s = s.Next {
+		if s.Type == obj.SDYNIMPORT {
+			continue
+		}
+
+		if last == nil {
+			Ctxt.Textp = s
+		} else {
+			last.Next = s
+		}
+		last = s
+	}
+
+	if last == nil {
+		Ctxt.Textp = nil
+		Ctxt.Etextp = nil
+	} else {
+		last.Next = nil
+		Ctxt.Etextp = last
+	}
+
+	Ctxt.Shlibs = append(Ctxt.Shlibs, Shlib{Path: libpath, Hash: hash, Deps: deps, File: f})
+}
+
+func mywhatsys() {
+	goroot = obj.Getgoroot()
+	goos = obj.Getgoos()
+	goarch = obj.Getgoarch()
+
+	if !strings.HasPrefix(goarch, Thestring) {
+		log.Fatalf("cannot use %cc with GOARCH=%s", Thearch.Thechar, goarch)
+	}
+}
+
+// Copied from ../gc/subr.c:/^pathtoprefix; must stay in sync.
+/*
+ * Convert raw string to the prefix that will be used in the symbol table.
+ * Invalid bytes turn into %xx.	 Right now the only bytes that need
+ * escaping are %, ., and ", but we escape all control characters too.
+ *
+ * If you edit this, edit ../gc/subr.c:/^pathtoprefix too.
+ * If you edit this, edit ../../debug/goobj/read.go:/importPathToPrefix too.
+ */
+func pathtoprefix(s string) string {
+	slash := strings.LastIndex(s, "/")
+	for i := 0; i < len(s); i++ {
+		c := s[i]
+		if c <= ' ' || i >= slash && c == '.' || c == '%' || c == '"' || c >= 0x7F {
+			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
+}
+
+func addsection(seg *Segment, name string, rwx int) *Section {
+	var l **Section
+
+	for l = &seg.Sect; *l != nil; l = &(*l).Next {
+	}
+	sect := new(Section)
+	sect.Rwx = uint8(rwx)
+	sect.Name = name
+	sect.Seg = seg
+	sect.Align = int32(Thearch.Ptrsize) // everything is at least pointer-aligned
+	*l = sect
+	return sect
+}
+
+func Le16(b []byte) uint16 {
+	return uint16(b[0]) | uint16(b[1])<<8
+}
+
+func Le32(b []byte) uint32 {
+	return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
+}
+
+func Le64(b []byte) uint64 {
+	return uint64(Le32(b)) | uint64(Le32(b[4:]))<<32
+}
+
+func Be16(b []byte) uint16 {
+	return uint16(b[0])<<8 | uint16(b[1])
+}
+
+func Be32(b []byte) uint32 {
+	return uint32(b[0])<<24 | uint32(b[1])<<16 | uint32(b[2])<<8 | uint32(b[3])
+}
+
+func Be64(b []byte) uint64 {
+	return uint64(Be32(b))<<32 | uint64(Be32(b[4:]))
+}
+
+type Chain struct {
+	sym   *LSym
+	up    *Chain
+	limit int // limit on entry to sym
+}
+
+var morestack *LSym
+
+// TODO: Record enough information in new object files to
+// allow stack checks here.
+
+func haslinkregister() bool {
+	return Thearch.Thechar == '5' || Thearch.Thechar == '9' || Thearch.Thechar == '7'
+}
+
+func callsize() int {
+	if haslinkregister() {
+		return 0
+	}
+	return Thearch.Regsize
+}
+
+func dostkcheck() {
+	var ch Chain
+
+	morestack = Linklookup(Ctxt, "runtime.morestack", 0)
+
+	// Every splitting function ensures that there are at least StackLimit
+	// bytes available below SP when the splitting prologue finishes.
+	// If the splitting function calls F, then F begins execution with
+	// at least StackLimit - callsize() bytes available.
+	// Check that every function behaves correctly with this amount
+	// of stack, following direct calls in order to piece together chains
+	// of non-splitting functions.
+	ch.up = nil
+
+	ch.limit = obj.StackLimit - callsize()
+
+	// 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 {
+		// 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.
+		if s.Name == "runtime.racesymbolizethunk" {
+			continue
+		}
+
+		if s.Nosplit != 0 {
+			Ctxt.Cursym = s
+			ch.sym = s
+			stkcheck(&ch, 0)
+		}
+	}
+
+	for s := Ctxt.Textp; s != nil; s = s.Next {
+		if s.Nosplit == 0 {
+			Ctxt.Cursym = s
+			ch.sym = s
+			stkcheck(&ch, 0)
+		}
+	}
+}
+
+func stkcheck(up *Chain, depth int) int {
+	limit := up.limit
+	s := up.sym
+
+	// Don't duplicate work: only need to consider each
+	// function at top of safe zone once.
+	top := limit == obj.StackLimit-callsize()
+	if top {
+		if s.Stkcheck != 0 {
+			return 0
+		}
+		s.Stkcheck = 1
+	}
+
+	if depth > 100 {
+		Diag("nosplit stack check too deep")
+		stkbroke(up, 0)
+		return -1
+	}
+
+	if s.External != 0 || s.Pcln == nil {
+		// external function.
+		// should never be called directly.
+		// only diagnose the direct caller.
+		// TODO(mwhudson): actually think about this.
+		if depth == 1 && s.Type != obj.SXREF && !DynlinkingGo() {
+			Diag("call to external function %s", s.Name)
+		}
+		return -1
+	}
+
+	if limit < 0 {
+		stkbroke(up, limit)
+		return -1
+	}
+
+	// morestack looks like it calls functions,
+	// but it switches the stack pointer first.
+	if s == morestack {
+		return 0
+	}
+
+	var ch Chain
+	ch.up = up
+
+	if s.Nosplit == 0 {
+		// Ensure we have enough stack to call morestack.
+		ch.limit = limit - callsize()
+		ch.sym = morestack
+		if stkcheck(&ch, depth+1) < 0 {
+			return -1
+		}
+		if !top {
+			return 0
+		}
+		// Raise limit to allow frame.
+		limit = int(obj.StackLimit + s.Locals)
+		if haslinkregister() {
+			limit += Thearch.Regsize
+		}
+	}
+
+	// Walk through sp adjustments in function, consuming relocs.
+	ri := 0
+
+	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).
+
+		// Check stack size in effect for this span.
+		if int32(limit)-pcsp.value < 0 {
+			stkbroke(up, int(int32(limit)-pcsp.value))
+			return -1
+		}
+
+		// Process calls in this span.
+		for ; ri < endr && uint32(s.R[ri].Off) < pcsp.nextpc; ri++ {
+			r = &s.R[ri]
+			switch r.Type {
+			// Direct call.
+			case obj.R_CALL, obj.R_CALLARM, obj.R_CALLARM64, obj.R_CALLPOWER:
+				ch.limit = int(int32(limit) - pcsp.value - int32(callsize()))
+				ch.sym = r.Sym
+				if stkcheck(&ch, depth+1) < 0 {
+					return -1
+				}
+
+			// Indirect call.  Assume it is a call to a splitting function,
+			// so we have to make sure it can call morestack.
+			// Arrange the data structures to report both calls, so that
+			// if there is an error, stkprint shows all the steps involved.
+			case obj.R_CALLIND:
+				ch.limit = int(int32(limit) - pcsp.value - int32(callsize()))
+
+				ch.sym = nil
+				ch1.limit = ch.limit - callsize() // for morestack in called prologue
+				ch1.up = &ch
+				ch1.sym = morestack
+				if stkcheck(&ch1, depth+2) < 0 {
+					return -1
+				}
+			}
+		}
+	}
+
+	return 0
+}
+
+func stkbroke(ch *Chain, limit int) {
+	Diag("nosplit stack overflow")
+	stkprint(ch, limit)
+}
+
+func stkprint(ch *Chain, limit int) {
+	var name string
+
+	if ch.sym != nil {
+		name = ch.sym.Name
+		if ch.sym.Nosplit != 0 {
+			name += " (nosplit)"
+		}
+	} else {
+		name = "function pointer"
+	}
+
+	if ch.up == nil {
+		// top of chain.  ch->sym != nil.
+		if ch.sym.Nosplit != 0 {
+			fmt.Printf("\t%d\tassumed on entry to %s\n", ch.limit, name)
+		} else {
+			fmt.Printf("\t%d\tguaranteed after split check in %s\n", ch.limit, name)
+		}
+	} else {
+		stkprint(ch.up, ch.limit+callsize())
+		if !haslinkregister() {
+			fmt.Printf("\t%d\ton entry to %s\n", ch.limit, name)
+		}
+	}
+
+	if ch.limit != limit {
+		fmt.Printf("\t%d\tafter %s uses %d\n", limit, name, ch.limit-limit)
+	}
+}
+
+func Yconv(s *LSym) string {
+	var fp string
+
+	if s == nil {
+		fp += fmt.Sprintf("<nil>")
+	} else {
+		fmt_ := ""
+		fmt_ += fmt.Sprintf("%s @0x%08x [%d]", s.Name, int64(s.Value), int64(s.Size))
+		for i := 0; int64(i) < s.Size; i++ {
+			if i%8 == 0 {
+				fmt_ += fmt.Sprintf("\n\t0x%04x ", i)
+			}
+			fmt_ += fmt.Sprintf("%02x ", s.P[i])
+		}
+
+		fmt_ += fmt.Sprintf("\n")
+		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_
+		fp += str
+	}
+
+	return fp
+}
+
+func Cflush() {
+	if err := coutbuf.Writer.Flush(); err != nil {
+		Exitf("flushing %s: %v", coutbuf.f.Name(), err)
+	}
+}
+
+func Cpos() int64 {
+	off, err := coutbuf.f.Seek(0, 1)
+	if err != nil {
+		Exitf("seeking in output [0, 1]: %v", err)
+	}
+	return off + int64(coutbuf.Buffered())
+}
+
+func Cseek(p int64) {
+	Cflush()
+	if _, err := coutbuf.f.Seek(p, 0); err != nil {
+		Exitf("seeking in output [0, 1]: %v", err)
+	}
+}
+
+func Cwrite(p []byte) {
+	coutbuf.Write(p)
+}
+
+func Cput(c uint8) {
+	coutbuf.WriteByte(c)
+}
+
+func usage() {
+	fmt.Fprintf(os.Stderr, "usage: link [options] main.o\n")
+	obj.Flagprint(2)
+	Exit(2)
+}
+
+func setheadtype(s string) {
+	h := headtype(s)
+	if h < 0 {
+		Exitf("unknown header type -H %s", s)
+	}
+
+	headstring = s
+	HEADTYPE = int32(headtype(s))
+}
+
+func setinterp(s string) {
+	Debug['I'] = 1 // denote cmdline interpreter override
+	interpreter = s
+}
+
+func doversion() {
+	Exitf("version %s", obj.Getgoversion())
+}
+
+func genasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) {
+	// 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)
+
+	if s.Type == obj.STEXT {
+		put(s, s.Name, 'T', s.Value, s.Size, int(s.Version), nil)
+	}
+	s = Linklookup(Ctxt, "runtime.etext", 0)
+	if s.Type == obj.STEXT {
+		put(s, s.Name, 'T', s.Value, s.Size, int(s.Version), nil)
+	}
+
+	for s := Ctxt.Allsym; s != nil; s = s.Allsym {
+		if s.Hide != 0 || (s.Name[0] == '.' && s.Version == 0 && s.Name != ".rathole") {
+			continue
+		}
+		switch s.Type & obj.SMASK {
+		case obj.SCONST,
+			obj.SRODATA,
+			obj.SSYMTAB,
+			obj.SPCLNTAB,
+			obj.SINITARR,
+			obj.SDATA,
+			obj.SNOPTRDATA,
+			obj.SELFROSECT,
+			obj.SMACHOGOT,
+			obj.STYPE,
+			obj.SSTRING,
+			obj.SGOSTRING,
+			obj.SGOFUNC,
+			obj.SGCBITS,
+			obj.SWINDOWS:
+			if !s.Reachable {
+				continue
+			}
+			put(s, s.Name, 'D', Symaddr(s), s.Size, int(s.Version), s.Gotype)
+
+		case obj.SBSS, obj.SNOPTRBSS:
+			if !s.Reachable {
+				continue
+			}
+			if len(s.P) > 0 {
+				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)
+
+		case obj.SFILE:
+			put(nil, s.Name, 'f', s.Value, 0, int(s.Version), nil)
+
+		case obj.SHOSTOBJ:
+			if HEADTYPE == obj.Hwindows || Iself {
+				put(s, s.Name, 'U', s.Value, 0, int(s.Version), nil)
+			}
+
+		case obj.SDYNIMPORT:
+			if !s.Reachable {
+				continue
+			}
+			put(s, s.Extname, 'U', 0, 0, int(s.Version), nil)
+
+		case obj.STLSBSS:
+			if Linkmode == LinkExternal && HEADTYPE != obj.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)
+			}
+		}
+	}
+
+	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
+		put(nil, ".frame", 'm', int64(s.Locals)+int64(Thearch.Ptrsize), 0, 0, nil)
+
+		for a = s.Autom; a != nil; a = a.Link {
+			// Emit a or p according to actual offset, even if label is wrong.
+			// This avoids negative offsets, which cannot be encoded.
+			if a.Name != obj.A_AUTO && a.Name != obj.A_PARAM {
+				continue
+			}
+
+			// compute offset relative to FP
+			if a.Name == obj.A_PARAM {
+				off = a.Aoffset
+			} else {
+				off = a.Aoffset - int32(Thearch.Ptrsize)
+			}
+
+			// FP
+			if off >= 0 {
+				put(nil, a.Asym.Name, 'p', int64(off), 0, 0, a.Gotype)
+				continue
+			}
+
+			// SP
+			if off <= int32(-Thearch.Ptrsize) {
+				put(nil, a.Asym.Name, 'a', -(int64(off) + int64(Thearch.Ptrsize)), 0, 0, a.Gotype)
+				continue
+			}
+		}
+	}
+
+	// Otherwise, off is addressing the saved program counter.
+	// Something underhanded is going on. Say nothing.
+	if Debug['v'] != 0 || Debug['n'] != 0 {
+		fmt.Fprintf(&Bso, "%5.2f symsize = %d\n", obj.Cputime(), uint32(Symsize))
+	}
+	Bso.Flush()
+}
+
+func Symaddr(s *LSym) int64 {
+	if !s.Reachable {
+		Diag("unreachable symbol in symaddr - %s", s.Name)
+	}
+	return s.Value
+}
+
+func xdefine(p string, t int, v int64) {
+	s := Linklookup(Ctxt, p, 0)
+	s.Type = int16(t)
+	s.Value = v
+	s.Reachable = true
+	s.Special = 1
+	s.Local = true
+}
+
+func datoff(addr int64) int64 {
+	if uint64(addr) >= Segdata.Vaddr {
+		return int64(uint64(addr) - Segdata.Vaddr + Segdata.Fileoff)
+	}
+	if uint64(addr) >= Segtext.Vaddr {
+		return int64(uint64(addr) - Segtext.Vaddr + Segtext.Fileoff)
+	}
+	Diag("datoff %#x", addr)
+	return 0
+}
+
+func Entryvalue() int64 {
+	a := INITENTRY
+	if a[0] >= '0' && a[0] <= '9' {
+		return atolwhex(a)
+	}
+	s := Linklookup(Ctxt, a, 0)
+	if s.Type == 0 {
+		return INITTEXT
+	}
+	if s.Type != obj.STEXT {
+		Diag("entry not text: %s", s.Name)
+	}
+	return s.Value
+}
+
+func undefsym(s *LSym) {
+	var r *Reloc
+
+	Ctxt.Cursym = s
+	for i := 0; i < len(s.R); i++ {
+		r = &s.R[i]
+		if r.Sym == nil { // happens for some external ARM relocs
+			continue
+		}
+		if r.Sym.Type == obj.Sxxx || r.Sym.Type == obj.SXREF {
+			Diag("undefined: %s", r.Sym.Name)
+		}
+		if !r.Sym.Reachable {
+			Diag("use of unreachable symbol: %s", r.Sym.Name)
+		}
+	}
+}
+
+func undef() {
+	for s := Ctxt.Textp; s != nil; s = s.Next {
+		undefsym(s)
+	}
+	for s := datap; s != nil; s = s.Next {
+		undefsym(s)
+	}
+	if nerrors > 0 {
+		errorexit()
+	}
+}
+
+func callgraph() {
+	if Debug['c'] == 0 {
+		return
+	}
+
+	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 {
+				continue
+			}
+			if (r.Type == obj.R_CALL || r.Type == obj.R_CALLARM || r.Type == obj.R_CALLPOWER) && r.Sym.Type == obj.STEXT {
+				fmt.Fprintf(&Bso, "%s calls %s\n", s.Name, r.Sym.Name)
+			}
+		}
+	}
+}
+
+func Diag(format string, args ...interface{}) {
+	tn := ""
+	sep := ""
+	if Ctxt.Cursym != nil {
+		tn = Ctxt.Cursym.Name
+		sep = ": "
+	}
+	fmt.Printf("%s%s%s\n", tn, sep, fmt.Sprintf(format, args...))
+	nerrors++
+	if Debug['h'] != 0 {
+		panic("error")
+	}
+	if nerrors > 20 {
+		Exitf("too many errors")
+	}
+}
+
+func checkgo() {
+	if Debug['C'] == 0 {
+		return
+	}
+
+	// TODO(rsc,khr): Eventually we want to get to no Go-called C functions at all,
+	// 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 {
+			if s.Cfunc == 0 || (s.Cfunc == 2 && s.Nosplit != 0) {
+				for i = 0; i < len(s.R); i++ {
+					r = &s.R[i]
+					if r.Sym == nil {
+						continue
+					}
+					if (r.Type == obj.R_CALL || r.Type == obj.R_CALLARM) && r.Sym.Type == obj.STEXT {
+						if r.Sym.Cfunc == 1 {
+							changed = 1
+							r.Sym.Cfunc = 2
+						}
+					}
+				}
+			}
+		}
+		if changed == 0 {
+			break
+		}
+	}
+
+	// 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 {
+		if s.Cfunc == 0 || (s.Cfunc == 2 && s.Nosplit != 0) {
+			for i = 0; i < len(s.R); i++ {
+				r = &s.R[i]
+				if r.Sym == nil {
+					continue
+				}
+				if (r.Type == obj.R_CALL || r.Type == obj.R_CALLARM) && r.Sym.Type == obj.STEXT {
+					if s.Cfunc == 0 && r.Sym.Cfunc == 2 && r.Sym.Nosplit == 0 {
+						fmt.Printf("Go %s calls C %s\n", s.Name, r.Sym.Name)
+					} else if s.Cfunc == 2 && s.Nosplit != 0 && r.Sym.Nosplit == 0 {
+						fmt.Printf("Go calls C %s calls %s\n", s.Name, r.Sym.Name)
+					}
+				}
+			}
+		}
+	}
+}
+
+func Rnd(v int64, r int64) int64 {
+	if r <= 0 {
+		return v
+	}
+	v += r - 1
+	c := v % r
+	if c < 0 {
+		c += r
+	}
+	v -= c
+	return v
+}
diff --git a/src/cmd/link/internal/ld/link.go b/src/cmd/link/internal/ld/link.go
new file mode 100644
index 0000000..33b17c5
--- /dev/null
+++ b/src/cmd/link/internal/ld/link.go
@@ -0,0 +1,227 @@
+// Derived from Inferno utils/6l/l.h and related files.
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/l.h
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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 ld
+
+import (
+	"cmd/internal/obj"
+	"debug/elf"
+	"encoding/binary"
+	"fmt"
+)
+
+type LSym struct {
+	Name       string
+	Extname    string
+	Type       int16
+	Version    int16
+	Dupok      uint8
+	Cfunc      uint8
+	External   uint8
+	Nosplit    uint8
+	Reachable  bool
+	Cgoexport  uint8
+	Special    uint8
+	Stkcheck   uint8
+	Hide       uint8
+	Leaf       uint8
+	Localentry uint8
+	Onlist     uint8
+	// ElfType is set for symbols read from shared libraries by ldshlibsyms. It
+	// is not set for symbols defined by the packages being linked or by symbols
+	// read by ldelf (and so is left as elf.STT_NOTYPE).
+	ElfType     elf.SymType
+	Dynid       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        *Section
+	Autom       *Auto
+	Pcln        *Pcln
+	P           []byte
+	R           []Reloc
+	Local       bool
+}
+
+func (s *LSym) String() string {
+	if s.Version == 0 {
+		return s.Name
+	}
+	return fmt.Sprintf("%s<%d>", s.Name, s.Version)
+}
+
+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 Shlib struct {
+	Path string
+	Hash []byte
+	Deps []string
+	File *elf.File
+}
+
+type Link struct {
+	Thechar   int32
+	Thestring string
+	Goarm     int32
+	Headtype  int
+	Arch      *LinkArch
+	Debugasm  int32
+	Debugvlog int32
+	Bso       *obj.Biobuf
+	Windows   int32
+	Goroot    string
+	Hash      map[symVer]*LSym
+	Allsym    *LSym
+	Nsymbol   int32
+	Tlsg      *LSym
+	Libdir    []string
+	Library   []*Library
+	Shlibs    []Shlib
+	Tlsoffset int
+	Diag      func(string, ...interface{})
+	Cursym    *LSym
+	Version   int
+	Textp     *LSym
+	Etextp    *LSym
+	Nhistfile int32
+	Filesyms  *LSym
+}
+
+type LinkArch struct {
+	ByteOrder binary.ByteOrder
+	Name      string
+	Thechar   int
+	Minlc     int
+	Ptrsize   int
+	Regsize   int
+}
+
+type Library struct {
+	Objref string
+	Srcref string
+	File   string
+	Pkg    string
+	Shlib  string
+	hash   []byte
+}
+
+type Pcln struct {
+	Pcsp        Pcdata
+	Pcfile      Pcdata
+	Pcline      Pcdata
+	Pcdata      []Pcdata
+	Npcdata     int
+	Funcdata    []*LSym
+	Funcdataoff []int64
+	Nfuncdata   int
+	File        []*LSym
+	Nfile       int
+	Mfile       int
+	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
+}
+
+// Reloc.variant
+const (
+	RV_NONE = iota
+	RV_POWER_LO
+	RV_POWER_HI
+	RV_POWER_HA
+	RV_POWER_DS
+	RV_CHECK_OVERFLOW = 1 << 8
+	RV_TYPE_MASK      = RV_CHECK_OVERFLOW - 1
+)
+
+const (
+	LINKHASH = 100003
+)
+
+// Pcdata iterator.
+//	for(pciterinit(ctxt, &it, &pcd); !it.done; pciternext(&it)) { it.value holds in [it.pc, it.nextpc) }
+
+// Link holds the context for writing object code from a compiler
+// to be linker input or for reading that input into the linker.
+
+// LinkArch is the definition of a single architecture.
+
+const (
+	LinkAuto = 0 + iota
+	LinkInternal
+	LinkExternal
+)
diff --git a/src/cmd/link/internal/ld/macho.go b/src/cmd/link/internal/ld/macho.go
new file mode 100644
index 0000000..ccc8491
--- /dev/null
+++ b/src/cmd/link/internal/ld/macho.go
@@ -0,0 +1,860 @@
+// 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 ld
+
+import (
+	"cmd/internal/obj"
+	"sort"
+	"strings"
+)
+
+type MachoHdr struct {
+	cpu    uint32
+	subcpu uint32
+}
+
+type MachoSect struct {
+	name    string
+	segname string
+	addr    uint64
+	size    uint64
+	off     uint32
+	align   uint32
+	reloc   uint32
+	nreloc  uint32
+	flag    uint32
+	res1    uint32
+	res2    uint32
+}
+
+type MachoSeg struct {
+	name       string
+	vsize      uint64
+	vaddr      uint64
+	fileoffset uint64
+	filesize   uint64
+	prot1      uint32
+	prot2      uint32
+	nsect      uint32
+	msect      uint32
+	sect       []MachoSect
+	flag       uint32
+}
+
+type MachoLoad struct {
+	type_ uint32
+	data  []uint32
+}
+
+/*
+ * Total amount of space to reserve at the start of the file
+ * for Header, PHeaders, and SHeaders.
+ * May waste some.
+ */
+const (
+	INITIAL_MACHO_HEADR = 4 * 1024
+)
+
+const (
+	MACHO_CPU_AMD64               = 1<<24 | 7
+	MACHO_CPU_386                 = 7
+	MACHO_SUBCPU_X86              = 3
+	MACHO_CPU_ARM                 = 12
+	MACHO_SUBCPU_ARM              = 0
+	MACHO_SUBCPU_ARMV7            = 9
+	MACHO_CPU_ARM64               = 1<<24 | 12
+	MACHO_SUBCPU_ARM64_ALL        = 0
+	MACHO32SYMSIZE                = 12
+	MACHO64SYMSIZE                = 16
+	MACHO_X86_64_RELOC_UNSIGNED   = 0
+	MACHO_X86_64_RELOC_SIGNED     = 1
+	MACHO_X86_64_RELOC_BRANCH     = 2
+	MACHO_X86_64_RELOC_GOT_LOAD   = 3
+	MACHO_X86_64_RELOC_GOT        = 4
+	MACHO_X86_64_RELOC_SUBTRACTOR = 5
+	MACHO_X86_64_RELOC_SIGNED_1   = 6
+	MACHO_X86_64_RELOC_SIGNED_2   = 7
+	MACHO_X86_64_RELOC_SIGNED_4   = 8
+	MACHO_ARM_RELOC_VANILLA       = 0
+	MACHO_ARM_RELOC_BR24          = 5
+	MACHO_ARM64_RELOC_UNSIGNED    = 0
+	MACHO_ARM64_RELOC_BRANCH26    = 2
+	MACHO_ARM64_RELOC_PAGE21      = 3
+	MACHO_ARM64_RELOC_PAGEOFF12   = 4
+	MACHO_ARM64_RELOC_ADDEND      = 10
+	MACHO_GENERIC_RELOC_VANILLA   = 0
+	MACHO_FAKE_GOTPCREL           = 100
+)
+
+// 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.
+
+// Mach-O file writing
+// http://developer.apple.com/mac/library/DOCUMENTATION/DeveloperTools/Conceptual/MachORuntime/Reference/reference.html
+
+var macho64 bool
+
+var machohdr MachoHdr
+
+var load []MachoLoad
+
+var seg [16]MachoSeg
+
+var nseg int
+
+var ndebug int
+
+var nsect int
+
+const (
+	SymKindLocal = 0 + iota
+	SymKindExtdef
+	SymKindUndef
+	NumSymKind
+)
+
+var nkind [NumSymKind]int
+
+var sortsym []*LSym
+
+var nsortsym int
+
+// Amount of space left for adding load commands
+// that refer to dynamic libraries.  Because these have
+// to go in the Mach-O header, we can't just pick a
+// "big enough" header size.  The initial header is
+// one page, the non-dynamic library stuff takes
+// up about 1300 bytes; we overestimate that as 2k.
+var load_budget int = INITIAL_MACHO_HEADR - 2*1024
+
+func Machoinit() {
+	switch Thearch.Thechar {
+	// 64-bit architectures
+	case '6', '7', '9':
+		macho64 = true
+
+		// 32-bit architectures
+	default:
+		break
+	}
+}
+
+func getMachoHdr() *MachoHdr {
+	return &machohdr
+}
+
+func newMachoLoad(type_ uint32, ndata uint32) *MachoLoad {
+	if macho64 && (ndata&1 != 0) {
+		ndata++
+	}
+
+	load = append(load, MachoLoad{})
+	l := &load[len(load)-1]
+	l.type_ = type_
+	l.data = make([]uint32, ndata)
+	return l
+}
+
+func newMachoSeg(name string, msect int) *MachoSeg {
+	if nseg >= len(seg) {
+		Exitf("too many segs")
+	}
+
+	s := &seg[nseg]
+	nseg++
+	s.name = name
+	s.msect = uint32(msect)
+	s.sect = make([]MachoSect, msect)
+	return s
+}
+
+func newMachoSect(seg *MachoSeg, name string, segname string) *MachoSect {
+	if seg.nsect >= seg.msect {
+		Exitf("too many sects in segment %s", seg.name)
+	}
+
+	s := &seg.sect[seg.nsect]
+	seg.nsect++
+	s.name = name
+	s.segname = segname
+	nsect++
+	return s
+}
+
+// Generic linking code.
+
+var dylib []string
+
+var linkoff int64
+
+func machowrite() int {
+	o1 := Cpos()
+
+	loadsize := 4 * 4 * ndebug
+	for i := 0; i < len(load); i++ {
+		loadsize += 4 * (len(load[i].data) + 2)
+	}
+	if macho64 {
+		loadsize += 18 * 4 * nseg
+		loadsize += 20 * 4 * nsect
+	} else {
+		loadsize += 14 * 4 * nseg
+		loadsize += 17 * 4 * nsect
+	}
+
+	if macho64 {
+		Thearch.Lput(0xfeedfacf)
+	} else {
+		Thearch.Lput(0xfeedface)
+	}
+	Thearch.Lput(machohdr.cpu)
+	Thearch.Lput(machohdr.subcpu)
+	if Linkmode == LinkExternal {
+		Thearch.Lput(1) /* file type - mach object */
+	} else {
+		Thearch.Lput(2) /* file type - mach executable */
+	}
+	Thearch.Lput(uint32(len(load)) + uint32(nseg) + uint32(ndebug))
+	Thearch.Lput(uint32(loadsize))
+	Thearch.Lput(1) /* flags - no undefines */
+	if macho64 {
+		Thearch.Lput(0) /* reserved */
+	}
+
+	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 */
+			Thearch.Lput(72 + 80*s.nsect)
+			strnput(s.name, 16)
+			Thearch.Vput(s.vaddr)
+			Thearch.Vput(s.vsize)
+			Thearch.Vput(s.fileoffset)
+			Thearch.Vput(s.filesize)
+			Thearch.Lput(s.prot1)
+			Thearch.Lput(s.prot2)
+			Thearch.Lput(s.nsect)
+			Thearch.Lput(s.flag)
+		} else {
+			Thearch.Lput(1) /* segment 32 */
+			Thearch.Lput(56 + 68*s.nsect)
+			strnput(s.name, 16)
+			Thearch.Lput(uint32(s.vaddr))
+			Thearch.Lput(uint32(s.vsize))
+			Thearch.Lput(uint32(s.fileoffset))
+			Thearch.Lput(uint32(s.filesize))
+			Thearch.Lput(s.prot1)
+			Thearch.Lput(s.prot2)
+			Thearch.Lput(s.nsect)
+			Thearch.Lput(s.flag)
+		}
+
+		for j = 0; uint32(j) < s.nsect; j++ {
+			t = &s.sect[j]
+			if macho64 {
+				strnput(t.name, 16)
+				strnput(t.segname, 16)
+				Thearch.Vput(t.addr)
+				Thearch.Vput(t.size)
+				Thearch.Lput(t.off)
+				Thearch.Lput(t.align)
+				Thearch.Lput(t.reloc)
+				Thearch.Lput(t.nreloc)
+				Thearch.Lput(t.flag)
+				Thearch.Lput(t.res1) /* reserved */
+				Thearch.Lput(t.res2) /* reserved */
+				Thearch.Lput(0)      /* reserved */
+			} else {
+				strnput(t.name, 16)
+				strnput(t.segname, 16)
+				Thearch.Lput(uint32(t.addr))
+				Thearch.Lput(uint32(t.size))
+				Thearch.Lput(t.off)
+				Thearch.Lput(t.align)
+				Thearch.Lput(t.reloc)
+				Thearch.Lput(t.nreloc)
+				Thearch.Lput(t.flag)
+				Thearch.Lput(t.res1) /* reserved */
+				Thearch.Lput(t.res2) /* reserved */
+			}
+		}
+	}
+
+	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))
+		for j = 0; j < len(l.data); j++ {
+			Thearch.Lput(l.data[j])
+		}
+	}
+
+	return int(Cpos() - o1)
+}
+
+func domacho() {
+	if Debug['d'] != 0 {
+		return
+	}
+
+	// empirically, string table must begin with " \x00".
+	s := Linklookup(Ctxt, ".machosymstr", 0)
+
+	s.Type = obj.SMACHOSYMSTR
+	s.Reachable = true
+	Adduint8(Ctxt, s, ' ')
+	Adduint8(Ctxt, s, '\x00')
+
+	s = Linklookup(Ctxt, ".machosymtab", 0)
+	s.Type = obj.SMACHOSYMTAB
+	s.Reachable = true
+
+	if Linkmode != LinkExternal {
+		s := Linklookup(Ctxt, ".plt", 0) // will be __symbol_stub
+		s.Type = obj.SMACHOPLT
+		s.Reachable = true
+
+		s = Linklookup(Ctxt, ".got", 0) // will be __nl_symbol_ptr
+		s.Type = obj.SMACHOGOT
+		s.Reachable = true
+		s.Align = 4
+
+		s = Linklookup(Ctxt, ".linkedit.plt", 0) // indirect table for .plt
+		s.Type = obj.SMACHOINDIRECTPLT
+		s.Reachable = true
+
+		s = Linklookup(Ctxt, ".linkedit.got", 0) // indirect table for .got
+		s.Type = obj.SMACHOINDIRECTGOT
+		s.Reachable = true
+	}
+}
+
+func Machoadddynlib(lib string) {
+	// Will need to store the library name rounded up
+	// and 24 bytes of header metadata.  If not enough
+	// space, grab another page of initial space at the
+	// beginning of the output file.
+	load_budget -= (len(lib)+7)/8*8 + 24
+
+	if load_budget < 0 {
+		HEADR += 4096
+		INITTEXT += 4096
+		load_budget += 4096
+	}
+
+	dylib = append(dylib, lib)
+}
+
+func machoshbits(mseg *MachoSeg, sect *Section, segname string) {
+	buf := "__" + strings.Replace(sect.Name[1:], ".", "_", -1)
+
+	var msect *MachoSect
+	if sect.Rwx&1 == 0 && (Thearch.Thechar == '7' || (Thearch.Thechar == '6' && Buildmode == BuildmodeCShared)) {
+		// Darwin external linker on arm64 and on amd64 in c-shared buildmode
+		// complains about absolute relocs in __TEXT, so if the section is not
+		// executable, put it in __DATA segment.
+		msect = newMachoSect(mseg, buf, "__DATA")
+	} else {
+		msect = newMachoSect(mseg, buf, segname)
+	}
+
+	if sect.Rellen > 0 {
+		msect.reloc = uint32(sect.Reloff)
+		msect.nreloc = uint32(sect.Rellen / 8)
+	}
+
+	for 1<<msect.align < sect.Align {
+		msect.align++
+	}
+	msect.addr = sect.Vaddr
+	msect.size = sect.Length
+
+	if sect.Vaddr < sect.Seg.Vaddr+sect.Seg.Filelen {
+		// data in file
+		if sect.Length > sect.Seg.Vaddr+sect.Seg.Filelen-sect.Vaddr {
+			Diag("macho cannot represent section %s crossing data and bss", sect.Name)
+		}
+		msect.off = uint32(sect.Seg.Fileoff + sect.Vaddr - sect.Seg.Vaddr)
+	} else {
+		// zero fill
+		msect.off = 0
+
+		msect.flag |= 1
+	}
+
+	if sect.Rwx&1 != 0 {
+		msect.flag |= 0x400 /* has instructions */
+	}
+
+	if sect.Name == ".plt" {
+		msect.name = "__symbol_stub1"
+		msect.flag = 0x80000408 /* only instructions, code, symbol stubs */
+		msect.res1 = 0          //nkind[SymKindLocal];
+		msect.res2 = 6
+	}
+
+	if sect.Name == ".got" {
+		msect.name = "__nl_symbol_ptr"
+		msect.flag = 6                                                     /* section with nonlazy symbol pointers */
+		msect.res1 = uint32(Linklookup(Ctxt, ".linkedit.plt", 0).Size / 4) /* offset into indirect symbol table */
+	}
+
+	if sect.Name == ".init_array" {
+		msect.name = "__mod_init_func"
+		msect.flag = 9 // S_MOD_INIT_FUNC_POINTERS
+	}
+}
+
+func Asmbmacho() {
+	/* apple MACH */
+	va := INITTEXT - int64(HEADR)
+
+	mh := getMachoHdr()
+	switch Thearch.Thechar {
+	default:
+		Exitf("unknown macho architecture: %v", Thearch.Thechar)
+
+	case '5':
+		mh.cpu = MACHO_CPU_ARM
+		mh.subcpu = MACHO_SUBCPU_ARMV7
+
+	case '6':
+		mh.cpu = MACHO_CPU_AMD64
+		mh.subcpu = MACHO_SUBCPU_X86
+
+	case '7':
+		mh.cpu = MACHO_CPU_ARM64
+		mh.subcpu = MACHO_SUBCPU_ARM64_ALL
+
+	case '8':
+		mh.cpu = MACHO_CPU_386
+		mh.subcpu = MACHO_SUBCPU_X86
+	}
+
+	var ms *MachoSeg
+	if Linkmode == LinkExternal {
+		/* segment for entire file */
+		ms = newMachoSeg("", 40)
+
+		ms.fileoffset = Segtext.Fileoff
+		if Thearch.Thechar == '5' {
+			ms.filesize = Segdata.Fileoff + Segdata.Filelen - Segtext.Fileoff
+		} else {
+			ms.filesize = Segdwarf.Fileoff + Segdwarf.Filelen - Segtext.Fileoff
+			ms.vsize = ms.filesize
+		}
+	}
+
+	/* segment for zero page */
+	if Linkmode != LinkExternal {
+		ms = newMachoSeg("__PAGEZERO", 0)
+		ms.vsize = uint64(va)
+	}
+
+	/* text */
+	v := Rnd(int64(uint64(HEADR)+Segtext.Length), int64(INITRND))
+
+	if Linkmode != LinkExternal {
+		ms = newMachoSeg("__TEXT", 20)
+		ms.vaddr = uint64(va)
+		ms.vsize = uint64(v)
+		ms.fileoffset = 0
+		ms.filesize = uint64(v)
+		ms.prot1 = 7
+		ms.prot2 = 5
+	}
+
+	for sect := Segtext.Sect; sect != nil; sect = sect.Next {
+		machoshbits(ms, sect, "__TEXT")
+	}
+
+	/* data */
+	if Linkmode != LinkExternal {
+		w := int64(Segdata.Length)
+		ms = newMachoSeg("__DATA", 20)
+		ms.vaddr = uint64(va) + uint64(v)
+		ms.vsize = uint64(w)
+		ms.fileoffset = uint64(v)
+		ms.filesize = Segdata.Filelen
+		ms.prot1 = 3
+		ms.prot2 = 3
+	}
+
+	for sect := Segdata.Sect; sect != nil; sect = sect.Next {
+		machoshbits(ms, sect, "__DATA")
+	}
+
+	if Linkmode != LinkExternal {
+		switch Thearch.Thechar {
+		default:
+			Exitf("unknown macho architecture: %v", Thearch.Thechar)
+
+		case '5':
+			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.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() >> 32)
+
+		case '7':
+			ml := newMachoLoad(5, 68+2)          /* unix thread */
+			ml.data[0] = 6                       /* thread type */
+			ml.data[1] = 68                      /* word count */
+			ml.data[2+64] = uint32(Entryvalue()) /* start pc */
+			ml.data[2+64+1] = uint32(Entryvalue() >> 32)
+
+		case '8':
+			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 */
+		}
+	}
+
+	if Debug['d'] == 0 {
+		// must match domacholink below
+		s1 := Linklookup(Ctxt, ".machosymtab", 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.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)
+			ms.filesize = ms.vsize
+			ms.prot1 = 7
+			ms.prot2 = 3
+		}
+
+		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 */
+		ml.data[3] = uint32(s4.Size)                               /* strsize */
+
+		machodysymtab()
+
+		if Linkmode != LinkExternal {
+			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++ {
+				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 */
+				ml.data[2] = 0                                           /* version */
+				ml.data[3] = 0                                           /* compatibility version */
+				stringtouint32(ml.data[4:], dylib[i])
+			}
+		}
+	}
+
+	// TODO: dwarf headers go in ms too
+	if Debug['s'] == 0 {
+		dwarfaddmachoheaders(ms)
+	}
+
+	a := machowrite()
+	if int32(a) > HEADR {
+		Exitf("HEADR too small: %d > %d", a, HEADR)
+	}
+}
+
+func symkind(s *LSym) int {
+	if s.Type == obj.SDYNIMPORT {
+		return SymKindUndef
+	}
+	if s.Cgoexport != 0 {
+		return SymKindExtdef
+	}
+	return SymKindLocal
+}
+
+func addsym(s *LSym, name string, type_ int, addr int64, size int64, ver int, gotype *LSym) {
+	if s == nil {
+		return
+	}
+
+	switch type_ {
+	default:
+		return
+
+	case 'D', 'B', 'T':
+		break
+	}
+
+	if sortsym != nil {
+		sortsym[nsortsym] = s
+		nkind[symkind(s)]++
+	}
+
+	nsortsym++
+}
+
+type machoscmp []*LSym
+
+func (x machoscmp) Len() int {
+	return len(x)
+}
+
+func (x machoscmp) Swap(i, j int) {
+	x[i], x[j] = x[j], x[i]
+}
+
+func (x machoscmp) Less(i, j int) bool {
+	s1 := x[i]
+	s2 := x[j]
+
+	k1 := symkind(s1)
+	k2 := symkind(s2)
+	if k1 != k2 {
+		return k1-k2 < 0
+	}
+
+	return stringsCompare(s1.Extname, s2.Extname) < 0
+}
+
+func machogenasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) {
+	genasmsym(put)
+	for s := Ctxt.Allsym; s != nil; s = s.Allsym {
+		if s.Type == obj.SDYNIMPORT || s.Type == obj.SHOSTOBJ {
+			if s.Reachable {
+				put(s, "", 'D', 0, 0, 0, nil)
+			}
+		}
+	}
+}
+
+func machosymorder() {
+	// On Mac OS X Mountain Lion, we must sort exported symbols
+	// So we sort them here and pre-allocate dynid for them
+	// See https://golang.org/issue/4029
+	for i := 0; i < len(dynexp); i++ {
+		dynexp[i].Reachable = true
+	}
+	machogenasmsym(addsym)
+	sortsym = make([]*LSym, nsortsym)
+	nsortsym = 0
+	machogenasmsym(addsym)
+	sort.Sort(machoscmp(sortsym[:nsortsym]))
+	for i := 0; i < nsortsym; i++ {
+		sortsym[i].Dynid = int32(i)
+	}
+}
+
+func machosymtab() {
+	var s *LSym
+	var o *LSym
+	var p string
+
+	symtab := Linklookup(Ctxt, ".machosymtab", 0)
+	symstr := Linklookup(Ctxt, ".machosymstr", 0)
+
+	for i := 0; i < nsortsym; i++ {
+		s = sortsym[i]
+		Adduint32(Ctxt, symtab, uint32(symstr.Size))
+
+		// Only add _ to C symbols. Go symbols have dot in the name.
+		if !strings.Contains(s.Extname, ".") {
+			Adduint8(Ctxt, symstr, '_')
+		}
+
+		// replace "·" as ".", because DTrace cannot handle it.
+		if !strings.Contains(s.Extname, "·") {
+			Addstring(symstr, s.Extname)
+		} else {
+			for p = s.Extname; p != ""; p = p[1:] {
+				if uint8(p[0]) == 0xc2 && uint8((p[1:])[0]) == 0xb7 {
+					Adduint8(Ctxt, symstr, '.')
+					p = p[1:]
+				} else {
+					Adduint8(Ctxt, symstr, uint8(p[0]))
+				}
+			}
+
+			Adduint8(Ctxt, symstr, '\x00')
+		}
+
+		if s.Type == obj.SDYNIMPORT || s.Type == obj.SHOSTOBJ {
+			Adduint8(Ctxt, symtab, 0x01)                // type N_EXT, external symbol
+			Adduint8(Ctxt, symtab, 0)                   // no section
+			Adduint16(Ctxt, symtab, 0)                  // desc
+			adduintxx(Ctxt, symtab, 0, Thearch.Ptrsize) // no value
+		} else {
+			if s.Cgoexport != 0 {
+				Adduint8(Ctxt, symtab, 0x0f)
+			} else {
+				Adduint8(Ctxt, symtab, 0x0e)
+			}
+			o = s
+			for o.Outer != nil {
+				o = o.Outer
+			}
+			if o.Sect == nil {
+				Diag("missing section for %s", s.Name)
+				Adduint8(Ctxt, symtab, 0)
+			} else {
+				Adduint8(Ctxt, symtab, uint8(o.Sect.Extnum))
+			}
+			Adduint16(Ctxt, symtab, 0) // desc
+			adduintxx(Ctxt, symtab, uint64(Symaddr(s)), Thearch.Ptrsize)
+		}
+	}
+}
+
+func machodysymtab() {
+	ml := newMachoLoad(11, 18) /* LC_DYSYMTAB */
+
+	n := 0
+	ml.data[0] = uint32(n)                   /* ilocalsym */
+	ml.data[1] = uint32(nkind[SymKindLocal]) /* nlocalsym */
+	n += nkind[SymKindLocal]
+
+	ml.data[2] = uint32(n)                    /* iextdefsym */
+	ml.data[3] = uint32(nkind[SymKindExtdef]) /* nextdefsym */
+	n += nkind[SymKindExtdef]
+
+	ml.data[4] = uint32(n)                   /* iundefsym */
+	ml.data[5] = uint32(nkind[SymKindUndef]) /* nundefsym */
+
+	ml.data[6] = 0  /* tocoffset */
+	ml.data[7] = 0  /* ntoc */
+	ml.data[8] = 0  /* modtaboff */
+	ml.data[9] = 0  /* nmodtab */
+	ml.data[10] = 0 /* extrefsymoff */
+	ml.data[11] = 0 /* nextrefsyms */
+
+	// must match domacholink below
+	s1 := Linklookup(Ctxt, ".machosymtab", 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 */
+
+	ml.data[14] = 0 /* extreloff */
+	ml.data[15] = 0 /* nextrel */
+	ml.data[16] = 0 /* locreloff */
+	ml.data[17] = 0 /* nlocrel */
+}
+
+func Domacholink() int64 {
+	machosymtab()
+
+	// write data that will be linkedit section
+	s1 := Linklookup(Ctxt, ".machosymtab", 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
+	// to be code signed correctly.
+	//
+	// Apple's codesign_allocate (a helper utility for
+	// the codesign utility) can do this fine itself if
+	// it is run on a dynamic Mach-O binary.  However,
+	// when it is run on a pure (non-cgo) Go binary, where
+	// the linkedit section is mostly empty, it fails to
+	// account for the extra padding that it itself adds
+	// when adding the LC_CODE_SIGNATURE load command
+	// (which must be aligned on a 16-byte boundary).
+	//
+	// By forcing the linkedit section to end on a 16-byte
+	// boundary, codesign_allocate will not need to apply
+	// any alignment padding itself, working around the
+	// issue.
+	for s4.Size%16 != 0 {
+		Adduint8(Ctxt, s4, 0)
+	}
+
+	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))
+		Cseek(linkoff)
+
+		Cwrite(s1.P[:s1.Size])
+		Cwrite(s2.P[:s2.Size])
+		Cwrite(s3.P[:s3.Size])
+		Cwrite(s4.P[:s4.Size])
+	}
+
+	return Rnd(int64(size), int64(INITRND))
+}
+
+func machorelocsect(sect *Section, first *LSym) {
+	// 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
+		}
+		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 Thearch.Machoreloc1(r, int64(uint64(sym.Value+int64(r.Off))-sect.Vaddr)) < 0 {
+				Diag("unsupported obj reloc %d/%d to %s", r.Type, r.Siz, r.Sym.Name)
+			}
+		}
+	}
+
+	sect.Rellen = uint64(Cpos()) - sect.Reloff
+}
+
+func Machoemitreloc() {
+	for Cpos()&7 != 0 {
+		Cput(0)
+	}
+
+	machorelocsect(Segtext.Sect, Ctxt.Textp)
+	for sect := Segtext.Sect.Next; sect != nil; sect = sect.Next {
+		machorelocsect(sect, datap)
+	}
+	for sect := Segdata.Sect; sect != nil; sect = sect.Next {
+		machorelocsect(sect, datap)
+	}
+	dwarfemitreloc()
+}
diff --git a/src/cmd/link/internal/ld/macho_combine_dwarf.go b/src/cmd/link/internal/ld/macho_combine_dwarf.go
new file mode 100644
index 0000000..b5a5a8d
--- /dev/null
+++ b/src/cmd/link/internal/ld/macho_combine_dwarf.go
@@ -0,0 +1,370 @@
+// 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 ld
+
+import (
+	"bytes"
+	"debug/macho"
+	"encoding/binary"
+	"fmt"
+	"io"
+	"os"
+	"reflect"
+	"unsafe"
+)
+
+var fakedwarf, realdwarf, linkseg *macho.Segment
+var dwarfstart, linkstart int64
+var linkoffset uint32
+var machHeader *macho.FileHeader
+var mappedHeader []byte
+
+const (
+	LC_ID_DYLIB             = 0xd
+	LC_LOAD_DYLINKER        = 0xe
+	LC_PREBOUND_DYLIB       = 0x10
+	LC_LOAD_WEAK_DYLIB      = 0x18
+	LC_UUID                 = 0x1b
+	LC_RPATH                = 0x8000001c
+	LC_CODE_SIGNATURE       = 0x1d
+	LC_SEGMENT_SPLIT_INFO   = 0x1e
+	LC_REEXPORT_DYLIB       = 0x8000001f
+	LC_ENCRYPTION_INFO      = 0x21
+	LC_DYLD_INFO            = 0x22
+	LC_DYLD_INFO_ONLY       = 0x80000022
+	LC_VERSION_MIN_MACOSX   = 0x24
+	LC_VERSION_MIN_IPHONEOS = 0x25
+	LC_FUNCTION_STARTS      = 0x26
+	LC_MAIN                 = 0x80000028
+	LC_DATA_IN_CODE         = 0x29
+	LC_SOURCE_VERSION       = 0x2A
+	LC_DYLIB_CODE_SIGN_DRS  = 0x2B
+	LC_ENCRYPTION_INFO_64   = 0x2C
+
+	dwarfMinAlign = 6  // 64 = 1 << 6
+	pageAlign     = 12 // 4096 = 1 << 12
+)
+
+type loadCmd struct {
+	Cmd macho.LoadCmd
+	Len uint32
+}
+
+type dyldInfoCmd struct {
+	Cmd                      macho.LoadCmd
+	Len                      uint32
+	RebaseOff, RebaseLen     uint32
+	BindOff, BindLen         uint32
+	WeakBindOff, WeakBindLen uint32
+	LazyBindOff, LazyBindLen uint32
+	ExportOff, ExportLen     uint32
+}
+
+type linkEditDataCmd struct {
+	Cmd              macho.LoadCmd
+	Len              uint32
+	DataOff, DataLen uint32
+}
+
+type encryptionInfoCmd struct {
+	Cmd                macho.LoadCmd
+	Len                uint32
+	CryptOff, CryptLen uint32
+	CryptId            uint32
+}
+
+type loadCmdReader struct {
+	offset, next int64
+	f            *os.File
+	order        binary.ByteOrder
+}
+
+func (r *loadCmdReader) Next() (cmd loadCmd, err error) {
+	r.offset = r.next
+	if _, err = r.f.Seek(r.offset, 0); err != nil {
+		return
+	}
+	if err = binary.Read(r.f, r.order, &cmd); err != nil {
+		return
+	}
+	r.next = r.offset + int64(cmd.Len)
+	return
+}
+
+func (r loadCmdReader) ReadAt(offset int64, data interface{}) error {
+	if _, err := r.f.Seek(r.offset+offset, 0); err != nil {
+		return err
+	}
+	return binary.Read(r.f, r.order, data)
+}
+
+func (r loadCmdReader) WriteAt(offset int64, data interface{}) error {
+	if _, err := r.f.Seek(r.offset+offset, 0); err != nil {
+		return err
+	}
+	return binary.Write(r.f, r.order, data)
+}
+
+// machoCombineDwarf merges dwarf info generated by dsymutil into a macho executable.
+// With internal linking, DWARF is embedded into the executable, this lets us do the
+// same for external linking.
+// inexe is the path to the executable with no DWARF. It must have enough room in the macho
+// header to add the DWARF sections. (Use ld's -headerpad option)
+// dsym is the path to the macho file containing DWARF from dsymutil.
+// outexe is the path where the combined executable should be saved.
+func machoCombineDwarf(inexe, dsym, outexe string) error {
+	exef, err := os.Open(inexe)
+	if err != nil {
+		return err
+	}
+	dwarff, err := os.Open(dsym)
+	if err != nil {
+		return err
+	}
+	outf, err := os.Create(outexe)
+	if err != nil {
+		return err
+	}
+	outf.Chmod(0755)
+
+	exem, err := macho.NewFile(exef)
+	if err != nil {
+		return err
+	}
+	dwarfm, err := macho.NewFile(dwarff)
+	if err != nil {
+		return err
+	}
+
+	// The string table needs to be the last thing in the file
+	// for code signing to work. So we'll need to move the
+	// linkedit section, but all the others can be copied directly.
+	linkseg = exem.Segment("__LINKEDIT")
+	if linkseg == nil {
+		return fmt.Errorf("missing __LINKEDIT segment")
+	}
+
+	if _, err = exef.Seek(0, 0); err != nil {
+		return err
+	}
+	if _, err := io.CopyN(outf, exef, int64(linkseg.Offset)); err != nil {
+		return err
+	}
+
+	realdwarf = dwarfm.Segment("__DWARF")
+	if realdwarf == nil {
+		return fmt.Errorf("missing __DWARF segment")
+	}
+
+	// Now copy the dwarf data into the output.
+	maxalign := uint32(dwarfMinAlign) //
+	for _, sect := range dwarfm.Sections {
+		if sect.Align > maxalign {
+			maxalign = sect.Align
+		}
+	}
+	dwarfstart = machoCalcStart(realdwarf.Offset, linkseg.Offset, maxalign)
+	if _, err = outf.Seek(dwarfstart, 0); err != nil {
+		return err
+	}
+
+	if _, err = dwarff.Seek(int64(realdwarf.Offset), 0); err != nil {
+		return err
+	}
+	if _, err := io.CopyN(outf, dwarff, int64(realdwarf.Filesz)); err != nil {
+		return err
+	}
+
+	// And finally the linkedit section.
+	if _, err = exef.Seek(int64(linkseg.Offset), 0); err != nil {
+		return err
+	}
+	linkstart = machoCalcStart(linkseg.Offset, uint64(dwarfstart)+realdwarf.Filesz, pageAlign)
+	linkoffset = uint32(linkstart - int64(linkseg.Offset))
+	if _, err = outf.Seek(linkstart, 0); err != nil {
+		return err
+	}
+	if _, err := io.Copy(outf, exef); err != nil {
+		return err
+	}
+
+	// Now we need to update the headers.
+	cmdOffset := unsafe.Sizeof(exem.FileHeader)
+	is64bit := exem.Magic == macho.Magic64
+	if is64bit {
+		// mach_header_64 has one extra uint32.
+		cmdOffset += unsafe.Sizeof(exem.Magic)
+	}
+
+	textsect := exem.Section("__text")
+	if linkseg == nil {
+		return fmt.Errorf("missing __text section")
+	}
+
+	dwarfCmdOffset := int64(cmdOffset) + int64(exem.FileHeader.Cmdsz)
+	availablePadding := int64(textsect.Offset) - dwarfCmdOffset
+	if availablePadding < int64(realdwarf.Len) {
+		return fmt.Errorf("No room to add dwarf info. Need at least %d padding bytes, found %d", realdwarf.Len, availablePadding)
+	}
+	// First, copy the dwarf load command into the header
+	if _, err = outf.Seek(dwarfCmdOffset, 0); err != nil {
+		return err
+	}
+	if _, err := io.CopyN(outf, bytes.NewReader(realdwarf.Raw()), int64(realdwarf.Len)); err != nil {
+		return err
+	}
+
+	if _, err = outf.Seek(int64(unsafe.Offsetof(exem.FileHeader.Ncmd)), 0); err != nil {
+		return err
+	}
+	if err = binary.Write(outf, exem.ByteOrder, exem.Ncmd+1); err != nil {
+		return err
+	}
+	if err = binary.Write(outf, exem.ByteOrder, exem.Cmdsz+realdwarf.Len); err != nil {
+		return err
+	}
+
+	reader := loadCmdReader{next: int64(cmdOffset), f: outf, order: exem.ByteOrder}
+	for i := uint32(0); i < exem.Ncmd; i++ {
+		cmd, err := reader.Next()
+		if err != nil {
+			return err
+		}
+		switch cmd.Cmd {
+		case macho.LoadCmdSegment64:
+			err = machoUpdateSegment(reader, &macho.Segment64{}, &macho.Section64{})
+		case macho.LoadCmdSegment:
+			err = machoUpdateSegment(reader, &macho.Segment32{}, &macho.Section32{})
+		case LC_DYLD_INFO, LC_DYLD_INFO_ONLY:
+			err = machoUpdateLoadCommand(reader, &dyldInfoCmd{}, "RebaseOff", "BindOff", "WeakBindOff", "LazyBindOff", "ExportOff")
+		case macho.LoadCmdSymtab:
+			err = machoUpdateLoadCommand(reader, &macho.SymtabCmd{}, "Symoff", "Stroff")
+		case macho.LoadCmdDysymtab:
+			err = machoUpdateLoadCommand(reader, &macho.DysymtabCmd{}, "Tocoffset", "Modtaboff", "Extrefsymoff", "Indirectsymoff", "Extreloff", "Locreloff")
+		case LC_CODE_SIGNATURE, LC_SEGMENT_SPLIT_INFO, LC_FUNCTION_STARTS, LC_DATA_IN_CODE, LC_DYLIB_CODE_SIGN_DRS:
+			err = machoUpdateLoadCommand(reader, &linkEditDataCmd{}, "DataOff")
+		case LC_ENCRYPTION_INFO, LC_ENCRYPTION_INFO_64:
+			err = machoUpdateLoadCommand(reader, &encryptionInfoCmd{}, "CryptOff")
+		case macho.LoadCmdDylib, macho.LoadCmdThread, macho.LoadCmdUnixThread, LC_PREBOUND_DYLIB, LC_UUID, LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS, LC_SOURCE_VERSION, LC_MAIN, LC_LOAD_DYLINKER, LC_LOAD_WEAK_DYLIB, LC_REEXPORT_DYLIB, LC_RPATH, LC_ID_DYLIB:
+			// Nothing to update
+		default:
+			err = fmt.Errorf("Unknown load command 0x%x (%s)\n", int(cmd.Cmd), cmd.Cmd)
+		}
+		if err != nil {
+			return err
+		}
+	}
+	return machoUpdateDwarfHeader(&reader)
+}
+
+// machoUpdateSegment updates the load command for a moved segment.
+// Only the linkedit segment should move, and it should have 0 sections.
+// seg should be a macho.Segment32 or macho.Segment64 as appropriate.
+// sect should be a macho.Section32 or macho.Section64 as appropriate.
+func machoUpdateSegment(r loadCmdReader, seg, sect interface{}) error {
+	if err := r.ReadAt(0, seg); err != nil {
+		return err
+	}
+	segValue := reflect.ValueOf(seg)
+	offset := reflect.Indirect(segValue).FieldByName("Offset")
+
+	// Only the linkedit segment moved, any thing before that is fine.
+	if offset.Uint() < linkseg.Offset {
+		return nil
+	}
+	offset.SetUint(offset.Uint() + uint64(linkoffset))
+	if err := r.WriteAt(0, seg); err != nil {
+		return err
+	}
+	// There shouldn't be any sections, but just to make sure...
+	return machoUpdateSections(r, segValue, reflect.ValueOf(sect), uint64(linkoffset))
+}
+
+func machoUpdateSections(r loadCmdReader, seg, sect reflect.Value, delta uint64) error {
+	iseg := reflect.Indirect(seg)
+	nsect := iseg.FieldByName("Nsect").Uint()
+	if nsect == 0 {
+		return nil
+	}
+	sectOffset := int64(iseg.Type().Size())
+
+	isect := reflect.Indirect(sect)
+	offsetField := isect.FieldByName("Offset")
+	reloffField := isect.FieldByName("Reloff")
+	sectSize := int64(isect.Type().Size())
+	for i := uint64(0); i < nsect; i++ {
+		if err := r.ReadAt(sectOffset, sect.Interface()); err != nil {
+			return err
+		}
+		if offsetField.Uint() != 0 {
+			offsetField.SetUint(offsetField.Uint() + delta)
+		}
+		if reloffField.Uint() != 0 {
+			reloffField.SetUint(reloffField.Uint() + delta)
+		}
+		if err := r.WriteAt(sectOffset, sect.Interface()); err != nil {
+			return err
+		}
+		sectOffset += sectSize
+	}
+	return nil
+}
+
+// machoUpdateDwarfHeader updates the DWARF segment load command.
+func machoUpdateDwarfHeader(r *loadCmdReader) error {
+	var seg, sect interface{}
+	cmd, err := r.Next()
+	if err != nil {
+		return err
+	}
+	if cmd.Cmd == macho.LoadCmdSegment64 {
+		seg = new(macho.Segment64)
+		sect = new(macho.Section64)
+	} else {
+		seg = new(macho.Segment32)
+		sect = new(macho.Section32)
+	}
+	if err := r.ReadAt(0, seg); err != nil {
+		return err
+	}
+	segValue := reflect.ValueOf(seg)
+	offset := reflect.Indirect(segValue).FieldByName("Offset")
+
+	delta := uint64(dwarfstart) - realdwarf.Offset
+	offset.SetUint(offset.Uint() + delta)
+	if err := r.WriteAt(0, seg); err != nil {
+		return err
+	}
+	return machoUpdateSections(*r, segValue, reflect.ValueOf(sect), delta)
+}
+
+func machoUpdateLoadCommand(r loadCmdReader, cmd interface{}, fields ...string) error {
+	if err := r.ReadAt(0, cmd); err != nil {
+		return err
+	}
+	value := reflect.Indirect(reflect.ValueOf(cmd))
+
+	for _, name := range fields {
+		field := value.FieldByName(name)
+		fieldval := field.Uint()
+		if fieldval >= linkseg.Offset {
+			field.SetUint(fieldval + uint64(linkoffset))
+		}
+	}
+	if err := r.WriteAt(0, cmd); err != nil {
+		return err
+	}
+	return nil
+}
+
+func machoCalcStart(origAddr, newAddr uint64, alignExp uint32) int64 {
+	align := uint64(1 << alignExp)
+	if (origAddr % align) == (newAddr % align) {
+		return int64(newAddr)
+	}
+	padding := (align - (newAddr % align))
+	padding += origAddr % align
+	return int64(padding + newAddr)
+}
diff --git a/src/cmd/link/internal/ld/objfile.go b/src/cmd/link/internal/ld/objfile.go
new file mode 100644
index 0000000..36a65ba
--- /dev/null
+++ b/src/cmd/link/internal/ld/objfile.go
@@ -0,0 +1,482 @@
+// 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 ld
+
+// Writing and reading 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.
+
+import (
+	"bytes"
+	"cmd/internal/obj"
+	"fmt"
+	"log"
+	"strconv"
+	"strings"
+)
+
+const (
+	startmagic = "\x00\x00go13ld"
+	endmagic   = "\xff\xffgo13ld"
+)
+
+func ldobjfile(ctxt *Link, f *obj.Biobuf, pkg string, length int64, pn string) {
+	start := obj.Boffset(f)
+	ctxt.Version++
+	var buf [8]uint8
+	obj.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 := obj.Bgetc(f)
+	if c != 1 {
+		log.Fatalf("%s: invalid file version number %d", pn, c)
+	}
+
+	var lib string
+	for {
+		lib = rdstring(f)
+		if lib == "" {
+			break
+		}
+		addlib(ctxt, pkg, pn, lib)
+	}
+
+	for {
+		c, err := f.Peek(1)
+		if err != nil {
+			log.Fatalf("%s: peeking: %v", pn, err)
+		}
+		if c[0] == 0xff {
+			break
+		}
+		readsym(ctxt, f, pkg, pn)
+	}
+
+	buf = [8]uint8{}
+	obj.Bread(f, buf[:])
+	if string(buf[:]) != endmagic {
+		log.Fatalf("%s: invalid file end", pn)
+	}
+
+	if obj.Boffset(f) != start+length {
+		log.Fatalf("%s: unexpected end at %d, want %d", pn, int64(obj.Boffset(f)), int64(start+length))
+	}
+}
+
+var readsym_ndup int
+
+func readsym(ctxt *Link, f *obj.Biobuf, pkg string, pn string) {
+	if obj.Bgetc(f) != 0xfe {
+		log.Fatalf("readsym out of sync")
+	}
+	t := rdint(f)
+	name := expandpkg(rdstring(f), pkg)
+	v := rdint(f)
+	if v != 0 && v != 1 {
+		log.Fatalf("invalid symbol version %d", v)
+	}
+	flags := rdint(f)
+	dupok := flags & 1
+	local := false
+	if flags&2 != 0 {
+		local = true
+	}
+	size := rdint(f)
+	typ := rdsym(ctxt, f, pkg)
+	data := rddata(f)
+	nreloc := rdint(f)
+
+	if v != 0 {
+		v = ctxt.Version
+	}
+	s := Linklookup(ctxt, name, v)
+	var dup *LSym
+	if s.Type != 0 && s.Type != obj.SXREF {
+		if (t == obj.SDATA || t == obj.SBSS || t == obj.SNOPTRBSS) && len(data) == 0 && nreloc == 0 {
+			if s.Size < int64(size) {
+				s.Size = int64(size)
+			}
+			if typ != nil && s.Gotype == nil {
+				s.Gotype = typ
+			}
+			return
+		}
+
+		if (s.Type == obj.SDATA || s.Type == obj.SBSS || s.Type == obj.SNOPTRBSS) && len(s.P) == 0 && len(s.R) == 0 {
+			goto overwrite
+		}
+		if s.Type != obj.SBSS && s.Type != obj.SNOPTRBSS && dupok == 0 && s.Dupok == 0 {
+			log.Fatalf("duplicate symbol %s (types %d and %d) in %s and %s", s.Name, s.Type, t, s.File, pn)
+		}
+		if len(s.P) > 0 {
+			dup = s
+			s = linknewsym(ctxt, ".dup", readsym_ndup)
+			readsym_ndup++ // scratch
+		}
+	}
+
+overwrite:
+	s.File = pkg
+	s.Dupok = uint8(dupok)
+	if t == obj.SXREF {
+		log.Fatalf("bad sxref")
+	}
+	if t == 0 {
+		log.Fatalf("missing type for %s in %s", name, pn)
+	}
+	if t == obj.SBSS && (s.Type == obj.SRODATA || s.Type == obj.SNOPTRBSS) {
+		t = int(s.Type)
+	}
+	s.Type = int16(t)
+	if s.Size < int64(size) {
+		s.Size = int64(size)
+	}
+	s.Local = local
+	if typ != nil { // if bss sym defined multiple times, take type from any one def
+		s.Gotype = typ
+	}
+	if dup != nil && typ != nil {
+		dup.Gotype = typ
+	}
+	s.P = data
+	s.P = s.P[:len(data)]
+	if nreloc > 0 {
+		s.R = make([]Reloc, nreloc)
+		s.R = s.R[:nreloc]
+		var r *Reloc
+		for i := 0; i < nreloc; i++ {
+			r = &s.R[i]
+			r.Off = rdint32(f)
+			r.Siz = rduint8(f)
+			r.Type = rdint32(f)
+			r.Add = rdint64(f)
+			rdint64(f) // Xadd, ignored
+			r.Sym = rdsym(ctxt, f, pkg)
+			rdsym(ctxt, f, pkg) // Xsym, ignored
+		}
+	}
+
+	if len(s.P) > 0 && dup != nil && len(dup.P) > 0 && strings.HasPrefix(s.Name, "gclocals·") {
+		// content-addressed garbage collection liveness bitmap symbol.
+		// double check for hash collisions.
+		if !bytes.Equal(s.P, dup.P) {
+			log.Fatalf("dupok hash collision for %s in %s and %s", s.Name, s.File, pn)
+		}
+	}
+
+	if s.Type == obj.STEXT {
+		s.Args = rdint32(f)
+		s.Locals = rdint32(f)
+		s.Nosplit = rduint8(f)
+		v := rdint(f)
+		s.Leaf = uint8(v & 1)
+		s.Cfunc = uint8(v & 2)
+		n := rdint(f)
+		var a *Auto
+		for i := 0; i < n; i++ {
+			a = new(Auto)
+			a.Asym = rdsym(ctxt, f, pkg)
+			a.Aoffset = rdint32(f)
+			a.Name = rdint16(f)
+			a.Gotype = rdsym(ctxt, f, pkg)
+			a.Link = s.Autom
+			s.Autom = a
+		}
+
+		s.Pcln = new(Pcln)
+		pc := s.Pcln
+		pc.Pcsp.P = rddata(f)
+		pc.Pcfile.P = rddata(f)
+		pc.Pcline.P = rddata(f)
+		n = rdint(f)
+		pc.Pcdata = make([]Pcdata, n)
+		pc.Npcdata = n
+		for i := 0; i < n; i++ {
+			pc.Pcdata[i].P = rddata(f)
+		}
+		n = rdint(f)
+		pc.Funcdata = make([]*LSym, n)
+		pc.Funcdataoff = make([]int64, n)
+		pc.Nfuncdata = n
+		for i := 0; i < n; i++ {
+			pc.Funcdata[i] = rdsym(ctxt, f, pkg)
+		}
+		for i := 0; i < n; i++ {
+			pc.Funcdataoff[i] = rdint64(f)
+		}
+		n = rdint(f)
+		pc.File = make([]*LSym, n)
+		pc.Nfile = n
+		for i := 0; i < n; i++ {
+			pc.File[i] = rdsym(ctxt, f, pkg)
+		}
+
+		if dup == nil {
+			if s.Onlist != 0 {
+				log.Fatalf("symbol %s listed multiple times", s.Name)
+			}
+			s.Onlist = 1
+			if ctxt.Etextp != nil {
+				ctxt.Etextp.Next = s
+			} else {
+				ctxt.Textp = s
+			}
+			ctxt.Etextp = s
+		}
+	}
+
+	if ctxt.Debugasm != 0 {
+		fmt.Fprintf(ctxt.Bso, "%s ", s.Name)
+		if s.Version != 0 {
+			fmt.Fprintf(ctxt.Bso, "v=%d ", s.Version)
+		}
+		if s.Type != 0 {
+			fmt.Fprintf(ctxt.Bso, "t=%d ", s.Type)
+		}
+		if s.Dupok != 0 {
+			fmt.Fprintf(ctxt.Bso, "dupok ")
+		}
+		if s.Cfunc != 0 {
+			fmt.Fprintf(ctxt.Bso, "cfunc ")
+		}
+		if s.Nosplit != 0 {
+			fmt.Fprintf(ctxt.Bso, "nosplit ")
+		}
+		fmt.Fprintf(ctxt.Bso, "size=%d value=%d", int64(s.Size), int64(s.Value))
+		if s.Type == obj.STEXT {
+			fmt.Fprintf(ctxt.Bso, " args=%#x locals=%#x", uint64(s.Args), uint64(s.Locals))
+		}
+		fmt.Fprintf(ctxt.Bso, "\n")
+		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])
+			}
+			for ; j < i+16; j++ {
+				fmt.Fprintf(ctxt.Bso, "   ")
+			}
+			fmt.Fprintf(ctxt.Bso, "  ")
+			for j = i; j < i+16 && j < len(s.P); j++ {
+				c = int(s.P[j])
+				if ' ' <= c && c <= 0x7e {
+					fmt.Fprintf(ctxt.Bso, "%c", c)
+				} else {
+					fmt.Fprintf(ctxt.Bso, ".")
+				}
+			}
+
+			fmt.Fprintf(ctxt.Bso, "\n")
+			i += 16
+		}
+
+		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))
+		}
+	}
+}
+
+func rdint64(f *obj.Biobuf) int64 {
+	var c int
+
+	uv := uint64(0)
+	for shift := 0; ; shift += 7 {
+		if shift >= 64 {
+			log.Fatalf("corrupt input")
+		}
+		c = obj.Bgetc(f)
+		uv |= uint64(c&0x7F) << uint(shift)
+		if c&0x80 == 0 {
+			break
+		}
+	}
+
+	return int64(uv>>1) ^ (int64(uint64(uv)<<63) >> 63)
+}
+
+func rdint(f *obj.Biobuf) int {
+	n := rdint64(f)
+	if int64(int(n)) != n {
+		log.Panicf("%v out of range for int", n)
+	}
+	return int(n)
+}
+
+func rdint32(f *obj.Biobuf) int32 {
+	n := rdint64(f)
+	if int64(int32(n)) != n {
+		log.Panicf("%v out of range for int32", n)
+	}
+	return int32(n)
+}
+
+func rdint16(f *obj.Biobuf) int16 {
+	n := rdint64(f)
+	if int64(int16(n)) != n {
+		log.Panicf("%v out of range for int16", n)
+	}
+	return int16(n)
+}
+
+func rduint8(f *obj.Biobuf) uint8 {
+	n := rdint64(f)
+	if int64(uint8(n)) != n {
+		log.Panicf("%v out of range for uint8", n)
+	}
+	return uint8(n)
+}
+
+func rdstring(f *obj.Biobuf) string {
+	n := rdint64(f)
+	p := make([]byte, n)
+	obj.Bread(f, p)
+	return string(p)
+}
+
+func rddata(f *obj.Biobuf) []byte {
+	n := rdint64(f)
+	p := make([]byte, n)
+	obj.Bread(f, p)
+	return p
+}
+
+var symbuf []byte
+
+func rdsym(ctxt *Link, f *obj.Biobuf, pkg string) *LSym {
+	n := rdint(f)
+	if n == 0 {
+		rdint64(f)
+		return nil
+	}
+
+	if len(symbuf) < n {
+		symbuf = make([]byte, n)
+	}
+	obj.Bread(f, symbuf[:n])
+	p := string(symbuf[:n])
+	v := rdint(f)
+	if v != 0 {
+		v = ctxt.Version
+	}
+	s := Linklookup(ctxt, expandpkg(p, pkg), v)
+
+	if v == 0 && s.Name[0] == '$' && s.Type == 0 {
+		if strings.HasPrefix(s.Name, "$f32.") {
+			x, _ := strconv.ParseUint(s.Name[5:], 16, 32)
+			i32 := int32(x)
+			s.Type = obj.SRODATA
+			s.Local = true
+			Adduint32(ctxt, s, uint32(i32))
+			s.Reachable = false
+		} else if strings.HasPrefix(s.Name, "$f64.") || strings.HasPrefix(s.Name, "$i64.") {
+			x, _ := strconv.ParseUint(s.Name[5:], 16, 64)
+			i64 := int64(x)
+			s.Type = obj.SRODATA
+			s.Local = true
+			Adduint64(ctxt, s, uint64(i64))
+			s.Reachable = false
+		}
+	}
+	if v == 0 && strings.HasPrefix(s.Name, "runtime.gcbits.") {
+		s.Local = true
+	}
+	return s
+}
diff --git a/src/cmd/link/internal/ld/pcln.go b/src/cmd/link/internal/ld/pcln.go
new file mode 100644
index 0000000..6697762
--- /dev/null
+++ b/src/cmd/link/internal/ld/pcln.go
@@ -0,0 +1,471 @@
+// 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 ld
+
+import (
+	"cmd/internal/obj"
+	"fmt"
+	"log"
+)
+
+// funcpctab writes to dst a pc-value table mapping the code in func to the values
+// returned by valfunc parameterized by arg. The invocation of valfunc to update the
+// current value is, for each p,
+//
+//	val = valfunc(func, val, p, 0, arg);
+//	record val as value at p->pc;
+//	val = valfunc(func, val, p, 1, arg);
+//
+// where func is the function, val is the current value, p is the instruction being
+// considered, and arg can be used to further parameterize valfunc.
+
+// pctofileline computes either the file number (arg == 0)
+// or the line number (arg == 1) to use at p.
+// Because p->lineno applies to p, phase == 0 (before p)
+// takes care of the update.
+
+// pctospadj computes the sp adjustment in effect.
+// It is oldval plus any adjustment made by p itself.
+// The adjustment by p takes effect only after p, so we
+// apply the change during phase == 1.
+
+// pctopcdata computes the pcdata value in effect at p.
+// A PCDATA instruction sets the value in effect at future
+// non-PCDATA instructions.
+// Since PCDATA instructions have no width in the final code,
+// it does not matter which phase we use for the update.
+
+// iteration over encoded pcdata tables.
+
+func getvarint(pp *[]byte) uint32 {
+	v := uint32(0)
+	p := *pp
+	for shift := 0; ; shift += 7 {
+		v |= uint32(p[0]&0x7F) << uint(shift)
+		tmp4 := p
+		p = p[1:]
+		if tmp4[0]&0x80 == 0 {
+			break
+		}
+	}
+
+	*pp = p
+	return v
+}
+
+func pciternext(it *Pciter) {
+	it.pc = it.nextpc
+	if it.done != 0 {
+		return
+	}
+	if -cap(it.p) >= -cap(it.d.P[len(it.d.P):]) {
+		it.done = 1
+		return
+	}
+
+	// value delta
+	v := getvarint(&it.p)
+
+	if v == 0 && it.start == 0 {
+		it.done = 1
+		return
+	}
+
+	it.start = 0
+	dv := int32(v>>1) ^ (int32(v<<31) >> 31)
+	it.value += dv
+
+	// pc delta
+	v = getvarint(&it.p)
+
+	it.nextpc = it.pc + v*it.pcscale
+}
+
+func pciterinit(ctxt *Link, it *Pciter, d *Pcdata) {
+	it.d = *d
+	it.p = it.d.P
+	it.pc = 0
+	it.nextpc = 0
+	it.value = -1
+	it.start = 1
+	it.done = 0
+	it.pcscale = uint32(ctxt.Arch.Minlc)
+	pciternext(it)
+}
+
+// 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.
+
+func addvarint(d *Pcdata, val uint32) {
+	n := int32(0)
+	for v := val; v >= 0x80; v >>= 7 {
+		n++
+	}
+	n++
+
+	old := len(d.P)
+	for cap(d.P) < len(d.P)+int(n) {
+		d.P = append(d.P[:cap(d.P)], 0)
+	}
+	d.P = d.P[:old+int(n)]
+
+	p := d.P[old:]
+	var v uint32
+	for v = val; v >= 0x80; v >>= 7 {
+		p[0] = byte(v | 0x80)
+		p = p[1:]
+	}
+	p[0] = byte(v)
+}
+
+func addpctab(ftab *LSym, off int32, d *Pcdata) int32 {
+	var start int32
+	if len(d.P) > 0 {
+		start = int32(len(ftab.P))
+		Symgrow(Ctxt, ftab, int64(start)+int64(len(d.P)))
+		copy(ftab.P[start:], d.P)
+	}
+	return int32(setuint32(Ctxt, ftab, int64(off), uint32(start)))
+}
+
+func ftabaddstring(ftab *LSym, s string) int32 {
+	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 f *LSym
+
+	// Give files numbers.
+	for i := 0; i < len(files); i++ {
+		f = files[i]
+		if f.Type != obj.SFILEPATH {
+			ctxt.Nhistfile++
+			f.Value = int64(ctxt.Nhistfile)
+			f.Type = obj.SFILEPATH
+			f.Next = ctxt.Filesyms
+			ctxt.Filesyms = f
+		}
+	}
+
+	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
+
+		if oldval == -1 {
+			val = -1
+		} else {
+			if oldval < 0 || oldval >= int32(len(files)) {
+				log.Fatalf("bad pcdata %d", oldval)
+			}
+			val = int32(files[oldval].Value)
+		}
+
+		dv = val - newval
+		newval = val
+		v = (uint32(dv) << 1) ^ uint32(int32(dv>>31))
+		addvarint(&out, v)
+
+		// pc delta
+		addvarint(&out, (it.nextpc-it.pc)/it.pcscale)
+	}
+
+	// terminating value delta
+	addvarint(&out, 0)
+
+	*d = out
+}
+
+func container(s *LSym) int {
+	// We want to generate func table entries only for the "lowest level" symbols,
+	// not containers of subsymbols.
+	if s != nil && s.Type&obj.SCONTAINER != 0 {
+		return 1
+	}
+	return 0
+}
+
+// pclntab initializes the pclntab symbol with
+// runtime function and file name information.
+
+var pclntab_zpcln Pcln
+
+// These variables are used to initialize runtime.firstmoduledata, see symtab.go:symtab.
+var pclntabNfunc int32
+var pclntabFiletabOffset int32
+var pclntabPclntabOffset int32
+var pclntabFirstFunc *LSym
+var pclntabLastFunc *LSym
+
+func pclntab() {
+	funcdata_bytes := int64(0)
+	ftab := Linklookup(Ctxt, "runtime.pclntab", 0)
+	ftab.Type = obj.SPCLNTAB
+	ftab.Reachable = true
+
+	// See golang.org/s/go12symtab for the format. Briefly:
+	//	8-byte header
+	//	nfunc [thearch.ptrsize bytes]
+	//	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 := int32(0)
+
+	// Find container symbols, mark them with SCONTAINER
+	for Ctxt.Cursym = Ctxt.Textp; Ctxt.Cursym != nil; Ctxt.Cursym = Ctxt.Cursym.Next {
+		if Ctxt.Cursym.Outer != nil {
+			Ctxt.Cursym.Outer.Type |= obj.SCONTAINER
+		}
+	}
+
+	for Ctxt.Cursym = Ctxt.Textp; Ctxt.Cursym != nil; Ctxt.Cursym = Ctxt.Cursym.Next {
+		if container(Ctxt.Cursym) == 0 {
+			nfunc++
+		}
+	}
+
+	pclntabNfunc = nfunc
+	Symgrow(Ctxt, ftab, 8+int64(Thearch.Ptrsize)+int64(nfunc)*2*int64(Thearch.Ptrsize)+int64(Thearch.Ptrsize)+4)
+	setuint32(Ctxt, ftab, 0, 0xfffffffb)
+	setuint8(Ctxt, ftab, 6, uint8(Thearch.Minlc))
+	setuint8(Ctxt, ftab, 7, uint8(Thearch.Ptrsize))
+	setuintxx(Ctxt, ftab, 8, uint64(nfunc), int64(Thearch.Ptrsize))
+	pclntabPclntabOffset = int32(8 + Thearch.Ptrsize)
+
+	nfunc = 0
+	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 {
+			continue
+		}
+		pcln = Ctxt.Cursym.Pcln
+		if pcln == nil {
+			pcln = &pclntab_zpcln
+		}
+
+		if pclntabFirstFunc == nil {
+			pclntabFirstFunc = Ctxt.Cursym
+		}
+
+		funcstart = int32(len(ftab.P))
+		funcstart += int32(-len(ftab.P)) & (int32(Thearch.Ptrsize) - 1)
+
+		setaddr(Ctxt, ftab, 8+int64(Thearch.Ptrsize)+int64(nfunc)*2*int64(Thearch.Ptrsize), Ctxt.Cursym)
+		setuintxx(Ctxt, ftab, 8+int64(Thearch.Ptrsize)+int64(nfunc)*2*int64(Thearch.Ptrsize)+int64(Thearch.Ptrsize), uint64(funcstart), int64(Thearch.Ptrsize))
+
+		// fixed size of struct, checked below
+		off = funcstart
+
+		end = funcstart + int32(Thearch.Ptrsize) + 3*4 + 5*4 + int32(pcln.Npcdata)*4 + int32(pcln.Nfuncdata)*int32(Thearch.Ptrsize)
+		if pcln.Nfuncdata > 0 && (end&int32(Thearch.Ptrsize-1) != 0) {
+			end += 4
+		}
+		Symgrow(Ctxt, ftab, int64(end))
+
+		// entry uintptr
+		off = int32(setaddr(Ctxt, ftab, int64(off), Ctxt.Cursym))
+
+		// name int32
+		off = int32(setuint32(Ctxt, ftab, int64(off), uint32(ftabaddstring(ftab, Ctxt.Cursym.Name))))
+
+		// args int32
+		// TODO: Move into funcinfo.
+		off = int32(setuint32(Ctxt, ftab, int64(off), uint32(Ctxt.Cursym.Args)))
+
+		// frame int32
+		// 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)
+			if false {
+				// Sanity check the new numbering
+				for pciterinit(Ctxt, &it, &pcln.Pcfile); it.done == 0; pciternext(&it) {
+					if it.value < 1 || it.value > Ctxt.Nhistfile {
+						Diag("bad file number in pcfile: %d not in range [1, %d]\n", it.value, Ctxt.Nhistfile)
+						errorexit()
+					}
+				}
+			}
+		}
+
+		// pcdata
+		off = addpctab(ftab, off, &pcln.Pcsp)
+
+		off = addpctab(ftab, off, &pcln.Pcfile)
+		off = addpctab(ftab, off, &pcln.Pcline)
+		off = int32(setuint32(Ctxt, ftab, int64(off), uint32(pcln.Npcdata)))
+		off = int32(setuint32(Ctxt, ftab, int64(off), uint32(pcln.Nfuncdata)))
+		for i = 0; i < int32(pcln.Npcdata); i++ {
+			off = addpctab(ftab, off, &pcln.Pcdata[i])
+		}
+
+		// funcdata, must be pointer-aligned and we're only int32-aligned.
+		// Missing funcdata will be 0 (nil pointer).
+		if pcln.Nfuncdata > 0 {
+			if off&int32(Thearch.Ptrsize-1) != 0 {
+				off += 4
+			}
+			for i = 0; i < int32(pcln.Nfuncdata); i++ {
+				if pcln.Funcdata[i] == nil {
+					setuintxx(Ctxt, ftab, int64(off)+int64(Thearch.Ptrsize)*int64(i), uint64(pcln.Funcdataoff[i]), int64(Thearch.Ptrsize))
+				} else {
+					// TODO: Dedup.
+					funcdata_bytes += pcln.Funcdata[i].Size
+
+					setaddrplus(Ctxt, ftab, int64(off)+int64(Thearch.Ptrsize)*int64(i), pcln.Funcdata[i], pcln.Funcdataoff[i])
+				}
+			}
+
+			off += int32(pcln.Nfuncdata) * int32(Thearch.Ptrsize)
+		}
+
+		if off != end {
+			Diag("bad math in functab: funcstart=%d off=%d but end=%d (npcdata=%d nfuncdata=%d ptrsize=%d)", funcstart, off, end, pcln.Npcdata, pcln.Nfuncdata, Thearch.Ptrsize)
+			errorexit()
+		}
+
+		nfunc++
+	}
+
+	pclntabLastFunc = last
+	// Final entry of table is just end pc.
+	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)) & (int32(Thearch.Ptrsize) - 1)
+	pclntabFiletabOffset = start
+	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 {
+		setuint32(Ctxt, ftab, int64(start)+s.Value*4, uint32(ftabaddstring(ftab, s.Name)))
+	}
+
+	ftab.Size = int64(len(ftab.P))
+
+	if Debug['v'] != 0 {
+		fmt.Fprintf(&Bso, "%5.2f pclntab=%d bytes, funcdata total %d bytes\n", obj.Cputime(), int64(ftab.Size), int64(funcdata_bytes))
+	}
+}
+
+const (
+	BUCKETSIZE    = 256 * MINFUNC
+	SUBBUCKETS    = 16
+	SUBBUCKETSIZE = BUCKETSIZE / SUBBUCKETS
+	NOIDX         = 0x7fffffff
+)
+
+// findfunctab generates a lookup table to quickly find the containing
+// function for a pc.  See src/runtime/symtab.go:findfunc for details.
+func findfunctab() {
+	t := Linklookup(Ctxt, "runtime.findfunctab", 0)
+	t.Type = obj.SRODATA
+	t.Reachable = true
+	t.Local = true
+
+	// find min and max address
+	min := Ctxt.Textp.Value
+
+	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)
+
+	indexes := make([]int32, n)
+	for i := int32(0); i < n; i++ {
+		indexes[i] = NOIDX
+	}
+	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
+		}
+		p = s.Value
+		e = s.Next
+		for container(e) != 0 {
+			e = e.Next
+		}
+		if e != nil {
+			q = e.Value
+		} else {
+			q = max
+		}
+
+		//print("%d: [%lld %lld] %s\n", idx, p, q, s->name);
+		for ; p < q; p += SUBBUCKETSIZE {
+			i = int32((p - min) / SUBBUCKETSIZE)
+			if indexes[i] > idx {
+				indexes[i] = idx
+			}
+		}
+
+		i = int32((q - 1 - min) / SUBBUCKETSIZE)
+		if indexes[i] > idx {
+			indexes[i] = idx
+		}
+		idx++
+	}
+
+	// allocate table
+	nbuckets := int32((max - min + BUCKETSIZE - 1) / BUCKETSIZE)
+
+	Symgrow(Ctxt, t, 4*int64(nbuckets)+int64(n))
+
+	// fill in table
+	var base int32
+	var j int32
+	for i := int32(0); i < nbuckets; i++ {
+		base = indexes[i*SUBBUCKETS]
+		if base == NOIDX {
+			Diag("hole in findfunctab")
+		}
+		setuint32(Ctxt, t, int64(i)*(4+SUBBUCKETS), uint32(base))
+		for j = 0; j < SUBBUCKETS && i*SUBBUCKETS+j < n; j++ {
+			idx = indexes[i*SUBBUCKETS+j]
+			if idx == NOIDX {
+				Diag("hole in findfunctab")
+			}
+			if idx-base >= 256 {
+				Diag("too many functions in a findfunc bucket! %d/%d %d %d", i, nbuckets, j, idx-base)
+			}
+
+			setuint8(Ctxt, t, int64(i)*(4+SUBBUCKETS)+4+int64(j), uint8(idx-base))
+		}
+	}
+}
diff --git a/src/cmd/link/internal/ld/pe.go b/src/cmd/link/internal/ld/pe.go
new file mode 100644
index 0000000..4a7d710
--- /dev/null
+++ b/src/cmd/link/internal/ld/pe.go
@@ -0,0 +1,1259 @@
+// 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 ld
+
+import (
+	"cmd/internal/obj"
+	"encoding/binary"
+	"fmt"
+	"sort"
+	"strconv"
+	"strings"
+)
+
+type IMAGE_FILE_HEADER struct {
+	Machine              uint16
+	NumberOfSections     uint16
+	TimeDateStamp        uint32
+	PointerToSymbolTable uint32
+	NumberOfSymbols      uint32
+	SizeOfOptionalHeader uint16
+	Characteristics      uint16
+}
+
+type IMAGE_DATA_DIRECTORY struct {
+	VirtualAddress uint32
+	Size           uint32
+}
+
+type IMAGE_OPTIONAL_HEADER struct {
+	Magic                       uint16
+	MajorLinkerVersion          uint8
+	MinorLinkerVersion          uint8
+	SizeOfCode                  uint32
+	SizeOfInitializedData       uint32
+	SizeOfUninitializedData     uint32
+	AddressOfEntryPoint         uint32
+	BaseOfCode                  uint32
+	BaseOfData                  uint32
+	ImageBase                   uint32
+	SectionAlignment            uint32
+	FileAlignment               uint32
+	MajorOperatingSystemVersion uint16
+	MinorOperatingSystemVersion uint16
+	MajorImageVersion           uint16
+	MinorImageVersion           uint16
+	MajorSubsystemVersion       uint16
+	MinorSubsystemVersion       uint16
+	Win32VersionValue           uint32
+	SizeOfImage                 uint32
+	SizeOfHeaders               uint32
+	CheckSum                    uint32
+	Subsystem                   uint16
+	DllCharacteristics          uint16
+	SizeOfStackReserve          uint32
+	SizeOfStackCommit           uint32
+	SizeOfHeapReserve           uint32
+	SizeOfHeapCommit            uint32
+	LoaderFlags                 uint32
+	NumberOfRvaAndSizes         uint32
+	DataDirectory               [16]IMAGE_DATA_DIRECTORY
+}
+
+type IMAGE_SECTION_HEADER struct {
+	Name                 [8]uint8
+	VirtualSize          uint32
+	VirtualAddress       uint32
+	SizeOfRawData        uint32
+	PointerToRawData     uint32
+	PointerToRelocations uint32
+	PointerToLineNumbers uint32
+	NumberOfRelocations  uint16
+	NumberOfLineNumbers  uint16
+	Characteristics      uint32
+}
+
+type IMAGE_IMPORT_DESCRIPTOR struct {
+	OriginalFirstThunk uint32
+	TimeDateStamp      uint32
+	ForwarderChain     uint32
+	Name               uint32
+	FirstThunk         uint32
+}
+
+type IMAGE_EXPORT_DIRECTORY struct {
+	Characteristics       uint32
+	TimeDateStamp         uint32
+	MajorVersion          uint16
+	MinorVersion          uint16
+	Name                  uint32
+	Base                  uint32
+	NumberOfFunctions     uint32
+	NumberOfNames         uint32
+	AddressOfFunctions    uint32
+	AddressOfNames        uint32
+	AddressOfNameOrdinals uint32
+}
+
+const (
+	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
+)
+
+const (
+	IMAGE_FILE_MACHINE_I386              = 0x14c
+	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
+	IMAGE_SCN_CNT_CODE                   = 0x00000020
+	IMAGE_SCN_CNT_INITIALIZED_DATA       = 0x00000040
+	IMAGE_SCN_CNT_UNINITIALIZED_DATA     = 0x00000080
+	IMAGE_SCN_MEM_EXECUTE                = 0x20000000
+	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
+	IMAGE_DIRECTORY_ENTRY_EXCEPTION      = 3
+	IMAGE_DIRECTORY_ENTRY_SECURITY       = 4
+	IMAGE_DIRECTORY_ENTRY_BASERELOC      = 5
+	IMAGE_DIRECTORY_ENTRY_DEBUG          = 6
+	IMAGE_DIRECTORY_ENTRY_COPYRIGHT      = 7
+	IMAGE_DIRECTORY_ENTRY_ARCHITECTURE   = 7
+	IMAGE_DIRECTORY_ENTRY_GLOBALPTR      = 8
+	IMAGE_DIRECTORY_ENTRY_TLS            = 9
+	IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG    = 10
+	IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT   = 11
+	IMAGE_DIRECTORY_ENTRY_IAT            = 12
+	IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT   = 13
+	IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR = 14
+	IMAGE_SUBSYSTEM_WINDOWS_GUI          = 2
+	IMAGE_SUBSYSTEM_WINDOWS_CUI          = 3
+)
+
+// X64
+type PE64_IMAGE_OPTIONAL_HEADER struct {
+	Magic                       uint16
+	MajorLinkerVersion          uint8
+	MinorLinkerVersion          uint8
+	SizeOfCode                  uint32
+	SizeOfInitializedData       uint32
+	SizeOfUninitializedData     uint32
+	AddressOfEntryPoint         uint32
+	BaseOfCode                  uint32
+	ImageBase                   uint64
+	SectionAlignment            uint32
+	FileAlignment               uint32
+	MajorOperatingSystemVersion uint16
+	MinorOperatingSystemVersion uint16
+	MajorImageVersion           uint16
+	MinorImageVersion           uint16
+	MajorSubsystemVersion       uint16
+	MinorSubsystemVersion       uint16
+	Win32VersionValue           uint32
+	SizeOfImage                 uint32
+	SizeOfHeaders               uint32
+	CheckSum                    uint32
+	Subsystem                   uint16
+	DllCharacteristics          uint16
+	SizeOfStackReserve          uint64
+	SizeOfStackCommit           uint64
+	SizeOfHeapReserve           uint64
+	SizeOfHeapCommit            uint64
+	LoaderFlags                 uint32
+	NumberOfRvaAndSizes         uint32
+	DataDirectory               [16]IMAGE_DATA_DIRECTORY
+}
+
+// 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.
+
+// PE (Portable Executable) file writing
+// http://www.microsoft.com/whdc/system/platform/firmware/PECOFF.mspx
+
+// DOS stub that prints out
+// "This program cannot be run in DOS mode."
+var dosstub = []uint8{
+	0x4d,
+	0x5a,
+	0x90,
+	0x00,
+	0x03,
+	0x00,
+	0x04,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0xff,
+	0xff,
+	0x00,
+	0x00,
+	0x8b,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x40,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x80,
+	0x00,
+	0x00,
+	0x00,
+	0x0e,
+	0x1f,
+	0xba,
+	0x0e,
+	0x00,
+	0xb4,
+	0x09,
+	0xcd,
+	0x21,
+	0xb8,
+	0x01,
+	0x4c,
+	0xcd,
+	0x21,
+	0x54,
+	0x68,
+	0x69,
+	0x73,
+	0x20,
+	0x70,
+	0x72,
+	0x6f,
+	0x67,
+	0x72,
+	0x61,
+	0x6d,
+	0x20,
+	0x63,
+	0x61,
+	0x6e,
+	0x6e,
+	0x6f,
+	0x74,
+	0x20,
+	0x62,
+	0x65,
+	0x20,
+	0x72,
+	0x75,
+	0x6e,
+	0x20,
+	0x69,
+	0x6e,
+	0x20,
+	0x44,
+	0x4f,
+	0x53,
+	0x20,
+	0x6d,
+	0x6f,
+	0x64,
+	0x65,
+	0x2e,
+	0x0d,
+	0x0d,
+	0x0a,
+	0x24,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+	0x00,
+}
+
+var rsrcsym *LSym
+
+var strtbl []byte
+
+var PESECTHEADR int32
+
+var PEFILEHEADR int32
+
+var pe64 int
+
+var pensect int
+
+var nextsectoff int
+
+var nextfileoff int
+
+var textsect int
+
+var datasect int
+
+var bsssect int
+
+var fh IMAGE_FILE_HEADER
+
+var oh IMAGE_OPTIONAL_HEADER
+
+var oh64 PE64_IMAGE_OPTIONAL_HEADER
+
+var sh [16]IMAGE_SECTION_HEADER
+
+var dd []IMAGE_DATA_DIRECTORY
+
+type Imp struct {
+	s       *LSym
+	off     uint64
+	next    *Imp
+	argsize int
+}
+
+type Dll struct {
+	name     string
+	nameoff  uint64
+	thunkoff uint64
+	ms       *Imp
+	next     *Dll
+}
+
+var dr *Dll
+
+var dexport [1024]*LSym
+
+var nexport int
+
+type COFFSym struct {
+	sym       *LSym
+	strtbloff int
+	sect      int
+	value     int64
+	typ       uint16
+}
+
+var coffsym []COFFSym
+
+var ncoffsym int
+
+func addpesection(name string, sectsize int, filesize int) *IMAGE_SECTION_HEADER {
+	if pensect == 16 {
+		Diag("too many sections")
+		errorexit()
+	}
+
+	h := &sh[pensect]
+	pensect++
+	copy(h.Name[:], name)
+	h.VirtualSize = uint32(sectsize)
+	h.VirtualAddress = uint32(nextsectoff)
+	nextsectoff = int(Rnd(int64(nextsectoff)+int64(sectsize), PESECTALIGN))
+	h.PointerToRawData = uint32(nextfileoff)
+	if filesize > 0 {
+		h.SizeOfRawData = uint32(Rnd(int64(filesize), PEFILEALIGN))
+		nextfileoff += int(h.SizeOfRawData)
+	}
+
+	return h
+}
+
+func chksectoff(h *IMAGE_SECTION_HEADER, off int64) {
+	if off != int64(h.PointerToRawData) {
+		Diag("%s.PointerToRawData = %#x, want %#x", cstring(h.Name[:]), uint64(int64(h.PointerToRawData)), uint64(off))
+		errorexit()
+	}
+}
+
+func chksectseg(h *IMAGE_SECTION_HEADER, s *Segment) {
+	if s.Vaddr-PEBASE != uint64(h.VirtualAddress) {
+		Diag("%s.VirtualAddress = %#x, want %#x", cstring(h.Name[:]), uint64(int64(h.VirtualAddress)), uint64(int64(s.Vaddr-PEBASE)))
+		errorexit()
+	}
+
+	if s.Fileoff != uint64(h.PointerToRawData) {
+		Diag("%s.PointerToRawData = %#x, want %#x", cstring(h.Name[:]), uint64(int64(h.PointerToRawData)), uint64(int64(s.Fileoff)))
+		errorexit()
+	}
+}
+
+func Peinit() {
+	var l int
+
+	switch Thearch.Thechar {
+	// 64-bit architectures
+	case '6':
+		pe64 = 1
+
+		l = binary.Size(&oh64)
+		dd = oh64.DataDirectory[:]
+
+	// 32-bit architectures
+	default:
+		l = binary.Size(&oh)
+
+		dd = oh.DataDirectory[:]
+	}
+
+	PEFILEHEADR = int32(Rnd(int64(len(dosstub)+binary.Size(&fh)+l+binary.Size(&sh)), PEFILEALIGN))
+	PESECTHEADR = int32(Rnd(int64(PEFILEHEADR), PESECTALIGN))
+	nextsectoff = int(PESECTHEADR)
+	nextfileoff = int(PEFILEHEADR)
+
+	// some mingw libs depend on this symbol, for example, FindPESectionByName
+	xdefine("__image_base__", obj.SDATA, PEBASE)
+
+	xdefine("_image_base__", obj.SDATA, PEBASE)
+}
+
+func pewrite() {
+	Cseek(0)
+	if Linkmode != LinkExternal {
+		Cwrite(dosstub)
+		strnput("PE", 4)
+	}
+
+	binary.Write(&coutbuf, binary.LittleEndian, &fh)
+
+	if pe64 != 0 {
+		binary.Write(&coutbuf, binary.LittleEndian, &oh64)
+	} else {
+		binary.Write(&coutbuf, binary.LittleEndian, &oh)
+	}
+	binary.Write(&coutbuf, binary.LittleEndian, sh[:pensect])
+}
+
+func strput(s string) {
+	coutbuf.WriteString(s)
+	Cput(0)
+	// string must be padded to even size
+	if (len(s)+1)%2 != 0 {
+		Cput(0)
+	}
+}
+
+func initdynimport() *Dll {
+	var d *Dll
+
+	dr = nil
+	var m *Imp
+	for s := Ctxt.Allsym; s != nil; s = s.Allsym {
+		if !s.Reachable || s.Type != obj.SDYNIMPORT {
+			continue
+		}
+		for d = dr; d != nil; d = d.next {
+			if d.name == s.Dynimplib {
+				m = new(Imp)
+				break
+			}
+		}
+
+		if d == nil {
+			d = new(Dll)
+			d.name = s.Dynimplib
+			d.next = dr
+			dr = d
+			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
+	}
+
+	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 = obj.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 = obj.SHOSTOBJ
+				r := Addrel(m.s)
+				r.Sym = dynSym
+				r.Off = 0
+				r.Siz = uint8(Thearch.Ptrsize)
+				r.Type = obj.R_ADDR
+			}
+		}
+	} else {
+		dynamic := Linklookup(Ctxt, ".windynamic", 0)
+		dynamic.Reachable = true
+		dynamic.Type = obj.SWINDOWS
+		for d := dr; d != nil; d = d.next {
+			for m = d.ms; m != nil; m = m.next {
+				m.s.Type = obj.SWINDOWS | obj.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)
+		}
+	}
+
+	return dr
+}
+
+// peimporteddlls returns the gcc command line argument to link all imported
+// DLLs.
+func peimporteddlls() []string {
+	var dlls []string
+
+	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 := uint64(0)
+
+	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 {
+		d.nameoff = uint64(Cpos()) - uint64(startoff)
+		strput(d.name)
+	}
+
+	// write function names
+	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
+			strput(m.s.Extname)
+		}
+	}
+
+	// write OriginalFirstThunks
+	oftbase := uint64(Cpos()) - uint64(startoff)
+
+	n = uint64(Cpos())
+	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 {
+				Vputl(m.off)
+			} else {
+				Lputl(uint32(m.off))
+			}
+		}
+
+		if pe64 != 0 {
+			Vputl(0)
+		} else {
+			Lputl(0)
+		}
+	}
+
+	// add pe section and pad it at the end
+	n = uint64(Cpos()) - uint64(startoff)
+
+	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()
+
+	// write FirstThunks (allocated in .data section)
+	ftbase := uint64(dynamic.Value) - uint64(datsect.VirtualAddress) - PEBASE
+
+	Cseek(int64(uint64(datsect.PointerToRawData) + ftbase))
+	for d := dr; d != nil; d = d.next {
+		for m = d.ms; m != nil; m = m.next {
+			if pe64 != 0 {
+				Vputl(m.off)
+			} else {
+				Lputl(uint32(m.off))
+			}
+		}
+
+		if pe64 != 0 {
+			Vputl(0)
+		} else {
+			Lputl(0)
+		}
+	}
+
+	// finally write import descriptor table
+	Cseek(startoff)
+
+	for d := dr; d != nil; d = d.next {
+		Lputl(uint32(uint64(isect.VirtualAddress) + oftbase + d.thunkoff))
+		Lputl(0)
+		Lputl(0)
+		Lputl(uint32(uint64(isect.VirtualAddress) + d.nameoff))
+		Lputl(uint32(uint64(datsect.VirtualAddress) + ftbase + d.thunkoff))
+	}
+
+	Lputl(0) //end
+	Lputl(0)
+	Lputl(0)
+	Lputl(0)
+	Lputl(0)
+
+	// update data directory
+	dd[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress = isect.VirtualAddress
+
+	dd[IMAGE_DIRECTORY_ENTRY_IMPORT].Size = isect.VirtualSize
+	dd[IMAGE_DIRECTORY_ENTRY_IAT].VirtualAddress = uint32(dynamic.Value - PEBASE)
+	dd[IMAGE_DIRECTORY_ENTRY_IAT].Size = uint32(dynamic.Size)
+
+	Cseek(endoff)
+}
+
+type pescmp []*LSym
+
+func (x pescmp) Len() int {
+	return len(x)
+}
+
+func (x pescmp) Swap(i, j int) {
+	x[i], x[j] = x[j], x[i]
+}
+
+func (x pescmp) Less(i, j int) bool {
+	s1 := x[i]
+	s2 := x[j]
+	return stringsCompare(s1.Extname, s2.Extname) < 0
+}
+
+func initdynexport() {
+	nexport = 0
+	for s := Ctxt.Allsym; s != nil; s = s.Allsym {
+		if !s.Reachable || s.Cgoexport&CgoExportDynamic == 0 {
+			continue
+		}
+		if nexport+1 > len(dexport) {
+			Diag("pe dynexport table is full")
+			errorexit()
+		}
+
+		dexport[nexport] = s
+		nexport++
+	}
+
+	sort.Sort(pescmp(dexport[:nexport]))
+}
+
+func addexports() {
+	var e IMAGE_EXPORT_DIRECTORY
+
+	size := binary.Size(&e) + 10*nexport + len(outfile) + 1
+	for i := 0; i < nexport; i++ {
+		size += len(dexport[i].Extname) + 1
+	}
+
+	if nexport == 0 {
+		return
+	}
+
+	sect := addpesection(".edata", size, size)
+	sect.Characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
+	chksectoff(sect, Cpos())
+	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
+
+	e.Characteristics = 0
+	e.MajorVersion = 0
+	e.MinorVersion = 0
+	e.NumberOfFunctions = uint32(nexport)
+	e.NumberOfNames = uint32(nexport)
+	e.Name = uint32(va+binary.Size(&e)) + uint32(nexport)*10 // Program names.
+	e.Base = 1
+	e.AddressOfFunctions = uint32(va_addr)
+	e.AddressOfNames = uint32(va_name)
+	e.AddressOfNameOrdinals = uint32(va_na)
+
+	// put IMAGE_EXPORT_DIRECTORY
+	binary.Write(&coutbuf, binary.LittleEndian, &e)
+
+	// put EXPORT Address Table
+	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)
+
+	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++ {
+		Wputl(uint16(i))
+	}
+
+	// put Names
+	strnput(outfile, len(outfile)+1)
+
+	for i := 0; i < nexport; i++ {
+		strnput(dexport[i].Extname, len(dexport[i].Extname)+1)
+	}
+	strnput("", int(sect.SizeOfRawData-uint32(size)))
+}
+
+// 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.Reachable = true
+	rel.Type = obj.SELFROSECT
+
+	initdynimport()
+	initdynexport()
+}
+
+func strtbladd(name string) int {
+	off := len(strtbl) + 4 // offset includes 4-byte length at beginning of table
+	strtbl = append(strtbl, name...)
+	strtbl = append(strtbl, 0)
+	return off
+}
+
+/*
+ * For more than 8 characters section names, name contains a slash (/) that is
+ * followed by an ASCII representation of a decimal number that is an offset into
+ * the string table.
+ * reference: pecoff_v8.docx Page 24.
+ * <http://www.microsoft.com/whdc/system/platform/firmware/PECOFFdwn.mspx>
+ */
+func newPEDWARFSection(name string, size int64) *IMAGE_SECTION_HEADER {
+	if size == 0 {
+		return nil
+	}
+
+	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) {
+	if s == nil {
+		return
+	}
+
+	if s.Sect == nil && type_ != 'U' {
+		return
+	}
+
+	switch type_ {
+	default:
+		return
+
+	case 'D', 'B', 'T', 'U':
+		break
+	}
+
+	if coffsym != nil {
+		// only windows/386 requires underscore prefix on external symbols
+		if Thearch.Thechar == '8' && Linkmode == LinkExternal && (s.Type == obj.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)
+		}
+		// 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 != obj.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
+			Diag("addpesym %#x", addr)
+		}
+	}
+
+	s.Dynid = int32(ncoffsym)
+	ncoffsym++
+}
+
+func pegenasmsym(put func(*LSym, string, int, int64, int64, int, *LSym)) {
+	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
+				put(s, s.Name, 'U', 0, int64(Thearch.Ptrsize), 0, nil)
+			}
+		}
+	}
+	genasmsym(put)
+}
+
+func addpesymtable() {
+	if Debug['s'] == 0 || Linkmode == LinkExternal {
+		ncoffsym = 0
+		pegenasmsym(addpesym)
+		coffsym = make([]COFFSym, ncoffsym)
+		ncoffsym = 0
+		pegenasmsym(addpesym)
+	}
+	size := len(strtbl) + 4 + 18*ncoffsym
+
+	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
+	var s *COFFSym
+	for i := 0; i < ncoffsym; i++ {
+		s = &coffsym[i]
+		if s.strtbloff == 0 {
+			strnput(s.sym.Name, 8)
+		} else {
+			Lputl(0)
+			Lputl(uint32(s.strtbloff))
+		}
+
+		Lputl(uint32(s.value))
+		Wputl(uint16(s.sect))
+		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++ {
+		Cput(uint8(strtbl[i]))
+	}
+	if Linkmode != LinkExternal {
+		strnput("", int(h.SizeOfRawData-uint32(size)))
+	}
+}
+
+func setpersrc(sym *LSym) {
+	if rsrcsym != nil {
+		Diag("too many .rsrc sections")
+	}
+
+	rsrcsym = sym
+}
+
+func addpersrc() {
+	if rsrcsym == nil {
+		return
+	}
+
+	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
+	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)
+
+		// 32-bit little-endian
+		p[0] = byte(val)
+
+		p[1] = byte(val >> 8)
+		p[2] = byte(val >> 16)
+		p[3] = byte(val >> 24)
+	}
+
+	Cwrite(rsrcsym.P)
+	strnput("", int(int64(h.SizeOfRawData)-rsrcsym.Size))
+
+	// update data directory
+	dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress = h.VirtualAddress
+
+	dd[IMAGE_DIRECTORY_ENTRY_RESOURCE].Size = h.VirtualSize
+}
+
+func Asmbpe() {
+	switch Thearch.Thechar {
+	default:
+		Exitf("unknown PE architecture: %v", Thearch.Thechar)
+	case '6':
+		fh.Machine = IMAGE_FILE_MACHINE_AMD64
+	case '8':
+		fh.Machine = IMAGE_FILE_MACHINE_I386
+	}
+
+	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
+	if Linkmode == LinkExternal {
+		// some data symbols (e.g. masks) end up in the .text section, and they normally
+		// expect larger alignment requirement than the default text section alignment.
+		t.Characteristics |= IMAGE_SCN_ALIGN_32BYTES
+	}
+	chksectseg(t, &Segtext)
+	textsect = 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))
+	if Linkmode != LinkExternal {
+		addimports(d)
+		addexports()
+	}
+	addpesymtable()
+	addpersrc()
+	if Linkmode == LinkExternal {
+		peemitreloc(t, d)
+	}
+
+	fh.NumberOfSections = uint16(pensect)
+
+	// Being able to produce identical output for identical input is
+	// much more beneficial than having build timestamp in the header.
+	fh.TimeDateStamp = 0
+
+	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 // PE32+
+	} else {
+		fh.SizeOfOptionalHeader = uint16(binary.Size(&oh))
+		fh.Characteristics |= IMAGE_FILE_32BIT_MACHINE
+		oh.Magic = 0x10b // PE32
+		oh.BaseOfData = d.VirtualAddress
+	}
+
+	// Fill out both oh64 and oh. We only use one. Oh well.
+	oh64.MajorLinkerVersion = 3
+
+	oh.MajorLinkerVersion = 3
+	oh64.MinorLinkerVersion = 0
+	oh.MinorLinkerVersion = 0
+	oh64.SizeOfCode = t.SizeOfRawData
+	oh.SizeOfCode = t.SizeOfRawData
+	oh64.SizeOfInitializedData = d.SizeOfRawData
+	oh.SizeOfInitializedData = d.SizeOfRawData
+	oh64.SizeOfUninitializedData = 0
+	oh.SizeOfUninitializedData = 0
+	if Linkmode != LinkExternal {
+		oh64.AddressOfEntryPoint = uint32(Entryvalue() - PEBASE)
+		oh.AddressOfEntryPoint = uint32(Entryvalue() - PEBASE)
+	}
+	oh64.BaseOfCode = t.VirtualAddress
+	oh.BaseOfCode = t.VirtualAddress
+	oh64.ImageBase = PEBASE
+	oh.ImageBase = PEBASE
+	oh64.SectionAlignment = PESECTALIGN
+	oh.SectionAlignment = PESECTALIGN
+	oh64.FileAlignment = PEFILEALIGN
+	oh.FileAlignment = PEFILEALIGN
+	oh64.MajorOperatingSystemVersion = 4
+	oh.MajorOperatingSystemVersion = 4
+	oh64.MinorOperatingSystemVersion = 0
+	oh.MinorOperatingSystemVersion = 0
+	oh64.MajorImageVersion = 1
+	oh.MajorImageVersion = 1
+	oh64.MinorImageVersion = 0
+	oh.MinorImageVersion = 0
+	oh64.MajorSubsystemVersion = 4
+	oh.MajorSubsystemVersion = 4
+	oh64.MinorSubsystemVersion = 0
+	oh.MinorSubsystemVersion = 0
+	oh64.SizeOfImage = uint32(nextsectoff)
+	oh.SizeOfImage = uint32(nextsectoff)
+	oh64.SizeOfHeaders = uint32(PEFILEHEADR)
+	oh.SizeOfHeaders = uint32(PEFILEHEADR)
+	if headstring == "windowsgui" {
+		oh64.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI
+		oh.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_GUI
+	} else {
+		oh64.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI
+		oh.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI
+	}
+
+	// Disable stack growth as we don't want Windows to
+	// fiddle with the thread stack limits, which we set
+	// ourselves to circumvent the stack checks in the
+	// Windows exception dispatcher.
+	// Commit size must be strictly less than reserve
+	// size otherwise reserve will be rounded up to a
+	// larger size, as verified with VMMap.
+
+	// Go code would be OK with 64k stacks, but we need larger stacks for cgo.
+	// That default stack reserve size affects only the main thread,
+	// for other threads we specify stack size in runtime explicitly
+	// (runtime knows whether cgo is enabled or not).
+	// If you change stack reserve sizes here,
+	// change STACKSIZE in runtime/cgo/gcc_windows_{386,amd64}.c and correspondent
+	// CreateThread parameter in runtime.newosproc as well.
+	if !iscgo {
+		oh64.SizeOfStackReserve = 0x00020000
+		oh.SizeOfStackReserve = 0x00020000
+		oh64.SizeOfStackCommit = 0x00001000
+		oh.SizeOfStackCommit = 0x00001000
+	} else {
+		oh64.SizeOfStackReserve = 0x00200000
+		oh.SizeOfStackReserve = 0x00100000
+
+		// account for 2 guard pages
+		oh64.SizeOfStackCommit = 0x00200000 - 0x2000
+
+		oh.SizeOfStackCommit = 0x00100000 - 0x2000
+	}
+
+	oh64.SizeOfHeapReserve = 0x00100000
+	oh.SizeOfHeapReserve = 0x00100000
+	oh64.SizeOfHeapCommit = 0x00001000
+	oh.SizeOfHeapCommit = 0x00001000
+	oh64.NumberOfRvaAndSizes = 16
+	oh.NumberOfRvaAndSizes = 16
+
+	pewrite()
+}
diff --git a/src/cmd/link/internal/ld/pobj.go b/src/cmd/link/internal/ld/pobj.go
new file mode 100644
index 0000000..5ce1977
--- /dev/null
+++ b/src/cmd/link/internal/ld/pobj.go
@@ -0,0 +1,259 @@
+// Inferno utils/6l/obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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 ld
+
+import (
+	"cmd/internal/obj"
+	"flag"
+	"fmt"
+	"os"
+	"strings"
+)
+
+var (
+	pkglistfornote []byte
+	buildid        string
+)
+
+func Ldmain() {
+	Ctxt = linknew(Thelinkarch)
+	Ctxt.Thechar = int32(Thearch.Thechar)
+	Ctxt.Thestring = Thestring
+	Ctxt.Diag = Diag
+	Ctxt.Bso = &Bso
+
+	Bso = *obj.Binitw(os.Stdout)
+	Debug = [128]int{}
+	nerrors = 0
+	outfile = ""
+	HEADTYPE = -1
+	INITTEXT = -1
+	INITDAT = -1
+	INITRND = -1
+	INITENTRY = ""
+	Linkmode = LinkAuto
+
+	// For testing behavior of go command when tools crash silently.
+	// Undocumented, not in standard flag parser to avoid
+	// exposing in usage message.
+	for _, arg := range os.Args {
+		if arg == "-crash_for_testing" {
+			os.Exit(2)
+		}
+	}
+
+	if Thearch.Thechar == '6' && obj.Getgoos() == "plan9" {
+		obj.Flagcount("8", "use 64-bit addresses in symbol table", &Debug['8'])
+	}
+	obj.Flagfn1("B", "add an ELF NT_GNU_BUILD_ID `note` when using ELF", addbuildinfo)
+	obj.Flagcount("C", "check Go calls to C code", &Debug['C'])
+	obj.Flagint64("D", "set data segment `address`", &INITDAT)
+	obj.Flagstr("E", "set `entry` symbol name", &INITENTRY)
+	obj.Flagfn1("I", "use `linker` as ELF dynamic linker", setinterp)
+	obj.Flagfn1("L", "add specified `directory` to library path", Lflag)
+	obj.Flagfn1("H", "set header `type`", setheadtype)
+	obj.Flagint32("R", "set address rounding `quantum`", &INITRND)
+	obj.Flagint64("T", "set text segment `address`", &INITTEXT)
+	obj.Flagfn0("V", "print version and exit", doversion)
+	obj.Flagcount("W", "disassemble input", &Debug['W'])
+	obj.Flagfn1("X", "add string value `definition` of the form importpath.name=value", addstrdata1)
+	obj.Flagcount("a", "disassemble output", &Debug['a'])
+	obj.Flagstr("buildid", "record `id` as Go toolchain build id", &buildid)
+	flag.Var(&Buildmode, "buildmode", "set build `mode`")
+	obj.Flagcount("c", "dump call graph", &Debug['c'])
+	obj.Flagcount("d", "disable dynamic executable", &Debug['d'])
+	obj.Flagstr("extld", "use `linker` when linking in external mode", &extld)
+	obj.Flagstr("extldflags", "pass `flags` to external linker", &extldflags)
+	obj.Flagcount("f", "ignore version mismatch", &Debug['f'])
+	obj.Flagcount("g", "disable go package data checks", &Debug['g'])
+	obj.Flagcount("h", "halt on error", &Debug['h'])
+	obj.Flagstr("installsuffix", "set package directory `suffix`", &flag_installsuffix)
+	obj.Flagstr("k", "set field tracking `symbol`", &tracksym)
+	obj.Flagfn1("linkmode", "set link `mode` (internal, external, auto)", setlinkmode)
+	flag.BoolVar(&Linkshared, "linkshared", false, "link against installed Go shared libraries")
+	obj.Flagcount("n", "dump symbol table", &Debug['n'])
+	obj.Flagstr("o", "write output to `file`", &outfile)
+	flag.Var(&rpath, "r", "set the ELF dynamic linker search `path` to dir1:dir2:...")
+	obj.Flagcount("race", "enable race detector", &flag_race)
+	obj.Flagcount("s", "disable symbol table", &Debug['s'])
+	var flagShared int
+	if Thearch.Thechar == '5' || Thearch.Thechar == '6' {
+		obj.Flagcount("shared", "generate shared object (implies -linkmode external)", &flagShared)
+	}
+	obj.Flagstr("tmpdir", "use `directory` for temporary files", &tmpdir)
+	obj.Flagcount("u", "reject unsafe packages", &Debug['u'])
+	obj.Flagcount("v", "print link trace", &Debug['v'])
+	obj.Flagcount("w", "disable DWARF generation", &Debug['w'])
+
+	obj.Flagstr("cpuprofile", "write cpu profile to `file`", &cpuprofile)
+	obj.Flagstr("memprofile", "write memory profile to `file`", &memprofile)
+	obj.Flagint64("memprofilerate", "set runtime.MemProfileRate to `rate`", &memprofilerate)
+
+	// Clumsy hack to preserve old two-argument -X name val syntax for old scripts.
+	// Rewrite that syntax into new syntax -X name=val.
+	// TODO(rsc): Delete this hack in Go 1.6 or later.
+	var args []string
+	for i := 0; i < len(os.Args); i++ {
+		arg := os.Args[i]
+		if (arg == "-X" || arg == "--X") && i+2 < len(os.Args) && !strings.Contains(os.Args[i+1], "=") {
+			fmt.Fprintf(os.Stderr, "link: warning: option %s %s %s may not work in future releases; use %s %s=%s\n",
+				arg, os.Args[i+1], os.Args[i+2],
+				arg, os.Args[i+1], os.Args[i+2])
+			args = append(args, arg)
+			args = append(args, os.Args[i+1]+"="+os.Args[i+2])
+			i += 2
+			continue
+		}
+		if (strings.HasPrefix(arg, "-X=") || strings.HasPrefix(arg, "--X=")) && i+1 < len(os.Args) && strings.Count(arg, "=") == 1 {
+			fmt.Fprintf(os.Stderr, "link: warning: option %s %s may not work in future releases; use %s=%s\n",
+				arg, os.Args[i+1],
+				arg, os.Args[i+1])
+			args = append(args, arg+"="+os.Args[i+1])
+			i++
+			continue
+		}
+		args = append(args, arg)
+	}
+	os.Args = args
+
+	obj.Flagparse(usage)
+
+	startProfile()
+	Ctxt.Bso = &Bso
+	Ctxt.Debugvlog = int32(Debug['v'])
+	if flagShared != 0 {
+		if Buildmode == BuildmodeUnset {
+			Buildmode = BuildmodeCShared
+		} else if Buildmode != BuildmodeCShared {
+			Exitf("-shared and -buildmode=%s are incompatible", Buildmode.String())
+		}
+	}
+	if Buildmode == BuildmodeUnset {
+		Buildmode = BuildmodeExe
+	}
+
+	if Buildmode != BuildmodeShared && flag.NArg() != 1 {
+		usage()
+	}
+
+	if outfile == "" {
+		outfile = "a.out"
+		if HEADTYPE == obj.Hwindows {
+			outfile += ".exe"
+		}
+	}
+
+	libinit() // creates outfile
+
+	if HEADTYPE == -1 {
+		HEADTYPE = int32(headtype(goos))
+	}
+	Ctxt.Headtype = int(HEADTYPE)
+	if headstring == "" {
+		headstring = Headstr(int(HEADTYPE))
+	}
+
+	Thearch.Archinit()
+
+	if Linkshared && !Iself {
+		Exitf("-linkshared can only be used on elf systems")
+	}
+
+	if Debug['v'] != 0 {
+		fmt.Fprintf(&Bso, "HEADER = -H%d -T0x%x -D0x%x -R0x%x\n", HEADTYPE, uint64(INITTEXT), uint64(INITDAT), uint32(INITRND))
+	}
+	Bso.Flush()
+
+	if Buildmode == BuildmodeShared {
+		for i := 0; i < flag.NArg(); i++ {
+			arg := flag.Arg(i)
+			parts := strings.SplitN(arg, "=", 2)
+			var pkgpath, file string
+			if len(parts) == 1 {
+				pkgpath, file = "main", arg
+			} else {
+				pkgpath, file = parts[0], parts[1]
+			}
+			pkglistfornote = append(pkglistfornote, pkgpath...)
+			pkglistfornote = append(pkglistfornote, '\n')
+			addlibpath(Ctxt, "command line", "command line", file, pkgpath, "")
+		}
+	} else {
+		addlibpath(Ctxt, "command line", "command line", flag.Arg(0), "main", "")
+	}
+	loadlib()
+
+	if Thearch.Thechar == '5' {
+		// mark some functions that are only referenced after linker code editing
+		if Ctxt.Goarm == 5 {
+			mark(Linkrlookup(Ctxt, "_sfloat", 0))
+		}
+		mark(Linklookup(Ctxt, "runtime.read_tls_fallback", 0))
+	}
+
+	checkgo()
+	checkstrdata()
+	deadcode()
+	callgraph()
+
+	doelf()
+	if HEADTYPE == obj.Hdarwin {
+		domacho()
+	}
+	dostkcheck()
+	if HEADTYPE == obj.Hwindows {
+		dope()
+	}
+	addexport()
+	Thearch.Gentext() // trampolines, call stubs, etc.
+	textbuildid()
+	textaddress()
+	pclntab()
+	findfunctab()
+	symtab()
+	dodata()
+	address()
+	doweak()
+	reloc()
+	Thearch.Asmb()
+	undef()
+	hostlink()
+	archive()
+	if Debug['v'] != 0 {
+		fmt.Fprintf(&Bso, "%5.2f cpu time\n", obj.Cputime())
+		fmt.Fprintf(&Bso, "%d symbols\n", Ctxt.Nsymbol)
+		fmt.Fprintf(&Bso, "%d liveness data\n", liveness)
+	}
+
+	Bso.Flush()
+
+	errorexit()
+}
diff --git a/src/cmd/link/internal/ld/sym.go b/src/cmd/link/internal/ld/sym.go
new file mode 100644
index 0000000..652109d
--- /dev/null
+++ b/src/cmd/link/internal/ld/sym.go
@@ -0,0 +1,227 @@
+// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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 ld
+
+import (
+	"cmd/internal/obj"
+	"log"
+	"os"
+	"path/filepath"
+	"strconv"
+)
+
+func yy_isalpha(c int) bool {
+	return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z'
+}
+
+var headers = []struct {
+	name string
+	val  int
+}{
+	{"darwin", obj.Hdarwin},
+	{"dragonfly", obj.Hdragonfly},
+	{"elf", obj.Helf},
+	{"freebsd", obj.Hfreebsd},
+	{"linux", obj.Hlinux},
+	{"android", obj.Hlinux}, // must be after "linux" entry or else headstr(Hlinux) == "android"
+	{"nacl", obj.Hnacl},
+	{"netbsd", obj.Hnetbsd},
+	{"openbsd", obj.Hopenbsd},
+	{"plan9", obj.Hplan9},
+	{"solaris", obj.Hsolaris},
+	{"windows", obj.Hwindows},
+	{"windowsgui", obj.Hwindows},
+}
+
+func linknew(arch *LinkArch) *Link {
+	ctxt := new(Link)
+	ctxt.Hash = make(map[symVer]*LSym)
+	ctxt.Arch = arch
+	ctxt.Version = obj.HistVersion
+	ctxt.Goroot = obj.Getgoroot()
+
+	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 = "/???"
+	}
+	buf = filepath.ToSlash(buf)
+
+	ctxt.Headtype = headtype(obj.Getgoos())
+	if ctxt.Headtype < 0 {
+		log.Fatalf("unknown goos %s", obj.Getgoos())
+	}
+
+	// Record thread-local storage offset.
+	// TODO(rsc): Move tlsoffset back into the linker.
+	switch ctxt.Headtype {
+	default:
+		log.Fatalf("unknown thread-local storage offset for %s", Headstr(ctxt.Headtype))
+
+	case obj.Hplan9, obj.Hwindows:
+		break
+
+		/*
+		 * ELF uses TLS offset negative from FS.
+		 * Translate 0(FS) and 8(FS) into -16(FS) and -8(FS).
+		 * Known to low-level assembly in package runtime and runtime/cgo.
+		 */
+	case obj.Hlinux,
+		obj.Hfreebsd,
+		obj.Hnetbsd,
+		obj.Hopenbsd,
+		obj.Hdragonfly,
+		obj.Hsolaris:
+		ctxt.Tlsoffset = -1 * ctxt.Arch.Ptrsize
+
+	case obj.Hnacl:
+		switch ctxt.Arch.Thechar {
+		default:
+			log.Fatalf("unknown thread-local storage offset for nacl/%s", ctxt.Arch.Name)
+
+		case '5':
+			ctxt.Tlsoffset = 0
+
+		case '6':
+			ctxt.Tlsoffset = 0
+
+		case '8':
+			ctxt.Tlsoffset = -8
+		}
+
+		/*
+		 * OS X system constants - offset from 0(GS) to our TLS.
+		 * Explained in ../../runtime/cgo/gcc_darwin_*.c.
+		 */
+	case obj.Hdarwin:
+		switch ctxt.Arch.Thechar {
+		default:
+			log.Fatalf("unknown thread-local storage offset for darwin/%s", ctxt.Arch.Name)
+
+		case '5':
+			ctxt.Tlsoffset = 0 // dummy value, not needed
+
+		case '6':
+			ctxt.Tlsoffset = 0x8a0
+
+		case '7':
+			ctxt.Tlsoffset = 0 // dummy value, not needed
+
+		case '8':
+			ctxt.Tlsoffset = 0x468
+		}
+	}
+
+	// On arm, record goarm.
+	if ctxt.Arch.Thechar == '5' {
+		p := obj.Getgoarm()
+		if p != "" {
+			ctxt.Goarm = int32(obj.Atoi(p))
+		} else {
+			ctxt.Goarm = 6
+		}
+	}
+
+	return ctxt
+}
+
+func linknewsym(ctxt *Link, symb string, v int) *LSym {
+	s := new(LSym)
+	*s = LSym{}
+
+	s.Dynid = -1
+	s.Plt = -1
+	s.Got = -1
+	s.Name = symb
+	s.Type = 0
+	s.Version = int16(v)
+	s.Value = 0
+	s.Size = 0
+	ctxt.Nsymbol++
+
+	s.Allsym = ctxt.Allsym
+	ctxt.Allsym = s
+
+	return s
+}
+
+type symVer struct {
+	sym string
+	ver int
+}
+
+func _lookup(ctxt *Link, symb string, v int, creat int) *LSym {
+	s := ctxt.Hash[symVer{symb, v}]
+	if s != nil {
+		return s
+	}
+	if creat == 0 {
+		return nil
+	}
+
+	s = linknewsym(ctxt, symb, v)
+	s.Extname = s.Name
+	ctxt.Hash[symVer{symb, v}] = s
+	return s
+}
+
+func Linklookup(ctxt *Link, name string, v int) *LSym {
+	return _lookup(ctxt, name, v, 1)
+}
+
+// read-only lookup
+func Linkrlookup(ctxt *Link, name string, v int) *LSym {
+	return _lookup(ctxt, name, v, 0)
+}
+
+func Headstr(v int) string {
+	for i := 0; i < len(headers); i++ {
+		if v == headers[i].val {
+			return headers[i].name
+		}
+	}
+	return strconv.Itoa(v)
+}
+
+func headtype(name string) int {
+	for i := 0; i < len(headers); i++ {
+		if name == headers[i].name {
+			return headers[i].val
+		}
+	}
+	return -1
+}
diff --git a/src/cmd/link/internal/ld/symtab.go b/src/cmd/link/internal/ld/symtab.go
new file mode 100644
index 0000000..5360ec1
--- /dev/null
+++ b/src/cmd/link/internal/ld/symtab.go
@@ -0,0 +1,541 @@
+// Inferno utils/6l/span.c
+// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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 ld
+
+import (
+	"cmd/internal/obj"
+	"fmt"
+	"path/filepath"
+	"strings"
+)
+
+// Symbol table.
+
+func putelfstr(s string) int {
+	if len(Elfstrdat) == 0 && s != "" {
+		// first entry must be empty string
+		putelfstr("")
+	}
+
+	// When dynamically linking, we create LSym's by reading the names from
+	// the symbol tables of the shared libraries and so the names need to
+	// match exactly.  Tools like DTrace will have to wait for now.
+	if !DynlinkingGo() {
+		// Rewrite · to . for ASCII-only tools like DTrace (sigh)
+		s = strings.Replace(s, "·", ".", -1)
+	}
+
+	n := len(s) + 1
+	for len(Elfstrdat)+n > cap(Elfstrdat) {
+		Elfstrdat = append(Elfstrdat[:cap(Elfstrdat)], 0)[:len(Elfstrdat)]
+	}
+
+	off := len(Elfstrdat)
+	Elfstrdat = Elfstrdat[:off+n]
+	copy(Elfstrdat[off:], s)
+
+	return off
+}
+
+func putelfsyment(off int, addr int64, size int64, info int, shndx int, other int) {
+	switch Thearch.Thechar {
+	case '6', '7', '9':
+		Thearch.Lput(uint32(off))
+		Cput(uint8(info))
+		Cput(uint8(other))
+		Thearch.Wput(uint16(shndx))
+		Thearch.Vput(uint64(addr))
+		Thearch.Vput(uint64(size))
+		Symsize += ELF64SYMSIZE
+
+	default:
+		Thearch.Lput(uint32(off))
+		Thearch.Lput(uint32(addr))
+		Thearch.Lput(uint32(size))
+		Cput(uint8(info))
+		Cput(uint8(other))
+		Thearch.Wput(uint16(shndx))
+		Symsize += ELF32SYMSIZE
+	}
+}
+
+var numelfsym int = 1 // 0 is reserved
+
+var elfbind int
+
+func putelfsym(x *LSym, s string, t int, addr int64, size int64, ver int, go_ *LSym) {
+	var type_ int
+
+	switch t {
+	default:
+		return
+
+	case 'T':
+		type_ = STT_FUNC
+
+	case 'D':
+		type_ = STT_OBJECT
+
+	case 'B':
+		type_ = STT_OBJECT
+
+	case 'U':
+		// ElfType is only set for symbols read from Go shared libraries, but
+		// for other symbols it is left as STT_NOTYPE which is fine.
+		type_ = int(x.ElfType)
+
+	case 't':
+		type_ = STT_TLS
+	}
+
+	xo := x
+	for xo.Outer != nil {
+		xo = xo.Outer
+	}
+
+	var elfshnum int
+	if xo.Type == obj.SDYNIMPORT || xo.Type == obj.SHOSTOBJ {
+		elfshnum = SHN_UNDEF
+	} else {
+		if xo.Sect == nil {
+			Ctxt.Cursym = x
+			Diag("missing section in putelfsym")
+			return
+		}
+		if xo.Sect.Elfsect == nil {
+			Ctxt.Cursym = x
+			Diag("missing ELF section in putelfsym")
+			return
+		}
+		elfshnum = xo.Sect.Elfsect.shnum
+	}
+
+	// One pass for each binding: STB_LOCAL, STB_GLOBAL,
+	// maybe one day STB_WEAK.
+	bind := STB_GLOBAL
+
+	if ver != 0 || (x.Type&obj.SHIDDEN != 0) || x.Local {
+		bind = STB_LOCAL
+	}
+
+	// In external linking mode, we have to invoke gcc with -rdynamic
+	// 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.
+	// But when we're dynamically linking, we need all those global symbols.
+	if !DynlinkingGo() && Linkmode == LinkExternal && x.Cgoexport&CgoExportStatic == 0 && elfshnum != SHN_UNDEF {
+		bind = STB_LOCAL
+	}
+
+	if bind != elfbind {
+		return
+	}
+
+	off := putelfstr(s)
+	if Linkmode == LinkExternal && elfshnum != SHN_UNDEF {
+		addr -= int64(xo.Sect.Vaddr)
+	}
+	other := STV_DEFAULT
+	if x.Type&obj.SHIDDEN != 0 {
+		other = STV_HIDDEN
+	}
+	putelfsyment(off, addr, size, bind<<4|type_&0xf, elfshnum, other)
+	x.Elfsym = int32(numelfsym)
+	numelfsym++
+}
+
+func putelfsectionsym(s *LSym, shndx int) {
+	putelfsyment(0, 0, 0, STB_LOCAL<<4|STT_SECTION, shndx, 0)
+	s.Elfsym = int32(numelfsym)
+	numelfsym++
+}
+
+func putelfsymshndx(sympos int64, shndx int) {
+	here := Cpos()
+	if elf64 {
+		Cseek(sympos + 6)
+	} else {
+		Cseek(sympos + 14)
+	}
+
+	Thearch.Wput(uint16(shndx))
+	Cseek(here)
+}
+
+func Asmelfsym() {
+	// the first symbol entry is reserved
+	putelfsyment(0, 0, 0, STB_LOCAL<<4|STT_NOTYPE, 0, 0)
+
+	dwarfaddelfsectionsyms()
+
+	elfbind = STB_LOCAL
+	genasmsym(putelfsym)
+
+	elfbind = STB_GLOBAL
+	elfglobalsymndx = numelfsym
+	genasmsym(putelfsym)
+}
+
+func putplan9sym(x *LSym, s string, t int, addr int64, size int64, ver int, go_ *LSym) {
+	switch t {
+	case 'T', 'L', 'D', 'B':
+		if ver != 0 {
+			t += 'a' - 'A'
+		}
+		fallthrough
+
+	case 'a',
+		'p',
+		'f',
+		'z',
+		'Z',
+		'm':
+		l := 4
+		if HEADTYPE == obj.Hplan9 && Thearch.Thechar == '6' && Debug['8'] == 0 {
+			Lputb(uint32(addr >> 32))
+			l = 8
+		}
+
+		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 {
+				Cput(uint8(s[i]))
+				Cput(uint8(s[i+1]))
+			}
+
+			Cput(0)
+			Cput(0)
+			i++
+		} else {
+			/* skip the '<' in filenames */
+			if t == 'f' {
+				s = s[1:]
+			}
+			for i = 0; i < len(s); i++ {
+				Cput(uint8(s[i]))
+			}
+			Cput(0)
+		}
+
+		Symsize += int32(l) + 1 + int32(i) + 1
+
+	default:
+		return
+	}
+}
+
+func Asmplan9sym() {
+	genasmsym(putplan9sym)
+}
+
+var symt *LSym
+
+func Wputl(w uint16) {
+	Cput(uint8(w))
+	Cput(uint8(w >> 8))
+}
+
+func Wputb(w uint16) {
+	Cput(uint8(w >> 8))
+	Cput(uint8(w))
+}
+
+func Lputb(l uint32) {
+	Cput(uint8(l >> 24))
+	Cput(uint8(l >> 16))
+	Cput(uint8(l >> 8))
+	Cput(uint8(l))
+}
+
+func Lputl(l uint32) {
+	Cput(uint8(l))
+	Cput(uint8(l >> 8))
+	Cput(uint8(l >> 16))
+	Cput(uint8(l >> 24))
+}
+
+func Vputb(v uint64) {
+	Lputb(uint32(v >> 32))
+	Lputb(uint32(v))
+}
+
+func Vputl(v uint64) {
+	Lputl(uint32(v))
+	Lputl(uint32(v >> 32))
+}
+
+type byPkg []*Library
+
+func (libs byPkg) Len() int {
+	return len(libs)
+}
+
+func (libs byPkg) Less(a, b int) bool {
+	return libs[a].Pkg < libs[b].Pkg
+}
+
+func (libs byPkg) Swap(a, b int) {
+	libs[a], libs[b] = libs[b], libs[a]
+}
+
+func symtab() {
+	dosymtype()
+
+	// Define these so that they'll get put into the symbol table.
+	// data.c:/^address will provide the actual values.
+	xdefine("runtime.text", obj.STEXT, 0)
+
+	xdefine("runtime.etext", obj.STEXT, 0)
+	xdefine("runtime.typelink", obj.SRODATA, 0)
+	xdefine("runtime.etypelink", obj.SRODATA, 0)
+	xdefine("runtime.rodata", obj.SRODATA, 0)
+	xdefine("runtime.erodata", obj.SRODATA, 0)
+	xdefine("runtime.noptrdata", obj.SNOPTRDATA, 0)
+	xdefine("runtime.enoptrdata", obj.SNOPTRDATA, 0)
+	xdefine("runtime.data", obj.SDATA, 0)
+	xdefine("runtime.edata", obj.SDATA, 0)
+	xdefine("runtime.bss", obj.SBSS, 0)
+	xdefine("runtime.ebss", obj.SBSS, 0)
+	xdefine("runtime.noptrbss", obj.SNOPTRBSS, 0)
+	xdefine("runtime.enoptrbss", obj.SNOPTRBSS, 0)
+	xdefine("runtime.end", obj.SBSS, 0)
+	xdefine("runtime.epclntab", obj.SRODATA, 0)
+	xdefine("runtime.esymtab", obj.SRODATA, 0)
+
+	// garbage collection symbols
+	s := Linklookup(Ctxt, "runtime.gcdata", 0)
+
+	s.Type = obj.SRODATA
+	s.Size = 0
+	s.Reachable = true
+	xdefine("runtime.egcdata", obj.SRODATA, 0)
+
+	s = Linklookup(Ctxt, "runtime.gcbss", 0)
+	s.Type = obj.SRODATA
+	s.Size = 0
+	s.Reachable = true
+	xdefine("runtime.egcbss", obj.SRODATA, 0)
+
+	// pseudo-symbols to mark locations of type, string, and go string data.
+	var symtype *LSym
+	if !DynlinkingGo() {
+		s = Linklookup(Ctxt, "type.*", 0)
+
+		s.Type = obj.STYPE
+		s.Size = 0
+		s.Reachable = true
+		symtype = s
+	}
+
+	s = Linklookup(Ctxt, "go.string.*", 0)
+	s.Type = obj.SGOSTRING
+	s.Local = true
+	s.Size = 0
+	s.Reachable = true
+	symgostring := s
+
+	s = Linklookup(Ctxt, "go.func.*", 0)
+	s.Type = obj.SGOFUNC
+	s.Local = true
+	s.Size = 0
+	s.Reachable = true
+	symgofunc := s
+
+	s = Linklookup(Ctxt, "runtime.gcbits.*", 0)
+	s.Type = obj.SGCBITS
+	s.Local = true
+	s.Size = 0
+	s.Reachable = true
+	symgcbits := s
+
+	symtypelink := Linklookup(Ctxt, "runtime.typelink", 0)
+
+	symt = Linklookup(Ctxt, "runtime.symtab", 0)
+	symt.Local = true
+	symt.Type = obj.SSYMTAB
+	symt.Size = 0
+	symt.Reachable = true
+
+	ntypelinks := 0
+
+	// assign specific types so that they sort together.
+	// 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 {
+		if !s.Reachable || s.Special != 0 || s.Type != obj.SRODATA {
+			continue
+		}
+
+		if strings.HasPrefix(s.Name, "type.") && !DynlinkingGo() {
+			s.Type = obj.STYPE
+			s.Hide = 1
+			s.Outer = symtype
+		}
+
+		if strings.HasPrefix(s.Name, "go.typelink.") {
+			ntypelinks++
+			s.Type = obj.STYPELINK
+			s.Hide = 1
+			s.Outer = symtypelink
+		}
+
+		if strings.HasPrefix(s.Name, "go.string.") {
+			s.Type = obj.SGOSTRING
+			s.Hide = 1
+			s.Outer = symgostring
+		}
+
+		if strings.HasPrefix(s.Name, "runtime.gcbits.") {
+			s.Type = obj.SGCBITS
+			s.Hide = 1
+			s.Outer = symgcbits
+		}
+
+		if strings.HasPrefix(s.Name, "go.func.") {
+			s.Type = obj.SGOFUNC
+			s.Hide = 1
+			s.Outer = symgofunc
+		}
+
+		if strings.HasPrefix(s.Name, "gcargs.") || strings.HasPrefix(s.Name, "gclocals.") || strings.HasPrefix(s.Name, "gclocals·") {
+			s.Type = obj.SGOFUNC
+			s.Hide = 1
+			s.Outer = symgofunc
+			s.Align = 4
+			liveness += (s.Size + int64(s.Align) - 1) &^ (int64(s.Align) - 1)
+		}
+	}
+
+	if Buildmode == BuildmodeShared {
+		abihashgostr := Linklookup(Ctxt, "go.link.abihash."+filepath.Base(outfile), 0)
+		abihashgostr.Reachable = true
+		abihashgostr.Type = obj.SRODATA
+		hashsym := Linklookup(Ctxt, "go.link.abihashbytes", 0)
+		Addaddr(Ctxt, abihashgostr, hashsym)
+		adduint(Ctxt, abihashgostr, uint64(hashsym.Size))
+	}
+
+	// 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.
+	// This code uses several global variables that are set by pcln.go:pclntab.
+	moduledata := Linklookup(Ctxt, "runtime.firstmoduledata", 0)
+	moduledata.Type = obj.SNOPTRDATA
+	moduledata.Size = 0 // truncate symbol back to 0 bytes to reinitialize
+	moduledata.Reachable = true
+	moduledata.Local = true
+	// The pclntab slice
+	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.pclntab", 0))
+	adduint(Ctxt, moduledata, uint64(Linklookup(Ctxt, "runtime.pclntab", 0).Size))
+	adduint(Ctxt, moduledata, uint64(Linklookup(Ctxt, "runtime.pclntab", 0).Size))
+	// The ftab slice
+	Addaddrplus(Ctxt, moduledata, Linklookup(Ctxt, "runtime.pclntab", 0), int64(pclntabPclntabOffset))
+	adduint(Ctxt, moduledata, uint64(pclntabNfunc+1))
+	adduint(Ctxt, moduledata, uint64(pclntabNfunc+1))
+	// The filetab slice
+	Addaddrplus(Ctxt, moduledata, Linklookup(Ctxt, "runtime.pclntab", 0), int64(pclntabFiletabOffset))
+	adduint(Ctxt, moduledata, uint64(Ctxt.Nhistfile))
+	adduint(Ctxt, moduledata, uint64(Ctxt.Nhistfile))
+	// findfunctab
+	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.findfunctab", 0))
+	// minpc, maxpc
+	Addaddr(Ctxt, moduledata, pclntabFirstFunc)
+	Addaddrplus(Ctxt, moduledata, pclntabLastFunc, pclntabLastFunc.Size)
+	// pointers to specific parts of the module
+	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))
+	// The typelinks slice
+	Addaddr(Ctxt, moduledata, Linklookup(Ctxt, "runtime.typelink", 0))
+	adduint(Ctxt, moduledata, uint64(ntypelinks))
+	adduint(Ctxt, moduledata, uint64(ntypelinks))
+	if len(Ctxt.Shlibs) > 0 {
+		thismodulename := filepath.Base(outfile)
+		if Buildmode == BuildmodeExe {
+			// When linking an executable, outfile is just "a.out". Make
+			// it something slightly more comprehensible.
+			thismodulename = "the executable"
+		}
+		addgostring(moduledata, "go.link.thismodulename", thismodulename)
+
+		modulehashes := Linklookup(Ctxt, "go.link.abihashes", 0)
+		modulehashes.Reachable = true
+		modulehashes.Local = true
+		modulehashes.Type = obj.SRODATA
+
+		for i, shlib := range Ctxt.Shlibs {
+			// modulehashes[i].modulename
+			modulename := filepath.Base(shlib.Path)
+			addgostring(modulehashes, fmt.Sprintf("go.link.libname.%d", i), modulename)
+
+			// modulehashes[i].linktimehash
+			addgostring(modulehashes, fmt.Sprintf("go.link.linkhash.%d", i), string(shlib.Hash))
+
+			// modulehashes[i].runtimehash
+			abihash := Linklookup(Ctxt, "go.link.abihash."+modulename, 0)
+			abihash.Reachable = true
+			Addaddr(Ctxt, modulehashes, abihash)
+		}
+
+		Addaddr(Ctxt, moduledata, modulehashes)
+		adduint(Ctxt, moduledata, uint64(len(Ctxt.Shlibs)))
+		adduint(Ctxt, moduledata, uint64(len(Ctxt.Shlibs)))
+	}
+	// The rest of moduledata is zero initialized.
+	// When linking an object that does not contain the runtime we are
+	// creating the moduledata from scratch and it does not have a
+	// compiler-provided size, so read it from the type data.
+	moduledatatype := Linkrlookup(Ctxt, "type.runtime.moduledata", 0)
+	moduledata.Size = decodetype_size(moduledatatype)
+	Symgrow(Ctxt, moduledata, moduledata.Size)
+
+	lastmoduledatap := Linklookup(Ctxt, "runtime.lastmoduledatap", 0)
+	if lastmoduledatap.Type != obj.SDYNIMPORT {
+		lastmoduledatap.Type = obj.SNOPTRDATA
+		lastmoduledatap.Size = 0 // overwrite existing value
+		Addaddr(Ctxt, lastmoduledatap, moduledata)
+	}
+}
diff --git a/src/cmd/link/internal/ld/textflag.go b/src/cmd/link/internal/ld/textflag.go
new file mode 100644
index 0000000..6457fda
--- /dev/null
+++ b/src/cmd/link/internal/ld/textflag.go
@@ -0,0 +1,29 @@
+// 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 ld
+
+// This file defines flags attached to various functions
+// and data objects.  The compilers, assemblers, and linker must
+// all agree on these values.
+
+const (
+	// Don't profile the marked routine.
+	//
+	// Deprecated: Not implemented, do not use.
+	NOPROF = 1
+	// It is ok for the linker to get multiple of these symbols.  It will
+	// pick one of the duplicates to use.
+	DUPOK = 2
+	// Don't insert stack check preamble.
+	NOSPLIT = 4
+	// Put this data in a read-only section.
+	RODATA = 8
+	// This data contains no pointers.
+	NOPTR = 16
+	// This is a wrapper function and should not count as disabling 'recover'.
+	WRAPPER = 32
+	// This function uses its incoming context register.
+	NEEDCTXT = 64
+)
diff --git a/src/cmd/link/internal/ld/util.go b/src/cmd/link/internal/ld/util.go
new file mode 100644
index 0000000..f38f05c
--- /dev/null
+++ b/src/cmd/link/internal/ld/util.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 ld
+
+import (
+	"bytes"
+	"encoding/binary"
+	"log"
+	"os"
+	"runtime"
+	"runtime/pprof"
+	"strings"
+	"time"
+)
+
+func cstring(x []byte) string {
+	i := bytes.IndexByte(x, '\x00')
+	if i >= 0 {
+		x = x[:i]
+	}
+	return string(x)
+}
+
+func tokenize(s string) []string {
+	var f []string
+	for {
+		s = strings.TrimLeft(s, " \t\r\n")
+		if s == "" {
+			break
+		}
+		quote := false
+		i := 0
+		for ; i < len(s); i++ {
+			if s[i] == '\'' {
+				if quote && i+1 < len(s) && s[i+1] == '\'' {
+					i++
+					continue
+				}
+				quote = !quote
+			}
+			if !quote && (s[i] == ' ' || s[i] == '\t' || s[i] == '\r' || s[i] == '\n') {
+				break
+			}
+		}
+		next := s[:i]
+		s = s[i:]
+		if strings.Contains(next, "'") {
+			var buf []byte
+			quote := false
+			for i := 0; i < len(next); i++ {
+				if next[i] == '\'' {
+					if quote && i+1 < len(next) && next[i+1] == '\'' {
+						i++
+						buf = append(buf, '\'')
+					}
+					quote = !quote
+					continue
+				}
+				buf = append(buf, next[i])
+			}
+			next = string(buf)
+		}
+		f = append(f, next)
+	}
+	return f
+}
+
+func cutStringAtNUL(s string) string {
+	if i := strings.Index(s, "\x00"); i >= 0 {
+		s = s[:i]
+	}
+	return s
+}
+
+func Access(name string, mode int) int {
+	if mode != 0 {
+		panic("bad access")
+	}
+	_, err := os.Stat(name)
+	if err != nil {
+		return -1
+	}
+	return 0
+}
+
+// strings.Compare, introduced in Go 1.5.
+func stringsCompare(a, b string) int {
+	if a == b {
+		return 0
+	}
+	if a < b {
+		return -1
+	}
+	return +1
+}
+
+var atExitFuncs []func()
+
+func AtExit(f func()) {
+	atExitFuncs = append(atExitFuncs, f)
+}
+
+func Exit(code int) {
+	for i := len(atExitFuncs) - 1; i >= 0; i-- {
+		f := atExitFuncs[i]
+		atExitFuncs = atExitFuncs[:i]
+		f()
+	}
+	os.Exit(code)
+}
+
+var (
+	cpuprofile     string
+	memprofile     string
+	memprofilerate int64
+)
+
+func startProfile() {
+	if cpuprofile != "" {
+		f, err := os.Create(cpuprofile)
+		if err != nil {
+			log.Fatalf("%v", err)
+		}
+		if err := pprof.StartCPUProfile(f); err != nil {
+			log.Fatalf("%v", err)
+		}
+		AtExit(pprof.StopCPUProfile)
+	}
+	if memprofile != "" {
+		if memprofilerate != 0 {
+			runtime.MemProfileRate = int(memprofilerate)
+		}
+		f, err := os.Create(memprofile)
+		if err != nil {
+			log.Fatalf("%v", err)
+		}
+		AtExit(func() {
+			runtime.GC() // profile all outstanding allocations
+			if err := pprof.WriteHeapProfile(f); err != nil {
+				log.Fatalf("%v", err)
+			}
+		})
+	}
+}
+
+func artrim(x []byte) string {
+	i := 0
+	j := len(x)
+	for i < len(x) && x[i] == ' ' {
+		i++
+	}
+	for j > i && x[j-1] == ' ' {
+		j--
+	}
+	return string(x[i:j])
+}
+
+func stringtouint32(x []uint32, s string) {
+	for i := 0; len(s) > 0; i++ {
+		var buf [4]byte
+		s = s[copy(buf[:], s):]
+		x[i] = binary.LittleEndian.Uint32(buf[:])
+	}
+}
+
+var start = time.Now()
+
+func elapsed() float64 {
+	return time.Since(start).Seconds()
+}
diff --git a/src/cmd/link/internal/ppc64/asm.go b/src/cmd/link/internal/ppc64/asm.go
new file mode 100644
index 0000000..f070921
--- /dev/null
+++ b/src/cmd/link/internal/ppc64/asm.go
@@ -0,0 +1,737 @@
+// 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 at 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 at 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 ppc64
+
+import (
+	"cmd/internal/obj"
+	"cmd/link/internal/ld"
+	"encoding/binary"
+	"fmt"
+	"log"
+)
+
+func gentext() {
+	var s *ld.LSym
+	var stub *ld.LSym
+	var pprevtextp **ld.LSym
+	var r *ld.Reloc
+	var n string
+	var o1 uint32
+	var i int
+
+	// The ppc64 ABI PLT has similar concepts to other
+	// architectures, but is laid out quite differently.  When we
+	// see an R_PPC64_REL24 relocation to a dynamic symbol
+	// (indicating that the call needs to go through the PLT), we
+	// generate up to three stubs and reserve a PLT slot.
+	//
+	// 1) The call site will be bl x; nop (where the relocation
+	//    applies to the bl).  We rewrite this to bl x_stub; ld
+	//    r2,24(r1).  The ld is necessary because x_stub will save
+	//    r2 (the TOC pointer) at 24(r1) (the "TOC save slot").
+	//
+	// 2) We reserve space for a pointer in the .plt section (once
+	//    per referenced dynamic function).  .plt is a data
+	//    section filled solely by the dynamic linker (more like
+	//    .plt.got on other architectures).  Initially, the
+	//    dynamic linker will fill each slot with a pointer to the
+	//    corresponding x at plt entry point.
+	//
+	// 3) We generate the "call stub" x_stub (once per dynamic
+	//    function/object file pair).  This saves the TOC in the
+	//    TOC save slot, reads the function pointer from x's .plt
+	//    slot and calls it like any other global entry point
+	//    (including setting r12 to the function address).
+	//
+	// 4) We generate the "symbol resolver stub" x at plt (once per
+	//    dynamic function).  This is solely a branch to the glink
+	//    resolver stub.
+	//
+	// 5) We generate the glink resolver stub (only once).  This
+	//    computes which symbol resolver stub we came through and
+	//    invokes the dynamic resolver via a pointer provided by
+	//    the dynamic linker.  This will patch up the .plt slot to
+	//    point directly at the function so future calls go
+	//    straight from the call stub to the real function, and
+	//    then call the function.
+
+	// NOTE: It's possible we could make ppc64 closer to other
+	// architectures: ppc64's .plt is like .plt.got on other
+	// platforms and ppc64's .glink is like .plt on other
+	// platforms.
+
+	// Find all R_PPC64_REL24 relocations that reference dynamic
+	// imports.  Reserve PLT entries for these symbols and
+	// generate call stubs.  The call stubs need to live in .text,
+	// which is why we need to do this pass this early.
+	//
+	// This assumes "case 1" from the ABI, where the caller needs
+	// us to save and restore the TOC pointer.
+	pprevtextp = &ld.Ctxt.Textp
+
+	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 != obj.SDYNIMPORT {
+				continue
+			}
+
+			// Reserve PLT entry and generate symbol
+			// resolver
+			addpltsym(ld.Ctxt, r.Sym)
+
+			// Generate call stub
+			n = fmt.Sprintf("%s.%s", s.Name, r.Sym.Name)
+
+			stub = ld.Linklookup(ld.Ctxt, n, 0)
+			stub.Reachable = stub.Reachable || s.Reachable
+			if stub.Size == 0 {
+				// Need outer to resolve .TOC.
+				stub.Outer = s
+
+				// Link in to textp before s (we could
+				// do it after, but would have to skip
+				// the subsymbols)
+				*pprevtextp = stub
+
+				stub.Next = s
+				pprevtextp = &stub.Next
+
+				gencallstub(1, stub, r.Sym)
+			}
+
+			// Update the relocation to use the call stub
+			r.Sym = stub
+
+			// 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+4:], o1)
+		}
+	}
+}
+
+// Construct a call stub in stub that calls symbol targ via its PLT
+// entry.
+func gencallstub(abicase int, stub *ld.LSym, targ *ld.LSym) {
+	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)
+
+	stub.Type = obj.STEXT
+
+	// Save TOC pointer in TOC save slot
+	ld.Adduint32(ld.Ctxt, stub, 0xf8410018) // std r2,24(r1)
+
+	// Load the function pointer from the PLT.
+	r := ld.Addrel(stub)
+
+	r.Off = int32(stub.Size)
+	r.Sym = plt
+	r.Add = int64(targ.Plt)
+	r.Siz = 2
+	if ld.Ctxt.Arch.ByteOrder == binary.BigEndian {
+		r.Off += int32(r.Siz)
+	}
+	r.Type = obj.R_POWER_TOC
+	r.Variant = ld.RV_POWER_HA
+	ld.Adduint32(ld.Ctxt, stub, 0x3d820000) // addis r12,r2,targ at plt@toc at ha
+	r = ld.Addrel(stub)
+	r.Off = int32(stub.Size)
+	r.Sym = plt
+	r.Add = int64(targ.Plt)
+	r.Siz = 2
+	if ld.Ctxt.Arch.ByteOrder == binary.BigEndian {
+		r.Off += int32(r.Siz)
+	}
+	r.Type = obj.R_POWER_TOC
+	r.Variant = ld.RV_POWER_LO
+	ld.Adduint32(ld.Ctxt, stub, 0xe98c0000) // ld r12,targ at plt@toc at l(r12)
+
+	// Jump to the loaded pointer
+	ld.Adduint32(ld.Ctxt, stub, 0x7d8903a6) // mtctr r12
+	ld.Adduint32(ld.Ctxt, stub, 0x4e800420) // bctr
+}
+
+func adddynrela(rel *ld.LSym, s *ld.LSym, r *ld.Reloc) {
+	log.Fatalf("adddynrela not implemented")
+}
+
+func adddynrel(s *ld.LSym, r *ld.Reloc) {
+	targ := r.Sym
+	ld.Ctxt.Cursym = s
+
+	switch r.Type {
+	default:
+		if r.Type >= 256 {
+			ld.Diag("unexpected relocation type %d", r.Type)
+			return
+		}
+
+		// Handle relocations found in ELF object files.
+	case 256 + ld.R_PPC64_REL24:
+		r.Type = obj.R_CALLPOWER
+
+		// This is a local call, so the caller isn't setting
+		// up r12 and r2 is the same for the caller and
+		// callee.  Hence, we need to go to the local entry
+		// point.  (If we don't do this, the callee will try
+		// to use r12 to compute r2.)
+		r.Add += int64(r.Sym.Localentry) * 4
+
+		if targ.Type == obj.SDYNIMPORT {
+			// Should have been handled in elfsetupplt
+			ld.Diag("unexpected R_PPC64_REL24 for dyn import")
+		}
+
+		return
+
+	case 256 + ld.R_PPC64_ADDR64:
+		r.Type = obj.R_ADDR
+		if targ.Type == obj.SDYNIMPORT {
+			// These happen in .toc sections
+			ld.Adddynsym(ld.Ctxt, targ)
+
+			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))
+			r.Type = 256 // ignore during relocsym
+		}
+
+		return
+
+	case 256 + ld.R_PPC64_TOC16:
+		r.Type = obj.R_POWER_TOC
+		r.Variant = ld.RV_POWER_LO | ld.RV_CHECK_OVERFLOW
+		return
+
+	case 256 + ld.R_PPC64_TOC16_LO:
+		r.Type = obj.R_POWER_TOC
+		r.Variant = ld.RV_POWER_LO
+		return
+
+	case 256 + ld.R_PPC64_TOC16_HA:
+		r.Type = obj.R_POWER_TOC
+		r.Variant = ld.RV_POWER_HA | ld.RV_CHECK_OVERFLOW
+		return
+
+	case 256 + ld.R_PPC64_TOC16_HI:
+		r.Type = obj.R_POWER_TOC
+		r.Variant = ld.RV_POWER_HI | ld.RV_CHECK_OVERFLOW
+		return
+
+	case 256 + ld.R_PPC64_TOC16_DS:
+		r.Type = obj.R_POWER_TOC
+		r.Variant = ld.RV_POWER_DS | ld.RV_CHECK_OVERFLOW
+		return
+
+	case 256 + ld.R_PPC64_TOC16_LO_DS:
+		r.Type = obj.R_POWER_TOC
+		r.Variant = ld.RV_POWER_DS
+		return
+
+	case 256 + ld.R_PPC64_REL16_LO:
+		r.Type = obj.R_PCREL
+		r.Variant = ld.RV_POWER_LO
+		r.Add += 2 // Compensate for relocation size of 2
+		return
+
+	case 256 + ld.R_PPC64_REL16_HI:
+		r.Type = obj.R_PCREL
+		r.Variant = ld.RV_POWER_HI | ld.RV_CHECK_OVERFLOW
+		r.Add += 2
+		return
+
+	case 256 + ld.R_PPC64_REL16_HA:
+		r.Type = obj.R_PCREL
+		r.Variant = ld.RV_POWER_HA | ld.RV_CHECK_OVERFLOW
+		r.Add += 2
+		return
+	}
+
+	// Handle references to ELF symbols from our own object files.
+	if targ.Type != obj.SDYNIMPORT {
+		return
+	}
+
+	// TODO(austin): Translate our relocations to ELF
+
+	ld.Diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ.Name, r.Type, targ.Type)
+}
+
+func elfreloc1(r *ld.Reloc, sectoff int64) int {
+	// TODO(minux)
+	return -1
+}
+
+func elfsetupplt() {
+	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
+		// doublewords at the beginning of the .plt section
+		// before the PLT array.  Reserve space for these.
+		plt.Size = 16
+	}
+}
+
+func machoreloc1(r *ld.Reloc, sectoff int64) int {
+	return -1
+}
+
+// Return the value of .TOC. for symbol s
+func symtoc(s *ld.LSym) int64 {
+	var toc *ld.LSym
+
+	if s.Outer != nil {
+		toc = ld.Linkrlookup(ld.Ctxt, ".TOC.", int(s.Outer.Version))
+	} else {
+		toc = ld.Linkrlookup(ld.Ctxt, ".TOC.", int(s.Version))
+	}
+
+	if toc == nil {
+		ld.Diag("TOC-relative relocation in object without .TOC.")
+		return 0
+	}
+
+	return toc.Value
+}
+
+func archreloc(r *ld.Reloc, s *ld.LSym, val *int64) int {
+	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.
+		// R_CALLPOWER corresponds to R_PPC_REL24.
+		return -1
+	}
+
+	switch r.Type {
+	case obj.R_CONST:
+		*val = r.Add
+		return 0
+
+	case obj.R_GOTOFF:
+		*val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got", 0))
+		return 0
+
+	case obj.R_ADDRPOWER:
+		// r->add is two ppc64 instructions holding an immediate 32-bit constant.
+		// We want to add r->sym's address to that constant.
+		// 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)
+		if t < 0 {
+			ld.Ctxt.Diag("relocation for %s is too big (>=2G): %d", s.Name, ld.Symaddr(r.Sym))
+		}
+
+		t += int64((o1&0xffff)<<16 + uint32(int32(o2)<<16>>16))
+		if t&0x8000 != 0 {
+			t += 0x10000
+		}
+		o1 = o1&0xffff0000 | (uint32(t)>>16)&0xffff
+		o2 = o2&0xffff0000 | uint32(t)&0xffff
+
+		// when laid out, the instruction order must always be o1, o2.
+		if ld.Ctxt.Arch.ByteOrder == binary.BigEndian {
+			*val = int64(o1)<<32 | int64(o2)
+		} else {
+			*val = int64(o2)<<32 | int64(o1)
+		}
+		return 0
+
+	case obj.R_CALLPOWER:
+		// Bits 6 through 29 = (S + A - P) >> 2
+		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))
+		if t&3 != 0 {
+			ld.Ctxt.Diag("relocation for %s+%d is not aligned: %d", r.Sym.Name, r.Off, t)
+		}
+		if int64(int32(t<<6)>>6) != t {
+			// TODO(austin) This can happen if text > 32M.
+			// Add a call trampoline to .text in that case.
+			ld.Ctxt.Diag("relocation for %s+%d is too big: %d", r.Sym.Name, r.Off, t)
+		}
+
+		*val = int64(o1&0xfc000003 | uint32(t)&^0xfc000003)
+		return 0
+
+	case obj.R_POWER_TOC: // S + A - .TOC.
+		*val = ld.Symaddr(r.Sym) + r.Add - symtoc(s)
+
+		return 0
+	}
+
+	return -1
+}
+
+func archrelocvariant(r *ld.Reloc, s *ld.LSym, t int64) int64 {
+	switch r.Variant & ld.RV_TYPE_MASK {
+	default:
+		ld.Diag("unexpected relocation variant %d", r.Variant)
+		fallthrough
+
+	case ld.RV_NONE:
+		return t
+
+	case ld.RV_POWER_LO:
+		if r.Variant&ld.RV_CHECK_OVERFLOW != 0 {
+			// Whether to check for signed or unsigned
+			// overflow depends on the instruction
+			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:])
+			}
+			switch o1 >> 26 {
+			case 24, // ori
+				26, // xori
+				28: // andi
+				if t>>16 != 0 {
+					goto overflow
+				}
+
+			default:
+				if int64(int16(t)) != t {
+					goto overflow
+				}
+			}
+		}
+
+		return int64(int16(t))
+
+	case ld.RV_POWER_HA:
+		t += 0x8000
+		fallthrough
+
+		// Fallthrough
+	case ld.RV_POWER_HI:
+		t >>= 16
+
+		if r.Variant&ld.RV_CHECK_OVERFLOW != 0 {
+			// Whether to check for signed or unsigned
+			// overflow depends on the instruction
+			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:])
+			}
+			switch o1 >> 26 {
+			case 25, // oris
+				27, // xoris
+				29: // andis
+				if t>>16 != 0 {
+					goto overflow
+				}
+
+			default:
+				if int64(int16(t)) != t {
+					goto overflow
+				}
+			}
+		}
+
+		return int64(int16(t))
+
+	case ld.RV_POWER_DS:
+		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:]))
+		}
+		if t&3 != 0 {
+			ld.Diag("relocation for %s+%d is not aligned: %d", r.Sym.Name, r.Off, t)
+		}
+		if (r.Variant&ld.RV_CHECK_OVERFLOW != 0) && int64(int16(t)) != t {
+			goto overflow
+		}
+		return int64(o1)&0x3 | int64(int16(t))
+	}
+
+overflow:
+	ld.Diag("relocation for %s+%d is too big: %d", r.Sym.Name, r.Off, t)
+	return t
+}
+
+func addpltsym(ctxt *ld.Link, s *ld.LSym) {
+	if s.Plt >= 0 {
+		return
+	}
+
+	ld.Adddynsym(ctxt, s)
+
+	if ld.Iself {
+		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()
+
+		// Write symbol resolver stub (just a branch to the
+		// glink resolver stub)
+		r := ld.Addrel(glink)
+
+		r.Sym = glink
+		r.Off = int32(glink.Size)
+		r.Siz = 4
+		r.Type = obj.R_CALLPOWER
+		ld.Adduint32(ctxt, glink, 0x48000000) // b .glink
+
+		// In the ppc64 ABI, the dynamic linker is responsible
+		// for writing the entire PLT.  We just need to
+		// reserve 8 bytes for each PLT entry and generate a
+		// JMP_SLOT dynamic relocation for it.
+		//
+		// TODO(austin): ABI v1 is different
+		s.Plt = int32(plt.Size)
+
+		plt.Size += 8
+
+		ld.Addaddrplus(ctxt, rela, plt, int64(s.Plt))
+		ld.Adduint64(ctxt, rela, ld.ELF64_R_INFO(uint32(s.Dynid), ld.R_PPC64_JMP_SLOT))
+		ld.Adduint64(ctxt, rela, 0)
+	} else {
+		ld.Diag("addpltsym: unsupported binary format")
+	}
+}
+
+// Generate the glink resolver stub if necessary and return the .glink section
+func ensureglinkresolver() *ld.LSym {
+	glink := ld.Linklookup(ld.Ctxt, ".glink", 0)
+	if glink.Size != 0 {
+		return glink
+	}
+
+	// This is essentially the resolver from the ppc64 ELF ABI.
+	// At entry, r12 holds the address of the symbol resolver stub
+	// for the target routine and the argument registers hold the
+	// arguments for the target routine.
+	//
+	// This stub is PIC, so first get the PC of label 1 into r11.
+	// Other things will be relative to this.
+	ld.Adduint32(ld.Ctxt, glink, 0x7c0802a6) // mflr r0
+	ld.Adduint32(ld.Ctxt, glink, 0x429f0005) // bcl 20,31,1f
+	ld.Adduint32(ld.Ctxt, glink, 0x7d6802a6) // 1: mflr r11
+	ld.Adduint32(ld.Ctxt, glink, 0x7c0803a6) // mtlf r0
+
+	// Compute the .plt array index from the entry point address.
+	// Because this is PIC, everything is relative to label 1b (in
+	// r11):
+	//   r0 = ((r12 - r11) - (res_0 - r11)) / 4 = (r12 - res_0) / 4
+	ld.Adduint32(ld.Ctxt, glink, 0x3800ffd0) // li r0,-(res_0-1b)=-48
+	ld.Adduint32(ld.Ctxt, glink, 0x7c006214) // add r0,r0,r12
+	ld.Adduint32(ld.Ctxt, glink, 0x7c0b0050) // sub r0,r0,r11
+	ld.Adduint32(ld.Ctxt, glink, 0x7800f082) // srdi r0,r0,2
+
+	// r11 = address of the first byte of the PLT
+	r := ld.Addrel(glink)
+
+	r.Off = int32(glink.Size)
+	r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
+	r.Siz = 8
+	r.Type = obj.R_ADDRPOWER
+
+	// addis r11,0,.plt at ha; addi r11,r11,.plt at l
+	r.Add = 0x3d600000<<32 | 0x396b0000
+
+	glink.Size += 8
+
+	// Load r12 = dynamic resolver address and r11 = DSO
+	// identifier from the first two doublewords of the PLT.
+	ld.Adduint32(ld.Ctxt, glink, 0xe98b0000) // ld r12,0(r11)
+	ld.Adduint32(ld.Ctxt, glink, 0xe96b0008) // ld r11,8(r11)
+
+	// Jump to the dynamic resolver
+	ld.Adduint32(ld.Ctxt, glink, 0x7d8903a6) // mtctr r12
+	ld.Adduint32(ld.Ctxt, glink, 0x4e800420) // bctr
+
+	// The symbol resolvers must immediately follow.
+	//   res_0:
+
+	// Add DT_PPC64_GLINK .dynamic entry, which points to 32 bytes
+	// before the first symbol resolver stub.
+	s := ld.Linklookup(ld.Ctxt, ".dynamic", 0)
+
+	ld.Elfwritedynentsymplus(s, ld.DT_PPC64_GLINK, glink, glink.Size-32)
+
+	return glink
+}
+
+func asmb() {
+	if ld.Debug['v'] != 0 {
+		fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
+	}
+	ld.Bso.Flush()
+
+	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.Bso.Flush()
+
+		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.Bso.Flush()
+
+	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.Bso.Flush()
+		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 obj.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 obj.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.Bso.Flush()
+	ld.Cseek(0)
+	switch ld.HEADTYPE {
+	default:
+	case obj.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 obj.Hlinux,
+		obj.Hfreebsd,
+		obj.Hnetbsd,
+		obj.Hopenbsd,
+		obj.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/link/internal/ppc64/l.go b/src/cmd/link/internal/ppc64/l.go
new file mode 100644
index 0000000..1275a34
--- /dev/null
+++ b/src/cmd/link/internal/ppc64/l.go
@@ -0,0 +1,78 @@
+// 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 at 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 at 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 ppc64
+
+// 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 at 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 at 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   = '9'
+	PtrSize   = 8
+	IntSize   = 8
+	RegSize   = 8
+	MaxAlign  = 32 // max data alignment
+	FuncAlign = 8
+	MINLC     = 4
+)
+
+/* Used by ../internal/ld/dwarf.go */
+const (
+	DWARFREGSP = 1
+	DWARFREGLR = 65
+)
diff --git a/src/cmd/link/internal/ppc64/obj.go b/src/cmd/link/internal/ppc64/obj.go
new file mode 100644
index 0000000..d663b6e
--- /dev/null
+++ b/src/cmd/link/internal/ppc64/obj.go
@@ -0,0 +1,162 @@
+// 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 at 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 at 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 ppc64
+
+import (
+	"cmd/internal/obj"
+	"cmd/link/internal/ld"
+	"fmt"
+	"log"
+)
+
+// Reading object files.
+
+func Main() {
+	linkarchinit()
+	ld.Ldmain()
+}
+
+func linkarchinit() {
+	ld.Thestring = obj.Getgoarch()
+	if ld.Thestring == "ppc64le" {
+		ld.Thelinkarch = &ld.Linkppc64le
+	} else {
+		ld.Thelinkarch = &ld.Linkppc64
+	}
+
+	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.Dwarfreglr = DWARFREGLR
+
+	ld.Thearch.Adddynrel = adddynrel
+	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
+	if ld.Thelinkarch == &ld.Linkppc64le {
+		ld.Thearch.Lput = ld.Lputl
+		ld.Thearch.Wput = ld.Wputl
+		ld.Thearch.Vput = ld.Vputl
+	} else {
+		ld.Thearch.Lput = ld.Lputb
+		ld.Thearch.Wput = ld.Wputb
+		ld.Thearch.Vput = ld.Vputb
+	}
+
+	// TODO(austin): ABI v1 uses /usr/lib/ld.so.1
+	ld.Thearch.Linuxdynld = "/lib64/ld64.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.Exitf("unknown -H option: %v", ld.HEADTYPE)
+
+	case obj.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 obj.Hlinux: /* ppc64 elf */
+		if ld.Thestring == "ppc64" {
+			ld.Debug['d'] = 1 // TODO(austin): ELF ABI v1 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 obj.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/link/internal/x86/asm.go b/src/cmd/link/internal/x86/asm.go
new file mode 100644
index 0000000..d30bd48
--- /dev/null
+++ b/src/cmd/link/internal/x86/asm.go
@@ -0,0 +1,643 @@
+// 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 at 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 at 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 x86
+
+import (
+	"cmd/internal/obj"
+	"cmd/link/internal/ld"
+	"fmt"
+	"log"
+)
+
+func gentext() {
+}
+
+func adddynrela(rela *ld.LSym, s *ld.LSym, r *ld.Reloc) {
+	log.Fatalf("adddynrela not implemented")
+}
+
+func adddynrel(s *ld.LSym, r *ld.Reloc) {
+	targ := r.Sym
+	ld.Ctxt.Cursym = s
+
+	switch r.Type {
+	default:
+		if r.Type >= 256 {
+			ld.Diag("unexpected relocation type %d", r.Type)
+			return
+		}
+
+		// Handle relocations found in ELF object files.
+	case 256 + ld.R_386_PC32:
+		if targ.Type == obj.SDYNIMPORT {
+			ld.Diag("unexpected R_386_PC32 relocation for dynamic symbol %s", targ.Name)
+		}
+		if targ.Type == 0 || targ.Type == obj.SXREF {
+			ld.Diag("unknown symbol %s in pcrel", targ.Name)
+		}
+		r.Type = obj.R_PCREL
+		r.Add += 4
+		return
+
+	case 256 + ld.R_386_PLT32:
+		r.Type = obj.R_PCREL
+		r.Add += 4
+		if targ.Type == obj.SDYNIMPORT {
+			addpltsym(ld.Ctxt, targ)
+			r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
+			r.Add += int64(targ.Plt)
+		}
+
+		return
+
+	case 256 + ld.R_386_GOT32:
+		if targ.Type != obj.SDYNIMPORT {
+			// have symbol
+			if r.Off >= 2 && s.P[r.Off-2] == 0x8b {
+				// turn MOVL of GOT entry into LEAL of symbol address, relative to GOT.
+				s.P[r.Off-2] = 0x8d
+
+				r.Type = obj.R_GOTOFF
+				return
+			}
+
+			if r.Off >= 2 && s.P[r.Off-2] == 0xff && s.P[r.Off-1] == 0xb3 {
+				// turn PUSHL of GOT entry into PUSHL of symbol itself.
+				// use unnecessary SS prefix to keep instruction same length.
+				s.P[r.Off-2] = 0x36
+
+				s.P[r.Off-1] = 0x68
+				r.Type = obj.R_ADDR
+				return
+			}
+
+			ld.Diag("unexpected GOT reloc for non-dynamic symbol %s", targ.Name)
+			return
+		}
+
+		addgotsym(ld.Ctxt, targ)
+		r.Type = obj.R_CONST // write r->add during relocsym
+		r.Sym = nil
+		r.Add += int64(targ.Got)
+		return
+
+	case 256 + ld.R_386_GOTOFF:
+		r.Type = obj.R_GOTOFF
+		return
+
+	case 256 + ld.R_386_GOTPC:
+		r.Type = obj.R_PCREL
+		r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
+		r.Add += 4
+		return
+
+	case 256 + ld.R_386_32:
+		if targ.Type == obj.SDYNIMPORT {
+			ld.Diag("unexpected R_386_32 relocation for dynamic symbol %s", targ.Name)
+		}
+		r.Type = obj.R_ADDR
+		return
+
+	case 512 + ld.MACHO_GENERIC_RELOC_VANILLA*2 + 0:
+		r.Type = obj.R_ADDR
+		if targ.Type == obj.SDYNIMPORT {
+			ld.Diag("unexpected reloc for dynamic symbol %s", targ.Name)
+		}
+		return
+
+	case 512 + ld.MACHO_GENERIC_RELOC_VANILLA*2 + 1:
+		if targ.Type == obj.SDYNIMPORT {
+			addpltsym(ld.Ctxt, targ)
+			r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
+			r.Add = int64(targ.Plt)
+			r.Type = obj.R_PCREL
+			return
+		}
+
+		r.Type = obj.R_PCREL
+		return
+
+	case 512 + ld.MACHO_FAKE_GOTPCREL:
+		if targ.Type != obj.SDYNIMPORT {
+			// have symbol
+			// turn MOVL of GOT entry into LEAL of symbol itself
+			if r.Off < 2 || s.P[r.Off-2] != 0x8b {
+				ld.Diag("unexpected GOT reloc for non-dynamic symbol %s", targ.Name)
+				return
+			}
+
+			s.P[r.Off-2] = 0x8d
+			r.Type = obj.R_PCREL
+			return
+		}
+
+		addgotsym(ld.Ctxt, targ)
+		r.Sym = ld.Linklookup(ld.Ctxt, ".got", 0)
+		r.Add += int64(targ.Got)
+		r.Type = obj.R_PCREL
+		return
+	}
+
+	// Handle references to ELF symbols from our own object files.
+	if targ.Type != obj.SDYNIMPORT {
+		return
+	}
+
+	switch r.Type {
+	case obj.R_CALL,
+		obj.R_PCREL:
+		addpltsym(ld.Ctxt, targ)
+		r.Sym = ld.Linklookup(ld.Ctxt, ".plt", 0)
+		r.Add = int64(targ.Plt)
+		return
+
+	case obj.R_ADDR:
+		if s.Type != obj.SDATA {
+			break
+		}
+		if ld.Iself {
+			ld.Adddynsym(ld.Ctxt, targ)
+			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 = obj.R_CONST // write r->add during relocsym
+			r.Sym = nil
+			return
+		}
+
+		if ld.HEADTYPE == obj.Hdarwin && s.Size == PtrSize && r.Off == 0 {
+			// Mach-O relocations are a royal pain to lay out.
+			// They use a compact stateful bytecode representation
+			// that is too much bother to deal with.
+			// Instead, interpret the C declaration
+			//	void *_Cvar_stderr = &stderr;
+			// as making _Cvar_stderr the name of a GOT entry
+			// for stderr.  This is separate from the usual GOT entry,
+			// just in case the C code assigns to the variable,
+			// and of course it only works for single pointers,
+			// but we only need to support cgo and that's all it needs.
+			ld.Adddynsym(ld.Ctxt, targ)
+
+			got := ld.Linklookup(ld.Ctxt, ".got", 0)
+			s.Type = got.Type | obj.SSUB
+			s.Outer = got
+			s.Sub = got.Sub
+			got.Sub = s
+			s.Value = got.Size
+			ld.Adduint32(ld.Ctxt, got, 0)
+			ld.Adduint32(ld.Ctxt, ld.Linklookup(ld.Ctxt, ".linkedit.got", 0), uint32(targ.Dynid))
+			r.Type = 256 // ignore during relocsym
+			return
+		}
+
+		if ld.HEADTYPE == obj.Hwindows && s.Size == PtrSize {
+			// nothing to do, the relocation will be laid out in pereloc1
+			return
+		}
+	}
+
+	ld.Ctxt.Cursym = s
+	ld.Diag("unsupported relocation for dynamic symbol %s (type=%d stype=%d)", targ.Name, r.Type, targ.Type)
+}
+
+func elfreloc1(r *ld.Reloc, sectoff int64) int {
+	ld.Thearch.Lput(uint32(sectoff))
+
+	elfsym := r.Xsym.Elfsym
+	switch r.Type {
+	default:
+		return -1
+
+	case obj.R_ADDR:
+		if r.Siz == 4 {
+			ld.Thearch.Lput(ld.R_386_32 | uint32(elfsym)<<8)
+		} else {
+			return -1
+		}
+
+	case obj.R_CALL,
+		obj.R_PCREL:
+		if r.Siz == 4 {
+			ld.Thearch.Lput(ld.R_386_PC32 | uint32(elfsym)<<8)
+		} else {
+			return -1
+		}
+
+	case obj.R_TLS_LE:
+		if r.Siz == 4 {
+			ld.Thearch.Lput(ld.R_386_TLS_LE | uint32(elfsym)<<8)
+		} else {
+			return -1
+		}
+	}
+
+	return 0
+}
+
+func machoreloc1(r *ld.Reloc, sectoff int64) int {
+	var v uint32
+
+	rs := r.Xsym
+
+	if rs.Type == obj.SHOSTOBJ {
+		if rs.Dynid < 0 {
+			ld.Diag("reloc %d to non-macho symbol %s type=%d", r.Type, rs.Name, rs.Type)
+			return -1
+		}
+
+		v = uint32(rs.Dynid)
+		v |= 1 << 27 // external relocation
+	} else {
+		v = uint32(rs.Sect.Extnum)
+		if v == 0 {
+			ld.Diag("reloc %d to symbol %s in non-macho section %s type=%d", r.Type, rs.Name, rs.Sect.Name, rs.Type)
+			return -1
+		}
+	}
+
+	switch r.Type {
+	default:
+		return -1
+
+	case obj.R_ADDR:
+		v |= ld.MACHO_GENERIC_RELOC_VANILLA << 28
+
+	case obj.R_CALL,
+		obj.R_PCREL:
+		v |= 1 << 24 // pc-relative bit
+		v |= ld.MACHO_GENERIC_RELOC_VANILLA << 28
+	}
+
+	switch r.Siz {
+	default:
+		return -1
+
+	case 1:
+		v |= 0 << 25
+
+	case 2:
+		v |= 1 << 25
+
+	case 4:
+		v |= 2 << 25
+
+	case 8:
+		v |= 3 << 25
+	}
+
+	ld.Thearch.Lput(uint32(sectoff))
+	ld.Thearch.Lput(v)
+	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 obj.R_ADDR:
+		v = ld.IMAGE_REL_I386_DIR32
+
+	case obj.R_CALL,
+		obj.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
+	}
+	switch r.Type {
+	case obj.R_CONST:
+		*val = r.Add
+		return 0
+
+	case obj.R_GOTOFF:
+		*val = ld.Symaddr(r.Sym) + r.Add - ld.Symaddr(ld.Linklookup(ld.Ctxt, ".got", 0))
+		return 0
+	}
+
+	return -1
+}
+
+func archrelocvariant(r *ld.Reloc, s *ld.LSym, t int64) int64 {
+	log.Fatalf("unexpected relocation variant")
+	return t
+}
+
+func elfsetupplt() {
+	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)
+
+		ld.Adduint8(ld.Ctxt, plt, 0x35)
+		ld.Addaddrplus(ld.Ctxt, plt, got, 4)
+
+		// jmp *got+8
+		ld.Adduint8(ld.Ctxt, plt, 0xff)
+
+		ld.Adduint8(ld.Ctxt, plt, 0x25)
+		ld.Addaddrplus(ld.Ctxt, plt, got, 8)
+
+		// zero pad
+		ld.Adduint32(ld.Ctxt, plt, 0)
+
+		// assume got->size == 0 too
+		ld.Addaddrplus(ld.Ctxt, got, ld.Linklookup(ld.Ctxt, ".dynamic", 0), 0)
+
+		ld.Adduint32(ld.Ctxt, got, 0)
+		ld.Adduint32(ld.Ctxt, got, 0)
+	}
+}
+
+func addpltsym(ctxt *ld.Link, s *ld.LSym) {
+	if s.Plt >= 0 {
+		return
+	}
+
+	ld.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)
+		if plt.Size == 0 {
+			elfsetupplt()
+		}
+
+		// jmpq *got+size
+		ld.Adduint8(ctxt, plt, 0xff)
+
+		ld.Adduint8(ctxt, plt, 0x25)
+		ld.Addaddrplus(ctxt, plt, got, got.Size)
+
+		// add to got: pointer to current pos in plt
+		ld.Addaddrplus(ctxt, got, plt, plt.Size)
+
+		// pushl $x
+		ld.Adduint8(ctxt, plt, 0x68)
+
+		ld.Adduint32(ctxt, plt, uint32(rel.Size))
+
+		// jmp .plt
+		ld.Adduint8(ctxt, plt, 0xe9)
+
+		ld.Adduint32(ctxt, plt, uint32(-(plt.Size + 4)))
+
+		// rel
+		ld.Addaddrplus(ctxt, rel, got, got.Size-4)
+
+		ld.Adduint32(ctxt, rel, ld.ELF32_R_INFO(uint32(s.Dynid), ld.R_386_JMP_SLOT))
+
+		s.Plt = int32(plt.Size - 16)
+	} else if ld.HEADTYPE == obj.Hdarwin {
+		// Same laziness as in 6l.
+
+		plt := ld.Linklookup(ctxt, ".plt", 0)
+
+		addgotsym(ctxt, s)
+
+		ld.Adduint32(ctxt, ld.Linklookup(ctxt, ".linkedit.plt", 0), uint32(s.Dynid))
+
+		// jmpq *got+size(IP)
+		s.Plt = int32(plt.Size)
+
+		ld.Adduint8(ctxt, plt, 0xff)
+		ld.Adduint8(ctxt, plt, 0x25)
+		ld.Addaddrplus(ctxt, plt, ld.Linklookup(ctxt, ".got", 0), int64(s.Got))
+	} else {
+		ld.Diag("addpltsym: unsupported binary format")
+	}
+}
+
+func addgotsym(ctxt *ld.Link, s *ld.LSym) {
+	if s.Got >= 0 {
+		return
+	}
+
+	ld.Adddynsym(ctxt, s)
+	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)
+		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 == obj.Hdarwin {
+		ld.Adduint32(ctxt, ld.Linklookup(ctxt, ".linkedit.got", 0), uint32(s.Dynid))
+	} else {
+		ld.Diag("addgotsym: unsupported binary format")
+	}
+}
+
+func asmb() {
+	if ld.Debug['v'] != 0 {
+		fmt.Fprintf(&ld.Bso, "%5.2f asmb\n", obj.Cputime())
+	}
+	ld.Bso.Flush()
+
+	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.Bso.Flush()
+
+		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.Bso.Flush()
+
+	ld.Cseek(int64(ld.Segdata.Fileoff))
+	ld.Datblk(int64(ld.Segdata.Vaddr), int64(ld.Segdata.Filelen))
+
+	machlink := uint32(0)
+	if ld.HEADTYPE == obj.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)))
+		ld.Cseek(int64(dwarfoff))
+
+		ld.Segdwarf.Fileoff = uint64(ld.Cpos())
+		ld.Dwarfemitdebugsections()
+		ld.Segdwarf.Filelen = uint64(ld.Cpos()) - ld.Segdwarf.Fileoff
+
+		machlink = uint32(ld.Domacholink())
+	}
+
+	ld.Symsize = 0
+	ld.Spsize = 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.Bso.Flush()
+		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 obj.Hplan9:
+			symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
+
+		case obj.Hdarwin:
+			symo = uint32(ld.Segdwarf.Fileoff + uint64(ld.Rnd(int64(ld.Segdwarf.Filelen), int64(ld.INITRND))) + uint64(machlink))
+
+		case obj.Hwindows:
+			symo = uint32(ld.Segdata.Fileoff + ld.Segdata.Filelen)
+			symo = uint32(ld.Rnd(int64(symo), ld.PEFILEALIGN))
+		}
+
+		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 obj.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()
+			}
+
+		case obj.Hwindows:
+			if ld.Debug['v'] != 0 {
+				fmt.Fprintf(&ld.Bso, "%5.2f dwarf\n", obj.Cputime())
+			}
+			ld.Dwarfemitdebugsections()
+
+		case obj.Hdarwin:
+			if ld.Linkmode == ld.LinkExternal {
+				ld.Machoemitreloc()
+			}
+		}
+	}
+
+	if ld.Debug['v'] != 0 {
+		fmt.Fprintf(&ld.Bso, "%5.2f headr\n", obj.Cputime())
+	}
+	ld.Bso.Flush()
+	ld.Cseek(0)
+	switch ld.HEADTYPE {
+	default:
+	case obj.Hplan9: /* plan9 */
+		magic := int32(4*11*11 + 7)
+
+		ld.Lputb(uint32(magic))              /* magic */
+		ld.Lputb(uint32(ld.Segtext.Filelen)) /* sizes */
+		ld.Lputb(uint32(ld.Segdata.Filelen))
+		ld.Lputb(uint32(ld.Segdata.Length - ld.Segdata.Filelen))
+		ld.Lputb(uint32(ld.Symsize))      /* nsyms */
+		ld.Lputb(uint32(ld.Entryvalue())) /* va of entry */
+		ld.Lputb(uint32(ld.Spsize))       /* sp offsets */
+		ld.Lputb(uint32(ld.Lcsize))       /* line offsets */
+
+	case obj.Hdarwin:
+		ld.Asmbmacho()
+
+	case obj.Hlinux,
+		obj.Hfreebsd,
+		obj.Hnetbsd,
+		obj.Hopenbsd,
+		obj.Hnacl:
+		ld.Asmbelf(int64(symo))
+
+	case obj.Hwindows:
+		ld.Asmbpe()
+	}
+
+	ld.Cflush()
+}
diff --git a/src/cmd/link/internal/x86/l.go b/src/cmd/link/internal/x86/l.go
new file mode 100644
index 0000000..8a811ff
--- /dev/null
+++ b/src/cmd/link/internal/x86/l.go
@@ -0,0 +1,47 @@
+// Inferno utils/8l/l.h
+// http://code.google.com/p/inferno-os/source/browse/utils/8l/l.h
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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 x86
+
+const (
+	thechar   = '8'
+	PtrSize   = 4
+	IntSize   = 4
+	RegSize   = 4
+	MaxAlign  = 32 // max data alignment
+	FuncAlign = 16
+	MINLC     = 1
+)
+
+/* Used by ../internal/ld/dwarf.go */
+const (
+	DWARFREGSP = 4
+	DWARFREGLR = 8
+)
diff --git a/src/cmd/link/internal/x86/obj.go b/src/cmd/link/internal/x86/obj.go
new file mode 100644
index 0000000..ee408f7
--- /dev/null
+++ b/src/cmd/link/internal/x86/obj.go
@@ -0,0 +1,187 @@
+// Inferno utils/8l/obj.c
+// http://code.google.com/p/inferno-os/source/browse/utils/8l/obj.c
+//
+//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
+//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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 x86
+
+import (
+	"cmd/internal/obj"
+	"cmd/link/internal/ld"
+	"fmt"
+	"log"
+)
+
+// Reading object files.
+
+func Main() {
+	linkarchinit()
+	ld.Ldmain()
+}
+
+func linkarchinit() {
+	ld.Thestring = "386"
+	ld.Thelinkarch = &ld.Link386
+
+	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.Dwarfreglr = DWARFREGLR
+
+	ld.Thearch.Adddynrel = adddynrel
+	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.PEreloc1 = pereloc1
+	ld.Thearch.Lput = ld.Lputl
+	ld.Thearch.Wput = ld.Wputl
+	ld.Thearch.Vput = ld.Vputl
+
+	ld.Thearch.Linuxdynld = "/lib/ld-linux.so.2"
+	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.Solarisdynld = "/lib/ld.so.1"
+}
+
+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)))
+		}
+
+	case obj.Hdarwin,
+		obj.Hfreebsd,
+		obj.Hlinux,
+		obj.Hnetbsd,
+		obj.Hopenbsd,
+		obj.Hwindows:
+		break
+	}
+
+	switch ld.HEADTYPE {
+	default:
+		ld.Exitf("unknown -H option: %v", ld.HEADTYPE)
+
+	case obj.Hplan9: /* plan 9 */
+		ld.HEADR = 32
+
+		if ld.INITTEXT == -1 {
+			ld.INITTEXT = 4096 + 32
+		}
+		if ld.INITDAT == -1 {
+			ld.INITDAT = 0
+		}
+		if ld.INITRND == -1 {
+			ld.INITRND = 4096
+		}
+
+	case obj.Hdarwin: /* apple MACH */
+		ld.Machoinit()
+
+		ld.HEADR = ld.INITIAL_MACHO_HEADR
+		if ld.INITTEXT == -1 {
+			ld.INITTEXT = 4096 + int64(ld.HEADR)
+		}
+		if ld.INITDAT == -1 {
+			ld.INITDAT = 0
+		}
+		if ld.INITRND == -1 {
+			ld.INITRND = 4096
+		}
+
+	case obj.Hlinux, /* elf32 executable */
+		obj.Hfreebsd,
+		obj.Hnetbsd,
+		obj.Hopenbsd:
+		ld.Elfinit()
+
+		ld.HEADR = ld.ELFRESERVE
+		if ld.INITTEXT == -1 {
+			ld.INITTEXT = 0x08048000 + int64(ld.HEADR)
+		}
+		if ld.INITDAT == -1 {
+			ld.INITDAT = 0
+		}
+		if ld.INITRND == -1 {
+			ld.INITRND = 4096
+		}
+
+	case obj.Hnacl:
+		ld.Elfinit()
+		ld.HEADR = 0x10000
+		ld.Funcalign = 32
+		if ld.INITTEXT == -1 {
+			ld.INITTEXT = 0x20000
+		}
+		if ld.INITDAT == -1 {
+			ld.INITDAT = 0
+		}
+		if ld.INITRND == -1 {
+			ld.INITRND = 0x10000
+		}
+
+	case obj.Hwindows: /* PE executable */
+		ld.Peinit()
+
+		ld.HEADR = ld.PEFILEHEADR
+		if ld.INITTEXT == -1 {
+			ld.INITTEXT = ld.PEBASE + int64(ld.PESECTHEADR)
+		}
+		if ld.INITDAT == -1 {
+			ld.INITDAT = 0
+		}
+		if ld.INITRND == -1 {
+			ld.INITRND = ld.PESECTALIGN
+		}
+	}
+
+	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/link/main.go b/src/cmd/link/main.go
new file mode 100644
index 0000000..0e6c34e
--- /dev/null
+++ b/src/cmd/link/main.go
@@ -0,0 +1,34 @@
+// 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 (
+	"cmd/internal/obj"
+	"cmd/link/internal/amd64"
+	"cmd/link/internal/arm"
+	"cmd/link/internal/arm64"
+	"cmd/link/internal/ppc64"
+	"cmd/link/internal/x86"
+	"fmt"
+	"os"
+)
+
+func main() {
+	switch obj.Getgoarch() {
+	default:
+		fmt.Fprintf(os.Stderr, "link: unknown architecture %q\n", obj.Getgoarch())
+		os.Exit(2)
+	case "386":
+		x86.Main()
+	case "amd64", "amd64p32":
+		amd64.Main()
+	case "arm":
+		arm.Main()
+	case "arm64":
+		arm64.Main()
+	case "ppc64", "ppc64le":
+		ppc64.Main()
+	}
+}
diff --git a/src/cmd/nm/nm_test.go b/src/cmd/nm/nm_test.go
index cb555d8..602a288 100644
--- a/src/cmd/nm/nm_test.go
+++ b/src/cmd/nm/nm_test.go
@@ -8,6 +8,7 @@ import (
 	"bufio"
 	"bytes"
 	"fmt"
+	"internal/testenv"
 	"io/ioutil"
 	"os"
 	"os/exec"
@@ -55,10 +56,7 @@ func checkSymbols(t *testing.T, nmoutput []byte) {
 }
 
 func TestNM(t *testing.T) {
-	switch runtime.GOOS {
-	case "android", "nacl":
-		t.Skipf("skipping on %s", runtime.GOOS)
-	}
+	testenv.MustHaveGoBuild(t)
 
 	tmpDir, err := ioutil.TempDir("", "TestNM")
 	if err != nil {
diff --git a/src/cmd/objdump/main.go b/src/cmd/objdump/main.go
index 708a853..8bf9e4e 100644
--- a/src/cmd/objdump/main.go
+++ b/src/cmd/objdump/main.go
@@ -80,7 +80,7 @@ func main() {
 
 	dis, err := f.Disasm()
 	if err != nil {
-		log.Fatal("disassemble %s: %v", flag.Arg(0), err)
+		log.Fatalf("disassemble %s: %v", flag.Arg(0), err)
 	}
 
 	switch flag.NArg() {
diff --git a/src/cmd/objdump/objdump_test.go b/src/cmd/objdump/objdump_test.go
index 2bb7466..b6c339b 100644
--- a/src/cmd/objdump/objdump_test.go
+++ b/src/cmd/objdump/objdump_test.go
@@ -5,6 +5,8 @@
 package main
 
 import (
+	"go/build"
+	"internal/testenv"
 	"io/ioutil"
 	"os"
 	"os/exec"
@@ -15,10 +17,7 @@ import (
 )
 
 func buildObjdump(t *testing.T) (tmp, exe string) {
-	switch runtime.GOOS {
-	case "android", "nacl":
-		t.Skipf("skipping on %s", runtime.GOOS)
-	}
+	testenv.MustHaveGoBuild(t)
 
 	tmp, err := ioutil.TempDir("", "TestObjDump")
 	if err != nil {
@@ -101,6 +100,12 @@ func testDisasm(t *testing.T, flags ...string) {
 }
 
 func TestDisasm(t *testing.T) {
+	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)
 }
 
@@ -109,5 +114,18 @@ func TestDisasmExtld(t *testing.T) {
 	case "plan9", "windows":
 		t.Skipf("skipping on %s", runtime.GOOS)
 	}
+	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)
+	}
+	// TODO(jsing): Reenable once openbsd/arm has external linking support.
+	if runtime.GOOS == "openbsd" && runtime.GOARCH == "arm" {
+		t.Skip("skipping on openbsd/arm, no support for external linking, issue 10619")
+	}
+	if !build.Default.CgoEnabled {
+		t.Skip("skipping because cgo is not enabled")
+	}
 	testDisasm(t, "-ldflags=-linkmode=external")
 }
diff --git a/src/cmd/pack/pack.go b/src/cmd/pack/pack.go
index ffb2d61..f65ae0c 100644
--- a/src/cmd/pack/pack.go
+++ b/src/cmd/pack/pack.go
@@ -183,7 +183,7 @@ func existingArchive(name string) bool {
 		if os.IsNotExist(err) {
 			return false
 		}
-		log.Fatal("cannot open file: %s", err)
+		log.Fatalf("cannot open file: %s", err)
 	}
 	checkHeader(fd)
 	fd.Close()
@@ -196,7 +196,7 @@ func checkHeader(fd *os.File) {
 	buf := make([]byte, len(arHeader))
 	_, err := io.ReadFull(fd, buf)
 	if err != nil || string(buf) != arHeader {
-		log.Fatal("%s is not an archive: bad header", fd.Name())
+		log.Fatalf("%s is not an archive: bad header", fd.Name())
 	}
 }
 
diff --git a/src/cmd/pack/pack_test.go b/src/cmd/pack/pack_test.go
index cf6121f..c305a87 100644
--- a/src/cmd/pack/pack_test.go
+++ b/src/cmd/pack/pack_test.go
@@ -8,13 +8,12 @@ import (
 	"bufio"
 	"bytes"
 	"fmt"
+	"internal/testenv"
 	"io"
 	"io/ioutil"
 	"os"
 	"os/exec"
 	"path/filepath"
-	"regexp"
-	"runtime"
 	"testing"
 	"time"
 	"unicode/utf8"
@@ -199,10 +198,7 @@ func TestExtract(t *testing.T) {
 
 // Test that pack-created archives can be understood by the tools.
 func TestHello(t *testing.T) {
-	switch runtime.GOOS {
-	case "android", "nacl":
-		t.Skipf("skipping on %s", runtime.GOOS)
-	}
+	testenv.MustHaveGoBuild(t)
 
 	dir := tmpDir(t)
 	defer os.RemoveAll(dir)
@@ -218,16 +214,14 @@ func TestHello(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	char := findChar(t, dir)
-
 	run := func(args ...string) string {
 		return doRun(t, dir, args...)
 	}
 
 	run("go", "build", "cmd/pack") // writes pack binary to dir
-	run("go", "tool", char+"g", "hello.go")
-	run("./pack", "grc", "hello.a", "hello."+char)
-	run("go", "tool", char+"l", "-o", "a.out", "hello.a")
+	run("go", "tool", "compile", "hello.go")
+	run("./pack", "grc", "hello.a", "hello.o")
+	run("go", "tool", "link", "-o", "a.out", "hello.a")
 	out := run("./a.out")
 	if out != "hello world\n" {
 		t.Fatalf("incorrect output: %q, want %q", out, "hello world\n")
@@ -236,10 +230,7 @@ func TestHello(t *testing.T) {
 
 // Test that pack works with very long lines in PKGDEF.
 func TestLargeDefs(t *testing.T) {
-	switch runtime.GOOS {
-	case "android", "nacl":
-		t.Skipf("skipping on %s", runtime.GOOS)
-	}
+	testenv.MustHaveGoBuild(t)
 
 	dir := tmpDir(t)
 	defer os.RemoveAll(dir)
@@ -258,7 +249,7 @@ func TestLargeDefs(t *testing.T) {
 	}
 
 	printf("package large\n\ntype T struct {\n")
-	for i := 0; i < 10000; i++ {
+	for i := 0; i < 1000; i++ {
 		printf("f%d int `tag:\"", i)
 		for j := 0; j < 100; j++ {
 			printf("t%d=%d,", j, j)
@@ -287,17 +278,15 @@ func TestLargeDefs(t *testing.T) {
 		t.Fatal(err)
 	}
 
-	char := findChar(t, dir)
-
 	run := func(args ...string) string {
 		return doRun(t, dir, args...)
 	}
 
 	run("go", "build", "cmd/pack") // writes pack binary to dir
-	run("go", "tool", char+"g", "large.go")
-	run("./pack", "grc", "large.a", "large."+char)
-	run("go", "tool", char+"g", "-I", ".", "main.go")
-	run("go", "tool", char+"l", "-L", ".", "-o", "a.out", "main."+char)
+	run("go", "tool", "compile", "large.go")
+	run("./pack", "grc", "large.a", "large.o")
+	run("go", "tool", "compile", "-I", ".", "main.go")
+	run("go", "tool", "link", "-L", ".", "-o", "a.out", "main.o")
 	out := run("./a.out")
 	if out != "ok\n" {
 		t.Fatalf("incorrect output: %q, want %q", out, "ok\n")
@@ -315,20 +304,6 @@ func doRun(t *testing.T, dir string, args ...string) string {
 	return string(out)
 }
 
-// findChar returns the architecture character for the go command.
-func findChar(t *testing.T, dir string) string {
-	out := doRun(t, dir, "go", "env")
-	re, err := regexp.Compile(`\s*GOCHAR=['"]?(\w)['"]?`)
-	if err != nil {
-		t.Fatal(err)
-	}
-	fields := re.FindStringSubmatch(out)
-	if fields == nil {
-		t.Fatal("cannot find GOCHAR in 'go env' output:\n", out)
-	}
-	return fields[1]
-}
-
 // Fake implementation of files.
 
 var helloFile = &FakeFile{
diff --git a/src/cmd/pprof/doc.go b/src/cmd/pprof/doc.go
index c6ff11d..1e094fe 100644
--- a/src/cmd/pprof/doc.go
+++ b/src/cmd/pprof/doc.go
@@ -8,5 +8,5 @@
 //
 //	go tool pprof binary profile
 //
-// For more information, see http://blog.golang.org/profiling-go-programs.
+// For more information, see https://blog.golang.org/profiling-go-programs.
 package main
diff --git a/src/cmd/pprof/internal/commands/commands.go b/src/cmd/pprof/internal/commands/commands.go
index 51397a3..9aeee57 100644
--- a/src/cmd/pprof/internal/commands/commands.go
+++ b/src/cmd/pprof/internal/commands/commands.go
@@ -9,10 +9,12 @@ import (
 	"bytes"
 	"fmt"
 	"io"
+	"io/ioutil"
 	"os"
 	"os/exec"
 	"runtime"
 	"strings"
+	"time"
 
 	"cmd/pprof/internal/plugin"
 	"cmd/pprof/internal/report"
@@ -42,7 +44,7 @@ type Completer func(prefix string) string
 type PostProcessor func(input *bytes.Buffer, output io.Writer, ui plugin.UI) error
 
 // PProf returns the basic pprof report-generation commands
-func PProf(c Completer, interactive **bool, svgpan **string) Commands {
+func PProf(c Completer, interactive **bool) Commands {
 	return Commands{
 		// Commands that require no post-processing.
 		"tags":   {nil, report.Tags, nil, false, "Outputs all tags in the profile"},
@@ -66,13 +68,13 @@ func PProf(c Completer, interactive **bool, svgpan **string) Commands {
 		"ps":  {c, report.Dot, invokeDot("ps"), false, "Outputs a graph in PS format"},
 
 		// Save SVG output into a file after including svgpan library
-		"svg": {c, report.Dot, saveSVGToFile(svgpan), false, "Outputs a graph in SVG format"},
+		"svg": {c, report.Dot, saveSVGToFile(), false, "Outputs a graph in SVG format"},
 
 		// Visualize postprocessed dot output
 		"eog":    {c, report.Dot, invokeVisualizer(interactive, invokeDot("svg"), "svg", []string{"eog"}), false, "Visualize graph through eog"},
 		"evince": {c, report.Dot, invokeVisualizer(interactive, invokeDot("pdf"), "pdf", []string{"evince"}), false, "Visualize graph through evince"},
 		"gv":     {c, report.Dot, invokeVisualizer(interactive, invokeDot("ps"), "ps", []string{"gv --noantialias"}), false, "Visualize graph through gv"},
-		"web":    {c, report.Dot, invokeVisualizer(interactive, saveSVGToFile(svgpan), "svg", browsers()), false, "Visualize graph through web browser"},
+		"web":    {c, report.Dot, invokeVisualizer(interactive, saveSVGToFile(), "svg", browsers()), false, "Visualize graph through web browser"},
 
 		// Visualize HTML directly generated by report.
 		"weblist": {c, report.WebList, invokeVisualizer(interactive, awayFromTTY("html"), "html", browsers()), true, "Output annotated source in HTML for functions matching regexp or address"},
@@ -82,7 +84,10 @@ func PProf(c Completer, interactive **bool, svgpan **string) Commands {
 // browsers returns a list of commands to attempt for web visualization
 // on the current platform
 func browsers() []string {
-	cmds := []string{"chrome", "google-chrome", "firefox"}
+	var cmds []string
+	if exe := os.Getenv("BROWSER"); exe != "" {
+		cmds = append(cmds, exe)
+	}
 	switch runtime.GOOS {
 	case "darwin":
 		cmds = append(cmds, "/usr/bin/open")
@@ -91,6 +96,7 @@ func browsers() []string {
 	default:
 		cmds = append(cmds, "xdg-open")
 	}
+	cmds = append(cmds, "chrome", "google-chrome", "firefox")
 	return cmds
 }
 
@@ -169,21 +175,38 @@ func invokeDot(format string) PostProcessor {
 	}
 }
 
-func saveSVGToFile(svgpan **string) PostProcessor {
+func saveSVGToFile() PostProcessor {
 	generateSVG := invokeDot("svg")
 	divert := awayFromTTY("svg")
 	return func(input *bytes.Buffer, output io.Writer, ui plugin.UI) error {
 		baseSVG := &bytes.Buffer{}
 		generateSVG(input, baseSVG, ui)
 		massaged := &bytes.Buffer{}
-		fmt.Fprint(massaged, svg.Massage(*baseSVG, **svgpan))
+		fmt.Fprint(massaged, svg.Massage(*baseSVG))
 		return divert(massaged, output, ui)
 	}
 }
 
+var vizTmpDir string
+
+func makeVizTmpDir() error {
+	if vizTmpDir != "" {
+		return nil
+	}
+	name, err := ioutil.TempDir("", "pprof-")
+	if err != nil {
+		return err
+	}
+	vizTmpDir = name
+	return nil
+}
+
 func invokeVisualizer(interactive **bool, format PostProcessor, suffix string, visualizers []string) PostProcessor {
 	return func(input *bytes.Buffer, output io.Writer, ui plugin.UI) error {
-		tempFile, err := tempfile.New(os.Getenv("PPROF_TMPDIR"), "pprof", "."+suffix)
+		if err := makeVizTmpDir(); err != nil {
+			return err
+		}
+		tempFile, err := tempfile.New(vizTmpDir, "pprof", "."+suffix)
 		if err != nil {
 			return err
 		}
@@ -202,6 +225,11 @@ func invokeVisualizer(interactive **bool, format PostProcessor, suffix string, v
 			viewer := exec.Command(args[0], append(args[1:], tempFile.Name())...)
 			viewer.Stderr = os.Stderr
 			if err = viewer.Start(); err == nil {
+				// The viewer might just send a message to another program
+				// to open the file. Give that program a little time to open the
+				// file before we remove it.
+				time.Sleep(1 * time.Second)
+
 				if !**interactive {
 					// In command-line mode, wait for the viewer to be closed
 					// before proceeding
diff --git a/src/cmd/pprof/internal/driver/driver.go b/src/cmd/pprof/internal/driver/driver.go
index 68b5d1b..df6a2d1 100644
--- a/src/cmd/pprof/internal/driver/driver.go
+++ b/src/cmd/pprof/internal/driver/driver.go
@@ -106,7 +106,9 @@ func PProf(flagset plugin.FlagSet, fetch plugin.Fetcher, sym plugin.Symbolizer,
 		return err
 	}
 
-	prof.RemoveUninteresting()
+	if !*f.flagRuntime {
+		prof.RemoveUninteresting()
+	}
 
 	if *f.flagInteractive {
 		return interactive(prof, obj, ui, f)
@@ -427,7 +429,6 @@ type flags struct {
 	flagCommands      map[string]*bool   // pprof commands without parameters
 	flagParamCommands map[string]*string // pprof commands with parameters
 
-	flagSVGPan *string // URL to fetch the SVG Pan library
 	flagOutput *string // Output file name
 
 	flagCum      *bool // Sort by cumulative data
@@ -445,6 +446,7 @@ type flags struct {
 	flagNodeFraction *float64 // Hide nodes below <f>*total
 	flagEdgeFraction *float64 // Hide edges below <f>*total
 	flagTrim         *bool    // Set to false to ignore NodeCount/*Fraction
+	flagRuntime      *bool    // Show runtime call frames in memory profiles
 	flagFocus        *string  // Restricts to paths going through a node matching regexp
 	flagIgnore       *string  // Skips paths going through any nodes matching regexp
 	flagHide         *string  // Skips sample locations matching regexp
@@ -622,7 +624,6 @@ func getFlags(flag plugin.FlagSet, overrides commands.Commands, ui plugin.UI) (*
 		flagBase:         flag.String("base", "", "Source for base profile for comparison"),
 		flagDropNegative: flag.Bool("drop_negative", false, "Ignore negative differences"),
 
-		flagSVGPan: flag.String("svgpan", "https://www.cyberz.org/projects/SVGPan/SVGPan.js", "URL for SVGPan Library"),
 		// Data sorting criteria.
 		flagCum: flag.Bool("cum", false, "Sort by cumulative data"),
 		// Graph handling options.
@@ -640,6 +641,7 @@ func getFlags(flag plugin.FlagSet, overrides commands.Commands, ui plugin.UI) (*
 		flagNodeFraction: flag.Float64("nodefraction", 0.005, "Hide nodes below <f>*total"),
 		flagEdgeFraction: flag.Float64("edgefraction", 0.001, "Hide edges below <f>*total"),
 		flagTrim:         flag.Bool("trim", true, "Honor nodefraction/edgefraction/nodecount defaults"),
+		flagRuntime:      flag.Bool("runtime", false, "Show runtime call frames in memory profiles"),
 		flagFocus:        flag.String("focus", "", "Restricts to paths going through a node matching regexp"),
 		flagIgnore:       flag.String("ignore", "", "Skips paths going through any nodes matching regexp"),
 		flagHide:         flag.String("hide", "", "Skips nodes matching regexp"),
@@ -666,8 +668,7 @@ func getFlags(flag plugin.FlagSet, overrides commands.Commands, ui plugin.UI) (*
 
 	// Flags used during command processing
 	interactive := &f.flagInteractive
-	svgpan := &f.flagSVGPan
-	f.commands = commands.PProf(functionCompleter, interactive, svgpan)
+	f.commands = commands.PProf(functionCompleter, interactive)
 
 	// Override commands
 	for name, cmd := range overrides {
@@ -877,6 +878,7 @@ var usageMsg = "Output file parameters (for file-based output formats):\n" +
 	"  -contentions      Display number of delays at each region\n" +
 	"  -mean_delay       Display mean delay at each region\n" +
 	"Filtering options:\n" +
+	"  -runtime          Show runtime call frames in memory profiles\n" +
 	"  -focus=r          Restricts to paths going through a node matching regexp\n" +
 	"  -ignore=r         Skips paths going through any nodes matching regexp\n" +
 	"  -tagfocus=r       Restrict to samples tagged with key:value matching regexp\n" +
@@ -886,14 +888,13 @@ var usageMsg = "Output file parameters (for file-based output formats):\n" +
 	"Miscellaneous:\n" +
 	"  -call_tree        Generate a context-sensitive call tree\n" +
 	"  -unit=u           Convert all samples to unit u for display\n" +
-	"  -show_bytes       Display all space in bytes\n" +
 	"  -divide_by=f      Scale all samples by dividing them by f\n" +
 	"  -buildid=id       Override build id for main binary in profile\n" +
 	"  -tools=path       Search path for object-level tools\n" +
 	"  -help             This message"
 
 var usageMsgVars = "Environment Variables:\n" +
-	"   PPROF_TMPDIR       Location for temporary files (default $HOME/pprof)\n" +
+	"   PPROF_TMPDIR       Location for saved profiles (default $HOME/pprof)\n" +
 	"   PPROF_TOOLS        Search path for object-level tools\n" +
 	"   PPROF_BINARY_PATH  Search path for local binary files\n" +
 	"                      default: $HOME/pprof/binaries\n" +
@@ -1009,6 +1010,10 @@ func generate(interactive bool, prof *profile.Profile, obj plugin.ObjTool, ui pl
 		w = outputFile
 	}
 
+	if prof.Empty() {
+		return fmt.Errorf("profile is empty")
+	}
+
 	value, stype, unit := sampleFormat(prof, f)
 	o.SampleType = stype
 	rpt := report.New(prof, *o, value, unit)
diff --git a/src/cmd/pprof/internal/profile/encode.go b/src/cmd/pprof/internal/profile/encode.go
index 455aca2..9e66998 100644
--- a/src/cmd/pprof/internal/profile/encode.go
+++ b/src/cmd/pprof/internal/profile/encode.go
@@ -162,7 +162,7 @@ var profileDecoder = []decoder{
 		pp.Location = append(pp.Location, x)
 		return decodeMessage(b, x)
 	},
-	// repeasted Function function = 5
+	// repeated Function function = 5
 	func(b *buffer, m message) error {
 		x := new(Function)
 		pp := m.(*Profile)
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/pprof/internal/profile/legacy_profile.go b/src/cmd/pprof/internal/profile/legacy_profile.go
index bfc8110..e4c92cd 100644
--- a/src/cmd/pprof/internal/profile/legacy_profile.go
+++ b/src/cmd/pprof/internal/profile/legacy_profile.go
@@ -554,9 +554,10 @@ func parseHeap(b []byte) (p *Profile, err error) {
 			}
 		}
 
-		if l = strings.TrimSpace(l); l == "" {
+		if isSpaceOrComment(l) {
 			continue
 		}
+		l = strings.TrimSpace(l)
 
 		if sectionTrigger(l) != unrecognizedSection {
 			break
diff --git a/src/cmd/pprof/internal/profile/profile.go b/src/cmd/pprof/internal/profile/profile.go
index 7ee58ee..6d175bf 100644
--- a/src/cmd/pprof/internal/profile/profile.go
+++ b/src/cmd/pprof/internal/profile/profile.go
@@ -125,11 +125,11 @@ func Parse(r io.Reader) (*Profile, error) {
 
 	var p *Profile
 	if len(orig) >= 2 && orig[0] == 0x1f && orig[1] == 0x8b {
-		var data []byte
-
-		if gz, err := gzip.NewReader(bytes.NewBuffer(orig)); err == nil {
-			data, err = ioutil.ReadAll(gz)
+		gz, err := gzip.NewReader(bytes.NewBuffer(orig))
+		if err != nil {
+			return nil, fmt.Errorf("decompressing profile: %v", err)
 		}
+		data, err := ioutil.ReadAll(gz)
 		if err != nil {
 			return nil, fmt.Errorf("decompressing profile: %v", err)
 		}
@@ -565,3 +565,8 @@ func (p *Profile) Demangle(d Demangler) error {
 	}
 	return nil
 }
+
+// Empty returns true if the profile contains no samples.
+func (p *Profile) Empty() bool {
+	return len(p.Sample) == 0
+}
diff --git a/src/cmd/pprof/internal/profile/profile_test.go b/src/cmd/pprof/internal/profile/profile_test.go
new file mode 100644
index 0000000..09b11a4
--- /dev/null
+++ b/src/cmd/pprof/internal/profile/profile_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.
+
+package profile
+
+import (
+	"bytes"
+	"testing"
+)
+
+func TestEmptyProfile(t *testing.T) {
+	var buf bytes.Buffer
+	p, err := Parse(&buf)
+	if err != nil {
+		t.Error("Want no error, got", err)
+	}
+	if p == nil {
+		t.Fatal("Want a valid profile, got <nil>")
+	}
+	if !p.Empty() {
+		t.Errorf("Profile should be empty, got %#v", p)
+	}
+}
diff --git a/src/cmd/pprof/internal/report/report.go b/src/cmd/pprof/internal/report/report.go
index e5977fd..586f41d 100644
--- a/src/cmd/pprof/internal/report/report.go
+++ b/src/cmd/pprof/internal/report/report.go
@@ -1531,7 +1531,7 @@ func memoryLabel(value int64, fromUnit, toUnit string) (v float64, u string, ok
 		output, toUnit = float64(value)/1024, "kB"
 	case "mb", "mbyte", "megabyte":
 		output, toUnit = float64(value)/(1024*1024), "MB"
-	case "gb", "gbyte", "giggabyte":
+	case "gb", "gbyte", "gigabyte":
 		output, toUnit = float64(value)/(1024*1024*1024), "GB"
 	}
 	return output, toUnit, true
diff --git a/src/cmd/pprof/internal/report/source.go b/src/cmd/pprof/internal/report/source.go
index 57300dd..73ae1b4 100644
--- a/src/cmd/pprof/internal/report/source.go
+++ b/src/cmd/pprof/internal/report/source.go
@@ -358,9 +358,13 @@ func getFunctionSource(fun, file string, fns nodes, start, end int) (nodes, stri
 	for {
 		line, err := buf.ReadString('\n')
 		if err != nil {
-			if line == "" || err != io.EOF {
+			if err != io.EOF {
 				return nil, file, err
 			}
+			if line == "" {
+				// end was at or past EOF; that's okay
+				break
+			}
 		}
 		if lineno >= start {
 			flat, cum := sumNodes(lineNodes[lineno])
diff --git a/src/cmd/pprof/internal/svg/svg.go b/src/cmd/pprof/internal/svg/svg.go
index aa65a1a..04f6ff1 100644
--- a/src/cmd/pprof/internal/svg/svg.go
+++ b/src/cmd/pprof/internal/svg/svg.go
@@ -17,18 +17,15 @@ var (
 	svgClose = regexp.MustCompile(`</svg>`)
 )
 
-// Massage enhances the SVG output from DOT to provide bettern
+// Massage enhances the SVG output from DOT to provide better
 // panning inside a web browser. It uses the SVGPan library, which is
-// accessed through the svgPan URL.
-func Massage(in bytes.Buffer, svgPan string) string {
+// included directly.
+func Massage(in bytes.Buffer) string {
 	svg := string(in.Bytes())
 
 	// Work around for dot bug which misses quoting some ampersands,
 	// resulting on unparsable SVG.
 	svg = strings.Replace(svg, "&;", "&;", -1)
-	if svgPan == "" {
-		return svg
-	}
 
 	//Dot's SVG output is
 	//
@@ -43,8 +40,7 @@ func Massage(in bytes.Buffer, svgPan string) string {
 	//
 	//    <svg width="100%" height="100%"
 	//     xmlns=...>
-	//    <script xlink:href=" ...$svgpan.. "/>
-
+	//    <script>...</script>
 	//    <g id="viewport" transform="translate(0,0)">
 	//    <g id="graph0" transform="...">
 	//    ...
@@ -60,7 +56,7 @@ func Massage(in bytes.Buffer, svgPan string) string {
 
 	if loc := graphId.FindStringIndex(svg); loc != nil {
 		svg = svg[:loc[0]] +
-			`<script xlink:href="` + svgPan + `"/>` +
+			`<script type="text/ecmascript"><![CDATA[` + svgPanJS + `]]></script>` +
 			`<g id="viewport" transform="scale(0.5,0.5) translate(0,0)">` +
 			svg[loc[0]:]
 	}
diff --git a/src/cmd/pprof/internal/svg/svgpan.go b/src/cmd/pprof/internal/svg/svgpan.go
new file mode 100644
index 0000000..4975b10
--- /dev/null
+++ b/src/cmd/pprof/internal/svg/svgpan.go
@@ -0,0 +1,291 @@
+// SVG pan and zoom library.
+// See copyright notice in string constant below.
+
+package svg
+
+// https://www.cyberz.org/projects/SVGPan/SVGPan.js
+
+const svgPanJS = `
+/** 
+ *  SVGPan library 1.2.1
+ * ======================
+ *
+ * Given an unique existing element with id "viewport" (or when missing, the first g 
+ * element), including the the library into any SVG adds the following capabilities:
+ *
+ *  - Mouse panning
+ *  - Mouse zooming (using the wheel)
+ *  - Object dragging
+ *
+ * You can configure the behaviour of the pan/zoom/drag with the variables
+ * listed in the CONFIGURATION section of this file.
+ *
+ * Known issues:
+ *
+ *  - Zooming (while panning) on Safari has still some issues
+ *
+ * Releases:
+ *
+ * 1.2.1, Mon Jul  4 00:33:18 CEST 2011, Andrea Leofreddi
+ *	- Fixed a regression with mouse wheel (now working on Firefox 5)
+ *	- Working with viewBox attribute (#4)
+ *	- Added "use strict;" and fixed resulting warnings (#5)
+ *	- Added configuration variables, dragging is disabled by default (#3)
+ *
+ * 1.2, Sat Mar 20 08:42:50 GMT 2010, Zeng Xiaohui
+ *	Fixed a bug with browser mouse handler interaction
+ *
+ * 1.1, Wed Feb  3 17:39:33 GMT 2010, Zeng Xiaohui
+ *	Updated the zoom code to support the mouse wheel on Safari/Chrome
+ *
+ * 1.0, Andrea Leofreddi
+ *	First release
+ *
+ * This code is licensed under the following BSD license:
+ *
+ * Copyright 2009-2010 Andrea Leofreddi <a.leofreddi at itcharm.com>. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ * 
+ *    1. Redistributions of source code must retain the above copyright notice, this list of
+ *       conditions and the following disclaimer.
+ * 
+ *    2. Redistributions in binary form must reproduce the above copyright notice, this list
+ *       of conditions and the following disclaimer in the documentation and/or other materials
+ *       provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY Andrea Leofreddi ` + "``AS IS''" + ` AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Andrea Leofreddi OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of Andrea Leofreddi.
+ */
+
+"use strict";
+
+/// CONFIGURATION 
+/// ====>
+
+var enablePan = 1; // 1 or 0: enable or disable panning (default enabled)
+var enableZoom = 1; // 1 or 0: enable or disable zooming (default enabled)
+var enableDrag = 0; // 1 or 0: enable or disable dragging (default disabled)
+
+/// <====
+/// END OF CONFIGURATION 
+
+var root = document.documentElement;
+
+var state = 'none', svgRoot, stateTarget, stateOrigin, stateTf;
+
+setupHandlers(root);
+
+/**
+ * Register handlers
+ */
+function setupHandlers(root){
+	setAttributes(root, {
+		"onmouseup" : "handleMouseUp(evt)",
+		"onmousedown" : "handleMouseDown(evt)",
+		"onmousemove" : "handleMouseMove(evt)",
+		//"onmouseout" : "handleMouseUp(evt)", // Decomment this to stop the pan functionality when dragging out of the SVG element
+	});
+
+	if(navigator.userAgent.toLowerCase().indexOf('webkit') >= 0)
+		window.addEventListener('mousewheel', handleMouseWheel, false); // Chrome/Safari
+	else
+		window.addEventListener('DOMMouseScroll', handleMouseWheel, false); // Others
+}
+
+/**
+ * Retrieves the root element for SVG manipulation. The element is then cached into the svgRoot global variable.
+ */
+function getRoot(root) {
+	if(typeof(svgRoot) == "undefined") {
+		var g = null;
+
+		g = root.getElementById("viewport");
+
+		if(g == null)
+			g = root.getElementsByTagName('g')[0];
+
+		if(g == null)
+			alert('Unable to obtain SVG root element');
+
+		setCTM(g, g.getCTM());
+
+		g.removeAttribute("viewBox");
+
+		svgRoot = g;
+	}
+
+	return svgRoot;
+}
+
+/**
+ * Instance an SVGPoint object with given event coordinates.
+ */
+function getEventPoint(evt) {
+	var p = root.createSVGPoint();
+
+	p.x = evt.clientX;
+	p.y = evt.clientY;
+
+	return p;
+}
+
+/**
+ * Sets the current transform matrix of an element.
+ */
+function setCTM(element, matrix) {
+	var s = "matrix(" + matrix.a + "," + matrix.b + "," + matrix.c + "," + matrix.d + "," + matrix.e + "," + matrix.f + ")";
+
+	element.setAttribute("transform", s);
+}
+
+/**
+ * Dumps a matrix to a string (useful for debug).
+ */
+function dumpMatrix(matrix) {
+	var s = "[ " + matrix.a + ", " + matrix.c + ", " + matrix.e + "\n  " + matrix.b + ", " + matrix.d + ", " + matrix.f + "\n  0, 0, 1 ]";
+
+	return s;
+}
+
+/**
+ * Sets attributes of an element.
+ */
+function setAttributes(element, attributes){
+	for (var i in attributes)
+		element.setAttributeNS(null, i, attributes[i]);
+}
+
+/**
+ * Handle mouse wheel event.
+ */
+function handleMouseWheel(evt) {
+	if(!enableZoom)
+		return;
+
+	if(evt.preventDefault)
+		evt.preventDefault();
+
+	evt.returnValue = false;
+
+	var svgDoc = evt.target.ownerDocument;
+
+	var delta;
+
+	if(evt.wheelDelta)
+		delta = evt.wheelDelta / 3600; // Chrome/Safari
+	else
+		delta = evt.detail / -90; // Mozilla
+
+	var z = 1 + delta; // Zoom factor: 0.9/1.1
+
+	var g = getRoot(svgDoc);
+	
+	var p = getEventPoint(evt);
+
+	p = p.matrixTransform(g.getCTM().inverse());
+
+	// Compute new scale matrix in current mouse position
+	var k = root.createSVGMatrix().translate(p.x, p.y).scale(z).translate(-p.x, -p.y);
+
+        setCTM(g, g.getCTM().multiply(k));
+
+	if(typeof(stateTf) == "undefined")
+		stateTf = g.getCTM().inverse();
+
+	stateTf = stateTf.multiply(k.inverse());
+}
+
+/**
+ * Handle mouse move event.
+ */
+function handleMouseMove(evt) {
+	if(evt.preventDefault)
+		evt.preventDefault();
+
+	evt.returnValue = false;
+
+	var svgDoc = evt.target.ownerDocument;
+
+	var g = getRoot(svgDoc);
+
+	if(state == 'pan' && enablePan) {
+		// Pan mode
+		var p = getEventPoint(evt).matrixTransform(stateTf);
+
+		setCTM(g, stateTf.inverse().translate(p.x - stateOrigin.x, p.y - stateOrigin.y));
+	} else if(state == 'drag' && enableDrag) {
+		// Drag mode
+		var p = getEventPoint(evt).matrixTransform(g.getCTM().inverse());
+
+		setCTM(stateTarget, root.createSVGMatrix().translate(p.x - stateOrigin.x, p.y - stateOrigin.y).multiply(g.getCTM().inverse()).multiply(stateTarget.getCTM()));
+
+		stateOrigin = p;
+	}
+}
+
+/**
+ * Handle click event.
+ */
+function handleMouseDown(evt) {
+	if(evt.preventDefault)
+		evt.preventDefault();
+
+	evt.returnValue = false;
+
+	var svgDoc = evt.target.ownerDocument;
+
+	var g = getRoot(svgDoc);
+
+	if(
+		evt.target.tagName == "svg" 
+		|| !enableDrag // Pan anyway when drag is disabled and the user clicked on an element 
+	) {
+		// Pan mode
+		state = 'pan';
+
+		stateTf = g.getCTM().inverse();
+
+		stateOrigin = getEventPoint(evt).matrixTransform(stateTf);
+	} else {
+		// Drag mode
+		state = 'drag';
+
+		stateTarget = evt.target;
+
+		stateTf = g.getCTM().inverse();
+
+		stateOrigin = getEventPoint(evt).matrixTransform(stateTf);
+	}
+}
+
+/**
+ * Handle mouse button release event.
+ */
+function handleMouseUp(evt) {
+	if(evt.preventDefault)
+		evt.preventDefault();
+
+	evt.returnValue = false;
+
+	var svgDoc = evt.target.ownerDocument;
+
+	if(state == 'pan' || state == 'drag') {
+		// Quit pan mode
+		state = '';
+	}
+}
+
+`
diff --git a/src/cmd/trace/goroutines.go b/src/cmd/trace/goroutines.go
new file mode 100644
index 0000000..f5a4ddb
--- /dev/null
+++ b/src/cmd/trace/goroutines.go
@@ -0,0 +1,168 @@
+// 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.
+
+// Goroutine-related profiles.
+
+package main
+
+import (
+	"fmt"
+	"html/template"
+	"internal/trace"
+	"net/http"
+	"sort"
+	"strconv"
+	"sync"
+)
+
+func init() {
+	http.HandleFunc("/goroutines", httpGoroutines)
+	http.HandleFunc("/goroutine", httpGoroutine)
+}
+
+// gtype describes a group of goroutines grouped by start PC.
+type gtype struct {
+	ID       uint64 // Unique identifier (PC).
+	Name     string // Start function.
+	N        int    // Total number of goroutines in this group.
+	ExecTime int64  // Total execution time of all goroutines in this group.
+}
+
+type gtypeList []gtype
+
+func (l gtypeList) Len() int {
+	return len(l)
+}
+
+func (l gtypeList) Less(i, j int) bool {
+	return l[i].ExecTime > l[j].ExecTime
+}
+
+func (l gtypeList) Swap(i, j int) {
+	l[i], l[j] = l[j], l[i]
+}
+
+type gdescList []*trace.GDesc
+
+func (l gdescList) Len() int {
+	return len(l)
+}
+
+func (l gdescList) Less(i, j int) bool {
+	return l[i].TotalTime > l[j].TotalTime
+}
+
+func (l gdescList) Swap(i, j int) {
+	l[i], l[j] = l[j], l[i]
+}
+
+var (
+	gsInit sync.Once
+	gs     map[uint64]*trace.GDesc
+)
+
+// analyzeGoroutines generates statistics about execution of all goroutines and stores them in gs.
+func analyzeGoroutines(events []*trace.Event) {
+	gsInit.Do(func() {
+		gs = trace.GoroutineStats(events)
+	})
+}
+
+// httpGoroutines serves list of goroutine groups.
+func httpGoroutines(w http.ResponseWriter, r *http.Request) {
+	events, err := parseEvents()
+	if err != nil {
+		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
+	}
+	analyzeGoroutines(events)
+	gss := make(map[uint64]gtype)
+	for _, g := range gs {
+		gs1 := gss[g.PC]
+		gs1.ID = g.PC
+		gs1.Name = g.Name
+		gs1.N++
+		gs1.ExecTime += g.ExecTime
+		gss[g.PC] = gs1
+	}
+	var glist gtypeList
+	for k, v := range gss {
+		v.ID = k
+		glist = append(glist, v)
+	}
+	sort.Sort(glist)
+	templGoroutines.Execute(w, glist)
+}
+
+var templGoroutines = template.Must(template.New("").Parse(`
+<html>
+<body>
+Goroutines: <br>
+{{range $}}
+  <a href="/goroutine?id={{.ID}}">{{.Name}}</a> N={{.N}} <br>
+{{end}}
+</body>
+</html>
+`))
+
+// httpGoroutine serves list of goroutines in a particular group.
+func httpGoroutine(w http.ResponseWriter, r *http.Request) {
+	events, err := parseEvents()
+	if err != nil {
+		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
+	}
+	pc, err := strconv.ParseUint(r.FormValue("id"), 10, 64)
+	if err != nil {
+		http.Error(w, fmt.Sprintf("failed to parse id parameter '%v': %v", r.FormValue("id"), err), http.StatusInternalServerError)
+		return
+	}
+	analyzeGoroutines(events)
+	var glist gdescList
+	for _, g := range gs {
+		if g.PC != pc || g.ExecTime == 0 {
+			continue
+		}
+		glist = append(glist, g)
+	}
+	sort.Sort(glist)
+	err = templGoroutine.Execute(w, glist)
+	if err != nil {
+		http.Error(w, fmt.Sprintf("failed to execute template: %v", err), http.StatusInternalServerError)
+		return
+	}
+}
+
+var templGoroutine = template.Must(template.New("").Parse(`
+<html>
+<body>
+<table border="1" sortable="1">
+<tr>
+<th> Goroutine </th>
+<th> Total time, ns </th>
+<th> Execution time, ns </th>
+<th> Network wait time, ns </th>
+<th> Sync block time, ns </th>
+<th> Blocking syscall time, ns </th>
+<th> Scheduler wait time, ns </th>
+<th> GC sweeping time, ns </th>
+<th> GC pause time, ns </th>
+</tr>
+{{range $}}
+  <tr>
+    <td> <a href="/trace?goid={{.ID}}">{{.ID}}</a> </td>
+    <td> {{.TotalTime}} </td>
+    <td> {{.ExecTime}} </td>
+    <td> {{.IOTime}} </td>
+    <td> {{.BlockTime}} </td>
+    <td> {{.SyscallTime}} </td>
+    <td> {{.SchedWaitTime}} </td>
+    <td> {{.SweepTime}} </td>
+    <td> {{.GCTime}} </td>
+  </tr>
+{{end}}
+</table>
+</body>
+</html>
+`))
diff --git a/src/cmd/trace/main.go b/src/cmd/trace/main.go
new file mode 100644
index 0000000..27d8699
--- /dev/null
+++ b/src/cmd/trace/main.go
@@ -0,0 +1,156 @@
+// 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.
+
+/*
+Trace is a tool for viewing trace files.
+
+Trace files can be generated with:
+	- runtime/trace.Start
+	- net/http/pprof package
+	- go test -trace
+
+Example usage:
+Generate a trace file with 'go test':
+	go test -trace trace.out pkg
+View the trace in a web browser:
+	go tool trace pkg.test trace.out
+*/
+package main
+
+import (
+	"bufio"
+	"flag"
+	"fmt"
+	"internal/trace"
+	"net"
+	"net/http"
+	"os"
+	"os/exec"
+	"runtime"
+	"sync"
+)
+
+const usageMessage = "" +
+	`Usage of 'go tool trace':
+Given a trace file produced by 'go test':
+	go test -trace=trace.out pkg
+
+Open a web browser displaying trace:
+	go tool trace [flags] pkg.test trace.out
+
+Flags:
+	-http=addr: HTTP service address (e.g., ':6060')
+`
+
+var (
+	httpFlag = flag.String("http", "localhost:0", "HTTP service address (e.g., ':6060')")
+
+	// The binary file name, left here for serveSVGProfile.
+	programBinary string
+	traceFile     string
+)
+
+func main() {
+	flag.Usage = func() {
+		fmt.Fprintln(os.Stderr, usageMessage)
+		os.Exit(2)
+	}
+	flag.Parse()
+
+	// Usage information when no arguments.
+	if flag.NArg() != 2 {
+		flag.Usage()
+	}
+	programBinary = flag.Arg(0)
+	traceFile = flag.Arg(1)
+
+	ln, err := net.Listen("tcp", *httpFlag)
+	if err != nil {
+		dief("failed to create server socket: %v\n", err)
+	}
+	// Open browser.
+	if !startBrowser("http://" + ln.Addr().String()) {
+		dief("failed to start browser\n")
+	}
+
+	// Parse and symbolize trace asynchronously while browser opens.
+	go parseEvents()
+
+	// Start http server.
+	http.HandleFunc("/", httpMain)
+	err = http.Serve(ln, nil)
+	dief("failed to start http server: %v\n", err)
+}
+
+var loader struct {
+	once   sync.Once
+	events []*trace.Event
+	err    error
+}
+
+func parseEvents() ([]*trace.Event, error) {
+	loader.once.Do(func() {
+		tracef, err := os.Open(flag.Arg(1))
+		if err != nil {
+			loader.err = fmt.Errorf("failed to open trace file: %v", err)
+			return
+		}
+		defer tracef.Close()
+
+		// Parse and symbolize.
+		events, err := trace.Parse(bufio.NewReader(tracef))
+		if err != nil {
+			loader.err = fmt.Errorf("failed to parse trace: %v", err)
+			return
+		}
+		err = trace.Symbolize(events, programBinary)
+		if err != nil {
+			loader.err = fmt.Errorf("failed to symbolize trace: %v", err)
+			return
+		}
+		loader.events = events
+	})
+	return loader.events, loader.err
+}
+
+// httpMain serves the starting page.
+func httpMain(w http.ResponseWriter, r *http.Request) {
+	w.Write(templMain)
+}
+
+var templMain = []byte(`
+<html>
+<body>
+<a href="/trace">View trace</a><br>
+<a href="/goroutines">Goroutine analysis</a><br>
+<a href="/io">Network blocking profile</a><br>
+<a href="/block">Synchronization blocking profile</a><br>
+<a href="/syscall">Syscall blocking profile</a><br>
+<a href="/sched">Scheduler latency profile</a><br>
+</body>
+</html>
+`)
+
+// startBrowser tries to open the URL in a browser
+// and reports whether it succeeds.
+// Note: copied from x/tools/cmd/cover/html.go
+func startBrowser(url string) bool {
+	// try to start the browser
+	var args []string
+	switch runtime.GOOS {
+	case "darwin":
+		args = []string{"open"}
+	case "windows":
+		args = []string{"cmd", "/c", "start"}
+	default:
+		args = []string{"xdg-open"}
+	}
+	cmd := exec.Command(args[0], append(args[1:], url)...)
+	return cmd.Start() == nil
+}
+
+func dief(msg string, args ...interface{}) {
+	fmt.Fprintf(os.Stderr, msg, args...)
+	os.Exit(1)
+}
diff --git a/src/cmd/trace/pprof.go b/src/cmd/trace/pprof.go
new file mode 100644
index 0000000..154f04d
--- /dev/null
+++ b/src/cmd/trace/pprof.go
@@ -0,0 +1,166 @@
+// 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.
+
+// Serving of pprof-like profiles.
+
+package main
+
+import (
+	"bufio"
+	"fmt"
+	"internal/trace"
+	"io/ioutil"
+	"net/http"
+	"os"
+	"os/exec"
+)
+
+func init() {
+	http.HandleFunc("/io", httpIO)
+	http.HandleFunc("/block", httpBlock)
+	http.HandleFunc("/syscall", httpSyscall)
+	http.HandleFunc("/sched", httpSched)
+}
+
+// Record represents one entry in pprof-like profiles.
+type Record struct {
+	stk  []*trace.Frame
+	n    uint64
+	time int64
+}
+
+// httpIO serves IO pprof-like profile (time spent in IO wait).
+func httpIO(w http.ResponseWriter, r *http.Request) {
+	events, err := parseEvents()
+	if err != nil {
+		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
+	}
+	prof := make(map[uint64]Record)
+	for _, ev := range events {
+		if ev.Type != trace.EvGoBlockNet || ev.Link == nil || ev.StkID == 0 || len(ev.Stk) == 0 {
+			continue
+		}
+		rec := prof[ev.StkID]
+		rec.stk = ev.Stk
+		rec.n++
+		rec.time += ev.Link.Ts - ev.Ts
+		prof[ev.StkID] = rec
+	}
+	serveSVGProfile(w, r, prof)
+}
+
+// httpBlock serves blocking pprof-like profile (time spent blocked on synchronization primitives).
+func httpBlock(w http.ResponseWriter, r *http.Request) {
+	events, err := parseEvents()
+	if err != nil {
+		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
+	}
+	prof := make(map[uint64]Record)
+	for _, ev := range events {
+		switch ev.Type {
+		case trace.EvGoBlockSend, trace.EvGoBlockRecv, trace.EvGoBlockSelect,
+			trace.EvGoBlockSync, trace.EvGoBlockCond:
+		default:
+			continue
+		}
+		if ev.Link == nil || ev.StkID == 0 || len(ev.Stk) == 0 {
+			continue
+		}
+		rec := prof[ev.StkID]
+		rec.stk = ev.Stk
+		rec.n++
+		rec.time += ev.Link.Ts - ev.Ts
+		prof[ev.StkID] = rec
+	}
+	serveSVGProfile(w, r, prof)
+}
+
+// httpSyscall serves syscall pprof-like profile (time spent blocked in syscalls).
+func httpSyscall(w http.ResponseWriter, r *http.Request) {
+	events, err := parseEvents()
+	if err != nil {
+		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
+	}
+	prof := make(map[uint64]Record)
+	for _, ev := range events {
+		if ev.Type != trace.EvGoSysCall || ev.Link == nil || ev.StkID == 0 || len(ev.Stk) == 0 {
+			continue
+		}
+		rec := prof[ev.StkID]
+		rec.stk = ev.Stk
+		rec.n++
+		rec.time += ev.Link.Ts - ev.Ts
+		prof[ev.StkID] = rec
+	}
+	serveSVGProfile(w, r, prof)
+}
+
+// httpSched serves scheduler latency pprof-like profile
+// (time between a goroutine become runnable and actually scheduled for execution).
+func httpSched(w http.ResponseWriter, r *http.Request) {
+	events, err := parseEvents()
+	if err != nil {
+		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
+	}
+	prof := make(map[uint64]Record)
+	for _, ev := range events {
+		if (ev.Type != trace.EvGoUnblock && ev.Type != trace.EvGoCreate) ||
+			ev.Link == nil || ev.StkID == 0 || len(ev.Stk) == 0 {
+			continue
+		}
+		rec := prof[ev.StkID]
+		rec.stk = ev.Stk
+		rec.n++
+		rec.time += ev.Link.Ts - ev.Ts
+		prof[ev.StkID] = rec
+	}
+	serveSVGProfile(w, r, prof)
+}
+
+// generateSVGProfile generates pprof-like profile stored in prof and writes in to w.
+func serveSVGProfile(w http.ResponseWriter, r *http.Request, prof map[uint64]Record) {
+	if len(prof) == 0 {
+		http.Error(w, "The profile is empty", http.StatusNotFound)
+		return
+	}
+	blockf, err := ioutil.TempFile("", "block")
+	if err != nil {
+		http.Error(w, fmt.Sprintf("failed to create temp file: %v", err), http.StatusInternalServerError)
+		return
+	}
+	defer os.Remove(blockf.Name())
+	blockb := bufio.NewWriter(blockf)
+	fmt.Fprintf(blockb, "--- contention:\ncycles/second=1000000000\n")
+	for _, rec := range prof {
+		fmt.Fprintf(blockb, "%v %v @", rec.time, rec.n)
+		for _, f := range rec.stk {
+			fmt.Fprintf(blockb, " 0x%x", f.PC)
+		}
+		fmt.Fprintf(blockb, "\n")
+	}
+	err = blockb.Flush()
+	if err != nil {
+		http.Error(w, fmt.Sprintf("failed to flush temp file: %v", err), http.StatusInternalServerError)
+		return
+	}
+	err = blockf.Close()
+	if err != nil {
+		http.Error(w, fmt.Sprintf("failed to close temp file: %v", err), http.StatusInternalServerError)
+		return
+	}
+
+	svgFilename := blockf.Name() + ".svg"
+	_, err = exec.Command("go", "tool", "pprof", "-svg", "-output", svgFilename, programBinary, blockf.Name()).CombinedOutput()
+	if err != nil {
+		http.Error(w, fmt.Sprintf("failed to execute go tool pprof: %v", err), http.StatusInternalServerError)
+		return
+	}
+	defer os.Remove(svgFilename)
+	w.Header().Set("Content-Type", "image/svg+xml")
+	http.ServeFile(w, r, svgFilename)
+}
diff --git a/src/cmd/trace/trace.go b/src/cmd/trace/trace.go
new file mode 100644
index 0000000..e6eb320
--- /dev/null
+++ b/src/cmd/trace/trace.go
@@ -0,0 +1,445 @@
+// 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 (
+	"encoding/json"
+	"fmt"
+	"internal/trace"
+	"log"
+	"net/http"
+	"path/filepath"
+	"runtime"
+	"strconv"
+	"strings"
+)
+
+func init() {
+	http.HandleFunc("/trace", httpTrace)
+	http.HandleFunc("/jsontrace", httpJsonTrace)
+	http.HandleFunc("/trace_viewer_html", httpTraceViewerHTML)
+}
+
+// httpTrace serves either whole trace (goid==0) or trace for goid goroutine.
+func httpTrace(w http.ResponseWriter, r *http.Request) {
+	_, err := parseEvents()
+	if err != nil {
+		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
+	}
+
+	params := ""
+	if goids := r.FormValue("goid"); goids != "" {
+		goid, err := strconv.ParseUint(goids, 10, 64)
+		if err != nil {
+			http.Error(w, fmt.Sprintf("failed to parse goid parameter '%v': %v", goids, err), http.StatusInternalServerError)
+			return
+		}
+		params = fmt.Sprintf("?goid=%v", goid)
+	}
+	html := strings.Replace(templTrace, "{{PARAMS}}", params, -1)
+	w.Write([]byte(html))
+
+}
+
+var templTrace = `
+<html>
+	<head>
+		<link href="/trace_viewer_html" rel="import">
+		<script>
+			document.addEventListener("DOMContentLoaded", function(event) {
+				var viewer = new tr.TraceViewer('/jsontrace{{PARAMS}}');
+				document.body.appendChild(viewer);
+			});
+		</script>
+	</head>
+	<body>
+	</body>
+</html>
+`
+
+// httpTraceViewerHTML serves static part of trace-viewer.
+// This URL is queried from templTrace HTML.
+func httpTraceViewerHTML(w http.ResponseWriter, r *http.Request) {
+	http.ServeFile(w, r, filepath.Join(runtime.GOROOT(), "misc", "trace", "trace_viewer_lean.html"))
+}
+
+// httpJsonTrace serves json trace, requested from within templTrace HTML.
+func httpJsonTrace(w http.ResponseWriter, r *http.Request) {
+	// This is an AJAX handler, so instead of http.Error we use log.Printf to log errors.
+	events, err := parseEvents()
+	if err != nil {
+		log.Printf("failed to parse trace: %v", err)
+		return
+	}
+
+	params := &traceParams{
+		events:  events,
+		endTime: int64(1<<63 - 1),
+	}
+
+	if goids := r.FormValue("goid"); goids != "" {
+		goid, err := strconv.ParseUint(goids, 10, 64)
+		if err != nil {
+			log.Printf("failed to parse goid parameter '%v': %v", goids, err)
+			return
+		}
+		analyzeGoroutines(events)
+		g := gs[goid]
+		params.gtrace = true
+		params.startTime = g.StartTime
+		params.endTime = g.EndTime
+		params.maing = goid
+		params.gs = trace.RelatedGoroutines(events, goid)
+	}
+
+	err = json.NewEncoder(w).Encode(generateTrace(params))
+	if err != nil {
+		log.Printf("failed to serialize trace: %v", err)
+		return
+	}
+}
+
+type traceParams struct {
+	events    []*trace.Event
+	gtrace    bool
+	startTime int64
+	endTime   int64
+	maing     uint64
+	gs        map[uint64]bool
+}
+
+type traceContext struct {
+	*traceParams
+	data      ViewerData
+	frameTree frameNode
+	frameSeq  int
+	arrowSeq  uint64
+	heapAlloc uint64
+	nextGC    uint64
+	gcount    uint64
+	grunnable uint64
+	grunning  uint64
+	insyscall uint64
+	prunning  uint64
+}
+
+type frameNode struct {
+	id       int
+	children map[uint64]frameNode
+}
+
+type ViewerData struct {
+	Events   []*ViewerEvent         `json:"traceEvents"`
+	Frames   map[string]ViewerFrame `json:"stackFrames"`
+	TimeUnit string                 `json:"displayTimeUnit"`
+}
+
+type ViewerEvent struct {
+	Name     string      `json:"name,omitempty"`
+	Phase    string      `json:"ph"`
+	Scope    string      `json:"s,omitempty"`
+	Time     float64     `json:"ts"`
+	Dur      float64     `json:"dur,omitempty"`
+	Pid      uint64      `json:"pid"`
+	Tid      uint64      `json:"tid"`
+	ID       uint64      `json:"id,omitempty"`
+	Stack    int         `json:"sf,omitempty"`
+	EndStack int         `json:"esf,omitempty"`
+	Arg      interface{} `json:"args,omitempty"`
+}
+
+type ViewerFrame struct {
+	Name   string `json:"name"`
+	Parent int    `json:"parent,omitempty"`
+}
+
+type NameArg struct {
+	Name string `json:"name"`
+}
+
+type SortIndexArg struct {
+	Index int `json:"sort_index"`
+}
+
+// generateTrace generates json trace for trace-viewer:
+// https://github.com/google/trace-viewer
+// Trace format is described at:
+// https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/view
+// If gtrace=true, generate trace for goroutine goid, otherwise whole trace.
+// startTime, endTime determine part of the trace that we are interested in.
+// gset restricts goroutines that are included in the resulting trace.
+func generateTrace(params *traceParams) ViewerData {
+	ctx := &traceContext{traceParams: params}
+	ctx.frameTree.children = make(map[uint64]frameNode)
+	ctx.data.Frames = make(map[string]ViewerFrame)
+	ctx.data.TimeUnit = "ns"
+	maxProc := 0
+	gnames := make(map[uint64]string)
+	for _, ev := range ctx.events {
+		// Handle trace.EvGoStart separately, because we need the goroutine name
+		// even if ignore the event otherwise.
+		if ev.Type == trace.EvGoStart {
+			if _, ok := gnames[ev.G]; !ok {
+				if len(ev.Stk) > 0 {
+					gnames[ev.G] = fmt.Sprintf("G%v %s", ev.G, ev.Stk[0].Fn)
+				} else {
+					gnames[ev.G] = fmt.Sprintf("G%v", ev.G)
+				}
+			}
+		}
+
+		// Ignore events that are from uninteresting goroutines
+		// or outside of the interesting timeframe.
+		if ctx.gs != nil && ev.P < trace.FakeP && !ctx.gs[ev.G] {
+			continue
+		}
+		if ev.Ts < ctx.startTime || ev.Ts > ctx.endTime {
+			continue
+		}
+
+		if ev.P < trace.FakeP && ev.P > maxProc {
+			maxProc = ev.P
+		}
+
+		switch ev.Type {
+		case trace.EvProcStart:
+			if ctx.gtrace {
+				continue
+			}
+			ctx.prunning++
+			ctx.emitThreadCounters(ev)
+			ctx.emitInstant(ev, "proc start")
+		case trace.EvProcStop:
+			if ctx.gtrace {
+				continue
+			}
+			ctx.prunning--
+			ctx.emitThreadCounters(ev)
+			ctx.emitInstant(ev, "proc stop")
+		case trace.EvGCStart:
+			ctx.emitSlice(ev, "GC")
+		case trace.EvGCDone:
+		case trace.EvGCScanStart:
+			if ctx.gtrace {
+				continue
+			}
+			ctx.emitSlice(ev, "MARK")
+		case trace.EvGCScanDone:
+		case trace.EvGCSweepStart:
+			ctx.emitSlice(ev, "SWEEP")
+		case trace.EvGCSweepDone:
+		case trace.EvGoStart:
+			ctx.grunnable--
+			ctx.grunning++
+			ctx.emitGoroutineCounters(ev)
+			ctx.emitSlice(ev, gnames[ev.G])
+		case trace.EvGoCreate:
+			ctx.gcount++
+			ctx.grunnable++
+			ctx.emitGoroutineCounters(ev)
+			ctx.emitArrow(ev, "go")
+		case trace.EvGoEnd:
+			ctx.gcount--
+			ctx.grunning--
+			ctx.emitGoroutineCounters(ev)
+		case trace.EvGoUnblock:
+			ctx.grunnable++
+			ctx.emitGoroutineCounters(ev)
+			ctx.emitArrow(ev, "unblock")
+		case trace.EvGoSysCall:
+			ctx.emitInstant(ev, "syscall")
+		case trace.EvGoSysExit:
+			ctx.grunnable++
+			ctx.emitGoroutineCounters(ev)
+			ctx.insyscall--
+			ctx.emitThreadCounters(ev)
+			ctx.emitArrow(ev, "sysexit")
+		case trace.EvGoSysBlock:
+			ctx.grunning--
+			ctx.emitGoroutineCounters(ev)
+			ctx.insyscall++
+			ctx.emitThreadCounters(ev)
+		case trace.EvGoSched, trace.EvGoPreempt:
+			ctx.grunnable++
+			ctx.grunning--
+			ctx.emitGoroutineCounters(ev)
+		case trace.EvGoStop,
+			trace.EvGoSleep, trace.EvGoBlock, trace.EvGoBlockSend, trace.EvGoBlockRecv,
+			trace.EvGoBlockSelect, trace.EvGoBlockSync, trace.EvGoBlockCond, trace.EvGoBlockNet:
+			ctx.grunning--
+			ctx.emitGoroutineCounters(ev)
+		case trace.EvGoWaiting:
+			ctx.grunnable--
+			ctx.emitGoroutineCounters(ev)
+		case trace.EvGoInSyscall:
+			ctx.insyscall++
+			ctx.emitThreadCounters(ev)
+		case trace.EvHeapAlloc:
+			ctx.heapAlloc = ev.Args[0]
+			ctx.emitHeapCounters(ev)
+		case trace.EvNextGC:
+			ctx.nextGC = ev.Args[0]
+			ctx.emitHeapCounters(ev)
+		}
+	}
+
+	ctx.emit(&ViewerEvent{Name: "process_name", Phase: "M", Pid: 0, Arg: &NameArg{"PROCS"}})
+	ctx.emit(&ViewerEvent{Name: "process_sort_index", Phase: "M", Pid: 0, Arg: &SortIndexArg{1}})
+
+	ctx.emit(&ViewerEvent{Name: "process_name", Phase: "M", Pid: 1, Arg: &NameArg{"STATS"}})
+	ctx.emit(&ViewerEvent{Name: "process_sort_index", Phase: "M", Pid: 1, Arg: &SortIndexArg{0}})
+
+	ctx.emit(&ViewerEvent{Name: "thread_name", Phase: "M", Pid: 0, Tid: trace.NetpollP, Arg: &NameArg{"Network"}})
+	ctx.emit(&ViewerEvent{Name: "thread_sort_index", Phase: "M", Pid: 0, Tid: trace.NetpollP, Arg: &SortIndexArg{-5}})
+
+	ctx.emit(&ViewerEvent{Name: "thread_name", Phase: "M", Pid: 0, Tid: trace.TimerP, Arg: &NameArg{"Timers"}})
+	ctx.emit(&ViewerEvent{Name: "thread_sort_index", Phase: "M", Pid: 0, Tid: trace.TimerP, Arg: &SortIndexArg{-4}})
+
+	ctx.emit(&ViewerEvent{Name: "thread_name", Phase: "M", Pid: 0, Tid: trace.SyscallP, Arg: &NameArg{"Syscalls"}})
+	ctx.emit(&ViewerEvent{Name: "thread_sort_index", Phase: "M", Pid: 0, Tid: trace.SyscallP, Arg: &SortIndexArg{-3}})
+
+	if !ctx.gtrace {
+		for i := 0; i <= maxProc; i++ {
+			ctx.emit(&ViewerEvent{Name: "thread_name", Phase: "M", Pid: 0, Tid: uint64(i), Arg: &NameArg{fmt.Sprintf("Proc %v", i)}})
+			ctx.emit(&ViewerEvent{Name: "thread_sort_index", Phase: "M", Pid: 0, Tid: uint64(i), Arg: &SortIndexArg{i}})
+		}
+	}
+
+	if ctx.gtrace && ctx.gs != nil {
+		for k, v := range gnames {
+			if !ctx.gs[k] {
+				continue
+			}
+			ctx.emit(&ViewerEvent{Name: "thread_name", Phase: "M", Pid: 0, Tid: k, Arg: &NameArg{v}})
+		}
+		ctx.emit(&ViewerEvent{Name: "thread_sort_index", Phase: "M", Pid: 0, Tid: ctx.maing, Arg: &SortIndexArg{-2}})
+		ctx.emit(&ViewerEvent{Name: "thread_sort_index", Phase: "M", Pid: 0, Tid: 0, Arg: &SortIndexArg{-1}})
+	}
+
+	return ctx.data
+}
+
+func (ctx *traceContext) emit(e *ViewerEvent) {
+	ctx.data.Events = append(ctx.data.Events, e)
+}
+
+func (ctx *traceContext) time(ev *trace.Event) float64 {
+	// Trace viewer wants timestamps in microseconds.
+	return float64(ev.Ts-ctx.startTime) / 1000
+}
+
+func (ctx *traceContext) proc(ev *trace.Event) uint64 {
+	if ctx.gtrace && ev.P < trace.FakeP {
+		return ev.G
+	} else {
+		return uint64(ev.P)
+	}
+}
+
+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),
+		EndStack: ctx.stack(ev.Link.Stk),
+	})
+}
+
+func (ctx *traceContext) emitHeapCounters(ev *trace.Event) {
+	type Arg struct {
+		Allocated uint64
+		NextGC    uint64
+	}
+	if ctx.gtrace {
+		return
+	}
+	diff := uint64(0)
+	if ctx.nextGC > ctx.heapAlloc {
+		diff = ctx.nextGC - ctx.heapAlloc
+	}
+	ctx.emit(&ViewerEvent{Name: "Heap", Phase: "C", Time: ctx.time(ev), Pid: 1, Arg: &Arg{ctx.heapAlloc, diff}})
+}
+
+func (ctx *traceContext) emitGoroutineCounters(ev *trace.Event) {
+	type Arg struct {
+		Running  uint64
+		Runnable uint64
+	}
+	if ctx.gtrace {
+		return
+	}
+	ctx.emit(&ViewerEvent{Name: "Goroutines", Phase: "C", Time: ctx.time(ev), Pid: 1, Arg: &Arg{ctx.grunning, ctx.grunnable}})
+}
+
+func (ctx *traceContext) emitThreadCounters(ev *trace.Event) {
+	type Arg struct {
+		Running   uint64
+		InSyscall uint64
+	}
+	if ctx.gtrace {
+		return
+	}
+	ctx.emit(&ViewerEvent{Name: "Threads", Phase: "C", Time: ctx.time(ev), Pid: 1, Arg: &Arg{ctx.prunning, ctx.insyscall}})
+}
+
+func (ctx *traceContext) emitInstant(ev *trace.Event, name string) {
+	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) {
+	if ev.Link == nil {
+		// The other end of the arrow is not captured in the trace.
+		// For example, a goroutine was unblocked but was not scheduled before trace stop.
+		return
+	}
+	if ctx.gtrace && (!ctx.gs[ev.Link.G] || ev.Link.Ts < ctx.startTime || ev.Link.Ts > ctx.endTime) {
+		return
+	}
+
+	if ev.P == trace.NetpollP || ev.P == trace.TimerP || ev.P == trace.SyscallP {
+		// Trace-viewer discards arrows if they don't start/end inside of a slice or instant.
+		// So emit a fake instant at the start of the arrow.
+		ctx.emitInstant(&trace.Event{P: ev.P, Ts: ev.Ts}, "unblock")
+	}
+
+	ctx.arrowSeq++
+	ctx.emit(&ViewerEvent{Name: name, Phase: "s", Tid: ctx.proc(ev), ID: ctx.arrowSeq, Time: ctx.time(ev), Stack: ctx.stack(ev.Stk)})
+	ctx.emit(&ViewerEvent{Name: name, Phase: "t", Tid: ctx.proc(ev.Link), ID: ctx.arrowSeq, Time: ctx.time(ev.Link)})
+}
+
+func (ctx *traceContext) stack(stk []*trace.Frame) int {
+	return ctx.buildBranch(ctx.frameTree, stk)
+}
+
+// buildBranch builds one branch in the prefix tree rooted at ctx.frameTree.
+func (ctx *traceContext) buildBranch(parent frameNode, stk []*trace.Frame) int {
+	if len(stk) == 0 {
+		return parent.id
+	}
+	last := len(stk) - 1
+	frame := stk[last]
+	stk = stk[:last]
+
+	node, ok := parent.children[frame.PC]
+	if !ok {
+		ctx.frameSeq++
+		node.id = ctx.frameSeq
+		node.children = make(map[uint64]frameNode)
+		parent.children[frame.PC] = node
+		ctx.data.Frames[strconv.Itoa(node.id)] = ViewerFrame{fmt.Sprintf("%v:%v", frame.Fn, frame.Line), parent.id}
+	}
+	return ctx.buildBranch(node, stk)
+}
diff --git a/src/cmd/vet/asmdecl.go b/src/cmd/vet/asmdecl.go
new file mode 100644
index 0000000..e4a9871
--- /dev/null
+++ b/src/cmd/vet/asmdecl.go
@@ -0,0 +1,662 @@
+// 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.
+
+// Identify mismatches between assembly files and Go func declarations.
+
+package main
+
+import (
+	"bytes"
+	"fmt"
+	"go/ast"
+	"go/token"
+	"regexp"
+	"strconv"
+	"strings"
+)
+
+// 'kind' is a kind of assembly variable.
+// The kinds 1, 2, 4, 8 stand for values of that size.
+type asmKind int
+
+// These special kinds are not valid sizes.
+const (
+	asmString asmKind = 100 + iota
+	asmSlice
+	asmInterface
+	asmEmptyInterface
+)
+
+// An asmArch describes assembly parameters for an architecture
+type asmArch struct {
+	name      string
+	ptrSize   int
+	intSize   int
+	maxAlign  int
+	bigEndian bool
+	stack     string
+	lr        bool
+}
+
+// An asmFunc describes the expected variables for a function on a given architecture.
+type asmFunc struct {
+	arch        *asmArch
+	size        int // size of all arguments
+	vars        map[string]*asmVar
+	varByOffset map[int]*asmVar
+}
+
+// An asmVar describes a single assembly variable.
+type asmVar struct {
+	name  string
+	kind  asmKind
+	typ   string
+	off   int
+	size  int
+	inner []*asmVar
+}
+
+var (
+	asmArch386      = asmArch{"386", 4, 4, 4, false, "SP", false}
+	asmArchArm      = asmArch{"arm", 4, 4, 4, false, "R13", true}
+	asmArchArm64    = asmArch{"arm64", 8, 8, 8, false, "RSP", true}
+	asmArchAmd64    = asmArch{"amd64", 8, 8, 8, false, "SP", false}
+	asmArchAmd64p32 = asmArch{"amd64p32", 4, 4, 8, false, "SP", false}
+	asmArchPpc64    = asmArch{"ppc64", 8, 8, 8, true, "R1", true}
+	asmArchPpc64LE  = asmArch{"ppc64le", 8, 8, 8, false, "R1", true}
+
+	arches = []*asmArch{
+		&asmArch386,
+		&asmArchArm,
+		&asmArchArm64,
+		&asmArchAmd64,
+		&asmArchAmd64p32,
+		&asmArchPpc64,
+		&asmArchPpc64LE,
+	}
+)
+
+var (
+	re           = regexp.MustCompile
+	asmPlusBuild = re(`//\s+\+build\s+([^\n]+)`)
+	asmTEXT      = re(`\bTEXT\b.*·([^\(]+)\(SB\)(?:\s*,\s*([0-9A-Z|+]+))?(?:\s*,\s*\$(-?[0-9]+)(?:-([0-9]+))?)?`)
+	asmDATA      = re(`\b(DATA|GLOBL)\b`)
+	asmNamedFP   = re(`([a-zA-Z0-9_\xFF-\x{10FFFF}]+)(?:\+([0-9]+))\(FP\)`)
+	asmUnnamedFP = re(`[^+\-0-9](([0-9]+)\(FP\))`)
+	asmSP        = re(`[^+\-0-9](([0-9]+)\(([A-Z0-9]+)\))`)
+	asmOpcode    = re(`^\s*(?:[A-Z0-9a-z_]+:)?\s*([A-Z]+)\s*([^,]*)(?:,\s*(.*))?`)
+	ppc64Suff    = re(`([BHWD])(ZU|Z|U|BR)?$`)
+)
+
+func asmCheck(pkg *Package) {
+	if !vet("asmdecl") {
+		return
+	}
+
+	// No work if no assembly files.
+	if !pkg.hasFileWithSuffix(".s") {
+		return
+	}
+
+	// Gather declarations. knownFunc[name][arch] is func description.
+	knownFunc := make(map[string]map[string]*asmFunc)
+
+	for _, f := range pkg.files {
+		if f.file != nil {
+			for _, decl := range f.file.Decls {
+				if decl, ok := decl.(*ast.FuncDecl); ok && decl.Body == nil {
+					knownFunc[decl.Name.Name] = f.asmParseDecl(decl)
+				}
+			}
+		}
+	}
+
+Files:
+	for _, f := range pkg.files {
+		if !strings.HasSuffix(f.name, ".s") {
+			continue
+		}
+		Println("Checking file", f.name)
+
+		// Determine architecture from file name if possible.
+		var arch string
+		var archDef *asmArch
+		for _, a := range arches {
+			if strings.HasSuffix(f.name, "_"+a.name+".s") {
+				arch = a.name
+				archDef = a
+				break
+			}
+		}
+
+		lines := strings.SplitAfter(string(f.content), "\n")
+		var (
+			fn                 *asmFunc
+			fnName             string
+			localSize, argSize int
+			wroteSP            bool
+			haveRetArg         bool
+			retLine            []int
+		)
+
+		flushRet := func() {
+			if fn != nil && fn.vars["ret"] != nil && !haveRetArg && len(retLine) > 0 {
+				v := fn.vars["ret"]
+				for _, line := range retLine {
+					f.Badf(token.NoPos, "%s:%d: [%s] %s: RET without writing to %d-byte ret+%d(FP)", f.name, line, arch, fnName, v.size, v.off)
+				}
+			}
+			retLine = nil
+		}
+		for lineno, line := range lines {
+			lineno++
+
+			badf := func(format string, args ...interface{}) {
+				f.Badf(token.NoPos, "%s:%d: [%s] %s: %s", f.name, lineno, arch, fnName, fmt.Sprintf(format, args...))
+			}
+
+			if arch == "" {
+				// Determine architecture from +build line if possible.
+				if m := asmPlusBuild.FindStringSubmatch(line); m != nil {
+				Fields:
+					for _, fld := range strings.Fields(m[1]) {
+						for _, a := range arches {
+							if a.name == fld {
+								arch = a.name
+								archDef = a
+								break Fields
+							}
+						}
+					}
+				}
+			}
+
+			if m := asmTEXT.FindStringSubmatch(line); m != nil {
+				flushRet()
+				if arch == "" {
+					f.Warnf(token.NoPos, "%s: cannot determine architecture for assembly file", f.name)
+					continue Files
+				}
+				fnName = m[1]
+				fn = knownFunc[m[1]][arch]
+				if fn != nil {
+					size, _ := strconv.Atoi(m[4])
+					if size != fn.size && (m[2] != "7" && !strings.Contains(m[2], "NOSPLIT") || size != 0) {
+						badf("wrong argument size %d; expected $...-%d", size, fn.size)
+					}
+				}
+				localSize, _ = strconv.Atoi(m[3])
+				localSize += archDef.intSize
+				if archDef.lr {
+					// Account for caller's saved LR
+					localSize += archDef.intSize
+				}
+				argSize, _ = strconv.Atoi(m[4])
+				if fn == nil && !strings.Contains(fnName, "<>") {
+					badf("function %s missing Go declaration", fnName)
+				}
+				wroteSP = false
+				haveRetArg = false
+				continue
+			} else if strings.Contains(line, "TEXT") && strings.Contains(line, "SB") {
+				// function, but not visible from Go (didn't match asmTEXT), so stop checking
+				flushRet()
+				fn = nil
+				fnName = ""
+				continue
+			}
+
+			if strings.Contains(line, "RET") {
+				retLine = append(retLine, lineno)
+			}
+
+			if fnName == "" {
+				continue
+			}
+
+			if asmDATA.FindStringSubmatch(line) != nil {
+				fn = nil
+			}
+
+			if archDef == nil {
+				continue
+			}
+
+			if strings.Contains(line, ", "+archDef.stack) || strings.Contains(line, ",\t"+archDef.stack) {
+				wroteSP = true
+				continue
+			}
+
+			for _, m := range asmSP.FindAllStringSubmatch(line, -1) {
+				if m[3] != archDef.stack || wroteSP {
+					continue
+				}
+				off := 0
+				if m[1] != "" {
+					off, _ = strconv.Atoi(m[2])
+				}
+				if off >= localSize {
+					if fn != nil {
+						v := fn.varByOffset[off-localSize]
+						if v != nil {
+							badf("%s should be %s+%d(FP)", m[1], v.name, off-localSize)
+							continue
+						}
+					}
+					if off >= localSize+argSize {
+						badf("use of %s points beyond argument frame", m[1])
+						continue
+					}
+					badf("use of %s to access argument frame", m[1])
+				}
+			}
+
+			if fn == nil {
+				continue
+			}
+
+			for _, m := range asmUnnamedFP.FindAllStringSubmatch(line, -1) {
+				off, _ := strconv.Atoi(m[2])
+				v := fn.varByOffset[off]
+				if v != nil {
+					badf("use of unnamed argument %s; offset %d is %s+%d(FP)", m[1], off, v.name, v.off)
+				} else {
+					badf("use of unnamed argument %s", m[1])
+				}
+			}
+
+			for _, m := range asmNamedFP.FindAllStringSubmatch(line, -1) {
+				name := m[1]
+				off := 0
+				if m[2] != "" {
+					off, _ = strconv.Atoi(m[2])
+				}
+				if name == "ret" || strings.HasPrefix(name, "ret_") {
+					haveRetArg = true
+				}
+				v := fn.vars[name]
+				if v == nil {
+					// Allow argframe+0(FP).
+					if name == "argframe" && off == 0 {
+						continue
+					}
+					v = fn.varByOffset[off]
+					if v != nil {
+						badf("unknown variable %s; offset %d is %s+%d(FP)", name, off, v.name, v.off)
+					} else {
+						badf("unknown variable %s", name)
+					}
+					continue
+				}
+				asmCheckVar(badf, fn, line, m[0], off, v)
+			}
+		}
+		flushRet()
+	}
+}
+
+// asmParseDecl parses a function decl for expected assembly variables.
+func (f *File) asmParseDecl(decl *ast.FuncDecl) map[string]*asmFunc {
+	var (
+		arch   *asmArch
+		fn     *asmFunc
+		offset int
+		failed bool
+	)
+
+	addVar := func(outer string, v asmVar) {
+		if vo := fn.vars[outer]; vo != nil {
+			vo.inner = append(vo.inner, &v)
+		}
+		fn.vars[v.name] = &v
+		for i := 0; i < v.size; i++ {
+			fn.varByOffset[v.off+i] = &v
+		}
+	}
+
+	addParams := func(list []*ast.Field) {
+		for i, fld := range list {
+			// Determine alignment, size, and kind of type in declaration.
+			var align, size int
+			var kind asmKind
+			names := fld.Names
+			typ := f.gofmt(fld.Type)
+			switch t := fld.Type.(type) {
+			default:
+				switch typ {
+				default:
+					f.Warnf(fld.Type.Pos(), "unknown assembly argument type %s", typ)
+					failed = true
+					return
+				case "int8", "uint8", "byte", "bool":
+					size = 1
+				case "int16", "uint16":
+					size = 2
+				case "int32", "uint32", "float32":
+					size = 4
+				case "int64", "uint64", "float64":
+					align = arch.maxAlign
+					size = 8
+				case "int", "uint":
+					size = arch.intSize
+				case "uintptr", "iword", "Word", "Errno", "unsafe.Pointer":
+					size = arch.ptrSize
+				case "string", "ErrorString":
+					size = arch.ptrSize * 2
+					align = arch.ptrSize
+					kind = asmString
+				}
+			case *ast.ChanType, *ast.FuncType, *ast.MapType, *ast.StarExpr:
+				size = arch.ptrSize
+			case *ast.InterfaceType:
+				align = arch.ptrSize
+				size = 2 * arch.ptrSize
+				if len(t.Methods.List) > 0 {
+					kind = asmInterface
+				} else {
+					kind = asmEmptyInterface
+				}
+			case *ast.ArrayType:
+				if t.Len == nil {
+					size = arch.ptrSize + 2*arch.intSize
+					align = arch.ptrSize
+					kind = asmSlice
+					break
+				}
+				f.Warnf(fld.Type.Pos(), "unsupported assembly argument type %s", typ)
+				failed = true
+			case *ast.StructType:
+				f.Warnf(fld.Type.Pos(), "unsupported assembly argument type %s", typ)
+				failed = true
+			}
+			if align == 0 {
+				align = size
+			}
+			if kind == 0 {
+				kind = asmKind(size)
+			}
+			offset += -offset & (align - 1)
+
+			// Create variable for each name being declared with this type.
+			if len(names) == 0 {
+				name := "unnamed"
+				if decl.Type.Results != nil && len(decl.Type.Results.List) > 0 && &list[0] == &decl.Type.Results.List[0] && i == 0 {
+					// Assume assembly will refer to single unnamed result as r.
+					name = "ret"
+				}
+				names = []*ast.Ident{{Name: name}}
+			}
+			for _, id := range names {
+				name := id.Name
+				addVar("", asmVar{
+					name: name,
+					kind: kind,
+					typ:  typ,
+					off:  offset,
+					size: size,
+				})
+				switch kind {
+				case 8:
+					if arch.ptrSize == 4 {
+						w1, w2 := "lo", "hi"
+						if arch.bigEndian {
+							w1, w2 = w2, w1
+						}
+						addVar(name, asmVar{
+							name: name + "_" + w1,
+							kind: 4,
+							typ:  "half " + typ,
+							off:  offset,
+							size: 4,
+						})
+						addVar(name, asmVar{
+							name: name + "_" + w2,
+							kind: 4,
+							typ:  "half " + typ,
+							off:  offset + 4,
+							size: 4,
+						})
+					}
+
+				case asmEmptyInterface:
+					addVar(name, asmVar{
+						name: name + "_type",
+						kind: asmKind(arch.ptrSize),
+						typ:  "interface type",
+						off:  offset,
+						size: arch.ptrSize,
+					})
+					addVar(name, asmVar{
+						name: name + "_data",
+						kind: asmKind(arch.ptrSize),
+						typ:  "interface data",
+						off:  offset + arch.ptrSize,
+						size: arch.ptrSize,
+					})
+
+				case asmInterface:
+					addVar(name, asmVar{
+						name: name + "_itable",
+						kind: asmKind(arch.ptrSize),
+						typ:  "interface itable",
+						off:  offset,
+						size: arch.ptrSize,
+					})
+					addVar(name, asmVar{
+						name: name + "_data",
+						kind: asmKind(arch.ptrSize),
+						typ:  "interface data",
+						off:  offset + arch.ptrSize,
+						size: arch.ptrSize,
+					})
+
+				case asmSlice:
+					addVar(name, asmVar{
+						name: name + "_base",
+						kind: asmKind(arch.ptrSize),
+						typ:  "slice base",
+						off:  offset,
+						size: arch.ptrSize,
+					})
+					addVar(name, asmVar{
+						name: name + "_len",
+						kind: asmKind(arch.intSize),
+						typ:  "slice len",
+						off:  offset + arch.ptrSize,
+						size: arch.intSize,
+					})
+					addVar(name, asmVar{
+						name: name + "_cap",
+						kind: asmKind(arch.intSize),
+						typ:  "slice cap",
+						off:  offset + arch.ptrSize + arch.intSize,
+						size: arch.intSize,
+					})
+
+				case asmString:
+					addVar(name, asmVar{
+						name: name + "_base",
+						kind: asmKind(arch.ptrSize),
+						typ:  "string base",
+						off:  offset,
+						size: arch.ptrSize,
+					})
+					addVar(name, asmVar{
+						name: name + "_len",
+						kind: asmKind(arch.intSize),
+						typ:  "string len",
+						off:  offset + arch.ptrSize,
+						size: arch.intSize,
+					})
+				}
+				offset += size
+			}
+		}
+	}
+
+	m := make(map[string]*asmFunc)
+	for _, arch = range arches {
+		fn = &asmFunc{
+			arch:        arch,
+			vars:        make(map[string]*asmVar),
+			varByOffset: make(map[int]*asmVar),
+		}
+		offset = 0
+		addParams(decl.Type.Params.List)
+		if decl.Type.Results != nil && len(decl.Type.Results.List) > 0 {
+			offset += -offset & (arch.maxAlign - 1)
+			addParams(decl.Type.Results.List)
+		}
+		fn.size = offset
+		m[arch.name] = fn
+	}
+
+	if failed {
+		return nil
+	}
+	return m
+}
+
+// asmCheckVar checks a single variable reference.
+func asmCheckVar(badf func(string, ...interface{}), fn *asmFunc, line, expr string, off int, v *asmVar) {
+	m := asmOpcode.FindStringSubmatch(line)
+	if m == nil {
+		if !strings.HasPrefix(strings.TrimSpace(line), "//") {
+			badf("cannot find assembly opcode")
+		}
+		return
+	}
+
+	// Determine operand sizes from instruction.
+	// Typically the suffix suffices, but there are exceptions.
+	var src, dst, kind asmKind
+	op := m[1]
+	switch fn.arch.name + "." + op {
+	case "386.FMOVLP":
+		src, dst = 8, 4
+	case "arm.MOVD":
+		src = 8
+	case "arm.MOVW":
+		src = 4
+	case "arm.MOVH", "arm.MOVHU":
+		src = 2
+	case "arm.MOVB", "arm.MOVBU":
+		src = 1
+	// LEA* opcodes don't really read the second arg.
+	// They just take the address of it.
+	case "386.LEAL":
+		dst = 4
+	case "amd64.LEAQ":
+		dst = 8
+	case "amd64p32.LEAL":
+		dst = 4
+	default:
+		switch fn.arch.name {
+		case "386", "amd64":
+			if strings.HasPrefix(op, "F") && (strings.HasSuffix(op, "D") || strings.HasSuffix(op, "DP")) {
+				// FMOVDP, FXCHD, etc
+				src = 8
+				break
+			}
+			if strings.HasPrefix(op, "F") && (strings.HasSuffix(op, "F") || strings.HasSuffix(op, "FP")) {
+				// FMOVFP, FXCHF, etc
+				src = 4
+				break
+			}
+			if strings.HasSuffix(op, "SD") {
+				// MOVSD, SQRTSD, etc
+				src = 8
+				break
+			}
+			if strings.HasSuffix(op, "SS") {
+				// MOVSS, SQRTSS, etc
+				src = 4
+				break
+			}
+			if strings.HasPrefix(op, "SET") {
+				// SETEQ, etc
+				src = 1
+				break
+			}
+			switch op[len(op)-1] {
+			case 'B':
+				src = 1
+			case 'W':
+				src = 2
+			case 'L':
+				src = 4
+			case 'D', 'Q':
+				src = 8
+			}
+		case "ppc64", "ppc64le":
+			// Strip standard suffixes to reveal size letter.
+			m := ppc64Suff.FindStringSubmatch(op)
+			if m != nil {
+				switch m[1][0] {
+				case 'B':
+					src = 1
+				case 'H':
+					src = 2
+				case 'W':
+					src = 4
+				case 'D':
+					src = 8
+				}
+			}
+		}
+	}
+	if dst == 0 {
+		dst = src
+	}
+
+	// Determine whether the match we're holding
+	// is the first or second argument.
+	if strings.Index(line, expr) > strings.Index(line, ",") {
+		kind = dst
+	} else {
+		kind = src
+	}
+
+	vk := v.kind
+	vt := v.typ
+	switch vk {
+	case asmInterface, asmEmptyInterface, asmString, asmSlice:
+		// allow reference to first word (pointer)
+		vk = v.inner[0].kind
+		vt = v.inner[0].typ
+	}
+
+	if off != v.off {
+		var inner bytes.Buffer
+		for i, vi := range v.inner {
+			if len(v.inner) > 1 {
+				fmt.Fprintf(&inner, ",")
+			}
+			fmt.Fprintf(&inner, " ")
+			if i == len(v.inner)-1 {
+				fmt.Fprintf(&inner, "or ")
+			}
+			fmt.Fprintf(&inner, "%s+%d(FP)", vi.name, vi.off)
+		}
+		badf("invalid offset %s; expected %s+%d(FP)%s", expr, v.name, v.off, inner.String())
+		return
+	}
+	if kind != 0 && kind != vk {
+		var inner bytes.Buffer
+		if len(v.inner) > 0 {
+			fmt.Fprintf(&inner, " containing")
+			for i, vi := range v.inner {
+				if i > 0 && len(v.inner) > 2 {
+					fmt.Fprintf(&inner, ",")
+				}
+				fmt.Fprintf(&inner, " ")
+				if i > 0 && i == len(v.inner)-1 {
+					fmt.Fprintf(&inner, "and ")
+				}
+				fmt.Fprintf(&inner, "%s+%d(FP)", vi.name, vi.off)
+			}
+		}
+		badf("invalid %s of %s; %s is %d-byte value%s", op, expr, vt, vk, inner.String())
+	}
+}
diff --git a/src/cmd/vet/assign.go b/src/cmd/vet/assign.go
new file mode 100644
index 0000000..54c1ae1
--- /dev/null
+++ b/src/cmd/vet/assign.go
@@ -0,0 +1,49 @@
+// 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.
+
+/*
+This file contains the code to check for useless assignments.
+*/
+
+package main
+
+import (
+	"go/ast"
+	"go/token"
+	"reflect"
+)
+
+func init() {
+	register("assign",
+		"check for useless assignments",
+		checkAssignStmt,
+		assignStmt)
+}
+
+// TODO: should also check for assignments to struct fields inside methods
+// that are on T instead of *T.
+
+// checkAssignStmt checks for assignments of the form "<expr> = <expr>".
+// These are almost always useless, and even when they aren't they are usually a mistake.
+func checkAssignStmt(f *File, node ast.Node) {
+	stmt := node.(*ast.AssignStmt)
+	if stmt.Tok != token.ASSIGN {
+		return // ignore :=
+	}
+	if len(stmt.Lhs) != len(stmt.Rhs) {
+		// If LHS and RHS have different cardinality, they can't be the same.
+		return
+	}
+	for i, lhs := range stmt.Lhs {
+		rhs := stmt.Rhs[i]
+		if reflect.TypeOf(lhs) != reflect.TypeOf(rhs) {
+			continue // short-circuit the heavy-weight gofmt check
+		}
+		le := f.gofmt(lhs)
+		re := f.gofmt(rhs)
+		if le == re {
+			f.Badf(stmt.Pos(), "self-assignment of %s to %s", re, le)
+		}
+	}
+}
diff --git a/src/cmd/vet/atomic.go b/src/cmd/vet/atomic.go
new file mode 100644
index 0000000..c084f13
--- /dev/null
+++ b/src/cmd/vet/atomic.go
@@ -0,0 +1,66 @@
+// 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 main
+
+import (
+	"go/ast"
+	"go/token"
+)
+
+func init() {
+	register("atomic",
+		"check for common mistaken usages of the sync/atomic package",
+		checkAtomicAssignment,
+		assignStmt)
+}
+
+// checkAtomicAssignment walks the assignment statement checking for common
+// mistaken usage of atomic package, such as: x = atomic.AddUint64(&x, 1)
+func checkAtomicAssignment(f *File, node ast.Node) {
+	n := node.(*ast.AssignStmt)
+	if len(n.Lhs) != len(n.Rhs) {
+		return
+	}
+
+	for i, right := range n.Rhs {
+		call, ok := right.(*ast.CallExpr)
+		if !ok {
+			continue
+		}
+		sel, ok := call.Fun.(*ast.SelectorExpr)
+		if !ok {
+			continue
+		}
+		pkg, ok := sel.X.(*ast.Ident)
+		if !ok || pkg.Name != "atomic" {
+			continue
+		}
+
+		switch sel.Sel.Name {
+		case "AddInt32", "AddInt64", "AddUint32", "AddUint64", "AddUintptr":
+			f.checkAtomicAddAssignment(n.Lhs[i], call)
+		}
+	}
+}
+
+// checkAtomicAddAssignment walks the atomic.Add* method calls checking for assigning the return value
+// to the same variable being used in the operation
+func (f *File) checkAtomicAddAssignment(left ast.Expr, call *ast.CallExpr) {
+	if len(call.Args) != 2 {
+		return
+	}
+	arg := call.Args[0]
+	broken := false
+
+	if uarg, ok := arg.(*ast.UnaryExpr); ok && uarg.Op == token.AND {
+		broken = f.gofmt(left) == f.gofmt(uarg.X)
+	} else if star, ok := left.(*ast.StarExpr); ok {
+		broken = f.gofmt(star.X) == f.gofmt(arg)
+	}
+
+	if broken {
+		f.Bad(left.Pos(), "direct assignment to atomic value")
+	}
+}
diff --git a/src/cmd/vet/bool.go b/src/cmd/vet/bool.go
new file mode 100644
index 0000000..07c2a93
--- /dev/null
+++ b/src/cmd/vet/bool.go
@@ -0,0 +1,186 @@
+// 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.
+
+// This file contains boolean condition tests.
+
+package main
+
+import (
+	"go/ast"
+	"go/token"
+)
+
+func init() {
+	register("bool",
+		"check for mistakes involving boolean operators",
+		checkBool,
+		binaryExpr)
+}
+
+func checkBool(f *File, n ast.Node) {
+	e := n.(*ast.BinaryExpr)
+
+	var op boolOp
+	switch e.Op {
+	case token.LOR:
+		op = or
+	case token.LAND:
+		op = and
+	default:
+		return
+	}
+
+	comm := op.commutativeSets(e)
+	for _, exprs := range comm {
+		op.checkRedundant(f, exprs)
+		op.checkSuspect(f, exprs)
+	}
+}
+
+type boolOp struct {
+	name  string
+	tok   token.Token // token corresponding to this operator
+	badEq token.Token // token corresponding to the equality test that should not be used with this operator
+}
+
+var (
+	or  = boolOp{"or", token.LOR, token.NEQ}
+	and = boolOp{"and", token.LAND, token.EQL}
+)
+
+// commutativeSets returns all side effect free sets of
+// expressions in e that are connected by op.
+// For example, given 'a || b || f() || c || d' with the or op,
+// commutativeSets returns {{b, a}, {d, c}}.
+func (op boolOp) commutativeSets(e *ast.BinaryExpr) [][]ast.Expr {
+	exprs := op.split(e)
+
+	// Partition the slice of expressions into commutative sets.
+	i := 0
+	var sets [][]ast.Expr
+	for j := 0; j <= len(exprs); j++ {
+		if j == len(exprs) || hasSideEffects(exprs[j]) {
+			if i < j {
+				sets = append(sets, exprs[i:j])
+			}
+			i = j + 1
+		}
+	}
+
+	return sets
+}
+
+// checkRedundant checks for expressions of the form
+//   e && e
+//   e || e
+// Exprs must contain only side effect free expressions.
+func (op boolOp) checkRedundant(f *File, exprs []ast.Expr) {
+	seen := make(map[string]bool)
+	for _, e := range exprs {
+		efmt := f.gofmt(e)
+		if seen[efmt] {
+			f.Badf(e.Pos(), "redundant %s: %s %s %s", op.name, efmt, op.tok, efmt)
+		} else {
+			seen[efmt] = true
+		}
+	}
+}
+
+// checkSuspect checks for expressions of the form
+//   x != c1 || x != c2
+//   x == c1 && x == c2
+// where c1 and c2 are constant expressions.
+// If c1 and c2 are the same then it's redundant;
+// if c1 and c2 are different then it's always true or always false.
+// Exprs must contain only side effect free expressions.
+func (op boolOp) checkSuspect(f *File, exprs []ast.Expr) {
+	// seen maps from expressions 'x' to equality expressions 'x != c'.
+	seen := make(map[string]string)
+
+	for _, e := range exprs {
+		bin, ok := e.(*ast.BinaryExpr)
+		if !ok || bin.Op != op.badEq {
+			continue
+		}
+
+		// In order to avoid false positives, restrict to cases
+		// in which one of the operands is constant. We're then
+		// interested in the other operand.
+		// In the rare case in which both operands are constant
+		// (e.g. runtime.GOOS and "windows"), we'll only catch
+		// mistakes if the LHS is repeated, which is how most
+		// code is written.
+		var x ast.Expr
+		switch {
+		case f.pkg.types[bin.Y].Value != nil:
+			x = bin.X
+		case f.pkg.types[bin.X].Value != nil:
+			x = bin.Y
+		default:
+			continue
+		}
+
+		// e is of the form 'x != c' or 'x == c'.
+		xfmt := f.gofmt(x)
+		efmt := f.gofmt(e)
+		if prev, found := seen[xfmt]; found {
+			// checkRedundant handles the case in which efmt == prev.
+			if efmt != prev {
+				f.Badf(e.Pos(), "suspect %s: %s %s %s", op.name, efmt, op.tok, prev)
+			}
+		} else {
+			seen[xfmt] = efmt
+		}
+	}
+}
+
+// hasSideEffects reports whether evaluation of e has side effects.
+func hasSideEffects(e ast.Expr) bool {
+	safe := true
+	ast.Inspect(e, func(node ast.Node) bool {
+		switch n := node.(type) {
+		// Using CallExpr here will catch conversions
+		// as well as function and method invocations.
+		// We'll live with the false negatives for now.
+		case *ast.CallExpr:
+			safe = false
+			return false
+		case *ast.UnaryExpr:
+			if n.Op == token.ARROW {
+				safe = false
+				return false
+			}
+		}
+		return true
+	})
+	return !safe
+}
+
+// split returns a slice of all subexpressions in e that are connected by op.
+// For example, given 'a || (b || c) || d' with the or op,
+// split returns []{d, c, b, a}.
+func (op boolOp) split(e ast.Expr) (exprs []ast.Expr) {
+	for {
+		e = unparen(e)
+		if b, ok := e.(*ast.BinaryExpr); ok && b.Op == op.tok {
+			exprs = append(exprs, op.split(b.Y)...)
+			e = b.X
+		} else {
+			exprs = append(exprs, e)
+			break
+		}
+	}
+	return
+}
+
+// unparen returns e with any enclosing parentheses stripped.
+func unparen(e ast.Expr) ast.Expr {
+	for {
+		p, ok := e.(*ast.ParenExpr)
+		if !ok {
+			return e
+		}
+		e = p.X
+	}
+}
diff --git a/src/cmd/vet/buildtag.go b/src/cmd/vet/buildtag.go
new file mode 100644
index 0000000..2d86edf
--- /dev/null
+++ b/src/cmd/vet/buildtag.go
@@ -0,0 +1,91 @@
+// 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 main
+
+import (
+	"bytes"
+	"fmt"
+	"os"
+	"strings"
+	"unicode"
+)
+
+var (
+	nl         = []byte("\n")
+	slashSlash = []byte("//")
+	plusBuild  = []byte("+build")
+)
+
+// checkBuildTag checks that build tags are in the correct location and well-formed.
+func checkBuildTag(name string, data []byte) {
+	if !vet("buildtags") {
+		return
+	}
+	lines := bytes.SplitAfter(data, nl)
+
+	// Determine cutpoint where +build comments are no longer valid.
+	// They are valid in leading // comments in the file followed by
+	// a blank line.
+	var cutoff int
+	for i, line := range lines {
+		line = bytes.TrimSpace(line)
+		if len(line) == 0 {
+			cutoff = i
+			continue
+		}
+		if bytes.HasPrefix(line, slashSlash) {
+			continue
+		}
+		break
+	}
+
+	for i, line := range lines {
+		line = bytes.TrimSpace(line)
+		if !bytes.HasPrefix(line, slashSlash) {
+			continue
+		}
+		text := bytes.TrimSpace(line[2:])
+		if bytes.HasPrefix(text, plusBuild) {
+			fields := bytes.Fields(text)
+			if !bytes.Equal(fields[0], plusBuild) {
+				// Comment is something like +buildasdf not +build.
+				fmt.Fprintf(os.Stderr, "%s:%d: possible malformed +build comment\n", name, i+1)
+				continue
+			}
+			if i >= cutoff {
+				fmt.Fprintf(os.Stderr, "%s:%d: +build comment must appear before package clause and be followed by a blank line\n", name, i+1)
+				setExit(1)
+				continue
+			}
+			// Check arguments.
+		Args:
+			for _, arg := range fields[1:] {
+				for _, elem := range strings.Split(string(arg), ",") {
+					if strings.HasPrefix(elem, "!!") {
+						fmt.Fprintf(os.Stderr, "%s:%d: invalid double negative in build constraint: %s\n", name, i+1, arg)
+						setExit(1)
+						break Args
+					}
+					if strings.HasPrefix(elem, "!") {
+						elem = elem[1:]
+					}
+					for _, c := range elem {
+						if !unicode.IsLetter(c) && !unicode.IsDigit(c) && c != '_' && c != '.' {
+							fmt.Fprintf(os.Stderr, "%s:%d: invalid non-alphanumeric build constraint: %s\n", name, i+1, arg)
+							setExit(1)
+							break Args
+						}
+					}
+				}
+			}
+			continue
+		}
+		// Comment with +build but not at beginning.
+		if bytes.Contains(line, plusBuild) && i < cutoff {
+			fmt.Fprintf(os.Stderr, "%s:%d: possible malformed +build comment\n", name, i+1)
+			continue
+		}
+	}
+}
diff --git a/src/cmd/vet/composite.go b/src/cmd/vet/composite.go
new file mode 100644
index 0000000..80b45e2
--- /dev/null
+++ b/src/cmd/vet/composite.go
@@ -0,0 +1,124 @@
+// 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.
+
+// This file contains the test for unkeyed struct literals.
+
+package main
+
+import (
+	"cmd/vet/whitelist"
+	"flag"
+	"go/ast"
+	"strings"
+)
+
+var compositeWhiteList = flag.Bool("compositewhitelist", true, "use composite white list; for testing only")
+
+func init() {
+	register("composites",
+		"check that composite literals used field-keyed elements",
+		checkUnkeyedLiteral,
+		compositeLit)
+}
+
+// checkUnkeyedLiteral checks if a composite literal is a struct literal with
+// unkeyed fields.
+func checkUnkeyedLiteral(f *File, node ast.Node) {
+	c := node.(*ast.CompositeLit)
+	typ := c.Type
+	for {
+		if typ1, ok := c.Type.(*ast.ParenExpr); ok {
+			typ = typ1
+			continue
+		}
+		break
+	}
+
+	switch typ.(type) {
+	case *ast.ArrayType:
+		return
+	case *ast.MapType:
+		return
+	case *ast.StructType:
+		return // a literal struct type does not need to use keys
+	case *ast.Ident:
+		// A simple type name like t or T does not need keys either,
+		// since it is almost certainly declared in the current package.
+		// (The exception is names being used via import . "pkg", but
+		// those are already breaking the Go 1 compatibility promise,
+		// so not reporting potential additional breakage seems okay.)
+		return
+	}
+
+	// Otherwise the type is a selector like pkg.Name.
+	// We only care if pkg.Name is a struct, not if it's a map, array, or slice.
+	isStruct, typeString := f.pkg.isStruct(c)
+	if !isStruct {
+		return
+	}
+
+	if typeString == "" { // isStruct doesn't know
+		typeString = f.gofmt(typ)
+	}
+
+	// It's a struct, or we can't tell it's not a struct because we don't have types.
+
+	// Check if the CompositeLit contains an unkeyed field.
+	allKeyValue := true
+	for _, e := range c.Elts {
+		if _, ok := e.(*ast.KeyValueExpr); !ok {
+			allKeyValue = false
+			break
+		}
+	}
+	if allKeyValue {
+		return
+	}
+
+	// Check that the CompositeLit's type has the form pkg.Typ.
+	s, ok := c.Type.(*ast.SelectorExpr)
+	if !ok {
+		return
+	}
+	pkg, ok := s.X.(*ast.Ident)
+	if !ok {
+		return
+	}
+
+	// Convert the package name to an import path, and compare to a whitelist.
+	path := pkgPath(f, pkg.Name)
+	if path == "" {
+		f.Badf(c.Pos(), "unresolvable package for %s.%s literal", pkg.Name, s.Sel.Name)
+		return
+	}
+	typeName := path + "." + s.Sel.Name
+	if *compositeWhiteList && whitelist.UnkeyedLiteral[typeName] {
+		return
+	}
+
+	f.Bad(c.Pos(), typeString+" composite literal uses unkeyed fields")
+}
+
+// pkgPath returns the import path "image/png" for the package name "png".
+//
+// This is based purely on syntax and convention, and not on the imported
+// package's contents. It will be incorrect if a package name differs from the
+// leaf element of the import path, or if the package was a dot import.
+func pkgPath(f *File, pkgName string) (path string) {
+	for _, x := range f.file.Imports {
+		s := strings.Trim(x.Path.Value, `"`)
+		if x.Name != nil {
+			// Catch `import pkgName "foo/bar"`.
+			if x.Name.Name == pkgName {
+				return s
+			}
+		} else {
+			// Catch `import "pkgName"` or `import "foo/bar/pkgName"`.
+			if s == pkgName || strings.HasSuffix(s, "/"+pkgName) {
+				return s
+			}
+		}
+	}
+	return ""
+}
diff --git a/src/cmd/vet/copylock.go b/src/cmd/vet/copylock.go
new file mode 100644
index 0000000..6c71061
--- /dev/null
+++ b/src/cmd/vet/copylock.go
@@ -0,0 +1,156 @@
+// 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.
+
+// This file contains the code to check that locks are not passed by value.
+
+package main
+
+import (
+	"bytes"
+	"fmt"
+	"go/ast"
+	"go/token"
+	"go/types"
+)
+
+func init() {
+	register("copylocks",
+		"check that locks are not passed by value",
+		checkCopyLocks,
+		funcDecl, rangeStmt, funcLit)
+}
+
+// checkCopyLocks checks whether node might
+// inadvertently copy a lock.
+func checkCopyLocks(f *File, node ast.Node) {
+	switch node := node.(type) {
+	case *ast.RangeStmt:
+		checkCopyLocksRange(f, node)
+	case *ast.FuncDecl:
+		checkCopyLocksFunc(f, node.Name.Name, node.Recv, node.Type)
+	case *ast.FuncLit:
+		checkCopyLocksFunc(f, "func", nil, node.Type)
+	}
+}
+
+// checkCopyLocksFunc checks whether a function might
+// inadvertently copy a lock, by checking whether
+// its receiver, parameters, or return values
+// are locks.
+func checkCopyLocksFunc(f *File, name string, recv *ast.FieldList, typ *ast.FuncType) {
+	if recv != nil && len(recv.List) > 0 {
+		expr := recv.List[0].Type
+		if path := lockPath(f.pkg.typesPkg, f.pkg.types[expr].Type); path != nil {
+			f.Badf(expr.Pos(), "%s passes Lock by value: %v", name, path)
+		}
+	}
+
+	if typ.Params != nil {
+		for _, field := range typ.Params.List {
+			expr := field.Type
+			if path := lockPath(f.pkg.typesPkg, f.pkg.types[expr].Type); path != nil {
+				f.Badf(expr.Pos(), "%s passes Lock by value: %v", name, path)
+			}
+		}
+	}
+
+	if typ.Results != nil {
+		for _, field := range typ.Results.List {
+			expr := field.Type
+			if path := lockPath(f.pkg.typesPkg, f.pkg.types[expr].Type); path != nil {
+				f.Badf(expr.Pos(), "%s returns Lock by value: %v", name, path)
+			}
+		}
+	}
+}
+
+// checkCopyLocksRange checks whether a range statement
+// might inadvertently copy a lock by checking whether
+// any of the range variables are locks.
+func checkCopyLocksRange(f *File, r *ast.RangeStmt) {
+	checkCopyLocksRangeVar(f, r.Tok, r.Key)
+	checkCopyLocksRangeVar(f, r.Tok, r.Value)
+}
+
+func checkCopyLocksRangeVar(f *File, rtok token.Token, e ast.Expr) {
+	if e == nil {
+		return
+	}
+	id, isId := e.(*ast.Ident)
+	if isId && id.Name == "_" {
+		return
+	}
+
+	var typ types.Type
+	if rtok == token.DEFINE {
+		if !isId {
+			return
+		}
+		obj := f.pkg.defs[id]
+		if obj == nil {
+			return
+		}
+		typ = obj.Type()
+	} else {
+		typ = f.pkg.types[e].Type
+	}
+
+	if typ == nil {
+		return
+	}
+	if path := lockPath(f.pkg.typesPkg, typ); path != nil {
+		f.Badf(e.Pos(), "range var %s copies Lock: %v", f.gofmt(e), path)
+	}
+}
+
+type typePath []types.Type
+
+// String pretty-prints a typePath.
+func (path typePath) String() string {
+	n := len(path)
+	var buf bytes.Buffer
+	for i := range path {
+		if i > 0 {
+			fmt.Fprint(&buf, " contains ")
+		}
+		// The human-readable path is in reverse order, outermost to innermost.
+		fmt.Fprint(&buf, path[n-i-1].String())
+	}
+	return buf.String()
+}
+
+// lockPath returns a typePath describing the location of a lock value
+// contained in typ. If there is no contained lock, it returns nil.
+func lockPath(tpkg *types.Package, typ types.Type) typePath {
+	if typ == nil {
+		return nil
+	}
+
+	// We're only interested in the case in which the underlying
+	// type is a struct. (Interfaces and pointers are safe to copy.)
+	styp, ok := typ.Underlying().(*types.Struct)
+	if !ok {
+		return nil
+	}
+
+	// We're looking for cases in which a reference to this type
+	// can be locked, but a value cannot. This differentiates
+	// embedded interfaces from embedded values.
+	if plock := types.NewMethodSet(types.NewPointer(typ)).Lookup(tpkg, "Lock"); plock != nil {
+		if lock := types.NewMethodSet(typ).Lookup(tpkg, "Lock"); lock == nil {
+			return []types.Type{typ}
+		}
+	}
+
+	nfields := styp.NumFields()
+	for i := 0; i < nfields; i++ {
+		ftyp := styp.Field(i).Type()
+		subpath := lockPath(tpkg, ftyp)
+		if subpath != nil {
+			return append(subpath, typ)
+		}
+	}
+
+	return nil
+}
diff --git a/src/cmd/vet/deadcode.go b/src/cmd/vet/deadcode.go
new file mode 100644
index 0000000..3b306c2
--- /dev/null
+++ b/src/cmd/vet/deadcode.go
@@ -0,0 +1,296 @@
+// 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.
+
+// Check for syntactically unreachable code.
+
+package main
+
+import (
+	"go/ast"
+	"go/token"
+)
+
+func init() {
+	register("unreachable",
+		"check for unreachable code",
+		checkUnreachable,
+		funcDecl, funcLit)
+}
+
+type deadState struct {
+	f           *File
+	hasBreak    map[ast.Stmt]bool
+	hasGoto     map[string]bool
+	labels      map[string]ast.Stmt
+	breakTarget ast.Stmt
+
+	reachable bool
+}
+
+// checkUnreachable checks a function body for dead code.
+func checkUnreachable(f *File, node ast.Node) {
+	var body *ast.BlockStmt
+	switch n := node.(type) {
+	case *ast.FuncDecl:
+		body = n.Body
+	case *ast.FuncLit:
+		body = n.Body
+	}
+	if body == nil {
+		return
+	}
+
+	d := &deadState{
+		f:        f,
+		hasBreak: make(map[ast.Stmt]bool),
+		hasGoto:  make(map[string]bool),
+		labels:   make(map[string]ast.Stmt),
+	}
+
+	d.findLabels(body)
+
+	d.reachable = true
+	d.findDead(body)
+}
+
+// findLabels gathers information about the labels defined and used by stmt
+// and about which statements break, whether a label is involved or not.
+func (d *deadState) findLabels(stmt ast.Stmt) {
+	switch x := stmt.(type) {
+	default:
+		d.f.Warnf(x.Pos(), "internal error in findLabels: unexpected statement %T", x)
+
+	case *ast.AssignStmt,
+		*ast.BadStmt,
+		*ast.DeclStmt,
+		*ast.DeferStmt,
+		*ast.EmptyStmt,
+		*ast.ExprStmt,
+		*ast.GoStmt,
+		*ast.IncDecStmt,
+		*ast.ReturnStmt,
+		*ast.SendStmt:
+		// no statements inside
+
+	case *ast.BlockStmt:
+		for _, stmt := range x.List {
+			d.findLabels(stmt)
+		}
+
+	case *ast.BranchStmt:
+		switch x.Tok {
+		case token.GOTO:
+			if x.Label != nil {
+				d.hasGoto[x.Label.Name] = true
+			}
+
+		case token.BREAK:
+			stmt := d.breakTarget
+			if x.Label != nil {
+				stmt = d.labels[x.Label.Name]
+			}
+			if stmt != nil {
+				d.hasBreak[stmt] = true
+			}
+		}
+
+	case *ast.IfStmt:
+		d.findLabels(x.Body)
+		if x.Else != nil {
+			d.findLabels(x.Else)
+		}
+
+	case *ast.LabeledStmt:
+		d.labels[x.Label.Name] = x.Stmt
+		d.findLabels(x.Stmt)
+
+	// These cases are all the same, but the x.Body only works
+	// when the specific type of x is known, so the cases cannot
+	// be merged.
+	case *ast.ForStmt:
+		outer := d.breakTarget
+		d.breakTarget = x
+		d.findLabels(x.Body)
+		d.breakTarget = outer
+
+	case *ast.RangeStmt:
+		outer := d.breakTarget
+		d.breakTarget = x
+		d.findLabels(x.Body)
+		d.breakTarget = outer
+
+	case *ast.SelectStmt:
+		outer := d.breakTarget
+		d.breakTarget = x
+		d.findLabels(x.Body)
+		d.breakTarget = outer
+
+	case *ast.SwitchStmt:
+		outer := d.breakTarget
+		d.breakTarget = x
+		d.findLabels(x.Body)
+		d.breakTarget = outer
+
+	case *ast.TypeSwitchStmt:
+		outer := d.breakTarget
+		d.breakTarget = x
+		d.findLabels(x.Body)
+		d.breakTarget = outer
+
+	case *ast.CommClause:
+		for _, stmt := range x.Body {
+			d.findLabels(stmt)
+		}
+
+	case *ast.CaseClause:
+		for _, stmt := range x.Body {
+			d.findLabels(stmt)
+		}
+	}
+}
+
+// findDead walks the statement looking for dead code.
+// If d.reachable is false on entry, stmt itself is dead.
+// When findDead returns, d.reachable tells whether the
+// statement following stmt is reachable.
+func (d *deadState) findDead(stmt ast.Stmt) {
+	// Is this a labeled goto target?
+	// If so, assume it is reachable due to the goto.
+	// This is slightly conservative, in that we don't
+	// check that the goto is reachable, so
+	//	L: goto L
+	// will not provoke a warning.
+	// But it's good enough.
+	if x, isLabel := stmt.(*ast.LabeledStmt); isLabel && d.hasGoto[x.Label.Name] {
+		d.reachable = true
+	}
+
+	if !d.reachable {
+		switch stmt.(type) {
+		case *ast.EmptyStmt:
+			// do not warn about unreachable empty statements
+		default:
+			d.f.Bad(stmt.Pos(), "unreachable code")
+			d.reachable = true // silence error about next statement
+		}
+	}
+
+	switch x := stmt.(type) {
+	default:
+		d.f.Warnf(x.Pos(), "internal error in findDead: unexpected statement %T", x)
+
+	case *ast.AssignStmt,
+		*ast.BadStmt,
+		*ast.DeclStmt,
+		*ast.DeferStmt,
+		*ast.EmptyStmt,
+		*ast.GoStmt,
+		*ast.IncDecStmt,
+		*ast.SendStmt:
+		// no control flow
+
+	case *ast.BlockStmt:
+		for _, stmt := range x.List {
+			d.findDead(stmt)
+		}
+
+	case *ast.BranchStmt:
+		switch x.Tok {
+		case token.BREAK, token.GOTO, token.FALLTHROUGH:
+			d.reachable = false
+		case token.CONTINUE:
+			// NOTE: We accept "continue" statements as terminating.
+			// They are not necessary in the spec definition of terminating,
+			// because a continue statement cannot be the final statement
+			// before a return. But for the more general problem of syntactically
+			// identifying dead code, continue redirects control flow just
+			// like the other terminating statements.
+			d.reachable = false
+		}
+
+	case *ast.ExprStmt:
+		// Call to panic?
+		call, ok := x.X.(*ast.CallExpr)
+		if ok {
+			name, ok := call.Fun.(*ast.Ident)
+			if ok && name.Name == "panic" && name.Obj == nil {
+				d.reachable = false
+			}
+		}
+
+	case *ast.ForStmt:
+		d.findDead(x.Body)
+		d.reachable = x.Cond != nil || d.hasBreak[x]
+
+	case *ast.IfStmt:
+		d.findDead(x.Body)
+		if x.Else != nil {
+			r := d.reachable
+			d.reachable = true
+			d.findDead(x.Else)
+			d.reachable = d.reachable || r
+		} else {
+			// might not have executed if statement
+			d.reachable = true
+		}
+
+	case *ast.LabeledStmt:
+		d.findDead(x.Stmt)
+
+	case *ast.RangeStmt:
+		d.findDead(x.Body)
+		d.reachable = true
+
+	case *ast.ReturnStmt:
+		d.reachable = false
+
+	case *ast.SelectStmt:
+		// NOTE: Unlike switch and type switch below, we don't care
+		// whether a select has a default, because a select without a
+		// default blocks until one of the cases can run. That's different
+		// from a switch without a default, which behaves like it has
+		// a default with an empty body.
+		anyReachable := false
+		for _, comm := range x.Body.List {
+			d.reachable = true
+			for _, stmt := range comm.(*ast.CommClause).Body {
+				d.findDead(stmt)
+			}
+			anyReachable = anyReachable || d.reachable
+		}
+		d.reachable = anyReachable || d.hasBreak[x]
+
+	case *ast.SwitchStmt:
+		anyReachable := false
+		hasDefault := false
+		for _, cas := range x.Body.List {
+			cc := cas.(*ast.CaseClause)
+			if cc.List == nil {
+				hasDefault = true
+			}
+			d.reachable = true
+			for _, stmt := range cc.Body {
+				d.findDead(stmt)
+			}
+			anyReachable = anyReachable || d.reachable
+		}
+		d.reachable = anyReachable || d.hasBreak[x] || !hasDefault
+
+	case *ast.TypeSwitchStmt:
+		anyReachable := false
+		hasDefault := false
+		for _, cas := range x.Body.List {
+			cc := cas.(*ast.CaseClause)
+			if cc.List == nil {
+				hasDefault = true
+			}
+			d.reachable = true
+			for _, stmt := range cc.Body {
+				d.findDead(stmt)
+			}
+			anyReachable = anyReachable || d.reachable
+		}
+		d.reachable = anyReachable || d.hasBreak[x] || !hasDefault
+	}
+}
diff --git a/src/cmd/vet/doc.go b/src/cmd/vet/doc.go
new file mode 100644
index 0000000..ea4654a
--- /dev/null
+++ b/src/cmd/vet/doc.go
@@ -0,0 +1,191 @@
+// Copyright 2010 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.
+
+/*
+
+Vet examines Go source code and reports suspicious constructs, such as Printf
+calls whose arguments do not align with the format string. Vet uses heuristics
+that do not guarantee all reports are genuine problems, but it can find errors
+not caught by the compilers.
+
+It can be invoked three ways:
+
+By package, from the go tool:
+	go vet package/path/name
+vets the package whose path is provided.
+
+By files:
+	go tool vet source/directory/*.go
+vets the files named, all of which must be in the same package.
+
+By directory:
+	go tool vet source/directory
+recursively descends the directory, vetting each package it finds.
+
+Vet's exit code is 2 for erroneous invocation of the tool, 1 if a
+problem was reported, and 0 otherwise. Note that the tool does not
+check every possible problem and depends on unreliable heuristics
+so it should be used as guidance only, not as a firm indicator of
+program correctness.
+
+By default all checks are performed. If any flags are explicitly set
+to true, only those tests are run. Conversely, if any flag is
+explicitly set to false, only those tests are disabled.
+Thus -printf=true runs the printf check, -printf=false runs all checks
+except the printf check.
+
+Available checks:
+
+Printf family
+
+Flag: -printf
+
+Suspicious calls to functions in the Printf family, including any functions
+with these names, disregarding case:
+	Print Printf Println
+	Fprint Fprintf Fprintln
+	Sprint Sprintf Sprintln
+	Error Errorf
+	Fatal Fatalf
+	Log Logf
+	Panic Panicf Panicln
+The -printfuncs flag can be used to redefine this list.
+If the function name ends with an 'f', the function is assumed to take
+a format descriptor string in the manner of fmt.Printf. If not, vet
+complains about arguments that look like format descriptor strings.
+
+It also checks for errors such as using a Writer as the first argument of
+Printf.
+
+Methods
+
+Flag: -methods
+
+Non-standard signatures for methods with familiar names, including:
+	Format GobEncode GobDecode MarshalJSON MarshalXML
+	Peek ReadByte ReadFrom ReadRune Scan Seek
+	UnmarshalJSON UnreadByte UnreadRune WriteByte
+	WriteTo
+
+Struct tags
+
+Flag: -structtags
+
+Struct tags that do not follow the format understood by reflect.StructTag.Get.
+Well-known encoding struct tags (json, xml) used with unexported fields.
+
+Unkeyed composite literals
+
+Flag: -composites
+
+Composite struct literals that do not use the field-keyed syntax.
+
+Assembly declarations
+
+Flag: -asmdecl
+
+Mismatches between assembly files and Go function declarations.
+
+Useless assignments
+
+Flag: -assign
+
+Check for useless assignments.
+
+Atomic mistakes
+
+Flag: -atomic
+
+Common mistaken usages of the sync/atomic package.
+
+Boolean conditions
+
+Flag: -bool
+
+Mistakes involving boolean operators.
+
+Build tags
+
+Flag: -buildtags
+
+Badly formed or misplaced +build tags.
+
+Copying locks
+
+Flag: -copylocks
+
+Locks that are erroneously passed by value.
+
+Nil function comparison
+
+Flag: -nilfunc
+
+Comparisons between functions and nil.
+
+Range loop variables
+
+Flag: -rangeloops
+
+Incorrect uses of range loop variables in closures.
+
+Unreachable code
+
+Flag: -unreachable
+
+Unreachable code.
+
+Shadowed variables
+
+Flag: -shadow=false (experimental; must be set explicitly)
+
+Variables that may have been unintentionally shadowed.
+
+Misuse of unsafe Pointers
+
+Flag: -unsafeptr
+
+Likely incorrect uses of unsafe.Pointer to convert integers to pointers.
+A conversion from uintptr to unsafe.Pointer is invalid if it implies that
+there is a uintptr-typed word in memory that holds a pointer value,
+because that word will be invisible to stack copying and to the garbage
+collector.
+
+Unused result of certain function calls
+
+Flag: -unusedresult
+
+Calls to well-known functions and methods that return a value that is
+discarded.  By default, this includes functions like fmt.Errorf and
+fmt.Sprintf and methods like String and Error. The flags -unusedfuncs
+and -unusedstringmethods control the set.
+
+Shifts
+
+Flag: -shift
+
+Shifts equal to or longer than the variable's length.
+
+Other flags
+
+These flags configure the behavior of vet:
+
+	-all (default true)
+		Check everything; disabled if any explicit check is requested.
+	-v
+		Verbose mode
+	-printfuncs
+		A comma-separated list of print-like functions to supplement the
+		standard list.  Each entry is in the form Name:N where N is the
+		zero-based argument position of the first argument involved in the
+		print: either the format or the first print argument for non-formatted
+		prints.  For example, if you have Warn and Warnf functions that
+		take an io.Writer as their first argument, like Fprintf,
+			-printfuncs=Warn:1,Warnf:1
+		For more information, see the discussion of the -printf flag.
+	-shadowstrict
+		Whether to be strict about shadowing; can be noisy.
+	-test
+		For testing only: sets -all and -shadow.
+*/
+package main // import "golang.org/x/tools/cmd/vet"
diff --git a/src/cmd/vet/main.go b/src/cmd/vet/main.go
new file mode 100644
index 0000000..453cfe0
--- /dev/null
+++ b/src/cmd/vet/main.go
@@ -0,0 +1,486 @@
+// Copyright 2010 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.
+
+// Vet is a simple checker for static errors in Go source code.
+// See doc.go for more information.
+package main
+
+import (
+	"bytes"
+	"flag"
+	"fmt"
+	"go/ast"
+	"go/build"
+	"go/parser"
+	"go/printer"
+	"go/token"
+	"go/types"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"strconv"
+	"strings"
+)
+
+var (
+	verbose  = flag.Bool("v", false, "verbose")
+	testFlag = flag.Bool("test", false, "for testing only: sets -all and -shadow")
+	tags     = flag.String("tags", "", "comma-separated list of build tags to apply when parsing")
+	tagList  = []string{} // exploded version of tags flag; set in main
+)
+
+var exitCode = 0
+
+// "all" is here only for the appearance of backwards compatibility.
+// It has no effect; the triState flags do the work.
+var all = flag.Bool("all", true, "check everything; disabled if any explicit check is requested")
+
+// Flags to control which individual checks to perform.
+var report = map[string]*triState{
+	// Only unusual checks are written here.
+	// Most checks that operate during the AST walk are added by register.
+	"asmdecl":   triStateFlag("asmdecl", unset, "check assembly against Go declarations"),
+	"buildtags": triStateFlag("buildtags", unset, "check that +build tags are valid"),
+}
+
+// experimental records the flags enabling experimental features. These must be
+// requested explicitly; they are not enabled by -all.
+var experimental = map[string]bool{}
+
+// setTrueCount record how many flags are explicitly set to true.
+var setTrueCount int
+
+// A triState is a boolean that knows whether it has been set to either true or false.
+// It is used to identify if a flag appears; the standard boolean flag cannot
+// distinguish missing from unset. It also satisfies flag.Value.
+type triState int
+
+const (
+	unset triState = iota
+	setTrue
+	setFalse
+)
+
+func triStateFlag(name string, value triState, usage string) *triState {
+	flag.Var(&value, name, usage)
+	return &value
+}
+
+// triState implements flag.Value, flag.Getter, and flag.boolFlag.
+// They work like boolean flags: we can say vet -printf as well as vet -printf=true
+func (ts *triState) Get() interface{} {
+	return *ts == setTrue
+}
+
+func (ts triState) isTrue() bool {
+	return ts == setTrue
+}
+
+func (ts *triState) Set(value string) error {
+	b, err := strconv.ParseBool(value)
+	if err != nil {
+		return err
+	}
+	if b {
+		*ts = setTrue
+		setTrueCount++
+	} else {
+		*ts = setFalse
+	}
+	return nil
+}
+
+func (ts *triState) String() string {
+	switch *ts {
+	case unset:
+		return "unset"
+	case setTrue:
+		return "true"
+	case setFalse:
+		return "false"
+	}
+	panic("not reached")
+}
+
+func (ts triState) IsBoolFlag() bool {
+	return true
+}
+
+// vet tells whether to report errors for the named check, a flag name.
+func vet(name string) bool {
+	if *testFlag {
+		return true
+	}
+	return report[name].isTrue()
+}
+
+// setExit sets the value for os.Exit when it is called, later.  It
+// remembers the highest value.
+func setExit(err int) {
+	if err > exitCode {
+		exitCode = err
+	}
+}
+
+var (
+	// Each of these vars has a corresponding case in (*File).Visit.
+	assignStmt    *ast.AssignStmt
+	binaryExpr    *ast.BinaryExpr
+	callExpr      *ast.CallExpr
+	compositeLit  *ast.CompositeLit
+	exprStmt      *ast.ExprStmt
+	field         *ast.Field
+	funcDecl      *ast.FuncDecl
+	funcLit       *ast.FuncLit
+	genDecl       *ast.GenDecl
+	interfaceType *ast.InterfaceType
+	rangeStmt     *ast.RangeStmt
+
+	// checkers is a two-level map.
+	// The outer level is keyed by a nil pointer, one of the AST vars above.
+	// The inner level is keyed by checker name.
+	checkers = make(map[ast.Node]map[string]func(*File, ast.Node))
+)
+
+func register(name, usage string, fn func(*File, ast.Node), types ...ast.Node) {
+	report[name] = triStateFlag(name, unset, usage)
+	for _, typ := range types {
+		m := checkers[typ]
+		if m == nil {
+			m = make(map[string]func(*File, ast.Node))
+			checkers[typ] = m
+		}
+		m[name] = fn
+	}
+}
+
+// Usage is a replacement usage function for the flags package.
+func Usage() {
+	fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
+	fmt.Fprintf(os.Stderr, "\tvet [flags] directory...\n")
+	fmt.Fprintf(os.Stderr, "\tvet [flags] files... # Must be a single package\n")
+	fmt.Fprintf(os.Stderr, "For more information run\n")
+	fmt.Fprintf(os.Stderr, "\tgodoc golang.org/x/tools/cmd/vet\n\n")
+	fmt.Fprintf(os.Stderr, "Flags:\n")
+	flag.PrintDefaults()
+	os.Exit(2)
+}
+
+// File is a wrapper for the state of a file used in the parser.
+// The parse tree walkers are all methods of this type.
+type File struct {
+	pkg     *Package
+	fset    *token.FileSet
+	name    string
+	content []byte
+	file    *ast.File
+	b       bytes.Buffer // for use by methods
+
+	// The objects that are receivers of a "String() string" method.
+	// This is used by the recursiveStringer method in print.go.
+	stringers map[*ast.Object]bool
+
+	// Registered checkers to run.
+	checkers map[ast.Node][]func(*File, ast.Node)
+}
+
+func main() {
+	flag.Usage = Usage
+	flag.Parse()
+
+	// If any flag is set, we run only those checks requested.
+	// If no flags are set true, set all the non-experimental ones not explicitly set (in effect, set the "-all" flag).
+	if setTrueCount == 0 {
+		for name, setting := range report {
+			if *setting == unset && !experimental[name] {
+				*setting = setTrue
+			}
+		}
+	}
+
+	tagList = strings.Split(*tags, ",")
+
+	initPrintFlags()
+	initUnusedFlags()
+
+	if flag.NArg() == 0 {
+		Usage()
+	}
+	dirs := false
+	files := false
+	for _, name := range flag.Args() {
+		// Is it a directory?
+		fi, err := os.Stat(name)
+		if err != nil {
+			warnf("error walking tree: %s", err)
+			continue
+		}
+		if fi.IsDir() {
+			dirs = true
+		} else {
+			files = true
+		}
+	}
+	if dirs && files {
+		Usage()
+	}
+	if dirs {
+		for _, name := range flag.Args() {
+			walkDir(name)
+		}
+		os.Exit(exitCode)
+	}
+	if !doPackage(".", flag.Args()) {
+		warnf("no files checked")
+	}
+	os.Exit(exitCode)
+}
+
+// prefixDirectory places the directory name on the beginning of each name in the list.
+func prefixDirectory(directory string, names []string) {
+	if directory != "." {
+		for i, name := range names {
+			names[i] = filepath.Join(directory, name)
+		}
+	}
+}
+
+// doPackageDir analyzes the single package found in the directory, if there is one,
+// plus a test package, if there is one.
+func doPackageDir(directory string) {
+	context := build.Default
+	if len(context.BuildTags) != 0 {
+		warnf("build tags %s previously set", context.BuildTags)
+	}
+	context.BuildTags = append(tagList, context.BuildTags...)
+
+	pkg, err := context.ImportDir(directory, 0)
+	if err != nil {
+		// If it's just that there are no go source files, that's fine.
+		if _, nogo := err.(*build.NoGoError); nogo {
+			return
+		}
+		// Non-fatal: we are doing a recursive walk and there may be other directories.
+		warnf("cannot process directory %s: %s", directory, err)
+		return
+	}
+	var names []string
+	names = append(names, pkg.GoFiles...)
+	names = append(names, pkg.CgoFiles...)
+	names = append(names, pkg.TestGoFiles...) // These are also in the "foo" package.
+	names = append(names, pkg.SFiles...)
+	prefixDirectory(directory, names)
+	doPackage(directory, names)
+	// Is there also a "foo_test" package? If so, do that one as well.
+	if len(pkg.XTestGoFiles) > 0 {
+		names = pkg.XTestGoFiles
+		prefixDirectory(directory, names)
+		doPackage(directory, names)
+	}
+}
+
+type Package struct {
+	path      string
+	defs      map[*ast.Ident]types.Object
+	uses      map[*ast.Ident]types.Object
+	selectors map[*ast.SelectorExpr]*types.Selection
+	types     map[ast.Expr]types.TypeAndValue
+	spans     map[types.Object]Span
+	files     []*File
+	typesPkg  *types.Package
+}
+
+// doPackage analyzes the single package constructed from the named files.
+// It returns whether any files were checked.
+func doPackage(directory string, names []string) bool {
+	var files []*File
+	var astFiles []*ast.File
+	fs := token.NewFileSet()
+	for _, name := range names {
+		data, err := ioutil.ReadFile(name)
+		if err != nil {
+			// Warn but continue to next package.
+			warnf("%s: %s", name, err)
+			return false
+		}
+		checkBuildTag(name, data)
+		var parsedFile *ast.File
+		if strings.HasSuffix(name, ".go") {
+			parsedFile, err = parser.ParseFile(fs, name, data, 0)
+			if err != nil {
+				warnf("%s: %s", name, err)
+				return false
+			}
+			astFiles = append(astFiles, parsedFile)
+		}
+		files = append(files, &File{fset: fs, content: data, name: name, file: parsedFile})
+	}
+	if len(astFiles) == 0 {
+		return false
+	}
+	pkg := new(Package)
+	pkg.path = astFiles[0].Name.Name
+	pkg.files = files
+	// Type check the package.
+	err := pkg.check(fs, astFiles)
+	if err != nil && *verbose {
+		warnf("%s", err)
+	}
+
+	// Check.
+	chk := make(map[ast.Node][]func(*File, ast.Node))
+	for typ, set := range checkers {
+		for name, fn := range set {
+			if vet(name) {
+				chk[typ] = append(chk[typ], fn)
+			}
+		}
+	}
+	for _, file := range files {
+		file.pkg = pkg
+		file.checkers = chk
+		if file.file != nil {
+			file.walkFile(file.name, file.file)
+		}
+	}
+	asmCheck(pkg)
+	return true
+}
+
+func visit(path string, f os.FileInfo, err error) error {
+	if err != nil {
+		warnf("walk error: %s", err)
+		return err
+	}
+	// One package per directory. Ignore the files themselves.
+	if !f.IsDir() {
+		return nil
+	}
+	doPackageDir(path)
+	return nil
+}
+
+func (pkg *Package) hasFileWithSuffix(suffix string) bool {
+	for _, f := range pkg.files {
+		if strings.HasSuffix(f.name, suffix) {
+			return true
+		}
+	}
+	return false
+}
+
+// walkDir recursively walks the tree looking for Go packages.
+func walkDir(root string) {
+	filepath.Walk(root, visit)
+}
+
+// errorf formats the error to standard error, adding program
+// identification and a newline, and exits.
+func errorf(format string, args ...interface{}) {
+	fmt.Fprintf(os.Stderr, "vet: "+format+"\n", args...)
+	os.Exit(2)
+}
+
+// warnf formats the error to standard error, adding program
+// identification and a newline, but does not exit.
+func warnf(format string, args ...interface{}) {
+	fmt.Fprintf(os.Stderr, "vet: "+format+"\n", args...)
+	setExit(1)
+}
+
+// Println is fmt.Println guarded by -v.
+func Println(args ...interface{}) {
+	if !*verbose {
+		return
+	}
+	fmt.Println(args...)
+}
+
+// Printf is fmt.Printf guarded by -v.
+func Printf(format string, args ...interface{}) {
+	if !*verbose {
+		return
+	}
+	fmt.Printf(format+"\n", args...)
+}
+
+// Bad reports an error and sets the exit code..
+func (f *File) Bad(pos token.Pos, args ...interface{}) {
+	f.Warn(pos, args...)
+	setExit(1)
+}
+
+// Badf reports a formatted error and sets the exit code.
+func (f *File) Badf(pos token.Pos, format string, args ...interface{}) {
+	f.Warnf(pos, format, args...)
+	setExit(1)
+}
+
+// loc returns a formatted representation of the position.
+func (f *File) loc(pos token.Pos) string {
+	if pos == token.NoPos {
+		return ""
+	}
+	// Do not print columns. Because the pos often points to the start of an
+	// expression instead of the inner part with the actual error, the
+	// precision can mislead.
+	posn := f.fset.Position(pos)
+	return fmt.Sprintf("%s:%d: ", posn.Filename, posn.Line)
+}
+
+// Warn reports an error but does not set the exit code.
+func (f *File) Warn(pos token.Pos, args ...interface{}) {
+	fmt.Fprint(os.Stderr, f.loc(pos)+fmt.Sprintln(args...))
+}
+
+// Warnf reports a formatted error but does not set the exit code.
+func (f *File) Warnf(pos token.Pos, format string, args ...interface{}) {
+	fmt.Fprintf(os.Stderr, f.loc(pos)+format+"\n", args...)
+}
+
+// walkFile walks the file's tree.
+func (f *File) walkFile(name string, file *ast.File) {
+	Println("Checking file", name)
+	ast.Walk(f, file)
+}
+
+// Visit implements the ast.Visitor interface.
+func (f *File) Visit(node ast.Node) ast.Visitor {
+	var key ast.Node
+	switch node.(type) {
+	case *ast.AssignStmt:
+		key = assignStmt
+	case *ast.BinaryExpr:
+		key = binaryExpr
+	case *ast.CallExpr:
+		key = callExpr
+	case *ast.CompositeLit:
+		key = compositeLit
+	case *ast.ExprStmt:
+		key = exprStmt
+	case *ast.Field:
+		key = field
+	case *ast.FuncDecl:
+		key = funcDecl
+	case *ast.FuncLit:
+		key = funcLit
+	case *ast.GenDecl:
+		key = genDecl
+	case *ast.InterfaceType:
+		key = interfaceType
+	case *ast.RangeStmt:
+		key = rangeStmt
+	}
+	for _, fn := range f.checkers[key] {
+		fn(f, node)
+	}
+	return f
+}
+
+// gofmt returns a string representation of the expression.
+func (f *File) gofmt(x ast.Expr) string {
+	f.b.Reset()
+	printer.Fprint(&f.b, f.fset, x)
+	return f.b.String()
+}
diff --git a/src/cmd/vet/method.go b/src/cmd/vet/method.go
new file mode 100644
index 0000000..00949df
--- /dev/null
+++ b/src/cmd/vet/method.go
@@ -0,0 +1,182 @@
+// Copyright 2010 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 contains the code to check canonical methods.
+
+package main
+
+import (
+	"fmt"
+	"go/ast"
+	"go/printer"
+	"strings"
+)
+
+func init() {
+	register("methods",
+		"check that canonically named methods are canonically defined",
+		checkCanonicalMethod,
+		funcDecl, interfaceType)
+}
+
+type MethodSig struct {
+	args    []string
+	results []string
+}
+
+// canonicalMethods lists the input and output types for Go methods
+// that are checked using dynamic interface checks.  Because the
+// checks are dynamic, such methods would not cause a compile error
+// if they have the wrong signature: instead the dynamic check would
+// fail, sometimes mysteriously.  If a method is found with a name listed
+// here but not the input/output types listed here, vet complains.
+//
+// A few of the canonical methods have very common names.
+// For example, a type might implement a Scan method that
+// has nothing to do with fmt.Scanner, but we still want to check
+// the methods that are intended to implement fmt.Scanner.
+// To do that, the arguments that have a = prefix are treated as
+// signals that the canonical meaning is intended: if a Scan
+// method doesn't have a fmt.ScanState as its first argument,
+// we let it go.  But if it does have a fmt.ScanState, then the
+// rest has to match.
+var canonicalMethods = map[string]MethodSig{
+	// "Flush": {{}, {"error"}}, // http.Flusher and jpeg.writer conflict
+	"Format":        {[]string{"=fmt.State", "rune"}, []string{}},                      // fmt.Formatter
+	"GobDecode":     {[]string{"[]byte"}, []string{"error"}},                           // gob.GobDecoder
+	"GobEncode":     {[]string{}, []string{"[]byte", "error"}},                         // gob.GobEncoder
+	"MarshalJSON":   {[]string{}, []string{"[]byte", "error"}},                         // json.Marshaler
+	"MarshalXML":    {[]string{"*xml.Encoder", "xml.StartElement"}, []string{"error"}}, // xml.Marshaler
+	"Peek":          {[]string{"=int"}, []string{"[]byte", "error"}},                   // image.reader (matching bufio.Reader)
+	"ReadByte":      {[]string{}, []string{"byte", "error"}},                           // io.ByteReader
+	"ReadFrom":      {[]string{"=io.Reader"}, []string{"int64", "error"}},              // io.ReaderFrom
+	"ReadRune":      {[]string{}, []string{"rune", "int", "error"}},                    // io.RuneReader
+	"Scan":          {[]string{"=fmt.ScanState", "rune"}, []string{"error"}},           // fmt.Scanner
+	"Seek":          {[]string{"=int64", "int"}, []string{"int64", "error"}},           // io.Seeker
+	"UnmarshalJSON": {[]string{"[]byte"}, []string{"error"}},                           // json.Unmarshaler
+	"UnmarshalXML":  {[]string{"*xml.Decoder", "xml.StartElement"}, []string{"error"}}, // xml.Unmarshaler
+	"UnreadByte":    {[]string{}, []string{"error"}},
+	"UnreadRune":    {[]string{}, []string{"error"}},
+	"WriteByte":     {[]string{"byte"}, []string{"error"}},                // jpeg.writer (matching bufio.Writer)
+	"WriteTo":       {[]string{"=io.Writer"}, []string{"int64", "error"}}, // io.WriterTo
+}
+
+func checkCanonicalMethod(f *File, node ast.Node) {
+	switch n := node.(type) {
+	case *ast.FuncDecl:
+		if n.Recv != nil {
+			canonicalMethod(f, n.Name, n.Type)
+		}
+	case *ast.InterfaceType:
+		for _, field := range n.Methods.List {
+			for _, id := range field.Names {
+				canonicalMethod(f, id, field.Type.(*ast.FuncType))
+			}
+		}
+	}
+}
+
+func canonicalMethod(f *File, id *ast.Ident, t *ast.FuncType) {
+	// Expected input/output.
+	expect, ok := canonicalMethods[id.Name]
+	if !ok {
+		return
+	}
+
+	// Actual input/output
+	args := typeFlatten(t.Params.List)
+	var results []ast.Expr
+	if t.Results != nil {
+		results = typeFlatten(t.Results.List)
+	}
+
+	// Do the =s (if any) all match?
+	if !f.matchParams(expect.args, args, "=") || !f.matchParams(expect.results, results, "=") {
+		return
+	}
+
+	// Everything must match.
+	if !f.matchParams(expect.args, args, "") || !f.matchParams(expect.results, results, "") {
+		expectFmt := id.Name + "(" + argjoin(expect.args) + ")"
+		if len(expect.results) == 1 {
+			expectFmt += " " + argjoin(expect.results)
+		} else if len(expect.results) > 1 {
+			expectFmt += " (" + argjoin(expect.results) + ")"
+		}
+
+		f.b.Reset()
+		if err := printer.Fprint(&f.b, f.fset, t); err != nil {
+			fmt.Fprintf(&f.b, "<%s>", err)
+		}
+		actual := f.b.String()
+		actual = strings.TrimPrefix(actual, "func")
+		actual = id.Name + actual
+
+		f.Badf(id.Pos(), "method %s should have signature %s", actual, expectFmt)
+	}
+}
+
+func argjoin(x []string) string {
+	y := make([]string, len(x))
+	for i, s := range x {
+		if s[0] == '=' {
+			s = s[1:]
+		}
+		y[i] = s
+	}
+	return strings.Join(y, ", ")
+}
+
+// Turn parameter list into slice of types
+// (in the ast, types are Exprs).
+// Have to handle f(int, bool) and f(x, y, z int)
+// so not a simple 1-to-1 conversion.
+func typeFlatten(l []*ast.Field) []ast.Expr {
+	var t []ast.Expr
+	for _, f := range l {
+		if len(f.Names) == 0 {
+			t = append(t, f.Type)
+			continue
+		}
+		for _ = range f.Names {
+			t = append(t, f.Type)
+		}
+	}
+	return t
+}
+
+// Does each type in expect with the given prefix match the corresponding type in actual?
+func (f *File) matchParams(expect []string, actual []ast.Expr, prefix string) bool {
+	for i, x := range expect {
+		if !strings.HasPrefix(x, prefix) {
+			continue
+		}
+		if i >= len(actual) {
+			return false
+		}
+		if !f.matchParamType(x, actual[i]) {
+			return false
+		}
+	}
+	if prefix == "" && len(actual) > len(expect) {
+		return false
+	}
+	return true
+}
+
+// Does this one type match?
+func (f *File) matchParamType(expect string, actual ast.Expr) bool {
+	if strings.HasPrefix(expect, "=") {
+		expect = expect[1:]
+	}
+	// Strip package name if we're in that package.
+	if n := len(f.file.Name.Name); len(expect) > n && expect[:n] == f.file.Name.Name && expect[n] == '.' {
+		expect = expect[n+1:]
+	}
+
+	// Overkill but easy.
+	f.b.Reset()
+	printer.Fprint(&f.b, f.fset, actual)
+	return f.b.String() == expect
+}
diff --git a/src/cmd/vet/nilfunc.go b/src/cmd/vet/nilfunc.go
new file mode 100644
index 0000000..bfe05e3
--- /dev/null
+++ b/src/cmd/vet/nilfunc.go
@@ -0,0 +1,67 @@
+// 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.
+
+/*
+This file contains the code to check for useless function comparisons.
+A useless comparison is one like f == nil as opposed to f() == nil.
+*/
+
+package main
+
+import (
+	"go/ast"
+	"go/token"
+	"go/types"
+)
+
+func init() {
+	register("nilfunc",
+		"check for comparisons between functions and nil",
+		checkNilFuncComparison,
+		binaryExpr)
+}
+
+func checkNilFuncComparison(f *File, node ast.Node) {
+	e := node.(*ast.BinaryExpr)
+
+	// Only want == or != comparisons.
+	if e.Op != token.EQL && e.Op != token.NEQ {
+		return
+	}
+
+	// Only want comparisons with a nil identifier on one side.
+	var e2 ast.Expr
+	switch {
+	case f.isNil(e.X):
+		e2 = e.Y
+	case f.isNil(e.Y):
+		e2 = e.X
+	default:
+		return
+	}
+
+	// Only want identifiers or selector expressions.
+	var obj types.Object
+	switch v := e2.(type) {
+	case *ast.Ident:
+		obj = f.pkg.uses[v]
+	case *ast.SelectorExpr:
+		obj = f.pkg.uses[v.Sel]
+	default:
+		return
+	}
+
+	// Only want functions.
+	if _, ok := obj.(*types.Func); !ok {
+		return
+	}
+
+	f.Badf(e.Pos(), "comparison of function %v %v nil is always %v", obj.Name(), e.Op, e.Op == token.NEQ)
+}
+
+// isNil reports whether the provided expression is the built-in nil
+// identifier.
+func (f *File) isNil(e ast.Expr) bool {
+	return f.pkg.types[e].Type == types.Typ[types.UntypedNil]
+}
diff --git a/src/cmd/vet/print.go b/src/cmd/vet/print.go
new file mode 100644
index 0000000..d79b096
--- /dev/null
+++ b/src/cmd/vet/print.go
@@ -0,0 +1,586 @@
+// Copyright 2010 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 contains the printf-checker.
+
+package main
+
+import (
+	"bytes"
+	"flag"
+	"go/ast"
+	"go/constant"
+	"go/token"
+	"go/types"
+	"strconv"
+	"strings"
+	"unicode/utf8"
+)
+
+var printfuncs = flag.String("printfuncs", "", "comma-separated list of print function names to check")
+
+func init() {
+	register("printf",
+		"check printf-like invocations",
+		checkFmtPrintfCall,
+		funcDecl, callExpr)
+}
+
+func initPrintFlags() {
+	if *printfuncs == "" {
+		return
+	}
+	for _, name := range strings.Split(*printfuncs, ",") {
+		if len(name) == 0 {
+			flag.Usage()
+		}
+		skip := 0
+		if colon := strings.LastIndex(name, ":"); colon > 0 {
+			var err error
+			skip, err = strconv.Atoi(name[colon+1:])
+			if err != nil {
+				errorf(`illegal format for "Func:N" argument %q; %s`, name, err)
+			}
+			name = name[:colon]
+		}
+		name = strings.ToLower(name)
+		if name[len(name)-1] == 'f' {
+			printfList[name] = skip
+		} else {
+			printList[name] = skip
+		}
+	}
+}
+
+// printfList records the formatted-print functions. The value is the location
+// of the format parameter. Names are lower-cased so the lookup is
+// case insensitive.
+var printfList = map[string]int{
+	"errorf":  0,
+	"fatalf":  0,
+	"fprintf": 1,
+	"logf":    0,
+	"panicf":  0,
+	"printf":  0,
+	"sprintf": 0,
+}
+
+// printList records the unformatted-print functions. The value is the location
+// of the first parameter to be printed.  Names are lower-cased so the lookup is
+// case insensitive.
+var printList = map[string]int{
+	"error":  0,
+	"fatal":  0,
+	"fprint": 1, "fprintln": 1,
+	"log":   0,
+	"panic": 0, "panicln": 0,
+	"print": 0, "println": 0,
+	"sprint": 0, "sprintln": 0,
+}
+
+// checkCall triggers the print-specific checks if the call invokes a print function.
+func checkFmtPrintfCall(f *File, node ast.Node) {
+	if d, ok := node.(*ast.FuncDecl); ok && isStringer(f, d) {
+		// Remember we saw this.
+		if f.stringers == nil {
+			f.stringers = make(map[*ast.Object]bool)
+		}
+		if l := d.Recv.List; len(l) == 1 {
+			if n := l[0].Names; len(n) == 1 {
+				f.stringers[n[0].Obj] = true
+			}
+		}
+		return
+	}
+
+	call, ok := node.(*ast.CallExpr)
+	if !ok {
+		return
+	}
+	var Name string
+	switch x := call.Fun.(type) {
+	case *ast.Ident:
+		Name = x.Name
+	case *ast.SelectorExpr:
+		Name = x.Sel.Name
+	default:
+		return
+	}
+
+	name := strings.ToLower(Name)
+	if skip, ok := printfList[name]; ok {
+		f.checkPrintf(call, Name, skip)
+		return
+	}
+	if skip, ok := printList[name]; ok {
+		f.checkPrint(call, Name, skip)
+		return
+	}
+}
+
+// isStringer returns true if the provided declaration is a "String() string"
+// method, an implementation of fmt.Stringer.
+func isStringer(f *File, d *ast.FuncDecl) bool {
+	return d.Recv != nil && d.Name.Name == "String" && d.Type.Results != nil &&
+		len(d.Type.Params.List) == 0 && len(d.Type.Results.List) == 1 &&
+		f.pkg.types[d.Type.Results.List[0].Type].Type == types.Typ[types.String]
+}
+
+// formatState holds the parsed representation of a printf directive such as "%3.*[4]d".
+// It is constructed by parsePrintfVerb.
+type formatState struct {
+	verb     rune   // the format verb: 'd' for "%d"
+	format   string // the full format directive from % through verb, "%.3d".
+	name     string // Printf, Sprintf etc.
+	flags    []byte // the list of # + etc.
+	argNums  []int  // the successive argument numbers that are consumed, adjusted to refer to actual arg in call
+	indexed  bool   // whether an indexing expression appears: %[1]d.
+	firstArg int    // Index of first argument after the format in the Printf call.
+	// Used only during parse.
+	file         *File
+	call         *ast.CallExpr
+	argNum       int  // Which argument we're expecting to format now.
+	indexPending bool // Whether we have an indexed argument that has not resolved.
+	nbytes       int  // number of bytes of the format string consumed.
+}
+
+// checkPrintf checks a call to a formatted print routine such as Printf.
+// call.Args[formatIndex] is (well, should be) the format argument.
+func (f *File) checkPrintf(call *ast.CallExpr, name string, formatIndex int) {
+	if formatIndex >= len(call.Args) {
+		f.Bad(call.Pos(), "too few arguments in call to", name)
+		return
+	}
+	lit := f.pkg.types[call.Args[formatIndex]].Value
+	if lit == nil {
+		if *verbose {
+			f.Warn(call.Pos(), "can't check non-constant format in call to", name)
+		}
+		return
+	}
+	if lit.Kind() != constant.String {
+		f.Badf(call.Pos(), "constant %v not a string in call to %s", lit, name)
+		return
+	}
+	format := constant.StringVal(lit)
+	firstArg := formatIndex + 1 // Arguments are immediately after format string.
+	if !strings.Contains(format, "%") {
+		if len(call.Args) > firstArg {
+			f.Badf(call.Pos(), "no formatting directive in %s call", name)
+		}
+		return
+	}
+	// Hard part: check formats against args.
+	argNum := firstArg
+	indexed := false
+	for i, w := 0, 0; i < len(format); i += w {
+		w = 1
+		if format[i] == '%' {
+			state := f.parsePrintfVerb(call, name, format[i:], firstArg, argNum)
+			if state == nil {
+				return
+			}
+			w = len(state.format)
+			if state.indexed {
+				indexed = true
+			}
+			if !f.okPrintfArg(call, state) { // One error per format is enough.
+				return
+			}
+			if len(state.argNums) > 0 {
+				// Continue with the next sequential argument.
+				argNum = state.argNums[len(state.argNums)-1] + 1
+			}
+		}
+	}
+	// Dotdotdot is hard.
+	if call.Ellipsis.IsValid() && argNum >= len(call.Args)-1 {
+		return
+	}
+	// If the arguments were direct indexed, we assume the programmer knows what's up.
+	// Otherwise, there should be no leftover arguments.
+	if !indexed && argNum != len(call.Args) {
+		expect := argNum - firstArg
+		numArgs := len(call.Args) - firstArg
+		f.Badf(call.Pos(), "wrong number of args for format in %s call: %d needed but %d args", name, expect, numArgs)
+	}
+}
+
+// parseFlags accepts any printf flags.
+func (s *formatState) parseFlags() {
+	for s.nbytes < len(s.format) {
+		switch c := s.format[s.nbytes]; c {
+		case '#', '0', '+', '-', ' ':
+			s.flags = append(s.flags, c)
+			s.nbytes++
+		default:
+			return
+		}
+	}
+}
+
+// scanNum advances through a decimal number if present.
+func (s *formatState) scanNum() {
+	for ; s.nbytes < len(s.format); s.nbytes++ {
+		c := s.format[s.nbytes]
+		if c < '0' || '9' < c {
+			return
+		}
+	}
+}
+
+// parseIndex scans an index expression. It returns false if there is a syntax error.
+func (s *formatState) parseIndex() bool {
+	if s.nbytes == len(s.format) || s.format[s.nbytes] != '[' {
+		return true
+	}
+	// Argument index present.
+	s.indexed = true
+	s.nbytes++ // skip '['
+	start := s.nbytes
+	s.scanNum()
+	if s.nbytes == len(s.format) || s.nbytes == start || s.format[s.nbytes] != ']' {
+		s.file.Badf(s.call.Pos(), "illegal syntax for printf argument index")
+		return false
+	}
+	arg32, err := strconv.ParseInt(s.format[start:s.nbytes], 10, 32)
+	if err != nil {
+		s.file.Badf(s.call.Pos(), "illegal syntax for printf argument index: %s", err)
+		return false
+	}
+	s.nbytes++ // skip ']'
+	arg := int(arg32)
+	arg += s.firstArg - 1 // We want to zero-index the actual arguments.
+	s.argNum = arg
+	s.indexPending = true
+	return true
+}
+
+// parseNum scans a width or precision (or *). It returns false if there's a bad index expression.
+func (s *formatState) parseNum() bool {
+	if s.nbytes < len(s.format) && s.format[s.nbytes] == '*' {
+		if s.indexPending { // Absorb it.
+			s.indexPending = false
+		}
+		s.nbytes++
+		s.argNums = append(s.argNums, s.argNum)
+		s.argNum++
+	} else {
+		s.scanNum()
+	}
+	return true
+}
+
+// parsePrecision scans for a precision. It returns false if there's a bad index expression.
+func (s *formatState) parsePrecision() bool {
+	// If there's a period, there may be a precision.
+	if s.nbytes < len(s.format) && s.format[s.nbytes] == '.' {
+		s.flags = append(s.flags, '.') // Treat precision as a flag.
+		s.nbytes++
+		if !s.parseIndex() {
+			return false
+		}
+		if !s.parseNum() {
+			return false
+		}
+	}
+	return true
+}
+
+// parsePrintfVerb looks the formatting directive that begins the format string
+// and returns a formatState that encodes what the directive wants, without looking
+// at the actual arguments present in the call. The result is nil if there is an error.
+func (f *File) parsePrintfVerb(call *ast.CallExpr, name, format string, firstArg, argNum int) *formatState {
+	state := &formatState{
+		format:   format,
+		name:     name,
+		flags:    make([]byte, 0, 5),
+		argNum:   argNum,
+		argNums:  make([]int, 0, 1),
+		nbytes:   1, // There's guaranteed to be a percent sign.
+		indexed:  false,
+		firstArg: firstArg,
+		file:     f,
+		call:     call,
+	}
+	// There may be flags.
+	state.parseFlags()
+	indexPending := false
+	// There may be an index.
+	if !state.parseIndex() {
+		return nil
+	}
+	// There may be a width.
+	if !state.parseNum() {
+		return nil
+	}
+	// There may be a precision.
+	if !state.parsePrecision() {
+		return nil
+	}
+	// Now a verb, possibly prefixed by an index (which we may already have).
+	if !indexPending && !state.parseIndex() {
+		return nil
+	}
+	if state.nbytes == len(state.format) {
+		f.Badf(call.Pos(), "missing verb at end of format string in %s call", name)
+		return nil
+	}
+	verb, w := utf8.DecodeRuneInString(state.format[state.nbytes:])
+	state.verb = verb
+	state.nbytes += w
+	if verb != '%' {
+		state.argNums = append(state.argNums, state.argNum)
+	}
+	state.format = state.format[:state.nbytes]
+	return state
+}
+
+// printfArgType encodes the types of expressions a printf verb accepts. It is a bitmask.
+type printfArgType int
+
+const (
+	argBool printfArgType = 1 << iota
+	argInt
+	argRune
+	argString
+	argFloat
+	argComplex
+	argPointer
+	anyType printfArgType = ^0
+)
+
+type printVerb struct {
+	verb  rune   // User may provide verb through Formatter; could be a rune.
+	flags string // known flags are all ASCII
+	typ   printfArgType
+}
+
+// Common flag sets for printf verbs.
+const (
+	noFlag       = ""
+	numFlag      = " -+.0"
+	sharpNumFlag = " -+.0#"
+	allFlags     = " -+.0#"
+)
+
+// printVerbs identifies which flags are known to printf for each verb.
+// TODO: A type that implements Formatter may do what it wants, and vet
+// will complain incorrectly.
+var printVerbs = []printVerb{
+	// '-' is a width modifier, always valid.
+	// '.' is a precision for float, max width for strings.
+	// '+' is required sign for numbers, Go format for %v.
+	// '#' is alternate format for several verbs.
+	// ' ' is spacer for numbers
+	{'%', noFlag, 0},
+	{'b', numFlag, argInt | argFloat | argComplex},
+	{'c', "-", argRune | argInt},
+	{'d', numFlag, argInt},
+	{'e', numFlag, argFloat | argComplex},
+	{'E', numFlag, argFloat | argComplex},
+	{'f', numFlag, argFloat | argComplex},
+	{'F', numFlag, argFloat | argComplex},
+	{'g', numFlag, argFloat | argComplex},
+	{'G', numFlag, argFloat | argComplex},
+	{'o', sharpNumFlag, argInt},
+	{'p', "-#", argPointer},
+	{'q', " -+.0#", argRune | argInt | argString},
+	{'s', " -+.0", argString},
+	{'t', "-", argBool},
+	{'T', "-", anyType},
+	{'U', "-#", argRune | argInt},
+	{'v', allFlags, anyType},
+	{'x', sharpNumFlag, argRune | argInt | argString},
+	{'X', sharpNumFlag, argRune | argInt | argString},
+}
+
+// okPrintfArg compares the formatState to the arguments actually present,
+// reporting any discrepancies it can discern. If the final argument is ellipsissed,
+// there's little it can do for that.
+func (f *File) okPrintfArg(call *ast.CallExpr, state *formatState) (ok bool) {
+	var v printVerb
+	found := false
+	// Linear scan is fast enough for a small list.
+	for _, v = range printVerbs {
+		if v.verb == state.verb {
+			found = true
+			break
+		}
+	}
+	if !found {
+		f.Badf(call.Pos(), "unrecognized printf verb %q", state.verb)
+		return false
+	}
+	for _, flag := range state.flags {
+		if !strings.ContainsRune(v.flags, rune(flag)) {
+			f.Badf(call.Pos(), "unrecognized printf flag for verb %q: %q", state.verb, flag)
+			return false
+		}
+	}
+	// Verb is good. If len(state.argNums)>trueArgs, we have something like %.*s and all
+	// but the final arg must be an integer.
+	trueArgs := 1
+	if state.verb == '%' {
+		trueArgs = 0
+	}
+	nargs := len(state.argNums)
+	for i := 0; i < nargs-trueArgs; i++ {
+		argNum := state.argNums[i]
+		if !f.argCanBeChecked(call, i, true, state) {
+			return
+		}
+		arg := call.Args[argNum]
+		if !f.matchArgType(argInt, nil, arg) {
+			f.Badf(call.Pos(), "arg %s for * in printf format not of type int", f.gofmt(arg))
+			return false
+		}
+	}
+	if state.verb == '%' {
+		return true
+	}
+	argNum := state.argNums[len(state.argNums)-1]
+	if !f.argCanBeChecked(call, len(state.argNums)-1, false, state) {
+		return false
+	}
+	arg := call.Args[argNum]
+	if !f.matchArgType(v.typ, nil, arg) {
+		typeString := ""
+		if typ := f.pkg.types[arg].Type; typ != nil {
+			typeString = typ.String()
+		}
+		f.Badf(call.Pos(), "arg %s for printf verb %%%c of wrong type: %s", f.gofmt(arg), state.verb, typeString)
+		return false
+	}
+	if v.typ&argString != 0 && v.verb != 'T' && !bytes.Contains(state.flags, []byte{'#'}) && f.recursiveStringer(arg) {
+		f.Badf(call.Pos(), "arg %s for printf causes recursive call to String method", f.gofmt(arg))
+		return false
+	}
+	return true
+}
+
+// recursiveStringer reports whether the provided argument is r or &r for the
+// fmt.Stringer receiver identifier r.
+func (f *File) recursiveStringer(e ast.Expr) bool {
+	if len(f.stringers) == 0 {
+		return false
+	}
+	var obj *ast.Object
+	switch e := e.(type) {
+	case *ast.Ident:
+		obj = e.Obj
+	case *ast.UnaryExpr:
+		if id, ok := e.X.(*ast.Ident); ok && e.Op == token.AND {
+			obj = id.Obj
+		}
+	}
+
+	// It's unlikely to be a recursive stringer if it has a Format method.
+	if typ := f.pkg.types[e].Type; typ != nil {
+		// Not a perfect match; see issue 6259.
+		if f.hasMethod(typ, "Format") {
+			return false
+		}
+	}
+
+	// We compare the underlying Object, which checks that the identifier
+	// is the one we declared as the receiver for the String method in
+	// which this printf appears.
+	return f.stringers[obj]
+}
+
+// argCanBeChecked reports whether the specified argument is statically present;
+// it may be beyond the list of arguments or in a terminal slice... argument, which
+// means we can't see it.
+func (f *File) argCanBeChecked(call *ast.CallExpr, formatArg int, isStar bool, state *formatState) bool {
+	argNum := state.argNums[formatArg]
+	if argNum < 0 {
+		// Shouldn't happen, so catch it with prejudice.
+		panic("negative arg num")
+	}
+	if argNum == 0 {
+		f.Badf(call.Pos(), `index value [0] for %s("%s"); indexes start at 1`, state.name, state.format)
+		return false
+	}
+	if argNum < len(call.Args)-1 {
+		return true // Always OK.
+	}
+	if call.Ellipsis.IsValid() {
+		return false // We just can't tell; there could be many more arguments.
+	}
+	if argNum < len(call.Args) {
+		return true
+	}
+	// There are bad indexes in the format or there are fewer arguments than the format needs.
+	// This is the argument number relative to the format: Printf("%s", "hi") will give 1 for the "hi".
+	arg := argNum - state.firstArg + 1 // People think of arguments as 1-indexed.
+	f.Badf(call.Pos(), `missing argument for %s("%s"): format reads arg %d, have only %d args`, state.name, state.format, arg, len(call.Args)-state.firstArg)
+	return false
+}
+
+// checkPrint checks a call to an unformatted print routine such as Println.
+// call.Args[firstArg] is the first argument to be printed.
+func (f *File) checkPrint(call *ast.CallExpr, name string, firstArg int) {
+	isLn := strings.HasSuffix(name, "ln")
+	isF := strings.HasPrefix(name, "F")
+	args := call.Args
+	if name == "Log" && len(args) > 0 {
+		// Special case: Don't complain about math.Log or cmplx.Log.
+		// Not strictly necessary because the only complaint likely is for Log("%d")
+		// but it feels wrong to check that math.Log is a good print function.
+		if sel, ok := args[0].(*ast.SelectorExpr); ok {
+			if x, ok := sel.X.(*ast.Ident); ok {
+				if x.Name == "math" || x.Name == "cmplx" {
+					return
+				}
+			}
+		}
+	}
+	// check for Println(os.Stderr, ...)
+	if firstArg == 0 && !isF && len(args) > 0 {
+		if sel, ok := args[0].(*ast.SelectorExpr); ok {
+			if x, ok := sel.X.(*ast.Ident); ok {
+				if x.Name == "os" && strings.HasPrefix(sel.Sel.Name, "Std") {
+					f.Badf(call.Pos(), "first argument to %s is %s.%s", name, x.Name, sel.Sel.Name)
+				}
+			}
+		}
+	}
+	if len(args) <= firstArg {
+		// If we have a call to a method called Error that satisfies the Error interface,
+		// then it's ok. Otherwise it's something like (*T).Error from the testing package
+		// and we need to check it.
+		if name == "Error" && f.isErrorMethodCall(call) {
+			return
+		}
+		// If it's an Error call now, it's probably for printing errors.
+		if !isLn {
+			// Check the signature to be sure: there are niladic functions called "error".
+			if firstArg != 0 || f.numArgsInSignature(call) != firstArg {
+				f.Badf(call.Pos(), "no args in %s call", name)
+			}
+		}
+		return
+	}
+	arg := args[firstArg]
+	if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING {
+		if strings.Contains(lit.Value, "%") {
+			f.Badf(call.Pos(), "possible formatting directive in %s call", name)
+		}
+	}
+	if isLn {
+		// The last item, if a string, should not have a newline.
+		arg = args[len(call.Args)-1]
+		if lit, ok := arg.(*ast.BasicLit); ok && lit.Kind == token.STRING {
+			if strings.HasSuffix(lit.Value, `\n"`) {
+				f.Badf(call.Pos(), "%s call ends with newline", name)
+			}
+		}
+	}
+	for _, arg := range args {
+		if f.recursiveStringer(arg) {
+			f.Badf(call.Pos(), "arg %s for print causes recursive call to String method", f.gofmt(arg))
+		}
+	}
+}
diff --git a/src/cmd/vet/rangeloop.go b/src/cmd/vet/rangeloop.go
new file mode 100644
index 0000000..11eef59
--- /dev/null
+++ b/src/cmd/vet/rangeloop.go
@@ -0,0 +1,70 @@
+// 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.
+
+/*
+This file contains the code to check range loop variables bound inside function
+literals that are deferred or launched in new goroutines. We only check
+instances where the defer or go statement is the last statement in the loop
+body, as otherwise we would need whole program analysis.
+
+For example:
+
+	for i, v := range s {
+		go func() {
+			println(i, v) // not what you might expect
+		}()
+	}
+
+See: https://golang.org/doc/go_faq.html#closures_and_goroutines
+*/
+
+package main
+
+import "go/ast"
+
+func init() {
+	register("rangeloops",
+		"check that range loop variables are used correctly",
+		checkRangeLoop,
+		rangeStmt)
+}
+
+// checkRangeLoop walks the body of the provided range statement, checking if
+// its index or value variables are used unsafely inside goroutines or deferred
+// function literals.
+func checkRangeLoop(f *File, node ast.Node) {
+	n := node.(*ast.RangeStmt)
+	key, _ := n.Key.(*ast.Ident)
+	val, _ := n.Value.(*ast.Ident)
+	if key == nil && val == nil {
+		return
+	}
+	sl := n.Body.List
+	if len(sl) == 0 {
+		return
+	}
+	var last *ast.CallExpr
+	switch s := sl[len(sl)-1].(type) {
+	case *ast.GoStmt:
+		last = s.Call
+	case *ast.DeferStmt:
+		last = s.Call
+	default:
+		return
+	}
+	lit, ok := last.Fun.(*ast.FuncLit)
+	if !ok {
+		return
+	}
+	ast.Inspect(lit.Body, func(n ast.Node) bool {
+		id, ok := n.(*ast.Ident)
+		if !ok || id.Obj == nil {
+			return true
+		}
+		if key != nil && id.Obj == key.Obj || val != nil && id.Obj == val.Obj {
+			f.Bad(id.Pos(), "range variable", id.Name, "captured by func literal")
+		}
+		return true
+	})
+}
diff --git a/src/cmd/vet/shadow.go b/src/cmd/vet/shadow.go
new file mode 100644
index 0000000..2149e70
--- /dev/null
+++ b/src/cmd/vet/shadow.go
@@ -0,0 +1,244 @@
+// 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.
+
+/*
+This file contains the code to check for shadowed variables.
+A shadowed variable is a variable declared in an inner scope
+with the same name and type as a variable in an outer scope,
+and where the outer variable is mentioned after the inner one
+is declared.
+
+(This definition can be refined; the module generates too many
+false positives and is not yet enabled by default.)
+
+For example:
+
+	func BadRead(f *os.File, buf []byte) error {
+		var err error
+		for {
+			n, err := f.Read(buf) // shadows the function variable 'err'
+			if err != nil {
+				break // causes return of wrong value
+			}
+			foo(buf)
+		}
+		return err
+	}
+
+*/
+
+package main
+
+import (
+	"flag"
+	"go/ast"
+	"go/token"
+	"go/types"
+)
+
+var strictShadowing = flag.Bool("shadowstrict", false, "whether to be strict about shadowing; can be noisy")
+
+func init() {
+	register("shadow",
+		"check for shadowed variables (experimental; must be set explicitly)",
+		checkShadow,
+		assignStmt, genDecl)
+	experimental["shadow"] = true
+}
+
+func checkShadow(f *File, node ast.Node) {
+	switch n := node.(type) {
+	case *ast.AssignStmt:
+		checkShadowAssignment(f, n)
+	case *ast.GenDecl:
+		checkShadowDecl(f, n)
+	}
+}
+
+// Span stores the minimum range of byte positions in the file in which a
+// given variable (types.Object) is mentioned. It is lexically defined: it spans
+// from the beginning of its first mention to the end of its last mention.
+// A variable is considered shadowed (if *strictShadowing is off) only if the
+// shadowing variable is declared within the span of the shadowed variable.
+// In other words, if a variable is shadowed but not used after the shadowed
+// variable is declared, it is inconsequential and not worth complaining about.
+// This simple check dramatically reduces the nuisance rate for the shadowing
+// check, at least until something cleverer comes along.
+//
+// One wrinkle: A "naked return" is a silent use of a variable that the Span
+// will not capture, but the compilers catch naked returns of shadowed
+// variables so we don't need to.
+//
+// Cases this gets wrong (TODO):
+// - If a for loop's continuation statement mentions a variable redeclared in
+// the block, we should complain about it but don't.
+// - A variable declared inside a function literal can falsely be identified
+// as shadowing a variable in the outer function.
+//
+type Span struct {
+	min token.Pos
+	max token.Pos
+}
+
+// contains reports whether the position is inside the span.
+func (s Span) contains(pos token.Pos) bool {
+	return s.min <= pos && pos < s.max
+}
+
+// growSpan expands the span for the object to contain the instance represented
+// by the identifier.
+func (pkg *Package) growSpan(ident *ast.Ident, obj types.Object) {
+	if *strictShadowing {
+		return // No need
+	}
+	pos := ident.Pos()
+	end := ident.End()
+	span, ok := pkg.spans[obj]
+	if ok {
+		if span.min > pos {
+			span.min = pos
+		}
+		if span.max < end {
+			span.max = end
+		}
+	} else {
+		span = Span{pos, end}
+	}
+	pkg.spans[obj] = span
+}
+
+// checkShadowAssignment checks for shadowing in a short variable declaration.
+func checkShadowAssignment(f *File, a *ast.AssignStmt) {
+	if a.Tok != token.DEFINE {
+		return
+	}
+	if f.idiomaticShortRedecl(a) {
+		return
+	}
+	for _, expr := range a.Lhs {
+		ident, ok := expr.(*ast.Ident)
+		if !ok {
+			f.Badf(expr.Pos(), "invalid AST: short variable declaration of non-identifier")
+			return
+		}
+		checkShadowing(f, ident)
+	}
+}
+
+// idiomaticShortRedecl reports whether this short declaration can be ignored for
+// the purposes of shadowing, that is, that any redeclarations it contains are deliberate.
+func (f *File) idiomaticShortRedecl(a *ast.AssignStmt) bool {
+	// Don't complain about deliberate redeclarations of the form
+	//	i := i
+	// Such constructs are idiomatic in range loops to create a new variable
+	// for each iteration. Another example is
+	//	switch n := n.(type)
+	if len(a.Rhs) != len(a.Lhs) {
+		return false
+	}
+	// We know it's an assignment, so the LHS must be all identifiers. (We check anyway.)
+	for i, expr := range a.Lhs {
+		lhs, ok := expr.(*ast.Ident)
+		if !ok {
+			f.Badf(expr.Pos(), "invalid AST: short variable declaration of non-identifier")
+			return true // Don't do any more processing.
+		}
+		switch rhs := a.Rhs[i].(type) {
+		case *ast.Ident:
+			if lhs.Name != rhs.Name {
+				return false
+			}
+		case *ast.TypeAssertExpr:
+			if id, ok := rhs.X.(*ast.Ident); ok {
+				if lhs.Name != id.Name {
+					return false
+				}
+			}
+		}
+	}
+	return true
+}
+
+// idiomaticRedecl reports whether this declaration spec can be ignored for
+// the purposes of shadowing, that is, that any redeclarations it contains are deliberate.
+func (f *File) idiomaticRedecl(d *ast.ValueSpec) bool {
+	// Don't complain about deliberate redeclarations of the form
+	//	var i, j = i, j
+	if len(d.Names) != len(d.Values) {
+		return false
+	}
+	for i, lhs := range d.Names {
+		if rhs, ok := d.Values[i].(*ast.Ident); ok {
+			if lhs.Name != rhs.Name {
+				return false
+			}
+		}
+	}
+	return true
+}
+
+// checkShadowDecl checks for shadowing in a general variable declaration.
+func checkShadowDecl(f *File, d *ast.GenDecl) {
+	if d.Tok != token.VAR {
+		return
+	}
+	for _, spec := range d.Specs {
+		valueSpec, ok := spec.(*ast.ValueSpec)
+		if !ok {
+			f.Badf(spec.Pos(), "invalid AST: var GenDecl not ValueSpec")
+			return
+		}
+		// Don't complain about deliberate redeclarations of the form
+		//	var i = i
+		if f.idiomaticRedecl(valueSpec) {
+			return
+		}
+		for _, ident := range valueSpec.Names {
+			checkShadowing(f, ident)
+		}
+	}
+}
+
+// checkShadowing checks whether the identifier shadows an identifier in an outer scope.
+func checkShadowing(f *File, ident *ast.Ident) {
+	if ident.Name == "_" {
+		// Can't shadow the blank identifier.
+		return
+	}
+	obj := f.pkg.defs[ident]
+	if obj == nil {
+		return
+	}
+	// obj.Parent.Parent is the surrounding scope. If we can find another declaration
+	// starting from there, we have a shadowed identifier.
+	_, shadowed := obj.Parent().Parent().LookupParent(obj.Name(), obj.Pos())
+	if shadowed == nil {
+		return
+	}
+	// Don't complain if it's shadowing a universe-declared identifier; that's fine.
+	if shadowed.Parent() == types.Universe {
+		return
+	}
+	if *strictShadowing {
+		// The shadowed identifier must appear before this one to be an instance of shadowing.
+		if shadowed.Pos() > ident.Pos() {
+			return
+		}
+	} else {
+		// Don't complain if the span of validity of the shadowed identifier doesn't include
+		// the shadowing identifier.
+		span, ok := f.pkg.spans[shadowed]
+		if !ok {
+			f.Badf(ident.Pos(), "internal error: no range for %s", ident.Name)
+			return
+		}
+		if !span.contains(ident.Pos()) {
+			return
+		}
+	}
+	// Don't complain if the types differ: that implies the programmer really wants two different things.
+	if types.Identical(obj.Type(), shadowed.Type()) {
+		f.Badf(ident.Pos(), "declaration of %s shadows declaration at %s", obj.Name(), f.loc(shadowed.Pos()))
+	}
+}
diff --git a/src/cmd/vet/shift.go b/src/cmd/vet/shift.go
new file mode 100644
index 0000000..8c038b4
--- /dev/null
+++ b/src/cmd/vet/shift.go
@@ -0,0 +1,82 @@
+// 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.
+
+/*
+This file contains the code to check for suspicious shifts.
+*/
+
+package main
+
+import (
+	"go/ast"
+	"go/constant"
+	"go/token"
+	"go/types"
+)
+
+func init() {
+	register("shift",
+		"check for useless shifts",
+		checkShift,
+		binaryExpr, assignStmt)
+}
+
+func checkShift(f *File, node ast.Node) {
+	switch node := node.(type) {
+	case *ast.BinaryExpr:
+		if node.Op == token.SHL || node.Op == token.SHR {
+			checkLongShift(f, node, node.X, node.Y)
+		}
+	case *ast.AssignStmt:
+		if len(node.Lhs) != 1 || len(node.Rhs) != 1 {
+			return
+		}
+		if node.Tok == token.SHL_ASSIGN || node.Tok == token.SHR_ASSIGN {
+			checkLongShift(f, node, node.Lhs[0], node.Rhs[0])
+		}
+	}
+}
+
+// checkLongShift checks if shift or shift-assign operations shift by more than
+// the length of the underlying variable.
+func checkLongShift(f *File, node ast.Node, x, y ast.Expr) {
+	v := f.pkg.types[y].Value
+	if v == nil {
+		return
+	}
+	amt, ok := constant.Int64Val(v)
+	if !ok {
+		return
+	}
+	t := f.pkg.types[x].Type
+	if t == nil {
+		return
+	}
+	b, ok := t.Underlying().(*types.Basic)
+	if !ok {
+		return
+	}
+	var size int64
+	var msg string
+	switch b.Kind() {
+	case types.Uint8, types.Int8:
+		size = 8
+	case types.Uint16, types.Int16:
+		size = 16
+	case types.Uint32, types.Int32:
+		size = 32
+	case types.Uint64, types.Int64:
+		size = 64
+	case types.Int, types.Uint, types.Uintptr:
+		// These types may be as small as 32 bits, but no smaller.
+		size = 32
+		msg = "might be "
+	default:
+		return
+	}
+	if amt >= size {
+		ident := f.gofmt(x)
+		f.Badf(node.Pos(), "%s %stoo small for shift of %d", ident, msg, amt)
+	}
+}
diff --git a/src/cmd/vet/structtag.go b/src/cmd/vet/structtag.go
new file mode 100644
index 0000000..e8164a4
--- /dev/null
+++ b/src/cmd/vet/structtag.go
@@ -0,0 +1,122 @@
+// Copyright 2010 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 contains the test for canonical struct tags.
+
+package main
+
+import (
+	"errors"
+	"go/ast"
+	"reflect"
+	"strconv"
+)
+
+func init() {
+	register("structtags",
+		"check that struct field tags have canonical format and apply to exported fields as needed",
+		checkCanonicalFieldTag,
+		field)
+}
+
+// checkCanonicalFieldTag checks a struct field tag.
+func checkCanonicalFieldTag(f *File, node ast.Node) {
+	field := node.(*ast.Field)
+	if field.Tag == nil {
+		return
+	}
+
+	tag, err := strconv.Unquote(field.Tag.Value)
+	if err != nil {
+		f.Badf(field.Pos(), "unable to read struct tag %s", field.Tag.Value)
+		return
+	}
+
+	if err := validateStructTag(tag); err != nil {
+		f.Badf(field.Pos(), "struct field tag %s not compatible with reflect.StructTag.Get: %s", field.Tag.Value, err)
+	}
+
+	// Check for use of json or xml tags with unexported fields.
+
+	// Embedded struct. Nothing to do for now, but that
+	// may change, depending on what happens with issue 7363.
+	if len(field.Names) == 0 {
+		return
+	}
+
+	if field.Names[0].IsExported() {
+		return
+	}
+
+	st := reflect.StructTag(tag)
+	for _, enc := range [...]string{"json", "xml"} {
+		if st.Get(enc) != "" {
+			f.Badf(field.Pos(), "struct field %s has %s tag but is not exported", field.Names[0].Name, enc)
+			return
+		}
+	}
+}
+
+var (
+	errTagSyntax      = errors.New("bad syntax for struct tag pair")
+	errTagKeySyntax   = errors.New("bad syntax for struct tag key")
+	errTagValueSyntax = errors.New("bad syntax for struct tag value")
+)
+
+// validateStructTag parses the struct tag and returns an error if it is not
+// in the canonical format, which is a space-separated list of key:"value"
+// settings. The value may contain spaces.
+func validateStructTag(tag string) error {
+	// This code is based on the StructTag.Get code in package reflect.
+
+	for tag != "" {
+		// Skip leading space.
+		i := 0
+		for i < len(tag) && tag[i] == ' ' {
+			i++
+		}
+		tag = tag[i:]
+		if tag == "" {
+			break
+		}
+
+		// Scan to colon. A space, a quote or a control character is a syntax error.
+		// Strictly speaking, control chars include the range [0x7f, 0x9f], not just
+		// [0x00, 0x1f], but in practice, we ignore the multi-byte control characters
+		// as it is simpler to inspect the tag's bytes than the tag's runes.
+		i = 0
+		for i < len(tag) && tag[i] > ' ' && tag[i] != ':' && tag[i] != '"' && tag[i] != 0x7f {
+			i++
+		}
+		if i == 0 {
+			return errTagKeySyntax
+		}
+		if i+1 >= len(tag) || tag[i] != ':' {
+			return errTagSyntax
+		}
+		if tag[i+1] != '"' {
+			return errTagValueSyntax
+		}
+		tag = tag[i+1:]
+
+		// Scan quoted string to find value.
+		i = 1
+		for i < len(tag) && tag[i] != '"' {
+			if tag[i] == '\\' {
+				i++
+			}
+			i++
+		}
+		if i >= len(tag) {
+			return errTagValueSyntax
+		}
+		qvalue := string(tag[:i+1])
+		tag = tag[i+1:]
+
+		if _, err := strconv.Unquote(qvalue); err != nil {
+			return errTagValueSyntax
+		}
+	}
+	return nil
+}
diff --git a/src/cmd/vet/testdata/asm.go b/src/cmd/vet/testdata/asm.go
new file mode 100644
index 0000000..9a3d531
--- /dev/null
+++ b/src/cmd/vet/testdata/asm.go
@@ -0,0 +1,33 @@
+// Copyright 2010 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 file contains declarations to test the assembly in test_asm.s.
+
+package testdata
+
+func arg1(x int8, y uint8)
+func arg2(x int16, y uint16)
+func arg4(x int32, y uint32)
+func arg8(x int64, y uint64)
+func argint(x int, y uint)
+func argptr(x *byte, y *byte, c chan int, m map[int]int, f func())
+func argstring(x, y string)
+func argslice(x, y []string)
+func argiface(x interface{}, y interface {
+	m()
+})
+func returnint() int
+func returnbyte(x int) byte
+func returnnamed(x byte) (r1 int, r2 int16, r3 string, r4 byte)
+func returnintmissing() int
+func leaf(x, y int) int
+
+func noprof(x int)
+func dupok(x int)
+func nosplit(x int)
+func rodata(x int)
+func noptr(x int)
+func wrapper(x int)
diff --git a/src/cmd/vet/testdata/asm1.s b/src/cmd/vet/testdata/asm1.s
new file mode 100644
index 0000000..62f423c
--- /dev/null
+++ b/src/cmd/vet/testdata/asm1.s
@@ -0,0 +1,254 @@
+// 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 amd64
+// +build vet_test
+
+TEXT ·arg1(SB),0,$0-2
+	MOVB	x+0(FP), AX
+	// MOVB x+0(FP), AX // commented out instructions used to panic
+	MOVB	y+1(FP), BX
+	MOVW	x+0(FP), AX // ERROR "\[amd64\] arg1: invalid MOVW of x\+0\(FP\); int8 is 1-byte value"
+	MOVW	y+1(FP), AX // ERROR "invalid MOVW of y\+1\(FP\); uint8 is 1-byte value"
+	MOVL	x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int8 is 1-byte value"
+	MOVL	y+1(FP), AX // ERROR "invalid MOVL of y\+1\(FP\); uint8 is 1-byte value"
+	MOVQ	x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); int8 is 1-byte value"
+	MOVQ	y+1(FP), AX // ERROR "invalid MOVQ of y\+1\(FP\); uint8 is 1-byte value"
+	MOVB	x+1(FP), AX // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)"
+	MOVB	y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)"
+	TESTB	x+0(FP), AX
+	TESTB	y+1(FP), BX
+	TESTW	x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int8 is 1-byte value"
+	TESTW	y+1(FP), AX // ERROR "invalid TESTW of y\+1\(FP\); uint8 is 1-byte value"
+	TESTL	x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int8 is 1-byte value"
+	TESTL	y+1(FP), AX // ERROR "invalid TESTL of y\+1\(FP\); uint8 is 1-byte value"
+	TESTQ	x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); int8 is 1-byte value"
+	TESTQ	y+1(FP), AX // ERROR "invalid TESTQ of y\+1\(FP\); uint8 is 1-byte value"
+	TESTB	x+1(FP), AX // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)"
+	TESTB	y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)"
+	MOVB	8(SP), AX // ERROR "8\(SP\) should be x\+0\(FP\)"
+	MOVB	9(SP), AX // ERROR "9\(SP\) should be y\+1\(FP\)"
+	MOVB	10(SP), AX // ERROR "use of 10\(SP\) points beyond argument frame"
+	RET
+
+TEXT ·arg2(SB),0,$0-4
+	MOVB	x+0(FP), AX // ERROR "arg2: invalid MOVB of x\+0\(FP\); int16 is 2-byte value"
+	MOVB	y+2(FP), AX // ERROR "invalid MOVB of y\+2\(FP\); uint16 is 2-byte value"
+	MOVW	x+0(FP), AX
+	MOVW	y+2(FP), BX
+	MOVL	x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int16 is 2-byte value"
+	MOVL	y+2(FP), AX // ERROR "invalid MOVL of y\+2\(FP\); uint16 is 2-byte value"
+	MOVQ	x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); int16 is 2-byte value"
+	MOVQ	y+2(FP), AX // ERROR "invalid MOVQ of y\+2\(FP\); uint16 is 2-byte value"
+	MOVW	x+2(FP), AX // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)"
+	MOVW	y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)"
+	TESTB	x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int16 is 2-byte value"
+	TESTB	y+2(FP), AX // ERROR "invalid TESTB of y\+2\(FP\); uint16 is 2-byte value"
+	TESTW	x+0(FP), AX
+	TESTW	y+2(FP), BX
+	TESTL	x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int16 is 2-byte value"
+	TESTL	y+2(FP), AX // ERROR "invalid TESTL of y\+2\(FP\); uint16 is 2-byte value"
+	TESTQ	x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); int16 is 2-byte value"
+	TESTQ	y+2(FP), AX // ERROR "invalid TESTQ of y\+2\(FP\); uint16 is 2-byte value"
+	TESTW	x+2(FP), AX // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)"
+	TESTW	y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)"
+	RET
+
+TEXT ·arg4(SB),0,$0-2 // ERROR "arg4: wrong argument size 2; expected \$\.\.\.-8"
+	MOVB	x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int32 is 4-byte value"
+	MOVB	y+4(FP), BX // ERROR "invalid MOVB of y\+4\(FP\); uint32 is 4-byte value"
+	MOVW	x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int32 is 4-byte value"
+	MOVW	y+4(FP), AX // ERROR "invalid MOVW of y\+4\(FP\); uint32 is 4-byte value"
+	MOVL	x+0(FP), AX
+	MOVL	y+4(FP), AX
+	MOVQ	x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); int32 is 4-byte value"
+	MOVQ	y+4(FP), AX // ERROR "invalid MOVQ of y\+4\(FP\); uint32 is 4-byte value"
+	MOVL	x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
+	MOVL	y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
+	TESTB	x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int32 is 4-byte value"
+	TESTB	y+4(FP), BX // ERROR "invalid TESTB of y\+4\(FP\); uint32 is 4-byte value"
+	TESTW	x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int32 is 4-byte value"
+	TESTW	y+4(FP), AX // ERROR "invalid TESTW of y\+4\(FP\); uint32 is 4-byte value"
+	TESTL	x+0(FP), AX
+	TESTL	y+4(FP), AX
+	TESTQ	x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); int32 is 4-byte value"
+	TESTQ	y+4(FP), AX // ERROR "invalid TESTQ of y\+4\(FP\); uint32 is 4-byte value"
+	TESTL	x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
+	TESTL	y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
+	RET
+
+TEXT ·arg8(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16"
+	MOVB	x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int64 is 8-byte value"
+	MOVB	y+8(FP), BX // ERROR "invalid MOVB of y\+8\(FP\); uint64 is 8-byte value"
+	MOVW	x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int64 is 8-byte value"
+	MOVW	y+8(FP), AX // ERROR "invalid MOVW of y\+8\(FP\); uint64 is 8-byte value"
+	MOVL	x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int64 is 8-byte value"
+	MOVL	y+8(FP), AX // ERROR "invalid MOVL of y\+8\(FP\); uint64 is 8-byte value"
+	MOVQ	x+0(FP), AX
+	MOVQ	y+8(FP), AX
+	MOVQ	x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
+	MOVQ	y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
+	TESTB	x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int64 is 8-byte value"
+	TESTB	y+8(FP), BX // ERROR "invalid TESTB of y\+8\(FP\); uint64 is 8-byte value"
+	TESTW	x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int64 is 8-byte value"
+	TESTW	y+8(FP), AX // ERROR "invalid TESTW of y\+8\(FP\); uint64 is 8-byte value"
+	TESTL	x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int64 is 8-byte value"
+	TESTL	y+8(FP), AX // ERROR "invalid TESTL of y\+8\(FP\); uint64 is 8-byte value"
+	TESTQ	x+0(FP), AX
+	TESTQ	y+8(FP), AX
+	TESTQ	x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
+	TESTQ	y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
+	RET
+
+TEXT ·argint(SB),0,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16"
+	MOVB	x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int is 8-byte value"
+	MOVB	y+8(FP), BX // ERROR "invalid MOVB of y\+8\(FP\); uint is 8-byte value"
+	MOVW	x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int is 8-byte value"
+	MOVW	y+8(FP), AX // ERROR "invalid MOVW of y\+8\(FP\); uint is 8-byte value"
+	MOVL	x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int is 8-byte value"
+	MOVL	y+8(FP), AX // ERROR "invalid MOVL of y\+8\(FP\); uint is 8-byte value"
+	MOVQ	x+0(FP), AX
+	MOVQ	y+8(FP), AX
+	MOVQ	x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
+	MOVQ	y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
+	TESTB	x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int is 8-byte value"
+	TESTB	y+8(FP), BX // ERROR "invalid TESTB of y\+8\(FP\); uint is 8-byte value"
+	TESTW	x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int is 8-byte value"
+	TESTW	y+8(FP), AX // ERROR "invalid TESTW of y\+8\(FP\); uint is 8-byte value"
+	TESTL	x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int is 8-byte value"
+	TESTL	y+8(FP), AX // ERROR "invalid TESTL of y\+8\(FP\); uint is 8-byte value"
+	TESTQ	x+0(FP), AX
+	TESTQ	y+8(FP), AX
+	TESTQ	x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
+	TESTQ	y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
+	RET
+
+TEXT ·argptr(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-40"
+	MOVB	x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); \*byte is 8-byte value"
+	MOVB	y+8(FP), BX // ERROR "invalid MOVB of y\+8\(FP\); \*byte is 8-byte value"
+	MOVW	x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); \*byte is 8-byte value"
+	MOVW	y+8(FP), AX // ERROR "invalid MOVW of y\+8\(FP\); \*byte is 8-byte value"
+	MOVL	x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); \*byte is 8-byte value"
+	MOVL	y+8(FP), AX // ERROR "invalid MOVL of y\+8\(FP\); \*byte is 8-byte value"
+	MOVQ	x+0(FP), AX
+	MOVQ	y+8(FP), AX
+	MOVQ	x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
+	MOVQ	y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
+	TESTB	x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); \*byte is 8-byte value"
+	TESTB	y+8(FP), BX // ERROR "invalid TESTB of y\+8\(FP\); \*byte is 8-byte value"
+	TESTW	x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); \*byte is 8-byte value"
+	TESTW	y+8(FP), AX // ERROR "invalid TESTW of y\+8\(FP\); \*byte is 8-byte value"
+	TESTL	x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); \*byte is 8-byte value"
+	TESTL	y+8(FP), AX // ERROR "invalid TESTL of y\+8\(FP\); \*byte is 8-byte value"
+	TESTQ	x+0(FP), AX
+	TESTQ	y+8(FP), AX
+	TESTQ	x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
+	TESTQ	y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
+	MOVL	c+16(FP), AX // ERROR "invalid MOVL of c\+16\(FP\); chan int is 8-byte value"
+	MOVL	m+24(FP), AX // ERROR "invalid MOVL of m\+24\(FP\); map\[int\]int is 8-byte value"
+	MOVL	f+32(FP), AX // ERROR "invalid MOVL of f\+32\(FP\); func\(\) is 8-byte value"
+	RET
+
+TEXT ·argstring(SB),0,$32 // ERROR "wrong argument size 0; expected \$\.\.\.-32"
+	MOVW	x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); string base is 8-byte value"
+	MOVL	x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); string base is 8-byte value"
+	MOVQ	x+0(FP), AX
+	MOVW	x_base+0(FP), AX // ERROR "invalid MOVW of x_base\+0\(FP\); string base is 8-byte value"
+	MOVL	x_base+0(FP), AX // ERROR "invalid MOVL of x_base\+0\(FP\); string base is 8-byte value"
+	MOVQ	x_base+0(FP), AX
+	MOVW	x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
+	MOVL	x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
+	MOVQ	x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
+	MOVW	x_len+8(FP), AX // ERROR "invalid MOVW of x_len\+8\(FP\); string len is 8-byte value"
+	MOVL	x_len+8(FP), AX // ERROR "invalid MOVL of x_len\+8\(FP\); string len is 8-byte value"
+	MOVQ	x_len+8(FP), AX
+	MOVQ	y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+16\(FP\)"
+	MOVQ	y_len+8(FP), AX // ERROR "invalid offset y_len\+8\(FP\); expected y_len\+24\(FP\)"
+	RET
+
+TEXT ·argslice(SB),0,$48 // ERROR "wrong argument size 0; expected \$\.\.\.-48"
+	MOVW	x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); slice base is 8-byte value"
+	MOVL	x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); slice base is 8-byte value"
+	MOVQ	x+0(FP), AX
+	MOVW	x_base+0(FP), AX // ERROR "invalid MOVW of x_base\+0\(FP\); slice base is 8-byte value"
+	MOVL	x_base+0(FP), AX // ERROR "invalid MOVL of x_base\+0\(FP\); slice base is 8-byte value"
+	MOVQ	x_base+0(FP), AX
+	MOVW	x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
+	MOVL	x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
+	MOVQ	x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+8\(FP\)"
+	MOVW	x_len+8(FP), AX // ERROR "invalid MOVW of x_len\+8\(FP\); slice len is 8-byte value"
+	MOVL	x_len+8(FP), AX // ERROR "invalid MOVL of x_len\+8\(FP\); slice len is 8-byte value"
+	MOVQ	x_len+8(FP), AX
+	MOVW	x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)"
+	MOVL	x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)"
+	MOVQ	x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+16\(FP\)"
+	MOVW	x_cap+16(FP), AX // ERROR "invalid MOVW of x_cap\+16\(FP\); slice cap is 8-byte value"
+	MOVL	x_cap+16(FP), AX // ERROR "invalid MOVL of x_cap\+16\(FP\); slice cap is 8-byte value"
+	MOVQ	x_cap+16(FP), AX
+	MOVQ	y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+24\(FP\)"
+	MOVQ	y_len+8(FP), AX // ERROR "invalid offset y_len\+8\(FP\); expected y_len\+32\(FP\)"
+	MOVQ	y_cap+16(FP), AX // ERROR "invalid offset y_cap\+16\(FP\); expected y_cap\+40\(FP\)"
+	RET
+
+TEXT ·argiface(SB),0,$0-32
+	MOVW	x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); interface type is 8-byte value"
+	MOVL	x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); interface type is 8-byte value"
+	MOVQ	x+0(FP), AX
+	MOVW	x_type+0(FP), AX // ERROR "invalid MOVW of x_type\+0\(FP\); interface type is 8-byte value"
+	MOVL	x_type+0(FP), AX // ERROR "invalid MOVL of x_type\+0\(FP\); interface type is 8-byte value"
+	MOVQ	x_type+0(FP), AX
+	MOVQ	x_itable+0(FP), AX // ERROR "unknown variable x_itable; offset 0 is x_type\+0\(FP\)"
+	MOVQ	x_itable+1(FP), AX // ERROR "unknown variable x_itable; offset 1 is x_type\+0\(FP\)"
+	MOVW	x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)"
+	MOVL	x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)"
+	MOVQ	x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+8\(FP\)"
+	MOVW	x_data+8(FP), AX // ERROR "invalid MOVW of x_data\+8\(FP\); interface data is 8-byte value"
+	MOVL	x_data+8(FP), AX // ERROR "invalid MOVL of x_data\+8\(FP\); interface data is 8-byte value"
+	MOVQ	x_data+8(FP), AX
+	MOVW	y+16(FP), AX // ERROR "invalid MOVW of y\+16\(FP\); interface itable is 8-byte value"
+	MOVL	y+16(FP), AX // ERROR "invalid MOVL of y\+16\(FP\); interface itable is 8-byte value"
+	MOVQ	y+16(FP), AX
+	MOVW	y_itable+16(FP), AX // ERROR "invalid MOVW of y_itable\+16\(FP\); interface itable is 8-byte value"
+	MOVL	y_itable+16(FP), AX // ERROR "invalid MOVL of y_itable\+16\(FP\); interface itable is 8-byte value"
+	MOVQ	y_itable+16(FP), AX
+	MOVQ	y_type+16(FP), AX // ERROR "unknown variable y_type; offset 16 is y_itable\+16\(FP\)"
+	MOVW	y_data+16(FP), AX // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)"
+	MOVL	y_data+16(FP), AX // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)"
+	MOVQ	y_data+16(FP), AX // ERROR "invalid offset y_data\+16\(FP\); expected y_data\+24\(FP\)"
+	MOVW	y_data+24(FP), AX // ERROR "invalid MOVW of y_data\+24\(FP\); interface data is 8-byte value"
+	MOVL	y_data+24(FP), AX // ERROR "invalid MOVL of y_data\+24\(FP\); interface data is 8-byte value"
+	MOVQ	y_data+24(FP), AX
+	RET
+
+TEXT ·returnint(SB),0,$0-8
+	MOVB	AX, ret+0(FP) // ERROR "invalid MOVB of ret\+0\(FP\); int is 8-byte value"
+	MOVW	AX, ret+0(FP) // ERROR "invalid MOVW of ret\+0\(FP\); int is 8-byte value"
+	MOVL	AX, ret+0(FP) // ERROR "invalid MOVL of ret\+0\(FP\); int is 8-byte value"
+	MOVQ	AX, ret+0(FP)
+	MOVQ	AX, ret+1(FP) // ERROR "invalid offset ret\+1\(FP\); expected ret\+0\(FP\)"
+	MOVQ	AX, r+0(FP) // ERROR "unknown variable r; offset 0 is ret\+0\(FP\)"
+	RET
+
+TEXT ·returnbyte(SB),0,$0-9
+	MOVQ	x+0(FP), AX
+	MOVB	AX, ret+8(FP)
+	MOVW	AX, ret+8(FP) // ERROR "invalid MOVW of ret\+8\(FP\); byte is 1-byte value"
+	MOVL	AX, ret+8(FP) // ERROR "invalid MOVL of ret\+8\(FP\); byte is 1-byte value"
+	MOVQ	AX, ret+8(FP) // ERROR "invalid MOVQ of ret\+8\(FP\); byte is 1-byte value"
+	MOVB	AX, ret+7(FP) // ERROR "invalid offset ret\+7\(FP\); expected ret\+8\(FP\)"
+	RET
+
+TEXT ·returnnamed(SB),0,$0-41
+	MOVB	x+0(FP), AX
+	MOVQ	AX, r1+8(FP)
+	MOVW	AX, r2+16(FP)
+	MOVQ	AX, r3+24(FP)
+	MOVQ	AX, r3_base+24(FP)
+	MOVQ	AX, r3_len+32(FP)
+	MOVB	AX, r4+40(FP)
+	MOVL	AX, r1+8(FP) // ERROR "invalid MOVL of r1\+8\(FP\); int is 8-byte value"
+	RET
+
+TEXT ·returnintmissing(SB),0,$0-8
+	RET // ERROR "RET without writing to 8-byte ret\+0\(FP\)"
diff --git a/src/cmd/vet/testdata/asm2.s b/src/cmd/vet/testdata/asm2.s
new file mode 100644
index 0000000..c33c02a
--- /dev/null
+++ b/src/cmd/vet/testdata/asm2.s
@@ -0,0 +1,257 @@
+// 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 386
+// +build vet_test
+
+TEXT ·arg1(SB),0,$0-2
+	MOVB	x+0(FP), AX
+	MOVB	y+1(FP), BX
+	MOVW	x+0(FP), AX // ERROR "\[386\] arg1: invalid MOVW of x\+0\(FP\); int8 is 1-byte value"
+	MOVW	y+1(FP), AX // ERROR "invalid MOVW of y\+1\(FP\); uint8 is 1-byte value"
+	MOVL	x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int8 is 1-byte value"
+	MOVL	y+1(FP), AX // ERROR "invalid MOVL of y\+1\(FP\); uint8 is 1-byte value"
+	MOVQ	x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); int8 is 1-byte value"
+	MOVQ	y+1(FP), AX // ERROR "invalid MOVQ of y\+1\(FP\); uint8 is 1-byte value"
+	MOVB	x+1(FP), AX // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)"
+	MOVB	y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)"
+	TESTB	x+0(FP), AX
+	TESTB	y+1(FP), BX
+	TESTW	x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int8 is 1-byte value"
+	TESTW	y+1(FP), AX // ERROR "invalid TESTW of y\+1\(FP\); uint8 is 1-byte value"
+	TESTL	x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int8 is 1-byte value"
+	TESTL	y+1(FP), AX // ERROR "invalid TESTL of y\+1\(FP\); uint8 is 1-byte value"
+	TESTQ	x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); int8 is 1-byte value"
+	TESTQ	y+1(FP), AX // ERROR "invalid TESTQ of y\+1\(FP\); uint8 is 1-byte value"
+	TESTB	x+1(FP), AX // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)"
+	TESTB	y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)"
+	MOVB	4(SP), AX // ERROR "4\(SP\) should be x\+0\(FP\)"
+	MOVB	5(SP), AX // ERROR "5\(SP\) should be y\+1\(FP\)"
+	MOVB	6(SP), AX // ERROR "use of 6\(SP\) points beyond argument frame"
+	RET
+
+TEXT ·arg2(SB),0,$0-4
+	MOVB	x+0(FP), AX // ERROR "arg2: invalid MOVB of x\+0\(FP\); int16 is 2-byte value"
+	MOVB	y+2(FP), AX // ERROR "invalid MOVB of y\+2\(FP\); uint16 is 2-byte value"
+	MOVW	x+0(FP), AX
+	MOVW	y+2(FP), BX
+	MOVL	x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int16 is 2-byte value"
+	MOVL	y+2(FP), AX // ERROR "invalid MOVL of y\+2\(FP\); uint16 is 2-byte value"
+	MOVQ	x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); int16 is 2-byte value"
+	MOVQ	y+2(FP), AX // ERROR "invalid MOVQ of y\+2\(FP\); uint16 is 2-byte value"
+	MOVW	x+2(FP), AX // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)"
+	MOVW	y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)"
+	TESTB	x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int16 is 2-byte value"
+	TESTB	y+2(FP), AX // ERROR "invalid TESTB of y\+2\(FP\); uint16 is 2-byte value"
+	TESTW	x+0(FP), AX
+	TESTW	y+2(FP), BX
+	TESTL	x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int16 is 2-byte value"
+	TESTL	y+2(FP), AX // ERROR "invalid TESTL of y\+2\(FP\); uint16 is 2-byte value"
+	TESTQ	x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); int16 is 2-byte value"
+	TESTQ	y+2(FP), AX // ERROR "invalid TESTQ of y\+2\(FP\); uint16 is 2-byte value"
+	TESTW	x+2(FP), AX // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)"
+	TESTW	y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)"
+	RET
+
+TEXT ·arg4(SB),0,$0-2 // ERROR "arg4: wrong argument size 2; expected \$\.\.\.-8"
+	MOVB	x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int32 is 4-byte value"
+	MOVB	y+4(FP), BX // ERROR "invalid MOVB of y\+4\(FP\); uint32 is 4-byte value"
+	MOVW	x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int32 is 4-byte value"
+	MOVW	y+4(FP), AX // ERROR "invalid MOVW of y\+4\(FP\); uint32 is 4-byte value"
+	MOVL	x+0(FP), AX
+	MOVL	y+4(FP), AX
+	MOVQ	x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); int32 is 4-byte value"
+	MOVQ	y+4(FP), AX // ERROR "invalid MOVQ of y\+4\(FP\); uint32 is 4-byte value"
+	MOVL	x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
+	MOVL	y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
+	TESTB	x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int32 is 4-byte value"
+	TESTB	y+4(FP), BX // ERROR "invalid TESTB of y\+4\(FP\); uint32 is 4-byte value"
+	TESTW	x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int32 is 4-byte value"
+	TESTW	y+4(FP), AX // ERROR "invalid TESTW of y\+4\(FP\); uint32 is 4-byte value"
+	TESTL	x+0(FP), AX
+	TESTL	y+4(FP), AX
+	TESTQ	x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); int32 is 4-byte value"
+	TESTQ	y+4(FP), AX // ERROR "invalid TESTQ of y\+4\(FP\); uint32 is 4-byte value"
+	TESTL	x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
+	TESTL	y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
+	RET
+
+TEXT ·arg8(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16"
+	MOVB	x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int64 is 8-byte value"
+	MOVB	y+8(FP), BX // ERROR "invalid MOVB of y\+8\(FP\); uint64 is 8-byte value"
+	MOVW	x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int64 is 8-byte value"
+	MOVW	y+8(FP), AX // ERROR "invalid MOVW of y\+8\(FP\); uint64 is 8-byte value"
+	MOVL	x+0(FP), AX // ERROR "invalid MOVL of x\+0\(FP\); int64 is 8-byte value containing x_lo\+0\(FP\) and x_hi\+4\(FP\)"
+	MOVL	x_lo+0(FP), AX
+	MOVL	x_hi+4(FP), AX
+	MOVL	y+8(FP), AX // ERROR "invalid MOVL of y\+8\(FP\); uint64 is 8-byte value containing y_lo\+8\(FP\) and y_hi\+12\(FP\)"
+	MOVL	y_lo+8(FP), AX
+	MOVL	y_hi+12(FP), AX
+	MOVQ	x+0(FP), AX
+	MOVQ	y+8(FP), AX
+	MOVQ	x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
+	MOVQ	y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
+	TESTB	x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int64 is 8-byte value"
+	TESTB	y+8(FP), BX // ERROR "invalid TESTB of y\+8\(FP\); uint64 is 8-byte value"
+	TESTW	x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int64 is 8-byte value"
+	TESTW	y+8(FP), AX // ERROR "invalid TESTW of y\+8\(FP\); uint64 is 8-byte value"
+	TESTL	x+0(FP), AX // ERROR "invalid TESTL of x\+0\(FP\); int64 is 8-byte value containing x_lo\+0\(FP\) and x_hi\+4\(FP\)"
+	TESTL	y+8(FP), AX // ERROR "invalid TESTL of y\+8\(FP\); uint64 is 8-byte value containing y_lo\+8\(FP\) and y_hi\+12\(FP\)"
+	TESTQ	x+0(FP), AX
+	TESTQ	y+8(FP), AX
+	TESTQ	x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
+	TESTQ	y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
+	RET
+
+TEXT ·argint(SB),0,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-8"
+	MOVB	x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int is 4-byte value"
+	MOVB	y+4(FP), BX // ERROR "invalid MOVB of y\+4\(FP\); uint is 4-byte value"
+	MOVW	x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int is 4-byte value"
+	MOVW	y+4(FP), AX // ERROR "invalid MOVW of y\+4\(FP\); uint is 4-byte value"
+	MOVL	x+0(FP), AX
+	MOVL	y+4(FP), AX
+	MOVQ	x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); int is 4-byte value"
+	MOVQ	y+4(FP), AX // ERROR "invalid MOVQ of y\+4\(FP\); uint is 4-byte value"
+	MOVQ	x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
+	MOVQ	y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
+	TESTB	x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); int is 4-byte value"
+	TESTB	y+4(FP), BX // ERROR "invalid TESTB of y\+4\(FP\); uint is 4-byte value"
+	TESTW	x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); int is 4-byte value"
+	TESTW	y+4(FP), AX // ERROR "invalid TESTW of y\+4\(FP\); uint is 4-byte value"
+	TESTL	x+0(FP), AX
+	TESTL	y+4(FP), AX
+	TESTQ	x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); int is 4-byte value"
+	TESTQ	y+4(FP), AX // ERROR "invalid TESTQ of y\+4\(FP\); uint is 4-byte value"
+	TESTQ	x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
+	TESTQ	y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
+	RET
+
+TEXT ·argptr(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-20"
+	MOVB	x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); \*byte is 4-byte value"
+	MOVB	y+4(FP), BX // ERROR "invalid MOVB of y\+4\(FP\); \*byte is 4-byte value"
+	MOVW	x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); \*byte is 4-byte value"
+	MOVW	y+4(FP), AX // ERROR "invalid MOVW of y\+4\(FP\); \*byte is 4-byte value"
+	MOVL	x+0(FP), AX
+	MOVL	y+4(FP), AX
+	MOVQ	x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); \*byte is 4-byte value"
+	MOVQ	y+4(FP), AX // ERROR "invalid MOVQ of y\+4\(FP\); \*byte is 4-byte value"
+	MOVQ	x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
+	MOVQ	y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
+	TESTB	x+0(FP), AX // ERROR "invalid TESTB of x\+0\(FP\); \*byte is 4-byte value"
+	TESTB	y+4(FP), BX // ERROR "invalid TESTB of y\+4\(FP\); \*byte is 4-byte value"
+	TESTW	x+0(FP), AX // ERROR "invalid TESTW of x\+0\(FP\); \*byte is 4-byte value"
+	TESTW	y+4(FP), AX // ERROR "invalid TESTW of y\+4\(FP\); \*byte is 4-byte value"
+	TESTL	x+0(FP), AX
+	TESTL	y+4(FP), AX
+	TESTQ	x+0(FP), AX // ERROR "invalid TESTQ of x\+0\(FP\); \*byte is 4-byte value"
+	TESTQ	y+4(FP), AX // ERROR "invalid TESTQ of y\+4\(FP\); \*byte is 4-byte value"
+	TESTQ	x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
+	TESTQ	y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
+	MOVW	c+8(FP), AX // ERROR "invalid MOVW of c\+8\(FP\); chan int is 4-byte value"
+	MOVW	m+12(FP), AX // ERROR "invalid MOVW of m\+12\(FP\); map\[int\]int is 4-byte value"
+	MOVW	f+16(FP), AX // ERROR "invalid MOVW of f\+16\(FP\); func\(\) is 4-byte value"
+	RET
+
+TEXT ·argstring(SB),0,$16 // ERROR "wrong argument size 0; expected \$\.\.\.-16"
+	MOVW	x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); string base is 4-byte value"
+	MOVL	x+0(FP), AX
+	MOVQ	x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); string base is 4-byte value"
+	MOVW	x_base+0(FP), AX // ERROR "invalid MOVW of x_base\+0\(FP\); string base is 4-byte value"
+	MOVL	x_base+0(FP), AX
+	MOVQ	x_base+0(FP), AX // ERROR "invalid MOVQ of x_base\+0\(FP\); string base is 4-byte value"
+	MOVW	x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
+	MOVL	x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
+	MOVQ	x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
+	MOVW	x_len+4(FP), AX // ERROR "invalid MOVW of x_len\+4\(FP\); string len is 4-byte value"
+	MOVL	x_len+4(FP), AX
+	MOVQ	x_len+4(FP), AX // ERROR "invalid MOVQ of x_len\+4\(FP\); string len is 4-byte value"
+	MOVQ	y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+8\(FP\)"
+	MOVQ	y_len+4(FP), AX // ERROR "invalid offset y_len\+4\(FP\); expected y_len\+12\(FP\)"
+	RET
+
+TEXT ·argslice(SB),0,$24 // ERROR "wrong argument size 0; expected \$\.\.\.-24"
+	MOVW	x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); slice base is 4-byte value"
+	MOVL	x+0(FP), AX
+	MOVQ	x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); slice base is 4-byte value"
+	MOVW	x_base+0(FP), AX // ERROR "invalid MOVW of x_base\+0\(FP\); slice base is 4-byte value"
+	MOVL	x_base+0(FP), AX
+	MOVQ	x_base+0(FP), AX // ERROR "invalid MOVQ of x_base\+0\(FP\); slice base is 4-byte value"
+	MOVW	x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
+	MOVL	x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
+	MOVQ	x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
+	MOVW	x_len+4(FP), AX // ERROR "invalid MOVW of x_len\+4\(FP\); slice len is 4-byte value"
+	MOVL	x_len+4(FP), AX
+	MOVQ	x_len+4(FP), AX // ERROR "invalid MOVQ of x_len\+4\(FP\); slice len is 4-byte value"
+	MOVW	x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+8\(FP\)"
+	MOVL	x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+8\(FP\)"
+	MOVQ	x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+8\(FP\)"
+	MOVW	x_cap+8(FP), AX // ERROR "invalid MOVW of x_cap\+8\(FP\); slice cap is 4-byte value"
+	MOVL	x_cap+8(FP), AX
+	MOVQ	x_cap+8(FP), AX // ERROR "invalid MOVQ of x_cap\+8\(FP\); slice cap is 4-byte value"
+	MOVQ	y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+12\(FP\)"
+	MOVQ	y_len+4(FP), AX // ERROR "invalid offset y_len\+4\(FP\); expected y_len\+16\(FP\)"
+	MOVQ	y_cap+8(FP), AX // ERROR "invalid offset y_cap\+8\(FP\); expected y_cap\+20\(FP\)"
+	RET
+
+TEXT ·argiface(SB),0,$0-16
+	MOVW	x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); interface type is 4-byte value"
+	MOVL	x+0(FP), AX
+	MOVQ	x+0(FP), AX // ERROR "invalid MOVQ of x\+0\(FP\); interface type is 4-byte value"
+	MOVW	x_type+0(FP), AX // ERROR "invalid MOVW of x_type\+0\(FP\); interface type is 4-byte value"
+	MOVL	x_type+0(FP), AX
+	MOVQ	x_type+0(FP), AX // ERROR "invalid MOVQ of x_type\+0\(FP\); interface type is 4-byte value"
+	MOVQ	x_itable+0(FP), AX // ERROR "unknown variable x_itable; offset 0 is x_type\+0\(FP\)"
+	MOVQ	x_itable+1(FP), AX // ERROR "unknown variable x_itable; offset 1 is x_type\+0\(FP\)"
+	MOVW	x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)"
+	MOVL	x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)"
+	MOVQ	x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)"
+	MOVW	x_data+4(FP), AX // ERROR "invalid MOVW of x_data\+4\(FP\); interface data is 4-byte value"
+	MOVL	x_data+4(FP), AX
+	MOVQ	x_data+4(FP), AX // ERROR "invalid MOVQ of x_data\+4\(FP\); interface data is 4-byte value"
+	MOVW	y+8(FP), AX // ERROR "invalid MOVW of y\+8\(FP\); interface itable is 4-byte value"
+	MOVL	y+8(FP), AX
+	MOVQ	y+8(FP), AX // ERROR "invalid MOVQ of y\+8\(FP\); interface itable is 4-byte value"
+	MOVW	y_itable+8(FP), AX // ERROR "invalid MOVW of y_itable\+8\(FP\); interface itable is 4-byte value"
+	MOVL	y_itable+8(FP), AX
+	MOVQ	y_itable+8(FP), AX // ERROR "invalid MOVQ of y_itable\+8\(FP\); interface itable is 4-byte value"
+	MOVQ	y_type+8(FP), AX // ERROR "unknown variable y_type; offset 8 is y_itable\+8\(FP\)"
+	MOVW	y_data+8(FP), AX // ERROR "invalid offset y_data\+8\(FP\); expected y_data\+12\(FP\)"
+	MOVL	y_data+8(FP), AX // ERROR "invalid offset y_data\+8\(FP\); expected y_data\+12\(FP\)"
+	MOVQ	y_data+8(FP), AX // ERROR "invalid offset y_data\+8\(FP\); expected y_data\+12\(FP\)"
+	MOVW	y_data+12(FP), AX // ERROR "invalid MOVW of y_data\+12\(FP\); interface data is 4-byte value"
+	MOVL	y_data+12(FP), AX
+	MOVQ	y_data+12(FP), AX // ERROR "invalid MOVQ of y_data\+12\(FP\); interface data is 4-byte value"
+	RET
+
+TEXT ·returnint(SB),0,$0-4
+	MOVB	AX, ret+0(FP) // ERROR "invalid MOVB of ret\+0\(FP\); int is 4-byte value"
+	MOVW	AX, ret+0(FP) // ERROR "invalid MOVW of ret\+0\(FP\); int is 4-byte value"
+	MOVL	AX, ret+0(FP)
+	MOVQ	AX, ret+0(FP) // ERROR "invalid MOVQ of ret\+0\(FP\); int is 4-byte value"
+	MOVQ	AX, ret+1(FP) // ERROR "invalid offset ret\+1\(FP\); expected ret\+0\(FP\)"
+	MOVQ	AX, r+0(FP) // ERROR "unknown variable r; offset 0 is ret\+0\(FP\)"
+	RET
+
+TEXT ·returnbyte(SB),0,$0-5
+	MOVL	x+0(FP), AX
+	MOVB	AX, ret+4(FP)
+	MOVW	AX, ret+4(FP) // ERROR "invalid MOVW of ret\+4\(FP\); byte is 1-byte value"
+	MOVL	AX, ret+4(FP) // ERROR "invalid MOVL of ret\+4\(FP\); byte is 1-byte value"
+	MOVQ	AX, ret+4(FP) // ERROR "invalid MOVQ of ret\+4\(FP\); byte is 1-byte value"
+	MOVB	AX, ret+3(FP) // ERROR "invalid offset ret\+3\(FP\); expected ret\+4\(FP\)"
+	RET
+
+TEXT ·returnnamed(SB),0,$0-21
+	MOVB	x+0(FP), AX
+	MOVL	AX, r1+4(FP)
+	MOVW	AX, r2+8(FP)
+	MOVL	AX, r3+12(FP)
+	MOVL	AX, r3_base+12(FP)
+	MOVL	AX, r3_len+16(FP)
+	MOVB	AX, r4+20(FP)
+	MOVQ	AX, r1+4(FP) // ERROR "invalid MOVQ of r1\+4\(FP\); int is 4-byte value"
+	RET
+
+TEXT ·returnintmissing(SB),0,$0-4
+	RET // ERROR "RET without writing to 4-byte ret\+0\(FP\)"
diff --git a/src/cmd/vet/testdata/asm3.s b/src/cmd/vet/testdata/asm3.s
new file mode 100644
index 0000000..3d69356
--- /dev/null
+++ b/src/cmd/vet/testdata/asm3.s
@@ -0,0 +1,178 @@
+// 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 arm
+// +build vet_test
+
+TEXT ·arg1(SB),0,$0-2
+	MOVB	x+0(FP), AX
+	MOVB	y+1(FP), BX
+	MOVH	x+0(FP), AX // ERROR "\[arm\] arg1: invalid MOVH of x\+0\(FP\); int8 is 1-byte value"
+	MOVH	y+1(FP), AX // ERROR "invalid MOVH of y\+1\(FP\); uint8 is 1-byte value"
+	MOVW	x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int8 is 1-byte value"
+	MOVW	y+1(FP), AX // ERROR "invalid MOVW of y\+1\(FP\); uint8 is 1-byte value"
+	MOVB	x+1(FP), AX // ERROR "invalid offset x\+1\(FP\); expected x\+0\(FP\)"
+	MOVB	y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+1\(FP\)"
+	MOVB	8(R13), AX // ERROR "8\(R13\) should be x\+0\(FP\)"
+	MOVB	9(R13), AX // ERROR "9\(R13\) should be y\+1\(FP\)"
+	MOVB	10(R13), AX // ERROR "use of 10\(R13\) points beyond argument frame"
+	RET
+
+TEXT ·arg2(SB),0,$0-4
+	MOVB	x+0(FP), AX // ERROR "arg2: invalid MOVB of x\+0\(FP\); int16 is 2-byte value"
+	MOVB	y+2(FP), AX // ERROR "invalid MOVB of y\+2\(FP\); uint16 is 2-byte value"
+	MOVH	x+0(FP), AX
+	MOVH	y+2(FP), BX
+	MOVW	x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int16 is 2-byte value"
+	MOVW	y+2(FP), AX // ERROR "invalid MOVW of y\+2\(FP\); uint16 is 2-byte value"
+	MOVH	x+2(FP), AX // ERROR "invalid offset x\+2\(FP\); expected x\+0\(FP\)"
+	MOVH	y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+2\(FP\)"
+	RET
+
+TEXT ·arg4(SB),0,$0-2 // ERROR "arg4: wrong argument size 2; expected \$\.\.\.-8"
+	MOVB	x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int32 is 4-byte value"
+	MOVB	y+4(FP), BX // ERROR "invalid MOVB of y\+4\(FP\); uint32 is 4-byte value"
+	MOVH	x+0(FP), AX // ERROR "invalid MOVH of x\+0\(FP\); int32 is 4-byte value"
+	MOVH	y+4(FP), AX // ERROR "invalid MOVH of y\+4\(FP\); uint32 is 4-byte value"
+	MOVW	x+0(FP), AX
+	MOVW	y+4(FP), AX
+	MOVW	x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
+	MOVW	y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
+	RET
+
+TEXT ·arg8(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-16"
+	MOVB	x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int64 is 8-byte value"
+	MOVB	y+8(FP), BX // ERROR "invalid MOVB of y\+8\(FP\); uint64 is 8-byte value"
+	MOVH	x+0(FP), AX // ERROR "invalid MOVH of x\+0\(FP\); int64 is 8-byte value"
+	MOVH	y+8(FP), AX // ERROR "invalid MOVH of y\+8\(FP\); uint64 is 8-byte value"
+	MOVW	x+0(FP), AX // ERROR "invalid MOVW of x\+0\(FP\); int64 is 8-byte value containing x_lo\+0\(FP\) and x_hi\+4\(FP\)"
+	MOVW	x_lo+0(FP), AX
+	MOVW	x_hi+4(FP), AX
+	MOVW	y+8(FP), AX // ERROR "invalid MOVW of y\+8\(FP\); uint64 is 8-byte value containing y_lo\+8\(FP\) and y_hi\+12\(FP\)"
+	MOVW	y_lo+8(FP), AX
+	MOVW	y_hi+12(FP), AX
+	MOVQ	x+0(FP), AX
+	MOVQ	y+8(FP), AX
+	MOVQ	x+8(FP), AX // ERROR "invalid offset x\+8\(FP\); expected x\+0\(FP\)"
+	MOVQ	y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+8\(FP\)"
+	RET
+
+TEXT ·argint(SB),0,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-8"
+	MOVB	x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); int is 4-byte value"
+	MOVB	y+4(FP), BX // ERROR "invalid MOVB of y\+4\(FP\); uint is 4-byte value"
+	MOVH	x+0(FP), AX // ERROR "invalid MOVH of x\+0\(FP\); int is 4-byte value"
+	MOVH	y+4(FP), AX // ERROR "invalid MOVH of y\+4\(FP\); uint is 4-byte value"
+	MOVW	x+0(FP), AX
+	MOVW	y+4(FP), AX
+	MOVQ	x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
+	MOVQ	y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
+	RET
+
+TEXT ·argptr(SB),7,$0-2 // ERROR "wrong argument size 2; expected \$\.\.\.-20"
+	MOVB	x+0(FP), AX // ERROR "invalid MOVB of x\+0\(FP\); \*byte is 4-byte value"
+	MOVB	y+4(FP), BX // ERROR "invalid MOVB of y\+4\(FP\); \*byte is 4-byte value"
+	MOVH	x+0(FP), AX // ERROR "invalid MOVH of x\+0\(FP\); \*byte is 4-byte value"
+	MOVH	y+4(FP), AX // ERROR "invalid MOVH of y\+4\(FP\); \*byte is 4-byte value"
+	MOVW	x+0(FP), AX
+	MOVW	y+4(FP), AX
+	MOVQ	x+4(FP), AX // ERROR "invalid offset x\+4\(FP\); expected x\+0\(FP\)"
+	MOVQ	y+2(FP), AX // ERROR "invalid offset y\+2\(FP\); expected y\+4\(FP\)"
+	MOVH	c+8(FP), AX // ERROR "invalid MOVH of c\+8\(FP\); chan int is 4-byte value"
+	MOVH	m+12(FP), AX // ERROR "invalid MOVH of m\+12\(FP\); map\[int\]int is 4-byte value"
+	MOVH	f+16(FP), AX // ERROR "invalid MOVH of f\+16\(FP\); func\(\) is 4-byte value"
+	RET
+
+TEXT ·argstring(SB),0,$16 // ERROR "wrong argument size 0; expected \$\.\.\.-16"
+	MOVH	x+0(FP), AX // ERROR "invalid MOVH of x\+0\(FP\); string base is 4-byte value"
+	MOVW	x+0(FP), AX
+	MOVH	x_base+0(FP), AX // ERROR "invalid MOVH of x_base\+0\(FP\); string base is 4-byte value"
+	MOVW	x_base+0(FP), AX
+	MOVH	x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
+	MOVW	x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
+	MOVQ	x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
+	MOVH	x_len+4(FP), AX // ERROR "invalid MOVH of x_len\+4\(FP\); string len is 4-byte value"
+	MOVW	x_len+4(FP), AX
+	MOVQ	y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+8\(FP\)"
+	MOVQ	y_len+4(FP), AX // ERROR "invalid offset y_len\+4\(FP\); expected y_len\+12\(FP\)"
+	RET
+
+TEXT ·argslice(SB),0,$24 // ERROR "wrong argument size 0; expected \$\.\.\.-24"
+	MOVH	x+0(FP), AX // ERROR "invalid MOVH of x\+0\(FP\); slice base is 4-byte value"
+	MOVW	x+0(FP), AX
+	MOVH	x_base+0(FP), AX // ERROR "invalid MOVH of x_base\+0\(FP\); slice base is 4-byte value"
+	MOVW	x_base+0(FP), AX
+	MOVH	x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
+	MOVW	x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
+	MOVQ	x_len+0(FP), AX // ERROR "invalid offset x_len\+0\(FP\); expected x_len\+4\(FP\)"
+	MOVH	x_len+4(FP), AX // ERROR "invalid MOVH of x_len\+4\(FP\); slice len is 4-byte value"
+	MOVW	x_len+4(FP), AX
+	MOVH	x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+8\(FP\)"
+	MOVW	x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+8\(FP\)"
+	MOVQ	x_cap+0(FP), AX // ERROR "invalid offset x_cap\+0\(FP\); expected x_cap\+8\(FP\)"
+	MOVH	x_cap+8(FP), AX // ERROR "invalid MOVH of x_cap\+8\(FP\); slice cap is 4-byte value"
+	MOVW	x_cap+8(FP), AX
+	MOVQ	y+0(FP), AX // ERROR "invalid offset y\+0\(FP\); expected y\+12\(FP\)"
+	MOVQ	y_len+4(FP), AX // ERROR "invalid offset y_len\+4\(FP\); expected y_len\+16\(FP\)"
+	MOVQ	y_cap+8(FP), AX // ERROR "invalid offset y_cap\+8\(FP\); expected y_cap\+20\(FP\)"
+	RET
+
+TEXT ·argiface(SB),0,$0-16
+	MOVH	x+0(FP), AX // ERROR "invalid MOVH of x\+0\(FP\); interface type is 4-byte value"
+	MOVW	x+0(FP), AX
+	MOVH	x_type+0(FP), AX // ERROR "invalid MOVH of x_type\+0\(FP\); interface type is 4-byte value"
+	MOVW	x_type+0(FP), AX
+	MOVQ	x_itable+0(FP), AX // ERROR "unknown variable x_itable; offset 0 is x_type\+0\(FP\)"
+	MOVQ	x_itable+1(FP), AX // ERROR "unknown variable x_itable; offset 1 is x_type\+0\(FP\)"
+	MOVH	x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)"
+	MOVW	x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)"
+	MOVQ	x_data+0(FP), AX // ERROR "invalid offset x_data\+0\(FP\); expected x_data\+4\(FP\)"
+	MOVH	x_data+4(FP), AX // ERROR "invalid MOVH of x_data\+4\(FP\); interface data is 4-byte value"
+	MOVW	x_data+4(FP), AX
+	MOVH	y+8(FP), AX // ERROR "invalid MOVH of y\+8\(FP\); interface itable is 4-byte value"
+	MOVW	y+8(FP), AX
+	MOVH	y_itable+8(FP), AX // ERROR "invalid MOVH of y_itable\+8\(FP\); interface itable is 4-byte value"
+	MOVW	y_itable+8(FP), AX
+	MOVQ	y_type+8(FP), AX // ERROR "unknown variable y_type; offset 8 is y_itable\+8\(FP\)"
+	MOVH	y_data+8(FP), AX // ERROR "invalid offset y_data\+8\(FP\); expected y_data\+12\(FP\)"
+	MOVW	y_data+8(FP), AX // ERROR "invalid offset y_data\+8\(FP\); expected y_data\+12\(FP\)"
+	MOVQ	y_data+8(FP), AX // ERROR "invalid offset y_data\+8\(FP\); expected y_data\+12\(FP\)"
+	MOVH	y_data+12(FP), AX // ERROR "invalid MOVH of y_data\+12\(FP\); interface data is 4-byte value"
+	MOVW	y_data+12(FP), AX
+	RET
+
+TEXT ·returnint(SB),0,$0-4
+	MOVB	AX, ret+0(FP) // ERROR "invalid MOVB of ret\+0\(FP\); int is 4-byte value"
+	MOVH	AX, ret+0(FP) // ERROR "invalid MOVH of ret\+0\(FP\); int is 4-byte value"
+	MOVW	AX, ret+0(FP)
+	MOVQ	AX, ret+1(FP) // ERROR "invalid offset ret\+1\(FP\); expected ret\+0\(FP\)"
+	MOVQ	AX, r+0(FP) // ERROR "unknown variable r; offset 0 is ret\+0\(FP\)"
+	RET
+
+TEXT ·returnbyte(SB),0,$0-5
+	MOVW	x+0(FP), AX
+	MOVB	AX, ret+4(FP)
+	MOVH	AX, ret+4(FP) // ERROR "invalid MOVH of ret\+4\(FP\); byte is 1-byte value"
+	MOVW	AX, ret+4(FP) // ERROR "invalid MOVW of ret\+4\(FP\); byte is 1-byte value"
+	MOVB	AX, ret+3(FP) // ERROR "invalid offset ret\+3\(FP\); expected ret\+4\(FP\)"
+	RET
+
+TEXT ·returnnamed(SB),0,$0-21
+	MOVB	x+0(FP), AX
+	MOVW	AX, r1+4(FP)
+	MOVH	AX, r2+8(FP)
+	MOVW	AX, r3+12(FP)
+	MOVW	AX, r3_base+12(FP)
+	MOVW	AX, r3_len+16(FP)
+	MOVB	AX, r4+20(FP)
+	MOVB	AX, r1+4(FP) // ERROR "invalid MOVB of r1\+4\(FP\); int is 4-byte value"
+	RET
+
+TEXT ·returnintmissing(SB),0,$0-4
+	RET // ERROR "RET without writing to 4-byte ret\+0\(FP\)"
+
+TEXT ·leaf(SB),0,$-4-12
+	MOVW	x+0(FP), AX
+	MOVW	y+4(FP), AX
+	MOVW	AX, ret+8(FP)
+	RET
diff --git a/src/cmd/vet/testdata/asm4.s b/src/cmd/vet/testdata/asm4.s
new file mode 100644
index 0000000..044b050
--- /dev/null
+++ b/src/cmd/vet/testdata/asm4.s
@@ -0,0 +1,26 @@
+// 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 amd64
+// +build vet_test
+
+// Test cases for symbolic NOSPLIT etc. on TEXT symbols.
+
+TEXT ·noprof(SB),NOPROF,$0-8
+	RET
+
+TEXT ·dupok(SB),DUPOK,$0-8
+	RET
+
+TEXT ·nosplit(SB),NOSPLIT,$0
+	RET
+
+TEXT ·rodata(SB),RODATA,$0-8
+	RET
+
+TEXT ·noptr(SB),NOPTR|NOSPLIT,$0
+	RET
+
+TEXT ·wrapper(SB),WRAPPER,$0-8
+	RET
diff --git a/src/cmd/vet/testdata/assign.go b/src/cmd/vet/testdata/assign.go
new file mode 100644
index 0000000..32ba868
--- /dev/null
+++ b/src/cmd/vet/testdata/assign.go
@@ -0,0 +1,18 @@
+// 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.
+
+// This file contains tests for the useless-assignment checker.
+
+package testdata
+
+type ST struct {
+	x int
+}
+
+func (s *ST) SetX(x int) {
+	// Accidental self-assignment; it should be "s.x = x"
+	x = x // ERROR "self-assignment of x to x"
+	// Another mistake
+	s.x = s.x // ERROR "self-assignment of s.x to s.x"
+}
diff --git a/src/cmd/vet/testdata/atomic.go b/src/cmd/vet/testdata/atomic.go
new file mode 100644
index 0000000..1ba261d
--- /dev/null
+++ b/src/cmd/vet/testdata/atomic.go
@@ -0,0 +1,43 @@
+// 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.
+
+// This file contains tests for the atomic checker.
+
+package testdata
+
+import (
+	"sync/atomic"
+)
+
+type Counter uint64
+
+func AtomicTests() {
+	x := uint64(1)
+	x = atomic.AddUint64(&x, 1)        // ERROR "direct assignment to atomic value"
+	_, x = 10, atomic.AddUint64(&x, 1) // ERROR "direct assignment to atomic value"
+	x, _ = atomic.AddUint64(&x, 1), 10 // ERROR "direct assignment to atomic value"
+
+	y := &x
+	*y = atomic.AddUint64(y, 1) // ERROR "direct assignment to atomic value"
+
+	var su struct{ Counter uint64 }
+	su.Counter = atomic.AddUint64(&su.Counter, 1) // ERROR "direct assignment to atomic value"
+	z1 := atomic.AddUint64(&su.Counter, 1)
+	_ = z1 // Avoid err "z declared and not used"
+
+	var sp struct{ Counter *uint64 }
+	*sp.Counter = atomic.AddUint64(sp.Counter, 1) // ERROR "direct assignment to atomic value"
+	z2 := atomic.AddUint64(sp.Counter, 1)
+	_ = z2 // Avoid err "z declared and not used"
+
+	au := []uint64{10, 20}
+	au[0] = atomic.AddUint64(&au[0], 1) // ERROR "direct assignment to atomic value"
+	au[1] = atomic.AddUint64(&au[0], 1)
+
+	ap := []*uint64{&au[0], &au[1]}
+	*ap[0] = atomic.AddUint64(ap[0], 1) // ERROR "direct assignment to atomic value"
+	*ap[1] = atomic.AddUint64(ap[0], 1)
+
+	x = atomic.AddUint64() // Used to make vet crash; now silently ignored.
+}
diff --git a/src/cmd/vet/testdata/bool.go b/src/cmd/vet/testdata/bool.go
new file mode 100644
index 0000000..af6cc01
--- /dev/null
+++ b/src/cmd/vet/testdata/bool.go
@@ -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.
+
+// This file contains tests for the bool checker.
+
+package testdata
+
+import "io"
+
+func RatherStupidConditions() {
+	var f, g func() int
+	if f() == 0 || f() == 0 { // OK f might have side effects
+	}
+	if v, w := f(), g(); v == w || v == w { // ERROR "redundant or: v == w || v == w"
+	}
+	_ = f == nil || f == nil // ERROR "redundant or: f == nil || f == nil"
+
+	_ = i == byte(1) || i == byte(1) // TODO conversions are treated as if they may have side effects
+
+	var c chan int
+	_ = 0 == <-c || 0 == <-c                                  // OK subsequent receives may yield different values
+	for i, j := <-c, <-c; i == j || i == j; i, j = <-c, <-c { // ERROR "redundant or: i == j || i == j"
+	}
+
+	var i, j, k int
+	_ = i+1 == 1 || i+1 == 1         // ERROR "redundant or: i\+1 == 1 || i\+1 == 1"
+	_ = i == 1 || j+1 == i || i == 1 // ERROR "redundant or: i == 1 || i == 1"
+
+	_ = i == 1 || i == 1 || f() == 1 // ERROR "redundant or: i == 1 || i == 1"
+	_ = i == 1 || f() == 1 || i == 1 // OK f may alter i as a side effect
+	_ = f() == 1 || i == 1 || i == 1 // ERROR "redundant or: i == 1 || i == 1"
+
+	// Test partition edge cases
+	_ = f() == 1 || i == 1 || i == 1 || j == 1 // ERROR "redundant or: i == 1 || i == 1"
+	_ = f() == 1 || j == 1 || i == 1 || i == 1 // ERROR "redundant or: i == 1 || i == 1"
+	_ = i == 1 || f() == 1 || i == 1 || i == 1 // ERROR "redundant or: i == 1 || i == 1"
+	_ = i == 1 || i == 1 || f() == 1 || i == 1 // ERROR "redundant or: i == 1 || i == 1"
+	_ = i == 1 || i == 1 || j == 1 || f() == 1 // ERROR "redundant or: i == 1 || i == 1"
+	_ = j == 1 || i == 1 || i == 1 || f() == 1 // ERROR "redundant or: i == 1 || i == 1"
+	_ = i == 1 || f() == 1 || f() == 1 || i == 1
+
+	_ = i == 1 || (i == 1 || i == 2)             // ERROR "redundant or: i == 1 || i == 1"
+	_ = i == 1 || (f() == 1 || i == 1)           // OK f may alter i as a side effect
+	_ = i == 1 || (i == 1 || f() == 1)           // ERROR "redundant or: i == 1 || i == 1"
+	_ = i == 1 || (i == 2 || (i == 1 || i == 3)) // ERROR "redundant or: i == 1 || i == 1"
+
+	var a, b bool
+	_ = i == 1 || (a || (i == 1 || b)) // ERROR "redundant or: i == 1 || i == 1"
+
+	// Check that all redundant ors are flagged
+	_ = j == 0 ||
+		i == 1 ||
+		f() == 1 ||
+		j == 0 || // ERROR "redundant or: j == 0 || j == 0"
+		i == 1 || // ERROR "redundant or: i == 1 || i == 1"
+		i == 1 || // ERROR "redundant or: i == 1 || i == 1"
+		i == 1 ||
+		j == 0 ||
+		k == 0
+
+	_ = i == 1*2*3 || i == 1*2*3 // ERROR "redundant or: i == 1\*2\*3 || i == 1\*2\*3"
+
+	// These test that redundant, suspect expressions do not trigger multiple errors.
+	_ = i != 0 || i != 0 // ERROR "redundant or: i != 0 || i != 0"
+	_ = i == 0 && i == 0 // ERROR "redundant and: i == 0 && i == 0"
+
+	// and is dual to or; check the basics and
+	// let the or tests pull the rest of the weight.
+	_ = 0 != <-c && 0 != <-c         // OK subsequent receives may yield different values
+	_ = f() != 0 && f() != 0         // OK f might have side effects
+	_ = f != nil && f != nil         // ERROR "redundant and: f != nil && f != nil"
+	_ = i != 1 && i != 1 && f() != 1 // ERROR "redundant and: i != 1 && i != 1"
+	_ = i != 1 && f() != 1 && i != 1 // OK f may alter i as a side effect
+	_ = f() != 1 && i != 1 && i != 1 // ERROR "redundant and: i != 1 && i != 1"
+}
+
+func RoyallySuspectConditions() {
+	var i, j int
+
+	_ = i == 0 || i == 1 // OK
+	_ = i != 0 || i != 1 // ERROR "suspect or: i != 0 || i != 1"
+	_ = i != 0 || 1 != i // ERROR "suspect or: i != 0 || 1 != i"
+	_ = 0 != i || 1 != i // ERROR "suspect or: 0 != i || 1 != i"
+	_ = 0 != i || i != 1 // ERROR "suspect or: 0 != i || i != 1"
+
+	_ = (0 != i) || i != 1 // ERROR "suspect or: 0 != i || i != 1"
+
+	_ = i+3 != 7 || j+5 == 0 || i+3 != 9 // ERROR "suspect or: i\+3 != 7 || i\+3 != 9"
+
+	_ = i != 0 || j == 0 || i != 1 // ERROR "suspect or: i != 0 || i != 1"
+
+	_ = i != 0 || i != 1<<4 // ERROR "suspect or: i != 0 || i != 1<<4"
+
+	_ = i != 0 || j != 0
+	_ = 0 != i || 0 != j
+
+	var s string
+	_ = s != "one" || s != "the other" // ERROR "suspect or: s != .one. || s != .the other."
+
+	_ = "et" != "alii" || "et" != "cetera"         // ERROR "suspect or: .et. != .alii. || .et. != .cetera."
+	_ = "me gustas" != "tu" || "le gustas" != "tu" // OK we could catch this case, but it's not worth the code
+
+	var err error
+	_ = err != nil || err != io.EOF // TODO catch this case?
+
+	// Sanity check and.
+	_ = i != 0 && i != 1 // OK
+	_ = i == 0 && i == 1 // ERROR "suspect and: i == 0 && i == 1"
+	_ = i == 0 && 1 == i // ERROR "suspect and: i == 0 && 1 == i"
+	_ = 0 == i && 1 == i // ERROR "suspect and: 0 == i && 1 == i"
+	_ = 0 == i && i == 1 // ERROR "suspect and: 0 == i && i == 1"
+}
diff --git a/src/cmd/vet/testdata/buildtag.go b/src/cmd/vet/testdata/buildtag.go
new file mode 100644
index 0000000..eb36fd3
--- /dev/null
+++ b/src/cmd/vet/testdata/buildtag.go
@@ -0,0 +1,14 @@
+// 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.
+
+// This file contains tests for the buildtag checker.
+
+// +builder // ERROR "possible malformed \+build comment"
+// +build !ignore
+
+package testdata
+
+// +build toolate // ERROR "build comment must appear before package clause and be followed by a blank line"
+
+var _ = 3
diff --git a/src/cmd/vet/testdata/buildtag_bad.go b/src/cmd/vet/testdata/buildtag_bad.go
new file mode 100644
index 0000000..fbe10cf
--- /dev/null
+++ b/src/cmd/vet/testdata/buildtag_bad.go
@@ -0,0 +1,15 @@
+// This file contains misplaced or malformed build constraints.
+// The Go tool will skip it, because the constraints are invalid.
+// It serves only to test the tag checker during make test.
+
+// Mention +build // ERROR "possible malformed \+build comment"
+
+// +build !!bang // ERROR "invalid double negative in build constraint"
+// +build @#$ // ERROR "invalid non-alphanumeric build constraint"
+
+// +build toolate // ERROR "build comment must appear before package clause and be followed by a blank line"
+package bad
+
+// This is package 'bad' rather than 'main' so the erroneous build
+// tag doesn't end up looking like a package doc for the vet command
+// when examined by godoc.
diff --git a/src/cmd/vet/testdata/composite.go b/src/cmd/vet/testdata/composite.go
new file mode 100644
index 0000000..69e7d7c
--- /dev/null
+++ b/src/cmd/vet/testdata/composite.go
@@ -0,0 +1,63 @@
+// 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.
+
+// This file contains tests for the untagged struct literal checker.
+
+// This file contains the test for untagged struct literals.
+
+package testdata
+
+import (
+	"flag"
+	"go/scanner"
+)
+
+var Okay1 = []string{
+	"Name",
+	"Usage",
+	"DefValue",
+}
+
+var Okay2 = map[string]bool{
+	"Name":     true,
+	"Usage":    true,
+	"DefValue": true,
+}
+
+var Okay3 = struct {
+	X string
+	Y string
+	Z string
+}{
+	"Name",
+	"Usage",
+	"DefValue",
+}
+
+type MyStruct struct {
+	X string
+	Y string
+	Z string
+}
+
+var Okay4 = MyStruct{
+	"Name",
+	"Usage",
+	"DefValue",
+}
+
+// Testing is awkward because we need to reference things from a separate package
+// to trigger the warnings.
+
+var BadStructLiteralUsedInTests = flag.Flag{ // ERROR "unkeyed fields"
+	"Name",
+	"Usage",
+	nil, // Value
+	"DefValue",
+}
+
+// Used to test the check for slices and arrays: If that test is disabled and
+// vet is run with --compositewhitelist=false, this line triggers an error.
+// Clumsy but sufficient.
+var scannerErrorListTest = scanner.ErrorList{nil, nil}
diff --git a/src/cmd/vet/testdata/copylock_func.go b/src/cmd/vet/testdata/copylock_func.go
new file mode 100644
index 0000000..d83957f
--- /dev/null
+++ b/src/cmd/vet/testdata/copylock_func.go
@@ -0,0 +1,95 @@
+// 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.
+
+// This file contains tests for the copylock checker's
+// function declaration analysis.
+
+package testdata
+
+import "sync"
+
+func OkFunc(*sync.Mutex) {}
+func BadFunc(sync.Mutex) {} // ERROR "BadFunc passes Lock by value: sync.Mutex"
+func OkRet() *sync.Mutex {}
+func BadRet() sync.Mutex {} // ERROR "BadRet returns Lock by value: sync.Mutex"
+
+var (
+	OkClosure  = func(*sync.Mutex) {}
+	BadClosure = func(sync.Mutex) {} // ERROR "func passes Lock by value: sync.Mutex"
+)
+
+type EmbeddedRWMutex struct {
+	sync.RWMutex
+}
+
+func (*EmbeddedRWMutex) OkMeth() {}
+func (EmbeddedRWMutex) BadMeth() {} // ERROR "BadMeth passes Lock by value: testdata.EmbeddedRWMutex"
+func OkFunc(e *EmbeddedRWMutex)  {}
+func BadFunc(EmbeddedRWMutex)    {} // ERROR "BadFunc passes Lock by value: testdata.EmbeddedRWMutex"
+func OkRet() *EmbeddedRWMutex    {}
+func BadRet() EmbeddedRWMutex    {} // ERROR "BadRet returns Lock by value: testdata.EmbeddedRWMutex"
+
+type FieldMutex struct {
+	s sync.Mutex
+}
+
+func (*FieldMutex) OkMeth()   {}
+func (FieldMutex) BadMeth()   {} // ERROR "BadMeth passes Lock by value: testdata.FieldMutex contains sync.Mutex"
+func OkFunc(*FieldMutex)      {}
+func BadFunc(FieldMutex, int) {} // ERROR "BadFunc passes Lock by value: testdata.FieldMutex contains sync.Mutex"
+
+type L0 struct {
+	L1
+}
+
+type L1 struct {
+	l L2
+}
+
+type L2 struct {
+	sync.Mutex
+}
+
+func (*L0) Ok() {}
+func (L0) Bad() {} // ERROR "Bad passes Lock by value: testdata.L0 contains testdata.L1 contains testdata.L2"
+
+type EmbeddedMutexPointer struct {
+	s *sync.Mutex // safe to copy this pointer
+}
+
+func (*EmbeddedMutexPointer) Ok()      {}
+func (EmbeddedMutexPointer) AlsoOk()   {}
+func StillOk(EmbeddedMutexPointer)     {}
+func LookinGood() EmbeddedMutexPointer {}
+
+type EmbeddedLocker struct {
+	sync.Locker // safe to copy interface values
+}
+
+func (*EmbeddedLocker) Ok()    {}
+func (EmbeddedLocker) AlsoOk() {}
+
+type CustomLock struct{}
+
+func (*CustomLock) Lock()   {}
+func (*CustomLock) Unlock() {}
+
+func Ok(*CustomLock) {}
+func Bad(CustomLock) {} // ERROR "Bad passes Lock by value: testdata.CustomLock"
+
+// TODO: Unfortunate cases
+
+// Non-ideal error message:
+// Since we're looking for Lock methods, sync.Once's underlying
+// sync.Mutex gets called out, but without any reference to the sync.Once.
+type LocalOnce sync.Once
+
+func (LocalOnce) Bad() {} // ERROR "Bad passes Lock by value: testdata.LocalOnce contains sync.Mutex"
+
+// False negative:
+// LocalMutex doesn't have a Lock method.
+// Nevertheless, it is probably a bad idea to pass it by value.
+type LocalMutex sync.Mutex
+
+func (LocalMutex) Bad() {} // WANTED: An error here :(
diff --git a/src/cmd/vet/testdata/copylock_range.go b/src/cmd/vet/testdata/copylock_range.go
new file mode 100644
index 0000000..f95b025
--- /dev/null
+++ b/src/cmd/vet/testdata/copylock_range.go
@@ -0,0 +1,67 @@
+// 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.
+
+// This file contains tests for the copylock checker's
+// range statement analysis.
+
+package testdata
+
+import "sync"
+
+func rangeMutex() {
+	var mu sync.Mutex
+	var i int
+
+	var s []sync.Mutex
+	for range s {
+	}
+	for i = range s {
+	}
+	for i := range s {
+	}
+	for i, _ = range s {
+	}
+	for i, _ := range s {
+	}
+	for _, mu = range s { // ERROR "range var mu copies Lock: sync.Mutex"
+	}
+	for _, m := range s { // ERROR "range var m copies Lock: sync.Mutex"
+	}
+	for i, mu = range s { // ERROR "range var mu copies Lock: sync.Mutex"
+	}
+	for i, m := range s { // ERROR "range var m copies Lock: sync.Mutex"
+	}
+
+	var a [3]sync.Mutex
+	for _, m := range a { // ERROR "range var m copies Lock: sync.Mutex"
+	}
+
+	var m map[sync.Mutex]sync.Mutex
+	for k := range m { // ERROR "range var k copies Lock: sync.Mutex"
+	}
+	for mu, _ = range m { // ERROR "range var mu copies Lock: sync.Mutex"
+	}
+	for k, _ := range m { // ERROR "range var k copies Lock: sync.Mutex"
+	}
+	for _, mu = range m { // ERROR "range var mu copies Lock: sync.Mutex"
+	}
+	for _, v := range m { // ERROR "range var v copies Lock: sync.Mutex"
+	}
+
+	var c chan sync.Mutex
+	for range c {
+	}
+	for mu = range c { // ERROR "range var mu copies Lock: sync.Mutex"
+	}
+	for v := range c { // ERROR "range var v copies Lock: sync.Mutex"
+	}
+
+	// Test non-idents in range variables
+	var t struct {
+		i  int
+		mu sync.Mutex
+	}
+	for t.i, t.mu = range s { // ERROR "range var t.mu copies Lock: sync.Mutex"
+	}
+}
diff --git a/src/cmd/vet/testdata/deadcode.go b/src/cmd/vet/testdata/deadcode.go
new file mode 100644
index 0000000..5370bc3
--- /dev/null
+++ b/src/cmd/vet/testdata/deadcode.go
@@ -0,0 +1,2125 @@
+// 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 ignore
+
+// This file contains tests for the dead code checker.
+
+package testdata
+
+type T int
+
+var x interface{}
+var c chan int
+
+func external() int // ok
+
+func _() int {
+}
+
+func _() int {
+	print(1)
+}
+
+func _() int {
+	print(1)
+	return 2
+	println() // ERROR "unreachable code"
+}
+
+func _() int {
+L:
+	print(1)
+	goto L
+	println() // ERROR "unreachable code"
+}
+
+func _() int {
+	print(1)
+	panic(2)
+	println() // ERROR "unreachable code"
+}
+
+// but only builtin panic
+func _() int {
+	var panic = func(int) {}
+	print(1)
+	panic(2)
+	println() // ok
+}
+
+func _() int {
+	{
+		print(1)
+		return 2
+		println() // ERROR "unreachable code"
+	}
+	println() // ok
+}
+
+func _() int {
+	{
+		print(1)
+		return 2
+	}
+	println() // ERROR "unreachable code"
+}
+
+func _() int {
+L:
+	{
+		print(1)
+		goto L
+		println() // ERROR "unreachable code"
+	}
+	println() // ok
+}
+
+func _() int {
+L:
+	{
+		print(1)
+		goto L
+	}
+	println() // ERROR "unreachable code"
+}
+
+func _() int {
+	print(1)
+	{
+		panic(2)
+	}
+}
+
+func _() int {
+	print(1)
+	{
+		panic(2)
+		println() // ERROR "unreachable code"
+	}
+}
+
+func _() int {
+	print(1)
+	{
+		panic(2)
+	}
+	println() // ERROR "unreachable code"
+}
+
+func _() int {
+	print(1)
+	return 2
+	{ // ERROR "unreachable code"
+	}
+}
+
+func _() int {
+L:
+	print(1)
+	goto L
+	{ // ERROR "unreachable code"
+	}
+}
+
+func _() int {
+	print(1)
+	panic(2)
+	{ // ERROR "unreachable code"
+	}
+}
+
+func _() int {
+	{
+		print(1)
+		return 2
+		{ // ERROR "unreachable code"
+		}
+	}
+}
+
+func _() int {
+L:
+	{
+		print(1)
+		goto L
+		{ // ERROR "unreachable code"
+		}
+	}
+}
+
+func _() int {
+	print(1)
+	{
+		panic(2)
+		{ // ERROR "unreachable code"
+		}
+	}
+}
+
+func _() int {
+	{
+		print(1)
+		return 2
+	}
+	{ // ERROR "unreachable code"
+	}
+}
+
+func _() int {
+L:
+	{
+		print(1)
+		goto L
+	}
+	{ // ERROR "unreachable code"
+	}
+}
+
+func _() int {
+	print(1)
+	{
+		panic(2)
+	}
+	{ // ERROR "unreachable code"
+	}
+}
+
+func _() int {
+	print(1)
+	if x == nil {
+		panic(2)
+	} else {
+		panic(3)
+	}
+	println() // ERROR "unreachable code"
+}
+
+func _() int {
+L:
+	print(1)
+	if x == nil {
+		panic(2)
+	} else {
+		goto L
+	}
+	println() // ERROR "unreachable code"
+}
+
+func _() int {
+L:
+	print(1)
+	if x == nil {
+		panic(2)
+	} else if x == 1 {
+		return 0
+	} else if x != 2 {
+		panic(3)
+	} else {
+		goto L
+	}
+	println() // ERROR "unreachable code"
+}
+
+// if-else chain missing final else is not okay, even if the
+// conditions cover every possible case.
+
+func _() int {
+	print(1)
+	if x == nil {
+		panic(2)
+	} else if x != nil {
+		panic(3)
+	}
+	println() // ok
+}
+
+func _() int {
+	print(1)
+	if x == nil {
+		panic(2)
+	}
+	println() // ok
+}
+
+func _() int {
+L:
+	print(1)
+	if x == nil {
+		panic(2)
+	} else if x == 1 {
+		return 0
+	} else if x != 1 {
+		panic(3)
+	}
+	println() // ok
+}
+
+func _() int {
+	print(1)
+	for {
+	}
+	println() // ERROR "unreachable code"
+}
+
+func _() int {
+	for {
+		for {
+			break
+		}
+	}
+	println() // ERROR "unreachable code"
+}
+
+func _() int {
+	for {
+		for {
+			break
+			println() // ERROR "unreachable code"
+		}
+	}
+}
+
+func _() int {
+	for {
+		for {
+			continue
+			println() // ERROR "unreachable code"
+		}
+	}
+}
+
+func _() int {
+	for {
+	L:
+		for {
+			break L
+		}
+	}
+	println() // ERROR "unreachable code"
+}
+
+func _() int {
+	print(1)
+	for {
+		break
+	}
+	println() // ok
+}
+
+func _() int {
+	for {
+		for {
+		}
+		break // ERROR "unreachable code"
+	}
+	println() // ok
+}
+
+func _() int {
+L:
+	for {
+		for {
+			break L
+		}
+	}
+	println() // ok
+}
+
+func _() int {
+	print(1)
+	for x == nil {
+	}
+	println() // ok
+}
+
+func _() int {
+	for x == nil {
+		for {
+			break
+		}
+	}
+	println() // ok
+}
+
+func _() int {
+	for x == nil {
+	L:
+		for {
+			break L
+		}
+	}
+	println() // ok
+}
+
+func _() int {
+	print(1)
+	for true {
+	}
+	println() // ok
+}
+
+func _() int {
+	for true {
+		for {
+			break
+		}
+	}
+	println() // ok
+}
+
+func _() int {
+	for true {
+	L:
+		for {
+			break L
+		}
+	}
+	println() // ok
+}
+
+func _() int {
+	print(1)
+	select {}
+	println() // ERROR "unreachable code"
+}
+
+func _() int {
+	print(1)
+	select {
+	case <-c:
+		print(2)
+		panic("abc")
+		println() // ERROR "unreachable code"
+	}
+}
+
+func _() int {
+	print(1)
+	select {
+	case <-c:
+		print(2)
+		panic("abc")
+	}
+	println() // ERROR "unreachable code"
+}
+
+func _() int {
+	print(1)
+	select {
+	case <-c:
+		print(2)
+		for {
+		}
+		println() // ERROR "unreachable code"
+	}
+}
+
+func _() int {
+	print(1)
+	select {
+	case <-c:
+		print(2)
+		for {
+		}
+	}
+	println() // ERROR "unreachable code"
+}
+
+func _() int {
+L:
+	print(1)
+	select {
+	case <-c:
+		print(2)
+		panic("abc")
+		println() // ERROR "unreachable code"
+	case c <- 1:
+		print(2)
+		goto L
+		println() // ERROR "unreachable code"
+	}
+}
+
+func _() int {
+L:
+	print(1)
+	select {
+	case <-c:
+		print(2)
+		panic("abc")
+	case c <- 1:
+		print(2)
+		goto L
+	}
+	println() // ERROR "unreachable code"
+}
+
+func _() int {
+	print(1)
+	select {
+	case <-c:
+		print(2)
+		panic("abc")
+		println() // ERROR "unreachable code"
+	default:
+		select {}
+		println() // ERROR "unreachable code"
+	}
+}
+
+func _() int {
+	print(1)
+	select {
+	case <-c:
+		print(2)
+		panic("abc")
+	default:
+		select {}
+	}
+	println() // ERROR "unreachable code"
+}
+
+func _() int {
+	print(1)
+	select {
+	case <-c:
+		print(2)
+	}
+	println() // ok
+}
+
+func _() int {
+L:
+	print(1)
+	select {
+	case <-c:
+		print(2)
+		panic("abc")
+		goto L // ERROR "unreachable code"
+	case c <- 1:
+		print(2)
+	}
+	println() // ok
+}
+
+func _() int {
+	print(1)
+	select {
+	case <-c:
+		print(2)
+		panic("abc")
+	default:
+		print(2)
+	}
+	println() // ok
+}
+
+func _() int {
+	print(1)
+	select {
+	default:
+		break
+	}
+	println() // ok
+}
+
+func _() int {
+	print(1)
+	select {
+	case <-c:
+		print(2)
+		panic("abc")
+		break // ERROR "unreachable code"
+	}
+	println() // ok
+}
+
+func _() int {
+	print(1)
+L:
+	select {
+	case <-c:
+		print(2)
+		for {
+			break L
+		}
+	}
+	println() // ok
+}
+
+func _() int {
+	print(1)
+L:
+	select {
+	case <-c:
+		print(2)
+		panic("abc")
+	case c <- 1:
+		print(2)
+		break L
+	}
+	println() // ok
+}
+
+func _() int {
+	print(1)
+	select {
+	case <-c:
+		print(1)
+		panic("abc")
+	default:
+		select {}
+		break // ERROR "unreachable code"
+	}
+	println() // ok
+}
+
+func _() int {
+	print(1)
+	switch x {
+	case 1:
+		print(2)
+		panic(3)
+		println() // ERROR "unreachable code"
+	default:
+		return 4
+		println() // ERROR "unreachable code"
+	}
+}
+
+func _() int {
+	print(1)
+	switch x {
+	case 1:
+		print(2)
+		panic(3)
+	default:
+		return 4
+	}
+	println() // ERROR "unreachable code"
+}
+
+func _() int {
+	print(1)
+	switch x {
+	default:
+		return 4
+		println() // ERROR "unreachable code"
+	case 1:
+		print(2)
+		panic(3)
+		println() // ERROR "unreachable code"
+	}
+}
+
+func _() int {
+	print(1)
+	switch x {
+	default:
+		return 4
+	case 1:
+		print(2)
+		panic(3)
+	}
+	println() // ERROR "unreachable code"
+}
+
+func _() int {
+	print(1)
+	switch x {
+	case 1:
+		print(2)
+		fallthrough
+	default:
+		return 4
+		println() // ERROR "unreachable code"
+	}
+}
+
+func _() int {
+	print(1)
+	switch x {
+	case 1:
+		print(2)
+		fallthrough
+	default:
+		return 4
+	}
+	println() // ERROR "unreachable code"
+}
+
+func _() int {
+	print(1)
+	switch {
+	}
+	println() // ok
+}
+
+func _() int {
+	print(1)
+	switch x {
+	case 1:
+		print(2)
+		panic(3)
+	case 2:
+		return 4
+	}
+	println() // ok
+}
+
+func _() int {
+	print(1)
+	switch x {
+	case 2:
+		return 4
+	case 1:
+		print(2)
+		panic(3)
+	}
+	println() // ok
+}
+
+func _() int {
+	print(1)
+	switch x {
+	case 1:
+		print(2)
+		fallthrough
+	case 2:
+		return 4
+	}
+	println() // ok
+}
+
+func _() int {
+	print(1)
+	switch x {
+	case 1:
+		print(2)
+		panic(3)
+	}
+	println() // ok
+}
+
+func _() int {
+	print(1)
+L:
+	switch x {
+	case 1:
+		print(2)
+		panic(3)
+		break L // ERROR "unreachable code"
+	default:
+		return 4
+	}
+	println() // ok
+}
+
+func _() int {
+	print(1)
+	switch x {
+	default:
+		return 4
+		break // ERROR "unreachable code"
+	case 1:
+		print(2)
+		panic(3)
+	}
+	println() // ok
+}
+
+func _() int {
+	print(1)
+L:
+	switch x {
+	case 1:
+		print(2)
+		for {
+			break L
+		}
+	default:
+		return 4
+	}
+	println() // ok
+}
+
+func _() int {
+	print(1)
+	switch x.(type) {
+	case int:
+		print(2)
+		panic(3)
+		println() // ERROR "unreachable code"
+	default:
+		return 4
+		println() // ERROR "unreachable code"
+	}
+}
+
+func _() int {
+	print(1)
+	switch x.(type) {
+	case int:
+		print(2)
+		panic(3)
+	default:
+		return 4
+	}
+	println() // ERROR "unreachable code"
+}
+
+func _() int {
+	print(1)
+	switch x.(type) {
+	default:
+		return 4
+		println() // ERROR "unreachable code"
+	case int:
+		print(2)
+		panic(3)
+		println() // ERROR "unreachable code"
+	}
+}
+
+func _() int {
+	print(1)
+	switch x.(type) {
+	default:
+		return 4
+	case int:
+		print(2)
+		panic(3)
+	}
+	println() // ERROR "unreachable code"
+}
+
+func _() int {
+	print(1)
+	switch x.(type) {
+	case int:
+		print(2)
+		fallthrough
+	default:
+		return 4
+		println() // ERROR "unreachable code"
+	}
+}
+
+func _() int {
+	print(1)
+	switch x.(type) {
+	case int:
+		print(2)
+		fallthrough
+	default:
+		return 4
+	}
+	println() // ERROR "unreachable code"
+}
+
+func _() int {
+	print(1)
+	switch {
+	}
+	println() // ok
+}
+
+func _() int {
+	print(1)
+	switch x.(type) {
+	case int:
+		print(2)
+		panic(3)
+	case float64:
+		return 4
+	}
+	println() // ok
+}
+
+func _() int {
+	print(1)
+	switch x.(type) {
+	case float64:
+		return 4
+	case int:
+		print(2)
+		panic(3)
+	}
+	println() // ok
+}
+
+func _() int {
+	print(1)
+	switch x.(type) {
+	case int:
+		print(2)
+		fallthrough
+	case float64:
+		return 4
+	}
+	println() // ok
+}
+
+func _() int {
+	print(1)
+	switch x.(type) {
+	case int:
+		print(2)
+		panic(3)
+	}
+	println() // ok
+}
+
+func _() int {
+	print(1)
+L:
+	switch x.(type) {
+	case int:
+		print(2)
+		panic(3)
+		break L // ERROR "unreachable code"
+	default:
+		return 4
+	}
+	println() // ok
+}
+
+func _() int {
+	print(1)
+	switch x.(type) {
+	default:
+		return 4
+		break // ERROR "unreachable code"
+	case int:
+		print(2)
+		panic(3)
+	}
+	println() // ok
+}
+
+func _() int {
+	print(1)
+L:
+	switch x.(type) {
+	case int:
+		print(2)
+		for {
+			break L
+		}
+	default:
+		return 4
+	}
+	println() // ok
+}
+
+// again, but without the leading print(1).
+// testing that everything works when the terminating statement is first.
+
+func _() int {
+	println() // ok
+}
+
+func _() int {
+	return 2
+	println() // ERROR "unreachable code"
+}
+
+func _() int {
+L:
+	goto L
+	println() // ERROR "unreachable code"
+}
+
+func _() int {
+	panic(2)
+	println() // ERROR "unreachable code"
+}
+
+// but only builtin panic
+func _() int {
+	var panic = func(int) {}
+	panic(2)
+	println() // ok
+}
+
+func _() int {
+	{
+		return 2
+		println() // ERROR "unreachable code"
+	}
+}
+
+func _() int {
+	{
+		return 2
+	}
+	println() // ERROR "unreachable code"
+}
+
+func _() int {
+L:
+	{
+		goto L
+		println() // ERROR "unreachable code"
+	}
+}
+
+func _() int {
+L:
+	{
+		goto L
+	}
+	println() // ERROR "unreachable code"
+}
+
+func _() int {
+	{
+		panic(2)
+		println() // ERROR "unreachable code"
+	}
+}
+
+func _() int {
+	{
+		panic(2)
+	}
+	println() // ERROR "unreachable code"
+}
+
+func _() int {
+	return 2
+	{ // ERROR "unreachable code"
+	}
+	println() // ok
+}
+
+func _() int {
+L:
+	goto L
+	{ // ERROR "unreachable code"
+	}
+	println() // ok
+}
+
+func _() int {
+	panic(2)
+	{ // ERROR "unreachable code"
+	}
+	println() // ok
+}
+
+func _() int {
+	{
+		return 2
+		{ // ERROR "unreachable code"
+		}
+	}
+	println() // ok
+}
+
+func _() int {
+L:
+	{
+		goto L
+		{ // ERROR "unreachable code"
+		}
+	}
+	println() // ok
+}
+
+func _() int {
+	{
+		panic(2)
+		{ // ERROR "unreachable code"
+		}
+	}
+	println() // ok
+}
+
+func _() int {
+	{
+		return 2
+	}
+	{ // ERROR "unreachable code"
+	}
+	println() // ok
+}
+
+func _() int {
+L:
+	{
+		goto L
+	}
+	{ // ERROR "unreachable code"
+	}
+	println() // ok
+}
+
+func _() int {
+	{
+		panic(2)
+	}
+	{ // ERROR "unreachable code"
+	}
+	println() // ok
+}
+
+// again, with func literals
+
+var _ = func() int {
+}
+
+var _ = func() int {
+	print(1)
+}
+
+var _ = func() int {
+	print(1)
+	return 2
+	println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+L:
+	print(1)
+	goto L
+	println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+	print(1)
+	panic(2)
+	println() // ERROR "unreachable code"
+}
+
+// but only builtin panic
+var _ = func() int {
+	var panic = func(int) {}
+	print(1)
+	panic(2)
+	println() // ok
+}
+
+var _ = func() int {
+	{
+		print(1)
+		return 2
+		println() // ERROR "unreachable code"
+	}
+	println() // ok
+}
+
+var _ = func() int {
+	{
+		print(1)
+		return 2
+	}
+	println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+L:
+	{
+		print(1)
+		goto L
+		println() // ERROR "unreachable code"
+	}
+	println() // ok
+}
+
+var _ = func() int {
+L:
+	{
+		print(1)
+		goto L
+	}
+	println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+	print(1)
+	{
+		panic(2)
+	}
+}
+
+var _ = func() int {
+	print(1)
+	{
+		panic(2)
+		println() // ERROR "unreachable code"
+	}
+}
+
+var _ = func() int {
+	print(1)
+	{
+		panic(2)
+	}
+	println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+	print(1)
+	return 2
+	{ // ERROR "unreachable code"
+	}
+}
+
+var _ = func() int {
+L:
+	print(1)
+	goto L
+	{ // ERROR "unreachable code"
+	}
+}
+
+var _ = func() int {
+	print(1)
+	panic(2)
+	{ // ERROR "unreachable code"
+	}
+}
+
+var _ = func() int {
+	{
+		print(1)
+		return 2
+		{ // ERROR "unreachable code"
+		}
+	}
+}
+
+var _ = func() int {
+L:
+	{
+		print(1)
+		goto L
+		{ // ERROR "unreachable code"
+		}
+	}
+}
+
+var _ = func() int {
+	print(1)
+	{
+		panic(2)
+		{ // ERROR "unreachable code"
+		}
+	}
+}
+
+var _ = func() int {
+	{
+		print(1)
+		return 2
+	}
+	{ // ERROR "unreachable code"
+	}
+}
+
+var _ = func() int {
+L:
+	{
+		print(1)
+		goto L
+	}
+	{ // ERROR "unreachable code"
+	}
+}
+
+var _ = func() int {
+	print(1)
+	{
+		panic(2)
+	}
+	{ // ERROR "unreachable code"
+	}
+}
+
+var _ = func() int {
+	print(1)
+	if x == nil {
+		panic(2)
+	} else {
+		panic(3)
+	}
+	println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+L:
+	print(1)
+	if x == nil {
+		panic(2)
+	} else {
+		goto L
+	}
+	println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+L:
+	print(1)
+	if x == nil {
+		panic(2)
+	} else if x == 1 {
+		return 0
+	} else if x != 2 {
+		panic(3)
+	} else {
+		goto L
+	}
+	println() // ERROR "unreachable code"
+}
+
+// if-else chain missing final else is not okay, even if the
+// conditions cover every possible case.
+
+var _ = func() int {
+	print(1)
+	if x == nil {
+		panic(2)
+	} else if x != nil {
+		panic(3)
+	}
+	println() // ok
+}
+
+var _ = func() int {
+	print(1)
+	if x == nil {
+		panic(2)
+	}
+	println() // ok
+}
+
+var _ = func() int {
+L:
+	print(1)
+	if x == nil {
+		panic(2)
+	} else if x == 1 {
+		return 0
+	} else if x != 1 {
+		panic(3)
+	}
+	println() // ok
+}
+
+var _ = func() int {
+	print(1)
+	for {
+	}
+	println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+	for {
+		for {
+			break
+		}
+	}
+	println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+	for {
+		for {
+			break
+			println() // ERROR "unreachable code"
+		}
+	}
+}
+
+var _ = func() int {
+	for {
+		for {
+			continue
+			println() // ERROR "unreachable code"
+		}
+	}
+}
+
+var _ = func() int {
+	for {
+	L:
+		for {
+			break L
+		}
+	}
+	println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+	print(1)
+	for {
+		break
+	}
+	println() // ok
+}
+
+var _ = func() int {
+	for {
+		for {
+		}
+		break // ERROR "unreachable code"
+	}
+	println() // ok
+}
+
+var _ = func() int {
+L:
+	for {
+		for {
+			break L
+		}
+	}
+	println() // ok
+}
+
+var _ = func() int {
+	print(1)
+	for x == nil {
+	}
+	println() // ok
+}
+
+var _ = func() int {
+	for x == nil {
+		for {
+			break
+		}
+	}
+	println() // ok
+}
+
+var _ = func() int {
+	for x == nil {
+	L:
+		for {
+			break L
+		}
+	}
+	println() // ok
+}
+
+var _ = func() int {
+	print(1)
+	for true {
+	}
+	println() // ok
+}
+
+var _ = func() int {
+	for true {
+		for {
+			break
+		}
+	}
+	println() // ok
+}
+
+var _ = func() int {
+	for true {
+	L:
+		for {
+			break L
+		}
+	}
+	println() // ok
+}
+
+var _ = func() int {
+	print(1)
+	select {}
+	println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+	print(1)
+	select {
+	case <-c:
+		print(2)
+		panic("abc")
+		println() // ERROR "unreachable code"
+	}
+}
+
+var _ = func() int {
+	print(1)
+	select {
+	case <-c:
+		print(2)
+		panic("abc")
+	}
+	println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+	print(1)
+	select {
+	case <-c:
+		print(2)
+		for {
+		}
+		println() // ERROR "unreachable code"
+	}
+}
+
+var _ = func() int {
+	print(1)
+	select {
+	case <-c:
+		print(2)
+		for {
+		}
+	}
+	println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+L:
+	print(1)
+	select {
+	case <-c:
+		print(2)
+		panic("abc")
+		println() // ERROR "unreachable code"
+	case c <- 1:
+		print(2)
+		goto L
+		println() // ERROR "unreachable code"
+	}
+}
+
+var _ = func() int {
+L:
+	print(1)
+	select {
+	case <-c:
+		print(2)
+		panic("abc")
+	case c <- 1:
+		print(2)
+		goto L
+	}
+	println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+	print(1)
+	select {
+	case <-c:
+		print(2)
+		panic("abc")
+		println() // ERROR "unreachable code"
+	default:
+		select {}
+		println() // ERROR "unreachable code"
+	}
+}
+
+var _ = func() int {
+	print(1)
+	select {
+	case <-c:
+		print(2)
+		panic("abc")
+	default:
+		select {}
+	}
+	println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+	print(1)
+	select {
+	case <-c:
+		print(2)
+	}
+	println() // ok
+}
+
+var _ = func() int {
+L:
+	print(1)
+	select {
+	case <-c:
+		print(2)
+		panic("abc")
+		goto L // ERROR "unreachable code"
+	case c <- 1:
+		print(2)
+	}
+	println() // ok
+}
+
+var _ = func() int {
+	print(1)
+	select {
+	case <-c:
+		print(2)
+		panic("abc")
+	default:
+		print(2)
+	}
+	println() // ok
+}
+
+var _ = func() int {
+	print(1)
+	select {
+	default:
+		break
+	}
+	println() // ok
+}
+
+var _ = func() int {
+	print(1)
+	select {
+	case <-c:
+		print(2)
+		panic("abc")
+		break // ERROR "unreachable code"
+	}
+	println() // ok
+}
+
+var _ = func() int {
+	print(1)
+L:
+	select {
+	case <-c:
+		print(2)
+		for {
+			break L
+		}
+	}
+	println() // ok
+}
+
+var _ = func() int {
+	print(1)
+L:
+	select {
+	case <-c:
+		print(2)
+		panic("abc")
+	case c <- 1:
+		print(2)
+		break L
+	}
+	println() // ok
+}
+
+var _ = func() int {
+	print(1)
+	select {
+	case <-c:
+		print(1)
+		panic("abc")
+	default:
+		select {}
+		break // ERROR "unreachable code"
+	}
+	println() // ok
+}
+
+var _ = func() int {
+	print(1)
+	switch x {
+	case 1:
+		print(2)
+		panic(3)
+		println() // ERROR "unreachable code"
+	default:
+		return 4
+		println() // ERROR "unreachable code"
+	}
+}
+
+var _ = func() int {
+	print(1)
+	switch x {
+	case 1:
+		print(2)
+		panic(3)
+	default:
+		return 4
+	}
+	println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+	print(1)
+	switch x {
+	default:
+		return 4
+		println() // ERROR "unreachable code"
+	case 1:
+		print(2)
+		panic(3)
+		println() // ERROR "unreachable code"
+	}
+}
+
+var _ = func() int {
+	print(1)
+	switch x {
+	default:
+		return 4
+	case 1:
+		print(2)
+		panic(3)
+	}
+	println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+	print(1)
+	switch x {
+	case 1:
+		print(2)
+		fallthrough
+	default:
+		return 4
+		println() // ERROR "unreachable code"
+	}
+}
+
+var _ = func() int {
+	print(1)
+	switch x {
+	case 1:
+		print(2)
+		fallthrough
+	default:
+		return 4
+	}
+	println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+	print(1)
+	switch {
+	}
+	println() // ok
+}
+
+var _ = func() int {
+	print(1)
+	switch x {
+	case 1:
+		print(2)
+		panic(3)
+	case 2:
+		return 4
+	}
+	println() // ok
+}
+
+var _ = func() int {
+	print(1)
+	switch x {
+	case 2:
+		return 4
+	case 1:
+		print(2)
+		panic(3)
+	}
+	println() // ok
+}
+
+var _ = func() int {
+	print(1)
+	switch x {
+	case 1:
+		print(2)
+		fallthrough
+	case 2:
+		return 4
+	}
+	println() // ok
+}
+
+var _ = func() int {
+	print(1)
+	switch x {
+	case 1:
+		print(2)
+		panic(3)
+	}
+	println() // ok
+}
+
+var _ = func() int {
+	print(1)
+L:
+	switch x {
+	case 1:
+		print(2)
+		panic(3)
+		break L // ERROR "unreachable code"
+	default:
+		return 4
+	}
+	println() // ok
+}
+
+var _ = func() int {
+	print(1)
+	switch x {
+	default:
+		return 4
+		break // ERROR "unreachable code"
+	case 1:
+		print(2)
+		panic(3)
+	}
+	println() // ok
+}
+
+var _ = func() int {
+	print(1)
+L:
+	switch x {
+	case 1:
+		print(2)
+		for {
+			break L
+		}
+	default:
+		return 4
+	}
+	println() // ok
+}
+
+var _ = func() int {
+	print(1)
+	switch x.(type) {
+	case int:
+		print(2)
+		panic(3)
+		println() // ERROR "unreachable code"
+	default:
+		return 4
+		println() // ERROR "unreachable code"
+	}
+}
+
+var _ = func() int {
+	print(1)
+	switch x.(type) {
+	case int:
+		print(2)
+		panic(3)
+	default:
+		return 4
+	}
+	println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+	print(1)
+	switch x.(type) {
+	default:
+		return 4
+		println() // ERROR "unreachable code"
+	case int:
+		print(2)
+		panic(3)
+		println() // ERROR "unreachable code"
+	}
+}
+
+var _ = func() int {
+	print(1)
+	switch x.(type) {
+	default:
+		return 4
+	case int:
+		print(2)
+		panic(3)
+	}
+	println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+	print(1)
+	switch x.(type) {
+	case int:
+		print(2)
+		fallthrough
+	default:
+		return 4
+		println() // ERROR "unreachable code"
+	}
+}
+
+var _ = func() int {
+	print(1)
+	switch x.(type) {
+	case int:
+		print(2)
+		fallthrough
+	default:
+		return 4
+	}
+	println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+	print(1)
+	switch {
+	}
+	println() // ok
+}
+
+var _ = func() int {
+	print(1)
+	switch x.(type) {
+	case int:
+		print(2)
+		panic(3)
+	case float64:
+		return 4
+	}
+	println() // ok
+}
+
+var _ = func() int {
+	print(1)
+	switch x.(type) {
+	case float64:
+		return 4
+	case int:
+		print(2)
+		panic(3)
+	}
+	println() // ok
+}
+
+var _ = func() int {
+	print(1)
+	switch x.(type) {
+	case int:
+		print(2)
+		fallthrough
+	case float64:
+		return 4
+	}
+	println() // ok
+}
+
+var _ = func() int {
+	print(1)
+	switch x.(type) {
+	case int:
+		print(2)
+		panic(3)
+	}
+	println() // ok
+}
+
+var _ = func() int {
+	print(1)
+L:
+	switch x.(type) {
+	case int:
+		print(2)
+		panic(3)
+		break L // ERROR "unreachable code"
+	default:
+		return 4
+	}
+	println() // ok
+}
+
+var _ = func() int {
+	print(1)
+	switch x.(type) {
+	default:
+		return 4
+		break // ERROR "unreachable code"
+	case int:
+		print(2)
+		panic(3)
+	}
+	println() // ok
+}
+
+var _ = func() int {
+	print(1)
+L:
+	switch x.(type) {
+	case int:
+		print(2)
+		for {
+			break L
+		}
+	default:
+		return 4
+	}
+	println() // ok
+}
+
+// again, but without the leading print(1).
+// testing that everything works when the terminating statement is first.
+
+var _ = func() int {
+	println() // ok
+}
+
+var _ = func() int {
+	return 2
+	println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+L:
+	goto L
+	println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+	panic(2)
+	println() // ERROR "unreachable code"
+}
+
+// but only builtin panic
+var _ = func() int {
+	var panic = func(int) {}
+	panic(2)
+	println() // ok
+}
+
+var _ = func() int {
+	{
+		return 2
+		println() // ERROR "unreachable code"
+	}
+}
+
+var _ = func() int {
+	{
+		return 2
+	}
+	println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+L:
+	{
+		goto L
+		println() // ERROR "unreachable code"
+	}
+}
+
+var _ = func() int {
+L:
+	{
+		goto L
+	}
+	println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+	{
+		panic(2)
+		println() // ERROR "unreachable code"
+	}
+}
+
+var _ = func() int {
+	{
+		panic(2)
+	}
+	println() // ERROR "unreachable code"
+}
+
+var _ = func() int {
+	return 2
+	{ // ERROR "unreachable code"
+	}
+	println() // ok
+}
+
+var _ = func() int {
+L:
+	goto L
+	{ // ERROR "unreachable code"
+	}
+	println() // ok
+}
+
+var _ = func() int {
+	panic(2)
+	{ // ERROR "unreachable code"
+	}
+	println() // ok
+}
+
+var _ = func() int {
+	{
+		return 2
+		{ // ERROR "unreachable code"
+		}
+	}
+	println() // ok
+}
+
+var _ = func() int {
+L:
+	{
+		goto L
+		{ // ERROR "unreachable code"
+		}
+	}
+	println() // ok
+}
+
+var _ = func() int {
+	{
+		panic(2)
+		{ // ERROR "unreachable code"
+		}
+	}
+	println() // ok
+}
+
+var _ = func() int {
+	{
+		return 2
+	}
+	{ // ERROR "unreachable code"
+	}
+	println() // ok
+}
+
+var _ = func() int {
+L:
+	{
+		goto L
+	}
+	{ // ERROR "unreachable code"
+	}
+	println() // ok
+}
+
+var _ = func() int {
+	{
+		panic(2)
+	}
+	{ // ERROR "unreachable code"
+	}
+	println() // ok
+}
+
+var _ = func() {
+	// goto without label used to panic
+	goto
+}
diff --git a/src/cmd/vet/testdata/method.go b/src/cmd/vet/testdata/method.go
new file mode 100644
index 0000000..52b500d
--- /dev/null
+++ b/src/cmd/vet/testdata/method.go
@@ -0,0 +1,22 @@
+// Copyright 2010 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 contains tests for the canonical method checker.
+
+// This file contains the code to check canonical methods.
+
+package testdata
+
+import (
+	"fmt"
+)
+
+type MethodTest int
+
+func (t *MethodTest) Scan(x fmt.ScanState, c byte) { // ERROR "should have signature Scan"
+}
+
+type MethodTestInterface interface {
+	ReadByte() byte // ERROR "should have signature ReadByte"
+}
diff --git a/src/cmd/vet/testdata/nilfunc.go b/src/cmd/vet/testdata/nilfunc.go
new file mode 100644
index 0000000..2ce7bc8
--- /dev/null
+++ b/src/cmd/vet/testdata/nilfunc.go
@@ -0,0 +1,35 @@
+// 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 testdata
+
+func F() {}
+
+type T struct {
+	F func()
+}
+
+func (T) M() {}
+
+var Fv = F
+
+func Comparison() {
+	var t T
+	var fn func()
+	if fn == nil || Fv == nil || t.F == nil {
+		// no error; these func vars or fields may be nil
+	}
+	if F == nil { // ERROR "comparison of function F == nil is always false"
+		panic("can't happen")
+	}
+	if t.M == nil { // ERROR "comparison of function M == nil is always false"
+		panic("can't happen")
+	}
+	if F != nil { // ERROR "comparison of function F != nil is always true"
+		if t.M != nil { // ERROR "comparison of function M != nil is always true"
+			return
+		}
+	}
+	panic("can't happen")
+}
diff --git a/src/cmd/vet/testdata/print.go b/src/cmd/vet/testdata/print.go
new file mode 100644
index 0000000..3390a31
--- /dev/null
+++ b/src/cmd/vet/testdata/print.go
@@ -0,0 +1,342 @@
+// Copyright 2010 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 contains tests for the printf checker.
+
+package testdata
+
+import (
+	"fmt"
+	"math"
+	"os"
+	"unsafe" // just for test case printing unsafe.Pointer
+)
+
+func UnsafePointerPrintfTest() {
+	var up unsafe.Pointer
+	fmt.Printf("%p, %x %X", up, up, up)
+}
+
+// Error methods that do not satisfy the Error interface and should be checked.
+type errorTest1 int
+
+func (errorTest1) Error(...interface{}) string {
+	return "hi"
+}
+
+type errorTest2 int // Analogous to testing's *T type.
+func (errorTest2) Error(...interface{}) {
+}
+
+type errorTest3 int
+
+func (errorTest3) Error() { // No return value.
+}
+
+type errorTest4 int
+
+func (errorTest4) Error() int { // Different return type.
+	return 3
+}
+
+type errorTest5 int
+
+func (errorTest5) error() { // niladic; don't complain if no args (was bug)
+}
+
+// This function never executes, but it serves as a simple test for the program.
+// Test with make test.
+func PrintfTests() {
+	var b bool
+	var i int
+	var r rune
+	var s string
+	var x float64
+	var p *int
+	var imap map[int]int
+	var fslice []float64
+	var c complex64
+	// Some good format/argtypes
+	fmt.Printf("")
+	fmt.Printf("%b %b %b", 3, i, x)
+	fmt.Printf("%c %c %c %c", 3, i, 'x', r)
+	fmt.Printf("%d %d %d", 3, i, imap)
+	fmt.Printf("%e %e %e %e", 3e9, x, fslice, c)
+	fmt.Printf("%E %E %E %E", 3e9, x, fslice, c)
+	fmt.Printf("%f %f %f %f", 3e9, x, fslice, c)
+	fmt.Printf("%F %F %F %F", 3e9, x, fslice, c)
+	fmt.Printf("%g %g %g %g", 3e9, x, fslice, c)
+	fmt.Printf("%G %G %G %G", 3e9, x, fslice, c)
+	fmt.Printf("%b %b %b %b", 3e9, x, fslice, c)
+	fmt.Printf("%o %o", 3, i)
+	fmt.Printf("%p %p", p, nil)
+	fmt.Printf("%q %q %q %q", 3, i, 'x', r)
+	fmt.Printf("%s %s %s", "hi", s, []byte{65})
+	fmt.Printf("%t %t", true, b)
+	fmt.Printf("%T %T", 3, i)
+	fmt.Printf("%U %U", 3, i)
+	fmt.Printf("%v %v", 3, i)
+	fmt.Printf("%x %x %x %x", 3, i, "hi", s)
+	fmt.Printf("%X %X %X %X", 3, i, "hi", s)
+	fmt.Printf("%.*s %d %g", 3, "hi", 23, 2.3)
+	fmt.Printf("%s", &stringerv)
+	fmt.Printf("%v", &stringerv)
+	fmt.Printf("%T", &stringerv)
+	fmt.Printf("%v", notstringerv)
+	fmt.Printf("%T", notstringerv)
+	fmt.Printf("%q", stringerarrayv)
+	fmt.Printf("%v", stringerarrayv)
+	fmt.Printf("%s", stringerarrayv)
+	fmt.Printf("%v", notstringerarrayv)
+	fmt.Printf("%T", notstringerarrayv)
+	fmt.Printf("%d", new(Formatter))
+	fmt.Printf("%*%", 2)               // Ridiculous but allowed.
+	fmt.Printf("%s", interface{}(nil)) // Nothing useful we can say.
+
+	fmt.Printf("%g", 1+2i)
+	// Some bad format/argTypes
+	fmt.Printf("%b", "hi")                     // ERROR "arg .hi. for printf verb %b of wrong type"
+	fmt.Printf("%t", c)                        // ERROR "arg c for printf verb %t of wrong type"
+	fmt.Printf("%t", 1+2i)                     // ERROR "arg 1 \+ 2i for printf verb %t of wrong type"
+	fmt.Printf("%c", 2.3)                      // ERROR "arg 2.3 for printf verb %c of wrong type"
+	fmt.Printf("%d", 2.3)                      // ERROR "arg 2.3 for printf verb %d of wrong type"
+	fmt.Printf("%e", "hi")                     // ERROR "arg .hi. for printf verb %e of wrong type"
+	fmt.Printf("%E", true)                     // ERROR "arg true for printf verb %E of wrong type"
+	fmt.Printf("%f", "hi")                     // ERROR "arg .hi. for printf verb %f of wrong type"
+	fmt.Printf("%F", 'x')                      // ERROR "arg 'x' for printf verb %F of wrong type"
+	fmt.Printf("%g", "hi")                     // ERROR "arg .hi. for printf verb %g of wrong type"
+	fmt.Printf("%g", imap)                     // ERROR "arg imap for printf verb %g of wrong type"
+	fmt.Printf("%G", i)                        // ERROR "arg i for printf verb %G of wrong type"
+	fmt.Printf("%o", x)                        // ERROR "arg x for printf verb %o of wrong type"
+	fmt.Printf("%p", 23)                       // ERROR "arg 23 for printf verb %p of wrong type"
+	fmt.Printf("%q", x)                        // ERROR "arg x for printf verb %q of wrong type"
+	fmt.Printf("%s", b)                        // ERROR "arg b for printf verb %s of wrong type"
+	fmt.Printf("%s", byte(65))                 // ERROR "arg byte\(65\) for printf verb %s of wrong type"
+	fmt.Printf("%t", 23)                       // ERROR "arg 23 for printf verb %t of wrong type"
+	fmt.Printf("%U", x)                        // ERROR "arg x for printf verb %U of wrong type"
+	fmt.Printf("%x", nil)                      // ERROR "arg nil for printf verb %x of wrong type"
+	fmt.Printf("%X", 2.3)                      // ERROR "arg 2.3 for printf verb %X of wrong type"
+	fmt.Printf("%s", stringerv)                // ERROR "arg stringerv for printf verb %s of wrong type"
+	fmt.Printf("%t", stringerv)                // ERROR "arg stringerv for printf verb %t of wrong type"
+	fmt.Printf("%q", notstringerv)             // ERROR "arg notstringerv for printf verb %q of wrong type"
+	fmt.Printf("%t", notstringerv)             // ERROR "arg notstringerv for printf verb %t of wrong type"
+	fmt.Printf("%t", stringerarrayv)           // ERROR "arg stringerarrayv for printf verb %t of wrong type"
+	fmt.Printf("%t", notstringerarrayv)        // ERROR "arg notstringerarrayv for printf verb %t of wrong type"
+	fmt.Printf("%q", notstringerarrayv)        // ERROR "arg notstringerarrayv for printf verb %q of wrong type"
+	fmt.Printf("%d", Formatter(true))          // correct (the type is responsible for formatting)
+	fmt.Printf("%s", nonemptyinterface)        // correct (the dynamic type of nonemptyinterface may be a stringer)
+	fmt.Printf("%.*s %d %g", 3, "hi", 23, 'x') // ERROR "arg 'x' for printf verb %g of wrong type"
+	fmt.Println()                              // not an error
+	fmt.Println("%s", "hi")                    // ERROR "possible formatting directive in Println call"
+	fmt.Printf("%s", "hi", 3)                  // ERROR "wrong number of args for format in Printf call"
+	_ = fmt.Sprintf("%"+("s"), "hi", 3)        // ERROR "wrong number of args for format in Sprintf call"
+	fmt.Printf("%s%%%d", "hi", 3)              // correct
+	fmt.Printf("%08s", "woo")                  // correct
+	fmt.Printf("% 8s", "woo")                  // correct
+	fmt.Printf("%.*d", 3, 3)                   // correct
+	fmt.Printf("%.*d", 3, 3, 3, 3)             // ERROR "wrong number of args for format in Printf call.*4 args"
+	fmt.Printf("%.*d", "hi", 3)                // ERROR "arg .hi. for \* in printf format not of type int"
+	fmt.Printf("%.*d", i, 3)                   // correct
+	fmt.Printf("%.*d", s, 3)                   // ERROR "arg s for \* in printf format not of type int"
+	fmt.Printf("%*%", 0.22)                    // ERROR "arg 0.22 for \* in printf format not of type int"
+	fmt.Printf("%q %q", multi()...)            // ok
+	fmt.Printf("%#q", `blah`)                  // ok
+	printf("now is the time", "buddy")         // ERROR "no formatting directive"
+	Printf("now is the time", "buddy")         // ERROR "no formatting directive"
+	Printf("hi")                               // ok
+	const format = "%s %s\n"
+	Printf(format, "hi", "there")
+	Printf(format, "hi")              // ERROR "missing argument for Printf..%s..: format reads arg 2, have only 1"
+	Printf("%s %d %.3v %q", "str", 4) // ERROR "missing argument for Printf..%.3v..: format reads arg 3, have only 2"
+	f := new(stringer)
+	f.Warn(0, "%s", "hello", 3)  // ERROR "possible formatting directive in Warn call"
+	f.Warnf(0, "%s", "hello", 3) // ERROR "wrong number of args for format in Warnf call"
+	f.Warnf(0, "%r", "hello")    // ERROR "unrecognized printf verb"
+	f.Warnf(0, "%#s", "hello")   // ERROR "unrecognized printf flag"
+	Printf("d%", 2)              // ERROR "missing verb at end of format string in Printf call"
+	Printf("%d", percentDV)
+	Printf("%d", &percentDV)
+	Printf("%d", notPercentDV)  // ERROR "arg notPercentDV for printf verb %d of wrong type"
+	Printf("%d", &notPercentDV) // ERROR "arg &notPercentDV for printf verb %d of wrong type"
+	Printf("%p", &notPercentDV) // Works regardless: we print it as a pointer.
+	Printf("%s", percentSV)
+	Printf("%s", &percentSV)
+	// Good argument reorderings.
+	Printf("%[1]d", 3)
+	Printf("%[1]*d", 3, 1)
+	Printf("%[2]*[1]d", 1, 3)
+	Printf("%[2]*.[1]*[3]d", 2, 3, 4)
+	fmt.Fprintf(os.Stderr, "%[2]*.[1]*[3]d", 2, 3, 4) // Use Fprintf to make sure we count arguments correctly.
+	// Bad argument reorderings.
+	Printf("%[xd", 3)                    // ERROR "illegal syntax for printf argument index"
+	Printf("%[x]d", 3)                   // ERROR "illegal syntax for printf argument index"
+	Printf("%[3]*s", "hi", 2)            // ERROR "missing argument for Printf.* reads arg 3, have only 2"
+	_ = fmt.Sprintf("%[3]d", 2)          // ERROR "missing argument for Sprintf.* reads arg 3, have only 1"
+	Printf("%[2]*.[1]*[3]d", 2, "hi", 4) // ERROR "arg .hi. for \* in printf format not of type int"
+	Printf("%[0]s", "arg1")              // ERROR "index value \[0\] for Printf.*; indexes start at 1"
+	Printf("%[0]d", 1)                   // ERROR "index value \[0\] for Printf.*; indexes start at 1"
+	// Something that satisfies the error interface.
+	var e error
+	fmt.Println(e.Error()) // ok
+	// Something that looks like an error interface but isn't, such as the (*T).Error method
+	// in the testing package.
+	var et1 errorTest1
+	fmt.Println(et1.Error())        // ERROR "no args in Error call"
+	fmt.Println(et1.Error("hi"))    // ok
+	fmt.Println(et1.Error("%d", 3)) // ERROR "possible formatting directive in Error call"
+	var et2 errorTest2
+	et2.Error()        // ERROR "no args in Error call"
+	et2.Error("hi")    // ok, not an error method.
+	et2.Error("%d", 3) // ERROR "possible formatting directive in Error call"
+	var et3 errorTest3
+	et3.Error() // ok, not an error method.
+	var et4 errorTest4
+	et4.Error() // ok, not an error method.
+	var et5 errorTest5
+	et5.error() // ok, not an error method.
+	// Bug: used to recur forever.
+	Printf("%p %x", recursiveStructV, recursiveStructV.next)
+	Printf("%p %x", recursiveStruct1V, recursiveStruct1V.next)
+	Printf("%p %x", recursiveSliceV, recursiveSliceV)
+	Printf("%p %x", recursiveMapV, recursiveMapV)
+	// Special handling for Log.
+	math.Log(3)  // OK
+	Log(3)       // OK
+	Log("%d", 3) // ERROR "possible formatting directive in Log call"
+	Logf("%d", 3)
+	Logf("%d", "hi") // ERROR "arg .hi. for printf verb %d of wrong type: untyped string"
+
+}
+
+// Printf is used by the test so we must declare it.
+func Printf(format string, args ...interface{}) {
+	panic("don't call - testing only")
+}
+
+// printf is used by the test so we must declare it.
+func printf(format string, args ...interface{}) {
+	panic("don't call - testing only")
+}
+
+// multi is used by the test.
+func multi() []interface{} {
+	panic("don't call - testing only")
+}
+
+type stringer float64
+
+var stringerv stringer
+
+func (*stringer) String() string {
+	return "string"
+}
+
+func (*stringer) Warn(int, ...interface{}) string {
+	return "warn"
+}
+
+func (*stringer) Warnf(int, string, ...interface{}) string {
+	return "warnf"
+}
+
+type notstringer struct {
+	f float64
+}
+
+var notstringerv notstringer
+
+type stringerarray [4]float64
+
+func (stringerarray) String() string {
+	return "string"
+}
+
+var stringerarrayv stringerarray
+
+type notstringerarray [4]float64
+
+var notstringerarrayv notstringerarray
+
+var nonemptyinterface = interface {
+	f()
+}(nil)
+
+// A data type we can print with "%d".
+type percentDStruct struct {
+	a int
+	b []byte
+	c *float64
+}
+
+var percentDV percentDStruct
+
+// A data type we cannot print correctly with "%d".
+type notPercentDStruct struct {
+	a int
+	b []byte
+	c bool
+}
+
+var notPercentDV notPercentDStruct
+
+// A data type we can print with "%s".
+type percentSStruct struct {
+	a string
+	b []byte
+	c stringerarray
+}
+
+var percentSV percentSStruct
+
+type recursiveStringer int
+
+func (s recursiveStringer) String() string {
+	_ = fmt.Sprintf("%d", s)
+	_ = fmt.Sprintf("%#v", s)
+	_ = fmt.Sprintf("%v", s)  // ERROR "arg s for printf causes recursive call to String method"
+	_ = fmt.Sprintf("%v", &s) // ERROR "arg &s for printf causes recursive call to String method"
+	_ = fmt.Sprintf("%T", s)  // ok; does not recursively call String
+	return fmt.Sprintln(s)    // ERROR "arg s for print causes recursive call to String method"
+}
+
+type recursivePtrStringer int
+
+func (p *recursivePtrStringer) String() string {
+	_ = fmt.Sprintf("%v", *p)
+	return fmt.Sprintln(p) // ERROR "arg p for print causes recursive call to String method"
+}
+
+type Formatter bool
+
+func (*Formatter) Format(fmt.State, rune) {
+}
+
+type RecursiveSlice []RecursiveSlice
+
+var recursiveSliceV = &RecursiveSlice{}
+
+type RecursiveMap map[int]RecursiveMap
+
+var recursiveMapV = make(RecursiveMap)
+
+type RecursiveStruct struct {
+	next *RecursiveStruct
+}
+
+var recursiveStructV = &RecursiveStruct{}
+
+type RecursiveStruct1 struct {
+	next *Recursive2Struct
+}
+
+type RecursiveStruct2 struct {
+	next *Recursive1Struct
+}
+
+var recursiveStruct1V = &RecursiveStruct1{}
+
+// Fix for issue 7149: Missing return type on String method caused fault.
+func (int) String() {
+	return ""
+}
diff --git a/src/cmd/vet/testdata/rangeloop.go b/src/cmd/vet/testdata/rangeloop.go
new file mode 100644
index 0000000..37b5940
--- /dev/null
+++ b/src/cmd/vet/testdata/rangeloop.go
@@ -0,0 +1,59 @@
+// 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.
+
+// This file contains tests for the rangeloop checker.
+
+package testdata
+
+func RangeLoopTests() {
+	var s []int
+	for i, v := range s {
+		go func() {
+			println(i) // ERROR "range variable i captured by func literal"
+			println(v) // ERROR "range variable v captured by func literal"
+		}()
+	}
+	for i, v := range s {
+		defer func() {
+			println(i) // ERROR "range variable i captured by func literal"
+			println(v) // ERROR "range variable v captured by func literal"
+		}()
+	}
+	for i := range s {
+		go func() {
+			println(i) // ERROR "range variable i captured by func literal"
+		}()
+	}
+	for _, v := range s {
+		go func() {
+			println(v) // ERROR "range variable v captured by func literal"
+		}()
+	}
+	for i, v := range s {
+		go func() {
+			println(i, v)
+		}()
+		println("unfortunately, we don't catch the error above because of this statement")
+	}
+	for i, v := range s {
+		go func(i, v int) {
+			println(i, v)
+		}(i, v)
+	}
+	for i, v := range s {
+		i, v := i, v
+		go func() {
+			println(i, v)
+		}()
+	}
+	// If the key of the range statement is not an identifier
+	// the code should not panic (it used to).
+	var x [2]int
+	var f int
+	for x[0], f = range s {
+		go func() {
+			_ = f // ERROR "range variable f captured by func literal"
+		}()
+	}
+}
diff --git a/src/cmd/vet/testdata/shadow.go b/src/cmd/vet/testdata/shadow.go
new file mode 100644
index 0000000..34a6806
--- /dev/null
+++ b/src/cmd/vet/testdata/shadow.go
@@ -0,0 +1,54 @@
+// 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.
+
+// This file contains tests for the shadowed variable checker.
+// Some of these errors are caught by the compiler (shadowed return parameters for example)
+// but are nonetheless useful tests.
+
+package testdata
+
+import "os"
+
+func ShadowRead(f *os.File, buf []byte) (err error) {
+	var x int
+	if f != nil {
+		err := 3 // OK - different type.
+		_ = err
+	}
+	if f != nil {
+		_, err := f.Read(buf) // ERROR "declaration of err shadows declaration at testdata/shadow.go:13"
+		if err != nil {
+			return err
+		}
+		i := 3 // OK
+		_ = i
+	}
+	if f != nil {
+		var _, err = f.Read(buf) // ERROR "declaration of err shadows declaration at testdata/shadow.go:13"
+		if err != nil {
+			return err
+		}
+	}
+	for i := 0; i < 10; i++ {
+		i := i // OK: obviously intentional idiomatic redeclaration
+		go func() {
+			println(i)
+		}()
+	}
+	var shadowTemp interface{}
+	switch shadowTemp := shadowTemp.(type) { // OK: obviously intentional idiomatic redeclaration
+	case int:
+		println("OK")
+		_ = shadowTemp
+	}
+	if shadowTemp := shadowTemp; true { // OK: obviously intentional idiomatic redeclaration
+		var f *os.File // OK because f is not mentioned later in the function.
+		// The declaration of x is a shadow because x is mentioned below.
+		var x int // ERROR "declaration of x shadows declaration at testdata/shadow.go:14"
+		_, _, _ = x, f, shadowTemp
+	}
+	// Use a couple of variables to trigger shadowing errors.
+	_, _ = err, x
+	return
+}
diff --git a/src/cmd/vet/testdata/shift.go b/src/cmd/vet/testdata/shift.go
new file mode 100644
index 0000000..6624f09
--- /dev/null
+++ b/src/cmd/vet/testdata/shift.go
@@ -0,0 +1,78 @@
+// 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.
+
+// This file contains tests for the suspicious shift checker.
+
+package testdata
+
+func ShiftTest() {
+	var i8 int8
+	_ = i8 << 7
+	_ = (i8 + 1) << 8 // ERROR "\(i8 \+ 1\) too small for shift of 8"
+	_ = i8 << (7 + 1) // ERROR "i8 too small for shift of 8"
+	_ = i8 >> 8       // ERROR "i8 too small for shift of 8"
+	i8 <<= 8          // ERROR "i8 too small for shift of 8"
+	i8 >>= 8          // ERROR "i8 too small for shift of 8"
+	var i16 int16
+	_ = i16 << 15
+	_ = i16 << 16 // ERROR "i16 too small for shift of 16"
+	_ = i16 >> 16 // ERROR "i16 too small for shift of 16"
+	i16 <<= 16    // ERROR "i16 too small for shift of 16"
+	i16 >>= 16    // ERROR "i16 too small for shift of 16"
+	var i32 int32
+	_ = i32 << 31
+	_ = i32 << 32 // ERROR "i32 too small for shift of 32"
+	_ = i32 >> 32 // ERROR "i32 too small for shift of 32"
+	i32 <<= 32    // ERROR "i32 too small for shift of 32"
+	i32 >>= 32    // ERROR "i32 too small for shift of 32"
+	var i64 int64
+	_ = i64 << 63
+	_ = i64 << 64 // ERROR "i64 too small for shift of 64"
+	_ = i64 >> 64 // ERROR "i64 too small for shift of 64"
+	i64 <<= 64    // ERROR "i64 too small for shift of 64"
+	i64 >>= 64    // ERROR "i64 too small for shift of 64"
+	var u8 uint8
+	_ = u8 << 7
+	_ = u8 << 8 // ERROR "u8 too small for shift of 8"
+	_ = u8 >> 8 // ERROR "u8 too small for shift of 8"
+	u8 <<= 8    // ERROR "u8 too small for shift of 8"
+	u8 >>= 8    // ERROR "u8 too small for shift of 8"
+	var u16 uint16
+	_ = u16 << 15
+	_ = u16 << 16 // ERROR "u16 too small for shift of 16"
+	_ = u16 >> 16 // ERROR "u16 too small for shift of 16"
+	u16 <<= 16    // ERROR "u16 too small for shift of 16"
+	u16 >>= 16    // ERROR "u16 too small for shift of 16"
+	var u32 uint32
+	_ = u32 << 31
+	_ = u32 << 32 // ERROR "u32 too small for shift of 32"
+	_ = u32 >> 32 // ERROR "u32 too small for shift of 32"
+	u32 <<= 32    // ERROR "u32 too small for shift of 32"
+	u32 >>= 32    // ERROR "u32 too small for shift of 32"
+	var u64 uint64
+	_ = u64 << 63
+	_ = u64 << 64  // ERROR "u64 too small for shift of 64"
+	_ = u64 >> 64  // ERROR "u64 too small for shift of 64"
+	u64 <<= 64     // ERROR "u64 too small for shift of 64"
+	u64 >>= 64     // ERROR "u64 too small for shift of 64"
+	_ = u64 << u64 // Non-constant shifts should succeed.
+	var i int
+	_ = i << 31
+	_ = i << 32 // ERROR "i might be too small for shift of 32"
+	_ = i >> 32 // ERROR "i might be too small for shift of 32"
+	i <<= 32    // ERROR "i might be too small for shift of 32"
+	i >>= 32    // ERROR "i might be too small for shift of 32"
+	var u uint
+	_ = u << 31
+	_ = u << 32 // ERROR "u might be too small for shift of 32"
+	_ = u >> 32 // ERROR "u might be too small for shift of 32"
+	u <<= 32    // ERROR "u might be too small for shift of 32"
+	u >>= 32    // ERROR "u might be too small for shift of 32"
+	var p uintptr
+	_ = p << 31
+	_ = p << 32 // ERROR "p might be too small for shift of 32"
+	_ = p >> 32 // ERROR "p might be too small for shift of 32"
+	p <<= 32    // ERROR "p might be too small for shift of 32"
+	p >>= 32    // ERROR "p might be too small for shift of 32"
+}
diff --git a/src/cmd/vet/testdata/structtag.go b/src/cmd/vet/testdata/structtag.go
new file mode 100644
index 0000000..6878f56
--- /dev/null
+++ b/src/cmd/vet/testdata/structtag.go
@@ -0,0 +1,36 @@
+// Copyright 2010 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 contains the test for canonical struct tags.
+
+package testdata
+
+type StructTagTest struct {
+	A   int "hello"            // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag pair"
+	B   int "\tx:\"y\""        // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag key"
+	C   int "x:\"y\"\tx:\"y\"" // ERROR "not compatible with reflect.StructTag.Get"
+	D   int "x:`y`"            // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag value"
+	E   int "ct\brl:\"char\""  // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag pair"
+	F   int `:"emptykey"`      // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag key"
+	G   int `x:"noEndQuote`    // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag value"
+	H   int `x:"trunc\x0"`     // ERROR "not compatible with reflect.StructTag.Get: bad syntax for struct tag value"
+	OK0 int `x:"y" u:"v" w:""`
+	OK1 int `x:"y:z" u:"v" w:""` // note multiple colons.
+	OK2 int "k0:\"values contain spaces\" k1:\"literal\ttabs\" k2:\"and\\tescaped\\tabs\""
+	OK3 int `under_scores:"and" CAPS:"ARE_OK"`
+}
+
+type UnexportedEncodingTagTest struct {
+	x int `json:"xx"` // ERROR "struct field x has json tag but is not exported"
+	y int `xml:"yy"`  // ERROR "struct field y has xml tag but is not exported"
+	z int
+	A int `json:"aa" xml:"bb"`
+}
+
+type unexp struct{}
+
+type JSONEmbeddedField struct {
+	UnexportedEncodingTagTest `is:"embedded"`
+	unexp                     `is:"embedded,notexported" json:"unexp"` // OK for now, see issue 7363
+}
diff --git a/src/cmd/vet/testdata/tagtest/file1.go b/src/cmd/vet/testdata/tagtest/file1.go
new file mode 100644
index 0000000..22a1509
--- /dev/null
+++ b/src/cmd/vet/testdata/tagtest/file1.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 testtag
+
+package main
+
+func main() {
+}
diff --git a/src/cmd/vet/testdata/tagtest/file2.go b/src/cmd/vet/testdata/tagtest/file2.go
new file mode 100644
index 0000000..ba7dd91
--- /dev/null
+++ b/src/cmd/vet/testdata/tagtest/file2.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 !testtag
+
+package main
+
+func ignore() {
+}
diff --git a/src/cmd/vet/testdata/unsafeptr.go b/src/cmd/vet/testdata/unsafeptr.go
new file mode 100644
index 0000000..8f64030
--- /dev/null
+++ b/src/cmd/vet/testdata/unsafeptr.go
@@ -0,0 +1,61 @@
+// 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 testdata
+
+import (
+	"reflect"
+	"unsafe"
+)
+
+func f() {
+	var x unsafe.Pointer
+	var y uintptr
+	x = unsafe.Pointer(y) // ERROR "possible misuse of unsafe.Pointer"
+	y = uintptr(x)
+
+	// only allowed pointer arithmetic is ptr +/- num.
+	// num+ptr is technically okay but still flagged: write ptr+num instead.
+	x = unsafe.Pointer(uintptr(x) + 1)
+	x = unsafe.Pointer(1 + uintptr(x))          // ERROR "possible misuse of unsafe.Pointer"
+	x = unsafe.Pointer(uintptr(x) + uintptr(x)) // ERROR "possible misuse of unsafe.Pointer"
+	x = unsafe.Pointer(uintptr(x) - 1)
+	x = unsafe.Pointer(1 - uintptr(x)) // ERROR "possible misuse of unsafe.Pointer"
+
+	// certain uses of reflect are okay
+	var v reflect.Value
+	x = unsafe.Pointer(v.Pointer())
+	x = unsafe.Pointer(v.UnsafeAddr())
+	var s1 *reflect.StringHeader
+	x = unsafe.Pointer(s1.Data)
+	var s2 *reflect.SliceHeader
+	x = unsafe.Pointer(s2.Data)
+	var s3 reflect.StringHeader
+	x = unsafe.Pointer(s3.Data) // ERROR "possible misuse of unsafe.Pointer"
+	var s4 reflect.SliceHeader
+	x = unsafe.Pointer(s4.Data) // ERROR "possible misuse of unsafe.Pointer"
+
+	// but only in reflect
+	var vv V
+	x = unsafe.Pointer(vv.Pointer())    // ERROR "possible misuse of unsafe.Pointer"
+	x = unsafe.Pointer(vv.UnsafeAddr()) // ERROR "possible misuse of unsafe.Pointer"
+	var ss1 *StringHeader
+	x = unsafe.Pointer(ss1.Data) // ERROR "possible misuse of unsafe.Pointer"
+	var ss2 *SliceHeader
+	x = unsafe.Pointer(ss2.Data) // ERROR "possible misuse of unsafe.Pointer"
+
+}
+
+type V interface {
+	Pointer() uintptr
+	UnsafeAddr() uintptr
+}
+
+type StringHeader struct {
+	Data uintptr
+}
+
+type SliceHeader struct {
+	Data uintptr
+}
diff --git a/src/cmd/vet/testdata/unused.go b/src/cmd/vet/testdata/unused.go
new file mode 100644
index 0000000..d50f659
--- /dev/null
+++ b/src/cmd/vet/testdata/unused.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.
+
+// This file contains tests for the unusedresult checker.
+
+package testdata
+
+import (
+	"bytes"
+	"errors"
+	"fmt"
+)
+
+func _() {
+	fmt.Errorf("") // ERROR "result of fmt.Errorf call not used"
+	_ = fmt.Errorf("")
+
+	errors.New("") // ERROR "result of errors.New call not used"
+
+	err := errors.New("")
+	err.Error() // ERROR "result of \(error\).Error call not used"
+
+	var buf bytes.Buffer
+	buf.String() // ERROR "result of \(bytes.Buffer\).String call not used"
+
+	fmt.Sprint("")  // ERROR "result of fmt.Sprint call not used"
+	fmt.Sprintf("") // ERROR "result of fmt.Sprintf call not used"
+}
diff --git a/src/cmd/vet/types.go b/src/cmd/vet/types.go
new file mode 100644
index 0000000..692bae6
--- /dev/null
+++ b/src/cmd/vet/types.go
@@ -0,0 +1,370 @@
+// Copyright 2010 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 contains the pieces of the tool that use typechecking from the go/types package.
+
+package main
+
+import (
+	"go/ast"
+	"go/importer"
+	"go/token"
+	"go/types"
+)
+
+// stdImporter is the importer we use to import packages.
+// It is created during initialization so that all packages
+// are imported by the same importer.
+var stdImporter = importer.Default()
+
+var (
+	errorType     *types.Interface
+	stringerType  *types.Interface // possibly nil
+	formatterType *types.Interface // possibly nil
+)
+
+func init() {
+	errorType = types.Universe.Lookup("error").Type().Underlying().(*types.Interface)
+
+	if typ := importType("fmt", "Stringer"); typ != nil {
+		stringerType = typ.Underlying().(*types.Interface)
+	}
+
+	if typ := importType("fmt", "Formatter"); typ != nil {
+		formatterType = typ.Underlying().(*types.Interface)
+	}
+}
+
+// importType returns the type denoted by the qualified identifier
+// path.name, and adds the respective package to the imports map
+// as a side effect. In case of an error, importType returns nil.
+func importType(path, name string) types.Type {
+	pkg, err := stdImporter.Import(path)
+	if err != nil {
+		// This can happen if the package at path hasn't been compiled yet.
+		warnf("import failed: %v", err)
+		return nil
+	}
+	if obj, ok := pkg.Scope().Lookup(name).(*types.TypeName); ok {
+		return obj.Type()
+	}
+	warnf("invalid type name %q", name)
+	return nil
+}
+
+func (pkg *Package) check(fs *token.FileSet, astFiles []*ast.File) error {
+	pkg.defs = make(map[*ast.Ident]types.Object)
+	pkg.uses = make(map[*ast.Ident]types.Object)
+	pkg.selectors = make(map[*ast.SelectorExpr]*types.Selection)
+	pkg.spans = make(map[types.Object]Span)
+	pkg.types = make(map[ast.Expr]types.TypeAndValue)
+	config := types.Config{
+		// We use the same importer for all imports to ensure that
+		// everybody sees identical packages for the given paths.
+		Importer: stdImporter,
+		// By providing a Config with our own error function, it will continue
+		// past the first error. There is no need for that function to do anything.
+		Error: func(error) {},
+	}
+	info := &types.Info{
+		Selections: pkg.selectors,
+		Types:      pkg.types,
+		Defs:       pkg.defs,
+		Uses:       pkg.uses,
+	}
+	typesPkg, err := config.Check(pkg.path, fs, astFiles, info)
+	pkg.typesPkg = typesPkg
+	// update spans
+	for id, obj := range pkg.defs {
+		pkg.growSpan(id, obj)
+	}
+	for id, obj := range pkg.uses {
+		pkg.growSpan(id, obj)
+	}
+	return err
+}
+
+// isStruct reports whether the composite literal c is a struct.
+// If it is not (probably a struct), it returns a printable form of the type.
+func (pkg *Package) isStruct(c *ast.CompositeLit) (bool, string) {
+	// Check that the CompositeLit's type is a slice or array (which needs no field keys), if possible.
+	typ := pkg.types[c].Type
+	// If it's a named type, pull out the underlying type. If it's not, the Underlying
+	// method returns the type itself.
+	actual := typ
+	if actual != nil {
+		actual = actual.Underlying()
+	}
+	if actual == nil {
+		// No type information available. Assume true, so we do the check.
+		return true, ""
+	}
+	switch actual.(type) {
+	case *types.Struct:
+		return true, typ.String()
+	default:
+		return false, ""
+	}
+}
+
+// matchArgType reports an error if printf verb t is not appropriate
+// for operand arg.
+//
+// typ is used only for recursive calls; external callers must supply nil.
+//
+// (Recursion arises from the compound types {map,chan,slice} which
+// may be printed with %d etc. if that is appropriate for their element
+// types.)
+func (f *File) matchArgType(t printfArgType, typ types.Type, arg ast.Expr) bool {
+	return f.matchArgTypeInternal(t, typ, arg, make(map[types.Type]bool))
+}
+
+// matchArgTypeInternal is the internal version of matchArgType. It carries a map
+// remembering what types are in progress so we don't recur when faced with recursive
+// types or mutually recursive types.
+func (f *File) matchArgTypeInternal(t printfArgType, typ types.Type, arg ast.Expr, inProgress map[types.Type]bool) bool {
+	// %v, %T accept any argument type.
+	if t == anyType {
+		return true
+	}
+	if typ == nil {
+		// external call
+		typ = f.pkg.types[arg].Type
+		if typ == nil {
+			return true // probably a type check problem
+		}
+	}
+	// If the type implements fmt.Formatter, we have nothing to check.
+	// formatterTyp may be nil - be conservative and check for Format method in that case.
+	if formatterType != nil && types.Implements(typ, formatterType) || f.hasMethod(typ, "Format") {
+		return true
+	}
+	// If we can use a string, might arg (dynamically) implement the Stringer or Error interface?
+	if t&argString != 0 {
+		if types.AssertableTo(errorType, typ) || stringerType != nil && types.AssertableTo(stringerType, typ) {
+			return true
+		}
+	}
+
+	typ = typ.Underlying()
+	if inProgress[typ] {
+		// We're already looking at this type. The call that started it will take care of it.
+		return true
+	}
+	inProgress[typ] = true
+
+	switch typ := typ.(type) {
+	case *types.Signature:
+		return t&argPointer != 0
+
+	case *types.Map:
+		// Recur: map[int]int matches %d.
+		return t&argPointer != 0 ||
+			(f.matchArgTypeInternal(t, typ.Key(), arg, inProgress) && f.matchArgTypeInternal(t, typ.Elem(), arg, inProgress))
+
+	case *types.Chan:
+		return t&argPointer != 0
+
+	case *types.Array:
+		// Same as slice.
+		if types.Identical(typ.Elem().Underlying(), types.Typ[types.Byte]) && t&argString != 0 {
+			return true // %s matches []byte
+		}
+		// Recur: []int matches %d.
+		return t&argPointer != 0 || f.matchArgTypeInternal(t, typ.Elem().Underlying(), arg, inProgress)
+
+	case *types.Slice:
+		// Same as array.
+		if types.Identical(typ.Elem().Underlying(), types.Typ[types.Byte]) && t&argString != 0 {
+			return true // %s matches []byte
+		}
+		// Recur: []int matches %d. But watch out for
+		//	type T []T
+		// If the element is a pointer type (type T[]*T), it's handled fine by the Pointer case below.
+		return t&argPointer != 0 || f.matchArgTypeInternal(t, typ.Elem(), arg, inProgress)
+
+	case *types.Pointer:
+		// Ugly, but dealing with an edge case: a known pointer to an invalid type,
+		// probably something from a failed import.
+		if typ.Elem().String() == "invalid type" {
+			if *verbose {
+				f.Warnf(arg.Pos(), "printf argument %v is pointer to invalid or unknown type", f.gofmt(arg))
+			}
+			return true // special case
+		}
+		// If it's actually a pointer with %p, it prints as one.
+		if t == argPointer {
+			return true
+		}
+		// If it's pointer to struct, that's equivalent in our analysis to whether we can print the struct.
+		if str, ok := typ.Elem().Underlying().(*types.Struct); ok {
+			return f.matchStructArgType(t, str, arg, inProgress)
+		}
+		// The rest can print with %p as pointers, or as integers with %x etc.
+		return t&(argInt|argPointer) != 0
+
+	case *types.Struct:
+		return f.matchStructArgType(t, typ, arg, inProgress)
+
+	case *types.Interface:
+		// If the static type of the argument is empty interface, there's little we can do.
+		// Example:
+		//	func f(x interface{}) { fmt.Printf("%s", x) }
+		// Whether x is valid for %s depends on the type of the argument to f. One day
+		// we will be able to do better. For now, we assume that empty interface is OK
+		// but non-empty interfaces, with Stringer and Error handled above, are errors.
+		return typ.NumMethods() == 0
+
+	case *types.Basic:
+		switch typ.Kind() {
+		case types.UntypedBool,
+			types.Bool:
+			return t&argBool != 0
+
+		case types.UntypedInt,
+			types.Int,
+			types.Int8,
+			types.Int16,
+			types.Int32,
+			types.Int64,
+			types.Uint,
+			types.Uint8,
+			types.Uint16,
+			types.Uint32,
+			types.Uint64,
+			types.Uintptr:
+			return t&argInt != 0
+
+		case types.UntypedFloat,
+			types.Float32,
+			types.Float64:
+			return t&argFloat != 0
+
+		case types.UntypedComplex,
+			types.Complex64,
+			types.Complex128:
+			return t&argComplex != 0
+
+		case types.UntypedString,
+			types.String:
+			return t&argString != 0
+
+		case types.UnsafePointer:
+			return t&(argPointer|argInt) != 0
+
+		case types.UntypedRune:
+			return t&(argInt|argRune) != 0
+
+		case types.UntypedNil:
+			return t&argPointer != 0 // TODO?
+
+		case types.Invalid:
+			if *verbose {
+				f.Warnf(arg.Pos(), "printf argument %v has invalid or unknown type", f.gofmt(arg))
+			}
+			return true // Probably a type check problem.
+		}
+		panic("unreachable")
+	}
+
+	return false
+}
+
+// hasBasicType reports whether x's type is a types.Basic with the given kind.
+func (f *File) hasBasicType(x ast.Expr, kind types.BasicKind) bool {
+	t := f.pkg.types[x].Type
+	if t != nil {
+		t = t.Underlying()
+	}
+	b, ok := t.(*types.Basic)
+	return ok && b.Kind() == kind
+}
+
+// matchStructArgType reports whether all the elements of the struct match the expected
+// type. For instance, with "%d" all the elements must be printable with the "%d" format.
+func (f *File) matchStructArgType(t printfArgType, typ *types.Struct, arg ast.Expr, inProgress map[types.Type]bool) bool {
+	for i := 0; i < typ.NumFields(); i++ {
+		if !f.matchArgTypeInternal(t, typ.Field(i).Type(), arg, inProgress) {
+			return false
+		}
+	}
+	return true
+}
+
+// numArgsInSignature tells how many formal arguments the function type
+// being called has.
+func (f *File) numArgsInSignature(call *ast.CallExpr) int {
+	// Check the type of the function or method declaration
+	typ := f.pkg.types[call.Fun].Type
+	if typ == nil {
+		return 0
+	}
+	// The type must be a signature, but be sure for safety.
+	sig, ok := typ.(*types.Signature)
+	if !ok {
+		return 0
+	}
+	return sig.Params().Len()
+}
+
+// isErrorMethodCall reports whether the call is of a method with signature
+//	func Error() string
+// where "string" is the universe's string type. We know the method is called "Error".
+func (f *File) isErrorMethodCall(call *ast.CallExpr) bool {
+	typ := f.pkg.types[call].Type
+	if typ != nil {
+		// We know it's called "Error", so just check the function signature
+		// (stringerType has exactly one method, String).
+		if stringerType != nil && stringerType.NumMethods() == 1 {
+			return types.Identical(f.pkg.types[call.Fun].Type, stringerType.Method(0).Type())
+		}
+	}
+	// Without types, we can still check by hand.
+	// Is it a selector expression? Otherwise it's a function call, not a method call.
+	sel, ok := call.Fun.(*ast.SelectorExpr)
+	if !ok {
+		return false
+	}
+	// The package is type-checked, so if there are no arguments, we're done.
+	if len(call.Args) > 0 {
+		return false
+	}
+	// Check the type of the method declaration
+	typ = f.pkg.types[sel].Type
+	if typ == nil {
+		return false
+	}
+	// The type must be a signature, but be sure for safety.
+	sig, ok := typ.(*types.Signature)
+	if !ok {
+		return false
+	}
+	// There must be a receiver for it to be a method call. Otherwise it is
+	// a function, not something that satisfies the error interface.
+	if sig.Recv() == nil {
+		return false
+	}
+	// There must be no arguments. Already verified by type checking, but be thorough.
+	if sig.Params().Len() > 0 {
+		return false
+	}
+	// Finally the real questions.
+	// There must be one result.
+	if sig.Results().Len() != 1 {
+		return false
+	}
+	// It must have return type "string" from the universe.
+	return sig.Results().At(0).Type() == types.Typ[types.String]
+}
+
+// hasMethod reports whether the type contains a method with the given name.
+// It is part of the workaround for Formatters and should be deleted when
+// that workaround is no longer necessary.
+// TODO: This could be better once issue 6259 is fixed.
+func (f *File) hasMethod(typ types.Type, name string) bool {
+	// assume we have an addressable variable of type typ
+	obj, _, _ := types.LookupFieldOrMethod(typ, true, f.pkg.typesPkg, name)
+	_, ok := obj.(*types.Func)
+	return ok
+}
diff --git a/src/cmd/vet/unsafeptr.go b/src/cmd/vet/unsafeptr.go
new file mode 100644
index 0000000..9ca27dc
--- /dev/null
+++ b/src/cmd/vet/unsafeptr.go
@@ -0,0 +1,97 @@
+// 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.
+
+// Check for invalid uintptr -> unsafe.Pointer conversions.
+
+package main
+
+import (
+	"go/ast"
+	"go/token"
+	"go/types"
+)
+
+func init() {
+	register("unsafeptr",
+		"check for misuse of unsafe.Pointer",
+		checkUnsafePointer,
+		callExpr)
+}
+
+func checkUnsafePointer(f *File, node ast.Node) {
+	x := node.(*ast.CallExpr)
+	if len(x.Args) != 1 {
+		return
+	}
+	if f.hasBasicType(x.Fun, types.UnsafePointer) && f.hasBasicType(x.Args[0], types.Uintptr) && !f.isSafeUintptr(x.Args[0]) {
+		f.Badf(x.Pos(), "possible misuse of unsafe.Pointer")
+	}
+}
+
+// isSafeUintptr reports whether x - already known to be a uintptr -
+// is safe to convert to unsafe.Pointer. It is safe if x is itself derived
+// directly from an unsafe.Pointer via conversion and pointer arithmetic
+// or if x is the result of reflect.Value.Pointer or reflect.Value.UnsafeAddr
+// or obtained from the Data field of a *reflect.SliceHeader or *reflect.StringHeader.
+func (f *File) isSafeUintptr(x ast.Expr) bool {
+	switch x := x.(type) {
+	case *ast.ParenExpr:
+		return f.isSafeUintptr(x.X)
+
+	case *ast.SelectorExpr:
+		switch x.Sel.Name {
+		case "Data":
+			// reflect.SliceHeader and reflect.StringHeader are okay,
+			// but only if they are pointing at a real slice or string.
+			// It's not okay to do:
+			//	var x SliceHeader
+			//	x.Data = uintptr(unsafe.Pointer(...))
+			//	... use x ...
+			//	p := unsafe.Pointer(x.Data)
+			// because in the middle the garbage collector doesn't
+			// see x.Data as a pointer and so x.Data may be dangling
+			// by the time we get to the conversion at the end.
+			// For now approximate by saying that *Header is okay
+			// but Header is not.
+			pt, ok := f.pkg.types[x.X].Type.(*types.Pointer)
+			if ok {
+				t, ok := pt.Elem().(*types.Named)
+				if ok && t.Obj().Pkg().Path() == "reflect" {
+					switch t.Obj().Name() {
+					case "StringHeader", "SliceHeader":
+						return true
+					}
+				}
+			}
+		}
+
+	case *ast.CallExpr:
+		switch len(x.Args) {
+		case 0:
+			// maybe call to reflect.Value.Pointer or reflect.Value.UnsafeAddr.
+			sel, ok := x.Fun.(*ast.SelectorExpr)
+			if !ok {
+				break
+			}
+			switch sel.Sel.Name {
+			case "Pointer", "UnsafeAddr":
+				t, ok := f.pkg.types[sel.X].Type.(*types.Named)
+				if ok && t.Obj().Pkg().Path() == "reflect" && t.Obj().Name() == "Value" {
+					return true
+				}
+			}
+
+		case 1:
+			// maybe conversion of uintptr to unsafe.Pointer
+			return f.hasBasicType(x.Fun, types.Uintptr) && f.hasBasicType(x.Args[0], types.UnsafePointer)
+		}
+
+	case *ast.BinaryExpr:
+		switch x.Op {
+		case token.ADD, token.SUB:
+			return f.isSafeUintptr(x.X) && !f.isSafeUintptr(x.Y)
+		}
+	}
+	return false
+}
diff --git a/src/cmd/vet/unused.go b/src/cmd/vet/unused.go
new file mode 100644
index 0000000..df2317a
--- /dev/null
+++ b/src/cmd/vet/unused.go
@@ -0,0 +1,93 @@
+// 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 defines the check for unused results of calls to certain
+// pure functions.
+
+package main
+
+import (
+	"flag"
+	"go/ast"
+	"go/token"
+	"go/types"
+	"strings"
+)
+
+var unusedFuncsFlag = flag.String("unusedfuncs",
+	"errors.New,fmt.Errorf,fmt.Sprintf,fmt.Sprint,sort.Reverse",
+	"comma-separated list of functions whose results must be used")
+
+var unusedStringMethodsFlag = flag.String("unusedstringmethods",
+	"Error,String",
+	"comma-separated list of names of methods of type func() string whose results must be used")
+
+func init() {
+	register("unusedresult",
+		"check for unused result of calls to functions in -unusedfuncs list and methods in -unusedstringmethods list",
+		checkUnusedResult,
+		exprStmt)
+}
+
+// func() string
+var sigNoArgsStringResult = types.NewSignature(nil, nil,
+	types.NewTuple(types.NewVar(token.NoPos, nil, "", types.Typ[types.String])),
+	false)
+
+var unusedFuncs = make(map[string]bool)
+var unusedStringMethods = make(map[string]bool)
+
+func initUnusedFlags() {
+	commaSplit := func(s string, m map[string]bool) {
+		if s != "" {
+			for _, name := range strings.Split(s, ",") {
+				if len(name) == 0 {
+					flag.Usage()
+				}
+				m[name] = true
+			}
+		}
+	}
+	commaSplit(*unusedFuncsFlag, unusedFuncs)
+	commaSplit(*unusedStringMethodsFlag, unusedStringMethods)
+}
+
+func checkUnusedResult(f *File, n ast.Node) {
+	call, ok := unparen(n.(*ast.ExprStmt).X).(*ast.CallExpr)
+	if !ok {
+		return // not a call statement
+	}
+	fun := unparen(call.Fun)
+
+	if f.pkg.types[fun].IsType() {
+		return // a conversion, not a call
+	}
+
+	selector, ok := fun.(*ast.SelectorExpr)
+	if !ok {
+		return // neither a method call nor a qualified ident
+	}
+
+	sel, ok := f.pkg.selectors[selector]
+	if ok && sel.Kind() == types.MethodVal {
+		// method (e.g. foo.String())
+		obj := sel.Obj().(*types.Func)
+		sig := sel.Type().(*types.Signature)
+		if types.Identical(sig, sigNoArgsStringResult) {
+			if unusedStringMethods[obj.Name()] {
+				f.Badf(call.Lparen, "result of (%s).%s call not used",
+					sig.Recv().Type(), obj.Name())
+			}
+		}
+	} else if !ok {
+		// package-qualified function (e.g. fmt.Errorf)
+		obj, _ := f.pkg.uses[selector.Sel]
+		if obj, ok := obj.(*types.Func); ok {
+			qname := obj.Pkg().Path() + "." + obj.Name()
+			if unusedFuncs[qname] {
+				f.Badf(call.Lparen, "result of %v call not used", qname)
+			}
+		}
+	}
+}
diff --git a/src/cmd/vet/vet_test.go b/src/cmd/vet/vet_test.go
new file mode 100644
index 0000000..9aae8dd
--- /dev/null
+++ b/src/cmd/vet/vet_test.go
@@ -0,0 +1,107 @@
+// 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 main_test
+
+import (
+	"bytes"
+	"internal/testenv"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"runtime"
+	"testing"
+)
+
+const (
+	dataDir = "testdata"
+	binary  = "testvet.exe"
+)
+
+// Run this shell script, but do it in Go so it can be run by "go test".
+// 	go build -o testvet
+// 	$(GOROOT)/test/errchk ./testvet -shadow -printfuncs='Warn:1,Warnf:1' testdata/*.go testdata/*.s
+// 	rm testvet
+//
+func TestVet(t *testing.T) {
+	testenv.MustHaveGoBuild(t)
+
+	switch runtime.GOOS {
+	case "plan9", "windows":
+		// Plan 9 and Windows systems can't be guaranteed to have Perl and so can't run errchk.
+		t.Skipf("skipping test; no Perl on %q", runtime.GOOS)
+	}
+
+	// go build
+	cmd := exec.Command("go", "build", "-o", binary)
+	run(cmd, t)
+
+	// defer removal of vet
+	defer os.Remove(binary)
+
+	// errchk ./testvet
+	gos, err := filepath.Glob(filepath.Join(dataDir, "*.go"))
+	if err != nil {
+		t.Fatal(err)
+	}
+	asms, err := filepath.Glob(filepath.Join(dataDir, "*.s"))
+	if err != nil {
+		t.Fatal(err)
+	}
+	files := append(gos, asms...)
+	errchk := filepath.Join(runtime.GOROOT(), "test", "errchk")
+	flags := []string{
+		"./" + binary,
+		"-printfuncs=Warn:1,Warnf:1",
+		"-test", // TODO: Delete once -shadow is part of -all.
+	}
+	cmd = exec.Command(errchk, append(flags, files...)...)
+	if !run(cmd, t) {
+		t.Fatal("vet command failed")
+	}
+}
+
+func run(c *exec.Cmd, t *testing.T) bool {
+	output, err := c.CombinedOutput()
+	os.Stderr.Write(output)
+	if err != nil {
+		t.Fatal(err)
+	}
+	// Errchk delights by not returning non-zero status if it finds errors, so we look at the output.
+	// It prints "BUG" if there is a failure.
+	if !c.ProcessState.Success() {
+		return false
+	}
+	return !bytes.Contains(output, []byte("BUG"))
+}
+
+// TestTags verifies that the -tags argument controls which files to check.
+func TestTags(t *testing.T) {
+	testenv.MustHaveGoBuild(t)
+
+	// go build
+	cmd := exec.Command("go", "build", "-o", binary)
+	run(cmd, t)
+
+	// defer removal of vet
+	defer os.Remove(binary)
+
+	args := []string{
+		"-tags=testtag",
+		"-v", // We're going to look at the files it examines.
+		"testdata/tagtest",
+	}
+	cmd = exec.Command("./"+binary, args...)
+	output, err := cmd.CombinedOutput()
+	if err != nil {
+		t.Fatal(err)
+	}
+	// file1 has testtag and file2 has !testtag.
+	if !bytes.Contains(output, []byte(filepath.Join("tagtest", "file1.go"))) {
+		t.Error("file1 was excluded, should be included")
+	}
+	if bytes.Contains(output, []byte(filepath.Join("tagtest", "file2.go"))) {
+		t.Error("file2 was included, should be excluded")
+	}
+}
diff --git a/src/cmd/vet/whitelist/whitelist.go b/src/cmd/vet/whitelist/whitelist.go
new file mode 100644
index 0000000..bf4b4bf
--- /dev/null
+++ b/src/cmd/vet/whitelist/whitelist.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 whitelist defines exceptions for the vet tool.
+package whitelist // import "cmd/vet/whitelist"
+
+// UnkeyedLiteral are types that are actually slices, but
+// syntactically, we cannot tell whether the Typ in pkg.Typ{1, 2, 3}
+// is a slice or a struct, so we whitelist all the standard package
+// library's exported slice types.
+var UnkeyedLiteral = map[string]bool{
+	/*
+		find $GOROOT/src -type f | grep -v _test.go | xargs grep '^type.*\[\]' | \
+			grep -v ' map\[' | sed 's,/[^/]*go.type,,' | sed 's,.*src/,,' | \
+			sed 's, ,.,' |  sed 's, .*,,' | grep -v '\.[a-z]' | \
+			sort | awk '{ print "\"" $0 "\": true," }'
+	*/
+	"crypto/x509/pkix.RDNSequence":                  true,
+	"crypto/x509/pkix.RelativeDistinguishedNameSET": true,
+	"database/sql.RawBytes":                         true,
+	"debug/macho.LoadBytes":                         true,
+	"encoding/asn1.ObjectIdentifier":                true,
+	"encoding/asn1.RawContent":                      true,
+	"encoding/json.RawMessage":                      true,
+	"encoding/xml.CharData":                         true,
+	"encoding/xml.Comment":                          true,
+	"encoding/xml.Directive":                        true,
+	"go/scanner.ErrorList":                          true,
+	"image/color.Palette":                           true,
+	"net.HardwareAddr":                              true,
+	"net.IP":                                        true,
+	"net.IPMask":                                    true,
+	"sort.Float64Slice":                             true,
+	"sort.IntSlice":                                 true,
+	"sort.StringSlice":                              true,
+	"unicode.SpecialCase":                           true,
+
+	// These image and image/color struct types are frozen. We will never add fields to them.
+	"image/color.Alpha16": true,
+	"image/color.Alpha":   true,
+	"image/color.CMYK":    true,
+	"image/color.Gray16":  true,
+	"image/color.Gray":    true,
+	"image/color.NRGBA64": true,
+	"image/color.NRGBA":   true,
+	"image/color.RGBA64":  true,
+	"image/color.RGBA":    true,
+	"image/color.YCbCr":   true,
+	"image.Point":         true,
+	"image.Rectangle":     true,
+	"image.Uniform":       true,
+}
diff --git a/src/cmd/yacc/doc.go b/src/cmd/yacc/doc.go
index 702c9f0..328d87b 100644
--- a/src/cmd/yacc/doc.go
+++ b/src/cmd/yacc/doc.go
@@ -20,12 +20,12 @@ written in C and documented at
 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.
 
-The generated parser is reentrant. Parse expects to be given an
-argument that conforms to the following interface:
+The generated parser is reentrant. The parsing function yyParse expects
+to be given an argument that conforms to the following interface:
 
 	type yyLexer interface {
 		Lex(lval *yySymType) int
@@ -36,8 +36,27 @@ Lex should return the token identifier, and place other token
 information in lval (which replaces the usual yylval).
 Error is equivalent to yyerror in the original yacc.
 
-Code inside the parser may refer to the variable yylex,
-which holds the yyLexer passed to Parse.
+Code inside the grammar actions may refer to the variable yylex,
+which holds the yyLexer passed to yyParse.
+
+Clients that need to understand more about the parser state can
+create the parser separately from invoking it. The function yyNewParser
+returns a yyParser conforming to the following interface:
+
+	type yyParser interface {
+		Parse(yyLex) int
+		Lookahead() int
+	}
+
+Parse runs the parser; the top-level call yyParse(yylex) is equivalent
+to yyNewParser().Parse(yylex).
+
+Lookahead can be called during grammar actions to read (but not consume)
+the value of the current lookahead token, as returned by yylex.Lex.
+If there is no current lookahead token (because the parser has not called Lex
+or has consumed the token returned by the most recent call to Lex),
+Lookahead returns -1. Calling Lookahead is equivalent to reading
+yychar from within in a grammar action.
 
 Multiple grammars compiled into a single program should be placed in
 distinct packages.  If that is impossible, the "-p prefix" flag to
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:
 	}
 |	'-' 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/cmd/yacc/testdata/expr/main.go b/src/cmd/yacc/testdata/expr/main.go
index 8d5b691..37f0023 100644
--- a/src/cmd/yacc/testdata/expr/main.go
+++ b/src/cmd/yacc/testdata/expr/main.go
@@ -11,5 +11,5 @@
 //go:generate yacc -o expr.go -p "expr" expr.y
 
 // Expr is a simple expression evaluator that serves as a working example of
-// how to use Go's yacc implemenation.
+// how to use Go's yacc implementation.
 package main
diff --git a/src/cmd/yacc/yacc.go b/src/cmd/yacc/yacc.go
index 4dba376..4f83f50 100644
--- a/src/cmd/yacc/yacc.go
+++ b/src/cmd/yacc/yacc.go
@@ -128,6 +128,7 @@ const (
 	TYPEDEF
 	TYPENAME
 	UNION
+	ERROR
 )
 
 const ENDFILE = 0
@@ -325,8 +326,24 @@ var resrv = []Resrv{
 	{"type", TYPEDEF},
 	{"union", UNION},
 	{"struct", UNION},
+	{"error", ERROR},
 }
 
+type Error struct {
+	lineno int
+	tokens []string
+	msg    string
+}
+
+var errors []Error
+
+type Row struct {
+	actions       []int
+	defaultAction int
+}
+
+var stateTable []Row
+
 var zznewstate = 0
 
 const EOF = -1
@@ -402,6 +419,27 @@ outer:
 			}
 			start = chfind(1, tokname)
 
+		case ERROR:
+			lno := lineno
+			var tokens []string
+			for {
+				t := gettok()
+				if t == ':' {
+					break
+				}
+				if t != IDENTIFIER && t != IDENTCOLON {
+					errorf("bad syntax in %%error")
+				}
+				tokens = append(tokens, tokname)
+				if t == IDENTCOLON {
+					break
+				}
+			}
+			if gettok() != IDENTIFIER {
+				errorf("bad syntax in %%error")
+			}
+			errors = append(errors, Error{lno, tokens, tokname})
+
 		case TYPEDEF:
 			t = gettok()
 			if t != TYPENAME {
@@ -507,29 +545,6 @@ outer:
 		errorf("unexpected EOF before %%")
 	}
 
-	// put out non-literal terminals
-	for i := TOKSTART; i <= ntokens; i++ {
-		// non-literals
-		if !tokset[i].noconst {
-			fmt.Fprintf(ftable, "const %v = %v\n", tokset[i].name, tokset[i].value)
-		}
-	}
-
-	// put out names of token names
-	ftable.WriteRune('\n')
-	fmt.Fprintf(ftable, "var %sToknames = []string{\n", prefix)
-	for i := TOKSTART; i <= ntokens; i++ {
-		fmt.Fprintf(ftable, "\t\"%v\",\n", tokset[i].name)
-	}
-	fmt.Fprintf(ftable, "}\n")
-
-	// put out names of state names
-	fmt.Fprintf(ftable, "var %sStatenames = []string{", prefix)
-	//	for i:=TOKSTART; i<=ntokens; i++ {
-	//		fmt.Fprintf(ftable, "\t\"%v\",\n", tokset[i].name);
-	//	}
-	fmt.Fprintf(ftable, "}\n")
-
 	fmt.Fprintf(fcode, "switch %snt {\n", prefix)
 
 	moreprod()
@@ -603,6 +618,7 @@ outer:
 			}
 			levprd[nprod] |= ACTFLAG
 			fmt.Fprintf(fcode, "\n\tcase %v:", nprod)
+			fmt.Fprintf(fcode, "\n\t\t%sDollar = %sS[%spt-%v:%spt+1]", prefix, prefix, prefix, mem-1, prefix)
 			cpyact(curprod, mem)
 
 			// action within rule...
@@ -659,9 +675,6 @@ outer:
 			if tempty != nontrst[curprod[0]-NTBASE].value {
 				lerrorf(ruleline, "default action causes potential type clash")
 			}
-			fmt.Fprintf(fcode, "\n\tcase %v:", nprod)
-			fmt.Fprintf(fcode, "\n\t\t%sVAL.%v = %sS[%spt-0].%v",
-				prefix, typeset[tempty], prefix, prefix, typeset[tempty])
 		}
 		moreprod()
 		prdptr[nprod] = make([]int, mem)
@@ -678,6 +691,31 @@ outer:
 
 	fmt.Fprintf(fcode, "\n\t}")
 
+	// put out non-literal terminals
+	for i := TOKSTART; i <= ntokens; i++ {
+		// non-literals
+		if !tokset[i].noconst {
+			fmt.Fprintf(ftable, "const %v = %v\n", tokset[i].name, tokset[i].value)
+		}
+	}
+
+	// put out names of tokens
+	ftable.WriteRune('\n')
+	fmt.Fprintf(ftable, "var %sToknames = [...]string{\n", prefix)
+	for i := 1; i <= ntokens; i++ {
+		fmt.Fprintf(ftable, "\t%q,\n", tokset[i].name)
+	}
+	fmt.Fprintf(ftable, "}\n")
+
+	// put out names of states.
+	// commented out to avoid a huge table just for debugging.
+	// re-enable to have the names in the binary.
+	fmt.Fprintf(ftable, "var %sStatenames = [...]string{", prefix)
+	//	for i:=TOKSTART; i<=ntokens; i++ {
+	//		fmt.Fprintf(ftable, "\t%q,\n", tokset[i].name);
+	//	}
+	fmt.Fprintf(ftable, "}\n")
+
 	ftable.WriteRune('\n')
 	fmt.Fprintf(ftable, "const %sEofCode = 1\n", prefix)
 	fmt.Fprintf(ftable, "const %sErrCode = 2\n", prefix)
@@ -1345,7 +1383,7 @@ loop:
 				ungetrune(finput, c)
 				continue loop
 			}
-			fmt.Fprintf(fcode, "%sS[%spt-%v]", prefix, prefix, max-j-1)
+			fmt.Fprintf(fcode, "%sDollar[%v]", prefix, j)
 
 			// put out the proper tag
 			if ntypes != 0 {
@@ -2155,7 +2193,11 @@ func output() {
 	if !lflag {
 		fmt.Fprintf(ftable, "\n//line yacctab:1")
 	}
-	fmt.Fprintf(ftable, "\nvar %sExca = []int{\n", prefix)
+	fmt.Fprintf(ftable, "\nvar %sExca = [...]int{\n", prefix)
+
+	if len(errors) > 0 {
+		stateTable = make([]Row, nstate)
+	}
 
 	noset := mkset()
 
@@ -2370,6 +2412,15 @@ func wrstate(i int) {
 	var j0, j1, u int
 	var pp, qq int
 
+	if len(errors) > 0 {
+		actions := append([]int(nil), temp1...)
+		defaultAction := ERRCODE
+		if lastred != 0 {
+			defaultAction = -lastred
+		}
+		stateTable[i] = Row{actions, defaultAction}
+	}
+
 	if foutput == nil {
 		return
 	}
@@ -2891,7 +2942,7 @@ func others() {
 	arout("Tok2", temp1, c+1)
 
 	// table 3 has everything else
-	fmt.Fprintf(ftable, "var %sTok3 = []int{\n\t", prefix)
+	fmt.Fprintf(ftable, "var %sTok3 = [...]int{\n\t", prefix)
 	c = 0
 	for i = 1; i <= ntokens; i++ {
 		j = tokset[i].value
@@ -2916,6 +2967,20 @@ func others() {
 	}
 	fmt.Fprintf(ftable, "%d,\n}\n", 0)
 
+	// Custom error messages.
+	fmt.Fprintf(ftable, "\n")
+	fmt.Fprintf(ftable, "var %sErrorMessages = [...]struct {\n", prefix)
+	fmt.Fprintf(ftable, "\tstate int\n")
+	fmt.Fprintf(ftable, "\ttoken int\n")
+	fmt.Fprintf(ftable, "\tmsg   string\n")
+	fmt.Fprintf(ftable, "}{\n")
+	for _, error := range errors {
+		lineno = error.lineno
+		state, token := runMachine(error.tokens)
+		fmt.Fprintf(ftable, "\t{%v, %v, %s},\n", state, token, error.msg)
+	}
+	fmt.Fprintf(ftable, "}\n")
+
 	// copy parser text
 	ch := getrune(finput)
 	for ch != EOF {
@@ -2934,9 +2999,62 @@ func others() {
 	fmt.Fprintf(ftable, "%v", parts[1])
 }
 
+func runMachine(tokens []string) (state, token int) {
+	var stack []int
+	i := 0
+	token = -1
+
+Loop:
+	if token < 0 {
+		token = chfind(2, tokens[i])
+		i++
+	}
+
+	row := stateTable[state]
+
+	c := token
+	if token >= NTBASE {
+		c = token - NTBASE + ntokens
+	}
+	action := row.actions[c]
+	if action == 0 {
+		action = row.defaultAction
+	}
+
+	switch {
+	case action == ACCEPTCODE:
+		errorf("tokens are accepted")
+		return
+	case action == ERRCODE:
+		if token >= NTBASE {
+			errorf("error at non-terminal token %s", symnam(token))
+		}
+		return
+	case action > 0:
+		// Shift to state action.
+		stack = append(stack, state)
+		state = action
+		token = -1
+		goto Loop
+	default:
+		// Reduce by production -action.
+		prod := prdptr[-action]
+		if rhsLen := len(prod) - 2; rhsLen > 0 {
+			n := len(stack) - rhsLen
+			state = stack[n]
+			stack = stack[:n]
+		}
+		if token >= 0 {
+			i--
+		}
+		token = prod[0]
+		goto Loop
+	}
+}
+
 func arout(s string, v []int, n int) {
 	s = prefix + s
-	fmt.Fprintf(ftable, "var %v = []int{\n", s)
+	fmt.Fprintf(ftable, "var %v = [...]int{\n", s)
 	for i := 0; i < n; i++ {
 		if i%10 == 0 {
 			fmt.Fprintf(ftable, "\n\t")
@@ -3197,20 +3315,42 @@ var yaccpar string // will be processed version of yaccpartext: s/$$/prefix/g
 var yaccpartext = `
 /*	parser for yacc output	*/
 
-var $$Debug = 0
+var (
+	$$Debug        = 0
+	$$ErrorVerbose = false
+)
 
 type $$Lexer interface {
 	Lex(lval *$$SymType) int
 	Error(s string)
 }
 
+type $$Parser interface {
+	Parse($$Lexer) int
+	Lookahead() int
+}
+
+type $$ParserImpl struct {
+	lookahead func() int
+}
+
+func (p *$$ParserImpl) Lookahead() int {
+	return p.lookahead()
+}
+
+func $$NewParser() $$Parser {
+	p := &$$ParserImpl{
+		lookahead: func() int { return -1 },
+	}
+	return p
+}
+
 const $$Flag = -1000
 
 func $$Tokname(c int) string {
-	// 4 is TOKSTART above
-	if c >= 4 && c-4 < len($$Toknames) {
-		if $$Toknames[c-4] != "" {
-			return $$Toknames[c-4]
+	if c >= 1 && c-1 < len($$Toknames) {
+		if $$Toknames[c-1] != "" {
+			return $$Toknames[c-1]
 		}
 	}
 	return __yyfmt__.Sprintf("tok-%v", c)
@@ -3225,51 +3365,129 @@ func $$Statname(s int) string {
 	return __yyfmt__.Sprintf("state-%v", s)
 }
 
-func $$lex1(lex $$Lexer, lval *$$SymType) int {
-	c := 0
-	char := lex.Lex(lval)
+func $$ErrorMessage(state, lookAhead int) string {
+	const TOKSTART = 4
+
+	if !$$ErrorVerbose {
+		return "syntax error"
+	}
+
+	for _, e := range $$ErrorMessages {
+		if e.state == state && e.token == lookAhead {
+			return "syntax error: " + e.msg
+		}
+	}
+
+	res := "syntax error: unexpected " + $$Tokname(lookAhead)
+
+	// To match Bison, suggest at most four expected tokens.
+	expected := make([]int, 0, 4)
+
+	// Look for shiftable tokens.
+	base := $$Pact[state]
+	for tok := TOKSTART; tok-1 < len($$Toknames); tok++ {
+		if n := base + tok; n >= 0 && n < $$Last && $$Chk[$$Act[n]] == tok {
+			if len(expected) == cap(expected) {
+				return res
+			}
+			expected = append(expected, tok)
+		}
+	}
+
+	if $$Def[state] == -2 {
+		i := 0
+		for $$Exca[i] != -1 || $$Exca[i+1] != state {
+			i += 2
+		}
+
+		// Look for tokens that we accept or reduce.
+		for i += 2; $$Exca[i] >= 0; i += 2 {
+			tok := $$Exca[i]
+			if tok < TOKSTART || $$Exca[i+1] == 0 {
+				continue
+			}
+			if len(expected) == cap(expected) {
+				return res
+			}
+			expected = append(expected, tok)
+		}
+
+		// If the default action is to accept or reduce, give up.
+		if $$Exca[i+1] != 0 {
+			return res
+		}
+	}
+
+	for i, tok := range expected {
+		if i == 0 {
+			res += ", expecting "
+		} else {
+			res += " or "
+		}
+		res += $$Tokname(tok)
+	}
+	return res
+}
+
+func $$lex1(lex $$Lexer, lval *$$SymType) (char, token int) {
+	token = 0
+	char = lex.Lex(lval)
 	if char <= 0 {
-		c = $$Tok1[0]
+		token = $$Tok1[0]
 		goto out
 	}
 	if char < len($$Tok1) {
-		c = $$Tok1[char]
+		token = $$Tok1[char]
 		goto out
 	}
 	if char >= $$Private {
 		if char < $$Private+len($$Tok2) {
-			c = $$Tok2[char-$$Private]
+			token = $$Tok2[char-$$Private]
 			goto out
 		}
 	}
 	for i := 0; i < len($$Tok3); i += 2 {
-		c = $$Tok3[i+0]
-		if c == char {
-			c = $$Tok3[i+1]
+		token = $$Tok3[i+0]
+		if token == char {
+			token = $$Tok3[i+1]
 			goto out
 		}
 	}
 
 out:
-	if c == 0 {
-		c = $$Tok2[1] /* unknown char */
+	if token == 0 {
+		token = $$Tok2[1] /* unknown char */
 	}
 	if $$Debug >= 3 {
-		__yyfmt__.Printf("lex %s(%d)\n", $$Tokname(c), uint(char))
+		__yyfmt__.Printf("lex %s(%d)\n", $$Tokname(token), uint(char))
 	}
-	return c
+	return char, token
 }
 
 func $$Parse($$lex $$Lexer) int {
+	return $$NewParser().Parse($$lex)
+}
+
+func ($$rcvr *$$ParserImpl) Parse($$lex $$Lexer) int {
 	var $$n int
 	var $$lval $$SymType
 	var $$VAL $$SymType
+	var $$Dollar []$$SymType
+	_ = $$Dollar // silence set and not used
 	$$S := make([]$$SymType, $$MaxDepth)
 
 	Nerrs := 0   /* number of errors */
 	Errflag := 0 /* error recovery flag */
 	$$state := 0
 	$$char := -1
+	$$token := -1 // $$char translated into internal numbering
+	$$rcvr.lookahead = func() int { return $$char }
+	defer func() {
+		// Make sure we report no lookahead when not parsing.
+		$$state = -1
+		$$char = -1
+		$$token = -1
+	}()
 	$$p := -1
 	goto $$stack
 
@@ -3282,7 +3500,7 @@ ret1:
 $$stack:
 	/* put a state and value onto the stack */
 	if $$Debug >= 4 {
-		__yyfmt__.Printf("char %v in %v\n", $$Tokname($$char), $$Statname($$state))
+		__yyfmt__.Printf("char %v in %v\n", $$Tokname($$token), $$Statname($$state))
 	}
 
 	$$p++
@@ -3300,15 +3518,16 @@ $$newstate:
 		goto $$default /* simple state */
 	}
 	if $$char < 0 {
-		$$char = $$lex1($$lex, &$$lval)
+		$$char, $$token = $$lex1($$lex, &$$lval)
 	}
-	$$n += $$char
+	$$n += $$token
 	if $$n < 0 || $$n >= $$Last {
 		goto $$default
 	}
 	$$n = $$Act[$$n]
-	if $$Chk[$$n] == $$char { /* valid shift */
+	if $$Chk[$$n] == $$token { /* valid shift */
 		$$char = -1
+		$$token = -1
 		$$VAL = $$lval
 		$$state = $$n
 		if Errflag > 0 {
@@ -3322,7 +3541,7 @@ $$default:
 	$$n = $$Def[$$state]
 	if $$n == -2 {
 		if $$char < 0 {
-			$$char = $$lex1($$lex, &$$lval)
+			$$char, $$token = $$lex1($$lex, &$$lval)
 		}
 
 		/* look through exception table */
@@ -3335,7 +3554,7 @@ $$default:
 		}
 		for xi += 2; ; xi += 2 {
 			$$n = $$Exca[xi+0]
-			if $$n < 0 || $$n == $$char {
+			if $$n < 0 || $$n == $$token {
 				break
 			}
 		}
@@ -3348,11 +3567,11 @@ $$default:
 		/* error ... attempt to resume parsing */
 		switch Errflag {
 		case 0: /* brand new error */
-			$$lex.Error("syntax error")
+			$$lex.Error($$ErrorMessage($$state, $$token))
 			Nerrs++
 			if $$Debug >= 1 {
 				__yyfmt__.Printf("%s", $$Statname($$state))
-				__yyfmt__.Printf(" saw %s\n", $$Tokname($$char))
+				__yyfmt__.Printf(" saw %s\n", $$Tokname($$token))
 			}
 			fallthrough
 
@@ -3380,12 +3599,13 @@ $$default:
 
 		case 3: /* no shift yet; clobber input char */
 			if $$Debug >= 2 {
-				__yyfmt__.Printf("error recovery discards %s\n", $$Tokname($$char))
+				__yyfmt__.Printf("error recovery discards %s\n", $$Tokname($$token))
 			}
-			if $$char == $$EofCode {
+			if $$token == $$EofCode {
 				goto ret1
 			}
 			$$char = -1
+			$$token = -1
 			goto $$newstate /* try again in the same state */
 		}
 	}
@@ -3400,6 +3620,13 @@ $$default:
 	_ = $$pt // guard against "declared and not used"
 
 	$$p -= $$R2[$$n]
+	// $$p is now the index of $0. Perform the default action. Iff the
+	// reduced production is ε, $1 is possibly out of range.
+	if $$p+1 >= len($$S) {
+		nyys := make([]$$SymType, len($$S)*2)
+		copy(nyys, $$S)
+		$$S = nyys
+	}
 	$$VAL = $$S[$$p+1]
 
 	/* consult goto table to find next state */
diff --git a/src/compress/bzip2/bzip2.go b/src/compress/bzip2/bzip2.go
index 15575d2..6897957 100644
--- a/src/compress/bzip2/bzip2.go
+++ b/src/compress/bzip2/bzip2.go
@@ -353,7 +353,7 @@ func (bz2 *reader) readBlock() (err error) {
 	// variables accumulate the repeat count. See the Wikipedia page for
 	// details.
 	repeat := 0
-	repeat_power := 0
+	repeatPower := 0
 
 	// The `C' array (used by the inverse BWT) needs to be zero initialized.
 	for i := range bz2.c {
@@ -380,10 +380,10 @@ func (bz2 *reader) readBlock() (err error) {
 		if v < 2 {
 			// This is either the RUNA or RUNB symbol.
 			if repeat == 0 {
-				repeat_power = 1
+				repeatPower = 1
 			}
-			repeat += repeat_power << v
-			repeat_power <<= 1
+			repeat += repeatPower << v
+			repeatPower <<= 1
 
 			// This limit of 2 million comes from the bzip2 source
 			// code. It prevents repeat from overflowing.
diff --git a/src/compress/bzip2/bzip2_test.go b/src/compress/bzip2/bzip2_test.go
index fb79d08..77c50df 100644
--- a/src/compress/bzip2/bzip2_test.go
+++ b/src/compress/bzip2/bzip2_test.go
@@ -200,7 +200,7 @@ func BenchmarkDecodeDigits(b *testing.B) { benchmarkDecode(b, digits) }
 func BenchmarkDecodeTwain(b *testing.B)  { benchmarkDecode(b, twain) }
 
 func TestBufferOverrun(t *testing.T) {
-	// Tests https://code.google.com/p/go/issues/detail?id=5747.
+	// Tests https://golang.org/issue/5747.
 	buffer := bytes.NewReader([]byte(bufferOverrunBase64))
 	decoder := base64.NewDecoder(base64.StdEncoding, buffer)
 	decompressor := NewReader(decoder)
@@ -209,7 +209,7 @@ func TestBufferOverrun(t *testing.T) {
 }
 
 func TestOutOfRangeSelector(t *testing.T) {
-	// Tests https://code.google.com/p/go/issues/detail?id=8363.
+	// Tests https://golang.org/issue/8363.
 	buffer := bytes.NewReader(outOfRangeSelector)
 	decompressor := NewReader(buffer)
 	// This shouldn't panic.
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 @@ const (
 	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/compress/flate/deflate_test.go b/src/compress/flate/deflate_test.go
index 730234c..d5d6e73 100644
--- a/src/compress/flate/deflate_test.go
+++ b/src/compress/flate/deflate_test.go
@@ -407,7 +407,7 @@ func TestWriterDict(t *testing.T) {
 	}
 }
 
-// See http://code.google.com/p/go/issues/detail?id=2508
+// See https://golang.org/issue/2508
 func TestRegression2508(t *testing.T) {
 	if testing.Short() {
 		t.Logf("test disabled with -short")
diff --git a/src/compress/flate/flate_test.go b/src/compress/flate/flate_test.go
index 0687663..3f67025 100644
--- a/src/compress/flate/flate_test.go
+++ b/src/compress/flate/flate_test.go
@@ -10,29 +10,18 @@ package flate
 
 import (
 	"bytes"
+	"encoding/hex"
+	"io/ioutil"
 	"testing"
 )
 
-func TestUncompressedSource(t *testing.T) {
-	decoder := NewReader(bytes.NewReader([]byte{0x01, 0x01, 0x00, 0xfe, 0xff, 0x11}))
-	output := make([]byte, 1)
-	n, error := decoder.Read(output)
-	if n != 1 || error != nil {
-		t.Fatalf("decoder.Read() = %d, %v, want 1, nil", n, error)
-	}
-	if output[0] != 0x11 {
-		t.Errorf("output[0] = %x, want 0x11", output[0])
-	}
-}
-
 // The following test should not panic.
 func TestIssue5915(t *testing.T) {
 	bits := []int{4, 0, 0, 6, 4, 3, 2, 3, 3, 4, 4, 5, 0, 0, 0, 0, 5, 5, 6,
 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 6, 0, 11, 0, 8, 0, 6, 6, 10, 8}
-	h := new(huffmanDecoder)
-	ok := h.init(bits)
-	if ok == true {
+	var h huffmanDecoder
+	if h.init(bits) {
 		t.Fatalf("Given sequence of bits is bad, and should not succeed.")
 	}
 }
@@ -41,9 +30,8 @@ func TestIssue5915(t *testing.T) {
 func TestIssue5962(t *testing.T) {
 	bits := []int{4, 0, 0, 6, 4, 3, 2, 3, 3, 4, 4, 5, 0, 0, 0, 0,
 		5, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11}
-	h := new(huffmanDecoder)
-	ok := h.init(bits)
-	if ok == true {
+	var h huffmanDecoder
+	if h.init(bits) {
 		t.Fatalf("Given sequence of bits is bad, and should not succeed.")
 	}
 }
@@ -52,7 +40,7 @@ func TestIssue5962(t *testing.T) {
 func TestIssue6255(t *testing.T) {
 	bits1 := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 11}
 	bits2 := []int{11, 13}
-	h := new(huffmanDecoder)
+	var h huffmanDecoder
 	if !h.init(bits1) {
 		t.Fatalf("Given sequence of bits is good and should succeed.")
 	}
@@ -60,3 +48,213 @@ func TestIssue6255(t *testing.T) {
 		t.Fatalf("Given sequence of bits is bad and should not succeed.")
 	}
 }
+
+func TestInvalidEncoding(t *testing.T) {
+	// Initialize Huffman decoder to recognize "0".
+	var h huffmanDecoder
+	if !h.init([]int{1}) {
+		t.Fatal("Failed to initialize Huffman decoder")
+	}
+
+	// Initialize decompressor with invalid Huffman coding.
+	var f decompressor
+	f.r = bytes.NewReader([]byte{0xff})
+
+	_, err := f.huffSym(&h)
+	if err == nil {
+		t.Fatal("Should have rejected invalid bit sequence")
+	}
+}
+
+func TestInvalidBits(t *testing.T) {
+	oversubscribed := []int{1, 2, 3, 4, 4, 5}
+	incomplete := []int{1, 2, 4, 4}
+	var h huffmanDecoder
+	if h.init(oversubscribed) {
+		t.Fatal("Should reject oversubscribed bit-length set")
+	}
+	if h.init(incomplete) {
+		t.Fatal("Should reject incomplete bit-length set")
+	}
+}
+
+func TestStreams(t *testing.T) {
+	// To verify any of these hexstrings as valid or invalid flate streams
+	// according to the C zlib library, you can use the Python wrapper library:
+	// >>> hex_string = "010100feff11"
+	// >>> import zlib
+	// >>> zlib.decompress(hex_string.decode("hex"), -15) # Negative means raw DEFLATE
+	// '\x11'
+
+	testCases := []struct {
+		desc   string // Description of the stream
+		stream string // Hexstring of the input DEFLATE stream
+		want   string // Expected result. Use "fail" to expect failure
+	}{{
+		"degenerate HCLenTree",
+		"05e0010000000000100000000000000000000000000000000000000000000000" +
+			"00000000000000000004",
+		"fail",
+	}, {
+		"complete HCLenTree, empty HLitTree, empty HDistTree",
+		"05e0010400000000000000000000000000000000000000000000000000000000" +
+			"00000000000000000010",
+		"fail",
+	}, {
+		"empty HCLenTree",
+		"05e0010000000000000000000000000000000000000000000000000000000000" +
+			"00000000000000000010",
+		"fail",
+	}, {
+		"complete HCLenTree, complete HLitTree, empty HDistTree, use missing HDist symbol",
+		"000100feff000de0010400000000100000000000000000000000000000000000" +
+			"0000000000000000000000000000002c",
+		"fail",
+	}, {
+		"complete HCLenTree, complete HLitTree, degenerate HDistTree, use missing HDist symbol",
+		"000100feff000de0010000000000000000000000000000000000000000000000" +
+			"00000000000000000610000000004070",
+		"fail",
+	}, {
+		"complete HCLenTree, empty HLitTree, empty HDistTree",
+		"05e0010400000000100400000000000000000000000000000000000000000000" +
+			"0000000000000000000000000008",
+		"fail",
+	}, {
+		"complete HCLenTree, empty HLitTree, degenerate HDistTree",
+		"05e0010400000000100400000000000000000000000000000000000000000000" +
+			"0000000000000000000800000008",
+		"fail",
+	}, {
+		"complete HCLenTree, degenerate HLitTree, degenerate HDistTree, use missing HLit symbol",
+		"05e0010400000000100000000000000000000000000000000000000000000000" +
+			"0000000000000000001c",
+		"fail",
+	}, {
+		"complete HCLenTree, complete HLitTree, too large HDistTree",
+		"edff870500000000200400000000000000000000000000000000000000000000" +
+			"000000000000000000080000000000000004",
+		"fail",
+	}, {
+		"complete HCLenTree, complete HLitTree, empty HDistTree, excessive repeater code",
+		"edfd870500000000200400000000000000000000000000000000000000000000" +
+			"000000000000000000e8b100",
+		"fail",
+	}, {
+		"complete HCLenTree, complete HLitTree, empty HDistTree of normal length 30",
+		"05fd01240000000000f8ffffffffffffffffffffffffffffffffffffffffffff" +
+			"ffffffffffffffffff07000000fe01",
+		"",
+	}, {
+		"complete HCLenTree, complete HLitTree, empty HDistTree of excessive length 31",
+		"05fe01240000000000f8ffffffffffffffffffffffffffffffffffffffffffff" +
+			"ffffffffffffffffff07000000fc03",
+		"fail",
+	}, {
+		"complete HCLenTree, over-subscribed HLitTree, empty HDistTree",
+		"05e001240000000000fcffffffffffffffffffffffffffffffffffffffffffff" +
+			"ffffffffffffffffff07f00f",
+		"fail",
+	}, {
+		"complete HCLenTree, under-subscribed HLitTree, empty HDistTree",
+		"05e001240000000000fcffffffffffffffffffffffffffffffffffffffffffff" +
+			"fffffffffcffffffff07f00f",
+		"fail",
+	}, {
+		"complete HCLenTree, complete HLitTree with single code, empty HDistTree",
+		"05e001240000000000f8ffffffffffffffffffffffffffffffffffffffffffff" +
+			"ffffffffffffffffff07f00f",
+		"01",
+	}, {
+		"complete HCLenTree, complete HLitTree with multiple codes, empty HDistTree",
+		"05e301240000000000f8ffffffffffffffffffffffffffffffffffffffffffff" +
+			"ffffffffffffffffff07807f",
+		"01",
+	}, {
+		"complete HCLenTree, complete HLitTree, degenerate HDistTree, use valid HDist symbol",
+		"000100feff000de0010400000000100000000000000000000000000000000000" +
+			"0000000000000000000000000000003c",
+		"00000000",
+	}, {
+		"complete HCLenTree, degenerate HLitTree, degenerate HDistTree",
+		"05e0010400000000100000000000000000000000000000000000000000000000" +
+			"0000000000000000000c",
+		"",
+	}, {
+		"complete HCLenTree, degenerate HLitTree, empty HDistTree",
+		"05e0010400000000100000000000000000000000000000000000000000000000" +
+			"00000000000000000004",
+		"",
+	}, {
+		"complete HCLenTree, complete HLitTree, empty HDistTree, spanning repeater code",
+		"edfd870500000000200400000000000000000000000000000000000000000000" +
+			"000000000000000000e8b000",
+		"",
+	}, {
+		"complete HCLenTree with length codes, complete HLitTree, empty HDistTree",
+		"ede0010400000000100000000000000000000000000000000000000000000000" +
+			"0000000000000000000400004000",
+		"",
+	}, {
+		"complete HCLenTree, complete HLitTree, degenerate HDistTree, use valid HLit symbol 284 with count 31",
+		"000100feff00ede0010400000000100000000000000000000000000000000000" +
+			"000000000000000000000000000000040000407f00",
+		"0000000000000000000000000000000000000000000000000000000000000000" +
+			"0000000000000000000000000000000000000000000000000000000000000000" +
+			"0000000000000000000000000000000000000000000000000000000000000000" +
+			"0000000000000000000000000000000000000000000000000000000000000000" +
+			"0000000000000000000000000000000000000000000000000000000000000000" +
+			"0000000000000000000000000000000000000000000000000000000000000000" +
+			"0000000000000000000000000000000000000000000000000000000000000000" +
+			"0000000000000000000000000000000000000000000000000000000000000000" +
+			"000000",
+	}, {
+		"complete HCLenTree, complete HLitTree, degenerate HDistTree, use valid HLit and HDist symbols",
+		"0cc2010d00000082b0ac4aff0eb07d27060000ffff",
+		"616263616263",
+	}, {
+		"fixed block, use reserved symbol 287",
+		"33180700",
+		"fail",
+	}, {
+		"raw block",
+		"010100feff11",
+		"11",
+	}, {
+		"issue 10426 - over-subscribed HCLenTree causes a hang",
+		"344c4a4e494d4b070000ff2e2eff2e2e2e2e2eff",
+		"fail",
+	}, {
+		"issue 11030 - empty HDistTree unexpectedly leads to error",
+		"05c0070600000080400fff37a0ca",
+		"",
+	}, {
+		"issue 11033 - empty HDistTree unexpectedly leads to error",
+		"050fb109c020cca5d017dcbca044881ee1034ec149c8980bbc413c2ab35be9dc" +
+			"b1473449922449922411202306ee97b0383a521b4ffdcf3217f9f7d3adb701",
+		"3130303634342068652e706870005d05355f7ed957ff084a90925d19e3ebc6d0" +
+			"c6d7",
+	}}
+
+	for i, tc := range testCases {
+		data, err := hex.DecodeString(tc.stream)
+		if err != nil {
+			t.Fatal(err)
+		}
+		data, err = ioutil.ReadAll(NewReader(bytes.NewReader(data)))
+		if tc.want == "fail" {
+			if err == nil {
+				t.Errorf("#%d (%s): got nil error, want non-nil", i, tc.desc)
+			}
+		} else {
+			if err != nil {
+				t.Errorf("#%d (%s): %v", i, tc.desc, err)
+				continue
+			}
+			if got := hex.EncodeToString(data); got != tc.want {
+				t.Errorf("#%d (%s):\ngot  %q\nwant %q", i, tc.desc, got, tc.want)
+			}
+
+		}
+	}
+}
diff --git a/src/compress/flate/gen.go b/src/compress/flate/gen.go
index 6288ecd..154c89a 100644
--- a/src/compress/flate/gen.go
+++ b/src/compress/flate/gen.go
@@ -45,7 +45,20 @@ type huffmanDecoder struct {
 }
 
 // Initialize Huffman decoding tables from array of code lengths.
+// Following this function, h is guaranteed to be initialized into a complete
+// tree (i.e., neither over-subscribed nor under-subscribed). The exception is a
+// degenerate case where the tree has only a single symbol with length 1. Empty
+// trees are permitted.
 func (h *huffmanDecoder) init(bits []int) bool {
+	// Sanity enables additional runtime tests during Huffman
+	// table construction.  It's intended to be used during
+	// development to supplement the currently ad-hoc unit tests.
+	const sanity = false
+
+	if h.min != 0 {
+		*h = huffmanDecoder{}
+	}
+
 	// Count number of codes of each length,
 	// compute min and max length.
 	var count [maxCodeLen]int
@@ -62,37 +75,53 @@ func (h *huffmanDecoder) init(bits []int) bool {
 		}
 		count[n]++
 	}
+
+	// Empty tree. The decompressor.huffSym function will fail later if the tree
+	// is used. Technically, an empty tree is only valid for the HDIST tree and
+	// not the HCLEN and HLIT tree. However, a stream with an empty HCLEN tree
+	// is guaranteed to fail since it will attempt to use the tree to decode the
+	// codes for the HLIT and HDIST trees. Similarly, an empty HLIT tree is
+	// guaranteed to fail later since the compressed data section must be
+	// composed of at least one symbol (the end-of-block marker).
 	if max == 0 {
+		return true
+	}
+
+	code := 0
+	var nextcode [maxCodeLen]int
+	for i := min; i <= max; i++ {
+		code <<= 1
+		nextcode[i] = code
+		code += count[i]
+	}
+
+	// Check that the coding is complete (i.e., that we've
+	// assigned all 2-to-the-max possible bit sequences).
+	// Exception: To be compatible with zlib, we also need to
+	// accept degenerate single-code codings.  See also
+	// TestDegenerateHuffmanCoding.
+	if code != 1<<uint(max) && !(code == 1 && max == 1) {
 		return false
 	}
 
 	h.min = min
-	var linkBits uint
-	var numLinks int
 	if max > huffmanChunkBits {
-		linkBits = uint(max) - huffmanChunkBits
-		numLinks = 1 << linkBits
+		numLinks := 1 << (uint(max) - huffmanChunkBits)
 		h.linkMask = uint32(numLinks - 1)
-	}
-	code := 0
-	var nextcode [maxCodeLen]int
-	for i := min; i <= max; i++ {
-		if i == huffmanChunkBits+1 {
-			// create link tables
-			link := code >> 1
-			h.links = make([][]uint32, huffmanNumChunks-link)
-			for j := uint(link); j < huffmanNumChunks; j++ {
-				reverse := int(reverseByte[j>>8]) | int(reverseByte[j&0xff])<<8
-				reverse >>= uint(16 - huffmanChunkBits)
-				off := j - uint(link)
-				h.chunks[reverse] = uint32(off<<huffmanValueShift + uint(i))
-				h.links[off] = make([]uint32, 1<<linkBits)
+
+		// create link tables
+		link := nextcode[huffmanChunkBits+1] >> 1
+		h.links = make([][]uint32, huffmanNumChunks-link)
+		for j := uint(link); j < huffmanNumChunks; j++ {
+			reverse := int(reverseByte[j>>8]) | int(reverseByte[j&0xff])<<8
+			reverse >>= uint(16 - huffmanChunkBits)
+			off := j - uint(link)
+			if sanity && h.chunks[reverse] != 0 {
+				panic("impossible: overwriting existing chunk")
 			}
+			h.chunks[reverse] = uint32(off<<huffmanValueShift | (huffmanChunkBits + 1))
+			h.links[off] = make([]uint32, numLinks)
 		}
-		n := count[i]
-		nextcode[i] = code
-		code += n
-		code <<= 1
 	}
 
 	for i, n := range bits {
@@ -105,17 +134,60 @@ func (h *huffmanDecoder) init(bits []int) bool {
 		reverse := int(reverseByte[code>>8]) | int(reverseByte[code&0xff])<<8
 		reverse >>= uint(16 - n)
 		if n <= huffmanChunkBits {
-			for off := reverse; off < huffmanNumChunks; off += 1 << uint(n) {
+			for off := reverse; off < len(h.chunks); off += 1 << uint(n) {
+				// We should never need to overwrite
+				// an existing chunk.  Also, 0 is
+				// never a valid chunk, because the
+				// lower 4 "count" bits should be
+				// between 1 and 15.
+				if sanity && h.chunks[off] != 0 {
+					panic("impossible: overwriting existing chunk")
+				}
 				h.chunks[off] = chunk
 			}
 		} else {
-			linktab := h.links[h.chunks[reverse&(huffmanNumChunks-1)]>>huffmanValueShift]
+			j := reverse & (huffmanNumChunks - 1)
+			if sanity && h.chunks[j]&huffmanCountMask != huffmanChunkBits+1 {
+				// Longer codes should have been
+				// associated with a link table above.
+				panic("impossible: not an indirect chunk")
+			}
+			value := h.chunks[j] >> huffmanValueShift
+			linktab := h.links[value]
 			reverse >>= huffmanChunkBits
-			for off := reverse; off < numLinks; off += 1 << uint(n-huffmanChunkBits) {
+			for off := reverse; off < len(linktab); off += 1 << uint(n-huffmanChunkBits) {
+				if sanity && linktab[off] != 0 {
+					panic("impossible: overwriting existing chunk")
+				}
 				linktab[off] = chunk
 			}
 		}
 	}
+
+	if sanity {
+		// Above we've sanity checked that we never overwrote
+		// an existing entry.  Here we additionally check that
+		// we filled the tables completely.
+		for i, chunk := range h.chunks {
+			if chunk == 0 {
+				// As an exception, in the degenerate
+				// single-code case, we allow odd
+				// chunks to be missing.
+				if code == 1 && i%2 == 1 {
+					continue
+				}
+				panic("impossible: missing chunk")
+			}
+		}
+		for _, linktab := range h.links {
+			for _, chunk := range linktab {
+				if chunk == 0 {
+					panic("impossible: missing chunk")
+				}
+			}
+		}
+	}
+
 	return true
 }
 
@@ -138,6 +210,9 @@ func main() {
 		bits[i] = 8
 	}
 	h.init(bits[:])
+	if h.links != nil {
+		log.Fatal("Unexpected links table in fixed Huffman decoder")
+	}
 
 	var buf bytes.Buffer
 
diff --git a/src/compress/flate/huffman_bit_writer.go b/src/compress/flate/huffman_bit_writer.go
index b182a71..6164404 100644
--- a/src/compress/flate/huffman_bit_writer.go
+++ b/src/compress/flate/huffman_bit_writer.go
@@ -87,11 +87,11 @@ type huffmanBitWriter struct {
 func newHuffmanBitWriter(w io.Writer) *huffmanBitWriter {
 	return &huffmanBitWriter{
 		w:               w,
-		literalFreq:     make([]int32, maxLit),
+		literalFreq:     make([]int32, maxNumLit),
 		offsetFreq:      make([]int32, offsetCodeCount),
-		codegen:         make([]uint8, maxLit+offsetCodeCount+1),
+		codegen:         make([]uint8, maxNumLit+offsetCodeCount+1),
 		codegenFreq:     make([]int32, codegenCodeCount),
-		literalEncoding: newHuffmanEncoder(maxLit),
+		literalEncoding: newHuffmanEncoder(maxNumLit),
 		offsetEncoding:  newHuffmanEncoder(offsetCodeCount),
 		codegenEncoding: newHuffmanEncoder(codegenCodeCount),
 	}
diff --git a/src/compress/flate/huffman_code.go b/src/compress/flate/huffman_code.go
index 3b9fce4..50ec79c 100644
--- a/src/compress/flate/huffman_code.go
+++ b/src/compress/flate/huffman_code.go
@@ -47,11 +47,11 @@ func newHuffmanEncoder(size int) *huffmanEncoder {
 
 // Generates a HuffmanCode corresponding to the fixed literal table
 func generateFixedLiteralEncoding() *huffmanEncoder {
-	h := newHuffmanEncoder(maxLit)
+	h := newHuffmanEncoder(maxNumLit)
 	codeBits := h.codeBits
 	code := h.code
 	var ch uint16
-	for ch = 0; ch < maxLit; ch++ {
+	for ch = 0; ch < maxNumLit; ch++ {
 		var bits uint16
 		var size uint8
 		switch {
diff --git a/src/compress/flate/inflate.go b/src/compress/flate/inflate.go
index 76519bb..04372de 100644
--- a/src/compress/flate/inflate.go
+++ b/src/compress/flate/inflate.go
@@ -18,10 +18,12 @@ import (
 const (
 	maxCodeLen = 16    // max length of Huffman code
 	maxHist    = 32768 // max history required
-	// The next three numbers come from the RFC, section 3.2.7.
-	maxLit   = 286
-	maxDist  = 32
-	numCodes = 19 // number of codes in Huffman meta-code
+	// The next three numbers come from the RFC section 3.2.7, with the
+	// additional proviso in section 3.2.5 which implies that distance codes
+	// 30 and 31 should never occur in compressed data.
+	maxNumLit  = 286
+	maxNumDist = 30
+	numCodes   = 19 // number of codes in Huffman meta-code
 )
 
 // A CorruptInputError reports the presence of corrupt input at a given offset.
@@ -101,7 +103,16 @@ type huffmanDecoder struct {
 }
 
 // Initialize Huffman decoding tables from array of code lengths.
+// Following this function, h is guaranteed to be initialized into a complete
+// tree (i.e., neither over-subscribed nor under-subscribed). The exception is a
+// degenerate case where the tree has only a single symbol with length 1. Empty
+// trees are permitted.
 func (h *huffmanDecoder) init(bits []int) bool {
+	// Sanity enables additional runtime tests during Huffman
+	// table construction.  It's intended to be used during
+	// development to supplement the currently ad-hoc unit tests.
+	const sanity = false
+
 	if h.min != 0 {
 		*h = huffmanDecoder{}
 	}
@@ -122,40 +133,53 @@ func (h *huffmanDecoder) init(bits []int) bool {
 		}
 		count[n]++
 	}
+
+	// Empty tree. The decompressor.huffSym function will fail later if the tree
+	// is used. Technically, an empty tree is only valid for the HDIST tree and
+	// not the HCLEN and HLIT tree. However, a stream with an empty HCLEN tree
+	// is guaranteed to fail since it will attempt to use the tree to decode the
+	// codes for the HLIT and HDIST trees. Similarly, an empty HLIT tree is
+	// guaranteed to fail later since the compressed data section must be
+	// composed of at least one symbol (the end-of-block marker).
 	if max == 0 {
+		return true
+	}
+
+	code := 0
+	var nextcode [maxCodeLen]int
+	for i := min; i <= max; i++ {
+		code <<= 1
+		nextcode[i] = code
+		code += count[i]
+	}
+
+	// Check that the coding is complete (i.e., that we've
+	// assigned all 2-to-the-max possible bit sequences).
+	// Exception: To be compatible with zlib, we also need to
+	// accept degenerate single-code codings.  See also
+	// TestDegenerateHuffmanCoding.
+	if code != 1<<uint(max) && !(code == 1 && max == 1) {
 		return false
 	}
 
 	h.min = min
-	var linkBits uint
-	var numLinks int
 	if max > huffmanChunkBits {
-		linkBits = uint(max) - huffmanChunkBits
-		numLinks = 1 << linkBits
+		numLinks := 1 << (uint(max) - huffmanChunkBits)
 		h.linkMask = uint32(numLinks - 1)
-	}
-	code := 0
-	var nextcode [maxCodeLen]int
-	for i := min; i <= max; i++ {
-		if i == huffmanChunkBits+1 {
-			// create link tables
-			link := code >> 1
-			if huffmanNumChunks < link {
-				return false
-			}
-			h.links = make([][]uint32, huffmanNumChunks-link)
-			for j := uint(link); j < huffmanNumChunks; j++ {
-				reverse := int(reverseByte[j>>8]) | int(reverseByte[j&0xff])<<8
-				reverse >>= uint(16 - huffmanChunkBits)
-				off := j - uint(link)
-				h.chunks[reverse] = uint32(off<<huffmanValueShift + uint(i))
-				h.links[off] = make([]uint32, 1<<linkBits)
+
+		// create link tables
+		link := nextcode[huffmanChunkBits+1] >> 1
+		h.links = make([][]uint32, huffmanNumChunks-link)
+		for j := uint(link); j < huffmanNumChunks; j++ {
+			reverse := int(reverseByte[j>>8]) | int(reverseByte[j&0xff])<<8
+			reverse >>= uint(16 - huffmanChunkBits)
+			off := j - uint(link)
+			if sanity && h.chunks[reverse] != 0 {
+				panic("impossible: overwriting existing chunk")
 			}
+			h.chunks[reverse] = uint32(off<<huffmanValueShift | (huffmanChunkBits + 1))
+			h.links[off] = make([]uint32, numLinks)
 		}
-		n := count[i]
-		nextcode[i] = code
-		code += n
-		code <<= 1
 	}
 
 	for i, n := range bits {
@@ -168,21 +192,60 @@ func (h *huffmanDecoder) init(bits []int) bool {
 		reverse := int(reverseByte[code>>8]) | int(reverseByte[code&0xff])<<8
 		reverse >>= uint(16 - n)
 		if n <= huffmanChunkBits {
-			for off := reverse; off < huffmanNumChunks; off += 1 << uint(n) {
+			for off := reverse; off < len(h.chunks); off += 1 << uint(n) {
+				// We should never need to overwrite
+				// an existing chunk.  Also, 0 is
+				// never a valid chunk, because the
+				// lower 4 "count" bits should be
+				// between 1 and 15.
+				if sanity && h.chunks[off] != 0 {
+					panic("impossible: overwriting existing chunk")
+				}
 				h.chunks[off] = chunk
 			}
 		} else {
-			value := h.chunks[reverse&(huffmanNumChunks-1)] >> huffmanValueShift
-			if value >= uint32(len(h.links)) {
-				return false
+			j := reverse & (huffmanNumChunks - 1)
+			if sanity && h.chunks[j]&huffmanCountMask != huffmanChunkBits+1 {
+				// Longer codes should have been
+				// associated with a link table above.
+				panic("impossible: not an indirect chunk")
 			}
+			value := h.chunks[j] >> huffmanValueShift
 			linktab := h.links[value]
 			reverse >>= huffmanChunkBits
-			for off := reverse; off < numLinks; off += 1 << uint(n-huffmanChunkBits) {
+			for off := reverse; off < len(linktab); off += 1 << uint(n-huffmanChunkBits) {
+				if sanity && linktab[off] != 0 {
+					panic("impossible: overwriting existing chunk")
+				}
 				linktab[off] = chunk
 			}
 		}
 	}
+
+	if sanity {
+		// Above we've sanity checked that we never overwrote
+		// an existing entry.  Here we additionally check that
+		// we filled the tables completely.
+		for i, chunk := range h.chunks {
+			if chunk == 0 {
+				// As an exception, in the degenerate
+				// single-code case, we allow odd
+				// chunks to be missing.
+				if code == 1 && i%2 == 1 {
+					continue
+				}
+				panic("impossible: missing chunk")
+			}
+		}
+		for _, linktab := range h.links {
+			for _, chunk := range linktab {
+				if chunk == 0 {
+					panic("impossible: missing chunk")
+				}
+			}
+		}
+	}
+
 	return true
 }
 
@@ -209,7 +272,7 @@ type decompressor struct {
 	h1, h2 huffmanDecoder
 
 	// Length arrays used to define Huffman codes.
-	bits     *[maxLit + maxDist]int
+	bits     *[maxNumLit + maxNumDist]int
 	codebits *[numCodes]int
 
 	// Output history, buffer.
@@ -307,12 +370,14 @@ func (f *decompressor) readHuffman() error {
 		}
 	}
 	nlit := int(f.b&0x1F) + 257
-	if nlit > maxLit {
+	if nlit > maxNumLit {
 		return CorruptInputError(f.roffset)
 	}
 	f.b >>= 5
 	ndist := int(f.b&0x1F) + 1
-	// maxDist is 32, so ndist is always valid.
+	if ndist > maxNumDist {
+		return CorruptInputError(f.roffset)
+	}
 	f.b >>= 5
 	nclen := int(f.b&0xF) + 4
 	// numCodes is 19, so nclen is always valid.
@@ -443,9 +508,12 @@ func (f *decompressor) huffmanBlock() {
 		case v < 285:
 			length = v*32 - (281*32 - 131)
 			n = 5
-		default:
+		case v < maxNumLit:
 			length = 258
 			n = 0
+		default:
+			f.err = CorruptInputError(f.roffset)
+			return
 		}
 		if n > 0 {
 			for f.nb < n {
@@ -480,10 +548,7 @@ func (f *decompressor) huffmanBlock() {
 		switch {
 		case dist < 4:
 			dist++
-		case dist >= 30:
-			f.err = CorruptInputError(f.roffset)
-			return
-		default:
+		case dist < maxNumDist:
 			nb := uint(dist-2) >> 1
 			// have 1 bit in bottom of dist, need nb more.
 			extra := (dist & 1) << nb
@@ -497,6 +562,9 @@ func (f *decompressor) huffmanBlock() {
 			f.b >>= nb
 			f.nb -= nb
 			dist = 1<<(nb+1) + 1 + extra
+		default:
+			f.err = CorruptInputError(f.roffset)
+			return
 		}
 
 		// Copy history[-dist:-dist+length] into output.
@@ -643,6 +711,10 @@ func (f *decompressor) moreBits() error {
 
 // Read the next Huffman-encoded symbol from f according to h.
 func (f *decompressor) huffSym(h *huffmanDecoder) (int, error) {
+	// Since a huffmanDecoder can be empty or be composed of a degenerate tree
+	// with single element, huffSym must error on these two edge cases. In both
+	// cases, the chunks slice will be 0 for the invalid sequence, leading it
+	// satisfy the n == 0 check below.
 	n := uint(h.min)
 	for {
 		for f.nb < n {
@@ -655,12 +727,12 @@ func (f *decompressor) huffSym(h *huffmanDecoder) (int, error) {
 		if n > huffmanChunkBits {
 			chunk = h.links[chunk>>huffmanValueShift][(f.b>>huffmanChunkBits)&h.linkMask]
 			n = uint(chunk & huffmanCountMask)
+		}
+		if n <= f.nb {
 			if n == 0 {
 				f.err = CorruptInputError(f.roffset)
 				return 0, f.err
 			}
-		}
-		if n <= f.nb {
 			f.b >>= n
 			f.nb -= n
 			return int(chunk >> huffmanValueShift), nil
@@ -712,7 +784,7 @@ func (f *decompressor) Reset(r io.Reader, dict []byte) error {
 // The ReadCloser returned by NewReader also implements Resetter.
 func NewReader(r io.Reader) io.ReadCloser {
 	var f decompressor
-	f.bits = new([maxLit + maxDist]int)
+	f.bits = new([maxNumLit + maxNumDist]int)
 	f.codebits = new([numCodes]int)
 	f.r = makeReader(r)
 	f.hist = new([maxHist]byte)
@@ -731,7 +803,7 @@ func NewReaderDict(r io.Reader, dict []byte) io.ReadCloser {
 	var f decompressor
 	f.r = makeReader(r)
 	f.hist = new([maxHist]byte)
-	f.bits = new([maxLit + maxDist]int)
+	f.bits = new([maxNumLit + maxNumDist]int)
 	f.codebits = new([numCodes]int)
 	f.step = (*decompressor).nextBlock
 	f.setDict(dict)
diff --git a/src/compress/lzw/reader.go b/src/compress/lzw/reader.go
index 526620c..1353831 100644
--- a/src/compress/lzw/reader.go
+++ b/src/compress/lzw/reader.go
@@ -139,6 +139,7 @@ func (d *decoder) decode() {
 				err = io.ErrUnexpectedEOF
 			}
 			d.err = err
+			d.flush()
 			return
 		}
 		switch {
@@ -190,6 +191,7 @@ func (d *decoder) decode() {
 			}
 		default:
 			d.err = errors.New("lzw: invalid code")
+			d.flush()
 			return
 		}
 		d.last, d.hi = code, d.hi+1
@@ -213,7 +215,7 @@ func (d *decoder) flush() {
 	d.o = 0
 }
 
-var errClosed = errors.New("compress/lzw: reader/writer is closed")
+var errClosed = errors.New("lzw: reader/writer is closed")
 
 func (d *decoder) Close() error {
 	d.err = errClosed // in case any Reads come along
@@ -227,7 +229,8 @@ func (d *decoder) Close() error {
 // It is the caller's responsibility to call Close on the ReadCloser when
 // finished reading.
 // The number of bits to use for literal codes, litWidth, must be in the
-// range [2,8] and is typically 8.
+// range [2,8] and is typically 8. It must equal the litWidth
+// used during compression.
 func NewReader(r io.Reader, order Order, litWidth int) io.ReadCloser {
 	d := new(decoder)
 	switch order {
diff --git a/src/compress/lzw/reader_test.go b/src/compress/lzw/reader_test.go
index 9006c91..c3a5c3a 100644
--- a/src/compress/lzw/reader_test.go
+++ b/src/compress/lzw/reader_test.go
@@ -98,13 +98,20 @@ func TestReader(t *testing.T) {
 		defer rc.Close()
 		b.Reset()
 		n, err := io.Copy(&b, rc)
+		s := b.String()
 		if err != nil {
 			if err != tt.err {
 				t.Errorf("%s: io.Copy: %v want %v", tt.desc, err, tt.err)
 			}
+			if err == io.ErrUnexpectedEOF {
+				// Even if the input is truncated, we should still return the
+				// partial decoded result.
+				if n == 0 || !strings.HasPrefix(tt.raw, s) {
+					t.Errorf("got %d bytes (%q), want a non-empty prefix of %q", n, s, tt.raw)
+				}
+			}
 			continue
 		}
-		s := b.String()
 		if s != tt.raw {
 			t.Errorf("%s: got %d-byte %q want %d-byte %q", tt.desc, n, s, len(tt.raw), tt.raw)
 		}
diff --git a/src/compress/lzw/writer.go b/src/compress/lzw/writer.go
index 961b25f..7367c29 100644
--- a/src/compress/lzw/writer.go
+++ b/src/compress/lzw/writer.go
@@ -138,16 +138,23 @@ func (e *encoder) Write(p []byte) (n int, err error) {
 	if len(p) == 0 {
 		return 0, nil
 	}
+	if maxLit := uint8(1<<e.litWidth - 1); maxLit != 0xff {
+		for _, x := range p {
+			if x > maxLit {
+				e.err = errors.New("lzw: input byte too large for the litWidth")
+				return 0, e.err
+			}
+		}
+	}
 	n = len(p)
-	litMask := uint32(1<<e.litWidth - 1)
 	code := e.savedCode
 	if code == invalidCode {
 		// The first code sent is always a literal code.
-		code, p = uint32(p[0])&litMask, p[1:]
+		code, p = uint32(p[0]), p[1:]
 	}
 loop:
 	for _, x := range p {
-		literal := uint32(x) & litMask
+		literal := uint32(x)
 		key := code<<8 | literal
 		// If there is a hash table hit for this key then we continue the loop
 		// and do not emit a code yet.
@@ -230,7 +237,7 @@ func (e *encoder) Close() error {
 // It is the caller's responsibility to call Close on the WriteCloser when
 // finished writing.
 // The number of bits to use for literal codes, litWidth, must be in the
-// range [2,8] and is typically 8.
+// range [2,8] and is typically 8. Input bytes must be less than 1<<litWidth.
 func NewWriter(w io.Writer, order Order, litWidth int) io.WriteCloser {
 	var write func(*encoder, uint32) error
 	switch order {
diff --git a/src/compress/lzw/writer_test.go b/src/compress/lzw/writer_test.go
index 3e4e6de..c20d058 100644
--- a/src/compress/lzw/writer_test.go
+++ b/src/compress/lzw/writer_test.go
@@ -104,6 +104,16 @@ func TestWriterReturnValues(t *testing.T) {
 	}
 }
 
+func TestSmallLitWidth(t *testing.T) {
+	w := NewWriter(ioutil.Discard, LSB, 2)
+	if _, err := w.Write([]byte{0x03}); err != nil {
+		t.Fatalf("write a byte < 1<<2: %v", err)
+	}
+	if _, err := w.Write([]byte{0x04}); err == nil {
+		t.Fatal("write a byte >= 1<<2: got nil error, want non-nil")
+	}
+}
+
 func benchmarkEncoder(b *testing.B, n int) {
 	b.StopTimer()
 	b.SetBytes(int64(n))
diff --git a/src/crypto/cipher/cipher.go b/src/crypto/cipher/cipher.go
index 67afdb1..7d27fde 100644
--- a/src/crypto/cipher/cipher.go
+++ b/src/crypto/cipher/cipher.go
@@ -29,6 +29,9 @@ type Block interface {
 type Stream interface {
 	// XORKeyStream XORs each byte in the given slice with a byte from the
 	// cipher's key stream. Dst and src may point to the same memory.
+	// If len(dst) < len(src), XORKeyStream should panic. It is acceptable
+	// to pass a dst bigger than src, and in that case, XORKeyStream will
+	// only update dst[:len(src)] and will not touch the rest of dst.
 	XORKeyStream(dst, src []byte)
 }
 
diff --git a/src/crypto/cipher/gcm.go b/src/crypto/cipher/gcm.go
index bdafd85..bbdf9f5 100644
--- a/src/crypto/cipher/gcm.go
+++ b/src/crypto/cipher/gcm.go
@@ -52,14 +52,26 @@ type gcmFieldElement struct {
 // gcm represents a Galois Counter Mode with a specific key. See
 // http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-revised-spec.pdf
 type gcm struct {
-	cipher Block
+	cipher    Block
+	nonceSize int
 	// productTable contains the first sixteen powers of the key, H.
-	// However, they are in bit reversed order. See NewGCM.
+	// However, they are in bit reversed order. See NewGCMWithNonceSize.
 	productTable [16]gcmFieldElement
 }
 
-// NewGCM returns the given 128-bit, block cipher wrapped in Galois Counter Mode.
+// NewGCM returns the given 128-bit, block cipher wrapped in Galois Counter Mode
+// with the standard nonce length.
 func NewGCM(cipher Block) (AEAD, error) {
+	return NewGCMWithNonceSize(cipher, gcmStandardNonceSize)
+}
+
+// NewGCMWithNonceSize returns the given 128-bit, block cipher wrapped in Galois
+// Counter Mode, which accepts nonces of the given length.
+//
+// Only use this function if you require compatibility with an existing
+// cryptosystem that uses non-standard nonce lengths. All other users should use
+// NewGCM, which is faster and more resistant to misuse.
+func NewGCMWithNonceSize(cipher Block, size int) (AEAD, error) {
 	if cipher.BlockSize() != gcmBlockSize {
 		return nil, errors.New("cipher: NewGCM requires 128-bit block cipher")
 	}
@@ -67,7 +79,7 @@ func NewGCM(cipher Block) (AEAD, error) {
 	var key [gcmBlockSize]byte
 	cipher.Encrypt(key[:], key[:])
 
-	g := &gcm{cipher: cipher}
+	g := &gcm{cipher: cipher, nonceSize: size}
 
 	// We precompute 16 multiples of |key|. However, when we do lookups
 	// into this table we'll be using bits from a field element and
@@ -89,13 +101,13 @@ func NewGCM(cipher Block) (AEAD, error) {
 }
 
 const (
-	gcmBlockSize = 16
-	gcmTagSize   = 16
-	gcmNonceSize = 12
+	gcmBlockSize         = 16
+	gcmTagSize           = 16
+	gcmStandardNonceSize = 12
 )
 
-func (*gcm) NonceSize() int {
-	return gcmNonceSize
+func (g *gcm) NonceSize() int {
+	return g.nonceSize
 }
 
 func (*gcm) Overhead() int {
@@ -103,16 +115,13 @@ func (*gcm) Overhead() int {
 }
 
 func (g *gcm) Seal(dst, nonce, plaintext, data []byte) []byte {
-	if len(nonce) != gcmNonceSize {
+	if len(nonce) != g.nonceSize {
 		panic("cipher: incorrect nonce length given to GCM")
 	}
-
 	ret, out := sliceForAppend(dst, len(plaintext)+gcmTagSize)
 
-	// See GCM spec, section 7.1.
 	var counter, tagMask [gcmBlockSize]byte
-	copy(counter[:], nonce)
-	counter[gcmBlockSize-1] = 1
+	g.deriveCounter(&counter, nonce)
 
 	g.cipher.Encrypt(tagMask[:], counter[:])
 	gcmInc32(&counter)
@@ -126,7 +135,7 @@ func (g *gcm) Seal(dst, nonce, plaintext, data []byte) []byte {
 var errOpen = errors.New("cipher: message authentication failed")
 
 func (g *gcm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
-	if len(nonce) != gcmNonceSize {
+	if len(nonce) != g.nonceSize {
 		panic("cipher: incorrect nonce length given to GCM")
 	}
 
@@ -136,10 +145,8 @@ func (g *gcm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
 	tag := ciphertext[len(ciphertext)-gcmTagSize:]
 	ciphertext = ciphertext[:len(ciphertext)-gcmTagSize]
 
-	// See GCM spec, section 7.1.
 	var counter, tagMask [gcmBlockSize]byte
-	copy(counter[:], nonce)
-	counter[gcmBlockSize-1] = 1
+	g.deriveCounter(&counter, nonce)
 
 	g.cipher.Encrypt(tagMask[:], counter[:])
 	gcmInc32(&counter)
@@ -198,7 +205,7 @@ var gcmReductionTable = []uint16{
 	0xe100, 0xfd20, 0xd940, 0xc560, 0x9180, 0x8da0, 0xa9c0, 0xb5e0,
 }
 
-// mul sets y to y*H, where H is the GCM key, fixed during NewGCM.
+// mul sets y to y*H, where H is the GCM key, fixed during NewGCMWithNonceSize.
 func (g *gcm) mul(y *gcmFieldElement) {
 	var z gcmFieldElement
 
@@ -219,7 +226,7 @@ func (g *gcm) mul(y *gcmFieldElement) {
 
 			// the values in |table| are ordered for
 			// little-endian bit positions. See the comment
-			// in NewGCM.
+			// in NewGCMWithNonceSize.
 			t := &g.productTable[word&0xf]
 
 			z.low ^= t.low
@@ -301,6 +308,29 @@ func (g *gcm) counterCrypt(out, in []byte, counter *[gcmBlockSize]byte) {
 	}
 }
 
+// deriveCounter computes the initial GCM counter state from the given nonce.
+// See NIST SP 800-38D, section 7.1. This assumes that counter is filled with
+// zeros on entry.
+func (g *gcm) deriveCounter(counter *[gcmBlockSize]byte, nonce []byte) {
+	// GCM has two modes of operation with respect to the initial counter
+	// state: a "fast path" for 96-bit (12-byte) nonces, and a "slow path"
+	// for nonces of other lengths. For a 96-bit nonce, the nonce, along
+	// with a four-byte big-endian counter starting at one, is used
+	// directly as the starting counter. For other nonce sizes, the counter
+	// is computed by passing it through the GHASH function.
+	if len(nonce) == gcmStandardNonceSize {
+		copy(counter[:], nonce)
+		counter[gcmBlockSize-1] = 1
+	} else {
+		var y gcmFieldElement
+		g.update(&y, nonce)
+		y.high ^= uint64(len(nonce)) * 8
+		g.mul(&y)
+		putUint64(counter[:8], y.low)
+		putUint64(counter[8:], y.high)
+	}
+}
+
 // auth calculates GHASH(ciphertext, additionalData), masks the result with
 // tagMask and writes the result to out.
 func (g *gcm) auth(out, ciphertext, additionalData []byte, tagMask *[gcmTagSize]byte) {
diff --git a/src/crypto/cipher/gcm_test.go b/src/crypto/cipher/gcm_test.go
index 0c502ce..81b9aa2 100644
--- a/src/crypto/cipher/gcm_test.go
+++ b/src/crypto/cipher/gcm_test.go
@@ -101,6 +101,35 @@ var aesGCMTests = []struct {
 		"",
 		"b2051c80014f42f08735a7b0cd38e6bcd29962e5f2c13626b85a877101",
 	},
+	// These cases test non-standard nonce sizes.
+	{
+		"1672c3537afa82004c6b8a46f6f0d026",
+		"05",
+		"",
+		"",
+		"8e2ad721f9455f74d8b53d3141f27e8e",
+	},
+	{
+		"9a4fea86a621a91ab371e492457796c0",
+		"75",
+		"ca6131faf0ff210e4e693d6c31c109fc5b6f54224eb120f37de31dc59ec669b6",
+		"4f6e2585c161f05a9ae1f2f894e9f0ab52b45d0f",
+		"5698c0a384241d30004290aac56bb3ece6fe8eacc5c4be98954deb9c3ff6aebf5d50e1af100509e1fba2a5e8a0af9670",
+	},
+	{
+		"d0f1f4defa1e8c08b4b26d576392027c",
+		"42b4f01eb9f5a1ea5b1eb73b0fb0baed54f387ecaa0393c7d7dffc6af50146ecc021abf7eb9038d4303d91f8d741a11743166c0860208bcc02c6258fd9511a2fa626f96d60b72fcff773af4e88e7a923506e4916ecbd814651e9f445adef4ad6a6b6c7290cc13b956130eef5b837c939fcac0cbbcc9656cd75b13823ee5acdac",
+		"",
+		"",
+		"7ab49b57ddf5f62c427950111c5c4f0d",
+	},
+	{
+		"4a0c00a3d284dea9d4bf8b8dde86685e",
+		"f8cbe82588e784bcacbe092cd9089b51e01527297f635bf294b3aa787d91057ef23869789698ac960707857f163ecb242135a228ad93964f5dc4a4d7f88fd7b3b07dd0a5b37f9768fb05a523639f108c34c661498a56879e501a2321c8a4a94d7e1b89db255ac1f685e185263368e99735ebe62a7f2931b47282be8eb165e4d7",
+		"6d4bf87640a6a48a50d28797b7",
+		"8d8c7ffc55086d539b5a8f0d1232654c",
+		"0d803ec309482f35b8e6226f2b56303239298e06b281c2d51aaba3c125",
+	},
 }
 
 func TestAESGCM(t *testing.T) {
@@ -114,7 +143,7 @@ func TestAESGCM(t *testing.T) {
 		nonce, _ := hex.DecodeString(test.nonce)
 		plaintext, _ := hex.DecodeString(test.plaintext)
 		ad, _ := hex.DecodeString(test.ad)
-		aesgcm, err := cipher.NewGCM(aes)
+		aesgcm, err := cipher.NewGCMWithNonceSize(aes, len(nonce))
 		if err != nil {
 			t.Fatal(err)
 		}
diff --git a/src/crypto/crypto.go b/src/crypto/crypto.go
index 59b23e9..184ea9d 100644
--- a/src/crypto/crypto.go
+++ b/src/crypto/crypto.go
@@ -21,36 +21,40 @@ func (h Hash) HashFunc() Hash {
 }
 
 const (
-	MD4       Hash = 1 + iota // import golang.org/x/crypto/md4
-	MD5                       // import crypto/md5
-	SHA1                      // import crypto/sha1
-	SHA224                    // import crypto/sha256
-	SHA256                    // import crypto/sha256
-	SHA384                    // import crypto/sha512
-	SHA512                    // import crypto/sha512
-	MD5SHA1                   // no implementation; MD5+SHA1 used for TLS RSA
-	RIPEMD160                 // import golang.org/x/crypto/ripemd160
-	SHA3_224                  // import golang.org/x/crypto/sha3
-	SHA3_256                  // import golang.org/x/crypto/sha3
-	SHA3_384                  // import golang.org/x/crypto/sha3
-	SHA3_512                  // import golang.org/x/crypto/sha3
+	MD4        Hash = 1 + iota // import golang.org/x/crypto/md4
+	MD5                        // import crypto/md5
+	SHA1                       // import crypto/sha1
+	SHA224                     // import crypto/sha256
+	SHA256                     // import crypto/sha256
+	SHA384                     // import crypto/sha512
+	SHA512                     // import crypto/sha512
+	MD5SHA1                    // no implementation; MD5+SHA1 used for TLS RSA
+	RIPEMD160                  // import golang.org/x/crypto/ripemd160
+	SHA3_224                   // import golang.org/x/crypto/sha3
+	SHA3_256                   // import golang.org/x/crypto/sha3
+	SHA3_384                   // import golang.org/x/crypto/sha3
+	SHA3_512                   // import golang.org/x/crypto/sha3
+	SHA512_224                 // import crypto/sha512
+	SHA512_256                 // import crypto/sha512
 	maxHash
 )
 
 var digestSizes = []uint8{
-	MD4:       16,
-	MD5:       16,
-	SHA1:      20,
-	SHA224:    28,
-	SHA256:    32,
-	SHA384:    48,
-	SHA512:    64,
-	SHA3_224:  28,
-	SHA3_256:  32,
-	SHA3_384:  48,
-	SHA3_512:  64,
-	MD5SHA1:   36,
-	RIPEMD160: 20,
+	MD4:        16,
+	MD5:        16,
+	SHA1:       20,
+	SHA224:     28,
+	SHA256:     32,
+	SHA384:     48,
+	SHA512:     64,
+	SHA512_224: 28,
+	SHA512_256: 32,
+	SHA3_224:   28,
+	SHA3_256:   32,
+	SHA3_384:   48,
+	SHA3_512:   64,
+	MD5SHA1:    36,
+	RIPEMD160:  20,
 }
 
 // Size returns the length, in bytes, of a digest resulting from the given hash
@@ -124,3 +128,19 @@ type SignerOpts interface {
 	// hashing was done.
 	HashFunc() Hash
 }
+
+// Decrypter is an interface for an opaque private key that can be used for
+// asymmetric decryption operations. An example would be 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 d613553..8d66477 100644
--- a/src/crypto/ecdsa/ecdsa.go
+++ b/src/crypto/ecdsa/ecdsa.go
@@ -4,22 +4,33 @@
 
 // Package ecdsa implements the Elliptic Curve Digital Signature Algorithm, as
 // defined in FIPS 186-3.
+//
+// This implementation  derives the nonce from an AES-CTR CSPRNG keyed by
+// ChopMD(256, SHA2-512(priv.D || entropy || hash)). The CSPRNG key is IRO by
+// a result of Coron; the AES-CTR stream is IRO under standard assumptions.
 package ecdsa
 
 // References:
 //   [NSA]: Suite B implementer's guide to FIPS 186-3,
 //     http://www.nsa.gov/ia/_files/ecdsa.pdf
 //   [SECG]: SECG, SEC1
-//     http://www.secg.org/download/aid-780/sec1-v2.pdf
+//     http://www.secg.org/sec1-v2.pdf
 
 import (
 	"crypto"
+	"crypto/aes"
+	"crypto/cipher"
 	"crypto/elliptic"
+	"crypto/sha512"
 	"encoding/asn1"
 	"io"
 	"math/big"
 )
 
+const (
+	aesIV = "IV for ECDSA CTR"
+)
+
 // PublicKey represents an ECDSA public key.
 type PublicKey struct {
 	elliptic.Curve
@@ -123,6 +134,38 @@ func fermatInverse(k, N *big.Int) *big.Int {
 // pair of integers. The security of the private key depends on the entropy of
 // rand.
 func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) {
+	// Get max(log2(q) / 2, 256) bits of entropy from rand.
+	entropylen := (priv.Curve.Params().BitSize + 7) / 16
+	if entropylen > 32 {
+		entropylen = 32
+	}
+	entropy := make([]byte, entropylen)
+	_, err = io.ReadFull(rand, entropy)
+	if err != nil {
+		return
+	}
+
+	// Initialize an SHA-512 hash context; digest ...
+	md := sha512.New()
+	md.Write(priv.D.Bytes()) // the private key,
+	md.Write(entropy)        // the entropy,
+	md.Write(hash)           // and the input hash;
+	key := md.Sum(nil)[:32]  // and compute ChopMD-256(SHA-512),
+	// which is an indifferentiable MAC.
+
+	// Create an AES-CTR instance to use as a CSPRNG.
+	block, err := aes.NewCipher(key)
+	if err != nil {
+		return nil, nil, err
+	}
+
+	// Create a CSPRNG that xors a stream of zeros with
+	// the output of the AES-CTR instance.
+	csprng := cipher.StreamReader{
+		R: zeroReader,
+		S: cipher.NewCTR(block, []byte(aesIV)),
+	}
+
 	// See [NSA] 3.4.1
 	c := priv.PublicKey.Curve
 	N := c.Params().N
@@ -130,7 +173,7 @@ func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err err
 	var k, kInv *big.Int
 	for {
 		for {
-			k, err = randFieldElement(c, rand)
+			k, err = randFieldElement(c, csprng)
 			if err != nil {
 				r = nil
 				return
@@ -187,3 +230,17 @@ func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool {
 	x.Mod(x, N)
 	return x.Cmp(r) == 0
 }
+
+type zr struct {
+	io.Reader
+}
+
+// Read replaces the contents of dst with zeros.
+func (z *zr) Read(dst []byte) (n int, err error) {
+	for i := range dst {
+		dst[i] = 0
+	}
+	return len(dst), nil
+}
+
+var zeroReader = &zr{}
diff --git a/src/crypto/ecdsa/ecdsa_test.go b/src/crypto/ecdsa/ecdsa_test.go
index 0c06431..169944d 100644
--- a/src/crypto/ecdsa/ecdsa_test.go
+++ b/src/crypto/ecdsa/ecdsa_test.go
@@ -72,6 +72,78 @@ func TestSignAndVerify(t *testing.T) {
 	testSignAndVerify(t, elliptic.P521(), "p521")
 }
 
+func testNonceSafety(t *testing.T, c elliptic.Curve, tag string) {
+	priv, _ := GenerateKey(c, rand.Reader)
+
+	hashed := []byte("testing")
+	r0, s0, err := Sign(zeroReader, priv, hashed)
+	if err != nil {
+		t.Errorf("%s: error signing: %s", tag, err)
+		return
+	}
+
+	hashed = []byte("testing...")
+	r1, s1, err := Sign(zeroReader, priv, hashed)
+	if err != nil {
+		t.Errorf("%s: error signing: %s", tag, err)
+		return
+	}
+
+	if s0.Cmp(s1) == 0 {
+		// This should never happen.
+		t.Errorf("%s: the signatures on two different messages were the same")
+	}
+
+	if r0.Cmp(r1) == 0 {
+		t.Errorf("%s: the nonce used for two diferent messages was the same")
+	}
+}
+
+func TestNonceSafety(t *testing.T) {
+	testNonceSafety(t, elliptic.P224(), "p224")
+	if testing.Short() {
+		return
+	}
+	testNonceSafety(t, elliptic.P256(), "p256")
+	testNonceSafety(t, elliptic.P384(), "p384")
+	testNonceSafety(t, elliptic.P521(), "p521")
+}
+
+func testINDCCA(t *testing.T, c elliptic.Curve, tag string) {
+	priv, _ := GenerateKey(c, rand.Reader)
+
+	hashed := []byte("testing")
+	r0, s0, err := Sign(rand.Reader, priv, hashed)
+	if err != nil {
+		t.Errorf("%s: error signing: %s", tag, err)
+		return
+	}
+
+	r1, s1, err := Sign(rand.Reader, priv, hashed)
+	if err != nil {
+		t.Errorf("%s: error signing: %s", tag, err)
+		return
+	}
+
+	if s0.Cmp(s1) == 0 {
+		t.Errorf("%s: two signatures of the same message produced the same result")
+	}
+
+	if r0.Cmp(r1) == 0 {
+		t.Errorf("%s: two signatures of the same message produced the same nonce")
+	}
+}
+
+func TestINDCCA(t *testing.T) {
+	testINDCCA(t, elliptic.P224(), "p224")
+	if testing.Short() {
+		return
+	}
+	testINDCCA(t, elliptic.P256(), "p256")
+	testINDCCA(t, elliptic.P384(), "p384")
+	testINDCCA(t, elliptic.P521(), "p521")
+}
+
 func fromHex(s string) *big.Int {
 	r, ok := new(big.Int).SetString(s, 16)
 	if !ok {
diff --git a/src/crypto/elliptic/elliptic.go b/src/crypto/elliptic/elliptic.go
index ba673f8..e6b59c5 100644
--- a/src/crypto/elliptic/elliptic.go
+++ b/src/crypto/elliptic/elliptic.go
@@ -24,7 +24,7 @@ import (
 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)
@@ -45,6 +45,7 @@ type CurveParams struct {
 	B       *big.Int // the constant of the curve equation
 	Gx, Gy  *big.Int // (x,y) of the base point
 	BitSize int      // the size of the underlying field
+	Name    string   // the canonical name of the curve
 }
 
 func (curve *CurveParams) Params() *CurveParams {
@@ -307,7 +308,8 @@ func Marshal(curve Curve, x, y *big.Int) []byte {
 	return ret
 }
 
-// Unmarshal converts a point, serialized by Marshal, into an x, y pair. On error, x = nil.
+// Unmarshal converts a point, serialized by Marshal, into an x, y pair.
+// It is an error if the point is not on the curve. On error, x = nil.
 func Unmarshal(curve Curve, data []byte) (x, y *big.Int) {
 	byteLen := (curve.Params().BitSize + 7) >> 3
 	if len(data) != 1+2*byteLen {
@@ -318,6 +320,9 @@ func Unmarshal(curve Curve, data []byte) (x, y *big.Int) {
 	}
 	x = new(big.Int).SetBytes(data[1 : 1+byteLen])
 	y = new(big.Int).SetBytes(data[1+byteLen:])
+	if !curve.IsOnCurve(x, y) {
+		x, y = nil, nil
+	}
 	return
 }
 
@@ -334,7 +339,7 @@ func initAll() {
 
 func initP384() {
 	// See FIPS 186-3, section D.2.4
-	p384 = new(CurveParams)
+	p384 = &CurveParams{Name: "P-384"}
 	p384.P, _ = new(big.Int).SetString("39402006196394479212279040100143613805079739270465446667948293404245721771496870329047266088258938001861606973112319", 10)
 	p384.N, _ = new(big.Int).SetString("39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942643", 10)
 	p384.B, _ = new(big.Int).SetString("b3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef", 16)
@@ -345,7 +350,7 @@ func initP384() {
 
 func initP521() {
 	// See FIPS 186-3, section D.2.5
-	p521 = new(CurveParams)
+	p521 = &CurveParams{Name: "P-521"}
 	p521.P, _ = new(big.Int).SetString("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151", 10)
 	p521.N, _ = new(big.Int).SetString("6864797660130609714981900799081393217269435300143305409394463459185543183397655394245057746333217197532963996371363321113864768612440380340372808892707005449", 10)
 	p521.B, _ = new(big.Int).SetString("051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00", 16)
diff --git a/src/crypto/elliptic/elliptic_test.go b/src/crypto/elliptic/elliptic_test.go
index 4dc27c9..7e27913 100644
--- a/src/crypto/elliptic/elliptic_test.go
+++ b/src/crypto/elliptic/elliptic_test.go
@@ -19,6 +19,19 @@ func TestOnCurve(t *testing.T) {
 	}
 }
 
+func TestOffCurve(t *testing.T) {
+	p224 := P224()
+	x, y := new(big.Int).SetInt64(1), new(big.Int).SetInt64(1)
+	if p224.IsOnCurve(x, y) {
+		t.Errorf("FAIL: point off curve is claimed to be on the curve")
+	}
+	b := Marshal(p224, x, y)
+	x1, y1 := Unmarshal(p224, b)
+	if x1 != nil || y1 != nil {
+		t.Errorf("FAIL: unmarshalling a point not on the curve succeeded")
+	}
+}
+
 type baseMultTest struct {
 	k    string
 	x, y string
diff --git a/src/crypto/elliptic/p224.go b/src/crypto/elliptic/p224.go
index 1f7ff3f..2d3fac7 100644
--- a/src/crypto/elliptic/p224.go
+++ b/src/crypto/elliptic/p224.go
@@ -22,7 +22,7 @@ type p224Curve struct {
 
 func initP224() {
 	// See FIPS 186-3, section D.2.2
-	p224.CurveParams = new(CurveParams)
+	p224.CurveParams = &CurveParams{Name: "P-224"}
 	p224.P, _ = new(big.Int).SetString("26959946667150639794667015087019630673557916260026308143510066298881", 10)
 	p224.N, _ = new(big.Int).SetString("26959946667150639794667015087019625940457807714424391721682722368061", 10)
 	p224.B, _ = new(big.Int).SetString("b4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4", 16)
diff --git a/src/crypto/elliptic/p256.go b/src/crypto/elliptic/p256.go
index 82be51e..82bc7b3 100644
--- a/src/crypto/elliptic/p256.go
+++ b/src/crypto/elliptic/p256.go
@@ -23,7 +23,7 @@ var (
 
 func initP256() {
 	// See FIPS 186-3, section D.2.3
-	p256.CurveParams = new(CurveParams)
+	p256.CurveParams = &CurveParams{Name: "P-256"}
 	p256.P, _ = new(big.Int).SetString("115792089210356248762697446949407573530086143415290314195533631308867097853951", 10)
 	p256.N, _ = new(big.Int).SetString("115792089210356248762697446949407573529996955224135760342422259061068512044369", 10)
 	p256.B, _ = new(big.Int).SetString("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16)
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 @@ The receiver verifies the hash by recomputing it using the same key.
 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/md5/md5block_arm.s b/src/crypto/md5/md5block_arm.s
index 3b26e54..f1f0f67 100644
--- a/src/crypto/md5/md5block_arm.s
+++ b/src/crypto/md5/md5block_arm.s
@@ -7,20 +7,20 @@
 #include "textflag.h"
 
 // Register definitions
-table = 0	// Pointer to MD5 constants table
-data = 1	// Pointer to data to hash
-a = 2		// MD5 accumulator
-b = 3		// MD5 accumulator
-c = 4		// MD5 accumulator
-d = 5		// MD5 accumulator
-c0 = 6		// MD5 constant
-c1 = 7		// MD5 constant
-c2 = 8		// MD5 constant
+#define Rtable	R0	// Pointer to MD5 constants table
+#define Rdata	R1	// Pointer to data to hash
+#define Ra	R2	// MD5 accumulator
+#define Rb	R3	// MD5 accumulator
+#define Rc	R4	// MD5 accumulator
+#define Rd	R5	// MD5 accumulator
+#define Rc0	R6	// MD5 constant
+#define Rc1	R7	// MD5 constant
+#define Rc2	R8	// MD5 constant
 // r9, r10 are forbidden
 // r11 is OK provided you check the assembler that no synthetic instructions use it
-c3 = 11		// MD5 constant
-t0 = 12		// temporary
-t1 = 14		// temporary
+#define Rc3	R11	// MD5 constant
+#define Rt0	R12	// temporary
+#define Rt1	R14	// temporary
 
 // func block(dig *digest, p []byte)
 // 0(FP) is *digest
@@ -29,198 +29,198 @@ t1 = 14		// temporary
 //12(FP) is p.cap
 //
 // Stack frame
-p_end = -4	// -4(SP) pointer to the end of data
-p_data = -8	// -8(SP) current data pointer
-buf = -8-4*16	//-72(SP) 16 words temporary buffer
+#define p_end	end-4(SP)	// pointer to the end of data
+#define p_data	data-8(SP)	// current data pointer
+#define buf	buffer-(8+4*16)(SP)	//16 words temporary buffer
 		// 3 words at 4..12(R13) for called routine parameters
 
 TEXT	·block(SB), NOSPLIT, $84-16
-	MOVW	p+4(FP), R(data)	// pointer to the data
-	MOVW	p_len+8(FP), R(t0)	// number of bytes
-	ADD	R(data), R(t0)
-	MOVW	R(t0), p_end(SP)	// pointer to end of data
+	MOVW	p+4(FP), Rdata	// pointer to the data
+	MOVW	p_len+8(FP), Rt0	// number of bytes
+	ADD	Rdata, Rt0
+	MOVW	Rt0, p_end	// pointer to end of data
 
 loop:
-	MOVW	R(data), p_data(SP)	// Save R(data)
-	AND.S	$3, R(data), R(t0)	// TST $3, R(data) not working see issue 5921
+	MOVW	Rdata, p_data	// Save Rdata
+	AND.S	$3, Rdata, Rt0	// TST $3, Rdata not working see issue 5921
 	BEQ	aligned			// aligned detected - skip copy
 
 	// Copy the unaligned source data into the aligned temporary buffer
 	// memove(to=4(R13), from=8(R13), n=12(R13)) - Corrupts all registers
-	MOVW	$buf(SP), R(table)	// to
-	MOVW	$64, R(c0)		// n
-	MOVM.IB	[R(table),R(data),R(c0)], (R13)
+	MOVW	$buf, Rtable	// to
+	MOVW	$64, Rc0		// n
+	MOVM.IB	[Rtable,Rdata,Rc0], (R13)
 	BL	runtime·memmove(SB)
 
 	// Point to the local aligned copy of the data
-	MOVW	$buf(SP), R(data)
+	MOVW	$buf, Rdata
 
 aligned:
 	// Point to the table of constants
 	// A PC relative add would be cheaper than this
-	MOVW	$·table(SB), R(table)
+	MOVW	$·table(SB), Rtable
 
 	// Load up initial MD5 accumulator
-	MOVW	dig+0(FP), R(c0)
-	MOVM.IA (R(c0)), [R(a),R(b),R(c),R(d)]
+	MOVW	dig+0(FP), Rc0
+	MOVM.IA (Rc0), [Ra,Rb,Rc,Rd]
 
 // a += (((c^d)&b)^d) + X[index] + const
 // a = a<<shift | a>>(32-shift) + b
-#define ROUND1(a, b, c, d, index, shift, const) \
-	EOR	R(c), R(d), R(t0)		; \
-	AND	R(b), R(t0)			; \
-	EOR	R(d), R(t0)			; \
-	MOVW	(index<<2)(R(data)), R(t1)	; \
-	ADD	R(t1), R(t0)			; \
-	ADD	R(const), R(t0)			; \
-	ADD	R(t0), R(a)			; \
-	ADD	R(a)@>(32-shift), R(b), R(a)	;
-
-	MOVM.IA.W (R(table)), [R(c0),R(c1),R(c2),R(c3)]
-	ROUND1(a, b, c, d,  0,	7, c0)
-	ROUND1(d, a, b, c,  1, 12, c1)
-	ROUND1(c, d, a, b,  2, 17, c2)
-	ROUND1(b, c, d, a,  3, 22, c3)
-
-	MOVM.IA.W (R(table)), [R(c0),R(c1),R(c2),R(c3)]
-	ROUND1(a, b, c, d,  4,	7, c0)
-	ROUND1(d, a, b, c,  5, 12, c1)
-	ROUND1(c, d, a, b,  6, 17, c2)
-	ROUND1(b, c, d, a,  7, 22, c3)
-
-	MOVM.IA.W (R(table)), [R(c0),R(c1),R(c2),R(c3)]
-	ROUND1(a, b, c, d,  8,	7, c0)
-	ROUND1(d, a, b, c,  9, 12, c1)
-	ROUND1(c, d, a, b, 10, 17, c2)
-	ROUND1(b, c, d, a, 11, 22, c3)
-
-	MOVM.IA.W (R(table)), [R(c0),R(c1),R(c2),R(c3)]
-	ROUND1(a, b, c, d, 12,	7, c0)
-	ROUND1(d, a, b, c, 13, 12, c1)
-	ROUND1(c, d, a, b, 14, 17, c2)
-	ROUND1(b, c, d, a, 15, 22, c3)
+#define ROUND1(Ra, Rb, Rc, Rd, index, shift, Rconst) \
+	EOR	Rc, Rd, Rt0		; \
+	AND	Rb, Rt0			; \
+	EOR	Rd, Rt0			; \
+	MOVW	(index<<2)(Rdata), Rt1	; \
+	ADD	Rt1, Rt0			; \
+	ADD	Rconst, Rt0			; \
+	ADD	Rt0, Ra			; \
+	ADD	Ra@>(32-shift), Rb, Ra	;
+
+	MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3]
+	ROUND1(Ra, Rb, Rc, Rd,  0,	7, Rc0)
+	ROUND1(Rd, Ra, Rb, Rc,  1, 12, Rc1)
+	ROUND1(Rc, Rd, Ra, Rb,  2, 17, Rc2)
+	ROUND1(Rb, Rc, Rd, Ra,  3, 22, Rc3)
+
+	MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3]
+	ROUND1(Ra, Rb, Rc, Rd,  4,	7, Rc0)
+	ROUND1(Rd, Ra, Rb, Rc,  5, 12, Rc1)
+	ROUND1(Rc, Rd, Ra, Rb,  6, 17, Rc2)
+	ROUND1(Rb, Rc, Rd, Ra,  7, 22, Rc3)
+
+	MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3]
+	ROUND1(Ra, Rb, Rc, Rd,  8,	7, Rc0)
+	ROUND1(Rd, Ra, Rb, Rc,  9, 12, Rc1)
+	ROUND1(Rc, Rd, Ra, Rb, 10, 17, Rc2)
+	ROUND1(Rb, Rc, Rd, Ra, 11, 22, Rc3)
+
+	MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3]
+	ROUND1(Ra, Rb, Rc, Rd, 12,	7, Rc0)
+	ROUND1(Rd, Ra, Rb, Rc, 13, 12, Rc1)
+	ROUND1(Rc, Rd, Ra, Rb, 14, 17, Rc2)
+	ROUND1(Rb, Rc, Rd, Ra, 15, 22, Rc3)
 
 // a += (((b^c)&d)^c) + X[index] + const
 // a = a<<shift | a>>(32-shift) + b
-#define ROUND2(a, b, c, d, index, shift, const) \
-	EOR	R(b), R(c), R(t0)		; \
-	AND	R(d), R(t0)			; \
-	EOR	R(c), R(t0)			; \
-	MOVW	(index<<2)(R(data)), R(t1)	; \
-	ADD	R(t1), R(t0)			; \
-	ADD	R(const), R(t0)			; \
-	ADD	R(t0), R(a)			; \
-	ADD	R(a)@>(32-shift), R(b), R(a)	;
-
-	MOVM.IA.W (R(table)), [R(c0),R(c1),R(c2),R(c3)]
-	ROUND2(a, b, c, d,  1,	5, c0)
-	ROUND2(d, a, b, c,  6,	9, c1)
-	ROUND2(c, d, a, b, 11, 14, c2)
-	ROUND2(b, c, d, a,  0, 20, c3)
-
-	MOVM.IA.W (R(table)), [R(c0),R(c1),R(c2),R(c3)]
-	ROUND2(a, b, c, d,  5,	5, c0)
-	ROUND2(d, a, b, c, 10,	9, c1)
-	ROUND2(c, d, a, b, 15, 14, c2)
-	ROUND2(b, c, d, a,  4, 20, c3)
-
-	MOVM.IA.W (R(table)), [R(c0),R(c1),R(c2),R(c3)]
-	ROUND2(a, b, c, d,  9,	5, c0)
-	ROUND2(d, a, b, c, 14,	9, c1)
-	ROUND2(c, d, a, b,  3, 14, c2)
-	ROUND2(b, c, d, a,  8, 20, c3)
-
-	MOVM.IA.W (R(table)), [R(c0),R(c1),R(c2),R(c3)]
-	ROUND2(a, b, c, d, 13,	5, c0)
-	ROUND2(d, a, b, c,  2,	9, c1)
-	ROUND2(c, d, a, b,  7, 14, c2)
-	ROUND2(b, c, d, a, 12, 20, c3)
+#define ROUND2(Ra, Rb, Rc, Rd, index, shift, Rconst) \
+	EOR	Rb, Rc, Rt0		; \
+	AND	Rd, Rt0			; \
+	EOR	Rc, Rt0			; \
+	MOVW	(index<<2)(Rdata), Rt1	; \
+	ADD	Rt1, Rt0			; \
+	ADD	Rconst, Rt0			; \
+	ADD	Rt0, Ra			; \
+	ADD	Ra@>(32-shift), Rb, Ra	;
+
+	MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3]
+	ROUND2(Ra, Rb, Rc, Rd,  1,	5, Rc0)
+	ROUND2(Rd, Ra, Rb, Rc,  6,	9, Rc1)
+	ROUND2(Rc, Rd, Ra, Rb, 11, 14, Rc2)
+	ROUND2(Rb, Rc, Rd, Ra,  0, 20, Rc3)
+
+	MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3]
+	ROUND2(Ra, Rb, Rc, Rd,  5,	5, Rc0)
+	ROUND2(Rd, Ra, Rb, Rc, 10,	9, Rc1)
+	ROUND2(Rc, Rd, Ra, Rb, 15, 14, Rc2)
+	ROUND2(Rb, Rc, Rd, Ra,  4, 20, Rc3)
+
+	MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3]
+	ROUND2(Ra, Rb, Rc, Rd,  9,	5, Rc0)
+	ROUND2(Rd, Ra, Rb, Rc, 14,	9, Rc1)
+	ROUND2(Rc, Rd, Ra, Rb,  3, 14, Rc2)
+	ROUND2(Rb, Rc, Rd, Ra,  8, 20, Rc3)
+
+	MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3]
+	ROUND2(Ra, Rb, Rc, Rd, 13,	5, Rc0)
+	ROUND2(Rd, Ra, Rb, Rc,  2,	9, Rc1)
+	ROUND2(Rc, Rd, Ra, Rb,  7, 14, Rc2)
+	ROUND2(Rb, Rc, Rd, Ra, 12, 20, Rc3)
 
 // a += (b^c^d) + X[index] + const
 // a = a<<shift | a>>(32-shift) + b
-#define ROUND3(a, b, c, d, index, shift, const) \
-	EOR	R(b), R(c), R(t0)		; \
-	EOR	R(d), R(t0)			; \
-	MOVW	(index<<2)(R(data)), R(t1)	; \
-	ADD	R(t1), R(t0)			; \
-	ADD	R(const), R(t0)			; \
-	ADD	R(t0), R(a)			; \
-	ADD	R(a)@>(32-shift), R(b), R(a)	;
-
-	MOVM.IA.W (R(table)), [R(c0),R(c1),R(c2),R(c3)]
-	ROUND3(a, b, c, d,  5,	4, c0)
-	ROUND3(d, a, b, c,  8, 11, c1)
-	ROUND3(c, d, a, b, 11, 16, c2)
-	ROUND3(b, c, d, a, 14, 23, c3)
-
-	MOVM.IA.W (R(table)), [R(c0),R(c1),R(c2),R(c3)]
-	ROUND3(a, b, c, d,  1,	4, c0)
-	ROUND3(d, a, b, c,  4, 11, c1)
-	ROUND3(c, d, a, b,  7, 16, c2)
-	ROUND3(b, c, d, a, 10, 23, c3)
-
-	MOVM.IA.W (R(table)), [R(c0),R(c1),R(c2),R(c3)]
-	ROUND3(a, b, c, d, 13,	4, c0)
-	ROUND3(d, a, b, c,  0, 11, c1)
-	ROUND3(c, d, a, b,  3, 16, c2)
-	ROUND3(b, c, d, a,  6, 23, c3)
-
-	MOVM.IA.W (R(table)), [R(c0),R(c1),R(c2),R(c3)]
-	ROUND3(a, b, c, d,  9,	4, c0)
-	ROUND3(d, a, b, c, 12, 11, c1)
-	ROUND3(c, d, a, b, 15, 16, c2)
-	ROUND3(b, c, d, a,  2, 23, c3)
+#define ROUND3(Ra, Rb, Rc, Rd, index, shift, Rconst) \
+	EOR	Rb, Rc, Rt0		; \
+	EOR	Rd, Rt0			; \
+	MOVW	(index<<2)(Rdata), Rt1	; \
+	ADD	Rt1, Rt0			; \
+	ADD	Rconst, Rt0			; \
+	ADD	Rt0, Ra			; \
+	ADD	Ra@>(32-shift), Rb, Ra	;
+
+	MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3]
+	ROUND3(Ra, Rb, Rc, Rd,  5,	4, Rc0)
+	ROUND3(Rd, Ra, Rb, Rc,  8, 11, Rc1)
+	ROUND3(Rc, Rd, Ra, Rb, 11, 16, Rc2)
+	ROUND3(Rb, Rc, Rd, Ra, 14, 23, Rc3)
+
+	MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3]
+	ROUND3(Ra, Rb, Rc, Rd,  1,	4, Rc0)
+	ROUND3(Rd, Ra, Rb, Rc,  4, 11, Rc1)
+	ROUND3(Rc, Rd, Ra, Rb,  7, 16, Rc2)
+	ROUND3(Rb, Rc, Rd, Ra, 10, 23, Rc3)
+
+	MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3]
+	ROUND3(Ra, Rb, Rc, Rd, 13,	4, Rc0)
+	ROUND3(Rd, Ra, Rb, Rc,  0, 11, Rc1)
+	ROUND3(Rc, Rd, Ra, Rb,  3, 16, Rc2)
+	ROUND3(Rb, Rc, Rd, Ra,  6, 23, Rc3)
+
+	MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3]
+	ROUND3(Ra, Rb, Rc, Rd,  9,	4, Rc0)
+	ROUND3(Rd, Ra, Rb, Rc, 12, 11, Rc1)
+	ROUND3(Rc, Rd, Ra, Rb, 15, 16, Rc2)
+	ROUND3(Rb, Rc, Rd, Ra,  2, 23, Rc3)
 
 // a += (c^(b|^d)) + X[index] + const
 // a = a<<shift | a>>(32-shift) + b
-#define ROUND4(a, b, c, d, index, shift, const) \
-	MVN	R(d), R(t0)			; \
-	ORR	R(b), R(t0)			; \
-	EOR	R(c), R(t0)			; \
-	MOVW	(index<<2)(R(data)), R(t1)	; \
-	ADD	R(t1), R(t0)			; \
-	ADD	R(const), R(t0)			; \
-	ADD	R(t0), R(a)			; \
-	ADD	R(a)@>(32-shift), R(b), R(a)	;
-
-	MOVM.IA.W (R(table)), [R(c0),R(c1),R(c2),R(c3)]
-	ROUND4(a, b, c, d,  0,	6, c0)
-	ROUND4(d, a, b, c,  7, 10, c1)
-	ROUND4(c, d, a, b, 14, 15, c2)
-	ROUND4(b, c, d, a,  5, 21, c3)
-
-	MOVM.IA.W (R(table)), [R(c0),R(c1),R(c2),R(c3)]
-	ROUND4(a, b, c, d, 12,	6, c0)
-	ROUND4(d, a, b, c,  3, 10, c1)
-	ROUND4(c, d, a, b, 10, 15, c2)
-	ROUND4(b, c, d, a,  1, 21, c3)
-
-	MOVM.IA.W (R(table)), [R(c0),R(c1),R(c2),R(c3)]
-	ROUND4(a, b, c, d,  8,	6, c0)
-	ROUND4(d, a, b, c, 15, 10, c1)
-	ROUND4(c, d, a, b,  6, 15, c2)
-	ROUND4(b, c, d, a, 13, 21, c3)
-
-	MOVM.IA.W (R(table)), [R(c0),R(c1),R(c2),R(c3)]
-	ROUND4(a, b, c, d,  4,	6, c0)
-	ROUND4(d, a, b, c, 11, 10, c1)
-	ROUND4(c, d, a, b,  2, 15, c2)
-	ROUND4(b, c, d, a,  9, 21, c3)
-
-	MOVW	dig+0(FP), R(t0)
-	MOVM.IA (R(t0)), [R(c0),R(c1),R(c2),R(c3)]
-
-	ADD	R(c0), R(a)
-	ADD	R(c1), R(b)
-	ADD	R(c2), R(c)
-	ADD	R(c3), R(d)
-
-	MOVM.IA [R(a),R(b),R(c),R(d)], (R(t0))
-
-	MOVW	p_data(SP), R(data)
-	MOVW	p_end(SP), R(t0)
-	ADD	$64, R(data)
-	CMP	R(t0), R(data)
+#define ROUND4(Ra, Rb, Rc, Rd, index, shift, Rconst) \
+	MVN	Rd, Rt0			; \
+	ORR	Rb, Rt0			; \
+	EOR	Rc, Rt0			; \
+	MOVW	(index<<2)(Rdata), Rt1	; \
+	ADD	Rt1, Rt0			; \
+	ADD	Rconst, Rt0			; \
+	ADD	Rt0, Ra			; \
+	ADD	Ra@>(32-shift), Rb, Ra	;
+
+	MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3]
+	ROUND4(Ra, Rb, Rc, Rd,  0,	6, Rc0)
+	ROUND4(Rd, Ra, Rb, Rc,  7, 10, Rc1)
+	ROUND4(Rc, Rd, Ra, Rb, 14, 15, Rc2)
+	ROUND4(Rb, Rc, Rd, Ra,  5, 21, Rc3)
+
+	MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3]
+	ROUND4(Ra, Rb, Rc, Rd, 12,	6, Rc0)
+	ROUND4(Rd, Ra, Rb, Rc,  3, 10, Rc1)
+	ROUND4(Rc, Rd, Ra, Rb, 10, 15, Rc2)
+	ROUND4(Rb, Rc, Rd, Ra,  1, 21, Rc3)
+
+	MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3]
+	ROUND4(Ra, Rb, Rc, Rd,  8,	6, Rc0)
+	ROUND4(Rd, Ra, Rb, Rc, 15, 10, Rc1)
+	ROUND4(Rc, Rd, Ra, Rb,  6, 15, Rc2)
+	ROUND4(Rb, Rc, Rd, Ra, 13, 21, Rc3)
+
+	MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3]
+	ROUND4(Ra, Rb, Rc, Rd,  4,	6, Rc0)
+	ROUND4(Rd, Ra, Rb, Rc, 11, 10, Rc1)
+	ROUND4(Rc, Rd, Ra, Rb,  2, 15, Rc2)
+	ROUND4(Rb, Rc, Rd, Ra,  9, 21, Rc3)
+
+	MOVW	dig+0(FP), Rt0
+	MOVM.IA (Rt0), [Rc0,Rc1,Rc2,Rc3]
+
+	ADD	Rc0, Ra
+	ADD	Rc1, Rb
+	ADD	Rc2, Rc
+	ADD	Rc3, Rd
+
+	MOVM.IA [Ra,Rb,Rc,Rd], (Rt0)
+
+	MOVW	p_data, Rdata
+	MOVW	p_end, Rt0
+	ADD	$64, Rdata
+	CMP	Rt0, Rdata
 	BLO	loop
 
 	RET
diff --git a/src/crypto/rand/eagain.go b/src/crypto/rand/eagain.go
new file mode 100644
index 0000000..2c853d0
--- /dev/null
+++ b/src/crypto/rand/eagain.go
@@ -0,0 +1,27 @@
+// 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 darwin dragonfly freebsd linux nacl netbsd openbsd solaris
+
+package rand
+
+import (
+	"os"
+	"syscall"
+)
+
+func init() {
+	isEAGAIN = unixIsEAGAIN
+}
+
+// unixIsEAGAIN reports whether err is a syscall.EAGAIN wrapped in a PathError.
+// See golang.org/issue/9205
+func unixIsEAGAIN(err error) bool {
+	if pe, ok := err.(*os.PathError); ok {
+		if errno, ok := pe.Err.(syscall.Errno); ok && errno == syscall.EAGAIN {
+			return true
+		}
+	}
+	return false
+}
diff --git a/src/crypto/rand/rand.go b/src/crypto/rand/rand.go
index 4da3adb..ee32fa0 100644
--- a/src/crypto/rand/rand.go
+++ b/src/crypto/rand/rand.go
@@ -10,7 +10,9 @@ import "io"
 
 // Reader is a global, shared instance of a cryptographically
 // strong pseudo-random generator.
+//
 // On Unix-like systems, Reader reads from /dev/urandom.
+// On Linux, Reader uses getrandom(2) if available, /dev/urandom otherwise.
 // On Windows systems, Reader uses the CryptGenRandom API.
 var Reader io.Reader
 
diff --git a/src/crypto/rand/rand_linux.go b/src/crypto/rand/rand_linux.go
index 8cb59c7..7d6d9e8 100644
--- a/src/crypto/rand/rand_linux.go
+++ b/src/crypto/rand/rand_linux.go
@@ -5,7 +5,7 @@
 package rand
 
 import (
-	"internal/syscall"
+	"internal/syscall/unix"
 	"sync"
 )
 
@@ -25,7 +25,7 @@ func pickStrategy() {
 	// - the machine has no entropy available (early boot + no hardware
 	//   entropy source?) and we want to avoid blocking later.
 	var buf [1]byte
-	n, err := syscall.GetRandom(buf[:], syscall.GRND_NONBLOCK)
+	n, err := unix.GetRandom(buf[:], unix.GRND_NONBLOCK)
 	useSyscall = n == 1 && err == nil
 }
 
@@ -34,6 +34,6 @@ func getRandomLinux(p []byte) (ok bool) {
 	if !useSyscall {
 		return false
 	}
-	n, err := syscall.GetRandom(p, 0)
+	n, err := unix.GetRandom(p, 0)
 	return n == len(p) && err == nil
 }
diff --git a/src/crypto/rand/rand_unix.go b/src/crypto/rand/rand_unix.go
index 62d0fbd..75c36e0 100644
--- a/src/crypto/rand/rand_unix.go
+++ b/src/crypto/rand/rand_unix.go
@@ -58,12 +58,28 @@ func (r *devReader) Read(b []byte) (n int, err error) {
 		if runtime.GOOS == "plan9" {
 			r.f = f
 		} else {
-			r.f = bufio.NewReader(f)
+			r.f = bufio.NewReader(hideAgainReader{f})
 		}
 	}
 	return r.f.Read(b)
 }
 
+var isEAGAIN func(error) bool // set by eagain.go on unix systems
+
+// hideAgainReader masks EAGAIN reads from /dev/urandom.
+// See golang.org/issue/9205
+type hideAgainReader struct {
+	r io.Reader
+}
+
+func (hr hideAgainReader) Read(p []byte) (n int, err error) {
+	n, err = hr.r.Read(p)
+	if err != nil && isEAGAIN != nil && isEAGAIN(err) {
+		err = nil
+	}
+	return
+}
+
 // Alternate pseudo-random implementation for use on
 // systems without a reliable /dev/urandom.
 
diff --git a/src/crypto/rand/util_test.go b/src/crypto/rand/util_test.go
index 1e2a4dd..2f7cba8 100644
--- a/src/crypto/rand/util_test.go
+++ b/src/crypto/rand/util_test.go
@@ -10,7 +10,7 @@ import (
 	"testing"
 )
 
-// http://golang.org/issue/6849.
+// https://golang.org/issue/6849.
 func TestPrimeSmall(t *testing.T) {
 	for n := 2; n < 10; n++ {
 		p, err := rand.Prime(rand.Reader, n)
diff --git a/src/crypto/rc4/rc4_arm.s b/src/crypto/rc4/rc4_arm.s
index 51be3bf..05e94cb 100644
--- a/src/crypto/rc4/rc4_arm.s
+++ b/src/crypto/rc4/rc4_arm.s
@@ -7,56 +7,56 @@
 #include "textflag.h"
 
 // Registers
-dst = 0
-src = 1
-n = 2
-state = 3
-pi = 4
-pj = 5
-i = 6
-j = 7
-k = 8
-t = 11
-t2 = 12
+#define Rdst	R0
+#define Rsrc	R1
+#define Rn	R2
+#define Rstate	R3
+#define Rpi	R4
+#define Rpj	R5
+#define Ri	R6
+#define Rj	R7
+#define Rk	R8
+#define Rt	R11
+#define Rt2	R12
 
 // func xorKeyStream(dst, src *byte, n int, state *[256]byte, i, j *uint8)
 TEXT ·xorKeyStream(SB),NOSPLIT,$0
-	MOVW 0(FP), R(dst)
-	MOVW 4(FP), R(src)
-	MOVW 8(FP), R(n)
-	MOVW 12(FP), R(state)
-	MOVW 16(FP), R(pi)
-	MOVW 20(FP), R(pj)
-	MOVBU (R(pi)), R(i)
-	MOVBU (R(pj)), R(j)
-	MOVW $0, R(k)
+	MOVW dst+0(FP), Rdst
+	MOVW src+4(FP), Rsrc
+	MOVW n+8(FP), Rn
+	MOVW state+12(FP), Rstate
+	MOVW pi+16(FP), Rpi
+	MOVW pj+20(FP), Rpj
+	MOVBU (Rpi), Ri
+	MOVBU (Rpj), Rj
+	MOVW $0, Rk
 
 loop:
 	// i += 1; j += state[i]
-	ADD $1, R(i)
-	AND $0xff, R(i)
-	MOVBU R(i)<<2(R(state)), R(t)
-	ADD R(t), R(j)
-	AND $0xff, R(j)
+	ADD $1, Ri
+	AND $0xff, Ri
+	MOVBU Ri<<2(Rstate), Rt
+	ADD Rt, Rj
+	AND $0xff, Rj
 
 	// swap state[i] <-> state[j]
-	MOVBU R(j)<<2(R(state)), R(t2)
-	MOVB R(t2), R(i)<<2(R(state))
-	MOVB R(t), R(j)<<2(R(state))
+	MOVBU Rj<<2(Rstate), Rt2
+	MOVB Rt2, Ri<<2(Rstate)
+	MOVB Rt, Rj<<2(Rstate)
 
 	// dst[k] = src[k] ^ state[state[i] + state[j]]
-	ADD R(t2), R(t)
-	AND $0xff, R(t)
-	MOVBU R(t)<<2(R(state)), R(t)
-	MOVBU R(k)<<0(R(src)), R(t2)
-	EOR R(t), R(t2)
-	MOVB R(t2), R(k)<<0(R(dst))
-
-	ADD $1, R(k)
-	CMP R(k), R(n)
+	ADD Rt2, Rt
+	AND $0xff, Rt
+	MOVBU Rt<<2(Rstate), Rt
+	MOVBU Rk<<0(Rsrc), Rt2
+	EOR Rt, Rt2
+	MOVB Rt2, Rk<<0(Rdst)
+
+	ADD $1, Rk
+	CMP Rk, Rn
 	BNE loop
 
 done:
-	MOVB R(i), (R(pi))
-	MOVB R(j), (R(pj))
+	MOVB Ri, (Rpi)
+	MOVB Rj, (Rpj)
 	RET
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 @@ import (
 
 // 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 @@ var decryptPKCS1v15Tests = []DecryptPKCS1v15Test{
 }
 
 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 TestEncryptPKCS1v15SessionKey(t *testing.T) {
 	}
 }
 
+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/pss.go b/src/crypto/rsa/pss.go
index e9f2908..0a41814 100644
--- a/src/crypto/rsa/pss.go
+++ b/src/crypto/rsa/pss.go
@@ -255,7 +255,7 @@ func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte,
 		saltLength = hash.Size()
 	}
 
-	if opts.Hash != 0 {
+	if opts != nil && opts.Hash != 0 {
 		hash = opts.Hash
 	}
 
diff --git a/src/crypto/rsa/pss_test.go b/src/crypto/rsa/pss_test.go
index 32e6fc3..cae24e5 100644
--- a/src/crypto/rsa/pss_test.go
+++ b/src/crypto/rsa/pss_test.go
@@ -189,6 +189,15 @@ func TestPSSOpenSSL(t *testing.T) {
 	}
 }
 
+func TestPSSNilOpts(t *testing.T) {
+	hash := crypto.SHA256
+	h := hash.New()
+	h.Write([]byte("testing"))
+	hashed := h.Sum(nil)
+
+	SignPSS(rand.Reader, rsaPrivateKey, hash, hashed, nil)
+}
+
 func TestPSSSigning(t *testing.T) {
 	var saltLengthCombinations = []struct {
 		signSaltLength, verifySaltLength int
diff --git a/src/crypto/rsa/rsa.go b/src/crypto/rsa/rsa.go
index 2702311..1293b78 100644
--- a/src/crypto/rsa/rsa.go
+++ b/src/crypto/rsa/rsa.go
@@ -24,6 +24,16 @@ type PublicKey struct {
 	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 @@ func (priv *PrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts)
 	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
@@ -88,7 +129,7 @@ type PrecomputedValues struct {
 	CRTValues []CRTValue
 }
 
-// CRTValue contains the precomputed chinese remainder theorem values.
+// CRTValue contains the precomputed Chinese remainder theorem values.
 type CRTValue struct {
 	Exp   *big.Int // D mod (prime-1).
 	Coeff *big.Int // R·Coeff ≡ 1 mod Prime.
@@ -102,19 +143,13 @@ func (priv *PrivateKey) Validate() error {
 		return err
 	}
 
-	// Check that the prime factors are actually prime. Note that this is
-	// just a sanity check. Since the random witnesses chosen by
-	// ProbablyPrime are deterministic, given the candidate number, it's
-	// easy for an attack to generate composites that pass this test.
-	for _, prime := range priv.Primes {
-		if !prime.ProbablyPrime(20) {
-			return errors.New("crypto/rsa: prime factor is composite")
-		}
-	}
-
 	// Check that Πprimes == n.
 	modulus := new(big.Int).Set(bigOne)
 	for _, prime := range priv.Primes {
+		// Any primes ≤ 1 will cause divide-by-zero panics later.
+		if prime.Cmp(bigOne) <= 0 {
+			return errors.New("crypto/rsa: invalid prime value")
+		}
 		modulus.Mul(modulus, prime)
 	}
 	if modulus.Cmp(priv.N) != 0 {
diff --git a/src/crypto/sha1/sha1block_arm.s b/src/crypto/sha1/sha1block_arm.s
index f11f33d..c06d4ba 100644
--- a/src/crypto/sha1/sha1block_arm.s
+++ b/src/crypto/sha1/sha1block_arm.s
@@ -23,20 +23,20 @@
 // the round macros instead of by explicit move instructions.
 
 // Register definitions
-data = 0	// Pointer to incoming data
-const = 1	// Current constant for SHA round
-a = 2		// SHA1 accumulator
-b = 3		// SHA1 accumulator
-c = 4		// SHA1 accumulator
-d = 5		// SHA1 accumulator
-e = 6		// SHA1 accumulator
-t0 = 7		// Temporary
-t1 = 8		// Temporary
+#define Rdata	R0	// Pointer to incoming data
+#define Rconst	R1	// Current constant for SHA round
+#define Ra	R2		// SHA1 accumulator
+#define Rb	R3		// SHA1 accumulator
+#define Rc	R4		// SHA1 accumulator
+#define Rd	R5		// SHA1 accumulator
+#define Re	R6		// SHA1 accumulator
+#define Rt0	R7		// Temporary
+#define Rt1	R8		// Temporary
 // r9, r10 are forbidden
 // r11 is OK provided you check the assembler that no synthetic instructions use it
-t2 = 11		// Temporary
-ctr = 12	// loop counter
-w = 14		// point to w buffer
+#define Rt2	R11		// Temporary
+#define Rctr	R12	// loop counter
+#define Rw	R14		// point to w buffer
 
 // func block(dig *digest, p []byte)
 // 0(FP) is *digest
@@ -45,173 +45,173 @@ w = 14		// point to w buffer
 //12(FP) is p.cap
 //
 // Stack frame
-p_end = -4		// -4(SP) pointer to the end of data
-p_data = p_end - 4	// -8(SP) current data pointer
-w_buf = p_data - 4*80	// -328(SP) 80 words temporary buffer w uint32[80]
-saved = w_buf - 4*5	// -348(SP) saved sha1 registers a,b,c,d,e - these must be last
+#define p_end	end-4(SP)		// pointer to the end of data
+#define p_data	data-8(SP)	// current data pointer (unused?)
+#define w_buf	buf-(8+4*80)(SP)	//80 words temporary buffer w uint32[80]
+#define saved	abcde-(8+4*80+4*5)(SP)	// saved sha1 registers a,b,c,d,e - these must be last (unused?)
 // Total size +4 for saved LR is 352
 
 	// w[i] = p[j]<<24 | p[j+1]<<16 | p[j+2]<<8 | p[j+3]
 	// e += w[i]
-#define LOAD(e) \
-	MOVBU	2(R(data)), R(t0) ; \
-	MOVBU	3(R(data)), R(t1) ; \
-	MOVBU	1(R(data)), R(t2) ; \
-	ORR	R(t0)<<8, R(t1), R(t0)	    ; \
-	MOVBU.P	4(R(data)), R(t1) ; \
-	ORR	R(t2)<<16, R(t0), R(t0)	    ; \
-	ORR	R(t1)<<24, R(t0), R(t0)	    ; \
-	MOVW.P	R(t0), 4(R(w))		    ; \
-	ADD	R(t0), R(e), R(e)
+#define LOAD(Re) \
+	MOVBU	2(Rdata), Rt0 ; \
+	MOVBU	3(Rdata), Rt1 ; \
+	MOVBU	1(Rdata), Rt2 ; \
+	ORR	Rt0<<8, Rt1, Rt0	    ; \
+	MOVBU.P	4(Rdata), Rt1 ; \
+	ORR	Rt2<<16, Rt0, Rt0	    ; \
+	ORR	Rt1<<24, Rt0, Rt0	    ; \
+	MOVW.P	Rt0, 4(Rw)		    ; \
+	ADD	Rt0, Re, Re
 	
 	// tmp := w[(i-3)&0xf] ^ w[(i-8)&0xf] ^ w[(i-14)&0xf] ^ w[(i)&0xf]
 	// w[i&0xf] = tmp<<1 | tmp>>(32-1)
 	// e += w[i&0xf] 
-#define SHUFFLE(e) \
-	MOVW	(-16*4)(R(w)), R(t0) ; \
-	MOVW	(-14*4)(R(w)), R(t1) ; \
-	MOVW	(-8*4)(R(w)), R(t2)  ; \
-	EOR	R(t0), R(t1), R(t0)  ; \
-	MOVW	(-3*4)(R(w)), R(t1)  ; \
-	EOR	R(t2), R(t0), R(t0)  ; \
-	EOR	R(t0), R(t1), R(t0)  ; \
-	MOVW	R(t0)@>(32-1), R(t0)  ; \
-	MOVW.P	R(t0), 4(R(w))	  ; \
-	ADD	R(t0), R(e), R(e)
+#define SHUFFLE(Re) \
+	MOVW	(-16*4)(Rw), Rt0 ; \
+	MOVW	(-14*4)(Rw), Rt1 ; \
+	MOVW	(-8*4)(Rw), Rt2  ; \
+	EOR	Rt0, Rt1, Rt0  ; \
+	MOVW	(-3*4)(Rw), Rt1  ; \
+	EOR	Rt2, Rt0, Rt0  ; \
+	EOR	Rt0, Rt1, Rt0  ; \
+	MOVW	Rt0@>(32-1), Rt0  ; \
+	MOVW.P	Rt0, 4(Rw)	  ; \
+	ADD	Rt0, Re, Re
 
 	// t1 = (b & c) | ((~b) & d)
-#define FUNC1(a, b, c, d, e) \
-	MVN	R(b), R(t1)	   ; \
-	AND	R(b), R(c), R(t0)  ; \
-	AND	R(d), R(t1), R(t1) ; \
-	ORR	R(t0), R(t1), R(t1)
+#define FUNC1(Ra, Rb, Rc, Rd, Re) \
+	MVN	Rb, Rt1	   ; \
+	AND	Rb, Rc, Rt0  ; \
+	AND	Rd, Rt1, Rt1 ; \
+	ORR	Rt0, Rt1, Rt1
 
 	// t1 = b ^ c ^ d
-#define FUNC2(a, b, c, d, e) \
-	EOR	R(b), R(c), R(t1) ; \
-	EOR	R(d), R(t1), R(t1)
+#define FUNC2(Ra, Rb, Rc, Rd, Re) \
+	EOR	Rb, Rc, Rt1 ; \
+	EOR	Rd, Rt1, Rt1
 
 	// t1 = (b & c) | (b & d) | (c & d) =
 	// t1 = (b & c) | ((b | c) & d)
-#define FUNC3(a, b, c, d, e) \
-	ORR	R(b), R(c), R(t0)  ; \
-	AND	R(b), R(c), R(t1)  ; \
-	AND	R(d), R(t0), R(t0) ; \
-	ORR	R(t0), R(t1), R(t1)
+#define FUNC3(Ra, Rb, Rc, Rd, Re) \
+	ORR	Rb, Rc, Rt0  ; \
+	AND	Rb, Rc, Rt1  ; \
+	AND	Rd, Rt0, Rt0 ; \
+	ORR	Rt0, Rt1, Rt1
 
 #define FUNC4 FUNC2
 
 	// a5 := a<<5 | a>>(32-5)
 	// b = b<<30 | b>>(32-30)
 	// e = a5 + t1 + e + const
-#define MIX(a, b, c, d, e) \
-	ADD	R(t1), R(e), R(e)	 ; \
-	MOVW	R(b)@>(32-30), R(b)	 ; \
-	ADD	R(a)@>(32-5), R(e), R(e) ; \
-	ADD	R(const), R(e), R(e)
-
-#define ROUND1(a, b, c, d, e) \
-	LOAD(e)		; \
-	FUNC1(a, b, c, d, e)	; \
-	MIX(a, b, c, d, e)
-
-#define ROUND1x(a, b, c, d, e) \
-	SHUFFLE(e)	; \
-	FUNC1(a, b, c, d, e)	; \
-	MIX(a, b, c, d, e)
-
-#define ROUND2(a, b, c, d, e) \
-	SHUFFLE(e)	; \
-	FUNC2(a, b, c, d, e)	; \
-	MIX(a, b, c, d, e)
-
-#define ROUND3(a, b, c, d, e) \
-	SHUFFLE(e)	; \
-	FUNC3(a, b, c, d, e)	; \
-	MIX(a, b, c, d, e)
-
-#define ROUND4(a, b, c, d, e) \
-	SHUFFLE(e)	; \
-	FUNC4(a, b, c, d, e)	; \
-	MIX(a, b, c, d, e)
+#define MIX(Ra, Rb, Rc, Rd, Re) \
+	ADD	Rt1, Re, Re	 ; \
+	MOVW	Rb@>(32-30), Rb	 ; \
+	ADD	Ra@>(32-5), Re, Re ; \
+	ADD	Rconst, Re, Re
+
+#define ROUND1(Ra, Rb, Rc, Rd, Re) \
+	LOAD(Re)		; \
+	FUNC1(Ra, Rb, Rc, Rd, Re)	; \
+	MIX(Ra, Rb, Rc, Rd, Re)
+
+#define ROUND1x(Ra, Rb, Rc, Rd, Re) \
+	SHUFFLE(Re)	; \
+	FUNC1(Ra, Rb, Rc, Rd, Re)	; \
+	MIX(Ra, Rb, Rc, Rd, Re)
+
+#define ROUND2(Ra, Rb, Rc, Rd, Re) \
+	SHUFFLE(Re)	; \
+	FUNC2(Ra, Rb, Rc, Rd, Re)	; \
+	MIX(Ra, Rb, Rc, Rd, Re)
+
+#define ROUND3(Ra, Rb, Rc, Rd, Re) \
+	SHUFFLE(Re)	; \
+	FUNC3(Ra, Rb, Rc, Rd, Re)	; \
+	MIX(Ra, Rb, Rc, Rd, Re)
+
+#define ROUND4(Ra, Rb, Rc, Rd, Re) \
+	SHUFFLE(Re)	; \
+	FUNC4(Ra, Rb, Rc, Rd, Re)	; \
+	MIX(Ra, Rb, Rc, Rd, Re)
 
 
 // func block(dig *digest, p []byte)
 TEXT	·block(SB), 0, $352-16
-	MOVW	p+4(FP), R(data)	// pointer to the data
-	MOVW	p_len+8(FP), R(t0)	// number of bytes
-	ADD	R(data), R(t0)
-	MOVW	R(t0), p_end(SP)	// pointer to end of data
+	MOVW	p+4(FP), Rdata	// pointer to the data
+	MOVW	p_len+8(FP), Rt0	// number of bytes
+	ADD	Rdata, Rt0
+	MOVW	Rt0, p_end	// pointer to end of data
 
 	// Load up initial SHA1 accumulator
-	MOVW	dig+0(FP), R(t0)
-	MOVM.IA (R(t0)), [R(a),R(b),R(c),R(d),R(e)]
+	MOVW	dig+0(FP), Rt0
+	MOVM.IA (Rt0), [Ra,Rb,Rc,Rd,Re]
 
 loop:
 	// Save registers at SP+4 onwards
-	MOVM.IB [R(a),R(b),R(c),R(d),R(e)], (R13)
-
-	MOVW	$w_buf(SP), R(w)
-	MOVW	$0x5A827999, R(const)
-	MOVW	$3, R(ctr)
-loop1:	ROUND1(a, b, c, d, e)
-	ROUND1(e, a, b, c, d)
-	ROUND1(d, e, a, b, c)
-	ROUND1(c, d, e, a, b)
-	ROUND1(b, c, d, e, a)
-	SUB.S	$1, R(ctr)
+	MOVM.IB [Ra,Rb,Rc,Rd,Re], (R13)
+
+	MOVW	$w_buf, Rw
+	MOVW	$0x5A827999, Rconst
+	MOVW	$3, Rctr
+loop1:	ROUND1(Ra, Rb, Rc, Rd, Re)
+	ROUND1(Re, Ra, Rb, Rc, Rd)
+	ROUND1(Rd, Re, Ra, Rb, Rc)
+	ROUND1(Rc, Rd, Re, Ra, Rb)
+	ROUND1(Rb, Rc, Rd, Re, Ra)
+	SUB.S	$1, Rctr
 	BNE	loop1
 
-	ROUND1(a, b, c, d, e)
-	ROUND1x(e, a, b, c, d)
-	ROUND1x(d, e, a, b, c)
-	ROUND1x(c, d, e, a, b)
-	ROUND1x(b, c, d, e, a)
+	ROUND1(Ra, Rb, Rc, Rd, Re)
+	ROUND1x(Re, Ra, Rb, Rc, Rd)
+	ROUND1x(Rd, Re, Ra, Rb, Rc)
+	ROUND1x(Rc, Rd, Re, Ra, Rb)
+	ROUND1x(Rb, Rc, Rd, Re, Ra)
 	
-	MOVW	$0x6ED9EBA1, R(const)
-	MOVW	$4, R(ctr)
-loop2:	ROUND2(a, b, c, d, e)
-	ROUND2(e, a, b, c, d)
-	ROUND2(d, e, a, b, c)
-	ROUND2(c, d, e, a, b)
-	ROUND2(b, c, d, e, a)
-	SUB.S	$1, R(ctr)
+	MOVW	$0x6ED9EBA1, Rconst
+	MOVW	$4, Rctr
+loop2:	ROUND2(Ra, Rb, Rc, Rd, Re)
+	ROUND2(Re, Ra, Rb, Rc, Rd)
+	ROUND2(Rd, Re, Ra, Rb, Rc)
+	ROUND2(Rc, Rd, Re, Ra, Rb)
+	ROUND2(Rb, Rc, Rd, Re, Ra)
+	SUB.S	$1, Rctr
 	BNE	loop2
 	
-	MOVW	$0x8F1BBCDC, R(const)
-	MOVW	$4, R(ctr)
-loop3:	ROUND3(a, b, c, d, e)
-	ROUND3(e, a, b, c, d)
-	ROUND3(d, e, a, b, c)
-	ROUND3(c, d, e, a, b)
-	ROUND3(b, c, d, e, a)
-	SUB.S	$1, R(ctr)
+	MOVW	$0x8F1BBCDC, Rconst
+	MOVW	$4, Rctr
+loop3:	ROUND3(Ra, Rb, Rc, Rd, Re)
+	ROUND3(Re, Ra, Rb, Rc, Rd)
+	ROUND3(Rd, Re, Ra, Rb, Rc)
+	ROUND3(Rc, Rd, Re, Ra, Rb)
+	ROUND3(Rb, Rc, Rd, Re, Ra)
+	SUB.S	$1, Rctr
 	BNE	loop3
 	
-	MOVW	$0xCA62C1D6, R(const)
-	MOVW	$4, R(ctr)
-loop4:	ROUND4(a, b, c, d, e)
-	ROUND4(e, a, b, c, d)
-	ROUND4(d, e, a, b, c)
-	ROUND4(c, d, e, a, b)
-	ROUND4(b, c, d, e, a)
-	SUB.S	$1, R(ctr)
+	MOVW	$0xCA62C1D6, Rconst
+	MOVW	$4, Rctr
+loop4:	ROUND4(Ra, Rb, Rc, Rd, Re)
+	ROUND4(Re, Ra, Rb, Rc, Rd)
+	ROUND4(Rd, Re, Ra, Rb, Rc)
+	ROUND4(Rc, Rd, Re, Ra, Rb)
+	ROUND4(Rb, Rc, Rd, Re, Ra)
+	SUB.S	$1, Rctr
 	BNE	loop4
 
 	// Accumulate - restoring registers from SP+4
-	MOVM.IB (R13), [R(t0),R(t1),R(t2),R(ctr),R(w)]
-	ADD	R(t0), R(a)
-	ADD	R(t1), R(b)
-	ADD	R(t2), R(c)
-	ADD	R(ctr), R(d)
-	ADD	R(w), R(e)
-
-	MOVW	p_end(SP), R(t0)
-	CMP	R(t0), R(data)
+	MOVM.IB (R13), [Rt0,Rt1,Rt2,Rctr,Rw]
+	ADD	Rt0, Ra
+	ADD	Rt1, Rb
+	ADD	Rt2, Rc
+	ADD	Rctr, Rd
+	ADD	Rw, Re
+
+	MOVW	p_end, Rt0
+	CMP	Rt0, Rdata
 	BLO	loop
 
 	// Save final SHA1 accumulator
-	MOVW	dig+0(FP), R(t0)
-	MOVM.IA [R(a),R(b),R(c),R(d),R(e)], (R(t0))
+	MOVW	dig+0(FP), Rt0
+	MOVM.IA [Ra,Rb,Rc,Rd,Re], (Rt0)
 
 	RET
diff --git a/src/crypto/sha512/sha512.go b/src/crypto/sha512/sha512.go
index bca7a91..e7781fd 100644
--- a/src/crypto/sha512/sha512.go
+++ b/src/crypto/sha512/sha512.go
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Package sha512 implements the SHA384 and SHA512 hash algorithms as defined
-// in FIPS 180-2.
+// Package sha512 implements the SHA-384, SHA-512, SHA-512/224, and SHA-512/256
+// hash algorithms as defined in FIPS 180-4.
 package sha512
 
 import (
@@ -14,16 +14,27 @@ import (
 func init() {
 	crypto.RegisterHash(crypto.SHA384, New384)
 	crypto.RegisterHash(crypto.SHA512, New)
+	crypto.RegisterHash(crypto.SHA512_224, New512_224)
+	crypto.RegisterHash(crypto.SHA512_256, New512_256)
 }
 
-// The size of a SHA512 checksum in bytes.
-const Size = 64
+const (
+	// Size is the size, in bytes, of a SHA-512 checksum.
+	Size = 64
+
+	// Size224 is the size, in bytes, of a SHA-512/224 checksum.
+	Size224 = 28
+
+	// Size256 is the size, in bytes, of a SHA-512/256 checksum.
+	Size256 = 32
 
-// The size of a SHA384 checksum in bytes.
-const Size384 = 48
+	// Size384 is the size, in bytes, of a SHA-384 checksum.
+	Size384 = 48
 
-// The blocksize of SHA512 and SHA384 in bytes.
-const BlockSize = 128
+	// BlockSize is the block size, in bytes, of the SHA-512/224,
+	// SHA-512/256, SHA-384 and SHA-512 hash functions.
+	BlockSize = 128
+)
 
 const (
 	chunk     = 128
@@ -35,6 +46,22 @@ const (
 	init5     = 0x9b05688c2b3e6c1f
 	init6     = 0x1f83d9abfb41bd6b
 	init7     = 0x5be0cd19137e2179
+	init0_224 = 0x8c3d37c819544da2
+	init1_224 = 0x73e1996689dcd4d6
+	init2_224 = 0x1dfab7ae32ff9c82
+	init3_224 = 0x679dd514582f9fcf
+	init4_224 = 0x0f6d2b697bd44da8
+	init5_224 = 0x77e36f7304c48942
+	init6_224 = 0x3f9d85a86a1d36c8
+	init7_224 = 0x1112e6ad91d692a1
+	init0_256 = 0x22312194fc2bf72c
+	init1_256 = 0x9f555fa3c84c64c2
+	init2_256 = 0x2393b86b6f53b151
+	init3_256 = 0x963877195940eabd
+	init4_256 = 0x96283ee2a88effe3
+	init5_256 = 0xbe5e1e2553863992
+	init6_256 = 0x2b0199fc2c85b8aa
+	init7_256 = 0x0eb72ddc81c52ca2
 	init0_384 = 0xcbbb9d5dc1059ed8
 	init1_384 = 0x629a292a367cd507
 	init2_384 = 0x9159015a3070dd17
@@ -47,24 +74,16 @@ const (
 
 // digest represents the partial evaluation of a checksum.
 type digest struct {
-	h     [8]uint64
-	x     [chunk]byte
-	nx    int
-	len   uint64
-	is384 bool // mark if this digest is SHA-384
+	h        [8]uint64
+	x        [chunk]byte
+	nx       int
+	len      uint64
+	function crypto.Hash
 }
 
 func (d *digest) Reset() {
-	if !d.is384 {
-		d.h[0] = init0
-		d.h[1] = init1
-		d.h[2] = init2
-		d.h[3] = init3
-		d.h[4] = init4
-		d.h[5] = init5
-		d.h[6] = init6
-		d.h[7] = init7
-	} else {
+	switch d.function {
+	case crypto.SHA384:
 		d.h[0] = init0_384
 		d.h[1] = init1_384
 		d.h[2] = init2_384
@@ -73,31 +92,77 @@ func (d *digest) Reset() {
 		d.h[5] = init5_384
 		d.h[6] = init6_384
 		d.h[7] = init7_384
+	case crypto.SHA512_224:
+		d.h[0] = init0_224
+		d.h[1] = init1_224
+		d.h[2] = init2_224
+		d.h[3] = init3_224
+		d.h[4] = init4_224
+		d.h[5] = init5_224
+		d.h[6] = init6_224
+		d.h[7] = init7_224
+	case crypto.SHA512_256:
+		d.h[0] = init0_256
+		d.h[1] = init1_256
+		d.h[2] = init2_256
+		d.h[3] = init3_256
+		d.h[4] = init4_256
+		d.h[5] = init5_256
+		d.h[6] = init6_256
+		d.h[7] = init7_256
+	default:
+		d.h[0] = init0
+		d.h[1] = init1
+		d.h[2] = init2
+		d.h[3] = init3
+		d.h[4] = init4
+		d.h[5] = init5
+		d.h[6] = init6
+		d.h[7] = init7
 	}
 	d.nx = 0
 	d.len = 0
 }
 
-// New returns a new hash.Hash computing the SHA512 checksum.
+// New returns a new hash.Hash computing the SHA-512 checksum.
 func New() hash.Hash {
-	d := new(digest)
+	d := &digest{function: crypto.SHA512}
 	d.Reset()
 	return d
 }
 
-// New384 returns a new hash.Hash computing the SHA384 checksum.
+// New512_224 returns a new hash.Hash computing the SHA-512/224 checksum.
+func New512_224() hash.Hash {
+	d := &digest{function: crypto.SHA512_224}
+	d.Reset()
+	return d
+}
+
+// New512_256 returns a new hash.Hash computing the SHA-512/256 checksum.
+func New512_256() hash.Hash {
+	d := &digest{function: crypto.SHA512_256}
+	d.Reset()
+	return d
+}
+
+// New384 returns a new hash.Hash computing the SHA-384 checksum.
 func New384() hash.Hash {
-	d := new(digest)
-	d.is384 = true
+	d := &digest{function: crypto.SHA384}
 	d.Reset()
 	return d
 }
 
 func (d *digest) Size() int {
-	if !d.is384 {
+	switch d.function {
+	case crypto.SHA512_224:
+		return Size224
+	case crypto.SHA512_256:
+		return Size256
+	case crypto.SHA384:
+		return Size384
+	default:
 		return Size
 	}
-	return Size384
 }
 
 func (d *digest) BlockSize() int { return BlockSize }
@@ -130,10 +195,16 @@ func (d0 *digest) Sum(in []byte) []byte {
 	d := new(digest)
 	*d = *d0
 	hash := d.checkSum()
-	if d.is384 {
+	switch d.function {
+	case crypto.SHA384:
 		return append(in, hash[:Size384]...)
+	case crypto.SHA512_224:
+		return append(in, hash[:Size224]...)
+	case crypto.SHA512_256:
+		return append(in, hash[:Size256]...)
+	default:
+		return append(in, hash[:]...)
 	}
-	return append(in, hash[:]...)
 }
 
 func (d *digest) checkSum() [Size]byte {
@@ -159,7 +230,7 @@ func (d *digest) checkSum() [Size]byte {
 	}
 
 	h := d.h[:]
-	if d.is384 {
+	if d.function == crypto.SHA384 {
 		h = d.h[:6]
 	}
 
@@ -180,7 +251,7 @@ func (d *digest) checkSum() [Size]byte {
 
 // Sum512 returns the SHA512 checksum of the data.
 func Sum512(data []byte) [Size]byte {
-	var d digest
+	d := digest{function: crypto.SHA512}
 	d.Reset()
 	d.Write(data)
 	return d.checkSum()
@@ -188,11 +259,30 @@ func Sum512(data []byte) [Size]byte {
 
 // Sum384 returns the SHA384 checksum of the data.
 func Sum384(data []byte) (sum384 [Size384]byte) {
-	var d digest
-	d.is384 = true
+	d := digest{function: crypto.SHA384}
 	d.Reset()
 	d.Write(data)
 	sum := d.checkSum()
 	copy(sum384[:], sum[:Size384])
 	return
 }
+
+// Sum512_224 returns the Sum512/224 checksum of the data.
+func Sum512_224(data []byte) (sum224 [Size224]byte) {
+	d := digest{function: crypto.SHA512_224}
+	d.Reset()
+	d.Write(data)
+	sum := d.checkSum()
+	copy(sum224[:], sum[:Size224])
+	return
+}
+
+// Sum512_256 returns the Sum512/256 checksum of the data.
+func Sum512_256(data []byte) (sum256 [Size256]byte) {
+	d := digest{function: crypto.SHA512_256}
+	d.Reset()
+	d.Write(data)
+	sum := d.checkSum()
+	copy(sum256[:], sum[:Size256])
+	return
+}
diff --git a/src/crypto/sha512/sha512_test.go b/src/crypto/sha512/sha512_test.go
index 541860f..04b3d4a 100644
--- a/src/crypto/sha512/sha512_test.go
+++ b/src/crypto/sha512/sha512_test.go
@@ -2,133 +2,279 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// SHA512 hash algorithm.  See FIPS 180-2.
+// SHA512 hash algorithm.  See FIPS 180-4.
 
 package sha512
 
 import (
-	"fmt"
+	"encoding/hex"
+	"hash"
 	"io"
 	"testing"
 )
 
 type sha512Test struct {
-	out string
-	in  string
+	in     string
+	out224 string
+	out256 string
+	out384 string
+	out512 string
 }
 
 var golden = []sha512Test{
-	{"cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e", ""},
-	{"1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75", "a"},
-	{"2d408a0717ec188158278a796c689044361dc6fdde28d6f04973b80896e1823975cdbf12eb63f9e0591328ee235d80e9b5bf1aa6a44f4617ff3caf6400eb172d", "ab"},
-	{"ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", "abc"},
-	{"d8022f2060ad6efd297ab73dcc5355c9b214054b0d1776a136a669d26a7d3b14f73aa0d0ebff19ee333368f0164b6419a96da49e3e481753e7e96b716bdccb6f", "abcd"},
-	{"878ae65a92e86cac011a570d4c30a7eaec442b85ce8eca0c2952b5e3cc0628c2e79d889ad4d5c7c626986d452dd86374b6ffaa7cd8b67665bef2289a5c70b0a1", "abcde"},
-	{"e32ef19623e8ed9d267f657a81944b3d07adbb768518068e88435745564e8d4150a0a703be2a7d88b61e3d390c2bb97e2d4c311fdc69d6b1267f05f59aa920e7", "abcdef"},
-	{"d716a4188569b68ab1b6dfac178e570114cdf0ea3a1cc0e31486c3e41241bc6a76424e8c37ab26f096fc85ef9886c8cb634187f4fddff645fb099f1ff54c6b8c", "abcdefg"},
-	{"a3a8c81bc97c2560010d7389bc88aac974a104e0e2381220c6e084c4dccd1d2d17d4f86db31c2a851dc80e6681d74733c55dcd03dd96f6062cdda12a291ae6ce", "abcdefgh"},
-	{"f22d51d25292ca1d0f68f69aedc7897019308cc9db46efb75a03dd494fc7f126c010e8ade6a00a0c1a5f1b75d81e0ed5a93ce98dc9b833db7839247b1d9c24fe", "abcdefghi"},
-	{"ef6b97321f34b1fea2169a7db9e1960b471aa13302a988087357c520be957ca119c3ba68e6b4982c019ec89de3865ccf6a3cda1fe11e59f98d99f1502c8b9745", "abcdefghij"},
-	{"2210d99af9c8bdecda1b4beff822136753d8342505ddce37f1314e2cdbb488c6016bdaa9bd2ffa513dd5de2e4b50f031393d8ab61f773b0e0130d7381e0f8a1d", "Discard medicine more than two years old."},
-	{"a687a8985b4d8d0a24f115fe272255c6afaf3909225838546159c1ed685c211a203796ae8ecc4c81a5b6315919b3a64f10713da07e341fcdbb08541bf03066ce", "He who has a shady past knows that nice guys finish last."},
-	{"8ddb0392e818b7d585ab22769a50df660d9f6d559cca3afc5691b8ca91b8451374e42bcdabd64589ed7c91d85f626596228a5c8572677eb98bc6b624befb7af8", "I wouldn't marry him with a ten foot pole."},
-	{"26ed8f6ca7f8d44b6a8a54ae39640fa8ad5c673f70ee9ce074ba4ef0d483eea00bab2f61d8695d6b34df9c6c48ae36246362200ed820448bdc03a720366a87c6", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
-	{"e5a14bf044be69615aade89afcf1ab0389d5fc302a884d403579d1386a2400c089b0dbb387ed0f463f9ee342f8244d5a38cfbc0e819da9529fbff78368c9a982", "The days of the digital watch are numbered.  -Tom Stoppard"},
-	{"420a1faa48919e14651bed45725abe0f7a58e0f099424c4e5a49194946e38b46c1f8034b18ef169b2e31050d1648e0b982386595f7df47da4b6fd18e55333015", "Nepal premier won't resign."},
-	{"d926a863beadb20134db07683535c72007b0e695045876254f341ddcccde132a908c5af57baa6a6a9c63e6649bba0c213dc05fadcf9abccea09f23dcfb637fbe", "For every action there is an equal and opposite government program."},
-	{"9a98dd9bb67d0da7bf83da5313dff4fd60a4bac0094f1b05633690ffa7f6d61de9a1d4f8617937d560833a9aaa9ccafe3fd24db418d0e728833545cadd3ad92d", "His money is twice tainted: 'taint yours and 'taint mine."},
-	{"d7fde2d2351efade52f4211d3746a0780a26eec3df9b2ed575368a8a1c09ec452402293a8ea4eceb5a4f60064ea29b13cdd86918cd7a4faf366160b009804107", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
-	{"b0f35ffa2697359c33a56f5c0cf715c7aeed96da9905ca2698acadb08fbc9e669bf566b6bd5d61a3e86dc22999bcc9f2224e33d1d4f32a228cf9d0349e2db518", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
-	{"3d2e5f91778c9e66f7e061293aaa8a8fc742dd3b2e4f483772464b1144189b49273e610e5cccd7a81a19ca1fa70f16b10f1a100a4d8c1372336be8484c64b311", "size:  a.out:  bad magic"},
-	{"b2f68ff58ac015efb1c94c908b0d8c2bf06f491e4de8e6302c49016f7f8a33eac3e959856c7fddbc464de618701338a4b46f76dbfaf9a1e5262b5f40639771c7", "The major problem is with sendmail.  -Mark Horton"},
-	{"d8c92db5fdf52cf8215e4df3b4909d29203ff4d00e9ad0b64a6a4e04dec5e74f62e7c35c7fb881bd5de95442123df8f57a489b0ae616bd326f84d10021121c57", "Give me a rock, paper and scissors and I will move the world.  CCFestoon"},
-	{"19a9f8dc0a233e464e8566ad3ca9b91e459a7b8c4780985b015776e1bf239a19bc233d0556343e2b0a9bc220900b4ebf4f8bdf89ff8efeaf79602d6849e6f72e", "If the enemy is within range, then so are you."},
-	{"00b4c41f307bde87301cdc5b5ab1ae9a592e8ecbb2021dd7bc4b34e2ace60741cc362560bec566ba35178595a91932b8d5357e2c9cec92d393b0fa7831852476", "It's well we cannot hear the screams/That we create in others' dreams."},
-	{"91eccc3d5375fd026e4d6787874b1dce201cecd8a27dbded5065728cb2d09c58a3d467bb1faf353bf7ba567e005245d5321b55bc344f7c07b91cb6f26c959be7", "You remind me of a TV show, but that's all right: I watch it anyway."},
-	{"fabbbe22180f1f137cfdc9556d2570e775d1ae02a597ded43a72a40f9b485d500043b7be128fb9fcd982b83159a0d99aa855a9e7cc4240c00dc01a9bdf8218d7", "C is as portable as Stonehedge!!"},
-	{"2ecdec235c1fa4fc2a154d8fba1dddb8a72a1ad73838b51d792331d143f8b96a9f6fcb0f34d7caa351fe6d88771c4f105040e0392f06e0621689d33b2f3ba92e", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
-	{"7ad681f6f96f82f7abfa7ecc0334e8fa16d3dc1cdc45b60b7af43fe4075d2357c0c1d60e98350f1afb1f2fe7a4d7cd2ad55b88e458e06b73c40b437331f5dab4", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction.  Lewis-Randall Rule"},
-	{"833f9248ab4a3b9e5131f745fda1ffd2dd435b30e965957e78291c7ab73605fd1912b0794e5c233ab0a12d205a39778d19b83515d6a47003f19cdee51d98c7e0", "How can you write a big system without C++?  -Paul Glick"},
+	{
+		"",
+		"6ed0dd02806fa89e25de060c19d3ac86cabb87d6a0ddd05c333b84f4",
+		"c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a",
+		"38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b",
+		"cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e",
+	},
+	{
+		"a",
+		"d5cdb9ccc769a5121d4175f2bfdd13d6310e0d3d361ea75d82108327",
+		"455e518824bc0601f9fb858ff5c37d417d67c2f8e0df2babe4808858aea830f8",
+		"54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31",
+		"1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75",
+	},
+	{
+		"ab",
+		"b35878d07bfedf39fc638af08547eb5d1072d8546319f247b442fbf5",
+		"22d4d37ec6370571af7109fb12eae79673d5f7c83e6e677083faa3cfac3b2c14",
+		"c7be03ba5bcaa384727076db0018e99248e1a6e8bd1b9ef58a9ec9dd4eeebb3f48b836201221175befa74ddc3d35afdd",
+		"2d408a0717ec188158278a796c689044361dc6fdde28d6f04973b80896e1823975cdbf12eb63f9e0591328ee235d80e9b5bf1aa6a44f4617ff3caf6400eb172d",
+	},
+	{
+		"abc",
+		"4634270f707b6a54daae7530460842e20e37ed265ceee9a43e8924aa",
+		"53048e2681941ef99b2e29b76b4c7dabe4c2d0c634fc6d46e0e2f13107e7af23",
+		"cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7",
+		"ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f",
+	},
+	{
+		"abcd",
+		"0c9f157ab030fb06e957c14e3938dc5908962e5dd7b66f04a36fc534",
+		"d2891c7978be0e24948f37caa415b87cb5cbe2b26b7bad9dc6391b8a6f6ddcc9",
+		"1165b3406ff0b52a3d24721f785462ca2276c9f454a116c2b2ba20171a7905ea5a026682eb659c4d5f115c363aa3c79b",
+		"d8022f2060ad6efd297ab73dcc5355c9b214054b0d1776a136a669d26a7d3b14f73aa0d0ebff19ee333368f0164b6419a96da49e3e481753e7e96b716bdccb6f",
+	},
+	{
+		"abcde",
+		"880e79bb0a1d2c9b7528d851edb6b8342c58c831de98123b432a4515",
+		"de8322b46e78b67d4431997070703e9764e03a1237b896fd8b379ed4576e8363",
+		"4c525cbeac729eaf4b4665815bc5db0c84fe6300068a727cf74e2813521565abc0ec57a37ee4d8be89d097c0d2ad52f0",
+		"878ae65a92e86cac011a570d4c30a7eaec442b85ce8eca0c2952b5e3cc0628c2e79d889ad4d5c7c626986d452dd86374b6ffaa7cd8b67665bef2289a5c70b0a1",
+	},
+	{
+		"abcdef",
+		"236c829cfea4fd6d4de61ad15fcf34dca62342adaf9f2001c16f29b8",
+		"e4fdcb11d1ac14e698743acd8805174cea5ddc0d312e3e47f6372032571bad84",
+		"c6a4c65b227e7387b9c3e839d44869c4cfca3ef583dea64117859b808c1e3d8ae689e1e314eeef52a6ffe22681aa11f5",
+		"e32ef19623e8ed9d267f657a81944b3d07adbb768518068e88435745564e8d4150a0a703be2a7d88b61e3d390c2bb97e2d4c311fdc69d6b1267f05f59aa920e7",
+	},
+	{
+		"abcdefg",
+		"4767af672b3ed107f25018dc22d6fa4b07d156e13b720971e2c4f6bf",
+		"a8117f680bdceb5d1443617cbdae9255f6900075422326a972fdd2f65ba9bee3",
+		"9f11fc131123f844c1226f429b6a0a6af0525d9f40f056c7fc16cdf1b06bda08e302554417a59fa7dcf6247421959d22",
+		"d716a4188569b68ab1b6dfac178e570114cdf0ea3a1cc0e31486c3e41241bc6a76424e8c37ab26f096fc85ef9886c8cb634187f4fddff645fb099f1ff54c6b8c",
+	},
+	{
+		"abcdefgh",
+		"792e25e0ae286d123a38950007e037d3122e76c4ee201668c385edab",
+		"a29b9645d2a02a8b582888d044199787220e316bf2e89d1422d3df26bf545bbe",
+		"9000cd7cada59d1d2eb82912f7f24e5e69cc5517f68283b005fa27c285b61e05edf1ad1a8a9bded6fd29eb87d75ad806",
+		"a3a8c81bc97c2560010d7389bc88aac974a104e0e2381220c6e084c4dccd1d2d17d4f86db31c2a851dc80e6681d74733c55dcd03dd96f6062cdda12a291ae6ce",
+	},
+	{
+		"abcdefghi",
+		"56b275d36127dc070cda4019baf2ce2579a25d8c67fa2bc9be61b539",
+		"b955095330f9c8188d11884ec1679dc44c9c5b25ff9bda700416df9cdd39188f",
+		"ef54915b60cf062b8dd0c29ae3cad69abe6310de63ac081f46ef019c5c90897caefd79b796cfa81139788a260ded52df",
+		"f22d51d25292ca1d0f68f69aedc7897019308cc9db46efb75a03dd494fc7f126c010e8ade6a00a0c1a5f1b75d81e0ed5a93ce98dc9b833db7839247b1d9c24fe",
+	},
+	{
+		"abcdefghij",
+		"f809423cbb25e81a2a64aecee2cd5fdc7d91d5db583901fbf1db3116",
+		"550762913d51eefbcd1a55068fcfc9b154fd11c1078b996df0d926ea59d2a68d",
+		"a12070030a02d86b0ddacd0d3a5b598344513d0a051e7355053e556a0055489c1555399b03342845c4adde2dc44ff66c",
+		"ef6b97321f34b1fea2169a7db9e1960b471aa13302a988087357c520be957ca119c3ba68e6b4982c019ec89de3865ccf6a3cda1fe11e59f98d99f1502c8b9745",
+	},
+	{
+		"Discard medicine more than two years old.",
+		"4c46e10b5b72204e509c3c06072cea970bc020cd45a61a0acdfa97ac",
+		"690c8ad3916cefd3ad29226d9875965e3ee9ec0d4482eacc248f2ff4aa0d8e5b",
+		"86f58ec2d74d1b7f8eb0c2ff0967316699639e8d4eb129de54bdf34c96cdbabe200d052149f2dd787f43571ba74670d4",
+		"2210d99af9c8bdecda1b4beff822136753d8342505ddce37f1314e2cdbb488c6016bdaa9bd2ffa513dd5de2e4b50f031393d8ab61f773b0e0130d7381e0f8a1d",
+	},
+	{
+		"He who has a shady past knows that nice guys finish last.",
+		"cb0cef13c1848d91a6d02637c7c520de1914ad4a7aea824671cc328e",
+		"25938ca49f7ef1178ce81620842b65e576245fcaed86026a36b516b80bb86b3b",
+		"ae4a2b639ca9bfa04b1855d5a05fe7f230994f790891c6979103e2605f660c4c1262a48142dcbeb57a1914ba5f7c3fa7",
+		"a687a8985b4d8d0a24f115fe272255c6afaf3909225838546159c1ed685c211a203796ae8ecc4c81a5b6315919b3a64f10713da07e341fcdbb08541bf03066ce",
+	},
+	{
+		"I wouldn't marry him with a ten foot pole.",
+		"6c7bd0f3a6544ea698006c2ea583a85f80ea2913590a186db8bb2f1b",
+		"698e420c3a7038e53d8e73f4be2b02e03b93464ac1a61ebe69f557079921ef65",
+		"40ae213df6436eca952aa6841886fcdb82908ef1576a99c8f49bb9dd5023169f7c53035abdda0b54c302f4974e2105e7",
+		"8ddb0392e818b7d585ab22769a50df660d9f6d559cca3afc5691b8ca91b8451374e42bcdabd64589ed7c91d85f626596228a5c8572677eb98bc6b624befb7af8",
+	},
+	{
+		"Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave",
+		"981323be3eca6ccfa598e58dd74ed8cb05d5f7f6653b7604b684f904",
+		"839b414d7e3900ee243aa3d1f9b6955720e64041f5ab9bedd3eb0a08da5a2ca8",
+		"e7cf8b873c9bc950f06259aa54309f349cefa72c00d597aebf903e6519a50011dfe355afff064a10701c705693848df9",
+		"26ed8f6ca7f8d44b6a8a54ae39640fa8ad5c673f70ee9ce074ba4ef0d483eea00bab2f61d8695d6b34df9c6c48ae36246362200ed820448bdc03a720366a87c6",
+	},
+	{
+		"The days of the digital watch are numbered.  -Tom Stoppard",
+		"e6fbf82df5138bf361e826903cadf0612cb2986649ba47a57e1bca99",
+		"5625ecb9d284e54c00b257b67a8cacb25a78db2845c60ef2d29e43c84f236e8e",
+		"c3d4f0f4047181c7d39d34703365f7bf70207183caf2c2f6145f04da895ef69124d9cdeb635da636c3a474e61024e29b",
+		"e5a14bf044be69615aade89afcf1ab0389d5fc302a884d403579d1386a2400c089b0dbb387ed0f463f9ee342f8244d5a38cfbc0e819da9529fbff78368c9a982",
+	},
+	{
+		"Nepal premier won't resign.",
+		"6ec2cb2ecafc1a9bddaf4caf57344d853e6ded398927d5694fd7714f",
+		"9b81d06bca2f985e6ad3249096ff3c0f2a9ec5bb16ef530d738d19d81e7806f2",
+		"a097aab567e167d5cf93676ed73252a69f9687cb3179bb2d27c9878119e94bf7b7c4b58dc90582edfaf66e11388ed714",
+		"420a1faa48919e14651bed45725abe0f7a58e0f099424c4e5a49194946e38b46c1f8034b18ef169b2e31050d1648e0b982386595f7df47da4b6fd18e55333015",
+	},
+	{
+		"For every action there is an equal and opposite government program.",
+		"7f62f36e716e0badaf4a4658da9d09bea26357a1bc6aeb8cf7c3ae35",
+		"08241df8d91edfcd68bb1a1dada6e0ae1475a5c6e7b8f12d8e24ca43a38240a9",
+		"5026ca45c41fc64712eb65065da92f6467541c78f8966d3fe2c8e3fb769a3ec14215f819654b47bd64f7f0eac17184f3",
+		"d926a863beadb20134db07683535c72007b0e695045876254f341ddcccde132a908c5af57baa6a6a9c63e6649bba0c213dc05fadcf9abccea09f23dcfb637fbe",
+	},
+	{
+		"His money is twice tainted: 'taint yours and 'taint mine.",
+		"45adffcb86a05ee4d91263a6115dda011b805d442c60836963cb8378",
+		"4ff74d9213a8117745f5d37b5353a774ec81c5dfe65c4c8986a56fc01f2c551e",
+		"ac1cc0f5ac8d5f5514a7b738ac322b7fb52a161b449c3672e9b6a6ad1a5e4b26b001cf3bad24c56598676ca17d4b445a",
+		"9a98dd9bb67d0da7bf83da5313dff4fd60a4bac0094f1b05633690ffa7f6d61de9a1d4f8617937d560833a9aaa9ccafe3fd24db418d0e728833545cadd3ad92d",
+	},
+	{
+		"There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977",
+		"51cb518f1f68daa901a3075a0a5e1acc755b4e5c82cb47687537f880",
+		"b5baf747c307f98849ec881cf0d48605ae4edd386372aea9b26e71db517e650b",
+		"722d10c5de371ec0c8c4b5247ac8a5f1d240d68c73f8da13d8b25f0166d6f309bf9561979a111a0049405771d201941a",
+		"d7fde2d2351efade52f4211d3746a0780a26eec3df9b2ed575368a8a1c09ec452402293a8ea4eceb5a4f60064ea29b13cdd86918cd7a4faf366160b009804107",
+	},
+	{
+		"It's a tiny change to the code and not completely disgusting. - Bob Manchek",
+		"3b59c5e64b0da7bfc18d7017bf458d90f2c83601ff1afc6263ac0993",
+		"7eef0538ebd7ecf18611d23b0e1cd26a74d65b929a2e374197dc66e755ca4944",
+		"dc2d3ea18bfa10549c63bf2b75b39b5167a80c12aff0e05443168ea87ff149fb0eda5e0bd234eb5d48c7d02ffc5807f1",
+		"b0f35ffa2697359c33a56f5c0cf715c7aeed96da9905ca2698acadb08fbc9e669bf566b6bd5d61a3e86dc22999bcc9f2224e33d1d4f32a228cf9d0349e2db518",
+	},
+	{
+		"size:  a.out:  bad magic",
+		"6a9525c0fac0f91b489bc4f0f539b9ec4a156a4e98bc15b655c2c881",
+		"d05600964f83f55323104aadab434f32391c029718a7690d08ddb2d7e8708443",
+		"1d67c969e2a945ae5346d2139760261504d4ba164c522443afe19ef3e29b152a4c52445489cfc9d7215e5a450e8e1e4e",
+		"3d2e5f91778c9e66f7e061293aaa8a8fc742dd3b2e4f483772464b1144189b49273e610e5cccd7a81a19ca1fa70f16b10f1a100a4d8c1372336be8484c64b311",
+	},
+	{
+		"The major problem is with sendmail.  -Mark Horton",
+		"a1b2b2905b1527d682049c6a76e35c7d8c72551abfe7833ac1be595f",
+		"53ed5f9b5c0b674ac0f3425d9f9a5d462655b07cc90f5d0f692eec093884a607",
+		"5ff8e075e465646e7b73ef36d812c6e9f7d60fa6ea0e533e5569b4f73cde53cdd2cc787f33540af57cca3fe467d32fe0",
+		"b2f68ff58ac015efb1c94c908b0d8c2bf06f491e4de8e6302c49016f7f8a33eac3e959856c7fddbc464de618701338a4b46f76dbfaf9a1e5262b5f40639771c7",
+	},
+	{
+		"Give me a rock, paper and scissors and I will move the world.  CCFestoon",
+		"76cf045c76a5f2e3d64d56c3cdba6a25479334611bc375460526f8c1",
+		"5a0147685a44eea2435dbd582724efca7637acd9c428e5e1a05115bc3bc2a0e0",
+		"5bd0a997a67c9ae1979a894eb0cde403dde003c9b6f2c03cf21925c42ff4e1176e6df1ca005381612ef18457b9b7ec3b",
+		"d8c92db5fdf52cf8215e4df3b4909d29203ff4d00e9ad0b64a6a4e04dec5e74f62e7c35c7fb881bd5de95442123df8f57a489b0ae616bd326f84d10021121c57",
+	},
+	{
+		"If the enemy is within range, then so are you.",
+		"4473671daeecfdb6f6c5bc06b26374aa5e497cc37119fe14144c430c",
+		"1152c9b27a99dbf4057d21438f4e63dd0cd0977d5ff12317c64d3b97fcac875a",
+		"1eee6da33e7e54fc5be52ae23b94b16ba4d2a947ae4505c6a3edfc7401151ea5205ac01b669b56f27d8ef7f175ed7762",
+		"19a9f8dc0a233e464e8566ad3ca9b91e459a7b8c4780985b015776e1bf239a19bc233d0556343e2b0a9bc220900b4ebf4f8bdf89ff8efeaf79602d6849e6f72e",
+	},
+	{
+		"It's well we cannot hear the screams/That we create in others' dreams.",
+		"6accb6394758523fcd453d47d37ebd10868957a0a9e81c796736abf8",
+		"105e890f5d5cf1748d9a7b4cdaf58b69855779deebc2097747c2210a17b2cb51",
+		"76b06e9dea66bfbb1a96029426dc0dfd7830bd297eb447ff5358d94a87cd00c88b59df2493fef56ecbb5231073892ea9",
+		"00b4c41f307bde87301cdc5b5ab1ae9a592e8ecbb2021dd7bc4b34e2ace60741cc362560bec566ba35178595a91932b8d5357e2c9cec92d393b0fa7831852476",
+	},
+	{
+		"You remind me of a TV show, but that's all right: I watch it anyway.",
+		"6f173f4b6eac7f2a73eaa0833c4563752df2c869dc00b7d30219e12e",
+		"74644ead770da1434365cd912656fe1aca2056d3039d39f10eb1151bddb32cf3",
+		"12acaf21452cff586143e3f5db0bfdf7802c057e1adf2a619031c4e1b0ccc4208cf6cef8fe722bbaa2fb46a30d9135d8",
+		"91eccc3d5375fd026e4d6787874b1dce201cecd8a27dbded5065728cb2d09c58a3d467bb1faf353bf7ba567e005245d5321b55bc344f7c07b91cb6f26c959be7",
+	},
+	{
+		"C is as portable as Stonehedge!!",
+		"db05bf4d0f73325208755f4af96cfac6cb3db5dbfc323d675d68f938",
+		"50a234625de5587581883dad9ef399460928032a5ea6bd005d7dc7b68d8cc3d6",
+		"0fc23d7f4183efd186f0bc4fc5db867e026e2146b06cb3d52f4bdbd57d1740122caa853b41868b197b2ac759db39df88",
+		"fabbbe22180f1f137cfdc9556d2570e775d1ae02a597ded43a72a40f9b485d500043b7be128fb9fcd982b83159a0d99aa855a9e7cc4240c00dc01a9bdf8218d7",
+	},
+	{
+		"Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley",
+		"05ffa71bb02e855de1aaee1777b3bdbaf7507646f19c4c6aa29933d0",
+		"a7a3846005f8a9935a0a2d43e7fd56d95132a9a3609bf3296ef80b8218acffa0",
+		"bc805578a7f85d34a86a32976e1c34fe65cf815186fbef76f46ef99cda10723f971f3f1464d488243f5e29db7488598d",
+		"2ecdec235c1fa4fc2a154d8fba1dddb8a72a1ad73838b51d792331d143f8b96a9f6fcb0f34d7caa351fe6d88771c4f105040e0392f06e0621689d33b2f3ba92e",
+	},
+	{
+		"The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction.  Lewis-Randall Rule",
+		"3ad3c89e15b91e6273534c5d18adadbb528e7b840b288f64e81b8c6d",
+		"688ff03e367680757aa9906cb1e2ad218c51f4526dc0426ea229a5ba9d002c69",
+		"b23918399a12ebf4431559eec3813eaf7412e875fd7464f16d581e473330842d2e96c6be49a7ce3f9bb0b8bc0fcbe0fe",
+		"7ad681f6f96f82f7abfa7ecc0334e8fa16d3dc1cdc45b60b7af43fe4075d2357c0c1d60e98350f1afb1f2fe7a4d7cd2ad55b88e458e06b73c40b437331f5dab4",
+	},
+	{
+		"How can you write a big system without C++?  -Paul Glick",
+		"e3763669d1b760c1be7bfcb6625f92300a8430419d1dbad57ec9f53c",
+		"3fa46d52094b01021cff5af9a438982b887a5793f624c0a6644149b6b7c3f485",
+		"1764b700eb1ead52a2fc33cc28975c2180f1b8faa5038d94cffa8d78154aab16e91dd787e7b0303948ebed62561542c8",
+		"833f9248ab4a3b9e5131f745fda1ffd2dd435b30e965957e78291c7ab73605fd1912b0794e5c233ab0a12d205a39778d19b83515d6a47003f19cdee51d98c7e0",
+	},
 }
 
-var golden384 = []sha512Test{
-	{"38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b", ""},
-	{"54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31", "a"},
-	{"c7be03ba5bcaa384727076db0018e99248e1a6e8bd1b9ef58a9ec9dd4eeebb3f48b836201221175befa74ddc3d35afdd", "ab"},
-	{"cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7", "abc"},
-	{"1165b3406ff0b52a3d24721f785462ca2276c9f454a116c2b2ba20171a7905ea5a026682eb659c4d5f115c363aa3c79b", "abcd"},
-	{"4c525cbeac729eaf4b4665815bc5db0c84fe6300068a727cf74e2813521565abc0ec57a37ee4d8be89d097c0d2ad52f0", "abcde"},
-	{"c6a4c65b227e7387b9c3e839d44869c4cfca3ef583dea64117859b808c1e3d8ae689e1e314eeef52a6ffe22681aa11f5", "abcdef"},
-	{"9f11fc131123f844c1226f429b6a0a6af0525d9f40f056c7fc16cdf1b06bda08e302554417a59fa7dcf6247421959d22", "abcdefg"},
-	{"9000cd7cada59d1d2eb82912f7f24e5e69cc5517f68283b005fa27c285b61e05edf1ad1a8a9bded6fd29eb87d75ad806", "abcdefgh"},
-	{"ef54915b60cf062b8dd0c29ae3cad69abe6310de63ac081f46ef019c5c90897caefd79b796cfa81139788a260ded52df", "abcdefghi"},
-	{"a12070030a02d86b0ddacd0d3a5b598344513d0a051e7355053e556a0055489c1555399b03342845c4adde2dc44ff66c", "abcdefghij"},
-	{"86f58ec2d74d1b7f8eb0c2ff0967316699639e8d4eb129de54bdf34c96cdbabe200d052149f2dd787f43571ba74670d4", "Discard medicine more than two years old."},
-	{"ae4a2b639ca9bfa04b1855d5a05fe7f230994f790891c6979103e2605f660c4c1262a48142dcbeb57a1914ba5f7c3fa7", "He who has a shady past knows that nice guys finish last."},
-	{"40ae213df6436eca952aa6841886fcdb82908ef1576a99c8f49bb9dd5023169f7c53035abdda0b54c302f4974e2105e7", "I wouldn't marry him with a ten foot pole."},
-	{"e7cf8b873c9bc950f06259aa54309f349cefa72c00d597aebf903e6519a50011dfe355afff064a10701c705693848df9", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave"},
-	{"c3d4f0f4047181c7d39d34703365f7bf70207183caf2c2f6145f04da895ef69124d9cdeb635da636c3a474e61024e29b", "The days of the digital watch are numbered.  -Tom Stoppard"},
-	{"a097aab567e167d5cf93676ed73252a69f9687cb3179bb2d27c9878119e94bf7b7c4b58dc90582edfaf66e11388ed714", "Nepal premier won't resign."},
-	{"5026ca45c41fc64712eb65065da92f6467541c78f8966d3fe2c8e3fb769a3ec14215f819654b47bd64f7f0eac17184f3", "For every action there is an equal and opposite government program."},
-	{"ac1cc0f5ac8d5f5514a7b738ac322b7fb52a161b449c3672e9b6a6ad1a5e4b26b001cf3bad24c56598676ca17d4b445a", "His money is twice tainted: 'taint yours and 'taint mine."},
-	{"722d10c5de371ec0c8c4b5247ac8a5f1d240d68c73f8da13d8b25f0166d6f309bf9561979a111a0049405771d201941a", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977"},
-	{"dc2d3ea18bfa10549c63bf2b75b39b5167a80c12aff0e05443168ea87ff149fb0eda5e0bd234eb5d48c7d02ffc5807f1", "It's a tiny change to the code and not completely disgusting. - Bob Manchek"},
-	{"1d67c969e2a945ae5346d2139760261504d4ba164c522443afe19ef3e29b152a4c52445489cfc9d7215e5a450e8e1e4e", "size:  a.out:  bad magic"},
-	{"5ff8e075e465646e7b73ef36d812c6e9f7d60fa6ea0e533e5569b4f73cde53cdd2cc787f33540af57cca3fe467d32fe0", "The major problem is with sendmail.  -Mark Horton"},
-	{"5bd0a997a67c9ae1979a894eb0cde403dde003c9b6f2c03cf21925c42ff4e1176e6df1ca005381612ef18457b9b7ec3b", "Give me a rock, paper and scissors and I will move the world.  CCFestoon"},
-	{"1eee6da33e7e54fc5be52ae23b94b16ba4d2a947ae4505c6a3edfc7401151ea5205ac01b669b56f27d8ef7f175ed7762", "If the enemy is within range, then so are you."},
-	{"76b06e9dea66bfbb1a96029426dc0dfd7830bd297eb447ff5358d94a87cd00c88b59df2493fef56ecbb5231073892ea9", "It's well we cannot hear the screams/That we create in others' dreams."},
-	{"12acaf21452cff586143e3f5db0bfdf7802c057e1adf2a619031c4e1b0ccc4208cf6cef8fe722bbaa2fb46a30d9135d8", "You remind me of a TV show, but that's all right: I watch it anyway."},
-	{"0fc23d7f4183efd186f0bc4fc5db867e026e2146b06cb3d52f4bdbd57d1740122caa853b41868b197b2ac759db39df88", "C is as portable as Stonehedge!!"},
-	{"bc805578a7f85d34a86a32976e1c34fe65cf815186fbef76f46ef99cda10723f971f3f1464d488243f5e29db7488598d", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley"},
-	{"b23918399a12ebf4431559eec3813eaf7412e875fd7464f16d581e473330842d2e96c6be49a7ce3f9bb0b8bc0fcbe0fe", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction.  Lewis-Randall Rule"},
-	{"1764b700eb1ead52a2fc33cc28975c2180f1b8faa5038d94cffa8d78154aab16e91dd787e7b0303948ebed62561542c8", "How can you write a big system without C++?  -Paul Glick"},
-}
+func testHash(t *testing.T, name, in, outHex string, oneShotResult []byte, digestFunc hash.Hash) {
+	if calculated := hex.EncodeToString(oneShotResult); calculated != outHex {
+		t.Errorf("one-shot result for %s(%q) = %q, but expected %q", name, in, calculated, outHex)
+		return
+	}
 
-func TestGolden(t *testing.T) {
-	for i := 0; i < len(golden); i++ {
-		g := golden[i]
-		s := fmt.Sprintf("%x", Sum512([]byte(g.in)))
-		if s != g.out {
-			t.Fatalf("Sum512 function: sha512(%s) = %s want %s", g.in, s, g.out)
+	for pass := 0; pass < 3; pass++ {
+		if pass < 2 {
+			io.WriteString(digestFunc, in)
+		} else {
+			io.WriteString(digestFunc, in[:len(in)/2])
+			digestFunc.Sum(nil)
+			io.WriteString(digestFunc, in[len(in)/2:])
 		}
-		c := New()
-		for j := 0; j < 3; j++ {
-			if j < 2 {
-				io.WriteString(c, g.in)
-			} else {
-				io.WriteString(c, g.in[0:len(g.in)/2])
-				c.Sum(nil)
-				io.WriteString(c, g.in[len(g.in)/2:])
-			}
-			s := fmt.Sprintf("%x", c.Sum(nil))
-			if s != g.out {
-				t.Fatalf("sha512[%d](%s) = %s want %s", j, g.in, s, g.out)
-			}
-			c.Reset()
+
+		if calculated := hex.EncodeToString(digestFunc.Sum(nil)); calculated != outHex {
+			t.Errorf("%s(%q) = %q (in pass #%d), but expected %q", name, in, calculated, pass, outHex)
 		}
+		digestFunc.Reset()
 	}
-	for i := 0; i < len(golden384); i++ {
-		g := golden384[i]
-		s := fmt.Sprintf("%x", Sum384([]byte(g.in)))
-		if s != g.out {
-			t.Fatalf("Sum384 function: sha384(%s) = %s want %s", g.in, s, g.out)
-		}
-		c := New384()
-		for j := 0; j < 3; j++ {
-			if j < 2 {
-				io.WriteString(c, g.in)
-			} else {
-				io.WriteString(c, g.in[0:len(g.in)/2])
-				c.Sum(nil)
-				io.WriteString(c, g.in[len(g.in)/2:])
-			}
-			s := fmt.Sprintf("%x", c.Sum(nil))
-			if s != g.out {
-				t.Fatalf("sha384[%d](%s) = %s want %s", j, g.in, s, g.out)
-			}
-			c.Reset()
-		}
+}
+
+func TestGolden(t *testing.T) {
+	for _, test := range golden {
+		in := []byte(test.in)
+
+		sum224 := Sum512_224(in)
+		sum256 := Sum512_256(in)
+		sum384 := Sum384(in)
+		sum512 := Sum512(in)
+		testHash(t, "SHA512/224", test.in, test.out224, sum224[:], New512_224())
+		testHash(t, "SHA512/256", test.in, test.out256, sum256[:], New512_256())
+		testHash(t, "SHA384", test.in, test.out384, sum384[:], New384())
+		testHash(t, "SHA512", test.in, test.out512, sum512[:], New())
 	}
 }
 
@@ -141,6 +287,14 @@ func TestSize(t *testing.T) {
 	if got := c.Size(); got != Size384 {
 		t.Errorf("New384.Size = %d; want %d", got, Size384)
 	}
+	c = New512_224()
+	if got := c.Size(); got != Size224 {
+		t.Errorf("New512224.Size = %d; want %d", got, Size224)
+	}
+	c = New512_256()
+	if got := c.Size(); got != Size256 {
+		t.Errorf("New512256.Size = %d; want %d", got, Size256)
+	}
 }
 
 func TestBlockSize(t *testing.T) {
diff --git a/src/crypto/tls/cipher_suites.go b/src/crypto/tls/cipher_suites.go
index 226e06d..a5fed29 100644
--- a/src/crypto/tls/cipher_suites.go
+++ b/src/crypto/tls/cipher_suites.go
@@ -48,6 +48,12 @@ const (
 	// suiteTLS12 indicates that the cipher suite should only be advertised
 	// and accepted when using TLS 1.2.
 	suiteTLS12
+	// suiteSHA384 indicates that the cipher suite uses SHA384 as the
+	// handshake hash.
+	suiteSHA384
+	// suiteDefaultOff indicates that this cipher suite is not included by
+	// default.
+	suiteDefaultOff
 )
 
 // A cipherSuite is a specific combination of key agreement, cipher and MAC
@@ -71,13 +77,15 @@ var cipherSuites = []*cipherSuite{
 	// and RC4 comes before AES (because of the Lucky13 attack).
 	{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadAESGCM},
 	{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12, nil, nil, aeadAESGCM},
-	{TLS_ECDHE_RSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheRSAKA, suiteECDHE, cipherRC4, macSHA1, nil},
-	{TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherRC4, macSHA1, nil},
+	{TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
+	{TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
+	{TLS_ECDHE_RSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheRSAKA, suiteECDHE | suiteDefaultOff, cipherRC4, macSHA1, nil},
+	{TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteDefaultOff, cipherRC4, macSHA1, nil},
 	{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil},
 	{TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil},
 	{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil},
 	{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA, cipherAES, macSHA1, nil},
-	{TLS_RSA_WITH_RC4_128_SHA, 16, 20, 0, rsaKA, 0, cipherRC4, macSHA1, nil},
+	{TLS_RSA_WITH_RC4_128_SHA, 16, 20, 0, rsaKA, suiteDefaultOff, cipherRC4, macSHA1, nil},
 	{TLS_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil},
 	{TLS_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil},
 	{TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, ecdheRSAKA, suiteECDHE, cipher3DES, macSHA1, nil},
@@ -267,6 +275,8 @@ const (
 	TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA      uint16 = 0xc014
 	TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256   uint16 = 0xc02f
 	TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 uint16 = 0xc02b
+	TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384   uint16 = 0xc030
+	TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 uint16 = 0xc02c
 
 	// TLS_FALLBACK_SCSV isn't a standard cipher suite but an indicator
 	// that the client is doing version fallback. See
diff --git a/src/crypto/tls/common.go b/src/crypto/tls/common.go
index 776b70c..a3d75d6 100644
--- a/src/crypto/tls/common.go
+++ b/src/crypto/tls/common.go
@@ -8,7 +8,9 @@ import (
 	"container/list"
 	"crypto"
 	"crypto/rand"
+	"crypto/sha512"
 	"crypto/x509"
+	"errors"
 	"fmt"
 	"io"
 	"math/big"
@@ -30,7 +32,7 @@ const (
 	recordHeaderLen = 5            // record header length
 	maxHandshake    = 65536        // maximum handshake we support (protocol max is 16 MB)
 
-	minVersion = VersionSSL30
+	minVersion = VersionTLS10
 	maxVersion = VersionTLS12
 )
 
@@ -73,6 +75,7 @@ const (
 	extensionSupportedPoints     uint16 = 11
 	extensionSignatureAlgorithms uint16 = 13
 	extensionALPN                uint16 = 16
+	extensionSCT                 uint16 = 18 // https://tools.ietf.org/html/rfc6962#section-6
 	extensionSessionTicket       uint16 = 35
 	extensionNextProtoNeg        uint16 = 13172 // not IANA assigned
 	extensionRenegotiationInfo   uint16 = 0xff01
@@ -123,6 +126,7 @@ const (
 const (
 	hashSHA1   uint8 = 2
 	hashSHA256 uint8 = 4
+	hashSHA384 uint8 = 5
 )
 
 // Signature algorithms for TLS 1.2 (See RFC 5246, section A.4.1)
@@ -137,34 +141,31 @@ type signatureAndHash struct {
 	hash, signature uint8
 }
 
-// supportedSKXSignatureAlgorithms contains the signature and hash algorithms
-// that the code advertises as supported in a TLS 1.2 ClientHello.
-var supportedSKXSignatureAlgorithms = []signatureAndHash{
+// supportedSignatureAlgorithms contains the signature and hash algorithms that
+// the code advertises as supported in a TLS 1.2 ClientHello and in a TLS 1.2
+// CertificateRequest.
+var supportedSignatureAlgorithms = []signatureAndHash{
 	{hashSHA256, signatureRSA},
 	{hashSHA256, signatureECDSA},
+	{hashSHA384, signatureRSA},
+	{hashSHA384, signatureECDSA},
 	{hashSHA1, signatureRSA},
 	{hashSHA1, signatureECDSA},
 }
 
-// supportedClientCertSignatureAlgorithms contains the signature and hash
-// algorithms that the code advertises as supported in a TLS 1.2
-// CertificateRequest.
-var supportedClientCertSignatureAlgorithms = []signatureAndHash{
-	{hashSHA256, signatureRSA},
-	{hashSHA256, signatureECDSA},
-}
-
 // ConnectionState records basic TLS details about the connection.
 type ConnectionState struct {
-	Version                    uint16                // TLS version used by the connection (e.g. VersionTLS12)
-	HandshakeComplete          bool                  // TLS handshake is complete
-	DidResume                  bool                  // connection resumes a previous TLS connection
-	CipherSuite                uint16                // cipher suite in use (TLS_RSA_WITH_RC4_128_SHA, ...)
-	NegotiatedProtocol         string                // negotiated next protocol (from Config.NextProtos)
-	NegotiatedProtocolIsMutual bool                  // negotiated protocol was advertised by server
-	ServerName                 string                // server name requested by client, if any (server side only)
-	PeerCertificates           []*x509.Certificate   // certificate chain presented by remote peer
-	VerifiedChains             [][]*x509.Certificate // verified chains built from PeerCertificates
+	Version                     uint16                // TLS version used by the connection (e.g. VersionTLS12)
+	HandshakeComplete           bool                  // TLS handshake is complete
+	DidResume                   bool                  // connection resumes a previous TLS connection
+	CipherSuite                 uint16                // cipher suite in use (TLS_RSA_WITH_RC4_128_SHA, ...)
+	NegotiatedProtocol          string                // negotiated next protocol (from Config.NextProtos)
+	NegotiatedProtocolIsMutual  bool                  // negotiated protocol was advertised by server
+	ServerName                  string                // server name requested by client, if any (server side only)
+	PeerCertificates            []*x509.Certificate   // certificate chain presented by remote peer
+	VerifiedChains              [][]*x509.Certificate // verified chains built from PeerCertificates
+	SignedCertificateTimestamps [][]byte              // SCTs from the server, if any
+	OCSPResponse                []byte                // stapled OCSP response from server, if any
 
 	// TLSUnique contains the "tls-unique" channel binding value (see RFC
 	// 5929, section 3). For resumed sessions this value will be nil
@@ -190,11 +191,12 @@ const (
 // ClientSessionState contains the state needed by clients to resume TLS
 // sessions.
 type ClientSessionState struct {
-	sessionTicket      []uint8             // Encrypted ticket used for session resumption with server
-	vers               uint16              // SSL/TLS version negotiated for the session
-	cipherSuite        uint16              // Ciphersuite negotiated for the session
-	masterSecret       []byte              // MasterSecret generated by client on a full handshake
-	serverCertificates []*x509.Certificate // Certificate chain presented by the server
+	sessionTicket      []uint8               // Encrypted ticket used for session resumption with server
+	vers               uint16                // SSL/TLS version negotiated for the session
+	cipherSuite        uint16                // Ciphersuite negotiated for the session
+	masterSecret       []byte                // MasterSecret generated by client on a full handshake
+	serverCertificates []*x509.Certificate   // Certificate chain presented by the server
+	verifiedChains     [][]*x509.Certificate // Certificate chains we built for verification
 }
 
 // ClientSessionCache is a cache of ClientSessionState objects that can be used
@@ -265,10 +267,12 @@ type Config struct {
 	NameToCertificate map[string]*Certificate
 
 	// GetCertificate returns a Certificate based on the given
-	// ClientHelloInfo. If GetCertificate is nil or returns nil, then the
-	// certificate is retrieved from NameToCertificate. If
-	// NameToCertificate is nil, the first element of Certificates will be
-	// used.
+	// ClientHelloInfo. It will only be called if the client supplies SNI
+	// information or if Certificates is empty.
+	//
+	// If GetCertificate is nil or returns nil, then the certificate is
+	// retrieved from NameToCertificate. If NameToCertificate is nil, the
+	// first element of Certificates will be used.
 	GetCertificate func(clientHello *ClientHelloInfo) (*Certificate, error)
 
 	// RootCAs defines the set of root certificate authorities
@@ -330,7 +334,7 @@ type Config struct {
 	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.
@@ -344,6 +348,38 @@ type Config struct {
 	CurvePreferences []CurveID
 
 	serverInitOnce sync.Once // guards calling (*Config).serverInit
+
+	// mutex protects sessionTicketKeys
+	mutex sync.RWMutex
+	// sessionTicketKeys contains zero or more ticket keys. If the length
+	// is zero, SessionTicketsDisabled must be true. The first key is used
+	// for new tickets and any subsequent keys can be used to decrypt old
+	// tickets.
+	sessionTicketKeys []ticketKey
+}
+
+// ticketKeyNameLen is the number of bytes of identifier that is prepended to
+// an encrypted session ticket in order to identify the key used to encrypt it.
+const ticketKeyNameLen = 16
+
+// ticketKey is the internal representation of a session ticket key.
+type ticketKey struct {
+	// keyName is an opaque byte string that serves to identify the session
+	// ticket key. It's exposed as plaintext in every session ticket.
+	keyName [ticketKeyNameLen]byte
+	aesKey  [16]byte
+	hmacKey [16]byte
+}
+
+// ticketKeyFromBytes converts from the external representation of a session
+// ticket key to a ticketKey. Externally, session ticket keys are 32 random
+// bytes and this function expands that into sufficient name and key material.
+func ticketKeyFromBytes(b [32]byte) (key ticketKey) {
+	hashed := sha512.Sum512(b[:])
+	copy(key.keyName[:], hashed[:ticketKeyNameLen])
+	copy(key.aesKey[:], hashed[ticketKeyNameLen:ticketKeyNameLen+16])
+	copy(key.hmacKey[:], hashed[ticketKeyNameLen+16:ticketKeyNameLen+32])
+	return key
 }
 
 func (c *Config) serverInit() {
@@ -351,16 +387,51 @@ func (c *Config) serverInit() {
 		return
 	}
 
-	// If the key has already been set then we have nothing to do.
+	alreadySet := false
 	for _, b := range c.SessionTicketKey {
 		if b != 0 {
+			alreadySet = true
+			break
+		}
+	}
+
+	if !alreadySet {
+		if _, err := io.ReadFull(c.rand(), c.SessionTicketKey[:]); err != nil {
+			c.SessionTicketsDisabled = true
 			return
 		}
 	}
 
-	if _, err := io.ReadFull(c.rand(), c.SessionTicketKey[:]); err != nil {
-		c.SessionTicketsDisabled = true
+	c.sessionTicketKeys = []ticketKey{ticketKeyFromBytes(c.SessionTicketKey)}
+}
+
+func (c *Config) ticketKeys() []ticketKey {
+	c.mutex.RLock()
+	// c.sessionTicketKeys is constant once created. SetSessionTicketKeys
+	// will only update it by replacing it with a new value.
+	ret := c.sessionTicketKeys
+	c.mutex.RUnlock()
+	return ret
+}
+
+// SetSessionTicketKeys updates the session ticket keys for a server. The first
+// key will be used when creating new tickets, while all keys can be used for
+// decrypting tickets. It is safe to call this function while the server is
+// running in order to rotate the session ticket keys. The function will panic
+// if keys is empty.
+func (c *Config) SetSessionTicketKeys(keys [][32]byte) {
+	if len(keys) == 0 {
+		panic("tls: keys must have at least one key")
 	}
+
+	newKeys := make([]ticketKey, len(keys))
+	for i, bytes := range keys {
+		newKeys[i] = ticketKeyFromBytes(bytes)
+	}
+
+	c.mutex.Lock()
+	c.sessionTicketKeys = newKeys
+	c.mutex.Unlock()
 }
 
 func (c *Config) rand() io.Reader {
@@ -428,13 +499,18 @@ func (c *Config) mutualVersion(vers uint16) (uint16, bool) {
 // getCertificate returns the best certificate for the given ClientHelloInfo,
 // defaulting to the first element of c.Certificates.
 func (c *Config) getCertificate(clientHello *ClientHelloInfo) (*Certificate, error) {
-	if c.GetCertificate != nil {
+	if c.GetCertificate != nil &&
+		(len(c.Certificates) == 0 || len(clientHello.ServerName) > 0) {
 		cert, err := c.GetCertificate(clientHello)
 		if cert != nil || err != nil {
 			return cert, err
 		}
 	}
 
+	if len(c.Certificates) == 0 {
+		return nil, errors.New("crypto/tls: no certificates configured")
+	}
+
 	if len(c.Certificates) == 1 || c.NameToCertificate == nil {
 		// There's only one choice, so no point doing any work.
 		return &c.Certificates[0], nil
@@ -488,14 +564,17 @@ func (c *Config) BuildNameToCertificate() {
 type Certificate struct {
 	Certificate [][]byte
 	// PrivateKey contains the private key corresponding to the public key
-	// in Leaf. For a server, this must be a *rsa.PrivateKey or
-	// *ecdsa.PrivateKey. For a client doing client authentication, this
-	// can be any type that implements crypto.Signer (which includes RSA
-	// and ECDSA private keys).
+	// in Leaf. For a server, this must implement crypto.Signer and/or
+	// crypto.Decrypter, with an RSA or ECDSA PublicKey. For a client
+	// (performing client authentication), this must be a crypto.Signer
+	// with an RSA or ECDSA PublicKey.
 	PrivateKey crypto.PrivateKey
 	// OCSPStaple contains an optional OCSP response which will be served
 	// to clients that request it.
 	OCSPStaple []byte
+	// SignedCertificateTimestamps contains an optional list of Signed
+	// Certificate Timestamps which will be served to clients that request it.
+	SignedCertificateTimestamps [][]byte
 	// Leaf is the parsed form of the leaf certificate, which may be
 	// initialized using x509.ParseCertificate to reduce per-handshake
 	// processing for TLS clients doing client authentication. If nil, the
@@ -610,12 +689,24 @@ func defaultCipherSuites() []uint16 {
 }
 
 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)
 	}
 }
 
 func unexpectedMessageError(wanted, got interface{}) error {
 	return fmt.Errorf("tls: received unexpected handshake message of type %T when waiting for %T", got, wanted)
 }
+
+func isSupportedSignatureAndHash(sigHash signatureAndHash, sigHashes []signatureAndHash) bool {
+	for _, s := range sigHashes {
+		if s == sigHash {
+			return true
+		}
+	}
+	return false
+}
diff --git a/src/crypto/tls/conn.go b/src/crypto/tls/conn.go
index ba8e4c2..e3dcf15 100644
--- a/src/crypto/tls/conn.go
+++ b/src/crypto/tls/conn.go
@@ -35,7 +35,8 @@ type Conn struct {
 	handshakeComplete bool
 	didResume         bool // whether this connection was a session resumption
 	cipherSuite       uint16
-	ocspResponse      []byte // stapled OCSP response
+	ocspResponse      []byte   // stapled OCSP response
+	scts              [][]byte // signed certificate timestamps from server
 	peerCertificates  []*x509.Certificate
 	// verifiedChains contains the certificate chains that we built, as
 	// opposed to the ones presented by the server.
@@ -570,15 +571,11 @@ Again:
 		return c.in.setErrorLocked(fmt.Errorf("tls: oversized record received with length %d", n))
 	}
 	if !c.haveVers {
-		// First message, be extra suspicious:
-		// this might not be a TLS client.
-		// Bail out before reading a full 'body', if possible.
-		// The current max version is 3.1.
-		// If the version is >= 16.0, it's probably not real.
-		// Similarly, a clientHello message encodes in
-		// well under a kilobyte.  If the length is >= 12 kB,
+		// First message, be extra suspicious: this might not be a TLS
+		// client. Bail out before reading a full 'body', if possible.
+		// The current max version is 3.3 so if the version is >= 16.0,
 		// it's probably not real.
-		if (typ != recordTypeAlert && typ != want) || vers >= 0x1000 || n >= 0x3000 {
+		if (typ != recordTypeAlert && typ != want) || vers >= 0x1000 {
 			c.sendAlert(alertUnexpectedMessage)
 			return c.in.setErrorLocked(fmt.Errorf("tls: first record does not look like a TLS handshake"))
 		}
@@ -926,7 +923,7 @@ func (c *Conn) Read(b []byte) (n int, err error) {
 		// tried to reuse the HTTP connection for a new
 		// request.
 		// See https://codereview.appspot.com/76400046
-		// and http://golang.org/issue/3514
+		// and https://golang.org/issue/3514
 		if ri := c.rawInput; ri != nil &&
 			n != 0 && err == nil &&
 			c.input == nil && len(ri.data) > 0 && recordType(ri.data[0]) == recordTypeAlert {
@@ -997,6 +994,8 @@ func (c *Conn) ConnectionState() ConnectionState {
 		state.PeerCertificates = c.peerCertificates
 		state.VerifiedChains = c.verifiedChains
 		state.ServerName = c.serverName
+		state.SignedCertificateTimestamps = c.scts
+		state.OCSPResponse = c.ocspResponse
 		if !c.didResume {
 			state.TLSUnique = c.firstFinished[:]
 		}
@@ -1026,5 +1025,8 @@ func (c *Conn) VerifyHostname(host string) error {
 	if !c.handshakeComplete {
 		return errors.New("tls: handshake has not yet been performed")
 	}
+	if len(c.verifiedChains) == 0 {
+		return errors.New("tls: handshake did not verify certificate chain")
+	}
 	return c.peerCertificates[0].VerifyHostname(host)
 }
diff --git a/src/crypto/tls/handshake_client.go b/src/crypto/tls/handshake_client.go
index 7f662e9..0b591d7 100644
--- a/src/crypto/tls/handshake_client.go
+++ b/src/crypto/tls/handshake_client.go
@@ -54,6 +54,7 @@ func (c *Conn) clientHandshake() error {
 		compressionMethods:  []uint8{compressionNone},
 		random:              make([]byte, 32),
 		ocspStapling:        true,
+		scts:                true,
 		serverName:          c.config.ServerName,
 		supportedCurves:     c.config.curvePreferences(),
 		supportedPoints:     []uint8{pointFormatUncompressed},
@@ -88,7 +89,7 @@ NextCipherSuite:
 	}
 
 	if hello.vers >= VersionTLS12 {
-		hello.signatureAndHashes = supportedSKXSignatureAlgorithms
+		hello.signatureAndHashes = supportedSignatureAlgorithms
 	}
 
 	var session *ClientSessionState
@@ -168,18 +169,26 @@ NextCipherSuite:
 		serverHello:  serverHello,
 		hello:        hello,
 		suite:        suite,
-		finishedHash: newFinishedHash(c.vers),
+		finishedHash: newFinishedHash(c.vers, suite),
 		session:      session,
 	}
 
-	hs.finishedHash.Write(hs.hello.marshal())
-	hs.finishedHash.Write(hs.serverHello.marshal())
-
 	isResume, err := hs.processServerHello()
 	if err != nil {
 		return err
 	}
 
+	// No signatures of the handshake are needed in a resumption.
+	// Otherwise, in a full handshake, if we don't have any certificates
+	// configured then we will never send a CertificateVerify message and
+	// thus no signatures are needed in that case either.
+	if isResume || len(c.config.Certificates) == 0 {
+		hs.finishedHash.discardHandshakeBuffer()
+	}
+
+	hs.finishedHash.Write(hs.hello.marshal())
+	hs.finishedHash.Write(hs.serverHello.marshal())
+
 	if isResume {
 		if err := hs.establishKeys(); err != nil {
 			return err
@@ -423,7 +432,6 @@ func (hs *clientHandshakeState) doFullHandshake() error {
 	}
 
 	if chainToSend != nil {
-		var signed []byte
 		certVerify := &certificateVerifyMsg{
 			hasSignatureAndHash: c.vers >= VersionTLS12,
 		}
@@ -433,31 +441,42 @@ func (hs *clientHandshakeState) doFullHandshake() error {
 			c.sendAlert(alertInternalError)
 			return fmt.Errorf("tls: client certificate private key of type %T does not implement crypto.Signer", chainToSend.PrivateKey)
 		}
+
+		var signatureType uint8
 		switch key.Public().(type) {
 		case *ecdsa.PublicKey:
-			digest, hashFunc, hashId := hs.finishedHash.hashForClientCertificate(signatureECDSA)
-			signed, err = key.Sign(c.config.rand(), digest, hashFunc)
-			certVerify.signatureAndHash.signature = signatureECDSA
-			certVerify.signatureAndHash.hash = hashId
+			signatureType = signatureECDSA
 		case *rsa.PublicKey:
-			digest, hashFunc, hashId := hs.finishedHash.hashForClientCertificate(signatureRSA)
-			signed, err = key.Sign(c.config.rand(), digest, hashFunc)
-			certVerify.signatureAndHash.signature = signatureRSA
-			certVerify.signatureAndHash.hash = hashId
+			signatureType = signatureRSA
 		default:
-			err = fmt.Errorf("tls: unknown client certificate key type: %T", key)
+			c.sendAlert(alertInternalError)
+			return fmt.Errorf("tls: failed to sign handshake with client certificate: unknown client certificate key type: %T", key)
+		}
+
+		certVerify.signatureAndHash, err = hs.finishedHash.selectClientCertSignatureAlgorithm(certReq.signatureAndHashes, signatureType)
+		if err != nil {
+			c.sendAlert(alertInternalError)
+			return err
 		}
+		digest, hashFunc, err := hs.finishedHash.hashForClientCertificate(certVerify.signatureAndHash, hs.masterSecret)
 		if err != nil {
 			c.sendAlert(alertInternalError)
-			return errors.New("tls: failed to sign handshake with client certificate: " + err.Error())
+			return err
+		}
+		certVerify.signature, err = key.Sign(c.config.rand(), digest, hashFunc)
+		if err != nil {
+			c.sendAlert(alertInternalError)
+			return err
 		}
-		certVerify.signature = signed
 
 		hs.finishedHash.Write(certVerify.marshal())
 		c.writeRecord(recordTypeHandshake, certVerify.marshal())
 	}
 
-	hs.masterSecret = masterFromPreMasterSecret(c.vers, preMasterSecret, hs.hello.random, hs.serverHello.random)
+	hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.hello.random, hs.serverHello.random)
+
+	hs.finishedHash.discardHandshakeBuffer()
+
 	return nil
 }
 
@@ -465,7 +484,7 @@ func (hs *clientHandshakeState) establishKeys() error {
 	c := hs.c
 
 	clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
-		keysFromMasterSecret(c.vers, hs.masterSecret, hs.hello.random, hs.serverHello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen)
+		keysFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.hello.random, hs.serverHello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen)
 	var clientCipher, serverCipher interface{}
 	var clientHash, serverHash macFunction
 	if hs.suite.cipher != nil {
@@ -522,11 +541,13 @@ func (hs *clientHandshakeState) processServerHello() (bool, error) {
 		c.clientProtocol = hs.serverHello.alpnProtocol
 		c.clientProtocolFallback = false
 	}
+	c.scts = hs.serverHello.scts
 
 	if hs.serverResumedSession() {
 		// Restore masterSecret and peerCerts from previous state
 		hs.masterSecret = hs.session.masterSecret
 		c.peerCertificates = hs.session.serverCertificates
+		c.verifiedChains = hs.session.verifiedChains
 		return true, nil
 	}
 	return false, nil
@@ -584,6 +605,7 @@ func (hs *clientHandshakeState) readSessionTicket() error {
 		cipherSuite:        hs.suite.id,
 		masterSecret:       hs.masterSecret,
 		serverCertificates: c.peerCertificates,
+		verifiedChains:     c.verifiedChains,
 	}
 
 	return nil
diff --git a/src/crypto/tls/handshake_client_test.go b/src/crypto/tls/handshake_client_test.go
index e5eaa7d..664fe8d 100644
--- a/src/crypto/tls/handshake_client_test.go
+++ b/src/crypto/tls/handshake_client_test.go
@@ -9,6 +9,8 @@ import (
 	"crypto/ecdsa"
 	"crypto/rsa"
 	"crypto/x509"
+	"encoding/base64"
+	"encoding/binary"
 	"encoding/pem"
 	"fmt"
 	"io"
@@ -49,6 +51,10 @@ type clientTest struct {
 	// key, if not nil, contains either a *rsa.PrivateKey or
 	// *ecdsa.PrivateKey which is the private key for the reference server.
 	key interface{}
+	// extensions, if not nil, contains a list of extension data to be returned
+	// from the ServerHello. The data should be in standard TLS format with
+	// a 2-byte uint16 type, 2-byte data length, followed by the extension data.
+	extensions [][]byte
 	// validate, if not nil, is a function that will be called with the
 	// ConnectionState of the resulting connection. It returns a non-nil
 	// error if the ConnectionState is unacceptable.
@@ -111,6 +117,19 @@ func (test *clientTest) connFromCommand() (conn *recordingConn, child *exec.Cmd,
 	const serverPort = 24323
 	command = append(command, "-accept", strconv.Itoa(serverPort))
 
+	if len(test.extensions) > 0 {
+		var serverInfo bytes.Buffer
+		for _, ext := range test.extensions {
+			pem.Encode(&serverInfo, &pem.Block{
+				Type:  fmt.Sprintf("SERVERINFO FOR EXTENSION %d", binary.BigEndian.Uint16(ext)),
+				Bytes: ext,
+			})
+		}
+		serverInfoPath := tempFile(serverInfo.String())
+		defer os.Remove(serverInfoPath)
+		command = append(command, "-serverinfo", serverInfoPath)
+	}
+
 	cmd := exec.Command(command[0], command[1:]...)
 	stdin = blockingSource(make(chan bool))
 	cmd.Stdin = stdin
@@ -127,7 +146,6 @@ func (test *clientTest) connFromCommand() (conn *recordingConn, child *exec.Cmd,
 	// connection.
 	var tcpConn net.Conn
 	for i := uint(0); i < 5; i++ {
-		var err error
 		tcpConn, err = net.DialTCP("tcp", nil, &net.TCPAddr{
 			IP:   net.IPv4(127, 0, 0, 1),
 			Port: serverPort,
@@ -137,7 +155,7 @@ func (test *clientTest) connFromCommand() (conn *recordingConn, child *exec.Cmd,
 		}
 		time.Sleep((1 << i) * 5 * time.Millisecond)
 	}
-	if tcpConn == nil {
+	if err != nil {
 		close(stdin)
 		out.WriteTo(os.Stdout)
 		cmd.Process.Kill()
@@ -190,11 +208,11 @@ func (test *clientTest) run(t *testing.T, write bool) {
 	doneChan := make(chan bool)
 	go func() {
 		if _, err := client.Write([]byte("hello\n")); err != nil {
-			t.Logf("Client.Write failed: %s", err)
+			t.Errorf("Client.Write failed: %s", err)
 		}
 		if test.validate != nil {
 			if err := test.validate(client.ConnectionState()); err != nil {
-				t.Logf("validate callback returned error: %s", err)
+				t.Errorf("validate callback returned error: %s", err)
 			}
 		}
 		client.Close()
@@ -311,6 +329,16 @@ func TestHandshakeClientECDHEECDSAAESGCM(t *testing.T) {
 	runClientTestTLS12(t, test)
 }
 
+func TestHandshakeClientAES256GCMSHA384(t *testing.T) {
+	test := &clientTest{
+		name:    "ECDHE-ECDSA-AES256-GCM-SHA384",
+		command: []string{"openssl", "s_server", "-cipher", "ECDHE-ECDSA-AES256-GCM-SHA384"},
+		cert:    testECDSACertificate,
+		key:     testECDSAPrivateKey,
+	}
+	runClientTestTLS12(t, test)
+}
+
 func TestHandshakeClientCertRSA(t *testing.T) {
 	config := *testConfig
 	cert, _ := X509KeyPair([]byte(clientCertificatePEM), []byte(clientKeyPEM))
@@ -335,6 +363,16 @@ func TestHandshakeClientCertRSA(t *testing.T) {
 
 	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) {
@@ -368,31 +406,67 @@ func TestClientResumption(t *testing.T) {
 		CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA},
 		Certificates: testConfig.Certificates,
 	}
+
+	issuer, err := x509.ParseCertificate(testRSACertificateIssuer)
+	if err != nil {
+		panic(err)
+	}
+
+	rootCAs := x509.NewCertPool()
+	rootCAs.AddCert(issuer)
+
 	clientConfig := &Config{
 		CipherSuites:       []uint16{TLS_RSA_WITH_RC4_128_SHA},
-		InsecureSkipVerify: true,
 		ClientSessionCache: NewLRUClientSessionCache(32),
+		RootCAs:            rootCAs,
+		ServerName:         "example.golang",
 	}
 
 	testResumeState := func(test string, didResume bool) {
-		hs, err := testHandshake(clientConfig, serverConfig)
+		_, hs, err := testHandshake(clientConfig, serverConfig)
 		if err != nil {
 			t.Fatalf("%s: handshake failed: %s", test, err)
 		}
 		if hs.DidResume != didResume {
 			t.Fatalf("%s resumed: %v, expected: %v", test, hs.DidResume, didResume)
 		}
+		if didResume && (hs.PeerCertificates == nil || hs.VerifiedChains == nil) {
+			t.Fatalf("expected non-nil certificates after resumption. Got peerCertificates: %#v, verifedCertificates: %#v", hs.PeerCertificates, hs.VerifiedChains)
+		}
+	}
+
+	getTicket := func() []byte {
+		return clientConfig.ClientSessionCache.(*lruSessionCache).q.Front().Value.(*lruSessionCacheEntry).state.sessionTicket
+	}
+	randomKey := func() [32]byte {
+		var k [32]byte
+		if _, err := io.ReadFull(serverConfig.rand(), k[:]); err != nil {
+			t.Fatalf("Failed to read new SessionTicketKey: %s", err)
+		}
+		return k
 	}
 
 	testResumeState("Handshake", false)
+	ticket := getTicket()
 	testResumeState("Resume", true)
-
-	if _, err := io.ReadFull(serverConfig.rand(), serverConfig.SessionTicketKey[:]); err != nil {
-		t.Fatalf("Failed to invalidate SessionTicketKey")
+	if !bytes.Equal(ticket, getTicket()) {
+		t.Fatal("first ticket doesn't match ticket after resumption")
 	}
+
+	key2 := randomKey()
+	serverConfig.SetSessionTicketKeys([][32]byte{key2})
+
 	testResumeState("InvalidSessionTicketKey", false)
 	testResumeState("ResumeAfterInvalidSessionTicketKey", true)
 
+	serverConfig.SetSessionTicketKeys([][32]byte{randomKey(), key2})
+	ticket = getTicket()
+	testResumeState("KeyChange", true)
+	if bytes.Equal(ticket, getTicket()) {
+		t.Fatal("new ticket wasn't included while resuming")
+	}
+	testResumeState("KeyChangeFinish", true)
+
 	clientConfig.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_RC4_128_SHA}
 	testResumeState("DifferentCipherSuite", false)
 	testResumeState("DifferentCipherSuiteRecovers", true)
@@ -488,3 +562,41 @@ func TestHandshakeClientALPNNoMatch(t *testing.T) {
 	}
 	runClientTestTLS12(t, test)
 }
+
+// sctsBase64 contains data from `openssl s_client -serverinfo 18 -connect ritter.vg:443`
+const sctsBase64 = "ABIBaQFnAHUApLkJkLQYWBSHuxOizGdwCjw1mAT5G9+443fNDsgN3BAAAAFHl5nuFgAABAMARjBEAiAcS4JdlW5nW9sElUv2zvQyPoZ6ejKrGGB03gjaBZFMLwIgc1Qbbn+hsH0RvObzhS+XZhr3iuQQJY8S9G85D9KeGPAAdgBo9pj4H2SCvjqM7rkoHUz8cVFdZ5PURNEKZ6y7T0/7xAAAAUeX4bVwAAAEAwBHMEUCIDIhFDgG2HIuADBkGuLobU5a4dlCHoJLliWJ1SYT05z6AiEAjxIoZFFPRNWMGGIjskOTMwXzQ1Wh2e7NxXE1kd1J0QsAdgDuS723dc5guuFCaR+r4Z5mow9+X7By2IMAxHuJeqj9ywAAAUhcZIqHAAAEAwBHMEUCICmJ1rBT09LpkbzxtUC+Hi7nXLR0J+2PmwLp+sJMuqK+AiEAr0NkUnEVKVhAkccIFpYDqHOlZaBs [...]
+
+func TestHandshakClientSCTs(t *testing.T) {
+	config := *testConfig
+
+	scts, err := base64.StdEncoding.DecodeString(sctsBase64)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	test := &clientTest{
+		name: "SCT",
+		// Note that this needs OpenSSL 1.0.2 because that is the first
+		// version that supports the -serverinfo flag.
+		command:    []string{"openssl", "s_server"},
+		config:     &config,
+		extensions: [][]byte{scts},
+		validate: func(state ConnectionState) error {
+			expectedSCTs := [][]byte{
+				scts[8:125],
+				scts[127:245],
+				scts[247:],
+			}
+			if n := len(state.SignedCertificateTimestamps); n != len(expectedSCTs) {
+				return fmt.Errorf("Got %d scts, wanted %d", n, len(expectedSCTs))
+			}
+			for i, expected := range expectedSCTs {
+				if sct := state.SignedCertificateTimestamps[i]; !bytes.Equal(sct, expected) {
+					return fmt.Errorf("SCT #%d contained %x, expected %x", i, sct, expected)
+				}
+			}
+			return nil
+		},
+	}
+	runClientTestTLS12(t, test)
+}
diff --git a/src/crypto/tls/handshake_messages.go b/src/crypto/tls/handshake_messages.go
index 5d14871..799a776 100644
--- a/src/crypto/tls/handshake_messages.go
+++ b/src/crypto/tls/handshake_messages.go
@@ -16,6 +16,7 @@ type clientHelloMsg struct {
 	nextProtoNeg        bool
 	serverName          string
 	ocspStapling        bool
+	scts                bool
 	supportedCurves     []CurveID
 	supportedPoints     []uint8
 	ticketSupported     bool
@@ -40,6 +41,7 @@ func (m *clientHelloMsg) equal(i interface{}) bool {
 		m.nextProtoNeg == m1.nextProtoNeg &&
 		m.serverName == m1.serverName &&
 		m.ocspStapling == m1.ocspStapling &&
+		m.scts == m1.scts &&
 		eqCurveIDs(m.supportedCurves, m1.supportedCurves) &&
 		bytes.Equal(m.supportedPoints, m1.supportedPoints) &&
 		m.ticketSupported == m1.ticketSupported &&
@@ -99,6 +101,9 @@ func (m *clientHelloMsg) marshal() []byte {
 		}
 		numExtensions++
 	}
+	if m.scts {
+		numExtensions++
+	}
 	if numExtensions > 0 {
 		extensionsLength += 4 * numExtensions
 		length += 2 + extensionsLength
@@ -271,6 +276,13 @@ func (m *clientHelloMsg) marshal() []byte {
 		lengths[0] = byte(stringsLength >> 8)
 		lengths[1] = byte(stringsLength)
 	}
+	if m.scts {
+		// https://tools.ietf.org/html/rfc6962#section-3.3.1
+		z[0] = byte(extensionSCT >> 8)
+		z[1] = byte(extensionSCT)
+		// zero uint16 for the zero-length extension_data
+		z = z[4:]
+	}
 
 	m.raw = x
 
@@ -326,6 +338,7 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
 	m.sessionTicket = nil
 	m.signatureAndHashes = nil
 	m.alpnProtocols = nil
+	m.scts = false
 
 	if len(data) == 0 {
 		// ClientHello is optionally followed by extension data
@@ -354,12 +367,16 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
 
 		switch extension {
 		case extensionServerName:
-			if length < 2 {
+			d := data[:length]
+			if len(d) < 2 {
 				return false
 			}
-			numNames := int(data[0])<<8 | int(data[1])
-			d := data[2:]
-			for i := 0; i < numNames; i++ {
+			namesLen := int(d[0])<<8 | int(d[1])
+			d = d[2:]
+			if len(d) != namesLen {
+				return false
+			}
+			for len(d) > 0 {
 				if len(d) < 3 {
 					return false
 				}
@@ -370,7 +387,7 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
 					return false
 				}
 				if nameType == 0 {
-					m.serverName = string(d[0:nameLen])
+					m.serverName = string(d[:nameLen])
 					break
 				}
 				d = d[nameLen:]
@@ -430,7 +447,7 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
 				m.signatureAndHashes[i].signature = d[1]
 				d = d[2:]
 			}
-		case extensionRenegotiationInfo + 1:
+		case extensionRenegotiationInfo:
 			if length != 1 || data[0] != 0 {
 				return false
 			}
@@ -453,6 +470,11 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
 				m.alpnProtocols = append(m.alpnProtocols, string(d[:stringLen]))
 				d = d[stringLen:]
 			}
+		case extensionSCT:
+			m.scts = true
+			if length != 0 {
+				return false
+			}
 		}
 		data = data[length:]
 	}
@@ -470,6 +492,7 @@ type serverHelloMsg struct {
 	nextProtoNeg        bool
 	nextProtos          []string
 	ocspStapling        bool
+	scts                [][]byte
 	ticketSupported     bool
 	secureRenegotiation bool
 	alpnProtocol        string
@@ -481,6 +504,15 @@ func (m *serverHelloMsg) equal(i interface{}) bool {
 		return false
 	}
 
+	if len(m.scts) != len(m1.scts) {
+		return false
+	}
+	for i, sct := range m.scts {
+		if !bytes.Equal(sct, m1.scts[i]) {
+			return false
+		}
+	}
+
 	return bytes.Equal(m.raw, m1.raw) &&
 		m.vers == m1.vers &&
 		bytes.Equal(m.random, m1.random) &&
@@ -530,6 +562,14 @@ func (m *serverHelloMsg) marshal() []byte {
 		extensionsLength += 2 + 1 + alpnLen
 		numExtensions++
 	}
+	sctLen := 0
+	if len(m.scts) > 0 {
+		for _, sct := range m.scts {
+			sctLen += len(sct) + 2
+		}
+		extensionsLength += 2 + sctLen
+		numExtensions++
+	}
 
 	if numExtensions > 0 {
 		extensionsLength += 4 * numExtensions
@@ -605,6 +645,23 @@ func (m *serverHelloMsg) marshal() []byte {
 		copy(z[7:], []byte(m.alpnProtocol))
 		z = z[7+alpnLen:]
 	}
+	if sctLen > 0 {
+		z[0] = byte(extensionSCT >> 8)
+		z[1] = byte(extensionSCT)
+		l := sctLen + 2
+		z[2] = byte(l >> 8)
+		z[3] = byte(l)
+		z[4] = byte(sctLen >> 8)
+		z[5] = byte(sctLen)
+
+		z = z[6:]
+		for _, sct := range m.scts {
+			z[0] = byte(len(sct) >> 8)
+			z[1] = byte(len(sct))
+			copy(z[2:], sct)
+			z = z[len(sct)+2:]
+		}
+	}
 
 	m.raw = x
 
@@ -634,6 +691,7 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool {
 	m.nextProtoNeg = false
 	m.nextProtos = nil
 	m.ocspStapling = false
+	m.scts = nil
 	m.ticketSupported = false
 	m.alpnProtocol = ""
 
@@ -706,6 +764,34 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool {
 			}
 			d = d[1:]
 			m.alpnProtocol = string(d)
+		case extensionSCT:
+			d := data[:length]
+
+			if len(d) < 2 {
+				return false
+			}
+			l := int(d[0])<<8 | int(d[1])
+			d = d[2:]
+			if len(d) != l {
+				return false
+			}
+			if l == 0 {
+				continue
+			}
+
+			m.scts = make([][]byte, 0, 3)
+			for len(d) != 0 {
+				if len(d) < 2 {
+					return false
+				}
+				sctLen := int(d[0])<<8 | int(d[1])
+				d = d[2:]
+				if len(d) < sctLen {
+					return false
+				}
+				m.scts = append(m.scts, d[:sctLen])
+				d = d[sctLen:]
+			}
 		}
 		data = data[length:]
 	}
diff --git a/src/crypto/tls/handshake_messages_test.go b/src/crypto/tls/handshake_messages_test.go
index a96e95c..95d825b 100644
--- a/src/crypto/tls/handshake_messages_test.go
+++ b/src/crypto/tls/handshake_messages_test.go
@@ -136,12 +136,15 @@ func (*clientHelloMsg) Generate(rand *rand.Rand, size int) reflect.Value {
 		}
 	}
 	if rand.Intn(10) > 5 {
-		m.signatureAndHashes = supportedSKXSignatureAlgorithms
+		m.signatureAndHashes = supportedSignatureAlgorithms
 	}
 	m.alpnProtocols = make([]string, rand.Intn(5))
 	for i := range m.alpnProtocols {
 		m.alpnProtocols[i] = randomString(rand.Intn(20)+1, rand)
 	}
+	if rand.Intn(10) > 5 {
+		m.scts = true
+	}
 
 	return reflect.ValueOf(m)
 }
@@ -172,6 +175,14 @@ func (*serverHelloMsg) Generate(rand *rand.Rand, size int) reflect.Value {
 	}
 	m.alpnProtocol = randomString(rand.Intn(32)+1, rand)
 
+	if rand.Intn(10) > 5 {
+		numSCTs := rand.Intn(4)
+		m.scts = make([][]byte, numSCTs)
+		for i := range m.scts {
+			m.scts[i] = randomBytes(rand.Intn(500), rand)
+		}
+	}
+
 	return reflect.ValueOf(m)
 }
 
diff --git a/src/crypto/tls/handshake_server.go b/src/crypto/tls/handshake_server.go
index 0d90765..e16cddc 100644
--- a/src/crypto/tls/handshake_server.go
+++ b/src/crypto/tls/handshake_server.go
@@ -25,6 +25,8 @@ type serverHandshakeState struct {
 	suite           *cipherSuite
 	ellipticOk      bool
 	ecdsaOk         bool
+	rsaDecryptOk    bool
+	rsaSignOk       bool
 	sessionState    *sessionState
 	finishedHash    finishedHash
 	masterSecret    []byte
@@ -57,6 +59,14 @@ func (c *Conn) serverHandshake() error {
 		if err := hs.establishKeys(); err != nil {
 			return err
 		}
+		// ticketSupported is set in a resumption handshake if the
+		// ticket from the client was encrypted with an old session
+		// ticket key and thus a refreshed ticket should be sent.
+		if hs.hello.ticketSupported {
+			if err := hs.sendSessionTicket(); err != nil {
+				return err
+			}
+		}
 		if err := hs.sendFinished(c.firstFinished[:]); err != nil {
 			return err
 		}
@@ -111,9 +121,6 @@ func (hs *serverHandshakeState) readClientHello() (isResume bool, err error) {
 	}
 	c.haveVers = true
 
-	hs.finishedHash = newFinishedHash(c.vers)
-	hs.finishedHash.Write(hs.clientHello.marshal())
-
 	hs.hello = new(serverHelloMsg)
 
 	supportedCurve := false
@@ -173,33 +180,47 @@ Curves:
 		// Although sending an empty NPN extension is reasonable, Firefox has
 		// had a bug around this. Best to send nothing at all if
 		// config.NextProtos is empty. See
-		// https://code.google.com/p/go/issues/detail?id=5445.
+		// https://golang.org/issue/5445.
 		if hs.clientHello.nextProtoNeg && len(config.NextProtos) > 0 {
 			hs.hello.nextProtoNeg = true
 			hs.hello.nextProtos = config.NextProtos
 		}
 	}
 
-	if len(config.Certificates) == 0 {
+	if hs.cert, err = config.getCertificate(&ClientHelloInfo{
+		CipherSuites:    hs.clientHello.cipherSuites,
+		ServerName:      hs.clientHello.serverName,
+		SupportedCurves: hs.clientHello.supportedCurves,
+		SupportedPoints: hs.clientHello.supportedPoints,
+	}); err != nil {
 		c.sendAlert(alertInternalError)
-		return false, errors.New("tls: no certificates configured")
+		return false, err
 	}
-	hs.cert = &config.Certificates[0]
-	if len(hs.clientHello.serverName) > 0 {
-		chi := &ClientHelloInfo{
-			CipherSuites:    hs.clientHello.cipherSuites,
-			ServerName:      hs.clientHello.serverName,
-			SupportedCurves: hs.clientHello.supportedCurves,
-			SupportedPoints: hs.clientHello.supportedPoints,
+	if hs.clientHello.scts {
+		hs.hello.scts = hs.cert.SignedCertificateTimestamps
+	}
+
+	if priv, ok := hs.cert.PrivateKey.(crypto.Signer); ok {
+		switch priv.Public().(type) {
+		case *ecdsa.PublicKey:
+			hs.ecdsaOk = true
+		case *rsa.PublicKey:
+			hs.rsaSignOk = true
+		default:
+			c.sendAlert(alertInternalError)
+			return false, fmt.Errorf("crypto/tls: unsupported signing key type (%T)", priv.Public())
 		}
-		if hs.cert, err = config.getCertificate(chi); err != nil {
+	}
+	if priv, ok := hs.cert.PrivateKey.(crypto.Decrypter); ok {
+		switch priv.Public().(type) {
+		case *rsa.PublicKey:
+			hs.rsaDecryptOk = true
+		default:
 			c.sendAlert(alertInternalError)
-			return false, err
+			return false, fmt.Errorf("crypto/tls: unsupported decryption key type (%T)", priv.Public())
 		}
 	}
 
-	_, hs.ecdsaOk = hs.cert.PrivateKey.(*ecdsa.PrivateKey)
-
 	if hs.checkForResumption() {
 		return true, nil
 	}
@@ -214,7 +235,7 @@ Curves:
 	}
 
 	for _, id := range preferenceList {
-		if hs.suite = c.tryCipherSuite(id, supportedList, c.vers, hs.ellipticOk, hs.ecdsaOk); hs.suite != nil {
+		if hs.setCipherSuite(id, supportedList, c.vers) {
 			break
 		}
 	}
@@ -228,9 +249,9 @@ Curves:
 	for _, id := range hs.clientHello.cipherSuites {
 		if id == TLS_FALLBACK_SCSV {
 			// The client is doing a fallback connection.
-			if hs.clientHello.vers < c.config.MaxVersion {
+			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
 		}
@@ -239,7 +260,7 @@ Curves:
 	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
 
@@ -248,7 +269,8 @@ func (hs *serverHandshakeState) checkForResumption() bool {
 	}
 
 	var ok bool
-	if hs.sessionState, ok = c.decryptTicket(hs.clientHello.sessionTicket); !ok {
+	var sessionTicket = append([]uint8{}, hs.clientHello.sessionTicket...)
+	if hs.sessionState, ok = c.decryptTicket(sessionTicket); !ok {
 		return false
 	}
 
@@ -272,8 +294,7 @@ func (hs *serverHandshakeState) checkForResumption() bool {
 	}
 
 	// Check that we also support the ciphersuite from the session.
-	hs.suite = c.tryCipherSuite(hs.sessionState.cipherSuite, c.config.cipherSuites(), hs.sessionState.vers, hs.ellipticOk, hs.ecdsaOk)
-	if hs.suite == nil {
+	if !hs.setCipherSuite(hs.sessionState.cipherSuite, c.config.cipherSuites(), hs.sessionState.vers) {
 		return false
 	}
 
@@ -296,6 +317,10 @@ func (hs *serverHandshakeState) doResumeHandshake() error {
 	// We echo the client's session ID in the ServerHello to let it know
 	// that we're doing a resumption.
 	hs.hello.sessionId = hs.clientHello.sessionId
+	hs.hello.ticketSupported = hs.sessionState.usedOldKey
+	hs.finishedHash = newFinishedHash(c.vers, hs.suite)
+	hs.finishedHash.discardHandshakeBuffer()
+	hs.finishedHash.Write(hs.clientHello.marshal())
 	hs.finishedHash.Write(hs.hello.marshal())
 	c.writeRecord(recordTypeHandshake, hs.hello.marshal())
 
@@ -320,6 +345,14 @@ func (hs *serverHandshakeState) doFullHandshake() error {
 
 	hs.hello.ticketSupported = hs.clientHello.ticketSupported && !config.SessionTicketsDisabled
 	hs.hello.cipherSuite = hs.suite.id
+
+	hs.finishedHash = newFinishedHash(hs.c.vers, hs.suite)
+	if config.ClientAuth == NoClientCert {
+		// No need to keep a full record of the handshake if client
+		// certificates won't be used.
+		hs.finishedHash.discardHandshakeBuffer()
+	}
+	hs.finishedHash.Write(hs.clientHello.marshal())
 	hs.finishedHash.Write(hs.hello.marshal())
 	c.writeRecord(recordTypeHandshake, hs.hello.marshal())
 
@@ -356,7 +389,7 @@ func (hs *serverHandshakeState) doFullHandshake() error {
 		}
 		if c.vers >= VersionTLS12 {
 			certReq.hasSignatureAndHash = true
-			certReq.signatureAndHashes = supportedClientCertSignatureAlgorithms
+			certReq.signatureAndHashes = supportedSignatureAlgorithms
 		}
 
 		// An empty list of certificateAuthorities signals to
@@ -420,6 +453,13 @@ func (hs *serverHandshakeState) doFullHandshake() error {
 	}
 	hs.finishedHash.Write(ckx.marshal())
 
+	preMasterSecret, err := keyAgreement.processClientKeyExchange(config, hs.cert, ckx, c.vers)
+	if err != nil {
+		c.sendAlert(alertHandshakeFailure)
+		return err
+	}
+	hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.clientHello.random, hs.hello.random)
+
 	// If we received a client cert in response to our certificate request message,
 	// the client will send us a certificateVerifyMsg immediately after the
 	// clientKeyExchangeMsg.  This message is a digest of all preceding
@@ -437,8 +477,31 @@ func (hs *serverHandshakeState) doFullHandshake() error {
 			return unexpectedMessageError(certVerify, msg)
 		}
 
+		// Determine the signature type.
+		var signatureAndHash signatureAndHash
+		if certVerify.hasSignatureAndHash {
+			signatureAndHash = certVerify.signatureAndHash
+			if !isSupportedSignatureAndHash(signatureAndHash, supportedSignatureAlgorithms) {
+				return errors.New("tls: unsupported hash function for client certificate")
+			}
+		} else {
+			// Before TLS 1.2 the signature algorithm was implicit
+			// from the key type, and only one hash per signature
+			// algorithm was possible. Leave the hash as zero.
+			switch pub.(type) {
+			case *ecdsa.PublicKey:
+				signatureAndHash.signature = signatureECDSA
+			case *rsa.PublicKey:
+				signatureAndHash.signature = signatureRSA
+			}
+		}
+
 		switch key := pub.(type) {
 		case *ecdsa.PublicKey:
+			if signatureAndHash.signature != signatureECDSA {
+				err = errors.New("bad signature type for client's ECDSA certificate")
+				break
+			}
 			ecdsaSig := new(ecdsaSignature)
 			if _, err = asn1.Unmarshal(certVerify.signature, ecdsaSig); err != nil {
 				break
@@ -447,29 +510,34 @@ func (hs *serverHandshakeState) doFullHandshake() error {
 				err = errors.New("ECDSA signature contained zero or negative values")
 				break
 			}
-			digest, _, _ := hs.finishedHash.hashForClientCertificate(signatureECDSA)
+			var digest []byte
+			if digest, _, err = hs.finishedHash.hashForClientCertificate(signatureAndHash, hs.masterSecret); err != nil {
+				break
+			}
 			if !ecdsa.Verify(key, digest, ecdsaSig.R, ecdsaSig.S) {
 				err = errors.New("ECDSA verification failure")
-				break
 			}
 		case *rsa.PublicKey:
-			digest, hashFunc, _ := hs.finishedHash.hashForClientCertificate(signatureRSA)
+			if signatureAndHash.signature != signatureRSA {
+				err = errors.New("bad signature type for client's RSA certificate")
+				break
+			}
+			var digest []byte
+			var hashFunc crypto.Hash
+			if digest, hashFunc, err = hs.finishedHash.hashForClientCertificate(signatureAndHash, hs.masterSecret); err != nil {
+				break
+			}
 			err = rsa.VerifyPKCS1v15(key, hashFunc, digest, certVerify.signature)
 		}
 		if err != nil {
 			c.sendAlert(alertBadCertificate)
-			return errors.New("could not validate signature of connection nonces: " + err.Error())
+			return errors.New("tls: could not validate signature of connection nonces: " + err.Error())
 		}
 
 		hs.finishedHash.Write(certVerify.marshal())
 	}
 
-	preMasterSecret, err := keyAgreement.processClientKeyExchange(config, hs.cert, ckx, c.vers)
-	if err != nil {
-		c.sendAlert(alertHandshakeFailure)
-		return err
-	}
-	hs.masterSecret = masterFromPreMasterSecret(c.vers, preMasterSecret, hs.clientHello.random, hs.hello.random)
+	hs.finishedHash.discardHandshakeBuffer()
 
 	return nil
 }
@@ -478,7 +546,7 @@ func (hs *serverHandshakeState) establishKeys() error {
 	c := hs.c
 
 	clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
-		keysFromMasterSecret(c.vers, hs.masterSecret, hs.clientHello.random, hs.hello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen)
+		keysFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.clientHello.random, hs.hello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen)
 
 	var clientCipher, serverCipher interface{}
 	var clientHash, serverHash macFunction
@@ -619,18 +687,6 @@ func (hs *serverHandshakeState) processCertsFromClient(certificates [][]byte) (c
 			return nil, errors.New("tls: failed to verify client's certificate: " + err.Error())
 		}
 
-		ok := false
-		for _, ku := range certs[0].ExtKeyUsage {
-			if ku == x509.ExtKeyUsageClientAuth {
-				ok = true
-				break
-			}
-		}
-		if !ok {
-			c.sendAlert(alertHandshakeFailure)
-			return nil, errors.New("tls: client's certificate's extended key usage doesn't permit it to be used for client authentication")
-		}
-
 		c.verifiedChains = chains
 	}
 
@@ -650,9 +706,10 @@ func (hs *serverHandshakeState) processCertsFromClient(certificates [][]byte) (c
 	return nil, nil
 }
 
-// tryCipherSuite returns a cipherSuite with the given id if that cipher suite
-// is acceptable to use.
-func (c *Conn) tryCipherSuite(id uint16, supportedCipherSuites []uint16, version uint16, ellipticOk, ecdsaOk bool) *cipherSuite {
+// setCipherSuite sets a cipherSuite with the given id as the serverHandshakeState
+// suite if that cipher suite is acceptable to use.
+// It returns a bool indicating if the suite was set.
+func (hs *serverHandshakeState) setCipherSuite(id uint16, supportedCipherSuites []uint16, version uint16) bool {
 	for _, supported := range supportedCipherSuites {
 		if id == supported {
 			var candidate *cipherSuite
@@ -668,18 +725,26 @@ func (c *Conn) tryCipherSuite(id uint16, supportedCipherSuites []uint16, version
 			}
 			// Don't select a ciphersuite which we can't
 			// support for this client.
-			if (candidate.flags&suiteECDHE != 0) && !ellipticOk {
-				continue
-			}
-			if (candidate.flags&suiteECDSA != 0) != ecdsaOk {
+			if candidate.flags&suiteECDHE != 0 {
+				if !hs.ellipticOk {
+					continue
+				}
+				if candidate.flags&suiteECDSA != 0 {
+					if !hs.ecdsaOk {
+						continue
+					}
+				} else if !hs.rsaSignOk {
+					continue
+				}
+			} else if !hs.rsaDecryptOk {
 				continue
 			}
 			if version < VersionTLS12 && candidate.flags&suiteTLS12 != 0 {
 				continue
 			}
-			return candidate
+			hs.suite = candidate
+			return true
 		}
 	}
-
-	return nil
+	return false
 }
diff --git a/src/crypto/tls/handshake_server_test.go b/src/crypto/tls/handshake_server_test.go
index 0338af4..20c2bd6 100644
--- a/src/crypto/tls/handshake_server_test.go
+++ b/src/crypto/tls/handshake_server_test.go
@@ -37,6 +37,15 @@ func (zeroSource) Read(b []byte) (n int, err error) {
 
 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 @@ func init() {
 		InsecureSkipVerify: true,
 		MinVersion:         VersionSSL30,
 		MaxVersion:         VersionTLS12,
+		CipherSuites:       allCipherSuites(),
 	}
 	testConfig.Certificates[0].Certificate = [][]byte{testRSACertificate}
 	testConfig.Certificates[0].PrivateKey = testRSAPrivateKey
@@ -53,7 +63,11 @@ func init() {
 	testConfig.BuildNameToCertificate()
 }
 
-func testClientHelloFailure(t *testing.T, m handshakeMessage, expectedSubStr string) {
+func testClientHello(t *testing.T, serverConfig *Config, m handshakeMessage) {
+	testClientHelloFailure(t, serverConfig, m, "")
+}
+
+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,22 +80,26 @@ func testClientHelloFailure(t *testing.T, m handshakeMessage, expectedSubStr str
 		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) {
+	if len(expectedSubStr) == 0 {
+		if err != nil && err != io.EOF {
+			t.Errorf("Got error: %s; expected to succeed", err, expectedSubStr)
+		}
+	} else if err == nil || !strings.Contains(err.Error(), expectedSubStr) {
 		t.Errorf("Got error: %s; expected to match substring '%s'", err, expectedSubStr)
 	}
 }
 
 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 +109,7 @@ func TestNoSuiteOverlap(t *testing.T) {
 		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 +118,117 @@ func TestNoCompressionOverlap(t *testing.T) {
 		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 TestDontSelectECDSAWithRSAKey(t *testing.T) {
+	// Test that, even when both sides support an ECDSA cipher suite, it
+	// won't be selected if the server's private key doesn't support it.
+	clientHello := &clientHelloMsg{
+		vers:               0x0301,
+		cipherSuites:       []uint16{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA},
+		compressionMethods: []uint8{0},
+		supportedCurves:    []CurveID{CurveP256},
+		supportedPoints:    []uint8{pointFormatUncompressed},
+	}
+	serverConfig := *testConfig
+	serverConfig.CipherSuites = clientHello.cipherSuites
+	serverConfig.Certificates = make([]Certificate, 1)
+	serverConfig.Certificates[0].Certificate = [][]byte{testECDSACertificate}
+	serverConfig.Certificates[0].PrivateKey = testECDSAPrivateKey
+	serverConfig.BuildNameToCertificate()
+	// First test that it *does* work when the server's key is ECDSA.
+	testClientHello(t, &serverConfig, clientHello)
+
+	// Now test that switching to an RSA key causes the expected error (and
+	// not an internal error about a signing failure).
+	serverConfig.Certificates = testConfig.Certificates
+	testClientHelloFailure(t, &serverConfig, clientHello, "no cipher suite supported by both client and server")
+}
+
+func TestDontSelectRSAWithECDSAKey(t *testing.T) {
+	// Test that, even when both sides support an RSA cipher suite, it
+	// won't be selected if the server's private key doesn't support it.
+	clientHello := &clientHelloMsg{
+		vers:               0x0301,
+		cipherSuites:       []uint16{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA},
+		compressionMethods: []uint8{0},
+		supportedCurves:    []CurveID{CurveP256},
+		supportedPoints:    []uint8{pointFormatUncompressed},
+	}
+	serverConfig := *testConfig
+	serverConfig.CipherSuites = clientHello.cipherSuites
+	// First test that it *does* work when the server's key is RSA.
+	testClientHello(t, &serverConfig, clientHello)
+
+	// Now test that switching to an ECDSA key causes the expected error
+	// (and not an internal error about a signing failure).
+	serverConfig.Certificates = make([]Certificate, 1)
+	serverConfig.Certificates[0].Certificate = [][]byte{testECDSACertificate}
+	serverConfig.Certificates[0].PrivateKey = testECDSAPrivateKey
+	serverConfig.BuildNameToCertificate()
+	testClientHelloFailure(t, &serverConfig, clientHello, "no cipher suite supported by both client and server")
+}
+
+func TestRenegotiationExtension(t *testing.T) {
+	clientHello := &clientHelloMsg{
+		vers:                VersionTLS12,
+		compressionMethods:  []uint8{compressionNone},
+		random:              make([]byte, 32),
+		secureRenegotiation: true,
+		cipherSuites:        []uint16{TLS_RSA_WITH_RC4_128_SHA},
+	}
+
+	var buf []byte
+	c, s := net.Pipe()
+
+	go func() {
+		cli := Client(c, testConfig)
+		cli.vers = clientHello.vers
+		cli.writeRecord(recordTypeHandshake, clientHello.marshal())
+
+		buf = make([]byte, 1024)
+		n, err := c.Read(buf)
+		if err != nil {
+			t.Fatalf("Server read returned error: %s", err)
+		}
+		buf = buf[:n]
+		c.Close()
+	}()
+
+	Server(s, testConfig).Handshake()
+
+	if len(buf) < 5+4 {
+		t.Fatalf("Server returned short message of length %d", len(buf))
+	}
+	// buf contains a TLS record, with a 5 byte record header and a 4 byte
+	// handshake header. The length of the ServerHello is taken from the
+	// handshake header.
+	serverHelloLen := int(buf[6])<<16 | int(buf[7])<<8 | int(buf[8])
+
+	var serverHello serverHelloMsg
+	// unmarshal expects to be given the handshake header, but
+	// serverHelloLen doesn't include it.
+	if !serverHello.unmarshal(buf[5 : 9+serverHelloLen]) {
+		t.Fatalf("Failed to parse ServerHello")
+	}
+
+	if !serverHello.secureRenegotiation {
+		t.Errorf("Secure renegotiation extension was not echoed.")
+	}
 }
 
 func TestTLS12OnlyCipherSuites(t *testing.T) {
@@ -175,19 +303,20 @@ func TestClose(t *testing.T) {
 	}
 }
 
-func testHandshake(clientConfig, serverConfig *Config) (state ConnectionState, err error) {
+func testHandshake(clientConfig, serverConfig *Config) (serverState, clientState ConnectionState, err error) {
 	c, s := net.Pipe()
 	done := make(chan bool)
 	go func() {
 		cli := Client(c, clientConfig)
 		cli.Handshake()
+		clientState = cli.ConnectionState()
 		c.Close()
 		done <- true
 	}()
 	server := Server(s, serverConfig)
 	err = server.Handshake()
 	if err == nil {
-		state = server.ConnectionState()
+		serverState = server.ConnectionState()
 	}
 	s.Close()
 	<-done
@@ -202,7 +331,7 @@ func TestVersion(t *testing.T) {
 	clientConfig := &Config{
 		InsecureSkipVerify: true,
 	}
-	state, err := testHandshake(clientConfig, serverConfig)
+	state, _, err := testHandshake(clientConfig, serverConfig)
 	if err != nil {
 		t.Fatalf("handshake failed: %s", err)
 	}
@@ -221,7 +350,7 @@ func TestCipherSuitePreference(t *testing.T) {
 		CipherSuites:       []uint16{TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_RC4_128_SHA},
 		InsecureSkipVerify: true,
 	}
-	state, err := testHandshake(clientConfig, serverConfig)
+	state, _, err := testHandshake(clientConfig, serverConfig)
 	if err != nil {
 		t.Fatalf("handshake failed: %s", err)
 	}
@@ -231,7 +360,7 @@ func TestCipherSuitePreference(t *testing.T) {
 	}
 
 	serverConfig.PreferServerCipherSuites = true
-	state, err = testHandshake(clientConfig, serverConfig)
+	state, _, err = testHandshake(clientConfig, serverConfig)
 	if err != nil {
 		t.Fatalf("handshake failed: %s", err)
 	}
@@ -240,6 +369,33 @@ func TestCipherSuitePreference(t *testing.T) {
 	}
 }
 
+func TestSCTHandshake(t *testing.T) {
+	expected := [][]byte{[]byte("certificate"), []byte("transparency")}
+	serverConfig := &Config{
+		Certificates: []Certificate{{
+			Certificate:                 [][]byte{testRSACertificate},
+			PrivateKey:                  testRSAPrivateKey,
+			SignedCertificateTimestamps: expected,
+		}},
+	}
+	clientConfig := &Config{
+		InsecureSkipVerify: true,
+	}
+	_, state, err := testHandshake(clientConfig, serverConfig)
+	if err != nil {
+		t.Fatalf("handshake failed: %s", err)
+	}
+	actual := state.SignedCertificateTimestamps
+	if len(actual) != len(expected) {
+		t.Fatalf("got %d scts, want %d", len(actual), len(expected))
+	}
+	for i, sct := range expected {
+		if !bytes.Equal(sct, actual[i]) {
+			t.Fatalf("SCT #%d was %x, but expected %x", i, actual[i], sct)
+		}
+	}
+}
+
 // Note: see comment in handshake_test.go for details of how the reference
 // tests work.
 
@@ -257,9 +413,6 @@ type serverTest struct {
 	expectedPeerCerts []string
 	// config, if not nil, contains a custom Config to use for this test.
 	config *Config
-	// expectAlert, if true, indicates that a fatal alert should be returned
-	// when handshaking with the server.
-	expectAlert bool
 	// expectHandshakeErrorIncluding, when not empty, contains a string
 	// that must be a substring of the error resulting from the handshake.
 	expectHandshakeErrorIncluding string
@@ -384,9 +537,7 @@ func (test *serverTest) run(t *testing.T, write bool) {
 	if !write {
 		flows, err := test.loadData()
 		if err != nil {
-			if !test.expectAlert {
-				t.Fatalf("%s: failed to load data from %s", test.name, test.dataPath())
-			}
+			t.Fatalf("%s: failed to load data from %s", test.name, test.dataPath())
 		}
 		for i, b := range flows {
 			if i%2 == 0 {
@@ -395,17 +546,11 @@ func (test *serverTest) run(t *testing.T, write bool) {
 			}
 			bb := make([]byte, len(b))
 			n, err := io.ReadFull(clientConn, bb)
-			if test.expectAlert {
-				if err == nil {
-					t.Fatal("Expected read failure but read succeeded")
-				}
-			} else {
-				if err != nil {
-					t.Fatalf("%s #%d: %s\nRead %d, wanted %d, got %x, wanted %x\n", test.name, i+1, err, n, len(bb), bb[:n], b)
-				}
-				if !bytes.Equal(b, bb) {
-					t.Fatalf("%s #%d: mismatch on read: got:%x want:%x", test.name, i+1, bb, b)
-				}
+			if err != nil {
+				t.Fatalf("%s #%d: %s\nRead %d, wanted %d, got %x, wanted %x\n", test.name, i+1, err, n, len(bb), bb[:n], b)
+			}
+			if !bytes.Equal(b, bb) {
+				t.Fatalf("%s #%d: mismatch on read: got:%x want:%x", test.name, i+1, bb, b)
 			}
 		}
 		clientConn.Close()
@@ -516,6 +661,14 @@ func TestHandshakeServerAESGCM(t *testing.T) {
 	runServerTestTLS12(t, test)
 }
 
+func TestHandshakeServerAES256GCMSHA384(t *testing.T) {
+	test := &serverTest{
+		name:    "RSA-AES256-GCM-SHA384",
+		command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "ECDHE-RSA-AES256-GCM-SHA384"},
+	}
+	runServerTestTLS12(t, test)
+}
+
 func TestHandshakeServerECDHEECDSAAES(t *testing.T) {
 	config := *testConfig
 	config.Certificates = make([]Certificate, 1)
@@ -599,7 +752,7 @@ func TestHandshakeServerSNIGetCertificate(t *testing.T) {
 		return cert, nil
 	}
 	test := &serverTest{
-		name:    "SNI",
+		name:    "SNI-GetCertificate",
 		command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA", "-servername", "snitest.com"},
 		config:  &config,
 	}
@@ -617,7 +770,7 @@ func TestHandshakeServerSNIGetCertificateNotFound(t *testing.T) {
 		return nil, nil
 	}
 	test := &serverTest{
-		name:    "SNI",
+		name:    "SNI-GetCertificateNotFound",
 		command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA", "-servername", "snitest.com"},
 		config:  &config,
 	}
@@ -627,18 +780,50 @@ func TestHandshakeServerSNIGetCertificateNotFound(t *testing.T) {
 // TestHandshakeServerSNICertForNameError tests to make sure that errors in
 // GetCertificate result in a tls alert.
 func TestHandshakeServerSNIGetCertificateError(t *testing.T) {
-	config := *testConfig
+	const errMsg = "TestHandshakeServerSNIGetCertificateError error"
 
-	config.GetCertificate = func(clientHello *ClientHelloInfo) (*Certificate, error) {
-		return nil, fmt.Errorf("Test error in GetCertificate")
+	serverConfig := *testConfig
+	serverConfig.GetCertificate = func(clientHello *ClientHelloInfo) (*Certificate, error) {
+		return nil, errors.New(errMsg)
 	}
-	test := &serverTest{
-		name:        "SNI",
-		command:     []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA", "-servername", "snitest.com"},
-		config:      &config,
-		expectAlert: true,
+
+	clientHello := &clientHelloMsg{
+		vers:               0x0301,
+		cipherSuites:       []uint16{TLS_RSA_WITH_RC4_128_SHA},
+		compressionMethods: []uint8{0},
+		serverName:         "test",
 	}
-	runServerTestTLS12(t, test)
+	testClientHelloFailure(t, &serverConfig, clientHello, errMsg)
+}
+
+// TestHandshakeServerEmptyCertificates tests that GetCertificates is called in
+// the case that Certificates is empty, even without SNI.
+func TestHandshakeServerEmptyCertificates(t *testing.T) {
+	const errMsg = "TestHandshakeServerEmptyCertificates error"
+
+	serverConfig := *testConfig
+	serverConfig.GetCertificate = func(clientHello *ClientHelloInfo) (*Certificate, error) {
+		return nil, errors.New(errMsg)
+	}
+	serverConfig.Certificates = nil
+
+	clientHello := &clientHelloMsg{
+		vers:               0x0301,
+		cipherSuites:       []uint16{TLS_RSA_WITH_RC4_128_SHA},
+		compressionMethods: []uint8{0},
+	}
+	testClientHelloFailure(t, &serverConfig, clientHello, errMsg)
+
+	// With an empty Certificates and a nil GetCertificate, the server
+	// should always return a “no certificates” error.
+	serverConfig.GetCertificate = nil
+
+	clientHello = &clientHelloMsg{
+		vers:               0x0301,
+		cipherSuites:       []uint16{TLS_RSA_WITH_RC4_128_SHA},
+		compressionMethods: []uint8{0},
+	}
+	testClientHelloFailure(t, &serverConfig, clientHello, "no certificates")
 }
 
 // TestCipherSuiteCertPreferance ensures that we select an RSA ciphersuite with
@@ -716,11 +901,15 @@ func TestResumptionDisabled(t *testing.T) {
 }
 
 func TestFallbackSCSV(t *testing.T) {
+	serverConfig := &Config{
+		Certificates: testConfig.Certificates,
+	}
 	test := &serverTest{
-		name: "FallbackSCSV",
+		name:   "FallbackSCSV",
+		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)
 }
@@ -840,7 +1029,9 @@ func fromHex(s string) []byte {
 	return b
 }
 
-var testRSACertificate = fromHex("308202b030820219a00302010202090085b0bba48a7fb8ca300d06092a864886f70d01010505003045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c7464301e170d3130303432343039303933385a170d3131303432343039303933385a3045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c746430819f300d06092a864886f70d010101 [...]
+var testRSACertificate = fromHex("30820263308201cca003020102020900a273000c8100cbf3300d06092a864886f70d01010b0500302b31173015060355040a130e476f6f676c652054455354494e473110300e06035504031307476f20526f6f74301e170d3135303130313030303030305a170d3235303130313030303030305a302631173015060355040a130e476f6f676c652054455354494e47310b300906035504031302476f30819f300d06092a864886f70d010101050003818d0030818902818100af8788f6201b95656c14ab4405af3b4514e3b76dfd00634d957ffe6a623586c04af9187cf6aa255e7a643166 [...]
+
+var testRSACertificateIssuer = fromHex("3082024d308201b6a003020102020827326bd913b7c43d300d06092a864886f70d01010b0500302b31173015060355040a130e476f6f676c652054455354494e473110300e06035504031307476f20526f6f74301e170d3135303130313030303030305a170d3235303130313030303030305a302b31173015060355040a130e476f6f676c652054455354494e473110300e06035504031307476f20526f6f7430819f300d06092a864886f70d010101050003818d0030818902818100f0429a7b9f66a222c8453800452db355b34c4409fee09af2510a6589bfa35bdb4d453200d1 [...]
 
 var testECDSACertificate = fromHex("3082020030820162020900b8bf2d47a0d2ebf4300906072a8648ce3d04013045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c7464301e170d3132313132323135303633325a170d3232313132303135303633325a3045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c746430819b301006072a8648ce3d020106052b81040023038186 [...]
 
@@ -848,13 +1039,13 @@ var testSNICertificate = fromHex("308201f23082015da003020102020100300b06092a8648
 
 var testRSAPrivateKey = &rsa.PrivateKey{
 	PublicKey: rsa.PublicKey{
-		N: bigFromString("131650079503776001033793877885499001334664249354723305978524647182322416328664556247316495448366990052837680518067798333412266673813370895702118944398081598789828837447552603077848001020611640547221687072142537202428102790818451901395596882588063427854225330436740647715202971973145151161964464812406232198521"),
+		N: bigFromString("123260960069105588390096594560395120585636206567569540256061833976822892593755073841963170165000086278069699238754008398039246547214989242849418349143232951701395321381739566687846006911427966669790845430647688107009232778985142860108863460556510585049041936029324503323373417214453307648498561956908810892027L"),
 		E: 65537,
 	},
-	D: bigFromString("29354450337804273969007277378287027274721892607543397931919078829901848876371746653677097639302788129485893852488285045793268732234230875671682624082413996177431586734171663258657462237320300610850244186316880055243099640544518318093544057213190320837094958164973959123058337475052510833916491060913053867729"),
+	D: bigFromString("73196363031103823625826315929954946106043759818067219550565550066527203472294428548476778865091068522665312037075674791871635825938217363523103946045078950060973913307430314113074463630778799389010335923241901501086246276485964417618981733827707048660375428006201525399194575538037883519254056917253456403553L"),
 	Primes: []*big.Int{
-		bigFromString("11969277782311800166562047708379380720136961987713178380670422671426759650127150688426177829077494755200794297055316163155755835813760102405344560929062149"),
-		bigFromString("10998999429884441391899182616418192492905073053684657075974935218461686523870125521822756579792315215543092255516093840728890783887287417039645833477273829"),
+		bigFromString("11157426355495284553529769521954035649776033703833034489026848970480272318436419662860715175517581249375929775774910501512841707465207184924996975125010787L"),
+		bigFromString("11047436580963564307160117670964629323534448585520694947919342920137706075617545637058809770319843170934495909554506529982972972247390145716507031692656521L"),
 	},
 }
 
diff --git a/src/crypto/tls/key_agreement.go b/src/crypto/tls/key_agreement.go
index 0974fc6..0e6a7c2 100644
--- a/src/crypto/tls/key_agreement.go
+++ b/src/crypto/tls/key_agreement.go
@@ -11,7 +11,6 @@ import (
 	"crypto/md5"
 	"crypto/rsa"
 	"crypto/sha1"
-	"crypto/sha256"
 	"crypto/x509"
 	"encoding/asn1"
 	"errors"
@@ -31,12 +30,6 @@ func (ka rsaKeyAgreement) generateServerKeyExchange(config *Config, cert *Certif
 }
 
 func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
-	preMasterSecret := make([]byte, 48)
-	_, err := io.ReadFull(config.rand(), preMasterSecret[2:])
-	if err != nil {
-		return nil, err
-	}
-
 	if len(ckx.ciphertext) < 2 {
 		return nil, errClientKeyExchange
 	}
@@ -49,8 +42,12 @@ func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, cert *Certifi
 		}
 		ciphertext = ckx.ciphertext[2:]
 	}
-
-	err = rsa.DecryptPKCS1v15SessionKey(config.rand(), cert.PrivateKey.(*rsa.PrivateKey), ciphertext, preMasterSecret)
+	priv, ok := cert.PrivateKey.(crypto.Decrypter)
+	if !ok {
+		return nil, errors.New("tls: certificate private key does not implement crypto.Decrypter")
+	}
+	// Perform constant time RSA PKCS#1 v1.5 decryption
+	preMasterSecret, err := priv.Decrypt(config.rand(), ciphertext, &rsa.PKCS1v15DecryptOptions{SessionKeyLen: 48})
 	if err != nil {
 		return nil, err
 	}
@@ -110,30 +107,26 @@ func md5SHA1Hash(slices [][]byte) []byte {
 	return md5sha1
 }
 
-// sha256Hash implements TLS 1.2's hash function.
-func sha256Hash(slices [][]byte) []byte {
-	h := sha256.New()
-	for _, slice := range slices {
-		h.Write(slice)
-	}
-	return h.Sum(nil)
-}
-
 // hashForServerKeyExchange hashes the given slices and returns their digest
-// and the identifier of the hash function used. The hashFunc argument is only
-// used for >= TLS 1.2 and precisely identifies the hash function to use.
-func hashForServerKeyExchange(sigType, hashFunc uint8, version uint16, slices ...[]byte) ([]byte, crypto.Hash, error) {
+// and the identifier of the hash function used. The sigAndHash argument is
+// only used for >= TLS 1.2 and precisely identifies the hash function to use.
+func hashForServerKeyExchange(sigAndHash signatureAndHash, version uint16, slices ...[]byte) ([]byte, crypto.Hash, error) {
 	if version >= VersionTLS12 {
-		switch hashFunc {
-		case hashSHA256:
-			return sha256Hash(slices), crypto.SHA256, nil
-		case hashSHA1:
-			return sha1Hash(slices), crypto.SHA1, nil
-		default:
-			return nil, crypto.Hash(0), errors.New("tls: unknown hash function used by peer")
+		if !isSupportedSignatureAndHash(sigAndHash, supportedSignatureAlgorithms) {
+			return nil, crypto.Hash(0), errors.New("tls: unsupported hash function used by peer")
 		}
+		hashFunc, err := lookupTLSHash(sigAndHash.hash)
+		if err != nil {
+			return nil, crypto.Hash(0), err
+		}
+		h := hashFunc.New()
+		for _, slice := range slices {
+			h.Write(slice)
+		}
+		digest := h.Sum(nil)
+		return digest, hashFunc, nil
 	}
-	if sigType == signatureECDSA {
+	if sigAndHash.signature == signatureECDSA {
 		return sha1Hash(slices), crypto.SHA1, nil
 	}
 	return md5SHA1Hash(slices), crypto.MD5SHA1, nil
@@ -142,20 +135,19 @@ func hashForServerKeyExchange(sigType, hashFunc uint8, version uint16, slices ..
 // pickTLS12HashForSignature returns a TLS 1.2 hash identifier for signing a
 // ServerKeyExchange given the signature type being used and the client's
 // advertised list of supported signature and hash combinations.
-func pickTLS12HashForSignature(sigType uint8, clientSignatureAndHashes []signatureAndHash) (uint8, error) {
-	if len(clientSignatureAndHashes) == 0 {
+func pickTLS12HashForSignature(sigType uint8, clientList []signatureAndHash) (uint8, error) {
+	if len(clientList) == 0 {
 		// If the client didn't specify any signature_algorithms
 		// extension then we can assume that it supports SHA1. See
 		// http://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
 		return hashSHA1, nil
 	}
 
-	for _, sigAndHash := range clientSignatureAndHashes {
+	for _, sigAndHash := range clientList {
 		if sigAndHash.signature != sigType {
 			continue
 		}
-		switch sigAndHash.hash {
-		case hashSHA1, hashSHA256:
+		if isSupportedSignatureAndHash(sigAndHash, supportedSignatureAlgorithms) {
 			return sigAndHash.hash, nil
 		}
 	}
@@ -228,41 +220,42 @@ NextCandidate:
 	serverECDHParams[3] = byte(len(ecdhePublic))
 	copy(serverECDHParams[4:], ecdhePublic)
 
-	var tls12HashId uint8
+	sigAndHash := signatureAndHash{signature: ka.sigType}
+
 	if ka.version >= VersionTLS12 {
-		if tls12HashId, err = pickTLS12HashForSignature(ka.sigType, clientHello.signatureAndHashes); err != nil {
+		if sigAndHash.hash, err = pickTLS12HashForSignature(ka.sigType, clientHello.signatureAndHashes); err != nil {
 			return nil, err
 		}
 	}
 
-	digest, hashFunc, err := hashForServerKeyExchange(ka.sigType, tls12HashId, ka.version, clientHello.random, hello.random, serverECDHParams)
+	digest, hashFunc, err := hashForServerKeyExchange(sigAndHash, ka.version, clientHello.random, hello.random, serverECDHParams)
 	if err != nil {
 		return nil, err
 	}
+
+	priv, ok := cert.PrivateKey.(crypto.Signer)
+	if !ok {
+		return nil, errors.New("tls: certificate private key does not implement crypto.Signer")
+	}
 	var sig []byte
 	switch ka.sigType {
 	case signatureECDSA:
-		privKey, ok := cert.PrivateKey.(*ecdsa.PrivateKey)
+		_, ok := priv.Public().(*ecdsa.PublicKey)
 		if !ok {
-			return nil, errors.New("ECDHE ECDSA requires an ECDSA server private key")
+			return nil, errors.New("ECDHE ECDSA requires an ECDSA server key")
 		}
-		r, s, err := ecdsa.Sign(config.rand(), privKey, digest)
-		if err != nil {
-			return nil, errors.New("failed to sign ECDHE parameters: " + err.Error())
-		}
-		sig, err = asn1.Marshal(ecdsaSignature{r, s})
 	case signatureRSA:
-		privKey, ok := cert.PrivateKey.(*rsa.PrivateKey)
+		_, ok := priv.Public().(*rsa.PublicKey)
 		if !ok {
-			return nil, errors.New("ECDHE RSA requires a RSA server private key")
-		}
-		sig, err = rsa.SignPKCS1v15(config.rand(), privKey, hashFunc, digest)
-		if err != nil {
-			return nil, errors.New("failed to sign ECDHE parameters: " + err.Error())
+			return nil, errors.New("ECDHE RSA requires a RSA server key")
 		}
 	default:
 		return nil, errors.New("unknown ECDHE signature algorithm")
 	}
+	sig, err = priv.Sign(config.rand(), digest, hashFunc)
+	if err != nil {
+		return nil, errors.New("failed to sign ECDHE parameters: " + err.Error())
+	}
 
 	skx := new(serverKeyExchangeMsg)
 	sigAndHashLen := 0
@@ -273,8 +266,8 @@ NextCandidate:
 	copy(skx.key, serverECDHParams)
 	k := skx.key[len(serverECDHParams):]
 	if ka.version >= VersionTLS12 {
-		k[0] = tls12HashId
-		k[1] = ka.sigType
+		k[0] = sigAndHash.hash
+		k[1] = sigAndHash.signature
 		k = k[2:]
 	}
 	k[0] = byte(len(sig) >> 8)
@@ -335,15 +328,14 @@ func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHell
 		return errServerKeyExchange
 	}
 
-	var tls12HashId uint8
+	sigAndHash := signatureAndHash{signature: ka.sigType}
 	if ka.version >= VersionTLS12 {
 		// handle SignatureAndHashAlgorithm
-		var sigAndHash []uint8
-		sigAndHash, sig = sig[:2], sig[2:]
-		if sigAndHash[1] != ka.sigType {
+		sigAndHash = signatureAndHash{hash: sig[0], signature: sig[1]}
+		if sigAndHash.signature != ka.sigType {
 			return errServerKeyExchange
 		}
-		tls12HashId = sigAndHash[0]
+		sig = sig[2:]
 		if len(sig) < 2 {
 			return errServerKeyExchange
 		}
@@ -354,7 +346,7 @@ func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHell
 	}
 	sig = sig[2:]
 
-	digest, hashFunc, err := hashForServerKeyExchange(ka.sigType, tls12HashId, ka.version, clientHello.random, serverHello.random, serverECDHParams)
+	digest, hashFunc, err := hashForServerKeyExchange(sigAndHash, ka.version, clientHello.random, serverHello.random, serverECDHParams)
 	if err != nil {
 		return err
 	}
diff --git a/src/crypto/tls/prf.go b/src/crypto/tls/prf.go
index fb8b3ab..6127c1c 100644
--- a/src/crypto/tls/prf.go
+++ b/src/crypto/tls/prf.go
@@ -10,6 +10,8 @@ import (
 	"crypto/md5"
 	"crypto/sha1"
 	"crypto/sha256"
+	"crypto/sha512"
+	"errors"
 	"hash"
 )
 
@@ -65,12 +67,14 @@ func prf10(result, secret, label, seed []byte) {
 }
 
 // prf12 implements the TLS 1.2 pseudo-random function, as defined in RFC 5246, section 5.
-func prf12(result, secret, label, seed []byte) {
-	labelAndSeed := make([]byte, len(label)+len(seed))
-	copy(labelAndSeed, label)
-	copy(labelAndSeed[len(label):], seed)
+func prf12(hashFunc func() hash.Hash) func(result, secret, label, seed []byte) {
+	return func(result, secret, label, seed []byte) {
+		labelAndSeed := make([]byte, len(label)+len(seed))
+		copy(labelAndSeed, label)
+		copy(labelAndSeed[len(label):], seed)
 
-	pHash(result, secret, labelAndSeed, sha256.New)
+		pHash(result, secret, labelAndSeed, hashFunc)
+	}
 }
 
 // prf30 implements the SSL 3.0 pseudo-random function, as defined in
@@ -117,41 +121,49 @@ var keyExpansionLabel = []byte("key expansion")
 var clientFinishedLabel = []byte("client finished")
 var serverFinishedLabel = []byte("server finished")
 
-func prfForVersion(version uint16) func(result, secret, label, seed []byte) {
+func prfAndHashForVersion(version uint16, suite *cipherSuite) (func(result, secret, label, seed []byte), crypto.Hash) {
 	switch version {
 	case VersionSSL30:
-		return prf30
+		return prf30, crypto.Hash(0)
 	case VersionTLS10, VersionTLS11:
-		return prf10
+		return prf10, crypto.Hash(0)
 	case VersionTLS12:
-		return prf12
+		if suite.flags&suiteSHA384 != 0 {
+			return prf12(sha512.New384), crypto.SHA384
+		}
+		return prf12(sha256.New), crypto.SHA256
 	default:
 		panic("unknown version")
 	}
 }
 
+func prfForVersion(version uint16, suite *cipherSuite) func(result, secret, label, seed []byte) {
+	prf, _ := prfAndHashForVersion(version, suite)
+	return prf
+}
+
 // masterFromPreMasterSecret generates the master secret from the pre-master
 // secret. See http://tools.ietf.org/html/rfc5246#section-8.1
-func masterFromPreMasterSecret(version uint16, preMasterSecret, clientRandom, serverRandom []byte) []byte {
+func masterFromPreMasterSecret(version uint16, suite *cipherSuite, preMasterSecret, clientRandom, serverRandom []byte) []byte {
 	var seed [tlsRandomLength * 2]byte
 	copy(seed[0:len(clientRandom)], clientRandom)
 	copy(seed[len(clientRandom):], serverRandom)
 	masterSecret := make([]byte, masterSecretLength)
-	prfForVersion(version)(masterSecret, preMasterSecret, masterSecretLabel, seed[0:])
+	prfForVersion(version, suite)(masterSecret, preMasterSecret, masterSecretLabel, seed[0:])
 	return masterSecret
 }
 
 // keysFromMasterSecret generates the connection keys from the master
 // secret, given the lengths of the MAC key, cipher key and IV, as defined in
 // RFC 2246, section 6.3.
-func keysFromMasterSecret(version uint16, masterSecret, clientRandom, serverRandom []byte, macLen, keyLen, ivLen int) (clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV []byte) {
+func keysFromMasterSecret(version uint16, suite *cipherSuite, masterSecret, clientRandom, serverRandom []byte, macLen, keyLen, ivLen int) (clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV []byte) {
 	var seed [tlsRandomLength * 2]byte
 	copy(seed[0:len(clientRandom)], serverRandom)
 	copy(seed[len(serverRandom):], clientRandom)
 
 	n := 2*macLen + 2*keyLen + 2*ivLen
 	keyMaterial := make([]byte, n)
-	prfForVersion(version)(keyMaterial, masterSecret, keyExpansionLabel, seed[0:])
+	prfForVersion(version, suite)(keyMaterial, masterSecret, keyExpansionLabel, seed[0:])
 	clientMAC = keyMaterial[:macLen]
 	keyMaterial = keyMaterial[macLen:]
 	serverMAC = keyMaterial[:macLen]
@@ -166,11 +178,33 @@ func keysFromMasterSecret(version uint16, masterSecret, clientRandom, serverRand
 	return
 }
 
-func newFinishedHash(version uint16) finishedHash {
-	if version >= VersionTLS12 {
-		return finishedHash{sha256.New(), sha256.New(), nil, nil, version}
+// lookupTLSHash looks up the corresponding crypto.Hash for a given
+// TLS hash identifier.
+func lookupTLSHash(hash uint8) (crypto.Hash, error) {
+	switch hash {
+	case hashSHA1:
+		return crypto.SHA1, nil
+	case hashSHA256:
+		return crypto.SHA256, nil
+	case hashSHA384:
+		return crypto.SHA384, nil
+	default:
+		return 0, errors.New("tls: unsupported hash algorithm")
+	}
+}
+
+func newFinishedHash(version uint16, cipherSuite *cipherSuite) finishedHash {
+	var buffer []byte
+	if version == VersionSSL30 || version >= VersionTLS12 {
+		buffer = []byte{}
 	}
-	return finishedHash{sha1.New(), sha1.New(), md5.New(), md5.New(), version}
+
+	prf, hash := prfAndHashForVersion(version, cipherSuite)
+	if hash != 0 {
+		return finishedHash{hash.New(), hash.New(), nil, nil, buffer, version, prf}
+	}
+
+	return finishedHash{sha1.New(), sha1.New(), md5.New(), md5.New(), buffer, version, prf}
 }
 
 // A finishedHash calculates the hash of a set of handshake messages suitable
@@ -183,10 +217,14 @@ type finishedHash struct {
 	clientMD5 hash.Hash
 	serverMD5 hash.Hash
 
+	// In TLS 1.2, a full buffer is sadly required.
+	buffer []byte
+
 	version uint16
+	prf     func(result, secret, label, seed []byte)
 }
 
-func (h finishedHash) Write(msg []byte) (n int, err error) {
+func (h *finishedHash) Write(msg []byte) (n int, err error) {
 	h.client.Write(msg)
 	h.server.Write(msg)
 
@@ -194,14 +232,29 @@ func (h finishedHash) Write(msg []byte) (n int, err error) {
 		h.clientMD5.Write(msg)
 		h.serverMD5.Write(msg)
 	}
+
+	if h.buffer != nil {
+		h.buffer = append(h.buffer, msg...)
+	}
+
 	return len(msg), nil
 }
 
+func (h finishedHash) Sum() []byte {
+	if h.version >= VersionTLS12 {
+		return h.client.Sum(nil)
+	}
+
+	out := make([]byte, 0, md5.Size+sha1.Size)
+	out = h.clientMD5.Sum(out)
+	return h.client.Sum(out)
+}
+
 // finishedSum30 calculates the contents of the verify_data member of a SSLv3
 // Finished message given the MD5 and SHA1 hashes of a set of handshake
 // messages.
-func finishedSum30(md5, sha1 hash.Hash, masterSecret []byte, magic [4]byte) []byte {
-	md5.Write(magic[:])
+func finishedSum30(md5, sha1 hash.Hash, masterSecret []byte, magic []byte) []byte {
+	md5.Write(magic)
 	md5.Write(masterSecret)
 	md5.Write(ssl30Pad1[:])
 	md5Digest := md5.Sum(nil)
@@ -212,7 +265,7 @@ func finishedSum30(md5, sha1 hash.Hash, masterSecret []byte, magic [4]byte) []by
 	md5.Write(md5Digest)
 	md5Digest = md5.Sum(nil)
 
-	sha1.Write(magic[:])
+	sha1.Write(magic)
 	sha1.Write(masterSecret)
 	sha1.Write(ssl30Pad1[:40])
 	sha1Digest := sha1.Sum(nil)
@@ -236,19 +289,11 @@ var ssl3ServerFinishedMagic = [4]byte{0x53, 0x52, 0x56, 0x52}
 // Finished message.
 func (h finishedHash) clientSum(masterSecret []byte) []byte {
 	if h.version == VersionSSL30 {
-		return finishedSum30(h.clientMD5, h.client, masterSecret, ssl3ClientFinishedMagic)
+		return finishedSum30(h.clientMD5, h.client, masterSecret, ssl3ClientFinishedMagic[:])
 	}
 
 	out := make([]byte, finishedVerifyLength)
-	if h.version >= VersionTLS12 {
-		seed := h.client.Sum(nil)
-		prf12(out, masterSecret, clientFinishedLabel, seed)
-	} else {
-		seed := make([]byte, 0, md5.Size+sha1.Size)
-		seed = h.clientMD5.Sum(seed)
-		seed = h.client.Sum(seed)
-		prf10(out, masterSecret, clientFinishedLabel, seed)
-	}
+	h.prf(out, masterSecret, clientFinishedLabel, h.Sum())
 	return out
 }
 
@@ -256,36 +301,67 @@ func (h finishedHash) clientSum(masterSecret []byte) []byte {
 // Finished message.
 func (h finishedHash) serverSum(masterSecret []byte) []byte {
 	if h.version == VersionSSL30 {
-		return finishedSum30(h.serverMD5, h.server, masterSecret, ssl3ServerFinishedMagic)
+		return finishedSum30(h.serverMD5, h.server, masterSecret, ssl3ServerFinishedMagic[:])
 	}
 
 	out := make([]byte, finishedVerifyLength)
-	if h.version >= VersionTLS12 {
-		seed := h.server.Sum(nil)
-		prf12(out, masterSecret, serverFinishedLabel, seed)
-	} else {
-		seed := make([]byte, 0, md5.Size+sha1.Size)
-		seed = h.serverMD5.Sum(seed)
-		seed = h.server.Sum(seed)
-		prf10(out, masterSecret, serverFinishedLabel, seed)
-	}
+	h.prf(out, masterSecret, serverFinishedLabel, h.Sum())
 	return out
 }
 
+// selectClientCertSignatureAlgorithm returns a signatureAndHash to sign a
+// client's CertificateVerify with, or an error if none can be found.
+func (h finishedHash) selectClientCertSignatureAlgorithm(serverList []signatureAndHash, sigType uint8) (signatureAndHash, error) {
+	if h.version < VersionTLS12 {
+		// Nothing to negotiate before TLS 1.2.
+		return signatureAndHash{signature: sigType}, nil
+	}
+
+	for _, v := range serverList {
+		if v.signature == sigType && isSupportedSignatureAndHash(v, supportedSignatureAlgorithms) {
+			return v, nil
+		}
+	}
+	return signatureAndHash{}, errors.New("tls: no supported signature algorithm found for signing client certificate")
+}
+
 // hashForClientCertificate returns a digest, hash function, and TLS 1.2 hash
 // id suitable for signing by a TLS client certificate.
-func (h finishedHash) hashForClientCertificate(sigType uint8) ([]byte, crypto.Hash, uint8) {
+func (h finishedHash) hashForClientCertificate(signatureAndHash signatureAndHash, masterSecret []byte) ([]byte, crypto.Hash, error) {
+	if (h.version == VersionSSL30 || h.version >= VersionTLS12) && h.buffer == nil {
+		panic("a handshake hash for a client-certificate was requested after discarding the handshake buffer")
+	}
+
+	if h.version == VersionSSL30 {
+		if signatureAndHash.signature != signatureRSA {
+			return nil, 0, errors.New("tls: unsupported signature type for client certificate")
+		}
+
+		md5Hash := md5.New()
+		md5Hash.Write(h.buffer)
+		sha1Hash := sha1.New()
+		sha1Hash.Write(h.buffer)
+		return finishedSum30(md5Hash, sha1Hash, masterSecret, nil), crypto.MD5SHA1, nil
+	}
 	if h.version >= VersionTLS12 {
-		digest := h.server.Sum(nil)
-		return digest, crypto.SHA256, hashSHA256
+		hashAlg, err := lookupTLSHash(signatureAndHash.hash)
+		if err != nil {
+			return nil, 0, err
+		}
+		hash := hashAlg.New()
+		hash.Write(h.buffer)
+		return hash.Sum(nil), hashAlg, nil
 	}
-	if sigType == signatureECDSA {
-		digest := h.server.Sum(nil)
-		return digest, crypto.SHA1, hashSHA1
+
+	if signatureAndHash.signature == signatureECDSA {
+		return h.server.Sum(nil), crypto.SHA1, nil
 	}
 
-	digest := make([]byte, 0, 36)
-	digest = h.serverMD5.Sum(digest)
-	digest = h.server.Sum(digest)
-	return digest, crypto.MD5SHA1, 0 /* not specified in TLS 1.2. */
+	return h.Sum(), crypto.MD5SHA1, nil
+}
+
+// discardHandshakeBuffer is called when there is no more need to
+// buffer the entirety of the handshake messages.
+func (h *finishedHash) discardHandshakeBuffer() {
+	h.buffer = nil
 }
diff --git a/src/crypto/tls/prf_test.go b/src/crypto/tls/prf_test.go
index a9b6c9e..0a1b1bc 100644
--- a/src/crypto/tls/prf_test.go
+++ b/src/crypto/tls/prf_test.go
@@ -35,6 +35,7 @@ func TestSplitPreMasterSecret(t *testing.T) {
 
 type testKeysFromTest struct {
 	version                    uint16
+	suite                      *cipherSuite
 	preMasterSecret            string
 	clientRandom, serverRandom string
 	masterSecret               string
@@ -49,13 +50,13 @@ func TestKeysFromPreMasterSecret(t *testing.T) {
 		clientRandom, _ := hex.DecodeString(test.clientRandom)
 		serverRandom, _ := hex.DecodeString(test.serverRandom)
 
-		masterSecret := masterFromPreMasterSecret(test.version, in, clientRandom, serverRandom)
+		masterSecret := masterFromPreMasterSecret(test.version, test.suite, in, clientRandom, serverRandom)
 		if s := hex.EncodeToString(masterSecret); s != test.masterSecret {
 			t.Errorf("#%d: bad master secret %s, want %s", i, s, test.masterSecret)
 			continue
 		}
 
-		clientMAC, serverMAC, clientKey, serverKey, _, _ := keysFromMasterSecret(test.version, masterSecret, clientRandom, serverRandom, test.macLen, test.keyLen, 0)
+		clientMAC, serverMAC, clientKey, serverKey, _, _ := keysFromMasterSecret(test.version, test.suite, masterSecret, clientRandom, serverRandom, test.macLen, test.keyLen, 0)
 		clientMACString := hex.EncodeToString(clientMAC)
 		serverMACString := hex.EncodeToString(serverMAC)
 		clientKeyString := hex.EncodeToString(clientKey)
@@ -69,10 +70,20 @@ func TestKeysFromPreMasterSecret(t *testing.T) {
 	}
 }
 
+func cipherSuiteById(id uint16) *cipherSuite {
+	for _, cipherSuite := range cipherSuites {
+		if cipherSuite.id == id {
+			return cipherSuite
+		}
+	}
+	panic("ciphersuite not found")
+}
+
 // These test vectors were generated from GnuTLS using `gnutls-cli --insecure -d 9 `
 var testKeysFromTests = []testKeysFromTest{
 	{
 		VersionTLS10,
+		cipherSuiteById(TLS_RSA_WITH_RC4_128_SHA),
 		"0302cac83ad4b1db3b9ab49ad05957de2a504a634a386fc600889321e1a971f57479466830ac3e6f468e87f5385fa0c5",
 		"4ae66303755184a3917fcb44880605fcc53baa01912b22ed94473fc69cebd558",
 		"4ae663020ec16e6bb5130be918cfcafd4d765979a3136a5d50c593446e4e44db",
@@ -86,6 +97,7 @@ var testKeysFromTests = []testKeysFromTest{
 	},
 	{
 		VersionTLS10,
+		cipherSuiteById(TLS_RSA_WITH_RC4_128_SHA),
 		"03023f7527316bc12cbcd69e4b9e8275d62c028f27e65c745cfcddc7ce01bd3570a111378b63848127f1c36e5f9e4890",
 		"4ae66364b5ea56b20ce4e25555aed2d7e67f42788dd03f3fee4adae0459ab106",
 		"4ae66363ab815cbf6a248b87d6b556184e945e9b97fbdf247858b0bdafacfa1c",
@@ -99,6 +111,7 @@ var testKeysFromTests = []testKeysFromTest{
 	},
 	{
 		VersionTLS10,
+		cipherSuiteById(TLS_RSA_WITH_RC4_128_SHA),
 		"832d515f1d61eebb2be56ba0ef79879efb9b527504abb386fb4310ed5d0e3b1f220d3bb6b455033a2773e6d8bdf951d278a187482b400d45deb88a5d5a6bb7d6a7a1decc04eb9ef0642876cd4a82d374d3b6ff35f0351dc5d411104de431375355addc39bfb1f6329fb163b0bc298d658338930d07d313cd980a7e3d9196cac1",
 		"4ae663b2ee389c0de147c509d8f18f5052afc4aaf9699efe8cb05ece883d3a5e",
 		"4ae664d503fd4cff50cfc1fb8fc606580f87b0fcdac9554ba0e01d785bdf278e",
@@ -112,6 +125,7 @@ var testKeysFromTests = []testKeysFromTest{
 	},
 	{
 		VersionSSL30,
+		cipherSuiteById(TLS_RSA_WITH_RC4_128_SHA),
 		"832d515f1d61eebb2be56ba0ef79879efb9b527504abb386fb4310ed5d0e3b1f220d3bb6b455033a2773e6d8bdf951d278a187482b400d45deb88a5d5a6bb7d6a7a1decc04eb9ef0642876cd4a82d374d3b6ff35f0351dc5d411104de431375355addc39bfb1f6329fb163b0bc298d658338930d07d313cd980a7e3d9196cac1",
 		"4ae663b2ee389c0de147c509d8f18f5052afc4aaf9699efe8cb05ece883d3a5e",
 		"4ae664d503fd4cff50cfc1fb8fc606580f87b0fcdac9554ba0e01d785bdf278e",
diff --git a/src/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA b/src/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA
index 00722cb..4bad786 100644
--- a/src/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA
+++ b/src/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA
@@ -1,18 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
 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 1a c0 2f  |.............../|
-00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
-00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
-00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
-00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
-00000070  03 02 01 02 03 ff 01 00  01 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 36  |...../.5.......6|
+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 0e 00  |................|
+00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
+00000080  01 00 00 12 00 00                                 |......|
 >>> Flow 2 (server to client)
-00000000  16 03 01 00 59 02 00 00  55 03 01 53 04 f1 03 46  |....Y...U..S...F|
-00000010  0f 84 c4 cb 55 ef 85 f6  4f d7 0e e1 4b 10 d4 bb  |....U...O...K...|
-00000020  35 87 2d f3 d7 18 ec 4e  95 4b f4 20 28 82 94 d9  |5.-....N.K. (...|
-00000030  df c4 fc ee 21 23 c1 e2  76 3e 7b 09 af 2c 39 23  |....!#..v>{..,9#|
-00000040  f8 46 6c 31 88 42 f0 79  de 37 2b 00 c0 09 00 00  |.Fl1.B.y.7+.....|
+00000000  16 03 01 00 59 02 00 00  55 03 01 c0 e1 5c 5b 45  |....Y...U....\[E|
+00000010  70 fc a1 73 44 e7 69 b6  83 a1 71 bc 03 21 2e cc  |p..sD.i...q..!..|
+00000020  21 7a 28 20 82 6b 2f 77  7d 40 c7 20 0d e4 19 db  |!z( .k/w}@. ....|
+00000030  35 cd 75 a4 e7 e5 6c 3e  c9 d5 fe 9d c5 88 78 7b  |5.u...l>......x{|
+00000040  c4 fc 04 9a c1 10 7a 15  d9 e9 4a 95 c0 09 00 00  |......z...J.....|
 00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
 00000060  01 02 0e 0b 00 02 0a 00  02 07 00 02 04 30 82 02  |.............0..|
 00000070  00 30 82 01 62 02 09 00  b8 bf 2d 47 a0 d2 eb f4  |.0..b.....-G....|
@@ -47,21 +48,21 @@
 00000240  13 83 0d 94 06 bb d4 37  7a f6 ec 7a c9 86 2e dd  |.......7z..z....|
 00000250  d7 11 69 7f 85 7c 56 de  fb 31 78 2b e4 c7 78 0d  |..i..|V..1x+..x.|
 00000260  ae cb be 9e 4e 36 24 31  7b 6a 0f 39 95 12 07 8f  |....N6$1{j.9....|
-00000270  2a 16 03 01 00 d5 0c 00  00 d1 03 00 17 41 04 4f  |*............A.O|
-00000280  47 16 72 98 9e 9f 2e 8e  78 e9 0f fe 95 83 7b aa  |G.r.....x.....{.|
-00000290  e5 3d c0 7d cf 83 bd 22  0b fd 48 f1 a7 49 a5 7d  |.=.}..."..H..I.}|
-000002a0  8e 0c 83 7f e1 2d 71 03  cc 90 09 ab f7 35 81 48  |.....-q......5.H|
-000002b0  a4 1e 7d 87 21 23 12 58  2c 47 f3 af c7 6c 71 00  |..}.!#.X,G...lq.|
-000002c0  8a 30 81 87 02 42 00 b4  03 38 60 43 d9 32 ef 64  |.0...B...8`C.2.d|
-000002d0  5a 9c 91 95 0d 10 21 53  c7 78 f8 bf 50 ed 13 5d  |Z.....!S.x..P..]|
-000002e0  c3 e7 71 d6 11 04 f1 e4  9d ce 17 99 8d 1a 87 1f  |..q.............|
-000002f0  cb dd f8 1b ae cd bc 4a  77 ab 7c 50 bf 73 c3 ea  |.......Jw.|P.s..|
-00000300  d6 df 88 56 f6 b1 03 83  02 41 66 3d fb 4e 7e af  |...V.....Af=.N~.|
-00000310  4e c1 60 fe 09 fa 7e 74  99 66 7f de b4 b2 74 89  |N.`...~t.f....t.|
-00000320  1c a4 cf 74 1a 55 a5 be  74 f9 36 21 3d ae c8 c3  |...t.U..t.6!=...|
-00000330  24 8e ad db a3 26 67 8f  98 27 e3 93 ee d9 5c fb  |$....&g..'....\.|
-00000340  85 82 e2 13 c3 50 ab e9  f6 39 2b 16 03 01 00 0e  |.....P...9+.....|
-00000350  0d 00 00 06 03 01 02 40  00 00 0e 00 00 00        |....... at ......|
+00000270  2a 16 03 01 00 d6 0c 00  00 d2 03 00 17 41 04 01  |*............A..|
+00000280  74 83 af 3a 65 7a ad 1a  63 1f 13 82 9d f4 de 06  |t..:ez..c.......|
+00000290  4e 3a 03 81 61 72 ff f8  58 da 7b f5 81 6d 81 57  |N:..ar..X.{..m.W|
+000002a0  d9 d1 b1 6d e3 97 db 86  72 17 15 18 16 d4 ec 04  |...m....r.......|
+000002b0  32 7c 38 90 6b a4 3c e9  35 79 2d 4c 39 5e 2d 00  |2|8.k.<.5y-L9^-.|
+000002c0  8b 30 81 88 02 42 01 44  78 e1 2a bb 95 f7 45 58  |.0...B.Dx.*...EX|
+000002d0  d4 0d b6 e4 4e ff 48 b3  11 14 ee d5 6c bb 5f 0c  |....N.H.....l._.|
+000002e0  90 b6 ef bc 05 77 f6 05  42 b4 d8 a6 70 e6 8c 90  |.....w..B...p...|
+000002f0  f0 4b 3b c9 d3 4e 0c 85  65 b4 e0 fe b5 10 09 9b  |.K;..N..e.......|
+00000300  e1 08 84 ea 93 96 8e a4  02 42 01 c7 15 ee 9d 98  |.........B......|
+00000310  b7 25 eb 07 ff f6 94 7e  e7 9d a5 17 9e 37 93 40  |.%.....~.....7.@|
+00000320  4c 9f eb 6b a3 7a 57 d8  81 c6 d9 09 34 aa 96 8c  |L..k.zW.....4...|
+00000330  4d 28 2e 9f f7 0b 1c 09  e1 d1 d8 48 6e 8a 8e 9c  |M(.........Hn...|
+00000340  01 4c e7 2d 53 8f 8e 71  61 82 ff ff 16 03 01 00  |.L.-S..qa.......|
+00000350  0e 0d 00 00 06 03 01 02  40 00 00 0e 00 00 00     |........ at ......|
 >>> Flow 3 (client to server)
 00000000  16 03 01 02 0a 0b 00 02  06 00 02 03 00 02 00 30  |...............0|
 00000010  82 01 fc 30 82 01 5e 02  09 00 9a 30 84 6c 26 35  |...0..^....0.l&5|
@@ -100,30 +101,30 @@
 00000220  51 88 35 75 71 b5 e5 54  5b 12 2e 8f 09 67 fd a7  |Q.5uq..T[....g..|
 00000230  24 20 3e b2 56 1c ce 97  28 5e f8 2b 2d 4f 9e f1  |$ >.V...(^.+-O..|
 00000240  07 9f 6c 4b 5b 83 56 e2  32 42 e9 58 b6 d7 49 a6  |..lK[.V.2B.X..I.|
-00000250  b5 68 1a 41 03 56 6b dc  5a 89 16 03 01 00 90 0f  |.h.A.Vk.Z.......|
-00000260  00 00 8c 00 8a 30 81 87  02 42 00 c6 85 8e 06 b7  |.....0...B......|
-00000270  04 04 e9 cd 9e 3e cb 66  23 95 b4 42 9c 64 81 39  |.....>.f#..B.d.9|
-00000280  05 3f b5 21 f8 28 af 60  6b 4d 3d ba a1 4b 5e 77  |.?.!.(.`kM=..K^w|
-00000290  ef e7 59 28 fe 1d c1 27  a2 ff a8 de 33 48 b3 c1  |..Y(...'....3H..|
-000002a0  85 6a 42 9b f9 7e 7e 31  c2 e5 bd 66 02 41 4b 49  |.jB..~~1...f.AKI|
-000002b0  c6 cd 02 e3 83 f7 03 50  18 6d b4 c9 51 02 c0 ab  |.......P.m..Q...|
-000002c0  87 bc e0 3e 4b 89 53 3a  e2 65 89 97 02 c1 87 f1  |...>K.S:.e......|
-000002d0  67 d0 f2 06 28 4e 51 4e  fd f0 01 be 41 3c 52 42  |g...(NQN....A<RB|
-000002e0  10 44 73 88 3e 44 24 bb  2e 77 01 77 6f a8 ac 14  |.Ds.>D$..w.wo...|
-000002f0  03 01 00 01 01 16 03 01  00 30 a3 da 45 22 96 83  |.........0..E"..|
-00000300  59 90 e9 6b ec 3b 77 50  05 89 e6 0c 61 d1 1d 2b  |Y..k.;wP....a..+|
-00000310  da d4 49 bf b9 c6 dd ad  c3 9c 82 bd 53 62 e8 57  |..I.........Sb.W|
-00000320  a4 6a e7 9f b1 d5 39 77  88 6d                    |.j....9w.m|
+00000250  b5 68 1a 41 03 56 6b dc  5a 89 16 03 01 00 91 0f  |.h.A.Vk.Z.......|
+00000260  00 00 8d 00 8b 30 81 88  02 42 01 91 2d e9 99 a4  |.....0...B..-...|
+00000270  88 5c 03 9c ea 8b 64 07  f2 c9 e7 ad 5b a3 fb 27  |.\....d.....[..'|
+00000280  fd 19 9b 78 bd 7b 9d 0a  cc 8a 61 c5 83 33 02 29  |...x.{....a..3.)|
+00000290  c3 66 24 9d 5f bc 03 d9  2a 49 aa 59 51 83 49 72  |.f$._...*I.YQ.Ir|
+000002a0  13 be ea 82 5a 5c 09 2f  da 23 bc 18 02 42 01 0d  |....Z\./.#...B..|
+000002b0  a1 15 4d fe 18 ec 90 d5  4e 9a 75 60 05 67 10 5e  |..M.....N.u`.g.^|
+000002c0  3c 34 00 e8 18 33 8f 90  26 2e d3 a9 81 6c 43 17  |<4...3..&....lC.|
+000002d0  80 9e c5 bd 23 c9 24 96  a1 29 23 a4 13 3f ad d2  |....#.$..)#..?..|
+000002e0  45 19 0b 56 56 4b c1 f1  cc 70 c8 af 44 ff 34 96  |E..VVK...p..D.4.|
+000002f0  14 03 01 00 01 01 16 03  01 00 30 c4 0c 67 53 06  |..........0..gS.|
+00000300  49 b3 c9 5c 2e 72 f6 54  ba ad ac a8 80 55 17 01  |I..\.r.T.....U..|
+00000310  5c 44 71 7d ad 15 34 95  9a 7f 7b 95 0e 08 70 ce  |\Dq}..4...{...p.|
+00000320  5a 33 f4 3b 4e 80 06 43  70 93 17                 |Z3.;N..Cp..|
 >>> Flow 4 (server to client)
-00000000  14 03 01 00 01 01 16 03  01 00 30 a4 45 dd 99 df  |..........0.E...|
-00000010  66 ae f5 c7 bd 1a eb 6a  ff ac a6 38 14 81 b5 07  |f......j...8....|
-00000020  86 24 80 f1 09 59 ad 33  3d 43 ed 9e 43 b1 1e 9f  |.$...Y.3=C..C...|
-00000030  bd 8c b3 e0 41 83 a1 34  91 c5 a1                 |....A..4...|
+00000000  14 03 01 00 01 01 16 03  01 00 30 3b ba 6c 73 ec  |..........0;.ls.|
+00000010  11 5b 44 46 1d bb 31 1b  1b e8 d8 51 4f 95 b0 40  |.[DF..1....QO..@|
+00000020  87 49 33 73 40 98 61 1c  94 02 48 9b 80 d3 6c af  |.I3s at .a...H...l.|
+00000030  e2 31 63 11 a7 c8 db ed  7a a4 4d                 |.1c.....z.M|
 >>> Flow 5 (client to server)
-00000000  17 03 01 00 20 ae e3 ae  7f 2d e3 a2 f7 1b 4e 69  |.... ....-....Ni|
-00000010  cb 18 c6 68 42 f8 de 61  92 4c fa d6 19 7c 8c 09  |...hB..a.L...|..|
-00000020  82 e2 f2 32 19 17 03 01  00 20 2a 77 65 1f c1 fd  |...2..... *we...|
-00000030  5e 37 b7 15 f6 1f 4c 7f  5f 89 52 b4 32 27 4d 17  |^7....L._.R.2'M.|
-00000040  33 c6 e8 50 ac 70 c8 b9  2d 0a 15 03 01 00 20 e0  |3..P.p..-..... .|
-00000050  cb ce 07 80 55 a0 46 ca  a7 25 4c 5f 9d 7c 73 37  |....U.F..%L_.|s7|
-00000060  de 72 6d 36 a8 e4 be fd  2a e7 f8 8d 14 80 b7     |.rm6....*......|
+00000000  17 03 01 00 20 2e f7 66  f0 ce 50 d7 38 7a d4 fd  |.... ..f..P.8z..|
+00000010  e3 66 b1 76 76 59 ad bc  b0 0a 75 1d f0 92 6e e3  |.f.vvY....u...n.|
+00000020  21 1d 13 dc ad 17 03 01  00 20 f1 b2 0f 3b 26 91  |!........ ...;&.|
+00000030  ed ff 9f fc 41 04 7e 47  17 02 af 0c 2b e8 b7 31  |....A.~G....+..1|
+00000040  ae 29 71 f9 a8 89 84 f3  e8 da 15 03 01 00 20 1f  |.)q........... .|
+00000050  26 64 cf 34 c1 48 6b 79  61 e2 77 57 9d 27 14 45  |&d.4.Hkya.wW.'.E|
+00000060  46 24 ad 2d 35 57 db 2b  32 03 e2 68 b0 1a 5a     |F$.-5W.+2..h..Z|
diff --git a/src/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA b/src/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA
index c0be824..0e420a6 100644
--- a/src/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA
+++ b/src/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA
@@ -1,18 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
 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 1a c0 2f  |.............../|
-00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
-00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
-00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
-00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
-00000070  03 02 01 02 03 ff 01 00  01 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 36  |...../.5.......6|
+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 0e 00  |................|
+00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
+00000080  01 00 00 12 00 00                                 |......|
 >>> Flow 2 (server to client)
-00000000  16 03 01 00 51 02 00 00  4d 03 01 53 04 f1 02 ed  |....Q...M..S....|
-00000010  86 9c 56 84 5a d3 7d d7  f3 4e 6f 2c 69 0d f0 59  |..V.Z.}..No,i..Y|
-00000020  a5 d1 de 2d 03 2f dd 63  c3 ab fa 20 30 d6 5a 24  |...-./.c... 0.Z$|
-00000030  5c 31 67 36 8d 4c 43 e1  64 c4 8a 2c a5 fd 39 92  |\1g6.LC.d..,..9.|
-00000040  c5 6f 58 47 a3 fe 63 14  98 92 11 90 00 05 00 00  |.oXG..c.........|
+00000000  16 03 01 00 51 02 00 00  4d 03 01 b7 de 52 5a 07  |....Q...M....RZ.|
+00000010  43 b8 72 1d d9 6f 5c a5  70 da ee 27 b7 a9 50 9d  |C.r..o\.p..'..P.|
+00000020  e7 75 ad 61 a5 2f 69 47  2a d8 2e 20 a8 b0 64 6b  |.u.a./iG*.. ..dk|
+00000030  4d 25 ec 50 2b 8e a7 9b  0c f9 f5 3c 62 96 a3 53  |M%.P+......<b..S|
+00000040  a7 4b af 33 1e e7 f8 43  b9 be 6e e7 00 05 00 00  |.K.3...C..n.....|
 00000050  05 ff 01 00 01 00 16 03  01 02 be 0b 00 02 ba 00  |................|
 00000060  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
 00000070  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
@@ -101,25 +102,25 @@
 00000260  ce 39 4c 9c 86 00 08 c2  4b e2 c6 ec 2f f7 ce e6  |.9L.....K.../...|
 00000270  bd 77 82 6f 23 b6 e0 bd  a2 92 b7 3a ac e8 56 f1  |.w.o#......:..V.|
 00000280  af 54 5e 46 87 e9 3b 33  e7 b8 28 b7 d6 c8 90 35  |.T^F..;3..(....5|
-00000290  d4 1c 43 d1 30 6f 55 4e  0a 70 16 03 01 00 90 0f  |..C.0oUN.p......|
-000002a0  00 00 8c 00 8a 30 81 87  02 42 00 c6 85 8e 06 b7  |.....0...B......|
-000002b0  04 04 e9 cd 9e 3e cb 66  23 95 b4 42 9c 64 81 39  |.....>.f#..B.d.9|
-000002c0  05 3f b5 21 f8 28 af 60  6b 4d 3d ba a1 4b 5e 77  |.?.!.(.`kM=..K^w|
-000002d0  ef e7 59 28 fe 1d c1 27  a2 ff a8 de 33 48 b3 c1  |..Y(...'....3H..|
-000002e0  85 6a 42 9b f9 7e 7e 31  c2 e5 bd 66 02 41 4b 49  |.jB..~~1...f.AKI|
-000002f0  c6 cd 02 e3 83 f7 03 50  18 6d b4 c9 51 02 c0 ab  |.......P.m..Q...|
-00000300  87 bc e0 3e 4b 89 53 3a  e2 65 89 97 02 c1 87 f1  |...>K.S:.e......|
-00000310  67 d0 f2 06 28 4e 51 4e  fd f0 01 47 e7 c9 d9 23  |g...(NQN...G...#|
-00000320  21 6b 87 d2 55 e3 c9 f7  eb 86 d5 1e 50 df d5 14  |!k..U.......P...|
-00000330  03 01 00 01 01 16 03 01  00 24 95 62 42 be 90 39  |.........$.bB..9|
-00000340  68 ae f5 77 47 21 14 b9  ac ee 81 2d e3 9e c7 34  |h..wG!.....-...4|
-00000350  3a 00 5c c9 12 1d c0 5a  7c e7 ef e0 cd fd        |:.\....Z|.....|
+00000290  d4 1c 43 d1 30 6f 55 4e  0a 70 16 03 01 00 91 0f  |..C.0oUN.p......|
+000002a0  00 00 8d 00 8b 30 81 88  02 42 00 b5 1a 9d 48 90  |.....0...B....H.|
+000002b0  2f d9 1a 04 66 f7 3b 4d  d7 ae d9 1e dd 3c fa 24  |/...f.;M.....<.$|
+000002c0  0f 24 97 b2 61 46 16 d9  a0 35 f9 f7 54 45 92 fd  |.$..aF...5..TE..|
+000002d0  10 56 ab 26 d7 b5 10 80  8b 88 95 ef c6 73 1c d2  |.V.&.........s..|
+000002e0  ff e9 20 cd 18 a8 40 c4  4d 83 c2 e2 02 42 01 8c  |.. ... at .M....B..|
+000002f0  d2 13 4c cc e5 38 37 17  6c 83 d6 ad c1 dc af ec  |..L..87.l.......|
+00000300  8d 06 75 b8 08 ad 56 4a  8f b9 03 59 80 f8 81 d4  |..u...VJ...Y....|
+00000310  f3 91 89 eb 9c 27 5d e1  dc 6d ef d6 20 da e7 9c  |.....']..m.. ...|
+00000320  71 75 cb 2a f9 e4 05 46  c8 85 ca 7b 9c 97 e8 6d  |qu.*...F...{...m|
+00000330  14 03 01 00 01 01 16 03  01 00 24 9f 67 4e 22 04  |..........$.gN".|
+00000340  10 f4 28 55 3e 50 88 90  61 07 42 29 f5 9b f5 32  |..(U>P..a.B)...2|
+00000350  16 3d ea c1 8f aa a1 4c  b5 72 26 d8 32 cd 50     |.=.....L.r&.2.P|
 >>> Flow 4 (server to client)
-00000000  14 03 01 00 01 01 16 03  01 00 24 ea 98 c0 fb 86  |..........$.....|
-00000010  87 7a 2e e1 c7 68 61 3e  5b cc da 1f d6 7b ab 5a  |.z...ha>[....{.Z|
-00000020  a0 ae a2 cf d0 54 44 19  12 db 75 2b 8c 73 8c     |.....TD...u+.s.|
+00000000  14 03 01 00 01 01 16 03  01 00 24 df 8d f1 07 6d  |..........$....m|
+00000010  63 39 fc ba b1 67 3b 68  85 b9 37 7d d3 67 19 76  |c9...g;h..7}.g.v|
+00000020  34 a4 1b 86 31 bd fe 06  72 00 d8 2b f2 65 3d     |4...1...r..+.e=|
 >>> Flow 5 (client to server)
-00000000  17 03 01 00 1a f3 28 77  31 33 4c b3 7c 4b 75 61  |......(w13L.|Kua|
-00000010  38 69 6b ae c9 36 ab 2e  56 16 29 6a 9a 00 2f 15  |8ik..6..V.)j../.|
-00000020  03 01 00 16 6b ed 68 18  ed ff 44 39 9b 4a e4 a2  |....k.h...D9.J..|
-00000030  cd 79 ef 2a 3e 5a 4d b1  5d 56                    |.y.*>ZM.]V|
+00000000  17 03 01 00 1a 60 cc 81  4f 8b 73 b3 7f 34 bf f1  |.....`..O.s..4..|
+00000010  7c d8 32 0a ef 2a 26 f9  b8 69 84 83 48 21 ee 15  ||.2..*&..i..H!..|
+00000020  03 01 00 16 23 7a 0c 65  3a 66 1a 75 03 e4 85 3f  |....#z.e:f.u...?|
+00000030  83 cd 55 70 99 f4 44 dc  67 ba                    |..Up..D.g.|
diff --git a/src/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA b/src/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA
index 3e6dbc2..7e33edc 100644
--- a/src/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA
+++ b/src/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA
@@ -1,18 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
 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 1a c0 2f  |.............../|
-00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
-00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
-00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
-00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
-00000070  03 02 01 02 03 ff 01 00  01 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 36  |...../.5.......6|
+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 0e 00  |................|
+00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
+00000080  01 00 00 12 00 00                                 |......|
 >>> Flow 2 (server to client)
-00000000  16 03 01 00 59 02 00 00  55 03 01 53 04 f1 02 4f  |....Y...U..S...O|
-00000010  73 06 2d 72 41 36 a1 b2  d3 50 97 55 8c c5 f1 43  |s.-rA6...P.U...C|
-00000020  37 1f 1a 2a fe 51 70 0b  2f 25 9e 20 50 61 86 80  |7..*.Qp./%. Pa..|
-00000030  9a 9c 6d 6f c9 ea 5c ce  0c b7 7c ce e3 be d0 e5  |..mo..\...|.....|
-00000040  be d0 c4 80 78 c3 c7 17  0c 2d 8e c8 c0 09 00 00  |....x....-......|
+00000000  16 03 01 00 59 02 00 00  55 03 01 dc a9 22 c2 a2  |....Y...U...."..|
+00000010  05 ba c4 66 9a 71 aa 0f  92 6a fc df b0 29 4d 36  |...f.q...j...)M6|
+00000020  39 2e f8 39 ed 8e f6 7f  8f 17 13 20 f8 9c f3 3d  |9..9....... ...=|
+00000030  0a 41 8f 30 c7 5d cd 17  c5 ad 1c 52 45 a3 47 8c  |.A.0.].....RE.G.|
+00000040  07 4c 48 e1 00 2b 32 38  01 c8 79 b7 c0 09 00 00  |.LH..+28..y.....|
 00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
 00000060  01 02 0e 0b 00 02 0a 00  02 07 00 02 04 30 82 02  |.............0..|
 00000070  00 30 82 01 62 02 09 00  b8 bf 2d 47 a0 d2 eb f4  |.0..b.....-G....|
@@ -47,21 +48,21 @@
 00000240  13 83 0d 94 06 bb d4 37  7a f6 ec 7a c9 86 2e dd  |.......7z..z....|
 00000250  d7 11 69 7f 85 7c 56 de  fb 31 78 2b e4 c7 78 0d  |..i..|V..1x+..x.|
 00000260  ae cb be 9e 4e 36 24 31  7b 6a 0f 39 95 12 07 8f  |....N6$1{j.9....|
-00000270  2a 16 03 01 00 d6 0c 00  00 d2 03 00 17 41 04 b1  |*............A..|
-00000280  0f 0f 4a 18 ed 25 32 b3  a3 19 ed 4b 61 b6 eb e4  |..J..%2....Ka...|
-00000290  d3 f7 77 13 ac 9f 60 c7  8d 6d cb f1 ee 99 1a 71  |..w...`..m.....q|
-000002a0  68 aa d3 a7 70 7f 38 d0  f6 23 ab 9a f6 dd 19 4f  |h...p.8..#.....O|
-000002b0  ce 10 ef d5 cf 64 85 2f  75 f6 20 06 4b f0 b9 00  |.....d./u. .K...|
-000002c0  8b 30 81 88 02 42 01 00  b9 6b 80 91 59 0a 48 3f  |.0...B...k..Y.H?|
-000002d0  72 16 96 8f 21 2c 28 e4  6d 03 74 66 35 16 7d ec  |r...!,(.m.tf5.}.|
-000002e0  c7 08 9b 52 b5 05 d9 38  d8 b7 51 42 a7 4a 9f 9b  |...R...8..QB.J..|
-000002f0  1a 37 14 de c5 f5 16 96  83 81 58 d3 a6 1e ce 8a  |.7........X.....|
-00000300  bc 19 47 30 fe c5 85 55  02 42 01 4f 61 59 68 85  |..G0...U.B.OaYh.|
-00000310  c7 64 23 22 f6 83 53 cc  58 38 25 b5 ce 74 c1 68  |.d#"..S.X8%..t.h|
-00000320  9f 32 72 33 ea c9 62 e0  26 63 92 e3 5f 34 10 0b  |.2r3..b.&c.._4..|
-00000330  3c d5 83 fe 9f 67 69 ef  33 6b 19 c1 ec d6 6c 35  |<....gi.3k....l5|
-00000340  89 33 17 d3 9d 93 e2 e5  6e 89 9a a1 16 03 01 00  |.3......n.......|
-00000350  0e 0d 00 00 06 03 01 02  40 00 00 0e 00 00 00     |........ at ......|
+00000270  2a 16 03 01 00 d5 0c 00  00 d1 03 00 17 41 04 89  |*............A..|
+00000280  95 9a 90 82 59 ab 29 bf  10 06 8c 6c 0d 67 cf b1  |....Y.)....l.g..|
+00000290  66 8b 5e 43 b8 46 56 3a  8d 30 92 35 28 82 f2 38  |f.^C.FV:.0.5(..8|
+000002a0  6e 19 5d 37 f0 ab fc 78  15 6a 6a 73 ca dc a6 f2  |n.]7...x.jjs....|
+000002b0  68 5d b3 ab 6d 68 44 3b  80 d2 d9 cd 78 0a ed 00  |h]..mhD;....x...|
+000002c0  8a 30 81 87 02 42 01 80  63 4a 22 4c 8e 66 4e 25  |.0...B..cJ"L.fN%|
+000002d0  e1 86 27 81 de eb b3 a0  c4 dc dc e2 a0 94 2a b6  |..'...........*.|
+000002e0  b3 e9 e7 42 e1 1d 1a c0  43 8d a1 d6 8d 77 84 06  |...B....C....w..|
+000002f0  ba 95 99 e3 54 80 59 4e  3c fb 0c f3 b7 d3 a8 d2  |....T.YN<.......|
+00000300  ce 49 97 fb e2 79 91 93  02 41 2b 2c b7 9f 81 ea  |.I...y...A+,....|
+00000310  de 17 12 af 4d 20 bc a1  43 1d 60 a0 37 52 a2 7b  |....M ..C.`.7R.{|
+00000320  a8 4c de fd 1d fe 37 3b  00 23 61 ce d2 80 47 43  |.L....7;.#a...GC|
+00000330  b0 3a f3 1f aa c7 07 b1  68 5b d8 f3 03 a9 56 5c  |.:......h[....V\|
+00000340  63 ef 83 1d 9c 9c 8d 29  81 e9 3b 16 03 01 00 0e  |c......)..;.....|
+00000350  0d 00 00 06 03 01 02 40  00 00 0e 00 00 00        |....... at ......|
 >>> Flow 3 (client to server)
 00000000  16 03 01 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|
@@ -100,29 +101,29 @@
 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 01 00 86  |..h.A.Vk.Z......|
-00000250  0f 00 00 82 00 80 20 2c  5a 08 3a 00 33 50 19 b2  |...... ,Z.:.3P..|
-00000260  0f ba 6c 76 7f 5c 92 e2  78 55 3e 32 32 bb 33 bc  |..lv.\..xU>22.3.|
-00000270  ab a9 34 e0 83 cf 82 cd  9e 6b 3f 9d e6 49 61 29  |..4......k?..Ia)|
-00000280  8b b4 ed e8 12 cd a9 52  86 11 48 64 08 61 72 8d  |.......R..Hd.ar.|
-00000290  d6 6a ac 42 cc e4 07 5f  08 56 9f 2f c5 35 d3 9b  |.j.B..._.V./.5..|
-000002a0  e9 0d 91 82 c0 e9 bb 9f  a9 8f df 96 85 08 9a 69  |...............i|
-000002b0  a4 93 b3 72 37 ba f9 b1  a4 0b b0 9f 43 6a 15 ec  |...r7.......Cj..|
-000002c0  79 b8 fd 9c 1f 5f 0d 2c  56 33 c7 15 d5 4a b7 82  |y...._.,V3...J..|
-000002d0  ea 44 80 20 c5 80 14 03  01 00 01 01 16 03 01 00  |.D. ............|
-000002e0  30 c9 c0 7c d7 57 d3 00  ab 87 eb 78 56 6b a1 69  |0..|.W.....xVk.i|
-000002f0  1d fa ec ae 38 f3 ef 5d  49 19 0d 4b f0 73 63 af  |....8..]I..K.sc.|
-00000300  89 b6 cb 76 cf fb b9 c1  99 98 06 0a 54 67 a0 6e  |...v........Tg.n|
-00000310  e7                                                |.|
+00000250  0f 00 00 82 00 80 0e 80  9c 3a 6e 40 51 09 39 d4  |.........:n at Q.9.|
+00000260  40 58 10 da 7f 32 12 08  9e f0 4d 9a d7 20 a2 9c  |@X...2....M.. ..|
+00000270  b0 95 3a 33 4e f8 b1 a3  74 62 ab 51 7d 23 d4 32  |..:3N...tb.Q}#.2|
+00000280  a2 af b8 5a 3b b0 23 e4  7a f1 eb 4d b7 bb 23 d5  |...Z;.#.z..M..#.|
+00000290  a9 0d b4 81 d2 b4 45 bd  15 52 ad 58 da 92 a2 c4  |......E..R.X....|
+000002a0  30 66 87 f2 ae c5 e4 8c  fa ba a0 40 76 b8 3f 72  |0f......... at v.?r|
+000002b0  2a d9 95 2a 2d c6 05 3c  1e 2f 11 ef c5 3c 11 e4  |*..*-..<./...<..|
+000002c0  be 5a de 37 43 7f 74 52  6e ee 3c 39 cc f1 14 05  |.Z.7C.tRn.<9....|
+000002d0  2d 91 c2 3d c4 7c 14 03  01 00 01 01 16 03 01 00  |-..=.|..........|
+000002e0  30 cd 3c 92 f8 b9 36 7a  e7 8a fb 0f 2f b8 2c 7b  |0.<...6z..../.,{|
+000002f0  10 59 45 14 0a b0 6a 8c  31 b2 89 5b ac 19 dc 12  |.YE...j.1..[....|
+00000300  73 8c 8c 10 49 5a bf 9f  bc 58 82 32 11 ba c5 38  |s...IZ...X.2...8|
+00000310  ff                                                |.|
 >>> Flow 4 (server to client)
-00000000  14 03 01 00 01 01 16 03  01 00 30 20 db fd ed ed  |..........0 ....|
-00000010  7c d5 bf 8f 06 3b 86 1b  c1 60 7d a4 74 e9 a6 c9  ||....;...`}.t...|
-00000020  f5 7c c7 f4 65 91 06 d5  53 88 d7 57 a4 22 b6 1f  |.|..e...S..W."..|
-00000030  f1 02 e9 79 36 e6 a1 22  51 3a 4c                 |...y6.."Q:L|
+00000000  14 03 01 00 01 01 16 03  01 00 30 da 45 99 fe 52  |..........0.E..R|
+00000010  4f cd d0 e6 30 19 f4 bd  80 6d 5c 8a 72 03 d3 88  |O...0....m\.r...|
+00000020  38 63 e9 c9 39 ee ab 3f  52 26 84 b0 4d cb 5c a4  |8c..9..?R&..M.\.|
+00000030  0d 51 c7 47 48 43 3a bf  89 c7 13                 |.Q.GHC:....|
 >>> Flow 5 (client to server)
-00000000  17 03 01 00 20 00 66 51  6a 14 ca ea e2 21 48 74  |.... .fQj....!Ht|
-00000010  c4 c1 6e b9 8b 23 af 7c  33 c9 00 f8 0b ec ab 35  |..n..#.|3......5|
-00000020  e7 42 0a d1 ae 17 03 01  00 20 00 1c 6d 60 75 5d  |.B....... ..m`u]|
-00000030  b3 fb 40 2e e0 b7 0d 48  f4 87 ac d4 bf ea 01 0d  |.. at ....H........|
-00000040  fe 10 0d 05 04 43 6b 19  ed f2 15 03 01 00 20 f8  |.....Ck....... .|
-00000050  03 ac 62 4b 1f db 2e d2  4e 00 c3 a4 57 3c 0a 62  |..bK....N...W<.b|
-00000060  05 a0 ef bd 2b 9b 9a 63  27 72 d7 d8 f1 8d 84     |....+..c'r.....|
+00000000  17 03 01 00 20 4d d9 1d  0d 3d 8b 73 91 b9 4e 5e  |.... M...=.s..N^|
+00000010  35 71 4f 67 79 d2 f7 39  35 ea 23 d0 6d 64 de a5  |5qOgy..95.#.md..|
+00000020  59 fb 75 1f c9 17 03 01  00 20 ba bd 3c b4 d7 be  |Y.u...... ..<...|
+00000030  24 64 68 1e 8c b2 bf 6f  78 9f ad 7f fa dd 89 a6  |$dh....ox.......|
+00000040  f9 e7 5e 70 db e9 db 3a  62 b2 15 03 01 00 20 2a  |..^p...:b..... *|
+00000050  82 f4 8b 45 fc 76 35 6c  54 48 62 2f 52 55 f2 d9  |...E.v5lTHb/RU..|
+00000060  99 b2 b5 2d 5f a0 05 ab  f1 93 58 75 4a 87 35     |...-_.....XuJ.5|
diff --git a/src/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA b/src/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA
index 94e6860..9b1a553 100644
--- a/src/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA
+++ b/src/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA
@@ -1,18 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
 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 1a c0 2f  |.............../|
-00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
-00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
-00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
-00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
-00000070  03 02 01 02 03 ff 01 00  01 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 36  |...../.5.......6|
+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 0e 00  |................|
+00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
+00000080  01 00 00 12 00 00                                 |......|
 >>> Flow 2 (server to client)
-00000000  16 03 01 00 51 02 00 00  4d 03 01 53 04 f1 02 73  |....Q...M..S...s|
-00000010  ee 5f 70 a4 aa 0d be d7  46 a3 25 3f e3 5d ef 7b  |._p.....F.%?.].{|
-00000020  73 49 7c b6 82 4d 99 2f  31 fc 8b 20 2d a3 33 7c  |sI|..M./1.. -.3||
-00000030  a5 c3 85 86 ba 61 4d 05  b0 5e d3 5e 88 6e c3 4b  |.....aM..^.^.n.K|
-00000040  95 d3 e9 67 f1 96 24 58  7a 6f e6 c5 00 05 00 00  |...g..$Xzo......|
+00000000  16 03 01 00 51 02 00 00  4d 03 01 90 e6 e1 c6 bd  |....Q...M.......|
+00000010  86 08 db 33 94 f3 bd 0b  2d fc e0 ba 89 a7 c5 66  |...3....-......f|
+00000020  a5 19 78 33 2b b9 c4 22  d8 e0 63 20 2e 85 53 25  |..x3+.."..c ..S%|
+00000030  f2 22 e3 ca 79 94 9e 50  00 13 da 9d 21 33 49 27  |."..y..P....!3I'|
+00000040  9b 44 c5 10 bc e8 44 01  04 31 02 81 00 05 00 00  |.D....D..1......|
 00000050  05 ff 01 00 01 00 16 03  01 02 be 0b 00 02 ba 00  |................|
 00000060  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
 00000070  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
@@ -101,24 +102,24 @@
 00000260  e6 bd 77 82 6f 23 b6 e0  bd a2 92 b7 3a ac e8 56  |..w.o#......:..V|
 00000270  f1 af 54 5e 46 87 e9 3b  33 e7 b8 28 b7 d6 c8 90  |..T^F..;3..(....|
 00000280  35 d4 1c 43 d1 30 6f 55  4e 0a 70 16 03 01 00 86  |5..C.0oUN.p.....|
-00000290  0f 00 00 82 00 80 0f 4c  d2 b2 f0 94 6d 61 d1 2c  |.......L....ma.,|
-000002a0  db 6f 79 03 bd 40 b2 d2  1d 61 ef 83 1b 4a 0c 7b  |.oy.. at ...a...J.{|
-000002b0  c5 73 1e 1a 81 e7 67 0a  d6 aa 2d 04 04 cc 0e 4b  |.s....g...-....K|
-000002c0  2e da 96 7f 15 6c 05 ee  c4 53 7e 33 89 28 7d db  |.....l...S~3.(}.|
-000002d0  a1 77 43 ba a3 51 a9 1c  b9 f5 ec 9a 8d eb 2c 46  |.wC..Q........,F|
-000002e0  5c 33 59 6b 16 af de f4  9b 80 76 a3 22 30 5d bb  |\3Yk......v."0].|
-000002f0  02 b9 77 96 8a db 36 9f  54 95 00 d8 58 e1 aa 04  |..w...6.T...X...|
-00000300  98 c9 0c 32 ae 62 81 12  0c f6 1b 76 c6 58 a7 8c  |...2.b.....v.X..|
-00000310  0e d8 b7 8e ed 0f 14 03  01 00 01 01 16 03 01 00  |................|
-00000320  24 1d c0 20 02 2d da 69  54 29 8c ff af 5c 56 a8  |$.. .-.iT)...\V.|
-00000330  eb d0 09 95 29 8f 52 8c  e2 7b 9f 36 3e 47 a0 33  |....).R..{.6>G.3|
-00000340  2e 63 a2 24 93                                    |.c.$.|
+00000290  0f 00 00 82 00 80 10 19  57 14 c3 ee 2d da cb de  |........W...-...|
+000002a0  f3 70 c5 62 91 2f ad 62  dd 10 f1 65 20 a2 cf d5  |.p.b./.b...e ...|
+000002b0  cd 6d 5f e4 b3 3e 38 e8  d0 1a f7 f0 e7 7e b6 5d  |.m_..>8......~.]|
+000002c0  c3 6c ad f6 0d 05 1e 41  35 2d 04 15 3c 36 96 00  |.l.....A5-..<6..|
+000002d0  e8 02 b2 01 b8 9f 21 4b  34 85 ef 5e 4c 87 ef 49  |......!K4..^L..I|
+000002e0  df d1 9a b6 b2 bd b8 90  fd 3f 31 93 0c dc c7 18  |.........?1.....|
+000002f0  ff f6 76 bd 5b 74 76 b3  62 87 6a df ff 63 15 d5  |..v.[tv.b.j..c..|
+00000300  94 d5 fe fd 4c 12 df f1  35 07 f1 8a f1 77 7a 35  |....L...5....wz5|
+00000310  cd 99 1d 2a d7 9a 14 03  01 00 01 01 16 03 01 00  |...*............|
+00000320  24 8d db 0c 87 b5 df fd  68 de fe 46 3e e4 41 b5  |$.......h..F>.A.|
+00000330  19 64 68 3c c4 e2 2b 43  50 e4 ee 52 75 34 d3 c1  |.dh<..+CP..Ru4..|
+00000340  51 18 c0 b2 5f                                    |Q..._|
 >>> Flow 4 (server to client)
-00000000  14 03 01 00 01 01 16 03  01 00 24 99 e8 fb 65 f4  |..........$...e.|
-00000010  95 ae 8b 71 cc 5d a4 95  a7 27 98 fd 16 3f 7a 1a  |...q.]...'...?z.|
-00000020  b6 bd bf 0a 58 72 77 97  1f 8e b1 dd 4b 12 12     |....Xrw.....K..|
+00000000  14 03 01 00 01 01 16 03  01 00 24 0b a4 04 46 60  |..........$...F`|
+00000010  15 fb 9a 9f 47 51 6d b4  4b c6 e7 2a 1b 98 b4 8a  |....GQm.K..*....|
+00000020  8a 1a 03 cf f4 16 7d 80  70 27 e5 e8 d5 9f ad     |......}.p'.....|
 >>> Flow 5 (client to server)
-00000000  17 03 01 00 1a 42 70 c0  89 78 12 5c 91 7e 88 2d  |.....Bp..x.\.~.-|
-00000010  2f 8f be f2 f2 12 9d 81  ae 78 08 38 5e 6d 1b 15  |/........x.8^m..|
-00000020  03 01 00 16 1a 64 b1 6f  8a ff d3 63 6a c7 b8 95  |.....d.o...cj...|
-00000030  3d b0 87 bc 62 e9 88 5b  26 bd                    |=...b..[&.|
+00000000  17 03 01 00 1a 6f 84 50  27 c7 f1 aa b0 04 7d 80  |.....o.P'.....}.|
+00000010  6d a7 20 8a 73 cf d9 de  9a d6 f5 e9 36 13 7c 15  |m. .s.......6.|.|
+00000020  03 01 00 16 e8 0b e0 a6  3b 1e 21 24 65 4e 49 b2  |........;.!$eNI.|
+00000030  2d a3 41 2b 98 23 4e d5  4b fd                    |-.A+.#N.K.|
diff --git a/src/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES b/src/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES
index 30c4c6b..937c290 100644
--- a/src/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES
+++ b/src/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES
@@ -1,18 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
 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 1a c0 2f  |.............../|
-00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
-00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
-00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
-00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
-00000070  03 02 01 02 03 ff 01 00  01 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 36  |...../.5.......6|
+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 0e 00  |................|
+00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
+00000080  01 00 00 12 00 00                                 |......|
 >>> Flow 2 (server to client)
-00000000  16 03 01 00 59 02 00 00  55 03 01 53 04 f1 02 b2  |....Y...U..S....|
-00000010  e0 f6 f6 b5 c9 5b 28 d0  5d 58 1b 6f 4e 2b 9d 05  |.....[(.]X.oN+..|
-00000020  2a b9 b4 da 45 cf f3 10  b2 23 44 20 f8 4d 59 05  |*...E....#D .MY.|
-00000030  ad 27 f2 a0 ee 7f ec cc  20 dc e7 a2 1b 07 b3 a5  |.'...... .......|
-00000040  37 7e 61 3d d6 5c 03 cf  cc f5 9b ca c0 09 00 00  |7~a=.\..........|
+00000000  16 03 01 00 59 02 00 00  55 03 01 f5 8f 8d 8e ca  |....Y...U.......|
+00000010  30 6b fe 63 c9 84 57 c0  f1 c8 a5 d8 10 56 14 62  |0k.c..W......V.b|
+00000020  c8 02 b2 89 21 5c 09 67  86 d8 9b 20 dc 3f 55 54  |....!\.g... .?UT|
+00000030  33 29 47 45 d3 e0 87 1a  4b 1b 75 30 89 e0 4d 01  |3)GE....K.u0..M.|
+00000040  a1 6a 46 f7 8f 23 d6 74  fd 90 2f 53 c0 09 00 00  |.jF..#.t../S....|
 00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
 00000060  01 02 0e 0b 00 02 0a 00  02 07 00 02 04 30 82 02  |.............0..|
 00000070  00 30 82 01 62 02 09 00  b8 bf 2d 47 a0 d2 eb f4  |.0..b.....-G....|
@@ -47,20 +48,20 @@
 00000240  13 83 0d 94 06 bb d4 37  7a f6 ec 7a c9 86 2e dd  |.......7z..z....|
 00000250  d7 11 69 7f 85 7c 56 de  fb 31 78 2b e4 c7 78 0d  |..i..|V..1x+..x.|
 00000260  ae cb be 9e 4e 36 24 31  7b 6a 0f 39 95 12 07 8f  |....N6$1{j.9....|
-00000270  2a 16 03 01 00 d5 0c 00  00 d1 03 00 17 41 04 da  |*............A..|
-00000280  5a fd 09 e5 d6 c0 70 41  5e 3a 87 eb df 0c ad 90  |Z.....pA^:......|
-00000290  22 8a 2f 90 81 0c 24 00  68 92 f3 d5 95 2f 93 43  |"./...$.h..../.C|
-000002a0  e9 58 2d 18 28 62 ee 33  5b 21 2e 49 87 21 4d 32  |.X-.(b.3[!.I.!M2|
-000002b0  32 19 b3 ba fe 2d 9a 85  12 0e a1 77 08 06 75 00  |2....-.....w..u.|
-000002c0  8a 30 81 87 02 42 01 91  14 fc 68 74 95 10 4b d4  |.0...B....ht..K.|
-000002d0  67 60 12 46 bb b0 f6 98  77 a3 41 b8 01 5c 49 54  |g`.F....w.A..\IT|
-000002e0  9e 3e 81 e7 97 a3 b9 73  6e 15 74 67 be e5 d9 eb  |.>.....sn.tg....|
-000002f0  8b 87 c5 22 ab ab 58 28  4f d1 b6 80 94 1b f5 f7  |..."..X(O.......|
-00000300  12 43 ef 0a c7 3e 1a 76  02 41 7a 00 49 cb 9f 3b  |.C...>.v.Az.I..;|
-00000310  91 6e 38 58 0a d3 d0 d1  ee 67 f0 b6 5d cd fa 23  |.n8X.....g..]..#|
-00000320  b6 98 43 af 9c 71 90 1e  1d 50 a2 6e 61 5b f2 92  |..C..q...P.na[..|
-00000330  b4 69 73 f2 3b 54 bf 1c  9d 05 19 97 e4 4e 41 9e  |.is.;T.......NA.|
-00000340  f2 9a 76 77 9a 86 43 1f  1f 30 a2 16 03 01 00 04  |..vw..C..0......|
+00000270  2a 16 03 01 00 d5 0c 00  00 d1 03 00 17 41 04 22  |*............A."|
+00000280  8a 47 c6 d3 7a c4 30 a4  8e 41 11 ac b3 2d 2f 45  |.G..z.0..A...-/E|
+00000290  61 54 9b 1f 2e 03 5d 50  eb fc 5b 44 a0 a7 48 78  |aT....]P..[D..Hx|
+000002a0  ce 14 d5 39 a7 c4 ed f5  4d 8f da 9d 71 52 69 70  |...9....M...qRip|
+000002b0  7e 52 29 ad 80 8a 19 ad  4c 5d 1c f1 22 7e 1a 00  |~R).....L].."~..|
+000002c0  8a 30 81 87 02 42 00 97  8b 6d f7 87 c1 a9 a6 55  |.0...B...m.....U|
+000002d0  0f 61 c2 f2 e1 05 26 a8  83 16 1c 0b 69 3b 95 57  |.a....&.....i;.W|
+000002e0  76 5b eb 45 7a bd 6a f1  3e a0 93 49 fa 74 32 fd  |v[.Ez.j.>..I.t2.|
+000002f0  dc 20 3a bb e3 ee 6d b8  56 aa e9 d2 7d 6a ec b7  |. :...m.V...}j..|
+00000300  0a bd aa dc d7 b0 69 65  02 41 4d 19 61 16 d8 5f  |......ie.AM.a.._|
+00000310  1d c1 32 25 15 26 eb 88  5b c1 dd 9a 12 40 fa f1  |..2%.&..[.... at ..|
+00000320  81 5e 7d b8 2b 6e 60 63  1a 9e 86 cb d5 64 96 d4  |.^}.+n`c.....d..|
+00000330  75 fc 02 33 e0 66 60 b2  40 47 cf e6 6d 25 9c 83  |u..3.f`. at G..m%..|
+00000340  23 d3 4b e2 eb ac f1 56  44 f8 3f 16 03 01 00 04  |#.K....VD.?.....|
 00000350  0e 00 00 00                                       |....|
 >>> Flow 3 (client to server)
 00000000  16 03 01 00 46 10 00 00  42 41 04 1e 18 37 ef 0d  |....F...BA...7..|
@@ -68,20 +69,20 @@
 00000020  a7 24 20 3e b2 56 1c ce  97 28 5e f8 2b 2d 4f 9e  |.$ >.V...(^.+-O.|
 00000030  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
 00000040  a6 b5 68 1a 41 03 56 6b  dc 5a 89 14 03 01 00 01  |..h.A.Vk.Z......|
-00000050  01 16 03 01 00 30 88 60  65 b2 d7 51 1f ad 96 56  |.....0.`e..Q...V|
-00000060  4e 0a 20 eb b5 b0 1a dd  4c f6 1a cf d4 5c 47 c4  |N. .....L....\G.|
-00000070  9c 7c a0 36 dd d1 1b 96  91 99 c0 a7 2d 9a 7c 42  |.|.6........-.|B|
-00000080  51 d1 de 87 2b a4                                 |Q...+.|
+00000050  01 16 03 01 00 30 cc 86  f1 7e 6e a8 c9 b5 02 5f  |.....0...~n...._|
+00000060  fb b2 3b ea 74 bf a8 da  e4 6a 69 50 a2 5a 78 4f  |..;.t....jiP.ZxO|
+00000070  35 e1 cc 87 c3 fb 1f 5e  f6 a4 5c 63 cc 59 12 3e  |5......^..\c.Y.>|
+00000080  07 c3 a8 d7 87 ba                                 |......|
 >>> Flow 4 (server to client)
-00000000  14 03 01 00 01 01 16 03  01 00 30 86 6c b5 94 69  |..........0.l..i|
-00000010  2e e0 55 a2 4d a8 63 f2  5b 1f ae 34 21 c8 21 6a  |..U.M.c.[..4!.!j|
-00000020  00 b6 56 ed 4e 2a b0 ff  01 2f da ce a1 c0 41 03  |..V.N*.../....A.|
-00000030  a9 1b 6e 2e e1 88 50 ba  62 14 88                 |..n...P.b..|
+00000000  14 03 01 00 01 01 16 03  01 00 30 e8 b6 20 b9 c1  |..........0.. ..|
+00000010  07 38 38 bb 42 b2 b2 a1  c5 8d 92 62 db 67 ab fc  |.88.B......b.g..|
+00000020  f6 64 3f 71 83 1d a0 86  bb 2d e3 4f 65 d5 44 52  |.d?q.....-.Oe.DR|
+00000030  4d f5 62 80 3c af 95 87  19 7c 20                 |M.b.<....| |
 >>> Flow 5 (client to server)
-00000000  17 03 01 00 20 a6 63 0a  2f a5 dc e1 fb cb 7b 1f  |.... .c./.....{.|
-00000010  f2 da 74 c3 ff e9 f5 8b  9c 5f 0c d3 f7 1f 44 e6  |..t......_....D.|
-00000020  90 13 5c 48 50 17 03 01  00 20 c7 75 b5 ff bc 09  |..\HP.... .u....|
-00000030  34 f2 45 db 0d 22 08 8e  f1 35 cd b6 0f b0 eb 2a  |4.E.."...5.....*|
-00000040  b7 1a d0 8e 14 a4 54 84  f9 dc 15 03 01 00 20 e0  |......T....... .|
-00000050  36 3d aa b3 a9 b4 20 23  ca 9e 8c 5d fc a8 c8 b7  |6=.... #...]....|
-00000060  f5 c2 b6 d0 5a e2 ce a5  7b 68 a0 48 86 95 6a     |....Z...{h.H..j|
+00000000  17 03 01 00 20 bd 65 61  28 e5 ea 1b 81 db 75 92  |.... .ea(.....u.|
+00000010  ad a7 3b 01 a3 23 0e 3b  60 10 8a 1e 04 91 fb 9e  |..;..#.;`.......|
+00000020  7a cf 1f cf 9c 17 03 01  00 20 87 9c dc ed 0d 08  |z........ ......|
+00000030  56 40 23 8b c5 2c d8 7e  42 82 3c 0a c9 f3 77 6d  |V@#..,.~B.<...wm|
+00000040  8d 9a 30 d1 9c c4 ae 04  fb b7 15 03 01 00 20 f7  |..0........... .|
+00000050  f0 12 0d e5 03 c1 80 4e  7e 21 d7 75 55 1c 91 89  |.......N~!.uU...|
+00000060  e7 e1 45 fc 7d d8 fc b1  d0 e7 dc e2 4c ba f4     |..E.}.......L..|
diff --git a/src/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES b/src/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES
index 868f0ce..f8183f1 100644
--- a/src/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES
+++ b/src/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES
@@ -1,18 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
 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 1a c0 2f  |.............../|
-00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
-00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
-00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
-00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
-00000070  03 02 01 02 03 ff 01 00  01 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 36  |...../.5.......6|
+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 0e 00  |................|
+00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
+00000080  01 00 00 12 00 00                                 |......|
 >>> Flow 2 (server to client)
-00000000  16 03 01 00 59 02 00 00  55 03 01 53 04 f1 02 21  |....Y...U..S...!|
-00000010  67 b5 2b 34 fb 62 d7 36  4f cf 68 2e 29 39 d0 28  |g.+4.b.6O.h.)9.(|
-00000020  3a 02 32 82 8f 95 de 62  d6 03 77 20 e6 98 56 cd  |:.2....b..w ..V.|
-00000030  96 24 d1 b9 4d eb 51 19  bb b7 71 f4 9c 29 32 d4  |.$..M.Q...q..)2.|
-00000040  e5 c6 0a 54 e0 4a 20 29  3e bd 06 0d c0 13 00 00  |...T.J )>.......|
+00000000  16 03 01 00 59 02 00 00  55 03 01 5c 69 d0 60 d6  |....Y...U..\i.`.|
+00000010  b3 f4 23 19 5e 3e 26 d8  29 ea c3 94 e4 ed 51 f6  |..#.^>&.).....Q.|
+00000020  58 a2 e3 9c 79 a1 0b 6d  29 90 32 20 23 5b 47 b1  |X...y..m).2 #[G.|
+00000030  8f 22 bc 06 aa ee f7 c3  97 ca 93 df b1 90 7d b4  |."............}.|
+00000040  8c c0 d9 54 35 ca 5b 11  98 37 84 ea c0 13 00 00  |...T5.[..7......|
 00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
 00000060  01 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..............|
@@ -58,40 +59,40 @@
 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 01 00 cb 0c 00  00 c7 03 00 17 41 04 05  |.............A..|
-00000330  45 33 f8 4b e9 96 0e 4a  fd ec 54 76 21 9b 24 8a  |E3.K...J..Tv!.$.|
-00000340  75 0b 80 84 c7 30 2b 22  f0 85 57 a4 a9 79 d6 f6  |u....0+"..W..y..|
-00000350  6d 80 b0 71 d9 66 c9 6c  dd 76 fc 32 d0 c6 bc 52  |m..q.f.l.v.2...R|
-00000360  2f f1 c9 62 17 53 76 ec  be a6 1c 93 f2 b4 5d 00  |/..b.Sv.......].|
-00000370  80 72 d9 20 52 70 7c 03  b1 33 fa 51 23 cd 05 97  |.r. Rp|..3.Q#...|
-00000380  6f d6 89 2f 8d 2e 3a 17  32 eb f2 ff 6b 39 70 5e  |o../..:.2...k9p^|
-00000390  21 41 8d 69 02 c8 9a 17  19 e4 48 9b 51 c3 7f 9b  |!A.i......H.Q...|
-000003a0  8d 4a 83 97 07 0e 30 f1  8b 6b e9 92 12 01 d6 96  |.J....0..k......|
-000003b0  f2 1a a2 10 7f 59 87 16  1a fb 55 67 68 fc 78 c6  |.....Y....Ugh.x.|
-000003c0  57 ac 05 dd f3 6f 77 84  eb ae b0 33 2d 19 2c ba  |W....ow....3-.,.|
-000003d0  b8 ae 9f 95 69 85 95 45  5e 37 f4 17 17 9b 03 c1  |....i..E^7......|
-000003e0  50 b1 36 42 bd 60 5c 8b  d8 b6 f3 c8 34 c8 9d 9d  |P.6B.`\.....4...|
-000003f0  75 16 03 01 00 04 0e 00  00 00                    |u.........|
+00000320  d9 16 03 01 00 cb 0c 00  00 c7 03 00 17 41 04 a6  |.............A..|
+00000330  57 60 8d 63 4e 4d 3f 48  e0 5d ad 9a 9c f7 e6 8c  |W`.cNM?H.]......|
+00000340  00 18 9c eb 34 ea f0 5c  d5 77 3f af 81 a9 50 d9  |....4..\.w?...P.|
+00000350  05 cf b9 bf 88 5c 70 29  24 61 6f d8 77 11 21 57  |.....\p)$ao.w.!W|
+00000360  a0 4d e1 4b 8e 55 06 50  7f a2 30 c1 c2 b9 c6 00  |.M.K.U.P..0.....|
+00000370  80 68 7c e4 1a bc a4 1e  16 b9 3e 4a 59 39 a9 54  |.h|.......>JY9.T|
+00000380  6f c7 17 b2 f5 af b5 73  5b db cc 71 f2 1b aa dc  |o......s[..q....|
+00000390  9d 64 3c 0f 82 e6 da 1a  6b 96 19 e2 f0 15 b0 df  |.d<.....k.......|
+000003a0  8a 2d 96 09 63 52 f6 53  ef 12 d4 3b 35 b7 0b 43  |.-..cR.S...;5..C|
+000003b0  2c 6e 58 4c c8 2f b8 55  84 89 c9 39 81 7a 7a 7d  |,nXL./.U...9.zz}|
+000003c0  88 68 db eb d7 81 aa 2e  b2 25 ba 98 6c 46 b7 85  |.h.......%..lF..|
+000003d0  8a 21 17 b9 36 23 c0 84  94 af 3b 9b 04 5d ec 31  |.!..6#....;..].1|
+000003e0  f5 75 84 d8 77 d7 80 37  ae c3 5c 26 41 f6 72 af  |.u..w..7..\&A.r.|
+000003f0  88 16 03 01 00 04 0e 00  00 00                    |..........|
 >>> Flow 3 (client to server)
 00000000  16 03 01 00 46 10 00 00  42 41 04 1e 18 37 ef 0d  |....F...BA...7..|
 00000010  19 51 88 35 75 71 b5 e5  54 5b 12 2e 8f 09 67 fd  |.Q.5uq..T[....g.|
 00000020  a7 24 20 3e b2 56 1c ce  97 28 5e f8 2b 2d 4f 9e  |.$ >.V...(^.+-O.|
 00000030  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
 00000040  a6 b5 68 1a 41 03 56 6b  dc 5a 89 14 03 01 00 01  |..h.A.Vk.Z......|
-00000050  01 16 03 01 00 30 ca d1  1b 08 27 9b 44 e7 e9 b4  |.....0....'.D...|
-00000060  90 16 4d 30 4e 65 5c 0d  47 ba 46 86 cf c9 80 e7  |..M0Ne\.G.F.....|
-00000070  64 31 f5 a1 9e dc 39 15  d3 be 16 4f c7 90 b6 62  |d1....9....O...b|
-00000080  5d 6d 7f 41 4e 3e                                 |]m.AN>|
+00000050  01 16 03 01 00 30 d2 5b  27 5a f5 64 49 31 d5 aa  |.....0.['Z.dI1..|
+00000060  a3 72 ae c9 af 0b aa 75  af ac f3 45 f4 e3 03 fa  |.r.....u...E....|
+00000070  e8 97 88 7b 51 a9 ae 61  40 c8 11 74 3e d8 9a b6  |...{Q..a at ..t>...|
+00000080  e7 6a 5e 71 84 7e                                 |.j^q.~|
 >>> Flow 4 (server to client)
-00000000  14 03 01 00 01 01 16 03  01 00 30 98 81 24 8e cd  |..........0..$..|
-00000010  b6 48 2f 80 de 8e 24 3c  cd 02 67 80 34 97 d7 92  |.H/...$<..g.4...|
-00000020  78 c2 44 3d 5d 05 eb 88  76 79 46 7a c3 fa ca 73  |x.D=]...vyFz...s|
-00000030  45 82 ad c1 81 00 ca 40  c1 2f 13                 |E...... at ./.|
+00000000  14 03 01 00 01 01 16 03  01 00 30 8d 63 fc 58 2e  |..........0.c.X.|
+00000010  50 f7 60 2c 9f 5a 8e 58  29 6c a6 3a 8d 2b a7 2b  |P.`,.Z.X)l.:.+.+|
+00000020  1c 12 8a 53 3f d5 60 79  12 c3 78 e3 aa 50 15 45  |...S?.`y..x..P.E|
+00000030  07 da 2d c7 a9 c3 45 07  48 00 78                 |..-...E.H.x|
 >>> Flow 5 (client to server)
-00000000  17 03 01 00 20 ee 19 59  67 67 a9 8b db 99 87 50  |.... ..Ygg.....P|
-00000010  01 e2 02 c1 d5 6d 36 79  af aa ec 1b 80 0e b6 5e  |.....m6y.......^|
-00000020  5f fa 03 01 cc 17 03 01  00 20 ec e2 04 b7 3b a5  |_........ ....;.|
-00000030  f2 e0 13 1f 17 48 e7 6e  d3 eb f0 fa 36 ef 6e 2e  |.....H.n....6.n.|
-00000040  fb ea c8 39 c4 5f 4b 28  d4 50 15 03 01 00 20 c7  |...9._K(.P.... .|
-00000050  45 ff fb c7 07 0c d8 0e  35 a3 c5 31 47 b7 03 0e  |E.......5..1G...|
-00000060  14 c8 29 fd 53 70 5f 15  ac d2 1c 4c 69 fb d6     |..).Sp_....Li..|
+00000000  17 03 01 00 20 40 91 8d  e6 95 2f 97 c8 0c 94 5c  |.... @..../....\|
+00000010  46 a7 d3 31 82 3d dc 7e  86 5b dd df 3f 3b 5b 9c  |F..1.=.~.[..?;[.|
+00000020  d5 0d 52 5a 53 17 03 01  00 20 1d 18 da 6b e8 66  |..RZS.... ...k.f|
+00000030  ce 58 18 81 4b 69 8c f6  db 1a ee d0 78 fb f5 68  |.X..Ki......x..h|
+00000040  2c 99 48 47 65 15 2a ae  ff 4e 15 03 01 00 20 68  |,.HGe.*..N.... h|
+00000050  aa 7f 75 33 45 7a 1a 33  18 35 5a 5b 14 b0 f6 83  |..u3Ez.3.5Z[....|
+00000060  97 85 3f b2 dc 78 68 eb  43 ef 92 7f 38 bd f8     |..?..xh.C...8..|
diff --git a/src/crypto/tls/testdata/Client-TLSv10-RSA-RC4 b/src/crypto/tls/testdata/Client-TLSv10-RSA-RC4
index 395d53b..b5deaeb 100644
--- a/src/crypto/tls/testdata/Client-TLSv10-RSA-RC4
+++ b/src/crypto/tls/testdata/Client-TLSv10-RSA-RC4
@@ -1,18 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
 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 1a c0 2f  |.............../|
-00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
-00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
-00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
-00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
-00000070  03 02 01 02 03 ff 01 00  01 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 36  |...../.5.......6|
+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 0e 00  |................|
+00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
+00000080  01 00 00 12 00 00                                 |......|
 >>> Flow 2 (server to client)
-00000000  16 03 01 00 51 02 00 00  4d 03 01 53 04 f1 02 76  |....Q...M..S...v|
-00000010  e8 45 7f 57 f3 42 4b 33  0b 06 fa a6 fa c4 3d 84  |.E.W.BK3......=.|
-00000020  5a 45 dc 93 41 a5 8d 79  6e 8f 11 20 e7 c6 29 2b  |ZE..A..yn.. ..)+|
-00000030  ff 4a 6e 63 67 a6 10 cb  49 19 46 1e 5e 0a d5 70  |.Jncg...I.F.^..p|
-00000040  96 88 9a 32 48 ef c3 4a  45 4c 6d e0 00 05 00 00  |...2H..JELm.....|
+00000000  16 03 01 00 51 02 00 00  4d 03 01 a9 b0 bf 24 3f  |....Q...M.....$?|
+00000010  98 c6 0f 83 23 2b b6 e4  3f d5 5b 10 9a 6f b8 63  |....#+..?.[..o.c|
+00000020  4c 3c d6 4d 05 c0 08 85  f7 72 72 20 ab 85 8c ff  |L<.M.....rr ....|
+00000030  f7 bb 95 ab 69 37 3d b6  79 cb 46 ad 4e 22 e7 c6  |....i7=.y.F.N"..|
+00000040  a5 9b 72 92 32 ff a5 f7  ed dc 30 41 00 05 00 00  |..r.2.....0A....|
 00000050  05 ff 01 00 01 00 16 03  01 02 be 0b 00 02 ba 00  |................|
 00000060  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
 00000070  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
@@ -69,15 +70,15 @@
 00000060  e6 bd 77 82 6f 23 b6 e0  bd a2 92 b7 3a ac e8 56  |..w.o#......:..V|
 00000070  f1 af 54 5e 46 87 e9 3b  33 e7 b8 28 b7 d6 c8 90  |..T^F..;3..(....|
 00000080  35 d4 1c 43 d1 30 6f 55  4e 0a 70 14 03 01 00 01  |5..C.0oUN.p.....|
-00000090  01 16 03 01 00 24 cd c0  68 dc 2e 69 cc c7 5b c5  |.....$..h..i..[.|
-000000a0  3f bd 40 cf a0 0f 41 34  ce 16 37 10 26 c8 3f d1  |?. at ...A4..7.&.?.|
-000000b0  46 3b ad 7b b0 31 f3 c5  36 e7                    |F;.{.1..6.|
+00000090  01 16 03 01 00 24 4d 1d  d7 8c d6 c7 65 a6 ce af  |.....$M.....e...|
+000000a0  e7 59 0d 7e dc d9 96 1c  ed 9c 57 94 84 b8 3f b5  |.Y.~......W...?.|
+000000b0  34 e1 61 a5 61 f3 5d 09  bc ff                    |4.a.a.]...|
 >>> Flow 4 (server to client)
-00000000  14 03 01 00 01 01 16 03  01 00 24 ea 77 6f 3c 42  |..........$.wo<B|
-00000010  12 16 51 de e8 b6 f9 85  06 d9 6d 05 75 50 2b 27  |..Q.......m.uP+'|
-00000020  93 b7 6b 65 e9 14 99 48  53 3e be e4 be 03 5d     |..ke...HS>....]|
+00000000  14 03 01 00 01 01 16 03  01 00 24 13 81 89 61 5c  |..........$...a\|
+00000010  fb 0a 9c a1 4b db 94 6b  8b 41 6e 63 d6 aa db 88  |....K..k.Anc....|
+00000020  03 b7 b5 19 b8 12 cf 5e  17 54 79 2f 03 91 7e     |.......^.Ty/..~|
 >>> Flow 5 (client to server)
-00000000  17 03 01 00 1a 9e ae ca  55 df c4 d9 47 04 55 dd  |........U...G.U.|
-00000010  3b 33 e1 a6 16 6f a1 94  b1 9b 4d 0d cb 6c 3b 15  |;3...o....M..l;.|
-00000020  03 01 00 16 92 5d 76 07  e9 b7 31 29 09 c5 b1 09  |.....]v...1)....|
-00000030  2d 64 3d 85 8d f1 d1 40  54 b8                    |-d=.... at T.|
+00000000  17 03 01 00 1a b3 2b da  ce 45 ec b2 9d 3b 18 d9  |......+..E...;..|
+00000010  7a cb 99 ea ff 4d 91 b5  48 df 6f 8b 2f 85 c7 15  |z....M..H.o./...|
+00000020  03 01 00 16 19 1c 72 74  36 cf 22 0f a0 a7 18 96  |......rt6.".....|
+00000030  3a 67 cb 22 16 f1 a8 7b  57 37                    |:g."...{W7|
diff --git a/src/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES b/src/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES
index 9f941f8..a4a2930 100644
--- a/src/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES
+++ b/src/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES
@@ -1,18 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
 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 1a c0 2f  |.............../|
-00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
-00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
-00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
-00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
-00000070  03 02 01 02 03 ff 01 00  01 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 36  |...../.5.......6|
+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 0e 00  |................|
+00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
+00000080  01 00 00 12 00 00                                 |......|
 >>> Flow 2 (server to client)
-00000000  16 03 02 00 59 02 00 00  55 03 02 53 04 f1 02 1c  |....Y...U..S....|
-00000010  d1 1c 6a 5f 7a 5c 26 69  92 cd ee c3 57 ed 96 90  |..j_z\&i....W...|
-00000020  e3 c5 f1 ee 8b ee 99 5f  46 2c e6 20 c8 50 6a a4  |......._F,. .Pj.|
-00000030  4b 93 e6 da ba 6d d4 87  f6 75 a8 9d 44 db b5 43  |K....m...u..D..C|
-00000040  df 12 57 de a4 f1 bc fb  b8 7a 3f 6a c0 09 00 00  |..W......z?j....|
+00000000  16 03 02 00 59 02 00 00  55 03 02 5a 52 92 23 05  |....Y...U..ZR.#.|
+00000010  58 68 b2 1e 77 a2 a8 16  e9 88 85 ea 38 b3 63 c2  |Xh..w.......8.c.|
+00000020  40 f8 de 37 3c d4 b9 51  11 2d d1 20 12 fd 95 b3  |@..7<..Q.-. ....|
+00000030  2a 54 40 c0 23 3a 4e 4e  f6 7b f8 77 04 6e e7 d7  |*T at .#:NN.{.w.n..|
+00000040  3b 9a 45 32 e0 af df aa  ff bf 78 8b c0 09 00 00  |;.E2......x.....|
 00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
 00000060  02 02 0e 0b 00 02 0a 00  02 07 00 02 04 30 82 02  |.............0..|
 00000070  00 30 82 01 62 02 09 00  b8 bf 2d 47 a0 d2 eb f4  |.0..b.....-G....|
@@ -47,21 +48,21 @@
 00000240  13 83 0d 94 06 bb d4 37  7a f6 ec 7a c9 86 2e dd  |.......7z..z....|
 00000250  d7 11 69 7f 85 7c 56 de  fb 31 78 2b e4 c7 78 0d  |..i..|V..1x+..x.|
 00000260  ae cb be 9e 4e 36 24 31  7b 6a 0f 39 95 12 07 8f  |....N6$1{j.9....|
-00000270  2a 16 03 02 00 d4 0c 00  00 d0 03 00 17 41 04 7b  |*............A.{|
-00000280  c4 00 37 35 51 de c3 f2  a4 95 2c 19 21 3e a6 94  |..75Q.....,.!>..|
-00000290  7b fd 04 d7 b7 1c 56 e6  af 3c ee 36 cb 55 e6 f0  |{.....V..<.6.U..|
-000002a0  e6 24 34 6b 8a 02 66 71  f9 e2 f5 a6 c9 d7 6c dc  |.$4k..fq......l.|
-000002b0  65 59 ff 1c c9 ec a9 8b  07 d6 52 2c 01 3c c3 00  |eY........R,.<..|
-000002c0  89 30 81 86 02 41 74 89  1a 31 72 e6 8b c0 4a ce  |.0...At..1r...J.|
-000002d0  8f 5a 49 a7 52 2d 6d b9  8b 50 17 62 2a 99 d6 3b  |.ZI.R-m..P.b*..;|
-000002e0  02 85 41 4d 34 53 b5 09  bd e3 ac 16 c1 9b e9 83  |..AM4S..........|
-000002f0  cc 83 e3 9c 23 34 67 71  72 d4 05 a2 34 f7 08 29  |....#4gqr...4..)|
-00000300  62 43 2e cc bc 08 01 02  41 59 de 5a d0 dd d7 6b  |bC......AY.Z...k|
-00000310  db 9c 35 29 79 f8 96 91  56 74 1f 18 7b ee 25 83  |..5)y...Vt..{.%.|
-00000320  f2 37 0e 77 ab 38 fb 5e  04 0b 09 d9 b4 1f 3f be  |.7.w.8.^......?.|
-00000330  2e e3 60 e3 96 f3 29 c1  6d 8f 56 1b fd 62 14 48  |..`...).m.V..b.H|
-00000340  e3 d9 2a ea 2f be 93 d0  8b 31 16 03 02 00 04 0e  |..*./....1......|
-00000350  00 00 00                                          |...|
+00000270  2a 16 03 02 00 d5 0c 00  00 d1 03 00 17 41 04 c3  |*............A..|
+00000280  55 86 65 95 83 02 4b 69  6e 95 f4 52 46 83 21 86  |U.e...Kin..RF.!.|
+00000290  9e 99 cf 81 d9 b8 20 7a  87 b3 07 48 14 04 20 d9  |...... z...H.. .|
+000002a0  6c 2e 22 5a b5 b4 ef de  15 b3 08 ef 1e 18 ea 67  |l."Z...........g|
+000002b0  eb 45 fd e1 27 43 ed 41  ea 05 7e f3 f9 ee 23 00  |.E..'C.A..~...#.|
+000002c0  8a 30 81 87 02 42 00 b0  9c 06 85 83 b2 bf 42 22  |.0...B........B"|
+000002d0  6e 57 7a 31 fe a9 d9 28  be 0a a9 80 49 a2 14 c1  |nWz1...(....I...|
+000002e0  a9 99 76 b7 f9 76 d0 3c  d3 0c c7 42 34 d7 94 a9  |..v..v.<...B4...|
+000002f0  15 66 7e 6b 83 6e b2 b4  5b 22 c9 4e a0 96 db 2b  |.f~k.n..[".N...+|
+00000300  ad 77 33 1e 4a 5c 2f 2e  02 41 26 0c 1a 5a b4 07  |.w3.J\/..A&..Z..|
+00000310  95 99 ec 0b 5b 2e bb db  0e d5 26 c4 b3 eb c2 30  |....[.....&....0|
+00000320  b0 7b c1 07 97 a0 99 3f  db 4e b0 c4 b8 bb 5e be  |.{.....?.N....^.|
+00000330  2a e4 b3 a4 5c ad d1 d7  7a 2d fb ae 73 ee 0c 1e  |*...\...z-..s...|
+00000340  3b 64 e1 74 14 bc c0 1e  8b f3 26 16 03 02 00 04  |;d.t......&.....|
+00000350  0e 00 00 00                                       |....|
 >>> Flow 3 (client to server)
 00000000  16 03 02 00 46 10 00 00  42 41 04 1e 18 37 ef 0d  |....F...BA...7..|
 00000010  19 51 88 35 75 71 b5 e5  54 5b 12 2e 8f 09 67 fd  |.Q.5uq..T[....g.|
@@ -69,21 +70,21 @@
 00000030  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
 00000040  a6 b5 68 1a 41 03 56 6b  dc 5a 89 14 03 02 00 01  |..h.A.Vk.Z......|
 00000050  01 16 03 02 00 40 00 00  00 00 00 00 00 00 00 00  |..... at ..........|
-00000060  00 00 00 00 00 00 b6 98  a2 a9 48 34 12 6b 0a 94  |..........H4.k..|
-00000070  89 fc 38 04 63 5a 6f 63  36 3e d9 35 12 64 8c 28  |..8.cZoc6>.5.d.(|
-00000080  99 a6 cf 2e 57 e3 14 6d  0a 8a ab f0 a6 58 37 7c  |....W..m.....X7||
-00000090  96 04 d3 71 bc d4                                 |...q..|
+00000060  00 00 00 00 00 00 33 07  8a af e1 94 ef f9 08 3a  |......3........:|
+00000070  33 5f b3 e6 42 07 85 af  40 e2 8b 34 53 62 1a 10  |3_..B... at ..4Sb..|
+00000080  bb 08 7e 75 d4 21 12 2d  54 87 33 1c 4e 13 27 72  |..~u.!.-T.3.N.'r|
+00000090  3f 9e 9f cc de 47                                 |?....G|
 >>> Flow 4 (server to client)
-00000000  14 03 02 00 01 01 16 03  02 00 40 c5 01 c9 0a b0  |.......... at .....|
-00000010  d8 ca 5e c1 19 dc 37 6c  2e a0 b3 11 a8 87 65 5a  |..^...7l......eZ|
-00000020  09 41 b9 fe 53 c4 c9 76  97 6d 7f ac c0 be d2 07  |.A..S..v.m......|
-00000030  84 e5 5b 78 37 34 ee da  3b cb 3e 82 52 79 91 44  |..[x74..;.>.Ry.D|
-00000040  b4 e4 1c ec 3a c0 c0 9d  cd ff 13                 |....:......|
+00000000  14 03 02 00 01 01 16 03  02 00 40 4f 47 0d 43 54  |.......... at OG.CT|
+00000010  50 69 3a c8 21 a6 6e 28  78 cc 01 b4 5d eb f7 2b  |Pi:.!.n(x...]..+|
+00000020  8b 7e 26 6e cf 56 98 65  ad bf 0f a0 b4 67 13 70  |.~&n.V.e.....g.p|
+00000030  de b5 b5 91 df d6 df 8c  53 c6 54 3d 5d 98 e4 25  |........S.T=]..%|
+00000040  47 a0 0f 91 c7 08 96 17  48 bd 0f                 |G.......H..|
 >>> Flow 5 (client to server)
 00000000  17 03 02 00 30 00 00 00  00 00 00 00 00 00 00 00  |....0...........|
-00000010  00 00 00 00 00 46 60 13  39 2b 2f 72 95 ed 0e aa  |.....F`.9+/r....|
-00000020  69 6e b4 64 3e 83 43 d0  f9 7f 37 7c 1d b9 ce 11  |in.d>.C...7|....|
-00000030  d9 41 66 60 6d 15 03 02  00 30 00 00 00 00 00 00  |.Af`m....0......|
-00000040  00 00 00 00 00 00 00 00  00 00 b1 26 d0 5d 08 98  |...........&.]..|
-00000050  eb 28 42 74 31 58 42 95  c5 ad 1a 92 0a f5 5f ed  |.(Bt1XB......._.|
-00000060  45 98 e0 90 e5 a3 b6 8b  8d 18                    |E.........|
+00000010  00 00 00 00 00 4e fe 12  d7 4b d7 3f 86 5a 2c f6  |.....N...K.?.Z,.|
+00000020  86 03 2a bd 1a 98 d7 bb  9f 59 6c 6d 4d 57 b0 50  |..*......YlmMW.P|
+00000030  d6 97 7e d4 b6 15 03 02  00 30 00 00 00 00 00 00  |..~......0......|
+00000040  00 00 00 00 00 00 00 00  00 00 65 8b b5 ae 86 90  |..........e.....|
+00000050  00 4e 1e 3f bc ac ed 49  f4 5e 73 49 e6 d8 37 83  |.N.?...I.^sI..7.|
+00000060  cf 4f e5 7b 5e c9 1d c8  c9 dc                    |.O.{^.....|
diff --git a/src/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES b/src/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES
index fc72339..103f1d8 100644
--- a/src/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES
+++ b/src/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES
@@ -1,18 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
 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 1a c0 2f  |.............../|
-00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
-00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
-00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
-00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
-00000070  03 02 01 02 03 ff 01 00  01 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 36  |...../.5.......6|
+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 0e 00  |................|
+00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
+00000080  01 00 00 12 00 00                                 |......|
 >>> Flow 2 (server to client)
-00000000  16 03 02 00 59 02 00 00  55 03 02 53 04 f1 02 fe  |....Y...U..S....|
-00000010  17 8b 79 ad 93 2e d3 89  66 9b 5d 9b b4 03 3e ba  |..y.....f.]...>.|
-00000020  65 2a f1 55 f9 3c 33 de  2c a7 47 20 fa 4f 82 11  |e*.U.<3.,.G .O..|
-00000030  96 81 d0 70 2e 65 b3 68  2e 3a 6d d7 6c 74 22 33  |...p.e.h.:m.lt"3|
-00000040  d4 ae 6c aa c8 f0 c7 20  8b 10 21 e7 c0 13 00 00  |..l.... ..!.....|
+00000000  16 03 02 00 59 02 00 00  55 03 02 e3 ed 49 27 a3  |....Y...U....I'.|
+00000010  28 c5 8c 30 27 c2 ed 57  9b f7 37 a1 6d 2b 88 c2  |(..0'..W..7.m+..|
+00000020  df a7 2d 01 01 00 9a 09  da c2 1f 20 ee 33 87 03  |..-........ .3..|
+00000030  28 93 1c 16 99 5b b1 e0  bf 87 e8 77 4a 72 c9 92  |(....[.....wJr..|
+00000040  8a bc b2 3e 24 e1 f6 e8  f4 3f a2 24 c0 13 00 00  |...>$....?.$....|
 00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
 00000060  02 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..............|
@@ -58,20 +59,20 @@
 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 02 00 cb 0c 00  00 c7 03 00 17 41 04 26  |.............A.&|
-00000330  56 18 02 e5 66 d4 aa 24  7e ae 39 e5 ca 78 6c c1  |V...f..$~.9..xl.|
-00000340  90 02 c3 c4 ad 79 2c 47  a8 bf 54 e2 8a 22 b6 ef  |.....y,G..T.."..|
-00000350  99 d4 7a 7f 8f 78 6a 78  4e 14 2a 16 0d bb 54 38  |..z..xjxN.*...T8|
-00000360  59 1f 7a 53 1b c7 73 10  89 4b de c3 66 39 7a 00  |Y.zS..s..K..f9z.|
-00000370  80 3a 88 38 c8 15 07 ab  2f 0f 0d cb 19 07 84 ac  |.:.8..../.......|
-00000380  24 fd 8b d2 9d 05 45 c6  11 c3 d6 84 58 95 5a 08  |$.....E.....X.Z.|
-00000390  b9 a4 2c c0 41 4e 34 e0  b2 24 98 94 b7 67 27 50  |..,.AN4..$...g'P|
-000003a0  ba 82 35 28 a9 bf 16 ee  e3 7b 49 9c 4c 81 80 69  |..5(.....{I.L..i|
-000003b0  d7 aa ed 46 ea 9a 68 c4  97 b7 11 d4 35 91 74 5e  |...F..h.....5.t^|
-000003c0  54 10 34 83 cd c4 06 18  49 7d 7a 28 c9 53 06 73  |T.4.....I}z(.S.s|
-000003d0  00 7b 04 b6 d8 36 a7 4b  67 7f 81 30 94 de 40 4d  |.{...6.Kg..0.. at M|
-000003e0  18 f8 c4 b7 02 00 44 8e  bc 72 06 24 53 15 74 72  |......D..r.$S.tr|
-000003f0  8d 16 03 02 00 04 0e 00  00 00                    |..........|
+00000320  d9 16 03 02 00 cb 0c 00  00 c7 03 00 17 41 04 f7  |.............A..|
+00000330  75 c1 b9 58 a0 7d 50 48  e9 85 79 db 89 76 4c d7  |u..X.}PH..y..vL.|
+00000340  84 5b 94 9a 15 d8 92 32  74 d2 3e ce 76 5a bd 0e  |.[.....2t.>.vZ..|
+00000350  24 e7 a6 d0 77 5d 8e 3d  9f 94 7a ea 15 46 3c 5c  |$...w].=..z..F<\|
+00000360  61 28 76 4a ff 81 97 2b  3a 0c b7 aa b4 0e cb 00  |a(vJ...+:.......|
+00000370  80 19 00 a8 fe 0a ea 35  30 51 a3 77 37 08 68 10  |.......50Q.w7.h.|
+00000380  5a e9 07 2d 83 67 77 4c  3a 25 14 1c 5b c1 2e 80  |Z..-.gwL:%..[...|
+00000390  30 6d ba 26 c1 f9 c6 3e  fc 55 34 8c d2 9f 2b a6  |0m.&...>.U4...+.|
+000003a0  46 0c 9d 58 2c 9c 2b ce  6f 03 d7 49 4e df 21 ce  |F..X,.+.o..IN.!.|
+000003b0  3f 8b 19 fe 3e 71 23 51  c3 ec 30 c8 3e 3c 3c 50  |?...>q#Q..0.><<P|
+000003c0  da 08 52 c0 10 9f e3 4a  be e0 97 aa de 5e 13 22  |..R....J.....^."|
+000003d0  b2 77 ee 5d 2d d4 ff fb  7f c3 1e e7 51 fe fc 4b  |.w.]-.......Q..K|
+000003e0  56 5b 8f 50 ad cc 34 7a  a9 dd 24 0a d0 c7 b9 bf  |V[.P..4z..$.....|
+000003f0  1a 16 03 02 00 04 0e 00  00 00                    |..........|
 >>> Flow 3 (client to server)
 00000000  16 03 02 00 46 10 00 00  42 41 04 1e 18 37 ef 0d  |....F...BA...7..|
 00000010  19 51 88 35 75 71 b5 e5  54 5b 12 2e 8f 09 67 fd  |.Q.5uq..T[....g.|
@@ -79,21 +80,21 @@
 00000030  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
 00000040  a6 b5 68 1a 41 03 56 6b  dc 5a 89 14 03 02 00 01  |..h.A.Vk.Z......|
 00000050  01 16 03 02 00 40 00 00  00 00 00 00 00 00 00 00  |..... at ..........|
-00000060  00 00 00 00 00 00 8a 87  81 38 35 c0 4c bb f8 12  |.........85.L...|
-00000070  fa 75 04 cd 1e 3a 61 96  93 c8 fb 07 d1 6d b4 55  |.u...:a......m.U|
-00000080  0f b5 0f 07 35 0a 96 ce  5c 6f 24 62 d3 68 e4 b0  |....5...\o$b.h..|
-00000090  5d be 81 37 c2 9c                                 |]..7..|
+00000060  00 00 00 00 00 00 1e 0b  cd 40 fa 0f ed fa 55 74  |......... at ....Ut|
+00000070  4e ad 10 d1 b5 e1 41 8c  c0 93 81 38 f3 83 f1 37  |N.....A....8...7|
+00000080  6a d4 6c ea ba 5b 9e 38  d3 c1 bb 41 45 fb f0 48  |j.l..[.8...AE..H|
+00000090  c1 06 31 64 e0 65                                 |..1d.e|
 >>> Flow 4 (server to client)
-00000000  14 03 02 00 01 01 16 03  02 00 40 66 36 8d f8 8c  |.......... at f6...|
-00000010  7f db 38 e8 39 df f8 2f  cb 88 9c 14 d9 89 10 b4  |..8.9../........|
-00000020  be 59 88 d7 f3 73 62 af  a3 42 66 6e 74 38 64 9f  |.Y...sb..Bfnt8d.|
-00000030  16 79 09 d7 14 7e 91 8a  70 73 63 28 30 58 fe cc  |.y...~..psc(0X..|
-00000040  42 45 d6 37 fb 9e 8c c1  01 af 34                 |BE.7......4|
+00000000  14 03 02 00 01 01 16 03  02 00 40 17 d1 79 f8 e0  |.......... at ..y..|
+00000010  d4 40 15 85 df 4d a6 d5  60 90 1f d6 52 58 e7 ae  |. at ...M..`...RX..|
+00000020  05 eb a2 ea ed c9 be ae  b5 54 39 de 05 66 27 67  |.........T9..f'g|
+00000030  59 07 03 e7 10 f9 3f da  d8 85 8b 2f 7b 33 9f f5  |Y.....?..../{3..|
+00000040  43 50 b9 9c 6e dd 01 ae  d8 c9 1d                 |CP..n......|
 >>> Flow 5 (client to server)
 00000000  17 03 02 00 30 00 00 00  00 00 00 00 00 00 00 00  |....0...........|
-00000010  00 00 00 00 00 31 0b e3  9d 2a 05 83 19 7d 10 36  |.....1...*...}.6|
-00000020  23 dc da fe 00 ab d3 aa  8f ce 28 5f 08 fd b7 59  |#.........(_...Y|
-00000030  1e 00 2e 25 5a 15 03 02  00 30 00 00 00 00 00 00  |...%Z....0......|
-00000040  00 00 00 00 00 00 00 00  00 00 10 91 fd fa 59 07  |..............Y.|
-00000050  df 2c 92 25 15 7b 7c 83  44 89 0d 4f 65 43 99 2e  |.,.%.{|.D..OeC..|
-00000060  41 5d 51 c9 09 89 ed 02  08 bc                    |A]Q.......|
+00000010  00 00 00 00 00 65 81 63  71 55 1c 46 8a 60 46 d9  |.....e.cqU.F.`F.|
+00000020  7d 71 a2 62 b8 a8 3b 06  3d a2 f4 53 a4 46 a8 9e  |}q.b..;.=..S.F..|
+00000030  b7 89 8a 42 ce 15 03 02  00 30 00 00 00 00 00 00  |...B.....0......|
+00000040  00 00 00 00 00 00 00 00  00 00 7a 78 a4 e7 2f 40  |..........zx../@|
+00000050  df 42 9b 76 7a 45 0a 86  40 af 3c 40 c6 69 ba e1  |.B.vzE.. at .<@.i..|
+00000060  23 82 fa 44 fd 73 fc 5b  f7 b9                    |#..D.s.[..|
diff --git a/src/crypto/tls/testdata/Client-TLSv11-RSA-RC4 b/src/crypto/tls/testdata/Client-TLSv11-RSA-RC4
index f7be3f7..729391f 100644
--- a/src/crypto/tls/testdata/Client-TLSv11-RSA-RC4
+++ b/src/crypto/tls/testdata/Client-TLSv11-RSA-RC4
@@ -1,18 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
 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 1a c0 2f  |.............../|
-00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
-00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
-00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
-00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
-00000070  03 02 01 02 03 ff 01 00  01 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 36  |...../.5.......6|
+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 0e 00  |................|
+00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
+00000080  01 00 00 12 00 00                                 |......|
 >>> Flow 2 (server to client)
-00000000  16 03 02 00 51 02 00 00  4d 03 02 53 04 f1 02 d4  |....Q...M..S....|
-00000010  69 65 aa 96 3d 42 96 eb  9e 7d 8a 18 af 4c 7c 5d  |ie..=B...}...L|]|
-00000020  fb 97 5f da 94 62 13 69  1f 66 06 20 aa 52 e3 08  |.._..b.i.f. .R..|
-00000030  35 0a 87 d5 ef 93 49 ab  1a 74 dd 90 bd 69 70 d1  |5.....I..t...ip.|
-00000040  e9 f1 44 17 3a dc 33 98  f5 e5 ab 93 00 05 00 00  |..D.:.3.........|
+00000000  16 03 02 00 51 02 00 00  4d 03 02 7e 38 ae 3c 50  |....Q...M..~8.<P|
+00000010  03 96 3d 54 2f cd 86 21  98 7f 87 43 d8 58 aa a3  |..=T/..!...C.X..|
+00000020  d5 9f e7 25 a6 ab 34 7f  10 5f 99 20 56 c5 a8 dd  |...%..4.._. V...|
+00000030  37 17 0d 51 f1 0d c4 4e  76 0f 01 26 56 c9 0c 20  |7..Q...Nv..&V.. |
+00000040  28 ef cd ac 38 ea d3 7f  6f aa 7c b8 00 05 00 00  |(...8...o.|.....|
 00000050  05 ff 01 00 01 00 16 03  02 02 be 0b 00 02 ba 00  |................|
 00000060  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
 00000070  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
@@ -69,15 +70,15 @@
 00000060  e6 bd 77 82 6f 23 b6 e0  bd a2 92 b7 3a ac e8 56  |..w.o#......:..V|
 00000070  f1 af 54 5e 46 87 e9 3b  33 e7 b8 28 b7 d6 c8 90  |..T^F..;3..(....|
 00000080  35 d4 1c 43 d1 30 6f 55  4e 0a 70 14 03 02 00 01  |5..C.0oUN.p.....|
-00000090  01 16 03 02 00 24 07 9f  dc df 2d c3 a6 88 06 28  |.....$....-....(|
-000000a0  21 e0 e0 d3 31 99 fc 89  b8 82 6e 95 f4 4b 9e e2  |!...1.....n..K..|
-000000b0  d9 36 5c 14 ce d7 db e2  78 4e                    |.6\.....xN|
+00000090  01 16 03 02 00 24 b9 df  85 a1 6d a7 14 b5 bc f5  |.....$....m.....|
+000000a0  c2 1d 40 fc 1e 19 f2 36  2d ec 6b 59 c5 6d ae c7  |.. at ....6-.kY.m..|
+000000b0  1c ad 7e a3 5b 4d 12 e5  58 5a                    |..~.[M..XZ|
 >>> Flow 4 (server to client)
-00000000  14 03 02 00 01 01 16 03  02 00 24 81 72 75 80 d4  |..........$.ru..|
-00000010  1b 1a 32 00 89 bf 9e 79  30 b9 6b 67 e0 8e c7 eb  |..2....y0.kg....|
-00000020  73 f2 e4 93 51 65 9b 5f  91 b1 b4 b1 f7 44 76     |s...Qe._.....Dv|
+00000000  14 03 02 00 01 01 16 03  02 00 24 a3 f3 22 a8 32  |..........$..".2|
+00000010  63 c3 88 5c 0f fb 2d 47  21 0d 62 e2 db aa ed ae  |c..\..-G!.b.....|
+00000020  b6 5f e3 c8 98 fc 91 5e  04 83 cf c3 21 17 ce     |._.....^....!..|
 >>> Flow 5 (client to server)
-00000000  17 03 02 00 1a b2 91 39  63 c0 38 3c 4d 25 fd 14  |.......9c.8<M%..|
-00000010  b9 b6 e1 23 21 b4 8d 17  9e 1f d8 33 92 69 c2 15  |...#!......3.i..|
-00000020  03 02 00 16 4b 10 25 4d  9d 09 c2 11 96 be f7 5b  |....K.%M.......[|
-00000030  c2 9b 99 fd 1f 8e af 0f  2c 51                    |........,Q|
+00000000  17 03 02 00 1a f1 e4 46  c7 14 91 4b c6 25 fd aa  |.......F...K.%..|
+00000010  5d dd 3f 61 ac 9c 79 68  bc e6 0f a1 e4 f3 73 15  |].?a..yh......s.|
+00000020  03 02 00 16 6b 8d 23 3c  99 b4 c2 23 3c 27 fd 41  |....k.#<...#<'.A|
+00000030  cc 04 e5 fc e7 f9 d9 81  0a b8                    |..........|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ALPN b/src/crypto/tls/testdata/Client-TLSv12-ALPN
index f09a4f1..9ecb065 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-ALPN
+++ b/src/crypto/tls/testdata/Client-TLSv12-ALPN
@@ -1,20 +1,20 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 8d 01 00 00  89 03 03 00 00 00 00 00  |................|
+00000000  16 03 01 00 99 01 00 00  95 03 03 00 00 00 00 00  |................|
 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 1a c0 2f  |.............../|
-00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
-00000040  00 2f 00 35 c0 12 00 0a  01 00 00 46 33 74 00 00  |./.5.......F3t..|
-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 00 10  |................|
-00000080  00 10 00 0e 06 70 72 6f  74 6f 32 06 70 72 6f 74  |.....proto2.prot|
-00000090  6f 31                                             |o1|
+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 4e  |...../.5.......N|
+00000050  33 74 00 00 00 05 00 05  01 00 00 00 00 00 0a 00  |3t..............|
+00000060  08 00 06 00 17 00 18 00  19 00 0b 00 02 01 00 00  |................|
+00000070  0d 00 0e 00 0c 04 01 04  03 05 01 05 03 02 01 02  |................|
+00000080  03 ff 01 00 01 00 00 10  00 10 00 0e 06 70 72 6f  |.............pro|
+00000090  74 6f 32 06 70 72 6f 74  6f 31 00 12 00 00        |to2.proto1....|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 66 02 00 00  62 03 03 77 a9 7d 9c 4b  |....f...b..w.}.K|
-00000010  69 65 aa dc 95 cb 78 08  3d d2 1a 0a 45 69 23 73  |ie....x.=...Ei#s|
-00000020  4f 41 4f 24 12 2e 57 47  b7 53 64 20 82 9a f8 e7  |OAO$..WG.Sd ....|
-00000030  79 f8 13 2c 9d cd b5 cb  cb 9a 95 56 0e e9 cb a8  |y..,.......V....|
-00000040  e4 a2 8a d6 bc dc fa 25  b3 57 cc cf c0 2f 00 00  |.......%.W.../..|
+00000000  16 03 03 00 66 02 00 00  62 03 03 56 83 34 0f 9e  |....f...b..V.4..|
+00000010  dd 02 1c 4f 4f 09 d0 2c  df e6 c1 d2 4a c0 6a e7  |...OO..,....J.j.|
+00000020  1e 65 51 c2 42 01 05 70  4a 6c 97 20 0f a8 fb d8  |.eQ.B..pJl. ....|
+00000030  2f 0f 75 21 17 f8 dd 63  28 4a 18 f6 b1 e5 6f 7c  |/.u!...c(J....o||
+00000040  1d 09 d4 13 bf 66 3a bd  c5 48 14 fc c0 2f 00 00  |.....f:..H.../..|
 00000050  1a ff 01 00 01 00 00 0b  00 04 03 00 01 02 00 10  |................|
 00000060  00 09 00 07 06 70 72 6f  74 6f 31 16 03 03 02 be  |.....proto1.....|
 00000070  0b 00 02 ba 00 02 b7 00  02 b4 30 82 02 b0 30 82  |..........0...0.|
@@ -61,19 +61,19 @@
 00000300  b6 d8 c9 75 90 96 8c 0f  52 98 b5 cd 98 1f 89 20  |...u....R...... |
 00000310  5f f2 a0 1c a3 1b 96 94  dd a9 fd 57 e9 70 e8 26  |_..........W.p.&|
 00000320  6d 71 99 9b 26 6e 38 50  29 6c 90 a7 bd d9 16 03  |mq..&n8P)l......|
-00000330  03 00 cd 0c 00 00 c9 03  00 17 41 04 1b 42 c3 ae  |..........A..B..|
-00000340  44 19 d3 84 7c 6c 98 cb  b9 22 a2 67 63 95 aa cc  |D...|l...".gc...|
-00000350  bd e4 1e f8 08 e6 60 f3  bc 83 9f 81 da 9c 1c 8c  |......`.........|
-00000360  ff 6f f4 3e 1e e5 3b f6  49 61 f9 70 43 7f c1 69  |.o.>..;.Ia.pC..i|
-00000370  de 73 98 4b bd 5c c3 78  24 18 a8 ec 04 01 00 80  |.s.K.\.x$.......|
-00000380  70 d2 5b e1 39 cf 4d 54  de d2 74 4e 5e a8 b3 ca  |p.[.9.MT..tN^...|
-00000390  e1 f2 4e 76 3c 77 8b ef  f7 d1 df b9 ad c1 70 39  |..Nv<w........p9|
-000003a0  c7 a3 1e 0f 7b 6c 78 2e  c1 86 d2 67 36 d8 25 e0  |....{lx....g6.%.|
-000003b0  e8 e5 cc 35 a2 96 a1 b4  b7 06 68 1e aa c7 06 97  |...5......h.....|
-000003c0  b7 c2 83 ce c0 17 dd 4f  9e 6f 7a bd cd c7 6e 7f  |.......O.oz...n.|
-000003d0  cb 80 d1 7d 06 2d f9 f1  fb 5f cc bb d8 62 5b f0  |...}.-..._...b[.|
-000003e0  27 12 57 d5 9b 55 aa 55  4b 9a 5a f6 a5 aa c1 82  |'.W..U.UK.Z.....|
-000003f0  39 11 6b dc 83 7f a8 47  28 5a 0f 3d 3f 0f c2 22  |9.k....G(Z.=?.."|
+00000330  03 00 cd 0c 00 00 c9 03  00 17 41 04 85 b7 f7 7c  |..........A....||
+00000340  49 4e 97 14 07 51 bc 56  2d 3f cf 1d 29 08 ac 6a  |IN...Q.V-?..)..j|
+00000350  b4 e7 0d 62 d8 fd 4d 03  29 0d f8 6c 36 6f 4d 5f  |...b..M.)..l6oM_|
+00000360  b7 5a 8e 37 3e c2 d9 dc  f4 15 52 e9 87 71 0f e5  |.Z.7>.....R..q..|
+00000370  4e a6 88 0e 54 35 e0 8b  50 91 e1 c4 04 01 00 80  |N...T5..P.......|
+00000380  51 eb f8 d6 52 ba f5 b5  0a 22 5f 91 fe f7 ee 43  |Q...R...."_....C|
+00000390  f8 af 52 b6 27 2c fc 14  e2 fb 41 61 ff 7c b9 be  |..R.',....Aa.|..|
+000003a0  f9 78 be dc 18 32 8c 4d  ef 46 c0 5a a7 91 6a 1b  |.x...2.M.F.Z..j.|
+000003b0  47 78 46 39 47 81 8a 2d  b4 cb fd bb 44 3e a7 b7  |GxF9G..-....D>..|
+000003c0  cc 4e df 17 7b 2b 38 49  fa 9d 9f 4e cd ed f2 16  |.N..{+8I...N....|
+000003d0  03 d9 68 cf c9 5a 08 32  f8 ed 02 30 54 61 f6 c0  |..h..Z.2...0Ta..|
+000003e0  f6 78 bc ad 04 9c 8e 90  7d 3d f5 35 86 aa 6e e9  |.x......}=.5..n.|
+000003f0  a2 9a d3 86 27 9f 2d 6e  ea 6e ad 82 0e aa ef 97  |....'.-n.n......|
 00000400  16 03 03 00 04 0e 00 00  00                       |.........|
 >>> Flow 3 (client to server)
 00000000  16 03 03 00 46 10 00 00  42 41 04 1e 18 37 ef 0d  |....F...BA...7..|
@@ -81,17 +81,17 @@
 00000020  a7 24 20 3e b2 56 1c ce  97 28 5e f8 2b 2d 4f 9e  |.$ >.V...(^.+-O.|
 00000030  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
 00000040  a6 b5 68 1a 41 03 56 6b  dc 5a 89 14 03 03 00 01  |..h.A.Vk.Z......|
-00000050  01 16 03 03 00 28 00 00  00 00 00 00 00 00 35 9d  |.....(........5.|
-00000060  92 e8 bf df 7f a7 77 1b  cf 03 2a bf e2 6c 62 2b  |......w...*..lb+|
-00000070  26 f0 fb 93 d3 df fd 55  84 d3 ed 88 31 cb        |&......U....1.|
+00000050  01 16 03 03 00 28 00 00  00 00 00 00 00 00 47 18  |.....(........G.|
+00000060  39 03 93 d9 5b 27 29 70  52 68 15 79 f2 60 e6 58  |9...[')pRh.y.`.X|
+00000070  d9 98 cd ce a1 8f 4d ee  2c f0 34 9f fa 73        |......M.,.4..s|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 28 c8 c0 78 09 73  |..........(..x.s|
-00000010  58 41 73 66 88 cf db f3  fe c6 57 ab 45 be 2e d8  |XAsf......W.E...|
-00000020  4e e5 ff 42 57 13 74 d2  cc c2 62 07 39 8b 06 46  |N..BW.t...b.9..F|
-00000030  1d 8f 88                                          |...|
+00000000  14 03 03 00 01 01 16 03  03 00 28 39 76 15 70 f1  |..........(9v.p.|
+00000010  73 c9 9a 1e 76 40 bc de  de 49 be 3e 10 4d 6a 42  |s...v at ...I.>.MjB|
+00000020  1b 9b bd 07 6b 19 ff f9  2c 19 3c c8 e7 06 fa c8  |....k...,.<.....|
+00000030  3d 52 b4                                          |=R.|
 >>> Flow 5 (client to server)
-00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 10 c3 5f  |..............._|
-00000010  3f c8 92 6c 7a a7 23 05  f3 d8 31 20 01 52 f1 99  |?..lz.#...1 .R..|
-00000020  33 c1 2a 15 03 03 00 1a  00 00 00 00 00 00 00 02  |3.*.............|
-00000030  cc ef eb 78 e4 e1 9d 90  05 6d 95 ac f2 49 ba 8e  |...x.....m...I..|
-00000040  6b 8d                                             |k.|
+00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 14 96 ec  |................|
+00000010  f4 bb ae 45 81 0c 39 10  e2 3a 91 51 04 2c 01 a8  |...E..9..:.Q.,..|
+00000020  8b a3 25 15 03 03 00 1a  00 00 00 00 00 00 00 02  |..%.............|
+00000030  fe 1a 53 01 17 ad a1 30  0a 73 17 9f 39 b4 30 ac  |..S....0.s..9.0.|
+00000040  91 ee                                             |..|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ALPN-NoMatch b/src/crypto/tls/testdata/Client-TLSv12-ALPN-NoMatch
index f24a70c..a22ffae 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-ALPN-NoMatch
+++ b/src/crypto/tls/testdata/Client-TLSv12-ALPN-NoMatch
@@ -1,19 +1,20 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 86 01 00 00  82 03 03 00 00 00 00 00  |................|
+00000000  16 03 01 00 92 01 00 00  8e 03 03 00 00 00 00 00  |................|
 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 1a c0 2f  |.............../|
-00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
-00000040  00 2f 00 35 c0 12 00 0a  01 00 00 3f 33 74 00 00  |./.5.......?3t..|
-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 00 10  |................|
-00000080  00 09 00 07 06 70 72 6f  74 6f 33                 |.....proto3|
+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 47  |...../.5.......G|
+00000050  33 74 00 00 00 05 00 05  01 00 00 00 00 00 0a 00  |3t..............|
+00000060  08 00 06 00 17 00 18 00  19 00 0b 00 02 01 00 00  |................|
+00000070  0d 00 0e 00 0c 04 01 04  03 05 01 05 03 02 01 02  |................|
+00000080  03 ff 01 00 01 00 00 10  00 09 00 07 06 70 72 6f  |.............pro|
+00000090  74 6f 33 00 12 00 00                              |to3....|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 59 02 00 00  55 03 03 69 84 d1 d3 44  |....Y...U..i...D|
-00000010  e9 66 08 48 bc 70 d8 ae  40 0b 17 69 e7 27 f6 7a  |.f.H.p.. at ..i.'.z|
-00000020  d5 ee 86 74 54 9e a8 bb  79 76 89 20 57 53 1b 02  |...tT...yv. WS..|
-00000030  5b 70 81 a6 f1 53 bc 9d  b7 42 5e ac 92 93 b5 20  |[p...S...B^.... |
-00000040  8a bb 36 cc 8f cb 7e a0  61 a2 e8 ef c0 2f 00 00  |..6...~.a..../..|
+00000000  16 03 03 00 59 02 00 00  55 03 03 94 d7 79 73 82  |....Y...U....ys.|
+00000010  87 7c 85 6e 8a 1b 7d bf  69 c9 98 0c 44 bd f6 78  |.|.n..}.i...D..x|
+00000020  d2 80 dc d8 7d 80 bb 91  4b d4 ed 20 fe 9f 2f 7b  |....}...K.. ../{|
+00000030  f2 1a 44 36 cd ce af f1  b5 01 8a ac 18 e4 2b 23  |..D6..........+#|
+00000040  a8 ab 1a 32 23 8b 0b e2  81 a8 0a 40 c0 2f 00 00  |...2#...... at ./..|
 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..............|
@@ -59,37 +60,37 @@
 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 04  |.............A..|
-00000330  be 27 08 6f 12 83 1b 04  76 fa 5f 16 d6 e3 64 76  |.'.o....v._...dv|
-00000340  ad 0a 77 37 71 64 44 4c  3f 1a be dc 85 ce 46 c8  |..w7qdDL?.....F.|
-00000350  29 a1 e2 24 78 66 1f 35  90 05 46 c0 91 d1 fd dd  |)..$xf.5..F.....|
-00000360  b5 5b 87 d7 6d 9d 77 a7  f7 b3 df 68 27 fd 6d 04  |.[..m.w....h'.m.|
-00000370  01 00 80 7b 9b fd 0d 62  57 07 ef 97 f5 ff a9 00  |...{...bW.......|
-00000380  a0 89 35 5a 8a e6 e7 ae  7b 55 c5 dc 21 64 87 6e  |..5Z....{U..!d.n|
-00000390  0f ab 85 6d 82 e8 83 fd  7d 3b 49 a7 ae 92 5f 6d  |...m....};I..._m|
-000003a0  a3 42 ce ff ef a6 00 6a  33 32 1f 7b eb b7 c2 5c  |.B.....j32.{...\|
-000003b0  2d 38 cf 10 4b 59 69 4d  15 e0 68 49 39 ba cb 2a  |-8..KYiM..hI9..*|
-000003c0  d9 b9 f3 fe 33 01 4f 7e  ac 69 02 35 a5 e0 33 8d  |....3.O~.i.5..3.|
-000003d0  b3 74 34 14 45 9c 89 ad  41 2d d0 27 22 90 58 c6  |.t4.E...A-.'".X.|
-000003e0  e0 2c b4 6e 19 04 e4 46  26 ec 13 35 48 a6 3f 64  |.,.n...F&..5H.?d|
-000003f0  dc 85 2b 16 03 03 00 04  0e 00 00 00              |..+.........|
+00000320  d9 16 03 03 00 cd 0c 00  00 c9 03 00 17 41 04 7d  |.............A.}|
+00000330  75 a5 53 0b a5 4d a6 81  e0 df c4 11 c9 b5 31 ba  |u.S..M........1.|
+00000340  9f 7b 51 04 57 c6 e0 b9  b0 bc 4f bc 71 74 8a 2e  |.{Q.W.....O.qt..|
+00000350  d1 f6 39 36 94 4e c7 d3  a7 1b 2c b5 55 04 71 01  |..96.N....,.U.q.|
+00000360  9e 2b 42 1e 8b a4 40 b2  13 4f 03 1f 51 9e 5c 04  |.+B... at ..O..Q.\.|
+00000370  01 00 80 68 05 c7 4a ca  df 00 85 2b 53 f7 4f c3  |...h..J....+S.O.|
+00000380  b4 0f e8 f7 b8 30 b7 36  56 65 7b 03 6a 72 f1 aa  |.....0.6Ve{.jr..|
+00000390  54 30 90 9e c7 dc fc 03  96 15 70 67 13 12 a4 f4  |T0........pg....|
+000003a0  42 f0 f9 a1 48 c0 44 44  77 0e ea fd cb b5 6e 19  |B...H.DDw.....n.|
+000003b0  89 94 a7 12 67 87 47 19  c3 00 2d c4 9b d4 dc 66  |....g.G...-....f|
+000003c0  fa ca d7 97 79 9b 28 7f  74 d4 37 c0 06 63 d4 9e  |....y.(.t.7..c..|
+000003d0  a1 53 16 5a 8e d7 a5 cc  90 4d 63 f9 0c 18 85 7f  |.S.Z.....Mc.....|
+000003e0  0e 35 3a 49 73 88 82 51  41 e5 2d 58 aa 38 3e bd  |.5:Is..QA.-X.8>.|
+000003f0  3d d8 da 16 03 03 00 04  0e 00 00 00              |=...........|
 >>> Flow 3 (client to server)
 00000000  16 03 03 00 46 10 00 00  42 41 04 1e 18 37 ef 0d  |....F...BA...7..|
 00000010  19 51 88 35 75 71 b5 e5  54 5b 12 2e 8f 09 67 fd  |.Q.5uq..T[....g.|
 00000020  a7 24 20 3e b2 56 1c ce  97 28 5e f8 2b 2d 4f 9e  |.$ >.V...(^.+-O.|
 00000030  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
 00000040  a6 b5 68 1a 41 03 56 6b  dc 5a 89 14 03 03 00 01  |..h.A.Vk.Z......|
-00000050  01 16 03 03 00 28 00 00  00 00 00 00 00 00 88 0d  |.....(..........|
-00000060  04 8b 8e 93 55 58 d6 75  ca 16 26 42 a3 60 20 67  |....UX.u..&B.` g|
-00000070  84 cf d7 b3 10 fe 63 6c  2f 40 64 0c d6 78        |......cl/@d..x|
+00000050  01 16 03 03 00 28 00 00  00 00 00 00 00 00 a8 da  |.....(..........|
+00000060  74 a6 d0 a5 26 86 f3 5f  89 a4 af ac 9c 1a 01 1f  |t...&.._........|
+00000070  89 8a 1c fc cf 68 3e a5  a3 20 1a b3 78 af        |.....h>.. ..x.|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 28 bd 6c 2f 70 b9  |..........(.l/p.|
-00000010  2f 9c 29 70 af 34 49 4c  5b 25 c3 14 b6 6d 28 81  |/.)p.4IL[%...m(.|
-00000020  ff 54 d9 71 8d 2c c7 38  dd 44 27 6b 54 1e 53 7b  |.T.q.,.8.D'kT.S{|
-00000030  22 cb 65                                          |".e|
+00000000  14 03 03 00 01 01 16 03  03 00 28 1a f2 a9 e8 71  |..........(....q|
+00000010  b2 a6 ca 36 4a ea 55 f6  20 03 fd f7 90 c3 af 30  |...6J.U. ......0|
+00000020  d3 29 c3 d7 1b d6 4d 3e  61 55 94 0d 4e 3e 83 1a  |.)....M>aU..N>..|
+00000030  97 dd 19                                          |...|
 >>> Flow 5 (client to server)
-00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 7f 0d d7  |................|
-00000010  d9 4b 87 7b 36 fb 24 92  69 22 43 50 1e 46 fb c4  |.K.{6.$.i"CP.F..|
-00000020  86 64 6f 15 03 03 00 1a  00 00 00 00 00 00 00 02  |.do.............|
-00000030  37 d5 2d 0a be c5 a8 ae  d4 bd 2b 09 34 18 a0 87  |7.-.......+.4...|
-00000040  08 a6                                             |..|
+00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 94 5b 5e  |..............[^|
+00000010  51 a1 52 ee 19 78 78 ef  12 0d 9c 66 bf e2 48 cb  |Q.R..xx....f..H.|
+00000020  f6 00 1e 15 03 03 00 1a  00 00 00 00 00 00 00 02  |................|
+00000030  cd 5d 31 58 d9 5a 12 65  5b c6 7e 4e e2 04 e7 1d  |.]1X.Z.e[.~N....|
+00000040  b1 4c                                             |.L|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA
index 2073270..1470ba7 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA
+++ b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA
@@ -1,18 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
 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 1a c0 2f  |.............../|
-00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
-00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
-00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
-00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
-00000070  03 02 01 02 03 ff 01 00  01 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 36  |...../.5.......6|
+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 0e 00  |................|
+00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
+00000080  01 00 00 12 00 00                                 |......|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 59 02 00 00  55 03 03 53 04 f1 03 6f  |....Y...U..S...o|
-00000010  c6 4b 55 27 fe e8 fe 4d  7c 0e d4 20 98 b8 7c 81  |.KU'...M|.. ..|.|
-00000020  3d 31 f8 35 66 2f 0a 0b  f1 2c e3 20 86 4d 12 32  |=1.5f/...,. .M.2|
-00000030  73 e3 ba be 25 50 a4 a2  a1 7b f1 9a 76 7a 75 fb  |s...%P...{..vzu.|
-00000040  e2 64 a2 12 ec f3 e7 9d  9a 24 6e 94 c0 09 00 00  |.d.......$n.....|
+00000000  16 03 03 00 59 02 00 00  55 03 03 a5 28 60 99 bf  |....Y...U...(`..|
+00000010  c7 54 04 87 60 ad c5 32  f6 bf ed 11 47 de 4d ff  |.T..`..2....G.M.|
+00000020  99 e1 8f 88 f6 af 10 6e  29 74 0a 20 1d 39 cb e0  |.......n)t. .9..|
+00000030  a5 11 fe 8e 23 11 83 c7  a6 53 fc 97 03 9d ff 7c  |....#....S.....||
+00000040  cf 51 ba 41 64 61 38 22  5c c6 4a 04 c0 09 00 00  |.Q.Ada8"\.J.....|
 00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
 00000060  03 02 0e 0b 00 02 0a 00  02 07 00 02 04 30 82 02  |.............0..|
 00000070  00 30 82 01 62 02 09 00  b8 bf 2d 47 a0 d2 eb f4  |.0..b.....-G....|
@@ -47,24 +48,23 @@
 00000240  13 83 0d 94 06 bb d4 37  7a f6 ec 7a c9 86 2e dd  |.......7z..z....|
 00000250  d7 11 69 7f 85 7c 56 de  fb 31 78 2b e4 c7 78 0d  |..i..|V..1x+..x.|
 00000260  ae cb be 9e 4e 36 24 31  7b 6a 0f 39 95 12 07 8f  |....N6$1{j.9....|
-00000270  2a 16 03 03 00 d7 0c 00  00 d3 03 00 17 41 04 a3  |*............A..|
-00000280  03 8c de d2 b0 68 c8 25  0e 85 ea d7 ae 13 0d 79  |.....h.%.......y|
-00000290  ec 59 0d b5 4d 51 96 d9  7f 64 36 fb 4c d5 6a 26  |.Y..MQ...d6.L.j&|
-000002a0  ae 0e 48 61 df 5c 2b d4  ff 09 41 15 c4 14 8e 1b  |..Ha.\+...A.....|
-000002b0  84 a8 c8 cd ef 10 97 95  66 67 85 dd fd dc 2a 04  |........fg....*.|
-000002c0  03 00 8a 30 81 87 02 41  11 75 5d bc bd 08 28 d4  |...0...A.u]...(.|
-000002d0  5b 1b 45 7f 9c d3 8d 0b  91 fa f6 82 ba 59 bd 3e  |[.E..........Y.>|
-000002e0  96 01 c6 1d 38 db fe 08  e7 56 89 fc 10 b0 37 6a  |....8....V....7j|
-000002f0  3d d6 c9 50 16 53 f7 c2  a2 60 67 82 1f 74 b8 d5  |=..P.S...`g..t..|
-00000300  bc 02 ec 96 db 82 18 8c  87 02 42 01 0d df f7 b7  |..........B.....|
-00000310  05 3c 8c 56 f0 1d 33 18  cf c5 4c 80 7e 0b d9 f9  |.<.V..3...L.~...|
-00000320  f0 51 69 fe 5d b8 0b 64  c0 c7 0d f4 75 65 ae 07  |.Qi.]..d....ue..|
-00000330  9d cf f4 4b ad 52 f6 b8  10 26 18 bd d6 e2 0d a8  |...K.R...&......|
-00000340  80 10 50 34 15 cd 72 0b  7d a9 94 de 4c 16 03 03  |..P4..r.}...L...|
-00000350  00 30 0d 00 00 28 03 01  02 40 00 20 06 01 06 02  |.0...(... at . ....|
+00000270  2a 16 03 03 00 d7 0c 00  00 d3 03 00 17 41 04 c4  |*............A..|
+00000280  0a 40 05 84 eb 90 3c 13  d0 90 af 69 fa 5c 20 75  |. at ....<....i.\ u|
+00000290  e1 9b f2 30 f7 df cc 75  2c 35 7e 38 16 99 7d 57  |...0...u,5~8..}W|
+000002a0  6d d7 f0 93 2d 1d c8 03  89 6e 52 3b 20 e5 8a 5f  |m...-....nR; .._|
+000002b0  6d ca 6e 6a ca 51 f8 a4  dc 1d ec 3e 73 c9 72 04  |m.nj.Q.....>s.r.|
+000002c0  03 00 8a 30 81 87 02 41  37 bf 0d 1d c1 9a 37 39  |...0...A7.....79|
+000002d0  4d 4a f8 17 50 5d 4c 78  d4 25 99 9d 81 48 98 a8  |MJ..P]Lx.%...H..|
+000002e0  ff 2d 3f 98 4b 9f d8 96  2b fa 37 cc e8 66 25 0e  |.-?.K...+.7..f%.|
+000002f0  d3 5e 53 c5 3b ad 17 3f  21 ce d2 45 d8 93 95 6c  |.^S.;..?!..E...l|
+00000300  25 f9 5a 10 9f 37 c8 14  a6 02 42 00 e6 bd 9a 89  |%.Z..7....B.....|
+00000310  8e 73 40 f4 90 e6 d8 e2  98 51 10 23 fb 98 e5 47  |.s at ......Q.#...G|
+00000320  0c 2a 7a 2f 02 66 a8 20  e4 cb 4f ba 14 1d 9e 3a  |.*z/.f. ..O....:|
+00000330  2f 09 47 44 02 e0 9f 30  21 71 f0 99 09 de 23 d2  |/.GD...0!q....#.|
+00000340  f5 f0 b2 93 70 a3 8f 79  b9 4f 88 0b 35 16 03 03  |....p..y.O..5...|
+00000350  00 2e 0d 00 00 26 03 01  02 40 00 1e 06 01 06 02  |.....&... at ......|
 00000360  06 03 05 01 05 02 05 03  04 01 04 02 04 03 03 01  |................|
-00000370  03 02 03 03 02 01 02 02  02 03 01 01 00 00 0e 00  |................|
-00000380  00 00                                             |..|
+00000370  03 02 03 03 02 01 02 02  02 03 00 00 0e 00 00 00  |................|
 >>> Flow 3 (client to server)
 00000000  16 03 03 02 0a 0b 00 02  06 00 02 03 00 02 00 30  |...............0|
 00000010  82 01 fc 30 82 01 5e 02  09 00 9a 30 84 6c 26 35  |...0..^....0.l&5|
@@ -104,31 +104,31 @@
 00000230  24 20 3e b2 56 1c ce 97  28 5e f8 2b 2d 4f 9e f1  |$ >.V...(^.+-O..|
 00000240  07 9f 6c 4b 5b 83 56 e2  32 42 e9 58 b6 d7 49 a6  |..lK[.V.2B.X..I.|
 00000250  b5 68 1a 41 03 56 6b dc  5a 89 16 03 03 00 92 0f  |.h.A.Vk.Z.......|
-00000260  00 00 8e 04 03 00 8a 30  81 87 02 42 00 c6 85 8e  |.......0...B....|
-00000270  06 b7 04 04 e9 cd 9e 3e  cb 66 23 95 b4 42 9c 64  |.......>.f#..B.d|
-00000280  81 39 05 3f b5 21 f8 28  af 60 6b 4d 3d ba a1 4b  |.9.?.!.(.`kM=..K|
-00000290  5e 77 ef e7 59 28 fe 1d  c1 27 a2 ff a8 de 33 48  |^w..Y(...'....3H|
-000002a0  b3 c1 85 6a 42 9b f9 7e  7e 31 c2 e5 bd 66 02 41  |...jB..~~1...f.A|
-000002b0  4b 49 c6 cd 02 e3 83 f7  03 50 18 6d b4 c9 51 02  |KI.......P.m..Q.|
-000002c0  c0 ab 87 bc e0 3e 4b 89  53 3a e2 65 89 97 02 c1  |.....>K.S:.e....|
-000002d0  88 0d 64 db 8e 4f 73 4e  ea 29 0b ed a0 f5 ce 3d  |..d..OsN.).....=|
-000002e0  5f cc 20 ef 0a 22 02 82  f2 14 2a b7 42 68 bd c7  |_. .."....*.Bh..|
-000002f0  4d 14 03 03 00 01 01 16  03 03 00 40 00 00 00 00  |M.......... at ....|
-00000300  00 00 00 00 00 00 00 00  00 00 00 00 f0 cc 4f c7  |..............O.|
-00000310  b6 0f c9 38 4d 4b 97 2c  4f be 53 08 4c d6 5b 4e  |...8MK.,O.S.L.[N|
-00000320  24 70 30 81 82 3a 7f 62  95 03 4d fc 54 78 ec 13  |$p0..:.b..M.Tx..|
-00000330  b2 a1 00 85 2b 04 e4 1d  7b 6e 87 60              |....+...{n.`|
+00000260  00 00 8e 05 03 00 8a 30  81 87 02 42 00 cc a4 ad  |.......0...B....|
+00000270  0b ff 09 40 8f 2c a6 37  72 1d f7 d2 19 74 85 ad  |... at .,.7r....t..|
+00000280  ac 33 b0 b8 5b 56 39 cf  b0 ef 46 68 94 39 4c d0  |.3..[V9...Fh.9L.|
+00000290  f4 97 32 10 99 36 c5 95  c8 14 23 37 78 46 5c a9  |..2..6....#7xF\.|
+000002a0  20 95 65 47 ff 54 02 f1  aa 1d d7 bc 39 2d 02 41  | .eG.T......9-.A|
+000002b0  2e f9 d6 8c e8 c5 a9 6f  10 4f d6 5f 4e 88 e9 71  |.......o.O._N..q|
+000002c0  23 5b 6f b8 ab 19 d3 dd  ec f3 32 e3 3b fa 41 a2  |#[o.......2.;.A.|
+000002d0  e8 ae dc 27 8d 4e 79 f4  47 ef c9 8f bf 0b 41 3b  |...'.Ny.G.....A;|
+000002e0  94 16 cb 8f 1e b5 f3 4e  6e 42 46 35 1a 0c ca 79  |.......NnBF5...y|
+000002f0  4b 14 03 03 00 01 01 16  03 03 00 40 00 00 00 00  |K.......... at ....|
+00000300  00 00 00 00 00 00 00 00  00 00 00 00 64 1c d9 9f  |............d...|
+00000310  34 ec c2 74 76 7a 9f cf  95 19 be 8d 6a 2f 25 96  |4..tvz......j/%.|
+00000320  df de 18 ca 0e c9 d4 2f  e4 b0 34 10 5b 72 7a 18  |......./..4.[rz.|
+00000330  5c 64 d7 fc 2e 1b 28 10  ae a6 31 e9              |\d....(...1.|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 40 d5 2a 76 79 1c  |.......... at .*vy.|
-00000010  e7 d5 b1 5c 65 6b d1 45  73 53 4c 05 3a 6c 5d 81  |...\ek.EsSL.:l].|
-00000020  dd 2f f0 74 62 e4 8e f8  ed 21 99 c7 4f d6 28 40  |./.tb....!..O.(@|
-00000030  63 d9 6d e5 b0 04 73 27  7a 1d 08 19 31 10 da ef  |c.m...s'z...1...|
-00000040  79 26 33 fb 45 23 be a4  7c 03 66                 |y&3.E#..|.f|
+00000000  14 03 03 00 01 01 16 03  03 00 40 27 6f 24 a3 0c  |..........@'o$..|
+00000010  6d d7 68 4a fb 43 b0 97  02 6c 22 7e 2f a1 f1 7a  |m.hJ.C...l"~/..z|
+00000020  37 bf 38 82 dc a0 83 24  01 4b c0 4f 15 e1 7c 4c  |7.8....$.K.O..|L|
+00000030  d4 cd b8 e2 71 af f5 20  7d f9 4a 48 4b f0 a1 f3  |....q.. }.JHK...|
+00000040  7b 02 29 18 c0 87 a5 dd  c4 73 8e                 |{.)......s.|
 >>> Flow 5 (client to server)
 00000000  17 03 03 00 30 00 00 00  00 00 00 00 00 00 00 00  |....0...........|
-00000010  00 00 00 00 00 e2 53 bd  c0 ef 9e e6 44 94 ea 5d  |......S.....D..]|
-00000020  f5 c5 a9 4b ed eb 1c 49  9f 79 44 f9 cd d7 de 02  |...K...I.yD.....|
-00000030  51 10 ae 87 7d 15 03 03  00 30 00 00 00 00 00 00  |Q...}....0......|
-00000040  00 00 00 00 00 00 00 00  00 00 d3 95 13 7f 5f 58  |.............._X|
-00000050  ab d6 17 ea 01 2c 2a ea  5d 7c 44 61 4a 27 97 52  |.....,*.]|DaJ'.R|
-00000060  cc 9b 86 f6 37 42 2b 94  01 49                    |....7B+..I|
+00000010  00 00 00 00 00 bf 7a e1  23 0d d0 13 6e 96 81 6d  |......z.#...n..m|
+00000020  32 56 0f 75 7e 01 88 5f  6d e6 d6 ca ec 3c 17 e9  |2V.u~.._m....<..|
+00000030  44 a9 c0 1c a4 15 03 03  00 30 00 00 00 00 00 00  |D........0......|
+00000040  00 00 00 00 00 00 00 00  00 00 76 be 7a 77 29 01  |..........v.zw).|
+00000050  8e 13 02 66 81 43 a0 55  03 35 22 09 de ea 52 bb  |...f.C.U.5"...R.|
+00000060  51 cc c1 09 0e 9b 4d bd  94 85                    |Q.....M...|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA
index c3b753a..95c5782 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA
+++ b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA
@@ -1,18 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
 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 1a c0 2f  |.............../|
-00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
-00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
-00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
-00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
-00000070  03 02 01 02 03 ff 01 00  01 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 36  |...../.5.......6|
+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 0e 00  |................|
+00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
+00000080  01 00 00 12 00 00                                 |......|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 51 02 00 00  4d 03 03 53 04 f1 03 b0  |....Q...M..S....|
-00000010  43 00 97 24 a7 a8 ea b2  24 fe 96 24 a1 49 64 fd  |C..$....$..$.Id.|
-00000020  1c a3 30 35 2d 85 a7 40  42 86 6b 20 af 27 7f ac  |..05-.. at B.k .'..|
-00000030  8b 16 89 6c 78 b7 f5 29  02 58 a6 8b 61 43 c2 b0  |...lx..).X..aC..|
-00000040  e0 a8 96 c8 fa 2b 26 ad  9a 5f 2d d6 00 05 00 00  |.....+&.._-.....|
+00000000  16 03 03 00 51 02 00 00  4d 03 03 79 e8 35 e3 d2  |....Q...M..y.5..|
+00000010  c0 5e 39 d1 46 da 9c 94  56 20 e2 06 d6 9b f6 dd  |.^9.F...V ......|
+00000020  4f 7a c1 e8 34 a1 9f 8b  c2 e1 fb 20 66 9c 5a 9a  |Oz..4...... f.Z.|
+00000030  3d 22 ab 8e d8 81 03 94  68 a0 6c 72 d8 23 0b 4b  |="......h.lr.#.K|
+00000040  fe 9d c7 49 a7 7c bd fa  b5 7a 5e 5b 00 05 00 00  |...I.|...z^[....|
 00000050  05 ff 01 00 01 00 16 03  03 02 be 0b 00 02 ba 00  |................|
 00000060  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
 00000070  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
@@ -57,10 +58,10 @@
 000002e0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
 000002f0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
 00000300  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
-00000310  6e 38 50 29 6c 90 a7 bd  d9 16 03 03 00 30 0d 00  |n8P)l........0..|
-00000320  00 28 03 01 02 40 00 20  06 01 06 02 06 03 05 01  |.(... at . ........|
+00000310  6e 38 50 29 6c 90 a7 bd  d9 16 03 03 00 2e 0d 00  |n8P)l...........|
+00000320  00 26 03 01 02 40 00 1e  06 01 06 02 06 03 05 01  |.&... at ..........|
 00000330  05 02 05 03 04 01 04 02  04 03 03 01 03 02 03 03  |................|
-00000340  02 01 02 02 02 03 01 01  00 00 0e 00 00 00        |..............|
+00000340  02 01 02 02 02 03 00 00  0e 00 00 00              |............|
 >>> Flow 3 (client to server)
 00000000  16 03 03 02 0a 0b 00 02  06 00 02 03 00 02 00 30  |...............0|
 00000010  82 01 fc 30 82 01 5e 02  09 00 9a 30 84 6c 26 35  |...0..^....0.l&5|
@@ -104,24 +105,24 @@
 00000270  bd 77 82 6f 23 b6 e0 bd  a2 92 b7 3a ac e8 56 f1  |.w.o#......:..V.|
 00000280  af 54 5e 46 87 e9 3b 33  e7 b8 28 b7 d6 c8 90 35  |.T^F..;3..(....5|
 00000290  d4 1c 43 d1 30 6f 55 4e  0a 70 16 03 03 00 92 0f  |..C.0oUN.p......|
-000002a0  00 00 8e 04 03 00 8a 30  81 87 02 42 00 c6 85 8e  |.......0...B....|
-000002b0  06 b7 04 04 e9 cd 9e 3e  cb 66 23 95 b4 42 9c 64  |.......>.f#..B.d|
-000002c0  81 39 05 3f b5 21 f8 28  af 60 6b 4d 3d ba a1 4b  |.9.?.!.(.`kM=..K|
-000002d0  5e 77 ef e7 59 28 fe 1d  c1 27 a2 ff a8 de 33 48  |^w..Y(...'....3H|
-000002e0  b3 c1 85 6a 42 9b f9 7e  7e 31 c2 e5 bd 66 02 41  |...jB..~~1...f.A|
-000002f0  4b 49 c6 cd 02 e3 83 f7  03 50 18 6d b4 c9 51 02  |KI.......P.m..Q.|
-00000300  c0 ab 87 bc e0 3e 4b 89  53 3a e2 65 89 97 02 c1  |.....>K.S:.e....|
-00000310  88 5a 97 82 3e 55 6b 7c  d8 db b8 cc 1b 30 84 0a  |.Z..>Uk|.....0..|
-00000320  7a 97 71 e4 10 bb a4 39  8c 2a cf f5 88 c7 d1 95  |z.q....9.*......|
-00000330  73 14 03 03 00 01 01 16  03 03 00 24 9f 1e f0 72  |s..........$...r|
-00000340  92 ea dc f7 56 96 37 e4  69 db db 66 1d f6 94 c4  |....V.7.i..f....|
-00000350  18 31 4f d0 5d c5 f4 53  21 aa 98 b1 dc 08 94 94  |.1O.]..S!.......|
+000002a0  00 00 8e 05 03 00 8a 30  81 87 02 41 19 c7 50 06  |.......0...A..P.|
+000002b0  42 82 f9 e5 ec 0b f7 65  7e b1 19 53 5f 23 ab 19  |B......e~..S_#..|
+000002c0  54 08 ec d2 a7 22 dd 83  7c 97 76 59 a5 6b f4 1d  |T...."..|.vY.k..|
+000002d0  92 86 34 2d ce 71 bb 01  d2 8a 67 0e a8 fb 51 e4  |..4-.q....g...Q.|
+000002e0  69 9c 27 23 74 b9 fd 6f  b6 5e 48 a0 cc 02 42 01  |i.'#t..o.^H...B.|
+000002f0  50 97 b7 95 14 f4 a6 f2  95 63 17 38 59 a1 51 95  |P........c.8Y.Q.|
+00000300  1e bc 99 fb fd 82 8b ab  cb 4d 8e 17 a9 f8 e9 c2  |.........M......|
+00000310  9b 93 15 02 50 e6 c2 05  54 e7 8a ec 6f 93 1f 79  |....P...T...o..y|
+00000320  8d 67 e7 2d d6 65 ab 97  fd be 20 97 bd 6b c4 fc  |.g.-.e.... ..k..|
+00000330  02 14 03 03 00 01 01 16  03 03 00 24 24 df 52 6e  |...........$$.Rn|
+00000340  c1 35 48 fe 60 77 28 69  36 fe 96 a1 72 db a2 f5  |.5H.`w(i6...r...|
+00000350  d0 b7 c3 d9 67 e5 ee f2  d9 18 bf f0 35 80 06 c2  |....g.......5...|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 24 ee 68 c1 87 9f  |..........$.h...|
-00000010  d7 90 94 f1 3b 6d 26 0b  3d 89 7a 45 3b 52 5d 3c  |....;m&.=.zE;R]<|
-00000020  dd 7c c1 4e 57 3e a9 ee  91 be cf 2b a3 98 9d     |.|.NW>.....+...|
+00000000  14 03 03 00 01 01 16 03  03 00 24 40 5b dc 01 59  |..........$@[..Y|
+00000010  33 6e 61 5a 6d fc c8 a5  f5 00 9b 55 77 c5 e6 f2  |3naZm......Uw...|
+00000020  c6 5c b6 2f 94 3c 72 5b  b5 0c 3e 78 88 e6 44     |.\./.<r[..>x..D|
 >>> Flow 5 (client to server)
-00000000  17 03 03 00 1a 88 33 3e  2b 22 6b 92 d0 bb 8a 1e  |......3>+"k.....|
-00000010  9b f4 9e aa 91 8b 2b 95  ea 53 c8 03 0a 93 58 15  |......+..S....X.|
-00000020  03 03 00 16 c4 67 79 ba  ec cf 90 b1 f9 ac ec 64  |.....gy........d|
-00000030  72 01 08 8f 3a 98 aa 66  25 00                    |r...:..f%.|
+00000000  17 03 03 00 1a cd 2f 11  b1 3a e4 1c 31 95 9b c4  |....../..:..1...|
+00000010  37 20 9f 03 d3 45 a4 15  e1 09 1e 0c f6 5d d3 15  |7 ...E.......]..|
+00000020  03 03 00 16 d7 f6 a1 d0  ad 41 69 73 c0 40 22 f2  |.........Ais.@".|
+00000030  5f e8 c3 50 f9 35 fc 59  e0 3a                    |_..P.5.Y.:|
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..52e3bef
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-AES256-GCM-SHA384
@@ -0,0 +1,139 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
+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 36  |...../.5.......6|
+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 0e 00  |................|
+00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
+00000080  01 00 00 12 00 00                                 |......|
+>>> Flow 2 (server to client)
+00000000  16 03 03 00 59 02 00 00  55 03 03 74 fe 19 af 4b  |....Y...U..t...K|
+00000010  f3 d8 92 62 5a df 90 2c  cc 09 fd 79 45 26 cd 52  |...bZ..,...yE&.R|
+00000020  9a e6 da 16 99 fe 1d 91  79 a7 a0 20 b3 13 e9 03  |........y.. ....|
+00000030  52 23 5f f0 55 59 f1 9e  00 a7 77 97 90 ed 2b fb  |R#_.UY....w...+.|
+00000040  9c ab fe b1 db ea 16 95  95 68 b0 e9 c0 30 00 00  |.........h...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 22  |.............A."|
+00000330  84 e9 5e 6e 35 92 a3 83  73 0a d6 0d 1a c1 4d ab  |..^n5...s.....M.|
+00000340  1f ab c2 dc 3f 53 a5 7d  38 c0 92 a4 82 e1 3c c5  |....?S.}8.....<.|
+00000350  24 60 20 a5 3b c5 65 ba  9c f1 b9 a5 b9 c2 70 73  |$` .;.e.......ps|
+00000360  19 74 a6 d1 0f 75 b4 75  e0 e8 60 20 e9 23 fe 04  |.t...u.u..` .#..|
+00000370  01 00 80 92 e0 56 3f 48  0d 10 23 48 b5 95 b6 91  |.....V?H..#H....|
+00000380  3e 8a 2e c7 02 e2 85 0e  59 c8 03 24 d9 1a 1a 25  |>.......Y..$...%|
+00000390  8e 12 bb 0b 83 ac 51 36  81 3f bc 0e be b9 3b 1d  |......Q6.?....;.|
+000003a0  67 56 21 4d 24 36 84 05  61 e7 70 60 d5 8e ae 97  |gV!M$6..a.p`....|
+000003b0  b8 3a d3 b1 94 72 52 cd  b0 0d dd 46 b1 15 3b 58  |.:...rR....F..;X|
+000003c0  c1 a4 63 2c 4c 31 f9 c7  4f 27 c1 0f f0 24 36 72  |..c,L1..O'...$6r|
+000003d0  e0 f8 51 12 86 c2 13 ed  6b 84 a8 15 c3 d0 39 55  |..Q.....k.....9U|
+000003e0  a4 60 50 88 c9 1e 60 60  aa 8d a5 31 3e 35 c3 f8  |.`P...``...1>5..|
+000003f0  2c 90 1c 16 03 03 00 2e  0d 00 00 26 03 01 02 40  |,..........&...@|
+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 at .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  33 bb 8e 67 64 03 e7 7e  |........3..gd..~|
+00000260  be a5 b1 bc cf 7a 07 24  01 17 c3 3d 4b 72 dd c3  |.....z.$...=Kr..|
+00000270  64 a7 36 e8 49 ab b6 87  ce d6 af 9e 07 22 76 e8  |d.6.I........"v.|
+00000280  0d 44 a3 36 c9 eb a4 49  85 cf 72 67 e8 2a a7 5b  |.D.6...I..rg.*.[|
+00000290  d3 f2 46 af 53 48 c6 13  f7 0b 5b 9c c7 4d 3e 05  |..F.SH....[..M>.|
+000002a0  3c 0f 69 a7 40 3a e8 70  04 01 1c 29 b2 42 0f 5f  |<.i.@:.p...).B._|
+000002b0  1c d5 b7 5c c2 17 07 7f  bd a2 b3 9a 95 81 51 24  |...\..........Q$|
+000002c0  54 5c 42 d6 a4 76 c0 d7  54 d2 11 54 bf fd dc a0  |T\B..v..T..T....|
+000002d0  ee 95 26 64 59 a0 fc 51  14 03 03 00 01 01 16 03  |..&dY..Q........|
+000002e0  03 00 28 00 00 00 00 00  00 00 00 af f4 8a be d9  |..(.............|
+000002f0  ff f1 44 e4 41 ab 9b b3  d8 b0 3d 3f 6b c5 1d b6  |..D.A.....=?k...|
+00000300  1d 9e 35 f5 20 f4 2a af  e8 35 77                 |..5. .*..5w|
+>>> Flow 4 (server to client)
+00000000  14 03 03 00 01 01 16 03  03 00 28 ff 0d 47 63 2b  |..........(..Gc+|
+00000010  bd 00 3a ad 82 e3 a7 b3  b0 84 4a 26 f4 30 78 20  |..:.......J&.0x |
+00000020  80 f2 2b 15 98 61 1c cb  8b 17 67 8a 11 96 aa 93  |..+..a....g.....|
+00000030  68 f7 fb                                          |h..|
+>>> Flow 5 (client to server)
+00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 a6 8d 7b  |...............{|
+00000010  99 5e a2 e1 95 bb 5f e4  01 f4 0e 20 52 b4 64 4e  |.^...._.... R.dN|
+00000020  86 b1 3f 15 03 03 00 1a  00 00 00 00 00 00 00 02  |..?.............|
+00000030  61 98 eb d0 7c ac bd 00  ac 7a e1 32 20 3e 81 b6  |a...|....z.2 >..|
+00000040  9d d5                                             |..|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA
index 0037af6..23bf29d 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA
+++ b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA
@@ -1,18 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
 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 1a c0 2f  |.............../|
-00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
-00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
-00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
-00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
-00000070  03 02 01 02 03 ff 01 00  01 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 36  |...../.5.......6|
+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 0e 00  |................|
+00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
+00000080  01 00 00 12 00 00                                 |......|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 59 02 00 00  55 03 03 53 04 f1 02 fd  |....Y...U..S....|
-00000010  41 bd ef ee f3 da fc 1a  31 8c 77 f2 e9 66 54 a0  |A.......1.w..fT.|
-00000020  f4 15 b1 1c 84 0d 6d 74  87 ac 7d 20 78 17 8b 08  |......mt..} x...|
-00000030  10 20 c9 44 e4 8a 43 af  4a c7 b8 3d 99 f2 f7 af  |. .D..C.J..=....|
-00000040  bb a3 21 2f 40 cc ed b6  da a8 a1 d5 c0 09 00 00  |..!/@...........|
+00000000  16 03 03 00 59 02 00 00  55 03 03 b3 7f 4e e7 11  |....Y...U....N..|
+00000010  6d bc 56 ec 9c a8 61 08  d6 5a 2a 42 7b f1 94 0a  |m.V...a..Z*B{...|
+00000020  29 35 8b 7e 23 a0 6c 59  23 cf 39 20 84 09 b6 5b  |)5.~#.lY#.9 ...[|
+00000030  2f 46 80 3b 26 92 fd 81  e9 24 8c e2 b8 64 a2 03  |/F.;&....$...d..|
+00000040  3a 68 c3 7b 44 f8 28 41  e2 d3 6c 7c c0 09 00 00  |:h.{D.(A..l|....|
 00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
 00000060  03 02 0e 0b 00 02 0a 00  02 07 00 02 04 30 82 02  |.............0..|
 00000070  00 30 82 01 62 02 09 00  b8 bf 2d 47 a0 d2 eb f4  |.0..b.....-G....|
@@ -47,24 +48,23 @@
 00000240  13 83 0d 94 06 bb d4 37  7a f6 ec 7a c9 86 2e dd  |.......7z..z....|
 00000250  d7 11 69 7f 85 7c 56 de  fb 31 78 2b e4 c7 78 0d  |..i..|V..1x+..x.|
 00000260  ae cb be 9e 4e 36 24 31  7b 6a 0f 39 95 12 07 8f  |....N6$1{j.9....|
-00000270  2a 16 03 03 00 d8 0c 00  00 d4 03 00 17 41 04 a9  |*............A..|
-00000280  19 8b d9 9b 5c 7c 6a 7d  85 d2 70 4e 89 7e 0b 5b  |....\|j}..pN.~.[|
-00000290  dd 5e a1 63 8d 15 bc 0b  0c 47 3d 4d e8 a7 56 88  |.^.c.....G=M..V.|
-000002a0  2e f6 7f e2 4d fc ed cc  03 ed a1 2d ac ae 81 a5  |....M......-....|
-000002b0  e2 6d 7f 9f a3 93 e9 10  c1 0e 48 1b f3 f4 38 04  |.m........H...8.|
-000002c0  03 00 8b 30 81 88 02 42  00 87 fe 7e 63 82 14 57  |...0...B...~c..W|
-000002d0  dc 7d e2 0f cc 97 2d ba  3c a7 56 4a 17 a8 09 6a  |.}....-.<.VJ...j|
-000002e0  28 2e f2 66 1a 3f 2d 48  2b 6f 79 a1 60 cd 5e 10  |(..f.?-H+oy.`.^.|
-000002f0  0b 0a 28 f2 5f e4 3f 4f  f9 c9 91 34 d9 dc bc fc  |..(._.?O...4....|
-00000300  98 ea 77 0b 99 f8 a2 11  c4 bd 02 42 01 a0 b0 dc  |..w........B....|
-00000310  db 5b c2 09 99 bd ee a0  b9 aa 31 b9 10 84 22 be  |.[........1...".|
-00000320  5a 63 12 5a 43 00 8e c1  33 cc 91 bb c2 70 7a 63  |Zc.ZC...3....pzc|
-00000330  19 82 c0 74 48 a1 c7 3d  1f f1 6f 4a 6f 6a 8c 3f  |...tH..=..oJoj.?|
-00000340  28 31 a8 0c 65 19 26 62  4b 7a 7c 4b ea 1a 16 03  |(1..e.&bKz|K....|
-00000350  03 00 30 0d 00 00 28 03  01 02 40 00 20 06 01 06  |..0...(... at . ...|
-00000360  02 06 03 05 01 05 02 05  03 04 01 04 02 04 03 03  |................|
-00000370  01 03 02 03 03 02 01 02  02 02 03 01 01 00 00 0e  |................|
-00000380  00 00 00                                          |...|
+00000270  2a 16 03 03 00 d7 0c 00  00 d3 03 00 17 41 04 0f  |*............A..|
+00000280  4d b0 41 d4 dc 6b 8a 85  52 eb eb 18 4a 8f a7 e6  |M.A..k..R...J...|
+00000290  24 52 e5 86 be 57 d7 0a  e7 23 84 a8 a9 6c 96 08  |$R...W...#...l..|
+000002a0  4b f7 47 32 79 d9 df 81  f6 05 40 63 3b 14 67 3b  |K.G2y..... at c;.g;|
+000002b0  ea 01 a0 0d 43 1a 36 29  b3 51 7a e4 af 1b 67 04  |....C.6).Qz...g.|
+000002c0  03 00 8a 30 81 87 02 42  01 8e 57 8a b8 b7 5b 2f  |...0...B..W...[/|
+000002d0  9c 31 74 d8 7d 68 d7 6e  83 73 5f fb d0 cd de 66  |.1t.}h.n.s_....f|
+000002e0  60 fa 0a 0a 15 0b 30 3b  08 b6 f1 3e 4f 20 13 62  |`.....0;...>O .b|
+000002f0  b5 ff 86 81 dc 42 a1 4c  af c8 ff b3 24 81 d8 e1  |.....B.L....$...|
+00000300  d1 09 0c 32 11 92 5e dd  3f 87 02 41 76 a7 29 48  |...2..^.?..Av.)H|
+00000310  52 68 1c 72 4d d5 39 bf  fa 61 ec b2 27 ce 10 4e  |Rh.rM.9..a..'..N|
+00000320  86 12 3d 1e 04 9c 11 b7  b4 0c cf 98 9d 01 c3 93  |..=.............|
+00000330  cf 83 9e 92 9a ca fd 8f  b1 9f 1b 20 c4 fb a4 46  |........... ...F|
+00000340  60 fc fd d5 33 b0 8f b5  b5 c8 a4 70 c5 16 03 03  |`...3......p....|
+00000350  00 2e 0d 00 00 26 03 01  02 40 00 1e 06 01 06 02  |.....&... at ......|
+00000360  06 03 05 01 05 02 05 03  04 01 04 02 04 03 03 01  |................|
+00000370  03 02 03 03 02 01 02 02  02 03 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|
@@ -103,31 +103,31 @@
 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 04 01 00 80  38 f2 16 e5 b5 86 16 62  |........8......b|
-00000260  86 e1 7d 01 f1 a8 e1 f7  e7 85 b1 a0 17 ee 84 25  |..}............%|
-00000270  cb 3c 46 61 1a 78 7b 1e  ee 32 bc d9 6c fa 6b 76  |.<Fa.x{..2..l.kv|
-00000280  67 a7 9e c8 7a 4c e8 79  0d 22 27 ad e7 98 6a 98  |g...zL.y."'...j.|
-00000290  89 88 8b a9 69 5b 6f c6  00 48 9a 21 77 a9 7c 15  |....i[o..H.!w.|.|
-000002a0  ba 47 16 74 8d 6c 67 dc  6d f1 98 b6 61 e8 bc 08  |.G.t.lg.m...a...|
-000002b0  18 53 a6 93 bf fc 27 5e  b7 4d d2 eb 68 e9 23 ee  |.S....'^.M..h.#.|
-000002c0  d2 70 d2 55 2c c7 99 7d  c0 66 b5 1c ea 38 71 5c  |.p.U,..}.f...8q\|
-000002d0  a6 57 1f 52 e4 8e e8 51  14 03 03 00 01 01 16 03  |.W.R...Q........|
+00000250  0f 00 00 84 05 01 00 80  02 19 16 cc 97 ad 70 20  |..............p |
+00000260  bd 64 63 dd b6 81 a0 16  b3 46 4b 42 ff 21 58 2c  |.dc......FKB.!X,|
+00000270  bb 2b 4c e1 4e d7 49 4d  5c 7c 63 32 3e ef e6 ad  |.+L.N.IM\|c2>...|
+00000280  85 3f ab b4 5c 2a 37 76  8b 28 56 08 4f 08 b9 51  |.?..\*7v.(V.O..Q|
+00000290  71 14 07 27 47 45 11 a0  03 cf 72 7d 67 ef 31 8d  |q..'GE....r}g.1.|
+000002a0  e7 db 36 76 b1 b3 f4 bf  aa 6c c4 56 94 35 71 e1  |..6v.....l.V.5q.|
+000002b0  dd 88 6d 15 90 c8 70 ad  d8 95 55 42 9b c1 45 19  |..m...p...UB..E.|
+000002c0  36 ce 87 c6 fd 94 8a d4  98 6e ec 18 d5 da 59 54  |6........n....YT|
+000002d0  80 a7 8c 90 ae 55 20 1c  14 03 03 00 01 01 16 03  |.....U .........|
 000002e0  03 00 40 00 00 00 00 00  00 00 00 00 00 00 00 00  |.. at .............|
-000002f0  00 00 00 5e e7 6e 1c a2  02 24 34 f0 a6 b6 27 ea  |...^.n...$4...'.|
-00000300  69 d5 0e 2e a8 ad 5c ad  6c 06 78 68 39 92 27 f1  |i.....\.l.xh9.'.|
-00000310  e8 35 49 67 4d fb 5d 8a  31 2e 4e 3f 19 ed ea 30  |.5IgM.].1.N?...0|
-00000320  20 60 e1                                          | `.|
+000002f0  00 00 00 58 fe bc 5c ba  b2 a9 96 77 2f 95 c9 10  |...X..\....w/...|
+00000300  fd 6d fc 6a 88 8c df 82  c3 a4 3d cc 28 f4 bf 7d  |.m.j......=.(..}|
+00000310  4a f8 3d 97 36 e5 a0 76  92 94 da dd cc f5 e4 0e  |J.=.6..v........|
+00000320  7a c4 2c                                          |z.,|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 40 ee a8 82 bc 3f  |.......... at ....?|
-00000010  bf ab a6 e4 30 e0 3d f1  2f 19 a2 ac 7a 81 57 f1  |....0.=./...z.W.|
-00000020  ee 67 3f 55 2b 30 fa 72  b5 10 03 ec 8d 0a 8f bb  |.g?U+0.r........|
-00000030  24 f5 45 f5 4e 53 4b 93  a5 0d 42 6c 46 69 98 fb  |$.E.NSK...BlFi..|
-00000040  63 c5 9f 95 65 d1 b6 f0  a4 15 bd                 |c...e......|
+00000000  14 03 03 00 01 01 16 03  03 00 40 81 ab 5a 66 a8  |.......... at ..Zf.|
+00000010  0f a5 d3 07 00 66 45 1f  31 a9 ef f7 a0 d9 23 46  |.....fE.1.....#F|
+00000020  f0 3e 50 18 99 e3 5a bd  eb b7 1d 81 d5 95 d5 ee  |.>P...Z.........|
+00000030  21 31 41 4b 19 92 b5 95  36 da 21 c0 4a 2a a0 1c  |!1AK....6.!.J*..|
+00000040  a3 9f 8e a0 6f 9d 37 5e  12 11 03                 |....o.7^...|
 >>> Flow 5 (client to server)
 00000000  17 03 03 00 30 00 00 00  00 00 00 00 00 00 00 00  |....0...........|
-00000010  00 00 00 00 00 cb 4e bc  d1 a9 58 ef c8 39 a9 36  |......N...X..9.6|
-00000020  f4 35 05 96 8e a4 50 bc  f4 15 06 f9 fd 41 6d 1e  |.5....P......Am.|
-00000030  5e 7c 82 63 94 15 03 03  00 30 00 00 00 00 00 00  |^|.c.....0......|
-00000040  00 00 00 00 00 00 00 00  00 00 bd 77 87 a5 5a d4  |...........w..Z.|
-00000050  b8 59 e6 6b 0f dd ea f9  ed 18 b2 9f a9 61 b4 3a  |.Y.k.........a.:|
-00000060  47 15 15 3b 83 ef e1 6d  db a8                    |G..;...m..|
+00000010  00 00 00 00 00 a9 51 94  19 72 ab 9f 3e 97 5e 99  |......Q..r..>.^.|
+00000020  2c ec 13 48 3e 10 54 5f  8a 85 88 4d 1a a8 f5 ed  |,..H>.T_...M....|
+00000030  c3 4f a9 59 a3 15 03 03  00 30 00 00 00 00 00 00  |.O.Y.....0......|
+00000040  00 00 00 00 00 00 00 00  00 00 25 00 6d 2f a0 f6  |..........%.m/..|
+00000050  ce 8a 30 ba 53 da 97 c6  11 f3 d2 f3 9e 66 d6 dd  |..0.S........f..|
+00000060  19 f3 ee 07 03 d3 e6 f1  30 32                    |........02|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA
index df3eaa4..ff79aa2 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA
+++ b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA
@@ -1,18 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
 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 1a c0 2f  |.............../|
-00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
-00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
-00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
-00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
-00000070  03 02 01 02 03 ff 01 00  01 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 36  |...../.5.......6|
+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 0e 00  |................|
+00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
+00000080  01 00 00 12 00 00                                 |......|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 51 02 00 00  4d 03 03 53 04 f1 02 1d  |....Q...M..S....|
-00000010  0e dc 86 e5 a9 07 71 46  15 34 af 47 15 3f 03 9c  |......qF.4.G.?..|
-00000020  fc d6 fd 44 7c f4 f1 c7  8d 6f f8 20 28 ea 3c dc  |...D|....o. (.<.|
-00000030  b2 4c b7 ba 20 88 c4 db  a5 73 ea 93 ab 3a 85 a6  |.L.. ....s...:..|
-00000040  8f 59 49 d9 a9 31 14 d5  a6 2b 4f d1 00 05 00 00  |.YI..1...+O.....|
+00000000  16 03 03 00 51 02 00 00  4d 03 03 b3 b2 22 69 e4  |....Q...M...."i.|
+00000010  1a a1 56 94 26 0c 43 b7  89 0c 34 ce dc 5a c8 ca  |..V.&.C...4..Z..|
+00000020  e2 42 92 5c 75 9a b3 22  22 64 38 20 6d 2c 26 0b  |.B.\u..""d8 m,&.|
+00000030  34 b6 b8 20 36 e2 58 e5  ee 1f e2 9f a0 75 f6 d9  |4.. 6.X......u..|
+00000040  0c e4 39 ce 3c 8e 2e f8  e8 d1 a2 16 00 05 00 00  |..9.<...........|
 00000050  05 ff 01 00 01 00 16 03  03 02 be 0b 00 02 ba 00  |................|
 00000060  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
 00000070  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
@@ -57,10 +58,10 @@
 000002e0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
 000002f0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
 00000300  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
-00000310  6e 38 50 29 6c 90 a7 bd  d9 16 03 03 00 30 0d 00  |n8P)l........0..|
-00000320  00 28 03 01 02 40 00 20  06 01 06 02 06 03 05 01  |.(... at . ........|
+00000310  6e 38 50 29 6c 90 a7 bd  d9 16 03 03 00 2e 0d 00  |n8P)l...........|
+00000320  00 26 03 01 02 40 00 1e  06 01 06 02 06 03 05 01  |.&... at ..........|
 00000330  05 02 05 03 04 01 04 02  04 03 03 01 03 02 03 03  |................|
-00000340  02 01 02 02 02 03 01 01  00 00 0e 00 00 00        |..............|
+00000340  02 01 02 02 02 03 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|
@@ -103,24 +104,24 @@
 00000260  e6 bd 77 82 6f 23 b6 e0  bd a2 92 b7 3a ac e8 56  |..w.o#......:..V|
 00000270  f1 af 54 5e 46 87 e9 3b  33 e7 b8 28 b7 d6 c8 90  |..T^F..;3..(....|
 00000280  35 d4 1c 43 d1 30 6f 55  4e 0a 70 16 03 03 00 88  |5..C.0oUN.p.....|
-00000290  0f 00 00 84 04 01 00 80  2a 1f ae 48 9f 86 16 dc  |........*..H....|
-000002a0  c2 55 1f 5f 95 81 ed 56  00 5d 35 46 e5 b6 57 d5  |.U._...V.]5F..W.|
-000002b0  a6 3e 32 38 8b e2 c6 1c  b9 b1 38 b2 da 66 45 ed  |.>28......8..fE.|
-000002c0  58 6a 7f 43 41 93 a5 09  da b9 04 ce 3f 13 8a 19  |Xj.CA.......?...|
-000002d0  13 e9 2c 1f c5 e7 35 b4  2d ea 7c 81 90 33 c0 66  |..,...5.-.|..3.f|
-000002e0  dc 41 8b 23 08 8f 69 d4  d6 a2 5f c1 bd 26 e6 2e  |.A.#..i..._..&..|
-000002f0  7f c8 7c a8 2d d4 08 95  ce 6e 58 54 04 a2 a6 63  |..|.-....nXT...c|
-00000300  54 72 67 f2 7f 61 0a 6b  58 46 d4 88 95 38 37 f2  |Trg..a.kXF...87.|
-00000310  93 95 48 56 14 a7 b9 7c  14 03 03 00 01 01 16 03  |..HV...|........|
-00000320  03 00 24 64 bb 41 3a cb  a2 2f 95 53 5c 2f f7 83  |..$d.A:../.S\/..|
-00000330  a2 35 18 f6 d0 8d 6f e2  54 ed 2f 07 10 f4 36 e2  |.5....o.T./...6.|
-00000340  3d e5 30 1d e3 63 01                              |=.0..c.|
+00000290  0f 00 00 84 05 01 00 80  01 24 8d bb 05 61 2d 29  |.........$...a-)|
+000002a0  12 11 90 f5 57 21 be b7  29 76 55 63 94 8e 7b 4d  |....W!..)vUc..{M|
+000002b0  3b 3d 89 5b 1f b9 e1 8c  36 68 6f 31 21 50 af e4  |;=.[....6ho1!P..|
+000002c0  9f ca a5 68 55 b9 eb 36  75 3a 0c be 11 30 28 c8  |...hU..6u:...0(.|
+000002d0  8b 82 93 9a 71 37 4d 4e  4f d2 0c 2f 13 36 ad c3  |....q7MNO../.6..|
+000002e0  df 8a 1b 59 b2 f9 8b a7  74 63 75 4a f4 9d e0 6b  |...Y....tcuJ...k|
+000002f0  42 02 5a a9 6e a4 a8 24  d3 23 f7 09 ee b0 dc c4  |B.Z.n..$.#......|
+00000300  6f 87 58 72 e7 e3 87 b3  6b 15 ba 7f dd 9b 93 91  |o.Xr....k.......|
+00000310  5b 21 a0 31 31 bd 15 b5  14 03 03 00 01 01 16 03  |[!.11...........|
+00000320  03 00 24 fc 0e 7c e8 3e  8b b5 dc c9 3d 38 61 a1  |..$..|.>....=8a.|
+00000330  24 d6 77 1f 06 1f 30 32  ba dd 05 68 45 f1 4f 0d  |$.w...02...hE.O.|
+00000340  2e 24 09 ad c1 e5 b7                              |.$.....|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 24 0a 22 b6 bc da  |..........$."...|
-00000010  34 38 53 8e 80 e2 25 7b  31 2f 70 8e 3a db e8 a3  |48S...%{1/p.:...|
-00000020  70 0e 88 22 b4 a8 be d4  a3 e3 cc 13 94 ef 47     |p.."..........G|
+00000000  14 03 03 00 01 01 16 03  03 00 24 d7 b6 b3 0a e6  |..........$.....|
+00000010  86 9a 25 e4 38 de d0 57  ff 93 0b f4 de 76 3d 00  |..%.8..W.....v=.|
+00000020  64 35 cf 70 f6 ea 74 2d  b0 71 2d 92 e2 df eb     |d5.p..t-.q-....|
 >>> Flow 5 (client to server)
-00000000  17 03 03 00 1a b4 9c b1  57 ea 01 03 fe 01 e7 1e  |........W.......|
-00000010  c4 a7 0f 25 14 99 00 4f  88 51 c1 98 6e 99 01 15  |...%...O.Q..n...|
-00000020  03 03 00 16 2e c4 11 8b  1a fc 37 81 18 33 e4 9f  |..........7..3..|
-00000030  48 a3 29 e3 ad 9b 9b ec  9f 99                    |H.).......|
+00000000  17 03 03 00 1a db bd 43  12 7c b5 83 b5 18 9d 6a  |.......C.|.....j|
+00000010  70 3f 5a eb cb d0 ba d4  03 3e a0 7b 25 f0 41 15  |p?Z......>.{%.A.|
+00000020  03 03 00 16 f8 f2 a3 27  a5 c7 25 d9 6c 08 b1 96  |.......'..%.l...|
+00000030  38 22 38 df 16 fb e2 9f  61 a3                    |8"8.....a.|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES
index 7644590..e700e16 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES
+++ b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES
@@ -1,18 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
 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 1a c0 2f  |.............../|
-00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
-00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
-00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
-00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
-00000070  03 02 01 02 03 ff 01 00  01 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 36  |...../.5.......6|
+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 0e 00  |................|
+00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
+00000080  01 00 00 12 00 00                                 |......|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 59 02 00 00  55 03 03 53 04 f1 02 a0  |....Y...U..S....|
-00000010  5f bd a4 8d 98 93 b8 da  08 86 9f b2 be 9a a4 91  |_...............|
-00000020  2b 3c 1f 18 f0 75 7c a9  a8 a0 f7 20 4a 89 9a d2  |+<...u|.... J...|
-00000030  34 3b d9 b1 c2 fd 61 bd  97 19 22 ce b9 d1 5b a7  |4;....a..."...[.|
-00000040  83 80 9c 19 d0 f5 a0 aa  4c ac 06 20 c0 09 00 00  |........L.. ....|
+00000000  16 03 03 00 59 02 00 00  55 03 03 21 9b eb 15 24  |....Y...U..!...$|
+00000010  46 b6 c1 85 f5 be c5 0d  e2 6b 60 bc ee 73 b1 fb  |F........k`..s..|
+00000020  34 6f f0 b8 f0 9e 1c 26  a4 4b 0f 20 cb 2b 84 a2  |4o.....&.K. .+..|
+00000030  cb a5 48 70 fe 84 25 b0  16 20 14 a1 83 21 fc f9  |..Hp..%.. ...!..|
+00000040  82 fc 9e 1a d1 3b 56 69  ab c5 0e 2c c0 09 00 00  |.....;Vi...,....|
 00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
 00000060  03 02 0e 0b 00 02 0a 00  02 07 00 02 04 30 82 02  |.............0..|
 00000070  00 30 82 01 62 02 09 00  b8 bf 2d 47 a0 d2 eb f4  |.0..b.....-G....|
@@ -47,21 +48,21 @@
 00000240  13 83 0d 94 06 bb d4 37  7a f6 ec 7a c9 86 2e dd  |.......7z..z....|
 00000250  d7 11 69 7f 85 7c 56 de  fb 31 78 2b e4 c7 78 0d  |..i..|V..1x+..x.|
 00000260  ae cb be 9e 4e 36 24 31  7b 6a 0f 39 95 12 07 8f  |....N6$1{j.9....|
-00000270  2a 16 03 03 00 d7 0c 00  00 d3 03 00 17 41 04 3c  |*............A.<|
-00000280  8f 35 1e 47 5d 7b ad 13  0c e9 5c c0 97 c7 83 06  |.5.G]{....\.....|
-00000290  49 0f 6c cf e5 4d 3b ed  f7 1b c6 96 8d ba 54 35  |I.l..M;.......T5|
-000002a0  7f df 35 e3 6e 28 e9 71  f2 24 b5 ab 17 2b 4b 2b  |..5.n(.q.$...+K+|
-000002b0  0c 8f 9f 48 89 73 8f 09  69 84 af 7f ec 43 7a 04  |...H.s..i....Cz.|
-000002c0  03 00 8a 30 81 87 02 41  79 84 43 0c 78 fa 7e e2  |...0...Ay.C.x.~.|
-000002d0  c5 51 c1 60 88 c4 4a 59  7d 02 fa dc 19 68 33 ed  |.Q.`..JY}....h3.|
-000002e0  19 ef a1 df ef 6b 21 a6  98 aa ba a9 13 70 91 0f  |.....k!......p..|
-000002f0  cc 6c 5c 1e 99 53 1b 42  51 6c 06 a7 3c c4 04 22  |.l\..S.BQl..<.."|
-00000300  5d 0d c1 30 ab e3 ec b4  54 02 42 01 15 15 1a 6e  |]..0....T.B....n|
-00000310  6f f1 c6 b1 10 84 2c c8  04 de 2b 52 d5 b4 f7 c9  |o.....,...+R....|
-00000320  4f 6d 0e 0e 26 45 1d 7a  28 59 2b 8b f6 92 3a 23  |Om..&E.z(Y+...:#|
-00000330  7a 39 9c d5 4e cc 5d c5  45 92 9c d0 5f 33 12 e3  |z9..N.].E..._3..|
-00000340  2b 29 39 52 bb 16 aa e1  72 9e b5 fe 99 16 03 03  |+)9R....r.......|
-00000350  00 04 0e 00 00 00                                 |......|
+00000270  2a 16 03 03 00 d8 0c 00  00 d4 03 00 17 41 04 b6  |*............A..|
+00000280  3f 37 33 68 cb 79 c0 86  f4 9d 12 ac c4 9d 8c 9b  |?73h.y..........|
+00000290  59 1c d4 a9 01 9f 2d cb  80 24 02 ec e0 ff d1 8c  |Y.....-..$......|
+000002a0  bd 82 67 3f 47 58 1a 2e  6b 61 f6 8e 4e 27 7f 49  |..g?GX..ka..N'.I|
+000002b0  b5 45 f1 0b 9a 33 ff 53  ac 65 e2 82 7a 18 5c 04  |.E...3.S.e..z.\.|
+000002c0  03 00 8b 30 81 88 02 42  00 e1 2d ff 5d e7 77 f1  |...0...B..-.].w.|
+000002d0  12 d9 e4 c2 4d cd 9c b5  ee e4 fd 21 b2 d8 53 a9  |....M......!..S.|
+000002e0  42 e7 c5 9b 51 c3 59 37  a5 08 d4 e6 29 12 c5 56  |B...Q.Y7....)..V|
+000002f0  b8 fe f0 bb 77 87 a3 ee  09 b0 8c cd 1c 39 9e b5  |....w........9..|
+00000300  d9 15 63 53 cb d7 f1 55  5b 48 02 42 01 19 10 8a  |..cS...U[H.B....|
+00000310  7a ee 95 b1 77 44 d4 a3  bf d1 f3 f1 b0 d8 c7 7e  |z...wD.........~|
+00000320  42 c0 83 04 f5 f7 9c c0  ce 6a 98 47 9d 21 29 84  |B........j.G.!).|
+00000330  c8 be 6b 67 4e fc c6 26  ec 63 df 00 33 e6 d2 f7  |..kgN..&.c..3...|
+00000340  34 93 85 9b 1b 0f e0 89  42 b6 0b 94 1b 80 16 03  |4.......B.......|
+00000350  03 00 04 0e 00 00 00                              |.......|
 >>> Flow 3 (client to server)
 00000000  16 03 03 00 46 10 00 00  42 41 04 1e 18 37 ef 0d  |....F...BA...7..|
 00000010  19 51 88 35 75 71 b5 e5  54 5b 12 2e 8f 09 67 fd  |.Q.5uq..T[....g.|
@@ -69,21 +70,21 @@
 00000030  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
 00000040  a6 b5 68 1a 41 03 56 6b  dc 5a 89 14 03 03 00 01  |..h.A.Vk.Z......|
 00000050  01 16 03 03 00 40 00 00  00 00 00 00 00 00 00 00  |..... at ..........|
-00000060  00 00 00 00 00 00 20 a3  f8 5a e2 ea f3 09 19 3e  |...... ..Z.....>|
-00000070  4a 54 69 70 06 5b 17 35  0f ed e7 30 3b 6f eb a1  |JTip.[.5...0;o..|
-00000080  cb 9c 35 81 10 2e 34 f7  12 a5 e4 63 20 b2 65 31  |..5...4....c .e1|
-00000090  19 da 30 43 39 59                                 |..0C9Y|
+00000060  00 00 00 00 00 00 50 73  9c 9f a8 d7 78 ac 06 14  |......Ps....x...|
+00000070  8f ae fc fb ef 7d 99 db  b7 c9 91 dd f2 fe da 1b  |.....}..........|
+00000080  aa 9e 7d e4 5c 2f 5f dd  74 aa fe 03 51 e7 cd 98  |..}.\/_.t...Q...|
+00000090  e9 21 19 c9 6f 59                                 |.!..oY|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 40 8d 4d 31 07 df  |.......... at .M1..|
-00000010  ab 41 f5 19 9c 1a 57 fc  33 ab 5f e6 bd 45 b9 fa  |.A....W.3._..E..|
-00000020  7f db c0 df 72 f2 3b ef  aa d4 5e 34 e6 3d 44 7c  |....r.;...^4.=D||
-00000030  12 05 c7 57 da 54 b1 e3  66 f0 0a ab cd 15 a5 bf  |...W.T..f.......|
-00000040  c5 c2 07 a9 d9 a7 2e 5e  29 da da                 |.......^)..|
+00000000  14 03 03 00 01 01 16 03  03 00 40 47 18 b5 1b 75  |.......... at G...u|
+00000010  b8 a3 63 ab 77 d3 47 cb  14 26 b4 88 fe 15 db 22  |..c.w.G..&....."|
+00000020  76 3b 25 d3 68 8e f2 a7  d5 03 2b 82 7b b1 0f 10  |v;%.h.....+.{...|
+00000030  49 6a 3d 95 d0 4b 55 0e  14 eb bb a7 34 bb 57 b3  |Ij=..KU.....4.W.|
+00000040  5d fb 7e 15 80 5a fa f3  3a df 90                 |].~..Z..:..|
 >>> Flow 5 (client to server)
 00000000  17 03 03 00 30 00 00 00  00 00 00 00 00 00 00 00  |....0...........|
-00000010  00 00 00 00 00 dc 03 7b  29 2c 49 64 58 2d dc f7  |.......{),IdX-..|
-00000020  26 a1 3b ec 2d e8 30 c4  6c a3 ff e2 bc b5 a4 a6  |&.;.-.0.l.......|
-00000030  93 ce 14 bd da 15 03 03  00 30 00 00 00 00 00 00  |.........0......|
-00000040  00 00 00 00 00 00 00 00  00 00 a6 77 10 30 15 eb  |...........w.0..|
-00000050  ed cf 73 5b 74 5d 09 52  4a 5b e2 f0 e4 67 f8 7a  |..s[t].RJ[...g.z|
-00000060  5e 5e fc ba 7f 80 0a d2  f4 fb                    |^^........|
+00000010  00 00 00 00 00 70 74 e2  60 fc 3a 7a b7 5e 16 07  |.....pt.`.:z.^..|
+00000020  22 92 07 fe 92 53 c4 43  1b 8f 94 07 84 48 2b 50  |"....S.C.....H+P|
+00000030  ab 1d 6d 49 ed 15 03 03  00 30 00 00 00 00 00 00  |..mI.....0......|
+00000040  00 00 00 00 00 00 00 00  00 00 ce a8 ba 91 0b e4  |................|
+00000050  8c 38 23 9b 8b 2c 0a 0c  63 79 61 f4 b6 25 f7 41  |.8#..,..cya..%.A|
+00000060  04 9f b0 8f e0 e5 24 44  2f e9                    |......$D/.|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM
index fb5af17..607ecdc 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM
+++ b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM
@@ -1,18 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
 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 1a c0 2f  |.............../|
-00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
-00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
-00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
-00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
-00000070  03 02 01 02 03 ff 01 00  01 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 36  |...../.5.......6|
+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 0e 00  |................|
+00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
+00000080  01 00 00 12 00 00                                 |......|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 59 02 00 00  55 03 03 53 04 f1 02 48  |....Y...U..S...H|
-00000010  03 36 01 05 56 6f f0 54  d2 c3 d3 41 c2 e2 69 7b  |.6..Vo.T...A..i{|
-00000020  50 f8 03 ef 3f 5d 7c e6  9c cb fe 20 82 a0 81 fd  |P...?]|.... ....|
-00000030  72 4b b8 e6 29 76 3b 0f  1d 0a b7 82 9d 0b cf a0  |rK..)v;.........|
-00000040  65 b1 56 53 c9 d5 58 7b  f0 b6 2d cf c0 2b 00 00  |e.VS..X{..-..+..|
+00000000  16 03 03 00 59 02 00 00  55 03 03 91 8a 4f 94 29  |....Y...U....O.)|
+00000010  32 fa 66 7a 7f b8 a7 04  5c 34 b9 7e 12 83 35 1f  |2.fz....\4.~..5.|
+00000020  93 b0 af e0 9f 71 07 5e  2f d7 ca 20 52 dc 0d e7  |.....q.^/.. R...|
+00000030  f8 16 db 90 9a 78 2f 03  0b f0 ae a7 2f c6 b4 4c  |.....x/...../..L|
+00000040  62 e7 de 32 d5 68 61 f3  07 e4 60 d2 c0 2b 00 00  |b..2.ha...`..+..|
 00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
 00000060  03 02 0e 0b 00 02 0a 00  02 07 00 02 04 30 82 02  |.............0..|
 00000070  00 30 82 01 62 02 09 00  b8 bf 2d 47 a0 d2 eb f4  |.0..b.....-G....|
@@ -47,38 +48,38 @@
 00000240  13 83 0d 94 06 bb d4 37  7a f6 ec 7a c9 86 2e dd  |.......7z..z....|
 00000250  d7 11 69 7f 85 7c 56 de  fb 31 78 2b e4 c7 78 0d  |..i..|V..1x+..x.|
 00000260  ae cb be 9e 4e 36 24 31  7b 6a 0f 39 95 12 07 8f  |....N6$1{j.9....|
-00000270  2a 16 03 03 00 d7 0c 00  00 d3 03 00 17 41 04 86  |*............A..|
-00000280  36 b4 78 76 87 70 ed ae  0d 34 70 3d 16 e5 a4 db  |6.xv.p...4p=....|
-00000290  ae 28 58 4c 01 5a 56 73  a7 0d 34 59 a7 04 75 69  |.(XL.ZVs..4Y..ui|
-000002a0  f2 55 24 40 b0 33 c6 93  ff ae e0 14 f5 4b ce a8  |.U$@.3.......K..|
-000002b0  e2 e6 9a 67 1d 66 fb 8f  fd 56 59 e7 73 f2 2c 04  |...g.f...VY.s.,.|
-000002c0  03 00 8a 30 81 87 02 41  73 ab a8 3c 64 17 69 9f  |...0...As..<d.i.|
-000002d0  4d b2 9b 55 12 60 33 94  cf f3 83 40 2b 7b 1b af  |M..U.`3.... at +{..|
-000002e0  5c f4 cd 02 66 fb 83 04  35 fd ab 74 98 1a 7d f6  |\...f...5..t..}.|
-000002f0  9e 50 98 c3 98 e8 56 9c  f2 2a b0 30 9d 05 14 58  |.P....V..*.0...X|
-00000300  68 6a 88 04 49 07 78 bf  3a 02 42 01 be b2 05 9e  |hj..I.x.:.B.....|
-00000310  67 da 1e e9 5a 36 98 52  21 9f 43 75 43 ba bb 9a  |g...Z6.R!.CuC...|
-00000320  e6 e2 65 f4 e0 44 45 08  5a 1e 54 06 dd 5f 60 2e  |..e..DE.Z.T.._`.|
-00000330  7d e7 55 08 d3 7b 4e 0a  c7 da d4 27 34 d4 bd b0  |}.U..{N....'4...|
-00000340  12 2f 41 7a ed 71 32 ef  ee 12 74 66 00 16 03 03  |./Az.q2...tf....|
-00000350  00 04 0e 00 00 00                                 |......|
+00000270  2a 16 03 03 00 d8 0c 00  00 d4 03 00 17 41 04 26  |*............A.&|
+00000280  c1 67 14 4b 9e b0 45 8c  27 bf a3 a2 78 5b 56 ad  |.g.K..E.'...x[V.|
+00000290  d1 21 56 53 df 86 e9 91  de e3 f9 5d e6 f6 5d 79  |.!VS.......]..]y|
+000002a0  11 8b 60 f9 c2 9a c6 3f  6b 72 cd 7c d7 0e 13 64  |..`....?kr.|...d|
+000002b0  af e8 9f 40 35 e6 fb 04  0c 60 aa 19 61 dd 24 04  |... at 5....`..a.$.|
+000002c0  03 00 8b 30 81 88 02 42  00 9d e1 02 5d 8b b1 45  |...0...B....]..E|
+000002d0  e5 c7 b6 94 27 df 36 31  fd 5e 47 fe c8 0f 5f 17  |....'.61.^G..._.|
+000002e0  b1 92 56 76 29 45 3d 90  be 91 6e 2c a7 b2 e1 33  |..Vv)E=...n,...3|
+000002f0  3b f9 3c bb 80 58 c2 d8  a8 59 82 16 dc 9e dd 60  |;.<..X...Y.....`|
+00000300  ff 82 b9 0c 5a ca ff f3  02 2c 02 42 00 a4 c0 d3  |....Z....,.B....|
+00000310  aa 1d 69 52 c0 06 fa 93  e8 50 da a4 2f 72 c9 4a  |..iR.....P../r.J|
+00000320  2c 43 7f 95 05 f7 7a f3  4a 2e 2d ce 13 be 80 40  |,C....z.J.-....@|
+00000330  a4 3b b2 f0 73 8d f1 d4  7b a3 ff 01 e1 58 71 31  |.;..s...{....Xq1|
+00000340  fc d8 2f b3 ef 62 2e b7  ac f5 c4 bc b8 68 16 03  |../..b.......h..|
+00000350  03 00 04 0e 00 00 00                              |.......|
 >>> Flow 3 (client to server)
 00000000  16 03 03 00 46 10 00 00  42 41 04 1e 18 37 ef 0d  |....F...BA...7..|
 00000010  19 51 88 35 75 71 b5 e5  54 5b 12 2e 8f 09 67 fd  |.Q.5uq..T[....g.|
 00000020  a7 24 20 3e b2 56 1c ce  97 28 5e f8 2b 2d 4f 9e  |.$ >.V...(^.+-O.|
 00000030  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
 00000040  a6 b5 68 1a 41 03 56 6b  dc 5a 89 14 03 03 00 01  |..h.A.Vk.Z......|
-00000050  01 16 03 03 00 28 00 00  00 00 00 00 00 00 87 7a  |.....(.........z|
-00000060  82 d7 46 25 1d a6 bb c2  a8 a8 4e a5 d1 f8 02 db  |..F%......N.....|
-00000070  33 33 ca 78 b6 d3 bd 77  8a 33 23 a7 95 fb        |33.x...w.3#...|
+00000050  01 16 03 03 00 28 00 00  00 00 00 00 00 00 83 cf  |.....(..........|
+00000060  ef 50 c2 e7 da b9 74 7f  1c e0 b8 fb dc 39 c9 98  |.P....t......9..|
+00000070  0c a3 7d 8c c6 fa 6f f2  ee 44 a0 a0 03 18        |..}...o..D....|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 28 ce a1 9d 01 c0  |..........(.....|
-00000010  31 e5 d5 57 16 e1 a6 b3  8b 25 58 0f fa 2a de 3e  |1..W.....%X..*.>|
-00000020  0c d9 06 11 a6 b0 d7 b0  33 ad 31 73 5b 26 b4 d2  |........3.1s[&..|
-00000030  12 56 c8                                          |.V.|
+00000000  14 03 03 00 01 01 16 03  03 00 28 73 c4 48 24 3d  |..........(s.H$=|
+00000010  8f 5f f3 8c fc fd 63 be  64 39 d5 56 67 bd d7 c4  |._....c.d9.Vg...|
+00000020  0d 57 88 1a 45 a6 f3 ad  11 b2 5a 41 58 33 f3 d3  |.W..E.....ZAX3..|
+00000030  58 fa 21                                          |X.!|
 >>> Flow 5 (client to server)
-00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 d5 04 4c  |...............L|
-00000010  7b 35 b4 d7 90 ae fe 00  d2 f2 4b 76 f1 36 5e 24  |{5........Kv.6^$|
-00000020  4a aa 94 15 03 03 00 1a  00 00 00 00 00 00 00 02  |J...............|
-00000030  d3 1c 41 37 ab f6 17 79  f0 01 a4 19 a5 75 7a 8e  |..A7...y.....uz.|
-00000040  a3 b2                                             |..|
+00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 65 5e 55  |.............e^U|
+00000010  32 be 00 77 6e 1d 8e 8f  95 33 24 3d 7a c2 b0 3f  |2..wn....3$=z..?|
+00000020  ca aa 97 15 03 03 00 1a  00 00 00 00 00 00 00 02  |................|
+00000030  b2 71 6e 42 6a 0d cf c9  ac 14 a4 b5 9c c9 71 60  |.qnBj.........q`|
+00000040  d7 c2                                             |..|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES256-GCM-SHA384 b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES256-GCM-SHA384
new file mode 100644
index 0000000..df2f737
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES256-GCM-SHA384
@@ -0,0 +1,85 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
+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 36  |...../.5.......6|
+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 0e 00  |................|
+00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
+00000080  01 00 00 12 00 00                                 |......|
+>>> Flow 2 (server to client)
+00000000  16 03 03 00 59 02 00 00  55 03 03 11 50 81 a7 ef  |....Y...U...P...|
+00000010  3f bd a5 a9 41 11 e6 86  b2 a3 d8 bf 29 c3 d4 f4  |?...A.......)...|
+00000020  b6 20 2d cb 94 1b 0e dd  99 d1 0b 20 78 92 23 31  |. -........ x.#1|
+00000030  e3 fc 99 67 1f fd f3 2a  fc 9c 4c 74 6e 32 e4 f8  |...g...*..Ltn2..|
+00000040  ed 6d 2e 6d ad a9 a9 bf  63 27 7e 44 c0 2c 00 00  |.m.m....c'~D.,..|
+00000050  0d ff 01 00 01 00 00 0b  00 04 03 00 01 02 16 03  |................|
+00000060  03 02 0e 0b 00 02 0a 00  02 07 00 02 04 30 82 02  |.............0..|
+00000070  00 30 82 01 62 02 09 00  b8 bf 2d 47 a0 d2 eb f4  |.0..b.....-G....|
+00000080  30 09 06 07 2a 86 48 ce  3d 04 01 30 45 31 0b 30  |0...*.H.=..0E1.0|
+00000090  09 06 03 55 04 06 13 02  41 55 31 13 30 11 06 03  |...U....AU1.0...|
+000000a0  55 04 08 13 0a 53 6f 6d  65 2d 53 74 61 74 65 31  |U....Some-State1|
+000000b0  21 30 1f 06 03 55 04 0a  13 18 49 6e 74 65 72 6e  |!0...U....Intern|
+000000c0  65 74 20 57 69 64 67 69  74 73 20 50 74 79 20 4c  |et Widgits Pty L|
+000000d0  74 64 30 1e 17 0d 31 32  31 31 32 32 31 35 30 36  |td0...1211221506|
+000000e0  33 32 5a 17 0d 32 32 31  31 32 30 31 35 30 36 33  |32Z..22112015063|
+000000f0  32 5a 30 45 31 0b 30 09  06 03 55 04 06 13 02 41  |2Z0E1.0...U....A|
+00000100  55 31 13 30 11 06 03 55  04 08 13 0a 53 6f 6d 65  |U1.0...U....Some|
+00000110  2d 53 74 61 74 65 31 21  30 1f 06 03 55 04 0a 13  |-State1!0...U...|
+00000120  18 49 6e 74 65 72 6e 65  74 20 57 69 64 67 69 74  |.Internet Widgit|
+00000130  73 20 50 74 79 20 4c 74  64 30 81 9b 30 10 06 07  |s Pty Ltd0..0...|
+00000140  2a 86 48 ce 3d 02 01 06  05 2b 81 04 00 23 03 81  |*.H.=....+...#..|
+00000150  86 00 04 00 c4 a1 ed be  98 f9 0b 48 73 36 7e c3  |...........Hs6~.|
+00000160  16 56 11 22 f2 3d 53 c3  3b 4d 21 3d cd 6b 75 e6  |.V.".=S.;M!=.ku.|
+00000170  f6 b0 dc 9a df 26 c1 bc  b2 87 f0 72 32 7c b3 64  |.....&.....r2|.d|
+00000180  2f 1c 90 bc ea 68 23 10  7e fe e3 25 c0 48 3a 69  |/....h#.~..%.H:i|
+00000190  e0 28 6d d3 37 00 ef 04  62 dd 0d a0 9c 70 62 83  |.(m.7...b....pb.|
+000001a0  d8 81 d3 64 31 aa 9e 97  31 bd 96 b0 68 c0 9b 23  |...d1...1...h..#|
+000001b0  de 76 64 3f 1a 5c 7f e9  12 0e 58 58 b6 5f 70 dd  |.vd?.\....XX._p.|
+000001c0  9b d8 ea d5 d7 f5 d5 cc  b9 b6 9f 30 66 5b 66 9a  |...........0f[f.|
+000001d0  20 e2 27 e5 bf fe 3b 30  09 06 07 2a 86 48 ce 3d  | .'...;0...*.H.=|
+000001e0  04 01 03 81 8c 00 30 81  88 02 42 01 88 a2 4f eb  |......0...B...O.|
+000001f0  e2 45 c5 48 7d 1b ac f5  ed 98 9d ae 47 70 c0 5e  |.E.H}.......Gp.^|
+00000200  1b b6 2f bd f1 b6 4d b7  61 40 d3 11 a2 ce ee 0b  |../...M.a at ......|
+00000210  7e 92 7e ff 76 9d c3 3b  7e a5 3f ce fa 10 e2 59  |~.~.v..;~.?....Y|
+00000220  ec 47 2d 7c ac da 4e 97  0e 15 a0 6f d0 02 42 01  |.G-|..N....o..B.|
+00000230  4d fc be 67 13 9c 2d 05  0e bd 3f a3 8c 25 c1 33  |M..g..-...?..%.3|
+00000240  13 83 0d 94 06 bb d4 37  7a f6 ec 7a c9 86 2e dd  |.......7z..z....|
+00000250  d7 11 69 7f 85 7c 56 de  fb 31 78 2b e4 c7 78 0d  |..i..|V..1x+..x.|
+00000260  ae cb be 9e 4e 36 24 31  7b 6a 0f 39 95 12 07 8f  |....N6$1{j.9....|
+00000270  2a 16 03 03 00 d7 0c 00  00 d3 03 00 17 41 04 fc  |*............A..|
+00000280  e6 25 27 3c 76 10 a8 9e  d3 a4 a8 68 31 06 85 fc  |.%'<v......h1...|
+00000290  35 2a 76 b3 ad 08 c5 70  ed 3d 61 e0 29 cc 47 52  |5*v....p.=a.).GR|
+000002a0  68 21 ab 48 19 f9 28 ba  54 8c 56 8e b0 7d 55 7f  |h!.H..(.T.V..}U.|
+000002b0  75 f5 42 38 61 ff e2 06  98 1a ae fc bc a0 3a 04  |u.B8a.........:.|
+000002c0  03 00 8a 30 81 87 02 42  01 0c b2 7f c9 d3 1b 83  |...0...B........|
+000002d0  1e 24 a3 d7 1c 81 f0 02  ae ed 42 6f e9 d9 91 4d  |.$........Bo...M|
+000002e0  16 5f aa 8e 5a de 3b 00  0e e6 2d fb 05 30 f3 cf  |._..Z.;...-..0..|
+000002f0  31 a2 ec 99 87 ea 42 03  0a 57 82 e5 12 27 98 8a  |1.....B..W...'..|
+00000300  c6 56 4b 9a 0b d7 37 5f  46 50 02 41 57 61 13 3c  |.VK...7_FP.AWa.<|
+00000310  48 d0 b3 b0 d5 21 72 49  80 7b d7 ef 8f 0d a0 c5  |H....!rI.{......|
+00000320  88 a1 5d ca 61 6d fb 8b  51 15 5d e5 a2 61 c4 78  |..].am..Q.]..a.x|
+00000330  8f d9 e3 78 df 7d a0 8f  0c c0 cc 18 36 41 e6 bb  |...x.}......6A..|
+00000340  6d e3 9d 04 c2 c4 d0 66  35 45 9a 08 b2 16 03 03  |m......f5E......|
+00000350  00 04 0e 00 00 00                                 |......|
+>>> Flow 3 (client to server)
+00000000  16 03 03 00 46 10 00 00  42 41 04 1e 18 37 ef 0d  |....F...BA...7..|
+00000010  19 51 88 35 75 71 b5 e5  54 5b 12 2e 8f 09 67 fd  |.Q.5uq..T[....g.|
+00000020  a7 24 20 3e b2 56 1c ce  97 28 5e f8 2b 2d 4f 9e  |.$ >.V...(^.+-O.|
+00000030  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
+00000040  a6 b5 68 1a 41 03 56 6b  dc 5a 89 14 03 03 00 01  |..h.A.Vk.Z......|
+00000050  01 16 03 03 00 28 00 00  00 00 00 00 00 00 a3 3f  |.....(.........?|
+00000060  be 65 91 cd fe 37 43 e0  ea 6f 15 9d c2 aa 6a 02  |.e...7C..o....j.|
+00000070  20 b8 bc b5 c8 9a 1c d4  c4 e5 9b 2e 39 e7        | ...........9.|
+>>> Flow 4 (server to client)
+00000000  14 03 03 00 01 01 16 03  03 00 28 7c b7 1f 13 9e  |..........(|....|
+00000010  21 d2 eb db 32 fc 36 d0  53 e1 11 04 ce d0 61 33  |!...2.6.S.....a3|
+00000020  1e 30 3d 91 c3 6a 0d 98  55 f5 e0 5c ca 77 fa 72  |.0=..j..U..\.w.r|
+00000030  63 6a be                                          |cj.|
+>>> Flow 5 (client to server)
+00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 d9 db db  |................|
+00000010  4b 3a ae 5c a4 dc 96 33  ed b5 a0 70 64 1f 96 2f  |K:.\...3...pd../|
+00000020  b6 cd 1e 15 03 03 00 1a  00 00 00 00 00 00 00 02  |................|
+00000030  18 a0 d1 98 a6 71 c9 56  36 bd 1a 46 4b 5b 45 29  |.....q.V6..FK[E)|
+00000040  1f dd                                             |..|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES
index 5336bbb..994ebb1 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES
+++ b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES
@@ -1,18 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
 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 1a c0 2f  |.............../|
-00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
-00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
-00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
-00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
-00000070  03 02 01 02 03 ff 01 00  01 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 36  |...../.5.......6|
+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 0e 00  |................|
+00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
+00000080  01 00 00 12 00 00                                 |......|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 59 02 00 00  55 03 03 53 04 f1 02 41  |....Y...U..S...A|
-00000010  95 cc 56 30 65 46 24 75  d5 9e 3c a7 5b 6c 99 fe  |..V0eF$u..<.[l..|
-00000020  86 35 23 42 3a 8f 4d 4c  b9 98 7d 20 a7 46 43 72  |.5#B:.ML..} .FCr|
-00000030  66 bb b6 ad ff ad cf 63  37 fe 6b b4 78 94 08 49  |f......c7.k.x..I|
-00000040  54 06 ed f4 85 73 38 4a  c6 fe b6 98 c0 13 00 00  |T....s8J........|
+00000000  16 03 03 00 59 02 00 00  55 03 03 e6 ae 89 0d 22  |....Y...U......"|
+00000010  e5 e0 cd 57 a3 ca 71 4f  17 2f 64 77 f8 30 89 ef  |...W..qO./dw.0..|
+00000020  e8 19 70 ac dd 2c c5 9f  84 7d 1d 20 1c 59 3c fe  |..p..,...}. .Y<.|
+00000030  a9 ec 10 dd 38 3b 43 fe  6b 09 e5 e4 83 d9 7a 78  |....8;C.k.....zx|
+00000040  86 08 33 da 9b e1 09 d8  c9 07 34 19 c0 13 00 00  |..3.......4.....|
 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..............|
@@ -58,20 +59,20 @@
 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 48  |.............A.H|
-00000330  68 d8 8a 10 b4 bf eb 8d  d1 98 b0 a6 f4 47 5d 91  |h............G].|
-00000340  61 da 50 d9 85 7b 5d 90  02 2c 38 c9 af 81 d3 55  |a.P..{]..,8....U|
-00000350  07 62 b1 62 58 7f 39 94  d7 91 96 a8 1f 47 60 a5  |.b.bX.9......G`.|
-00000360  c0 04 f2 fb cb 15 75 a6  16 3f 94 53 7c ff dd 04  |......u..?.S|...|
-00000370  01 00 80 b9 82 fa 0b f8  8c 94 2c 6e 05 81 7d 80  |..........,n..}.|
-00000380  5d 9a 77 78 af c8 33 5d  89 7e 2e 3c e5 72 66 a8  |].wx..3].~.<.rf.|
-00000390  f1 5c 02 04 02 70 76 7b  45 ff 0d 29 a0 cb 0d db  |.\...pv{E..)....|
-000003a0  7a 4c c4 13 19 cd 47 b2  f1 c9 43 4f 95 d2 f1 c6  |zL....G...CO....|
-000003b0  bc ae 31 4a 9d de 80 b2  a4 b7 b6 dd 8c 03 3e 2a  |..1J..........>*|
-000003c0  46 5e d1 e7 5b c5 9e 06  58 f3 55 b2 77 09 f3 98  |F^..[...X.U.w...|
-000003d0  d5 7f 5a 74 64 7e 48 22  8f 7d a8 68 b6 1d 90 df  |..Ztd~H".}.h....|
-000003e0  2c 91 d7 c5 07 3d d1 6f  e9 c1 91 03 3c 23 5a 56  |,....=.o....<#ZV|
-000003f0  3b b2 c2 16 03 03 00 04  0e 00 00 00              |;...........|
+00000320  d9 16 03 03 00 cd 0c 00  00 c9 03 00 17 41 04 77  |.............A.w|
+00000330  87 a7 ad f6 f8 34 82 05  ef bb 14 6d c7 8b 7b 2a  |.....4.....m..{*|
+00000340  4d ca 41 65 58 3c 83 fa  4d ce 0c 74 46 85 fe 38  |M.AeX<..M..tF..8|
+00000350  95 80 ee 7c c2 bf f2 be  a3 c6 bf f3 aa 07 23 40  |...|..........#@|
+00000360  7e cc 74 4a 4e 2e 69 af  6b e0 42 8a fc 41 be 04  |~.tJN.i.k.B..A..|
+00000370  01 00 80 99 ed a8 3a ef  93 1b 4c 17 80 9e cc eb  |......:...L.....|
+00000380  da 39 fb c8 9a 73 e1 96  20 3e 41 fa 8b 1a b1 68  |.9...s.. >A....h|
+00000390  cd 47 bc 4b 7b 0c 14 da  87 d3 36 09 5e 37 33 88  |.G.K{.....6.^73.|
+000003a0  7f 88 07 87 46 ec e5 72  a8 59 92 07 fa 4d 02 dc  |....F..r.Y...M..|
+000003b0  bf 3a f5 e4 77 0b a6 85  ce 43 ee 1b 90 30 7f ec  |.:..w....C...0..|
+000003c0  88 79 f8 88 59 af 6b 7f  2d 88 de 92 cd c8 36 cf  |.y..Y.k.-.....6.|
+000003d0  ba b9 08 6a c4 3d d7 9a  48 50 e1 67 d0 62 a5 b3  |...j.=..HP.g.b..|
+000003e0  b0 5f 2e 16 ee 4d 7d a2  cf d9 93 19 89 b7 64 0f  |._...M}.......d.|
+000003f0  0f 8e 3d 16 03 03 00 04  0e 00 00 00              |..=.........|
 >>> Flow 3 (client to server)
 00000000  16 03 03 00 46 10 00 00  42 41 04 1e 18 37 ef 0d  |....F...BA...7..|
 00000010  19 51 88 35 75 71 b5 e5  54 5b 12 2e 8f 09 67 fd  |.Q.5uq..T[....g.|
@@ -79,21 +80,21 @@
 00000030  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
 00000040  a6 b5 68 1a 41 03 56 6b  dc 5a 89 14 03 03 00 01  |..h.A.Vk.Z......|
 00000050  01 16 03 03 00 40 00 00  00 00 00 00 00 00 00 00  |..... at ..........|
-00000060  00 00 00 00 00 00 59 e6  92 05 27 ec 09 2c b0 a5  |......Y...'..,..|
-00000070  2a fb 7e f1 03 53 16 63  68 a1 86 13 bb da 98 27  |*.~..S.ch......'|
-00000080  6d 42 08 35 6a ec 58 61  2a 4d 44 ec ae c5 b9 d2  |mB.5j.Xa*MD.....|
-00000090  76 57 1f 75 9f 8d                                 |vW.u..|
+00000060  00 00 00 00 00 00 f2 20  58 ec f1 88 a6 26 79 9d  |....... X....&y.|
+00000070  2e 9b 02 b5 5e da e2 c1  c5 8d c8 93 6f 6d 07 4e  |....^.......om.N|
+00000080  fa dd ee cb b1 ae c7 3b  09 b2 cc 64 7a cd 98 91  |.......;...dz...|
+00000090  cb f8 3c 34 3b ed                                 |..<4;.|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 40 6e 03 d0 e6 98  |.......... at n....|
-00000010  1f f5 39 7b 06 9f 95 f0  7a 88 35 7c 55 db c3 2f  |..9{....z.5|U../|
-00000020  00 ef 5b d3 62 87 a2 94  da 2f f6 4a 89 c9 a8 3d  |..[.b..../.J...=|
-00000030  3a 92 db 77 35 92 01 4b  f5 c5 6b 95 09 9f cd 79  |:..w5..K..k....y|
-00000040  3c af 37 5b 27 bf 93 3e  04 55 71                 |<.7['..>.Uq|
+00000000  14 03 03 00 01 01 16 03  03 00 40 4c a1 8d bd 49  |.......... at L...I|
+00000010  33 d3 72 fb 2f 23 7e 11  29 fc d2 ff 9b 67 30 c8  |3.r./#~.)....g0.|
+00000020  be c1 bc 51 6e 92 a5 f4  9d e3 b3 f9 d2 d4 c4 a5  |...Qn...........|
+00000030  83 23 90 b3 17 00 35 18  c5 ef 8b 18 a3 cf ed 9d  |.#....5.........|
+00000040  a9 52 c9 11 0a c9 55 c2  76 df 78                 |.R....U.v.x|
 >>> Flow 5 (client to server)
 00000000  17 03 03 00 30 00 00 00  00 00 00 00 00 00 00 00  |....0...........|
-00000010  00 00 00 00 00 bc c9 d0  8e 80 14 de 32 18 49 e8  |............2.I.|
-00000020  20 dc 5e 6c e4 6d 14 00  df 51 71 fb 86 95 16 4c  | .^l.m...Qq....L|
-00000030  04 8e 71 e1 48 15 03 03  00 30 00 00 00 00 00 00  |..q.H....0......|
-00000040  00 00 00 00 00 00 00 00  00 00 b7 6d 30 72 61 53  |...........m0raS|
-00000050  d8 0a d4 1d ae e5 d4 22  46 c9 d5 4e 4a 86 f5 ac  |......."F..NJ...|
-00000060  72 98 c6 db 38 29 97 2c  84 0b                    |r...8).,..|
+00000010  00 00 00 00 00 60 40 d0  bf 8f ef 05 2b 89 d7 bb  |.....`@.....+...|
+00000020  27 d0 1f b2 cf c3 ff 8e  be 69 16 a9 b3 03 e8 3c  |'........i.....<|
+00000030  30 1d 58 39 4a 15 03 03  00 30 00 00 00 00 00 00  |0.X9J....0......|
+00000040  00 00 00 00 00 00 00 00  00 00 de 61 51 a1 3c fc  |...........aQ.<.|
+00000050  1c 7b e6 f2 7d e0 aa 80  2d 9c e9 22 09 5c dd 8a  |.{..}...-..".\..|
+00000060  55 cc c4 77 34 97 05 88  98 d3                    |U..w4.....|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-RSA-RC4 b/src/crypto/tls/testdata/Client-TLSv12-RSA-RC4
index 0377f05..73e34c0 100644
--- a/src/crypto/tls/testdata/Client-TLSv12-RSA-RC4
+++ b/src/crypto/tls/testdata/Client-TLSv12-RSA-RC4
@@ -1,18 +1,19 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 75 01 00 00  71 03 03 00 00 00 00 00  |....u...q.......|
+00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
 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 1a c0 2f  |.............../|
-00000030  c0 2b c0 11 c0 07 c0 13  c0 09 c0 14 c0 0a 00 05  |.+..............|
-00000040  00 2f 00 35 c0 12 00 0a  01 00 00 2e 00 05 00 05  |./.5............|
-00000050  01 00 00 00 00 00 0a 00  08 00 06 00 17 00 18 00  |................|
-00000060  19 00 0b 00 02 01 00 00  0d 00 0a 00 08 04 01 04  |................|
-00000070  03 02 01 02 03 ff 01 00  01 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 36  |...../.5.......6|
+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 0e 00  |................|
+00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
+00000080  01 00 00 12 00 00                                 |......|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 51 02 00 00  4d 03 03 53 04 f1 02 9d  |....Q...M..S....|
-00000010  2e 4e d9 17 4a 35 fa 9d  94 f6 45 0a f6 6b 5d 1c  |.N..J5....E..k].|
-00000020  1e 15 19 8d 6d 94 cc 90  d9 39 94 20 8b 4b de 76  |....m....9. .K.v|
-00000030  d5 64 5d b7 19 df e7 eb  7e a0 22 c4 09 38 a0 12  |.d].....~."..8..|
-00000040  d5 59 10 c8 31 06 dc fc  e4 9d d1 80 00 05 00 00  |.Y..1...........|
+00000000  16 03 03 00 51 02 00 00  4d 03 03 e8 ae 4c 97 41  |....Q...M....L.A|
+00000010  78 0f 08 84 d4 4a 80 6d  a2 e1 d0 67 40 8f 01 8b  |x....J.m...g at ...|
+00000020  20 54 cb 28 16 52 04 fd  3c c2 84 20 30 96 f0 51  | T.(.R..<.. 0..Q|
+00000030  72 86 6a d8 47 b9 47 e3  a4 ad 97 77 a9 77 1a f9  |r.j.G.G....w.w..|
+00000040  ba 63 33 32 4f 43 09 1c  e1 bd 1b 3b 00 05 00 00  |.c32OC.....;....|
 00000050  05 ff 01 00 01 00 16 03  03 02 be 0b 00 02 ba 00  |................|
 00000060  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
 00000070  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
@@ -69,15 +70,15 @@
 00000060  e6 bd 77 82 6f 23 b6 e0  bd a2 92 b7 3a ac e8 56  |..w.o#......:..V|
 00000070  f1 af 54 5e 46 87 e9 3b  33 e7 b8 28 b7 d6 c8 90  |..T^F..;3..(....|
 00000080  35 d4 1c 43 d1 30 6f 55  4e 0a 70 14 03 03 00 01  |5..C.0oUN.p.....|
-00000090  01 16 03 03 00 24 37 14  b2 97 7b b5 f0 9a 38 05  |.....$7...{...8.|
-000000a0  22 35 69 9c 95 2f 86 4b  37 98 22 db 4e 9a 46 9c  |"5i../.K7.".N.F.|
-000000b0  b9 81 74 72 58 18 53 0c  5c 3c                    |..trX.S.\<|
+00000090  01 16 03 03 00 24 54 8c  7f 71 03 7c 98 e5 97 65  |.....$T..q.|...e|
+000000a0  51 13 b2 9d 4a b8 c9 c1  e6 11 1b 50 c8 1b c0 46  |Q...J......P...F|
+000000b0  a7 cb 13 97 92 a0 51 d4  a9 e5                    |......Q...|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 24 3c b3 e7 77 5a  |..........$<..wZ|
-00000010  7c 36 5a 74 74 26 8d 5b  5a 09 96 60 e8 24 45 2f  ||6Ztt&.[Z..`.$E/|
-00000020  c2 39 14 5e db 58 12 49  ad a8 b6 ea ef 58 16     |.9.^.X.I.....X.|
+00000000  14 03 03 00 01 01 16 03  03 00 24 37 ca ae 55 79  |..........$7..Uy|
+00000010  e7 0a 70 55 1e d1 76 61  57 46 d2 c0 d0 ed 3d 70  |..pU..vaWF....=p|
+00000020  1f 02 f2 06 5b 3e 50 ec  13 4b 67 e2 7c bd 45     |....[>P..Kg.|.E|
 >>> Flow 5 (client to server)
-00000000  17 03 03 00 1a 6d 29 d7  ba 2f 85 02 b6 f0 82 64  |.....m)../.....d|
-00000010  6c 55 ae ab f6 fd 14 ff  b8 38 f0 f8 a6 ea cc 15  |lU.......8......|
-00000020  03 03 00 16 10 c5 d9 41  7b e2 89 67 dc 29 8e f8  |.......A{..g.)..|
-00000030  b5 ab 32 91 44 2c 27 84  49 f7                    |..2.D,'.I.|
+00000000  17 03 03 00 1a c4 13 68  ec e0 38 a1 07 35 da d7  |.......h..8..5..|
+00000010  c4 6b f9 5c ed a7 8a cb  96 7a 22 7c ca a5 30 15  |.k.\.....z"|..0.|
+00000020  03 03 00 16 f7 a7 8d 41  b0 c1 4b 61 60 b0 b2 ed  |.......A..Ka`...|
+00000030  4a ab c3 54 d5 20 eb 67  b7 8f                    |J..T. .g..|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-SCT b/src/crypto/tls/testdata/Client-TLSv12-SCT
new file mode 100644
index 0000000..826c9f0
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv12-SCT
@@ -0,0 +1,118 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 81 01 00 00  7d 03 03 00 00 00 00 00  |........}.......|
+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 36  |...../.5.......6|
+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 0e 00  |................|
+00000070  0c 04 01 04 03 05 01 05  03 02 01 02 03 ff 01 00  |................|
+00000080  01 00 00 12 00 00                                 |......|
+>>> Flow 2 (server to client)
+00000000  16 03 03 01 c6 02 00 01  c2 03 03 1b f6 69 c1 c2  |.............i..|
+00000010  36 77 72 32 69 95 c9 e7  db 9b 5d bd 59 ba 08 02  |6wr2i.....].Y...|
+00000020  1e 76 11 c4 8e 49 08 22  8e 8a 5a 20 44 ec d9 13  |.v...I."..Z D...|
+00000030  23 ad 05 45 48 29 00 c6  11 3d 5a 5c a1 ee 34 2b  |#..EH)...=Z\..4+|
+00000040  58 ef 34 5b 7e 42 08 84  23 66 56 ee c0 2f 00 01  |X.4[~B..#fV../..|
+00000050  7a ff 01 00 01 00 00 0b  00 04 03 00 01 02 00 12  |z...............|
+00000060  01 69 01 67 00 75 00 a4  b9 09 90 b4 18 58 14 87  |.i.g.u.......X..|
+00000070  bb 13 a2 cc 67 70 0a 3c  35 98 04 f9 1b df b8 e3  |....gp.<5.......|
+00000080  77 cd 0e c8 0d dc 10 00  00 01 47 97 99 ee 16 00  |w.........G.....|
+00000090  00 04 03 00 46 30 44 02  20 1c 4b 82 5d 95 6e 67  |....F0D. .K.].ng|
+000000a0  5b db 04 95 4b f6 ce f4  32 3e 86 7a 7a 32 ab 18  |[...K...2>.zz2..|
+000000b0  60 74 de 08 da 05 91 4c  2f 02 20 73 54 1b 6e 7f  |`t.....L/. sT.n.|
+000000c0  a1 b0 7d 11 bc e6 f3 85  2f 97 66 1a f7 8a e4 10  |..}...../.f.....|
+000000d0  25 8f 12 f4 6f 39 0f d2  9e 18 f0 00 76 00 68 f6  |%...o9......v.h.|
+000000e0  98 f8 1f 64 82 be 3a 8c  ee b9 28 1d 4c fc 71 51  |...d..:...(.L.qQ|
+000000f0  5d 67 93 d4 44 d1 0a 67  ac bb 4f 4f fb c4 00 00  |]g..D..g..OO....|
+00000100  01 47 97 e1 b5 70 00 00  04 03 00 47 30 45 02 20  |.G...p.....G0E. |
+00000110  32 21 14 38 06 d8 72 2e  00 30 64 1a e2 e8 6d 4e  |2!.8..r..0d...mN|
+00000120  5a e1 d9 42 1e 82 4b 96  25 89 d5 26 13 d3 9c fa  |Z..B..K.%..&....|
+00000130  02 21 00 8f 12 28 64 51  4f 44 d5 8c 18 62 23 b2  |.!...(dQOD...b#.|
+00000140  43 93 33 05 f3 43 55 a1  d9 ee cd c5 71 35 91 dd  |C.3..CU.....q5..|
+00000150  49 d1 0b 00 76 00 ee 4b  bd b7 75 ce 60 ba e1 42  |I...v..K..u.`..B|
+00000160  69 1f ab e1 9e 66 a3 0f  7e 5f b0 72 d8 83 00 c4  |i....f..~_.r....|
+00000170  7b 89 7a a8 fd cb 00 00  01 48 5c 64 8a 87 00 00  |{.z......H\d....|
+00000180  04 03 00 47 30 45 02 20  29 89 d6 b0 53 d3 d2 e9  |...G0E. )...S...|
+00000190  91 bc f1 b5 40 be 1e 2e  e7 5c b4 74 27 ed 8f 9b  |.... at ....\.t'...|
+000001a0  02 e9 fa c2 4c ba a2 be  02 21 00 af 43 64 52 71  |....L....!..CdRq|
+000001b0  15 29 58 40 91 c7 08 16  96 03 a8 73 a5 65 a0 6c  |.)X at .......s.e.l|
+000001c0  b8 48 56 5a b6 29 83 64  6d 2a 9d 16 03 03 02 be  |.HVZ.).dm*......|
+000001d0  0b 00 02 ba 00 02 b7 00  02 b4 30 82 02 b0 30 82  |..........0...0.|
+000001e0  02 19 a0 03 02 01 02 02  09 00 85 b0 bb a4 8a 7f  |................|
+000001f0  b8 ca 30 0d 06 09 2a 86  48 86 f7 0d 01 01 05 05  |..0...*.H.......|
+00000200  00 30 45 31 0b 30 09 06  03 55 04 06 13 02 41 55  |.0E1.0...U....AU|
+00000210  31 13 30 11 06 03 55 04  08 13 0a 53 6f 6d 65 2d  |1.0...U....Some-|
+00000220  53 74 61 74 65 31 21 30  1f 06 03 55 04 0a 13 18  |State1!0...U....|
+00000230  49 6e 74 65 72 6e 65 74  20 57 69 64 67 69 74 73  |Internet Widgits|
+00000240  20 50 74 79 20 4c 74 64  30 1e 17 0d 31 30 30 34  | Pty Ltd0...1004|
+00000250  32 34 30 39 30 39 33 38  5a 17 0d 31 31 30 34 32  |24090938Z..11042|
+00000260  34 30 39 30 39 33 38 5a  30 45 31 0b 30 09 06 03  |4090938Z0E1.0...|
+00000270  55 04 06 13 02 41 55 31  13 30 11 06 03 55 04 08  |U....AU1.0...U..|
+00000280  13 0a 53 6f 6d 65 2d 53  74 61 74 65 31 21 30 1f  |..Some-State1!0.|
+00000290  06 03 55 04 0a 13 18 49  6e 74 65 72 6e 65 74 20  |..U....Internet |
+000002a0  57 69 64 67 69 74 73 20  50 74 79 20 4c 74 64 30  |Widgits Pty Ltd0|
+000002b0  81 9f 30 0d 06 09 2a 86  48 86 f7 0d 01 01 01 05  |..0...*.H.......|
+000002c0  00 03 81 8d 00 30 81 89  02 81 81 00 bb 79 d6 f5  |.....0.......y..|
+000002d0  17 b5 e5 bf 46 10 d0 dc  69 be e6 2b 07 43 5a d0  |....F...i..+.CZ.|
+000002e0  03 2d 8a 7a 43 85 b7 14  52 e7 a5 65 4c 2c 78 b8  |.-.zC...R..eL,x.|
+000002f0  23 8c b5 b4 82 e5 de 1f  95 3b 7e 62 a5 2c a5 33  |#........;~b.,.3|
+00000300  d6 fe 12 5c 7a 56 fc f5  06 bf fa 58 7b 26 3f b5  |...\zV.....X{&?.|
+00000310  cd 04 d3 d0 c9 21 96 4a  c7 f4 54 9f 5a bf ef 42  |.....!.J..T.Z..B|
+00000320  71 00 fe 18 99 07 7f 7e  88 7d 7d f1 04 39 c4 a2  |q......~.}}..9..|
+00000330  2e db 51 c9 7c e3 c0 4c  3b 32 66 01 cf af b1 1d  |..Q.|..L;2f.....|
+00000340  b8 71 9a 1d db db 89 6b  ae da 2d 79 02 03 01 00  |.q.....k..-y....|
+00000350  01 a3 81 a7 30 81 a4 30  1d 06 03 55 1d 0e 04 16  |....0..0...U....|
+00000360  04 14 b1 ad e2 85 5a cf  cb 28 db 69 ce 23 69 de  |......Z..(.i.#i.|
+00000370  d3 26 8e 18 88 39 30 75  06 03 55 1d 23 04 6e 30  |.&...90u..U.#.n0|
+00000380  6c 80 14 b1 ad e2 85 5a  cf cb 28 db 69 ce 23 69  |l......Z..(.i.#i|
+00000390  de d3 26 8e 18 88 39 a1  49 a4 47 30 45 31 0b 30  |..&...9.I.G0E1.0|
+000003a0  09 06 03 55 04 06 13 02  41 55 31 13 30 11 06 03  |...U....AU1.0...|
+000003b0  55 04 08 13 0a 53 6f 6d  65 2d 53 74 61 74 65 31  |U....Some-State1|
+000003c0  21 30 1f 06 03 55 04 0a  13 18 49 6e 74 65 72 6e  |!0...U....Intern|
+000003d0  65 74 20 57 69 64 67 69  74 73 20 50 74 79 20 4c  |et Widgits Pty L|
+000003e0  74 64 82 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0c 06  |td...........0..|
+000003f0  03 55 1d 13 04 05 30 03  01 01 ff 30 0d 06 09 2a  |.U....0....0...*|
+00000400  86 48 86 f7 0d 01 01 05  05 00 03 81 81 00 08 6c  |.H.............l|
+00000410  45 24 c7 6b b1 59 ab 0c  52 cc f2 b0 14 d7 87 9d  |E$.k.Y..R.......|
+00000420  7a 64 75 b5 5a 95 66 e4  c5 2b 8e ae 12 66 1f eb  |zdu.Z.f..+...f..|
+00000430  4f 38 b3 6e 60 d3 92 fd  f7 41 08 b5 25 13 b1 18  |O8.n`....A..%...|
+00000440  7a 24 fb 30 1d ba ed 98  b9 17 ec e7 d7 31 59 db  |z$.0.........1Y.|
+00000450  95 d3 1d 78 ea 50 56 5c  d5 82 5a 2d 5a 5f 33 c4  |...x.PV\..Z-Z_3.|
+00000460  b6 d8 c9 75 90 96 8c 0f  52 98 b5 cd 98 1f 89 20  |...u....R...... |
+00000470  5f f2 a0 1c a3 1b 96 94  dd a9 fd 57 e9 70 e8 26  |_..........W.p.&|
+00000480  6d 71 99 9b 26 6e 38 50  29 6c 90 a7 bd d9 16 03  |mq..&n8P)l......|
+00000490  03 00 cd 0c 00 00 c9 03  00 17 41 04 d7 61 5b 05  |..........A..a[.|
+000004a0  de 22 d3 3d 00 72 a5 be  0a c1 76 94 a1 34 41 6e  |.".=.r....v..4An|
+000004b0  55 f2 74 91 d2 6f 5c 47  87 c8 4b eb ab ab 10 b9  |U.t..o\G..K.....|
+000004c0  f9 0a bc 63 03 5f 90 5b  e3 6f e1 44 97 cc bf d2  |...c._.[.o.D....|
+000004d0  e8 0d f5 9c 2e 9d 07 2c  b2 00 90 0b 04 01 00 80  |.......,........|
+000004e0  67 3d c7 73 42 b9 b2 fd  4b dd 02 57 87 95 20 75  |g=.sB...K..W.. u|
+000004f0  da c1 e7 d3 33 09 01 5d  e9 32 d7 20 7f 92 a9 dd  |....3..].2. ....|
+00000500  bb 17 c5 ee f2 07 b2 04  1d 5e 1f c2 41 66 3f 14  |.........^..Af?.|
+00000510  90 cd 84 ac 49 46 04 3e  ce 89 7d 79 42 2a 8c 56  |....IF.>..}yB*.V|
+00000520  93 d3 9c 3b 57 38 9e 91  af 62 ad 86 40 29 3d 46  |...;W8...b..@)=F|
+00000530  c7 cc f4 3f a1 7d ee 53  3d 94 1c 85 b9 1d a9 5f  |...?.}.S=......_|
+00000540  10 8e ee 38 5e 98 5d 39  31 79 83 cd f9 02 a8 a9  |...8^.]91y......|
+00000550  b8 82 21 33 40 ed 27 54  a3 6e 64 cb e9 ce dd e1  |..!3 at .'T.nd.....|
+00000560  16 03 03 00 04 0e 00 00  00                       |.........|
+>>> Flow 3 (client to server)
+00000000  16 03 03 00 46 10 00 00  42 41 04 1e 18 37 ef 0d  |....F...BA...7..|
+00000010  19 51 88 35 75 71 b5 e5  54 5b 12 2e 8f 09 67 fd  |.Q.5uq..T[....g.|
+00000020  a7 24 20 3e b2 56 1c ce  97 28 5e f8 2b 2d 4f 9e  |.$ >.V...(^.+-O.|
+00000030  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
+00000040  a6 b5 68 1a 41 03 56 6b  dc 5a 89 14 03 03 00 01  |..h.A.Vk.Z......|
+00000050  01 16 03 03 00 28 00 00  00 00 00 00 00 00 60 0e  |.....(........`.|
+00000060  49 99 7a 9f 28 6e 46 03  a8 fd 0e b7 ed bb 9c ba  |I.z.(nF.........|
+00000070  07 9c 4d cc 26 2b c2 70  a0 26 38 a0 f2 a0        |..M.&+.p.&8...|
+>>> Flow 4 (server to client)
+00000000  14 03 03 00 01 01 16 03  03 00 28 d2 ef 8f f4 7b  |..........(....{|
+00000010  7a 9b c8 98 a4 36 f2 be  61 46 0e af f4 6f 63 71  |z....6..aF...ocq|
+00000020  6e bd 87 ea 1b f2 95 ad  36 7d a3 52 7f b2 b6 45  |n.......6}.R...E|
+00000030  3f 0b 62                                          |?.b|
+>>> Flow 5 (client to server)
+00000000  17 03 03 00 1e 00 00 00  00 00 00 00 01 53 a1 85  |.............S..|
+00000010  ce 3c c1 64 39 80 fb db  67 ec 48 20 7f e9 82 f4  |.<.d9...g.H ....|
+00000020  2d 69 0a 15 03 03 00 1a  00 00 00 00 00 00 00 02  |-i..............|
+00000030  ab 78 11 1b 80 55 23 db  07 c5 7f c3 5e 19 d8 b3  |.x...U#.....^...|
+00000040  f8 c6                                             |..|
diff --git a/src/crypto/tls/testdata/Server-SSLv3-RSA-3DES b/src/crypto/tls/testdata/Server-SSLv3-RSA-3DES
index a6c7a41..20520f5 100644
--- a/src/crypto/tls/testdata/Server-SSLv3-RSA-3DES
+++ b/src/crypto/tls/testdata/Server-SSLv3-RSA-3DES
@@ -1,83 +1,78 @@
 >>> Flow 1 (client to server)
-00000000  16 03 00 00 2f 01 00 00  2b 03 00 52 cc 57 59 d8  |..../...+..R.WY.|
-00000010  86 d6 07 ae e0 8d 63 b7  1e cb aa c6 67 32 c8 dd  |......c.....g2..|
-00000020  68 03 d8 3d 37 18 72 c3  c0 f1 9d 00 00 04 00 0a  |h..=7.r.........|
+00000000  16 03 00 00 2f 01 00 00  2b 03 00 10 71 68 59 99  |..../...+...qhY.|
+00000010  9c a6 e7 36 8b 0d 03 be  f5 42 ab 7c d0 3b 76 3e  |...6.....B.|.;v>|
+00000020  46 7c 6c a3 94 09 b7 1b  0e 42 27 00 00 04 00 0a  |F|l......B'.....|
 00000030  00 ff 01 00                                       |....|
 >>> Flow 2 (server to client)
 00000000  16 03 00 00 31 02 00 00  2d 03 00 00 00 00 00 00  |....1...-.......|
 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 0a 00 00  |................|
-00000030  05 ff 01 00 01 00 16 03  00 02 be 0b 00 02 ba 00  |................|
-00000040  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
-00000050  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
-00000060  09 2a 86 48 86 f7 0d 01  01 05 05 00 30 45 31 0b  |.*.H........0E1.|
-00000070  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
-00000080  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
-00000090  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
-000000a0  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
-000000b0  4c 74 64 30 1e 17 0d 31  30 30 34 32 34 30 39 30  |Ltd0...100424090|
-000000c0  39 33 38 5a 17 0d 31 31  30 34 32 34 30 39 30 39  |938Z..1104240909|
-000000d0  33 38 5a 30 45 31 0b 30  09 06 03 55 04 06 13 02  |38Z0E1.0...U....|
-000000e0  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
-000000f0  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
-00000100  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
-00000110  74 73 20 50 74 79 20 4c  74 64 30 81 9f 30 0d 06  |ts Pty Ltd0..0..|
-00000120  09 2a 86 48 86 f7 0d 01  01 01 05 00 03 81 8d 00  |.*.H............|
-00000130  30 81 89 02 81 81 00 bb  79 d6 f5 17 b5 e5 bf 46  |0.......y......F|
-00000140  10 d0 dc 69 be e6 2b 07  43 5a d0 03 2d 8a 7a 43  |...i..+.CZ..-.zC|
-00000150  85 b7 14 52 e7 a5 65 4c  2c 78 b8 23 8c b5 b4 82  |...R..eL,x.#....|
-00000160  e5 de 1f 95 3b 7e 62 a5  2c a5 33 d6 fe 12 5c 7a  |....;~b.,.3...\z|
-00000170  56 fc f5 06 bf fa 58 7b  26 3f b5 cd 04 d3 d0 c9  |V.....X{&?......|
-00000180  21 96 4a c7 f4 54 9f 5a  bf ef 42 71 00 fe 18 99  |!.J..T.Z..Bq....|
-00000190  07 7f 7e 88 7d 7d f1 04  39 c4 a2 2e db 51 c9 7c  |..~.}}..9....Q.||
-000001a0  e3 c0 4c 3b 32 66 01 cf  af b1 1d b8 71 9a 1d db  |..L;2f......q...|
-000001b0  db 89 6b ae da 2d 79 02  03 01 00 01 a3 81 a7 30  |..k..-y........0|
-000001c0  81 a4 30 1d 06 03 55 1d  0e 04 16 04 14 b1 ad e2  |..0...U.........|
-000001d0  85 5a cf cb 28 db 69 ce  23 69 de d3 26 8e 18 88  |.Z..(.i.#i..&...|
-000001e0  39 30 75 06 03 55 1d 23  04 6e 30 6c 80 14 b1 ad  |90u..U.#.n0l....|
-000001f0  e2 85 5a cf cb 28 db 69  ce 23 69 de d3 26 8e 18  |..Z..(.i.#i..&..|
-00000200  88 39 a1 49 a4 47 30 45  31 0b 30 09 06 03 55 04  |.9.I.G0E1.0...U.|
-00000210  06 13 02 41 55 31 13 30  11 06 03 55 04 08 13 0a  |...AU1.0...U....|
-00000220  53 6f 6d 65 2d 53 74 61  74 65 31 21 30 1f 06 03  |Some-State1!0...|
-00000230  55 04 0a 13 18 49 6e 74  65 72 6e 65 74 20 57 69  |U....Internet Wi|
-00000240  64 67 69 74 73 20 50 74  79 20 4c 74 64 82 09 00  |dgits Pty Ltd...|
-00000250  85 b0 bb a4 8a 7f b8 ca  30 0c 06 03 55 1d 13 04  |........0...U...|
-00000260  05 30 03 01 01 ff 30 0d  06 09 2a 86 48 86 f7 0d  |.0....0...*.H...|
-00000270  01 01 05 05 00 03 81 81  00 08 6c 45 24 c7 6b b1  |..........lE$.k.|
-00000280  59 ab 0c 52 cc f2 b0 14  d7 87 9d 7a 64 75 b5 5a  |Y..R.......zdu.Z|
-00000290  95 66 e4 c5 2b 8e ae 12  66 1f eb 4f 38 b3 6e 60  |.f..+...f..O8.n`|
-000002a0  d3 92 fd f7 41 08 b5 25  13 b1 18 7a 24 fb 30 1d  |....A..%...z$.0.|
-000002b0  ba ed 98 b9 17 ec e7 d7  31 59 db 95 d3 1d 78 ea  |........1Y....x.|
-000002c0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
-000002d0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
-000002e0  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
-000002f0  6e 38 50 29 6c 90 a7 bd  d9 16 03 00 00 04 0e 00  |n8P)l...........|
-00000300  00 00                                             |..|
+00000030  05 ff 01 00 01 00 16 03  00 02 71 0b 00 02 6d 00  |..........q...m.|
+00000040  02 6a 00 02 67 30 82 02  63 30 82 01 cc a0 03 02  |.j..g0..c0......|
+00000050  01 02 02 09 00 a2 73 00  0c 81 00 cb f3 30 0d 06  |......s......0..|
+00000060  09 2a 86 48 86 f7 0d 01  01 0b 05 00 30 2b 31 17  |.*.H........0+1.|
+00000070  30 15 06 03 55 04 0a 13  0e 47 6f 6f 67 6c 65 20  |0...U....Google |
+00000080  54 45 53 54 49 4e 47 31  10 30 0e 06 03 55 04 03  |TESTING1.0...U..|
+00000090  13 07 47 6f 20 52 6f 6f  74 30 1e 17 0d 31 35 30  |..Go Root0...150|
+000000a0  31 30 31 30 30 30 30 30  30 5a 17 0d 32 35 30 31  |101000000Z..2501|
+000000b0  30 31 30 30 30 30 30 30  5a 30 26 31 17 30 15 06  |01000000Z0&1.0..|
+000000c0  03 55 04 0a 13 0e 47 6f  6f 67 6c 65 20 54 45 53  |.U....Google TES|
+000000d0  54 49 4e 47 31 0b 30 09  06 03 55 04 03 13 02 47  |TING1.0...U....G|
+000000e0  6f 30 81 9f 30 0d 06 09  2a 86 48 86 f7 0d 01 01  |o0..0...*.H.....|
+000000f0  01 05 00 03 81 8d 00 30  81 89 02 81 81 00 af 87  |.......0........|
+00000100  88 f6 20 1b 95 65 6c 14  ab 44 05 af 3b 45 14 e3  |.. ..el..D..;E..|
+00000110  b7 6d fd 00 63 4d 95 7f  fe 6a 62 35 86 c0 4a f9  |.m..cM...jb5..J.|
+00000120  18 7c f6 aa 25 5e 7a 64  31 66 00 ba f4 8e 92 af  |.|..%^zd1f......|
+00000130  c7 6b d8 76 d4 f3 5f 41  cb 6e 56 15 97 1b 97 c1  |.k.v.._A.nV.....|
+00000140  3c 12 39 21 66 3d 2b 16  d1 bc db 1c c0 a7 da b7  |<.9!f=+.........|
+00000150  ca ad ba da cb d5 21 50  ec de 8d ab d1 6b 81 4b  |......!P.....k.K|
+00000160  89 02 f3 c4 be c1 6c 89  b1 44 84 bd 21 d1 04 7d  |......l..D..!..}|
+00000170  9d 16 4d f9 82 15 f6 ef  fa d6 09 47 f2 fb 02 03  |..M........G....|
+00000180  01 00 01 a3 81 93 30 81  90 30 0e 06 03 55 1d 0f  |......0..0...U..|
+00000190  01 01 ff 04 04 03 02 05  a0 30 1d 06 03 55 1d 25  |.........0...U.%|
+000001a0  04 16 30 14 06 08 2b 06  01 05 05 07 03 01 06 08  |..0...+.........|
+000001b0  2b 06 01 05 05 07 03 02  30 0c 06 03 55 1d 13 01  |+.......0...U...|
+000001c0  01 ff 04 02 30 00 30 19  06 03 55 1d 0e 04 12 04  |....0.0...U.....|
+000001d0  10 12 50 8d 89 6f 1b d1  dc 54 4d 6e cb 69 5e 06  |..P..o...TMn.i^.|
+000001e0  f4 30 1b 06 03 55 1d 23  04 14 30 12 80 10 bf 3d  |.0...U.#..0....=|
+000001f0  b6 a9 66 f2 b8 40 cf ea  b4 03 78 48 1a 41 30 19  |..f.. at ....xH.A0.|
+00000200  06 03 55 1d 11 04 12 30  10 82 0e 65 78 61 6d 70  |..U....0...examp|
+00000210  6c 65 2e 67 6f 6c 61 6e  67 30 0d 06 09 2a 86 48  |le.golang0...*.H|
+00000220  86 f7 0d 01 01 0b 05 00  03 81 81 00 92 7c af 91  |.............|..|
+00000230  55 12 18 96 59 31 a6 48  40 d5 2d d5 ee bb 02 a0  |U...Y1.H at .-.....|
+00000240  f5 c2 1e 7c 9b b3 30 7d  3c dc 76 da 4f 3d c0 fa  |...|..0}<.v.O=..|
+00000250  ae 2d 33 24 6b 03 7b 1b  67 59 11 21 b5 11 bc 77  |.-3$k.{.gY.!...w|
+00000260  b9 d9 e0 6e a8 2d 2e 35  fa 64 5f 22 3e 63 10 6b  |...n.-.5.d_">c.k|
+00000270  be ff 14 86 6d 0d f0 15  31 a8 14 38 1e 3b 84 87  |....m...1..8.;..|
+00000280  2c cb 98 ed 51 76 b9 b1  4f dd db 9b 84 04 86 40  |,...Qv..O......@|
+00000290  fa 51 dd ba b4 8d eb e3  46 de 46 b9 4f 86 c7 f9  |.Q......F.F.O...|
+000002a0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 00 00  |..A4......9.....|
+000002b0  04 0e 00 00 00                                    |.....|
 >>> Flow 3 (client to server)
-00000000  16 03 00 00 84 10 00 00  80 75 e0 c9 76 d6 e9 34  |.........u..v..4|
-00000010  1d e3 31 9e db 3b 03 41  93 e8 db 73 7c e9 3f 6a  |..1..;.A...s|.?j|
-00000020  d8 2a 7b 25 83 4f 45 de  3f 78 3f b6 53 a7 b4 6c  |.*{%.OE.?x?.S..l|
-00000030  e3 87 c4 c3 70 55 71 79  55 dc 74 98 84 21 19 13  |....pUqyU.t..!..|
-00000040  be d5 8e 0a ff 2f 9f 7a  6b d4 6c ef 78 d1 cb 65  |...../.zk.l.x..e|
-00000050  32 4c 0c c5 29 b9 60 94  c6 79 56 a2 aa 2d d9 ad  |2L..).`..yV..-..|
-00000060  51 2c 54 1b 28 23 33 54  cd 48 cb 80 13 45 3d 4a  |Q,T.(#3T.H...E=J|
-00000070  8e 2f f2 da bd 68 3e 1b  eb 73 f9 2d 35 6b b1 40  |./...h>..s.-5k.@|
-00000080  2e 6d 9d 1c e9 c1 02 80  37 14 03 00 00 01 01 16  |.m......7.......|
-00000090  03 00 00 40 f7 c3 dd a4  64 3d 81 24 de a2 81 7d  |... at ....d=.$...}|
-000000a0  e4 df 78 46 e7 ba 93 6c  36 43 05 96 fc 75 ef ec  |..xF...l6C...u..|
-000000b0  a5 46 6d 47 a5 be 74 ad  15 93 d9 87 4f 1d e2 b3  |.FmG..t.....O...|
-000000c0  03 ff 2e 89 6e 50 f4 d6  a6 e2 b3 54 cb 74 07 f7  |....nP.....T.t..|
-000000d0  ca 1b 8c 0a                                       |....|
+00000000  16 03 00 00 84 10 00 00  80 1b 62 18 c8 60 0b f7  |..........b..`..|
+00000010  4a b8 ec 98 56 eb aa 4b  d9 05 c0 f1 be b9 a5 28  |J...V..K.......(|
+00000020  62 e8 3e 25 08 9f 28 dd  08 1f 04 80 5f 10 81 cf  |b.>%..(....._...|
+00000030  aa 2f 55 cd f1 0f ec 5b  90 0a 1f 49 bc a3 96 38  |./U....[...I...8|
+00000040  c7 32 b6 0a da b3 a5 7a  76 28 82 19 30 f4 6b ae  |.2.....zv(..0.k.|
+00000050  fb 81 cc b4 ad 92 f8 c6  20 da 27 89 45 f4 43 c2  |........ .'.E.C.|
+00000060  16 7e de 29 03 dc 90 dd  3a 23 58 4c 35 be 11 a5  |.~.)....:#XL5...|
+00000070  52 18 79 13 e6 b3 2d e6  8e f5 76 60 0c c1 92 bb  |R.y...-...v`....|
+00000080  07 67 c5 24 12 1b aa d6  53 14 03 00 00 01 01 16  |.g.$....S.......|
+00000090  03 00 00 40 5f 64 da b6  24 19 07 44 32 85 f3 c0  |... at _d..$..D2...|
+000000a0  9b c6 2c ad b1 d1 0f 4b  52 20 2f ea 6f 15 80 44  |..,....KR /.o..D|
+000000b0  78 34 44 02 67 e0 2e b4  b8 df 7b 3f 21 dd 66 9b  |x4D.g.....{?!.f.|
+000000c0  e7 5f 71 ff 5f 30 fb 5b  5a 19 f0 24 f8 21 bc 7c  |._q._0.[Z..$.!.||
+000000d0  00 e1 1f e8                                       |....|
 >>> Flow 4 (server to client)
-00000000  14 03 00 00 01 01 16 03  00 00 40 6d 3d d8 d5 cf  |.......... at m=...|
-00000010  05 7d 98 8c 28 28 e2 43  ab ad 4a fa ae bf ec c3  |.}..((.C..J.....|
-00000020  9c 0a 13 4d 28 a4 45 c4  b9 f2 bc c5 12 a2 68 91  |...M(.E.......h.|
-00000030  77 fa 72 f8 9e 4e b7 1f  b4 02 02 e3 5d 57 b0 8b  |w.r..N......]W..|
-00000040  d8 90 0c 9d e6 df 5b 90  92 a1 0d 17 03 00 00 18  |......[.........|
-00000050  91 48 8a e1 d6 bf 79 1c  d5 0a 70 d5 94 20 25 78  |.H....y...p.. %x|
-00000060  d8 84 c8 6e 54 f0 99 01  17 03 00 00 28 74 19 90  |...nT.......(t..|
-00000070  41 44 53 27 bb fb 1f fd  71 34 20 61 a0 eb a4 7c  |ADS'....q4 a...||
-00000080  fe 36 f8 4b d7 b0 27 d3  b9 36 e1 67 af 2d 0e 23  |.6.K..'..6.g.-.#|
-00000090  2b 76 a7 2f c3 15 03 00  00 18 db fc e9 fd 87 5f  |+v./..........._|
-000000a0  92 a8 3d 4b 35 f5 c6 48  2c b4 42 50 c3 81 28 f0  |..=K5..H,.BP..(.|
-000000b0  2b 41                                             |+A|
+00000000  14 03 00 00 01 01 16 03  00 00 40 48 01 fc 08 a0  |.......... at H....|
+00000010  fa 0e 63 58 25 18 06 3c  54 5c 60 ce 35 f6 ec b8  |..cX%..<T\`.5...|
+00000020  ed f8 97 c7 b0 5f 96 6b  d1 10 53 e9 23 20 44 56  |....._.k..S.# DV|
+00000030  d7 ee 11 e1 6f b7 1e fb  33 94 7f f0 78 f5 2e 02  |....o...3...x...|
+00000040  37 7a 43 cf e7 c7 52 b3  c6 8d 8e 17 03 00 00 18  |7zC...R.........|
+00000050  f7 3c 05 79 4b 55 8c d7  2c 50 82 f0 61 34 f6 c7  |.<.yKU..,P..a4..|
+00000060  f3 71 e1 76 1d f0 65 b6  17 03 00 00 28 50 ce 6c  |.q.v..e.....(P.l|
+00000070  96 97 70 88 b7 3c 74 a9  cb a3 0e ae 3a 7f 85 99  |..p..<t.....:...|
+00000080  58 36 10 7f 1a e8 f8 7d  83 75 24 7e b1 6a 8e b0  |X6.....}.u$~.j..|
+00000090  f1 cc 06 19 f7 15 03 00  00 18 2c 1d 87 1d ce 08  |..........,.....|
+000000a0  8f 10 09 6e bd fc ad e0  1d a7 47 d5 b9 8f 3e b8  |...n......G...>.|
+000000b0  b3 fa                                             |..|
diff --git a/src/crypto/tls/testdata/Server-SSLv3-RSA-AES b/src/crypto/tls/testdata/Server-SSLv3-RSA-AES
index 4885b26..e0fe956 100644
--- a/src/crypto/tls/testdata/Server-SSLv3-RSA-AES
+++ b/src/crypto/tls/testdata/Server-SSLv3-RSA-AES
@@ -1,84 +1,79 @@
 >>> Flow 1 (client to server)
-00000000  16 03 00 00 2f 01 00 00  2b 03 00 52 cc 57 59 30  |..../...+..R.WY0|
-00000010  e1 ee 8c 60 5b 40 dd 95  bd b4 84 87 2f 01 15 e7  |...`[@....../...|
-00000020  50 88 4c 82 6b 6d 93 8a  57 d0 27 00 00 04 00 2f  |P.L.km..W.'..../|
+00000000  16 03 00 00 2f 01 00 00  2b 03 00 37 cd 49 a6 9f  |..../...+..7.I..|
+00000010  e9 19 6a 39 cd 75 ce 6c  f1 1b 96 d3 d4 f0 33 0c  |..j9.u.l......3.|
+00000020  8f 53 b2 06 c4 0e 39 86  e3 98 7e 00 00 04 00 2f  |.S....9...~..../|
 00000030  00 ff 01 00                                       |....|
 >>> Flow 2 (server to client)
 00000000  16 03 00 00 31 02 00 00  2d 03 00 00 00 00 00 00  |....1...-.......|
 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 2f 00 00  |............./..|
-00000030  05 ff 01 00 01 00 16 03  00 02 be 0b 00 02 ba 00  |................|
-00000040  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
-00000050  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
-00000060  09 2a 86 48 86 f7 0d 01  01 05 05 00 30 45 31 0b  |.*.H........0E1.|
-00000070  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
-00000080  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
-00000090  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
-000000a0  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
-000000b0  4c 74 64 30 1e 17 0d 31  30 30 34 32 34 30 39 30  |Ltd0...100424090|
-000000c0  39 33 38 5a 17 0d 31 31  30 34 32 34 30 39 30 39  |938Z..1104240909|
-000000d0  33 38 5a 30 45 31 0b 30  09 06 03 55 04 06 13 02  |38Z0E1.0...U....|
-000000e0  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
-000000f0  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
-00000100  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
-00000110  74 73 20 50 74 79 20 4c  74 64 30 81 9f 30 0d 06  |ts Pty Ltd0..0..|
-00000120  09 2a 86 48 86 f7 0d 01  01 01 05 00 03 81 8d 00  |.*.H............|
-00000130  30 81 89 02 81 81 00 bb  79 d6 f5 17 b5 e5 bf 46  |0.......y......F|
-00000140  10 d0 dc 69 be e6 2b 07  43 5a d0 03 2d 8a 7a 43  |...i..+.CZ..-.zC|
-00000150  85 b7 14 52 e7 a5 65 4c  2c 78 b8 23 8c b5 b4 82  |...R..eL,x.#....|
-00000160  e5 de 1f 95 3b 7e 62 a5  2c a5 33 d6 fe 12 5c 7a  |....;~b.,.3...\z|
-00000170  56 fc f5 06 bf fa 58 7b  26 3f b5 cd 04 d3 d0 c9  |V.....X{&?......|
-00000180  21 96 4a c7 f4 54 9f 5a  bf ef 42 71 00 fe 18 99  |!.J..T.Z..Bq....|
-00000190  07 7f 7e 88 7d 7d f1 04  39 c4 a2 2e db 51 c9 7c  |..~.}}..9....Q.||
-000001a0  e3 c0 4c 3b 32 66 01 cf  af b1 1d b8 71 9a 1d db  |..L;2f......q...|
-000001b0  db 89 6b ae da 2d 79 02  03 01 00 01 a3 81 a7 30  |..k..-y........0|
-000001c0  81 a4 30 1d 06 03 55 1d  0e 04 16 04 14 b1 ad e2  |..0...U.........|
-000001d0  85 5a cf cb 28 db 69 ce  23 69 de d3 26 8e 18 88  |.Z..(.i.#i..&...|
-000001e0  39 30 75 06 03 55 1d 23  04 6e 30 6c 80 14 b1 ad  |90u..U.#.n0l....|
-000001f0  e2 85 5a cf cb 28 db 69  ce 23 69 de d3 26 8e 18  |..Z..(.i.#i..&..|
-00000200  88 39 a1 49 a4 47 30 45  31 0b 30 09 06 03 55 04  |.9.I.G0E1.0...U.|
-00000210  06 13 02 41 55 31 13 30  11 06 03 55 04 08 13 0a  |...AU1.0...U....|
-00000220  53 6f 6d 65 2d 53 74 61  74 65 31 21 30 1f 06 03  |Some-State1!0...|
-00000230  55 04 0a 13 18 49 6e 74  65 72 6e 65 74 20 57 69  |U....Internet Wi|
-00000240  64 67 69 74 73 20 50 74  79 20 4c 74 64 82 09 00  |dgits Pty Ltd...|
-00000250  85 b0 bb a4 8a 7f b8 ca  30 0c 06 03 55 1d 13 04  |........0...U...|
-00000260  05 30 03 01 01 ff 30 0d  06 09 2a 86 48 86 f7 0d  |.0....0...*.H...|
-00000270  01 01 05 05 00 03 81 81  00 08 6c 45 24 c7 6b b1  |..........lE$.k.|
-00000280  59 ab 0c 52 cc f2 b0 14  d7 87 9d 7a 64 75 b5 5a  |Y..R.......zdu.Z|
-00000290  95 66 e4 c5 2b 8e ae 12  66 1f eb 4f 38 b3 6e 60  |.f..+...f..O8.n`|
-000002a0  d3 92 fd f7 41 08 b5 25  13 b1 18 7a 24 fb 30 1d  |....A..%...z$.0.|
-000002b0  ba ed 98 b9 17 ec e7 d7  31 59 db 95 d3 1d 78 ea  |........1Y....x.|
-000002c0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
-000002d0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
-000002e0  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
-000002f0  6e 38 50 29 6c 90 a7 bd  d9 16 03 00 00 04 0e 00  |n8P)l...........|
-00000300  00 00                                             |..|
+00000030  05 ff 01 00 01 00 16 03  00 02 71 0b 00 02 6d 00  |..........q...m.|
+00000040  02 6a 00 02 67 30 82 02  63 30 82 01 cc a0 03 02  |.j..g0..c0......|
+00000050  01 02 02 09 00 a2 73 00  0c 81 00 cb f3 30 0d 06  |......s......0..|
+00000060  09 2a 86 48 86 f7 0d 01  01 0b 05 00 30 2b 31 17  |.*.H........0+1.|
+00000070  30 15 06 03 55 04 0a 13  0e 47 6f 6f 67 6c 65 20  |0...U....Google |
+00000080  54 45 53 54 49 4e 47 31  10 30 0e 06 03 55 04 03  |TESTING1.0...U..|
+00000090  13 07 47 6f 20 52 6f 6f  74 30 1e 17 0d 31 35 30  |..Go Root0...150|
+000000a0  31 30 31 30 30 30 30 30  30 5a 17 0d 32 35 30 31  |101000000Z..2501|
+000000b0  30 31 30 30 30 30 30 30  5a 30 26 31 17 30 15 06  |01000000Z0&1.0..|
+000000c0  03 55 04 0a 13 0e 47 6f  6f 67 6c 65 20 54 45 53  |.U....Google TES|
+000000d0  54 49 4e 47 31 0b 30 09  06 03 55 04 03 13 02 47  |TING1.0...U....G|
+000000e0  6f 30 81 9f 30 0d 06 09  2a 86 48 86 f7 0d 01 01  |o0..0...*.H.....|
+000000f0  01 05 00 03 81 8d 00 30  81 89 02 81 81 00 af 87  |.......0........|
+00000100  88 f6 20 1b 95 65 6c 14  ab 44 05 af 3b 45 14 e3  |.. ..el..D..;E..|
+00000110  b7 6d fd 00 63 4d 95 7f  fe 6a 62 35 86 c0 4a f9  |.m..cM...jb5..J.|
+00000120  18 7c f6 aa 25 5e 7a 64  31 66 00 ba f4 8e 92 af  |.|..%^zd1f......|
+00000130  c7 6b d8 76 d4 f3 5f 41  cb 6e 56 15 97 1b 97 c1  |.k.v.._A.nV.....|
+00000140  3c 12 39 21 66 3d 2b 16  d1 bc db 1c c0 a7 da b7  |<.9!f=+.........|
+00000150  ca ad ba da cb d5 21 50  ec de 8d ab d1 6b 81 4b  |......!P.....k.K|
+00000160  89 02 f3 c4 be c1 6c 89  b1 44 84 bd 21 d1 04 7d  |......l..D..!..}|
+00000170  9d 16 4d f9 82 15 f6 ef  fa d6 09 47 f2 fb 02 03  |..M........G....|
+00000180  01 00 01 a3 81 93 30 81  90 30 0e 06 03 55 1d 0f  |......0..0...U..|
+00000190  01 01 ff 04 04 03 02 05  a0 30 1d 06 03 55 1d 25  |.........0...U.%|
+000001a0  04 16 30 14 06 08 2b 06  01 05 05 07 03 01 06 08  |..0...+.........|
+000001b0  2b 06 01 05 05 07 03 02  30 0c 06 03 55 1d 13 01  |+.......0...U...|
+000001c0  01 ff 04 02 30 00 30 19  06 03 55 1d 0e 04 12 04  |....0.0...U.....|
+000001d0  10 12 50 8d 89 6f 1b d1  dc 54 4d 6e cb 69 5e 06  |..P..o...TMn.i^.|
+000001e0  f4 30 1b 06 03 55 1d 23  04 14 30 12 80 10 bf 3d  |.0...U.#..0....=|
+000001f0  b6 a9 66 f2 b8 40 cf ea  b4 03 78 48 1a 41 30 19  |..f.. at ....xH.A0.|
+00000200  06 03 55 1d 11 04 12 30  10 82 0e 65 78 61 6d 70  |..U....0...examp|
+00000210  6c 65 2e 67 6f 6c 61 6e  67 30 0d 06 09 2a 86 48  |le.golang0...*.H|
+00000220  86 f7 0d 01 01 0b 05 00  03 81 81 00 92 7c af 91  |.............|..|
+00000230  55 12 18 96 59 31 a6 48  40 d5 2d d5 ee bb 02 a0  |U...Y1.H at .-.....|
+00000240  f5 c2 1e 7c 9b b3 30 7d  3c dc 76 da 4f 3d c0 fa  |...|..0}<.v.O=..|
+00000250  ae 2d 33 24 6b 03 7b 1b  67 59 11 21 b5 11 bc 77  |.-3$k.{.gY.!...w|
+00000260  b9 d9 e0 6e a8 2d 2e 35  fa 64 5f 22 3e 63 10 6b  |...n.-.5.d_">c.k|
+00000270  be ff 14 86 6d 0d f0 15  31 a8 14 38 1e 3b 84 87  |....m...1..8.;..|
+00000280  2c cb 98 ed 51 76 b9 b1  4f dd db 9b 84 04 86 40  |,...Qv..O......@|
+00000290  fa 51 dd ba b4 8d eb e3  46 de 46 b9 4f 86 c7 f9  |.Q......F.F.O...|
+000002a0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 00 00  |..A4......9.....|
+000002b0  04 0e 00 00 00                                    |.....|
 >>> Flow 3 (client to server)
-00000000  16 03 00 00 84 10 00 00  80 74 50 05 6f f5 83 c9  |.........tP.o...|
-00000010  f5 0c 5a 65 c7 4e c6 f3  87 96 d7 5d 3e 88 27 32  |..Ze.N.....]>.'2|
-00000020  89 12 ba ec db ef c0 85  70 84 ed b6 83 03 8f 44  |........p......D|
-00000030  f5 6f fa fa d0 1f 95 30  d1 ae a7 71 cf ee e9 b1  |.o.....0...q....|
-00000040  80 7b 34 a9 ea 1b 5e e5  71 40 3f e8 7d 30 d1 8b  |.{4...^.q@?.}0..|
-00000050  11 f1 68 1f c8 25 f0 77  c5 af b3 92 6e d9 81 cc  |..h..%.w....n...|
-00000060  f8 fd 82 95 cc 1f 4a b1  05 15 7a b3 a1 22 33 09  |......J...z.."3.|
-00000070  e7 a5 c2 89 7f 03 e0 91  b6 61 a3 a0 4e 17 0d 7a  |.........a..N..z|
-00000080  13 01 c4 b6 50 c7 d9 81  15 14 03 00 00 01 01 16  |....P...........|
-00000090  03 00 00 40 56 da 56 ab  e6 26 98 58 53 1f 36 b5  |... at V.V..&.XS.6.|
-000000a0  03 14 bd 42 29 ee 9c 7c  e4 48 26 82 68 ae fd fe  |...B)..|.H&.h...|
-000000b0  5e a4 43 22 75 95 7b c8  77 88 fd d6 d4 9b c9 b5  |^.C"u.{.w.......|
-000000c0  ee 3e a6 e8 c5 04 90 63  3f ac be 56 67 da 30 d4  |.>.....c?..Vg.0.|
-000000d0  64 fb a8 a0                                       |d...|
+00000000  16 03 00 00 84 10 00 00  80 4d 3f 93 aa 84 d8 ad  |.........M?.....|
+00000010  93 2c 63 02 66 2f 96 88  b8 5c 09 1e 63 e2 e5 96  |.,c.f/...\..c...|
+00000020  26 d8 07 14 86 26 62 f4  0c 04 68 1c bf bb b1 53  |&....&b...h....S|
+00000030  97 96 43 59 4a 57 65 12  88 45 34 2b 86 2b 05 aa  |..CYJWe..E4+.+..|
+00000040  9b 2b b9 aa 13 30 5c 91  c0 9f 03 8a 96 61 dd 87  |.+...0\......a..|
+00000050  ae e3 ad 6a 7b 8a 18 23  67 c9 df ad f2 47 eb 8b  |...j{..#g....G..|
+00000060  7d 24 95 47 f1 4e b5 c6  15 b4 12 2a 42 df b3 99  |}$.G.N.....*B...|
+00000070  d1 b8 60 ce 6a cf 98 c1  13 a1 68 e6 92 ee 92 a2  |..`.j.....h.....|
+00000080  1d 2f 63 66 f3 b9 1b fc  33 14 03 00 00 01 01 16  |./cf....3.......|
+00000090  03 00 00 40 75 48 68 7d  8f f5 5a c0 cb 90 a5 9e  |... at uHh}..Z.....|
+000000a0  94 bb eb 61 b5 36 aa ce  09 7a 11 ba 22 56 2a d7  |...a.6...z.."V*.|
+000000b0  91 a3 99 73 5b c5 b2 b7  b9 92 56 c6 cb fe 13 73  |...s[.....V....s|
+000000c0  28 30 03 26 62 63 7e 8a  d2 58 c8 e7 52 03 26 67  |(0.&bc~..X..R.&g|
+000000d0  48 21 4f 21                                       |H!O!|
 >>> Flow 4 (server to client)
-00000000  14 03 00 00 01 01 16 03  00 00 40 96 af fb 79 96  |.......... at ...y.|
-00000010  92 97 2d d0 67 46 1e 08  b5 35 65 ef dc bc 8e 57  |..-.gF...5e....W|
-00000020  53 b7 36 58 74 d7 88 b1  55 fc eb fa 2e f3 17 b7  |S.6Xt...U.......|
-00000030  62 58 a0 9d 99 e1 85 d4  33 e0 b4 1f 1d 94 f2 88  |bX......3.......|
-00000040  d5 9a 34 5b 74 cd d2 ff  87 bd 52 17 03 00 00 20  |..4[t.....R.... |
-00000050  c6 61 c2 28 ac d2 0c 08  7f f1 c2 62 af 37 7e 78  |.a.(.......b.7~x|
-00000060  e8 e2 a1 54 f2 3a 80 97  f8 47 64 f2 cd 94 dd 0b  |...T.:...Gd.....|
-00000070  17 03 00 00 30 b8 40 8f  a3 18 ff 03 84 d4 1c 28  |....0. at ........(|
-00000080  82 ce d8 9a 81 3a dd 23  7c 65 d8 ca f7 f1 46 1b  |.....:.#|e....F.|
-00000090  70 f0 d7 d9 54 a7 71 e6  4d d4 25 61 5a e4 30 d3  |p...T.q.M.%aZ.0.|
-000000a0  4a 42 ae 26 a5 15 03 00  00 20 c4 e8 ed 40 57 00  |JB.&..... ... at W.|
-000000b0  dc a5 0e 82 90 47 92 08  dd 7e 50 6b 30 66 5e 90  |.....G...~Pk0f^.|
-000000c0  73 7c 81 93 8d 24 b1 06  e7 39                    |s|...$...9|
+00000000  14 03 00 00 01 01 16 03  00 00 40 84 8f 6e 80 35  |.......... at ..n.5|
+00000010  57 73 64 ef 29 bb 25 ff  5d 9d c7 55 38 b7 18 b3  |Wsd.).%.]..U8...|
+00000020  13 d1 ac 20 e0 1e f8 48  47 7a 40 2d bc a7 f2 af  |... ...HGz at -....|
+00000030  ed a6 26 48 f4 51 b4 b6  56 60 9b c3 d9 43 00 95  |..&H.Q..V`...C..|
+00000040  86 be 6c 4e 49 6b f9 10  99 51 22 17 03 00 00 20  |..lNIk...Q".... |
+00000050  d4 7e dc 50 7b c2 26 ee  79 09 84 9f d7 e0 52 b1  |.~.P{.&.y.....R.|
+00000060  e8 9c 92 30 b7 34 06 c6  e5 86 57 a1 fb 8d 06 d6  |...0.4....W.....|
+00000070  17 03 00 00 30 93 0a 3d  64 26 3d a2 74 bc 8f d1  |....0..=d&=.t...|
+00000080  16 38 d0 6b 62 eb 82 b0  9a 50 68 aa 7e f7 45 32  |.8.kb....Ph.~.E2|
+00000090  43 cb 84 2d 95 39 6c bc  c8 a0 2d aa ea fe f5 84  |C..-.9l...-.....|
+000000a0  c8 e4 8b 93 a1 15 03 00  00 20 03 7b 3e 43 1d 0a  |......... .{>C..|
+000000b0  9b 9b e3 17 0f de be 75  e5 6e 2f 5b e8 8d a8 68  |.......u.n/[...h|
+000000c0  4e f0 82 49 00 dd b6 95  b4 22                    |N..I....."|
diff --git a/src/crypto/tls/testdata/Server-SSLv3-RSA-RC4 b/src/crypto/tls/testdata/Server-SSLv3-RSA-RC4
index 1314b65..39124c6 100644
--- a/src/crypto/tls/testdata/Server-SSLv3-RSA-RC4
+++ b/src/crypto/tls/testdata/Server-SSLv3-RSA-RC4
@@ -1,79 +1,74 @@
 >>> Flow 1 (client to server)
-00000000  16 03 00 00 2f 01 00 00  2b 03 00 52 cc 57 59 79  |..../...+..R.WYy|
-00000010  b9 3b ef df 53 fb 09 f6  01 e5 18 0a fc 3d 65 bb  |.;..S........=e.|
-00000020  cf 9c 4c 77 b1 e8 6b 4f  5f c7 94 00 00 04 00 05  |..Lw..kO_.......|
+00000000  16 03 00 00 2f 01 00 00  2b 03 00 a7 1d 3d ed 0f  |..../...+....=..|
+00000010  2c 7b 1f f1 c8 1c a9 17  ce 69 e2 73 a2 07 d2 91  |,{.......i.s....|
+00000020  e9 27 fa 70 11 6f 18 6d  2a 25 f1 00 00 04 00 05  |.'.p.o.m*%......|
 00000030  00 ff 01 00                                       |....|
 >>> Flow 2 (server to client)
 00000000  16 03 00 00 31 02 00 00  2d 03 00 00 00 00 00 00  |....1...-.......|
 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 05 00 00  |................|
-00000030  05 ff 01 00 01 00 16 03  00 02 be 0b 00 02 ba 00  |................|
-00000040  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
-00000050  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
-00000060  09 2a 86 48 86 f7 0d 01  01 05 05 00 30 45 31 0b  |.*.H........0E1.|
-00000070  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
-00000080  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
-00000090  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
-000000a0  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
-000000b0  4c 74 64 30 1e 17 0d 31  30 30 34 32 34 30 39 30  |Ltd0...100424090|
-000000c0  39 33 38 5a 17 0d 31 31  30 34 32 34 30 39 30 39  |938Z..1104240909|
-000000d0  33 38 5a 30 45 31 0b 30  09 06 03 55 04 06 13 02  |38Z0E1.0...U....|
-000000e0  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
-000000f0  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
-00000100  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
-00000110  74 73 20 50 74 79 20 4c  74 64 30 81 9f 30 0d 06  |ts Pty Ltd0..0..|
-00000120  09 2a 86 48 86 f7 0d 01  01 01 05 00 03 81 8d 00  |.*.H............|
-00000130  30 81 89 02 81 81 00 bb  79 d6 f5 17 b5 e5 bf 46  |0.......y......F|
-00000140  10 d0 dc 69 be e6 2b 07  43 5a d0 03 2d 8a 7a 43  |...i..+.CZ..-.zC|
-00000150  85 b7 14 52 e7 a5 65 4c  2c 78 b8 23 8c b5 b4 82  |...R..eL,x.#....|
-00000160  e5 de 1f 95 3b 7e 62 a5  2c a5 33 d6 fe 12 5c 7a  |....;~b.,.3...\z|
-00000170  56 fc f5 06 bf fa 58 7b  26 3f b5 cd 04 d3 d0 c9  |V.....X{&?......|
-00000180  21 96 4a c7 f4 54 9f 5a  bf ef 42 71 00 fe 18 99  |!.J..T.Z..Bq....|
-00000190  07 7f 7e 88 7d 7d f1 04  39 c4 a2 2e db 51 c9 7c  |..~.}}..9....Q.||
-000001a0  e3 c0 4c 3b 32 66 01 cf  af b1 1d b8 71 9a 1d db  |..L;2f......q...|
-000001b0  db 89 6b ae da 2d 79 02  03 01 00 01 a3 81 a7 30  |..k..-y........0|
-000001c0  81 a4 30 1d 06 03 55 1d  0e 04 16 04 14 b1 ad e2  |..0...U.........|
-000001d0  85 5a cf cb 28 db 69 ce  23 69 de d3 26 8e 18 88  |.Z..(.i.#i..&...|
-000001e0  39 30 75 06 03 55 1d 23  04 6e 30 6c 80 14 b1 ad  |90u..U.#.n0l....|
-000001f0  e2 85 5a cf cb 28 db 69  ce 23 69 de d3 26 8e 18  |..Z..(.i.#i..&..|
-00000200  88 39 a1 49 a4 47 30 45  31 0b 30 09 06 03 55 04  |.9.I.G0E1.0...U.|
-00000210  06 13 02 41 55 31 13 30  11 06 03 55 04 08 13 0a  |...AU1.0...U....|
-00000220  53 6f 6d 65 2d 53 74 61  74 65 31 21 30 1f 06 03  |Some-State1!0...|
-00000230  55 04 0a 13 18 49 6e 74  65 72 6e 65 74 20 57 69  |U....Internet Wi|
-00000240  64 67 69 74 73 20 50 74  79 20 4c 74 64 82 09 00  |dgits Pty Ltd...|
-00000250  85 b0 bb a4 8a 7f b8 ca  30 0c 06 03 55 1d 13 04  |........0...U...|
-00000260  05 30 03 01 01 ff 30 0d  06 09 2a 86 48 86 f7 0d  |.0....0...*.H...|
-00000270  01 01 05 05 00 03 81 81  00 08 6c 45 24 c7 6b b1  |..........lE$.k.|
-00000280  59 ab 0c 52 cc f2 b0 14  d7 87 9d 7a 64 75 b5 5a  |Y..R.......zdu.Z|
-00000290  95 66 e4 c5 2b 8e ae 12  66 1f eb 4f 38 b3 6e 60  |.f..+...f..O8.n`|
-000002a0  d3 92 fd f7 41 08 b5 25  13 b1 18 7a 24 fb 30 1d  |....A..%...z$.0.|
-000002b0  ba ed 98 b9 17 ec e7 d7  31 59 db 95 d3 1d 78 ea  |........1Y....x.|
-000002c0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
-000002d0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
-000002e0  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
-000002f0  6e 38 50 29 6c 90 a7 bd  d9 16 03 00 00 04 0e 00  |n8P)l...........|
-00000300  00 00                                             |..|
+00000030  05 ff 01 00 01 00 16 03  00 02 71 0b 00 02 6d 00  |..........q...m.|
+00000040  02 6a 00 02 67 30 82 02  63 30 82 01 cc a0 03 02  |.j..g0..c0......|
+00000050  01 02 02 09 00 a2 73 00  0c 81 00 cb f3 30 0d 06  |......s......0..|
+00000060  09 2a 86 48 86 f7 0d 01  01 0b 05 00 30 2b 31 17  |.*.H........0+1.|
+00000070  30 15 06 03 55 04 0a 13  0e 47 6f 6f 67 6c 65 20  |0...U....Google |
+00000080  54 45 53 54 49 4e 47 31  10 30 0e 06 03 55 04 03  |TESTING1.0...U..|
+00000090  13 07 47 6f 20 52 6f 6f  74 30 1e 17 0d 31 35 30  |..Go Root0...150|
+000000a0  31 30 31 30 30 30 30 30  30 5a 17 0d 32 35 30 31  |101000000Z..2501|
+000000b0  30 31 30 30 30 30 30 30  5a 30 26 31 17 30 15 06  |01000000Z0&1.0..|
+000000c0  03 55 04 0a 13 0e 47 6f  6f 67 6c 65 20 54 45 53  |.U....Google TES|
+000000d0  54 49 4e 47 31 0b 30 09  06 03 55 04 03 13 02 47  |TING1.0...U....G|
+000000e0  6f 30 81 9f 30 0d 06 09  2a 86 48 86 f7 0d 01 01  |o0..0...*.H.....|
+000000f0  01 05 00 03 81 8d 00 30  81 89 02 81 81 00 af 87  |.......0........|
+00000100  88 f6 20 1b 95 65 6c 14  ab 44 05 af 3b 45 14 e3  |.. ..el..D..;E..|
+00000110  b7 6d fd 00 63 4d 95 7f  fe 6a 62 35 86 c0 4a f9  |.m..cM...jb5..J.|
+00000120  18 7c f6 aa 25 5e 7a 64  31 66 00 ba f4 8e 92 af  |.|..%^zd1f......|
+00000130  c7 6b d8 76 d4 f3 5f 41  cb 6e 56 15 97 1b 97 c1  |.k.v.._A.nV.....|
+00000140  3c 12 39 21 66 3d 2b 16  d1 bc db 1c c0 a7 da b7  |<.9!f=+.........|
+00000150  ca ad ba da cb d5 21 50  ec de 8d ab d1 6b 81 4b  |......!P.....k.K|
+00000160  89 02 f3 c4 be c1 6c 89  b1 44 84 bd 21 d1 04 7d  |......l..D..!..}|
+00000170  9d 16 4d f9 82 15 f6 ef  fa d6 09 47 f2 fb 02 03  |..M........G....|
+00000180  01 00 01 a3 81 93 30 81  90 30 0e 06 03 55 1d 0f  |......0..0...U..|
+00000190  01 01 ff 04 04 03 02 05  a0 30 1d 06 03 55 1d 25  |.........0...U.%|
+000001a0  04 16 30 14 06 08 2b 06  01 05 05 07 03 01 06 08  |..0...+.........|
+000001b0  2b 06 01 05 05 07 03 02  30 0c 06 03 55 1d 13 01  |+.......0...U...|
+000001c0  01 ff 04 02 30 00 30 19  06 03 55 1d 0e 04 12 04  |....0.0...U.....|
+000001d0  10 12 50 8d 89 6f 1b d1  dc 54 4d 6e cb 69 5e 06  |..P..o...TMn.i^.|
+000001e0  f4 30 1b 06 03 55 1d 23  04 14 30 12 80 10 bf 3d  |.0...U.#..0....=|
+000001f0  b6 a9 66 f2 b8 40 cf ea  b4 03 78 48 1a 41 30 19  |..f.. at ....xH.A0.|
+00000200  06 03 55 1d 11 04 12 30  10 82 0e 65 78 61 6d 70  |..U....0...examp|
+00000210  6c 65 2e 67 6f 6c 61 6e  67 30 0d 06 09 2a 86 48  |le.golang0...*.H|
+00000220  86 f7 0d 01 01 0b 05 00  03 81 81 00 92 7c af 91  |.............|..|
+00000230  55 12 18 96 59 31 a6 48  40 d5 2d d5 ee bb 02 a0  |U...Y1.H at .-.....|
+00000240  f5 c2 1e 7c 9b b3 30 7d  3c dc 76 da 4f 3d c0 fa  |...|..0}<.v.O=..|
+00000250  ae 2d 33 24 6b 03 7b 1b  67 59 11 21 b5 11 bc 77  |.-3$k.{.gY.!...w|
+00000260  b9 d9 e0 6e a8 2d 2e 35  fa 64 5f 22 3e 63 10 6b  |...n.-.5.d_">c.k|
+00000270  be ff 14 86 6d 0d f0 15  31 a8 14 38 1e 3b 84 87  |....m...1..8.;..|
+00000280  2c cb 98 ed 51 76 b9 b1  4f dd db 9b 84 04 86 40  |,...Qv..O......@|
+00000290  fa 51 dd ba b4 8d eb e3  46 de 46 b9 4f 86 c7 f9  |.Q......F.F.O...|
+000002a0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 00 00  |..A4......9.....|
+000002b0  04 0e 00 00 00                                    |.....|
 >>> Flow 3 (client to server)
-00000000  16 03 00 00 84 10 00 00  80 4d 66 7a f3 f8 ab 86  |.........Mfz....|
-00000010  43 4c 5f 7c 52 ca e7 3f  ba 62 b3 82 88 16 7d ca  |CL_|R..?.b....}.|
-00000020  3a 66 15 c0 36 55 2c ab  bf 30 6b cd 9c d8 b9 48  |:f..6U,..0k....H|
-00000030  03 c9 d0 98 ab 0b a6 5b  39 c8 fe 82 8e bb f0 16  |.......[9.......|
-00000040  6f 96 62 81 f2 dc 52 02  c9 de e4 47 73 21 6e 1e  |o.b...R....Gs!n.|
-00000050  3a 11 89 7a e2 6b 9e 04  64 72 15 ba 2d 10 a2 69  |:..z.k..dr..-..i|
-00000060  07 e6 ba 17 cf 54 d6 4e  5f 99 e8 59 8b 54 ce 8e  |.....T.N_..Y.T..|
-00000070  6b 58 ba 83 68 46 4a 5f  43 3e 9b e1 32 a2 19 42  |kX..hFJ_C>..2..B|
-00000080  46 0f e4 47 1a 3b 16 5f  e1 14 03 00 00 01 01 16  |F..G.;._........|
-00000090  03 00 00 3c 78 7e ee da  0d 38 0b 1a d6 d4 8e d5  |...<x~...8......|
-000000a0  6a c5 3a 0f 85 e7 37 a6  3c 8d 1e 4b da 02 94 bf  |j.:...7.<..K....|
-000000b0  ae 2c 50 3b 4e 1c 0c 3c  4f cc d5 1c da 33 13 43  |.,P;N..<O....3.C|
-000000c0  37 64 44 ac 26 43 28 0b  d0 c2 04 09 b5 0f 23 1d  |7dD.&C(.......#.|
+00000000  16 03 00 00 84 10 00 00  80 25 85 a3 22 29 e4 fb  |.........%..")..|
+00000010  53 b9 a3 6b ed 70 2b 35  7f db 08 35 b8 4c 95 cd  |S..k.p+5...5.L..|
+00000020  00 ec 5e a1 2e ba e9 ac  a6 d4 ef ca 74 a0 12 1b  |..^.........t...|
+00000030  a7 ec 76 22 2c 63 71 1a  3a 50 94 ce 96 c4 d7 76  |..v",cq.:P.....v|
+00000040  1f 47 58 c7 57 98 af ea  7e 57 05 68 d3 f9 87 02  |.GX.W...~W.h....|
+00000050  35 72 35 66 08 b4 cf 48  24 15 92 d5 ba 46 8d 60  |5r5f...H$....F.`|
+00000060  5a 53 0b e4 9b 53 44 55  dc 77 d1 e4 e0 25 51 f6  |ZS...SDU.w...%Q.|
+00000070  f1 7c 96 0b 32 d4 8c 04  d3 3d e6 70 c7 d6 60 a7  |.|..2....=.p..`.|
+00000080  ae 69 22 69 41 1a 8d 12  67 14 03 00 00 01 01 16  |.i"iA...g.......|
+00000090  03 00 00 3c 32 dd 86 fd  5b 53 74 ea 01 45 5b 9e  |...<2...[St..E[.|
+000000a0  32 d0 9d 27 e8 ce 4c d5  a1 c2 d3 2e 0a e9 e5 d2  |2..'..L.........|
+000000b0  04 8c 77 a3 ff e9 8b 02  14 16 af 54 db ec c4 98  |..w........T....|
+000000c0  72 50 f7 65 fa eb ac 11  07 81 d7 fa 4e 18 34 bc  |rP.e........N.4.|
 >>> Flow 4 (server to client)
-00000000  14 03 00 00 01 01 16 03  00 00 3c 23 29 64 62 23  |..........<#)db#|
-00000010  19 20 f8 2e 15 07 ee c8  f4 ab f0 3e 66 c3 ed 7b  |. .........>f..{|
-00000020  7c a7 c2 7e c3 25 3c 8f  f3 04 dc 37 e8 fc 0a 1d  ||..~.%<....7....|
-00000030  fa 7a 09 d4 21 11 e3 24  21 4b 37 d1 85 cc 40 bf  |.z..!..$!K7... at .|
-00000040  bd bd f8 59 6b cd 73 17  03 00 00 21 47 1d ac 54  |...Yk.s....!G..T|
-00000050  bd 58 a6 c0 04 e2 0c 6b  66 64 5a 85 09 0e 47 fc  |.X.....kfdZ...G.|
-00000060  0b 57 ee f1 24 b6 89 57  46 be 6b 0d f2 15 03 00  |.W..$..WF.k.....|
-00000070  00 16 b4 f7 34 99 19 43  b6 b3 5a 8b c3 d2 67 2f  |....4..C..Z...g/|
-00000080  3b 19 1c 31 d4 f9 bd 96                           |;..1....|
+00000000  14 03 00 00 01 01 16 03  00 00 3c 29 af 2c 96 3a  |..........<).,.:|
+00000010  be a0 91 a8 e4 66 6b 30  ba e2 80 fc a2 8a 09 b4  |.....fk0........|
+00000020  28 14 3b 36 c2 3b 3e 88  e2 10 da 93 af 71 9a 06  |(.;6.;>......q..|
+00000030  1c 8d 97 04 05 ec e2 69  cf 28 20 0f ec 4c a7 f3  |.......i.( ..L..|
+00000040  18 4e 6b 5b 88 9c a9 17  03 00 00 21 5e 0b b4 2d  |.Nk[.......!^..-|
+00000050  a6 b5 0b 3a 86 de 8a e7  87 f3 4c f6 74 7e 0d 16  |...:......L.t~..|
+00000060  9b fc 0c 42 6b f4 9e 15  8b 6a c5 97 88 15 03 00  |...Bk....j......|
+00000070  00 16 f0 a4 e2 16 bf 81  05 ad 1d f5 1c 89 d9 ab  |................|
+00000080  48 23 ab 96 ea 92 aa cd                           |H#......|
diff --git a/src/crypto/tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES b/src/crypto/tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES
index 9b8cb4d..f81ffc2 100644
--- a/src/crypto/tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES
+++ b/src/crypto/tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES
@@ -1,12 +1,13 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 76 01 00 00  72 03 01 53 04 f0 f9 4b  |....v...r..S...K|
-00000010  30 a8 68 d0 79 13 14 69  ee 3b 5d 05 cb 71 63 43  |0.h.y..i.;]..qcC|
-00000020  4a 55 6b 05 25 53 19 ba  e0 2f b1 00 00 04 c0 0a  |JUk.%S.../......|
-00000030  00 ff 01 00 00 45 00 0b  00 04 03 00 01 02 00 0a  |.....E..........|
-00000040  00 34 00 32 00 0e 00 0d  00 19 00 0b 00 0c 00 18  |.4.2............|
-00000050  00 09 00 0a 00 16 00 17  00 08 00 06 00 07 00 14  |................|
-00000060  00 15 00 04 00 05 00 12  00 13 00 01 00 02 00 03  |................|
-00000070  00 0f 00 10 00 11 00 0f  00 01 01                 |...........|
+00000000  16 03 01 00 7d 01 00 00  79 03 01 65 14 3f 40 e4  |....}...y..e.?@.|
+00000010  2f 74 65 7e d0 c8 87 03  59 61 9d c3 84 5e c9 62  |/te~....Ya...^.b|
+00000020  e6 46 b8 0c 4a 5e 3f 33  43 a5 dd 00 00 04 c0 0a  |.F..J^?3C.......|
+00000030  00 ff 02 01 00 00 4b 00  0b 00 04 03 00 01 02 00  |......K.........|
+00000040  0a 00 3a 00 38 00 0e 00  0d 00 19 00 1c 00 0b 00  |..:.8...........|
+00000050  0c 00 1b 00 18 00 09 00  0a 00 1a 00 16 00 17 00  |................|
+00000060  08 00 06 00 07 00 14 00  15 00 04 00 05 00 12 00  |................|
+00000070  13 00 01 00 02 00 03 00  0f 00 10 00 11 00 0f 00  |................|
+00000080  01 01                                             |..|
 >>> Flow 2 (server to client)
 00000000  16 03 01 00 31 02 00 00  2d 03 01 00 00 00 00 00  |....1...-.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
@@ -49,36 +50,36 @@
 00000260  75 71 b5 e5 54 5b 12 2e  8f 09 67 fd a7 24 20 3e  |uq..T[....g..$ >|
 00000270  b2 56 1c ce 97 28 5e f8  2b 2d 4f 9e f1 07 9f 6c  |.V...(^.+-O....l|
 00000280  4b 5b 83 56 e2 32 42 e9  58 b6 d7 49 a6 b5 68 1a  |K[.V.2B.X..I..h.|
-00000290  41 03 56 6b dc 5a 89 00  8b 30 81 88 02 42 00 c6  |A.Vk.Z...0...B..|
-000002a0  85 8e 06 b7 04 04 e9 cd  9e 3e cb 66 23 95 b4 42  |.........>.f#..B|
-000002b0  9c 64 81 39 05 3f b5 21  f8 28 af 60 6b 4d 3d ba  |.d.9.?.!.(.`kM=.|
-000002c0  a1 4b 5e 77 ef e7 59 28  fe 1d c1 27 a2 ff a8 de  |.K^w..Y(...'....|
-000002d0  33 48 b3 c1 85 6a 42 9b  f9 7e 7e 31 c2 e5 bd 66  |3H...jB..~~1...f|
-000002e0  02 42 00 ad 7d 06 35 ab  ec 8d ac d4 ba 1b 49 5e  |.B..}.5.......I^|
-000002f0  05 5f f0 97 93 82 b8 2b  8d 91 98 63 8e b4 14 62  |._.....+...c...b|
-00000300  db 1e c9 2b 30 f8 41 9b  a6 e6 bc de 0e 68 30 21  |...+0.A......h0!|
-00000310  d8 ef 2f 05 42 da f2 e0  2c 06 33 1d 0d 9a 1a 75  |../.B...,.3....u|
-00000320  59 a7 3a bc 16 03 01 00  04 0e 00 00 00           |Y.:..........|
+00000290  41 03 56 6b dc 5a 89 00  8b 30 81 88 02 42 01 3e  |A.Vk.Z...0...B.>|
+000002a0  79 81 6e 89 cd 3e 3f ec  e4 b5 75 17 28 ee fb 09  |y.n..>?...u.(...|
+000002b0  21 19 6f 3c e6 ca 1e f2  18 b6 47 f8 37 05 1c 85  |!.o<......G.7...|
+000002c0  0f a4 b8 6b 40 04 50 77  e3 05 9b 24 b8 93 e8 4d  |...k at .Pw...$...M|
+000002d0  ef 30 cd 51 90 58 a2 49  71 b3 3f b9 46 ab a9 72  |.0.Q.X.Iq.?.F..r|
+000002e0  02 42 01 58 ef 20 c1 0a  33 f8 fd 50 9e 65 f5 ef  |.B.X. ..3..P.e..|
+000002f0  f4 91 49 2d d2 de 66 2b  97 69 7d b1 d0 ef d6 91  |..I-..f+.i}.....|
+00000300  0f fc 57 2b 73 b9 49 01  33 d2 1b 5b 9a 2c 51 35  |..W+s.I.3..[.,Q5|
+00000310  0e eb 38 53 fa 20 07 84  52 b3 43 24 09 5a 32 c0  |..8S. ..R.C$.Z2.|
+00000320  32 17 34 6c 16 03 01 00  04 0e 00 00 00           |2.4l.........|
 >>> Flow 3 (client to server)
-00000000  16 03 01 00 46 10 00 00  42 41 04 08 28 cf bd 3c  |....F...BA..(..<|
-00000010  3c cc 98 9e 73 3f 92 a7  cb 22 83 3b c7 61 46 0e  |<...s?...".;.aF.|
-00000020  4d 7c 30 b5 06 85 2f 01  be b5 40 e2 64 1e 45 c1  |M|0.../... at .d.E.|
-00000030  9d 73 95 d5 65 92 0b 9b  e7 6f c6 91 ab b6 fa be  |.s..e....o......|
-00000040  61 83 a7 f2 eb f5 65 31  fe 24 7b 14 03 01 00 01  |a.....e1.${.....|
-00000050  01 16 03 01 00 30 15 d1  c4 ca 0b 01 84 13 5a ba  |.....0........Z.|
-00000060  89 04 87 73 7c bb d8 89  7e 10 27 ba 6f 5d dc d3  |...s|...~.'.o]..|
-00000070  b5 ef 32 86 58 cc fb eb  5c 32 9e 95 ef 01 1c ac  |..2.X...\2......|
-00000080  dc 8e df 7f fe 0a                                 |......|
+00000000  16 03 01 00 46 10 00 00  42 41 04 31 74 f8 f6 18  |....F...BA.1t...|
+00000010  55 6a 9b 3b 78 0a 0e f0  c9 91 aa 8e 77 39 0a 88  |Uj.;x.......w9..|
+00000020  a4 d4 f6 04 9d de 89 18  b6 50 12 72 26 9c 8f e1  |.........P.r&...|
+00000030  f0 b2 e6 df ce 3b 46 be  e9 2a 9a e3 7f d1 d5 92  |.....;F..*......|
+00000040  ff e3 ae 0a 2d a1 3b 07  f6 04 59 14 03 01 00 01  |....-.;...Y.....|
+00000050  01 16 03 01 00 30 02 4f  df 41 30 97 6f f7 18 ca  |.....0.O.A0.o...|
+00000060  05 35 17 a1 a2 a5 71 61  b1 d8 dd 9a c6 f3 54 53  |.5....qa......TS|
+00000070  84 f6 fb 93 1e 0e 9d e7  fe 35 85 9e 73 d0 2e a1  |.........5..s...|
+00000080  a7 63 d9 40 c6 ac                                 |.c. at ..|
 >>> Flow 4 (server to client)
-00000000  14 03 01 00 01 01 16 03  01 00 30 e8 48 86 81 3c  |..........0.H..<|
-00000010  f5 25 5c 94 a9 06 c4 5c  71 62 b1 43 76 ec 2c 44  |.%\....\qb.Cv.,D|
-00000020  95 b5 8c 95 d2 ff 82 92  b6 fc 52 75 03 c6 a1 f0  |..........Ru....|
-00000030  99 6d b1 ed ec 68 6c d7  9f 18 50 17 03 01 00 20  |.m...hl...P.... |
-00000040  32 d9 26 8a 81 b8 9d a5  7b fd d5 4e 7a db 2e 29  |2.&.....{..Nz..)|
-00000050  58 9a 4f 6a 27 18 bc dc  c2 49 b8 65 cb 8e 16 5a  |X.Oj'....I.e...Z|
-00000060  17 03 01 00 30 c4 56 0a  ad 9a 82 cb 3e 32 f1 7c  |....0.V.....>2.||
-00000070  95 6e dd cd e9 4d f0 e5  2d c9 a3 f7 de bb d7 fd  |.n...M..-.......|
-00000080  84 bb df 34 8c 64 1f 03  58 64 19 4a 5b 7a a8 81  |...4.d..Xd.J[z..|
-00000090  52 bb 51 0a 43 15 03 01  00 20 89 18 7a 40 ec 49  |R.Q.C.... ..z at .I|
-000000a0  52 d5 d3 20 ac 07 eb e9  4a 78 23 cf e7 21 32 74  |R.. ....Jx#..!2t|
-000000b0  ec 40 8d a8 f4 33 1c ae  93 cf                    |. at ...3....|
+00000000  14 03 01 00 01 01 16 03  01 00 30 07 7e 4e 9c 19  |..........0.~N..|
+00000010  f0 35 cd 02 b7 a6 0a 1a  b1 a8 11 a3 f9 b1 35 7b  |.5............5{|
+00000020  96 7f e6 e1 00 c6 6d 9e  e6 8a bb a2 b8 bd a3 9d  |......m.........|
+00000030  05 22 1b f1 f5 28 4a 00  6e f1 71 17 03 01 00 20  |."...(J.n.q.... |
+00000040  ad c7 4c dc f4 81 1a 39  3d 86 5e 8e f5 0d a3 33  |..L....9=.^....3|
+00000050  88 32 e7 be 8b 6a 8d 44  29 7b 47 fd e5 33 01 1e  |.2...j.D){G..3..|
+00000060  17 03 01 00 30 61 47 ee  ae 89 25 ac 85 3b 8a 84  |....0aG...%..;..|
+00000070  47 61 ea 3e 4c 70 57 07  d6 f1 1c 21 cb 44 7e de  |Ga.>LpW....!.D~.|
+00000080  b5 01 9e fb fe ad bc be  74 c0 65 a0 6b c1 0c 8c  |........t.e.k...|
+00000090  2b 00 24 c6 b7 15 03 01  00 20 b7 8b 6b e5 77 ab  |+.$...... ..k.w.|
+000000a0  f6 50 9e 88 4d 56 a8 25  8d 02 db cb 68 8b 3f 62  |.P..MV.%....h.?b|
+000000b0  be aa 02 24 75 b1 e5 4b  18 c9                    |...$u..K..|
diff --git a/src/crypto/tls/testdata/Server-TLSv10-RSA-3DES b/src/crypto/tls/testdata/Server-TLSv10-RSA-3DES
index c0e6241..55cb487 100644
--- a/src/crypto/tls/testdata/Server-TLSv10-RSA-3DES
+++ b/src/crypto/tls/testdata/Server-TLSv10-RSA-3DES
@@ -1,79 +1,74 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 36 01 00 00  32 03 01 52 cc 57 59 13  |....6...2..R.WY.|
-00000010  8b e6 5b a3 1d cb 94 ef  48 e4 59 7e 20 6d 07 67  |..[.....H.Y~ m.g|
-00000020  1e 28 6d 31 a2 e7 96 b3  7d 32 cc 00 00 04 00 0a  |.(m1....}2......|
+00000000  16 03 01 00 36 01 00 00  32 03 01 35 4a e8 32 84  |....6...2..5J.2.|
+00000010  51 68 04 7e d0 0f 43 94  c7 5d 44 d2 95 a3 12 63  |Qh.~..C..]D....c|
+00000020  77 c5 ce 78 5a 25 a3 81  df c4 6b 00 00 04 00 0a  |w..xZ%....k.....|
 00000030  00 ff 01 00 00 05 00 0f  00 01 01                 |...........|
 >>> Flow 2 (server to client)
 00000000  16 03 01 00 31 02 00 00  2d 03 01 00 00 00 00 00  |....1...-.......|
 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 0a 00 00  |................|
-00000030  05 ff 01 00 01 00 16 03  01 02 be 0b 00 02 ba 00  |................|
-00000040  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
-00000050  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
-00000060  09 2a 86 48 86 f7 0d 01  01 05 05 00 30 45 31 0b  |.*.H........0E1.|
-00000070  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
-00000080  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
-00000090  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
-000000a0  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
-000000b0  4c 74 64 30 1e 17 0d 31  30 30 34 32 34 30 39 30  |Ltd0...100424090|
-000000c0  39 33 38 5a 17 0d 31 31  30 34 32 34 30 39 30 39  |938Z..1104240909|
-000000d0  33 38 5a 30 45 31 0b 30  09 06 03 55 04 06 13 02  |38Z0E1.0...U....|
-000000e0  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
-000000f0  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
-00000100  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
-00000110  74 73 20 50 74 79 20 4c  74 64 30 81 9f 30 0d 06  |ts Pty Ltd0..0..|
-00000120  09 2a 86 48 86 f7 0d 01  01 01 05 00 03 81 8d 00  |.*.H............|
-00000130  30 81 89 02 81 81 00 bb  79 d6 f5 17 b5 e5 bf 46  |0.......y......F|
-00000140  10 d0 dc 69 be e6 2b 07  43 5a d0 03 2d 8a 7a 43  |...i..+.CZ..-.zC|
-00000150  85 b7 14 52 e7 a5 65 4c  2c 78 b8 23 8c b5 b4 82  |...R..eL,x.#....|
-00000160  e5 de 1f 95 3b 7e 62 a5  2c a5 33 d6 fe 12 5c 7a  |....;~b.,.3...\z|
-00000170  56 fc f5 06 bf fa 58 7b  26 3f b5 cd 04 d3 d0 c9  |V.....X{&?......|
-00000180  21 96 4a c7 f4 54 9f 5a  bf ef 42 71 00 fe 18 99  |!.J..T.Z..Bq....|
-00000190  07 7f 7e 88 7d 7d f1 04  39 c4 a2 2e db 51 c9 7c  |..~.}}..9....Q.||
-000001a0  e3 c0 4c 3b 32 66 01 cf  af b1 1d b8 71 9a 1d db  |..L;2f......q...|
-000001b0  db 89 6b ae da 2d 79 02  03 01 00 01 a3 81 a7 30  |..k..-y........0|
-000001c0  81 a4 30 1d 06 03 55 1d  0e 04 16 04 14 b1 ad e2  |..0...U.........|
-000001d0  85 5a cf cb 28 db 69 ce  23 69 de d3 26 8e 18 88  |.Z..(.i.#i..&...|
-000001e0  39 30 75 06 03 55 1d 23  04 6e 30 6c 80 14 b1 ad  |90u..U.#.n0l....|
-000001f0  e2 85 5a cf cb 28 db 69  ce 23 69 de d3 26 8e 18  |..Z..(.i.#i..&..|
-00000200  88 39 a1 49 a4 47 30 45  31 0b 30 09 06 03 55 04  |.9.I.G0E1.0...U.|
-00000210  06 13 02 41 55 31 13 30  11 06 03 55 04 08 13 0a  |...AU1.0...U....|
-00000220  53 6f 6d 65 2d 53 74 61  74 65 31 21 30 1f 06 03  |Some-State1!0...|
-00000230  55 04 0a 13 18 49 6e 74  65 72 6e 65 74 20 57 69  |U....Internet Wi|
-00000240  64 67 69 74 73 20 50 74  79 20 4c 74 64 82 09 00  |dgits Pty Ltd...|
-00000250  85 b0 bb a4 8a 7f b8 ca  30 0c 06 03 55 1d 13 04  |........0...U...|
-00000260  05 30 03 01 01 ff 30 0d  06 09 2a 86 48 86 f7 0d  |.0....0...*.H...|
-00000270  01 01 05 05 00 03 81 81  00 08 6c 45 24 c7 6b b1  |..........lE$.k.|
-00000280  59 ab 0c 52 cc f2 b0 14  d7 87 9d 7a 64 75 b5 5a  |Y..R.......zdu.Z|
-00000290  95 66 e4 c5 2b 8e ae 12  66 1f eb 4f 38 b3 6e 60  |.f..+...f..O8.n`|
-000002a0  d3 92 fd f7 41 08 b5 25  13 b1 18 7a 24 fb 30 1d  |....A..%...z$.0.|
-000002b0  ba ed 98 b9 17 ec e7 d7  31 59 db 95 d3 1d 78 ea  |........1Y....x.|
-000002c0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
-000002d0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
-000002e0  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
-000002f0  6e 38 50 29 6c 90 a7 bd  d9 16 03 01 00 04 0e 00  |n8P)l...........|
-00000300  00 00                                             |..|
+00000030  05 ff 01 00 01 00 16 03  01 02 71 0b 00 02 6d 00  |..........q...m.|
+00000040  02 6a 00 02 67 30 82 02  63 30 82 01 cc a0 03 02  |.j..g0..c0......|
+00000050  01 02 02 09 00 a2 73 00  0c 81 00 cb f3 30 0d 06  |......s......0..|
+00000060  09 2a 86 48 86 f7 0d 01  01 0b 05 00 30 2b 31 17  |.*.H........0+1.|
+00000070  30 15 06 03 55 04 0a 13  0e 47 6f 6f 67 6c 65 20  |0...U....Google |
+00000080  54 45 53 54 49 4e 47 31  10 30 0e 06 03 55 04 03  |TESTING1.0...U..|
+00000090  13 07 47 6f 20 52 6f 6f  74 30 1e 17 0d 31 35 30  |..Go Root0...150|
+000000a0  31 30 31 30 30 30 30 30  30 5a 17 0d 32 35 30 31  |101000000Z..2501|
+000000b0  30 31 30 30 30 30 30 30  5a 30 26 31 17 30 15 06  |01000000Z0&1.0..|
+000000c0  03 55 04 0a 13 0e 47 6f  6f 67 6c 65 20 54 45 53  |.U....Google TES|
+000000d0  54 49 4e 47 31 0b 30 09  06 03 55 04 03 13 02 47  |TING1.0...U....G|
+000000e0  6f 30 81 9f 30 0d 06 09  2a 86 48 86 f7 0d 01 01  |o0..0...*.H.....|
+000000f0  01 05 00 03 81 8d 00 30  81 89 02 81 81 00 af 87  |.......0........|
+00000100  88 f6 20 1b 95 65 6c 14  ab 44 05 af 3b 45 14 e3  |.. ..el..D..;E..|
+00000110  b7 6d fd 00 63 4d 95 7f  fe 6a 62 35 86 c0 4a f9  |.m..cM...jb5..J.|
+00000120  18 7c f6 aa 25 5e 7a 64  31 66 00 ba f4 8e 92 af  |.|..%^zd1f......|
+00000130  c7 6b d8 76 d4 f3 5f 41  cb 6e 56 15 97 1b 97 c1  |.k.v.._A.nV.....|
+00000140  3c 12 39 21 66 3d 2b 16  d1 bc db 1c c0 a7 da b7  |<.9!f=+.........|
+00000150  ca ad ba da cb d5 21 50  ec de 8d ab d1 6b 81 4b  |......!P.....k.K|
+00000160  89 02 f3 c4 be c1 6c 89  b1 44 84 bd 21 d1 04 7d  |......l..D..!..}|
+00000170  9d 16 4d f9 82 15 f6 ef  fa d6 09 47 f2 fb 02 03  |..M........G....|
+00000180  01 00 01 a3 81 93 30 81  90 30 0e 06 03 55 1d 0f  |......0..0...U..|
+00000190  01 01 ff 04 04 03 02 05  a0 30 1d 06 03 55 1d 25  |.........0...U.%|
+000001a0  04 16 30 14 06 08 2b 06  01 05 05 07 03 01 06 08  |..0...+.........|
+000001b0  2b 06 01 05 05 07 03 02  30 0c 06 03 55 1d 13 01  |+.......0...U...|
+000001c0  01 ff 04 02 30 00 30 19  06 03 55 1d 0e 04 12 04  |....0.0...U.....|
+000001d0  10 12 50 8d 89 6f 1b d1  dc 54 4d 6e cb 69 5e 06  |..P..o...TMn.i^.|
+000001e0  f4 30 1b 06 03 55 1d 23  04 14 30 12 80 10 bf 3d  |.0...U.#..0....=|
+000001f0  b6 a9 66 f2 b8 40 cf ea  b4 03 78 48 1a 41 30 19  |..f.. at ....xH.A0.|
+00000200  06 03 55 1d 11 04 12 30  10 82 0e 65 78 61 6d 70  |..U....0...examp|
+00000210  6c 65 2e 67 6f 6c 61 6e  67 30 0d 06 09 2a 86 48  |le.golang0...*.H|
+00000220  86 f7 0d 01 01 0b 05 00  03 81 81 00 92 7c af 91  |.............|..|
+00000230  55 12 18 96 59 31 a6 48  40 d5 2d d5 ee bb 02 a0  |U...Y1.H at .-.....|
+00000240  f5 c2 1e 7c 9b b3 30 7d  3c dc 76 da 4f 3d c0 fa  |...|..0}<.v.O=..|
+00000250  ae 2d 33 24 6b 03 7b 1b  67 59 11 21 b5 11 bc 77  |.-3$k.{.gY.!...w|
+00000260  b9 d9 e0 6e a8 2d 2e 35  fa 64 5f 22 3e 63 10 6b  |...n.-.5.d_">c.k|
+00000270  be ff 14 86 6d 0d f0 15  31 a8 14 38 1e 3b 84 87  |....m...1..8.;..|
+00000280  2c cb 98 ed 51 76 b9 b1  4f dd db 9b 84 04 86 40  |,...Qv..O......@|
+00000290  fa 51 dd ba b4 8d eb e3  46 de 46 b9 4f 86 c7 f9  |.Q......F.F.O...|
+000002a0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 01 00  |..A4......9.....|
+000002b0  04 0e 00 00 00                                    |.....|
 >>> Flow 3 (client to server)
-00000000  16 03 01 00 86 10 00 00  82 00 80 2e af d2 61 f6  |..............a.|
-00000010  e2 b8 24 da 28 17 55 99  fd 11 bd 7a ab 98 dd f2  |..$.(.U....z....|
-00000020  f6 5f e0 11 6b 12 61 6f  86 48 b2 6e db f0 dd d5  |._..k.ao.H.n....|
-00000030  07 88 e5 95 f4 2d 6b 0c  d0 09 1a 5e 5f 50 1f dc  |.....-k....^_P..|
-00000040  f2 e7 02 7d 5e a0 70 29  80 ef 87 aa cc 95 3f 2e  |...}^.p)......?.|
-00000050  24 d1 40 b6 62 53 1d 25  31 87 1e 2f 77 d3 e1 1c  |$. at .bS.%1../w...|
-00000060  c4 99 89 bc 99 09 e9 ad  1f ce 09 e6 36 1c 3e 97  |............6.>.|
-00000070  be 62 69 a0 4e 14 20 9c  82 2a 3e fc 7e 9b c4 7a  |.bi.N. ..*>.~..z|
-00000080  5a f7 ad 1a 03 17 2a f8  7a 5f 44 14 03 01 00 01  |Z.....*.z_D.....|
-00000090  01 16 03 01 00 28 49 6b  da 73 07 ad 85 9a 0e fb  |.....(Ik.s......|
-000000a0  dd e0 69 ef c9 22 2d 86  91 51 26 63 d0 24 7d 16  |..i.."-..Q&c.$}.|
-000000b0  3c db 9b 00 c9 7e 64 e2  69 02 85 7d f7 47        |<....~d.i..}.G|
+00000000  16 03 01 00 86 10 00 00  82 00 80 1f 4d 12 64 f2  |............M.d.|
+00000010  72 22 86 4a 16 05 3f d2  1b e5 ed a7 f1 19 c4 6d  |r".J..?........m|
+00000020  1d 3a 5c f6 46 8f b9 4d  9e c4 d4 19 95 0a 63 9f  |.:\.F..M......c.|
+00000030  8a 41 1f fc d5 98 45 ca  69 33 37 64 d5 c8 0e 5a  |.A....E.i37d...Z|
+00000040  12 9f 06 54 8a 61 8b 13  f0 d8 fb b9 97 fb cd 1d  |...T.a..........|
+00000050  bd 6c 88 cc 98 57 c3 66  3a 86 04 c9 b9 21 c6 f2  |.l...W.f:....!..|
+00000060  f3 43 7d 4e bf 28 d5 a2  d7 39 e0 78 cb eb b4 af  |.C}N.(...9.x....|
+00000070  21 0e ae 4c 16 9b b3 49  5f 81 02 55 59 97 d9 d2  |!..L...I_..UY...|
+00000080  c4 e2 4c be 0a a6 41 62  48 1d 66 14 03 01 00 01  |..L...AbH.f.....|
+00000090  01 16 03 01 00 28 9d e0  c3 31 82 c2 48 5d fb 47  |.....(...1..H].G|
+000000a0  85 60 d4 17 d2 4f 4d 3c  64 db e4 49 1f a9 66 93  |.`...OM<d..I..f.|
+000000b0  72 6c 32 06 a5 0c 1f db  64 6d 54 71 fd 30        |rl2.....dmTq.0|
 >>> Flow 4 (server to client)
-00000000  14 03 01 00 01 01 16 03  01 00 28 dc 60 83 43 6c  |..........(.`.Cl|
-00000010  37 79 ab 6e 92 1f 66 d0  b1 12 ce c1 64 9d 2b 68  |7y.n..f.....d.+h|
-00000020  c7 1a e5 1f 8c 80 08 d2  86 3e a1 2c e3 7e f4 64  |.........>.,.~.d|
-00000030  e7 96 b2 17 03 01 00 18  8d b5 7c 03 78 cf dc 09  |..........|.x...|
-00000040  95 06 4b a6 82 f9 30 d2  6b 26 cb 0a 9a 9d 47 9f  |..K...0.k&....G.|
-00000050  17 03 01 00 28 30 a9 55  dd b9 4d 6a 76 00 39 96  |....(0.U..Mjv.9.|
-00000060  a3 94 6a df e5 af 1e a2  eb bb e4 ac 95 2c f7 93  |..j..........,..|
-00000070  ef d1 b5 13 d8 e2 06 1a  ad 5c 00 dd 0c 15 03 01  |.........\......|
-00000080  00 18 a5 62 e4 8b 51 1d  28 46 bc 8a c8 50 a3 32  |...b..Q.(F...P.2|
-00000090  6b 7b f1 b6 19 43 63 1f  7d 38                    |k{...Cc.}8|
+00000000  14 03 01 00 01 01 16 03  01 00 28 94 66 8f ad 8f  |..........(.f...|
+00000010  9f 00 72 f6 af 51 47 67  63 df 3f dd 17 09 0a c5  |..r..QGgc.?.....|
+00000020  bf f8 4d 66 39 f9 b5 47  01 f8 e8 6d ed b4 17 39  |..Mf9..G...m...9|
+00000030  ff 0a ca 17 03 01 00 18  68 93 94 51 12 b9 17 0b  |........h..Q....|
+00000040  d1 a0 22 fc cc c4 76 1a  1e 02 c6 20 5e 74 83 4c  |.."...v.... ^t.L|
+00000050  17 03 01 00 28 08 bd 86  07 84 90 78 bd 1d 90 ce  |....(......x....|
+00000060  09 80 bb d8 de fd 39 82  4b c4 0d 06 f3 65 f5 5b  |......9.K....e.[|
+00000070  3d c3 fd 69 80 1f 51 ce  1d 98 f1 05 fa 15 03 01  |=..i..Q.........|
+00000080  00 18 ed 48 04 21 85 77  d7 b6 29 e3 25 af ea ec  |...H.!.w..).%...|
+00000090  3e 41 82 a0 ca 7d 44 79  8a 0b                    |>A...}Dy..|
diff --git a/src/crypto/tls/testdata/Server-TLSv10-RSA-AES b/src/crypto/tls/testdata/Server-TLSv10-RSA-AES
index 1670997..4671302 100644
--- a/src/crypto/tls/testdata/Server-TLSv10-RSA-AES
+++ b/src/crypto/tls/testdata/Server-TLSv10-RSA-AES
@@ -1,82 +1,77 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 36 01 00 00  32 03 01 52 cc 57 59 5d  |....6...2..R.WY]|
-00000010  0d 77 24 3e b3 32 3d ba  0f b0 aa 1d e3 13 06 f6  |.w$>.2=.........|
-00000020  0f be 3c 92 ba 93 bd a6  6d 69 53 00 00 04 00 2f  |..<.....miS..../|
+00000000  16 03 01 00 36 01 00 00  32 03 01 8c 5a 87 31 6a  |....6...2...Z.1j|
+00000010  8c 7a d5 26 4b 94 17 27  fc a2 c0 5f b5 bc 3f 10  |.z.&K..'..._..?.|
+00000020  80 0e e0 1e 36 80 4b 91  61 77 d4 00 00 04 00 2f  |....6.K.aw...../|
 00000030  00 ff 01 00 00 05 00 0f  00 01 01                 |...........|
 >>> Flow 2 (server to client)
 00000000  16 03 01 00 31 02 00 00  2d 03 01 00 00 00 00 00  |....1...-.......|
 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 2f 00 00  |............./..|
-00000030  05 ff 01 00 01 00 16 03  01 02 be 0b 00 02 ba 00  |................|
-00000040  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
-00000050  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
-00000060  09 2a 86 48 86 f7 0d 01  01 05 05 00 30 45 31 0b  |.*.H........0E1.|
-00000070  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
-00000080  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
-00000090  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
-000000a0  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
-000000b0  4c 74 64 30 1e 17 0d 31  30 30 34 32 34 30 39 30  |Ltd0...100424090|
-000000c0  39 33 38 5a 17 0d 31 31  30 34 32 34 30 39 30 39  |938Z..1104240909|
-000000d0  33 38 5a 30 45 31 0b 30  09 06 03 55 04 06 13 02  |38Z0E1.0...U....|
-000000e0  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
-000000f0  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
-00000100  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
-00000110  74 73 20 50 74 79 20 4c  74 64 30 81 9f 30 0d 06  |ts Pty Ltd0..0..|
-00000120  09 2a 86 48 86 f7 0d 01  01 01 05 00 03 81 8d 00  |.*.H............|
-00000130  30 81 89 02 81 81 00 bb  79 d6 f5 17 b5 e5 bf 46  |0.......y......F|
-00000140  10 d0 dc 69 be e6 2b 07  43 5a d0 03 2d 8a 7a 43  |...i..+.CZ..-.zC|
-00000150  85 b7 14 52 e7 a5 65 4c  2c 78 b8 23 8c b5 b4 82  |...R..eL,x.#....|
-00000160  e5 de 1f 95 3b 7e 62 a5  2c a5 33 d6 fe 12 5c 7a  |....;~b.,.3...\z|
-00000170  56 fc f5 06 bf fa 58 7b  26 3f b5 cd 04 d3 d0 c9  |V.....X{&?......|
-00000180  21 96 4a c7 f4 54 9f 5a  bf ef 42 71 00 fe 18 99  |!.J..T.Z..Bq....|
-00000190  07 7f 7e 88 7d 7d f1 04  39 c4 a2 2e db 51 c9 7c  |..~.}}..9....Q.||
-000001a0  e3 c0 4c 3b 32 66 01 cf  af b1 1d b8 71 9a 1d db  |..L;2f......q...|
-000001b0  db 89 6b ae da 2d 79 02  03 01 00 01 a3 81 a7 30  |..k..-y........0|
-000001c0  81 a4 30 1d 06 03 55 1d  0e 04 16 04 14 b1 ad e2  |..0...U.........|
-000001d0  85 5a cf cb 28 db 69 ce  23 69 de d3 26 8e 18 88  |.Z..(.i.#i..&...|
-000001e0  39 30 75 06 03 55 1d 23  04 6e 30 6c 80 14 b1 ad  |90u..U.#.n0l....|
-000001f0  e2 85 5a cf cb 28 db 69  ce 23 69 de d3 26 8e 18  |..Z..(.i.#i..&..|
-00000200  88 39 a1 49 a4 47 30 45  31 0b 30 09 06 03 55 04  |.9.I.G0E1.0...U.|
-00000210  06 13 02 41 55 31 13 30  11 06 03 55 04 08 13 0a  |...AU1.0...U....|
-00000220  53 6f 6d 65 2d 53 74 61  74 65 31 21 30 1f 06 03  |Some-State1!0...|
-00000230  55 04 0a 13 18 49 6e 74  65 72 6e 65 74 20 57 69  |U....Internet Wi|
-00000240  64 67 69 74 73 20 50 74  79 20 4c 74 64 82 09 00  |dgits Pty Ltd...|
-00000250  85 b0 bb a4 8a 7f b8 ca  30 0c 06 03 55 1d 13 04  |........0...U...|
-00000260  05 30 03 01 01 ff 30 0d  06 09 2a 86 48 86 f7 0d  |.0....0...*.H...|
-00000270  01 01 05 05 00 03 81 81  00 08 6c 45 24 c7 6b b1  |..........lE$.k.|
-00000280  59 ab 0c 52 cc f2 b0 14  d7 87 9d 7a 64 75 b5 5a  |Y..R.......zdu.Z|
-00000290  95 66 e4 c5 2b 8e ae 12  66 1f eb 4f 38 b3 6e 60  |.f..+...f..O8.n`|
-000002a0  d3 92 fd f7 41 08 b5 25  13 b1 18 7a 24 fb 30 1d  |....A..%...z$.0.|
-000002b0  ba ed 98 b9 17 ec e7 d7  31 59 db 95 d3 1d 78 ea  |........1Y....x.|
-000002c0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
-000002d0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
-000002e0  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
-000002f0  6e 38 50 29 6c 90 a7 bd  d9 16 03 01 00 04 0e 00  |n8P)l...........|
-00000300  00 00                                             |..|
+00000030  05 ff 01 00 01 00 16 03  01 02 71 0b 00 02 6d 00  |..........q...m.|
+00000040  02 6a 00 02 67 30 82 02  63 30 82 01 cc a0 03 02  |.j..g0..c0......|
+00000050  01 02 02 09 00 a2 73 00  0c 81 00 cb f3 30 0d 06  |......s......0..|
+00000060  09 2a 86 48 86 f7 0d 01  01 0b 05 00 30 2b 31 17  |.*.H........0+1.|
+00000070  30 15 06 03 55 04 0a 13  0e 47 6f 6f 67 6c 65 20  |0...U....Google |
+00000080  54 45 53 54 49 4e 47 31  10 30 0e 06 03 55 04 03  |TESTING1.0...U..|
+00000090  13 07 47 6f 20 52 6f 6f  74 30 1e 17 0d 31 35 30  |..Go Root0...150|
+000000a0  31 30 31 30 30 30 30 30  30 5a 17 0d 32 35 30 31  |101000000Z..2501|
+000000b0  30 31 30 30 30 30 30 30  5a 30 26 31 17 30 15 06  |01000000Z0&1.0..|
+000000c0  03 55 04 0a 13 0e 47 6f  6f 67 6c 65 20 54 45 53  |.U....Google TES|
+000000d0  54 49 4e 47 31 0b 30 09  06 03 55 04 03 13 02 47  |TING1.0...U....G|
+000000e0  6f 30 81 9f 30 0d 06 09  2a 86 48 86 f7 0d 01 01  |o0..0...*.H.....|
+000000f0  01 05 00 03 81 8d 00 30  81 89 02 81 81 00 af 87  |.......0........|
+00000100  88 f6 20 1b 95 65 6c 14  ab 44 05 af 3b 45 14 e3  |.. ..el..D..;E..|
+00000110  b7 6d fd 00 63 4d 95 7f  fe 6a 62 35 86 c0 4a f9  |.m..cM...jb5..J.|
+00000120  18 7c f6 aa 25 5e 7a 64  31 66 00 ba f4 8e 92 af  |.|..%^zd1f......|
+00000130  c7 6b d8 76 d4 f3 5f 41  cb 6e 56 15 97 1b 97 c1  |.k.v.._A.nV.....|
+00000140  3c 12 39 21 66 3d 2b 16  d1 bc db 1c c0 a7 da b7  |<.9!f=+.........|
+00000150  ca ad ba da cb d5 21 50  ec de 8d ab d1 6b 81 4b  |......!P.....k.K|
+00000160  89 02 f3 c4 be c1 6c 89  b1 44 84 bd 21 d1 04 7d  |......l..D..!..}|
+00000170  9d 16 4d f9 82 15 f6 ef  fa d6 09 47 f2 fb 02 03  |..M........G....|
+00000180  01 00 01 a3 81 93 30 81  90 30 0e 06 03 55 1d 0f  |......0..0...U..|
+00000190  01 01 ff 04 04 03 02 05  a0 30 1d 06 03 55 1d 25  |.........0...U.%|
+000001a0  04 16 30 14 06 08 2b 06  01 05 05 07 03 01 06 08  |..0...+.........|
+000001b0  2b 06 01 05 05 07 03 02  30 0c 06 03 55 1d 13 01  |+.......0...U...|
+000001c0  01 ff 04 02 30 00 30 19  06 03 55 1d 0e 04 12 04  |....0.0...U.....|
+000001d0  10 12 50 8d 89 6f 1b d1  dc 54 4d 6e cb 69 5e 06  |..P..o...TMn.i^.|
+000001e0  f4 30 1b 06 03 55 1d 23  04 14 30 12 80 10 bf 3d  |.0...U.#..0....=|
+000001f0  b6 a9 66 f2 b8 40 cf ea  b4 03 78 48 1a 41 30 19  |..f.. at ....xH.A0.|
+00000200  06 03 55 1d 11 04 12 30  10 82 0e 65 78 61 6d 70  |..U....0...examp|
+00000210  6c 65 2e 67 6f 6c 61 6e  67 30 0d 06 09 2a 86 48  |le.golang0...*.H|
+00000220  86 f7 0d 01 01 0b 05 00  03 81 81 00 92 7c af 91  |.............|..|
+00000230  55 12 18 96 59 31 a6 48  40 d5 2d d5 ee bb 02 a0  |U...Y1.H at .-.....|
+00000240  f5 c2 1e 7c 9b b3 30 7d  3c dc 76 da 4f 3d c0 fa  |...|..0}<.v.O=..|
+00000250  ae 2d 33 24 6b 03 7b 1b  67 59 11 21 b5 11 bc 77  |.-3$k.{.gY.!...w|
+00000260  b9 d9 e0 6e a8 2d 2e 35  fa 64 5f 22 3e 63 10 6b  |...n.-.5.d_">c.k|
+00000270  be ff 14 86 6d 0d f0 15  31 a8 14 38 1e 3b 84 87  |....m...1..8.;..|
+00000280  2c cb 98 ed 51 76 b9 b1  4f dd db 9b 84 04 86 40  |,...Qv..O......@|
+00000290  fa 51 dd ba b4 8d eb e3  46 de 46 b9 4f 86 c7 f9  |.Q......F.F.O...|
+000002a0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 01 00  |..A4......9.....|
+000002b0  04 0e 00 00 00                                    |.....|
 >>> Flow 3 (client to server)
-00000000  16 03 01 00 86 10 00 00  82 00 80 20 e6 80 f7 48  |........... ...H|
-00000010  7e 7d 08 08 54 e1 b4 e3  98 27 5f 90 9d 3b e3 c2  |~}..T....'_..;..|
-00000020  c8 8b dc 9e ff 75 fa fc  60 e1 9e 67 7c c4 08 27  |.....u..`..g|..'|
-00000030  cc 6f 15 6c bc 7c 96 de  83 8f 98 6d 4a c7 b7 20  |.o.l.|.....mJ.. |
-00000040  8c 19 47 5a ff 76 92 0a  df df 66 d2 b6 9d 2d 06  |..GZ.v....f...-.|
-00000050  fb ac 07 cf 38 08 f1 fd  0d fe 07 d7 69 3e 8a 79  |....8.......i>.y|
-00000060  dc 2d ab bb f7 18 3c 51  14 6e c6 70 95 a2 59 b1  |.-....<Q.n.p..Y.|
-00000070  39 04 9f ae f3 5f fb a7  2b d3 5a c0 96 d9 4d 2a  |9...._..+.Z...M*|
-00000080  2a 6c 6d 39 ee fc ce 76  1a 92 1b 14 03 01 00 01  |*lm9...v........|
-00000090  01 16 03 01 00 30 10 20  90 7b 0e e6 c2 05 81 c3  |.....0. .{......|
-000000a0  bc da 84 67 dd 5f 97 e2  74 c4 35 4e bf d2 1b 90  |...g._..t.5N....|
-000000b0  2f e0 af dd 6b f5 52 db  36 cd 3e e1 e6 bd 99 30  |/...k.R.6.>....0|
-000000c0  ed c6 bc c2 38 b6                                 |....8.|
+00000000  16 03 01 00 86 10 00 00  82 00 80 31 f5 2e e4 c7  |...........1....|
+00000010  f5 76 d6 f7 2d 1b 8d 4d  a9 2a 43 84 b2 0b 08 d6  |.v..-..M.*C.....|
+00000020  4d d9 9a eb 4b 01 49 6e  11 45 43 0d 31 a7 c3 66  |M...K.In.EC.1..f|
+00000030  da 1c 92 68 fb 3d 36 27  94 2f 67 ae 3d 31 a3 8f  |...h.=6'./g.=1..|
+00000040  01 5a d9 17 92 bc 20 7c  cb ae b4 ca 4c ce d4 a9  |.Z.... |....L...|
+00000050  2c 1d fe fc 3c a9 14 31  1d 65 08 d8 6e 8d ac 9d  |,...<..1.e..n...|
+00000060  21 ee 63 4a e2 da 3c 0e  b1 34 8f 6e 20 dd d4 d4  |!.cJ..<..4.n ...|
+00000070  d8 16 27 5d 02 54 e6 ec  5f 43 84 5b 21 24 ef 5d  |..'].T.._C.[!$.]|
+00000080  45 c4 2b 2c 98 7d 50 dc  0b fc 76 14 03 01 00 01  |E.+,.}P...v.....|
+00000090  01 16 03 01 00 30 ef 50  ea 3c e3 b7 a8 5b 9a d2  |.....0.P.<...[..|
+000000a0  11 69 0f d0 5e 79 c8 cb  68 4a ac 16 ef b4 de 1f  |.i..^y..hJ......|
+000000b0  21 0b 8e 91 cb 70 3f 02  bd 45 c1 34 02 e0 66 8a  |!....p?..E.4..f.|
+000000c0  00 ea 6c 5a 96 41                                 |..lZ.A|
 >>> Flow 4 (server to client)
-00000000  14 03 01 00 01 01 16 03  01 00 30 5d 0c a2 18 13  |..........0]....|
-00000010  40 a1 84 ce c5 d8 4e fc  a4 8a 14 b5 94 18 b1 86  |@.....N.........|
-00000020  da 6a 7d 26 08 d6 a0 f8  78 5b 42 7e f8 83 54 56  |.j}&....x[B~..TV|
-00000030  36 a4 91 37 67 5a d7 68  37 c4 4f 17 03 01 00 20  |6..7gZ.h7.O.... |
-00000040  fd aa 5e cf 4b 12 c5 be  a4 a2 65 5d 6e 65 46 5f  |..^.K.....e]neF_|
-00000050  d2 fe 46 e7 77 2d 9c 1e  0b 39 40 48 c2 2f be 21  |..F.w-...9 at H./.!|
-00000060  17 03 01 00 30 03 af 9e  6b d6 76 ed 9e 1d 8b 8b  |....0...k.v.....|
-00000070  2e 2a 5d da c4 73 95 ac  0e 6f 69 cb 63 df 50 27  |.*]..s...oi.c.P'|
-00000080  30 de 2e 55 86 85 ad 3e  33 22 49 72 f2 e2 9f 8f  |0..U...>3"Ir....|
-00000090  ba cf 4e 30 34 15 03 01  00 20 4c 4c 97 61 70 ea  |..N04.... LL.ap.|
-000000a0  ae fc a2 e9 c6 c2 b6 2e  4d 85 f6 ae 2b 56 46 82  |........M...+VF.|
-000000b0  9d d8 a5 82 17 fa 3e 62  67 7e                    |......>bg~|
+00000000  14 03 01 00 01 01 16 03  01 00 30 99 2c 65 32 5f  |..........0.,e2_|
+00000010  53 37 d8 c2 98 87 f4 68  b6 d7 52 6a 14 c7 df 6e  |S7.....h..Rj...n|
+00000020  bb ce ae 31 d4 04 24 4d  e9 c2 39 7b 68 a7 fa 90  |...1..$M..9{h...|
+00000030  c1 30 14 a2 20 c0 8d e1  2a dc 22 17 03 01 00 20  |.0.. ...*.".... |
+00000040  41 c5 03 05 20 53 e9 fa  0a 26 38 ab 84 6a 5e 36  |A... S...&8..j^6|
+00000050  1b 03 80 2f c3 5c 0b 2c  bd 7f 79 68 bb ab 4d 70  |.../.\.,..yh..Mp|
+00000060  17 03 01 00 30 a1 04 3e  f4 a2 54 7a e7 09 0f 20  |....0..>..Tz... |
+00000070  38 f8 9e bb 1b 61 28 bf  46 e8 75 56 b4 c3 93 b9  |8....a(.F.uV....|
+00000080  8c 18 3e 8e af 9f 59 1a  96 be db 61 80 56 c6 09  |..>...Y....a.V..|
+00000090  3c 21 02 37 d2 15 03 01  00 20 13 d1 81 7d ca 04  |<!.7..... ...}..|
+000000a0  2b c3 fc fa 06 5b b4 98  59 27 0d 07 2a 39 3c 6f  |+....[..Y'..*9<o|
+000000b0  8d 64 83 17 0f ba ec 22  21 36                    |.d....."!6|
diff --git a/src/crypto/tls/testdata/Server-TLSv10-RSA-RC4 b/src/crypto/tls/testdata/Server-TLSv10-RSA-RC4
index d653561..b5cb479 100644
--- a/src/crypto/tls/testdata/Server-TLSv10-RSA-RC4
+++ b/src/crypto/tls/testdata/Server-TLSv10-RSA-RC4
@@ -1,76 +1,71 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 36 01 00 00  32 03 01 52 cc 57 59 cf  |....6...2..R.WY.|
-00000010  00 a1 49 a4 37 69 74 d8  a7 93 ea 8d e7 50 b7 b3  |..I.7it......P..|
-00000020  8c ec e5 56 fb dc 5f 1a  2e ab 18 00 00 04 00 05  |...V.._.........|
+00000000  16 03 01 00 36 01 00 00  32 03 01 c5 fc 32 c0 09  |....6...2....2..|
+00000010  47 0b a9 f3 72 c9 6c 3a  e0 94 33 48 35 ac b9 3b  |G...r.l:..3H5..;|
+00000020  da 5f 8b 6e 0c 54 c3 16  f0 39 bd 00 00 04 00 05  |._.n.T...9......|
 00000030  00 ff 01 00 00 05 00 0f  00 01 01                 |...........|
 >>> Flow 2 (server to client)
 00000000  16 03 01 00 31 02 00 00  2d 03 01 00 00 00 00 00  |....1...-.......|
 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 05 00 00  |................|
-00000030  05 ff 01 00 01 00 16 03  01 02 be 0b 00 02 ba 00  |................|
-00000040  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
-00000050  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
-00000060  09 2a 86 48 86 f7 0d 01  01 05 05 00 30 45 31 0b  |.*.H........0E1.|
-00000070  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
-00000080  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
-00000090  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
-000000a0  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
-000000b0  4c 74 64 30 1e 17 0d 31  30 30 34 32 34 30 39 30  |Ltd0...100424090|
-000000c0  39 33 38 5a 17 0d 31 31  30 34 32 34 30 39 30 39  |938Z..1104240909|
-000000d0  33 38 5a 30 45 31 0b 30  09 06 03 55 04 06 13 02  |38Z0E1.0...U....|
-000000e0  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
-000000f0  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
-00000100  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
-00000110  74 73 20 50 74 79 20 4c  74 64 30 81 9f 30 0d 06  |ts Pty Ltd0..0..|
-00000120  09 2a 86 48 86 f7 0d 01  01 01 05 00 03 81 8d 00  |.*.H............|
-00000130  30 81 89 02 81 81 00 bb  79 d6 f5 17 b5 e5 bf 46  |0.......y......F|
-00000140  10 d0 dc 69 be e6 2b 07  43 5a d0 03 2d 8a 7a 43  |...i..+.CZ..-.zC|
-00000150  85 b7 14 52 e7 a5 65 4c  2c 78 b8 23 8c b5 b4 82  |...R..eL,x.#....|
-00000160  e5 de 1f 95 3b 7e 62 a5  2c a5 33 d6 fe 12 5c 7a  |....;~b.,.3...\z|
-00000170  56 fc f5 06 bf fa 58 7b  26 3f b5 cd 04 d3 d0 c9  |V.....X{&?......|
-00000180  21 96 4a c7 f4 54 9f 5a  bf ef 42 71 00 fe 18 99  |!.J..T.Z..Bq....|
-00000190  07 7f 7e 88 7d 7d f1 04  39 c4 a2 2e db 51 c9 7c  |..~.}}..9....Q.||
-000001a0  e3 c0 4c 3b 32 66 01 cf  af b1 1d b8 71 9a 1d db  |..L;2f......q...|
-000001b0  db 89 6b ae da 2d 79 02  03 01 00 01 a3 81 a7 30  |..k..-y........0|
-000001c0  81 a4 30 1d 06 03 55 1d  0e 04 16 04 14 b1 ad e2  |..0...U.........|
-000001d0  85 5a cf cb 28 db 69 ce  23 69 de d3 26 8e 18 88  |.Z..(.i.#i..&...|
-000001e0  39 30 75 06 03 55 1d 23  04 6e 30 6c 80 14 b1 ad  |90u..U.#.n0l....|
-000001f0  e2 85 5a cf cb 28 db 69  ce 23 69 de d3 26 8e 18  |..Z..(.i.#i..&..|
-00000200  88 39 a1 49 a4 47 30 45  31 0b 30 09 06 03 55 04  |.9.I.G0E1.0...U.|
-00000210  06 13 02 41 55 31 13 30  11 06 03 55 04 08 13 0a  |...AU1.0...U....|
-00000220  53 6f 6d 65 2d 53 74 61  74 65 31 21 30 1f 06 03  |Some-State1!0...|
-00000230  55 04 0a 13 18 49 6e 74  65 72 6e 65 74 20 57 69  |U....Internet Wi|
-00000240  64 67 69 74 73 20 50 74  79 20 4c 74 64 82 09 00  |dgits Pty Ltd...|
-00000250  85 b0 bb a4 8a 7f b8 ca  30 0c 06 03 55 1d 13 04  |........0...U...|
-00000260  05 30 03 01 01 ff 30 0d  06 09 2a 86 48 86 f7 0d  |.0....0...*.H...|
-00000270  01 01 05 05 00 03 81 81  00 08 6c 45 24 c7 6b b1  |..........lE$.k.|
-00000280  59 ab 0c 52 cc f2 b0 14  d7 87 9d 7a 64 75 b5 5a  |Y..R.......zdu.Z|
-00000290  95 66 e4 c5 2b 8e ae 12  66 1f eb 4f 38 b3 6e 60  |.f..+...f..O8.n`|
-000002a0  d3 92 fd f7 41 08 b5 25  13 b1 18 7a 24 fb 30 1d  |....A..%...z$.0.|
-000002b0  ba ed 98 b9 17 ec e7 d7  31 59 db 95 d3 1d 78 ea  |........1Y....x.|
-000002c0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
-000002d0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
-000002e0  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
-000002f0  6e 38 50 29 6c 90 a7 bd  d9 16 03 01 00 04 0e 00  |n8P)l...........|
-00000300  00 00                                             |..|
+00000030  05 ff 01 00 01 00 16 03  01 02 71 0b 00 02 6d 00  |..........q...m.|
+00000040  02 6a 00 02 67 30 82 02  63 30 82 01 cc a0 03 02  |.j..g0..c0......|
+00000050  01 02 02 09 00 a2 73 00  0c 81 00 cb f3 30 0d 06  |......s......0..|
+00000060  09 2a 86 48 86 f7 0d 01  01 0b 05 00 30 2b 31 17  |.*.H........0+1.|
+00000070  30 15 06 03 55 04 0a 13  0e 47 6f 6f 67 6c 65 20  |0...U....Google |
+00000080  54 45 53 54 49 4e 47 31  10 30 0e 06 03 55 04 03  |TESTING1.0...U..|
+00000090  13 07 47 6f 20 52 6f 6f  74 30 1e 17 0d 31 35 30  |..Go Root0...150|
+000000a0  31 30 31 30 30 30 30 30  30 5a 17 0d 32 35 30 31  |101000000Z..2501|
+000000b0  30 31 30 30 30 30 30 30  5a 30 26 31 17 30 15 06  |01000000Z0&1.0..|
+000000c0  03 55 04 0a 13 0e 47 6f  6f 67 6c 65 20 54 45 53  |.U....Google TES|
+000000d0  54 49 4e 47 31 0b 30 09  06 03 55 04 03 13 02 47  |TING1.0...U....G|
+000000e0  6f 30 81 9f 30 0d 06 09  2a 86 48 86 f7 0d 01 01  |o0..0...*.H.....|
+000000f0  01 05 00 03 81 8d 00 30  81 89 02 81 81 00 af 87  |.......0........|
+00000100  88 f6 20 1b 95 65 6c 14  ab 44 05 af 3b 45 14 e3  |.. ..el..D..;E..|
+00000110  b7 6d fd 00 63 4d 95 7f  fe 6a 62 35 86 c0 4a f9  |.m..cM...jb5..J.|
+00000120  18 7c f6 aa 25 5e 7a 64  31 66 00 ba f4 8e 92 af  |.|..%^zd1f......|
+00000130  c7 6b d8 76 d4 f3 5f 41  cb 6e 56 15 97 1b 97 c1  |.k.v.._A.nV.....|
+00000140  3c 12 39 21 66 3d 2b 16  d1 bc db 1c c0 a7 da b7  |<.9!f=+.........|
+00000150  ca ad ba da cb d5 21 50  ec de 8d ab d1 6b 81 4b  |......!P.....k.K|
+00000160  89 02 f3 c4 be c1 6c 89  b1 44 84 bd 21 d1 04 7d  |......l..D..!..}|
+00000170  9d 16 4d f9 82 15 f6 ef  fa d6 09 47 f2 fb 02 03  |..M........G....|
+00000180  01 00 01 a3 81 93 30 81  90 30 0e 06 03 55 1d 0f  |......0..0...U..|
+00000190  01 01 ff 04 04 03 02 05  a0 30 1d 06 03 55 1d 25  |.........0...U.%|
+000001a0  04 16 30 14 06 08 2b 06  01 05 05 07 03 01 06 08  |..0...+.........|
+000001b0  2b 06 01 05 05 07 03 02  30 0c 06 03 55 1d 13 01  |+.......0...U...|
+000001c0  01 ff 04 02 30 00 30 19  06 03 55 1d 0e 04 12 04  |....0.0...U.....|
+000001d0  10 12 50 8d 89 6f 1b d1  dc 54 4d 6e cb 69 5e 06  |..P..o...TMn.i^.|
+000001e0  f4 30 1b 06 03 55 1d 23  04 14 30 12 80 10 bf 3d  |.0...U.#..0....=|
+000001f0  b6 a9 66 f2 b8 40 cf ea  b4 03 78 48 1a 41 30 19  |..f.. at ....xH.A0.|
+00000200  06 03 55 1d 11 04 12 30  10 82 0e 65 78 61 6d 70  |..U....0...examp|
+00000210  6c 65 2e 67 6f 6c 61 6e  67 30 0d 06 09 2a 86 48  |le.golang0...*.H|
+00000220  86 f7 0d 01 01 0b 05 00  03 81 81 00 92 7c af 91  |.............|..|
+00000230  55 12 18 96 59 31 a6 48  40 d5 2d d5 ee bb 02 a0  |U...Y1.H at .-.....|
+00000240  f5 c2 1e 7c 9b b3 30 7d  3c dc 76 da 4f 3d c0 fa  |...|..0}<.v.O=..|
+00000250  ae 2d 33 24 6b 03 7b 1b  67 59 11 21 b5 11 bc 77  |.-3$k.{.gY.!...w|
+00000260  b9 d9 e0 6e a8 2d 2e 35  fa 64 5f 22 3e 63 10 6b  |...n.-.5.d_">c.k|
+00000270  be ff 14 86 6d 0d f0 15  31 a8 14 38 1e 3b 84 87  |....m...1..8.;..|
+00000280  2c cb 98 ed 51 76 b9 b1  4f dd db 9b 84 04 86 40  |,...Qv..O......@|
+00000290  fa 51 dd ba b4 8d eb e3  46 de 46 b9 4f 86 c7 f9  |.Q......F.F.O...|
+000002a0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 01 00  |..A4......9.....|
+000002b0  04 0e 00 00 00                                    |.....|
 >>> Flow 3 (client to server)
-00000000  16 03 01 00 86 10 00 00  82 00 80 b1 96 7b 6f f5  |.............{o.|
-00000010  a0 cb 0d 60 9b 64 d3 f5  17 76 47 7b bc a5 0e 96  |...`.d...vG{....|
-00000020  53 af 68 0c 96 22 f7 28  0c 24 37 9c 51 69 ed b2  |S.h..".(.$7.Qi..|
-00000030  47 14 ba 33 c5 79 6b 96  f2 ab 3c 02 5c 37 a4 97  |G..3.yk...<.\7..|
-00000040  23 fc 7f d3 95 2d 85 99  1a 10 1b 38 e5 f1 83 55  |#....-.....8...U|
-00000050  4a ab 60 f8 89 0a 6a c4  eb 45 f5 b0 f4 f8 09 31  |J.`...j..E.....1|
-00000060  6e f0 25 30 fd 5e 68 61  bc cb 0d 9e 05 73 0a f4  |n.%0.^ha.....s..|
-00000070  a5 2e d9 d5 4e 08 f6 3b  8d 2d 21 f5 79 b6 97 55  |....N..;.-!.y..U|
-00000080  b9 99 03 49 ea 96 36 49  21 56 bf 14 03 01 00 01  |...I..6I!V......|
-00000090  01 16 03 01 00 24 f0 4f  30 06 c3 25 01 93 34 ab  |.....$.O0..%..4.|
-000000a0  93 8f 59 26 83 6e 8a fd  5a a6 cf af ad b1 a2 83  |..Y&.n..Z.......|
-000000b0  28 ff c2 66 5f ac e5 a5  a5 03                    |(..f_.....|
+00000000  16 03 01 00 86 10 00 00  82 00 80 6a ad 7f e3 26  |...........j...&|
+00000010  71 da 48 af 11 63 de 2e  e8 50 f9 6a be 04 3d 17  |q.H..c...P.j..=.|
+00000020  d1 29 fe 2c 7f b6 26 c1  7e 0b 18 1c 41 62 5c 91  |.).,..&.~...Ab\.|
+00000030  ee 26 9c 92 f5 d1 e9 29  e1 ca a7 01 6a 41 b9 00  |.&.....)....jA..|
+00000040  34 1d 5b c6 28 0e 1a 8f  32 c5 03 e7 a1 8f 89 1b  |4.[.(...2.......|
+00000050  af 13 22 2b 5b e8 76 2d  00 ac da 27 75 95 75 e7  |.."+[.v-...'u.u.|
+00000060  00 00 39 2c bf f2 01 57  e6 29 e3 26 b1 6b ae c5  |..9,...W.).&.k..|
+00000070  8d ce d2 36 b2 94 1f 9c  30 5e b2 16 3d 20 cf 4d  |...6....0^..= .M|
+00000080  88 f5 ac 4c 27 e3 f5 86  ef 9e dc 14 03 01 00 01  |...L'...........|
+00000090  01 16 03 01 00 24 48 d8  80 c4 37 22 31 99 53 30  |.....$H...7"1.S0|
+000000a0  5b 00 07 7e 87 2e 59 9a  d9 0c 42 9e dd ed da 89  |[..~..Y...B.....|
+000000b0  1a 1f cb ab 55 0c ba d9  a9 c0                    |....U.....|
 >>> Flow 4 (server to client)
-00000000  14 03 01 00 01 01 16 03  01 00 24 9d b4 ea d8 be  |..........$.....|
-00000010  b5 9f 00 fd b5 99 04 12  6b 7a 3f b8 52 d7 52 a9  |........kz?.R.R.|
-00000020  e9 bd 5b 63 ad b0 53 ac  46 80 be 48 6e dd ee 17  |..[c..S.F..Hn...|
-00000030  03 01 00 21 07 ac c4 fb  21 e4 b8 6b 64 3b b5 27  |...!....!..kd;.'|
-00000040  29 67 a1 10 2e d2 71 d5  59 5e fc 1d 84 31 15 6e  |)g....q.Y^...1.n|
-00000050  4d 4b dc a9 3a 15 03 01  00 16 25 22 a5 78 23 5a  |MK..:.....%".x#Z|
-00000060  69 6f 99 a1 b3 1c 8d bf  f3 bd 1b c8 1c 57 15 75  |io...........W.u|
+00000000  14 03 01 00 01 01 16 03  01 00 24 ae 00 c8 14 67  |..........$....g|
+00000010  4b b5 21 96 98 91 d6 27  40 9b 5e a5 86 53 56 f3  |K.!....'@.^..SV.|
+00000020  f6 dc 7e b2 49 78 4b 4d  57 7c 62 a5 f2 16 8f 17  |..~.IxKMW|b.....|
+00000030  03 01 00 21 34 e3 48 58  1c 67 fb 3a 46 28 5d a1  |...!4.HX.g.:F(].|
+00000040  19 66 58 b1 bb fb e7 17  71 07 3f 0a d0 7c c9 24  |.fX.....q.?..|.$|
+00000050  c7 ef 41 af 62 15 03 01  00 16 dd dc 16 dc 16 cc  |..A.b...........|
+00000060  0d f3 2c 29 00 c0 4f 01  68 05 92 a0 f7 ad e2 63  |..,)..O.h......c|
diff --git a/src/crypto/tls/testdata/Server-TLSv11-RSA-RC4 b/src/crypto/tls/testdata/Server-TLSv11-RSA-RC4
index 9237db0..dc5e765 100644
--- a/src/crypto/tls/testdata/Server-TLSv11-RSA-RC4
+++ b/src/crypto/tls/testdata/Server-TLSv11-RSA-RC4
@@ -1,76 +1,71 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 36 01 00 00  32 03 02 52 cc 57 59 bd  |....6...2..R.WY.|
-00000010  cd 9d 1e 17 38 43 a5 e3  e7 30 e4 2b 2a ef f7 5b  |....8C...0.+*..[|
-00000020  81 91 0c 0b 52 f8 2d 2c  61 d3 13 00 00 04 00 05  |....R.-,a.......|
+00000000  16 03 01 00 36 01 00 00  32 03 02 ff e1 a1 04 0b  |....6...2.......|
+00000010  c2 dc fb 7d 07 61 44 9b  00 67 fe 38 73 f5 fc 4e  |...}.aD..g.8s..N|
+00000020  35 94 0a d5 c1 d0 e7 54  dc 44 1f 00 00 04 00 05  |5......T.D......|
 00000030  00 ff 01 00 00 05 00 0f  00 01 01                 |...........|
 >>> Flow 2 (server to client)
 00000000  16 03 02 00 31 02 00 00  2d 03 02 00 00 00 00 00  |....1...-.......|
 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 05 00 00  |................|
-00000030  05 ff 01 00 01 00 16 03  02 02 be 0b 00 02 ba 00  |................|
-00000040  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
-00000050  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
-00000060  09 2a 86 48 86 f7 0d 01  01 05 05 00 30 45 31 0b  |.*.H........0E1.|
-00000070  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
-00000080  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
-00000090  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
-000000a0  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
-000000b0  4c 74 64 30 1e 17 0d 31  30 30 34 32 34 30 39 30  |Ltd0...100424090|
-000000c0  39 33 38 5a 17 0d 31 31  30 34 32 34 30 39 30 39  |938Z..1104240909|
-000000d0  33 38 5a 30 45 31 0b 30  09 06 03 55 04 06 13 02  |38Z0E1.0...U....|
-000000e0  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
-000000f0  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
-00000100  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
-00000110  74 73 20 50 74 79 20 4c  74 64 30 81 9f 30 0d 06  |ts Pty Ltd0..0..|
-00000120  09 2a 86 48 86 f7 0d 01  01 01 05 00 03 81 8d 00  |.*.H............|
-00000130  30 81 89 02 81 81 00 bb  79 d6 f5 17 b5 e5 bf 46  |0.......y......F|
-00000140  10 d0 dc 69 be e6 2b 07  43 5a d0 03 2d 8a 7a 43  |...i..+.CZ..-.zC|
-00000150  85 b7 14 52 e7 a5 65 4c  2c 78 b8 23 8c b5 b4 82  |...R..eL,x.#....|
-00000160  e5 de 1f 95 3b 7e 62 a5  2c a5 33 d6 fe 12 5c 7a  |....;~b.,.3...\z|
-00000170  56 fc f5 06 bf fa 58 7b  26 3f b5 cd 04 d3 d0 c9  |V.....X{&?......|
-00000180  21 96 4a c7 f4 54 9f 5a  bf ef 42 71 00 fe 18 99  |!.J..T.Z..Bq....|
-00000190  07 7f 7e 88 7d 7d f1 04  39 c4 a2 2e db 51 c9 7c  |..~.}}..9....Q.||
-000001a0  e3 c0 4c 3b 32 66 01 cf  af b1 1d b8 71 9a 1d db  |..L;2f......q...|
-000001b0  db 89 6b ae da 2d 79 02  03 01 00 01 a3 81 a7 30  |..k..-y........0|
-000001c0  81 a4 30 1d 06 03 55 1d  0e 04 16 04 14 b1 ad e2  |..0...U.........|
-000001d0  85 5a cf cb 28 db 69 ce  23 69 de d3 26 8e 18 88  |.Z..(.i.#i..&...|
-000001e0  39 30 75 06 03 55 1d 23  04 6e 30 6c 80 14 b1 ad  |90u..U.#.n0l....|
-000001f0  e2 85 5a cf cb 28 db 69  ce 23 69 de d3 26 8e 18  |..Z..(.i.#i..&..|
-00000200  88 39 a1 49 a4 47 30 45  31 0b 30 09 06 03 55 04  |.9.I.G0E1.0...U.|
-00000210  06 13 02 41 55 31 13 30  11 06 03 55 04 08 13 0a  |...AU1.0...U....|
-00000220  53 6f 6d 65 2d 53 74 61  74 65 31 21 30 1f 06 03  |Some-State1!0...|
-00000230  55 04 0a 13 18 49 6e 74  65 72 6e 65 74 20 57 69  |U....Internet Wi|
-00000240  64 67 69 74 73 20 50 74  79 20 4c 74 64 82 09 00  |dgits Pty Ltd...|
-00000250  85 b0 bb a4 8a 7f b8 ca  30 0c 06 03 55 1d 13 04  |........0...U...|
-00000260  05 30 03 01 01 ff 30 0d  06 09 2a 86 48 86 f7 0d  |.0....0...*.H...|
-00000270  01 01 05 05 00 03 81 81  00 08 6c 45 24 c7 6b b1  |..........lE$.k.|
-00000280  59 ab 0c 52 cc f2 b0 14  d7 87 9d 7a 64 75 b5 5a  |Y..R.......zdu.Z|
-00000290  95 66 e4 c5 2b 8e ae 12  66 1f eb 4f 38 b3 6e 60  |.f..+...f..O8.n`|
-000002a0  d3 92 fd f7 41 08 b5 25  13 b1 18 7a 24 fb 30 1d  |....A..%...z$.0.|
-000002b0  ba ed 98 b9 17 ec e7 d7  31 59 db 95 d3 1d 78 ea  |........1Y....x.|
-000002c0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
-000002d0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
-000002e0  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
-000002f0  6e 38 50 29 6c 90 a7 bd  d9 16 03 02 00 04 0e 00  |n8P)l...........|
-00000300  00 00                                             |..|
+00000030  05 ff 01 00 01 00 16 03  02 02 71 0b 00 02 6d 00  |..........q...m.|
+00000040  02 6a 00 02 67 30 82 02  63 30 82 01 cc a0 03 02  |.j..g0..c0......|
+00000050  01 02 02 09 00 a2 73 00  0c 81 00 cb f3 30 0d 06  |......s......0..|
+00000060  09 2a 86 48 86 f7 0d 01  01 0b 05 00 30 2b 31 17  |.*.H........0+1.|
+00000070  30 15 06 03 55 04 0a 13  0e 47 6f 6f 67 6c 65 20  |0...U....Google |
+00000080  54 45 53 54 49 4e 47 31  10 30 0e 06 03 55 04 03  |TESTING1.0...U..|
+00000090  13 07 47 6f 20 52 6f 6f  74 30 1e 17 0d 31 35 30  |..Go Root0...150|
+000000a0  31 30 31 30 30 30 30 30  30 5a 17 0d 32 35 30 31  |101000000Z..2501|
+000000b0  30 31 30 30 30 30 30 30  5a 30 26 31 17 30 15 06  |01000000Z0&1.0..|
+000000c0  03 55 04 0a 13 0e 47 6f  6f 67 6c 65 20 54 45 53  |.U....Google TES|
+000000d0  54 49 4e 47 31 0b 30 09  06 03 55 04 03 13 02 47  |TING1.0...U....G|
+000000e0  6f 30 81 9f 30 0d 06 09  2a 86 48 86 f7 0d 01 01  |o0..0...*.H.....|
+000000f0  01 05 00 03 81 8d 00 30  81 89 02 81 81 00 af 87  |.......0........|
+00000100  88 f6 20 1b 95 65 6c 14  ab 44 05 af 3b 45 14 e3  |.. ..el..D..;E..|
+00000110  b7 6d fd 00 63 4d 95 7f  fe 6a 62 35 86 c0 4a f9  |.m..cM...jb5..J.|
+00000120  18 7c f6 aa 25 5e 7a 64  31 66 00 ba f4 8e 92 af  |.|..%^zd1f......|
+00000130  c7 6b d8 76 d4 f3 5f 41  cb 6e 56 15 97 1b 97 c1  |.k.v.._A.nV.....|
+00000140  3c 12 39 21 66 3d 2b 16  d1 bc db 1c c0 a7 da b7  |<.9!f=+.........|
+00000150  ca ad ba da cb d5 21 50  ec de 8d ab d1 6b 81 4b  |......!P.....k.K|
+00000160  89 02 f3 c4 be c1 6c 89  b1 44 84 bd 21 d1 04 7d  |......l..D..!..}|
+00000170  9d 16 4d f9 82 15 f6 ef  fa d6 09 47 f2 fb 02 03  |..M........G....|
+00000180  01 00 01 a3 81 93 30 81  90 30 0e 06 03 55 1d 0f  |......0..0...U..|
+00000190  01 01 ff 04 04 03 02 05  a0 30 1d 06 03 55 1d 25  |.........0...U.%|
+000001a0  04 16 30 14 06 08 2b 06  01 05 05 07 03 01 06 08  |..0...+.........|
+000001b0  2b 06 01 05 05 07 03 02  30 0c 06 03 55 1d 13 01  |+.......0...U...|
+000001c0  01 ff 04 02 30 00 30 19  06 03 55 1d 0e 04 12 04  |....0.0...U.....|
+000001d0  10 12 50 8d 89 6f 1b d1  dc 54 4d 6e cb 69 5e 06  |..P..o...TMn.i^.|
+000001e0  f4 30 1b 06 03 55 1d 23  04 14 30 12 80 10 bf 3d  |.0...U.#..0....=|
+000001f0  b6 a9 66 f2 b8 40 cf ea  b4 03 78 48 1a 41 30 19  |..f.. at ....xH.A0.|
+00000200  06 03 55 1d 11 04 12 30  10 82 0e 65 78 61 6d 70  |..U....0...examp|
+00000210  6c 65 2e 67 6f 6c 61 6e  67 30 0d 06 09 2a 86 48  |le.golang0...*.H|
+00000220  86 f7 0d 01 01 0b 05 00  03 81 81 00 92 7c af 91  |.............|..|
+00000230  55 12 18 96 59 31 a6 48  40 d5 2d d5 ee bb 02 a0  |U...Y1.H at .-.....|
+00000240  f5 c2 1e 7c 9b b3 30 7d  3c dc 76 da 4f 3d c0 fa  |...|..0}<.v.O=..|
+00000250  ae 2d 33 24 6b 03 7b 1b  67 59 11 21 b5 11 bc 77  |.-3$k.{.gY.!...w|
+00000260  b9 d9 e0 6e a8 2d 2e 35  fa 64 5f 22 3e 63 10 6b  |...n.-.5.d_">c.k|
+00000270  be ff 14 86 6d 0d f0 15  31 a8 14 38 1e 3b 84 87  |....m...1..8.;..|
+00000280  2c cb 98 ed 51 76 b9 b1  4f dd db 9b 84 04 86 40  |,...Qv..O......@|
+00000290  fa 51 dd ba b4 8d eb e3  46 de 46 b9 4f 86 c7 f9  |.Q......F.F.O...|
+000002a0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 02 00  |..A4......9.....|
+000002b0  04 0e 00 00 00                                    |.....|
 >>> Flow 3 (client to server)
-00000000  16 03 02 00 86 10 00 00  82 00 80 71 2b 19 25 86  |...........q+.%.|
-00000010  a0 ff ba d5 1c a6 0c 8b  6b 0a b8 e9 42 93 2f 55  |........k...B./U|
-00000020  a8 ee 62 fa ed bc 6d e2  9d e3 76 a6 73 d7 99 58  |..b...m...v.s..X|
-00000030  cc 0b 14 42 96 7c b6 c7  8f 21 16 cf 71 9b 2b b9  |...B.|...!..q.+.|
-00000040  e0 34 57 76 22 d5 87 8a  ce 1f ea 26 6e 1e e6 ca  |.4Wv"......&n...|
-00000050  55 3b 20 cd cf 42 26 b1  51 3e 8c 1d a2 ae c4 63  |U; ..B&.Q>.....c|
-00000060  f5 ce 27 3c 1e c3 e0 e3  b1 16 c1 8a 62 bd 21 7f  |..'<........b.!.|
-00000070  38 b5 b7 3a 3c bb 03 37  e1 a5 ff f1 29 e2 21 0a  |8..:<..7....).!.|
-00000080  8c 20 02 e0 c0 82 97 9d  18 6d f8 14 03 02 00 01  |. .......m......|
-00000090  01 16 03 02 00 24 bc 19  16 6e fd 0b db 9e d5 1d  |.....$...n......|
-000000a0  65 b6 57 1c 58 b5 6a ac  f7 4f f0 cd a1 a9 0c c0  |e.W.X.j..O......|
-000000b0  df e6 eb d5 00 f7 fd 43  bb 27                    |.......C.'|
+00000000  16 03 02 00 86 10 00 00  82 00 80 4c e0 4d 6a 19  |...........L.Mj.|
+00000010  a2 72 2a 3d 41 14 a7 b3  0a 25 11 bf c9 9f cf 8c  |.r*=A....%......|
+00000020  3c 0b 01 49 aa f1 59 4b  60 ac e5 72 9b ec 20 41  |<..I..YK`..r.. A|
+00000030  2f 7e ef bf e0 fe 13 c0  1d fd 51 c5 08 c6 9a 9e  |/~........Q.....|
+00000040  74 88 c7 e3 36 99 73 fd  00 2d a2 6a bd 25 f2 d7  |t...6.s..-.j.%..|
+00000050  24 fd fd ab 0c e0 18 38  ba 7b f0 c9 c0 58 a6 d0  |$......8.{...X..|
+00000060  4e e2 59 70 aa f4 52 34  12 a0 ec a4 53 1e 8b ee  |N.Yp..R4....S...|
+00000070  3e bf a4 87 da 02 4c 95  bd 10 af e8 88 c9 ce 87  |>.....L.........|
+00000080  3c 9e 91 70 91 a0 85 18  84 e4 e0 14 03 02 00 01  |<..p............|
+00000090  01 16 03 02 00 24 c5 c0  27 71 49 ad ed 37 e6 5d  |.....$..'qI..7.]|
+000000a0  1b 78 3e 74 15 b7 61 e5  f3 af 1e d0 a2 85 b3 13  |.x>t..a.........|
+000000b0  6e 5e 9a c7 3d 47 32 4d  1b 8d                    |n^..=G2M..|
 >>> Flow 4 (server to client)
-00000000  14 03 02 00 01 01 16 03  02 00 24 cf 4f e4 27 b0  |..........$.O.'.|
-00000010  3d 17 34 b1 3c 37 6e c5  2b 3d 4a c3 46 50 44 b4  |=.4.<7n.+=J.FPD.|
-00000020  de 77 18 10 4f 60 b3 4e  dc 06 fd 25 ec 05 15 17  |.w..O`.N...%....|
-00000030  03 02 00 21 a5 c9 32 f2  21 fb 94 7e 0d 15 65 fd  |...!..2.!..~..e.|
-00000040  3e fe e4 c1 a5 e9 88 72  b2 f1 26 39 a6 48 59 97  |>......r..&9.HY.|
-00000050  65 e3 f0 cb 46 15 03 02  00 16 4b 02 ec cd ca 30  |e...F.....K....0|
-00000060  42 cf 3d a0 4a fa 8e 79  bb ed b0 59 40 9b 2c 1a  |B.=.J..y...Y at .,.|
+00000000  14 03 02 00 01 01 16 03  02 00 24 31 22 76 4d 43  |..........$1"vMC|
+00000010  7a 8a 58 2c 7d 1c 41 39  bf 08 7e 82 17 55 52 b3  |z.X,}.A9..~..UR.|
+00000020  81 bd 7a f8 3c bf 9c 2b  f0 9b 3f 65 f5 42 15 17  |..z.<..+..?e.B..|
+00000030  03 02 00 21 b1 cc e5 56  16 70 58 0b 91 3c 8c 46  |...!...V.pX..<.F|
+00000040  0e 3b b6 fe 32 5d 2e b0  8c 6a 1c a0 82 c9 43 81  |.;..2]...j....C.|
+00000050  cf 07 25 47 c9 15 03 02  00 16 53 91 04 70 ba 03  |..%G......S..p..|
+00000060  53 69 57 86 3b 2f 8b 97  37 7c b8 85 46 b6 72 42  |SiW.;/..7|..F.rB|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-ALPN b/src/crypto/tls/testdata/Server-TLSv12-ALPN
index 106244d..cbfeb42 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-ALPN
+++ b/src/crypto/tls/testdata/Server-TLSv12-ALPN
@@ -1,122 +1,109 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 01 8a 01 00 01  86 03 03 34 54 69 f3 d7  |...........4Ti..|
-00000010  20 9d 1d 74 db 72 e9 2f  51 7c c2 82 0a 9b cb 6d  | ..t.r./Q|.....m|
-00000020  90 b4 8e a2 1f 2f c7 66  74 8f 33 00 00 d6 c0 30  |...../.ft.3....0|
-00000030  c0 2c c0 28 c0 24 c0 14  c0 0a c0 22 c0 21 c0 20  |.,.(.$.....".!. |
-00000040  00 a5 00 a3 00 a1 00 9f  00 6b 00 6a 00 69 00 68  |.........k.j.i.h|
-00000050  00 39 00 38 00 37 00 36  00 88 00 87 00 86 00 85  |.9.8.7.6........|
-00000060  c0 32 c0 2e c0 2a c0 26  c0 0f c0 05 00 9d 00 3d  |.2...*.&.......=|
-00000070  00 35 00 84 c0 2f c0 2b  c0 27 c0 23 c0 13 c0 09  |.5.../.+.'.#....|
-00000080  c0 1f c0 1e c0 1d 00 a4  00 a2 00 a0 00 9e 00 67  |...............g|
-00000090  00 40 00 3f 00 3e 00 33  00 32 00 31 00 30 00 9a  |. at .?.>.3.2.1.0..|
-000000a0  00 99 00 98 00 97 00 45  00 44 00 43 00 42 c0 31  |.......E.D.C.B.1|
-000000b0  c0 2d c0 29 c0 25 c0 0e  c0 04 00 9c 00 3c 00 2f  |.-.).%.......<./|
-000000c0  00 96 00 41 00 07 c0 11  c0 07 c0 0c c0 02 00 05  |...A............|
-000000d0  00 04 c0 12 c0 08 c0 1c  c0 1b c0 1a 00 16 00 13  |................|
-000000e0  00 10 00 0d c0 0d c0 03  00 0a 00 15 00 12 00 0f  |................|
-000000f0  00 0c 00 09 00 14 00 11  00 0e 00 0b 00 08 00 06  |................|
-00000100  00 03 00 ff 01 00 00 87  00 0b 00 04 03 00 01 02  |................|
-00000110  00 0a 00 3a 00 38 00 0e  00 0d 00 19 00 1c 00 0b  |...:.8..........|
-00000120  00 0c 00 1b 00 18 00 09  00 0a 00 1a 00 16 00 17  |................|
-00000130  00 08 00 06 00 07 00 14  00 15 00 04 00 05 00 12  |................|
-00000140  00 13 00 01 00 02 00 03  00 0f 00 10 00 11 00 23  |...............#|
-00000150  00 00 00 0d 00 20 00 1e  06 01 06 02 06 03 05 01  |..... ..........|
-00000160  05 02 05 03 04 01 04 02  04 03 03 01 03 02 03 03  |................|
-00000170  02 01 02 02 02 03 00 0f  00 01 01 00 10 00 10 00  |................|
-00000180  0e 06 70 72 6f 74 6f 32  06 70 72 6f 74 6f 31     |..proto2.proto1|
+00000000  16 03 01 01 4c 01 00 01  48 03 03 44 3b 24 ee 2f  |....L...H..D;$./|
+00000010  63 3d ca bd 3e c5 bf a2  24 f1 59 c3 54 dc f0 43  |c=..>...$.Y.T..C|
+00000020  15 c4 51 f2 29 ea 1b ce  2c fe af 00 00 b6 c0 30  |..Q.)...,......0|
+00000030  c0 2c c0 28 c0 24 c0 14  c0 0a 00 a5 00 a3 00 a1  |.,.(.$..........|
+00000040  00 9f 00 6b 00 6a 00 69  00 68 00 39 00 38 00 37  |...k.j.i.h.9.8.7|
+00000050  00 36 00 88 00 87 00 86  00 85 c0 32 c0 2e c0 2a  |.6.........2...*|
+00000060  c0 26 c0 0f c0 05 00 9d  00 3d 00 35 00 84 c0 2f  |.&.......=.5.../|
+00000070  c0 2b c0 27 c0 23 c0 13  c0 09 00 a4 00 a2 00 a0  |.+.'.#..........|
+00000080  00 9e 00 67 00 40 00 3f  00 3e 00 33 00 32 00 31  |...g. at .?.>.3.2.1|
+00000090  00 30 00 9a 00 99 00 98  00 97 00 45 00 44 00 43  |.0.........E.D.C|
+000000a0  00 42 c0 31 c0 2d c0 29  c0 25 c0 0e c0 04 00 9c  |.B.1.-.).%......|
+000000b0  00 3c 00 2f 00 96 00 41  00 07 c0 11 c0 07 c0 0c  |.<./...A........|
+000000c0  c0 02 00 05 00 04 c0 12  c0 08 00 16 00 13 00 10  |................|
+000000d0  00 0d c0 0d c0 03 00 0a  00 15 00 12 00 0f 00 0c  |................|
+000000e0  00 09 00 ff 01 00 00 69  00 0b 00 04 03 00 01 02  |.......i........|
+000000f0  00 0a 00 1c 00 1a 00 17  00 19 00 1c 00 1b 00 18  |................|
+00000100  00 1a 00 16 00 0e 00 0d  00 0b 00 0c 00 09 00 0a  |................|
+00000110  00 23 00 00 00 0d 00 20  00 1e 06 01 06 02 06 03  |.#..... ........|
+00000120  05 01 05 02 05 03 04 01  04 02 04 03 03 01 03 02  |................|
+00000130  03 03 02 01 02 02 02 03  00 0f 00 01 01 00 10 00  |................|
+00000140  10 00 0e 06 70 72 6f 74  6f 32 06 70 72 6f 74 6f  |....proto2.proto|
+00000150  31                                                |1|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 42 02 00 00  3e 03 03 00 00 00 00 00  |....B...>.......|
 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 c0 14 00 00  |................|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 c0 30 00 00  |.............0..|
 00000030  16 00 23 00 00 ff 01 00  01 00 00 10 00 09 00 07  |..#.............|
-00000040  06 70 72 6f 74 6f 31 16  03 03 02 be 0b 00 02 ba  |.proto1.........|
-00000050  00 02 b7 00 02 b4 30 82  02 b0 30 82 02 19 a0 03  |......0...0.....|
-00000060  02 01 02 02 09 00 85 b0  bb a4 8a 7f b8 ca 30 0d  |..............0.|
-00000070  06 09 2a 86 48 86 f7 0d  01 01 05 05 00 30 45 31  |..*.H........0E1|
-00000080  0b 30 09 06 03 55 04 06  13 02 41 55 31 13 30 11  |.0...U....AU1.0.|
-00000090  06 03 55 04 08 13 0a 53  6f 6d 65 2d 53 74 61 74  |..U....Some-Stat|
-000000a0  65 31 21 30 1f 06 03 55  04 0a 13 18 49 6e 74 65  |e1!0...U....Inte|
-000000b0  72 6e 65 74 20 57 69 64  67 69 74 73 20 50 74 79  |rnet Widgits Pty|
-000000c0  20 4c 74 64 30 1e 17 0d  31 30 30 34 32 34 30 39  | Ltd0...10042409|
-000000d0  30 39 33 38 5a 17 0d 31  31 30 34 32 34 30 39 30  |0938Z..110424090|
-000000e0  39 33 38 5a 30 45 31 0b  30 09 06 03 55 04 06 13  |938Z0E1.0...U...|
-000000f0  02 41 55 31 13 30 11 06  03 55 04 08 13 0a 53 6f  |.AU1.0...U....So|
-00000100  6d 65 2d 53 74 61 74 65  31 21 30 1f 06 03 55 04  |me-State1!0...U.|
-00000110  0a 13 18 49 6e 74 65 72  6e 65 74 20 57 69 64 67  |...Internet Widg|
-00000120  69 74 73 20 50 74 79 20  4c 74 64 30 81 9f 30 0d  |its Pty Ltd0..0.|
-00000130  06 09 2a 86 48 86 f7 0d  01 01 01 05 00 03 81 8d  |..*.H...........|
-00000140  00 30 81 89 02 81 81 00  bb 79 d6 f5 17 b5 e5 bf  |.0.......y......|
-00000150  46 10 d0 dc 69 be e6 2b  07 43 5a d0 03 2d 8a 7a  |F...i..+.CZ..-.z|
-00000160  43 85 b7 14 52 e7 a5 65  4c 2c 78 b8 23 8c b5 b4  |C...R..eL,x.#...|
-00000170  82 e5 de 1f 95 3b 7e 62  a5 2c a5 33 d6 fe 12 5c  |.....;~b.,.3...\|
-00000180  7a 56 fc f5 06 bf fa 58  7b 26 3f b5 cd 04 d3 d0  |zV.....X{&?.....|
-00000190  c9 21 96 4a c7 f4 54 9f  5a bf ef 42 71 00 fe 18  |.!.J..T.Z..Bq...|
-000001a0  99 07 7f 7e 88 7d 7d f1  04 39 c4 a2 2e db 51 c9  |...~.}}..9....Q.|
-000001b0  7c e3 c0 4c 3b 32 66 01  cf af b1 1d b8 71 9a 1d  ||..L;2f......q..|
-000001c0  db db 89 6b ae da 2d 79  02 03 01 00 01 a3 81 a7  |...k..-y........|
-000001d0  30 81 a4 30 1d 06 03 55  1d 0e 04 16 04 14 b1 ad  |0..0...U........|
-000001e0  e2 85 5a cf cb 28 db 69  ce 23 69 de d3 26 8e 18  |..Z..(.i.#i..&..|
-000001f0  88 39 30 75 06 03 55 1d  23 04 6e 30 6c 80 14 b1  |.90u..U.#.n0l...|
-00000200  ad e2 85 5a cf cb 28 db  69 ce 23 69 de d3 26 8e  |...Z..(.i.#i..&.|
-00000210  18 88 39 a1 49 a4 47 30  45 31 0b 30 09 06 03 55  |..9.I.G0E1.0...U|
-00000220  04 06 13 02 41 55 31 13  30 11 06 03 55 04 08 13  |....AU1.0...U...|
-00000230  0a 53 6f 6d 65 2d 53 74  61 74 65 31 21 30 1f 06  |.Some-State1!0..|
-00000240  03 55 04 0a 13 18 49 6e  74 65 72 6e 65 74 20 57  |.U....Internet W|
-00000250  69 64 67 69 74 73 20 50  74 79 20 4c 74 64 82 09  |idgits Pty Ltd..|
-00000260  00 85 b0 bb a4 8a 7f b8  ca 30 0c 06 03 55 1d 13  |.........0...U..|
-00000270  04 05 30 03 01 01 ff 30  0d 06 09 2a 86 48 86 f7  |..0....0...*.H..|
-00000280  0d 01 01 05 05 00 03 81  81 00 08 6c 45 24 c7 6b  |...........lE$.k|
-00000290  b1 59 ab 0c 52 cc f2 b0  14 d7 87 9d 7a 64 75 b5  |.Y..R.......zdu.|
-000002a0  5a 95 66 e4 c5 2b 8e ae  12 66 1f eb 4f 38 b3 6e  |Z.f..+...f..O8.n|
-000002b0  60 d3 92 fd f7 41 08 b5  25 13 b1 18 7a 24 fb 30  |`....A..%...z$.0|
-000002c0  1d ba ed 98 b9 17 ec e7  d7 31 59 db 95 d3 1d 78  |.........1Y....x|
-000002d0  ea 50 56 5c d5 82 5a 2d  5a 5f 33 c4 b6 d8 c9 75  |.PV\..Z-Z_3....u|
-000002e0  90 96 8c 0f 52 98 b5 cd  98 1f 89 20 5f f2 a0 1c  |....R...... _...|
-000002f0  a3 1b 96 94 dd a9 fd 57  e9 70 e8 26 6d 71 99 9b  |.......W.p.&mq..|
-00000300  26 6e 38 50 29 6c 90 a7  bd d9 16 03 03 00 cd 0c  |&n8P)l..........|
-00000310  00 00 c9 03 00 17 41 04  1e 18 37 ef 0d 19 51 88  |......A...7...Q.|
-00000320  35 75 71 b5 e5 54 5b 12  2e 8f 09 67 fd a7 24 20  |5uq..T[....g..$ |
-00000330  3e b2 56 1c ce 97 28 5e  f8 2b 2d 4f 9e f1 07 9f  |>.V...(^.+-O....|
-00000340  6c 4b 5b 83 56 e2 32 42  e9 58 b6 d7 49 a6 b5 68  |lK[.V.2B.X..I..h|
-00000350  1a 41 03 56 6b dc 5a 89  04 01 00 80 2d a0 6e 47  |.A.Vk.Z.....-.nG|
-00000360  93 a2 19 17 32 f5 42 58  93 f6 4f d4 e9 4d a4 0f  |....2.BX..O..M..|
-00000370  fe 4e d7 2c 62 b6 fb 83  37 a3 09 60 4b 69 e2 4c  |.N.,b...7..`Ki.L|
-00000380  fc b8 4c d1 a6 9a 89 a0  c5 76 f5 62 b7 e8 eb c2  |..L......v.b....|
-00000390  fa 0f 0e 61 86 bc 70 da  13 72 8d 87 94 16 9a 8d  |...a..p..r......|
-000003a0  5f 80 82 92 77 37 4f 9e  55 5d dc 35 42 a3 75 5c  |_...w7O.U].5B.u\|
-000003b0  ec a4 58 78 66 97 97 da  49 67 2e b6 7e 11 de fb  |..Xxf...Ig..~...|
-000003c0  e3 8f e8 bf 1d 91 1e 91  20 1b 2a df c6 58 e4 82  |........ .*..X..|
-000003d0  ce 37 dd 6f a5 ac 51 3d  65 db 3f f5 16 03 03 00  |.7.o..Q=e.?.....|
-000003e0  04 0e 00 00 00                                    |.....|
+00000040  06 70 72 6f 74 6f 31 16  03 03 02 71 0b 00 02 6d  |.proto1....q...m|
+00000050  00 02 6a 00 02 67 30 82  02 63 30 82 01 cc a0 03  |..j..g0..c0.....|
+00000060  02 01 02 02 09 00 a2 73  00 0c 81 00 cb f3 30 0d  |.......s......0.|
+00000070  06 09 2a 86 48 86 f7 0d  01 01 0b 05 00 30 2b 31  |..*.H........0+1|
+00000080  17 30 15 06 03 55 04 0a  13 0e 47 6f 6f 67 6c 65  |.0...U....Google|
+00000090  20 54 45 53 54 49 4e 47  31 10 30 0e 06 03 55 04  | TESTING1.0...U.|
+000000a0  03 13 07 47 6f 20 52 6f  6f 74 30 1e 17 0d 31 35  |...Go Root0...15|
+000000b0  30 31 30 31 30 30 30 30  30 30 5a 17 0d 32 35 30  |0101000000Z..250|
+000000c0  31 30 31 30 30 30 30 30  30 5a 30 26 31 17 30 15  |101000000Z0&1.0.|
+000000d0  06 03 55 04 0a 13 0e 47  6f 6f 67 6c 65 20 54 45  |..U....Google TE|
+000000e0  53 54 49 4e 47 31 0b 30  09 06 03 55 04 03 13 02  |STING1.0...U....|
+000000f0  47 6f 30 81 9f 30 0d 06  09 2a 86 48 86 f7 0d 01  |Go0..0...*.H....|
+00000100  01 01 05 00 03 81 8d 00  30 81 89 02 81 81 00 af  |........0.......|
+00000110  87 88 f6 20 1b 95 65 6c  14 ab 44 05 af 3b 45 14  |... ..el..D..;E.|
+00000120  e3 b7 6d fd 00 63 4d 95  7f fe 6a 62 35 86 c0 4a  |..m..cM...jb5..J|
+00000130  f9 18 7c f6 aa 25 5e 7a  64 31 66 00 ba f4 8e 92  |..|..%^zd1f.....|
+00000140  af c7 6b d8 76 d4 f3 5f  41 cb 6e 56 15 97 1b 97  |..k.v.._A.nV....|
+00000150  c1 3c 12 39 21 66 3d 2b  16 d1 bc db 1c c0 a7 da  |.<.9!f=+........|
+00000160  b7 ca ad ba da cb d5 21  50 ec de 8d ab d1 6b 81  |.......!P.....k.|
+00000170  4b 89 02 f3 c4 be c1 6c  89 b1 44 84 bd 21 d1 04  |K......l..D..!..|
+00000180  7d 9d 16 4d f9 82 15 f6  ef fa d6 09 47 f2 fb 02  |}..M........G...|
+00000190  03 01 00 01 a3 81 93 30  81 90 30 0e 06 03 55 1d  |.......0..0...U.|
+000001a0  0f 01 01 ff 04 04 03 02  05 a0 30 1d 06 03 55 1d  |..........0...U.|
+000001b0  25 04 16 30 14 06 08 2b  06 01 05 05 07 03 01 06  |%..0...+........|
+000001c0  08 2b 06 01 05 05 07 03  02 30 0c 06 03 55 1d 13  |.+.......0...U..|
+000001d0  01 01 ff 04 02 30 00 30  19 06 03 55 1d 0e 04 12  |.....0.0...U....|
+000001e0  04 10 12 50 8d 89 6f 1b  d1 dc 54 4d 6e cb 69 5e  |...P..o...TMn.i^|
+000001f0  06 f4 30 1b 06 03 55 1d  23 04 14 30 12 80 10 bf  |..0...U.#..0....|
+00000200  3d b6 a9 66 f2 b8 40 cf  ea b4 03 78 48 1a 41 30  |=..f.. at ....xH.A0|
+00000210  19 06 03 55 1d 11 04 12  30 10 82 0e 65 78 61 6d  |...U....0...exam|
+00000220  70 6c 65 2e 67 6f 6c 61  6e 67 30 0d 06 09 2a 86  |ple.golang0...*.|
+00000230  48 86 f7 0d 01 01 0b 05  00 03 81 81 00 92 7c af  |H.............|.|
+00000240  91 55 12 18 96 59 31 a6  48 40 d5 2d d5 ee bb 02  |.U...Y1.H at .-....|
+00000250  a0 f5 c2 1e 7c 9b b3 30  7d 3c dc 76 da 4f 3d c0  |....|..0}<.v.O=.|
+00000260  fa ae 2d 33 24 6b 03 7b  1b 67 59 11 21 b5 11 bc  |..-3$k.{.gY.!...|
+00000270  77 b9 d9 e0 6e a8 2d 2e  35 fa 64 5f 22 3e 63 10  |w...n.-.5.d_">c.|
+00000280  6b be ff 14 86 6d 0d f0  15 31 a8 14 38 1e 3b 84  |k....m...1..8.;.|
+00000290  87 2c cb 98 ed 51 76 b9  b1 4f dd db 9b 84 04 86  |.,...Qv..O......|
+000002a0  40 fa 51 dd ba b4 8d eb  e3 46 de 46 b9 4f 86 c7  |@.Q......F.F.O..|
+000002b0  f9 a4 c2 41 34 ac cc f6  ea b0 ab 39 18 16 03 03  |...A4......9....|
+000002c0  00 cd 0c 00 00 c9 03 00  17 41 04 1e 18 37 ef 0d  |.........A...7..|
+000002d0  19 51 88 35 75 71 b5 e5  54 5b 12 2e 8f 09 67 fd  |.Q.5uq..T[....g.|
+000002e0  a7 24 20 3e b2 56 1c ce  97 28 5e f8 2b 2d 4f 9e  |.$ >.V...(^.+-O.|
+000002f0  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
+00000300  a6 b5 68 1a 41 03 56 6b  dc 5a 89 05 01 00 80 40  |..h.A.Vk.Z.....@|
+00000310  93 b2 1f 79 3d 56 c0 ae  94 87 c0 a7 28 ef 1d 15  |...y=V......(...|
+00000320  be 4b fb 66 e0 60 2c a3  57 ee 56 7d d6 89 b8 8e  |.K.f.`,.W.V}....|
+00000330  8f 0f 3f 1b c6 9f a4 1d  34 60 b6 9c e9 9b a9 27  |..?.....4`.....'|
+00000340  d0 45 7b 04 71 2d db 9c  67 1b d5 d4 fe 19 69 59  |.E{.q-..g.....iY|
+00000350  71 8a 35 75 33 a8 c9 f2  4d c4 8f 40 17 a7 25 53  |q.5u3...M.. at ..%S|
+00000360  57 c5 cd ee df a9 3b a3  61 ab e2 a2 ca de 5c 08  |W.....;.a.....\.|
+00000370  3d 5b a2 ef cd c8 bc 16  1f 1d 0f 83 9e b7 20 f5  |=[............ .|
+00000380  89 3f 09 ba 2e da 12 34  81 e5 2f 8d 3c 90 89 16  |.?.....4../.<...|
+00000390  03 03 00 04 0e 00 00 00                           |........|
 >>> Flow 3 (client to server)
-00000000  16 03 03 00 46 10 00 00  42 41 04 f3 fc ea d8 50  |....F...BA.....P|
-00000010  e6 15 b0 e7 11 c7 6d ee  09 ad 80 d5 54 eb 4f 62  |......m.....T.Ob|
-00000020  7d bb a7 2d 28 0c 66 33  42 09 cf 2b 58 f8 58 41  |}..-(.f3B..+X.XA|
-00000030  bd 46 51 0a f0 7d 8c 0c  98 9e 26 77 20 fd 5e c1  |.FQ..}....&w .^.|
-00000040  a9 b3 e5 c3 6c 05 97 e3  81 fd db 14 03 03 00 01  |....l...........|
-00000050  01 16 03 03 00 40 02 2a  28 41 e3 9c 5d 45 d4 45  |..... at .*(A..]E.E|
-00000060  51 8c 7a c0 ba b1 8e a4  84 2c f3 83 cd c4 55 5c  |Q.z......,....U\|
-00000070  d6 5c 6f 72 ab 89 7a c6  d7 9c 2a 54 f0 c4 20 ee  |.\or..z...*T.. .|
-00000080  37 74 9b b6 8c f7 e4 37  2c eb d4 9f 5c 5e 55 a0  |7t.....7,...\^U.|
-00000090  e2 5a fe 1e c8 67                                 |.Z...g|
+00000000  16 03 03 00 46 10 00 00  42 41 04 8b a2 de a6 1e  |....F...BA......|
+00000010  d9 22 3c 03 4a be 49 2f  40 e3 1e e0 b4 76 7f 78  |."<.J.I/@....v.x|
+00000020  96 22 8d 8d c9 45 3b d8  7a ce e3 16 3d 37 ec 80  |."...E;.z...=7..|
+00000030  aa 3f d5 19 de c1 2c 7b  7f eb 3c fc 5d c3 52 3b  |.?....,{..<.].R;|
+00000040  d4 22 25 1c c7 1f 39 c5  23 bd 73 14 03 03 00 01  |."%...9.#.s.....|
+00000050  01 16 03 03 00 28 c8 53  0a ad c2 f6 7e 18 08 a3  |.....(.S....~...|
+00000060  29 27 20 1c 6c 1d 6c d8  8f 05 31 de e6 ab 7f 22  |)' .l.l...1...."|
+00000070  93 6a fb ef b0 f8 43 a9  d3 4f 9d 04 b5 9a        |.j....C..O....|
 >>> Flow 4 (server to client)
-00000000  16 03 03 00 72 04 00 00  6e 00 00 00 00 00 68 00  |....r...n.....h.|
-00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 65  |...............e|
-00000020  ea 8b c0 ef ba 59 31 75  33 96 f1 f8 c9 e1 ef 30  |.....Y1u3......0|
-00000030  00 a3 a9 1d ab c8 4b 29  94 f2 c8 c8 8d 03 57 ab  |......K)......W.|
-00000040  56 df 0f 4e 0d 30 13 09  c9 e4 fa 51 4e b3 26 ad  |V..N.0.....QN.&.|
-00000050  43 9f ae 62 d5 59 23 05  9b 69 8f 5b a8 ba 39 f1  |C..b.Y#..i.[..9.|
-00000060  90 84 35 bf 8f 8d d5 39  93 98 ee b9 75 03 3f 91  |..5....9....u.?.|
-00000070  e8 56 0b cb 44 a6 7a 14  03 03 00 01 01 16 03 03  |.V..D.z.........|
-00000080  00 40 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |. at ..............|
-00000090  00 00 f9 a0 8e 23 34 f1  61 15 a8 4e ae c4 f3 2a  |.....#4.a..N...*|
-000000a0  a6 f8 ee 1b 65 c4 c0 ff  93 14 74 ed 82 ae 48 a8  |....e.....t...H.|
-000000b0  42 fb a9 24 5d dd fd 98  b8 65 73 03 88 99 e1 ed  |B..$]....es.....|
-000000c0  02 95 17 03 03 00 40 00  00 00 00 00 00 00 00 00  |...... at .........|
-000000d0  00 00 00 00 00 00 00 b9  b3 f5 41 84 3b 2a a9 c3  |..........A.;*..|
-000000e0  9c e3 d4 38 90 76 c1 8c  f0 4f 10 1b 04 b5 07 fe  |...8.v...O......|
-000000f0  79 3d 7b 77 a4 17 0f 4e  df 64 70 70 9e 34 8e b6  |y={w...N.dpp.4..|
-00000100  db b2 b6 fd 41 fe b3 15  03 03 00 30 00 00 00 00  |....A......0....|
-00000110  00 00 00 00 00 00 00 00  00 00 00 00 02 73 de fe  |.............s..|
-00000120  fa 4b 69 6d 30 69 79 96  7e 4f 2f 04 67 36 96 27  |.Kim0iy.~O/.g6.'|
-00000130  67 23 2b dc 7a c4 6c 34  ea fc 79 fd              |g#+.z.l4..y.|
+00000000  16 03 03 00 82 04 00 00  7e 00 00 00 00 00 78 50  |........~.....xP|
+00000010  46 ad c1 db a8 38 86 7b  2b bb fd d0 c3 42 3e 00  |F....8.{+....B>.|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 94  |................|
+00000030  6f ec 80 83 61 8e d9 64  ac a2 ee 3b 69 31 79 e1  |o...a..d...;i1y.|
+00000040  53 0a 92 1d aa 23 09 c2  49 02 2d 0d 1d c1 63 d6  |S....#..I.-...c.|
+00000050  21 56 c7 24 02 28 d5 f1  11 b0 e7 1b 4a 7c 55 af  |!V.$.(......J|U.|
+00000060  1b c8 32 4c 5b 33 94 b0  ed b0 2f 52 c4 52 81 ee  |..2L[3..../R.R..|
+00000070  60 6f 66 fb f5 db dd f9  1e 30 11 d4 ca 75 0e 2b  |`of......0...u.+|
+00000080  ff d0 e5 f2 68 a4 e7 14  03 03 00 01 01 16 03 03  |....h...........|
+00000090  00 28 00 00 00 00 00 00  00 00 67 3b 4a ba f3 27  |.(........g;J..'|
+000000a0  c8 45 94 68 36 5a 40 e1  dc 67 9b d4 45 58 e9 24  |.E.h6Z at ..g..EX.$|
+000000b0  31 85 3a f8 5d cb 84 8e  64 05 17 03 03 00 25 00  |1.:.]...d.....%.|
+000000c0  00 00 00 00 00 00 01 35  d9 ba 0a e2 3e fd a2 80  |.......5....>...|
+000000d0  10 0e 38 7b ad 85 85 48  6a 2a ab 2a 46 c3 59 96  |..8{...Hj*.*F.Y.|
+000000e0  fd 75 11 5d 15 03 03 00  1a 00 00 00 00 00 00 00  |.u.]............|
+000000f0  02 0b 4d a5 89 4d 86 47  14 60 27 f8 09 bc c9 4d  |..M..M.G.`'....M|
+00000100  00 31 cb                                          |.1.|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-ALPN-NoMatch b/src/crypto/tls/testdata/Server-TLSv12-ALPN-NoMatch
index db5881b..af75445 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-ALPN-NoMatch
+++ b/src/crypto/tls/testdata/Server-TLSv12-ALPN-NoMatch
@@ -1,121 +1,108 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 01 8a 01 00 01  86 03 03 0a a8 82 53 61  |..............Sa|
-00000010  68 e0 83 91 71 36 f9 c1  19 ff e8 09 fc 21 9f 03  |h...q6.......!..|
-00000020  31 f3 87 4a 04 8c 3d c2  6e 00 32 00 00 d6 c0 30  |1..J..=.n.2....0|
-00000030  c0 2c c0 28 c0 24 c0 14  c0 0a c0 22 c0 21 c0 20  |.,.(.$.....".!. |
-00000040  00 a5 00 a3 00 a1 00 9f  00 6b 00 6a 00 69 00 68  |.........k.j.i.h|
-00000050  00 39 00 38 00 37 00 36  00 88 00 87 00 86 00 85  |.9.8.7.6........|
-00000060  c0 32 c0 2e c0 2a c0 26  c0 0f c0 05 00 9d 00 3d  |.2...*.&.......=|
-00000070  00 35 00 84 c0 2f c0 2b  c0 27 c0 23 c0 13 c0 09  |.5.../.+.'.#....|
-00000080  c0 1f c0 1e c0 1d 00 a4  00 a2 00 a0 00 9e 00 67  |...............g|
-00000090  00 40 00 3f 00 3e 00 33  00 32 00 31 00 30 00 9a  |. at .?.>.3.2.1.0..|
-000000a0  00 99 00 98 00 97 00 45  00 44 00 43 00 42 c0 31  |.......E.D.C.B.1|
-000000b0  c0 2d c0 29 c0 25 c0 0e  c0 04 00 9c 00 3c 00 2f  |.-.).%.......<./|
-000000c0  00 96 00 41 00 07 c0 11  c0 07 c0 0c c0 02 00 05  |...A............|
-000000d0  00 04 c0 12 c0 08 c0 1c  c0 1b c0 1a 00 16 00 13  |................|
-000000e0  00 10 00 0d c0 0d c0 03  00 0a 00 15 00 12 00 0f  |................|
-000000f0  00 0c 00 09 00 14 00 11  00 0e 00 0b 00 08 00 06  |................|
-00000100  00 03 00 ff 01 00 00 87  00 0b 00 04 03 00 01 02  |................|
-00000110  00 0a 00 3a 00 38 00 0e  00 0d 00 19 00 1c 00 0b  |...:.8..........|
-00000120  00 0c 00 1b 00 18 00 09  00 0a 00 1a 00 16 00 17  |................|
-00000130  00 08 00 06 00 07 00 14  00 15 00 04 00 05 00 12  |................|
-00000140  00 13 00 01 00 02 00 03  00 0f 00 10 00 11 00 23  |...............#|
-00000150  00 00 00 0d 00 20 00 1e  06 01 06 02 06 03 05 01  |..... ..........|
-00000160  05 02 05 03 04 01 04 02  04 03 03 01 03 02 03 03  |................|
-00000170  02 01 02 02 02 03 00 0f  00 01 01 00 10 00 10 00  |................|
-00000180  0e 06 70 72 6f 74 6f 32  06 70 72 6f 74 6f 31     |..proto2.proto1|
+00000000  16 03 01 01 4c 01 00 01  48 03 03 1d 1a f7 e5 ad  |....L...H.......|
+00000010  a4 5c fd 61 b4 c2 25 33  c7 b9 fc fb 2b a5 4b fe  |.\.a..%3....+.K.|
+00000020  16 84 55 4b 9f 68 73 61  b8 92 4d 00 00 b6 c0 30  |..UK.hsa..M....0|
+00000030  c0 2c c0 28 c0 24 c0 14  c0 0a 00 a5 00 a3 00 a1  |.,.(.$..........|
+00000040  00 9f 00 6b 00 6a 00 69  00 68 00 39 00 38 00 37  |...k.j.i.h.9.8.7|
+00000050  00 36 00 88 00 87 00 86  00 85 c0 32 c0 2e c0 2a  |.6.........2...*|
+00000060  c0 26 c0 0f c0 05 00 9d  00 3d 00 35 00 84 c0 2f  |.&.......=.5.../|
+00000070  c0 2b c0 27 c0 23 c0 13  c0 09 00 a4 00 a2 00 a0  |.+.'.#..........|
+00000080  00 9e 00 67 00 40 00 3f  00 3e 00 33 00 32 00 31  |...g. at .?.>.3.2.1|
+00000090  00 30 00 9a 00 99 00 98  00 97 00 45 00 44 00 43  |.0.........E.D.C|
+000000a0  00 42 c0 31 c0 2d c0 29  c0 25 c0 0e c0 04 00 9c  |.B.1.-.).%......|
+000000b0  00 3c 00 2f 00 96 00 41  00 07 c0 11 c0 07 c0 0c  |.<./...A........|
+000000c0  c0 02 00 05 00 04 c0 12  c0 08 00 16 00 13 00 10  |................|
+000000d0  00 0d c0 0d c0 03 00 0a  00 15 00 12 00 0f 00 0c  |................|
+000000e0  00 09 00 ff 01 00 00 69  00 0b 00 04 03 00 01 02  |.......i........|
+000000f0  00 0a 00 1c 00 1a 00 17  00 19 00 1c 00 1b 00 18  |................|
+00000100  00 1a 00 16 00 0e 00 0d  00 0b 00 0c 00 09 00 0a  |................|
+00000110  00 23 00 00 00 0d 00 20  00 1e 06 01 06 02 06 03  |.#..... ........|
+00000120  05 01 05 02 05 03 04 01  04 02 04 03 03 01 03 02  |................|
+00000130  03 03 02 01 02 02 02 03  00 0f 00 01 01 00 10 00  |................|
+00000140  10 00 0e 06 70 72 6f 74  6f 32 06 70 72 6f 74 6f  |....proto2.proto|
+00000150  31                                                |1|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 35 02 00 00  31 03 03 00 00 00 00 00  |....5...1.......|
 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 c0 14 00 00  |................|
-00000030  09 00 23 00 00 ff 01 00  01 00 16 03 03 02 be 0b  |..#.............|
-00000040  00 02 ba 00 02 b7 00 02  b4 30 82 02 b0 30 82 02  |.........0...0..|
-00000050  19 a0 03 02 01 02 02 09  00 85 b0 bb a4 8a 7f b8  |................|
-00000060  ca 30 0d 06 09 2a 86 48  86 f7 0d 01 01 05 05 00  |.0...*.H........|
-00000070  30 45 31 0b 30 09 06 03  55 04 06 13 02 41 55 31  |0E1.0...U....AU1|
-00000080  13 30 11 06 03 55 04 08  13 0a 53 6f 6d 65 2d 53  |.0...U....Some-S|
-00000090  74 61 74 65 31 21 30 1f  06 03 55 04 0a 13 18 49  |tate1!0...U....I|
-000000a0  6e 74 65 72 6e 65 74 20  57 69 64 67 69 74 73 20  |nternet Widgits |
-000000b0  50 74 79 20 4c 74 64 30  1e 17 0d 31 30 30 34 32  |Pty Ltd0...10042|
-000000c0  34 30 39 30 39 33 38 5a  17 0d 31 31 30 34 32 34  |4090938Z..110424|
-000000d0  30 39 30 39 33 38 5a 30  45 31 0b 30 09 06 03 55  |090938Z0E1.0...U|
-000000e0  04 06 13 02 41 55 31 13  30 11 06 03 55 04 08 13  |....AU1.0...U...|
-000000f0  0a 53 6f 6d 65 2d 53 74  61 74 65 31 21 30 1f 06  |.Some-State1!0..|
-00000100  03 55 04 0a 13 18 49 6e  74 65 72 6e 65 74 20 57  |.U....Internet W|
-00000110  69 64 67 69 74 73 20 50  74 79 20 4c 74 64 30 81  |idgits Pty Ltd0.|
-00000120  9f 30 0d 06 09 2a 86 48  86 f7 0d 01 01 01 05 00  |.0...*.H........|
-00000130  03 81 8d 00 30 81 89 02  81 81 00 bb 79 d6 f5 17  |....0.......y...|
-00000140  b5 e5 bf 46 10 d0 dc 69  be e6 2b 07 43 5a d0 03  |...F...i..+.CZ..|
-00000150  2d 8a 7a 43 85 b7 14 52  e7 a5 65 4c 2c 78 b8 23  |-.zC...R..eL,x.#|
-00000160  8c b5 b4 82 e5 de 1f 95  3b 7e 62 a5 2c a5 33 d6  |........;~b.,.3.|
-00000170  fe 12 5c 7a 56 fc f5 06  bf fa 58 7b 26 3f b5 cd  |..\zV.....X{&?..|
-00000180  04 d3 d0 c9 21 96 4a c7  f4 54 9f 5a bf ef 42 71  |....!.J..T.Z..Bq|
-00000190  00 fe 18 99 07 7f 7e 88  7d 7d f1 04 39 c4 a2 2e  |......~.}}..9...|
-000001a0  db 51 c9 7c e3 c0 4c 3b  32 66 01 cf af b1 1d b8  |.Q.|..L;2f......|
-000001b0  71 9a 1d db db 89 6b ae  da 2d 79 02 03 01 00 01  |q.....k..-y.....|
-000001c0  a3 81 a7 30 81 a4 30 1d  06 03 55 1d 0e 04 16 04  |...0..0...U.....|
-000001d0  14 b1 ad e2 85 5a cf cb  28 db 69 ce 23 69 de d3  |.....Z..(.i.#i..|
-000001e0  26 8e 18 88 39 30 75 06  03 55 1d 23 04 6e 30 6c  |&...90u..U.#.n0l|
-000001f0  80 14 b1 ad e2 85 5a cf  cb 28 db 69 ce 23 69 de  |......Z..(.i.#i.|
-00000200  d3 26 8e 18 88 39 a1 49  a4 47 30 45 31 0b 30 09  |.&...9.I.G0E1.0.|
-00000210  06 03 55 04 06 13 02 41  55 31 13 30 11 06 03 55  |..U....AU1.0...U|
-00000220  04 08 13 0a 53 6f 6d 65  2d 53 74 61 74 65 31 21  |....Some-State1!|
-00000230  30 1f 06 03 55 04 0a 13  18 49 6e 74 65 72 6e 65  |0...U....Interne|
-00000240  74 20 57 69 64 67 69 74  73 20 50 74 79 20 4c 74  |t Widgits Pty Lt|
-00000250  64 82 09 00 85 b0 bb a4  8a 7f b8 ca 30 0c 06 03  |d...........0...|
-00000260  55 1d 13 04 05 30 03 01  01 ff 30 0d 06 09 2a 86  |U....0....0...*.|
-00000270  48 86 f7 0d 01 01 05 05  00 03 81 81 00 08 6c 45  |H.............lE|
-00000280  24 c7 6b b1 59 ab 0c 52  cc f2 b0 14 d7 87 9d 7a  |$.k.Y..R.......z|
-00000290  64 75 b5 5a 95 66 e4 c5  2b 8e ae 12 66 1f eb 4f  |du.Z.f..+...f..O|
-000002a0  38 b3 6e 60 d3 92 fd f7  41 08 b5 25 13 b1 18 7a  |8.n`....A..%...z|
-000002b0  24 fb 30 1d ba ed 98 b9  17 ec e7 d7 31 59 db 95  |$.0.........1Y..|
-000002c0  d3 1d 78 ea 50 56 5c d5  82 5a 2d 5a 5f 33 c4 b6  |..x.PV\..Z-Z_3..|
-000002d0  d8 c9 75 90 96 8c 0f 52  98 b5 cd 98 1f 89 20 5f  |..u....R...... _|
-000002e0  f2 a0 1c a3 1b 96 94 dd  a9 fd 57 e9 70 e8 26 6d  |..........W.p.&m|
-000002f0  71 99 9b 26 6e 38 50 29  6c 90 a7 bd d9 16 03 03  |q..&n8P)l.......|
-00000300  00 cd 0c 00 00 c9 03 00  17 41 04 1e 18 37 ef 0d  |.........A...7..|
-00000310  19 51 88 35 75 71 b5 e5  54 5b 12 2e 8f 09 67 fd  |.Q.5uq..T[....g.|
-00000320  a7 24 20 3e b2 56 1c ce  97 28 5e f8 2b 2d 4f 9e  |.$ >.V...(^.+-O.|
-00000330  f1 07 9f 6c 4b 5b 83 56  e2 32 42 e9 58 b6 d7 49  |...lK[.V.2B.X..I|
-00000340  a6 b5 68 1a 41 03 56 6b  dc 5a 89 04 01 00 80 b9  |..h.A.Vk.Z......|
-00000350  0f 79 8a 16 f4 da 8f 27  b4 16 fc c0 51 db ae d1  |.y.....'....Q...|
-00000360  af 79 77 d5 d5 a2 13 05  45 20 cc eb ac ed cb 30  |.yw.....E .....0|
-00000370  32 2e 2c bd fa 1c 4d b5  32 a6 37 43 c8 5c 2d f8  |2.,...M.2.7C.\-.|
-00000380  6e 85 f5 cd 54 92 29 ad  13 7d d5 9e 8c 1d b7 d0  |n...T.)..}......|
-00000390  c1 c7 3d e8 ba 4a 0f 9a  a6 3e 25 5f 27 62 b1 00  |..=..J...>%_'b..|
-000003a0  91 d9 23 48 3f 10 fe c5  e3 07 9a 58 57 6d cc 10  |..#H?......XWm..|
-000003b0  3b f8 1a d5 6e 8b 1f 03  6f 82 84 98 b5 f7 71 5d  |;...n...o.....q]|
-000003c0  c2 ad 60 14 c1 88 07 5a  3d 99 fd a8 c9 9a 03 16  |..`....Z=.......|
-000003d0  03 03 00 04 0e 00 00 00                           |........|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 c0 30 00 00  |.............0..|
+00000030  09 00 23 00 00 ff 01 00  01 00 16 03 03 02 71 0b  |..#...........q.|
+00000040  00 02 6d 00 02 6a 00 02  67 30 82 02 63 30 82 01  |..m..j..g0..c0..|
+00000050  cc a0 03 02 01 02 02 09  00 a2 73 00 0c 81 00 cb  |..........s.....|
+00000060  f3 30 0d 06 09 2a 86 48  86 f7 0d 01 01 0b 05 00  |.0...*.H........|
+00000070  30 2b 31 17 30 15 06 03  55 04 0a 13 0e 47 6f 6f  |0+1.0...U....Goo|
+00000080  67 6c 65 20 54 45 53 54  49 4e 47 31 10 30 0e 06  |gle TESTING1.0..|
+00000090  03 55 04 03 13 07 47 6f  20 52 6f 6f 74 30 1e 17  |.U....Go Root0..|
+000000a0  0d 31 35 30 31 30 31 30  30 30 30 30 30 5a 17 0d  |.150101000000Z..|
+000000b0  32 35 30 31 30 31 30 30  30 30 30 30 5a 30 26 31  |250101000000Z0&1|
+000000c0  17 30 15 06 03 55 04 0a  13 0e 47 6f 6f 67 6c 65  |.0...U....Google|
+000000d0  20 54 45 53 54 49 4e 47  31 0b 30 09 06 03 55 04  | TESTING1.0...U.|
+000000e0  03 13 02 47 6f 30 81 9f  30 0d 06 09 2a 86 48 86  |...Go0..0...*.H.|
+000000f0  f7 0d 01 01 01 05 00 03  81 8d 00 30 81 89 02 81  |...........0....|
+00000100  81 00 af 87 88 f6 20 1b  95 65 6c 14 ab 44 05 af  |...... ..el..D..|
+00000110  3b 45 14 e3 b7 6d fd 00  63 4d 95 7f fe 6a 62 35  |;E...m..cM...jb5|
+00000120  86 c0 4a f9 18 7c f6 aa  25 5e 7a 64 31 66 00 ba  |..J..|..%^zd1f..|
+00000130  f4 8e 92 af c7 6b d8 76  d4 f3 5f 41 cb 6e 56 15  |.....k.v.._A.nV.|
+00000140  97 1b 97 c1 3c 12 39 21  66 3d 2b 16 d1 bc db 1c  |....<.9!f=+.....|
+00000150  c0 a7 da b7 ca ad ba da  cb d5 21 50 ec de 8d ab  |..........!P....|
+00000160  d1 6b 81 4b 89 02 f3 c4  be c1 6c 89 b1 44 84 bd  |.k.K......l..D..|
+00000170  21 d1 04 7d 9d 16 4d f9  82 15 f6 ef fa d6 09 47  |!..}..M........G|
+00000180  f2 fb 02 03 01 00 01 a3  81 93 30 81 90 30 0e 06  |..........0..0..|
+00000190  03 55 1d 0f 01 01 ff 04  04 03 02 05 a0 30 1d 06  |.U...........0..|
+000001a0  03 55 1d 25 04 16 30 14  06 08 2b 06 01 05 05 07  |.U.%..0...+.....|
+000001b0  03 01 06 08 2b 06 01 05  05 07 03 02 30 0c 06 03  |....+.......0...|
+000001c0  55 1d 13 01 01 ff 04 02  30 00 30 19 06 03 55 1d  |U.......0.0...U.|
+000001d0  0e 04 12 04 10 12 50 8d  89 6f 1b d1 dc 54 4d 6e  |......P..o...TMn|
+000001e0  cb 69 5e 06 f4 30 1b 06  03 55 1d 23 04 14 30 12  |.i^..0...U.#..0.|
+000001f0  80 10 bf 3d b6 a9 66 f2  b8 40 cf ea b4 03 78 48  |...=..f.. at ....xH|
+00000200  1a 41 30 19 06 03 55 1d  11 04 12 30 10 82 0e 65  |.A0...U....0...e|
+00000210  78 61 6d 70 6c 65 2e 67  6f 6c 61 6e 67 30 0d 06  |xample.golang0..|
+00000220  09 2a 86 48 86 f7 0d 01  01 0b 05 00 03 81 81 00  |.*.H............|
+00000230  92 7c af 91 55 12 18 96  59 31 a6 48 40 d5 2d d5  |.|..U...Y1.H at .-.|
+00000240  ee bb 02 a0 f5 c2 1e 7c  9b b3 30 7d 3c dc 76 da  |.......|..0}<.v.|
+00000250  4f 3d c0 fa ae 2d 33 24  6b 03 7b 1b 67 59 11 21  |O=...-3$k.{.gY.!|
+00000260  b5 11 bc 77 b9 d9 e0 6e  a8 2d 2e 35 fa 64 5f 22  |...w...n.-.5.d_"|
+00000270  3e 63 10 6b be ff 14 86  6d 0d f0 15 31 a8 14 38  |>c.k....m...1..8|
+00000280  1e 3b 84 87 2c cb 98 ed  51 76 b9 b1 4f dd db 9b  |.;..,...Qv..O...|
+00000290  84 04 86 40 fa 51 dd ba  b4 8d eb e3 46 de 46 b9  |... at .Q......F.F.|
+000002a0  4f 86 c7 f9 a4 c2 41 34  ac cc f6 ea b0 ab 39 18  |O.....A4......9.|
+000002b0  16 03 03 00 cd 0c 00 00  c9 03 00 17 41 04 1e 18  |............A...|
+000002c0  37 ef 0d 19 51 88 35 75  71 b5 e5 54 5b 12 2e 8f  |7...Q.5uq..T[...|
+000002d0  09 67 fd a7 24 20 3e b2  56 1c ce 97 28 5e f8 2b  |.g..$ >.V...(^.+|
+000002e0  2d 4f 9e f1 07 9f 6c 4b  5b 83 56 e2 32 42 e9 58  |-O....lK[.V.2B.X|
+000002f0  b6 d7 49 a6 b5 68 1a 41  03 56 6b dc 5a 89 05 01  |..I..h.A.Vk.Z...|
+00000300  00 80 36 d2 96 c8 27 66  d8 bd 6c 28 29 30 b3 be  |..6...'f..l()0..|
+00000310  0a bb b2 fe 9d c3 59 47  34 cf de fe f4 ab 5d 79  |......YG4.....]y|
+00000320  24 a9 9d c9 b5 e9 50 6a  3b 96 e3 29 cb d7 37 06  |$.....Pj;..)..7.|
+00000330  19 08 88 15 29 c2 55 03  62 75 1d 35 c2 8e 25 a2  |....).U.bu.5..%.|
+00000340  86 20 bf 18 46 15 81 f2  74 4b bb dd 3d e3 a5 f6  |. ..F...tK..=...|
+00000350  28 18 41 89 c8 39 13 f9  c0 88 fd cc f0 6e 9e 3d  |(.A..9.......n.=|
+00000360  cb 29 ad 26 5b d1 e6 11  5c 64 7d b6 df d7 39 87  |.).&[...\d}...9.|
+00000370  24 df 9f 62 17 ef f2 b3  3a b3 88 a4 f0 91 ea f2  |$..b....:.......|
+00000380  5d c9 16 03 03 00 04 0e  00 00 00                 |]..........|
 >>> Flow 3 (client to server)
-00000000  16 03 03 00 46 10 00 00  42 41 04 76 aa 4e b9 f9  |....F...BA.v.N..|
-00000010  68 85 81 74 7c d9 f9 64  7f bd 09 83 08 5b 4f 76  |h..t|..d.....[Ov|
-00000020  6e be 79 b6 4e 97 17 63  e4 b5 1c 77 e5 85 76 8a  |n.y.N..c...w..v.|
-00000030  5d 9f f1 21 88 ec f9 a7  7c 41 af f9 c5 fe 11 81  |]..!....|A......|
-00000040  11 51 8e a7 20 33 5f cf  e7 90 90 14 03 03 00 01  |.Q.. 3_.........|
-00000050  01 16 03 03 00 40 44 3e  32 01 71 ac 5a b5 1f 2c  |..... at D>2.q.Z..,|
-00000060  37 d9 4b 70 72 91 89 d4  d7 c2 c3 e7 ff dc 72 2a  |7.Kpr.........r*|
-00000070  ba f5 30 b0 e9 dd 48 10  3d cd 98 48 a3 e3 ca de  |..0...H.=..H....|
-00000080  15 0e 90 8e e5 04 14 74  42 b8 b0 12 cc 68 7b 7d  |.......tB....h{}|
-00000090  6c 43 72 60 05 0d                                 |lCr`..|
+00000000  16 03 03 00 46 10 00 00  42 41 04 b0 22 15 73 fc  |....F...BA..".s.|
+00000010  1c fd 24 4a 36 69 8a be  ac bd 72 30 bb 6b e1 9b  |..$J6i....r0.k..|
+00000020  42 e8 56 7a 86 b1 8d cb  9c 3e 2d 63 13 57 a8 13  |B.Vz.....>-c.W..|
+00000030  71 3b a2 01 86 af f8 76  40 0b 44 4f 0a 0f 5a da  |q;.....v at .DO..Z.|
+00000040  31 36 3b 13 c0 10 6c 96  64 a7 24 14 03 03 00 01  |16;...l.d.$.....|
+00000050  01 16 03 03 00 28 10 2d  45 93 5c 37 34 d9 2a a0  |.....(.-E.\74.*.|
+00000060  b6 37 13 bc a6 1f 0c ce  2e 55 c1 ad 36 b8 60 72  |.7.......U..6.`r|
+00000070  81 cb 1a 7a 5b 26 49 ad  77 ef 62 e8 fc 00        |...z[&I.w.b...|
 >>> Flow 4 (server to client)
-00000000  16 03 03 00 72 04 00 00  6e 00 00 00 00 00 68 00  |....r...n.....h.|
-00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 65  |...............e|
-00000020  ea 8b c0 ef ba 12 45 17  61 24 cd d2 4c 22 bb 3b  |......E.a$..L".;|
-00000030  e3 0e d0 ff 83 e9 7c b7  8f 10 3c 16 1c fc c2 44  |......|...<....D|
-00000040  ef 45 f8 27 30 56 db ea  eb ae f5 b6 17 b2 ef f9  |.E.'0V..........|
-00000050  96 0d 2d db e4 59 23 0a  fc fa e3 13 48 57 e5 b3  |..-..Y#.....HW..|
-00000060  3a d1 f5 5e ca ef d7 3f  7b b5 f4 69 85 c3 bd da  |:..^...?{..i....|
-00000070  fd 9c 50 05 2f 86 ce 14  03 03 00 01 01 16 03 03  |..P./...........|
-00000080  00 40 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |. at ..............|
-00000090  00 00 60 25 1c ed 6f c6  a5 bd b2 29 39 4e 09 d1  |..`%..o....)9N..|
-000000a0  64 cc 75 cd df 91 a8 90  9d 03 aa 92 07 f2 d0 8a  |d.u.............|
-000000b0  60 bb 3e 85 21 22 fe f8  dc 52 3c 4e 82 77 14 14  |`.>.!"...R<N.w..|
-000000c0  0f 1f 17 03 03 00 40 00  00 00 00 00 00 00 00 00  |...... at .........|
-000000d0  00 00 00 00 00 00 00 0b  87 12 62 3e e5 3e 7d 74  |..........b>.>}t|
-000000e0  0d ac c4 a9 df 67 1c 5a  ad 3e 01 34 03 88 2f 39  |.....g.Z.>.4../9|
-000000f0  f7 3c 06 e4 f6 81 43 66  b1 1b ed a5 e5 b6 a8 43  |.<....Cf.......C|
-00000100  7f 36 2f b2 da 45 9a 15  03 03 00 30 00 00 00 00  |.6/..E.....0....|
-00000110  00 00 00 00 00 00 00 00  00 00 00 00 fa 63 4e c5  |.............cN.|
-00000120  77 89 71 56 e3 0a cf 98  da 2f 89 8f 74 8e 76 24  |w.qV...../..t.v$|
-00000130  e2 40 a5 9f 29 1b b2 11  ef 7a 55 7f              |. at ..)....zU.|
+00000000  16 03 03 00 82 04 00 00  7e 00 00 00 00 00 78 50  |........~.....xP|
+00000010  46 ad c1 db a8 38 86 7b  2b bb fd d0 c3 42 3e 00  |F....8.{+....B>.|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 94  |................|
+00000030  6f ec 80 83 61 05 33 d2  9d 95 89 7b 28 54 50 50  |o...a.3....{(TPP|
+00000040  b3 3c 99 5c 82 ab cf 88  24 e8 48 81 db 4a 22 79  |.<.\....$.H..J"y|
+00000050  0b fa 33 50 ed 82 a1 7c  33 0e f2 ff 6d a7 d6 88  |..3P...|3...m...|
+00000060  29 65 74 e3 27 33 94 97  66 0c 86 ce fc ca 0e 2a  |)et.'3..f......*|
+00000070  96 fa fe 19 a3 01 64 d9  4d 8e 58 95 5b 74 a6 aa  |......d.M.X.[t..|
+00000080  f4 9f c1 34 97 2d e5 14  03 03 00 01 01 16 03 03  |...4.-..........|
+00000090  00 28 00 00 00 00 00 00  00 00 4d 56 6d d5 6f cc  |.(........MVm.o.|
+000000a0  3d d4 85 32 3c 07 ea 3c  52 61 88 8e dd d5 d3 d0  |=..2<..<Ra......|
+000000b0  f9 4e 1b b1 c1 d1 67 cb  1a e8 17 03 03 00 25 00  |.N....g.......%.|
+000000c0  00 00 00 00 00 00 01 c3  43 ab 0c ab 59 30 e9 d4  |........C...Y0..|
+000000d0  eb 65 c2 7f 9a 5a 1e 09  06 a4 9d 69 bb 3f 0b 06  |.e...Z.....i.?..|
+000000e0  87 b8 09 39 15 03 03 00  1a 00 00 00 00 00 00 00  |...9............|
+000000f0  02 c2 6f f4 88 f0 7a 59  a6 49 3e 44 a3 7b 6e 36  |..o...zY.I>D.{n6|
+00000100  ae 66 87                                          |.f.|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA b/src/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA
index 0ab8b8d..344d973 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA
+++ b/src/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceECDSA
@@ -1,91 +1,98 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 ca 01 00 00  c6 03 03 53 04 f1 3f 5f  |...........S..?_|
-00000010  f4 ef 1f b3 41 0b 54 e4  4d 56 0a 31 22 b8 5c 73  |....A.T.MV.1".\s|
-00000020  a3 cb b5 b2 9d 43 f1 83  bc d3 bd 00 00 32 c0 30  |.....C.......2.0|
-00000030  c0 2c c0 28 c0 24 c0 14  c0 0a c0 22 c0 21 00 a3  |.,.(.$.....".!..|
-00000040  00 9f 00 6b 00 6a 00 39  00 38 00 88 00 87 c0 32  |...k.j.9.8.....2|
-00000050  c0 2e c0 2a c0 26 c0 0f  c0 05 00 9d 00 3d 00 35  |...*.&.......=.5|
-00000060  01 00 00 6b 00 0b 00 04  03 00 01 02 00 0a 00 34  |...k...........4|
-00000070  00 32 00 0e 00 0d 00 19  00 0b 00 0c 00 18 00 09  |.2..............|
-00000080  00 0a 00 16 00 17 00 08  00 06 00 07 00 14 00 15  |................|
-00000090  00 04 00 05 00 12 00 13  00 01 00 02 00 03 00 0f  |................|
-000000a0  00 10 00 11 00 0d 00 22  00 20 06 01 06 02 06 03  |.......". ......|
-000000b0  05 01 05 02 05 03 04 01  04 02 04 03 03 01 03 02  |................|
-000000c0  03 03 02 01 02 02 02 03  01 01 00 0f 00 01 01     |...............|
+00000000  16 03 01 01 34 01 00 01  30 03 03 78 08 b2 d4 18  |....4...0..x....|
+00000010  8e b1 6b a2 d2 e0 c6 41  02 c5 93 f1 b9 60 94 e8  |..k....A.....`..|
+00000020  f2 64 6c 97 50 2d 24 a3  cd c0 36 00 00 b6 c0 30  |.dl.P-$...6....0|
+00000030  c0 2c c0 28 c0 24 c0 14  c0 0a 00 a5 00 a3 00 a1  |.,.(.$..........|
+00000040  00 9f 00 6b 00 6a 00 69  00 68 00 39 00 38 00 37  |...k.j.i.h.9.8.7|
+00000050  00 36 00 88 00 87 00 86  00 85 c0 32 c0 2e c0 2a  |.6.........2...*|
+00000060  c0 26 c0 0f c0 05 00 9d  00 3d 00 35 00 84 c0 2f  |.&.......=.5.../|
+00000070  c0 2b c0 27 c0 23 c0 13  c0 09 00 a4 00 a2 00 a0  |.+.'.#..........|
+00000080  00 9e 00 67 00 40 00 3f  00 3e 00 33 00 32 00 31  |...g. at .?.>.3.2.1|
+00000090  00 30 00 9a 00 99 00 98  00 97 00 45 00 44 00 43  |.0.........E.D.C|
+000000a0  00 42 c0 31 c0 2d c0 29  c0 25 c0 0e c0 04 00 9c  |.B.1.-.).%......|
+000000b0  00 3c 00 2f 00 96 00 41  00 07 c0 11 c0 07 c0 0c  |.<./...A........|
+000000c0  c0 02 00 05 00 04 c0 12  c0 08 00 16 00 13 00 10  |................|
+000000d0  00 0d c0 0d c0 03 00 0a  00 15 00 12 00 0f 00 0c  |................|
+000000e0  00 09 00 ff 01 00 00 51  00 0b 00 04 03 00 01 02  |.......Q........|
+000000f0  00 0a 00 1c 00 1a 00 17  00 19 00 1c 00 1b 00 18  |................|
+00000100  00 1a 00 16 00 0e 00 0d  00 0b 00 0c 00 09 00 0a  |................|
+00000110  00 0d 00 20 00 1e 06 01  06 02 06 03 05 01 05 02  |... ............|
+00000120  05 03 04 01 04 02 04 03  03 01 03 02 03 03 02 01  |................|
+00000130  02 02 02 03 00 0f 00 01  01                       |.........|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 2a 02 00 00  26 03 03 00 00 00 00 00  |....*...&.......|
+00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
 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 c0 0a 00 16  |................|
-00000030  03 03 02 0e 0b 00 02 0a  00 02 07 00 02 04 30 82  |..............0.|
-00000040  02 00 30 82 01 62 02 09  00 b8 bf 2d 47 a0 d2 eb  |..0..b.....-G...|
-00000050  f4 30 09 06 07 2a 86 48  ce 3d 04 01 30 45 31 0b  |.0...*.H.=..0E1.|
-00000060  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
-00000070  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
-00000080  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
-00000090  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
-000000a0  4c 74 64 30 1e 17 0d 31  32 31 31 32 32 31 35 30  |Ltd0...121122150|
-000000b0  36 33 32 5a 17 0d 32 32  31 31 32 30 31 35 30 36  |632Z..2211201506|
-000000c0  33 32 5a 30 45 31 0b 30  09 06 03 55 04 06 13 02  |32Z0E1.0...U....|
-000000d0  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
-000000e0  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
-000000f0  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
-00000100  74 73 20 50 74 79 20 4c  74 64 30 81 9b 30 10 06  |ts Pty Ltd0..0..|
-00000110  07 2a 86 48 ce 3d 02 01  06 05 2b 81 04 00 23 03  |.*.H.=....+...#.|
-00000120  81 86 00 04 00 c4 a1 ed  be 98 f9 0b 48 73 36 7e  |............Hs6~|
-00000130  c3 16 56 11 22 f2 3d 53  c3 3b 4d 21 3d cd 6b 75  |..V.".=S.;M!=.ku|
-00000140  e6 f6 b0 dc 9a df 26 c1  bc b2 87 f0 72 32 7c b3  |......&.....r2|.|
-00000150  64 2f 1c 90 bc ea 68 23  10 7e fe e3 25 c0 48 3a  |d/....h#.~..%.H:|
-00000160  69 e0 28 6d d3 37 00 ef  04 62 dd 0d a0 9c 70 62  |i.(m.7...b....pb|
-00000170  83 d8 81 d3 64 31 aa 9e  97 31 bd 96 b0 68 c0 9b  |....d1...1...h..|
-00000180  23 de 76 64 3f 1a 5c 7f  e9 12 0e 58 58 b6 5f 70  |#.vd?.\....XX._p|
-00000190  dd 9b d8 ea d5 d7 f5 d5  cc b9 b6 9f 30 66 5b 66  |............0f[f|
-000001a0  9a 20 e2 27 e5 bf fe 3b  30 09 06 07 2a 86 48 ce  |. .'...;0...*.H.|
-000001b0  3d 04 01 03 81 8c 00 30  81 88 02 42 01 88 a2 4f  |=......0...B...O|
-000001c0  eb e2 45 c5 48 7d 1b ac  f5 ed 98 9d ae 47 70 c0  |..E.H}.......Gp.|
-000001d0  5e 1b b6 2f bd f1 b6 4d  b7 61 40 d3 11 a2 ce ee  |^../...M.a at .....|
-000001e0  0b 7e 92 7e ff 76 9d c3  3b 7e a5 3f ce fa 10 e2  |.~.~.v..;~.?....|
-000001f0  59 ec 47 2d 7c ac da 4e  97 0e 15 a0 6f d0 02 42  |Y.G-|..N....o..B|
-00000200  01 4d fc be 67 13 9c 2d  05 0e bd 3f a3 8c 25 c1  |.M..g..-...?..%.|
-00000210  33 13 83 0d 94 06 bb d4  37 7a f6 ec 7a c9 86 2e  |3.......7z..z...|
-00000220  dd d7 11 69 7f 85 7c 56  de fb 31 78 2b e4 c7 78  |...i..|V..1x+..x|
-00000230  0d ae cb be 9e 4e 36 24  31 7b 6a 0f 39 95 12 07  |.....N6$1{j.9...|
-00000240  8f 2a 16 03 03 00 d8 0c  00 00 d4 03 00 17 41 04  |.*............A.|
-00000250  1e 18 37 ef 0d 19 51 88  35 75 71 b5 e5 54 5b 12  |..7...Q.5uq..T[.|
-00000260  2e 8f 09 67 fd a7 24 20  3e b2 56 1c ce 97 28 5e  |...g..$ >.V...(^|
-00000270  f8 2b 2d 4f 9e f1 07 9f  6c 4b 5b 83 56 e2 32 42  |.+-O....lK[.V.2B|
-00000280  e9 58 b6 d7 49 a6 b5 68  1a 41 03 56 6b dc 5a 89  |.X..I..h.A.Vk.Z.|
-00000290  04 03 00 8b 30 81 88 02  42 00 c6 85 8e 06 b7 04  |....0...B.......|
-000002a0  04 e9 cd 9e 3e cb 66 23  95 b4 42 9c 64 81 39 05  |....>.f#..B.d.9.|
-000002b0  3f b5 21 f8 28 af 60 6b  4d 3d ba a1 4b 5e 77 ef  |?.!.(.`kM=..K^w.|
-000002c0  e7 59 28 fe 1d c1 27 a2  ff a8 de 33 48 b3 c1 85  |.Y(...'....3H...|
-000002d0  6a 42 9b f9 7e 7e 31 c2  e5 bd 66 02 42 00 ad 7d  |jB..~~1...f.B..}|
-000002e0  06 35 ab ec 8d ac d4 ba  1b 49 5e 05 5f f0 97 93  |.5.......I^._...|
-000002f0  82 b8 2b 8d 91 98 63 8e  b4 14 62 db 1e c9 2b 64  |..+...c...b...+d|
-00000300  e9 e6 bf 15 5b 67 c2 40  90 c6 1f b7 92 db 4b f6  |....[g. at ......K.|
-00000310  f4 db ae 82 f1 4f 02 75  52 40 38 10 ff 35 f0 16  |.....O.uR at 8..5..|
-00000320  03 03 00 04 0e 00 00 00                           |........|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 c0 0a 00 00  |................|
+00000030  05 ff 01 00 01 00 16 03  03 02 0e 0b 00 02 0a 00  |................|
+00000040  02 07 00 02 04 30 82 02  00 30 82 01 62 02 09 00  |.....0...0..b...|
+00000050  b8 bf 2d 47 a0 d2 eb f4  30 09 06 07 2a 86 48 ce  |..-G....0...*.H.|
+00000060  3d 04 01 30 45 31 0b 30  09 06 03 55 04 06 13 02  |=..0E1.0...U....|
+00000070  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
+00000080  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
+00000090  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
+000000a0  74 73 20 50 74 79 20 4c  74 64 30 1e 17 0d 31 32  |ts Pty Ltd0...12|
+000000b0  31 31 32 32 31 35 30 36  33 32 5a 17 0d 32 32 31  |1122150632Z..221|
+000000c0  31 32 30 31 35 30 36 33  32 5a 30 45 31 0b 30 09  |120150632Z0E1.0.|
+000000d0  06 03 55 04 06 13 02 41  55 31 13 30 11 06 03 55  |..U....AU1.0...U|
+000000e0  04 08 13 0a 53 6f 6d 65  2d 53 74 61 74 65 31 21  |....Some-State1!|
+000000f0  30 1f 06 03 55 04 0a 13  18 49 6e 74 65 72 6e 65  |0...U....Interne|
+00000100  74 20 57 69 64 67 69 74  73 20 50 74 79 20 4c 74  |t Widgits Pty Lt|
+00000110  64 30 81 9b 30 10 06 07  2a 86 48 ce 3d 02 01 06  |d0..0...*.H.=...|
+00000120  05 2b 81 04 00 23 03 81  86 00 04 00 c4 a1 ed be  |.+...#..........|
+00000130  98 f9 0b 48 73 36 7e c3  16 56 11 22 f2 3d 53 c3  |...Hs6~..V.".=S.|
+00000140  3b 4d 21 3d cd 6b 75 e6  f6 b0 dc 9a df 26 c1 bc  |;M!=.ku......&..|
+00000150  b2 87 f0 72 32 7c b3 64  2f 1c 90 bc ea 68 23 10  |...r2|.d/....h#.|
+00000160  7e fe e3 25 c0 48 3a 69  e0 28 6d d3 37 00 ef 04  |~..%.H:i.(m.7...|
+00000170  62 dd 0d a0 9c 70 62 83  d8 81 d3 64 31 aa 9e 97  |b....pb....d1...|
+00000180  31 bd 96 b0 68 c0 9b 23  de 76 64 3f 1a 5c 7f e9  |1...h..#.vd?.\..|
+00000190  12 0e 58 58 b6 5f 70 dd  9b d8 ea d5 d7 f5 d5 cc  |..XX._p.........|
+000001a0  b9 b6 9f 30 66 5b 66 9a  20 e2 27 e5 bf fe 3b 30  |...0f[f. .'...;0|
+000001b0  09 06 07 2a 86 48 ce 3d  04 01 03 81 8c 00 30 81  |...*.H.=......0.|
+000001c0  88 02 42 01 88 a2 4f eb  e2 45 c5 48 7d 1b ac f5  |..B...O..E.H}...|
+000001d0  ed 98 9d ae 47 70 c0 5e  1b b6 2f bd f1 b6 4d b7  |....Gp.^../...M.|
+000001e0  61 40 d3 11 a2 ce ee 0b  7e 92 7e ff 76 9d c3 3b  |a at ......~.~.v..;|
+000001f0  7e a5 3f ce fa 10 e2 59  ec 47 2d 7c ac da 4e 97  |~.?....Y.G-|..N.|
+00000200  0e 15 a0 6f d0 02 42 01  4d fc be 67 13 9c 2d 05  |...o..B.M..g..-.|
+00000210  0e bd 3f a3 8c 25 c1 33  13 83 0d 94 06 bb d4 37  |..?..%.3.......7|
+00000220  7a f6 ec 7a c9 86 2e dd  d7 11 69 7f 85 7c 56 de  |z..z......i..|V.|
+00000230  fb 31 78 2b e4 c7 78 0d  ae cb be 9e 4e 36 24 31  |.1x+..x.....N6$1|
+00000240  7b 6a 0f 39 95 12 07 8f  2a 16 03 03 00 d8 0c 00  |{j.9....*.......|
+00000250  00 d4 03 00 17 41 04 1e  18 37 ef 0d 19 51 88 35  |.....A...7...Q.5|
+00000260  75 71 b5 e5 54 5b 12 2e  8f 09 67 fd a7 24 20 3e  |uq..T[....g..$ >|
+00000270  b2 56 1c ce 97 28 5e f8  2b 2d 4f 9e f1 07 9f 6c  |.V...(^.+-O....l|
+00000280  4b 5b 83 56 e2 32 42 e9  58 b6 d7 49 a6 b5 68 1a  |K[.V.2B.X..I..h.|
+00000290  41 03 56 6b dc 5a 89 05  03 00 8b 30 81 88 02 42  |A.Vk.Z.....0...B|
+000002a0  00 91 b4 4a f2 9d 13 a1  6d 3b ee 46 2f 3b 97 50  |...J....m;.F/;.P|
+000002b0  b9 3e 28 7a 51 7a 8b 3b  a6 16 03 d6 1f 92 0a ec  |.>(zQz.;........|
+000002c0  5b 9b b5 48 98 ce d8 22  bd 7d eb cb 14 7b 14 73  |[..H...".}...{.s|
+000002d0  2d 5f 01 8c dc 5a 63 34  92 4e 59 4a 90 f9 b1 c9  |-_...Zc4.NYJ....|
+000002e0  d8 18 02 42 01 89 e4 e4  39 d0 52 d1 70 19 fe d7  |...B....9.R.p...|
+000002f0  c6 70 10 36 94 1e 45 fd  b4 03 37 79 c7 db cf 6d  |.p.6..E...7y...m|
+00000300  33 5d 80 fe 04 de d1 78  bf c4 dd cf 91 82 57 14  |3].....x......W.|
+00000310  14 09 e3 2d dd d2 78 9c  53 cc 1f f7 40 6c 4a 59  |...-..x.S... at lJY|
+00000320  49 a8 a1 06 24 18 16 03  03 00 04 0e 00 00 00     |I...$..........|
 >>> Flow 3 (client to server)
-00000000  16 03 03 00 46 10 00 00  42 41 04 d8 94 c4 05 26  |....F...BA.....&|
-00000010  76 29 2d 0e ec 47 b6 50  d5 a3 da 2a ba 02 11 37  |v)-..G.P...*...7|
-00000020  3d ef e6 2a db d0 47 47  a7 9a 5f 43 2d 98 78 26  |=..*..GG.._C-.x&|
-00000030  81 e2 f1 ba fe f7 66 c6  61 cb c1 b7 60 62 34 a5  |......f.a...`b4.|
-00000040  78 67 50 3d 9a 0e 4a 8c  8f d7 10 14 03 03 00 01  |xgP=..J.........|
-00000050  01 16 03 03 00 40 5e 46  b0 5d 30 f6 da 8f 9e 67  |.....@^F.]0....g|
-00000060  f5 3e bd fe c9 b8 53 b2  10 d5 7c 0e 34 e3 93 6d  |.>....S...|.4..m|
-00000070  0e 8e 8a 2b df fb 9a 0f  a5 23 55 e7 0a 4b e2 d3  |...+.....#U..K..|
-00000080  db 15 e8 52 74 26 78 b3  b0 56 65 63 ac ae 1e c0  |...Rt&x..Vec....|
-00000090  0b f4 92 56 a9 04                                 |...V..|
+00000000  16 03 03 00 46 10 00 00  42 41 04 66 37 3a ce 68  |....F...BA.f7:.h|
+00000010  23 0f b2 d0 cb 20 24 26  37 d5 84 46 4a 2e 59 80  |#.... $&7..FJ.Y.|
+00000020  87 b3 10 7e 36 fd af 7c  99 07 99 dd 18 af 6d 7c  |...~6..|......m||
+00000030  b5 b2 b7 93 45 95 d9 98  1a 13 5b a2 12 e8 b7 95  |....E.....[.....|
+00000040  ed a1 3a 6d aa 8f fc b6  b5 b4 41 14 03 03 00 01  |..:m......A.....|
+00000050  01 16 03 03 00 40 b0 12  69 00 a4 3a 6d bd 56 40  |..... at ..i..:m.V@|
+00000060  6e 9d 5e a8 1b 0f 59 c5  09 48 b2 07 d8 bc 7b 02  |n.^...Y..H....{.|
+00000070  70 61 f6 1b a9 27 55 8c  16 4d 69 4c ca 31 30 9f  |pa...'U..MiL.10.|
+00000080  d3 62 ba d4 1b 11 ee 0a  a0 f3 61 be c6 64 c3 dc  |.b........a..d..|
+00000090  97 50 47 27 ed 09                                 |.PG'..|
 >>> Flow 4 (server to client)
 00000000  14 03 03 00 01 01 16 03  03 00 40 00 00 00 00 00  |.......... at .....|
-00000010  00 00 00 00 00 00 00 00  00 00 00 16 a9 63 0a 99  |.............c..|
-00000020  21 8a fc 5c b3 ee 05 71  4e 75 c0 d9 40 54 0d 3e  |!..\...qNu.. at T.>|
-00000030  4e 5d 44 b7 4b 5d a9 e7  5a 30 ed b6 d5 08 50 b1  |N]D.K]..Z0....P.|
-00000040  e8 8c 54 eb 1b 39 7a f9  3b ac 2e 17 03 03 00 40  |..T..9z.;......@|
+00000010  00 00 00 00 00 00 00 00  00 00 00 09 34 9a eb 7c  |............4..||
+00000020  6a 6d 6a 02 7b 50 14 b8  f7 b0 93 30 ea 0b 61 4a  |jmj.{P.....0..aJ|
+00000030  0b 75 10 39 41 78 46 9d  ba 8e d3 e9 e4 ab dc 1f  |.u.9AxF.........|
+00000040  c9 43 95 e8 f9 d6 3a d3  5d 7d 09 17 03 03 00 40  |.C....:.]}.....@|
 00000050  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000060  96 03 20 2b 20 c4 c1 9a  76 7b f3 96 bd 33 ed e6  |.. + ...v{...3..|
-00000070  38 48 ea 53 d5 e0 62 b5  7e 1a 36 a8 dd 9f 2d 4b  |8H.S..b.~.6...-K|
-00000080  06 0d ae f6 bc 99 14 b3  93 14 27 63 e2 a0 c8 76  |..........'c...v|
+00000060  b4 64 88 d5 53 f9 1e 47  d4 d8 c4 fa 0e c2 76 a6  |.d..S..G......v.|
+00000070  ed 5c 17 ba ea 76 72 cb  c5 73 a3 c5 44 21 3c 40  |.\...vr..s..D!<@|
+00000080  33 27 09 37 73 3b 0e a3  7b 95 72 10 8d 74 85 19  |3'.7s;..{.r..t..|
 00000090  15 03 03 00 30 00 00 00  00 00 00 00 00 00 00 00  |....0...........|
-000000a0  00 00 00 00 00 48 af e1  e4 11 e1 b7 03 19 b0 e3  |.....H..........|
-000000b0  e6 a9 66 d8 ac af aa 03  f6 0d 51 df 9a 27 78 3a  |..f.......Q..'x:|
-000000c0  56 5a 03 1a 4c                                    |VZ..L|
+000000a0  00 00 00 00 00 b3 c0 05  e9 ec 05 06 52 ef 09 b7  |............R...|
+000000b0  52 29 04 88 ed 11 bb bd  36 a3 0f ce 2c 55 a2 87  |R)......6...,U..|
+000000c0  7e 2b 0c aa 83                                    |~+...|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA b/src/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA
index 88abb15..10624c0 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA
+++ b/src/crypto/tls/testdata/Server-TLSv12-CipherSuiteCertPreferenceRSA
@@ -1,101 +1,104 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 ca 01 00 00  c6 03 03 53 04 f1 3f cc  |...........S..?.|
-00000010  41 74 00 07 cb ae 3b 30  79 48 51 60 41 a3 8c ab  |At....;0yHQ`A...|
-00000020  dc 76 f9 74 52 1e c5 fb  a9 69 c2 00 00 32 c0 30  |.v.tR....i...2.0|
-00000030  c0 2c c0 28 c0 24 c0 14  c0 0a c0 22 c0 21 00 a3  |.,.(.$.....".!..|
-00000040  00 9f 00 6b 00 6a 00 39  00 38 00 88 00 87 c0 32  |...k.j.9.8.....2|
-00000050  c0 2e c0 2a c0 26 c0 0f  c0 05 00 9d 00 3d 00 35  |...*.&.......=.5|
-00000060  01 00 00 6b 00 0b 00 04  03 00 01 02 00 0a 00 34  |...k...........4|
-00000070  00 32 00 0e 00 0d 00 19  00 0b 00 0c 00 18 00 09  |.2..............|
-00000080  00 0a 00 16 00 17 00 08  00 06 00 07 00 14 00 15  |................|
-00000090  00 04 00 05 00 12 00 13  00 01 00 02 00 03 00 0f  |................|
-000000a0  00 10 00 11 00 0d 00 22  00 20 06 01 06 02 06 03  |.......". ......|
-000000b0  05 01 05 02 05 03 04 01  04 02 04 03 03 01 03 02  |................|
-000000c0  03 03 02 01 02 02 02 03  01 01 00 0f 00 01 01     |...............|
+00000000  16 03 01 01 34 01 00 01  30 03 03 10 5e c8 3f c6  |....4...0...^.?.|
+00000010  fe 44 c4 f0 13 c5 bd ad  06 21 65 e5 a8 40 b5 1d  |.D.......!e.. at ..|
+00000020  21 07 99 34 5b ef 70 85  29 92 7d 00 00 b6 c0 30  |!..4[.p.).}....0|
+00000030  c0 2c c0 28 c0 24 c0 14  c0 0a 00 a5 00 a3 00 a1  |.,.(.$..........|
+00000040  00 9f 00 6b 00 6a 00 69  00 68 00 39 00 38 00 37  |...k.j.i.h.9.8.7|
+00000050  00 36 00 88 00 87 00 86  00 85 c0 32 c0 2e c0 2a  |.6.........2...*|
+00000060  c0 26 c0 0f c0 05 00 9d  00 3d 00 35 00 84 c0 2f  |.&.......=.5.../|
+00000070  c0 2b c0 27 c0 23 c0 13  c0 09 00 a4 00 a2 00 a0  |.+.'.#..........|
+00000080  00 9e 00 67 00 40 00 3f  00 3e 00 33 00 32 00 31  |...g. at .?.>.3.2.1|
+00000090  00 30 00 9a 00 99 00 98  00 97 00 45 00 44 00 43  |.0.........E.D.C|
+000000a0  00 42 c0 31 c0 2d c0 29  c0 25 c0 0e c0 04 00 9c  |.B.1.-.).%......|
+000000b0  00 3c 00 2f 00 96 00 41  00 07 c0 11 c0 07 c0 0c  |.<./...A........|
+000000c0  c0 02 00 05 00 04 c0 12  c0 08 00 16 00 13 00 10  |................|
+000000d0  00 0d c0 0d c0 03 00 0a  00 15 00 12 00 0f 00 0c  |................|
+000000e0  00 09 00 ff 01 00 00 51  00 0b 00 04 03 00 01 02  |.......Q........|
+000000f0  00 0a 00 1c 00 1a 00 17  00 19 00 1c 00 1b 00 18  |................|
+00000100  00 1a 00 16 00 0e 00 0d  00 0b 00 0c 00 09 00 0a  |................|
+00000110  00 0d 00 20 00 1e 06 01  06 02 06 03 05 01 05 02  |... ............|
+00000120  05 03 04 01 04 02 04 03  03 01 03 02 03 03 02 01  |................|
+00000130  02 02 02 03 00 0f 00 01  01                       |.........|
 >>> Flow 2 (server to client)
-00000000  16 03 03 00 2a 02 00 00  26 03 03 00 00 00 00 00  |....*...&.......|
+00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
 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 c0 14 00 16  |................|
-00000030  03 03 02 be 0b 00 02 ba  00 02 b7 00 02 b4 30 82  |..............0.|
-00000040  02 b0 30 82 02 19 a0 03  02 01 02 02 09 00 85 b0  |..0.............|
-00000050  bb a4 8a 7f b8 ca 30 0d  06 09 2a 86 48 86 f7 0d  |......0...*.H...|
-00000060  01 01 05 05 00 30 45 31  0b 30 09 06 03 55 04 06  |.....0E1.0...U..|
-00000070  13 02 41 55 31 13 30 11  06 03 55 04 08 13 0a 53  |..AU1.0...U....S|
-00000080  6f 6d 65 2d 53 74 61 74  65 31 21 30 1f 06 03 55  |ome-State1!0...U|
-00000090  04 0a 13 18 49 6e 74 65  72 6e 65 74 20 57 69 64  |....Internet Wid|
-000000a0  67 69 74 73 20 50 74 79  20 4c 74 64 30 1e 17 0d  |gits Pty Ltd0...|
-000000b0  31 30 30 34 32 34 30 39  30 39 33 38 5a 17 0d 31  |100424090938Z..1|
-000000c0  31 30 34 32 34 30 39 30  39 33 38 5a 30 45 31 0b  |10424090938Z0E1.|
-000000d0  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
-000000e0  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
-000000f0  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
-00000100  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
-00000110  4c 74 64 30 81 9f 30 0d  06 09 2a 86 48 86 f7 0d  |Ltd0..0...*.H...|
-00000120  01 01 01 05 00 03 81 8d  00 30 81 89 02 81 81 00  |.........0......|
-00000130  bb 79 d6 f5 17 b5 e5 bf  46 10 d0 dc 69 be e6 2b  |.y......F...i..+|
-00000140  07 43 5a d0 03 2d 8a 7a  43 85 b7 14 52 e7 a5 65  |.CZ..-.zC...R..e|
-00000150  4c 2c 78 b8 23 8c b5 b4  82 e5 de 1f 95 3b 7e 62  |L,x.#........;~b|
-00000160  a5 2c a5 33 d6 fe 12 5c  7a 56 fc f5 06 bf fa 58  |.,.3...\zV.....X|
-00000170  7b 26 3f b5 cd 04 d3 d0  c9 21 96 4a c7 f4 54 9f  |{&?......!.J..T.|
-00000180  5a bf ef 42 71 00 fe 18  99 07 7f 7e 88 7d 7d f1  |Z..Bq......~.}}.|
-00000190  04 39 c4 a2 2e db 51 c9  7c e3 c0 4c 3b 32 66 01  |.9....Q.|..L;2f.|
-000001a0  cf af b1 1d b8 71 9a 1d  db db 89 6b ae da 2d 79  |.....q.....k..-y|
-000001b0  02 03 01 00 01 a3 81 a7  30 81 a4 30 1d 06 03 55  |........0..0...U|
-000001c0  1d 0e 04 16 04 14 b1 ad  e2 85 5a cf cb 28 db 69  |..........Z..(.i|
-000001d0  ce 23 69 de d3 26 8e 18  88 39 30 75 06 03 55 1d  |.#i..&...90u..U.|
-000001e0  23 04 6e 30 6c 80 14 b1  ad e2 85 5a cf cb 28 db  |#.n0l......Z..(.|
-000001f0  69 ce 23 69 de d3 26 8e  18 88 39 a1 49 a4 47 30  |i.#i..&...9.I.G0|
-00000200  45 31 0b 30 09 06 03 55  04 06 13 02 41 55 31 13  |E1.0...U....AU1.|
-00000210  30 11 06 03 55 04 08 13  0a 53 6f 6d 65 2d 53 74  |0...U....Some-St|
-00000220  61 74 65 31 21 30 1f 06  03 55 04 0a 13 18 49 6e  |ate1!0...U....In|
-00000230  74 65 72 6e 65 74 20 57  69 64 67 69 74 73 20 50  |ternet Widgits P|
-00000240  74 79 20 4c 74 64 82 09  00 85 b0 bb a4 8a 7f b8  |ty Ltd..........|
-00000250  ca 30 0c 06 03 55 1d 13  04 05 30 03 01 01 ff 30  |.0...U....0....0|
-00000260  0d 06 09 2a 86 48 86 f7  0d 01 01 05 05 00 03 81  |...*.H..........|
-00000270  81 00 08 6c 45 24 c7 6b  b1 59 ab 0c 52 cc f2 b0  |...lE$.k.Y..R...|
-00000280  14 d7 87 9d 7a 64 75 b5  5a 95 66 e4 c5 2b 8e ae  |....zdu.Z.f..+..|
-00000290  12 66 1f eb 4f 38 b3 6e  60 d3 92 fd f7 41 08 b5  |.f..O8.n`....A..|
-000002a0  25 13 b1 18 7a 24 fb 30  1d ba ed 98 b9 17 ec e7  |%...z$.0........|
-000002b0  d7 31 59 db 95 d3 1d 78  ea 50 56 5c d5 82 5a 2d  |.1Y....x.PV\..Z-|
-000002c0  5a 5f 33 c4 b6 d8 c9 75  90 96 8c 0f 52 98 b5 cd  |Z_3....u....R...|
-000002d0  98 1f 89 20 5f f2 a0 1c  a3 1b 96 94 dd a9 fd 57  |... _..........W|
-000002e0  e9 70 e8 26 6d 71 99 9b  26 6e 38 50 29 6c 90 a7  |.p.&mq..&n8P)l..|
-000002f0  bd d9 16 03 03 00 cd 0c  00 00 c9 03 00 17 41 04  |..............A.|
-00000300  1e 18 37 ef 0d 19 51 88  35 75 71 b5 e5 54 5b 12  |..7...Q.5uq..T[.|
-00000310  2e 8f 09 67 fd a7 24 20  3e b2 56 1c ce 97 28 5e  |...g..$ >.V...(^|
-00000320  f8 2b 2d 4f 9e f1 07 9f  6c 4b 5b 83 56 e2 32 42  |.+-O....lK[.V.2B|
-00000330  e9 58 b6 d7 49 a6 b5 68  1a 41 03 56 6b dc 5a 89  |.X..I..h.A.Vk.Z.|
-00000340  04 01 00 80 9d 84 09 35  73 fb f6 ea 94 7b 49 fb  |.......5s....{I.|
-00000350  c2 70 b1 11 64 5b 93 9f  d9 8c f5 56 98 f6 d3 66  |.p..d[.....V...f|
-00000360  a6 1d 18 56 88 87 71 3f  b0 38 9d 44 1f ad 2c 0d  |...V..q?.8.D..,.|
-00000370  3a a7 e8 d4 3e 33 3c 41  20 f3 3f 5c e5 fb e3 23  |:...>3<A .?\...#|
-00000380  12 48 ff d2 c4 30 7c 8a  51 3f 9f 19 6e 34 d7 60  |.H...0|.Q?..n4.`|
-00000390  7d 12 8a aa 90 0f 50 d9  0b 9a b2 d7 66 b1 c6 84  |}.....P.....f...|
-000003a0  af 5c e2 5e 16 3e 36 61  73 84 64 89 b3 c1 6d 50  |.\.^.>6as.d...mP|
-000003b0  33 55 c7 e1 c5 a5 4c 32  5c 95 dc 07 43 60 49 11  |3U....L2\...C`I.|
-000003c0  e9 98 cc ba 16 03 03 00  04 0e 00 00 00           |.............|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 c0 14 00 00  |................|
+00000030  05 ff 01 00 01 00 16 03  03 02 71 0b 00 02 6d 00  |..........q...m.|
+00000040  02 6a 00 02 67 30 82 02  63 30 82 01 cc a0 03 02  |.j..g0..c0......|
+00000050  01 02 02 09 00 a2 73 00  0c 81 00 cb f3 30 0d 06  |......s......0..|
+00000060  09 2a 86 48 86 f7 0d 01  01 0b 05 00 30 2b 31 17  |.*.H........0+1.|
+00000070  30 15 06 03 55 04 0a 13  0e 47 6f 6f 67 6c 65 20  |0...U....Google |
+00000080  54 45 53 54 49 4e 47 31  10 30 0e 06 03 55 04 03  |TESTING1.0...U..|
+00000090  13 07 47 6f 20 52 6f 6f  74 30 1e 17 0d 31 35 30  |..Go Root0...150|
+000000a0  31 30 31 30 30 30 30 30  30 5a 17 0d 32 35 30 31  |101000000Z..2501|
+000000b0  30 31 30 30 30 30 30 30  5a 30 26 31 17 30 15 06  |01000000Z0&1.0..|
+000000c0  03 55 04 0a 13 0e 47 6f  6f 67 6c 65 20 54 45 53  |.U....Google TES|
+000000d0  54 49 4e 47 31 0b 30 09  06 03 55 04 03 13 02 47  |TING1.0...U....G|
+000000e0  6f 30 81 9f 30 0d 06 09  2a 86 48 86 f7 0d 01 01  |o0..0...*.H.....|
+000000f0  01 05 00 03 81 8d 00 30  81 89 02 81 81 00 af 87  |.......0........|
+00000100  88 f6 20 1b 95 65 6c 14  ab 44 05 af 3b 45 14 e3  |.. ..el..D..;E..|
+00000110  b7 6d fd 00 63 4d 95 7f  fe 6a 62 35 86 c0 4a f9  |.m..cM...jb5..J.|
+00000120  18 7c f6 aa 25 5e 7a 64  31 66 00 ba f4 8e 92 af  |.|..%^zd1f......|
+00000130  c7 6b d8 76 d4 f3 5f 41  cb 6e 56 15 97 1b 97 c1  |.k.v.._A.nV.....|
+00000140  3c 12 39 21 66 3d 2b 16  d1 bc db 1c c0 a7 da b7  |<.9!f=+.........|
+00000150  ca ad ba da cb d5 21 50  ec de 8d ab d1 6b 81 4b  |......!P.....k.K|
+00000160  89 02 f3 c4 be c1 6c 89  b1 44 84 bd 21 d1 04 7d  |......l..D..!..}|
+00000170  9d 16 4d f9 82 15 f6 ef  fa d6 09 47 f2 fb 02 03  |..M........G....|
+00000180  01 00 01 a3 81 93 30 81  90 30 0e 06 03 55 1d 0f  |......0..0...U..|
+00000190  01 01 ff 04 04 03 02 05  a0 30 1d 06 03 55 1d 25  |.........0...U.%|
+000001a0  04 16 30 14 06 08 2b 06  01 05 05 07 03 01 06 08  |..0...+.........|
+000001b0  2b 06 01 05 05 07 03 02  30 0c 06 03 55 1d 13 01  |+.......0...U...|
+000001c0  01 ff 04 02 30 00 30 19  06 03 55 1d 0e 04 12 04  |....0.0...U.....|
+000001d0  10 12 50 8d 89 6f 1b d1  dc 54 4d 6e cb 69 5e 06  |..P..o...TMn.i^.|
+000001e0  f4 30 1b 06 03 55 1d 23  04 14 30 12 80 10 bf 3d  |.0...U.#..0....=|
+000001f0  b6 a9 66 f2 b8 40 cf ea  b4 03 78 48 1a 41 30 19  |..f.. at ....xH.A0.|
+00000200  06 03 55 1d 11 04 12 30  10 82 0e 65 78 61 6d 70  |..U....0...examp|
+00000210  6c 65 2e 67 6f 6c 61 6e  67 30 0d 06 09 2a 86 48  |le.golang0...*.H|
+00000220  86 f7 0d 01 01 0b 05 00  03 81 81 00 92 7c af 91  |.............|..|
+00000230  55 12 18 96 59 31 a6 48  40 d5 2d d5 ee bb 02 a0  |U...Y1.H at .-.....|
+00000240  f5 c2 1e 7c 9b b3 30 7d  3c dc 76 da 4f 3d c0 fa  |...|..0}<.v.O=..|
+00000250  ae 2d 33 24 6b 03 7b 1b  67 59 11 21 b5 11 bc 77  |.-3$k.{.gY.!...w|
+00000260  b9 d9 e0 6e a8 2d 2e 35  fa 64 5f 22 3e 63 10 6b  |...n.-.5.d_">c.k|
+00000270  be ff 14 86 6d 0d f0 15  31 a8 14 38 1e 3b 84 87  |....m...1..8.;..|
+00000280  2c cb 98 ed 51 76 b9 b1  4f dd db 9b 84 04 86 40  |,...Qv..O......@|
+00000290  fa 51 dd ba b4 8d eb e3  46 de 46 b9 4f 86 c7 f9  |.Q......F.F.O...|
+000002a0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 03 00  |..A4......9.....|
+000002b0  cd 0c 00 00 c9 03 00 17  41 04 1e 18 37 ef 0d 19  |........A...7...|
+000002c0  51 88 35 75 71 b5 e5 54  5b 12 2e 8f 09 67 fd a7  |Q.5uq..T[....g..|
+000002d0  24 20 3e b2 56 1c ce 97  28 5e f8 2b 2d 4f 9e f1  |$ >.V...(^.+-O..|
+000002e0  07 9f 6c 4b 5b 83 56 e2  32 42 e9 58 b6 d7 49 a6  |..lK[.V.2B.X..I.|
+000002f0  b5 68 1a 41 03 56 6b dc  5a 89 05 01 00 80 6a 4b  |.h.A.Vk.Z.....jK|
+00000300  b1 7d 23 cd 0e cb 26 02  d4 ee 90 f2 e0 4a 47 3d  |.}#...&......JG=|
+00000310  b3 36 90 8d 01 42 98 92  ad 75 87 71 02 70 02 a8  |.6...B...u.q.p..|
+00000320  0c b0 06 ee bd 6a 1f 3f  6c 4b 4b 6b 75 41 23 b4  |.....j.?lKKkuA#.|
+00000330  f9 c2 a6 60 e2 de 55 b6  d4 85 62 e9 8f 20 70 ed  |...`..U...b.. p.|
+00000340  9a b8 bb dd 1f 19 87 e9  ad b3 30 3f 7c 63 51 f1  |..........0?|cQ.|
+00000350  59 ab d1 a0 a1 80 22 56  ca 68 52 f8 0f 80 c6 a6  |Y....."V.hR.....|
+00000360  9e 12 51 ed 29 d0 6d c2  1a e5 37 dc 76 e3 f3 53  |..Q.).m...7.v..S|
+00000370  1b 07 0b ea a6 11 af dc  54 d3 ee 25 cc 27 16 03  |........T..%.'..|
+00000380  03 00 04 0e 00 00 00                              |.......|
 >>> Flow 3 (client to server)
-00000000  16 03 03 00 46 10 00 00  42 41 04 28 02 84 d5 b4  |....F...BA.(....|
-00000010  58 07 47 d5 a0 d6 0b 1d  37 91 e6 34 a4 ad 0b ad  |X.G.....7..4....|
-00000020  22 01 82 77 a7 32 86 78  83 3a da 75 2f e5 68 7a  |"..w.2.x.:.u/.hz|
-00000030  de e4 05 e0 02 47 40 4e  38 d2 2c c3 7b da 53 73  |.....G at N8.,.{.Ss|
-00000040  19 cb 8b 73 34 72 4d 33  71 39 c8 14 03 03 00 01  |...s4rM3q9......|
-00000050  01 16 03 03 00 40 10 63  43 76 83 bd 36 e4 1e 4d  |..... at .cCv..6..M|
-00000060  7e 13 b0 ac aa c8 ec 90  31 df 84 46 49 68 39 5a  |~.......1..FIh9Z|
-00000070  05 8b 73 32 86 15 3a 18  57 d8 e2 2c 2d 05 89 93  |..s2..:.W..,-...|
-00000080  37 b8 dd 73 33 92 ff a7  b2 53 27 94 b7 25 56 64  |7..s3....S'..%Vd|
-00000090  a1 d3 2c f7 6b 71                                 |..,.kq|
+00000000  16 03 03 00 46 10 00 00  42 41 04 2d 4b 0c 6b 65  |....F...BA.-K.ke|
+00000010  82 32 95 8b 77 ec f0 f2  b2 ba d1 38 74 ed 82 49  |.2..w......8t..I|
+00000020  fb ce 8f 66 97 9d b6 97  d8 ae f5 19 af ad 47 b9  |...f..........G.|
+00000030  db 7b d2 c9 4e 10 68 14  ed 23 a5 98 94 f9 2a 00  |.{..N.h..#....*.|
+00000040  b6 44 b3 44 01 29 6c 56  da bb a8 14 03 03 00 01  |.D.D.)lV........|
+00000050  01 16 03 03 00 40 f4 fd  de d6 20 2e 18 80 4e 73  |..... at .... ...Ns|
+00000060  af dd 97 42 08 3b 51 80  e9 26 00 48 6b 8b 21 99  |...B.;Q..&.Hk.!.|
+00000070  a8 60 1f 64 51 d0 5a 90  8b b0 69 b8 6b 29 59 21  |.`.dQ.Z...i.k)Y!|
+00000080  b1 13 19 13 07 01 e1 2c  c3 6b 17 2d 01 a5 be d6  |.......,.k.-....|
+00000090  b0 0d 3d 6a 8c fe                                 |..=j..|
 >>> Flow 4 (server to client)
 00000000  14 03 03 00 01 01 16 03  03 00 40 00 00 00 00 00  |.......... at .....|
-00000010  00 00 00 00 00 00 00 00  00 00 00 21 5c 31 b1 4b  |...........!\1.K|
-00000020  96 96 30 8f 79 35 3a 3a  2d 26 67 d0 70 48 be 30  |..0.y5::-&g.pH.0|
-00000030  f8 3e e8 c1 cb 1d d5 89  f6 9c 72 bb 1c f9 4d 90  |.>........r...M.|
-00000040  9c d7 c6 fa 40 76 a5 61  46 61 24 17 03 03 00 40  |.... at v.aFa$....@|
+00000010  00 00 00 00 00 00 00 00  00 00 00 84 e2 7f e3 b4  |................|
+00000020  53 d7 d0 30 c4 e5 ea 09  df ba 33 b0 02 34 eb 2e  |S..0......3..4..|
+00000030  b2 ec 47 0d e7 20 76 12  fa 53 3b 44 86 e1 e1 63  |..G.. v..S;D...c|
+00000040  06 29 57 98 ce 87 18 ad  02 17 01 17 03 03 00 40  |.)W............@|
 00000050  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000060  94 8a 14 04 06 b9 30 a0  67 fd b2 4c 84 f4 10 93  |......0.g..L....|
-00000070  7d d4 2b 23 f0 e9 62 93  c2 20 a2 f2 7c 07 21 4b  |}.+#..b.. ..|.!K|
-00000080  94 ba 7b 7d cb 77 da 85  93 bd 53 ee ca db 9b 3e  |..{}.w....S....>|
+00000060  b0 3a f5 90 90 30 9c b3  39 5b b4 56 f6 b9 30 7e  |.:...0..9[.V..0~|
+00000070  8e a8 2d 60 47 b6 57 8a  20 61 02 f2 8e 43 c2 01  |..-`G.W. a...C..|
+00000080  ee f0 be 5a 93 52 2f ea  03 2a 4f 01 ea 9e 1c a2  |...Z.R/..*O.....|
 00000090  15 03 03 00 30 00 00 00  00 00 00 00 00 00 00 00  |....0...........|
-000000a0  00 00 00 00 00 17 3f 53  8d b3 35 b4 84 ed bb 12  |......?S..5.....|
-000000b0  cf 73 25 25 7c c3 d3 bb  1f 5a 6b 73 9a 8a b1 a2  |.s%%|....Zks....|
-000000c0  ba 99 f8 0e 43                                    |....C|
+000000a0  00 00 00 00 00 c0 7e 61  51 a1 76 15 8a 7e 20 5f  |......~aQ.v..~ _|
+000000b0  d4 a4 c6 3e 6c 50 18 c6  63 88 d0 ac 4c fa 31 b3  |...>lP..c...L.1.|
+000000c0  e7 c9 77 11 7a                                    |..w.z|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven b/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven
index 547f798..56c3c82 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven
+++ b/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven
@@ -1,62 +1,57 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 5c 01 00 00  58 03 03 52 cc 57 59 65  |....\...X..R.WYe|
-00000010  ae b3 ec a4 7a 05 f7 ec  39 22 7d 8c 91 96 6b e0  |....z...9"}...k.|
-00000020  69 81 ff 88 28 17 60 ac  94 19 ff 00 00 04 00 05  |i...(.`.........|
-00000030  00 ff 01 00 00 2b 00 0d  00 22 00 20 06 01 06 02  |.....+...". ....|
+00000000  16 03 01 00 5a 01 00 00  56 03 03 80 13 c8 83 43  |....Z...V......C|
+00000010  94 79 15 01 6e 0a 9f c5  0f e7 f6 d8 b1 94 de b4  |.y..n...........|
+00000020  57 8c 4f a8 08 48 ee 9b  b4 d2 43 00 00 04 00 05  |W.O..H....C.....|
+00000030  00 ff 01 00 00 29 00 0d  00 20 00 1e 06 01 06 02  |.....)... ......|
 00000040  06 03 05 01 05 02 05 03  04 01 04 02 04 03 03 01  |................|
-00000050  03 02 03 03 02 01 02 02  02 03 01 01 00 0f 00 01  |................|
-00000060  01                                                |.|
+00000050  03 02 03 03 02 01 02 02  02 03 00 0f 00 01 01     |...............|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
 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 05 00 00  |................|
-00000030  05 ff 01 00 01 00 16 03  03 02 be 0b 00 02 ba 00  |................|
-00000040  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
-00000050  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
-00000060  09 2a 86 48 86 f7 0d 01  01 05 05 00 30 45 31 0b  |.*.H........0E1.|
-00000070  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
-00000080  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
-00000090  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
-000000a0  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
-000000b0  4c 74 64 30 1e 17 0d 31  30 30 34 32 34 30 39 30  |Ltd0...100424090|
-000000c0  39 33 38 5a 17 0d 31 31  30 34 32 34 30 39 30 39  |938Z..1104240909|
-000000d0  33 38 5a 30 45 31 0b 30  09 06 03 55 04 06 13 02  |38Z0E1.0...U....|
-000000e0  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
-000000f0  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
-00000100  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
-00000110  74 73 20 50 74 79 20 4c  74 64 30 81 9f 30 0d 06  |ts Pty Ltd0..0..|
-00000120  09 2a 86 48 86 f7 0d 01  01 01 05 00 03 81 8d 00  |.*.H............|
-00000130  30 81 89 02 81 81 00 bb  79 d6 f5 17 b5 e5 bf 46  |0.......y......F|
-00000140  10 d0 dc 69 be e6 2b 07  43 5a d0 03 2d 8a 7a 43  |...i..+.CZ..-.zC|
-00000150  85 b7 14 52 e7 a5 65 4c  2c 78 b8 23 8c b5 b4 82  |...R..eL,x.#....|
-00000160  e5 de 1f 95 3b 7e 62 a5  2c a5 33 d6 fe 12 5c 7a  |....;~b.,.3...\z|
-00000170  56 fc f5 06 bf fa 58 7b  26 3f b5 cd 04 d3 d0 c9  |V.....X{&?......|
-00000180  21 96 4a c7 f4 54 9f 5a  bf ef 42 71 00 fe 18 99  |!.J..T.Z..Bq....|
-00000190  07 7f 7e 88 7d 7d f1 04  39 c4 a2 2e db 51 c9 7c  |..~.}}..9....Q.||
-000001a0  e3 c0 4c 3b 32 66 01 cf  af b1 1d b8 71 9a 1d db  |..L;2f......q...|
-000001b0  db 89 6b ae da 2d 79 02  03 01 00 01 a3 81 a7 30  |..k..-y........0|
-000001c0  81 a4 30 1d 06 03 55 1d  0e 04 16 04 14 b1 ad e2  |..0...U.........|
-000001d0  85 5a cf cb 28 db 69 ce  23 69 de d3 26 8e 18 88  |.Z..(.i.#i..&...|
-000001e0  39 30 75 06 03 55 1d 23  04 6e 30 6c 80 14 b1 ad  |90u..U.#.n0l....|
-000001f0  e2 85 5a cf cb 28 db 69  ce 23 69 de d3 26 8e 18  |..Z..(.i.#i..&..|
-00000200  88 39 a1 49 a4 47 30 45  31 0b 30 09 06 03 55 04  |.9.I.G0E1.0...U.|
-00000210  06 13 02 41 55 31 13 30  11 06 03 55 04 08 13 0a  |...AU1.0...U....|
-00000220  53 6f 6d 65 2d 53 74 61  74 65 31 21 30 1f 06 03  |Some-State1!0...|
-00000230  55 04 0a 13 18 49 6e 74  65 72 6e 65 74 20 57 69  |U....Internet Wi|
-00000240  64 67 69 74 73 20 50 74  79 20 4c 74 64 82 09 00  |dgits Pty Ltd...|
-00000250  85 b0 bb a4 8a 7f b8 ca  30 0c 06 03 55 1d 13 04  |........0...U...|
-00000260  05 30 03 01 01 ff 30 0d  06 09 2a 86 48 86 f7 0d  |.0....0...*.H...|
-00000270  01 01 05 05 00 03 81 81  00 08 6c 45 24 c7 6b b1  |..........lE$.k.|
-00000280  59 ab 0c 52 cc f2 b0 14  d7 87 9d 7a 64 75 b5 5a  |Y..R.......zdu.Z|
-00000290  95 66 e4 c5 2b 8e ae 12  66 1f eb 4f 38 b3 6e 60  |.f..+...f..O8.n`|
-000002a0  d3 92 fd f7 41 08 b5 25  13 b1 18 7a 24 fb 30 1d  |....A..%...z$.0.|
-000002b0  ba ed 98 b9 17 ec e7 d7  31 59 db 95 d3 1d 78 ea  |........1Y....x.|
-000002c0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
-000002d0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
-000002e0  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
-000002f0  6e 38 50 29 6c 90 a7 bd  d9 16 03 03 00 0f 0d 00  |n8P)l...........|
-00000300  00 0b 02 01 40 00 04 04  01 04 03 00 00 16 03 03  |.... at ...........|
-00000310  00 04 0e 00 00 00                                 |......|
+00000030  05 ff 01 00 01 00 16 03  03 02 71 0b 00 02 6d 00  |..........q...m.|
+00000040  02 6a 00 02 67 30 82 02  63 30 82 01 cc a0 03 02  |.j..g0..c0......|
+00000050  01 02 02 09 00 a2 73 00  0c 81 00 cb f3 30 0d 06  |......s......0..|
+00000060  09 2a 86 48 86 f7 0d 01  01 0b 05 00 30 2b 31 17  |.*.H........0+1.|
+00000070  30 15 06 03 55 04 0a 13  0e 47 6f 6f 67 6c 65 20  |0...U....Google |
+00000080  54 45 53 54 49 4e 47 31  10 30 0e 06 03 55 04 03  |TESTING1.0...U..|
+00000090  13 07 47 6f 20 52 6f 6f  74 30 1e 17 0d 31 35 30  |..Go Root0...150|
+000000a0  31 30 31 30 30 30 30 30  30 5a 17 0d 32 35 30 31  |101000000Z..2501|
+000000b0  30 31 30 30 30 30 30 30  5a 30 26 31 17 30 15 06  |01000000Z0&1.0..|
+000000c0  03 55 04 0a 13 0e 47 6f  6f 67 6c 65 20 54 45 53  |.U....Google TES|
+000000d0  54 49 4e 47 31 0b 30 09  06 03 55 04 03 13 02 47  |TING1.0...U....G|
+000000e0  6f 30 81 9f 30 0d 06 09  2a 86 48 86 f7 0d 01 01  |o0..0...*.H.....|
+000000f0  01 05 00 03 81 8d 00 30  81 89 02 81 81 00 af 87  |.......0........|
+00000100  88 f6 20 1b 95 65 6c 14  ab 44 05 af 3b 45 14 e3  |.. ..el..D..;E..|
+00000110  b7 6d fd 00 63 4d 95 7f  fe 6a 62 35 86 c0 4a f9  |.m..cM...jb5..J.|
+00000120  18 7c f6 aa 25 5e 7a 64  31 66 00 ba f4 8e 92 af  |.|..%^zd1f......|
+00000130  c7 6b d8 76 d4 f3 5f 41  cb 6e 56 15 97 1b 97 c1  |.k.v.._A.nV.....|
+00000140  3c 12 39 21 66 3d 2b 16  d1 bc db 1c c0 a7 da b7  |<.9!f=+.........|
+00000150  ca ad ba da cb d5 21 50  ec de 8d ab d1 6b 81 4b  |......!P.....k.K|
+00000160  89 02 f3 c4 be c1 6c 89  b1 44 84 bd 21 d1 04 7d  |......l..D..!..}|
+00000170  9d 16 4d f9 82 15 f6 ef  fa d6 09 47 f2 fb 02 03  |..M........G....|
+00000180  01 00 01 a3 81 93 30 81  90 30 0e 06 03 55 1d 0f  |......0..0...U..|
+00000190  01 01 ff 04 04 03 02 05  a0 30 1d 06 03 55 1d 25  |.........0...U.%|
+000001a0  04 16 30 14 06 08 2b 06  01 05 05 07 03 01 06 08  |..0...+.........|
+000001b0  2b 06 01 05 05 07 03 02  30 0c 06 03 55 1d 13 01  |+.......0...U...|
+000001c0  01 ff 04 02 30 00 30 19  06 03 55 1d 0e 04 12 04  |....0.0...U.....|
+000001d0  10 12 50 8d 89 6f 1b d1  dc 54 4d 6e cb 69 5e 06  |..P..o...TMn.i^.|
+000001e0  f4 30 1b 06 03 55 1d 23  04 14 30 12 80 10 bf 3d  |.0...U.#..0....=|
+000001f0  b6 a9 66 f2 b8 40 cf ea  b4 03 78 48 1a 41 30 19  |..f.. at ....xH.A0.|
+00000200  06 03 55 1d 11 04 12 30  10 82 0e 65 78 61 6d 70  |..U....0...examp|
+00000210  6c 65 2e 67 6f 6c 61 6e  67 30 0d 06 09 2a 86 48  |le.golang0...*.H|
+00000220  86 f7 0d 01 01 0b 05 00  03 81 81 00 92 7c af 91  |.............|..|
+00000230  55 12 18 96 59 31 a6 48  40 d5 2d d5 ee bb 02 a0  |U...Y1.H at .-.....|
+00000240  f5 c2 1e 7c 9b b3 30 7d  3c dc 76 da 4f 3d c0 fa  |...|..0}<.v.O=..|
+00000250  ae 2d 33 24 6b 03 7b 1b  67 59 11 21 b5 11 bc 77  |.-3$k.{.gY.!...w|
+00000260  b9 d9 e0 6e a8 2d 2e 35  fa 64 5f 22 3e 63 10 6b  |...n.-.5.d_">c.k|
+00000270  be ff 14 86 6d 0d f0 15  31 a8 14 38 1e 3b 84 87  |....m...1..8.;..|
+00000280  2c cb 98 ed 51 76 b9 b1  4f dd db 9b 84 04 86 40  |,...Qv..O......@|
+00000290  fa 51 dd ba b4 8d eb e3  46 de 46 b9 4f 86 c7 f9  |.Q......F.F.O...|
+000002a0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 03 00  |..A4......9.....|
+000002b0  17 0d 00 00 13 02 01 40  00 0c 04 01 04 03 05 01  |....... at ........|
+000002c0  05 03 02 01 02 03 00 00  16 03 03 00 04 0e 00 00  |................|
+000002d0  00                                                |.|
 >>> Flow 3 (client to server)
 00000000  16 03 03 02 0a 0b 00 02  06 00 02 03 00 02 00 30  |...............0|
 00000010  82 01 fc 30 82 01 5e 02  09 00 9a 30 84 6c 26 35  |...0..^....0.l&5|
@@ -91,32 +86,32 @@
 000001e0  be e8 91 b3 da 1a f5 5d  a3 23 f5 26 8b 45 70 8d  |.......].#.&.Ep.|
 000001f0  65 62 9b 7e 01 99 3d 18  f6 10 9a 38 61 9b 2e 57  |eb.~..=....8a..W|
 00000200  e4 fa cc b1 8a ce e2 23  a0 87 f0 e1 67 51 eb 16  |.......#....gQ..|
-00000210  03 03 00 86 10 00 00 82  00 80 47 5a 2f b8 78 46  |..........GZ/.xF|
-00000220  9f 3c fc ab 8b 35 c9 77  da c3 96 78 31 7c 2b 4f  |.<...5.w...x1|+O|
-00000230  56 be 0f 33 bd 17 bc 1c  86 5a ae b3 0f 8b 18 2f  |V..3.....Z...../|
-00000240  48 0d e0 0a 20 d3 53 96  88 d2 8a 7d b6 58 13 44  |H... .S....}.X.D|
-00000250  a5 e8 19 6d 02 df a6 1b  79 c5 54 c2 ef 4d 41 4f  |...m....y.T..MAO|
-00000260  04 1c eb 37 55 b7 2b f4  7c 6d 37 9c f1 89 a0 2c  |...7U.+.|m7....,|
-00000270  0f ba 10 09 e4 a1 ee 0a  7e 9a fd 2c 32 63 1c 55  |........~..,2c.U|
-00000280  85 38 de d0 7b 5f 46 03  1f cc 4d 69 51 97 d8 d7  |.8..{_F...MiQ...|
-00000290  88 6f ba 43 04 b0 42 09  61 5e 16 03 03 00 92 0f  |.o.C..B.a^......|
-000002a0  00 00 8e 04 03 00 8a 30  81 87 02 41 14 3d 4c 71  |.......0...A.=Lq|
-000002b0  c2 32 4a 20 ee b7 69 17  55 e8 99 55 11 76 51 7a  |.2J ..i.U..U.vQz|
-000002c0  74 55 e7 e8 c3 3b b3 70  db 1c 8e f6 8a d4 99 40  |tU...;.p.......@|
-000002d0  6e da 04 fd 7a 47 41 d6  ae c0 63 ad fd 91 a8 58  |n...zGA...c....X|
-000002e0  24 b9 ac 2f 7a 4c bf 5b  24 12 cb 3a f3 02 42 00  |$../zL.[$..:..B.|
-000002f0  90 f9 48 97 0e d4 33 99  09 9f 1d a8 97 16 60 82  |..H...3.......`.|
-00000300  85 cc 5a 5d 79 f7 2f 03  2a c0 b8 12 61 ac 9f 88  |..Z]y./.*...a...|
-00000310  1d 0d 9e 0a ee 28 a8 5a  e2 42 b7 94 e2 e6 0e 13  |.....(.Z.B......|
-00000320  c8 64 dc 4e d3 6b 10 d6  83 41 9c dc d4 53 c3 08  |.d.N.k...A...S..|
-00000330  19 14 03 03 00 01 01 16  03 03 00 24 ef bd e3 23  |...........$...#|
-00000340  10 23 ae 6e b5 12 eb 9c  21 78 db 36 fd bf 7f ee  |.#.n....!x.6....|
-00000350  6f c8 00 2d b6 35 cc 2f  38 73 ae a4 34 cf 0d df  |o..-.5./8s..4...|
+00000210  03 03 00 86 10 00 00 82  00 80 88 00 24 23 a5 c7  |............$#..|
+00000220  03 2d 86 37 91 f1 71 a9  5f fb 97 49 88 04 9b 0e  |.-.7..q._..I....|
+00000230  89 da 65 d0 56 71 e7 76  22 ef 8e 11 0e 6b 50 3d  |..e.Vq.v"....kP=|
+00000240  64 3f f7 9b e4 45 01 d9  12 cb da fe 10 da 4e b5  |d?...E........N.|
+00000250  b8 6a b5 bc 74 19 d3 4f  a9 bb ee 54 37 e4 70 d0  |.j..t..O...T7.p.|
+00000260  b6 e7 35 96 70 fe a5 2b  14 ac fb c6 1a fa 7d 12  |..5.p..+......}.|
+00000270  87 1b 63 9d 72 30 4d 2c  1a c9 29 32 72 b6 13 53  |..c.r0M,..)2r..S|
+00000280  96 05 de 78 bc f0 1a 74  e2 31 b9 ea db 62 62 6e  |...x...t.1...bbn|
+00000290  a0 a6 b2 c0 3e 2a 94 0d  6a f7 16 03 03 00 92 0f  |....>*..j.......|
+000002a0  00 00 8e 04 03 00 8a 30  81 87 02 42 01 71 5b 3b  |.......0...B.q[;|
+000002b0  a3 35 58 c0 b6 08 09 4f  ac af 89 e0 b3 d5 3d 45  |.5X....O......=E|
+000002c0  1f 49 7f 4a c9 bc 9d 0e  50 3a f5 79 bc 54 5d a9  |.I.J....P:.y.T].|
+000002d0  62 ed 85 c5 f3 47 36 03  cc f1 cd 33 c3 70 2a a6  |b....G6....3.p*.|
+000002e0  7c d9 6e 0c db 0d 1b 4f  6a 39 ba 77 bd ea 02 41  ||.n....Oj9.w...A|
+000002f0  00 f2 b7 06 df 2f 81 7e  98 24 46 06 59 4e 86 6a  |...../.~.$F.YN.j|
+00000300  b7 4f b6 4b 95 40 88 f0  8f f8 bd 16 f5 d5 82 7e  |.O.K. at .........~|
+00000310  82 51 6f 05 49 43 59 cd  1d 40 69 67 ff 65 a8 68  |.Qo.ICY.. at ig.e.h|
+00000320  39 2f a1 ad a7 6a ef 5c  d5 69 5e 16 50 bb 2a b2  |9/...j.\.i^.P.*.|
+00000330  2f 14 03 03 00 01 01 16  03 03 00 24 55 f6 74 21  |/..........$U.t!|
+00000340  b4 08 a0 7f a2 dc 86 44  e3 f8 e3 0d e1 d6 5c 1c  |.......D......\.|
+00000350  22 1e 41 2b 30 cc 34 0f  a4 a1 7c a0 27 21 01 e0  |".A+0.4...|.'!..|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 24 a7 50 0f 50 b4  |..........$.P.P.|
-00000010  1c c3 4d f3 7a 64 df 65  ac 35 22 13 46 cc ec 36  |..M.zd.e.5".F..6|
-00000020  e6 d2 f3 67 94 6a 18 85  9f 4a 3c 44 a3 58 b0 17  |...g.j...J<D.X..|
-00000030  03 03 00 21 51 0a 41 8c  fd 50 e3 54 8b 6a 1f 83  |...!Q.A..P.T.j..|
-00000040  a5 37 98 e1 5b 1e ec 03  1d c7 0e 28 6d 79 3f 34  |.7..[......(my?4|
-00000050  de 1c 38 6d 7e 15 03 03  00 16 06 fc b1 7d ad 70  |..8m~........}.p|
-00000060  1a de d4 b7 b5 e7 a2 6d  1b 9a b0 31 0c cc 7b 70  |.......m...1..{p|
+00000000  14 03 03 00 01 01 16 03  03 00 24 6f 6b e7 fb f7  |..........$ok...|
+00000010  52 83 b3 6f ba 1b d7 e8  cb 0a 05 ee 90 04 2b c7  |R..o..........+.|
+00000020  c2 bd 0d 8e ee 42 88 40  ae 01 4a d0 07 4b f4 17  |.....B. at ..J..K..|
+00000030  03 03 00 21 e0 8b bd 80  04 18 9c be 12 07 d4 4d  |...!...........M|
+00000040  58 d9 ec c3 f0 67 b5 b3  d1 78 25 e7 2e dd a0 0a  |X....g...x%.....|
+00000050  ac 0f a1 90 59 15 03 03  00 16 76 30 22 0b 00 83  |....Y.....v0"...|
+00000060  c4 31 29 1c ca 44 cb 9f  0e 48 17 21 43 f6 af 47  |.1)..D...H.!C..G|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndGiven b/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndGiven
index 04a5b11..862e0be 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndGiven
+++ b/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndGiven
@@ -1,62 +1,57 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 5c 01 00 00  58 03 03 52 cc 57 59 6b  |....\...X..R.WYk|
-00000010  11 07 04 39 77 20 c2 b4  3f cb 0a c9 53 fe 5b 3e  |...9w ..?...S.[>|
-00000020  5f 58 2c 7e 30 69 e1 8e  6c 9d c8 00 00 04 00 05  |_X,~0i..l.......|
-00000030  00 ff 01 00 00 2b 00 0d  00 22 00 20 06 01 06 02  |.....+...". ....|
+00000000  16 03 01 00 5a 01 00 00  56 03 03 b0 80 f6 7c 13  |....Z...V.....|.|
+00000010  30 5d 57 f0 11 3b 30 4b  0e 01 50 9a 44 0b 89 6f  |0]W..;0K..P.D..o|
+00000020  b6 f1 a3 34 b4 f1 b9 bf  fe 66 a5 00 00 04 00 05  |...4.....f......|
+00000030  00 ff 01 00 00 29 00 0d  00 20 00 1e 06 01 06 02  |.....)... ......|
 00000040  06 03 05 01 05 02 05 03  04 01 04 02 04 03 03 01  |................|
-00000050  03 02 03 03 02 01 02 02  02 03 01 01 00 0f 00 01  |................|
-00000060  01                                                |.|
+00000050  03 02 03 03 02 01 02 02  02 03 00 0f 00 01 01     |...............|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
 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 05 00 00  |................|
-00000030  05 ff 01 00 01 00 16 03  03 02 be 0b 00 02 ba 00  |................|
-00000040  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
-00000050  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
-00000060  09 2a 86 48 86 f7 0d 01  01 05 05 00 30 45 31 0b  |.*.H........0E1.|
-00000070  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
-00000080  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
-00000090  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
-000000a0  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
-000000b0  4c 74 64 30 1e 17 0d 31  30 30 34 32 34 30 39 30  |Ltd0...100424090|
-000000c0  39 33 38 5a 17 0d 31 31  30 34 32 34 30 39 30 39  |938Z..1104240909|
-000000d0  33 38 5a 30 45 31 0b 30  09 06 03 55 04 06 13 02  |38Z0E1.0...U....|
-000000e0  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
-000000f0  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
-00000100  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
-00000110  74 73 20 50 74 79 20 4c  74 64 30 81 9f 30 0d 06  |ts Pty Ltd0..0..|
-00000120  09 2a 86 48 86 f7 0d 01  01 01 05 00 03 81 8d 00  |.*.H............|
-00000130  30 81 89 02 81 81 00 bb  79 d6 f5 17 b5 e5 bf 46  |0.......y......F|
-00000140  10 d0 dc 69 be e6 2b 07  43 5a d0 03 2d 8a 7a 43  |...i..+.CZ..-.zC|
-00000150  85 b7 14 52 e7 a5 65 4c  2c 78 b8 23 8c b5 b4 82  |...R..eL,x.#....|
-00000160  e5 de 1f 95 3b 7e 62 a5  2c a5 33 d6 fe 12 5c 7a  |....;~b.,.3...\z|
-00000170  56 fc f5 06 bf fa 58 7b  26 3f b5 cd 04 d3 d0 c9  |V.....X{&?......|
-00000180  21 96 4a c7 f4 54 9f 5a  bf ef 42 71 00 fe 18 99  |!.J..T.Z..Bq....|
-00000190  07 7f 7e 88 7d 7d f1 04  39 c4 a2 2e db 51 c9 7c  |..~.}}..9....Q.||
-000001a0  e3 c0 4c 3b 32 66 01 cf  af b1 1d b8 71 9a 1d db  |..L;2f......q...|
-000001b0  db 89 6b ae da 2d 79 02  03 01 00 01 a3 81 a7 30  |..k..-y........0|
-000001c0  81 a4 30 1d 06 03 55 1d  0e 04 16 04 14 b1 ad e2  |..0...U.........|
-000001d0  85 5a cf cb 28 db 69 ce  23 69 de d3 26 8e 18 88  |.Z..(.i.#i..&...|
-000001e0  39 30 75 06 03 55 1d 23  04 6e 30 6c 80 14 b1 ad  |90u..U.#.n0l....|
-000001f0  e2 85 5a cf cb 28 db 69  ce 23 69 de d3 26 8e 18  |..Z..(.i.#i..&..|
-00000200  88 39 a1 49 a4 47 30 45  31 0b 30 09 06 03 55 04  |.9.I.G0E1.0...U.|
-00000210  06 13 02 41 55 31 13 30  11 06 03 55 04 08 13 0a  |...AU1.0...U....|
-00000220  53 6f 6d 65 2d 53 74 61  74 65 31 21 30 1f 06 03  |Some-State1!0...|
-00000230  55 04 0a 13 18 49 6e 74  65 72 6e 65 74 20 57 69  |U....Internet Wi|
-00000240  64 67 69 74 73 20 50 74  79 20 4c 74 64 82 09 00  |dgits Pty Ltd...|
-00000250  85 b0 bb a4 8a 7f b8 ca  30 0c 06 03 55 1d 13 04  |........0...U...|
-00000260  05 30 03 01 01 ff 30 0d  06 09 2a 86 48 86 f7 0d  |.0....0...*.H...|
-00000270  01 01 05 05 00 03 81 81  00 08 6c 45 24 c7 6b b1  |..........lE$.k.|
-00000280  59 ab 0c 52 cc f2 b0 14  d7 87 9d 7a 64 75 b5 5a  |Y..R.......zdu.Z|
-00000290  95 66 e4 c5 2b 8e ae 12  66 1f eb 4f 38 b3 6e 60  |.f..+...f..O8.n`|
-000002a0  d3 92 fd f7 41 08 b5 25  13 b1 18 7a 24 fb 30 1d  |....A..%...z$.0.|
-000002b0  ba ed 98 b9 17 ec e7 d7  31 59 db 95 d3 1d 78 ea  |........1Y....x.|
-000002c0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
-000002d0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
-000002e0  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
-000002f0  6e 38 50 29 6c 90 a7 bd  d9 16 03 03 00 0f 0d 00  |n8P)l...........|
-00000300  00 0b 02 01 40 00 04 04  01 04 03 00 00 16 03 03  |.... at ...........|
-00000310  00 04 0e 00 00 00                                 |......|
+00000030  05 ff 01 00 01 00 16 03  03 02 71 0b 00 02 6d 00  |..........q...m.|
+00000040  02 6a 00 02 67 30 82 02  63 30 82 01 cc a0 03 02  |.j..g0..c0......|
+00000050  01 02 02 09 00 a2 73 00  0c 81 00 cb f3 30 0d 06  |......s......0..|
+00000060  09 2a 86 48 86 f7 0d 01  01 0b 05 00 30 2b 31 17  |.*.H........0+1.|
+00000070  30 15 06 03 55 04 0a 13  0e 47 6f 6f 67 6c 65 20  |0...U....Google |
+00000080  54 45 53 54 49 4e 47 31  10 30 0e 06 03 55 04 03  |TESTING1.0...U..|
+00000090  13 07 47 6f 20 52 6f 6f  74 30 1e 17 0d 31 35 30  |..Go Root0...150|
+000000a0  31 30 31 30 30 30 30 30  30 5a 17 0d 32 35 30 31  |101000000Z..2501|
+000000b0  30 31 30 30 30 30 30 30  5a 30 26 31 17 30 15 06  |01000000Z0&1.0..|
+000000c0  03 55 04 0a 13 0e 47 6f  6f 67 6c 65 20 54 45 53  |.U....Google TES|
+000000d0  54 49 4e 47 31 0b 30 09  06 03 55 04 03 13 02 47  |TING1.0...U....G|
+000000e0  6f 30 81 9f 30 0d 06 09  2a 86 48 86 f7 0d 01 01  |o0..0...*.H.....|
+000000f0  01 05 00 03 81 8d 00 30  81 89 02 81 81 00 af 87  |.......0........|
+00000100  88 f6 20 1b 95 65 6c 14  ab 44 05 af 3b 45 14 e3  |.. ..el..D..;E..|
+00000110  b7 6d fd 00 63 4d 95 7f  fe 6a 62 35 86 c0 4a f9  |.m..cM...jb5..J.|
+00000120  18 7c f6 aa 25 5e 7a 64  31 66 00 ba f4 8e 92 af  |.|..%^zd1f......|
+00000130  c7 6b d8 76 d4 f3 5f 41  cb 6e 56 15 97 1b 97 c1  |.k.v.._A.nV.....|
+00000140  3c 12 39 21 66 3d 2b 16  d1 bc db 1c c0 a7 da b7  |<.9!f=+.........|
+00000150  ca ad ba da cb d5 21 50  ec de 8d ab d1 6b 81 4b  |......!P.....k.K|
+00000160  89 02 f3 c4 be c1 6c 89  b1 44 84 bd 21 d1 04 7d  |......l..D..!..}|
+00000170  9d 16 4d f9 82 15 f6 ef  fa d6 09 47 f2 fb 02 03  |..M........G....|
+00000180  01 00 01 a3 81 93 30 81  90 30 0e 06 03 55 1d 0f  |......0..0...U..|
+00000190  01 01 ff 04 04 03 02 05  a0 30 1d 06 03 55 1d 25  |.........0...U.%|
+000001a0  04 16 30 14 06 08 2b 06  01 05 05 07 03 01 06 08  |..0...+.........|
+000001b0  2b 06 01 05 05 07 03 02  30 0c 06 03 55 1d 13 01  |+.......0...U...|
+000001c0  01 ff 04 02 30 00 30 19  06 03 55 1d 0e 04 12 04  |....0.0...U.....|
+000001d0  10 12 50 8d 89 6f 1b d1  dc 54 4d 6e cb 69 5e 06  |..P..o...TMn.i^.|
+000001e0  f4 30 1b 06 03 55 1d 23  04 14 30 12 80 10 bf 3d  |.0...U.#..0....=|
+000001f0  b6 a9 66 f2 b8 40 cf ea  b4 03 78 48 1a 41 30 19  |..f.. at ....xH.A0.|
+00000200  06 03 55 1d 11 04 12 30  10 82 0e 65 78 61 6d 70  |..U....0...examp|
+00000210  6c 65 2e 67 6f 6c 61 6e  67 30 0d 06 09 2a 86 48  |le.golang0...*.H|
+00000220  86 f7 0d 01 01 0b 05 00  03 81 81 00 92 7c af 91  |.............|..|
+00000230  55 12 18 96 59 31 a6 48  40 d5 2d d5 ee bb 02 a0  |U...Y1.H at .-.....|
+00000240  f5 c2 1e 7c 9b b3 30 7d  3c dc 76 da 4f 3d c0 fa  |...|..0}<.v.O=..|
+00000250  ae 2d 33 24 6b 03 7b 1b  67 59 11 21 b5 11 bc 77  |.-3$k.{.gY.!...w|
+00000260  b9 d9 e0 6e a8 2d 2e 35  fa 64 5f 22 3e 63 10 6b  |...n.-.5.d_">c.k|
+00000270  be ff 14 86 6d 0d f0 15  31 a8 14 38 1e 3b 84 87  |....m...1..8.;..|
+00000280  2c cb 98 ed 51 76 b9 b1  4f dd db 9b 84 04 86 40  |,...Qv..O......@|
+00000290  fa 51 dd ba b4 8d eb e3  46 de 46 b9 4f 86 c7 f9  |.Q......F.F.O...|
+000002a0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 03 00  |..A4......9.....|
+000002b0  17 0d 00 00 13 02 01 40  00 0c 04 01 04 03 05 01  |....... at ........|
+000002c0  05 03 02 01 02 03 00 00  16 03 03 00 04 0e 00 00  |................|
+000002d0  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|
@@ -90,32 +85,32 @@
 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 86 10 00 00  82 00 80 44 89 7d aa 26  |...........D.}.&|
-00000210  30 ce 6b db 25 70 b0 1e  16 fa 5b 3a dd 4a 4b bd  |0.k.%p....[:.JK.|
-00000220  ec ee 50 9d 21 ba 52 b5  51 4f a8 65 d8 2e 41 e2  |..P.!.R.QO.e..A.|
-00000230  e1 dc f3 1a df 58 4f 87  7a d3 e1 e1 1c 13 b2 0b  |.....XO.z.......|
-00000240  b7 43 b7 92 f2 df 19 bb  79 71 e0 71 44 ab 19 2f  |.C......yq.qD../|
-00000250  37 11 ac 62 50 b6 f1 53  fe aa b4 bc 29 8e 0b 4c  |7..bP..S....)..L|
-00000260  0b 12 8d d5 84 a9 fa a9  ea 16 aa c3 0d da 32 c8  |..............2.|
-00000270  e0 4c 9f 99 f8 69 cd a8  c3 b1 76 42 67 f3 ff 15  |.L...i....vBg...|
-00000280  52 95 43 66 da 49 43 25  9d e5 eb 16 03 03 00 88  |R.Cf.IC%........|
-00000290  0f 00 00 84 04 01 00 80  01 d5 0e 1c 75 97 89 52  |............u..R|
-000002a0  1a f0 cc ef 93 6e 71 b2  b1 38 8c 50 11 f7 a3 02  |.....nq..8.P....|
-000002b0  71 c4 d5 6f 8d 01 83 06  2e ea 5a 10 8a 0d d0 fc  |q..o......Z.....|
-000002c0  b6 a2 63 af 4f 99 b5 eb  ab fd 01 c2 fb 26 fc fd  |..c.O........&..|
-000002d0  ad 2c b3 63 b3 87 a6 f5  14 ea 7d e7 fe a8 e7 7e  |.,.c......}....~|
-000002e0  20 ab b9 f6 c3 58 bd c0  f3 96 eb 83 dc 42 6c 0d  | ....X.......Bl.|
-000002f0  5e e8 09 55 c7 b8 24 05  dd e1 7c af 9f 2c 22 6c  |^..U..$...|..,"l|
-00000300  fa b8 94 13 3b f1 09 e1  38 59 fc a1 8c cb aa ca  |....;...8Y......|
-00000310  f8 e0 2a 9c 36 f9 c3 2b  14 03 03 00 01 01 16 03  |..*.6..+........|
-00000320  03 00 24 d0 12 7c cc d2  3e 37 1f f4 7d b4 c0 fc  |..$..|..>7..}...|
-00000330  19 f6 c8 ea 62 12 e0 0d  af 62 d4 69 f7 96 5a c0  |....b....b.i..Z.|
-00000340  97 d3 bb b0 a3 f7 3f                              |......?|
+00000200  16 03 03 00 86 10 00 00  82 00 80 98 61 16 34 c4  |............a.4.|
+00000210  c6 0a 47 c1 de 87 b1 b7  70 1b 24 8d 7e 35 90 35  |..G.....p.$.~5.5|
+00000220  f7 a5 6f c7 c9 91 ad 46  4c 50 e5 7e 61 7c 49 66  |..o....FLP.~a|If|
+00000230  e9 fe 1e 2c 30 fa 22 03  36 8f 44 27 a7 d2 14 84  |...,0.".6.D'....|
+00000240  d0 1f 21 ca 40 35 d1 7d  31 3f e1 73 de 69 bc da  |..!. at 5.}1?.s.i..|
+00000250  a5 96 8a b5 50 2b 4b 87  5a b3 fb e1 11 0a 29 59  |....P+K.Z.....)Y|
+00000260  13 2e e3 c2 05 d3 23 e8  09 0c 42 f6 8e 26 67 89  |......#...B..&g.|
+00000270  24 0f 08 2f 3d 24 2b 0c  a2 98 38 02 5c 95 9f ce  |$../=$+...8.\...|
+00000280  e3 75 ba 05 b5 f8 f0 07  e9 a1 44 16 03 03 00 88  |.u........D.....|
+00000290  0f 00 00 84 04 01 00 80  04 c0 bc 4b 23 59 ed 26  |...........K#Y.&|
+000002a0  8d 90 35 da 5b 55 88 e7  12 10 7b d7 1c 27 d1 c4  |..5.[U....{..'..|
+000002b0  d8 1b e2 e7 54 ad a4 be  00 6b 5b 61 2d ec 97 0c  |....T....k[a-...|
+000002c0  a5 9b ae ab 13 fa 94 53  1c 65 28 21 7d b5 c5 be  |.......S.e(!}...|
+000002d0  22 62 91 78 fc e3 de 84  5c 4e 0d f5 73 5e 20 49  |"b.x....\N..s^ I|
+000002e0  5a e2 f9 d3 2f 36 23 91  31 5b ee c7 0b 6f b3 35  |Z.../6#.1[...o.5|
+000002f0  2f 8a 51 84 3c fe 78 34  1f 8c 68 d3 fc 4f c6 5e  |/.Q.<.x4..h..O.^|
+00000300  7b fe b2 81 79 91 37 ee  7f f1 9b a4 88 5f 1b 44  |{...y.7......_.D|
+00000310  dc e9 36 bb d1 45 bb 1f  14 03 03 00 01 01 16 03  |..6..E..........|
+00000320  03 00 24 12 e7 8a 31 36  26 9f fe 45 95 cf 41 56  |..$...16&..E..AV|
+00000330  b4 69 ef e4 22 14 5a 4d  c8 79 a7 18 7b 68 a8 02  |.i..".ZM.y..{h..|
+00000340  75 ea 42 fe c4 a1 32                              |u.B...2|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 24 cd 20 85 1e 74  |..........$. ..t|
-00000010  18 b2 71 48 d5 10 61 c6  b0 18 26 83 c2 7f f1 b1  |..qH..a...&.....|
-00000020  2f b5 35 d0 47 a8 99 9a  9a a5 62 64 fb f9 29 17  |/.5.G.....bd..).|
-00000030  03 03 00 21 22 7b ed 61  e3 9b 6d 98 b9 23 98 e3  |...!"{.a..m..#..|
-00000040  55 11 b8 0f 7e 2b e1 c1  d4 f1 83 79 c3 f8 03 f0  |U...~+.....y....|
-00000050  02 5c 61 24 d7 15 03 03  00 16 14 2b a3 5a 56 f0  |.\a$.......+.ZV.|
-00000060  92 da d0 e6 32 91 d8 30  7a b4 d0 a2 93 f5 01 ea  |....2..0z.......|
+00000000  14 03 03 00 01 01 16 03  03 00 24 ae 6d 7b ac b6  |..........$.m{..|
+00000010  62 5c 40 65 6b 0e 5c 12  68 61 14 90 54 3e 24 78  |b\@ek.\.ha..T>$x|
+00000020  be 85 17 a0 9b de a0 00  e9 80 1b a9 0f e4 d7 17  |................|
+00000030  03 03 00 21 86 06 17 6b  62 02 a7 a0 71 fe c0 e4  |...!...kb...q...|
+00000040  44 00 54 dd cc a9 70 cf  bc 92 0d 40 07 62 f5 39  |D.T...p.... at .b.9|
+00000050  2a 30 ab 7f cd 15 03 03  00 16 6f 8d c9 d4 62 02  |*0........o...b.|
+00000060  da 64 4c 89 32 86 9f 29  24 05 ed cc 77 9d e5 55  |.dL.2..)$...w..U|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven b/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven
index 562fe1a..5de6dd8 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven
+++ b/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven
@@ -1,81 +1,76 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 5c 01 00 00  58 03 03 52 cc 57 59 1b  |....\...X..R.WY.|
-00000010  08 fe f7 8a bf 07 84 2b  60 a6 13 2d 15 13 f8 b6  |.......+`..-....|
-00000020  d4 b6 3b f2 7a 98 ff 32  a0 68 7c 00 00 04 00 05  |..;.z..2.h|.....|
-00000030  00 ff 01 00 00 2b 00 0d  00 22 00 20 06 01 06 02  |.....+...". ....|
+00000000  16 03 01 00 5a 01 00 00  56 03 03 52 b6 c5 b4 e3  |....Z...V..R....|
+00000010  35 ce 4e b2 9c e0 38 09  e7 fe 00 a2 1a 0a 43 eb  |5.N...8.......C.|
+00000020  df 98 6a 34 71 f9 d0 f8  5d e7 5e 00 00 04 00 05  |..j4q...].^.....|
+00000030  00 ff 01 00 00 29 00 0d  00 20 00 1e 06 01 06 02  |.....)... ......|
 00000040  06 03 05 01 05 02 05 03  04 01 04 02 04 03 03 01  |................|
-00000050  03 02 03 03 02 01 02 02  02 03 01 01 00 0f 00 01  |................|
-00000060  01                                                |.|
+00000050  03 02 03 03 02 01 02 02  02 03 00 0f 00 01 01     |...............|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
 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 05 00 00  |................|
-00000030  05 ff 01 00 01 00 16 03  03 02 be 0b 00 02 ba 00  |................|
-00000040  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
-00000050  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
-00000060  09 2a 86 48 86 f7 0d 01  01 05 05 00 30 45 31 0b  |.*.H........0E1.|
-00000070  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
-00000080  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
-00000090  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
-000000a0  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
-000000b0  4c 74 64 30 1e 17 0d 31  30 30 34 32 34 30 39 30  |Ltd0...100424090|
-000000c0  39 33 38 5a 17 0d 31 31  30 34 32 34 30 39 30 39  |938Z..1104240909|
-000000d0  33 38 5a 30 45 31 0b 30  09 06 03 55 04 06 13 02  |38Z0E1.0...U....|
-000000e0  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
-000000f0  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
-00000100  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
-00000110  74 73 20 50 74 79 20 4c  74 64 30 81 9f 30 0d 06  |ts Pty Ltd0..0..|
-00000120  09 2a 86 48 86 f7 0d 01  01 01 05 00 03 81 8d 00  |.*.H............|
-00000130  30 81 89 02 81 81 00 bb  79 d6 f5 17 b5 e5 bf 46  |0.......y......F|
-00000140  10 d0 dc 69 be e6 2b 07  43 5a d0 03 2d 8a 7a 43  |...i..+.CZ..-.zC|
-00000150  85 b7 14 52 e7 a5 65 4c  2c 78 b8 23 8c b5 b4 82  |...R..eL,x.#....|
-00000160  e5 de 1f 95 3b 7e 62 a5  2c a5 33 d6 fe 12 5c 7a  |....;~b.,.3...\z|
-00000170  56 fc f5 06 bf fa 58 7b  26 3f b5 cd 04 d3 d0 c9  |V.....X{&?......|
-00000180  21 96 4a c7 f4 54 9f 5a  bf ef 42 71 00 fe 18 99  |!.J..T.Z..Bq....|
-00000190  07 7f 7e 88 7d 7d f1 04  39 c4 a2 2e db 51 c9 7c  |..~.}}..9....Q.||
-000001a0  e3 c0 4c 3b 32 66 01 cf  af b1 1d b8 71 9a 1d db  |..L;2f......q...|
-000001b0  db 89 6b ae da 2d 79 02  03 01 00 01 a3 81 a7 30  |..k..-y........0|
-000001c0  81 a4 30 1d 06 03 55 1d  0e 04 16 04 14 b1 ad e2  |..0...U.........|
-000001d0  85 5a cf cb 28 db 69 ce  23 69 de d3 26 8e 18 88  |.Z..(.i.#i..&...|
-000001e0  39 30 75 06 03 55 1d 23  04 6e 30 6c 80 14 b1 ad  |90u..U.#.n0l....|
-000001f0  e2 85 5a cf cb 28 db 69  ce 23 69 de d3 26 8e 18  |..Z..(.i.#i..&..|
-00000200  88 39 a1 49 a4 47 30 45  31 0b 30 09 06 03 55 04  |.9.I.G0E1.0...U.|
-00000210  06 13 02 41 55 31 13 30  11 06 03 55 04 08 13 0a  |...AU1.0...U....|
-00000220  53 6f 6d 65 2d 53 74 61  74 65 31 21 30 1f 06 03  |Some-State1!0...|
-00000230  55 04 0a 13 18 49 6e 74  65 72 6e 65 74 20 57 69  |U....Internet Wi|
-00000240  64 67 69 74 73 20 50 74  79 20 4c 74 64 82 09 00  |dgits Pty Ltd...|
-00000250  85 b0 bb a4 8a 7f b8 ca  30 0c 06 03 55 1d 13 04  |........0...U...|
-00000260  05 30 03 01 01 ff 30 0d  06 09 2a 86 48 86 f7 0d  |.0....0...*.H...|
-00000270  01 01 05 05 00 03 81 81  00 08 6c 45 24 c7 6b b1  |..........lE$.k.|
-00000280  59 ab 0c 52 cc f2 b0 14  d7 87 9d 7a 64 75 b5 5a  |Y..R.......zdu.Z|
-00000290  95 66 e4 c5 2b 8e ae 12  66 1f eb 4f 38 b3 6e 60  |.f..+...f..O8.n`|
-000002a0  d3 92 fd f7 41 08 b5 25  13 b1 18 7a 24 fb 30 1d  |....A..%...z$.0.|
-000002b0  ba ed 98 b9 17 ec e7 d7  31 59 db 95 d3 1d 78 ea  |........1Y....x.|
-000002c0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
-000002d0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
-000002e0  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
-000002f0  6e 38 50 29 6c 90 a7 bd  d9 16 03 03 00 0f 0d 00  |n8P)l...........|
-00000300  00 0b 02 01 40 00 04 04  01 04 03 00 00 16 03 03  |.... at ...........|
-00000310  00 04 0e 00 00 00                                 |......|
+00000030  05 ff 01 00 01 00 16 03  03 02 71 0b 00 02 6d 00  |..........q...m.|
+00000040  02 6a 00 02 67 30 82 02  63 30 82 01 cc a0 03 02  |.j..g0..c0......|
+00000050  01 02 02 09 00 a2 73 00  0c 81 00 cb f3 30 0d 06  |......s......0..|
+00000060  09 2a 86 48 86 f7 0d 01  01 0b 05 00 30 2b 31 17  |.*.H........0+1.|
+00000070  30 15 06 03 55 04 0a 13  0e 47 6f 6f 67 6c 65 20  |0...U....Google |
+00000080  54 45 53 54 49 4e 47 31  10 30 0e 06 03 55 04 03  |TESTING1.0...U..|
+00000090  13 07 47 6f 20 52 6f 6f  74 30 1e 17 0d 31 35 30  |..Go Root0...150|
+000000a0  31 30 31 30 30 30 30 30  30 5a 17 0d 32 35 30 31  |101000000Z..2501|
+000000b0  30 31 30 30 30 30 30 30  5a 30 26 31 17 30 15 06  |01000000Z0&1.0..|
+000000c0  03 55 04 0a 13 0e 47 6f  6f 67 6c 65 20 54 45 53  |.U....Google TES|
+000000d0  54 49 4e 47 31 0b 30 09  06 03 55 04 03 13 02 47  |TING1.0...U....G|
+000000e0  6f 30 81 9f 30 0d 06 09  2a 86 48 86 f7 0d 01 01  |o0..0...*.H.....|
+000000f0  01 05 00 03 81 8d 00 30  81 89 02 81 81 00 af 87  |.......0........|
+00000100  88 f6 20 1b 95 65 6c 14  ab 44 05 af 3b 45 14 e3  |.. ..el..D..;E..|
+00000110  b7 6d fd 00 63 4d 95 7f  fe 6a 62 35 86 c0 4a f9  |.m..cM...jb5..J.|
+00000120  18 7c f6 aa 25 5e 7a 64  31 66 00 ba f4 8e 92 af  |.|..%^zd1f......|
+00000130  c7 6b d8 76 d4 f3 5f 41  cb 6e 56 15 97 1b 97 c1  |.k.v.._A.nV.....|
+00000140  3c 12 39 21 66 3d 2b 16  d1 bc db 1c c0 a7 da b7  |<.9!f=+.........|
+00000150  ca ad ba da cb d5 21 50  ec de 8d ab d1 6b 81 4b  |......!P.....k.K|
+00000160  89 02 f3 c4 be c1 6c 89  b1 44 84 bd 21 d1 04 7d  |......l..D..!..}|
+00000170  9d 16 4d f9 82 15 f6 ef  fa d6 09 47 f2 fb 02 03  |..M........G....|
+00000180  01 00 01 a3 81 93 30 81  90 30 0e 06 03 55 1d 0f  |......0..0...U..|
+00000190  01 01 ff 04 04 03 02 05  a0 30 1d 06 03 55 1d 25  |.........0...U.%|
+000001a0  04 16 30 14 06 08 2b 06  01 05 05 07 03 01 06 08  |..0...+.........|
+000001b0  2b 06 01 05 05 07 03 02  30 0c 06 03 55 1d 13 01  |+.......0...U...|
+000001c0  01 ff 04 02 30 00 30 19  06 03 55 1d 0e 04 12 04  |....0.0...U.....|
+000001d0  10 12 50 8d 89 6f 1b d1  dc 54 4d 6e cb 69 5e 06  |..P..o...TMn.i^.|
+000001e0  f4 30 1b 06 03 55 1d 23  04 14 30 12 80 10 bf 3d  |.0...U.#..0....=|
+000001f0  b6 a9 66 f2 b8 40 cf ea  b4 03 78 48 1a 41 30 19  |..f.. at ....xH.A0.|
+00000200  06 03 55 1d 11 04 12 30  10 82 0e 65 78 61 6d 70  |..U....0...examp|
+00000210  6c 65 2e 67 6f 6c 61 6e  67 30 0d 06 09 2a 86 48  |le.golang0...*.H|
+00000220  86 f7 0d 01 01 0b 05 00  03 81 81 00 92 7c af 91  |.............|..|
+00000230  55 12 18 96 59 31 a6 48  40 d5 2d d5 ee bb 02 a0  |U...Y1.H at .-.....|
+00000240  f5 c2 1e 7c 9b b3 30 7d  3c dc 76 da 4f 3d c0 fa  |...|..0}<.v.O=..|
+00000250  ae 2d 33 24 6b 03 7b 1b  67 59 11 21 b5 11 bc 77  |.-3$k.{.gY.!...w|
+00000260  b9 d9 e0 6e a8 2d 2e 35  fa 64 5f 22 3e 63 10 6b  |...n.-.5.d_">c.k|
+00000270  be ff 14 86 6d 0d f0 15  31 a8 14 38 1e 3b 84 87  |....m...1..8.;..|
+00000280  2c cb 98 ed 51 76 b9 b1  4f dd db 9b 84 04 86 40  |,...Qv..O......@|
+00000290  fa 51 dd ba b4 8d eb e3  46 de 46 b9 4f 86 c7 f9  |.Q......F.F.O...|
+000002a0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 03 00  |..A4......9.....|
+000002b0  17 0d 00 00 13 02 01 40  00 0c 04 01 04 03 05 01  |....... at ........|
+000002c0  05 03 02 01 02 03 00 00  16 03 03 00 04 0e 00 00  |................|
+000002d0  00                                                |.|
 >>> Flow 3 (client to server)
 00000000  16 03 03 00 07 0b 00 00  03 00 00 00 16 03 03 00  |................|
-00000010  86 10 00 00 82 00 80 6b  51 48 d3 18 7d 30 e0 0c  |.......kQH..}0..|
-00000020  20 8d f3 e4 39 47 30 0e  a5 85 79 f9 8b 11 50 9e  | ...9G0...y...P.|
-00000030  81 71 5c 26 c6 bb cb aa  d5 00 d1 89 79 b1 77 2d  |.q\&........y.w-|
-00000040  eb 9b 86 7c 52 c6 f7 b7  10 b0 b6 94 22 51 b8 12  |...|R......."Q..|
-00000050  3c 09 35 8e 1b cc f4 3b  b7 b8 78 ab 89 59 41 49  |<.5....;..x..YAI|
-00000060  21 31 eb f0 f8 94 63 3d  e6 96 8f b6 63 95 05 dd  |!1....c=....c...|
-00000070  46 b3 00 8a d6 83 75 99  1b 5a 48 0a 23 b5 10 c1  |F.....u..ZH.#...|
-00000080  95 b5 bc 15 72 b5 f5 a0  62 e2 1d c0 ff d2 87 a5  |....r...b.......|
-00000090  97 5c 33 49 a7 26 35 14  03 03 00 01 01 16 03 03  |.\3I.&5.........|
-000000a0  00 24 61 38 1f 9d fb d9  65 2e 02 07 fb be f9 85  |.$a8....e.......|
-000000b0  8d 15 34 c0 d1 0e 4e 10  3c 25 60 2f ac 04 21 66  |..4...N.<%`/..!f|
-000000c0  04 9d 9a 60 31 72                                 |...`1r|
+00000010  86 10 00 00 82 00 80 2e  8e cb 6c f5 db 45 5b f0  |..........l..E[.|
+00000020  67 7d b1 ac 87 c2 d6 e9  ea 37 40 15 2a ea a1 af  |g}.......7 at .*...|
+00000030  ed 71 68 18 9c 6c 84 20  52 3e 38 94 8e d9 cd b3  |.qh..l. R>8.....|
+00000040  15 73 8b db d7 ff 1d 8a  ed a6 f4 00 7d d0 0a 1e  |.s..........}...|
+00000050  9a 1b 5c 59 f6 a0 29 62  03 a1 c6 bf 8a 57 14 06  |..\Y..)b.....W..|
+00000060  9a e8 03 72 bc cd cd 6f  6d e2 ce a8 41 7a f0 65  |...r...om...Az.e|
+00000070  42 0c 7b dd 93 d7 ab 37  f8 2a b3 c4 72 95 61 e1  |B.{....7.*..r.a.|
+00000080  75 98 f5 99 69 ef 0a d0  00 41 0f 05 87 13 d3 7d  |u...i....A.....}|
+00000090  ba 74 34 43 9a 6c d0 14  03 03 00 01 01 16 03 03  |.t4C.l..........|
+000000a0  00 24 87 7e 7d 48 ca 17  9c ad 30 b8 6a 05 2f d3  |.$.~}H....0.j./.|
+000000b0  fc 18 2e df fd f5 0e 38  c3 06 57 4c 27 66 02 af  |.......8..WL'f..|
+000000c0  6d 78 4d 2e b6 dc                                 |mxM...|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 24 fe 0e 3e 84 af  |..........$..>..|
-00000010  e5 6b 10 ed 41 9c 2b e0  ba e0 2b 53 61 36 1b 40  |.k..A.+...+Sa6.@|
-00000020  35 de 3a c7 c3 5c df 74  67 f7 05 74 84 f5 e1 17  |5.:..\.tg..t....|
-00000030  03 03 00 21 d3 8d 81 85  b7 1f 30 bd 89 33 f9 81  |...!......0..3..|
-00000040  89 f7 af d1 be b0 c1 46  e3 df 32 f6 dc 2f 4d 82  |.......F..2../M.|
-00000050  0a 84 9f 5b 03 15 03 03  00 16 13 af 37 91 82 67  |...[........7..g|
-00000060  b0 7c 5e 0e ec 8e cc 31  a0 ea a5 72 a4 2b 0b 73  |.|^....1...r.+.s|
+00000000  14 03 03 00 01 01 16 03  03 00 24 cf ee f6 28 ea  |..........$...(.|
+00000010  df e2 7e 9a 75 e0 f9 b4  c4 c2 57 3a 54 26 db 7f  |..~.u.....W:T&..|
+00000020  c4 19 6d b6 d6 c7 b1 05  7f 92 21 9e 51 1a 0a 17  |..m.......!.Q...|
+00000030  03 03 00 21 87 48 77 c4  eb 7c 5d 13 3b f4 8d 08  |...!.Hw..|].;...|
+00000040  f9 35 c3 d2 e5 c0 8c ea  15 c9 2d c5 e0 70 fd 7c  |.5........-..p.||
+00000050  de 93 4f 8c 8d 15 03 03  00 16 d4 8a d5 6a fc db  |..O..........j..|
+00000060  c7 1d 1f 76 64 b9 31 68  72 cc 58 de 9f 2a a6 45  |...vd.1hr.X..*.E|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES b/src/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES
index aacbb86..3b7238a 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES
+++ b/src/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES
@@ -1,15 +1,15 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 9c 01 00 00  98 03 03 53 04 f0 f9 09  |...........S....|
-00000010  13 56 01 37 84 b1 32 59  4c 73 b1 8e bb 02 1a 32  |.V.7..2YLs.....2|
-00000020  db ab 8c e6 ed ad 7f 52  9a 59 39 00 00 04 c0 0a  |.......R.Y9.....|
-00000030  00 ff 01 00 00 6b 00 0b  00 04 03 00 01 02 00 0a  |.....k..........|
-00000040  00 34 00 32 00 0e 00 0d  00 19 00 0b 00 0c 00 18  |.4.2............|
-00000050  00 09 00 0a 00 16 00 17  00 08 00 06 00 07 00 14  |................|
-00000060  00 15 00 04 00 05 00 12  00 13 00 01 00 02 00 03  |................|
-00000070  00 0f 00 10 00 11 00 0d  00 22 00 20 06 01 06 02  |.........". ....|
-00000080  06 03 05 01 05 02 05 03  04 01 04 02 04 03 03 01  |................|
-00000090  03 02 03 03 02 01 02 02  02 03 01 01 00 0f 00 01  |................|
-000000a0  01                                                |.|
+00000000  16 03 01 00 a1 01 00 00  9d 03 03 0f b7 07 5f c7  |.............._.|
+00000010  18 b8 39 6d 92 b3 90 ed  bf 5c 48 7c 6a 56 ee e9  |..9m.....\H|jV..|
+00000020  7a 5b 5f 71 a4 f0 7f 47  57 73 78 00 00 04 c0 0a  |z[_q...GWsx.....|
+00000030  00 ff 02 01 00 00 6f 00  0b 00 04 03 00 01 02 00  |......o.........|
+00000040  0a 00 3a 00 38 00 0e 00  0d 00 19 00 1c 00 0b 00  |..:.8...........|
+00000050  0c 00 1b 00 18 00 09 00  0a 00 1a 00 16 00 17 00  |................|
+00000060  08 00 06 00 07 00 14 00  15 00 04 00 05 00 12 00  |................|
+00000070  13 00 01 00 02 00 03 00  0f 00 10 00 11 00 0d 00  |................|
+00000080  20 00 1e 06 01 06 02 06  03 05 01 05 02 05 03 04  | ...............|
+00000090  01 04 02 04 03 03 01 03  02 03 03 02 01 02 02 02  |................|
+000000a0  03 00 0f 00 01 01                                 |......|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
@@ -52,38 +52,38 @@
 00000260  75 71 b5 e5 54 5b 12 2e  8f 09 67 fd a7 24 20 3e  |uq..T[....g..$ >|
 00000270  b2 56 1c ce 97 28 5e f8  2b 2d 4f 9e f1 07 9f 6c  |.V...(^.+-O....l|
 00000280  4b 5b 83 56 e2 32 42 e9  58 b6 d7 49 a6 b5 68 1a  |K[.V.2B.X..I..h.|
-00000290  41 03 56 6b dc 5a 89 04  03 00 8b 30 81 88 02 42  |A.Vk.Z.....0...B|
-000002a0  00 c6 85 8e 06 b7 04 04  e9 cd 9e 3e cb 66 23 95  |...........>.f#.|
-000002b0  b4 42 9c 64 81 39 05 3f  b5 21 f8 28 af 60 6b 4d  |.B.d.9.?.!.(.`kM|
-000002c0  3d ba a1 4b 5e 77 ef e7  59 28 fe 1d c1 27 a2 ff  |=..K^w..Y(...'..|
-000002d0  a8 de 33 48 b3 c1 85 6a  42 9b f9 7e 7e 31 c2 e5  |..3H...jB..~~1..|
-000002e0  bd 66 02 42 00 ad 7d 06  35 ab ec 8d ac d4 ba 1b  |.f.B..}.5.......|
-000002f0  49 5e 05 5f f0 97 93 82  b8 2b 8d 91 98 63 8e b4  |I^._.....+...c..|
-00000300  14 62 db 1e c9 2c 13 ae  b7 d3 17 38 23 2f f6 7f  |.b...,.....8#/..|
-00000310  0c 4d d3 33 d2 79 d1 77  ee cb b1 c2 fc 34 b8 69  |.M.3.y.w.....4.i|
-00000320  f9 10 8b 61 89 85 16 03  03 00 04 0e 00 00 00     |...a...........|
+00000290  41 03 56 6b dc 5a 89 05  03 00 8b 30 81 88 02 42  |A.Vk.Z.....0...B|
+000002a0  00 d3 cf 21 cd 3c 2e 11  f5 f8 1d c8 c1 57 4b f8  |...!.<.......WK.|
+000002b0  1a c0 2b 1d 47 0f 2d a5  ac a1 c8 83 5d 76 87 05  |..+.G.-.....]v..|
+000002c0  2b 0d 36 d5 57 9f b9 8a  a0 a2 94 67 6a cd 29 db  |+.6.W......gj.).|
+000002d0  04 b0 6b 06 d9 f7 17 9f  1c 60 92 e7 4e 50 48 7f  |..k......`..NPH.|
+000002e0  dc d0 02 42 01 56 fd 38  bd 05 a5 16 6d 91 d1 ce  |...B.V.8....m...|
+000002f0  bb 8c 45 b2 76 2f 92 9c  8b 94 57 7d de 53 8b 7b  |..E.v/....W}.S.{|
+00000300  80 26 6c 4a 43 4b a6 c9  46 49 08 ab c7 57 f3 d9  |.&lJCK..FI...W..|
+00000310  fa 1d 55 fe 91 de 8a 0d  8b d1 44 96 87 85 cb 02  |..U.......D.....|
+00000320  76 9c 00 ad 5f b8 16 03  03 00 04 0e 00 00 00     |v..._..........|
 >>> Flow 3 (client to server)
-00000000  16 03 03 00 46 10 00 00  42 41 04 dd 22 68 a1 4e  |....F...BA.."h.N|
-00000010  04 1b 47 f9 c5 7d 04 1d  d8 fe 84 fa be 31 2e a7  |..G..}.......1..|
-00000020  f8 e5 b8 14 92 44 99 11  0e 34 97 fc e5 b1 91 cf  |.....D...4......|
-00000030  a4 d1 3f b4 71 94 c6 06  16 f0 98 c0 3e 05 f9 2f  |..?.q.......>../|
-00000040  0a 97 78 3d ef dc fa a2  d7 ee 7d 14 03 03 00 01  |..x=......}.....|
-00000050  01 16 03 03 00 40 90 bf  7f e9 c9 6e d1 80 f5 12  |..... at .....n....|
-00000060  6d c5 b7 c5 15 4b 18 a5  d3 18 1e f8 8c 4d 7e 6d  |m....K.......M~m|
-00000070  03 60 29 7c 45 7c b2 ca  8c 07 71 70 aa 23 fa 6e  |.`)|E|....qp.#.n|
-00000080  d9 0b 0a 32 4c 9e e5 00  f9 19 9b b6 8d dc d3 67  |...2L..........g|
-00000090  3d 0f bb b8 4b 9e                                 |=...K.|
+00000000  16 03 03 00 46 10 00 00  42 41 04 0b dc ea 22 05  |....F...BA....".|
+00000010  44 c2 09 47 65 31 3b 0b  e1 05 1a 87 8c 2d 3b 56  |D..Ge1;......-;V|
+00000020  49 34 27 3e d6 3b 93 e2  12 7f 5d 7b dc 85 c8 96  |I4'>.;....]{....|
+00000030  4c 8c f9 18 6f 15 cf db  6e 2c 14 6a c9 dd 1c 70  |L...o...n,.j...p|
+00000040  7e 05 c4 17 71 76 df 10  ee 8c b1 14 03 03 00 01  |~...qv..........|
+00000050  01 16 03 03 00 40 ff 12  88 36 3c 00 17 d1 b9 41  |..... at ...6<....A|
+00000060  7a 12 25 94 4c 90 65 62  d8 09 ab f9 b4 ee c3 de  |z.%.L.eb........|
+00000070  46 2f cb ee 18 76 4f 76  8e dd 89 fc 7a 21 3b 5f  |F/...vOv....z!;_|
+00000080  ff ac 1c 03 aa be 96 82  82 ea 2e 22 2a 80 b3 86  |..........."*...|
+00000090  38 e4 4d 90 91 46                                 |8.M..F|
 >>> Flow 4 (server to client)
 00000000  14 03 03 00 01 01 16 03  03 00 40 00 00 00 00 00  |.......... at .....|
-00000010  00 00 00 00 00 00 00 00  00 00 00 a1 6e e5 d1 ca  |............n...|
-00000020  03 f4 77 dc ec ee 5d f0  22 5e 7f 55 1a 8d ad 45  |..w...]."^.U...E|
-00000030  09 f1 3b b2 61 36 dc 3d  2a 1e 1f e5 a7 84 76 a9  |..;.a6.=*.....v.|
-00000040  41 5b 86 03 ac 22 18 20  9b a9 29 17 03 03 00 40  |A[...". ..)....@|
+00000010  00 00 00 00 00 00 00 00  00 00 00 e5 c1 f0 6a db  |..............j.|
+00000020  05 98 ed 33 94 73 7f 13  7f 78 17 7f d1 9e c5 a7  |...3.s...x......|
+00000030  62 7f 85 14 2c 7d b2 8e  ef 75 a9 df 92 cc 22 20  |b...,}...u...." |
+00000040  66 08 85 22 d3 ea 5c 4c  4c c8 d7 17 03 03 00 40  |f.."..\LL......@|
 00000050  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000060  f5 cb 28 1e b5 bc 82 7f  82 38 54 14 e8 b9 6d 3b  |..(......8T...m;|
-00000070  bc 99 d6 0e f9 00 96 99  a8 92 2e 86 9d 62 4e 90  |.............bN.|
-00000080  27 52 58 45 20 93 90 a1  f3 a8 89 2b e7 21 24 16  |'RXE ......+.!$.|
+00000060  f2 20 07 d2 13 ca ed 01  c9 7b 91 14 01 2c 08 f5  |. .......{...,..|
+00000070  8a 69 94 bc 19 9a d9 65  6b 15 04 b4 45 17 ec 6f  |.i.....ek...E..o|
+00000080  85 de 31 dc a2 de 8b 4d  53 57 66 4a 29 21 5a 20  |..1....MSWfJ)!Z |
 00000090  15 03 03 00 30 00 00 00  00 00 00 00 00 00 00 00  |....0...........|
-000000a0  00 00 00 00 00 a8 2a ab  8f b0 ce 49 8b fd a5 c9  |......*....I....|
-000000b0  11 b2 04 83 18 f3 1d 6c  82 34 1d df dd 2f 45 3b  |.......l.4.../E;|
-000000c0  27 8a 0f 16 69                                    |'...i|
+000000a0  00 00 00 00 00 55 15 f7  89 8d 75 57 7e 92 db ec  |.....U....uW~...|
+000000b0  32 ec 07 5c 83 32 36 59  61 f1 9d a6 7a eb 76 c1  |2..\.26Ya...z.v.|
+000000c0  c7 96 3f 4d 0a                                    |..?M.|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-IssueTicket b/src/crypto/tls/testdata/Server-TLSv12-IssueTicket
index e3e62f2..20a0731 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-IssueTicket
+++ b/src/crypto/tls/testdata/Server-TLSv12-IssueTicket
@@ -1,87 +1,83 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 60 01 00 00  5c 03 03 52 cc 57 59 7e  |....`...\..R.WY~|
-00000010  43 5c 3b fd 50 ab 61 3f  64 a4 f9 bd ba 8c 28 e1  |C\;.P.a?d.....(.|
-00000020  f9 a1 45 7e 48 9e 62 af  25 de 0e 00 00 04 00 05  |..E~H.b.%.......|
-00000030  00 ff 01 00 00 2f 00 23  00 00 00 0d 00 22 00 20  |...../.#.....". |
+00000000  16 03 01 00 5e 01 00 00  5a 03 03 f0 0a 06 d0 65  |....^...Z......e|
+00000010  1c c3 90 ac dc 61 42 e5  b8 a9 17 fb e7 c3 1e bd  |.....aB.........|
+00000020  d9 09 5a 63 71 e2 f9 58  db 26 6e 00 00 04 00 05  |..Zcq..X.&n.....|
+00000030  00 ff 01 00 00 2d 00 23  00 00 00 0d 00 20 00 1e  |.....-.#..... ..|
 00000040  06 01 06 02 06 03 05 01  05 02 05 03 04 01 04 02  |................|
-00000050  04 03 03 01 03 02 03 03  02 01 02 02 02 03 01 01  |................|
-00000060  00 0f 00 01 01                                    |.....|
+00000050  04 03 03 01 03 02 03 03  02 01 02 02 02 03 00 0f  |................|
+00000060  00 01 01                                          |...|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 35 02 00 00  31 03 03 00 00 00 00 00  |....5...1.......|
 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 05 00 00  |................|
-00000030  09 00 23 00 00 ff 01 00  01 00 16 03 03 02 be 0b  |..#.............|
-00000040  00 02 ba 00 02 b7 00 02  b4 30 82 02 b0 30 82 02  |.........0...0..|
-00000050  19 a0 03 02 01 02 02 09  00 85 b0 bb a4 8a 7f b8  |................|
-00000060  ca 30 0d 06 09 2a 86 48  86 f7 0d 01 01 05 05 00  |.0...*.H........|
-00000070  30 45 31 0b 30 09 06 03  55 04 06 13 02 41 55 31  |0E1.0...U....AU1|
-00000080  13 30 11 06 03 55 04 08  13 0a 53 6f 6d 65 2d 53  |.0...U....Some-S|
-00000090  74 61 74 65 31 21 30 1f  06 03 55 04 0a 13 18 49  |tate1!0...U....I|
-000000a0  6e 74 65 72 6e 65 74 20  57 69 64 67 69 74 73 20  |nternet Widgits |
-000000b0  50 74 79 20 4c 74 64 30  1e 17 0d 31 30 30 34 32  |Pty Ltd0...10042|
-000000c0  34 30 39 30 39 33 38 5a  17 0d 31 31 30 34 32 34  |4090938Z..110424|
-000000d0  30 39 30 39 33 38 5a 30  45 31 0b 30 09 06 03 55  |090938Z0E1.0...U|
-000000e0  04 06 13 02 41 55 31 13  30 11 06 03 55 04 08 13  |....AU1.0...U...|
-000000f0  0a 53 6f 6d 65 2d 53 74  61 74 65 31 21 30 1f 06  |.Some-State1!0..|
-00000100  03 55 04 0a 13 18 49 6e  74 65 72 6e 65 74 20 57  |.U....Internet W|
-00000110  69 64 67 69 74 73 20 50  74 79 20 4c 74 64 30 81  |idgits Pty Ltd0.|
-00000120  9f 30 0d 06 09 2a 86 48  86 f7 0d 01 01 01 05 00  |.0...*.H........|
-00000130  03 81 8d 00 30 81 89 02  81 81 00 bb 79 d6 f5 17  |....0.......y...|
-00000140  b5 e5 bf 46 10 d0 dc 69  be e6 2b 07 43 5a d0 03  |...F...i..+.CZ..|
-00000150  2d 8a 7a 43 85 b7 14 52  e7 a5 65 4c 2c 78 b8 23  |-.zC...R..eL,x.#|
-00000160  8c b5 b4 82 e5 de 1f 95  3b 7e 62 a5 2c a5 33 d6  |........;~b.,.3.|
-00000170  fe 12 5c 7a 56 fc f5 06  bf fa 58 7b 26 3f b5 cd  |..\zV.....X{&?..|
-00000180  04 d3 d0 c9 21 96 4a c7  f4 54 9f 5a bf ef 42 71  |....!.J..T.Z..Bq|
-00000190  00 fe 18 99 07 7f 7e 88  7d 7d f1 04 39 c4 a2 2e  |......~.}}..9...|
-000001a0  db 51 c9 7c e3 c0 4c 3b  32 66 01 cf af b1 1d b8  |.Q.|..L;2f......|
-000001b0  71 9a 1d db db 89 6b ae  da 2d 79 02 03 01 00 01  |q.....k..-y.....|
-000001c0  a3 81 a7 30 81 a4 30 1d  06 03 55 1d 0e 04 16 04  |...0..0...U.....|
-000001d0  14 b1 ad e2 85 5a cf cb  28 db 69 ce 23 69 de d3  |.....Z..(.i.#i..|
-000001e0  26 8e 18 88 39 30 75 06  03 55 1d 23 04 6e 30 6c  |&...90u..U.#.n0l|
-000001f0  80 14 b1 ad e2 85 5a cf  cb 28 db 69 ce 23 69 de  |......Z..(.i.#i.|
-00000200  d3 26 8e 18 88 39 a1 49  a4 47 30 45 31 0b 30 09  |.&...9.I.G0E1.0.|
-00000210  06 03 55 04 06 13 02 41  55 31 13 30 11 06 03 55  |..U....AU1.0...U|
-00000220  04 08 13 0a 53 6f 6d 65  2d 53 74 61 74 65 31 21  |....Some-State1!|
-00000230  30 1f 06 03 55 04 0a 13  18 49 6e 74 65 72 6e 65  |0...U....Interne|
-00000240  74 20 57 69 64 67 69 74  73 20 50 74 79 20 4c 74  |t Widgits Pty Lt|
-00000250  64 82 09 00 85 b0 bb a4  8a 7f b8 ca 30 0c 06 03  |d...........0...|
-00000260  55 1d 13 04 05 30 03 01  01 ff 30 0d 06 09 2a 86  |U....0....0...*.|
-00000270  48 86 f7 0d 01 01 05 05  00 03 81 81 00 08 6c 45  |H.............lE|
-00000280  24 c7 6b b1 59 ab 0c 52  cc f2 b0 14 d7 87 9d 7a  |$.k.Y..R.......z|
-00000290  64 75 b5 5a 95 66 e4 c5  2b 8e ae 12 66 1f eb 4f  |du.Z.f..+...f..O|
-000002a0  38 b3 6e 60 d3 92 fd f7  41 08 b5 25 13 b1 18 7a  |8.n`....A..%...z|
-000002b0  24 fb 30 1d ba ed 98 b9  17 ec e7 d7 31 59 db 95  |$.0.........1Y..|
-000002c0  d3 1d 78 ea 50 56 5c d5  82 5a 2d 5a 5f 33 c4 b6  |..x.PV\..Z-Z_3..|
-000002d0  d8 c9 75 90 96 8c 0f 52  98 b5 cd 98 1f 89 20 5f  |..u....R...... _|
-000002e0  f2 a0 1c a3 1b 96 94 dd  a9 fd 57 e9 70 e8 26 6d  |..........W.p.&m|
-000002f0  71 99 9b 26 6e 38 50 29  6c 90 a7 bd d9 16 03 03  |q..&n8P)l.......|
-00000300  00 04 0e 00 00 00                                 |......|
+00000030  09 00 23 00 00 ff 01 00  01 00 16 03 03 02 71 0b  |..#...........q.|
+00000040  00 02 6d 00 02 6a 00 02  67 30 82 02 63 30 82 01  |..m..j..g0..c0..|
+00000050  cc a0 03 02 01 02 02 09  00 a2 73 00 0c 81 00 cb  |..........s.....|
+00000060  f3 30 0d 06 09 2a 86 48  86 f7 0d 01 01 0b 05 00  |.0...*.H........|
+00000070  30 2b 31 17 30 15 06 03  55 04 0a 13 0e 47 6f 6f  |0+1.0...U....Goo|
+00000080  67 6c 65 20 54 45 53 54  49 4e 47 31 10 30 0e 06  |gle TESTING1.0..|
+00000090  03 55 04 03 13 07 47 6f  20 52 6f 6f 74 30 1e 17  |.U....Go Root0..|
+000000a0  0d 31 35 30 31 30 31 30  30 30 30 30 30 5a 17 0d  |.150101000000Z..|
+000000b0  32 35 30 31 30 31 30 30  30 30 30 30 5a 30 26 31  |250101000000Z0&1|
+000000c0  17 30 15 06 03 55 04 0a  13 0e 47 6f 6f 67 6c 65  |.0...U....Google|
+000000d0  20 54 45 53 54 49 4e 47  31 0b 30 09 06 03 55 04  | TESTING1.0...U.|
+000000e0  03 13 02 47 6f 30 81 9f  30 0d 06 09 2a 86 48 86  |...Go0..0...*.H.|
+000000f0  f7 0d 01 01 01 05 00 03  81 8d 00 30 81 89 02 81  |...........0....|
+00000100  81 00 af 87 88 f6 20 1b  95 65 6c 14 ab 44 05 af  |...... ..el..D..|
+00000110  3b 45 14 e3 b7 6d fd 00  63 4d 95 7f fe 6a 62 35  |;E...m..cM...jb5|
+00000120  86 c0 4a f9 18 7c f6 aa  25 5e 7a 64 31 66 00 ba  |..J..|..%^zd1f..|
+00000130  f4 8e 92 af c7 6b d8 76  d4 f3 5f 41 cb 6e 56 15  |.....k.v.._A.nV.|
+00000140  97 1b 97 c1 3c 12 39 21  66 3d 2b 16 d1 bc db 1c  |....<.9!f=+.....|
+00000150  c0 a7 da b7 ca ad ba da  cb d5 21 50 ec de 8d ab  |..........!P....|
+00000160  d1 6b 81 4b 89 02 f3 c4  be c1 6c 89 b1 44 84 bd  |.k.K......l..D..|
+00000170  21 d1 04 7d 9d 16 4d f9  82 15 f6 ef fa d6 09 47  |!..}..M........G|
+00000180  f2 fb 02 03 01 00 01 a3  81 93 30 81 90 30 0e 06  |..........0..0..|
+00000190  03 55 1d 0f 01 01 ff 04  04 03 02 05 a0 30 1d 06  |.U...........0..|
+000001a0  03 55 1d 25 04 16 30 14  06 08 2b 06 01 05 05 07  |.U.%..0...+.....|
+000001b0  03 01 06 08 2b 06 01 05  05 07 03 02 30 0c 06 03  |....+.......0...|
+000001c0  55 1d 13 01 01 ff 04 02  30 00 30 19 06 03 55 1d  |U.......0.0...U.|
+000001d0  0e 04 12 04 10 12 50 8d  89 6f 1b d1 dc 54 4d 6e  |......P..o...TMn|
+000001e0  cb 69 5e 06 f4 30 1b 06  03 55 1d 23 04 14 30 12  |.i^..0...U.#..0.|
+000001f0  80 10 bf 3d b6 a9 66 f2  b8 40 cf ea b4 03 78 48  |...=..f.. at ....xH|
+00000200  1a 41 30 19 06 03 55 1d  11 04 12 30 10 82 0e 65  |.A0...U....0...e|
+00000210  78 61 6d 70 6c 65 2e 67  6f 6c 61 6e 67 30 0d 06  |xample.golang0..|
+00000220  09 2a 86 48 86 f7 0d 01  01 0b 05 00 03 81 81 00  |.*.H............|
+00000230  92 7c af 91 55 12 18 96  59 31 a6 48 40 d5 2d d5  |.|..U...Y1.H at .-.|
+00000240  ee bb 02 a0 f5 c2 1e 7c  9b b3 30 7d 3c dc 76 da  |.......|..0}<.v.|
+00000250  4f 3d c0 fa ae 2d 33 24  6b 03 7b 1b 67 59 11 21  |O=...-3$k.{.gY.!|
+00000260  b5 11 bc 77 b9 d9 e0 6e  a8 2d 2e 35 fa 64 5f 22  |...w...n.-.5.d_"|
+00000270  3e 63 10 6b be ff 14 86  6d 0d f0 15 31 a8 14 38  |>c.k....m...1..8|
+00000280  1e 3b 84 87 2c cb 98 ed  51 76 b9 b1 4f dd db 9b  |.;..,...Qv..O...|
+00000290  84 04 86 40 fa 51 dd ba  b4 8d eb e3 46 de 46 b9  |... at .Q......F.F.|
+000002a0  4f 86 c7 f9 a4 c2 41 34  ac cc f6 ea b0 ab 39 18  |O.....A4......9.|
+000002b0  16 03 03 00 04 0e 00 00  00                       |.........|
 >>> Flow 3 (client to server)
-00000000  16 03 03 00 86 10 00 00  82 00 80 6e 2e 79 82 3a  |...........n.y.:|
-00000010  c4 68 72 f5 a2 42 3d 71  f9 ec 22 8c 0b fa f0 82  |.hr..B=q..".....|
-00000020  82 c0 cb fc 52 0a 51 03  04 8c eb 4a 4e 4f b6 49  |....R.Q....JNO.I|
-00000030  ef 94 65 21 3c f7 9d 46  85 6e 35 d5 17 6b ff a3  |..e!<..F.n5..k..|
-00000040  5e 4d c1 36 1a 2f 68 f5  06 d4 2d 73 4f 1c 3b 7b  |^M.6./h...-sO.;{|
-00000050  c1 fa 4e 7e 7c f9 6c 13  a6 f4 3a 43 e9 aa be 22  |..N~|.l...:C..."|
-00000060  85 6f 2f 7c 5b b0 08 e2  86 b2 ae cb a9 12 d8 32  |.o/|[..........2|
-00000070  80 1d e4 2e 5d c3 66 d1  19 e5 89 33 2a 88 24 40  |....].f....3*.$@|
-00000080  2a 6d 6b b5 f1 92 4b 66  06 b8 49 14 03 03 00 01  |*mk...Kf..I.....|
-00000090  01 16 03 03 00 24 16 49  e2 a0 67 31 cf 0d 72 cb  |.....$.I..g1..r.|
-000000a0  ac 16 2c 80 37 71 69 f7  5f c4 d3 00 19 b7 4b fb  |..,.7qi._.....K.|
-000000b0  e5 e9 74 8e 30 b3 1c c5  ae e6                    |..t.0.....|
+00000000  16 03 03 00 86 10 00 00  82 00 80 87 06 ba d7 1f  |................|
+00000010  68 0c f2 a6 51 b4 ae af  8c c5 5d d4 bd f1 82 6d  |h...Q.....]....m|
+00000020  1d dd ce 69 be 07 62 13  af 06 71 3a 47 a9 bd f7  |...i..b...q:G...|
+00000030  bb 27 f0 38 df 88 01 40  29 c9 bb 7b 5d 6d 28 bd  |.'.8...@)..{]m(.|
+00000040  c8 28 e6 6d ff 5c c9 d3  c6 f5 06 17 e5 e5 1c 5b  |.(.m.\.........[|
+00000050  a1 18 7a 34 92 0a 39 20  5a 22 44 6c cc 5c 8c 83  |..z4..9 Z"Dl.\..|
+00000060  d0 19 4c bb 4e dc e2 64  ec b2 b8 3f 18 3f 9d 65  |..L.N..d...?.?.e|
+00000070  5b 89 26 ae f6 fd 54 71  c4 45 e9 56 6a 28 42 a9  |[.&...Tq.E.Vj(B.|
+00000080  5b 9f 12 69 a4 08 83 53  95 04 18 14 03 03 00 01  |[..i...S........|
+00000090  01 16 03 03 00 24 55 80  0f 43 c3 08 45 99 c9 1b  |.....$U..C..E...|
+000000a0  fd fe dd e8 48 f2 89 99  86 ef f7 fd 5f 2a 4b 0b  |....H......._*K.|
+000000b0  33 0e 5f 17 bb b7 a2 3c  9d 30                    |3._....<.0|
 >>> Flow 4 (server to client)
-00000000  16 03 03 00 72 04 00 00  6e 00 00 00 00 00 68 00  |....r...n.....h.|
-00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 65  |...............e|
-00000020  ea 4b d1 ef ba 06 38 1e  e1 88 82 3a cd 03 ac 3b  |.K....8....:...;|
-00000030  39 0a e0 19 fd af 6c 57  30 df 31 6e f7 92 38 4b  |9.....lW0.1n..8K|
-00000040  5d 77 90 39 ff 32 51 f5  ed 12 d7 b0 7c 4d 6c c5  |]w.9.2Q.....|Ml.|
-00000050  76 e4 72 48 3e 59 23 fe  0d 15 df f4 ba ea b9 67  |v.rH>Y#........g|
-00000060  16 23 8f 7d 15 b6 11 f1  ab d7 d4 cd a3 21 82 92  |.#.}.........!..|
-00000070  2a 12 cf 95 f3 60 b2 14  03 03 00 01 01 16 03 03  |*....`..........|
-00000080  00 24 89 ad 87 04 4f 08  dc 2a 71 37 fb f1 95 d1  |.$....O..*q7....|
-00000090  2e 3c c2 6e 0f 38 5d e4  0e c3 f7 27 d0 46 a3 c1  |.<.n.8]....'.F..|
-000000a0  a8 3b 06 ed 96 ec 17 03  03 00 21 30 d4 9f 0b 49  |.;........!0...I|
-000000b0  9f a2 a8 a1 2c 0a 79 93  56 2d 8a ee 85 ed 62 42  |....,.y.V-....bB|
-000000c0  8c 18 fe 7a 09 3a 24 c4  5e ed 7d 2a 15 03 03 00  |...z.:$.^.}*....|
-000000d0  16 a0 24 0a 8b 90 4c fc  99 ba 67 bb 04 1e 59 69  |..$...L...g...Yi|
-000000e0  c2 98 49 b5 00 0b e0                              |..I....|
+00000000  16 03 03 00 82 04 00 00  7e 00 00 00 00 00 78 50  |........~.....xP|
+00000010  46 ad c1 db a8 38 86 7b  2b bb fd d0 c3 42 3e 00  |F....8.{+....B>.|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 94  |................|
+00000030  6f 2c b5 83 61 c4 74 90  94 e5 6c fd 70 64 57 3a  |o,..a.t...l.pdW:|
+00000040  25 78 bf 9f a0 7c 51 bc  2a 69 1e b3 fd 71 34 b7  |%x...|Q.*i...q4.|
+00000050  9a ef cb 49 37 f8 5d 5e  7c cf 6d fc 13 c1 52 79  |...I7.]^|.m...Ry|
+00000060  8e ed c3 84 01 33 94 10  65 34 64 5e b4 9c 07 46  |.....3..e4d^...F|
+00000070  5b 9e d7 5e 55 df fd c0  e9 d2 e8 d3 c6 42 18 ef  |[..^U........B..|
+00000080  a5 6c be e8 d2 49 c6 14  03 03 00 01 01 16 03 03  |.l...I..........|
+00000090  00 24 66 94 4b b5 3f 5d  59 db 36 c1 dd 55 8c ee  |.$f.K.?]Y.6..U..|
+000000a0  de a4 bc d0 12 44 31 3e  e4 e7 4a 51 e3 62 69 ab  |.....D1>..JQ.bi.|
+000000b0  14 78 85 49 a3 97 17 03  03 00 21 dd 96 5d 21 e0  |.x.I......!..]!.|
+000000c0  2e 3d 33 dd 6c df bb 41  d7 bd 50 c7 1c 6f 97 34  |.=3.l..A..P..o.4|
+000000d0  6a 6e d6 1d 27 81 2d f7  fb 32 85 02 15 03 03 00  |jn..'.-..2......|
+000000e0  16 5e 4e 62 15 97 a7 a3  9b 1b 50 44 85 fb 28 66  |.^Nb......PD..(f|
+000000f0  aa 66 54 45 c9 dc 61                              |.fTE..a|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-IssueTicketPreDisable b/src/crypto/tls/testdata/Server-TLSv12-IssueTicketPreDisable
index 30f0026..a8f7edf 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-IssueTicketPreDisable
+++ b/src/crypto/tls/testdata/Server-TLSv12-IssueTicketPreDisable
@@ -1,87 +1,83 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 60 01 00 00  5c 03 03 54 23 54 02 17  |....`...\..T#T..|
-00000010  f3 53 13 3d 48 88 c3 19  b9 d1 3d 33 7f f5 99 56  |.S.=H.....=3...V|
-00000020  04 71 1b d9 d5 64 8a 0d  4a 54 00 00 00 04 00 05  |.q...d..JT......|
-00000030  00 ff 01 00 00 2f 00 23  00 00 00 0d 00 22 00 20  |...../.#.....". |
+00000000  16 03 01 00 5e 01 00 00  5a 03 03 62 f6 20 66 23  |....^...Z..b. f#|
+00000010  d5 71 0a c0 57 92 2e 80  b6 06 0c 54 5b 1c 77 a0  |.q..W......T[.w.|
+00000020  ce 0b b2 52 4a b9 f2 c6  97 33 42 00 00 04 00 05  |...RJ....3B.....|
+00000030  00 ff 01 00 00 2d 00 23  00 00 00 0d 00 20 00 1e  |.....-.#..... ..|
 00000040  06 01 06 02 06 03 05 01  05 02 05 03 04 01 04 02  |................|
-00000050  04 03 03 01 03 02 03 03  02 01 02 02 02 03 01 01  |................|
-00000060  00 0f 00 01 01                                    |.....|
+00000050  04 03 03 01 03 02 03 03  02 01 02 02 02 03 00 0f  |................|
+00000060  00 01 01                                          |...|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 35 02 00 00  31 03 03 00 00 00 00 00  |....5...1.......|
 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 05 00 00  |................|
-00000030  09 00 23 00 00 ff 01 00  01 00 16 03 03 02 be 0b  |..#.............|
-00000040  00 02 ba 00 02 b7 00 02  b4 30 82 02 b0 30 82 02  |.........0...0..|
-00000050  19 a0 03 02 01 02 02 09  00 85 b0 bb a4 8a 7f b8  |................|
-00000060  ca 30 0d 06 09 2a 86 48  86 f7 0d 01 01 05 05 00  |.0...*.H........|
-00000070  30 45 31 0b 30 09 06 03  55 04 06 13 02 41 55 31  |0E1.0...U....AU1|
-00000080  13 30 11 06 03 55 04 08  13 0a 53 6f 6d 65 2d 53  |.0...U....Some-S|
-00000090  74 61 74 65 31 21 30 1f  06 03 55 04 0a 13 18 49  |tate1!0...U....I|
-000000a0  6e 74 65 72 6e 65 74 20  57 69 64 67 69 74 73 20  |nternet Widgits |
-000000b0  50 74 79 20 4c 74 64 30  1e 17 0d 31 30 30 34 32  |Pty Ltd0...10042|
-000000c0  34 30 39 30 39 33 38 5a  17 0d 31 31 30 34 32 34  |4090938Z..110424|
-000000d0  30 39 30 39 33 38 5a 30  45 31 0b 30 09 06 03 55  |090938Z0E1.0...U|
-000000e0  04 06 13 02 41 55 31 13  30 11 06 03 55 04 08 13  |....AU1.0...U...|
-000000f0  0a 53 6f 6d 65 2d 53 74  61 74 65 31 21 30 1f 06  |.Some-State1!0..|
-00000100  03 55 04 0a 13 18 49 6e  74 65 72 6e 65 74 20 57  |.U....Internet W|
-00000110  69 64 67 69 74 73 20 50  74 79 20 4c 74 64 30 81  |idgits Pty Ltd0.|
-00000120  9f 30 0d 06 09 2a 86 48  86 f7 0d 01 01 01 05 00  |.0...*.H........|
-00000130  03 81 8d 00 30 81 89 02  81 81 00 bb 79 d6 f5 17  |....0.......y...|
-00000140  b5 e5 bf 46 10 d0 dc 69  be e6 2b 07 43 5a d0 03  |...F...i..+.CZ..|
-00000150  2d 8a 7a 43 85 b7 14 52  e7 a5 65 4c 2c 78 b8 23  |-.zC...R..eL,x.#|
-00000160  8c b5 b4 82 e5 de 1f 95  3b 7e 62 a5 2c a5 33 d6  |........;~b.,.3.|
-00000170  fe 12 5c 7a 56 fc f5 06  bf fa 58 7b 26 3f b5 cd  |..\zV.....X{&?..|
-00000180  04 d3 d0 c9 21 96 4a c7  f4 54 9f 5a bf ef 42 71  |....!.J..T.Z..Bq|
-00000190  00 fe 18 99 07 7f 7e 88  7d 7d f1 04 39 c4 a2 2e  |......~.}}..9...|
-000001a0  db 51 c9 7c e3 c0 4c 3b  32 66 01 cf af b1 1d b8  |.Q.|..L;2f......|
-000001b0  71 9a 1d db db 89 6b ae  da 2d 79 02 03 01 00 01  |q.....k..-y.....|
-000001c0  a3 81 a7 30 81 a4 30 1d  06 03 55 1d 0e 04 16 04  |...0..0...U.....|
-000001d0  14 b1 ad e2 85 5a cf cb  28 db 69 ce 23 69 de d3  |.....Z..(.i.#i..|
-000001e0  26 8e 18 88 39 30 75 06  03 55 1d 23 04 6e 30 6c  |&...90u..U.#.n0l|
-000001f0  80 14 b1 ad e2 85 5a cf  cb 28 db 69 ce 23 69 de  |......Z..(.i.#i.|
-00000200  d3 26 8e 18 88 39 a1 49  a4 47 30 45 31 0b 30 09  |.&...9.I.G0E1.0.|
-00000210  06 03 55 04 06 13 02 41  55 31 13 30 11 06 03 55  |..U....AU1.0...U|
-00000220  04 08 13 0a 53 6f 6d 65  2d 53 74 61 74 65 31 21  |....Some-State1!|
-00000230  30 1f 06 03 55 04 0a 13  18 49 6e 74 65 72 6e 65  |0...U....Interne|
-00000240  74 20 57 69 64 67 69 74  73 20 50 74 79 20 4c 74  |t Widgits Pty Lt|
-00000250  64 82 09 00 85 b0 bb a4  8a 7f b8 ca 30 0c 06 03  |d...........0...|
-00000260  55 1d 13 04 05 30 03 01  01 ff 30 0d 06 09 2a 86  |U....0....0...*.|
-00000270  48 86 f7 0d 01 01 05 05  00 03 81 81 00 08 6c 45  |H.............lE|
-00000280  24 c7 6b b1 59 ab 0c 52  cc f2 b0 14 d7 87 9d 7a  |$.k.Y..R.......z|
-00000290  64 75 b5 5a 95 66 e4 c5  2b 8e ae 12 66 1f eb 4f  |du.Z.f..+...f..O|
-000002a0  38 b3 6e 60 d3 92 fd f7  41 08 b5 25 13 b1 18 7a  |8.n`....A..%...z|
-000002b0  24 fb 30 1d ba ed 98 b9  17 ec e7 d7 31 59 db 95  |$.0.........1Y..|
-000002c0  d3 1d 78 ea 50 56 5c d5  82 5a 2d 5a 5f 33 c4 b6  |..x.PV\..Z-Z_3..|
-000002d0  d8 c9 75 90 96 8c 0f 52  98 b5 cd 98 1f 89 20 5f  |..u....R...... _|
-000002e0  f2 a0 1c a3 1b 96 94 dd  a9 fd 57 e9 70 e8 26 6d  |..........W.p.&m|
-000002f0  71 99 9b 26 6e 38 50 29  6c 90 a7 bd d9 16 03 03  |q..&n8P)l.......|
-00000300  00 04 0e 00 00 00                                 |......|
+00000030  09 00 23 00 00 ff 01 00  01 00 16 03 03 02 71 0b  |..#...........q.|
+00000040  00 02 6d 00 02 6a 00 02  67 30 82 02 63 30 82 01  |..m..j..g0..c0..|
+00000050  cc a0 03 02 01 02 02 09  00 a2 73 00 0c 81 00 cb  |..........s.....|
+00000060  f3 30 0d 06 09 2a 86 48  86 f7 0d 01 01 0b 05 00  |.0...*.H........|
+00000070  30 2b 31 17 30 15 06 03  55 04 0a 13 0e 47 6f 6f  |0+1.0...U....Goo|
+00000080  67 6c 65 20 54 45 53 54  49 4e 47 31 10 30 0e 06  |gle TESTING1.0..|
+00000090  03 55 04 03 13 07 47 6f  20 52 6f 6f 74 30 1e 17  |.U....Go Root0..|
+000000a0  0d 31 35 30 31 30 31 30  30 30 30 30 30 5a 17 0d  |.150101000000Z..|
+000000b0  32 35 30 31 30 31 30 30  30 30 30 30 5a 30 26 31  |250101000000Z0&1|
+000000c0  17 30 15 06 03 55 04 0a  13 0e 47 6f 6f 67 6c 65  |.0...U....Google|
+000000d0  20 54 45 53 54 49 4e 47  31 0b 30 09 06 03 55 04  | TESTING1.0...U.|
+000000e0  03 13 02 47 6f 30 81 9f  30 0d 06 09 2a 86 48 86  |...Go0..0...*.H.|
+000000f0  f7 0d 01 01 01 05 00 03  81 8d 00 30 81 89 02 81  |...........0....|
+00000100  81 00 af 87 88 f6 20 1b  95 65 6c 14 ab 44 05 af  |...... ..el..D..|
+00000110  3b 45 14 e3 b7 6d fd 00  63 4d 95 7f fe 6a 62 35  |;E...m..cM...jb5|
+00000120  86 c0 4a f9 18 7c f6 aa  25 5e 7a 64 31 66 00 ba  |..J..|..%^zd1f..|
+00000130  f4 8e 92 af c7 6b d8 76  d4 f3 5f 41 cb 6e 56 15  |.....k.v.._A.nV.|
+00000140  97 1b 97 c1 3c 12 39 21  66 3d 2b 16 d1 bc db 1c  |....<.9!f=+.....|
+00000150  c0 a7 da b7 ca ad ba da  cb d5 21 50 ec de 8d ab  |..........!P....|
+00000160  d1 6b 81 4b 89 02 f3 c4  be c1 6c 89 b1 44 84 bd  |.k.K......l..D..|
+00000170  21 d1 04 7d 9d 16 4d f9  82 15 f6 ef fa d6 09 47  |!..}..M........G|
+00000180  f2 fb 02 03 01 00 01 a3  81 93 30 81 90 30 0e 06  |..........0..0..|
+00000190  03 55 1d 0f 01 01 ff 04  04 03 02 05 a0 30 1d 06  |.U...........0..|
+000001a0  03 55 1d 25 04 16 30 14  06 08 2b 06 01 05 05 07  |.U.%..0...+.....|
+000001b0  03 01 06 08 2b 06 01 05  05 07 03 02 30 0c 06 03  |....+.......0...|
+000001c0  55 1d 13 01 01 ff 04 02  30 00 30 19 06 03 55 1d  |U.......0.0...U.|
+000001d0  0e 04 12 04 10 12 50 8d  89 6f 1b d1 dc 54 4d 6e  |......P..o...TMn|
+000001e0  cb 69 5e 06 f4 30 1b 06  03 55 1d 23 04 14 30 12  |.i^..0...U.#..0.|
+000001f0  80 10 bf 3d b6 a9 66 f2  b8 40 cf ea b4 03 78 48  |...=..f.. at ....xH|
+00000200  1a 41 30 19 06 03 55 1d  11 04 12 30 10 82 0e 65  |.A0...U....0...e|
+00000210  78 61 6d 70 6c 65 2e 67  6f 6c 61 6e 67 30 0d 06  |xample.golang0..|
+00000220  09 2a 86 48 86 f7 0d 01  01 0b 05 00 03 81 81 00  |.*.H............|
+00000230  92 7c af 91 55 12 18 96  59 31 a6 48 40 d5 2d d5  |.|..U...Y1.H at .-.|
+00000240  ee bb 02 a0 f5 c2 1e 7c  9b b3 30 7d 3c dc 76 da  |.......|..0}<.v.|
+00000250  4f 3d c0 fa ae 2d 33 24  6b 03 7b 1b 67 59 11 21  |O=...-3$k.{.gY.!|
+00000260  b5 11 bc 77 b9 d9 e0 6e  a8 2d 2e 35 fa 64 5f 22  |...w...n.-.5.d_"|
+00000270  3e 63 10 6b be ff 14 86  6d 0d f0 15 31 a8 14 38  |>c.k....m...1..8|
+00000280  1e 3b 84 87 2c cb 98 ed  51 76 b9 b1 4f dd db 9b  |.;..,...Qv..O...|
+00000290  84 04 86 40 fa 51 dd ba  b4 8d eb e3 46 de 46 b9  |... at .Q......F.F.|
+000002a0  4f 86 c7 f9 a4 c2 41 34  ac cc f6 ea b0 ab 39 18  |O.....A4......9.|
+000002b0  16 03 03 00 04 0e 00 00  00                       |.........|
 >>> Flow 3 (client to server)
-00000000  16 03 03 00 86 10 00 00  82 00 80 27 e9 a4 f7 e7  |...........'....|
-00000010  df 25 de 84 8c 1f d6 e6  c3 11 28 55 9a c1 91 37  |.%........(U...7|
-00000020  84 f5 ba f8 80 0d ca 50  cb 1e 72 f7 97 6f c2 b2  |.......P..r..o..|
-00000030  04 4d 13 7c e0 6e a0 1f  91 e1 38 1b a2 c0 55 16  |.M.|.n....8...U.|
-00000040  7f 29 fc ed 1c 1a cf 72  14 c3 00 c1 dd 36 36 af  |.).....r.....66.|
-00000050  a6 e4 a8 be ba ec 13 d0  1e d0 1d fd e1 5b 27 fd  |.............['.|
-00000060  9a da 2e 12 c8 b0 b9 c2  b9 76 ec 7f 3c 98 b6 63  |.........v..<..c|
-00000070  bc da f0 07 7a 3d e7 61  f4 2f 12 80 3b f9 3b cc  |....z=.a./..;.;.|
-00000080  05 c8 2f 7e 28 b2 73 bf  97 61 29 14 03 03 00 01  |../~(.s..a).....|
-00000090  01 16 03 03 00 24 17 59  a9 45 53 46 33 96 50 dd  |.....$.Y.ESF3.P.|
-000000a0  3e 23 aa 91 38 f8 56 4a  2f 1a f2 b1 44 9b ce 17  |>#..8.VJ/...D...|
-000000b0  6b 8a 89 76 bc 67 b8 8b  ba 90                    |k..v.g....|
+00000000  16 03 03 00 86 10 00 00  82 00 80 5b 43 6f db 52  |...........[Co.R|
+00000010  56 e3 d9 4b 1e c8 95 8b  78 a6 19 00 44 9c 44 b4  |V..K....x...D.D.|
+00000020  f7 fe d4 3f 69 ea 9c 67  d3 48 b8 c5 93 bc 22 f1  |...?i..g.H....".|
+00000030  a9 0e 81 82 d0 cf dc 0b  ea f0 02 67 92 8d 72 40  |...........g..r@|
+00000040  25 bb f3 88 53 c0 2f ba  38 ef da d1 7c 73 84 ec  |%...S./.8...|s..|
+00000050  61 96 b9 d4 93 06 4a 06  7b 6d 40 e7 bb 15 59 6e  |a.....J.{m at ...Yn|
+00000060  ad 31 71 eb cf 84 57 3b  0c ad aa 70 02 63 24 a9  |.1q...W;...p.c$.|
+00000070  7c a1 9a 6d b7 e0 4c d5  67 4c ce 53 9d b6 31 de  ||..m..L.gL.S..1.|
+00000080  69 b9 f5 ca a8 e3 ea d6  f5 a3 f3 14 03 03 00 01  |i...............|
+00000090  01 16 03 03 00 24 66 ae  13 67 70 20 f5 f5 76 03  |.....$f..gp ..v.|
+000000a0  11 6e 32 a6 73 a2 70 42  ab 4f 16 93 d2 fa a1 ac  |.n2.s.pB.O......|
+000000b0  4e b2 08 4a a9 b5 20 aa  80 b6                    |N..J.. ...|
 >>> Flow 4 (server to client)
-00000000  16 03 03 00 72 04 00 00  6e 00 00 00 00 00 68 00  |....r...n.....h.|
-00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 65  |...............e|
-00000020  ea 4b d1 ef ba 2d db 0c  ba 9a d4 20 76 57 c8 ec  |.K...-..... vW..|
-00000030  dc 2d 77 fb fb 3b 93 5f  53 e0 14 4f 90 fb d6 55  |.-w..;._S..O...U|
-00000040  57 8c 8d 0d 25 ea 5d 0d  f2 91 e5 12 22 12 ec 7b  |W...%.]....."..{|
-00000050  5f b6 6e fd 07 59 23 24  fc b1 97 ca ea 56 a5 c2  |_.n..Y#$.....V..|
-00000060  a0 e4 9e 99 64 f2 64 d0  75 7a 46 63 e3 dc 21 ed  |....d.d.uzFc..!.|
-00000070  78 56 e9 e1 ab 66 80 14  03 03 00 01 01 16 03 03  |xV...f..........|
-00000080  00 24 fc 14 68 07 17 1f  df b7 84 cb fd c1 e0 e4  |.$..h...........|
-00000090  f2 1a ea 34 b5 00 7f 70  be c8 1c 0a d6 55 e3 57  |...4...p.....U.W|
-000000a0  50 4e 6d 7d 8a 5d 17 03  03 00 21 24 27 50 40 c1  |PNm}.]....!$'P at .|
-000000b0  c5 bd c7 9f 95 d9 ba 2e  7b 0e db ea a7 31 81 05  |........{....1..|
-000000c0  75 43 b1 63 cf b8 55 92  ef 76 98 a9 15 03 03 00  |uC.c..U..v......|
-000000d0  16 d7 ea 3c 79 e7 a6 2f  61 39 ec 4e 95 86 48 5e  |...<y../a9.N..H^|
-000000e0  75 a0 9e 41 42 89 67                              |u..AB.g|
+00000000  16 03 03 00 82 04 00 00  7e 00 00 00 00 00 78 50  |........~.....xP|
+00000010  46 ad c1 db a8 38 86 7b  2b bb fd d0 c3 42 3e 00  |F....8.{+....B>.|
+00000020  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 94  |................|
+00000030  6f 2c b5 83 61 bd 50 da  49 7f 8b 8f 58 57 00 a1  |o,..a.P.I...XW..|
+00000040  11 0d 4a 9d 8a 39 dd 85  23 c0 eb 9d 1a 45 93 92  |..J..9..#....E..|
+00000050  e7 af 15 a3 a4 48 da f9  a4 d8 8e cb 6c 3d 44 77  |.....H......l=Dw|
+00000060  f9 c4 83 89 85 33 94 c1  c6 20 9a 73 44 83 89 5e  |.....3... .sD..^|
+00000070  59 ee 05 c6 7e 8d e9 7d  7b f8 84 46 b6 7d 43 ec  |Y...~..}{..F.}C.|
+00000080  f1 af 1f 0f 35 b4 1c 14  03 03 00 01 01 16 03 03  |....5...........|
+00000090  00 24 8c 0d bd bc 34 93  ed ad 80 21 6d 08 e4 0e  |.$....4....!m...|
+000000a0  67 4f 99 8d df 2a 2d 4f  13 39 82 be a1 d2 1f 75  |gO...*-O.9.....u|
+000000b0  73 c8 b2 ce 41 0c 17 03  03 00 21 d8 c2 50 d6 11  |s...A.....!..P..|
+000000c0  bc 86 58 68 0e 60 4a 47  a5 d0 12 7e a3 b5 be 64  |..Xh.`JG...~...d|
+000000d0  e6 b1 bc 62 70 85 d4 7c  cd fe 67 cf 15 03 03 00  |...bp..|..g.....|
+000000e0  16 e4 1c d5 f4 f7 d0 f5  b2 b3 2b 3d b0 7d c0 23  |..........+=.}.#|
+000000f0  e2 5c a5 c7 a4 23 fa                              |.\...#.|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-RSA-3DES b/src/crypto/tls/testdata/Server-TLSv12-RSA-3DES
index 5995b33..7457626 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-RSA-3DES
+++ b/src/crypto/tls/testdata/Server-TLSv12-RSA-3DES
@@ -1,83 +1,77 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 5c 01 00 00  58 03 03 52 cc 57 59 68  |....\...X..R.WYh|
-00000010  11 72 a6 ec 6b 0a 47 1d  10 06 ec 75 af 07 38 a0  |.r..k.G....u..8.|
-00000020  30 9e 91 12 e1 9b 19 46  0d d4 45 00 00 04 00 0a  |0......F..E.....|
-00000030  00 ff 01 00 00 2b 00 0d  00 22 00 20 06 01 06 02  |.....+...". ....|
+00000000  16 03 01 00 5a 01 00 00  56 03 03 ac 1d 0b 6e f3  |....Z...V.....n.|
+00000010  25 04 00 97 a0 79 39 c5  ef 95 8b e3 c1 87 0d 1c  |%....y9.........|
+00000020  0b c3 39 3e ff 23 0e 3c  28 8f 75 00 00 04 00 0a  |..9>.#.<(.u.....|
+00000030  00 ff 01 00 00 29 00 0d  00 20 00 1e 06 01 06 02  |.....)... ......|
 00000040  06 03 05 01 05 02 05 03  04 01 04 02 04 03 03 01  |................|
-00000050  03 02 03 03 02 01 02 02  02 03 01 01 00 0f 00 01  |................|
-00000060  01                                                |.|
+00000050  03 02 03 03 02 01 02 02  02 03 00 0f 00 01 01     |...............|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
 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 0a 00 00  |................|
-00000030  05 ff 01 00 01 00 16 03  03 02 be 0b 00 02 ba 00  |................|
-00000040  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
-00000050  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
-00000060  09 2a 86 48 86 f7 0d 01  01 05 05 00 30 45 31 0b  |.*.H........0E1.|
-00000070  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
-00000080  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
-00000090  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
-000000a0  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
-000000b0  4c 74 64 30 1e 17 0d 31  30 30 34 32 34 30 39 30  |Ltd0...100424090|
-000000c0  39 33 38 5a 17 0d 31 31  30 34 32 34 30 39 30 39  |938Z..1104240909|
-000000d0  33 38 5a 30 45 31 0b 30  09 06 03 55 04 06 13 02  |38Z0E1.0...U....|
-000000e0  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
-000000f0  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
-00000100  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
-00000110  74 73 20 50 74 79 20 4c  74 64 30 81 9f 30 0d 06  |ts Pty Ltd0..0..|
-00000120  09 2a 86 48 86 f7 0d 01  01 01 05 00 03 81 8d 00  |.*.H............|
-00000130  30 81 89 02 81 81 00 bb  79 d6 f5 17 b5 e5 bf 46  |0.......y......F|
-00000140  10 d0 dc 69 be e6 2b 07  43 5a d0 03 2d 8a 7a 43  |...i..+.CZ..-.zC|
-00000150  85 b7 14 52 e7 a5 65 4c  2c 78 b8 23 8c b5 b4 82  |...R..eL,x.#....|
-00000160  e5 de 1f 95 3b 7e 62 a5  2c a5 33 d6 fe 12 5c 7a  |....;~b.,.3...\z|
-00000170  56 fc f5 06 bf fa 58 7b  26 3f b5 cd 04 d3 d0 c9  |V.....X{&?......|
-00000180  21 96 4a c7 f4 54 9f 5a  bf ef 42 71 00 fe 18 99  |!.J..T.Z..Bq....|
-00000190  07 7f 7e 88 7d 7d f1 04  39 c4 a2 2e db 51 c9 7c  |..~.}}..9....Q.||
-000001a0  e3 c0 4c 3b 32 66 01 cf  af b1 1d b8 71 9a 1d db  |..L;2f......q...|
-000001b0  db 89 6b ae da 2d 79 02  03 01 00 01 a3 81 a7 30  |..k..-y........0|
-000001c0  81 a4 30 1d 06 03 55 1d  0e 04 16 04 14 b1 ad e2  |..0...U.........|
-000001d0  85 5a cf cb 28 db 69 ce  23 69 de d3 26 8e 18 88  |.Z..(.i.#i..&...|
-000001e0  39 30 75 06 03 55 1d 23  04 6e 30 6c 80 14 b1 ad  |90u..U.#.n0l....|
-000001f0  e2 85 5a cf cb 28 db 69  ce 23 69 de d3 26 8e 18  |..Z..(.i.#i..&..|
-00000200  88 39 a1 49 a4 47 30 45  31 0b 30 09 06 03 55 04  |.9.I.G0E1.0...U.|
-00000210  06 13 02 41 55 31 13 30  11 06 03 55 04 08 13 0a  |...AU1.0...U....|
-00000220  53 6f 6d 65 2d 53 74 61  74 65 31 21 30 1f 06 03  |Some-State1!0...|
-00000230  55 04 0a 13 18 49 6e 74  65 72 6e 65 74 20 57 69  |U....Internet Wi|
-00000240  64 67 69 74 73 20 50 74  79 20 4c 74 64 82 09 00  |dgits Pty Ltd...|
-00000250  85 b0 bb a4 8a 7f b8 ca  30 0c 06 03 55 1d 13 04  |........0...U...|
-00000260  05 30 03 01 01 ff 30 0d  06 09 2a 86 48 86 f7 0d  |.0....0...*.H...|
-00000270  01 01 05 05 00 03 81 81  00 08 6c 45 24 c7 6b b1  |..........lE$.k.|
-00000280  59 ab 0c 52 cc f2 b0 14  d7 87 9d 7a 64 75 b5 5a  |Y..R.......zdu.Z|
-00000290  95 66 e4 c5 2b 8e ae 12  66 1f eb 4f 38 b3 6e 60  |.f..+...f..O8.n`|
-000002a0  d3 92 fd f7 41 08 b5 25  13 b1 18 7a 24 fb 30 1d  |....A..%...z$.0.|
-000002b0  ba ed 98 b9 17 ec e7 d7  31 59 db 95 d3 1d 78 ea  |........1Y....x.|
-000002c0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
-000002d0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
-000002e0  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
-000002f0  6e 38 50 29 6c 90 a7 bd  d9 16 03 03 00 04 0e 00  |n8P)l...........|
-00000300  00 00                                             |..|
+00000030  05 ff 01 00 01 00 16 03  03 02 71 0b 00 02 6d 00  |..........q...m.|
+00000040  02 6a 00 02 67 30 82 02  63 30 82 01 cc a0 03 02  |.j..g0..c0......|
+00000050  01 02 02 09 00 a2 73 00  0c 81 00 cb f3 30 0d 06  |......s......0..|
+00000060  09 2a 86 48 86 f7 0d 01  01 0b 05 00 30 2b 31 17  |.*.H........0+1.|
+00000070  30 15 06 03 55 04 0a 13  0e 47 6f 6f 67 6c 65 20  |0...U....Google |
+00000080  54 45 53 54 49 4e 47 31  10 30 0e 06 03 55 04 03  |TESTING1.0...U..|
+00000090  13 07 47 6f 20 52 6f 6f  74 30 1e 17 0d 31 35 30  |..Go Root0...150|
+000000a0  31 30 31 30 30 30 30 30  30 5a 17 0d 32 35 30 31  |101000000Z..2501|
+000000b0  30 31 30 30 30 30 30 30  5a 30 26 31 17 30 15 06  |01000000Z0&1.0..|
+000000c0  03 55 04 0a 13 0e 47 6f  6f 67 6c 65 20 54 45 53  |.U....Google TES|
+000000d0  54 49 4e 47 31 0b 30 09  06 03 55 04 03 13 02 47  |TING1.0...U....G|
+000000e0  6f 30 81 9f 30 0d 06 09  2a 86 48 86 f7 0d 01 01  |o0..0...*.H.....|
+000000f0  01 05 00 03 81 8d 00 30  81 89 02 81 81 00 af 87  |.......0........|
+00000100  88 f6 20 1b 95 65 6c 14  ab 44 05 af 3b 45 14 e3  |.. ..el..D..;E..|
+00000110  b7 6d fd 00 63 4d 95 7f  fe 6a 62 35 86 c0 4a f9  |.m..cM...jb5..J.|
+00000120  18 7c f6 aa 25 5e 7a 64  31 66 00 ba f4 8e 92 af  |.|..%^zd1f......|
+00000130  c7 6b d8 76 d4 f3 5f 41  cb 6e 56 15 97 1b 97 c1  |.k.v.._A.nV.....|
+00000140  3c 12 39 21 66 3d 2b 16  d1 bc db 1c c0 a7 da b7  |<.9!f=+.........|
+00000150  ca ad ba da cb d5 21 50  ec de 8d ab d1 6b 81 4b  |......!P.....k.K|
+00000160  89 02 f3 c4 be c1 6c 89  b1 44 84 bd 21 d1 04 7d  |......l..D..!..}|
+00000170  9d 16 4d f9 82 15 f6 ef  fa d6 09 47 f2 fb 02 03  |..M........G....|
+00000180  01 00 01 a3 81 93 30 81  90 30 0e 06 03 55 1d 0f  |......0..0...U..|
+00000190  01 01 ff 04 04 03 02 05  a0 30 1d 06 03 55 1d 25  |.........0...U.%|
+000001a0  04 16 30 14 06 08 2b 06  01 05 05 07 03 01 06 08  |..0...+.........|
+000001b0  2b 06 01 05 05 07 03 02  30 0c 06 03 55 1d 13 01  |+.......0...U...|
+000001c0  01 ff 04 02 30 00 30 19  06 03 55 1d 0e 04 12 04  |....0.0...U.....|
+000001d0  10 12 50 8d 89 6f 1b d1  dc 54 4d 6e cb 69 5e 06  |..P..o...TMn.i^.|
+000001e0  f4 30 1b 06 03 55 1d 23  04 14 30 12 80 10 bf 3d  |.0...U.#..0....=|
+000001f0  b6 a9 66 f2 b8 40 cf ea  b4 03 78 48 1a 41 30 19  |..f.. at ....xH.A0.|
+00000200  06 03 55 1d 11 04 12 30  10 82 0e 65 78 61 6d 70  |..U....0...examp|
+00000210  6c 65 2e 67 6f 6c 61 6e  67 30 0d 06 09 2a 86 48  |le.golang0...*.H|
+00000220  86 f7 0d 01 01 0b 05 00  03 81 81 00 92 7c af 91  |.............|..|
+00000230  55 12 18 96 59 31 a6 48  40 d5 2d d5 ee bb 02 a0  |U...Y1.H at .-.....|
+00000240  f5 c2 1e 7c 9b b3 30 7d  3c dc 76 da 4f 3d c0 fa  |...|..0}<.v.O=..|
+00000250  ae 2d 33 24 6b 03 7b 1b  67 59 11 21 b5 11 bc 77  |.-3$k.{.gY.!...w|
+00000260  b9 d9 e0 6e a8 2d 2e 35  fa 64 5f 22 3e 63 10 6b  |...n.-.5.d_">c.k|
+00000270  be ff 14 86 6d 0d f0 15  31 a8 14 38 1e 3b 84 87  |....m...1..8.;..|
+00000280  2c cb 98 ed 51 76 b9 b1  4f dd db 9b 84 04 86 40  |,...Qv..O......@|
+00000290  fa 51 dd ba b4 8d eb e3  46 de 46 b9 4f 86 c7 f9  |.Q......F.F.O...|
+000002a0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 03 00  |..A4......9.....|
+000002b0  04 0e 00 00 00                                    |.....|
 >>> Flow 3 (client to server)
-00000000  16 03 03 00 86 10 00 00  82 00 80 7a c0 73 ec cb  |...........z.s..|
-00000010  cf c2 a8 86 c0 7e 03 63  57 a1 ce 42 37 6d 78 54  |.....~.cW..B7mxT|
-00000020  29 f5 3e cc 57 c7 0d d9  69 e1 52 5c 3b 6b c4 c7  |).>.W...i.R\;k..|
-00000030  20 6d 59 ee c0 07 81 74  74 9f 62 41 64 f0 4d c8  | mY....tt.bAd.M.|
-00000040  9b aa 1a b9 da 56 07 f5  6c 1c 59 8c d3 f9 08 d9  |.....V..l.Y.....|
-00000050  08 f4 16 93 5d 9a e5 6f  fb 9f ba 3d 3c d6 81 ad  |....]..o...=<...|
-00000060  02 12 a7 28 b6 81 6a 77  c3 e9 d7 c7 54 d6 77 83  |...(..jw....T.w.|
-00000070  77 de 71 fb b3 f3 2d c4  a5 b1 e5 de aa 0e 21 bd  |w.q...-.......!.|
-00000080  91 a2 dc 7f f7 6f 90 82  54 b1 e7 14 03 03 00 01  |.....o..T.......|
-00000090  01 16 03 03 00 30 8f ee  bf fb c8 5c 54 f5 29 23  |.....0.....\T.)#|
-000000a0  d4 55 f6 98 a1 6e d5 43  e7 81 b2 36 f2 98 d8 1b  |.U...n.C...6....|
-000000b0  0d 76 cb 14 ba 32 d7 36  30 e6 ab 42 80 95 f6 8a  |.v...2.60..B....|
-000000c0  60 64 a0 6b 90 81                                 |`d.k..|
+00000000  16 03 03 00 86 10 00 00  82 00 80 15 75 c5 63 e0  |............u.c.|
+00000010  c3 a5 89 dd b3 bf 03 1d  bd 62 86 2e 10 98 79 cb  |.........b....y.|
+00000020  40 3d 9b 36 7e 55 65 d7  80 0a c5 24 ff ad 98 d5  |@=.6~Ue....$....|
+00000030  d4 d9 4e 1b ed 50 0a fa  8a 3e f3 01 c4 e3 47 f7  |..N..P...>....G.|
+00000040  bd 81 fc 33 0b 61 6b b5  3f 38 9b 24 cd 7d 46 66  |...3.ak.?8.$.}Ff|
+00000050  18 87 ea 67 04 b7 ad 23  ac 64 4e 21 cd 29 9f 60  |...g...#.dN!.).`|
+00000060  0e c1 ca 3d 25 d6 d5 2b  e2 60 dc b5 57 be c0 b8  |...=%..+.`..W...|
+00000070  b6 35 25 96 5b 36 55 53  86 b7 90 ef 6c bf 45 2a  |.5%.[6US....l.E*|
+00000080  3d a0 af 08 f0 8a 9c d0  d8 6b 88 14 03 03 00 01  |=........k......|
+00000090  01 16 03 03 00 30 c5 0f  b8 12 c6 5a 42 6a d8 3f  |.....0.....ZBj.?|
+000000a0  f5 49 e4 9a 5d b7 93 90  e7 09 1f 68 40 9d 33 a9  |.I..]......h at .3.|
+000000b0  21 fa 9c 12 c7 7c d4 bf  91 c2 f8 ac 27 b9 8b b6  |!....|......'...|
+000000c0  34 6e f3 c0 fb 83                                 |4n....|
 >>> Flow 4 (server to client)
 00000000  14 03 03 00 01 01 16 03  03 00 30 00 00 00 00 00  |..........0.....|
-00000010  00 00 00 2c 21 52 34 63  ac e3 a3 66 45 00 41 0c  |...,!R4c...fE.A.|
-00000020  93 5d 6a 74 5a 25 dc 69  1d 76 73 0c f4 42 6a 18  |.]jtZ%.i.vs..Bj.|
-00000030  5b 62 23 e7 fe 41 cf d4  9b 86 35 17 03 03 00 30  |[b#..A....5....0|
-00000040  00 00 00 00 00 00 00 00  7d 5d ce 43 85 5c 6b 89  |........}].C.\k.|
-00000050  c9 a5 0e 22 69 8e b9 4a  77 4c c0 4e cc 79 d9 7e  |..."i..JwL.N.y.~|
-00000060  a3 c8 d3 db 5c 53 f8 92  4d c4 5a 88 72 58 05 11  |....\S..M.Z.rX..|
-00000070  15 03 03 00 20 00 00 00  00 00 00 00 00 1d 63 8b  |.... .........c.|
-00000080  a7 74 fb 76 1d 47 31 93  1f ec 8c e2 18 8e 21 dd  |.t.v.G1.......!.|
-00000090  87 97 9f 1c ca                                    |.....|
+00000010  00 00 00 c1 a2 65 c1 36  63 85 cd ca 5a eb 50 ab  |.....e.6c...Z.P.|
+00000020  bb ec 43 30 37 8f 71 b9  b7 2d 1b bb a2 88 fa d5  |..C07.q..-......|
+00000030  b4 a5 c5 4b 19 71 53 46  7d bb d0 17 03 03 00 30  |...K.qSF}......0|
+00000040  00 00 00 00 00 00 00 00  6a a1 3d c6 35 a0 58 c4  |........j.=.5.X.|
+00000050  ef 12 f2 59 1e 02 42 33  42 5f fe 87 a2 1a ce b7  |...Y..B3B_......|
+00000060  0d d2 36 7c 7f 1a 4c 79  1f 38 34 58 b3 05 fb 96  |..6|..Ly.84X....|
+00000070  15 03 03 00 20 00 00 00  00 00 00 00 00 a1 89 42  |.... ..........B|
+00000080  bc 58 1f 2f 9b c4 d7 e2  d1 ce 1c c9 e0 a5 47 be  |.X./..........G.|
+00000090  63 0c a4 bf 26                                    |c...&|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-RSA-AES b/src/crypto/tls/testdata/Server-TLSv12-RSA-AES
index a152a96..4ca860d 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-RSA-AES
+++ b/src/crypto/tls/testdata/Server-TLSv12-RSA-AES
@@ -1,87 +1,81 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 5c 01 00 00  58 03 03 52 cc 57 59 d0  |....\...X..R.WY.|
-00000010  38 05 36 7e e3 1e 93 2a  5a bf dc c2 f8 0a 03 6f  |8.6~...*Z......o|
-00000020  1a fc 21 74 e5 8b 2a c3  9e 2c 26 00 00 04 00 2f  |..!t..*..,&..../|
-00000030  00 ff 01 00 00 2b 00 0d  00 22 00 20 06 01 06 02  |.....+...". ....|
+00000000  16 03 01 00 5a 01 00 00  56 03 03 be 9a 2f 46 66  |....Z...V..../Ff|
+00000010  a3 b3 10 62 63 b6 32 cb  de 1e eb 76 13 50 60 d0  |...bc.2....v.P`.|
+00000020  ee 40 a9 cd 50 ae d8 86  10 37 8b 00 00 04 00 2f  |. at ..P....7...../|
+00000030  00 ff 01 00 00 29 00 0d  00 20 00 1e 06 01 06 02  |.....)... ......|
 00000040  06 03 05 01 05 02 05 03  04 01 04 02 04 03 03 01  |................|
-00000050  03 02 03 03 02 01 02 02  02 03 01 01 00 0f 00 01  |................|
-00000060  01                                                |.|
+00000050  03 02 03 03 02 01 02 02  02 03 00 0f 00 01 01     |...............|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
 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 2f 00 00  |............./..|
-00000030  05 ff 01 00 01 00 16 03  03 02 be 0b 00 02 ba 00  |................|
-00000040  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
-00000050  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
-00000060  09 2a 86 48 86 f7 0d 01  01 05 05 00 30 45 31 0b  |.*.H........0E1.|
-00000070  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
-00000080  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
-00000090  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
-000000a0  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
-000000b0  4c 74 64 30 1e 17 0d 31  30 30 34 32 34 30 39 30  |Ltd0...100424090|
-000000c0  39 33 38 5a 17 0d 31 31  30 34 32 34 30 39 30 39  |938Z..1104240909|
-000000d0  33 38 5a 30 45 31 0b 30  09 06 03 55 04 06 13 02  |38Z0E1.0...U....|
-000000e0  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
-000000f0  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
-00000100  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
-00000110  74 73 20 50 74 79 20 4c  74 64 30 81 9f 30 0d 06  |ts Pty Ltd0..0..|
-00000120  09 2a 86 48 86 f7 0d 01  01 01 05 00 03 81 8d 00  |.*.H............|
-00000130  30 81 89 02 81 81 00 bb  79 d6 f5 17 b5 e5 bf 46  |0.......y......F|
-00000140  10 d0 dc 69 be e6 2b 07  43 5a d0 03 2d 8a 7a 43  |...i..+.CZ..-.zC|
-00000150  85 b7 14 52 e7 a5 65 4c  2c 78 b8 23 8c b5 b4 82  |...R..eL,x.#....|
-00000160  e5 de 1f 95 3b 7e 62 a5  2c a5 33 d6 fe 12 5c 7a  |....;~b.,.3...\z|
-00000170  56 fc f5 06 bf fa 58 7b  26 3f b5 cd 04 d3 d0 c9  |V.....X{&?......|
-00000180  21 96 4a c7 f4 54 9f 5a  bf ef 42 71 00 fe 18 99  |!.J..T.Z..Bq....|
-00000190  07 7f 7e 88 7d 7d f1 04  39 c4 a2 2e db 51 c9 7c  |..~.}}..9....Q.||
-000001a0  e3 c0 4c 3b 32 66 01 cf  af b1 1d b8 71 9a 1d db  |..L;2f......q...|
-000001b0  db 89 6b ae da 2d 79 02  03 01 00 01 a3 81 a7 30  |..k..-y........0|
-000001c0  81 a4 30 1d 06 03 55 1d  0e 04 16 04 14 b1 ad e2  |..0...U.........|
-000001d0  85 5a cf cb 28 db 69 ce  23 69 de d3 26 8e 18 88  |.Z..(.i.#i..&...|
-000001e0  39 30 75 06 03 55 1d 23  04 6e 30 6c 80 14 b1 ad  |90u..U.#.n0l....|
-000001f0  e2 85 5a cf cb 28 db 69  ce 23 69 de d3 26 8e 18  |..Z..(.i.#i..&..|
-00000200  88 39 a1 49 a4 47 30 45  31 0b 30 09 06 03 55 04  |.9.I.G0E1.0...U.|
-00000210  06 13 02 41 55 31 13 30  11 06 03 55 04 08 13 0a  |...AU1.0...U....|
-00000220  53 6f 6d 65 2d 53 74 61  74 65 31 21 30 1f 06 03  |Some-State1!0...|
-00000230  55 04 0a 13 18 49 6e 74  65 72 6e 65 74 20 57 69  |U....Internet Wi|
-00000240  64 67 69 74 73 20 50 74  79 20 4c 74 64 82 09 00  |dgits Pty Ltd...|
-00000250  85 b0 bb a4 8a 7f b8 ca  30 0c 06 03 55 1d 13 04  |........0...U...|
-00000260  05 30 03 01 01 ff 30 0d  06 09 2a 86 48 86 f7 0d  |.0....0...*.H...|
-00000270  01 01 05 05 00 03 81 81  00 08 6c 45 24 c7 6b b1  |..........lE$.k.|
-00000280  59 ab 0c 52 cc f2 b0 14  d7 87 9d 7a 64 75 b5 5a  |Y..R.......zdu.Z|
-00000290  95 66 e4 c5 2b 8e ae 12  66 1f eb 4f 38 b3 6e 60  |.f..+...f..O8.n`|
-000002a0  d3 92 fd f7 41 08 b5 25  13 b1 18 7a 24 fb 30 1d  |....A..%...z$.0.|
-000002b0  ba ed 98 b9 17 ec e7 d7  31 59 db 95 d3 1d 78 ea  |........1Y....x.|
-000002c0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
-000002d0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
-000002e0  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
-000002f0  6e 38 50 29 6c 90 a7 bd  d9 16 03 03 00 04 0e 00  |n8P)l...........|
-00000300  00 00                                             |..|
+00000030  05 ff 01 00 01 00 16 03  03 02 71 0b 00 02 6d 00  |..........q...m.|
+00000040  02 6a 00 02 67 30 82 02  63 30 82 01 cc a0 03 02  |.j..g0..c0......|
+00000050  01 02 02 09 00 a2 73 00  0c 81 00 cb f3 30 0d 06  |......s......0..|
+00000060  09 2a 86 48 86 f7 0d 01  01 0b 05 00 30 2b 31 17  |.*.H........0+1.|
+00000070  30 15 06 03 55 04 0a 13  0e 47 6f 6f 67 6c 65 20  |0...U....Google |
+00000080  54 45 53 54 49 4e 47 31  10 30 0e 06 03 55 04 03  |TESTING1.0...U..|
+00000090  13 07 47 6f 20 52 6f 6f  74 30 1e 17 0d 31 35 30  |..Go Root0...150|
+000000a0  31 30 31 30 30 30 30 30  30 5a 17 0d 32 35 30 31  |101000000Z..2501|
+000000b0  30 31 30 30 30 30 30 30  5a 30 26 31 17 30 15 06  |01000000Z0&1.0..|
+000000c0  03 55 04 0a 13 0e 47 6f  6f 67 6c 65 20 54 45 53  |.U....Google TES|
+000000d0  54 49 4e 47 31 0b 30 09  06 03 55 04 03 13 02 47  |TING1.0...U....G|
+000000e0  6f 30 81 9f 30 0d 06 09  2a 86 48 86 f7 0d 01 01  |o0..0...*.H.....|
+000000f0  01 05 00 03 81 8d 00 30  81 89 02 81 81 00 af 87  |.......0........|
+00000100  88 f6 20 1b 95 65 6c 14  ab 44 05 af 3b 45 14 e3  |.. ..el..D..;E..|
+00000110  b7 6d fd 00 63 4d 95 7f  fe 6a 62 35 86 c0 4a f9  |.m..cM...jb5..J.|
+00000120  18 7c f6 aa 25 5e 7a 64  31 66 00 ba f4 8e 92 af  |.|..%^zd1f......|
+00000130  c7 6b d8 76 d4 f3 5f 41  cb 6e 56 15 97 1b 97 c1  |.k.v.._A.nV.....|
+00000140  3c 12 39 21 66 3d 2b 16  d1 bc db 1c c0 a7 da b7  |<.9!f=+.........|
+00000150  ca ad ba da cb d5 21 50  ec de 8d ab d1 6b 81 4b  |......!P.....k.K|
+00000160  89 02 f3 c4 be c1 6c 89  b1 44 84 bd 21 d1 04 7d  |......l..D..!..}|
+00000170  9d 16 4d f9 82 15 f6 ef  fa d6 09 47 f2 fb 02 03  |..M........G....|
+00000180  01 00 01 a3 81 93 30 81  90 30 0e 06 03 55 1d 0f  |......0..0...U..|
+00000190  01 01 ff 04 04 03 02 05  a0 30 1d 06 03 55 1d 25  |.........0...U.%|
+000001a0  04 16 30 14 06 08 2b 06  01 05 05 07 03 01 06 08  |..0...+.........|
+000001b0  2b 06 01 05 05 07 03 02  30 0c 06 03 55 1d 13 01  |+.......0...U...|
+000001c0  01 ff 04 02 30 00 30 19  06 03 55 1d 0e 04 12 04  |....0.0...U.....|
+000001d0  10 12 50 8d 89 6f 1b d1  dc 54 4d 6e cb 69 5e 06  |..P..o...TMn.i^.|
+000001e0  f4 30 1b 06 03 55 1d 23  04 14 30 12 80 10 bf 3d  |.0...U.#..0....=|
+000001f0  b6 a9 66 f2 b8 40 cf ea  b4 03 78 48 1a 41 30 19  |..f.. at ....xH.A0.|
+00000200  06 03 55 1d 11 04 12 30  10 82 0e 65 78 61 6d 70  |..U....0...examp|
+00000210  6c 65 2e 67 6f 6c 61 6e  67 30 0d 06 09 2a 86 48  |le.golang0...*.H|
+00000220  86 f7 0d 01 01 0b 05 00  03 81 81 00 92 7c af 91  |.............|..|
+00000230  55 12 18 96 59 31 a6 48  40 d5 2d d5 ee bb 02 a0  |U...Y1.H at .-.....|
+00000240  f5 c2 1e 7c 9b b3 30 7d  3c dc 76 da 4f 3d c0 fa  |...|..0}<.v.O=..|
+00000250  ae 2d 33 24 6b 03 7b 1b  67 59 11 21 b5 11 bc 77  |.-3$k.{.gY.!...w|
+00000260  b9 d9 e0 6e a8 2d 2e 35  fa 64 5f 22 3e 63 10 6b  |...n.-.5.d_">c.k|
+00000270  be ff 14 86 6d 0d f0 15  31 a8 14 38 1e 3b 84 87  |....m...1..8.;..|
+00000280  2c cb 98 ed 51 76 b9 b1  4f dd db 9b 84 04 86 40  |,...Qv..O......@|
+00000290  fa 51 dd ba b4 8d eb e3  46 de 46 b9 4f 86 c7 f9  |.Q......F.F.O...|
+000002a0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 03 00  |..A4......9.....|
+000002b0  04 0e 00 00 00                                    |.....|
 >>> Flow 3 (client to server)
-00000000  16 03 03 00 86 10 00 00  82 00 80 4b b4 28 bc 78  |...........K.(.x|
-00000010  41 34 f3 49 e8 74 07 74  42 ae 2e 55 9e 9a ce e5  |A4.I.t.tB..U....|
-00000020  4a 1b e7 55 c7 64 c4 9c  b3 dd 20 d6 f8 8e 67 b3  |J..U.d.... ...g.|
-00000030  7a 5c 3b 34 e4 1a f6 bd  65 fc 21 cd 9a de 64 77  |z\;4....e.!...dw|
-00000040  09 a5 92 e5 a4 f5 18 7b  23 5b 8b c1 95 23 97 6f  |.......{#[...#.o|
-00000050  76 55 04 34 22 7d 43 71  db cd eb f8 36 36 44 4b  |vU.4"}Cq....66DK|
-00000060  ae e3 cc ec 64 88 7b e1  ea d6 ab 49 35 94 a5 04  |....d.{....I5...|
-00000070  1e 83 c5 cf 21 bb ca 33  5f d4 bf 1d d3 4d 07 59  |....!..3_....M.Y|
-00000080  b4 39 b2 4b 7b 05 43 70  0d ba 7a 14 03 03 00 01  |.9.K{.Cp..z.....|
-00000090  01 16 03 03 00 40 74 4b  7d b2 53 49 ea 86 90 c3  |..... at tK}.SI....|
-000000a0  64 6b 64 31 1a 2a 3f 1a  37 1e 56 b8 dd 12 6d 56  |dkd1.*?.7.V...mV|
-000000b0  2a 61 92 5b 39 e7 e1 be  71 70 4b 9b b3 f0 71 e7  |*a.[9...qpK...q.|
-000000c0  47 2e 2e 17 c3 0a 66 9f  69 74 30 2d f0 a0 7f 84  |G.....f.it0-....|
-000000d0  25 db c1 81 ee cf                                 |%.....|
+00000000  16 03 03 00 86 10 00 00  82 00 80 61 b4 31 93 2b  |...........a.1.+|
+00000010  d5 e8 06 74 b1 f6 d6 5f  a3 92 78 b6 cf bf 7f ea  |...t..._..x.....|
+00000020  a2 07 1e 90 94 68 5b 19  ae d4 e3 11 78 96 58 fd  |.....h[.....x.X.|
+00000030  96 18 f2 09 58 dc 39 a1  d9 9e 83 f0 24 45 6e 6b  |....X.9.....$Enk|
+00000040  e6 5e e7 cb 94 42 00 10  64 d5 d2 bc 80 23 bd fe  |.^...B..d....#..|
+00000050  5c 3e 3a 80 ff 38 b8 dc  ff 25 ba b0 0a cc ef 94  |\>:..8...%......|
+00000060  a1 31 bd 04 93 91 86 6e  8b fd a1 9d 01 ee 91 a6  |.1.....n........|
+00000070  44 8b 21 55 52 67 3e b1  e4 6e bd 1f 07 85 e1 97  |D.!URg>..n......|
+00000080  7f 55 70 00 5f f4 4b e6  50 45 f7 14 03 03 00 01  |.Up._.K.PE......|
+00000090  01 16 03 03 00 40 71 ff  ab 6d 79 3c da dc 5b 34  |..... at q..my<..[4|
+000000a0  48 39 48 08 e3 29 cb 53  21 fd 67 93 0b f8 81 47  |H9H..).S!.g....G|
+000000b0  40 7f 23 50 5f 94 db 2b  7b 7e 9f 0b bf 38 59 d9  |@.#P_..+{~...8Y.|
+000000c0  6b 57 8f 1e 83 eb 93 2c  62 12 31 c6 f5 21 f2 22  |kW.....,b.1..!."|
+000000d0  7a 82 e9 e6 ec 38                                 |z....8|
 >>> Flow 4 (server to client)
 00000000  14 03 03 00 01 01 16 03  03 00 40 00 00 00 00 00  |.......... at .....|
-00000010  00 00 00 00 00 00 00 00  00 00 00 f3 4d 5a fc 21  |............MZ.!|
-00000020  30 b5 a1 86 9d e2 ea 38  ac 54 57 fa 5a 54 97 b8  |0......8.TW.ZT..|
-00000030  bb 4d 64 09 ef ce a1 75  0c 50 8d ff 5c c2 e9 47  |.Md....u.P..\..G|
-00000040  95 93 53 c0 bd dc c5 9c  e0 59 17 17 03 03 00 40  |..S......Y.....@|
+00000010  00 00 00 00 00 00 00 00  00 00 00 45 87 33 41 c1  |...........E.3A.|
+00000020  b8 e7 4c 11 1c 1b 7b 55  51 85 06 01 c1 b6 87 6b  |..L...{UQ......k|
+00000030  01 b3 56 c4 5a 37 ea b6  3a c4 b0 da 1b 5c 15 d4  |..V.Z7..:....\..|
+00000040  03 5a 57 e9 9a 56 16 a5  fa 77 1c 17 03 03 00 40  |.ZW..V...w.....@|
 00000050  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000060  69 c5 48 6e 45 cf 98 1b  2c 23 40 d1 ab a3 c2 e2  |i.HnE...,#@.....|
-00000070  10 7b b1 c8 21 3c f0 eb  96 bd 4f 78 b2 4a 7b 18  |.{..!<....Ox.J{.|
-00000080  4c b1 a6 67 bf 06 40 01  d0 8d 91 be 17 d8 0c 71  |L..g.. at ........q|
+00000060  6f 2e 7c ba 3d 85 4c 7b  1f 13 a5 d6 97 e6 67 f4  |o.|.=.L{......g.|
+00000070  24 d5 a8 d4 26 41 64 0a  fd b3 2e a0 a2 7a 2b 54  |$...&Ad......z+T|
+00000080  a4 1d 6e fe 4c c4 73 e3  76 d0 3a 60 52 df b0 53  |..n.L.s.v.:`R..S|
 00000090  15 03 03 00 30 00 00 00  00 00 00 00 00 00 00 00  |....0...........|
-000000a0  00 00 00 00 00 20 84 80  3d 70 fe ae ee d7 2f e9  |..... ..=p..../.|
-000000b0  bf 65 30 bf 0b dd 98 ea  bb ba 12 14 98 53 7f d5  |.e0..........S..|
-000000c0  56 ce 06 3c d0                                    |V..<.|
+000000a0  00 00 00 00 00 8b 0a 6d  14 3b 84 bc 7d c6 8d 9d  |.......m.;..}...|
+000000b0  d5 27 32 84 4b 14 75 42  0f aa 5e 88 ba fa a2 c7  |.'2.K.uB..^.....|
+000000c0  16 93 8a c4 fd                                    |.....|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM b/src/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM
index 0ddfe02..7a26ebd 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM
+++ b/src/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM
@@ -1,93 +1,87 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 9c 01 00 00  98 03 03 53 04 f1 30 73  |...........S..0s|
-00000010  a1 ea 8c d2 90 1c c6 d6  0d 3c af 58 21 65 90 25  |.........<.X!e.%|
-00000020  5e fa f4 27 22 65 c9 68  90 b9 04 00 00 04 c0 2f  |^..'"e.h......./|
-00000030  00 ff 01 00 00 6b 00 0b  00 04 03 00 01 02 00 0a  |.....k..........|
+00000000  16 03 01 00 9a 01 00 00  96 03 03 16 dc f8 f5 3a  |...............:|
+00000010  13 32 e6 1f bd f6 3c 66  b7 4c 67 17 ee b2 2a ba  |.2....<f.Lg...*.|
+00000020  68 5b 8e b1 7c 8f 71 d6  6c 30 e1 00 00 04 c0 2f  |h[..|.q.l0...../|
+00000030  00 ff 01 00 00 69 00 0b  00 04 03 00 01 02 00 0a  |.....i..........|
 00000040  00 34 00 32 00 0e 00 0d  00 19 00 0b 00 0c 00 18  |.4.2............|
 00000050  00 09 00 0a 00 16 00 17  00 08 00 06 00 07 00 14  |................|
 00000060  00 15 00 04 00 05 00 12  00 13 00 01 00 02 00 03  |................|
-00000070  00 0f 00 10 00 11 00 0d  00 22 00 20 06 01 06 02  |.........". ....|
+00000070  00 0f 00 10 00 11 00 0d  00 20 00 1e 06 01 06 02  |......... ......|
 00000080  06 03 05 01 05 02 05 03  04 01 04 02 04 03 03 01  |................|
-00000090  03 02 03 03 02 01 02 02  02 03 01 01 00 0f 00 01  |................|
-000000a0  01                                                |.|
+00000090  03 02 03 03 02 01 02 02  02 03 00 0f 00 01 01     |...............|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
 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 c0 2f 00 00  |............./..|
-00000030  05 ff 01 00 01 00 16 03  03 02 be 0b 00 02 ba 00  |................|
-00000040  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
-00000050  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
-00000060  09 2a 86 48 86 f7 0d 01  01 05 05 00 30 45 31 0b  |.*.H........0E1.|
-00000070  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
-00000080  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
-00000090  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
-000000a0  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
-000000b0  4c 74 64 30 1e 17 0d 31  30 30 34 32 34 30 39 30  |Ltd0...100424090|
-000000c0  39 33 38 5a 17 0d 31 31  30 34 32 34 30 39 30 39  |938Z..1104240909|
-000000d0  33 38 5a 30 45 31 0b 30  09 06 03 55 04 06 13 02  |38Z0E1.0...U....|
-000000e0  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
-000000f0  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
-00000100  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
-00000110  74 73 20 50 74 79 20 4c  74 64 30 81 9f 30 0d 06  |ts Pty Ltd0..0..|
-00000120  09 2a 86 48 86 f7 0d 01  01 01 05 00 03 81 8d 00  |.*.H............|
-00000130  30 81 89 02 81 81 00 bb  79 d6 f5 17 b5 e5 bf 46  |0.......y......F|
-00000140  10 d0 dc 69 be e6 2b 07  43 5a d0 03 2d 8a 7a 43  |...i..+.CZ..-.zC|
-00000150  85 b7 14 52 e7 a5 65 4c  2c 78 b8 23 8c b5 b4 82  |...R..eL,x.#....|
-00000160  e5 de 1f 95 3b 7e 62 a5  2c a5 33 d6 fe 12 5c 7a  |....;~b.,.3...\z|
-00000170  56 fc f5 06 bf fa 58 7b  26 3f b5 cd 04 d3 d0 c9  |V.....X{&?......|
-00000180  21 96 4a c7 f4 54 9f 5a  bf ef 42 71 00 fe 18 99  |!.J..T.Z..Bq....|
-00000190  07 7f 7e 88 7d 7d f1 04  39 c4 a2 2e db 51 c9 7c  |..~.}}..9....Q.||
-000001a0  e3 c0 4c 3b 32 66 01 cf  af b1 1d b8 71 9a 1d db  |..L;2f......q...|
-000001b0  db 89 6b ae da 2d 79 02  03 01 00 01 a3 81 a7 30  |..k..-y........0|
-000001c0  81 a4 30 1d 06 03 55 1d  0e 04 16 04 14 b1 ad e2  |..0...U.........|
-000001d0  85 5a cf cb 28 db 69 ce  23 69 de d3 26 8e 18 88  |.Z..(.i.#i..&...|
-000001e0  39 30 75 06 03 55 1d 23  04 6e 30 6c 80 14 b1 ad  |90u..U.#.n0l....|
-000001f0  e2 85 5a cf cb 28 db 69  ce 23 69 de d3 26 8e 18  |..Z..(.i.#i..&..|
-00000200  88 39 a1 49 a4 47 30 45  31 0b 30 09 06 03 55 04  |.9.I.G0E1.0...U.|
-00000210  06 13 02 41 55 31 13 30  11 06 03 55 04 08 13 0a  |...AU1.0...U....|
-00000220  53 6f 6d 65 2d 53 74 61  74 65 31 21 30 1f 06 03  |Some-State1!0...|
-00000230  55 04 0a 13 18 49 6e 74  65 72 6e 65 74 20 57 69  |U....Internet Wi|
-00000240  64 67 69 74 73 20 50 74  79 20 4c 74 64 82 09 00  |dgits Pty Ltd...|
-00000250  85 b0 bb a4 8a 7f b8 ca  30 0c 06 03 55 1d 13 04  |........0...U...|
-00000260  05 30 03 01 01 ff 30 0d  06 09 2a 86 48 86 f7 0d  |.0....0...*.H...|
-00000270  01 01 05 05 00 03 81 81  00 08 6c 45 24 c7 6b b1  |..........lE$.k.|
-00000280  59 ab 0c 52 cc f2 b0 14  d7 87 9d 7a 64 75 b5 5a  |Y..R.......zdu.Z|
-00000290  95 66 e4 c5 2b 8e ae 12  66 1f eb 4f 38 b3 6e 60  |.f..+...f..O8.n`|
-000002a0  d3 92 fd f7 41 08 b5 25  13 b1 18 7a 24 fb 30 1d  |....A..%...z$.0.|
-000002b0  ba ed 98 b9 17 ec e7 d7  31 59 db 95 d3 1d 78 ea  |........1Y....x.|
-000002c0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
-000002d0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
-000002e0  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
-000002f0  6e 38 50 29 6c 90 a7 bd  d9 16 03 03 00 cd 0c 00  |n8P)l...........|
-00000300  00 c9 03 00 17 41 04 1e  18 37 ef 0d 19 51 88 35  |.....A...7...Q.5|
-00000310  75 71 b5 e5 54 5b 12 2e  8f 09 67 fd a7 24 20 3e  |uq..T[....g..$ >|
-00000320  b2 56 1c ce 97 28 5e f8  2b 2d 4f 9e f1 07 9f 6c  |.V...(^.+-O....l|
-00000330  4b 5b 83 56 e2 32 42 e9  58 b6 d7 49 a6 b5 68 1a  |K[.V.2B.X..I..h.|
-00000340  41 03 56 6b dc 5a 89 04  01 00 80 a2 54 61 84 29  |A.Vk.Z......Ta.)|
-00000350  3e 97 4b 97 9a 9f 5c c0  49 6d 86 d2 79 8e 95 a1  |>.K...\.Im..y...|
-00000360  0a 5a 36 73 34 bb 05 73  35 47 e1 2b 5d f3 ef 36  |.Z6s4..s5G.+]..6|
-00000370  a8 32 e2 7e ef aa 3f 1f  b3 64 60 d4 06 2e 98 e3  |.2.~..?..d`.....|
-00000380  11 e2 60 3c d6 20 17 63  b2 6f a0 cd 21 01 2b 4e  |..`<. .c.o..!.+N|
-00000390  b2 a8 55 04 39 37 5c 6c  71 66 4d a3 eb 1b 83 67  |..U.97\lqfM....g|
-000003a0  6b 15 a0 56 9a f1 a2 79  92 29 ce 58 3c 10 4d 65  |k..V...y.).X<.Me|
-000003b0  1f 22 e3 ea d8 74 aa 01  7e ca f3 89 23 41 4d bd  |."...t..~...#AM.|
-000003c0  df 77 4e 59 54 97 74 ad  07 ea c0 16 03 03 00 04  |.wNYT.t.........|
-000003d0  0e 00 00 00                                       |....|
+00000030  05 ff 01 00 01 00 16 03  03 02 71 0b 00 02 6d 00  |..........q...m.|
+00000040  02 6a 00 02 67 30 82 02  63 30 82 01 cc a0 03 02  |.j..g0..c0......|
+00000050  01 02 02 09 00 a2 73 00  0c 81 00 cb f3 30 0d 06  |......s......0..|
+00000060  09 2a 86 48 86 f7 0d 01  01 0b 05 00 30 2b 31 17  |.*.H........0+1.|
+00000070  30 15 06 03 55 04 0a 13  0e 47 6f 6f 67 6c 65 20  |0...U....Google |
+00000080  54 45 53 54 49 4e 47 31  10 30 0e 06 03 55 04 03  |TESTING1.0...U..|
+00000090  13 07 47 6f 20 52 6f 6f  74 30 1e 17 0d 31 35 30  |..Go Root0...150|
+000000a0  31 30 31 30 30 30 30 30  30 5a 17 0d 32 35 30 31  |101000000Z..2501|
+000000b0  30 31 30 30 30 30 30 30  5a 30 26 31 17 30 15 06  |01000000Z0&1.0..|
+000000c0  03 55 04 0a 13 0e 47 6f  6f 67 6c 65 20 54 45 53  |.U....Google TES|
+000000d0  54 49 4e 47 31 0b 30 09  06 03 55 04 03 13 02 47  |TING1.0...U....G|
+000000e0  6f 30 81 9f 30 0d 06 09  2a 86 48 86 f7 0d 01 01  |o0..0...*.H.....|
+000000f0  01 05 00 03 81 8d 00 30  81 89 02 81 81 00 af 87  |.......0........|
+00000100  88 f6 20 1b 95 65 6c 14  ab 44 05 af 3b 45 14 e3  |.. ..el..D..;E..|
+00000110  b7 6d fd 00 63 4d 95 7f  fe 6a 62 35 86 c0 4a f9  |.m..cM...jb5..J.|
+00000120  18 7c f6 aa 25 5e 7a 64  31 66 00 ba f4 8e 92 af  |.|..%^zd1f......|
+00000130  c7 6b d8 76 d4 f3 5f 41  cb 6e 56 15 97 1b 97 c1  |.k.v.._A.nV.....|
+00000140  3c 12 39 21 66 3d 2b 16  d1 bc db 1c c0 a7 da b7  |<.9!f=+.........|
+00000150  ca ad ba da cb d5 21 50  ec de 8d ab d1 6b 81 4b  |......!P.....k.K|
+00000160  89 02 f3 c4 be c1 6c 89  b1 44 84 bd 21 d1 04 7d  |......l..D..!..}|
+00000170  9d 16 4d f9 82 15 f6 ef  fa d6 09 47 f2 fb 02 03  |..M........G....|
+00000180  01 00 01 a3 81 93 30 81  90 30 0e 06 03 55 1d 0f  |......0..0...U..|
+00000190  01 01 ff 04 04 03 02 05  a0 30 1d 06 03 55 1d 25  |.........0...U.%|
+000001a0  04 16 30 14 06 08 2b 06  01 05 05 07 03 01 06 08  |..0...+.........|
+000001b0  2b 06 01 05 05 07 03 02  30 0c 06 03 55 1d 13 01  |+.......0...U...|
+000001c0  01 ff 04 02 30 00 30 19  06 03 55 1d 0e 04 12 04  |....0.0...U.....|
+000001d0  10 12 50 8d 89 6f 1b d1  dc 54 4d 6e cb 69 5e 06  |..P..o...TMn.i^.|
+000001e0  f4 30 1b 06 03 55 1d 23  04 14 30 12 80 10 bf 3d  |.0...U.#..0....=|
+000001f0  b6 a9 66 f2 b8 40 cf ea  b4 03 78 48 1a 41 30 19  |..f.. at ....xH.A0.|
+00000200  06 03 55 1d 11 04 12 30  10 82 0e 65 78 61 6d 70  |..U....0...examp|
+00000210  6c 65 2e 67 6f 6c 61 6e  67 30 0d 06 09 2a 86 48  |le.golang0...*.H|
+00000220  86 f7 0d 01 01 0b 05 00  03 81 81 00 92 7c af 91  |.............|..|
+00000230  55 12 18 96 59 31 a6 48  40 d5 2d d5 ee bb 02 a0  |U...Y1.H at .-.....|
+00000240  f5 c2 1e 7c 9b b3 30 7d  3c dc 76 da 4f 3d c0 fa  |...|..0}<.v.O=..|
+00000250  ae 2d 33 24 6b 03 7b 1b  67 59 11 21 b5 11 bc 77  |.-3$k.{.gY.!...w|
+00000260  b9 d9 e0 6e a8 2d 2e 35  fa 64 5f 22 3e 63 10 6b  |...n.-.5.d_">c.k|
+00000270  be ff 14 86 6d 0d f0 15  31 a8 14 38 1e 3b 84 87  |....m...1..8.;..|
+00000280  2c cb 98 ed 51 76 b9 b1  4f dd db 9b 84 04 86 40  |,...Qv..O......@|
+00000290  fa 51 dd ba b4 8d eb e3  46 de 46 b9 4f 86 c7 f9  |.Q......F.F.O...|
+000002a0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 03 00  |..A4......9.....|
+000002b0  cd 0c 00 00 c9 03 00 17  41 04 1e 18 37 ef 0d 19  |........A...7...|
+000002c0  51 88 35 75 71 b5 e5 54  5b 12 2e 8f 09 67 fd a7  |Q.5uq..T[....g..|
+000002d0  24 20 3e b2 56 1c ce 97  28 5e f8 2b 2d 4f 9e f1  |$ >.V...(^.+-O..|
+000002e0  07 9f 6c 4b 5b 83 56 e2  32 42 e9 58 b6 d7 49 a6  |..lK[.V.2B.X..I.|
+000002f0  b5 68 1a 41 03 56 6b dc  5a 89 05 01 00 80 40 b3  |.h.A.Vk.Z..... at .|
+00000300  66 ee 53 3c 80 f4 da d1  de e6 fe 50 c8 89 60 d5  |f.S<.......P..`.|
+00000310  e4 80 73 39 91 79 6c cf  89 bb a5 da e4 c7 e5 0d  |..s9.yl.........|
+00000320  13 a6 76 24 65 1a a2 b8  cb 95 c2 c6 9d 66 74 57  |..v$e........ftW|
+00000330  9e 90 4f 48 77 88 3a b4  f3 fa 88 ab 61 22 d3 40  |..OHw.:.....a".@|
+00000340  08 c4 0a 69 19 ed c3 ea  d8 15 79 12 d5 ac 8d af  |...i......y.....|
+00000350  41 7d 87 4b a9 ff f8 cb  24 55 88 38 34 11 a5 bd  |A}.K....$U.84...|
+00000360  c1 d6 e5 86 d5 64 b5 f2  df c8 03 f2 a2 6b ff f4  |.....d.......k..|
+00000370  a8 38 e0 18 04 d4 cd bd  e0 cc 63 fc 3f 8b 16 03  |.8........c.?...|
+00000380  03 00 04 0e 00 00 00                              |.......|
 >>> Flow 3 (client to server)
-00000000  16 03 03 00 46 10 00 00  42 41 04 45 65 ce f7 b9  |....F...BA.Ee...|
-00000010  52 e3 fb 13 db 91 f2 65  43 84 57 f5 1a 19 a0 e6  |R......eC.W.....|
-00000020  89 2d bb 2c 83 6b 62 f6  6f 1f 26 ae 59 67 bd dc  |.-.,.kb.o.&.Yg..|
-00000030  c4 9e 0b dc 7d 6e f8 6b  95 8c 61 47 3d cd d1 df  |....}n.k..aG=...|
-00000040  82 45 30 81 c3 a3 49 5d  85 59 70 14 03 03 00 01  |.E0...I].Yp.....|
-00000050  01 16 03 03 00 28 3f aa  85 33 f9 c6 95 a0 56 ff  |.....(?..3....V.|
-00000060  1c f1 5a ba 6e 41 50 0c  ab 92 e1 e2 8e 89 1c f1  |..Z.nAP.........|
-00000070  fa 54 1b f1 f5 00 01 12  6d c4 96 78 b6 87        |.T......m..x..|
+00000000  16 03 03 00 46 10 00 00  42 41 04 de de ff 8c df  |....F...BA......|
+00000010  d8 4c 72 af 29 3c 4d e0  ed 0f 34 cc fd 2d 52 63  |.Lr.)<M...4..-Rc|
+00000020  94 e8 74 f1 0b 18 69 28  ed 1e f7 62 4e 4f 2c 14  |..t...i(...bNO,.|
+00000030  61 4b 9f 55 d8 70 59 8f  4b a8 ab c6 d2 cd aa 59  |aK.U.pY.K......Y|
+00000040  8a ef 9b b3 f6 ba 52 e5  51 bb a1 14 03 03 00 01  |......R.Q.......|
+00000050  01 16 03 03 00 28 44 1c  eb 89 59 bb ad fb 9f 3f  |.....(D...Y....?|
+00000060  56 06 54 ae 27 6d e4 47  3c 0c 60 30 db 0e d6 0e  |V.T.'m.G<.`0....|
+00000070  9d 0d a9 a0 e7 25 26 6e  99 d0 8f e0 1b 9d        |.....%&n......|
 >>> Flow 4 (server to client)
 00000000  14 03 03 00 01 01 16 03  03 00 28 00 00 00 00 00  |..........(.....|
-00000010  00 00 00 94 5c be 46 05  d6 d0 b0 3a 56 dc 2c 10  |....\.F....:V.,.|
-00000020  0f 6f 5d 33 33 7f a5 4e  74 84 bf 63 87 c4 f4 49  |.o]33..Nt..c...I|
-00000030  bc 6b ab 17 03 03 00 25  00 00 00 00 00 00 00 01  |.k.....%........|
-00000040  7e 4f f9 ae ae fe 6b a0  4a f8 0f 0b b4 b6 65 b6  |~O....k.J.....e.|
-00000050  be 24 5f 94 6d d1 db 54  11 07 b9 ce 01 15 03 03  |.$_.m..T........|
-00000060  00 1a 00 00 00 00 00 00  00 02 a8 1c d6 62 ac fd  |.............b..|
-00000070  77 ba 23 92 5d 34 f1 17  c7 e1 1c 99              |w.#.]4......|
+00000010  00 00 00 92 90 01 f0 70  fa 57 2e 40 d3 4c ef 6a  |.......p.W. at .L.j|
+00000020  03 0c 56 65 f7 c0 3b d0  8a db 48 c9 ae 58 3e 7c  |..Ve..;...H..X>||
+00000030  d1 48 67 17 03 03 00 25  00 00 00 00 00 00 00 01  |.Hg....%........|
+00000040  9e 35 a0 13 73 da 3f 26  ff 1d 90 08 e9 cc 40 7e  |.5..s.?&......@~|
+00000050  82 f3 5e 6e b4 8e 5a 39  7f a4 09 60 b2 15 03 03  |..^n..Z9...`....|
+00000060  00 1a 00 00 00 00 00 00  00 02 04 95 9b 2d 17 1c  |.............-..|
+00000070  6a bc 26 f7 6c 8e f1 c0  0e 82 4a 44              |j.&.l.....JD|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-RSA-AES256-GCM-SHA384 b/src/crypto/tls/testdata/Server-TLSv12-RSA-AES256-GCM-SHA384
new file mode 100644
index 0000000..d59645c
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv12-RSA-AES256-GCM-SHA384
@@ -0,0 +1,87 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 9a 01 00 00  96 03 03 5d 6b 2a ff 74  |...........]k*.t|
+00000010  88 f1 68 8d 1b eb c3 84  34 b5 19 0a 7d f1 9a 0f  |..h.....4...}...|
+00000020  4d c3 0a d7 98 b8 72 e0  73 e4 38 00 00 04 c0 30  |M.....r.s.8....0|
+00000030  00 ff 01 00 00 69 00 0b  00 04 03 00 01 02 00 0a  |.....i..........|
+00000040  00 34 00 32 00 0e 00 0d  00 19 00 0b 00 0c 00 18  |.4.2............|
+00000050  00 09 00 0a 00 16 00 17  00 08 00 06 00 07 00 14  |................|
+00000060  00 15 00 04 00 05 00 12  00 13 00 01 00 02 00 03  |................|
+00000070  00 0f 00 10 00 11 00 0d  00 20 00 1e 06 01 06 02  |......... ......|
+00000080  06 03 05 01 05 02 05 03  04 01 04 02 04 03 03 01  |................|
+00000090  03 02 03 03 02 01 02 02  02 03 00 0f 00 01 01     |...............|
+>>> Flow 2 (server to client)
+00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
+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 c0 30 00 00  |.............0..|
+00000030  05 ff 01 00 01 00 16 03  03 02 71 0b 00 02 6d 00  |..........q...m.|
+00000040  02 6a 00 02 67 30 82 02  63 30 82 01 cc a0 03 02  |.j..g0..c0......|
+00000050  01 02 02 09 00 a2 73 00  0c 81 00 cb f3 30 0d 06  |......s......0..|
+00000060  09 2a 86 48 86 f7 0d 01  01 0b 05 00 30 2b 31 17  |.*.H........0+1.|
+00000070  30 15 06 03 55 04 0a 13  0e 47 6f 6f 67 6c 65 20  |0...U....Google |
+00000080  54 45 53 54 49 4e 47 31  10 30 0e 06 03 55 04 03  |TESTING1.0...U..|
+00000090  13 07 47 6f 20 52 6f 6f  74 30 1e 17 0d 31 35 30  |..Go Root0...150|
+000000a0  31 30 31 30 30 30 30 30  30 5a 17 0d 32 35 30 31  |101000000Z..2501|
+000000b0  30 31 30 30 30 30 30 30  5a 30 26 31 17 30 15 06  |01000000Z0&1.0..|
+000000c0  03 55 04 0a 13 0e 47 6f  6f 67 6c 65 20 54 45 53  |.U....Google TES|
+000000d0  54 49 4e 47 31 0b 30 09  06 03 55 04 03 13 02 47  |TING1.0...U....G|
+000000e0  6f 30 81 9f 30 0d 06 09  2a 86 48 86 f7 0d 01 01  |o0..0...*.H.....|
+000000f0  01 05 00 03 81 8d 00 30  81 89 02 81 81 00 af 87  |.......0........|
+00000100  88 f6 20 1b 95 65 6c 14  ab 44 05 af 3b 45 14 e3  |.. ..el..D..;E..|
+00000110  b7 6d fd 00 63 4d 95 7f  fe 6a 62 35 86 c0 4a f9  |.m..cM...jb5..J.|
+00000120  18 7c f6 aa 25 5e 7a 64  31 66 00 ba f4 8e 92 af  |.|..%^zd1f......|
+00000130  c7 6b d8 76 d4 f3 5f 41  cb 6e 56 15 97 1b 97 c1  |.k.v.._A.nV.....|
+00000140  3c 12 39 21 66 3d 2b 16  d1 bc db 1c c0 a7 da b7  |<.9!f=+.........|
+00000150  ca ad ba da cb d5 21 50  ec de 8d ab d1 6b 81 4b  |......!P.....k.K|
+00000160  89 02 f3 c4 be c1 6c 89  b1 44 84 bd 21 d1 04 7d  |......l..D..!..}|
+00000170  9d 16 4d f9 82 15 f6 ef  fa d6 09 47 f2 fb 02 03  |..M........G....|
+00000180  01 00 01 a3 81 93 30 81  90 30 0e 06 03 55 1d 0f  |......0..0...U..|
+00000190  01 01 ff 04 04 03 02 05  a0 30 1d 06 03 55 1d 25  |.........0...U.%|
+000001a0  04 16 30 14 06 08 2b 06  01 05 05 07 03 01 06 08  |..0...+.........|
+000001b0  2b 06 01 05 05 07 03 02  30 0c 06 03 55 1d 13 01  |+.......0...U...|
+000001c0  01 ff 04 02 30 00 30 19  06 03 55 1d 0e 04 12 04  |....0.0...U.....|
+000001d0  10 12 50 8d 89 6f 1b d1  dc 54 4d 6e cb 69 5e 06  |..P..o...TMn.i^.|
+000001e0  f4 30 1b 06 03 55 1d 23  04 14 30 12 80 10 bf 3d  |.0...U.#..0....=|
+000001f0  b6 a9 66 f2 b8 40 cf ea  b4 03 78 48 1a 41 30 19  |..f.. at ....xH.A0.|
+00000200  06 03 55 1d 11 04 12 30  10 82 0e 65 78 61 6d 70  |..U....0...examp|
+00000210  6c 65 2e 67 6f 6c 61 6e  67 30 0d 06 09 2a 86 48  |le.golang0...*.H|
+00000220  86 f7 0d 01 01 0b 05 00  03 81 81 00 92 7c af 91  |.............|..|
+00000230  55 12 18 96 59 31 a6 48  40 d5 2d d5 ee bb 02 a0  |U...Y1.H at .-.....|
+00000240  f5 c2 1e 7c 9b b3 30 7d  3c dc 76 da 4f 3d c0 fa  |...|..0}<.v.O=..|
+00000250  ae 2d 33 24 6b 03 7b 1b  67 59 11 21 b5 11 bc 77  |.-3$k.{.gY.!...w|
+00000260  b9 d9 e0 6e a8 2d 2e 35  fa 64 5f 22 3e 63 10 6b  |...n.-.5.d_">c.k|
+00000270  be ff 14 86 6d 0d f0 15  31 a8 14 38 1e 3b 84 87  |....m...1..8.;..|
+00000280  2c cb 98 ed 51 76 b9 b1  4f dd db 9b 84 04 86 40  |,...Qv..O......@|
+00000290  fa 51 dd ba b4 8d eb e3  46 de 46 b9 4f 86 c7 f9  |.Q......F.F.O...|
+000002a0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 03 00  |..A4......9.....|
+000002b0  cd 0c 00 00 c9 03 00 17  41 04 1e 18 37 ef 0d 19  |........A...7...|
+000002c0  51 88 35 75 71 b5 e5 54  5b 12 2e 8f 09 67 fd a7  |Q.5uq..T[....g..|
+000002d0  24 20 3e b2 56 1c ce 97  28 5e f8 2b 2d 4f 9e f1  |$ >.V...(^.+-O..|
+000002e0  07 9f 6c 4b 5b 83 56 e2  32 42 e9 58 b6 d7 49 a6  |..lK[.V.2B.X..I.|
+000002f0  b5 68 1a 41 03 56 6b dc  5a 89 05 01 00 80 22 6b  |.h.A.Vk.Z....."k|
+00000300  87 4b f8 ba f2 09 91 ee  ce 81 67 d4 fd d8 b5 07  |.K........g.....|
+00000310  fe c3 88 96 ca e3 3a f0  87 cc ae 44 94 8e 8f 70  |......:....D...p|
+00000320  79 cd de a2 26 4e 17 45  d7 ea 0f 95 a6 c9 7b 17  |y...&N.E......{.|
+00000330  68 7c f5 e8 6c d5 87 6d  5a 7e 53 af 95 0c 42 91  |h|..l..mZ~S...B.|
+00000340  c0 07 18 75 fd 74 1c ad  ef df f8 41 b1 ad fc 36  |...u.t.....A...6|
+00000350  19 31 cf c8 3f 36 55 dd  54 ac 44 a9 3a d1 ae 23  |.1..?6U.T.D.:..#|
+00000360  0a 18 bf b7 6f c7 bc a6  70 50 5e 50 dd da ff 5b  |....o...pP^P...[|
+00000370  67 7d 0a f5 70 a0 8c 88  d9 38 d4 bf a9 c3 16 03  |g}..p....8......|
+00000380  03 00 04 0e 00 00 00                              |.......|
+>>> Flow 3 (client to server)
+00000000  16 03 03 00 46 10 00 00  42 41 04 d0 f7 11 ae 9f  |....F...BA......|
+00000010  ec 2e ac 8e 97 6c 58 0e  57 32 8e ac fa 3e af 36  |.....lX.W2...>.6|
+00000020  22 e1 41 2b d3 d1 9c c2  1d 51 c0 e4 20 b3 4c 85  |".A+.....Q.. .L.|
+00000030  b8 bd f2 d1 c6 2f 7d 83  c7 43 d9 31 36 1a 83 ca  |...../}..C.16...|
+00000040  c6 89 f8 ba 8c d1 7e 99  04 6e 92 14 03 03 00 01  |......~..n......|
+00000050  01 16 03 03 00 28 32 67  c1 6e 5e 1e 4b 51 1b 70  |.....(2g.n^.KQ.p|
+00000060  54 b9 1d 69 79 38 bd fa  7c 6b 58 71 af 72 08 2d  |T..iy8..|kXq.r.-|
+00000070  55 df 24 be 5b 41 0a ef  0e 90 cf d9 62 81        |U.$.[A......b.|
+>>> Flow 4 (server to client)
+00000000  14 03 03 00 01 01 16 03  03 00 28 00 00 00 00 00  |..........(.....|
+00000010  00 00 00 87 2a 3e 09 54  54 c3 58 c0 5b 7b 91 00  |....*>.TT.X.[{..|
+00000020  c4 07 98 9e de 1f f8 04  bb d7 42 04 55 7d 18 a4  |..........B.U}..|
+00000030  41 7c a6 17 03 03 00 25  00 00 00 00 00 00 00 01  |A|.....%........|
+00000040  ab 23 05 51 b4 60 a2 77  01 58 be a6 9f 89 2b b5  |.#.Q.`.w.X....+.|
+00000050  77 6b 19 23 67 f7 89 f1  ef d6 1b f5 e7 15 03 03  |wk.#g...........|
+00000060  00 1a 00 00 00 00 00 00  00 02 8a bf f0 fb 9f 56  |...............V|
+00000070  36 f1 92 49 a9 e5 40 87  f9 87 9e 4d              |6..I.. at ....M|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-RSA-RC4 b/src/crypto/tls/testdata/Server-TLSv12-RSA-RC4
index b703a8f..13163d6 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-RSA-RC4
+++ b/src/crypto/tls/testdata/Server-TLSv12-RSA-RC4
@@ -1,79 +1,73 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 5c 01 00 00  58 03 03 52 cc 57 59 c9  |....\...X..R.WY.|
-00000010  c3 13 fc 18 8a ee c2 0e  88 ff fb 4a 16 f2 eb eb  |...........J....|
-00000020  d4 f8 b3 5b cd bb 25 0e  0b cb 48 00 00 04 00 05  |...[..%...H.....|
-00000030  00 ff 01 00 00 2b 00 0d  00 22 00 20 06 01 06 02  |.....+...". ....|
+00000000  16 03 01 00 5a 01 00 00  56 03 03 8a fe f5 09 70  |....Z...V......p|
+00000010  8e 6b e3 2b 12 ff d1 b2  ae 15 bf 47 0e ca 5c b5  |.k.+.......G..\.|
+00000020  bb 0e ad af e5 a6 7e 36  c5 a4 c3 00 00 04 00 05  |......~6........|
+00000030  00 ff 01 00 00 29 00 0d  00 20 00 1e 06 01 06 02  |.....)... ......|
 00000040  06 03 05 01 05 02 05 03  04 01 04 02 04 03 03 01  |................|
-00000050  03 02 03 03 02 01 02 02  02 03 01 01 00 0f 00 01  |................|
-00000060  01                                                |.|
+00000050  03 02 03 03 02 01 02 02  02 03 00 0f 00 01 01     |...............|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
 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 05 00 00  |................|
-00000030  05 ff 01 00 01 00 16 03  03 02 be 0b 00 02 ba 00  |................|
-00000040  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
-00000050  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
-00000060  09 2a 86 48 86 f7 0d 01  01 05 05 00 30 45 31 0b  |.*.H........0E1.|
-00000070  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
-00000080  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
-00000090  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
-000000a0  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
-000000b0  4c 74 64 30 1e 17 0d 31  30 30 34 32 34 30 39 30  |Ltd0...100424090|
-000000c0  39 33 38 5a 17 0d 31 31  30 34 32 34 30 39 30 39  |938Z..1104240909|
-000000d0  33 38 5a 30 45 31 0b 30  09 06 03 55 04 06 13 02  |38Z0E1.0...U....|
-000000e0  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
-000000f0  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
-00000100  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
-00000110  74 73 20 50 74 79 20 4c  74 64 30 81 9f 30 0d 06  |ts Pty Ltd0..0..|
-00000120  09 2a 86 48 86 f7 0d 01  01 01 05 00 03 81 8d 00  |.*.H............|
-00000130  30 81 89 02 81 81 00 bb  79 d6 f5 17 b5 e5 bf 46  |0.......y......F|
-00000140  10 d0 dc 69 be e6 2b 07  43 5a d0 03 2d 8a 7a 43  |...i..+.CZ..-.zC|
-00000150  85 b7 14 52 e7 a5 65 4c  2c 78 b8 23 8c b5 b4 82  |...R..eL,x.#....|
-00000160  e5 de 1f 95 3b 7e 62 a5  2c a5 33 d6 fe 12 5c 7a  |....;~b.,.3...\z|
-00000170  56 fc f5 06 bf fa 58 7b  26 3f b5 cd 04 d3 d0 c9  |V.....X{&?......|
-00000180  21 96 4a c7 f4 54 9f 5a  bf ef 42 71 00 fe 18 99  |!.J..T.Z..Bq....|
-00000190  07 7f 7e 88 7d 7d f1 04  39 c4 a2 2e db 51 c9 7c  |..~.}}..9....Q.||
-000001a0  e3 c0 4c 3b 32 66 01 cf  af b1 1d b8 71 9a 1d db  |..L;2f......q...|
-000001b0  db 89 6b ae da 2d 79 02  03 01 00 01 a3 81 a7 30  |..k..-y........0|
-000001c0  81 a4 30 1d 06 03 55 1d  0e 04 16 04 14 b1 ad e2  |..0...U.........|
-000001d0  85 5a cf cb 28 db 69 ce  23 69 de d3 26 8e 18 88  |.Z..(.i.#i..&...|
-000001e0  39 30 75 06 03 55 1d 23  04 6e 30 6c 80 14 b1 ad  |90u..U.#.n0l....|
-000001f0  e2 85 5a cf cb 28 db 69  ce 23 69 de d3 26 8e 18  |..Z..(.i.#i..&..|
-00000200  88 39 a1 49 a4 47 30 45  31 0b 30 09 06 03 55 04  |.9.I.G0E1.0...U.|
-00000210  06 13 02 41 55 31 13 30  11 06 03 55 04 08 13 0a  |...AU1.0...U....|
-00000220  53 6f 6d 65 2d 53 74 61  74 65 31 21 30 1f 06 03  |Some-State1!0...|
-00000230  55 04 0a 13 18 49 6e 74  65 72 6e 65 74 20 57 69  |U....Internet Wi|
-00000240  64 67 69 74 73 20 50 74  79 20 4c 74 64 82 09 00  |dgits Pty Ltd...|
-00000250  85 b0 bb a4 8a 7f b8 ca  30 0c 06 03 55 1d 13 04  |........0...U...|
-00000260  05 30 03 01 01 ff 30 0d  06 09 2a 86 48 86 f7 0d  |.0....0...*.H...|
-00000270  01 01 05 05 00 03 81 81  00 08 6c 45 24 c7 6b b1  |..........lE$.k.|
-00000280  59 ab 0c 52 cc f2 b0 14  d7 87 9d 7a 64 75 b5 5a  |Y..R.......zdu.Z|
-00000290  95 66 e4 c5 2b 8e ae 12  66 1f eb 4f 38 b3 6e 60  |.f..+...f..O8.n`|
-000002a0  d3 92 fd f7 41 08 b5 25  13 b1 18 7a 24 fb 30 1d  |....A..%...z$.0.|
-000002b0  ba ed 98 b9 17 ec e7 d7  31 59 db 95 d3 1d 78 ea  |........1Y....x.|
-000002c0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
-000002d0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
-000002e0  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
-000002f0  6e 38 50 29 6c 90 a7 bd  d9 16 03 03 00 04 0e 00  |n8P)l...........|
-00000300  00 00                                             |..|
+00000030  05 ff 01 00 01 00 16 03  03 02 71 0b 00 02 6d 00  |..........q...m.|
+00000040  02 6a 00 02 67 30 82 02  63 30 82 01 cc a0 03 02  |.j..g0..c0......|
+00000050  01 02 02 09 00 a2 73 00  0c 81 00 cb f3 30 0d 06  |......s......0..|
+00000060  09 2a 86 48 86 f7 0d 01  01 0b 05 00 30 2b 31 17  |.*.H........0+1.|
+00000070  30 15 06 03 55 04 0a 13  0e 47 6f 6f 67 6c 65 20  |0...U....Google |
+00000080  54 45 53 54 49 4e 47 31  10 30 0e 06 03 55 04 03  |TESTING1.0...U..|
+00000090  13 07 47 6f 20 52 6f 6f  74 30 1e 17 0d 31 35 30  |..Go Root0...150|
+000000a0  31 30 31 30 30 30 30 30  30 5a 17 0d 32 35 30 31  |101000000Z..2501|
+000000b0  30 31 30 30 30 30 30 30  5a 30 26 31 17 30 15 06  |01000000Z0&1.0..|
+000000c0  03 55 04 0a 13 0e 47 6f  6f 67 6c 65 20 54 45 53  |.U....Google TES|
+000000d0  54 49 4e 47 31 0b 30 09  06 03 55 04 03 13 02 47  |TING1.0...U....G|
+000000e0  6f 30 81 9f 30 0d 06 09  2a 86 48 86 f7 0d 01 01  |o0..0...*.H.....|
+000000f0  01 05 00 03 81 8d 00 30  81 89 02 81 81 00 af 87  |.......0........|
+00000100  88 f6 20 1b 95 65 6c 14  ab 44 05 af 3b 45 14 e3  |.. ..el..D..;E..|
+00000110  b7 6d fd 00 63 4d 95 7f  fe 6a 62 35 86 c0 4a f9  |.m..cM...jb5..J.|
+00000120  18 7c f6 aa 25 5e 7a 64  31 66 00 ba f4 8e 92 af  |.|..%^zd1f......|
+00000130  c7 6b d8 76 d4 f3 5f 41  cb 6e 56 15 97 1b 97 c1  |.k.v.._A.nV.....|
+00000140  3c 12 39 21 66 3d 2b 16  d1 bc db 1c c0 a7 da b7  |<.9!f=+.........|
+00000150  ca ad ba da cb d5 21 50  ec de 8d ab d1 6b 81 4b  |......!P.....k.K|
+00000160  89 02 f3 c4 be c1 6c 89  b1 44 84 bd 21 d1 04 7d  |......l..D..!..}|
+00000170  9d 16 4d f9 82 15 f6 ef  fa d6 09 47 f2 fb 02 03  |..M........G....|
+00000180  01 00 01 a3 81 93 30 81  90 30 0e 06 03 55 1d 0f  |......0..0...U..|
+00000190  01 01 ff 04 04 03 02 05  a0 30 1d 06 03 55 1d 25  |.........0...U.%|
+000001a0  04 16 30 14 06 08 2b 06  01 05 05 07 03 01 06 08  |..0...+.........|
+000001b0  2b 06 01 05 05 07 03 02  30 0c 06 03 55 1d 13 01  |+.......0...U...|
+000001c0  01 ff 04 02 30 00 30 19  06 03 55 1d 0e 04 12 04  |....0.0...U.....|
+000001d0  10 12 50 8d 89 6f 1b d1  dc 54 4d 6e cb 69 5e 06  |..P..o...TMn.i^.|
+000001e0  f4 30 1b 06 03 55 1d 23  04 14 30 12 80 10 bf 3d  |.0...U.#..0....=|
+000001f0  b6 a9 66 f2 b8 40 cf ea  b4 03 78 48 1a 41 30 19  |..f.. at ....xH.A0.|
+00000200  06 03 55 1d 11 04 12 30  10 82 0e 65 78 61 6d 70  |..U....0...examp|
+00000210  6c 65 2e 67 6f 6c 61 6e  67 30 0d 06 09 2a 86 48  |le.golang0...*.H|
+00000220  86 f7 0d 01 01 0b 05 00  03 81 81 00 92 7c af 91  |.............|..|
+00000230  55 12 18 96 59 31 a6 48  40 d5 2d d5 ee bb 02 a0  |U...Y1.H at .-.....|
+00000240  f5 c2 1e 7c 9b b3 30 7d  3c dc 76 da 4f 3d c0 fa  |...|..0}<.v.O=..|
+00000250  ae 2d 33 24 6b 03 7b 1b  67 59 11 21 b5 11 bc 77  |.-3$k.{.gY.!...w|
+00000260  b9 d9 e0 6e a8 2d 2e 35  fa 64 5f 22 3e 63 10 6b  |...n.-.5.d_">c.k|
+00000270  be ff 14 86 6d 0d f0 15  31 a8 14 38 1e 3b 84 87  |....m...1..8.;..|
+00000280  2c cb 98 ed 51 76 b9 b1  4f dd db 9b 84 04 86 40  |,...Qv..O......@|
+00000290  fa 51 dd ba b4 8d eb e3  46 de 46 b9 4f 86 c7 f9  |.Q......F.F.O...|
+000002a0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 03 00  |..A4......9.....|
+000002b0  04 0e 00 00 00                                    |.....|
 >>> Flow 3 (client to server)
-00000000  16 03 03 00 86 10 00 00  82 00 80 35 b3 60 ba 14  |...........5.`..|
-00000010  5f 19 24 a0 24 de 4e 85  a9 64 78 3a 51 24 64 70  |_.$.$.N..dx:Q$dp|
-00000020  88 55 6d c3 11 b8 d3 9f  bc 7a 33 f8 3c 48 93 2f  |.Um......z3.<H./|
-00000030  66 69 11 33 39 37 7a 36  a3 1c ef b0 81 71 7d 25  |fi.397z6.....q}%|
-00000040  35 da 2c 42 e2 ab d3 b7  07 8b 4a 0d 6d 77 bd ae  |5.,B......J.mw..|
-00000050  02 51 7c a5 0d a6 03 4c  3c d0 ce 89 2c 83 6c de  |.Q|....L<...,.l.|
-00000060  40 15 cc 72 c7 95 c8 6d  ee 05 86 da 3e c6 7c d4  |@..r...m....>.|.|
-00000070  44 82 f4 24 03 22 40 00  64 27 53 15 41 8c 01 e9  |D..$."@.d'S.A...|
-00000080  39 32 fa 8e 2d f9 b4 89  34 15 d6 14 03 03 00 01  |92..-...4.......|
-00000090  01 16 03 03 00 24 f5 61  8b 24 bf b4 82 3a cf 49  |.....$.a.$...:.I|
-000000a0  99 a0 b1 1b a7 a7 a3 92  7c 84 85 e0 64 a3 3d bd  |........|...d.=.|
-000000b0  38 98 7d 97 a8 b9 2a 35  a9 09                    |8.}...*5..|
+00000000  16 03 03 00 86 10 00 00  82 00 80 1c f7 2c 18 38  |.............,.8|
+00000010  d9 41 b5 ab b7 35 2b 75  2d 66 ba c8 70 c2 19 1c  |.A...5+u-f..p...|
+00000020  f2 6d d9 a9 a8 40 8e b5  2c 75 99 06 a5 25 be 0d  |.m... at ..,u...%..|
+00000030  b4 b0 9b aa fc 6b 12 a5  b3 e7 02 60 aa 25 e9 7f  |.....k.....`.%..|
+00000040  6b f5 c4 7a 1d 16 a5 d1  76 cc d5 a1 18 68 91 c3  |k..z....v....h..|
+00000050  57 b8 10 f2 b8 81 f3 1b  74 ef 6c 37 3e 81 41 09  |W.......t.l7>.A.|
+00000060  2a c5 15 e6 cc bb 74 4c  01 7a b9 82 5c e2 7f b7  |*.....tL.z..\...|
+00000070  ac 2d 76 30 18 30 c2 19  8c 5f f2 80 41 89 bb 47  |.-v0.0..._..A..G|
+00000080  28 3d 61 cc 3c 06 a8 76  93 57 71 14 03 03 00 01  |(=a.<..v.Wq.....|
+00000090  01 16 03 03 00 24 46 34  1f cc eb 53 c7 d2 04 28  |.....$F4...S...(|
+000000a0  b6 3d 3f 39 06 70 56 b7  db eb 53 9c 66 c3 45 9f  |.=?9.pV...S.f.E.|
+000000b0  69 ca 58 8f e7 ba a7 e6  5a 97                    |i.X.....Z.|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 24 c9 0b 84 e6 39  |..........$....9|
-00000010  f2 e0 f3 ac 9f 0f 17 92  5f 6d de 94 18 c4 60 d9  |........_m....`.|
-00000020  66 c3 0d 1a ae c2 8f 46  8f 7f f0 58 0e 4a 9b 17  |f......F...X.J..|
-00000030  03 03 00 21 8b 73 a1 6a  7e d9 7e 4f 1d cc b2 7d  |...!.s.j~.~O...}|
-00000040  3c 83 3f 52 f8 08 77 01  4c 65 11 6d 50 25 9a cc  |<.?R..w.Le.mP%..|
-00000050  e3 54 27 72 59 15 03 03  00 16 3d c8 ab 14 51 fa  |.T'rY.....=...Q.|
-00000060  97 f1 ef 5f b4 4f 44 58  d4 93 3b ae e5 61 1f a3  |..._.ODX..;..a..|
+00000000  14 03 03 00 01 01 16 03  03 00 24 78 c3 02 89 60  |..........$x...`|
+00000010  e7 72 9f 51 87 14 ca 2e  0d 79 98 eb 1e 39 62 f9  |.r.Q.....y...9b.|
+00000020  fc a5 c9 2c f8 0c 04 16  60 70 90 b7 31 f8 30 17  |...,....`p..1.0.|
+00000030  03 03 00 21 6a b7 24 73  a7 0d 17 04 d7 54 a8 ea  |...!j.$s.....T..|
+00000040  28 4e f2 0a ef 87 d5 a9  b8 84 81 46 8e 97 d1 ae  |(N.........F....|
+00000050  3c cc b1 6b 72 15 03 03  00 16 1a bb 2f df ae 3e  |<..kr......./..>|
+00000060  a7 89 69 3e 35 f2 f6 cd  35 60 29 3a 6f be 32 0d  |..i>5...5`):o.2.|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-Resume b/src/crypto/tls/testdata/Server-TLSv12-Resume
index c495d4a..8cacd21 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-Resume
+++ b/src/crypto/tls/testdata/Server-TLSv12-Resume
@@ -1,36 +1,37 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 e8 01 00 00  e4 03 03 52 cc 57 59 c3  |...........R.WY.|
-00000010  8b df 97 05 d8 5f 16 22  b4 b1 e7 cb 7d 2f 9b 58  |....._."....}/.X|
-00000020  a3 f4 d7 2c a4 c1 9d 49  ed 4b ba 20 90 da 90 3e  |...,...I.K. ...>|
-00000030  36 19 7a db 56 43 26 f7  dc 42 57 33 22 ed 9d a4  |6.z.VC&..BW3"...|
-00000040  9d 53 da f8 9d 4e 60 66  71 a0 2e 2e 00 04 00 05  |.S...N`fq.......|
-00000050  00 ff 01 00 00 97 00 23  00 68 00 00 00 00 00 00  |.......#.h......|
-00000060  00 00 00 00 00 00 00 00  00 00 65 ea 4b d1 ef ba  |..........e.K...|
-00000070  06 38 1e e1 88 82 3a cd  03 ac 3b 39 0a e0 19 fd  |.8....:...;9....|
-00000080  af 6c 57 30 df 31 6e f7  92 38 4b 5d 77 90 39 ff  |.lW0.1n..8K]w.9.|
-00000090  32 51 f5 ed 12 d7 b0 7c  4d 6c c5 76 e4 72 48 3e  |2Q.....|Ml.v.rH>|
-000000a0  59 23 fe 0d 15 df f4 ba  ea b9 67 16 23 8f 7d 15  |Y#........g.#.}.|
-000000b0  b6 11 f1 ab d7 d4 cd a3  21 82 92 2a 12 cf 95 f3  |........!..*....|
-000000c0  60 b2 00 0d 00 22 00 20  06 01 06 02 06 03 05 01  |`....". ........|
-000000d0  05 02 05 03 04 01 04 02  04 03 03 01 03 02 03 03  |................|
-000000e0  02 01 02 02 02 03 01 01  00 0f 00 01 01           |.............|
+00000000  16 03 01 00 f6 01 00 00  f2 03 03 53 1e 13 2e bd  |...........S....|
+00000010  ad 66 fd 77 1a ad 5f 4d  cb bd 2e ca b5 c2 45 1d  |.f.w.._M......E.|
+00000020  7c 83 9d 62 3e 39 9c ce  78 99 e7 20 b4 06 b0 ec  ||..b>9..x.. ....|
+00000030  cf b7 52 6e 38 10 31 37  b2 e6 58 0f fa e3 b0 cb  |..Rn8.17..X.....|
+00000040  20 a4 d2 4b f3 7d 92 e6  7e 13 37 08 00 04 00 05  | ..K.}..~.7.....|
+00000050  00 ff 01 00 00 a5 00 23  00 78 50 46 ad c1 db a8  |.......#.xPF....|
+00000060  38 86 7b 2b bb fd d0 c3  42 3e 00 00 00 00 00 00  |8.{+....B>......|
+00000070  00 00 00 00 00 00 00 00  00 00 94 6f 2c b5 83 61  |...........o,..a|
+00000080  c4 74 90 94 e5 6c fd 70  64 57 3a 25 78 bf 9f a0  |.t...l.pdW:%x...|
+00000090  7c 51 bc 2a 69 1e b3 fd  71 34 b7 9a ef cb 49 37  ||Q.*i...q4....I7|
+000000a0  f8 5d 5e 7c cf 6d fc 13  c1 52 79 8e ed c3 84 01  |.]^|.m...Ry.....|
+000000b0  33 94 10 65 34 64 5e b4  9c 07 46 5b 9e d7 5e 55  |3..e4d^...F[..^U|
+000000c0  df fd c0 e9 d2 e8 d3 c6  42 18 ef a5 6c be e8 d2  |........B...l...|
+000000d0  49 c6 00 0d 00 20 00 1e  06 01 06 02 06 03 05 01  |I.... ..........|
+000000e0  05 02 05 03 04 01 04 02  04 03 03 01 03 02 03 03  |................|
+000000f0  02 01 02 02 02 03 00 0f  00 01 01                 |...........|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 51 02 00 00  4d 03 03 00 00 00 00 00  |....Q...M.......|
 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 20 90 da 90 3e  |........... ...>|
-00000030  36 19 7a db 56 43 26 f7  dc 42 57 33 22 ed 9d a4  |6.z.VC&..BW3"...|
-00000040  9d 53 da f8 9d 4e 60 66  71 a0 2e 2e 00 05 00 00  |.S...N`fq.......|
+00000020  00 00 00 00 00 00 00 00  00 00 00 20 b4 06 b0 ec  |........... ....|
+00000030  cf b7 52 6e 38 10 31 37  b2 e6 58 0f fa e3 b0 cb  |..Rn8.17..X.....|
+00000040  20 a4 d2 4b f3 7d 92 e6  7e 13 37 08 00 05 00 00  | ..K.}..~.7.....|
 00000050  05 ff 01 00 01 00 14 03  03 00 01 01 16 03 03 00  |................|
-00000060  24 11 12 ff 28 10 14 4c  e5 0e ad a7 fa f3 92 fb  |$...(..L........|
-00000070  13 7d ae f2 b2 4a 6b a1  9e 67 cf a8 f7 8c 6f a0  |.}...Jk..g....o.|
-00000080  6c 30 0e 18 55                                    |l0..U|
+00000060  24 24 31 13 8c 45 4f 8a  fc 71 50 94 b0 6f 02 5e  |$$1..EO..qP..o.^|
+00000070  da d3 a3 13 8b c8 53 fb  54 8d ef 90 f7 55 b1 be  |......S.T....U..|
+00000080  37 30 05 e5 5d                                    |70..]|
 >>> Flow 3 (client to server)
-00000000  14 03 03 00 01 01 16 03  03 00 24 0d 46 41 8b 24  |..........$.FA.$|
-00000010  36 01 a9 fd 8b ec fc e6  b1 83 96 df 0d 3e 53 54  |6............>ST|
-00000020  58 b8 43 f2 a6 25 5e 1a  ae 19 9e d2 28 44 92     |X.C..%^.....(D.|
+00000000  14 03 03 00 01 01 16 03  03 00 24 ed dd e4 a5 09  |..........$.....|
+00000010  0d 7c cb e4 90 9c a1 1c  21 f4 13 bd 45 8f f4 d8  |.|......!...E...|
+00000020  7e e2 89 7a 0d f4 75 99  66 8c 05 a3 1a e2 2b     |~..z..u.f.....+|
 >>> Flow 4 (server to client)
-00000000  17 03 03 00 21 c4 fb f6  53 bb 3e 04 cc 0b a0 03  |....!...S.>.....|
-00000010  fa 49 96 da b5 8d b2 f2  e5 d8 f3 5c 27 57 4f 9c  |.I.........\'WO.|
-00000020  30 00 34 fc 52 92 15 03  03 00 16 a3 02 7a 50 d2  |0.4.R........zP.|
-00000030  c6 b3 fc 69 8f e4 94 ae  ab 22 ad 05 1d 15 69 b9  |...i....."....i.|
-00000040  a5                                                |.|
+00000000  17 03 03 00 21 69 fa 9e  98 fb 7a 95 b1 8e e5 74  |....!i....z....t|
+00000010  03 02 d7 3d 69 c4 b8 c9  5b 49 e3 30 32 e3 c5 6a  |...=i...[I.02..j|
+00000020  fa 20 98 bd 01 ed 15 03  03 00 16 c9 b1 20 1f 30  |. ........... .0|
+00000030  c1 2f 15 75 cd 82 45 de  1a 81 cd dc 10 05 1c 45  |./.u..E........E|
+00000040  dc                                                |.|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-ResumeDisabled b/src/crypto/tls/testdata/Server-TLSv12-ResumeDisabled
index db833f6..912c178 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-ResumeDisabled
+++ b/src/crypto/tls/testdata/Server-TLSv12-ResumeDisabled
@@ -1,87 +1,83 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 e8 01 00 00  e4 03 03 54 23 54 02 a5  |...........T#T..|
-00000010  10 11 0f 6d e5 2d 2f e8  bb 52 b1 38 3f 65 01 43  |...m.-/..R.8?e.C|
-00000020  36 cc 48 f6 09 22 a1 85  20 28 3c 20 35 8b fe 7a  |6.H..".. (< 5..z|
-00000030  41 3b 59 3a 5d b9 b3 21  f0 62 e9 0d 7b af f5 5d  |A;Y:]..!.b..{..]|
-00000040  fa 65 1a 40 c8 ca cd 74  8c ef d2 fb 00 04 00 05  |.e. at ...t........|
-00000050  00 ff 01 00 00 97 00 23  00 68 00 00 00 00 00 00  |.......#.h......|
-00000060  00 00 00 00 00 00 00 00  00 00 65 ea 4b d1 ef ba  |..........e.K...|
-00000070  2d db 0c ba 9a d4 20 76  57 c8 ec dc 2d 77 fb fb  |-..... vW...-w..|
-00000080  3b 93 5f 53 e0 14 4f 90  fb d6 55 57 8c 8d 0d 25  |;._S..O...UW...%|
-00000090  ea 5d 0d f2 91 e5 12 22  12 ec 7b 5f b6 6e fd 07  |.]....."..{_.n..|
-000000a0  59 23 24 fc b1 97 ca ea  56 a5 c2 a0 e4 9e 99 64  |Y#$.....V......d|
-000000b0  f2 64 d0 75 7a 46 63 e3  dc 21 ed 78 56 e9 e1 ab  |.d.uzFc..!.xV...|
-000000c0  66 80 00 0d 00 22 00 20  06 01 06 02 06 03 05 01  |f....". ........|
-000000d0  05 02 05 03 04 01 04 02  04 03 03 01 03 02 03 03  |................|
-000000e0  02 01 02 02 02 03 01 01  00 0f 00 01 01           |.............|
+00000000  16 03 01 00 f6 01 00 00  f2 03 03 aa 0c c2 75 42  |..............uB|
+00000010  62 2a 1d 14 a0 cc a1 e4  a7 19 77 50 80 2b f8 05  |b*........wP.+..|
+00000020  0b fa 60 3a a7 a7 84 d3  e1 68 26 20 68 97 0c ae  |..`:.....h& h...|
+00000030  7b 1d bc 13 14 a8 f6 c1  e1 96 1f 54 18 2c cb 99  |{..........T.,..|
+00000040  17 7d be 45 6a 39 53 c6  50 c7 8c 75 00 04 00 05  |.}.Ej9S.P..u....|
+00000050  00 ff 01 00 00 a5 00 23  00 78 50 46 ad c1 db a8  |.......#.xPF....|
+00000060  38 86 7b 2b bb fd d0 c3  42 3e 00 00 00 00 00 00  |8.{+....B>......|
+00000070  00 00 00 00 00 00 00 00  00 00 94 6f 2c b5 83 61  |...........o,..a|
+00000080  bd 50 da 49 7f 8b 8f 58  57 00 a1 11 0d 4a 9d 8a  |.P.I...XW....J..|
+00000090  39 dd 85 23 c0 eb 9d 1a  45 93 92 e7 af 15 a3 a4  |9..#....E.......|
+000000a0  48 da f9 a4 d8 8e cb 6c  3d 44 77 f9 c4 83 89 85  |H......l=Dw.....|
+000000b0  33 94 c1 c6 20 9a 73 44  83 89 5e 59 ee 05 c6 7e  |3... .sD..^Y...~|
+000000c0  8d e9 7d 7b f8 84 46 b6  7d 43 ec f1 af 1f 0f 35  |..}{..F.}C.....5|
+000000d0  b4 1c 00 0d 00 20 00 1e  06 01 06 02 06 03 05 01  |..... ..........|
+000000e0  05 02 05 03 04 01 04 02  04 03 03 01 03 02 03 03  |................|
+000000f0  02 01 02 02 02 03 00 0f  00 01 01                 |...........|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
 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 05 00 00  |................|
-00000030  05 ff 01 00 01 00 16 03  03 02 be 0b 00 02 ba 00  |................|
-00000040  02 b7 00 02 b4 30 82 02  b0 30 82 02 19 a0 03 02  |.....0...0......|
-00000050  01 02 02 09 00 85 b0 bb  a4 8a 7f b8 ca 30 0d 06  |.............0..|
-00000060  09 2a 86 48 86 f7 0d 01  01 05 05 00 30 45 31 0b  |.*.H........0E1.|
-00000070  30 09 06 03 55 04 06 13  02 41 55 31 13 30 11 06  |0...U....AU1.0..|
-00000080  03 55 04 08 13 0a 53 6f  6d 65 2d 53 74 61 74 65  |.U....Some-State|
-00000090  31 21 30 1f 06 03 55 04  0a 13 18 49 6e 74 65 72  |1!0...U....Inter|
-000000a0  6e 65 74 20 57 69 64 67  69 74 73 20 50 74 79 20  |net Widgits Pty |
-000000b0  4c 74 64 30 1e 17 0d 31  30 30 34 32 34 30 39 30  |Ltd0...100424090|
-000000c0  39 33 38 5a 17 0d 31 31  30 34 32 34 30 39 30 39  |938Z..1104240909|
-000000d0  33 38 5a 30 45 31 0b 30  09 06 03 55 04 06 13 02  |38Z0E1.0...U....|
-000000e0  41 55 31 13 30 11 06 03  55 04 08 13 0a 53 6f 6d  |AU1.0...U....Som|
-000000f0  65 2d 53 74 61 74 65 31  21 30 1f 06 03 55 04 0a  |e-State1!0...U..|
-00000100  13 18 49 6e 74 65 72 6e  65 74 20 57 69 64 67 69  |..Internet Widgi|
-00000110  74 73 20 50 74 79 20 4c  74 64 30 81 9f 30 0d 06  |ts Pty Ltd0..0..|
-00000120  09 2a 86 48 86 f7 0d 01  01 01 05 00 03 81 8d 00  |.*.H............|
-00000130  30 81 89 02 81 81 00 bb  79 d6 f5 17 b5 e5 bf 46  |0.......y......F|
-00000140  10 d0 dc 69 be e6 2b 07  43 5a d0 03 2d 8a 7a 43  |...i..+.CZ..-.zC|
-00000150  85 b7 14 52 e7 a5 65 4c  2c 78 b8 23 8c b5 b4 82  |...R..eL,x.#....|
-00000160  e5 de 1f 95 3b 7e 62 a5  2c a5 33 d6 fe 12 5c 7a  |....;~b.,.3...\z|
-00000170  56 fc f5 06 bf fa 58 7b  26 3f b5 cd 04 d3 d0 c9  |V.....X{&?......|
-00000180  21 96 4a c7 f4 54 9f 5a  bf ef 42 71 00 fe 18 99  |!.J..T.Z..Bq....|
-00000190  07 7f 7e 88 7d 7d f1 04  39 c4 a2 2e db 51 c9 7c  |..~.}}..9....Q.||
-000001a0  e3 c0 4c 3b 32 66 01 cf  af b1 1d b8 71 9a 1d db  |..L;2f......q...|
-000001b0  db 89 6b ae da 2d 79 02  03 01 00 01 a3 81 a7 30  |..k..-y........0|
-000001c0  81 a4 30 1d 06 03 55 1d  0e 04 16 04 14 b1 ad e2  |..0...U.........|
-000001d0  85 5a cf cb 28 db 69 ce  23 69 de d3 26 8e 18 88  |.Z..(.i.#i..&...|
-000001e0  39 30 75 06 03 55 1d 23  04 6e 30 6c 80 14 b1 ad  |90u..U.#.n0l....|
-000001f0  e2 85 5a cf cb 28 db 69  ce 23 69 de d3 26 8e 18  |..Z..(.i.#i..&..|
-00000200  88 39 a1 49 a4 47 30 45  31 0b 30 09 06 03 55 04  |.9.I.G0E1.0...U.|
-00000210  06 13 02 41 55 31 13 30  11 06 03 55 04 08 13 0a  |...AU1.0...U....|
-00000220  53 6f 6d 65 2d 53 74 61  74 65 31 21 30 1f 06 03  |Some-State1!0...|
-00000230  55 04 0a 13 18 49 6e 74  65 72 6e 65 74 20 57 69  |U....Internet Wi|
-00000240  64 67 69 74 73 20 50 74  79 20 4c 74 64 82 09 00  |dgits Pty Ltd...|
-00000250  85 b0 bb a4 8a 7f b8 ca  30 0c 06 03 55 1d 13 04  |........0...U...|
-00000260  05 30 03 01 01 ff 30 0d  06 09 2a 86 48 86 f7 0d  |.0....0...*.H...|
-00000270  01 01 05 05 00 03 81 81  00 08 6c 45 24 c7 6b b1  |..........lE$.k.|
-00000280  59 ab 0c 52 cc f2 b0 14  d7 87 9d 7a 64 75 b5 5a  |Y..R.......zdu.Z|
-00000290  95 66 e4 c5 2b 8e ae 12  66 1f eb 4f 38 b3 6e 60  |.f..+...f..O8.n`|
-000002a0  d3 92 fd f7 41 08 b5 25  13 b1 18 7a 24 fb 30 1d  |....A..%...z$.0.|
-000002b0  ba ed 98 b9 17 ec e7 d7  31 59 db 95 d3 1d 78 ea  |........1Y....x.|
-000002c0  50 56 5c d5 82 5a 2d 5a  5f 33 c4 b6 d8 c9 75 90  |PV\..Z-Z_3....u.|
-000002d0  96 8c 0f 52 98 b5 cd 98  1f 89 20 5f f2 a0 1c a3  |...R...... _....|
-000002e0  1b 96 94 dd a9 fd 57 e9  70 e8 26 6d 71 99 9b 26  |......W.p.&mq..&|
-000002f0  6e 38 50 29 6c 90 a7 bd  d9 16 03 03 00 04 0e 00  |n8P)l...........|
-00000300  00 00                                             |..|
+00000030  05 ff 01 00 01 00 16 03  03 02 71 0b 00 02 6d 00  |..........q...m.|
+00000040  02 6a 00 02 67 30 82 02  63 30 82 01 cc a0 03 02  |.j..g0..c0......|
+00000050  01 02 02 09 00 a2 73 00  0c 81 00 cb f3 30 0d 06  |......s......0..|
+00000060  09 2a 86 48 86 f7 0d 01  01 0b 05 00 30 2b 31 17  |.*.H........0+1.|
+00000070  30 15 06 03 55 04 0a 13  0e 47 6f 6f 67 6c 65 20  |0...U....Google |
+00000080  54 45 53 54 49 4e 47 31  10 30 0e 06 03 55 04 03  |TESTING1.0...U..|
+00000090  13 07 47 6f 20 52 6f 6f  74 30 1e 17 0d 31 35 30  |..Go Root0...150|
+000000a0  31 30 31 30 30 30 30 30  30 5a 17 0d 32 35 30 31  |101000000Z..2501|
+000000b0  30 31 30 30 30 30 30 30  5a 30 26 31 17 30 15 06  |01000000Z0&1.0..|
+000000c0  03 55 04 0a 13 0e 47 6f  6f 67 6c 65 20 54 45 53  |.U....Google TES|
+000000d0  54 49 4e 47 31 0b 30 09  06 03 55 04 03 13 02 47  |TING1.0...U....G|
+000000e0  6f 30 81 9f 30 0d 06 09  2a 86 48 86 f7 0d 01 01  |o0..0...*.H.....|
+000000f0  01 05 00 03 81 8d 00 30  81 89 02 81 81 00 af 87  |.......0........|
+00000100  88 f6 20 1b 95 65 6c 14  ab 44 05 af 3b 45 14 e3  |.. ..el..D..;E..|
+00000110  b7 6d fd 00 63 4d 95 7f  fe 6a 62 35 86 c0 4a f9  |.m..cM...jb5..J.|
+00000120  18 7c f6 aa 25 5e 7a 64  31 66 00 ba f4 8e 92 af  |.|..%^zd1f......|
+00000130  c7 6b d8 76 d4 f3 5f 41  cb 6e 56 15 97 1b 97 c1  |.k.v.._A.nV.....|
+00000140  3c 12 39 21 66 3d 2b 16  d1 bc db 1c c0 a7 da b7  |<.9!f=+.........|
+00000150  ca ad ba da cb d5 21 50  ec de 8d ab d1 6b 81 4b  |......!P.....k.K|
+00000160  89 02 f3 c4 be c1 6c 89  b1 44 84 bd 21 d1 04 7d  |......l..D..!..}|
+00000170  9d 16 4d f9 82 15 f6 ef  fa d6 09 47 f2 fb 02 03  |..M........G....|
+00000180  01 00 01 a3 81 93 30 81  90 30 0e 06 03 55 1d 0f  |......0..0...U..|
+00000190  01 01 ff 04 04 03 02 05  a0 30 1d 06 03 55 1d 25  |.........0...U.%|
+000001a0  04 16 30 14 06 08 2b 06  01 05 05 07 03 01 06 08  |..0...+.........|
+000001b0  2b 06 01 05 05 07 03 02  30 0c 06 03 55 1d 13 01  |+.......0...U...|
+000001c0  01 ff 04 02 30 00 30 19  06 03 55 1d 0e 04 12 04  |....0.0...U.....|
+000001d0  10 12 50 8d 89 6f 1b d1  dc 54 4d 6e cb 69 5e 06  |..P..o...TMn.i^.|
+000001e0  f4 30 1b 06 03 55 1d 23  04 14 30 12 80 10 bf 3d  |.0...U.#..0....=|
+000001f0  b6 a9 66 f2 b8 40 cf ea  b4 03 78 48 1a 41 30 19  |..f.. at ....xH.A0.|
+00000200  06 03 55 1d 11 04 12 30  10 82 0e 65 78 61 6d 70  |..U....0...examp|
+00000210  6c 65 2e 67 6f 6c 61 6e  67 30 0d 06 09 2a 86 48  |le.golang0...*.H|
+00000220  86 f7 0d 01 01 0b 05 00  03 81 81 00 92 7c af 91  |.............|..|
+00000230  55 12 18 96 59 31 a6 48  40 d5 2d d5 ee bb 02 a0  |U...Y1.H at .-.....|
+00000240  f5 c2 1e 7c 9b b3 30 7d  3c dc 76 da 4f 3d c0 fa  |...|..0}<.v.O=..|
+00000250  ae 2d 33 24 6b 03 7b 1b  67 59 11 21 b5 11 bc 77  |.-3$k.{.gY.!...w|
+00000260  b9 d9 e0 6e a8 2d 2e 35  fa 64 5f 22 3e 63 10 6b  |...n.-.5.d_">c.k|
+00000270  be ff 14 86 6d 0d f0 15  31 a8 14 38 1e 3b 84 87  |....m...1..8.;..|
+00000280  2c cb 98 ed 51 76 b9 b1  4f dd db 9b 84 04 86 40  |,...Qv..O......@|
+00000290  fa 51 dd ba b4 8d eb e3  46 de 46 b9 4f 86 c7 f9  |.Q......F.F.O...|
+000002a0  a4 c2 41 34 ac cc f6 ea  b0 ab 39 18 16 03 03 00  |..A4......9.....|
+000002b0  04 0e 00 00 00                                    |.....|
 >>> Flow 3 (client to server)
-00000000  16 03 03 00 86 10 00 00  82 00 80 ae 02 dd 1f 1a  |................|
-00000010  86 83 f5 2f 82 46 4b 29  58 aa a1 b3 56 8b 4e 40  |.../.FK)X...V.N@|
-00000020  ef 23 65 67 ad 48 e5 e1  fd ae dd bf 68 fd bd a6  |.#eg.H......h...|
-00000030  13 a0 7e 05 ab f7 20 e1  6a 4e d1 37 93 08 1d c9  |..~... .jN.7....|
-00000040  37 e0 b5 34 28 bf 20 45  45 da 0f 7e 51 a7 c6 ae  |7..4(. EE..~Q...|
-00000050  61 6c 07 1b 73 ef da 6e  25 c4 ed be e3 3f da ae  |al..s..n%....?..|
-00000060  cd 3c 17 9c 2e ee fb 47  9d b3 a1 b2 c3 5d e0 83  |.<.....G.....]..|
-00000070  74 20 37 2d 72 d6 d0 4d  58 0e 26 1c 50 22 95 08  |t 7-r..MX.&.P"..|
-00000080  7d e0 5f 86 99 9e 2c 2e  a7 a0 7f 14 03 03 00 01  |}._...,.........|
-00000090  01 16 03 03 00 24 a2 ab  41 25 a5 cf 04 18 1d 98  |.....$..A%......|
-000000a0  88 6c 59 21 86 33 54 f4  35 b4 21 6e a5 29 d5 6e  |.lY!.3T.5.!n.).n|
-000000b0  3d 08 72 b0 af 46 b5 8f  6b 86                    |=.r..F..k.|
+00000000  16 03 03 00 86 10 00 00  82 00 80 ac 10 32 61 b0  |.............2a.|
+00000010  03 e3 1e 2f 89 91 5f d6  4c e0 82 a7 82 41 67 d3  |.../.._.L....Ag.|
+00000020  5f b3 68 2d c0 d1 6f 03  7b 79 94 cc bb 35 6c 8a  |_.h-..o.{y...5l.|
+00000030  bf 1c 83 ff 88 91 5c 04  64 cc a0 df 0b 08 8c 0f  |......\.d.......|
+00000040  72 13 17 9f 27 14 8d 9a  af 17 70 41 44 9f 89 8c  |r...'.....pAD...|
+00000050  fa e4 66 33 4d bd 2f 93  2a 1e 85 a1 af 9e 27 12  |..f3M./.*.....'.|
+00000060  59 a4 13 67 56 85 c2 86  47 f8 c5 49 8f a4 c2 6e  |Y..gV...G..I...n|
+00000070  04 78 0f 11 2b fb 7e 34  b8 eb 25 93 71 ab 9f f5  |.x..+.~4..%.q...|
+00000080  93 df 2b c3 1e 9e 6a 9e  e3 57 aa 14 03 03 00 01  |..+...j..W......|
+00000090  01 16 03 03 00 24 e0 13  15 10 4c db f3 b6 de d2  |.....$....L.....|
+000000a0  68 02 f5 ea 1f 8e 58 70  4a 5a 78 d9 66 c5 74 77  |h.....XpJZx.f.tw|
+000000b0  a0 3a ec d8 b7 42 e3 a5  d4 62                    |.:...B...b|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 24 59 20 4d c2 17  |..........$Y M..|
-00000010  8b 3c 9b 33 d9 f9 ef fb  80 18 1f 67 a7 58 12 89  |.<.3.......g.X..|
-00000020  4e 73 0f 2d 7b e6 c4 a6  79 73 01 da 22 e8 54 17  |Ns.-{...ys..".T.|
-00000030  03 03 00 21 36 ca 64 0f  4a 12 a5 50 3d 97 bb 39  |...!6.d.J..P=..9|
-00000040  02 fc ed d1 82 6a 9a 2e  21 79 f6 e1 b3 cc 32 db  |.....j..!y....2.|
-00000050  0f 5d b3 fb a5 15 03 03  00 16 51 f4 be 57 7a df  |.]........Q..Wz.|
-00000060  f1 f2 bd b5 51 5e 45 80  be 0b 9a 0c d1 19 3c 79  |....Q^E.......<y|
+00000000  14 03 03 00 01 01 16 03  03 00 24 e9 c1 1f 5b e6  |..........$...[.|
+00000010  c1 d5 8a 14 eb c6 41 c1  77 6d 59 83 b6 95 34 f9  |......A.wmY...4.|
+00000020  7b a1 c9 9d 58 a5 b2 1b  33 6e 04 ab e0 03 61 17  |{...X...3n....a.|
+00000030  03 03 00 21 67 8b 55 43  d7 a7 05 c9 1f a0 d3 65  |...!g.UC.......e|
+00000040  30 36 07 8f d8 52 7e 40  79 31 2e 1c 1a c2 a6 fe  |06...R~@y1......|
+00000050  e0 39 4d a0 5d 15 03 03  00 16 b8 94 fb 17 e5 1d  |.9M.]...........|
+00000060  2e 28 95 cf 02 85 8e 11  2e 16 b1 53 72 aa a4 94  |.(.........Sr...|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-SNI b/src/crypto/tls/testdata/Server-TLSv12-SNI
index 61b17a1..aee5742 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-SNI
+++ b/src/crypto/tls/testdata/Server-TLSv12-SNI
@@ -1,12 +1,12 @@
 >>> Flow 1 (client to server)
-00000000  16 03 01 00 70 01 00 00  6c 03 03 52 cc 57 59 2d  |....p...l..R.WY-|
-00000010  77 aa 75 35 fa ff 2a a2  bf 91 5e e3 7f 38 7d 7a  |w.u5..*...^..8}z|
-00000020  e3 93 d3 e8 8b 09 bb 06  c8 6d 91 00 00 04 00 2f  |.........m...../|
-00000030  00 ff 01 00 00 3f 00 00  00 10 00 0e 00 00 0b 73  |.....?.........s|
-00000040  6e 69 74 65 73 74 2e 63  6f 6d 00 0d 00 22 00 20  |nitest.com...". |
+00000000  16 03 01 00 6e 01 00 00  6a 03 03 be 99 22 5c d2  |....n...j...."\.|
+00000010  02 c7 a6 be f3 33 7a d4  76 1f cf 1e 39 0b 25 7c  |.....3z.v...9.%||
+00000020  32 70 e4 8c 49 a6 87 b9  c1 2f 6d 00 00 04 00 2f  |2p..I..../m..../|
+00000030  00 ff 01 00 00 3d 00 00  00 10 00 0e 00 00 0b 73  |.....=.........s|
+00000040  6e 69 74 65 73 74 2e 63  6f 6d 00 0d 00 20 00 1e  |nitest.com... ..|
 00000050  06 01 06 02 06 03 05 01  05 02 05 03 04 01 04 02  |................|
-00000060  04 03 03 01 03 02 03 03  02 01 02 02 02 03 01 01  |................|
-00000070  00 0f 00 01 01                                    |.....|
+00000060  04 03 03 01 03 02 03 03  02 01 02 02 02 03 00 0f  |................|
+00000070  00 01 01                                          |...|
 >>> Flow 2 (server to client)
 00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
@@ -46,31 +46,19 @@
 00000230  2c 65 25 d6 52 b6 e3 18  45 bd cc 16 03 03 00 04  |,e%.R...E.......|
 00000240  0e 00 00 00                                       |....|
 >>> Flow 3 (client to server)
-00000000  16 03 03 00 86 10 00 00  82 00 80 0d f2 bf 75 a9  |..............u.|
-00000010  aa db f3 25 55 d4 20 59  63 54 d1 70 82 f9 61 c5  |...%U. YcT.p..a.|
-00000020  b7 ae 3f 75 71 75 9d c5  01 a1 ed b1 07 66 9f 3f  |..?uqu.......f.?|
-00000030  cf c6 e6 ad 44 03 fd 18  6f 53 24 ce 76 01 bd fe  |....D...oS$.v...|
-00000040  e2 51 f7 df 8a 23 3a 21  c4 00 15 ff d0 e0 ff c8  |.Q...#:!........|
-00000050  8b 89 33 c6 8e e0 ce 97  ef b4 c6 f9 b0 ea 38 89  |..3...........8.|
-00000060  79 98 34 9e f7 bc c6 fd  d2 5d 56 84 5c d2 9a ce  |y.4......]V.\...|
-00000070  ae de 09 bc 24 25 fc 09  0c bc 0e 91 0d 6b 36 ae  |....$%.......k6.|
-00000080  ce 6b cd 14 ec b6 3c fa  d6 df fc 14 03 03 00 01  |.k....<.........|
-00000090  01 16 03 03 00 40 ad 21  13 2b 33 7a 4a 0d fb 0f  |..... at .!.+3zJ...|
-000000a0  eb d2 b6 85 29 1f 59 79  ba 86 53 5c 68 b4 c7 e3  |....).Yy..S\h...|
-000000b0  8a 6c 5c 18 04 4d e4 76  19 30 ba 92 b4 79 8c 64  |.l\..M.v.0...y.d|
-000000c0  00 a0 2e 13 96 45 9f e7  a9 e4 23 9e 9f 89 23 26  |.....E....#...#&|
-000000d0  36 20 82 fc 75 fe                                 |6 ..u.|
+00000000  16 03 03 00 86 10 00 00  82 00 80 6b 03 31 ca a0  |...........k.1..|
+00000010  62 a2 53 11 ce 13 d9 f6  e7 d4 ec 2e c3 0a 38 56  |b.S...........8V|
+00000020  23 22 67 23 c8 8d 16 b4  3c 0b 26 9f 1c 2d 65 13  |#"g#....<.&..-e.|
+00000030  c3 cb 65 69 b0 47 ff 87  e8 02 56 c4 77 8a 40 29  |..ei.G....V.w.@)|
+00000040  82 62 8b 06 61 0a 1c b3  c7 29 b6 aa c9 96 37 18  |.b..a....)....7.|
+00000050  d0 60 66 63 9b 62 4b 30  cc 03 9c 37 05 c6 32 98  |.`fc.bK0...7..2.|
+00000060  cb a0 e2 e4 38 60 d4 93  99 9a fc 03 66 fb b6 ef  |....8`......f...|
+00000070  8a 1e bb ca 13 c5 d9 7a  7c 3b 50 dc d0 ad 00 b5  |.......z|;P.....|
+00000080  2c dc 1a ef c4 5c af d3  4e cd e6 14 03 03 00 01  |,....\..N.......|
+00000090  01 16 03 03 00 40 42 31  83 8a 2c 86 22 c5 df e5  |..... at B1..,."...|
+000000a0  f2 0b f8 0c 2f 1e 82 f4  69 fe 1d bd 4c db f1 80  |..../...i...L...|
+000000b0  68 30 b7 e3 60 76 b3 f1  52 ae d6 e7 b3 cb 4a e0  |h0..`v..R.....J.|
+000000c0  27 0a c1 1a 72 ed 71 ab  0a fc 10 d9 5e 4d fd 10  |'...r.q.....^M..|
+000000d0  04 92 39 78 be 23                                 |..9x.#|
 >>> Flow 4 (server to client)
-00000000  14 03 03 00 01 01 16 03  03 00 40 00 00 00 00 00  |.......... at .....|
-00000010  00 00 00 00 00 00 00 00  00 00 00 b7 87 61 10 03  |.............a..|
-00000020  b8 a4 42 d4 8b 49 bc 40  80 70 92 c8 25 b0 c6 7f  |..B..I. at .p..%...|
-00000030  b3 87 76 50 5a 59 b3 3c  d8 3e 23 24 aa 1a f3 36  |..vPZY.<.>#$...6|
-00000040  c9 2c 87 c1 22 d2 94 f8  2c fd ef 17 03 03 00 40  |.,.."...,......@|
-00000050  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
-00000060  e5 7f bd 3e ff 9f d4 1b  91 02 f8 69 6f 70 9d 51  |...>.......iop.Q|
-00000070  a5 ec ef 5b 10 3f 4e 3f  44 e5 9a 39 68 7c 3a b9  |...[.?N?D..9h|:.|
-00000080  69 38 31 ec 9c 45 bf 19  d1 5c 5e 2e 06 00 ca 19  |i81..E...\^.....|
-00000090  15 03 03 00 30 00 00 00  00 00 00 00 00 00 00 00  |....0...........|
-000000a0  00 00 00 00 00 63 5e 79  2c f2 05 dc 2b d7 5b ac  |.....c^y,...+.[.|
-000000b0  9d fc 75 94 03 16 ca 1f  b2 75 58 2d f1 2f f1 1e  |..u......uX-./..|
-000000c0  d2 f6 84 8f 2e                                    |.....|
+00000000  15 03 03 00 02 02 14                              |.......|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-SNI-GetCertificate b/src/crypto/tls/testdata/Server-TLSv12-SNI-GetCertificate
new file mode 100644
index 0000000..40d3714
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv12-SNI-GetCertificate
@@ -0,0 +1,64 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 6e 01 00 00  6a 03 03 23 de 75 da 8e  |....n...j..#.u..|
+00000010  0a 4b 7b e4 cb 34 14 83  be d1 6a 95 25 86 f8 91  |.K{..4....j.%...|
+00000020  d8 bb ac 82 9e 19 d6 9f  52 26 f6 00 00 04 00 2f  |........R&...../|
+00000030  00 ff 01 00 00 3d 00 00  00 10 00 0e 00 00 0b 73  |.....=.........s|
+00000040  6e 69 74 65 73 74 2e 63  6f 6d 00 0d 00 20 00 1e  |nitest.com... ..|
+00000050  06 01 06 02 06 03 05 01  05 02 05 03 04 01 04 02  |................|
+00000060  04 03 03 01 03 02 03 03  02 01 02 02 02 03 00 0f  |................|
+00000070  00 01 01                                          |...|
+>>> Flow 2 (server to client)
+00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
+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 2f 00 00  |............./..|
+00000030  05 ff 01 00 01 00 16 03  03 02 00 0b 00 01 fc 00  |................|
+00000040  01 f9 00 01 f6 30 82 01  f2 30 82 01 5d a0 03 02  |.....0...0..]...|
+00000050  01 02 02 01 00 30 0b 06  09 2a 86 48 86 f7 0d 01  |.....0...*.H....|
+00000060  01 05 30 28 31 10 30 0e  06 03 55 04 0a 13 07 41  |..0(1.0...U....A|
+00000070  63 6d 65 20 43 6f 31 14  30 12 06 03 55 04 03 13  |cme Co1.0...U...|
+00000080  0b 73 6e 69 74 65 73 74  2e 63 6f 6d 30 1e 17 0d  |.snitest.com0...|
+00000090  31 32 30 34 31 31 31 37  34 30 33 35 5a 17 0d 31  |120411174035Z..1|
+000000a0  33 30 34 31 31 31 37 34  35 33 35 5a 30 28 31 10  |30411174535Z0(1.|
+000000b0  30 0e 06 03 55 04 0a 13  07 41 63 6d 65 20 43 6f  |0...U....Acme Co|
+000000c0  31 14 30 12 06 03 55 04  03 13 0b 73 6e 69 74 65  |1.0...U....snite|
+000000d0  73 74 2e 63 6f 6d 30 81  9d 30 0b 06 09 2a 86 48  |st.com0..0...*.H|
+000000e0  86 f7 0d 01 01 01 03 81  8d 00 30 81 89 02 81 81  |..........0.....|
+000000f0  00 bb 79 d6 f5 17 b5 e5  bf 46 10 d0 dc 69 be e6  |..y......F...i..|
+00000100  2b 07 43 5a d0 03 2d 8a  7a 43 85 b7 14 52 e7 a5  |+.CZ..-.zC...R..|
+00000110  65 4c 2c 78 b8 23 8c b5  b4 82 e5 de 1f 95 3b 7e  |eL,x.#........;~|
+00000120  62 a5 2c a5 33 d6 fe 12  5c 7a 56 fc f5 06 bf fa  |b.,.3...\zV.....|
+00000130  58 7b 26 3f b5 cd 04 d3  d0 c9 21 96 4a c7 f4 54  |X{&?......!.J..T|
+00000140  9f 5a bf ef 42 71 00 fe  18 99 07 7f 7e 88 7d 7d  |.Z..Bq......~.}}|
+00000150  f1 04 39 c4 a2 2e db 51  c9 7c e3 c0 4c 3b 32 66  |..9....Q.|..L;2f|
+00000160  01 cf af b1 1d b8 71 9a  1d db db 89 6b ae da 2d  |......q.....k..-|
+00000170  79 02 03 01 00 01 a3 32  30 30 30 0e 06 03 55 1d  |y......2000...U.|
+00000180  0f 01 01 ff 04 04 03 02  00 a0 30 0d 06 03 55 1d  |..........0...U.|
+00000190  0e 04 06 04 04 01 02 03  04 30 0f 06 03 55 1d 23  |.........0...U.#|
+000001a0  04 08 30 06 80 04 01 02  03 04 30 0b 06 09 2a 86  |..0.......0...*.|
+000001b0  48 86 f7 0d 01 01 05 03  81 81 00 89 c6 45 5f 1c  |H............E_.|
+000001c0  1f 5e f8 eb 1a b1 74 ee  24 39 05 9f 5c 42 59 bb  |.^....t.$9..\BY.|
+000001d0  1a 8d 86 cd b1 d0 56 f5  6a 71 7d a4 0e 95 ab 90  |......V.jq}.....|
+000001e0  f5 9e 8d ea f6 27 c1 57  99 50 94 db 08 02 26 6e  |.....'.W.P....&n|
+000001f0  b3 4f c6 84 2d ea 8a 4b  68 d9 c1 38 91 03 ab 84  |.O..-..Kh..8....|
+00000200  fb 9e 1f 85 d9 b5 d2 3f  f2 31 2c 86 70 fb b5 40  |.......?.1,.p..@|
+00000210  14 82 45 a4 eb af e2 64  d9 0c 8a 4c f4 f8 5b 0f  |..E....d...L..[.|
+00000220  ac 12 ac 2f c4 a3 15 4b  ad 52 46 28 68 af 96 c6  |.../...K.RF(h...|
+00000230  2c 65 25 d6 52 b6 e3 18  45 bd cc 16 03 03 00 04  |,e%.R...E.......|
+00000240  0e 00 00 00                                       |....|
+>>> Flow 3 (client to server)
+00000000  16 03 03 00 86 10 00 00  82 00 80 a2 99 61 c5 90  |.............a..|
+00000010  47 1a e7 47 56 51 59 e4  6e ab 82 01 18 78 ee 95  |G..GVQY.n....x..|
+00000020  b8 e2 c7 c7 f9 64 98 dd  84 8d 96 d9 2d 08 62 1e  |.....d......-.b.|
+00000030  4f 29 83 b6 93 68 77 7a  14 1b f0 b3 1a 67 7b 7a  |O)...hwz.....g{z|
+00000040  f9 54 f3 7e 6d eb b6 7a  c9 37 70 6a 83 68 f2 15  |.T.~m..z.7pj.h..|
+00000050  81 07 30 6e b8 fa 19 0e  46 dc d6 9a 4a 8e 8d f1  |..0n....F...J...|
+00000060  05 78 60 75 d4 00 d9 1e  11 5f 16 f7 bc 9f e8 8a  |.x`u....._......|
+00000070  c4 3e bd d9 1a b8 67 50  00 be 5f 43 ee 07 ad be  |.>....gP.._C....|
+00000080  f5 85 67 fc 8f c6 87 47  6d 6e b2 14 03 03 00 01  |..g....Gmn......|
+00000090  01 16 03 03 00 40 91 7d  7b 05 99 48 05 70 a9 67  |..... at .}{..H.p.g|
+000000a0  e9 7a 0a c3 6b bf b0 ad  68 65 17 fb 18 bf 8d bd  |.z..k...he......|
+000000b0  e1 4b 12 bf ea 82 9d a6  1e 3a c8 77 65 32 bd 5e  |.K.......:.we2.^|
+000000c0  c4 46 da e7 e1 ac 09 fe  4a ac bc 57 6a 17 7d dc  |.F......J..Wj.}.|
+000000d0  fe 9c d0 d0 6e fc                                 |....n.|
+>>> Flow 4 (server to client)
+00000000  15 03 03 00 02 02 14                              |.......|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-SNI-GetCertificateNotFound b/src/crypto/tls/testdata/Server-TLSv12-SNI-GetCertificateNotFound
new file mode 100644
index 0000000..904f69e
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv12-SNI-GetCertificateNotFound
@@ -0,0 +1,64 @@
+>>> Flow 1 (client to server)
+00000000  16 03 01 00 6e 01 00 00  6a 03 03 27 db e3 e8 f4  |....n...j..'....|
+00000010  48 1d 45 d5 20 64 97 b2  20 a6 67 94 7a 1e 87 12  |H.E. d.. .g.z...|
+00000020  25 b1 53 94 27 78 ed ae  58 2f 1b 00 00 04 00 2f  |%.S.'x..X/...../|
+00000030  00 ff 01 00 00 3d 00 00  00 10 00 0e 00 00 0b 73  |.....=.........s|
+00000040  6e 69 74 65 73 74 2e 63  6f 6d 00 0d 00 20 00 1e  |nitest.com... ..|
+00000050  06 01 06 02 06 03 05 01  05 02 05 03 04 01 04 02  |................|
+00000060  04 03 03 01 03 02 03 03  02 01 02 02 02 03 00 0f  |................|
+00000070  00 01 01                                          |...|
+>>> Flow 2 (server to client)
+00000000  16 03 03 00 31 02 00 00  2d 03 03 00 00 00 00 00  |....1...-.......|
+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 2f 00 00  |............./..|
+00000030  05 ff 01 00 01 00 16 03  03 02 00 0b 00 01 fc 00  |................|
+00000040  01 f9 00 01 f6 30 82 01  f2 30 82 01 5d a0 03 02  |.....0...0..]...|
+00000050  01 02 02 01 00 30 0b 06  09 2a 86 48 86 f7 0d 01  |.....0...*.H....|
+00000060  01 05 30 28 31 10 30 0e  06 03 55 04 0a 13 07 41  |..0(1.0...U....A|
+00000070  63 6d 65 20 43 6f 31 14  30 12 06 03 55 04 03 13  |cme Co1.0...U...|
+00000080  0b 73 6e 69 74 65 73 74  2e 63 6f 6d 30 1e 17 0d  |.snitest.com0...|
+00000090  31 32 30 34 31 31 31 37  34 30 33 35 5a 17 0d 31  |120411174035Z..1|
+000000a0  33 30 34 31 31 31 37 34  35 33 35 5a 30 28 31 10  |30411174535Z0(1.|
+000000b0  30 0e 06 03 55 04 0a 13  07 41 63 6d 65 20 43 6f  |0...U....Acme Co|
+000000c0  31 14 30 12 06 03 55 04  03 13 0b 73 6e 69 74 65  |1.0...U....snite|
+000000d0  73 74 2e 63 6f 6d 30 81  9d 30 0b 06 09 2a 86 48  |st.com0..0...*.H|
+000000e0  86 f7 0d 01 01 01 03 81  8d 00 30 81 89 02 81 81  |..........0.....|
+000000f0  00 bb 79 d6 f5 17 b5 e5  bf 46 10 d0 dc 69 be e6  |..y......F...i..|
+00000100  2b 07 43 5a d0 03 2d 8a  7a 43 85 b7 14 52 e7 a5  |+.CZ..-.zC...R..|
+00000110  65 4c 2c 78 b8 23 8c b5  b4 82 e5 de 1f 95 3b 7e  |eL,x.#........;~|
+00000120  62 a5 2c a5 33 d6 fe 12  5c 7a 56 fc f5 06 bf fa  |b.,.3...\zV.....|
+00000130  58 7b 26 3f b5 cd 04 d3  d0 c9 21 96 4a c7 f4 54  |X{&?......!.J..T|
+00000140  9f 5a bf ef 42 71 00 fe  18 99 07 7f 7e 88 7d 7d  |.Z..Bq......~.}}|
+00000150  f1 04 39 c4 a2 2e db 51  c9 7c e3 c0 4c 3b 32 66  |..9....Q.|..L;2f|
+00000160  01 cf af b1 1d b8 71 9a  1d db db 89 6b ae da 2d  |......q.....k..-|
+00000170  79 02 03 01 00 01 a3 32  30 30 30 0e 06 03 55 1d  |y......2000...U.|
+00000180  0f 01 01 ff 04 04 03 02  00 a0 30 0d 06 03 55 1d  |..........0...U.|
+00000190  0e 04 06 04 04 01 02 03  04 30 0f 06 03 55 1d 23  |.........0...U.#|
+000001a0  04 08 30 06 80 04 01 02  03 04 30 0b 06 09 2a 86  |..0.......0...*.|
+000001b0  48 86 f7 0d 01 01 05 03  81 81 00 89 c6 45 5f 1c  |H............E_.|
+000001c0  1f 5e f8 eb 1a b1 74 ee  24 39 05 9f 5c 42 59 bb  |.^....t.$9..\BY.|
+000001d0  1a 8d 86 cd b1 d0 56 f5  6a 71 7d a4 0e 95 ab 90  |......V.jq}.....|
+000001e0  f5 9e 8d ea f6 27 c1 57  99 50 94 db 08 02 26 6e  |.....'.W.P....&n|
+000001f0  b3 4f c6 84 2d ea 8a 4b  68 d9 c1 38 91 03 ab 84  |.O..-..Kh..8....|
+00000200  fb 9e 1f 85 d9 b5 d2 3f  f2 31 2c 86 70 fb b5 40  |.......?.1,.p..@|
+00000210  14 82 45 a4 eb af e2 64  d9 0c 8a 4c f4 f8 5b 0f  |..E....d...L..[.|
+00000220  ac 12 ac 2f c4 a3 15 4b  ad 52 46 28 68 af 96 c6  |.../...K.RF(h...|
+00000230  2c 65 25 d6 52 b6 e3 18  45 bd cc 16 03 03 00 04  |,e%.R...E.......|
+00000240  0e 00 00 00                                       |....|
+>>> Flow 3 (client to server)
+00000000  16 03 03 00 86 10 00 00  82 00 80 72 23 e9 89 70  |...........r#..p|
+00000010  97 02 08 58 0d 28 96 5b  19 73 dd 4f 6e 4c 11 dd  |...X.(.[.s.OnL..|
+00000020  cb 56 14 f4 8f c8 e5 84  03 f5 7e f0 a4 08 44 8c  |.V........~...D.|
+00000030  22 74 01 5c e4 9d e0 38  53 90 66 e3 df bb 09 a8  |"t.\...8S.f.....|
+00000040  11 97 0a 44 01 d2 70 85  14 a1 9a 2f 02 34 40 6d  |...D..p..../.4 at m|
+00000050  66 80 72 9a 97 98 5c 91  0e dc 42 ac c2 90 2f 30  |f.r...\...B.../0|
+00000060  ca 39 25 94 da 6e b6 5f  94 a9 94 66 7f 32 6a bb  |.9%..n._...f.2j.|
+00000070  5d 43 20 c3 74 f7 52 29  1f d5 62 6b a4 a1 8c 25  |]C .t.R)..bk...%|
+00000080  46 69 22 a5 68 54 f4 68  30 e2 52 14 03 03 00 01  |Fi".hT.h0.R.....|
+00000090  01 16 03 03 00 40 51 d2  78 64 e3 59 ee b7 5f 95  |..... at Q.xd.Y.._.|
+000000a0  4c 49 7f 0d 49 3f 55 71  8c 3b 24 e3 81 22 4a d1  |LI..I?Uq.;$.."J.|
+000000b0  ab 84 4e df 02 9d 56 ea  2a 14 71 e1 dc 1d 5c 1d  |..N...V.*.q...\.|
+000000c0  54 ce cb 58 f6 4d e7 73  44 0d 99 95 a5 2d 7c 2f  |T..X.M.sD....-|/|
+000000d0  15 f5 8f fd 97 40                                 |.....@|
+>>> Flow 4 (server to client)
+00000000  15 03 03 00 02 02 14                              |.......|
diff --git a/src/crypto/tls/ticket.go b/src/crypto/tls/ticket.go
index 0923027..7be50ce 100644
--- a/src/crypto/tls/ticket.go
+++ b/src/crypto/tls/ticket.go
@@ -22,6 +22,9 @@ type sessionState struct {
 	cipherSuite  uint16
 	masterSecret []byte
 	certificates [][]byte
+	// usedOldKey is true if the ticket from which this session came from
+	// was encrypted with an older key and thus should be refreshed.
+	usedOldKey bool
 }
 
 func (s *sessionState) equal(i interface{}) bool {
@@ -132,20 +135,23 @@ func (s *sessionState) unmarshal(data []byte) bool {
 
 func (c *Conn) encryptTicket(state *sessionState) ([]byte, error) {
 	serialized := state.marshal()
-	encrypted := make([]byte, aes.BlockSize+len(serialized)+sha256.Size)
-	iv := encrypted[:aes.BlockSize]
+	encrypted := make([]byte, ticketKeyNameLen+aes.BlockSize+len(serialized)+sha256.Size)
+	keyName := encrypted[:ticketKeyNameLen]
+	iv := encrypted[ticketKeyNameLen : ticketKeyNameLen+aes.BlockSize]
 	macBytes := encrypted[len(encrypted)-sha256.Size:]
 
 	if _, err := io.ReadFull(c.config.rand(), iv); err != nil {
 		return nil, err
 	}
-	block, err := aes.NewCipher(c.config.SessionTicketKey[:16])
+	key := c.config.ticketKeys()[0]
+	copy(keyName, key.keyName[:])
+	block, err := aes.NewCipher(key.aesKey[:])
 	if err != nil {
 		return nil, errors.New("tls: failed to create cipher while encrypting ticket: " + err.Error())
 	}
-	cipher.NewCTR(block, iv).XORKeyStream(encrypted[aes.BlockSize:], serialized)
+	cipher.NewCTR(block, iv).XORKeyStream(encrypted[ticketKeyNameLen+aes.BlockSize:], serialized)
 
-	mac := hmac.New(sha256.New, c.config.SessionTicketKey[16:32])
+	mac := hmac.New(sha256.New, key.hmacKey[:])
 	mac.Write(encrypted[:len(encrypted)-sha256.Size])
 	mac.Sum(macBytes[:0])
 
@@ -154,14 +160,29 @@ func (c *Conn) encryptTicket(state *sessionState) ([]byte, error) {
 
 func (c *Conn) decryptTicket(encrypted []byte) (*sessionState, bool) {
 	if c.config.SessionTicketsDisabled ||
-		len(encrypted) < aes.BlockSize+sha256.Size {
+		len(encrypted) < ticketKeyNameLen+aes.BlockSize+sha256.Size {
 		return nil, false
 	}
 
-	iv := encrypted[:aes.BlockSize]
+	keyName := encrypted[:ticketKeyNameLen]
+	iv := encrypted[ticketKeyNameLen : ticketKeyNameLen+aes.BlockSize]
 	macBytes := encrypted[len(encrypted)-sha256.Size:]
 
-	mac := hmac.New(sha256.New, c.config.SessionTicketKey[16:32])
+	keys := c.config.ticketKeys()
+	keyIndex := -1
+	for i, candidateKey := range keys {
+		if bytes.Equal(keyName, candidateKey.keyName[:]) {
+			keyIndex = i
+			break
+		}
+	}
+
+	if keyIndex == -1 {
+		return nil, false
+	}
+	key := &keys[keyIndex]
+
+	mac := hmac.New(sha256.New, key.hmacKey[:])
 	mac.Write(encrypted[:len(encrypted)-sha256.Size])
 	expected := mac.Sum(nil)
 
@@ -169,15 +190,15 @@ func (c *Conn) decryptTicket(encrypted []byte) (*sessionState, bool) {
 		return nil, false
 	}
 
-	block, err := aes.NewCipher(c.config.SessionTicketKey[:16])
+	block, err := aes.NewCipher(key.aesKey[:])
 	if err != nil {
 		return nil, false
 	}
-	ciphertext := encrypted[aes.BlockSize : len(encrypted)-sha256.Size]
+	ciphertext := encrypted[ticketKeyNameLen+aes.BlockSize : len(encrypted)-sha256.Size]
 	plaintext := ciphertext
 	cipher.NewCTR(block, iv).XORKeyStream(plaintext, ciphertext)
 
-	state := new(sessionState)
+	state := &sessionState{usedOldKey: keyIndex > 0}
 	ok := state.unmarshal(plaintext)
 	return state, ok
 }
diff --git a/src/crypto/tls/tls.go b/src/crypto/tls/tls.go
index d50e120..0b1c377 100644
--- a/src/crypto/tls/tls.go
+++ b/src/crypto/tls/tls.go
@@ -167,22 +167,24 @@ func Dial(network, addr string, config *Config) (*Conn, error) {
 
 // LoadX509KeyPair reads and parses a public/private key pair from a pair of
 // files. The files must contain PEM encoded data.
-func LoadX509KeyPair(certFile, keyFile string) (cert Certificate, err error) {
+func LoadX509KeyPair(certFile, keyFile string) (Certificate, error) {
 	certPEMBlock, err := ioutil.ReadFile(certFile)
 	if err != nil {
-		return
+		return Certificate{}, err
 	}
 	keyPEMBlock, err := ioutil.ReadFile(keyFile)
 	if err != nil {
-		return
+		return Certificate{}, err
 	}
 	return X509KeyPair(certPEMBlock, keyPEMBlock)
 }
 
 // X509KeyPair parses a public/private key pair from a pair of
 // PEM encoded data.
-func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (cert Certificate, err error) {
+func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (Certificate, error) {
+	var cert Certificate
 	var certDERBlock *pem.Block
+	fail := func(err error) (Certificate, error) { return Certificate{}, err }
 	for {
 		certDERBlock, certPEMBlock = pem.Decode(certPEMBlock)
 		if certDERBlock == nil {
@@ -194,62 +196,56 @@ func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (cert Certificate, err error)
 	}
 
 	if len(cert.Certificate) == 0 {
-		err = errors.New("crypto/tls: failed to parse certificate PEM data")
-		return
+		return fail(errors.New("crypto/tls: failed to parse certificate PEM data"))
 	}
 
 	var keyDERBlock *pem.Block
 	for {
 		keyDERBlock, keyPEMBlock = pem.Decode(keyPEMBlock)
 		if keyDERBlock == nil {
-			err = errors.New("crypto/tls: failed to parse key PEM data")
-			return
+			return fail(errors.New("crypto/tls: failed to parse key PEM data"))
 		}
 		if keyDERBlock.Type == "PRIVATE KEY" || strings.HasSuffix(keyDERBlock.Type, " PRIVATE KEY") {
 			break
 		}
 	}
 
+	var err error
 	cert.PrivateKey, err = parsePrivateKey(keyDERBlock.Bytes)
 	if err != nil {
-		return
+		return fail(err)
 	}
 
 	// We don't need to parse the public key for TLS, but we so do anyway
 	// to check that it looks sane and matches the private key.
 	x509Cert, err := x509.ParseCertificate(cert.Certificate[0])
 	if err != nil {
-		return
+		return fail(err)
 	}
 
 	switch pub := x509Cert.PublicKey.(type) {
 	case *rsa.PublicKey:
 		priv, ok := cert.PrivateKey.(*rsa.PrivateKey)
 		if !ok {
-			err = errors.New("crypto/tls: private key type does not match public key type")
-			return
+			return fail(errors.New("crypto/tls: private key type does not match public key type"))
 		}
 		if pub.N.Cmp(priv.N) != 0 {
-			err = errors.New("crypto/tls: private key does not match public key")
-			return
+			return fail(errors.New("crypto/tls: private key does not match public key"))
 		}
 	case *ecdsa.PublicKey:
 		priv, ok := cert.PrivateKey.(*ecdsa.PrivateKey)
 		if !ok {
-			err = errors.New("crypto/tls: private key type does not match public key type")
-			return
+			return fail(errors.New("crypto/tls: private key type does not match public key type"))
 
 		}
 		if pub.X.Cmp(priv.X) != 0 || pub.Y.Cmp(priv.Y) != 0 {
-			err = errors.New("crypto/tls: private key does not match public key")
-			return
+			return fail(errors.New("crypto/tls: private key does not match public key"))
 		}
 	default:
-		err = errors.New("crypto/tls: unknown public key algorithm")
-		return
+		return fail(errors.New("crypto/tls: unknown public key algorithm"))
 	}
 
-	return
+	return cert, nil
 }
 
 // Attempt to parse the given private key DER block. OpenSSL 0.9.8 generates
diff --git a/src/crypto/tls/tls_test.go b/src/crypto/tls/tls_test.go
index e82579e..c45c103 100644
--- a/src/crypto/tls/tls_test.go
+++ b/src/crypto/tls/tls_test.go
@@ -7,6 +7,7 @@ package tls
 import (
 	"bytes"
 	"fmt"
+	"internal/testenv"
 	"io"
 	"net"
 	"strings"
@@ -40,7 +41,7 @@ D2lWusoe2/nEqfDVVWGWlyJ7yOmqaVm/iNUN9B2N2g==
 `
 
 // keyPEM is the same as rsaKeyPEM, but declares itself as just
-// "PRIVATE KEY", not "RSA PRIVATE KEY".  http://golang.org/issue/4477
+// "PRIVATE KEY", not "RSA PRIVATE KEY".  https://golang.org/issue/4477
 var keyPEM = `-----BEGIN PRIVATE KEY-----
 MIIBOwIBAAJBANLJhPHhITqQbPklG3ibCVxwGMRfp/v4XqhfdQHdcVfHap6NQ5Wo
 k/4xIA+ui35/MmNartNuC+BdZ1tMuVCPFZcCAwEAAQJAEJ2N+zsR0Xn8/Q6twa4G
@@ -280,3 +281,54 @@ func TestTLSUniqueMatches(t *testing.T) {
 		t.Error("client and server channel bindings differ when session resumption is used")
 	}
 }
+
+func TestVerifyHostname(t *testing.T) {
+	testenv.MustHaveExternalNetwork(t)
+
+	c, err := Dial("tcp", "www.google.com:https", nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if err := c.VerifyHostname("www.google.com"); err != nil {
+		t.Fatalf("verify www.google.com: %v", err)
+	}
+	if err := c.VerifyHostname("www.yahoo.com"); err == nil {
+		t.Fatalf("verify www.yahoo.com succeeded")
+	}
+
+	c, err = Dial("tcp", "www.google.com:https", &Config{InsecureSkipVerify: true})
+	if err != nil {
+		t.Fatal(err)
+	}
+	if err := c.VerifyHostname("www.google.com"); err == nil {
+		t.Fatalf("verify www.google.com succeeded with InsecureSkipVerify=true")
+	}
+	if err := c.VerifyHostname("www.yahoo.com"); err == nil {
+		t.Fatalf("verify www.google.com succeeded with InsecureSkipVerify=true")
+	}
+}
+
+func TestVerifyHostnameResumed(t *testing.T) {
+	testenv.MustHaveExternalNetwork(t)
+
+	config := &Config{
+		ClientSessionCache: NewLRUClientSessionCache(32),
+	}
+	for i := 0; i < 2; i++ {
+		c, err := Dial("tcp", "www.google.com:https", config)
+		if err != nil {
+			t.Fatalf("Dial #%d: %v", i, err)
+		}
+		cs := c.ConnectionState()
+		if i > 0 && !cs.DidResume {
+			t.Fatalf("Subsequent connection unexpectedly didn't resume")
+		}
+		if cs.VerifiedChains == nil {
+			t.Fatalf("Dial #%d: cs.VerifiedChains == nil", i)
+		}
+		if err := c.VerifyHostname("www.google.com"); err != nil {
+			t.Fatalf("verify www.google.com #%d: %v", i, err)
+		}
+		c.Close()
+	}
+}
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 @@ func (s *CertPool) AddCert(cert *Certificate) {
 }
 
 // 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..49ceadb 100644
--- a/src/crypto/x509/pem_decrypt.go
+++ b/src/crypto/x509/pem_decrypt.go
@@ -108,7 +108,10 @@ var IncorrectPasswordError = errors.New("x509: decryption password incorrect")
 // 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 {
@@ -141,6 +144,10 @@ func DecryptPEMBlock(b *pem.Block, password []byte) ([]byte, error) {
 		return nil, err
 	}
 
+	if len(b.Bytes)%block.BlockSize() != 0 {
+		return nil, errors.New("x509: encrypted PEM data is not a multiple of the block size")
+	}
+
 	data := make([]byte, len(b.Bytes))
 	dec := cipher.NewCBCDecrypter(block, iv)
 	dec.CryptBlocks(data, b.Bytes)
diff --git a/src/crypto/x509/pem_decrypt_test.go b/src/crypto/x509/pem_decrypt_test.go
index 13e4700..685d5ee 100644
--- a/src/crypto/x509/pem_decrypt_test.go
+++ b/src/crypto/x509/pem_decrypt_test.go
@@ -9,6 +9,7 @@ import (
 	"crypto/rand"
 	"encoding/base64"
 	"encoding/pem"
+	"strings"
 	"testing"
 )
 
@@ -221,3 +222,26 @@ AgkA8SEfu/2i3g0CCQDGNlXbBHX7kQIIK3Ww5o0cYbECCQDCimPb0dYGsQIIeQ7A
 jryIst8=`,
 	},
 }
+
+const incompleteBlockPEM = `
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-CBC,74611ABC2571AF11B1BF9B69E62C89E7
+
+6L8yXK2MTQUWBk4ZD6OvCiYp+mXyR1594TQ1K38MxGvDw5pwcDME2Lek8RrR5fd40P2XsL2Z4KKt
+ai+OP1BZUetfK6AW4MiqB2FDyIdOAJ8XeWuZy21Wtsh8wPD6yYOFM/w7WZL8weX3Y0TSeG/T
+-----END RSA PRIVATE KEY-----`
+
+func TestIncompleteBlock(t *testing.T) {
+	// incompleteBlockPEM contains ciphertext that is not a multiple of the
+	// block size. This previously panicked. See #11215.
+	block, _ := pem.Decode([]byte(incompleteBlockPEM))
+	_, err := DecryptPEMBlock(block, []byte("foo"))
+	if err == nil {
+		t.Fatal("Bad PEM data decrypted successfully")
+	}
+	const expectedSubstr = "block size"
+	if e := err.Error(); !strings.Contains(e, expectedSubstr) {
+		t.Fatalf("Expected error containing %q but got: %q", expectedSubstr, e)
+	}
+}
diff --git a/src/crypto/x509/pkix/pkix.go b/src/crypto/x509/pkix/pkix.go
index 8768b78..5add4e5 100644
--- a/src/crypto/x509/pkix/pkix.go
+++ b/src/crypto/x509/pkix/pkix.go
@@ -46,14 +46,17 @@ type Extension struct {
 }
 
 // Name represents an X.509 distinguished name. This only includes the common
-// elements of a DN.  Additional elements in the name are ignored.
+// elements of a DN. When parsing, all elements are stored in Names and
+// non-standard elements can be extracted from there. When marshaling, elements
+// in ExtraNames are appended and override other values with the same OID.
 type Name struct {
 	Country, Organization, OrganizationalUnit []string
 	Locality, Province                        []string
 	StreetAddress, PostalCode                 []string
 	SerialNumber, CommonName                  string
 
-	Names []AttributeTypeAndValue
+	Names      []AttributeTypeAndValue
+	ExtraNames []AttributeTypeAndValue
 }
 
 func (n *Name) FillFromRDNSequence(rdns *RDNSequence) {
@@ -110,8 +113,8 @@ var (
 // and returns the new value. The relativeDistinguishedNameSET contains an
 // attributeTypeAndValue for each of the given values. See RFC 5280, A.1, and
 // search for AttributeTypeAndValue.
-func appendRDNs(in RDNSequence, values []string, oid asn1.ObjectIdentifier) RDNSequence {
-	if len(values) == 0 {
+func (n Name) appendRDNs(in RDNSequence, values []string, oid asn1.ObjectIdentifier) RDNSequence {
+	if len(values) == 0 || oidInAttributeTypeAndValue(oid, n.ExtraNames) {
 		return in
 	}
 
@@ -125,23 +128,37 @@ func appendRDNs(in RDNSequence, values []string, oid asn1.ObjectIdentifier) RDNS
 }
 
 func (n Name) ToRDNSequence() (ret RDNSequence) {
-	ret = appendRDNs(ret, n.Country, oidCountry)
-	ret = appendRDNs(ret, n.Organization, oidOrganization)
-	ret = appendRDNs(ret, n.OrganizationalUnit, oidOrganizationalUnit)
-	ret = appendRDNs(ret, n.Locality, oidLocality)
-	ret = appendRDNs(ret, n.Province, oidProvince)
-	ret = appendRDNs(ret, n.StreetAddress, oidStreetAddress)
-	ret = appendRDNs(ret, n.PostalCode, oidPostalCode)
+	ret = n.appendRDNs(ret, n.Country, oidCountry)
+	ret = n.appendRDNs(ret, n.Organization, oidOrganization)
+	ret = n.appendRDNs(ret, n.OrganizationalUnit, oidOrganizationalUnit)
+	ret = n.appendRDNs(ret, n.Locality, oidLocality)
+	ret = n.appendRDNs(ret, n.Province, oidProvince)
+	ret = n.appendRDNs(ret, n.StreetAddress, oidStreetAddress)
+	ret = n.appendRDNs(ret, n.PostalCode, oidPostalCode)
 	if len(n.CommonName) > 0 {
-		ret = appendRDNs(ret, []string{n.CommonName}, oidCommonName)
+		ret = n.appendRDNs(ret, []string{n.CommonName}, oidCommonName)
 	}
 	if len(n.SerialNumber) > 0 {
-		ret = appendRDNs(ret, []string{n.SerialNumber}, oidSerialNumber)
+		ret = n.appendRDNs(ret, []string{n.SerialNumber}, oidSerialNumber)
+	}
+	for _, atv := range n.ExtraNames {
+		ret = append(ret, []AttributeTypeAndValue{atv})
 	}
 
 	return ret
 }
 
+// oidInAttributeTypeAndValue returns whether a type with the given OID exists
+// in atv.
+func oidInAttributeTypeAndValue(oid asn1.ObjectIdentifier, atv []AttributeTypeAndValue) bool {
+	for _, a := range atv {
+		if a.Type.Equal(oid) {
+			return true
+		}
+	}
+	return false
+}
+
 // CertificateList represents the ASN.1 structure of the same name. See RFC
 // 5280, section 5.1. Use Certificate.CheckCRLSignature to verify the
 // signature.
@@ -160,7 +177,7 @@ func (certList *CertificateList) HasExpired(now time.Time) bool {
 // 5280, section 5.1.
 type TBSCertificateList struct {
 	Raw                 asn1.RawContent
-	Version             int `asn1:"optional,default:2"`
+	Version             int `asn1:"optional,default:1"`
 	Signature           AlgorithmIdentifier
 	Issuer              RDNSequence
 	ThisUpdate          time.Time
diff --git a/src/crypto/x509/root_bsd.go b/src/crypto/x509/root_bsd.go
new file mode 100644
index 0000000..9317283
--- /dev/null
+++ b/src/crypto/x509/root_bsd.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 dragonfly freebsd netbsd openbsd
+
+package x509
+
+// Possible certificate files; stop after finding one.
+var certFiles = []string{
+	"/usr/local/share/certs/ca-root-nss.crt", // FreeBSD/DragonFly
+	"/etc/ssl/cert.pem",                      // OpenBSD
+	"/etc/openssl/certs/ca-certificates.crt", // NetBSD
+}
diff --git a/src/crypto/x509/root_cgo_darwin.go b/src/crypto/x509/root_cgo_darwin.go
index bdcc2c1..bf4a5cd 100644
--- a/src/crypto/x509/root_cgo_darwin.go
+++ b/src/crypto/x509/root_cgo_darwin.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 cgo
+// +build cgo,!arm,!arm64,!ios
 
 package x509
 
diff --git a/src/crypto/x509/root_darwin.go b/src/crypto/x509/root_darwin.go
index 2a61d36..78de56c 100644
--- a/src/crypto/x509/root_darwin.go
+++ b/src/crypto/x509/root_darwin.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.
 
+//go:generate go run root_darwin_arm_gen.go -output root_darwin_armx.go
+
 package x509
 
 import "os/exec"
diff --git a/src/crypto/x509/root_darwin_arm_gen.go b/src/crypto/x509/root_darwin_arm_gen.go
new file mode 100644
index 0000000..5817158
--- /dev/null
+++ b/src/crypto/x509/root_darwin_arm_gen.go
@@ -0,0 +1,191 @@
+// 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
+
+// Generates root_darwin_armx.go.
+//
+// As of iOS 8, there is no API for querying the system trusted X.509 root
+// certificates. We could use SecTrustEvaluate to verify that a trust chain
+// exists for a certificate, but the x509 API requires returning the entire
+// chain.
+//
+// Apple publishes the list of trusted root certificates for iOS on
+// support.apple.com. So we parse the list and extract the certificates from
+// an OS X machine and embed them into the x509 package.
+package main
+
+import (
+	"bytes"
+	"crypto/x509"
+	"encoding/pem"
+	"flag"
+	"fmt"
+	"go/format"
+	"io/ioutil"
+	"log"
+	"math/big"
+	"net/http"
+	"os/exec"
+	"strings"
+)
+
+var output = flag.String("output", "root_darwin_armx.go", "file name to write")
+
+func main() {
+	certs, err := selectCerts()
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	buf := new(bytes.Buffer)
+
+	fmt.Fprintf(buf, "// Created by root_darwin_arm_gen --output %s; DO NOT EDIT\n", *output)
+	fmt.Fprintf(buf, "%s", header)
+
+	fmt.Fprintf(buf, "const systemRootsPEM = `\n")
+	for _, cert := range certs {
+		b := &pem.Block{
+			Type:  "CERTIFICATE",
+			Bytes: cert.Raw,
+		}
+		if err := pem.Encode(buf, b); err != nil {
+			log.Fatal(err)
+		}
+	}
+	fmt.Fprintf(buf, "`")
+
+	source, err := format.Source(buf.Bytes())
+	if err != nil {
+		log.Fatal("source format error:", err)
+	}
+	if err := ioutil.WriteFile(*output, source, 0644); err != nil {
+		log.Fatal(err)
+	}
+}
+
+func selectCerts() ([]*x509.Certificate, error) {
+	ids, err := fetchCertIDs()
+	if err != nil {
+		return nil, err
+	}
+
+	scerts, err := sysCerts()
+	if err != nil {
+		return nil, err
+	}
+
+	var certs []*x509.Certificate
+	for _, id := range ids {
+		sn, ok := big.NewInt(0).SetString(id.serialNumber, 0) // 0x prefix selects hex
+		if !ok {
+			return nil, fmt.Errorf("invalid serial number: %q", id.serialNumber)
+		}
+		ski, ok := big.NewInt(0).SetString(id.subjectKeyID, 0)
+		if !ok {
+			return nil, fmt.Errorf("invalid Subject Key ID: %q", id.subjectKeyID)
+		}
+
+		for _, cert := range scerts {
+			if sn.Cmp(cert.SerialNumber) != 0 {
+				continue
+			}
+			cski := big.NewInt(0).SetBytes(cert.SubjectKeyId)
+			if ski.Cmp(cski) != 0 {
+				continue
+			}
+			certs = append(certs, cert)
+			break
+		}
+	}
+	return certs, nil
+}
+
+func sysCerts() (certs []*x509.Certificate, err error) {
+	cmd := exec.Command("/usr/bin/security", "find-certificate", "-a", "-p", "/System/Library/Keychains/SystemRootCertificates.keychain")
+	data, err := cmd.Output()
+	if err != nil {
+		return nil, err
+	}
+	for len(data) > 0 {
+		var block *pem.Block
+		block, data = pem.Decode(data)
+		if block == nil {
+			break
+		}
+		if block.Type != "CERTIFICATE" || len(block.Headers) != 0 {
+			continue
+		}
+
+		cert, err := x509.ParseCertificate(block.Bytes)
+		if err != nil {
+			continue
+		}
+		certs = append(certs, cert)
+	}
+	return certs, nil
+}
+
+type certID struct {
+	serialNumber string
+	subjectKeyID string
+}
+
+// fetchCertIDs fetches IDs of iOS X509 certificates from apple.com.
+func fetchCertIDs() ([]certID, error) {
+	resp, err := http.Get("https://support.apple.com/en-us/HT204132")
+	if err != nil {
+		return nil, err
+	}
+	defer resp.Body.Close()
+	body, err := ioutil.ReadAll(resp.Body)
+	if err != nil {
+		return nil, err
+	}
+	text := string(body)
+	text = text[strings.Index(text, "<section id=trusted"):]
+	text = text[:strings.Index(text, "</section>")]
+
+	lines := strings.Split(text, "\n")
+	var ids []certID
+	var id certID
+	for i, ln := range lines {
+		if i == len(lines)-1 {
+			break
+		}
+		const sn = "Serial Number:"
+		if ln == sn {
+			id.serialNumber = "0x" + strings.Replace(strings.TrimSpace(lines[i+1]), ":", "", -1)
+			continue
+		}
+		if strings.HasPrefix(ln, sn) {
+			// extract hex value from parentheses.
+			id.serialNumber = ln[strings.Index(ln, "(")+1 : len(ln)-1]
+			continue
+		}
+		if strings.TrimSpace(ln) == "X509v3 Subject Key Identifier:" {
+			id.subjectKeyID = "0x" + strings.Replace(strings.TrimSpace(lines[i+1]), ":", "", -1)
+			ids = append(ids, id)
+			id = certID{}
+		}
+	}
+	return ids, nil
+}
+
+const header = `
+// 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 cgo
+// +build darwin
+// +build arm arm64
+
+package x509
+
+func initSystemRoots() {
+	systemRoots = NewCertPool()
+	systemRoots.AppendCertsFromPEM([]byte(systemRootsPEM))
+}
+`
diff --git a/src/crypto/x509/root_darwin_armx.go b/src/crypto/x509/root_darwin_armx.go
new file mode 100644
index 0000000..37675b4
--- /dev/null
+++ b/src/crypto/x509/root_darwin_armx.go
@@ -0,0 +1,4907 @@
+// Created by root_darwin_arm_gen --output root_darwin_armx.go; DO NOT EDIT
+
+// 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 cgo
+// +build darwin
+// +build arm arm64 ios
+
+package x509
+
+func initSystemRoots() {
+	systemRoots = NewCertPool()
+	systemRoots.AppendCertsFromPEM([]byte(systemRootsPEM))
+}
+
+const systemRootsPEM = `
+-----BEGIN CERTIFICATE-----
+MIIF8DCCA9igAwIBAgIPBuhGJy8fCo/RhFzjafbVMA0GCSqGSIb3DQEBBQUAMDgx
+CzAJBgNVBAYTAkVTMRQwEgYDVQQKDAtJWkVOUEUgUy5BLjETMBEGA1UEAwwKSXpl
+bnBlLmNvbTAeFw0wNzEyMTMxMzA4MjdaFw0zNzEyMTMwODI3MjVaMDgxCzAJBgNV
+BAYTAkVTMRQwEgYDVQQKDAtJWkVOUEUgUy5BLjETMBEGA1UEAwwKSXplbnBlLmNv
+bTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMnTesoPHqynhugWZWqx
+whtFMnGV2f4QW8yv56V5AY+Jw8ryVXH3d753lPNypCxE2J6SmxQ6oeckkAoKVo7F
+2CaU4dlI4S0+2gpy3aOZFdqBoof0e24md4lYrdbrDLJBenNubdt6eEHpCIgSfocu
+ZhFjbFT7PJ1ywLwu/8K33Q124zrX97RovqL144FuwUZvXY3gTcZUVYkaMzEKsVe5
+o4qYw+w7NMWVQWl+dcI8IMVhulFHoCCQk6GQS/NOfIVFVJrRBSZBsLVNHTO+xAPI
+JXzBcNs79AktVCdIrC/hxKw+yMuSTFM5NyPs0wH54AlETU1kwOENWocivK0bo/4m
+tRXzp/yEGensoYi0RGmEg/OJ0XQGqcwL1sLeJ4VQJsoXuMl6h1YsGgEebL4TrRCs
+tST1OJGh1kva8bvS3ke18byB9llrzxlT6Y0Vy0rLqW9E5RtBz+GGp8rQap+8TI0G
+M1qiheWQNaBiXBZO8OOi+gMatCxxs1gs3nsL2xoP694hHwZ3BgOwye+Z/MC5TwuG
+KP7Suerj2qXDR2kS4Nvw9hmL7Xtw1wLW7YcYKCwEJEx35EiKGsY7mtQPyvp10gFA
+Wo15v4vPS8+qFsGV5K1Mij4XkdSxYuWC5YAEpAN+jb/af6IPl08M0w3719Hlcn4c
+yHf/W5oPt64FRuXxqBbsR6QXAgMBAAGjgfYwgfMwgbAGA1UdEQSBqDCBpYEPaW5m
+b0BpemVucGUuY29tpIGRMIGOMUcwRQYDVQQKDD5JWkVOUEUgUy5BLiAtIENJRiBB
+MDEzMzcyNjAtUk1lcmMuVml0b3JpYS1HYXN0ZWl6IFQxMDU1IEY2MiBTODFDMEEG
+A1UECQw6QXZkYSBkZWwgTWVkaXRlcnJhbmVvIEV0b3JiaWRlYSAxNCAtIDAxMDEw
+IFZpdG9yaWEtR2FzdGVpejAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB
+BjAdBgNVHQ4EFgQUHRxlDqjyJXu0kc/ksbHmvVV0bAUwDQYJKoZIhvcNAQEFBQAD
+ggIBAMeBRm8hGE+gBe/n1bqXUKJg7aWSFBpSm/nxiEqg3Hh10dUflU7F57dp5iL0
++CmoKom+z892j+Mxc50m0xwbRxYpB2iEitL7sRskPtKYGCwkjq/2e+pEFhsqxPqg
+l+nqbFik73WrAGLRne0TNtsiC7bw0fRue0aHwp28vb5CO7dz0JoqPLRbEhYArxk5
+ja2DUBzIgU+9Ag89njWW7u/kwgN8KRwCfr00J16vU9adF79XbOnQgxCvv11N75B7
+XSus7Op9ACYXzAJcY9cZGKfsK8eKPlgOiofmg59OsjQerFQJTx0CCzl+gQgVuaBp
+E8gyK+OtbBPWg50jLbJtooiGfqgNASYJQNntKE6MkyQP2/EeTXp6WuKlWPHcj1+Z
+ggwuz7LdmMySlD/5CbOlliVbN/UShUHiGUzGigjB3Bh6Dx4/glmimj4/+eAJn/3B
+kUtdyXvWton83x18hqrNA/ILUpLxYm9/h+qrdslsUMIZgq+qHfUgKGgu1fxkN0/P
+pUTEvnK0jHS0bKf68r10OEMr3q/53NjgnZ/cPcqlY0S/kqJPTIAcuxrDmkoEVU3K
+7iYLHL8CxWTTnn7S05EcS6L1HOUXHA0MUqORH5zwIe0ClG+poEnK6EOMxPQ02nwi
+o8ZmPrgbBYhdurz3vOXcFD2nhqi2WVIhA16L4wTtSyoeo09Q
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML
+RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp
+bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5
+IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp
+ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0yOTA3
+MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3
+LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp
+YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG
+A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq
+K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe
+sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX
+MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT
+XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/
+HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH
+4QIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV
+HQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJKoZIhvcNAQEFBQADggEBADub
+j1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPyT/4xmf3IDExo
+U8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf
+zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5b
+u/8j72gZyxKTJ1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+
+bYQLCIt+jerXmCHG8+c8eS9enNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/Er
+fF6adulZkMV8gzURZVE=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFwTCCA6mgAwIBAgIITrIAZwwDXU8wDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UE
+BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEjMCEGA1UEAxMaU3dpc3NTaWdu
+IFBsYXRpbnVtIENBIC0gRzIwHhcNMDYxMDI1MDgzNjAwWhcNMzYxMDI1MDgzNjAw
+WjBJMQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMSMwIQYDVQQD
+ExpTd2lzc1NpZ24gUGxhdGludW0gQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQAD
+ggIPADCCAgoCggIBAMrfogLi2vj8Bxax3mCq3pZcZB/HL37PZ/pEQtZ2Y5Wu669y
+IIpFR4ZieIbWIDkm9K6j/SPnpZy1IiEZtzeTIsBQnIJ71NUERFzLtMKfkr4k2Htn
+IuJpX+UFeNSH2XFwMyVTtIc7KZAoNppVRDBopIOXfw0enHb/FZ1glwCNioUD7IC+
+6ixuEFGSzH7VozPY1kneWCqv9hbrS3uQMpe5up1Y8fhXSQQeol0GcN1x2/ndi5ob
+jM89o03Oy3z2u5yg+gnOI2Ky6Q0f4nIoj5+saCB9bzuohTEJfwvH6GXp43gOCWcw
+izSC+13gzJ2BbWLuCB4ELE6b7P6pT1/9aXjvCR+htL/68++QHkwFix7qepF6w9fl
++zC8bBsQWJj3Gl/QKTIDE0ZNYWqFTFJ0LwYfexHihJfGmfNtf9dng34TaNhxKFrY
+zt3oEBSa/m0jh26OWnA81Y0JAKeqvLAxN23IhBQeW71FYyBrS3SMvds6DsHPWhaP
+pZjydomyExI7C3d3rLvlPClKknLKYRorXkzig3R3+jVIeoVNjZpTxN94ypeRSCtF
+KwH3HBqi7Ri6Cr2D+m+8jVeTO9TUps4e8aCxzqv9KyiaTxvXw3LbpMS/XUz13XuW
+ae5ogObnmLo2t/5u7Su9IPhlGdpVCX4l3P5hYnL5fhgC72O00Puv5TtjjGePAgMB
+AAGjgawwgakwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O
+BBYEFFCvzAeHFUdvOMW0ZdHelarp35zMMB8GA1UdIwQYMBaAFFCvzAeHFUdvOMW0
+ZdHelarp35zMMEYGA1UdIAQ/MD0wOwYJYIV0AVkBAQEBMC4wLAYIKwYBBQUHAgEW
+IGh0dHA6Ly9yZXBvc2l0b3J5LnN3aXNzc2lnbi5jb20vMA0GCSqGSIb3DQEBBQUA
+A4ICAQAIhab1Fgz8RBrBY+D5VUYI/HAcQiiWjrfFwUF1TglxeeVtlspLpYhg0DB0
+uMoI3LQwnkAHFmtllXcBrqS3NQuB2nEVqXQXOHtYyvkv+8Bldo1bAbl93oI9ZLi+
+FHSjClTTLJUYFzX1UWs/j6KWYTl4a0vlpqD4U99REJNi54Av4tHgvI42Rncz7Lj7
+jposiU0xEQ8mngS7twSNC/K5/FqdOxa3L8iYq/6KUFkuozv8KV2LwUvJ4ooTHbG/
+u0IdUt1O2BReEMYxB+9xJ/cbOQncguqLs5WGXv312l0xpuAxtpTmREl0xRbl9x8D
+YSjFyMsSoEJL+WuICI20MhjzdZ/EfwBPBZWcoxcCw7NTm6ogOSkrZvqdr16zktK1
+puEa+S1BaYEUtLS17Yk9zvupnTVCRLEcFHOBzyoBNZox1S2PbYTfgE1X4z/FhHXa
+icYwu+uPyyIIoK6q8QNsOktNCaUOcsZWayFCTiMlFGiudgp8DAdwZPmaL/YFOSbG
+DI8Zf0NebvRbFS/bYV3mZy8/CJT5YLSYMdp08YSTcU1f+2BY0fvEwW2JorsgH51x
+kcsymxM9Pn2SUjWskpSi0xjCfMfqr3YFFt1nJ8J+HAciIfNAChs0B0QTwoRqjt8Z
+Wr9/6x3iGjjRXK9HkmuAtTClyY3YqzGBH9/CZjfTk6mFhnll0g==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UE
+BhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8w
+MzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290
+IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDkyMjExMjIwMlowazELMAkGA1UEBhMC
+SVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1
+ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENB
+MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNv
+UTufClrJwkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX
+4ay8IMKx4INRimlNAJZaby/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9
+KK3giq0itFZljoZUj5NDKd45RnijMCO6zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/
+gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1fYVEiVRvjRuPjPdA1Yprb
+rxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2oxgkg4YQ
+51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2F
+be8lEfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxe
+KF+w6D9Fz8+vm2/7hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4F
+v6MGn8i1zeQf1xcGDXqVdFUNaBr8EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbn
+fpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5jF66CyCU3nuDuP/jVo23Eek7
+jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLYiDrIn3hm7Ynz
+ezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt
+ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAL
+e3KHwGCmSUyIWOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70
+jsNjLiNmsGe+b7bAEzlgqqI0JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDz
+WochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKxK3JCaKygvU5a2hi/a5iB0P2avl4V
+SM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+Xlff1ANATIGk0k9j
+pwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC4yyX
+X04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+Ok
+fcvHlXHo2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7R
+K4X9p2jIugErsWx0Hbhzlefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btU
+ZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXemOR/qnuOf0GZvBeyqdn6/axag67XH/JJU
+LysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9vwGYT7JZVEc+NHt4bVaT
+LnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UE
+BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz
+dCBOZXR3b3JraW5nMB4XDTEwMDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDEL
+MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp
+cm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SEHi3y
+YJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbua
+kCNrmreIdIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRL
+QESxG9fhwoXA3hA/Pe24/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp
+6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gbh+0t+nvujArjqWaJGctB+d1ENmHP4ndG
+yH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNVHQ4EFgQUBx/S55zawm6i
+QLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ
+KoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfO
+tDIuUFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzu
+QY0x2+c06lkh1QF612S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZ
+Lgo/bNjR9eUJtGxUAArgFU2HdW23WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4u
+olu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9/ZFvgrG+CJPbFEfxojfHRZ48
+x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEvTCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEn
+MCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQL
+ExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMg
+b2YgQ29tbWVyY2UgUm9vdDAeFw0wMzA5MzAxNjEzNDNaFw0zNzA5MzAxNjEzNDRa
+MH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZpcm1hIFNBIENJRiBB
+ODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3JnMSIw
+IAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJjZSBSb290MIIBIDANBgkqhkiG9w0B
+AQEFAAOCAQ0AMIIBCAKCAQEAtzZV5aVdGDDg2olUkfzIx1L4L1DZ77F1c2VHfRtb
+unXF/KGIJPov7coISjlUxFF6tdpg6jg8gbLL8bvZkSM/SAFwdakFKq0fcfPJVD0d
+BmpAPrMMhe5cG3nCYsS4No41XQEMIwRHNaqbYE6gZj3LJgqcQKH0XZi/caulAGgq
+7YN6D6IUtdQis4CwPAxaUWktWBiP7Zme8a7ileb2R6jWDA+wWFjbw2Y3npuRVDM3
+0pQcakjJyfKl2qUMI/cjDpwyVV5xnIQFUZot/eZOKjRa3spAN2cMVCFVd9oKDMyX
+roDclDZK9D7ONhMeU+SsTjoF7Nuucpw4i9A5O4kKPnf+dQIBA6OCAUQwggFAMBIG
+A1UdEwEB/wQIMAYBAf8CAQwwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5j
+aGFtYmVyc2lnbi5vcmcvY2hhbWJlcnNyb290LmNybDAdBgNVHQ4EFgQU45T1sU3p
+26EpW1eLTXYGduHRooowDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIA
+BzAnBgNVHREEIDAegRxjaGFtYmVyc3Jvb3RAY2hhbWJlcnNpZ24ub3JnMCcGA1Ud
+EgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwWAYDVR0gBFEwTzBN
+BgsrBgEEAYGHLgoDATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY3BzLmNoYW1iZXJz
+aWduLm9yZy9jcHMvY2hhbWJlcnNyb290Lmh0bWwwDQYJKoZIhvcNAQEFBQADggEB
+AAxBl8IahsAifJ/7kPMa0QOx7xP5IV8EnNrJpY0nbJaHkb5BkAFyk+cefV/2icZd
+p0AJPaxJRUXcLo0waLIJuvvDL8y6C98/d3tGfToSJI6WjzwFCm/SlCgdbQzALogi
+1djPHRPH8EjX1wWnz8dHnjs8NMiAT9QUu/wNUPf6s+xCX6ndbcj0dc97wXImsQEc
+XCz9ek60AcUFV7nnPKoF2YjpB0ZBzu9Bga5Y34OirsrXdx/nADydb47kMgkdTXg0
+eDQ8lJsm7U9xxhl6vSAiSFr+S30Dt+dYvsYyTnQeaN2oaFuzPu5ifdmA6Ap1erfu
+tGWaIZDgqtCYvDi1czyL+Nw=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb
+MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow
+GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj
+YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL
+MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE
+BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM
+GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua
+BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe
+3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4
+YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR
+rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm
+ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU
+oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF
+MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v
+QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t
+b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF
+AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q
+GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz
+Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2
+G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi
+l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3
+smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB
+gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
+A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV
+BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw
+MDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl
+YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P
+RE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0
+aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3
+UcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI
+2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8
+Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp
++2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+
+DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5O
+nKVIrLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW
+/zAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6g
+PKA6hjhodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9u
+QXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOCAQEAPpiem/Yb6dc5t3iuHXIY
+SdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CPOGEIqB6BCsAv
+IC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/
+RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4
+zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd
+BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB
+ZQ==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDcDCCAligAwIBAgIBBTANBgkqhkiG9w0BAQUFADBbMQswCQYDVQQGEwJVUzEY
+MBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsT
+A1BLSTEWMBQGA1UEAxMNRG9EIFJvb3QgQ0EgMjAeFw0wNDEyMTMxNTAwMTBaFw0y
+OTEyMDUxNTAwMTBaMFsxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVy
+bm1lbnQxDDAKBgNVBAsTA0RvRDEMMAoGA1UECxMDUEtJMRYwFAYDVQQDEw1Eb0Qg
+Um9vdCBDQSAyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwCzB9o07
+rP8/PNZxvrh0IgfscEEV/KtA4weqwcPYn/7aTDq/P8jYKHtLNgHArEUlw9IOCo+F
+GGQQPRoTcCpvjtfcjZOzQQ84Ic2tq8I9KgXTVxE3Dc2MUfmT48xGSSGOFLTNyxQ+
+OM1yMe6rEvJl6jQuVl3/7mN1y226kTT8nvP0LRy+UMRC31mI/2qz+qhsPctWcXEF
+lrufgOWARVlnQbDrw61gpIB1BhecDvRD4JkOG/t/9bPMsoGCsf0ywbi+QaRktWA6
+WlEwjM7eQSwZR1xJEGS5dKmHQa99brrBuKG/ZTE6BGf5tbuOkooAY7ix5ow4X4P/
+UNU7ol1rshDMYwIDAQABoz8wPTAdBgNVHQ4EFgQUSXS7DF66ev4CVO97oMaVxgmA
+cJYwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD
+ggEBAJiRjT+JyLv1wGlzKTs1rLqzCHY9cAmS6YREIQF9FHYb7lFsHY0VNy17MWn0
+mkS4r0bMNPojywMnGdKDIXUr5+AbmSbchECV6KjSzPZYXGbvP0qXEIIdugqi3VsG
+K52nZE7rLgE1pLQ/E61V5NVzqGmbEfGY8jEeb0DU+HifjpGgb3AEkGaqBivO4XqS
+tX3h4NGW56E6LcyxnR8FRO2HmdNNGnA5wQQM5X7Z8a/XIA7xInolpHOZzD+kByeW
+qKKV7YK5FtOeC4fCwfKI9WLfaN/HvGlR7bFc3FRUKQ8JOZqsA8HbDE2ubwp6Fknx
+v5HSOJTT9pUst2zJQraNypCNhdk=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAw
+PTELMAkGA1UEBhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFz
+cyAyIFByaW1hcnkgQ0EwHhcNOTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9
+MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2VydHBsdXMxGzAZBgNVBAMTEkNsYXNz
+IDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANxQ
+ltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR5aiR
+VhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyL
+kcAbmXuZVg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCd
+EgETjdyAYveVqUSISnFOYFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yas
+H7WLO7dDWWuwJKZtkIvEcupdM5i3y95ee++U8Rs+yskhwcWYAqqi9lt3m/V+llU0
+HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRMECDAGAQH/AgEKMAsGA1Ud
+DwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJYIZIAYb4
+QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMu
+Y29tL0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/
+AN9WM2K191EBkOvDP9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8
+yfFC82x/xXp8HVGIutIKPidd3i1RTtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMR
+FcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+7UCmnYR0ObncHoUW2ikbhiMA
+ybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW//1IMwrh3KWB
+kJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7
+l7+ijrRU
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMC
+VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50
+cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3Qs
+IEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVz
+dCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwHhcNMDkwNzA3MTcy
+NTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVu
+dHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwt
+dGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0
+aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmlj
+YXRpb24gQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+AoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP/vaCeb9zYQYKpSfYs1/T
+RU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXzHHfV1IWN
+cCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hW
+wcKUs/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1
+U1+cPvQXLOZprE4yTGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0
+jaWvYkxN4FisZDQSA/i2jZRjJKRxAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAP
+BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ60B7vfec7aVHUbI2fkBJmqzAN
+BgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5ZiXMRrEPR9RP/
+jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ
+Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v
+1fN2D807iDginWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4R
+nAuknZoh8/CbCzB428Hch0P+vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmH
+VHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xOe4pIb4tF9g==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIID9jCCAt6gAwIBAgIQZIKe/DcedF38l/+XyLH/QTANBgkqhkiG9w0BAQsFADCB
+lDELMAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8w
+HQYDVQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRl
+YyBDbGFzcyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5
+IC0gRzYwHhcNMTExMDE4MDAwMDAwWhcNMzcxMjAxMjM1OTU5WjCBlDELMAkGA1UE
+BhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZT
+eW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBDbGFzcyAy
+IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzYwggEi
+MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDNzOkFyGOFyz9AYxe9GPo15gRn
+V2WYKaRPyVyPDzTS+NqoE2KquB5QZ3iwFkygOakVeq7t0qLA8JA3KRgmXOgNPLZs
+ST/B4NzZS7YUGQum05bh1gnjGSYc+R9lS/kaQxwAg9bQqkmi1NvmYji6UBRDbfkx
++FYW2TgCkc/rbN27OU6Z4TBnRfHU8I3D3/7yOAchfQBeVkSz5GC9kSucq1sEcg+y
+KNlyqwUgQiWpWwNqIBDMMfAr2jUs0Pual07wgksr2F82owstr2MNHSV/oW5cYqGN
+KD6h/Bwg+AEvulWaEbAZ0shQeWsOagXXqgQ2sqPy4V93p3ec5R7c6d9qwWVdAgMB
+AAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW
+BBSHjCCVyJhK0daABkqQNETfHE2/sDANBgkqhkiG9w0BAQsFAAOCAQEAgY6ypWaW
+tyGltu9vI1pf24HFQqV4wWn99DzX+VxrcHIa/FqXTQCAiIiCisNxDY7FiZss7Y0L
+0nJU9X3UXENX6fOupQIR9nYrgVfdfdp0MP1UR/bgFm6mtApI5ud1Bw8pGTnOefS2
+bMVfmdUfS/rfbSw8DVSAcPCIC4DPxmiiuB1w2XaM/O6lyc+tHc+ZJVdaYkXLFmu9
+Sc2lo4xpeSWuuExsi0BmSxY/zwIa3eFsawdhanYVKZl/G92IgMG/tY9zxaaWI4Sm
+KIYkM2oBLldzJbZev4/mHWGoQClnHYebHX+bn5nNMdZUvmK7OaxoEkiRIKXLsd3+
+b/xa5IJVWa8xqQ==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCB
+lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
+Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
+dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3Qt
+SGFyZHdhcmUwHhcNOTkwNzA5MTgxMDQyWhcNMTkwNzA5MTgxOTIyWjCBlzELMAkG
+A1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEe
+MBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8v
+d3d3LnVzZXJ0cnVzdC5jb20xHzAdBgNVBAMTFlVUTi1VU0VSRmlyc3QtSGFyZHdh
+cmUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCx98M4P7Sof885glFn
+0G2f0v9Y8+efK+wNiVSZuTiZFvfgIXlIwrthdBKWHTxqctU8EGc6Oe0rE81m65UJ
+M6Rsl7HoxuzBdXmcRl6Nq9Bq/bkqVRcQVLMZ8Jr28bFdtqdt++BxF2uiiPsA3/4a
+MXcMmgF6sTLjKwEHOG7DpV4jvEWbe1DByTCP2+UretNb+zNAHqDVmBe8i4fDidNd
+oI6yqqr2jmmIBsX6iSHzCJ1pLgkzmykNRg+MzEk0sGlRvfkGzWitZky8PqxhvQqI
+DsjfPe58BEydCl5rkdbux+0ojatNh4lz0G6k0B4WixThdkQDf2Os5M1JnMWS9Ksy
+oUhbAgMBAAGjgbkwgbYwCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYD
+VR0OBBYEFKFyXyYbKJhDlV0HN9WFlp1L0sNFMEQGA1UdHwQ9MDswOaA3oDWGM2h0
+dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LUhhcmR3YXJlLmNy
+bDAxBgNVHSUEKjAoBggrBgEFBQcDAQYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEF
+BQcDBzANBgkqhkiG9w0BAQUFAAOCAQEARxkP3nTGmZev/K0oXnWO6y1n7k57K9cM
+//bey1WiCuFMVGWTYGufEpytXoMs61quwOQt9ABjHbjAbPLPSbtNk28Gpgoiskli
+CE7/yMgUsogWXecB5BKV5UU0s4tpvc+0hY91UZ59Ojg6FEgSxvunOxqNDYJAB+gE
+CJChicsZUN/KHAG8HQQZexB2lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t
+3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kniCrVWFCVH/A7HFe7fRQ5YiuayZSS
+KqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67nfhmqA==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUFADBr
+MQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRl
+cm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNv
+bW1lcmNlIFJvb3QwHhcNMDIwNjI2MDIxODM2WhcNMjIwNjI0MDAxNjEyWjBrMQsw
+CQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRlcm5h
+dGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xHDAaBgNVBAMTE1Zpc2EgZUNvbW1l
+cmNlIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvV95WHm6h
+2mCxlCfLF9sHP4CFT8icttD0b0/Pmdjh28JIXDqsOTPHH2qLJj0rNfVIsZHBAk4E
+lpF7sDPwsRROEW+1QK8bRaVK7362rPKgH1g/EkZgPI2h4H3PVz4zHvtH8aoVlwdV
+ZqW1LS7YgFmypw23RuwhY/81q6UCzyr0TP579ZRdhE2o8mCP2w4lPJ9zcc+U30rq
+299yOIzzlr3xF7zSujtFWsan9sYXiwGd/BmoKoMWuDpI/k4+oKsGGelT84ATB+0t
+vz8KPFUgOSwsAGl0lUq8ILKpeeUYiZGo3BxN77t+Nwtd/jmliFKMAGzsGHxBvfaL
+dXe6YJ2E5/4tAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD
+AgEGMB0GA1UdDgQWBBQVOIMPPyw/cDMezUb+B4wg4NfDtzANBgkqhkiG9w0BAQUF
+AAOCAQEAX/FBfXxcCLkr4NWSR/pnXKUTwwMhmytMiUbPWU3J/qVAtmPN3XEolWcR
+zCSs00Rsca4BIGsDoo8Ytyk6feUWYFN4PMCvFYP3j1IzJL1kk5fui/fbGKhtcbP3
+LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pzzkWKsKZJ/0x9nXGIxHYdkFsd
+7v3M9+79YKWxehZx0RbQfBI8bGmX265fOZpwLwU8GUYEmSA20GBuYQa7FkKMcPcw
+++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/hC3euiInlhBx6yLt
+398znM/jra6O1I7mT1GvFpLgXPYHDw==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFpDCCA4ygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEc
+MBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBP
+bmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAyMB4XDTAyMDUyODA2
+MDAwMFoXDTM3MDkyOTE0MDgwMFowYzELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0Ft
+ZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2EgT25saW5lIFJvb3Qg
+Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIP
+ADCCAgoCggIBAMxBRR3pPU0Q9oyxQcngXssNt79Hc9PwVU3dxgz6sWYFas14tNwC
+206B89enfHG8dWOgXeMHDEjsJcQDIPT/DjsS/5uN4cbVG7RtIuOx238hZK+GvFci
+KtZHgVdEglZTvYYUAQv8f3SkWq7xuhG1m1hagLQ3eAkzfDJHA1zEpYNI9FdWboE2
+JxhP7JsowtS013wMPgwr38oE18aO6lhOqKSlGBxsRZijQdEt0sdtjRnxrXm3gT+9
+BoInLRBYBbV4Bbkv2wxrkJB+FFk4u5QkE+XRnRTf04JNRvCAOVIyD+OEsnpD8l7e
+Xz8d3eOyG6ChKiMDbi4BFYdcpnV1x5dhvt6G3NRI270qv0pV2uh9UPu0gBe4lL8B
+PeraunzgWGcXuVjgiIZGZ2ydEEdYMtA1fHkqkKJaEBEjNa0vzORKW6fIJ/KD3l67
+Xnfn6KVuY8INXWHQjNJsWiEOyiijzirplcdIz5ZvHZIlyMbGwcEMBawmxNJ10uEq
+Z8A9W6Wa6897GqidFEXlD6CaZd4vKL3Ob5Rmg0gp2OpljK+T2WSfVVcmv2/LNzGZ
+o2C7HK2JNDJiuEMhBnIMoVxtRsX6Kc8w3onccVvdtjc+31D1uAclJuW8tf48ArO3
++L5DwYcRlJ4jbBeKuIonDFRH8KmzwICMoCfrHRnjB453cMor9H124HhnAgMBAAGj
+YzBhMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE1FwWg4u3OpaaEg5+31IqEj
+FNeeMB8GA1UdIwQYMBaAFE1FwWg4u3OpaaEg5+31IqEjFNeeMA4GA1UdDwEB/wQE
+AwIBhjANBgkqhkiG9w0BAQUFAAOCAgEAZ2sGuV9FOypLM7PmG2tZTiLMubekJcmn
+xPBUlgtk87FYT15R/LKXeydlwuXK5w0MJXti4/qftIe3RUavg6WXSIylvfEWK5t2
+LHo1YGwRgJfMqZJS5ivmae2p+DYtLHe/YUjRYwu5W1LtGLBDQiKmsXeu3mnFzccc
+obGlHBD7GL4acN3Bkku+KVqdPzW+5X1R+FXgJXUjhx5c3LqdsKyzadsXg8n33gy8
+CNyRnqjQ1xU3c6U1uPx+xURABsPr+CKAXEfOAuMRn0T//ZoyzH1kUQ7rVyZ2OuMe
+IjzCpjbdGe+n/BLzJsBZMYVMnNjP36TMzCmT/5RtdlwTCJfy7aULTd3oyWgOZtMA
+DjMSW7yV5TKQqLPGbIOtd+6Lfn6xqavT4fG2wLHqiMDn05DpKJKUe2h7lyoKZy2F
+AjgQ5ANh1NolNscIWC2hp1GvMApJ9aZphwctREZ2jirlmjvXGKL8nDgQzMY70rUX
+Om/9riW99XJZZLF0KjhfGEzfz3EEWjbUvy+ZnOjZurGV5gJLIaFb1cFPj65pbVPb
+AZO1XB4Y3WRayhgoPmMEEf0cjQAPuDffZ4qdZqkCapH/E8ovXYO8h5Ns3CRRFgQl
+Zvqz2cK6Kb6aSDiCmfS/O0oxGfm/jiEzFMpPVF/7zvuPcX/9XhmgD0uRuMRUvAaw
+RY8mkaKO/qk=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYD
+VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0
+ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0G
+CSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTAeFw0wOTA2MTYxMTMwMThaFw0y
+OTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3Qx
+FjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3pp
+Z25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o
+dTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvP
+kd6mJviZpWNwrZuuyjNAfW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tc
+cbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG0IMZfcChEhyVbUr02MelTTMuhTlAdX4U
+fIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKApxn1ntxVUwOXewdI/5n7
+N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm1HxdrtbC
+xkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1
++rUCAwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G
+A1UdDgQWBBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPM
+Pcu1SCOhGnqmKrs0aDAbBgNVHREEFDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqG
+SIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0olZMEyL/azXm4Q5DwpL7v8u8h
+mLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfXI/OMn74dseGk
+ddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775
+tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c
+2Pm2G2JwCz02yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5t
+HMN1Rq41Bab2XD0h7lbwyYIiLXpUq3DDfSJlgnCW
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIHqTCCBZGgAwIBAgIQYwaGp8U3ZaVDkKhqWMzUMjANBgkqhkiG9w0BAQUFADCB
+jzELMAkGA1UEBhMCTFYxNTAzBgNVBAoTLFZBUyBMYXR2aWphcyBQYXN0cyAtIFZp
+ZW4ucmVnLk5yLjQwMDAzMDUyNzkwMSMwIQYDVQQLExpTZXJ0aWZpa2FjaWphcyBw
+YWthbHBvanVtaTEkMCIGA1UEAxMbVkFTIExhdHZpamFzIFBhc3RzIFNTSShSQ0Ep
+MB4XDTA2MDkxMzA5MjIxMFoXDTI0MDkxMzA5Mjc1N1owgY8xCzAJBgNVBAYTAkxW
+MTUwMwYDVQQKEyxWQVMgTGF0dmlqYXMgUGFzdHMgLSBWaWVuLnJlZy5Oci40MDAw
+MzA1Mjc5MDEjMCEGA1UECxMaU2VydGlmaWthY2lqYXMgcGFrYWxwb2p1bWkxJDAi
+BgNVBAMTG1ZBUyBMYXR2aWphcyBQYXN0cyBTU0koUkNBKTCCAiIwDQYJKoZIhvcN
+AQEBBQADggIPADCCAgoCggIBAJu4+f1hVS9PpKUUtS6OuSSPrPuxVD9A/0/F5YZo
+e1OT+zWCNahQLpRSoNuDPnXaFXCsCc/ugkmtNkm5tHGLtAChQgbKCApjl7YI/O60
+3Jh4GYLJ+H9kPqrJ/rGN67Bk9bzzxD46kOpOjj8bGbxqg8ORPGxV+wpSwOjhXXeF
+M8VJ3+xqv79sN/6OSaIVGM6LjmseOKMwb4iBfnJWRBrEejkP9sSPltSy6wBOXN67
+5zu35iQFk2tN5pFEv+6YG8eFGxFBeyI2p74+6Ho33BjekJ2PzbLXmj/iF39bDOHv
+P2Y9biTksM7DDIhslNo4JXxSOeNzFLMARWOaDEJAXgTG93JkzsluM7Pk020klTeT
+fvIAXRmLH/NDc6ifRdIGqey0Qrv67gzHTz9RH9Gv0KwYf4eBIv6p3QeWbXz4TtlN
+OlBp1UF+xdp02I5z5X6D4cMZgbe9v0COvi6aogyqTgIuuyrhCF0xA8msJ7Cv3NXI
+FH1AnVWJIfmQzNTJYEFzq+jN2DpVOQqCmf6b9fU8HJHLwPpGVK4h/CqsXHveepdx
+/WxrzUiapNuBfBg3L5B9YZS9F8lctlQWd8oJSqrpvE+UdQFaVryS0o+515feVnQB
+9xZxSbH1GEaZQe5i4bMsZXVpKXJDA/ibH/o49J7sQBCOrJfVsDO+nxjcLfdBeFRK
+YkTnAgMBAAGjggH9MIIB+TAOBgNVHQ8BAf8EBAMCAQYwGAYIKwYBBQUHAQMEDDAK
+MAgGBgQAjkYBATAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTMw/Vm/3OsOFqW
+GyGJuIFMH8teJTAQBgkrBgEEAYI3FQEEAwIBADCCAYkGA1UdIASCAYAwggF8MIIB
+eAYLKwYBBAGBxFkBAQIwggFnMIIBOAYIKwYBBQUHAgIwggEqHoIBJgBTAGkAcwAg
+AGkAcgAgAHMAZQByAHQAaQBmAGkAawBhAHQAcwAsACAAawBvACAAaQB6AGQAZQB2
+AGkAcwAgAFYAQQBTACAATABhAHQAdgBpAGoAYQBzACAAUABhAHMAdABzACwAIABu
+AG8AZAByAG8AcwBpAG4AbwB0ACAAYQB0AGIAaQBsAHMAdABpAGIAdQAgAEUAbABl
+AGsAdAByAG8AbgBpAHMAawBvACAAZABvAGsAdQBtAGUAbgB0AHUAIABsAGkAawB1
+AG0AYQBtACAAdQBuACAARQBpAHIAbwBwAGEAcwAgAFAAYQByAGwAYQBtAGUAbgB0
+AGEAIABkAGkAcgBlAGsAdABpAHYAYQBpACAAMQA5ADkAOQAvADkAMwAvAEUASzAp
+BggrBgEFBQcCARYdaHR0cDovL3d3dy5lLW1lLmx2L3JlcG9zaXRvcnkwDQYJKoZI
+hvcNAQEFBQADggIBAB8oSjWQIWNoCi94r6MegiaXoz8nGdJLo0J6BhNlW8EEy+t9
+fO+U8vGJ9bffUgIhadLqljTloM+XuJxVDhCFoxReLAX4tTp28/l6uN62DCdp8suU
+kQsdudWOb5kvzfIZVjk6SFbwAf+Cdbay/dHU9fJjV0xNoX7MELoEae/0FPyzlx9F
+7m9KKH/Rxie8x6Opa3vtghNvq94P+3HrXBEaqSzQMJ/8NjdW75XpurcTtq6fAmGt
+nuxrBG82nw+Z98LJyEwouSjUIdeeVNXAzvSO5FWUe48kxjj8q3qkVnc9qEXvZJKk
+0Ep+u3OL9A1Sc7g6SF5DgNOpcHdi/8coHHMeQ+YnJFtJueY2pI79xS0veqV5EnrX
+IbIlbcgPosNhS+VI4le6n/KKId3bZPDaGd/OwJuAOcJ3d2MVU3KE+qSPBzeGIX1Q
++j1qN9uRDjez/c4Lynth0Jx0nH04aG3pex3W8Sq07ztgUncF5gLCX4xbvPB9t3PH
+kWuyKrNjozTVq60lcUf/Gj56to2VdsPups0DCWzuRWeYz5lIdsHOinSaaFIBNCLI
+7eIUC4S9bhCMsXKbvugI11fVf+q0AT1O5OLoZ+eMfunnQhHvlUbIkda+JxeAGTSY
+58bfHvwhX56GPbx+8Jy9cp70R4JbcWfz+txUTKhc2FnH0AcOEzMnvPRp8Gsh
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEDzCCAvegAwIBAgIBATANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQGEwJTSzET
+MBEGA1UEBxMKQnJhdGlzbGF2YTETMBEGA1UEChMKRGlzaWcgYS5zLjERMA8GA1UE
+AxMIQ0EgRGlzaWcwHhcNMDYwMzIyMDEzOTM0WhcNMTYwMzIyMDEzOTM0WjBKMQsw
+CQYDVQQGEwJTSzETMBEGA1UEBxMKQnJhdGlzbGF2YTETMBEGA1UEChMKRGlzaWcg
+YS5zLjERMA8GA1UEAxMIQ0EgRGlzaWcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQCS9jHBfYj9mQGp2HvycXXxMcbzdWb6UShGhJd4NLxs/LxFWYgmGErE
+Nx+hSkS943EE9UQX4j/8SFhvXJ56CbpRNyIjZkMhsDxkovhqFQ4/61HhVKndBpnX
+mjxUizkDPw/Fzsbrg3ICqB9x8y34dQjbYkzo+s7552oftms1grrijxaSfQUMbEYD
+XcDtab86wYqg6I7ZuUUohwjstMoVvoLdtUSLLa2GDGhibYVW8qwUYzrG0ZmsNHhW
+S8+2rT+MitcE5eN4TPWGqvWP+j1scaMtymfraHtuM6kMgiioTGohQBUgDCZbg8Kp
+FhXAJIJdKxatymP2dACw30PEEGBWZ2NFAgMBAAGjgf8wgfwwDwYDVR0TAQH/BAUw
+AwEB/zAdBgNVHQ4EFgQUjbJJaJ1yCCW5wCf1UJNWSEZx+Y8wDgYDVR0PAQH/BAQD
+AgEGMDYGA1UdEQQvMC2BE2Nhb3BlcmF0b3JAZGlzaWcuc2uGFmh0dHA6Ly93d3cu
+ZGlzaWcuc2svY2EwZgYDVR0fBF8wXTAtoCugKYYnaHR0cDovL3d3dy5kaXNpZy5z
+ay9jYS9jcmwvY2FfZGlzaWcuY3JsMCygKqAohiZodHRwOi8vY2EuZGlzaWcuc2sv
+Y2EvY3JsL2NhX2Rpc2lnLmNybDAaBgNVHSAEEzARMA8GDSuBHpGT5goAAAABAQEw
+DQYJKoZIhvcNAQEFBQADggEBAF00dGFMrzvY/59tWDYcPQuBDRIrRhCA/ec8J9B6
+yKm2fnQwM6M6int0wHl5QpNt/7EpFIKrIYwvF/k/Ji/1WcbvgAa3mkkp7M5+cTxq
+EEHA9tOasnxakZzArFvITV734VP/Q3f8nktnbNfzg9Gg4H8l37iYC5oyOGwwoPP/
+CBUz91BKez6jPiCp3C9WgArtQVCwyfTssuMmRAAOb54GvCKWU3BlxFAKRmukLyeB
+EicTXxChds6KezfqwzlhA5WYOudsiCUI/HloDYd9Yvi0X/vF2Ey9WLw/Q1vUHgFN
+PGO+I++MzVpQuGhU+QqZMxEA4Z7CRneC9VkGjCFMhwnN5ag=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDXTCCAkWgAwIBAgIDAOJCMA0GCSqGSIb3DQEBBQUAMFUxCzAJBgNVBAYTAkFU
+MRAwDgYDVQQKEwdBLVRydXN0MRkwFwYDVQQLExBBLVRydXN0LW5RdWFsLTAxMRkw
+FwYDVQQDExBBLVRydXN0LW5RdWFsLTAxMB4XDTA0MTEzMDIzMDAwMFoXDTE0MTEz
+MDIzMDAwMFowVTELMAkGA1UEBhMCQVQxEDAOBgNVBAoTB0EtVHJ1c3QxGTAXBgNV
+BAsTEEEtVHJ1c3QtblF1YWwtMDExGTAXBgNVBAMTEEEtVHJ1c3QtblF1YWwtMDEw
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQD/9RyAEZ6eHmhYzNJ328f0
+jmdSUFi6EqRqOxb3jHNPTIpK82CR6z5lmSnZQNUuCPD+htbNZffd2DKVB06NOyZ1
+2zcOMCgj4GtkZoqE0zPpPT3bpoE55nkZZe/qWEX/64wz/L/4EdkvKDSKG/UsP75M
+tmCVY5m2Eg73RVFRz4ccBIMpHel4lzEqSkdDtZOY5fnkrE333hx67nxq21vY8Eyf
+8O4fPQ5RtN8eohQCcPQ1z6ypU1R7N9jPRpnI+yzMOiwd3+QcKhHi1miCzo0pkOaB
+1CwmfsTyNl8qU0NJUL9Ta6cea7WThwTiWol2yD88cd2cy388xpbNkfrCPmZNGLoV
+AgMBAAGjNjA0MA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0OBAoECE5ZzscCMocwMA4G
+A1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEA69I9R1hU9Gbl9vV7W7AH
+QpUJAlFAvv2It/eY8p2ouQUPVaSZikaKtAYrCD/arzfXB43Qet+dM6CpHsn8ikYR
+vQKePjXv3Evf+C1bxwJAimcnZV6W+bNOTpdo8lXljxkmfN+Z5S+XzvK2ttUtP4Et
+YOVaxHw2mPMNbvDeY+foJkiBn3KYjGabMaR8moZqof5ofj4iS/WyamTZti6v/fKx
+n1vII+/uWkcxV5DT5+r9HLon0NYF0Vg317Wh+gWDV59VZo+dcwJDb+keYqMFYoqp
+77SGkZGu41S8NGYkQY3X9rNHRkDbLfpKYDmy6NanpOE1EHW1/sNSFAs43qZZKJEQ
+xg==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEojCCA4qgAwIBAgIQRL4Mi1AAJLQR0zYlJWfJiTANBgkqhkiG9w0BAQUFADCB
+rjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
+Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
+dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xNjA0BgNVBAMTLVVUTi1VU0VSRmlyc3Qt
+Q2xpZW50IEF1dGhlbnRpY2F0aW9uIGFuZCBFbWFpbDAeFw05OTA3MDkxNzI4NTBa
+Fw0xOTA3MDkxNzM2NThaMIGuMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQxFzAV
+BgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5l
+dHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRydXN0LmNvbTE2MDQGA1UE
+AxMtVVROLVVTRVJGaXJzdC1DbGllbnQgQXV0aGVudGljYXRpb24gYW5kIEVtYWls
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsjmFpPJ9q0E7YkY3rs3B
+YHW8OWX5ShpHornMSMxqmNVNNRm5pELlzkniii8efNIxB8dOtINknS4p1aJkxIW9
+hVE1eaROaJB7HHqkkqgX8pgV8pPMyaQylbsMTzC9mKALi+VuG6JG+ni8om+rWV6l
+L8/K2m2qL+usobNqqrcuZzWLeeEeaYji5kbNoKXqvgvOdjp6Dpvq/NonWz1zHyLm
+SGHGTPNpsaguG7bUMSAsvIKKjqQOpdeJQ/wWWq8dcdcRWdq6hw2v+vPhwvCkxWeM
+1tZUOt4KpLoDd7NlyP0e03RiqhjKaJMeoYV+9Udly/hNVyh00jT/MLbu9mIwFIws
+6wIDAQABo4G5MIG2MAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud
+DgQWBBSJgmd9xJ0mcABLtFBIfN49rgRufTBYBgNVHR8EUTBPME2gS6BJhkdodHRw
+Oi8vY3JsLnVzZXJ0cnVzdC5jb20vVVROLVVTRVJGaXJzdC1DbGllbnRBdXRoZW50
+aWNhdGlvbmFuZEVtYWlsLmNybDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUH
+AwQwDQYJKoZIhvcNAQEFBQADggEBALFtYV2mGn98q0rkMPxTbyUkxsrt4jFcKw7u
+7mFVbwQ+zznexRtJlOTrIEy05p5QLnLZjfWqo7NK2lYcYJeA3IKirUq9iiv/Cwm0
+xtcgBEXkzYABurorbs6q15L+5K/r9CYdFip/bDCVNy8zEqx/3cfREYxRmLLQo5HQ
+rfafnoOTHh1CuEava2bwm3/q4wMC5QJRwarVNZ1yQAOJujEdxRBoUp7fooXFXAim
+eOZTT7Hot9MUnpOmw2TjrH5xzbyf6QMbzPvprDHBr3wVdAKZw7JHpsIyYdfHb0gk
+USeh1YdV8nuPmD0Wnu51tvjQjvLzxq4oW6fw8zYX/MMF08oDSlQ=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UE
+BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVz
+dCBQcmVtaXVtMB4XDTEwMDEyOTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkG
+A1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1U
+cnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxBLf
+qV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtnBKAQ
+JG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ
++jjeRFcV5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrS
+s8PhaJyJ+HoAVt70VZVs+7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5
+HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmdGPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d7
+70O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5Rp9EixAqnOEhss/n/fauG
+V+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NIS+LI+H+S
+qHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S
+5u046uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4Ia
+C1nEWTJ3s7xgaVY5/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TX
+OwF0lkLgAOIua+rF7nKsu7/+6qqo+Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYE
+FJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/
+BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByvMiPIs0laUZx2
+KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg
+Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B
+8OWycvpEgjNC6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQ
+MKSOyARiqcTtNd56l+0OOF6SL5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc
+0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK+4w1IX2COPKpVJEZNZOUbWo6xbLQ
+u4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmVBtWVyuEklut89pMF
+u+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFgIxpH
+YoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8
+GKa1qF60g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaO
+RtGdFNrHF+QFlozEJLUbzxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6e
+KeC2uAloGRwYQw==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEFTCCAv2gAwIBAgIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJTRTEU
+MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3
+b3JrMSAwHgYDVQQDExdBZGRUcnVzdCBQdWJsaWMgQ0EgUm9vdDAeFw0wMDA1MzAx
+MDQxNTBaFw0yMDA1MzAxMDQxNTBaMGQxCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtB
+ZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIDAeBgNV
+BAMTF0FkZFRydXN0IFB1YmxpYyBDQSBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOC
+AQ8AMIIBCgKCAQEA6Rowj4OIFMEg2Dybjxt+A3S72mnTRqX4jsIMEZBRpS9mVEBV
+6tsfSlbunyNu9DnLoblv8n75XYcmYZ4c+OLspoH4IcUkzBEMP9smcnrHAZcHF/nX
+GCwwfQ56HmIexkvA/X1id9NEHif2P0tEs7c42TkfYNVRknMDtABp4/MUTu7R3AnP
+dzRGULD4EfL+OHn3Bzn+UZKXC1sIXzSGAa2Il+tmzV7R/9x98oTaunet3IAIx6eH
+1lWfl2royBFkuucZKT8Rs3iQhCBSWxHveNCD9tVIkNAwHM+A+WD+eeSI8t0A65RF
+62WUaUC6wNW0uLp9BBGo6zEFlpROWCGOn9Bg/QIDAQABo4HRMIHOMB0GA1UdDgQW
+BBSBPjfYkrAfd59ctKtzquf2NGAv+jALBgNVHQ8EBAMCAQYwDwYDVR0TAQH/BAUw
+AwEB/zCBjgYDVR0jBIGGMIGDgBSBPjfYkrAfd59ctKtzquf2NGAv+qFopGYwZDEL
+MAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQLExRBZGRU
+cnVzdCBUVFAgTmV0d29yazEgMB4GA1UEAxMXQWRkVHJ1c3QgUHVibGljIENBIFJv
+b3SCAQEwDQYJKoZIhvcNAQEFBQADggEBAAP3FUr4JNojVhaTdt02KLmuG7jD8WS6
+IBh4lSknVwW8fCr0uVFV2ocC3g8WFzH4qnkuCRO7r7IgGRLlk/lL+YPoRNWyQSW/
+iHVv/xD8SlTQX/D67zZzfRs2RcYhbbQVuE7PnFylPVoAjgbjPGsye/Kf8Lb93/Ao
+GEjwxrzQvzSAlsJKsW2Ox5BF3i9nrEUEo3rcVZLJR2bYGozH7ZxOmuASu7VqTITh
+4SINhwBk/ox9Yjllpu9CtoAlEmEBqCQTcAARJl/6NVDFSMwGR+gn2HCNX2TmoUQm
+XiLsks3/QppEIW1cxeMiHV9HEufOX1362KqxMy3ZdvJOOjMMK7MtkAY=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEajCCA1KgAwIBAgIBATANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJKUDEN
+MAsGA1UECgwESlBLSTEpMCcGA1UECwwgUHJlZmVjdHVyYWwgQXNzb2NpYXRpb24g
+Rm9yIEpQS0kxETAPBgNVBAsMCEJyaWRnZUNBMB4XDTAzMTIyNzA1MDgxNVoXDTEz
+MTIyNjE0NTk1OVowWjELMAkGA1UEBhMCSlAxDTALBgNVBAoMBEpQS0kxKTAnBgNV
+BAsMIFByZWZlY3R1cmFsIEFzc29jaWF0aW9uIEZvciBKUEtJMREwDwYDVQQLDAhC
+cmlkZ2VDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANTnUmg7K3m8
+52vd77kwkq156euwoWm5no8E8kmaTSc7x2RABPpqNTlMKdZ6ttsyYrqREeDkcvPL
+yF7yf/I8+innasNtsytcTAy8xY8Avsbd4JkCGW9dyPjk9pzzc3yLQ64Rx2fujRn2
+agcEVdPCr/XpJygX8FD5bbhkZ0CVoiASBmlHOcC3YpFlfbT1QcpOSOb7o+VdKVEi
+MMfbBuU2IlYIaSr/R1nO7RPNtkqkFWJ1/nKjKHyzZje7j70qSxb+BTGcNgTHa1YA
+UrogKB+UpBftmb4ds+XlkEJ1dvwokiSbCDaWFKD+YD4B2s0bvjCbw8xuZFYGhNyR
+/2D5XfN1s2MCAwEAAaOCATkwggE1MA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E
+BTADAQH/MG0GA1UdHwRmMGQwYqBgoF6kXDBaMQswCQYDVQQGEwJKUDENMAsGA1UE
+CgwESlBLSTEpMCcGA1UECwwgUHJlZmVjdHVyYWwgQXNzb2NpYXRpb24gRm9yIEpQ
+S0kxETAPBgNVBAsMCEJyaWRnZUNBMIGDBgNVHREEfDB6pHgwdjELMAkGA1UEBhMC
+SlAxJzAlBgNVBAoMHuWFrOeahOWAi+S6uuiqjeiovOOCteODvOODk+OCuTEeMBwG
+A1UECwwV6YO96YGT5bqc55yM5Y2U6K2w5LyaMR4wHAYDVQQLDBXjg5bjg6rjg4Pj
+grjoqo3oqLzlsYAwHQYDVR0OBBYEFNQXMiCqQNkR2OaZmQgLtf8mR8p8MA0GCSqG
+SIb3DQEBBQUAA4IBAQATjJo4reTNPC5CsvAKu1RYT8PyXFVYHbKsEpGt4GR8pDCg
+HEGAiAhHSNrGh9CagZMXADvlG0gmMOnXowriQQixrtpkmx0TB8tNAlZptZWkZC+R
+8TnjOkHrk2nFAEC3ezbdK0R7MR4tJLDQCnhEWbg50rf0wZ/aF8uAaVeEtHXa6W0M
+Xq3dSe0XAcrLbX4zZHQTaWvdpLAIjl6DZ3SCieRMyoWUL+LXaLFdTP5WBCd+No58
+IounD9X4xxze2aeRVaiV/WnQ0OSPNS7n7YXy6xQdnaOU4KRW/Lne1EDf5IfWC/ih
+bVAmhZMbcrkWWcsR6aCPG+2mV3zTD6AUzuKPal8Y
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG
+A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv
+b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw
+MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i
+YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT
+aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ
+jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp
+xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp
+1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG
+snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ
+U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8
+9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E
+BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B
+AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz
+yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE
+38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP
+AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad
+DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME
+HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDdTCCAl2gAwIBAgILAgAAAAAA1ni3lAUwDQYJKoZIhvcNAQEEBQAwVzELMAkG
+A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv
+b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw
+MDBaFw0xNDAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i
+YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT
+aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ
+jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp
+xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp
+1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG
+snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ
+U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8
+9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIABjAdBgNVHQ4EFgQU
+YHtmGkUNl8qJUC99BM00qP/8/UswDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0B
+AQQFAAOCAQEArqqf/LfSyx9fOSkoGJ40yWxPbxrwZKJwSk8ThptgKJ7ogUmYfQq7
+5bCdPTbbjwVR/wkxKh/diXeeDy5slQTthsu0AD+EAk2AaioteAuubyuig0SDH81Q
+gkwkr733pbTIWg/050deSY43lv6aiAU62cDbKYfmGZZHpzqmjIs8d/5GY6dT2iHR
+rH5Jokvmw2dZL7OKDrssvamqQnw1wdh/1acxOk5jQzmvCLBhNIzTmKlDNPYPhyk7
+ncJWWJh3w/cbrPad+D6qp1RF8PX51TFl/mtYnHGzHtdS6jIX/EBgHcl5JLL2bP2o
+Zg6C3ZjL2sJETy6ge/L3ayx2EYRGinij4w==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEKzCCAxOgAwIBAgIEOsylTDANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJE
+SzEVMBMGA1UEChMMVERDIEludGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQg
+Um9vdCBDQTAeFw0wMTA0MDUxNjMzMTdaFw0yMTA0MDUxNzAzMTdaMEMxCzAJBgNV
+BAYTAkRLMRUwEwYDVQQKEwxUREMgSW50ZXJuZXQxHTAbBgNVBAsTFFREQyBJbnRl
+cm5ldCBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxLhA
+vJHVYx/XmaCLDEAedLdInUaMArLgJF/wGROnN4NrXceO+YQwzho7+vvOi20jxsNu
+Zp+Jpd/gQlBn+h9sHvTQBda/ytZO5GhgbEaqHF1j4QeGDmUApy6mcca8uYGoOn0a
+0vnRrEvLznWv3Hv6gXPU/Lq9QYjUdLP5Xjg6PEOo0pVOd20TDJ2PeAG3WiAfAzc1
+4izbSysseLlJ28TQx5yc5IogCSEWVmb/Bexb4/DPqyQkXsN/cHoSxNK1EKC2IeGN
+eGlVRGn1ypYcNIUXJXfi9i8nmHj9eQY6otZaQ8H/7AQ77hPv01ha/5Lr7K7a8jcD
+R0G2l8ktCkEiu7vmpwIDAQABo4IBJTCCASEwEQYJYIZIAYb4QgEBBAQDAgAHMGUG
+A1UdHwReMFwwWqBYoFakVDBSMQswCQYDVQQGEwJESzEVMBMGA1UEChMMVERDIElu
+dGVybmV0MR0wGwYDVQQLExRUREMgSW50ZXJuZXQgUm9vdCBDQTENMAsGA1UEAxME
+Q1JMMTArBgNVHRAEJDAigA8yMDAxMDQwNTE2MzMxN1qBDzIwMjEwNDA1MTcwMzE3
+WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUbGQBx/2FbazI2p5QCIUItTxWqFAw
+HQYDVR0OBBYEFGxkAcf9hW2syNqeUAiFCLU8VqhQMAwGA1UdEwQFMAMBAf8wHQYJ
+KoZIhvZ9B0EABBAwDhsIVjUuMDo0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4IBAQBO
+Q8zR3R0QGwZ/t6T609lN+yOfI1Rb5osvBCiLtSdtiaHsmGnc540mgwV5dOy0uaOX
+wTUA/RXaOYE6lTGQ3pfphqiZdwzlWqCE/xIWrG64jcN7ksKsLtB9KOy282A4aW8+
+2ARVPp7MVdK6/rtHBNcK2RYKNCn1WBPVT8+PVkuzHu7TmHnaCB4Mb7j4Fifvwm89
+9qNLPg7kbWzbO0ESm70NRyN/PErQr8Cv9u8btRXE64PECV90i9kR+8JWsTz4cMo0
+jUNAE4z9mQNUecYu6oah9jrUCbz0vGbMPVjQV0kK7iXiQe4T+Zs4NNEA9X7nlB38
+aQNiuJkFBT1reBK9sG9l
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEk
+MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpH
+bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX
+DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD
+QSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu
+MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprlOQcJ
+FspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAw
+DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61F
+uOJAf/sKbvu+M8k8o4TVMAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGX
+kPoUVy0D7O48027KqGx2vKLeuwIgJ6iFJzWbVsaj8kfSt24bAgAXqmemFZHe+pTs
+ewv4n4Q=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJC
+TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0
+aWZpY2F0aW9uIEF1dGhvcml0eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0
+aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAzMTkxODMzMzNaFw0yMTAzMTcxODMz
+MzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUw
+IwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQDEyVR
+dW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Yp
+li4kVEAkOPcahdxYTMukJ0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2D
+rOpm2RgbaIr1VxqYuvXtdj182d6UajtLF8HVj71lODqV0D1VNk7feVcxKh7YWWVJ
+WCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeLYzcS19Dsw3sgQUSj7cug
+F+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWenAScOospU
+xbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCC
+Ak4wPQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVv
+dmFkaXNvZmZzaG9yZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREw
+ggENMIIBCQYJKwYBBAG+WAABMIH7MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNl
+IG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBh
+c3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFy
+ZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh
+Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYI
+KwYBBQUHAgEWFmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3T
+KbkGGew5Oanwl4Rqy+/fMIGuBgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rq
+y+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1p
+dGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYD
+VQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6tlCL
+MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSk
+fnIYj9lofFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf8
+7C9TqnN7Az10buYWnuulLsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1R
+cHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2xgI4JVrmcGmD+XcHXetwReNDWXcG31a0y
+mQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi5upZIof4l/UO/erMkqQW
+xFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi5nrQNiOK
+SnQ2+Q==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx
+KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd
+BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl
+YyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgxMDAxMTA0MDE0WhcNMzMxMDAxMjM1
+OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy
+aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50
+ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUd
+AqSzm1nzHoqvNK38DcLZSBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiC
+FoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/FvudocP05l03Sx5iRUKrERLMjfTlH6VJi
+1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx9702cu+fjOlbpSD8DT6Iavq
+jnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGVWOHAD3bZ
+wI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGj
+QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/
+WSA2AHmgoCJrjNXyYdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhy
+NsZt+U2e+iKo4YFWz827n+qrkRk4r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPAC
+uvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNfvNoBYimipidx5joifsFvHZVw
+IEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR3p1m0IvVVGb6
+g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN
+9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlP
+BSeOE6Fuwg==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAw
+NzEUMBIGA1UECgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJv
+b3QgQ0EgdjEwHhcNMDcxMDE4MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYD
+VQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwWVGVsaWFTb25lcmEgUm9vdCBDQSB2
+MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+6yfwIaPzaSZVfp3F
+VRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA3GV1
+7CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+X
+Z75Ljo1kB1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+
+/jXh7VB7qTCNGdMJjmhnXb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs
+81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxHoLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkm
+dtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3F0fUTPHSiXk+TT2YqGHe
+Oh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJoWjiUIMu
+sDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4
+pgd7gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fs
+slESl1MpWtTwEhDcTwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQ
+arMCpgKIv7NHfirZ1fpoeDVNAgMBAAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYD
+VR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qWDNXr+nuqF+gTEjANBgkqhkiG
+9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNmzqjMDfz1mgbl
+dxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx
+0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1Tj
+TQpgcmLNkQfWpb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBed
+Y2gea+zDTYa4EzAvXUYNR0PVG6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7
+Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpcc41teyWRyu5FrgZLAMzTsVlQ2jqI
+OylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOTJsjrDNYmiLbAJM+7
+vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2qReW
+t88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcn
+HL/EVlP6Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVx
+SK236thZiNSQvxaz2emsWWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCB
+qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf
+Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw
+MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV
+BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3MDAwMDAwWhcNMzYw
+NzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5j
+LjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYG
+A1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl
+IG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqG
+SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsoPD7gFnUnMekz52hWXMJEEUMDSxuaPFs
+W0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ1CRfBsDMRJSUjQJib+ta
+3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGcq/gcfomk
+6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6
+Sk/KaAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94J
+NqR32HuHUETVPm4pafs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBA
+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XP
+r87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUFAAOCAQEAeRHAS7ORtvzw6WfU
+DW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeEuzLlQRHAd9mz
+YJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX
+xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2
+/qxAeeWsEG89jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/
+LHbTY5xZ3Y+m4Q6gLkH3LpVHz7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7
+jVaMaA==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDhDCCAmygAwIBAgIBCTANBgkqhkiG9w0BAQUFADAzMQswCQYDVQQGEwJDTjER
+MA8GA1UEChMIVW5pVHJ1c3QxETAPBgNVBAMTCFVDQSBSb290MB4XDTA0MDEwMTAw
+MDAwMFoXDTI5MTIzMTAwMDAwMFowMzELMAkGA1UEBhMCQ04xETAPBgNVBAoTCFVu
+aVRydXN0MREwDwYDVQQDEwhVQ0EgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBALNdB8qGJn1r4vs4CQ7MgsJqGgCiFV/W6dQBt1YDAVmP9ThpJHbC
+XivF9iu/r/tB/Q9a/KvXg3BNMJjRnrJ2u5LWu+kQKGkoNkTo8SzXWHwk1n8COvCB
+a2FgP/Qz3m3l6ihST/ypHWN8C7rqrsRoRuTej8GnsrZYWm0dLNmMOreIy4XU9+gD
+Xv2yTVDo1h//rgI/i0+WITyb1yXJHT/7mLFZ5PCpO6+zzYUs4mBGzG+OoOvwNMXx
+QhhgrhLtRnUc5dipllq+3lrWeGeWW5N3UPJuG96WUUqm1ktDdSFmjXfsAoR2XEQQ
+th1hbOSjIH23jboPkXXHjd+8AmCoKai9PUMCAwEAAaOBojCBnzALBgNVHQ8EBAMC
+AQYwDAYDVR0TBAUwAwEB/zBjBgNVHSUEXDBaBggrBgEFBQcDAQYIKwYBBQUHAwIG
+CCsGAQUFBwMDBggrBgEFBQcDBAYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEFBQcD
+BwYIKwYBBQUHAwgGCCsGAQUFBwMJMB0GA1UdDgQWBBTbHzXza0z/QjFkm827Wh4d
+SBC37jANBgkqhkiG9w0BAQUFAAOCAQEAOGy3iPGt+lg3dNHocN6cJ1nL5BXXoMNg
+14iABMUwTD3UGusGXllH5rxmy+AI/Og17GJ9ysDawXiv5UZv+4mCI4/211NmVaDe
+JRI7cTYWVRJ2+z34VFsxugAG+H1V5ad2g6pcSpemKijfvcZsCyOVjjN/Hl5AHxNU
+LJzltQ7dFyiuawHTUin1Ih+QOfTcYmjwPIZH7LgFRbu3DJaUxmfLI3HQjnQi1kHr
+A6i26r7EARK1s11AdgYg1GS4KUYGis4fk5oQ7vuqWrTcL9Ury/bXBYSYBZELhPc9
++tb5evosFeo2gkO3t7jj83EB7UNDogVFwygFBzXjAaU4HoDU18PZ3g==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCB
+ijELMAkGA1UEBhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHly
+aWdodCAoYykgMjAwNTEiMCAGA1UECxMZT0lTVEUgRm91bmRhdGlvbiBFbmRvcnNl
+ZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwgUm9vdCBHQSBDQTAeFw0w
+NTEyMTExNjAzNDRaFw0zNzEyMTExNjA5NTFaMIGKMQswCQYDVQQGEwJDSDEQMA4G
+A1UEChMHV0lTZUtleTEbMBkGA1UECxMSQ29weXJpZ2h0IChjKSAyMDA1MSIwIAYD
+VQQLExlPSVNURSBGb3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBX
+SVNlS2V5IEdsb2JhbCBSb290IEdBIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEAy0+zAJs9Nt350UlqaxBJH+zYK7LG+DKBKUOVTJoZIyEVRd7jyBxR
+VVuuk+g3/ytr6dTqvirdqFEr12bDYVxgAsj1znJ7O7jyTmUIms2kahnBAbtzptf2
+w93NvKSLtZlhuAGio9RN1AU9ka34tAhxZK9w8RxrfvbDd50kc3vkDIzh2TbhmYsF
+mQvtRTEJysIA2/dyoJaqlYfQjse2YXMNdmaM3Bu0Y6Kff5MTMPGhJ9vZ/yxViJGg
+4E8HsChWjBgbl0SOid3gF27nKu+POQoxhILYQBRJLnpB5Kf+42TMwVlxSywhp1t9
+4B3RLoGbw9ho972WG6xwsRYUC9tguSYBBQIDAQABo1EwTzALBgNVHQ8EBAMCAYYw
+DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUswN+rja8sHnR3JQmthG+IbJphpQw
+EAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBAEuh/wuHbrP5wUOx
+SPMowB0uyQlB+pQAHKSkq0lPjz0e701vvbyk9vImMMkQyh2I+3QZH4VFvbBsUfk2
+ftv1TDI6QU9bR8/oCy22xBmddMVHxjtqD6wU2zz0c5ypBd8A3HR4+vg1YFkCExh8
+vPtNsCBtQ7tgMHpnM1zFmdH4LTlSc/uMqpclXHLZCB6rTjzjgTGfA6b7wP4piFXa
+hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZi
+Fj4A4xylNoEYokxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ
+/L7fCg0=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDlDCCAnygAwIBAgIQWAsFbFMk27JQVxhf+eWmUDANBgkqhkiG9w0BAQUFADAn
+MQswCQYDVQQGEwJCRTEYMBYGA1UEAxMPQmVsZ2l1bSBSb290IENBMB4XDTAzMDEy
+NjIzMDAwMFoXDTE0MDEyNjIzMDAwMFowJzELMAkGA1UEBhMCQkUxGDAWBgNVBAMT
+D0JlbGdpdW0gUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+AMihcekcRkJ5eHFvna6pqKsot03HIOswkVp19eLSz8hMFJhCWK3HEcVAQGpa+XQS
+J4fpnOVxTiIs0RIYqjBeoiG52bv/9nTrMQHnO35YD5EWTXaJqAFPrSJmcPpLHZXB
+MFjqvNll2Jq0iOtJRlLf0lMVdssUXRlJsW9q09P9vMIt7EU/CT9YvvzU7wCMgTVy
+v/cY6pZifSsofxVsY9LKyn0FrMhtB20yvmi4BUCuVJhWPmbxMOjvxKuTXgfeMo8S
+dKpbNCNUwOpszv42kqgJF+qhLc9s44Qd3ocuMws8dOIhUDiVLlzg5cYx+dtA+mqh
+pIqTm6chBocdJ9PEoclMsG8CAwEAAaOBuzCBuDAOBgNVHQ8BAf8EBAMCAQYwDwYD
+VR0TAQH/BAUwAwEB/zBCBgNVHSAEOzA5MDcGBWA4AQEBMC4wLAYIKwYBBQUHAgEW
+IGh0dHA6Ly9yZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMB0GA1UdDgQWBBQQ8AxW
+m2HqVzq2NZdtn925FI7b5jARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAU
+EPAMVpth6lc6tjWXbZ/duRSO2+YwDQYJKoZIhvcNAQEFBQADggEBAMhtIlGKYfgP
+lm7VILKB+MbcoxYA2s1q52sq+llIp0xJN9dzoWoBZV4yveeX09AuPHPTjHuD79ZC
+wT+oqV0PN7p20kC9zC0/00RBSZz9Wyn0AiMiW3Ebv1jZKE4tRfTa57VjRUQRDSp/
+M382SbTObqkCMa5c/ciJv0J71/Fg8teH9lcuen5qE4Ad3OPQYx49cTGxYNSeCMqr
+8JTHSHVUgfMbrXec6LKP24OsjzRr6L/D2fVDw2RV6xq9NoY2uiGMlxoh1OotO6y6
+7Kcdq765Sps1LxxcHVGnH1TtEpf/8m6HfUbJdNbv6z195lluBpQE5KJVhzgoaiJe
+4r50ErAEQyo=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE
+BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz
+dCBDb21tZXJjaWFsMB4XDTEwMDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDEL
+MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp
+cm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6EqdbDuKP
+Hx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yr
+ba0F8PrVC8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPAL
+MeIrJmqbTFeurCA+ukV6BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1
+yHp52UKqK39c/s4mT6NmgTWvRLpUHhwwMmWd5jyTXlBOeuM61G7MGvv50jeuJCqr
+VwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNVHQ4EFgQUnZPGU4teyq8/
+nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ
+KoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYG
+XUPGhi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNj
+vbz4YYCanrHOQnDiqX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivt
+Z8SOyUOyXGsViQK8YvxO8rUzqrJv0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9g
+N53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0khsUlHRUe072o0EclNmsxZt9YC
+nlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRF
+MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBD
+bGFzcyAzIENBIDIgRVYgMjAwOTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUw
+NDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNV
+BAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAwOTCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfSegpn
+ljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM0
+3TP1YtHhzRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6Z
+qQTMFexgaDbtCHu39b+T7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lR
+p75mpoo6Kr3HGrHhFPC+Oh25z1uxav60sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8
+HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure3511H3a6UCAwEAAaOCASQw
+ggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyvcop9Ntea
+HNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFw
+Oi8vZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xh
+c3MlMjAzJTIwQ0ElMjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1E
+RT9jZXJ0aWZpY2F0ZXJldm9jYXRpb25saXN0MEagRKBChkBodHRwOi8vd3d3LmQt
+dHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xhc3NfM19jYV8yX2V2XzIwMDku
+Y3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+PPoeUSbrh/Yp
+3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05
+nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNF
+CSuGdXzfX2lXANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7na
+xpeG0ILD5EJt/rDiZE4OJudANCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqX
+KVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVvw9y4AyHqnxbxLFS1
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIF2TCCA8GgAwIBAgIQHp4o6Ejy5e/DfEoeWhhntjANBgkqhkiG9w0BAQsFADBk
+MQswCQYDVQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0
+YWwgQ2VydGlmaWNhdGUgU2VydmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3Qg
+Q0EgMjAeFw0xMTA2MjQwODM4MTRaFw0zMTA2MjUwNzM4MTRaMGQxCzAJBgNVBAYT
+AmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGlnaXRhbCBDZXJ0aWZp
+Y2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAyMIICIjAN
+BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAlUJOhJ1R5tMJ6HJaI2nbeHCOFvEr
+jw0DzpPMLgAIe6szjPTpQOYXTKueuEcUMncy3SgM3hhLX3af+Dk7/E6J2HzFZ++r
+0rk0X2s682Q2zsKwzxNoysjL67XiPS4h3+os1OD5cJZM/2pYmLcX5BtS5X4HAB1f
+2uY+lQS3aYg5oUFgJWFLlTloYhyxCwWJwDaCFCE/rtuh/bxvHGCGtlOUSbkrRsVP
+ACu/obvLP+DHVxxX6NZp+MEkUp2IVd3Chy50I9AU/SpHWrumnf2U5NGKpV+GY3aF
+y6//SSj8gO1MedK75MDvAe5QQQg1I3ArqRa0jG6F6bYRzzHdUyYb3y1aSgJA/MTA
+tukxGggo5WDDH8SQjhBiYEQN7Aq+VRhxLKX0srwVYv8c474d2h5Xszx+zYIdkeNL
+6yxSNLCK/RJOlrDrcH+eOfdmQrGrrFLadkBXeyq96G4DsguAhYidDMfCd7Camlf0
+uPoTXGiTOmekl9AbmbeGMktg2M7v0Ax/lZ9vh0+Hio5fCHyqW/xavqGRn1V9TrAL
+acywlKinh/LTSlDcX3KwFnUey7QYYpqwpzmqm59m2I2mbJYV4+by+PGDYmy7Velh
+k6M99bFXi08jsJvllGov34zflVEpYKELKeRcVVi3qPyZ7iVNTA6z00yPhOgpD/0Q
+VAKFyPnlw4vP5w8CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0hBBYw
+FDASBgdghXQBUwIBBgdghXQBUwIBMBIGA1UdEwEB/wQIMAYBAf8CAQcwHQYDVR0O
+BBYEFE0mICKJS9PVpAqhb97iEoHF8TwuMB8GA1UdIwQYMBaAFE0mICKJS9PVpAqh
+b97iEoHF8TwuMA0GCSqGSIb3DQEBCwUAA4ICAQAyCrKkG8t9voJXiblqf/P0wS4R
+fbgZPnm3qKhyN2abGu2sEzsOv2LwnN+ee6FTSA5BesogpxcbtnjsQJHzQq0Qw1zv
+/2BZf82Fo4s9SBwlAjxnffUy6S8w5X2lejjQ82YqZh6NM4OKb3xuqFp1mrjX2lhI
+REeoTPpMSQpKwhI3qEAMw8jh0FcNlzKVxzqfl9NX+Ave5XLzo9v/tdhZsnPdTSpx
+srpJ9csc1fV5yJmz/MFMdOO0vSk3FQQoHt5FRnDsr7p4DooqzgB53MBfGWcsa0vv
+aGgLQ+OswWIJ76bdZWGgr4RVSJFSHMYlkSrQwSIjYVmvRRGFHQEkNI/Ps/8XciAT
+woCqISxxOQ7Qj1zB09GOInJGTB2Wrk9xseEFKZZZ9LuedT3PDTcNYtsmjGOpI99n
+Bjx8Oto0QuFmtEYE3saWmA9LSHokMnWRn6z3aOkquVVlzl1h0ydw2Df+n7mvoC5W
+t6NlUe07qxS/TFED6F+KBZvuim6c779o+sjaC+NCydAXFJy3SuCvkychVSa1ZC+N
+8f+mQAWFBVzKBxlcCxMoTFh/wqXvRdpg065lYZ1Tg3TCrvJcwhbtkj6EPnNgiLx2
+9CzP0H1907he0ZESEOnN3col49XtmS++dYFLJPlFRpTJKSFTnCZFqhMX5OfNeOI5
+wSsSnqaeG8XmDtkx2Q==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEZjCCA06gAwIBAgIQRL4Mi1AAJLQR0zYt4LNfGzANBgkqhkiG9w0BAQUFADCB
+lTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
+Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
+dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHTAbBgNVBAMTFFVUTi1VU0VSRmlyc3Qt
+T2JqZWN0MB4XDTk5MDcwOTE4MzEyMFoXDTE5MDcwOTE4NDAzNlowgZUxCzAJBgNV
+BAYTAlVTMQswCQYDVQQIEwJVVDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkxHjAc
+BgNVBAoTFVRoZSBVU0VSVFJVU1QgTmV0d29yazEhMB8GA1UECxMYaHR0cDovL3d3
+dy51c2VydHJ1c3QuY29tMR0wGwYDVQQDExRVVE4tVVNFUkZpcnN0LU9iamVjdDCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM6qgT+jo2F4qjEAVZURnicP
+HxzfOpuCaDDASmEd8S8O+r5596Uj71VRloTN2+O5bj4x2AogZ8f02b+U60cEPgLO
+KqJdhwQJ9jCdGIqXsqoc/EHSoTbL+z2RuufZcDX65OeQw5ujm9M89RKZd7G3CeBo
+5hy485RjiGpq/gt2yb70IuRnuasaXnfBhQfdDWy/7gbHd2pBnqcP1/vulBe3/IW+
+pKvEHDHd17bR5PDv3xaPslKT16HUiaEHLr/hARJCHhrh2JU022R5KP+6LhHC5ehb
+kkj7RwvCbNqtMoNB86XlQXD9ZZBt+vpRxPm9lisZBCzTbafc8H9vg2XiaquHhnUC
+AwEAAaOBrzCBrDALBgNVHQ8EBAMCAcYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E
+FgQU2u1kdBScFDyr3ZmpvVsoTYs8ydgwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDov
+L2NybC51c2VydHJ1c3QuY29tL1VUTi1VU0VSRmlyc3QtT2JqZWN0LmNybDApBgNV
+HSUEIjAgBggrBgEFBQcDAwYIKwYBBQUHAwgGCisGAQQBgjcKAwQwDQYJKoZIhvcN
+AQEFBQADggEBAAgfUrE3RHjb/c652pWWmKpVZIC1WkDdIaXFwfNfLEzIR1pp6ujw
+NTX00CXzyKakh0q9G7FzCL3Uw8q2NbtZhncxzaeAFK4T7/yxSPlrJSUtUbYsbUXB
+mMiKVl0+7kNOPmsnjtA6S4ULX9Ptaqd1y9Fahy85dRNacrACgZ++8A+EVCBibGnU
+4U3GDZlDAQ0Slox4nb9QorFEqmrPF3rPbw/U+CRVX/A0FklmPlBGyWNxODFiuGK5
+81OtbLUrohKqGU8J2l7nk8aOFAj+8DCAGKCGhU3IfdeLA/5u1fedFqySLKAj5ZyR
+Uh+U3xeUc8OzwcFxBSAAeL0TUh2oPs0AH8g=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDjjCCAnagAwIBAgIIKv++n6Lw6YcwDQYJKoZIhvcNAQEFBQAwKDELMAkGA1UE
+BhMCQkUxGTAXBgNVBAMTEEJlbGdpdW0gUm9vdCBDQTIwHhcNMDcxMDA0MTAwMDAw
+WhcNMjExMjE1MDgwMDAwWjAoMQswCQYDVQQGEwJCRTEZMBcGA1UEAxMQQmVsZ2l1
+bSBSb290IENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMZzQh6S
+/3UPi790hqc/7bIYLS2X+an7mEoj39WN4IzGMhwWLQdC1i22bi+n9fzGhYJdld61
+IgDMqFNAn68KNaJ6x+HK92AQZw6nUHMXU5WfIp8MXW+2QbyM69odRr2nlL/zGsvU
++40OHjPIltfsjFPekx40HopQcSZYtF3CiInaYNKJIT/e1wEYNm7hLHADBGXvmAYr
+XR5i3FVr/mZkIV/4L+HXmymvb82fqgxG0YjFnaKVn6w/Fa7yYd/vw2uaItgscf1Y
+HewApDgglVrH1Tdjuk+bqv5WRi5j2Qsj1Yr6tSPwiRuhFA0m2kHwOI8w7QUmecFL
+TqG4flVSOmlGhHUCAwEAAaOBuzCBuDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/
+BAUwAwEB/zBCBgNVHSAEOzA5MDcGBWA4CQEBMC4wLAYIKwYBBQUHAgEWIGh0dHA6
+Ly9yZXBvc2l0b3J5LmVpZC5iZWxnaXVtLmJlMB0GA1UdDgQWBBSFiuv0xbu+DlkD
+lN7WgAEV4xCcOTARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUhYrr9MW7
+vg5ZA5Te1oABFeMQnDkwDQYJKoZIhvcNAQEFBQADggEBAFHYhd27V2/MoGy1oyCc
+UwnzSgEMdL8rs5qauhjyC4isHLMzr87lEwEnkoRYmhC598wUkmt0FoqW6FHvv/pK
+JaeJtmMrXZRY0c8RcrYeuTlBFk0pvDVTC9rejg7NqZV3JcqUWumyaa7YwBO+mPyW
+nIR/VRPmPIfjvCCkpDZoa01gZhz5v6yAlGYuuUGK02XThIAC71AdXkbc98m6tTR8
+KvPG2F9fVJ3bTc0R5/0UAoNmXsimABKgX77OFP67H6dh96tK8QYUn8pJQsKpvO2F
+sauBQeYNxUJpU4c5nUwfAA4+Bw11V0SoU7Q2dmSZ3G7rPUZuFF1eR1ONeE3gJ7uO
+hXY=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFyjCCA7KgAwIBAgIEAJiWjDANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJO
+TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFh
+dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQSAtIEcyMB4XDTA4MDMyNjExMTgxN1oX
+DTIwMDMyNTExMDMxMFowWjELMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRl
+ciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5lZGVybGFuZGVuIFJv
+b3QgQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMVZ5291
+qj5LnLW4rJ4L5PnZyqtdj7U5EILXr1HgO+EASGrP2uEGQxGZqhQlEq0i6ABtQ8Sp
+uOUfiUtnvWFI7/3S4GCI5bkYYCjDdyutsDeqN95kWSpGV+RLufg3fNU254DBtvPU
+Z5uW6M7XxgpT0GtJlvOjCwV3SPcl5XCsMBQgJeN/dVrlSPhOewMHBPqCYYdu8DvE
+pMfQ9XQ+pV0aCPKbJdL2rAQmPlU6Yiile7Iwr/g3wtG61jj99O9JMDeZJiFIhQGp
+5Rbn3JBV3w/oOM2ZNyFPXfUib2rFEhZgF1XyZWampzCROME4HYYEhLoaJXhena/M
+UGDWE4dS7WMfbWV9whUYdMrhfmQpjHLYFhN9C0lK8SgbIHRrxT3dsKpICT0ugpTN
+GmXZK4iambwYfp/ufWZ8Pr2UuIHOzZgweMFvZ9C+X+Bo7d7iscksWXiSqt8rYGPy
+5V6548r6f1CGPqI0GAwJaCgRHOThuVw+R7oyPxjMW4T182t0xHJ04eOLoEq9jWYv
+6q012iDTiIJh8BIitrzQ1aTsr1SIJSQ8p22xcik/Plemf1WvbibG/ufMQFxRRIEK
+eN5KzlW/HdXZt1bv8Hb/C3m1r737qWmRRpdogBQ2HbN/uymYNqUg+oJgYjOk7Na6
+B6duxc8UpufWkjTYgfX8HV2qXB72o007uPc5AgMBAAGjgZcwgZQwDwYDVR0TAQH/
+BAUwAwEB/zBSBgNVHSAESzBJMEcGBFUdIAAwPzA9BggrBgEFBQcCARYxaHR0cDov
+L3d3dy5wa2lvdmVyaGVpZC5ubC9wb2xpY2llcy9yb290LXBvbGljeS1HMjAOBgNV
+HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJFoMocVHYnitfGsNig0jQt8YojrMA0GCSqG
+SIb3DQEBCwUAA4ICAQCoQUpnKpKBglBu4dfYszk78wIVCVBR7y29JHuIhjv5tLyS
+CZa59sCrI2AGeYwRTlHSeYAz+51IvuxBQ4EffkdAHOV6CMqqi3WtFMTC6GY8ggen
+5ieCWxjmD27ZUD6KQhgpxrRW/FYQoAUXvQwjf/ST7ZwaUb7dRUG/kSS0H4zpX897
+IZmflZ85OkYcbPnNe5yQzSipx6lVu6xiNGI1E0sUOlWDuYaNkqbG9AclVMwWVxJK
+gnjIFNkXgiYtXSAfea7+1HAWFpWD2DU5/1JddRwWxRNVz0fMdWVSSt7wsKfkCpYL
++63C4iWEst3kvX5ZbJvw8NjnyvLplzh+ib7M+zkXYT9y2zqR2GUBGR2tUKRXCnxL
+vJxxcypFURmFzI79R6d0lR2o0a9OF7FpJsKqeFdbxU2n5Z4FF5TKsl+gSRiNNOkm
+bEgeqmiSBeGCc1qb3AdbCG19ndeNIdn8FCCqwkXfP+cAslHkwvgFuXkajDTznlvk
+N1trSt8sV4pAWja63XVECDdCcAz+3F4hoKOKwJCcaNpQ5kUQR3i2TtJlycM33+FC
+Y7BXN0Ute4qcvwXqZVUz9zkQxSgqIXobisQk+T8VyJoVIPVVYpbtbZNQvOSqeK3Z
+ywplh6ZmwcSBo3c6WB4L7oOLnR7SUqTMHW+wmG2UMbX4cQrcufx9MmDm66+KAQ==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEk
+MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpH
+bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX
+DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD
+QSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu
+MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6SFkc
+8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8ke
+hOvRnkmSh5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD
+VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYI
+KoZIzj0EAwMDaAAwZQIxAOVpEslu28YxuglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg
+515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7yFz9SO8NdCKoCOJuxUnO
+xwy8p2Fp8fc74SrL+SvzZpA3
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYD
+VQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0
+IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3
+MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD
+aGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMxNDBaFw0zODA3MzEx
+MjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3Vy
+cmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAG
+A1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAl
+BgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZI
+hvcNAQEBBQADggIPADCCAgoCggIBAMDfVtPkOpt2RbQT2//BthmLN0EYlVJH6xed
+KYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXfXjaOcNFccUMd2drvXNL7
+G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0ZJJ0YPP2
+zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4
+ddPB/gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyG
+HoiMvvKRhI9lNNgATH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2
+Id3UwD2ln58fQ1DJu7xsepeY7s2MH/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3V
+yJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfeOx2YItaswTXbo6Al/3K1dh3e
+beksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSFHTynyQbehP9r
+6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh
+wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsog
+zCtLkykPAgMBAAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQW
+BBS5CcqcHtvTbDprru1U8VuTBjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDpr
+ru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UEBhMCRVUxQzBBBgNVBAcTOk1hZHJp
+ZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJmaXJtYS5jb20vYWRk
+cmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJmaXJt
+YSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiC
+CQDJzdPp1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCow
+KAYIKwYBBQUHAgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZI
+hvcNAQEFBQADggIBAICIf3DekijZBZRG/5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZ
+UohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6ReAJ3spED8IXDneRRXoz
+X1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/sdZ7LoR/x
+fxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVz
+a2Mg9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yyd
+Yhz2rXzdpjEetrHHfoUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMd
+SqlapskD7+3056huirRXhOukP9DuqqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9O
+AP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETrP3iZ8ntxPjzxmKfFGBI/5rso
+M0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVqc5iJWzouE4ge
+v8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z
+09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIF3zCCA8egAwIBAgIOGTMAAQACKBqaBLzyVUUwDQYJKoZIhvcNAQEFBQAwejEL
+MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNV
+BAsTG1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQTEnMCUGA1UEAxMeVEMgVHJ1
+c3RDZW50ZXIgVW5pdmVyc2FsIENBIElJMB4XDTA2MDMyMjE1NTgzNFoXDTMwMTIz
+MTIyNTk1OVowejELMAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVy
+IEdtYkgxJDAiBgNVBAsTG1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQTEnMCUG
+A1UEAxMeVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBIElJMIICIjANBgkqhkiG
+9w0BAQEFAAOCAg8AMIICCgKCAgEAi9R3azRs5TbYalxeOO781R15Azt7g2JEgk6I
+7d6D/+7MUGIFBZWZdpj2ufJf2AaRksL2LWYXH/1TA+iojWOpbuHWG4y8mLOLO9Tk
+Lsp9hUkmW3m4GotAnn+7yT9jLM/RWny6KCJBElpN+Rd3/IX9wkngKhh/6aAsnPlE
+/AxoOUL1JwW+jhV6YJ3wO8c85j4WvK923mq3ouGrRkXrjGV90ZfzlxElq1nroCLZ
+gt2Y7X7i+qBhCkoy3iwX921E6oFHWZdXNwM53V6CItQzuPomCba8OYgvURVOm8M7
+3xOCiN1LNPIz1pDp81PcNXzAw9l8eLPNcD+NauCjgUjkKa1juPD8KGQ7mbN9/pqd
+iPaZIgiRRxaJNXhdd6HPv0nh/SSUK2k2e+gc5iqQilvVOzRZQtxtz7sPQRxVzfUN
+Wy4WIibvYR6X/OJTyM9bo8ep8boOhhLLE8oVx+zkNo3aXBM9ZdIOXXB03L+PemrB
+Lg/Txl4PK1lszGFs/sBhTtnmT0ayWuIZFHCE+CAA7QGnl37DvRJckiMXoKUdRRcV
+I5qSCLUiiI3cKyTr4LEXaNOvYb3ZhXj2jbp4yjeNY77nrB/fpUcJucglMVRGURFV
+DYlcjdrSGC1z8rjVJ/VIIjfRYvd7Dcg4i6FKsPzQ8eu3hmPn4A5zf/1yUbXpfeJV
+BWR4Z38CAwEAAaNjMGEwHwYDVR0jBBgwFoAUzdeQoW6jv9sw1toyJZAM5jkegGUw
+DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFM3XkKFu
+o7/bMNbaMiWQDOY5HoBlMA0GCSqGSIb3DQEBBQUAA4ICAQB+FojoEw42zG4qhQc4
+xlaJeuNHIWZMUAgxWlHQ/KZeFHXeTDvs8e3MfhEHSmHu6rOOOqQzxu2KQmZP8Tx7
+yaUFQZmx7Cxb7tyW0ohTS3g0uW7muw/FeqZ8Dhjfbw90TNGp8aHp2FRkzF6WeKJW
+GsFzshXGVwXf2vdIJIqOf2qp+U3pPmrOYCx9LZAI9mOPFdAtnIz/8f38DBZQVhT7
+upeG7rRJA1TuG1l/MDoCgoYhrv7wFfLfToPmmcW6NfcgkIw47XXP4S73BDD7Ua2O
+giRAyn0pXdXZ92Vk/KqfdLh9kl3ShCngE+qK99CrxK7vFcXCifJ7tjtJmGHzTnKR
+N4xJkunI7Cqg90lufA0kxmts8jgvynAF5X/fxisrgIDV2m/LQLvYG/AkyRDIRAJ+
+LtOYqqIN8SvQ2vqOHP9U6OFKbt2o1ni1N6WsZNUUI8cOpevhCTjXwHxgpV2Yj4wC
+1dxWqPNNWKkL1HxkdAEy8t8PSoqpAqKiHYR3wvHMl700GXRd4nQ+dSf3r7/ufA5t
+VIimVuImrTESPB5BeW0X6hNeH/Vcn0lZo7Ivo0LD+qh+v6WfSMlgYmIK371F3uNC
+tVGW/cT1Gpm4UqJEzS1hjBWPgdVdotSQPYxuQGHDWV3Y2eH2dEcieXR92sqjbzcV
+NvAsGnE8EXbfXRo+VGN4a2V+Hw==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIF2TCCA8GgAwIBAgIQXAuFXAvnWUHfV8w/f52oNjANBgkqhkiG9w0BAQUFADBk
+MQswCQYDVQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0
+YWwgQ2VydGlmaWNhdGUgU2VydmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3Qg
+Q0EgMTAeFw0wNTA4MTgxMjA2MjBaFw0yNTA4MTgyMjA2MjBaMGQxCzAJBgNVBAYT
+AmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGlnaXRhbCBDZXJ0aWZp
+Y2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAxMIICIjAN
+BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0LmwqAzZuz8h+BvVM5OAFmUgdbI9
+m2BtRsiMMW8Xw/qabFbtPMWRV8PNq5ZJkCoZSx6jbVfd8StiKHVFXqrWW/oLJdih
+FvkcxC7mlSpnzNApbjyFNDhhSbEAn9Y6cV9Nbc5fuankiX9qUvrKm/LcqfmdmUc/
+TilftKaNXXsLmREDA/7n29uj/x2lzZAeAR81sH8A25Bvxn570e56eqeqDFdvpG3F
+EzuwpdntMhy0XmeLVNxzh+XTF3xmUHJd1BpYwdnP2IkCb6dJtDZd0KTeByy2dbco
+kdaXvij1mB7qWybJvbCXc9qukSbraMH5ORXWZ0sKbU/Lz7DkQnGMU3nn7uHbHaBu
+HYwadzVcFh4rUx80i9Fs/PJnB3r1re3WmquhsUvhzDdf/X/NTa64H5xD+SpYVUNF
+vJbNcA78yeNmuk6NO4HLFWR7uZToXTNShXEuT46iBhFRyePLoW4xCGQMwtI89Tbo
+19AOeCMgkckkKmUpWyL3Ic6DXqTz3kvTaI9GdVyDCW4pa8RwjPWd1yAv/0bSKzjC
+L3UcPX7ape8eYIVpQtPM+GP+HkM5haa2Y0EQs3MevNP6yn0WR+Kn1dCjigoIlmJW
+bjTb2QK5MHXjBNLnj8KwEUAKrNVxAmKLMb7dxiNYMUJDLXT5xp6mig/p/r+D5kNX
+JLrvRjSq1xIBOO0CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0hBBYw
+FDASBgdghXQBUwABBgdghXQBUwABMBIGA1UdEwEB/wQIMAYBAf8CAQcwHwYDVR0j
+BBgwFoAUAyUv3m+CATpcLNwroWm1Z9SM0/0wHQYDVR0OBBYEFAMlL95vggE6XCzc
+K6FptWfUjNP9MA0GCSqGSIb3DQEBBQUAA4ICAQA1EMvspgQNDQ/NwNurqPKIlwzf
+ky9NfEBWMXrrpA9gzXrzvsMnjgM+pN0S734edAY8PzHyHHuRMSG08NBsl9Tpl7Ik
+Vh5WwzW9iAUPWxAaZOHHgjD5Mq2eUCzneAXQMbFamIp1TpBcahQq4FJHgmDmHtqB
+sfsUC1rxn9KVuj7QG9YVHaO+htXbD8BJZLsuUBlL0iT43R4HVtA4oJVwIHaM190e
+3p9xxCPvgxNcoyQVTSlAPGrEqdi3pkSlDfTgnXceQHAm/NrZNuR55LU/vJtlvrsR
+ls/bxig5OgjOR1tTWsWZ/l2p3e9M1MalrQLmjAcSHm8D0W+go/MpvRLHUKKwf4ip
+mXeascClOS5cfGniLLDqN2qk4Vrh9VDlg++luyqI54zb/W1elxmofmZ1a3Hqv7HH
+b6D0jqTsNFFbjCYDcKF31QESVwA12yPeDooomf2xEG9L/zgtYE4snOtnta1J7ksf
+rK/7DZBaZmBwXarNeNQk7shBoJMBkpxqnvy5JMWzFYJ+vq6VK+uxwNrjAWALXmms
+hFZhvnEX/h0TD/7Gh0Xp/jKgGg0TpJRVcaUWi7rKibCyx/yP2FS1k2Kdzs9Z+z0Y
+zirLNRWCXf9UIltxUvu3yf5gmwBBZPCqKuy2QkPOiWaByIufOVQDJdMWNY6E0F/6
+MBr1mmz0DlP5OlvRHA==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCB
+kzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
+Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
+dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xGzAZBgNVBAMTElVUTiAtIERBVEFDb3Jw
+IFNHQzAeFw05OTA2MjQxODU3MjFaFw0xOTA2MjQxOTA2MzBaMIGTMQswCQYDVQQG
+EwJVUzELMAkGA1UECBMCVVQxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYD
+VQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxITAfBgNVBAsTGGh0dHA6Ly93d3cu
+dXNlcnRydXN0LmNvbTEbMBkGA1UEAxMSVVROIC0gREFUQUNvcnAgU0dDMIIBIjAN
+BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3+5YEKIrblXEjr8uRgnn4AgPLit6
+E5Qbvfa2gI5lBZMAHryv4g+OGQ0SR+ysraP6LnD43m77VkIVni5c7yPeIbkFdicZ
+D0/Ww5y0vpQZY/KmEQrrU0icvvIpOxboGqBMpsn0GFlowHDyUwDAXlCCpVZvNvlK
+4ESGoE1O1kduSUrLZ9emxAW5jh70/P/N5zbgnAVssjMiFdC04MwXwLLA9P4yPykq
+lXvY8qdOD1R8oQ2AswkDwf9c3V6aPryuvEeKaq5xyh+xKrhfQgUL7EYw0XILyulW
+bfXv33i+Ybqypa4ETLyorGkVl73v67SMvzX41MPRKA5cOp9wGDMgd8SirwIDAQAB
+o4GrMIGoMAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRT
+MtGzz3/64PGgXYVOktKeRR20TzA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3Js
+LnVzZXJ0cnVzdC5jb20vVVROLURBVEFDb3JwU0dDLmNybDAqBgNVHSUEIzAhBggr
+BgEFBQcDAQYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMA0GCSqGSIb3DQEBBQUAA4IB
+AQAnNZcAiosovcYzMB4p/OL31ZjUQLtgyr+rFywJNn9Q+kHcrpY6CiM+iVnJowft
+Gzet/Hy+UUla3joKVAgWRcKZsYfNjGjgaQPpxE6YsjuMFrMOoAyYUJuTqXAJyCyj
+j98C5OBxOvG0I3KgqgHf35g+FFCgMSa9KOlaMCZ1+XtgHI3zzVAmbQQnmt/VDUVH
+KWss5nbZqSl9Mt3JNjy9rjXxEZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv
+2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwPDPafepE39peC4N1xaf92P2BNPM/3
+mfnGV/TJVTl4uix5yaaIK/QI
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEBDCCAuygAwIBAgIIGHqpqMKWIQwwDQYJKoZIhvcNAQELBQAwYjELMAkGA1UE
+BhMCVVMxEzARBgNVBAoTCkFwcGxlIEluYy4xJjAkBgNVBAsTHUFwcGxlIENlcnRp
+ZmljYXRpb24gQXV0aG9yaXR5MRYwFAYDVQQDEw1BcHBsZSBSb290IENBMB4XDTEy
+MDIwMTIyMTIxNVoXDTI3MDIwMTIyMTIxNVoweTEtMCsGA1UEAwwkRGV2ZWxvcGVy
+IElEIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSYwJAYDVQQLDB1BcHBsZSBDZXJ0
+aWZpY2F0aW9uIEF1dGhvcml0eTETMBEGA1UECgwKQXBwbGUgSW5jLjELMAkGA1UE
+BhMCVVMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCJdk8GW5pB7qUj
+KwKjX9dzP8A1sIuECj8GJH+nlT/rTw6Tr7QO0Mg+5W0Ysx/oiUe/1wkI5P9WmCkV
+55SduTWjCs20wOHiYPTK7Cl4RWlpYGtfipL8niPmOsIiszFPHLrytjRZQu6wqQID
+GJEEtrN4LjMfgEUNRW+7Dlpbfzrn2AjXCw4ybfuGNuRsq8QRinCEJqqfRNHxuMZ7
+lBebSPcLWBa6I8WfFTl+yl3DMl8P4FJ/QOq+rAhklVvJGpzlgMofakQcbD7EsCYf
+Hex7r16gaj1HqVgSMT8gdihtHRywwk4RaSaLy9bQEYLJTg/xVnTQ2QhLZniiq6yn
+4tJMh1nJAgMBAAGjgaYwgaMwHQYDVR0OBBYEFFcX7aLP3HyYoRDg/L6HLSzy4xdU
+MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUK9BpR5R2Cf70a40uQKb3R01/
+CF4wLgYDVR0fBCcwJTAjoCGgH4YdaHR0cDovL2NybC5hcHBsZS5jb20vcm9vdC5j
+cmwwDgYDVR0PAQH/BAQDAgGGMBAGCiqGSIb3Y2QGAgYEAgUAMA0GCSqGSIb3DQEB
+CwUAA4IBAQBCOXRrodzGpI83KoyzHQpEvJUsf7xZuKxh+weQkjK51L87wVA5akR0
+ouxbH3Dlqt1LbBwjcS1f0cWTvu6binBlgp0W4xoQF4ktqM39DHhYSQwofzPuAHob
+tHastrW7T9+oG53IGZdKC1ZnL8I+trPEgzrwd210xC4jUe6apQNvYPSlSKcGwrta
+4h8fRkV+5Jf1JxC3ICJyb3LaxlB1xT0lj12jAOmfNoxIOY+zO+qQgC6VmmD0eM70
+DgpTPqL6T9geroSVjTK8Vk2J6XgY4KyaQrp6RhuEoonOFOiI0ViL9q5WxCwFKkWv
+C9lLqQIPNKyIx2FViUTJJ3MH7oLlTvVw
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEvTCCA6WgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBhTELMAkGA1UEBhMCVVMx
+IDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxs
+cyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9v
+dCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcNMDcxMjEzMTcwNzU0WhcNMjIxMjE0
+MDAwNzU0WjCBhTELMAkGA1UEBhMCVVMxIDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdl
+bGxzU2VjdXJlMRwwGgYDVQQLDBNXZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQD
+DC1XZWxsc1NlY3VyZSBQdWJsaWMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkw
+ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDub7S9eeKPCCGeOARBJe+r
+WxxTkqxtnt3CxC5FlAM1iGd0V+PfjLindo8796jE2yljDpFoNoqXjopxaAkH5OjU
+Dk/41itMpBb570OYj7OeUt9tkTmPOL13i0Nj67eT/DBMHAGTthP796EfvyXhdDcs
+HqRePGj4S78NuR4uNuip5Kf4D8uCdXw1LSLWwr8L87T8bJVhHlfXBIEyg1J55oNj
+z7fLY4sR4r1e6/aN7ZVyKLSsEmLpSjPmgzKuBXWVvYSV2ypcm44uDLiBK0HmOFaf
+SZtsdvqKXfcBeYF8wYNABf5x/Qw/zE5gCQ5lRxAvAcAFP4/4s0HvWkJ+We/Slwxl
+AgMBAAGjggE0MIIBMDAPBgNVHRMBAf8EBTADAQH/MDkGA1UdHwQyMDAwLqAsoCqG
+KGh0dHA6Ly9jcmwucGtpLndlbGxzZmFyZ28uY29tL3dzcHJjYS5jcmwwDgYDVR0P
+AQH/BAQDAgHGMB0GA1UdDgQWBBQmlRkQ2eihl5H/3BnZtQQ+0nMKajCBsgYDVR0j
+BIGqMIGngBQmlRkQ2eihl5H/3BnZtQQ+0nMKaqGBi6SBiDCBhTELMAkGA1UEBhMC
+VVMxIDAeBgNVBAoMF1dlbGxzIEZhcmdvIFdlbGxzU2VjdXJlMRwwGgYDVQQLDBNX
+ZWxscyBGYXJnbyBCYW5rIE5BMTYwNAYDVQQDDC1XZWxsc1NlY3VyZSBQdWJsaWMg
+Um9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHmCAQEwDQYJKoZIhvcNAQEFBQADggEB
+ALkVsUSRzCPIK0134/iaeycNzXK7mQDKfGYZUMbVmO2rvwNa5U3lHshPcZeG1eMd
+/ZDJPHV3V3p9+N701NX3leZ0bh08rnyd2wIDBSxxSyU+B+NemvVmFymIGjifz6pB
+A4SXa5M4esowRBskRDPQ5NHcKDj0E0M1NSljqHyita04pO2t/caaH/+Xc/77szWn
+k4bGdpEA5qxRFsQnMlzbc9qlk1eOPm01JghZ1edE13YgY+esE2fDbbFwRnzVlhE9
+iW9dqKHrjQrawx0zbKPqZxmamX9LPYNRKh3KL4YMon4QLSvUFpULB6ouFJJJtylv
+2G0xffX8oRAHh84vWdw+WNs=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICqDCCAi2gAwIBAgIQIW4zpcvTiKRvKQe0JzzE2DAKBggqhkjOPQQDAzCBlDEL
+MAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYD
+VQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBD
+bGFzcyAxIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0g
+RzQwHhcNMTExMDA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBlDELMAkGA1UEBhMC
+VVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZTeW1h
+bnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBDbGFzcyAxIFB1
+YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcq
+hkjOPQIBBgUrgQQAIgNiAATXZrUb266zYO5G6ohjdTsqlG3zXxL24w+etgoUU0hS
+yNw6s8tIICYSTvqJhNTfkeQpfSgB2dsYQ2mhH7XThhbcx39nI9/fMTGDAzVwsUu3
+yBe7UcvclBfb6gk7dhLeqrWjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E
+BTADAQH/MB0GA1UdDgQWBBRlwI0l9Qy6l3eQP54u4Fr1ztXh5DAKBggqhkjOPQQD
+AwNpADBmAjEApa7jRlP4mDbjIvouKEkN7jB+M/PsP3FezFWJeJmssv3cHFwzjim5
+axfIEWi13IMHAjEAnMhE2mnCNsNUGRCFAtqdR+9B52wmnQk9922Q0QVEL7C8g5No
+8gxFSTm/mQQc0xCg
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIID3TCCAsWgAwIBAgIOHaIAAQAC7LdggHiNtgYwDQYJKoZIhvcNAQEFBQAweTEL
+MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNV
+BAsTG1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQTEmMCQGA1UEAxMdVEMgVHJ1
+c3RDZW50ZXIgVW5pdmVyc2FsIENBIEkwHhcNMDYwMzIyMTU1NDI4WhcNMjUxMjMx
+MjI1OTU5WjB5MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIg
+R21iSDEkMCIGA1UECxMbVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBMSYwJAYD
+VQQDEx1UQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0EgSTCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBAKR3I5ZEr5D0MacQ9CaHnPM42Q9e3s9B6DGtxnSR
+JJZ4Hgmgm5qVSkr1YnwCqMqs+1oEdjneX/H5s7/zA1hV0qq34wQi0fiU2iIIAI3T
+fCZdzHd55yx4Oagmcw6iXSVphU9VDprvxrlE4Vc93x9UIuVvZaozhDrzznq+VZeu
+jRIPFDPiUHDDSYcTvFHe15gSWu86gzOSBnWLknwSaHtwag+1m7Z3W0hZneTvWq3z
+wZ7U10VOylY0Ibw+F1tvdwxIAUMpsN0/lm7mlaoMwCC2/T42J5zjXM9OgdwZu5GQ
+fezmlwQek8wiSdeXhrYTCjxDI3d+8NzmzSQfO4ObNDqDNOMCAwEAAaNjMGEwHwYD
+VR0jBBgwFoAUkqR1LKSevoFE63n8isWVpesQdXMwDwYDVR0TAQH/BAUwAwEB/zAO
+BgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFJKkdSyknr6BROt5/IrFlaXrEHVzMA0G
+CSqGSIb3DQEBBQUAA4IBAQAo0uCG1eb4e/CX3CJrO5UUVg8RMKWaTzqwOuAGy2X1
+7caXJ/4l8lfmXpWMPmRgFVp/Lw0BxbFg/UU1z/CyvwbZ71q+s2IhtNerNXxTPqYn
+8aEt2hojnczd7Dwtnic0XQ/CNnm8yUpiLe1r2X1BQ3y2qsrtYbE3ghUJGooWMNjs
+ydZHcnhLEEYUjl8Or+zHL6sQ17bxbuyGssLoDZJz3KL0Dzq/YSMQiZxIQG5wALPT
+ujdEWBF6AmqI8Dc08BnprNRlc/ZpjGSUOnmFKbAWKwyCPwacx/0QK54PLLae4xW/
+2TYcuiUaUj0a7CIMHOCkoj3w6DnPgcB77V0fb8XQC9eY
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDtjCCAp6gAwIBAgIOBcAAAQACQdAGCk3OdRAwDQYJKoZIhvcNAQEFBQAwdjEL
+MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNV
+BAsTGVRDIFRydXN0Q2VudGVyIENsYXNzIDQgQ0ExJTAjBgNVBAMTHFRDIFRydXN0
+Q2VudGVyIENsYXNzIDQgQ0EgSUkwHhcNMDYwMzIzMTQxMDIzWhcNMjUxMjMxMjI1
+OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIgR21i
+SDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgNCBDQTElMCMGA1UEAxMc
+VEMgVHJ1c3RDZW50ZXIgQ2xhc3MgNCBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBALXNTJytrlG7fEjFDSmGehSt2VA9CXIgDRS2Y8b+WJ7gIV7z
+jyIZ3E6RIM1viCmis8GsKnK6i1S4QF/yqvhDhsIwXMynXX/GCEnkDjkvjhjWkd0j
+FnmA22xIHbzB3ygQY9GB493fL3l1oht48pQB5hBiecugfQLANIJ7x8CtHUzXapZ2
+W78mhEj9h/aECqqSB5lIPGG8ToVYx5ct/YFKocabEvVCUNFkPologiJw3fX64yhC
+L04y87OjNopq1mJcrPoBbbTgci6VaLTxkwzGioLSHVPqfOA/QrcSWrjN2qUGZ8uh
+d32llvCSHmcOHUJG5vnt+0dTf1cERh9GX8eu4I8CAwEAAaNCMEAwDwYDVR0TAQH/
+BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFB/quz4lGwa9pd1iBX7G
+TFq/6A9DMA0GCSqGSIb3DQEBBQUAA4IBAQBYpCubTPfkpJKknGWYGWIi/HIy6QRd
+xMRwLVpG3kxHiiW5ot3u6hKvSI3vK2fbO8w0mCr3CEf/Iq978fTr4jgCMxh1KBue
+dmWsiANy8jhHHYz1nwqIUxAUu4DlDLNdjRfuHhkcho0UZ3iMksseIUn3f9MYv5x5
++F0IebWqak2SNmy8eesOPXmK2PajVnBd3ttPedJ60pVchidlvqDTB4FAVd0Qy+BL
+iILAkH0457+W4Ze6mqtCD9Of2J4VMxHL94J59bXAQVaS4d9VA61Iz9PyLrHHLVZM
+ZHQqMc7cdalUR6SnQnIJ5+ECpkeyBM1CE+FhDOB4OiIgohxgQoaH96Xm
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEU
+MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3
+b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwHhcNMDAwNTMw
+MTAzODMxWhcNMjAwNTMwMTAzODMxWjBlMQswCQYDVQQGEwJTRTEUMBIGA1UEChML
+QWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYD
+VQQDExhBZGRUcnVzdCBDbGFzcyAxIENBIFJvb3QwggEiMA0GCSqGSIb3DQEBAQUA
+A4IBDwAwggEKAoIBAQCWltQhSWDia+hBBwzexODcEyPNwTXH+9ZOEQpnXvUGW2ul
+CDtbKRY654eyNAbFvAWlA3yCyykQruGIgb3WntP+LVbBFc7jJp0VLhD7Bo8wBN6n
+tGO0/7Gcrjyvd7ZWxbWroulpOj0OM3kyP3CCkplhbY0wCI9xP6ZIVxn4JdxLZlyl
+dI+Yrsj5wAYi56xz36Uu+1LcsRVlIPo1Zmne3yzxbrww2ywkEtvrNTVokMsAsJch
+PXQhI2U0K7t4WaPW4XY5mqRJjox0r26kmqPZm9I4XJuiGMx1I4S+6+JNM3GOGvDC
++Mcdoq0Dlyz4zyXG9rgkMbFjXZJ/Y/AlyVMuH79NAgMBAAGjgdIwgc8wHQYDVR0O
+BBYEFJWxtPCUtr3H2tERCSG+wa9J/RB7MAsGA1UdDwQEAwIBBjAPBgNVHRMBAf8E
+BTADAQH/MIGPBgNVHSMEgYcwgYSAFJWxtPCUtr3H2tERCSG+wa9J/RB7oWmkZzBl
+MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFk
+ZFRydXN0IFRUUCBOZXR3b3JrMSEwHwYDVQQDExhBZGRUcnVzdCBDbGFzcyAxIENB
+IFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBACxtZBsfzQ3duQH6lmM0MkhHma6X
+7f1yFqZzR1r0693p9db7RcwpiURdv0Y5PejuvE1Uhh4dbOMXJ0PhiVYrqW9yTkkz
+43J8KiOavD7/KCrto/8cI7pDVwlnTUtiBi34/2ydYB7YHEt9tTEv2dB8Xfjea4MY
+eDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL/bscVjby/rK25Xa71SJl
+pz/+0WatC7xrmYbvP33zGDLKe8bjq2RGlfgmadlVg3sslgf/WSxEo8bl6ancoWOA
+WiFeIc9TVPC6b4nbqKqVz4vjccweGyBECMB6tkD9xOQ14R0WHNC8K47Wcdk=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDpDCCAoygAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEc
+MBoGA1UEChMTQW1lcmljYSBPbmxpbmUgSW5jLjE2MDQGA1UEAxMtQW1lcmljYSBP
+bmxpbmUgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAxMB4XDTAyMDUyODA2
+MDAwMFoXDTM3MTExOTIwNDMwMFowYzELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0Ft
+ZXJpY2EgT25saW5lIEluYy4xNjA0BgNVBAMTLUFtZXJpY2EgT25saW5lIFJvb3Qg
+Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgMTCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBAKgv6KRpBgNHw+kqmP8ZonCaxlCyfqXfaE0bfA+2l2h9LaaLl+lk
+hsmj76CGv2BlnEtUiMJIxUo5vxTjWVXlGbR0yLQFOVwWpeKVBeASrlmLojNoWBym
+1BW32J/X3HGrfpq/m44zDyL9Hy7nBzbvYjnF3cu6JRQj3gzGPTzOggjmZj7aUTsW
+OqMFf6Dch9Wc/HKpoH145LcxVR5lu9RhsCFg7RAycsWSJR74kEoYeEfffjA3PlAb
+2xzTa5qGUwew76wGePiEmf4hjUyAtgyC9mZweRrTT6PP8c9GsEsPPt2IYriMqQko
+O3rHl+Ee5fSfwMCuJKDIodkP1nsmgmkyPacCAwEAAaNjMGEwDwYDVR0TAQH/BAUw
+AwEB/zAdBgNVHQ4EFgQUAK3Zo/Z59m50qX8zPYEX10zPM94wHwYDVR0jBBgwFoAU
+AK3Zo/Z59m50qX8zPYEX10zPM94wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB
+BQUAA4IBAQB8itEfGDeC4Liwo+1WlchiYZwFos3CYiZhzRAW18y0ZTTQEYqtqKkF
+Zu90821fnZmv9ov761KyBZiibyrFVL0lvV+uyIbqRizBs73B6UlwGBaXCBOMIOAb
+LjpHyx7kADCVW/RFo8AasAFOq73AI25jP4BKxQft3OJvx8Fi8eNy1gTIdGcL+oir
+oQHIb/AUr9KZzVGTfu0uOMe9zkZQPXLjeSWdm4grECDdpbgyn43gKd8hdIaC2y+C
+MMbHNYaz+ZZfRtsMRf3zUMNvxsNIrUam4SdHCh0Om7bCd39j8uB9Gr784N/Xx6ds
+sPmuujz9dLQR6FgNgLzTqIA6me11zEZ7
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBi
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3Qg
+RzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBiMQswCQYDVQQGEwJV
+UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu
+Y29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0GCSqG
+SIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3y
+ithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1If
+xp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDV
+ySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfISKhmV1efVFiO
+DCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jHtrHEtWoYOAMQ
+jdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSaM0C/
+CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCi
+EhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADM
+fRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QY
+uKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXK
+chYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4KJpn15GkvmB0t
+9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB
+hjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD
+ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2
+SV1EY+CtnJYYZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd
++SeuMIW59mdNOj6PWTkiU0TryF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWc
+fFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy7zBZLq7gcfJW5GqXb5JQbZaNaHqa
+sjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iahixTXTBmyUEFxPT9N
+cCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN5r5N
+0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie
+4u1Ki7wb/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mI
+r/OSmbaz5mEP0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1
+/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tKG48BtieVU+i2iW1bvGjUI+iLUaJW+fCm
+gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEuzCCA6OgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQGEwJVUzET
+MBEGA1UEChMKQXBwbGUgSW5jLjEmMCQGA1UECxMdQXBwbGUgQ2VydGlmaWNhdGlv
+biBBdXRob3JpdHkxFjAUBgNVBAMTDUFwcGxlIFJvb3QgQ0EwHhcNMDYwNDI1MjE0
+MDM2WhcNMzUwMjA5MjE0MDM2WjBiMQswCQYDVQQGEwJVUzETMBEGA1UEChMKQXBw
+bGUgSW5jLjEmMCQGA1UECxMdQXBwbGUgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkx
+FjAUBgNVBAMTDUFwcGxlIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQDkkakJH5HbHkdQ6wXtXnmELes2oldMVeyLGYne+Uts9QerIjAC6Bg+
++FAJ039BqJj50cpmnCRrEdCju+QbKsMflZ56DKRHi1vUFjczy8QPTc4UadHJGXL1
+XQ7Vf1+b8iUDulWPTV0N8WQ1IxVLFVkds5T39pyez1C6wVhQZ48ItCD3y6wsIG9w
+tj8BMIy3Q88PnT3zK0koGsj+zrW5DtleHNbLPbU6rfQPDgCSC7EhFi501TwN22IW
+q6NxkkdTVcGvL0Gz+PvjcM3mo0xFfh9Ma1CWQYnEdGILEINBhzOKgbEwWOxaBDKM
+aLOPHd5lc/9nXmW8Sdh2nzMUZaF3lMktAgMBAAGjggF6MIIBdjAOBgNVHQ8BAf8E
+BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUK9BpR5R2Cf70a40uQKb3
+R01/CF4wHwYDVR0jBBgwFoAUK9BpR5R2Cf70a40uQKb3R01/CF4wggERBgNVHSAE
+ggEIMIIBBDCCAQAGCSqGSIb3Y2QFATCB8jAqBggrBgEFBQcCARYeaHR0cHM6Ly93
+d3cuYXBwbGUuY29tL2FwcGxlY2EvMIHDBggrBgEFBQcCAjCBthqBs1JlbGlhbmNl
+IG9uIHRoaXMgY2VydGlmaWNhdGUgYnkgYW55IHBhcnR5IGFzc3VtZXMgYWNjZXB0
+YW5jZSBvZiB0aGUgdGhlbiBhcHBsaWNhYmxlIHN0YW5kYXJkIHRlcm1zIGFuZCBj
+b25kaXRpb25zIG9mIHVzZSwgY2VydGlmaWNhdGUgcG9saWN5IGFuZCBjZXJ0aWZp
+Y2F0aW9uIHByYWN0aWNlIHN0YXRlbWVudHMuMA0GCSqGSIb3DQEBBQUAA4IBAQBc
+NplMLXi37Yyb3PN3m/J20ncwT8EfhYOFG5k9RzfyqZtAjizUsZAS2L70c5vu0mQP
+y3lPNNiiPvl4/2vIB+x9OYOLUyDTOMSxv5pPCmv/K/xZpwUJfBdAVhEedNO3iyM7
+R6PVbyTi69G3cN8PReEnyvFteO3ntRcXqNx+IjXKJdXZD9Zr1KIkIxH3oayPc4Fg
+xhtbCS+SsvhESPBgOJ4V9T0mZyCKM2r3DYLP3uujL/lTaltkwGMzd/c6ByxW69oP
+IQ7aunMZT7XZNn/Bh1XZp5m5MkL72NVxnn6hUrcbvZNCJBIqxw8dtk2cXmPIS4AX
+UKqK1drk/NAJBzewdXUh
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIID9zCCAt+gAwIBAgIESJ8AATANBgkqhkiG9w0BAQUFADCBijELMAkGA1UEBhMC
+Q04xMjAwBgNVBAoMKUNoaW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24g
+Q2VudGVyMUcwRQYDVQQDDD5DaGluYSBJbnRlcm5ldCBOZXR3b3JrIEluZm9ybWF0
+aW9uIENlbnRlciBFViBDZXJ0aWZpY2F0ZXMgUm9vdDAeFw0xMDA4MzEwNzExMjVa
+Fw0zMDA4MzEwNzExMjVaMIGKMQswCQYDVQQGEwJDTjEyMDAGA1UECgwpQ2hpbmEg
+SW50ZXJuZXQgTmV0d29yayBJbmZvcm1hdGlvbiBDZW50ZXIxRzBFBgNVBAMMPkNo
+aW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24gQ2VudGVyIEVWIENlcnRp
+ZmljYXRlcyBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm35z
+7r07eKpkQ0H1UN+U8i6yjUqORlTSIRLIOTJCBumD1Z9S7eVnAztUwYyZmczpwA//
+DdmEEbK40ctb3B75aDFk4Zv6dOtouSCV98YPjUesWgbdYavi7NifFy2cyjw1l1Vx
+zUOFsUcW9SxTgHbP0wBkvUCZ3czY28Sf1hNfQYOL+Q2HklY0bBoQCxfVWhyXWIQ8
+hBouXJE0bhlffxdpxWXvayHG1VA6v2G5BY3vbzQ6sm8UY78WO5upKv23KzhmBsUs
+4qpnHkWnjQRmQvaPK++IIGmPMowUc9orhpFjIpryp9vOiYurXccUwVswah+xt54u
+gQEC7c+WXmPbqOY4twIDAQABo2MwYTAfBgNVHSMEGDAWgBR8cks5x8DbYqVPm6oY
+NJKiyoOCWTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4E
+FgQUfHJLOcfA22KlT5uqGDSSosqDglkwDQYJKoZIhvcNAQEFBQADggEBACrDx0M3
+j92tpLIM7twUbY8opJhJywyA6vPtI2Z1fcXTIWd50XPFtQO3WKwMVC/GVhMPMdoG
+52U7HW8228gd+f2ABsqjPWYWqJ1MFn3AlUa1UeTiH9fqBk1jjZaM7+czV0I664zB
+echNdn3e9rG3geCg+aF4RhcaVpjwTj2rHO3sOdwHSPdj/gauwqRcalsyiMXHM4Ws
+ZkJHwlgkmeHlPuV1LI5D1l08eB6olYIpUNHRFrrvwb562bTYzB5MRuF3sTGrvSrI
+zo9uoV1/A3U05K2JRVRevq4opbs/eHnrc7MKDf2+yfdWrPa37S+bISnHOLaVxATy
+wy39FCqQmbkHzJ8=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x
+GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv
+b3QgQ0EgMjAeFw0wNjExMjQxODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNV
+BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W
+YWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCa
+GMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6XJxg
+Fyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55J
+WpzmM+Yklvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bB
+rrcCaoF6qUWD4gXmuVbBlDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp
++ARz8un+XJiM9XOva7R+zdRcAitMOeGylZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1
+ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt66/3FsvbzSUr5R/7mp/i
+Ucw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1JdxnwQ5hYIiz
+PtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og
+/zOhD7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UH
+oycR7hYQe7xFSkyyBNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuI
+yV77zGHcizN300QyNQliBJIWENieJ0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1Ud
+EwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBQahGK8SEwzJQTU7tD2
+A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGUa6FJpEcwRTEL
+MAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT
+ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2f
+BluornFdLwUvZ+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzn
+g/iN/Ae42l9NLmeyhP3ZRPx3UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2Bl
+fF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodmVjB3pjd4M1IQWK4/YY7yarHvGH5K
+WWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK+JDSV6IZUaUtl0Ha
+B0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrWIozc
+hLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPR
+TUIZ3Ph1WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWD
+mbA4CD/pXvk1B+TJYm5Xf6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0Z
+ohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y
+4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8VCLAAVBpQ570su9t+Oza
+8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIE5jCCA86gAwIBAgIEO45L/DANBgkqhkiG9w0BAQUFADBdMRgwFgYJKoZIhvcN
+AQkBFglwa2lAc2suZWUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKExlBUyBTZXJ0aWZp
+dHNlZXJpbWlza2Vza3VzMRAwDgYDVQQDEwdKdXVyLVNLMB4XDTAxMDgzMDE0MjMw
+MVoXDTE2MDgyNjE0MjMwMVowXTEYMBYGCSqGSIb3DQEJARYJcGtpQHNrLmVlMQsw
+CQYDVQQGEwJFRTEiMCAGA1UEChMZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1czEQ
+MA4GA1UEAxMHSnV1ci1TSzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+AIFxNj4zB9bjMI0TfncyRsvPGbJgMUaXhvSYRqTCZUXP00B841oiqBB4M8yIsdOB
+SvZiF3tfTQou0M+LI+5PAk676w7KvRhj6IAcjeEcjT3g/1tf6mTll+g/mX8MCgkz
+ABpTpyHhOEvWgxutr2TC+Rx6jGZITWYfGAriPrsfB2WThbkasLnE+w0R9vXW+RvH
+LCu3GFH+4Hv2qEivbDtPL+/40UceJlfwUR0zlv/vWT3aTdEVNMfqPxZIe5EcgEMP
+PbgFPtGzlc3Yyg/CQ2fbt5PgIoIuvvVoKIO5wTtpeyDaTpxt4brNj3pssAki14sL
+2xzVWiZbDcDq5WDQn/413z8CAwEAAaOCAawwggGoMA8GA1UdEwEB/wQFMAMBAf8w
+ggEWBgNVHSAEggENMIIBCTCCAQUGCisGAQQBzh8BAQEwgfYwgdAGCCsGAQUFBwIC
+MIHDHoHAAFMAZQBlACAAcwBlAHIAdABpAGYAaQBrAGEAYQB0ACAAbwBuACAAdgDk
+AGwAagBhAHMAdABhAHQAdQBkACAAQQBTAC0AaQBzACAAUwBlAHIAdABpAGYAaQB0
+AHMAZQBlAHIAaQBtAGkAcwBrAGUAcwBrAHUAcwAgAGEAbABhAG0ALQBTAEsAIABz
+AGUAcgB0AGkAZgBpAGsAYQBhAHQAaQBkAGUAIABrAGkAbgBuAGkAdABhAG0AaQBz
+AGUAawBzMCEGCCsGAQUFBwIBFhVodHRwOi8vd3d3LnNrLmVlL2Nwcy8wKwYDVR0f
+BCQwIjAgoB6gHIYaaHR0cDovL3d3dy5zay5lZS9qdXVyL2NybC8wHQYDVR0OBBYE
+FASqekej5ImvGs8KQKcYP2/v6X2+MB8GA1UdIwQYMBaAFASqekej5ImvGs8KQKcY
+P2/v6X2+MA4GA1UdDwEB/wQEAwIB5jANBgkqhkiG9w0BAQUFAAOCAQEAe8EYlFOi
+CfP+JmeaUOTDBS8rNXiRTHyoERF5TElZrMj3hWVcRrs7EKACr81Ptcw2Kuxd/u+g
+kcm2k298gFTsxwhwDY77guwqYHhpNjbRxZyLabVAyJRld/JXIWY7zoVAtjNjGr95
+HvxcHdMdkxuLDF2FvZkwMhgJkVLpfKG6/2SSmuz+Ne6ML678IIbsSt4beDI3poHS
+na9aEhbKmVv8b20OxaAehsmR0FyYgl9jDIpaq9iVpszLita/ZEuOyoqysOkhMp6q
+qIWYNIE5ITuoOlIyPfZrN4YGWhWY3PARZv40ILcD9EEQfTmEeZZyY7aWAuVrua0Z
+TbvGRNs2yyqcjg==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICQzCCAcmgAwIBAgIILcX8iNLFS5UwCgYIKoZIzj0EAwMwZzEbMBkGA1UEAwwS
+QXBwbGUgUm9vdCBDQSAtIEczMSYwJAYDVQQLDB1BcHBsZSBDZXJ0aWZpY2F0aW9u
+IEF1dGhvcml0eTETMBEGA1UECgwKQXBwbGUgSW5jLjELMAkGA1UEBhMCVVMwHhcN
+MTQwNDMwMTgxOTA2WhcNMzkwNDMwMTgxOTA2WjBnMRswGQYDVQQDDBJBcHBsZSBS
+b290IENBIC0gRzMxJjAkBgNVBAsMHUFwcGxlIENlcnRpZmljYXRpb24gQXV0aG9y
+aXR5MRMwEQYDVQQKDApBcHBsZSBJbmMuMQswCQYDVQQGEwJVUzB2MBAGByqGSM49
+AgEGBSuBBAAiA2IABJjpLz1AcqTtkyJygRMc3RCV8cWjTnHcFBbZDuWmBSp3ZHtf
+TjjTuxxEtX/1H7YyYl3J6YRbTzBPEVoA/VhYDKX1DyxNB0cTddqXl5dvMVztK517
+IDvYuVTZXpmkOlEKMaNCMEAwHQYDVR0OBBYEFLuw3qFYM4iapIqZ3r6966/ayySr
+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2gA
+MGUCMQCD6cHEFl4aXTQY2e3v9GwOAEZLuN+yRhHFD/3meoyhpmvOwgPUnPWTxnS4
+at+qIxUCMG1mihDK1A3UT82NQz60imOlM27jbdoXt2QfyFMm+YhidDkLF1vLUagM
+6BgD56KyKA==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIExTCCA62gAwIBAgIBADANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJFVTEn
+MCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQL
+ExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEgMB4GA1UEAxMXR2xvYmFsIENo
+YW1iZXJzaWduIFJvb3QwHhcNMDMwOTMwMTYxNDE4WhcNMzcwOTMwMTYxNDE4WjB9
+MQswCQYDVQQGEwJFVTEnMCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgy
+NzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEgMB4G
+A1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwggEgMA0GCSqGSIb3DQEBAQUA
+A4IBDQAwggEIAoIBAQCicKLQn0KuWxfH2H3PFIP8T8mhtxOviteePgQKkotgVvq0
+Mi+ITaFgCPS3CU6gSS9J1tPfnZdan5QEcOw/Wdm3zGaLmFIoCQLfxS+EjXqXd7/s
+QJ0lcqu1PzKY+7e3/HKE5TWH+VX6ox8Oby4o3Wmg2UIQxvi1RMLQQ3/bvOSiPGpV
+eAp3qdjqGTK3L/5cPxvusZjsyq16aUXjlg9V9ubtdepl6DJWk0aJqCWKZQbua795
+B9Dxt6/tLE2Su8CoX6dnfQTyFQhwrJLWfQTSM/tMtgsL+xrJxI0DqX5c8lCrEqWh
+z0hQpe/SyBoT+rB/sYIcd2oPX9wLlY/vQ37mRQklAgEDo4IBUDCCAUwwEgYDVR0T
+AQH/BAgwBgEB/wIBDDA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLmNoYW1i
+ZXJzaWduLm9yZy9jaGFtYmVyc2lnbnJvb3QuY3JsMB0GA1UdDgQWBBRDnDafsJ4w
+TcbOX60Qq+UDpfqpFDAOBgNVHQ8BAf8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgAH
+MCoGA1UdEQQjMCGBH2NoYW1iZXJzaWducm9vdEBjaGFtYmVyc2lnbi5vcmcwKgYD
+VR0SBCMwIYEfY2hhbWJlcnNpZ25yb290QGNoYW1iZXJzaWduLm9yZzBbBgNVHSAE
+VDBSMFAGCysGAQQBgYcuCgEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly9jcHMuY2hh
+bWJlcnNpZ24ub3JnL2Nwcy9jaGFtYmVyc2lnbnJvb3QuaHRtbDANBgkqhkiG9w0B
+AQUFAAOCAQEAPDtwkfkEVCeR4e3t/mh/YV3lQWVPMvEYBZRqHN4fcNs+ezICNLUM
+bKGKfKX0j//U2K0X1S0E0T9YgOKBWYi+wONGkyT+kL0mojAt6JcmVzWJdJYY9hXi
+ryQZVgICsroPFOrGimbBhkVVi76SvpykBMdJPJ7oKXqJ1/6v/2j1pReQvayZzKWG
+VwlnRtvWFsJG8eSpUPWP0ZIV018+xgBJOm5YstHRJw0lyDL4IBHNfTIzSJRUTN3c
+ecQwn+uOuFW114hcxWokPbLTBQNRxgfvzBRydD1ucs4YKIxKoHflCStFREest2d/
+AYoFWpO+ocH/+OcOZ6RHSXZddZAa9SaP8A==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRF
+MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBD
+bGFzcyAzIENBIDIgMjAwOTAeFw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NTha
+ME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMM
+HkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIwDQYJKoZIhvcNAQEB
+BQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOADER03
+UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42
+tSHKXzlABF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9R
+ySPocq60vFYJfxLLHLGvKZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsM
+lFqVlNpQmvH/pStmMaTJOKDfHR+4CS7zp+hnUquVH+BGPtikw8paxTGA6Eian5Rp
+/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUCAwEAAaOCARowggEWMA8G
+A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ4PGEMA4G
+A1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVj
+dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUy
+MENBJTIwMiUyMDIwMDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRl
+cmV2b2NhdGlvbmxpc3QwQ6BBoD+GPWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3Js
+L2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAwOS5jcmwwDQYJKoZIhvcNAQEL
+BQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm2H6NMLVwMeni
+acfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0
+o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4K
+zCUqNQT4YJEVdT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8
+PIWmawomDeCTmGCufsYkl4phX5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3Y
+Johw1+qRzT65ysCQblrGXnRl11z+o+I=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBI
+MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x
+FzAVBgNVBAMTDlNlY3VyZVRydXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIz
+MTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1NlY3VyZVRydXN0IENv
+cnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQXOZEz
+Zum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO
+0gMdA+9tDWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIao
+wW8xQmxSPmjL8xk037uHGFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj
+7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b01k/unK8RCSc43Oz969XL0Imnal0ugBS
+8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmHursCAwEAAaOBnTCBmjAT
+BgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB
+/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCeg
+JYYjaHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGC
+NxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt3
+6Z3q059c4EVlew3KW+JwULKUBRSuSceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/
+3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHfmbx8IVQr5Fiiu1cprp6poxkm
+D5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZnMUFdAvnZyPS
+CPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR
+3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDczCCAlugAwIBAgIBBDANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJLUjEN
+MAsGA1UECgwES0lTQTEuMCwGA1UECwwlS29yZWEgQ2VydGlmaWNhdGlvbiBBdXRo
+b3JpdHkgQ2VudHJhbDEWMBQGA1UEAwwNS0lTQSBSb290Q0EgMTAeFw0wNTA4MjQw
+ODA1NDZaFw0yNTA4MjQwODA1NDZaMGQxCzAJBgNVBAYTAktSMQ0wCwYDVQQKDARL
+SVNBMS4wLAYDVQQLDCVLb3JlYSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBDZW50
+cmFsMRYwFAYDVQQDDA1LSVNBIFJvb3RDQSAxMIIBIDANBgkqhkiG9w0BAQEFAAOC
+AQ0AMIIBCAKCAQEAvATk+hM58DSWIGtsaLv623f/J/es7C/n/fB/bW+MKs0lCVsk
+9KFo/CjsySXirO3eyDOE9bClCTqnsUdIxcxPjHmc+QZXfd3uOPbPFLKc6tPAXXdi
+8EcNuRpAU1xkcK8IWsD3z3X5bI1kKB4g/rcbGdNaZoNy4rCbvdMlFQ0yb2Q3lIVG
+yHK+d9VuHygvx2nt54OJM1jT3qC/QOhDUO7cTWu8peqmyGGO9cNkrwYV3CmLP3WM
+vHFE2/yttRcdbYmDz8Yzvb9Fov4Kn6MRXw+5H5wawkbMnChmn3AmPC7fqoD+jMUE
+CSVPzZNHPDfqAmeS/vwiJFys0izgXAEzisEZ2wIBA6MyMDAwHQYDVR0OBBYEFL+2
+J9gDWnZlTGEBQVYx5Yt7OtnMMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEF
+BQADggEBABOvUQveimpb5poKyLGQSk6hAp3MiNKrZr097LuxQpVqslxa/6FjZJap
+aBV/JV6K+KRzwYCKhQoOUugy50X4TmWAkZl0Q+VFnUkq8JSV3enhMNITbslOsXfl
+BM+tWh6UCVrXPAgcrnrpFDLBRa3SJkhyrKhB2vAhhzle3/xk/2F0KpzZm4tfwjeT
+2KM3LzuTa7IbB6d/CVDv0zq+IWuKkDsnSlFOa56ch534eJAx7REnxqhZvvwYC/uO
+fi5C4e3nCSG9uRPFVmf0JqZCQ5BEVLRxm3bkGhKsGigA35vB1fjbXKP4krG9tNT5
+UNkAAk/bg9ART6RCVmE6fhMy04Qfybo=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1Ix
+RDBCBgNVBAoTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1
+dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1p
+YyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIFJvb3RDQSAyMDExMB4XDTExMTIw
+NjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYTAkdSMUQwQgYDVQQK
+EztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIENl
+cnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl
+c2VhcmNoIEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEB
+BQADggEPADCCAQoCggEBAKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPz
+dYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJ
+fel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa71HFK9+WXesyHgLacEns
+bgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u8yBRQlqD
+75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSP
+FEDH3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNV
+HRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp
+5dgTBCPuQSUwRwYDVR0eBEAwPqA8MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQu
+b3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQub3JnMA0GCSqGSIb3DQEBBQUA
+A4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVtXdMiKahsog2p
+6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8
+TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7
+dIsXRSZMFpGD/md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8Acys
+Nnq/onN694/BtZqhFLKPM58N7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXI
+l7WdmplNsDz4SgCbZN2fOUvRJ9e4
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG
+EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3
+MDUGA1UECwwuVGFuw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNl
+cnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBBcmFueSAoQ2xhc3MgR29sZCkgRsWR
+dGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgxMjA2MTUwODIxWjCB
+pzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxOZXRM
+b2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlm
+aWNhdGlvbiBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNz
+IEdvbGQpIEbFkXRhbsO6c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEAxCRec75LbRTDofTjl5Bu0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrT
+lF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw/HpYzY6b7cNGbIRwXdrz
+AZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAkH3B5r9s5
+VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRG
+ILdwfzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2
+BJtr+UBdADTHLpl1neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAG
+AQH/AgEEMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2M
+U9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwWqZw8UQCgwBEIBaeZ5m8BiFRh
+bvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTtaYtOUZcTh5m2C
++C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC
+bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2F
+uLjbvrW5KfnaNwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2
+XjG4Kvte9nHfRCaexOYNkbQudZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEPzCCAyegAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MQswCQYDVQQGEwJHQjEb
+MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow
+GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEkMCIGA1UEAwwbU2VjdXJlIENlcnRp
+ZmljYXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVow
+fjELMAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
+A1UEBwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxJDAiBgNV
+BAMMG1NlY3VyZSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEB
+BQADggEPADCCAQoCggEBAMBxM4KK0HDrc4eCQNUd5MvJDkKQ+d40uaG6EfQlhfPM
+cm3ye5drswfxdySRXyWP9nQ95IDC+DwN879A6vfIUtFyb+/Iq0G4bi4XKpVpDM3S
+HpR7LZQdqnXXs5jLrLxkU0C8j6ysNstcrbvd4JQX7NFc0L/vpZXJkMWwrPsbQ996
+CF23uPJAGysnnlDOXmWCiIxe004MeuoIkbY2qitC++rCoznl2yY4rYsK7hljxxwk
+3wN42ubqwUcaCwtGCd0C/N7Lh1/XMGNooa7cMqG6vv5Eq2i2pRcV/b3Vp6ea5EQz
+6YiO/O1R65NxTq0B50SOqy3LqP4BSUjwwN3HaNiS/j0CAwEAAaOBxzCBxDAdBgNV
+HQ4EFgQUPNiTiMLAggnMAZkGkyDpnnAJY08wDgYDVR0PAQH/BAQDAgEGMA8GA1Ud
+EwEB/wQFMAMBAf8wgYEGA1UdHwR6MHgwO6A5oDeGNWh0dHA6Ly9jcmwuY29tb2Rv
+Y2EuY29tL1NlY3VyZUNlcnRpZmljYXRlU2VydmljZXMuY3JsMDmgN6A1hjNodHRw
+Oi8vY3JsLmNvbW9kby5uZXQvU2VjdXJlQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmww
+DQYJKoZIhvcNAQEFBQADggEBAIcBbSMdflsXfcFhMs+P5/OKlFlm4J4oqF7Tt/Q0
+5qo5spcWxYJvMqTpjOev/e/C6LlLqqP05tqNZSH7uoDrJiiFGv45jN5bBAS0VPmj
+Z55B+glSzAVIqMk/IQQezkhr/IXownuvf7fM+F86/TXGDe+X3EyrEeFryzHRbPtI
+gKvcnDe4IRRLDXE97IMzbtFuMhbsmMcWi1mmNKsFVy2T96oTy9IT4rcuO81rUBcJ
+aD61JlfutuC23bkpgHl9j6PwpCikFcSF9CfUa7/lXORlAnZUtOM3ZiTTGWHIUhDl
+izeauan5Hb/qmZJhlv8BzaFfDbxxvA6sCx1HRR3B7Hzs/Sk=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIF0zCCA7ugAwIBAgIVALhZFHE/V9+PMcAzPdLWGXojF7TrMA0GCSqGSIb3DQEB
+DQUAMIGAMQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dp
+ZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5
+MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBIDIwHhcNMTExMDA2
+MDgzOTU2WhcNNDYxMDA2MDgzOTU2WjCBgDELMAkGA1UEBhMCUEwxIjAgBgNVBAoT
+GVVuaXpldG8gVGVjaG5vbG9naWVzIFMuQS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0
+aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIGA1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0
+d29yayBDQSAyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAvfl4+ObV
+gAxknYYblmRnPyI6HnUBfe/7XGeMycxca6mR5rlC5SBLm9qbe7mZXdmbgEvXhEAr
+J9PoujC7Pgkap0mV7ytAJMKXx6fumyXvqAoAl4Vaqp3cKcniNQfrcE1K1sGzVrih
+QTib0fsxf4/gX+GxPw+OFklg1waNGPmqJhCrKtPQ0WeNG0a+RzDVLnLRxWPa52N5
+RH5LYySJhi40PylMUosqp8DikSiJucBb+R3Z5yet/5oCl8HGUJKbAiy9qbk0WQq/
+hEr/3/6zn+vZnuCYI+yma3cWKtvMrTscpIfcRnNeGWJoRVfkkIJCu0LW8GHgwaM9
+ZqNd9BjuiMmNF0UpmTJ1AjHuKSbIawLmtWJFfzcVWiNoidQ+3k4nsPBADLxNF8tN
+orMe0AZa3faTz1d1mfX6hhpneLO/lv403L3nUlbls+V1e9dBkQXcXWnjlQ1DufyD
+ljmVe2yAWk8TcsbXfSl6RLpSpCrVQUYJIP4ioLZbMI28iQzV13D4h1L92u+sUS4H
+s07+0AnacO+Y+lbmbdu1V0vc5SwlFcieLnhO+NqcnoYsylfzGuXIkosagpZ6w7xQ
+EmnYDlpGizrrJvojybawgb5CAKT41v4wLsfSRvbljnX98sy50IdbzAYQYLuDNbde
+Z95H7JlI8aShFf6tjGKOOVVPORa5sWOd/7cCAwEAAaNCMEAwDwYDVR0TAQH/BAUw
+AwEB/zAdBgNVHQ4EFgQUtqFUOQLDoD+Oirz61PgcptE6Dv0wDgYDVR0PAQH/BAQD
+AgEGMA0GCSqGSIb3DQEBDQUAA4ICAQCdU8KBJdw1LK4K3VqbRjBWu9S0bEuG5gql
+0pKKmo3cj7TudvQDy+ubAXirKmu1uiNOMXy1LN0taWczbmNdORgS+KAoU0SHq2rE
+kpYfKqIcup3dJ/tSTbCPWujtjcNo45KgJgyHkLAD6mplKAjERnjgW7oO8DPcJ7Z+
+iD29kqSWfkGogAh71jYSvBAVmyS8q619EYkvMe340s9Tjuu0U6fnBMovpiLEEdzr
+mMkiXUFq3ApSBFu8LqB9x7aSuySg8zfRK0OozPFoeBp+b2OQe590yGvZC1X2eQM9
+g8dBQJL7dgs3JRc8rz76PFwbhvlKDD+KxF4OmPGt7s/g/SE1xzNhzKI3GEN8M+mu
+doKCB0VIO8lnbq2jheiWVs+8u/qry7dXJ40aL5nzIzM0jspTY9NXNFBPz0nBBbrF
+qId744aP+0OiEumsUewEdkzw+o+5MRPpCLckCfmgtwc2WFfPxLt+SWaVNQS2dzW4
+qVMpX5KF+FLEWk79BmE5+33QdkeSzOwrvYRu5ptFwX1isVMtnnWg58koUNflvKiq
+B3hquXS0YPOEjQPcrpHadEQNe0Kpd9YrfKHGbBNTIqkSmqX5TyhFNbCXT0ZlhcX0
+/WKiomr8NDAGft8M4HOBlslEKt4fguxscletKWSk8cYpjjVgU85r2QK+OTB14Pdc
+Y2rwQMEsjQ==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDQzCCAiugAwIBAgIQX/h7KCtU3I1CoxW1aMmt/zANBgkqhkiG9w0BAQUFADA1
+MRYwFAYDVQQKEw1DaXNjbyBTeXN0ZW1zMRswGQYDVQQDExJDaXNjbyBSb290IENB
+IDIwNDgwHhcNMDQwNTE0MjAxNzEyWhcNMjkwNTE0MjAyNTQyWjA1MRYwFAYDVQQK
+Ew1DaXNjbyBTeXN0ZW1zMRswGQYDVQQDExJDaXNjbyBSb290IENBIDIwNDgwggEg
+MA0GCSqGSIb3DQEBAQUAA4IBDQAwggEIAoIBAQCwmrmrp68Kd6ficba0ZmKUeIhH
+xmJVhEAyv8CrLqUccda8bnuoqrpu0hWISEWdovyD0My5jOAmaHBKeN8hF570YQXJ
+FcjPFto1YYmUQ6iEqDGYeJu5Tm8sUxJszR2tKyS7McQr/4NEb7Y9JHcJ6r8qqB9q
+VvYgDxFUl4F1pyXOWWqCZe+36ufijXWLbvLdT6ZeYpzPEApk0E5tzivMW/VgpSdH
+jWn0f84bcN5wGyDWbs2mAag8EtKpP6BrXruOIIt6keO1aO6g58QBdKhTCytKmg9l
+Eg6CTY5j/e/rmxrbU6YTYK/CfdfHbBcl1HP7R2RQgYCUTOG/rksc35LtLgXfAgED
+o1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUJ/PI
+FR5umgIJFq0roIlgX9p7L6owEAYJKwYBBAGCNxUBBAMCAQAwDQYJKoZIhvcNAQEF
+BQADggEBAJ2dhISjQal8dwy3U8pORFBi71R803UXHOjgxkhLtv5MOhmBVrBW7hmW
+Yqpao2TB9k5UM8Z3/sUcuuVdJcr18JOagxEu5sv4dEX+5wW4q+ffy0vhN4TauYuX
+cB7w4ovXsNgOnbFp1iqRe6lJT37mjpXYgyc81WhJDtSd9i7rp77rMKSsH0T8lasz
+Bvt9YAretIpjsJyp8qS5UwGH0GikJ3+r/+n6yUA4iGe0OcaEb1fJU9u6ju7AQ7L4
+CYNu/2bPPu8Xs1gYJQk0XuPL1hS27PKSb3TkL4Eq1ZKR4OCXPDJoBYVL0fdX4lId
+kxpUnwVwwEpxYB5DC2Ae/qPOgRnhCzU=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx
+EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT
+HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs
+ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw
+MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6
+b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj
+aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp
+Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg
+nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1
+HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N
+Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN
+dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0
+HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO
+BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G
+CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU
+sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3
+4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg
+8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K
+pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1
+mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDzzCCAregAwIBAgIDAWweMA0GCSqGSIb3DQEBBQUAMIGNMQswCQYDVQQGEwJB
+VDFIMEYGA1UECgw/QS1UcnVzdCBHZXMuIGYuIFNpY2hlcmhlaXRzc3lzdGVtZSBp
+bSBlbGVrdHIuIERhdGVudmVya2VociBHbWJIMRkwFwYDVQQLDBBBLVRydXN0LW5R
+dWFsLTAzMRkwFwYDVQQDDBBBLVRydXN0LW5RdWFsLTAzMB4XDTA1MDgxNzIyMDAw
+MFoXDTE1MDgxNzIyMDAwMFowgY0xCzAJBgNVBAYTAkFUMUgwRgYDVQQKDD9BLVRy
+dXN0IEdlcy4gZi4gU2ljaGVyaGVpdHNzeXN0ZW1lIGltIGVsZWt0ci4gRGF0ZW52
+ZXJrZWhyIEdtYkgxGTAXBgNVBAsMEEEtVHJ1c3QtblF1YWwtMDMxGTAXBgNVBAMM
+EEEtVHJ1c3QtblF1YWwtMDMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
+AQCtPWFuA/OQO8BBC4SAzewqo51ru27CQoT3URThoKgtUaNR8t4j8DRE/5TrzAUj
+lUC5B3ilJfYKvUWG6Nm9wASOhURh73+nyfrBJcyFLGM/BWBzSQXgYHiVEEvc+RFZ
+znF/QJuKqiTfC0Li21a8StKlDJu3Qz7dg9MmEALP6iPESU7l0+m0iKsMrmKS1GWH
+2WrX9IWf5DMiJaXlyDO6w8dB3F/GaswADm0yqLaHNgBid5seHzTLkDx4iHQF63n1
+k3Flyp3HaxgtPVxO59X4PzF9j4fsCiIvI+n+u33J4PTs63zEsMMtYrWacdaxaujs
+2e3Vcuy+VwHOBVWf3tFgiBCzAgMBAAGjNjA0MA8GA1UdEwEB/wQFMAMBAf8wEQYD
+VR0OBAoECERqlWdVeRFPMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOC
+AQEAVdRU0VlIXLOThaq/Yy/kgM40ozRiPvbY7meIMQQDbwvUB/tOdQ/TLtPAF8fG
+KOwGDREkDg6lXb+MshOWcdzUzg4NCmgybLlBMRmrsQd7TZjTXLDR8KdCoLXEjq/+
+8T/0709GAHbrAvv5ndJAlseIOrifEXnzgGWovR/TeIGgUUw3tKZdJXDRZslo+S4R
+FGjxVJgIrCaSD96JntT6s3kr0qN51OyLrIdTaEJMUVF0HhsnLuP1Hyl0Te2v9+GS
+mYHovjrHF1D2t8b8m7CKa9aIA5GPBnc6hQLdmNVDeD/GMBWsm2vLV7eJUYs66MmE
+DNuxUCAKGkq6ahq97BvIxYSazQ==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCB
+rjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf
+Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw
+MDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNV
+BAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0wODA0MDIwMDAwMDBa
+Fw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhhd3Rl
+LCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9u
+MTgwNgYDVQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXpl
+ZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEcz
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsr8nLPvb2FvdeHsbnndm
+gcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2AtP0LMqmsywCPLLEHd5N/8
+YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC+BsUa0Lf
+b1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS9
+9irY7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2S
+zhkGcuYMXDhpxwTWvGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUk
+OQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV
+HQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJKoZIhvcNAQELBQADggEBABpA
+2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweKA3rD6z8KLFIW
+oCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu
+t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7c
+KUGRIjxpp7sC8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fM
+m7v/OeZWYdMKp8RcTGB7BXcmer/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZu
+MdRAGmI0Nj81Aa6sY6A=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFHjCCBAagAwIBAgIEAKA3oDANBgkqhkiG9w0BAQsFADCBtzELMAkGA1UEBhMC
+Q1oxOjA4BgNVBAMMMUkuQ0EgLSBRdWFsaWZpZWQgQ2VydGlmaWNhdGlvbiBBdXRo
+b3JpdHksIDA5LzIwMDkxLTArBgNVBAoMJFBydm7DrSBjZXJ0aWZpa2HEjW7DrSBh
+dXRvcml0YSwgYS5zLjE9MDsGA1UECww0SS5DQSAtIEFjY3JlZGl0ZWQgUHJvdmlk
+ZXIgb2YgQ2VydGlmaWNhdGlvbiBTZXJ2aWNlczAeFw0wOTA5MDEwMDAwMDBaFw0x
+OTA5MDEwMDAwMDBaMIG3MQswCQYDVQQGEwJDWjE6MDgGA1UEAwwxSS5DQSAtIFF1
+YWxpZmllZCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSwgMDkvMjAwOTEtMCsGA1UE
+CgwkUHJ2bsOtIGNlcnRpZmlrYcSNbsOtIGF1dG9yaXRhLCBhLnMuMT0wOwYDVQQL
+DDRJLkNBIC0gQWNjcmVkaXRlZCBQcm92aWRlciBvZiBDZXJ0aWZpY2F0aW9uIFNl
+cnZpY2VzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtTaEy0KC8M9l
+4lSaWHMs4+sVV1LwzyJYiIQNeCrv1HHm/YpGIdY/Z640ceankjQvIX7m23BK4OSC
+6KO8kZYA3zopOz6GFCOKV2PvLukbc+c2imF6kLHEv6qNA8WxhPbR3xKwlHDwB2yh
+Wzo7V3QVgDRG83sugqQntKYC3LnlTGbJpNP+Az72gpO9AHUn/IBhFk4ksc8lYS2L
+9GCy9CsmdKSBP78p9w8Lx7vDLqkDgt1/zBrcUWmSSb7AE/BPEeMryQV1IdI6nlGn
+BhWkXOYf6GSdayJw86btuxC7viDKNrbp44HjQRaSxnp6O3eto1x4DfiYdw/YbJFe
+7EjkxSQBywIDAQABo4IBLjCCASowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E
+BAMCAQYwgecGA1UdIASB3zCB3DCB2QYEVR0gADCB0DCBzQYIKwYBBQUHAgIwgcAa
+gb1UZW50byBjZXJ0aWZpa2F0IGplIHZ5ZGFuIGpha28ga3ZhbGlmaWtvdmFueSBz
+eXN0ZW1vdnkgY2VydGlmaWthdCBwb2RsZSB6YWtvbmEgYy4gMjI3LzIwMDAgU2Iu
+IHYgcGxhdG5lbSB6bmVuaS9UaGlzIGlzIHF1YWxpZmllZCBzeXN0ZW0gY2VydGlm
+aWNhdGUgYWNjb3JkaW5nIHRvIEN6ZWNoIEFjdCBOby4gMjI3LzIwMDAgQ29sbC4w
+HQYDVR0OBBYEFHnL0CPpOmdwkXRP01Hi4CD94Sj7MA0GCSqGSIb3DQEBCwUAA4IB
+AQB9laU214hYaBHPZftbDS/2dIGLWdmdSbj1OZbJ8LIPBMxYjPoEMqzAR74tw96T
+i6aWRa5WdOWaS6I/qibEKFZhJAVXX5mkx2ewGFLJ+0Go+eTxnjLOnhVF2V2s+57b
+m8c8j6/bS6Ij6DspcHEYpfjjh64hE2r0aSpZDjGzKFM6YpqsCJN8qYe2X1qmGMLQ
+wvNdjG+nPzCJOOuUEypIWt555ZDLXqS5F7ZjBjlfyDZjEfS2Es9Idok8alf563Mi
+9/o+Ba46wMYOkk3P1IlU0RqCajdbliioACKDztAqubONU1guZVzV8tuMASVzbJeL
+/GAB7ECTwe1RuKrLYtglMKI9
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW
+MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg
+Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM2WhcNMzYwOTE3MTk0NjM2WjB9
+MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi
+U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh
+cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA
+A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk
+pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf
+OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C
+Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT
+Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi
+HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM
+Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w
++2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+
+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3
+Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B
+26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID
+AQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE
+FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9j
+ZXJ0LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3Js
+LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFM
+BgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUHAgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0
+Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRwOi8vY2VydC5zdGFy
+dGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYgU3Rh
+cnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlh
+YmlsaXR5LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2Yg
+dGhlIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFp
+bGFibGUgYXQgaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL3BvbGljeS5wZGYwEQYJ
+YIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNT
+TCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAgEAFmyZ
+9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8
+jhvh3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUW
+FjgKXlf2Ysd6AgXmvB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJz
+ewT4F+irsfMuXGRuczE6Eri8sxHkfY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1
+ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3fsNrarnDy0RLrHiQi+fHLB5L
+EUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZEoalHmdkrQYu
+L6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq
+yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuC
+O3NJo2pXh5Tl1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6V
+um0ABj6y6koQOdjQK/W/7HW/lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkySh
+NOsF/5oirpt9P/FlUQqmMGqz9IgcgA38corog14=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIHhzCCBW+gAwIBAgIBLTANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJJTDEW
+MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg
+Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM3WhcNMzYwOTE3MTk0NjM2WjB9
+MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi
+U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh
+cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA
+A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk
+pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf
+OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C
+Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT
+Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi
+HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM
+Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w
++2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+
+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3
+Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B
+26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID
+AQABo4ICEDCCAgwwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD
+VR0OBBYEFE4L7xqkQFulF2mHMMo0aEPQQa7yMB8GA1UdIwQYMBaAFE4L7xqkQFul
+F2mHMMo0aEPQQa7yMIIBWgYDVR0gBIIBUTCCAU0wggFJBgsrBgEEAYG1NwEBATCC
+ATgwLgYIKwYBBQUHAgEWImh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL3BvbGljeS5w
+ZGYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL2ludGVybWVk
+aWF0ZS5wZGYwgc8GCCsGAQUFBwICMIHCMCcWIFN0YXJ0IENvbW1lcmNpYWwgKFN0
+YXJ0Q29tKSBMdGQuMAMCAQEagZZMaW1pdGVkIExpYWJpbGl0eSwgcmVhZCB0aGUg
+c2VjdGlvbiAqTGVnYWwgTGltaXRhdGlvbnMqIG9mIHRoZSBTdGFydENvbSBDZXJ0
+aWZpY2F0aW9uIEF1dGhvcml0eSBQb2xpY3kgYXZhaWxhYmxlIGF0IGh0dHA6Ly93
+d3cuc3RhcnRzc2wuY29tL3BvbGljeS5wZGYwEQYJYIZIAYb4QgEBBAQDAgAHMDgG
+CWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNTTCBDZXJ0aWZpY2F0aW9uIEF1
+dGhvcml0eTANBgkqhkiG9w0BAQsFAAOCAgEAjo/n3JR5fPGFf59Jb2vKXfuM/gTF
+wWLRfUKKvFO3lANmMD+x5wqnUCBVJX92ehQN6wQOQOY+2IirByeDqXWmN3PH/UvS
+Ta0XQMhGvjt/UfzDtgUx3M2FIk5xt/JxXrAaxrqTi3iSSoX4eA+D/i+tLPfkpLst
+0OcNOrg+zvZ49q5HJMqjNTbOx8aHmNrs++myziebiMMEofYLWWivydsQD032ZGNc
+pRJvkrKTlMeIFw6Ttn5ii5B/q06f/ON1FE8qMt9bDeD1e5MNq6HPh+GlBEXoPBKl
+CcWw0bdT82AUuoVpaiF8H3VhFyAXe2w7QSlc4axa0c2Mm+tgHRns9+Ww2vl5GKVF
+P0lDV9LdJNUso/2RjSe15esUBppMeyG7Oq0wBhjA2MFrLH9ZXF2RsXAiV+uKa0hK
+1Q8p7MZAwC+ITGgBF3f0JBlPvfrhsiAhS90a2Cl9qrjeVOwhVYBsHvUwyKMQ5bLm
+KhQxw4UtjJixhlpPiVktucf3HMiKf8CdBUrmQk9io20ppB+Fq9vlgcitKj1MXVuE
+JnHEhV5xJMqlG2zYYdMa4FTbzrqpMrUi9nNBCV24F10OD5mQ1kfabwo6YigUZ4LZ
+8dCAWZvLMdibD4x3TrVoivJs9iQOLWxwxXPR3hTQcY+203sC9uO41Alua551hDnm
+fyWl8kgAwKQB2j8=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
+QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
+MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
+b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
+CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
+nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
+43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
+T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
+gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
+BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
+TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
+DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
+hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
+06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
+PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
+YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
+CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDkzCCAnugAwIBAgIQFBOWgxRVjOp7Y+X8NId3RDANBgkqhkiG9w0BAQUFADA0
+MRMwEQYDVQQDEwpDb21TaWduIENBMRAwDgYDVQQKEwdDb21TaWduMQswCQYDVQQG
+EwJJTDAeFw0wNDAzMjQxMTMyMThaFw0yOTAzMTkxNTAyMThaMDQxEzARBgNVBAMT
+CkNvbVNpZ24gQ0ExEDAOBgNVBAoTB0NvbVNpZ24xCzAJBgNVBAYTAklMMIIBIjAN
+BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8ORUaSvTx49qROR+WCf4C9DklBKK
+8Rs4OC8fMZwG1Cyn3gsqrhqg455qv588x26i+YtkbDqthVVRVKU4VbirgwTyP2Q2
+98CNQ0NqZtH3FyrV7zb6MBBC11PN+fozc0yz6YQgitZBJzXkOPqUm7h65HkfM/sb
+2CEJKHxNGGleZIp6GZPKfuzzcuc3B1hZKKxC+cX/zT/npfo4sdAMx9lSGlPWgcxC
+ejVb7Us6eva1jsz/D3zkYDaHL63woSV9/9JLEYhwVKZBqGdTUkJe5DSe5L6j7Kpi
+Xd3DTKaCQeQzC6zJMw9kglcq/QytNuEMrkvF7zuZ2SOzW120V+x0cAwqTwIDAQAB
+o4GgMIGdMAwGA1UdEwQFMAMBAf8wPQYDVR0fBDYwNDAyoDCgLoYsaHR0cDovL2Zl
+ZGlyLmNvbXNpZ24uY28uaWwvY3JsL0NvbVNpZ25DQS5jcmwwDgYDVR0PAQH/BAQD
+AgGGMB8GA1UdIwQYMBaAFEsBmz5WGmU2dst7l6qSBe4y5ygxMB0GA1UdDgQWBBRL
+AZs+VhplNnbLe5eqkgXuMucoMTANBgkqhkiG9w0BAQUFAAOCAQEA0Nmlfv4pYEWd
+foPPbrxHbvUanlR2QnG0PFg/LUAlQvaBnPGJEMgOqnhPOAlXsDzACPw1jvFIUY0M
+cXS6hMTXcpuEfDhOZAYnKuGntewImbQKDdSFc8gS4TXt8QUxHXOZDOuWyt3T5oWq
+8Ir7dcHyCTxlZWTzTNity4hp8+SDtwy9F1qWF8pb/627HOkthIDYIb6FUtnUdLlp
+hbpN7Sgy6/lhSuTENh4Z3G+EER+V9YMoGKgzkkMn3V0TBEVPh9VGzT2ouvDzuFYk
+Res3x+F2T3I5GN9+dHLHcy056mDmrRGiVod7w2ia/viMcKjfZTL0pECMocJEAw6U
+AGegcQCCSA==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEZDCCA0ygAwIBAgIQRL4Mi1AAJLQR0zYwS8AzdzANBgkqhkiG9w0BAQUFADCB
+ozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
+Q2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho
+dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVUTi1VU0VSRmlyc3Qt
+TmV0d29yayBBcHBsaWNhdGlvbnMwHhcNOTkwNzA5MTg0ODM5WhcNMTkwNzA5MTg1
+NzQ5WjCBozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0
+IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYD
+VQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVUTi1VU0VS
+Rmlyc3QtTmV0d29yayBBcHBsaWNhdGlvbnMwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQCz+5Gh5DZVhawGNFugmliy+LUPBXeDrjKxdpJo7CNKyXY/45y2
+N3kDuatpjQclthln5LAbGHNhSuh+zdMvZOOmfAz6F4CjDUeJT1FxL+78P/m4FoCH
+iZMlIJpDgmkkdihZNaEdwH+DBmQWICzTSaSFtMBhf1EI+GgVkYDLpdXuOzr0hARe
+YFmnjDRy7rh4xdE7EkpvfmUnuaRVxblvQ6TFHSyZwFKkeEwVs0CYCGtDxgGwenv1
+axwiP8vv/6jQOkt2FZ7S0cYu49tXGzKiuG/ohqY/cKvlcJKrRB5AUPuco2LkbG6g
+yN7igEL66S/ozjIEj3yNtxyjNTwV3Z7DrpelAgMBAAGjgZEwgY4wCwYDVR0PBAQD
+AgHGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFPqGydvguul49Uuo1hXf8NPh
+ahQ8ME8GA1UdHwRIMEYwRKBCoECGPmh0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9V
+VE4tVVNFUkZpcnN0LU5ldHdvcmtBcHBsaWNhdGlvbnMuY3JsMA0GCSqGSIb3DQEB
+BQUAA4IBAQCk8yXM0dSRgyLQzDKrm5ZONJFUICU0YV8qAhXhi6r/fWRRzwr/vH3Y
+IWp4yy9Rb/hCHTO967V7lMPDqaAt39EpHx3+jz+7qEUqf9FuVSTiuwL7MT++6Lzs
+QCv4AdRWOOTKRIK1YSAhZ2X28AvnNPilwpyjXEAfhZOVBt5P1CeptqX8Fs1zMT+4
+ZSfP1FMa8Kxun08FDAOBp4QpxFq9ZFdyrTvPNximmMatBrTcCKME1SmklpoSZ0qM
+YEWd8SOasACcaLWYUNPvji6SZbFIPiG+FTAqDbUMo2s/rn9X9R+WfN9v3YIwLGUb
+QErNaLly7HF27FSOH4UMAWr6pjisH8SE
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv
+b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG
+EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl
+cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi
+MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c
+JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP
+mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+
+wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4
+VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/
+AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB
+AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW
+BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun
+pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC
+dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf
+fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm
+NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx
+H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe
++o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDEL
+MAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMp
+IDIwMDcgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAi
+BgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMjAeFw0wNzExMDUwMDAw
+MDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh
+d3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBGb3Ig
+YXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9v
+dCBDQSAtIEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/
+BebfowJPDQfGAFG6DAJSLSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6
+papu+7qzcMBniKI11KOasf2twu8x+qi58/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8E
+BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUmtgAMADna3+FGO6Lts6K
+DPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUNG4k8VIZ3
+KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41ox
+XZ3Krr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIETTCCAzWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBtMQswCQYDVQQGEwJDSDEO
+MAwGA1UEChMFYWRtaW4xETAPBgNVBAsTCFNlcnZpY2VzMSIwIAYDVQQLExlDZXJ0
+aWZpY2F0aW9uIEF1dGhvcml0aWVzMRcwFQYDVQQDEw5BZG1pbkNBLUNELVQwMTAe
+Fw0wNjAxMjUxMzM2MTlaFw0xNjAxMjUxMjM2MTlaMG0xCzAJBgNVBAYTAkNIMQ4w
+DAYDVQQKEwVhZG1pbjERMA8GA1UECxMIU2VydmljZXMxIjAgBgNVBAsTGUNlcnRp
+ZmljYXRpb24gQXV0aG9yaXRpZXMxFzAVBgNVBAMTDkFkbWluQ0EtQ0QtVDAxMIIB
+IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0jQlMZmpLDhV+GNR9TAoSNle
+JgQB4xAXJELQf5/ySMfoFA4MmjKqYXQkB6MGPuQKwR9XRRSPf61vqb8YPsdjRmgp
+byHBcUd5t0N8RX6wRZUnPMW+bCCo2VqAU4XFbnlc2gHKaam0wdTtbBTXEkv0ieIH
+fxCfFxXqSsSr60IkF/2/xbrAgV/QD5yHk6Ie8feAVWwi5UtaFqtu4LiFEh2QMyxs
+Oyz1OcvKzkM2g873tyiE7jzMgZP+Ww3tibk2F9+e6ZeiB37TLOmVtvgpmrws4fiI
+rFNXEYSWBVrUTbn81U47yWzOgf5fEHP07bRV5QOCzCm99qNimsbL6CG7nT78CQID
+AQABo4H3MIH0MBIGA1UdEwEB/wQIMAYBAf8CAQAwga4GA1UdIASBpjCBozCBoAYI
+YIV0AREDFQEwgZMwSAYIKwYBBQUHAgIwPBo6VGhpcyBpcyB0aGUgQWRtaW5DQS1D
+RC1UMDEgQ2VydGlmaWNhdGUgUHJhY3RpY2UgU3RhdGVtZW50LjBHBggrBgEFBQcC
+ARY7aHR0cDovL3d3dy5wa2kuYWRtaW4uY2gvcG9saWN5L0NQU18yXzE2Xzc1Nl8x
+XzE3XzNfMjFfMS5wZGYwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBQqxGkKocZV
+xgNucM6GgbOkD6oZ2zANBgkqhkiG9w0BAQUFAAOCAQEAn356bbusjI5glGXRQ1DR
+v21qQf0S4s3GHyZm7cqdOkFleM70ArBT+kOP5Nm7rlSAFyVgEkmBdOg7s9tlXClU
+yeZFnp6UEYRUcijPN8D1VaNRK6PIUObpDBQT0C+kAfxG9z4v29T0SxT4sgAdC/xQ
+Fyv58Fp9bPn7owuKwKcyCH1XSyi/Bp4XFELlLOaigBZO/w+dPBz4FcJSdZjU+BaJ
+0E3nKAjHlShO5ouBSZnaJz3p+nkw2Wyo36s6GxCK0XbkSP45iniIG4FmwwZkonYF
+ypQntHbx2oL7tUQQY0PDo8bGBMcPy/G2j+dciqZRlsnfgMy10SCzQ9MUx92xUG2V
+eg==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFVTCCBD2gAwIBAgIEO/OB0DANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQGEwJj
+aDEOMAwGA1UEChMFYWRtaW4xETAPBgNVBAsTCFNlcnZpY2VzMSIwIAYDVQQLExlD
+ZXJ0aWZpY2F0aW9uIEF1dGhvcml0aWVzMRYwFAYDVQQDEw1BZG1pbi1Sb290LUNB
+MB4XDTAxMTExNTA4NTEwN1oXDTIxMTExMDA3NTEwN1owbDELMAkGA1UEBhMCY2gx
+DjAMBgNVBAoTBWFkbWluMREwDwYDVQQLEwhTZXJ2aWNlczEiMCAGA1UECxMZQ2Vy
+dGlmaWNhdGlvbiBBdXRob3JpdGllczEWMBQGA1UEAxMNQWRtaW4tUm9vdC1DQTCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMvgr0QUIv5qF0nyXZ3PXAJi
+C4C5Wr+oVTN7oxIkXkxvO0GJToM9n7OVJjSmzBL0zJ2HXj0MDRcvhSY+KiZZc6Go
+vDvr5Ua481l7ILFeQAFtumeza+vvxeL5Nd0Maga2miiacLNAKXbAcUYRa0Ov5VZB
+++YcOYNNt/aisWbJqA2y8He+NsEgJzK5zNdayvYXQTZN+7tVgWOck16Da3+4FXdy
+fH1NCWtZlebtMKtERtkVAaVbiWW24CjZKAiVfggjsiLo3yVMPGj3budLx5D9hEEm
+vlyDOtcjebca+AcZglppWMX/iHIrx7740y0zd6cWEqiLIcZCrnpkr/KzwO135GkC
+AwEAAaOCAf0wggH5MA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIASBkTCBjjCBiwYI
+YIV0AREDAQAwfzArBggrBgEFBQcCAjAfGh1UaGlzIGlzIHRoZSBBZG1pbi1Sb290
+LUNBIENQUzBQBggrBgEFBQcCARZEaHR0cDovL3d3dy5pbmZvcm1hdGlrLmFkbWlu
+LmNoL1BLSS9saW5rcy9DUFNfMl8xNl83NTZfMV8xN18zXzFfMC5wZGYwfwYDVR0f
+BHgwdjB0oHKgcKRuMGwxFjAUBgNVBAMTDUFkbWluLVJvb3QtQ0ExIjAgBgNVBAsT
+GUNlcnRpZmljYXRpb24gQXV0aG9yaXRpZXMxETAPBgNVBAsTCFNlcnZpY2VzMQ4w
+DAYDVQQKEwVhZG1pbjELMAkGA1UEBhMCY2gwHQYDVR0OBBYEFIKf+iNzIPGXi7JM
+Tb5CxX9mzWToMIGZBgNVHSMEgZEwgY6AFIKf+iNzIPGXi7JMTb5CxX9mzWTooXCk
+bjBsMQswCQYDVQQGEwJjaDEOMAwGA1UEChMFYWRtaW4xETAPBgNVBAsTCFNlcnZp
+Y2VzMSIwIAYDVQQLExlDZXJ0aWZpY2F0aW9uIEF1dGhvcml0aWVzMRYwFAYDVQQD
+Ew1BZG1pbi1Sb290LUNBggQ784HQMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0B
+AQUFAAOCAQEAeE96XCYRpy6umkPKXDWCRn7INo96ZrWpMggcDORuofHIwdTkgOeM
+vWOxDN/yuT7CC3FAaUajbPRbDw0hRMcqKz0aC8CgwcyIyhw/rFK29mfNTG3EviP9
+QSsEbnelFnjpm1wjz4EaBiFjatwpUbI6+Zv3XbEt9QQXBn+c6DeFLe4xvC4B+MTr
+a440xTk59pSYux8OHhEvqIwHCkiijGqZhTS3KmGFeBopaR+dJVBRBMoXwzk4B3Hn
+0Zib1dEYFZa84vPJZyvxCbLOnPRDJgH6V2uQqbG+6DXVaf/wORVOvF/wzzv0viM/
+RWbEtJZdvo8N3sdtCULzifnxP/V0T9+4ZQ==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIG0TCCBbmgAwIBAgIBezANBgkqhkiG9w0BAQUFADCByTELMAkGA1UEBhMCSFUx
+ETAPBgNVBAcTCEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0
+b25zYWdpIEtmdC4xGjAYBgNVBAsTEVRhbnVzaXR2YW55a2lhZG9rMUIwQAYDVQQD
+EzlOZXRMb2NrIE1pbm9zaXRldHQgS296amVneXpvaSAoQ2xhc3MgUUEpIFRhbnVz
+aXR2YW55a2lhZG8xHjAcBgkqhkiG9w0BCQEWD2luZm9AbmV0bG9jay5odTAeFw0w
+MzAzMzAwMTQ3MTFaFw0yMjEyMTUwMTQ3MTFaMIHJMQswCQYDVQQGEwJIVTERMA8G
+A1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRvbnNh
+Z2kgS2Z0LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxQjBABgNVBAMTOU5l
+dExvY2sgTWlub3NpdGV0dCBLb3pqZWd5em9pIChDbGFzcyBRQSkgVGFudXNpdHZh
+bnlraWFkbzEeMBwGCSqGSIb3DQEJARYPaW5mb0BuZXRsb2NrLmh1MIIBIjANBgkq
+hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx1Ilstg91IRVCacbvWy5FPSKAtt2/Goq
+eKvld/Bu4IwjZ9ulZJm53QE+b+8tmjwi8F3JV6BVQX/yQ15YglMxZc4e8ia6AFQe
+r7C8HORSjKAyr7c3sVNnaHRnUPYtLmTeriZ539+Zhqurf4XsoPuAzPS4DB6TRWO5
+3Lhbm+1bOdRfYrCnjnxmOCyqsQhjF2d9zL2z8cM/z1A57dEZgxXbhxInlrfa6uWd
+vLrqOU+L73Sa58XQ0uqGURzk/mQIKAR5BevKxXEOC++r6uwSEaEYBTJp0QwsGj0l
+mT+1fMptsK6ZmfoIYOcZwvK9UdPM0wKswREMgM6r3JSda6M5UzrWhQIDAMV9o4IC
+wDCCArwwEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNVHQ8BAf8EBAMCAQYwggJ1Bglg
+hkgBhvhCAQ0EggJmFoICYkZJR1lFTEVNISBFemVuIHRhbnVzaXR2YW55IGEgTmV0
+TG9jayBLZnQuIE1pbm9zaXRldHQgU3pvbGdhbHRhdGFzaSBTemFiYWx5emF0YWJh
+biBsZWlydCBlbGphcmFzb2sgYWxhcGphbiBrZXN6dWx0LiBBIG1pbm9zaXRldHQg
+ZWxla3Ryb25pa3VzIGFsYWlyYXMgam9naGF0YXMgZXJ2ZW55ZXN1bGVzZW5laywg
+dmFsYW1pbnQgZWxmb2dhZGFzYW5hayBmZWx0ZXRlbGUgYSBNaW5vc2l0ZXR0IFN6
+b2xnYWx0YXRhc2kgU3phYmFseXphdGJhbiwgYXogQWx0YWxhbm9zIFN6ZXJ6b2Rl
+c2kgRmVsdGV0ZWxla2JlbiBlbG9pcnQgZWxsZW5vcnplc2kgZWxqYXJhcyBtZWd0
+ZXRlbGUuIEEgZG9rdW1lbnR1bW9rIG1lZ3RhbGFsaGF0b2sgYSBodHRwczovL3d3
+dy5uZXRsb2NrLmh1L2RvY3MvIGNpbWVuIHZhZ3kga2VyaGV0b2sgYXogaW5mb0Bu
+ZXRsb2NrLm5ldCBlLW1haWwgY2ltZW4uIFdBUk5JTkchIFRoZSBpc3N1YW5jZSBh
+bmQgdGhlIHVzZSBvZiB0aGlzIGNlcnRpZmljYXRlIGFyZSBzdWJqZWN0IHRvIHRo
+ZSBOZXRMb2NrIFF1YWxpZmllZCBDUFMgYXZhaWxhYmxlIGF0IGh0dHBzOi8vd3d3
+Lm5ldGxvY2suaHUvZG9jcy8gb3IgYnkgZS1tYWlsIGF0IGluZm9AbmV0bG9jay5u
+ZXQwHQYDVR0OBBYEFAlqYhaSsFq7VQ7LdTI6MuWyIckoMA0GCSqGSIb3DQEBBQUA
+A4IBAQCRalCc23iBmz+LQuM7/KbD7kPgz/PigDVJRXYC4uMvBcXxKufAQTPGtpvQ
+MznNwNuhrWw3AkxYQTvyl5LGSKjN5Yo5iWH5Upfpvfb5lHTocQ68d4bDBsxafEp+
+NFAwLvt/MpqNPfMgW/hqyobzMUwsWYACff44yTB1HLdV47yfuqhthCgFdbOLDcCR
+VCHnpgu0mfVRQdzNo0ci2ccBgcTcR08m6h/t280NmPSjnLRzMkqWmf68f8glWPhY
+83ZmiVSkpj7EUFy6iRiCdUgh0k8T6GB+B3bbELVR5qq5aKrN9p2QdRLqOBrKROi3
+macqaJVmlaut74nLYKkGEsaUR+ko
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQsw
+CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu
+ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe
+Fw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVTMRUw
+EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x
+IDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0CAQYF
+K4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FG
+fp4tn+6OYwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPO
+Z9wj/wMco+I+o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAd
+BgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNpYim8S8YwCgYIKoZIzj0EAwMDaAAwZQIx
+AK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y3maTD/HMsQmP3Wyr+mt/
+oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8
+sycX
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFkjCCA3qgAwIBAgIBCDANBgkqhkiG9w0BAQUFADA6MQswCQYDVQQGEwJDTjER
+MA8GA1UEChMIVW5pVHJ1c3QxGDAWBgNVBAMTD1VDQSBHbG9iYWwgUm9vdDAeFw0w
+ODAxMDEwMDAwMDBaFw0zNzEyMzEwMDAwMDBaMDoxCzAJBgNVBAYTAkNOMREwDwYD
+VQQKEwhVbmlUcnVzdDEYMBYGA1UEAxMPVUNBIEdsb2JhbCBSb290MIICIjANBgkq
+hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA2rPlBlA/9nP3xDK/RqUlYjOHsGj+p9+I
+A2N9Apb964fJ7uIIu527u+RBj8cwiQ9tJMAEbBSUgU2gDXRm8/CFr/hkGd656YGT
+0CiFmUdCSiw8OCdKzP/5bBnXtfPvm65bNAbXj6ITBpyKhELVs6OQaG2BkO5NhOxM
+cE4t3iQ5zhkAQ5N4+QiGHUPR9HK8BcBn+sBR0smFBySuOR56zUHSNqth6iur8CBV
+mTxtLRwuLnWW2HKX4AzKaXPudSsVCeCObbvaE/9GqOgADKwHLx25urnRoPeZnnRc
+GQVmMc8+KlL+b5/zub35wYH1N9ouTIElXfbZlJrTNYsgKDdfUet9Ysepk9H50DTL
+qScmLCiQkjtVY7cXDlRzq6987DqrcDOsIfsiJrOGrCOp139tywgg8q9A9f9ER3Hd
+J90TKKHqdjn5EKCgTUCkJ7JZFStsLSS3JGN490MYeg9NEePorIdCjedYcaSrbqLA
+l3y74xNLytu7awj5abQEctXDRrl36v+6++nwOgw19o8PrgaEFt2UVdTvyie3AzzF
+HCYq9TyopZWbhvGKiWf4xwxmse1Bv4KmAGg6IjTuHuvlb4l0T2qqaqhXZ1LUIGHB
+zlPL/SR/XybfoQhplqCe/klD4tPq2sTxiDEhbhzhzfN1DiBEFsx9c3Q1RSw7gdQg
+7LYJjD5IskkCAwEAAaOBojCBnzALBgNVHQ8EBAMCAQYwDAYDVR0TBAUwAwEB/zBj
+BgNVHSUEXDBaBggrBgEFBQcDAQYIKwYBBQUHAwIGCCsGAQUFBwMDBggrBgEFBQcD
+BAYIKwYBBQUHAwUGCCsGAQUFBwMGBggrBgEFBQcDBwYIKwYBBQUHAwgGCCsGAQUF
+BwMJMB0GA1UdDgQWBBTZw9P4gJJnzF3SOqLXcaK0xDiALTANBgkqhkiG9w0BAQUF
+AAOCAgEA0Ih5ygiq9ws0oE4Jwul+NUiJcIQjL1HDKy9e21NrW3UIKlS6Mg7VxnGF
+sZdJgPaE0PC6t3GUyHlrpsVE6EKirSUtVy/m1jEp+hmJVCl+t35HNmktbjK81HXa
+QnO4TuWDQHOyXd/URHOmYgvbqm4FjMh/Rk85hZCdvBtUKayl1/7lWFZXbSyZoUkh
+1WHGjGHhdSTBAd0tGzbDLxLMC9Z4i3WA6UG5iLHKPKkWxk4V43I29tSgQYWvimVw
+TbVEEFDs7d9t5tnGwBLxSzovc+k8qe4bqi81pZufTcU0hF8mFGmzI7GJchT46U1R
+IgP/SobEHOh7eQrbRyWBfvw0hKxZuFhD5D1DCVR0wtD92e9uWfdyYJl2b/Unp7uD
+pEqB7CmB9HdL4UISVdSGKhK28FWbAS7d9qjjGcPORy/AeGEYWsdl/J1GW1fcfA67
+loMQfFUYCQSu0feLKj6g5lDWMDbX54s4U+xJRODPpN/xU3uLWrb2EZBL1nXz/gLz
+Ka/wI3J9FO2pXd96gZ6bkiL8HvgBRUGXx2sBYb4zaPKgZYRmvOAqpGjTcezHCN6j
+w8k2SjTxF+KAryAhk5Qe5hXTVGLxtTgv48y5ZwSpuuXu+RBuyy5+E6+SFP7zJ3N7
+OPxzbbm5iPZujAv1/P8JDrMtXnt145Ik4ubhWD5LKAN1axibRww=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDdjCCAl6gAwIBAgIEOhsEBTANBgkqhkiG9w0BAQUFADBRMQswCQYDVQQGEwJE
+SzEMMAoGA1UEChMDS01EMQ8wDQYDVQQLEwZLTUQtQ0ExIzAhBgNVBAMTGktNRC1D
+QSBLdmFsaWZpY2VyZXQgUGVyc29uMB4XDTAwMTEyMTIzMjQ1OVoXDTE1MTEyMjIz
+MjQ1OVowUTELMAkGA1UEBhMCREsxDDAKBgNVBAoTA0tNRDEPMA0GA1UECxMGS01E
+LUNBMSMwIQYDVQQDExpLTUQtQ0EgS3ZhbGlmaWNlcmV0IFBlcnNvbjCCASIwDQYJ
+KoZIhvcNAQEBBQADggEPADCCAQoCggEBANriF4Xd6yD7ZlBE317UBDObn+vRMVc6
+p3wNQODdEDJe2z1ncCz9NJvhoLGdOJhyg7VVPh0P2c+KZ9WI9mWOKZI2bp2WkLju
+jCcxbhTrurY3Wfc6gwLBqqFV8wWgaZKmvVWizjw9Kyi25f3yX4fOho6Qq2lvVbub
+tvVFXAd51GJ+/2Yed+a4Or2bz2RcqHS81B3pywsD4mgJR5xREv5jqPfwNP+V7bkc
+X+pfO4kVhZ/V+8MSPdQHgcV/iB3wP2mwgWyIBNc1reBidGTiz8unnWu55hcNfsvt
+LJbTs9OHhsR7naRuy+S402nDnD5vnONOFEsiHn46w+T0rtu7h6j4OvkCAwEAAaNW
+MFQwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUeWLqmhI42Jxj7DifDsW+
+DlQhKD0wHwYDVR0jBBgwFoAUeWLqmhI42Jxj7DifDsW+DlQhKD0wDQYJKoZIhvcN
+AQEFBQADggEBANML/P42OuJ9aUV/0fItuIyc1JhqWvSqn5bXj+9eyEegcp8bHLHY
+42D1O+z0lNipdjYPSdMJ0wZOEUhr+150SdDQ1P/zQL8AUaLEBkRt7ZdzXPVH3PER
+qnf9IrpYBknZKfCAoVchA6Rr9WU3Sd8bMoRfMLKg8c0M8G6EPwCTcOFriSkbtvNG
+zd8r8I+WfUYIN/p8DI9JT9qfjVODnYPRMUm6KPvq27TsrGruKrqyaV94kWc8co8A
+v3zFLeCtghvUiRBdx+8Q7m5t4CkuSr0WINrqjIPFW2QrM1r82y09Fd16RkqL4LOg
+Lh6vB5KnTApv62rWdw7zWwYnjY6/vXYY1Aw=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIF4DCCA8igAwIBAgIRAPL6ZOJ0Y9ON/RAdBB92ylgwDQYJKoZIhvcNAQELBQAw
+ZzELMAkGA1UEBhMCY2gxETAPBgNVBAoTCFN3aXNzY29tMSUwIwYDVQQLExxEaWdp
+dGFsIENlcnRpZmljYXRlIFNlcnZpY2VzMR4wHAYDVQQDExVTd2lzc2NvbSBSb290
+IEVWIENBIDIwHhcNMTEwNjI0MDk0NTA4WhcNMzEwNjI1MDg0NTA4WjBnMQswCQYD
+VQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0YWwgQ2Vy
+dGlmaWNhdGUgU2VydmljZXMxHjAcBgNVBAMTFVN3aXNzY29tIFJvb3QgRVYgQ0Eg
+MjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMT3HS9X6lds93BdY7Bx
+UglgRCgzo3pOCvrY6myLURYaVa5UJsTMRQdBTxB5f3HSek4/OE6zAMaVylvNwSqD
+1ycfMQ4jFrclyxy0uYAyXhqdk/HoPGAsp15XGVhRXrwsVgu42O+LgrQ8uMIkqBPH
+oCE2G3pXKSinLr9xJZDzRINpUKTk4RtiGZQJo/PDvO/0vezbE53PnUgJUmfANykR
+HvvSEaeFGHR55E+FFOtSN+KxRdjMDUN/rhPSays/p8LiqG12W0OfvrSdsyaGOx9/
+5fLoZigWJdBLlzin5M8J0TbDC77aO0RYjb7xnglrPvMyxyuHxuxenPaHZa0zKcQv
+idm5y8kDnftslFGXEBuGCxobP/YCfnvUxVFkKJ3106yDgYjTdLRZncHrYTNaRdHL
+OdAGalNgHa/2+2m8atwBz735j9m9W8E6X47aD0upm50qKGsaCnw8qyIL5XctcfaC
+NYGu+HuB5ur+rPQam3Rc6I8k9l2dRsQs0h4rIWqDJ2dVSqTjyDKXZpBy2uPUZC5f
+46Fq9mDU5zXNysRojddxyNMkM3OxbPlq4SjbX8Y96L5V5jcb7STZDxmPX2MYWFCB
+UWVv8p9+agTnNCRxunZLWB4ZvRVgRaoMEkABnRDixzgHcgplwLa7JSnaFp6LNYth
+7eVxV4O1PHGf40+/fh6Bn0GXAgMBAAGjgYYwgYMwDgYDVR0PAQH/BAQDAgGGMB0G
+A1UdIQQWMBQwEgYHYIV0AVMCAgYHYIV0AVMCAjASBgNVHRMBAf8ECDAGAQH/AgED
+MB0GA1UdDgQWBBRF2aWBbj2ITY1x0kbBbkUe88SAnTAfBgNVHSMEGDAWgBRF2aWB
+bj2ITY1x0kbBbkUe88SAnTANBgkqhkiG9w0BAQsFAAOCAgEAlDpzBp9SSzBc1P6x
+XCX5145v9Ydkn+0UjrgEjihLj6p7jjm02Vj2e6E1CqGdivdj5eu9OYLU43otb98T
+PLr+flaYC/NUn81ETm484T4VvwYmneTwkLbUwp4wLh/vx3rEUMfqe9pQy3omywC0
+Wqu1kx+AiYQElY2NfwmTv9SoqORjbdlk5LgpWgi/UOGED1V7XwgiG/W9mR4U9s70
+WBCCswo9GcG/W6uqmdjyMb3lOGbcWAXH7WMaLgqXfIeTK7KK4/HsGOV1timH59yL
+Gn602MnTihdsfSlEvoqq9X46Lmgxk7lq2prg2+kupYTNHAq4Sgj5nPFhJpiTt3tm
+7JFe3VE/23MPrQRYCd0EApUKPtN236YQHoA96M2kZNEzx5LH4k5E4wnJTsJdhw4S
+nr8PyQUQ3nqjsTzyP6WqJ3mtMX0f/fwZacXduT98zca0wjAefm6S139hdlqP65VN
+vBFuIXxZN5nQBrz5Bm0yFqXZaajh3DyAHmBR3NdUIR7KYndP+tiPsys6DXhyyWhB
+WkdKwqPrGtcKqzwyVcgKEZzfdNbwQBUdyLmPtTbFr/giuMod89a2GQ+fYWVq6nTI
+fI/DT11lgh/ZDYnadXL77/FHZxOzyNEZiCcmmpl5fx7kLD977vHeTYuWl8PVP3wb
+I+2ksx0WckNLIOFZfsLorSa/ovc=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4
+MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6
+ZW5wZS5jb20wHhcNMDcxMjEzMTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYD
+VQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5j
+b20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ03rKDx6sp4boFmVq
+scIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAKClaO
+xdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6H
+LmYRY2xU+zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFX
+uaOKmMPsOzTFlUFpfnXCPCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQD
+yCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxTOTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+
+JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbKF7jJeodWLBoBHmy+E60Q
+rLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK0GqfvEyN
+BjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8L
+hij+0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIB
+QFqNeb+Lz0vPqhbBleStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+
+HMh3/1uaD7euBUbl8agW7EekFwIDAQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2lu
+Zm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+SVpFTlBFIFMuQS4gLSBDSUYg
+QTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBGNjIgUzgxQzBB
+BgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx
+MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
+AQYwHQYDVR0OBBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUA
+A4ICAQB4pgwWSp9MiDrAyw6lFn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWb
+laQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbgakEyrkgPH7UIBzg/YsfqikuFgba56
+awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8qhT/AQKM6WfxZSzwo
+JNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Csg1lw
+LDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCT
+VyvehQP5aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGk
+LhObNA5me0mrZJfQRsN5nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJb
+UjWumDqtujWTI6cfSN01RpiyEGjkpTHCClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/
+QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZoQ0iy2+tzJOeRf1SktoA+
+naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1ZWrOZyGls
+QyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDczCCAlugAwIBAgIQMDAwMDk3Mzc1NzM4NjAwMDANBgkqhkiG9w0BAQUFADBV
+MQswCQYDVQQGEwJGUjETMBEGA1UEChMKQ2VydGlOb21pczEcMBoGA1UECxMTQUMg
+UmFjaW5lIC0gUm9vdCBDQTETMBEGA1UEAxMKQ2VydGlOb21pczAeFw0wMDExMDkw
+MDAwMDBaFw0xMjExMDkwMDAwMDBaMFUxCzAJBgNVBAYTAkZSMRMwEQYDVQQKEwpD
+ZXJ0aU5vbWlzMRwwGgYDVQQLExNBQyBSYWNpbmUgLSBSb290IENBMRMwEQYDVQQD
+EwpDZXJ0aU5vbWlzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8SWb
+4mS5RXB3ENSIcfrEzCj/TRUQuT1tMCU0YUfXFSgcPdWglIzCv3kvh07QoB+8xMl+
+fQHvSSduAxnNewz0GBY9rApCPKlP6CcnJr74OSVZIiWt9wLfl4wwhNhZOiikIpZp
+EdOXWqRc84P5cUlN3Lwmr1sjCWmHfTSS4cAKxfDbFLfE61etosyoFZUTQbIhb1Bf
+JL5xRXAUZudQiU42n/yAoSUrN4FLUfPQNlOe1AB81pIgX8g2ojwxDjfgqSs1JmBF
+uLKJ45uVLEenQBPmQCGjL3maV86IRmR3a9UGlgvKAk0NBdh8mrQyQvcUlLBIQBCm
+l7wppt6maQHUNEPQSwIDAQABoz8wPTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw
+AwEB/zAdBgNVHQ4EFgQU+F4ho6ijFeb4tRG7/kIEXU2OgnowDQYJKoZIhvcNAQEF
+BQADggEBACe9FJayK6bXkJQrilBFMh75QPdFOks9PJuo86OMUlBDZGYFTCh9Arex
+N3KYCnAEzazYIALwr7eASJJDIQMu1Q+pkx/7ACde4kP47F27M2rm+v5HnGooCLz2
+s7Fe/WUycTQqgwF5lNp03m1ce/TvovgkEZeVN5wM/7+SsZLJGDigXGeq48j2g2hn
+8OckX9Ciyo0U3/1IVeigNBisiaOlsHSZOEPBZQRiZULob+NVbXVPo8nM1OyP3aHI
+LQex1yYcCr9m93nOiZyKkur3Uedf1yMTBe+fflnPFKGYnVqvTGXCKVdHzQBfpILA
+AuaC+5ykZhSiSMf8nmL2oPMcLO7YQw4=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx
+KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd
+BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl
+YyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgxMDAxMTAyOTU2WhcNMzMxMDAxMjM1
+OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy
+aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50
+ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN
+8ELg63iIVl6bmlQdTQyK9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/
+RLyTPWGrTs0NvvAgJ1gORH8EGoel15YUNpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4
+hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZFiP0Zf3WHHx+xGwpzJFu5
+ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W0eDrXltM
+EnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGj
+QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1
+A/d2O2GCahKqGFPrAyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOy
+WL6ukK2YJ5f+AbGwUgC4TeQbIXQbfsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ
+1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzTucpH9sry9uetuUg/vBa3wW30
+6gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7hP0HHRwA11fXT
+91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml
+e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4p
+TpPDpFQUWw==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G
+A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp
+Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1
+MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG
+A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL
+v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8
+eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq
+tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd
+C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa
+zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB
+mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH
+V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n
+bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG
+3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs
+J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO
+291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS
+ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd
+AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7
+TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDoTCCAomgAwIBAgIQKTZHquOKrIZKI1byyrdhrzANBgkqhkiG9w0BAQUFADBO
+MQswCQYDVQQGEwJ1czEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQ0wCwYDVQQL
+EwRGQkNBMRYwFAYDVQQDEw1Db21tb24gUG9saWN5MB4XDTA3MTAxNTE1NTgwMFoX
+DTI3MTAxNTE2MDgwMFowTjELMAkGA1UEBhMCdXMxGDAWBgNVBAoTD1UuUy4gR292
+ZXJubWVudDENMAsGA1UECxMERkJDQTEWMBQGA1UEAxMNQ29tbW9uIFBvbGljeTCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJeNvTMn5K1b+3i9L0dHbsd4
+6ZOcpN7JHP0vGzk4rEcXwH53KQA7Ax9oD81Npe53uCxiazH2+nIJfTApBnznfKM9
+hBiKHa4skqgf6F5PjY7rPxr4nApnnbBnTfAu0DDew5SwoM8uCjR/VAnTNr2kSVdS
+c+md/uRIeUYbW40y5KVIZPMiDZKdCBW/YDyD90ciJSKtKXG3d+8XyaK2lF7IMJCk
+FEhcVlcLQUwF1CpMP64Sm1kRdXAHImktLNMxzJJ+zM2kfpRHqpwJCPZLr1LoakCR
+xVW9QLHIbVeGlRfmH3O+Ry4+i0wXubklHKVSFzYIWcBCvgortFZRPBtVyYyQd+sC
+AwEAAaN7MHkwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O
+BBYEFC9Yl9ipBZilVh/72at17wI8NjTHMBIGCSsGAQQBgjcVAQQFAgMBAAEwIwYJ
+KwYBBAGCNxUCBBYEFHa3YJbdFFYprHWF03BjwbxHhhyLMA0GCSqGSIb3DQEBBQUA
+A4IBAQBgrvNIFkBypgiIybxHLCRLXaCRc+1leJDwZ5B6pb8KrbYq+Zln34PFdx80
+CTj5fp5B4Ehg/uKqXYeI6oj9XEWyyWrafaStsU+/HA2fHprA1RRzOCuKeEBuMPdi
+4c2Z/FFpZ2wR3bgQo2jeJqVW/TZsN5hs++58PGxrcD/3SDcJjwtCga1GRrgLgwb0
+Gzigf0/NC++DiYeXHIowZ9z9VKEDfgHLhUyxCynDvux84T8PCVI8L6eaSP436REG
+WOE2QYrEtr+O3c5Ks7wawM36GpnScZv6z7zyxFSjiDV2zBssRm8MtNHDYXaSdBHq
+S4CNHIkRi+xb/xfJSPzn4AYR4oRe
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFYzCCA0ugAwIBAgIBOzANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJJTDEW
+MBQGA1UEChMNU3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlm
+aWNhdGlvbiBBdXRob3JpdHkgRzIwHhcNMTAwMTAxMDEwMDAxWhcNMzkxMjMxMjM1
+OTAxWjBTMQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjEsMCoG
+A1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgRzIwggIiMA0G
+CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2iTZbB7cgNr2Cu+EWIAOVeq8Oo1XJ
+JZlKxdBWQYeQTSFgpBSHO839sj60ZwNq7eEPS8CRhXBF4EKe3ikj1AENoBB5uNsD
+vfOpL9HG4A/LnooUCri99lZi8cVytjIl2bLzvWXFDSxu1ZJvGIsAQRSCb0AgJnoo
+D/Uefyf3lLE3PbfHkffiAez9lInhzG7TNtYKGXmu1zSCZf98Qru23QumNK9LYP5/
+Q0kGi4xDuFby2X8hQxfqp0iVAXV16iulQ5XqFYSdCI0mblWbq9zSOdIxHWDirMxW
+RST1HFSr7obdljKF+ExP6JV2tgXdNiNnvP8V4so75qbsO+wmETRIjfaAKxojAuuK
+HDp2KntWFhxyKrOq42ClAJ8Em+JvHhRYW6Vsi1g8w7pOOlz34ZYrPu8HvKTlXcxN
+nw3h3Kq74W4a7I/htkxNeXJdFzULHdfBR9qWJODQcqhaX2YtENwvKhOuJv4KHBnM
+0D4LnMgJLvlblnpHnOl68wVQdJVznjAJ85eCXuaPOQgeWeU1FEIT/wCc976qUM/i
+UUjXuG+v+E5+M5iSFGI6dWPPe/regjupuznixL0sAA7IF6wT700ljtizkC+p2il9
+Ha90OrInwMEePnWjFqmveiJdnxMaz6eg6+OGCtP95paV1yPIN93EfKo2rJgaErHg
+TuixO/XWb/Ew1wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE
+AwIBBjAdBgNVHQ4EFgQUS8W0QGutHLOlHGVuRjaJhwUMDrYwDQYJKoZIhvcNAQEL
+BQADggIBAHNXPyzVlTJ+N9uWkusZXn5T50HsEbZH77Xe7XRcxfGOSeD8bpkTzZ+K
+2s06Ctg6Wgk/XzTQLwPSZh0avZyQN8gMjgdalEVGKua+etqhqaRpEpKwfTbURIfX
+UfEpY9Z1zRbkJ4kd+MIySP3bmdCPX1R0zKxnNBFi2QwKN4fRoxdIjtIXHfbX/dtl
+6/2o1PXWT6RbdejF0mCy2wl+JYt7ulKSnj7oxXehPOBKc2thz4bcQ///If4jXSRK
+9dNtD2IEBVeC2m6kMyV5Sy5UGYvMLD0w6dEG/+gyRr61M3Z3qAFdlsHB1b6uJcDJ
+HgoJIIihDsnzb02CVAAgp9KP5DlUFy6NHrgbuxu9mk47EDTcnIhT76IxW1hPkWLI
+wpqazRVdOKnWvvgTtZ8SafJQYqz7Fzf07rh1Z2AQ+4NQ+US1dZxAF7L+/XldblhY
+XzD8AK6vM8EOTmy6p6ahfzLbOOCxchcKK5HsamMm7YnUeMx0HgX4a/6ManY5Ka5l
+IxKVCCIcl85bBu4M4ru8H0ST9tg4RQUh7eStqxK2A6RCLi3ECToDZ2mEmuFZkIoo
+hdVddLHRDiBYmxOlsGOm7XtH/UVVMKTumtTm4ofvmMkyghEpIrwACjFeLQ/Ajulr
+so8uBtjRkcfGEvRM/TAXw8HaOFvjqermobp573PYtlNXLfbQ4ddI
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEP
+MA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAx
+MDQwNjA3Mjk0MFoXDTIxMDQwNjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNV
+BAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMiBDQTCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3/Ei9vX+ALTU74W+o
+Z6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybTdXnt
+5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s
+3TmVToMGf+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2Ej
+vOr7nQKV0ba5cTppCD8PtOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu
+8nYybieDwnPz3BjotJPqdURrBGAgcVeHnfO+oJAjPYok4doh28MCAwEAAaMzMDEw
+DwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITTXjwwCwYDVR0PBAQDAgEG
+MA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt0jSv9zil
+zqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/
+3DEIcbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvD
+FNr450kkkdAdavphOe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6
+Tk6ezAyNlNzZRZxe7EJQY670XcSxEtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2
+ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLHllpwrN9M
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDoDCCAoigAwIBAgIBMTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJKUDEO
+MAwGA1UEChMFTEdQS0kxGjAYBgNVBAsTEUFwcGxpY2F0aW9uIENBIEcyMB4XDTA2
+MDMzMTE1MDAwMFoXDTE2MDMzMTE0NTk1OVowOTELMAkGA1UEBhMCSlAxDjAMBgNV
+BAoTBUxHUEtJMRowGAYDVQQLExFBcHBsaWNhdGlvbiBDQSBHMjCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBALk1xhD422jbB8RATLAdHjbcw0H2z1UVbQh/
+XMZoVeXnV/GWUebhTXgPbkAVcDtl/hHf59PWWDU74Z8C/JRSRi6znmCbAp7JgtL2
+464JT4REtmKbAFFouDqt7GTRMkvplESDtA7OIYlrsDbAmMZLnMI+W2AqCTErLatM
+3rGg/VhWwoMdILzEhAmHe6iVl8YljoPgPpMN0cd9c6mo/BkAQC4iuHozQfV4/Vpx
+54LZSIhc7KiFhy1tgIlnGmm+EMBaju2IfT5vLDhrN85H2KIxMN5+U2Vsi4ZTQSBs
+vUilfq8AWlYSWIHR3IlZ+bXu+E2a2EQpi3mn9yKq6nxctBaIIA0CAwEAAaOBsjCB
+rzAdBgNVHQ4EFgQUf7hdjsQYa8Z9zC7prs405xdd4KEwDgYDVR0PAQH/BAQDAgEG
+MEwGA1UdHwRFMEMwQaA/oD2kOzA5MQswCQYDVQQGEwJKUDEOMAwGA1UEChMFTEdQ
+S0kxGjAYBgNVBAsTEUFwcGxpY2F0aW9uIENBIEcyMA8GA1UdEwEB/wQFMAMBAf8w
+HwYDVR0jBBgwFoAUf7hdjsQYa8Z9zC7prs405xdd4KEwDQYJKoZIhvcNAQEFBQAD
+ggEBADzYczZABkhKVBn1J0g5JaVuQue2zRvLOTS3m+xPKr535MqE/B3rmyJA1fT7
+aIdy/Eddag5SSuO1XUjGIpbmM21tq/bN18skWoyoRZ4+YYJ9lNUF8Bo1X3EvLlS1
+QQXvhg1S75yYG/EsTDrR84bTjD56L4ZFjoMyJlu/U8oOUVbcmsJaMBkNp57Vqpsg
+OWl4IfSXbdEOEUwu0xtasPmXeFwqj1Jl7kxCJcI3MA5tKzWUgwbor0U7BGanMLv5
+4CE7Y259RF06alPvERck/VSyWmxzViHJbC2XpEKzJ2EFIWNt6ii8TxpvQtyYq1XT
+HhvAkj+bweY7F1bixJhDJe62ywA=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICZzCCAdCgAwIBAgIBBDANBgkqhkiG9w0BAQUFADBhMQswCQYDVQQGEwJVUzEY
+MBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxDDAKBgNVBAsT
+A1BLSTEcMBoGA1UEAxMTRG9EIENMQVNTIDMgUm9vdCBDQTAeFw0wMDA1MTkxMzEz
+MDBaFw0yMDA1MTQxMzEzMDBaMGExCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMu
+IEdvdmVybm1lbnQxDDAKBgNVBAsTA0RvRDEMMAoGA1UECxMDUEtJMRwwGgYDVQQD
+ExNEb0QgQ0xBU1MgMyBSb290IENBMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB
+gQC1MP5kvurMbe2BLPd/6Rm6DmlqKOGpqcuVWB/x5pppU+CIP5HFUbljl6jmIYwT
+XjY8qFf6+HAsTGrLvzCnTBbkMlz4ErBR+BZXjS+0TfouqJToKmHUVw1Hzm4sL36Y
+Z8wACKu2lhY1woWR5VugCsdmUmLzYXWVF668KlYppeArUwIDAQABoy8wLTAdBgNV
+HQ4EFgQUbJyl8FyPbUGNxBc7kFfCD6PNbf4wDAYDVR0TBAUwAwEB/zANBgkqhkiG
+9w0BAQUFAAOBgQCvcUT5lyPMaGmMQwdBuoggsyIAQciYoFUczT9usZNcrfoYmrsc
+c2/9JEKPh59Rz76Gn+nXikhPCNlplKw/5g8tlw8ok3ZPYt//oM1h+KaGDDE0INx/
+L6j7Ob6V7jhZAmLB3mwVT+DfnbvkeXMk/WNklfdKqJkfSGWVx3u/eDLneg==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFUjCCBDqgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJLUjEN
+MAsGA1UEChMES0lTQTEuMCwGA1UECxMlS29yZWEgQ2VydGlmaWNhdGlvbiBBdXRo
+b3JpdHkgQ2VudHJhbDEWMBQGA1UEAxMNS0lTQSBSb290Q0EgMzAeFw0wNDExMTkw
+NjM5NTFaFw0xNDExMTkwNjM5NTFaMGQxCzAJBgNVBAYTAktSMQ0wCwYDVQQKEwRL
+SVNBMS4wLAYDVQQLEyVLb3JlYSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBDZW50
+cmFsMRYwFAYDVQQDEw1LSVNBIFJvb3RDQSAzMIIBIDANBgkqhkiG9w0BAQEFAAOC
+AQ0AMIIBCAKCAQEA3rrtF2Wu0b1KPazbgHLMWOHn4ZPazDB6z+8Lri2nQ6u/p0LP
+CFYIpEcdffqG79gwlyY0YTyADvjU65/8IjAboW0+40zSVU4WQDfC9gdu2we1pYyW
+geKbXH6UYcjOhDyx+gDmctMJhXfp3F4hT7TkTvTiF6tQrxz/oTlYdVsSspa5jfBw
+YkhbVigqpYeRNrkeJPW5unu2UlFbF1pgBWycwubGjD756t08jP+J3kNwrB248XXN
+OMpTDUdoasY8GMq94bS+DvTQ49IT+rBRERHUQavo9DmO4TSETwuTqmo4/OXGeEeu
+dhf6oYA3BgAVCP1rI476cg2V1ktisWjC3TSbXQIBA6OCAg8wggILMB8GA1UdIwQY
+MBaAFI+B8NqmzXQ8vmb0FWtGpP4GKMyqMB0GA1UdDgQWBBSPgfDaps10PL5m9BVr
+RqT+BijMqjAOBgNVHQ8BAf8EBAMCAQYwggEuBgNVHSAEggElMIIBITCCAR0GBFUd
+IAAwggETMDAGCCsGAQUFBwIBFiRodHRwOi8vd3d3LnJvb3RjYS5vci5rci9yY2Ev
+Y3BzLmh0bWwwgd4GCCsGAQUFBwICMIHRHoHOx3QAIMd4yZ3BHLKUACCs9cd4x3jJ
+ncEcx4WyyLLkACgAVABoAGkAcwAgAGMAZQByAHQAaQBmAGkAYwBhAHQAZQAgAGkA
+cwAgAGEAYwBjAHIAZQBkAGkAdABlAGQAIAB1AG4AZABlAHIAIABFAGwAZQBjAHQA
+cgBvAG4AaQBjACAAUwBpAGcAbgBhAHQAdQByAGUAIABBAGMAdAAgAG8AZgAgAHQA
+aABlACAAUgBlAHAAdQBiAGwAaQBjACAAbwBmACAASwBvAHIAZQBhACkwMwYDVR0R
+BCwwKqQoMCYxJDAiBgNVBAMMG+2VnOq1reygleuztOuztO2YuOynhO2dpeybkDAz
+BgNVHRIELDAqpCgwJjEkMCIGA1UEAwwb7ZWc6rWt7KCV67O067O07Zi47KeE7Z2l
+7JuQMA8GA1UdEwEB/wQFMAMBAf8wDAYDVR0kBAUwA4ABADANBgkqhkiG9w0BAQUF
+AAOCAQEAz9b3Dv2wjG4FFY6oXCuyWtEeV6ZeGKqCEQj8mbdbp+PI0qLT+SQ09+Pk
+rolUR9NpScmAwRHr4inH9gaLX7riXs+rw87P7pIl3J85Hg4D9N6QW6FwmVzHc07J
+pHVJeyWhn4KSjU3sYcUMMqfHODiAVToqgx2cZHm5Dac1Smjvj/8F2LpOVmHY+Epw
+mAiWk9hgxzrsX58dKzVPSBShmrtv7tIDhlPxEMcHVGJeNo7iHCsdF03m9VrvirqC
+6HfZKBF+N4dKlArJQOk1pTr7ZD7yXxZ683bXzu4/RB1Fql8RqlMcOh9SUWJUD6OQ
+Nc9Nb7rHviwJ8TX4Absk3TC8SA/u2Q==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G
+A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp
+Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4
+MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG
+A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8
+RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT
+gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm
+KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd
+QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ
+XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw
+DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o
+LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU
+RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp
+jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK
+6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX
+mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs
+Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH
+WD9f
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkG
+A1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3
+d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVu
+dHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEzMDEGA1UEAxMq
+RW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRUMxMB4XDTEy
+MTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYwFAYD
+VQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0
+L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0g
+Zm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBD
+ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEVDMTB2MBAGByqGSM49AgEGBSuBBAAi
+A2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHyAsWfoPZb1YsGGYZPUxBt
+ByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef9eNi1KlH
+Bz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O
+BBYEFLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVC
+R98crlOZF7ZvHH3hvxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nX
+hTcGtXsI/esni0qU+eH6p44mCOh8kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYD
+VQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0
+IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3
+MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xKTAnBgNVBAMTIENoYW1iZXJz
+IG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4MB4XDTA4MDgwMTEyMjk1MFoXDTM4MDcz
+MTEyMjk1MFowga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBj
+dXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIw
+EAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEp
+MCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0G
+CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW9
+28sNRHI+JrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKAXuFixrYp4YFs8r/lfTJq
+VKAyGVn+H4vXPWCGhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorjh40G072Q
+DuKZoRuGDtqaCrsLYVAGUvGef3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR
+5gN/ikilTWh1uem8nk4ZcfUyS5xtYBkL+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfL
+ZEFHcpOrUMPrCXZkNNI5t3YRCQ12RcSprj1qr7V9ZS+UWBDsXHyvfuK2GNnQm05a
+Sd+pZgvMPMZ4fKecHePOjlO+Bd5gD2vlGts/4+EhySnB8esHnFIbAURRPHsl18Tl
+UlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331lubKgdaX8ZSD6e2wsWsSaR6s
++12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ0wlf2eOKNcx5
+Wk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhj
+ya6BXBg14JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAx
+hduub+84Mxh2EQIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNV
+HQ4EFgQU+SSsD7K1+HnA+mCIG8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1
++HnA+mCIG8TZTQKeFxmhgbSkgbEwga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpN
+YWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29t
+L2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVy
+ZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAt
+IDIwMDiCCQCj2kJ+pLGu2jAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRV
+HSAAMCowKAYIKwYBBQUHAgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20w
+DQYJKoZIhvcNAQEFBQADggIBAJASryI1wqM58C7e6bXpeHxIvj99RZJe6dqxGfwW
+PJ+0W2aeaufDuV2I6A+tzyMP3iU6XsxPpcG1Lawk0lgH3qLPaYRgM+gQDROpI9CF
+5Y57pp49chNyM/WqfcZjHwj0/gF/JM8rLFQJ3uIrbZLGOU8W6jx+ekbURWpGqOt1
+glanq6B8aBMz9p0w8G8nOSQjKpD9kCk18pPfNKXG9/jvjA9iSnyu0/VU+I22mlaH
+FoI6M6taIgj3grrqLuBHmrS1RaMFO9ncLkVAO+rcf+g769HsJtg1pDDFOqxXnrN2
+pSB7+R5KBWIBpih1YJeSDW4+TTdDDZIVnBgizVGZoCkaPF+KMjNbMMeJL0eYD6MD
+xvbxrN8y8NmBGuScvfaAFPDRLLmF9dijscilIeUcE5fuDr3fKanvNFNb0+RqE4QG
+tjICxFKuItLcsiFCGtpA8CnJ7AoMXOLQusxI0zcKzBIKinmwPQN/aUv0NCB9szTq
+jktk9T79syNnFQ0EuPAtwQlRPLJsFfClI9eDdOTlLsn+mCdCxqvGnrDQWzilm1De
+fhiYtUU79nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRg
+OGcEMeyP84LG3rlV8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZ
+d0jQ
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV
+BAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2ln
+biBHb2xkIENBIC0gRzIwHhcNMDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBF
+MQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMR8wHQYDVQQDExZT
+d2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
+CgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUqt2/8
+76LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+
+bbqBHH5CjCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c
+6bM8K8vzARO/Ws/BtQpgvd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqE
+emA8atufK+ze3gE/bk3lUIbLtK/tREDFylqM2tIrfKjuvqblCqoOpd8FUrdVxyJd
+MmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvRAiTysybUa9oEVeXBCsdt
+MDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuendjIj3o02y
+MszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69y
+FGkOpeUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPi
+aG59je883WX0XaxR7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxM
+gI93e2CaHt+28kgeDrpOVG2Y4OGiGqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCB
+qTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUWyV7
+lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64OfPAeGZe6Drn
+8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov
+L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe6
+45R88a7A3hfm5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczO
+UYrHUDFu4Up+GC9pWbY9ZIEr44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5
+O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOfMke6UiI0HTJ6CVanfCU2qT1L2sCC
+bwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6mGu6uLftIdxf+u+yv
+GPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxpmo/a
+77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCC
+hdiDyyJkvC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid3
+92qgQmwLOM7XdVAyksLfKzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEpp
+Ld6leNcG2mqeSz53OiATIgHQv2ieY2BrNU0LbbqhPcCT4H8js1WtciVORvnSFu+w
+ZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6LqjviOvrv1vA+ACOzB2+htt
+Qc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNV
+BAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4X
+DTA3MDYyOTE1MTMwNVoXDTI3MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQ
+BgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwIQ2VydGlnbmEwggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7qXOEm7RFHYeGifBZ4
+QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyHGxny
+gQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbw
+zBfsV1/pogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q
+130yGLMLLGq/jj8UEYkgDncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2
+JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKfIrjxwo1p3Po6WAbfAgMBAAGjgbwwgbkw
+DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQtCRZvgHyUtVF9lo53BEw
+ZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJBgNVBAYT
+AkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzj
+AQ/JSP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG
+9w0BAQUFAAOCAQEAhQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8h
+bV6lUmPOEvjvKtpv6zf+EwLHyzs+ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFnc
+fca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1kluPBS1xp81HlDQwY9qcEQCYsuu
+HWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY1gkIl2PlwS6w
+t0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw
+WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDUzCCAjugAwIBAgIBAjANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEd
+MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3Mg
+Q2xhc3MgMyBDQSAxMB4XDTA1MDUwOTE0MTMwM1oXDTE1MDUwOTE0MTMwM1owSzEL
+MAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MR0wGwYD
+VQQDDBRCdXlwYXNzIENsYXNzIDMgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBAKSO13TZKWTeXx+HgJHqTjnmGcZEC4DVC69TB4sSveZn8AKxifZg
+isRbsELRwCGoy+Gb72RRtqfPFfV0gGgEkKBYouZ0plNTVUhjP5JW3SROjvi6K//z
+NIqeKNc0n6wv1g/xpC+9UrJJhW05NfBEMJNGJPO251P7vGGvqaMU+8IXF4Rs4HyI
++MkcVyzwPX6UvCWThOiaAJpFBUJXgPROztmuOfbIUxAMZTpHe2DC1vqRycZxbL2R
+hzyRhkmr8w+gbCZ2Xhysm3HljbybIR6c1jh+JIAVMYKWsUnTYjdbiAwKYjT+p0h+
+mbEwi5A3lRyoH6UsjfRVyNvdWQrCrXig9IsCAwEAAaNCMEAwDwYDVR0TAQH/BAUw
+AwEB/zAdBgNVHQ4EFgQUOBTmyPCppAP0Tj4io1vy1uCtQHQwDgYDVR0PAQH/BAQD
+AgEGMA0GCSqGSIb3DQEBBQUAA4IBAQABZ6OMySU9E2NdFm/soT4JXJEVKirZgCFP
+Bdy7pYmrEzMqnji3jG8CcmPHc3ceCQa6Oyh7pEfJYWsICCD8igWKH7y6xsL+z27s
+EzNxZy5p+qksP2bAEllNC1QCkoS72xLvg3BweMhT+t/Gxv/ciC8HwEmdMldg0/L2
+mSlf56oBzKwzqBwKu5HEA6BvtjT5htOzdlSY9EqBs1OdTUDs5XcTRa9bqh/YL0yC
+e/4qxFi7T/ye/QNlGioOw6UgFpRreaaiErS7GqQjel/wroQk5PMr+4okoyeYZdow
+dXb8GZHo2+ubPzK/QJcHJrrM85SFSnonk8+QQtS4Wxam58tAA915
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDqzCCApOgAwIBAgIRAMcoRwmzuGxFjB36JPU2TukwDQYJKoZIhvcNAQEFBQAw
+PDEbMBkGA1UEAxMSQ29tU2lnbiBTZWN1cmVkIENBMRAwDgYDVQQKEwdDb21TaWdu
+MQswCQYDVQQGEwJJTDAeFw0wNDAzMjQxMTM3MjBaFw0yOTAzMTYxNTA0NTZaMDwx
+GzAZBgNVBAMTEkNvbVNpZ24gU2VjdXJlZCBDQTEQMA4GA1UEChMHQ29tU2lnbjEL
+MAkGA1UEBhMCSUwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGtWhf
+HZQVw6QIVS3joFd67+l0Kru5fFdJGhFeTymHDEjWaueP1H5XJLkGieQcPOqs49oh
+gHMhCu95mGwfCP+hUH3ymBvJVG8+pSjsIQQPRbsHPaHA+iqYHU4Gk/v1iDurX8sW
+v+bznkqH7Rnqwp9D5PGBpX8QTz7RSmKtUxvLg/8HZaWSLWapW7ha9B20IZFKF3ue
+Mv5WJDmyVIRD9YTC2LxBkMyd1mja6YJQqTtoz7VdApRgFrFD2UNd3V2Hbuq7s8lr
+9gOUCXDeFhF6K+h2j0kQmHe5Y1yLM5d19guMsqtb3nQgJT/j8xH5h2iGNXHDHYwt
+6+UarA9z1YJZQIDTAgMBAAGjgacwgaQwDAYDVR0TBAUwAwEB/zBEBgNVHR8EPTA7
+MDmgN6A1hjNodHRwOi8vZmVkaXIuY29tc2lnbi5jby5pbC9jcmwvQ29tU2lnblNl
+Y3VyZWRDQS5jcmwwDgYDVR0PAQH/BAQDAgGGMB8GA1UdIwQYMBaAFMFL7XC29z58
+ADsAj8c+DkWfHl3sMB0GA1UdDgQWBBTBS+1wtvc+fAA7AI/HPg5Fnx5d7DANBgkq
+hkiG9w0BAQUFAAOCAQEAFs/ukhNQq3sUnjO2QiBq1BW9Cav8cujvR3qQrFHBZE7p
+iL1DRYHjZiM/EoZNGeQFsOY3wo3aBijJD4mkU6l1P7CW+6tMM1X5eCZGbxs2mPtC
+dsGCuY7e+0X5YxtiOzkGynd6qDwJz2w2PQ8KRUtpFhpFfTMDZflScZAmlaxMDPWL
+kz/MdXSFmLr/YnpNH4n+rr2UAJm/EaXc4HnFFgt9AmEd6oX5AhVP51qJThRv4zdL
+hfXBPGHg/QVBspJ/wx2g0K5SZGBrGMYmnNj1ZOQ2GmKfig8+/21OGVZOIJFsnzQz
+OjRXUDpvgV4GxvU+fE6OK85lBi5d0ipTdF7Tbieejw==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCB
+mDELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsT
+MChjKSAyMDA4IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s
+eTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv
+cml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIzNTk1OVowgZgxCzAJ
+BgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg
+MjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0
+BgNVBAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg
+LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz
++uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5jK/BGvESyiaHAKAxJcCGVn2TAppMSAmUm
+hsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdEc5IiaacDiGydY8hS2pgn
+5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3CIShwiP/W
+JmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exAL
+DmKudlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZC
+huOl1UcCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw
+HQYDVR0OBBYEFMR5yo6hTgMdHNxr2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IB
+AQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9cr5HqQ6XErhK8WTTOd8lNNTB
+zU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbEAp7aDHdlDkQN
+kv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD
+AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUH
+SJsMC8tJP33st/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2G
+spki4cErx5z481+oghLrGREt
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBe
+MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0
+ZC4xKjAoBgNVBAsMIWVQS0kgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe
+Fw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMxMjdaMF4xCzAJBgNVBAYTAlRXMSMw
+IQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEqMCgGA1UECwwhZVBL
+SSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAH
+SyZbCUNsIZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAh
+ijHyl3SJCRImHJ7K2RKilTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3X
+DZoTM1PRYfl61dd4s5oz9wCGzh1NlDivqOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1
+TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX12ruOzjjK9SXDrkb5wdJ
+fzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0OWQqraffA
+sgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uU
+WH1+ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLS
+nT0IFaUQAS2zMnaolQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pH
+dmX2Os+PYhcZewoozRrSgx4hxyy/vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJip
+NiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXiZo1jDiVN1Rmy5nk3pyKdVDEC
+AwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/QkqiMAwGA1UdEwQF
+MAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH
+ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGB
+uvl2ICO1J2B01GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6Yl
+PwZpVnPDimZI+ymBV3QGypzqKOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkP
+JXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdVxrsStZf0X4OFunHB2WyBEXYKCrC/
+gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEPNXubrjlpC2JgQCA2
+j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+rGNm6
+5ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUB
+o2M3IUxExJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS
+/jQ6fbjpKdx2qcgw+BRxgMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2z
+Gp1iro2C6pSe3VkQw63d4k3jMdXH7OjysP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTE
+W9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmODBCEIZ43ygknQW/2xzQ+D
+hNQ+IIX3Sj0rnP0qCglN6oH4EZw=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEXzCCA0egAwIBAgIBATANBgkqhkiG9w0BAQUFADCB0DELMAkGA1UEBhMCRVMx
+SDBGBgNVBAoTP0laRU5QRSBTLkEuIC0gQ0lGIEEtMDEzMzcyNjAtUk1lcmMuVml0
+b3JpYS1HYXN0ZWl6IFQxMDU1IEY2MiBTODFCMEAGA1UEBxM5QXZkYSBkZWwgTWVk
+aXRlcnJhbmVvIEV0b3JiaWRlYSAzIC0gMDEwMTAgVml0b3JpYS1HYXN0ZWl6MRMw
+EQYDVQQDEwpJemVucGUuY29tMR4wHAYJKoZIhvcNAQkBFg9JbmZvQGl6ZW5wZS5j
+b20wHhcNMDMwMTMwMjMwMDAwWhcNMTgwMTMwMjMwMDAwWjCB0DELMAkGA1UEBhMC
+RVMxSDBGBgNVBAoTP0laRU5QRSBTLkEuIC0gQ0lGIEEtMDEzMzcyNjAtUk1lcmMu
+Vml0b3JpYS1HYXN0ZWl6IFQxMDU1IEY2MiBTODFCMEAGA1UEBxM5QXZkYSBkZWwg
+TWVkaXRlcnJhbmVvIEV0b3JiaWRlYSAzIC0gMDEwMTAgVml0b3JpYS1HYXN0ZWl6
+MRMwEQYDVQQDEwpJemVucGUuY29tMR4wHAYJKoZIhvcNAQkBFg9JbmZvQGl6ZW5w
+ZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC1btoCXXhp3xIW
+D+Bxl8nUCxkyiazWfpt0e68t+Qt9+lZjKZSdEw2Omj4qvr+ovRmDXO3iWpWVOWDl
+3JHJjAzFCe8ZEBNDH+QNYwZHmPBaMYFOYFdbAFVHWvys152C308hcFJ6xWWGmjvl
+2eMiEl9P2nR2LWue368DCu+ak7j3gjAXaCOdP1a7Bfr+RW3X2SC5R4Xyp8iHlL5J
+PHJD/WBkLrezwzQPdACw8m9EG7q9kUwlNpL32mROujS3ZkT6mQTzJieLiE3X04s0
+uIUqVkk5MhjcHFf7al0N5CzjtTcnXYJKN2Z9EDVskk4olAdGi46eSoZXbjUOP5gk
+Ej6wVZAXAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG
+MB0GA1UdDgQWBBTqVk/sPIOhFIh4gbIrBSLAB0FbQjANBgkqhkiG9w0BAQUFAAOC
+AQEAYp7mEzzhw6o5Hf5+T5kcI+t4BJyiIWy7vHlLs/G8dLYXO81aN/Mzg928eMTR
+TxxYZL8dd9uwsJ50TVfX6L0R4Dyw6wikh3fHRrat9ufXi63j5K91Ysr7aXqnF38d
+iAgHYkrwC3kuxHBb9C0KBz6h8Q45/KCyN7d37wWAq38yyhPDlaOvyoE6bdUuK5hT
+m5EYA5JmPyrhQ1moDOyueWBAjxzMEMj+OAY1H90cLv6wszsqerxRrdTOHBdv7MjB
+EIpvEEQkXUxVXAzFuuT6m2t91Lfnwfl/IvljHaVC7DlyyhRYHD6D4Rx+4QKp4tWL
+vpw6LkI+gKNJ/YdMCsRZQzEEFA==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBi
+MQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu
+MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3Jp
+dHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMxMjM1OTU5WjBiMQswCQYDVQQGEwJV
+UzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydO
+ZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqG
+SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwz
+c7MEL7xxjOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPP
+OCwGJgl6cvf6UDL4wpPTaaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rl
+mGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXTcrA/vGp97Eh/jcOrqnErU2lBUzS1sLnF
+BgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc/Qzpf14Dl847ABSHJ3A4
+qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMBAAGjgZcw
+gZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIB
+BjAPBgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwu
+bmV0c29sc3NsLmNvbS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3Jp
+dHkuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc8
+6fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q4LqILPxFzBiwmZVRDuwduIj/
+h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/GGUsyfJj4akH
+/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv
+wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHN
+pGxlaKFJdlxDydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCB
+vTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
+ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJp
+U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MTgwNgYDVQQDEy9W
+ZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe
+Fw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJVUzEX
+MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0
+IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9y
+IGF1dGhvcml6ZWQgdXNlIG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNh
+bCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj1mCOkdeQmIN65lgZOIzF
+9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGPMiJhgsWH
+H26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+H
+LL729fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN
+/BMReYTtXlT2NJ8IAfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPT
+rJ9VAMf2CGqUuV/c4DPxhGD5WycRtPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1Ud
+EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0GCCsGAQUFBwEMBGEwX6FdoFsw
+WTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2Oa8PPgGrUSBgs
+exkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud
+DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4
+sAPmLGd75JR3Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+
+seQxIcaBlVZaDrHC1LGmWazxY8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz
+4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTxP/jgdFcrGJ2BtMQo2pSXpXDrrB2+
+BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+PwGZsY6rp2aQW9IHR
+lRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4mJO3
+7M2CYfE45k+XmCpajQ==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIECTCCAvGgAwIBAgIQDV6ZCtadt3js2AdWO4YV2TANBgkqhkiG9w0BAQUFADBb
+MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3Qx
+ETAPBgNVBAsTCERTVCBBQ0VTMRcwFQYDVQQDEw5EU1QgQUNFUyBDQSBYNjAeFw0w
+MzExMjAyMTE5NThaFw0xNzExMjAyMTE5NThaMFsxCzAJBgNVBAYTAlVTMSAwHgYD
+VQQKExdEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdDERMA8GA1UECxMIRFNUIEFDRVMx
+FzAVBgNVBAMTDkRTVCBBQ0VTIENBIFg2MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEAuT31LMmU3HWKlV1j6IR3dma5WZFcRt2SPp/5DgO0PWGSvSMmtWPu
+ktKe1jzIDZBfZIGxqAgNTNj50wUoUrQBJcWVHAx+PhCEdc/BGZFjz+iokYi5Q1K7
+gLFViYsx+tC3dr5BPTCapCIlF3PoHuLTrCq9Wzgh1SpL11V94zpVvddtawJXa+ZH
+fAjIgrrep4c9oW24MFbCswKBXy314powGCi4ZtPLAZZv6opFVdbgnf9nKxcCpk4a
+ahELfrd755jWjHZvwTvbUJN+5dCOHze4vbrGn2zpfDPyMjwmR/onJALJfh1biEIT
+ajV8fTXpLmaRcpPVMibEdPVTo7NdmvYJywIDAQABo4HIMIHFMA8GA1UdEwEB/wQF
+MAMBAf8wDgYDVR0PAQH/BAQDAgHGMB8GA1UdEQQYMBaBFHBraS1vcHNAdHJ1c3Rk
+c3QuY29tMGIGA1UdIARbMFkwVwYKYIZIAWUDAgEBATBJMEcGCCsGAQUFBwIBFjto
+dHRwOi8vd3d3LnRydXN0ZHN0LmNvbS9jZXJ0aWZpY2F0ZXMvcG9saWN5L0FDRVMt
+aW5kZXguaHRtbDAdBgNVHQ4EFgQUCXIGThhDD+XWzMNqizF7eI+og7gwDQYJKoZI
+hvcNAQEFBQADggEBAKPYjtay284F5zLNAdMEA+V25FYrnJmQ6AgwbN99Pe7lv7Uk
+QIRJ4dEorsTCOlMwiPH1d25Ryvr/ma8kXxug/fKshMrfqfBfBC6tFr8hlxCBPeP/
+h40y3JTlR4peahPJlJU90u7INJXQgNStMgiAVDzgvVJT11J8smk/f3rPanTK+gQq
+nExaBqXpIK1FZg9p8d2/6eMyi/rgwYZNcjwu2JN4Cir42NInPRmJX1p7ijvMDNpR
+rscL9yuwNwXsvFcj4jjSm2jzVhKIT0J8uDHEtdvkyCE06UgRNe76x5JXxZ805Mf2
+9w4LTJxoeHtxMcfrHuBnQfO3oKfN5XozNmr6mis=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBl
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv
+b3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQG
+EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl
+cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwggEi
+MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSA
+n61UQbVH35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4Htecc
+biJVMWWXvdMX0h5i89vqbFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9Hp
+EgjAALAcKxHad3A2m67OeYfcgnDmCXRwVWmvo2ifv922ebPynXApVfSr/5Vh88lA
+bx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OPYLfykqGxvYmJHzDNw6Yu
+YjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+RnlTGNAgMB
+AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQW
+BBTOw0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPI
+QW5pJ6d1Ee88hjZv0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I
+0jJmwYrA8y8678Dj1JGG0VDjA9tzd29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4Gni
+lmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAWhsI6yLETcDbYz+70CjTVW0z9
+B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0MjomZmWzwPDCv
+ON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo
+IhNzbM8m9Yop5w==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzES
+MBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFU
+V0NBIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMz
+WhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJVEFJV0FO
+LUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlm
+aWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
+AQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFE
+AcK0HMMxQhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HH
+K3XLfJ+utdGdIzdjp9xCoi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeX
+RfwZVzsrb+RH9JlF/h3x+JejiB03HFyP4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/z
+rX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1ry+UPizgN7gr8/g+YnzAx
+3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
+HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkq
+hkiG9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeC
+MErJk/9q56YAf4lCmtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdls
+XebQ79NqZp4VKIV66IIArB6nCWlWQtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62D
+lhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVYT0bf+215WfKEIlKuD8z7fDvn
+aspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocnyYh0igzyXxfkZ
+YiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIE5zCCA8+gAwIBAgIBADANBgkqhkiG9w0BAQUFADCBjTELMAkGA1UEBhMCQ0Ex
+EDAOBgNVBAgTB09udGFyaW8xEDAOBgNVBAcTB1Rvcm9udG8xHTAbBgNVBAoTFEVj
+aG93b3J4IENvcnBvcmF0aW9uMR8wHQYDVQQLExZDZXJ0aWZpY2F0aW9uIFNlcnZp
+Y2VzMRowGAYDVQQDExFFY2hvd29yeCBSb290IENBMjAeFw0wNTEwMDYxMDQ5MTNa
+Fw0zMDEwMDcxMDQ5MTNaMIGNMQswCQYDVQQGEwJDQTEQMA4GA1UECBMHT250YXJp
+bzEQMA4GA1UEBxMHVG9yb250bzEdMBsGA1UEChMURWNob3dvcnggQ29ycG9yYXRp
+b24xHzAdBgNVBAsTFkNlcnRpZmljYXRpb24gU2VydmljZXMxGjAYBgNVBAMTEUVj
+aG93b3J4IFJvb3QgQ0EyMIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKCAQEA
+utU/5BkV15UBf+s+JQruKQxr77s3rjp/RpOtmhHILIiO5gsEWP8MMrfrVEiidjI6
+Qh6ans0KAWc2Dw0/j4qKAQzOSyAZgjcdypNTBZ7muv212DA2Pu41rXqwMrlBrVi/
+KTghfdLlNRu6JrC5y8HarrnRFSKF1Thbzz921kLDRoCi+FVs5eVuK5LvIfkhNAqA
+byrTgO3T9zfZgk8upmEkANPDL1+8y7dGPB/d6lk0I5mv8PESKX02TlvwgRSIiTHR
+k8++iOPLBWlGp7ZfqTEXkPUZhgrQQvxcrwCUo6mk8TqgxCDP5FgPoHFiPLef5szP
+ZLBJDWp7GLyE1PmkQI6WiwIBA6OCAVAwggFMMA8GA1UdEwEB/wQFMAMBAf8wCwYD
+VR0PBAQDAgEGMB0GA1UdDgQWBBQ74YEboKs/OyGC1eISrq5QqxSlEzCBugYDVR0j
+BIGyMIGvgBQ74YEboKs/OyGC1eISrq5QqxSlE6GBk6SBkDCBjTELMAkGA1UEBhMC
+Q0ExEDAOBgNVBAgTB09udGFyaW8xEDAOBgNVBAcTB1Rvcm9udG8xHTAbBgNVBAoT
+FEVjaG93b3J4IENvcnBvcmF0aW9uMR8wHQYDVQQLExZDZXJ0aWZpY2F0aW9uIFNl
+cnZpY2VzMRowGAYDVQQDExFFY2hvd29yeCBSb290IENBMoIBADBQBgNVHSAESTBH
+MEUGCysGAQQB+REKAQMBMDYwNAYIKwYBBQUHAgEWKGh0dHA6Ly93d3cuZWNob3dv
+cnguY29tL2NhL3Jvb3QyL2Nwcy5wZGYwDQYJKoZIhvcNAQEFBQADggEBAG+nrPi/
+0RpfEzrj02C6JGPUar4nbjIhcY6N7DWNeqBoUulBSIH/PYGNHYx7/lnJefiixPGE
+7TQ5xPgElxb9bK8zoAApO7U33OubqZ7M7DlHnFeCoOoIAZnG1kuwKwD5CXKB2a74
+HzcqNnFW0IsBFCYqrVh/rQgJOzDA8POGbH0DeD0xjwBBooAolkKT+7ZItJF1Pb56
+QpDL9G+16F7GkmnKlAIYT3QTS3yFGYChnJcd+6txUPhKi9sSOOmAIaKHnkH9Scz+
+A2cSi4A3wUYXVatuVNHpRb2lygfH3SuCX9MU8Ure3zBlSU1LALtMqI4JmcQmQpIq
+zIzvO2jHyu9PQqo=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEqjCCA5KgAwIBAgIOLmoAAQACH9dSISwRXDswDQYJKoZIhvcNAQEFBQAwdjEL
+MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNV
+BAsTGVRDIFRydXN0Q2VudGVyIENsYXNzIDIgQ0ExJTAjBgNVBAMTHFRDIFRydXN0
+Q2VudGVyIENsYXNzIDIgQ0EgSUkwHhcNMDYwMTEyMTQzODQzWhcNMjUxMjMxMjI1
+OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIgR21i
+SDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQTElMCMGA1UEAxMc
+VEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMiBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBAKuAh5uO8MN8h9foJIIRszzdQ2Lu+MNF2ujhoF/RKrLqk2jf
+tMjWQ+nEdVl//OEd+DFwIxuInie5e/060smp6RQvkL4DUsFJzfb95AhmC1eKokKg
+uNV/aVyQMrKXDcpK3EY+AlWJU+MaWss2xgdW94zPEfRMuzBwBJWl9jmM/XOBCH2J
+XjIeIqkiRUuwZi4wzJ9l/fzLganx4Duvo4bRierERXlQXa7pIXSSTYtZgo+U4+lK
+8edJsBTj9WLL1XK9H7nSn6DNqPoByNkN39r8R52zyFTfSUrxIan+GE7uSNQZu+99
+5OKdy1u2bv/jzVrndIIFuoAlOMvkaZ6vQaoahPUCAwEAAaOCATQwggEwMA8GA1Ud
+EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTjq1RMgKHbVkO3
+kUrL84J6E1wIqzCB7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRy
+dXN0Y2VudGVyLmRlL2NybC92Mi90Y19jbGFzc18yX2NhX0lJLmNybIaBn2xkYXA6
+Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBUcnVzdENlbnRlciUyMENsYXNz
+JTIwMiUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21iSCxPVT1yb290
+Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u
+TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEAjNfffu4bgBCzg/XbEeprS6iS
+GNn3Bzn1LL4GdXpoUxUc6krtXvwjshOg0wn/9vYua0Fxec3ibf2uWWuFHbhOIprt
+ZjluS5TmVfwLG4t3wVMTZonZKNaL80VKY7f9ewthXbhtvsPcW3nS7Yblok2+XnR8
+au0WOB9/WIFaGusyiC2y8zl3gK9etmF1KdsjTYjKUCjLhdLTEKJZbtOTVAB6okaV
+hgWcqRmY5TFyDADiZ9lA4CQze28suVyrZZ0srHbqNZn1l7kPJOzHdiEoZa5X6AeI
+dUpWoNIFOqTmjZKILPPy4cHGYdtBxceb9w4aUUXCYWvcZCcXjFq32nQozZfkvQ==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCB
+gjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEk
+MCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRY
+UmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQxMTAxMTcx
+NDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3
+dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2Vy
+dmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB
+dXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS6
+38eMpSe2OAtp87ZOqCwuIR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCP
+KZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMxfoArtYzAQDsRhtDLooY2YKTVMIJt2W7Q
+DxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FEzG+gSqmUsE3a56k0enI4
+qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqsAxcZZPRa
+JSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNVi
+PvryxS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0P
+BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASs
+jVy16bYbMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0
+eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQEwDQYJKoZIhvcNAQEFBQAD
+ggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc/Kh4ZzXxHfAR
+vbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt
+qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLa
+IR9NmXmd4c8nnxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSy
+i6mx5O+aGtA9aZnuqCij4Tyz8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQ
+O+7ETPTsJ3xCwnR8gooJybQDJbw=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDOzCCAiOgAwIBAgIRANAeRlAAACmMAAAAAgAAAAIwDQYJKoZIhvcNAQEFBQAw
+PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD
+Ew5EU1QgUm9vdCBDQSBYNDAeFw0wMDA5MTMwNjIyNTBaFw0yMDA5MTMwNjIyNTBa
+MD8xJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0dXJlIFRydXN0IENvLjEXMBUGA1UE
+AxMORFNUIFJvb3QgQ0EgWDQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
+AQCthX3OFEYY8gSeIYur0O4ypOT68HnDrjLfIutL5PZHRwQGjzCPb9PFo/ihboJ8
+RvfGhBAqpQCo47zwYEhpWm1jB+L/OE/dBBiyn98krfU2NiBKSom2J58RBeAwHGEy
+cO+lewyjVvbDDLUy4CheY059vfMjPAftCRXjqSZIolQb9FdPcAoa90mFwB7rKniE
+J7vppdrUScSS0+eBrHSUPLdvwyn4RGp+lSwbWYcbg5EpSpE0GRJdchic0YDjvIoC
+YHpe7Rkj93PYRTQyU4bhC88ck8tMqbvRYqMRqR+vobbkrj5LLCOQCHV5WEoxWh+0
+E2SpIFe7RkV++MmpIAc0h1tZAgMBAAGjMjAwMA8GA1UdEwEB/wQFMAMBAf8wHQYD
+VR0OBBYEFPCD6nPIP1ubWzdf9UyPWvf0hki9MA0GCSqGSIb3DQEBBQUAA4IBAQCE
+G85wl5eEWd7adH6XW/ikGN5salvpq/Fix6yVTzE6CrhlP5LBdkf6kx1bSPL18M45
+g0rw2zA/MWOhJ3+S6U+BE0zPGCuu8YQaZibR7snm3HiHUaZNMu5c8D0x0bcMxDjY
+AVVcHCoNiL53Q4PLW27nbY6wwG0ffFKmgV3blxrYWfuUDgGpyPwHwkfVFvz9qjaV
+mf12VJffL6W8omBPtgteb6UaT/k1oJ7YI0ldGf+ngpVbRhD+LC3cUtT6GO/BEPZu
+8YTV/hbiDH5v3khVqMIeKT6o8IuXGG7F6a6vKwP1F1FwTXf4UC/ivhme7vdUH7B/
+Vv4AEbT8dNfEeFxrkDbh
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEQzCCAyugAwIBAgIBATANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJHQjEb
+MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow
+GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDElMCMGA1UEAwwcVHJ1c3RlZCBDZXJ0
+aWZpY2F0ZSBTZXJ2aWNlczAeFw0wNDAxMDEwMDAwMDBaFw0yODEyMzEyMzU5NTla
+MH8xCzAJBgNVBAYTAkdCMRswGQYDVQQIDBJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO
+BgNVBAcMB1NhbGZvcmQxGjAYBgNVBAoMEUNvbW9kbyBDQSBMaW1pdGVkMSUwIwYD
+VQQDDBxUcnVzdGVkIENlcnRpZmljYXRlIFNlcnZpY2VzMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEA33FvNlhTWvI2VFeAxHQIIO0Yfyod5jWaHiWsnOWW
+fnJSoBVC21ndZHoa0Lh73TkVvFVIxO06AOoxEbrycXQaZ7jPM8yoMa+j49d/vzMt
+TGo87IvDktJTdyR0nAducPy9C1t2ul/y/9c3S0pgePfw+spwtOpZqqPOSC+pw7IL
+fhdyFgymBwwbOM/JYrc/oJOlh0Hyt3BAd9i+FHzjqMB6juljatEPmsbS9Is6FARW
+1O24zG71++IsWL1/T2sr92AkWCTOJu80kTrV44HQsvAEAtdbtz6SrGsSivnkBbA7
+kUlcsutT6vifR4buv5XAwAaf0lteERv0xwQ1KdJVXOTt6wIDAQABo4HJMIHGMB0G
+A1UdDgQWBBTFe1i97doladL3WRaoszLAeydb9DAOBgNVHQ8BAf8EBAMCAQYwDwYD
+VR0TAQH/BAUwAwEB/zCBgwYDVR0fBHwwejA8oDqgOIY2aHR0cDovL2NybC5jb21v
+ZG9jYS5jb20vVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMuY3JsMDqgOKA2hjRo
+dHRwOi8vY3JsLmNvbW9kby5uZXQvVHJ1c3RlZENlcnRpZmljYXRlU2VydmljZXMu
+Y3JsMA0GCSqGSIb3DQEBBQUAA4IBAQDIk4E7ibSvuIQSTI3S8NtwuleGFTQQuS9/
+HrCoiWChisJ3DFBKmwCL2Iv0QeLQg4pKHBQGsKNoBXAxMKdTmw7pSqBYaWcOrp32
+pSxBvzwGa+RZzG0Q8ZZvH9/0BAKkn0U+yNj6NkZEUD+Cl5EfKNsYEYwq5GWDVxIS
+jBc/lDb+XbDABHcTuPQV1T84zJQ6VdCsmPW6AF/ghhmBeC8owH7TzEIK9a5QoNE+
+xqFx7D+gIIxmOom0jtTYsU0lR+4viMi14QVFwL4Ucd56/Y57fU0IlqUSc/Atyjcn
+dBInTMu2l+nZrghtWjlA3QVHdWpaIbOjGM9O9y5Xt5hwXsjEeLBi
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBK
+MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x
+GTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkx
+MjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3Qg
+Q29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwggEiMA0GCSqG
+SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jxYDiJ
+iQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa
+/FHtaMbQbqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJ
+jnIFHovdRIWCQtBJwB1g8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnI
+HmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYVHDGA76oYa8J719rO+TMg1fW9ajMtgQT7
+sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi0XPnj3pDAgMBAAGjgZ0w
+gZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQF
+MAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCsw
+KaAnoCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsG
+AQQBgjcVAQQDAgEAMA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0L
+URYD7xh8yOOvaliTFGCRsoTciE6+OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXO
+H0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cnCDpOGR86p1hcF895P4vkp9Mm
+I50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/53CYNv6ZHdAbY
+iNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc
+f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIID+TCCAuGgAwIBAgIQW1fXqEywr9nTb0ugMbTW4jANBgkqhkiG9w0BAQUFADB5
+MQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRl
+cm5hdGlvbmFsIFNlcnZpY2UgQXNzb2NpYXRpb24xKjAoBgNVBAMTIVZpc2EgSW5m
+b3JtYXRpb24gRGVsaXZlcnkgUm9vdCBDQTAeFw0wNTA2MjcxNzQyNDJaFw0yNTA2
+MjkxNzQyNDJaMHkxCzAJBgNVBAYTAlVTMQ0wCwYDVQQKEwRWSVNBMS8wLQYDVQQL
+EyZWaXNhIEludGVybmF0aW9uYWwgU2VydmljZSBBc3NvY2lhdGlvbjEqMCgGA1UE
+AxMhVmlzYSBJbmZvcm1hdGlvbiBEZWxpdmVyeSBSb290IENBMIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyREA4R/QkkfpLx0cYjga/EhIPZpchH0MZsRZ
+FfP6C2ITtf/Wc+MtgD4yTK0yoiXvni3d+aCtEgK3GDvkdgYrgF76ROJFZwUQjQ9l
+x42gRT05DbXvWFoy7dTglCZ9z/Tt2Cnktv9oxKgmkeHY/CyfpCBg1S8xth2JlGMR
+0ug/GMO5zANuegZOv438p5Lt5So+du2Gl+RMFQqEPwqN5uJSqAe0VtmB4gWdQ8on
+Bj2ZAM2R73QW7UW0Igt2vA4JaSiNtaAG/Y/58VXWHGgbq7rDtNK1R30X0kJV0rGA
+ib3RSwB3LpG7bOjbIucV5mQgJoVjoA1e05w6g1x/KmNTmOGRVwIDAQABo30wezAP
+BgNVHRMBAf8EBTADAQH/MDkGA1UdIAQyMDAwLgYFZ4EDAgEwJTAVBggrBgEFBQcC
+ARYJMS4yLjMuNC41MAwGCCsGAQUFBwICMAAwDgYDVR0PAQH/BAQDAgEGMB0GA1Ud
+DgQWBBRPitp2/2d3I5qmgH1924h1hfeBejANBgkqhkiG9w0BAQUFAAOCAQEACUW1
+QdUHdDJydgDPmYt+telnG/Su+DPaf1cregzlN43bJaJosMP7NwjoJY/H2He4XLWb
+5rXEkl+xH1UyUwF7mtaUoxbGxEvt8hPZSTB4da2mzXgwKvXuHyzF5Qjy1hOB0/pS
+WaF9ARpVKJJ7TOJQdGKBsF2Ty4fSCLqZLgfxbqwMsd9sysXI3rDXjIhekqvbgeLz
+PqZr+pfgFhwCCLSMQWl5Ll3u7Qk9wR094DZ6jj6+JCVCRUS3HyabH4OlM0Vc2K+j
+INsF/64Or7GNtRf9HYEJvrPxHINxl3JVwhYj4ASeaO4KwhVbwtw94Tc/XrGcexDo
+c5lC3rAi4/UZqweYCw==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx
+EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT
+HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs
+ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5
+MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYD
+VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy
+ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2Vy
+dmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20p
+OsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm2
+8xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1K
+Ts9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufe
+hRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk
+6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAw
+DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+q
+AdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMI
+bw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXB
+ve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1z
+qwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd
+iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn
+0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN
+sSi6
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl
+MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp
+U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw
+NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE
+ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp
+ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3
+DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf
+8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN
++lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0
+X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa
+K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA
+1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G
+A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR
+zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0
+YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD
+bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w
+DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3
+L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D
+eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl
+xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp
+VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY
+WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEqjCCA5KgAwIBAgIOSkcAAQAC5aBd1j8AUb8wDQYJKoZIhvcNAQEFBQAwdjEL
+MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxIjAgBgNV
+BAsTGVRDIFRydXN0Q2VudGVyIENsYXNzIDMgQ0ExJTAjBgNVBAMTHFRDIFRydXN0
+Q2VudGVyIENsYXNzIDMgQ0EgSUkwHhcNMDYwMTEyMTQ0MTU3WhcNMjUxMjMxMjI1
+OTU5WjB2MQswCQYDVQQGEwJERTEcMBoGA1UEChMTVEMgVHJ1c3RDZW50ZXIgR21i
+SDEiMCAGA1UECxMZVEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQTElMCMGA1UEAxMc
+VEMgVHJ1c3RDZW50ZXIgQ2xhc3MgMyBDQSBJSTCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBALTgu1G7OVyLBMVMeRwjhjEQY0NVJz/GRcekPewJDRoeIMJW
+Ht4bNwcwIi9v8Qbxq63WyKthoy9DxLCyLfzDlml7forkzMA5EpBCYMnMNWju2l+Q
+Vl/NHE1bWEnrDgFPZPosPIlY2C8u4rBo6SI7dYnWRBpl8huXJh0obazovVkdKyT2
+1oQDZogkAHhg8fir/gKya/si+zXmFtGt9i4S5Po1auUZuV3bOx4a+9P/FRQI2Alq
+ukWdFHlgfa9Aigdzs5OW03Q0jTo3Kd5c7PXuLjHCINy+8U9/I1LZW+Jk2ZyqBwi1
+Rb3R0DHBq1SfqdLDYmAD8bs5SpJKPQq5ncWg/jcCAwEAAaOCATQwggEwMA8GA1Ud
+EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTUovyfs8PYA9NX
+XAek0CSnwPIA1DCB7QYDVR0fBIHlMIHiMIHfoIHcoIHZhjVodHRwOi8vd3d3LnRy
+dXN0Y2VudGVyLmRlL2NybC92Mi90Y19jbGFzc18zX2NhX0lJLmNybIaBn2xkYXA6
+Ly93d3cudHJ1c3RjZW50ZXIuZGUvQ049VEMlMjBUcnVzdENlbnRlciUyMENsYXNz
+JTIwMyUyMENBJTIwSUksTz1UQyUyMFRydXN0Q2VudGVyJTIwR21iSCxPVT1yb290
+Y2VydHMsREM9dHJ1c3RjZW50ZXIsREM9ZGU/Y2VydGlmaWNhdGVSZXZvY2F0aW9u
+TGlzdD9iYXNlPzANBgkqhkiG9w0BAQUFAAOCAQEANmDkcPcGIEPZIxpC8vijsrlN
+irTzwppVMXzEO2eatN9NDoqTSheLG43KieHPOh6sHfGcMrSOWXaiQYUlN6AT0PV8
+TtXqluJucsG7Kv5sbviRmEb8yRtXW+rIGjs/sFGYPAfaLFkB2otE6OF0/ado3VS6
+g0bsyEa1+K+XwDsJHI/OcpY9M1ZwvJbL2NV9IJqDnxrcOfHFcqMRA/07QlIp2+gB
+95tejNaNhk4Z+rwcvsUhpYeeeC422wlxo3I0+GzjBgnyXlal092Y+tTmBvTwtiBj
+S+opvaqCZh77gaqnN60TGOaSw4HBM7uIHqHn4rS9MWwOUT1v+5ZWgOI2F9Hc5A==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBY
+MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMo
+R2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEx
+MjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgxCzAJBgNVBAYTAlVTMRYwFAYDVQQK
+Ew1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQcmltYXJ5IENlcnRp
+ZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9
+AWbK7hWNb6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjA
+ZIVcFU2Ix7e64HXprQU9nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE0
+7e9GceBrAqg1cmuXm2bgyxx5X9gaBGgeRwLmnWDiNpcB3841kt++Z8dtd1k7j53W
+kBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGttm/81w7a4DSwDRp35+MI
+mO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G
+A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJ
+KoZIhvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ1
+6CePbJC/kRYkRj5KTs4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl
+4b7UVXGYNTq+k+qurUKykG/g/CFNNWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6K
+oKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHaFloxt/m0cYASSJlyc1pZU8Fj
+UjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG1riR/aYNKxoU
+AT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UE
+BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWdu
+IFNpbHZlciBDQSAtIEcyMB4XDTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0Nlow
+RzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMY
+U3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
+MIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644N0Mv
+Fz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7br
+YT7QbNHm+/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieF
+nbAVlDLaYQ1HTWBCrpJH6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH
+6ATK72oxh9TAtvmUcXtnZLi2kUpCe2UuMGoM9ZDulebyzYLs2aFK7PayS+VFheZt
+eJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5hqAaEuSh6XzjZG6k4sIN/
+c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5FZGkECwJ
+MoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRH
+HTBsROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTf
+jNFusB3hB48IHpmccelM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb6
+5i/4z3GcRm25xBWNOHkDRUjvxF3XCO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOB
+rDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU
+F6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRBtjpbO8tFnb0c
+wpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0
+cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIB
+AHPGgeAn0i0P4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShp
+WJHckRE1qTodvBqlYJ7YH39FkWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9
+xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L3XWgwF15kIwb4FDm3jH+mHtwX6WQ
+2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx/uNncqCxv1yL5PqZ
+IseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFaDGi8
+aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2X
+em1ZqSqPe97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQR
+dAtq/gsD/KNVV4n+SsuuWxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/
+OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJDIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+
+hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ubDgEj8Z+7fNzcbBGXJbLy
+tGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEAzCCAuugAwIBAgIQVID5oHPtPwBMyonY43HmSjANBgkqhkiG9w0BAQUFADB1
+MQswCQYDVQQGEwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1
+czEoMCYGA1UEAwwfRUUgQ2VydGlmaWNhdGlvbiBDZW50cmUgUm9vdCBDQTEYMBYG
+CSqGSIb3DQEJARYJcGtpQHNrLmVlMCIYDzIwMTAxMDMwMTAxMDMwWhgPMjAzMDEy
+MTcyMzU5NTlaMHUxCzAJBgNVBAYTAkVFMSIwIAYDVQQKDBlBUyBTZXJ0aWZpdHNl
+ZXJpbWlza2Vza3VzMSgwJgYDVQQDDB9FRSBDZXJ0aWZpY2F0aW9uIENlbnRyZSBS
+b290IENBMRgwFgYJKoZIhvcNAQkBFglwa2lAc2suZWUwggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQDIIMDs4MVLqwd4lfNE7vsLDP90jmG7sWLqI9iroWUy
+euuOF0+W2Ap7kaJjbMeMTC55v6kF/GlclY1i+blw7cNRfdCT5mzrMEvhvH2/UpvO
+bntl8jixwKIy72KyaOBhU8E2lf/slLo2rpwcpzIP5Xy0xm90/XsY6KxX7QYgSzIw
+WFv9zajmofxwvI6Sc9uXp3whrj3B9UiHbCe9nyV0gVWw93X2PaRka9ZP585ArQ/d
+MtO8ihJTmMmJ+xAdTX7Nfh9WDSFwhfYggx/2uh8Ej+p3iDXE/+pOoYtNP2MbRMNE
+1CV2yreN1x5KZmTNXMWcg+HCCIia7E6j8T4cLNlsHaFLAgMBAAGjgYowgYcwDwYD
+VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBLyWj7qVhy/
+zQas8fElyalL1BSZMEUGA1UdJQQ+MDwGCCsGAQUFBwMCBggrBgEFBQcDAQYIKwYB
+BQUHAwMGCCsGAQUFBwMEBggrBgEFBQcDCAYIKwYBBQUHAwkwDQYJKoZIhvcNAQEF
+BQADggEBAHv25MANqhlHt01Xo/6tu7Fq1Q+e2+RjxY6hUFaTlrg4wCQiZrxTFGGV
+v9DHKpY5P30osxBAIWrEr7BSdxjhlthWXePdNl4dp1BUoMUq5KqMlIpPnTX/dqQG
+E5Gion0ARD9V04I8GtVbvFZMIi5GQ4okQC3zErg7cBqklrkar4dBGmoYDQZPxz5u
+uSlNDUmJEYcyW+ZLBMjkXOZ0c5RdFpgTlf7727FE5TpwrDdr5rMzcijJs1eg9gIW
+iAYLtqZLICjU3j2LrTcFU3T+bsy8QxdxXvnFzBqpYe73dgzzcvRyrc9yAjYHR8/v
+GVCJYMzpJJUPwssd8m92kMfMdcGWxZ0=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB
+yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
+ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp
+U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW
+ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0
+aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL
+MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW
+ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln
+biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp
+U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y
+aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1
+nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex
+t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz
+SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG
+BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+
+rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/
+NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E
+BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH
+BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy
+aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv
+MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE
+p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y
+5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK
+WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ
+4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N
+hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDoDCCAoigAwIBAgIBMTANBgkqhkiG9w0BAQUFADBDMQswCQYDVQQGEwJKUDEc
+MBoGA1UEChMTSmFwYW5lc2UgR292ZXJubWVudDEWMBQGA1UECxMNQXBwbGljYXRp
+b25DQTAeFw0wNzEyMTIxNTAwMDBaFw0xNzEyMTIxNTAwMDBaMEMxCzAJBgNVBAYT
+AkpQMRwwGgYDVQQKExNKYXBhbmVzZSBHb3Zlcm5tZW50MRYwFAYDVQQLEw1BcHBs
+aWNhdGlvbkNBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp23gdE6H
+j6UG3mii24aZS2QNcfAKBZuOquHMLtJqO8F6tJdhjYq+xpqcBrSGUeQ3DnR4fl+K
+f5Sk10cI/VBaVuRorChzoHvpfxiSQE8tnfWuREhzNgaeZCw7NCPbXCbkcXmP1G55
+IrmTwcrNwVbtiGrXoDkhBFcsovW8R0FPXjQilbUfKW1eSvNNcr5BViCH/OlQR9cw
+FO5cjFW6WY2H/CPek9AEjP3vbb3QesmlOmpyM8ZKDQUXKi17safY1vC+9D/qDiht
+QWEjdnjDuGWk81quzMKq2edY3rZ+nYVunyoKb58DKTCXKB28t89UKU5RMfkntigm
+/qJj5kEW8DOYRwIDAQABo4GeMIGbMB0GA1UdDgQWBBRUWssmP3HMlEYNllPqa0jQ
+k/5CdTAOBgNVHQ8BAf8EBAMCAQYwWQYDVR0RBFIwUKROMEwxCzAJBgNVBAYTAkpQ
+MRgwFgYDVQQKDA/ml6XmnKzlm73mlL/lupwxIzAhBgNVBAsMGuOCouODl+ODquOC
+seODvOOCt+ODp+ODs0NBMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD
+ggEBADlqRHZ3ODrso2dGD/mLBqj7apAxzn7s2tGJfHrrLgy9mTLnsCTWw//1sogJ
+hyzjVOGjprIIC8CFqMjSnHH2HZ9g/DgzE+Ge3Atf2hZQKXsvcJEPmbo0NI2VdMV+
+eKlmXb3KIXdCEKxmJj3ekav9FfBv7WxfEPjzFvYDio+nEhEMy/0/ecGc/WLuo89U
+DNErXxc+4z6/wCs+CZv+iKZ+tJIX/COUgb1up8WMwusRRdv4QcmWdupwX3kSa+Sj
+B1oF7ydJzyGfikwJcGapJsErEU4z0g781mzSDjJkaP+tBXhfAx2o45CsJOAPQKdL
+rosot4LKGAfmt1t06SAZf7IbiVQ=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDIDCCAgigAwIBAgIBJDANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEP
+MA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MxIENBMB4XDTAx
+MDQwNjEwNDkxM1oXDTIxMDQwNjEwNDkxM1owOTELMAkGA1UEBhMCRkkxDzANBgNV
+BAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMSBDQTCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBALWJHytPZwp5/8Ue+H887dF+2rDNbS82rDTG
+29lkFwhjMDMiikzujrsPDUJVyZ0upe/3p4zDq7mXy47vPxVnqIJyY1MPQYx9EJUk
+oVqlBvqSV536pQHydekfvFYmUk54GWVYVQNYwBSujHxVX3BbdyMGNpfzJLWaRpXk
+3w0LBUXl0fIdgrvGE+D+qnr9aTCU89JFhfzyMlsy3uhsXR/LpCJ0sICOXZT3BgBL
+qdReLjVQCfOAl/QMF6452F/NM8EcyonCIvdFEu1eEpOdY6uCLrnrQkFEy0oaAIIN
+nvmLVz5MxxftLItyM19yejhW1ebZrgUaHXVFsculJRwSVzb9IjcCAwEAAaMzMDEw
+DwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQIR+IMi/ZTiFIwCwYDVR0PBAQDAgEG
+MA0GCSqGSIb3DQEBBQUAA4IBAQCLGrLJXWG04bkruVPRsoWdd44W7hE928Jj2VuX
+ZfsSZ9gqXLar5V7DtxYvyOirHYr9qxp81V9jz9yw3Xe5qObSIjiHBxTZ/75Wtf0H
+DjxVyhbMp6Z3N/vbXB9OWQaHowND9Rart4S9Tu+fMTfwRvFAttEMpWT4Y14h21VO
+TzF2nBBhjrZTOqMRvq9tfB69ri3iDGnHhVNoomG6xT60eVR4ngrHAr5i0RGCS2Uv
+kVrCqIexVmiUefkl98HVrhq4uz2PqYo4Ffdz0Fpg0YCw8NzVUM1O7pJIae2yIx4w
+zMiUyLb1O4Z/P6Yun/Y+LLWSlj7fLJOK/4GMDw9ZIRlXvVWa
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/
+MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
+DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow
+PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD
+Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O
+rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq
+OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b
+xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw
+7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD
+aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV
+HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG
+SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69
+ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr
+AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz
+R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5
+JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo
+Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFGTCCBAGgAwIBAgIEPki9xDANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQGEwJE
+SzEMMAoGA1UEChMDVERDMRQwEgYDVQQDEwtUREMgT0NFUyBDQTAeFw0wMzAyMTEw
+ODM5MzBaFw0zNzAyMTEwOTA5MzBaMDExCzAJBgNVBAYTAkRLMQwwCgYDVQQKEwNU
+REMxFDASBgNVBAMTC1REQyBPQ0VTIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEArGL2YSCyz8DGhdfjeebM7fI5kqSXLmSjhFuHnEz9pPPEXyG9VhDr
+2y5h7JNp46PMvZnDBfwGuMo2HP6QjklMxFaaL1a8z3sM8W9Hpg1DTeLpHTk0zY0s
+2RKY+ePhwUp8hjjEqcRhiNJerxomTdXkoCJHhNlktxmW/OwZ5LKXJk5KTMuPJItU
+GBxIYXvViGjaXbXqzRowwYCDdlCqT9HU3Tjw7xb04QxQBr/q+3pJoSgrHPb8FTKj
+dGqPqcNiKXEx5TukYBdedObaE+3pHx8b0bJoc8YQNHVGEBDjkAB2QMuLt0MJIf+r
+TpPGWOmlgtt3xDqZsXKVSQTwtyv6e1mO3QIDAQABo4ICNzCCAjMwDwYDVR0TAQH/
+BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwgewGA1UdIASB5DCB4TCB3gYIKoFQgSkB
+AQEwgdEwLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuY2VydGlmaWthdC5kay9yZXBv
+c2l0b3J5MIGdBggrBgEFBQcCAjCBkDAKFgNUREMwAwIBARqBgUNlcnRpZmlrYXRl
+ciBmcmEgZGVubmUgQ0EgdWRzdGVkZXMgdW5kZXIgT0lEIDEuMi4yMDguMTY5LjEu
+MS4xLiBDZXJ0aWZpY2F0ZXMgZnJvbSB0aGlzIENBIGFyZSBpc3N1ZWQgdW5kZXIg
+T0lEIDEuMi4yMDguMTY5LjEuMS4xLjARBglghkgBhvhCAQEEBAMCAAcwgYEGA1Ud
+HwR6MHgwSKBGoESkQjBAMQswCQYDVQQGEwJESzEMMAoGA1UEChMDVERDMRQwEgYD
+VQQDEwtUREMgT0NFUyBDQTENMAsGA1UEAxMEQ1JMMTAsoCqgKIYmaHR0cDovL2Ny
+bC5vY2VzLmNlcnRpZmlrYXQuZGsvb2Nlcy5jcmwwKwYDVR0QBCQwIoAPMjAwMzAy
+MTEwODM5MzBagQ8yMDM3MDIxMTA5MDkzMFowHwYDVR0jBBgwFoAUYLWF7FZkfhIZ
+J2cdUBVLc647+RIwHQYDVR0OBBYEFGC1hexWZH4SGSdnHVAVS3OuO/kSMB0GCSqG
+SIb2fQdBAAQQMA4bCFY2LjA6NC4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEACrom
+JkbTc6gJ82sLMJn9iuFXehHTuJTXCRBuo7E4A9G28kNBKWKnctj7fAXmMXAnVBhO
+inxO5dHKjHiIzxvTkIvmI/gLDjNDfZziChmPyQE+dF10yYscA+UYyAFMP8uXBV2Y
+caaYb7Z8vTd/vuGTJW1v8AqtFxjhA7wHKcitJuj4YfD9IQl+mo6paH1IYnK9AOoB
+mbgGglGBTvH1tJFUuSN6AJqfXY3gPGS5GhKSKseCRHI53OI8xthV9RVOyAUO28bQ
+YqbsFbS1AoLbrIyigfCbmTH1ICCoiGEKB5+U/NDXG8wuF/MEJ3Zn61SD/aSQfgY9
+BKNDLdr8C2LqL19iUw==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDYTCCAkmgAwIBAgIQCgEBAQAAAnwAAAAKAAAAAjANBgkqhkiG9w0BAQUFADA6
+MRkwFwYDVQQKExBSU0EgU2VjdXJpdHkgSW5jMR0wGwYDVQQLExRSU0EgU2VjdXJp
+dHkgMjA0OCBWMzAeFw0wMTAyMjIyMDM5MjNaFw0yNjAyMjIyMDM5MjNaMDoxGTAX
+BgNVBAoTEFJTQSBTZWN1cml0eSBJbmMxHTAbBgNVBAsTFFJTQSBTZWN1cml0eSAy
+MDQ4IFYzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAt49VcdKA3Xtp
+eafwGFAyPGJn9gqVB93mG/Oe2dJBVGutn3y+Gc37RqtBaB4Y6lXIL5F4iSj7Jylg
+/9+PjDvJSZu1pJTOAeo+tWN7fyb9Gd3AIb2E0S1PRsNO3Ng3OTsor8udGuorryGl
+wSMiuLgbWhOHV4PR8CDn6E8jQrAApX2J6elhc5SYcSa8LWrg903w8bYqODGBDSnh
+AMFRD0xS+ARaqn1y07iHKrtjEAMqs6FPDVpeRrc9DvV07Jmf+T0kgYim3WBU6JU2
+PcYJk5qjEoAAVZkZR73QpXzDuvsf9/UP+Ky5tfQ3mBMY3oVbtwyCO4dvlTlYMNpu
+AWgXIszACwIDAQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB
+BjAfBgNVHSMEGDAWgBQHw1EwpKrpRa41JPr/JCwz0LGdjDAdBgNVHQ4EFgQUB8NR
+MKSq6UWuNST6/yQsM9CxnYwwDQYJKoZIhvcNAQEFBQADggEBAF8+hnZuuDU8TjYc
+HnmYv/3VEhF5Ug7uMYm83X/50cYVIeiKAVQNOvtUudZj1LGqlk2iQk3UUx+LEN5/
+Zb5gEydxiKRz44Rj0aRV4VCT5hsOedBnvEbIvz8XDZXmxpBp3ue0L96VfdASPz0+
+f00/FGj1EVDVwfSQpQgdMWD/YIwjVAqv/qFuxdF6Kmh4zx6CCiC0H63lhbJqaHVO
+rSU3lIW+vaHU6rcMSzyd6BIA8F+sDeGscGNz9395nzIlQnQFgCi/vcEkllgVsRch
+6YlL2weIZ/QVrXA+L02FO8K32/6YaCOJ4XQP3vTFhGMpG8zLB8kApKnXwiJPZ9d3
+7CAFYd4=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UE
+BhMCRVMxQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h
+cHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEy
+MzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIwQAYDVQQDDDlBdXRvcmlkYWQgZGUg
+Q2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBBNjI2MzQwNjgwggIi
+MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDDUtd9
+thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQM
+cas9UX4PB99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefG
+L9ItWY16Ck6WaVICqjaY7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15i
+NA9wBj4gGFrO93IbJWyTdBSTo3OxDqqHECNZXyAFGUftaI6SEspd/NYrspI8IM/h
+X68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyIplD9amML9ZMWGxmPsu2b
+m8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctXMbScyJCy
+Z/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirja
+EbsXLZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/T
+KI8xWVvTyQKmtFLKbpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF
+6NkBiDkal4ZkQdU7hwxu+g/GvUgUvzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVh
+OSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1UdEwEB/wQIMAYBAf8CAQEwDgYD
+VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNHDhpkLzCBpgYD
+VR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp
+cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBv
+ACAAZABlACAAbABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBl
+AGwAbwBuAGEAIAAwADgAMAAxADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF
+661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx51tkljYyGOylMnfX40S2wBEqgLk9
+am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qkR71kMrv2JYSiJ0L1
+ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaPT481
+PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS
+3a/DTg4fJl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5k
+SeTy36LssUzAKh3ntLFlosS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF
+3dvd6qJ2gHN99ZwExEWN57kci57q13XRcrHedUTnQn3iV2t93Jm8PYMo6oCTjcVM
+ZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoRsaS8I8nkvof/uZS2+F0g
+StRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTDKCOM/icz
+Q0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQB
+jLMi6Et8Vcad+qMUu2WFbm5PEn4KPJ2V
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU
+MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs
+IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290
+MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux
+FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h
+bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v
+dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt
+H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9
+uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX
+mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX
+a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN
+E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0
+WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD
+VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0
+Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU
+cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx
+IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN
+AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH
+YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5
+6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC
+Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX
+c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a
+mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICgjCCAeugAwIBAgIBBDANBgkqhkiG9w0BAQQFADBTMQswCQYDVQQGEwJVUzEc
+MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEmMCQGA1UEAxMdRXF1aWZheCBT
+ZWN1cmUgZUJ1c2luZXNzIENBLTEwHhcNOTkwNjIxMDQwMDAwWhcNMjAwNjIxMDQw
+MDAwWjBTMQswCQYDVQQGEwJVUzEcMBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5j
+LjEmMCQGA1UEAxMdRXF1aWZheCBTZWN1cmUgZUJ1c2luZXNzIENBLTEwgZ8wDQYJ
+KoZIhvcNAQEBBQADgY0AMIGJAoGBAM4vGbwXt3fek6lfWg0XTzQaDJj0ItlZ1MRo
+RvC0NcWFAyDGr0WlIVFFQesWWDYyb+JQYmT5/VGcqiTZ9J2DKocKIdMSODRsjQBu
+WqDZQu4aIZX5UkxVWsUPOE9G+m34LjXWHXzr4vCwdYDIqROsvojvOm6rXyo4YgKw
+Env+j6YDAgMBAAGjZjBkMBEGCWCGSAGG+EIBAQQEAwIABzAPBgNVHRMBAf8EBTAD
+AQH/MB8GA1UdIwQYMBaAFEp4MlIR21kWNl7fwRQ2QGpHfEyhMB0GA1UdDgQWBBRK
+eDJSEdtZFjZe38EUNkBqR3xMoTANBgkqhkiG9w0BAQQFAAOBgQB1W6ibAxHm6VZM
+zfmpTMANmvPMZWnmJXbMWbfWVMMdzZmsGd20hdXgPfxiIKeES1hl8eL5lSE/9dR+
+WB5Hh1Q+WKG1tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN
+/Bf+KpYrtWKmpj29f5JZzVoqgrI3eQ==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBM
+MSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5D
+ZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBU
+cnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIyMTIwNzM3WhcNMjkxMjMxMTIwNzM3
+WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMg
+Uy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSIw
+IAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rH
+UV+rpDKmYYe2bg+G0jACl/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LM
+TXPb865Px1bVWqeWifrzq2jUI4ZZJ88JJ7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVU
+BBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4fOQtf/WsX+sWn7Et0brM
+kUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0cvW0QM8x
+AcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNV
+HRMBAf8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNV
+HQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15y
+sHhE49wcrwn9I0j6vSrEuVUEtRCjjSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfL
+I9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1mS1FhIrlQgnXdAIv94nYmem8
+J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5ajZt3hrvJBW8qY
+VoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI
+03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx
+EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT
+EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp
+ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz
+NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH
+EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE
+AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw
+DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD
+E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH
+/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy
+DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh
+GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR
+tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA
+AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE
+FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX
+WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu
+9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr
+gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo
+2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO
+LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI
+4uJEvlz36hz1
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFkjCCA3qgAwIBAgIBATANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJGUjET
+MBEGA1UEChMKQ2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxHTAb
+BgNVBAMTFENlcnRpbm9taXMgLSBSb290IENBMB4XDTEzMTAyMTA5MTcxOFoXDTMz
+MTAyMTA5MTcxOFowWjELMAkGA1UEBhMCRlIxEzARBgNVBAoTCkNlcnRpbm9taXMx
+FzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMR0wGwYDVQQDExRDZXJ0aW5vbWlzIC0g
+Um9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANTMCQosP5L2
+fxSeC5yaah1AMGT9qt8OHgZbn1CF6s2Nq0Nn3rD6foCWnoR4kkjW4znuzuRZWJfl
+LieY6pOod5tK8O90gC3rMB+12ceAnGInkYjwSond3IjmFPnVAy//ldu9n+ws+hQV
+WZUKxkd8aRi5pwP5ynapz8dvtF4F/u7BUrJ1Mofs7SlmO/NKFoL21prbcpjp3vDF
+TKWrteoB4owuZH9kb/2jJZOLyKIOSY008B/sWEUuNKqEUL3nskoTuLAPrjhdsKkb
+5nPJWqHZZkCqqU2mNAKthH6yI8H7KsZn9DS2sJVqM09xRLWtwHkziOC/7aOgFLSc
+CbAK42C++PhmiM1b8XcF4LVzbsF9Ri6OSyemzTUK/eVNfaoqoynHWmgE6OXWk6Ri
+wsXm9E/G+Z8ajYJJGYrKWUM66A0ywfRMEwNvbqY/kXPLynNvEiCL7sCCeN5LLsJJ
+wx3tFvYk9CcbXFcx3FXuqB5vbKziRcxXV4p1VxngtViZSTYxPDMBbRZKzbgqg4SG
+m/lg0h9tkQPTYKbVPZrdd5A9NaSfD171UkRpucC63M9933zZxKyGIjK8e2uR73r4
+F2iw4lNVYC2vPsKD2NkJK/DAZNuHi5HMkesE/Xa0lZrmFAYb1TQdvtj/dBxThZng
+WVJKYe2InmtJiUZ+IFrZ50rlau7SZRFDAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIB
+BjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTvkUz1pcMw6C8I6tNxIqSSaHh0
+2TAfBgNVHSMEGDAWgBTvkUz1pcMw6C8I6tNxIqSSaHh02TANBgkqhkiG9w0BAQsF
+AAOCAgEAfj1U2iJdGlg+O1QnurrMyOMaauo++RLrVl89UM7g6kgmJs95Vn6RHJk/
+0KGRHCwPT5iVWVO90CLYiF2cN/z7ZMF4jIuaYAnq1fohX9B0ZedQxb8uuQsLrbWw
+F6YSjNRieOpWauwK0kDDPAUwPk2Ut59KA9N9J0u2/kTO+hkzGm2kQtHdzMjI1xZS
+g081lLMSVX3l4kLr5JyTCcBMWwerx20RoFAXlCOotQqSD7J6wWAsOMwaplv/8gzj
+qh8c3LigkyfeY+N/IZ865Z764BNqdeuWXGKRlI5nU7aJ+BIJy29SWwNyhlCVCNSN
+h4YVH5Uk2KRvms6knZtt0rJ2BobGVgjF6wnaNsIbW0G+YSrjcOa4pvi2WsS9Iff/
+ql+hbHY5ZtbqTFXhADObE5hjyW/QASAJN1LnDE8+zbz1X5YnpyACleAu6AdBBR8V
+btaw5BngDwKTACdyxYvRVB9dSsNAl35VpnzBMwQUAR1JIGkLGZOdblgi90AMRgwj
+Y/M50n92Uaf0yKHxDHYiI0ZSKS3io0EHVmmY0gUJvGnHWmHNj4FgFU2A3ZDifcRQ
+8ow7bkrHxuaAKzyBvBGAFhAn1/DNP3nMcyrDflOR1m749fPH0FFNjkulW+YZFzvW
+gQncItzujrnEj1PhZ7szuIgVRs/taTX/dQ1G885x4cVrhkIGuUE=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFujCCBKKgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBhjELMAkGA1UEBhMCVVMx
+HTAbBgNVBAoTFEFwcGxlIENvbXB1dGVyLCBJbmMuMS0wKwYDVQQLEyRBcHBsZSBD
+b21wdXRlciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxKTAnBgNVBAMTIEFwcGxlIFJv
+b3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTA1MDIxMDAwMTgxNFoXDTI1MDIx
+MDAwMTgxNFowgYYxCzAJBgNVBAYTAlVTMR0wGwYDVQQKExRBcHBsZSBDb21wdXRl
+ciwgSW5jLjEtMCsGA1UECxMkQXBwbGUgQ29tcHV0ZXIgQ2VydGlmaWNhdGUgQXV0
+aG9yaXR5MSkwJwYDVQQDEyBBcHBsZSBSb290IENlcnRpZmljYXRlIEF1dGhvcml0
+eTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOSRqQkfkdseR1DrBe1e
+eYQt6zaiV0xV7IsZid75S2z1B6siMALoGD74UAnTf0GomPnRymacJGsR0KO75Bsq
+wx+VnnoMpEeLW9QWNzPLxA9NzhRp0ckZcvVdDtV/X5vyJQO6VY9NXQ3xZDUjFUsV
+WR2zlPf2nJ7PULrBWFBnjwi0IPfLrCwgb3C2PwEwjLdDzw+dPfMrSSgayP7OtbkO
+2V4c1ss9tTqt9A8OAJILsSEWLnTVPA3bYharo3GSR1NVwa8vQbP4++NwzeajTEV+
+H0xrUJZBicR0YgsQg0GHM4qBsTBY7FoEMoxos48d3mVz/2deZbxJ2HafMxRloXeU
+yS0CAwEAAaOCAi8wggIrMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/
+MB0GA1UdDgQWBBQr0GlHlHYJ/vRrjS5ApvdHTX8IXjAfBgNVHSMEGDAWgBQr0GlH
+lHYJ/vRrjS5ApvdHTX8IXjCCASkGA1UdIASCASAwggEcMIIBGAYJKoZIhvdjZAUB
+MIIBCTBBBggrBgEFBQcCARY1aHR0cHM6Ly93d3cuYXBwbGUuY29tL2NlcnRpZmlj
+YXRlYXV0aG9yaXR5L3Rlcm1zLmh0bWwwgcMGCCsGAQUFBwICMIG2GoGzUmVsaWFu
+Y2Ugb24gdGhpcyBjZXJ0aWZpY2F0ZSBieSBhbnkgcGFydHkgYXNzdW1lcyBhY2Nl
+cHRhbmNlIG9mIHRoZSB0aGVuIGFwcGxpY2FibGUgc3RhbmRhcmQgdGVybXMgYW5k
+IGNvbmRpdGlvbnMgb2YgdXNlLCBjZXJ0aWZpY2F0ZSBwb2xpY3kgYW5kIGNlcnRp
+ZmljYXRpb24gcHJhY3RpY2Ugc3RhdGVtZW50cy4wRAYDVR0fBD0wOzA5oDegNYYz
+aHR0cHM6Ly93d3cuYXBwbGUuY29tL2NlcnRpZmljYXRlYXV0aG9yaXR5L3Jvb3Qu
+Y3JsMFUGCCsGAQUFBwEBBEkwRzBFBggrBgEFBQcwAoY5aHR0cHM6Ly93d3cuYXBw
+bGUuY29tL2NlcnRpZmljYXRlYXV0aG9yaXR5L2Nhc2lnbmVycy5odG1sMA0GCSqG
+SIb3DQEBBQUAA4IBAQCd2i0oWC99dgS5BNM+zrdmY06PL9T+S61yvaM5xlJNBZhS
+9YlRASR5vhoy9+VEi0tEBzmC1lrKtCBe2a4VXR2MHTK/ODFiSF3H4ZCx+CRA+F9Y
+m1FdV53B5f88zHIhbsTp6aF31ywXJsM/65roCwO66bNKcuszCVut5mIxauivL9Wv
+Hld2j383LS4CXN1jyfJxuCZA3xWNdUQ/eb3mHZnhQyw+rW++uaT+DjUZUWOxw961
+kj5ReAFziqQjyqSI8R5cH0EWLX6VCqrpiUGYGxrdyyC/R14MJsVVNU3GMIuZZxTH
+CR+6R8faAQmHJEKVvRNgGQrv6n8Obs3BREM6StXj
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIGZjCCBE6gAwIBAgIPB35Sk3vgFeNX8GmMy+wMMA0GCSqGSIb3DQEBBQUAMHsx
+CzAJBgNVBAYTAkNPMUcwRQYDVQQKDD5Tb2NpZWRhZCBDYW1lcmFsIGRlIENlcnRp
+ZmljYWNpw7NuIERpZ2l0YWwgLSBDZXJ0aWPDoW1hcmEgUy5BLjEjMCEGA1UEAwwa
+QUMgUmHDrXogQ2VydGljw6FtYXJhIFMuQS4wHhcNMDYxMTI3MjA0NjI5WhcNMzAw
+NDAyMjE0MjAyWjB7MQswCQYDVQQGEwJDTzFHMEUGA1UECgw+U29jaWVkYWQgQ2Ft
+ZXJhbCBkZSBDZXJ0aWZpY2FjacOzbiBEaWdpdGFsIC0gQ2VydGljw6FtYXJhIFMu
+QS4xIzAhBgNVBAMMGkFDIFJhw616IENlcnRpY8OhbWFyYSBTLkEuMIICIjANBgkq
+hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAq2uJo1PMSCMI+8PPUZYILrgIem08kBeG
+qentLhM0R7LQcNzJPNCNyu5LF6vQhbCnIwTLqKL85XXbQMpiiY9QngE9JlsYhBzL
+fDe3fezTf3MZsGqy2IiKLUV0qPezuMDU2s0iiXRNWhU5cxh0T7XrmafBHoi0wpOQ
+Y5fzp6cSsgkiBzPZkc0OnB8OIMfuuzONj8LSWKdf/WU34ojC2I+GdV75LaeHM/J4
+Ny+LvB2GNzmxlPLYvEqcgxhaBvzz1NS6jBUJJfD5to0EfhcSM2tXSExP2yYe68yQ
+54v5aHxwD6Mq0Do43zeX4lvegGHTgNiRg0JaTASJaBE8rF9ogEHMYELODVoqDA+b
+MMCm8Ibbq0nXl21Ii/kDwFJnmxL3wvIumGVC2daa49AZMQyth9VXAnow6IYm+48j
+ilSH5L887uvDdUhfHjlvgWJsxS3EF1QZtzeNnDeRyPYL1epjb4OsOMLzP96a++Ej
+YfDIJss2yKHzMI+ko6Kh3VOz3vCaMh+DkXkwwakfU5tTohVTP92dsxA7SH2JD/zt
+A/X7JWR1DhcZDY8AFmd5ekD8LVkH2ZD6mq093ICK5lw1omdMEWux+IBkAC1vImHF
+rEsm5VoQgpukg3s0956JkSCXjrdCx2bD0Omk1vUgjcTDlaxECp1bczwmPS9KvqfJ
+pxAe+59QafMCAwEAAaOB5jCB4zAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE
+AwIBBjAdBgNVHQ4EFgQU0QnQ6dfOeXRU+Tows/RtLAMDG2gwgaAGA1UdIASBmDCB
+lTCBkgYEVR0gADCBiTArBggrBgEFBQcCARYfaHR0cDovL3d3dy5jZXJ0aWNhbWFy
+YS5jb20vZHBjLzBaBggrBgEFBQcCAjBOGkxMaW1pdGFjaW9uZXMgZGUgZ2FyYW50
+7WFzIGRlIGVzdGUgY2VydGlmaWNhZG8gc2UgcHVlZGVuIGVuY29udHJhciBlbiBs
+YSBEUEMuMA0GCSqGSIb3DQEBBQUAA4ICAQBclLW4RZFNjmEfAygPU3zmpFmps4p6
+xbD/CHwso3EcIRNnoZUSQDWDg4902zNc8El2CoFS3UnUmjIz75uny3XlesuXEpBc
+unvFm9+7OSPI/5jOCk0iAUgHforA1SBClETvv3eiiWdIG0ADBaGJ7M9i4z0ldma/
+Jre7Ir5v/zlXdLp6yQGVwZVR6Kss+LGGIOk/yzVb0hfpKv6DExdA7ohiZVvVO2Dp
+ezy4ydV/NgIlqmjCMRW3MGXrfx1IebHPOeJCgBbT9ZMj/EyXyVo3bHwi2ErN0o42
+gzmRkBDI8ck1fj+404HGIGQatlDCIaR43NAvO2STdPCWkPHv+wlaNECW8DYSwaN0
+jJN+Qd53i+yG2dIPPy3RzECiiWZIHiCznCNZc6lEc7wkeZBWN7PGKX6jD/EpOe9+
+XCgycDWs2rjIdWb8m0w5R44bb5tNAlQiM+9hup4phO9OSzNHdpdqy35f/RWmnkJD
+W2ZaiogN9xa5P1FlK2Zqi9E4UqLWRhH6/JocdJ6PlwsCT2TG9WjTSy3/pDceiz+/
+RL5hRqGEPQgnTIEgd4kI6mdAXmwIUV80WoyWaM3X94nCHNMyAK9Sy9NgWyo6R35r
+MDOhYil/SrnhLecUIw4OGEfhefwVVdCx/CVxY3UzHCMrr1zZ7Ud3YA47Dx7SwNxk
+BYn8eNZcLCZDqQ==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDUzCCAjugAwIBAgIBATANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJOTzEd
+MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxHTAbBgNVBAMMFEJ1eXBhc3Mg
+Q2xhc3MgMiBDQSAxMB4XDTA2MTAxMzEwMjUwOVoXDTE2MTAxMzEwMjUwOVowSzEL
+MAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MR0wGwYD
+VQQDDBRCdXlwYXNzIENsYXNzIDIgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBAIs8B0XY9t/mx8q6jUPFR42wWsE425KEHK8T1A9vNkYgxC7McXA0
+ojTTNy7Y3Tp3L8DrKehc0rWpkTSHIln+zNvnma+WwajHQN2lFYxuyHyXA8vmIPLX
+l18xoS830r7uvqmtqEyeIWZDO6i88wmjONVZJMHCR3axiFyCO7srpgTXjAePzdVB
+HfCuuCkslFJgNJQ72uA40Z0zPhX0kzLFANq1KWYOOngPIVJfAuWSeyXTkh4vFZ2B
+5J2O6O+JzhRMVB0cgRJNcKi+EAUXfh/RuFdV7c27UsKwHnjCTTZoy1YmwVLBvXb3
+WNVyfh9EdrsAiR0WnVE1703CVu9r4Iw7DekCAwEAAaNCMEAwDwYDVR0TAQH/BAUw
+AwEB/zAdBgNVHQ4EFgQUP42aWYv8e3uco684sDntkHGA1sgwDgYDVR0PAQH/BAQD
+AgEGMA0GCSqGSIb3DQEBBQUAA4IBAQAVGn4TirnoB6NLJzKyQJHyIdFkhb5jatLP
+gcIV1Xp+DCmsNx4cfHZSldq1fyOhKXdlyTKdqC5Wq2B2zha0jX94wNWZUYN/Xtm+
+DKhQ7SLHrQVMdvvt7h5HZPb3J31cKA9FxVxiXqaakZG3Uxcu3K1gnZZkOb1naLKu
+BctN518fV4bVIJwo+28TOPX2EZL2fZleHwzoq0QkKXJAPTZSr4xYkHPB7GEseaHs
+h7U/2k3ZIQAw3pDaDtMaSKk+hQsUi4y8QZ5q9w5wwDX3OaJdZtB7WZ+oRxKaJyOk
+LY4ng5IgodcVf/EuGO70SH8vf/GhGLWhC5SgYiAynB321O+/TIho
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFnDCCA4SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJGUjET
+MBEGA1UEChMKQ2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxJjAk
+BgNVBAMMHUNlcnRpbm9taXMgLSBBdXRvcml0w6kgUmFjaW5lMB4XDTA4MDkxNzA4
+Mjg1OVoXDTI4MDkxNzA4Mjg1OVowYzELMAkGA1UEBhMCRlIxEzARBgNVBAoTCkNl
+cnRpbm9taXMxFzAVBgNVBAsTDjAwMDIgNDMzOTk4OTAzMSYwJAYDVQQDDB1DZXJ0
+aW5vbWlzIC0gQXV0b3JpdMOpIFJhY2luZTCCAiIwDQYJKoZIhvcNAQEBBQADggIP
+ADCCAgoCggIBAJ2Fn4bT46/HsmtuM+Cet0I0VZ35gb5j2CN2DpdUzZlMGvE5x4jY
+F1AMnmHawE5V3udauHpOd4cN5bjr+p5eex7Ezyh0x5P1FMYiKAT5kcOrJ3NqDi5N
+8y4oH3DfVS9O7cdxbwlyLu3VMpfQ8Vh30WC8Tl7bmoT2R2FFK/ZQpn9qcSdIhDWe
+rP5pqZ56XjUl+rSnSTV3lqc2W+HN3yNw2F1MpQiD8aYkOBOo7C+ooWfHpi2GR+6K
+/OybDnT0K0kCe5B1jPyZOQE51kqJ5Z52qz6WKDgmi92NjMD2AR5vpTESOH2VwnHu
+7XSu5DaiQ3XV8QCb4uTXzEIDS3h65X27uK4uIJPT5GHfceF2Z5c/tt9qc1pkIuVC
+28+BA5PY9OMQ4HL2AHCs8MF6DwV/zzRpRbWT5BnbUhYjBYkOjUjkJW+zeL9i9Qf6
+lSTClrLooyPCXQP8w9PlfMl1I9f09bze5N/NgL+RiH2nE7Q5uiy6vdFrzPOlKO1E
+nn1So2+WLhl+HPNbxxaOu2B9d2ZHVIIAEWBsMsGoOBvrbpgT1u449fCfDu/+MYHB
+0iSVL1N6aaLwD4ZFjliCK0wi1F6g530mJ0jfJUaNSih8hp75mxpZuWW/Bd22Ql09
+5gBIgl4g9xGC3srYn+Y3RyYe63j3YcNBZFgCQfna4NH4+ej9Uji29YnfAgMBAAGj
+WzBZMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBQN
+jLZh2kS40RR9w759XkjwzspqsDAXBgNVHSAEEDAOMAwGCiqBegFWAgIAAQEwDQYJ
+KoZIhvcNAQEFBQADggIBACQ+YAZ+He86PtvqrxyaLAEL9MW12Ukx9F1BjYkMTv9s
+ov3/4gbIOZ/xWqndIlgVqIrTseYyCYIDbNc/CMf4uboAbbnW/FIyXaR/pDGUu7ZM
+OH8oMDX/nyNTt7buFHAAQCvaR6s0fl6nVjBhK4tDrP22iCj1a7Y+YEq6QpA0Z43q
+619FVDsXrIvkxmUP7tCMXWY5zjKn2BCXwH40nJ+U8/aGH88bc62UeYdocMMzpXDn
+2NU4lG9jeeu/Cg4I58UvD0KgKxRA/yHgBcUn4YQRE7rWhh1BCxMjidPJC+iKunqj
+o3M3NYB9Ergzd0A4wPpeMNLytqOx1qKVl4GbUu1pTP+A5FPbVFsDbVRfsbjvJL1v
+nxHDx2TCDyhihWZeGnuyt++uNckZM6i4J9szVb9o4XVIRFb7zdNIu0eJOqxp9YDG
+5ERQL1TEqkPFMTFYvZbF6nVsmnWxTfj3l/+WFvKXTej28xH5On2KOG4Ey+HTRRWq
+pdEdnV1j6CTmNhTih60bWfVEm/vXd3wfAXBioSAaosUaKPQhA+4u2cGA6rnZgtZb
+dsLLO7XSAPCjDuGtbkD326C00EauFddEwk01+dIL8hf2rGbVJLJP0RyZwG71fet0
+BLj5TXcJ17TPBzAJ8bgAVtkXFhYKK4bfjwEZGuW7gmP/vgt2Fl43N+bYdJeimUV5
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYT
+AlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBD
+QTAeFw0wNjA3MDQxNzIwMDRaFw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJP
+MREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTCC
+ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7IJUqOtdu0KBuqV5Do
+0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHHrfAQ
+UySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5d
+RdY4zTW2ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQ
+OA7+j0xbm0bqQfWwCHTD0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwv
+JoIQ4uNllAoEwF73XVv4EOLQunpL+943AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08C
+AwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAcYwHQYDVR0O
+BBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IBAQA+0hyJ
+LjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecY
+MnQ8SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ
+44gx+FkagQnIl6Z0x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6I
+Jd1hJyMctTEHBDa0GpC9oHRxUIltvBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNw
+i/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7NzTogVZ96edhBiIL5VaZVDADlN
+9u6wWk5JRFRYX0KD
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x
+GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv
+b3QgQ0EgMzAeFw0wNjExMjQxOTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNV
+BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W
+YWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDM
+V0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNggDhoB
+4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUr
+H556VOijKTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd
+8lyyBTNvijbO0BNO/79KDDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9Cabwv
+vWhDFlaJKjdhkf2mrk7AyxRllDdLkgbvBNDInIjbC3uBr7E9KsRlOni27tyAsdLT
+mZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwpp5ijJUMv7/FfJuGITfhe
+btfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8nT8KKdjc
+T5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDt
+WAEXMJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZ
+c6tsgLjoC2SToJyMGf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A
+4iLItLRkT9a6fUg+qGkM17uGcclzuD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYD
+VR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHTBgkrBgEEAb5YAAMwgcUwgZMG
+CCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0
+aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0
+aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVu
+dC4wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2Nw
+czALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4G
+A1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4ywLQoUmkRzBFMQswCQYDVQQGEwJC
+TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UEAxMSUXVvVmFkaXMg
+Um9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZVqyM0
+7ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSem
+d1o417+shvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd
++LJ2w/w4E6oM3kJpK27zPOuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B
+4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadN
+t54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp8kokUvd0/bpO5qgdAm6x
+DYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBCbjPsMZ57
+k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6s
+zHXug/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0j
+Wy10QJLZYxkNc91pvGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeT
+mJlglFwjz1onl14LBQaTNx47aTbrqZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK
+4SVhM7JZG+Ju1zdXtg2pEto=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDVTCCAj2gAwIBAgIESTMAATANBgkqhkiG9w0BAQUFADAyMQswCQYDVQQGEwJD
+TjEOMAwGA1UEChMFQ05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1QwHhcNMDcwNDE2
+MDcwOTE0WhcNMjcwNDE2MDcwOTE0WjAyMQswCQYDVQQGEwJDTjEOMAwGA1UEChMF
+Q05OSUMxEzARBgNVBAMTCkNOTklDIFJPT1QwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQDTNfc/c3et6FtzF8LRb+1VvG7q6KR5smzDo+/hn7E7SIX1mlwh
+IhAsxYLO2uOabjfhhyzcuQxauohV3/2q2x8x6gHx3zkBwRP9SFIhxFXf2tizVHa6
+dLG3fdfA6PZZxU3Iva0fFNrfWEQlMhkqx35+jq44sDB7R3IJMfAw28Mbdim7aXZO
+V/kbZKKTVrdvmW7bCgScEeOAH8tjlBAKqeFkgjH5jCftppkA9nCTGPihNIaj3XrC
+GHn2emU1z5DrvTOTn1OrczvmmzQgLx3vqR1jGqCA2wMv+SYahtKNu6m+UjqHZ0gN
+v7Sg2Ca+I19zN38m5pIEo3/PIKe38zrKy5nLAgMBAAGjczBxMBEGCWCGSAGG+EIB
+AQQEAwIABzAfBgNVHSMEGDAWgBRl8jGtKvf33VKWCscCwQ7vptU7ETAPBgNVHRMB
+Af8EBTADAQH/MAsGA1UdDwQEAwIB/jAdBgNVHQ4EFgQUZfIxrSr3991SlgrHAsEO
+76bVOxEwDQYJKoZIhvcNAQEFBQADggEBAEs17szkrr/Dbq2flTtLP1se31cpolnK
+OOK5Gv+e5m4y3R6u6jW39ZORTtpC4cMXYFDy0VwmuYK36m3knITnA3kXr5g9lNvH
+ugDnuL8BV8F3RTIMO/G0HAiw/VGgod2aHRM2mm23xzy54cXZF/qD1T0VoDy7Hgvi
+yJA/qIYM/PmLXoXLT1tLYhFHxUV8BS9BsZ4QaRuZluBVeftOhpm4lNqGOGqTo+fL
+buXf6iFViZx9fX+Y9QCJ7uOEwFyWtcVG6kbghVW2G8kS1sHNzYDzAgE8yGnLRUhj
+2JTQ7IUOO04RZfSCjKY9ri4ilAnIXOo8gV0WKgOXFlUJ24pBgp5mmxE=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
+MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
+YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG
+EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg
+R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9
+9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq
+fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv
+iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU
+1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+
+bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW
+MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA
+ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l
+uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn
+Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS
+tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF
+PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un
+hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV
+5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDyzCCArOgAwIBAgIDAOJIMA0GCSqGSIb3DQEBBQUAMIGLMQswCQYDVQQGEwJB
+VDFIMEYGA1UECgw/QS1UcnVzdCBHZXMuIGYuIFNpY2hlcmhlaXRzc3lzdGVtZSBp
+bSBlbGVrdHIuIERhdGVudmVya2VociBHbWJIMRgwFgYDVQQLDA9BLVRydXN0LVF1
+YWwtMDIxGDAWBgNVBAMMD0EtVHJ1c3QtUXVhbC0wMjAeFw0wNDEyMDIyMzAwMDBa
+Fw0xNDEyMDIyMzAwMDBaMIGLMQswCQYDVQQGEwJBVDFIMEYGA1UECgw/QS1UcnVz
+dCBHZXMuIGYuIFNpY2hlcmhlaXRzc3lzdGVtZSBpbSBlbGVrdHIuIERhdGVudmVy
+a2VociBHbWJIMRgwFgYDVQQLDA9BLVRydXN0LVF1YWwtMDIxGDAWBgNVBAMMD0Et
+VHJ1c3QtUXVhbC0wMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJaR
+q9eOsFm4Ab20Hq2Z/aH86gyWa48uSUjY6eQkguHYuszr3gdcSMYZggFHQgnhfLmf
+ro/27l5rqKhWiDhWs+b+yZ1PNDhRPJy+86ycHMg9XJqErveULBSyZDdgjhSwOyrN
+ibUir/fkf+4sKzP5jjytTKJXD/uCxY4fAd9TjMEVpN3umpIS0ijpYhclYDHvzzGU
+833z5Dwhq5D8bc9jp8YSAHFJ1xzIoO1jmn3jjyjdYPnY5harJtHQL73nDQnfbtTs
+5ThT9GQLulrMgLU4WeyAWWWEMWpfVZFMJOUkmoOEer6A8e5fIAeqdxdsC+JVqpZ4
+CAKel/Arrlj1gFA//jsCAwEAAaM2MDQwDwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4E
+CgQIQj0rJKbBRc4wDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQBG
+yxFjUA2bPkXUSC2SfJ29tmrbiLKal+g6a9M8Xwd+Ejo+oYkNP6F4GfeDtAXpm7xb
+9Ly8lhdbHcpRhzCUQHJ1tBCiGdLgmhSx7TXjhhanKOdDgkdsC1T+++piuuYL72TD
+gUy2Sb1GHlJ1Nc6rvB4fpxSDAOHqGpUq9LWsc3tFkXqRqmQVtqtR77npKIFBioc6
+2jTBwDMPX3hDJDR1DSPc6BnZliaNw2IHdiMQ0mBoYeRnFdq+TyDKsjmJOOQPLzzL
+/saaw6F891+gBjLFEFquDyR73lAPJS279R3csi8WWk4ZYUC/1V8H3Ktip/J6ac8e
+qhLCbmJ81Lo92JGHz/ot
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ
+RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD
+VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX
+DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y
+ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy
+VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr
+mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr
+IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK
+mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu
+XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy
+dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye
+jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1
+BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3
+DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92
+9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx
+jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0
+Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz
+ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS
+R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC
+VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0
+Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW
+KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl
+cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIw
+NTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkw
+NwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSBy
+ZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNV
+BAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ
+KoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFo
+Nu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf4
+4LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9
+KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGI
+rb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi
+94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB
+sDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAi
+gA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSMEGDAWgBRo
+kORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE
+vW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA
+A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9t
+O1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6Zua
+AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP
+9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/
+eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m
+0vdXcDazv/wor3ElhVsT/h5/WrQ8
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICpzCCAi2gAwIBAgIQTHm1miicdjFk9YlE0JEC3jAKBggqhkjOPQQDAzCBlDEL
+MAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYD
+VQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBD
+bGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0g
+RzQwHhcNMTIxMDE4MDAwMDAwWhcNMzcxMjAxMjM1OTU5WjCBlDELMAkGA1UEBhMC
+VVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZTeW1h
+bnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBDbGFzcyAzIFB1
+YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcq
+hkjOPQIBBgUrgQQAIgNiAARXz+qzOU0/oSHgbi84csaHl/OFC0fnD1HI0fSZm8pZ
+Zf9M+eoLtyXV0vbsMS0yYhLXdoan+jjJZdT+c+KEOfhMSWIT3brViKBfPchPsD+P
+oVAR5JNGrcNfy/GkapVW6MCjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E
+BTADAQH/MB0GA1UdDgQWBBQknbzScfcdwiW+IvGJpSwVOzQeXjAKBggqhkjOPQQD
+AwNoADBlAjEAuWZoZdsF0Dh9DvPIdWG40CjEsUozUVj78jwQyK5HeHbKZiQXhj5Q
+Vm6lLZmIuL0kAjAD6qfnqDzqnWLGX1TamPR3vU+PGJyRXEdrQE0QHbPhicoLIsga
+xcX+i93B3294n5E=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
+ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL
+MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
+LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug
+RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm
++9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW
+PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM
+xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB
+Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3
+hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg
+EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF
+MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA
+FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec
+nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z
+eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF
+hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2
+Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
+vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep
++OkuE6N36B9K
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIGHDCCBASgAwIBAgIES45gAzANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJE
+SzESMBAGA1UEChMJVFJVU1QyNDA4MSIwIAYDVQQDExlUUlVTVDI0MDggT0NFUyBQ
+cmltYXJ5IENBMB4XDTEwMDMwMzEyNDEzNFoXDTM3MTIwMzEzMTEzNFowRTELMAkG
+A1UEBhMCREsxEjAQBgNVBAoTCVRSVVNUMjQwODEiMCAGA1UEAxMZVFJVU1QyNDA4
+IE9DRVMgUHJpbWFyeSBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB
+AJlJodr3U1Fa+v8HnyACHV81/wLevLS0KUk58VIABl6Wfs3LLNoj5soVAZv4LBi5
+gs7E8CZ9w0F2CopW8vzM8i5HLKE4eedPdnaFqHiBZ0q5aaaQArW+qKJx1rT/AaXt
+alMB63/yvJcYlXS2lpexk5H/zDBUXeEQyvfmK+slAySWT6wKxIPDwVapauFY9QaG
++VBhCa5jBstWS7A5gQfEvYqn6csZ3jW472kW6OFNz6ftBcTwufomGJBMkonf4ZLr
+6t0AdRi9jflBPz3MNNRGxyjIuAmFqGocYFA/OODBRjvSHB2DygqQ8k+9tlpvzMRr
+kU7jq3RKL+83G1dJ3/LTjCLz4ryEMIC/OJ/gNZfE0qXddpPtzflIPtUFVffXdbFV
+1t6XZFhJ+wBHQCpJobq/BjqLWUA86upsDbfwnePtmIPRCemeXkY0qabC+2Qmd2Fe
+xyZphwTyMnbqy6FG1tB65dYf3mOqStmLa3RcHn9+2dwNfUkh0tjO2FXD7drWcU0O
+I9DW8oAypiPhm/QCjMU6j6t+0pzqJ/S0tdAo+BeiXK5hwk6aR+sRb608QfBbRAs3
+U/q8jSPByenggac2BtTN6cl+AA1Mfcgl8iXWNFVGegzd/VS9vINClJCe3FNVoUnR
+YCKkj+x0fqxvBLopOkJkmuZw/yhgMxljUi2qYYGn90OzAgMBAAGjggESMIIBDjAP
+BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjARBgNVHSAECjAIMAYGBFUd
+IAAwgZcGA1UdHwSBjzCBjDAsoCqgKIYmaHR0cDovL2NybC5vY2VzLnRydXN0MjQw
+OC5jb20vb2Nlcy5jcmwwXKBaoFikVjBUMQswCQYDVQQGEwJESzESMBAGA1UEChMJ
+VFJVU1QyNDA4MSIwIAYDVQQDExlUUlVTVDI0MDggT0NFUyBQcmltYXJ5IENBMQ0w
+CwYDVQQDEwRDUkwxMB8GA1UdIwQYMBaAFPZt+LFIs0FDAduGROUYBbdezAY3MB0G
+A1UdDgQWBBT2bfixSLNBQwHbhkTlGAW3XswGNzANBgkqhkiG9w0BAQsFAAOCAgEA
+VPAQGrT7dIjD3/sIbQW86f9CBPu0c7JKN6oUoRUtKqgJ2KCdcB5ANhCoyznHpu3m
+/dUfVUI5hc31CaPgZyY37hch1q4/c9INcELGZVE/FWfehkH+acpdNr7j8UoRZlkN
+15b/0UUBfGeiiJG/ugo4llfoPrp8bUmXEGggK3wyqIPcJatPtHwlb6ympfC2b/Ld
+v/0IdIOzIOm+A89Q0utx+1cOBq72OHy8gpGb6MfncVFMoL2fjP652Ypgtr8qN9Ka
+/XOazktiIf+2Pzp7hLi92hRc9QMYexrV/nnFSQoWdU8TqULFUoZ3zTEC3F/g2yj+
+FhbrgXHGo5/A4O74X+lpbY2XV47aSuw+DzcPt/EhMj2of7SA55WSgbjPMbmNX0rb
+oenSIte2HRFW5Tr2W+qqkc/StixgkKdyzGLoFx/xeTWdJkZKwyjqge2wJqws2upY
+EiThhC497+/mTiSuXd69eVUwKyqYp9SD2rTtNmF6TCghRM/dNsJOl+osxDVGcwvt
+WIVFF/Onlu5fu1NHXdqNEfzldKDUvCfii3L2iATTZyHwU9CALE+2eIA+PIaLgnM1
+1oCfUnYBkQurTrihvzz9PryCVkLxiqRmBVvUz+D4N5G/wvvKDS6t6cPCS+hqM482
+cbBsn0R9fFLO4El62S9eH1tqOzO20OAOK65yJIsOpSE=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEY
+MBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21t
+dW5pY2F0aW9uIFJvb3RDQTEwHhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5
+WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYD
+VQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEwggEiMA0GCSqGSIb3
+DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw8yl8
+9f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJ
+DKaVv0uMDPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9
+Ms+k2Y7CI9eNqPPYJayX5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/N
+QV3Is00qVUarH9oe4kA92819uZKAnDfdDJZkndwi92SL32HeFZRSFaB9UslLqCHJ
+xrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2JChzAgMBAAGjPzA9MB0G
+A1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYwDwYDVR0T
+AQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vG
+kl3g0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfr
+Uj94nK9NrvjVT8+amCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5
+Bw+SUEmK3TGXX8npN6o7WWWXlDLJs58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJU
+JRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ6rBK+1YWc26sTfcioU+tHXot
+RSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAiFL39vmwLAw==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICkDCCAfmgAwIBAgIBATANBgkqhkiG9w0BAQQFADBaMQswCQYDVQQGEwJVUzEc
+MBoGA1UEChMTRXF1aWZheCBTZWN1cmUgSW5jLjEtMCsGA1UEAxMkRXF1aWZheCBT
+ZWN1cmUgR2xvYmFsIGVCdXNpbmVzcyBDQS0xMB4XDTk5MDYyMTA0MDAwMFoXDTIw
+MDYyMTA0MDAwMFowWjELMAkGA1UEBhMCVVMxHDAaBgNVBAoTE0VxdWlmYXggU2Vj
+dXJlIEluYy4xLTArBgNVBAMTJEVxdWlmYXggU2VjdXJlIEdsb2JhbCBlQnVzaW5l
+c3MgQ0EtMTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuucXkAJlsTRVPEnC
+UdXfp9E3j9HngXNBUmCbnaEXJnitx7HoJpQytd4zjTov2/KaelpzmKNc6fuKcxtc
+58O/gGzNqfTWK8D3+ZmqY6KxRwIP1ORROhI8bIpaVIRw28HFkM9yRcuoWcDNM50/
+o5brhTMhHD4ePmBudpxnhcXIw2ECAwEAAaNmMGQwEQYJYIZIAYb4QgEBBAQDAgAH
+MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUvqigdHJQa0S3ySPY+6j/s1dr
+aGwwHQYDVR0OBBYEFL6ooHRyUGtEt8kj2Puo/7NXa2hsMA0GCSqGSIb3DQEBBAUA
+A4GBADDiAVGqx+pf2rnQZQ8w1j7aDRRJbpGTJxQx78T3LUX47Me/okENI7SS+RkA
+Z70Br83gcfxaz2TE4JaY0KNA4gGK7ycH8WUBikQtBmV1UsCGECAhX2xrD2yuCRyv
+8qIYNMR1pHMc8Y3c7635s3a0kr/clRAevsvIO1qEYBlWlKlV
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIF5zCCA8+gAwIBAgIITK9zQhyOdAIwDQYJKoZIhvcNAQEFBQAwgYAxODA2BgNV
+BAMML0VCRyBFbGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sx
+c8SxMTcwNQYDVQQKDC5FQkcgQmlsacWfaW0gVGVrbm9sb2ppbGVyaSB2ZSBIaXpt
+ZXRsZXJpIEEuxZ4uMQswCQYDVQQGEwJUUjAeFw0wNjA4MTcwMDIxMDlaFw0xNjA4
+MTQwMDMxMDlaMIGAMTgwNgYDVQQDDC9FQkcgRWxla3Ryb25payBTZXJ0aWZpa2Eg
+SGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTE3MDUGA1UECgwuRUJHIEJpbGnFn2ltIFRl
+a25vbG9qaWxlcmkgdmUgSGl6bWV0bGVyaSBBLsWeLjELMAkGA1UEBhMCVFIwggIi
+MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDuoIRh0DpqZhAy2DE4f6en5f2h
+4fuXd7hxlugTlkaDT7byX3JWbhNgpQGR4lvFzVcfd2NR/y8927k/qqk153nQ9dAk
+tiHq6yOU/im/+4mRDGSaBUorzAzu8T2bgmmkTPiab+ci2hC6X5L8GCcKqKpE+i4s
+tPtGmggDg3KriORqcsnlZR9uKg+ds+g75AxuetpX/dfreYteIAbTdgtsApWjluTL
+dlHRKJ2hGvxEok3MenaoDT2/F08iiFD9rrbskFBKW5+VQarKD7JK/oCZTqNGFav4
+c0JqwmZ2sQomFd2TkuzbqV9UIlKRcF0T6kjsbgNs2d1s/OsNA/+mgxKb8amTD8Um
+TDGyY5lhcucqZJnSuOl14nypqZoaqsNW2xCaPINStnuWt6yHd6i58mcLlEOzrz5z
++kI2sSXFCjEmN1ZnuqMLfdb3ic1nobc6HmZP9qBVFCVMLDMNpkGMvQQxahByCp0O
+Lna9XvNRiYuoP1Vzv9s6xiQFlpJIqkuNKgPlV5EQ9GooFW5Hd4RcUXSfGenmHmMW
+OeMRFeNYGkS9y8RsZteEBt8w9DeiQyJ50hBs37vmExH8nYQKE3vwO9D8owrXieqW
+fo1IhR5kX9tUoqzVegJ5a9KK8GfaZXINFHDk6Y54jzJ0fFfy1tb0Nokb+Clsi7n2
+l9GkLqq+CxnCRelwXQIDAJ3Zo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB
+/wQEAwIBBjAdBgNVHQ4EFgQU587GT/wWZ5b6SqMHwQSny2re2kcwHwYDVR0jBBgw
+FoAU587GT/wWZ5b6SqMHwQSny2re2kcwDQYJKoZIhvcNAQEFBQADggIBAJuYml2+
+8ygjdsZs93/mQJ7ANtyVDR2tFcU22NU57/IeIl6zgrRdu0waypIN30ckHrMk2pGI
+6YNw3ZPX6bqz3xZaPt7gyPvT/Wwp+BVGoGgmzJNSroIBk5DKd8pNSe/iWtkqvTDO
+TLKBtjDOWU/aWR1qeqRFsIImgYZ29fUQALjuswnoT4cCB64kXPBfrAowzIpAoHME
+wfuJJPaaHFy3PApnNgUIMbOv2AFoKuB4j3TeuFGkjGwgPaL7s9QJ/XvCgKqTbCmY
+Iai7FvOpEl90tYeY8pUm3zTvilORiF0alKM/fCL414i6poyWqD1SNGKfAB5UVUJn
+xk1Gj7sURT0KlhaOEKGXmdXTMIXM3rRyt7yKPBgpaP3ccQfuJDlq+u2lrDgv+R4Q
+DgZxGhBM/nV+/x5XOULK1+EVoVZVWRvRo68R2E7DpSvvkL/A7IITW43WciyTTo9q
+Kd+FPNMN4KIYEsxVL0e3p5sC/kH2iExt2qkBR4NkJ2IQgtYSe14DHzSpyZH+r11t
+hie3I6p1GMog57AP14kOpmciY/SDQSsGS7tY1dHXt7kQY9iJSrSq3RZj9W6+YKH4
+7ejWkE8axsWgKdOnIaj1Wjz3x0miIZpKlVIglnKaZsv30oZDfCK+lvm9AahH3eU7
+QPl1K5srRmSGjR70j/sHd9DqSaIcjVIUpgqT
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFFzCCA/+gAwIBAgIBETANBgkqhkiG9w0BAQUFADCCASsxCzAJBgNVBAYTAlRS
+MRgwFgYDVQQHDA9HZWJ6ZSAtIEtvY2FlbGkxRzBFBgNVBAoMPlTDvHJraXllIEJp
+bGltc2VsIHZlIFRla25vbG9qaWsgQXJhxZ90xLFybWEgS3VydW11IC0gVMOcQsSw
+VEFLMUgwRgYDVQQLDD9VbHVzYWwgRWxla3Ryb25payB2ZSBLcmlwdG9sb2ppIEFy
+YcWfdMSxcm1hIEVuc3RpdMO8c8O8IC0gVUVLQUUxIzAhBgNVBAsMGkthbXUgU2Vy
+dGlmaWthc3lvbiBNZXJrZXppMUowSAYDVQQDDEFUw5xCxLBUQUsgVUVLQUUgS8O2
+ayBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsSAtIFPDvHLDvG0gMzAe
+Fw0wNzA4MjQxMTM3MDdaFw0xNzA4MjExMTM3MDdaMIIBKzELMAkGA1UEBhMCVFIx
+GDAWBgNVBAcMD0dlYnplIC0gS29jYWVsaTFHMEUGA1UECgw+VMO8cmtpeWUgQmls
+aW1zZWwgdmUgVGVrbm9sb2ppayBBcmHFn3TEsXJtYSBLdXJ1bXUgLSBUw5xCxLBU
+QUsxSDBGBgNVBAsMP1VsdXNhbCBFbGVrdHJvbmlrIHZlIEtyaXB0b2xvamkgQXJh
+xZ90xLFybWEgRW5zdGl0w7xzw7wgLSBVRUtBRTEjMCEGA1UECwwaS2FtdSBTZXJ0
+aWZpa2FzeW9uIE1lcmtlemkxSjBIBgNVBAMMQVTDnELEsFRBSyBVRUtBRSBLw7Zr
+IFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIC0gU8O8csO8bSAzMIIB
+IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAim1L/xCIOsP2fpTo6iBkcK4h
+gb46ezzb8R1Sf1n68yJMlaCQvEhOEav7t7WNeoMojCZG2E6VQIdhn8WebYGHV2yK
+O7Rm6sxA/OOqbLLLAdsyv9Lrhc+hDVXDWzhXcLh1xnnRFDDtG1hba+818qEhTsXO
+fJlfbLm4IpNQp81McGq+agV/E5wrHur+R84EpW+sky58K5+eeROR6Oqeyjh1jmKw
+lZMq5d/pXpduIF9fhHpEORlAHLpVK/swsoHvhOPc7Jg4OQOFCKlUAwUp8MmPi+oL
+hmUZEdPpCSPeaJMDyTYcIW7OjGbxmTDY17PDHfiBLqi9ggtm/oLL4eAagsNAgQID
+AQABo0IwQDAdBgNVHQ4EFgQUvYiHyY/2pAoLquvF/pEjnatKijIwDgYDVR0PAQH/
+BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAB18+kmP
+NOm3JpIWmgV050vQbTlswyb2zrgxvMTfvCr4N5EY3ATIZJkrGG2AA1nJrvhY0D7t
+wyOfaTyGOBye79oneNGEN3GKPEs5z35FBtYt2IpNeBLWrcLTy9LQQfMmNkqblWwM
+7uXRQydmwYj3erMgbOqwaSvHIOgMA8RBBZniP+Rr+KCGgceExh/VS4ESshYhLBOh
+gLJeDEoTniDYYkCrkOpkSi+sDQESeUWoL4cZaMjihccwsnX5OD+ywJO0a+IDRM5n
+oN+J1q2MdqMTw5RhK2vZbMEHCiIHhWyFJEapvj+LeISCfiQMnf2BN+MlqO02TpUs
+yZyQ2uypQjyttgI=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEPTCCAyWgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvzE/MD0GA1UEAww2VMOc
+UktUUlVTVCBFbGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sx
+c8SxMQswCQYDVQQGEwJUUjEPMA0GA1UEBwwGQW5rYXJhMV4wXAYDVQQKDFVUw5xS
+S1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kg
+SGl6bWV0bGVyaSBBLsWeLiAoYykgQXJhbMSxayAyMDA3MB4XDTA3MTIyNTE4Mzcx
+OVoXDTE3MTIyMjE4MzcxOVowgb8xPzA9BgNVBAMMNlTDnFJLVFJVU1QgRWxla3Ry
+b25payBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTELMAkGA1UEBhMC
+VFIxDzANBgNVBAcMBkFua2FyYTFeMFwGA1UECgxVVMOcUktUUlVTVCBCaWxnaSDE
+sGxldGnFn2ltIHZlIEJpbGnFn2ltIEfDvHZlbmxpxJ9pIEhpem1ldGxlcmkgQS7F
+ni4gKGMpIEFyYWzEsWsgMjAwNzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAKu3PgqMyKVYFeaK7yc9SrToJdPNM8Ig3BnuiD9NYvDdE3ePYakqtdTyuTFY
+KTsvP2qcb3N2Je40IIDu6rfwxArNK4aUyeNgsURSsloptJGXg9i3phQvKUmi8wUG
++7RP2qFsmmaf8EMJyupyj+sA1zU511YXRxcw9L6/P8JorzZAwan0qafoEGsIiveG
+HtyaKhUG9qPw9ODHFNRRf8+0222vR5YXm3dx2KdxnSQM9pQ/hTEST7ruToK4uT6P
+IzdezKKqdfcYbwnTrqdUKDT74eA7YH2gvnmJhsifLfkKS8RQouf9eRbHegsYz85M
+733WB2+Y8a+xwXrXgTW4qhe04MsCAwEAAaNCMEAwHQYDVR0OBBYEFCnFkKslrxHk
+Yb+j/4hhkeYO/pyBMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0G
+CSqGSIb3DQEBBQUAA4IBAQAQDdr4Ouwo0RSVgrESLFF6QSU2TJ/sPx+EnWVUXKgW
+AkD6bho3hO9ynYYKVZ1WKKxmLNA6VpM0ByWtCLCPyA8JWcqdmBzlVPi5RX9ql2+I
+aE1KBiY3iAIOtsbWcpnOa3faYjGkVh+uX4132l32iPwa2Z61gfAyuOOI0JzzaqC5
+mxRZNTZPz/OOXl0XrRWV2N2y1RVuAE6zS89mlOTgzbUF2mNXi+WzqtvALhyQRNsa
+XRik7r4EW5nVcV9VZWRi1aKbBFmGyGJ353yCRWo9F7/snXUMrqNvWtMvmDb08PUZ
+qxFdyKbjKlhqQgnDvZImZjINXQhVdP+MmNAKpoRq0Tl9
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEYDCCA0igAwIBAgICATAwDQYJKoZIhvcNAQELBQAwWTELMAkGA1UEBhMCVVMx
+GDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDENMAsGA1UECxMERlBLSTEhMB8GA1UE
+AxMYRmVkZXJhbCBDb21tb24gUG9saWN5IENBMB4XDTEwMTIwMTE2NDUyN1oXDTMw
+MTIwMTE2NDUyN1owWTELMAkGA1UEBhMCVVMxGDAWBgNVBAoTD1UuUy4gR292ZXJu
+bWVudDENMAsGA1UECxMERlBLSTEhMB8GA1UEAxMYRmVkZXJhbCBDb21tb24gUG9s
+aWN5IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2HX7NRY0WkG/
+Wq9cMAQUHK14RLXqJup1YcfNNnn4fNi9KVFmWSHjeavUeL6wLbCh1bI1FiPQzB6+
+Duir3MPJ1hLXp3JoGDG4FyKyPn66CG3G/dFYLGmgA/Aqo/Y/ISU937cyxY4nsyOl
+4FKzXZbpsLjFxZ+7xaBugkC7xScFNknWJidpDDSPzyd6KgqjQV+NHQOGgxXgVcHF
+mCye7Bpy3EjBPvmE0oSCwRvDdDa3ucc2Mnr4MrbQNq4iGDGMUHMhnv6DOzCIJOPp
+wX7e7ZjHH5IQip9bYi+dpLzVhW86/clTpyBLqtsgqyFOHQ1O5piF5asRR12dP8Qj
+wOMUBm7+nQIDAQABo4IBMDCCASwwDwYDVR0TAQH/BAUwAwEB/zCB6QYIKwYBBQUH
+AQsEgdwwgdkwPwYIKwYBBQUHMAWGM2h0dHA6Ly9odHRwLmZwa2kuZ292L2ZjcGNh
+L2NhQ2VydHNJc3N1ZWRCeWZjcGNhLnA3YzCBlQYIKwYBBQUHMAWGgYhsZGFwOi8v
+bGRhcC5mcGtpLmdvdi9jbj1GZWRlcmFsJTIwQ29tbW9uJTIwUG9saWN5JTIwQ0Es
+b3U9RlBLSSxvPVUuUy4lMjBHb3Zlcm5tZW50LGM9VVM/Y0FDZXJ0aWZpY2F0ZTti
+aW5hcnksY3Jvc3NDZXJ0aWZpY2F0ZVBhaXI7YmluYXJ5MA4GA1UdDwEB/wQEAwIB
+BjAdBgNVHQ4EFgQUrQx6dVzl85jEeZgOrCj9l/TnAvwwDQYJKoZIhvcNAQELBQAD
+ggEBAI9z2uF/gLGH9uwsz9GEYx728Yi3mvIRte9UrYpuGDco71wb5O9Qt2wmGCMi
+TR0mRyDpCZzicGJxqxHPkYnos/UqoEfAFMtOQsHdDA4b8Idb7OV316rgVNdF9IU+
+7LQd3nyKf1tNnJaK0KIyn9psMQz4pO9+c+iR3Ah6cFqgr2KBWfgAdKLI3VTKQVZH
+venAT+0g3eOlCd+uKML80cgX2BLHb94u6b2akfI8WpQukSKAiaGMWMyDeiYZdQKl
+Dn0KJnNR6obLB6jI/WNaNZvSr79PMUjBhHDbNXuaGQ/lj/RqDG8z2esccKIN47lQ
+A2EC/0rskqTcLe4qNJMHtyznGI8=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjEL
+MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW
+ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2ln
+biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp
+U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y
+aXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjELMAkG
+A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJp
+U2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwg
+SW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2ln
+biBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5
+IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8Utpkmw4tXNherJI9/gHm
+GUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGzrl0Bp3ve
+fLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUw
+AwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJ
+aW1hZ2UvZ2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYj
+aHR0cDovL2xvZ28udmVyaXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMW
+kf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMDA2gAMGUCMGYhDBgmYFo4e1ZC
+4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIxAJw9SDkjOVga
+FRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIID4TCCAsmgAwIBAgIOYyUAAQACFI0zFQLkbPQwDQYJKoZIhvcNAQEFBQAwezEL
+MAkGA1UEBhMCREUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNV
+BAsTG1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQTEoMCYGA1UEAxMfVEMgVHJ1
+c3RDZW50ZXIgVW5pdmVyc2FsIENBIElJSTAeFw0wOTA5MDkwODE1MjdaFw0yOTEy
+MzEyMzU5NTlaMHsxCzAJBgNVBAYTAkRFMRwwGgYDVQQKExNUQyBUcnVzdENlbnRl
+ciBHbWJIMSQwIgYDVQQLExtUQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0ExKDAm
+BgNVBAMTH1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQSBJSUkwggEiMA0GCSqG
+SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDC2pxisLlxErALyBpXsq6DFJmzNEubkKLF
+5+cvAqBNLaT6hdqbJYUtQCggbergvbFIgyIpRJ9Og+41URNzdNW88jBmlFPAQDYv
+DIRlzg9uwliT6CwLOunBjvvya8o84pxOjuT5fdMnnxvVZ3iHLX8LR7PH6MlIfK8v
+zArZQe+f/prhsq75U7Xl6UafYOPfjdN/+5Z+s7Vy+EutCHnNaYlAJ/Uqwa1D7KRT
+yGG299J5KmcYdkhtWyUB0SbFt1dpIxVbYYqt8Bst2a9c8SaQaanVDED1M4BDj5yj
+dipFtK+/fz6HP3bFzSreIMUWWMv5G/UPyw0RUmS40nZid4PxWJ//AgMBAAGjYzBh
+MB8GA1UdIwQYMBaAFFbn4VslQ4Dg9ozhcbyO5YAvxEjiMA8GA1UdEwEB/wQFMAMB
+Af8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRW5+FbJUOA4PaM4XG8juWAL8RI
+4jANBgkqhkiG9w0BAQUFAAOCAQEAg8ev6n9NCjw5sWi+e22JLumzCecYV42Fmhfz
+dkJQEw/HkG8zrcVJYCtsSVgZ1OK+t7+rSbyUyKu+KGwWaODIl0YgoGhnYIg5IFHY
+aAERzqf2EQf27OysGh+yZm5WZ2B6dF7AbZc2rrUNXWZzwCUyRdhKBgePxLcHsU0G
+DeGl6/R1yrqc0L2z0zIkTO5+4nYES0lT2PLpVDP85XEfPRRclkvxOvIAu2y0+pZV
+CIgJwcyRGSmwIC3/yzikQOEXvnlhgP8HA4ZMTnsGnxGGjYnuJ8Tb4rwZjgvDwxPH
+LQNjO9Po5KIqwoIIlBZU8O8fJ5AluA0OKBtHd0e9HKgl8ZS0Zg==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDcTCCAlmgAwIBAgIVAOYJ/nrqAGiM4CS07SAbH+9StETRMA0GCSqGSIb3DQEB
+BQUAMFAxCzAJBgNVBAYTAlBMMSgwJgYDVQQKDB9LcmFqb3dhIEl6YmEgUm96bGlj
+emVuaW93YSBTLkEuMRcwFQYDVQQDDA5TWkFGSVIgUk9PVCBDQTAeFw0xMTEyMDYx
+MTEwNTdaFw0zMTEyMDYxMTEwNTdaMFAxCzAJBgNVBAYTAlBMMSgwJgYDVQQKDB9L
+cmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRcwFQYDVQQDDA5TWkFGSVIg
+Uk9PVCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKxHL49ZMTml
+6g3wpYwrvQKkvc0Kc6oJ5sxfgmp1qZfluwbv88BdocHSiXlY8NzrVYzuWBp7J/9K
+ULMAoWoTIzOQ6C9TNm4YbA9A1jdX1wYNL5Akylf8W5L/I4BXhT9KnlI6x+a7BVAm
+nr/Ttl+utT/Asms2fRfEsF2vZPMxH4UFqOAhFjxTkmJWf2Cu4nvRQJHcttB+cEAo
+ag/hERt/+tzo4URz6x6r19toYmxx4FjjBkUhWQw1X21re//Hof2+0YgiwYT84zLb
+eqDqCOMOXxvH480yGDkh/QoazWX3U75HQExT/iJlwnu7I1V6HXztKIwCBjsxffbH
+3jOshCJtywcCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
+AQYwHQYDVR0OBBYEFFOSo33/gnbwM9TrkmdHYTMbaDsqMA0GCSqGSIb3DQEBBQUA
+A4IBAQA5UFWd5EL/pBviIMm1zD2JLUCpp0mJG7JkwznIOzawhGmFFaxGoxAhQBEg
+haP+E0KR66oAwVC6xe32QUVSHfWqWndzbODzLB8yj7WAR0cDM45ZngSBPBuFE3Wu
+GLJX9g100ETfIX+4YBR/4NR/uvTnpnd9ete7Whl0ZfY94yuu4xQqB5QFv+P7IXXV
+lTOjkjuGXEcyQAjQzbFaT9vIABSbeCXWBbjvOXukJy6WgAiclzGNSYprre8Ryydd
+fmjW9HIGwsIO03EldivvqEYL1Hv1w/Pur+6FUEOaL68PEIUovfgwIB2BAw+vZDuw
+cH0mX548PojGyg434cDjkSXa3mHF
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEPDCCAySgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvjE/MD0GA1UEAww2VMOc
+UktUUlVTVCBFbGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sx
+c8SxMQswCQYDVQQGEwJUUjEPMA0GA1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xS
+S1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kg
+SGl6bWV0bGVyaSBBLsWeLiAoYykgS2FzxLFtIDIwMDUwHhcNMDUxMTA3MTAwNzU3
+WhcNMTUwOTE2MTAwNzU3WjCBvjE/MD0GA1UEAww2VMOcUktUUlVTVCBFbGVrdHJv
+bmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJU
+UjEPMA0GA1UEBwwGQW5rYXJhMV0wWwYDVQQKDFRUw5xSS1RSVVNUIEJpbGdpIMSw
+bGV0acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWe
+LiAoYykgS2FzxLFtIDIwMDUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
+AQCpNn7DkUNMwxmYCMjHWHtPFoylzkkBH3MOrHUTpvqeLCDe2JAOCtFp0if7qnef
+J1Il4std2NiDUBd9irWCPwSOtNXwSadktx4uXyCcUHVPr+G1QRT0mJKIx+XlZEdh
+R3n9wFHxwZnn3M5q+6+1ATDcRhzviuyV79z/rxAc653YsKpqhRgNF8k+v/Gb0AmJ
+Qv2gQrSdiVFVKc8bcLyEVK3BEx+Y9C52YItdP5qtygy/p1Zbj3e41Z55SZI/4PGX
+JHpsmxcPbe9TmJEr5A++WXkHeLuXlfSfadRYhwqp48y2WBmfJiGxxFmNskF1wK1p
+zpwACPI2/z7woQ8arBT9pmAPAgMBAAGjQzBBMB0GA1UdDgQWBBTZN7NOBf3Zz58S
+Fq62iS/rJTqIHDAPBgNVHQ8BAf8EBQMDBwYAMA8GA1UdEwEB/wQFMAMBAf8wDQYJ
+KoZIhvcNAQEFBQADggEBAHJglrfJ3NgpXiOFX7KzLXb7iNcX/nttRbj2hWyfIvwq
+ECLsqrkw9qtY1jkQMZkpAL2JZkH7dN6RwRgLn7Vhy506vvWolKMiVW4XSf/SKfE4
+Jl3vpao6+XF75tpYHdN0wgH6PmlYX63LaL4ULptswLbcoCb6dxriJNoaN+BnrdFz
+gw2lGh1uEpJ+hGIAF728JRhX8tepb1mIvDS3LoV4nZbcFMMsilKbloxSZj2GFotH
+uFEJjOp9zYhys2AzsfAKRO8P9Qk3iCQOLGsgOqL6EfJANZxEaGM7rDNvY7wsu/LS
+y3Z9fYjYHcgFHW68lKlmjHdxx/qR+i9Rnuk5UrbnBEI=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDfTCCAmWgAwIBAgIBADANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJKUDEl
+MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEqMCgGA1UECxMh
+U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBFViBSb290Q0ExMB4XDTA3MDYwNjAyMTIz
+MloXDTM3MDYwNjAyMTIzMlowYDELMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09N
+IFRydXN0IFN5c3RlbXMgQ08uLExURC4xKjAoBgNVBAsTIVNlY3VyaXR5IENvbW11
+bmljYXRpb24gRVYgUm9vdENBMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBALx/7FebJOD+nLpCeamIivqA4PUHKUPqjgo0No0c+qe1OXj/l3X3L+SqawSE
+RMqm4miO/VVQYg+kcQ7OBzgtQoVQrTyWb4vVog7P3kmJPdZkLjjlHmy1V4qe70gO
+zXppFodEtZDkBp2uoQSXWHnvIEqCa4wiv+wfD+mEce3xDuS4GBPMVjZd0ZoeUWs5
+bmB2iDQL87PRsJ3KYeJkHcFGB7hj3R4zZbOOCVVSPbW9/wfrrWFVGCypaZhKqkDF
+MxRldAD5kd6vA0jFQFTcD4SQaCDFkpbcLuUCRarAX1T4bepJz11sS6/vmsJWXMY1
+VkJqMF/Cq/biPT+zyRGPMUzXn0kCAwEAAaNCMEAwHQYDVR0OBBYEFDVK9U2vP9eC
+OKyrcWUXdYydVZPmMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0G
+CSqGSIb3DQEBBQUAA4IBAQCoh+ns+EBnXcPBZsdAS5f8hxOQWsTvoMpfi7ent/HW
+tWS3irO4G8za+6xmiEHO6Pzk2x6Ipu0nUBsCMCRGef4Eh3CXQHPRwMFXGZpppSeZ
+q51ihPZRwSzJIxXYKLerJRO1RuGGAv8mjMSIkh1W/hln8lXkgKNrnKt34VFxDSDb
+EJrbvXZ5B3eZKK2aXtqxT0QsNY6llsf9g/BYxnnWmHyojf6GPgcWkuF75x3sM3Z+
+Qi5KhfmRiWiEA4Glm5q+4zfFVKtWOxgtQaQM+ELbmaDgcm+7XeEWT1MKZPlO9L9O
+VL14bIjqv5wTJMJwaaJ/D8g8rQjJsJhAoyrniIPtd490
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICqDCCAi2gAwIBAgIQNBdlEkA7t1aALYDLeVWmHjAKBggqhkjOPQQDAzCBlDEL
+MAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYD
+VQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBD
+bGFzcyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0g
+RzQwHhcNMTExMDA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBlDELMAkGA1UEBhMC
+VVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZTeW1h
+bnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBDbGFzcyAyIFB1
+YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcq
+hkjOPQIBBgUrgQQAIgNiAATR2UqOTA2ESlG6fO/TzPo6mrWnYxM9AeBJPvrBR8mS
+szrX/m+c95o6D/UOCgrDP8jnEhSO1dVtmCyzcTIK6yq99tdqIAtnRZzSsr9TImYJ
+XdsR8/EFM1ij4rjPfM2Cm72jQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E
+BTADAQH/MB0GA1UdDgQWBBQ9MvM6qQyQhPmijGkGYVQvh3L+BTAKBggqhkjOPQQD
+AwNpADBmAjEAyKapr0F/tckRQhZoaUxcuCcYtpjxwH+QbYfTjEYX8D5P/OqwCMR6
+S7wIL8fip29lAjEA1lnehs5fDspU1cbQFQ78i5Ry1I4AWFPPfrFLDeVQhuuea9//
+KabYR9mglhjb8kWz
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd
+MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg
+Q2xhc3MgMyBSb290IENBMB4XDTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFow
+TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw
+HgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB
+BQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRHsJ8Y
+ZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3E
+N3coTRiR5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9
+tznDDgFHmV0ST9tD+leh7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX
+0DJq1l1sDPGzbjniazEuOQAnFN44wOwZZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c
+/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH2xc519woe2v1n/MuwU8X
+KhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV/afmiSTY
+zIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvS
+O1UQRwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D
+34xFMFbG02SrZvPAXpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgP
+K9Dx2hzLabjKSWJtyNBjYt1gD1iqj6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3
+AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFEe4zf/lb+74suwv
+Tg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAACAj
+QTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV
+cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXS
+IGrs/CIBKM+GuIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2
+HJLw5QY33KbmkJs4j1xrG0aGQ0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsa
+O5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8ZORK15FTAaggiG6cX0S5y2CBNOxv
+033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2KSb12tjE8nVhz36u
+dmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz6MkE
+kbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg41
+3OEMXbugUZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvD
+u79leNKGef9JOxqDDPDeeOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq
+4/g7u9xN12TyUb7mqqta6THuBrxzvxNiCp/HuZc=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIF9jCCA96gAwIBAgIQZWNxhdNvRcaPfzH5CYeSgjANBgkqhkiG9w0BAQwFADCB
+lDELMAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8w
+HQYDVQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRl
+YyBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5
+IC0gRzYwHhcNMTIxMDE4MDAwMDAwWhcNMzcxMjAxMjM1OTU5WjCBlDELMAkGA1UE
+BhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZT
+eW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBDbGFzcyAz
+IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzYwggIi
+MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC3DrL6TbyachX7d1vb/UMPywv3
+YC6zK34Mu1PyzE5l8xm7/zUd99Opu0Attd141Kb5N+qFBXttt+YTSwZ8+3ZjjyAd
+LTgrBIXy6LDRX01KIclq2JTqHgJQpqqQB6BHIepm+QSg5oPwxPVeluInTWHDs8GM
+IrZmoQDRVin77cF/JMo9+lqUsITDx7pDHP1kDvEo+0dZ8ibhMblE+avd+76+LDfj
+rAsY0/wBovGkCjWCR0yrvYpe3xOF/CDMSFmvr0FvyyPNypOn3dVfyGQ7/wEDoApP
+LW49hL6vyDKyUymQFfewBZoKPPa5BpDJpeFdoDuw/qi2v/WJKFckOiGGceTciotB
+VeweMCRZ0cBZuHivqlp03iWAMJjtMERvIXAc2xJTDtamKGaTLB/MTzwbgcW59nhv
+0DI6CHLbaw5GF4WU87zvvPekXo7p6bVk5bdLRRIsTDe3YEMKTXEGAJQmNXQfu3o5
+XE475rgD4seTi4QsJUlF3X8jlGAfy+nN9quX92Hn+39igcjcCjBcGHzmzu/Hbh6H
+fLPpysh7avRo/IOlDFa0urKNSgrHl5fFiDAVPRAIVBVycmczM/R8t84AJ1NlziTx
+WmTnNi/yLgLCl99y6AIeoPc9tftoYAP6M6nmEm0G4amoXU48/tnnAGWsthlNe4N/
+NEfq4RhtsYsceavnnQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/
+BAUwAwEB/zAdBgNVHQ4EFgQUOXEIAD7eyIbnkP/k/SEPziQZFvYwDQYJKoZIhvcN
+AQEMBQADggIBAFBriE1gSM5a4yLOZ3yEp80c/ekMA4w2rwqHDmquV64B0Da78v25
+c8FftaiuTKL6ScsHRhY2vePIVzh+OOS/JTNgxtw3nGO7XpgeGrKC8K6mdxGAREeh
+KcXwszrOmPC47NMOgAZ3IzBM/3lkYyJbd5NDS3Wz2ztuO0rd8ciutTeKlYg6EGhw
+OLlbcH7VQ8n8X0/l5ns27vAg7UdXEyYQXhQGDXt2B8LGLRb0rqdsD7yID08sAraj
+1yLmmUc12I2lT4ESOhF9s8wLdfMecKMbA+r6mujmLjY5zJnOOj8Mt674Q5mwk25v
+qtkPajGRu5zTtCj7g0x6c4JQZ9IOrO1gxbJdNZjPh34eWR0kvFa62qRa2MzmvB4Q
+jxuMjvPB27e+1LBbZY8WaPNWxSoZFk0PuGWHbSSDuGLc4EdhGoh7zk5//dzGDVqa
+pPO1TPbdMaboHREhMzAEYX0c4D5PjT+1ixIAWn2poQDUg+twuxj4pNIcgS23CBHI
+Jnu21OUPA0Zy1CVAHr5JXW2T8VyyO3VUaTqg7kwiuqya4gitRWMFSlI1dsQ09V4H
+Mq3cfCbRW4+t5OaqG3Wf61206MCpFXxOSgdy30bJ1JGSdVaw4e43NmUoxRXIK3bM
+bW8Zg/T92hXiQeczeUaDV/nxpbZt07zXU+fucW14qZen7iCcGRVyFT0E
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQsw
+CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu
+ZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3Qg
+RzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQGEwJV
+UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu
+Y29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQBgcq
+hkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJf
+Zn4f5dwbRXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17Q
+RSAPWXYQ1qAk8C3eNvJsKTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/
+BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgFUaFNN6KDec6NHSrkhDAKBggqhkjOPQQD
+AwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5FyYZ5eEJJZVrmDxxDnOOlY
+JjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy1vUhZscv
+6pZjamVFkpUBtA==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEUzCCAzugAwIBAgIDAOJDMA0GCSqGSIb3DQEBBQUAMIHPMQswCQYDVQQGEwJB
+VDGBizCBiAYDVQQKHoGAAEEALQBUAHIAdQBzAHQAIABHAGUAcwAuACAAZgD8AHIA
+IABTAGkAYwBoAGUAcgBoAGUAaQB0AHMAcwB5AHMAdABlAG0AZQAgAGkAbQAgAGUA
+bABlAGsAdAByAC4AIABEAGEAdABlAG4AdgBlAHIAawBlAGgAcgAgAEcAbQBiAEgx
+GDAWBgNVBAsTD0EtVHJ1c3QtUXVhbC0wMTEYMBYGA1UEAxMPQS1UcnVzdC1RdWFs
+LTAxMB4XDTA0MTEzMDIzMDAwMFoXDTE0MTEzMDIzMDAwMFowgc8xCzAJBgNVBAYT
+AkFUMYGLMIGIBgNVBAoegYAAQQAtAFQAcgB1AHMAdAAgAEcAZQBzAC4AIABmAPwA
+cgAgAFMAaQBjAGgAZQByAGgAZQBpAHQAcwBzAHkAcwB0AGUAbQBlACAAaQBtACAA
+ZQBsAGUAawB0AHIALgAgAEQAYQB0AGUAbgB2AGUAcgBrAGUAaAByACAARwBtAGIA
+SDEYMBYGA1UECxMPQS1UcnVzdC1RdWFsLTAxMRgwFgYDVQQDEw9BLVRydXN0LVF1
+YWwtMDEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCmhgdxIbxTGEOH
+fXGiewI3NFldAWKFWfLofO+5I1UbvA5avt7IgsGXz/tI/f5HGUbascI0i7xG0tqV
+lA5ctQgLRqxgxHtgTkMcqsAEYdsz3LZsCdXO1QrvEBGLTSABdxiL/gSWJ6z77CSw
+x7Xg02HwxPV82cjGkSF3ENGJntuIAAnRDWn/ORHjFatNRymoMbHaOEZXSGhf7Y5F
+rrHEqGyi9E6sv784De/T1aTvskn8cWeUmDzv//omiG/a/V9KQex/61XN8OthUQVn
+X+u/liL2NKx74I2C/GgHX5B0WkPNqsSOgmlvJ/cKuT0PveUgVFDAA0oYBgcE1KDM
+lBbN0kmPAgMBAAGjNjA0MA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0OBAoECEs8jB2F
+6W+tMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAIUusmJzMJRiQ
+8TAHrJAOelfuWoTGcqdIv7Tys/fNl2yF2fjvHT8J01aKialFVpbVeQ2XKb1O2bHO
+QYAKgsdZ2jZ/sdL2UVFRTHmidLu6PdgWCBRhJYQELQophO9QVvfhAA0TwbESYqTz
++nlI5Gr7CZe8f6HEmhJmCtUQsdQCufGglRh4T+tIGiNGcnyVEHZ93mSVepFr1VA2
+9CTRPteuGjA81jeAz9peYiFE1CXvxK9cJiv0BcALFLWmADCoRLzIRZhA+sAwYUmw
+M1rqVCPA3kBQvIC95tyQvNy2dG0Vs+O6PwLaNX/suSlElQ06X2l1VwMaYb4vZKFq
+N0bOhBXEVg==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIJmzCCB4OgAwIBAgIBATANBgkqhkiG9w0BAQwFADCCAR4xPjA8BgNVBAMTNUF1
+dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIFJhaXogZGVsIEVzdGFkbyBWZW5lem9s
+YW5vMQswCQYDVQQGEwJWRTEQMA4GA1UEBxMHQ2FyYWNhczEZMBcGA1UECBMQRGlz
+dHJpdG8gQ2FwaXRhbDE2MDQGA1UEChMtU2lzdGVtYSBOYWNpb25hbCBkZSBDZXJ0
+aWZpY2FjaW9uIEVsZWN0cm9uaWNhMUMwQQYDVQQLEzpTdXBlcmludGVuZGVuY2lh
+IGRlIFNlcnZpY2lvcyBkZSBDZXJ0aWZpY2FjaW9uIEVsZWN0cm9uaWNhMSUwIwYJ
+KoZIhvcNAQkBFhZhY3JhaXpAc3VzY2VydGUuZ29iLnZlMB4XDTEwMTIyMjE4MDgy
+MVoXDTMwMTIxNzIzNTk1OVowggEeMT4wPAYDVQQDEzVBdXRvcmlkYWQgZGUgQ2Vy
+dGlmaWNhY2lvbiBSYWl6IGRlbCBFc3RhZG8gVmVuZXpvbGFubzELMAkGA1UEBhMC
+VkUxEDAOBgNVBAcTB0NhcmFjYXMxGTAXBgNVBAgTEERpc3RyaXRvIENhcGl0YWwx
+NjA0BgNVBAoTLVNpc3RlbWEgTmFjaW9uYWwgZGUgQ2VydGlmaWNhY2lvbiBFbGVj
+dHJvbmljYTFDMEEGA1UECxM6U3VwZXJpbnRlbmRlbmNpYSBkZSBTZXJ2aWNpb3Mg
+ZGUgQ2VydGlmaWNhY2lvbiBFbGVjdHJvbmljYTElMCMGCSqGSIb3DQEJARYWYWNy
+YWl6QHN1c2NlcnRlLmdvYi52ZTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoC
+ggIBAME77xNS8ZlW47RsBeEaaRZhJoZ4rw785UAFCuPZOAVMqNS1wMYqzy95q6Gk
+UO81ER/ugiQX/KMcq/4HBn83fwdYWxPZfwBfK7BP2p/JsFgzYeFP0BXOLmvoJIzl
+Jb6FW+1MPwGBjuaZGFImWZsSmGUclb51mRYMZETh9/J5CLThR1exStxHQptwSzra
+zNFpkQY/zmj7+YZNA9yDoroVFv6sybYOZ7OxNDo7zkSLo45I7gMwtxqWZ8VkJZkC
+8+p0dX6mkhUT0QAV64Zc9HsZiH/oLhEkXjhrgZ28cF73MXIqLx1fyM4kPH1yOJi/
+R72nMwL7D+Sd6mZgI035TxuHXc2/uOwXfKrrTjaJDz8Jp6DdessOkxIgkKXRjP+F
+K3ze3n4NUIRGhGRtyvEjK95/2g02t6PeYiYVGur6ruS49n0RAaSS0/LJb6XzaAAe
+0mmO2evnEqxIKwy2mZRNPfAVW1l3wCnWiUwryBU6OsbFcFFrQm+00wOicXvOTHBM
+aiCVAVZTb9RSLyi+LJ1llzJZO3pq3IRiiBj38Nooo+2ZNbMEciSgmig7YXaUcmud
+SVQvLSL+Yw+SqawyezwZuASbp7d/0rutQ59d81zlbMt3J7yB567rT2IqIydQ8qBW
+k+fmXzghX+/FidYsh/aK+zZ7Wy68kKHuzEw1Vqkat5DGs+VzAgMBAAGjggLeMIIC
+2jASBgNVHRMBAf8ECDAGAQH/AgECMDcGA1UdEgQwMC6CD3N1c2NlcnRlLmdvYi52
+ZaAbBgVghl4CAqASDBBSSUYtRy0yMDAwNDAzNi0wMB0GA1UdDgQWBBStuyIdxuDS
+Aaj9dlBSk+2YwU2u0zCCAVAGA1UdIwSCAUcwggFDgBStuyIdxuDSAaj9dlBSk+2Y
+wU2u06GCASakggEiMIIBHjE+MDwGA1UEAxM1QXV0b3JpZGFkIGRlIENlcnRpZmlj
+YWNpb24gUmFpeiBkZWwgRXN0YWRvIFZlbmV6b2xhbm8xCzAJBgNVBAYTAlZFMRAw
+DgYDVQQHEwdDYXJhY2FzMRkwFwYDVQQIExBEaXN0cml0byBDYXBpdGFsMTYwNAYD
+VQQKEy1TaXN0ZW1hIE5hY2lvbmFsIGRlIENlcnRpZmljYWNpb24gRWxlY3Ryb25p
+Y2ExQzBBBgNVBAsTOlN1cGVyaW50ZW5kZW5jaWEgZGUgU2VydmljaW9zIGRlIENl
+cnRpZmljYWNpb24gRWxlY3Ryb25pY2ExJTAjBgkqhkiG9w0BCQEWFmFjcmFpekBz
+dXNjZXJ0ZS5nb2IudmWCAQEwDgYDVR0PAQH/BAQDAgEGMDcGA1UdEQQwMC6CD3N1
+c2NlcnRlLmdvYi52ZaAbBgVghl4CAqASDBBSSUYtRy0yMDAwNDAzNi0wMFQGA1Ud
+HwRNMEswJKAioCCGHmhodHA6Ly93d3cuc3VzY2VydGUuZ29iLnZlL2xjcjAjoCGg
+H4YdbGRhcDovL2FjcmFpei5zdXNjZXJ0ZS5nb2IudmUwNwYIKwYBBQUHAQEEKzAp
+MCcGCCsGAQUFBzABhhtoaHRwOi8vb2NzcC5zdXNjZXJ0ZS5nb2IudmUwQAYDVR0g
+BDkwNzA1BgVghl4BAjAsMCoGCCsGAQUFBwIBFh5odHRwOi8vd3d3LnN1c2NlcnRl
+LmdvYi52ZS9kcGMwDQYJKoZIhvcNAQEMBQADggIBAK4qy/zmZ9zBwfW3yOYtLcBT
+Oy4szJyPz7/RhNH3bPVH7HbDTGpi6JZ4YXdXMBeJE5qBF4a590Kgj8Rlnltt+Rbo
+OFQOU1UDqKuTdBsA//Zry5899fmn8jBUkg4nh09jhHHbLlaUScdz704Zz2+UVg7i
+s/r3Legxap60KzmdrmTAE9VKte1TQRgavQwVX5/2mO/J+SCas//UngI+h8SyOucq
+mjudYEgBrZaodUsagUfn/+AzFNrGLy+al+5nZeHb8JnCfLHWS0M9ZyhgoeO/czyn
+99+5G93VWNv4zfc4KiavHZKrkn8F9pg0ycIZh+OwPT/RE2zq4gTazBMlP3ACIe/p
+olkNaOEa8KvgzW96sjBZpMW49zFmyINYkcj+uaNCJrVGsXgdBmkuRGJNWFZ9r0cG
+woIaxViFBypsz045r1ESfYPlfDOavBhZ/giR/Xocm9CHkPRY2BApMMR0DUCyGETg
+Ql+L3kfdTKzuDjUp2DM9FqysQmaM81YDZufWkMhlZPfHwC7KbNougoLroa5Umeos
+bqAXWmk46SwIdWRPLLqbUpDTKooynZKpSYIkkotdgJoVZUUCY+RCO8jsVPEU6ece
+SxztNUm5UOta1OJPMwSAKRHOo3ilVb9c6lAixDdvV8MeNbqe6asM1mpCHWbJ/0rg
+5Ls9Cxx8hracyp0ev7b0
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIGATCCA+mgAwIBAgIRAI9hcRW6eVgXjH0ROqzW264wDQYJKoZIhvcNAQELBQAw
+RTEfMB0GA1UEAxMWQ29tU2lnbiBHbG9iYWwgUm9vdCBDQTEVMBMGA1UEChMMQ29t
+U2lnbiBMdGQuMQswCQYDVQQGEwJJTDAeFw0xMTA3MTgxMDI0NTRaFw0zNjA3MTYx
+MDI0NTVaMEUxHzAdBgNVBAMTFkNvbVNpZ24gR2xvYmFsIFJvb3QgQ0ExFTATBgNV
+BAoTDENvbVNpZ24gTHRkLjELMAkGA1UEBhMCSUwwggIiMA0GCSqGSIb3DQEBAQUA
+A4ICDwAwggIKAoICAQCyKClzKh3rm6n1nvigmV/VU1D4hSwYW2ro3VqpzpPo0Ph3
+3LguqjXd5juDwN4mpxTpD99d7Xu5X6KGTlMVtfN+bTbA4t3x7DU0Zqn0BE5XuOgs
+3GLH41Vmr5wox1bShVpM+IsjcN4E/hMnDtt/Bkb5s33xCG+ohz5dlq0gA9qfr/g4
+O9lkHZXTCeYrmVzd/il4x79CqNvGkdL3um+OKYl8rg1dPtD8UsytMaDgBAopKR+W
+igc16QJzCbvcinlETlrzP/Ny76BWPnAQgaYBULax/Q5thVU+N3sEOKp6uviTdD+X
+O6i96gARU4H0xxPFI75PK/YdHrHjfjQevXl4J37FJfPMSHAbgPBhHC+qn/014DOx
+46fEGXcdw2BFeIIIwbj2GH70VyJWmuk/xLMCHHpJ/nIF8w25BQtkPpkwESL6esaU
+b1CyB4Vgjyf16/0nRiCAKAyC/DY/Yh+rDWtXK8c6QkXD2XamrVJo43DVNFqGZzbf
+5bsUXqiVDOz71AxqqK+p4ek9374xPNMJ2rB5MLPAPycwI0bUuLHhLy6nAIFHLhut
+TNI+6Y/soYpi5JSaEjcY7pxI8WIkUAzr2r+6UoT0vAdyOt7nt1y8844a7szo/aKf
+woziHl2O1w6ZXUC30K+ptXVaOiW79pBDcbLZ9ZdbONhS7Ea3iH4HJNwktrBJLQID
+AQABo4HrMIHoMA8GA1UdEwEB/wQFMAMBAf8wgYQGA1UdHwR9MHswPKA6oDiGNmh0
+dHA6Ly9mZWRpci5jb21zaWduLmNvLmlsL2NybC9jb21zaWduZ2xvYmFscm9vdGNh
+LmNybDA7oDmgN4Y1aHR0cDovL2NybDEuY29tc2lnbi5jby5pbC9jcmwvY29tc2ln
+bmdsb2JhbHJvb3RjYS5jcmwwDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBQCRZPY
+DUhirGm6rgZbPvuqJpFQsTAfBgNVHSMEGDAWgBQCRZPYDUhirGm6rgZbPvuqJpFQ
+sTANBgkqhkiG9w0BAQsFAAOCAgEAk1V5V9701xsfy4mfX+tP9Ln5e9h3N+QMwUfj
+kr+k3e8iXOqADjTpUHeBkEee5tJq09ZLp/43F5tZ2eHdYq2ZEX7iWHCnOQet6Yw9
+SU1TahsrGDA6JJD9sdPFnNZooGsU1520e0zNB0dNWwxrWAmu4RsBxvEpWCJbvzQL
+dOfyX85RWwli81OiVMBc5XvJ1mxsIIqli45oRynKtsWP7E+b0ISJ1n+XFLdQo/Nm
+WA/5sDfT0F5YPzWdZymudMbXitimxC+n4oQE4mbQ4Zm718Iwg3pP9gMMcSc7Qc1J
+kJHPH9O7gVubkKHuSYj9T3Ym6c6egL1pb4pz/uT7cT26Fiopc/jdqbe2EAfoJZkv
+hlp/zdzOoXTWjiKNA5zmgWnZn943FuE9KMRyKtyi/ezJXCh8ypnqLIKxeFfZl69C
+BwJsPXUTuqj8Fic0s3aZmmr7C4jXycP+Q8V+akMEIoHAxcd960b4wVWKqOcI/kZS
+Q0cYqWOY1LNjznRt9lweWEfwDBL3FhrHOmD4++1N3FkkM4W+Q1b2WOL24clDMj+i
+2n9Iw0lc1llHMSMvA5D0vpsXZpOgcCVahfXczQKi9wQ3oZyonJeWx4/rXdMtagAB
+VBYGFuMEUEQtybI+eIbnp5peO2WAAblQI4eTy/jMVowe5tfMEXovV3sz9ULgmGb3
+DscLP1I=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICmDCCAgGgAwIBAgIBDjANBgkqhkiG9w0BAQUFADBLMQswCQYDVQQGEwJVUzEY
+MBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNFQ0ExFDASBgNVBAMT
+C0VDQSBSb290IENBMB4XDTA0MDYxNDEwMjAwOVoXDTQwMDYxNDEwMjAwOVowSzEL
+MAkGA1UEBhMCVVMxGDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMD
+RUNBMRQwEgYDVQQDEwtFQ0EgUm9vdCBDQTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
+gYkCgYEArkr2eXIS6oAKIpDkOlcQZdMGdncoygCEIU+ktqY3of5SVVXU7/it7kJ1
+EUzR4ii2vthQtbww9aAnpQxcEmXZk8eEyiGEPy+cCQMllBY+efOtKgjbQNDZ3lB9
+19qzUJwBl2BMxslU1XsJQw9SK10lPbQm4asa8E8e5zTUknZBWnECAwEAAaOBizCB
+iDAfBgNVHSMEGDAWgBT2uAQnDlYW2blj2f2hVGVBoAhILzAdBgNVHQ4EFgQU9rgE
+Jw5WFtm5Y9n9oVRlQaAISC8wDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMB
+Af8wJQYDVR0gBB4wHDAMBgpghkgBZQMCAQwBMAwGCmCGSAFlAwIBDAIwDQYJKoZI
+hvcNAQEFBQADgYEAHh0EQY2cZ209aBb5q0wW1ER0dc4OGzsLyqjHfaQ4TEaMmUwL
+AJRta/c4KVWLiwbODsvgJk+CaWmSL03gRW/ciVb/qDV7qh9Pyd1cOlanZTAnPog2
+i82yL3i2fK9DCC84uoxEQbgqK2jx9bIjFTwlAqITk9fGAm5mdT84IEwq1Gw=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH
+MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT
+MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
+b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI
+2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx
+1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ
+q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz
+tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ
+vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP
+BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV
+5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY
+1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4
+NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG
+Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91
+8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe
+pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl
+MrY=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFSzCCAzOgAwIBAgIRALZLiAfiI+7IXBKtpg4GofIwDQYJKoZIhvcNAQELBQAw
+PzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dvdmVybm1lbnQgUm9vdCBDZXJ0aWZp
+Y2F0aW9uIEF1dGhvcml0eTAeFw0xMjA5MjgwODU4NTFaFw0zNzEyMzExNTU5NTla
+MD8xCzAJBgNVBAYTAlRXMTAwLgYDVQQKDCdHb3Zlcm5tZW50IFJvb3QgQ2VydGlm
+aWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
+AQC2/5c8gb4BWCQnr44BK9ZykjAyG1+bfNTUf+ihYHMwVxAA+lCWJP5Q5ow6ldFX
+eYTVZ1MMKoI+GFy4MCYa1l7GLbIEUQ7v3wxjR+vEEghRK5lxXtVpe+FdyXcdIOxW
+juVhYC386RyA3/pqg7sFtR4jEpyCygrzFB0g5AaPQySZn7YKk1pzGxY5vgW28Yyl
+ZJKPBeRcdvc5w88tvQ7Yy6gOMZvJRg9nU0MEj8iyyIOAX7ryD6uBNaIgIZfOD4k0
+eA/PH07p+4woPN405+2f0mb1xcoxeNLOUNFggmOd4Ez3B66DNJ1JSUPUfr0t4urH
+cWWACOQ2nnlwCjyHKenkkpTqBpIpJ3jmrdc96QoLXvTg1oadLXLLi2RW5vSueKWg
+OTNYPNyoj420ai39iHPplVBzBN8RiD5C1gJ0+yzEb7xs1uCAb9GGpTJXA9ZN9E4K
+mSJ2fkpAgvjJ5E7LUy3Hsbbi08J1J265DnGyNPy/HE7CPfg26QrMWJqhGIZO4uGq
+s3NZbl6dtMIIr69c/aQCb/+4DbvVq9dunxpPkUDwH0ZVbaCSw4nNt7H/HLPLo5wK
+4/7NqrwB7N1UypHdTxOHpPaY7/1J1lcqPKZc9mA3v9g+fk5oKiMyOr5u5CI9ByTP
+isubXVGzMNJxbc5Gim18SjNE2hIvNkvy6fFRCW3bapcOFwIDAQABo0IwQDAPBgNV
+HRMBAf8EBTADAQH/MB0GA1UdDgQWBBTVZx3gnHosnMvFmOcdByYqhux0zTAOBgNV
+HQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggIBAJA75cJTQijq9TFOjj2Rnk0J
+89ixUuZPrAwxIbvx6pnMg/y2KOTshAcOD06Xu29oRo8OURWV+Do7H1+CDgxxDryR
+T64zLiNB9CZrTxOH+nj2LsIPkQWXqmrBap+8hJ4IKifd2ocXhuGzyl3tOKkpboTe
+Rmv8JxlQpRJ6jH1i/NrnzLyfSa8GuCcn8on3Fj0Y5r3e9YwSkZ/jBI3+BxQaWqw5
+ghvxOBnhY+OvbLamURfr+kvriyL2l/4QOl+UoEtTcT9a4RD4co+WgN2NApgAYT2N
+vC2xR8zaXeEgp4wxXPHj2rkKhkfIoT0Hozymc26Uke1uJDr5yTDRB6iBfSZ9fYTf
+hsmL5a4NHr6JSFEVg5iWL0rrczTXdM3Jb9DCuiv2mv6Z3WAUjhv5nDk8f0OJU+jl
+wqu+Iq0nOJt3KLejY2OngeepaUXrjnhWzAWEx/uttjB8YwWfLYwkf0uLkvw4Hp+g
+pVezbp3YZLhwmmBScMip0P/GnO0QYV7Ngw5u6E0CQUridgR51lQ/ipgyFKDdLZzn
+uoJxo4ZVKZnSKdt1OvfbQ/+2W/u3fjWAjg1srnm3Ni2XUqGwB5wH5Ss2zQOXlL0t
+DjQG/MAWifw3VOTWzz0TBPKR2ck2Lj7FWtClTILD/y58Jnb38/1FoqVuVa4uzM8s
+iTTa9g3nkagQ6hed8vbs
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMC
+VVMxFDASBgNVBAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQ
+cmVtaXVtIEVDQzAeFw0xMDAxMjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJ
+BgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1UcnVzdDEgMB4GA1UEAwwXQWZmaXJt
+VHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNMF4bFZ0D
+0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQN8O9
+ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0G
+A1UdDgQWBBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4G
+A1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/Vs
+aobgxCd05DhT1wV/GzTjxi+zygk8N53X57hG8f2h4nECMEJZh0PUUd+60wkyWs6I
+flc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKMeQ==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd
+MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg
+Q2xhc3MgMiBSb290IENBMB4XDTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1ow
+TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw
+HgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB
+BQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1g1Lr
+6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPV
+L4O2fuPn9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC91
+1K2GScuVr1QGbNgGE41b/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHx
+MlAQTn/0hpPshNOOvEu/XAFOBz3cFIqUCqTqc/sLUegTBxj6DvEr0VQVfTzh97QZ
+QmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeffawrbD02TTqigzXsu8lkB
+arcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgIzRFo1clr
+Us3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLi
+FRhnBkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRS
+P/TizPJhk9H9Z2vXUq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN
+9SG9dKpN6nIDSdvHXx1iY8f93ZHsM+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxP
+AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMmAd+BikoL1Rpzz
+uvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAU18h
+9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s
+A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3t
+OluwlN5E40EIosHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo
++fsicdl9sz1Gv7SEr5AcD48Saq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7
+KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYdDnkM/crqJIByw5c/8nerQyIKx+u2
+DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWDLfJ6v9r9jv6ly0Us
+H8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0oyLQ
+I+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK7
+5t98biGCwWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h
+3PFaTWwyI0PurKju7koSCTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPz
+Y11aWOIv4x3kqdbQCtCev9eBCfHJxyYNrJgWVqA=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFaTCCA1GgAwIBAgIJAMMDmu5QkG4oMA0GCSqGSIb3DQEBBQUAMFIxCzAJBgNV
+BAYTAlNLMRMwEQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMu
+MRkwFwYDVQQDExBDQSBEaXNpZyBSb290IFIxMB4XDTEyMDcxOTA5MDY1NloXDTQy
+MDcxOTA5MDY1NlowUjELMAkGA1UEBhMCU0sxEzARBgNVBAcTCkJyYXRpc2xhdmEx
+EzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERpc2lnIFJvb3QgUjEw
+ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCqw3j33Jijp1pedxiy3QRk
+D2P9m5YJgNXoqqXinCaUOuiZc4yd39ffg/N4T0Dhf9Kn0uXKE5Pn7cZ3Xza1lK/o
+OI7bm+V8u8yN63Vz4STN5qctGS7Y1oprFOsIYgrY3LMATcMjfF9DCCMyEtztDK3A
+fQ+lekLZWnDZv6fXARz2m6uOt0qGeKAeVjGu74IKgEH3G8muqzIm1Cxr7X1r5OJe
+IgpFy4QxTaz+29FHuvlglzmxZcfe+5nkCiKxLU3lSCZpq+Kq8/v8kiky6bM+TR8n
+oc2OuRf7JT7JbvN32g0S9l3HuzYQ1VTW8+DiR0jm3hTaYVKvJrT1cU/J19IG32PK
+/yHoWQbgCNWEFVP3Q+V8xaCJmGtzxmjOZd69fwX3se72V6FglcXM6pM6vpmumwKj
+rckWtc7dXpl4fho5frLABaTAgqWjR56M6ly2vGfb5ipN0gTco65F97yLnByn1tUD
+3AjLLhbKXEAz6GfDLuemROoRRRw1ZS0eRWEkG4IupZ0zXWX4Qfkuy5Q/H6MMMSRE
+7cderVC6xkGbrPAXZcD4XW9boAo0PO7X6oifmPmvTiT6l7Jkdtqr9O3jw2Dv1fkC
+yC2fg69naQanMVXVz0tv/wQFx1isXxYb5dKj6zHbHzMVTdDypVP1y+E9Tmgt2BLd
+qvLmTZtJ5cUoobqwWsagtQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud
+DwEB/wQEAwIBBjAdBgNVHQ4EFgQUiQq0OJMa5qvum5EY+fU8PjXQ04IwDQYJKoZI
+hvcNAQEFBQADggIBADKL9p1Kyb4U5YysOMo6CdQbzoaz3evUuii+Eq5FLAR0rBNR
+xVgYZk2C2tXck8An4b58n1KeElb21Zyp9HWc+jcSjxyT7Ff+Bw+r1RL3D65hXlaA
+SfX8MPWbTx9BLxyE04nH4toCdu0Jz2zBuByDHBb6lM19oMgY0sidbvW9adRtPTXo
+HqJPYNcHKfyyo6SdbhWSVhlMCrDpfNIZTUJG7L399ldb3Zh+pE3McgODWF3vkzpB
+emOqfDqo9ayk0d2iLbYq/J8BjuIQscTK5GfbVSUZP/3oNn6z4eGBrxEWi1CXYBmC
+AMBrTXO40RMHPuq2MU/wQppt4hF05ZSsjYSVPCGvxdpHyN85YmLLW1AL14FABZyb
+7bq2ix4Eb5YgOe2kfSnbSM6C3NQCjR0EMVrHS/BsYVLXtFHCgWzN4funodKSds+x
+DzdYpPJScWc/DIh4gInByLUfkmO+p3qKViwaqKactV2zY9ATIKHrkWzQjX2v3wvk
+F7mGnjixlAxYjOBVqjtjbZqJYLhkKpLGN/R+Q0O3c+gB53+XD9fyexn9GtePyfqF
+a3qdnom2piiZk4hA9z7NUaPK6u95RyG1/jLix8NRb76AdPCkwzryT+lf3xkK8jsT
+Q6wxpLPn6/wY1gGp8yqPNg7rtLG8t0zJa7+h89n07eLw4+1knj0vllJPgFOL
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIID9jCCAt6gAwIBAgIQJDJ18h0v0gkz97RqytDzmDANBgkqhkiG9w0BAQsFADCB
+lDELMAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8w
+HQYDVQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRl
+YyBDbGFzcyAxIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5
+IC0gRzYwHhcNMTExMDE4MDAwMDAwWhcNMzcxMjAxMjM1OTU5WjCBlDELMAkGA1UE
+BhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZT
+eW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBDbGFzcyAx
+IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzYwggEi
+MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDHOddJZKmZgiJM6kXZBxbje/SD
+6Jlz+muxNuCad6BAwoGNAcfMjL2Pffd543pMA03Z+/2HOCgs3ZqLVAjbZ/sbjP4o
+ki++t7JIp4Gh2F6Iw8w5QEFa0dzl2hCfL9oBTf0uRnz5LicKaTfukaMbasxEvxvH
+w9QRslBglwm9LiL1QYRmn81ApqkAgMEflZKf3vNI79sdd2H8f9/ulqRy0LY+/3gn
+r8uSFWkI22MQ4uaXrG7crPaizh5HmbmJtxLmodTNWRFnw2+F2EJOKL5ZVVkElauP
+N4C/DfD8HzpkMViBeNfiNfYgPym4jxZuPkjctUwH4fIa6n4KedaovetdhitNAgMB
+AAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW
+BBQzQejIORIVk0jyljIuWvXalF9TYDANBgkqhkiG9w0BAQsFAAOCAQEAFeNzV7EX
+tl9JaUSm9l56Z6zS3nVJq/4lVcc6yUQVEG6/MWvL2QeTfxyFYwDjMhLgzMv7OWyP
+4lPiPEAz2aSMR+atWPuJr+PehilWNCxFuBL6RIluLRQlKCQBZdbqUqwFblYSCT3Q
+dPTXvQbKqDqNVkL6jXI+dPEDct+HG14OelWWLDi3mIXNTTNEyZSPWjEwN0ujOhKz
+5zbRIWhLLTjmU64cJVYIVgNnhJ3Gw84kYsdMNs+wBkS39V8C3dlU6S+QTnrIToNA
+DJqXPDe/v+z28LSFdyjBC8hnghAXOKK3Buqbvzr46SMHv3TgmDgVVXjucgBcGaP0
+0jPg/73RVDkpDw==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNV
+BAYTAlNLMRMwEQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMu
+MRkwFwYDVQQDExBDQSBEaXNpZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQy
+MDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sxEzARBgNVBAcTCkJyYXRpc2xhdmEx
+EzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERpc2lnIFJvb3QgUjIw
+ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbCw3Oe
+NcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNH
+PWSb6WiaxswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3I
+x2ymrdMxp7zo5eFm1tL7A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbe
+QTg06ov80egEFGEtQX6sx3dOy1FU+16SGBsEWmjGycT6txOgmLcRK7fWV8x8nhfR
+yyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqVg8NTEQxzHQuyRpDRQjrO
+QG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa5Beny912
+H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJ
+QfYEkoopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUD
+i/ZnWejBBhG93c+AAk9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORs
+nLMOPReisjQS1n6yqEm70XooQL6iFh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1
+rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud
+DwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5uQu0wDQYJKoZI
+hvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM
+tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqf
+GopTpti72TVVsRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkb
+lvdhuDvEK7Z4bLQjb/D907JedR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka
++elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W81k/BfDxujRNt+3vrMNDcTa/F1bal
+TFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjxmHHEt38OFdAlab0i
+nSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01utI3
+gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18Dr
+G5gPcFw0sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3Os
+zMOl6W8KjptlwlCFtaOgUxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8x
+L4ysEr3vQCj8KWefshNPZiTEUxnpHikV7+ZtsH8tZ/3zbBt1RqPlShfppNcL
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh
+MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE
+YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3
+MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo
+ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg
+MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN
+ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA
+PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w
+wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi
+EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY
+avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+
+YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE
+sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h
+/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5
+IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj
+YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD
+ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy
+OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P
+TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ
+HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER
+dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf
+ReYNnyicsbkqWletNw+vHX/bvZ8=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEGjCCAwKgAwIBAgIDAYagMA0GCSqGSIb3DQEBBQUAMIGjMQswCQYDVQQGEwJG
+STEQMA4GA1UECBMHRmlubGFuZDEhMB8GA1UEChMYVmFlc3RvcmVraXN0ZXJpa2Vz
+a3VzIENBMSkwJwYDVQQLEyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBTZXJ2aWNl
+czEZMBcGA1UECxMQVmFybWVubmVwYWx2ZWx1dDEZMBcGA1UEAxMQVlJLIEdvdi4g
+Um9vdCBDQTAeFw0wMjEyMTgxMzUzMDBaFw0yMzEyMTgxMzUxMDhaMIGjMQswCQYD
+VQQGEwJGSTEQMA4GA1UECBMHRmlubGFuZDEhMB8GA1UEChMYVmFlc3RvcmVraXN0
+ZXJpa2Vza3VzIENBMSkwJwYDVQQLEyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSBT
+ZXJ2aWNlczEZMBcGA1UECxMQVmFybWVubmVwYWx2ZWx1dDEZMBcGA1UEAxMQVlJL
+IEdvdi4gUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALCF
+FdrIAzfQo0Y3bBseljDCWoUSZyPyu5/nioFgJ/gTqTy894aqqvTzJSm0/nWuHoGG
+igWyHWWyOOi0zCia+xc28ZPVec7Bg4shT8MNrUHfeJ1I4x9CRPw8bSEga60ihCRC
+jxdNwlAfZM0tOSJWiP2yY51U2kJpwMhP1xjiPshphJQ9LIDGfM6911Mf64i5psu7
+hVfvV3ZdDIvTXhJBnyHAOfQmbQj6OLOhd7HuFtjQaNq0mKWgZUZKa41+qk1guPjI
+DfxxPu45h4G02fhukO4/DmHXHSto5i7hQkQmeCxY8n0Wf2HASSQqiYe2XS8pGfim
+545SnkFLWg6quMJmQlMCAwEAAaNVMFMwDwYDVR0TAQH/BAUwAwEB/zARBglghkgB
+hvhCAQEEBAMCAAcwDgYDVR0PAQH/BAQDAgHGMB0GA1UdDgQWBBTb6eGb0tEkC/yr
+46Bn6q6cS3f0sDANBgkqhkiG9w0BAQUFAAOCAQEArX1ID1QRnljurw2bEi8hpM2b
+uoRH5sklVSPj3xhYKizbXvfNVPVRJHtiZ+GxH0mvNNDrsczZog1Sf0JLiGCXzyVy
+t08pLWKfT6HAVVdWDsRol5EfnGTCKTIB6dTI2riBmCguGMcs/OubUpbf9MiQGS0j
+8/G7cdqehSO9Gu8u5Hp5t8OdhkktY7ktdM9lDzJmid87Ie4pbzlj2RXBbvbfgD5Q
+eBmK3QOjFKU3p7UsfLYRh+cF8ry23tT/l4EohP7+bEaFEEGfTXWMB9SZZ291im/k
+UJL2mdUQuMSpe/cXjUu/15WfCdxEDx4yw8DP03kN5Mc7h/CQNIghYkmSBAQfvA==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDujCCAqKgAwIBAgIEAJiWijANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJO
+TDEeMBwGA1UEChMVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSYwJAYDVQQDEx1TdGFh
+dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQTAeFw0wMjEyMTcwOTIzNDlaFw0xNTEy
+MTYwOTE1MzhaMFUxCzAJBgNVBAYTAk5MMR4wHAYDVQQKExVTdGFhdCBkZXIgTmVk
+ZXJsYW5kZW4xJjAkBgNVBAMTHVN0YWF0IGRlciBOZWRlcmxhbmRlbiBSb290IENB
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmNK1URF6gaYUmHFtvszn
+ExvWJw56s2oYHLZhWtVhCb/ekBPHZ+7d89rFDBKeNVU+LCeIQGv33N0iYfXCxw71
+9tV2U02PjLwYdjeFnejKScfST5gTCaI+Ioicf9byEGW07l8Y1Rfj+MX94p2i71MO
+hXeiD+EwR+4A5zN9RGcaC1Hoi6CeUJhoNFIfLm0B8mBF8jHrqTFoKbt6QZ7GGX+U
+tFE5A3+y3qcym7RHjm+0Sq7lr7HcsBthvJly3uSJt3omXdozSVtSnA71iq3DuD3o
+BmrC1SoLbHuEvVYFy4ZlkuxEK7COudxwC0barbxjiDn622r+I/q85Ej0ZytqERAh
+SQIDAQABo4GRMIGOMAwGA1UdEwQFMAMBAf8wTwYDVR0gBEgwRjBEBgRVHSAAMDww
+OgYIKwYBBQUHAgEWLmh0dHA6Ly93d3cucGtpb3ZlcmhlaWQubmwvcG9saWNpZXMv
+cm9vdC1wb2xpY3kwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSofeu8Y6R0E3QA
+7Jbg0zTBLL9s+DANBgkqhkiG9w0BAQUFAAOCAQEABYSHVXQ2YcG70dTGFagTtJ+k
+/rvuFbQvBgwp8qiSpGEN/KtcCFtREytNwiphyPgJWPwtArI5fZlmgb9uXJVFIGzm
+eafR2Bwp/MIgJ1HI8XxdNGdphREwxgDS1/PTfLbwMVcoEoJz6TMvplW0C5GUR5z6
+u3pCMuiufi3IvKwUv9kP2Vv8wfl6leF9fpb8cbDCTMjfRTTJzg3ynGQI0DvDKcWy
+7ZAEwbEpkcUwb8GpcjPM/l0WFywRaed+/sWDCN+83CI6LiBpIzlWYGeQiy52OfsR
+iJf2fL1LuCAWZwWN4jvBcj+UlTfHXbme2JOhF4//DGYVwSR8MnwDHTuhWEUykw==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDEl
+MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMe
+U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoX
+DTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRy
+dXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3VyaXR5IENvbW11bmlj
+YXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANAV
+OVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGr
+zbl+dp+++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVM
+VAX3NuRFg3sUZdbcDE3R3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQ
+hNBqyjoGADdH5H5XTz+L62e4iKrFvlNVspHEfbmwhRkGeC7bYRr6hfVKkaHnFtWO
+ojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1KEOtOghY6rCcMU/Gt1SSw
+awNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8QIH4D5cs
+OPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3
+DQEBCwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpF
+coJxDjrSzG+ntKEju/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXc
+okgfGT+Ok+vx+hfuzU7jBBJV1uXk3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8
+t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6qtnRGEmyR7jTV7JqR50S+kDFy
+1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29mvVXIwAHIRc/
+SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEHjCCAwagAwIBAgIBATANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJTRTEU
+MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3
+b3JrMSMwIQYDVQQDExpBZGRUcnVzdCBRdWFsaWZpZWQgQ0EgUm9vdDAeFw0wMDA1
+MzAxMDQ0NTBaFw0yMDA1MzAxMDQ0NTBaMGcxCzAJBgNVBAYTAlNFMRQwEgYDVQQK
+EwtBZGRUcnVzdCBBQjEdMBsGA1UECxMUQWRkVHJ1c3QgVFRQIE5ldHdvcmsxIzAh
+BgNVBAMTGkFkZFRydXN0IFF1YWxpZmllZCBDQSBSb290MIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEA5B6a/twJWoekn0e+EV+vhDTbYjx5eLfpMLXsDBwq
+xBb/4Oxx64r1EW7tTw2R0hIYLUkVAcKkIhPHEWT/IhKauY5cLwjPcWqzZwFZ8V1G
+87B4pfYOQnrjfxvM0PC3KP0q6p6zsLkEqv32x7SxuCqg+1jxGaBvcCV+PmlKfw8i
+2O+tCBGaKZnhqkRFmhJePp1tUvznoD1oL/BLcHwTOK28FSXx1s6rosAx1i+f4P8U
+WfyEk9mHfExUE+uf0S0R+Bg6Ot4l2ffTQO2kBhLEO+GRwVY18BTcZTYJbqukB8c1
+0cIDMzZbdSZtQvESa0NvS3GU+jQd7RNuyoB/mC9suWXY6QIDAQABo4HUMIHRMB0G
+A1UdDgQWBBQ5lYtii1zJ1IC6WA+XPxUIQ8yYpzALBgNVHQ8EBAMCAQYwDwYDVR0T
+AQH/BAUwAwEB/zCBkQYDVR0jBIGJMIGGgBQ5lYtii1zJ1IC6WA+XPxUIQ8yYp6Fr
+pGkwZzELMAkGA1UEBhMCU0UxFDASBgNVBAoTC0FkZFRydXN0IEFCMR0wGwYDVQQL
+ExRBZGRUcnVzdCBUVFAgTmV0d29yazEjMCEGA1UEAxMaQWRkVHJ1c3QgUXVhbGlm
+aWVkIENBIFJvb3SCAQEwDQYJKoZIhvcNAQEFBQADggEBABmrder4i2VhlRO6aQTv
+hsoToMeqT2QbPxj2qC0sVY8FtzDqQmodwCVRLae/DLPt7wh/bDxGGuoYQ992zPlm
+hpwsaPXpF/gxsxjE1kh9I0xowX67ARRvxdlu3rsEQmr49lx95dr6h+sNNVJn0J6X
+dgWTP5XHAeZpVTh/EGGZyeNfpso+gmNIquIISD6q8rKFYqa0p9m9N5xotS1WfbC3
+P6CxB9bpT9zeRXEwMn8bLgn5v1Kh7sKAPgZcLlVAwRv1cEWw3F369nJad9Jjzc9Y
+iQBCYz95OdBEsIJuQRno3eDBiFrRHnGTHyQwdOUeqN48Jzd/g66ed8/wMLH/S5no
+xqE=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIEXDCCA0SgAwIBAgIEOGO5ZjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML
+RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp
+bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5
+IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp
+ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0xOTEy
+MjQxODIwNTFaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3
+LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp
+YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG
+A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq
+K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe
+sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX
+MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT
+XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/
+HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH
+4QIDAQABo3QwcjARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUVeSB0RGA
+vtiJuQijMfmhJAkWuXAwHQYDVR0OBBYEFFXkgdERgL7YibkIozH5oSQJFrlwMB0G
+CSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEA
+WUesIYSKF8mciVMeuoCFGsY8Tj6xnLZ8xpJdGGQC49MGCBFhfGPjK50xA3B20qMo
+oPS7mmNz7W3lKtvtFKkrxjYR0CvrB4ul2p5cGZ1WEvVUKcgF7bISKo30Axv/55IQ
+h7A6tcOdBTcSo8f0FbnVpDkWm1M6I5HxqIKiaohowXkCIryqptau37AUX7iH0N18
+f3v/rxzP5tsHrV7bhZ3QKw0z2wTR5klAEyt2+z7pnIkPFc4YsIV4IU9rTw76NmfN
+B/L/CNDi3tm/Kq+4h4YhPATKt5Rof8886ZjXOP/swNlQ8C5LWK5Gb9Auw2DaclVy
+vUxFnmG6v4SBkgPR0ml8xQ==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFkjCCA3qgAwIBAgIIAeDltYNno+AwDQYJKoZIhvcNAQEMBQAwZzEbMBkGA1UE
+AwwSQXBwbGUgUm9vdCBDQSAtIEcyMSYwJAYDVQQLDB1BcHBsZSBDZXJ0aWZpY2F0
+aW9uIEF1dGhvcml0eTETMBEGA1UECgwKQXBwbGUgSW5jLjELMAkGA1UEBhMCVVMw
+HhcNMTQwNDMwMTgxMDA5WhcNMzkwNDMwMTgxMDA5WjBnMRswGQYDVQQDDBJBcHBs
+ZSBSb290IENBIC0gRzIxJjAkBgNVBAsMHUFwcGxlIENlcnRpZmljYXRpb24gQXV0
+aG9yaXR5MRMwEQYDVQQKDApBcHBsZSBJbmMuMQswCQYDVQQGEwJVUzCCAiIwDQYJ
+KoZIhvcNAQEBBQADggIPADCCAgoCggIBANgREkhI2imKScUcx+xuM23+TfvgHN6s
+XuI2pyT5f1BrTM65MFQn5bPW7SXmMLYFN14UIhHF6Kob0vuy0gmVOKTvKkmMXT5x
+ZgM4+xb1hYjkWpIMBDLyyED7Ul+f9sDx47pFoFDVEovy3d6RhiPw9bZyLgHaC/Yu
+OQhfGaFjQQscp5TBhsRTL3b2CtcM0YM/GlMZ81fVJ3/8E7j4ko380yhDPLVoACVd
+J2LT3VXdRCCQgzWTxb+4Gftr49wIQuavbfqeQMpOhYV4SbHXw8EwOTKrfl+q04tv
+ny0aIWhwZ7Oj8ZhBbZF8+NfbqOdfIRqMM78xdLe40fTgIvS/cjTf94FNcX1RoeKz
+8NMoFnNvzcytN31O661A4T+B/fc9Cj6i8b0xlilZ3MIZgIxbdMYs0xBTJh0UT8TU
+gWY8h2czJxQI6bR3hDRSj4n4aJgXv8O7qhOTH11UL6jHfPsNFL4VPSQ08prcdUFm
+IrQB1guvkJ4M6mL4m1k8COKWNORj3rw31OsMiANDC1CvoDTdUE0V+1ok2Az6DGOe
+HwOx4e7hqkP0ZmUoNwIx7wHHHtHMn23KVDpA287PT0aLSmWaasZobNfMmRtHsHLD
+d4/E92GcdB/O/WuhwpyUgquUoue9G7q5cDmVF8Up8zlYNPXEpMZ7YLlmQ1A/bmH8
+DvmGqmAMQ0uVAgMBAAGjQjBAMB0GA1UdDgQWBBTEmRNsGAPCe8CjoA1/coB6HHcm
+jTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQwF
+AAOCAgEAUabz4vS4PZO/Lc4Pu1vhVRROTtHlznldgX/+tvCHM/jvlOV+3Gp5pxy+
+8JS3ptEwnMgNCnWefZKVfhidfsJxaXwU6s+DDuQUQp50DhDNqxq6EWGBeNjxtUVA
+eKuowM77fWM3aPbn+6/Gw0vsHzYmE1SGlHKy6gLti23kDKaQwFd1z4xCfVzmMX3z
+ybKSaUYOiPjjLUKyOKimGY3xn83uamW8GrAlvacp/fQ+onVJv57byfenHmOZ4VxG
+/5IFjPoeIPmGlFYl5bRXOJ3riGQUIUkhOb9iZqmxospvPyFgxYnURTbImHy99v6Z
+SYA7LNKmp4gDBDEZt7Y6YUX6yfIjyGNzv1aJMbDZfGKnexWoiIqrOEDCzBL/FePw
+N983csvMmOa/orz6JopxVtfnJBtIRD6e/J/JzBrsQzwBvDR4yGn1xuZW7AYJNpDr
+FEobXsmII9oDMJELuDY++ee1KG++P+w8j2Ud5cAeh6Squpj9kuNsJnfdBrRkBof0
+Tta6SqoWqPQFZ2aWuuJVecMsXUmPgEkrihLHdoBR37q9ZV0+N0djMenl9MU/S60E
+inpxLK8JQzcPqOMyT/RFtm2XNuyE9QoB6he7hY1Ck3DDUOUUi78/w0EP3SIEIwiK
+um1xRKtzCTrJ+VKACd+66eYWyi4uTLLT3OUEVLLUNIAytbwPF+E=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDtDCCApygAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJKUDEc
+MBoGA1UEChMTSmFwYW5lc2UgR292ZXJubWVudDEOMAwGA1UECxMFTVBIUFQxJjAk
+BgNVBAsTHU1QSFBUIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTAyMDMxNDA3
+NTAyNloXDTEyMDMxMzE0NTk1OVowYzELMAkGA1UEBhMCSlAxHDAaBgNVBAoTE0ph
+cGFuZXNlIEdvdmVybm1lbnQxDjAMBgNVBAsTBU1QSFBUMSYwJAYDVQQLEx1NUEhQ
+VCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBAI3GUWlK9G9FVm8DhpKu5t37oxZbj6lZcFvEZY07YrYojWO657ub
+z56WE7q/PI/6Sm7i7qYE+Vp80r6thJvfmn7SS3BENrRqiapSenhooYD12jIe3iZQ
+2SXqx7WgYwyBGdQwGaYTijzbRFpgc0K8o4a99fIoHhz9J8AKqXasddMCqfJRaH30
+YJ7HnOvRYGL6HBrGhJ7X4Rzijyk9a9+3VOBsYcnIlx9iODoiYhA6r0ojuIu8/JA1
+oTTZrS0MyU/SLdFdJze2O1wnqTULXQybzJz3ad6oC/F5a69c0m92akYd9nGBrPxj
+EhucaQynC/QoCLs3aciLgioAnEJqy7i3EgUCAwEAAaNzMHEwHwYDVR0jBBgwFoAU
+YML3pLoA0h93Yngl8Gb/UgAh73owHQYDVR0OBBYEFGDC96S6ANIfd2J4JfBm/1IA
+Ie96MAwGA1UdEwQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQE
+AwIABTANBgkqhkiG9w0BAQUFAAOCAQEANPR8DN66iWZBs/lSm1vOzhqRkXDLT6xL
+LvJtjPLqmE469szGyFSKzsof6y+/8YgZlOoeX1inF4ox/SH1ATnwdIIsPbXuRLjt
+axboXvBh5y2ffC3hmzJVvJ87tb6mVWQeL9VFUhNhAI0ib+9OIZVEYI/64MFkDk4e
+iWG5ts6oqIJH1V7dVZg6pQ1Tc0Ckhn6N1m1hD30S0/zoPn/20Wq6OCF3he8VJrRG
+dcW9BD/Bkesko1HKhMBDjHVrJ8cFwbnDSoo+Ki47eJWaz/cOzaSsaMVUsR5POava
+/abhhgHn/eOJdXiVslyK0DYscjsdB3aBUfwZlomxYOzG6CgjQPhJdw==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIID9zCCAt+gAwIBAgILMTI1MzcyODI4MjgwDQYJKoZIhvcNAQELBQAwWDELMAkG
+A1UEBhMCSlAxHDAaBgNVBAoTE0phcGFuZXNlIEdvdmVybm1lbnQxDTALBgNVBAsT
+BEdQS0kxHDAaBgNVBAMTE0FwcGxpY2F0aW9uQ0EyIFJvb3QwHhcNMTMwMzEyMTUw
+MDAwWhcNMzMwMzEyMTUwMDAwWjBYMQswCQYDVQQGEwJKUDEcMBoGA1UEChMTSmFw
+YW5lc2UgR292ZXJubWVudDENMAsGA1UECxMER1BLSTEcMBoGA1UEAxMTQXBwbGlj
+YXRpb25DQTIgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKaq
+rSVl1gAR1uh6dqr05rRL88zDUrSNrKZPtZJxb0a11a2LEiIXJc5F6BR6hZrkIxCo
++rFnUOVtR+BqiRPjrq418fRCxQX3TZd+PCj8sCaRHoweOBqW3FhEl2LjMsjRFUFN
+dZh4vqtoqV7tR76kuo6hApfek3SZbWe0BSXulMjtqqS6MmxCEeu+yxcGkOGThchk
+KM4fR8fAXWDudjbcMztR63vPctgPeKgZggiQPhqYjY60zxU2pm7dt+JNQCBT2XYq
+0HisifBPizJtROouurCp64ndt295D6uBbrjmiykLWa+2SQ1RLKn9nShjZrhwlXOa
+2Po7M7xCQhsyrLEy+z0CAwEAAaOBwTCBvjAdBgNVHQ4EFgQUVqesqgIdsqw9kA6g
+by5Bxnbne9owDgYDVR0PAQH/BAQDAgEGMHwGA1UdEQR1MHOkcTBvMQswCQYDVQQG
+EwJKUDEYMBYGA1UECgwP5pel5pys5Zu95pS/5bqcMRswGQYDVQQLDBLmlL/lupzo
+qo3oqLzln7rnm6QxKTAnBgNVBAMMIOOCouODl+ODquOCseODvOOCt+ODp+ODs0NB
+MiBSb290MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAH+aCXWs
+B9FydC53VzDCBJzUgKaD56WgG5/+q/OAvdVKo6GPtkxgEefK4WCB10jBIFmlYTKL
+nZ6X02aD2mUuWD7b5S+lzYxzplG+WCigeVxpL0PfY7KJR8q73rk0EWOgDiUX5Yf0
+HbCwpc9BqHTG6FPVQvSCLVMJEWgmcZR1E02qdog8dLHW40xPYsNJTE5t8XB+w3+m
+Bcx4m+mB26jIx1ye/JKSLaaX8ji1bnOVDMA/zqaUMLX6BbfeniCq/BNkyYq6ZO/i
+Y+TYmK5rtT6mVbgzPixy+ywRAPtbFi+E0hOe+gXFwctyTiLdhMpLvNIthhoEdlkf
+SUJiOxMfFui61/0=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV
+UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy
+dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1
+MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx
+dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B
+AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f
+BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A
+cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC
+AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ
+MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm
+aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw
+ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj
+IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF
+MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA
+A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y
+7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh
+1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDEL
+MAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChj
+KSAyMDA3IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2
+MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0
+eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1OVowgZgxCzAJBgNV
+BAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykgMjAw
+NyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNV
+BAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH
+MjB2MBAGByqGSM49AgEGBSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcL
+So17VDs6bl8VAsBQps8lL33KSLjHUGMcKiEIfJo22Av+0SbFWDEwKCXzXV2juLal
+tJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO
+BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+EVXVMAoG
+CCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGT
+qQ7mndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBucz
+rD6ogRLQy7rQkgu2npaqBA+K
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIFcDCCA1igAwIBAgIEAJiWjTANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJO
+TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSkwJwYDVQQDDCBTdGFh
+dCBkZXIgTmVkZXJsYW5kZW4gRVYgUm9vdCBDQTAeFw0xMDEyMDgxMTE5MjlaFw0y
+MjEyMDgxMTEwMjhaMFgxCzAJBgNVBAYTAk5MMR4wHAYDVQQKDBVTdGFhdCBkZXIg
+TmVkZXJsYW5kZW4xKTAnBgNVBAMMIFN0YWF0IGRlciBOZWRlcmxhbmRlbiBFViBS
+b290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA48d+ifkkSzrS
+M4M1LGns3Amk41GoJSt5uAg94JG6hIXGhaTK5skuU6TJJB79VWZxXSzFYGgEt9nC
+UiY4iKTWO0Cmws0/zZiTs1QUWJZV1VD+hq2kY39ch/aO5ieSZxeSAgMs3NZmdO3d
+Z//BYY1jTw+bbRcwJu+r0h8QoPnFfxZpgQNH7R5ojXKhTbImxrpsX23Wr9GxE46p
+rfNeaXUmGD5BKyF/7otdBwadQ8QpCiv8Kj6GyzyDOvnJDdrFmeK8eEEzduG/L13l
+pJhQDBXd4Pqcfzho0LKmeqfRMb1+ilgnQ7O6M5HTp5gVXJrm0w912fxBmJc+qiXb
+j5IusHsMX/FjqTf5m3VpTCgmJdrV8hJwRVXj33NeN/UhbJCONVrJ0yPr08C+eKxC
+KFhmpUZtcALXEPlLVPxdhkqHz3/KRawRWrUgUY0viEeXOcDPusBCAUCZSCELa6fS
+/ZbV0b5GnUngC6agIk440ME8MLxwjyx1zNDFjFE7PZQIZCZhfbnDZY8UnCHQqv0X
+cgOPvZuM5l5Tnrmd74K74bzickFbIZTTRTeU0d8JOV3nI6qaHcptqAqGhYqCvkIH
+1vI4gnPah1vlPNOePqc7nvQDs/nxfRN0Av+7oeX6AHkcpmZBiFxgV6YuCcS6/ZrP
+px9Aw7vMWgpVSzs4dlG4Y4uElBbmVvMCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB
+/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFP6rAJCYniT8qcwaivsnuL8wbqg7
+MA0GCSqGSIb3DQEBCwUAA4ICAQDPdyxuVr5Os7aEAJSrR8kN0nbHhp8dB9O2tLsI
+eK9p0gtJ3jPFrK3CiAJ9Brc1AsFgyb/E6JTe1NOpEyVa/m6irn0F3H3zbPB+po3u
+2dfOWBfoqSmuc0iH55vKbimhZF8ZE/euBhD/UcabTVUlT5OZEAFTdfETzsemQUHS
+v4ilf0X8rLiltTMMgsT7B/Zq5SWEXwbKwYY5EdtYzXc7LMJMD16a4/CrPmEbUCTC
+wPTxGfARKbalGAKb12NMcIxHowNDXLldRqANb/9Zjr7dn3LDWyvfjFvO5QxGbJKy
+CqNMVEIYFRIYvdr8unRu/8G2oGTYqV9Vrp9canaW2HNnh/tNf1zuacpzEPuKqf2e
+vTY4SUmH9A4U8OmHuD+nT3pajnnUk+S7aFKErGzp85hwVXIy+TSrK0m1zSBi5Dp6
+Z2Orltxtrpfs/J92VoguZs9btsmksNcFuuEnL5O7Jiqik7Ab846+HUCjuTaPPoIa
+Gl6I6lD4WeKDRikL40Rc4ZW2aZCaFG+XroHPaO+Zmr615+F/+PoTRxZMzG0IQOeL
+eG9QgkRQP2YGiqtDhFZKDyAthg710tvSeopLzaXoTvFeJiUBWSOgftL2fiFX1ye8
+FVdMpEbB4IMeDExNH08GGeL5qPQ6gqGyeUN51q1veieQA6TqJIc/2b3Z6fJfUEkc
+7uzXLg==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDnzCCAoegAwIBAgIBJjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJERTEc
+MBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxlU2Vj
+IFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290IENB
+IDIwHhcNOTkwNzA5MTIxMTAwWhcNMTkwNzA5MjM1OTAwWjBxMQswCQYDVQQGEwJE
+RTEcMBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxl
+U2VjIFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290
+IENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrC6M14IspFLEU
+ha88EOQ5bzVdSq7d6mGNlUn0b2SjGmBmpKlAIoTZ1KXleJMOaAGtuU1cOs7TuKhC
+QN/Po7qCWWqSG6wcmtoIKyUn+WkjR/Hg6yx6m/UTAtB+NHzCnjwAWav12gz1Mjwr
+rFDa1sPeg5TKqAyZMg4ISFZbavva4VhYAUlfckE8FQYBjl2tqriTtM2e66foai1S
+NNs671x1Udrb8zH57nGYMsRUFUQM+ZtV7a3fGAigo4aKSe5TBY8ZTNXeWHmb0moc
+QqvF1afPaA+W5OFhmHZhyJF81j4A4pFQh+GdCuatl9Idxjp9y7zaAzTVjlsB9WoH
+txa2bkp/AgMBAAGjQjBAMB0GA1UdDgQWBBQxw3kbuvVT1xfgiXotF2wKsyudMzAP
+BgNVHRMECDAGAQH/AgEFMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOC
+AQEAlGRZrTlk5ynrE/5aw4sTV8gEJPB0d8Bg42f76Ymmg7+Wgnxu1MM9756Abrsp
+tJh6sTtU6zkXR34ajgv8HzFZMQSyzhfzLMdiNlXiItiJVbSYSKpk+tYcNthEeFpa
+IzpXl/V6ME+un2pMSyuOoAPjPuCp1NJ70rOo4nI8rZ7/gFnkm0W09juwzTkZmDLl
+6iFhkOQxIY40sfcvNUqFENrnijchvllj4PKFiDFT1FQUhXB59C4Gdyd1Lx+4ivn+
+xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU
+Cm26OWMohpLzGITY+9HPBVZkVw==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIGSzCCBDOgAwIBAgIIamg+nFGby1MwDQYJKoZIhvcNAQELBQAwgbIxCzAJBgNV
+BAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExQDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBC
+aWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhpem1ldGxlcmkgQS7Fni4xJjAkBgNV
+BAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBNZXJrZXppMSgwJgYDVQQDDB9FLVR1
+Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTEzMDMwNTEyMDk0OFoXDTIz
+MDMwMzEyMDk0OFowgbIxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExQDA+
+BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhp
+em1ldGxlcmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBN
+ZXJrZXppMSgwJgYDVQQDDB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5
+MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA4vU/kwVRHoViVF56C/UY
+B4Oufq9899SKa6VjQzm5S/fDxmSJPZQuVIBSOTkHS0vdhQd2h8y/L5VMzH2nPbxH
+D5hw+IyFHnSOkm0bQNGZDbt1bsipa5rAhDGvykPL6ys06I+XawGb1Q5KCKpbknSF
+Q9OArqGIW66z6l7LFpp3RMih9lRozt6Plyu6W0ACDGQXwLWTzeHxE2bODHnv0ZEo
+q1+gElIwcxmOj+GMB6LDu0rw6h8VqO4lzKRG+Bsi77MOQ7osJLjFLFzUHPhdZL3D
+k14opz8n8Y4e0ypQBaNV2cvnOVPAmJ6MVGKLJrD3fY185MaeZkJVgkfnsliNZvcH
+fC425lAcP9tDJMW/hkd5s3kc91r0E+xs+D/iWR+V7kI+ua2oMoVJl0b+SzGPWsut
+dEcf6ZG33ygEIqDUD13ieU/qbIWGvaimzuT6w+Gzrt48Ue7LE3wBf4QOXVGUnhMM
+ti6lTPk5cDZvlsouDERVxcr6XQKj39ZkjFqzAQqptQpHF//vkUAqjqFGOjGY5RH8
+zLtJVor8udBhmm9lbObDyz51Sf6Pp+KJxWfXnUYTTjF2OySznhFlhqt/7x3U+Lzn
+rFpct1pHXFXOVbQicVtbC/DP3KBhZOqp12gKY6fgDT+gr9Oq0n7vUaDmUStVkhUX
+U8u3Zg5mTPj5dUyQ5xJwx0UCAwEAAaNjMGEwHQYDVR0OBBYEFC7j27JJ0JxUeVz6
+Jyr+zE7S6E5UMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAULuPbsknQnFR5
+XPonKv7MTtLoTlQwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAF
+Nzr0TbdF4kV1JI+2d1LoHNgQk2Xz8lkGpD4eKexd0dCrfOAKkEh47U6YA5n+KGCR
+HTAduGN8qOY1tfrTYXbm1gdLymmasoR6d5NFFxWfJNCYExL/u6Au/U5Mh/jOXKqY
+GwXgAEZKgoClM4so3O0409/lPun++1ndYYRP0lSWE2ETPo+Aab6TR7U1Q9Jauz1c
+77NCR807VRMGsAnb/WP2OogKmW9+4c4bU2pEZiNRCHu8W1Ki/QY3OEBhj0qWuJA3
++GbHeJAAFS6LrVE1Uweoa2iu+U48BybNCAVwzDk/dr2l02cmAYamU9JgO3xDf1WK
+vJUawSg5TB9D0pH0clmKuVb8P7Sd2nCcdlqMQ1DujjByTd//SffGqWfZbawCEeI6
+FiWnWAjLb1NBnEg4R2gz0dfHj9R0IdTDBZB6/86WiLEVKV0jq9BgoRJP3vQXzTLl
+yb/IQ639Lo7xr+L0mPoSHyDYwKcMhcWQ9DstliaxLL5Mq+ux0orJ23gTDx4JnW2P
+AJ8C2sH6H3p6CcRK5ogql5+Ji/03X186zjhZhkuvcQu02PJwT58yE+Owp1fl2tpD
+y4Q08ijE6m30Ku/Ba3ba+367hTzSU8JNvnHhRdH9I2cNE3X7z2VnIp2usAnRCf8d
+NL/+I5c30jn6PQ0GC7TbO6Orb1wdtn7os4I07QZcJA==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDtTCCAp2gAwIBAgIIBhDCeat3PfIwDQYJKoZIhvcNAQEFBQAwdjELMAkGA1UE
+BhMCQ0gxEjAQBgNVBAoTCVN3aXNzU2lnbjEyMDAGA1UEAxMpU3dpc3NTaWduIENB
+IChSU0EgSUsgTWF5IDYgMTk5OSAxODowMDo1OCkxHzAdBgkqhkiG9w0BCQEWEGNh
+QFN3aXNzU2lnbi5jb20wHhcNMDAxMTI2MjMyNzQxWhcNMzExMTI2MjMyNzQxWjB2
+MQswCQYDVQQGEwJDSDESMBAGA1UEChMJU3dpc3NTaWduMTIwMAYDVQQDEylTd2lz
+c1NpZ24gQ0EgKFJTQSBJSyBNYXkgNiAxOTk5IDE4OjAwOjU4KTEfMB0GCSqGSIb3
+DQEJARYQY2FAU3dpc3NTaWduLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
+AQoCggEBAKw5fjnmNneLQlUCQG8jQLwwfbrOZoUwNX8cbNqhxK03/xUloFVgAt+S
+Te2RxNXaCAXLBPn5ZST35TLV57aLmbHCtifv3YZqaaQGvjedltIBMJihJhZ+h3LY
+SKsUb+xEJ3x5ZUf8jP+Q1g57y1s8SnBFWN/ni5NkF1Y1y31VwOi9wiOf/VISL+uu
+SC4i1CP1Kbz3BDs6Hht1GpRYCbJ/K0bc9oJSpWpT5PGONsGIawqMbJuyoDghsXQ1
+pbn2e8K64BSscGZVZTNooSGgNiHmACNJBYXiWVWrwXPF4l6SddmC3Rj0aKXjgECc
+FkHLDQcsM5JsK2ZLryTDUsQFbxVP2ikCAwEAAaNHMEUwCwYDVR0PBAQDAgEGMAwG
+A1UdEwQFMAMBAf8wHQYDVR0OBBYEFJbXcc05KtT8iLGKq1N4ae+PR34WMAkGA1Ud
+IwQCMAAwDQYJKoZIhvcNAQEFBQADggEBAKMy6W8HvZdS1fBpEUzl6Lvw50bgE1Xc
+HU1JypSBG9mhdcXZo5AlPB4sCvx9Dmfwhyrdsshc0TP2V3Vh6eQqnEF5qB4lVziT
+Bko9mW6Ot+pPnwsy4SHpx3rw6jCYnOqfUcZjWqqqRrq/3P1waz+Mn4cLMVEg3Xaz
+qYov/khvSqS0JniwjRlo2H6f/1oVUKZvP+dUhpQepfZrOqMAWZW4otp6FolyQyeU
+NN6UCRNiUKl5vTijbKwUUwfER/1Vci3M1/O1QCfttQ4vRN4Buc0xqYtGL3cd5WiO
+vWzyhlTzAI6VUdNkQhhHJSAyTpj6dmXDRzrryoFGa2PjgESxz7XBaSI=
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDZzCCAk+gAwIBAgIQGx+ttiD5JNM2a/fH8YygWTANBgkqhkiG9w0BAQUFADBF
+MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQL
+ExNUcnVzdGlzIEZQUyBSb290IENBMB4XDTAzMTIyMzEyMTQwNloXDTI0MDEyMTEx
+MzY1NFowRTELMAkGA1UEBhMCR0IxGDAWBgNVBAoTD1RydXN0aXMgTGltaXRlZDEc
+MBoGA1UECxMTVHJ1c3RpcyBGUFMgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBAMVQe547NdDfxIzNjpvto8A2mfRC6qc+gIMPpqdZh8mQRUN+
+AOqGeSoDvT03mYlmt+WKVoaTnGhLaASMk5MCPjDSNzoiYYkchU59j9WvezX2fihH
+iTHcDnlkH5nSW7r+f2C/revnPDgpai/lkQtV/+xvWNUtyd5MZnGPDNcE2gfmHhjj
+vSkCqPoc4Vu5g6hBSLwacY3nYuUtsuvffM/bq1rKMfFMIvMFE/eC+XN5DL7XSxzA
+0RU8k0Fk0ea+IxciAIleH2ulrG6nS4zto3Lmr2NNL4XSFDWaLk6M6jKYKIahkQlB
+OrTh4/L68MkKokHdqeMDx4gVOxzUGpTXn2RZEm0CAwEAAaNTMFEwDwYDVR0TAQH/
+BAUwAwEB/zAfBgNVHSMEGDAWgBS6+nEleYtXQSUhhgtx67JkDoshZzAdBgNVHQ4E
+FgQUuvpxJXmLV0ElIYYLceuyZA6LIWcwDQYJKoZIhvcNAQEFBQADggEBAH5Y//01
+GX2cGE+esCu8jowU/yyg2kdbw++BLa8F6nRIW/M+TgfHbcWzk88iNVy2P3UnXwmW
+zaD+vkAMXBJV+JOCyinpXj9WV4s4NvdFGkwozZ5BuO1WTISkQMi4sKUraXAEasP4
+1BIy+Q7DsdwyhEQsb8tGD+pmQQ9P8Vilpg0ND2HepZ5dfWWhPBfnqFVO76DH7cZE
+f1T1o+CP8HxVIo8ptoGj4W1OLBuAZ+ytIJ8MYmHVl/9D7S3B2l0pKoU/rGXuhg8F
+jZBf3+6f9L/uHfuY5H+QK4R4EA5sSVPvFVtlRkpdr7r7OnIdzfYliB6XzCGcKQEN
+ZetX2fNXlrtIzYE=
+-----END CERTIFICATE-----
+`
diff --git a/src/crypto/x509/root_darwin_test.go b/src/crypto/x509/root_darwin_test.go
index 87ea4e3..cc6d23c 100644
--- a/src/crypto/x509/root_darwin_test.go
+++ b/src/crypto/x509/root_darwin_test.go
@@ -1,8 +1,20 @@
+// 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 x509
 
-import "testing"
+import (
+	"runtime"
+	"testing"
+)
 
 func TestSystemRoots(t *testing.T) {
+	switch runtime.GOARCH {
+	case "arm", "arm64":
+		t.Skipf("skipping on %s/%s, no system root", runtime.GOOS, runtime.GOARCH)
+	}
+
 	sysRoots := systemRootsPool()         // actual system roots
 	execRoots, err := execSecurityRoots() // non-cgo roots
 
diff --git a/src/crypto/x509/root_linux.go b/src/crypto/x509/root_linux.go
new file mode 100644
index 0000000..cfeca69
--- /dev/null
+++ b/src/crypto/x509/root_linux.go
@@ -0,0 +1,13 @@
+// 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
+
+// Possible certificate files; stop after finding one.
+var certFiles = []string{
+	"/etc/ssl/certs/ca-certificates.crt", // Debian/Ubuntu/Gentoo etc.
+	"/etc/pki/tls/certs/ca-bundle.crt",   // Fedora/RHEL
+	"/etc/ssl/ca-bundle.pem",             // OpenSUSE
+	"/etc/pki/tls/cacert.pem",            // OpenELEC
+}
diff --git a/src/crypto/x509/root_nacl.go b/src/crypto/x509/root_nacl.go
new file mode 100644
index 0000000..4413f64
--- /dev/null
+++ b/src/crypto/x509/root_nacl.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.
+
+package x509
+
+// Possible certificate files; stop after finding one.
+var certFiles = []string{}
diff --git a/src/crypto/x509/root_solaris.go b/src/crypto/x509/root_solaris.go
new file mode 100644
index 0000000..e6d4e61
--- /dev/null
+++ b/src/crypto/x509/root_solaris.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.
+
+package x509
+
+// Possible certificate files; stop after finding one.
+var certFiles = []string{
+	"/etc/certs/ca-certificates.crt",     // Solaris 11.2+
+	"/etc/ssl/certs/ca-certificates.crt", // Joyent SmartOS
+	"/etc/ssl/cacert.pem",                // OmniOS
+}
diff --git a/src/crypto/x509/root_unix.go b/src/crypto/x509/root_unix.go
index f77d6c0..8d3b2fb 100644
--- a/src/crypto/x509/root_unix.go
+++ b/src/crypto/x509/root_unix.go
@@ -8,22 +8,10 @@ package x509
 
 import "io/ioutil"
 
-// Possible certificate files; stop after finding one.
-var certFiles = []string{
-	"/etc/ssl/certs/ca-certificates.crt",     // Debian/Ubuntu/Gentoo etc.
-	"/etc/pki/tls/certs/ca-bundle.crt",       // Fedora/RHEL
-	"/etc/ssl/ca-bundle.pem",                 // OpenSUSE
-	"/etc/ssl/cert.pem",                      // OpenBSD
-	"/usr/local/share/certs/ca-root-nss.crt", // FreeBSD/DragonFly
-	"/etc/pki/tls/cacert.pem",                // OpenELEC
-	"/etc/certs/ca-certificates.crt",         // Solaris 11.2+
-}
-
 // Possible directories with certificate files; stop after successfully
 // reading at least one file from a directory.
 var certDirectories = []string{
 	"/system/etc/security/cacerts", // Android
-
 }
 
 func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
diff --git a/src/crypto/x509/sec1.go b/src/crypto/x509/sec1.go
index 7de6675..c4d7ab6 100644
--- a/src/crypto/x509/sec1.go
+++ b/src/crypto/x509/sec1.go
@@ -18,7 +18,7 @@ const ecPrivKeyVersion = 1
 // ecPrivateKey reflects an ASN.1 Elliptic Curve Private Key Structure.
 // References:
 //   RFC5915
-//   SEC1 - http://www.secg.org/download/aid-780/sec1-v2.pdf
+//   SEC1 - http://www.secg.org/sec1-v2.pdf
 // Per RFC5915 the NamedCurveOID is marked as ASN.1 OPTIONAL, however in
 // most cases it is not.
 type ecPrivateKey struct {
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.go b/src/crypto/x509/verify.go
index ec19814..21b870c 100644
--- a/src/crypto/x509/verify.go
+++ b/src/crypto/x509/verify.go
@@ -215,6 +215,10 @@ func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err e
 		return c.systemVerify(&opts)
 	}
 
+	if len(c.UnhandledCriticalExtensions) > 0 {
+		return nil, UnhandledCriticalExtension{}
+	}
+
 	if opts.Roots == nil {
 		opts.Roots = systemRootsPool()
 		if opts.Roots == nil {
@@ -323,6 +327,9 @@ nextIntermediate:
 }
 
 func matchHostnames(pattern, host string) bool {
+	host = strings.TrimSuffix(host, ".")
+	pattern = strings.TrimSuffix(pattern, ".")
+
 	if len(pattern) == 0 || len(host) == 0 {
 		return false
 	}
@@ -335,7 +342,7 @@ func matchHostnames(pattern, host string) bool {
 	}
 
 	for i, patternPart := range patternParts {
-		if patternPart == "*" {
+		if i == 0 && patternPart == "*" {
 			continue
 		}
 		if patternPart != hostParts[i] {
diff --git a/src/crypto/x509/verify_test.go b/src/crypto/x509/verify_test.go
index 96b9d9b..694c140 100644
--- a/src/crypto/x509/verify_test.go
+++ b/src/crypto/x509/verify_test.go
@@ -14,6 +14,8 @@ import (
 	"time"
 )
 
+var supportSHA2 = true
+
 type verifyTest struct {
 	leaf                 string
 	intermediates        []string
@@ -23,6 +25,7 @@ type verifyTest struct {
 	systemSkip           bool
 	keyUsages            []ExtKeyUsage
 	testSystemRootsError bool
+	sha2                 bool
 
 	errorCallback  func(*testing.T, int, error) bool
 	expectedChains [][]string
@@ -218,6 +221,11 @@ var verifyTests = []verifyTest{
 		currentTime:   1397502195,
 		dnsName:       "api.moip.com.br",
 
+		// CryptoAPI can find alternative validation paths so we don't
+		// perform this test with system validation.
+		systemSkip: true,
+
+		sha2: true,
 		expectedChains: [][]string{
 			{
 				"api.moip.com.br",
@@ -297,6 +305,9 @@ func testVerify(t *testing.T, useSystemRoots bool) {
 		if runtime.GOOS == "windows" && test.testSystemRootsError {
 			continue
 		}
+		if useSystemRoots && !supportSHA2 && test.sha2 {
+			continue
+		}
 
 		opts := VerifyOptions{
 			Intermediates: NewCertPool(),
diff --git a/src/crypto/x509/x509.go b/src/crypto/x509/x509.go
index 7a37b98..be6c013 100644
--- a/src/crypto/x509/x509.go
+++ b/src/crypto/x509/x509.go
@@ -12,7 +12,7 @@ import (
 	"crypto/ecdsa"
 	"crypto/elliptic"
 	"crypto/rsa"
-	"crypto/sha1"
+	_ "crypto/sha1"
 	_ "crypto/sha256"
 	_ "crypto/sha512"
 	"crypto/x509/pkix"
@@ -37,8 +37,10 @@ type pkixPublicKey struct {
 // typically found in PEM blocks with "BEGIN PUBLIC KEY".
 func ParsePKIXPublicKey(derBytes []byte) (pub interface{}, err error) {
 	var pki publicKeyInfo
-	if _, err = asn1.Unmarshal(derBytes, &pki); err != nil {
-		return
+	if rest, err := asn1.Unmarshal(derBytes, &pki); err != nil {
+		return nil, err
+	} else if len(rest) != 0 {
+		return nil, errors.New("x509: trailing data after ASN.1 of public-key")
 	}
 	algo := getPublicKeyAlgorithmFromOID(pki.Algorithm.Algorithm)
 	if algo == UnknownPublicKeyAlgorithm {
@@ -488,6 +490,16 @@ type Certificate struct {
 	// field is not populated when parsing certificates, see Extensions.
 	ExtraExtensions []pkix.Extension
 
+	// UnhandledCriticalExtensions contains a list of extension IDs that
+	// were not (fully) processed when parsing. Verify will fail if this
+	// slice is non-empty, unless verification is delegated to an OS
+	// library which understands all the critical extensions.
+	//
+	// Users can access these extensions using Extensions and can remove
+	// elements from this slice if they believe that they have been
+	// handled.
+	UnhandledCriticalExtensions []asn1.ObjectIdentifier
+
 	ExtKeyUsage        []ExtKeyUsage           // Sequence of extended key usages.
 	UnknownExtKeyUsage []asn1.ObjectIdentifier // Encountered extended key usages unknown to this package.
 
@@ -619,6 +631,12 @@ func (c *Certificate) CheckSignatureFrom(parent *Certificate) (err error) {
 // CheckSignature verifies that signature is a valid signature over signed from
 // c's public key.
 func (c *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature []byte) (err error) {
+	return checkSignature(algo, signed, signature, c.PublicKey)
+}
+
+// CheckSignature verifies that signature is a valid signature over signed from
+// a crypto.PublicKey.
+func checkSignature(algo SignatureAlgorithm, signed, signature []byte, publicKey crypto.PublicKey) (err error) {
 	var hashType crypto.Hash
 
 	switch algo {
@@ -642,13 +660,15 @@ func (c *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature
 	h.Write(signed)
 	digest := h.Sum(nil)
 
-	switch pub := c.PublicKey.(type) {
+	switch pub := publicKey.(type) {
 	case *rsa.PublicKey:
 		return rsa.VerifyPKCS1v15(pub, hashType, digest, signature)
 	case *dsa.PublicKey:
 		dsaSig := new(dsaSignature)
-		if _, err := asn1.Unmarshal(signature, dsaSig); err != nil {
+		if rest, err := asn1.Unmarshal(signature, dsaSig); err != nil {
 			return err
+		} else if len(rest) != 0 {
+			return errors.New("x509: trailing data after DSA signature")
 		}
 		if dsaSig.R.Sign() <= 0 || dsaSig.S.Sign() <= 0 {
 			return errors.New("x509: DSA signature contained zero or negative values")
@@ -659,8 +679,10 @@ func (c *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature
 		return
 	case *ecdsa.PublicKey:
 		ecdsaSig := new(ecdsaSignature)
-		if _, err := asn1.Unmarshal(signature, ecdsaSig); err != nil {
+		if rest, err := asn1.Unmarshal(signature, ecdsaSig); err != nil {
 			return err
+		} else if len(rest) != 0 {
+			return errors.New("x509: trailing data after ECDSA signature")
 		}
 		if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 {
 			return errors.New("x509: ECDSA signature contained zero or negative values")
@@ -729,10 +751,13 @@ func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{
 	switch algo {
 	case RSA:
 		p := new(rsaPublicKey)
-		_, err := asn1.Unmarshal(asn1Data, p)
+		rest, err := asn1.Unmarshal(asn1Data, p)
 		if err != nil {
 			return nil, err
 		}
+		if len(rest) != 0 {
+			return nil, errors.New("x509: trailing data after RSA public key")
+		}
 
 		if p.N.Sign() <= 0 {
 			return nil, errors.New("x509: RSA modulus is not a positive number")
@@ -748,16 +773,22 @@ func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{
 		return pub, nil
 	case DSA:
 		var p *big.Int
-		_, err := asn1.Unmarshal(asn1Data, &p)
+		rest, err := asn1.Unmarshal(asn1Data, &p)
 		if err != nil {
 			return nil, err
 		}
+		if len(rest) != 0 {
+			return nil, errors.New("x509: trailing data after DSA public key")
+		}
 		paramsData := keyData.Algorithm.Parameters.FullBytes
 		params := new(dsaAlgorithmParameters)
-		_, err = asn1.Unmarshal(paramsData, params)
+		rest, err = asn1.Unmarshal(paramsData, params)
 		if err != nil {
 			return nil, err
 		}
+		if len(rest) != 0 {
+			return nil, errors.New("x509: trailing data after DSA parameters")
+		}
 		if p.Sign() <= 0 || params.P.Sign() <= 0 || params.Q.Sign() <= 0 || params.G.Sign() <= 0 {
 			return nil, errors.New("x509: zero or negative DSA parameter")
 		}
@@ -773,10 +804,13 @@ func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{
 	case ECDSA:
 		paramsData := keyData.Algorithm.Parameters.FullBytes
 		namedCurveOID := new(asn1.ObjectIdentifier)
-		_, err := asn1.Unmarshal(paramsData, namedCurveOID)
+		rest, err := asn1.Unmarshal(paramsData, namedCurveOID)
 		if err != nil {
 			return nil, err
 		}
+		if len(rest) != 0 {
+			return nil, errors.New("x509: trailing data after ECDSA parameters")
+		}
 		namedCurve := namedCurveFromOID(*namedCurveOID)
 		if namedCurve == nil {
 			return nil, errors.New("x509: unsupported elliptic curve")
@@ -814,7 +848,11 @@ func parseSANExtension(value []byte) (dnsNames, emailAddresses []string, ipAddre
 	//      iPAddress                       [7]     OCTET STRING,
 	//      registeredID                    [8]     OBJECT IDENTIFIER }
 	var seq asn1.RawValue
-	if _, err = asn1.Unmarshal(value, &seq); err != nil {
+	var rest []byte
+	if rest, err = asn1.Unmarshal(value, &seq); err != nil {
+		return
+	} else if len(rest) != 0 {
+		err = errors.New("x509: trailing data after X.509 extension")
 		return
 	}
 	if !seq.IsCompound || seq.Tag != 16 || seq.Class != 0 {
@@ -822,7 +860,7 @@ func parseSANExtension(value []byte) (dnsNames, emailAddresses []string, ipAddre
 		return
 	}
 
-	rest := seq.Bytes
+	rest = seq.Bytes
 	for len(rest) > 0 {
 		var v asn1.RawValue
 		rest, err = asn1.Unmarshal(rest, &v)
@@ -876,11 +914,15 @@ func parseCertificate(in *certificate) (*Certificate, error) {
 	out.SerialNumber = in.TBSCertificate.SerialNumber
 
 	var issuer, subject pkix.RDNSequence
-	if _, err := asn1.Unmarshal(in.TBSCertificate.Subject.FullBytes, &subject); err != nil {
+	if rest, err := asn1.Unmarshal(in.TBSCertificate.Subject.FullBytes, &subject); err != nil {
 		return nil, err
+	} else if len(rest) != 0 {
+		return nil, errors.New("x509: trailing data after X.509 subject")
 	}
-	if _, err := asn1.Unmarshal(in.TBSCertificate.Issuer.FullBytes, &issuer); err != nil {
+	if rest, err := asn1.Unmarshal(in.TBSCertificate.Issuer.FullBytes, &issuer); err != nil {
 		return nil, err
+	} else if len(rest) != 0 {
+		return nil, errors.New("x509: trailing data after X.509 subject")
 	}
 
 	out.Issuer.FillFromRDNSequence(&issuer)
@@ -891,47 +933,51 @@ func parseCertificate(in *certificate) (*Certificate, error) {
 
 	for _, e := range in.TBSCertificate.Extensions {
 		out.Extensions = append(out.Extensions, e)
+		unhandled := false
 
 		if len(e.Id) == 4 && e.Id[0] == 2 && e.Id[1] == 5 && e.Id[2] == 29 {
 			switch e.Id[3] {
 			case 15:
 				// RFC 5280, 4.2.1.3
 				var usageBits asn1.BitString
-				_, err := asn1.Unmarshal(e.Value, &usageBits)
+				if rest, err := asn1.Unmarshal(e.Value, &usageBits); err != nil {
+					return nil, err
+				} else if len(rest) != 0 {
+					return nil, errors.New("x509: trailing data after X.509 KeyUsage")
+				}
 
-				if err == nil {
-					var usage int
-					for i := 0; i < 9; i++ {
-						if usageBits.At(i) != 0 {
-							usage |= 1 << uint(i)
-						}
+				var usage int
+				for i := 0; i < 9; i++ {
+					if usageBits.At(i) != 0 {
+						usage |= 1 << uint(i)
 					}
-					out.KeyUsage = KeyUsage(usage)
-					continue
 				}
+				out.KeyUsage = KeyUsage(usage)
+
 			case 19:
 				// RFC 5280, 4.2.1.9
 				var constraints basicConstraints
-				_, err := asn1.Unmarshal(e.Value, &constraints)
-
-				if err == nil {
-					out.BasicConstraintsValid = true
-					out.IsCA = constraints.IsCA
-					out.MaxPathLen = constraints.MaxPathLen
-					out.MaxPathLenZero = out.MaxPathLen == 0
-					continue
+				if rest, err := asn1.Unmarshal(e.Value, &constraints); err != nil {
+					return nil, err
+				} else if len(rest) != 0 {
+					return nil, errors.New("x509: trailing data after X.509 BasicConstraints")
 				}
+
+				out.BasicConstraintsValid = true
+				out.IsCA = constraints.IsCA
+				out.MaxPathLen = constraints.MaxPathLen
+				out.MaxPathLenZero = out.MaxPathLen == 0
+
 			case 17:
 				out.DNSNames, out.EmailAddresses, out.IPAddresses, err = parseSANExtension(e.Value)
 				if err != nil {
 					return nil, err
 				}
 
-				if len(out.DNSNames) > 0 || len(out.EmailAddresses) > 0 || len(out.IPAddresses) > 0 {
-					continue
+				if len(out.DNSNames) == 0 && len(out.EmailAddresses) == 0 && len(out.IPAddresses) == 0 {
+					// If we didn't parse anything then we do the critical check, below.
+					unhandled = true
 				}
-				// If we didn't parse any of the names then we
-				// fall through to the critical check below.
 
 			case 30:
 				// RFC 5280, 4.2.1.10
@@ -950,9 +996,10 @@ func parseCertificate(in *certificate) (*Certificate, error) {
 				// BaseDistance ::= INTEGER (0..MAX)
 
 				var constraints nameConstraints
-				_, err := asn1.Unmarshal(e.Value, &constraints)
-				if err != nil {
+				if rest, err := asn1.Unmarshal(e.Value, &constraints); err != nil {
 					return nil, err
+				} else if len(rest) != 0 {
+					return nil, errors.New("x509: trailing data after X.509 NameConstraints")
 				}
 
 				if len(constraints.Excluded) > 0 && e.Critical {
@@ -968,7 +1015,6 @@ func parseCertificate(in *certificate) (*Certificate, error) {
 					}
 					out.PermittedDNSDomains = append(out.PermittedDNSDomains, subtree.Name)
 				}
-				continue
 
 			case 31:
 				// RFC 5280, 4.2.1.14
@@ -985,33 +1031,35 @@ func parseCertificate(in *certificate) (*Certificate, error) {
 				//     nameRelativeToCRLIssuer [1]     RelativeDistinguishedName }
 
 				var cdp []distributionPoint
-				_, err := asn1.Unmarshal(e.Value, &cdp)
-				if err != nil {
+				if rest, err := asn1.Unmarshal(e.Value, &cdp); err != nil {
 					return nil, err
+				} else if len(rest) != 0 {
+					return nil, errors.New("x509: trailing data after X.509 CRL distribution point")
 				}
 
 				for _, dp := range cdp {
 					var n asn1.RawValue
-					_, err = asn1.Unmarshal(dp.DistributionPoint.FullName.Bytes, &n)
-					if err != nil {
+					if _, err := asn1.Unmarshal(dp.DistributionPoint.FullName.Bytes, &n); err != nil {
 						return nil, err
 					}
+					// Trailing data after the fullName is
+					// allowed because other elements of
+					// the SEQUENCE can appear.
 
 					if n.Tag == 6 {
 						out.CRLDistributionPoints = append(out.CRLDistributionPoints, string(n.Bytes))
 					}
 				}
-				continue
 
 			case 35:
 				// RFC 5280, 4.2.1.1
 				var a authKeyId
-				_, err = asn1.Unmarshal(e.Value, &a)
-				if err != nil {
+				if rest, err := asn1.Unmarshal(e.Value, &a); err != nil {
 					return nil, err
+				} else if len(rest) != 0 {
+					return nil, errors.New("x509: trailing data after X.509 authority key-id")
 				}
 				out.AuthorityKeyId = a.Id
-				continue
 
 			case 37:
 				// RFC 5280, 4.2.1.12.  Extended Key Usage
@@ -1023,9 +1071,10 @@ func parseCertificate(in *certificate) (*Certificate, error) {
 				// KeyPurposeId ::= OBJECT IDENTIFIER
 
 				var keyUsage []asn1.ObjectIdentifier
-				_, err = asn1.Unmarshal(e.Value, &keyUsage)
-				if err != nil {
+				if rest, err := asn1.Unmarshal(e.Value, &keyUsage); err != nil {
 					return nil, err
+				} else if len(rest) != 0 {
+					return nil, errors.New("x509: trailing data after X.509 ExtendedKeyUsage")
 				}
 
 				for _, u := range keyUsage {
@@ -1036,34 +1085,40 @@ func parseCertificate(in *certificate) (*Certificate, error) {
 					}
 				}
 
-				continue
-
 			case 14:
 				// RFC 5280, 4.2.1.2
 				var keyid []byte
-				_, err = asn1.Unmarshal(e.Value, &keyid)
-				if err != nil {
+				if rest, err := asn1.Unmarshal(e.Value, &keyid); err != nil {
 					return nil, err
+				} else if len(rest) != 0 {
+					return nil, errors.New("x509: trailing data after X.509 authority key-id")
 				}
 				out.SubjectKeyId = keyid
-				continue
 
 			case 32:
 				// RFC 5280 4.2.1.4: Certificate Policies
 				var policies []policyInformation
-				if _, err = asn1.Unmarshal(e.Value, &policies); err != nil {
+				if rest, err := asn1.Unmarshal(e.Value, &policies); err != nil {
 					return nil, err
+				} else if len(rest) != 0 {
+					return nil, errors.New("x509: trailing data after X.509 certificate policies")
 				}
 				out.PolicyIdentifiers = make([]asn1.ObjectIdentifier, len(policies))
 				for i, policy := range policies {
 					out.PolicyIdentifiers[i] = policy.Policy
 				}
+
+			default:
+				// Unknown extensions are recorded if critical.
+				unhandled = true
 			}
 		} else if e.Id.Equal(oidExtensionAuthorityInfoAccess) {
 			// RFC 5280 4.2.2.1: Authority Information Access
 			var aia []authorityInfoAccess
-			if _, err = asn1.Unmarshal(e.Value, &aia); err != nil {
+			if rest, err := asn1.Unmarshal(e.Value, &aia); err != nil {
 				return nil, err
+			} else if len(rest) != 0 {
+				return nil, errors.New("x509: trailing data after X.509 authority information")
 			}
 
 			for _, v := range aia {
@@ -1077,10 +1132,13 @@ func parseCertificate(in *certificate) (*Certificate, error) {
 					out.IssuingCertificateURL = append(out.IssuingCertificateURL, string(v.Location.Bytes))
 				}
 			}
+		} else {
+			// Unknown extensions are recorded if critical.
+			unhandled = true
 		}
 
-		if e.Critical {
-			return out, UnhandledCriticalExtension{}
+		if e.Critical && unhandled {
+			out.UnhandledCriticalExtensions = append(out.UnhandledCriticalExtensions, e.Id)
 		}
 	}
 
@@ -1135,6 +1193,26 @@ func reverseBitsInAByte(in byte) byte {
 	return b3
 }
 
+// asn1BitLength returns the bit-length of bitString by considering the
+// most-significant bit in a byte to be the "first" bit. This convention
+// matches ASN.1, but differs from almost everything else.
+func asn1BitLength(bitString []byte) int {
+	bitLen := len(bitString) * 8
+
+	for i := range bitString {
+		b := bitString[len(bitString)-i-1]
+
+		for bit := uint(0); bit < 8; bit++ {
+			if (b>>bit)&1 == 1 {
+				return bitLen
+			}
+			bitLen--
+		}
+	}
+
+	return 0
+}
+
 var (
 	oidExtensionSubjectKeyId          = []int{2, 5, 29, 14}
 	oidExtensionKeyUsage              = []int{2, 5, 29, 15}
@@ -1203,7 +1281,8 @@ func buildExtensions(template *Certificate) (ret []pkix.Extension, err error) {
 			l = 2
 		}
 
-		ret[n].Value, err = asn1.Marshal(asn1.BitString{Bytes: a[0:l], BitLength: l * 8})
+		bitString := a[:l]
+		ret[n].Value, err = asn1.Marshal(asn1.BitString{Bytes: bitString, BitLength: asn1BitLength(bitString)})
 		if err != nil {
 			return
 		}
@@ -1368,22 +1447,25 @@ func subjectBytes(cert *Certificate) ([]byte, error) {
 	return asn1.Marshal(cert.Subject.ToRDNSequence())
 }
 
-// signingParamsForPrivateKey returns the parameters to use for signing with
+// signingParamsForPublicKey returns the parameters to use for signing with
 // priv. If requestedSigAlgo is not zero then it overrides the default
 // signature algorithm.
-func signingParamsForPrivateKey(priv interface{}, requestedSigAlgo SignatureAlgorithm) (hashFunc crypto.Hash, sigAlgo pkix.AlgorithmIdentifier, err error) {
+func signingParamsForPublicKey(pub interface{}, requestedSigAlgo SignatureAlgorithm) (hashFunc crypto.Hash, sigAlgo pkix.AlgorithmIdentifier, err error) {
 	var pubType PublicKeyAlgorithm
 
-	switch priv := priv.(type) {
-	case *rsa.PrivateKey:
+	switch pub := pub.(type) {
+	case *rsa.PublicKey:
 		pubType = RSA
-		sigAlgo.Algorithm = oidSignatureSHA256WithRSA
 		hashFunc = crypto.SHA256
+		sigAlgo.Algorithm = oidSignatureSHA256WithRSA
+		sigAlgo.Parameters = asn1.RawValue{
+			Tag: 5,
+		}
 
-	case *ecdsa.PrivateKey:
+	case *ecdsa.PublicKey:
 		pubType = ECDSA
 
-		switch priv.Curve {
+		switch pub.Curve {
 		case elliptic.P224(), elliptic.P256():
 			hashFunc = crypto.SHA256
 			sigAlgo.Algorithm = oidSignatureECDSAWithSHA256
@@ -1398,7 +1480,7 @@ func signingParamsForPrivateKey(priv interface{}, requestedSigAlgo SignatureAlgo
 		}
 
 	default:
-		err = errors.New("x509: only RSA and ECDSA private keys supported")
+		err = errors.New("x509: only RSA and ECDSA keys supported")
 	}
 
 	if err != nil {
@@ -1445,21 +1527,22 @@ func signingParamsForPrivateKey(priv interface{}, requestedSigAlgo SignatureAlgo
 //
 // The returned slice is the certificate in DER encoding.
 //
-// The only supported key types are RSA and ECDSA (*rsa.PublicKey or
-// *ecdsa.PublicKey for pub, *rsa.PrivateKey or *ecdsa.PrivateKey for priv).
-func CreateCertificate(rand io.Reader, template, parent *Certificate, pub interface{}, priv interface{}) (cert []byte, err error) {
-	hashFunc, signatureAlgorithm, err := signingParamsForPrivateKey(priv, template.SignatureAlgorithm)
-	if err != nil {
-		return nil, err
+// All keys types that are implemented via crypto.Signer are supported (This
+// includes *rsa.PublicKey and *ecdsa.PublicKey.)
+func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv interface{}) (cert []byte, err error) {
+	key, ok := priv.(crypto.Signer)
+	if !ok {
+		return nil, errors.New("x509: certificate private key does not implement crypto.Signer")
 	}
 
-	publicKeyBytes, publicKeyAlgorithm, err := marshalPublicKey(pub)
+	hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(key.Public(), template.SignatureAlgorithm)
 	if err != nil {
 		return nil, err
 	}
 
+	publicKeyBytes, publicKeyAlgorithm, err := marshalPublicKey(pub)
 	if err != nil {
-		return
+		return nil, err
 	}
 
 	if len(parent.SubjectKeyId) > 0 {
@@ -1505,30 +1588,17 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub interf
 	digest := h.Sum(nil)
 
 	var signature []byte
-
-	switch priv := priv.(type) {
-	case *rsa.PrivateKey:
-		signature, err = rsa.SignPKCS1v15(rand, priv, hashFunc, digest)
-	case *ecdsa.PrivateKey:
-		var r, s *big.Int
-		if r, s, err = ecdsa.Sign(rand, priv, digest); err == nil {
-			signature, err = asn1.Marshal(ecdsaSignature{r, s})
-		}
-	default:
-		panic("internal error")
-	}
-
+	signature, err = key.Sign(rand, digest, hashFunc)
 	if err != nil {
 		return
 	}
 
-	cert, err = asn1.Marshal(certificate{
+	return asn1.Marshal(certificate{
 		nil,
 		c,
 		signatureAlgorithm,
 		asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
 	})
-	return
 }
 
 // pemCRLPrefix is the magic string that indicates that we have a PEM encoded
@@ -1555,53 +1625,66 @@ func ParseCRL(crlBytes []byte) (certList *pkix.CertificateList, err error) {
 // ParseDERCRL parses a DER encoded CRL from the given bytes.
 func ParseDERCRL(derBytes []byte) (certList *pkix.CertificateList, err error) {
 	certList = new(pkix.CertificateList)
-	_, err = asn1.Unmarshal(derBytes, certList)
-	if err != nil {
-		certList = nil
+	if rest, err := asn1.Unmarshal(derBytes, certList); err != nil {
+		return nil, err
+	} else if len(rest) != 0 {
+		return nil, errors.New("x509: trailing data after CRL")
 	}
-	return
+	return certList, nil
 }
 
 // CreateCRL returns a DER encoded CRL, signed by this Certificate, that
 // contains the given list of revoked certificates.
-//
-// The only supported key type is RSA (*rsa.PrivateKey for priv).
 func (c *Certificate) CreateCRL(rand io.Reader, priv interface{}, revokedCerts []pkix.RevokedCertificate, now, expiry time.Time) (crlBytes []byte, err error) {
-	rsaPriv, ok := priv.(*rsa.PrivateKey)
+	key, ok := priv.(crypto.Signer)
 	if !ok {
-		return nil, errors.New("x509: non-RSA private keys not supported")
+		return nil, errors.New("x509: certificate private key does not implement crypto.Signer")
 	}
+
+	hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(key.Public(), 0)
+	if err != nil {
+		return nil, err
+	}
+
 	tbsCertList := pkix.TBSCertificateList{
-		Version: 2,
-		Signature: pkix.AlgorithmIdentifier{
-			Algorithm: oidSignatureSHA1WithRSA,
-		},
+		Version:             1,
+		Signature:           signatureAlgorithm,
 		Issuer:              c.Subject.ToRDNSequence(),
 		ThisUpdate:          now.UTC(),
 		NextUpdate:          expiry.UTC(),
 		RevokedCertificates: revokedCerts,
 	}
 
+	// Authority Key Id
+	if len(c.SubjectKeyId) > 0 {
+		var aki pkix.Extension
+		aki.Id = oidExtensionAuthorityKeyId
+		aki.Value, err = asn1.Marshal(authKeyId{Id: c.SubjectKeyId})
+		if err != nil {
+			return
+		}
+		tbsCertList.Extensions = append(tbsCertList.Extensions, aki)
+	}
+
 	tbsCertListContents, err := asn1.Marshal(tbsCertList)
 	if err != nil {
 		return
 	}
 
-	h := sha1.New()
+	h := hashFunc.New()
 	h.Write(tbsCertListContents)
 	digest := h.Sum(nil)
 
-	signature, err := rsa.SignPKCS1v15(rand, rsaPriv, crypto.SHA1, digest)
+	var signature []byte
+	signature, err = key.Sign(rand, digest, hashFunc)
 	if err != nil {
 		return
 	}
 
 	return asn1.Marshal(pkix.CertificateList{
-		TBSCertList: tbsCertList,
-		SignatureAlgorithm: pkix.AlgorithmIdentifier{
-			Algorithm: oidSignatureSHA1WithRSA,
-		},
-		SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
+		TBSCertList:        tbsCertList,
+		SignatureAlgorithm: signatureAlgorithm,
+		SignatureValue:     asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
 	})
 }
 
@@ -1650,11 +1733,11 @@ type CertificateRequest struct {
 // signature requests (see RFC 2986):
 
 type tbsCertificateRequest struct {
-	Raw        asn1.RawContent
-	Version    int
-	Subject    asn1.RawValue
-	PublicKey  publicKeyInfo
-	Attributes []pkix.AttributeTypeAndValueSET `asn1:"tag:0"`
+	Raw           asn1.RawContent
+	Version       int
+	Subject       asn1.RawValue
+	PublicKey     publicKeyInfo
+	RawAttributes []asn1.RawValue `asn1:"tag:0"`
 }
 
 type certificateRequest struct {
@@ -1668,6 +1751,36 @@ type certificateRequest struct {
 // extensions in a CSR.
 var oidExtensionRequest = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 14}
 
+// newRawAttributes converts AttributeTypeAndValueSETs from a template
+// CertificateRequest's Attributes into tbsCertificateRequest RawAttributes.
+func newRawAttributes(attributes []pkix.AttributeTypeAndValueSET) ([]asn1.RawValue, error) {
+	var rawAttributes []asn1.RawValue
+	b, err := asn1.Marshal(attributes)
+	rest, err := asn1.Unmarshal(b, &rawAttributes)
+	if err != nil {
+		return nil, err
+	}
+	if len(rest) != 0 {
+		return nil, errors.New("x509: failed to unmarshall raw CSR Attributes")
+	}
+	return rawAttributes, nil
+}
+
+// parseRawAttributes Unmarshals RawAttributes intos AttributeTypeAndValueSETs.
+func parseRawAttributes(rawAttributes []asn1.RawValue) []pkix.AttributeTypeAndValueSET {
+	var attributes []pkix.AttributeTypeAndValueSET
+	for _, rawAttr := range rawAttributes {
+		var attr pkix.AttributeTypeAndValueSET
+		rest, err := asn1.Unmarshal(rawAttr.FullBytes, &attr)
+		// Ignore attributes that don't parse into pkix.AttributeTypeAndValueSET
+		// (i.e.: challengePassword or unstructuredName).
+		if err == nil && len(rest) == 0 {
+			attributes = append(attributes, attr)
+		}
+	}
+	return attributes
+}
+
 // CreateCertificateRequest creates a new certificate based on a template. The
 // following members of template are used: Subject, Attributes,
 // SignatureAlgorithm, Extensions, DNSNames, EmailAddresses, and IPAddresses.
@@ -1675,26 +1788,24 @@ var oidExtensionRequest = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 14}
 //
 // The returned slice is the certificate request in DER encoding.
 //
-// The only supported key types are RSA (*rsa.PrivateKey) and ECDSA
-// (*ecdsa.PrivateKey).
+// All keys types that are implemented via crypto.Signer are supported (This
+// includes *rsa.PublicKey and *ecdsa.PublicKey.)
 func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv interface{}) (csr []byte, err error) {
-	hashFunc, sigAlgo, err := signingParamsForPrivateKey(priv, template.SignatureAlgorithm)
+	key, ok := priv.(crypto.Signer)
+	if !ok {
+		return nil, errors.New("x509: certificate private key does not implement crypto.Signer")
+	}
+
+	var hashFunc crypto.Hash
+	var sigAlgo pkix.AlgorithmIdentifier
+	hashFunc, sigAlgo, err = signingParamsForPublicKey(key.Public(), template.SignatureAlgorithm)
 	if err != nil {
 		return nil, err
 	}
 
 	var publicKeyBytes []byte
 	var publicKeyAlgorithm pkix.AlgorithmIdentifier
-
-	switch priv := priv.(type) {
-	case *rsa.PrivateKey:
-		publicKeyBytes, publicKeyAlgorithm, err = marshalPublicKey(&priv.PublicKey)
-	case *ecdsa.PrivateKey:
-		publicKeyBytes, publicKeyAlgorithm, err = marshalPublicKey(&priv.PublicKey)
-	default:
-		panic("internal error")
-	}
-
+	publicKeyBytes, publicKeyAlgorithm, err = marshalPublicKey(key.Public())
 	if err != nil {
 		return nil, err
 	}
@@ -1782,6 +1893,11 @@ func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv
 		}
 	}
 
+	rawAttributes, err := newRawAttributes(attributes)
+	if err != nil {
+		return
+	}
+
 	tbsCSR := tbsCertificateRequest{
 		Version: 0, // PKCS #10, RFC 2986
 		Subject: asn1.RawValue{FullBytes: asn1Subject},
@@ -1792,7 +1908,7 @@ func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv
 				BitLength: len(publicKeyBytes) * 8,
 			},
 		},
-		Attributes: attributes,
+		RawAttributes: rawAttributes,
 	}
 
 	tbsCSRContents, err := asn1.Marshal(tbsCSR)
@@ -1806,18 +1922,7 @@ func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv
 	digest := h.Sum(nil)
 
 	var signature []byte
-	switch priv := priv.(type) {
-	case *rsa.PrivateKey:
-		signature, err = rsa.SignPKCS1v15(rand, priv, hashFunc, digest)
-	case *ecdsa.PrivateKey:
-		var r, s *big.Int
-		if r, s, err = ecdsa.Sign(rand, priv, digest); err == nil {
-			signature, err = asn1.Marshal(ecdsaSignature{r, s})
-		}
-	default:
-		panic("internal error")
-	}
-
+	signature, err = key.Sign(rand, digest, hashFunc)
 	if err != nil {
 		return
 	}
@@ -1860,7 +1965,7 @@ func parseCertificateRequest(in *certificateRequest) (*CertificateRequest, error
 		PublicKeyAlgorithm: getPublicKeyAlgorithmFromOID(in.TBSCSR.PublicKey.Algorithm.Algorithm),
 
 		Version:    in.TBSCSR.Version,
-		Attributes: in.TBSCSR.Attributes,
+		Attributes: parseRawAttributes(in.TBSCSR.RawAttributes),
 	}
 
 	var err error
@@ -1870,15 +1975,17 @@ func parseCertificateRequest(in *certificateRequest) (*CertificateRequest, error
 	}
 
 	var subject pkix.RDNSequence
-	if _, err := asn1.Unmarshal(in.TBSCSR.Subject.FullBytes, &subject); err != nil {
+	if rest, err := asn1.Unmarshal(in.TBSCSR.Subject.FullBytes, &subject); err != nil {
 		return nil, err
+	} else if len(rest) != 0 {
+		return nil, errors.New("x509: trailing data after X.509 Subject")
 	}
 
 	out.Subject.FillFromRDNSequence(&subject)
 
 	var extensions []pkix.AttributeTypeAndValue
 
-	for _, atvSet := range in.TBSCSR.Attributes {
+	for _, atvSet := range out.Attributes {
 		if !atvSet.Type.Equal(oidExtensionRequest) {
 			continue
 		}
@@ -1914,3 +2021,8 @@ func parseCertificateRequest(in *certificateRequest) (*CertificateRequest, error
 
 	return out, nil
 }
+
+// CheckSignature verifies that the signature on c is a valid signature
+func (c *CertificateRequest) CheckSignature() (err error) {
+	return checkSignature(c.SignatureAlgorithm, c.RawTBSCertificateRequest, c.Signature, c.PublicKey)
+}
diff --git a/src/crypto/x509/x509_test.go b/src/crypto/x509/x509_test.go
index 4f5173f..f4f9fa2 100644
--- a/src/crypto/x509/x509_test.go
+++ b/src/crypto/x509/x509_test.go
@@ -18,11 +18,11 @@ import (
 	"encoding/base64"
 	"encoding/hex"
 	"encoding/pem"
+	"internal/testenv"
 	"math/big"
 	"net"
 	"os/exec"
 	"reflect"
-	"runtime"
 	"testing"
 	"time"
 )
@@ -41,6 +41,13 @@ func TestParsePKCS1PrivateKey(t *testing.T) {
 		priv.Primes[1].Cmp(rsaPrivateKey.Primes[1]) != 0 {
 		t.Errorf("got:%+v want:%+v", priv, rsaPrivateKey)
 	}
+
+	// This private key includes an invalid prime that
+	// rsa.PrivateKey.Validate should reject.
+	data := []byte("0\x16\x02\x00\x02\x02\u007f\x00\x02\x0200\x02\x0200\x02\x02\x00\x01\x02\x02\u007f\x00")
+	if _, err := ParsePKCS1PrivateKey(data); err == nil {
+		t.Errorf("parsing invalid private key did not result in an error")
+	}
 }
 
 func TestParsePKIXPublicKey(t *testing.T) {
@@ -162,17 +169,31 @@ var matchHostnamesTests = []matchHostnamesTest{
 	{"a.b.c", "", false},
 	{"example.com", "example.com", true},
 	{"example.com", "www.example.com", false},
+	{"*.example.com", "example.com", false},
 	{"*.example.com", "www.example.com", true},
+	{"*.example.com", "www.example.com.", true},
 	{"*.example.com", "xyz.www.example.com", false},
-	{"*.*.example.com", "xyz.www.example.com", true},
-	{"*.www.*.com", "xyz.www.example.com", true},
+	{"*.*.example.com", "xyz.www.example.com", false},
+	{"*.www.*.com", "xyz.www.example.com", false},
+	{"*bar.example.com", "foobar.example.com", false},
+	{"f*.example.com", "foobar.example.com", false},
+	{"", ".", false},
+	{".", "", false},
+	{".", ".", false},
+	{"example.com", "example.com.", true},
+	{"example.com.", "example.com", true},
+	{"example.com.", "example.com.", true},
+	{"*.com.", "example.com.", true},
+	{"*.com.", "example.com", true},
+	{"*.com", "example.com", true},
+	{"*.com", "example.com.", true},
 }
 
 func TestMatchHostnames(t *testing.T) {
 	for i, test := range matchHostnamesTests {
 		r := matchHostnames(test.pattern, test.host)
 		if r != test.ok {
-			t.Errorf("#%d mismatch got: %t want: %t", i, r, test.ok)
+			t.Errorf("#%d mismatch got: %t want: %t when matching '%s' against '%s'", i, r, test.ok, test.host, test.pattern)
 		}
 	}
 }
@@ -326,6 +347,18 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
 			Subject: pkix.Name{
 				CommonName:   commonName,
 				Organization: []string{"Σ Acme Co"},
+				Country:      []string{"US"},
+				ExtraNames: []pkix.AttributeTypeAndValue{
+					{
+						Type:  []int{2, 5, 4, 42},
+						Value: "Gopher",
+					},
+					// This should override the Country, above.
+					{
+						Type:  []int{2, 5, 4, 6},
+						Value: "NL",
+					},
+				},
 			},
 			NotBefore: time.Unix(1000, 0),
 			NotAfter:  time.Unix(100000, 0),
@@ -391,6 +424,21 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
 			t.Errorf("%s: subject wasn't correctly copied from the template. Got %s, want %s", test.name, cert.Subject.CommonName, commonName)
 		}
 
+		if len(cert.Subject.Country) != 1 || cert.Subject.Country[0] != "NL" {
+			t.Errorf("%s: ExtraNames didn't override Country", test.name)
+		}
+
+		found := false
+		for _, atv := range cert.Subject.Names {
+			if atv.Type.Equal([]int{2, 5, 4, 42}) {
+				found = true
+				break
+			}
+		}
+		if !found {
+			t.Errorf("%s: Names didn't contain oid 2.5.4.42 from ExtraNames", test.name)
+		}
+
 		if cert.Issuer.CommonName != commonName {
 			t.Errorf("%s: issuer wasn't correctly copied from the template. Got %s, want %s", test.name, cert.Issuer.CommonName, commonName)
 		}
@@ -448,6 +496,74 @@ func TestCreateSelfSignedCertificate(t *testing.T) {
 	}
 }
 
+func TestUnknownCriticalExtension(t *testing.T) {
+	priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+	if err != nil {
+		t.Fatalf("Failed to generate ECDSA key: %s", err)
+	}
+
+	oids := []asn1.ObjectIdentifier{
+		// This OID is in the PKIX arc, but unknown.
+		asn1.ObjectIdentifier{2, 5, 29, 999999},
+		// This is a nonsense, unassigned OID.
+		asn1.ObjectIdentifier{1, 2, 3, 4},
+	}
+
+	for _, oid := range oids {
+		template := Certificate{
+			SerialNumber: big.NewInt(1),
+			Subject: pkix.Name{
+				CommonName: "foo",
+			},
+			NotBefore: time.Unix(1000, 0),
+			NotAfter:  time.Now().AddDate(1, 0, 0),
+
+			BasicConstraintsValid: true,
+			IsCA: true,
+
+			KeyUsage:    KeyUsageCertSign,
+			ExtKeyUsage: []ExtKeyUsage{ExtKeyUsageServerAuth},
+
+			ExtraExtensions: []pkix.Extension{
+				{
+					Id:       oid,
+					Critical: true,
+					Value:    nil,
+				},
+			},
+		}
+
+		derBytes, err := CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
+		if err != nil {
+			t.Fatalf("failed to create certificate: %s", err)
+		}
+
+		cert, err := ParseCertificate(derBytes)
+		if err != nil {
+			t.Fatalf("Certificate with unknown critical extension was not parsed: %s", err)
+		}
+
+		roots := NewCertPool()
+		roots.AddCert(cert)
+
+		// Setting Roots ensures that Verify won't delegate to the OS
+		// library and thus the correct error should always be
+		// returned.
+		_, err = cert.Verify(VerifyOptions{Roots: roots})
+		if err == nil {
+			t.Fatal("Certificate with unknown critical extension was verified without error")
+		}
+		if _, ok := err.(UnhandledCriticalExtension); !ok {
+			t.Fatalf("Error was %#v, but wanted one of type UnhandledCriticalExtension", err)
+		}
+
+		cert.UnhandledCriticalExtensions = nil
+		if _, err = cert.Verify(VerifyOptions{Roots: roots}); err != nil {
+			t.Errorf("Certificate failed to verify after unhandled critical extensions were cleared: %s", err)
+		}
+	}
+}
+
 // Self-signed certificate using ECDSA with SHA1 & secp256r1
 var ecdsaSHA1CertPem = `
 -----BEGIN CERTIFICATE-----
@@ -739,10 +855,7 @@ func TestParsePEMCRL(t *testing.T) {
 }
 
 func TestImports(t *testing.T) {
-	switch runtime.GOOS {
-	case "android", "nacl":
-		t.Skipf("skipping on %s", runtime.GOOS)
-	}
+	testenv.MustHaveGoRun(t)
 
 	if err := exec.Command("go", "run", "x509_test_import.go").Run(); err != nil {
 		t.Errorf("failed to run x509_test_import.go: %s", err)
@@ -812,6 +925,12 @@ func TestCreateCertificateRequest(t *testing.T) {
 			continue
 		}
 
+		err = out.CheckSignature()
+		if err != nil {
+			t.Errorf("%s: failed to check certificate request signature: %s", test.name, err)
+			continue
+		}
+
 		if out.Subject.CommonName != template.Subject.CommonName {
 			t.Errorf("%s: output subject common name and template subject common name don't match", test.name)
 		} else if len(out.Subject.Organization) != len(template.Subject.Organization) {
@@ -923,33 +1042,35 @@ func TestCertificateRequestOverrides(t *testing.T) {
 }
 
 func TestParseCertificateRequest(t *testing.T) {
-	csrBytes := fromBase64(csrBase64)
-	csr, err := ParseCertificateRequest(csrBytes)
-	if err != nil {
-		t.Fatalf("failed to parse CSR: %s", err)
-	}
+	for _, csrBase64 := range csrBase64Array {
+		csrBytes := fromBase64(csrBase64)
+		csr, err := ParseCertificateRequest(csrBytes)
+		if err != nil {
+			t.Fatalf("failed to parse CSR: %s", err)
+		}
 
-	if len(csr.EmailAddresses) != 1 || csr.EmailAddresses[0] != "gopher at golang.org" {
-		t.Errorf("incorrect email addresses found: %v", csr.EmailAddresses)
-	}
+		if len(csr.EmailAddresses) != 1 || csr.EmailAddresses[0] != "gopher at golang.org" {
+			t.Errorf("incorrect email addresses found: %v", csr.EmailAddresses)
+		}
 
-	if len(csr.DNSNames) != 1 || csr.DNSNames[0] != "test.example.com" {
-		t.Errorf("incorrect DNS names found: %v", csr.DNSNames)
-	}
+		if len(csr.DNSNames) != 1 || csr.DNSNames[0] != "test.example.com" {
+			t.Errorf("incorrect DNS names found: %v", csr.DNSNames)
+		}
 
-	if len(csr.Subject.Country) != 1 || csr.Subject.Country[0] != "AU" {
-		t.Errorf("incorrect Subject name: %v", csr.Subject)
-	}
+		if len(csr.Subject.Country) != 1 || csr.Subject.Country[0] != "AU" {
+			t.Errorf("incorrect Subject name: %v", csr.Subject)
+		}
 
-	found := false
-	for _, e := range csr.Extensions {
-		if e.Id.Equal(oidExtensionBasicConstraints) {
-			found = true
-			break
+		found := false
+		for _, e := range csr.Extensions {
+			if e.Id.Equal(oidExtensionBasicConstraints) {
+				found = true
+				break
+			}
+		}
+		if !found {
+			t.Errorf("basic constraints extension not found in CSR")
 		}
-	}
-	if !found {
-		t.Errorf("basic constraints extension not found in CSR")
 	}
 }
 
@@ -1016,12 +1137,42 @@ func TestMaxPathLen(t *testing.T) {
 	}
 }
 
-// This CSR was generated with OpenSSL:
-//  openssl req -out CSR.csr -new -newkey rsa:2048 -nodes -keyout privateKey.key -config openssl.cnf
+func TestASN1BitLength(t *testing.T) {
+	tests := []struct {
+		bytes  []byte
+		bitLen int
+	}{
+		{nil, 0},
+		{[]byte{0x00}, 0},
+		{[]byte{0x00, 0x00}, 0},
+		{[]byte{0xf0}, 4},
+		{[]byte{0x88}, 5},
+		{[]byte{0xff}, 8},
+		{[]byte{0xff, 0x80}, 9},
+		{[]byte{0xff, 0x81}, 16},
+	}
+
+	for i, test := range tests {
+		if got := asn1BitLength(test.bytes); got != test.bitLen {
+			t.Errorf("#%d: calculated bit-length of %d for %x, wanted %d", i, got, test.bytes, test.bitLen)
+		}
+	}
+}
+
+// These CSR was generated with OpenSSL:
+//  openssl req -out CSR.csr -new -sha256 -nodes -keyout privateKey.key -config openssl.cnf
 //
-// The openssl.cnf needs to include this section:
+// With openssl.cnf containing the following sections:
 //   [ v3_req ]
 //   basicConstraints = CA:FALSE
 //   keyUsage = nonRepudiation, digitalSignature, keyEncipherment
 //   subjectAltName = email:gopher at golang.org,DNS:test.example.com
-const csrBase64 = "MIIC4zCCAcsCAQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOY+MVedRg2JEnyeLcSzcsMv2VcsTfkB5+Etd6hihAh6MrGezNyASMMKuQN6YhCX1icQDiQtGsDLTtheNnSXK06tAhHjAP/hGlszRJp+5+rP2M58fDBAkUBEhskbCUWwpY14jFtVuGNJ8vF8h8IeczdolvQhX9lVai9G0EUXJMliMKdjA899H0mRs9PzHyidyrXFNiZlQXfD8Kg7gETn2Ny965iyI6ujAIYSCvam6TnxRHYH2MBKyVGvsYGbPYUQJCsgdgyajEg6ekihvQY3SzO1HSAlZAd7d1QYO4VeWJ2mY6Wu3Jpmh+AmG19S9CcHq [...]
+//   [ req_attributes ]
+//   challengePassword = ignored challenge
+//   unstructuredName  = ignored unstructured name
+var csrBase64Array = [...]string{
+	// Just [ v3_req ]
+	"MIIDHDCCAgQCAQAwfjELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEUMBIGA1UEAwwLQ29tbW9uIE5hbWUxITAfBgkqhkiG9w0BCQEWEnRlc3RAZW1haWwuYWRkcmVzczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK1GY4YFx2ujlZEOJxQVYmsjUnLsd5nFVnNpLE4cV+77sgv9NPNlB8uhn3MXt5leD34rm/2BisCHOifPucYlSrszo2beuKhvwn4+2FxDmWtBEMu/QA16L5IvoOfYZm/gJTsPwKDqvaR0tTU67a9OtxwNTBMI56YKtmwd/o8d3hYv9cg+9ZGAZ/gKONcg/OWYx/XRh6bd0g8DMbCikpWgXKDsvvK1Nk+VtkDO1JxuBaj4Lz/p/MifTfnHoqHxWOWl4EaTs4 [...]
+	// Both [ v3_req ] and [ req_attributes ]
+	"MIIDaTCCAlECAQAwfjELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEUMBIGA1UEAwwLQ29tbW9uIE5hbWUxITAfBgkqhkiG9w0BCQEWEnRlc3RAZW1haWwuYWRkcmVzczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK1GY4YFx2ujlZEOJxQVYmsjUnLsd5nFVnNpLE4cV+77sgv9NPNlB8uhn3MXt5leD34rm/2BisCHOifPucYlSrszo2beuKhvwn4+2FxDmWtBEMu/QA16L5IvoOfYZm/gJTsPwKDqvaR0tTU67a9OtxwNTBMI56YKtmwd/o8d3hYv9cg+9ZGAZ/gKONcg/OWYx/XRh6bd0g8DMbCikpWgXKDsvvK1Nk+VtkDO1JxuBaj4Lz/p/MifTfnHoqHxWOWl4EaTs4 [...]
+}
diff --git a/src/database/sql/fakedb_test.go b/src/database/sql/fakedb_test.go
index a993fd4..8cbbb29 100644
--- a/src/database/sql/fakedb_test.go
+++ b/src/database/sql/fakedb_test.go
@@ -89,7 +89,10 @@ type fakeConn struct {
 	stmtsMade   int
 	stmtsClosed int
 	numPrepare  int
-	bad         bool
+
+	// bad connection tests; see isBad()
+	bad       bool
+	stickyBad bool
 }
 
 func (c *fakeConn) incrStat(v *int) {
@@ -243,13 +246,15 @@ func (db *fakeDB) columnType(table, column string) (typ string, ok bool) {
 }
 
 func (c *fakeConn) isBad() bool {
-	// if not simulating bad conn, do nothing
-	if !c.bad {
+	if c.stickyBad {
+		return true
+	} else if c.bad {
+		// alternate between bad conn and not bad conn
+		c.db.badConn = !c.db.badConn
+		return c.db.badConn
+	} else {
 		return false
 	}
-	// alternate between bad conn and not bad conn
-	c.db.badConn = !c.db.badConn
-	return c.db.badConn
 }
 
 func (c *fakeConn) Begin() (driver.Tx, error) {
@@ -466,7 +471,7 @@ func (c *fakeConn) Prepare(query string) (driver.Stmt, error) {
 		panic("nil c.db; conn = " + fmt.Sprintf("%#v", c))
 	}
 
-	if hookPrepareBadConn != nil && hookPrepareBadConn() {
+	if c.stickyBad || (hookPrepareBadConn != nil && hookPrepareBadConn()) {
 		return nil, driver.ErrBadConn
 	}
 
@@ -529,7 +534,7 @@ func (s *fakeStmt) Exec(args []driver.Value) (driver.Result, error) {
 		return nil, errClosed
 	}
 
-	if hookExecBadConn != nil && hookExecBadConn() {
+	if s.c.stickyBad || (hookExecBadConn != nil && hookExecBadConn()) {
 		return nil, driver.ErrBadConn
 	}
 
@@ -613,7 +618,7 @@ func (s *fakeStmt) Query(args []driver.Value) (driver.Rows, error) {
 		return nil, errClosed
 	}
 
-	if hookQueryBadConn != nil && hookQueryBadConn() {
+	if s.c.stickyBad || (hookQueryBadConn != nil && hookQueryBadConn()) {
 		return nil, driver.ErrBadConn
 	}
 
diff --git a/src/database/sql/sql.go b/src/database/sql/sql.go
index 6e6f246..aaa4ea2 100644
--- a/src/database/sql/sql.go
+++ b/src/database/sql/sql.go
@@ -6,10 +6,10 @@
 // databases.
 //
 // The sql package must be used in conjunction with a database driver.
-// See http://golang.org/s/sqldrivers for a list of drivers.
+// See https://golang.org/s/sqldrivers for a list of drivers.
 //
 // For more usage examples, see the wiki page at
-// http://golang.org/s/sqlwiki.
+// https://golang.org/s/sqlwiki.
 package sql
 
 import (
@@ -20,14 +20,20 @@ import (
 	"runtime"
 	"sort"
 	"sync"
+	"sync/atomic"
 )
 
-var drivers = make(map[string]driver.Driver)
+var (
+	driversMu sync.Mutex
+	drivers   = make(map[string]driver.Driver)
+)
 
 // Register makes a database driver available by the provided name.
 // If Register is called twice with the same name or if driver is nil,
 // it panics.
 func Register(name string, driver driver.Driver) {
+	driversMu.Lock()
+	defer driversMu.Unlock()
 	if driver == nil {
 		panic("sql: Register driver is nil")
 	}
@@ -38,12 +44,16 @@ func Register(name string, driver driver.Driver) {
 }
 
 func unregisterAllDrivers() {
+	driversMu.Lock()
+	defer driversMu.Unlock()
 	// For tests.
 	drivers = make(map[string]driver.Driver)
 }
 
 // Drivers returns a sorted list of the names of the registered drivers.
 func Drivers() []string {
+	driversMu.Lock()
+	defer driversMu.Unlock()
 	var list []string
 	for name := range drivers {
 		list = append(list, name)
@@ -211,6 +221,10 @@ var ErrNoRows = errors.New("sql: no rows in result set")
 type DB struct {
 	driver driver.Driver
 	dsn    string
+	// numClosed is an atomic counter which represents a total number of
+	// closed connections. Stmt.openStmt checks it before cleaning closed
+	// connections in Stmt.css.
+	numClosed uint64
 
 	mu           sync.Mutex // protects following fields
 	freeConn     []*driverConn
@@ -230,6 +244,18 @@ type DB struct {
 	maxOpen  int                    // <= 0 means unlimited
 }
 
+// connReuseStrategy determines how (*DB).conn returns database connections.
+type connReuseStrategy uint8
+
+const (
+	// alwaysNewConn forces a new connection to the database.
+	alwaysNewConn connReuseStrategy = iota
+	// cachedOrNewConn returns a cached connection, if available, else waits
+	// for one to become available (if MaxOpenConns has been reached) or
+	// creates a new database connection.
+	cachedOrNewConn
+)
+
 // driverConn wraps a driver.Conn with a mutex, to
 // be held during all calls into the Conn. (including any calls onto
 // interfaces returned via that Conn, such as calls on Tx, Stmt,
@@ -246,7 +272,7 @@ type driverConn struct {
 	// guarded by db.mu
 	inUse      bool
 	onPut      []func() // code (with db.mu held) run when conn is next returned
-	dbmuClosed bool     // same as closed, but guarded by db.mu, for connIfFree
+	dbmuClosed bool     // same as closed, but guarded by db.mu, for removeClosedStmtLocked
 }
 
 func (dc *driverConn) releaseConn(err error) {
@@ -329,6 +355,7 @@ func (dc *driverConn) finalClose() error {
 	dc.db.maybeOpenNewConnections()
 	dc.db.mu.Unlock()
 
+	atomic.AddUint64(&dc.db.numClosed, 1)
 	return err
 }
 
@@ -427,7 +454,7 @@ var connectionRequestQueueSize = 1000000
 //
 // Most users will open a database via a driver-specific connection
 // helper function that returns a *DB. No database drivers are included
-// in the Go standard library. See http://golang.org/s/sqldrivers for
+// in the Go standard library. See https://golang.org/s/sqldrivers for
 // a list of third-party drivers.
 //
 // Open may just validate its arguments without creating a connection
@@ -439,7 +466,9 @@ var connectionRequestQueueSize = 1000000
 // function should be called just once. It is rarely necessary to
 // close a DB.
 func Open(driverName, dataSourceName string) (*DB, error) {
+	driversMu.Lock()
 	driveri, ok := drivers[driverName]
+	driversMu.Unlock()
 	if !ok {
 		return nil, fmt.Errorf("sql: unknown driver %q (forgotten import?)", driverName)
 	}
@@ -459,7 +488,7 @@ func (db *DB) Ping() error {
 	// TODO(bradfitz): give drivers an optional hook to implement
 	// this in a more efficient or more reliable way, if they
 	// have one.
-	dc, err := db.conn()
+	dc, err := db.conn(cachedOrNewConn)
 	if err != nil {
 		return err
 	}
@@ -566,6 +595,22 @@ func (db *DB) SetMaxOpenConns(n int) {
 	}
 }
 
+// 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.
@@ -629,36 +674,37 @@ type connRequest struct {
 
 var errDBClosed = errors.New("sql: database is closed")
 
-// conn returns a newly-opened or cached *driverConn
-func (db *DB) conn() (*driverConn, error) {
+// conn returns a newly-opened or cached *driverConn.
+func (db *DB) conn(strategy connReuseStrategy) (*driverConn, error) {
 	db.mu.Lock()
 	if db.closed {
 		db.mu.Unlock()
 		return nil, errDBClosed
 	}
 
-	// If db.maxOpen > 0 and the number of open connections is over the limit
-	// and there are no free connection, make a request and wait.
-	if db.maxOpen > 0 && db.numOpen >= db.maxOpen && len(db.freeConn) == 0 {
+	// Prefer a free connection, if possible.
+	numFree := len(db.freeConn)
+	if strategy == cachedOrNewConn && numFree > 0 {
+		conn := db.freeConn[0]
+		copy(db.freeConn, db.freeConn[1:])
+		db.freeConn = db.freeConn[:numFree-1]
+		conn.inUse = true
+		db.mu.Unlock()
+		return conn, nil
+	}
+
+	// Out of free connections or we were asked not to use one.  If we're not
+	// allowed to open any more connections, make a request and wait.
+	if db.maxOpen > 0 && db.numOpen >= db.maxOpen {
 		// Make the connRequest channel. It's buffered so that the
 		// connectionOpener doesn't block while waiting for the req to be read.
 		req := make(chan connRequest, 1)
 		db.connRequests = append(db.connRequests, req)
-		db.maybeOpenNewConnections()
 		db.mu.Unlock()
 		ret := <-req
 		return ret.conn, ret.err
 	}
 
-	if c := len(db.freeConn); c > 0 {
-		conn := db.freeConn[0]
-		copy(db.freeConn, db.freeConn[1:])
-		db.freeConn = db.freeConn[:c-1]
-		conn.inUse = true
-		db.mu.Unlock()
-		return conn, nil
-	}
-
 	db.numOpen++ // optimistically
 	db.mu.Unlock()
 	ci, err := db.driver.Open(db.dsn)
@@ -684,42 +730,6 @@ var (
 	errConnBusy   = errors.New("database/sql: internal sentinel error: conn is busy")
 )
 
-// connIfFree returns (wanted, nil) if wanted is still a valid conn and
-// isn't in use.
-//
-// The error is errConnClosed if the connection if the requested connection
-// is invalid because it's been closed.
-//
-// The error is errConnBusy if the connection is in use.
-func (db *DB) connIfFree(wanted *driverConn) (*driverConn, error) {
-	db.mu.Lock()
-	defer db.mu.Unlock()
-	if wanted.dbmuClosed {
-		return nil, errConnClosed
-	}
-	if wanted.inUse {
-		return nil, errConnBusy
-	}
-	idx := -1
-	for ii, v := range db.freeConn {
-		if v == wanted {
-			idx = ii
-			break
-		}
-	}
-	if idx >= 0 {
-		db.freeConn = append(db.freeConn[:idx], db.freeConn[idx+1:]...)
-		wanted.inUse = true
-		return wanted, nil
-	}
-	// TODO(bradfitz): shouldn't get here. After Go 1.1, change this to:
-	// panic("connIfFree call requested a non-closed, non-busy, non-free conn")
-	// Which passes all the tests, but I'm too paranoid to include this
-	// late in Go 1.1.
-	// Instead, treat it like a busy connection:
-	return nil, errConnBusy
-}
-
 // putConnHook is a hook for testing.
 var putConnHook func(*DB, *driverConn)
 
@@ -797,6 +807,9 @@ func (db *DB) putConn(dc *driverConn, err error) {
 // If a connRequest was fulfilled or the *driverConn was placed in the
 // freeConn list, then true is returned, otherwise false is returned.
 func (db *DB) putConnDBLocked(dc *driverConn, err error) bool {
+	if db.maxOpen > 0 && db.numOpen > db.maxOpen {
+		return false
+	}
 	if c := len(db.connRequests); c > 0 {
 		req := db.connRequests[0]
 		// This copy is O(n) but in practice faster than a linked list.
@@ -820,32 +833,38 @@ func (db *DB) putConnDBLocked(dc *driverConn, err error) bool {
 }
 
 // maxBadConnRetries is the number of maximum retries if the driver returns
-// driver.ErrBadConn to signal a broken connection.
-const maxBadConnRetries = 10
+// driver.ErrBadConn to signal a broken connection before forcing a new
+// connection to be opened.
+const maxBadConnRetries = 2
 
 // Prepare creates a prepared statement for later queries or executions.
 // Multiple queries or executions may be run concurrently from the
 // returned statement.
+// The caller must call the statement's Close method
+// when the statement is no longer needed.
 func (db *DB) Prepare(query string) (*Stmt, error) {
 	var stmt *Stmt
 	var err error
 	for i := 0; i < maxBadConnRetries; i++ {
-		stmt, err = db.prepare(query)
+		stmt, err = db.prepare(query, cachedOrNewConn)
 		if err != driver.ErrBadConn {
 			break
 		}
 	}
+	if err == driver.ErrBadConn {
+		return db.prepare(query, alwaysNewConn)
+	}
 	return stmt, err
 }
 
-func (db *DB) prepare(query string) (*Stmt, error) {
+func (db *DB) prepare(query string, strategy connReuseStrategy) (*Stmt, error) {
 	// TODO: check if db.driver supports an optional
 	// driver.Preparer interface and call that instead, if so,
 	// otherwise we make a prepared statement that's bound
 	// to a connection, and to execute this prepared statement
 	// we either need to use this connection (if it's free), else
 	// get a new connection + re-prepare + execute on that one.
-	dc, err := db.conn()
+	dc, err := db.conn(strategy)
 	if err != nil {
 		return nil, err
 	}
@@ -857,9 +876,10 @@ func (db *DB) prepare(query string) (*Stmt, error) {
 		return nil, err
 	}
 	stmt := &Stmt{
-		db:    db,
-		query: query,
-		css:   []connStmt{{dc, si}},
+		db:            db,
+		query:         query,
+		css:           []connStmt{{dc, si}},
+		lastNumClosed: atomic.LoadUint64(&db.numClosed),
 	}
 	db.addDep(stmt, stmt)
 	db.putConn(dc, nil)
@@ -872,16 +892,19 @@ func (db *DB) Exec(query string, args ...interface{}) (Result, error) {
 	var res Result
 	var err error
 	for i := 0; i < maxBadConnRetries; i++ {
-		res, err = db.exec(query, args)
+		res, err = db.exec(query, args, cachedOrNewConn)
 		if err != driver.ErrBadConn {
 			break
 		}
 	}
+	if err == driver.ErrBadConn {
+		return db.exec(query, args, alwaysNewConn)
+	}
 	return res, err
 }
 
-func (db *DB) exec(query string, args []interface{}) (res Result, err error) {
-	dc, err := db.conn()
+func (db *DB) exec(query string, args []interface{}, strategy connReuseStrategy) (res Result, err error) {
+	dc, err := db.conn(strategy)
 	if err != nil {
 		return nil, err
 	}
@@ -921,16 +944,19 @@ func (db *DB) Query(query string, args ...interface{}) (*Rows, error) {
 	var rows *Rows
 	var err error
 	for i := 0; i < maxBadConnRetries; i++ {
-		rows, err = db.query(query, args)
+		rows, err = db.query(query, args, cachedOrNewConn)
 		if err != driver.ErrBadConn {
 			break
 		}
 	}
+	if err == driver.ErrBadConn {
+		return db.query(query, args, alwaysNewConn)
+	}
 	return rows, err
 }
 
-func (db *DB) query(query string, args []interface{}) (*Rows, error) {
-	ci, err := db.conn()
+func (db *DB) query(query string, args []interface{}, strategy connReuseStrategy) (*Rows, error) {
+	ci, err := db.conn(strategy)
 	if err != nil {
 		return nil, err
 	}
@@ -1009,16 +1035,19 @@ func (db *DB) Begin() (*Tx, error) {
 	var tx *Tx
 	var err error
 	for i := 0; i < maxBadConnRetries; i++ {
-		tx, err = db.begin()
+		tx, err = db.begin(cachedOrNewConn)
 		if err != driver.ErrBadConn {
 			break
 		}
 	}
+	if err == driver.ErrBadConn {
+		return db.begin(alwaysNewConn)
+	}
 	return tx, err
 }
 
-func (db *DB) begin() (tx *Tx, err error) {
-	dc, err := db.conn()
+func (db *DB) begin(strategy connReuseStrategy) (tx *Tx, err error) {
+	dc, err := db.conn(strategy)
 	if err != nil {
 		return nil, err
 	}
@@ -1047,6 +1076,10 @@ func (db *DB) Driver() driver.Driver {
 //
 // After a call to Commit or Rollback, all operations on the
 // transaction fail with ErrTxDone.
+//
+// The statements prepared for a transaction by calling
+// the transaction's Prepare or Stmt methods are closed
+// by the call to Commit or Rollback.
 type Tx struct {
 	db *DB
 
@@ -1182,6 +1215,9 @@ func (tx *Tx) Prepare(query string) (*Stmt, error) {
 //  tx, err := db.Begin()
 //  ...
 //  res, err := tx.Stmt(updateMoney).Exec(123.45, 98293203)
+//
+// The returned statement operates within the transaction and can no longer
+// be used once the transaction has been committed or rolled back.
 func (tx *Tx) Stmt(stmt *Stmt) *Stmt {
 	// TODO(bradfitz): optimize this. Currently this re-prepares
 	// each time.  This is fine for now to illustrate the API but
@@ -1273,7 +1309,8 @@ type connStmt struct {
 	si driver.Stmt
 }
 
-// Stmt is a prepared statement. Stmt is safe for concurrent use by multiple goroutines.
+// Stmt is a prepared statement.
+// A Stmt is safe for concurrent use by multiple goroutines.
 type Stmt struct {
 	// Immutable:
 	db        *DB    // where we came from
@@ -1294,6 +1331,10 @@ type Stmt struct {
 	// used if tx == nil and one is found that has idle
 	// connections.  If tx != nil, txsi is always used.
 	css []connStmt
+
+	// lastNumClosed is copied from db.numClosed when Stmt is created
+	// without tx and closed connections in css are removed.
+	lastNumClosed uint64
 }
 
 // Exec executes a prepared statement with the given arguments and
@@ -1347,6 +1388,32 @@ func resultFromStatement(ds driverStmt, args ...interface{}) (Result, error) {
 	return driverResult{ds.Locker, resi}, nil
 }
 
+// removeClosedStmtLocked removes closed conns in s.css.
+//
+// To avoid lock contention on DB.mu, we do it only when
+// s.db.numClosed - s.lastNum is large enough.
+func (s *Stmt) removeClosedStmtLocked() {
+	t := len(s.css)/2 + 1
+	if t > 10 {
+		t = 10
+	}
+	dbClosed := atomic.LoadUint64(&s.db.numClosed)
+	if dbClosed-s.lastNumClosed < uint64(t) {
+		return
+	}
+
+	s.db.mu.Lock()
+	for i := 0; i < len(s.css); i++ {
+		if s.css[i].dc.dbmuClosed {
+			s.css[i] = s.css[len(s.css)-1]
+			s.css = s.css[:len(s.css)-1]
+			i--
+		}
+	}
+	s.db.mu.Unlock()
+	s.lastNumClosed = dbClosed
+}
+
 // connStmt returns a free driver connection on which to execute the
 // statement, a function to call to release the connection, and a
 // statement bound to that connection.
@@ -1373,35 +1440,15 @@ func (s *Stmt) connStmt() (ci *driverConn, releaseConn func(error), si driver.St
 		return ci, releaseConn, s.txsi.si, nil
 	}
 
-	for i := 0; i < len(s.css); i++ {
-		v := s.css[i]
-		_, err := s.db.connIfFree(v.dc)
-		if err == nil {
-			s.mu.Unlock()
-			return v.dc, v.dc.releaseConn, v.si, nil
-		}
-		if err == errConnClosed {
-			// Lazily remove dead conn from our freelist.
-			s.css[i] = s.css[len(s.css)-1]
-			s.css = s.css[:len(s.css)-1]
-			i--
-		}
-
-	}
+	s.removeClosedStmtLocked()
 	s.mu.Unlock()
 
-	// If all connections are busy, either wait for one to become available (if
-	// we've already hit the maximum number of open connections) or create a
-	// new one.
-	//
 	// TODO(bradfitz): or always wait for one? make configurable later?
-	dc, err := s.db.conn()
+	dc, err := s.db.conn(cachedOrNewConn)
 	if err != nil {
 		return nil, nil, nil, err
 	}
 
-	// Do another pass over the list to see whether this statement has
-	// already been prepared on the connection assigned to us.
 	s.mu.Lock()
 	for _, v := range s.css {
 		if v.dc == dc {
diff --git a/src/database/sql/sql_test.go b/src/database/sql/sql_test.go
index 34efdf2..432a641 100644
--- a/src/database/sql/sql_test.go
+++ b/src/database/sql/sql_test.go
@@ -497,7 +497,7 @@ func TestTxStmt(t *testing.T) {
 	}
 }
 
-// Issue: http://golang.org/issue/2784
+// Issue: https://golang.org/issue/2784
 // This test didn't fail before because we got lucky with the fakedb driver.
 // It was failing, and now not, in github.com/bradfitz/go-sql-test
 func TestTxQuery(t *testing.T) {
@@ -1070,6 +1070,57 @@ func TestMaxOpenConns(t *testing.T) {
 	}
 }
 
+// Issue 9453: tests that SetMaxOpenConns can be lowered at runtime
+// and affects the subsequent release of connections.
+func TestMaxOpenConnsOnBusy(t *testing.T) {
+	defer setHookpostCloseConn(nil)
+	setHookpostCloseConn(func(_ *fakeConn, err error) {
+		if err != nil {
+			t.Errorf("Error closing fakeConn: %v", err)
+		}
+	})
+
+	db := newTestDB(t, "magicquery")
+	defer closeDB(t, db)
+
+	db.SetMaxOpenConns(3)
+
+	conn0, err := db.conn(cachedOrNewConn)
+	if err != nil {
+		t.Fatalf("db open conn fail: %v", err)
+	}
+
+	conn1, err := db.conn(cachedOrNewConn)
+	if err != nil {
+		t.Fatalf("db open conn fail: %v", err)
+	}
+
+	conn2, err := db.conn(cachedOrNewConn)
+	if err != nil {
+		t.Fatalf("db open conn fail: %v", err)
+	}
+
+	if g, w := db.numOpen, 3; g != w {
+		t.Errorf("free conns = %d; want %d", g, w)
+	}
+
+	db.SetMaxOpenConns(2)
+	if g, w := db.numOpen, 3; g != w {
+		t.Errorf("free conns = %d; want %d", g, w)
+	}
+
+	conn0.releaseConn(nil)
+	conn1.releaseConn(nil)
+	if g, w := db.numOpen, 2; g != w {
+		t.Errorf("free conns = %d; want %d", g, w)
+	}
+
+	conn2.releaseConn(nil)
+	if g, w := db.numOpen, 2; g != w {
+		t.Errorf("free conns = %d; want %d", g, w)
+	}
+}
+
 func TestSingleOpenConn(t *testing.T) {
 	db := newTestDB(t, "people")
 	defer closeDB(t, db)
@@ -1093,6 +1144,26 @@ func TestSingleOpenConn(t *testing.T) {
 	}
 }
 
+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() {
@@ -1314,7 +1385,80 @@ func TestStmtCloseOrder(t *testing.T) {
 	}
 }
 
-// golang.org/issue/5781
+// Test cases where there's more than maxBadConnRetries bad connections in the
+// pool (issue 8834)
+func TestManyErrBadConn(t *testing.T) {
+	manyErrBadConnSetup := func() *DB {
+		db := newTestDB(t, "people")
+
+		nconn := maxBadConnRetries + 1
+		db.SetMaxIdleConns(nconn)
+		db.SetMaxOpenConns(nconn)
+		// open enough connections
+		func() {
+			for i := 0; i < nconn; i++ {
+				rows, err := db.Query("SELECT|people|age,name|")
+				if err != nil {
+					t.Fatal(err)
+				}
+				defer rows.Close()
+			}
+		}()
+
+		if db.numOpen != nconn {
+			t.Fatalf("unexpected numOpen %d (was expecting %d)", db.numOpen, nconn)
+		} else if len(db.freeConn) != nconn {
+			t.Fatalf("unexpected len(db.freeConn) %d (was expecting %d)", len(db.freeConn), nconn)
+		}
+		for _, conn := range db.freeConn {
+			conn.ci.(*fakeConn).stickyBad = true
+		}
+		return db
+	}
+
+	// Query
+	db := manyErrBadConnSetup()
+	defer closeDB(t, db)
+	rows, err := db.Query("SELECT|people|age,name|")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if err = rows.Close(); err != nil {
+		t.Fatal(err)
+	}
+
+	// Exec
+	db = manyErrBadConnSetup()
+	defer closeDB(t, db)
+	_, err = db.Exec("INSERT|people|name=Julia,age=19")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// Begin
+	db = manyErrBadConnSetup()
+	defer closeDB(t, db)
+	tx, err := db.Begin()
+	if err != nil {
+		t.Fatal(err)
+	}
+	if err = tx.Rollback(); err != nil {
+		t.Fatal(err)
+	}
+
+	// Prepare
+	db = manyErrBadConnSetup()
+	defer closeDB(t, db)
+	stmt, err := db.Prepare("SELECT|people|age,name|")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if err = stmt.Close(); err != nil {
+		t.Fatal(err)
+	}
+}
+
+// golang.org/issue/5718
 func TestErrBadConnReconnect(t *testing.T) {
 	db := newTestDB(t, "foo")
 	defer closeDB(t, db)
@@ -1764,56 +1908,6 @@ func doConcurrentTest(t testing.TB, ct concurrentTest) {
 	wg.Wait()
 }
 
-func manyConcurrentQueries(t testing.TB) {
-	maxProcs, numReqs := 16, 500
-	if testing.Short() {
-		maxProcs, numReqs = 4, 50
-	}
-	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(maxProcs))
-
-	db := newTestDB(t, "people")
-	defer closeDB(t, db)
-
-	stmt, err := db.Prepare("SELECT|people|name|")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer stmt.Close()
-
-	var wg sync.WaitGroup
-	wg.Add(numReqs)
-
-	reqs := make(chan bool)
-	defer close(reqs)
-
-	for i := 0; i < maxProcs*2; i++ {
-		go func() {
-			for range reqs {
-				rows, err := stmt.Query()
-				if err != nil {
-					t.Errorf("error on query:  %v", err)
-					wg.Done()
-					continue
-				}
-
-				var name string
-				for rows.Next() {
-					rows.Scan(&name)
-				}
-				rows.Close()
-
-				wg.Done()
-			}
-		}()
-	}
-
-	for i := 0; i < numReqs; i++ {
-		reqs <- true
-	}
-
-	wg.Wait()
-}
-
 func TestIssue6081(t *testing.T) {
 	db := newTestDB(t, "people")
 	defer closeDB(t, db)
@@ -1985,3 +2079,31 @@ func BenchmarkConcurrentRandom(b *testing.B) {
 		doConcurrentTest(b, ct)
 	}
 }
+
+func BenchmarkManyConcurrentQueries(b *testing.B) {
+	b.ReportAllocs()
+	// To see lock contention in Go 1.4, 16~ cores and 128~ goroutines are required.
+	const parallelism = 16
+
+	db := newTestDB(b, "magicquery")
+	defer closeDB(b, db)
+	db.SetMaxIdleConns(runtime.GOMAXPROCS(0) * parallelism)
+
+	stmt, err := db.Prepare("SELECT|magicquery|op|op=?,millis=?")
+	if err != nil {
+		b.Fatal(err)
+	}
+	defer stmt.Close()
+
+	b.SetParallelism(parallelism)
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			rows, err := stmt.Query("sleep", 1)
+			if err != nil {
+				b.Error(err)
+				return
+			}
+			rows.Close()
+		}
+	})
+}
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 @@ func (b *buf) addr() uint64 {
 	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/class_string.go b/src/debug/dwarf/class_string.go
new file mode 100644
index 0000000..0b1206b
--- /dev/null
+++ b/src/debug/dwarf/class_string.go
@@ -0,0 +1,17 @@
+// generated by stringer -type=Class; DO NOT EDIT
+
+package dwarf
+
+import "fmt"
+
+const _Class_name = "ClassAddressClassBlockClassConstantClassExprLocClassFlagClassLinePtrClassLocListPtrClassMacPtrClassRangeListPtrClassReferenceClassReferenceSigClassStringClassReferenceAltClassStringAlt"
+
+var _Class_index = [...]uint8{0, 12, 22, 35, 47, 56, 68, 83, 94, 111, 125, 142, 153, 170, 184}
+
+func (i Class) String() string {
+	i -= 1
+	if i < 0 || i+1 >= Class(len(_Class_index)) {
+		return fmt.Sprintf("Class(%d)", i+1)
+	}
+	return _Class_name[_Class_index[i]:_Class_index[i+1]]
+}
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 @@ const (
 	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..d607e5b 100644
--- a/src/debug/dwarf/entry.go
+++ b/src/debug/dwarf/entry.go
@@ -23,8 +23,9 @@ type abbrev struct {
 }
 
 type afield struct {
-	attr Attr
-	fmt  format
+	attr  Attr
+	fmt   format
+	class Class
 }
 
 // a map from entry format ids to their descriptions
@@ -32,7 +33,7 @@ type abbrevTable map[uint32]abbrev
 
 // ParseAbbrev returns the abbreviation table that starts at byte off
 // in the .debug_abbrev section.
-func (d *Data) parseAbbrev(off uint32) (abbrevTable, error) {
+func (d *Data) parseAbbrev(off uint32, vers int) (abbrevTable, error) {
 	if m, ok := d.abbrevCache[off]; ok {
 		return m, nil
 	}
@@ -80,6 +81,7 @@ func (d *Data) parseAbbrev(off uint32) (abbrevTable, error) {
 		for i := range a.field {
 			a.field[i].attr = Attr(b.uint())
 			a.field[i].fmt = format(b.uint())
+			a.field[i].class = formToClass(a.field[i].fmt, a.field[i].attr, vers, &b)
 		}
 		b.uint()
 		b.uint()
@@ -93,6 +95,118 @@ func (d *Data) parseAbbrev(off uint32) (abbrevTable, error) {
 	return m, nil
 }
 
+// attrIsExprloc indicates attributes that allow exprloc values that
+// are encoded as block values in DWARF 2 and 3. See DWARF 4, Figure
+// 20.
+var attrIsExprloc = map[Attr]bool{
+	AttrLocation:      true,
+	AttrByteSize:      true,
+	AttrBitOffset:     true,
+	AttrBitSize:       true,
+	AttrStringLength:  true,
+	AttrLowerBound:    true,
+	AttrReturnAddr:    true,
+	AttrStrideSize:    true,
+	AttrUpperBound:    true,
+	AttrCount:         true,
+	AttrDataMemberLoc: true,
+	AttrFrameBase:     true,
+	AttrSegment:       true,
+	AttrStaticLink:    true,
+	AttrUseLocation:   true,
+	AttrVtableElemLoc: true,
+	AttrAllocated:     true,
+	AttrAssociated:    true,
+	AttrDataLocation:  true,
+	AttrStride:        true,
+}
+
+// attrPtrClass indicates the *ptr class of attributes that have
+// encoding formSecOffset in DWARF 4 or formData* in DWARF 2 and 3.
+var attrPtrClass = map[Attr]Class{
+	AttrLocation:      ClassLocListPtr,
+	AttrStmtList:      ClassLinePtr,
+	AttrStringLength:  ClassLocListPtr,
+	AttrReturnAddr:    ClassLocListPtr,
+	AttrStartScope:    ClassRangeListPtr,
+	AttrDataMemberLoc: ClassLocListPtr,
+	AttrFrameBase:     ClassLocListPtr,
+	AttrMacroInfo:     ClassMacPtr,
+	AttrSegment:       ClassLocListPtr,
+	AttrStaticLink:    ClassLocListPtr,
+	AttrUseLocation:   ClassLocListPtr,
+	AttrVtableElemLoc: ClassLocListPtr,
+	AttrRanges:        ClassRangeListPtr,
+}
+
+// formToClass returns the DWARF 4 Class for the given form. If the
+// DWARF version is less then 4, it will disambiguate some forms
+// depending on the attribute.
+func formToClass(form format, attr Attr, vers int, b *buf) Class {
+	switch form {
+	default:
+		b.error("cannot determine class of unknown attribute form")
+		return 0
+
+	case formAddr:
+		return ClassAddress
+
+	case formDwarfBlock1, formDwarfBlock2, formDwarfBlock4, formDwarfBlock:
+		// In DWARF 2 and 3, ClassExprLoc was encoded as a
+		// block. DWARF 4 distinguishes ClassBlock and
+		// ClassExprLoc, but there are no attributes that can
+		// be both, so we also promote ClassBlock values in
+		// DWARF 4 that should be ClassExprLoc in case
+		// producers get this wrong.
+		if attrIsExprloc[attr] {
+			return ClassExprLoc
+		}
+		return ClassBlock
+
+	case formData1, formData2, formData4, formData8, formSdata, formUdata:
+		// In DWARF 2 and 3, ClassPtr was encoded as a
+		// constant. Unlike ClassExprLoc/ClassBlock, some
+		// DWARF 4 attributes need to distinguish Class*Ptr
+		// from ClassConstant, so we only do this promotion
+		// for versions 2 and 3.
+		if class, ok := attrPtrClass[attr]; vers < 4 && ok {
+			return class
+		}
+		return ClassConstant
+
+	case formFlag, formFlagPresent:
+		return ClassFlag
+
+	case formRefAddr, formRef1, formRef2, formRef4, formRef8, formRefUdata:
+		return ClassReference
+
+	case formRefSig8:
+		return ClassReferenceSig
+
+	case formString, formStrp:
+		return ClassString
+
+	case formSecOffset:
+		// DWARF 4 defines four *ptr classes, but doesn't
+		// distinguish them in the encoding. Disambiguate
+		// these classes using the attribute.
+		if class, ok := attrPtrClass[attr]; ok {
+			return class
+		}
+		b.error("cannot determine class of unknown attribute with formSecOffset")
+		return 0
+
+	case formExprloc:
+		return ClassExprLoc
+
+	case formGnuRefAlt:
+		return ClassReferenceAlt
+
+	case formGnuStrpAlt:
+		return ClassStringAlt
+	}
+}
+
 // An entry is a sequence of attribute/value pairs.
 type Entry struct {
 	Offset   Offset // offset of Entry in DWARF info
@@ -102,9 +216,115 @@ type Entry struct {
 }
 
 // A Field is a single attribute/value pair in an Entry.
+//
+// A value can be one of several "attribute classes" defined by DWARF.
+// The Go types corresponding to each class are:
+//
+//    DWARF class       Go type        Class
+//    -----------       -------        -----
+//    address           uint64         ClassAddress
+//    block             []byte         ClassBlock
+//    constant          int64          ClassConstant
+//    flag              bool           ClassFlag
+//    reference
+//      to info         dwarf.Offset   ClassReference
+//      to type unit    uint64         ClassReferenceSig
+//    string            string         ClassString
+//    exprloc           []byte         ClassExprLoc
+//    lineptr           int64          ClassLinePtr
+//    loclistptr        int64          ClassLocListPtr
+//    macptr            int64          ClassMacPtr
+//    rangelistptr      int64          ClassRangeListPtr
 type Field struct {
-	Attr Attr
-	Val  interface{}
+	Attr  Attr
+	Val   interface{}
+	Class Class
+}
+
+// A Class is the DWARF 4 class of an attibute value.
+//
+// In general, a given attribute's value may take on one of several
+// possible classes defined by DWARF, each of which leads to a
+// slightly different interpretation of the attribute.
+//
+// DWARF version 4 distinguishes attribute value classes more finely
+// than previous versions of DWARF. The reader will disambiguate
+// coarser classes from earlier versions of DWARF into the appropriate
+// DWARF 4 class. For example, DWARF 2 uses "constant" for constants
+// as well as all types of section offsets, but the reader will
+// canonicalize attributes in DWARF 2 files that refer to section
+// offsets to one of the Class*Ptr classes, even though these classes
+// were only defined in DWARF 3.
+type Class int
+
+const (
+	// ClassAddress represents values of type uint64 that are
+	// addresses on the target machine.
+	ClassAddress Class = 1 + iota
+
+	// ClassBlock represents values of type []byte whose
+	// interpretation depends on the attribute.
+	ClassBlock
+
+	// ClassConstant represents values of type int64 that are
+	// constants. The interpretation of this constant depends on
+	// the attribute.
+	ClassConstant
+
+	// ClassExprLoc represents values of type []byte that contain
+	// an encoded DWARF expression or location description.
+	ClassExprLoc
+
+	// ClassFlag represents values of type bool.
+	ClassFlag
+
+	// ClassLinePtr represents values that are an int64 offset
+	// into the "line" section.
+	ClassLinePtr
+
+	// ClassLocListPtr represents values that are an int64 offset
+	// into the "loclist" section.
+	ClassLocListPtr
+
+	// ClassMacPtr represents values that are an int64 offset into
+	// the "mac" section.
+	ClassMacPtr
+
+	// ClassMacPtr represents values that are an int64 offset into
+	// the "rangelist" section.
+	ClassRangeListPtr
+
+	// ClassReference represents values that are an Offset offset
+	// of an Entry in the info section (for use with Reader.Seek).
+	// The DWARF specification combines ClassReference and
+	// ClassReferenceSig into class "reference".
+	ClassReference
+
+	// ClassReferenceSig represents values that are a uint64 type
+	// signature referencing a type Entry.
+	ClassReferenceSig
+
+	// ClassString represents values that are strings. If the
+	// compilation unit specifies the AttrUseUTF8 flag (strongly
+	// recommended), the string value will be encoded in UTF-8.
+	// Otherwise, the encoding is unspecified.
+	ClassString
+
+	// ClassReferenceAlt represents values of type int64 that are
+	// an offset into the DWARF "info" section of an alternate
+	// object file.
+	ClassReferenceAlt
+
+	// ClassStringAlt represents values of type int64 that are an
+	// offset into the DWARF string section of an alternate object
+	// file.
+	ClassStringAlt
+)
+
+//go:generate stringer -type=Class
+
+func (i Class) GoString() string {
+	return "dwarf." + i.String()
 }
 
 // Val returns the value associated with attribute Attr in Entry,
@@ -112,12 +332,21 @@ type Field struct {
 //
 // 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 {
+	if f := e.AttrField(a); f != nil {
+		return f.Val
+	}
+	return nil
+}
+
+// AttrField returns the Field associated with attribute Attr in
+// Entry, or nil if there is no such attribute.
+func (e *Entry) AttrField(a Attr) *Field {
+	for i, f := range e.Field {
 		if f.Attr == a {
-			return f.Val
+			return &e.Field[i]
 		}
 	}
 	return nil
@@ -148,6 +377,7 @@ func (b *buf) entry(atab abbrevTable, ubase Offset) *Entry {
 	}
 	for i := range e.Field {
 		e.Field[i].Attr = a.field[i].attr
+		e.Field[i].Class = a.field[i].class
 		fmt := a.field[i].fmt
 		if fmt == formIndirect {
 			fmt = format(b.uint())
@@ -292,6 +522,12 @@ func (d *Data) Reader() *Reader {
 	return r
 }
 
+// AddressSize returns the size in bytes of addresses in the current compilation
+// unit.
+func (r *Reader) AddressSize() int {
+	return r.d.unit[r.unit].asize
+}
+
 // Seek positions the Reader at offset off in the encoded entry stream.
 // Offset 0 can be used to denote the first entry.
 func (r *Reader) Seek(off Offset) {
@@ -308,18 +544,14 @@ func (r *Reader) Seek(off Offset) {
 		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")
+		return
 	}
-	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
Binary files /dev/null and b/src/debug/dwarf/testdata/line-clang.elf 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
Binary files /dev/null and b/src/debug/dwarf/testdata/line-gcc.elf 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/type.go b/src/debug/dwarf/type.go
index 6986b19..a5daa1d 100644
--- a/src/debug/dwarf/type.go
+++ b/src/debug/dwarf/type.go
@@ -268,6 +268,9 @@ type typeReader interface {
 	Next() (*Entry, error)
 	clone() typeReader
 	offset() Offset
+	// AddressSize returns the size in bytes of addresses in the current
+	// compilation unit.
+	AddressSize() int
 }
 
 // Type reads the type at off in the DWARF ``info'' section.
@@ -286,6 +289,7 @@ func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Off
 	if err != nil {
 		return nil, err
 	}
+	addressSize := r.AddressSize()
 	if e == nil || e.Offset != off {
 		return nil, DecodeError{name, off, "no type at offset"}
 	}
@@ -668,6 +672,12 @@ func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Off
 		b, ok := e.Val(AttrByteSize).(int64)
 		if !ok {
 			b = -1
+			switch t := typ.(type) {
+			case *TypedefType:
+				b = t.Type.Size()
+			case *PtrType:
+				b = int64(addressSize)
+			}
 		}
 		typ.Common().ByteSize = b
 	}
diff --git a/src/debug/dwarf/typeunit.go b/src/debug/dwarf/typeunit.go
index 3fd1c99..9cfb4a8 100644
--- a/src/debug/dwarf/typeunit.go
+++ b/src/debug/dwarf/typeunit.go
@@ -27,21 +27,15 @@ func (d *Data) parseTypes(name string, types []byte) error {
 	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()
+		vers := int(b.uint16())
 		if vers != 4 {
-			b.error("unsupported DWARF version " + strconv.Itoa(int(vers)))
+			b.error("unsupported DWARF version " + strconv.Itoa(vers))
 			return b.err
 		}
 		var ao uint32
@@ -55,7 +49,7 @@ func (d *Data) parseTypes(name string, types []byte) error {
 			}
 			ao = uint32(ao64)
 		}
-		atable, err := d.parseAbbrev(ao)
+		atable, err := d.parseAbbrev(ao, vers)
 		if err != nil {
 			return err
 		}
@@ -79,7 +73,7 @@ func (d *Data) parseTypes(name string, types []byte) error {
 			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),
@@ -135,6 +129,11 @@ func (tur *typeUnitReader) Seek(off Offset) {
 	tur.b = makeBuf(tur.d, tur.tu, tur.tu.name, off, tur.tu.data[doff:])
 }
 
+// AddressSize returns the size in bytes of addresses in the current type unit.
+func (tur *typeUnitReader) AddressSize() int {
+	return tur.tu.unit.asize
+}
+
 // Next reads the next Entry from the type unit.
 func (tur *typeUnitReader) Next() (*Entry, error) {
 	if tur.err != nil {
diff --git a/src/debug/dwarf/unit.go b/src/debug/dwarf/unit.go
index 0fbc8e0..ceb6cdb 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 @@ func (d *Data) parseUnits() ([]unit, error) {
 	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,18 +59,15 @@ func (d *Data) parseUnits() ([]unit, error) {
 	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)))
 			break
 		}
 		u.vers = int(vers)
-		atable, err := d.parseAbbrev(b.uint32())
+		atable, err := d.parseAbbrev(b.uint32(), u.vers)
 		if err != nil {
 			if b.err == nil {
 				b.err = err
@@ -88,3 +84,20 @@ func (d *Data) parseUnits() ([]unit, error) {
 	}
 	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/elf.go b/src/debug/elf/elf.go
index cde296c..70daeec 100644
--- a/src/debug/elf/elf.go
+++ b/src/debug/elf/elf.go
@@ -312,7 +312,7 @@ const (
 	SHN_HIOS      SectionIndex = 0xff3f /* Last operating system-specific. */
 	SHN_ABS       SectionIndex = 0xfff1 /* Absolute values. */
 	SHN_COMMON    SectionIndex = 0xfff2 /* Common data. */
-	SHN_XINDEX    SectionIndex = 0xffff /* Escape -- index stored elsewhere. */
+	SHN_XINDEX    SectionIndex = 0xffff /* Escape; index stored elsewhere. */
 	SHN_HIRESERVE SectionIndex = 0xffff /* Last of reserved range. */
 )
 
@@ -1414,6 +1414,184 @@ var rppcStrings = []intName{
 func (i R_PPC) String() string   { return stringName(uint32(i), rppcStrings, false) }
 func (i R_PPC) GoString() string { return stringName(uint32(i), rppcStrings, true) }
 
+// Relocation types for 64-bit PowerPC or Power Architecture processors.
+type R_PPC64 int
+
+const (
+	R_PPC64_NONE               R_PPC64 = 0
+	R_PPC64_ADDR32             R_PPC64 = 1
+	R_PPC64_ADDR24             R_PPC64 = 2
+	R_PPC64_ADDR16             R_PPC64 = 3
+	R_PPC64_ADDR16_LO          R_PPC64 = 4
+	R_PPC64_ADDR16_HI          R_PPC64 = 5
+	R_PPC64_ADDR16_HA          R_PPC64 = 6
+	R_PPC64_ADDR14             R_PPC64 = 7
+	R_PPC64_ADDR14_BRTAKEN     R_PPC64 = 8
+	R_PPC64_ADDR14_BRNTAKEN    R_PPC64 = 9
+	R_PPC64_REL24              R_PPC64 = 10
+	R_PPC64_REL14              R_PPC64 = 11
+	R_PPC64_REL14_BRTAKEN      R_PPC64 = 12
+	R_PPC64_REL14_BRNTAKEN     R_PPC64 = 13
+	R_PPC64_GOT16              R_PPC64 = 14
+	R_PPC64_GOT16_LO           R_PPC64 = 15
+	R_PPC64_GOT16_HI           R_PPC64 = 16
+	R_PPC64_GOT16_HA           R_PPC64 = 17
+	R_PPC64_JMP_SLOT           R_PPC64 = 21
+	R_PPC64_REL32              R_PPC64 = 26
+	R_PPC64_ADDR64             R_PPC64 = 38
+	R_PPC64_ADDR16_HIGHER      R_PPC64 = 39
+	R_PPC64_ADDR16_HIGHERA     R_PPC64 = 40
+	R_PPC64_ADDR16_HIGHEST     R_PPC64 = 41
+	R_PPC64_ADDR16_HIGHESTA    R_PPC64 = 42
+	R_PPC64_REL64              R_PPC64 = 44
+	R_PPC64_TOC16              R_PPC64 = 47
+	R_PPC64_TOC16_LO           R_PPC64 = 48
+	R_PPC64_TOC16_HI           R_PPC64 = 49
+	R_PPC64_TOC16_HA           R_PPC64 = 50
+	R_PPC64_TOC                R_PPC64 = 51
+	R_PPC64_ADDR16_DS          R_PPC64 = 56
+	R_PPC64_ADDR16_LO_DS       R_PPC64 = 57
+	R_PPC64_GOT16_DS           R_PPC64 = 58
+	R_PPC64_GOT16_LO_DS        R_PPC64 = 59
+	R_PPC64_TOC16_DS           R_PPC64 = 63
+	R_PPC64_TOC16_LO_DS        R_PPC64 = 64
+	R_PPC64_TLS                R_PPC64 = 67
+	R_PPC64_DTPMOD64           R_PPC64 = 68
+	R_PPC64_TPREL16            R_PPC64 = 69
+	R_PPC64_TPREL16_LO         R_PPC64 = 70
+	R_PPC64_TPREL16_HI         R_PPC64 = 71
+	R_PPC64_TPREL16_HA         R_PPC64 = 72
+	R_PPC64_TPREL64            R_PPC64 = 73
+	R_PPC64_DTPREL16           R_PPC64 = 74
+	R_PPC64_DTPREL16_LO        R_PPC64 = 75
+	R_PPC64_DTPREL16_HI        R_PPC64 = 76
+	R_PPC64_DTPREL16_HA        R_PPC64 = 77
+	R_PPC64_DTPREL64           R_PPC64 = 78
+	R_PPC64_GOT_TLSGD16        R_PPC64 = 79
+	R_PPC64_GOT_TLSGD16_LO     R_PPC64 = 80
+	R_PPC64_GOT_TLSGD16_HI     R_PPC64 = 81
+	R_PPC64_GOT_TLSGD16_HA     R_PPC64 = 82
+	R_PPC64_GOT_TLSLD16        R_PPC64 = 83
+	R_PPC64_GOT_TLSLD16_LO     R_PPC64 = 84
+	R_PPC64_GOT_TLSLD16_HI     R_PPC64 = 85
+	R_PPC64_GOT_TLSLD16_HA     R_PPC64 = 86
+	R_PPC64_GOT_TPREL16_DS     R_PPC64 = 87
+	R_PPC64_GOT_TPREL16_LO_DS  R_PPC64 = 88
+	R_PPC64_GOT_TPREL16_HI     R_PPC64 = 89
+	R_PPC64_GOT_TPREL16_HA     R_PPC64 = 90
+	R_PPC64_GOT_DTPREL16_DS    R_PPC64 = 91
+	R_PPC64_GOT_DTPREL16_LO_DS R_PPC64 = 92
+	R_PPC64_GOT_DTPREL16_HI    R_PPC64 = 93
+	R_PPC64_GOT_DTPREL16_HA    R_PPC64 = 94
+	R_PPC64_TPREL16_DS         R_PPC64 = 95
+	R_PPC64_TPREL16_LO_DS      R_PPC64 = 96
+	R_PPC64_TPREL16_HIGHER     R_PPC64 = 97
+	R_PPC64_TPREL16_HIGHERA    R_PPC64 = 98
+	R_PPC64_TPREL16_HIGHEST    R_PPC64 = 99
+	R_PPC64_TPREL16_HIGHESTA   R_PPC64 = 100
+	R_PPC64_DTPREL16_DS        R_PPC64 = 101
+	R_PPC64_DTPREL16_LO_DS     R_PPC64 = 102
+	R_PPC64_DTPREL16_HIGHER    R_PPC64 = 103
+	R_PPC64_DTPREL16_HIGHERA   R_PPC64 = 104
+	R_PPC64_DTPREL16_HIGHEST   R_PPC64 = 105
+	R_PPC64_DTPREL16_HIGHESTA  R_PPC64 = 106
+	R_PPC64_TLSGD              R_PPC64 = 107
+	R_PPC64_TLSLD              R_PPC64 = 108
+	R_PPC64_REL16              R_PPC64 = 249
+	R_PPC64_REL16_LO           R_PPC64 = 250
+	R_PPC64_REL16_HI           R_PPC64 = 251
+	R_PPC64_REL16_HA           R_PPC64 = 252
+)
+
+var rppc64Strings = []intName{
+	{0, "R_PPC64_NONE"},
+	{1, "R_PPC64_ADDR32"},
+	{2, "R_PPC64_ADDR24"},
+	{3, "R_PPC64_ADDR16"},
+	{4, "R_PPC64_ADDR16_LO"},
+	{5, "R_PPC64_ADDR16_HI"},
+	{6, "R_PPC64_ADDR16_HA"},
+	{7, "R_PPC64_ADDR14"},
+	{8, "R_PPC64_ADDR14_BRTAKEN"},
+	{9, "R_PPC64_ADDR14_BRNTAKEN"},
+	{10, "R_PPC64_REL24"},
+	{11, "R_PPC64_REL14"},
+	{12, "R_PPC64_REL14_BRTAKEN"},
+	{13, "R_PPC64_REL14_BRNTAKEN"},
+	{14, "R_PPC64_GOT16"},
+	{15, "R_PPC64_GOT16_LO"},
+	{16, "R_PPC64_GOT16_HI"},
+	{17, "R_PPC64_GOT16_HA"},
+	{21, "R_PPC64_JMP_SLOT"},
+	{26, "R_PPC64_REL32"},
+	{38, "R_PPC64_ADDR64"},
+	{39, "R_PPC64_ADDR16_HIGHER"},
+	{40, "R_PPC64_ADDR16_HIGHERA"},
+	{41, "R_PPC64_ADDR16_HIGHEST"},
+	{42, "R_PPC64_ADDR16_HIGHESTA"},
+	{44, "R_PPC64_REL64"},
+	{47, "R_PPC64_TOC16"},
+	{48, "R_PPC64_TOC16_LO"},
+	{49, "R_PPC64_TOC16_HI"},
+	{50, "R_PPC64_TOC16_HA"},
+	{51, "R_PPC64_TOC"},
+	{56, "R_PPC64_ADDR16_DS"},
+	{57, "R_PPC64_ADDR16_LO_DS"},
+	{58, "R_PPC64_GOT16_DS"},
+	{59, "R_PPC64_GOT16_LO_DS"},
+	{63, "R_PPC64_TOC16_DS"},
+	{64, "R_PPC64_TOC16_LO_DS"},
+	{67, "R_PPC64_TLS"},
+	{68, "R_PPC64_DTPMOD64"},
+	{69, "R_PPC64_TPREL16"},
+	{70, "R_PPC64_TPREL16_LO"},
+	{71, "R_PPC64_TPREL16_HI"},
+	{72, "R_PPC64_TPREL16_HA"},
+	{73, "R_PPC64_TPREL64"},
+	{74, "R_PPC64_DTPREL16"},
+	{75, "R_PPC64_DTPREL16_LO"},
+	{76, "R_PPC64_DTPREL16_HI"},
+	{77, "R_PPC64_DTPREL16_HA"},
+	{78, "R_PPC64_DTPREL64"},
+	{79, "R_PPC64_GOT_TLSGD16"},
+	{80, "R_PPC64_GOT_TLSGD16_LO"},
+	{81, "R_PPC64_GOT_TLSGD16_HI"},
+	{82, "R_PPC64_GOT_TLSGD16_HA"},
+	{83, "R_PPC64_GOT_TLSLD16"},
+	{84, "R_PPC64_GOT_TLSLD16_LO"},
+	{85, "R_PPC64_GOT_TLSLD16_HI"},
+	{86, "R_PPC64_GOT_TLSLD16_HA"},
+	{87, "R_PPC64_GOT_TPREL16_DS"},
+	{88, "R_PPC64_GOT_TPREL16_LO_DS"},
+	{89, "R_PPC64_GOT_TPREL16_HI"},
+	{90, "R_PPC64_GOT_TPREL16_HA"},
+	{91, "R_PPC64_GOT_DTPREL16_DS"},
+	{92, "R_PPC64_GOT_DTPREL16_LO_DS"},
+	{93, "R_PPC64_GOT_DTPREL16_HI"},
+	{94, "R_PPC64_GOT_DTPREL16_HA"},
+	{95, "R_PPC64_TPREL16_DS"},
+	{96, "R_PPC64_TPREL16_LO_DS"},
+	{97, "R_PPC64_TPREL16_HIGHER"},
+	{98, "R_PPC64_TPREL16_HIGHERA"},
+	{99, "R_PPC64_TPREL16_HIGHEST"},
+	{100, "R_PPC64_TPREL16_HIGHESTA"},
+	{101, "R_PPC64_DTPREL16_DS"},
+	{102, "R_PPC64_DTPREL16_LO_DS"},
+	{103, "R_PPC64_DTPREL16_HIGHER"},
+	{104, "R_PPC64_DTPREL16_HIGHERA"},
+	{105, "R_PPC64_DTPREL16_HIGHEST"},
+	{106, "R_PPC64_DTPREL16_HIGHESTA"},
+	{107, "R_PPC64_TLSGD"},
+	{108, "R_PPC64_TLSLD"},
+	{249, "R_PPC64_REL16"},
+	{250, "R_PPC64_REL16_LO"},
+	{251, "R_PPC64_REL16_HI"},
+	{252, "R_PPC64_REL16_HA"},
+}
+
+func (i R_PPC64) String() string   { return stringName(uint32(i), rppc64Strings, false) }
+func (i R_PPC64) GoString() string { return stringName(uint32(i), rppc64Strings, true) }
+
 // Relocation types for SPARC.
 type R_SPARC int
 
diff --git a/src/debug/elf/file.go b/src/debug/elf/file.go
index de8a3a2..4062543 100644
--- a/src/debug/elf/file.go
+++ b/src/debug/elf/file.go
@@ -13,6 +13,7 @@ import (
 	"fmt"
 	"io"
 	"os"
+	"strings"
 )
 
 // TODO: error reporting detail
@@ -523,17 +524,22 @@ func (f *File) Section(name string) *Section {
 // 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)
+	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 {
@@ -622,6 +628,44 @@ func (f *File) applyRelocations386(dst []byte, rels []byte) error {
 	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_ABS32:
+			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 {
@@ -671,54 +715,138 @@ func (f *File) applyRelocationsARM64(dst []byte, rels []byte) error {
 	return nil
 }
 
-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 {
+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
 		}
-		b, err := s.Data()
-		if err != nil && uint64(len(b)) < s.Size {
-			return nil, err
+		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))
 		}
-		dat[i] = b
 	}
 
-	// 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) {
-		data, err := rela.Data()
-		if err != nil {
-			return nil, err
+	return nil
+}
+
+func (f *File) applyRelocationsPPC64(dst []byte, rels []byte) error {
+	// 24 is the size of Rela64.
+	if len(rels)%24 != 0 {
+		return errors.New("length of relocation section is not a multiple of 24")
+	}
+
+	symbols, _, err := f.getSymbols(SHT_SYMTAB)
+	if err != nil {
+		return err
+	}
+
+	b := bytes.NewReader(rels)
+	var rela Rela64
+
+	for b.Len() > 0 {
+		binary.Read(b, f.ByteOrder, &rela)
+		symNo := rela.Info >> 32
+		t := R_PPC64(rela.Info & 0xffff)
+
+		if symNo == 0 || symNo > uint64(len(symbols)) {
+			continue
 		}
-		err = f.applyRelocations(dat[1], data)
-		if err != nil {
-			return nil, err
+		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_PPC64_ADDR64:
+			if rela.Off+8 >= uint64(len(dst)) || rela.Addend < 0 {
+				continue
+			}
+			f.ByteOrder.PutUint64(dst[rela.Off:rela.Off+8], uint64(rela.Addend))
+		case R_PPC64_ADDR32:
+			if rela.Off+4 >= uint64(len(dst)) || rela.Addend < 0 {
+				continue
+			}
+			f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
 		}
 	}
 
-	// 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
+}
+
+func (f *File) DWARF() (*dwarf.Data, error) {
+	// 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
 		}
-		err = f.applyRelocations(dat[1], data)
+
+		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
+	}
+
+	// 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
 		}
+		dat[s.Name[7:]] = b
 	}
 
-	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
 	}
@@ -726,28 +854,11 @@ func (f *File) DWARF() (*dwarf.Data, error) {
 	// 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 5e5ba52..1ad4314 100644
--- a/src/debug/elf/file_test.go
+++ b/src/debug/elf/file_test.go
@@ -245,38 +245,62 @@ var relocationTests = []relocationTest{
 	{
 		"testdata/go-relocation-test-gcc441-x86-64.obj",
 		[]relocationTestEntry{
-			{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "go-relocation-test.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: uint64(0x6)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}}},
+			{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1", Class: dwarf.ClassString}, {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrName, Val: "go-relocation-test.c", Class: dwarf.ClassString}, {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress}, {Attr: dwarf.AttrHighpc, Val: uint6 [...]
 		},
 	},
 	{
 		"testdata/go-relocation-test-gcc441-x86.obj",
 		[]relocationTestEntry{
-			{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "t.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: uint64(0x5)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}}},
+			{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.4.1", Class: dwarf.ClassString}, {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrName, Val: "t.c", Class: dwarf.ClassString}, {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress}, {Attr: dwarf.AttrHighpc, Val: uint64(0x5), Class: dw [...]
 		},
 	},
 	{
 		"testdata/go-relocation-test-gcc424-x86-64.obj",
 		[]relocationTestEntry{
-			{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.2.4 (Ubuntu 4.2.4-1ubuntu4)"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc424.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: uint64(0x6)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}}},
+			{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.2.4 (Ubuntu 4.2.4-1ubuntu4)", Class: dwarf.ClassString}, {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc424.c", Class: dwarf.ClassString}, {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress}, {Att [...]
 		},
 	},
 	{
 		"testdata/go-relocation-test-gcc482-aarch64.obj",
 		[]relocationTestEntry{
-			{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.8.2 -g -fstack-protector"}, {Attr: dwarf.AttrLanguage, Val: int64(1)}, {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc482.c"}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0)}, {Attr: dwarf.AttrHighpc, Val: int64(0x24)}, {Attr: dwarf.AttrStmtList, Val: int64(0)}}}},
+			{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "GNU C 4.8.2 -g -fstack-protector", Class: dwarf.ClassString}, {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc482.c", Class: dwarf.ClassString}, {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}, {Attr: dwarf.AttrLowpc, Val: uint64(0x0), Class: dwarf.ClassAddress}, {Attr:  [...]
+		},
+	},
+	{
+		"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", Class: dwarf.ClassString}, {Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrName, Val: "go-relocation-test-gcc492.c", Class: dwarf.ClassString}, {Attr: dwarf.AttrCompDir, Val: "/root/go/src/debug/elf/testdata", Class:  [...]
+		},
+	},
+	{
+		"testdata/go-relocation-test-clang-arm.obj",
+		[]relocationTestEntry{
+			{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{dwarf.Field{Attr: dwarf.AttrProducer, Val: "Debian clang version 3.5.0-10 (tags/RELEASE_350/final) (based on LLVM 3.5.0)", Class: dwarf.ClassString}, dwarf.Field{Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant}, dwarf.Field{Attr: dwarf.AttrName, Val: "hello.c", Class: dwarf.ClassString}, dwarf.Field{Attr: dwarf.AttrStmtList, Val: int64(0x0), Class: dwarf.ClassLinePtr}, dw [...]
+		},
+	},
+	{
+		"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", Class: dwarf.ClassString}, dwarf.Field{Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant}, dwarf.Field{Attr: dwarf.AttrName, Val: "go-relocation-test-gcc5-ppc.c", Class: dwarf.ClassString}, dwarf.Field{Attr: dwarf.AttrCompDir, Val: "/tmp", Class [...]
+		},
+	},
+	{
+		"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", Class: dwarf.ClassString}, dwarf.Field{Attr: dwarf.AttrLanguage, Val: int64(1), Class: dwarf.ClassConstant}, dwarf.Field{Attr: dwarf.AttrName, Val: "go-relocation-test-gcc482-ppc64le.c", Class: dwarf.ClassString}, dwarf.Field [...]
 		},
 	},
 	{
 		"testdata/go-relocation-test-clang-x86.obj",
 		[]relocationTestEntry{
-			{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "clang version google3-trunk (trunk r209387)"}, {Attr: dwarf.AttrLanguage, Val: int64(12)}, {Attr: dwarf.AttrName, Val: "go-relocation-test-clang.c"}, {Attr: dwarf.AttrStmtList, Val: int64(0)}, {Attr: dwarf.AttrCompDir, Val: "/tmp"}}}},
+			{0, &dwarf.Entry{Offset: 0xb, Tag: dwarf.TagCompileUnit, Children: true, Field: []dwarf.Field{{Attr: dwarf.AttrProducer, Val: "clang version google3-trunk (trunk r209387)", Class: dwarf.ClassString}, {Attr: dwarf.AttrLanguage, Val: int64(12), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrName, Val: "go-relocation-test-clang.c", Class: dwarf.ClassString}, {Attr: dwarf.AttrStmtList, Val: int64(0), Class: dwarf.ClassLinePtr}, {Attr: dwarf.AttrCompDir, Val: "/tmp", Class: dwarf.ClassString}}}},
 		},
 	},
 	{
 		"testdata/gcc-amd64-openbsd-debug-with-rela.obj",
 		[]relocationTestEntry{
-			{203, &dwarf.Entry{Offset: 0xc62, Tag: dwarf.TagMember, Children: false, Field: []dwarf.Field{{Attr: dwarf.AttrName, Val: "it_interval"}, {Attr: dwarf.AttrDeclFile, Val: int64(7)}, {Attr: dwarf.AttrDeclLine, Val: int64(236)}, {Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f)}, {Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x0}}}}},
-			{204, &dwarf.Entry{Offset: 0xc70, Tag: dwarf.TagMember, Children: false, Field: []dwarf.Field{{Attr: dwarf.AttrName, Val: "it_value"}, {Attr: dwarf.AttrDeclFile, Val: int64(7)}, {Attr: dwarf.AttrDeclLine, Val: int64(237)}, {Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f)}, {Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x10}}}}},
+			{203, &dwarf.Entry{Offset: 0xc62, Tag: dwarf.TagMember, Children: false, Field: []dwarf.Field{{Attr: dwarf.AttrName, Val: "it_interval", Class: dwarf.ClassString}, {Attr: dwarf.AttrDeclFile, Val: int64(7), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrDeclLine, Val: int64(236), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f), Class: dwarf.ClassReference}, {Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x0}, Class: dwarf.ClassExprLoc}}}},
+			{204, &dwarf.Entry{Offset: 0xc70, Tag: dwarf.TagMember, Children: false, Field: []dwarf.Field{{Attr: dwarf.AttrName, Val: "it_value", Class: dwarf.ClassString}, {Attr: dwarf.AttrDeclFile, Val: int64(7), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrDeclLine, Val: int64(237), Class: dwarf.ClassConstant}, {Attr: dwarf.AttrType, Val: dwarf.Offset(0xb7f), Class: dwarf.ClassReference}, {Attr: dwarf.AttrDataMemberLoc, Val: []byte{0x23, 0x10}, Class: dwarf.ClassExprLoc}}}},
 		},
 	},
 }
diff --git a/src/debug/elf/testdata/go-relocation-test-clang-arm.obj b/src/debug/elf/testdata/go-relocation-test-clang-arm.obj
new file mode 100644
index 0000000..1cc7e4b
Binary files /dev/null and b/src/debug/elf/testdata/go-relocation-test-clang-arm.obj differ
diff --git a/src/debug/elf/testdata/go-relocation-test-gcc482-ppc64le.obj b/src/debug/elf/testdata/go-relocation-test-gcc482-ppc64le.obj
new file mode 100644
index 0000000..dad7445
Binary files /dev/null and b/src/debug/elf/testdata/go-relocation-test-gcc482-ppc64le.obj differ
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
Binary files /dev/null and b/src/debug/elf/testdata/go-relocation-test-gcc492-arm.obj 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
Binary files /dev/null and b/src/debug/elf/testdata/go-relocation-test-gcc5-ppc.obj differ
diff --git a/src/debug/gosym/pclntab_test.go b/src/debug/gosym/pclntab_test.go
index 35502e8..53f3e95 100644
--- a/src/debug/gosym/pclntab_test.go
+++ b/src/debug/gosym/pclntab_test.go
@@ -6,7 +6,6 @@ package gosym
 
 import (
 	"debug/elf"
-	"fmt"
 	"io/ioutil"
 	"os"
 	"os/exec"
@@ -30,10 +29,6 @@ func dotest(self bool) bool {
 	if self && runtime.GOOS != "linux" {
 		return false
 	}
-	// Command below expects "sh", so Unix.
-	if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
-		return false
-	}
 	if pclinetestBinary != "" {
 		return true
 	}
@@ -49,9 +44,14 @@ func dotest(self bool) bool {
 	// the resulting binary looks like it was built from pclinetest.s,
 	// but we have renamed it to keep it away from the go tool.
 	pclinetestBinary = filepath.Join(pclineTempDir, "pclinetest")
-	command := fmt.Sprintf("go tool 6a -o %s.6 pclinetest.asm && go tool 6l -H linux -E main -o %s %s.6",
-		pclinetestBinary, pclinetestBinary, pclinetestBinary)
-	cmd := exec.Command("sh", "-c", command)
+	cmd := exec.Command("go", "tool", "asm", "-o", pclinetestBinary+".o", "pclinetest.asm")
+	cmd.Stdout = os.Stdout
+	cmd.Stderr = os.Stderr
+	if err := cmd.Run(); err != nil {
+		panic(err)
+	}
+	cmd = exec.Command("go", "tool", "link", "-H", "linux", "-E", "main",
+		"-o", pclinetestBinary, pclinetestBinary+".o")
 	cmd.Stdout = os.Stdout
 	cmd.Stderr = os.Stderr
 	if err := cmd.Run(); err != nil {
@@ -84,7 +84,11 @@ func crack(file string, t *testing.T) (*elf.File, *Table) {
 }
 
 func parse(file string, f *elf.File, t *testing.T) (*elf.File, *Table) {
-	symdat, err := f.Section(".gosymtab").Data()
+	s := f.Section(".gosymtab")
+	if s == nil {
+		t.Skip("no .gosymtab section")
+	}
+	symdat, err := s.Data()
 	if err != nil {
 		f.Close()
 		t.Fatalf("reading %s gosymtab: %v", file, err)
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 Sym struct {
 	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 @@ func (f *File) Section(name string) *Section {
 // 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 @@ func (f *File) DWARF() (*dwarf.Data, error) {
 		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..3df4ae7 100644
--- a/src/debug/pe/file.go
+++ b/src/debug/pe/file.go
@@ -296,9 +296,9 @@ func (f *File) Section(name string) *Section {
 
 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
@@ -310,11 +310,14 @@ func (f *File) DWARF() (*dwarf.Data, error) {
 		if err != nil && uint32(len(b)) < s.Size {
 			return nil, err
 		}
+		if 0 < s.VirtualSize && s.VirtualSize < s.Size {
+			b = b[:s.VirtualSize]
+		}
 		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_test.go b/src/debug/pe/file_test.go
index 0d73969..316a569 100644
--- a/src/debug/pe/file_test.go
+++ b/src/debug/pe/file_test.go
@@ -5,24 +5,30 @@
 package pe
 
 import (
+	"debug/dwarf"
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"path/filepath"
 	"reflect"
+	"runtime"
 	"testing"
 )
 
 type fileTest struct {
-	file     string
-	hdr      FileHeader
-	opthdr   interface{}
-	sections []*SectionHeader
-	symbols  []*Symbol
+	file           string
+	hdr            FileHeader
+	opthdr         interface{}
+	sections       []*SectionHeader
+	symbols        []*Symbol
+	hasNoDwarfInfo bool
 }
 
 var fileTests = []fileTest{
 	{
-		"testdata/gcc-386-mingw-obj",
-		FileHeader{0x014c, 0x000c, 0x0, 0x64a, 0x1e, 0x0, 0x104},
-		nil,
-		[]*SectionHeader{
+		file: "testdata/gcc-386-mingw-obj",
+		hdr:  FileHeader{0x014c, 0x000c, 0x0, 0x64a, 0x1e, 0x0, 0x104},
+		sections: []*SectionHeader{
 			{".text", 0, 0, 36, 500, 1440, 0, 3, 0, 0x60300020},
 			{".data", 0, 0, 0, 0, 0, 0, 0, 0, 3224371264},
 			{".bss", 0, 0, 0, 0, 0, 0, 0, 0, 3224371328},
@@ -36,7 +42,7 @@ var fileTests = []fileTest{
 			{".debug_pubtypes", 0, 0, 38, 1370, 1580, 0, 1, 0, 1108344832},
 			{".debug_aranges", 0, 0, 32, 1408, 1590, 0, 2, 0, 1108344832},
 		},
-		[]*Symbol{
+		symbols: []*Symbol{
 			{".file", 0x0, -2, 0x0, 0x67},
 			{"_main", 0x0, 1, 0x20, 0x2},
 			{".text", 0x0, 1, 0x0, 0x3},
@@ -56,9 +62,9 @@ var fileTests = []fileTest{
 		},
 	},
 	{
-		"testdata/gcc-386-mingw-exec",
-		FileHeader{0x014c, 0x000f, 0x4c6a1b60, 0x3c00, 0x282, 0xe0, 0x107},
-		&OptionalHeader32{
+		file: "testdata/gcc-386-mingw-exec",
+		hdr:  FileHeader{0x014c, 0x000f, 0x4c6a1b60, 0x3c00, 0x282, 0xe0, 0x107},
+		opthdr: &OptionalHeader32{
 			0x10b, 0x2, 0x38, 0xe00, 0x1a00, 0x200, 0x1160, 0x1000, 0x2000, 0x400000, 0x1000, 0x200, 0x4, 0x0, 0x1, 0x0, 0x4, 0x0, 0x0, 0x10000, 0x400, 0x14abb, 0x3, 0x0, 0x200000, 0x1000, 0x100000, 0x1000, 0x0, 0x10,
 			[16]DataDirectory{
 				{0x0, 0x0},
@@ -79,7 +85,7 @@ var fileTests = []fileTest{
 				{0x0, 0x0},
 			},
 		},
-		[]*SectionHeader{
+		sections: []*SectionHeader{
 			{".text", 0xcd8, 0x1000, 0xe00, 0x400, 0x0, 0x0, 0x0, 0x0, 0x60500060},
 			{".data", 0x10, 0x2000, 0x200, 0x1200, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
 			{".rdata", 0x120, 0x3000, 0x200, 0x1400, 0x0, 0x0, 0x0, 0x0, 0x40300040},
@@ -96,13 +102,11 @@ var fileTests = []fileTest{
 			{".debug_frame", 0x34, 0xe000, 0x200, 0x3800, 0x0, 0x0, 0x0, 0x0, 0x42300000},
 			{".debug_loc", 0x38, 0xf000, 0x200, 0x3a00, 0x0, 0x0, 0x0, 0x0, 0x42100000},
 		},
-		[]*Symbol{},
 	},
 	{
-		"testdata/gcc-amd64-mingw-obj",
-		FileHeader{0x8664, 0x6, 0x0, 0x198, 0x12, 0x0, 0x4},
-		nil,
-		[]*SectionHeader{
+		file: "testdata/gcc-amd64-mingw-obj",
+		hdr:  FileHeader{0x8664, 0x6, 0x0, 0x198, 0x12, 0x0, 0x4},
+		sections: []*SectionHeader{
 			{".text", 0x0, 0x0, 0x30, 0x104, 0x15c, 0x0, 0x3, 0x0, 0x60500020},
 			{".data", 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0500040},
 			{".bss", 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0500080},
@@ -110,7 +114,7 @@ var fileTests = []fileTest{
 			{".xdata", 0x0, 0x0, 0xc, 0x144, 0x0, 0x0, 0x0, 0x0, 0x40300040},
 			{".pdata", 0x0, 0x0, 0xc, 0x150, 0x17a, 0x0, 0x3, 0x0, 0x40300040},
 		},
-		[]*Symbol{
+		symbols: []*Symbol{
 			{".file", 0x0, -2, 0x0, 0x67},
 			{"main", 0x0, 1, 0x20, 0x2},
 			{".text", 0x0, 1, 0x0, 0x3},
@@ -122,11 +126,12 @@ var fileTests = []fileTest{
 			{"__main", 0x0, 0, 0x20, 0x2},
 			{"puts", 0x0, 0, 0x20, 0x2},
 		},
+		hasNoDwarfInfo: true,
 	},
 	{
-		"testdata/gcc-amd64-mingw-exec",
-		FileHeader{0x8664, 0x11, 0x53e4364f, 0x39600, 0x6fc, 0xf0, 0x27},
-		&OptionalHeader64{
+		file: "testdata/gcc-amd64-mingw-exec",
+		hdr:  FileHeader{0x8664, 0x11, 0x53e4364f, 0x39600, 0x6fc, 0xf0, 0x27},
+		opthdr: &OptionalHeader64{
 			0x20b, 0x2, 0x16, 0x6a00, 0x2400, 0x1600, 0x14e0, 0x1000, 0x400000, 0x1000, 0x200, 0x4, 0x0, 0x0, 0x0, 0x5, 0x2, 0x0, 0x45000, 0x600, 0x46f19, 0x3, 0x0, 0x200000, 0x1000, 0x100000, 0x1000, 0x0, 0x10,
 			[16]DataDirectory{
 				{0x0, 0x0},
@@ -146,7 +151,7 @@ var fileTests = []fileTest{
 				{0x0, 0x0},
 				{0x0, 0x0},
 			}},
-		[]*SectionHeader{
+		sections: []*SectionHeader{
 			{".text", 0x6860, 0x1000, 0x6a00, 0x600, 0x0, 0x0, 0x0, 0x0, 0x60500020},
 			{".data", 0xe0, 0x8000, 0x200, 0x7000, 0x0, 0x0, 0x0, 0x0, 0xc0500040},
 			{".rdata", 0x6b0, 0x9000, 0x800, 0x7200, 0x0, 0x0, 0x0, 0x0, 0x40600040},
@@ -165,7 +170,6 @@ var fileTests = []fileTest{
 			{".debug_loc", 0x13240, 0x30000, 0x13400, 0x25600, 0x0, 0x0, 0x0, 0x0, 0x42100040},
 			{".debug_ranges", 0xa70, 0x44000, 0xc00, 0x38a00, 0x0, 0x0, 0x0, 0x0, 0x42100040},
 		},
-		[]*Symbol{},
 	},
 }
 
@@ -231,6 +235,12 @@ func TestOpen(t *testing.T) {
 				t.Errorf("open %s, symbol %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want)
 			}
 		}
+		if !tt.hasNoDwarfInfo {
+			_, err = f.DWARF()
+			if err != nil {
+				t.Errorf("fetching %s dwarf details failed: %v", tt.file, err)
+			}
+		}
 	}
 }
 
@@ -241,3 +251,59 @@ func TestOpenFailure(t *testing.T) {
 		t.Errorf("open %s: succeeded unexpectedly", filename)
 	}
 }
+
+func TestDWARF(t *testing.T) {
+	if runtime.GOOS != "windows" {
+		t.Skip("skipping windows only test")
+	}
+
+	tmpdir, err := ioutil.TempDir("", "TestDWARF")
+	if err != nil {
+		t.Fatal("TempDir failed: ", err)
+	}
+	defer os.RemoveAll(tmpdir)
+
+	prog := `
+package main
+func main() {
+}
+`
+	src := filepath.Join(tmpdir, "a.go")
+	exe := filepath.Join(tmpdir, "a.exe")
+	err = ioutil.WriteFile(src, []byte(prog), 0644)
+	output, err := exec.Command("go", "build", "-o", exe, src).CombinedOutput()
+	if err != nil {
+		t.Fatalf("building test executable failed: %s %s", err, output)
+	}
+
+	f, err := Open(exe)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer f.Close()
+
+	d, err := f.DWARF()
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// look for main.main
+	r := d.Reader()
+	for {
+		e, err := r.Next()
+		if err != nil {
+			t.Fatal("r.Next:", err)
+		}
+		if e == nil {
+			break
+		}
+		if e.Tag == dwarf.TagSubprogram {
+			for _, f := range e.Field {
+				if f.Attr == dwarf.AttrName && e.Val(dwarf.AttrName) == "main.main" {
+					return
+				}
+			}
+		}
+	}
+	t.Fatal("main.main not found")
+}
diff --git a/src/encoding/asn1/asn1.go b/src/encoding/asn1/asn1.go
index 8b3d1b3..2ac411a 100644
--- a/src/encoding/asn1/asn1.go
+++ b/src/encoding/asn1/asn1.go
@@ -20,11 +20,13 @@ package asn1
 // everything by any means.
 
 import (
+	"errors"
 	"fmt"
 	"math/big"
 	"reflect"
 	"strconv"
 	"time"
+	"unicode/utf8"
 )
 
 // A StructuralError suggests that the ASN.1 data is valid, but the Go type
@@ -287,11 +289,23 @@ func parseBase128Int(bytes []byte, initOffset int) (ret, offset int, err error)
 
 func parseUTCTime(bytes []byte) (ret time.Time, err error) {
 	s := string(bytes)
-	ret, err = time.Parse("0601021504Z0700", s)
+
+	formatStr := "0601021504Z0700"
+	ret, err = time.Parse(formatStr, s)
+	if err != nil {
+		formatStr = "060102150405Z0700"
+		ret, err = time.Parse(formatStr, s)
+	}
 	if err != nil {
-		ret, err = time.Parse("060102150405Z0700", s)
+		return
 	}
-	if err == nil && ret.Year() >= 2050 {
+
+	if serialized := ret.Format(formatStr); serialized != s {
+		err = fmt.Errorf("asn1: time did not serialize back to the original value and may be invalid: given %q, but serialized as %q", s, serialized)
+		return
+	}
+
+	if ret.Year() >= 2050 {
 		// UTCTime only encodes times prior to 2050. See https://tools.ietf.org/html/rfc5280#section-4.1.2.5.1
 		ret = ret.AddDate(-100, 0, 0)
 	}
@@ -302,7 +316,18 @@ func parseUTCTime(bytes []byte) (ret time.Time, err error) {
 // parseGeneralizedTime parses the GeneralizedTime from the given byte slice
 // and returns the resulting time.
 func parseGeneralizedTime(bytes []byte) (ret time.Time, err error) {
-	return time.Parse("20060102150405Z0700", string(bytes))
+	const formatStr = "20060102150405Z0700"
+	s := string(bytes)
+
+	if ret, err = time.Parse(formatStr, s); err != nil {
+		return
+	}
+
+	if serialized := ret.Format(formatStr); serialized != s {
+		err = fmt.Errorf("asn1: time did not serialize back to the original value and may be invalid: given %q, but serialized as %q", s, serialized)
+	}
+
+	return
 }
 
 // PrintableString
@@ -320,7 +345,7 @@ func parsePrintableString(bytes []byte) (ret string, err error) {
 	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' ||
@@ -365,6 +390,9 @@ func parseT61String(bytes []byte) (ret string, err error) {
 // parseUTF8String parses a ASN.1 UTF8String (raw UTF-8) from the given byte
 // array and returns it.
 func parseUTF8String(bytes []byte) (ret string, err error) {
+	if !utf8.Valid(bytes) {
+		return "", errors.New("asn1: invalid UTF-8 string")
+	}
 	return string(bytes), nil
 }
 
@@ -389,6 +417,12 @@ type RawContent []byte
 // don't distinguish between ordered and unordered objects in this code.
 func parseTagAndLength(bytes []byte, initOffset int) (ret tagAndLength, offset int, err error) {
 	offset = initOffset
+	// parseTagAndLength should not be called without at least a single
+	// byte to read. Thus this check is for robustness:
+	if offset >= len(bytes) {
+		err = errors.New("asn1: internal error in parseTagAndLength")
+		return
+	}
 	b := bytes[offset]
 	offset++
 	ret.class = int(b >> 6)
@@ -579,6 +613,8 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
 				result, err = parseObjectIdentifier(innerBytes)
 			case tagUTCTime:
 				result, err = parseUTCTime(innerBytes)
+			case tagGeneralizedTime:
+				result, err = parseGeneralizedTime(innerBytes)
 			case tagOctetString:
 				result = innerBytes
 			default:
@@ -609,6 +645,10 @@ func parseField(v reflect.Value, bytes []byte, initOffset int, params fieldParam
 		if params.application {
 			expectedClass = classApplication
 		}
+		if offset == len(bytes) {
+			err = StructuralError{"explicit tag has no child"}
+			return
+		}
 		if t.class == expectedClass && t.tag == *params.tag && (t.length == 0 || t.isCompound) {
 			if t.length > 0 {
 				t, offset, err = parseTagAndLength(bytes, offset)
diff --git a/src/encoding/asn1/asn1_test.go b/src/encoding/asn1/asn1_test.go
index 4e864d0..893d080 100644
--- a/src/encoding/asn1/asn1_test.go
+++ b/src/encoding/asn1/asn1_test.go
@@ -9,6 +9,7 @@ import (
 	"fmt"
 	"math/big"
 	"reflect"
+	"strings"
 	"testing"
 	"time"
 )
@@ -258,6 +259,24 @@ var utcTestData = []timeTest{
 	{"91050633444aZ", false, time.Time{}},
 	{"910506334461Z", false, time.Time{}},
 	{"910506334400Za", false, time.Time{}},
+	/* These are invalid times. However, the time package normalises times
+	 * and they were accepted in some versions. See #11134. */
+	{"000100000000Z", false, time.Time{}},
+	{"101302030405Z", false, time.Time{}},
+	{"100002030405Z", false, time.Time{}},
+	{"100100030405Z", false, time.Time{}},
+	{"100132030405Z", false, time.Time{}},
+	{"100231030405Z", false, time.Time{}},
+	{"100102240405Z", false, time.Time{}},
+	{"100102036005Z", false, time.Time{}},
+	{"100102030460Z", false, time.Time{}},
+	{"-100102030410Z", false, time.Time{}},
+	{"10-0102030410Z", false, time.Time{}},
+	{"10-0002030410Z", false, time.Time{}},
+	{"1001-02030410Z", false, time.Time{}},
+	{"100102-030410Z", false, time.Time{}},
+	{"10010203-0410Z", false, time.Time{}},
+	{"1001020304-10Z", false, time.Time{}},
 }
 
 func TestUTCTime(t *testing.T) {
@@ -287,6 +306,24 @@ var generalizedTimeTestData = []timeTest{
 	{"20100102030405", false, time.Time{}},
 	{"20100102030405+0607", true, time.Date(2010, 01, 02, 03, 04, 05, 0, time.FixedZone("", 6*60*60+7*60))},
 	{"20100102030405-0607", true, time.Date(2010, 01, 02, 03, 04, 05, 0, time.FixedZone("", -6*60*60-7*60))},
+	/* These are invalid times. However, the time package normalises times
+	 * and they were accepted in some versions. See #11134. */
+	{"00000100000000Z", false, time.Time{}},
+	{"20101302030405Z", false, time.Time{}},
+	{"20100002030405Z", false, time.Time{}},
+	{"20100100030405Z", false, time.Time{}},
+	{"20100132030405Z", false, time.Time{}},
+	{"20100231030405Z", false, time.Time{}},
+	{"20100102240405Z", false, time.Time{}},
+	{"20100102036005Z", false, time.Time{}},
+	{"20100102030460Z", false, time.Time{}},
+	{"-20100102030410Z", false, time.Time{}},
+	{"2010-0102030410Z", false, time.Time{}},
+	{"2010-0002030410Z", false, time.Time{}},
+	{"201001-02030410Z", false, time.Time{}},
+	{"20100102-030410Z", false, time.Time{}},
+	{"2010010203-0410Z", false, time.Time{}},
+	{"201001020304-10Z", false, time.Time{}},
 }
 
 func TestGeneralizedTime(t *testing.T) {
@@ -297,7 +334,7 @@ func TestGeneralizedTime(t *testing.T) {
 		}
 		if err == nil {
 			if !reflect.DeepEqual(test.out, ret) {
-				t.Errorf("#%d: Bad result: %v (expected %v)", i, ret, test.out)
+				t.Errorf("#%d: Bad result: %q → %v (expected %v)", i, test.in, ret, test.out)
 			}
 		}
 	}
@@ -358,6 +395,8 @@ func newBool(b bool) *bool { return &b }
 var parseFieldParametersTestData []parseFieldParametersTest = []parseFieldParametersTest{
 	{"", fieldParameters{}},
 	{"ia5", fieldParameters{stringType: tagIA5String}},
+	{"generalized", fieldParameters{timeType: tagGeneralizedTime}},
+	{"utc", fieldParameters{timeType: tagUTCTime}},
 	{"printable", fieldParameters{stringType: tagPrintableString}},
 	{"optional", fieldParameters{optional: true}},
 	{"explicit", fieldParameters{explicit: true, tag: new(int)}},
@@ -366,7 +405,7 @@ var parseFieldParametersTestData []parseFieldParametersTest = []parseFieldParame
 	{"default:42", fieldParameters{defaultValue: newInt64(42)}},
 	{"tag:17", fieldParameters{tag: newInt(17)}},
 	{"optional,explicit,default:42,tag:17", fieldParameters{optional: true, explicit: true, defaultValue: newInt64(42), tag: newInt(17)}},
-	{"optional,explicit,default:42,tag:17,rubbish1", fieldParameters{true, true, false, newInt64(42), newInt(17), 0, false, false}},
+	{"optional,explicit,default:42,tag:17,rubbish1", fieldParameters{true, true, false, newInt64(42), newInt(17), 0, 0, false, false}},
 	{"set", fieldParameters{set: true}},
 }
 
@@ -865,3 +904,39 @@ func TestImplicitTaggedTime(t *testing.T) {
 		t.Errorf("Wrong result. Got %v, want %v", result.Time, expected)
 	}
 }
+
+type truncatedExplicitTagTest struct {
+	Test int `asn1:"explicit,tag:0"`
+}
+
+func TestTruncatedExplicitTag(t *testing.T) {
+	// This crashed Unmarshal in the past. See #11154.
+	der := []byte{
+		0x30, // SEQUENCE
+		0x02, // two bytes long
+		0xa0, // context-specific, tag 0
+		0x30, // 48 bytes long
+	}
+
+	var result truncatedExplicitTagTest
+	if _, err := Unmarshal(der, &result); err == nil {
+		t.Error("Unmarshal returned without error")
+	}
+}
+
+type invalidUTF8Test struct {
+	Str string `asn1:"utf8"`
+}
+
+func TestUnmarshalInvalidUTF8(t *testing.T) {
+	data := []byte("0\x05\f\x03a\xc9c")
+	var result invalidUTF8Test
+	_, err := Unmarshal(data, &result)
+
+	const expectedSubstring = "UTF"
+	if err == nil {
+		t.Fatal("Successfully unmarshaled invalid UTF-8 data")
+	} else if !strings.Contains(err.Error(), expectedSubstring) {
+		t.Fatalf("Expected error to mention %q but error was %q", expectedSubstring, err.Error())
+	}
+}
diff --git a/src/encoding/asn1/common.go b/src/encoding/asn1/common.go
index 33a117e..ab85e04 100644
--- a/src/encoding/asn1/common.go
+++ b/src/encoding/asn1/common.go
@@ -74,6 +74,7 @@ type fieldParameters struct {
 	defaultValue *int64 // a default value for INTEGER typed fields (maybe nil).
 	tag          *int   // the EXPLICIT or IMPLICIT tag (maybe nil).
 	stringType   int    // the string tag to use when marshaling.
+	timeType     int    // the time tag to use when marshaling.
 	set          bool   // true iff this should be encoded as a SET
 	omitEmpty    bool   // true iff this should be omitted if empty when marshaling.
 
@@ -94,6 +95,10 @@ func parseFieldParameters(str string) (ret fieldParameters) {
 			if ret.tag == nil {
 				ret.tag = new(int)
 			}
+		case part == "generalized":
+			ret.timeType = tagGeneralizedTime
+		case part == "utc":
+			ret.timeType = tagUTCTime
 		case part == "ia5":
 			ret.stringType = tagIA5String
 		case part == "printable":
diff --git a/src/encoding/asn1/marshal.go b/src/encoding/asn1/marshal.go
index b2f104b..67a019d 100644
--- a/src/encoding/asn1/marshal.go
+++ b/src/encoding/asn1/marshal.go
@@ -18,7 +18,7 @@ import (
 // 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
@@ -410,9 +410,11 @@ func stripTagAndLength(in []byte) []byte {
 
 func marshalBody(out *forkableWriter, value reflect.Value, params fieldParameters) (err error) {
 	switch value.Type() {
+	case flagType:
+		return nil
 	case timeType:
 		t := value.Interface().(time.Time)
-		if outsideUTCRange(t) {
+		if params.timeType == tagGeneralizedTime || outsideUTCRange(t) {
 			return marshalGeneralizedTime(out, t)
 		} else {
 			return marshalUTCTime(out, t)
@@ -552,6 +554,10 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters)
 	}
 	class := classUniversal
 
+	if params.timeType != 0 && tag != tagUTCTime {
+		return StructuralError{"explicit time type given to non-time member"}
+	}
+
 	if params.stringType != 0 && tag != tagPrintableString {
 		return StructuralError{"explicit string type given to non-string member"}
 	}
@@ -575,7 +581,7 @@ func marshalField(out *forkableWriter, v reflect.Value, params fieldParameters)
 			tag = params.stringType
 		}
 	case tagUTCTime:
-		if outsideUTCRange(v.Interface().(time.Time)) {
+		if params.timeType == tagGeneralizedTime || outsideUTCRange(v.Interface().(time.Time)) {
 			tag = tagGeneralizedTime
 		}
 	}
diff --git a/src/encoding/asn1/marshal_test.go b/src/encoding/asn1/marshal_test.go
index 5b0115f..cdca8aa 100644
--- a/src/encoding/asn1/marshal_test.go
+++ b/src/encoding/asn1/marshal_test.go
@@ -42,6 +42,14 @@ type explicitTagTest struct {
 	A int `asn1:"explicit,tag:5"`
 }
 
+type flagTest struct {
+	A Flag `asn1:"tag:0,optional"`
+}
+
+type generalizedTimeTest struct {
+	A time.Time `asn1:"generalized"`
+}
+
 type ia5StringTest struct {
 	A string `asn1:"ia5"`
 }
@@ -92,10 +100,13 @@ var marshalTests = []marshalTest{
 	{[]byte{1, 2, 3}, "0403010203"},
 	{implicitTagTest{64}, "3003850140"},
 	{explicitTagTest{64}, "3005a503020140"},
+	{flagTest{true}, "30028000"},
+	{flagTest{false}, "3000"},
 	{time.Unix(0, 0).UTC(), "170d3730303130313030303030305a"},
 	{time.Unix(1258325776, 0).UTC(), "170d3039313131353232353631365a"},
 	{time.Unix(1258325776, 0).In(PST), "17113039313131353134353631362d30383030"},
 	{farFuture(), "180f32313030303430353132303130315a"},
+	{generalizedTimeTest{time.Unix(1258325776, 0).UTC()}, "3011180f32303039313131353232353631365a"},
 	{BitString{[]byte{0x80}, 1}, "03020780"},
 	{BitString{[]byte{0x81, 0xf0}, 12}, "03030481f0"},
 	{ObjectIdentifier([]int{1, 2, 3, 4}), "06032a0304"},
diff --git a/src/encoding/base64/base64.go b/src/encoding/base64/base64.go
index ad3abe6..3302fb4 100644
--- a/src/encoding/base64/base64.go
+++ b/src/encoding/base64/base64.go
@@ -6,10 +6,8 @@
 package base64
 
 import (
-	"bytes"
 	"io"
 	"strconv"
-	"strings"
 )
 
 /*
@@ -22,18 +20,32 @@ import (
 // (RFC 1421).  RFC 4648 also defines an alternate encoding, which is
 // the standard encoding with - and _ substituted for + and /.
 type Encoding struct {
-	encode    string
+	encode    [64]byte
 	decodeMap [256]byte
+	padChar   rune
 }
 
+const (
+	StdPadding rune = '=' // Standard padding character
+	NoPadding  rune = -1  // No padding
+)
+
 const encodeStd = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
 const encodeURL = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
 
-// NewEncoding returns a new Encoding defined by the given alphabet,
+// NewEncoding returns a new padded Encoding defined by the given alphabet,
 // which must be a 64-byte string.
+// The resulting Encoding uses the default padding character ('='),
+// which may be changed or disabled via WithPadding.
 func NewEncoding(encoder string) *Encoding {
+	if len(encoder) != 64 {
+		panic("encoding alphabet is not 64-bytes long")
+	}
+
 	e := new(Encoding)
-	e.encode = encoder
+	e.padChar = StdPadding
+	copy(e.encode[:], encoder)
+
 	for i := 0; i < len(e.decodeMap); i++ {
 		e.decodeMap[i] = 0xFF
 	}
@@ -43,6 +55,13 @@ func NewEncoding(encoder string) *Encoding {
 	return e
 }
 
+// WithPadding creates a new encoding identical to enc except
+// with a specified padding character, or NoPadding to disable padding.
+func (enc Encoding) WithPadding(padding rune) *Encoding {
+	enc.padChar = padding
+	return &enc
+}
+
 // StdEncoding is the standard base64 encoding, as defined in
 // RFC 4648.
 var StdEncoding = NewEncoding(encodeStd)
@@ -51,12 +70,15 @@ var StdEncoding = NewEncoding(encodeStd)
 // It is typically used in URLs and file names.
 var URLEncoding = NewEncoding(encodeURL)
 
-var removeNewlinesMapper = func(r rune) rune {
-	if r == '\r' || r == '\n' {
-		return -1
-	}
-	return r
-}
+// RawStdEncoding is the standard raw, unpadded base64 encoding,
+// as defined in RFC 4648 section 3.2.
+// This is the same as StdEncoding but omits padding characters.
+var RawStdEncoding = StdEncoding.WithPadding(NoPadding)
+
+// URLEncoding is the unpadded alternate base64 encoding defined in RFC 4648.
+// It is typically used in URLs and file names.
+// This is the same as URLEncoding but omits padding characters.
+var RawURLEncoding = URLEncoding.WithPadding(NoPadding)
 
 /*
  * Encoder
@@ -73,42 +95,45 @@ func (enc *Encoding) Encode(dst, src []byte) {
 		return
 	}
 
-	for len(src) > 0 {
-		var b0, b1, b2, b3 byte
+	di, si := 0, 0
+	n := (len(src) / 3) * 3
+	for si < n {
+		// Convert 3x 8bit source bytes into 4 bytes
+		val := uint(src[si+0])<<16 | uint(src[si+1])<<8 | uint(src[si+2])
 
-		// Unpack 4x 6-bit source blocks into a 4 byte
-		// destination quantum
-		switch len(src) {
-		default:
-			b3 = src[2] & 0x3F
-			b2 = src[2] >> 6
-			fallthrough
-		case 2:
-			b2 |= (src[1] << 2) & 0x3F
-			b1 = src[1] >> 4
-			fallthrough
-		case 1:
-			b1 |= (src[0] << 4) & 0x3F
-			b0 = src[0] >> 2
-		}
+		dst[di+0] = enc.encode[val>>18&0x3F]
+		dst[di+1] = enc.encode[val>>12&0x3F]
+		dst[di+2] = enc.encode[val>>6&0x3F]
+		dst[di+3] = enc.encode[val&0x3F]
 
-		// Encode 6-bit blocks using the base64 alphabet
-		dst[0] = enc.encode[b0]
-		dst[1] = enc.encode[b1]
-		dst[2] = enc.encode[b2]
-		dst[3] = enc.encode[b3]
-
-		// Pad the final quantum
-		if len(src) < 3 {
-			dst[3] = '='
-			if len(src) < 2 {
-				dst[2] = '='
-			}
-			break
-		}
+		si += 3
+		di += 4
+	}
+
+	remain := len(src) - si
+	if remain == 0 {
+		return
+	}
+	// Add the remaining small block
+	val := uint(src[si+0]) << 16
+	if remain == 2 {
+		val |= uint(src[si+1]) << 8
+	}
+
+	dst[di+0] = enc.encode[val>>18&0x3F]
+	dst[di+1] = enc.encode[val>>12&0x3F]
 
-		src = src[3:]
-		dst = dst[4:]
+	switch remain {
+	case 2:
+		dst[di+2] = enc.encode[val>>6&0x3F]
+		if enc.padChar != NoPadding {
+			dst[di+3] = byte(enc.padChar)
+		}
+	case 1:
+		if enc.padChar != NoPadding {
+			dst[di+2] = byte(enc.padChar)
+			dst[di+3] = byte(enc.padChar)
+		}
 	}
 }
 
@@ -145,8 +170,8 @@ func (e *encoder) Write(p []byte) (n int, err error) {
 		if e.nbuf < 3 {
 			return
 		}
-		e.enc.Encode(e.out[0:], e.buf[0:])
-		if _, e.err = e.w.Write(e.out[0:4]); e.err != nil {
+		e.enc.Encode(e.out[:], e.buf[:])
+		if _, e.err = e.w.Write(e.out[:4]); e.err != nil {
 			return n, e.err
 		}
 		e.nbuf = 0
@@ -159,7 +184,7 @@ func (e *encoder) Write(p []byte) (n int, err error) {
 			nn = len(p)
 			nn -= nn % 3
 		}
-		e.enc.Encode(e.out[0:], p[0:nn])
+		e.enc.Encode(e.out[:], p[:nn])
 		if _, e.err = e.w.Write(e.out[0 : nn/3*4]); e.err != nil {
 			return n, e.err
 		}
@@ -181,9 +206,9 @@ func (e *encoder) Write(p []byte) (n int, err error) {
 func (e *encoder) Close() error {
 	// If there's anything left in the buffer, flush it out
 	if e.err == nil && e.nbuf > 0 {
-		e.enc.Encode(e.out[0:], e.buf[0:e.nbuf])
+		e.enc.Encode(e.out[:], e.buf[:e.nbuf])
+		_, e.err = e.w.Write(e.out[:e.enc.EncodedLen(e.nbuf)])
 		e.nbuf = 0
-		_, e.err = e.w.Write(e.out[0:4])
 	}
 	return e.err
 }
@@ -199,7 +224,12 @@ func NewEncoder(enc *Encoding, w io.Writer) io.WriteCloser {
 
 // EncodedLen returns the length in bytes of the base64 encoding
 // of an input buffer of length n.
-func (enc *Encoding) EncodedLen(n int) int { return (n + 2) / 3 * 4 }
+func (enc *Encoding) EncodedLen(n int) int {
+	if enc.padChar == NoPadding {
+		return (n*8 + 5) / 6 // minimum # chars at 6 bits per char
+	}
+	return (n + 2) / 3 * 4 // minimum # 4-char quanta, 3 bytes each
+}
 
 /*
  * Decoder
@@ -212,66 +242,86 @@ func (e CorruptInputError) Error() string {
 }
 
 // decode is like Decode but returns an additional 'end' value, which
-// indicates if end-of-message padding was encountered and thus any
-// additional data is an error. This method assumes that src has been
-// stripped of all supported whitespace ('\r' and '\n').
+// indicates if end-of-message padding or a partial quantum was encountered
+// and thus any additional data is an error.
 func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
-	olen := len(src)
-	for len(src) > 0 && !end {
+	si := 0
+
+	// skip over newlines
+	for si < len(src) && (src[si] == '\n' || src[si] == '\r') {
+		si++
+	}
+
+	for si < len(src) && !end {
 		// Decode quantum using the base64 alphabet
 		var dbuf [4]byte
-		dlen := 4
+		dinc, dlen := 3, 4
 
 		for j := range dbuf {
-			if len(src) == 0 {
-				return n, false, CorruptInputError(olen - len(src) - j)
+			if len(src) == si {
+				if enc.padChar != NoPadding || j < 2 {
+					return n, false, CorruptInputError(si - j)
+				}
+				dinc, dlen, end = j-1, j, true
+				break
 			}
-			in := src[0]
-			src = src[1:]
-			if in == '=' {
+			in := src[si]
+
+			si++
+			// skip over newlines
+			for si < len(src) && (src[si] == '\n' || src[si] == '\r') {
+				si++
+			}
+
+			if rune(in) == enc.padChar {
 				// We've reached the end and there's padding
 				switch j {
 				case 0, 1:
 					// incorrect padding
-					return n, false, CorruptInputError(olen - len(src) - 1)
+					return n, false, CorruptInputError(si - 1)
 				case 2:
 					// "==" is expected, the first "=" is already consumed.
-					if len(src) == 0 {
+					if si == len(src) {
 						// not enough padding
-						return n, false, CorruptInputError(olen)
+						return n, false, CorruptInputError(len(src))
 					}
-					if src[0] != '=' {
+					if rune(src[si]) != enc.padChar {
 						// incorrect padding
-						return n, false, CorruptInputError(olen - len(src) - 1)
+						return n, false, CorruptInputError(si - 1)
+					}
+
+					si++
+					// skip over newlines
+					for si < len(src) && (src[si] == '\n' || src[si] == '\r') {
+						si++
 					}
-					src = src[1:]
 				}
-				if len(src) > 0 {
+				if si < len(src) {
 					// trailing garbage
-					err = CorruptInputError(olen - len(src))
+					err = CorruptInputError(si)
 				}
-				dlen, end = j, true
+				dinc, dlen, end = 3, j, true
 				break
 			}
 			dbuf[j] = enc.decodeMap[in]
 			if dbuf[j] == 0xFF {
-				return n, false, CorruptInputError(olen - len(src) - 1)
+				return n, false, CorruptInputError(si - 1)
 			}
 		}
 
-		// Pack 4x 6-bit source blocks into 3 byte destination
-		// quantum
+		// Convert 4x 6bit source bytes into 3 bytes
+		val := uint(dbuf[0])<<18 | uint(dbuf[1])<<12 | uint(dbuf[2])<<6 | uint(dbuf[3])
 		switch dlen {
 		case 4:
-			dst[2] = dbuf[2]<<6 | dbuf[3]
+			dst[2] = byte(val >> 0)
 			fallthrough
 		case 3:
-			dst[1] = dbuf[1]<<4 | dbuf[2]>>2
+			dst[1] = byte(val >> 8)
 			fallthrough
 		case 2:
-			dst[0] = dbuf[0]<<2 | dbuf[1]>>4
+			dst[0] = byte(val >> 16)
 		}
-		dst = dst[3:]
+		dst = dst[dinc:]
 		n += dlen - 1
 	}
 
@@ -284,14 +334,12 @@ func (enc *Encoding) decode(dst, src []byte) (n int, end bool, err error) {
 // number of bytes successfully written and CorruptInputError.
 // New line characters (\r and \n) are ignored.
 func (enc *Encoding) Decode(dst, src []byte) (n int, err error) {
-	src = bytes.Map(removeNewlinesMapper, src)
 	n, _, err = enc.decode(dst, src)
 	return
 }
 
 // DecodeString returns the bytes represented by the base64 string s.
 func (enc *Encoding) DecodeString(s string) ([]byte, error) {
-	s = strings.Map(removeNewlinesMapper, s)
 	dbuf := make([]byte, enc.DecodedLen(len(s)))
 	n, _, err := enc.decode(dbuf, []byte(s))
 	return dbuf[:n], err
@@ -320,6 +368,8 @@ func (d *decoder) Read(p []byte) (n int, err error) {
 		return n, nil
 	}
 
+	// This code assumes that d.r strips supported whitespace ('\r' and '\n').
+
 	// Read a chunk.
 	nn := len(p) / 3 * 4
 	if nn < 4 {
@@ -338,12 +388,12 @@ func (d *decoder) Read(p []byte) (n int, err error) {
 	nr := d.nbuf / 4 * 4
 	nw := d.nbuf / 4 * 3
 	if nw > len(p) {
-		nw, d.end, d.err = d.enc.decode(d.outbuf[0:], d.buf[0:nr])
-		d.out = d.outbuf[0:nw]
+		nw, d.end, d.err = d.enc.decode(d.outbuf[:], d.buf[:nr])
+		d.out = d.outbuf[:nw]
 		n = copy(p, d.out)
 		d.out = d.out[n:]
 	} else {
-		n, d.end, d.err = d.enc.decode(p, d.buf[0:nr])
+		n, d.end, d.err = d.enc.decode(p, d.buf[:nr])
 	}
 	d.nbuf -= nr
 	for i := 0; i < d.nbuf; i++ {
@@ -364,7 +414,7 @@ func (r *newlineFilteringReader) Read(p []byte) (int, error) {
 	n, err := r.wrapped.Read(p)
 	for n > 0 {
 		offset := 0
-		for i, b := range p[0:n] {
+		for i, b := range p[:n] {
 			if b != '\r' && b != '\n' {
 				if i != offset {
 					p[offset] = b
@@ -388,4 +438,11 @@ func NewDecoder(enc *Encoding, r io.Reader) io.Reader {
 
 // DecodedLen returns the maximum length in bytes of the decoded data
 // corresponding to n bytes of base64-encoded data.
-func (enc *Encoding) DecodedLen(n int) int { return n / 4 * 3 }
+func (enc *Encoding) DecodedLen(n int) int {
+	if enc.padChar == NoPadding {
+		// Unpadded data may end with partial block of 2-3 characters.
+		return (n*6 + 7) / 8
+	}
+	// Padded base64 should always be a multiple of 4 characters in length.
+	return n / 4 * 3
+}
diff --git a/src/encoding/base64/base64_test.go b/src/encoding/base64/base64_test.go
index 7d199bf..d144b96 100644
--- a/src/encoding/base64/base64_test.go
+++ b/src/encoding/base64/base64_test.go
@@ -45,6 +45,48 @@ var pairs = []testpair{
 	{"sure.", "c3VyZS4="},
 }
 
+// Do nothing to a reference base64 string (leave in standard format)
+func stdRef(ref string) string {
+	return ref
+}
+
+// Convert a reference string to URL-encoding
+func urlRef(ref string) string {
+	ref = strings.Replace(ref, "+", "-", -1)
+	ref = strings.Replace(ref, "/", "_", -1)
+	return ref
+}
+
+// Convert a reference string to raw, unpadded format
+func rawRef(ref string) string {
+	return strings.TrimRight(ref, "=")
+}
+
+// Both URL and unpadding conversions
+func rawUrlRef(ref string) string {
+	return rawRef(urlRef(ref))
+}
+
+// A nonstandard encoding with a funny padding character, for testing
+var funnyEncoding = NewEncoding(encodeStd).WithPadding(rune('@'))
+
+func funnyRef(ref string) string {
+	return strings.Replace(ref, "=", "@", -1)
+}
+
+type encodingTest struct {
+	enc  *Encoding           // Encoding to test
+	conv func(string) string // Reference string converter
+}
+
+var encodingTests = []encodingTest{
+	encodingTest{StdEncoding, stdRef},
+	encodingTest{URLEncoding, urlRef},
+	encodingTest{RawStdEncoding, rawRef},
+	encodingTest{RawURLEncoding, rawUrlRef},
+	encodingTest{funnyEncoding, funnyRef},
+}
+
 var bigtest = testpair{
 	"Twas brillig, and the slithy toves",
 	"VHdhcyBicmlsbGlnLCBhbmQgdGhlIHNsaXRoeSB0b3Zlcw==",
@@ -60,8 +102,11 @@ func testEqual(t *testing.T, msg string, args ...interface{}) bool {
 
 func TestEncode(t *testing.T) {
 	for _, p := range pairs {
-		got := StdEncoding.EncodeToString([]byte(p.decoded))
-		testEqual(t, "Encode(%q) = %q, want %q", p.decoded, got, p.encoded)
+		for _, tt := range encodingTests {
+			got := tt.enc.EncodeToString([]byte(p.decoded))
+			testEqual(t, "Encode(%q) = %q, want %q", p.decoded,
+				got, tt.conv(p.encoded))
+		}
 	}
 }
 
@@ -97,18 +142,21 @@ func TestEncoderBuffering(t *testing.T) {
 
 func TestDecode(t *testing.T) {
 	for _, p := range pairs {
-		dbuf := make([]byte, StdEncoding.DecodedLen(len(p.encoded)))
-		count, end, err := StdEncoding.decode(dbuf, []byte(p.encoded))
-		testEqual(t, "Decode(%q) = error %v, want %v", p.encoded, err, error(nil))
-		testEqual(t, "Decode(%q) = length %v, want %v", p.encoded, count, len(p.decoded))
-		if len(p.encoded) > 0 {
-			testEqual(t, "Decode(%q) = end %v, want %v", p.encoded, end, (p.encoded[len(p.encoded)-1] == '='))
-		}
-		testEqual(t, "Decode(%q) = %q, want %q", p.encoded, string(dbuf[0:count]), p.decoded)
+		for _, tt := range encodingTests {
+			encoded := tt.conv(p.encoded)
+			dbuf := make([]byte, tt.enc.DecodedLen(len(encoded)))
+			count, end, err := tt.enc.decode(dbuf, []byte(encoded))
+			testEqual(t, "Decode(%q) = error %v, want %v", encoded, err, error(nil))
+			testEqual(t, "Decode(%q) = length %v, want %v", encoded, count, len(p.decoded))
+			if len(encoded) > 0 {
+				testEqual(t, "Decode(%q) = end %v, want %v", encoded, end, len(p.decoded)%3 != 0)
+			}
+			testEqual(t, "Decode(%q) = %q, want %q", encoded, string(dbuf[0:count]), p.decoded)
 
-		dbuf, err = StdEncoding.DecodeString(p.encoded)
-		testEqual(t, "DecodeString(%q) = error %v, want %v", p.encoded, err, error(nil))
-		testEqual(t, "DecodeString(%q) = %q, want %q", string(dbuf), p.decoded)
+			dbuf, err = tt.enc.DecodeString(encoded)
+			testEqual(t, "DecodeString(%q) = error %v, want %v", encoded, err, error(nil))
+			testEqual(t, "DecodeString(%q) = %q, want %q", string(dbuf), p.decoded)
+		}
 	}
 }
 
diff --git a/src/encoding/binary/binary.go b/src/encoding/binary/binary.go
index 466bf97..2bbe07c 100644
--- a/src/encoding/binary/binary.go
+++ b/src/encoding/binary/binary.go
@@ -13,7 +13,7 @@
 // The varint functions encode and decode single integer values using
 // a variable-length encoding; smaller values require fewer bytes.
 // For a specification, see
-// http://code.google.com/apis/protocolbuffers/docs/encoding.html.
+// https://developers.google.com/protocol-buffers/docs/encoding.
 //
 // This package favors simplicity over efficiency. Clients that require
 // high-performance serialization, especially for large data structures,
@@ -239,78 +239,62 @@ func Write(w io.Writer, order ByteOrder, data interface{}) error {
 		}
 		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 {
@@ -605,25 +589,25 @@ func (e *encoder) skip(v reflect.Value) {
 // It returns zero if the type cannot be implemented by the fast path in Read or Write.
 func intDataSize(data interface{}) int {
 	switch data := data.(type) {
-	case int8, *int8, *uint8:
+	case int8, uint8, *int8, *uint8:
 		return 1
 	case []int8:
 		return len(data)
 	case []uint8:
 		return len(data)
-	case int16, *int16, *uint16:
+	case int16, uint16, *int16, *uint16:
 		return 2
 	case []int16:
 		return 2 * len(data)
 	case []uint16:
 		return 2 * len(data)
-	case int32, *int32, *uint32:
+	case int32, uint32, *int32, *uint32:
 		return 4
 	case []int32:
 		return 4 * len(data)
 	case []uint32:
 		return 4 * len(data)
-	case int64, *int64, *uint64:
+	case int64, uint64, *int64, *uint64:
 		return 8
 	case []int64:
 		return 8 * len(data)
diff --git a/src/encoding/csv/example_test.go b/src/encoding/csv/example_test.go
new file mode 100644
index 0000000..dc227d4
--- /dev/null
+++ b/src/encoding/csv/example_test.go
@@ -0,0 +1,131 @@
+// 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 csv_test
+
+import (
+	"encoding/csv"
+	"fmt"
+	"io"
+	"log"
+	"os"
+	"strings"
+)
+
+func ExampleReader() {
+	in := `first_name,last_name,username
+"Rob","Pike",rob
+Ken,Thompson,ken
+"Robert","Griesemer","gri"
+`
+	r := csv.NewReader(strings.NewReader(in))
+
+	for {
+		record, err := r.Read()
+		if err == io.EOF {
+			break
+		}
+		if err != nil {
+			log.Fatal(err)
+		}
+
+		fmt.Println(record)
+	}
+	// Output:
+	// [first_name last_name username]
+	// [Rob Pike rob]
+	// [Ken Thompson ken]
+	// [Robert Griesemer gri]
+}
+
+// This example shows how csv.Reader can be configured to handle other
+// types of CSV files.
+func ExampleReader_options() {
+	in := `first_name;last_name;username
+"Rob";"Pike";rob
+# lines beginning with a # character are ignored
+Ken;Thompson;ken
+"Robert";"Griesemer";"gri"
+`
+	r := csv.NewReader(strings.NewReader(in))
+	r.Comma = ';'
+	r.Comment = '#'
+
+	records, err := r.ReadAll()
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	fmt.Print(records)
+	// Output:
+	// [[first_name last_name username] [Rob Pike rob] [Ken Thompson ken] [Robert Griesemer gri]]
+}
+
+func ExampleReader_ReadAll() {
+	in := `first_name,last_name,username
+"Rob","Pike",rob
+Ken,Thompson,ken
+"Robert","Griesemer","gri"
+`
+	r := csv.NewReader(strings.NewReader(in))
+
+	records, err := r.ReadAll()
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	fmt.Print(records)
+	// Output:
+	// [[first_name last_name username] [Rob Pike rob] [Ken Thompson ken] [Robert Griesemer gri]]
+}
+
+func ExampleWriter() {
+	records := [][]string{
+		{"first_name", "last_name", "username"},
+		{"Rob", "Pike", "rob"},
+		{"Ken", "Thompson", "ken"},
+		{"Robert", "Griesemer", "gri"},
+	}
+
+	w := csv.NewWriter(os.Stdout)
+
+	for _, record := range records {
+		if err := w.Write(record); err != nil {
+			log.Fatalln("error writing record to csv:", err)
+		}
+	}
+
+	// Write any buffered data to the underlying writer (standard output).
+	w.Flush()
+
+	if err := w.Error(); err != nil {
+		log.Fatal(err)
+	}
+	// Output:
+	// first_name,last_name,username
+	// Rob,Pike,rob
+	// Ken,Thompson,ken
+	// Robert,Griesemer,gri
+}
+
+func ExampleWriter_WriteAll() {
+	records := [][]string{
+		{"first_name", "last_name", "username"},
+		{"Rob", "Pike", "rob"},
+		{"Ken", "Thompson", "ken"},
+		{"Robert", "Griesemer", "gri"},
+	}
+
+	w := csv.NewWriter(os.Stdout)
+	w.WriteAll(records) // calls Flush internally
+
+	if err := w.Error(); err != nil {
+		log.Fatalln("error writing csv:", err)
+	}
+	// Output:
+	// first_name,last_name,username
+	// Rob,Pike,rob
+	// Ken,Thompson,ken
+	// Robert,Griesemer,gri
+}
diff --git a/src/encoding/csv/reader.go b/src/encoding/csv/reader.go
index d943295..37bf80c 100644
--- a/src/encoding/csv/reader.go
+++ b/src/encoding/csv/reader.go
@@ -215,7 +215,7 @@ func (r *Reader) parseRecord() (fields []string, err error) {
 	r.column = -1
 
 	// Peek at the first rune.  If it is an error we are done.
-	// If we are support comments and it is the comment character
+	// If we support comments and it is the comment character
 	// then skip to the end of line.
 
 	r1, _, err := r.r.ReadRune()
@@ -232,6 +232,11 @@ func (r *Reader) parseRecord() (fields []string, err error) {
 	for {
 		haveField, delim, err := r.parseField()
 		if haveField {
+			// If FieldsPerRecord is greater then 0 we can assume the final
+			// length of fields to be equal to FieldsPerRecord.
+			if r.FieldsPerRecord > 0 && fields == nil {
+				fields = make([]string, 0, r.FieldsPerRecord)
+			}
 			fields = append(fields, r.field.String())
 		}
 		if delim == '\n' || err == io.EOF {
diff --git a/src/encoding/csv/reader_test.go b/src/encoding/csv/reader_test.go
index 123df06..be1002d 100644
--- a/src/encoding/csv/reader_test.go
+++ b/src/encoding/csv/reader_test.go
@@ -87,6 +87,15 @@ field"`,
 		},
 	},
 	{
+		Name:               "BlankLineFieldCount",
+		Input:              "a,b,c\n\nd,e,f\n\n",
+		UseFieldsPerRecord: true,
+		Output: [][]string{
+			{"a", "b", "c"},
+			{"d", "e", "f"},
+		},
+	},
+	{
 		Name:             "TrimSpace",
 		Input:            " a,  b,   c\n",
 		TrimLeadingSpace: true,
@@ -282,3 +291,25 @@ func TestRead(t *testing.T) {
 		}
 	}
 }
+
+func BenchmarkRead(b *testing.B) {
+	data := `x,y,z,w
+x,y,z,
+x,y,,
+x,,,
+,,,
+"x","y","z","w"
+"x","y","z",""
+"x","y","",""
+"x","","",""
+"","","",""
+`
+
+	for i := 0; i < b.N; i++ {
+		_, err := NewReader(strings.NewReader(data)).ReadAll()
+
+		if err != nil {
+			b.Fatalf("could not read data: %s", err)
+		}
+	}
+}
diff --git a/src/encoding/csv/writer.go b/src/encoding/csv/writer.go
index 17e7bb7..353d91f 100644
--- a/src/encoding/csv/writer.go
+++ b/src/encoding/csv/writer.go
@@ -114,7 +114,7 @@ func (w *Writer) WriteAll(records [][]string) (err error) {
 	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).
@@ -125,7 +125,7 @@ func (w *Writer) WriteAll(records [][]string) (err error) {
 // CSV with quoted empty strings strictly less useful.
 // Not quoting the empty string also makes this package match the behavior
 // of Microsoft Excel and Google Drive.
-// For Postgres, quote the data termating string `\.`.
+// For Postgres, quote the data terminating string `\.`.
 func (w *Writer) fieldNeedsQuotes(field string) bool {
 	if field == "" {
 		return false
diff --git a/src/encoding/gob/codec_test.go b/src/encoding/gob/codec_test.go
index 56a7298..c2583bf 100644
--- a/src/encoding/gob/codec_test.go
+++ b/src/encoding/gob/codec_test.go
@@ -1473,3 +1473,22 @@ func TestFuzzOneByte(t *testing.T) {
 		}
 	}
 }
+
+// Don't crash, just give error with invalid type id.
+// Issue 9649.
+func TestErrorInvalidTypeId(t *testing.T) {
+	data := []byte{0x01, 0x00, 0x01, 0x00}
+	d := NewDecoder(bytes.NewReader(data))
+	// When running d.Decode(&foo) the first time the decoder stops
+	// after []byte{0x01, 0x00} and reports an errBadType. Running
+	// d.Decode(&foo) again on exactly the same input sequence should
+	// give another errBadType, but instead caused a panic because
+	// decoderMap wasn't cleaned up properly after the first error.
+	for i := 0; i < 2; i++ {
+		var foo struct{}
+		err := d.Decode(&foo)
+		if err != errBadType {
+			t.Fatal("decode: expected %s, got %s", errBadType, err)
+		}
+	}
+}
diff --git a/src/encoding/gob/decode.go b/src/encoding/gob/decode.go
index a5bef93..e913f15 100644
--- a/src/encoding/gob/decode.go
+++ b/src/encoding/gob/decode.go
@@ -182,6 +182,17 @@ func (state *decoderState) decodeInt() int64 {
 	return int64(x >> 1)
 }
 
+// getLength decodes the next uint and makes sure it is a possible
+// size for a data item that follows, which means it must fit in a
+// non-negative int and fit in the buffer.
+func (state *decoderState) getLength() (int, bool) {
+	n := int(state.decodeUint())
+	if n < 0 || state.b.Len() < n || tooBig <= n {
+		return 0, false
+	}
+	return n, true
+}
+
 // decOp is the signature of a decoding operator for a given type.
 type decOp func(i *decInstr, state *decoderState, v reflect.Value)
 
@@ -363,16 +374,9 @@ func decComplex128(i *decInstr, state *decoderState, value reflect.Value) {
 // describing the data.
 // uint8 slices are encoded as an unsigned count followed by the raw bytes.
 func decUint8Slice(i *decInstr, state *decoderState, value reflect.Value) {
-	u := state.decodeUint()
-	n := int(u)
-	if n < 0 || uint64(n) != u {
-		errorf("length of %s exceeds input size (%d bytes)", value.Type(), u)
-	}
-	if n > state.b.Len() {
-		errorf("%s data too long for buffer: %d", value.Type(), n)
-	}
-	if n > tooBig {
-		errorf("byte slice too big: %d", n)
+	n, ok := state.getLength()
+	if !ok {
+		errorf("bad %s slice length: %d", value.Type(), n)
 	}
 	if value.Cap() < n {
 		value.Set(reflect.MakeSlice(value.Type(), n, n))
@@ -388,13 +392,9 @@ func decUint8Slice(i *decInstr, state *decoderState, value reflect.Value) {
 // describing the data.
 // Strings are encoded as an unsigned count followed by the raw bytes.
 func decString(i *decInstr, state *decoderState, value reflect.Value) {
-	u := state.decodeUint()
-	n := int(u)
-	if n < 0 || uint64(n) != u || n > state.b.Len() {
-		errorf("length of %s exceeds input size (%d bytes)", value.Type(), u)
-	}
-	if n > state.b.Len() {
-		errorf("%s data too long for buffer: %d", value.Type(), n)
+	n, ok := state.getLength()
+	if !ok {
+		errorf("bad %s slice length: %d", value.Type(), n)
 	}
 	// Read the data.
 	data := make([]byte, n)
@@ -406,7 +406,11 @@ func decString(i *decInstr, state *decoderState, value reflect.Value) {
 
 // ignoreUint8Array skips over the data for a byte slice value with no destination.
 func ignoreUint8Array(i *decInstr, state *decoderState, value reflect.Value) {
-	b := make([]byte, state.decodeUint())
+	n, ok := state.getLength()
+	if !ok {
+		errorf("slice length too large")
+	}
+	b := make([]byte, n)
 	state.b.Read(b)
 }
 
@@ -571,6 +575,9 @@ func (dec *Decoder) decodeMap(mtyp reflect.Type, state *decoderState, value refl
 func (dec *Decoder) ignoreArrayHelper(state *decoderState, elemOp decOp, length int) {
 	instr := &decInstr{elemOp, 0, nil, errors.New("no error")}
 	for i := 0; i < length; i++ {
+		if state.b.Len() == 0 {
+			errorf("decoding array or slice: length exceeds input size (%d elements)", length)
+		}
 		elemOp(instr, state, noValue)
 	}
 }
@@ -678,7 +685,11 @@ func (dec *Decoder) decodeInterface(ityp reflect.Type, state *decoderState, valu
 // ignoreInterface discards the data for an interface value with no destination.
 func (dec *Decoder) ignoreInterface(state *decoderState) {
 	// Read the name of the concrete type.
-	b := make([]byte, state.decodeUint())
+	n, ok := state.getLength()
+	if !ok {
+		errorf("bad interface encoding: name too large for buffer")
+	}
+	b := make([]byte, n)
 	_, err := state.b.Read(b)
 	if err != nil {
 		error_(err)
@@ -688,14 +699,22 @@ func (dec *Decoder) ignoreInterface(state *decoderState) {
 		error_(dec.err)
 	}
 	// At this point, the decoder buffer contains a delimited value. Just toss it.
-	state.b.Drop(int(state.decodeUint()))
+	n, ok = state.getLength()
+	if !ok {
+		errorf("bad interface encoding: data length too large for buffer")
+	}
+	state.b.Drop(n)
 }
 
 // decodeGobDecoder decodes something implementing the GobDecoder interface.
 // The data is encoded as a byte slice.
 func (dec *Decoder) decodeGobDecoder(ut *userTypeInfo, state *decoderState, value reflect.Value) {
 	// Read the bytes for the value.
-	b := make([]byte, state.decodeUint())
+	n, ok := state.getLength()
+	if !ok {
+		errorf("GobDecoder: length too large for buffer")
+	}
+	b := make([]byte, n)
 	_, err := state.b.Read(b)
 	if err != nil {
 		error_(err)
@@ -717,7 +736,11 @@ func (dec *Decoder) decodeGobDecoder(ut *userTypeInfo, state *decoderState, valu
 // ignoreGobDecoder discards the data for a GobDecoder value with no destination.
 func (dec *Decoder) ignoreGobDecoder(state *decoderState) {
 	// Read the bytes for the value.
-	b := make([]byte, state.decodeUint())
+	n, ok := state.getLength()
+	if !ok {
+		errorf("GobDecoder: length too large for buffer")
+	}
+	b := make([]byte, n)
 	_, err := state.b.Read(b)
 	if err != nil {
 		error_(err)
@@ -840,16 +863,22 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string, inProg
 }
 
 // decIgnoreOpFor returns the decoding op for a field that has no destination.
-func (dec *Decoder) decIgnoreOpFor(wireId typeId) decOp {
+func (dec *Decoder) decIgnoreOpFor(wireId typeId, inProgress map[typeId]*decOp) *decOp {
+	// If this type is already in progress, it's a recursive type (e.g. map[string]*T).
+	// Return the pointer to the op we're already building.
+	if opPtr := inProgress[wireId]; opPtr != nil {
+		return opPtr
+	}
 	op, ok := decIgnoreOpMap[wireId]
 	if !ok {
+		inProgress[wireId] = &op
 		if wireId == tInterface {
 			// Special case because it's a method: the ignored item might
 			// define types and we need to record their state in the decoder.
 			op = func(i *decInstr, state *decoderState, value reflect.Value) {
 				state.dec.ignoreInterface(state)
 			}
-			return op
+			return &op
 		}
 		// Special cases
 		wire := dec.wireType[wireId]
@@ -858,25 +887,25 @@ func (dec *Decoder) decIgnoreOpFor(wireId typeId) decOp {
 			errorf("bad data: undefined type %s", wireId.string())
 		case wire.ArrayT != nil:
 			elemId := wire.ArrayT.Elem
-			elemOp := dec.decIgnoreOpFor(elemId)
+			elemOp := dec.decIgnoreOpFor(elemId, inProgress)
 			op = func(i *decInstr, state *decoderState, value reflect.Value) {
-				state.dec.ignoreArray(state, elemOp, wire.ArrayT.Len)
+				state.dec.ignoreArray(state, *elemOp, wire.ArrayT.Len)
 			}
 
 		case wire.MapT != nil:
 			keyId := dec.wireType[wireId].MapT.Key
 			elemId := dec.wireType[wireId].MapT.Elem
-			keyOp := dec.decIgnoreOpFor(keyId)
-			elemOp := dec.decIgnoreOpFor(elemId)
+			keyOp := dec.decIgnoreOpFor(keyId, inProgress)
+			elemOp := dec.decIgnoreOpFor(elemId, inProgress)
 			op = func(i *decInstr, state *decoderState, value reflect.Value) {
-				state.dec.ignoreMap(state, keyOp, elemOp)
+				state.dec.ignoreMap(state, *keyOp, *elemOp)
 			}
 
 		case wire.SliceT != nil:
 			elemId := wire.SliceT.Elem
-			elemOp := dec.decIgnoreOpFor(elemId)
+			elemOp := dec.decIgnoreOpFor(elemId, inProgress)
 			op = func(i *decInstr, state *decoderState, value reflect.Value) {
-				state.dec.ignoreSlice(state, elemOp)
+				state.dec.ignoreSlice(state, *elemOp)
 			}
 
 		case wire.StructT != nil:
@@ -899,7 +928,7 @@ func (dec *Decoder) decIgnoreOpFor(wireId typeId) decOp {
 	if op == nil {
 		errorf("bad data: ignore can't handle type %s", wireId.string())
 	}
-	return op
+	return &op
 }
 
 // gobDecodeOpFor returns the op for a type that is known to implement
@@ -1033,9 +1062,9 @@ func (dec *Decoder) compileSingle(remoteId typeId, ut *userTypeInfo) (engine *de
 func (dec *Decoder) compileIgnoreSingle(remoteId typeId) (engine *decEngine, err error) {
 	engine = new(decEngine)
 	engine.instr = make([]decInstr, 1) // one item
-	op := dec.decIgnoreOpFor(remoteId)
+	op := dec.decIgnoreOpFor(remoteId, make(map[typeId]*decOp))
 	ovfl := overflow(dec.typeString(remoteId))
-	engine.instr[0] = decInstr{op, 0, nil, ovfl}
+	engine.instr[0] = decInstr{*op, 0, nil, ovfl}
 	engine.numInstr = 1
 	return
 }
@@ -1043,6 +1072,7 @@ func (dec *Decoder) compileIgnoreSingle(remoteId typeId) (engine *decEngine, err
 // compileDec compiles the decoder engine for a value.  If the value is not a struct,
 // it calls out to compileSingle.
 func (dec *Decoder) compileDec(remoteId typeId, ut *userTypeInfo) (engine *decEngine, err error) {
+	defer catchError(&err)
 	rt := ut.base
 	srt := rt
 	if srt.Kind() != reflect.Struct || ut.externalDec != 0 {
@@ -1077,8 +1107,8 @@ func (dec *Decoder) compileDec(remoteId typeId, ut *userTypeInfo) (engine *decEn
 		localField, present := srt.FieldByName(wireField.Name)
 		// TODO(r): anonymous names
 		if !present || !isExported(wireField.Name) {
-			op := dec.decIgnoreOpFor(wireField.Id)
-			engine.instr[fieldnum] = decInstr{op, fieldnum, nil, ovfl}
+			op := dec.decIgnoreOpFor(wireField.Id, make(map[typeId]*decOp))
+			engine.instr[fieldnum] = decInstr{*op, fieldnum, nil, ovfl}
 			continue
 		}
 		if !dec.compatibleType(localField.Type, wireField.Id, make(map[reflect.Type]typeId)) {
@@ -1116,7 +1146,7 @@ type emptyStruct struct{}
 
 var emptyStructType = reflect.TypeOf(emptyStruct{})
 
-// getDecEnginePtr returns the engine for the specified type when the value is to be discarded.
+// getIgnoreEnginePtr returns the engine for the specified type when the value is to be discarded.
 func (dec *Decoder) getIgnoreEnginePtr(wireId typeId) (enginePtr **decEngine, err error) {
 	var ok bool
 	if enginePtr, ok = dec.ignorerCache[wireId]; !ok {
@@ -1155,8 +1185,9 @@ func (dec *Decoder) decodeValue(wireId typeId, value reflect.Value) {
 	value = decAlloc(value)
 	engine := *enginePtr
 	if st := base; st.Kind() == reflect.Struct && ut.externalDec == 0 {
+		wt := dec.wireType[wireId]
 		if engine.numInstr == 0 && st.NumField() > 0 &&
-			dec.wireType[wireId] != nil && len(dec.wireType[wireId].StructT.Field) > 0 {
+			wt != nil && len(wt.StructT.Field) > 0 {
 			name := base.Name()
 			errorf("type mismatch: no fields matched compiling decoder for %s", name)
 		}
diff --git a/src/encoding/gob/doc.go b/src/encoding/gob/doc.go
index d0acaba..4d3d007 100644
--- a/src/encoding/gob/doc.go
+++ b/src/encoding/gob/doc.go
@@ -6,7 +6,7 @@
 Package gob manages streams of gobs - binary values exchanged between an
 Encoder (transmitter) and a Decoder (receiver).  A typical use is transporting
 arguments and results of remote procedure calls (RPCs) such as those provided by
-package "rpc".
+package "net/rpc".
 
 The implementation compiles a custom codec for each data type in the stream and
 is most efficient when a single Encoder is used to transmit a stream of values,
@@ -83,7 +83,7 @@ allocated. Regardless, the length of the resulting slice reports the number of
 elements decoded.
 
 Functions and channels will not be sent in a gob. Attempting to encode such a value
-at top the level will fail. A struct field of chan or func type is treated exactly
+at the top level will fail. A struct field of chan or func type is treated exactly
 like an unexported field and is ignored.
 
 Gob can encode a value of any type implementing the GobEncoder or
@@ -111,11 +111,11 @@ A signed integer, i, is encoded within an unsigned integer, u.  Within u, bits 1
 upward contain the value; bit 0 says whether they should be complemented upon
 receipt.  The encode algorithm looks like this:
 
-	uint u;
+	var u uint
 	if i < 0 {
-		u = (^i << 1) | 1	// complement i, bit 0 is 1
+		u = (^uint(i) << 1) | 1 // complement i, bit 0 is 1
 	} else {
-		u = (i << 1)	// do not complement i, bit 0 is 0
+		u = (uint(i) << 1) // do not complement i, bit 0 is 0
 	}
 	encodeUnsigned(u)
 
@@ -137,9 +137,9 @@ All other slices and arrays are sent as an unsigned count followed by that many
 elements using the standard gob encoding for their type, recursively.
 
 Maps are sent as an unsigned count followed by that many key, element
-pairs. Empty but non-nil maps are sent, so if the sender has allocated
-a map, the receiver will allocate a map even if no elements are
-transmitted.
+pairs. Empty but non-nil maps are sent, so if the receiver has not allocated
+one already, one will always be allocated on receipt unless the transmitted map
+is nil and not at the top level.
 
 Structs are sent as a sequence of (field number, field value) pairs.  The field
 value is sent using the standard gob encoding for its type, recursively.  If a
@@ -246,7 +246,7 @@ where * signifies zero or more repetitions and the type id of a value must
 be predefined or be defined before the value in the stream.
 
 See "Gobs of data" for a design discussion of the gob wire format:
-http://golang.org/doc/articles/gobs_of_data.html
+https://blog.golang.org/gobs-of-data
 */
 package gob
 
diff --git a/src/encoding/gob/encoder.go b/src/encoding/gob/encoder.go
index a340e47..62d0f42 100644
--- a/src/encoding/gob/encoder.go
+++ b/src/encoding/gob/encoder.go
@@ -5,6 +5,7 @@
 package gob
 
 import (
+	"errors"
 	"io"
 	"reflect"
 	"sync"
@@ -65,6 +66,11 @@ func (enc *Encoder) writeMessage(w io.Writer, b *encBuffer) {
 	// it by hand.
 	message := b.Bytes()
 	messageLen := len(message) - maxLength
+	// Length cannot be bigger than the decoder can handle.
+	if messageLen >= tooBig {
+		enc.setError(errors.New("gob: encoder: message too big"))
+		return
+	}
 	// Encode the length.
 	enc.countState.b.Reset()
 	enc.countState.encodeUint(uint64(messageLen))
diff --git a/src/encoding/gob/encoder_test.go b/src/encoding/gob/encoder_test.go
index 0ea4c0e..dc65734 100644
--- a/src/encoding/gob/encoder_test.go
+++ b/src/encoding/gob/encoder_test.go
@@ -6,8 +6,8 @@ package gob
 
 import (
 	"bytes"
+	"encoding/hex"
 	"fmt"
-	"io"
 	"reflect"
 	"strings"
 	"testing"
@@ -187,24 +187,6 @@ func TestWrongTypeDecoder(t *testing.T) {
 	badTypeCheck(new(ET4), true, "different type of field", t)
 }
 
-func corruptDataCheck(s string, err error, t *testing.T) {
-	b := bytes.NewBufferString(s)
-	dec := NewDecoder(b)
-	err1 := dec.Decode(new(ET2))
-	if err1 != err {
-		t.Errorf("from %q expected error %s; got %s", s, err, err1)
-	}
-}
-
-// Check that we survive bad data.
-func TestBadData(t *testing.T) {
-	corruptDataCheck("", io.EOF, t)
-	corruptDataCheck("\x7Fhi", io.ErrUnexpectedEOF, t)
-	corruptDataCheck("\x03now is the time for all good men", errBadType, t)
-	// issue 6323.
-	corruptDataCheck("\x04\x24foo", errRange, t)
-}
-
 // Types not supported at top level by the Encoder.
 var unsupportedValues = []interface{}{
 	make(chan int),
@@ -545,6 +527,30 @@ func TestDecodeIntoNothing(t *testing.T) {
 	}
 }
 
+func TestIgnoreRecursiveType(t *testing.T) {
+	// It's hard to build a self-contained test for this because
+	// we can't build compatible types in one package with
+	// different items so something is ignored. Here is
+	// some data that represents, according to debug.go:
+	// type definition {
+	//	slice "recursiveSlice" id=106
+	//		elem id=106
+	// }
+	data := []byte{
+		0x1d, 0xff, 0xd3, 0x02, 0x01, 0x01, 0x0e, 0x72,
+		0x65, 0x63, 0x75, 0x72, 0x73, 0x69, 0x76, 0x65,
+		0x53, 0x6c, 0x69, 0x63, 0x65, 0x01, 0xff, 0xd4,
+		0x00, 0x01, 0xff, 0xd4, 0x00, 0x00, 0x07, 0xff,
+		0xd4, 0x00, 0x02, 0x01, 0x00, 0x00,
+	}
+	dec := NewDecoder(bytes.NewReader(data))
+	// Issue 10415: This caused infinite recursion.
+	err := dec.Decode(nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+}
+
 // Another bug from golang-nuts, involving nested interfaces.
 type Bug0Outer struct {
 	Bug0Field interface{}
@@ -951,6 +957,64 @@ func TestErrorForHugeSlice(t *testing.T) {
 		t.Fatal("decode: no error")
 	}
 	if !strings.Contains(err.Error(), "slice too big") {
-		t.Fatal("decode: expected slice too big error, got %s", err.Error())
+		t.Fatalf("decode: expected slice too big error, got %s", err.Error())
+	}
+}
+
+type badDataTest struct {
+	input string      // The input encoded as a hex string.
+	error string      // A substring of the error that should result.
+	data  interface{} // What to decode into.
+}
+
+var badDataTests = []badDataTest{
+	{"", "EOF", nil},
+	{"7F6869", "unexpected EOF", nil},
+	{"036e6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e", "unknown type id", new(ET2)},
+	{"0424666f6f", "field numbers out of bounds", new(ET2)}, // Issue 6323.
+	{"05100028557b02027f8302", "interface encoding", nil},   // Issue 10270.
+	// Issue 10273.
+	{"130a00fb5dad0bf8ff020263e70002fa28020202a89859", "slice length too large", nil},
+	{"0f1000fb285d003316020735ff023a65c5", "interface encoding", nil},
+	{"03fffb0616fffc00f902ff02ff03bf005d02885802a311a8120228022c028ee7", "GobDecoder", nil},
+	// Issue 10491.
+	{"10fe010f020102fe01100001fe010e000016fe010d030102fe010e00010101015801fe01100000000bfe011000f85555555555555555", "length exceeds input size", nil},
+}
+
+// TestBadData tests that various problems caused by malformed input
+// are caught as errors and do not cause panics.
+func TestBadData(t *testing.T) {
+	for i, test := range badDataTests {
+		data, err := hex.DecodeString(test.input)
+		if err != nil {
+			t.Fatalf("#%d: hex error: %s", i, err)
+		}
+		d := NewDecoder(bytes.NewReader(data))
+		err = d.Decode(test.data)
+		if err == nil {
+			t.Errorf("decode: no error")
+			continue
+		}
+		if !strings.Contains(err.Error(), test.error) {
+			t.Errorf("#%d: decode: expected %q error, got %s", i, test.error, err.Error())
+		}
+	}
+}
+
+// TestHugeWriteFails tests that enormous messages trigger an error.
+func TestHugeWriteFails(t *testing.T) {
+	if testing.Short() {
+		// Requires allocating a monster, so don't do this from all.bash.
+		t.Skip("skipping huge allocation in short mode")
+	}
+	huge := make([]byte, tooBig)
+	huge[0] = 7 // Make sure it's not all zeros.
+	buf := new(bytes.Buffer)
+	err := NewEncoder(buf).Encode(huge)
+	if err == nil {
+		t.Fatalf("expected error for huge slice")
+	}
+	if !strings.Contains(err.Error(), "message too big") {
+		t.Fatalf("expected 'too big' error; got %s\n", err.Error())
 	}
 }
diff --git a/src/encoding/json/bench_test.go b/src/encoding/json/bench_test.go
index 29dbc26..ed89d11 100644
--- a/src/encoding/json/bench_test.go
+++ b/src/encoding/json/bench_test.go
@@ -15,6 +15,7 @@ import (
 	"compress/gzip"
 	"io/ioutil"
 	"os"
+	"strings"
 	"testing"
 )
 
@@ -126,6 +127,28 @@ func BenchmarkCodeDecoder(b *testing.B) {
 	b.SetBytes(int64(len(codeJSON)))
 }
 
+func BenchmarkDecoderStream(b *testing.B) {
+	b.StopTimer()
+	var buf bytes.Buffer
+	dec := NewDecoder(&buf)
+	buf.WriteString(`"` + strings.Repeat("x", 1000000) + `"` + "\n\n\n")
+	var x interface{}
+	if err := dec.Decode(&x); err != nil {
+		b.Fatal("Decode:", err)
+	}
+	ones := strings.Repeat(" 1\n", 300000) + "\n\n\n"
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		if i%300000 == 0 {
+			buf.WriteString(ones)
+		}
+		x = nil
+		if err := dec.Decode(&x); err != nil || x != 1.0 {
+			b.Fatalf("Decode: %v after %d", err, i)
+		}
+	}
+}
+
 func BenchmarkCodeUnmarshal(b *testing.B) {
 	if codeJSON == nil {
 		b.StopTimer()
@@ -187,3 +210,14 @@ func BenchmarkUnmarshalInt64(b *testing.B) {
 		}
 	}
 }
+
+func BenchmarkIssue10335(b *testing.B) {
+	b.ReportAllocs()
+	var s struct{}
+	j := []byte(`{"a":{ }}`)
+	for n := 0; n < b.N; n++ {
+		if err := Unmarshal(j, &s); err != nil {
+			b.Fatal(err)
+		}
+	}
+}
diff --git a/src/encoding/json/decode.go b/src/encoding/json/decode.go
index 705bc2e..530e852 100644
--- a/src/encoding/json/decode.go
+++ b/src/encoding/json/decode.go
@@ -48,6 +48,13 @@ import (
 //	map[string]interface{}, for JSON objects
 //	nil for JSON null
 //
+// To unmarshal a JSON array into a slice, Unmarshal resets the slice to nil
+// and then appends each element to the slice.
+//
+// To unmarshal a JSON object into a map, Unmarshal replaces the map
+// with an empty map and then adds key-value pairs from the object to
+// the map.
+//
 // If a JSON value is not appropriate for a given target type,
 // or if a JSON number overflows the target type, Unmarshal
 // skips that field and completes the unmarshalling as best it can.
@@ -90,8 +97,9 @@ type Unmarshaler interface {
 // An UnmarshalTypeError describes a JSON value that was
 // not appropriate for a value of a specific Go type.
 type UnmarshalTypeError struct {
-	Value string       // description of JSON value - "bool", "array", "number -5"
-	Type  reflect.Type // type of Go value it could not be assigned to
+	Value  string       // description of JSON value - "bool", "array", "number -5"
+	Type   reflect.Type // type of Go value it could not be assigned to
+	Offset int64        // error occurred after reading Offset bytes
 }
 
 func (e *UnmarshalTypeError) Error() string {
@@ -377,7 +385,7 @@ func (d *decodeState) array(v reflect.Value) {
 		return
 	}
 	if ut != nil {
-		d.saveError(&UnmarshalTypeError{"array", v.Type()})
+		d.saveError(&UnmarshalTypeError{"array", v.Type(), int64(d.off)})
 		d.off--
 		d.next()
 		return
@@ -396,7 +404,7 @@ func (d *decodeState) array(v reflect.Value) {
 		// Otherwise it's invalid.
 		fallthrough
 	default:
-		d.saveError(&UnmarshalTypeError{"array", v.Type()})
+		d.saveError(&UnmarshalTypeError{"array", v.Type(), int64(d.off)})
 		d.off--
 		d.next()
 		return
@@ -485,7 +493,7 @@ func (d *decodeState) object(v reflect.Value) {
 		return
 	}
 	if ut != nil {
-		d.saveError(&UnmarshalTypeError{"object", v.Type()})
+		d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)})
 		d.off--
 		d.next() // skip over { } in input
 		return
@@ -504,7 +512,7 @@ func (d *decodeState) object(v reflect.Value) {
 		// map must have string kind
 		t := v.Type()
 		if t.Key().Kind() != reflect.String {
-			d.saveError(&UnmarshalTypeError{"object", v.Type()})
+			d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)})
 			d.off--
 			d.next() // skip over { } in input
 			return
@@ -515,7 +523,7 @@ func (d *decodeState) object(v reflect.Value) {
 	case reflect.Struct:
 
 	default:
-		d.saveError(&UnmarshalTypeError{"object", v.Type()})
+		d.saveError(&UnmarshalTypeError{"object", v.Type(), int64(d.off)})
 		d.off--
 		d.next() // skip over { } in input
 		return
@@ -599,7 +607,7 @@ func (d *decodeState) object(v reflect.Value) {
 			case string:
 				d.literalStore([]byte(qv), subv, true)
 			default:
-				d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal unquoted value into %v", item, v.Type()))
+				d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal unquoted value into %v", subv.Type()))
 			}
 		} else {
 			d.value(subv)
@@ -646,7 +654,7 @@ func (d *decodeState) convertNumber(s string) (interface{}, error) {
 	}
 	f, err := strconv.ParseFloat(s, 64)
 	if err != nil {
-		return nil, &UnmarshalTypeError{"number " + s, reflect.TypeOf(0.0)}
+		return nil, &UnmarshalTypeError{"number " + s, reflect.TypeOf(0.0), int64(d.off)}
 	}
 	return f, nil
 }
@@ -679,8 +687,9 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
 			if fromQuoted {
 				d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
 			} else {
-				d.saveError(&UnmarshalTypeError{"string", v.Type()})
+				d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)})
 			}
+			return
 		}
 		s, ok := unquoteBytes(item)
 		if !ok {
@@ -713,7 +722,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
 			if fromQuoted {
 				d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
 			} else {
-				d.saveError(&UnmarshalTypeError{"bool", v.Type()})
+				d.saveError(&UnmarshalTypeError{"bool", v.Type(), int64(d.off)})
 			}
 		case reflect.Bool:
 			v.SetBool(value)
@@ -721,7 +730,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
 			if v.NumMethod() == 0 {
 				v.Set(reflect.ValueOf(value))
 			} else {
-				d.saveError(&UnmarshalTypeError{"bool", v.Type()})
+				d.saveError(&UnmarshalTypeError{"bool", v.Type(), int64(d.off)})
 			}
 		}
 
@@ -736,10 +745,10 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
 		}
 		switch v.Kind() {
 		default:
-			d.saveError(&UnmarshalTypeError{"string", v.Type()})
+			d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)})
 		case reflect.Slice:
-			if v.Type() != byteSliceType {
-				d.saveError(&UnmarshalTypeError{"string", v.Type()})
+			if v.Type().Elem().Kind() != reflect.Uint8 {
+				d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)})
 				break
 			}
 			b := make([]byte, base64.StdEncoding.DecodedLen(len(s)))
@@ -755,7 +764,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
 			if v.NumMethod() == 0 {
 				v.Set(reflect.ValueOf(string(s)))
 			} else {
-				d.saveError(&UnmarshalTypeError{"string", v.Type()})
+				d.saveError(&UnmarshalTypeError{"string", v.Type(), int64(d.off)})
 			}
 		}
 
@@ -777,7 +786,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
 			if fromQuoted {
 				d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
 			} else {
-				d.error(&UnmarshalTypeError{"number", v.Type()})
+				d.error(&UnmarshalTypeError{"number", v.Type(), int64(d.off)})
 			}
 		case reflect.Interface:
 			n, err := d.convertNumber(s)
@@ -786,7 +795,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
 				break
 			}
 			if v.NumMethod() != 0 {
-				d.saveError(&UnmarshalTypeError{"number", v.Type()})
+				d.saveError(&UnmarshalTypeError{"number", v.Type(), int64(d.off)})
 				break
 			}
 			v.Set(reflect.ValueOf(n))
@@ -794,7 +803,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
 		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 			n, err := strconv.ParseInt(s, 10, 64)
 			if err != nil || v.OverflowInt(n) {
-				d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
+				d.saveError(&UnmarshalTypeError{"number " + s, v.Type(), int64(d.off)})
 				break
 			}
 			v.SetInt(n)
@@ -802,7 +811,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
 		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
 			n, err := strconv.ParseUint(s, 10, 64)
 			if err != nil || v.OverflowUint(n) {
-				d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
+				d.saveError(&UnmarshalTypeError{"number " + s, v.Type(), int64(d.off)})
 				break
 			}
 			v.SetUint(n)
@@ -810,7 +819,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
 		case reflect.Float32, reflect.Float64:
 			n, err := strconv.ParseFloat(s, v.Type().Bits())
 			if err != nil || v.OverflowFloat(n) {
-				d.saveError(&UnmarshalTypeError{"number " + s, v.Type()})
+				d.saveError(&UnmarshalTypeError{"number " + s, v.Type(), int64(d.off)})
 				break
 			}
 			v.SetFloat(n)
diff --git a/src/encoding/json/decode_test.go b/src/encoding/json/decode_test.go
index 7235969..8aa158f 100644
--- a/src/encoding/json/decode_test.go
+++ b/src/encoding/json/decode_test.go
@@ -9,6 +9,7 @@ import (
 	"encoding"
 	"fmt"
 	"image"
+	"net"
 	"reflect"
 	"strings"
 	"testing"
@@ -216,6 +217,9 @@ type XYZ struct {
 	Z interface{}
 }
 
+func sliceAddr(x []int) *[]int                 { return &x }
+func mapAddr(x map[string]int) *map[string]int { return &x }
+
 var unmarshalTests = []unmarshalTest{
 	// basic types
 	{in: `true`, ptr: new(bool), out: true},
@@ -231,7 +235,7 @@ var unmarshalTests = []unmarshalTest{
 	{in: `"g-clef: \uD834\uDD1E"`, ptr: new(string), out: "g-clef: \U0001D11E"},
 	{in: `"invalid: \uD834x\uDD1E"`, ptr: new(string), out: "invalid: \uFFFDx\uFFFD"},
 	{in: "null", ptr: new(interface{}), out: nil},
-	{in: `{"X": [1,2,3], "Y": 4}`, ptr: new(T), out: T{Y: 4}, err: &UnmarshalTypeError{"array", reflect.TypeOf("")}},
+	{in: `{"X": [1,2,3], "Y": 4}`, ptr: new(T), out: T{Y: 4}, err: &UnmarshalTypeError{"array", reflect.TypeOf(""), 7}},
 	{in: `{"x": 1}`, ptr: new(tx), out: tx{}},
 	{in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: float64(1), F2: int32(2), F3: Number("3")}},
 	{in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: Number("1"), F2: int32(2), F3: Number("3")}, useNumber: true},
@@ -302,6 +306,12 @@ var unmarshalTests = []unmarshalTest{
 	{in: `["X"]`, ptr: &umslicepT, out: &umsliceT},
 	{in: `{"M":"X"}`, ptr: &umstructT, out: umstructT},
 
+	// Overwriting of data.
+	// This is different from package xml, but it's what we've always done.
+	// Now documented and tested.
+	{in: `[2]`, ptr: sliceAddr([]int{1}), out: []int{2}},
+	{in: `{"key": 2}`, ptr: mapAddr(map[string]int{"old": 0, "key": 1}), out: map[string]int{"key": 2}},
+
 	{
 		in: `{
 			"Level0": 1,
@@ -411,7 +421,7 @@ var unmarshalTests = []unmarshalTest{
 	{
 		in:  `{"2009-11-10T23:00:00Z": "hello world"}`,
 		ptr: &map[time.Time]string{},
-		err: &UnmarshalTypeError{"object", reflect.TypeOf(map[time.Time]string{})},
+		err: &UnmarshalTypeError{"object", reflect.TypeOf(map[time.Time]string{}), 1},
 	},
 }
 
@@ -688,6 +698,7 @@ var wrongStringTests = []wrongStringTest{
 	{`{"result":"x"}`, `json: invalid use of ,string struct tag, trying to unmarshal "x" into string`},
 	{`{"result":"foo"}`, `json: invalid use of ,string struct tag, trying to unmarshal "foo" into string`},
 	{`{"result":"123"}`, `json: invalid use of ,string struct tag, trying to unmarshal "123" into string`},
+	{`{"result":123}`, `json: invalid use of ,string struct tag, trying to unmarshal unquoted value into string`},
 }
 
 // If people misuse the ,string modifier, the error message should be
@@ -1085,7 +1096,7 @@ func TestNullString(t *testing.T) {
 	*s.C = 2
 	err := Unmarshal(data, &s)
 	if err != nil {
-		t.Fatalf("Unmarshal: %v")
+		t.Fatalf("Unmarshal: %v", err)
 	}
 	if s.B != 1 || s.C != nil {
 		t.Fatalf("after Unmarshal, s.B=%d, s.C=%p, want 1, nil", s.B, s.C)
@@ -1206,7 +1217,28 @@ func TestStringKind(t *testing.T) {
 	if !reflect.DeepEqual(m1, m2) {
 		t.Error("Items should be equal after encoding and then decoding")
 	}
+}
+
+// Custom types with []byte as underlying type could not be marshalled
+// and then unmarshalled.
+// Issue 8962.
+func TestByteKind(t *testing.T) {
+	type byteKind []byte
 
+	a := byteKind("hello")
+
+	data, err := Marshal(a)
+	if err != nil {
+		t.Error(err)
+	}
+	var b byteKind
+	err = Unmarshal(data, &b)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if !reflect.DeepEqual(a, b) {
+		t.Errorf("expected %v == %v", a, b)
+	}
 }
 
 var decodeTypeErrorTests = []struct {
@@ -1371,3 +1403,51 @@ func TestInvalidUnmarshal(t *testing.T) {
 		}
 	}
 }
+
+var invalidUnmarshalTextTests = []struct {
+	v    interface{}
+	want string
+}{
+	{nil, "json: Unmarshal(nil)"},
+	{struct{}{}, "json: Unmarshal(non-pointer struct {})"},
+	{(*int)(nil), "json: Unmarshal(nil *int)"},
+	{new(net.IP), "json: cannot unmarshal string into Go value of type *net.IP"},
+}
+
+func TestInvalidUnmarshalText(t *testing.T) {
+	buf := []byte(`123`)
+	for _, tt := range invalidUnmarshalTextTests {
+		err := Unmarshal(buf, tt.v)
+		if err == nil {
+			t.Errorf("Unmarshal expecting error, got nil")
+			continue
+		}
+		if got := err.Error(); got != tt.want {
+			t.Errorf("Unmarshal = %q; want %q", got, tt.want)
+		}
+	}
+}
+
+// Test that string option is ignored for invalid types.
+// Issue 9812.
+func TestInvalidStringOption(t *testing.T) {
+	num := 0
+	item := struct {
+		T time.Time         `json:",string"`
+		M map[string]string `json:",string"`
+		S []string          `json:",string"`
+		A [1]string         `json:",string"`
+		I interface{}       `json:",string"`
+		P *int              `json:",string"`
+	}{M: make(map[string]string), S: make([]string, 0), I: num, P: &num}
+
+	data, err := Marshal(item)
+	if err != nil {
+		t.Fatalf("Marshal: %v", err)
+	}
+
+	err = Unmarshal(data, &item)
+	if err != nil {
+		t.Fatalf("Unmarshal: %v", err)
+	}
+}
diff --git a/src/encoding/json/encode.go b/src/encoding/json/encode.go
index fca2a09..90782de 100644
--- a/src/encoding/json/encode.go
+++ b/src/encoding/json/encode.go
@@ -7,7 +7,7 @@
 // in the documentation for the Marshal and Unmarshal functions.
 //
 // See "JSON and Go" for an introduction to this package:
-// http://golang.org/doc/articles/json_and_go.html
+// https://golang.org/doc/articles/json_and_go.html
 package json
 
 import (
@@ -79,8 +79,8 @@ import (
 //
 // The "string" option signals that a field is stored as JSON inside a
 // JSON-encoded string. It applies only to fields of string, floating point,
-// or integer types. This extra level of encoding is sometimes used when
-// communicating with JavaScript programs:
+// integer, or boolean types. This extra level of encoding is sometimes used
+// when communicating with JavaScript programs:
 //
 //    Int64String int64 `json:",string"`
 //
@@ -113,8 +113,8 @@ import (
 // a JSON tag of "-".
 //
 // Map values encode as JSON objects.
-// The map's key type must be string; the object keys are used directly
-// as map keys.
+// The map's key type must be string; the map keys are used as JSON object
+// keys, subject to the UTF-8 coercion described for string values above.
 //
 // Pointer values encode as the value pointed to.
 // A nil pointer encodes as the null JSON object.
@@ -275,8 +275,6 @@ func (e *encodeState) error(err error) {
 	panic(err)
 }
 
-var byteSliceType = reflect.TypeOf([]byte(nil))
-
 func isEmptyValue(v reflect.Value) bool {
 	switch v.Kind() {
 	case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
@@ -1045,6 +1043,19 @@ func typeFields(t reflect.Type) []field {
 					ft = ft.Elem()
 				}
 
+				// Only strings, floats, integers, and booleans can be quoted.
+				quoted := false
+				if opts.Contains("string") {
+					switch ft.Kind() {
+					case reflect.Bool,
+						reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
+						reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
+						reflect.Float32, reflect.Float64,
+						reflect.String:
+						quoted = true
+					}
+				}
+
 				// Record found field and index sequence.
 				if name != "" || !sf.Anonymous || ft.Kind() != reflect.Struct {
 					tagged := name != ""
@@ -1057,7 +1068,7 @@ func typeFields(t reflect.Type) []field {
 						index:     index,
 						typ:       ft,
 						omitEmpty: opts.Contains("omitempty"),
-						quoted:    opts.Contains("string"),
+						quoted:    quoted,
 					}))
 					if count[f.typ] > 1 {
 						// If there were multiple instances, add a second,
diff --git a/src/encoding/json/example_test.go b/src/encoding/json/example_test.go
index ca4e5ae..da08e10 100644
--- a/src/encoding/json/example_test.go
+++ b/src/encoding/json/example_test.go
@@ -83,6 +83,97 @@ func ExampleDecoder() {
 	// Ed: Go fmt yourself!
 }
 
+// This example uses a Decoder to decode a stream of distinct JSON values.
+func ExampleDecoder_Token() {
+	const jsonStream = `
+		{"Message": "Hello", "Array": [1, 2, 3], "Null": null, "Number": 1.234}
+	`
+	dec := json.NewDecoder(strings.NewReader(jsonStream))
+	for {
+		t, err := dec.Token()
+		if err == io.EOF {
+			break
+		}
+		if err != nil {
+			log.Fatal(err)
+		}
+		fmt.Printf("%T: %v", t, t)
+		if dec.More() {
+			fmt.Printf(" (more)")
+		}
+		fmt.Printf("\n")
+	}
+	// Output:
+	// json.Delim: { (more)
+	// string: Message (more)
+	// string: Hello (more)
+	// string: Array (more)
+	// json.Delim: [ (more)
+	// float64: 1 (more)
+	// float64: 2 (more)
+	// float64: 3
+	// json.Delim: ] (more)
+	// string: Null (more)
+	// <nil>: <nil> (more)
+	// string: Number (more)
+	// float64: 1.234
+	// json.Delim: }
+}
+
+// This example uses a Decoder to decode a streaming array of JSON objects.
+func ExampleDecoder_Decode_stream() {
+	const jsonStream = `
+		[
+			{"Name": "Ed", "Text": "Knock knock."},
+			{"Name": "Sam", "Text": "Who's there?"},
+			{"Name": "Ed", "Text": "Go fmt."},
+			{"Name": "Sam", "Text": "Go fmt who?"},
+			{"Name": "Ed", "Text": "Go fmt yourself!"}
+		]
+	`
+	type Message struct {
+		Name, Text string
+	}
+	dec := json.NewDecoder(strings.NewReader(jsonStream))
+
+	// read open bracket
+	t, err := dec.Token()
+	if err != nil {
+		log.Fatal(err)
+	}
+	fmt.Printf("%T: %v\n", t, t)
+
+	var m Message
+	// while the array contains values
+	for dec.More() {
+
+		// decode an array value (Message)
+		err := dec.Decode(&m)
+		if err != nil {
+			log.Fatal(err)
+		}
+
+		fmt.Printf("%v: %v\n", m.Name, m.Text)
+	}
+
+	// read closing bracket
+	t, err = dec.Token()
+	if err != nil {
+		log.Fatal(err)
+	}
+	fmt.Printf("%T: %v\n", t, t)
+
+	// Output:
+	// json.Delim: [
+	// Ed: Knock knock.
+	// Sam: Who's there?
+	// Ed: Go fmt.
+	// Sam: Go fmt who?
+	// Ed: Go fmt yourself!
+	// json.Delim: ]
+
+}
+
 // This example uses RawMessage to delay parsing part of a JSON message.
 func ExampleRawMessage() {
 	type Color struct {
diff --git a/src/encoding/json/fold.go b/src/encoding/json/fold.go
index d6f77c9..9e17012 100644
--- a/src/encoding/json/fold.go
+++ b/src/encoding/json/fold.go
@@ -26,7 +26,7 @@ const (
 // The letters S and K are special because they map to 3 runes, not just 2:
 //  * S maps to s and to U+017F 'ſ' Latin small letter long s
 //  * k maps to K and to U+212A 'K' Kelvin sign
-// See http://play.golang.org/p/tTxjOc0OGo
+// See https://play.golang.org/p/tTxjOc0OGo
 //
 // The returned function is specialized for matching against s and
 // should only be given s. It's not curried for performance reasons.
diff --git a/src/encoding/json/scanner.go b/src/encoding/json/scanner.go
index a4609c8..38d0b08 100644
--- a/src/encoding/json/scanner.go
+++ b/src/encoding/json/scanner.go
@@ -38,8 +38,15 @@ func nextValue(data []byte, scan *scanner) (value, rest []byte, err error) {
 	scan.reset()
 	for i, c := range data {
 		v := scan.step(scan, int(c))
-		if v >= scanEnd {
+		if v >= scanEndObject {
 			switch v {
+			// probe the scanner with a space to determine whether we will
+			// get scanEnd on the next character. Otherwise, if the next character
+			// is not a space, scanEndTop allocates a needless error.
+			case scanEndObject, scanEndArray:
+				if scan.step(scan, ' ') == scanEnd {
+					return data[:i+1], data[i+1:], nil
+				}
 			case scanError:
 				return nil, nil, scan.err
 			case scanEnd:
diff --git a/src/encoding/json/scanner_test.go b/src/encoding/json/scanner_test.go
index 7880342..66383ef 100644
--- a/src/encoding/json/scanner_test.go
+++ b/src/encoding/json/scanner_test.go
@@ -209,6 +209,7 @@ var benchScan scanner
 
 func BenchmarkSkipValue(b *testing.B) {
 	initBig()
+	b.ResetTimer()
 	for i := 0; i < b.N; i++ {
 		nextValue(jsonBig, &benchScan)
 	}
diff --git a/src/encoding/json/stream.go b/src/encoding/json/stream.go
index 9566eca..dc53bce 100644
--- a/src/encoding/json/stream.go
+++ b/src/encoding/json/stream.go
@@ -12,11 +12,15 @@ import (
 
 // A Decoder reads and decodes JSON objects from an input stream.
 type Decoder struct {
-	r    io.Reader
-	buf  []byte
-	d    decodeState
-	scan scanner
-	err  error
+	r     io.Reader
+	buf   []byte
+	d     decodeState
+	scanp int // start of unread data in buf
+	scan  scanner
+	err   error
+
+	tokenState int
+	tokenStack []int
 }
 
 // NewDecoder returns a new decoder that reads from r.
@@ -41,20 +45,29 @@ func (dec *Decoder) Decode(v interface{}) error {
 		return dec.err
 	}
 
+	if err := dec.tokenPrepareForDecode(); err != nil {
+		return err
+	}
+
+	if !dec.tokenValueAllowed() {
+		return &SyntaxError{msg: "not at beginning of value"}
+	}
+
+	// Read whole value into buffer.
 	n, err := dec.readValue()
 	if err != nil {
 		return err
 	}
+	dec.d.init(dec.buf[dec.scanp : dec.scanp+n])
+	dec.scanp += n
 
 	// Don't save err from unmarshal into dec.err:
 	// the connection is still usable since we read a complete JSON
 	// object from it before the error happened.
-	dec.d.init(dec.buf[0:n])
 	err = dec.d.unmarshal(v)
 
-	// Slide rest of data down.
-	rest := copy(dec.buf, dec.buf[n:])
-	dec.buf = dec.buf[0:rest]
+	// fixup token streaming state
+	dec.tokenValueEnd()
 
 	return err
 }
@@ -62,7 +75,7 @@ func (dec *Decoder) Decode(v interface{}) error {
 // Buffered returns a reader of the data remaining in the Decoder's
 // buffer. The reader is valid until the next call to Decode.
 func (dec *Decoder) Buffered() io.Reader {
-	return bytes.NewReader(dec.buf)
+	return bytes.NewReader(dec.buf[dec.scanp:])
 }
 
 // readValue reads a JSON value into dec.buf.
@@ -70,7 +83,7 @@ func (dec *Decoder) Buffered() io.Reader {
 func (dec *Decoder) readValue() (int, error) {
 	dec.scan.reset()
 
-	scanp := 0
+	scanp := dec.scanp
 	var err error
 Input:
 	for {
@@ -111,20 +124,35 @@ Input:
 			return 0, err
 		}
 
-		// Make room to read more into the buffer.
-		const minRead = 512
-		if cap(dec.buf)-len(dec.buf) < minRead {
-			newBuf := make([]byte, len(dec.buf), 2*cap(dec.buf)+minRead)
-			copy(newBuf, dec.buf)
-			dec.buf = newBuf
-		}
+		n := scanp - dec.scanp
+		err = dec.refill()
+		scanp = dec.scanp + n
+	}
+	return scanp - dec.scanp, nil
+}
 
-		// Read.  Delay error for next iteration (after scan).
-		var n int
-		n, err = dec.r.Read(dec.buf[len(dec.buf):cap(dec.buf)])
-		dec.buf = dec.buf[0 : len(dec.buf)+n]
+func (dec *Decoder) refill() error {
+	// Make room to read more into the buffer.
+	// First slide down data already consumed.
+	if dec.scanp > 0 {
+		n := copy(dec.buf, dec.buf[dec.scanp:])
+		dec.buf = dec.buf[:n]
+		dec.scanp = 0
 	}
-	return scanp, nil
+
+	// Grow buffer if not large enough.
+	const minRead = 512
+	if cap(dec.buf)-len(dec.buf) < minRead {
+		newBuf := make([]byte, len(dec.buf), 2*cap(dec.buf)+minRead)
+		copy(newBuf, dec.buf)
+		dec.buf = newBuf
+	}
+
+	// Read.  Delay error for next iteration (after scan).
+	n, err := dec.r.Read(dec.buf[len(dec.buf):cap(dec.buf)])
+	dec.buf = dec.buf[0 : len(dec.buf)+n]
+
+	return err
 }
 
 func nonSpace(b []byte) bool {
@@ -198,3 +226,255 @@ func (m *RawMessage) UnmarshalJSON(data []byte) error {
 
 var _ Marshaler = (*RawMessage)(nil)
 var _ Unmarshaler = (*RawMessage)(nil)
+
+// A Token holds a value of one of these types:
+//
+//	Delim, for the four JSON delimiters [ ] { }
+//	bool, for JSON booleans
+//	float64, for JSON numbers
+//	Number, for JSON numbers
+//	string, for JSON string literals
+//	nil, for JSON null
+//
+type Token interface{}
+
+const (
+	tokenTopValue = iota
+	tokenArrayStart
+	tokenArrayValue
+	tokenArrayComma
+	tokenObjectStart
+	tokenObjectKey
+	tokenObjectColon
+	tokenObjectValue
+	tokenObjectComma
+)
+
+// advance tokenstate from a separator state to a value state
+func (dec *Decoder) tokenPrepareForDecode() error {
+	// Note: Not calling peek before switch, to avoid
+	// putting peek into the standard Decode path.
+	// peek is only called when using the Token API.
+	switch dec.tokenState {
+	case tokenArrayComma:
+		c, err := dec.peek()
+		if err != nil {
+			return err
+		}
+		if c != ',' {
+			return &SyntaxError{"expected comma after array element", 0}
+		}
+		dec.scanp++
+		dec.tokenState = tokenArrayValue
+	case tokenObjectColon:
+		c, err := dec.peek()
+		if err != nil {
+			return err
+		}
+		if c != ':' {
+			return &SyntaxError{"expected colon after object key", 0}
+		}
+		dec.scanp++
+		dec.tokenState = tokenObjectValue
+	}
+	return nil
+}
+
+func (dec *Decoder) tokenValueAllowed() bool {
+	switch dec.tokenState {
+	case tokenTopValue, tokenArrayStart, tokenArrayValue, tokenObjectValue:
+		return true
+	}
+	return false
+}
+
+func (dec *Decoder) tokenValueEnd() {
+	switch dec.tokenState {
+	case tokenArrayStart, tokenArrayValue:
+		dec.tokenState = tokenArrayComma
+	case tokenObjectValue:
+		dec.tokenState = tokenObjectComma
+	}
+}
+
+// A Delim is a JSON array or object delimiter, one of [ ] { or }.
+type Delim rune
+
+func (d Delim) String() string {
+	return string(d)
+}
+
+// Token returns the next JSON token in the input stream.
+// At the end of the input stream, Token returns nil, io.EOF.
+//
+// Token guarantees that the delimiters [ ] { } it returns are
+// properly nested and matched: if Token encounters an unexpected
+// delimiter in the input, it will return an error.
+//
+// The input stream consists of basic JSON values—bool, string,
+// number, and null—along with delimiters [ ] { } of type Delim
+// to mark the start and end of arrays and objects.
+// Commas and colons are elided.
+func (dec *Decoder) Token() (Token, error) {
+	for {
+		c, err := dec.peek()
+		if err != nil {
+			return nil, err
+		}
+		switch c {
+		case '[':
+			if !dec.tokenValueAllowed() {
+				return dec.tokenError(c)
+			}
+			dec.scanp++
+			dec.tokenStack = append(dec.tokenStack, dec.tokenState)
+			dec.tokenState = tokenArrayStart
+			return Delim('['), nil
+
+		case ']':
+			if dec.tokenState != tokenArrayStart && dec.tokenState != tokenArrayComma {
+				return dec.tokenError(c)
+			}
+			dec.scanp++
+			dec.tokenState = dec.tokenStack[len(dec.tokenStack)-1]
+			dec.tokenStack = dec.tokenStack[:len(dec.tokenStack)-1]
+			dec.tokenValueEnd()
+			return Delim(']'), nil
+
+		case '{':
+			if !dec.tokenValueAllowed() {
+				return dec.tokenError(c)
+			}
+			dec.scanp++
+			dec.tokenStack = append(dec.tokenStack, dec.tokenState)
+			dec.tokenState = tokenObjectStart
+			return Delim('{'), nil
+
+		case '}':
+			if dec.tokenState != tokenObjectStart && dec.tokenState != tokenObjectComma {
+				return dec.tokenError(c)
+			}
+			dec.scanp++
+			dec.tokenState = dec.tokenStack[len(dec.tokenStack)-1]
+			dec.tokenStack = dec.tokenStack[:len(dec.tokenStack)-1]
+			dec.tokenValueEnd()
+			return Delim('}'), nil
+
+		case ':':
+			if dec.tokenState != tokenObjectColon {
+				return dec.tokenError(c)
+			}
+			dec.scanp++
+			dec.tokenState = tokenObjectValue
+			continue
+
+		case ',':
+			if dec.tokenState == tokenArrayComma {
+				dec.scanp++
+				dec.tokenState = tokenArrayValue
+				continue
+			}
+			if dec.tokenState == tokenObjectComma {
+				dec.scanp++
+				dec.tokenState = tokenObjectKey
+				continue
+			}
+			return dec.tokenError(c)
+
+		case '"':
+			if dec.tokenState == tokenObjectStart || dec.tokenState == tokenObjectKey {
+				var x string
+				old := dec.tokenState
+				dec.tokenState = tokenTopValue
+				err := dec.Decode(&x)
+				dec.tokenState = old
+				if err != nil {
+					clearOffset(err)
+					return nil, err
+				}
+				dec.tokenState = tokenObjectColon
+				return x, nil
+			}
+			fallthrough
+
+		default:
+			if !dec.tokenValueAllowed() {
+				return dec.tokenError(c)
+			}
+			var x interface{}
+			if err := dec.Decode(&x); err != nil {
+				clearOffset(err)
+				return nil, err
+			}
+			return x, nil
+		}
+	}
+}
+
+func clearOffset(err error) {
+	if s, ok := err.(*SyntaxError); ok {
+		s.Offset = 0
+	}
+}
+
+func (dec *Decoder) tokenError(c byte) (Token, error) {
+	var context string
+	switch dec.tokenState {
+	case tokenTopValue:
+		context = " looking for beginning of value"
+	case tokenArrayStart, tokenArrayValue, tokenObjectValue:
+		context = " looking for beginning of value"
+	case tokenArrayComma:
+		context = " after array element"
+	case tokenObjectKey:
+		context = " looking for beginning of object key string"
+	case tokenObjectColon:
+		context = " after object key"
+	case tokenObjectComma:
+		context = " after object key:value pair"
+	}
+	return nil, &SyntaxError{"invalid character " + quoteChar(int(c)) + " " + context, 0}
+}
+
+// More reports whether there is another element in the
+// current array or object being parsed.
+func (dec *Decoder) More() bool {
+	c, err := dec.peek()
+	return err == nil && c != ']' && c != '}'
+}
+
+func (dec *Decoder) peek() (byte, error) {
+	var err error
+	for {
+		for i := dec.scanp; i < len(dec.buf); i++ {
+			c := dec.buf[i]
+			if isSpace(rune(c)) {
+				continue
+			}
+			dec.scanp = i
+			return c, nil
+		}
+		// buffer has been scanned, now report any error
+		if err != nil {
+			return 0, err
+		}
+		err = dec.refill()
+	}
+}
+
+/*
+TODO
+
+// EncodeToken writes the given JSON token to the stream.
+// It returns an error if the delimiters [ ] { } are not properly used.
+//
+// EncodeToken does not call Flush, because usually it is part of
+// a larger operation such as Encode, and those will call Flush when finished.
+// Callers that create an Encoder and then invoke EncodeToken directly,
+// without using Encode, need to call Flush when finished to ensure that
+// the JSON is written to the underlying writer.
+func (e *Encoder) EncodeToken(t Token) error  {
+	...
+}
+
+*/
diff --git a/src/encoding/json/stream_test.go b/src/encoding/json/stream_test.go
index b562e87..c2e3040 100644
--- a/src/encoding/json/stream_test.go
+++ b/src/encoding/json/stream_test.go
@@ -6,8 +6,12 @@ package json
 
 import (
 	"bytes"
+	"io"
 	"io/ioutil"
+	"log"
 	"net"
+	"net/http"
+	"net/http/httptest"
 	"reflect"
 	"strings"
 	"testing"
@@ -204,3 +208,147 @@ func BenchmarkEncoderEncode(b *testing.B) {
 		}
 	}
 }
+
+type tokenStreamCase struct {
+	json      string
+	expTokens []interface{}
+}
+
+type decodeThis struct {
+	v interface{}
+}
+
+var tokenStreamCases []tokenStreamCase = []tokenStreamCase{
+	// streaming token cases
+	{json: `10`, expTokens: []interface{}{float64(10)}},
+	{json: ` [10] `, expTokens: []interface{}{
+		Delim('['), float64(10), Delim(']')}},
+	{json: ` [false,10,"b"] `, expTokens: []interface{}{
+		Delim('['), false, float64(10), "b", Delim(']')}},
+	{json: `{ "a": 1 }`, expTokens: []interface{}{
+		Delim('{'), "a", float64(1), Delim('}')}},
+	{json: `{"a": 1, "b":"3"}`, expTokens: []interface{}{
+		Delim('{'), "a", float64(1), "b", "3", Delim('}')}},
+	{json: ` [{"a": 1},{"a": 2}] `, expTokens: []interface{}{
+		Delim('['),
+		Delim('{'), "a", float64(1), Delim('}'),
+		Delim('{'), "a", float64(2), Delim('}'),
+		Delim(']')}},
+	{json: `{"obj": {"a": 1}}`, expTokens: []interface{}{
+		Delim('{'), "obj", Delim('{'), "a", float64(1), Delim('}'),
+		Delim('}')}},
+	{json: `{"obj": [{"a": 1}]}`, expTokens: []interface{}{
+		Delim('{'), "obj", Delim('['),
+		Delim('{'), "a", float64(1), Delim('}'),
+		Delim(']'), Delim('}')}},
+
+	// streaming tokens with intermittent Decode()
+	{json: `{ "a": 1 }`, expTokens: []interface{}{
+		Delim('{'), "a",
+		decodeThis{float64(1)},
+		Delim('}')}},
+	{json: ` [ { "a" : 1 } ] `, expTokens: []interface{}{
+		Delim('['),
+		decodeThis{map[string]interface{}{"a": float64(1)}},
+		Delim(']')}},
+	{json: ` [{"a": 1},{"a": 2}] `, expTokens: []interface{}{
+		Delim('['),
+		decodeThis{map[string]interface{}{"a": float64(1)}},
+		decodeThis{map[string]interface{}{"a": float64(2)}},
+		Delim(']')}},
+	{json: `{ "obj" : [ { "a" : 1 } ] }`, expTokens: []interface{}{
+		Delim('{'), "obj", Delim('['),
+		decodeThis{map[string]interface{}{"a": float64(1)}},
+		Delim(']'), Delim('}')}},
+
+	{json: `{"obj": {"a": 1}}`, expTokens: []interface{}{
+		Delim('{'), "obj",
+		decodeThis{map[string]interface{}{"a": float64(1)}},
+		Delim('}')}},
+	{json: `{"obj": [{"a": 1}]}`, expTokens: []interface{}{
+		Delim('{'), "obj",
+		decodeThis{[]interface{}{
+			map[string]interface{}{"a": float64(1)},
+		}},
+		Delim('}')}},
+	{json: ` [{"a": 1} {"a": 2}] `, expTokens: []interface{}{
+		Delim('['),
+		decodeThis{map[string]interface{}{"a": float64(1)}},
+		decodeThis{&SyntaxError{"expected comma after array element", 0}},
+	}},
+	{json: `{ "a" 1 }`, expTokens: []interface{}{
+		Delim('{'), "a",
+		decodeThis{&SyntaxError{"expected colon after object key", 0}},
+	}},
+}
+
+func TestDecodeInStream(t *testing.T) {
+
+	for ci, tcase := range tokenStreamCases {
+
+		dec := NewDecoder(strings.NewReader(tcase.json))
+		for i, etk := range tcase.expTokens {
+
+			var tk interface{}
+			var err error
+
+			if dt, ok := etk.(decodeThis); ok {
+				etk = dt.v
+				err = dec.Decode(&tk)
+			} else {
+				tk, err = dec.Token()
+			}
+			if experr, ok := etk.(error); ok {
+				if err == nil || err.Error() != experr.Error() {
+					t.Errorf("case %v: Expected error %v in %q, but was %v", ci, experr, tcase.json, err)
+				}
+				break
+			} else if err == io.EOF {
+				t.Errorf("case %v: Unexpected EOF in %q", ci, tcase.json)
+				break
+			} else if err != nil {
+				t.Errorf("case %v: Unexpected error '%v' in %q", ci, err, tcase.json)
+				break
+			}
+			if !reflect.DeepEqual(tk, etk) {
+				t.Errorf(`case %v: %q @ %v expected %T(%v) was %T(%v)`, ci, tcase.json, i, etk, etk, tk, tk)
+				break
+			}
+		}
+	}
+
+}
+
+// Test from golang.org/issue/11893
+func TestHTTPDecoding(t *testing.T) {
+	const raw = `{ "foo": "bar" }`
+
+	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		w.Write([]byte(raw))
+	}))
+	defer ts.Close()
+	res, err := http.Get(ts.URL)
+	if err != nil {
+		log.Fatalf("GET failed: %v", err)
+	}
+	defer res.Body.Close()
+
+	foo := struct {
+		Foo string
+	}{}
+
+	d := NewDecoder(res.Body)
+	err = d.Decode(&foo)
+	if err != nil {
+		t.Fatalf("Decode: %v", err)
+	}
+	if foo.Foo != "bar" {
+		t.Errorf("decoded %q; want \"bar\"", foo.Foo)
+	}
+
+	// make sure we get the EOF the second time
+	err = d.Decode(&foo)
+	if err != io.EOF {
+		t.Errorf("err = %v; want io.EOF", err)
+	}
+}
diff --git a/src/encoding/json/tagkey_test.go b/src/encoding/json/tagkey_test.go
index 23e71c7..85bb4ba 100644
--- a/src/encoding/json/tagkey_test.go
+++ b/src/encoding/json/tagkey_test.go
@@ -37,11 +37,11 @@ type miscPlaneTag struct {
 }
 
 type percentSlashTag struct {
-	V string `json:"text/html%"` // http://golang.org/issue/2718
+	V string `json:"text/html%"` // https://golang.org/issue/2718
 }
 
 type punctuationTag struct {
-	V string `json:"!#$%&()*+-./:<=>?@[]^_{|}~"` // http://golang.org/issue/3546
+	V string `json:"!#$%&()*+-./:<=>?@[]^_{|}~"` // https://golang.org/issue/3546
 }
 
 type emptyTag struct {
diff --git a/src/encoding/pem/pem.go b/src/encoding/pem/pem.go
index 8ff7ee8..506196b 100644
--- a/src/encoding/pem/pem.go
+++ b/src/encoding/pem/pem.go
@@ -10,8 +10,10 @@ package pem
 import (
 	"bytes"
 	"encoding/base64"
+	"errors"
 	"io"
 	"sort"
+	"strings"
 )
 
 // A Block represents a PEM encoded structure.
@@ -110,27 +112,37 @@ func Decode(data []byte) (p *Block, rest []byte) {
 		}
 
 		// TODO(agl): need to cope with values that spread across lines.
-		key, val := line[0:i], line[i+1:]
+		key, val := line[:i], line[i+1:]
 		key = bytes.TrimSpace(key)
 		val = bytes.TrimSpace(val)
 		p.Headers[string(key)] = string(val)
 		rest = next
 	}
 
-	i := bytes.Index(rest, pemEnd)
-	if i < 0 {
+	var endIndex int
+	// If there were no headers, the END line might occur
+	// immediately, without a leading newline.
+	if len(p.Headers) == 0 && bytes.HasPrefix(rest, pemEnd[1:]) {
+		endIndex = 0
+	} else {
+		endIndex = bytes.Index(rest, pemEnd)
+	}
+
+	if endIndex < 0 {
 		return decodeError(data, rest)
 	}
-	base64Data := removeWhitespace(rest[0:i])
 
+	base64Data := removeWhitespace(rest[:endIndex])
 	p.Bytes = make([]byte, base64.StdEncoding.DecodedLen(len(base64Data)))
 	n, err := base64.StdEncoding.Decode(p.Bytes, base64Data)
 	if err != nil {
 		return decodeError(data, rest)
 	}
-	p.Bytes = p.Bytes[0:n]
+	p.Bytes = p.Bytes[:n]
 
-	_, rest = getLine(rest[i+len(pemEnd):])
+	// the -1 is because we might have only matched pemEnd without the
+	// leading newline if the PEM block was empty.
+	_, rest = getLine(rest[endIndex+len(pemEnd)-1:])
 
 	return
 }
@@ -171,6 +183,8 @@ type lineBreaker struct {
 	out  io.Writer
 }
 
+var nl = []byte{'\n'}
+
 func (l *lineBreaker) Write(b []byte) (n int, err error) {
 	if l.used+len(b) < pemLineLength {
 		copy(l.line[l.used:], b)
@@ -190,7 +204,7 @@ func (l *lineBreaker) Write(b []byte) (n int, err error) {
 		return
 	}
 
-	n, err = l.out.Write([]byte{'\n'})
+	n, err = l.out.Write(nl)
 	if err != nil {
 		return
 	}
@@ -204,7 +218,7 @@ func (l *lineBreaker) Close() (err error) {
 		if err != nil {
 			return
 		}
-		_, err = l.out.Write([]byte{'\n'})
+		_, err = l.out.Write(nl)
 	}
 
 	return
@@ -244,11 +258,14 @@ func Encode(out io.Writer, b *Block) error {
 		// For consistency of output, write other headers sorted by key.
 		sort.Strings(h)
 		for _, k := range h {
+			if strings.Contains(k, ":") {
+				return errors.New("pem: cannot encode a header key that contains a colon")
+			}
 			if err := writeHeader(out, k, b.Headers[k]); err != nil {
 				return err
 			}
 		}
-		if _, err := out.Write([]byte{'\n'}); err != nil {
+		if _, err := out.Write(nl); err != nil {
 			return err
 		}
 	}
diff --git a/src/encoding/pem/pem_test.go b/src/encoding/pem/pem_test.go
index ccce42c..ab656c6 100644
--- a/src/encoding/pem/pem_test.go
+++ b/src/encoding/pem/pem_test.go
@@ -6,8 +6,11 @@ package pem
 
 import (
 	"bytes"
+	"io/ioutil"
 	"reflect"
+	"strings"
 	"testing"
+	"testing/quick"
 )
 
 type GetLineTest struct {
@@ -43,6 +46,32 @@ func TestDecode(t *testing.T) {
 	if !reflect.DeepEqual(result, privateKey) {
 		t.Errorf("#1 got:%#v want:%#v", result, privateKey)
 	}
+
+	isEmpty := func(block *Block) bool {
+		return block != nil && block.Type == "EMPTY" && len(block.Headers) == 0 && len(block.Bytes) == 0
+	}
+	result, remainder = Decode(remainder)
+	if !isEmpty(result) {
+		t.Errorf("#2 should be empty but got:%#v", result)
+	}
+	result, remainder = Decode(remainder)
+	if !isEmpty(result) {
+		t.Errorf("#3 should be empty but got:%#v", result)
+	}
+	result, remainder = Decode(remainder)
+	if !isEmpty(result) {
+		t.Errorf("#4 should be empty but got:%#v", result)
+	}
+
+	result, remainder = Decode(remainder)
+	if result == nil || result.Type != "HEADERS" || len(result.Headers) != 1 {
+		t.Errorf("#5 expected single header block but got :%v", result)
+	}
+
+	if len(remainder) != 0 {
+		t.Errorf("expected nothing remaining of pemData, but found %s", string(remainder))
+	}
+
 	result, _ = Decode([]byte(pemPrivateKey2))
 	if !reflect.DeepEqual(result, privateKey2) {
 		t.Errorf("#2 got:%#v want:%#v", result, privateKey2)
@@ -116,6 +145,62 @@ func TestLineBreaker(t *testing.T) {
 	}
 }
 
+func TestFuzz(t *testing.T) {
+	testRoundtrip := func(block Block) bool {
+		for key := range block.Headers {
+			if strings.Contains(key, ":") {
+				// Keys with colons cannot be encoded.
+				return true
+			}
+		}
+
+		var buf bytes.Buffer
+		err := Encode(&buf, &block)
+		decoded, rest := Decode(buf.Bytes())
+
+		switch {
+		case err != nil:
+			t.Errorf("Encode of %#v resulted in error: %s", &block, err)
+		case !reflect.DeepEqual(&block, decoded):
+			t.Errorf("Encode of %#v decoded as %#v", &block, decoded)
+		case len(rest) != 0:
+			t.Errorf("Encode of %#v decoded correctly, but with %x left over", block, rest)
+		default:
+			return true
+		}
+		return false
+	}
+
+	// Explicitly test the empty block.
+	if !testRoundtrip(Block{
+		Type:    "EMPTY",
+		Headers: make(map[string]string),
+		Bytes:   []byte{},
+	}) {
+		return
+	}
+
+	quick.Check(testRoundtrip, nil)
+}
+
+func BenchmarkEncode(b *testing.B) {
+	data := &Block{Bytes: make([]byte, 65536)}
+	b.SetBytes(int64(len(data.Bytes)))
+	for i := 0; i < b.N; i++ {
+		Encode(ioutil.Discard, data)
+	}
+}
+
+func BenchmarkDecode(b *testing.B) {
+	block := &Block{Bytes: make([]byte, 65536)}
+	data := EncodeToMemory(block)
+	b.SetBytes(int64(len(data)))
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		Decode(data)
+	}
+}
+
 var pemData = `verify return:0
 -----BEGIN CERTIFICATE-----
 sdlfkjskldfj
@@ -169,7 +254,32 @@ BTiHcL3s3KrJu1vDVrshvxfnz71KTeNnZH8UbOqT5i7fPGyXtY1XJddcbI/Q6tXf
 wHFsZc20TzSdsVLBtwksUacpbDogcEVMctnNrB8FIrB3vZEv9Q0Z1VeY7nmTpF+6
 a+z2P7acL7j6A6Pr3+q8P9CPiPC7zFonVzuVPyB8GchGR2hytyiOVpuD9+k8hcuw
 ZWAaUoVtWIQ52aKS0p19G99hhb+IVANC4akkdHV4SP8i7MVNZhfUmg==
------END RSA PRIVATE KEY-----`
+-----END RSA PRIVATE KEY-----
+
+
+-----BEGIN EMPTY-----
+-----END EMPTY-----
+
+-----BEGIN EMPTY-----
+
+-----END EMPTY-----
+
+-----BEGIN EMPTY-----
+
+
+-----END EMPTY-----
+
+# This shouldn't be recognised because of the missing newline after the
+headers.
+-----BEGIN HEADERS-----
+Header: 1
+-----END HEADERS-----
+
+# This should be valid, however.
+-----BEGIN HEADERS-----
+Header: 1
+
+-----END HEADERS-----`
 
 var certificate = &Block{Type: "CERTIFICATE",
 	Headers: map[string]string{},
diff --git a/src/encoding/xml/marshal.go b/src/encoding/xml/marshal.go
index 8c63420..86d1422 100644
--- a/src/encoding/xml/marshal.go
+++ b/src/encoding/xml/marshal.go
@@ -173,6 +173,7 @@ func (enc *Encoder) EncodeElement(v interface{}, start StartElement) error {
 }
 
 var (
+	begComment   = []byte("<!--")
 	endComment   = []byte("-->")
 	endProcInst  = []byte("?>")
 	endDirective = []byte(">")
@@ -191,6 +192,7 @@ var (
 // EncodeToken allows writing a ProcInst with Target set to "xml" only as the first token
 // in the stream.
 func (enc *Encoder) EncodeToken(t Token) error {
+
 	p := &enc.p
 	switch t := t.(type) {
 	case StartElement:
@@ -202,7 +204,7 @@ func (enc *Encoder) EncodeToken(t Token) error {
 			return err
 		}
 	case CharData:
-		EscapeText(p, t)
+		escapeText(p, t, false)
 	case Comment:
 		if bytes.Contains(t, endComment) {
 			return fmt.Errorf("xml: EncodeToken of Comment containing --> marker")
@@ -231,16 +233,59 @@ func (enc *Encoder) EncodeToken(t Token) error {
 		}
 		p.WriteString("?>")
 	case Directive:
-		if bytes.Contains(t, endDirective) {
-			return fmt.Errorf("xml: EncodeToken of Directive containing > marker")
+		if !isValidDirective(t) {
+			return fmt.Errorf("xml: EncodeToken of Directive containing wrong < or > markers")
 		}
 		p.WriteString("<!")
 		p.Write(t)
 		p.WriteString(">")
+	default:
+		return fmt.Errorf("xml: EncodeToken of invalid token type")
+
 	}
 	return p.cachedWriteError()
 }
 
+// isValidDirective reports whether dir is a valid directive text,
+// meaning angle brackets are matched, ignoring comments and strings.
+func isValidDirective(dir Directive) bool {
+	var (
+		depth     int
+		inquote   uint8
+		incomment bool
+	)
+	for i, c := range dir {
+		switch {
+		case incomment:
+			if c == '>' {
+				if n := 1 + i - len(endComment); n >= 0 && bytes.Equal(dir[n:i+1], endComment) {
+					incomment = false
+				}
+			}
+			// Just ignore anything in comment
+		case inquote != 0:
+			if c == inquote {
+				inquote = 0
+			}
+			// Just ignore anything within quotes
+		case c == '\'' || c == '"':
+			inquote = c
+		case c == '<':
+			if i+len(begComment) < len(dir) && bytes.Equal(dir[i:i+len(begComment)], begComment) {
+				incomment = true
+			} else {
+				depth++
+			}
+		case c == '>':
+			if depth == 0 {
+				return false
+			}
+			depth--
+		}
+	}
+	return depth == 0 && inquote == 0 && !incomment
+}
+
 // Flush flushes any buffered XML to the underlying writer.
 // See the EncodeToken documentation for details about when it is necessary.
 func (enc *Encoder) Flush() error {
@@ -724,6 +769,9 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
 
 		switch finfo.flags & fMode {
 		case fCharData:
+			if err := s.trim(finfo.parents); err != nil {
+				return err
+			}
 			if vf.CanInterface() && vf.Type().Implements(textMarshalerType) {
 				data, err := vf.Interface().(encoding.TextMarshaler).MarshalText()
 				if err != nil {
@@ -767,6 +815,9 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
 			continue
 
 		case fComment:
+			if err := s.trim(finfo.parents); err != nil {
+				return err
+			}
 			k := vf.Kind()
 			if !(k == reflect.String || k == reflect.Slice && vf.Type().Elem().Kind() == reflect.Uint8) {
 				return fmt.Errorf("xml: bad type for comment field of %s", val.Type())
@@ -894,7 +945,7 @@ func (s *parentStack) trim(parents []string) error {
 			return err
 		}
 	}
-	s.stack = parents[:split]
+	s.stack = s.stack[:split]
 	return nil
 }
 
diff --git a/src/encoding/xml/marshal_test.go b/src/encoding/xml/marshal_test.go
index 14f73a7..66675d7 100644
--- a/src/encoding/xml/marshal_test.go
+++ b/src/encoding/xml/marshal_test.go
@@ -12,6 +12,7 @@ import (
 	"reflect"
 	"strconv"
 	"strings"
+	"sync"
 	"testing"
 	"time"
 )
@@ -339,6 +340,16 @@ type OuterOuterStruct struct {
 	OuterStruct
 }
 
+type NestedAndChardata struct {
+	AB       []string `xml:"A>B"`
+	Chardata string   `xml:",chardata"`
+}
+
+type NestedAndComment struct {
+	AB      []string `xml:"A>B"`
+	Comment string   `xml:",comment"`
+}
+
 func ifaceptr(x interface{}) interface{} {
 	return &x
 }
@@ -617,6 +628,69 @@ var marshalTests = []struct {
 			`</service>`,
 		MarshalOnly: true,
 	},
+	{
+		Value: &struct {
+			XMLName struct{} `xml:"space top"`
+			A       string   `xml:"x>a"`
+			B       string   `xml:"x>b"`
+			C       string   `xml:"space x>c"`
+			C1      string   `xml:"space1 x>c"`
+			D1      string   `xml:"space1 x>d"`
+		}{
+			A:  "a",
+			B:  "b",
+			C:  "c",
+			C1: "c1",
+			D1: "d1",
+		},
+		ExpectXML: `<top xmlns="space">` +
+			`<x><a>a</a><b>b</b><c xmlns="space">c</c>` +
+			`<c xmlns="space1">c1</c>` +
+			`<d xmlns="space1">d1</d>` +
+			`</x>` +
+			`</top>`,
+	},
+	{
+		Value: &struct {
+			XMLName Name
+			A       string `xml:"x>a"`
+			B       string `xml:"x>b"`
+			C       string `xml:"space x>c"`
+			C1      string `xml:"space1 x>c"`
+			D1      string `xml:"space1 x>d"`
+		}{
+			XMLName: Name{
+				Space: "space0",
+				Local: "top",
+			},
+			A:  "a",
+			B:  "b",
+			C:  "c",
+			C1: "c1",
+			D1: "d1",
+		},
+		ExpectXML: `<top xmlns="space0">` +
+			`<x><a>a</a><b>b</b>` +
+			`<c xmlns="space">c</c>` +
+			`<c xmlns="space1">c1</c>` +
+			`<d xmlns="space1">d1</d>` +
+			`</x>` +
+			`</top>`,
+	},
+	{
+		Value: &struct {
+			XMLName struct{} `xml:"top"`
+			B       string   `xml:"space x>b"`
+			B1      string   `xml:"space1 x>b"`
+		}{
+			B:  "b",
+			B1: "b1",
+		},
+		ExpectXML: `<top>` +
+			`<x><b xmlns="space">b</b>` +
+			`<b xmlns="space1">b1</b></x>` +
+			`</top>`,
+	},
 
 	// Test struct embedding
 	{
@@ -924,6 +998,14 @@ var marshalTests = []struct {
 		ExpectXML: `<outer xmlns="testns" int="10"></outer>`,
 		Value:     &OuterOuterStruct{OuterStruct{IntAttr: 10}},
 	},
+	{
+		ExpectXML: `<NestedAndChardata><A><B></B><B></B></A>test</NestedAndChardata>`,
+		Value:     &NestedAndChardata{AB: make([]string, 2), Chardata: "test"},
+	},
+	{
+		ExpectXML: `<NestedAndComment><A><B></B><B></B></A><!--test--></NestedAndComment>`,
+		Value:     &NestedAndComment{AB: make([]string, 2), Comment: "test"},
+	},
 }
 
 func TestMarshal(t *testing.T) {
@@ -933,7 +1015,7 @@ func TestMarshal(t *testing.T) {
 		}
 		data, err := Marshal(test.Value)
 		if err != nil {
-			t.Errorf("#%d: Error: %s", idx, err)
+			t.Errorf("#%d: marshal(%#v): %s", idx, test.Value, err)
 			continue
 		}
 		if got, want := string(data), test.ExpectXML; got != want {
@@ -1037,6 +1119,14 @@ func TestUnmarshal(t *testing.T) {
 		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()
@@ -1148,12 +1238,14 @@ func TestMarshalFlush(t *testing.T) {
 }
 
 func BenchmarkMarshal(b *testing.B) {
+	b.ReportAllocs()
 	for i := 0; i < b.N; i++ {
 		Marshal(atomValue)
 	}
 }
 
 func BenchmarkUnmarshal(b *testing.B) {
+	b.ReportAllocs()
 	xml := []byte(atomXml)
 	for i := 0; i < b.N; i++ {
 		Unmarshal(xml, &Feed{})
@@ -1192,41 +1284,369 @@ func TestStructPointerMarshal(t *testing.T) {
 }
 
 var encodeTokenTests = []struct {
-	tok  Token
+	desc string
+	toks []Token
 	want string
-	ok   bool
-}{
-	{StartElement{Name{"space", "local"}, nil}, "<local xmlns=\"space\">", true},
-	{StartElement{Name{"space", ""}, nil}, "", false},
-	{EndElement{Name{"space", ""}}, "", false},
-	{CharData("foo"), "foo", true},
-	{Comment("foo"), "<!--foo-->", true},
-	{Comment("foo-->"), "", false},
-	{ProcInst{"Target", []byte("Instruction")}, "<?Target Instruction?>", true},
-	{ProcInst{"", []byte("Instruction")}, "", false},
-	{ProcInst{"Target", []byte("Instruction?>")}, "", false},
-	{Directive("foo"), "<!foo>", true},
-	{Directive("foo>"), "", false},
-}
+	err  string
+}{{
+	desc: "start element with name space",
+	toks: []Token{
+		StartElement{Name{"space", "local"}, nil},
+	},
+	want: `<local xmlns="space">`,
+}, {
+	desc: "start element with no name",
+	toks: []Token{
+		StartElement{Name{"space", ""}, nil},
+	},
+	err: "xml: start tag with no name",
+}, {
+	desc: "end element with no name",
+	toks: []Token{
+		EndElement{Name{"space", ""}},
+	},
+	err: "xml: end tag with no name",
+}, {
+	desc: "char data",
+	toks: []Token{
+		CharData("foo"),
+	},
+	want: `foo`,
+}, {
+	desc: "char data with escaped chars",
+	toks: []Token{
+		CharData(" \t\n"),
+	},
+	want: " &#x9;\n",
+}, {
+	desc: "comment",
+	toks: []Token{
+		Comment("foo"),
+	},
+	want: `<!--foo-->`,
+}, {
+	desc: "comment with invalid content",
+	toks: []Token{
+		Comment("foo-->"),
+	},
+	err: "xml: EncodeToken of Comment containing --> marker",
+}, {
+	desc: "proc instruction",
+	toks: []Token{
+		ProcInst{"Target", []byte("Instruction")},
+	},
+	want: `<?Target Instruction?>`,
+}, {
+	desc: "proc instruction with empty target",
+	toks: []Token{
+		ProcInst{"", []byte("Instruction")},
+	},
+	err: "xml: EncodeToken of ProcInst with invalid Target",
+}, {
+	desc: "proc instruction with bad content",
+	toks: []Token{
+		ProcInst{"", []byte("Instruction?>")},
+	},
+	err: "xml: EncodeToken of ProcInst with invalid Target",
+}, {
+	desc: "directive",
+	toks: []Token{
+		Directive("foo"),
+	},
+	want: `<!foo>`,
+}, {
+	desc: "more complex directive",
+	toks: []Token{
+		Directive("DOCTYPE doc [ <!ELEMENT doc '>'> <!-- com>ment --> ]"),
+	},
+	want: `<!DOCTYPE doc [ <!ELEMENT doc '>'> <!-- com>ment --> ]>`,
+}, {
+	desc: "directive instruction with bad name",
+	toks: []Token{
+		Directive("foo>"),
+	},
+	err: "xml: EncodeToken of Directive containing wrong < or > markers",
+}, {
+	desc: "end tag without start tag",
+	toks: []Token{
+		EndElement{Name{"foo", "bar"}},
+	},
+	err: "xml: end tag </bar> without start tag",
+}, {
+	desc: "mismatching end tag local name",
+	toks: []Token{
+		StartElement{Name{"", "foo"}, nil},
+		EndElement{Name{"", "bar"}},
+	},
+	err:  "xml: end tag </bar> does not match start tag <foo>",
+	want: `<foo>`,
+}, {
+	desc: "mismatching end tag namespace",
+	toks: []Token{
+		StartElement{Name{"space", "foo"}, nil},
+		EndElement{Name{"another", "foo"}},
+	},
+	err:  "xml: end tag </foo> in namespace another does not match start tag <foo> in namespace space",
+	want: `<foo xmlns="space">`,
+}, {
+	desc: "start element with explicit namespace",
+	toks: []Token{
+		StartElement{Name{"space", "local"}, []Attr{
+			{Name{"xmlns", "x"}, "space"},
+			{Name{"space", "foo"}, "value"},
+		}},
+	},
+	want: `<local xmlns="space" xmlns:_xmlns="xmlns" _xmlns:x="space" xmlns:space="space" space:foo="value">`,
+}, {
+	desc: "start element with explicit namespace and colliding prefix",
+	toks: []Token{
+		StartElement{Name{"space", "local"}, []Attr{
+			{Name{"xmlns", "x"}, "space"},
+			{Name{"space", "foo"}, "value"},
+			{Name{"x", "bar"}, "other"},
+		}},
+	},
+	want: `<local xmlns="space" xmlns:_xmlns="xmlns" _xmlns:x="space" xmlns:space="space" space:foo="value" xmlns:x="x" x:bar="other">`,
+}, {
+	desc: "start element using previously defined namespace",
+	toks: []Token{
+		StartElement{Name{"", "local"}, []Attr{
+			{Name{"xmlns", "x"}, "space"},
+		}},
+		StartElement{Name{"space", "foo"}, []Attr{
+			{Name{"space", "x"}, "y"},
+		}},
+	},
+	want: `<local xmlns:_xmlns="xmlns" _xmlns:x="space"><foo xmlns="space" xmlns:space="space" space:x="y">`,
+}, {
+	desc: "nested name space with same prefix",
+	toks: []Token{
+		StartElement{Name{"", "foo"}, []Attr{
+			{Name{"xmlns", "x"}, "space1"},
+		}},
+		StartElement{Name{"", "foo"}, []Attr{
+			{Name{"xmlns", "x"}, "space2"},
+		}},
+		StartElement{Name{"", "foo"}, []Attr{
+			{Name{"space1", "a"}, "space1 value"},
+			{Name{"space2", "b"}, "space2 value"},
+		}},
+		EndElement{Name{"", "foo"}},
+		EndElement{Name{"", "foo"}},
+		StartElement{Name{"", "foo"}, []Attr{
+			{Name{"space1", "a"}, "space1 value"},
+			{Name{"space2", "b"}, "space2 value"},
+		}},
+	},
+	want: `<foo xmlns:_xmlns="xmlns" _xmlns:x="space1"><foo _xmlns:x="space2"><foo xmlns:space1="space1" space1:a="space1 value" xmlns:space2="space2" space2:b="space2 value"></foo></foo><foo xmlns:space1="space1" space1:a="space1 value" xmlns:space2="space2" space2:b="space2 value">`,
+}, {
+	desc: "start element defining several prefixes for the same name space",
+	toks: []Token{
+		StartElement{Name{"space", "foo"}, []Attr{
+			{Name{"xmlns", "a"}, "space"},
+			{Name{"xmlns", "b"}, "space"},
+			{Name{"space", "x"}, "value"},
+		}},
+	},
+	want: `<foo xmlns="space" xmlns:_xmlns="xmlns" _xmlns:a="space" _xmlns:b="space" xmlns:space="space" space:x="value">`,
+}, {
+	desc: "nested element redefines name space",
+	toks: []Token{
+		StartElement{Name{"", "foo"}, []Attr{
+			{Name{"xmlns", "x"}, "space"},
+		}},
+		StartElement{Name{"space", "foo"}, []Attr{
+			{Name{"xmlns", "y"}, "space"},
+			{Name{"space", "a"}, "value"},
+		}},
+	},
+	want: `<foo xmlns:_xmlns="xmlns" _xmlns:x="space"><foo xmlns="space" _xmlns:y="space" xmlns:space="space" space:a="value">`,
+}, {
+	desc: "nested element creates alias for default name space",
+	toks: []Token{
+		StartElement{Name{"space", "foo"}, []Attr{
+			{Name{"", "xmlns"}, "space"},
+		}},
+		StartElement{Name{"space", "foo"}, []Attr{
+			{Name{"xmlns", "y"}, "space"},
+			{Name{"space", "a"}, "value"},
+		}},
+	},
+	want: `<foo xmlns="space" xmlns="space"><foo xmlns="space" xmlns:_xmlns="xmlns" _xmlns:y="space" xmlns:space="space" space:a="value">`,
+}, {
+	desc: "nested element defines default name space with existing prefix",
+	toks: []Token{
+		StartElement{Name{"", "foo"}, []Attr{
+			{Name{"xmlns", "x"}, "space"},
+		}},
+		StartElement{Name{"space", "foo"}, []Attr{
+			{Name{"", "xmlns"}, "space"},
+			{Name{"space", "a"}, "value"},
+		}},
+	},
+	want: `<foo xmlns:_xmlns="xmlns" _xmlns:x="space"><foo xmlns="space" xmlns="space" xmlns:space="space" space:a="value">`,
+}, {
+	desc: "nested element uses empty attribute name space when default ns defined",
+	toks: []Token{
+		StartElement{Name{"space", "foo"}, []Attr{
+			{Name{"", "xmlns"}, "space"},
+		}},
+		StartElement{Name{"space", "foo"}, []Attr{
+			{Name{"", "attr"}, "value"},
+		}},
+	},
+	want: `<foo xmlns="space" xmlns="space"><foo xmlns="space" attr="value">`,
+}, {
+	desc: "redefine xmlns",
+	toks: []Token{
+		StartElement{Name{"", "foo"}, []Attr{
+			{Name{"foo", "xmlns"}, "space"},
+		}},
+	},
+	want: `<foo xmlns:foo="foo" foo:xmlns="space">`,
+}, {
+	desc: "xmlns with explicit name space #1",
+	toks: []Token{
+		StartElement{Name{"space", "foo"}, []Attr{
+			{Name{"xml", "xmlns"}, "space"},
+		}},
+	},
+	want: `<foo xmlns="space" xmlns:_xml="xml" _xml:xmlns="space">`,
+}, {
+	desc: "xmlns with explicit name space #2",
+	toks: []Token{
+		StartElement{Name{"space", "foo"}, []Attr{
+			{Name{xmlURL, "xmlns"}, "space"},
+		}},
+	},
+	want: `<foo xmlns="space" xml:xmlns="space">`,
+}, {
+	desc: "empty name space declaration is ignored",
+	toks: []Token{
+		StartElement{Name{"", "foo"}, []Attr{
+			{Name{"xmlns", "foo"}, ""},
+		}},
+	},
+	want: `<foo xmlns:_xmlns="xmlns" _xmlns:foo="">`,
+}, {
+	desc: "attribute with no name is ignored",
+	toks: []Token{
+		StartElement{Name{"", "foo"}, []Attr{
+			{Name{"", ""}, "value"},
+		}},
+	},
+	want: `<foo>`,
+}, {
+	desc: "namespace URL with non-valid name",
+	toks: []Token{
+		StartElement{Name{"/34", "foo"}, []Attr{
+			{Name{"/34", "x"}, "value"},
+		}},
+	},
+	want: `<foo xmlns="/34" xmlns:_="/34" _:x="value">`,
+}, {
+	desc: "nested element resets default namespace to empty",
+	toks: []Token{
+		StartElement{Name{"space", "foo"}, []Attr{
+			{Name{"", "xmlns"}, "space"},
+		}},
+		StartElement{Name{"", "foo"}, []Attr{
+			{Name{"", "xmlns"}, ""},
+			{Name{"", "x"}, "value"},
+			{Name{"space", "x"}, "value"},
+		}},
+	},
+	want: `<foo xmlns="space" xmlns="space"><foo xmlns="" x="value" xmlns:space="space" space:x="value">`,
+}, {
+	desc: "nested element requires empty default name space",
+	toks: []Token{
+		StartElement{Name{"space", "foo"}, []Attr{
+			{Name{"", "xmlns"}, "space"},
+		}},
+		StartElement{Name{"", "foo"}, nil},
+	},
+	want: `<foo xmlns="space" xmlns="space"><foo>`,
+}, {
+	desc: "attribute uses name space from xmlns",
+	toks: []Token{
+		StartElement{Name{"some/space", "foo"}, []Attr{
+			{Name{"", "attr"}, "value"},
+			{Name{"some/space", "other"}, "other value"},
+		}},
+	},
+	want: `<foo xmlns="some/space" attr="value" xmlns:space="some/space" space:other="other value">`,
+}, {
+	desc: "default name space should not be used by attributes",
+	toks: []Token{
+		StartElement{Name{"space", "foo"}, []Attr{
+			{Name{"", "xmlns"}, "space"},
+			{Name{"xmlns", "bar"}, "space"},
+			{Name{"space", "baz"}, "foo"},
+		}},
+		StartElement{Name{"space", "baz"}, nil},
+		EndElement{Name{"space", "baz"}},
+		EndElement{Name{"space", "foo"}},
+	},
+	want: `<foo xmlns="space" xmlns="space" xmlns:_xmlns="xmlns" _xmlns:bar="space" xmlns:space="space" space:baz="foo"><baz xmlns="space"></baz></foo>`,
+}, {
+	desc: "default name space not used by attributes, not explicitly defined",
+	toks: []Token{
+		StartElement{Name{"space", "foo"}, []Attr{
+			{Name{"", "xmlns"}, "space"},
+			{Name{"space", "baz"}, "foo"},
+		}},
+		StartElement{Name{"space", "baz"}, nil},
+		EndElement{Name{"space", "baz"}},
+		EndElement{Name{"space", "foo"}},
+	},
+	want: `<foo xmlns="space" xmlns="space" xmlns:space="space" space:baz="foo"><baz xmlns="space"></baz></foo>`,
+}, {
+	desc: "impossible xmlns declaration",
+	toks: []Token{
+		StartElement{Name{"", "foo"}, []Attr{
+			{Name{"", "xmlns"}, "space"},
+		}},
+		StartElement{Name{"space", "bar"}, []Attr{
+			{Name{"space", "attr"}, "value"},
+		}},
+	},
+	want: `<foo xmlns="space"><bar xmlns="space" xmlns:space="space" space:attr="value">`,
+}}
 
 func TestEncodeToken(t *testing.T) {
-	for _, tt := range encodeTokenTests {
+loop:
+	for i, tt := range encodeTokenTests {
 		var buf bytes.Buffer
 		enc := NewEncoder(&buf)
-		err := enc.EncodeToken(tt.tok)
+		var err error
+		for j, tok := range tt.toks {
+			err = enc.EncodeToken(tok)
+			if err != nil && j < len(tt.toks)-1 {
+				t.Errorf("#%d %s token #%d: %v", i, tt.desc, j, err)
+				continue loop
+			}
+		}
+		errorf := func(f string, a ...interface{}) {
+			t.Errorf("#%d %s token #%d:%s", i, tt.desc, len(tt.toks)-1, fmt.Sprintf(f, a...))
+		}
 		switch {
-		case !tt.ok && err == nil:
-			t.Errorf("enc.EncodeToken(%#v): expected error; got none", tt.tok)
-		case tt.ok && err != nil:
-			t.Fatalf("enc.EncodeToken: %v", err)
-		case !tt.ok && err != nil:
-			// expected error, got one
+		case tt.err != "" && err == nil:
+			errorf(" expected error; got none")
+			continue
+		case tt.err == "" && err != nil:
+			errorf(" got error: %v", err)
+			continue
+		case tt.err != "" && err != nil && tt.err != err.Error():
+			errorf(" error mismatch; got %v, want %v", err, tt.err)
+			continue
 		}
 		if err := enc.Flush(); err != nil {
-			t.Fatalf("enc.EncodeToken: %v", err)
+			errorf(" %v", err)
+			continue
 		}
 		if got := buf.String(); got != tt.want {
-			t.Errorf("enc.EncodeToken = %s; want: %s", got, tt.want)
+			errorf("\ngot  %v\nwant %v", got, tt.want)
+			continue
 		}
 	}
 }
@@ -1264,3 +1684,83 @@ func TestDecodeEncode(t *testing.T) {
 		}
 	}
 }
+
+// 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()
+}
+
+func TestIsValidDirective(t *testing.T) {
+	testOK := []string{
+		"<>",
+		"< < > >",
+		"<!DOCTYPE '<' '>' '>' <!--nothing-->>",
+		"<!DOCTYPE doc [ <!ELEMENT doc ANY> <!ELEMENT doc ANY> ]>",
+		"<!DOCTYPE doc [ <!ELEMENT doc \"ANY> '<' <!E\" LEMENT '>' doc ANY> ]>",
+		"<!DOCTYPE doc <!-- just>>>> a < comment --> [ <!ITEM anything> ] >",
+	}
+	testKO := []string{
+		"<",
+		">",
+		"<!--",
+		"-->",
+		"< > > < < >",
+		"<!dummy <!-- > -->",
+		"<!DOCTYPE doc '>",
+		"<!DOCTYPE doc '>'",
+		"<!DOCTYPE doc <!--comment>",
+	}
+	for _, s := range testOK {
+		if !isValidDirective(Directive(s)) {
+			t.Errorf("Directive %q is expected to be valid", s)
+		}
+	}
+	for _, s := range testKO {
+		if isValidDirective(Directive(s)) {
+			t.Errorf("Directive %q is expected to be invalid", s)
+		}
+	}
+}
+
+// Issue 11719. EncodeToken used to silently eat tokens with an invalid type.
+func TestSimpleUseOfEncodeToken(t *testing.T) {
+	var buf bytes.Buffer
+	enc := NewEncoder(&buf)
+	if err := enc.EncodeToken(&StartElement{Name: Name{"", "object1"}}); err == nil {
+		t.Errorf("enc.EncodeToken: pointer type should be rejected")
+	}
+	if err := enc.EncodeToken(&EndElement{Name: Name{"", "object1"}}); err == nil {
+		t.Errorf("enc.EncodeToken: pointer type should be rejected")
+	}
+	if err := enc.EncodeToken(StartElement{Name: Name{"", "object2"}}); err != nil {
+		t.Errorf("enc.EncodeToken: StartElement %s", err)
+	}
+	if err := enc.EncodeToken(EndElement{Name: Name{"", "object2"}}); err != nil {
+		t.Errorf("enc.EncodeToken: EndElement %s", err)
+	}
+	if err := enc.EncodeToken(Universe{}); err == nil {
+		t.Errorf("enc.EncodeToken: invalid type not caught")
+	}
+	if err := enc.Flush(); err != nil {
+		t.Errorf("enc.Flush: %s", err)
+	}
+	if buf.Len() == 0 {
+		t.Errorf("enc.EncodeToken: empty buffer")
+	}
+	want := "<object2></object2>"
+	if buf.String() != want {
+		t.Errorf("enc.EncodeToken: expected %q; got %q", want, buf.String())
+	}
+}
diff --git a/src/encoding/xml/read_test.go b/src/encoding/xml/read_test.go
index 01f55d0..7d004dc 100644
--- a/src/encoding/xml/read_test.go
+++ b/src/encoding/xml/read_test.go
@@ -694,7 +694,7 @@ type Pod struct {
 	Pea interface{} `xml:"Pea"`
 }
 
-// https://code.google.com/p/go/issues/detail?id=6836
+// https://golang.org/issue/6836
 func TestUnmarshalIntoInterface(t *testing.T) {
 	pod := new(Pod)
 	pod.Pea = new(Pea)
diff --git a/src/encoding/xml/xml.go b/src/encoding/xml/xml.go
index 8c15b98..0a21c93 100644
--- a/src/encoding/xml/xml.go
+++ b/src/encoding/xml/xml.go
@@ -549,7 +549,6 @@ func (d *Decoder) rawToken() (Token, error) {
 
 	case '?':
 		// <?: Processing instruction.
-		// TODO(rsc): Should parse the <?xml declaration to make sure the version is 1.0.
 		var target string
 		if target, ok = d.name(); !ok {
 			if d.err == nil {
@@ -574,7 +573,13 @@ func (d *Decoder) rawToken() (Token, error) {
 		data = data[0 : len(data)-2] // chop ?>
 
 		if target == "xml" {
-			enc := procInstEncoding(string(data))
+			content := string(data)
+			ver := procInst("version", content)
+			if ver != "" && ver != "1.0" {
+				d.err = fmt.Errorf("xml: unsupported version %q; only version 1.0 is supported", ver)
+				return nil, d.err
+			}
+			enc := procInst("encoding", content)
 			if enc != "" && enc != "utf-8" && enc != "UTF-8" {
 				if d.CharsetReader == nil {
 					d.err = fmt.Errorf("xml: encoding %q declared but Decoder.CharsetReader is nil", enc)
@@ -723,7 +728,7 @@ func (d *Decoder) rawToken() (Token, error) {
 		return nil, d.err
 	}
 
-	attr = make([]Attr, 0, 4)
+	attr = []Attr{}
 	for {
 		d.space()
 		if b, ok = d.mustgetc(); !ok {
@@ -747,7 +752,11 @@ func (d *Decoder) rawToken() (Token, error) {
 
 		n := len(attr)
 		if n >= cap(attr) {
-			nattr := make([]Attr, n, 2*cap(attr))
+			nCap := 2 * cap(attr)
+			if nCap == 0 {
+				nCap = 4
+			}
+			nattr := make([]Attr, n, nCap)
 			copy(nattr, attr)
 			attr = nattr
 		}
@@ -1119,12 +1128,12 @@ func (d *Decoder) name() (s string, ok bool) {
 	}
 
 	// Now we check the characters.
-	s = d.buf.String()
-	if !isName([]byte(s)) {
-		d.err = d.syntaxError("invalid XML name: " + s)
+	b := d.buf.Bytes()
+	if !isName(b) {
+		d.err = d.syntaxError("invalid XML name: " + string(b))
 		return "", false
 	}
-	return s, true
+	return string(b), true
 }
 
 // Read a name and append its bytes to d.buf.
@@ -1832,6 +1841,13 @@ var (
 // EscapeText writes to w the properly escaped XML equivalent
 // of the plain text data s.
 func EscapeText(w io.Writer, s []byte) error {
+	return escapeText(w, s, true)
+}
+
+// escapeText writes to w the properly escaped XML equivalent
+// of the plain text data s. If escapeNewline is true, newline
+// characters will be escaped.
+func escapeText(w io.Writer, s []byte, escapeNewline bool) error {
 	var esc []byte
 	last := 0
 	for i := 0; i < len(s); {
@@ -1851,6 +1867,9 @@ func EscapeText(w io.Writer, s []byte) error {
 		case '\t':
 			esc = esc_tab
 		case '\n':
+			if !escapeNewline {
+				continue
+			}
 			esc = esc_nl
 		case '\r':
 			esc = esc_cr
@@ -1921,16 +1940,17 @@ func Escape(w io.Writer, s []byte) {
 	EscapeText(w, s)
 }
 
-// procInstEncoding parses the `encoding="..."` or `encoding='...'`
+// procInst parses the `param="..."` or `param='...'`
 // value out of the provided string, returning "" if not found.
-func procInstEncoding(s string) string {
+func procInst(param, s string) string {
 	// TODO: this parsing is somewhat lame and not exact.
 	// It works for all actual cases, though.
-	idx := strings.Index(s, "encoding=")
+	param = param + "="
+	idx := strings.Index(s, param)
 	if idx == -1 {
 		return ""
 	}
-	v := s[idx+len("encoding="):]
+	v := s[idx+len(param):]
 	if v == "" {
 		return ""
 	}
diff --git a/src/encoding/xml/xml_test.go b/src/encoding/xml/xml_test.go
index be995c0..312a7c9 100644
--- a/src/encoding/xml/xml_test.go
+++ b/src/encoding/xml/xml_test.go
@@ -657,20 +657,23 @@ type procInstEncodingTest struct {
 }
 
 var procInstTests = []struct {
-	input, expect string
+	input  string
+	expect [2]string
 }{
-	{`version="1.0" encoding="utf-8"`, "utf-8"},
-	{`version="1.0" encoding='utf-8'`, "utf-8"},
-	{`version="1.0" encoding='utf-8' `, "utf-8"},
-	{`version="1.0" encoding=utf-8`, ""},
-	{`encoding="FOO" `, "FOO"},
+	{`version="1.0" encoding="utf-8"`, [2]string{"1.0", "utf-8"}},
+	{`version="1.0" encoding='utf-8'`, [2]string{"1.0", "utf-8"}},
+	{`version="1.0" encoding='utf-8' `, [2]string{"1.0", "utf-8"}},
+	{`version="1.0" encoding=utf-8`, [2]string{"1.0", ""}},
+	{`encoding="FOO" `, [2]string{"", "FOO"}},
 }
 
 func TestProcInstEncoding(t *testing.T) {
 	for _, test := range procInstTests {
-		got := procInstEncoding(test.input)
-		if got != test.expect {
-			t.Errorf("procInstEncoding(%q) = %q; want %q", test.input, got, test.expect)
+		if got := procInst("version", test.input); got != test.expect[0] {
+			t.Errorf("procInst(version, %q) = %q; want %q", test.input, got, test.expect[0])
+		}
+		if got := procInst("encoding", test.input); got != test.expect[1] {
+			t.Errorf("procInst(encoding, %q) = %q; want %q", test.input, got, test.expect[1])
 		}
 	}
 }
diff --git a/src/expvar/expvar.go b/src/expvar/expvar.go
index 9b6dab4..24c2d6b 100644
--- a/src/expvar/expvar.go
+++ b/src/expvar/expvar.go
@@ -26,12 +26,14 @@ import (
 	"encoding/json"
 	"fmt"
 	"log"
+	"math"
 	"net/http"
 	"os"
 	"runtime"
 	"sort"
 	"strconv"
 	"sync"
+	"sync/atomic"
 )
 
 // Var is an abstract type for all exported variables.
@@ -41,52 +43,47 @@ type Var interface {
 
 // Int is a 64-bit integer variable that satisfies the Var interface.
 type Int struct {
-	mu sync.RWMutex
-	i  int64
+	i int64
 }
 
 func (v *Int) String() string {
-	v.mu.RLock()
-	defer v.mu.RUnlock()
-	return strconv.FormatInt(v.i, 10)
+	return strconv.FormatInt(atomic.LoadInt64(&v.i), 10)
 }
 
 func (v *Int) Add(delta int64) {
-	v.mu.Lock()
-	defer v.mu.Unlock()
-	v.i += delta
+	atomic.AddInt64(&v.i, delta)
 }
 
 func (v *Int) Set(value int64) {
-	v.mu.Lock()
-	defer v.mu.Unlock()
-	v.i = value
+	atomic.StoreInt64(&v.i, value)
 }
 
 // Float is a 64-bit float variable that satisfies the Var interface.
 type Float struct {
-	mu sync.RWMutex
-	f  float64
+	f uint64
 }
 
 func (v *Float) String() string {
-	v.mu.RLock()
-	defer v.mu.RUnlock()
-	return strconv.FormatFloat(v.f, 'g', -1, 64)
+	return strconv.FormatFloat(
+		math.Float64frombits(atomic.LoadUint64(&v.f)), 'g', -1, 64)
 }
 
 // Add adds delta to v.
 func (v *Float) Add(delta float64) {
-	v.mu.Lock()
-	defer v.mu.Unlock()
-	v.f += delta
+	for {
+		cur := atomic.LoadUint64(&v.f)
+		curVal := math.Float64frombits(cur)
+		nxtVal := curVal + delta
+		nxt := math.Float64bits(nxtVal)
+		if atomic.CompareAndSwapUint64(&v.f, cur, nxt) {
+			return
+		}
+	}
 }
 
 // Set sets v to value.
 func (v *Float) Set(value float64) {
-	v.mu.Lock()
-	defer v.mu.Unlock()
-	v.f = value
+	atomic.StoreUint64(&v.f, math.Float64bits(value))
 }
 
 // Map is a string-to-Var map variable that satisfies the Var interface.
diff --git a/src/expvar/expvar_test.go b/src/expvar/expvar_test.go
index 765e3b7..8bc633e 100644
--- a/src/expvar/expvar_test.go
+++ b/src/expvar/expvar_test.go
@@ -7,8 +7,13 @@ package expvar
 import (
 	"bytes"
 	"encoding/json"
+	"math"
+	"net"
 	"net/http/httptest"
+	"runtime"
 	"strconv"
+	"sync"
+	"sync/atomic"
 	"testing"
 )
 
@@ -47,6 +52,30 @@ func TestInt(t *testing.T) {
 	}
 }
 
+func BenchmarkIntAdd(b *testing.B) {
+	var v Int
+
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			v.Add(1)
+		}
+	})
+}
+
+func BenchmarkIntSet(b *testing.B) {
+	var v Int
+
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			v.Set(1)
+		}
+	})
+}
+
+func (v *Float) val() float64 {
+	return math.Float64frombits(atomic.LoadUint64(&v.f))
+}
+
 func TestFloat(t *testing.T) {
 	RemoveAll()
 	reqs := NewFloat("requests-float")
@@ -59,8 +88,8 @@ func TestFloat(t *testing.T) {
 
 	reqs.Add(1.5)
 	reqs.Add(1.25)
-	if reqs.f != 2.75 {
-		t.Errorf("reqs.f = %v, want 2.75", reqs.f)
+	if v := reqs.val(); v != 2.75 {
+		t.Errorf("reqs.val() = %v, want 2.75", v)
 	}
 
 	if s := reqs.String(); s != "2.75" {
@@ -68,11 +97,31 @@ func TestFloat(t *testing.T) {
 	}
 
 	reqs.Add(-2)
-	if reqs.f != 0.75 {
-		t.Errorf("reqs.f = %v, want 0.75", reqs.f)
+	if v := reqs.val(); v != 0.75 {
+		t.Errorf("reqs.val() = %v, want 0.75", v)
 	}
 }
 
+func BenchmarkFloatAdd(b *testing.B) {
+	var f Float
+
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			f.Add(1.0)
+		}
+	})
+}
+
+func BenchmarkFloatSet(b *testing.B) {
+	var f Float
+
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			f.Set(1.0)
+		}
+	})
+}
+
 func TestString(t *testing.T) {
 	RemoveAll()
 	name := NewString("my-name")
@@ -90,6 +139,16 @@ func TestString(t *testing.T) {
 	}
 }
 
+func BenchmarkStringSet(b *testing.B) {
+	var s String
+
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			s.Set("red")
+		}
+	})
+}
+
 func TestMapCounter(t *testing.T) {
 	RemoveAll()
 	colors := NewMap("bike-shed-colors")
@@ -104,8 +163,8 @@ func TestMapCounter(t *testing.T) {
 	if x := colors.m["blue"].(*Int).i; x != 4 {
 		t.Errorf("colors.m[\"blue\"] = %v, want 4", x)
 	}
-	if x := colors.m[`green "midori"`].(*Float).f; x != 4.125 {
-		t.Errorf("colors.m[`green \"midori\"] = %v, want 3.14", x)
+	if x := colors.m[`green "midori"`].(*Float).val(); x != 4.125 {
+		t.Errorf("colors.m[`green \"midori\"] = %v, want 4.125", x)
 	}
 
 	// colors.String() should be '{"red":3, "blue":4}',
@@ -130,6 +189,38 @@ func TestMapCounter(t *testing.T) {
 	}
 }
 
+func BenchmarkMapSet(b *testing.B) {
+	m := new(Map).Init()
+
+	v := new(Int)
+
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			m.Set("red", v)
+		}
+	})
+}
+
+func BenchmarkMapAddSame(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		m := new(Map).Init()
+		m.Add("red", 1)
+		m.Add("red", 1)
+		m.Add("red", 1)
+		m.Add("red", 1)
+	}
+}
+
+func BenchmarkMapAddDifferent(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		m := new(Map).Init()
+		m.Add("red", 1)
+		m.Add("blue", 1)
+		m.Add("green", 1)
+		m.Add("yellow", 1)
+	}
+}
+
 func TestFunc(t *testing.T) {
 	RemoveAll()
 	var x interface{} = []string{"a", "b"}
@@ -165,3 +256,135 @@ func TestHandler(t *testing.T) {
 		t.Errorf("HTTP handler wrote:\n%s\nWant:\n%s", got, want)
 	}
 }
+
+func BenchmarkRealworldExpvarUsage(b *testing.B) {
+	var (
+		bytesSent Int
+		bytesRead Int
+	)
+
+	// The benchmark creates GOMAXPROCS client/server pairs.
+	// Each pair creates 4 goroutines: client reader/writer and server reader/writer.
+	// The benchmark stresses concurrent reading and writing to the same connection.
+	// Such pattern is used in net/http and net/rpc.
+
+	b.StopTimer()
+
+	P := runtime.GOMAXPROCS(0)
+	N := b.N / P
+	W := 1000
+
+	// Setup P client/server connections.
+	clients := make([]net.Conn, P)
+	servers := make([]net.Conn, P)
+	ln, err := net.Listen("tcp", "127.0.0.1:0")
+	if err != nil {
+		b.Fatalf("Listen failed: %v", err)
+	}
+	defer ln.Close()
+	done := make(chan bool)
+	go func() {
+		for p := 0; p < P; p++ {
+			s, err := ln.Accept()
+			if err != nil {
+				b.Errorf("Accept failed: %v", err)
+				return
+			}
+			servers[p] = s
+		}
+		done <- true
+	}()
+	for p := 0; p < P; p++ {
+		c, err := net.Dial("tcp", ln.Addr().String())
+		if err != nil {
+			b.Fatalf("Dial failed: %v", err)
+		}
+		clients[p] = c
+	}
+	<-done
+
+	b.StartTimer()
+
+	var wg sync.WaitGroup
+	wg.Add(4 * P)
+	for p := 0; p < P; p++ {
+		// Client writer.
+		go func(c net.Conn) {
+			defer wg.Done()
+			var buf [1]byte
+			for i := 0; i < N; i++ {
+				v := byte(i)
+				for w := 0; w < W; w++ {
+					v *= v
+				}
+				buf[0] = v
+				n, err := c.Write(buf[:])
+				if err != nil {
+					b.Errorf("Write failed: %v", err)
+					return
+				}
+
+				bytesSent.Add(int64(n))
+			}
+		}(clients[p])
+
+		// Pipe between server reader and server writer.
+		pipe := make(chan byte, 128)
+
+		// Server reader.
+		go func(s net.Conn) {
+			defer wg.Done()
+			var buf [1]byte
+			for i := 0; i < N; i++ {
+				n, err := s.Read(buf[:])
+
+				if err != nil {
+					b.Errorf("Read failed: %v", err)
+					return
+				}
+
+				bytesRead.Add(int64(n))
+				pipe <- buf[0]
+			}
+		}(servers[p])
+
+		// Server writer.
+		go func(s net.Conn) {
+			defer wg.Done()
+			var buf [1]byte
+			for i := 0; i < N; i++ {
+				v := <-pipe
+				for w := 0; w < W; w++ {
+					v *= v
+				}
+				buf[0] = v
+				n, err := s.Write(buf[:])
+				if err != nil {
+					b.Errorf("Write failed: %v", err)
+					return
+				}
+
+				bytesSent.Add(int64(n))
+			}
+			s.Close()
+		}(servers[p])
+
+		// Client reader.
+		go func(c net.Conn) {
+			defer wg.Done()
+			var buf [1]byte
+			for i := 0; i < N; i++ {
+				n, err := c.Read(buf[:])
+
+				if err != nil {
+					b.Errorf("Read failed: %v", err)
+					return
+				}
+
+				bytesRead.Add(int64(n))
+			}
+			c.Close()
+		}(clients[p])
+	}
+	wg.Wait()
+}
diff --git a/src/flag/flag.go b/src/flag/flag.go
index 60aef5d..3abc80e 100644
--- a/src/flag/flag.go
+++ b/src/flag/flag.go
@@ -31,7 +31,7 @@
 		fmt.Println("ip has value ", *ip)
 		fmt.Println("flagvar has value ", flagvar)
 
-	After parsing, the arguments after the flag are available as the
+	After parsing, the arguments following the flags are available as the
 	slice flag.Args() or individually as flag.Arg(i).
 	The arguments are indexed from 0 through flag.NArg()-1.
 
@@ -235,6 +235,8 @@ func (d *durationValue) String() string { return (*time.Duration)(d).String() }
 // If a Value has an IsBoolFlag() bool method returning true,
 // the command-line parser makes -name equivalent to -name=true
 // rather than using the next command-line argument.
+//
+// Set is called once, in command line order, for each flag present.
 type Value interface {
 	String() string
 	Set(string) error
@@ -249,13 +251,14 @@ type Getter interface {
 	Get() interface{}
 }
 
-// ErrorHandling defines how to handle flag parsing errors.
+// ErrorHandling defines how FlagSet.Parse behaves if the parse fails.
 type ErrorHandling int
 
+// These constants cause FlagSet.Parse to behave as described if the parse fails.
 const (
-	ContinueOnError ErrorHandling = iota
-	ExitOnError
-	PanicOnError
+	ContinueOnError ErrorHandling = iota // Return a descriptive error.
+	ExitOnError                          // Call os.Exit(2).
+	PanicOnError                         // Call panic with a descriptive error.
 )
 
 // A FlagSet represents a set of defined flags.  The zero value of a FlagSet
@@ -373,20 +376,110 @@ func Set(name, value string) error {
 	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
+		}
+		// 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"
 		}
-		fmt.Fprintf(f.out(), format, flag.Name, flag.DefValue, flag.Usage)
+		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 +501,8 @@ func defaultUsage(f *FlagSet) {
 // 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()
@@ -420,7 +515,8 @@ func (f *FlagSet) NFlag() int { return len(f.actual) }
 func NFlag() int { return len(CommandLine.actual) }
 
 // Arg returns the i'th argument.  Arg(0) is the first remaining argument
-// after flags have been processed.
+// after flags have been processed. Arg returns an empty string if the
+// requested element does not exist.
 func (f *FlagSet) Arg(i int) string {
 	if i < 0 || i >= len(f.args) {
 		return ""
@@ -429,7 +525,8 @@ func (f *FlagSet) Arg(i int) string {
 }
 
 // Arg returns the i'th command-line argument.  Arg(0) is the first remaining argument
-// after flags have been processed.
+// after flags have been processed. Arg returns an empty string if the
+// requested element does not exist.
 func Arg(i int) string {
 	return CommandLine.Arg(i)
 }
@@ -726,27 +823,27 @@ func (f *FlagSet) parseOne() (bool, error) {
 	if len(s) == 0 || s[0] != '-' || len(s) == 1 {
 		return false, nil
 	}
-	num_minuses := 1
+	numMinuses := 1
 	if s[1] == '-' {
-		num_minuses++
+		numMinuses++
 		if len(s) == 2 { // "--" terminates the flags
 			f.args = f.args[1:]
 			return false, nil
 		}
 	}
-	name := s[num_minuses:]
+	name := s[numMinuses:]
 	if len(name) == 0 || name[0] == '-' || name[0] == '=' {
 		return false, f.failf("bad flag syntax: %s", s)
 	}
 
 	// it's a flag. does it have an argument?
 	f.args = f.args[1:]
-	has_value := false
+	hasValue := false
 	value := ""
 	for i := 1; i < len(name); i++ { // equals cannot be first
 		if name[i] == '=' {
 			value = name[i+1:]
-			has_value = true
+			hasValue = true
 			name = name[0:i]
 			break
 		}
@@ -762,21 +859,23 @@ func (f *FlagSet) parseOne() (bool, error) {
 	}
 
 	if fv, ok := flag.Value.(boolFlag); ok && fv.IsBoolFlag() { // special case: doesn't need an arg
-		if has_value {
+		if hasValue {
 			if err := fv.Set(value); err != nil {
 				return false, f.failf("invalid boolean value %q for -%s: %v", value, name, err)
 			}
 		} else {
-			fv.Set("true")
+			if err := fv.Set("true"); err != nil {
+				return false, f.failf("invalid boolean flag %s: %v", name, err)
+			}
 		}
 	} else {
 		// It must have a value, which might be the next argument.
-		if !has_value && len(f.args) > 0 {
+		if !hasValue && len(f.args) > 0 {
 			// value is the next arg
-			has_value = true
+			hasValue = true
 			value, f.args = f.args[0], f.args[1:]
 		}
-		if !has_value {
+		if !hasValue {
 			return false, f.failf("flag needs an argument: -%s", name)
 		}
 		if err := flag.Value.Set(value); err != nil {
@@ -829,7 +928,7 @@ func Parse() {
 	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 @@ func TestHelp(t *testing.T) {
 		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/doc.go b/src/fmt/doc.go
index ee54463..ef91368 100644
--- a/src/fmt/doc.go
+++ b/src/fmt/doc.go
@@ -40,7 +40,7 @@
 		%F	synonym for %f
 		%g	%e for large exponents, %f otherwise
 		%G	%E for large exponents, %F otherwise
-	String and slice of bytes:
+	String and slice of bytes (treated equivalently with these verbs):
 		%s	the uninterpreted bytes of the string or slice
 		%q	a double-quoted string safely escaped with Go syntax
 		%x	base 16, lower-case, two characters per byte
@@ -66,13 +66,13 @@
 		maps:               map[key1:value1 key2:value2]
 		pointer to above:   &{}, &[], &map[]
 
-	Width is specified by an optional decimal number immediately following the verb.
+	Width is specified by an optional decimal number immediately preceding the verb.
 	If absent, the width is whatever is necessary to represent the value.
 	Precision is specified after the (optional) width by a period followed by a
 	decimal number. If no period is present, a default precision is used.
 	A period with no following number specifies a precision of zero.
 	Examples:
-		%f:    default width, default precision
+		%f     default width, default precision
 		%9f    width 9, default precision
 		%.2f   default width, precision 2
 		%9.2f  width 9, precision 2
@@ -138,20 +138,23 @@
 	formatting considerations apply for operands that implement
 	certain interfaces. In order of application:
 
-	1. If an operand implements the Formatter interface, it will
+	1. If the operand is a reflect.Value, the concrete value it
+	holds is printed as if it was the operand.
+
+	2. If an operand implements the Formatter interface, it will
 	be invoked. Formatter provides fine control of formatting.
 
-	2. If the %v verb is used with the # flag (%#v) and the operand
+	3. If the %v verb is used with the # flag (%#v) and the operand
 	implements the GoStringer interface, that will be invoked.
 
 	If the format (which is implicitly %v for Println etc.) is valid
 	for a string (%s %q %v %x %X), the following two rules apply:
 
-	3. If an operand implements the error interface, the Error method
+	4. If an operand implements the error interface, the Error method
 	will be invoked to convert the object to a string, which will then
 	be formatted as required by the verb (if any).
 
-	4. If an operand implements method String() string, that method
+	5. If an operand implements method String() string, that method
 	will be invoked to convert the object to a string, which will then
 	be formatted as required by the verb (if any).
 
@@ -161,6 +164,9 @@
 	of strings, and %6.2f will control formatting for each element
 	of a floating-point array.
 
+	However, when printing a byte slice with a string-like verb
+	(%s %q %x %X), it is treated identically to a string, as a single item.
+
 	To avoid recursion in cases such as
 		type X string
 		func (x X) String() string { return Sprintf("<%s>", x) }
@@ -178,8 +184,8 @@
 	However, the notation [n] immediately before the verb indicates that the
 	nth one-indexed argument is to be formatted instead. The same notation
 	before a '*' for a width or precision selects the argument index holding
-	the value. After processing a bracketed expression [n], arguments n+1,
-	n+2, etc. will be processed unless otherwise directed.
+	the value. After processing a bracketed expression [n], subsequent verbs
+	will use arguments n+1, n+2, etc. unless otherwise directed.
 
 	For example,
 		fmt.Sprintf("%[2]d %[1]d\n", 11, 22)
@@ -225,18 +231,33 @@
 		%!s(PANIC=bad)
 
 	The %!s just shows the print verb in use when the failure
-	occurred.
+	occurred. If the panic is caused by a nil receiver to an Error
+	or String method, however, the output is the undecorated
+	string, "<nil>".
 
 	Scanning
 
 	An analogous set of functions scans formatted text to yield
 	values.  Scan, Scanf and Scanln read from os.Stdin; Fscan,
 	Fscanf and Fscanln read from a specified io.Reader; Sscan,
-	Sscanf and Sscanln read from an argument string.  Scanln,
-	Fscanln and Sscanln stop scanning at a newline and require that
-	the items be followed by one; Scanf, Fscanf and Sscanf require
-	newlines in the input to match newlines in the format; the other
-	routines treat newlines as spaces.
+	Sscanf and Sscanln read from an argument string.
+
+	Scan, Fscan, Sscan treat newlines in the input as spaces.
+
+	Scanln, Fscanln and Sscanln stop scanning at a newline and
+	require that the items be followed by a newline or EOF.
+
+	Scanf, Fscanf and Sscanf require that (after skipping spaces)
+	newlines in the format are matched by newlines in the input
+	and vice versa.  This behavior differs from the corresponding
+	routines in C, which uniformly treat newlines as spaces.
+
+	When scanning with Scanf, Fscanf, and Sscanf, all non-empty
+	runs of space characters (except newline) are equivalent
+	to a single space in both the format and the input.  With
+	that proviso, text in the format string must match the input
+	text; scanning stops if it does not, with the return value
+	of the function indicating the number of arguments scanned.
 
 	Scanf, Fscanf, and Sscanf parse the arguments according to a
 	format string, analogous to that of Printf.  For example, %x
@@ -253,20 +274,18 @@
 		Flags # and + are not implemented.
 
 	The familiar base-setting prefixes 0 (octal) and 0x
-	(hexadecimal) are accepted when scanning integers without a
-	format or with the %v verb.
-
-	Width is interpreted in the input text (%5s means at most
-	five runes of input will be read to scan a string) but there
-	is no syntax for scanning with a precision (no %5.2f, just
-	%5f).
-
-	When scanning with a format, all non-empty runs of space
-	characters (except newline) are equivalent to a single
-	space in both the format and the input.  With that proviso,
-	text in the format string must match the input text; scanning
-	stops if it does not, with the return value of the function
-	indicating the number of arguments scanned.
+	(hexadecimal) are accepted when scanning integers without
+	a format or with the %v verb.
+
+	Width is interpreted in the input text but there is no
+	syntax for scanning with a precision (no %5.2f, just %5f).
+	If width is provided, it applies after leading spaces are
+	trimmed and specifies the maximum number of runes to read
+	to satisfy the verb. For example,
+	   Sscanf(" 1234567 ", "%5s%d", &s, &i)
+	will set s to "12345" and i to 67 while
+	   Sscanf(" 12 34 567 ", "%5s%d", &s, &i)
+	will set s to "12" and i to 34.
 
 	In all the scanning functions, a carriage return followed
 	immediately by a newline is treated as a plain newline
diff --git a/src/fmt/fmt_test.go b/src/fmt/fmt_test.go
index ff5fa79..90a4031 100644
--- a/src/fmt/fmt_test.go
+++ b/src/fmt/fmt_test.go
@@ -9,6 +9,7 @@ import (
 	. "fmt"
 	"io"
 	"math"
+	"reflect"
 	"runtime"
 	"strings"
 	"testing"
@@ -135,27 +136,33 @@ var fmtTests = []struct {
 
 	// 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`"},
@@ -388,6 +395,8 @@ var fmtTests = []struct {
 	{"%v", &slice, "&[1 2 3 4 5]"},
 	{"%v", &islice, "&[1 hello 2.5 <nil>]"},
 	{"%v", &bslice, "&[1 2 3 4 5]"},
+	{"%v", []byte{1}, "[1]"},
+	{"%v", []byte{}, "[]"},
 
 	// complexes with %v
 	{"%v", 1 + 2i, "(1+2i)"},
@@ -441,6 +450,32 @@ var fmtTests = []struct {
 	{"%d", []int{1, 2, 15}, `[1 2 15]`},
 	{"%d", []byte{1, 2, 15}, `[1 2 15]`},
 	{"%q", []string{"a", "b"}, `["a" "b"]`},
+	{"% 02x", []byte{1}, "01"},
+	{"% 02x", []byte{1, 2, 3}, "01 02 03"},
+	// Padding with byte slices.
+	{"%x", []byte{}, ""},
+	{"%02x", []byte{}, "00"},
+	{"% 02x", []byte{}, "00"},
+	{"%08x", []byte{0xab}, "000000ab"},
+	{"% 08x", []byte{0xab}, "000000ab"},
+	{"%08x", []byte{0xab, 0xcd}, "0000abcd"},
+	{"% 08x", []byte{0xab, 0xcd}, "000ab cd"},
+	{"%8x", []byte{0xab}, "      ab"},
+	{"% 8x", []byte{0xab}, "      ab"},
+	{"%8x", []byte{0xab, 0xcd}, "    abcd"},
+	{"% 8x", []byte{0xab, 0xcd}, "   ab cd"},
+	// Same for strings
+	{"%x", "", ""},
+	{"%02x", "", "00"},
+	{"% 02x", "", "00"},
+	{"%08x", "\xab", "000000ab"},
+	{"% 08x", "\xab", "000000ab"},
+	{"%08x", "\xab\xcd", "0000abcd"},
+	{"% 08x", "\xab\xcd", "000ab cd"},
+	{"%8x", "\xab", "      ab"},
+	{"% 8x", "\xab", "      ab"},
+	{"%8x", "\xab\xcd", "    abcd"},
+	{"% 8x", "\xab\xcd", "   ab cd"},
 
 	// renamings
 	{"%v", renamedBool(true), "true"},
@@ -522,6 +557,8 @@ var fmtTests = []struct {
 	{"%s", nil, "%!s(<nil>)"},
 	{"%T", nil, "<nil>"},
 	{"%-1", 100, "%!(NOVERB)%!(EXTRA int=100)"},
+	{"%017091901790959340919092959340919017929593813360", 0, "%!(NOVERB)%!(EXTRA int=0)"},
+	{"%184467440737095516170v", 0, "%!(NOVERB)%!(EXTRA int=0)"},
 
 	// The "<nil>" show up because maps are printed by
 	// first obtaining a list of keys and then looking up
@@ -540,6 +577,15 @@ var fmtTests = []struct {
 	{"%0.100f", 1.0, zeroFill("1.", 100, "")},
 	{"%0.100f", -1.0, zeroFill("-1.", 100, "")},
 
+	// Used to panic: integer function didn't look at f.prec, f.unicode, f.width or sign.
+	{"%#.80x", 42, "0x0000000000000000000000000000000000000000000000000000000000000000000000000000002a"},
+	{"%.80U", 42, "U+0000000000000000000000000000000000000000000000000000000000000000000000000000002A"},
+	{"%#.80U", '日', "U+000000000000000000000000000000000000000000000000000000000000000000000000000065E5 '日'"},
+	{"%.65d", -44, "-00000000000000000000000000000000000000000000000000000000000000044"},
+	{"%+.65d", 44, "+00000000000000000000000000000000000000000000000000000000000000044"},
+	{"% .65d", 44, " 00000000000000000000000000000000000000000000000000000000000000044"},
+	{"%  +.65d", 44, "+00000000000000000000000000000000000000000000000000000000000000044"},
+
 	// Comparison of padding rules with C printf.
 	/*
 		C program:
@@ -665,6 +711,20 @@ var fmtTests = []struct {
 	{"%x", byteFormatterSlice, "61626364"},
 	// This next case seems wrong, but the docs say the Formatter wins here.
 	{"%#v", byteFormatterSlice, "[]fmt_test.byteFormatter{X, X, X, X}"},
+
+	// reflect.Value handled specially in Go 1.5, making it possible to
+	// see inside non-exported fields (which cannot be accessed with Interface()).
+	// Issue 8965.
+	{"%v", reflect.ValueOf(A{}).Field(0).String(), "<int Value>"}, // Equivalent to the old way.
+	{"%v", reflect.ValueOf(A{}).Field(0), "0"},                    // Sees inside the field.
+
+	// verbs apply to the extracted value too.
+	{"%s", reflect.ValueOf("hello"), "hello"},
+	{"%q", reflect.ValueOf("hello"), `"hello"`},
+	{"%#04x", reflect.ValueOf(256), "0x0100"},
+
+	// invalid reflect.Value doesn't crash.
+	{"%v", reflect.Value{}, "<invalid reflect.Value>"},
 }
 
 // zeroFill generates zero-filled strings of the specified width. The length
@@ -791,6 +851,11 @@ var reorderTests = []struct {
 	{"%d %d %d %#[1]o %#o %#o %#o", SE{11, 12, 13}, "11 12 13 013 014 015 %!o(MISSING)"},
 	{"%[5]d %[2]d %d", SE{1, 2, 3}, "%!d(BADINDEX) 2 3"},
 	{"%d %[3]d %d", SE{1, 2}, "1 %!d(BADINDEX) 2"}, // Erroneous index does not affect sequence.
+	{"%.[]", SE{}, "%!](BADINDEX)"},                // Issue 10675
+	{"%.-3d", SE{42}, "%!-(int=42)3d"},             // TODO: Should this set return better error messages?
+	{"%2147483648d", SE{42}, "%!(NOVERB)%!(EXTRA int=42)"},
+	{"%-2147483648d", SE{42}, "%!(NOVERB)%!(EXTRA int=42)"},
+	{"%.2147483648d", SE{42}, "%!(NOVERB)%!(EXTRA int=42)"},
 }
 
 func TestReorder(t *testing.T) {
@@ -869,6 +934,15 @@ func BenchmarkFprintInt(b *testing.B) {
 	}
 }
 
+func BenchmarkFprintfBytes(b *testing.B) {
+	data := []byte(string("0123456789"))
+	var buf bytes.Buffer
+	for i := 0; i < b.N; i++ {
+		buf.Reset()
+		Fprintf(&buf, "%s", data)
+	}
+}
+
 func BenchmarkFprintIntNoAlloc(b *testing.B) {
 	var x interface{} = 123456
 	var buf bytes.Buffer
@@ -903,11 +977,13 @@ var mallocTest = []struct {
 var _ bytes.Buffer
 
 func TestCountMallocs(t *testing.T) {
-	if testing.Short() {
+	switch {
+	case testing.Short():
 		t.Skip("skipping malloc count in short mode")
-	}
-	if runtime.GOMAXPROCS(0) > 1 {
+	case runtime.GOMAXPROCS(0) > 1:
 		t.Skip("skipping; GOMAXPROCS>1")
+	case raceenabled:
+		t.Skip("skipping malloc count under race detector")
 	}
 	for _, mt := range mallocTest {
 		mallocs := testing.AllocsPerRun(100, mt.fn)
@@ -1106,14 +1182,20 @@ var startests = []struct {
 	out string
 }{
 	{"%*d", args(4, 42), "  42"},
+	{"%-*d", args(4, 42), "42  "},
+	{"%*d", args(-4, 42), "42  "},
+	{"%-*d", args(-4, 42), "42  "},
 	{"%.*d", args(4, 42), "0042"},
 	{"%*.*d", args(8, 4, 42), "    0042"},
 	{"%0*d", args(4, 42), "0042"},
-	{"%-*d", args(4, 42), "42  "},
 
 	// erroneous
 	{"%*d", args(nil, 42), "%!(BADWIDTH)42"},
+	{"%*d", args(int(1e7), 42), "%!(BADWIDTH)42"},
+	{"%*d", args(int(-1e7), 42), "%!(BADWIDTH)42"},
 	{"%.*d", args(nil, 42), "%!(BADPREC)42"},
+	{"%.*d", args(-1, 42), "%!(BADPREC)42"},
+	{"%.*d", args(int(1e7), 42), "%!(BADPREC)42"},
 	{"%*d", args(5, "foo"), "%!d(string=  foo)"},
 	{"%*% %d", args(20, 5), "% 5"},
 	{"%*", args(4), "%!(NOVERB)"},
@@ -1231,7 +1313,7 @@ func TestNilDoesNotBecomeTyped(t *testing.T) {
 	type B struct{}
 	var a *A = nil
 	var b B = B{}
-	got := Sprintf("%s %s %s %s %s", nil, a, nil, b, nil)
+	got := Sprintf("%s %s %s %s %s", nil, a, nil, b, nil) // go vet should complain about this line.
 	const expect = "%!s(<nil>) %!s(*fmt_test.A=<nil>) %!s(<nil>) {} %!s(<nil>)"
 	if got != expect {
 		t.Errorf("expected:\n\t%q\ngot:\n\t%q", expect, got)
diff --git a/src/fmt/format.go b/src/fmt/format.go
index 4d97d14..517b18f 100644
--- a/src/fmt/format.go
+++ b/src/fmt/format.go
@@ -162,24 +162,35 @@ func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) {
 		return
 	}
 
+	negative := signedness == signed && a < 0
+	if negative {
+		a = -a
+	}
+
 	var buf []byte = f.intbuf[0:]
-	if f.widPresent {
-		width := f.wid
+	if f.widPresent || f.precPresent || f.plus || f.space {
+		width := f.wid + f.prec // Only one will be set, both are positive; this provides the maximum.
 		if base == 16 && f.sharp {
 			// Also adds "0x".
 			width += 2
 		}
+		if f.unicode {
+			// Also adds "U+".
+			width += 2
+			if f.uniQuote {
+				// Also adds " 'x'".
+				width += 1 + 1 + utf8.UTFMax + 1
+			}
+		}
+		if negative || f.plus || f.space {
+			width++
+		}
 		if width > nByte {
 			// We're going to need a bigger boat.
 			buf = make([]byte, width)
 		}
 	}
 
-	negative := signedness == signed && a < 0
-	if negative {
-		a = -a
-	}
-
 	// two ways to ask for extra leading zero digits: %.3d or %03d.
 	// apparently the first cancels the second.
 	prec := 0
diff --git a/src/fmt/norace_test.go b/src/fmt/norace_test.go
new file mode 100644
index 0000000..1267cc3
--- /dev/null
+++ b/src/fmt/norace_test.go
@@ -0,0 +1,9 @@
+// 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 !race
+
+package fmt_test
+
+const raceenabled = false
diff --git a/src/fmt/print.go b/src/fmt/print.go
index 59a30d2..8d3e97c 100644
--- a/src/fmt/print.go
+++ b/src/fmt/print.go
@@ -285,12 +285,22 @@ func getField(v reflect.Value, i int) reflect.Value {
 	return val
 }
 
+// tooLarge reports whether the magnitude of the integer is
+// too large to be used as a formatting width or precision.
+func tooLarge(x int) bool {
+	const max int = 1e6
+	return x > max || x < -max
+}
+
 // parsenum converts ASCII to integer.  num is 0 (and isnum is false) if no number present.
 func parsenum(s string, start, end int) (num int, isnum bool, newi int) {
 	if start >= end {
 		return 0, false, end
 	}
 	for newi = start; newi < end && '0' <= s[newi] && s[newi] <= '9'; newi++ {
+		if tooLarge(num) {
+			return 0, false, end // Overflow; crazy long number most likely.
+		}
 		num = num*10 + int(s[newi]-'0')
 		isnum = true
 	}
@@ -789,6 +799,8 @@ func (p *pp) printArg(arg interface{}, verb rune, depth int) (wasString bool) {
 	case []byte:
 		p.fmtBytes(f, verb, nil, depth)
 		wasString = verb == 's'
+	case reflect.Value:
+		return p.printReflectValue(f, verb, depth)
 	default:
 		// If the type is not simple, it might have methods.
 		if handled := p.handleMethods(verb, depth); handled {
@@ -845,6 +857,8 @@ func (p *pp) printReflectValue(value reflect.Value, verb rune, depth int) (wasSt
 	p.value = value
 BigSwitch:
 	switch f := value; f.Kind() {
+	case reflect.Invalid:
+		p.buf.WriteString("<invalid reflect.Value>")
 	case reflect.Bool:
 		p.fmtBool(f.Bool(), verb)
 	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
@@ -1016,6 +1030,10 @@ func intFromArg(a []interface{}, argNum int) (num int, isInt bool, newArgNum int
 	if argNum < len(a) {
 		num, isInt = a[argNum].(int)
 		newArgNum = argNum + 1
+		if tooLarge(num) {
+			num = 0
+			isInt = false
+		}
 	}
 	return
 }
@@ -1027,6 +1045,11 @@ func intFromArg(a []interface{}, argNum int) (num int, isInt bool, newArgNum int
 // up to the closing paren, if present, and whether the number parsed
 // ok. The bytes to consume will be 1 if no closing paren is present.
 func parseArgNumber(format string) (index int, wid int, ok bool) {
+	// There must be at least 3 bytes: [n].
+	if len(format) < 3 {
+		return 0, 1, false
+	}
+
 	// Find closing bracket.
 	for i := 1; i < len(format); i++ {
 		if format[i] == ']' {
@@ -1053,7 +1076,7 @@ func (p *pp) argNumber(argNum int, format string, i int, numArgs int) (newArgNum
 		return index, i + wid, true
 	}
 	p.goodArgNum = false
-	return argNum, i + wid, true
+	return argNum, i + wid, ok
 }
 
 func (p *pp) doPrintf(format string, a []interface{}) {
@@ -1105,9 +1128,17 @@ func (p *pp) doPrintf(format string, a []interface{}) {
 		if i < end && format[i] == '*' {
 			i++
 			p.fmt.wid, p.fmt.widPresent, argNum = intFromArg(a, argNum)
+
 			if !p.fmt.widPresent {
 				p.buf.Write(badWidthBytes)
 			}
+
+			// We have a negative width, so take its value and ensure
+			// that the minus flag is set
+			if p.fmt.wid < 0 {
+				p.fmt.wid = -p.fmt.wid
+				p.fmt.minus = true
+			}
 			afterIndex = false
 		} else {
 			p.fmt.wid, p.fmt.widPresent, i = parsenum(format, i, end)
@@ -1123,9 +1154,14 @@ func (p *pp) doPrintf(format string, a []interface{}) {
 				p.goodArgNum = false
 			}
 			argNum, i, afterIndex = p.argNumber(argNum, format, i, len(a))
-			if format[i] == '*' {
+			if i < end && format[i] == '*' {
 				i++
 				p.fmt.prec, p.fmt.precPresent, argNum = intFromArg(a, argNum)
+				// Negative precision arguments don't make sense
+				if p.fmt.prec < 0 {
+					p.fmt.prec = 0
+					p.fmt.precPresent = false
+				}
 				if !p.fmt.precPresent {
 					p.buf.Write(badPrecBytes)
 				}
diff --git a/src/fmt/race_test.go b/src/fmt/race_test.go
new file mode 100644
index 0000000..ae3147a
--- /dev/null
+++ b/src/fmt/race_test.go
@@ -0,0 +1,9 @@
+// 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 race
+
+package fmt_test
+
+const raceenabled = true
diff --git a/src/fmt/scan.go b/src/fmt/scan.go
index d7befea..e3e0fd0 100644
--- a/src/fmt/scan.go
+++ b/src/fmt/scan.go
@@ -34,16 +34,16 @@ type ScanState interface {
 	ReadRune() (r rune, size int, err error)
 	// UnreadRune causes the next call to ReadRune to return the same rune.
 	UnreadRune() error
-	// SkipSpace skips space in the input. Newlines are treated as space
-	// unless the scan operation is Scanln, Fscanln or Sscanln, in which case
-	// a newline is treated as EOF.
+	// SkipSpace skips space in the input. Newlines are treated appropriately
+	// for the operation being performed; see the package documentation
+	// for more information.
 	SkipSpace()
 	// Token skips space in the input if skipSpace is true, then returns the
 	// run of Unicode code points c satisfying f(c).  If f is nil,
 	// !unicode.IsSpace(c) is used; that is, the token will hold non-space
-	// characters.  Newlines are treated as space unless the scan operation
-	// is Scanln, Fscanln or Sscanln, in which case a newline is treated as
-	// EOF.  The returned slice points to shared data that may be overwritten
+	// characters.  Newlines are treated appropriately for the operation being
+	// performed; see the package documentation for more information.
+	// The returned slice points to shared data that may be overwritten
 	// by the next call to Token, a call to a Scan function using the ScanState
 	// as input, or when the calling Scan method returns.
 	Token(skipSpace bool, f func(rune) bool) (token []byte, err error)
@@ -81,6 +81,10 @@ func Scanln(a ...interface{}) (n int, err error) {
 // Scanf scans text read from standard input, storing successive
 // space-separated values into successive arguments as determined by
 // the format.  It returns the number of items successfully scanned.
+// If that is less than the number of arguments, err will report why.
+// Newlines in the input must match newlines in the format.
+// The one exception: the verb %c always scans the next rune in the
+// input, even if it is a space (or tab etc.) or newline.
 func Scanf(format string, a ...interface{}) (n int, err error) {
 	return Fscanf(os.Stdin, format, a...)
 }
@@ -113,6 +117,7 @@ func Sscanln(str string, a ...interface{}) (n int, err error) {
 // Sscanf scans the argument string, storing successive space-separated
 // values into successive arguments as determined by the format.  It
 // returns the number of items successfully parsed.
+// Newlines in the input must match newlines in the format.
 func Sscanf(str string, format string, a ...interface{}) (n int, err error) {
 	return Fscanf((*stringReader)(&str), format, a...)
 }
@@ -140,6 +145,7 @@ func Fscanln(r io.Reader, a ...interface{}) (n int, err error) {
 // Fscanf scans text read from r, storing successive space-separated
 // values into successive arguments as determined by the format.  It
 // returns the number of items successfully parsed.
+// Newlines in the input must match newlines in the format.
 func Fscanf(r io.Reader, format string, a ...interface{}) (n int, err error) {
 	s, old := newScanState(r, false, false)
 	n, err = s.doScanf(format, a)
@@ -387,17 +393,6 @@ var ssFree = sync.Pool{
 
 // newScanState allocates a new ss struct or grab a cached one.
 func newScanState(r io.Reader, nlIsSpace, nlIsEnd bool) (s *ss, old ssave) {
-	// If the reader is a *ss, then we've got a recursive
-	// call to Scan, so re-use the scan state.
-	s, ok := r.(*ss)
-	if ok {
-		old = s.ssave
-		s.limit = s.argLimit
-		s.nlIsEnd = nlIsEnd || s.nlIsEnd
-		s.nlIsSpace = nlIsSpace
-		return
-	}
-
 	s = ssFree.Get().(*ss)
 	if rr, ok := r.(io.RuneReader); ok {
 		s.rr = rr
@@ -875,34 +870,39 @@ func (s *ss) quotedString() string {
 	return ""
 }
 
-// hexDigit returns the value of the hexadecimal digit
-func (s *ss) hexDigit(d rune) int {
+// hexDigit returns the value of the hexadecimal digit.
+func hexDigit(d rune) (int, bool) {
 	digit := int(d)
 	switch digit {
 	case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
-		return digit - '0'
+		return digit - '0', true
 	case 'a', 'b', 'c', 'd', 'e', 'f':
-		return 10 + digit - 'a'
+		return 10 + digit - 'a', true
 	case 'A', 'B', 'C', 'D', 'E', 'F':
-		return 10 + digit - 'A'
+		return 10 + digit - 'A', true
 	}
-	s.errorString("illegal hex digit")
-	return 0
+	return -1, false
 }
 
 // hexByte returns the next hex-encoded (two-character) byte from the input.
-// There must be either two hexadecimal digits or a space character in the input.
+// It returns ok==false if the next bytes in the input do not encode a hex byte.
+// If the first byte is hex and the second is not, processing stops.
 func (s *ss) hexByte() (b byte, ok bool) {
 	rune1 := s.getRune()
 	if rune1 == eof {
 		return
 	}
-	if isSpace(rune1) {
+	value1, ok := hexDigit(rune1)
+	if !ok {
 		s.UnreadRune()
 		return
 	}
-	rune2 := s.mustReadRune()
-	return byte(s.hexDigit(rune1)<<4 | s.hexDigit(rune2)), true
+	value2, ok := hexDigit(s.mustReadRune())
+	if !ok {
+		s.errorString("illegal hex digit")
+		return
+	}
+	return byte(value1<<4 | value2), true
 }
 
 // hexString returns the space-delimited hexpair-encoded string.
@@ -1050,8 +1050,8 @@ func (s *ss) doScan(a []interface{}) (numProcessed int, err error) {
 		s.scanOne('v', arg)
 		numProcessed++
 	}
-	// Check for newline if required.
-	if !s.nlIsSpace {
+	// Check for newline (or EOF) if required (Scanln etc.).
+	if s.nlIsEnd {
 		for {
 			r := s.getRune()
 			if r == '\n' || r == eof {
@@ -1067,12 +1067,13 @@ func (s *ss) doScan(a []interface{}) (numProcessed int, err error) {
 }
 
 // advance determines whether the next characters in the input match
-// those of the format.  It returns the number of bytes (sic) consumed
-// in the format. Newlines included, all runs of space characters in
-// either input or format behave as a single space. This routine also
-// handles the %% case.  If the return value is zero, either format
-// starts with a % (with no following %) or the input is empty.
-// If it is negative, the input did not match the string.
+// those of the format. It returns the number of bytes (sic) consumed
+// in the format. All runs of space characters in either input or
+// format behave as a single space. Newlines are special, though:
+// newlines in the format must match those in the input and vice versa.
+// This routine also handles the %% case. If the return value is zero,
+// either format starts with a % (with no following %) or the input
+// is empty. If it is negative, the input did not match the string.
 func (s *ss) advance(format string) (i int) {
 	for i < len(format) {
 		fmtc, w := utf8.DecodeRuneInString(format[i:])
@@ -1085,24 +1086,45 @@ func (s *ss) advance(format string) (i int) {
 			i += w // skip the first %
 		}
 		sawSpace := false
+		wasNewline := false
+		// Skip spaces in format but absorb at most one newline.
 		for isSpace(fmtc) && i < len(format) {
+			if fmtc == '\n' {
+				if wasNewline { // Already saw one; stop here.
+					break
+				}
+				wasNewline = true
+			}
 			sawSpace = true
 			i += w
 			fmtc, w = utf8.DecodeRuneInString(format[i:])
 		}
 		if sawSpace {
-			// There was space in the format, so there should be space (EOF)
+			// There was space in the format, so there should be space
 			// in the input.
 			inputc := s.getRune()
-			if inputc == eof || inputc == '\n' {
-				// If we've reached a newline, stop now; don't read ahead.
+			if inputc == eof {
 				return
 			}
 			if !isSpace(inputc) {
-				// Space in format but not in input: error
+				// Space in format but not in input.
 				s.errorString("expected space in input to match format")
 			}
-			s.skipSpace(true)
+			// Skip spaces but stop at newline.
+			for inputc != '\n' && isSpace(inputc) {
+				inputc = s.getRune()
+			}
+			if inputc == '\n' {
+				if !wasNewline {
+					s.errorString("newline in input does not match format")
+				}
+				// We've reached a newline, stop now; don't read further.
+				return
+			}
+			s.UnreadRune()
+			if wasNewline {
+				s.errorString("newline in format does not match input")
+			}
 			continue
 		}
 		inputc := s.mustReadRune()
@@ -1144,14 +1166,18 @@ func (s *ss) doScanf(format string, a []interface{}) (numProcessed int, err erro
 		if !widPresent {
 			s.maxWid = hugeWid
 		}
+
+		c, w := utf8.DecodeRuneInString(format[i:])
+		i += w
+
+		if c != 'c' {
+			s.SkipSpace()
+		}
 		s.argLimit = s.limit
 		if f := s.count + s.maxWid; f < s.argLimit {
 			s.argLimit = f
 		}
 
-		c, w := utf8.DecodeRuneInString(format[i:])
-		i += w
-
 		if numProcessed >= len(a) { // out of operands
 			s.errorString("too few operands for format %" + format[i-w:])
 			break
diff --git a/src/fmt/scan_test.go b/src/fmt/scan_test.go
index 541e12d..334c4a6 100644
--- a/src/fmt/scan_test.go
+++ b/src/fmt/scan_test.go
@@ -300,10 +300,13 @@ var scanfTests = []ScanfTest{
 	{"%2s", "sssss", &xVal, Xs("ss")},
 
 	// Fixed bugs
-	{"%d\n", "27\n", &intVal, 27},  // ok
-	{"%d\n", "28 \n", &intVal, 28}, // was: "unexpected newline"
-	{"%v", "0", &intVal, 0},        // was: "EOF"; 0 was taken as base prefix and not counted.
-	{"%v", "0", &uintVal, uint(0)}, // was: "EOF"; 0 was taken as base prefix and not counted.
+	{"%d\n", "27\n", &intVal, 27},      // ok
+	{"%d\n", "28 \n", &intVal, 28},     // was: "unexpected newline"
+	{"%v", "0", &intVal, 0},            // was: "EOF"; 0 was taken as base prefix and not counted.
+	{"%v", "0", &uintVal, uint(0)},     // was: "EOF"; 0 was taken as base prefix and not counted.
+	{"%c", " ", &uintVal, uint(' ')},   // %c must accept a blank.
+	{"%c", "\t", &uintVal, uint('\t')}, // %c must accept any space.
+	{"%c", "\n", &uintVal, uint('\n')}, // %c must accept any space.
 }
 
 var overflowTests = []ScanTest{
@@ -340,6 +343,8 @@ var multiTests = []ScanfMultiTest{
 	{"%6vX=%3fY", "3+2iX=2.5Y", args(&c, &f), args((3 + 2i), 2.5), ""},
 	{"%d%s", "123abc", args(&i, &s), args(123, "abc"), ""},
 	{"%c%c%c", "2\u50c2X", args(&r1, &r2, &r3), args('2', '\u50c2', 'X'), ""},
+	{"%5s%d", " 1234567 ", args(&s, &i), args("12345", 67), ""},
+	{"%5s%d", " 12 34 567 ", args(&s, &i), args("12", 34), ""},
 
 	// Custom scanners.
 	{"%e%f", "eefffff", args(&x, &y), args(Xs("ee"), Xs("fffff")), ""},
@@ -864,7 +869,7 @@ func TestScanStateCount(t *testing.T) {
 		t.Fatal(err)
 	}
 	if n != 3 {
-		t.Fatalf("expected 3 items consumed, got %d")
+		t.Fatalf("expected 3 items consumed, got %d", n)
 	}
 	if a.rune != '1' || b.rune != '2' || c.rune != '➂' {
 		t.Errorf("bad scan rune: %q %q %q should be '1' '2' '➂'", a.rune, b.rune, c.rune)
@@ -990,3 +995,167 @@ func BenchmarkScanRecursiveInt(b *testing.B) {
 		b.StopTimer()
 	}
 }
+
+// Issue 9124.
+// %x on bytes couldn't handle non-space bytes terminating the scan.
+func TestHexBytes(t *testing.T) {
+	var a, b []byte
+	n, err := Sscanf("00010203", "%x", &a)
+	if n != 1 || err != nil {
+		t.Errorf("simple: got count, err = %d, %v; expected 1, nil", n, err)
+	}
+	check := func(msg string, x []byte) {
+		if len(x) != 4 {
+			t.Errorf("%s: bad length %d", msg, len(x))
+		}
+		for i, b := range x {
+			if int(b) != i {
+				t.Errorf("%s: bad x[%d] = %x", msg, i, x[i])
+			}
+		}
+	}
+	check("simple", a)
+	a = nil
+
+	n, err = Sscanf("00010203 00010203", "%x %x", &a, &b)
+	if n != 2 || err != nil {
+		t.Errorf("simple pair: got count, err = %d, %v; expected 2, nil", n, err)
+	}
+	check("simple pair a", a)
+	check("simple pair b", b)
+	a = nil
+	b = nil
+
+	n, err = Sscanf("00010203:", "%x", &a)
+	if n != 1 || err != nil {
+		t.Errorf("colon: got count, err = %d, %v; expected 1, nil", n, err)
+	}
+	check("colon", a)
+	a = nil
+
+	n, err = Sscanf("00010203:00010203", "%x:%x", &a, &b)
+	if n != 2 || err != nil {
+		t.Errorf("colon pair: got count, err = %d, %v; expected 2, nil", n, err)
+	}
+	check("colon pair a", a)
+	check("colon pair b", b)
+	a = nil
+	b = nil
+
+	// This one fails because there is a hex byte after the data,
+	// that is, an odd number of hex input bytes.
+	n, err = Sscanf("000102034:", "%x", &a)
+	if n != 0 || err == nil {
+		t.Errorf("odd count: got count, err = %d, %v; expected 0, error", n, err)
+	}
+}
+
+func TestScanNewlinesAreSpaces(t *testing.T) {
+	var a, b int
+	var tests = []struct {
+		name  string
+		text  string
+		count int
+	}{
+		{"newlines", "1\n2\n", 2},
+		{"no final newline", "1\n2", 2},
+		{"newlines with spaces ", "1  \n  2  \n", 2},
+		{"no final newline with spaces", "1  \n  2", 2},
+	}
+	for _, test := range tests {
+		n, err := Sscan(test.text, &a, &b)
+		if n != test.count {
+			t.Errorf("%s: expected to scan %d item(s), scanned %d", test.name, test.count, n)
+		}
+		if err != nil {
+			t.Errorf("%s: unexpected error: %s", test.name, err)
+		}
+	}
+}
+
+func TestScanlnNewlinesTerminate(t *testing.T) {
+	var a, b int
+	var tests = []struct {
+		name  string
+		text  string
+		count int
+		ok    bool
+	}{
+		{"one line one item", "1\n", 1, false},
+		{"one line two items with spaces ", "   1 2    \n", 2, true},
+		{"one line two items no newline", "   1 2", 2, true},
+		{"two lines two items", "1\n2\n", 1, false},
+	}
+	for _, test := range tests {
+		n, err := Sscanln(test.text, &a, &b)
+		if n != test.count {
+			t.Errorf("%s: expected to scan %d item(s), scanned %d", test.name, test.count, n)
+		}
+		if test.ok && err != nil {
+			t.Errorf("%s: unexpected error: %s", test.name, err)
+		}
+		if !test.ok && err == nil {
+			t.Errorf("%s: expected error; got none", test.name)
+		}
+	}
+}
+
+func TestScanfNewlineMatchFormat(t *testing.T) {
+	var a, b int
+	var tests = []struct {
+		name   string
+		text   string
+		format string
+		count  int
+		ok     bool
+	}{
+		{"newline in both", "1\n2", "%d\n%d\n", 2, true},
+		{"newline in input", "1\n2", "%d %d", 1, false},
+		{"space-newline in input", "1 \n2", "%d %d", 1, false},
+		{"newline in format", "1 2", "%d\n%d", 1, false},
+		{"space-newline in format", "1 2", "%d \n%d", 1, false},
+		{"space-newline in both", "1 \n2", "%d \n%d", 2, true},
+		{"extra space in format", "1\n2", "%d\n %d", 2, true},
+		{"two extra spaces in format", "1\n2", "%d \n %d", 2, true},
+	}
+	for _, test := range tests {
+		n, err := Sscanf(test.text, test.format, &a, &b)
+		if n != test.count {
+			t.Errorf("%s: expected to scan %d item(s), scanned %d", test.name, test.count, n)
+		}
+		if test.ok && err != nil {
+			t.Errorf("%s: unexpected error: %s", test.name, err)
+		}
+		if !test.ok && err == nil {
+			t.Errorf("%s: expected error; got none", test.name)
+		}
+	}
+}
+
+// Test for issue 12090: Was unreading at EOF, double-scanning a byte.
+
+type hexBytes [2]byte
+
+func (h *hexBytes) Scan(ss ScanState, verb rune) error {
+	var b []byte
+	_, err := Fscanf(ss, "%4x", &b)
+	if err != nil {
+		panic(err) // Really shouldn't happen.
+	}
+	copy((*h)[:], b)
+	return err
+}
+
+func TestHexByte(t *testing.T) {
+	var h hexBytes
+	n, err := Sscanln("0123\n", &h)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if n != 1 {
+		t.Fatalf("expected 1 item; scanned %d", n)
+	}
+	if h[0] != 0x01 || h[1] != 0x23 {
+		t.Fatalf("expected 0123 got %x", h)
+	}
+}
diff --git a/src/go/ast/ast.go b/src/go/ast/ast.go
index 312e3d1..5ab4283 100644
--- a/src/go/ast/ast.go
+++ b/src/go/ast/ast.go
@@ -486,7 +486,7 @@ func (x *MapType) End() token.Pos       { return x.Value.End() }
 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()          {}
@@ -562,10 +562,11 @@ type (
 
 	// An EmptyStmt node represents an empty statement.
 	// The "position" of the empty statement is the position
-	// of the immediately preceding semicolon.
+	// of the immediately following (explicit or implicit) semicolon.
 	//
 	EmptyStmt struct {
-		Semicolon token.Pos // position of preceding ";"
+		Semicolon token.Pos // position of following ";"
+		Implicit  bool      // if set, ";" was omitted in the source
 	}
 
 	// A LabeledStmt node represents a labeled statement.
@@ -734,6 +735,9 @@ func (s *RangeStmt) Pos() token.Pos      { return s.For }
 func (s *BadStmt) End() token.Pos  { return s.To }
 func (s *DeclStmt) End() token.Pos { return s.Decl.End() }
 func (s *EmptyStmt) End() token.Pos {
+	if s.Implicit {
+		return s.Semicolon
+	}
 	return s.Semicolon + 1 /* len(";") */
 }
 func (s *LabeledStmt) End() token.Pos { return s.Stmt.End() }
@@ -783,7 +787,7 @@ func (s *ForStmt) End() token.Pos    { return s.Body.End() }
 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()       {}
@@ -947,7 +951,7 @@ func (d *FuncDecl) End() token.Pos {
 }
 
 // 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 fc3eeb4..bb57116 100644
--- a/src/go/ast/filter.go
+++ b/src/go/ast/filter.go
@@ -23,8 +23,7 @@ func exportFilter(name string) bool {
 // 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 @@ func FileExports(src *File) bool {
 // 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 @@ func filterSpecList(list []Spec, f Filter, export bool) []Spec {
 // 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)
@@ -221,11 +220,11 @@ func filterDecl(decl Decl, f Filter, export bool) bool {
 // names from top-level declarations (including struct field and
 // interface method names, but not from parameter lists) that don't
 // pass through the filter f. If the declaration is empty afterwards,
-// the declaration is removed from the AST. The File.Comments list
-// is not changed.
+// 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 @@ func filterFile(src *File, f Filter, export bool) bool {
 // 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 @@ func (s *Scope) Lookup(name string) *Object {
 // 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/ast/walk.go b/src/go/ast/walk.go
index 73ac386..8ca2195 100644
--- a/src/go/ast/walk.go
+++ b/src/go/ast/walk.go
@@ -361,8 +361,7 @@ func Walk(v Visitor, node Node) {
 		}
 
 	default:
-		fmt.Printf("ast.Walk: unexpected node type %T", n)
-		panic("ast.Walk")
+		panic(fmt.Sprintf("ast.Walk: unexpected node type %T", n))
 	}
 
 	v.Visit(nil)
@@ -379,7 +378,8 @@ func (f inspector) Visit(node Node) Visitor {
 
 // Inspect traverses an AST in depth-first order: It starts by calling
 // f(node); node must not be nil. If f returns true, Inspect invokes f
-// for all the non-nil children of node, recursively.
+// recursively for each of the non-nil children of node, followed by a
+// call of f(nil).
 //
 func Inspect(node Node, f func(Node) bool) {
 	Walk(inspector(f), node)
diff --git a/src/go/build/build.go b/src/go/build/build.go
index 311ecb0..496fe11 100644
--- a/src/go/build/build.go
+++ b/src/go/build/build.go
@@ -256,10 +256,12 @@ func (ctxt *Context) SrcDirs() []string {
 // if set, or else the compiled code's GOARCH, GOOS, and GOROOT.
 var Default Context = defaultContext()
 
+// Also known to cmd/dist/build.go.
 var cgoEnabled = map[string]bool{
 	"darwin/386":      true,
 	"darwin/amd64":    true,
-	"dragonfly/386":   true,
+	"darwin/arm":      true,
+	"darwin/arm64":    true,
 	"dragonfly/amd64": true,
 	"freebsd/386":     true,
 	"freebsd/amd64":   true,
@@ -267,6 +269,8 @@ var cgoEnabled = map[string]bool{
 	"linux/386":       true,
 	"linux/amd64":     true,
 	"linux/arm":       true,
+	"linux/arm64":     true,
+	"linux/ppc64le":   true,
 	"android/386":     true,
 	"android/amd64":   true,
 	"android/arm":     true,
@@ -275,6 +279,7 @@ var cgoEnabled = map[string]bool{
 	"netbsd/arm":      true,
 	"openbsd/386":     true,
 	"openbsd/amd64":   true,
+	"solaris/amd64":   true,
 	"windows/386":     true,
 	"windows/amd64":   true,
 }
@@ -293,11 +298,7 @@ func defaultContext() Context {
 	// in all releases >= Go 1.x. Code that requires Go 1.x or later should
 	// say "+build go1.x", and code that should only be built before Go 1.x
 	// (perhaps it is the stub to use in that case) should say "+build !go1.x".
-	//
-	// When we reach Go 1.5 the line will read
-	//	c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3", "go1.4", "go1.5"}
-	// and so on.
-	c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3", "go1.4"}
+	c.ReleaseTags = []string{"go1.1", "go1.2", "go1.3", "go1.4", "go1.5"}
 
 	switch os.Getenv("CGO_ENABLED") {
 	case "1":
@@ -354,6 +355,7 @@ type Package struct {
 	Root          string   // root of Go tree where this package lives
 	SrcRoot       string   // package source root directory ("" if unknown)
 	PkgRoot       string   // package install root directory ("" if unknown)
+	PkgTargetRoot string   // architecture dependent install root directory ("" if unknown)
 	BinDir        string   // command install directory ("" if unknown)
 	Goroot        bool     // package found in Go root
 	PkgObj        string   // installed .a file
@@ -462,18 +464,21 @@ func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Packa
 		return p, fmt.Errorf("import %q: invalid import path", path)
 	}
 
+	var pkgtargetroot string
 	var pkga string
 	var pkgerr error
+	suffix := ""
+	if ctxt.InstallSuffix != "" {
+		suffix = "_" + ctxt.InstallSuffix
+	}
 	switch ctxt.Compiler {
 	case "gccgo":
+		pkgtargetroot = "pkg/gccgo_" + ctxt.GOOS + "_" + ctxt.GOARCH + suffix
 		dir, elem := pathpkg.Split(p.ImportPath)
-		pkga = "pkg/gccgo_" + ctxt.GOOS + "_" + ctxt.GOARCH + "/" + dir + "lib" + elem + ".a"
+		pkga = pkgtargetroot + "/" + dir + "lib" + elem + ".a"
 	case "gc":
-		suffix := ""
-		if ctxt.InstallSuffix != "" {
-			suffix = "_" + ctxt.InstallSuffix
-		}
-		pkga = "pkg/" + ctxt.GOOS + "_" + ctxt.GOARCH + suffix + "/" + p.ImportPath + ".a"
+		pkgtargetroot = "pkg/" + ctxt.GOOS + "_" + ctxt.GOARCH + suffix
+		pkga = pkgtargetroot + "/" + p.ImportPath + ".a"
 	default:
 		// Save error for end of function.
 		pkgerr = fmt.Errorf("import %q: unknown compiler %q", path, ctxt.Compiler)
@@ -489,9 +494,13 @@ func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Packa
 			p.Dir = ctxt.joinPath(srcDir, path)
 		}
 		// Determine canonical import path, if any.
+		// Exclude results where the import path would include /testdata/.
+		inTestdata := func(sub string) bool {
+			return strings.Contains(sub, "/testdata/") || strings.HasSuffix(sub, "/testdata") || strings.HasPrefix(sub, "testdata/") || sub == "testdata"
+		}
 		if ctxt.GOROOT != "" {
 			root := ctxt.joinPath(ctxt.GOROOT, "src")
-			if sub, ok := ctxt.hasSubdir(root, p.Dir); ok {
+			if sub, ok := ctxt.hasSubdir(root, p.Dir); ok && !inTestdata(sub) {
 				p.Goroot = true
 				p.ImportPath = sub
 				p.Root = ctxt.GOROOT
@@ -501,7 +510,7 @@ func (ctxt *Context) Import(path string, srcDir string, mode ImportMode) (*Packa
 		all := ctxt.gopath()
 		for i, root := range all {
 			rootsrc := ctxt.joinPath(root, "src")
-			if sub, ok := ctxt.hasSubdir(rootsrc, p.Dir); ok {
+			if sub, ok := ctxt.hasSubdir(rootsrc, p.Dir); ok && !inTestdata(sub) {
 				// We found a potential import path for dir,
 				// but check that using it wouldn't find something
 				// else first.
@@ -590,6 +599,7 @@ Found:
 		p.PkgRoot = ctxt.joinPath(p.Root, "pkg")
 		p.BinDir = ctxt.joinPath(p.Root, "bin")
 		if pkga != "" {
+			p.PkgTargetRoot = ctxt.joinPath(p.Root, pkgtargetroot)
 			p.PkgObj = ctxt.joinPath(p.Root, pkga)
 		}
 	}
@@ -688,7 +698,11 @@ Found:
 			p.Name = pkg
 			firstFile = name
 		} else if pkg != p.Name {
-			return p, &MultiplePackageError{p.Dir, []string{firstFile, name}, []string{p.Name, pkg}}
+			return p, &MultiplePackageError{
+				Dir:      p.Dir,
+				Packages: []string{p.Name, pkg},
+				Files:    []string{firstFile, name},
+			}
 		}
 		if pf.Doc != nil && p.Doc == "" {
 			p.Doc = doc.Synopsis(pf.Doc.Text())
@@ -955,7 +969,7 @@ func (ctxt *Context) matchFile(dir, name string, returnImports bool, allTags map
 	}
 
 	if strings.HasSuffix(filename, ".go") {
-		data, err = readImports(f, false)
+		data, err = readImports(f, false, nil)
 	} else {
 		data, err = readComments(f)
 	}
@@ -1068,9 +1082,6 @@ func (ctxt *Context) shouldBuild(content []byte, allTags map[string]bool) bool {
 // saveCgo saves the information from the #cgo lines in the import "C" comment.
 // These lines set CFLAGS, CPPFLAGS, CXXFLAGS and LDFLAGS and pkg-config directives
 // that affect the way cgo's C code is built.
-//
-// TODO(rsc): This duplicates code in cgo.
-// Once the dust settles, remove this code from cgo.
 func (ctxt *Context) saveCgo(filename string, di *Package, cg *ast.CommentGroup) error {
 	text := cg.Text()
 	for _, line := range strings.Split(text, "\n") {
@@ -1116,10 +1127,12 @@ func (ctxt *Context) saveCgo(filename string, di *Package, cg *ast.CommentGroup)
 		if err != nil {
 			return fmt.Errorf("%s: invalid #cgo line: %s", filename, orig)
 		}
-		for _, arg := range args {
+		for i, arg := range args {
+			arg = expandSrcDir(arg, di.Dir)
 			if !safeCgoName(arg) {
 				return fmt.Errorf("%s: malformed #cgo argument: %s", filename, arg)
 			}
+			args[i] = arg
 		}
 
 		switch verb {
@@ -1140,6 +1153,14 @@ func (ctxt *Context) saveCgo(filename string, di *Package, cg *ast.CommentGroup)
 	return nil
 }
 
+func expandSrcDir(str string, srcdir string) string {
+	// "\" delimited paths cause safeCgoName to fail
+	// so convert native paths with a different delimeter
+	// to "/" before starting (eg: on windows)
+	srcdir = filepath.ToSlash(srcdir)
+	return strings.Replace(str, "${SRCDIR}", srcdir, -1)
+}
+
 // NOTE: $ is not safe for the shell, but it is allowed here because of linker options like -Wl,$ORIGIN.
 // We never pass these arguments to a shell (just to programs we construct argv for), so this should be okay.
 // See golang.org/issue/6038.
@@ -1218,7 +1239,7 @@ func splitQuoted(s string) (r []string, err error) {
 	return args, err
 }
 
-// match returns true if the name is one of:
+// match reports whether the name is one of:
 //
 //	$GOOS
 //	$GOARCH
@@ -1309,7 +1330,7 @@ func (ctxt *Context) goodOSArchFile(name string, allTags map[string]bool) bool {
 	// build tag "linux" in that file. For Go 1.4 and beyond, we require this
 	// auto-tagging to apply only to files with a non-empty prefix, so
 	// "foo_linux.go" is tagged but "linux.go" is not. This allows new operating
-	// sytems, such as android, to arrive without breaking existing code with
+	// systems, such as android, to arrive without breaking existing code with
 	// innocuous source code in "android.go". The easiest fix: cut everything
 	// in the name before the initial _.
 	i := strings.Index(name, "_")
@@ -1376,16 +1397,11 @@ func IsLocalImport(path string) bool {
 		strings.HasPrefix(path, "./") || strings.HasPrefix(path, "../")
 }
 
-// ArchChar returns the architecture character for the given goarch.
-// For example, ArchChar("amd64") returns "6".
+// ArchChar returns "?" and an error.
+// In earlier versions of Go, the returned string was used to derive
+// the compiler and linker tool names, the default object file suffix,
+// and the default linker output name. As of Go 1.5, those strings
+// no longer vary by architecture; they are compile, link, .o, and a.out, respectively.
 func ArchChar(goarch string) (string, error) {
-	switch goarch {
-	case "386":
-		return "8", nil
-	case "amd64", "amd64p32":
-		return "6", nil
-	case "arm":
-		return "5", nil
-	}
-	return "", errors.New("unsupported GOARCH " + goarch)
+	return "?", errors.New("architecture letter no longer used")
 }
diff --git a/src/go/build/build_test.go b/src/go/build/build_test.go
index a40def0..92c3fe3 100644
--- a/src/go/build/build_test.go
+++ b/src/go/build/build_test.go
@@ -94,12 +94,28 @@ func TestEmptyFolderImport(t *testing.T) {
 
 func TestMultiplePackageImport(t *testing.T) {
 	_, err := Import(".", "testdata/multi", 0)
-	if _, ok := err.(*MultiplePackageError); !ok {
+	mpe, ok := err.(*MultiplePackageError)
+	if !ok {
 		t.Fatal(`Import("testdata/multi") did not return MultiplePackageError.`)
 	}
+	want := &MultiplePackageError{
+		Dir:      filepath.FromSlash("testdata/multi"),
+		Packages: []string{"main", "test_package"},
+		Files:    []string{"file.go", "file_appengine.go"},
+	}
+	if !reflect.DeepEqual(mpe, want) {
+		t.Errorf("got %#v; want %#v", mpe, want)
+	}
 }
 
 func TestLocalDirectory(t *testing.T) {
+	if runtime.GOOS == "darwin" {
+		switch runtime.GOARCH {
+		case "arm", "arm64":
+			t.Skipf("skipping on %s/%s, no valid GOROOT", runtime.GOOS, runtime.GOARCH)
+		}
+	}
+
 	cwd, err := os.Getwd()
 	if err != nil {
 		t.Fatal(err)
@@ -214,6 +230,13 @@ func TestMatchFile(t *testing.T) {
 }
 
 func TestImportCmd(t *testing.T) {
+	if runtime.GOOS == "darwin" {
+		switch runtime.GOARCH {
+		case "arm", "arm64":
+			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)
@@ -222,3 +245,33 @@ func TestImportCmd(t *testing.T) {
 		t.Fatalf("Import cmd/internal/objfile returned Dir=%q, want %q", filepath.ToSlash(p.Dir), ".../src/cmd/internal/objfile")
 	}
 }
+
+var (
+	expandSrcDirPath = filepath.Join(string(filepath.Separator)+"projects", "src", "add")
+)
+
+var expandSrcDirTests = []struct {
+	input, expected string
+}{
+	{"-L ${SRCDIR}/libs -ladd", "-L /projects/src/add/libs -ladd"},
+	{"${SRCDIR}/add_linux_386.a -pthread -lstdc++", "/projects/src/add/add_linux_386.a -pthread -lstdc++"},
+	{"Nothing to expand here!", "Nothing to expand here!"},
+	{"$", "$"},
+	{"$$", "$$"},
+	{"${", "${"},
+	{"$}", "$}"},
+	{"$FOO ${BAR}", "$FOO ${BAR}"},
+	{"Find me the $SRCDIRECTORY.", "Find me the $SRCDIRECTORY."},
+	{"$SRCDIR is missing braces", "$SRCDIR is missing braces"},
+}
+
+func TestExpandSrcDir(t *testing.T) {
+	for _, test := range expandSrcDirTests {
+		output := expandSrcDir(test.input, expandSrcDirPath)
+		if output != test.expected {
+			t.Errorf("%q expands to %q with SRCDIR=%q when %q is expected", test.input, output, expandSrcDirPath, test.expected)
+		} else {
+			t.Logf("%q expands to %q with SRCDIR=%q", test.input, output, expandSrcDirPath)
+		}
+	}
+}
diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go
index b74595e..7cea949 100644
--- a/src/go/build/deps_test.go
+++ b/src/go/build/deps_test.go
@@ -8,8 +8,15 @@
 package build
 
 import (
+	"bytes"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"path/filepath"
 	"runtime"
 	"sort"
+	"strconv"
+	"strings"
 	"testing"
 )
 
@@ -121,9 +128,12 @@ var pkgDeps = map[string][]string{
 	// End of linear dependency definitions.
 
 	// Operating system access.
-	"syscall":       {"L0", "unicode/utf16"},
-	"time":          {"L0", "syscall"},
-	"os":            {"L1", "os", "syscall", "time"},
+	"syscall":                           {"L0", "unicode/utf16"},
+	"internal/syscall/unix":             {"L0", "syscall"},
+	"internal/syscall/windows":          {"L0", "syscall"},
+	"internal/syscall/windows/registry": {"L0", "syscall", "unicode/utf16"},
+	"time":          {"L0", "syscall", "internal/syscall/windows/registry"},
+	"os":            {"L1", "os", "syscall", "time", "internal/syscall/windows"},
 	"path/filepath": {"L2", "os", "syscall"},
 	"io/ioutil":     {"L2", "os", "path/filepath", "time"},
 	"os/exec":       {"L2", "os", "path/filepath", "syscall"},
@@ -148,11 +158,13 @@ var pkgDeps = map[string][]string{
 	"regexp/syntax":  {"L2"},
 	"runtime/debug":  {"L2", "fmt", "io/ioutil", "os", "time"},
 	"runtime/pprof":  {"L2", "fmt", "text/tabwriter"},
+	"runtime/trace":  {"L0"},
 	"text/tabwriter": {"L2"},
 
-	"testing":        {"L2", "flag", "fmt", "os", "runtime/pprof", "time"},
-	"testing/iotest": {"L2", "log"},
-	"testing/quick":  {"L2", "flag", "fmt", "reflect"},
+	"testing":          {"L2", "flag", "fmt", "os", "runtime/pprof", "runtime/trace", "time"},
+	"testing/iotest":   {"L2", "log"},
+	"testing/quick":    {"L2", "flag", "fmt", "reflect"},
+	"internal/testenv": {"L2", "os", "testing"},
 
 	// L4 is defined as L3+fmt+log+time, because in general once
 	// you're using L3 packages, use of fmt, log, or time is not a big deal.
@@ -180,43 +192,60 @@ var pkgDeps = map[string][]string{
 		"go/token",
 	},
 
+	"go/format":       {"L4", "GOPARSER", "internal/format"},
+	"internal/format": {"L4", "GOPARSER"},
+
+	// Go type checking.
+	"go/constant":               {"L4", "go/token", "math/big"},
+	"go/importer":               {"L4", "go/internal/gcimporter", "go/internal/gccgoimporter", "go/types"},
+	"go/internal/gcimporter":    {"L4", "OS", "go/build", "go/constant", "go/token", "go/types", "text/scanner"},
+	"go/internal/gccgoimporter": {"L4", "OS", "debug/elf", "go/constant", "go/token", "go/types", "text/scanner"},
+	"go/types":                  {"L4", "GOPARSER", "container/heap", "go/constant"},
+
 	// One of a kind.
-	"archive/tar":         {"L4", "OS", "syscall"},
-	"archive/zip":         {"L4", "OS", "compress/flate"},
-	"compress/bzip2":      {"L4"},
-	"compress/flate":      {"L4"},
-	"compress/gzip":       {"L4", "compress/flate"},
-	"compress/lzw":        {"L4"},
-	"compress/zlib":       {"L4", "compress/flate"},
-	"database/sql":        {"L4", "container/list", "database/sql/driver"},
-	"database/sql/driver": {"L4", "time"},
-	"debug/dwarf":         {"L4"},
-	"debug/elf":           {"L4", "OS", "debug/dwarf"},
-	"debug/gosym":         {"L4"},
-	"debug/macho":         {"L4", "OS", "debug/dwarf"},
-	"debug/pe":            {"L4", "OS", "debug/dwarf"},
-	"encoding":            {"L4"},
-	"encoding/ascii85":    {"L4"},
-	"encoding/asn1":       {"L4", "math/big"},
-	"encoding/csv":        {"L4"},
-	"encoding/gob":        {"L4", "OS", "encoding"},
-	"encoding/hex":        {"L4"},
-	"encoding/json":       {"L4", "encoding"},
-	"encoding/pem":        {"L4"},
-	"encoding/xml":        {"L4", "encoding"},
-	"flag":                {"L4", "OS"},
-	"go/build":            {"L4", "OS", "GOPARSER"},
-	"html":                {"L4"},
-	"image/draw":          {"L4"},
-	"image/gif":           {"L4", "compress/lzw", "image/color/palette", "image/draw"},
-	"image/jpeg":          {"L4"},
-	"image/png":           {"L4", "compress/zlib"},
-	"index/suffixarray":   {"L4", "regexp"},
-	"math/big":            {"L4"},
-	"mime":                {"L4", "OS", "syscall"},
-	"net/url":             {"L4"},
-	"text/scanner":        {"L4", "OS"},
-	"text/template/parse": {"L4"},
+	"archive/tar":              {"L4", "OS", "syscall"},
+	"archive/zip":              {"L4", "OS", "compress/flate"},
+	"container/heap":           {"sort"},
+	"compress/bzip2":           {"L4"},
+	"compress/flate":           {"L4"},
+	"compress/gzip":            {"L4", "compress/flate"},
+	"compress/lzw":             {"L4"},
+	"compress/zlib":            {"L4", "compress/flate"},
+	"database/sql":             {"L4", "container/list", "database/sql/driver"},
+	"database/sql/driver":      {"L4", "time"},
+	"debug/dwarf":              {"L4"},
+	"debug/elf":                {"L4", "OS", "debug/dwarf"},
+	"debug/gosym":              {"L4"},
+	"debug/macho":              {"L4", "OS", "debug/dwarf"},
+	"debug/pe":                 {"L4", "OS", "debug/dwarf"},
+	"debug/plan9obj":           {"L4", "OS"},
+	"encoding":                 {"L4"},
+	"encoding/ascii85":         {"L4"},
+	"encoding/asn1":            {"L4", "math/big"},
+	"encoding/csv":             {"L4"},
+	"encoding/gob":             {"L4", "OS", "encoding"},
+	"encoding/hex":             {"L4"},
+	"encoding/json":            {"L4", "encoding"},
+	"encoding/pem":             {"L4"},
+	"encoding/xml":             {"L4", "encoding"},
+	"flag":                     {"L4", "OS"},
+	"go/build":                 {"L4", "OS", "GOPARSER"},
+	"html":                     {"L4"},
+	"image/draw":               {"L4", "image/internal/imageutil"},
+	"image/gif":                {"L4", "compress/lzw", "image/color/palette", "image/draw"},
+	"image/internal/imageutil": {"L4"},
+	"image/jpeg":               {"L4", "image/internal/imageutil"},
+	"image/png":                {"L4", "compress/zlib"},
+	"index/suffixarray":        {"L4", "regexp"},
+	"internal/singleflight":    {"sync"},
+	"internal/trace":           {"L4", "OS"},
+	"math/big":                 {"L4"},
+	"mime":                     {"L4", "OS", "syscall", "internal/syscall/windows/registry"},
+	"mime/quotedprintable":     {"L4"},
+	"net/internal/socktest":    {"L4", "OS", "syscall"},
+	"net/url":                  {"L4"},
+	"text/scanner":             {"L4", "OS"},
+	"text/template/parse":      {"L4"},
 
 	"html/template": {
 		"L4", "OS", "encoding/json", "html", "text/template",
@@ -234,13 +263,16 @@ var pkgDeps = map[string][]string{
 	// that shows up in programs that use cgo.
 	"C": {},
 
+	// Race detector uses cgo.
+	"runtime/race": {"C"},
+
 	// Plan 9 alone needs io/ioutil and os.
 	"os/user": {"L4", "CGO", "io/ioutil", "os", "syscall"},
 
 	// Basic networking.
 	// Because net must be used by any package that wants to
 	// do networking portably, it must have a small dependency set: just L1+basic os.
-	"net": {"L1", "CGO", "os", "syscall", "time"},
+	"net": {"L1", "CGO", "os", "syscall", "time", "internal/syscall/windows", "internal/singleflight"},
 
 	// NET enables use of basic network-related packages.
 	"NET": {
@@ -252,7 +284,7 @@ var pkgDeps = map[string][]string{
 
 	// Uses of networking.
 	"log/syslog":    {"L4", "OS", "net"},
-	"net/mail":      {"L4", "NET", "OS"},
+	"net/mail":      {"L4", "NET", "OS", "mime"},
 	"net/textproto": {"L4", "OS", "net"},
 
 	// Core crypto.
@@ -279,7 +311,7 @@ var pkgDeps = map[string][]string{
 	// Random byte, number generation.
 	// This would be part of core crypto except that it imports
 	// math/big, which imports fmt.
-	"crypto/rand": {"L4", "CRYPTO", "OS", "math/big", "syscall", "internal/syscall"},
+	"crypto/rand": {"L4", "CRYPTO", "OS", "math/big", "syscall", "internal/syscall/unix"},
 
 	// Mathematical crypto: dependencies on fmt (L4) and math/big.
 	// We could avoid some of the fmt, but math/big imports fmt anyway.
@@ -311,7 +343,7 @@ var pkgDeps = map[string][]string{
 	"crypto/x509/pkix": {"L4", "CRYPTO-MATH"},
 
 	// Simple net+crypto-aware packages.
-	"mime/multipart": {"L4", "OS", "mime", "crypto/rand", "net/textproto"},
+	"mime/multipart": {"L4", "OS", "mime", "crypto/rand", "net/textproto", "mime/quotedprintable"},
 	"net/smtp":       {"L4", "CRYPTO", "NET", "crypto/tls"},
 
 	// HTTP, kingpin of dependencies.
@@ -320,16 +352,18 @@ var pkgDeps = map[string][]string{
 		"compress/gzip", "crypto/tls", "mime/multipart", "runtime/debug",
 		"net/http/internal",
 	},
+	"net/http/internal": {"L4"},
 
 	// HTTP-using packages.
-	"expvar":            {"L4", "OS", "encoding/json", "net/http"},
-	"net/http/cgi":      {"L4", "NET", "OS", "crypto/tls", "net/http", "regexp"},
-	"net/http/fcgi":     {"L4", "NET", "OS", "net/http", "net/http/cgi"},
-	"net/http/httptest": {"L4", "NET", "OS", "crypto/tls", "flag", "net/http"},
-	"net/http/httputil": {"L4", "NET", "OS", "net/http", "net/http/internal"},
-	"net/http/pprof":    {"L4", "OS", "html/template", "net/http", "runtime/pprof"},
-	"net/rpc":           {"L4", "NET", "encoding/gob", "html/template", "net/http"},
-	"net/rpc/jsonrpc":   {"L4", "NET", "encoding/json", "net/rpc"},
+	"expvar":             {"L4", "OS", "encoding/json", "net/http"},
+	"net/http/cgi":       {"L4", "NET", "OS", "crypto/tls", "net/http", "regexp"},
+	"net/http/cookiejar": {"L4", "NET", "net/http"},
+	"net/http/fcgi":      {"L4", "NET", "OS", "net/http", "net/http/cgi"},
+	"net/http/httptest":  {"L4", "NET", "OS", "crypto/tls", "flag", "net/http"},
+	"net/http/httputil":  {"L4", "NET", "OS", "net/http", "net/http/internal"},
+	"net/http/pprof":     {"L4", "OS", "html/template", "net/http", "runtime/pprof", "runtime/trace"},
+	"net/rpc":            {"L4", "NET", "encoding/gob", "html/template", "net/http"},
+	"net/rpc/jsonrpc":    {"L4", "NET", "encoding/json", "net/rpc"},
 }
 
 // isMacro reports whether p is a package dependency macro
@@ -375,69 +409,112 @@ var allowedErrors = map[osPkg]bool{
 	osPkg{"plan9", "log/syslog"}:   true,
 }
 
+// listStdPkgs returns the same list of packages as "go list std".
+func listStdPkgs(goroot string) ([]string, error) {
+	// Based on cmd/go's matchPackages function.
+	var pkgs []string
+
+	src := filepath.Join(goroot, "src") + string(filepath.Separator)
+	walkFn := func(path string, fi os.FileInfo, err error) error {
+		if err != nil || !fi.IsDir() || path == src {
+			return nil
+		}
+
+		base := filepath.Base(path)
+		if strings.HasPrefix(base, ".") || strings.HasPrefix(base, "_") || base == "testdata" {
+			return filepath.SkipDir
+		}
+
+		name := filepath.ToSlash(path[len(src):])
+		if name == "builtin" || name == "cmd" || strings.Contains(name, ".") {
+			return filepath.SkipDir
+		}
+
+		pkgs = append(pkgs, name)
+		return nil
+	}
+	if err := filepath.Walk(src, walkFn); err != nil {
+		return nil, err
+	}
+	return pkgs, nil
+}
+
 func TestDependencies(t *testing.T) {
-	if runtime.GOOS == "nacl" {
-		// NaCl tests run in a limited file system and we do not
+	iOS := runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64")
+	if runtime.GOOS == "nacl" || iOS {
+		// Tests run in a limited file system and we do not
 		// provide access to every source file.
-		t.Skip("skipping on NaCl")
+		t.Skipf("skipping on %s/%s, missing full GOROOT", runtime.GOOS, runtime.GOARCH)
 	}
-	var all []string
 
-	for k := range pkgDeps {
-		all = append(all, k)
+	ctxt := Default
+	all, err := listStdPkgs(ctxt.GOROOT)
+	if err != nil {
+		t.Fatal(err)
 	}
 	sort.Strings(all)
 
-	ctxt := Default
 	test := func(mustImport bool) {
 		for _, pkg := range all {
-			if isMacro(pkg) {
-				continue
-			}
-			if pkg == "runtime/cgo" && !ctxt.CgoEnabled {
-				continue
-			}
-			p, err := ctxt.Import(pkg, "", 0)
+			imports, err := findImports(pkg)
 			if err != nil {
-				if allowedErrors[osPkg{ctxt.GOOS, pkg}] {
-					continue
-				}
-				if !ctxt.CgoEnabled && pkg == "runtime/cgo" {
-					continue
-				}
-				// Some of the combinations we try might not
-				// be reasonable (like arm,plan9,cgo), so ignore
-				// errors for the auto-generated combinations.
-				if !mustImport {
-					continue
-				}
-				t.Errorf("%s/%s/cgo=%v %v", ctxt.GOOS, ctxt.GOARCH, ctxt.CgoEnabled, err)
+				t.Error(err)
 				continue
 			}
 			ok := allowed(pkg)
 			var bad []string
-			for _, imp := range p.Imports {
+			for _, imp := range imports {
 				if !ok[imp] {
 					bad = append(bad, imp)
 				}
 			}
 			if bad != nil {
-				t.Errorf("%s/%s/cgo=%v unexpected dependency: %s imports %v", ctxt.GOOS, ctxt.GOARCH, ctxt.CgoEnabled, pkg, bad)
+				t.Errorf("unexpected dependency: %s imports %v", pkg, bad)
 			}
 		}
 	}
 	test(true)
+}
 
-	if testing.Short() {
-		t.Logf("skipping other systems")
-		return
-	}
+var buildIgnore = []byte("\n// +build ignore")
 
-	for _, ctxt.GOOS = range geese {
-		for _, ctxt.GOARCH = range goarches {
-			for _, ctxt.CgoEnabled = range bools {
-				test(false)
+func findImports(pkg string) ([]string, error) {
+	dir := filepath.Join(Default.GOROOT, "src", pkg)
+	files, err := ioutil.ReadDir(dir)
+	if err != nil {
+		return nil, err
+	}
+	var imports []string
+	var haveImport = map[string]bool{}
+	for _, file := range files {
+		name := file.Name()
+		if !strings.HasSuffix(name, ".go") || strings.HasSuffix(name, "_test.go") {
+			continue
+		}
+		f, err := os.Open(filepath.Join(dir, name))
+		if err != nil {
+			return nil, err
+		}
+		var imp []string
+		data, err := readImports(f, false, &imp)
+		f.Close()
+		if err != nil {
+			return nil, fmt.Errorf("reading %v: %v", name, err)
+		}
+		if bytes.Contains(data, buildIgnore) {
+			continue
+		}
+		for _, quoted := range imp {
+			path, err := strconv.Unquote(quoted)
+			if err != nil {
+				continue
+			}
+			if !haveImport[path] {
+				haveImport[path] = true
+				imports = append(imports, path)
 			}
 		}
 	}
+	sort.Strings(imports)
+	return imports, nil
 }
diff --git a/src/go/build/doc.go b/src/go/build/doc.go
index 75a827b..233f8b9 100644
--- a/src/go/build/doc.go
+++ b/src/go/build/doc.go
@@ -101,6 +101,7 @@
 //	- "go1.2", from Go version 1.2 onward
 //	- "go1.3", from Go version 1.3 onward
 //	- "go1.4", from Go version 1.4 onward
+//	- "go1.5", from Go version 1.5 onward
 //	- any additional words listed in ctxt.BuildTags
 //
 // If a file's name, after stripping the extension and a possible _test suffix,
@@ -111,7 +112,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/read.go b/src/go/build/read.go
index c8079df..1049ac5 100644
--- a/src/go/build/read.go
+++ b/src/go/build/read.go
@@ -146,11 +146,15 @@ func (r *importReader) readIdent() {
 
 // readString reads a quoted string literal from the input.
 // If an identifier is not present, readString records a syntax error.
-func (r *importReader) readString() {
+func (r *importReader) readString(save *[]string) {
 	switch r.nextByte(true) {
 	case '`':
+		start := len(r.buf) - 1
 		for r.err == nil {
 			if r.nextByte(false) == '`' {
+				if save != nil {
+					*save = append(*save, string(r.buf[start:]))
+				}
 				break
 			}
 			if r.eof {
@@ -158,9 +162,13 @@ func (r *importReader) readString() {
 			}
 		}
 	case '"':
+		start := len(r.buf) - 1
 		for r.err == nil {
 			c := r.nextByte(false)
 			if c == '"' {
+				if save != nil {
+					*save = append(*save, string(r.buf[start:]))
+				}
 				break
 			}
 			if r.eof || c == '\n' {
@@ -177,14 +185,14 @@ func (r *importReader) readString() {
 
 // readImport reads an import clause - optional identifier followed by quoted string -
 // from the input.
-func (r *importReader) readImport() {
+func (r *importReader) readImport(imports *[]string) {
 	c := r.peekByte(true)
 	if c == '.' {
 		r.peek = 0
 	} else if isIdent(c) {
 		r.readIdent()
 	}
-	r.readString()
+	r.readString(imports)
 }
 
 // readComments is like ioutil.ReadAll, except that it only reads the leading
@@ -201,7 +209,7 @@ func readComments(f io.Reader) ([]byte, error) {
 
 // readImports is like ioutil.ReadAll, except that it expects a Go file as input
 // and stops reading the input once the imports have completed.
-func readImports(f io.Reader, reportSyntaxError bool) ([]byte, error) {
+func readImports(f io.Reader, reportSyntaxError bool, imports *[]string) ([]byte, error) {
 	r := &importReader{b: bufio.NewReader(f)}
 
 	r.readKeyword("package")
@@ -211,11 +219,11 @@ func readImports(f io.Reader, reportSyntaxError bool) ([]byte, error) {
 		if r.peekByte(true) == '(' {
 			r.nextByte(false)
 			for r.peekByte(true) != ')' && r.err == nil {
-				r.readImport()
+				r.readImport(imports)
 			}
 			r.nextByte(false)
 		} else {
-			r.readImport()
+			r.readImport(imports)
 		}
 	}
 
diff --git a/src/go/build/read_test.go b/src/go/build/read_test.go
index 2dcc120..326960b 100644
--- a/src/go/build/read_test.go
+++ b/src/go/build/read_test.go
@@ -131,7 +131,7 @@ func testRead(t *testing.T, tests []readTest, read func(io.Reader) ([]byte, erro
 }
 
 func TestReadImports(t *testing.T) {
-	testRead(t, readImportsTests, func(r io.Reader) ([]byte, error) { return readImports(r, true) })
+	testRead(t, readImportsTests, func(r io.Reader) ([]byte, error) { return readImports(r, true, nil) })
 }
 
 func TestReadComments(t *testing.T) {
@@ -207,7 +207,7 @@ var readFailuresTests = []readTest{
 
 func TestReadFailures(t *testing.T) {
 	// Errors should be reported (true arg to readImports).
-	testRead(t, readFailuresTests, func(r io.Reader) ([]byte, error) { return readImports(r, true) })
+	testRead(t, readFailuresTests, func(r io.Reader) ([]byte, error) { return readImports(r, true, nil) })
 }
 
 func TestReadFailuresIgnored(t *testing.T) {
@@ -222,5 +222,5 @@ func TestReadFailuresIgnored(t *testing.T) {
 			tt.err = ""
 		}
 	}
-	testRead(t, tests, func(r io.Reader) ([]byte, error) { return readImports(r, false) })
+	testRead(t, tests, func(r io.Reader) ([]byte, error) { return readImports(r, false, nil) })
 }
diff --git a/src/go/build/syslist.go b/src/go/build/syslist.go
index 965f873..7adb0ca 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 "
+const goarchList = "386 amd64 amd64p32 arm armbe arm64 arm64be ppc64 ppc64le mips mipsle mips64 mips64le mips64p32 mips64p32le ppc s390 s390x sparc sparc64 "
diff --git a/src/go/constant/go13.go b/src/go/constant/go13.go
new file mode 100644
index 0000000..a4a838a
--- /dev/null
+++ b/src/go/constant/go13.go
@@ -0,0 +1,24 @@
+// 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 !go1.4
+
+package constant
+
+import (
+	"math"
+	"math/big"
+)
+
+func ratToFloat32(x *big.Rat) (float32, bool) {
+	// Before 1.4, there's no Rat.Float32.
+	// Emulate it, albeit at the cost of
+	// imprecision in corner cases.
+	x64, exact := x.Float64()
+	x32 := float32(x64)
+	if math.IsInf(float64(x32), 0) {
+		exact = false
+	}
+	return x32, exact
+}
diff --git a/src/go/constant/go14.go b/src/go/constant/go14.go
new file mode 100644
index 0000000..2ab6da0
--- /dev/null
+++ b/src/go/constant/go14.go
@@ -0,0 +1,13 @@
+// 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 go1.4
+
+package constant
+
+import "math/big"
+
+func ratToFloat32(x *big.Rat) (float32, bool) {
+	return x.Float32()
+}
diff --git a/src/go/constant/value.go b/src/go/constant/value.go
new file mode 100644
index 0000000..79a80af
--- /dev/null
+++ b/src/go/constant/value.go
@@ -0,0 +1,925 @@
+// 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 constant implements Values representing untyped
+// Go constants and the corresponding operations. Values
+// and operations may have arbitrary or unlimited precision.
+//
+// A special Unknown value may be used when a value
+// is unknown due to an error. Operations on unknown
+// values produce unknown values unless specified
+// otherwise.
+//
+package constant // import "go/constant"
+
+import (
+	"fmt"
+	"go/token"
+	"math/big"
+	"strconv"
+)
+
+// Kind specifies the kind of value represented by a Value.
+type Kind int
+
+// Implementation note: Kinds must be enumerated in
+// order of increasing "complexity" (used by match).
+
+const (
+	// unknown values
+	Unknown Kind = iota
+
+	// non-numeric values
+	Bool
+	String
+
+	// numeric values
+	Int
+	Float
+	Complex
+)
+
+// A Value represents a mathematically exact value of a given Kind.
+type Value interface {
+	// Kind returns the value kind; it is always the smallest
+	// kind in which the value can be represented exactly.
+	Kind() Kind
+
+	// String returns a human-readable form of the value.
+	String() string
+
+	// Prevent external implementations.
+	implementsValue()
+}
+
+// ----------------------------------------------------------------------------
+// Implementations
+
+type (
+	unknownVal struct{}
+	boolVal    bool
+	stringVal  string
+	int64Val   int64
+	intVal     struct{ val *big.Int }
+	floatVal   struct{ val *big.Rat }
+	complexVal struct{ re, im *big.Rat }
+)
+
+func (unknownVal) Kind() Kind { return Unknown }
+func (boolVal) Kind() Kind    { return Bool }
+func (stringVal) Kind() Kind  { return String }
+func (int64Val) Kind() Kind   { return Int }
+func (intVal) Kind() Kind     { return Int }
+func (floatVal) Kind() Kind   { return Float }
+func (complexVal) Kind() Kind { return Complex }
+
+func (unknownVal) String() string   { return "unknown" }
+func (x boolVal) String() string    { return fmt.Sprintf("%v", bool(x)) }
+func (x stringVal) String() string  { return strconv.Quote(string(x)) }
+func (x int64Val) String() string   { return strconv.FormatInt(int64(x), 10) }
+func (x intVal) String() string     { return x.val.String() }
+func (x floatVal) String() string   { return x.val.String() }
+func (x complexVal) String() string { return fmt.Sprintf("(%s + %si)", x.re, x.im) }
+
+func (unknownVal) implementsValue() {}
+func (boolVal) implementsValue()    {}
+func (stringVal) implementsValue()  {}
+func (int64Val) implementsValue()   {}
+func (intVal) implementsValue()     {}
+func (floatVal) implementsValue()   {}
+func (complexVal) implementsValue() {}
+
+// int64 bounds
+var (
+	minInt64 = big.NewInt(-1 << 63)
+	maxInt64 = big.NewInt(1<<63 - 1)
+)
+
+func normInt(x *big.Int) Value {
+	if minInt64.Cmp(x) <= 0 && x.Cmp(maxInt64) <= 0 {
+		return int64Val(x.Int64())
+	}
+	return intVal{x}
+}
+
+func normFloat(x *big.Rat) Value {
+	if x.IsInt() {
+		return normInt(x.Num())
+	}
+	return floatVal{x}
+}
+
+func normComplex(re, im *big.Rat) Value {
+	if im.Sign() == 0 {
+		return normFloat(re)
+	}
+	return complexVal{re, im}
+}
+
+// ----------------------------------------------------------------------------
+// Factories
+
+// MakeUnknown returns the Unknown value.
+func MakeUnknown() Value { return unknownVal{} }
+
+// MakeBool returns the Bool value for x.
+func MakeBool(b bool) Value { return boolVal(b) }
+
+// MakeString returns the String value for x.
+func MakeString(s string) Value { return stringVal(s) }
+
+// MakeInt64 returns the Int value for x.
+func MakeInt64(x int64) Value { return int64Val(x) }
+
+// MakeUint64 returns the Int value for x.
+func MakeUint64(x uint64) Value { return normInt(new(big.Int).SetUint64(x)) }
+
+// MakeFloat64 returns the numeric value for x.
+// If x is not finite, the result is unknown.
+func MakeFloat64(x float64) Value {
+	if f := new(big.Rat).SetFloat64(x); f != nil {
+		return normFloat(f)
+	}
+	return unknownVal{}
+}
+
+// MakeFromLiteral returns the corresponding integer, floating-point,
+// imaginary, character, or string value for a Go literal string.
+// If prec > 0, prec specifies an upper limit for the precision of
+// a numeric value. If the literal string is invalid, the result is
+// nil.
+// BUG(gri) Only prec == 0 is supported at the moment.
+func MakeFromLiteral(lit string, tok token.Token, prec uint) Value {
+	if prec != 0 {
+		panic("limited precision not supported")
+	}
+	switch tok {
+	case token.INT:
+		if x, err := strconv.ParseInt(lit, 0, 64); err == nil {
+			return int64Val(x)
+		}
+		if x, ok := new(big.Int).SetString(lit, 0); ok {
+			return intVal{x}
+		}
+
+	case token.FLOAT:
+		if x, ok := new(big.Rat).SetString(lit); ok {
+			return normFloat(x)
+		}
+
+	case token.IMAG:
+		if n := len(lit); n > 0 && lit[n-1] == 'i' {
+			if im, ok := new(big.Rat).SetString(lit[0 : n-1]); ok {
+				return normComplex(big.NewRat(0, 1), im)
+			}
+		}
+
+	case token.CHAR:
+		if n := len(lit); n >= 2 {
+			if code, _, _, err := strconv.UnquoteChar(lit[1:n-1], '\''); err == nil {
+				return int64Val(code)
+			}
+		}
+
+	case token.STRING:
+		if s, err := strconv.Unquote(lit); err == nil {
+			return stringVal(s)
+		}
+	}
+
+	return nil
+}
+
+// ----------------------------------------------------------------------------
+// Accessors
+//
+// For unknown arguments the result is the zero value for the respective
+// accessor type, except for Sign, where the result is 1.
+
+// BoolVal returns the Go boolean value of x, which must be a Bool or an Unknown.
+// If x is Unknown, the result is false.
+func BoolVal(x Value) bool {
+	switch x := x.(type) {
+	case boolVal:
+		return bool(x)
+	case unknownVal:
+		return false
+	}
+	panic(fmt.Sprintf("%v not a Bool", x))
+}
+
+// StringVal returns the Go string value of x, which must be a String or an Unknown.
+// If x is Unknown, the result is "".
+func StringVal(x Value) string {
+	switch x := x.(type) {
+	case stringVal:
+		return string(x)
+	case unknownVal:
+		return ""
+	}
+	panic(fmt.Sprintf("%v not a String", x))
+}
+
+// Int64Val returns the Go int64 value of x and whether the result is exact;
+// x must be an Int or an Unknown. If the result is not exact, its value is undefined.
+// If x is Unknown, the result is (0, false).
+func Int64Val(x Value) (int64, bool) {
+	switch x := x.(type) {
+	case int64Val:
+		return int64(x), true
+	case intVal:
+		return x.val.Int64(), x.val.BitLen() <= 63
+	case unknownVal:
+		return 0, false
+	}
+	panic(fmt.Sprintf("%v not an Int", x))
+}
+
+// Uint64Val returns the Go uint64 value of x and whether the result is exact;
+// x must be an Int or an Unknown. If the result is not exact, its value is undefined.
+// If x is Unknown, the result is (0, false).
+func Uint64Val(x Value) (uint64, bool) {
+	switch x := x.(type) {
+	case int64Val:
+		return uint64(x), x >= 0
+	case intVal:
+		return x.val.Uint64(), x.val.Sign() >= 0 && x.val.BitLen() <= 64
+	case unknownVal:
+		return 0, false
+	}
+	panic(fmt.Sprintf("%v not an Int", x))
+}
+
+// Float32Val is like Float64Val but for float32 instead of float64.
+func Float32Val(x Value) (float32, bool) {
+	switch x := x.(type) {
+	case int64Val:
+		f := float32(x)
+		return f, int64Val(f) == x
+	case intVal:
+		return ratToFloat32(new(big.Rat).SetFrac(x.val, int1))
+	case floatVal:
+		return ratToFloat32(x.val)
+	case unknownVal:
+		return 0, false
+	}
+	panic(fmt.Sprintf("%v not a Float", x))
+}
+
+// Float64Val returns the nearest Go float64 value of x and whether the result is exact;
+// x must be numeric but not Complex, or Unknown. For values too small (too close to 0)
+// to represent as float64, Float64Val silently underflows to 0. The result sign always
+// matches the sign of x, even for 0.
+// If x is Unknown, the result is (0, false).
+func Float64Val(x Value) (float64, bool) {
+	switch x := x.(type) {
+	case int64Val:
+		f := float64(int64(x))
+		return f, int64Val(f) == x
+	case intVal:
+		return new(big.Rat).SetFrac(x.val, int1).Float64()
+	case floatVal:
+		return x.val.Float64()
+	case unknownVal:
+		return 0, false
+	}
+	panic(fmt.Sprintf("%v not a Float", x))
+}
+
+// BitLen returns the number of bits required to represent
+// the absolute value x in binary representation; x must be an Int or an Unknown.
+// If x is Unknown, the result is 0.
+func BitLen(x Value) int {
+	switch x := x.(type) {
+	case int64Val:
+		return new(big.Int).SetInt64(int64(x)).BitLen()
+	case intVal:
+		return x.val.BitLen()
+	case unknownVal:
+		return 0
+	}
+	panic(fmt.Sprintf("%v not an Int", x))
+}
+
+// Sign returns -1, 0, or 1 depending on whether x < 0, x == 0, or x > 0;
+// x must be numeric or Unknown. For complex values x, the sign is 0 if x == 0,
+// otherwise it is != 0. If x is Unknown, the result is 1.
+func Sign(x Value) int {
+	switch x := x.(type) {
+	case int64Val:
+		switch {
+		case x < 0:
+			return -1
+		case x > 0:
+			return 1
+		}
+		return 0
+	case intVal:
+		return x.val.Sign()
+	case floatVal:
+		return x.val.Sign()
+	case complexVal:
+		return x.re.Sign() | x.im.Sign()
+	case unknownVal:
+		return 1 // avoid spurious division by zero errors
+	}
+	panic(fmt.Sprintf("%v not numeric", x))
+}
+
+// ----------------------------------------------------------------------------
+// Support for serializing/deserializing integers
+
+const (
+	// Compute the size of a Word in bytes.
+	_m       = ^big.Word(0)
+	_log     = _m>>8&1 + _m>>16&1 + _m>>32&1
+	wordSize = 1 << _log
+)
+
+// Bytes returns the bytes for the absolute value of x in little-
+// endian binary representation; x must be an Int.
+func Bytes(x Value) []byte {
+	var val *big.Int
+	switch x := x.(type) {
+	case int64Val:
+		val = new(big.Int).SetInt64(int64(x))
+	case intVal:
+		val = x.val
+	default:
+		panic(fmt.Sprintf("%v not an Int", x))
+	}
+
+	words := val.Bits()
+	bytes := make([]byte, len(words)*wordSize)
+
+	i := 0
+	for _, w := range words {
+		for j := 0; j < wordSize; j++ {
+			bytes[i] = byte(w)
+			w >>= 8
+			i++
+		}
+	}
+	// remove leading 0's
+	for i > 0 && bytes[i-1] == 0 {
+		i--
+	}
+
+	return bytes[:i]
+}
+
+// MakeFromBytes returns the Int value given the bytes of its little-endian
+// binary representation. An empty byte slice argument represents 0.
+func MakeFromBytes(bytes []byte) Value {
+	words := make([]big.Word, (len(bytes)+(wordSize-1))/wordSize)
+
+	i := 0
+	var w big.Word
+	var s uint
+	for _, b := range bytes {
+		w |= big.Word(b) << s
+		if s += 8; s == wordSize*8 {
+			words[i] = w
+			i++
+			w = 0
+			s = 0
+		}
+	}
+	// store last word
+	if i < len(words) {
+		words[i] = w
+		i++
+	}
+	// remove leading 0's
+	for i > 0 && words[i-1] == 0 {
+		i--
+	}
+
+	return normInt(new(big.Int).SetBits(words[:i]))
+}
+
+// ----------------------------------------------------------------------------
+// Support for disassembling fractions
+
+// Num returns the numerator of x; x must be Int, Float, or Unknown.
+// If x is Unknown, the result is Unknown, otherwise it is an Int
+// with the same sign as x.
+func Num(x Value) Value {
+	switch x := x.(type) {
+	case unknownVal, int64Val, intVal:
+		return x
+	case floatVal:
+		return normInt(x.val.Num())
+	}
+	panic(fmt.Sprintf("%v not Int or Float", x))
+}
+
+// Denom returns the denominator of x; x must be Int, Float, or Unknown.
+// If x is Unknown, the result is Unknown, otherwise it is an Int >= 1.
+func Denom(x Value) Value {
+	switch x := x.(type) {
+	case unknownVal:
+		return x
+	case int64Val, intVal:
+		return int64Val(1)
+	case floatVal:
+		return normInt(x.val.Denom())
+	}
+	panic(fmt.Sprintf("%v not Int or Float", x))
+}
+
+// ----------------------------------------------------------------------------
+// Support for assembling/disassembling complex numbers
+
+// MakeImag returns the numeric value x*i (possibly 0);
+// x must be Int, Float, or Unknown.
+// If x is Unknown, the result is Unknown.
+func MakeImag(x Value) Value {
+	var im *big.Rat
+	switch x := x.(type) {
+	case unknownVal:
+		return x
+	case int64Val:
+		im = big.NewRat(int64(x), 1)
+	case intVal:
+		im = new(big.Rat).SetFrac(x.val, int1)
+	case floatVal:
+		im = x.val
+	default:
+		panic(fmt.Sprintf("%v not Int or Float", x))
+	}
+	return normComplex(rat0, im)
+}
+
+// Real returns the real part of x, which must be a numeric or unknown value.
+// If x is Unknown, the result is Unknown.
+func Real(x Value) Value {
+	switch x := x.(type) {
+	case unknownVal, int64Val, intVal, floatVal:
+		return x
+	case complexVal:
+		return normFloat(x.re)
+	}
+	panic(fmt.Sprintf("%v not numeric", x))
+}
+
+// Imag returns the imaginary part of x, which must be a numeric or unknown value.
+// If x is Unknown, the result is Unknown.
+func Imag(x Value) Value {
+	switch x := x.(type) {
+	case unknownVal:
+		return x
+	case int64Val, intVal, floatVal:
+		return int64Val(0)
+	case complexVal:
+		return normFloat(x.im)
+	}
+	panic(fmt.Sprintf("%v not numeric", x))
+}
+
+// ----------------------------------------------------------------------------
+// Operations
+
+// is32bit reports whether x can be represented using 32 bits.
+func is32bit(x int64) bool {
+	const s = 32
+	return -1<<(s-1) <= x && x <= 1<<(s-1)-1
+}
+
+// is63bit reports whether x can be represented using 63 bits.
+func is63bit(x int64) bool {
+	const s = 63
+	return -1<<(s-1) <= x && x <= 1<<(s-1)-1
+}
+
+// UnaryOp returns the result of the unary expression op y.
+// The operation must be defined for the operand.
+// If prec > 0 it specifies the ^ (xor) result size in bits.
+// If y is Unknown, the result is Unknown.
+//
+func UnaryOp(op token.Token, y Value, prec uint) Value {
+	switch op {
+	case token.ADD:
+		switch y.(type) {
+		case unknownVal, int64Val, intVal, floatVal, complexVal:
+			return y
+		}
+
+	case token.SUB:
+		switch y := y.(type) {
+		case unknownVal:
+			return y
+		case int64Val:
+			if z := -y; z != y {
+				return z // no overflow
+			}
+			return normInt(new(big.Int).Neg(big.NewInt(int64(y))))
+		case intVal:
+			return normInt(new(big.Int).Neg(y.val))
+		case floatVal:
+			return normFloat(new(big.Rat).Neg(y.val))
+		case complexVal:
+			return normComplex(new(big.Rat).Neg(y.re), new(big.Rat).Neg(y.im))
+		}
+
+	case token.XOR:
+		var z big.Int
+		switch y := y.(type) {
+		case unknownVal:
+			return y
+		case int64Val:
+			z.Not(big.NewInt(int64(y)))
+		case intVal:
+			z.Not(y.val)
+		default:
+			goto Error
+		}
+		// For unsigned types, the result will be negative and
+		// thus "too large": We must limit the result precision
+		// to the type's precision.
+		if prec > 0 {
+			z.AndNot(&z, new(big.Int).Lsh(big.NewInt(-1), prec)) // z &^= (-1)<<prec
+		}
+		return normInt(&z)
+
+	case token.NOT:
+		switch y := y.(type) {
+		case unknownVal:
+			return y
+		case boolVal:
+			return !y
+		}
+	}
+
+Error:
+	panic(fmt.Sprintf("invalid unary operation %s%v", op, y))
+}
+
+var (
+	int1 = big.NewInt(1)
+	rat0 = big.NewRat(0, 1)
+)
+
+func ord(x Value) int {
+	switch x.(type) {
+	default:
+		return 0
+	case boolVal, stringVal:
+		return 1
+	case int64Val:
+		return 2
+	case intVal:
+		return 3
+	case floatVal:
+		return 4
+	case complexVal:
+		return 5
+	}
+}
+
+// match returns the matching representation (same type) with the
+// smallest complexity for two values x and y. If one of them is
+// numeric, both of them must be numeric. If one of them is Unknown,
+// both results are Unknown.
+//
+func match(x, y Value) (_, _ Value) {
+	if ord(x) > ord(y) {
+		y, x = match(y, x)
+		return x, y
+	}
+	// ord(x) <= ord(y)
+
+	switch x := x.(type) {
+	case unknownVal:
+		return x, x
+
+	case boolVal, stringVal, complexVal:
+		return x, y
+
+	case int64Val:
+		switch y := y.(type) {
+		case int64Val:
+			return x, y
+		case intVal:
+			return intVal{big.NewInt(int64(x))}, y
+		case floatVal:
+			return floatVal{big.NewRat(int64(x), 1)}, y
+		case complexVal:
+			return complexVal{big.NewRat(int64(x), 1), rat0}, y
+		}
+
+	case intVal:
+		switch y := y.(type) {
+		case intVal:
+			return x, y
+		case floatVal:
+			return floatVal{new(big.Rat).SetFrac(x.val, int1)}, y
+		case complexVal:
+			return complexVal{new(big.Rat).SetFrac(x.val, int1), rat0}, y
+		}
+
+	case floatVal:
+		switch y := y.(type) {
+		case floatVal:
+			return x, y
+		case complexVal:
+			return complexVal{x.val, rat0}, y
+		}
+	}
+
+	panic("unreachable")
+}
+
+// BinaryOp returns the result of the binary expression x op y.
+// The operation must be defined for the operands. If one of the
+// operands is Unknown, the result is Unknown.
+// To force integer division of Int operands, use op == token.QUO_ASSIGN
+// instead of token.QUO; the result is guaranteed to be Int in this case.
+// Division by zero leads to a run-time panic.
+//
+func BinaryOp(x Value, op token.Token, y Value) Value {
+	x, y = match(x, y)
+
+	switch x := x.(type) {
+	case unknownVal:
+		return x
+
+	case boolVal:
+		y := y.(boolVal)
+		switch op {
+		case token.LAND:
+			return x && y
+		case token.LOR:
+			return x || y
+		}
+
+	case int64Val:
+		a := int64(x)
+		b := int64(y.(int64Val))
+		var c int64
+		switch op {
+		case token.ADD:
+			if !is63bit(a) || !is63bit(b) {
+				return normInt(new(big.Int).Add(big.NewInt(a), big.NewInt(b)))
+			}
+			c = a + b
+		case token.SUB:
+			if !is63bit(a) || !is63bit(b) {
+				return normInt(new(big.Int).Sub(big.NewInt(a), big.NewInt(b)))
+			}
+			c = a - b
+		case token.MUL:
+			if !is32bit(a) || !is32bit(b) {
+				return normInt(new(big.Int).Mul(big.NewInt(a), big.NewInt(b)))
+			}
+			c = a * b
+		case token.QUO:
+			return normFloat(new(big.Rat).SetFrac(big.NewInt(a), big.NewInt(b)))
+		case token.QUO_ASSIGN: // force integer division
+			c = a / b
+		case token.REM:
+			c = a % b
+		case token.AND:
+			c = a & b
+		case token.OR:
+			c = a | b
+		case token.XOR:
+			c = a ^ b
+		case token.AND_NOT:
+			c = a &^ b
+		default:
+			goto Error
+		}
+		return int64Val(c)
+
+	case intVal:
+		a := x.val
+		b := y.(intVal).val
+		var c big.Int
+		switch op {
+		case token.ADD:
+			c.Add(a, b)
+		case token.SUB:
+			c.Sub(a, b)
+		case token.MUL:
+			c.Mul(a, b)
+		case token.QUO:
+			return normFloat(new(big.Rat).SetFrac(a, b))
+		case token.QUO_ASSIGN: // force integer division
+			c.Quo(a, b)
+		case token.REM:
+			c.Rem(a, b)
+		case token.AND:
+			c.And(a, b)
+		case token.OR:
+			c.Or(a, b)
+		case token.XOR:
+			c.Xor(a, b)
+		case token.AND_NOT:
+			c.AndNot(a, b)
+		default:
+			goto Error
+		}
+		return normInt(&c)
+
+	case floatVal:
+		a := x.val
+		b := y.(floatVal).val
+		var c big.Rat
+		switch op {
+		case token.ADD:
+			c.Add(a, b)
+		case token.SUB:
+			c.Sub(a, b)
+		case token.MUL:
+			c.Mul(a, b)
+		case token.QUO:
+			c.Quo(a, b)
+		default:
+			goto Error
+		}
+		return normFloat(&c)
+
+	case complexVal:
+		y := y.(complexVal)
+		a, b := x.re, x.im
+		c, d := y.re, y.im
+		var re, im big.Rat
+		switch op {
+		case token.ADD:
+			// (a+c) + i(b+d)
+			re.Add(a, c)
+			im.Add(b, d)
+		case token.SUB:
+			// (a-c) + i(b-d)
+			re.Sub(a, c)
+			im.Sub(b, d)
+		case token.MUL:
+			// (ac-bd) + i(bc+ad)
+			var ac, bd, bc, ad big.Rat
+			ac.Mul(a, c)
+			bd.Mul(b, d)
+			bc.Mul(b, c)
+			ad.Mul(a, d)
+			re.Sub(&ac, &bd)
+			im.Add(&bc, &ad)
+		case token.QUO:
+			// (ac+bd)/s + i(bc-ad)/s, with s = cc + dd
+			var ac, bd, bc, ad, s, cc, dd big.Rat
+			ac.Mul(a, c)
+			bd.Mul(b, d)
+			bc.Mul(b, c)
+			ad.Mul(a, d)
+			cc.Mul(c, c)
+			dd.Mul(d, d)
+			s.Add(&cc, &dd)
+			re.Add(&ac, &bd)
+			re.Quo(&re, &s)
+			im.Sub(&bc, &ad)
+			im.Quo(&im, &s)
+		default:
+			goto Error
+		}
+		return normComplex(&re, &im)
+
+	case stringVal:
+		if op == token.ADD {
+			return x + y.(stringVal)
+		}
+	}
+
+Error:
+	panic(fmt.Sprintf("invalid binary operation %v %s %v", x, op, y))
+}
+
+// Shift returns the result of the shift expression x op s
+// with op == token.SHL or token.SHR (<< or >>). x must be
+// an Int or an Unknown. If x is Unknown, the result is x.
+//
+func Shift(x Value, op token.Token, s uint) Value {
+	switch x := x.(type) {
+	case unknownVal:
+		return x
+
+	case int64Val:
+		if s == 0 {
+			return x
+		}
+		switch op {
+		case token.SHL:
+			z := big.NewInt(int64(x))
+			return normInt(z.Lsh(z, s))
+		case token.SHR:
+			return x >> s
+		}
+
+	case intVal:
+		if s == 0 {
+			return x
+		}
+		var z big.Int
+		switch op {
+		case token.SHL:
+			return normInt(z.Lsh(x.val, s))
+		case token.SHR:
+			return normInt(z.Rsh(x.val, s))
+		}
+	}
+
+	panic(fmt.Sprintf("invalid shift %v %s %d", x, op, s))
+}
+
+func cmpZero(x int, op token.Token) bool {
+	switch op {
+	case token.EQL:
+		return x == 0
+	case token.NEQ:
+		return x != 0
+	case token.LSS:
+		return x < 0
+	case token.LEQ:
+		return x <= 0
+	case token.GTR:
+		return x > 0
+	case token.GEQ:
+		return x >= 0
+	}
+	panic("unreachable")
+}
+
+// Compare returns the result of the comparison x op y.
+// The comparison must be defined for the operands.
+// If one of the operands is Unknown, the result is
+// false.
+//
+func Compare(x Value, op token.Token, y Value) bool {
+	x, y = match(x, y)
+
+	switch x := x.(type) {
+	case unknownVal:
+		return false
+
+	case boolVal:
+		y := y.(boolVal)
+		switch op {
+		case token.EQL:
+			return x == y
+		case token.NEQ:
+			return x != y
+		}
+
+	case int64Val:
+		y := y.(int64Val)
+		switch op {
+		case token.EQL:
+			return x == y
+		case token.NEQ:
+			return x != y
+		case token.LSS:
+			return x < y
+		case token.LEQ:
+			return x <= y
+		case token.GTR:
+			return x > y
+		case token.GEQ:
+			return x >= y
+		}
+
+	case intVal:
+		return cmpZero(x.val.Cmp(y.(intVal).val), op)
+
+	case floatVal:
+		return cmpZero(x.val.Cmp(y.(floatVal).val), op)
+
+	case complexVal:
+		y := y.(complexVal)
+		re := x.re.Cmp(y.re)
+		im := x.im.Cmp(y.im)
+		switch op {
+		case token.EQL:
+			return re == 0 && im == 0
+		case token.NEQ:
+			return re != 0 || im != 0
+		}
+
+	case stringVal:
+		y := y.(stringVal)
+		switch op {
+		case token.EQL:
+			return x == y
+		case token.NEQ:
+			return x != y
+		case token.LSS:
+			return x < y
+		case token.LEQ:
+			return x <= y
+		case token.GTR:
+			return x > y
+		case token.GEQ:
+			return x >= y
+		}
+	}
+
+	panic(fmt.Sprintf("invalid comparison %v %s %v", x, op, y))
+}
diff --git a/src/go/constant/value_test.go b/src/go/constant/value_test.go
new file mode 100644
index 0000000..08cdd5e
--- /dev/null
+++ b/src/go/constant/value_test.go
@@ -0,0 +1,375 @@
+// 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 constant
+
+import (
+	"go/token"
+	"strings"
+	"testing"
+)
+
+// TODO(gri) expand this test framework
+
+var opTests = []string{
+	// unary operations
+	`+ 0 = 0`,
+	`+ ? = ?`,
+	`- 1 = -1`,
+	`- ? = ?`,
+	`^ 0 = -1`,
+	`^ ? = ?`,
+
+	`! true = false`,
+	`! false = true`,
+	`! ? = ?`,
+
+	// etc.
+
+	// binary operations
+	`"" + "" = ""`,
+	`"foo" + "" = "foo"`,
+	`"" + "bar" = "bar"`,
+	`"foo" + "bar" = "foobar"`,
+
+	`0 + 0 = 0`,
+	`0 + 0.1 = 0.1`,
+	`0 + 0.1i = 0.1i`,
+	`0.1 + 0.9 = 1`,
+	`1e100 + 1e100 = 2e100`,
+	`? + 0 = ?`,
+	`0 + ? = ?`,
+
+	`0 - 0 = 0`,
+	`0 - 0.1 = -0.1`,
+	`0 - 0.1i = -0.1i`,
+	`1e100 - 1e100 = 0`,
+	`? - 0 = ?`,
+	`0 - ? = ?`,
+
+	`0 * 0 = 0`,
+	`1 * 0.1 = 0.1`,
+	`1 * 0.1i = 0.1i`,
+	`1i * 1i = -1`,
+	`? * 0 = ?`,
+	`0 * ? = ?`,
+
+	`0 / 0 = "division_by_zero"`,
+	`10 / 2 = 5`,
+	`5 / 3 = 5/3`,
+	`5i / 3i = 5/3`,
+	`? / 0 = ?`,
+	`0 / ? = ?`,
+
+	`0 % 0 = "runtime_error:_integer_divide_by_zero"`, // TODO(gri) should be the same as for /
+	`10 % 3 = 1`,
+	`? % 0 = ?`,
+	`0 % ? = ?`,
+
+	`0 & 0 = 0`,
+	`12345 & 0 = 0`,
+	`0xff & 0xf = 0xf`,
+	`? & 0 = ?`,
+	`0 & ? = ?`,
+
+	`0 | 0 = 0`,
+	`12345 | 0 = 12345`,
+	`0xb | 0xa0 = 0xab`,
+	`? | 0 = ?`,
+	`0 | ? = ?`,
+
+	`0 ^ 0 = 0`,
+	`1 ^ -1 = -2`,
+	`? ^ 0 = ?`,
+	`0 ^ ? = ?`,
+
+	`0 &^ 0 = 0`,
+	`0xf &^ 1 = 0xe`,
+	`1 &^ 0xf = 0`,
+	// etc.
+
+	// shifts
+	`0 << 0 = 0`,
+	`1 << 10 = 1024`,
+	`0 >> 0 = 0`,
+	`1024 >> 10 == 1`,
+	`? << 0 == ?`,
+	`? >> 10 == ?`,
+	// etc.
+
+	// comparisons
+	`false == false = true`,
+	`false == true = false`,
+	`true == false = false`,
+	`true == true = true`,
+
+	`false != false = false`,
+	`false != true = true`,
+	`true != false = true`,
+	`true != true = false`,
+
+	`"foo" == "bar" = false`,
+	`"foo" != "bar" = true`,
+	`"foo" < "bar" = false`,
+	`"foo" <= "bar" = false`,
+	`"foo" > "bar" = true`,
+	`"foo" >= "bar" = true`,
+
+	`0 == 0 = true`,
+	`0 != 0 = false`,
+	`0 < 10 = true`,
+	`10 <= 10 = true`,
+	`0 > 10 = false`,
+	`10 >= 10 = true`,
+
+	`1/123456789 == 1/123456789 == true`,
+	`1/123456789 != 1/123456789 == false`,
+	`1/123456789 < 1/123456788 == true`,
+	`1/123456788 <= 1/123456789 == false`,
+	`0.11 > 0.11 = false`,
+	`0.11 >= 0.11 = true`,
+
+	`? == 0 = false`,
+	`? != 0 = false`,
+	`? < 10 = false`,
+	`? <= 10 = false`,
+	`? > 10 = false`,
+	`? >= 10 = false`,
+
+	`0 == ? = false`,
+	`0 != ? = false`,
+	`0 < ? = false`,
+	`10 <= ? = false`,
+	`0 > ? = false`,
+	`10 >= ? = false`,
+
+	// etc.
+}
+
+func TestOps(t *testing.T) {
+	for _, test := range opTests {
+		a := strings.Split(test, " ")
+		i := 0 // operator index
+
+		var x, x0 Value
+		switch len(a) {
+		case 4:
+			// unary operation
+		case 5:
+			// binary operation
+			x, x0 = val(a[0]), val(a[0])
+			i = 1
+		default:
+			t.Errorf("invalid test case: %s", test)
+			continue
+		}
+
+		op, ok := optab[a[i]]
+		if !ok {
+			panic("missing optab entry for " + a[i])
+		}
+
+		y, y0 := val(a[i+1]), val(a[i+1])
+
+		got := doOp(x, op, y)
+		want := val(a[i+3])
+		if !eql(got, want) {
+			t.Errorf("%s: got %s; want %s", test, got, want)
+		}
+		if x0 != nil && !eql(x, x0) {
+			t.Errorf("%s: x changed to %s", test, x)
+		}
+		if !eql(y, y0) {
+			t.Errorf("%s: y changed to %s", test, y)
+		}
+	}
+}
+
+func eql(x, y Value) bool {
+	_, ux := x.(unknownVal)
+	_, uy := y.(unknownVal)
+	if ux || uy {
+		return ux == uy
+	}
+	return Compare(x, token.EQL, y)
+}
+
+// ----------------------------------------------------------------------------
+// Support functions
+
+func val(lit string) Value {
+	if len(lit) == 0 {
+		return MakeUnknown()
+	}
+
+	switch lit {
+	case "?":
+		return MakeUnknown()
+	case "true":
+		return MakeBool(true)
+	case "false":
+		return MakeBool(false)
+	}
+
+	tok := token.INT
+	switch first, last := lit[0], lit[len(lit)-1]; {
+	case first == '"' || first == '`':
+		tok = token.STRING
+		lit = strings.Replace(lit, "_", " ", -1)
+	case first == '\'':
+		tok = token.CHAR
+	case last == 'i':
+		tok = token.IMAG
+	default:
+		if !strings.HasPrefix(lit, "0x") && strings.ContainsAny(lit, "./Ee") {
+			tok = token.FLOAT
+		}
+	}
+
+	return MakeFromLiteral(lit, tok, 0)
+}
+
+var optab = map[string]token.Token{
+	"!": token.NOT,
+
+	"+": token.ADD,
+	"-": token.SUB,
+	"*": token.MUL,
+	"/": token.QUO,
+	"%": token.REM,
+
+	"<<": token.SHL,
+	">>": token.SHR,
+
+	"&":  token.AND,
+	"|":  token.OR,
+	"^":  token.XOR,
+	"&^": token.AND_NOT,
+
+	"==": token.EQL,
+	"!=": token.NEQ,
+	"<":  token.LSS,
+	"<=": token.LEQ,
+	">":  token.GTR,
+	">=": token.GEQ,
+}
+
+func panicHandler(v *Value) {
+	switch p := recover().(type) {
+	case nil:
+		// nothing to do
+	case string:
+		*v = MakeString(p)
+	case error:
+		*v = MakeString(p.Error())
+	default:
+		panic(p)
+	}
+}
+
+func doOp(x Value, op token.Token, y Value) (z Value) {
+	defer panicHandler(&z)
+
+	if x == nil {
+		return UnaryOp(op, y, 0)
+	}
+
+	switch op {
+	case token.EQL, token.NEQ, token.LSS, token.LEQ, token.GTR, token.GEQ:
+		return MakeBool(Compare(x, op, y))
+	case token.SHL, token.SHR:
+		s, _ := Int64Val(y)
+		return Shift(x, op, uint(s))
+	default:
+		return BinaryOp(x, op, y)
+	}
+}
+
+// ----------------------------------------------------------------------------
+// Other tests
+
+var fracTests = []string{
+	"0 0 1",
+	"1 1 1",
+	"-1 -1 1",
+	"1.2 6 5",
+	"-0.991 -991 1000",
+	"1e100 1e100 1",
+}
+
+func TestFractions(t *testing.T) {
+	for _, test := range fracTests {
+		a := strings.Split(test, " ")
+		if len(a) != 3 {
+			t.Errorf("invalid test case: %s", test)
+			continue
+		}
+
+		x := val(a[0])
+		n := val(a[1])
+		d := val(a[2])
+
+		if got := Num(x); !eql(got, n) {
+			t.Errorf("%s: got num = %s; want %s", test, got, n)
+		}
+
+		if got := Denom(x); !eql(got, d) {
+			t.Errorf("%s: got denom = %s; want %s", test, got, d)
+		}
+	}
+}
+
+var bytesTests = []string{
+	"0",
+	"1",
+	"123456789",
+	"123456789012345678901234567890123456789012345678901234567890",
+}
+
+func TestBytes(t *testing.T) {
+	for _, test := range bytesTests {
+		x := val(test)
+		bytes := Bytes(x)
+
+		// special case 0
+		if Sign(x) == 0 && len(bytes) != 0 {
+			t.Errorf("%s: got %v; want empty byte slice", test, bytes)
+		}
+
+		if n := len(bytes); n > 0 && bytes[n-1] == 0 {
+			t.Errorf("%s: got %v; want no leading 0 byte", test, bytes)
+		}
+
+		if got := MakeFromBytes(bytes); !eql(got, x) {
+			t.Errorf("%s: got %s; want %s (bytes = %v)", test, got, x, bytes)
+		}
+	}
+}
+
+func TestUnknown(t *testing.T) {
+	u := MakeUnknown()
+	var values = []Value{
+		u,
+		MakeBool(false), // token.ADD ok below, operation is never considered
+		MakeString(""),
+		MakeInt64(1),
+		MakeFromLiteral("-1234567890123456789012345678901234567890", token.INT, 0),
+		MakeFloat64(1.2),
+		MakeImag(MakeFloat64(1.2)),
+	}
+	for _, val := range values {
+		x, y := val, u
+		for i := range [2]int{} {
+			if i == 1 {
+				x, y = y, x
+			}
+			if got := BinaryOp(x, token.ADD, y); got.Kind() != Unknown {
+				t.Errorf("%s + %s: got %s; want %s", x, y, got, u)
+			}
+			if got := Compare(x, token.EQL, y); got {
+				t.Errorf("%s == %s: got true; want false", x, y)
+			}
+		}
+	}
+}
diff --git a/src/go/doc/doc.go b/src/go/doc/doc.go
index 4264940..3c3e28d 100644
--- a/src/go/doc/doc.go
+++ b/src/go/doc/doc.go
@@ -18,7 +18,8 @@ type Package struct {
 	Imports    []string
 	Filenames  []string
 	Notes      map[string][]*Note
-	// DEPRECATED. For backward compatibility Bugs is still populated,
+
+	// Deprecated: For backward compatibility Bugs is still populated,
 	// but all new code should use Notes instead.
 	Bugs []string
 
diff --git a/src/go/doc/exports.go b/src/go/doc/exports.go
index 1d3b466..4a12b1e 100644
--- a/src/go/doc/exports.go
+++ b/src/go/doc/exports.go
@@ -12,13 +12,12 @@ import (
 )
 
 // filterIdentList removes unexported names from list in place
-// and returns the resulting list. If blankOk is set, blank
-// identifiers are considered exported names.
+// and returns the resulting list.
 //
-func filterIdentList(list []*ast.Ident, blankOk bool) []*ast.Ident {
+func filterIdentList(list []*ast.Ident) []*ast.Ident {
 	j := 0
 	for _, x := range list {
-		if ast.IsExported(x.Name) || (blankOk && x.Name == "_") {
+		if ast.IsExported(x.Name) {
 			list[j] = x
 			j++
 		}
@@ -26,6 +25,17 @@ func filterIdentList(list []*ast.Ident, blankOk bool) []*ast.Ident {
 	return list[0:j]
 }
 
+// hasExportedName reports whether list contains any exported names.
+//
+func hasExportedName(list []*ast.Ident) bool {
+	for _, x := range list {
+		if x.IsExported() {
+			return true
+		}
+	}
+	return false
+}
+
 // removeErrorField removes anonymous fields named "error" from an interface.
 // This is called when "error" has been determined to be a local name,
 // not the predeclared type.
@@ -53,7 +63,7 @@ func removeErrorField(ityp *ast.InterfaceType) {
 }
 
 // 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.
 //
@@ -78,7 +88,7 @@ func (r *reader) filterFieldList(parent *namedType, fields *ast.FieldList, ityp
 				r.remember(ityp)
 			}
 		} else {
-			field.Names = filterIdentList(field.Names, false)
+			field.Names = filterIdentList(field.Names)
 			if len(field.Names) < n {
 				removedFields = true
 			}
@@ -146,9 +156,7 @@ func (r *reader) filterSpec(spec ast.Spec, tok token.Token) bool {
 		// always keep imports so we can collect them
 		return true
 	case *ast.ValueSpec:
-		// special case: consider blank constants as exported
-		// (work-around for issue 5397)
-		s.Names = filterIdentList(s.Names, tok == token.CONST)
+		s.Names = filterIdentList(s.Names)
 		if len(s.Names) > 0 {
 			r.filterType(nil, s.Type)
 			return true
@@ -165,7 +173,46 @@ func (r *reader) filterSpec(spec ast.Spec, tok token.Token) bool {
 	return false
 }
 
+// copyConstType returns a copy of typ with position pos.
+// typ must be a valid constant type.
+// In practice, only (possibly qualified) identifiers are possible.
+//
+func copyConstType(typ ast.Expr, pos token.Pos) ast.Expr {
+	switch typ := typ.(type) {
+	case *ast.Ident:
+		return &ast.Ident{Name: typ.Name, NamePos: pos}
+	case *ast.SelectorExpr:
+		if id, ok := typ.X.(*ast.Ident); ok {
+			// presumably a qualified identifier
+			return &ast.SelectorExpr{
+				Sel: ast.NewIdent(typ.Sel.Name),
+				X:   &ast.Ident{Name: id.Name, NamePos: pos},
+			}
+		}
+	}
+	return nil // shouldn't happen, but be conservative and don't panic
+}
+
 func (r *reader) filterSpecList(list []ast.Spec, tok token.Token) []ast.Spec {
+	if tok == token.CONST {
+		// Propagate any type information that would get lost otherwise
+		// when unexported constants are filtered.
+		var prevType ast.Expr
+		for _, spec := range list {
+			spec := spec.(*ast.ValueSpec)
+			if spec.Type == nil && prevType != nil {
+				// provide current spec with an explicit type
+				spec.Type = copyConstType(prevType, spec.Pos())
+			}
+			if hasExportedName(spec.Names) {
+				// exported names are preserved so there's no need to propagate the type
+				prevType = nil
+			} else {
+				prevType = spec.Type
+			}
+		}
+	}
+
 	j := 0
 	for _, s := range list {
 		if r.filterSpec(s, tok) {
diff --git a/src/go/doc/testdata/blank.0.golden b/src/go/doc/testdata/blank.0.golden
index dae3ab2..c2987cf 100644
--- a/src/go/doc/testdata/blank.0.golden
+++ b/src/go/doc/testdata/blank.0.golden
@@ -4,14 +4,33 @@ PACKAGE blank
 IMPORTPATH
 	testdata/blank
 
+IMPORTS
+	os
+
 FILENAMES
 	testdata/blank.go
 
 CONSTANTS
+	// T constants counting from unexported constants. 
+	const (
+		C1	T
+		C2
+	
+		C3
+	
+		C4	int
+	)
+
+	// Constants with an imported type that needs to be propagated. 
+	const (
+		Default		os.FileMode	= 0644
+		Useless				= 0312
+		WideOpen			= 0777
+	)
+
 	// Package constants. 
 	const (
-		_	int	= iota
-		I1
+		I1	int
 		I2
 	)
 
@@ -28,10 +47,9 @@ TYPES
 	// 
 	type T int
 
-	// T constants. 
+	// T constants counting from a blank constant. 
 	const (
-		_	T	= iota
-		T1
+		T1	T
 		T2
 	)
 
diff --git a/src/go/doc/testdata/blank.1.golden b/src/go/doc/testdata/blank.1.golden
index 333d7e5..ee5054a 100644
--- a/src/go/doc/testdata/blank.1.golden
+++ b/src/go/doc/testdata/blank.1.golden
@@ -4,10 +4,25 @@ PACKAGE blank
 IMPORTPATH
 	testdata/blank
 
+IMPORTS
+	os
+
 FILENAMES
 	testdata/blank.go
 
 CONSTANTS
+	// T constants counting from unexported constants. 
+	const (
+		tweedledee	T	= iota
+		tweedledum
+		C1
+		C2
+		alice
+		C3
+		redQueen	int	= iota
+		C4
+	)
+
 	// Package constants. 
 	const (
 		_	int	= iota
@@ -15,6 +30,20 @@ CONSTANTS
 		I2
 	)
 
+	// Constants with an imported type that needs to be propagated. 
+	const (
+		zero		os.FileMode	= 0
+		Default				= 0644
+		Useless				= 0312
+		WideOpen			= 0777
+	)
+
+	// Unexported constants counting from blank iota. See issue 9615. 
+	const (
+		_	= iota
+		one	= iota + 1
+	)
+
 
 VARIABLES
 	// 
@@ -37,7 +66,7 @@ TYPES
 	// 
 	type T int
 
-	// T constants. 
+	// T constants counting from a blank constant. 
 	const (
 		_	T	= iota
 		T1
diff --git a/src/go/doc/testdata/blank.2.golden b/src/go/doc/testdata/blank.2.golden
index dae3ab2..c2987cf 100644
--- a/src/go/doc/testdata/blank.2.golden
+++ b/src/go/doc/testdata/blank.2.golden
@@ -4,14 +4,33 @@ PACKAGE blank
 IMPORTPATH
 	testdata/blank
 
+IMPORTS
+	os
+
 FILENAMES
 	testdata/blank.go
 
 CONSTANTS
+	// T constants counting from unexported constants. 
+	const (
+		C1	T
+		C2
+	
+		C3
+	
+		C4	int
+	)
+
+	// Constants with an imported type that needs to be propagated. 
+	const (
+		Default		os.FileMode	= 0644
+		Useless				= 0312
+		WideOpen			= 0777
+	)
+
 	// Package constants. 
 	const (
-		_	int	= iota
-		I1
+		I1	int
 		I2
 	)
 
@@ -28,10 +47,9 @@ TYPES
 	// 
 	type T int
 
-	// T constants. 
+	// T constants counting from a blank constant. 
 	const (
-		_	T	= iota
-		T1
+		T1	T
 		T2
 	)
 
diff --git a/src/go/doc/testdata/blank.go b/src/go/doc/testdata/blank.go
index f812c77..419a78f 100644
--- a/src/go/doc/testdata/blank.go
+++ b/src/go/doc/testdata/blank.go
@@ -6,15 +6,37 @@
 // See issue 5397.
 package blank
 
+import "os"
+
 type T int
 
-// T constants.
+// T constants counting from a blank constant.
 const (
 	_ T = iota
 	T1
 	T2
 )
 
+// T constants counting from unexported constants.
+const (
+	tweedledee T = iota
+	tweedledum
+	C1
+	C2
+	alice
+	C3
+	redQueen int = iota
+	C4
+)
+
+// Constants with an imported type that needs to be propagated.
+const (
+	zero     os.FileMode = 0
+	Default              = 0644
+	Useless              = 0312
+	WideOpen             = 0777
+)
+
 // Package constants.
 const (
 	_ int = iota
@@ -22,6 +44,13 @@ const (
 	I2
 )
 
+// Unexported constants counting from blank iota.
+// See issue 9615.
+const (
+	_   = iota
+	one = iota + 1
+)
+
 // Blanks not in doc output:
 
 // S has a padding field.
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 @@ import (
 	"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 Node(dst io.Writer, fset *token.FileSet, node interface{}) error {
 //
 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 @@ func Source(src []byte) ([]byte, error) {
 		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 @@ func hasUnsortedImports(file *ast.File) bool {
 	}
 	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/format/format_test.go b/src/go/format/format_test.go
index d7846be..000c611 100644
--- a/src/go/format/format_test.go
+++ b/src/go/format/format_test.go
@@ -91,7 +91,11 @@ var tests = []string{
 	"\n\t\t\n\n\t\t\tx := 0\n\t\t\tconst s = `\n\t\tfoo\n`\n\n\n", // no indentation removed inside raw strings
 
 	// comments
-	"i := 5 /* Comment */", // Issue 5551.
+	"i := 5 /* Comment */",         // Issue 5551.
+	"\ta()\n//line :1",             // Issue 11276.
+	"\t//xxx\n\ta()\n//line :2",    // Issue 11276.
+	"\ta() //line :1\n\tb()\n",     // Issue 11276.
+	"x := 0\n//line :1\n//line :2", // Issue 11276.
 
 	// erroneous programs
 	"ERROR1 + 2 +",
diff --git a/src/go/importer/importer.go b/src/go/importer/importer.go
new file mode 100644
index 0000000..4590ca3
--- /dev/null
+++ b/src/go/importer/importer.go
@@ -0,0 +1,69 @@
+// 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 importer provides access to export data importers.
+package importer
+
+import (
+	"go/internal/gccgoimporter"
+	"go/internal/gcimporter"
+	"go/types"
+	"io"
+	"runtime"
+)
+
+// A Lookup function returns a reader to access package data for
+// a given import path, or an error if no matching package is found.
+type Lookup func(path string) (io.ReadCloser, error)
+
+// For returns an Importer for the given compiler and lookup interface,
+// or nil. Supported compilers are "gc", and "gccgo". If lookup is nil,
+// the default package lookup mechanism for the given compiler is used.
+func For(compiler string, lookup Lookup) types.Importer {
+	switch compiler {
+	case "gc":
+		if lookup == nil {
+			return make(gcimports)
+		}
+		panic("gc importer for custom import path lookup not yet implemented")
+	case "gccgo":
+		if lookup == nil {
+			var inst gccgoimporter.GccgoInstallation
+			if err := inst.InitFromDriver("gccgo"); err != nil {
+				return nil
+			}
+			return &gccgoimports{
+				packages: make(map[string]*types.Package),
+				importer: inst.GetImporter(nil, nil),
+			}
+		}
+		panic("gccgo importer for custom import path lookup not yet implemented")
+	}
+	// compiler not supported
+	return nil
+}
+
+// Default returns an Importer for the compiler that built the running binary.
+func Default() types.Importer {
+	return For(runtime.Compiler, nil)
+}
+
+// gc support
+
+type gcimports map[string]*types.Package
+
+func (m gcimports) Import(path string) (*types.Package, error) {
+	return gcimporter.Import(m, path)
+}
+
+// gccgo support
+
+type gccgoimports struct {
+	packages map[string]*types.Package
+	importer gccgoimporter.Importer
+}
+
+func (m *gccgoimports) Import(path string) (*types.Package, error) {
+	return m.importer(m.packages, path)
+}
diff --git a/src/go/internal/gccgoimporter/gccgoinstallation.go b/src/go/internal/gccgoimporter/gccgoinstallation.go
new file mode 100644
index 0000000..622dfc8
--- /dev/null
+++ b/src/go/internal/gccgoimporter/gccgoinstallation.go
@@ -0,0 +1,94 @@
+// 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 gccgoimporter
+
+import (
+	"bufio"
+	"go/types"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"strings"
+)
+
+// Information about a specific installation of gccgo.
+type GccgoInstallation struct {
+	// Version of gcc (e.g. 4.8.0).
+	GccVersion string
+
+	// Target triple (e.g. x86_64-unknown-linux-gnu).
+	TargetTriple string
+
+	// Built-in library paths used by this installation.
+	LibPaths []string
+}
+
+// Ask the driver at the given path for information for this GccgoInstallation.
+func (inst *GccgoInstallation) InitFromDriver(gccgoPath string) (err error) {
+	cmd := exec.Command(gccgoPath, "-###", "-S", "-x", "go", "-")
+	stderr, err := cmd.StderrPipe()
+	if err != nil {
+		return
+	}
+
+	err = cmd.Start()
+	if err != nil {
+		return
+	}
+
+	scanner := bufio.NewScanner(stderr)
+	for scanner.Scan() {
+		line := scanner.Text()
+		switch {
+		case strings.HasPrefix(line, "Target: "):
+			inst.TargetTriple = line[8:]
+
+		case line[0] == ' ':
+			args := strings.Fields(line)
+			for _, arg := range args[1:] {
+				if strings.HasPrefix(arg, "-L") {
+					inst.LibPaths = append(inst.LibPaths, arg[2:])
+				}
+			}
+		}
+	}
+
+	stdout, err := exec.Command(gccgoPath, "-dumpversion").Output()
+	if err != nil {
+		return
+	}
+	inst.GccVersion = strings.TrimSpace(string(stdout))
+
+	return
+}
+
+// Return the list of export search paths for this GccgoInstallation.
+func (inst *GccgoInstallation) SearchPaths() (paths []string) {
+	for _, lpath := range inst.LibPaths {
+		spath := filepath.Join(lpath, "go", inst.GccVersion)
+		fi, err := os.Stat(spath)
+		if err != nil || !fi.IsDir() {
+			continue
+		}
+		paths = append(paths, spath)
+
+		spath = filepath.Join(spath, inst.TargetTriple)
+		fi, err = os.Stat(spath)
+		if err != nil || !fi.IsDir() {
+			continue
+		}
+		paths = append(paths, spath)
+	}
+
+	paths = append(paths, inst.LibPaths...)
+
+	return
+}
+
+// Return an importer that searches incpaths followed by the gcc installation's
+// built-in search paths and the current directory.
+func (inst *GccgoInstallation) GetImporter(incpaths []string, initmap map[*types.Package]InitData) Importer {
+	return GetImporter(append(append(incpaths, inst.SearchPaths()...), "."), initmap)
+}
diff --git a/src/go/internal/gccgoimporter/gccgoinstallation_test.go b/src/go/internal/gccgoimporter/gccgoinstallation_test.go
new file mode 100644
index 0000000..ef293ed
--- /dev/null
+++ b/src/go/internal/gccgoimporter/gccgoinstallation_test.go
@@ -0,0 +1,193 @@
+// 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 gccgoimporter
+
+import (
+	"go/types"
+	"runtime"
+	"testing"
+)
+
+var importablePackages = [...]string{
+	"archive/tar",
+	"archive/zip",
+	"bufio",
+	"bytes",
+	"compress/bzip2",
+	"compress/flate",
+	"compress/gzip",
+	"compress/lzw",
+	"compress/zlib",
+	"container/heap",
+	"container/list",
+	"container/ring",
+	"crypto/aes",
+	"crypto/cipher",
+	"crypto/des",
+	"crypto/dsa",
+	"crypto/ecdsa",
+	"crypto/elliptic",
+	"crypto",
+	"crypto/hmac",
+	"crypto/md5",
+	"crypto/rand",
+	"crypto/rc4",
+	"crypto/rsa",
+	"crypto/sha1",
+	"crypto/sha256",
+	"crypto/sha512",
+	"crypto/subtle",
+	"crypto/tls",
+	"crypto/x509",
+	"crypto/x509/pkix",
+	"database/sql/driver",
+	"database/sql",
+	"debug/dwarf",
+	"debug/elf",
+	"debug/gosym",
+	"debug/macho",
+	"debug/pe",
+	"encoding/ascii85",
+	"encoding/asn1",
+	"encoding/base32",
+	"encoding/base64",
+	"encoding/binary",
+	"encoding/csv",
+	"encoding/gob",
+	"encoding",
+	"encoding/hex",
+	"encoding/json",
+	"encoding/pem",
+	"encoding/xml",
+	"errors",
+	"exp/proxy",
+	"exp/terminal",
+	"expvar",
+	"flag",
+	"fmt",
+	"go/ast",
+	"go/build",
+	"go/doc",
+	"go/format",
+	"go/parser",
+	"go/printer",
+	"go/scanner",
+	"go/token",
+	"hash/adler32",
+	"hash/crc32",
+	"hash/crc64",
+	"hash/fnv",
+	"hash",
+	"html",
+	"html/template",
+	"image/color",
+	"image/color/palette",
+	"image/draw",
+	"image/gif",
+	"image",
+	"image/jpeg",
+	"image/png",
+	"index/suffixarray",
+	"io",
+	"io/ioutil",
+	"log",
+	"log/syslog",
+	"math/big",
+	"math/cmplx",
+	"math",
+	"math/rand",
+	"mime",
+	"mime/multipart",
+	"net",
+	"net/http/cgi",
+	"net/http/cookiejar",
+	"net/http/fcgi",
+	"net/http",
+	"net/http/httptest",
+	"net/http/httputil",
+	"net/http/pprof",
+	"net/mail",
+	"net/rpc",
+	"net/rpc/jsonrpc",
+	"net/smtp",
+	"net/textproto",
+	"net/url",
+	"old/regexp",
+	"old/template",
+	"os/exec",
+	"os",
+	"os/signal",
+	"os/user",
+	"path/filepath",
+	"path",
+	"reflect",
+	"regexp",
+	"regexp/syntax",
+	"runtime/debug",
+	"runtime",
+	"runtime/pprof",
+	"sort",
+	"strconv",
+	"strings",
+	"sync/atomic",
+	"sync",
+	"syscall",
+	"testing",
+	"testing/iotest",
+	"testing/quick",
+	"text/scanner",
+	"text/tabwriter",
+	"text/template",
+	"text/template/parse",
+	"time",
+	"unicode",
+	"unicode/utf16",
+	"unicode/utf8",
+}
+
+func TestInstallationImporter(t *testing.T) {
+	// This test relies on gccgo being around, which it most likely will be if we
+	// were compiled with gccgo.
+	if runtime.Compiler != "gccgo" {
+		t.Skip("This test needs gccgo")
+		return
+	}
+
+	var inst GccgoInstallation
+	err := inst.InitFromDriver("gccgo")
+	if err != nil {
+		t.Fatal(err)
+	}
+	imp := inst.GetImporter(nil, nil)
+
+	// Ensure we don't regress the number of packages we can parse. First import
+	// all packages into the same map and then each individually.
+	pkgMap := make(map[string]*types.Package)
+	for _, pkg := range importablePackages {
+		_, err = imp(pkgMap, pkg)
+		if err != nil {
+			t.Error(err)
+		}
+	}
+
+	for _, pkg := range importablePackages {
+		_, err = imp(make(map[string]*types.Package), pkg)
+		if err != nil {
+			t.Error(err)
+		}
+	}
+
+	// Test for certain specific entities in the imported data.
+	for _, test := range [...]importerTest{
+		{pkgpath: "io", name: "Reader", want: "type Reader interface{Read(p []uint8) (n int, err error)}"},
+		{pkgpath: "io", name: "ReadWriter", want: "type ReadWriter interface{Reader; Writer}"},
+		{pkgpath: "math", name: "Pi", want: "const Pi untyped float"},
+		{pkgpath: "math", name: "Sin", want: "func Sin(x float64) float64"},
+		{pkgpath: "sort", name: "Ints", want: "func Ints(a []int)"},
+		{pkgpath: "unsafe", name: "Pointer", want: "type Pointer unsafe.Pointer"},
+	} {
+		runImporterTest(t, imp, nil, &test)
+	}
+}
diff --git a/src/go/internal/gccgoimporter/importer.go b/src/go/internal/gccgoimporter/importer.go
new file mode 100644
index 0000000..aa0d01a
--- /dev/null
+++ b/src/go/internal/gccgoimporter/importer.go
@@ -0,0 +1,212 @@
+// 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 gccgoimporter implements Import for gccgo-generated object files.
+package gccgoimporter // import "go/internal/gccgoimporter"
+
+import (
+	"bytes"
+	"debug/elf"
+	"fmt"
+	"go/types"
+	"io"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"strings"
+)
+
+// A PackageInit describes an imported package that needs initialization.
+type PackageInit struct {
+	Name     string // short package name
+	InitFunc string // name of init function
+	Priority int    // priority of init function, see InitData.Priority
+}
+
+// The gccgo-specific init data for a package.
+type InitData struct {
+	// Initialization priority of this package relative to other packages.
+	// This is based on the maximum depth of the package's dependency graph;
+	// it is guaranteed to be greater than that of its dependencies.
+	Priority int
+
+	// The list of packages which this package depends on to be initialized,
+	// including itself if needed. This is the subset of the transitive closure of
+	// the package's dependencies that need initialization.
+	Inits []PackageInit
+}
+
+// Locate the file from which to read export data.
+// This is intended to replicate the logic in gofrontend.
+func findExportFile(searchpaths []string, pkgpath string) (string, error) {
+	for _, spath := range searchpaths {
+		pkgfullpath := filepath.Join(spath, pkgpath)
+		pkgdir, name := filepath.Split(pkgfullpath)
+
+		for _, filepath := range [...]string{
+			pkgfullpath,
+			pkgfullpath + ".gox",
+			pkgdir + "lib" + name + ".so",
+			pkgdir + "lib" + name + ".a",
+			pkgfullpath + ".o",
+		} {
+			fi, err := os.Stat(filepath)
+			if err == nil && !fi.IsDir() {
+				return filepath, nil
+			}
+		}
+	}
+
+	return "", fmt.Errorf("%s: could not find export data (tried %s)", pkgpath, strings.Join(searchpaths, ":"))
+}
+
+const (
+	gccgov1Magic    = "v1;\n"
+	goimporterMagic = "\n$$ "
+	archiveMagic    = "!<ar"
+)
+
+// Opens the export data file at the given path. If this is an ELF file,
+// searches for and opens the .go_export section. If this is an archive,
+// reads the export data from the first member, which is assumed to be an ELF file.
+// This is intended to replicate the logic in gofrontend.
+func openExportFile(fpath string) (reader io.ReadSeeker, closer io.Closer, err error) {
+	f, err := os.Open(fpath)
+	if err != nil {
+		return
+	}
+	closer = f
+	defer func() {
+		if err != nil && closer != nil {
+			f.Close()
+		}
+	}()
+
+	var magic [4]byte
+	_, err = f.ReadAt(magic[:], 0)
+	if err != nil {
+		return
+	}
+	// reset to offset 0 - needed on Plan 9 (see issue #11265)
+	// TODO: remove once issue #11265 has been resolved.
+	_, err = f.Seek(0, 0)
+	if err != nil {
+		return
+	}
+
+	var elfreader io.ReaderAt
+	switch string(magic[:]) {
+	case gccgov1Magic, goimporterMagic:
+		// Raw export data.
+		reader = f
+		return
+
+	case archiveMagic:
+		// TODO(pcc): Read the archive directly instead of using "ar".
+		f.Close()
+		closer = nil
+
+		cmd := exec.Command("ar", "p", fpath)
+		var out []byte
+		out, err = cmd.Output()
+		if err != nil {
+			return
+		}
+
+		elfreader = bytes.NewReader(out)
+
+	default:
+		elfreader = f
+	}
+
+	ef, err := elf.NewFile(elfreader)
+	if err != nil {
+		return
+	}
+
+	sec := ef.Section(".go_export")
+	if sec == nil {
+		err = fmt.Errorf("%s: .go_export section not found", fpath)
+		return
+	}
+
+	reader = sec.Open()
+	return
+}
+
+// An Importer resolves import paths to Packages. The imports map records
+// packages already known, indexed by package path.
+// An importer must determine the canonical package path and check imports
+// to see if it is already present in the map. If so, the Importer can return
+// the map entry. Otherwise, the importer must load the package data for the
+// given path into a new *Package, record it in imports map, and return the
+// package.
+type Importer func(imports map[string]*types.Package, path string) (*types.Package, error)
+
+func GetImporter(searchpaths []string, initmap map[*types.Package]InitData) Importer {
+	return func(imports map[string]*types.Package, pkgpath string) (pkg *types.Package, err error) {
+		if pkgpath == "unsafe" {
+			return types.Unsafe, nil
+		}
+
+		fpath, err := findExportFile(searchpaths, pkgpath)
+		if err != nil {
+			return
+		}
+
+		reader, closer, err := openExportFile(fpath)
+		if err != nil {
+			return
+		}
+		if closer != nil {
+			defer closer.Close()
+		}
+
+		var magic [4]byte
+		_, err = reader.Read(magic[:])
+		if err != nil {
+			return
+		}
+		_, err = reader.Seek(0, 0)
+		if err != nil {
+			return
+		}
+
+		switch string(magic[:]) {
+		case gccgov1Magic:
+			var p parser
+			p.init(fpath, reader, imports)
+			pkg = p.parsePackage()
+			if initmap != nil {
+				initmap[pkg] = p.initdata
+			}
+
+		// Excluded for now: Standard gccgo doesn't support this import format currently.
+		// case goimporterMagic:
+		// 	var data []byte
+		// 	data, err = ioutil.ReadAll(reader)
+		// 	if err != nil {
+		// 		return
+		// 	}
+		// 	var n int
+		// 	n, pkg, err = importer.ImportData(imports, data)
+		// 	if err != nil {
+		// 		return
+		// 	}
+
+		// 	if initmap != nil {
+		// 		suffixreader := bytes.NewReader(data[n:])
+		// 		var p parser
+		// 		p.init(fpath, suffixreader, nil)
+		// 		p.parseInitData()
+		// 		initmap[pkg] = p.initdata
+		// 	}
+
+		default:
+			err = fmt.Errorf("unrecognized magic string: %q", string(magic[:]))
+		}
+
+		return
+	}
+}
diff --git a/src/go/internal/gccgoimporter/importer_test.go b/src/go/internal/gccgoimporter/importer_test.go
new file mode 100644
index 0000000..f3bcadb
--- /dev/null
+++ b/src/go/internal/gccgoimporter/importer_test.go
@@ -0,0 +1,171 @@
+// 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 gccgoimporter
+
+import (
+	"go/types"
+	"internal/testenv"
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"runtime"
+	"testing"
+)
+
+type importerTest struct {
+	pkgpath, name, want, wantval string
+	wantinits                    []string
+}
+
+func runImporterTest(t *testing.T, imp Importer, initmap map[*types.Package]InitData, test *importerTest) {
+	pkg, err := imp(make(map[string]*types.Package), test.pkgpath)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+
+	if test.name != "" {
+		obj := pkg.Scope().Lookup(test.name)
+		if obj == nil {
+			t.Errorf("%s: object not found", test.name)
+			return
+		}
+
+		got := types.ObjectString(obj, types.RelativeTo(pkg))
+		if got != test.want {
+			t.Errorf("%s: got %q; want %q", test.name, got, test.want)
+		}
+
+		if test.wantval != "" {
+			gotval := obj.(*types.Const).Val().String()
+			if gotval != test.wantval {
+				t.Errorf("%s: got val %q; want val %q", test.name, gotval, test.wantval)
+			}
+		}
+	}
+
+	if len(test.wantinits) > 0 {
+		initdata := initmap[pkg]
+		found := false
+		// Check that the package's own init function has the package's priority
+		for _, pkginit := range initdata.Inits {
+			if pkginit.InitFunc == test.wantinits[0] {
+				if initdata.Priority != pkginit.Priority {
+					t.Errorf("%s: got self priority %d; want %d", test.pkgpath, pkginit.Priority, initdata.Priority)
+				}
+				found = true
+				break
+			}
+		}
+
+		if !found {
+			t.Errorf("%s: could not find expected function %q", test.pkgpath, test.wantinits[0])
+		}
+
+		// Each init function in the list other than the first one is a
+		// dependency of the function immediately before it. Check that
+		// the init functions appear in descending priority order.
+		priority := initdata.Priority
+		for _, wantdepinit := range test.wantinits[1:] {
+			found = false
+			for _, pkginit := range initdata.Inits {
+				if pkginit.InitFunc == wantdepinit {
+					if priority <= pkginit.Priority {
+						t.Errorf("%s: got dep priority %d; want less than %d", test.pkgpath, pkginit.Priority, priority)
+					}
+					found = true
+					priority = pkginit.Priority
+					break
+				}
+			}
+
+			if !found {
+				t.Errorf("%s: could not find expected function %q", test.pkgpath, wantdepinit)
+			}
+		}
+	}
+}
+
+var importerTests = [...]importerTest{
+	{pkgpath: "pointer", name: "Int8Ptr", want: "type Int8Ptr *int8"},
+	{pkgpath: "complexnums", name: "NN", want: "const NN untyped complex", wantval: "(-1/1 + -1/1i)"},
+	{pkgpath: "complexnums", name: "NP", want: "const NP untyped complex", wantval: "(-1/1 + 1/1i)"},
+	{pkgpath: "complexnums", name: "PN", want: "const PN untyped complex", wantval: "(1/1 + -1/1i)"},
+	{pkgpath: "complexnums", name: "PP", want: "const PP untyped complex", wantval: "(1/1 + 1/1i)"},
+	// TODO: enable this entry once bug has been tracked down
+	//{pkgpath: "imports", wantinits: []string{"imports..import", "fmt..import", "math..import"}},
+}
+
+func TestGoxImporter(t *testing.T) {
+	testenv.MustHaveGoBuild(t)
+
+	initmap := make(map[*types.Package]InitData)
+	imp := GetImporter([]string{"testdata"}, initmap)
+
+	for _, test := range importerTests {
+		runImporterTest(t, imp, initmap, &test)
+	}
+}
+
+func TestObjImporter(t *testing.T) {
+	testenv.MustHaveGoBuild(t)
+
+	// This test relies on gccgo being around, which it most likely will be if we
+	// were compiled with gccgo.
+	if runtime.Compiler != "gccgo" {
+		t.Skip("This test needs gccgo")
+		return
+	}
+
+	tmpdir, err := ioutil.TempDir("", "")
+	if err != nil {
+		t.Fatal(err)
+	}
+	initmap := make(map[*types.Package]InitData)
+	imp := GetImporter([]string{tmpdir}, initmap)
+
+	artmpdir, err := ioutil.TempDir("", "")
+	if err != nil {
+		t.Fatal(err)
+	}
+	arinitmap := make(map[*types.Package]InitData)
+	arimp := GetImporter([]string{artmpdir}, arinitmap)
+
+	for _, test := range importerTests {
+		gofile := filepath.Join("testdata", test.pkgpath+".go")
+		ofile := filepath.Join(tmpdir, test.pkgpath+".o")
+		afile := filepath.Join(artmpdir, "lib"+test.pkgpath+".a")
+
+		cmd := exec.Command("gccgo", "-fgo-pkgpath="+test.pkgpath, "-c", "-o", ofile, gofile)
+		out, err := cmd.CombinedOutput()
+		if err != nil {
+			t.Logf("%s", out)
+			t.Fatalf("gccgo %s failed: %s", gofile, err)
+		}
+
+		runImporterTest(t, imp, initmap, &test)
+
+		cmd = exec.Command("ar", "cr", afile, ofile)
+		out, err = cmd.CombinedOutput()
+		if err != nil {
+			t.Logf("%s", out)
+			t.Fatalf("ar cr %s %s failed: %s", afile, ofile, err)
+		}
+
+		runImporterTest(t, arimp, arinitmap, &test)
+
+		if err = os.Remove(ofile); err != nil {
+			t.Fatal(err)
+		}
+		if err = os.Remove(afile); err != nil {
+			t.Fatal(err)
+		}
+	}
+
+	if err = os.Remove(tmpdir); err != nil {
+		t.Fatal(err)
+	}
+}
diff --git a/src/go/internal/gccgoimporter/parser.go b/src/go/internal/gccgoimporter/parser.go
new file mode 100644
index 0000000..c06cce4
--- /dev/null
+++ b/src/go/internal/gccgoimporter/parser.go
@@ -0,0 +1,855 @@
+// 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 gccgoimporter
+
+import (
+	"bytes"
+	"errors"
+	"fmt"
+	"go/constant"
+	"go/token"
+	"go/types"
+	"io"
+	"strconv"
+	"strings"
+	"text/scanner"
+)
+
+type parser struct {
+	scanner  scanner.Scanner
+	tok      rune                      // current token
+	lit      string                    // literal string; only valid for Ident, Int, String tokens
+	pkgpath  string                    // package path of imported package
+	pkgname  string                    // name of imported package
+	pkg      *types.Package            // reference to imported package
+	imports  map[string]*types.Package // package path -> package object
+	typeMap  map[int]types.Type        // type number -> type
+	initdata InitData                  // package init priority data
+}
+
+func (p *parser) init(filename string, src io.Reader, imports map[string]*types.Package) {
+	p.scanner.Init(src)
+	p.scanner.Error = func(_ *scanner.Scanner, msg string) { p.error(msg) }
+	p.scanner.Mode = scanner.ScanIdents | scanner.ScanInts | scanner.ScanFloats | scanner.ScanStrings | scanner.ScanComments | scanner.SkipComments
+	p.scanner.Whitespace = 1<<'\t' | 1<<'\n' | 1<<' '
+	p.scanner.Filename = filename // for good error messages
+	p.next()
+	p.imports = imports
+	p.typeMap = make(map[int]types.Type)
+}
+
+type importError struct {
+	pos scanner.Position
+	err error
+}
+
+func (e importError) Error() string {
+	return fmt.Sprintf("import error %s (byte offset = %d): %s", e.pos, e.pos.Offset, e.err)
+}
+
+func (p *parser) error(err interface{}) {
+	if s, ok := err.(string); ok {
+		err = errors.New(s)
+	}
+	// panic with a runtime.Error if err is not an error
+	panic(importError{p.scanner.Pos(), err.(error)})
+}
+
+func (p *parser) errorf(format string, args ...interface{}) {
+	p.error(fmt.Errorf(format, args...))
+}
+
+func (p *parser) expect(tok rune) string {
+	lit := p.lit
+	if p.tok != tok {
+		p.errorf("expected %s, got %s (%s)", scanner.TokenString(tok), scanner.TokenString(p.tok), lit)
+	}
+	p.next()
+	return lit
+}
+
+func (p *parser) expectKeyword(keyword string) {
+	lit := p.expect(scanner.Ident)
+	if lit != keyword {
+		p.errorf("expected keyword %s, got %q", keyword, lit)
+	}
+}
+
+func (p *parser) parseString() string {
+	str, err := strconv.Unquote(p.expect(scanner.String))
+	if err != nil {
+		p.error(err)
+	}
+	return str
+}
+
+// unquotedString     = { unquotedStringChar } .
+// unquotedStringChar = <neither a whitespace nor a ';' char> .
+func (p *parser) parseUnquotedString() string {
+	if p.tok == scanner.EOF {
+		p.error("unexpected EOF")
+	}
+	var buf bytes.Buffer
+	buf.WriteString(p.scanner.TokenText())
+	// This loop needs to examine each character before deciding whether to consume it. If we see a semicolon,
+	// we need to let it be consumed by p.next().
+	for ch := p.scanner.Peek(); ch != ';' && ch != scanner.EOF && p.scanner.Whitespace&(1<<uint(ch)) == 0; ch = p.scanner.Peek() {
+		buf.WriteRune(ch)
+		p.scanner.Next()
+	}
+	p.next()
+	return buf.String()
+}
+
+func (p *parser) next() {
+	p.tok = p.scanner.Scan()
+	switch p.tok {
+	case scanner.Ident, scanner.Int, scanner.Float, scanner.String, '·':
+		p.lit = p.scanner.TokenText()
+	default:
+		p.lit = ""
+	}
+}
+
+func (p *parser) parseQualifiedName() (path, name string) {
+	return p.parseQualifiedNameStr(p.parseString())
+}
+
+func (p *parser) parseUnquotedQualifiedName() (path, name string) {
+	return p.parseQualifiedNameStr(p.parseUnquotedString())
+}
+
+// qualifiedName = [ ["."] unquotedString "." ] unquotedString .
+//
+// The above production uses greedy matching.
+func (p *parser) parseQualifiedNameStr(unquotedName string) (pkgpath, name string) {
+	parts := strings.Split(unquotedName, ".")
+	if parts[0] == "" {
+		parts = parts[1:]
+	}
+
+	switch len(parts) {
+	case 0:
+		p.errorf("malformed qualified name: %q", unquotedName)
+	case 1:
+		// unqualified name
+		pkgpath = p.pkgpath
+		name = parts[0]
+	default:
+		// qualified name, which may contain periods
+		pkgpath = strings.Join(parts[0:len(parts)-1], ".")
+		name = parts[len(parts)-1]
+	}
+
+	return
+}
+
+// getPkg returns the package for a given path. If the package is
+// not found but we have a package name, create the package and
+// add it to the p.imports map.
+//
+func (p *parser) getPkg(pkgpath, name string) *types.Package {
+	// package unsafe is not in the imports map - handle explicitly
+	if pkgpath == "unsafe" {
+		return types.Unsafe
+	}
+	pkg := p.imports[pkgpath]
+	if pkg == nil && name != "" {
+		pkg = types.NewPackage(pkgpath, name)
+		p.imports[pkgpath] = pkg
+	}
+	return pkg
+}
+
+// parseExportedName is like parseQualifiedName, but
+// the package path is resolved to an imported *types.Package.
+//
+// ExportedName = string [string] .
+func (p *parser) parseExportedName() (pkg *types.Package, name string) {
+	path, name := p.parseQualifiedName()
+	var pkgname string
+	if p.tok == scanner.String {
+		pkgname = p.parseString()
+	}
+	pkg = p.getPkg(path, pkgname)
+	if pkg == nil {
+		p.errorf("package %s (path = %q) not found", name, path)
+	}
+	return
+}
+
+// Name = QualifiedName | "?" .
+func (p *parser) parseName() string {
+	if p.tok == '?' {
+		// Anonymous.
+		p.next()
+		return ""
+	}
+	// The package path is redundant for us. Don't try to parse it.
+	_, name := p.parseUnquotedQualifiedName()
+	return name
+}
+
+func deref(typ types.Type) types.Type {
+	if p, _ := typ.(*types.Pointer); p != nil {
+		typ = p.Elem()
+	}
+	return typ
+}
+
+// Field = Name Type [string] .
+func (p *parser) parseField(pkg *types.Package) (field *types.Var, tag string) {
+	name := p.parseName()
+	typ := p.parseType(pkg)
+	anon := false
+	if name == "" {
+		anon = true
+		switch typ := deref(typ).(type) {
+		case *types.Basic:
+			name = typ.Name()
+		case *types.Named:
+			name = typ.Obj().Name()
+		default:
+			p.error("anonymous field expected")
+		}
+	}
+	field = types.NewField(token.NoPos, pkg, name, typ, anon)
+	if p.tok == scanner.String {
+		tag = p.parseString()
+	}
+	return
+}
+
+// Param = Name ["..."] Type .
+func (p *parser) parseParam(pkg *types.Package) (param *types.Var, isVariadic bool) {
+	name := p.parseName()
+	if p.tok == '.' {
+		p.next()
+		p.expect('.')
+		p.expect('.')
+		isVariadic = true
+	}
+	typ := p.parseType(pkg)
+	if isVariadic {
+		typ = types.NewSlice(typ)
+	}
+	param = types.NewParam(token.NoPos, pkg, name, typ)
+	return
+}
+
+// Var = Name Type .
+func (p *parser) parseVar(pkg *types.Package) *types.Var {
+	name := p.parseName()
+	return types.NewVar(token.NoPos, pkg, name, p.parseType(pkg))
+}
+
+// ConstValue     = string | "false" | "true" | ["-"] (int ["'"] | FloatOrComplex) .
+// FloatOrComplex = float ["i" | ("+"|"-") float "i"] .
+func (p *parser) parseConstValue() (val constant.Value, typ types.Type) {
+	switch p.tok {
+	case scanner.String:
+		str := p.parseString()
+		val = constant.MakeString(str)
+		typ = types.Typ[types.UntypedString]
+		return
+
+	case scanner.Ident:
+		b := false
+		switch p.lit {
+		case "false":
+		case "true":
+			b = true
+
+		default:
+			p.errorf("expected const value, got %s (%q)", scanner.TokenString(p.tok), p.lit)
+		}
+
+		p.next()
+		val = constant.MakeBool(b)
+		typ = types.Typ[types.UntypedBool]
+		return
+	}
+
+	sign := ""
+	if p.tok == '-' {
+		p.next()
+		sign = "-"
+	}
+
+	switch p.tok {
+	case scanner.Int:
+		val = constant.MakeFromLiteral(sign+p.lit, token.INT, 0)
+		if val == nil {
+			p.error("could not parse integer literal")
+		}
+
+		p.next()
+		if p.tok == '\'' {
+			p.next()
+			typ = types.Typ[types.UntypedRune]
+		} else {
+			typ = types.Typ[types.UntypedInt]
+		}
+
+	case scanner.Float:
+		re := sign + p.lit
+		p.next()
+
+		var im string
+		switch p.tok {
+		case '+':
+			p.next()
+			im = p.expect(scanner.Float)
+
+		case '-':
+			p.next()
+			im = "-" + p.expect(scanner.Float)
+
+		case scanner.Ident:
+			// re is in fact the imaginary component. Expect "i" below.
+			im = re
+			re = "0"
+
+		default:
+			val = constant.MakeFromLiteral(re, token.FLOAT, 0)
+			if val == nil {
+				p.error("could not parse float literal")
+			}
+			typ = types.Typ[types.UntypedFloat]
+			return
+		}
+
+		p.expectKeyword("i")
+		reval := constant.MakeFromLiteral(re, token.FLOAT, 0)
+		if reval == nil {
+			p.error("could not parse real component of complex literal")
+		}
+		imval := constant.MakeFromLiteral(im+"i", token.IMAG, 0)
+		if imval == nil {
+			p.error("could not parse imag component of complex literal")
+		}
+		val = constant.BinaryOp(reval, token.ADD, imval)
+		typ = types.Typ[types.UntypedComplex]
+
+	default:
+		p.errorf("expected const value, got %s (%q)", scanner.TokenString(p.tok), p.lit)
+	}
+
+	return
+}
+
+// Const = Name [Type] "=" ConstValue .
+func (p *parser) parseConst(pkg *types.Package) *types.Const {
+	name := p.parseName()
+	var typ types.Type
+	if p.tok == '<' {
+		typ = p.parseType(pkg)
+	}
+	p.expect('=')
+	val, vtyp := p.parseConstValue()
+	if typ == nil {
+		typ = vtyp
+	}
+	return types.NewConst(token.NoPos, pkg, name, typ, val)
+}
+
+// TypeName = ExportedName .
+func (p *parser) parseTypeName() *types.TypeName {
+	pkg, name := p.parseExportedName()
+	scope := pkg.Scope()
+	if obj := scope.Lookup(name); obj != nil {
+		return obj.(*types.TypeName)
+	}
+	obj := types.NewTypeName(token.NoPos, pkg, name, nil)
+	// a named type may be referred to before the underlying type
+	// is known - set it up
+	types.NewNamed(obj, nil, nil)
+	scope.Insert(obj)
+	return obj
+}
+
+// NamedType = TypeName Type { Method } .
+// Method    = "func" "(" Param ")" Name ParamList ResultList ";" .
+func (p *parser) parseNamedType(n int) types.Type {
+	obj := p.parseTypeName()
+
+	pkg := obj.Pkg()
+	typ := obj.Type()
+	p.typeMap[n] = typ
+
+	nt, ok := typ.(*types.Named)
+	if !ok {
+		// This can happen for unsafe.Pointer, which is a TypeName holding a Basic type.
+		pt := p.parseType(pkg)
+		if pt != typ {
+			p.error("unexpected underlying type for non-named TypeName")
+		}
+		return typ
+	}
+
+	underlying := p.parseType(pkg)
+	if nt.Underlying() == nil {
+		nt.SetUnderlying(underlying.Underlying())
+	}
+
+	for p.tok == scanner.Ident {
+		// collect associated methods
+		p.expectKeyword("func")
+		p.expect('(')
+		receiver, _ := p.parseParam(pkg)
+		p.expect(')')
+		name := p.parseName()
+		params, isVariadic := p.parseParamList(pkg)
+		results := p.parseResultList(pkg)
+		p.expect(';')
+
+		sig := types.NewSignature(receiver, params, results, isVariadic)
+		nt.AddMethod(types.NewFunc(token.NoPos, pkg, name, sig))
+	}
+
+	return nt
+}
+
+func (p *parser) parseInt() int64 {
+	lit := p.expect(scanner.Int)
+	n, err := strconv.ParseInt(lit, 10, 0)
+	if err != nil {
+		p.error(err)
+	}
+	return n
+}
+
+// ArrayOrSliceType = "[" [ int ] "]" Type .
+func (p *parser) parseArrayOrSliceType(pkg *types.Package) types.Type {
+	p.expect('[')
+	if p.tok == ']' {
+		p.next()
+		return types.NewSlice(p.parseType(pkg))
+	}
+
+	n := p.parseInt()
+	p.expect(']')
+	return types.NewArray(p.parseType(pkg), n)
+}
+
+// MapType = "map" "[" Type "]" Type .
+func (p *parser) parseMapType(pkg *types.Package) types.Type {
+	p.expectKeyword("map")
+	p.expect('[')
+	key := p.parseType(pkg)
+	p.expect(']')
+	elem := p.parseType(pkg)
+	return types.NewMap(key, elem)
+}
+
+// ChanType = "chan" ["<-" | "-<"] Type .
+func (p *parser) parseChanType(pkg *types.Package) types.Type {
+	p.expectKeyword("chan")
+	dir := types.SendRecv
+	switch p.tok {
+	case '-':
+		p.next()
+		p.expect('<')
+		dir = types.SendOnly
+
+	case '<':
+		// don't consume '<' if it belongs to Type
+		if p.scanner.Peek() == '-' {
+			p.next()
+			p.expect('-')
+			dir = types.RecvOnly
+		}
+	}
+
+	return types.NewChan(dir, p.parseType(pkg))
+}
+
+// StructType = "struct" "{" { Field } "}" .
+func (p *parser) parseStructType(pkg *types.Package) types.Type {
+	p.expectKeyword("struct")
+
+	var fields []*types.Var
+	var tags []string
+
+	p.expect('{')
+	for p.tok != '}' && p.tok != scanner.EOF {
+		field, tag := p.parseField(pkg)
+		p.expect(';')
+		fields = append(fields, field)
+		tags = append(tags, tag)
+	}
+	p.expect('}')
+
+	return types.NewStruct(fields, tags)
+}
+
+// ParamList = "(" [ { Parameter "," } Parameter ] ")" .
+func (p *parser) parseParamList(pkg *types.Package) (*types.Tuple, bool) {
+	var list []*types.Var
+	isVariadic := false
+
+	p.expect('(')
+	for p.tok != ')' && p.tok != scanner.EOF {
+		if len(list) > 0 {
+			p.expect(',')
+		}
+		par, variadic := p.parseParam(pkg)
+		list = append(list, par)
+		if variadic {
+			if isVariadic {
+				p.error("... not on final argument")
+			}
+			isVariadic = true
+		}
+	}
+	p.expect(')')
+
+	return types.NewTuple(list...), isVariadic
+}
+
+// ResultList = Type | ParamList .
+func (p *parser) parseResultList(pkg *types.Package) *types.Tuple {
+	switch p.tok {
+	case '<':
+		return types.NewTuple(types.NewParam(token.NoPos, pkg, "", p.parseType(pkg)))
+
+	case '(':
+		params, _ := p.parseParamList(pkg)
+		return params
+
+	default:
+		return nil
+	}
+}
+
+// FunctionType = ParamList ResultList .
+func (p *parser) parseFunctionType(pkg *types.Package) *types.Signature {
+	params, isVariadic := p.parseParamList(pkg)
+	results := p.parseResultList(pkg)
+	return types.NewSignature(nil, params, results, isVariadic)
+}
+
+// Func = Name FunctionType .
+func (p *parser) parseFunc(pkg *types.Package) *types.Func {
+	name := p.parseName()
+	if strings.ContainsRune(name, '$') {
+		// This is a Type$equal or Type$hash function, which we don't want to parse,
+		// except for the types.
+		p.discardDirectiveWhileParsingTypes(pkg)
+		return nil
+	}
+	return types.NewFunc(token.NoPos, pkg, name, p.parseFunctionType(pkg))
+}
+
+// InterfaceType = "interface" "{" { ("?" Type | Func) ";" } "}" .
+func (p *parser) parseInterfaceType(pkg *types.Package) types.Type {
+	p.expectKeyword("interface")
+
+	var methods []*types.Func
+	var typs []*types.Named
+
+	p.expect('{')
+	for p.tok != '}' && p.tok != scanner.EOF {
+		if p.tok == '?' {
+			p.next()
+			typs = append(typs, p.parseType(pkg).(*types.Named))
+		} else {
+			method := p.parseFunc(pkg)
+			methods = append(methods, method)
+		}
+		p.expect(';')
+	}
+	p.expect('}')
+
+	return types.NewInterface(methods, typs)
+}
+
+// PointerType = "*" ("any" | Type) .
+func (p *parser) parsePointerType(pkg *types.Package) types.Type {
+	p.expect('*')
+	if p.tok == scanner.Ident {
+		p.expectKeyword("any")
+		return types.Typ[types.UnsafePointer]
+	}
+	return types.NewPointer(p.parseType(pkg))
+}
+
+// TypeDefinition = NamedType | MapType | ChanType | StructType | InterfaceType | PointerType | ArrayOrSliceType | FunctionType .
+func (p *parser) parseTypeDefinition(pkg *types.Package, n int) types.Type {
+	var t types.Type
+	switch p.tok {
+	case scanner.String:
+		t = p.parseNamedType(n)
+
+	case scanner.Ident:
+		switch p.lit {
+		case "map":
+			t = p.parseMapType(pkg)
+
+		case "chan":
+			t = p.parseChanType(pkg)
+
+		case "struct":
+			t = p.parseStructType(pkg)
+
+		case "interface":
+			t = p.parseInterfaceType(pkg)
+		}
+
+	case '*':
+		t = p.parsePointerType(pkg)
+
+	case '[':
+		t = p.parseArrayOrSliceType(pkg)
+
+	case '(':
+		t = p.parseFunctionType(pkg)
+	}
+
+	p.typeMap[n] = t
+	return t
+}
+
+const (
+	// From gofrontend/go/export.h
+	// Note that these values are negative in the gofrontend and have been made positive
+	// in the gccgoimporter.
+	gccgoBuiltinINT8       = 1
+	gccgoBuiltinINT16      = 2
+	gccgoBuiltinINT32      = 3
+	gccgoBuiltinINT64      = 4
+	gccgoBuiltinUINT8      = 5
+	gccgoBuiltinUINT16     = 6
+	gccgoBuiltinUINT32     = 7
+	gccgoBuiltinUINT64     = 8
+	gccgoBuiltinFLOAT32    = 9
+	gccgoBuiltinFLOAT64    = 10
+	gccgoBuiltinINT        = 11
+	gccgoBuiltinUINT       = 12
+	gccgoBuiltinUINTPTR    = 13
+	gccgoBuiltinBOOL       = 15
+	gccgoBuiltinSTRING     = 16
+	gccgoBuiltinCOMPLEX64  = 17
+	gccgoBuiltinCOMPLEX128 = 18
+	gccgoBuiltinERROR      = 19
+	gccgoBuiltinBYTE       = 20
+	gccgoBuiltinRUNE       = 21
+)
+
+func lookupBuiltinType(typ int) types.Type {
+	return [...]types.Type{
+		gccgoBuiltinINT8:       types.Typ[types.Int8],
+		gccgoBuiltinINT16:      types.Typ[types.Int16],
+		gccgoBuiltinINT32:      types.Typ[types.Int32],
+		gccgoBuiltinINT64:      types.Typ[types.Int64],
+		gccgoBuiltinUINT8:      types.Typ[types.Uint8],
+		gccgoBuiltinUINT16:     types.Typ[types.Uint16],
+		gccgoBuiltinUINT32:     types.Typ[types.Uint32],
+		gccgoBuiltinUINT64:     types.Typ[types.Uint64],
+		gccgoBuiltinFLOAT32:    types.Typ[types.Float32],
+		gccgoBuiltinFLOAT64:    types.Typ[types.Float64],
+		gccgoBuiltinINT:        types.Typ[types.Int],
+		gccgoBuiltinUINT:       types.Typ[types.Uint],
+		gccgoBuiltinUINTPTR:    types.Typ[types.Uintptr],
+		gccgoBuiltinBOOL:       types.Typ[types.Bool],
+		gccgoBuiltinSTRING:     types.Typ[types.String],
+		gccgoBuiltinCOMPLEX64:  types.Typ[types.Complex64],
+		gccgoBuiltinCOMPLEX128: types.Typ[types.Complex128],
+		gccgoBuiltinERROR:      types.Universe.Lookup("error").Type(),
+		gccgoBuiltinBYTE:       types.Universe.Lookup("byte").Type(),
+		gccgoBuiltinRUNE:       types.Universe.Lookup("rune").Type(),
+	}[typ]
+}
+
+// Type = "<" "type" ( "-" int | int [ TypeDefinition ] ) ">" .
+func (p *parser) parseType(pkg *types.Package) (t types.Type) {
+	p.expect('<')
+	p.expectKeyword("type")
+
+	switch p.tok {
+	case scanner.Int:
+		n := p.parseInt()
+
+		if p.tok == '>' {
+			t = p.typeMap[int(n)]
+		} else {
+			t = p.parseTypeDefinition(pkg, int(n))
+		}
+
+	case '-':
+		p.next()
+		n := p.parseInt()
+		t = lookupBuiltinType(int(n))
+
+	default:
+		p.errorf("expected type number, got %s (%q)", scanner.TokenString(p.tok), p.lit)
+		return nil
+	}
+
+	p.expect('>')
+	return
+}
+
+// PackageInit = unquotedString unquotedString int .
+func (p *parser) parsePackageInit() PackageInit {
+	name := p.parseUnquotedString()
+	initfunc := p.parseUnquotedString()
+	priority := int(p.parseInt())
+	return PackageInit{Name: name, InitFunc: initfunc, Priority: priority}
+}
+
+// Throw away tokens until we see a ';'. If we see a '<', attempt to parse as a type.
+func (p *parser) discardDirectiveWhileParsingTypes(pkg *types.Package) {
+	for {
+		switch p.tok {
+		case ';':
+			return
+		case '<':
+			p.parseType(p.pkg)
+		case scanner.EOF:
+			p.error("unexpected EOF")
+		default:
+			p.next()
+		}
+	}
+}
+
+// Create the package if we have parsed both the package path and package name.
+func (p *parser) maybeCreatePackage() {
+	if p.pkgname != "" && p.pkgpath != "" {
+		p.pkg = p.getPkg(p.pkgpath, p.pkgname)
+	}
+}
+
+// InitDataDirective = "v1" ";" |
+//                     "priority" int ";" |
+//                     "init" { PackageInit } ";" |
+//                     "checksum" unquotedString ";" .
+func (p *parser) parseInitDataDirective() {
+	if p.tok != scanner.Ident {
+		// unexpected token kind; panic
+		p.expect(scanner.Ident)
+	}
+
+	switch p.lit {
+	case "v1":
+		p.next()
+		p.expect(';')
+
+	case "priority":
+		p.next()
+		p.initdata.Priority = int(p.parseInt())
+		p.expect(';')
+
+	case "init":
+		p.next()
+		for p.tok != ';' && p.tok != scanner.EOF {
+			p.initdata.Inits = append(p.initdata.Inits, p.parsePackageInit())
+		}
+		p.expect(';')
+
+	case "checksum":
+		// Don't let the scanner try to parse the checksum as a number.
+		defer func(mode uint) {
+			p.scanner.Mode = mode
+		}(p.scanner.Mode)
+		p.scanner.Mode &^= scanner.ScanInts | scanner.ScanFloats
+		p.next()
+		p.parseUnquotedString()
+		p.expect(';')
+
+	default:
+		p.errorf("unexpected identifier: %q", p.lit)
+	}
+}
+
+// Directive = InitDataDirective |
+//             "package" unquotedString ";" |
+//             "pkgpath" unquotedString ";" |
+//             "import" unquotedString unquotedString string ";" |
+//             "func" Func ";" |
+//             "type" Type ";" |
+//             "var" Var ";" |
+//             "const" Const ";" .
+func (p *parser) parseDirective() {
+	if p.tok != scanner.Ident {
+		// unexpected token kind; panic
+		p.expect(scanner.Ident)
+	}
+
+	switch p.lit {
+	case "v1", "priority", "init", "checksum":
+		p.parseInitDataDirective()
+
+	case "package":
+		p.next()
+		p.pkgname = p.parseUnquotedString()
+		p.maybeCreatePackage()
+		p.expect(';')
+
+	case "pkgpath":
+		p.next()
+		p.pkgpath = p.parseUnquotedString()
+		p.maybeCreatePackage()
+		p.expect(';')
+
+	case "import":
+		p.next()
+		pkgname := p.parseUnquotedString()
+		pkgpath := p.parseUnquotedString()
+		p.getPkg(pkgpath, pkgname)
+		p.parseString()
+		p.expect(';')
+
+	case "func":
+		p.next()
+		fun := p.parseFunc(p.pkg)
+		if fun != nil {
+			p.pkg.Scope().Insert(fun)
+		}
+		p.expect(';')
+
+	case "type":
+		p.next()
+		p.parseType(p.pkg)
+		p.expect(';')
+
+	case "var":
+		p.next()
+		v := p.parseVar(p.pkg)
+		p.pkg.Scope().Insert(v)
+		p.expect(';')
+
+	case "const":
+		p.next()
+		c := p.parseConst(p.pkg)
+		p.pkg.Scope().Insert(c)
+		p.expect(';')
+
+	default:
+		p.errorf("unexpected identifier: %q", p.lit)
+	}
+}
+
+// Package = { Directive } .
+func (p *parser) parsePackage() *types.Package {
+	for p.tok != scanner.EOF {
+		p.parseDirective()
+	}
+	for _, typ := range p.typeMap {
+		if it, ok := typ.(*types.Interface); ok {
+			it.Complete()
+		}
+	}
+	p.pkg.MarkComplete()
+	return p.pkg
+}
+
+// InitData = { InitDataDirective } .
+func (p *parser) parseInitData() {
+	for p.tok != scanner.EOF {
+		p.parseInitDataDirective()
+	}
+}
diff --git a/src/go/internal/gccgoimporter/parser_test.go b/src/go/internal/gccgoimporter/parser_test.go
new file mode 100644
index 0000000..b96486f
--- /dev/null
+++ b/src/go/internal/gccgoimporter/parser_test.go
@@ -0,0 +1,72 @@
+// 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 gccgoimporter
+
+import (
+	"bytes"
+	"go/types"
+	"strings"
+	"testing"
+	"text/scanner"
+)
+
+var typeParserTests = []struct {
+	id, typ, want, underlying, methods string
+}{
+	{id: "foo", typ: "<type -1>", want: "int8"},
+	{id: "foo", typ: "<type 1 *<type -19>>", want: "*error"},
+	{id: "foo", typ: "<type 1 *any>", want: "unsafe.Pointer"},
+	{id: "foo", typ: "<type 1 \"Bar\" <type 2 *<type 1>>>", want: "foo.Bar", underlying: "*foo.Bar"},
+	{id: "foo", typ: "<type 1 \"bar.Foo\" \"bar\" <type -1> func (? <type 1>) M (); >", want: "bar.Foo", underlying: "int8", methods: "func (bar.Foo).M()"},
+	{id: "foo", typ: "<type 1 \".bar.foo\" \"bar\" <type -1>>", want: "bar.foo", underlying: "int8"},
+	{id: "foo", typ: "<type 1 []<type -1>>", want: "[]int8"},
+	{id: "foo", typ: "<type 1 [42]<type -1>>", want: "[42]int8"},
+	{id: "foo", typ: "<type 1 map [<type -1>] <type -2>>", want: "map[int8]int16"},
+	{id: "foo", typ: "<type 1 chan <type -1>>", want: "chan int8"},
+	{id: "foo", typ: "<type 1 chan <- <type -1>>", want: "<-chan int8"},
+	{id: "foo", typ: "<type 1 chan -< <type -1>>", want: "chan<- int8"},
+	{id: "foo", typ: "<type 1 struct { I8 <type -1>; I16 <type -2> \"i16\"; }>", want: "struct{I8 int8; I16 int16 \"i16\"}"},
+	{id: "foo", typ: "<type 1 interface { Foo (a <type -1>, b <type -2>) <type -1>; Bar (? <type -2>, ? ...<type -1>) (? <type -2>, ? <type -1>); Baz (); }>", want: "interface{Bar(int16, ...int8) (int16, int8); Baz(); Foo(a int8, b int16) int8}"},
+	{id: "foo", typ: "<type 1 (? <type -1>) <type -2>>", want: "func(int8) int16"},
+}
+
+func TestTypeParser(t *testing.T) {
+	for _, test := range typeParserTests {
+		var p parser
+		p.init("test.gox", strings.NewReader(test.typ), make(map[string]*types.Package))
+		p.pkgname = test.id
+		p.pkgpath = test.id
+		p.maybeCreatePackage()
+		typ := p.parseType(p.pkg)
+
+		if p.tok != scanner.EOF {
+			t.Errorf("expected full parse, stopped at %q", p.lit)
+		}
+
+		got := typ.String()
+		if got != test.want {
+			t.Errorf("got type %q, expected %q", got, test.want)
+		}
+
+		if test.underlying != "" {
+			underlying := typ.Underlying().String()
+			if underlying != test.underlying {
+				t.Errorf("got underlying type %q, expected %q", underlying, test.underlying)
+			}
+		}
+
+		if test.methods != "" {
+			nt := typ.(*types.Named)
+			var buf bytes.Buffer
+			for i := 0; i != nt.NumMethods(); i++ {
+				buf.WriteString(nt.Method(i).String())
+			}
+			methods := buf.String()
+			if methods != test.methods {
+				t.Errorf("got methods %q, expected %q", methods, test.methods)
+			}
+		}
+	}
+}
diff --git a/src/go/internal/gccgoimporter/testdata/complexnums.go b/src/go/internal/gccgoimporter/testdata/complexnums.go
new file mode 100644
index 0000000..a51b6b0
--- /dev/null
+++ b/src/go/internal/gccgoimporter/testdata/complexnums.go
@@ -0,0 +1,6 @@
+package complexnums
+
+const NN = -1 - 1i
+const NP = -1 + 1i
+const PN = 1 - 1i
+const PP = 1 + 1i
diff --git a/src/go/internal/gccgoimporter/testdata/complexnums.gox b/src/go/internal/gccgoimporter/testdata/complexnums.gox
new file mode 100644
index 0000000..b66524f
--- /dev/null
+++ b/src/go/internal/gccgoimporter/testdata/complexnums.gox
@@ -0,0 +1,8 @@
+v1;
+package complexnums;
+pkgpath complexnums;
+priority 1;
+const NN = -0.1E1-0.1E1i ;
+const NP = -0.1E1+0.1E1i ;
+const PN = 0.1E1-0.1E1i ;
+const PP = 0.1E1+0.1E1i ;
diff --git a/src/go/internal/gccgoimporter/testdata/imports.go b/src/go/internal/gccgoimporter/testdata/imports.go
new file mode 100644
index 0000000..7907316
--- /dev/null
+++ b/src/go/internal/gccgoimporter/testdata/imports.go
@@ -0,0 +1,5 @@
+package imports
+
+import "fmt"
+
+var Hello = fmt.Sprintf("Hello, world")
diff --git a/src/go/internal/gccgoimporter/testdata/imports.gox b/src/go/internal/gccgoimporter/testdata/imports.gox
new file mode 100644
index 0000000..958a4f5
--- /dev/null
+++ b/src/go/internal/gccgoimporter/testdata/imports.gox
@@ -0,0 +1,7 @@
+v1;
+package imports;
+pkgpath imports;
+priority 7;
+import fmt fmt "fmt";
+init imports imports..import 7 math math..import 1 runtime runtime..import 1 strconv strconv..import 2 io io..import 3 reflect reflect..import 3 syscall syscall..import 3 time time..import 4 os os..import 5 fmt fmt..import 6;
+var Hello <type -16>;
diff --git a/src/go/internal/gccgoimporter/testdata/pointer.go b/src/go/internal/gccgoimporter/testdata/pointer.go
new file mode 100644
index 0000000..4ebc671
--- /dev/null
+++ b/src/go/internal/gccgoimporter/testdata/pointer.go
@@ -0,0 +1,3 @@
+package pointer
+
+type Int8Ptr *int8
diff --git a/src/go/internal/gccgoimporter/testdata/pointer.gox b/src/go/internal/gccgoimporter/testdata/pointer.gox
new file mode 100644
index 0000000..d96ebbd
--- /dev/null
+++ b/src/go/internal/gccgoimporter/testdata/pointer.gox
@@ -0,0 +1,4 @@
+v1;
+package pointer;
+pkgpath pointer;
+type <type 1 "Int8Ptr" <type 2 *<type -1>>>;
diff --git a/src/go/internal/gcimporter/exportdata.go b/src/go/internal/gcimporter/exportdata.go
new file mode 100644
index 0000000..657742b
--- /dev/null
+++ b/src/go/internal/gcimporter/exportdata.go
@@ -0,0 +1,108 @@
+// 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.
+
+// This file implements FindExportData.
+
+package gcimporter
+
+import (
+	"bufio"
+	"errors"
+	"fmt"
+	"io"
+	"strconv"
+	"strings"
+)
+
+func readGopackHeader(r *bufio.Reader) (name string, size int, err error) {
+	// See $GOROOT/include/ar.h.
+	hdr := make([]byte, 16+12+6+6+8+10+2)
+	_, err = io.ReadFull(r, hdr)
+	if err != nil {
+		return
+	}
+	// leave for debugging
+	if false {
+		fmt.Printf("header: %s", hdr)
+	}
+	s := strings.TrimSpace(string(hdr[16+12+6+6+8:][:10]))
+	size, err = strconv.Atoi(s)
+	if err != nil || hdr[len(hdr)-2] != '`' || hdr[len(hdr)-1] != '\n' {
+		err = errors.New("invalid archive header")
+		return
+	}
+	name = strings.TrimSpace(string(hdr[:16]))
+	return
+}
+
+// FindExportData positions the reader r at the beginning of the
+// export data section of an underlying GC-created object/archive
+// file by reading from it. The reader must be positioned at the
+// start of the file before calling this function.
+//
+func FindExportData(r *bufio.Reader) (err error) {
+	// Read first line to make sure this is an object file.
+	line, err := r.ReadSlice('\n')
+	if err != nil {
+		return
+	}
+	if string(line) == "!<arch>\n" {
+		// Archive file. Scan to __.PKGDEF.
+		var name string
+		var size int
+		if name, size, err = readGopackHeader(r); err != nil {
+			return
+		}
+
+		// Optional leading __.GOSYMDEF or __.SYMDEF.
+		// Read and discard.
+		if name == "__.SYMDEF" || name == "__.GOSYMDEF" {
+			const block = 4096
+			tmp := make([]byte, block)
+			for size > 0 {
+				n := size
+				if n > block {
+					n = block
+				}
+				if _, err = io.ReadFull(r, tmp[:n]); err != nil {
+					return
+				}
+				size -= n
+			}
+
+			if name, size, err = readGopackHeader(r); err != nil {
+				return
+			}
+		}
+
+		// First real entry should be __.PKGDEF.
+		if name != "__.PKGDEF" {
+			err = errors.New("go archive is missing __.PKGDEF")
+			return
+		}
+
+		// Read first line of __.PKGDEF data, so that line
+		// is once again the first line of the input.
+		if line, err = r.ReadSlice('\n'); err != nil {
+			return
+		}
+	}
+
+	// Now at __.PKGDEF in archive or still at beginning of file.
+	// Either way, line should begin with "go object ".
+	if !strings.HasPrefix(string(line), "go object ") {
+		err = errors.New("not a go object file")
+		return
+	}
+
+	// Skip over object header to export data.
+	// Begins after first line with $$.
+	for line[0] != '$' {
+		if line, err = r.ReadSlice('\n'); err != nil {
+			return
+		}
+	}
+
+	return
+}
diff --git a/src/go/internal/gcimporter/gcimporter.go b/src/go/internal/gcimporter/gcimporter.go
new file mode 100644
index 0000000..1d485cf
--- /dev/null
+++ b/src/go/internal/gcimporter/gcimporter.go
@@ -0,0 +1,991 @@
+// 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 gcimporter implements Import for gc-generated object files.
+package gcimporter // import "go/internal/gcimporter"
+
+import (
+	"bufio"
+	"errors"
+	"fmt"
+	"go/build"
+	"go/token"
+	"io"
+	"os"
+	"path/filepath"
+	"sort"
+	"strconv"
+	"strings"
+	"text/scanner"
+
+	exact "go/constant"
+	"go/types"
+)
+
+// debugging/development support
+const debug = false
+
+var pkgExts = [...]string{".a", ".o"}
+
+// FindPkg returns the filename and unique package id for an import
+// path based on package information provided by build.Import (using
+// the build.Default build.Context).
+// If no file was found, an empty filename is returned.
+//
+func FindPkg(path, srcDir string) (filename, id string) {
+	if len(path) == 0 {
+		return
+	}
+
+	id = path
+	var noext string
+	switch {
+	default:
+		// "x" -> "$GOPATH/pkg/$GOOS_$GOARCH/x.ext", "x"
+		// Don't require the source files to be present.
+		bp, _ := build.Import(path, srcDir, build.FindOnly|build.AllowBinary)
+		if bp.PkgObj == "" {
+			return
+		}
+		noext = strings.TrimSuffix(bp.PkgObj, ".a")
+
+	case build.IsLocalImport(path):
+		// "./x" -> "/this/directory/x.ext", "/this/directory/x"
+		noext = filepath.Join(srcDir, path)
+		id = noext
+
+	case filepath.IsAbs(path):
+		// for completeness only - go/build.Import
+		// does not support absolute imports
+		// "/x" -> "/x.ext", "/x"
+		noext = path
+	}
+
+	// try extensions
+	for _, ext := range pkgExts {
+		filename = noext + ext
+		if f, err := os.Stat(filename); err == nil && !f.IsDir() {
+			return
+		}
+	}
+
+	filename = "" // not found
+	return
+}
+
+// ImportData imports a package by reading the gc-generated export data,
+// adds the corresponding package object to the packages map indexed by id,
+// and returns the object.
+//
+// The packages map must contains all packages already imported. The data
+// reader position must be the beginning of the export data section. The
+// filename is only used in error messages.
+//
+// If packages[id] contains the completely imported package, that package
+// can be used directly, and there is no need to call this function (but
+// there is also no harm but for extra time used).
+//
+func ImportData(packages map[string]*types.Package, filename, id string, data io.Reader) (pkg *types.Package, err error) {
+	// support for parser error handling
+	defer func() {
+		switch r := recover().(type) {
+		case nil:
+			// nothing to do
+		case importError:
+			err = r
+		default:
+			panic(r) // internal error
+		}
+	}()
+
+	var p parser
+	p.init(filename, id, data, packages)
+	pkg = p.parseExport()
+
+	return
+}
+
+// Import imports a gc-generated package given its import path, adds the
+// corresponding package object to the packages map, and returns the object.
+// Local import paths are interpreted relative to the current working directory.
+// The packages map must contain all packages already imported.
+//
+func Import(packages map[string]*types.Package, path string) (pkg *types.Package, err error) {
+	// package "unsafe" is handled by the type checker
+	if path == "unsafe" {
+		panic(`gcimporter.Import called for package "unsafe"`)
+	}
+
+	srcDir := "."
+	if build.IsLocalImport(path) {
+		srcDir, err = os.Getwd()
+		if err != nil {
+			return
+		}
+	}
+
+	filename, id := FindPkg(path, srcDir)
+	if filename == "" {
+		err = fmt.Errorf("can't find import: %s", id)
+		return
+	}
+
+	// no need to re-import if the package was imported completely before
+	if pkg = packages[id]; pkg != nil && pkg.Complete() {
+		return
+	}
+
+	// open file
+	f, err := os.Open(filename)
+	if err != nil {
+		return
+	}
+	defer func() {
+		f.Close()
+		if err != nil {
+			// add file name to error
+			err = fmt.Errorf("reading export data: %s: %v", filename, err)
+		}
+	}()
+
+	buf := bufio.NewReader(f)
+	if err = FindExportData(buf); err != nil {
+		return
+	}
+
+	pkg, err = ImportData(packages, filename, id, buf)
+
+	return
+}
+
+// ----------------------------------------------------------------------------
+// Parser
+
+// TODO(gri) Imported objects don't have position information.
+//           Ideally use the debug table line info; alternatively
+//           create some fake position (or the position of the
+//           import). That way error messages referring to imported
+//           objects can print meaningful information.
+
+// parser parses the exports inside a gc compiler-produced
+// object/archive file and populates its scope with the results.
+type parser struct {
+	scanner    scanner.Scanner
+	tok        rune                      // current token
+	lit        string                    // literal string; only valid for Ident, Int, String tokens
+	id         string                    // package id of imported package
+	sharedPkgs map[string]*types.Package // package id -> package object (across importer)
+	localPkgs  map[string]*types.Package // package id -> package object (just this package)
+}
+
+func (p *parser) init(filename, id string, src io.Reader, packages map[string]*types.Package) {
+	p.scanner.Init(src)
+	p.scanner.Error = func(_ *scanner.Scanner, msg string) { p.error(msg) }
+	p.scanner.Mode = scanner.ScanIdents | scanner.ScanInts | scanner.ScanChars | scanner.ScanStrings | scanner.ScanComments | scanner.SkipComments
+	p.scanner.Whitespace = 1<<'\t' | 1<<' '
+	p.scanner.Filename = filename // for good error messages
+	p.next()
+	p.id = id
+	p.sharedPkgs = packages
+	if debug {
+		// check consistency of packages map
+		for _, pkg := range packages {
+			if pkg.Name() == "" {
+				fmt.Printf("no package name for %s\n", pkg.Path())
+			}
+		}
+	}
+}
+
+func (p *parser) next() {
+	p.tok = p.scanner.Scan()
+	switch p.tok {
+	case scanner.Ident, scanner.Int, scanner.Char, scanner.String, '·':
+		p.lit = p.scanner.TokenText()
+	default:
+		p.lit = ""
+	}
+	if debug {
+		fmt.Printf("%s: %q -> %q\n", scanner.TokenString(p.tok), p.scanner.TokenText(), p.lit)
+	}
+}
+
+func declTypeName(pkg *types.Package, name string) *types.TypeName {
+	scope := pkg.Scope()
+	if obj := scope.Lookup(name); obj != nil {
+		return obj.(*types.TypeName)
+	}
+	obj := types.NewTypeName(token.NoPos, pkg, name, nil)
+	// a named type may be referred to before the underlying type
+	// is known - set it up
+	types.NewNamed(obj, nil, nil)
+	scope.Insert(obj)
+	return obj
+}
+
+// ----------------------------------------------------------------------------
+// Error handling
+
+// Internal errors are boxed as importErrors.
+type importError struct {
+	pos scanner.Position
+	err error
+}
+
+func (e importError) Error() string {
+	return fmt.Sprintf("import error %s (byte offset = %d): %s", e.pos, e.pos.Offset, e.err)
+}
+
+func (p *parser) error(err interface{}) {
+	if s, ok := err.(string); ok {
+		err = errors.New(s)
+	}
+	// panic with a runtime.Error if err is not an error
+	panic(importError{p.scanner.Pos(), err.(error)})
+}
+
+func (p *parser) errorf(format string, args ...interface{}) {
+	p.error(fmt.Sprintf(format, args...))
+}
+
+func (p *parser) expect(tok rune) string {
+	lit := p.lit
+	if p.tok != tok {
+		p.errorf("expected %s, got %s (%s)", scanner.TokenString(tok), scanner.TokenString(p.tok), lit)
+	}
+	p.next()
+	return lit
+}
+
+func (p *parser) expectSpecial(tok string) {
+	sep := 'x' // not white space
+	i := 0
+	for i < len(tok) && p.tok == rune(tok[i]) && sep > ' ' {
+		sep = p.scanner.Peek() // if sep <= ' ', there is white space before the next token
+		p.next()
+		i++
+	}
+	if i < len(tok) {
+		p.errorf("expected %q, got %q", tok, tok[0:i])
+	}
+}
+
+func (p *parser) expectKeyword(keyword string) {
+	lit := p.expect(scanner.Ident)
+	if lit != keyword {
+		p.errorf("expected keyword %s, got %q", keyword, lit)
+	}
+}
+
+// ----------------------------------------------------------------------------
+// Qualified and unqualified names
+
+// PackageId = string_lit .
+//
+func (p *parser) parsePackageId() string {
+	id, err := strconv.Unquote(p.expect(scanner.String))
+	if err != nil {
+		p.error(err)
+	}
+	// id == "" stands for the imported package id
+	// (only known at time of package installation)
+	if id == "" {
+		id = p.id
+	}
+	return id
+}
+
+// PackageName = ident .
+//
+func (p *parser) parsePackageName() string {
+	return p.expect(scanner.Ident)
+}
+
+// dotIdentifier = ( ident | '·' ) { ident | int | '·' } .
+func (p *parser) parseDotIdent() string {
+	ident := ""
+	if p.tok != scanner.Int {
+		sep := 'x' // not white space
+		for (p.tok == scanner.Ident || p.tok == scanner.Int || p.tok == '·') && sep > ' ' {
+			ident += p.lit
+			sep = p.scanner.Peek() // if sep <= ' ', there is white space before the next token
+			p.next()
+		}
+	}
+	if ident == "" {
+		p.expect(scanner.Ident) // use expect() for error handling
+	}
+	return ident
+}
+
+// QualifiedName = "@" PackageId "." ( "?" | dotIdentifier ) .
+//
+func (p *parser) parseQualifiedName() (id, name string) {
+	p.expect('@')
+	id = p.parsePackageId()
+	p.expect('.')
+	// Per rev f280b8a485fd (10/2/2013), qualified names may be used for anonymous fields.
+	if p.tok == '?' {
+		p.next()
+	} else {
+		name = p.parseDotIdent()
+	}
+	return
+}
+
+// getPkg returns the package for a given id. If the package is
+// not found but we have a package name, create the package and
+// add it to the p.localPkgs and p.sharedPkgs maps.
+//
+// id identifies a package, usually by a canonical package path like
+// "encoding/json" but possibly by a non-canonical import path like
+// "./json".
+//
+func (p *parser) getPkg(id, name string) *types.Package {
+	// package unsafe is not in the packages maps - handle explicitly
+	if id == "unsafe" {
+		return types.Unsafe
+	}
+
+	pkg := p.localPkgs[id]
+	if pkg == nil && name != "" {
+		// first import of id from this package
+		pkg = p.sharedPkgs[id]
+		if pkg == nil {
+			// first import of id by this importer
+			pkg = types.NewPackage(id, name)
+			p.sharedPkgs[id] = pkg
+		}
+
+		if p.localPkgs == nil {
+			p.localPkgs = make(map[string]*types.Package)
+		}
+		p.localPkgs[id] = pkg
+	}
+	return pkg
+}
+
+// parseExportedName is like parseQualifiedName, but
+// the package id is resolved to an imported *types.Package.
+//
+func (p *parser) parseExportedName() (pkg *types.Package, name string) {
+	id, name := p.parseQualifiedName()
+	pkg = p.getPkg(id, "")
+	if pkg == nil {
+		p.errorf("%s package not found", id)
+	}
+	return
+}
+
+// ----------------------------------------------------------------------------
+// Types
+
+// BasicType = identifier .
+//
+func (p *parser) parseBasicType() types.Type {
+	id := p.expect(scanner.Ident)
+	obj := types.Universe.Lookup(id)
+	if obj, ok := obj.(*types.TypeName); ok {
+		return obj.Type()
+	}
+	p.errorf("not a basic type: %s", id)
+	return nil
+}
+
+// ArrayType = "[" int_lit "]" Type .
+//
+func (p *parser) parseArrayType() types.Type {
+	// "[" already consumed and lookahead known not to be "]"
+	lit := p.expect(scanner.Int)
+	p.expect(']')
+	elem := p.parseType()
+	n, err := strconv.ParseInt(lit, 10, 64)
+	if err != nil {
+		p.error(err)
+	}
+	return types.NewArray(elem, n)
+}
+
+// MapType = "map" "[" Type "]" Type .
+//
+func (p *parser) parseMapType() types.Type {
+	p.expectKeyword("map")
+	p.expect('[')
+	key := p.parseType()
+	p.expect(']')
+	elem := p.parseType()
+	return types.NewMap(key, elem)
+}
+
+// Name = identifier | "?" | QualifiedName .
+//
+// If materializePkg is set, the returned package is guaranteed to be set.
+// For fully qualified names, the returned package may be a fake package
+// (without name, scope, and not in the p.sharedPkgs map), created for the
+// sole purpose of providing a package path. Fake packages are created
+// when the package id is not found in the p.sharedPkgs map; in that case
+// we cannot create a real package because we don't have a package name.
+// For non-qualified names, the returned package is the imported package.
+//
+func (p *parser) parseName(materializePkg bool) (pkg *types.Package, name string) {
+	switch p.tok {
+	case scanner.Ident:
+		pkg = p.sharedPkgs[p.id]
+		name = p.lit
+		p.next()
+	case '?':
+		// anonymous
+		pkg = p.sharedPkgs[p.id]
+		p.next()
+	case '@':
+		// exported name prefixed with package path
+		var id string
+		id, name = p.parseQualifiedName()
+		if materializePkg {
+			// we don't have a package name - if the package
+			// doesn't exist yet, create a fake package instead
+			pkg = p.getPkg(id, "")
+			if pkg == nil {
+				pkg = types.NewPackage(id, "")
+			}
+		}
+	default:
+		p.error("name expected")
+	}
+	return
+}
+
+func deref(typ types.Type) types.Type {
+	if p, _ := typ.(*types.Pointer); p != nil {
+		return p.Elem()
+	}
+	return typ
+}
+
+// Field = Name Type [ string_lit ] .
+//
+func (p *parser) parseField() (*types.Var, string) {
+	pkg, name := p.parseName(true)
+	typ := p.parseType()
+	anonymous := false
+	if name == "" {
+		// anonymous field - typ must be T or *T and T must be a type name
+		switch typ := deref(typ).(type) {
+		case *types.Basic: // basic types are named types
+			pkg = nil
+			name = typ.Name()
+		case *types.Named:
+			name = typ.Obj().Name()
+		default:
+			p.errorf("anonymous field expected")
+		}
+		anonymous = true
+	}
+	tag := ""
+	if p.tok == scanner.String {
+		s := p.expect(scanner.String)
+		var err error
+		tag, err = strconv.Unquote(s)
+		if err != nil {
+			p.errorf("invalid struct tag %s: %s", s, err)
+		}
+	}
+	return types.NewField(token.NoPos, pkg, name, typ, anonymous), tag
+}
+
+// StructType = "struct" "{" [ FieldList ] "}" .
+// FieldList  = Field { ";" Field } .
+//
+func (p *parser) parseStructType() types.Type {
+	var fields []*types.Var
+	var tags []string
+
+	p.expectKeyword("struct")
+	p.expect('{')
+	for i := 0; p.tok != '}' && p.tok != scanner.EOF; i++ {
+		if i > 0 {
+			p.expect(';')
+		}
+		fld, tag := p.parseField()
+		if tag != "" && tags == nil {
+			tags = make([]string, i)
+		}
+		if tags != nil {
+			tags = append(tags, tag)
+		}
+		fields = append(fields, fld)
+	}
+	p.expect('}')
+
+	return types.NewStruct(fields, tags)
+}
+
+// Parameter = ( identifier | "?" ) [ "..." ] Type [ string_lit ] .
+//
+func (p *parser) parseParameter() (par *types.Var, isVariadic bool) {
+	_, name := p.parseName(false)
+	// remove gc-specific parameter numbering
+	if i := strings.Index(name, "·"); i >= 0 {
+		name = name[:i]
+	}
+	if p.tok == '.' {
+		p.expectSpecial("...")
+		isVariadic = true
+	}
+	typ := p.parseType()
+	if isVariadic {
+		typ = types.NewSlice(typ)
+	}
+	// ignore argument tag (e.g. "noescape")
+	if p.tok == scanner.String {
+		p.next()
+	}
+	// TODO(gri) should we provide a package?
+	par = types.NewVar(token.NoPos, nil, name, typ)
+	return
+}
+
+// Parameters    = "(" [ ParameterList ] ")" .
+// ParameterList = { Parameter "," } Parameter .
+//
+func (p *parser) parseParameters() (list []*types.Var, isVariadic bool) {
+	p.expect('(')
+	for p.tok != ')' && p.tok != scanner.EOF {
+		if len(list) > 0 {
+			p.expect(',')
+		}
+		par, variadic := p.parseParameter()
+		list = append(list, par)
+		if variadic {
+			if isVariadic {
+				p.error("... not on final argument")
+			}
+			isVariadic = true
+		}
+	}
+	p.expect(')')
+
+	return
+}
+
+// Signature = Parameters [ Result ] .
+// Result    = Type | Parameters .
+//
+func (p *parser) parseSignature(recv *types.Var) *types.Signature {
+	params, isVariadic := p.parseParameters()
+
+	// optional result type
+	var results []*types.Var
+	if p.tok == '(' {
+		var variadic bool
+		results, variadic = p.parseParameters()
+		if variadic {
+			p.error("... not permitted on result type")
+		}
+	}
+
+	return types.NewSignature(recv, types.NewTuple(params...), types.NewTuple(results...), isVariadic)
+}
+
+// InterfaceType = "interface" "{" [ MethodList ] "}" .
+// MethodList    = Method { ";" Method } .
+// Method        = Name Signature .
+//
+// The methods of embedded interfaces are always "inlined"
+// by the compiler and thus embedded interfaces are never
+// visible in the export data.
+//
+func (p *parser) parseInterfaceType() types.Type {
+	var methods []*types.Func
+
+	p.expectKeyword("interface")
+	p.expect('{')
+	for i := 0; p.tok != '}' && p.tok != scanner.EOF; i++ {
+		if i > 0 {
+			p.expect(';')
+		}
+		pkg, name := p.parseName(true)
+		sig := p.parseSignature(nil)
+		methods = append(methods, types.NewFunc(token.NoPos, pkg, name, sig))
+	}
+	p.expect('}')
+
+	// Complete requires the type's embedded interfaces to be fully defined,
+	// but we do not define any
+	return types.NewInterface(methods, nil).Complete()
+}
+
+// ChanType = ( "chan" [ "<-" ] | "<-" "chan" ) Type .
+//
+func (p *parser) parseChanType() types.Type {
+	dir := types.SendRecv
+	if p.tok == scanner.Ident {
+		p.expectKeyword("chan")
+		if p.tok == '<' {
+			p.expectSpecial("<-")
+			dir = types.SendOnly
+		}
+	} else {
+		p.expectSpecial("<-")
+		p.expectKeyword("chan")
+		dir = types.RecvOnly
+	}
+	elem := p.parseType()
+	return types.NewChan(dir, elem)
+}
+
+// Type =
+//	BasicType | TypeName | ArrayType | SliceType | StructType |
+//      PointerType | FuncType | InterfaceType | MapType | ChanType |
+//      "(" Type ")" .
+//
+// BasicType   = ident .
+// TypeName    = ExportedName .
+// SliceType   = "[" "]" Type .
+// PointerType = "*" Type .
+// FuncType    = "func" Signature .
+//
+func (p *parser) parseType() types.Type {
+	switch p.tok {
+	case scanner.Ident:
+		switch p.lit {
+		default:
+			return p.parseBasicType()
+		case "struct":
+			return p.parseStructType()
+		case "func":
+			// FuncType
+			p.next()
+			return p.parseSignature(nil)
+		case "interface":
+			return p.parseInterfaceType()
+		case "map":
+			return p.parseMapType()
+		case "chan":
+			return p.parseChanType()
+		}
+	case '@':
+		// TypeName
+		pkg, name := p.parseExportedName()
+		return declTypeName(pkg, name).Type()
+	case '[':
+		p.next() // look ahead
+		if p.tok == ']' {
+			// SliceType
+			p.next()
+			return types.NewSlice(p.parseType())
+		}
+		return p.parseArrayType()
+	case '*':
+		// PointerType
+		p.next()
+		return types.NewPointer(p.parseType())
+	case '<':
+		return p.parseChanType()
+	case '(':
+		// "(" Type ")"
+		p.next()
+		typ := p.parseType()
+		p.expect(')')
+		return typ
+	}
+	p.errorf("expected type, got %s (%q)", scanner.TokenString(p.tok), p.lit)
+	return nil
+}
+
+// ----------------------------------------------------------------------------
+// Declarations
+
+// ImportDecl = "import" PackageName PackageId .
+//
+func (p *parser) parseImportDecl() {
+	p.expectKeyword("import")
+	name := p.parsePackageName()
+	p.getPkg(p.parsePackageId(), name)
+}
+
+// int_lit = [ "+" | "-" ] { "0" ... "9" } .
+//
+func (p *parser) parseInt() string {
+	s := ""
+	switch p.tok {
+	case '-':
+		s = "-"
+		p.next()
+	case '+':
+		p.next()
+	}
+	return s + p.expect(scanner.Int)
+}
+
+// number = int_lit [ "p" int_lit ] .
+//
+func (p *parser) parseNumber() (typ *types.Basic, val exact.Value) {
+	// mantissa
+	mant := exact.MakeFromLiteral(p.parseInt(), token.INT, 0)
+	if mant == nil {
+		panic("invalid mantissa")
+	}
+
+	if p.lit == "p" {
+		// exponent (base 2)
+		p.next()
+		exp, err := strconv.ParseInt(p.parseInt(), 10, 0)
+		if err != nil {
+			p.error(err)
+		}
+		if exp < 0 {
+			denom := exact.MakeInt64(1)
+			denom = exact.Shift(denom, token.SHL, uint(-exp))
+			typ = types.Typ[types.UntypedFloat]
+			val = exact.BinaryOp(mant, token.QUO, denom)
+			return
+		}
+		if exp > 0 {
+			mant = exact.Shift(mant, token.SHL, uint(exp))
+		}
+		typ = types.Typ[types.UntypedFloat]
+		val = mant
+		return
+	}
+
+	typ = types.Typ[types.UntypedInt]
+	val = mant
+	return
+}
+
+// ConstDecl   = "const" ExportedName [ Type ] "=" Literal .
+// Literal     = bool_lit | int_lit | float_lit | complex_lit | rune_lit | string_lit .
+// bool_lit    = "true" | "false" .
+// complex_lit = "(" float_lit "+" float_lit "i" ")" .
+// rune_lit    = "(" int_lit "+" int_lit ")" .
+// string_lit  = `"` { unicode_char } `"` .
+//
+func (p *parser) parseConstDecl() {
+	p.expectKeyword("const")
+	pkg, name := p.parseExportedName()
+
+	var typ0 types.Type
+	if p.tok != '=' {
+		typ0 = p.parseType()
+	}
+
+	p.expect('=')
+	var typ types.Type
+	var val exact.Value
+	switch p.tok {
+	case scanner.Ident:
+		// bool_lit
+		if p.lit != "true" && p.lit != "false" {
+			p.error("expected true or false")
+		}
+		typ = types.Typ[types.UntypedBool]
+		val = exact.MakeBool(p.lit == "true")
+		p.next()
+
+	case '-', scanner.Int:
+		// int_lit
+		typ, val = p.parseNumber()
+
+	case '(':
+		// complex_lit or rune_lit
+		p.next()
+		if p.tok == scanner.Char {
+			p.next()
+			p.expect('+')
+			typ = types.Typ[types.UntypedRune]
+			_, val = p.parseNumber()
+			p.expect(')')
+			break
+		}
+		_, re := p.parseNumber()
+		p.expect('+')
+		_, im := p.parseNumber()
+		p.expectKeyword("i")
+		p.expect(')')
+		typ = types.Typ[types.UntypedComplex]
+		val = exact.BinaryOp(re, token.ADD, exact.MakeImag(im))
+
+	case scanner.Char:
+		// rune_lit
+		typ = types.Typ[types.UntypedRune]
+		val = exact.MakeFromLiteral(p.lit, token.CHAR, 0)
+		p.next()
+
+	case scanner.String:
+		// string_lit
+		typ = types.Typ[types.UntypedString]
+		val = exact.MakeFromLiteral(p.lit, token.STRING, 0)
+		p.next()
+
+	default:
+		p.errorf("expected literal got %s", scanner.TokenString(p.tok))
+	}
+
+	if typ0 == nil {
+		typ0 = typ
+	}
+
+	pkg.Scope().Insert(types.NewConst(token.NoPos, pkg, name, typ0, val))
+}
+
+// TypeDecl = "type" ExportedName Type .
+//
+func (p *parser) parseTypeDecl() {
+	p.expectKeyword("type")
+	pkg, name := p.parseExportedName()
+	obj := declTypeName(pkg, name)
+
+	// The type object may have been imported before and thus already
+	// have a type associated with it. We still need to parse the type
+	// structure, but throw it away if the object already has a type.
+	// This ensures that all imports refer to the same type object for
+	// a given type declaration.
+	typ := p.parseType()
+
+	if name := obj.Type().(*types.Named); name.Underlying() == nil {
+		name.SetUnderlying(typ)
+	}
+}
+
+// VarDecl = "var" ExportedName Type .
+//
+func (p *parser) parseVarDecl() {
+	p.expectKeyword("var")
+	pkg, name := p.parseExportedName()
+	typ := p.parseType()
+	pkg.Scope().Insert(types.NewVar(token.NoPos, pkg, name, typ))
+}
+
+// Func = Signature [ Body ] .
+// Body = "{" ... "}" .
+//
+func (p *parser) parseFunc(recv *types.Var) *types.Signature {
+	sig := p.parseSignature(recv)
+	if p.tok == '{' {
+		p.next()
+		for i := 1; i > 0; p.next() {
+			switch p.tok {
+			case '{':
+				i++
+			case '}':
+				i--
+			}
+		}
+	}
+	return sig
+}
+
+// MethodDecl = "func" Receiver Name Func .
+// Receiver   = "(" ( identifier | "?" ) [ "*" ] ExportedName ")" .
+//
+func (p *parser) parseMethodDecl() {
+	// "func" already consumed
+	p.expect('(')
+	recv, _ := p.parseParameter() // receiver
+	p.expect(')')
+
+	// determine receiver base type object
+	base := deref(recv.Type()).(*types.Named)
+
+	// parse method name, signature, and possibly inlined body
+	_, name := p.parseName(true)
+	sig := p.parseFunc(recv)
+
+	// methods always belong to the same package as the base type object
+	pkg := base.Obj().Pkg()
+
+	// add method to type unless type was imported before
+	// and method exists already
+	// TODO(gri) This leads to a quadratic algorithm - ok for now because method counts are small.
+	base.AddMethod(types.NewFunc(token.NoPos, pkg, name, sig))
+}
+
+// FuncDecl = "func" ExportedName Func .
+//
+func (p *parser) parseFuncDecl() {
+	// "func" already consumed
+	pkg, name := p.parseExportedName()
+	typ := p.parseFunc(nil)
+	pkg.Scope().Insert(types.NewFunc(token.NoPos, pkg, name, typ))
+}
+
+// Decl = [ ImportDecl | ConstDecl | TypeDecl | VarDecl | FuncDecl | MethodDecl ] "\n" .
+//
+func (p *parser) parseDecl() {
+	if p.tok == scanner.Ident {
+		switch p.lit {
+		case "import":
+			p.parseImportDecl()
+		case "const":
+			p.parseConstDecl()
+		case "type":
+			p.parseTypeDecl()
+		case "var":
+			p.parseVarDecl()
+		case "func":
+			p.next() // look ahead
+			if p.tok == '(' {
+				p.parseMethodDecl()
+			} else {
+				p.parseFuncDecl()
+			}
+		}
+	}
+	p.expect('\n')
+}
+
+// ----------------------------------------------------------------------------
+// Export
+
+// Export        = "PackageClause { Decl } "$$" .
+// PackageClause = "package" PackageName [ "safe" ] "\n" .
+//
+func (p *parser) parseExport() *types.Package {
+	p.expectKeyword("package")
+	name := p.parsePackageName()
+	if p.tok == scanner.Ident && p.lit == "safe" {
+		// package was compiled with -u option - ignore
+		p.next()
+	}
+	p.expect('\n')
+
+	pkg := p.getPkg(p.id, name)
+
+	for p.tok != '$' && p.tok != scanner.EOF {
+		p.parseDecl()
+	}
+
+	if ch := p.scanner.Peek(); p.tok != '$' || ch != '$' {
+		// don't call next()/expect() since reading past the
+		// export data may cause scanner errors (e.g. NUL chars)
+		p.errorf("expected '$$', got %s %c", scanner.TokenString(p.tok), ch)
+	}
+
+	if n := p.scanner.ErrorCount; n != 0 {
+		p.errorf("expected no scanner errors, got %d", n)
+	}
+
+	// Record all referenced packages as imports.
+	var imports []*types.Package
+	for id, pkg2 := range p.localPkgs {
+		if id == p.id {
+			continue // avoid self-edge
+		}
+		imports = append(imports, pkg2)
+	}
+	sort.Sort(byPath(imports))
+	pkg.SetImports(imports)
+
+	// package was imported completely and without errors
+	pkg.MarkComplete()
+
+	return pkg
+}
+
+type byPath []*types.Package
+
+func (a byPath) Len() int           { return len(a) }
+func (a byPath) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
+func (a byPath) Less(i, j int) bool { return a[i].Path() < a[j].Path() }
diff --git a/src/go/internal/gcimporter/gcimporter_test.go b/src/go/internal/gcimporter/gcimporter_test.go
new file mode 100644
index 0000000..07993a8
--- /dev/null
+++ b/src/go/internal/gcimporter/gcimporter_test.go
@@ -0,0 +1,225 @@
+// 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 gcimporter
+
+import (
+	"fmt"
+	"internal/testenv"
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"runtime"
+	"strings"
+	"testing"
+	"time"
+
+	"go/types"
+)
+
+// skipSpecialPlatforms causes the test to be skipped for platforms where
+// builders (build.golang.org) don't have access to compiled packages for
+// import.
+func skipSpecialPlatforms(t *testing.T) {
+	switch platform := runtime.GOOS + "-" + runtime.GOARCH; platform {
+	case "nacl-amd64p32",
+		"nacl-386",
+		"nacl-arm",
+		"darwin-arm",
+		"darwin-arm64":
+		t.Skipf("no compiled packages available for import on %s", platform)
+	}
+}
+
+func compile(t *testing.T, dirname, filename string) string {
+	testenv.MustHaveGoBuild(t)
+	cmd := exec.Command("go", "tool", "compile", filename)
+	cmd.Dir = dirname
+	out, err := cmd.CombinedOutput()
+	if err != nil {
+		t.Logf("%s", out)
+		t.Fatalf("go tool compile %s failed: %s", filename, err)
+	}
+	// filename should end with ".go"
+	return filepath.Join(dirname, filename[:len(filename)-2]+"o")
+}
+
+// Use the same global imports map for all tests. The effect is
+// as if all tested packages were imported into a single package.
+var imports = make(map[string]*types.Package)
+
+func testPath(t *testing.T, path string) *types.Package {
+	t0 := time.Now()
+	pkg, err := Import(imports, path)
+	if err != nil {
+		t.Errorf("testPath(%s): %s", path, err)
+		return nil
+	}
+	t.Logf("testPath(%s): %v", path, time.Since(t0))
+	return pkg
+}
+
+const maxTime = 30 * time.Second
+
+func testDir(t *testing.T, dir string, endTime time.Time) (nimports int) {
+	dirname := filepath.Join(runtime.GOROOT(), "pkg", runtime.GOOS+"_"+runtime.GOARCH, dir)
+	list, err := ioutil.ReadDir(dirname)
+	if err != nil {
+		t.Fatalf("testDir(%s): %s", dirname, err)
+	}
+	for _, f := range list {
+		if time.Now().After(endTime) {
+			t.Log("testing time used up")
+			return
+		}
+		switch {
+		case !f.IsDir():
+			// try extensions
+			for _, ext := range pkgExts {
+				if strings.HasSuffix(f.Name(), ext) {
+					name := f.Name()[0 : len(f.Name())-len(ext)] // remove extension
+					if testPath(t, filepath.Join(dir, name)) != nil {
+						nimports++
+					}
+				}
+			}
+		case f.IsDir():
+			nimports += testDir(t, filepath.Join(dir, f.Name()), endTime)
+		}
+	}
+	return
+}
+
+func TestImport(t *testing.T) {
+	// This package only handles gc export data.
+	if runtime.Compiler != "gc" {
+		t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
+		return
+	}
+
+	if outFn := compile(t, "testdata", "exports.go"); outFn != "" {
+		defer os.Remove(outFn)
+	}
+
+	nimports := 0
+	if pkg := testPath(t, "./testdata/exports"); pkg != nil {
+		nimports++
+		// The package's Imports should include all the types
+		// referenced by the exportdata, which may be more than
+		// the import statements in the package's source, but
+		// fewer than the transitive closure of dependencies.
+		want := `[package ast ("go/ast") package token ("go/token") package runtime ("runtime")]`
+		got := fmt.Sprint(pkg.Imports())
+		if got != want {
+			t.Errorf(`Package("exports").Imports() = %s, want %s`, got, want)
+		}
+	}
+	nimports += testDir(t, "", time.Now().Add(maxTime)) // installed packages
+	t.Logf("tested %d imports", nimports)
+}
+
+var importedObjectTests = []struct {
+	name string
+	want string
+}{
+	{"math.Pi", "const Pi untyped float"},
+	{"io.Reader", "type Reader interface{Read(p []byte) (n int, err error)}"},
+	{"io.ReadWriter", "type ReadWriter interface{Read(p []byte) (n int, err error); Write(p []byte) (n int, err error)}"},
+	{"math.Sin", "func Sin(x float64) float64"},
+	// TODO(gri) add more tests
+}
+
+func TestImportedTypes(t *testing.T) {
+	skipSpecialPlatforms(t)
+
+	// This package only handles gc export data.
+	if runtime.Compiler != "gc" {
+		t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
+		return
+	}
+
+	for _, test := range importedObjectTests {
+		s := strings.Split(test.name, ".")
+		if len(s) != 2 {
+			t.Fatal("inconsistent test data")
+		}
+		importPath := s[0]
+		objName := s[1]
+
+		pkg, err := Import(imports, importPath)
+		if err != nil {
+			t.Error(err)
+			continue
+		}
+
+		obj := pkg.Scope().Lookup(objName)
+		if obj == nil {
+			t.Errorf("%s: object not found", test.name)
+			continue
+		}
+
+		got := types.ObjectString(obj, types.RelativeTo(pkg))
+		if got != test.want {
+			t.Errorf("%s: got %q; want %q", test.name, got, test.want)
+		}
+	}
+}
+
+func TestIssue5815(t *testing.T) {
+	skipSpecialPlatforms(t)
+
+	// This package only handles gc export data.
+	if runtime.Compiler != "gc" {
+		t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
+		return
+	}
+
+	pkg, err := Import(make(map[string]*types.Package), "strings")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	scope := pkg.Scope()
+	for _, name := range scope.Names() {
+		obj := scope.Lookup(name)
+		if obj.Pkg() == nil {
+			t.Errorf("no pkg for %s", obj)
+		}
+		if tname, _ := obj.(*types.TypeName); tname != nil {
+			named := tname.Type().(*types.Named)
+			for i := 0; i < named.NumMethods(); i++ {
+				m := named.Method(i)
+				if m.Pkg() == nil {
+					t.Errorf("no pkg for %s", m)
+				}
+			}
+		}
+	}
+}
+
+// Smoke test to ensure that imported methods get the correct package.
+func TestCorrectMethodPackage(t *testing.T) {
+	skipSpecialPlatforms(t)
+
+	// This package only handles gc export data.
+	if runtime.Compiler != "gc" {
+		t.Skipf("gc-built packages not available (compiler = %s)", runtime.Compiler)
+		return
+	}
+
+	imports := make(map[string]*types.Package)
+	_, err := Import(imports, "net/http")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	mutex := imports["sync"].Scope().Lookup("Mutex").(*types.TypeName).Type()
+	mset := types.NewMethodSet(types.NewPointer(mutex)) // methods of *sync.Mutex
+	sel := mset.Lookup(nil, "Lock")
+	lock := sel.Obj().(*types.Func)
+	if got, want := lock.Pkg().Path(), "sync"; got != want {
+		t.Errorf("got package path %q; want %q", got, want)
+	}
+}
diff --git a/src/go/internal/gcimporter/testdata/exports.go b/src/go/internal/gcimporter/testdata/exports.go
new file mode 100644
index 0000000..8ee28b0
--- /dev/null
+++ b/src/go/internal/gcimporter/testdata/exports.go
@@ -0,0 +1,89 @@
+// 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.
+
+// This file is used to generate an object file which
+// serves as test file for gcimporter_test.go.
+
+package exports
+
+import (
+	"go/ast"
+)
+
+// Issue 3682: Correctly read dotted identifiers from export data.
+const init1 = 0
+
+func init() {}
+
+const (
+	C0 int = 0
+	C1     = 3.14159265
+	C2     = 2.718281828i
+	C3     = -123.456e-789
+	C4     = +123.456E+789
+	C5     = 1234i
+	C6     = "foo\n"
+	C7     = `bar\n`
+)
+
+type (
+	T1  int
+	T2  [10]int
+	T3  []int
+	T4  *int
+	T5  chan int
+	T6a chan<- int
+	T6b chan (<-chan int)
+	T6c chan<- (chan int)
+	T7  <-chan *ast.File
+	T8  struct{}
+	T9  struct {
+		a    int
+		b, c float32
+		d    []string `go:"tag"`
+	}
+	T10 struct {
+		T8
+		T9
+		_ *T10
+	}
+	T11 map[int]string
+	T12 interface{}
+	T13 interface {
+		m1()
+		m2(int) float32
+	}
+	T14 interface {
+		T12
+		T13
+		m3(x ...struct{}) []T9
+	}
+	T15 func()
+	T16 func(int)
+	T17 func(x int)
+	T18 func() float32
+	T19 func() (x float32)
+	T20 func(...interface{})
+	T21 struct{ next *T21 }
+	T22 struct{ link *T23 }
+	T23 struct{ link *T22 }
+	T24 *T24
+	T25 *T26
+	T26 *T27
+	T27 *T25
+	T28 func(T28) T28
+)
+
+var (
+	V0 int
+	V1 = -991.0
+)
+
+func F1()         {}
+func F2(x int)    {}
+func F3() int     { return 0 }
+func F4() float32 { return 0 }
+func F5(a, b, c int, u, v, w struct{ x, y T1 }, more ...interface{}) (p, q, r chan<- T10)
+
+func (p *T1) M1()
diff --git a/src/go/parser/error_test.go b/src/go/parser/error_test.go
index 48fb53e..1a08d5a 100644
--- a/src/go/parser/error_test.go
+++ b/src/go/parser/error_test.go
@@ -34,11 +34,9 @@ import (
 
 const testdata = "testdata"
 
-var fsetErrs = token.NewFileSet()
-
 // getFile assumes that each filename occurs at most once
-func getFile(filename string) (file *token.File) {
-	fsetErrs.Iterate(func(f *token.File) bool {
+func getFile(fset *token.FileSet, filename string) (file *token.File) {
+	fset.Iterate(func(f *token.File) bool {
 		if f.Name() == filename {
 			if file != nil {
 				panic(filename + " used multiple times")
@@ -50,8 +48,8 @@ func getFile(filename string) (file *token.File) {
 	return file
 }
 
-func getPos(filename string, offset int) token.Pos {
-	if f := getFile(filename); f != nil {
+func getPos(fset *token.FileSet, filename string, offset int) token.Pos {
+	if f := getFile(fset, filename); f != nil {
 		return f.Pos(offset)
 	}
 	return token.NoPos
@@ -68,14 +66,14 @@ var errRx = regexp.MustCompile(`^/\* *ERROR *(HERE)? *"([^"]*)" *\*/$`)
 // expectedErrors collects the regular expressions of ERROR comments found
 // in files and returns them as a map of error positions to error messages.
 //
-func expectedErrors(t *testing.T, filename string, src []byte) map[token.Pos]string {
+func expectedErrors(t *testing.T, fset *token.FileSet, filename string, src []byte) map[token.Pos]string {
 	errors := make(map[token.Pos]string)
 
 	var s scanner.Scanner
 	// file was parsed already - do not add it again to the file
 	// set otherwise the position information returned here will
 	// not match the position information collected by the parser
-	s.Init(getFile(filename), src, nil, scanner.ScanComments)
+	s.Init(getFile(fset, filename), src, nil, scanner.ScanComments)
 	var prev token.Pos // position of last non-comment, non-semicolon token
 	var here token.Pos // position immediately after the token at position prev
 
@@ -109,11 +107,11 @@ func expectedErrors(t *testing.T, filename string, src []byte) map[token.Pos]str
 // compareErrors compares the map of expected error messages with the list
 // of found errors and reports discrepancies.
 //
-func compareErrors(t *testing.T, expected map[token.Pos]string, found scanner.ErrorList) {
+func compareErrors(t *testing.T, fset *token.FileSet, expected map[token.Pos]string, found scanner.ErrorList) {
 	for _, error := range found {
 		// error.Pos is a token.Position, but we want
 		// a token.Pos so we can do a map lookup
-		pos := getPos(error.Pos.Filename, error.Pos.Offset)
+		pos := getPos(fset, error.Pos.Filename, error.Pos.Offset)
 		if msg, found := expected[pos]; found {
 			// we expect a message at pos; check if it matches
 			rx, err := regexp.Compile(msg)
@@ -140,7 +138,7 @@ func compareErrors(t *testing.T, expected map[token.Pos]string, found scanner.Er
 	if len(expected) > 0 {
 		t.Errorf("%d errors not reported:", len(expected))
 		for pos, msg := range expected {
-			t.Errorf("%s: %s\n", fsetErrs.Position(pos), msg)
+			t.Errorf("%s: %s\n", fset.Position(pos), msg)
 		}
 	}
 }
@@ -152,7 +150,8 @@ func checkErrors(t *testing.T, filename string, input interface{}) {
 		return
 	}
 
-	_, err = ParseFile(fsetErrs, filename, src, DeclarationErrors|AllErrors)
+	fset := token.NewFileSet()
+	_, err = ParseFile(fset, filename, src, DeclarationErrors|AllErrors)
 	found, ok := err.(scanner.ErrorList)
 	if err != nil && !ok {
 		t.Error(err)
@@ -162,10 +161,10 @@ func checkErrors(t *testing.T, filename string, input interface{}) {
 
 	// we are expecting the following errors
 	// (collect these after parsing a file so that it is found in the file set)
-	expected := expectedErrors(t, filename, src)
+	expected := expectedErrors(t, fset, filename, src)
 
 	// verify errors returned by the parser
-	compareErrors(t, expected, found)
+	compareErrors(t, fset, expected, found)
 }
 
 func TestErrors(t *testing.T) {
diff --git a/src/go/parser/interface.go b/src/go/parser/interface.go
index 4910305..c6fd932 100644
--- a/src/go/parser/interface.go
+++ b/src/go/parser/interface.go
@@ -91,7 +91,10 @@ func ParseFile(fset *token.FileSet, filename string, src interface{}, mode Mode)
 	var p parser
 	defer func() {
 		if e := recover(); e != nil {
-			_ = e.(bailout) // re-panics if it's not a bailout
+			// resume same panic if it's not a bailout
+			if _, ok := e.(bailout); !ok {
+				panic(e)
+			}
 		}
 
 		// set result values
@@ -164,14 +167,31 @@ func ParseDir(fset *token.FileSet, path string, filter func(os.FileInfo) bool, m
 	return
 }
 
-// ParseExpr is a convenience function for obtaining the AST of an expression x.
-// The position information recorded in the AST is undefined. The filename used
-// in error messages is the empty string.
+// ParseExprFrom is a convenience function for parsing an expression.
+// The arguments have the same meaning as for Parse, but the source must
+// be a valid Go (type or value) expression.
 //
-func ParseExpr(x string) (ast.Expr, error) {
+func ParseExprFrom(fset *token.FileSet, filename string, src interface{}, mode Mode) (ast.Expr, error) {
+	// get source
+	text, err := readSource(filename, src)
+	if err != nil {
+		return nil, err
+	}
+
 	var p parser
-	p.init(token.NewFileSet(), "", []byte(x), 0)
+	defer func() {
+		if e := recover(); e != nil {
+			// resume same panic if it's not a bailout
+			if _, ok := e.(bailout); !ok {
+				panic(e)
+			}
+		}
+		p.errors.Sort()
+		err = p.errors.Err()
+	}()
 
+	// parse expr
+	p.init(fset, filename, text, mode)
 	// Set up pkg-level scopes to avoid nil-pointer errors.
 	// This is not needed for a correct expression x as the
 	// parser will be ok with a nil topScope, but be cautious
@@ -196,3 +216,11 @@ func ParseExpr(x string) (ast.Expr, error) {
 
 	return e, nil
 }
+
+// ParseExpr is a convenience function for obtaining the AST of an expression x.
+// The position information recorded in the AST is undefined. The filename used
+// in error messages is the empty string.
+//
+func ParseExpr(x string) (ast.Expr, error) {
+	return ParseExprFrom(token.NewFileSet(), "", []byte(x), 0)
+}
diff --git a/src/go/parser/parser.go b/src/go/parser/parser.go
index 4a005d8..e82c0bd 100644
--- a/src/go/parser/parser.go
+++ b/src/go/parser/parser.go
@@ -7,6 +7,13 @@
 // output is an abstract syntax tree (AST) representing the Go source. The
 // parser is invoked through one of the Parse* functions.
 //
+// The parser accepts a larger language than is syntactically permitted by
+// the Go spec, for simplicity, and for improved robustness in the presence
+// of syntax errors. For instance, in method declarations, the receiver is
+// treated like an ordinary parameter list and thus may contain multiple
+// entries where the spec permits exactly one. Consequently, the corresponding
+// field in the AST (ast.FuncDecl.Recv) field is not restricted to one entry.
+//
 package parser
 
 import (
@@ -412,14 +419,17 @@ func (p *parser) expectSemi() {
 	}
 }
 
-func (p *parser) atComma(context string) bool {
+func (p *parser) atComma(context string, follow token.Token) bool {
 	if p.tok == token.COMMA {
 		return true
 	}
-	if p.tok == token.SEMICOLON && p.lit == "\n" {
-		p.error(p.pos, "missing ',' before newline in "+context)
-		return true // "insert" the comma and continue
-
+	if p.tok != follow {
+		msg := "missing ','"
+		if p.tok == token.SEMICOLON && p.lit == "\n" {
+			msg += " before newline"
+		}
+		p.error(p.pos, msg+" in "+context)
+		return true // "insert" comma and continue
 	}
 	return false
 }
@@ -825,7 +835,7 @@ func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params [
 		// parameter or result variable is the function body.
 		p.declare(field, nil, scope, ast.Var, idents...)
 		p.resolve(typ)
-		if !p.atComma("parameter list") {
+		if !p.atComma("parameter list", token.RPAREN) {
 			return
 		}
 		p.next()
@@ -838,7 +848,7 @@ func (p *parser) parseParameterList(scope *ast.Scope, ellipsisOk bool) (params [
 			// parameter or result variable is the function body.
 			p.declare(field, nil, scope, ast.Var, idents...)
 			p.resolve(typ)
-			if !p.atComma("parameter list") {
+			if !p.atComma("parameter list", token.RPAREN) {
 				break
 			}
 			p.next()
@@ -1248,7 +1258,7 @@ func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr {
 			ellipsis = p.pos
 			p.next()
 		}
-		if !p.atComma("argument list") {
+		if !p.atComma("argument list", token.RPAREN) {
 			break
 		}
 		p.next()
@@ -1259,7 +1269,7 @@ func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr {
 	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 +1297,30 @@ func (p *parser) parseElement(keyOk bool) ast.Expr {
 	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,8 +1332,8 @@ func (p *parser) parseElementList() (list []ast.Expr) {
 	}
 
 	for p.tok != token.RBRACE && p.tok != token.EOF {
-		list = append(list, p.parseElement(true))
-		if !p.atComma("composite literal") {
+		list = append(list, p.parseElement())
+		if !p.atComma("composite literal", token.RBRACE) {
 			break
 		}
 		p.next()
@@ -1365,7 +1389,7 @@ func (p *parser) checkExpr(x ast.Expr) ast.Expr {
 	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 +1403,7 @@ func isTypeName(x ast.Expr) bool {
 	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:
@@ -1455,7 +1479,8 @@ L:
 				pos := p.pos
 				p.errorExpected(pos, "selector or type assertion")
 				p.next() // make progress
-				x = &ast.BadExpr{From: pos, To: p.pos}
+				sel := &ast.Ident{NamePos: pos, Name: "_"}
+				x = &ast.SelectorExpr{X: x, Sel: sel}
 			}
 		case token.LBRACK:
 			if lhs {
@@ -2123,7 +2148,7 @@ func (p *parser) parseStmt() (s ast.Stmt) {
 	case
 		// tokens that may start an expression
 		token.IDENT, token.INT, token.FLOAT, token.IMAG, token.CHAR, token.STRING, token.FUNC, token.LPAREN, // operands
-		token.LBRACK, token.STRUCT, // composite types
+		token.LBRACK, token.STRUCT, token.MAP, token.CHAN, token.INTERFACE, // composite types
 		token.ADD, token.SUB, token.MUL, token.AND, token.XOR, token.ARROW, token.NOT: // unary operators
 		s, _ = p.parseSimpleStmt(labelOk)
 		// because of the required look-ahead, labeled statements are
@@ -2152,11 +2177,14 @@ func (p *parser) parseStmt() (s ast.Stmt) {
 	case token.FOR:
 		s = p.parseForStmt()
 	case token.SEMICOLON:
-		s = &ast.EmptyStmt{Semicolon: p.pos}
+		// Is it ever possible to have an implicit semicolon
+		// producing an empty statement in a valid program?
+		// (handle correctly anyway)
+		s = &ast.EmptyStmt{Semicolon: p.pos, Implicit: p.lit == "\n"}
 		p.next()
 	case token.RBRACE:
 		// a semicolon may be omitted before a closing "}"
-		s = &ast.EmptyStmt{Semicolon: p.pos}
+		s = &ast.EmptyStmt{Semicolon: p.pos, Implicit: true}
 	default:
 		// no statement found
 		pos := p.pos
@@ -2228,6 +2256,7 @@ func (p *parser) parseValueSpec(doc *ast.CommentGroup, keyword token.Token, iota
 		defer un(trace(p, keyword.String()+"Spec"))
 	}
 
+	pos := p.pos
 	idents := p.parseIdentList()
 	typ := p.tryType()
 	var values []ast.Expr
@@ -2238,6 +2267,17 @@ func (p *parser) parseValueSpec(doc *ast.CommentGroup, keyword token.Token, iota
 	}
 	p.expectSemi() // call before accessing p.linecomment
 
+	switch keyword {
+	case token.VAR:
+		if typ == nil && values == nil {
+			p.error(pos, "missing variable type or initialization")
+		}
+	case token.CONST:
+		if values == nil && (iota == 0 || typ != nil) {
+			p.error(pos, "missing constant value")
+		}
+	}
+
 	// Go spec: The scope of a constant or variable identifier declared inside
 	// a function begins at the end of the ConstSpec or VarSpec and ends at
 	// the end of the innermost containing block.
diff --git a/src/go/parser/parser_test.go b/src/go/parser/parser_test.go
index 85065fd..c7bb36d 100644
--- a/src/go/parser/parser_test.go
+++ b/src/go/parser/parser_test.go
@@ -14,8 +14,6 @@ import (
 	"testing"
 )
 
-var fset = token.NewFileSet()
-
 var validFiles = []string{
 	"parser.go",
 	"parser_test.go",
@@ -25,7 +23,7 @@ var validFiles = []string{
 
 func TestParse(t *testing.T) {
 	for _, filename := range validFiles {
-		_, err := ParseFile(fset, filename, nil, DeclarationErrors)
+		_, err := ParseFile(token.NewFileSet(), filename, nil, DeclarationErrors)
 		if err != nil {
 			t.Fatalf("ParseFile(%s): %v", filename, err)
 		}
@@ -46,7 +44,7 @@ func dirFilter(f os.FileInfo) bool { return nameFilter(f.Name()) }
 
 func TestParseDir(t *testing.T) {
 	path := "."
-	pkgs, err := ParseDir(fset, path, dirFilter, 0)
+	pkgs, err := ParseDir(token.NewFileSet(), path, dirFilter, 0)
 	if err != nil {
 		t.Fatalf("ParseDir(%s): %v", path, err)
 	}
@@ -131,7 +129,7 @@ func TestParseExpr(t *testing.T) {
 }
 
 func TestColonEqualsScope(t *testing.T) {
-	f, err := ParseFile(fset, "", `package p; func f() { x, y, z := x, y, z }`, 0)
+	f, err := ParseFile(token.NewFileSet(), "", `package p; func f() { x, y, z := x, y, z }`, 0)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -153,7 +151,7 @@ func TestColonEqualsScope(t *testing.T) {
 }
 
 func TestVarScope(t *testing.T) {
-	f, err := ParseFile(fset, "", `package p; func f() { var x, y, z = x, y, z }`, 0)
+	f, err := ParseFile(token.NewFileSet(), "", `package p; func f() { var x, y, z = x, y, z }`, 0)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -183,7 +181,7 @@ var x int
 func f() { L: }
 `
 
-	f, err := ParseFile(fset, "", src, 0)
+	f, err := ParseFile(token.NewFileSet(), "", src, 0)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -221,7 +219,7 @@ func f() { L: }
 }
 
 func TestUnresolved(t *testing.T) {
-	f, err := ParseFile(fset, "", `
+	f, err := ParseFile(token.NewFileSet(), "", `
 package p
 //
 func f1a(int)
@@ -316,7 +314,7 @@ var imports = map[string]bool{
 func TestImports(t *testing.T) {
 	for path, isValid := range imports {
 		src := fmt.Sprintf("package p; import %s", path)
-		_, err := ParseFile(fset, "", src, 0)
+		_, err := ParseFile(token.NewFileSet(), "", src, 0)
 		switch {
 		case err != nil && isValid:
 			t.Errorf("ParseFile(%s): got %v; expected no error", src, err)
@@ -327,7 +325,7 @@ func TestImports(t *testing.T) {
 }
 
 func TestCommentGroups(t *testing.T) {
-	f, err := ParseFile(fset, "", `
+	f, err := ParseFile(token.NewFileSet(), "", `
 package p /* 1a */ /* 1b */      /* 1c */ // 1d
 /* 2a
 */
@@ -421,7 +419,7 @@ func checkFieldComments(t *testing.T, file *ast.File, fieldname, lead, line stri
 }
 
 func TestLeadAndLineComments(t *testing.T) {
-	f, err := ParseFile(fset, "", `
+	f, err := ParseFile(token.NewFileSet(), "", `
 package p
 type T struct {
 	/* F1 lead comment */
@@ -447,3 +445,89 @@ type T struct {
 		t.Error("not expected to find T.f3")
 	}
 }
+
+// TestIssue9979 verifies that empty statements are contained within their enclosing blocks.
+func TestIssue9979(t *testing.T) {
+	for _, src := range []string{
+		"package p; func f() {;}",
+		"package p; func f() {L:}",
+		"package p; func f() {L:;}",
+		"package p; func f() {L:\n}",
+		"package p; func f() {L:\n;}",
+		"package p; func f() { ; }",
+		"package p; func f() { L: }",
+		"package p; func f() { L: ; }",
+		"package p; func f() { L: \n}",
+		"package p; func f() { L: \n; }",
+	} {
+		fset := token.NewFileSet()
+		f, err := ParseFile(fset, "", src, 0)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		var pos, end token.Pos
+		ast.Inspect(f, func(x ast.Node) bool {
+			switch s := x.(type) {
+			case *ast.BlockStmt:
+				pos, end = s.Pos()+1, s.End()-1 // exclude "{", "}"
+			case *ast.LabeledStmt:
+				pos, end = s.Pos()+2, s.End() // exclude "L:"
+			case *ast.EmptyStmt:
+				// check containment
+				if s.Pos() < pos || s.End() > end {
+					t.Errorf("%s: %T[%d, %d] not inside [%d, %d]", src, s, s.Pos(), s.End(), pos, end)
+				}
+				// check semicolon
+				offs := fset.Position(s.Pos()).Offset
+				if ch := src[offs]; ch != ';' != s.Implicit {
+					want := "want ';'"
+					if s.Implicit {
+						want = "but ';' is implicit"
+					}
+					t.Errorf("%s: found %q at offset %d; %s", src, ch, offs, want)
+				}
+			}
+			return true
+		})
+	}
+}
+
+// TestIncompleteSelection ensures that an incomplete selector
+// expression is parsed as a (blank) *ast.SelectorExpr, not a
+// *ast.BadExpr.
+func TestIncompleteSelection(t *testing.T) {
+	for _, src := range []string{
+		"package p; var _ = fmt.",             // at EOF
+		"package p; var _ = fmt.\ntype X int", // not at EOF
+	} {
+		fset := token.NewFileSet()
+		f, err := ParseFile(fset, "", src, 0)
+		if err == nil {
+			t.Errorf("ParseFile(%s) succeeded unexpectedly", src)
+			continue
+		}
+
+		const wantErr = "expected selector or type assertion"
+		if !strings.Contains(err.Error(), wantErr) {
+			t.Errorf("ParseFile returned wrong error %q, want %q", err, wantErr)
+		}
+
+		var sel *ast.SelectorExpr
+		ast.Inspect(f, func(n ast.Node) bool {
+			if n, ok := n.(*ast.SelectorExpr); ok {
+				sel = n
+			}
+			return true
+		})
+		if sel == nil {
+			t.Error("found no *ast.SelectorExpr")
+			continue
+		}
+		const wantSel = "&{fmt _}"
+		if fmt.Sprint(sel) != wantSel {
+			t.Errorf("found selector %s, want %s", sel, wantSel)
+			continue
+		}
+	}
+}
diff --git a/src/go/parser/short_test.go b/src/go/parser/short_test.go
index 05e44de..ef2ffad 100644
--- a/src/go/parser/short_test.go
+++ b/src/go/parser/short_test.go
@@ -40,6 +40,12 @@ var valids = []string{
 	`package p; func (*(T),) m() {}`,
 	`package p; func _(x []int) { for range x {} }`,
 	`package p; func _() { if [T{}.n]int{} {} }`,
+	`package p; func _() { map[int]int{}[0]++; map[int]int{}[0] += 1 }`,
+	`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) {
@@ -93,8 +99,13 @@ var invalids = []string{
 	`package p; func f() { for i /* ERROR "boolean or range expression" */ , x := []string {} }`,
 	`package p; func f() { go f /* ERROR HERE "function must be invoked" */ }`,
 	`package p; func f() { defer func() {} /* ERROR HERE "function must be invoked" */ }`,
-	`package p; func f() { go func() { func() { f(x func /* ERROR "expected '\)'" */ (){}) } } }`,
-	`package p; func f() (a b string /* ERROR "expected '\)'" */ , ok bool) // issue 8656`,
+	`package p; func f() { go func() { func() { f(x func /* ERROR "missing ','" */ (){}) } } }`,
+	`package p; func f(x func(), u v func /* ERROR "missing ','" */ ()){}`,
+	`package p; func f() (a b string /* ERROR "missing ','" */ , ok bool)`,           // issue 8656
+	`package p; var x /* ERROR "missing variable type or initialization" */ , y, z;`, // issue 9639
+	`package p; const x /* ERROR "missing constant value" */ ;`,                      // issue 9639
+	`package p; const x /* ERROR "missing constant value" */ int;`,                   // issue 9639
+	`package p; const (x = 0; y; z /* ERROR "missing constant value" */ int);`,       // issue 9639
 }
 
 func TestInvalid(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 @@ func f() {
 				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/nodes.go b/src/go/printer/nodes.go
index d5a6934..fe04705 100644
--- a/src/go/printer/nodes.go
+++ b/src/go/printer/nodes.go
@@ -12,6 +12,9 @@ import (
 	"bytes"
 	"go/ast"
 	"go/token"
+	"strconv"
+	"strings"
+	"unicode"
 	"unicode/utf8"
 )
 
@@ -1334,6 +1337,49 @@ func (p *printer) valueSpec(s *ast.ValueSpec, keepType bool) {
 	}
 }
 
+func sanitizeImportPath(lit *ast.BasicLit) *ast.BasicLit {
+	// Note: An unmodified AST generated by go/parser will already
+	// contain a backward- or double-quoted path string that does
+	// not contain any invalid characters, and most of the work
+	// here is not needed. However, a modified or generated AST
+	// may possibly contain non-canonical paths. Do the work in
+	// all cases since it's not too hard and not speed-critical.
+
+	// if we don't have a proper string, be conservative and return whatever we have
+	if lit.Kind != token.STRING {
+		return lit
+	}
+	s, err := strconv.Unquote(lit.Value)
+	if err != nil {
+		return lit
+	}
+
+	// if the string is an invalid path, return whatever we have
+	//
+	// spec: "Implementation restriction: A compiler may restrict
+	// ImportPaths to non-empty strings using only characters belonging
+	// to Unicode's L, M, N, P, and S general categories (the Graphic
+	// characters without spaces) and may also exclude the characters
+	// !"#$%&'()*,:;<=>?[\]^`{|} and the Unicode replacement character
+	// U+FFFD."
+	if s == "" {
+		return lit
+	}
+	const illegalChars = `!"#$%&'()*,:;<=>?[\]^{|}` + "`\uFFFD"
+	for _, r := range s {
+		if !unicode.IsGraphic(r) || unicode.IsSpace(r) || strings.ContainsRune(illegalChars, r) {
+			return lit
+		}
+	}
+
+	// otherwise, return the double-quoted path
+	s = strconv.Quote(s)
+	if s == lit.Value {
+		return lit // nothing wrong with lit
+	}
+	return &ast.BasicLit{ValuePos: lit.ValuePos, Kind: token.STRING, Value: s}
+}
+
 // The parameter n is the number of specs in the group. If doIndent is set,
 // multi-line identifier lists in the spec are indented when the first
 // linebreak is encountered.
@@ -1346,7 +1392,7 @@ func (p *printer) spec(spec ast.Spec, n int, doIndent bool) {
 			p.expr(s.Name)
 			p.print(blank)
 		}
-		p.expr(s.Path)
+		p.expr(sanitizeImportPath(s.Path))
 		p.setComment(s.Comment)
 		p.print(s.EndPos)
 
diff --git a/src/go/printer/printer.go b/src/go/printer/printer.go
index 280c697..f9343d3 100644
--- a/src/go/printer/printer.go
+++ b/src/go/printer/printer.go
@@ -144,7 +144,7 @@ func (p *printer) nextComment() {
 	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.
 //
@@ -496,29 +496,33 @@ func stripCommonPrefix(lines []string) {
 	// Compute maximum common white prefix of all but the first,
 	// last, and blank lines, and replace blank lines with empty
 	// lines (the first line starts with /* and has no prefix).
-	// In case of two-line comments, consider the last line for
-	// the prefix computation since otherwise the prefix would
-	// be empty.
+	// In cases where only the first and last lines are not blank,
+	// such as two-line comments, or comments where all inner lines
+	// are blank, consider the last line for the prefix computation
+	// since otherwise the prefix would be empty.
 	//
 	// Note that the first and last line are never empty (they
 	// contain the opening /* and closing */ respectively) and
 	// thus they can be ignored by the blank line check.
-	var prefix string
+	prefix := ""
+	prefixSet := false
 	if len(lines) > 2 {
-		first := true
 		for i, line := range lines[1 : len(lines)-1] {
-			switch {
-			case isBlank(line):
+			if isBlank(line) {
 				lines[1+i] = "" // range starts with lines[1]
-			case first:
-				prefix = commonPrefix(line, line)
-				first = false
-			default:
+			} else {
+				if !prefixSet {
+					prefix = line
+					prefixSet = true
+				}
 				prefix = commonPrefix(prefix, line)
 			}
+
 		}
-	} else { // len(lines) == 2, lines cannot be blank (contain /* and */)
-		line := lines[1]
+	}
+	// If we don't have a prefix yet, consider the last line.
+	if !prefixSet {
+		line := lines[len(lines)-1]
 		prefix = commonPrefix(line, line)
 	}
 
diff --git a/src/go/printer/testdata/comments.golden b/src/go/printer/testdata/comments.golden
index b1af795..849fa62 100644
--- a/src/go/printer/testdata/comments.golden
+++ b/src/go/printer/testdata/comments.golden
@@ -413,6 +413,68 @@ func _() {
 		aligned line */
 }
 
+// Issue 9751.
+func _() {
+	/*a string
+
+	b string*/
+
+	/*A string
+
+
+
+	Z string*/
+
+	/*a string
+
+	b string
+
+	c string*/
+
+	{
+		/*a string
+		b string*/
+
+		/*a string
+
+		b string*/
+
+		/*a string
+
+		b string
+
+		c string*/
+	}
+
+	{
+		/*a string
+		b string*/
+
+		/*a string
+
+		b string*/
+
+		/*a string
+
+		b string
+
+		c string*/
+	}
+
+	/*
+	 */
+
+	/*
+
+	 */
+
+	/*
+
+	 * line
+
+	 */
+}
+
 /*
  * line
  * of
diff --git a/src/go/printer/testdata/comments.input b/src/go/printer/testdata/comments.input
index 983e2b2..30cd23c 100644
--- a/src/go/printer/testdata/comments.input
+++ b/src/go/printer/testdata/comments.input
@@ -418,6 +418,68 @@ func _() {
 		aligned line */
 }
 
+// Issue 9751.
+func _() {
+	/*a string
+
+	b string*/
+
+	/*A string
+
+
+
+	Z string*/
+
+	/*a string
+
+	b string
+
+	c string*/
+
+	{
+		/*a string
+b string*/
+
+		/*a string
+
+b string*/
+
+		/*a string
+
+b string
+
+c string*/
+	}
+
+	{
+		/*a string
+				b string*/
+
+		/*a string
+
+				b string*/
+
+		/*a string
+
+				b string
+
+				c string*/
+	}
+
+	/*
+	*/
+
+	/*
+
+	*/
+
+	/*
+
+	 * line
+
+	*/
+}
+
 /*
  * line
  * of
diff --git a/src/go/printer/testdata/declarations.golden b/src/go/printer/testdata/declarations.golden
index 9acd41b..82f5e0f 100644
--- a/src/go/printer/testdata/declarations.golden
+++ b/src/go/printer/testdata/declarations.golden
@@ -110,6 +110,15 @@ import (
 	"package_dddd"	// comment
 )
 
+// print import paths as double-quoted strings
+// (we would like more test cases but the go/parser
+// already excludes most incorrect paths, and we don't
+// bother setting up test-ASTs manually)
+import (
+	"fmt"
+	"math"
+)
+
 // at least one empty line between declarations of different kind
 import _ "io"
 
diff --git a/src/go/printer/testdata/declarations.input b/src/go/printer/testdata/declarations.input
index 45beec2..a0a3783 100644
--- a/src/go/printer/testdata/declarations.input
+++ b/src/go/printer/testdata/declarations.input
@@ -111,6 +111,15 @@ import (
 	"package_dddd" // comment
 )
 
+// print import paths as double-quoted strings
+// (we would like more test cases but the go/parser
+// already excludes most incorrect paths, and we don't
+// bother setting up test-ASTs manually)
+import (
+	`fmt`
+	"math"
+)
+
 // at least one empty line between declarations of different kind
 import _ "io"
 var _ int
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 @@ func (p *parser) checkExpr(x ast.Expr) ast.Expr {
 	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 @@ func isTypeName(x ast.Expr) bool {
 	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..bf7bfa3 100644
--- a/src/go/scanner/errors.go
+++ b/src/go/scanner/errors.go
@@ -54,18 +54,16 @@ func (p ErrorList) Less(i, j int) bool {
 	// Note that it is not sufficient to simply compare file offsets because
 	// the offsets do not reflect modified line information (through //line
 	// comments).
-	if e.Filename < f.Filename {
-		return true
+	if e.Filename != f.Filename {
+		return e.Filename < f.Filename
 	}
-	if e.Filename == f.Filename {
-		if e.Line < f.Line {
-			return true
-		}
-		if e.Line == f.Line {
-			return e.Column < f.Column
-		}
+	if e.Line != f.Line {
+		return e.Line < f.Line
+	}
+	if e.Column != f.Column {
+		return e.Column < f.Column
 	}
-	return false
+	return p[i].Msg < p[j].Msg
 }
 
 // Sort sorts an ErrorList. *Error entries are sorted by position,
diff --git a/src/go/scanner/scanner.go b/src/go/scanner/scanner.go
index cec82ea..e9476c4 100644
--- a/src/go/scanner/scanner.go
+++ b/src/go/scanner/scanner.go
@@ -706,13 +706,14 @@ scanAgain:
 					s.insertSemi = false // newline consumed
 					return pos, token.SEMICOLON, "\n"
 				}
-				lit = s.scanComment()
+				comment := s.scanComment()
 				if s.mode&ScanComments == 0 {
 					// skip comment
 					s.insertSemi = false // newline consumed
 					goto scanAgain
 				}
 				tok = token.COMMENT
+				lit = comment
 			} else {
 				tok = s.switch2(token.QUO, token.QUO_ASSIGN)
 			}
diff --git a/src/go/scanner/scanner_test.go b/src/go/scanner/scanner_test.go
index fc450d8..0d21905 100644
--- a/src/go/scanner/scanner_test.go
+++ b/src/go/scanner/scanner_test.go
@@ -734,6 +734,41 @@ func TestScanErrors(t *testing.T) {
 	}
 }
 
+// Verify that no comments show up as literal values when skipping comments.
+func TestIssue10213(t *testing.T) {
+	var src = `
+		var (
+			A = 1 // foo
+		)
+
+		var (
+			B = 2
+			// foo
+		)
+
+		var C = 3 // foo
+
+		var D = 4
+		// foo
+
+		func anycode() {
+		// foo
+		}
+	`
+	var s Scanner
+	s.Init(fset.AddFile("", fset.Base(), len(src)), []byte(src), nil, 0)
+	for {
+		pos, tok, lit := s.Scan()
+		class := tokenclass(tok)
+		if lit != "" && class != keyword && class != literal && tok != token.SEMICOLON {
+			t.Errorf("%s: tok = %s, lit = %q", fset.Position(pos), tok, lit)
+		}
+		if tok <= token.EOF {
+			break
+		}
+	}
+}
+
 func BenchmarkScan(b *testing.B) {
 	b.StopTimer()
 	fset := token.NewFileSet()
diff --git a/src/go/token/position.go b/src/go/token/position.go
index 82d90ee..3375177 100644
--- a/src/go/token/position.go
+++ b/src/go/token/position.go
@@ -21,10 +21,10 @@ type Position struct {
 	Filename string // filename, if any
 	Offset   int    // offset, starting at 0
 	Line     int    // line number, starting at 1
-	Column   int    // column number, starting at 1 (character count)
+	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:
@@ -56,8 +56,8 @@ func (pos Position) String() string {
 // where base and size are specified when adding the file to the file set via
 // AddFile.
 //
-// To create the Pos value for a specific source offset, first add
-// the respective file to the current file set (via FileSet.AddFile)
+// To create the Pos value for a specific source offset (measured in bytes),
+// first add the respective file to the current file set using FileSet.AddFile
 // and then call File.Pos(offset) for that file. Given a Pos value p
 // for a specific file set fset, the corresponding Position value is
 // obtained by calling fset.Position(p).
@@ -77,7 +77,7 @@ type Pos int
 //
 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 @@ func (f *File) MergeLine(line int) {
 	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/go/types/api.go b/src/go/types/api.go
new file mode 100644
index 0000000..b3bf6f0
--- /dev/null
+++ b/src/go/types/api.go
@@ -0,0 +1,336 @@
+// 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.
+
+// Package types declares the data types and implements
+// the algorithms for type-checking of Go packages. Use
+// Config.Check to invoke the type checker for a package.
+// Alternatively, create a new type checked with NewChecker
+// and invoke it incrementally by calling Checker.Files.
+//
+// Type-checking consists of several interdependent phases:
+//
+// Name resolution maps each identifier (ast.Ident) in the program to the
+// language object (Object) it denotes.
+// Use Info.{Defs,Uses,Implicits} for the results of name resolution.
+//
+// Constant folding computes the exact constant value (constant.Value)
+// for every expression (ast.Expr) that is a compile-time constant.
+// Use Info.Types[expr].Value for the results of constant folding.
+//
+// Type inference computes the type (Type) of every expression (ast.Expr)
+// and checks for compliance with the language specification.
+// Use Info.Types[expr].Type for the results of type inference.
+//
+package types // import "go/types"
+
+import (
+	"bytes"
+	"fmt"
+	"go/ast"
+	"go/constant"
+	"go/token"
+)
+
+// An Error describes a type-checking error; it implements the error interface.
+// A "soft" error is an error that still permits a valid interpretation of a
+// package (such as "unused variable"); "hard" errors may lead to unpredictable
+// behavior if ignored.
+type Error struct {
+	Fset *token.FileSet // file set for interpretation of Pos
+	Pos  token.Pos      // error position
+	Msg  string         // error message
+	Soft bool           // if set, error is "soft"
+}
+
+// Error returns an error string formatted as follows:
+// filename:line:column: message
+func (err Error) Error() string {
+	return fmt.Sprintf("%s: %s", err.Fset.Position(err.Pos), err.Msg)
+}
+
+// An importer resolves import paths to Packages.
+// See go/importer for existing implementations.
+type Importer interface {
+	// Import returns the imported package for the given import
+	// path, or an error if the package couldn't be imported.
+	// Import is responsible for returning the same package for
+	// matching import paths.
+	Import(path string) (*Package, error)
+}
+
+// A Config specifies the configuration for type checking.
+// The zero value for Config is a ready-to-use default configuration.
+type Config struct {
+	// If IgnoreFuncBodies is set, function bodies are not
+	// type-checked.
+	IgnoreFuncBodies bool
+
+	// If FakeImportC is set, `import "C"` (for packages requiring Cgo)
+	// declares an empty "C" package and errors are omitted for qualified
+	// identifiers referring to package C (which won't find an object).
+	// This feature is intended for the standard library cmd/api tool.
+	//
+	// Caution: Effects may be unpredictable due to follow-up errors.
+	//          Do not use casually!
+	FakeImportC bool
+
+	// If Error != nil, it is called with each error found
+	// during type checking; err has dynamic type Error.
+	// Secondary errors (for instance, to enumerate all types
+	// involved in an invalid recursive type declaration) have
+	// error strings that start with a '\t' character.
+	// If Error == nil, type-checking stops with the first
+	// error found.
+	Error func(err error)
+
+	// Importer is called for each import declaration except when
+	// importing package "unsafe". An error is reported if an
+	// importer is needed but none was installed.
+	Importer Importer
+
+	// If Sizes != nil, it provides the sizing functions for package unsafe.
+	// Otherwise &StdSizes{WordSize: 8, MaxAlign: 8} is used instead.
+	Sizes Sizes
+
+	// If DisableUnusedImportCheck is set, packages are not checked
+	// for unused imports.
+	DisableUnusedImportCheck bool
+}
+
+// Info holds result type information for a type-checked package.
+// Only the information for which a map is provided is collected.
+// If the package has type errors, the collected information may
+// be incomplete.
+type Info struct {
+	// Types maps expressions to their types, and for constant
+	// expressions, their values. Invalid expressions are omitted.
+	//
+	// For (possibly parenthesized) identifiers denoting built-in
+	// functions, the recorded signatures are call-site specific:
+	// if the call result is not a constant, the recorded type is
+	// an argument-specific signature. Otherwise, the recorded type
+	// is invalid.
+	//
+	// Identifiers on the lhs of declarations (i.e., the identifiers
+	// which are being declared) are collected in the Defs map.
+	// Identifiers denoting packages are collected in the Uses maps.
+	Types map[ast.Expr]TypeAndValue
+
+	// Defs maps identifiers to the objects they define (including
+	// package names, dots "." of dot-imports, and blank "_" identifiers).
+	// For identifiers that do not denote objects (e.g., the package name
+	// in package clauses, or symbolic variables t in t := x.(type) of
+	// type switch headers), the corresponding objects are nil.
+	//
+	// For an anonymous field, Defs returns the field *Var it defines.
+	//
+	// Invariant: Defs[id] == nil || Defs[id].Pos() == id.Pos()
+	Defs map[*ast.Ident]Object
+
+	// Uses maps identifiers to the objects they denote.
+	//
+	// For an anonymous field, Uses returns the *TypeName it denotes.
+	//
+	// Invariant: Uses[id].Pos() != id.Pos()
+	Uses map[*ast.Ident]Object
+
+	// Implicits maps nodes to their implicitly declared objects, if any.
+	// The following node and object types may appear:
+	//
+	//	node               declared object
+	//
+	//	*ast.ImportSpec    *PkgName for dot-imports and imports without renames
+	//	*ast.CaseClause    type-specific *Var for each type switch case clause (incl. default)
+	//      *ast.Field         anonymous struct field or parameter *Var
+	//
+	Implicits map[ast.Node]Object
+
+	// Selections maps selector expressions (excluding qualified identifiers)
+	// to their corresponding selections.
+	Selections map[*ast.SelectorExpr]*Selection
+
+	// Scopes maps ast.Nodes to the scopes they define. Package scopes are not
+	// associated with a specific node but with all files belonging to a package.
+	// Thus, the package scope can be found in the type-checked Package object.
+	// Scopes nest, with the Universe scope being the outermost scope, enclosing
+	// the package scope, which contains (one or more) files scopes, which enclose
+	// function scopes which in turn enclose statement and function literal scopes.
+	// Note that even though package-level functions are declared in the package
+	// scope, the function scopes are embedded in the file scope of the file
+	// containing the function declaration.
+	//
+	// The following node types may appear in Scopes:
+	//
+	//	*ast.File
+	//	*ast.FuncType
+	//	*ast.BlockStmt
+	//	*ast.IfStmt
+	//	*ast.SwitchStmt
+	//	*ast.TypeSwitchStmt
+	//	*ast.CaseClause
+	//	*ast.CommClause
+	//	*ast.ForStmt
+	//	*ast.RangeStmt
+	//
+	Scopes map[ast.Node]*Scope
+
+	// InitOrder is the list of package-level initializers in the order in which
+	// they must be executed. Initializers referring to variables related by an
+	// initialization dependency appear in topological order, the others appear
+	// in source order. Variables without an initialization expression do not
+	// appear in this list.
+	InitOrder []*Initializer
+}
+
+// TypeOf returns the type of expression e, or nil if not found.
+// Precondition: the Types, Uses and Defs maps are populated.
+//
+func (info *Info) TypeOf(e ast.Expr) Type {
+	if t, ok := info.Types[e]; ok {
+		return t.Type
+	}
+	if id, _ := e.(*ast.Ident); id != nil {
+		if obj := info.ObjectOf(id); obj != nil {
+			return obj.Type()
+		}
+	}
+	return nil
+}
+
+// ObjectOf returns the object denoted by the specified id,
+// or nil if not found.
+//
+// If id is an anonymous struct field, ObjectOf returns the field (*Var)
+// it uses, not the type (*TypeName) it defines.
+//
+// Precondition: the Uses and Defs maps are populated.
+//
+func (info *Info) ObjectOf(id *ast.Ident) Object {
+	if obj, _ := info.Defs[id]; obj != nil {
+		return obj
+	}
+	return info.Uses[id]
+}
+
+// TypeAndValue reports the type and value (for constants)
+// of the corresponding expression.
+type TypeAndValue struct {
+	mode  operandMode
+	Type  Type
+	Value constant.Value
+}
+
+// TODO(gri) Consider eliminating the IsVoid predicate. Instead, report
+// "void" values as regular values but with the empty tuple type.
+
+// IsVoid reports whether the corresponding expression
+// is a function call without results.
+func (tv TypeAndValue) IsVoid() bool {
+	return tv.mode == novalue
+}
+
+// IsType reports whether the corresponding expression specifies a type.
+func (tv TypeAndValue) IsType() bool {
+	return tv.mode == typexpr
+}
+
+// IsBuiltin reports whether the corresponding expression denotes
+// a (possibly parenthesized) built-in function.
+func (tv TypeAndValue) IsBuiltin() bool {
+	return tv.mode == builtin
+}
+
+// IsValue reports whether the corresponding expression is a value.
+// Builtins are not considered values. Constant values have a non-
+// nil Value.
+func (tv TypeAndValue) IsValue() bool {
+	switch tv.mode {
+	case constant_, variable, mapindex, value, commaok:
+		return true
+	}
+	return false
+}
+
+// IsNil reports whether the corresponding expression denotes the
+// predeclared value nil.
+func (tv TypeAndValue) IsNil() bool {
+	return tv.mode == value && tv.Type == Typ[UntypedNil]
+}
+
+// Addressable reports whether the corresponding expression
+// is addressable (https://golang.org/ref/spec#Address_operators).
+func (tv TypeAndValue) Addressable() bool {
+	return tv.mode == variable
+}
+
+// Assignable reports whether the corresponding expression
+// is assignable to (provided a value of the right type).
+func (tv TypeAndValue) Assignable() bool {
+	return tv.mode == variable || tv.mode == mapindex
+}
+
+// HasOk reports whether the corresponding expression may be
+// used on the lhs of a comma-ok assignment.
+func (tv TypeAndValue) HasOk() bool {
+	return tv.mode == commaok || tv.mode == mapindex
+}
+
+// An Initializer describes a package-level variable, or a list of variables in case
+// of a multi-valued initialization expression, and the corresponding initialization
+// expression.
+type Initializer struct {
+	Lhs []*Var // var Lhs = Rhs
+	Rhs ast.Expr
+}
+
+func (init *Initializer) String() string {
+	var buf bytes.Buffer
+	for i, lhs := range init.Lhs {
+		if i > 0 {
+			buf.WriteString(", ")
+		}
+		buf.WriteString(lhs.Name())
+	}
+	buf.WriteString(" = ")
+	WriteExpr(&buf, init.Rhs)
+	return buf.String()
+}
+
+// Check type-checks a package and returns the resulting package object,
+// the first error if any, and if info != nil, additional type information.
+// The package is marked as complete if no errors occurred, otherwise it is
+// incomplete. See Config.Error for controlling behavior in the presence of
+// errors.
+//
+// The package is specified by a list of *ast.Files and corresponding
+// file set, and the package path the package is identified with.
+// The clean path must not be empty or dot (".").
+func (conf *Config) Check(path string, fset *token.FileSet, files []*ast.File, info *Info) (*Package, error) {
+	pkg := NewPackage(path, "")
+	return pkg, NewChecker(conf, fset, pkg, info).Files(files)
+}
+
+// AssertableTo reports whether a value of type V can be asserted to have type T.
+func AssertableTo(V *Interface, T Type) bool {
+	m, _ := assertableTo(V, T)
+	return m == nil
+}
+
+// AssignableTo reports whether a value of type V is assignable to a variable of type T.
+func AssignableTo(V, T Type) bool {
+	x := operand{mode: value, typ: V}
+	return x.assignableTo(nil, T) // config not needed for non-constant x
+}
+
+// ConvertibleTo reports whether a value of type V is convertible to a value of type T.
+func ConvertibleTo(V, T Type) bool {
+	x := operand{mode: value, typ: V}
+	return x.convertibleTo(nil, T) // config not needed for non-constant x
+}
+
+// Implements reports whether type V implements interface T.
+func Implements(V Type, T *Interface) bool {
+	f, _ := MissingMethod(V, T, true)
+	return f == nil
+}
diff --git a/src/go/types/api_test.go b/src/go/types/api_test.go
new file mode 100644
index 0000000..eeda0d8
--- /dev/null
+++ b/src/go/types/api_test.go
@@ -0,0 +1,1044 @@
+// 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 types_test
+
+import (
+	"bytes"
+	"fmt"
+	"go/ast"
+	"go/importer"
+	"go/parser"
+	"go/token"
+	"internal/testenv"
+	"reflect"
+	"regexp"
+	"strings"
+	"testing"
+
+	. "go/types"
+)
+
+func pkgFor(path, source string, info *Info) (*Package, error) {
+	fset := token.NewFileSet()
+	f, err := parser.ParseFile(fset, path, source, 0)
+	if err != nil {
+		return nil, err
+	}
+
+	conf := Config{Importer: importer.Default()}
+	return conf.Check(f.Name.Name, fset, []*ast.File{f}, info)
+}
+
+func mustTypecheck(t *testing.T, path, source string, info *Info) string {
+	pkg, err := pkgFor(path, source, info)
+	if err != nil {
+		name := path
+		if pkg != nil {
+			name = "package " + pkg.Name()
+		}
+		t.Fatalf("%s: didn't type-check (%s)", name, err)
+	}
+	return pkg.Name()
+}
+
+func TestValuesInfo(t *testing.T) {
+	var tests = []struct {
+		src  string
+		expr string // constant expression
+		typ  string // constant type
+		val  string // constant value
+	}{
+		{`package a0; const _ = false`, `false`, `untyped bool`, `false`},
+		{`package a1; const _ = 0`, `0`, `untyped int`, `0`},
+		{`package a2; const _ = 'A'`, `'A'`, `untyped rune`, `65`},
+		{`package a3; const _ = 0.`, `0.`, `untyped float`, `0`},
+		{`package a4; const _ = 0i`, `0i`, `untyped complex`, `0`},
+		{`package a5; const _ = "foo"`, `"foo"`, `untyped string`, `"foo"`},
+
+		{`package b0; var _ = false`, `false`, `bool`, `false`},
+		{`package b1; var _ = 0`, `0`, `int`, `0`},
+		{`package b2; var _ = 'A'`, `'A'`, `rune`, `65`},
+		{`package b3; var _ = 0.`, `0.`, `float64`, `0`},
+		{`package b4; var _ = 0i`, `0i`, `complex128`, `0`},
+		{`package b5; var _ = "foo"`, `"foo"`, `string`, `"foo"`},
+
+		{`package c0a; var _ = bool(false)`, `false`, `bool`, `false`},
+		{`package c0b; var _ = bool(false)`, `bool(false)`, `bool`, `false`},
+		{`package c0c; type T bool; var _ = T(false)`, `T(false)`, `c0c.T`, `false`},
+
+		{`package c1a; var _ = int(0)`, `0`, `int`, `0`},
+		{`package c1b; var _ = int(0)`, `int(0)`, `int`, `0`},
+		{`package c1c; type T int; var _ = T(0)`, `T(0)`, `c1c.T`, `0`},
+
+		{`package c2a; var _ = rune('A')`, `'A'`, `rune`, `65`},
+		{`package c2b; var _ = rune('A')`, `rune('A')`, `rune`, `65`},
+		{`package c2c; type T rune; var _ = T('A')`, `T('A')`, `c2c.T`, `65`},
+
+		{`package c3a; var _ = float32(0.)`, `0.`, `float32`, `0`},
+		{`package c3b; var _ = float32(0.)`, `float32(0.)`, `float32`, `0`},
+		{`package c3c; type T float32; var _ = T(0.)`, `T(0.)`, `c3c.T`, `0`},
+
+		{`package c4a; var _ = complex64(0i)`, `0i`, `complex64`, `0`},
+		{`package c4b; var _ = complex64(0i)`, `complex64(0i)`, `complex64`, `0`},
+		{`package c4c; type T complex64; var _ = T(0i)`, `T(0i)`, `c4c.T`, `0`},
+
+		{`package c5a; var _ = string("foo")`, `"foo"`, `string`, `"foo"`},
+		{`package c5b; var _ = string("foo")`, `string("foo")`, `string`, `"foo"`},
+		{`package c5c; type T string; var _ = T("foo")`, `T("foo")`, `c5c.T`, `"foo"`},
+
+		{`package d0; var _ = []byte("foo")`, `"foo"`, `string`, `"foo"`},
+		{`package d1; var _ = []byte(string("foo"))`, `"foo"`, `string`, `"foo"`},
+		{`package d2; var _ = []byte(string("foo"))`, `string("foo")`, `string`, `"foo"`},
+		{`package d3; type T []byte; var _ = T("foo")`, `"foo"`, `string`, `"foo"`},
+
+		{`package e0; const _ = float32( 1e-200)`, `float32(1e-200)`, `float32`, `0`},
+		{`package e1; const _ = float32(-1e-200)`, `float32(-1e-200)`, `float32`, `0`},
+		{`package e2; const _ = float64( 1e-2000)`, `float64(1e-2000)`, `float64`, `0`},
+		{`package e3; const _ = float64(-1e-2000)`, `float64(-1e-2000)`, `float64`, `0`},
+		{`package e4; const _ = complex64( 1e-200)`, `complex64(1e-200)`, `complex64`, `0`},
+		{`package e5; const _ = complex64(-1e-200)`, `complex64(-1e-200)`, `complex64`, `0`},
+		{`package e6; const _ = complex128( 1e-2000)`, `complex128(1e-2000)`, `complex128`, `0`},
+		{`package e7; const _ = complex128(-1e-2000)`, `complex128(-1e-2000)`, `complex128`, `0`},
+
+		{`package f0 ; var _ float32 =  1e-200`, `1e-200`, `float32`, `0`},
+		{`package f1 ; var _ float32 = -1e-200`, `-1e-200`, `float32`, `0`},
+		{`package f2a; var _ float64 =  1e-2000`, `1e-2000`, `float64`, `0`},
+		{`package f3a; var _ float64 = -1e-2000`, `-1e-2000`, `float64`, `0`},
+		{`package f2b; var _         =  1e-2000`, `1e-2000`, `float64`, `0`},
+		{`package f3b; var _         = -1e-2000`, `-1e-2000`, `float64`, `0`},
+		{`package f4 ; var _ complex64  =  1e-200 `, `1e-200`, `complex64`, `0`},
+		{`package f5 ; var _ complex64  = -1e-200 `, `-1e-200`, `complex64`, `0`},
+		{`package f6a; var _ complex128 =  1e-2000i`, `1e-2000i`, `complex128`, `0`},
+		{`package f7a; var _ complex128 = -1e-2000i`, `-1e-2000i`, `complex128`, `0`},
+		{`package f6b; var _            =  1e-2000i`, `1e-2000i`, `complex128`, `0`},
+		{`package f7b; var _            = -1e-2000i`, `-1e-2000i`, `complex128`, `0`},
+	}
+
+	for _, test := range tests {
+		info := Info{
+			Types: make(map[ast.Expr]TypeAndValue),
+		}
+		name := mustTypecheck(t, "ValuesInfo", test.src, &info)
+
+		// look for constant expression
+		var expr ast.Expr
+		for e := range info.Types {
+			if ExprString(e) == test.expr {
+				expr = e
+				break
+			}
+		}
+		if expr == nil {
+			t.Errorf("package %s: no expression found for %s", name, test.expr)
+			continue
+		}
+		tv := info.Types[expr]
+
+		// check that type is correct
+		if got := tv.Type.String(); got != test.typ {
+			t.Errorf("package %s: got type %s; want %s", name, got, test.typ)
+			continue
+		}
+
+		// check that value is correct
+		if got := tv.Value.String(); got != test.val {
+			t.Errorf("package %s: got value %s; want %s", name, got, test.val)
+		}
+	}
+}
+
+func TestTypesInfo(t *testing.T) {
+	var tests = []struct {
+		src  string
+		expr string // expression
+		typ  string // value type
+	}{
+		// single-valued expressions of untyped constants
+		{`package b0; var x interface{} = false`, `false`, `bool`},
+		{`package b1; var x interface{} = 0`, `0`, `int`},
+		{`package b2; var x interface{} = 0.`, `0.`, `float64`},
+		{`package b3; var x interface{} = 0i`, `0i`, `complex128`},
+		{`package b4; var x interface{} = "foo"`, `"foo"`, `string`},
+
+		// comma-ok expressions
+		{`package p0; var x interface{}; var _, _ = x.(int)`,
+			`x.(int)`,
+			`(int, bool)`,
+		},
+		{`package p1; var x interface{}; func _() { _, _ = x.(int) }`,
+			`x.(int)`,
+			`(int, bool)`,
+		},
+		// TODO(gri): uncomment if we accept issue 8189.
+		// {`package p2; type mybool bool; var m map[string]complex128; var b mybool; func _() { _, b = m["foo"] }`,
+		// 	`m["foo"]`,
+		// 	`(complex128, p2.mybool)`,
+		// },
+		// TODO(gri): remove if we accept issue 8189.
+		{`package p2; var m map[string]complex128; var b bool; func _() { _, b = m["foo"] }`,
+			`m["foo"]`,
+			`(complex128, bool)`,
+		},
+		{`package p3; var c chan string; var _, _ = <-c`,
+			`<-c`,
+			`(string, bool)`,
+		},
+
+		// issue 6796
+		{`package issue6796_a; var x interface{}; var _, _ = (x.(int))`,
+			`x.(int)`,
+			`(int, bool)`,
+		},
+		{`package issue6796_b; var c chan string; var _, _ = (<-c)`,
+			`(<-c)`,
+			`(string, bool)`,
+		},
+		{`package issue6796_c; var c chan string; var _, _ = (<-c)`,
+			`<-c`,
+			`(string, bool)`,
+		},
+		{`package issue6796_d; var c chan string; var _, _ = ((<-c))`,
+			`(<-c)`,
+			`(string, bool)`,
+		},
+		{`package issue6796_e; func f(c chan string) { _, _ = ((<-c)) }`,
+			`(<-c)`,
+			`(string, bool)`,
+		},
+
+		// issue 7060
+		{`package issue7060_a; var ( m map[int]string; x, ok = m[0] )`,
+			`m[0]`,
+			`(string, bool)`,
+		},
+		{`package issue7060_b; var ( m map[int]string; x, ok interface{} = m[0] )`,
+			`m[0]`,
+			`(string, bool)`,
+		},
+		{`package issue7060_c; func f(x interface{}, ok bool, m map[int]string) { x, ok = m[0] }`,
+			`m[0]`,
+			`(string, bool)`,
+		},
+		{`package issue7060_d; var ( ch chan string; x, ok = <-ch )`,
+			`<-ch`,
+			`(string, bool)`,
+		},
+		{`package issue7060_e; var ( ch chan string; x, ok interface{} = <-ch )`,
+			`<-ch`,
+			`(string, bool)`,
+		},
+		{`package issue7060_f; func f(x interface{}, ok bool, ch chan string) { x, ok = <-ch }`,
+			`<-ch`,
+			`(string, bool)`,
+		},
+	}
+
+	for _, test := range tests {
+		info := Info{Types: make(map[ast.Expr]TypeAndValue)}
+		name := mustTypecheck(t, "TypesInfo", test.src, &info)
+
+		// look for expression type
+		var typ Type
+		for e, tv := range info.Types {
+			if ExprString(e) == test.expr {
+				typ = tv.Type
+				break
+			}
+		}
+		if typ == nil {
+			t.Errorf("package %s: no type found for %s", name, test.expr)
+			continue
+		}
+
+		// check that type is correct
+		if got := typ.String(); got != test.typ {
+			t.Errorf("package %s: got %s; want %s", name, got, test.typ)
+		}
+	}
+}
+
+func predString(tv TypeAndValue) string {
+	var buf bytes.Buffer
+	pred := func(b bool, s string) {
+		if b {
+			if buf.Len() > 0 {
+				buf.WriteString(", ")
+			}
+			buf.WriteString(s)
+		}
+	}
+
+	pred(tv.IsVoid(), "void")
+	pred(tv.IsType(), "type")
+	pred(tv.IsBuiltin(), "builtin")
+	pred(tv.IsValue() && tv.Value != nil, "const")
+	pred(tv.IsValue() && tv.Value == nil, "value")
+	pred(tv.IsNil(), "nil")
+	pred(tv.Addressable(), "addressable")
+	pred(tv.Assignable(), "assignable")
+	pred(tv.HasOk(), "hasOk")
+
+	if buf.Len() == 0 {
+		return "invalid"
+	}
+	return buf.String()
+}
+
+func TestPredicatesInfo(t *testing.T) {
+	testenv.MustHaveGoBuild(t)
+
+	var tests = []struct {
+		src  string
+		expr string
+		pred string
+	}{
+		// void
+		{`package n0; func f() { f() }`, `f()`, `void`},
+
+		// types
+		{`package t0; type _ int`, `int`, `type`},
+		{`package t1; type _ []int`, `[]int`, `type`},
+		{`package t2; type _ func()`, `func()`, `type`},
+
+		// built-ins
+		{`package b0; var _ = len("")`, `len`, `builtin`},
+		{`package b1; var _ = (len)("")`, `(len)`, `builtin`},
+
+		// constants
+		{`package c0; var _ = 42`, `42`, `const`},
+		{`package c1; var _ = "foo" + "bar"`, `"foo" + "bar"`, `const`},
+		{`package c2; const (i = 1i; _ = i)`, `i`, `const`},
+
+		// values
+		{`package v0; var (a, b int; _ = a + b)`, `a + b`, `value`},
+		{`package v1; var _ = &[]int{1}`, `([]int literal)`, `value`},
+		{`package v2; var _ = func(){}`, `(func() literal)`, `value`},
+		{`package v4; func f() { _ = f }`, `f`, `value`},
+		{`package v3; var _ *int = nil`, `nil`, `value, nil`},
+		{`package v3; var _ *int = (nil)`, `(nil)`, `value, nil`},
+
+		// addressable (and thus assignable) operands
+		{`package a0; var (x int; _ = x)`, `x`, `value, addressable, assignable`},
+		{`package a1; var (p *int; _ = *p)`, `*p`, `value, addressable, assignable`},
+		{`package a2; var (s []int; _ = s[0])`, `s[0]`, `value, addressable, assignable`},
+		{`package a3; var (s struct{f int}; _ = s.f)`, `s.f`, `value, addressable, assignable`},
+		{`package a4; var (a [10]int; _ = a[0])`, `a[0]`, `value, addressable, assignable`},
+		{`package a5; func _(x int) { _ = x }`, `x`, `value, addressable, assignable`},
+		{`package a6; func _()(x int) { _ = x; return }`, `x`, `value, addressable, assignable`},
+		{`package a7; type T int; func (x T) _() { _ = x }`, `x`, `value, addressable, assignable`},
+		// composite literals are not addressable
+
+		// assignable but not addressable values
+		{`package s0; var (m map[int]int; _ = m[0])`, `m[0]`, `value, assignable, hasOk`},
+		{`package s1; var (m map[int]int; _, _ = m[0])`, `m[0]`, `value, assignable, hasOk`},
+
+		// hasOk expressions
+		{`package k0; var (ch chan int; _ = <-ch)`, `<-ch`, `value, hasOk`},
+		{`package k1; var (ch chan int; _, _ = <-ch)`, `<-ch`, `value, hasOk`},
+
+		// missing entries
+		// - package names are collected in the Uses map
+		// - identifiers being declared are collected in the Defs map
+		{`package m0; import "os"; func _() { _ = os.Stdout }`, `os`, `<missing>`},
+		{`package m1; import p "os"; func _() { _ = p.Stdout }`, `p`, `<missing>`},
+		{`package m2; const c = 0`, `c`, `<missing>`},
+		{`package m3; type T int`, `T`, `<missing>`},
+		{`package m4; var v int`, `v`, `<missing>`},
+		{`package m5; func f() {}`, `f`, `<missing>`},
+		{`package m6; func _(x int) {}`, `x`, `<missing>`},
+		{`package m6; func _()(x int) { return }`, `x`, `<missing>`},
+		{`package m6; type T int; func (x T) _() {}`, `x`, `<missing>`},
+	}
+
+	for _, test := range tests {
+		info := Info{Types: make(map[ast.Expr]TypeAndValue)}
+		name := mustTypecheck(t, "PredicatesInfo", test.src, &info)
+
+		// look for expression predicates
+		got := "<missing>"
+		for e, tv := range info.Types {
+			//println(name, ExprString(e))
+			if ExprString(e) == test.expr {
+				got = predString(tv)
+				break
+			}
+		}
+
+		if got != test.pred {
+			t.Errorf("package %s: got %s; want %s", name, got, test.pred)
+		}
+	}
+}
+
+func TestScopesInfo(t *testing.T) {
+	testenv.MustHaveGoBuild(t)
+
+	var tests = []struct {
+		src    string
+		scopes []string // list of scope descriptors of the form kind:varlist
+	}{
+		{`package p0`, []string{
+			"file:",
+		}},
+		{`package p1; import ( "fmt"; m "math"; _ "os" ); var ( _ = fmt.Println; _ = m.Pi )`, []string{
+			"file:fmt m",
+		}},
+		{`package p2; func _() {}`, []string{
+			"file:", "func:",
+		}},
+		{`package p3; func _(x, y int) {}`, []string{
+			"file:", "func:x y",
+		}},
+		{`package p4; func _(x, y int) { x, z := 1, 2; _ = z }`, []string{
+			"file:", "func:x y z", // redeclaration of x
+		}},
+		{`package p5; func _(x, y int) (u, _ int) { return }`, []string{
+			"file:", "func:u x y",
+		}},
+		{`package p6; func _() { { var x int; _ = x } }`, []string{
+			"file:", "func:", "block:x",
+		}},
+		{`package p7; func _() { if true {} }`, []string{
+			"file:", "func:", "if:", "block:",
+		}},
+		{`package p8; func _() { if x := 0; x < 0 { y := x; _ = y } }`, []string{
+			"file:", "func:", "if:x", "block:y",
+		}},
+		{`package p9; func _() { switch x := 0; x {} }`, []string{
+			"file:", "func:", "switch:x",
+		}},
+		{`package p10; func _() { switch x := 0; x { case 1: y := x; _ = y; default: }}`, []string{
+			"file:", "func:", "switch:x", "case:y", "case:",
+		}},
+		{`package p11; func _(t interface{}) { switch t.(type) {} }`, []string{
+			"file:", "func:t", "type switch:",
+		}},
+		{`package p12; func _(t interface{}) { switch t := t; t.(type) {} }`, []string{
+			"file:", "func:t", "type switch:t",
+		}},
+		{`package p13; func _(t interface{}) { switch x := t.(type) { case int: _ = x } }`, []string{
+			"file:", "func:t", "type switch:", "case:x", // x implicitly declared
+		}},
+		{`package p14; func _() { select{} }`, []string{
+			"file:", "func:",
+		}},
+		{`package p15; func _(c chan int) { select{ case <-c: } }`, []string{
+			"file:", "func:c", "comm:",
+		}},
+		{`package p16; func _(c chan int) { select{ case i := <-c: x := i; _ = x} }`, []string{
+			"file:", "func:c", "comm:i x",
+		}},
+		{`package p17; func _() { for{} }`, []string{
+			"file:", "func:", "for:", "block:",
+		}},
+		{`package p18; func _(n int) { for i := 0; i < n; i++ { _ = i } }`, []string{
+			"file:", "func:n", "for:i", "block:",
+		}},
+		{`package p19; func _(a []int) { for i := range a { _ = i} }`, []string{
+			"file:", "func:a", "range:i", "block:",
+		}},
+		{`package p20; var s int; func _(a []int) { for i, x := range a { s += x; _ = i } }`, []string{
+			"file:", "func:a", "range:i x", "block:",
+		}},
+	}
+
+	for _, test := range tests {
+		info := Info{Scopes: make(map[ast.Node]*Scope)}
+		name := mustTypecheck(t, "ScopesInfo", test.src, &info)
+
+		// number of scopes must match
+		if len(info.Scopes) != len(test.scopes) {
+			t.Errorf("package %s: got %d scopes; want %d", name, len(info.Scopes), len(test.scopes))
+		}
+
+		// scope descriptions must match
+		for node, scope := range info.Scopes {
+			kind := "<unknown node kind>"
+			switch node.(type) {
+			case *ast.File:
+				kind = "file"
+			case *ast.FuncType:
+				kind = "func"
+			case *ast.BlockStmt:
+				kind = "block"
+			case *ast.IfStmt:
+				kind = "if"
+			case *ast.SwitchStmt:
+				kind = "switch"
+			case *ast.TypeSwitchStmt:
+				kind = "type switch"
+			case *ast.CaseClause:
+				kind = "case"
+			case *ast.CommClause:
+				kind = "comm"
+			case *ast.ForStmt:
+				kind = "for"
+			case *ast.RangeStmt:
+				kind = "range"
+			}
+
+			// look for matching scope description
+			desc := kind + ":" + strings.Join(scope.Names(), " ")
+			found := false
+			for _, d := range test.scopes {
+				if desc == d {
+					found = true
+					break
+				}
+			}
+			if !found {
+				t.Errorf("package %s: no matching scope found for %s", name, desc)
+			}
+		}
+	}
+}
+
+func TestInitOrderInfo(t *testing.T) {
+	var tests = []struct {
+		src   string
+		inits []string
+	}{
+		{`package p0; var (x = 1; y = x)`, []string{
+			"x = 1", "y = x",
+		}},
+		{`package p1; var (a = 1; b = 2; c = 3)`, []string{
+			"a = 1", "b = 2", "c = 3",
+		}},
+		{`package p2; var (a, b, c = 1, 2, 3)`, []string{
+			"a = 1", "b = 2", "c = 3",
+		}},
+		{`package p3; var _ = f(); func f() int { return 1 }`, []string{
+			"_ = f()", // blank var
+		}},
+		{`package p4; var (a = 0; x = y; y = z; z = 0)`, []string{
+			"a = 0", "z = 0", "y = z", "x = y",
+		}},
+		{`package p5; var (a, _ = m[0]; m map[int]string)`, []string{
+			"a, _ = m[0]", // blank var
+		}},
+		{`package p6; var a, b = f(); func f() (_, _ int) { return z, z }; var z = 0`, []string{
+			"z = 0", "a, b = f()",
+		}},
+		{`package p7; var (a = func() int { return b }(); b = 1)`, []string{
+			"b = 1", "a = (func() int literal)()",
+		}},
+		{`package p8; var (a, b = func() (_, _ int) { return c, c }(); c = 1)`, []string{
+			"c = 1", "a, b = (func() (_, _ int) literal)()",
+		}},
+		{`package p9; type T struct{}; func (T) m() int { _ = y; return 0 }; var x, y = T.m, 1`, []string{
+			"y = 1", "x = T.m",
+		}},
+		{`package p10; var (d = c + b; a = 0; b = 0; c = 0)`, []string{
+			"a = 0", "b = 0", "c = 0", "d = c + b",
+		}},
+		{`package p11; var (a = e + c; b = d + c; c = 0; d = 0; e = 0)`, []string{
+			"c = 0", "d = 0", "b = d + c", "e = 0", "a = e + c",
+		}},
+		// emit an initializer for n:1 initializations only once (not for each node
+		// on the lhs which may appear in different order in the dependency graph)
+		{`package p12; var (a = x; b = 0; x, y = m[0]; m map[int]int)`, []string{
+			"b = 0", "x, y = m[0]", "a = x",
+		}},
+		// test case from spec section on package initialization
+		{`package p12
+
+		var (
+			a = c + b
+			b = f()
+			c = f()
+			d = 3
+		)
+
+		func f() int {
+			d++
+			return d
+		}`, []string{
+			"d = 3", "b = f()", "c = f()", "a = c + b",
+		}},
+		// test case for issue 7131
+		{`package main
+
+		var counter int
+		func next() int { counter++; return counter }
+
+		var _ = makeOrder()
+		func makeOrder() []int { return []int{f, b, d, e, c, a} }
+
+		var a       = next()
+		var b, c    = next(), next()
+		var d, e, f = next(), next(), next()
+		`, []string{
+			"a = next()", "b = next()", "c = next()", "d = next()", "e = next()", "f = next()", "_ = makeOrder()",
+		}},
+	}
+
+	for _, test := range tests {
+		info := Info{}
+		name := mustTypecheck(t, "InitOrderInfo", test.src, &info)
+
+		// number of initializers must match
+		if len(info.InitOrder) != len(test.inits) {
+			t.Errorf("package %s: got %d initializers; want %d", name, len(info.InitOrder), len(test.inits))
+			continue
+		}
+
+		// initializers must match
+		for i, want := range test.inits {
+			got := info.InitOrder[i].String()
+			if got != want {
+				t.Errorf("package %s, init %d: got %s; want %s", name, i, got, want)
+				continue
+			}
+		}
+	}
+}
+
+func TestMultiFileInitOrder(t *testing.T) {
+	fset := token.NewFileSet()
+	mustParse := func(src string) *ast.File {
+		f, err := parser.ParseFile(fset, "main", src, 0)
+		if err != nil {
+			t.Fatal(err)
+		}
+		return f
+	}
+
+	fileA := mustParse(`package main; var a = 1`)
+	fileB := mustParse(`package main; var b = 2`)
+
+	// The initialization order must not depend on the parse
+	// order of the files, only on the presentation order to
+	// the type-checker.
+	for _, test := range []struct {
+		files []*ast.File
+		want  string
+	}{
+		{[]*ast.File{fileA, fileB}, "[a = 1 b = 2]"},
+		{[]*ast.File{fileB, fileA}, "[b = 2 a = 1]"},
+	} {
+		var info Info
+		if _, err := new(Config).Check("main", fset, test.files, &info); err != nil {
+			t.Fatal(err)
+		}
+		if got := fmt.Sprint(info.InitOrder); got != test.want {
+			t.Fatalf("got %s; want %s", got, test.want)
+		}
+	}
+}
+
+func TestFiles(t *testing.T) {
+	var sources = []string{
+		"package p; type T struct{}; func (T) m1() {}",
+		"package p; func (T) m2() {}; var x interface{ m1(); m2() } = T{}",
+		"package p; func (T) m3() {}; var y interface{ m1(); m2(); m3() } = T{}",
+		"package p",
+	}
+
+	var conf Config
+	fset := token.NewFileSet()
+	pkg := NewPackage("p", "p")
+	var info Info
+	check := NewChecker(&conf, fset, pkg, &info)
+
+	for i, src := range sources {
+		filename := fmt.Sprintf("sources%d", i)
+		f, err := parser.ParseFile(fset, filename, src, 0)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if err := check.Files([]*ast.File{f}); err != nil {
+			t.Error(err)
+		}
+	}
+
+	// check InitOrder is [x y]
+	var vars []string
+	for _, init := range info.InitOrder {
+		for _, v := range init.Lhs {
+			vars = append(vars, v.Name())
+		}
+	}
+	if got, want := fmt.Sprint(vars), "[x y]"; got != want {
+		t.Errorf("InitOrder == %s, want %s", got, want)
+	}
+}
+
+type testImporter map[string]*Package
+
+func (m testImporter) Import(path string) (*Package, error) {
+	if pkg := m[path]; pkg != nil {
+		return pkg, nil
+	}
+	return nil, fmt.Errorf("package %q not found", path)
+}
+
+func TestSelection(t *testing.T) {
+	selections := make(map[*ast.SelectorExpr]*Selection)
+
+	fset := token.NewFileSet()
+	imports := make(testImporter)
+	conf := Config{Importer: imports}
+	makePkg := func(path, src string) {
+		f, err := parser.ParseFile(fset, path+".go", src, 0)
+		if err != nil {
+			t.Fatal(err)
+		}
+		pkg, err := conf.Check(path, fset, []*ast.File{f}, &Info{Selections: selections})
+		if err != nil {
+			t.Fatal(err)
+		}
+		imports[path] = pkg
+	}
+
+	const libSrc = `
+package lib
+type T float64
+const C T = 3
+var V T
+func F() {}
+func (T) M() {}
+`
+	const mainSrc = `
+package main
+import "lib"
+
+type A struct {
+	*B
+	C
+}
+
+type B struct {
+	b int
+}
+
+func (B) f(int)
+
+type C struct {
+	c int
+}
+
+func (C) g()
+func (*C) h()
+
+func main() {
+	// qualified identifiers
+	var _ lib.T
+        _ = lib.C
+        _ = lib.F
+        _ = lib.V
+	_ = lib.T.M
+
+	// fields
+	_ = A{}.B
+	_ = new(A).B
+
+	_ = A{}.C
+	_ = new(A).C
+
+	_ = A{}.b
+	_ = new(A).b
+
+	_ = A{}.c
+	_ = new(A).c
+
+	// methods
+        _ = A{}.f
+        _ = new(A).f
+        _ = A{}.g
+        _ = new(A).g
+        _ = new(A).h
+
+        _ = B{}.f
+        _ = new(B).f
+
+        _ = C{}.g
+        _ = new(C).g
+        _ = new(C).h
+
+	// method expressions
+        _ = A.f
+        _ = (*A).f
+        _ = B.f
+        _ = (*B).f
+}`
+
+	wantOut := map[string][2]string{
+		"lib.T.M": {"method expr (lib.T) M(lib.T)", ".[0]"},
+
+		"A{}.B":    {"field (main.A) B *main.B", ".[0]"},
+		"new(A).B": {"field (*main.A) B *main.B", "->[0]"},
+		"A{}.C":    {"field (main.A) C main.C", ".[1]"},
+		"new(A).C": {"field (*main.A) C main.C", "->[1]"},
+		"A{}.b":    {"field (main.A) b int", "->[0 0]"},
+		"new(A).b": {"field (*main.A) b int", "->[0 0]"},
+		"A{}.c":    {"field (main.A) c int", ".[1 0]"},
+		"new(A).c": {"field (*main.A) c int", "->[1 0]"},
+
+		"A{}.f":    {"method (main.A) f(int)", "->[0 0]"},
+		"new(A).f": {"method (*main.A) f(int)", "->[0 0]"},
+		"A{}.g":    {"method (main.A) g()", ".[1 0]"},
+		"new(A).g": {"method (*main.A) g()", "->[1 0]"},
+		"new(A).h": {"method (*main.A) h()", "->[1 1]"}, // TODO(gri) should this report .[1 1] ?
+		"B{}.f":    {"method (main.B) f(int)", ".[0]"},
+		"new(B).f": {"method (*main.B) f(int)", "->[0]"},
+		"C{}.g":    {"method (main.C) g()", ".[0]"},
+		"new(C).g": {"method (*main.C) g()", "->[0]"},
+		"new(C).h": {"method (*main.C) h()", "->[1]"}, // TODO(gri) should this report .[1] ?
+
+		"A.f":    {"method expr (main.A) f(main.A, int)", "->[0 0]"},
+		"(*A).f": {"method expr (*main.A) f(*main.A, int)", "->[0 0]"},
+		"B.f":    {"method expr (main.B) f(main.B, int)", ".[0]"},
+		"(*B).f": {"method expr (*main.B) f(*main.B, int)", "->[0]"},
+	}
+
+	makePkg("lib", libSrc)
+	makePkg("main", mainSrc)
+
+	for e, sel := range selections {
+		sel.String() // assertion: must not panic
+
+		start := fset.Position(e.Pos()).Offset
+		end := fset.Position(e.End()).Offset
+		syntax := mainSrc[start:end] // (all SelectorExprs are in main, not lib)
+
+		direct := "."
+		if sel.Indirect() {
+			direct = "->"
+		}
+		got := [2]string{
+			sel.String(),
+			fmt.Sprintf("%s%v", direct, sel.Index()),
+		}
+		want := wantOut[syntax]
+		if want != got {
+			t.Errorf("%s: got %q; want %q", syntax, got, want)
+		}
+		delete(wantOut, syntax)
+
+		// We must explicitly assert properties of the
+		// Signature's receiver since it doesn't participate
+		// in Identical() or String().
+		sig, _ := sel.Type().(*Signature)
+		if sel.Kind() == MethodVal {
+			got := sig.Recv().Type()
+			want := sel.Recv()
+			if !Identical(got, want) {
+				t.Errorf("%s: Recv() = %s, want %s", syntax, got, want)
+			}
+		} else if sig != nil && sig.Recv() != nil {
+			t.Errorf("%s: signature has receiver %s", sig, sig.Recv().Type())
+		}
+	}
+	// Assert that all wantOut entries were used exactly once.
+	for syntax := range wantOut {
+		t.Errorf("no ast.Selection found with syntax %q", syntax)
+	}
+}
+
+func TestIssue8518(t *testing.T) {
+	fset := token.NewFileSet()
+	imports := make(testImporter)
+	conf := Config{
+		Error:    func(err error) { t.Log(err) }, // don't exit after first error
+		Importer: imports,
+	}
+	makePkg := func(path, src string) {
+		f, err := parser.ParseFile(fset, path, src, 0)
+		if err != nil {
+			t.Fatal(err)
+		}
+		pkg, _ := conf.Check(path, fset, []*ast.File{f}, nil) // errors logged via conf.Error
+		imports[path] = pkg
+	}
+
+	const libSrc = `
+package a
+import "missing"
+const C1 = foo
+const C2 = missing.C
+`
+
+	const mainSrc = `
+package main
+import "a"
+var _ = a.C1
+var _ = a.C2
+`
+
+	makePkg("a", libSrc)
+	makePkg("main", mainSrc) // don't crash when type-checking this package
+}
+
+func TestLookupFieldOrMethod(t *testing.T) {
+	// Test cases assume a lookup of the form a.f or x.f, where a stands for an
+	// addressable value, and x for a non-addressable value (even though a variable
+	// for ease of test case writing).
+	var tests = []struct {
+		src      string
+		found    bool
+		index    []int
+		indirect bool
+	}{
+		// field lookups
+		{"var x T; type T struct{}", false, nil, false},
+		{"var x T; type T struct{ f int }", true, []int{0}, false},
+		{"var x T; type T struct{ a, b, f, c int }", true, []int{2}, false},
+
+		// method lookups
+		{"var a T; type T struct{}; func (T) f() {}", true, []int{0}, false},
+		{"var a *T; type T struct{}; func (T) f() {}", true, []int{0}, true},
+		{"var a T; type T struct{}; func (*T) f() {}", true, []int{0}, false},
+		{"var a *T; type T struct{}; func (*T) f() {}", true, []int{0}, true}, // TODO(gri) should this report indirect = false?
+
+		// collisions
+		{"type ( E1 struct{ f int }; E2 struct{ f int }; x struct{ E1; *E2 })", false, []int{1, 0}, false},
+		{"type ( E1 struct{ f int }; E2 struct{}; x struct{ E1; *E2 }); func (E2) f() {}", false, []int{1, 0}, false},
+
+		// outside methodset
+		// (*T).f method exists, but value of type T is not addressable
+		{"var x T; type T struct{}; func (*T) f() {}", false, nil, true},
+	}
+
+	for _, test := range tests {
+		pkg, err := pkgFor("test", "package p;"+test.src, nil)
+		if err != nil {
+			t.Errorf("%s: incorrect test case: %s", test.src, err)
+			continue
+		}
+
+		obj := pkg.Scope().Lookup("a")
+		if obj == nil {
+			if obj = pkg.Scope().Lookup("x"); obj == nil {
+				t.Errorf("%s: incorrect test case - no object a or x", test.src)
+				continue
+			}
+		}
+
+		f, index, indirect := LookupFieldOrMethod(obj.Type(), obj.Name() == "a", pkg, "f")
+		if (f != nil) != test.found {
+			if f == nil {
+				t.Errorf("%s: got no object; want one", test.src)
+			} else {
+				t.Errorf("%s: got object = %v; want none", test.src, f)
+			}
+		}
+		if !sameSlice(index, test.index) {
+			t.Errorf("%s: got index = %v; want %v", test.src, index, test.index)
+		}
+		if indirect != test.indirect {
+			t.Errorf("%s: got indirect = %v; want %v", test.src, indirect, test.indirect)
+		}
+	}
+}
+
+func sameSlice(a, b []int) bool {
+	if len(a) != len(b) {
+		return false
+	}
+	for i, x := range a {
+		if x != b[i] {
+			return false
+		}
+	}
+	return true
+}
+
+// TestScopeLookupParent ensures that (*Scope).LookupParent returns
+// the correct result at various positions with the source.
+func TestScopeLookupParent(t *testing.T) {
+	fset := token.NewFileSet()
+	imports := make(testImporter)
+	conf := Config{Importer: imports}
+	mustParse := func(src string) *ast.File {
+		f, err := parser.ParseFile(fset, "dummy.go", src, parser.ParseComments)
+		if err != nil {
+			t.Fatal(err)
+		}
+		return f
+	}
+	var info Info
+	makePkg := func(path string, files ...*ast.File) {
+		imports[path], _ = conf.Check(path, fset, files, &info)
+	}
+
+	makePkg("lib", mustParse("package lib; var X int"))
+	// Each /*name=kind:line*/ comment makes the test look up the
+	// name at that point and checks that it resolves to a decl of
+	// the specified kind and line number.  "undef" means undefined.
+	mainSrc := `
+package main
+import "lib"
+var Y = lib.X
+func f() {
+	print(Y) /*Y=var:4*/
+	z /*z=undef*/ := /*z=undef*/ 1 /*z=var:7*/
+	print(z)
+	/*f=func:5*/ /*lib=pkgname:3*/
+	type /*T=undef*/ T /*T=typename:10*/ *T
+}
+`
+	info.Uses = make(map[*ast.Ident]Object)
+	f := mustParse(mainSrc)
+	makePkg("main", f)
+	mainScope := imports["main"].Scope()
+	rx := regexp.MustCompile(`^/\*(\w*)=([\w:]*)\*/$`)
+	for _, group := range f.Comments {
+		for _, comment := range group.List {
+			// Parse the assertion in the comment.
+			m := rx.FindStringSubmatch(comment.Text)
+			if m == nil {
+				t.Errorf("%s: bad comment: %s",
+					fset.Position(comment.Pos()), comment.Text)
+				continue
+			}
+			name, want := m[1], m[2]
+
+			// Look up the name in the innermost enclosing scope.
+			inner := mainScope.Innermost(comment.Pos())
+			if inner == nil {
+				t.Errorf("%s: at %s: can't find innermost scope",
+					fset.Position(comment.Pos()), comment.Text)
+				continue
+			}
+			got := "undef"
+			if _, obj := inner.LookupParent(name, comment.Pos()); obj != nil {
+				kind := strings.ToLower(strings.TrimPrefix(reflect.TypeOf(obj).String(), "*types."))
+				got = fmt.Sprintf("%s:%d", kind, fset.Position(obj.Pos()).Line)
+			}
+			if got != want {
+				t.Errorf("%s: at %s: %s resolved to %s, want %s",
+					fset.Position(comment.Pos()), comment.Text, name, got, want)
+			}
+		}
+	}
+
+	// Check that for each referring identifier,
+	// a lookup of its name on the innermost
+	// enclosing scope returns the correct object.
+
+	for id, wantObj := range info.Uses {
+		inner := mainScope.Innermost(id.Pos())
+		if inner == nil {
+			t.Errorf("%s: can't find innermost scope enclosing %q",
+				fset.Position(id.Pos()), id.Name)
+			continue
+		}
+
+		// Exclude selectors and qualified identifiers---lexical
+		// refs only.  (Ideally, we'd see if the AST parent is a
+		// SelectorExpr, but that requires PathEnclosingInterval
+		// from golang.org/x/tools/go/ast/astutil.)
+		if id.Name == "X" {
+			continue
+		}
+
+		_, gotObj := inner.LookupParent(id.Name, id.Pos())
+		if gotObj != wantObj {
+			t.Errorf("%s: got %v, want %v",
+				fset.Position(id.Pos()), gotObj, wantObj)
+			continue
+		}
+	}
+}
diff --git a/src/go/types/assignments.go b/src/go/types/assignments.go
new file mode 100644
index 0000000..e88de56
--- /dev/null
+++ b/src/go/types/assignments.go
@@ -0,0 +1,328 @@
+// 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.
+
+// This file implements initialization and assignment checks.
+
+package types
+
+import (
+	"go/ast"
+	"go/token"
+)
+
+// assignment reports whether x can be assigned to a variable of type T,
+// if necessary by attempting to convert untyped values to the appropriate
+// type. If x.mode == invalid upon return, then assignment has already
+// issued an error message and the caller doesn't have to report another.
+// Use T == nil to indicate assignment to an untyped blank identifier.
+//
+// TODO(gri) Should find a better way to handle in-band errors.
+//
+func (check *Checker) assignment(x *operand, T Type) bool {
+	switch x.mode {
+	case invalid:
+		return true // error reported before
+	case constant_, variable, mapindex, value, commaok:
+		// ok
+	default:
+		unreachable()
+	}
+
+	// x must be a single value
+	// (tuple types are never named - no need for underlying type)
+	if t, _ := x.typ.(*Tuple); t != nil {
+		assert(t.Len() > 1)
+		check.errorf(x.pos(), "%d-valued expression %s used as single value", t.Len(), x)
+		x.mode = invalid
+		return false
+	}
+
+	if isUntyped(x.typ) {
+		target := T
+		// spec: "If an untyped constant is assigned to a variable of interface
+		// type or the blank identifier, the constant is first converted to type
+		// bool, rune, int, float64, complex128 or string respectively, depending
+		// on whether the value is a boolean, rune, integer, floating-point, complex,
+		// or string constant."
+		if T == nil || IsInterface(T) {
+			if T == nil && x.typ == Typ[UntypedNil] {
+				check.errorf(x.pos(), "use of untyped nil")
+				x.mode = invalid
+				return false
+			}
+			target = defaultType(x.typ)
+		}
+		check.convertUntyped(x, target)
+		if x.mode == invalid {
+			return false
+		}
+	}
+
+	// spec: "If a left-hand side is the blank identifier, any typed or
+	// non-constant value except for the predeclared identifier nil may
+	// be assigned to it."
+	return T == nil || x.assignableTo(check.conf, T)
+}
+
+func (check *Checker) initConst(lhs *Const, x *operand) {
+	if x.mode == invalid || x.typ == Typ[Invalid] || lhs.typ == Typ[Invalid] {
+		if lhs.typ == nil {
+			lhs.typ = Typ[Invalid]
+		}
+		return
+	}
+
+	// rhs must be a constant
+	if x.mode != constant_ {
+		check.errorf(x.pos(), "%s is not constant", x)
+		if lhs.typ == nil {
+			lhs.typ = Typ[Invalid]
+		}
+		return
+	}
+	assert(isConstType(x.typ))
+
+	// If the lhs doesn't have a type yet, use the type of x.
+	if lhs.typ == nil {
+		lhs.typ = x.typ
+	}
+
+	if !check.assignment(x, lhs.typ) {
+		if x.mode != invalid {
+			check.errorf(x.pos(), "cannot define constant %s (type %s) as %s", lhs.Name(), lhs.typ, x)
+		}
+		return
+	}
+
+	lhs.val = x.val
+}
+
+// If result is set, lhs is a function result parameter and x is a return result.
+func (check *Checker) initVar(lhs *Var, x *operand, result bool) Type {
+	if x.mode == invalid || x.typ == Typ[Invalid] || lhs.typ == Typ[Invalid] {
+		if lhs.typ == nil {
+			lhs.typ = Typ[Invalid]
+		}
+		return nil
+	}
+
+	// If the lhs doesn't have a type yet, use the type of x.
+	if lhs.typ == nil {
+		typ := x.typ
+		if isUntyped(typ) {
+			// convert untyped types to default types
+			if typ == Typ[UntypedNil] {
+				check.errorf(x.pos(), "use of untyped nil")
+				lhs.typ = Typ[Invalid]
+				return nil
+			}
+			typ = defaultType(typ)
+		}
+		lhs.typ = typ
+	}
+
+	if !check.assignment(x, lhs.typ) {
+		if x.mode != invalid {
+			if result {
+				// don't refer to lhs.name because it may be an anonymous result parameter
+				check.errorf(x.pos(), "cannot return %s as value of type %s", x, lhs.typ)
+			} else {
+				check.errorf(x.pos(), "cannot initialize %s with %s", lhs, x)
+			}
+		}
+		return nil
+	}
+
+	return x.typ
+}
+
+func (check *Checker) assignVar(lhs ast.Expr, x *operand) Type {
+	if x.mode == invalid || x.typ == Typ[Invalid] {
+		return nil
+	}
+
+	// Determine if the lhs is a (possibly parenthesized) identifier.
+	ident, _ := unparen(lhs).(*ast.Ident)
+
+	// Don't evaluate lhs if it is the blank identifier.
+	if ident != nil && ident.Name == "_" {
+		check.recordDef(ident, nil)
+		if !check.assignment(x, nil) {
+			assert(x.mode == invalid)
+			x.typ = nil
+		}
+		return x.typ
+	}
+
+	// If the lhs is an identifier denoting a variable v, this assignment
+	// is not a 'use' of v. Remember current value of v.used and restore
+	// after evaluating the lhs via check.expr.
+	var v *Var
+	var v_used bool
+	if ident != nil {
+		if _, obj := check.scope.LookupParent(ident.Name, token.NoPos); obj != nil {
+			v, _ = obj.(*Var)
+			if v != nil {
+				v_used = v.used
+			}
+		}
+	}
+
+	var z operand
+	check.expr(&z, lhs)
+	if v != nil {
+		v.used = v_used // restore v.used
+	}
+
+	if z.mode == invalid || z.typ == Typ[Invalid] {
+		return nil
+	}
+
+	// spec: "Each left-hand side operand must be addressable, a map index
+	// expression, or the blank identifier. Operands may be parenthesized."
+	switch z.mode {
+	case invalid:
+		return nil
+	case variable, mapindex:
+		// ok
+	default:
+		check.errorf(z.pos(), "cannot assign to %s", &z)
+		return nil
+	}
+
+	if !check.assignment(x, z.typ) {
+		if x.mode != invalid {
+			check.errorf(x.pos(), "cannot assign %s to %s", x, &z)
+		}
+		return nil
+	}
+
+	return x.typ
+}
+
+// If returnPos is valid, initVars is called to type-check the assignment of
+// return expressions, and returnPos is the position of the return statement.
+func (check *Checker) initVars(lhs []*Var, rhs []ast.Expr, returnPos token.Pos) {
+	l := len(lhs)
+	get, r, commaOk := unpack(func(x *operand, i int) { check.expr(x, rhs[i]) }, len(rhs), l == 2 && !returnPos.IsValid())
+	if get == nil || l != r {
+		// invalidate lhs and use rhs
+		for _, obj := range lhs {
+			if obj.typ == nil {
+				obj.typ = Typ[Invalid]
+			}
+		}
+		if get == nil {
+			return // error reported by unpack
+		}
+		check.useGetter(get, r)
+		if returnPos.IsValid() {
+			check.errorf(returnPos, "wrong number of return values (want %d, got %d)", l, r)
+			return
+		}
+		check.errorf(rhs[0].Pos(), "assignment count mismatch (%d vs %d)", l, r)
+		return
+	}
+
+	var x operand
+	if commaOk {
+		var a [2]Type
+		for i := range a {
+			get(&x, i)
+			a[i] = check.initVar(lhs[i], &x, returnPos.IsValid())
+		}
+		check.recordCommaOkTypes(rhs[0], a)
+		return
+	}
+
+	for i, lhs := range lhs {
+		get(&x, i)
+		check.initVar(lhs, &x, returnPos.IsValid())
+	}
+}
+
+func (check *Checker) assignVars(lhs, rhs []ast.Expr) {
+	l := len(lhs)
+	get, r, commaOk := unpack(func(x *operand, i int) { check.expr(x, rhs[i]) }, len(rhs), l == 2)
+	if get == nil {
+		return // error reported by unpack
+	}
+	if l != r {
+		check.useGetter(get, r)
+		check.errorf(rhs[0].Pos(), "assignment count mismatch (%d vs %d)", l, r)
+		return
+	}
+
+	var x operand
+	if commaOk {
+		var a [2]Type
+		for i := range a {
+			get(&x, i)
+			a[i] = check.assignVar(lhs[i], &x)
+		}
+		check.recordCommaOkTypes(rhs[0], a)
+		return
+	}
+
+	for i, lhs := range lhs {
+		get(&x, i)
+		check.assignVar(lhs, &x)
+	}
+}
+
+func (check *Checker) shortVarDecl(pos token.Pos, lhs, rhs []ast.Expr) {
+	scope := check.scope
+
+	// collect lhs variables
+	var newVars []*Var
+	var lhsVars = make([]*Var, len(lhs))
+	for i, lhs := range lhs {
+		var obj *Var
+		if ident, _ := lhs.(*ast.Ident); ident != nil {
+			// Use the correct obj if the ident is redeclared. The
+			// variable's scope starts after the declaration; so we
+			// must use Scope.Lookup here and call Scope.Insert
+			// (via check.declare) later.
+			name := ident.Name
+			if alt := scope.Lookup(name); alt != nil {
+				// redeclared object must be a variable
+				if alt, _ := alt.(*Var); alt != nil {
+					obj = alt
+				} else {
+					check.errorf(lhs.Pos(), "cannot assign to %s", lhs)
+				}
+				check.recordUse(ident, alt)
+			} else {
+				// declare new variable, possibly a blank (_) variable
+				obj = NewVar(ident.Pos(), check.pkg, name, nil)
+				if name != "_" {
+					newVars = append(newVars, obj)
+				}
+				check.recordDef(ident, obj)
+			}
+		} else {
+			check.errorf(lhs.Pos(), "cannot declare %s", lhs)
+		}
+		if obj == nil {
+			obj = NewVar(lhs.Pos(), check.pkg, "_", nil) // dummy variable
+		}
+		lhsVars[i] = obj
+	}
+
+	check.initVars(lhsVars, rhs, token.NoPos)
+
+	// declare new variables
+	if len(newVars) > 0 {
+		// spec: "The scope of a constant or variable identifier declared inside
+		// a function begins at the end of the ConstSpec or VarSpec (ShortVarDecl
+		// for short variable declarations) and ends at the end of the innermost
+		// containing block."
+		scopePos := rhs[len(rhs)-1].End()
+		for _, obj := range newVars {
+			check.declare(scope, nil, obj, scopePos) // recordObject already called
+		}
+	} else {
+		check.softErrorf(pos, "no new variables on left side of :=")
+	}
+}
diff --git a/src/go/types/builtins.go b/src/go/types/builtins.go
new file mode 100644
index 0000000..4729591
--- /dev/null
+++ b/src/go/types/builtins.go
@@ -0,0 +1,627 @@
+// 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.
+
+// This file implements typechecking of builtin function calls.
+
+package types
+
+import (
+	"go/ast"
+	"go/constant"
+	"go/token"
+)
+
+// builtin type-checks a call to the built-in specified by id and
+// returns true if the call is valid, with *x holding the result;
+// but x.expr is not set. If the call is invalid, the result is
+// false, and *x is undefined.
+//
+func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ bool) {
+	// append is the only built-in that permits the use of ... for the last argument
+	bin := predeclaredFuncs[id]
+	if call.Ellipsis.IsValid() && id != _Append {
+		check.invalidOp(call.Ellipsis, "invalid use of ... with built-in %s", bin.name)
+		check.use(call.Args...)
+		return
+	}
+
+	// For len(x) and cap(x) we need to know if x contains any function calls or
+	// receive operations. Save/restore current setting and set hasCallOrRecv to
+	// false for the evaluation of x so that we can check it afterwards.
+	// Note: We must do this _before_ calling unpack because unpack evaluates the
+	//       first argument before we even call arg(x, 0)!
+	if id == _Len || id == _Cap {
+		defer func(b bool) {
+			check.hasCallOrRecv = b
+		}(check.hasCallOrRecv)
+		check.hasCallOrRecv = false
+	}
+
+	// determine actual arguments
+	var arg getter
+	nargs := len(call.Args)
+	switch id {
+	default:
+		// make argument getter
+		arg, nargs, _ = unpack(func(x *operand, i int) { check.expr(x, call.Args[i]) }, nargs, false)
+		if arg == nil {
+			return
+		}
+		// evaluate first argument, if present
+		if nargs > 0 {
+			arg(x, 0)
+			if x.mode == invalid {
+				return
+			}
+		}
+	case _Make, _New, _Offsetof, _Trace:
+		// arguments require special handling
+	}
+
+	// check argument count
+	{
+		msg := ""
+		if nargs < bin.nargs {
+			msg = "not enough"
+		} else if !bin.variadic && nargs > bin.nargs {
+			msg = "too many"
+		}
+		if msg != "" {
+			check.invalidOp(call.Rparen, "%s arguments for %s (expected %d, found %d)", msg, call, bin.nargs, nargs)
+			return
+		}
+	}
+
+	switch id {
+	case _Append:
+		// append(s S, x ...T) S, where T is the element type of S
+		// spec: "The variadic function append appends zero or more values x to s of type
+		// S, which must be a slice type, and returns the resulting slice, also of type S.
+		// The values x are passed to a parameter of type ...T where T is the element type
+		// of S and the respective parameter passing rules apply."
+		S := x.typ
+		var T Type
+		if s, _ := S.Underlying().(*Slice); s != nil {
+			T = s.elem
+		} else {
+			check.invalidArg(x.pos(), "%s is not a slice", x)
+			return
+		}
+
+		// remember arguments that have been evaluated already
+		alist := []operand{*x}
+
+		// spec: "As a special case, append also accepts a first argument assignable
+		// to type []byte with a second argument of string type followed by ... .
+		// This form appends the bytes of the string.
+		if nargs == 2 && call.Ellipsis.IsValid() && x.assignableTo(check.conf, NewSlice(universeByte)) {
+			arg(x, 1)
+			if x.mode == invalid {
+				return
+			}
+			if isString(x.typ) {
+				if check.Types != nil {
+					sig := makeSig(S, S, x.typ)
+					sig.variadic = true
+					check.recordBuiltinType(call.Fun, sig)
+				}
+				x.mode = value
+				x.typ = S
+				break
+			}
+			alist = append(alist, *x)
+			// fallthrough
+		}
+
+		// check general case by creating custom signature
+		sig := makeSig(S, S, NewSlice(T)) // []T required for variadic signature
+		sig.variadic = true
+		check.arguments(x, call, sig, func(x *operand, i int) {
+			// only evaluate arguments that have not been evaluated before
+			if i < len(alist) {
+				*x = alist[i]
+				return
+			}
+			arg(x, i)
+		}, nargs)
+		// ok to continue even if check.arguments reported errors
+
+		x.mode = value
+		x.typ = S
+		if check.Types != nil {
+			check.recordBuiltinType(call.Fun, sig)
+		}
+
+	case _Cap, _Len:
+		// cap(x)
+		// len(x)
+		mode := invalid
+		var typ Type
+		var val constant.Value
+		switch typ = implicitArrayDeref(x.typ.Underlying()); t := typ.(type) {
+		case *Basic:
+			if isString(t) && id == _Len {
+				if x.mode == constant_ {
+					mode = constant_
+					val = constant.MakeInt64(int64(len(constant.StringVal(x.val))))
+				} else {
+					mode = value
+				}
+			}
+
+		case *Array:
+			mode = value
+			// spec: "The expressions len(s) and cap(s) are constants
+			// if the type of s is an array or pointer to an array and
+			// the expression s does not contain channel receives or
+			// function calls; in this case s is not evaluated."
+			if !check.hasCallOrRecv {
+				mode = constant_
+				val = constant.MakeInt64(t.len)
+			}
+
+		case *Slice, *Chan:
+			mode = value
+
+		case *Map:
+			if id == _Len {
+				mode = value
+			}
+		}
+
+		if mode == invalid {
+			check.invalidArg(x.pos(), "%s for %s", x, bin.name)
+			return
+		}
+
+		x.mode = mode
+		x.typ = Typ[Int]
+		x.val = val
+		if check.Types != nil && mode != constant_ {
+			check.recordBuiltinType(call.Fun, makeSig(x.typ, typ))
+		}
+
+	case _Close:
+		// close(c)
+		c, _ := x.typ.Underlying().(*Chan)
+		if c == nil {
+			check.invalidArg(x.pos(), "%s is not a channel", x)
+			return
+		}
+		if c.dir == RecvOnly {
+			check.invalidArg(x.pos(), "%s must not be a receive-only channel", x)
+			return
+		}
+
+		x.mode = novalue
+		if check.Types != nil {
+			check.recordBuiltinType(call.Fun, makeSig(nil, c))
+		}
+
+	case _Complex:
+		// complex(x, y realT) complexT
+		if !check.complexArg(x) {
+			return
+		}
+
+		var y operand
+		arg(&y, 1)
+		if y.mode == invalid {
+			return
+		}
+		if !check.complexArg(&y) {
+			return
+		}
+
+		check.convertUntyped(x, y.typ)
+		if x.mode == invalid {
+			return
+		}
+		check.convertUntyped(&y, x.typ)
+		if y.mode == invalid {
+			return
+		}
+
+		if !Identical(x.typ, y.typ) {
+			check.invalidArg(x.pos(), "mismatched types %s and %s", x.typ, y.typ)
+			return
+		}
+
+		if x.mode == constant_ && y.mode == constant_ {
+			x.val = constant.BinaryOp(x.val, token.ADD, constant.MakeImag(y.val))
+		} else {
+			x.mode = value
+		}
+
+		realT := x.typ
+		complexT := Typ[Invalid]
+		switch realT.Underlying().(*Basic).kind {
+		case Float32:
+			complexT = Typ[Complex64]
+		case Float64:
+			complexT = Typ[Complex128]
+		case UntypedInt, UntypedRune, UntypedFloat:
+			if x.mode == constant_ {
+				realT = defaultType(realT).(*Basic)
+				complexT = Typ[UntypedComplex]
+			} else {
+				// untyped but not constant; probably because one
+				// operand is a non-constant shift of untyped lhs
+				realT = Typ[Float64]
+				complexT = Typ[Complex128]
+			}
+		default:
+			check.invalidArg(x.pos(), "float32 or float64 arguments expected")
+			return
+		}
+
+		x.typ = complexT
+		if check.Types != nil && x.mode != constant_ {
+			check.recordBuiltinType(call.Fun, makeSig(complexT, realT, realT))
+		}
+
+		if x.mode != constant_ {
+			// The arguments have now their final types, which at run-
+			// time will be materialized. Update the expression trees.
+			// If the current types are untyped, the materialized type
+			// is the respective default type.
+			// (If the result is constant, the arguments are never
+			// materialized and there is nothing to do.)
+			check.updateExprType(x.expr, realT, true)
+			check.updateExprType(y.expr, realT, true)
+		}
+
+	case _Copy:
+		// copy(x, y []T) int
+		var dst Type
+		if t, _ := x.typ.Underlying().(*Slice); t != nil {
+			dst = t.elem
+		}
+
+		var y operand
+		arg(&y, 1)
+		if y.mode == invalid {
+			return
+		}
+		var src Type
+		switch t := y.typ.Underlying().(type) {
+		case *Basic:
+			if isString(y.typ) {
+				src = universeByte
+			}
+		case *Slice:
+			src = t.elem
+		}
+
+		if dst == nil || src == nil {
+			check.invalidArg(x.pos(), "copy expects slice arguments; found %s and %s", x, &y)
+			return
+		}
+
+		if !Identical(dst, src) {
+			check.invalidArg(x.pos(), "arguments to copy %s and %s have different element types %s and %s", x, &y, dst, src)
+			return
+		}
+
+		if check.Types != nil {
+			check.recordBuiltinType(call.Fun, makeSig(Typ[Int], x.typ, y.typ))
+		}
+		x.mode = value
+		x.typ = Typ[Int]
+
+	case _Delete:
+		// delete(m, k)
+		m, _ := x.typ.Underlying().(*Map)
+		if m == nil {
+			check.invalidArg(x.pos(), "%s is not a map", x)
+			return
+		}
+		arg(x, 1) // k
+		if x.mode == invalid {
+			return
+		}
+
+		if !x.assignableTo(check.conf, m.key) {
+			check.invalidArg(x.pos(), "%s is not assignable to %s", x, m.key)
+			return
+		}
+
+		x.mode = novalue
+		if check.Types != nil {
+			check.recordBuiltinType(call.Fun, makeSig(nil, m, m.key))
+		}
+
+	case _Imag, _Real:
+		// imag(complexT) realT
+		// real(complexT) realT
+		if !isComplex(x.typ) {
+			check.invalidArg(x.pos(), "%s must be a complex number", x)
+			return
+		}
+		if x.mode == constant_ {
+			if id == _Real {
+				x.val = constant.Real(x.val)
+			} else {
+				x.val = constant.Imag(x.val)
+			}
+		} else {
+			x.mode = value
+		}
+		var k BasicKind
+		switch x.typ.Underlying().(*Basic).kind {
+		case Complex64:
+			k = Float32
+		case Complex128:
+			k = Float64
+		case UntypedComplex:
+			k = UntypedFloat
+		default:
+			unreachable()
+		}
+
+		if check.Types != nil && x.mode != constant_ {
+			check.recordBuiltinType(call.Fun, makeSig(Typ[k], x.typ))
+		}
+		x.typ = Typ[k]
+
+	case _Make:
+		// make(T, n)
+		// make(T, n, m)
+		// (no argument evaluated yet)
+		arg0 := call.Args[0]
+		T := check.typ(arg0)
+		if T == Typ[Invalid] {
+			return
+		}
+
+		var min int // minimum number of arguments
+		switch T.Underlying().(type) {
+		case *Slice:
+			min = 2
+		case *Map, *Chan:
+			min = 1
+		default:
+			check.invalidArg(arg0.Pos(), "cannot make %s; type must be slice, map, or channel", arg0)
+			return
+		}
+		if nargs < min || min+1 < nargs {
+			check.errorf(call.Pos(), "%s expects %d or %d arguments; found %d", call, min, min+1, nargs)
+			return
+		}
+		var sizes []int64 // constant integer arguments, if any
+		for _, arg := range call.Args[1:] {
+			if s, ok := check.index(arg, -1); ok && s >= 0 {
+				sizes = append(sizes, s)
+			}
+		}
+		if len(sizes) == 2 && sizes[0] > sizes[1] {
+			check.invalidArg(call.Args[1].Pos(), "length and capacity swapped")
+			// safe to continue
+		}
+		x.mode = value
+		x.typ = T
+		if check.Types != nil {
+			params := [...]Type{T, Typ[Int], Typ[Int]}
+			check.recordBuiltinType(call.Fun, makeSig(x.typ, params[:1+len(sizes)]...))
+		}
+
+	case _New:
+		// new(T)
+		// (no argument evaluated yet)
+		T := check.typ(call.Args[0])
+		if T == Typ[Invalid] {
+			return
+		}
+
+		x.mode = value
+		x.typ = &Pointer{base: T}
+		if check.Types != nil {
+			check.recordBuiltinType(call.Fun, makeSig(x.typ, T))
+		}
+
+	case _Panic:
+		// panic(x)
+		T := new(Interface)
+		if !check.assignment(x, T) {
+			assert(x.mode == invalid)
+			return
+		}
+
+		x.mode = novalue
+		if check.Types != nil {
+			check.recordBuiltinType(call.Fun, makeSig(nil, T))
+		}
+
+	case _Print, _Println:
+		// print(x, y, ...)
+		// println(x, y, ...)
+		var params []Type
+		if nargs > 0 {
+			params = make([]Type, nargs)
+			for i := 0; i < nargs; i++ {
+				if i > 0 {
+					arg(x, i) // first argument already evaluated
+				}
+				if !check.assignment(x, nil) {
+					assert(x.mode == invalid)
+					return
+				}
+				params[i] = x.typ
+			}
+		}
+
+		x.mode = novalue
+		if check.Types != nil {
+			check.recordBuiltinType(call.Fun, makeSig(nil, params...))
+		}
+
+	case _Recover:
+		// recover() interface{}
+		x.mode = value
+		x.typ = new(Interface)
+		if check.Types != nil {
+			check.recordBuiltinType(call.Fun, makeSig(x.typ))
+		}
+
+	case _Alignof:
+		// unsafe.Alignof(x T) uintptr
+		if !check.assignment(x, nil) {
+			assert(x.mode == invalid)
+			return
+		}
+
+		x.mode = constant_
+		x.val = constant.MakeInt64(check.conf.alignof(x.typ))
+		x.typ = Typ[Uintptr]
+		// result is constant - no need to record signature
+
+	case _Offsetof:
+		// unsafe.Offsetof(x T) uintptr, where x must be a selector
+		// (no argument evaluated yet)
+		arg0 := call.Args[0]
+		selx, _ := unparen(arg0).(*ast.SelectorExpr)
+		if selx == nil {
+			check.invalidArg(arg0.Pos(), "%s is not a selector expression", arg0)
+			check.use(arg0)
+			return
+		}
+
+		check.expr(x, selx.X)
+		if x.mode == invalid {
+			return
+		}
+
+		base := derefStructPtr(x.typ)
+		sel := selx.Sel.Name
+		obj, index, indirect := LookupFieldOrMethod(base, false, check.pkg, sel)
+		switch obj.(type) {
+		case nil:
+			check.invalidArg(x.pos(), "%s has no single field %s", base, sel)
+			return
+		case *Func:
+			// TODO(gri) Using derefStructPtr may result in methods being found
+			// that don't actually exist. An error either way, but the error
+			// message is confusing. See: https://play.golang.org/p/al75v23kUy ,
+			// but go/types reports: "invalid argument: x.m is a method value".
+			check.invalidArg(arg0.Pos(), "%s is a method value", arg0)
+			return
+		}
+		if indirect {
+			check.invalidArg(x.pos(), "field %s is embedded via a pointer in %s", sel, base)
+			return
+		}
+
+		// TODO(gri) Should we pass x.typ instead of base (and indirect report if derefStructPtr indirected)?
+		check.recordSelection(selx, FieldVal, base, obj, index, false)
+
+		offs := check.conf.offsetof(base, index)
+		x.mode = constant_
+		x.val = constant.MakeInt64(offs)
+		x.typ = Typ[Uintptr]
+		// result is constant - no need to record signature
+
+	case _Sizeof:
+		// unsafe.Sizeof(x T) uintptr
+		if !check.assignment(x, nil) {
+			assert(x.mode == invalid)
+			return
+		}
+
+		x.mode = constant_
+		x.val = constant.MakeInt64(check.conf.sizeof(x.typ))
+		x.typ = Typ[Uintptr]
+		// result is constant - no need to record signature
+
+	case _Assert:
+		// assert(pred) causes a typechecker error if pred is false.
+		// The result of assert is the value of pred if there is no error.
+		// Note: assert is only available in self-test mode.
+		if x.mode != constant_ || !isBoolean(x.typ) {
+			check.invalidArg(x.pos(), "%s is not a boolean constant", x)
+			return
+		}
+		if x.val.Kind() != constant.Bool {
+			check.errorf(x.pos(), "internal error: value of %s should be a boolean constant", x)
+			return
+		}
+		if !constant.BoolVal(x.val) {
+			check.errorf(call.Pos(), "%s failed", call)
+			// compile-time assertion failure - safe to continue
+		}
+		// result is constant - no need to record signature
+
+	case _Trace:
+		// trace(x, y, z, ...) dumps the positions, expressions, and
+		// values of its arguments. The result of trace is the value
+		// of the first argument.
+		// Note: trace is only available in self-test mode.
+		// (no argument evaluated yet)
+		if nargs == 0 {
+			check.dump("%s: trace() without arguments", call.Pos())
+			x.mode = novalue
+			break
+		}
+		var t operand
+		x1 := x
+		for _, arg := range call.Args {
+			check.rawExpr(x1, arg, nil) // permit trace for types, e.g.: new(trace(T))
+			check.dump("%s: %s", x1.pos(), x1)
+			x1 = &t // use incoming x only for first argument
+		}
+		// trace is only available in test mode - no need to record signature
+
+	default:
+		unreachable()
+	}
+
+	return true
+}
+
+// makeSig makes a signature for the given argument and result types.
+// Default types are used for untyped arguments, and res may be nil.
+func makeSig(res Type, args ...Type) *Signature {
+	list := make([]*Var, len(args))
+	for i, param := range args {
+		list[i] = NewVar(token.NoPos, nil, "", defaultType(param))
+	}
+	params := NewTuple(list...)
+	var result *Tuple
+	if res != nil {
+		assert(!isUntyped(res))
+		result = NewTuple(NewVar(token.NoPos, nil, "", res))
+	}
+	return &Signature{params: params, results: result}
+}
+
+// implicitArrayDeref returns A if typ is of the form *A and A is an array;
+// otherwise it returns typ.
+//
+func implicitArrayDeref(typ Type) Type {
+	if p, ok := typ.(*Pointer); ok {
+		if a, ok := p.base.Underlying().(*Array); ok {
+			return a
+		}
+	}
+	return typ
+}
+
+// unparen returns e with any enclosing parentheses stripped.
+func unparen(e ast.Expr) ast.Expr {
+	for {
+		p, ok := e.(*ast.ParenExpr)
+		if !ok {
+			return e
+		}
+		e = p.X
+	}
+}
+
+func (check *Checker) complexArg(x *operand) bool {
+	t, _ := x.typ.Underlying().(*Basic)
+	if t != nil && (t.info&IsFloat != 0 || t.kind == UntypedInt || t.kind == UntypedRune) {
+		return true
+	}
+	check.invalidArg(x.pos(), "%s must be a float32, float64, or an untyped non-complex numeric constant", x)
+	return false
+}
diff --git a/src/go/types/builtins_test.go b/src/go/types/builtins_test.go
new file mode 100644
index 0000000..9835a48
--- /dev/null
+++ b/src/go/types/builtins_test.go
@@ -0,0 +1,204 @@
+// 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 types_test
+
+import (
+	"fmt"
+	"go/ast"
+	"go/importer"
+	"go/parser"
+	"testing"
+
+	. "go/types"
+)
+
+var builtinCalls = []struct {
+	name, src, sig string
+}{
+	{"append", `var s []int; _ = append(s)`, `func([]int, ...int) []int`},
+	{"append", `var s []int; _ = append(s, 0)`, `func([]int, ...int) []int`},
+	{"append", `var s []int; _ = (append)(s, 0)`, `func([]int, ...int) []int`},
+	{"append", `var s []byte; _ = ((append))(s, 0)`, `func([]byte, ...byte) []byte`},
+	{"append", `var s []byte; _ = append(s, "foo"...)`, `func([]byte, string...) []byte`},
+	{"append", `type T []byte; var s T; var str string; _ = append(s, str...)`, `func(p.T, string...) p.T`},
+	{"append", `type T []byte; type U string; var s T; var str U; _ = append(s, str...)`, `func(p.T, p.U...) p.T`},
+
+	{"cap", `var s [10]int; _ = cap(s)`, `invalid type`},  // constant
+	{"cap", `var s [10]int; _ = cap(&s)`, `invalid type`}, // constant
+	{"cap", `var s []int64; _ = cap(s)`, `func([]int64) int`},
+	{"cap", `var c chan<-bool; _ = cap(c)`, `func(chan<- bool) int`},
+
+	{"len", `_ = len("foo")`, `invalid type`}, // constant
+	{"len", `var s string; _ = len(s)`, `func(string) int`},
+	{"len", `var s [10]int; _ = len(s)`, `invalid type`},  // constant
+	{"len", `var s [10]int; _ = len(&s)`, `invalid type`}, // constant
+	{"len", `var s []int64; _ = len(s)`, `func([]int64) int`},
+	{"len", `var c chan<-bool; _ = len(c)`, `func(chan<- bool) int`},
+	{"len", `var m map[string]float32; _ = len(m)`, `func(map[string]float32) int`},
+
+	{"close", `var c chan int; close(c)`, `func(chan int)`},
+	{"close", `var c chan<- chan string; close(c)`, `func(chan<- chan string)`},
+
+	{"complex", `_ = complex(1, 0)`, `invalid type`}, // constant
+	{"complex", `var re float32; _ = complex(re, 1.0)`, `func(float32, float32) complex64`},
+	{"complex", `var im float64; _ = complex(1, im)`, `func(float64, float64) complex128`},
+	{"complex", `type F32 float32; var re, im F32; _ = complex(re, im)`, `func(p.F32, p.F32) complex64`},
+	{"complex", `type F64 float64; var re, im F64; _ = complex(re, im)`, `func(p.F64, p.F64) complex128`},
+
+	{"copy", `var src, dst []byte; copy(dst, src)`, `func([]byte, []byte) int`},
+	{"copy", `type T [][]int; var src, dst T; _ = copy(dst, src)`, `func(p.T, p.T) int`},
+	{"copy", `var src string; var dst []byte; copy(dst, src)`, `func([]byte, string) int`},
+	{"copy", `type T string; type U []byte; var src T; var dst U; copy(dst, src)`, `func(p.U, p.T) int`},
+	{"copy", `var dst []byte; copy(dst, "hello")`, `func([]byte, string) int`},
+
+	{"delete", `var m map[string]bool; delete(m, "foo")`, `func(map[string]bool, string)`},
+	{"delete", `type (K string; V int); var m map[K]V; delete(m, "foo")`, `func(map[p.K]p.V, p.K)`},
+
+	{"imag", `_ = imag(1i)`, `invalid type`}, // constant
+	{"imag", `var c complex64; _ = imag(c)`, `func(complex64) float32`},
+	{"imag", `var c complex128; _ = imag(c)`, `func(complex128) float64`},
+	{"imag", `type C64 complex64; var c C64; _ = imag(c)`, `func(p.C64) float32`},
+	{"imag", `type C128 complex128; var c C128; _ = imag(c)`, `func(p.C128) float64`},
+
+	{"real", `_ = real(1i)`, `invalid type`}, // constant
+	{"real", `var c complex64; _ = real(c)`, `func(complex64) float32`},
+	{"real", `var c complex128; _ = real(c)`, `func(complex128) float64`},
+	{"real", `type C64 complex64; var c C64; _ = real(c)`, `func(p.C64) float32`},
+	{"real", `type C128 complex128; var c C128; _ = real(c)`, `func(p.C128) float64`},
+
+	{"make", `_ = make([]int, 10)`, `func([]int, int) []int`},
+	{"make", `type T []byte; _ = make(T, 10, 20)`, `func(p.T, int, int) p.T`},
+
+	{"new", `_ = new(int)`, `func(int) *int`},
+	{"new", `type T struct{}; _ = new(T)`, `func(p.T) *p.T`},
+
+	{"panic", `panic(0)`, `func(interface{})`},
+	{"panic", `panic("foo")`, `func(interface{})`},
+
+	{"print", `print()`, `func()`},
+	{"print", `print(0)`, `func(int)`},
+	{"print", `print(1, 2.0, "foo", true)`, `func(int, float64, string, bool)`},
+
+	{"println", `println()`, `func()`},
+	{"println", `println(0)`, `func(int)`},
+	{"println", `println(1, 2.0, "foo", true)`, `func(int, float64, string, bool)`},
+
+	{"recover", `recover()`, `func() interface{}`},
+	{"recover", `_ = recover()`, `func() interface{}`},
+
+	{"Alignof", `_ = unsafe.Alignof(0)`, `invalid type`},                 // constant
+	{"Alignof", `var x struct{}; _ = unsafe.Alignof(x)`, `invalid type`}, // constant
+
+	{"Offsetof", `var x struct{f bool}; _ = unsafe.Offsetof(x.f)`, `invalid type`},           // constant
+	{"Offsetof", `var x struct{_ int; f bool}; _ = unsafe.Offsetof((&x).f)`, `invalid type`}, // constant
+
+	{"Sizeof", `_ = unsafe.Sizeof(0)`, `invalid type`},                 // constant
+	{"Sizeof", `var x struct{}; _ = unsafe.Sizeof(x)`, `invalid type`}, // constant
+
+	{"assert", `assert(true)`, `invalid type`},                                    // constant
+	{"assert", `type B bool; const pred B = 1 < 2; assert(pred)`, `invalid type`}, // constant
+
+	// no tests for trace since it produces output as a side-effect
+}
+
+func TestBuiltinSignatures(t *testing.T) {
+	DefPredeclaredTestFuncs()
+
+	seen := map[string]bool{"trace": true} // no test for trace built-in; add it manually
+	for _, call := range builtinCalls {
+		testBuiltinSignature(t, call.name, call.src, call.sig)
+		seen[call.name] = true
+	}
+
+	// make sure we didn't miss one
+	for _, name := range Universe.Names() {
+		if _, ok := Universe.Lookup(name).(*Builtin); ok && !seen[name] {
+			t.Errorf("missing test for %s", name)
+		}
+	}
+	for _, name := range Unsafe.Scope().Names() {
+		if _, ok := Unsafe.Scope().Lookup(name).(*Builtin); ok && !seen[name] {
+			t.Errorf("missing test for unsafe.%s", name)
+		}
+	}
+}
+
+func testBuiltinSignature(t *testing.T, name, src0, want string) {
+	src := fmt.Sprintf(`package p; import "unsafe"; type _ unsafe.Pointer /* use unsafe */; func _() { %s }`, src0)
+	f, err := parser.ParseFile(fset, "", src, 0)
+	if err != nil {
+		t.Errorf("%s: %s", src0, err)
+		return
+	}
+
+	conf := Config{Importer: importer.Default()}
+	uses := make(map[*ast.Ident]Object)
+	types := make(map[ast.Expr]TypeAndValue)
+	_, err = conf.Check(f.Name.Name, fset, []*ast.File{f}, &Info{Uses: uses, Types: types})
+	if err != nil {
+		t.Errorf("%s: %s", src0, err)
+		return
+	}
+
+	// find called function
+	n := 0
+	var fun ast.Expr
+	for x := range types {
+		if call, _ := x.(*ast.CallExpr); call != nil {
+			fun = call.Fun
+			n++
+		}
+	}
+	if n != 1 {
+		t.Errorf("%s: got %d CallExprs; want 1", src0, n)
+		return
+	}
+
+	// check recorded types for fun and descendents (may be parenthesized)
+	for {
+		// the recorded type for the built-in must match the wanted signature
+		typ := types[fun].Type
+		if typ == nil {
+			t.Errorf("%s: no type recorded for %s", src0, ExprString(fun))
+			return
+		}
+		if got := typ.String(); got != want {
+			t.Errorf("%s: got type %s; want %s", src0, got, want)
+			return
+		}
+
+		// called function must be a (possibly parenthesized, qualified)
+		// identifier denoting the expected built-in
+		switch p := fun.(type) {
+		case *ast.Ident:
+			obj := uses[p]
+			if obj == nil {
+				t.Errorf("%s: no object found for %s", src0, p)
+				return
+			}
+			bin, _ := obj.(*Builtin)
+			if bin == nil {
+				t.Errorf("%s: %s does not denote a built-in", src0, p)
+				return
+			}
+			if bin.Name() != name {
+				t.Errorf("%s: got built-in %s; want %s", src0, bin.Name(), name)
+				return
+			}
+			return // we're done
+
+		case *ast.ParenExpr:
+			fun = p.X // unpack
+
+		case *ast.SelectorExpr:
+			// built-in from package unsafe - ignore details
+			return // we're done
+
+		default:
+			t.Errorf("%s: invalid function call", src0)
+			return
+		}
+	}
+}
diff --git a/src/go/types/call.go b/src/go/types/call.go
new file mode 100644
index 0000000..62cefc0
--- /dev/null
+++ b/src/go/types/call.go
@@ -0,0 +1,441 @@
+// 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.
+
+// This file implements typechecking of call and selector expressions.
+
+package types
+
+import (
+	"go/ast"
+	"go/token"
+)
+
+func (check *Checker) call(x *operand, e *ast.CallExpr) exprKind {
+	check.exprOrType(x, e.Fun)
+
+	switch x.mode {
+	case invalid:
+		check.use(e.Args...)
+		x.mode = invalid
+		x.expr = e
+		return statement
+
+	case typexpr:
+		// conversion
+		T := x.typ
+		x.mode = invalid
+		switch n := len(e.Args); n {
+		case 0:
+			check.errorf(e.Rparen, "missing argument in conversion to %s", T)
+		case 1:
+			check.expr(x, e.Args[0])
+			if x.mode != invalid {
+				check.conversion(x, T)
+			}
+		default:
+			check.errorf(e.Args[n-1].Pos(), "too many arguments in conversion to %s", T)
+		}
+		x.expr = e
+		return conversion
+
+	case builtin:
+		id := x.id
+		if !check.builtin(x, e, id) {
+			x.mode = invalid
+		}
+		x.expr = e
+		// a non-constant result implies a function call
+		if x.mode != invalid && x.mode != constant_ {
+			check.hasCallOrRecv = true
+		}
+		return predeclaredFuncs[id].kind
+
+	default:
+		// function/method call
+		sig, _ := x.typ.Underlying().(*Signature)
+		if sig == nil {
+			check.invalidOp(x.pos(), "cannot call non-function %s", x)
+			x.mode = invalid
+			x.expr = e
+			return statement
+		}
+
+		arg, n, _ := unpack(func(x *operand, i int) { check.expr(x, e.Args[i]) }, len(e.Args), false)
+		if arg == nil {
+			x.mode = invalid
+			x.expr = e
+			return statement
+		}
+
+		check.arguments(x, e, sig, arg, n)
+
+		// determine result
+		switch sig.results.Len() {
+		case 0:
+			x.mode = novalue
+		case 1:
+			x.mode = value
+			x.typ = sig.results.vars[0].typ // unpack tuple
+		default:
+			x.mode = value
+			x.typ = sig.results
+		}
+		x.expr = e
+		check.hasCallOrRecv = true
+
+		return statement
+	}
+}
+
+// use type-checks each argument.
+// Useful to make sure expressions are evaluated
+// (and variables are "used") in the presence of other errors.
+func (check *Checker) use(arg ...ast.Expr) {
+	var x operand
+	for _, e := range arg {
+		check.rawExpr(&x, e, nil)
+	}
+}
+
+// useGetter is like use, but takes a getter instead of a list of expressions.
+// It should be called instead of use if a getter is present to avoid repeated
+// evaluation of the first argument (since the getter was likely obtained via
+// unpack, which may have evaluated the first argument already).
+func (check *Checker) useGetter(get getter, n int) {
+	var x operand
+	for i := 0; i < n; i++ {
+		get(&x, i)
+	}
+}
+
+// A getter sets x as the i'th operand, where 0 <= i < n and n is the total
+// number of operands (context-specific, and maintained elsewhere). A getter
+// type-checks the i'th operand; the details of the actual check are getter-
+// specific.
+type getter func(x *operand, i int)
+
+// unpack takes a getter get and a number of operands n. If n == 1, unpack
+// calls the incoming getter for the first operand. If that operand is
+// invalid, unpack returns (nil, 0, false). Otherwise, if that operand is a
+// function call, or a comma-ok expression and allowCommaOk is set, the result
+// is a new getter and operand count providing access to the function results,
+// or comma-ok values, respectively. The third result value reports if it
+// is indeed the comma-ok case. In all other cases, the incoming getter and
+// operand count are returned unchanged, and the third result value is false.
+//
+// In other words, if there's exactly one operand that - after type-checking
+// by calling get - stands for multiple operands, the resulting getter provides
+// access to those operands instead.
+//
+// If the returned getter is called at most once for a given operand index i
+// (including i == 0), that operand is guaranteed to cause only one call of
+// the incoming getter with that i.
+//
+func unpack(get getter, n int, allowCommaOk bool) (getter, int, bool) {
+	if n == 1 {
+		// possibly result of an n-valued function call or comma,ok value
+		var x0 operand
+		get(&x0, 0)
+		if x0.mode == invalid {
+			return nil, 0, false
+		}
+
+		if t, ok := x0.typ.(*Tuple); ok {
+			// result of an n-valued function call
+			return func(x *operand, i int) {
+				x.mode = value
+				x.expr = x0.expr
+				x.typ = t.At(i).typ
+			}, t.Len(), false
+		}
+
+		if x0.mode == mapindex || x0.mode == commaok {
+			// comma-ok value
+			if allowCommaOk {
+				a := [2]Type{x0.typ, Typ[UntypedBool]}
+				return func(x *operand, i int) {
+					x.mode = value
+					x.expr = x0.expr
+					x.typ = a[i]
+				}, 2, true
+			}
+			x0.mode = value
+		}
+
+		// single value
+		return func(x *operand, i int) {
+			if i != 0 {
+				unreachable()
+			}
+			*x = x0
+		}, 1, false
+	}
+
+	// zero or multiple values
+	return get, n, false
+}
+
+// arguments checks argument passing for the call with the given signature.
+// The arg function provides the operand for the i'th argument.
+func (check *Checker) arguments(x *operand, call *ast.CallExpr, sig *Signature, arg getter, n int) {
+	if call.Ellipsis.IsValid() {
+		// last argument is of the form x...
+		if len(call.Args) == 1 && n > 1 {
+			// f()... is not permitted if f() is multi-valued
+			check.errorf(call.Ellipsis, "cannot use ... with %d-valued expression %s", n, call.Args[0])
+			check.useGetter(arg, n)
+			return
+		}
+		if !sig.variadic {
+			check.errorf(call.Ellipsis, "cannot use ... in call to non-variadic %s", call.Fun)
+			check.useGetter(arg, n)
+			return
+		}
+	}
+
+	// evaluate arguments
+	for i := 0; i < n; i++ {
+		arg(x, i)
+		if x.mode != invalid {
+			var ellipsis token.Pos
+			if i == n-1 && call.Ellipsis.IsValid() {
+				ellipsis = call.Ellipsis
+			}
+			check.argument(sig, i, x, ellipsis)
+		}
+	}
+
+	// check argument count
+	if sig.variadic {
+		// a variadic function accepts an "empty"
+		// last argument: count one extra
+		n++
+	}
+	if n < sig.params.Len() {
+		check.errorf(call.Rparen, "too few arguments in call to %s", call.Fun)
+		// ok to continue
+	}
+}
+
+// argument checks passing of argument x to the i'th parameter of the given signature.
+// If ellipsis is valid, the argument is followed by ... at that position in the call.
+func (check *Checker) argument(sig *Signature, i int, x *operand, ellipsis token.Pos) {
+	n := sig.params.Len()
+
+	// determine parameter type
+	var typ Type
+	switch {
+	case i < n:
+		typ = sig.params.vars[i].typ
+	case sig.variadic:
+		typ = sig.params.vars[n-1].typ
+		if debug {
+			if _, ok := typ.(*Slice); !ok {
+				check.dump("%s: expected unnamed slice type, got %s", sig.params.vars[n-1].Pos(), typ)
+			}
+		}
+	default:
+		check.errorf(x.pos(), "too many arguments")
+		return
+	}
+
+	if ellipsis.IsValid() {
+		// argument is of the form x...
+		if i != n-1 {
+			check.errorf(ellipsis, "can only use ... with matching parameter")
+			return
+		}
+		switch t := x.typ.Underlying().(type) {
+		case *Slice:
+			// ok
+		case *Tuple:
+			check.errorf(ellipsis, "cannot use ... with %d-valued expression %s", t.Len(), x)
+			return
+		default:
+			check.errorf(x.pos(), "cannot use %s as parameter of type %s", x, typ)
+			return
+		}
+	} else if sig.variadic && i >= n-1 {
+		// use the variadic parameter slice's element type
+		typ = typ.(*Slice).elem
+	}
+
+	if !check.assignment(x, typ) && x.mode != invalid {
+		check.errorf(x.pos(), "cannot pass argument %s to parameter of type %s", x, typ)
+	}
+}
+
+func (check *Checker) selector(x *operand, e *ast.SelectorExpr) {
+	// these must be declared before the "goto Error" statements
+	var (
+		obj      Object
+		index    []int
+		indirect bool
+	)
+
+	sel := e.Sel.Name
+	// If the identifier refers to a package, handle everything here
+	// so we don't need a "package" mode for operands: package names
+	// can only appear in qualified identifiers which are mapped to
+	// selector expressions.
+	if ident, ok := e.X.(*ast.Ident); ok {
+		_, obj := check.scope.LookupParent(ident.Name, check.pos)
+		if pkg, _ := obj.(*PkgName); pkg != nil {
+			assert(pkg.pkg == check.pkg)
+			check.recordUse(ident, pkg)
+			pkg.used = true
+			exp := pkg.imported.scope.Lookup(sel)
+			if exp == nil {
+				if !pkg.imported.fake {
+					check.errorf(e.Pos(), "%s not declared by package %s", sel, ident)
+				}
+				goto Error
+			}
+			if !exp.Exported() {
+				check.errorf(e.Pos(), "%s not exported by package %s", sel, ident)
+				// ok to continue
+			}
+			check.recordUse(e.Sel, exp)
+			// Simplified version of the code for *ast.Idents:
+			// - imported objects are always fully initialized
+			switch exp := exp.(type) {
+			case *Const:
+				assert(exp.Val() != nil)
+				x.mode = constant_
+				x.typ = exp.typ
+				x.val = exp.val
+			case *TypeName:
+				x.mode = typexpr
+				x.typ = exp.typ
+			case *Var:
+				x.mode = variable
+				x.typ = exp.typ
+			case *Func:
+				x.mode = value
+				x.typ = exp.typ
+			case *Builtin:
+				x.mode = builtin
+				x.typ = exp.typ
+				x.id = exp.id
+			default:
+				unreachable()
+			}
+			x.expr = e
+			return
+		}
+	}
+
+	check.exprOrType(x, e.X)
+	if x.mode == invalid {
+		goto Error
+	}
+
+	obj, index, indirect = LookupFieldOrMethod(x.typ, x.mode == variable, check.pkg, sel)
+	if obj == nil {
+		switch {
+		case index != nil:
+			// TODO(gri) should provide actual type where the conflict happens
+			check.invalidOp(e.Pos(), "ambiguous selector %s", sel)
+		case indirect:
+			check.invalidOp(e.Pos(), "%s is not in method set of %s", sel, x.typ)
+		default:
+			check.invalidOp(e.Pos(), "%s has no field or method %s", x, sel)
+		}
+		goto Error
+	}
+
+	if x.mode == typexpr {
+		// method expression
+		m, _ := obj.(*Func)
+		if m == nil {
+			check.invalidOp(e.Pos(), "%s has no method %s", x, sel)
+			goto Error
+		}
+
+		check.recordSelection(e, MethodExpr, x.typ, m, index, indirect)
+
+		// the receiver type becomes the type of the first function
+		// argument of the method expression's function type
+		var params []*Var
+		sig := m.typ.(*Signature)
+		if sig.params != nil {
+			params = sig.params.vars
+		}
+		x.mode = value
+		x.typ = &Signature{
+			params:   NewTuple(append([]*Var{NewVar(token.NoPos, check.pkg, "", x.typ)}, params...)...),
+			results:  sig.results,
+			variadic: sig.variadic,
+		}
+
+		check.addDeclDep(m)
+
+	} else {
+		// regular selector
+		switch obj := obj.(type) {
+		case *Var:
+			check.recordSelection(e, FieldVal, x.typ, obj, index, indirect)
+			if x.mode == variable || indirect {
+				x.mode = variable
+			} else {
+				x.mode = value
+			}
+			x.typ = obj.typ
+
+		case *Func:
+			// TODO(gri) If we needed to take into account the receiver's
+			// addressability, should we report the type &(x.typ) instead?
+			check.recordSelection(e, MethodVal, x.typ, obj, index, indirect)
+
+			if debug {
+				// Verify that LookupFieldOrMethod and MethodSet.Lookup agree.
+				typ := x.typ
+				if x.mode == variable {
+					// If typ is not an (unnamed) pointer or an interface,
+					// use *typ instead, because the method set of *typ
+					// includes the methods of typ.
+					// Variables are addressable, so we can always take their
+					// address.
+					if _, ok := typ.(*Pointer); !ok && !IsInterface(typ) {
+						typ = &Pointer{base: typ}
+					}
+				}
+				// If we created a synthetic pointer type above, we will throw
+				// away the method set computed here after use.
+				// TODO(gri) Method set computation should probably always compute
+				// both, the value and the pointer receiver method set and represent
+				// them in a single structure.
+				// TODO(gri) Consider also using a method set cache for the lifetime
+				// of checker once we rely on MethodSet lookup instead of individual
+				// lookup.
+				mset := NewMethodSet(typ)
+				if m := mset.Lookup(check.pkg, sel); m == nil || m.obj != obj {
+					check.dump("%s: (%s).%v -> %s", e.Pos(), typ, obj.name, m)
+					check.dump("%s\n", mset)
+					panic("method sets and lookup don't agree")
+				}
+			}
+
+			x.mode = value
+
+			// remove receiver
+			sig := *obj.typ.(*Signature)
+			sig.recv = nil
+			x.typ = &sig
+
+			check.addDeclDep(obj)
+
+		default:
+			unreachable()
+		}
+	}
+
+	// everything went well
+	x.expr = e
+	return
+
+Error:
+	x.mode = invalid
+	x.expr = e
+}
diff --git a/src/go/types/check.go b/src/go/types/check.go
new file mode 100644
index 0000000..bb0b074
--- /dev/null
+++ b/src/go/types/check.go
@@ -0,0 +1,358 @@
+// 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.
+
+// This file implements the Check function, which drives type-checking.
+
+package types
+
+import (
+	"go/ast"
+	"go/constant"
+	"go/token"
+)
+
+// debugging/development support
+const (
+	debug = false // leave on during development
+	trace = false // turn on for detailed type resolution traces
+)
+
+// If Strict is set, the type-checker enforces additional
+// rules not specified by the Go 1 spec, but which will
+// catch guaranteed run-time errors if the respective
+// code is executed. In other words, programs passing in
+// Strict mode are Go 1 compliant, but not all Go 1 programs
+// will pass in Strict mode. The additional rules are:
+//
+// - A type assertion x.(T) where T is an interface type
+//   is invalid if any (statically known) method that exists
+//   for both x and T have different signatures.
+//
+const strict = false
+
+// exprInfo stores information about an untyped expression.
+type exprInfo struct {
+	isLhs bool // expression is lhs operand of a shift with delayed type-check
+	mode  operandMode
+	typ   *Basic
+	val   constant.Value // constant value; or nil (if not a constant)
+}
+
+// funcInfo stores the information required for type-checking a function.
+type funcInfo struct {
+	name string    // for debugging/tracing only
+	decl *declInfo // for cycle detection
+	sig  *Signature
+	body *ast.BlockStmt
+}
+
+// A context represents the context within which an object is type-checked.
+type context struct {
+	decl          *declInfo      // package-level declaration whose init expression/function body is checked
+	scope         *Scope         // top-most scope for lookups
+	iota          constant.Value // value of iota in a constant declaration; nil otherwise
+	sig           *Signature     // function signature if inside a function; nil otherwise
+	hasLabel      bool           // set if a function makes use of labels (only ~1% of functions); unused outside functions
+	hasCallOrRecv bool           // set if an expression contains a function call or channel receive operation
+}
+
+// A Checker maintains the state of the type checker.
+// It must be created with NewChecker.
+type Checker struct {
+	// package information
+	// (initialized by NewChecker, valid for the life-time of checker)
+	conf *Config
+	fset *token.FileSet
+	pkg  *Package
+	*Info
+	objMap map[Object]*declInfo // maps package-level object to declaration info
+
+	// information collected during type-checking of a set of package files
+	// (initialized by Files, valid only for the duration of check.Files;
+	// maps and lists are allocated on demand)
+	files            []*ast.File                       // package files
+	unusedDotImports map[*Scope]map[*Package]token.Pos // positions of unused dot-imported packages for each file scope
+
+	firstErr error                 // first error encountered
+	methods  map[string][]*Func    // maps type names to associated methods
+	untyped  map[ast.Expr]exprInfo // map of expressions without final type
+	funcs    []funcInfo            // list of functions to type-check
+	delayed  []func()              // delayed checks requiring fully setup types
+
+	// context within which the current object is type-checked
+	// (valid only for the duration of type-checking a specific object)
+	context
+	pos token.Pos // if valid, identifiers are looked up as if at position pos (used by Eval)
+
+	// debugging
+	indent int // indentation for tracing
+}
+
+// addUnusedImport adds the position of a dot-imported package
+// pkg to the map of dot imports for the given file scope.
+func (check *Checker) addUnusedDotImport(scope *Scope, pkg *Package, pos token.Pos) {
+	mm := check.unusedDotImports
+	if mm == nil {
+		mm = make(map[*Scope]map[*Package]token.Pos)
+		check.unusedDotImports = mm
+	}
+	m := mm[scope]
+	if m == nil {
+		m = make(map[*Package]token.Pos)
+		mm[scope] = m
+	}
+	m[pkg] = pos
+}
+
+// addDeclDep adds the dependency edge (check.decl -> to) if check.decl exists
+func (check *Checker) addDeclDep(to Object) {
+	from := check.decl
+	if from == nil {
+		return // not in a package-level init expression
+	}
+	if _, found := check.objMap[to]; !found {
+		return // to is not a package-level object
+	}
+	from.addDep(to)
+}
+
+func (check *Checker) assocMethod(tname string, meth *Func) {
+	m := check.methods
+	if m == nil {
+		m = make(map[string][]*Func)
+		check.methods = m
+	}
+	m[tname] = append(m[tname], meth)
+}
+
+func (check *Checker) rememberUntyped(e ast.Expr, lhs bool, mode operandMode, typ *Basic, val constant.Value) {
+	m := check.untyped
+	if m == nil {
+		m = make(map[ast.Expr]exprInfo)
+		check.untyped = m
+	}
+	m[e] = exprInfo{lhs, mode, typ, val}
+}
+
+func (check *Checker) later(name string, decl *declInfo, sig *Signature, body *ast.BlockStmt) {
+	check.funcs = append(check.funcs, funcInfo{name, decl, sig, body})
+}
+
+func (check *Checker) delay(f func()) {
+	check.delayed = append(check.delayed, f)
+}
+
+// NewChecker returns a new Checker instance for a given package.
+// Package files may be added incrementally via checker.Files.
+func NewChecker(conf *Config, fset *token.FileSet, pkg *Package, info *Info) *Checker {
+	// make sure we have a configuration
+	if conf == nil {
+		conf = new(Config)
+	}
+
+	// make sure we have an info struct
+	if info == nil {
+		info = new(Info)
+	}
+
+	return &Checker{
+		conf:   conf,
+		fset:   fset,
+		pkg:    pkg,
+		Info:   info,
+		objMap: make(map[Object]*declInfo),
+	}
+}
+
+// initFiles initializes the files-specific portion of checker.
+// The provided files must all belong to the same package.
+func (check *Checker) initFiles(files []*ast.File) {
+	// start with a clean slate (check.Files may be called multiple times)
+	check.files = nil
+	check.unusedDotImports = nil
+
+	check.firstErr = nil
+	check.methods = nil
+	check.untyped = nil
+	check.funcs = nil
+	check.delayed = nil
+
+	// determine package name and collect valid files
+	pkg := check.pkg
+	for _, file := range files {
+		switch name := file.Name.Name; pkg.name {
+		case "":
+			if name != "_" {
+				pkg.name = name
+			} else {
+				check.errorf(file.Name.Pos(), "invalid package name _")
+			}
+			fallthrough
+
+		case name:
+			check.files = append(check.files, file)
+
+		default:
+			check.errorf(file.Package, "package %s; expected %s", name, pkg.name)
+			// ignore this file
+		}
+	}
+}
+
+// A bailout panic is used for early termination.
+type bailout struct{}
+
+func (check *Checker) handleBailout(err *error) {
+	switch p := recover().(type) {
+	case nil, bailout:
+		// normal return or early exit
+		*err = check.firstErr
+	default:
+		// re-panic
+		panic(p)
+	}
+}
+
+// Files checks the provided files as part of the checker's package.
+func (check *Checker) Files(files []*ast.File) (err error) {
+	defer check.handleBailout(&err)
+
+	check.initFiles(files)
+
+	check.collectObjects()
+
+	check.packageObjects(check.resolveOrder())
+
+	check.functionBodies()
+
+	check.initOrder()
+
+	if !check.conf.DisableUnusedImportCheck {
+		check.unusedImports()
+	}
+
+	// perform delayed checks
+	for _, f := range check.delayed {
+		f()
+	}
+
+	check.recordUntyped()
+
+	check.pkg.complete = true
+	return
+}
+
+func (check *Checker) recordUntyped() {
+	if !debug && check.Types == nil {
+		return // nothing to do
+	}
+
+	for x, info := range check.untyped {
+		if debug && isTyped(info.typ) {
+			check.dump("%s: %s (type %s) is typed", x.Pos(), x, info.typ)
+			unreachable()
+		}
+		check.recordTypeAndValue(x, info.mode, info.typ, info.val)
+	}
+}
+
+func (check *Checker) recordTypeAndValue(x ast.Expr, mode operandMode, typ Type, val constant.Value) {
+	assert(x != nil)
+	assert(typ != nil)
+	if mode == invalid {
+		return // omit
+	}
+	assert(typ != nil)
+	if mode == constant_ {
+		assert(val != nil)
+		assert(typ == Typ[Invalid] || isConstType(typ))
+	}
+	if m := check.Types; m != nil {
+		m[x] = TypeAndValue{mode, typ, val}
+	}
+}
+
+func (check *Checker) recordBuiltinType(f ast.Expr, sig *Signature) {
+	// f must be a (possibly parenthesized) identifier denoting a built-in
+	// (built-ins in package unsafe always produce a constant result and
+	// we don't record their signatures, so we don't see qualified idents
+	// here): record the signature for f and possible children.
+	for {
+		check.recordTypeAndValue(f, builtin, sig, nil)
+		switch p := f.(type) {
+		case *ast.Ident:
+			return // we're done
+		case *ast.ParenExpr:
+			f = p.X
+		default:
+			unreachable()
+		}
+	}
+}
+
+func (check *Checker) recordCommaOkTypes(x ast.Expr, a [2]Type) {
+	assert(x != nil)
+	if a[0] == nil || a[1] == nil {
+		return
+	}
+	assert(isTyped(a[0]) && isTyped(a[1]) && isBoolean(a[1]))
+	if m := check.Types; m != nil {
+		for {
+			tv := m[x]
+			assert(tv.Type != nil) // should have been recorded already
+			pos := x.Pos()
+			tv.Type = NewTuple(
+				NewVar(pos, check.pkg, "", a[0]),
+				NewVar(pos, check.pkg, "", a[1]),
+			)
+			m[x] = tv
+			// if x is a parenthesized expression (p.X), update p.X
+			p, _ := x.(*ast.ParenExpr)
+			if p == nil {
+				break
+			}
+			x = p.X
+		}
+	}
+}
+
+func (check *Checker) recordDef(id *ast.Ident, obj Object) {
+	assert(id != nil)
+	if m := check.Defs; m != nil {
+		m[id] = obj
+	}
+}
+
+func (check *Checker) recordUse(id *ast.Ident, obj Object) {
+	assert(id != nil)
+	assert(obj != nil)
+	if m := check.Uses; m != nil {
+		m[id] = obj
+	}
+}
+
+func (check *Checker) recordImplicit(node ast.Node, obj Object) {
+	assert(node != nil)
+	assert(obj != nil)
+	if m := check.Implicits; m != nil {
+		m[node] = obj
+	}
+}
+
+func (check *Checker) recordSelection(x *ast.SelectorExpr, kind SelectionKind, recv Type, obj Object, index []int, indirect bool) {
+	assert(obj != nil && (recv == nil || len(index) > 0))
+	check.recordUse(x.Sel, obj)
+	// TODO(gri) Should we also call recordTypeAndValue?
+	if m := check.Selections; m != nil {
+		m[x] = &Selection{kind, recv, obj, index, indirect}
+	}
+}
+
+func (check *Checker) recordScope(node ast.Node, scope *Scope) {
+	assert(node != nil)
+	assert(scope != nil)
+	if m := check.Scopes; m != nil {
+		m[node] = scope
+	}
+}
diff --git a/src/go/types/check_test.go b/src/go/types/check_test.go
new file mode 100644
index 0000000..5e34c65
--- /dev/null
+++ b/src/go/types/check_test.go
@@ -0,0 +1,298 @@
+// 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.
+
+// This file implements a typechecker test harness. The packages specified
+// in tests are typechecked. Error messages reported by the typechecker are
+// compared against the error messages expected in the test files.
+//
+// Expected errors are indicated in the test files by putting a comment
+// of the form /* ERROR "rx" */ immediately following an offending token.
+// The harness will verify that an error matching the regular expression
+// rx is reported at that source position. Consecutive comments may be
+// used to indicate multiple errors for the same token position.
+//
+// For instance, the following test file indicates that a "not declared"
+// error should be reported for the undeclared variable x:
+//
+//	package p
+//	func f() {
+//		_ = x /* ERROR "not declared" */ + 1
+//	}
+
+// TODO(gri) Also collect strict mode errors of the form /* STRICT ... */
+//           and test against strict mode.
+
+package types_test
+
+import (
+	"flag"
+	"go/ast"
+	"go/importer"
+	"go/parser"
+	"go/scanner"
+	"go/token"
+	"internal/testenv"
+	"io/ioutil"
+	"regexp"
+	"strings"
+	"testing"
+
+	. "go/types"
+)
+
+var (
+	listErrors = flag.Bool("list", false, "list errors")
+	testFiles  = flag.String("files", "", "space-separated list of test files")
+)
+
+// The test filenames do not end in .go so that they are invisible
+// to gofmt since they contain comments that must not change their
+// positions relative to surrounding tokens.
+
+// Each tests entry is list of files belonging to the same package.
+var tests = [][]string{
+	{"testdata/errors.src"},
+	{"testdata/importdecl0a.src", "testdata/importdecl0b.src"},
+	{"testdata/importdecl1a.src", "testdata/importdecl1b.src"},
+	{"testdata/cycles.src"},
+	{"testdata/cycles1.src"},
+	{"testdata/cycles2.src"},
+	{"testdata/cycles3.src"},
+	{"testdata/cycles4.src"},
+	{"testdata/init0.src"},
+	{"testdata/init1.src"},
+	{"testdata/init2.src"},
+	{"testdata/decls0.src"},
+	{"testdata/decls1.src"},
+	{"testdata/decls2a.src", "testdata/decls2b.src"},
+	{"testdata/decls3.src"},
+	{"testdata/const0.src"},
+	{"testdata/const1.src"},
+	{"testdata/constdecl.src"},
+	{"testdata/vardecl.src"},
+	{"testdata/expr0.src"},
+	{"testdata/expr1.src"},
+	{"testdata/expr2.src"},
+	{"testdata/expr3.src"},
+	{"testdata/methodsets.src"},
+	{"testdata/shifts.src"},
+	{"testdata/builtins.src"},
+	{"testdata/conversions.src"},
+	{"testdata/stmt0.src"},
+	{"testdata/stmt1.src"},
+	{"testdata/gotos.src"},
+	{"testdata/labels.src"},
+	{"testdata/issues.src"},
+	{"testdata/blank.src"},
+}
+
+var fset = token.NewFileSet()
+
+// Positioned errors are of the form filename:line:column: message .
+var posMsgRx = regexp.MustCompile(`^(.*:[0-9]+:[0-9]+): *(.*)`)
+
+// splitError splits an error's error message into a position string
+// and the actual error message. If there's no position information,
+// pos is the empty string, and msg is the entire error message.
+//
+func splitError(err error) (pos, msg string) {
+	msg = err.Error()
+	if m := posMsgRx.FindStringSubmatch(msg); len(m) == 3 {
+		pos = m[1]
+		msg = m[2]
+	}
+	return
+}
+
+func parseFiles(t *testing.T, filenames []string) ([]*ast.File, []error) {
+	var files []*ast.File
+	var errlist []error
+	for _, filename := range filenames {
+		file, err := parser.ParseFile(fset, filename, nil, parser.AllErrors)
+		if file == nil {
+			t.Fatalf("%s: %s", filename, err)
+		}
+		files = append(files, file)
+		if err != nil {
+			if list, _ := err.(scanner.ErrorList); len(list) > 0 {
+				for _, err := range list {
+					errlist = append(errlist, err)
+				}
+			} else {
+				errlist = append(errlist, err)
+			}
+		}
+	}
+	return files, errlist
+}
+
+// ERROR comments must start with text `ERROR "rx"` or `ERROR rx` where
+// rx is a regular expression that matches the expected error message.
+// Space around "rx" or rx is ignored. Use the form `ERROR HERE "rx"`
+// for error messages that are located immediately after rather than
+// at a token's position.
+//
+var errRx = regexp.MustCompile(`^ *ERROR *(HERE)? *"?([^"]*)"?`)
+
+// errMap collects the regular expressions of ERROR comments found
+// in files and returns them as a map of error positions to error messages.
+//
+func errMap(t *testing.T, testname string, files []*ast.File) map[string][]string {
+	// map of position strings to lists of error message patterns
+	errmap := make(map[string][]string)
+
+	for _, file := range files {
+		filename := fset.Position(file.Package).Filename
+		src, err := ioutil.ReadFile(filename)
+		if err != nil {
+			t.Fatalf("%s: could not read %s", testname, filename)
+		}
+
+		var s scanner.Scanner
+		s.Init(fset.AddFile(filename, -1, len(src)), src, nil, scanner.ScanComments)
+		var prev token.Pos // position of last non-comment, non-semicolon token
+		var here token.Pos // position immediately after the token at position prev
+
+	scanFile:
+		for {
+			pos, tok, lit := s.Scan()
+			switch tok {
+			case token.EOF:
+				break scanFile
+			case token.COMMENT:
+				if lit[1] == '*' {
+					lit = lit[:len(lit)-2] // strip trailing */
+				}
+				if s := errRx.FindStringSubmatch(lit[2:]); len(s) == 3 {
+					pos := prev
+					if s[1] == "HERE" {
+						pos = here
+					}
+					p := fset.Position(pos).String()
+					errmap[p] = append(errmap[p], strings.TrimSpace(s[2]))
+				}
+			case token.SEMICOLON:
+				// ignore automatically inserted semicolon
+				if lit == "\n" {
+					continue scanFile
+				}
+				fallthrough
+			default:
+				prev = pos
+				var l int // token length
+				if tok.IsLiteral() {
+					l = len(lit)
+				} else {
+					l = len(tok.String())
+				}
+				here = prev + token.Pos(l)
+			}
+		}
+	}
+
+	return errmap
+}
+
+func eliminate(t *testing.T, errmap map[string][]string, errlist []error) {
+	for _, err := range errlist {
+		pos, gotMsg := splitError(err)
+		list := errmap[pos]
+		index := -1 // list index of matching message, if any
+		// we expect one of the messages in list to match the error at pos
+		for i, wantRx := range list {
+			rx, err := regexp.Compile(wantRx)
+			if err != nil {
+				t.Errorf("%s: %v", pos, err)
+				continue
+			}
+			if rx.MatchString(gotMsg) {
+				index = i
+				break
+			}
+		}
+		if index >= 0 {
+			// eliminate from list
+			if n := len(list) - 1; n > 0 {
+				// not the last entry - swap in last element and shorten list by 1
+				list[index] = list[n]
+				errmap[pos] = list[:n]
+			} else {
+				// last entry - remove list from map
+				delete(errmap, pos)
+			}
+		} else {
+			t.Errorf("%s: no error expected: %q", pos, gotMsg)
+		}
+	}
+}
+
+func checkFiles(t *testing.T, testfiles []string) {
+	// parse files and collect parser errors
+	files, errlist := parseFiles(t, testfiles)
+
+	pkgName := "<no package>"
+	if len(files) > 0 {
+		pkgName = files[0].Name.Name
+	}
+
+	if *listErrors && len(errlist) > 0 {
+		t.Errorf("--- %s:", pkgName)
+		for _, err := range errlist {
+			t.Error(err)
+		}
+	}
+
+	// typecheck and collect typechecker errors
+	var conf Config
+	conf.Importer = importer.Default()
+	conf.Error = func(err error) {
+		if *listErrors {
+			t.Error(err)
+			return
+		}
+		// Ignore secondary error messages starting with "\t";
+		// they are clarifying messages for a primary error.
+		if !strings.Contains(err.Error(), ": \t") {
+			errlist = append(errlist, err)
+		}
+	}
+	conf.Check(pkgName, fset, files, nil)
+
+	if *listErrors {
+		return
+	}
+
+	// match and eliminate errors;
+	// we are expecting the following errors
+	errmap := errMap(t, pkgName, files)
+	eliminate(t, errmap, errlist)
+
+	// there should be no expected errors left
+	if len(errmap) > 0 {
+		t.Errorf("--- %s: %d source positions with expected (but not reported) errors:", pkgName, len(errmap))
+		for pos, list := range errmap {
+			for _, rx := range list {
+				t.Errorf("%s: %q", pos, rx)
+			}
+		}
+	}
+}
+
+func TestCheck(t *testing.T) {
+	testenv.MustHaveGoBuild(t)
+
+	// Declare builtins for testing.
+	DefPredeclaredTestFuncs()
+
+	// If explicit test files are specified, only check those.
+	if files := *testFiles; files != "" {
+		checkFiles(t, strings.Split(files, " "))
+		return
+	}
+
+	// Otherwise, run all the tests.
+	for _, files := range tests {
+		checkFiles(t, files)
+	}
+}
diff --git a/src/go/types/conversions.go b/src/go/types/conversions.go
new file mode 100644
index 0000000..74826ce
--- /dev/null
+++ b/src/go/types/conversions.go
@@ -0,0 +1,146 @@
+// 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.
+
+// This file implements typechecking of conversions.
+
+package types
+
+import "go/constant"
+
+// Conversion type-checks the conversion T(x).
+// The result is in x.
+func (check *Checker) conversion(x *operand, T Type) {
+	constArg := x.mode == constant_
+
+	var ok bool
+	switch {
+	case constArg && isConstType(T):
+		// constant conversion
+		switch t := T.Underlying().(*Basic); {
+		case representableConst(x.val, check.conf, t.kind, &x.val):
+			ok = true
+		case isInteger(x.typ) && isString(t):
+			codepoint := int64(-1)
+			if i, ok := constant.Int64Val(x.val); ok {
+				codepoint = i
+			}
+			// If codepoint < 0 the absolute value is too large (or unknown) for
+			// conversion. This is the same as converting any other out-of-range
+			// value - let string(codepoint) do the work.
+			x.val = constant.MakeString(string(codepoint))
+			ok = true
+		}
+	case x.convertibleTo(check.conf, T):
+		// non-constant conversion
+		x.mode = value
+		ok = true
+	}
+
+	if !ok {
+		check.errorf(x.pos(), "cannot convert %s to %s", x, T)
+		x.mode = invalid
+		return
+	}
+
+	// The conversion argument types are final. For untyped values the
+	// conversion provides the type, per the spec: "A constant may be
+	// given a type explicitly by a constant declaration or conversion,...".
+	final := x.typ
+	if isUntyped(x.typ) {
+		final = T
+		// - For conversions to interfaces, use the argument's default type.
+		// - For conversions of untyped constants to non-constant types, also
+		//   use the default type (e.g., []byte("foo") should report string
+		//   not []byte as type for the constant "foo").
+		// - Keep untyped nil for untyped nil arguments.
+		if IsInterface(T) || constArg && !isConstType(T) {
+			final = defaultType(x.typ)
+		}
+		check.updateExprType(x.expr, final, true)
+	}
+
+	x.typ = T
+}
+
+func (x *operand) convertibleTo(conf *Config, T Type) bool {
+	// "x is assignable to T"
+	if x.assignableTo(conf, T) {
+		return true
+	}
+
+	// "x's type and T have identical underlying types"
+	V := x.typ
+	Vu := V.Underlying()
+	Tu := T.Underlying()
+	if Identical(Vu, Tu) {
+		return true
+	}
+
+	// "x's type and T are unnamed pointer types and their pointer base types have identical underlying types"
+	if V, ok := V.(*Pointer); ok {
+		if T, ok := T.(*Pointer); ok {
+			if Identical(V.base.Underlying(), T.base.Underlying()) {
+				return true
+			}
+		}
+	}
+
+	// "x's type and T are both integer or floating point types"
+	if (isInteger(V) || isFloat(V)) && (isInteger(T) || isFloat(T)) {
+		return true
+	}
+
+	// "x's type and T are both complex types"
+	if isComplex(V) && isComplex(T) {
+		return true
+	}
+
+	// "x is an integer or a slice of bytes or runes and T is a string type"
+	if (isInteger(V) || isBytesOrRunes(Vu)) && isString(T) {
+		return true
+	}
+
+	// "x is a string and T is a slice of bytes or runes"
+	if isString(V) && isBytesOrRunes(Tu) {
+		return true
+	}
+
+	// package unsafe:
+	// "any pointer or value of underlying type uintptr can be converted into a unsafe.Pointer"
+	if (isPointer(Vu) || isUintptr(Vu)) && isUnsafePointer(T) {
+		return true
+	}
+	// "and vice versa"
+	if isUnsafePointer(V) && (isPointer(Tu) || isUintptr(Tu)) {
+		return true
+	}
+
+	return false
+}
+
+func isUintptr(typ Type) bool {
+	t, ok := typ.Underlying().(*Basic)
+	return ok && t.kind == Uintptr
+}
+
+func isUnsafePointer(typ Type) bool {
+	// TODO(gri): Is this (typ.Underlying() instead of just typ) correct?
+	//            The spec does not say so, but gc claims it is. See also
+	//            issue 6326.
+	t, ok := typ.Underlying().(*Basic)
+	return ok && t.kind == UnsafePointer
+}
+
+func isPointer(typ Type) bool {
+	_, ok := typ.Underlying().(*Pointer)
+	return ok
+}
+
+func isBytesOrRunes(typ Type) bool {
+	if s, ok := typ.(*Slice); ok {
+		t, ok := s.elem.Underlying().(*Basic)
+		return ok && (t.kind == Byte || t.kind == Rune)
+	}
+	return false
+}
diff --git a/src/go/types/decl.go b/src/go/types/decl.go
new file mode 100644
index 0000000..8e9e5f3
--- /dev/null
+++ b/src/go/types/decl.go
@@ -0,0 +1,430 @@
+// 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 types
+
+import (
+	"go/ast"
+	"go/constant"
+	"go/token"
+)
+
+func (check *Checker) reportAltDecl(obj Object) {
+	if pos := obj.Pos(); pos.IsValid() {
+		// We use "other" rather than "previous" here because
+		// the first declaration seen may not be textually
+		// earlier in the source.
+		check.errorf(pos, "\tother declaration of %s", obj.Name()) // secondary error, \t indented
+	}
+}
+
+func (check *Checker) declare(scope *Scope, id *ast.Ident, obj Object, pos token.Pos) {
+	// spec: "The blank identifier, represented by the underscore
+	// character _, may be used in a declaration like any other
+	// identifier but the declaration does not introduce a new
+	// binding."
+	if obj.Name() != "_" {
+		if alt := scope.Insert(obj); alt != nil {
+			check.errorf(obj.Pos(), "%s redeclared in this block", obj.Name())
+			check.reportAltDecl(alt)
+			return
+		}
+		obj.setScopePos(pos)
+	}
+	if id != nil {
+		check.recordDef(id, obj)
+	}
+}
+
+// objDecl type-checks the declaration of obj in its respective (file) context.
+// See check.typ for the details on def and path.
+func (check *Checker) objDecl(obj Object, def *Named, path []*TypeName) {
+	if obj.Type() != nil {
+		return // already checked - nothing to do
+	}
+
+	if trace {
+		check.trace(obj.Pos(), "-- declaring %s", obj.Name())
+		check.indent++
+		defer func() {
+			check.indent--
+			check.trace(obj.Pos(), "=> %s", obj)
+		}()
+	}
+
+	d := check.objMap[obj]
+	if d == nil {
+		check.dump("%s: %s should have been declared", obj.Pos(), obj.Name())
+		unreachable()
+	}
+
+	// save/restore current context and setup object context
+	defer func(ctxt context) {
+		check.context = ctxt
+	}(check.context)
+	check.context = context{
+		scope: d.file,
+	}
+
+	// Const and var declarations must not have initialization
+	// cycles. We track them by remembering the current declaration
+	// in check.decl. Initialization expressions depending on other
+	// consts, vars, or functions, add dependencies to the current
+	// check.decl.
+	switch obj := obj.(type) {
+	case *Const:
+		check.decl = d // new package-level const decl
+		check.constDecl(obj, d.typ, d.init)
+	case *Var:
+		check.decl = d // new package-level var decl
+		check.varDecl(obj, d.lhs, d.typ, d.init)
+	case *TypeName:
+		// invalid recursive types are detected via path
+		check.typeDecl(obj, d.typ, def, path)
+	case *Func:
+		// functions may be recursive - no need to track dependencies
+		check.funcDecl(obj, d)
+	default:
+		unreachable()
+	}
+}
+
+func (check *Checker) constDecl(obj *Const, typ, init ast.Expr) {
+	assert(obj.typ == nil)
+
+	if obj.visited {
+		obj.typ = Typ[Invalid]
+		return
+	}
+	obj.visited = true
+
+	// use the correct value of iota
+	assert(check.iota == nil)
+	check.iota = obj.val
+	defer func() { check.iota = nil }()
+
+	// provide valid constant value under all circumstances
+	obj.val = constant.MakeUnknown()
+
+	// determine type, if any
+	if typ != nil {
+		t := check.typ(typ)
+		if !isConstType(t) {
+			check.errorf(typ.Pos(), "invalid constant type %s", t)
+			obj.typ = Typ[Invalid]
+			return
+		}
+		obj.typ = t
+	}
+
+	// check initialization
+	var x operand
+	if init != nil {
+		check.expr(&x, init)
+	}
+	check.initConst(obj, &x)
+}
+
+func (check *Checker) varDecl(obj *Var, lhs []*Var, typ, init ast.Expr) {
+	assert(obj.typ == nil)
+
+	if obj.visited {
+		obj.typ = Typ[Invalid]
+		return
+	}
+	obj.visited = true
+
+	// var declarations cannot use iota
+	assert(check.iota == nil)
+
+	// determine type, if any
+	if typ != nil {
+		obj.typ = check.typ(typ)
+	}
+
+	// check initialization
+	if init == nil {
+		if typ == nil {
+			// error reported before by arityMatch
+			obj.typ = Typ[Invalid]
+		}
+		return
+	}
+
+	if lhs == nil || len(lhs) == 1 {
+		assert(lhs == nil || lhs[0] == obj)
+		var x operand
+		check.expr(&x, init)
+		check.initVar(obj, &x, false)
+		return
+	}
+
+	if debug {
+		// obj must be one of lhs
+		found := false
+		for _, lhs := range lhs {
+			if obj == lhs {
+				found = true
+				break
+			}
+		}
+		if !found {
+			panic("inconsistent lhs")
+		}
+	}
+	check.initVars(lhs, []ast.Expr{init}, token.NoPos)
+}
+
+// underlying returns the underlying type of typ; possibly by following
+// forward chains of named types. Such chains only exist while named types
+// are incomplete.
+func underlying(typ Type) Type {
+	for {
+		n, _ := typ.(*Named)
+		if n == nil {
+			break
+		}
+		typ = n.underlying
+	}
+	return typ
+}
+
+func (n *Named) setUnderlying(typ Type) {
+	if n != nil {
+		n.underlying = typ
+	}
+}
+
+func (check *Checker) typeDecl(obj *TypeName, typ ast.Expr, def *Named, path []*TypeName) {
+	assert(obj.typ == nil)
+
+	// type declarations cannot use iota
+	assert(check.iota == nil)
+
+	named := &Named{obj: obj}
+	def.setUnderlying(named)
+	obj.typ = named // make sure recursive type declarations terminate
+
+	// determine underlying type of named
+	check.typExpr(typ, named, append(path, obj))
+
+	// The underlying type of named may be itself a named type that is
+	// incomplete:
+	//
+	//	type (
+	//		A B
+	//		B *C
+	//		C A
+	//	)
+	//
+	// The type of C is the (named) type of A which is incomplete,
+	// and which has as its underlying type the named type B.
+	// Determine the (final, unnamed) underlying type by resolving
+	// any forward chain (they always end in an unnamed type).
+	named.underlying = underlying(named.underlying)
+
+	// check and add associated methods
+	// TODO(gri) It's easy to create pathological cases where the
+	// current approach is incorrect: In general we need to know
+	// and add all methods _before_ type-checking the type.
+	// See https://play.golang.org/p/WMpE0q2wK8
+	check.addMethodDecls(obj)
+}
+
+func (check *Checker) addMethodDecls(obj *TypeName) {
+	// get associated methods
+	methods := check.methods[obj.name]
+	if len(methods) == 0 {
+		return // no methods
+	}
+	delete(check.methods, obj.name)
+
+	// use an objset to check for name conflicts
+	var mset objset
+
+	// spec: "If the base type is a struct type, the non-blank method
+	// and field names must be distinct."
+	base := obj.typ.(*Named)
+	if t, _ := base.underlying.(*Struct); t != nil {
+		for _, fld := range t.fields {
+			if fld.name != "_" {
+				assert(mset.insert(fld) == nil)
+			}
+		}
+	}
+
+	// Checker.Files may be called multiple times; additional package files
+	// may add methods to already type-checked types. Add pre-existing methods
+	// so that we can detect redeclarations.
+	for _, m := range base.methods {
+		assert(m.name != "_")
+		assert(mset.insert(m) == nil)
+	}
+
+	// type-check methods
+	for _, m := range methods {
+		// spec: "For a base type, the non-blank names of methods bound
+		// to it must be unique."
+		if m.name != "_" {
+			if alt := mset.insert(m); alt != nil {
+				switch alt.(type) {
+				case *Var:
+					check.errorf(m.pos, "field and method with the same name %s", m.name)
+				case *Func:
+					check.errorf(m.pos, "method %s already declared for %s", m.name, base)
+				default:
+					unreachable()
+				}
+				check.reportAltDecl(alt)
+				continue
+			}
+		}
+		check.objDecl(m, nil, nil)
+		// methods with blank _ names cannot be found - don't keep them
+		if m.name != "_" {
+			base.methods = append(base.methods, m)
+		}
+	}
+}
+
+func (check *Checker) funcDecl(obj *Func, decl *declInfo) {
+	assert(obj.typ == nil)
+
+	// func declarations cannot use iota
+	assert(check.iota == nil)
+
+	sig := new(Signature)
+	obj.typ = sig // guard against cycles
+	fdecl := decl.fdecl
+	check.funcType(sig, fdecl.Recv, fdecl.Type)
+	if sig.recv == nil && obj.name == "init" && (sig.params.Len() > 0 || sig.results.Len() > 0) {
+		check.errorf(fdecl.Pos(), "func init must have no arguments and no return values")
+		// ok to continue
+	}
+
+	// function body must be type-checked after global declarations
+	// (functions implemented elsewhere have no body)
+	if !check.conf.IgnoreFuncBodies && fdecl.Body != nil {
+		check.later(obj.name, decl, sig, fdecl.Body)
+	}
+}
+
+func (check *Checker) declStmt(decl ast.Decl) {
+	pkg := check.pkg
+
+	switch d := decl.(type) {
+	case *ast.BadDecl:
+		// ignore
+
+	case *ast.GenDecl:
+		var last *ast.ValueSpec // last ValueSpec with type or init exprs seen
+		for iota, spec := range d.Specs {
+			switch s := spec.(type) {
+			case *ast.ValueSpec:
+				switch d.Tok {
+				case token.CONST:
+					// determine which init exprs to use
+					switch {
+					case s.Type != nil || len(s.Values) > 0:
+						last = s
+					case last == nil:
+						last = new(ast.ValueSpec) // make sure last exists
+					}
+
+					// declare all constants
+					lhs := make([]*Const, len(s.Names))
+					for i, name := range s.Names {
+						obj := NewConst(name.Pos(), pkg, name.Name, nil, constant.MakeInt64(int64(iota)))
+						lhs[i] = obj
+
+						var init ast.Expr
+						if i < len(last.Values) {
+							init = last.Values[i]
+						}
+
+						check.constDecl(obj, last.Type, init)
+					}
+
+					check.arityMatch(s, last)
+
+					// spec: "The scope of a constant or variable identifier declared
+					// inside a function begins at the end of the ConstSpec or VarSpec
+					// (ShortVarDecl for short variable declarations) and ends at the
+					// end of the innermost containing block."
+					scopePos := s.End()
+					for i, name := range s.Names {
+						check.declare(check.scope, name, lhs[i], scopePos)
+					}
+
+				case token.VAR:
+					lhs0 := make([]*Var, len(s.Names))
+					for i, name := range s.Names {
+						lhs0[i] = NewVar(name.Pos(), pkg, name.Name, nil)
+					}
+
+					// initialize all variables
+					for i, obj := range lhs0 {
+						var lhs []*Var
+						var init ast.Expr
+						switch len(s.Values) {
+						case len(s.Names):
+							// lhs and rhs match
+							init = s.Values[i]
+						case 1:
+							// rhs is expected to be a multi-valued expression
+							lhs = lhs0
+							init = s.Values[0]
+						default:
+							if i < len(s.Values) {
+								init = s.Values[i]
+							}
+						}
+						check.varDecl(obj, lhs, s.Type, init)
+						if len(s.Values) == 1 {
+							// If we have a single lhs variable we are done either way.
+							// If we have a single rhs expression, it must be a multi-
+							// valued expression, in which case handling the first lhs
+							// variable will cause all lhs variables to have a type
+							// assigned, and we are done as well.
+							if debug {
+								for _, obj := range lhs0 {
+									assert(obj.typ != nil)
+								}
+							}
+							break
+						}
+					}
+
+					check.arityMatch(s, nil)
+
+					// declare all variables
+					// (only at this point are the variable scopes (parents) set)
+					scopePos := s.End() // see constant declarations
+					for i, name := range s.Names {
+						// see constant declarations
+						check.declare(check.scope, name, lhs0[i], scopePos)
+					}
+
+				default:
+					check.invalidAST(s.Pos(), "invalid token %s", d.Tok)
+				}
+
+			case *ast.TypeSpec:
+				obj := NewTypeName(s.Name.Pos(), pkg, s.Name.Name, nil)
+				// spec: "The scope of a type identifier declared inside a function
+				// begins at the identifier in the TypeSpec and ends at the end of
+				// the innermost containing block."
+				scopePos := s.Name.Pos()
+				check.declare(check.scope, s.Name, obj, scopePos)
+				check.typeDecl(obj, s.Type, nil, nil)
+
+			default:
+				check.invalidAST(s.Pos(), "const, type, or var declaration expected")
+			}
+		}
+
+	default:
+		check.invalidAST(d.Pos(), "unknown ast.Decl node %T", d)
+	}
+}
diff --git a/src/go/types/errors.go b/src/go/types/errors.go
new file mode 100644
index 0000000..0c0049b
--- /dev/null
+++ b/src/go/types/errors.go
@@ -0,0 +1,103 @@
+// 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.
+
+// This file implements various error reporters.
+
+package types
+
+import (
+	"fmt"
+	"go/ast"
+	"go/token"
+	"strings"
+)
+
+func assert(p bool) {
+	if !p {
+		panic("assertion failed")
+	}
+}
+
+func unreachable() {
+	panic("unreachable")
+}
+
+func (check *Checker) qualifier(pkg *Package) string {
+	if pkg != check.pkg {
+		return pkg.path
+	}
+	return ""
+}
+
+func (check *Checker) sprintf(format string, args ...interface{}) string {
+	for i, arg := range args {
+		switch a := arg.(type) {
+		case nil:
+			arg = "<nil>"
+		case operand:
+			panic("internal error: should always pass *operand")
+		case *operand:
+			arg = operandString(a, check.qualifier)
+		case token.Pos:
+			arg = check.fset.Position(a).String()
+		case ast.Expr:
+			arg = ExprString(a)
+		case Object:
+			arg = ObjectString(a, check.qualifier)
+		case Type:
+			arg = TypeString(a, check.qualifier)
+		}
+		args[i] = arg
+	}
+	return fmt.Sprintf(format, args...)
+}
+
+func (check *Checker) trace(pos token.Pos, format string, args ...interface{}) {
+	fmt.Printf("%s:\t%s%s\n",
+		check.fset.Position(pos),
+		strings.Repeat(".  ", check.indent),
+		check.sprintf(format, args...),
+	)
+}
+
+// dump is only needed for debugging
+func (check *Checker) dump(format string, args ...interface{}) {
+	fmt.Println(check.sprintf(format, args...))
+}
+
+func (check *Checker) err(pos token.Pos, msg string, soft bool) {
+	err := Error{check.fset, pos, msg, soft}
+	if check.firstErr == nil {
+		check.firstErr = err
+	}
+	f := check.conf.Error
+	if f == nil {
+		panic(bailout{}) // report only first error
+	}
+	f(err)
+}
+
+func (check *Checker) error(pos token.Pos, msg string) {
+	check.err(pos, msg, false)
+}
+
+func (check *Checker) errorf(pos token.Pos, format string, args ...interface{}) {
+	check.err(pos, check.sprintf(format, args...), false)
+}
+
+func (check *Checker) softErrorf(pos token.Pos, format string, args ...interface{}) {
+	check.err(pos, check.sprintf(format, args...), true)
+}
+
+func (check *Checker) invalidAST(pos token.Pos, format string, args ...interface{}) {
+	check.errorf(pos, "invalid AST: "+format, args...)
+}
+
+func (check *Checker) invalidArg(pos token.Pos, format string, args ...interface{}) {
+	check.errorf(pos, "invalid argument: "+format, args...)
+}
+
+func (check *Checker) invalidOp(pos token.Pos, format string, args ...interface{}) {
+	check.errorf(pos, "invalid operation: "+format, args...)
+}
diff --git a/src/go/types/eval.go b/src/go/types/eval.go
new file mode 100644
index 0000000..7b42ff1
--- /dev/null
+++ b/src/go/types/eval.go
@@ -0,0 +1,83 @@
+// 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 types
+
+import (
+	"fmt"
+	"go/parser"
+	"go/token"
+)
+
+// Eval returns the type and, if constant, the value for the
+// expression expr, evaluated at position pos of package pkg,
+// which must have been derived from type-checking an AST with
+// complete position information relative to the provided file
+// set.
+//
+// If the expression contains function literals, their bodies
+// are ignored (i.e., the bodies are not type-checked).
+//
+// If pkg == nil, the Universe scope is used and the provided
+// position pos is ignored. If pkg != nil, and pos is invalid,
+// the package scope is used. Otherwise, pos must belong to the
+// package.
+//
+// An error is returned if pos is not within the package or
+// if the node cannot be evaluated.
+//
+// Note: Eval should not be used instead of running Check to compute
+// types and values, but in addition to Check. Eval will re-evaluate
+// its argument each time, and it also does not know about the context
+// in which an expression is used (e.g., an assignment). Thus, top-
+// level untyped constants will return an untyped type rather then the
+// respective context-specific type.
+//
+func Eval(fset *token.FileSet, pkg *Package, pos token.Pos, expr string) (tv TypeAndValue, err error) {
+	// determine scope
+	var scope *Scope
+	if pkg == nil {
+		scope = Universe
+		pos = token.NoPos
+	} else if !pos.IsValid() {
+		scope = pkg.scope
+	} else {
+		// The package scope extent (position information) may be
+		// incorrect (files spread accross a wide range of fset
+		// positions) - ignore it and just consider its children
+		// (file scopes).
+		for _, fscope := range pkg.scope.children {
+			if scope = fscope.Innermost(pos); scope != nil {
+				break
+			}
+		}
+		if scope == nil || debug {
+			s := scope
+			for s != nil && s != pkg.scope {
+				s = s.parent
+			}
+			// s == nil || s == pkg.scope
+			if s == nil {
+				return TypeAndValue{}, fmt.Errorf("no position %s found in package %s", fset.Position(pos), pkg.name)
+			}
+		}
+	}
+
+	// parse expressions
+	node, err := parser.ParseExprFrom(fset, "eval", expr, 0)
+	if err != nil {
+		return TypeAndValue{}, err
+	}
+
+	// initialize checker
+	check := NewChecker(nil, fset, pkg, nil)
+	check.scope = scope
+	check.pos = pos
+	defer check.handleBailout(&err)
+
+	// evaluate node
+	var x operand
+	check.rawExpr(&x, node, nil)
+	return TypeAndValue{x.mode, x.typ, x.val}, err
+}
diff --git a/src/go/types/eval_test.go b/src/go/types/eval_test.go
new file mode 100644
index 0000000..7e0be43
--- /dev/null
+++ b/src/go/types/eval_test.go
@@ -0,0 +1,188 @@
+// 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.
+
+// This file contains tests for Eval.
+
+package types_test
+
+import (
+	"go/ast"
+	"go/importer"
+	"go/parser"
+	"go/token"
+	"internal/testenv"
+	"strings"
+	"testing"
+
+	. "go/types"
+)
+
+func testEval(t *testing.T, fset *token.FileSet, pkg *Package, pos token.Pos, expr string, typ Type, typStr, valStr string) {
+	gotTv, err := Eval(fset, pkg, pos, expr)
+	if err != nil {
+		t.Errorf("Eval(%q) failed: %s", expr, err)
+		return
+	}
+	if gotTv.Type == nil {
+		t.Errorf("Eval(%q) got nil type but no error", expr)
+		return
+	}
+
+	// compare types
+	if typ != nil {
+		// we have a type, check identity
+		if !Identical(gotTv.Type, typ) {
+			t.Errorf("Eval(%q) got type %s, want %s", expr, gotTv.Type, typ)
+			return
+		}
+	} else {
+		// we have a string, compare type string
+		gotStr := gotTv.Type.String()
+		if gotStr != typStr {
+			t.Errorf("Eval(%q) got type %s, want %s", expr, gotStr, typStr)
+			return
+		}
+	}
+
+	// compare values
+	gotStr := ""
+	if gotTv.Value != nil {
+		gotStr = gotTv.Value.String()
+	}
+	if gotStr != valStr {
+		t.Errorf("Eval(%q) got value %s, want %s", expr, gotStr, valStr)
+	}
+}
+
+func TestEvalBasic(t *testing.T) {
+	fset := token.NewFileSet()
+	for _, typ := range Typ[Bool : String+1] {
+		testEval(t, fset, nil, token.NoPos, typ.Name(), typ, "", "")
+	}
+}
+
+func TestEvalComposite(t *testing.T) {
+	fset := token.NewFileSet()
+	for _, test := range independentTestTypes {
+		testEval(t, fset, nil, token.NoPos, test.src, nil, test.str, "")
+	}
+}
+
+func TestEvalArith(t *testing.T) {
+	var tests = []string{
+		`true`,
+		`false == false`,
+		`12345678 + 87654321 == 99999999`,
+		`10 * 20 == 200`,
+		`(1<<1000)*2 >> 100 == 2<<900`,
+		`"foo" + "bar" == "foobar"`,
+		`"abc" <= "bcd"`,
+		`len([10]struct{}{}) == 2*5`,
+	}
+	fset := token.NewFileSet()
+	for _, test := range tests {
+		testEval(t, fset, nil, token.NoPos, test, Typ[UntypedBool], "", "true")
+	}
+}
+
+func TestEvalPos(t *testing.T) {
+	testenv.MustHaveGoBuild(t)
+
+	// The contents of /*-style comments are of the form
+	//	expr => value, type
+	// where value may be the empty string.
+	// Each expr is evaluated at the position of the comment
+	// and the result is compared with the expected value
+	// and type.
+	var sources = []string{
+		`
+		package p
+		import "fmt"
+		import m "math"
+		const c = 3.0
+		type T []int
+		func f(a int, s string) float64 {
+			fmt.Println("calling f")
+			_ = m.Pi // use package math
+			const d int = c + 1
+			var x int
+			x = a + len(s)
+			return float64(x)
+			/* true => true, untyped bool */
+			/* fmt.Println => , func(a ...interface{}) (n int, err error) */
+			/* c => 3, untyped float */
+			/* T => , p.T */
+			/* a => , int */
+			/* s => , string */
+			/* d => 4, int */
+			/* x => , int */
+			/* d/c => 1, int */
+			/* c/2 => 3/2, untyped float */
+			/* m.Pi < m.E => false, untyped bool */
+		}
+		`,
+		`
+		package p
+		/* c => 3, untyped float */
+		type T1 /* T1 => , p.T1 */ struct {}
+		var v1 /* v1 => , int */ = 42
+		func /* f1 => , func(v1 float64) */ f1(v1 float64) {
+			/* f1 => , func(v1 float64) */
+			/* v1 => , float64 */
+			var c /* c => 3, untyped float */ = "foo" /* c => , string */
+			{
+				var c struct {
+					c /* c => , string */ int
+				}
+				/* c => , struct{c int} */
+				_ = c
+			}
+			_ = func(a, b, c int) /* c => , string */ {
+				/* c => , int */
+			}
+			_ = c
+			type FT /* FT => , p.FT */ interface{}
+		}
+		`,
+		`
+		package p
+		/* T => , p.T */
+		`,
+	}
+
+	fset := token.NewFileSet()
+	var files []*ast.File
+	for i, src := range sources {
+		file, err := parser.ParseFile(fset, "p", src, parser.ParseComments)
+		if err != nil {
+			t.Fatalf("could not parse file %d: %s", i, err)
+		}
+		files = append(files, file)
+	}
+
+	conf := Config{Importer: importer.Default()}
+	pkg, err := conf.Check("p", fset, files, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	for _, file := range files {
+		for _, group := range file.Comments {
+			for _, comment := range group.List {
+				s := comment.Text
+				if len(s) >= 4 && s[:2] == "/*" && s[len(s)-2:] == "*/" {
+					str, typ := split(s[2:len(s)-2], ", ")
+					str, val := split(str, "=>")
+					testEval(t, fset, pkg, comment.Pos(), str, nil, typ, val)
+				}
+			}
+		}
+	}
+}
+
+// split splits string s at the first occurrence of s.
+func split(s, sep string) (string, string) {
+	i := strings.Index(s, sep)
+	return strings.TrimSpace(s[:i]), strings.TrimSpace(s[i+len(sep):])
+}
diff --git a/src/go/types/example_test.go b/src/go/types/example_test.go
new file mode 100644
index 0000000..8882e50
--- /dev/null
+++ b/src/go/types/example_test.go
@@ -0,0 +1,312 @@
+// 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.
+
+// Only run where builders (build.golang.org) have
+// access to compiled packages for import.
+//
+// +build !arm,!arm64,!nacl
+
+package types_test
+
+// This file shows examples of basic usage of the go/types API.
+//
+// To locate a Go package, use (*go/build.Context).Import.
+// To load, parse, and type-check a complete Go program
+// from source, use golang.org/x/tools/go/loader.
+
+import (
+	"bytes"
+	"fmt"
+	"go/ast"
+	"go/format"
+	"go/importer"
+	"go/parser"
+	"go/token"
+	"go/types"
+	"log"
+	"regexp"
+	"sort"
+	"strings"
+)
+
+// ExampleScope prints the tree of Scopes of a package created from a
+// set of parsed files.
+func ExampleScope() {
+	// Parse the source files for a package.
+	fset := token.NewFileSet()
+	var files []*ast.File
+	for _, file := range []struct{ name, input string }{
+		{"main.go", `
+package main
+import "fmt"
+func main() {
+	freezing := FToC(-18)
+	fmt.Println(freezing, Boiling) }
+`},
+		{"celsius.go", `
+package main
+import "fmt"
+type Celsius float64
+func (c Celsius) String() string { return fmt.Sprintf("%g°C", c) }
+func FToC(f float64) Celsius { return Celsius(f - 32 / 9 * 5) }
+const Boiling Celsius = 100
+`},
+	} {
+		f, err := parser.ParseFile(fset, file.name, file.input, 0)
+		if err != nil {
+			log.Fatal(err)
+		}
+		files = append(files, f)
+	}
+
+	// Type-check a package consisting of these files.
+	// Type information for the imported "fmt" package
+	// comes from $GOROOT/pkg/$GOOS_$GOOARCH/fmt.a.
+	conf := types.Config{Importer: importer.Default()}
+	pkg, err := conf.Check("temperature", fset, files, nil)
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	// Print the tree of scopes.
+	// For determinism, we redact addresses.
+	var buf bytes.Buffer
+	pkg.Scope().WriteTo(&buf, 0, true)
+	rx := regexp.MustCompile(` 0x[a-fA-F0-9]*`)
+	fmt.Println(rx.ReplaceAllString(buf.String(), ""))
+
+	// Output:
+	// package "temperature" scope {
+	// .  const temperature.Boiling temperature.Celsius
+	// .  type temperature.Celsius float64
+	// .  func temperature.FToC(f float64) temperature.Celsius
+	// .  func temperature.main()
+	//
+	// .  main.go scope {
+	// .  .  package fmt
+	//
+	// .  .  function scope {
+	// .  .  .  var freezing temperature.Celsius
+	// .  .  }.  }
+	// .  celsius.go scope {
+	// .  .  package fmt
+	//
+	// .  .  function scope {
+	// .  .  .  var c temperature.Celsius
+	// .  .  }
+	// .  .  function scope {
+	// .  .  .  var f float64
+	// .  .  }.  }}
+}
+
+// ExampleMethodSet prints the method sets of various types.
+func ExampleMethodSet() {
+	// Parse a single source file.
+	const input = `
+package temperature
+import "fmt"
+type Celsius float64
+func (c Celsius) String() string  { return fmt.Sprintf("%g°C", c) }
+func (c *Celsius) SetF(f float64) { *c = Celsius(f - 32 / 9 * 5) }
+`
+	fset := token.NewFileSet()
+	f, err := parser.ParseFile(fset, "celsius.go", input, 0)
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	// Type-check a package consisting of this file.
+	// Type information for the imported packages
+	// comes from $GOROOT/pkg/$GOOS_$GOOARCH/fmt.a.
+	conf := types.Config{Importer: importer.Default()}
+	pkg, err := conf.Check("temperature", fset, []*ast.File{f}, nil)
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	// Print the method sets of Celsius and *Celsius.
+	celsius := pkg.Scope().Lookup("Celsius").Type()
+	for _, t := range []types.Type{celsius, types.NewPointer(celsius)} {
+		fmt.Printf("Method set of %s:\n", t)
+		mset := types.NewMethodSet(t)
+		for i := 0; i < mset.Len(); i++ {
+			fmt.Println(mset.At(i))
+		}
+		fmt.Println()
+	}
+
+	// Output:
+	// Method set of temperature.Celsius:
+	// method (temperature.Celsius) String() string
+	//
+	// Method set of *temperature.Celsius:
+	// method (*temperature.Celsius) SetF(f float64)
+	// method (*temperature.Celsius) String() string
+}
+
+// ExampleInfo prints various facts recorded by the type checker in a
+// types.Info struct: definitions of and references to each named object,
+// and the type, value, and mode of every expression in the package.
+func ExampleInfo() {
+	// Parse a single source file.
+	const input = `
+package fib
+
+type S string
+
+var a, b, c = len(b), S(c), "hello"
+
+func fib(x int) int {
+	if x < 2 {
+		return x
+	}
+	return fib(x-1) - fib(x-2)
+}`
+	fset := token.NewFileSet()
+	f, err := parser.ParseFile(fset, "fib.go", input, 0)
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	// Type-check the package.
+	// We create an empty map for each kind of input
+	// we're interested in, and Check populates them.
+	info := types.Info{
+		Types: make(map[ast.Expr]types.TypeAndValue),
+		Defs:  make(map[*ast.Ident]types.Object),
+		Uses:  make(map[*ast.Ident]types.Object),
+	}
+	var conf types.Config
+	pkg, err := conf.Check("fib", fset, []*ast.File{f}, &info)
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	// Print package-level variables in initialization order.
+	fmt.Printf("InitOrder: %v\n\n", info.InitOrder)
+
+	// For each named object, print the line and
+	// column of its definition and each of its uses.
+	fmt.Println("Defs and Uses of each named object:")
+	usesByObj := make(map[types.Object][]string)
+	for id, obj := range info.Uses {
+		posn := fset.Position(id.Pos())
+		lineCol := fmt.Sprintf("%d:%d", posn.Line, posn.Column)
+		usesByObj[obj] = append(usesByObj[obj], lineCol)
+	}
+	var items []string
+	for obj, uses := range usesByObj {
+		sort.Strings(uses)
+		item := fmt.Sprintf("%s:\n  defined at %s\n  used at %s",
+			types.ObjectString(obj, types.RelativeTo(pkg)),
+			fset.Position(obj.Pos()),
+			strings.Join(uses, ", "))
+		items = append(items, item)
+	}
+	sort.Strings(items) // sort by line:col, in effect
+	fmt.Println(strings.Join(items, "\n"))
+	fmt.Println()
+
+	fmt.Println("Types and Values of each expression:")
+	items = nil
+	for expr, tv := range info.Types {
+		var buf bytes.Buffer
+		posn := fset.Position(expr.Pos())
+		tvstr := tv.Type.String()
+		if tv.Value != nil {
+			tvstr += " = " + tv.Value.String()
+		}
+		// line:col | expr | mode : type = value
+		fmt.Fprintf(&buf, "%2d:%2d | %-19s | %-7s : %s",
+			posn.Line, posn.Column, exprString(fset, expr),
+			mode(tv), tvstr)
+		items = append(items, buf.String())
+	}
+	sort.Strings(items)
+	fmt.Println(strings.Join(items, "\n"))
+
+	// Output:
+	// InitOrder: [c = "hello" b = S(c) a = len(b)]
+	//
+	// Defs and Uses of each named object:
+	// builtin len:
+	//   defined at -
+	//   used at 6:15
+	// func fib(x int) int:
+	//   defined at fib.go:8:6
+	//   used at 12:20, 12:9
+	// type S string:
+	//   defined at fib.go:4:6
+	//   used at 6:23
+	// type int int:
+	//   defined at -
+	//   used at 8:12, 8:17
+	// type string string:
+	//   defined at -
+	//   used at 4:8
+	// var b S:
+	//   defined at fib.go:6:8
+	//   used at 6:19
+	// var c string:
+	//   defined at fib.go:6:11
+	//   used at 6:25
+	// var x int:
+	//   defined at fib.go:8:10
+	//   used at 10:10, 12:13, 12:24, 9:5
+	//
+	// Types and Values of each expression:
+	//  4: 8 | string              | type    : string
+	//  6:15 | len                 | builtin : func(string) int
+	//  6:15 | len(b)              | value   : int
+	//  6:19 | b                   | var     : fib.S
+	//  6:23 | S                   | type    : fib.S
+	//  6:23 | S(c)                | value   : fib.S
+	//  6:25 | c                   | var     : string
+	//  6:29 | "hello"             | value   : string = "hello"
+	//  8:12 | int                 | type    : int
+	//  8:17 | int                 | type    : int
+	//  9: 5 | x                   | var     : int
+	//  9: 5 | x < 2               | value   : untyped bool
+	//  9: 9 | 2                   | value   : int = 2
+	// 10:10 | x                   | var     : int
+	// 12: 9 | fib                 | value   : func(x int) int
+	// 12: 9 | fib(x - 1)          | value   : int
+	// 12: 9 | fib(x-1) - fib(x-2) | value   : int
+	// 12:13 | x                   | var     : int
+	// 12:13 | x - 1               | value   : int
+	// 12:15 | 1                   | value   : int = 1
+	// 12:20 | fib                 | value   : func(x int) int
+	// 12:20 | fib(x - 2)          | value   : int
+	// 12:24 | x                   | var     : int
+	// 12:24 | x - 2               | value   : int
+	// 12:26 | 2                   | value   : int = 2
+}
+
+func mode(tv types.TypeAndValue) string {
+	switch {
+	case tv.IsVoid():
+		return "void"
+	case tv.IsType():
+		return "type"
+	case tv.IsBuiltin():
+		return "builtin"
+	case tv.IsNil():
+		return "nil"
+	case tv.Assignable():
+		if tv.Addressable() {
+			return "var"
+		}
+		return "mapindex"
+	case tv.IsValue():
+		return "value"
+	default:
+		return "unknown"
+	}
+}
+
+func exprString(fset *token.FileSet, expr ast.Expr) string {
+	var buf bytes.Buffer
+	format.Node(&buf, fset, expr)
+	return buf.String()
+}
diff --git a/src/go/types/expr.go b/src/go/types/expr.go
new file mode 100644
index 0000000..7d00dd5
--- /dev/null
+++ b/src/go/types/expr.go
@@ -0,0 +1,1496 @@
+// 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.
+
+// This file implements typechecking of expressions.
+
+package types
+
+import (
+	"fmt"
+	"go/ast"
+	"go/constant"
+	"go/token"
+	"math"
+)
+
+/*
+Basic algorithm:
+
+Expressions are checked recursively, top down. Expression checker functions
+are generally of the form:
+
+  func f(x *operand, e *ast.Expr, ...)
+
+where e is the expression to be checked, and x is the result of the check.
+The check performed by f may fail in which case x.mode == invalid, and
+related error messages will have been issued by f.
+
+If a hint argument is present, it is the composite literal element type
+of an outer composite literal; it is used to type-check composite literal
+elements that have no explicit type specification in the source
+(e.g.: []T{{...}, {...}}, the hint is the type T in this case).
+
+All expressions are checked via rawExpr, which dispatches according
+to expression kind. Upon returning, rawExpr is recording the types and
+constant values for all expressions that have an untyped type (those types
+may change on the way up in the expression tree). Usually these are constants,
+but the results of comparisons or non-constant shifts of untyped constants
+may also be untyped, but not constant.
+
+Untyped expressions may eventually become fully typed (i.e., not untyped),
+typically when the value is assigned to a variable, or is used otherwise.
+The updateExprType method is used to record this final type and update
+the recorded types: the type-checked expression tree is again traversed down,
+and the new type is propagated as needed. Untyped constant expression values
+that become fully typed must now be representable by the full type (constant
+sub-expression trees are left alone except for their roots). This mechanism
+ensures that a client sees the actual (run-time) type an untyped value would
+have. It also permits type-checking of lhs shift operands "as if the shift
+were not present": when updateExprType visits an untyped lhs shift operand
+and assigns it it's final type, that type must be an integer type, and a
+constant lhs must be representable as an integer.
+
+When an expression gets its final type, either on the way out from rawExpr,
+on the way down in updateExprType, or at the end of the type checker run,
+the type (and constant value, if any) is recorded via Info.Types, if present.
+*/
+
+type opPredicates map[token.Token]func(Type) bool
+
+var unaryOpPredicates = opPredicates{
+	token.ADD: isNumeric,
+	token.SUB: isNumeric,
+	token.XOR: isInteger,
+	token.NOT: isBoolean,
+}
+
+func (check *Checker) op(m opPredicates, x *operand, op token.Token) bool {
+	if pred := m[op]; pred != nil {
+		if !pred(x.typ) {
+			check.invalidOp(x.pos(), "operator %s not defined for %s", op, x)
+			return false
+		}
+	} else {
+		check.invalidAST(x.pos(), "unknown operator %s", op)
+		return false
+	}
+	return true
+}
+
+// The unary expression e may be nil. It's passed in for better error messages only.
+func (check *Checker) unary(x *operand, e *ast.UnaryExpr, op token.Token) {
+	switch op {
+	case token.AND:
+		// spec: "As an exception to the addressability
+		// requirement x may also be a composite literal."
+		if _, ok := unparen(x.expr).(*ast.CompositeLit); !ok && x.mode != variable {
+			check.invalidOp(x.pos(), "cannot take address of %s", x)
+			x.mode = invalid
+			return
+		}
+		x.mode = value
+		x.typ = &Pointer{base: x.typ}
+		return
+
+	case token.ARROW:
+		typ, ok := x.typ.Underlying().(*Chan)
+		if !ok {
+			check.invalidOp(x.pos(), "cannot receive from non-channel %s", x)
+			x.mode = invalid
+			return
+		}
+		if typ.dir == SendOnly {
+			check.invalidOp(x.pos(), "cannot receive from send-only channel %s", x)
+			x.mode = invalid
+			return
+		}
+		x.mode = commaok
+		x.typ = typ.elem
+		check.hasCallOrRecv = true
+		return
+	}
+
+	if !check.op(unaryOpPredicates, x, op) {
+		x.mode = invalid
+		return
+	}
+
+	if x.mode == constant_ {
+		typ := x.typ.Underlying().(*Basic)
+		var prec uint
+		if isUnsigned(typ) {
+			prec = uint(check.conf.sizeof(typ) * 8)
+		}
+		x.val = constant.UnaryOp(op, x.val, prec)
+		// Typed constants must be representable in
+		// their type after each constant operation.
+		if isTyped(typ) {
+			if e != nil {
+				x.expr = e // for better error message
+			}
+			check.representable(x, typ)
+		}
+		return
+	}
+
+	x.mode = value
+	// x.typ remains unchanged
+}
+
+func isShift(op token.Token) bool {
+	return op == token.SHL || op == token.SHR
+}
+
+func isComparison(op token.Token) bool {
+	// Note: tokens are not ordered well to make this much easier
+	switch op {
+	case token.EQL, token.NEQ, token.LSS, token.LEQ, token.GTR, token.GEQ:
+		return true
+	}
+	return false
+}
+
+func fitsFloat32(x constant.Value) bool {
+	f32, _ := constant.Float32Val(x)
+	f := float64(f32)
+	return !math.IsInf(f, 0)
+}
+
+func roundFloat32(x constant.Value) constant.Value {
+	f32, _ := constant.Float32Val(x)
+	f := float64(f32)
+	if !math.IsInf(f, 0) {
+		return constant.MakeFloat64(f)
+	}
+	return nil
+}
+
+func fitsFloat64(x constant.Value) bool {
+	f, _ := constant.Float64Val(x)
+	return !math.IsInf(f, 0)
+}
+
+func roundFloat64(x constant.Value) constant.Value {
+	f, _ := constant.Float64Val(x)
+	if !math.IsInf(f, 0) {
+		return constant.MakeFloat64(f)
+	}
+	return nil
+}
+
+// representableConst reports whether x can be represented as
+// value of the given basic type kind and for the configuration
+// provided (only needed for int/uint sizes).
+//
+// If rounded != nil, *rounded is set to the rounded value of x for
+// representable floating-point values; it is left alone otherwise.
+// It is ok to provide the addressof the first argument for rounded.
+func representableConst(x constant.Value, conf *Config, as BasicKind, rounded *constant.Value) bool {
+	switch x.Kind() {
+	case constant.Unknown:
+		return true
+
+	case constant.Bool:
+		return as == Bool || as == UntypedBool
+
+	case constant.Int:
+		if x, ok := constant.Int64Val(x); ok {
+			switch as {
+			case Int:
+				var s = uint(conf.sizeof(Typ[as])) * 8
+				return int64(-1)<<(s-1) <= x && x <= int64(1)<<(s-1)-1
+			case Int8:
+				const s = 8
+				return -1<<(s-1) <= x && x <= 1<<(s-1)-1
+			case Int16:
+				const s = 16
+				return -1<<(s-1) <= x && x <= 1<<(s-1)-1
+			case Int32:
+				const s = 32
+				return -1<<(s-1) <= x && x <= 1<<(s-1)-1
+			case Int64:
+				return true
+			case Uint, Uintptr:
+				if s := uint(conf.sizeof(Typ[as])) * 8; s < 64 {
+					return 0 <= x && x <= int64(1)<<s-1
+				}
+				return 0 <= x
+			case Uint8:
+				const s = 8
+				return 0 <= x && x <= 1<<s-1
+			case Uint16:
+				const s = 16
+				return 0 <= x && x <= 1<<s-1
+			case Uint32:
+				const s = 32
+				return 0 <= x && x <= 1<<s-1
+			case Uint64:
+				return 0 <= x
+			case Float32, Float64, Complex64, Complex128,
+				UntypedInt, UntypedFloat, UntypedComplex:
+				return true
+			}
+		}
+
+		n := constant.BitLen(x)
+		switch as {
+		case Uint, Uintptr:
+			var s = uint(conf.sizeof(Typ[as])) * 8
+			return constant.Sign(x) >= 0 && n <= int(s)
+		case Uint64:
+			return constant.Sign(x) >= 0 && n <= 64
+		case Float32, Complex64:
+			if rounded == nil {
+				return fitsFloat32(x)
+			}
+			r := roundFloat32(x)
+			if r != nil {
+				*rounded = r
+				return true
+			}
+		case Float64, Complex128:
+			if rounded == nil {
+				return fitsFloat64(x)
+			}
+			r := roundFloat64(x)
+			if r != nil {
+				*rounded = r
+				return true
+			}
+		case UntypedInt, UntypedFloat, UntypedComplex:
+			return true
+		}
+
+	case constant.Float:
+		switch as {
+		case Float32, Complex64:
+			if rounded == nil {
+				return fitsFloat32(x)
+			}
+			r := roundFloat32(x)
+			if r != nil {
+				*rounded = r
+				return true
+			}
+		case Float64, Complex128:
+			if rounded == nil {
+				return fitsFloat64(x)
+			}
+			r := roundFloat64(x)
+			if r != nil {
+				*rounded = r
+				return true
+			}
+		case UntypedFloat, UntypedComplex:
+			return true
+		}
+
+	case constant.Complex:
+		switch as {
+		case Complex64:
+			if rounded == nil {
+				return fitsFloat32(constant.Real(x)) && fitsFloat32(constant.Imag(x))
+			}
+			re := roundFloat32(constant.Real(x))
+			im := roundFloat32(constant.Imag(x))
+			if re != nil && im != nil {
+				*rounded = constant.BinaryOp(re, token.ADD, constant.MakeImag(im))
+				return true
+			}
+		case Complex128:
+			if rounded == nil {
+				return fitsFloat64(constant.Real(x)) && fitsFloat64(constant.Imag(x))
+			}
+			re := roundFloat64(constant.Real(x))
+			im := roundFloat64(constant.Imag(x))
+			if re != nil && im != nil {
+				*rounded = constant.BinaryOp(re, token.ADD, constant.MakeImag(im))
+				return true
+			}
+		case UntypedComplex:
+			return true
+		}
+
+	case constant.String:
+		return as == String || as == UntypedString
+
+	default:
+		unreachable()
+	}
+
+	return false
+}
+
+// representable checks that a constant operand is representable in the given basic type.
+func (check *Checker) representable(x *operand, typ *Basic) {
+	assert(x.mode == constant_)
+	if !representableConst(x.val, check.conf, typ.kind, &x.val) {
+		var msg string
+		if isNumeric(x.typ) && isNumeric(typ) {
+			// numeric conversion : error msg
+			//
+			// integer -> integer : overflows
+			// integer -> float   : overflows (actually not possible)
+			// float   -> integer : truncated
+			// float   -> float   : overflows
+			//
+			if !isInteger(x.typ) && isInteger(typ) {
+				msg = "%s truncated to %s"
+			} else {
+				msg = "%s overflows %s"
+			}
+		} else {
+			msg = "cannot convert %s to %s"
+		}
+		check.errorf(x.pos(), msg, x, typ)
+		x.mode = invalid
+	}
+}
+
+// updateExprType updates the type of x to typ and invokes itself
+// recursively for the operands of x, depending on expression kind.
+// If typ is still an untyped and not the final type, updateExprType
+// only updates the recorded untyped type for x and possibly its
+// operands. Otherwise (i.e., typ is not an untyped type anymore,
+// or it is the final type for x), the type and value are recorded.
+// Also, if x is a constant, it must be representable as a value of typ,
+// and if x is the (formerly untyped) lhs operand of a non-constant
+// shift, it must be an integer value.
+//
+func (check *Checker) updateExprType(x ast.Expr, typ Type, final bool) {
+	old, found := check.untyped[x]
+	if !found {
+		return // nothing to do
+	}
+
+	// update operands of x if necessary
+	switch x := x.(type) {
+	case *ast.BadExpr,
+		*ast.FuncLit,
+		*ast.CompositeLit,
+		*ast.IndexExpr,
+		*ast.SliceExpr,
+		*ast.TypeAssertExpr,
+		*ast.StarExpr,
+		*ast.KeyValueExpr,
+		*ast.ArrayType,
+		*ast.StructType,
+		*ast.FuncType,
+		*ast.InterfaceType,
+		*ast.MapType,
+		*ast.ChanType:
+		// These expression are never untyped - nothing to do.
+		// The respective sub-expressions got their final types
+		// upon assignment or use.
+		if debug {
+			check.dump("%s: found old type(%s): %s (new: %s)", x.Pos(), x, old.typ, typ)
+			unreachable()
+		}
+		return
+
+	case *ast.CallExpr:
+		// Resulting in an untyped constant (e.g., built-in complex).
+		// The respective calls take care of calling updateExprType
+		// for the arguments if necessary.
+
+	case *ast.Ident, *ast.BasicLit, *ast.SelectorExpr:
+		// An identifier denoting a constant, a constant literal,
+		// or a qualified identifier (imported untyped constant).
+		// No operands to take care of.
+
+	case *ast.ParenExpr:
+		check.updateExprType(x.X, typ, final)
+
+	case *ast.UnaryExpr:
+		// If x is a constant, the operands were constants.
+		// They don't need to be updated since they never
+		// get "materialized" into a typed value; and they
+		// will be processed at the end of the type check.
+		if old.val != nil {
+			break
+		}
+		check.updateExprType(x.X, typ, final)
+
+	case *ast.BinaryExpr:
+		if old.val != nil {
+			break // see comment for unary expressions
+		}
+		if isComparison(x.Op) {
+			// The result type is independent of operand types
+			// and the operand types must have final types.
+		} else if isShift(x.Op) {
+			// The result type depends only on lhs operand.
+			// The rhs type was updated when checking the shift.
+			check.updateExprType(x.X, typ, final)
+		} else {
+			// The operand types match the result type.
+			check.updateExprType(x.X, typ, final)
+			check.updateExprType(x.Y, typ, final)
+		}
+
+	default:
+		unreachable()
+	}
+
+	// If the new type is not final and still untyped, just
+	// update the recorded type.
+	if !final && isUntyped(typ) {
+		old.typ = typ.Underlying().(*Basic)
+		check.untyped[x] = old
+		return
+	}
+
+	// Otherwise we have the final (typed or untyped type).
+	// Remove it from the map of yet untyped expressions.
+	delete(check.untyped, x)
+
+	// If x is the lhs of a shift, its final type must be integer.
+	// We already know from the shift check that it is representable
+	// as an integer if it is a constant.
+	if old.isLhs && !isInteger(typ) {
+		check.invalidOp(x.Pos(), "shifted operand %s (type %s) must be integer", x, typ)
+		return
+	}
+
+	// Everything's fine, record final type and value for x.
+	check.recordTypeAndValue(x, old.mode, typ, old.val)
+}
+
+// updateExprVal updates the value of x to val.
+func (check *Checker) updateExprVal(x ast.Expr, val constant.Value) {
+	if info, ok := check.untyped[x]; ok {
+		info.val = val
+		check.untyped[x] = info
+	}
+}
+
+// convertUntyped attempts to set the type of an untyped value to the target type.
+func (check *Checker) convertUntyped(x *operand, target Type) {
+	if x.mode == invalid || isTyped(x.typ) || target == Typ[Invalid] {
+		return
+	}
+
+	// TODO(gri) Sloppy code - clean up. This function is central
+	//           to assignment and expression checking.
+
+	if isUntyped(target) {
+		// both x and target are untyped
+		xkind := x.typ.(*Basic).kind
+		tkind := target.(*Basic).kind
+		if isNumeric(x.typ) && isNumeric(target) {
+			if xkind < tkind {
+				x.typ = target
+				check.updateExprType(x.expr, target, false)
+			}
+		} else if xkind != tkind {
+			goto Error
+		}
+		return
+	}
+
+	// typed target
+	switch t := target.Underlying().(type) {
+	case *Basic:
+		if x.mode == constant_ {
+			check.representable(x, t)
+			if x.mode == invalid {
+				return
+			}
+			// expression value may have been rounded - update if needed
+			// TODO(gri) A floating-point value may silently underflow to
+			// zero. If it was negative, the sign is lost. See issue 6898.
+			check.updateExprVal(x.expr, x.val)
+		} else {
+			// Non-constant untyped values may appear as the
+			// result of comparisons (untyped bool), intermediate
+			// (delayed-checked) rhs operands of shifts, and as
+			// the value nil.
+			switch x.typ.(*Basic).kind {
+			case UntypedBool:
+				if !isBoolean(target) {
+					goto Error
+				}
+			case UntypedInt, UntypedRune, UntypedFloat, UntypedComplex:
+				if !isNumeric(target) {
+					goto Error
+				}
+			case UntypedString:
+				// Non-constant untyped string values are not
+				// permitted by the spec and should not occur.
+				unreachable()
+			case UntypedNil:
+				// Unsafe.Pointer is a basic type that includes nil.
+				if !hasNil(target) {
+					goto Error
+				}
+			default:
+				goto Error
+			}
+		}
+	case *Interface:
+		if !x.isNil() && !t.Empty() /* empty interfaces are ok */ {
+			goto Error
+		}
+		// Update operand types to the default type rather then
+		// the target (interface) type: values must have concrete
+		// dynamic types. If the value is nil, keep it untyped
+		// (this is important for tools such as go vet which need
+		// the dynamic type for argument checking of say, print
+		// functions)
+		if x.isNil() {
+			target = Typ[UntypedNil]
+		} else {
+			// cannot assign untyped values to non-empty interfaces
+			if !t.Empty() {
+				goto Error
+			}
+			target = defaultType(x.typ)
+		}
+	case *Pointer, *Signature, *Slice, *Map, *Chan:
+		if !x.isNil() {
+			goto Error
+		}
+		// keep nil untyped - see comment for interfaces, above
+		target = Typ[UntypedNil]
+	default:
+		goto Error
+	}
+
+	x.typ = target
+	check.updateExprType(x.expr, target, true) // UntypedNils are final
+	return
+
+Error:
+	check.errorf(x.pos(), "cannot convert %s to %s", x, target)
+	x.mode = invalid
+}
+
+func (check *Checker) comparison(x, y *operand, op token.Token) {
+	// spec: "In any comparison, the first operand must be assignable
+	// to the type of the second operand, or vice versa."
+	err := ""
+	if x.assignableTo(check.conf, y.typ) || y.assignableTo(check.conf, x.typ) {
+		defined := false
+		switch op {
+		case token.EQL, token.NEQ:
+			// spec: "The equality operators == and != apply to operands that are comparable."
+			defined = Comparable(x.typ) || x.isNil() && hasNil(y.typ) || y.isNil() && hasNil(x.typ)
+		case token.LSS, token.LEQ, token.GTR, token.GEQ:
+			// spec: The ordering operators <, <=, >, and >= apply to operands that are ordered."
+			defined = isOrdered(x.typ)
+		default:
+			unreachable()
+		}
+		if !defined {
+			typ := x.typ
+			if x.isNil() {
+				typ = y.typ
+			}
+			err = check.sprintf("operator %s not defined for %s", op, typ)
+		}
+	} else {
+		err = check.sprintf("mismatched types %s and %s", x.typ, y.typ)
+	}
+
+	if err != "" {
+		check.errorf(x.pos(), "cannot compare %s %s %s (%s)", x.expr, op, y.expr, err)
+		x.mode = invalid
+		return
+	}
+
+	if x.mode == constant_ && y.mode == constant_ {
+		x.val = constant.MakeBool(constant.Compare(x.val, op, y.val))
+		// The operands are never materialized; no need to update
+		// their types.
+	} else {
+		x.mode = value
+		// The operands have now their final types, which at run-
+		// time will be materialized. Update the expression trees.
+		// If the current types are untyped, the materialized type
+		// is the respective default type.
+		check.updateExprType(x.expr, defaultType(x.typ), true)
+		check.updateExprType(y.expr, defaultType(y.typ), true)
+	}
+
+	// spec: "Comparison operators compare two operands and yield
+	//        an untyped boolean value."
+	x.typ = Typ[UntypedBool]
+}
+
+func (check *Checker) shift(x, y *operand, op token.Token) {
+	untypedx := isUntyped(x.typ)
+
+	// The lhs must be of integer type or be representable
+	// as an integer; otherwise the shift has no chance.
+	if !x.isInteger() {
+		check.invalidOp(x.pos(), "shifted operand %s must be integer", x)
+		x.mode = invalid
+		return
+	}
+
+	// spec: "The right operand in a shift expression must have unsigned
+	// integer type or be an untyped constant that can be converted to
+	// unsigned integer type."
+	switch {
+	case isInteger(y.typ) && isUnsigned(y.typ):
+		// nothing to do
+	case isUntyped(y.typ):
+		check.convertUntyped(y, Typ[UntypedInt])
+		if y.mode == invalid {
+			x.mode = invalid
+			return
+		}
+	default:
+		check.invalidOp(y.pos(), "shift count %s must be unsigned integer", y)
+		x.mode = invalid
+		return
+	}
+
+	if x.mode == constant_ {
+		if y.mode == constant_ {
+			// rhs must be an integer value
+			if !y.isInteger() {
+				check.invalidOp(y.pos(), "shift count %s must be unsigned integer", y)
+				x.mode = invalid
+				return
+			}
+			// rhs must be within reasonable bounds
+			const stupidShift = 1023 - 1 + 52 // so we can express smallestFloat64
+			s, ok := constant.Uint64Val(y.val)
+			if !ok || s > stupidShift {
+				check.invalidOp(y.pos(), "stupid shift count %s", y)
+				x.mode = invalid
+				return
+			}
+			// The lhs is representable as an integer but may not be an integer
+			// (e.g., 2.0, an untyped float) - this can only happen for untyped
+			// non-integer numeric constants. Correct the type so that the shift
+			// result is of integer type.
+			if !isInteger(x.typ) {
+				x.typ = Typ[UntypedInt]
+			}
+			x.val = constant.Shift(x.val, op, uint(s))
+			return
+		}
+
+		// non-constant shift with constant lhs
+		if untypedx {
+			// spec: "If the left operand of a non-constant shift
+			// expression is an untyped constant, the type of the
+			// constant is what it would be if the shift expression
+			// were replaced by its left operand alone.".
+			//
+			// Delay operand checking until we know the final type:
+			// The lhs expression must be in the untyped map, mark
+			// the entry as lhs shift operand.
+			info, found := check.untyped[x.expr]
+			assert(found)
+			info.isLhs = true
+			check.untyped[x.expr] = info
+			// keep x's type
+			x.mode = value
+			return
+		}
+	}
+
+	// constant rhs must be >= 0
+	if y.mode == constant_ && constant.Sign(y.val) < 0 {
+		check.invalidOp(y.pos(), "shift count %s must not be negative", y)
+	}
+
+	// non-constant shift - lhs must be an integer
+	if !isInteger(x.typ) {
+		check.invalidOp(x.pos(), "shifted operand %s must be integer", x)
+		x.mode = invalid
+		return
+	}
+
+	x.mode = value
+}
+
+var binaryOpPredicates = opPredicates{
+	token.ADD: func(typ Type) bool { return isNumeric(typ) || isString(typ) },
+	token.SUB: isNumeric,
+	token.MUL: isNumeric,
+	token.QUO: isNumeric,
+	token.REM: isInteger,
+
+	token.AND:     isInteger,
+	token.OR:      isInteger,
+	token.XOR:     isInteger,
+	token.AND_NOT: isInteger,
+
+	token.LAND: isBoolean,
+	token.LOR:  isBoolean,
+}
+
+// The binary expression e may be nil. It's passed in for better error messages only.
+func (check *Checker) binary(x *operand, e *ast.BinaryExpr, lhs, rhs ast.Expr, op token.Token) {
+	var y operand
+
+	check.expr(x, lhs)
+	check.expr(&y, rhs)
+
+	if x.mode == invalid {
+		return
+	}
+	if y.mode == invalid {
+		x.mode = invalid
+		x.expr = y.expr
+		return
+	}
+
+	if isShift(op) {
+		check.shift(x, &y, op)
+		return
+	}
+
+	check.convertUntyped(x, y.typ)
+	if x.mode == invalid {
+		return
+	}
+	check.convertUntyped(&y, x.typ)
+	if y.mode == invalid {
+		x.mode = invalid
+		return
+	}
+
+	if isComparison(op) {
+		check.comparison(x, &y, op)
+		return
+	}
+
+	if !Identical(x.typ, y.typ) {
+		// only report an error if we have valid types
+		// (otherwise we had an error reported elsewhere already)
+		if x.typ != Typ[Invalid] && y.typ != Typ[Invalid] {
+			check.invalidOp(x.pos(), "mismatched types %s and %s", x.typ, y.typ)
+		}
+		x.mode = invalid
+		return
+	}
+
+	if !check.op(binaryOpPredicates, x, op) {
+		x.mode = invalid
+		return
+	}
+
+	if (op == token.QUO || op == token.REM) && (x.mode == constant_ || isInteger(x.typ)) && y.mode == constant_ && constant.Sign(y.val) == 0 {
+		check.invalidOp(y.pos(), "division by zero")
+		x.mode = invalid
+		return
+	}
+
+	if x.mode == constant_ && y.mode == constant_ {
+		typ := x.typ.Underlying().(*Basic)
+		// force integer division of integer operands
+		if op == token.QUO && isInteger(typ) {
+			op = token.QUO_ASSIGN
+		}
+		x.val = constant.BinaryOp(x.val, op, y.val)
+		// Typed constants must be representable in
+		// their type after each constant operation.
+		if isTyped(typ) {
+			if e != nil {
+				x.expr = e // for better error message
+			}
+			check.representable(x, typ)
+		}
+		return
+	}
+
+	x.mode = value
+	// x.typ is unchanged
+}
+
+// index checks an index expression for validity.
+// If max >= 0, it is the upper bound for index.
+// If index is valid and the result i >= 0, then i is the constant value of index.
+func (check *Checker) index(index ast.Expr, max int64) (i int64, valid bool) {
+	var x operand
+	check.expr(&x, index)
+	if x.mode == invalid {
+		return
+	}
+
+	// an untyped constant must be representable as Int
+	check.convertUntyped(&x, Typ[Int])
+	if x.mode == invalid {
+		return
+	}
+
+	// the index must be of integer type
+	if !isInteger(x.typ) {
+		check.invalidArg(x.pos(), "index %s must be integer", &x)
+		return
+	}
+
+	// a constant index i must be in bounds
+	if x.mode == constant_ {
+		if constant.Sign(x.val) < 0 {
+			check.invalidArg(x.pos(), "index %s must not be negative", &x)
+			return
+		}
+		i, valid = constant.Int64Val(x.val)
+		if !valid || max >= 0 && i >= max {
+			check.errorf(x.pos(), "index %s is out of bounds", &x)
+			return i, false
+		}
+		// 0 <= i [ && i < max ]
+		return i, true
+	}
+
+	return -1, true
+}
+
+// indexElts checks the elements (elts) of an array or slice composite literal
+// against the literal's element type (typ), and the element indices against
+// the literal length if known (length >= 0). It returns the length of the
+// literal (maximum index value + 1).
+//
+func (check *Checker) indexedElts(elts []ast.Expr, typ Type, length int64) int64 {
+	visited := make(map[int64]bool, len(elts))
+	var index, max int64
+	for _, e := range elts {
+		// determine and check index
+		validIndex := false
+		eval := e
+		if kv, _ := e.(*ast.KeyValueExpr); kv != nil {
+			if i, ok := check.index(kv.Key, length); ok {
+				if i >= 0 {
+					index = i
+					validIndex = true
+				} else {
+					check.errorf(e.Pos(), "index %s must be integer constant", kv.Key)
+				}
+			}
+			eval = kv.Value
+		} else if length >= 0 && index >= length {
+			check.errorf(e.Pos(), "index %d is out of bounds (>= %d)", index, length)
+		} else {
+			validIndex = true
+		}
+
+		// if we have a valid index, check for duplicate entries
+		if validIndex {
+			if visited[index] {
+				check.errorf(e.Pos(), "duplicate index %d in array or slice literal", index)
+			}
+			visited[index] = true
+		}
+		index++
+		if index > max {
+			max = index
+		}
+
+		// check element against composite literal element type
+		var x operand
+		check.exprWithHint(&x, eval, typ)
+		if !check.assignment(&x, typ) && x.mode != invalid {
+			check.errorf(x.pos(), "cannot use %s as %s value in array or slice literal", &x, typ)
+		}
+	}
+	return max
+}
+
+// exprKind describes the kind of an expression; the kind
+// determines if an expression is valid in 'statement context'.
+type exprKind int
+
+const (
+	conversion exprKind = iota
+	expression
+	statement
+)
+
+// rawExpr typechecks expression e and initializes x with the expression
+// value or type. If an error occurred, x.mode is set to invalid.
+// If hint != nil, it is the type of a composite literal element.
+//
+func (check *Checker) rawExpr(x *operand, e ast.Expr, hint Type) exprKind {
+	if trace {
+		check.trace(e.Pos(), "%s", e)
+		check.indent++
+		defer func() {
+			check.indent--
+			check.trace(e.Pos(), "=> %s", x)
+		}()
+	}
+
+	kind := check.exprInternal(x, e, hint)
+
+	// convert x into a user-friendly set of values
+	// TODO(gri) this code can be simplified
+	var typ Type
+	var val constant.Value
+	switch x.mode {
+	case invalid:
+		typ = Typ[Invalid]
+	case novalue:
+		typ = (*Tuple)(nil)
+	case constant_:
+		typ = x.typ
+		val = x.val
+	default:
+		typ = x.typ
+	}
+	assert(x.expr != nil && typ != nil)
+
+	if isUntyped(typ) {
+		// delay type and value recording until we know the type
+		// or until the end of type checking
+		check.rememberUntyped(x.expr, false, x.mode, typ.(*Basic), val)
+	} else {
+		check.recordTypeAndValue(e, x.mode, typ, val)
+	}
+
+	return kind
+}
+
+// exprInternal contains the core of type checking of expressions.
+// Must only be called by rawExpr.
+//
+func (check *Checker) exprInternal(x *operand, e ast.Expr, hint Type) exprKind {
+	// make sure x has a valid state in case of bailout
+	// (was issue 5770)
+	x.mode = invalid
+	x.typ = Typ[Invalid]
+
+	switch e := e.(type) {
+	case *ast.BadExpr:
+		goto Error // error was reported before
+
+	case *ast.Ident:
+		check.ident(x, e, nil, nil)
+
+	case *ast.Ellipsis:
+		// ellipses are handled explicitly where they are legal
+		// (array composite literals and parameter lists)
+		check.error(e.Pos(), "invalid use of '...'")
+		goto Error
+
+	case *ast.BasicLit:
+		x.setConst(e.Kind, e.Value)
+		if x.mode == invalid {
+			check.invalidAST(e.Pos(), "invalid literal %v", e.Value)
+			goto Error
+		}
+
+	case *ast.FuncLit:
+		if sig, ok := check.typ(e.Type).(*Signature); ok {
+			// Anonymous functions are considered part of the
+			// init expression/func declaration which contains
+			// them: use existing package-level declaration info.
+			check.funcBody(check.decl, "", sig, e.Body)
+			x.mode = value
+			x.typ = sig
+		} else {
+			check.invalidAST(e.Pos(), "invalid function literal %s", e)
+			goto Error
+		}
+
+	case *ast.CompositeLit:
+		typ := hint
+		openArray := false
+		if e.Type != nil {
+			// [...]T array types may only appear with composite literals.
+			// Check for them here so we don't have to handle ... in general.
+			typ = nil
+			if atyp, _ := e.Type.(*ast.ArrayType); atyp != nil && atyp.Len != nil {
+				if ellip, _ := atyp.Len.(*ast.Ellipsis); ellip != nil && ellip.Elt == nil {
+					// We have an "open" [...]T array type.
+					// Create a new ArrayType with unknown length (-1)
+					// and finish setting it up after analyzing the literal.
+					typ = &Array{len: -1, elem: check.typ(atyp.Elt)}
+					openArray = true
+				}
+			}
+			if typ == nil {
+				typ = check.typ(e.Type)
+			}
+		}
+		if typ == nil {
+			// TODO(gri) provide better error messages depending on context
+			check.error(e.Pos(), "missing type in composite literal")
+			goto Error
+		}
+
+		switch typ, _ := deref(typ); utyp := typ.Underlying().(type) {
+		case *Struct:
+			if len(e.Elts) == 0 {
+				break
+			}
+			fields := utyp.fields
+			if _, ok := e.Elts[0].(*ast.KeyValueExpr); ok {
+				// all elements must have keys
+				visited := make([]bool, len(fields))
+				for _, e := range e.Elts {
+					kv, _ := e.(*ast.KeyValueExpr)
+					if kv == nil {
+						check.error(e.Pos(), "mixture of field:value and value elements in struct literal")
+						continue
+					}
+					key, _ := kv.Key.(*ast.Ident)
+					if key == nil {
+						check.errorf(kv.Pos(), "invalid field name %s in struct literal", kv.Key)
+						continue
+					}
+					i := fieldIndex(utyp.fields, check.pkg, key.Name)
+					if i < 0 {
+						check.errorf(kv.Pos(), "unknown field %s in struct literal", key.Name)
+						continue
+					}
+					fld := fields[i]
+					check.recordUse(key, fld)
+					// 0 <= i < len(fields)
+					if visited[i] {
+						check.errorf(kv.Pos(), "duplicate field name %s in struct literal", key.Name)
+						continue
+					}
+					visited[i] = true
+					check.expr(x, kv.Value)
+					etyp := fld.typ
+					if !check.assignment(x, etyp) {
+						if x.mode != invalid {
+							check.errorf(x.pos(), "cannot use %s as %s value in struct literal", x, etyp)
+						}
+						continue
+					}
+				}
+			} else {
+				// no element must have a key
+				for i, e := range e.Elts {
+					if kv, _ := e.(*ast.KeyValueExpr); kv != nil {
+						check.error(kv.Pos(), "mixture of field:value and value elements in struct literal")
+						continue
+					}
+					check.expr(x, e)
+					if i >= len(fields) {
+						check.error(x.pos(), "too many values in struct literal")
+						break // cannot continue
+					}
+					// i < len(fields)
+					fld := fields[i]
+					if !fld.Exported() && fld.pkg != check.pkg {
+						check.errorf(x.pos(), "implicit assignment to unexported field %s in %s literal", fld.name, typ)
+						continue
+					}
+					etyp := fld.typ
+					if !check.assignment(x, etyp) {
+						if x.mode != invalid {
+							check.errorf(x.pos(), "cannot use %s as %s value in struct literal", x, etyp)
+						}
+						continue
+					}
+				}
+				if len(e.Elts) < len(fields) {
+					check.error(e.Rbrace, "too few values in struct literal")
+					// ok to continue
+				}
+			}
+
+		case *Array:
+			n := check.indexedElts(e.Elts, utyp.elem, utyp.len)
+			// if we have an "open" [...]T array, set the length now that we know it
+			if openArray {
+				utyp.len = n
+			}
+
+		case *Slice:
+			check.indexedElts(e.Elts, utyp.elem, -1)
+
+		case *Map:
+			visited := make(map[interface{}][]Type, len(e.Elts))
+			for _, e := range e.Elts {
+				kv, _ := e.(*ast.KeyValueExpr)
+				if kv == nil {
+					check.error(e.Pos(), "missing key in map literal")
+					continue
+				}
+				check.exprWithHint(x, kv.Key, utyp.key)
+				if !check.assignment(x, utyp.key) {
+					if x.mode != invalid {
+						check.errorf(x.pos(), "cannot use %s as %s key in map literal", x, utyp.key)
+					}
+					continue
+				}
+				if x.mode == constant_ {
+					duplicate := false
+					// if the key is of interface type, the type is also significant when checking for duplicates
+					if _, ok := utyp.key.Underlying().(*Interface); ok {
+						for _, vtyp := range visited[x.val] {
+							if Identical(vtyp, x.typ) {
+								duplicate = true
+								break
+							}
+						}
+						visited[x.val] = append(visited[x.val], x.typ)
+					} else {
+						_, duplicate = visited[x.val]
+						visited[x.val] = nil
+					}
+					if duplicate {
+						check.errorf(x.pos(), "duplicate key %s in map literal", x.val)
+						continue
+					}
+				}
+				check.exprWithHint(x, kv.Value, utyp.elem)
+				if !check.assignment(x, utyp.elem) {
+					if x.mode != invalid {
+						check.errorf(x.pos(), "cannot use %s as %s value in map literal", x, utyp.elem)
+					}
+					continue
+				}
+			}
+
+		default:
+			// if utyp is invalid, an error was reported before
+			if utyp != Typ[Invalid] {
+				check.errorf(e.Pos(), "invalid composite literal type %s", typ)
+				goto Error
+			}
+		}
+
+		x.mode = value
+		x.typ = typ
+
+	case *ast.ParenExpr:
+		kind := check.rawExpr(x, e.X, nil)
+		x.expr = e
+		return kind
+
+	case *ast.SelectorExpr:
+		check.selector(x, e)
+
+	case *ast.IndexExpr:
+		check.expr(x, e.X)
+		if x.mode == invalid {
+			goto Error
+		}
+
+		valid := false
+		length := int64(-1) // valid if >= 0
+		switch typ := x.typ.Underlying().(type) {
+		case *Basic:
+			if isString(typ) {
+				valid = true
+				if x.mode == constant_ {
+					length = int64(len(constant.StringVal(x.val)))
+				}
+				// an indexed string always yields a byte value
+				// (not a constant) even if the string and the
+				// index are constant
+				x.mode = value
+				x.typ = universeByte // use 'byte' name
+			}
+
+		case *Array:
+			valid = true
+			length = typ.len
+			if x.mode != variable {
+				x.mode = value
+			}
+			x.typ = typ.elem
+
+		case *Pointer:
+			if typ, _ := typ.base.Underlying().(*Array); typ != nil {
+				valid = true
+				length = typ.len
+				x.mode = variable
+				x.typ = typ.elem
+			}
+
+		case *Slice:
+			valid = true
+			x.mode = variable
+			x.typ = typ.elem
+
+		case *Map:
+			var key operand
+			check.expr(&key, e.Index)
+			if !check.assignment(&key, typ.key) {
+				if key.mode != invalid {
+					check.invalidOp(key.pos(), "cannot use %s as map index of type %s", &key, typ.key)
+				}
+				goto Error
+			}
+			x.mode = mapindex
+			x.typ = typ.elem
+			x.expr = e
+			return expression
+		}
+
+		if !valid {
+			check.invalidOp(x.pos(), "cannot index %s", x)
+			goto Error
+		}
+
+		if e.Index == nil {
+			check.invalidAST(e.Pos(), "missing index for %s", x)
+			goto Error
+		}
+
+		check.index(e.Index, length)
+		// ok to continue
+
+	case *ast.SliceExpr:
+		check.expr(x, e.X)
+		if x.mode == invalid {
+			goto Error
+		}
+
+		valid := false
+		length := int64(-1) // valid if >= 0
+		switch typ := x.typ.Underlying().(type) {
+		case *Basic:
+			if isString(typ) {
+				if slice3(e) {
+					check.invalidOp(x.pos(), "3-index slice of string")
+					goto Error
+				}
+				valid = true
+				if x.mode == constant_ {
+					length = int64(len(constant.StringVal(x.val)))
+				}
+				// spec: "For untyped string operands the result
+				// is a non-constant value of type string."
+				if typ.kind == UntypedString {
+					x.typ = Typ[String]
+				}
+			}
+
+		case *Array:
+			valid = true
+			length = typ.len
+			if x.mode != variable {
+				check.invalidOp(x.pos(), "cannot slice %s (value not addressable)", x)
+				goto Error
+			}
+			x.typ = &Slice{elem: typ.elem}
+
+		case *Pointer:
+			if typ, _ := typ.base.Underlying().(*Array); typ != nil {
+				valid = true
+				length = typ.len
+				x.typ = &Slice{elem: typ.elem}
+			}
+
+		case *Slice:
+			valid = true
+			// x.typ doesn't change
+		}
+
+		if !valid {
+			check.invalidOp(x.pos(), "cannot slice %s", x)
+			goto Error
+		}
+
+		x.mode = value
+
+		// spec: "Only the first index may be omitted; it defaults to 0."
+		if slice3(e) && (e.High == nil || sliceMax(e) == nil) {
+			check.error(e.Rbrack, "2nd and 3rd index required in 3-index slice")
+			goto Error
+		}
+
+		// check indices
+		var ind [3]int64
+		for i, expr := range []ast.Expr{e.Low, e.High, sliceMax(e)} {
+			x := int64(-1)
+			switch {
+			case expr != nil:
+				// The "capacity" is only known statically for strings, arrays,
+				// and pointers to arrays, and it is the same as the length for
+				// those types.
+				max := int64(-1)
+				if length >= 0 {
+					max = length + 1
+				}
+				if t, ok := check.index(expr, max); ok && t >= 0 {
+					x = t
+				}
+			case i == 0:
+				// default is 0 for the first index
+				x = 0
+			case length >= 0:
+				// default is length (== capacity) otherwise
+				x = length
+			}
+			ind[i] = x
+		}
+
+		// constant indices must be in range
+		// (check.index already checks that existing indices >= 0)
+	L:
+		for i, x := range ind[:len(ind)-1] {
+			if x > 0 {
+				for _, y := range ind[i+1:] {
+					if y >= 0 && x > y {
+						check.errorf(e.Rbrack, "invalid slice indices: %d > %d", x, y)
+						break L // only report one error, ok to continue
+					}
+				}
+			}
+		}
+
+	case *ast.TypeAssertExpr:
+		check.expr(x, e.X)
+		if x.mode == invalid {
+			goto Error
+		}
+		xtyp, _ := x.typ.Underlying().(*Interface)
+		if xtyp == nil {
+			check.invalidOp(x.pos(), "%s is not an interface", x)
+			goto Error
+		}
+		// x.(type) expressions are handled explicitly in type switches
+		if e.Type == nil {
+			check.invalidAST(e.Pos(), "use of .(type) outside type switch")
+			goto Error
+		}
+		T := check.typ(e.Type)
+		if T == Typ[Invalid] {
+			goto Error
+		}
+		check.typeAssertion(x.pos(), x, xtyp, T)
+		x.mode = commaok
+		x.typ = T
+
+	case *ast.CallExpr:
+		return check.call(x, e)
+
+	case *ast.StarExpr:
+		check.exprOrType(x, e.X)
+		switch x.mode {
+		case invalid:
+			goto Error
+		case typexpr:
+			x.typ = &Pointer{base: x.typ}
+		default:
+			if typ, ok := x.typ.Underlying().(*Pointer); ok {
+				x.mode = variable
+				x.typ = typ.base
+			} else {
+				check.invalidOp(x.pos(), "cannot indirect %s", x)
+				goto Error
+			}
+		}
+
+	case *ast.UnaryExpr:
+		check.expr(x, e.X)
+		if x.mode == invalid {
+			goto Error
+		}
+		check.unary(x, e, e.Op)
+		if x.mode == invalid {
+			goto Error
+		}
+		if e.Op == token.ARROW {
+			x.expr = e
+			return statement // receive operations may appear in statement context
+		}
+
+	case *ast.BinaryExpr:
+		check.binary(x, e, e.X, e.Y, e.Op)
+		if x.mode == invalid {
+			goto Error
+		}
+
+	case *ast.KeyValueExpr:
+		// key:value expressions are handled in composite literals
+		check.invalidAST(e.Pos(), "no key:value expected")
+		goto Error
+
+	case *ast.ArrayType, *ast.StructType, *ast.FuncType,
+		*ast.InterfaceType, *ast.MapType, *ast.ChanType:
+		x.mode = typexpr
+		x.typ = check.typ(e)
+		// Note: rawExpr (caller of exprInternal) will call check.recordTypeAndValue
+		// even though check.typ has already called it. This is fine as both
+		// times the same expression and type are recorded. It is also not a
+		// performance issue because we only reach here for composite literal
+		// types, which are comparatively rare.
+
+	default:
+		panic(fmt.Sprintf("%s: unknown expression type %T", check.fset.Position(e.Pos()), e))
+	}
+
+	// everything went well
+	x.expr = e
+	return expression
+
+Error:
+	x.mode = invalid
+	x.expr = e
+	return statement // avoid follow-up errors
+}
+
+// typeAssertion checks that x.(T) is legal; xtyp must be the type of x.
+func (check *Checker) typeAssertion(pos token.Pos, x *operand, xtyp *Interface, T Type) {
+	method, wrongType := assertableTo(xtyp, T)
+	if method == nil {
+		return
+	}
+
+	var msg string
+	if wrongType {
+		msg = "wrong type for method"
+	} else {
+		msg = "missing method"
+	}
+	check.errorf(pos, "%s cannot have dynamic type %s (%s %s)", x, T, msg, method.name)
+}
+
+// expr typechecks expression e and initializes x with the expression value.
+// If an error occurred, x.mode is set to invalid.
+//
+func (check *Checker) expr(x *operand, e ast.Expr) {
+	check.rawExpr(x, e, nil)
+	var msg string
+	switch x.mode {
+	default:
+		return
+	case novalue:
+		msg = "used as value"
+	case builtin:
+		msg = "must be called"
+	case typexpr:
+		msg = "is not an expression"
+	}
+	check.errorf(x.pos(), "%s %s", x, msg)
+	x.mode = invalid
+}
+
+// exprWithHint typechecks expression e and initializes x with the expression value.
+// If an error occurred, x.mode is set to invalid.
+// If hint != nil, it is the type of a composite literal element.
+//
+func (check *Checker) exprWithHint(x *operand, e ast.Expr, hint Type) {
+	assert(hint != nil)
+	check.rawExpr(x, e, hint)
+	var msg string
+	switch x.mode {
+	default:
+		return
+	case novalue:
+		msg = "used as value"
+	case builtin:
+		msg = "must be called"
+	case typexpr:
+		msg = "is not an expression"
+	}
+	check.errorf(x.pos(), "%s %s", x, msg)
+	x.mode = invalid
+}
+
+// exprOrType typechecks expression or type e and initializes x with the expression value or type.
+// If an error occurred, x.mode is set to invalid.
+//
+func (check *Checker) exprOrType(x *operand, e ast.Expr) {
+	check.rawExpr(x, e, nil)
+	if x.mode == novalue {
+		check.errorf(x.pos(), "%s used as value or type", x)
+		x.mode = invalid
+	}
+}
diff --git a/src/go/types/exprstring.go b/src/go/types/exprstring.go
new file mode 100644
index 0000000..370bdf3
--- /dev/null
+++ b/src/go/types/exprstring.go
@@ -0,0 +1,220 @@
+// 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.
+
+// This file implements printing of expressions.
+
+package types
+
+import (
+	"bytes"
+	"go/ast"
+)
+
+// ExprString returns the (possibly simplified) string representation for x.
+func ExprString(x ast.Expr) string {
+	var buf bytes.Buffer
+	WriteExpr(&buf, x)
+	return buf.String()
+}
+
+// WriteExpr writes the (possibly simplified) string representation for x to buf.
+func WriteExpr(buf *bytes.Buffer, x ast.Expr) {
+	// The AST preserves source-level parentheses so there is
+	// no need to introduce them here to correct for different
+	// operator precedences. (This assumes that the AST was
+	// generated by a Go parser.)
+
+	switch x := x.(type) {
+	default:
+		buf.WriteString("(bad expr)") // nil, ast.BadExpr, ast.KeyValueExpr
+
+	case *ast.Ident:
+		buf.WriteString(x.Name)
+
+	case *ast.Ellipsis:
+		buf.WriteString("...")
+		if x.Elt != nil {
+			WriteExpr(buf, x.Elt)
+		}
+
+	case *ast.BasicLit:
+		buf.WriteString(x.Value)
+
+	case *ast.FuncLit:
+		buf.WriteByte('(')
+		WriteExpr(buf, x.Type)
+		buf.WriteString(" literal)") // simplified
+
+	case *ast.CompositeLit:
+		buf.WriteByte('(')
+		WriteExpr(buf, x.Type)
+		buf.WriteString(" literal)") // simplified
+
+	case *ast.ParenExpr:
+		buf.WriteByte('(')
+		WriteExpr(buf, x.X)
+		buf.WriteByte(')')
+
+	case *ast.SelectorExpr:
+		WriteExpr(buf, x.X)
+		buf.WriteByte('.')
+		buf.WriteString(x.Sel.Name)
+
+	case *ast.IndexExpr:
+		WriteExpr(buf, x.X)
+		buf.WriteByte('[')
+		WriteExpr(buf, x.Index)
+		buf.WriteByte(']')
+
+	case *ast.SliceExpr:
+		WriteExpr(buf, x.X)
+		buf.WriteByte('[')
+		if x.Low != nil {
+			WriteExpr(buf, x.Low)
+		}
+		buf.WriteByte(':')
+		if x.High != nil {
+			WriteExpr(buf, x.High)
+		}
+		if x.Slice3 {
+			buf.WriteByte(':')
+			if x.Max != nil {
+				WriteExpr(buf, x.Max)
+			}
+		}
+		buf.WriteByte(']')
+
+	case *ast.TypeAssertExpr:
+		WriteExpr(buf, x.X)
+		buf.WriteString(".(")
+		WriteExpr(buf, x.Type)
+		buf.WriteByte(')')
+
+	case *ast.CallExpr:
+		WriteExpr(buf, x.Fun)
+		buf.WriteByte('(')
+		for i, arg := range x.Args {
+			if i > 0 {
+				buf.WriteString(", ")
+			}
+			WriteExpr(buf, arg)
+		}
+		if x.Ellipsis.IsValid() {
+			buf.WriteString("...")
+		}
+		buf.WriteByte(')')
+
+	case *ast.StarExpr:
+		buf.WriteByte('*')
+		WriteExpr(buf, x.X)
+
+	case *ast.UnaryExpr:
+		buf.WriteString(x.Op.String())
+		WriteExpr(buf, x.X)
+
+	case *ast.BinaryExpr:
+		WriteExpr(buf, x.X)
+		buf.WriteByte(' ')
+		buf.WriteString(x.Op.String())
+		buf.WriteByte(' ')
+		WriteExpr(buf, x.Y)
+
+	case *ast.ArrayType:
+		buf.WriteByte('[')
+		if x.Len != nil {
+			WriteExpr(buf, x.Len)
+		}
+		buf.WriteByte(']')
+		WriteExpr(buf, x.Elt)
+
+	case *ast.StructType:
+		buf.WriteString("struct{")
+		writeFieldList(buf, x.Fields, "; ", false)
+		buf.WriteByte('}')
+
+	case *ast.FuncType:
+		buf.WriteString("func")
+		writeSigExpr(buf, x)
+
+	case *ast.InterfaceType:
+		buf.WriteString("interface{")
+		writeFieldList(buf, x.Methods, "; ", true)
+		buf.WriteByte('}')
+
+	case *ast.MapType:
+		buf.WriteString("map[")
+		WriteExpr(buf, x.Key)
+		buf.WriteByte(']')
+		WriteExpr(buf, x.Value)
+
+	case *ast.ChanType:
+		var s string
+		switch x.Dir {
+		case ast.SEND:
+			s = "chan<- "
+		case ast.RECV:
+			s = "<-chan "
+		default:
+			s = "chan "
+		}
+		buf.WriteString(s)
+		WriteExpr(buf, x.Value)
+	}
+}
+
+func writeSigExpr(buf *bytes.Buffer, sig *ast.FuncType) {
+	buf.WriteByte('(')
+	writeFieldList(buf, sig.Params, ", ", false)
+	buf.WriteByte(')')
+
+	res := sig.Results
+	n := res.NumFields()
+	if n == 0 {
+		// no result
+		return
+	}
+
+	buf.WriteByte(' ')
+	if n == 1 && len(res.List[0].Names) == 0 {
+		// single unnamed result
+		WriteExpr(buf, res.List[0].Type)
+		return
+	}
+
+	// multiple or named result(s)
+	buf.WriteByte('(')
+	writeFieldList(buf, res, ", ", false)
+	buf.WriteByte(')')
+}
+
+func writeFieldList(buf *bytes.Buffer, fields *ast.FieldList, sep string, iface bool) {
+	for i, f := range fields.List {
+		if i > 0 {
+			buf.WriteString(sep)
+		}
+
+		// field list names
+		for i, name := range f.Names {
+			if i > 0 {
+				buf.WriteString(", ")
+			}
+			buf.WriteString(name.Name)
+		}
+
+		// types of interface methods consist of signatures only
+		if sig, _ := f.Type.(*ast.FuncType); sig != nil && iface {
+			writeSigExpr(buf, sig)
+			continue
+		}
+
+		// named fields are separated with a blank from the field type
+		if len(f.Names) > 0 {
+			buf.WriteByte(' ')
+		}
+
+		WriteExpr(buf, f.Type)
+
+		// ignore tag
+	}
+}
diff --git a/src/go/types/exprstring_test.go b/src/go/types/exprstring_test.go
new file mode 100644
index 0000000..5110288
--- /dev/null
+++ b/src/go/types/exprstring_test.go
@@ -0,0 +1,94 @@
+// 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 types_test
+
+import (
+	"go/parser"
+	"testing"
+
+	. "go/types"
+)
+
+var testExprs = []testEntry{
+	// basic type literals
+	dup("x"),
+	dup("true"),
+	dup("42"),
+	dup("3.1415"),
+	dup("2.71828i"),
+	dup(`'a'`),
+	dup(`"foo"`),
+	dup("`bar`"),
+
+	// func and composite literals
+	{"func(){}", "(func() literal)"},
+	{"func(x int) complex128 {}", "(func(x int) complex128 literal)"},
+	{"[]int{1, 2, 3}", "([]int literal)"},
+
+	// non-type expressions
+	dup("(x)"),
+	dup("x.f"),
+	dup("a[i]"),
+
+	dup("s[:]"),
+	dup("s[i:]"),
+	dup("s[:j]"),
+	dup("s[i:j]"),
+	dup("s[:j:k]"),
+	dup("s[i:j:k]"),
+
+	dup("x.(T)"),
+
+	dup("x.([10]int)"),
+	dup("x.([...]int)"),
+
+	dup("x.(struct{})"),
+	dup("x.(struct{x int; y, z float32; E})"),
+
+	dup("x.(func())"),
+	dup("x.(func(x int))"),
+	dup("x.(func() int)"),
+	dup("x.(func(x, y int, z float32) (r int))"),
+	dup("x.(func(a, b, c int))"),
+	dup("x.(func(x ...T))"),
+
+	dup("x.(interface{})"),
+	dup("x.(interface{m(); n(x int); E})"),
+	dup("x.(interface{m(); n(x int) T; E; F})"),
+
+	dup("x.(map[K]V)"),
+
+	dup("x.(chan E)"),
+	dup("x.(<-chan E)"),
+	dup("x.(chan<- chan int)"),
+	dup("x.(chan<- <-chan int)"),
+	dup("x.(<-chan chan int)"),
+	dup("x.(chan (<-chan int))"),
+
+	dup("f()"),
+	dup("f(x)"),
+	dup("int(x)"),
+	dup("f(x, x + y)"),
+	dup("f(s...)"),
+	dup("f(a, s...)"),
+
+	dup("*x"),
+	dup("&x"),
+	dup("x + y"),
+	dup("x + y << (2 * s)"),
+}
+
+func TestExprString(t *testing.T) {
+	for _, test := range testExprs {
+		x, err := parser.ParseExpr(test.src)
+		if err != nil {
+			t.Errorf("%s: %s", test.src, err)
+			continue
+		}
+		if got := ExprString(x); got != test.str {
+			t.Errorf("%s: got %s, want %s", test.src, got, test.str)
+		}
+	}
+}
diff --git a/src/go/types/go11.go b/src/go/types/go11.go
new file mode 100644
index 0000000..cf41cab
--- /dev/null
+++ b/src/go/types/go11.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.
+
+// +build !go1.2
+
+package types
+
+import "go/ast"
+
+func slice3(x *ast.SliceExpr) bool {
+	return false
+}
+
+func sliceMax(x *ast.SliceExpr) ast.Expr {
+	return nil
+}
diff --git a/src/go/types/go12.go b/src/go/types/go12.go
new file mode 100644
index 0000000..2017442
--- /dev/null
+++ b/src/go/types/go12.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.
+
+// +build go1.2
+
+package types
+
+import "go/ast"
+
+func slice3(x *ast.SliceExpr) bool {
+	return x.Slice3
+}
+
+func sliceMax(x *ast.SliceExpr) ast.Expr {
+	return x.Max
+}
diff --git a/src/go/types/hilbert_test.go b/src/go/types/hilbert_test.go
new file mode 100644
index 0000000..cfd51b1
--- /dev/null
+++ b/src/go/types/hilbert_test.go
@@ -0,0 +1,234 @@
+// 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 types_test
+
+import (
+	"bytes"
+	"flag"
+	"fmt"
+	"go/ast"
+	"go/importer"
+	"go/parser"
+	"go/token"
+	"io/ioutil"
+	"testing"
+
+	. "go/types"
+)
+
+var (
+	H   = flag.Int("H", 5, "Hilbert matrix size")
+	out = flag.String("out", "", "write generated program to out")
+)
+
+func TestHilbert(t *testing.T) {
+	// generate source
+	src := program(*H, *out)
+	if *out != "" {
+		ioutil.WriteFile(*out, src, 0666)
+		return
+	}
+
+	// parse source
+	fset := token.NewFileSet()
+	f, err := parser.ParseFile(fset, "hilbert.go", src, 0)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// type-check file
+	DefPredeclaredTestFuncs() // define assert built-in
+	conf := Config{Importer: importer.Default()}
+	_, err = conf.Check(f.Name.Name, fset, []*ast.File{f}, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+}
+
+func program(n int, out string) []byte {
+	var g gen
+
+	g.p(`// WARNING: GENERATED FILE - DO NOT MODIFY MANUALLY!
+// (To generate, in go/types directory: go test -run=Hilbert -H=%d -out=%q)
+
+// This program tests arbitrary precision constant arithmetic
+// by generating the constant elements of a Hilbert matrix H,
+// its inverse I, and the product P = H*I. The product should
+// be the identity matrix.
+package main
+
+func main() {
+	if !ok {
+		printProduct()
+		return
+	}
+	println("PASS")
+}
+
+`, n, out)
+	g.hilbert(n)
+	g.inverse(n)
+	g.product(n)
+	g.verify(n)
+	g.printProduct(n)
+	g.binomials(2*n - 1)
+	g.factorials(2*n - 1)
+
+	return g.Bytes()
+}
+
+type gen struct {
+	bytes.Buffer
+}
+
+func (g *gen) p(format string, args ...interface{}) {
+	fmt.Fprintf(&g.Buffer, format, args...)
+}
+
+func (g *gen) hilbert(n int) {
+	g.p(`// Hilbert matrix, n = %d
+const (
+`, n)
+	for i := 0; i < n; i++ {
+		g.p("\t")
+		for j := 0; j < n; j++ {
+			if j > 0 {
+				g.p(", ")
+			}
+			g.p("h%d_%d", i, j)
+		}
+		if i == 0 {
+			g.p(" = ")
+			for j := 0; j < n; j++ {
+				if j > 0 {
+					g.p(", ")
+				}
+				g.p("1.0/(iota + %d)", j+1)
+			}
+		}
+		g.p("\n")
+	}
+	g.p(")\n\n")
+}
+
+func (g *gen) inverse(n int) {
+	g.p(`// Inverse Hilbert matrix
+const (
+`)
+	for i := 0; i < n; i++ {
+		for j := 0; j < n; j++ {
+			s := "+"
+			if (i+j)&1 != 0 {
+				s = "-"
+			}
+			g.p("\ti%d_%d = %s%d * b%d_%d * b%d_%d * b%d_%d * b%d_%d\n",
+				i, j, s, i+j+1, n+i, n-j-1, n+j, n-i-1, i+j, i, i+j, i)
+		}
+		g.p("\n")
+	}
+	g.p(")\n\n")
+}
+
+func (g *gen) product(n int) {
+	g.p(`// Product matrix
+const (
+`)
+	for i := 0; i < n; i++ {
+		for j := 0; j < n; j++ {
+			g.p("\tp%d_%d = ", i, j)
+			for k := 0; k < n; k++ {
+				if k > 0 {
+					g.p(" + ")
+				}
+				g.p("h%d_%d*i%d_%d", i, k, k, j)
+			}
+			g.p("\n")
+		}
+		g.p("\n")
+	}
+	g.p(")\n\n")
+}
+
+func (g *gen) verify(n int) {
+	g.p(`// Verify that product is the identity matrix
+const ok =
+`)
+	for i := 0; i < n; i++ {
+		for j := 0; j < n; j++ {
+			if j == 0 {
+				g.p("\t")
+			} else {
+				g.p(" && ")
+			}
+			v := 0
+			if i == j {
+				v = 1
+			}
+			g.p("p%d_%d == %d", i, j, v)
+		}
+		g.p(" &&\n")
+	}
+	g.p("\ttrue\n\n")
+
+	// verify ok at type-check time
+	if *out == "" {
+		g.p("const _ = assert(ok)\n\n")
+	}
+}
+
+func (g *gen) printProduct(n int) {
+	g.p("func printProduct() {\n")
+	for i := 0; i < n; i++ {
+		g.p("\tprintln(")
+		for j := 0; j < n; j++ {
+			if j > 0 {
+				g.p(", ")
+			}
+			g.p("p%d_%d", i, j)
+		}
+		g.p(")\n")
+	}
+	g.p("}\n\n")
+}
+
+func (g *gen) mulRange(a, b int) {
+	if a > b {
+		g.p("1")
+		return
+	}
+	for i := a; i <= b; i++ {
+		if i > a {
+			g.p("*")
+		}
+		g.p("%d", i)
+	}
+}
+
+func (g *gen) binomials(n int) {
+	g.p(`// Binomials
+const (
+`)
+	for j := 0; j <= n; j++ {
+		if j > 0 {
+			g.p("\n")
+		}
+		for k := 0; k <= j; k++ {
+			g.p("\tb%d_%d = f%d / (f%d*f%d)\n", j, k, j, k, j-k)
+		}
+	}
+	g.p(")\n\n")
+}
+
+func (g *gen) factorials(n int) {
+	g.p(`// Factorials
+const (
+	f0 = 1
+	f1 = 1
+`)
+	for i := 2; i <= n; i++ {
+		g.p("\tf%d = f%d * %d\n", i, i-1, i)
+	}
+	g.p(")\n\n")
+}
diff --git a/src/go/types/initorder.go b/src/go/types/initorder.go
new file mode 100644
index 0000000..0fd567b
--- /dev/null
+++ b/src/go/types/initorder.go
@@ -0,0 +1,222 @@
+// 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 types
+
+import (
+	"container/heap"
+	"fmt"
+)
+
+// initOrder computes the Info.InitOrder for package variables.
+func (check *Checker) initOrder() {
+	// An InitOrder may already have been computed if a package is
+	// built from several calls to (*Checker).Files.  Clear it.
+	check.Info.InitOrder = check.Info.InitOrder[:0]
+
+	// compute the object dependency graph and
+	// initialize a priority queue with the list
+	// of graph nodes
+	pq := nodeQueue(dependencyGraph(check.objMap))
+	heap.Init(&pq)
+
+	const debug = false
+	if debug {
+		fmt.Printf("package %s: object dependency graph\n", check.pkg.Name())
+		for _, n := range pq {
+			for _, o := range n.out {
+				fmt.Printf("\t%s -> %s\n", n.obj.Name(), o.obj.Name())
+			}
+		}
+		fmt.Println()
+		fmt.Printf("package %s: initialization order\n", check.pkg.Name())
+	}
+
+	// determine initialization order by removing the highest priority node
+	// (the one with the fewest dependencies) and its edges from the graph,
+	// repeatedly, until there are no nodes left.
+	// In a valid Go program, those nodes always have zero dependencies (after
+	// removing all incoming dependencies), otherwise there are initialization
+	// cycles.
+	mark := 0
+	emitted := make(map[*declInfo]bool)
+	for len(pq) > 0 {
+		// get the next node
+		n := heap.Pop(&pq).(*objNode)
+
+		// if n still depends on other nodes, we have a cycle
+		if n.in > 0 {
+			mark++ // mark nodes using a different value each time
+			cycle := findPath(n, n, mark)
+			if i := valIndex(cycle); i >= 0 {
+				check.reportCycle(cycle, i)
+			}
+			// ok to continue, but the variable initialization order
+			// will be incorrect at this point since it assumes no
+			// cycle errors
+		}
+
+		// reduce dependency count of all dependent nodes
+		// and update priority queue
+		for _, out := range n.out {
+			out.in--
+			heap.Fix(&pq, out.index)
+		}
+
+		// record the init order for variables with initializers only
+		v, _ := n.obj.(*Var)
+		info := check.objMap[v]
+		if v == nil || !info.hasInitializer() {
+			continue
+		}
+
+		// n:1 variable declarations such as: a, b = f()
+		// introduce a node for each lhs variable (here: a, b);
+		// but they all have the same initializer - emit only
+		// one, for the first variable seen
+		if emitted[info] {
+			continue // initializer already emitted, if any
+		}
+		emitted[info] = true
+
+		infoLhs := info.lhs // possibly nil (see declInfo.lhs field comment)
+		if infoLhs == nil {
+			infoLhs = []*Var{v}
+		}
+		init := &Initializer{infoLhs, info.init}
+		check.Info.InitOrder = append(check.Info.InitOrder, init)
+
+		if debug {
+			fmt.Printf("\t%s\n", init)
+		}
+	}
+
+	if debug {
+		fmt.Println()
+	}
+}
+
+// findPath returns the (reversed) list of nodes z, ... c, b, a,
+// such that there is a path (list of edges) from a to z.
+// If there is no such path, the result is nil.
+// Nodes marked with the value mark are considered "visited";
+// unvisited nodes are marked during the graph search.
+func findPath(a, z *objNode, mark int) []*objNode {
+	if a.mark == mark {
+		return nil // node already seen
+	}
+	a.mark = mark
+
+	for _, n := range a.out {
+		if n == z {
+			return []*objNode{z}
+		}
+		if P := findPath(n, z, mark); P != nil {
+			return append(P, n)
+		}
+	}
+
+	return nil
+}
+
+// valIndex returns the index of the first constant or variable in a,
+// if any; or a value < 0.
+func valIndex(a []*objNode) int {
+	for i, n := range a {
+		switch n.obj.(type) {
+		case *Const, *Var:
+			return i
+		}
+	}
+	return -1
+}
+
+// reportCycle reports an error for the cycle starting at i.
+func (check *Checker) reportCycle(cycle []*objNode, i int) {
+	obj := cycle[i].obj
+	check.errorf(obj.Pos(), "initialization cycle for %s", obj.Name())
+	// print cycle
+	for _ = range cycle {
+		check.errorf(obj.Pos(), "\t%s refers to", obj.Name()) // secondary error, \t indented
+		i++
+		if i >= len(cycle) {
+			i = 0
+		}
+		obj = cycle[i].obj
+	}
+	check.errorf(obj.Pos(), "\t%s", obj.Name())
+}
+
+// An objNode represents a node in the object dependency graph.
+// Each node b in a.out represents an edge a->b indicating that
+// b depends on a.
+// Nodes may be marked for cycle detection. A node n is marked
+// if n.mark corresponds to the current mark value.
+type objNode struct {
+	obj   Object     // object represented by this node
+	in    int        // number of nodes this node depends on
+	out   []*objNode // list of nodes that depend on this node
+	index int        // node index in list of nodes
+	mark  int        // for cycle detection
+}
+
+// dependencyGraph computes the transposed object dependency graph
+// from the given objMap. The transposed graph is returned as a list
+// of nodes; an edge d->n indicates that node n depends on node d.
+func dependencyGraph(objMap map[Object]*declInfo) []*objNode {
+	// M maps each object to its corresponding node
+	M := make(map[Object]*objNode, len(objMap))
+	for obj := range objMap {
+		M[obj] = &objNode{obj: obj}
+	}
+
+	// G is the graph of nodes n
+	G := make([]*objNode, len(M))
+	i := 0
+	for obj, n := range M {
+		deps := objMap[obj].deps
+		n.in = len(deps)
+		for d := range deps {
+			d := M[d]                // node n depends on node d
+			d.out = append(d.out, n) // add edge d->n
+		}
+
+		G[i] = n
+		n.index = i
+		i++
+	}
+
+	return G
+}
+
+// nodeQueue implements the container/heap interface;
+// a nodeQueue may be used as a priority queue.
+type nodeQueue []*objNode
+
+func (a nodeQueue) Len() int { return len(a) }
+
+func (a nodeQueue) Swap(i, j int) {
+	x, y := a[i], a[j]
+	a[i], a[j] = y, x
+	x.index, y.index = j, i
+}
+
+func (a nodeQueue) Less(i, j int) bool {
+	x, y := a[i], a[j]
+	// nodes are prioritized by number of incoming dependencies (1st key)
+	// and source order (2nd key)
+	return x.in < y.in || x.in == y.in && x.obj.order() < y.obj.order()
+}
+
+func (a *nodeQueue) Push(x interface{}) {
+	panic("unreachable")
+}
+
+func (a *nodeQueue) Pop() interface{} {
+	n := len(*a)
+	x := (*a)[n-1]
+	x.index = -1 // for safety
+	*a = (*a)[:n-1]
+	return x
+}
diff --git a/src/go/types/issues_test.go b/src/go/types/issues_test.go
new file mode 100644
index 0000000..672c78d
--- /dev/null
+++ b/src/go/types/issues_test.go
@@ -0,0 +1,206 @@
+// 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.
+
+// This file implements tests for various issues.
+
+package types_test
+
+import (
+	"fmt"
+	"go/ast"
+	"go/importer"
+	"go/parser"
+	"sort"
+	"strings"
+	"testing"
+
+	. "go/types"
+)
+
+func TestIssue5770(t *testing.T) {
+	src := `package p; type S struct{T}`
+	f, err := parser.ParseFile(fset, "", src, 0)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	conf := Config{Importer: importer.Default()}
+	_, err = conf.Check(f.Name.Name, fset, []*ast.File{f}, nil) // do not crash
+	want := "undeclared name: T"
+	if err == nil || !strings.Contains(err.Error(), want) {
+		t.Errorf("got: %v; want: %s", err, want)
+	}
+}
+
+func TestIssue5849(t *testing.T) {
+	src := `
+package p
+var (
+	s uint
+	_ = uint8(8)
+	_ = uint16(16) << s
+	_ = uint32(32 << s)
+	_ = uint64(64 << s + s)
+	_ = (interface{})("foo")
+	_ = (interface{})(nil)
+)`
+	f, err := parser.ParseFile(fset, "", src, 0)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	var conf Config
+	types := make(map[ast.Expr]TypeAndValue)
+	_, err = conf.Check(f.Name.Name, fset, []*ast.File{f}, &Info{Types: types})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	for x, tv := range types {
+		var want Type
+		switch x := x.(type) {
+		case *ast.BasicLit:
+			switch x.Value {
+			case `8`:
+				want = Typ[Uint8]
+			case `16`:
+				want = Typ[Uint16]
+			case `32`:
+				want = Typ[Uint32]
+			case `64`:
+				want = Typ[Uint] // because of "+ s", s is of type uint
+			case `"foo"`:
+				want = Typ[String]
+			}
+		case *ast.Ident:
+			if x.Name == "nil" {
+				want = Typ[UntypedNil]
+			}
+		}
+		if want != nil && !Identical(tv.Type, want) {
+			t.Errorf("got %s; want %s", tv.Type, want)
+		}
+	}
+}
+
+func TestIssue6413(t *testing.T) {
+	src := `
+package p
+func f() int {
+	defer f()
+	go f()
+	return 0
+}
+`
+	f, err := parser.ParseFile(fset, "", src, 0)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	var conf Config
+	types := make(map[ast.Expr]TypeAndValue)
+	_, err = conf.Check(f.Name.Name, fset, []*ast.File{f}, &Info{Types: types})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	want := Typ[Int]
+	n := 0
+	for x, tv := range types {
+		if _, ok := x.(*ast.CallExpr); ok {
+			if tv.Type != want {
+				t.Errorf("%s: got %s; want %s", fset.Position(x.Pos()), tv.Type, want)
+			}
+			n++
+		}
+	}
+
+	if n != 2 {
+		t.Errorf("got %d CallExprs; want 2", n)
+	}
+}
+
+func TestIssue7245(t *testing.T) {
+	src := `
+package p
+func (T) m() (res bool) { return }
+type T struct{} // receiver type after method declaration
+`
+	f, err := parser.ParseFile(fset, "", src, 0)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	var conf Config
+	defs := make(map[*ast.Ident]Object)
+	_, err = conf.Check(f.Name.Name, fset, []*ast.File{f}, &Info{Defs: defs})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	m := f.Decls[0].(*ast.FuncDecl)
+	res1 := defs[m.Name].(*Func).Type().(*Signature).Results().At(0)
+	res2 := defs[m.Type.Results.List[0].Names[0]].(*Var)
+
+	if res1 != res2 {
+		t.Errorf("got %s (%p) != %s (%p)", res1, res2, res1, res2)
+	}
+}
+
+// This tests that uses of existing vars on the LHS of an assignment
+// are Uses, not Defs; and also that the (illegal) use of a non-var on
+// the LHS of an assignment is a Use nonetheless.
+func TestIssue7827(t *testing.T) {
+	const src = `
+package p
+func _() {
+	const w = 1        // defs w
+        x, y := 2, 3       // defs x, y
+        w, x, z := 4, 5, 6 // uses w, x, defs z; error: cannot assign to w
+        _, _, _ = x, y, z  // uses x, y, z
+}
+`
+	const want = `L3 defs func p._()
+L4 defs const w untyped int
+L5 defs var x int
+L5 defs var y int
+L6 defs var z int
+L6 uses const w untyped int
+L6 uses var x int
+L7 uses var x int
+L7 uses var y int
+L7 uses var z int`
+
+	f, err := parser.ParseFile(fset, "", src, 0)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// don't abort at the first error
+	conf := Config{Error: func(err error) { t.Log(err) }}
+	defs := make(map[*ast.Ident]Object)
+	uses := make(map[*ast.Ident]Object)
+	_, err = conf.Check(f.Name.Name, fset, []*ast.File{f}, &Info{Defs: defs, Uses: uses})
+	if s := fmt.Sprint(err); !strings.HasSuffix(s, "cannot assign to w") {
+		t.Errorf("Check: unexpected error: %s", s)
+	}
+
+	var facts []string
+	for id, obj := range defs {
+		if obj != nil {
+			fact := fmt.Sprintf("L%d defs %s", fset.Position(id.Pos()).Line, obj)
+			facts = append(facts, fact)
+		}
+	}
+	for id, obj := range uses {
+		fact := fmt.Sprintf("L%d uses %s", fset.Position(id.Pos()).Line, obj)
+		facts = append(facts, fact)
+	}
+	sort.Strings(facts)
+
+	got := strings.Join(facts, "\n")
+	if got != want {
+		t.Errorf("Unexpected defs/uses\ngot:\n%s\nwant:\n%s", got, want)
+	}
+}
diff --git a/src/go/types/labels.go b/src/go/types/labels.go
new file mode 100644
index 0000000..7364d4d
--- /dev/null
+++ b/src/go/types/labels.go
@@ -0,0 +1,268 @@
+// 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 types
+
+import (
+	"go/ast"
+	"go/token"
+)
+
+// labels checks correct label use in body.
+func (check *Checker) labels(body *ast.BlockStmt) {
+	// set of all labels in this body
+	all := NewScope(nil, body.Pos(), body.End(), "label")
+
+	fwdJumps := check.blockBranches(all, nil, nil, body.List)
+
+	// If there are any forward jumps left, no label was found for
+	// the corresponding goto statements. Either those labels were
+	// never defined, or they are inside blocks and not reachable
+	// for the respective gotos.
+	for _, jmp := range fwdJumps {
+		var msg string
+		name := jmp.Label.Name
+		if alt := all.Lookup(name); alt != nil {
+			msg = "goto %s jumps into block"
+			alt.(*Label).used = true // avoid another error
+		} else {
+			msg = "label %s not declared"
+		}
+		check.errorf(jmp.Label.Pos(), msg, name)
+	}
+
+	// spec: "It is illegal to define a label that is never used."
+	for _, obj := range all.elems {
+		if lbl := obj.(*Label); !lbl.used {
+			check.softErrorf(lbl.pos, "label %s declared but not used", lbl.name)
+		}
+	}
+}
+
+// A block tracks label declarations in a block and its enclosing blocks.
+type block struct {
+	parent *block                      // enclosing block
+	lstmt  *ast.LabeledStmt            // labeled statement to which this block belongs, or nil
+	labels map[string]*ast.LabeledStmt // allocated lazily
+}
+
+// insert records a new label declaration for the current block.
+// The label must not have been declared before in any block.
+func (b *block) insert(s *ast.LabeledStmt) {
+	name := s.Label.Name
+	if debug {
+		assert(b.gotoTarget(name) == nil)
+	}
+	labels := b.labels
+	if labels == nil {
+		labels = make(map[string]*ast.LabeledStmt)
+		b.labels = labels
+	}
+	labels[name] = s
+}
+
+// gotoTarget returns the labeled statement in the current
+// or an enclosing block with the given label name, or nil.
+func (b *block) gotoTarget(name string) *ast.LabeledStmt {
+	for s := b; s != nil; s = s.parent {
+		if t := s.labels[name]; t != nil {
+			return t
+		}
+	}
+	return nil
+}
+
+// enclosingTarget returns the innermost enclosing labeled
+// statement with the given label name, or nil.
+func (b *block) enclosingTarget(name string) *ast.LabeledStmt {
+	for s := b; s != nil; s = s.parent {
+		if t := s.lstmt; t != nil && t.Label.Name == name {
+			return t
+		}
+	}
+	return nil
+}
+
+// blockBranches processes a block's statement list and returns the set of outgoing forward jumps.
+// all is the scope of all declared labels, parent the set of labels declared in the immediately
+// enclosing block, and lstmt is the labeled statement this block is associated with (or nil).
+func (check *Checker) blockBranches(all *Scope, parent *block, lstmt *ast.LabeledStmt, list []ast.Stmt) []*ast.BranchStmt {
+	b := &block{parent: parent, lstmt: lstmt}
+
+	var (
+		varDeclPos         token.Pos
+		fwdJumps, badJumps []*ast.BranchStmt
+	)
+
+	// All forward jumps jumping over a variable declaration are possibly
+	// invalid (they may still jump out of the block and be ok).
+	// recordVarDecl records them for the given position.
+	recordVarDecl := func(pos token.Pos) {
+		varDeclPos = pos
+		badJumps = append(badJumps[:0], fwdJumps...) // copy fwdJumps to badJumps
+	}
+
+	jumpsOverVarDecl := func(jmp *ast.BranchStmt) bool {
+		if varDeclPos.IsValid() {
+			for _, bad := range badJumps {
+				if jmp == bad {
+					return true
+				}
+			}
+		}
+		return false
+	}
+
+	blockBranches := func(lstmt *ast.LabeledStmt, list []ast.Stmt) {
+		// Unresolved forward jumps inside the nested block
+		// become forward jumps in the current block.
+		fwdJumps = append(fwdJumps, check.blockBranches(all, b, lstmt, list)...)
+	}
+
+	var stmtBranches func(ast.Stmt)
+	stmtBranches = func(s ast.Stmt) {
+		switch s := s.(type) {
+		case *ast.DeclStmt:
+			if d, _ := s.Decl.(*ast.GenDecl); d != nil && d.Tok == token.VAR {
+				recordVarDecl(d.Pos())
+			}
+
+		case *ast.LabeledStmt:
+			// declare non-blank label
+			if name := s.Label.Name; name != "_" {
+				lbl := NewLabel(s.Label.Pos(), check.pkg, name)
+				if alt := all.Insert(lbl); alt != nil {
+					check.softErrorf(lbl.pos, "label %s already declared", name)
+					check.reportAltDecl(alt)
+					// ok to continue
+				} else {
+					b.insert(s)
+					check.recordDef(s.Label, lbl)
+				}
+				// resolve matching forward jumps and remove them from fwdJumps
+				i := 0
+				for _, jmp := range fwdJumps {
+					if jmp.Label.Name == name {
+						// match
+						lbl.used = true
+						check.recordUse(jmp.Label, lbl)
+						if jumpsOverVarDecl(jmp) {
+							check.softErrorf(
+								jmp.Label.Pos(),
+								"goto %s jumps over variable declaration at line %d",
+								name,
+								check.fset.Position(varDeclPos).Line,
+							)
+							// ok to continue
+						}
+					} else {
+						// no match - record new forward jump
+						fwdJumps[i] = jmp
+						i++
+					}
+				}
+				fwdJumps = fwdJumps[:i]
+				lstmt = s
+			}
+			stmtBranches(s.Stmt)
+
+		case *ast.BranchStmt:
+			if s.Label == nil {
+				return // checked in 1st pass (check.stmt)
+			}
+
+			// determine and validate target
+			name := s.Label.Name
+			switch s.Tok {
+			case token.BREAK:
+				// spec: "If there is a label, it must be that of an enclosing
+				// "for", "switch", or "select" statement, and that is the one
+				// whose execution terminates."
+				valid := false
+				if t := b.enclosingTarget(name); t != nil {
+					switch t.Stmt.(type) {
+					case *ast.SwitchStmt, *ast.TypeSwitchStmt, *ast.SelectStmt, *ast.ForStmt, *ast.RangeStmt:
+						valid = true
+					}
+				}
+				if !valid {
+					check.errorf(s.Label.Pos(), "invalid break label %s", name)
+					return
+				}
+
+			case token.CONTINUE:
+				// spec: "If there is a label, it must be that of an enclosing
+				// "for" statement, and that is the one whose execution advances."
+				valid := false
+				if t := b.enclosingTarget(name); t != nil {
+					switch t.Stmt.(type) {
+					case *ast.ForStmt, *ast.RangeStmt:
+						valid = true
+					}
+				}
+				if !valid {
+					check.errorf(s.Label.Pos(), "invalid continue label %s", name)
+					return
+				}
+
+			case token.GOTO:
+				if b.gotoTarget(name) == nil {
+					// label may be declared later - add branch to forward jumps
+					fwdJumps = append(fwdJumps, s)
+					return
+				}
+
+			default:
+				check.invalidAST(s.Pos(), "branch statement: %s %s", s.Tok, name)
+				return
+			}
+
+			// record label use
+			obj := all.Lookup(name)
+			obj.(*Label).used = true
+			check.recordUse(s.Label, obj)
+
+		case *ast.AssignStmt:
+			if s.Tok == token.DEFINE {
+				recordVarDecl(s.Pos())
+			}
+
+		case *ast.BlockStmt:
+			blockBranches(lstmt, s.List)
+
+		case *ast.IfStmt:
+			stmtBranches(s.Body)
+			if s.Else != nil {
+				stmtBranches(s.Else)
+			}
+
+		case *ast.CaseClause:
+			blockBranches(nil, s.Body)
+
+		case *ast.SwitchStmt:
+			stmtBranches(s.Body)
+
+		case *ast.TypeSwitchStmt:
+			stmtBranches(s.Body)
+
+		case *ast.CommClause:
+			blockBranches(nil, s.Body)
+
+		case *ast.SelectStmt:
+			stmtBranches(s.Body)
+
+		case *ast.ForStmt:
+			stmtBranches(s.Body)
+
+		case *ast.RangeStmt:
+			stmtBranches(s.Body)
+		}
+	}
+
+	for _, s := range list {
+		stmtBranches(s)
+	}
+
+	return fwdJumps
+}
diff --git a/src/go/types/lookup.go b/src/go/types/lookup.go
new file mode 100644
index 0000000..3caca55
--- /dev/null
+++ b/src/go/types/lookup.go
@@ -0,0 +1,341 @@
+// 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.
+
+// This file implements various field and method lookup functions.
+
+package types
+
+// LookupFieldOrMethod looks up a field or method with given package and name
+// in T and returns the corresponding *Var or *Func, an index sequence, and a
+// bool indicating if there were any pointer indirections on the path to the
+// field or method. If addressable is set, T is the type of an addressable
+// variable (only matters for method lookups).
+//
+// The last index entry is the field or method index in the (possibly embedded)
+// type where the entry was found, either:
+//
+//	1) the list of declared methods of a named type; or
+//	2) the list of all methods (method set) of an interface type; or
+//	3) the list of fields of a struct type.
+//
+// The earlier index entries are the indices of the anonymous struct fields
+// traversed to get to the found entry, starting at depth 0.
+//
+// If no entry is found, a nil object is returned. In this case, the returned
+// index and indirect values have the following meaning:
+//
+//	- If index != nil, the index sequence points to an ambiguous entry
+//	(the same name appeared more than once at the same embedding level).
+//
+//	- If indirect is set, a method with a pointer receiver type was found
+//      but there was no pointer on the path from the actual receiver type to
+//	the method's formal receiver base type, nor was the receiver addressable.
+//
+func LookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (obj Object, index []int, indirect bool) {
+	// Methods cannot be associated to a named pointer type
+	// (spec: "The type denoted by T is called the receiver base type;
+	// it must not be a pointer or interface type and it must be declared
+	// in the same package as the method.").
+	// Thus, if we have a named pointer type, proceed with the underlying
+	// pointer type but discard the result if it is a method since we would
+	// not have found it for T (see also issue 8590).
+	if t, _ := T.(*Named); t != nil {
+		if p, _ := t.underlying.(*Pointer); p != nil {
+			obj, index, indirect = lookupFieldOrMethod(p, false, pkg, name)
+			if _, ok := obj.(*Func); ok {
+				return nil, nil, false
+			}
+			return
+		}
+	}
+
+	return lookupFieldOrMethod(T, addressable, pkg, name)
+}
+
+// TODO(gri) The named type consolidation and seen maps below must be
+//           indexed by unique keys for a given type. Verify that named
+//           types always have only one representation (even when imported
+//           indirectly via different packages.)
+
+func lookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (obj Object, index []int, indirect bool) {
+	// WARNING: The code in this function is extremely subtle - do not modify casually!
+	//          This function and NewMethodSet should be kept in sync.
+
+	if name == "_" {
+		return // blank fields/methods are never found
+	}
+
+	typ, isPtr := deref(T)
+	named, _ := typ.(*Named)
+
+	// *typ where typ is an interface has no methods.
+	if isPtr {
+		utyp := typ
+		if named != nil {
+			utyp = named.underlying
+		}
+		if _, ok := utyp.(*Interface); ok {
+			return
+		}
+	}
+
+	// Start with typ as single entry at shallowest depth.
+	// If typ is not a named type, insert a nil type instead.
+	current := []embeddedType{{named, nil, isPtr, false}}
+
+	// named types that we have seen already, allocated lazily
+	var seen map[*Named]bool
+
+	// search current depth
+	for len(current) > 0 {
+		var next []embeddedType // embedded types found at current depth
+
+		// look for (pkg, name) in all types at current depth
+		for _, e := range current {
+			// The very first time only, e.typ may be nil.
+			// In this case, we don't have a named type and
+			// we simply continue with the underlying type.
+			if e.typ != nil {
+				if seen[e.typ] {
+					// We have seen this type before, at a more shallow depth
+					// (note that multiples of this type at the current depth
+					// were consolidated before). The type at that depth shadows
+					// this same type at the current depth, so we can ignore
+					// this one.
+					continue
+				}
+				if seen == nil {
+					seen = make(map[*Named]bool)
+				}
+				seen[e.typ] = true
+
+				// look for a matching attached method
+				if i, m := lookupMethod(e.typ.methods, pkg, name); m != nil {
+					// potential match
+					assert(m.typ != nil)
+					index = concat(e.index, i)
+					if obj != nil || e.multiples {
+						return nil, index, false // collision
+					}
+					obj = m
+					indirect = e.indirect
+					continue // we can't have a matching field or interface method
+				}
+
+				// continue with underlying type
+				typ = e.typ.underlying
+			}
+
+			switch t := typ.(type) {
+			case *Struct:
+				// look for a matching field and collect embedded types
+				for i, f := range t.fields {
+					if f.sameId(pkg, name) {
+						assert(f.typ != nil)
+						index = concat(e.index, i)
+						if obj != nil || e.multiples {
+							return nil, index, false // collision
+						}
+						obj = f
+						indirect = e.indirect
+						continue // we can't have a matching interface method
+					}
+					// Collect embedded struct fields for searching the next
+					// lower depth, but only if we have not seen a match yet
+					// (if we have a match it is either the desired field or
+					// we have a name collision on the same depth; in either
+					// case we don't need to look further).
+					// Embedded fields are always of the form T or *T where
+					// T is a named type. If e.typ appeared multiple times at
+					// this depth, f.typ appears multiple times at the next
+					// depth.
+					if obj == nil && f.anonymous {
+						// Ignore embedded basic types - only user-defined
+						// named types can have methods or struct fields.
+						typ, isPtr := deref(f.typ)
+						if t, _ := typ.(*Named); t != nil {
+							next = append(next, embeddedType{t, concat(e.index, i), e.indirect || isPtr, e.multiples})
+						}
+					}
+				}
+
+			case *Interface:
+				// look for a matching method
+				// TODO(gri) t.allMethods is sorted - use binary search
+				if i, m := lookupMethod(t.allMethods, pkg, name); m != nil {
+					assert(m.typ != nil)
+					index = concat(e.index, i)
+					if obj != nil || e.multiples {
+						return nil, index, false // collision
+					}
+					obj = m
+					indirect = e.indirect
+				}
+			}
+		}
+
+		if obj != nil {
+			// found a potential match
+			// spec: "A method call x.m() is valid if the method set of (the type of) x
+			//        contains m and the argument list can be assigned to the parameter
+			//        list of m. If x is addressable and &x's method set contains m, x.m()
+			//        is shorthand for (&x).m()".
+			if f, _ := obj.(*Func); f != nil && ptrRecv(f) && !indirect && !addressable {
+				return nil, nil, true // pointer/addressable receiver required
+			}
+			return
+		}
+
+		current = consolidateMultiples(next)
+	}
+
+	return nil, nil, false // not found
+}
+
+// embeddedType represents an embedded named type
+type embeddedType struct {
+	typ       *Named // nil means use the outer typ variable instead
+	index     []int  // embedded field indices, starting with index at depth 0
+	indirect  bool   // if set, there was a pointer indirection on the path to this field
+	multiples bool   // if set, typ appears multiple times at this depth
+}
+
+// consolidateMultiples collects multiple list entries with the same type
+// into a single entry marked as containing multiples. The result is the
+// consolidated list.
+func consolidateMultiples(list []embeddedType) []embeddedType {
+	if len(list) <= 1 {
+		return list // at most one entry - nothing to do
+	}
+
+	n := 0                       // number of entries w/ unique type
+	prev := make(map[*Named]int) // index at which type was previously seen
+	for _, e := range list {
+		if i, found := prev[e.typ]; found {
+			list[i].multiples = true
+			// ignore this entry
+		} else {
+			prev[e.typ] = n
+			list[n] = e
+			n++
+		}
+	}
+	return list[:n]
+}
+
+// MissingMethod returns (nil, false) if V implements T, otherwise it
+// returns a missing method required by T and whether it is missing or
+// just has the wrong type.
+//
+// For non-interface types V, or if static is set, V implements T if all
+// methods of T are present in V. Otherwise (V is an interface and static
+// is not set), MissingMethod only checks that methods of T which are also
+// present in V have matching types (e.g., for a type assertion x.(T) where
+// x is of interface type V).
+//
+func MissingMethod(V Type, T *Interface, static bool) (method *Func, wrongType bool) {
+	// fast path for common case
+	if T.Empty() {
+		return
+	}
+
+	// TODO(gri) Consider using method sets here. Might be more efficient.
+
+	if ityp, _ := V.Underlying().(*Interface); ityp != nil {
+		// TODO(gri) allMethods is sorted - can do this more efficiently
+		for _, m := range T.allMethods {
+			_, obj := lookupMethod(ityp.allMethods, m.pkg, m.name)
+			switch {
+			case obj == nil:
+				if static {
+					return m, false
+				}
+			case !Identical(obj.Type(), m.typ):
+				return m, true
+			}
+		}
+		return
+	}
+
+	// A concrete type implements T if it implements all methods of T.
+	for _, m := range T.allMethods {
+		obj, _, _ := lookupFieldOrMethod(V, false, m.pkg, m.name)
+
+		f, _ := obj.(*Func)
+		if f == nil {
+			return m, false
+		}
+
+		if !Identical(f.typ, m.typ) {
+			return m, true
+		}
+	}
+
+	return
+}
+
+// assertableTo reports whether a value of type V can be asserted to have type T.
+// It returns (nil, false) as affirmative answer. Otherwise it returns a missing
+// method required by V and whether it is missing or just has the wrong type.
+func assertableTo(V *Interface, T Type) (method *Func, wrongType bool) {
+	// no static check is required if T is an interface
+	// spec: "If T is an interface type, x.(T) asserts that the
+	//        dynamic type of x implements the interface T."
+	if _, ok := T.Underlying().(*Interface); ok && !strict {
+		return
+	}
+	return MissingMethod(T, V, false)
+}
+
+// deref dereferences typ if it is a *Pointer and returns its base and true.
+// Otherwise it returns (typ, false).
+func deref(typ Type) (Type, bool) {
+	if p, _ := typ.(*Pointer); p != nil {
+		return p.base, true
+	}
+	return typ, false
+}
+
+// derefStructPtr dereferences typ if it is a (named or unnamed) pointer to a
+// (named or unnamed) struct and returns its base. Otherwise it returns typ.
+func derefStructPtr(typ Type) Type {
+	if p, _ := typ.Underlying().(*Pointer); p != nil {
+		if _, ok := p.base.Underlying().(*Struct); ok {
+			return p.base
+		}
+	}
+	return typ
+}
+
+// concat returns the result of concatenating list and i.
+// The result does not share its underlying array with list.
+func concat(list []int, i int) []int {
+	var t []int
+	t = append(t, list...)
+	return append(t, i)
+}
+
+// fieldIndex returns the index for the field with matching package and name, or a value < 0.
+func fieldIndex(fields []*Var, pkg *Package, name string) int {
+	if name != "_" {
+		for i, f := range fields {
+			if f.sameId(pkg, name) {
+				return i
+			}
+		}
+	}
+	return -1
+}
+
+// lookupMethod returns the index of and method with matching package and name, or (-1, nil).
+func lookupMethod(methods []*Func, pkg *Package, name string) (int, *Func) {
+	if name != "_" {
+		for i, m := range methods {
+			if m.sameId(pkg, name) {
+				return i, m
+			}
+		}
+	}
+	return -1, nil
+}
diff --git a/src/go/types/methodset.go b/src/go/types/methodset.go
new file mode 100644
index 0000000..b27f2da
--- /dev/null
+++ b/src/go/types/methodset.go
@@ -0,0 +1,268 @@
+// 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.
+
+// This file implements method sets.
+
+package types
+
+import (
+	"bytes"
+	"fmt"
+	"sort"
+)
+
+// A MethodSet is an ordered set of concrete or abstract (interface) methods;
+// a method is a MethodVal selection, and they are ordered by ascending m.Obj().Id().
+// The zero value for a MethodSet is a ready-to-use empty method set.
+type MethodSet struct {
+	list []*Selection
+}
+
+func (s *MethodSet) String() string {
+	if s.Len() == 0 {
+		return "MethodSet {}"
+	}
+
+	var buf bytes.Buffer
+	fmt.Fprintln(&buf, "MethodSet {")
+	for _, f := range s.list {
+		fmt.Fprintf(&buf, "\t%s\n", f)
+	}
+	fmt.Fprintln(&buf, "}")
+	return buf.String()
+}
+
+// Len returns the number of methods in s.
+func (s *MethodSet) Len() int { return len(s.list) }
+
+// At returns the i'th method in s for 0 <= i < s.Len().
+func (s *MethodSet) At(i int) *Selection { return s.list[i] }
+
+// Lookup returns the method with matching package and name, or nil if not found.
+func (s *MethodSet) Lookup(pkg *Package, name string) *Selection {
+	if s.Len() == 0 {
+		return nil
+	}
+
+	key := Id(pkg, name)
+	i := sort.Search(len(s.list), func(i int) bool {
+		m := s.list[i]
+		return m.obj.Id() >= key
+	})
+	if i < len(s.list) {
+		m := s.list[i]
+		if m.obj.Id() == key {
+			return m
+		}
+	}
+	return nil
+}
+
+// Shared empty method set.
+var emptyMethodSet MethodSet
+
+// NewMethodSet returns the method set for the given type T.
+// It always returns a non-nil method set, even if it is empty.
+func NewMethodSet(T Type) *MethodSet {
+	// WARNING: The code in this function is extremely subtle - do not modify casually!
+	//          This function and lookupFieldOrMethod should be kept in sync.
+
+	// method set up to the current depth, allocated lazily
+	var base methodSet
+
+	typ, isPtr := deref(T)
+	named, _ := typ.(*Named)
+
+	// *typ where typ is an interface has no methods.
+	if isPtr {
+		utyp := typ
+		if named != nil {
+			utyp = named.underlying
+		}
+		if _, ok := utyp.(*Interface); ok {
+			return &emptyMethodSet
+		}
+	}
+
+	// Start with typ as single entry at shallowest depth.
+	// If typ is not a named type, insert a nil type instead.
+	current := []embeddedType{{named, nil, isPtr, false}}
+
+	// named types that we have seen already, allocated lazily
+	var seen map[*Named]bool
+
+	// collect methods at current depth
+	for len(current) > 0 {
+		var next []embeddedType // embedded types found at current depth
+
+		// field and method sets at current depth, allocated lazily
+		var fset fieldSet
+		var mset methodSet
+
+		for _, e := range current {
+			// The very first time only, e.typ may be nil.
+			// In this case, we don't have a named type and
+			// we simply continue with the underlying type.
+			if e.typ != nil {
+				if seen[e.typ] {
+					// We have seen this type before, at a more shallow depth
+					// (note that multiples of this type at the current depth
+					// were consolidated before). The type at that depth shadows
+					// this same type at the current depth, so we can ignore
+					// this one.
+					continue
+				}
+				if seen == nil {
+					seen = make(map[*Named]bool)
+				}
+				seen[e.typ] = true
+
+				mset = mset.add(e.typ.methods, e.index, e.indirect, e.multiples)
+
+				// continue with underlying type
+				typ = e.typ.underlying
+			}
+
+			switch t := typ.(type) {
+			case *Struct:
+				for i, f := range t.fields {
+					fset = fset.add(f, e.multiples)
+
+					// Embedded fields are always of the form T or *T where
+					// T is a named type. If typ appeared multiple times at
+					// this depth, f.Type appears multiple times at the next
+					// depth.
+					if f.anonymous {
+						// Ignore embedded basic types - only user-defined
+						// named types can have methods or struct fields.
+						typ, isPtr := deref(f.typ)
+						if t, _ := typ.(*Named); t != nil {
+							next = append(next, embeddedType{t, concat(e.index, i), e.indirect || isPtr, e.multiples})
+						}
+					}
+				}
+
+			case *Interface:
+				mset = mset.add(t.allMethods, e.index, true, e.multiples)
+			}
+		}
+
+		// Add methods and collisions at this depth to base if no entries with matching
+		// names exist already.
+		for k, m := range mset {
+			if _, found := base[k]; !found {
+				// Fields collide with methods of the same name at this depth.
+				if _, found := fset[k]; found {
+					m = nil // collision
+				}
+				if base == nil {
+					base = make(methodSet)
+				}
+				base[k] = m
+			}
+		}
+
+		// Multiple fields with matching names collide at this depth and shadow all
+		// entries further down; add them as collisions to base if no entries with
+		// matching names exist already.
+		for k, f := range fset {
+			if f == nil {
+				if _, found := base[k]; !found {
+					if base == nil {
+						base = make(methodSet)
+					}
+					base[k] = nil // collision
+				}
+			}
+		}
+
+		current = consolidateMultiples(next)
+	}
+
+	if len(base) == 0 {
+		return &emptyMethodSet
+	}
+
+	// collect methods
+	var list []*Selection
+	for _, m := range base {
+		if m != nil {
+			m.recv = T
+			list = append(list, m)
+		}
+	}
+	sort.Sort(byUniqueName(list))
+	return &MethodSet{list}
+}
+
+// A fieldSet is a set of fields and name collisions.
+// A collision indicates that multiple fields with the
+// same unique id appeared.
+type fieldSet map[string]*Var // a nil entry indicates a name collision
+
+// Add adds field f to the field set s.
+// If multiples is set, f appears multiple times
+// and is treated as a collision.
+func (s fieldSet) add(f *Var, multiples bool) fieldSet {
+	if s == nil {
+		s = make(fieldSet)
+	}
+	key := f.Id()
+	// if f is not in the set, add it
+	if !multiples {
+		if _, found := s[key]; !found {
+			s[key] = f
+			return s
+		}
+	}
+	s[key] = nil // collision
+	return s
+}
+
+// A methodSet is a set of methods and name collisions.
+// A collision indicates that multiple methods with the
+// same unique id appeared.
+type methodSet map[string]*Selection // a nil entry indicates a name collision
+
+// Add adds all functions in list to the method set s.
+// If multiples is set, every function in list appears multiple times
+// and is treated as a collision.
+func (s methodSet) add(list []*Func, index []int, indirect bool, multiples bool) methodSet {
+	if len(list) == 0 {
+		return s
+	}
+	if s == nil {
+		s = make(methodSet)
+	}
+	for i, f := range list {
+		key := f.Id()
+		// if f is not in the set, add it
+		if !multiples {
+			// TODO(gri) A found method may not be added because it's not in the method set
+			// (!indirect && ptrRecv(f)). A 2nd method on the same level may be in the method
+			// set and may not collide with the first one, thus leading to a false positive.
+			// Is that possible? Investigate.
+			if _, found := s[key]; !found && (indirect || !ptrRecv(f)) {
+				s[key] = &Selection{MethodVal, nil, f, concat(index, i), indirect}
+				continue
+			}
+		}
+		s[key] = nil // collision
+	}
+	return s
+}
+
+// ptrRecv reports whether the receiver is of the form *T.
+// The receiver must exist.
+func ptrRecv(f *Func) bool {
+	_, isPtr := deref(f.typ.(*Signature).recv.typ)
+	return isPtr
+}
+
+// byUniqueName function lists can be sorted by their unique names.
+type byUniqueName []*Selection
+
+func (a byUniqueName) Len() int           { return len(a) }
+func (a byUniqueName) Less(i, j int) bool { return a[i].obj.Id() < a[j].obj.Id() }
+func (a byUniqueName) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
diff --git a/src/go/types/object.go b/src/go/types/object.go
new file mode 100644
index 0000000..b835c6e
--- /dev/null
+++ b/src/go/types/object.go
@@ -0,0 +1,360 @@
+// 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 types
+
+import (
+	"bytes"
+	"fmt"
+	"go/ast"
+	"go/constant"
+	"go/token"
+)
+
+// TODO(gri) Document factory, accessor methods, and fields. General clean-up.
+
+// An Object describes a named language entity such as a package,
+// constant, type, variable, function (incl. methods), or label.
+// All objects implement the Object interface.
+//
+type Object interface {
+	Parent() *Scope // scope in which this object is declared
+	Pos() token.Pos // position of object identifier in declaration
+	Pkg() *Package  // nil for objects in the Universe scope and labels
+	Name() string   // package local object name
+	Type() Type     // object type
+	Exported() bool // reports whether the name starts with a capital letter
+	Id() string     // object id (see Id below)
+
+	// String returns a human-readable string of the object.
+	String() string
+
+	// order reflects a package-level object's source order: if object
+	// a is before object b in the source, then a.order() < b.order().
+	// order returns a value > 0 for package-level objects; it returns
+	// 0 for all other objects (including objects in file scopes).
+	order() uint32
+
+	// setOrder sets the order number of the object. It must be > 0.
+	setOrder(uint32)
+
+	// setParent sets the parent scope of the object.
+	setParent(*Scope)
+
+	// sameId reports whether obj.Id() and Id(pkg, name) are the same.
+	sameId(pkg *Package, name string) bool
+
+	// scopePos returns the start position of the scope of this Object
+	scopePos() token.Pos
+
+	// setScopePos sets the start position of the scope for this Object.
+	setScopePos(pos token.Pos)
+}
+
+// Id returns name if it is exported, otherwise it
+// returns the name qualified with the package path.
+func Id(pkg *Package, name string) string {
+	if ast.IsExported(name) {
+		return name
+	}
+	// unexported names need the package path for differentiation
+	// (if there's no package, make sure we don't start with '.'
+	// as that may change the order of methods between a setup
+	// inside a package and outside a package - which breaks some
+	// tests)
+	path := "_"
+	// TODO(gri): shouldn't !ast.IsExported(name) => pkg != nil be an precondition?
+	// if pkg == nil {
+	// 	panic("nil package in lookup of unexported name")
+	// }
+	if pkg != nil {
+		path = pkg.path
+		if path == "" {
+			path = "_"
+		}
+	}
+	return path + "." + name
+}
+
+// An object implements the common parts of an Object.
+type object struct {
+	parent    *Scope
+	pos       token.Pos
+	pkg       *Package
+	name      string
+	typ       Type
+	order_    uint32
+	scopePos_ token.Pos
+}
+
+func (obj *object) Parent() *Scope      { return obj.parent }
+func (obj *object) Pos() token.Pos      { return obj.pos }
+func (obj *object) Pkg() *Package       { return obj.pkg }
+func (obj *object) Name() string        { return obj.name }
+func (obj *object) Type() Type          { return obj.typ }
+func (obj *object) Exported() bool      { return ast.IsExported(obj.name) }
+func (obj *object) Id() string          { return Id(obj.pkg, obj.name) }
+func (obj *object) String() string      { panic("abstract") }
+func (obj *object) order() uint32       { return obj.order_ }
+func (obj *object) scopePos() token.Pos { return obj.scopePos_ }
+
+func (obj *object) setParent(parent *Scope)   { obj.parent = parent }
+func (obj *object) setOrder(order uint32)     { assert(order > 0); obj.order_ = order }
+func (obj *object) setScopePos(pos token.Pos) { obj.scopePos_ = pos }
+
+func (obj *object) sameId(pkg *Package, name string) bool {
+	// spec:
+	// "Two identifiers are different if they are spelled differently,
+	// or if they appear in different packages and are not exported.
+	// Otherwise, they are the same."
+	if name != obj.name {
+		return false
+	}
+	// obj.Name == name
+	if obj.Exported() {
+		return true
+	}
+	// not exported, so packages must be the same (pkg == nil for
+	// fields in Universe scope; this can only happen for types
+	// introduced via Eval)
+	if pkg == nil || obj.pkg == nil {
+		return pkg == obj.pkg
+	}
+	// pkg != nil && obj.pkg != nil
+	return pkg.path == obj.pkg.path
+}
+
+// A PkgName represents an imported Go package.
+type PkgName struct {
+	object
+	imported *Package
+	used     bool // set if the package was used
+}
+
+func NewPkgName(pos token.Pos, pkg *Package, name string, imported *Package) *PkgName {
+	return &PkgName{object{nil, pos, pkg, name, Typ[Invalid], 0, token.NoPos}, imported, false}
+}
+
+// Imported returns the package that was imported.
+// It is distinct from Pkg(), which is the package containing the import statement.
+func (obj *PkgName) Imported() *Package { return obj.imported }
+
+// A Const represents a declared constant.
+type Const struct {
+	object
+	val     constant.Value
+	visited bool // for initialization cycle detection
+}
+
+func NewConst(pos token.Pos, pkg *Package, name string, typ Type, val constant.Value) *Const {
+	return &Const{object{nil, pos, pkg, name, typ, 0, token.NoPos}, val, false}
+}
+
+func (obj *Const) Val() constant.Value { return obj.val }
+
+// A TypeName represents a declared type.
+type TypeName struct {
+	object
+}
+
+func NewTypeName(pos token.Pos, pkg *Package, name string, typ Type) *TypeName {
+	return &TypeName{object{nil, pos, pkg, name, typ, 0, token.NoPos}}
+}
+
+// A Variable represents a declared variable (including function parameters and results, and struct fields).
+type Var struct {
+	object
+	anonymous bool // if set, the variable is an anonymous struct field, and name is the type name
+	visited   bool // for initialization cycle detection
+	isField   bool // var is struct field
+	used      bool // set if the variable was used
+}
+
+func NewVar(pos token.Pos, pkg *Package, name string, typ Type) *Var {
+	return &Var{object: object{nil, pos, pkg, name, typ, 0, token.NoPos}}
+}
+
+func NewParam(pos token.Pos, pkg *Package, name string, typ Type) *Var {
+	return &Var{object: object{nil, pos, pkg, name, typ, 0, token.NoPos}, used: true} // parameters are always 'used'
+}
+
+func NewField(pos token.Pos, pkg *Package, name string, typ Type, anonymous bool) *Var {
+	return &Var{object: object{nil, pos, pkg, name, typ, 0, token.NoPos}, anonymous: anonymous, isField: true}
+}
+
+func (obj *Var) Anonymous() bool { return obj.anonymous }
+
+func (obj *Var) IsField() bool { return obj.isField }
+
+// A Func represents a declared function, concrete method, or abstract
+// (interface) method.  Its Type() is always a *Signature.
+// An abstract method may belong to many interfaces due to embedding.
+type Func struct {
+	object
+}
+
+func NewFunc(pos token.Pos, pkg *Package, name string, sig *Signature) *Func {
+	// don't store a nil signature
+	var typ Type
+	if sig != nil {
+		typ = sig
+	}
+	return &Func{object{nil, pos, pkg, name, typ, 0, token.NoPos}}
+}
+
+// FullName returns the package- or receiver-type-qualified name of
+// function or method obj.
+func (obj *Func) FullName() string {
+	var buf bytes.Buffer
+	writeFuncName(&buf, obj, nil)
+	return buf.String()
+}
+
+func (obj *Func) Scope() *Scope {
+	return obj.typ.(*Signature).scope
+}
+
+// A Label represents a declared label.
+type Label struct {
+	object
+	used bool // set if the label was used
+}
+
+func NewLabel(pos token.Pos, pkg *Package, name string) *Label {
+	return &Label{object{pos: pos, pkg: pkg, name: name, typ: Typ[Invalid]}, false}
+}
+
+// A Builtin represents a built-in function.
+// Builtins don't have a valid type.
+type Builtin struct {
+	object
+	id builtinId
+}
+
+func newBuiltin(id builtinId) *Builtin {
+	return &Builtin{object{name: predeclaredFuncs[id].name, typ: Typ[Invalid]}, id}
+}
+
+// Nil represents the predeclared value nil.
+type Nil struct {
+	object
+}
+
+func writeObject(buf *bytes.Buffer, obj Object, qf Qualifier) {
+	typ := obj.Type()
+	switch obj := obj.(type) {
+	case *PkgName:
+		fmt.Fprintf(buf, "package %s", obj.Name())
+		if path := obj.imported.path; path != "" && path != obj.name {
+			fmt.Fprintf(buf, " (%q)", path)
+		}
+		return
+
+	case *Const:
+		buf.WriteString("const")
+
+	case *TypeName:
+		buf.WriteString("type")
+		typ = typ.Underlying()
+
+	case *Var:
+		if obj.isField {
+			buf.WriteString("field")
+		} else {
+			buf.WriteString("var")
+		}
+
+	case *Func:
+		buf.WriteString("func ")
+		writeFuncName(buf, obj, qf)
+		if typ != nil {
+			WriteSignature(buf, typ.(*Signature), qf)
+		}
+		return
+
+	case *Label:
+		buf.WriteString("label")
+		typ = nil
+
+	case *Builtin:
+		buf.WriteString("builtin")
+		typ = nil
+
+	case *Nil:
+		buf.WriteString("nil")
+		return
+
+	default:
+		panic(fmt.Sprintf("writeObject(%T)", obj))
+	}
+
+	buf.WriteByte(' ')
+
+	// For package-level objects, qualify the name.
+	if obj.Pkg() != nil && obj.Pkg().scope.Lookup(obj.Name()) == obj {
+		writePackage(buf, obj.Pkg(), qf)
+	}
+	buf.WriteString(obj.Name())
+	if typ != nil {
+		buf.WriteByte(' ')
+		WriteType(buf, typ, qf)
+	}
+}
+
+func writePackage(buf *bytes.Buffer, pkg *Package, qf Qualifier) {
+	if pkg == nil {
+		return
+	}
+	var s string
+	if qf != nil {
+		s = qf(pkg)
+	} else {
+		s = pkg.Path()
+	}
+	if s != "" {
+		buf.WriteString(s)
+		buf.WriteByte('.')
+	}
+}
+
+// ObjectString returns the string form of obj.
+// The Qualifier controls the printing of
+// package-level objects, and may be nil.
+func ObjectString(obj Object, qf Qualifier) string {
+	var buf bytes.Buffer
+	writeObject(&buf, obj, qf)
+	return buf.String()
+}
+
+func (obj *PkgName) String() string  { return ObjectString(obj, nil) }
+func (obj *Const) String() string    { return ObjectString(obj, nil) }
+func (obj *TypeName) String() string { return ObjectString(obj, nil) }
+func (obj *Var) String() string      { return ObjectString(obj, nil) }
+func (obj *Func) String() string     { return ObjectString(obj, nil) }
+func (obj *Label) String() string    { return ObjectString(obj, nil) }
+func (obj *Builtin) String() string  { return ObjectString(obj, nil) }
+func (obj *Nil) String() string      { return ObjectString(obj, nil) }
+
+func writeFuncName(buf *bytes.Buffer, f *Func, qf Qualifier) {
+	if f.typ != nil {
+		sig := f.typ.(*Signature)
+		if recv := sig.Recv(); recv != nil {
+			buf.WriteByte('(')
+			if _, ok := recv.Type().(*Interface); ok {
+				// gcimporter creates abstract methods of
+				// named interfaces using the interface type
+				// (not the named type) as the receiver.
+				// Don't print it in full.
+				buf.WriteString("interface")
+			} else {
+				WriteType(buf, recv.Type(), qf)
+			}
+			buf.WriteByte(')')
+			buf.WriteByte('.')
+		} else if f.pkg != nil {
+			writePackage(buf, f.pkg, qf)
+		}
+	}
+	buf.WriteString(f.name)
+}
diff --git a/src/go/types/objset.go b/src/go/types/objset.go
new file mode 100644
index 0000000..55eb74a
--- /dev/null
+++ b/src/go/types/objset.go
@@ -0,0 +1,31 @@
+// 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.
+
+// This file implements objsets.
+//
+// An objset is similar to a Scope but objset elements
+// are identified by their unique id, instead of their
+// object name.
+
+package types
+
+// An objset is a set of objects identified by their unique id.
+// The zero value for objset is a ready-to-use empty objset.
+type objset map[string]Object // initialized lazily
+
+// insert attempts to insert an object obj into objset s.
+// If s already contains an alternative object alt with
+// the same name, insert leaves s unchanged and returns alt.
+// Otherwise it inserts obj and returns nil.
+func (s *objset) insert(obj Object) Object {
+	id := obj.Id()
+	if alt := (*s)[id]; alt != nil {
+		return alt
+	}
+	if *s == nil {
+		*s = make(map[string]Object)
+	}
+	(*s)[id] = obj
+	return nil
+}
diff --git a/src/go/types/operand.go b/src/go/types/operand.go
new file mode 100644
index 0000000..d3bab51
--- /dev/null
+++ b/src/go/types/operand.go
@@ -0,0 +1,287 @@
+// 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.
+
+// This file defines operands and associated operations.
+
+package types
+
+import (
+	"bytes"
+	"go/ast"
+	"go/constant"
+	"go/token"
+)
+
+// An operandMode specifies the (addressing) mode of an operand.
+type operandMode byte
+
+const (
+	invalid   operandMode = iota // operand is invalid
+	novalue                      // operand represents no value (result of a function call w/o result)
+	builtin                      // operand is a built-in function
+	typexpr                      // operand is a type
+	constant_                    // operand is a constant; the operand's typ is a Basic type
+	variable                     // operand is an addressable variable
+	mapindex                     // operand is a map index expression (acts like a variable on lhs, commaok on rhs of an assignment)
+	value                        // operand is a computed value
+	commaok                      // like value, but operand may be used in a comma,ok expression
+)
+
+var operandModeString = [...]string{
+	invalid:   "invalid operand",
+	novalue:   "no value",
+	builtin:   "built-in",
+	typexpr:   "type",
+	constant_: "constant",
+	variable:  "variable",
+	mapindex:  "map index expression",
+	value:     "value",
+	commaok:   "comma, ok expression",
+}
+
+// An operand represents an intermediate value during type checking.
+// Operands have an (addressing) mode, the expression evaluating to
+// the operand, the operand's type, a value for constants, and an id
+// for built-in functions.
+// The zero value of operand is a ready to use invalid operand.
+//
+type operand struct {
+	mode operandMode
+	expr ast.Expr
+	typ  Type
+	val  constant.Value
+	id   builtinId
+}
+
+// pos returns the position of the expression corresponding to x.
+// If x is invalid the position is token.NoPos.
+//
+func (x *operand) pos() token.Pos {
+	// x.expr may not be set if x is invalid
+	if x.expr == nil {
+		return token.NoPos
+	}
+	return x.expr.Pos()
+}
+
+// Operand string formats
+// (not all "untyped" cases can appear due to the type system,
+// but they fall out naturally here)
+//
+// mode       format
+//
+// invalid    <expr> (               <mode>                    )
+// novalue    <expr> (               <mode>                    )
+// builtin    <expr> (               <mode>                    )
+// typexpr    <expr> (               <mode>                    )
+//
+// constant   <expr> (<untyped kind> <mode>                    )
+// constant   <expr> (               <mode>       of type <typ>)
+// constant   <expr> (<untyped kind> <mode> <val>              )
+// constant   <expr> (               <mode> <val> of type <typ>)
+//
+// variable   <expr> (<untyped kind> <mode>                    )
+// variable   <expr> (               <mode>       of type <typ>)
+//
+// mapindex   <expr> (<untyped kind> <mode>                    )
+// mapindex   <expr> (               <mode>       of type <typ>)
+//
+// value      <expr> (<untyped kind> <mode>                    )
+// value      <expr> (               <mode>       of type <typ>)
+//
+// commaok    <expr> (<untyped kind> <mode>                    )
+// commaok    <expr> (               <mode>       of type <typ>)
+//
+func operandString(x *operand, qf Qualifier) string {
+	var buf bytes.Buffer
+
+	var expr string
+	if x.expr != nil {
+		expr = ExprString(x.expr)
+	} else {
+		switch x.mode {
+		case builtin:
+			expr = predeclaredFuncs[x.id].name
+		case typexpr:
+			expr = TypeString(x.typ, qf)
+		case constant_:
+			expr = x.val.String()
+		}
+	}
+
+	// <expr> (
+	if expr != "" {
+		buf.WriteString(expr)
+		buf.WriteString(" (")
+	}
+
+	// <untyped kind>
+	hasType := false
+	switch x.mode {
+	case invalid, novalue, builtin, typexpr:
+		// no type
+	default:
+		// has type
+		if isUntyped(x.typ) {
+			buf.WriteString(x.typ.(*Basic).name)
+			buf.WriteByte(' ')
+			break
+		}
+		hasType = true
+	}
+
+	// <mode>
+	buf.WriteString(operandModeString[x.mode])
+
+	// <val>
+	if x.mode == constant_ {
+		if s := x.val.String(); s != expr {
+			buf.WriteByte(' ')
+			buf.WriteString(s)
+		}
+	}
+
+	// <typ>
+	if hasType {
+		if x.typ != Typ[Invalid] {
+			buf.WriteString(" of type ")
+			WriteType(&buf, x.typ, qf)
+		} else {
+			buf.WriteString(" with invalid type")
+		}
+	}
+
+	// )
+	if expr != "" {
+		buf.WriteByte(')')
+	}
+
+	return buf.String()
+}
+
+func (x *operand) String() string {
+	return operandString(x, nil)
+}
+
+// setConst sets x to the untyped constant for literal lit.
+func (x *operand) setConst(tok token.Token, lit string) {
+	val := constant.MakeFromLiteral(lit, tok, 0)
+	if val == nil {
+		// TODO(gri) Should we make it an unknown constant instead?
+		x.mode = invalid
+		return
+	}
+
+	var kind BasicKind
+	switch tok {
+	case token.INT:
+		kind = UntypedInt
+	case token.FLOAT:
+		kind = UntypedFloat
+	case token.IMAG:
+		kind = UntypedComplex
+	case token.CHAR:
+		kind = UntypedRune
+	case token.STRING:
+		kind = UntypedString
+	}
+
+	x.mode = constant_
+	x.typ = Typ[kind]
+	x.val = val
+}
+
+// isNil reports whether x is the nil value.
+func (x *operand) isNil() bool {
+	return x.mode == value && x.typ == Typ[UntypedNil]
+}
+
+// TODO(gri) The functions operand.assignableTo, checker.convertUntyped,
+//           checker.representable, and checker.assignment are
+//           overlapping in functionality. Need to simplify and clean up.
+
+// assignableTo reports whether x is assignable to a variable of type T.
+func (x *operand) assignableTo(conf *Config, T Type) bool {
+	if x.mode == invalid || T == Typ[Invalid] {
+		return true // avoid spurious errors
+	}
+
+	V := x.typ
+
+	// x's type is identical to T
+	if Identical(V, T) {
+		return true
+	}
+
+	Vu := V.Underlying()
+	Tu := T.Underlying()
+
+	// T is an interface type and x implements T
+	// (Do this check first as it might succeed early.)
+	if Ti, ok := Tu.(*Interface); ok {
+		if Implements(x.typ, Ti) {
+			return true
+		}
+	}
+
+	// x's type V and T have identical underlying types
+	// and at least one of V or T is not a named type
+	if Identical(Vu, Tu) && (!isNamed(V) || !isNamed(T)) {
+		return true
+	}
+
+	// x is a bidirectional channel value, T is a channel
+	// type, x's type V and T have identical element types,
+	// and at least one of V or T is not a named type
+	if Vc, ok := Vu.(*Chan); ok && Vc.dir == SendRecv {
+		if Tc, ok := Tu.(*Chan); ok && Identical(Vc.elem, Tc.elem) {
+			return !isNamed(V) || !isNamed(T)
+		}
+	}
+
+	// x is the predeclared identifier nil and T is a pointer,
+	// function, slice, map, channel, or interface type
+	if x.isNil() {
+		switch t := Tu.(type) {
+		case *Basic:
+			if t.kind == UnsafePointer {
+				return true
+			}
+		case *Pointer, *Signature, *Slice, *Map, *Chan, *Interface:
+			return true
+		}
+		return false
+	}
+
+	// x is an untyped constant representable by a value of type T
+	// TODO(gri) This is borrowing from checker.convertUntyped and
+	//           checker.representable. Need to clean up.
+	if isUntyped(Vu) {
+		switch t := Tu.(type) {
+		case *Basic:
+			if x.mode == constant_ {
+				return representableConst(x.val, conf, t.kind, nil)
+			}
+			// The result of a comparison is an untyped boolean,
+			// but may not be a constant.
+			if Vb, _ := Vu.(*Basic); Vb != nil {
+				return Vb.kind == UntypedBool && isBoolean(Tu)
+			}
+		case *Interface:
+			return x.isNil() || t.Empty()
+		case *Pointer, *Signature, *Slice, *Map, *Chan:
+			return x.isNil()
+		}
+	}
+
+	return false
+}
+
+// isInteger reports whether x is value of integer type
+// or an untyped constant representable as an integer.
+func (x *operand) isInteger() bool {
+	return x.mode == invalid ||
+		isInteger(x.typ) ||
+		isUntyped(x.typ) && x.mode == constant_ && representableConst(x.val, nil, UntypedInt, nil) // no *Config required for UntypedInt
+}
diff --git a/src/go/types/ordering.go b/src/go/types/ordering.go
new file mode 100644
index 0000000..6bb98f2
--- /dev/null
+++ b/src/go/types/ordering.go
@@ -0,0 +1,127 @@
+// 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.
+
+// This file implements resolveOrder.
+
+package types
+
+import (
+	"go/ast"
+	"sort"
+)
+
+// resolveOrder computes the order in which package-level objects
+// must be type-checked.
+//
+// Interface types appear first in the list, sorted topologically
+// by dependencies on embedded interfaces that are also declared
+// in this package, followed by all other objects sorted in source
+// order.
+//
+// TODO(gri) Consider sorting all types by dependencies here, and
+// in the process check _and_ report type cycles. This may simplify
+// the full type-checking phase.
+//
+func (check *Checker) resolveOrder() []Object {
+	var ifaces, others []Object
+
+	// collect interface types with their dependencies, and all other objects
+	for obj := range check.objMap {
+		if ityp := check.interfaceFor(obj); ityp != nil {
+			ifaces = append(ifaces, obj)
+			// determine dependencies on embedded interfaces
+			for _, f := range ityp.Methods.List {
+				if len(f.Names) == 0 {
+					// Embedded interface: The type must be a (possibly
+					// qualified) identifier denoting another interface.
+					// Imported interfaces are already fully resolved,
+					// so we can ignore qualified identifiers.
+					if ident, _ := f.Type.(*ast.Ident); ident != nil {
+						embedded := check.pkg.scope.Lookup(ident.Name)
+						if check.interfaceFor(embedded) != nil {
+							check.objMap[obj].addDep(embedded)
+						}
+					}
+				}
+			}
+		} else {
+			others = append(others, obj)
+		}
+	}
+
+	// final object order
+	var order []Object
+
+	// sort interface types topologically by dependencies,
+	// and in source order if there are no dependencies
+	sort.Sort(inSourceOrder(ifaces))
+	if debug {
+		for _, obj := range ifaces {
+			assert(check.objMap[obj].mark == 0)
+		}
+	}
+	for _, obj := range ifaces {
+		check.appendInPostOrder(&order, obj)
+	}
+
+	// sort everything else in source order
+	sort.Sort(inSourceOrder(others))
+
+	return append(order, others...)
+}
+
+// interfaceFor returns the AST interface denoted by obj, or nil.
+func (check *Checker) interfaceFor(obj Object) *ast.InterfaceType {
+	tname, _ := obj.(*TypeName)
+	if tname == nil {
+		return nil // not a type
+	}
+	d := check.objMap[obj]
+	if d == nil {
+		check.dump("%s: %s should have been declared", obj.Pos(), obj.Name())
+		unreachable()
+	}
+	if d.typ == nil {
+		return nil // invalid AST - ignore (will be handled later)
+	}
+	ityp, _ := d.typ.(*ast.InterfaceType)
+	return ityp
+}
+
+func (check *Checker) appendInPostOrder(order *[]Object, obj Object) {
+	d := check.objMap[obj]
+	if d.mark != 0 {
+		// We've already seen this object; either because it's
+		// already added to order, or because we have a cycle.
+		// In both cases we stop. Cycle errors are reported
+		// when type-checking types.
+		return
+	}
+	d.mark = 1
+
+	for _, obj := range orderedSetObjects(d.deps) {
+		check.appendInPostOrder(order, obj)
+	}
+
+	*order = append(*order, obj)
+}
+
+func orderedSetObjects(set map[Object]bool) []Object {
+	list := make([]Object, len(set))
+	i := 0
+	for obj := range set {
+		// we don't care about the map element value
+		list[i] = obj
+		i++
+	}
+	sort.Sort(inSourceOrder(list))
+	return list
+}
+
+// inSourceOrder implements the sort.Sort interface.
+type inSourceOrder []Object
+
+func (a inSourceOrder) Len() int           { return len(a) }
+func (a inSourceOrder) Less(i, j int) bool { return a[i].order() < a[j].order() }
+func (a inSourceOrder) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
diff --git a/src/go/types/package.go b/src/go/types/package.go
new file mode 100644
index 0000000..48fe839
--- /dev/null
+++ b/src/go/types/package.go
@@ -0,0 +1,65 @@
+// 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 types
+
+import (
+	"fmt"
+	"go/token"
+)
+
+// A Package describes a Go package.
+type Package struct {
+	path     string
+	name     string
+	scope    *Scope
+	complete bool
+	imports  []*Package
+	fake     bool // scope lookup errors are silently dropped if package is fake (internal use only)
+}
+
+// NewPackage returns a new Package for the given package path and name;
+// the name must not be the blank identifier.
+// The package is not complete and contains no explicit imports.
+func NewPackage(path, name string) *Package {
+	if name == "_" {
+		panic("invalid package name _")
+	}
+	scope := NewScope(Universe, token.NoPos, token.NoPos, fmt.Sprintf("package %q", path))
+	return &Package{path: path, name: name, scope: scope}
+}
+
+// Path returns the package path.
+func (pkg *Package) Path() string { return pkg.path }
+
+// Name returns the package name.
+func (pkg *Package) Name() string { return pkg.name }
+
+// Scope returns the (complete or incomplete) package scope
+// holding the objects declared at package level (TypeNames,
+// Consts, Vars, and Funcs).
+func (pkg *Package) Scope() *Scope { return pkg.scope }
+
+// A package is complete if its scope contains (at least) all
+// exported objects; otherwise it is incomplete.
+func (pkg *Package) Complete() bool { return pkg.complete }
+
+// MarkComplete marks a package as complete.
+func (pkg *Package) MarkComplete() { pkg.complete = true }
+
+// Imports returns the list of packages directly imported by
+// pkg; the list is in source order. Package unsafe is excluded.
+//
+// If pkg was loaded from export data, Imports includes packages that
+// provide package-level objects referenced by pkg.  This may be more or
+// less than the set of packages directly imported by pkg's source code.
+func (pkg *Package) Imports() []*Package { return pkg.imports }
+
+// SetImports sets the list of explicitly imported packages to list.
+// It is the caller's responsibility to make sure list elements are unique.
+func (pkg *Package) SetImports(list []*Package) { pkg.imports = list }
+
+func (pkg *Package) String() string {
+	return fmt.Sprintf("package %s (%q)", pkg.name, pkg.path)
+}
diff --git a/src/go/types/predicates.go b/src/go/types/predicates.go
new file mode 100644
index 0000000..993c6d2
--- /dev/null
+++ b/src/go/types/predicates.go
@@ -0,0 +1,309 @@
+// 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.
+
+// This file implements commonly used type predicates.
+
+package types
+
+import "sort"
+
+func isNamed(typ Type) bool {
+	if _, ok := typ.(*Basic); ok {
+		return ok
+	}
+	_, ok := typ.(*Named)
+	return ok
+}
+
+func isBoolean(typ Type) bool {
+	t, ok := typ.Underlying().(*Basic)
+	return ok && t.info&IsBoolean != 0
+}
+
+func isInteger(typ Type) bool {
+	t, ok := typ.Underlying().(*Basic)
+	return ok && t.info&IsInteger != 0
+}
+
+func isUnsigned(typ Type) bool {
+	t, ok := typ.Underlying().(*Basic)
+	return ok && t.info&IsUnsigned != 0
+}
+
+func isFloat(typ Type) bool {
+	t, ok := typ.Underlying().(*Basic)
+	return ok && t.info&IsFloat != 0
+}
+
+func isComplex(typ Type) bool {
+	t, ok := typ.Underlying().(*Basic)
+	return ok && t.info&IsComplex != 0
+}
+
+func isNumeric(typ Type) bool {
+	t, ok := typ.Underlying().(*Basic)
+	return ok && t.info&IsNumeric != 0
+}
+
+func isString(typ Type) bool {
+	t, ok := typ.Underlying().(*Basic)
+	return ok && t.info&IsString != 0
+}
+
+func isTyped(typ Type) bool {
+	t, ok := typ.Underlying().(*Basic)
+	return !ok || t.info&IsUntyped == 0
+}
+
+func isUntyped(typ Type) bool {
+	t, ok := typ.Underlying().(*Basic)
+	return ok && t.info&IsUntyped != 0
+}
+
+func isOrdered(typ Type) bool {
+	t, ok := typ.Underlying().(*Basic)
+	return ok && t.info&IsOrdered != 0
+}
+
+func isConstType(typ Type) bool {
+	t, ok := typ.Underlying().(*Basic)
+	return ok && t.info&IsConstType != 0
+}
+
+// IsInterface reports whether typ is an interface type.
+func IsInterface(typ Type) bool {
+	_, ok := typ.Underlying().(*Interface)
+	return ok
+}
+
+// Comparable reports whether values of type T are comparable.
+func Comparable(T Type) bool {
+	switch t := T.Underlying().(type) {
+	case *Basic:
+		// assume invalid types to be comparable
+		// to avoid follow-up errors
+		return t.kind != UntypedNil
+	case *Pointer, *Interface, *Chan:
+		return true
+	case *Struct:
+		for _, f := range t.fields {
+			if !Comparable(f.typ) {
+				return false
+			}
+		}
+		return true
+	case *Array:
+		return Comparable(t.elem)
+	}
+	return false
+}
+
+// hasNil reports whether a type includes the nil value.
+func hasNil(typ Type) bool {
+	switch t := typ.Underlying().(type) {
+	case *Basic:
+		return t.kind == UnsafePointer
+	case *Slice, *Pointer, *Signature, *Interface, *Map, *Chan:
+		return true
+	}
+	return false
+}
+
+// Identical reports whether x and y are identical.
+func Identical(x, y Type) bool {
+	return identical(x, y, nil)
+}
+
+// An ifacePair is a node in a stack of interface type pairs compared for identity.
+type ifacePair struct {
+	x, y *Interface
+	prev *ifacePair
+}
+
+func (p *ifacePair) identical(q *ifacePair) bool {
+	return p.x == q.x && p.y == q.y || p.x == q.y && p.y == q.x
+}
+
+func identical(x, y Type, p *ifacePair) bool {
+	if x == y {
+		return true
+	}
+
+	switch x := x.(type) {
+	case *Basic:
+		// Basic types are singletons except for the rune and byte
+		// aliases, thus we cannot solely rely on the x == y check
+		// above.
+		if y, ok := y.(*Basic); ok {
+			return x.kind == y.kind
+		}
+
+	case *Array:
+		// Two array types are identical if they have identical element types
+		// and the same array length.
+		if y, ok := y.(*Array); ok {
+			return x.len == y.len && identical(x.elem, y.elem, p)
+		}
+
+	case *Slice:
+		// Two slice types are identical if they have identical element types.
+		if y, ok := y.(*Slice); ok {
+			return identical(x.elem, y.elem, p)
+		}
+
+	case *Struct:
+		// Two struct types are identical if they have the same sequence of fields,
+		// and if corresponding fields have the same names, and identical types,
+		// and identical tags. Two anonymous fields are considered to have the same
+		// name. Lower-case field names from different packages are always different.
+		if y, ok := y.(*Struct); ok {
+			if x.NumFields() == y.NumFields() {
+				for i, f := range x.fields {
+					g := y.fields[i]
+					if f.anonymous != g.anonymous ||
+						x.Tag(i) != y.Tag(i) ||
+						!f.sameId(g.pkg, g.name) ||
+						!identical(f.typ, g.typ, p) {
+						return false
+					}
+				}
+				return true
+			}
+		}
+
+	case *Pointer:
+		// Two pointer types are identical if they have identical base types.
+		if y, ok := y.(*Pointer); ok {
+			return identical(x.base, y.base, p)
+		}
+
+	case *Tuple:
+		// Two tuples types are identical if they have the same number of elements
+		// and corresponding elements have identical types.
+		if y, ok := y.(*Tuple); ok {
+			if x.Len() == y.Len() {
+				if x != nil {
+					for i, v := range x.vars {
+						w := y.vars[i]
+						if !identical(v.typ, w.typ, p) {
+							return false
+						}
+					}
+				}
+				return true
+			}
+		}
+
+	case *Signature:
+		// Two function types are identical if they have the same number of parameters
+		// and result values, corresponding parameter and result types are identical,
+		// and either both functions are variadic or neither is. Parameter and result
+		// names are not required to match.
+		if y, ok := y.(*Signature); ok {
+			return x.variadic == y.variadic &&
+				identical(x.params, y.params, p) &&
+				identical(x.results, y.results, p)
+		}
+
+	case *Interface:
+		// Two interface types are identical if they have the same set of methods with
+		// the same names and identical function types. Lower-case method names from
+		// different packages are always different. The order of the methods is irrelevant.
+		if y, ok := y.(*Interface); ok {
+			a := x.allMethods
+			b := y.allMethods
+			if len(a) == len(b) {
+				// Interface types are the only types where cycles can occur
+				// that are not "terminated" via named types; and such cycles
+				// can only be created via method parameter types that are
+				// anonymous interfaces (directly or indirectly) embedding
+				// the current interface. Example:
+				//
+				//    type T interface {
+				//        m() interface{T}
+				//    }
+				//
+				// If two such (differently named) interfaces are compared,
+				// endless recursion occurs if the cycle is not detected.
+				//
+				// If x and y were compared before, they must be equal
+				// (if they were not, the recursion would have stopped);
+				// search the ifacePair stack for the same pair.
+				//
+				// This is a quadratic algorithm, but in practice these stacks
+				// are extremely short (bounded by the nesting depth of interface
+				// type declarations that recur via parameter types, an extremely
+				// rare occurrence). An alternative implementation might use a
+				// "visited" map, but that is probably less efficient overall.
+				q := &ifacePair{x, y, p}
+				for p != nil {
+					if p.identical(q) {
+						return true // same pair was compared before
+					}
+					p = p.prev
+				}
+				if debug {
+					assert(sort.IsSorted(byUniqueMethodName(a)))
+					assert(sort.IsSorted(byUniqueMethodName(b)))
+				}
+				for i, f := range a {
+					g := b[i]
+					if f.Id() != g.Id() || !identical(f.typ, g.typ, q) {
+						return false
+					}
+				}
+				return true
+			}
+		}
+
+	case *Map:
+		// Two map types are identical if they have identical key and value types.
+		if y, ok := y.(*Map); ok {
+			return identical(x.key, y.key, p) && identical(x.elem, y.elem, p)
+		}
+
+	case *Chan:
+		// Two channel types are identical if they have identical value types
+		// and the same direction.
+		if y, ok := y.(*Chan); ok {
+			return x.dir == y.dir && identical(x.elem, y.elem, p)
+		}
+
+	case *Named:
+		// Two named types are identical if their type names originate
+		// in the same type declaration.
+		if y, ok := y.(*Named); ok {
+			return x.obj == y.obj
+		}
+
+	default:
+		unreachable()
+	}
+
+	return false
+}
+
+// defaultType returns the default "typed" type for an "untyped" type;
+// it returns the incoming type for all other types. The default type
+// for untyped nil is untyped nil.
+//
+func defaultType(typ Type) Type {
+	if t, ok := typ.(*Basic); ok {
+		switch t.kind {
+		case UntypedBool:
+			return Typ[Bool]
+		case UntypedInt:
+			return Typ[Int]
+		case UntypedRune:
+			return universeRune // use 'rune' name
+		case UntypedFloat:
+			return Typ[Float64]
+		case UntypedComplex:
+			return Typ[Complex128]
+		case UntypedString:
+			return Typ[String]
+		}
+	}
+	return typ
+}
diff --git a/src/go/types/resolver.go b/src/go/types/resolver.go
new file mode 100644
index 0000000..c31ef42
--- /dev/null
+++ b/src/go/types/resolver.go
@@ -0,0 +1,445 @@
+// 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 types
+
+import (
+	"fmt"
+	"go/ast"
+	"go/constant"
+	"go/token"
+	pathLib "path"
+	"strconv"
+	"strings"
+	"unicode"
+)
+
+// A declInfo describes a package-level const, type, var, or func declaration.
+type declInfo struct {
+	file  *Scope        // scope of file containing this declaration
+	lhs   []*Var        // lhs of n:1 variable declarations, or nil
+	typ   ast.Expr      // type, or nil
+	init  ast.Expr      // init expression, or nil
+	fdecl *ast.FuncDecl // func declaration, or nil
+
+	deps map[Object]bool // type and init dependencies; lazily allocated
+	mark int             // for dependency analysis
+}
+
+// hasInitializer reports whether the declared object has an initialization
+// expression or function body.
+func (d *declInfo) hasInitializer() bool {
+	return d.init != nil || d.fdecl != nil && d.fdecl.Body != nil
+}
+
+// addDep adds obj as a dependency to d.
+func (d *declInfo) addDep(obj Object) {
+	m := d.deps
+	if m == nil {
+		m = make(map[Object]bool)
+		d.deps = m
+	}
+	m[obj] = true
+}
+
+// arityMatch checks that the lhs and rhs of a const or var decl
+// have the appropriate number of names and init exprs. For const
+// decls, init is the value spec providing the init exprs; for
+// var decls, init is nil (the init exprs are in s in this case).
+func (check *Checker) arityMatch(s, init *ast.ValueSpec) {
+	l := len(s.Names)
+	r := len(s.Values)
+	if init != nil {
+		r = len(init.Values)
+	}
+
+	switch {
+	case init == nil && r == 0:
+		// var decl w/o init expr
+		if s.Type == nil {
+			check.errorf(s.Pos(), "missing type or init expr")
+		}
+	case l < r:
+		if l < len(s.Values) {
+			// init exprs from s
+			n := s.Values[l]
+			check.errorf(n.Pos(), "extra init expr %s", n)
+			// TODO(gri) avoid declared but not used error here
+		} else {
+			// init exprs "inherited"
+			check.errorf(s.Pos(), "extra init expr at %s", init.Pos())
+			// TODO(gri) avoid declared but not used error here
+		}
+	case l > r && (init != nil || r != 1):
+		n := s.Names[r]
+		check.errorf(n.Pos(), "missing init expr for %s", n)
+	}
+}
+
+func validatedImportPath(path string) (string, error) {
+	s, err := strconv.Unquote(path)
+	if err != nil {
+		return "", err
+	}
+	if s == "" {
+		return "", fmt.Errorf("empty string")
+	}
+	const illegalChars = `!"#$%&'()*,:;<=>?[\]^{|}` + "`\uFFFD"
+	for _, r := range s {
+		if !unicode.IsGraphic(r) || unicode.IsSpace(r) || strings.ContainsRune(illegalChars, r) {
+			return s, fmt.Errorf("invalid character %#U", r)
+		}
+	}
+	return s, nil
+}
+
+// declarePkgObj declares obj in the package scope, records its ident -> obj mapping,
+// and updates check.objMap. The object must not be a function or method.
+func (check *Checker) declarePkgObj(ident *ast.Ident, obj Object, d *declInfo) {
+	assert(ident.Name == obj.Name())
+
+	// spec: "A package-scope or file-scope identifier with name init
+	// may only be declared to be a function with this (func()) signature."
+	if ident.Name == "init" {
+		check.errorf(ident.Pos(), "cannot declare init - must be func")
+		return
+	}
+
+	check.declare(check.pkg.scope, ident, obj, token.NoPos)
+	check.objMap[obj] = d
+	obj.setOrder(uint32(len(check.objMap)))
+}
+
+// filename returns a filename suitable for debugging output.
+func (check *Checker) filename(fileNo int) string {
+	file := check.files[fileNo]
+	if pos := file.Pos(); pos.IsValid() {
+		return check.fset.File(pos).Name()
+	}
+	return fmt.Sprintf("file[%d]", fileNo)
+}
+
+// collectObjects collects all file and package objects and inserts them
+// into their respective scopes. It also performs imports and associates
+// methods with receiver base type names.
+func (check *Checker) collectObjects() {
+	pkg := check.pkg
+
+	// pkgImports is the set of packages already imported by any package file seen
+	// so far. Used to avoid duplicate entries in pkg.imports. Allocate and populate
+	// it (pkg.imports may not be empty if we are checking test files incrementally).
+	var pkgImports = make(map[*Package]bool)
+	for _, imp := range pkg.imports {
+		pkgImports[imp] = true
+	}
+
+	for fileNo, file := range check.files {
+		// The package identifier denotes the current package,
+		// but there is no corresponding package object.
+		check.recordDef(file.Name, nil)
+
+		// Use the actual source file extent rather than *ast.File extent since the
+		// latter doesn't include comments which appear at the start or end of the file.
+		// Be conservative and use the *ast.File extent if we don't have a *token.File.
+		pos, end := file.Pos(), file.End()
+		if f := check.fset.File(file.Pos()); f != nil {
+			pos, end = token.Pos(f.Base()), token.Pos(f.Base()+f.Size())
+		}
+		fileScope := NewScope(check.pkg.scope, pos, end, check.filename(fileNo))
+		check.recordScope(file, fileScope)
+
+		for _, decl := range file.Decls {
+			switch d := decl.(type) {
+			case *ast.BadDecl:
+				// ignore
+
+			case *ast.GenDecl:
+				var last *ast.ValueSpec // last ValueSpec with type or init exprs seen
+				for iota, spec := range d.Specs {
+					switch s := spec.(type) {
+					case *ast.ImportSpec:
+						// import package
+						var imp *Package
+						path, err := validatedImportPath(s.Path.Value)
+						if err != nil {
+							check.errorf(s.Path.Pos(), "invalid import path (%s)", err)
+							continue
+						}
+						if path == "C" && check.conf.FakeImportC {
+							// TODO(gri) shouldn't create a new one each time
+							imp = NewPackage("C", "C")
+							imp.fake = true
+						} else if path == "unsafe" {
+							// package "unsafe" is known to the language
+							imp = Unsafe
+						} else {
+							if importer := check.conf.Importer; importer != nil {
+								imp, err = importer.Import(path)
+								if imp == nil && err == nil {
+									err = fmt.Errorf("Config.Importer.Import(%s) returned nil but no error", path)
+								}
+							} else {
+								err = fmt.Errorf("Config.Importer not installed")
+							}
+							if err != nil {
+								check.errorf(s.Path.Pos(), "could not import %s (%s)", path, err)
+								continue
+							}
+						}
+
+						// add package to list of explicit imports
+						// (this functionality is provided as a convenience
+						// for clients; it is not needed for type-checking)
+						if !pkgImports[imp] {
+							pkgImports[imp] = true
+							if imp != Unsafe {
+								pkg.imports = append(pkg.imports, imp)
+							}
+						}
+
+						// local name overrides imported package name
+						name := imp.name
+						if s.Name != nil {
+							name = s.Name.Name
+							if name == "init" {
+								check.errorf(s.Name.Pos(), "cannot declare init - must be func")
+								continue
+							}
+						}
+
+						obj := NewPkgName(s.Pos(), pkg, name, imp)
+						if s.Name != nil {
+							// in a dot-import, the dot represents the package
+							check.recordDef(s.Name, obj)
+						} else {
+							check.recordImplicit(s, obj)
+						}
+
+						// add import to file scope
+						if name == "." {
+							// merge imported scope with file scope
+							for _, obj := range imp.scope.elems {
+								// A package scope may contain non-exported objects,
+								// do not import them!
+								if obj.Exported() {
+									// TODO(gri) When we import a package, we create
+									// a new local package object. We should do the
+									// same for each dot-imported object. That way
+									// they can have correct position information.
+									// (We must not modify their existing position
+									// information because the same package - found
+									// via Config.Packages - may be dot-imported in
+									// another package!)
+									check.declare(fileScope, nil, obj, token.NoPos)
+									check.recordImplicit(s, obj)
+								}
+							}
+							// add position to set of dot-import positions for this file
+							// (this is only needed for "imported but not used" errors)
+							check.addUnusedDotImport(fileScope, imp, s.Pos())
+						} else {
+							// declare imported package object in file scope
+							check.declare(fileScope, nil, obj, token.NoPos)
+						}
+
+					case *ast.ValueSpec:
+						switch d.Tok {
+						case token.CONST:
+							// determine which initialization expressions to use
+							switch {
+							case s.Type != nil || len(s.Values) > 0:
+								last = s
+							case last == nil:
+								last = new(ast.ValueSpec) // make sure last exists
+							}
+
+							// declare all constants
+							for i, name := range s.Names {
+								obj := NewConst(name.Pos(), pkg, name.Name, nil, constant.MakeInt64(int64(iota)))
+
+								var init ast.Expr
+								if i < len(last.Values) {
+									init = last.Values[i]
+								}
+
+								d := &declInfo{file: fileScope, typ: last.Type, init: init}
+								check.declarePkgObj(name, obj, d)
+							}
+
+							check.arityMatch(s, last)
+
+						case token.VAR:
+							lhs := make([]*Var, len(s.Names))
+							// If there's exactly one rhs initializer, use
+							// the same declInfo d1 for all lhs variables
+							// so that each lhs variable depends on the same
+							// rhs initializer (n:1 var declaration).
+							var d1 *declInfo
+							if len(s.Values) == 1 {
+								// The lhs elements are only set up after the for loop below,
+								// but that's ok because declareVar only collects the declInfo
+								// for a later phase.
+								d1 = &declInfo{file: fileScope, lhs: lhs, typ: s.Type, init: s.Values[0]}
+							}
+
+							// declare all variables
+							for i, name := range s.Names {
+								obj := NewVar(name.Pos(), pkg, name.Name, nil)
+								lhs[i] = obj
+
+								d := d1
+								if d == nil {
+									// individual assignments
+									var init ast.Expr
+									if i < len(s.Values) {
+										init = s.Values[i]
+									}
+									d = &declInfo{file: fileScope, typ: s.Type, init: init}
+								}
+
+								check.declarePkgObj(name, obj, d)
+							}
+
+							check.arityMatch(s, nil)
+
+						default:
+							check.invalidAST(s.Pos(), "invalid token %s", d.Tok)
+						}
+
+					case *ast.TypeSpec:
+						obj := NewTypeName(s.Name.Pos(), pkg, s.Name.Name, nil)
+						check.declarePkgObj(s.Name, obj, &declInfo{file: fileScope, typ: s.Type})
+
+					default:
+						check.invalidAST(s.Pos(), "unknown ast.Spec node %T", s)
+					}
+				}
+
+			case *ast.FuncDecl:
+				name := d.Name.Name
+				obj := NewFunc(d.Name.Pos(), pkg, name, nil)
+				if d.Recv == nil {
+					// regular function
+					if name == "init" {
+						// don't declare init functions in the package scope - they are invisible
+						obj.parent = pkg.scope
+						check.recordDef(d.Name, obj)
+						// init functions must have a body
+						if d.Body == nil {
+							check.softErrorf(obj.pos, "missing function body")
+						}
+					} else {
+						check.declare(pkg.scope, d.Name, obj, token.NoPos)
+					}
+				} else {
+					// method
+					check.recordDef(d.Name, obj)
+					// Associate method with receiver base type name, if possible.
+					// Ignore methods that have an invalid receiver, or a blank _
+					// receiver name. They will be type-checked later, with regular
+					// functions.
+					if list := d.Recv.List; len(list) > 0 {
+						typ := list[0].Type
+						if ptr, _ := typ.(*ast.StarExpr); ptr != nil {
+							typ = ptr.X
+						}
+						if base, _ := typ.(*ast.Ident); base != nil && base.Name != "_" {
+							check.assocMethod(base.Name, obj)
+						}
+					}
+				}
+				info := &declInfo{file: fileScope, fdecl: d}
+				check.objMap[obj] = info
+				obj.setOrder(uint32(len(check.objMap)))
+
+			default:
+				check.invalidAST(d.Pos(), "unknown ast.Decl node %T", d)
+			}
+		}
+	}
+
+	// verify that objects in package and file scopes have different names
+	for _, scope := range check.pkg.scope.children /* file scopes */ {
+		for _, obj := range scope.elems {
+			if alt := pkg.scope.Lookup(obj.Name()); alt != nil {
+				if pkg, ok := obj.(*PkgName); ok {
+					check.errorf(alt.Pos(), "%s already declared through import of %s", alt.Name(), pkg.Imported())
+					check.reportAltDecl(pkg)
+				} else {
+					check.errorf(alt.Pos(), "%s already declared through dot-import of %s", alt.Name(), obj.Pkg())
+					// TODO(gri) dot-imported objects don't have a position; reportAltDecl won't print anything
+					check.reportAltDecl(obj)
+				}
+			}
+		}
+	}
+}
+
+// packageObjects typechecks all package objects in objList, but not function bodies.
+func (check *Checker) packageObjects(objList []Object) {
+	// add new methods to already type-checked types (from a prior Checker.Files call)
+	for _, obj := range objList {
+		if obj, _ := obj.(*TypeName); obj != nil && obj.typ != nil {
+			check.addMethodDecls(obj)
+		}
+	}
+
+	// pre-allocate space for type declaration paths so that the underlying array is reused
+	typePath := make([]*TypeName, 0, 8)
+
+	for _, obj := range objList {
+		check.objDecl(obj, nil, typePath)
+	}
+
+	// At this point we may have a non-empty check.methods map; this means that not all
+	// entries were deleted at the end of typeDecl because the respective receiver base
+	// types were not found. In that case, an error was reported when declaring those
+	// methods. We can now safely discard this map.
+	check.methods = nil
+}
+
+// functionBodies typechecks all function bodies.
+func (check *Checker) functionBodies() {
+	for _, f := range check.funcs {
+		check.funcBody(f.decl, f.name, f.sig, f.body)
+	}
+}
+
+// unusedImports checks for unused imports.
+func (check *Checker) unusedImports() {
+	// if function bodies are not checked, packages' uses are likely missing - don't check
+	if check.conf.IgnoreFuncBodies {
+		return
+	}
+
+	// spec: "It is illegal (...) to directly import a package without referring to
+	// any of its exported identifiers. To import a package solely for its side-effects
+	// (initialization), use the blank identifier as explicit package name."
+
+	// check use of regular imported packages
+	for _, scope := range check.pkg.scope.children /* file scopes */ {
+		for _, obj := range scope.elems {
+			if obj, ok := obj.(*PkgName); ok {
+				// Unused "blank imports" are automatically ignored
+				// since _ identifiers are not entered into scopes.
+				if !obj.used {
+					path := obj.imported.path
+					base := pathLib.Base(path)
+					if obj.name == base {
+						check.softErrorf(obj.pos, "%q imported but not used", path)
+					} else {
+						check.softErrorf(obj.pos, "%q imported but not used as %s", path, obj.name)
+					}
+				}
+			}
+		}
+	}
+
+	// check use of dot-imported packages
+	for _, unusedDotImports := range check.unusedDotImports {
+		for pkg, pos := range unusedDotImports {
+			check.softErrorf(pos, "%q imported but not used", pkg.path)
+		}
+	}
+}
diff --git a/src/go/types/resolver_test.go b/src/go/types/resolver_test.go
new file mode 100644
index 0000000..34deae2
--- /dev/null
+++ b/src/go/types/resolver_test.go
@@ -0,0 +1,209 @@
+// 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 types_test
+
+import (
+	"fmt"
+	"go/ast"
+	"go/importer"
+	"go/parser"
+	"go/token"
+	"internal/testenv"
+	"sort"
+	"testing"
+
+	. "go/types"
+)
+
+type resolveTestImporter struct {
+	importer Importer
+	imported map[string]bool
+}
+
+func (imp *resolveTestImporter) Import(path string) (*Package, error) {
+	if imp.importer == nil {
+		imp.importer = importer.Default()
+		imp.imported = make(map[string]bool)
+	}
+	pkg, err := imp.importer.Import(path)
+	if err != nil {
+		return nil, err
+	}
+	imp.imported[path] = true
+	return pkg, nil
+}
+
+func TestResolveIdents(t *testing.T) {
+	testenv.MustHaveGoBuild(t)
+
+	sources := []string{
+		`
+		package p
+		import "fmt"
+		import "math"
+		const pi = math.Pi
+		func sin(x float64) float64 {
+			return math.Sin(x)
+		}
+		var Println = fmt.Println
+		`,
+		`
+		package p
+		import "fmt"
+		type errorStringer struct { fmt.Stringer; error }
+		func f() string {
+			_ = "foo"
+			return fmt.Sprintf("%d", g())
+		}
+		func g() (x int) { return }
+		`,
+		`
+		package p
+		import . "go/parser"
+		import "sync"
+		func h() Mode { return ImportsOnly }
+		var _, x int = 1, 2
+		func init() {}
+		type T struct{ *sync.Mutex; a, b, c int}
+		type I interface{ m() }
+		var _ = T{a: 1, b: 2, c: 3}
+		func (_ T) m() {}
+		func (T) _() {}
+		var i I
+		var _ = i.m
+		func _(s []int) { for i, x := range s { _, _ = i, x } }
+		func _(x interface{}) {
+			switch x := x.(type) {
+			case int:
+				_ = x
+			}
+			switch {} // implicit 'true' tag
+		}
+		`,
+		`
+		package p
+		type S struct{}
+		func (T) _() {}
+		func (T) _() {}
+		`,
+		`
+		package p
+		func _() {
+		L0:
+		L1:
+			goto L0
+			for {
+				goto L1
+			}
+			if true {
+				goto L2
+			}
+		L2:
+		}
+		`,
+	}
+
+	pkgnames := []string{
+		"fmt",
+		"math",
+	}
+
+	// parse package files
+	fset := token.NewFileSet()
+	var files []*ast.File
+	for i, src := range sources {
+		f, err := parser.ParseFile(fset, fmt.Sprintf("sources[%d]", i), src, parser.DeclarationErrors)
+		if err != nil {
+			t.Fatal(err)
+		}
+		files = append(files, f)
+	}
+
+	// resolve and type-check package AST
+	importer := new(resolveTestImporter)
+	conf := Config{Importer: importer}
+	uses := make(map[*ast.Ident]Object)
+	defs := make(map[*ast.Ident]Object)
+	_, err := conf.Check("testResolveIdents", fset, files, &Info{Defs: defs, Uses: uses})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// check that all packages were imported
+	for _, name := range pkgnames {
+		if !importer.imported[name] {
+			t.Errorf("package %s not imported", name)
+		}
+	}
+
+	// check that qualified identifiers are resolved
+	for _, f := range files {
+		ast.Inspect(f, func(n ast.Node) bool {
+			if s, ok := n.(*ast.SelectorExpr); ok {
+				if x, ok := s.X.(*ast.Ident); ok {
+					obj := uses[x]
+					if obj == nil {
+						t.Errorf("%s: unresolved qualified identifier %s", fset.Position(x.Pos()), x.Name)
+						return false
+					}
+					if _, ok := obj.(*PkgName); ok && uses[s.Sel] == nil {
+						t.Errorf("%s: unresolved selector %s", fset.Position(s.Sel.Pos()), s.Sel.Name)
+						return false
+					}
+					return false
+				}
+				return false
+			}
+			return true
+		})
+	}
+
+	for id, obj := range uses {
+		if obj == nil {
+			t.Errorf("%s: Uses[%s] == nil", fset.Position(id.Pos()), id.Name)
+		}
+	}
+
+	// check that each identifier in the source is found in uses or defs or both
+	var both []string
+	for _, f := range files {
+		ast.Inspect(f, func(n ast.Node) bool {
+			if x, ok := n.(*ast.Ident); ok {
+				var objects int
+				if _, found := uses[x]; found {
+					objects |= 1
+					delete(uses, x)
+				}
+				if _, found := defs[x]; found {
+					objects |= 2
+					delete(defs, x)
+				}
+				if objects == 0 {
+					t.Errorf("%s: unresolved identifier %s", fset.Position(x.Pos()), x.Name)
+				} else if objects == 3 {
+					both = append(both, x.Name)
+				}
+				return false
+			}
+			return true
+		})
+	}
+
+	// check the expected set of idents that are simultaneously uses and defs
+	sort.Strings(both)
+	if got, want := fmt.Sprint(both), "[Mutex Stringer error]"; got != want {
+		t.Errorf("simultaneous uses/defs = %s, want %s", got, want)
+	}
+
+	// any left-over identifiers didn't exist in the source
+	for x := range uses {
+		t.Errorf("%s: identifier %s not present in source", fset.Position(x.Pos()), x.Name)
+	}
+	for x := range defs {
+		t.Errorf("%s: identifier %s not present in source", fset.Position(x.Pos()), x.Name)
+	}
+
+	// TODO(gri) add tests to check ImplicitObj callbacks
+}
diff --git a/src/go/types/return.go b/src/go/types/return.go
new file mode 100644
index 0000000..6628985
--- /dev/null
+++ b/src/go/types/return.go
@@ -0,0 +1,185 @@
+// 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.
+
+// This file implements isTerminating.
+
+package types
+
+import (
+	"go/ast"
+	"go/token"
+)
+
+// isTerminating reports if s is a terminating statement.
+// If s is labeled, label is the label name; otherwise s
+// is "".
+func (check *Checker) isTerminating(s ast.Stmt, label string) bool {
+	switch s := s.(type) {
+	default:
+		unreachable()
+
+	case *ast.BadStmt, *ast.DeclStmt, *ast.EmptyStmt, *ast.SendStmt,
+		*ast.IncDecStmt, *ast.AssignStmt, *ast.GoStmt, *ast.DeferStmt,
+		*ast.RangeStmt:
+		// no chance
+
+	case *ast.LabeledStmt:
+		return check.isTerminating(s.Stmt, s.Label.Name)
+
+	case *ast.ExprStmt:
+		// the predeclared (possibly parenthesized) panic() function is terminating
+		if call, _ := unparen(s.X).(*ast.CallExpr); call != nil {
+			if id, _ := call.Fun.(*ast.Ident); id != nil {
+				if _, obj := check.scope.LookupParent(id.Name, token.NoPos); obj != nil {
+					if b, _ := obj.(*Builtin); b != nil && b.id == _Panic {
+						return true
+					}
+				}
+			}
+		}
+
+	case *ast.ReturnStmt:
+		return true
+
+	case *ast.BranchStmt:
+		if s.Tok == token.GOTO || s.Tok == token.FALLTHROUGH {
+			return true
+		}
+
+	case *ast.BlockStmt:
+		return check.isTerminatingList(s.List, "")
+
+	case *ast.IfStmt:
+		if s.Else != nil &&
+			check.isTerminating(s.Body, "") &&
+			check.isTerminating(s.Else, "") {
+			return true
+		}
+
+	case *ast.SwitchStmt:
+		return check.isTerminatingSwitch(s.Body, label)
+
+	case *ast.TypeSwitchStmt:
+		return check.isTerminatingSwitch(s.Body, label)
+
+	case *ast.SelectStmt:
+		for _, s := range s.Body.List {
+			cc := s.(*ast.CommClause)
+			if !check.isTerminatingList(cc.Body, "") || hasBreakList(cc.Body, label, true) {
+				return false
+			}
+
+		}
+		return true
+
+	case *ast.ForStmt:
+		if s.Cond == nil && !hasBreak(s.Body, label, true) {
+			return true
+		}
+	}
+
+	return false
+}
+
+func (check *Checker) isTerminatingList(list []ast.Stmt, label string) bool {
+	n := len(list)
+	return n > 0 && check.isTerminating(list[n-1], label)
+}
+
+func (check *Checker) isTerminatingSwitch(body *ast.BlockStmt, label string) bool {
+	hasDefault := false
+	for _, s := range body.List {
+		cc := s.(*ast.CaseClause)
+		if cc.List == nil {
+			hasDefault = true
+		}
+		if !check.isTerminatingList(cc.Body, "") || hasBreakList(cc.Body, label, true) {
+			return false
+		}
+	}
+	return hasDefault
+}
+
+// TODO(gri) For nested breakable statements, the current implementation of hasBreak
+//	     will traverse the same subtree repeatedly, once for each label. Replace
+//           with a single-pass label/break matching phase.
+
+// hasBreak reports if s is or contains a break statement
+// referring to the label-ed statement or implicit-ly the
+// closest outer breakable statement.
+func hasBreak(s ast.Stmt, label string, implicit bool) bool {
+	switch s := s.(type) {
+	default:
+		unreachable()
+
+	case *ast.BadStmt, *ast.DeclStmt, *ast.EmptyStmt, *ast.ExprStmt,
+		*ast.SendStmt, *ast.IncDecStmt, *ast.AssignStmt, *ast.GoStmt,
+		*ast.DeferStmt, *ast.ReturnStmt:
+		// no chance
+
+	case *ast.LabeledStmt:
+		return hasBreak(s.Stmt, label, implicit)
+
+	case *ast.BranchStmt:
+		if s.Tok == token.BREAK {
+			if s.Label == nil {
+				return implicit
+			}
+			if s.Label.Name == label {
+				return true
+			}
+		}
+
+	case *ast.BlockStmt:
+		return hasBreakList(s.List, label, implicit)
+
+	case *ast.IfStmt:
+		if hasBreak(s.Body, label, implicit) ||
+			s.Else != nil && hasBreak(s.Else, label, implicit) {
+			return true
+		}
+
+	case *ast.CaseClause:
+		return hasBreakList(s.Body, label, implicit)
+
+	case *ast.SwitchStmt:
+		if label != "" && hasBreak(s.Body, label, false) {
+			return true
+		}
+
+	case *ast.TypeSwitchStmt:
+		if label != "" && hasBreak(s.Body, label, false) {
+			return true
+		}
+
+	case *ast.CommClause:
+		return hasBreakList(s.Body, label, implicit)
+
+	case *ast.SelectStmt:
+		if label != "" && hasBreak(s.Body, label, false) {
+			return true
+		}
+
+	case *ast.ForStmt:
+		if label != "" && hasBreak(s.Body, label, false) {
+			return true
+		}
+
+	case *ast.RangeStmt:
+		if label != "" && hasBreak(s.Body, label, false) {
+			return true
+		}
+	}
+
+	return false
+}
+
+func hasBreakList(list []ast.Stmt, label string, implicit bool) bool {
+	for _, s := range list {
+		if hasBreak(s, label, implicit) {
+			return true
+		}
+	}
+	return false
+}
diff --git a/src/go/types/scope.go b/src/go/types/scope.go
new file mode 100644
index 0000000..3502840
--- /dev/null
+++ b/src/go/types/scope.go
@@ -0,0 +1,190 @@
+// 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.
+
+// This file implements Scopes.
+
+package types
+
+import (
+	"bytes"
+	"fmt"
+	"go/token"
+	"io"
+	"sort"
+	"strings"
+)
+
+// TODO(gri) Provide scopes with a name or other mechanism so that
+//           objects can use that information for better printing.
+
+// A Scope maintains a set of objects and links to its containing
+// (parent) and contained (children) scopes. Objects may be inserted
+// and looked up by name. The zero value for Scope is a ready-to-use
+// empty scope.
+type Scope struct {
+	parent   *Scope
+	children []*Scope
+	elems    map[string]Object // lazily allocated
+	pos, end token.Pos         // scope extent; may be invalid
+	comment  string            // for debugging only
+}
+
+// NewScope returns a new, empty scope contained in the given parent
+// scope, if any.  The comment is for debugging only.
+func NewScope(parent *Scope, pos, end token.Pos, comment string) *Scope {
+	s := &Scope{parent, nil, nil, pos, end, comment}
+	// don't add children to Universe scope!
+	if parent != nil && parent != Universe {
+		parent.children = append(parent.children, s)
+	}
+	return s
+}
+
+// Parent returns the scope's containing (parent) scope.
+func (s *Scope) Parent() *Scope { return s.parent }
+
+// Len() returns the number of scope elements.
+func (s *Scope) Len() int { return len(s.elems) }
+
+// Names returns the scope's element names in sorted order.
+func (s *Scope) Names() []string {
+	names := make([]string, len(s.elems))
+	i := 0
+	for name := range s.elems {
+		names[i] = name
+		i++
+	}
+	sort.Strings(names)
+	return names
+}
+
+// NumChildren() returns the number of scopes nested in s.
+func (s *Scope) NumChildren() int { return len(s.children) }
+
+// Child returns the i'th child scope for 0 <= i < NumChildren().
+func (s *Scope) Child(i int) *Scope { return s.children[i] }
+
+// Lookup returns the object in scope s with the given name if such an
+// object exists; otherwise the result is nil.
+func (s *Scope) Lookup(name string) Object {
+	return s.elems[name]
+}
+
+// LookupParent follows the parent chain of scopes starting with s until
+// it finds a scope where Lookup(name) returns a non-nil object, and then
+// returns that scope and object. If a valid position pos is provided,
+// only objects that were declared at or before pos are considered.
+// If no such scope and object exists, the result is (nil, nil).
+//
+// Note that obj.Parent() may be different from the returned scope if the
+// object was inserted into the scope and already had a parent at that
+// time (see Insert, below). This can only happen for dot-imported objects
+// whose scope is the scope of the package that exported them.
+func (s *Scope) LookupParent(name string, pos token.Pos) (*Scope, Object) {
+	for ; s != nil; s = s.parent {
+		if obj := s.elems[name]; obj != nil && (!pos.IsValid() || obj.scopePos() <= pos) {
+			return s, obj
+		}
+	}
+	return nil, nil
+}
+
+// Insert attempts to insert an object obj into scope s.
+// If s already contains an alternative object alt with
+// the same name, Insert leaves s unchanged and returns alt.
+// Otherwise it inserts obj, sets the object's parent scope
+// if not already set, and returns nil.
+func (s *Scope) Insert(obj Object) Object {
+	name := obj.Name()
+	if alt := s.elems[name]; alt != nil {
+		return alt
+	}
+	if s.elems == nil {
+		s.elems = make(map[string]Object)
+	}
+	s.elems[name] = obj
+	if obj.Parent() == nil {
+		obj.setParent(s)
+	}
+	return nil
+}
+
+// Pos and End describe the scope's source code extent [pos, end).
+// The results are guaranteed to be valid only if the type-checked
+// AST has complete position information. The extent is undefined
+// for Universe and package scopes.
+func (s *Scope) Pos() token.Pos { return s.pos }
+func (s *Scope) End() token.Pos { return s.end }
+
+// Contains returns true if pos is within the scope's extent.
+// The result is guaranteed to be valid only if the type-checked
+// AST has complete position information.
+func (s *Scope) Contains(pos token.Pos) bool {
+	return s.pos <= pos && pos < s.end
+}
+
+// Innermost returns the innermost (child) scope containing
+// pos. If pos is not within any scope, the result is nil.
+// The result is also nil for the Universe scope.
+// The result is guaranteed to be valid only if the type-checked
+// AST has complete position information.
+func (s *Scope) Innermost(pos token.Pos) *Scope {
+	// Package scopes do not have extents since they may be
+	// discontiguous, so iterate over the package's files.
+	if s.parent == Universe {
+		for _, s := range s.children {
+			if inner := s.Innermost(pos); inner != nil {
+				return inner
+			}
+		}
+	}
+
+	if s.Contains(pos) {
+		for _, s := range s.children {
+			if s.Contains(pos) {
+				return s.Innermost(pos)
+			}
+		}
+		return s
+	}
+	return nil
+}
+
+// WriteTo writes a string representation of the scope to w,
+// with the scope elements sorted by name.
+// The level of indentation is controlled by n >= 0, with
+// n == 0 for no indentation.
+// If recurse is set, it also writes nested (children) scopes.
+func (s *Scope) WriteTo(w io.Writer, n int, recurse bool) {
+	const ind = ".  "
+	indn := strings.Repeat(ind, n)
+
+	fmt.Fprintf(w, "%s%s scope %p {", indn, s.comment, s)
+	if len(s.elems) == 0 {
+		fmt.Fprintf(w, "}\n")
+		return
+	}
+
+	fmt.Fprintln(w)
+	indn1 := indn + ind
+	for _, name := range s.Names() {
+		fmt.Fprintf(w, "%s%s\n", indn1, s.elems[name])
+	}
+
+	if recurse {
+		for _, s := range s.children {
+			fmt.Fprintln(w)
+			s.WriteTo(w, n+1, recurse)
+		}
+	}
+
+	fmt.Fprintf(w, "%s}", indn)
+}
+
+// String returns a string representation of the scope, for debugging.
+func (s *Scope) String() string {
+	var buf bytes.Buffer
+	s.WriteTo(&buf, 0, false)
+	return buf.String()
+}
diff --git a/src/go/types/selection.go b/src/go/types/selection.go
new file mode 100644
index 0000000..124e0d3
--- /dev/null
+++ b/src/go/types/selection.go
@@ -0,0 +1,143 @@
+// 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.
+
+// This file implements Selections.
+
+package types
+
+import (
+	"bytes"
+	"fmt"
+)
+
+// SelectionKind describes the kind of a selector expression x.f
+// (excluding qualified identifiers).
+type SelectionKind int
+
+const (
+	FieldVal   SelectionKind = iota // x.f is a struct field selector
+	MethodVal                       // x.f is a method selector
+	MethodExpr                      // x.f is a method expression
+)
+
+// A Selection describes a selector expression x.f.
+// For the declarations:
+//
+//	type T struct{ x int; E }
+//	type E struct{}
+//	func (e E) m() {}
+//	var p *T
+//
+// the following relations exist:
+//
+//	Selector    Kind          Recv    Obj    Type               Index     Indirect
+//
+//	p.x         FieldVal      T       x      int                {0}       true
+//	p.m         MethodVal     *T      m      func (e *T) m()    {1, 0}    true
+//	T.m         MethodExpr    T       m      func m(_ T)        {1, 0}    false
+//
+type Selection struct {
+	kind     SelectionKind
+	recv     Type   // type of x
+	obj      Object // object denoted by x.f
+	index    []int  // path from x to x.f
+	indirect bool   // set if there was any pointer indirection on the path
+}
+
+// Kind returns the selection kind.
+func (s *Selection) Kind() SelectionKind { return s.kind }
+
+// Recv returns the type of x in x.f.
+func (s *Selection) Recv() Type { return s.recv }
+
+// Obj returns the object denoted by x.f; a *Var for
+// a field selection, and a *Func in all other cases.
+func (s *Selection) Obj() Object { return s.obj }
+
+// Type returns the type of x.f, which may be different from the type of f.
+// See Selection for more information.
+func (s *Selection) Type() Type {
+	switch s.kind {
+	case MethodVal:
+		// The type of x.f is a method with its receiver type set
+		// to the type of x.
+		sig := *s.obj.(*Func).typ.(*Signature)
+		recv := *sig.recv
+		recv.typ = s.recv
+		sig.recv = &recv
+		return &sig
+
+	case MethodExpr:
+		// The type of x.f is a function (without receiver)
+		// and an additional first argument with the same type as x.
+		// TODO(gri) Similar code is already in call.go - factor!
+		// TODO(gri) Compute this eagerly to avoid allocations.
+		sig := *s.obj.(*Func).typ.(*Signature)
+		arg0 := *sig.recv
+		sig.recv = nil
+		arg0.typ = s.recv
+		var params []*Var
+		if sig.params != nil {
+			params = sig.params.vars
+		}
+		sig.params = NewTuple(append([]*Var{&arg0}, params...)...)
+		return &sig
+	}
+
+	// In all other cases, the type of x.f is the type of x.
+	return s.obj.Type()
+}
+
+// Index describes the path from x to f in x.f.
+// The last index entry is the field or method index of the type declaring f;
+// either:
+//
+//	1) the list of declared methods of a named type; or
+//	2) the list of methods of an interface type; or
+//	3) the list of fields of a struct type.
+//
+// The earlier index entries are the indices of the embedded fields implicitly
+// traversed to get from (the type of) x to f, starting at embedding depth 0.
+func (s *Selection) Index() []int { return s.index }
+
+// Indirect reports whether any pointer indirection was required to get from
+// x to f in x.f.
+func (s *Selection) Indirect() bool { return s.indirect }
+
+func (s *Selection) String() string { return SelectionString(s, nil) }
+
+// SelectionString returns the string form of s.
+// The Qualifier controls the printing of
+// package-level objects, and may be nil.
+//
+// Examples:
+//	"field (T) f int"
+//	"method (T) f(X) Y"
+//	"method expr (T) f(X) Y"
+//
+func SelectionString(s *Selection, qf Qualifier) string {
+	var k string
+	switch s.kind {
+	case FieldVal:
+		k = "field "
+	case MethodVal:
+		k = "method "
+	case MethodExpr:
+		k = "method expr "
+	default:
+		unreachable()
+	}
+	var buf bytes.Buffer
+	buf.WriteString(k)
+	buf.WriteByte('(')
+	WriteType(&buf, s.Recv(), qf)
+	fmt.Fprintf(&buf, ") %s", s.obj.Name())
+	if T := s.Type(); s.kind == FieldVal {
+		buf.WriteByte(' ')
+		WriteType(&buf, T, qf)
+	} else {
+		WriteSignature(&buf, T.(*Signature), qf)
+	}
+	return buf.String()
+}
diff --git a/src/go/types/self_test.go b/src/go/types/self_test.go
new file mode 100644
index 0000000..10ad06f
--- /dev/null
+++ b/src/go/types/self_test.go
@@ -0,0 +1,102 @@
+// 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 types_test
+
+import (
+	"flag"
+	"fmt"
+	"go/ast"
+	"go/importer"
+	"go/parser"
+	"go/token"
+	"path/filepath"
+	"testing"
+	"time"
+
+	. "go/types"
+)
+
+var benchmark = flag.Bool("b", false, "run benchmarks")
+
+func TestSelf(t *testing.T) {
+	fset := token.NewFileSet()
+	files, err := pkgFiles(fset, ".")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	conf := Config{Importer: importer.Default()}
+	_, err = conf.Check("go/types", fset, files, nil)
+	if err != nil {
+		// Importing go/constant doesn't work in the
+		// build dashboard environment. Don't report an error
+		// for now so that the build remains green.
+		// TODO(gri) fix this
+		t.Log(err) // replace w/ t.Fatal eventually
+		return
+	}
+}
+
+func TestBenchmark(t *testing.T) {
+	if !*benchmark {
+		return
+	}
+
+	// We're not using testing's benchmarking mechanism directly
+	// because we want custom output.
+
+	for _, p := range []string{"types", "constant", filepath.Join("internal", "gcimporter")} {
+		path := filepath.Join("..", p)
+		runbench(t, path, false)
+		runbench(t, path, true)
+		fmt.Println()
+	}
+}
+
+func runbench(t *testing.T, path string, ignoreFuncBodies bool) {
+	fset := token.NewFileSet()
+	files, err := pkgFiles(fset, path)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	b := testing.Benchmark(func(b *testing.B) {
+		for i := 0; i < b.N; i++ {
+			conf := Config{IgnoreFuncBodies: ignoreFuncBodies}
+			conf.Check(path, fset, files, nil)
+		}
+	})
+
+	// determine line count
+	lines := 0
+	fset.Iterate(func(f *token.File) bool {
+		lines += f.LineCount()
+		return true
+	})
+
+	d := time.Duration(b.NsPerOp())
+	fmt.Printf(
+		"%s: %s for %d lines (%d lines/s), ignoreFuncBodies = %v\n",
+		filepath.Base(path), d, lines, int64(float64(lines)/d.Seconds()), ignoreFuncBodies,
+	)
+}
+
+func pkgFiles(fset *token.FileSet, path string) ([]*ast.File, error) {
+	filenames, err := pkgFilenames(path) // from stdlib_test.go
+	if err != nil {
+		return nil, err
+	}
+
+	var files []*ast.File
+	for _, filename := range filenames {
+		file, err := parser.ParseFile(fset, filename, nil, 0)
+		if err != nil {
+			return nil, err
+		}
+		files = append(files, file)
+	}
+
+	return files, nil
+}
diff --git a/src/go/types/sizes.go b/src/go/types/sizes.go
new file mode 100644
index 0000000..56fb310
--- /dev/null
+++ b/src/go/types/sizes.go
@@ -0,0 +1,211 @@
+// 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.
+
+// This file implements Sizes.
+
+package types
+
+// Sizes defines the sizing functions for package unsafe.
+type Sizes interface {
+	// Alignof returns the alignment of a variable of type T.
+	// Alignof must implement the alignment guarantees required by the spec.
+	Alignof(T Type) int64
+
+	// Offsetsof returns the offsets of the given struct fields, in bytes.
+	// Offsetsof must implement the offset guarantees required by the spec.
+	Offsetsof(fields []*Var) []int64
+
+	// Sizeof returns the size of a variable of type T.
+	// Sizeof must implement the size guarantees required by the spec.
+	Sizeof(T Type) int64
+}
+
+// StdSizes is a convenience type for creating commonly used Sizes.
+// It makes the following simplifying assumptions:
+//
+//	- The size of explicitly sized basic types (int16, etc.) is the
+//	  specified size.
+//	- The size of strings and interfaces is 2*WordSize.
+//	- The size of slices is 3*WordSize.
+//	- The size of an array of n elements corresponds to the size of
+//	  a struct of n consecutive fields of the array's element type.
+//      - The size of a struct is the offset of the last field plus that
+//	  field's size. As with all element types, if the struct is used
+//	  in an array its size must first be aligned to a multiple of the
+//	  struct's alignment.
+//	- All other types have size WordSize.
+//	- Arrays and structs are aligned per spec definition; all other
+//	  types are naturally aligned with a maximum alignment MaxAlign.
+//
+// *StdSizes implements Sizes.
+//
+type StdSizes struct {
+	WordSize int64 // word size in bytes - must be >= 4 (32bits)
+	MaxAlign int64 // maximum alignment in bytes - must be >= 1
+}
+
+func (s *StdSizes) Alignof(T Type) int64 {
+	// For arrays and structs, alignment is defined in terms
+	// of alignment of the elements and fields, respectively.
+	switch t := T.Underlying().(type) {
+	case *Array:
+		// spec: "For a variable x of array type: unsafe.Alignof(x)
+		// is the same as unsafe.Alignof(x[0]), but at least 1."
+		return s.Alignof(t.elem)
+	case *Struct:
+		// spec: "For a variable x of struct type: unsafe.Alignof(x)
+		// is the largest of the values unsafe.Alignof(x.f) for each
+		// field f of x, but at least 1."
+		max := int64(1)
+		for _, f := range t.fields {
+			if a := s.Alignof(f.typ); a > max {
+				max = a
+			}
+		}
+		return max
+	}
+	a := s.Sizeof(T) // may be 0
+	// spec: "For a variable x of any type: unsafe.Alignof(x) is at least 1."
+	if a < 1 {
+		return 1
+	}
+	if a > s.MaxAlign {
+		return s.MaxAlign
+	}
+	return a
+}
+
+func (s *StdSizes) Offsetsof(fields []*Var) []int64 {
+	offsets := make([]int64, len(fields))
+	var o int64
+	for i, f := range fields {
+		a := s.Alignof(f.typ)
+		o = align(o, a)
+		offsets[i] = o
+		o += s.Sizeof(f.typ)
+	}
+	return offsets
+}
+
+var basicSizes = [...]byte{
+	Bool:       1,
+	Int8:       1,
+	Int16:      2,
+	Int32:      4,
+	Int64:      8,
+	Uint8:      1,
+	Uint16:     2,
+	Uint32:     4,
+	Uint64:     8,
+	Float32:    4,
+	Float64:    8,
+	Complex64:  8,
+	Complex128: 16,
+}
+
+func (s *StdSizes) Sizeof(T Type) int64 {
+	switch t := T.Underlying().(type) {
+	case *Basic:
+		assert(isTyped(T))
+		k := t.kind
+		if int(k) < len(basicSizes) {
+			if s := basicSizes[k]; s > 0 {
+				return int64(s)
+			}
+		}
+		if k == String {
+			return s.WordSize * 2
+		}
+	case *Array:
+		n := t.len
+		if n == 0 {
+			return 0
+		}
+		a := s.Alignof(t.elem)
+		z := s.Sizeof(t.elem)
+		return align(z, a)*(n-1) + z
+	case *Slice:
+		return s.WordSize * 3
+	case *Struct:
+		n := t.NumFields()
+		if n == 0 {
+			return 0
+		}
+		offsets := t.offsets
+		if t.offsets == nil {
+			// compute offsets on demand
+			offsets = s.Offsetsof(t.fields)
+			t.offsets = offsets
+		}
+		return offsets[n-1] + s.Sizeof(t.fields[n-1].typ)
+	case *Interface:
+		return s.WordSize * 2
+	}
+	return s.WordSize // catch-all
+}
+
+// stdSizes is used if Config.Sizes == nil.
+var stdSizes = StdSizes{8, 8}
+
+func (conf *Config) alignof(T Type) int64 {
+	if s := conf.Sizes; s != nil {
+		if a := s.Alignof(T); a >= 1 {
+			return a
+		}
+		panic("Config.Sizes.Alignof returned an alignment < 1")
+	}
+	return stdSizes.Alignof(T)
+}
+
+func (conf *Config) offsetsof(T *Struct) []int64 {
+	offsets := T.offsets
+	if offsets == nil && T.NumFields() > 0 {
+		// compute offsets on demand
+		if s := conf.Sizes; s != nil {
+			offsets = s.Offsetsof(T.fields)
+			// sanity checks
+			if len(offsets) != T.NumFields() {
+				panic("Config.Sizes.Offsetsof returned the wrong number of offsets")
+			}
+			for _, o := range offsets {
+				if o < 0 {
+					panic("Config.Sizes.Offsetsof returned an offset < 0")
+				}
+			}
+		} else {
+			offsets = stdSizes.Offsetsof(T.fields)
+		}
+		T.offsets = offsets
+	}
+	return offsets
+}
+
+// offsetof returns the offset of the field specified via
+// the index sequence relative to typ. All embedded fields
+// must be structs (rather than pointer to structs).
+func (conf *Config) offsetof(typ Type, index []int) int64 {
+	var o int64
+	for _, i := range index {
+		s := typ.Underlying().(*Struct)
+		o += conf.offsetsof(s)[i]
+		typ = s.fields[i].typ
+	}
+	return o
+}
+
+func (conf *Config) sizeof(T Type) int64 {
+	if s := conf.Sizes; s != nil {
+		if z := s.Sizeof(T); z >= 0 {
+			return z
+		}
+		panic("Config.Sizes.Sizeof returned a size < 0")
+	}
+	return stdSizes.Sizeof(T)
+}
+
+// align returns the smallest y >= x such that y % a == 0.
+func align(x, a int64) int64 {
+	y := x + a - 1
+	return y - y%a
+}
diff --git a/src/go/types/stdlib_test.go b/src/go/types/stdlib_test.go
new file mode 100644
index 0000000..c6c946e
--- /dev/null
+++ b/src/go/types/stdlib_test.go
@@ -0,0 +1,279 @@
+// 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.
+
+// This file tests types.Check by using it to
+// typecheck the standard library and tests.
+
+package types_test
+
+import (
+	"fmt"
+	"go/ast"
+	"go/build"
+	"go/importer"
+	"go/parser"
+	"go/scanner"
+	"go/token"
+	"internal/testenv"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"runtime"
+	"strings"
+	"testing"
+	"time"
+
+	. "go/types"
+)
+
+var (
+	pkgCount int // number of packages processed
+	start    time.Time
+
+	// Use the same importer for all std lib tests to
+	// avoid repeated importing of the same packages.
+	stdLibImporter = importer.Default()
+)
+
+func TestStdlib(t *testing.T) {
+	testenv.MustHaveGoBuild(t)
+
+	start = time.Now()
+	walkDirs(t, filepath.Join(runtime.GOROOT(), "src"))
+	if testing.Verbose() {
+		fmt.Println(pkgCount, "packages typechecked in", time.Since(start))
+	}
+}
+
+// firstComment returns the contents of the first comment in
+// the given file, assuming there's one within the first KB.
+func firstComment(filename string) string {
+	f, err := os.Open(filename)
+	if err != nil {
+		return ""
+	}
+	defer f.Close()
+
+	var src [1 << 10]byte // read at most 1KB
+	n, _ := f.Read(src[:])
+
+	var s scanner.Scanner
+	s.Init(fset.AddFile("", fset.Base(), n), src[:n], nil, scanner.ScanComments)
+	for {
+		_, tok, lit := s.Scan()
+		switch tok {
+		case token.COMMENT:
+			// remove trailing */ of multi-line comment
+			if lit[1] == '*' {
+				lit = lit[:len(lit)-2]
+			}
+			return strings.TrimSpace(lit[2:])
+		case token.EOF:
+			return ""
+		}
+	}
+}
+
+func testTestDir(t *testing.T, path string, ignore ...string) {
+	files, err := ioutil.ReadDir(path)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	excluded := make(map[string]bool)
+	for _, filename := range ignore {
+		excluded[filename] = true
+	}
+
+	fset := token.NewFileSet()
+	for _, f := range files {
+		// filter directory contents
+		if f.IsDir() || !strings.HasSuffix(f.Name(), ".go") || excluded[f.Name()] {
+			continue
+		}
+
+		// get per-file instructions
+		expectErrors := false
+		filename := filepath.Join(path, f.Name())
+		if cmd := firstComment(filename); cmd != "" {
+			switch cmd {
+			case "skip", "compiledir":
+				continue // ignore this file
+			case "errorcheck":
+				expectErrors = true
+			}
+		}
+
+		// parse and type-check file
+		file, err := parser.ParseFile(fset, filename, nil, 0)
+		if err == nil {
+			conf := Config{Importer: stdLibImporter}
+			_, err = conf.Check(filename, fset, []*ast.File{file}, nil)
+		}
+
+		if expectErrors {
+			if err == nil {
+				t.Errorf("expected errors but found none in %s", filename)
+			}
+		} else {
+			if err != nil {
+				t.Error(err)
+			}
+		}
+	}
+}
+
+func TestStdTest(t *testing.T) {
+	testenv.MustHaveGoBuild(t)
+
+	// test/recover4.go is only built for Linux and Darwin.
+	// TODO(gri) Remove once tests consider +build tags (issue 10370).
+	if runtime.GOOS != "linux" && runtime.GOOS != "darwin" {
+		return
+	}
+
+	testTestDir(t, filepath.Join(runtime.GOROOT(), "test"),
+		"cmplxdivide.go", // also needs file cmplxdivide1.go - ignore
+		"sigchld.go",     // don't work on Windows; testTestDir should consult build tags
+	)
+}
+
+func TestStdFixed(t *testing.T) {
+	testenv.MustHaveGoBuild(t)
+
+	testTestDir(t, filepath.Join(runtime.GOROOT(), "test", "fixedbugs"),
+		"bug248.go", "bug302.go", "bug369.go", // complex test instructions - ignore
+		"bug459.go",      // possibly incorrect test - see issue 6703 (pending spec clarification)
+		"issue3924.go",   // possibly incorrect test - see issue 6671 (pending spec clarification)
+		"issue6889.go",   // gc-specific test
+		"issue7746.go",   // large constants - consumes too much memory
+		"issue11326.go",  // large constants
+		"issue11326b.go", // large constants
+	)
+}
+
+func TestStdKen(t *testing.T) {
+	testenv.MustHaveGoBuild(t)
+
+	testTestDir(t, filepath.Join(runtime.GOROOT(), "test", "ken"))
+}
+
+// Package paths of excluded packages.
+var excluded = map[string]bool{
+	"builtin": true,
+}
+
+// typecheck typechecks the given package files.
+func typecheck(t *testing.T, path string, filenames []string) {
+	fset := token.NewFileSet()
+
+	// parse package files
+	var files []*ast.File
+	for _, filename := range filenames {
+		file, err := parser.ParseFile(fset, filename, nil, parser.AllErrors)
+		if err != nil {
+			// the parser error may be a list of individual errors; report them all
+			if list, ok := err.(scanner.ErrorList); ok {
+				for _, err := range list {
+					t.Error(err)
+				}
+				return
+			}
+			t.Error(err)
+			return
+		}
+
+		if testing.Verbose() {
+			if len(files) == 0 {
+				fmt.Println("package", file.Name.Name)
+			}
+			fmt.Println("\t", filename)
+		}
+
+		files = append(files, file)
+	}
+
+	// typecheck package files
+	conf := Config{
+		Error:    func(err error) { t.Error(err) },
+		Importer: stdLibImporter,
+	}
+	info := Info{Uses: make(map[*ast.Ident]Object)}
+	conf.Check(path, fset, files, &info)
+	pkgCount++
+
+	// Perform checks of API invariants.
+
+	// All Objects have a package, except predeclared ones.
+	errorError := Universe.Lookup("error").Type().Underlying().(*Interface).ExplicitMethod(0) // (error).Error
+	for id, obj := range info.Uses {
+		predeclared := obj == Universe.Lookup(obj.Name()) || obj == errorError
+		if predeclared == (obj.Pkg() != nil) {
+			posn := fset.Position(id.Pos())
+			if predeclared {
+				t.Errorf("%s: predeclared object with package: %s", posn, obj)
+			} else {
+				t.Errorf("%s: user-defined object without package: %s", posn, obj)
+			}
+		}
+	}
+}
+
+// pkgFilenames returns the list of package filenames for the given directory.
+func pkgFilenames(dir string) ([]string, error) {
+	ctxt := build.Default
+	ctxt.CgoEnabled = false
+	pkg, err := ctxt.ImportDir(dir, 0)
+	if err != nil {
+		if _, nogo := err.(*build.NoGoError); nogo {
+			return nil, nil // no *.go files, not an error
+		}
+		return nil, err
+	}
+	if excluded[pkg.ImportPath] {
+		return nil, nil
+	}
+	var filenames []string
+	for _, name := range pkg.GoFiles {
+		filenames = append(filenames, filepath.Join(pkg.Dir, name))
+	}
+	for _, name := range pkg.TestGoFiles {
+		filenames = append(filenames, filepath.Join(pkg.Dir, name))
+	}
+	return filenames, nil
+}
+
+// Note: Could use filepath.Walk instead of walkDirs but that wouldn't
+//       necessarily be shorter or clearer after adding the code to
+//       terminate early for -short tests.
+
+func walkDirs(t *testing.T, dir string) {
+	// limit run time for short tests
+	if testing.Short() && time.Since(start) >= 750*time.Millisecond {
+		return
+	}
+
+	fis, err := ioutil.ReadDir(dir)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+
+	// typecheck package in directory
+	files, err := pkgFilenames(dir)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	if files != nil {
+		typecheck(t, dir, files)
+	}
+
+	// traverse subdirectories, but don't walk into testdata
+	for _, fi := range fis {
+		if fi.IsDir() && fi.Name() != "testdata" {
+			walkDirs(t, filepath.Join(dir, fi.Name()))
+		}
+	}
+}
diff --git a/src/go/types/stmt.go b/src/go/types/stmt.go
new file mode 100644
index 0000000..88a1d9b
--- /dev/null
+++ b/src/go/types/stmt.go
@@ -0,0 +1,744 @@
+// 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.
+
+// This file implements typechecking of statements.
+
+package types
+
+import (
+	"fmt"
+	"go/ast"
+	"go/constant"
+	"go/token"
+)
+
+func (check *Checker) funcBody(decl *declInfo, name string, sig *Signature, body *ast.BlockStmt) {
+	if trace {
+		if name == "" {
+			name = "<function literal>"
+		}
+		fmt.Printf("--- %s: %s {\n", name, sig)
+		defer fmt.Println("--- <end>")
+	}
+
+	// set function scope extent
+	sig.scope.pos = body.Pos()
+	sig.scope.end = body.End()
+
+	// save/restore current context and setup function context
+	// (and use 0 indentation at function start)
+	defer func(ctxt context, indent int) {
+		check.context = ctxt
+		check.indent = indent
+	}(check.context, check.indent)
+	check.context = context{
+		decl:  decl,
+		scope: sig.scope,
+		sig:   sig,
+	}
+	check.indent = 0
+
+	check.stmtList(0, body.List)
+
+	if check.hasLabel {
+		check.labels(body)
+	}
+
+	if sig.results.Len() > 0 && !check.isTerminating(body, "") {
+		check.error(body.Rbrace, "missing return")
+	}
+
+	// spec: "Implementation restriction: A compiler may make it illegal to
+	// declare a variable inside a function body if the variable is never used."
+	// (One could check each scope after use, but that distributes this check
+	// over several places because CloseScope is not always called explicitly.)
+	check.usage(sig.scope)
+}
+
+func (check *Checker) usage(scope *Scope) {
+	for _, obj := range scope.elems {
+		if v, _ := obj.(*Var); v != nil && !v.used {
+			check.softErrorf(v.pos, "%s declared but not used", v.name)
+		}
+	}
+	for _, scope := range scope.children {
+		check.usage(scope)
+	}
+}
+
+// stmtContext is a bitset describing which
+// control-flow statements are permissible.
+type stmtContext uint
+
+const (
+	breakOk stmtContext = 1 << iota
+	continueOk
+	fallthroughOk
+)
+
+func (check *Checker) simpleStmt(s ast.Stmt) {
+	if s != nil {
+		check.stmt(0, s)
+	}
+}
+
+func (check *Checker) stmtList(ctxt stmtContext, list []ast.Stmt) {
+	ok := ctxt&fallthroughOk != 0
+	inner := ctxt &^ fallthroughOk
+	for i, s := range list {
+		inner := inner
+		if ok && i+1 == len(list) {
+			inner |= fallthroughOk
+		}
+		check.stmt(inner, s)
+	}
+}
+
+func (check *Checker) multipleDefaults(list []ast.Stmt) {
+	var first ast.Stmt
+	for _, s := range list {
+		var d ast.Stmt
+		switch c := s.(type) {
+		case *ast.CaseClause:
+			if len(c.List) == 0 {
+				d = s
+			}
+		case *ast.CommClause:
+			if c.Comm == nil {
+				d = s
+			}
+		default:
+			check.invalidAST(s.Pos(), "case/communication clause expected")
+		}
+		if d != nil {
+			if first != nil {
+				check.errorf(d.Pos(), "multiple defaults (first at %s)", first.Pos())
+			} else {
+				first = d
+			}
+		}
+	}
+}
+
+func (check *Checker) openScope(s ast.Stmt, comment string) {
+	scope := NewScope(check.scope, s.Pos(), s.End(), comment)
+	check.recordScope(s, scope)
+	check.scope = scope
+}
+
+func (check *Checker) closeScope() {
+	check.scope = check.scope.Parent()
+}
+
+func assignOp(op token.Token) token.Token {
+	// token_test.go verifies the token ordering this function relies on
+	if token.ADD_ASSIGN <= op && op <= token.AND_NOT_ASSIGN {
+		return op + (token.ADD - token.ADD_ASSIGN)
+	}
+	return token.ILLEGAL
+}
+
+func (check *Checker) suspendedCall(keyword string, call *ast.CallExpr) {
+	var x operand
+	var msg string
+	switch check.rawExpr(&x, call, nil) {
+	case conversion:
+		msg = "requires function call, not conversion"
+	case expression:
+		msg = "discards result of"
+	case statement:
+		return
+	default:
+		unreachable()
+	}
+	check.errorf(x.pos(), "%s %s %s", keyword, msg, &x)
+}
+
+func (check *Checker) caseValues(x operand /* copy argument (not *operand!) */, values []ast.Expr) {
+	// No duplicate checking for now. See issue 4524.
+	for _, e := range values {
+		var y operand
+		check.expr(&y, e)
+		if y.mode == invalid {
+			return
+		}
+		// TODO(gri) The convertUntyped call pair below appears in other places. Factor!
+		// Order matters: By comparing y against x, error positions are at the case values.
+		check.convertUntyped(&y, x.typ)
+		if y.mode == invalid {
+			return
+		}
+		check.convertUntyped(&x, y.typ)
+		if x.mode == invalid {
+			return
+		}
+		check.comparison(&y, &x, token.EQL)
+	}
+}
+
+func (check *Checker) caseTypes(x *operand, xtyp *Interface, types []ast.Expr, seen map[Type]token.Pos) (T Type) {
+L:
+	for _, e := range types {
+		T = check.typOrNil(e)
+		if T == Typ[Invalid] {
+			continue
+		}
+		// complain about duplicate types
+		// TODO(gri) use a type hash to avoid quadratic algorithm
+		for t, pos := range seen {
+			if T == nil && t == nil || T != nil && t != nil && Identical(T, t) {
+				// talk about "case" rather than "type" because of nil case
+				check.error(e.Pos(), "duplicate case in type switch")
+				check.errorf(pos, "\tprevious case %s", T) // secondary error, \t indented
+				continue L
+			}
+		}
+		seen[T] = e.Pos()
+		if T != nil {
+			check.typeAssertion(e.Pos(), x, xtyp, T)
+		}
+	}
+	return
+}
+
+// stmt typechecks statement s.
+func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
+	// statements cannot use iota in general
+	// (constant declarations set it explicitly)
+	assert(check.iota == nil)
+
+	// statements must end with the same top scope as they started with
+	if debug {
+		defer func(scope *Scope) {
+			// don't check if code is panicking
+			if p := recover(); p != nil {
+				panic(p)
+			}
+			assert(scope == check.scope)
+		}(check.scope)
+	}
+
+	inner := ctxt &^ fallthroughOk
+	switch s := s.(type) {
+	case *ast.BadStmt, *ast.EmptyStmt:
+		// ignore
+
+	case *ast.DeclStmt:
+		check.declStmt(s.Decl)
+
+	case *ast.LabeledStmt:
+		check.hasLabel = true
+		check.stmt(ctxt, s.Stmt)
+
+	case *ast.ExprStmt:
+		// spec: "With the exception of specific built-in functions,
+		// function and method calls and receive operations can appear
+		// in statement context. Such statements may be parenthesized."
+		var x operand
+		kind := check.rawExpr(&x, s.X, nil)
+		var msg string
+		switch x.mode {
+		default:
+			if kind == statement {
+				return
+			}
+			msg = "is not used"
+		case builtin:
+			msg = "must be called"
+		case typexpr:
+			msg = "is not an expression"
+		}
+		check.errorf(x.pos(), "%s %s", &x, msg)
+
+	case *ast.SendStmt:
+		var ch, x operand
+		check.expr(&ch, s.Chan)
+		check.expr(&x, s.Value)
+		if ch.mode == invalid || x.mode == invalid {
+			return
+		}
+		if tch, ok := ch.typ.Underlying().(*Chan); !ok || tch.dir == RecvOnly || !check.assignment(&x, tch.elem) {
+			if x.mode != invalid {
+				check.invalidOp(ch.pos(), "cannot send %s to channel %s", &x, &ch)
+			}
+		}
+
+	case *ast.IncDecStmt:
+		var op token.Token
+		switch s.Tok {
+		case token.INC:
+			op = token.ADD
+		case token.DEC:
+			op = token.SUB
+		default:
+			check.invalidAST(s.TokPos, "unknown inc/dec operation %s", s.Tok)
+			return
+		}
+		var x operand
+		Y := &ast.BasicLit{ValuePos: s.X.Pos(), Kind: token.INT, Value: "1"} // use x's position
+		check.binary(&x, nil, s.X, Y, op)
+		if x.mode == invalid {
+			return
+		}
+		check.assignVar(s.X, &x)
+
+	case *ast.AssignStmt:
+		switch s.Tok {
+		case token.ASSIGN, token.DEFINE:
+			if len(s.Lhs) == 0 {
+				check.invalidAST(s.Pos(), "missing lhs in assignment")
+				return
+			}
+			if s.Tok == token.DEFINE {
+				check.shortVarDecl(s.TokPos, s.Lhs, s.Rhs)
+			} else {
+				// regular assignment
+				check.assignVars(s.Lhs, s.Rhs)
+			}
+
+		default:
+			// assignment operations
+			if len(s.Lhs) != 1 || len(s.Rhs) != 1 {
+				check.errorf(s.TokPos, "assignment operation %s requires single-valued expressions", s.Tok)
+				return
+			}
+			op := assignOp(s.Tok)
+			if op == token.ILLEGAL {
+				check.invalidAST(s.TokPos, "unknown assignment operation %s", s.Tok)
+				return
+			}
+			var x operand
+			check.binary(&x, nil, s.Lhs[0], s.Rhs[0], op)
+			if x.mode == invalid {
+				return
+			}
+			check.assignVar(s.Lhs[0], &x)
+		}
+
+	case *ast.GoStmt:
+		check.suspendedCall("go", s.Call)
+
+	case *ast.DeferStmt:
+		check.suspendedCall("defer", s.Call)
+
+	case *ast.ReturnStmt:
+		res := check.sig.results
+		if res.Len() > 0 {
+			// function returns results
+			// (if one, say the first, result parameter is named, all of them are named)
+			if len(s.Results) == 0 && res.vars[0].name != "" {
+				// spec: "Implementation restriction: A compiler may disallow an empty expression
+				// list in a "return" statement if a different entity (constant, type, or variable)
+				// with the same name as a result parameter is in scope at the place of the return."
+				for _, obj := range res.vars {
+					if _, alt := check.scope.LookupParent(obj.name, check.pos); alt != nil && alt != obj {
+						check.errorf(s.Pos(), "result parameter %s not in scope at return", obj.name)
+						check.errorf(alt.Pos(), "\tinner declaration of %s", obj)
+						// ok to continue
+					}
+				}
+			} else {
+				// return has results or result parameters are unnamed
+				check.initVars(res.vars, s.Results, s.Return)
+			}
+		} else if len(s.Results) > 0 {
+			check.error(s.Results[0].Pos(), "no result values expected")
+			check.use(s.Results...)
+		}
+
+	case *ast.BranchStmt:
+		if s.Label != nil {
+			check.hasLabel = true
+			return // checked in 2nd pass (check.labels)
+		}
+		switch s.Tok {
+		case token.BREAK:
+			if ctxt&breakOk == 0 {
+				check.error(s.Pos(), "break not in for, switch, or select statement")
+			}
+		case token.CONTINUE:
+			if ctxt&continueOk == 0 {
+				check.error(s.Pos(), "continue not in for statement")
+			}
+		case token.FALLTHROUGH:
+			if ctxt&fallthroughOk == 0 {
+				check.error(s.Pos(), "fallthrough statement out of place")
+			}
+		default:
+			check.invalidAST(s.Pos(), "branch statement: %s", s.Tok)
+		}
+
+	case *ast.BlockStmt:
+		check.openScope(s, "block")
+		defer check.closeScope()
+
+		check.stmtList(inner, s.List)
+
+	case *ast.IfStmt:
+		check.openScope(s, "if")
+		defer check.closeScope()
+
+		check.simpleStmt(s.Init)
+		var x operand
+		check.expr(&x, s.Cond)
+		if x.mode != invalid && !isBoolean(x.typ) {
+			check.error(s.Cond.Pos(), "non-boolean condition in if statement")
+		}
+		check.stmt(inner, s.Body)
+		if s.Else != nil {
+			check.stmt(inner, s.Else)
+		}
+
+	case *ast.SwitchStmt:
+		inner |= breakOk
+		check.openScope(s, "switch")
+		defer check.closeScope()
+
+		check.simpleStmt(s.Init)
+		var x operand
+		if s.Tag != nil {
+			check.expr(&x, s.Tag)
+		} else {
+			// spec: "A missing switch expression is
+			// equivalent to the boolean value true."
+			x.mode = constant_
+			x.typ = Typ[Bool]
+			x.val = constant.MakeBool(true)
+			x.expr = &ast.Ident{NamePos: s.Body.Lbrace, Name: "true"}
+		}
+
+		check.multipleDefaults(s.Body.List)
+
+		for i, c := range s.Body.List {
+			clause, _ := c.(*ast.CaseClause)
+			if clause == nil {
+				check.invalidAST(c.Pos(), "incorrect expression switch case")
+				continue
+			}
+			if x.mode != invalid {
+				check.caseValues(x, clause.List)
+			}
+			check.openScope(clause, "case")
+			inner := inner
+			if i+1 < len(s.Body.List) {
+				inner |= fallthroughOk
+			}
+			check.stmtList(inner, clause.Body)
+			check.closeScope()
+		}
+
+	case *ast.TypeSwitchStmt:
+		inner |= breakOk
+		check.openScope(s, "type switch")
+		defer check.closeScope()
+
+		check.simpleStmt(s.Init)
+
+		// A type switch guard must be of the form:
+		//
+		//     TypeSwitchGuard = [ identifier ":=" ] PrimaryExpr "." "(" "type" ")" .
+		//
+		// The parser is checking syntactic correctness;
+		// remaining syntactic errors are considered AST errors here.
+		// TODO(gri) better factoring of error handling (invalid ASTs)
+		//
+		var lhs *ast.Ident // lhs identifier or nil
+		var rhs ast.Expr
+		switch guard := s.Assign.(type) {
+		case *ast.ExprStmt:
+			rhs = guard.X
+		case *ast.AssignStmt:
+			if len(guard.Lhs) != 1 || guard.Tok != token.DEFINE || len(guard.Rhs) != 1 {
+				check.invalidAST(s.Pos(), "incorrect form of type switch guard")
+				return
+			}
+
+			lhs, _ = guard.Lhs[0].(*ast.Ident)
+			if lhs == nil {
+				check.invalidAST(s.Pos(), "incorrect form of type switch guard")
+				return
+			}
+
+			if lhs.Name == "_" {
+				// _ := x.(type) is an invalid short variable declaration
+				check.softErrorf(lhs.Pos(), "no new variable on left side of :=")
+				lhs = nil // avoid declared but not used error below
+			} else {
+				check.recordDef(lhs, nil) // lhs variable is implicitly declared in each cause clause
+			}
+
+			rhs = guard.Rhs[0]
+
+		default:
+			check.invalidAST(s.Pos(), "incorrect form of type switch guard")
+			return
+		}
+
+		// rhs must be of the form: expr.(type) and expr must be an interface
+		expr, _ := rhs.(*ast.TypeAssertExpr)
+		if expr == nil || expr.Type != nil {
+			check.invalidAST(s.Pos(), "incorrect form of type switch guard")
+			return
+		}
+		var x operand
+		check.expr(&x, expr.X)
+		if x.mode == invalid {
+			return
+		}
+		xtyp, _ := x.typ.Underlying().(*Interface)
+		if xtyp == nil {
+			check.errorf(x.pos(), "%s is not an interface", &x)
+			return
+		}
+
+		check.multipleDefaults(s.Body.List)
+
+		var lhsVars []*Var               // list of implicitly declared lhs variables
+		seen := make(map[Type]token.Pos) // map of seen types to positions
+		for _, s := range s.Body.List {
+			clause, _ := s.(*ast.CaseClause)
+			if clause == nil {
+				check.invalidAST(s.Pos(), "incorrect type switch case")
+				continue
+			}
+			// Check each type in this type switch case.
+			T := check.caseTypes(&x, xtyp, clause.List, seen)
+			check.openScope(clause, "case")
+			// If lhs exists, declare a corresponding variable in the case-local scope.
+			if lhs != nil {
+				// spec: "The TypeSwitchGuard may include a short variable declaration.
+				// When that form is used, the variable is declared at the beginning of
+				// the implicit block in each clause. In clauses with a case listing
+				// exactly one type, the variable has that type; otherwise, the variable
+				// has the type of the expression in the TypeSwitchGuard."
+				if len(clause.List) != 1 || T == nil {
+					T = x.typ
+				}
+				obj := NewVar(lhs.Pos(), check.pkg, lhs.Name, T)
+				scopePos := clause.End()
+				if len(clause.Body) > 0 {
+					scopePos = clause.Body[0].Pos()
+				}
+				check.declare(check.scope, nil, obj, scopePos)
+				check.recordImplicit(clause, obj)
+				// For the "declared but not used" error, all lhs variables act as
+				// one; i.e., if any one of them is 'used', all of them are 'used'.
+				// Collect them for later analysis.
+				lhsVars = append(lhsVars, obj)
+			}
+			check.stmtList(inner, clause.Body)
+			check.closeScope()
+		}
+
+		// If lhs exists, we must have at least one lhs variable that was used.
+		if lhs != nil {
+			var used bool
+			for _, v := range lhsVars {
+				if v.used {
+					used = true
+				}
+				v.used = true // avoid usage error when checking entire function
+			}
+			if !used {
+				check.softErrorf(lhs.Pos(), "%s declared but not used", lhs.Name)
+			}
+		}
+
+	case *ast.SelectStmt:
+		inner |= breakOk
+
+		check.multipleDefaults(s.Body.List)
+
+		for _, s := range s.Body.List {
+			clause, _ := s.(*ast.CommClause)
+			if clause == nil {
+				continue // error reported before
+			}
+
+			// clause.Comm must be a SendStmt, RecvStmt, or default case
+			valid := false
+			var rhs ast.Expr // rhs of RecvStmt, or nil
+			switch s := clause.Comm.(type) {
+			case nil, *ast.SendStmt:
+				valid = true
+			case *ast.AssignStmt:
+				if len(s.Rhs) == 1 {
+					rhs = s.Rhs[0]
+				}
+			case *ast.ExprStmt:
+				rhs = s.X
+			}
+
+			// if present, rhs must be a receive operation
+			if rhs != nil {
+				if x, _ := unparen(rhs).(*ast.UnaryExpr); x != nil && x.Op == token.ARROW {
+					valid = true
+				}
+			}
+
+			if !valid {
+				check.error(clause.Comm.Pos(), "select case must be send or receive (possibly with assignment)")
+				continue
+			}
+
+			check.openScope(s, "case")
+			if clause.Comm != nil {
+				check.stmt(inner, clause.Comm)
+			}
+			check.stmtList(inner, clause.Body)
+			check.closeScope()
+		}
+
+	case *ast.ForStmt:
+		inner |= breakOk | continueOk
+		check.openScope(s, "for")
+		defer check.closeScope()
+
+		check.simpleStmt(s.Init)
+		if s.Cond != nil {
+			var x operand
+			check.expr(&x, s.Cond)
+			if x.mode != invalid && !isBoolean(x.typ) {
+				check.error(s.Cond.Pos(), "non-boolean condition in for statement")
+			}
+		}
+		check.simpleStmt(s.Post)
+		// spec: "The init statement may be a short variable
+		// declaration, but the post statement must not."
+		if s, _ := s.Post.(*ast.AssignStmt); s != nil && s.Tok == token.DEFINE {
+			check.softErrorf(s.Pos(), "cannot declare in post statement")
+			check.use(s.Lhs...) // avoid follow-up errors
+		}
+		check.stmt(inner, s.Body)
+
+	case *ast.RangeStmt:
+		inner |= breakOk | continueOk
+		check.openScope(s, "for")
+		defer check.closeScope()
+
+		// check expression to iterate over
+		var x operand
+		check.expr(&x, s.X)
+
+		// determine key/value types
+		var key, val Type
+		if x.mode != invalid {
+			switch typ := x.typ.Underlying().(type) {
+			case *Basic:
+				if isString(typ) {
+					key = Typ[Int]
+					val = universeRune // use 'rune' name
+				}
+			case *Array:
+				key = Typ[Int]
+				val = typ.elem
+			case *Slice:
+				key = Typ[Int]
+				val = typ.elem
+			case *Pointer:
+				if typ, _ := typ.base.Underlying().(*Array); typ != nil {
+					key = Typ[Int]
+					val = typ.elem
+				}
+			case *Map:
+				key = typ.key
+				val = typ.elem
+			case *Chan:
+				key = typ.elem
+				val = Typ[Invalid]
+				if typ.dir == SendOnly {
+					check.errorf(x.pos(), "cannot range over send-only channel %s", &x)
+					// ok to continue
+				}
+				if s.Value != nil {
+					check.errorf(s.Value.Pos(), "iteration over %s permits only one iteration variable", &x)
+					// ok to continue
+				}
+			}
+		}
+
+		if key == nil {
+			check.errorf(x.pos(), "cannot range over %s", &x)
+			// ok to continue
+		}
+
+		// check assignment to/declaration of iteration variables
+		// (irregular assignment, cannot easily map to existing assignment checks)
+
+		// lhs expressions and initialization value (rhs) types
+		lhs := [2]ast.Expr{s.Key, s.Value}
+		rhs := [2]Type{key, val} // key, val may be nil
+
+		if s.Tok == token.DEFINE {
+			// short variable declaration; variable scope starts after the range clause
+			// (the for loop opens a new scope, so variables on the lhs never redeclare
+			// previously declared variables)
+			var vars []*Var
+			for i, lhs := range lhs {
+				if lhs == nil {
+					continue
+				}
+
+				// determine lhs variable
+				var obj *Var
+				if ident, _ := lhs.(*ast.Ident); ident != nil {
+					// declare new variable
+					name := ident.Name
+					obj = NewVar(ident.Pos(), check.pkg, name, nil)
+					check.recordDef(ident, obj)
+					// _ variables don't count as new variables
+					if name != "_" {
+						vars = append(vars, obj)
+					}
+				} else {
+					check.errorf(lhs.Pos(), "cannot declare %s", lhs)
+					obj = NewVar(lhs.Pos(), check.pkg, "_", nil) // dummy variable
+				}
+
+				// initialize lhs variable
+				if typ := rhs[i]; typ != nil {
+					x.mode = value
+					x.expr = lhs // we don't have a better rhs expression to use here
+					x.typ = typ
+					check.initVar(obj, &x, false)
+				} else {
+					obj.typ = Typ[Invalid]
+					obj.used = true // don't complain about unused variable
+				}
+			}
+
+			// declare variables
+			if len(vars) > 0 {
+				for _, obj := range vars {
+					// spec: "The scope of a constant or variable identifier declared inside
+					// a function begins at the end of the ConstSpec or VarSpec (ShortVarDecl
+					// for short variable declarations) and ends at the end of the innermost
+					// containing block."
+					scopePos := s.End()
+					check.declare(check.scope, nil /* recordDef already called */, obj, scopePos)
+				}
+			} else {
+				check.error(s.TokPos, "no new variables on left side of :=")
+			}
+		} else {
+			// ordinary assignment
+			for i, lhs := range lhs {
+				if lhs == nil {
+					continue
+				}
+				if typ := rhs[i]; typ != nil {
+					x.mode = value
+					x.expr = lhs // we don't have a better rhs expression to use here
+					x.typ = typ
+					check.assignVar(lhs, &x)
+				}
+			}
+		}
+
+		check.stmt(inner, s.Body)
+
+	default:
+		check.error(s.Pos(), "invalid statement")
+	}
+}
diff --git a/src/go/types/testdata/blank.src b/src/go/types/testdata/blank.src
new file mode 100644
index 0000000..6a2507f
--- /dev/null
+++ b/src/go/types/testdata/blank.src
@@ -0,0 +1,5 @@
+// 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 _ /* ERROR invalid package name */
diff --git a/src/go/types/testdata/builtins.src b/src/go/types/testdata/builtins.src
new file mode 100644
index 0000000..9eb551d
--- /dev/null
+++ b/src/go/types/testdata/builtins.src
@@ -0,0 +1,881 @@
+// 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.
+
+// builtin calls
+
+package builtins
+
+import "unsafe"
+
+func f0() {}
+
+func append1() {
+	var b byte
+	var x int
+	var s []byte
+	_ = append() // ERROR not enough arguments
+	_ = append("foo" /* ERROR not a slice */ )
+	_ = append(nil /* ERROR not a slice */ , s)
+	_ = append(x /* ERROR not a slice */ , s)
+	_ = append(s)
+	append /* ERROR not used */ (s)
+
+	_ = append(s, b)
+	_ = append(s, x /* ERROR cannot pass argument x */ )
+	_ = append(s, s /* ERROR cannot pass argument s */ )
+	_ = append(s... /* ERROR can only use ... with matching parameter */ )
+	_ = append(s, b, s... /* ERROR can only use ... with matching parameter */ )
+	_ = append(s, 1, 2, 3)
+	_ = append(s, 1, 2, 3, x /* ERROR cannot pass argument x */ , 5, 6, 6)
+	_ = append(s, 1, 2, s... /* ERROR can only use ... with matching parameter */ )
+	_ = append([]interface{}(nil), 1, 2, "foo", x, 3.1425, false)
+
+	type S []byte
+	type T string
+	var t T
+	_ = append(s, "foo" /* ERROR cannot convert */ )
+	_ = append(s, "foo"...)
+	_ = append(S(s), "foo" /* ERROR cannot convert */ )
+	_ = append(S(s), "foo"...)
+	_ = append(s, t /* ERROR cannot pass argument t */ )
+	_ = append(s, t...)
+	_ = append(s, T("foo")...)
+	_ = append(S(s), t /* ERROR cannot pass argument t */ )
+	_ = append(S(s), t...)
+	_ = append(S(s), T("foo")...)
+	_ = append([]string{}, t /* ERROR cannot pass argument t */ , "foo")
+	_ = append([]T{}, t, "foo")
+}
+
+// from the spec
+func append2() {
+	s0 := []int{0, 0}
+	s1 := append(s0, 2)                // append a single element     s1 == []int{0, 0, 2}
+	s2 := append(s1, 3, 5, 7)          // append multiple elements    s2 == []int{0, 0, 2, 3, 5, 7}
+	s3 := append(s2, s0...)            // append a slice              s3 == []int{0, 0, 2, 3, 5, 7, 0, 0}
+	s4 := append(s3[3:6], s3[2:]...)   // append overlapping slice    s4 == []int{3, 5, 7, 2, 3, 5, 7, 0, 0}
+
+	var t []interface{}
+	t = append(t, 42, 3.1415, "foo")   //                             t == []interface{}{42, 3.1415, "foo"}
+
+	var b []byte
+	b = append(b, "bar"...)            // append string contents      b == []byte{'b', 'a', 'r' }
+
+	_ = s4
+}
+
+func append3() {
+	f1 := func() (s []int) { return }
+	f2 := func() (s []int, x int) { return }
+	f3 := func() (s []int, x, y int) { return }
+	f5 := func() (s []interface{}, x int, y float32, z string, b bool) { return }
+	ff := func() (int, float32) { return 0, 0 }
+	_ = append(f0 /* ERROR used as value */ ())
+	_ = append(f1())
+	_ = append(f2())
+	_ = append(f3())
+	_ = append(f5())
+	_ = append(ff /* ERROR not a slice */ ()) // TODO(gri) better error message
+}
+
+func cap1() {
+	var a [10]bool
+	var p *[20]int
+	var c chan string
+	_ = cap() // ERROR not enough arguments
+	_ = cap(1, 2) // ERROR too many arguments
+	_ = cap(42 /* ERROR invalid */)
+	const _3 = cap(a)
+	assert(_3 == 10)
+	const _4 = cap(p)
+	assert(_4 == 20)
+	_ = cap(c)
+	cap /* ERROR not used */ (c)
+
+	// issue 4744
+	type T struct{ a [10]int }
+	const _ = cap(((*T)(nil)).a)
+
+	var s [][]byte
+	_ = cap(s)
+	_ = cap(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func cap2() {
+	f1a := func() (a [10]int) { return }
+	f1s := func() (s []int) { return }
+	f2 := func() (s []int, x int) { return }
+	_ = cap(f0 /* ERROR used as value */ ())
+	_ = cap(f1a())
+	_ = cap(f1s())
+	_ = cap(f2()) // ERROR too many arguments
+}
+
+// test cases for issue 7387
+func cap3() {
+	var f = func() int { return 0 }
+	var x = f()
+	const (
+		_ = cap([4]int{})
+		_ = cap([4]int{x})
+		_ = cap /* ERROR not constant */ ([4]int{f()})
+		_ = cap /* ERROR not constant */ ([4]int{cap([]int{})})
+		_ = cap([4]int{cap([4]int{})})
+	)
+	var y float64
+	var z complex128
+	const (
+		_ = cap([4]float64{})
+		_ = cap([4]float64{y})
+		_ = cap([4]float64{real(2i)})
+		_ = cap /* ERROR not constant */ ([4]float64{real(z)})
+	)
+	var ch chan [10]int
+	const (
+		_ = cap /* ERROR not constant */ (<-ch)
+		_ = cap /* ERROR not constant */ ([4]int{(<-ch)[0]})
+	)
+}
+
+func close1() {
+	var c chan int
+	var r <-chan int
+	close() // ERROR not enough arguments
+	close(1, 2) // ERROR too many arguments
+	close(42 /* ERROR not a channel */)
+	close(r /* ERROR receive-only channel */)
+	close(c)
+	_ = close /* ERROR used as value */ (c)
+
+	var s []chan int
+	close(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func close2() {
+	f1 := func() (ch chan int) { return }
+	f2 := func() (ch chan int, x int) { return }
+	close(f0 /* ERROR used as value */ ())
+	close(f1())
+	close(f2()) // ERROR too many arguments
+}
+
+func complex1() {
+	var i32 int32
+	var f32 float32
+	var f64 float64
+	var c64 complex64
+	var c128 complex128
+	_ = complex() // ERROR not enough arguments
+	_ = complex(1) // ERROR not enough arguments
+	_ = complex(true /* ERROR invalid argument */ , 0)
+	_ = complex(i32 /* ERROR invalid argument */ , 0)
+	_ = complex("foo" /* ERROR invalid argument */ , 0)
+	_ = complex(c64 /* ERROR invalid argument */ , 0)
+	_ = complex(0, true /* ERROR invalid argument */ )
+	_ = complex(0, i32 /* ERROR invalid argument */ )
+	_ = complex(0, "foo" /* ERROR invalid argument */ )
+	_ = complex(0, c64 /* ERROR invalid argument */ )
+	_ = complex(f32, f32)
+	_ = complex(f32, 1)
+	_ = complex(f32, 1.0)
+	_ = complex(f32, 'a')
+	_ = complex(f64, f64)
+	_ = complex(f64, 1)
+	_ = complex(f64, 1.0)
+	_ = complex(f64, 'a')
+	_ = complex(f32 /* ERROR mismatched types */ , f64)
+	_ = complex(f64 /* ERROR mismatched types */ , f32)
+	_ = complex(1, 1)
+	_ = complex(1, 1.1)
+	_ = complex(1, 'a')
+	complex /* ERROR not used */ (1, 2)
+
+	var _ complex64 = complex(f32, f32)
+	var _ complex64 = complex /* ERROR cannot initialize */ (f64, f64)
+
+	var _ complex128 = complex /* ERROR cannot initialize */ (f32, f32)
+	var _ complex128 = complex(f64, f64)
+
+	// untyped constants
+	const _ int = complex(1, 0)
+	const _ float32 = complex(1, 0)
+	const _ complex64 = complex(1, 0)
+	const _ complex128 = complex(1, 0)
+
+	const _ int = complex /* ERROR int */ (1.1, 0)
+	const _ float32 = complex /* ERROR float32 */ (1, 2)
+
+	// untyped values
+	var s uint
+	_ = complex(1 /* ERROR integer */ <<s, 0)
+	const _ = complex /* ERROR not constant */ (1 /* ERROR integer */ <<s, 0)
+	var _ int = complex /* ERROR cannot initialize */ (1 /* ERROR integer */ <<s, 0)
+
+	// floating-point argument types must be identical
+	type F32 float32
+	type F64 float64
+	var x32 F32
+	var x64 F64
+	c64 = complex(x32, x32)
+	_ = complex(x32 /* ERROR mismatched types */ , f32)
+	_ = complex(f32 /* ERROR mismatched types */ , x32)
+	c128 = complex(x64, x64)
+	_ = c128
+	_ = complex(x64 /* ERROR mismatched types */ , f64)
+	_ = complex(f64 /* ERROR mismatched types */ , x64)
+
+	var t []float32
+	_ = complex(t... /* ERROR invalid use of \.\.\. */ )
+}
+
+func complex2() {
+	f1 := func() (x float32) { return }
+	f2 := func() (x, y float32) { return }
+	f3 := func() (x, y, z float32) { return }
+	_ = complex(f0 /* ERROR used as value */ ())
+	_ = complex(f1()) // ERROR not enough arguments
+	_ = complex(f2())
+	_ = complex(f3()) // ERROR too many arguments
+}
+
+func copy1() {
+	copy() // ERROR not enough arguments
+	copy("foo") // ERROR not enough arguments
+	copy([ /* ERROR copy expects slice arguments */ ...]int{}, []int{})
+	copy([ /* ERROR copy expects slice arguments */ ]int{}, [...]int{})
+	copy([ /* ERROR different element types */ ]int8{}, "foo")
+
+	// spec examples
+	var a = [...]int{0, 1, 2, 3, 4, 5, 6, 7}
+	var s = make([]int, 6)
+	var b = make([]byte, 5)
+	n1 := copy(s, a[0:])            // n1 == 6, s == []int{0, 1, 2, 3, 4, 5}
+	n2 := copy(s, s[2:])            // n2 == 4, s == []int{2, 3, 4, 5, 4, 5}
+	n3 := copy(b, "Hello, World!")  // n3 == 5, b == []byte("Hello")
+	_, _, _ = n1, n2, n3
+
+	var t [][]int
+	copy(t, t)
+	copy(t /* ERROR copy expects slice arguments */ , nil)
+	copy(nil /* ERROR copy expects slice arguments */ , t)
+	copy(nil /* ERROR copy expects slice arguments */ , nil)
+	copy(t... /* ERROR invalid use of \.\.\. */ )
+}
+
+func copy2() {
+	f1 := func() (a []int) { return }
+	f2 := func() (a, b []int) { return }
+	f3 := func() (a, b, c []int) { return }
+	copy(f0 /* ERROR used as value */ ())
+	copy(f1()) // ERROR not enough arguments
+	copy(f2())
+	copy(f3()) // ERROR too many arguments
+}
+
+func delete1() {
+	var m map[string]int
+	var s string
+	delete() // ERROR not enough arguments
+	delete(1) // ERROR not enough arguments
+	delete(1, 2, 3) // ERROR too many arguments
+	delete(m, 0 /* ERROR not assignable */)
+	delete(m, s)
+	_ = delete /* ERROR used as value */ (m, s)
+
+	var t []map[string]string
+	delete(t... /* ERROR invalid use of \.\.\. */ )
+}
+
+func delete2() {
+	f1 := func() (m map[string]int) { return }
+	f2 := func() (m map[string]int, k string) { return }
+	f3 := func() (m map[string]int, k string, x float32) { return }
+	delete(f0 /* ERROR used as value */ ())
+	delete(f1()) // ERROR not enough arguments
+	delete(f2())
+	delete(f3()) // ERROR too many arguments
+}
+
+func imag1() {
+	var f32 float32
+	var f64 float64
+	var c64 complex64
+	var c128 complex128
+	_ = imag() // ERROR not enough arguments
+	_ = imag(1, 2) // ERROR too many arguments
+	_ = imag(10 /* ERROR must be a complex number */)
+	_ = imag(2.7182818 /* ERROR must be a complex number */)
+	_ = imag("foo" /* ERROR must be a complex number */)
+	const _5 = imag(1 + 2i)
+	assert(_5 == 2)
+	f32 = _5
+	f64 = _5
+	const _6 = imag(0i)
+	assert(_6 == 0)
+	f32 = imag(c64)
+	f64 = imag(c128)
+	f32 = imag /* ERROR cannot assign */ (c128)
+	f64 = imag /* ERROR cannot assign */ (c64)
+	imag /* ERROR not used */ (c64)
+	_, _ = f32, f64
+
+	// complex type may not be predeclared
+	type C64 complex64
+	type C128 complex128
+	var x64 C64
+	var x128 C128
+	f32 = imag(x64)
+	f64 = imag(x128)
+
+	var s []complex64
+	_ = imag(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func imag2() {
+	f1 := func() (x complex128) { return }
+	f2 := func() (x, y complex128) { return }
+	_ = imag(f0 /* ERROR used as value */ ())
+	_ = imag(f1())
+	_ = imag(f2()) // ERROR too many arguments
+}
+
+func len1() {
+	const c = "foobar"
+	var a [10]bool
+	var p *[20]int
+	var m map[string]complex128
+	_ = len() // ERROR not enough arguments
+	_ = len(1, 2) // ERROR too many arguments
+	_ = len(42 /* ERROR invalid */)
+	const _3 = len(c)
+	assert(_3 == 6)
+	const _4 = len(a)
+	assert(_4 == 10)
+	const _5 = len(p)
+	assert(_5 == 20)
+	_ = len(m)
+	len /* ERROR not used */ (c)
+
+	// esoteric case
+	var t string
+	var hash map[interface{}][]*[10]int
+	const n = len /* ERROR not constant */ (hash[recover()][len(t)])
+	assert(n == 10) // ok because n has unknown value and no error is reported
+	var ch <-chan int
+	const nn = len /* ERROR not constant */ (hash[<-ch][len(t)])
+
+	// issue 4744
+	type T struct{ a [10]int }
+	const _ = len(((*T)(nil)).a)
+
+	var s [][]byte
+	_ = len(s)
+	_ = len(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func len2() {
+	f1 := func() (x []int) { return }
+	f2 := func() (x, y []int) { return }
+	_ = len(f0 /* ERROR used as value */ ())
+	_ = len(f1())
+	_ = len(f2()) // ERROR too many arguments
+}
+
+// test cases for issue 7387
+func len3() {
+	var f = func() int { return 0 }
+	var x = f()
+	const (
+		_ = len([4]int{})
+		_ = len([4]int{x})
+		_ = len /* ERROR not constant */ ([4]int{f()})
+		_ = len /* ERROR not constant */ ([4]int{len([]int{})})
+		_ = len([4]int{len([4]int{})})
+	)
+	var y float64
+	var z complex128
+	const (
+		_ = len([4]float64{})
+		_ = len([4]float64{y})
+		_ = len([4]float64{real(2i)})
+		_ = len /* ERROR not constant */ ([4]float64{real(z)})
+	)
+	var ch chan [10]int
+	const (
+		_ = len /* ERROR not constant */ (<-ch)
+		_ = len /* ERROR not constant */ ([4]int{(<-ch)[0]})
+	)
+}
+
+func make1() {
+	var n int
+	var m float32
+	var s uint
+
+	_ = make() // ERROR not enough arguments
+	_ = make(1 /* ERROR not a type */)
+	_ = make(int /* ERROR cannot make */)
+
+	// slices
+	_ = make/* ERROR arguments */ ([]int)
+	_ = make/* ERROR arguments */ ([]int, 2, 3, 4)
+	_ = make([]int, int /* ERROR not an expression */)
+	_ = make([]int, 10, float32 /* ERROR not an expression */)
+	_ = make([]int, "foo" /* ERROR cannot convert */)
+	_ = make([]int, 10, 2.3 /* ERROR truncated */)
+	_ = make([]int, 5, 10.0)
+	_ = make([]int, 0i)
+	_ = make([]int, 1.0)
+	_ = make([]int, 1.0<<s)
+	_ = make([]int, 1.1 /* ERROR int */ <<s)
+	_ = make([]int, - /* ERROR must not be negative */ 1, 10)
+	_ = make([]int, 0, - /* ERROR must not be negative */ 1)
+	_ = make([]int, - /* ERROR must not be negative */ 1, - /* ERROR must not be negative */ 1)
+	_ = make([]int, 1 /* ERROR overflows */ <<100, 1 /* ERROR overflows */ <<100)
+	_ = make([]int, 10 /* ERROR length and capacity swapped */ , 9)
+	_ = make([]int, 1 /* ERROR overflows */ <<100, 12345)
+	_ = make([]int, m /* ERROR must be integer */ )
+        _ = &make /* ERROR cannot take address */ ([]int, 0)
+
+	// maps
+	_ = make /* ERROR arguments */ (map[int]string, 10, 20)
+	_ = make(map[int]float32, int /* ERROR not an expression */)
+	_ = make(map[int]float32, "foo" /* ERROR cannot convert */)
+	_ = make(map[int]float32, 10)
+	_ = make(map[int]float32, n)
+	_ = make(map[int]float32, int64(n))
+	_ = make(map[string]bool, 10.0)
+	_ = make(map[string]bool, 10.0<<s)
+        _ = &make /* ERROR cannot take address */ (map[string]bool)
+
+	// channels
+	_ = make /* ERROR arguments */ (chan int, 10, 20)
+	_ = make(chan int, int /* ERROR not an expression */)
+	_ = make(chan<- int, "foo" /* ERROR cannot convert */)
+	_ = make(chan int, - /* ERROR must not be negative */ 10)
+	_ = make(<-chan float64, 10)
+	_ = make(chan chan int, n)
+	_ = make(chan string, int64(n))
+	_ = make(chan bool, 10.0)
+	_ = make(chan bool, 10.0<<s)
+        _ = &make /* ERROR cannot take address */ (chan bool)
+
+	make /* ERROR not used */ ([]int, 10)
+
+	var t []int
+	_ = make([]int, t[0], t[1])
+	_ = make([]int, t... /* ERROR invalid use of \.\.\. */ )
+}
+
+func make2() {
+	f1 /* ERROR not used */ := func() (x []int) { return }
+	_ = make(f0 /* ERROR not a type */ ())
+	_ = make(f1 /* ERROR not a type */ ())
+}
+
+func new1() {
+	_ = new() // ERROR not enough arguments
+	_ = new(1, 2) // ERROR too many arguments
+	_ = new("foo" /* ERROR not a type */)
+	p := new(float64)
+	_ = new(struct{ x, y int })
+	q := new(*float64)
+	_ = *p == **q
+	new /* ERROR not used */ (int)
+        _ = &new /* ERROR cannot take address */ (int)
+
+	_ = new(int... /* ERROR invalid use of \.\.\. */ )
+}
+
+func new2() {
+	f1 /* ERROR not used */ := func() (x []int) { return }
+	_ = new(f0 /* ERROR not a type */ ())
+	_ = new(f1 /* ERROR not a type */ ())
+}
+
+func panic1() {
+	panic() // ERROR not enough arguments
+	panic(1, 2) // ERROR too many arguments
+	panic(0)
+	panic("foo")
+	panic(false)
+	panic(1<<10)
+	panic(1 /* ERROR overflows */ <<1000)
+	_ = panic /* ERROR used as value */ (0)
+
+	var s []byte
+	panic(s)
+	panic(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func panic2() {
+	f1 := func() (x int) { return }
+	f2 := func() (x, y int) { return }
+	panic(f0 /* ERROR used as value */ ())
+	panic(f1())
+	panic(f2()) // ERROR too many arguments
+}
+
+func print1() {
+	print()
+	print(1)
+	print(1, 2)
+	print("foo")
+	print(2.718281828)
+	print(false)
+	print(1<<10)
+	print(1 /* ERROR overflows */ <<1000)
+	println(nil /* ERROR untyped nil */ )
+
+	var s []int
+	print(s... /* ERROR invalid use of \.\.\. */ )
+	_ = print /* ERROR used as value */ ()
+}
+
+func print2() {
+	f1 := func() (x int) { return }
+	f2 := func() (x, y int) { return }
+	f3 := func() (x int, y float32, z string) { return }
+	print(f0 /* ERROR used as value */ ())
+	print(f1())
+	print(f2())
+	print(f3())
+}
+
+func println1() {
+	println()
+	println(1)
+	println(1, 2)
+	println("foo")
+	println(2.718281828)
+	println(false)
+	println(1<<10)
+	println(1 /* ERROR overflows */ <<1000)
+	println(nil /* ERROR untyped nil */ )
+
+	var s []int
+	println(s... /* ERROR invalid use of \.\.\. */ )
+	_ = println /* ERROR used as value */ ()
+}
+
+func println2() {
+	f1 := func() (x int) { return }
+	f2 := func() (x, y int) { return }
+	f3 := func() (x int, y float32, z string) { return }
+	println(f0 /* ERROR used as value */ ())
+	println(f1())
+	println(f2())
+	println(f3())
+}
+
+func real1() {
+	var f32 float32
+	var f64 float64
+	var c64 complex64
+	var c128 complex128
+	_ = real() // ERROR not enough arguments
+	_ = real(1, 2) // ERROR too many arguments
+	_ = real(10 /* ERROR must be a complex number */)
+	_ = real(2.7182818 /* ERROR must be a complex number */)
+	_ = real("foo" /* ERROR must be a complex number */)
+	const _5 = real(1 + 2i)
+	assert(_5 == 1)
+	f32 = _5
+	f64 = _5
+	const _6 = real(0i)
+	assert(_6 == 0)
+	f32 = real(c64)
+	f64 = real(c128)
+	f32 = real /* ERROR cannot assign */ (c128)
+	f64 = real /* ERROR cannot assign */ (c64)
+	real /* ERROR not used */ (c64)
+
+	// complex type may not be predeclared
+	type C64 complex64
+	type C128 complex128
+	var x64 C64
+	var x128 C128
+	f32 = imag(x64)
+	f64 = imag(x128)
+
+	var s []complex64
+	_ = real(s... /* ERROR invalid use of \.\.\. */ )
+	_, _ = f32, f64
+}
+
+func real2() {
+	f1 := func() (x complex128) { return }
+	f2 := func() (x, y complex128) { return }
+	_ = real(f0 /* ERROR used as value */ ())
+	_ = real(f1())
+	_ = real(f2()) // ERROR too many arguments
+}
+
+func recover1() {
+	_ = recover()
+	_ = recover(10) // ERROR too many arguments
+	recover()
+
+	var s []int
+	recover(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func recover2() {
+	f1 := func() (x int) { return }
+	f2 := func() (x, y int) { return }
+	_ = recover(f0 /* ERROR used as value */ ())
+	_ = recover(f1()) // ERROR too many arguments
+	_ = recover(f2()) // ERROR too many arguments
+}
+
+// assuming types.DefaultPtrSize == 8
+type S0 struct{      // offset
+	a bool       //  0
+	b rune       //  4
+	c *int       //  8
+	d bool       // 16
+	e complex128 // 24
+}                    // 40
+
+type S1 struct{   // offset
+	x float32 //  0
+	y string  //  8
+	z *S1     // 24
+	S0        // 32
+}                 // 72
+
+type S2 struct{ // offset
+	*S1     //  0
+}               //  8
+
+type S3 struct { // offset
+	a int64  //  0
+	b int32  //  8
+}                // 12
+
+type S4 struct { // offset
+	S3       //  0
+	int32    // 12
+}                // 16
+
+type S5 struct {   // offset
+	a [3]int32 //  0
+	b int32    // 12
+}                  // 16
+
+func (S2) m() {}
+
+func Alignof1() {
+	var x int
+	_ = unsafe.Alignof() // ERROR not enough arguments
+	_ = unsafe.Alignof(1, 2) // ERROR too many arguments
+	_ = unsafe.Alignof(int /* ERROR not an expression */)
+	_ = unsafe.Alignof(42)
+	_ = unsafe.Alignof(new(struct{}))
+	_ = unsafe.Alignof(1<<10)
+	_ = unsafe.Alignof(1 /* ERROR overflows */ <<1000)
+	_ = unsafe.Alignof(nil /* ERROR "untyped nil */ )
+	unsafe /* ERROR not used */ .Alignof(x)
+
+	var y S0
+	assert(unsafe.Alignof(y.a) == 1)
+	assert(unsafe.Alignof(y.b) == 4)
+	assert(unsafe.Alignof(y.c) == 8)
+	assert(unsafe.Alignof(y.d) == 1)
+	assert(unsafe.Alignof(y.e) == 8)
+
+	var s []byte
+	_ = unsafe.Alignof(s)
+	_ = unsafe.Alignof(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func Alignof2() {
+	f1 := func() (x int32) { return }
+	f2 := func() (x, y int32) { return }
+	_ = unsafe.Alignof(f0 /* ERROR used as value */ ())
+	assert(unsafe.Alignof(f1()) == 4)
+	_ = unsafe.Alignof(f2()) // ERROR too many arguments
+}
+
+func Offsetof1() {
+	var x struct{ f int }
+	_ = unsafe.Offsetof() // ERROR not enough arguments
+	_ = unsafe.Offsetof(1, 2) // ERROR too many arguments
+	_ = unsafe.Offsetof(int /* ERROR not a selector expression */ )
+	_ = unsafe.Offsetof(x /* ERROR not a selector expression */ )
+	_ = unsafe.Offsetof(nil /* ERROR not a selector expression */ )
+	_ = unsafe.Offsetof(x.f)
+	_ = unsafe.Offsetof((x.f))
+	_ = unsafe.Offsetof((((((((x))).f)))))
+	unsafe /* ERROR not used */ .Offsetof(x.f)
+
+	var y0 S0
+	assert(unsafe.Offsetof(y0.a) == 0)
+	assert(unsafe.Offsetof(y0.b) == 4)
+	assert(unsafe.Offsetof(y0.c) == 8)
+	assert(unsafe.Offsetof(y0.d) == 16)
+	assert(unsafe.Offsetof(y0.e) == 24)
+
+	var y1 S1
+	assert(unsafe.Offsetof(y1.x) == 0)
+	assert(unsafe.Offsetof(y1.y) == 8)
+	assert(unsafe.Offsetof(y1.z) == 24)
+	assert(unsafe.Offsetof(y1.S0) == 32)
+
+	assert(unsafe.Offsetof(y1.S0.a) == 0) // relative to S0
+	assert(unsafe.Offsetof(y1.a) == 32)   // relative to S1
+	assert(unsafe.Offsetof(y1.b) == 36)   // relative to S1
+	assert(unsafe.Offsetof(y1.c) == 40)   // relative to S1
+	assert(unsafe.Offsetof(y1.d) == 48)   // relative to S1
+	assert(unsafe.Offsetof(y1.e) == 56)   // relative to S1
+
+	var y1p *S1
+	assert(unsafe.Offsetof(y1p.S0) == 32)
+
+	type P *S1
+	var p P = y1p
+	assert(unsafe.Offsetof(p.S0) == 32)
+
+	var y2 S2
+	assert(unsafe.Offsetof(y2.S1) == 0)
+	_ = unsafe.Offsetof(y2 /* ERROR embedded via a pointer */ .x)
+	_ = unsafe.Offsetof(y2 /* ERROR method value */ .m)
+
+	var s []byte
+	_ = unsafe.Offsetof(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func Offsetof2() {
+	f1 := func() (x int32) { return }
+	f2 := func() (x, y int32) { return }
+	_ = unsafe.Offsetof(f0 /* ERROR not a selector expression */ ())
+	_ = unsafe.Offsetof(f1 /* ERROR not a selector expression */ ())
+	_ = unsafe.Offsetof(f2 /* ERROR not a selector expression */ ())
+}
+
+func Sizeof1() {
+	var x int
+	_ = unsafe.Sizeof() // ERROR not enough arguments
+	_ = unsafe.Sizeof(1, 2) // ERROR too many arguments
+	_ = unsafe.Sizeof(int /* ERROR not an expression */)
+	_ = unsafe.Sizeof(42)
+	_ = unsafe.Sizeof(new(complex128))
+	_ = unsafe.Sizeof(1<<10)
+	_ = unsafe.Sizeof(1 /* ERROR overflows */ <<1000)
+	_ = unsafe.Sizeof(nil /* ERROR untyped nil */ )
+	unsafe /* ERROR not used */ .Sizeof(x)
+
+	// basic types have size guarantees
+	assert(unsafe.Sizeof(byte(0)) == 1)
+	assert(unsafe.Sizeof(uint8(0)) == 1)
+	assert(unsafe.Sizeof(int8(0)) == 1)
+	assert(unsafe.Sizeof(uint16(0)) == 2)
+	assert(unsafe.Sizeof(int16(0)) == 2)
+	assert(unsafe.Sizeof(uint32(0)) == 4)
+	assert(unsafe.Sizeof(int32(0)) == 4)
+	assert(unsafe.Sizeof(float32(0)) == 4)
+	assert(unsafe.Sizeof(uint64(0)) == 8)
+	assert(unsafe.Sizeof(int64(0)) == 8)
+	assert(unsafe.Sizeof(float64(0)) == 8)
+	assert(unsafe.Sizeof(complex64(0)) == 8)
+	assert(unsafe.Sizeof(complex128(0)) == 16)
+
+	var y0 S0
+	assert(unsafe.Sizeof(y0.a) == 1)
+	assert(unsafe.Sizeof(y0.b) == 4)
+	assert(unsafe.Sizeof(y0.c) == 8)
+	assert(unsafe.Sizeof(y0.d) == 1)
+	assert(unsafe.Sizeof(y0.e) == 16)
+	assert(unsafe.Sizeof(y0) == 40)
+
+	var y1 S1
+	assert(unsafe.Sizeof(y1) == 72)
+
+	var y2 S2
+	assert(unsafe.Sizeof(y2) == 8)
+
+	var y3 S3
+	assert(unsafe.Sizeof(y3) == 12)
+
+	var y4 S4
+	assert(unsafe.Sizeof(y4) == 16)
+
+	var y5 S5
+	assert(unsafe.Sizeof(y5) == 16)
+
+	var a3 [10]S3
+	assert(unsafe.Sizeof(a3) == 156)
+
+	// test case for issue 5670
+	type T struct {
+		a int32
+		_ int32
+		c int32
+	}
+	assert(unsafe.Sizeof(T{}) == 12)
+
+	var s []byte
+	_ = unsafe.Sizeof(s)
+	_ = unsafe.Sizeof(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func Sizeof2() {
+	f1 := func() (x int64) { return }
+	f2 := func() (x, y int64) { return }
+	_ = unsafe.Sizeof(f0 /* ERROR used as value */ ())
+	assert(unsafe.Sizeof(f1()) == 8)
+	_ = unsafe.Sizeof(f2()) // ERROR too many arguments
+}
+
+// self-testing only
+func assert1() {
+	var x int
+	assert() /* ERROR not enough arguments */
+	assert(1, 2) /* ERROR too many arguments */
+	assert("foo" /* ERROR boolean constant */ )
+	assert(x /* ERROR boolean constant */)
+	assert(true)
+	assert /* ERROR failed */ (false)
+	_ = assert(true)
+
+	var s []byte
+	assert(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func assert2() {
+	f1 := func() (x bool) { return }
+	f2 := func() (x bool) { return }
+	assert(f0 /* ERROR used as value */ ())
+	assert(f1 /* ERROR boolean constant */ ())
+	assert(f2 /* ERROR boolean constant */ ())
+}
+
+// self-testing only
+func trace1() {
+	// Uncomment the code below to test trace - will produce console output
+	// _ = trace /* ERROR no value */ ()
+	// _ = trace(1)
+	// _ = trace(true, 1.2, '\'', "foo", 42i, "foo" <= "bar")
+
+	var s []byte
+	trace(s... /* ERROR invalid use of \.\.\. */ )
+}
+
+func trace2() {
+	f1 := func() (x int) { return }
+	f2 := func() (x int, y string) { return }
+	f3 := func() (x int, y string, z []int) { return }
+	_ = f1
+	_ = f2
+	_ = f3
+	// Uncomment the code below to test trace - will produce console output
+	// trace(f0())
+	// trace(f1())
+	// trace(f2())
+	// trace(f3())
+	// trace(f0(), 1)
+	// trace(f1(), 1, 2)
+	// trace(f2(), 1, 2, 3)
+	// trace(f3(), 1, 2, 3, 4)
+}
diff --git a/src/go/types/testdata/const0.src b/src/go/types/testdata/const0.src
new file mode 100644
index 0000000..c4419ab
--- /dev/null
+++ b/src/go/types/testdata/const0.src
@@ -0,0 +1,282 @@
+// 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.
+
+// constant declarations
+
+package const0
+
+// constants declarations must be initialized by constants
+var x = 0
+const c0 = x /* ERROR "not constant" */
+
+// typed constants must have constant types
+const _ interface /* ERROR invalid constant type */ {} = 0
+
+func _ () {
+	const _ interface /* ERROR invalid constant type */ {} = 0
+	for i := 0; i < 10; i++ {} // don't crash with non-nil iota here
+}
+
+// untyped constants
+const (
+	// boolean values
+	ub0 = false
+	ub1 = true
+	ub2 = 2 < 1
+	ub3 = ui1 == uf1
+	ub4 = true /* ERROR "cannot convert" */ == 0
+
+	// integer values
+	ui0 = 0
+	ui1 = 1
+	ui2 = 42
+	ui3 = 3141592653589793238462643383279502884197169399375105820974944592307816406286
+	ui4 = -10
+
+	ui5 = ui0 + ui1
+	ui6 = ui1 - ui1
+	ui7 = ui2 * ui1
+	ui8 = ui3 / ui3
+	ui9 = ui3 % ui3
+
+	ui10 = 1 / 0 /* ERROR "division by zero" */
+	ui11 = ui1 / 0 /* ERROR "division by zero" */
+	ui12 = ui3 / ui0 /* ERROR "division by zero" */
+	ui13 = 1 % 0 /* ERROR "division by zero" */
+	ui14 = ui1 % 0 /* ERROR "division by zero" */
+	ui15 = ui3 % ui0 /* ERROR "division by zero" */
+
+	ui16 = ui2 & ui3
+	ui17 = ui2 | ui3
+	ui18 = ui2 ^ ui3
+	ui19 = 1 /* ERROR "invalid operation" */ % 1.0
+
+	// floating point values
+	uf0 = 0.
+	uf1 = 1.
+	uf2 = 4.2e1
+	uf3 = 3.141592653589793238462643383279502884197169399375105820974944592307816406286
+	uf4 = 1e-1
+
+	uf5 = uf0 + uf1
+	uf6 = uf1 - uf1
+	uf7 = uf2 * uf1
+	uf8 = uf3 / uf3
+	uf9 = uf3 /* ERROR "not defined" */ % uf3
+
+	uf10 = 1 / 0 /* ERROR "division by zero" */
+	uf11 = uf1 / 0 /* ERROR "division by zero" */
+	uf12 = uf3 / uf0 /* ERROR "division by zero" */
+
+	uf16 = uf2 /* ERROR "not defined" */ & uf3
+	uf17 = uf2 /* ERROR "not defined" */ | uf3
+	uf18 = uf2 /* ERROR "not defined" */ ^ uf3
+
+	// complex values
+	uc0 = 0.i
+	uc1 = 1.i
+	uc2 = 4.2e1i
+	uc3 = 3.141592653589793238462643383279502884197169399375105820974944592307816406286i
+	uc4 = 1e-1i
+
+	uc5 = uc0 + uc1
+	uc6 = uc1 - uc1
+	uc7 = uc2 * uc1
+	uc8 = uc3 / uc3
+	uc9 = uc3 /* ERROR "not defined" */ % uc3
+
+	uc10 = 1 / 0 /* ERROR "division by zero" */
+	uc11 = uc1 / 0 /* ERROR "division by zero" */
+	uc12 = uc3 / uc0 /* ERROR "division by zero" */
+
+	uc16 = uc2 /* ERROR "not defined" */ & uc3
+	uc17 = uc2 /* ERROR "not defined" */ | uc3
+	uc18 = uc2 /* ERROR "not defined" */ ^ uc3
+)
+
+type (
+	mybool bool
+	myint int
+	myfloat float64
+	mycomplex complex128
+)
+
+// typed constants
+const (
+	// boolean values
+	tb0 bool = false
+	tb1 bool = true
+	tb2 mybool = 2 < 1
+	tb3 mybool = ti1 /* ERROR "mismatched types" */ == tf1
+
+	// integer values
+	ti0 int8 = ui0
+	ti1 int32 = ui1
+	ti2 int64 = ui2
+	ti3 myint = ui3 /* ERROR "overflows" */
+	ti4 myint = ui4
+
+	ti5 = ti0 /* ERROR "mismatched types" */ + ti1
+	ti6 = ti1 - ti1
+	ti7 = ti2 /* ERROR "mismatched types" */ * ti1
+	ti8 = ti3 / ti3
+	ti9 = ti3 % ti3
+
+	ti10 = 1 / 0 /* ERROR "division by zero" */
+	ti11 = ti1 / 0 /* ERROR "division by zero" */
+	ti12 = ti3 /* ERROR "mismatched types" */ / ti0
+	ti13 = 1 % 0 /* ERROR "division by zero" */
+	ti14 = ti1 % 0 /* ERROR "division by zero" */
+	ti15 = ti3 /* ERROR "mismatched types" */ % ti0
+
+	ti16 = ti2 /* ERROR "mismatched types" */ & ti3
+	ti17 = ti2 /* ERROR "mismatched types" */ | ti4
+	ti18 = ti2 ^ ti5 // no mismatched types error because the type of ti5 is unknown
+
+	// floating point values
+	tf0 float32 = 0.
+	tf1 float32 = 1.
+	tf2 float64 = 4.2e1
+	tf3 myfloat = 3.141592653589793238462643383279502884197169399375105820974944592307816406286
+	tf4 myfloat = 1e-1
+
+	tf5 = tf0 + tf1
+	tf6 = tf1 - tf1
+	tf7 = tf2 /* ERROR "mismatched types" */ * tf1
+	tf8 = tf3 / tf3
+	tf9 = tf3 /* ERROR "not defined" */ % tf3
+
+	tf10 = 1 / 0 /* ERROR "division by zero" */
+	tf11 = tf1 / 0 /* ERROR "division by zero" */
+	tf12 = tf3 /* ERROR "mismatched types" */ / tf0
+
+	tf16 = tf2 /* ERROR "mismatched types" */ & tf3
+	tf17 = tf2 /* ERROR "mismatched types" */ | tf3
+	tf18 = tf2 /* ERROR "mismatched types" */ ^ tf3
+
+	// complex values
+	tc0 = 0.i
+	tc1 = 1.i
+	tc2 = 4.2e1i
+	tc3 = 3.141592653589793238462643383279502884197169399375105820974944592307816406286i
+	tc4 = 1e-1i
+
+	tc5 = tc0 + tc1
+	tc6 = tc1 - tc1
+	tc7 = tc2 * tc1
+	tc8 = tc3 / tc3
+	tc9 = tc3 /* ERROR "not defined" */ % tc3
+
+	tc10 = 1 / 0 /* ERROR "division by zero" */
+	tc11 = tc1 / 0 /* ERROR "division by zero" */
+	tc12 = tc3 / tc0 /* ERROR "division by zero" */
+
+	tc16 = tc2 /* ERROR "not defined" */ & tc3
+	tc17 = tc2 /* ERROR "not defined" */ | tc3
+	tc18 = tc2 /* ERROR "not defined" */ ^ tc3
+)
+
+// initialization cycles
+const (
+	a /* ERROR "initialization cycle" */ = a
+	b /* ERROR "initialization cycle" */ , c /* ERROR "initialization cycle" */, d, e = e, d, c, b // TODO(gri) should only have one cycle error
+	f float64 = d
+)
+
+// multiple initialization
+const (
+	a1, a2, a3 = 7, 3.1415926, "foo"
+	b1, b2, b3 = b3, b1, 42
+	c1, c2, c3  /* ERROR "missing init expr for c3" */ = 1, 2
+	d1, d2, d3 = 1, 2, 3, 4 /* ERROR "extra init expr 4" */
+	_p0 = assert(a1 == 7)
+	_p1 = assert(a2 == 3.1415926)
+	_p2 = assert(a3 == "foo")
+	_p3 = assert(b1 == 42)
+	_p4 = assert(b2 == 42)
+	_p5 = assert(b3 == 42)
+)
+
+func _() {
+	const (
+		a1, a2, a3 = 7, 3.1415926, "foo"
+		b1, b2, b3 = b3, b1, 42
+		c1, c2, c3  /* ERROR "missing init expr for c3" */ = 1, 2
+		d1, d2, d3 = 1, 2, 3, 4 /* ERROR "extra init expr 4" */
+		_p0 = assert(a1 == 7)
+		_p1 = assert(a2 == 3.1415926)
+		_p2 = assert(a3 == "foo")
+		_p3 = assert(b1 == 42)
+		_p4 = assert(b2 == 42)
+		_p5 = assert(b3 == 42)
+	)
+}
+
+// iota
+const (
+	iota0 = iota
+	iota1 = iota
+	iota2 = iota*2
+	_a0 = assert(iota0 == 0)
+	_a1 = assert(iota1 == 1)
+	_a2 = assert(iota2 == 4)
+	iota6 = iota*3
+
+	iota7
+	iota8
+	_a3 = assert(iota7 == 21)
+	_a4 = assert(iota8 == 24)
+)
+
+const (
+	_b0 = iota
+	_b1 = assert(iota + iota2 == 5)
+	_b2 = len([iota]int{}) // iota may appear in a type!
+	_b3 = assert(_b2 == 2)
+	_b4 = len(A{})
+)
+
+type A [iota /* ERROR "cannot use iota" */ ]int
+
+// constant expressions with operands accross different
+// constant declarations must use the right iota values
+const (
+	_c0 = iota
+	_c1
+	_c2
+	_x = _c2 + _d1 + _e0 // 3
+)
+
+const (
+	_d0 = iota
+	_d1
+)
+
+const (
+	_e0 = iota
+)
+
+var _ = assert(_x == 3)
+
+// special cases
+const (
+	_n0 = nil /* ERROR "not constant" */
+	_n1 = [ /* ERROR "not constant" */ ]int{}
+)
+
+// iotas must not be usable in expressions outside constant declarations
+type _ [iota /* ERROR "iota outside constant decl" */ ]byte
+var _ = iota /* ERROR "iota outside constant decl" */
+func _() {
+	_ = iota /* ERROR "iota outside constant decl" */
+	const _ = iota
+	_ = iota /* ERROR "iota outside constant decl" */
+}
+
+func _() {
+	iota := 123
+	const x = iota /* ERROR "is not constant" */
+	var y = iota
+	_ = y
+}
diff --git a/src/go/types/testdata/const1.src b/src/go/types/testdata/const1.src
new file mode 100644
index 0000000..88e9fad
--- /dev/null
+++ b/src/go/types/testdata/const1.src
@@ -0,0 +1,314 @@
+// 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.
+
+// constant conversions
+
+package const1
+
+const(
+	mi = ^int(0)
+	mu = ^uint(0)
+	mp = ^uintptr(0)
+
+	logSizeofInt     = uint(mi>>8&1 + mi>>16&1 + mi>>32&1)
+	logSizeofUint    = uint(mu>>8&1 + mu>>16&1 + mu>>32&1)
+	logSizeofUintptr = uint(mp>>8&1 + mp>>16&1 + mp>>32&1)
+)
+
+const (
+	minInt8 = -1<<(8<<iota - 1)
+	minInt16
+	minInt32
+	minInt64
+	minInt = -1<<(8<<logSizeofInt - 1)
+)
+
+const (
+	maxInt8 = 1<<(8<<iota - 1) - 1
+	maxInt16
+	maxInt32
+	maxInt64
+	maxInt = 1<<(8<<logSizeofInt - 1) - 1
+)
+
+const (
+	maxUint8 = 1<<(8<<iota) - 1
+	maxUint16
+	maxUint32
+	maxUint64
+	maxUint    = 1<<(8<<logSizeofUint) - 1
+	maxUintptr = 1<<(8<<logSizeofUintptr) - 1
+)
+
+const (
+	smallestFloat32 = 1.0 / (1<<(127 - 1 + 23))
+	smallestFloat64 = 1.0 / (1<<(1023 - 1 + 52))
+)
+
+const (
+	_ = assert(smallestFloat32 > 0)
+	_ = assert(smallestFloat64 > 0)
+)
+
+const (
+	maxFloat32 = 1<<127 * (1<<24 - 1) / (1.0<<23)
+	maxFloat64 = 1<<1023 * (1<<53 - 1) / (1.0<<52)
+)
+
+const (
+	_ int8 = minInt8 /* ERROR "overflows" */ - 1
+	_ int8 = minInt8
+	_ int8 = maxInt8
+	_ int8 = maxInt8 /* ERROR "overflows" */ + 1
+	_ int8 = smallestFloat64 /* ERROR "truncated" */
+
+	_ = int8(minInt8 /* ERROR "cannot convert" */ - 1)
+	_ = int8(minInt8)
+	_ = int8(maxInt8)
+	_ = int8(maxInt8 /* ERROR "cannot convert" */ + 1)
+	_ = int8(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+	_ int16 = minInt16 /* ERROR "overflows" */ - 1
+	_ int16 = minInt16
+	_ int16 = maxInt16
+	_ int16 = maxInt16 /* ERROR "overflows" */ + 1
+	_ int16 = smallestFloat64 /* ERROR "truncated" */
+
+	_ = int16(minInt16 /* ERROR "cannot convert" */ - 1)
+	_ = int16(minInt16)
+	_ = int16(maxInt16)
+	_ = int16(maxInt16 /* ERROR "cannot convert" */ + 1)
+	_ = int16(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+	_ int32 = minInt32 /* ERROR "overflows" */ - 1
+	_ int32 = minInt32
+	_ int32 = maxInt32
+	_ int32 = maxInt32 /* ERROR "overflows" */ + 1
+	_ int32 = smallestFloat64 /* ERROR "truncated" */
+
+	_ = int32(minInt32 /* ERROR "cannot convert" */ - 1)
+	_ = int32(minInt32)
+	_ = int32(maxInt32)
+	_ = int32(maxInt32 /* ERROR "cannot convert" */ + 1)
+	_ = int32(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+	_ int64 = minInt64 /* ERROR "overflows" */ - 1
+	_ int64 = minInt64
+	_ int64 = maxInt64
+	_ int64 = maxInt64 /* ERROR "overflows" */ + 1
+	_ int64 = smallestFloat64 /* ERROR "truncated" */
+
+	_ = int64(minInt64 /* ERROR "cannot convert" */ - 1)
+	_ = int64(minInt64)
+	_ = int64(maxInt64)
+	_ = int64(maxInt64 /* ERROR "cannot convert" */ + 1)
+	_ = int64(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+	_ int = minInt /* ERROR "overflows" */ - 1
+	_ int = minInt
+	_ int = maxInt
+	_ int = maxInt /* ERROR "overflows" */ + 1
+	_ int = smallestFloat64 /* ERROR "truncated" */
+
+	_ = int(minInt /* ERROR "cannot convert" */ - 1)
+	_ = int(minInt)
+	_ = int(maxInt)
+	_ = int(maxInt /* ERROR "cannot convert" */ + 1)
+	_ = int(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+	_ uint8 = 0 /* ERROR "overflows" */ - 1
+	_ uint8 = 0
+	_ uint8 = maxUint8
+	_ uint8 = maxUint8 /* ERROR "overflows" */ + 1
+	_ uint8 = smallestFloat64 /* ERROR "truncated" */
+
+	_ = uint8(0 /* ERROR "cannot convert" */ - 1)
+	_ = uint8(0)
+	_ = uint8(maxUint8)
+	_ = uint8(maxUint8 /* ERROR "cannot convert" */ + 1)
+	_ = uint8(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+	_ uint16 = 0 /* ERROR "overflows" */ - 1
+	_ uint16 = 0
+	_ uint16 = maxUint16
+	_ uint16 = maxUint16 /* ERROR "overflows" */ + 1
+	_ uint16 = smallestFloat64 /* ERROR "truncated" */
+
+	_ = uint16(0 /* ERROR "cannot convert" */ - 1)
+	_ = uint16(0)
+	_ = uint16(maxUint16)
+	_ = uint16(maxUint16 /* ERROR "cannot convert" */ + 1)
+	_ = uint16(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+	_ uint32 = 0 /* ERROR "overflows" */ - 1
+	_ uint32 = 0
+	_ uint32 = maxUint32
+	_ uint32 = maxUint32 /* ERROR "overflows" */ + 1
+	_ uint32 = smallestFloat64 /* ERROR "truncated" */
+
+	_ = uint32(0 /* ERROR "cannot convert" */ - 1)
+	_ = uint32(0)
+	_ = uint32(maxUint32)
+	_ = uint32(maxUint32 /* ERROR "cannot convert" */ + 1)
+	_ = uint32(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+	_ uint64 = 0 /* ERROR "overflows" */ - 1
+	_ uint64 = 0
+	_ uint64 = maxUint64
+	_ uint64 = maxUint64 /* ERROR "overflows" */ + 1
+	_ uint64 = smallestFloat64 /* ERROR "truncated" */
+
+	_ = uint64(0 /* ERROR "cannot convert" */ - 1)
+	_ = uint64(0)
+	_ = uint64(maxUint64)
+	_ = uint64(maxUint64 /* ERROR "cannot convert" */ + 1)
+	_ = uint64(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+	_ uint = 0 /* ERROR "overflows" */ - 1
+	_ uint = 0
+	_ uint = maxUint
+	_ uint = maxUint /* ERROR "overflows" */ + 1
+	_ uint = smallestFloat64 /* ERROR "truncated" */
+
+	_ = uint(0 /* ERROR "cannot convert" */ - 1)
+	_ = uint(0)
+	_ = uint(maxUint)
+	_ = uint(maxUint /* ERROR "cannot convert" */ + 1)
+	_ = uint(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+	_ uintptr = 0 /* ERROR "overflows" */ - 1
+	_ uintptr = 0
+	_ uintptr = maxUintptr
+	_ uintptr = maxUintptr /* ERROR "overflows" */ + 1
+	_ uintptr = smallestFloat64 /* ERROR "truncated" */
+
+	_ = uintptr(0 /* ERROR "cannot convert" */ - 1)
+	_ = uintptr(0)
+	_ = uintptr(maxUintptr)
+	_ = uintptr(maxUintptr /* ERROR "cannot convert" */ + 1)
+	_ = uintptr(smallestFloat64 /* ERROR "cannot convert" */)
+)
+
+const (
+	_ float32 = minInt64
+	_ float64 = minInt64
+	_ complex64 = minInt64
+	_ complex128 = minInt64
+
+	_ = float32(minInt64)
+	_ = float64(minInt64)
+	_ = complex64(minInt64)
+	_ = complex128(minInt64)
+)
+
+const (
+	_ float32 = maxUint64
+	_ float64 = maxUint64
+	_ complex64 = maxUint64
+	_ complex128 = maxUint64
+
+	_ = float32(maxUint64)
+	_ = float64(maxUint64)
+	_ = complex64(maxUint64)
+	_ = complex128(maxUint64)
+)
+
+// TODO(gri) find smaller deltas below
+
+const delta32 = maxFloat32/(1 << 23)
+
+const (
+	_ float32 = - /* ERROR "overflow" */ (maxFloat32 + delta32)
+	_ float32 = -maxFloat32
+	_ float32 = maxFloat32
+	_ float32 = maxFloat32 /* ERROR "overflow" */ + delta32
+
+	_ = float32(- /* ERROR "cannot convert" */ (maxFloat32 + delta32))
+	_ = float32(-maxFloat32)
+	_ = float32(maxFloat32)
+	_ = float32(maxFloat32 /* ERROR "cannot convert" */ + delta32)
+
+	_ = assert(float32(smallestFloat32) == smallestFloat32)
+	_ = assert(float32(smallestFloat32/2) == 0)
+	_ = assert(float32(smallestFloat64) == 0)
+	_ = assert(float32(smallestFloat64/2) == 0)
+)
+
+const delta64 = maxFloat64/(1 << 52)
+
+const (
+	_ float64 = - /* ERROR "overflow" */ (maxFloat64 + delta64)
+	_ float64 = -maxFloat64
+	_ float64 = maxFloat64
+	_ float64 = maxFloat64 /* ERROR "overflow" */ + delta64
+
+	_ = float64(- /* ERROR "cannot convert" */ (maxFloat64 + delta64))
+	_ = float64(-maxFloat64)
+	_ = float64(maxFloat64)
+	_ = float64(maxFloat64 /* ERROR "cannot convert" */ + delta64)
+
+	_ = assert(float64(smallestFloat32) == smallestFloat32)
+	_ = assert(float64(smallestFloat32/2) == smallestFloat32/2)
+	_ = assert(float64(smallestFloat64) == smallestFloat64)
+	_ = assert(float64(smallestFloat64/2) == 0)
+)
+
+const (
+	_ complex64 = - /* ERROR "overflow" */ (maxFloat32 + delta32)
+	_ complex64 = -maxFloat32
+	_ complex64 = maxFloat32
+	_ complex64 = maxFloat32 /* ERROR "overflow" */ + delta32
+
+	_ = complex64(- /* ERROR "cannot convert" */ (maxFloat32 + delta32))
+	_ = complex64(-maxFloat32)
+	_ = complex64(maxFloat32)
+	_ = complex64(maxFloat32 /* ERROR "cannot convert" */ + delta32)
+)
+
+const (
+	_ complex128 = - /* ERROR "overflow" */ (maxFloat64 + delta64)
+	_ complex128 = -maxFloat64
+	_ complex128 = maxFloat64
+	_ complex128 = maxFloat64 /* ERROR "overflow" */ + delta64
+
+	_ = complex128(- /* ERROR "cannot convert" */ (maxFloat64 + delta64))
+	_ = complex128(-maxFloat64)
+	_ = complex128(maxFloat64)
+	_ = complex128(maxFloat64 /* ERROR "cannot convert" */ + delta64)
+)
+
+// Initialization of typed constant and conversion are the same:
+const (
+	f32 = 1 + smallestFloat32
+	x32 float32 = f32
+	y32 = float32(f32)
+	_ = assert(x32 - y32 == 0)
+)
+
+const (
+	f64 = 1 + smallestFloat64
+	x64 float64 = f64
+	y64 = float64(f64)
+	_ = assert(x64 - y64 == 0)
+)
diff --git a/src/go/types/testdata/constdecl.src b/src/go/types/testdata/constdecl.src
new file mode 100644
index 0000000..6de9b13
--- /dev/null
+++ b/src/go/types/testdata/constdecl.src
@@ -0,0 +1,97 @@
+// 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 constdecl
+
+import "math"
+
+var v int
+
+// Const decls must be initialized by constants.
+const _ = v /* ERROR "not constant" */
+const _ = math /* ERROR "not constant" */ .Sin(0)
+const _ = int /* ERROR "not an expression" */
+
+func _() {
+	const _ = v /* ERROR "not constant" */
+	const _ = math /* ERROR "not constant" */ .Sin(0)
+	const _ = int /* ERROR "not an expression" */
+}
+
+// Identifier and expression arity must match.
+// The first error message is produced by the parser.
+// In a real-world scenario, the type-checker would not be run
+// in this case and the 2nd error message would not appear.
+const _ /* ERROR "missing constant value" */ /* ERROR "missing init expr for _" */
+const _ = 1, 2 /* ERROR "extra init expr 2" */
+
+const _ /* ERROR "missing constant value" */ /* ERROR "missing init expr for _" */ int
+const _ int = 1, 2 /* ERROR "extra init expr 2" */
+
+const (
+	_ /* ERROR "missing constant value" */ /* ERROR "missing init expr for _" */
+	_ = 1, 2 /* ERROR "extra init expr 2" */
+
+	_ /* ERROR "missing constant value" */ /* ERROR "missing init expr for _" */ int
+	_ int = 1, 2 /* ERROR "extra init expr 2" */
+)
+
+const (
+	_ = 1
+	_
+	_, _ /* ERROR "missing init expr for _" */
+	_
+)
+
+const (
+	_, _ = 1, 2
+	_, _
+	_ /* ERROR "extra init expr at" */
+	_, _
+	_, _, _ /* ERROR "missing init expr for _" */
+	_, _
+)
+
+func _() {
+	const _ /* ERROR "missing constant value" */ /* ERROR "missing init expr for _" */
+	const _ = 1, 2 /* ERROR "extra init expr 2" */
+
+	const _ /* ERROR "missing constant value" */ /* ERROR "missing init expr for _" */ int
+	const _ int = 1, 2 /* ERROR "extra init expr 2" */
+
+	const (
+		_ /* ERROR "missing constant value" */ /* ERROR "missing init expr for _" */
+		_ = 1, 2 /* ERROR "extra init expr 2" */
+
+		_ /* ERROR "missing constant value" */ /* ERROR "missing init expr for _" */ int
+		_ int = 1, 2 /* ERROR "extra init expr 2" */
+	)
+
+	const (
+		_ = 1
+		_
+		_, _ /* ERROR "missing init expr for _" */
+		_
+	)
+
+	const (
+		_, _ = 1, 2
+		_, _
+		_ /* ERROR "extra init expr at" */
+		_, _
+		_, _, _ /* ERROR "missing init expr for _" */
+		_, _
+	)
+}
+
+// Test case for constant with invalid initialization.
+// Caused panic because the constant value was not set up (gri - 7/8/2014).
+func _() {
+	const (
+	    x string = missing /* ERROR "undeclared name" */
+	    y = x + ""
+	)
+}
+
+// TODO(gri) move extra tests from testdata/const0.src into here
diff --git a/src/go/types/testdata/conversions.src b/src/go/types/testdata/conversions.src
new file mode 100644
index 0000000..e1336c0
--- /dev/null
+++ b/src/go/types/testdata/conversions.src
@@ -0,0 +1,93 @@
+// 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.
+
+// conversions
+
+package conversions
+
+import "unsafe"
+
+// argument count
+var (
+	_ = int() /* ERROR "missing argument" */
+	_ = int(1, 2 /* ERROR "too many arguments" */ )
+)
+
+// numeric constant conversions are in const1.src.
+
+func string_conversions() {
+	const A = string(65)
+	assert(A == "A")
+	const E = string(-1)
+	assert(E == "\uFFFD")
+	assert(E == string(1234567890))
+
+	type myint int
+	assert(A == string(myint(65)))
+
+	type mystring string
+	const _ mystring = mystring("foo")
+
+	const _ = string(true /* ERROR "cannot convert" */ )
+	const _ = string(1.2 /* ERROR "cannot convert" */ )
+	const _ = string(nil /* ERROR "cannot convert" */ )
+
+	// issues 11357, 11353: argument must be of integer type
+	_ = string(0.0 /* ERROR "cannot convert" */ )
+	_ = string(0i /* ERROR "cannot convert" */ )
+	_ = string(1 /* ERROR "cannot convert" */ + 2i)
+}
+
+func interface_conversions() {
+	type E interface{}
+
+	type I1 interface{
+		m1()
+	}
+
+	type I2 interface{
+		m1()
+		m2(x int)
+	}
+
+	type I3 interface{
+		m1()
+		m2() int
+	}
+
+	var e E
+	var i1 I1
+	var i2 I2
+	var i3 I3
+
+	_ = E(0)
+	_ = E(nil)
+	_ = E(e)
+	_ = E(i1)
+	_ = E(i2)
+
+	_ = I1(0 /* ERROR "cannot convert" */ )
+	_ = I1(nil)
+	_ = I1(i1)
+	_ = I1(e /* ERROR "cannot convert" */ )
+	_ = I1(i2)
+
+	_ = I2(nil)
+	_ = I2(i1 /* ERROR "cannot convert" */ )
+	_ = I2(i2)
+	_ = I2(i3 /* ERROR "cannot convert" */ )
+
+	_ = I3(nil)
+	_ = I3(i1 /* ERROR "cannot convert" */ )
+	_ = I3(i2 /* ERROR "cannot convert" */ )
+	_ = I3(i3)
+
+	// TODO(gri) add more tests, improve error message
+}
+
+func issue6326() {
+	type T unsafe.Pointer
+	var x T
+	_ = uintptr(x) // see issue 6326
+}
diff --git a/src/go/types/testdata/cycles.src b/src/go/types/testdata/cycles.src
new file mode 100644
index 0000000..621d83c
--- /dev/null
+++ b/src/go/types/testdata/cycles.src
@@ -0,0 +1,143 @@
+// 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 cycles
+
+type (
+	T0 int
+	T1 /* ERROR cycle */ T1
+	T2 *T2
+
+	T3 /* ERROR cycle */ T4
+	T4 T5
+	T5 T3
+
+	T6 T7
+	T7 *T8
+	T8 T6
+
+	// arrays
+	A0 /* ERROR cycle */ [10]A0
+	A1 [10]*A1
+
+	A2 /* ERROR cycle */ [10]A3
+	A3 [10]A4
+	A4 A2
+
+	A5 [10]A6
+	A6 *A5
+
+	// slices
+	L0 []L0
+
+	// structs
+	S0 /* ERROR cycle */ struct{ _ S0 }
+	S1 /* ERROR cycle */ struct{ S1 }
+	S2 struct{ _ *S2 }
+	S3 struct{ *S3 }
+
+	S4 /* ERROR cycle */ struct{ S5 }
+	S5 struct{ S6 }
+	S6 S4
+
+	// pointers
+	P0 *P0
+
+	// functions
+	F0 func(F0)
+	F1 func() F1
+	F2 func(F2) F2
+
+	// interfaces
+	I0 /* ERROR cycle */ interface{ I0 }
+
+	I1 interface{ I2 }
+	I2 interface{ I3 }
+	I3 /* ERROR cycle */ interface{ I1 }
+
+	I4 interface{ f(I4) }
+
+	// testcase for issue 5090
+	I5 interface{ f(I6) }
+	I6 interface{ I5 }
+
+	// maps
+	M0 map[M0 /* ERROR invalid map key */ ]M0
+
+	// channels
+	C0 chan C0
+)
+
+func _() {
+	type (
+		t1 /* ERROR cycle */ t1
+		t2 *t2
+
+		t3 t4 /* ERROR undeclared */
+		t4 t5 /* ERROR undeclared */
+		t5 t3
+
+		// arrays
+		a0 /* ERROR cycle */ [10]a0
+		a1 [10]*a1
+
+		// slices
+		l0 []l0
+
+		// structs
+		s0 /* ERROR cycle */ struct{ _ s0 }
+		s1 /* ERROR cycle */ struct{ s1 }
+		s2 struct{ _ *s2 }
+		s3 struct{ *s3 }
+
+		// pointers
+		p0 *p0
+
+		// functions
+		f0 func(f0)
+		f1 func() f1
+		f2 func(f2) f2
+
+		// interfaces
+		i0 /* ERROR cycle */ interface{ i0 }
+
+		// maps
+		m0 map[m0 /* ERROR invalid map key */ ]m0
+
+		// channels
+		c0 chan c0
+	)
+}
+
+// test cases for issue 6667
+
+type A [10]map[A /* ERROR invalid map key */ ]bool
+
+type S struct {
+	m map[S /* ERROR invalid map key */ ]bool
+}
+
+// test cases for issue 7236
+// (cycle detection must not be dependent on starting point of resolution)
+
+type (
+	P1 *T9
+	T9 /* ERROR cycle */ T9
+
+	T10 /* ERROR cycle */ T10
+	P2 *T10
+)
+
+func (T11) m() {}
+
+type T11 /* ERROR cycle */ struct{ T11 }
+
+type T12 /* ERROR cycle */ struct{ T12 }
+
+func (*T12) m() {}
+
+type (
+	P3 *T13
+	T13 /* ERROR cycle */ T13
+)
\ No newline at end of file
diff --git a/src/go/types/testdata/cycles1.src b/src/go/types/testdata/cycles1.src
new file mode 100644
index 0000000..ae2b38e
--- /dev/null
+++ b/src/go/types/testdata/cycles1.src
@@ -0,0 +1,77 @@
+// 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 p
+
+type (
+	A interface {
+		a() interface {
+			ABC1
+		}
+	}
+	B interface {
+		b() interface {
+			ABC2
+		}
+	}
+	C interface {
+		c() interface {
+			ABC3
+		}
+	}
+
+	AB interface {
+		A
+		B
+	}
+	BC interface {
+		B
+		C
+	}
+
+	ABC1 interface {
+		A
+		B
+		C
+	}
+	ABC2 interface {
+		AB
+		C
+	}
+	ABC3 interface {
+		A
+		BC
+	}
+)
+
+var (
+	x1 ABC1
+	x2 ABC2
+	x3 ABC3
+)
+
+func _() {
+	// all types have the same method set
+	x1 = x2
+	x2 = x1
+
+	x1 = x3
+	x3 = x1
+
+	x2 = x3
+	x3 = x2
+
+	// all methods return the same type again
+	x1 = x1.a()
+	x1 = x1.b()
+	x1 = x1.c()
+
+	x2 = x2.a()
+	x2 = x2.b()
+	x2 = x2.c()
+
+	x3 = x3.a()
+	x3 = x3.b()
+	x3 = x3.c()
+}
diff --git a/src/go/types/testdata/cycles2.src b/src/go/types/testdata/cycles2.src
new file mode 100644
index 0000000..345ab56
--- /dev/null
+++ b/src/go/types/testdata/cycles2.src
@@ -0,0 +1,118 @@
+// 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 p
+
+import "unsafe"
+
+// Test case for issue 5090
+
+type t interface {
+	f(u)
+}
+
+type u interface {
+	t
+}
+
+func _() {
+	var t t
+	var u u
+
+	t.f(t)
+	t.f(u)
+	
+	u.f(t)
+	u.f(u)
+}
+
+
+// Test case for issue 6589.
+
+type A interface {
+	a() interface {
+		AB
+	}
+}
+
+type B interface {
+	a() interface {
+		AB
+	}
+}
+
+type AB interface {
+	a() interface {
+		A
+		B /* ERROR a redeclared */
+	}
+	b() interface {
+		A
+		B /* ERROR a redeclared */
+	}
+}
+
+var x AB
+var y interface {
+	A
+	B /* ERROR a redeclared */
+}
+var _ = x /* ERROR cannot compare */ == y
+
+
+// Test case for issue 6638.
+
+type T interface {
+	m() [T /* ERROR no value */ (nil).m()[0]]int
+}
+
+// Variations of this test case.
+
+type T1 interface {
+	m() [x1 /* ERROR no value */ .m()[0]]int
+}
+
+var x1 T1
+
+type T2 interface {
+	m() [len(x2 /* ERROR no value */ .m())]int
+}
+
+var x2 T2
+
+type T3 interface {
+	m() [unsafe.Sizeof(x3.m)]int
+}
+
+var x3 T3
+
+// The test case below should also report an error for
+// the cast inside the T4 interface (like it does for the
+// variable initialization). The reason why it does not is
+// that inside T4, the method x4.m depends on T4 which is not
+// fully set up yet. The x4.m method happens to have an empty
+// signature which is why the cast is permitted.
+// TODO(gri) Consider marking methods as incomplete and provide
+// a better error message in that case.
+
+type T4 interface {
+	m() [unsafe.Sizeof(cast4(x4.m))]int
+}
+
+var x4 T4
+var _ = cast4(x4 /* ERROR cannot convert */.m)
+
+type cast4 func()
+
+// This test is symmetric to the T4 case: Here the cast is
+// "correct", but it doesn't work inside the T5 interface.
+
+type T5 interface {
+	m() [unsafe.Sizeof(cast5(x5 /* ERROR cannot convert */ .m))]int
+}
+
+var x5 T5
+var _ = cast5(x5.m)
+
+type cast5 func() [0]int
diff --git a/src/go/types/testdata/cycles3.src b/src/go/types/testdata/cycles3.src
new file mode 100644
index 0000000..3da4fb5
--- /dev/null
+++ b/src/go/types/testdata/cycles3.src
@@ -0,0 +1,60 @@
+// 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 p
+
+import "unsafe"
+
+var (
+	_ A = A(nil).a().b().c().d().e().f()
+	_ A = A(nil).b().c().d().e().f()
+	_ A = A(nil).c().d().e().f()
+	_ A = A(nil).d().e().f()
+	_ A = A(nil).e().f()
+	_ A = A(nil).f()
+	_ A = A(nil)
+)
+
+type (
+	A interface {
+		a() B
+		B
+	}
+
+	B interface {
+		b() C
+		C
+	}
+
+	C interface {
+		c() D
+		D
+	}
+
+	D interface {
+		d() E
+		E
+	}
+
+	E interface {
+		e() F
+		F
+	}
+
+	F interface {
+		f() A
+	}
+)
+
+type (
+	U interface {
+		V
+	}
+
+	V interface {
+		v() [unsafe.Sizeof(u)]int
+	}
+)
+
+var u U
diff --git a/src/go/types/testdata/cycles4.src b/src/go/types/testdata/cycles4.src
new file mode 100644
index 0000000..445babc
--- /dev/null
+++ b/src/go/types/testdata/cycles4.src
@@ -0,0 +1,110 @@
+// 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 p
+
+// Check that all methods of T are collected before
+// determining the result type of m (which embeds
+// all methods of T).
+
+type T interface {
+	m() interface {T}
+	E
+}
+
+var _ = T.m(nil).m().e()
+
+type E interface {
+	e() int
+}
+
+// Check that unresolved forward chains are followed
+// (see also comment in resolver.go, checker.typeDecl).
+
+var _ = C.m(nil).m().e()
+
+type A B
+
+type B interface {
+	m() interface{C}
+	E
+}
+
+type C A
+
+// Check that interface type comparison for identity
+// does not recur endlessly.
+
+type T1 interface {
+	m() interface{T1}
+}
+
+type T2 interface {
+	m() interface{T2}
+}
+
+func _(x T1, y T2) {
+	// Checking for assignability of interfaces must check
+	// if all methods of x are present in y, and that they
+	// have identical signatures. The signatures recur via
+	// the result type, which is an interface that embeds
+	// a single method m that refers to the very interface
+	// that contains it. This requires cycle detection in
+	// identity checks for interface types.
+	x = y
+}
+
+type T3 interface {
+	m() interface{T4}
+}
+
+type T4 interface {
+	m() interface{T3}
+}
+
+func _(x T1, y T3) {
+	x = y
+}
+
+// Check that interfaces are type-checked in order of
+// (embedded interface) dependencies (was issue 7158).
+
+var x1 T5 = T7(nil)
+
+type T5 interface {
+	T6
+}
+
+type T6 interface {
+	m() T7
+}
+type T7 interface {
+	T5
+}
+
+// Actual test case from issue 7158.
+
+func wrapNode() Node {
+	return wrapElement()
+}
+
+func wrapElement() Element {
+	return nil
+}
+
+type EventTarget interface {
+	AddEventListener(Event)
+}
+
+type Node interface {
+	EventTarget
+}
+
+type Element interface {
+	Node
+}
+
+type Event interface {
+	Target() Element
+}
diff --git a/src/go/types/testdata/decls0.src b/src/go/types/testdata/decls0.src
new file mode 100644
index 0000000..21baafe
--- /dev/null
+++ b/src/go/types/testdata/decls0.src
@@ -0,0 +1,207 @@
+// 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.
+
+// type declarations
+
+package decls0
+
+import "unsafe"
+
+const pi = 3.1415
+
+type (
+	N undeclared /* ERROR "undeclared" */
+	B bool
+	I int32
+	A [10]P
+	T struct {
+		x, y P
+	}
+	P *T
+	R (*R)
+	F func(A) I
+	Y interface {
+		f(A) I
+	}
+	S [](((P)))
+	M map[I]F
+	C chan<- I
+
+	// blank types must be typechecked
+	_ pi /* ERROR "not a type" */
+	_ struct{}
+	_ struct{ pi /* ERROR "not a type" */ }
+)
+
+
+// declarations of init
+const _, init /* ERROR "cannot declare init" */ , _ = 0, 1, 2
+type init /* ERROR "cannot declare init" */ struct{}
+var _, init /* ERROR "cannot declare init" */ int
+
+func init() {}
+func init /* ERROR "missing function body" */ ()
+
+func _() { const init = 0 }
+func _() { type init int }
+func _() { var init int; _ = init }
+
+// invalid array types
+type (
+	iA0 [... /* ERROR "invalid use of '...'" */ ]byte
+	iA1 [1 /* ERROR "invalid array length" */ <<100]int
+	iA2 [- /* ERROR "invalid array length" */ 1]complex128
+	iA3 ["foo" /* ERROR "must be integer" */ ]string
+	iA4 [float64 /* ERROR "must be integer" */ (0)]int
+)
+
+
+type (
+	p1 pi /* ERROR "no field or method foo" */ .foo
+	p2 unsafe.Pointer
+)
+
+
+type (
+	Pi pi /* ERROR "not a type" */
+
+	a /* ERROR "illegal cycle" */ a
+	a /* ERROR "redeclared" */ int
+
+	// where the cycle error appears depends on the
+	// order in which declarations are processed
+	// (which depends on the order in which a map
+	// is iterated through)
+	b /* ERROR "illegal cycle" */ c
+	c d
+	d e
+	e b
+
+	t *t
+
+	U V
+	V *W
+	W U
+
+	P1 *S2
+	P2 P1
+
+	S0 struct {
+	}
+	S1 struct {
+		a, b, c int
+		u, v, a /* ERROR "redeclared" */ float32
+	}
+	S2 struct {
+		S0 // anonymous field
+		S0 /* ERROR "redeclared" */ int
+	}
+	S3 struct {
+		x S2
+	}
+	S4/* ERROR "illegal cycle" */ struct {
+		S4
+	}
+	S5 /* ERROR "illegal cycle" */ struct {
+		S6
+	}
+	S6 struct {
+		field S7
+	}
+	S7 struct {
+		S5
+	}
+
+	L1 []L1
+	L2 []int
+
+	A1 [10.0]int
+	A2 /* ERROR "illegal cycle" */ [10]A2
+	A3 /* ERROR "illegal cycle" */ [10]struct {
+		x A4
+	}
+	A4 [10]A3
+
+	F1 func()
+	F2 func(x, y, z float32)
+	F3 func(x, y, x /* ERROR "redeclared" */ float32)
+	F4 func() (x, y, x /* ERROR "redeclared" */ float32)
+	F5 func(x int) (x /* ERROR "redeclared" */ float32)
+	F6 func(x ...int)
+
+	I1 interface{}
+	I2 interface {
+		m1()
+	}
+	I3 interface {
+		m1()
+		m1 /* ERROR "redeclared" */ ()
+	}
+	I4 interface {
+		m1(x, y, x /* ERROR "redeclared" */ float32)
+		m2() (x, y, x /* ERROR "redeclared" */ float32)
+		m3(x int) (x /* ERROR "redeclared" */ float32)
+	}
+	I5 interface {
+		m1(I5)
+	}
+	I6 interface {
+		S0 /* ERROR "not an interface" */
+	}
+	I7 interface {
+		I1
+		I1
+	}
+	I8 /* ERROR "illegal cycle" */ interface {
+		I8
+	}
+	I9 interface {
+		I10
+	}
+	I10 interface {
+		I11
+	}
+	I11 /* ERROR "illegal cycle" */ interface {
+		I9
+	}
+
+	C1 chan int
+	C2 <-chan int
+	C3 chan<- C3
+	C4 chan C5
+	C5 chan C6
+	C6 chan C4
+
+	M1 map[Last]string
+	M2 map[string]M2
+
+	Last int
+)
+
+// cycles in function/method declarations
+// (test cases for issue 5217 and variants)
+func f1(x f1 /* ERROR "not a type" */ ) {}
+func f2(x *f2 /* ERROR "not a type" */ ) {}
+func f3() (x f3 /* ERROR "not a type" */ ) { return }
+func f4() (x *f4 /* ERROR "not a type" */ ) { return }
+
+func (S0) m1(x S0 /* ERROR "field or method" */ .m1) {}
+func (S0) m2(x *S0 /* ERROR "field or method" */ .m2) {}
+func (S0) m3() (x S0 /* ERROR "field or method" */ .m3) { return }
+func (S0) m4() (x *S0 /* ERROR "field or method" */ .m4) { return }
+
+// interfaces may not have any blank methods
+type BlankI interface {
+	_ /* ERROR "invalid method name" */ ()
+	_ /* ERROR "invalid method name" */ (float32) int
+	m()
+}
+
+// non-interface types may have multiple blank methods
+type BlankT struct{}
+
+func (BlankT) _() {}
+func (BlankT) _(int) {}
+func (BlankT) _() int { return 0 }
+func (BlankT) _(int) int { return 0}
diff --git a/src/go/types/testdata/decls1.src b/src/go/types/testdata/decls1.src
new file mode 100644
index 0000000..7855e46
--- /dev/null
+++ b/src/go/types/testdata/decls1.src
@@ -0,0 +1,144 @@
+// 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.
+
+// variable declarations
+
+package decls1
+
+import (
+	"math"
+)
+
+// Global variables without initialization
+var (
+	a, b bool
+	c byte
+	d uint8
+	r rune
+	i int
+	j, k, l int
+	x, y float32
+	xx, yy float64
+	u, v complex64
+	uu, vv complex128
+	s, t string
+	array []byte
+	iface interface{}
+	
+	blank _ /* ERROR "cannot use _" */
+)
+
+// Global variables with initialization
+var (
+	s1 = i + j
+	s2 = i /* ERROR "mismatched types" */ + x
+	s3 = c + d
+	s4 = s + t
+	s5 = s /* ERROR "invalid operation" */ / t
+	s6 = array[t1]
+	s7 = array[x /* ERROR "integer" */]
+	s8 = &a
+	s10 = &42 /* ERROR "cannot take address" */
+	s11 = &v
+	s12 = -(u + *t11) / *&v
+	s13 = a /* ERROR "shifted operand" */ << d
+	s14 = i << j /* ERROR "must be unsigned" */ 
+	s18 = math.Pi * 10.0
+	s19 = s1 /* ERROR "cannot call" */ ()
+ 	s20 = f0 /* ERROR "no value" */ ()
+	s21 = f6(1, s1, i)
+	s22 = f6(1, s1, uu /* ERROR "cannot pass argument" */ )
+	
+	t1 int = i + j
+	t2 int = i /* ERROR "mismatched types" */ + x
+	t3 int = c /* ERROR "cannot initialize" */ + d
+	t4 string = s + t
+	t5 string = s /* ERROR "invalid operation" */ / t
+	t6 byte = array[t1]
+	t7 byte = array[x /* ERROR "must be integer" */]
+	t8 *int = & /* ERROR "cannot initialize" */ a
+	t10 *int = &42 /* ERROR "cannot take address" */
+	t11 *complex64 = &v
+	t12 complex64 = -(u + *t11) / *&v
+	t13 int = a /* ERROR "shifted operand" */ << d
+	t14 int = i << j /* ERROR "must be unsigned" */ 
+	t15 math /* ERROR "not in selector" */
+	t16 math /* ERROR "not declared" */ .xxx
+	t17 math /* ERROR "not a type" */ .Pi
+	t18 float64 = math.Pi * 10.0
+	t19 int = t1 /* ERROR "cannot call" */ ()
+	t20 int = f0 /* ERROR "no value" */ ()
+	t21 int = a /* ERROR "cannot initialize" */
+)
+
+// Various more complex expressions
+var (
+	u1 = x /* ERROR "not an interface" */ .(int)
+	u2 = iface.([]int)
+	u3 = iface.(a /* ERROR "not a type" */ )
+	u4, ok = iface.(int)
+	u5, ok2, ok3 = iface /* ERROR "assignment count mismatch" */ .(int)
+)
+
+// Constant expression initializations
+var (
+	v1 = 1 /* ERROR "cannot convert" */ + "foo"
+	v2 = c + 255
+	v3 = c + 256 /* ERROR "overflows" */
+	v4 = r + 2147483647
+	v5 = r + 2147483648 /* ERROR "overflows" */
+	v6 = 42
+	v7 = v6 + 9223372036854775807
+	v8 = v6 + 9223372036854775808 /* ERROR "overflows" */
+	v9 = i + 1 << 10
+	v10 byte = 1024 /* ERROR "overflows" */
+	v11 = xx/yy*yy - xx
+	v12 = true && false
+	v13 = nil /* ERROR "use of untyped nil" */
+)
+
+// Multiple assignment expressions
+var (
+	m1a, m1b = 1, 2
+	m2a, m2b, m2c /* ERROR "missing init expr for m2c" */ = 1, 2
+	m3a, m3b = 1, 2, 3 /* ERROR "extra init expr 3" */
+)
+
+func _() {
+	var (
+		m1a, m1b = 1, 2
+		m2a, m2b, m2c /* ERROR "missing init expr for m2c" */ = 1, 2
+		m3a, m3b = 1, 2, 3 /* ERROR "extra init expr 3" */
+	)
+
+	_, _ = m1a, m1b
+	_, _, _ = m2a, m2b, m2c
+	_, _ = m3a, m3b
+}
+
+// Declaration of parameters and results
+func f0() {}
+func f1(a /* ERROR "not a type" */) {}
+func f2(a, b, c d /* ERROR "not a type" */) {}
+
+func f3() int { return 0 }
+func f4() a /* ERROR "not a type" */ { return 0 }
+func f5() (a, b, c d /* ERROR "not a type" */) { return }
+
+func f6(a, b, c int) complex128 { return 0 }
+
+// Declaration of receivers
+type T struct{}
+
+func (T) m0() {}
+func (*T) m1() {}
+func (x T) m2() {}
+func (x *T) m3() {}
+
+// Initialization functions
+func init() {}
+func /* ERROR "no arguments and no return values" */ init(int) {}
+func /* ERROR "no arguments and no return values" */ init() int { return 0 }
+func /* ERROR "no arguments and no return values" */ init(int) int { return 0 }
+func (T) init(int) int { return 0 }
diff --git a/src/go/types/testdata/decls2a.src b/src/go/types/testdata/decls2a.src
new file mode 100644
index 0000000..bdbecd9
--- /dev/null
+++ b/src/go/types/testdata/decls2a.src
@@ -0,0 +1,111 @@
+// 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.
+
+// method declarations
+
+package decls2
+
+import "time"
+import "unsafe"
+
+// T1 declared before its methods.
+type T1 struct{
+	f int
+}
+
+func (T1) m() {}
+func (T1) m /* ERROR "already declared" */ () {}
+func (x *T1) f /* ERROR "field and method" */ () {}
+
+// Conflict between embedded field and method name,
+// with the embedded field being a basic type.
+type T1b struct {
+	int
+}
+
+func (T1b) int /* ERROR "field and method" */ () {}
+
+type T1c struct {
+	time.Time
+}
+
+func (T1c) Time /* ERROR "field and method" */ () int { return 0 }
+
+// Disabled for now: LookupFieldOrMethod will find Pointer even though
+// it's double-declared (it would cost extra in the common case to verify
+// this). But the MethodSet computation will not find it due to the name
+// collision caused by the double-declaration, leading to an internal
+// inconsistency while we are verifying one computation against the other.
+// var _ = T1c{}.Pointer
+
+// T2's method declared before the type.
+func (*T2) f /* ERROR "field and method" */ () {}
+
+type T2 struct {
+	f int
+}
+
+// Methods declared without a declared type.
+func (undeclared /* ERROR "undeclared" */) m() {}
+func (x *undeclared /* ERROR "undeclared" */) m() {}
+
+func (pi /* ERROR "not a type" */) m1() {}
+func (x pi /* ERROR "not a type" */) m2() {}
+func (x *pi /* ERROR "not a type" */ ) m3() {}
+
+// Blank types.
+type _ struct { m int }
+type _ struct { m int }
+
+func (_ /* ERROR "cannot use _" */) m() {}
+func m(_ /* ERROR "cannot use _" */) {}
+
+// Methods with receiver base type declared in another file.
+func (T3) m1() {}
+func (*T3) m2() {}
+func (x T3) m3() {}
+func (x *T3) f /* ERROR "field and method" */ () {}
+
+// Methods of non-struct type.
+type T4 func()
+
+func (self T4) m() func() { return self }
+
+// Methods associated with an interface.
+type T5 interface {
+	m() int
+}
+
+func (T5 /* ERROR "invalid receiver" */ ) m1() {}
+func (T5 /* ERROR "invalid receiver" */ ) m2() {}
+
+// Methods associated with a named pointer type.
+type ptr *int
+func (ptr /* ERROR "invalid receiver" */ ) _() {}
+func (* /* ERROR "invalid receiver" */ ptr) _() {}
+
+// Methods with zero or multiple receivers.
+func ( /* ERROR "missing receiver" */ ) _() {}
+func (T3, * /* ERROR "exactly one receiver" */ T3) _() {}
+func (T3, T3, T3 /* ERROR "exactly one receiver" */ ) _() {}
+func (a, b /* ERROR "exactly one receiver" */ T3) _() {}
+func (a, b, c /* ERROR "exactly one receiver" */ T3) _() {}
+
+// Methods associated with non-local or unnamed types.
+func (int /* ERROR "invalid receiver" */ ) m() {}
+func ([ /* ERROR "invalid receiver" */ ]int) m() {}
+func (time /* ERROR "invalid receiver" */ .Time) m() {}
+func (* /* ERROR "invalid receiver" */ time.Time) m() {}
+func (x /* ERROR "invalid receiver" */ interface{}) m() {}
+
+// Unsafe.Pointer is treated like a pointer when used as receiver type.
+type UP unsafe.Pointer
+func (UP /* ERROR "invalid" */ ) m1() {}
+func (* /* ERROR "invalid" */ UP) m2() {}
+
+// Double declarations across package files
+const c_double = 0
+type t_double int
+var v_double int
+func f_double() {}
diff --git a/src/go/types/testdata/decls2b.src b/src/go/types/testdata/decls2b.src
new file mode 100644
index 0000000..e7bc394
--- /dev/null
+++ b/src/go/types/testdata/decls2b.src
@@ -0,0 +1,65 @@
+// 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.
+
+// method declarations
+
+package decls2
+
+import "io"
+
+const pi = 3.1415
+
+func (T1) m /* ERROR "already declared" */ () {}
+func (T2) m(io.Writer) {}
+
+type T3 struct {
+	f *T3
+}
+
+type T6 struct {
+	x int
+}
+
+func (t *T6) m1() int {
+	return t.x
+}
+
+func f() {
+	var t *T6
+	t.m1()
+}
+
+// Double declarations across package files
+const c_double /* ERROR "redeclared" */ = 0
+type t_double  /* ERROR "redeclared" */ int
+var v_double /* ERROR "redeclared" */ int
+func f_double /* ERROR "redeclared" */ () {}
+
+// Blank methods need to be type-checked.
+// Verify by checking that errors are reported.
+func (T /* ERROR "undeclared" */ ) _() {}
+func (T1) _(undeclared /* ERROR "undeclared" */ ) {}
+func (T1) _() int { return "foo" /* ERROR "cannot convert" */ }
+
+// Methods with undeclared receiver type can still be checked.
+// Verify by checking that errors are reported.
+func (Foo /* ERROR "undeclared" */ ) m() {}
+func (Foo /* ERROR "undeclared" */ ) m(undeclared /* ERROR "undeclared" */ ) {}
+func (Foo /* ERROR "undeclared" */ ) m() int { return "foo" /* ERROR "cannot convert" */ }
+
+func (Foo /* ERROR "undeclared" */ ) _() {}
+func (Foo /* ERROR "undeclared" */ ) _(undeclared /* ERROR "undeclared" */ ) {}
+func (Foo /* ERROR "undeclared" */ ) _() int { return "foo" /* ERROR "cannot convert" */ }
+
+// Receiver declarations are regular parameter lists;
+// receiver types may use parentheses, and the list
+// may have a trailing comma.
+type T7 struct {}
+
+func (T7) m1() {}
+func ((T7)) m2() {}
+func ((*T7)) m3() {}
+func (x *(T7),) m4() {}
+func (x (*(T7)),) m5() {}
+func (x ((*((T7)))),) m6() {}
diff --git a/src/go/types/testdata/decls3.src b/src/go/types/testdata/decls3.src
new file mode 100644
index 0000000..80d2bc8
--- /dev/null
+++ b/src/go/types/testdata/decls3.src
@@ -0,0 +1,309 @@
+// 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.
+
+// embedded types
+
+package decls3
+
+import "unsafe"
+import "fmt"
+
+// fields with the same name at the same level cancel each other out
+
+func _() {
+	type (
+		T1 struct { X int }
+		T2 struct { X int }
+		T3 struct { T1; T2 } // X is embedded twice at the same level via T1->X, T2->X
+	)
+
+	var t T3
+	_ = t /* ERROR "ambiguous selector" */ .X
+}
+
+func _() {
+	type (
+		T1 struct { X int }
+		T2 struct { T1 }
+		T3 struct { T1 }
+		T4 struct { T2; T3 } // X is embedded twice at the same level via T2->T1->X, T3->T1->X
+	)
+
+	var t T4
+	_ = t /* ERROR "ambiguous selector" */ .X
+}
+
+func issue4355() {
+	type (
+	    T1 struct {X int}
+	    T2 struct {T1}
+	    T3 struct {T2}
+	    T4 struct {T2}
+	    T5 struct {T3; T4} // X is embedded twice at the same level via T3->T2->T1->X, T4->T2->T1->X
+	)	
+
+	var t T5
+	_ = t /* ERROR "ambiguous selector" */ .X
+}
+
+func _() {
+	type State int
+	type A struct{ State }
+	type B struct{ fmt.State }
+	type T struct{ A; B }
+
+	var t T
+	_ = t /* ERROR "ambiguous selector" */ .State
+}
+
+// Embedded fields can be predeclared types.
+
+func _() {
+	type T0 struct{
+		int
+		float32
+		f int
+	}
+	var x T0
+	_ = x.int
+	_ = x.float32
+	_ = x.f
+
+	type T1 struct{
+		T0
+	}
+	var y T1
+	_ = y.int
+	_ = y.float32
+	_ = y.f
+}
+
+// Restrictions on embedded field types.
+
+func _() {
+	type I1 interface{}
+	type I2 interface{}
+	type P1 *int
+	type P2 *int
+	type UP unsafe.Pointer
+
+	type T1 struct {
+		I1
+		* /* ERROR "cannot be a pointer to an interface" */ I2
+		* /* ERROR "cannot be a pointer to an interface" */ error
+		P1 /* ERROR "cannot be a pointer" */
+		* /* ERROR "cannot be a pointer" */ P2
+	}
+
+	// unsafe.Pointers are treated like regular pointers when embedded
+	type T2 struct {
+		unsafe /* ERROR "cannot be unsafe.Pointer" */ .Pointer
+		*/* ERROR "cannot be unsafe.Pointer" */ unsafe.Pointer
+		UP /* ERROR "cannot be unsafe.Pointer" */
+		* /* ERROR "cannot be unsafe.Pointer" */ UP
+	}
+}
+
+// Named types that are pointers.
+
+type S struct{ x int }
+func (*S) m() {}
+type P *S
+
+func _() {
+	var s *S
+	_ = s.x
+	_ = s.m
+
+	var p P
+	_ = p.x
+	_ = p /* ERROR "no field or method" */ .m
+	_ = P /* ERROR "no field or method" */ .m
+}
+
+// Borrowed from the FieldByName test cases in reflect/all_test.go.
+
+type D1 struct {
+	d int
+}
+type D2 struct {
+	d int
+}
+
+type S0 struct {
+	A, B, C int
+	D1
+	D2
+}
+
+type S1 struct {
+	B int
+	S0
+}
+
+type S2 struct {
+	A int
+	*S1
+}
+
+type S1x struct {
+	S1
+}
+
+type S1y struct {
+	S1
+}
+
+type S3 struct {
+	S1x
+	S2
+	D, E int
+	*S1y
+}
+
+type S4 struct {
+	*S4
+	A int
+}
+
+// The X in S6 and S7 annihilate, but they also block the X in S8.S9.
+type S5 struct {
+	S6
+	S7
+	S8
+}
+
+type S6 struct {
+	X int
+}
+
+type S7 S6
+
+type S8 struct {
+	S9
+}
+
+type S9 struct {
+	X int
+	Y int
+}
+
+// The X in S11.S6 and S12.S6 annihilate, but they also block the X in S13.S8.S9.
+type S10 struct {
+	S11
+	S12
+	S13
+}
+
+type S11 struct {
+	S6
+}
+
+type S12 struct {
+	S6
+}
+
+type S13 struct {
+	S8
+}
+
+func _() {
+	_ = struct /* ERROR "no field or method" */ {}{}.Foo
+	_ = S0{}.A
+	_ = S0 /* ERROR "no field or method" */ {}.D
+	_ = S1{}.A
+	_ = S1{}.B
+	_ = S1{}.S0
+	_ = S1{}.C
+	_ = S2{}.A
+	_ = S2{}.S1
+	_ = S2{}.B
+	_ = S2{}.C
+	_ = S2 /* ERROR "no field or method" */ {}.D
+	_ = S3 /* ERROR "ambiguous selector" */ {}.S1
+	_ = S3{}.A
+	_ = S3 /* ERROR "ambiguous selector" */ {}.B
+	_ = S3{}.D
+	_ = S3{}.E
+	_ = S4{}.A
+	_ = S4 /* ERROR "no field or method" */ {}.B
+	_ = S5 /* ERROR "ambiguous selector" */ {}.X
+	_ = S5{}.Y
+	_ = S10 /* ERROR "ambiguous selector" */ {}.X
+	_ = S10{}.Y
+}
+
+// Borrowed from the FieldByName benchmark in reflect/all_test.go.
+
+type R0 struct {
+	*R1
+	*R2
+	*R3
+	*R4
+}
+
+type R1 struct {
+	*R5
+	*R6
+	*R7
+	*R8
+}
+
+type R2 R1
+type R3 R1
+type R4 R1
+
+type R5 struct {
+	*R9
+	*R10
+	*R11
+	*R12
+}
+
+type R6 R5
+type R7 R5
+type R8 R5
+
+type R9 struct {
+	*R13
+	*R14
+	*R15
+	*R16
+}
+
+type R10 R9
+type R11 R9
+type R12 R9
+
+type R13 struct {
+	*R17
+	*R18
+	*R19
+	*R20
+}
+
+type R14 R13
+type R15 R13
+type R16 R13
+
+type R17 struct {
+	*R21
+	*R22
+	*R23
+	*R24
+}
+
+type R18 R17
+type R19 R17
+type R20 R17
+
+type R21 struct {
+	X int
+}
+
+type R22 R21
+type R23 R21
+type R24 R21
+
+var _ = R0 /* ERROR "ambiguous selector" */ {}.X
\ No newline at end of file
diff --git a/src/go/types/testdata/errors.src b/src/go/types/testdata/errors.src
new file mode 100644
index 0000000..45bd45a
--- /dev/null
+++ b/src/go/types/testdata/errors.src
@@ -0,0 +1,55 @@
+// 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 errors
+
+// Testing precise operand formatting in error messages
+// (matching messages are regular expressions, hence the \'s).
+func f(x int, m map[string]int) {
+	// no values
+	_ = f /* ERROR "f\(0, m\) \(no value\) used as value" */ (0, m)
+
+	// built-ins
+	_ = println /* ERROR "println \(built-in\) must be called" */
+
+	// types
+	_ = complex128 /* ERROR "complex128 \(type\) is not an expression" */
+
+	// constants
+	const c1 = 991
+	const c2 float32 = 0.5
+	0 /* ERROR "0 \(untyped int constant\) is not used" */
+	c1 /* ERROR "c1 \(untyped int constant 991\) is not used" */
+	c2 /* ERROR "c2 \(constant 1/2 of type float32\) is not used" */
+	c1 /* ERROR "c1 \+ c2 \(constant 1983/2 of type float32\) is not used" */ + c2
+
+	// variables
+	x /* ERROR "x \(variable of type int\) is not used" */
+
+	// values
+	x /* ERROR "x != x \(untyped bool value\) is not used" */ != x
+	x /* ERROR "x \+ x \(value of type int\) is not used" */ + x
+
+	// value, ok's
+	const s = "foo"
+	m /* ERROR "m\[s\] \(map index expression of type int\) is not used" */ [s]
+}
+
+// Valid ERROR comments can have a variety of forms.
+func _() {
+	0 /* ERROR "0 .* is not used" */
+	0 /* ERROR 0 .* is not used */
+	0 // ERROR "0 .* is not used"
+	0 // ERROR 0 .* is not used
+}
+
+// Don't report spurious errors as a consequence of earlier errors.
+// Add more tests as needed.
+func _() {
+	if err := foo /* ERROR undeclared */ (); err != nil /* no error here */ {}
+}
+
+// Use unqualified names for package-local objects.
+type T struct{}
+var _ int = T /* ERROR value of type T */ {} // use T in error message rather then errors.T
diff --git a/src/go/types/testdata/expr0.src b/src/go/types/testdata/expr0.src
new file mode 100644
index 0000000..3120c6f
--- /dev/null
+++ b/src/go/types/testdata/expr0.src
@@ -0,0 +1,174 @@
+// 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.
+
+// unary expressions
+
+package expr0 
+
+type mybool bool
+
+var (
+	// bool
+	b0 = true
+	b1 bool = b0
+	b2 = !true
+	b3 = !b1
+	b4 bool = !true
+	b5 bool = !b4
+	b6 = +b0 /* ERROR "not defined" */
+	b7 = -b0 /* ERROR "not defined" */
+	b8 = ^b0 /* ERROR "not defined" */
+	b9 = *b0 /* ERROR "cannot indirect" */
+	b10 = &true /* ERROR "cannot take address" */
+	b11 = &b0
+	b12 = <-b0 /* ERROR "cannot receive" */
+	b13 = & & /* ERROR "cannot take address" */ b0
+
+	// byte
+	_ = byte(0)
+	_ = byte(- /* ERROR "cannot convert" */ 1)
+	_ = - /* ERROR "-byte\(1\) \(constant -1 of type byte\) overflows byte" */ byte(1) // test for issue 11367
+	_ = byte /* ERROR "overflows byte" */ (0) - byte(1)
+
+	// int
+	i0 = 1
+	i1 int = i0
+	i2 = +1
+	i3 = +i0
+	i4 int = +1
+	i5 int = +i4
+	i6 = -1
+	i7 = -i0
+	i8 int = -1
+	i9 int = -i4
+	i10 = !i0 /* ERROR "not defined" */
+	i11 = ^1
+	i12 = ^i0
+	i13 int = ^1
+	i14 int = ^i4
+	i15 = *i0 /* ERROR "cannot indirect" */
+	i16 = &i0
+	i17 = *i16
+	i18 = <-i16 /* ERROR "cannot receive" */
+
+	// uint
+	u0 = uint(1)
+	u1 uint = u0
+	u2 = +1
+	u3 = +u0
+	u4 uint = +1
+	u5 uint = +u4
+	u6 = -1
+	u7 = -u0
+	u8 uint = - /* ERROR "overflows" */ 1
+	u9 uint = -u4
+	u10 = !u0 /* ERROR "not defined" */
+	u11 = ^1
+	u12 = ^i0
+	u13 uint = ^ /* ERROR "overflows" */ 1
+	u14 uint = ^u4
+	u15 = *u0 /* ERROR "cannot indirect" */
+	u16 = &u0
+	u17 = *u16
+	u18 = <-u16 /* ERROR "cannot receive" */
+	u19 = ^uint(0)
+
+	// float64
+	f0 = float64(1)
+	f1 float64 = f0
+	f2 = +1
+	f3 = +f0
+	f4 float64 = +1
+	f5 float64 = +f4
+	f6 = -1
+	f7 = -f0
+	f8 float64 = -1
+	f9 float64 = -f4
+	f10 = !f0 /* ERROR "not defined" */
+	f11 = ^1
+	f12 = ^i0
+	f13 float64 = ^1
+	f14 float64 = ^f4 /* ERROR "not defined" */
+	f15 = *f0 /* ERROR "cannot indirect" */
+	f16 = &f0
+	f17 = *u16
+	f18 = <-u16 /* ERROR "cannot receive" */
+
+	// complex128
+	c0 = complex128(1)
+	c1 complex128 = c0
+	c2 = +1
+	c3 = +c0
+	c4 complex128 = +1
+	c5 complex128 = +c4
+	c6 = -1
+	c7 = -c0
+	c8 complex128 = -1
+	c9 complex128 = -c4
+	c10 = !c0 /* ERROR "not defined" */
+	c11 = ^1
+	c12 = ^i0
+	c13 complex128 = ^1
+	c14 complex128 = ^c4 /* ERROR "not defined" */
+	c15 = *c0 /* ERROR "cannot indirect" */
+	c16 = &c0
+	c17 = *u16
+	c18 = <-u16 /* ERROR "cannot receive" */
+
+	// string
+	s0 = "foo"
+	s1 = +"foo" /* ERROR "not defined" */
+	s2 = -s0 /* ERROR "not defined" */
+	s3 = !s0 /* ERROR "not defined" */
+	s4 = ^s0 /* ERROR "not defined" */
+	s5 = *s4
+	s6 = &s4
+	s7 = *s6
+	s8 = <-s7
+
+	// channel
+	ch chan int
+	rc <-chan float64
+	sc chan <- string
+	ch0 = +ch /* ERROR "not defined" */
+	ch1 = -ch /* ERROR "not defined" */
+	ch2 = !ch /* ERROR "not defined" */
+	ch3 = ^ch /* ERROR "not defined" */
+	ch4 = *ch /* ERROR "cannot indirect" */
+	ch5 = &ch
+	ch6 = *ch5
+	ch7 = <-ch
+	ch8 = <-rc
+	ch9 = <-sc /* ERROR "cannot receive" */
+	ch10, ok = <-ch
+	// ok is of type bool
+	ch11, myok = <-ch
+	_ mybool = myok /* ERROR "cannot initialize" */
+)
+
+// address of composite literals
+type T struct{x, y int}
+
+func f() T { return T{} }
+
+var (
+	_ = &T{1, 2}
+	_ = &[...]int{}
+	_ = &[]int{}
+	_ = &[]int{}
+	_ = &map[string]T{}
+	_ = &(T{1, 2})
+	_ = &((((T{1, 2}))))
+	_ = &f /* ERROR "cannot take address" */ ()
+)
+
+// recursive pointer types
+type P *P
+
+var (
+	p1 P = new(P)
+	p2 P = *p1
+	p3 P = &p2
+)
+
diff --git a/src/go/types/testdata/expr1.src b/src/go/types/testdata/expr1.src
new file mode 100644
index 0000000..8ef0aed
--- /dev/null
+++ b/src/go/types/testdata/expr1.src
@@ -0,0 +1,7 @@
+// 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.
+
+// binary expressions
+
+package expr1
diff --git a/src/go/types/testdata/expr2.src b/src/go/types/testdata/expr2.src
new file mode 100644
index 0000000..31dc5f0
--- /dev/null
+++ b/src/go/types/testdata/expr2.src
@@ -0,0 +1,247 @@
+// 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.
+
+// comparisons
+
+package expr2
+
+func _bool() {
+	const t = true == true
+	const f = true == false
+	_ = t /* ERROR "cannot compare" */ < f
+	_ = 0 /* ERROR "cannot convert" */ == t
+	var b bool
+	var x, y float32
+	b = x < y
+	_ = b
+	_ = struct{b bool}{x < y}
+}
+
+// corner cases
+var (
+	v0 = nil /* ERROR "cannot compare" */ == nil
+)
+
+func arrays() {
+	// basics
+	var a, b [10]int
+	_ = a == b
+	_ = a != b
+	_ = a /* ERROR < not defined */ < b
+	_ = a == nil /* ERROR cannot convert */
+
+	type C [10]int
+	var c C
+	_ = a == c
+
+	type D [10]int
+	var d D
+	_ = c /* ERROR mismatched types */ == d
+
+	var e [10]func() int
+	_ = e /* ERROR == not defined */ == e
+}
+
+func structs() {
+	// basics
+	var s, t struct {
+		x int
+		a [10]float32
+		_ bool
+	}
+	_ = s == t
+	_ = s != t
+	_ = s /* ERROR < not defined */ < t
+	_ = s == nil /* ERROR cannot convert */
+
+	type S struct {
+		x int
+		a [10]float32
+		_ bool
+	}
+	type T struct {
+		x int
+		a [10]float32
+		_ bool
+	}
+	var ss S
+	var tt T
+	_ = s == ss
+	_ = ss /* ERROR mismatched types */ == tt
+
+	var u struct {
+		x int
+		a [10]map[string]int
+	}
+	_ = u /* ERROR cannot compare */ == u
+}
+
+func pointers() {
+	// nil
+	_ = nil /* ERROR == not defined */ == nil
+	_ = nil /* ERROR != not defined */ != nil
+	_ = nil /* ERROR < not defined */ < nil
+	_ = nil /* ERROR <= not defined */ <= nil
+	_ = nil /* ERROR > not defined */ > nil
+	_ = nil /* ERROR >= not defined */ >= nil
+
+	// basics
+	var p, q *int
+	_ = p == q
+	_ = p != q
+
+	_ = p == nil
+	_ = p != nil
+	_ = nil == q
+	_ = nil != q
+
+	_ = p /* ERROR < not defined */ < q
+	_ = p /* ERROR <= not defined */ <= q
+	_ = p /* ERROR > not defined */ > q
+	_ = p /* ERROR >= not defined */ >= q
+
+	// various element types
+	type (
+		S1 struct{}
+		S2 struct{}
+		P1 *S1
+		P2 *S2
+	)
+	var (
+		ps1 *S1
+		ps2 *S2
+		p1 P1
+		p2 P2
+	)
+	_ = ps1 == ps1
+	_ = ps1 /* ERROR mismatched types */ == ps2
+	_ = ps2 /* ERROR mismatched types */ == ps1
+
+	_ = p1 == p1
+	_ = p1 /* ERROR mismatched types */ == p2
+
+	_ = p1 == ps1
+}
+
+func channels() {
+	// basics
+	var c, d chan int
+	_ = c == d
+	_ = c != d
+	_ = c == nil
+	_ = c /* ERROR < not defined */ < d
+
+	// various element types (named types)
+	type (
+		C1 chan int
+		C1r <-chan int
+		C1s chan<- int
+		C2 chan float32
+	)
+	var (
+		c1 C1
+		c1r C1r
+		c1s C1s
+		c1a chan int
+		c2 C2
+	)
+	_ = c1 == c1
+	_ = c1 /* ERROR mismatched types */ == c1r
+	_ = c1 /* ERROR mismatched types */ == c1s
+	_ = c1r /* ERROR mismatched types */ == c1s
+	_ = c1 == c1a
+	_ = c1a == c1
+	_ = c1 /* ERROR mismatched types */ == c2
+	_ = c1a /* ERROR mismatched types */ == c2
+
+	// various element types (unnamed types)
+	var (
+		d1 chan int
+		d1r <-chan int
+		d1s chan<- int
+		d1a chan<- int
+		d2 chan float32
+	)
+	_ = d1 == d1
+	_ = d1 == d1r
+	_ = d1 == d1s
+	_ = d1r /* ERROR mismatched types */ == d1s
+	_ = d1 == d1a
+	_ = d1a == d1
+	_ = d1 /* ERROR mismatched types */ == d2
+	_ = d1a /* ERROR mismatched types */ == d2
+}
+
+// for interfaces test
+type S1 struct{}
+type S11 struct{}
+type S2 struct{}
+func (*S1) m() int
+func (*S11) m() int
+func (*S11) n()
+func (*S2) m() float32
+
+func interfaces() {
+	// basics
+	var i, j interface{ m() int }
+	_ = i == j
+	_ = i != j
+	_ = i == nil
+	_ = i /* ERROR < not defined */ < j
+
+	// various interfaces
+	var ii interface { m() int; n() }
+	var k interface { m() float32 }
+	_ = i == ii
+	_ = i /* ERROR mismatched types */ == k
+
+	// interfaces vs values
+	var s1 S1
+	var s11 S11
+	var s2 S2
+
+	_ = i == 0 /* ERROR cannot convert */
+	_ = i /* ERROR mismatched types */ == s1
+	_ = i == &s1
+	_ = i == &s11
+
+	_ = i /* ERROR mismatched types */ == s2
+	_ = i /* ERROR mismatched types */ == &s2
+}
+
+func slices() {
+	// basics
+	var s []int
+	_ = s == nil
+	_ = s != nil
+	_ = s /* ERROR < not defined */ < nil
+
+	// slices are not otherwise comparable
+	_ = s /* ERROR == not defined */ == s
+	_ = s /* ERROR < not defined */ < s
+}
+
+func maps() {
+	// basics
+	var m map[string]int
+	_ = m == nil
+	_ = m != nil
+	_ = m /* ERROR < not defined */ < nil
+
+	// maps are not otherwise comparable
+	_ = m /* ERROR == not defined */ == m
+	_ = m /* ERROR < not defined */ < m
+}
+
+func funcs() {
+	// basics
+	var f func(int) float32
+	_ = f == nil
+	_ = f != nil
+	_ = f /* ERROR < not defined */ < nil
+
+	// funcs are not otherwise comparable
+	_ = f /* ERROR == not defined */ == f
+	_ = f /* ERROR < not defined */ < f
+}
diff --git a/src/go/types/testdata/expr3.src b/src/go/types/testdata/expr3.src
new file mode 100644
index 0000000..5772095
--- /dev/null
+++ b/src/go/types/testdata/expr3.src
@@ -0,0 +1,534 @@
+// 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.
+
+package expr3
+
+import "time"
+
+func indexes() {
+	_ = 1 /* ERROR "cannot index" */ [0]
+	_ = indexes /* ERROR "cannot index" */ [0]
+	_ = ( /* ERROR "cannot slice" */ 12 + 3)[1:2]
+
+	var a [10]int
+	_ = a[true /* ERROR "cannot convert" */ ]
+	_ = a["foo" /* ERROR "cannot convert" */ ]
+	_ = a[1.1 /* ERROR "truncated" */ ]
+	_ = a[1.0]
+	_ = a[- /* ERROR "negative" */ 1]
+	_ = a[- /* ERROR "negative" */ 1 :]
+	_ = a[: - /* ERROR "negative" */ 1]
+	_ = a[: /* ERROR "2nd index required" */ : /* ERROR "3rd index required" */ ]
+	_ = a[0: /* ERROR "2nd index required" */ : /* ERROR "3rd index required" */ ]
+	_ = a[0: /* ERROR "2nd index required" */ :10]
+	_ = a[:10:10]
+
+	var a0 int
+	a0 = a[0]
+	_ = a0
+	var a1 int32
+	a1 = a /* ERROR "cannot assign" */ [1]
+	_ = a1
+
+	_ = a[9]
+	_ = a[10 /* ERROR "index .* out of bounds" */ ]
+	_ = a[1 /* ERROR "overflows" */ <<100]
+	_ = a[10:]
+	_ = a[:10]
+	_ = a[10:10]
+	_ = a[11 /* ERROR "index .* out of bounds" */ :]
+	_ = a[: 11 /* ERROR "index .* out of bounds" */ ]
+	_ = a[: 1 /* ERROR "overflows" */ <<100]
+	_ = a[:10:10]
+	_ = a[:11 /* ERROR "index .* out of bounds" */ :10]
+	_ = a[:10:11 /* ERROR "index .* out of bounds" */ ]
+	_ = a[10:0:10] /* ERROR "invalid slice indices" */
+	_ = a[0:10:0] /* ERROR "invalid slice indices" */
+	_ = a[10:0:0] /* ERROR "invalid slice indices" */
+	_ = &a /* ERROR "cannot take address" */ [:10]
+
+	pa := &a
+	_ = pa[9]
+	_ = pa[10 /* ERROR "index .* out of bounds" */ ]
+	_ = pa[1 /* ERROR "overflows" */ <<100]
+	_ = pa[10:]
+	_ = pa[:10]
+	_ = pa[10:10]
+	_ = pa[11 /* ERROR "index .* out of bounds" */ :]
+	_ = pa[: 11 /* ERROR "index .* out of bounds" */ ]
+	_ = pa[: 1 /* ERROR "overflows" */ <<100]
+	_ = pa[:10:10]
+	_ = pa[:11 /* ERROR "index .* out of bounds" */ :10]
+	_ = pa[:10:11 /* ERROR "index .* out of bounds" */ ]
+	_ = pa[10:0:10] /* ERROR "invalid slice indices" */
+	_ = pa[0:10:0] /* ERROR "invalid slice indices" */
+	_ = pa[10:0:0] /* ERROR "invalid slice indices" */
+	_ = &pa /* ERROR "cannot take address" */ [:10]
+
+	var b [0]int
+	_ = b[0 /* ERROR "index .* out of bounds" */ ]
+	_ = b[:]
+	_ = b[0:]
+	_ = b[:0]
+	_ = b[0:0]
+	_ = b[0:0:0]
+	_ = b[1 /* ERROR "index .* out of bounds" */ :0:0]
+
+	var s []int
+	_ = s[- /* ERROR "negative" */ 1]
+	_ = s[- /* ERROR "negative" */ 1 :]
+	_ = s[: - /* ERROR "negative" */ 1]
+	_ = s[0]
+	_ = s[1:2]
+	_ = s[2:1] /* ERROR "invalid slice indices" */
+	_ = s[2:]
+	_ = s[: 1 /* ERROR "overflows" */ <<100]
+	_ = s[1 /* ERROR "overflows" */ <<100 :]
+	_ = s[1 /* ERROR "overflows" */ <<100 : 1 /* ERROR "overflows" */ <<100]
+	_ = s[: /* ERROR "2nd index required" */ :  /* ERROR "3rd index required" */ ]
+	_ = s[:10:10]
+	_ = s[10:0:10] /* ERROR "invalid slice indices" */
+	_ = s[0:10:0] /* ERROR "invalid slice indices" */
+	_ = s[10:0:0] /* ERROR "invalid slice indices" */
+	_ = &s /* ERROR "cannot take address" */ [:10]
+
+	var m map[string]int
+	_ = m[0 /* ERROR "cannot convert" */ ]
+	_ = m /* ERROR "cannot slice" */ ["foo" : "bar"]
+	_ = m["foo"]
+	// ok is of type bool
+	type mybool bool
+	var ok mybool
+	_, ok = m["bar"]
+	_ = ok
+
+	var t string
+	_ = t[- /* ERROR "negative" */ 1]
+	_ = t[- /* ERROR "negative" */ 1 :]
+	_ = t[: - /* ERROR "negative" */ 1]
+	_ = t /* ERROR "3-index slice of string" */ [1:2:3]
+	_ = "foo" /* ERROR "3-index slice of string" */ [1:2:3]
+	var t0 byte
+	t0 = t[0]
+	_ = t0
+	var t1 rune
+	t1 = t /* ERROR "cannot assign" */ [2]
+	_ = t1
+	_ = ("foo" + "bar")[5]
+	_ = ("foo" + "bar")[6 /* ERROR "index .* out of bounds" */ ]
+
+	const c = "foo"
+	_ = c[- /* ERROR "negative" */ 1]
+	_ = c[- /* ERROR "negative" */ 1 :]
+	_ = c[: - /* ERROR "negative" */ 1]
+	var c0 byte
+	c0 = c[0]
+	_ = c0
+	var c2 float32
+	c2 = c /* ERROR "cannot assign" */ [2]
+	_ = c[3 /* ERROR "index .* out of bounds" */ ]
+	_ = ""[0 /* ERROR "index .* out of bounds" */ ]
+	_ = c2
+
+	_ = s[1<<30] // no compile-time error here
+
+	// issue 4913
+	type mystring string
+	var ss string
+	var ms mystring
+	var i, j int
+	ss = "foo"[1:2]
+	ss = "foo"[i:j]
+	ms = "foo" /* ERROR "cannot assign" */ [1:2]
+	ms = "foo" /* ERROR "cannot assign" */ [i:j]
+	_, _ = ss, ms
+}
+
+type T struct {
+	x int
+	y func()
+}
+
+func (*T) m() {}
+
+func method_expressions() {
+	_ = T /* ERROR "no field or method" */ .a
+	_ = T /* ERROR "has no method" */ .x
+	_ = T /* ERROR "not in method set" */ .m
+	_ = (*T).m
+
+	var f func(*T) = T /* ERROR "not in method set" */ .m
+	var g func(*T) = (*T).m
+	_, _ = f, g
+
+	_ = T /* ERROR "has no method" */ .y
+	_ = ( /* ERROR "has no method" */ *T).y
+}
+
+func struct_literals() {
+	type T0 struct {
+		a, b, c int
+	}
+
+	type T1 struct {
+		T0
+		a, b int
+		u float64
+		s string
+	}
+
+	// keyed elements
+	_ = T1{}
+	_ = T1{a: 0, 1 /* ERROR "mixture of .* elements" */ }
+	_ = T1{aa /* ERROR "unknown field" */ : 0}
+	_ = T1{1 /* ERROR "invalid field name" */ : 0}
+	_ = T1{a: 0, s: "foo", u: 0, a /* ERROR "duplicate field" */: 10}
+	_ = T1{a: "foo" /* ERROR "cannot convert" */ }
+	_ = T1{c /* ERROR "unknown field" */ : 0}
+	_ = T1{T0: { /* ERROR "missing type" */ }} // struct literal element type may not be elided
+	_ = T1{T0: T0{}}
+	_ = T1{T0 /* ERROR "invalid field name" */ .a: 0}
+
+	// unkeyed elements
+	_ = T0{1, 2, 3}
+	_ = T0{1, b /* ERROR "mixture" */ : 2, 3}
+	_ = T0{1, 2} /* ERROR "too few values" */
+	_ = T0{1, 2, 3, 4  /* ERROR "too many values" */ }
+	_ = T0{1, "foo" /* ERROR "cannot convert" */, 3.4  /* ERROR "truncated" */}
+
+	// invalid type
+	type P *struct{
+		x int
+	}
+	_ = P /* ERROR "invalid composite literal type" */ {}
+
+	// unexported fields
+	_ = time.Time{}
+	_ = time.Time{sec /* ERROR "unknown field" */ : 0}
+	_ = time.Time{
+		0 /* ERROR implicit assignment to unexported field sec in time.Time literal */,
+		0 /* ERROR implicit assignment */ ,
+		nil /* ERROR implicit assignment */ ,
+	}
+}
+
+func array_literals() {
+	type A0 [0]int
+	_ = A0{}
+	_ = A0{0 /* ERROR "index .* out of bounds" */}
+	_ = A0{0 /* ERROR "index .* out of bounds" */ : 0}
+
+	type A1 [10]int
+	_ = A1{}
+	_ = A1{0, 1, 2}
+	_ = A1{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
+	_ = A1{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 /* ERROR "index .* out of bounds" */ }
+	_ = A1{- /* ERROR "negative" */ 1: 0}
+	_ = A1{8: 8, 9}
+	_ = A1{8: 8, 9, 10 /* ERROR "index .* out of bounds" */ }
+	_ = A1{0, 1, 2, 0 /* ERROR "duplicate index" */ : 0, 3: 3, 4}
+	_ = A1{5: 5, 6, 7, 3: 3, 4}
+	_ = A1{5: 5, 6, 7, 3: 3, 4, 5 /* ERROR "duplicate index" */ }
+	_ = A1{10 /* ERROR "index .* out of bounds" */ : 10, 10 /* ERROR "index .* out of bounds" */ : 10}
+	_ = A1{5: 5, 6, 7, 3: 3, 1 /* ERROR "overflows" */ <<100: 4, 5 /* ERROR "duplicate index" */ }
+	_ = A1{5: 5, 6, 7, 4: 4, 1 /* ERROR "overflows" */ <<100: 4}
+	_ = A1{2.0}
+	_ = A1{2.1 /* ERROR "truncated" */ }
+	_ = A1{"foo" /* ERROR "cannot convert" */ }
+
+	// indices must be integer constants
+	i := 1
+	const f = 2.1
+	const s = "foo"
+	_ = A1{i /* ERROR "index i must be integer constant" */ : 0}
+	_ = A1{f /* ERROR "truncated" */ : 0}
+	_ = A1{s /* ERROR "cannot convert" */ : 0}
+
+	a0 := [...]int{}
+	assert(len(a0) == 0)
+
+	a1 := [...]int{0, 1, 2}
+	assert(len(a1) == 3)
+	var a13 [3]int
+	var a14 [4]int
+	a13 = a1
+	a14 = a1 /* ERROR "cannot assign" */
+	_, _ = a13, a14
+
+	a2 := [...]int{- /* ERROR "negative" */ 1: 0}
+	_ = a2
+
+	a3 := [...]int{0, 1, 2, 0 /* ERROR "duplicate index" */ : 0, 3: 3, 4}
+	assert(len(a3) == 5) // somewhat arbitrary
+
+	a4 := [...]complex128{0, 1, 2, 1<<10-2: -1i, 1i, 400: 10, 12, 14}
+	assert(len(a4) == 1024)
+
+	// composite literal element types may be elided
+	type T []int
+	_ = [10]T{T{}, {}, 5: T{1, 2, 3}, 7: {1, 2, 3}}
+	a6 := [...]T{T{}, {}, 5: T{1, 2, 3}, 7: {1, 2, 3}}
+	assert(len(a6) == 8)
+
+	// recursively so
+	_ = [10][10]T{{}, [10]T{{}}, {{1, 2, 3}}}
+
+	// from the spec
+	type Point struct { x, y float32 }
+	_ = [...]Point{Point{1.5, -3.5}, Point{0, 0}}
+	_ = [...]Point{{1.5, -3.5}, {0, 0}}
+	_ = [][]int{[]int{1, 2, 3}, []int{4, 5}}
+	_ = [][]int{{1, 2, 3}, {4, 5}}
+	_ = [...]*Point{&Point{1.5, -3.5}, &Point{0, 0}}
+	_ = [...]*Point{{1.5, -3.5}, {0, 0}}
+}
+
+func slice_literals() {
+	type S0 []int
+	_ = S0{}
+	_ = S0{0, 1, 2}
+	_ = S0{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
+	_ = S0{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
+	_ = S0{- /* ERROR "negative" */ 1: 0}
+	_ = S0{8: 8, 9}
+	_ = S0{8: 8, 9, 10}
+	_ = S0{0, 1, 2, 0 /* ERROR "duplicate index" */ : 0, 3: 3, 4}
+	_ = S0{5: 5, 6, 7, 3: 3, 4}
+	_ = S0{5: 5, 6, 7, 3: 3, 4, 5 /* ERROR "duplicate index" */ }
+	_ = S0{10: 10, 10 /* ERROR "duplicate index" */ : 10}
+	_ = S0{5: 5, 6, 7, 3: 3, 1 /* ERROR "overflows" */ <<100: 4, 5 /* ERROR "duplicate index" */ }
+	_ = S0{5: 5, 6, 7, 4: 4, 1 /* ERROR "overflows" */ <<100: 4}
+	_ = S0{2.0}
+	_ = S0{2.1 /* ERROR "truncated" */ }
+	_ = S0{"foo" /* ERROR "cannot convert" */ }
+
+	// indices must be resolved correctly
+	const index1 = 1
+	_ = S0{index1: 1}
+	_ = S0{index2: 2}
+	_ = S0{index3 /* ERROR "undeclared name" */ : 3}
+
+	// indices must be integer constants
+	i := 1
+	const f = 2.1
+	const s = "foo"
+	_ = S0{i /* ERROR "index i must be integer constant" */ : 0}
+	_ = S0{f /* ERROR "truncated" */ : 0}
+	_ = S0{s /* ERROR "cannot convert" */ : 0}
+
+	// composite literal element types may be elided
+	type T []int
+	_ = []T{T{}, {}, 5: T{1, 2, 3}, 7: {1, 2, 3}}
+	_ = [][]int{{1, 2, 3}, {4, 5}}
+
+	// recursively so
+	_ = [][]T{{}, []T{{}}, {{1, 2, 3}}}
+}
+
+const index2 int = 2
+
+type N int
+func (N) f() {}
+
+func map_literals() {
+	type M0 map[string]int
+	type M1 map[bool]int
+	type M2 map[*int]int
+
+	_ = M0{}
+	_ = M0{1 /* ERROR "missing key" */ }
+	_ = M0{1 /* ERROR "cannot convert" */ : 2}
+	_ = M0{"foo": "bar" /* ERROR "cannot convert" */ }
+	_ = M0{"foo": 1, "bar": 2, "foo" /* ERROR "duplicate key" */ : 3 }
+
+	_ = map[interface{}]int{2: 1, 2 /* ERROR "duplicate key" */ : 1}
+	_ = map[interface{}]int{int(2): 1, int16(2): 1}
+	_ = map[interface{}]int{int16(2): 1, int16 /* ERROR "duplicate key" */ (2): 1}
+
+	type S string
+
+	_ = map[interface{}]int{"a": 1, "a" /* ERROR "duplicate key" */ : 1}
+	_ = map[interface{}]int{"a": 1, S("a"): 1}
+	_ = map[interface{}]int{S("a"): 1, S /* ERROR "duplicate key" */ ("a"): 1}
+
+	type I interface {
+		f()
+	}
+
+	_ = map[I]int{N(0): 1, N(2): 1}
+	_ = map[I]int{N(2): 1, N /* ERROR "duplicate key" */ (2): 1}
+
+	// map keys must be resolved correctly
+	key1 := "foo"
+	_ = M0{key1: 1}
+	_ = M0{key2: 2}
+	_ = M0{key3 /* ERROR "undeclared name" */ : 2}
+
+	var value int
+	_ = M1{true: 1, false: 0}
+	_ = M2{nil: 0, &value: 1}
+
+	// composite literal element types may be elided
+	type T [2]int
+	_ = map[int]T{0: T{3, 4}, 1: {5, 6}}
+
+	// recursively so
+	_ = map[int][]T{0: {}, 1: {{}, T{1, 2}}}
+
+	// composite literal key types may be elided
+	_ = map[T]int{T{3, 4}: 0, {5, 6}: 1}
+
+	// recursively so
+	_ = map[[2]T]int{{}: 0, {{}}: 1, [2]T{{}}: 2, {T{1, 2}}: 3}
+
+	// composite literal element and key types may be elided
+	_ = map[T]T{{}: {}, {1, 2}: T{3, 4}, T{4, 5}: {}}
+	_ = map[T]M0{{} : {}, T{1, 2}: M0{"foo": 0}, {1, 3}: {"foo": 1}}
+
+	// recursively so
+	_ = map[[2]T][]T{{}: {}, {{}}: {{}, T{1, 2}}, [2]T{{}}: nil, {T{1, 2}}: {{}, {}}}
+
+	// from the spec
+	type Point struct { x, y float32 }
+	_ = map[string]Point{"orig": {0, 0}}
+	_ = map[*Point]string{{0, 0}: "orig"}
+}
+
+var key2 string = "bar"
+
+type I interface {
+	m()
+}
+
+type I2 interface {
+	m(int)
+}
+
+type T1 struct{}
+type T2 struct{}
+
+func (T2) m(int) {}
+
+type mybool bool
+
+func type_asserts() {
+	var x int
+	_ = x /* ERROR "not an interface" */ .(int)
+
+	var e interface{}
+	var ok bool
+	x, ok = e.(int)
+	_ = ok
+
+	// ok value is of type bool
+	var myok mybool
+	_, myok = e.(int)
+	_ = myok
+
+	var t I
+	_ = t /* ERROR "use of .* outside type switch" */ .(type)
+	_ = t /* ERROR "missing method m" */ .(T)
+	_ = t.(*T)
+	_ = t /* ERROR "missing method m" */ .(T1)
+	_ = t /* ERROR "wrong type for method m" */ .(T2)
+	_ = t /* STRICT "wrong type for method m" */ .(I2) // only an error in strict mode (issue 8561)
+
+	// e doesn't statically have an m, but may have one dynamically.
+	_ = e.(I2)
+}
+
+func f0() {}
+func f1(x int) {}
+func f2(u float32, s string) {}
+func fs(s []byte) {}
+func fv(x ...int) {}
+func fi(x ... interface{}) {}
+func (T) fm(x ...int)
+
+func g0() {}
+func g1() int { return 0}
+func g2() (u float32, s string) { return }
+func gs() []byte { return nil }
+
+func _calls() {
+	var x int
+	var y float32
+	var s []int
+
+	f0()
+	_ = f0 /* ERROR "used as value" */ ()
+	f0(g0 /* ERROR "too many arguments" */ )
+
+	f1(0)
+	f1(x)
+	f1(10.0)
+	f1() /* ERROR "too few arguments" */
+	f1(x, y /* ERROR "too many arguments" */ )
+	f1(s /* ERROR "cannot pass" */ )
+	f1(x ... /* ERROR "cannot use ..." */ )
+	f1(g0 /* ERROR "used as value" */ ())
+	f1(g1())
+	// f1(g2()) // TODO(gri) missing position in error message
+
+	f2() /* ERROR "too few arguments" */
+	f2(3.14) /* ERROR "too few arguments" */
+	f2(3.14, "foo")
+	f2(x /* ERROR "cannot pass" */ , "foo")
+	f2(g0 /* ERROR "used as value" */ ())
+	f2(g1 /* ERROR "cannot pass" */ ()) /* ERROR "too few arguments" */
+	f2(g2())
+
+	fs() /* ERROR "too few arguments" */
+	fs(g0 /* ERROR "used as value" */ ())
+	fs(g1 /* ERROR "cannot pass" */ ())
+	fs(g2 /* ERROR "cannot pass" */ /* ERROR "too many arguments" */ ())
+	fs(gs())
+
+	fv()
+	fv(1, 2.0, x)
+	fv(s /* ERROR "cannot pass" */ )
+	fv(s...)
+	fv(x /* ERROR "cannot use" */ ...)
+	fv(1, s... /* ERROR "can only use ... with matching parameter" */ )
+	fv(gs /* ERROR "cannot pass" */ ())
+	fv(gs /* ERROR "cannot pass" */ ()...)
+
+	var t T
+	t.fm()
+	t.fm(1, 2.0, x)
+	t.fm(s /* ERROR "cannot pass" */ )
+	t.fm(g1())
+	t.fm(1, s... /* ERROR "can only use ... with matching parameter" */ )
+	t.fm(gs /* ERROR "cannot pass" */ ())
+	t.fm(gs /* ERROR "cannot pass" */ ()...)
+
+	T.fm(t, )
+	T.fm(t, 1, 2.0, x)
+	T.fm(t, s /* ERROR "cannot pass" */ )
+	T.fm(t, g1())
+	T.fm(t, 1, s... /* ERROR "can only use ... with matching parameter" */ )
+	T.fm(t, gs /* ERROR "cannot pass" */ ())
+	T.fm(t, gs /* ERROR "cannot pass" */ ()...)
+
+	var i interface{ fm(x ...int) } = t
+	i.fm()
+	i.fm(1, 2.0, x)
+	i.fm(s /* ERROR "cannot pass" */ )
+	i.fm(g1())
+	i.fm(1, s... /* ERROR "can only use ... with matching parameter" */ )
+	i.fm(gs /* ERROR "cannot pass" */ ())
+	i.fm(gs /* ERROR "cannot pass" */ ()...)
+
+	fi()
+	fi(1, 2.0, x, 3.14, "foo")
+	fi(g2())
+	fi(0, g2)
+	fi(0, g2 /* ERROR "2-valued expression" */ ())
+}
+
+func issue6344() {
+	type T []interface{}
+	var x T
+	fi(x...) // ... applies also to named slices
+}
diff --git a/src/go/types/testdata/gotos.src b/src/go/types/testdata/gotos.src
new file mode 100644
index 0000000..0c7ee44
--- /dev/null
+++ b/src/go/types/testdata/gotos.src
@@ -0,0 +1,560 @@
+// 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.
+
+// This file is a modified copy of $GOROOT/test/goto.go.
+
+package gotos
+
+var (
+	i, n int
+	x    []int
+	c    chan int
+	m    map[int]int
+	s    string
+)
+
+// goto after declaration okay
+func _() {
+	x := 1
+	goto L
+L:
+	_ = x
+}
+
+// goto before declaration okay
+func _() {
+	goto L
+L:
+	x := 1
+	_ = x
+}
+
+// goto across declaration not okay
+func _() {
+	goto L /* ERROR "goto L jumps over variable declaration at line 36" */
+	x := 1
+	_ = x
+L:
+}
+
+// goto across declaration in inner scope okay
+func _() {
+	goto L
+	{
+		x := 1
+		_ = x
+	}
+L:
+}
+
+// goto across declaration after inner scope not okay
+func _() {
+	goto L /* ERROR "goto L jumps over variable declaration at line 58" */
+	{
+		x := 1
+		_ = x
+	}
+	x := 1
+	_ = x
+L:
+}
+
+// goto across declaration in reverse okay
+func _() {
+L:
+	x := 1
+	_ = x
+	goto L
+}
+
+func _() {
+L: L1:
+	x := 1
+	_ = x
+	goto L
+	goto L1
+}
+
+// error shows first offending variable
+func _() {
+	goto L /* ERROR "goto L jumps over variable declaration at line 84" */
+	x := 1
+	_ = x
+	y := 1
+	_ = y
+L:
+}
+
+// goto not okay even if code path is dead
+func _() {
+	goto L /* ERROR "goto L jumps over variable declaration" */
+	x := 1
+	_ = x
+	y := 1
+	_ = y
+	return
+L:
+}
+
+// goto into outer block okay
+func _() {
+	{
+		goto L
+	}
+L:
+}
+
+func _() {
+	{
+		goto L
+		goto L1
+	}
+L: L1:
+}
+
+// goto backward into outer block okay
+func _() {
+L:
+	{
+		goto L
+	}
+}
+
+func _() {
+L: L1:
+	{
+		goto L
+		goto L1
+	}
+}
+
+// goto into inner block not okay
+func _() {
+	goto L /* ERROR "goto L jumps into block" */
+	{
+	L:
+	}
+}
+
+func _() {
+	goto L /* ERROR "goto L jumps into block" */
+	goto L1 /* ERROR "goto L1 jumps into block" */
+	{
+	L: L1:
+	}
+}
+
+// goto backward into inner block still not okay
+func _() {
+	{
+	L:
+	}
+	goto L /* ERROR "goto L jumps into block" */
+}
+
+func _() {
+	{
+	L: L1:
+	}
+	goto L /* ERROR "goto L jumps into block" */
+	goto L1 /* ERROR "goto L1 jumps into block" */
+}
+
+// error shows first (outermost) offending block
+func _() {
+	goto L /* ERROR "goto L jumps into block" */
+	{
+		{
+			{
+			L:
+			}
+		}
+	}
+}
+
+// error prefers block diagnostic over declaration diagnostic
+func _() {
+	goto L /* ERROR "goto L jumps into block" */
+	x := 1
+	_ = x
+	{
+	L:
+	}
+}
+
+// many kinds of blocks, all invalid to jump into or among,
+// but valid to jump out of
+
+// if
+
+func _() {
+L:
+	if true {
+		goto L
+	}
+}
+
+func _() {
+L:
+	if true {
+		goto L
+	} else {
+	}
+}
+
+func _() {
+L:
+	if false {
+	} else {
+		goto L
+	}
+}
+
+func _() {
+	goto L /* ERROR "goto L jumps into block" */
+	if true {
+	L:
+	}
+}
+
+func _() {
+	goto L /* ERROR "goto L jumps into block" */
+	if true {
+	L:
+	} else {
+	}
+}
+
+func _() {
+	goto L /* ERROR "goto L jumps into block" */
+	if true {
+	} else {
+	L:
+	}
+}
+
+func _() {
+	if false {
+	L:
+	} else {
+		goto L /* ERROR "goto L jumps into block" */
+	}
+}
+
+func _() {
+	if true {
+		goto L /* ERROR "goto L jumps into block" */
+	} else {
+	L:
+	}
+}
+
+func _() {
+	if true {
+		goto L /* ERROR "goto L jumps into block" */
+	} else if false {
+	L:
+	}
+}
+
+func _() {
+	if true {
+		goto L /* ERROR "goto L jumps into block" */
+	} else if false {
+	L:
+	} else {
+	}
+}
+
+func _() {
+	if true {
+		goto L /* ERROR "goto L jumps into block" */
+	} else if false {
+	} else {
+	L:
+	}
+}
+
+func _() {
+	if true {
+		goto L /* ERROR "goto L jumps into block" */
+	} else {
+		L:
+	}
+}
+
+func _() {
+	if true {
+		L:
+	} else {
+		goto L /* ERROR "goto L jumps into block" */
+	}
+}
+
+// for
+
+func _() {
+	for {
+		goto L
+	}
+L:
+}
+
+func _() {
+	for {
+		goto L
+	L:
+	}
+}
+
+func _() {
+	for {
+	L:
+	}
+	goto L /* ERROR "goto L jumps into block" */
+}
+
+func _() {
+	for {
+		goto L
+	L1:
+	}
+L:
+	goto L1 /* ERROR "goto L1 jumps into block" */
+}
+
+func _() {
+	for i < n {
+	L:
+	}
+	goto L /* ERROR "goto L jumps into block" */
+}
+
+func _() {
+	for i = 0; i < n; i++ {
+	L:
+	}
+	goto L /* ERROR "goto L jumps into block" */
+}
+
+func _() {
+	for i = range x {
+	L:
+	}
+	goto L /* ERROR "goto L jumps into block" */
+}
+
+func _() {
+	for i = range c {
+	L:
+	}
+	goto L /* ERROR "goto L jumps into block" */
+}
+
+func _() {
+	for i = range m {
+	L:
+	}
+	goto L /* ERROR "goto L jumps into block" */
+}
+
+func _() {
+	for i = range s {
+	L:
+	}
+	goto L /* ERROR "goto L jumps into block" */
+}
+
+// switch
+
+func _() {
+L:
+	switch i {
+	case 0:
+		goto L
+	}
+}
+
+func _() {
+L:
+	switch i {
+	case 0:
+
+	default:
+		goto L
+	}
+}
+
+func _() {
+	switch i {
+	case 0:
+
+	default:
+	L:
+		goto L
+	}
+}
+
+func _() {
+	switch i {
+	case 0:
+
+	default:
+		goto L
+	L:
+	}
+}
+
+func _() {
+	switch i {
+	case 0:
+		goto L
+	L:
+		;
+	default:
+	}
+}
+
+func _() {
+	goto L /* ERROR "goto L jumps into block" */
+	switch i {
+	case 0:
+	L:
+	}
+}
+
+func _() {
+	goto L /* ERROR "goto L jumps into block" */
+	switch i {
+	case 0:
+	L:
+		;
+	default:
+	}
+}
+
+func _() {
+	goto L /* ERROR "goto L jumps into block" */
+	switch i {
+	case 0:
+	default:
+	L:
+	}
+}
+
+func _() {
+	switch i {
+	default:
+		goto L /* ERROR "goto L jumps into block" */
+	case 0:
+	L:
+	}
+}
+
+func _() {
+	switch i {
+	case 0:
+	L:
+		;
+	default:
+		goto L /* ERROR "goto L jumps into block" */
+	}
+}
+
+// select
+// different from switch.  the statement has no implicit block around it.
+
+func _() {
+L:
+	select {
+	case <-c:
+		goto L
+	}
+}
+
+func _() {
+L:
+	select {
+	case c <- 1:
+
+	default:
+		goto L
+	}
+}
+
+func _() {
+	select {
+	case <-c:
+
+	default:
+	L:
+		goto L
+	}
+}
+
+func _() {
+	select {
+	case c <- 1:
+
+	default:
+		goto L
+	L:
+	}
+}
+
+func _() {
+	select {
+	case <-c:
+		goto L
+	L:
+		;
+	default:
+	}
+}
+
+func _() {
+	goto L /* ERROR "goto L jumps into block" */
+	select {
+	case c <- 1:
+	L:
+	}
+}
+
+func _() {
+	goto L /* ERROR "goto L jumps into block" */
+	select {
+	case c <- 1:
+	L:
+		;
+	default:
+	}
+}
+
+func _() {
+	goto L /* ERROR "goto L jumps into block" */
+	select {
+	case <-c:
+	default:
+	L:
+	}
+}
+
+func _() {
+	select {
+	default:
+		goto L /* ERROR "goto L jumps into block" */
+	case <-c:
+	L:
+	}
+}
+
+func _() {
+	select {
+	case <-c:
+	L:
+		;
+	default:
+		goto L /* ERROR "goto L jumps into block" */
+	}
+}
diff --git a/src/go/types/testdata/importdecl0a.src b/src/go/types/testdata/importdecl0a.src
new file mode 100644
index 0000000..463dcd0
--- /dev/null
+++ b/src/go/types/testdata/importdecl0a.src
@@ -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 importdecl0
+
+import ()
+
+import (
+	// we can have multiple blank imports (was bug)
+	_ "math"
+	_ "net/rpc"
+	init /* ERROR "cannot declare init" */ "fmt"
+	// reflect defines a type "flag" which shows up in the gc export data
+	"reflect"
+	. /* ERROR "imported but not used" */ "reflect"
+)
+
+import "math" /* ERROR "imported but not used" */
+import m /* ERROR "imported but not used as m" */ "math"
+import _ "math"
+
+import (
+	"math/big" /* ERROR "imported but not used" */
+	b /* ERROR "imported but not used" */ "math/big"
+	_ "math/big"
+)
+
+import "fmt"
+import f1 "fmt"
+import f2 "fmt"
+
+// reflect.flag must not be visible in this package
+type flag int
+type _ reflect /* ERROR "not exported" */ .flag
+
+// imported package name may conflict with local objects
+type reflect /* ERROR "reflect already declared" */ int
+
+// dot-imported exported objects may conflict with local objects
+type Value /* ERROR "Value already declared through dot-import of package reflect" */ struct{}
+
+var _ = fmt.Println // use "fmt"
+
+func _() {
+	f1.Println() // use "fmt"
+}
+
+func _() {
+	_ = func() {
+		f2.Println() // use "fmt"
+	}
+}
diff --git a/src/go/types/testdata/importdecl0b.src b/src/go/types/testdata/importdecl0b.src
new file mode 100644
index 0000000..6844e70
--- /dev/null
+++ b/src/go/types/testdata/importdecl0b.src
@@ -0,0 +1,33 @@
+// 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 importdecl0
+
+import "math"
+import m "math"
+
+import . "testing" // declares T in file scope
+import . /* ERROR "imported but not used" */ "unsafe"
+import . "fmt"     // declares Println in file scope
+
+import (
+	// TODO(gri) At the moment, 2 errors are reported because both go/parser
+	// and the type checker report it. Eventually, this test should not be
+	// done by the parser anymore.
+	"" /* ERROR invalid import path */ /* ERROR invalid import path */
+	"a!b" /* ERROR invalid import path */ /* ERROR invalid import path */
+	"abc\xffdef" /* ERROR invalid import path */ /* ERROR invalid import path */
+)
+
+// using "math" in this file doesn't affect its use in other files
+const Pi0 = math.Pi
+const Pi1 = m.Pi
+
+type _ T // use "testing"
+
+func _() func() interface{} {
+	return func() interface{} {
+		return Println // use "fmt"
+	}
+}
diff --git a/src/go/types/testdata/importdecl1a.src b/src/go/types/testdata/importdecl1a.src
new file mode 100644
index 0000000..8301820
--- /dev/null
+++ b/src/go/types/testdata/importdecl1a.src
@@ -0,0 +1,11 @@
+// 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.
+
+// Test case for issue 8969.
+
+package importdecl1
+
+import . "unsafe"
+
+var _ Pointer // use dot-imported package unsafe
diff --git a/src/go/types/testdata/importdecl1b.src b/src/go/types/testdata/importdecl1b.src
new file mode 100644
index 0000000..f24bb9a
--- /dev/null
+++ b/src/go/types/testdata/importdecl1b.src
@@ -0,0 +1,7 @@
+// 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 importdecl1
+
+import . /* ERROR "imported but not used" */ "unsafe"
diff --git a/src/go/types/testdata/init0.src b/src/go/types/testdata/init0.src
new file mode 100644
index 0000000..ef0349c
--- /dev/null
+++ b/src/go/types/testdata/init0.src
@@ -0,0 +1,106 @@
+// 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.
+
+// initialization cycles
+
+package init0
+
+// initialization cycles (we don't know the types)
+const (
+	s0 /* ERROR initialization cycle */ = s0
+
+	x0 /* ERROR initialization cycle */ = y0
+	y0 = x0
+
+	a0 = b0
+	b0 /* ERROR initialization cycle */ = c0
+	c0 = d0
+	d0 = b0
+)
+
+var (
+	s1 /* ERROR initialization cycle */ = s1
+
+	x1 /* ERROR initialization cycle */ = y1
+	y1 = x1
+
+	a1 = b1
+	b1 /* ERROR initialization cycle */ = c1
+	c1 = d1
+	d1 = b1
+)
+
+// initialization cycles (we know the types)
+const (
+	s2 /* ERROR initialization cycle */ int = s2
+
+	x2 /* ERROR initialization cycle */ int = y2
+	y2 = x2
+
+	a2 = b2
+	b2 /* ERROR initialization cycle */ int = c2
+	c2 = d2
+	d2 = b2
+)
+
+var (
+	s3 /* ERROR initialization cycle */ int = s3
+
+	x3 /* ERROR initialization cycle */ int = y3
+	y3 = x3
+
+	a3 = b3
+	b3 /* ERROR initialization cycle */ int = c3
+	c3 = d3
+	d3 = b3
+)
+
+// cycles via struct fields
+
+type S1 struct {
+	f int
+}
+const cx3 S1 /* ERROR invalid constant type */ = S1{cx3.f}
+var vx3 /* ERROR initialization cycle */ S1 = S1{vx3.f}
+
+// cycles via functions
+
+var x4 = x5
+var x5 /* ERROR initialization cycle */ = f1()
+func f1() int { return x5*10 }
+
+var x6, x7 /* ERROR initialization cycle */ = f2()
+var x8 = x7
+func f2() (int, int) { return f3() + f3(), 0 }
+func f3() int { return x8 }
+
+// cycles via closures
+
+var x9 /* ERROR initialization cycle */ = func() int { return x9 }()
+
+var x10 /* ERROR initialization cycle */ = f4()
+
+func f4() int {
+	_ = func() {
+		_ = x10
+	}
+	return 0
+}
+
+// cycles via method expressions
+
+type T1 struct{}
+
+func (T1) m() bool { _ = x11; return false }
+
+var x11 /* ERROR initialization cycle */ = T1.m(T1{})
+
+// cycles via method values
+
+type T2 struct{}
+
+func (T2) m() bool { _ = x12; return false }
+
+var t1 T2
+var x12 /* ERROR initialization cycle */ = t1.m
diff --git a/src/go/types/testdata/init1.src b/src/go/types/testdata/init1.src
new file mode 100644
index 0000000..39ca314
--- /dev/null
+++ b/src/go/types/testdata/init1.src
@@ -0,0 +1,97 @@
+// 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.
+
+// initialization cycles
+
+package init1
+
+// issue 6683 (marked as WorkingAsIntended)
+
+type T0 struct{}
+
+func (T0) m() int { return y0 }
+
+var x0 = T0{}
+
+var y0 /* ERROR initialization cycle */ = x0.m()
+
+type T1 struct{}
+
+func (T1) m() int { return y1 }
+
+var x1 interface {
+	m() int
+} = T1{}
+
+var y1 = x1.m() // no cycle reported, x1 is of interface type
+
+// issue 6703 (modified)
+
+var x2 /* ERROR initialization cycle */ = T2.m
+
+var y2 = x2
+
+type T2 struct{}
+
+func (T2) m() int {
+	_ = y2
+	return 0
+}
+
+var x3 /* ERROR initialization cycle */ = T3.m(T3{}) // <<<< added (T3{})
+
+var y3 = x3
+
+type T3 struct{}
+
+func (T3) m() int {
+	_ = y3
+	return 0
+}
+
+var x4 /* ERROR initialization cycle */ = T4{}.m // <<<< added {}
+
+var y4 = x4
+
+type T4 struct{}
+
+func (T4) m() int {
+	_ = y4
+	return 0
+}
+
+var x5 /* ERROR initialization cycle */ = T5{}.m() // <<<< added ()
+
+var y5 = x5
+
+type T5 struct{}
+
+func (T5) m() int {
+	_ = y5
+	return 0
+}
+
+// issue 4847
+// simplified test case
+
+var x6 = f6
+var y6 /* ERROR initialization cycle */ = f6
+func f6() { _ = y6 }
+
+// full test case
+
+type (
+      E int
+      S int
+)
+
+type matcher func(s *S) E
+
+func matchList(s *S) E { return matcher(matchAnyFn)(s) }
+
+var foo = matcher(matchList)
+
+var matchAny /* ERROR initialization cycle */ = matcher(matchList)
+
+func matchAnyFn(s *S) (err E) { return matchAny(s) }
\ No newline at end of file
diff --git a/src/go/types/testdata/init2.src b/src/go/types/testdata/init2.src
new file mode 100644
index 0000000..614db6c
--- /dev/null
+++ b/src/go/types/testdata/init2.src
@@ -0,0 +1,139 @@
+// 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.
+
+// initialization cycles
+
+package init2
+
+// cycles through functions
+
+func f1() int { _ = x1; return 0 }
+var x1 /* ERROR initialization cycle */ = f1
+
+func f2() int { _ = x2; return 0 }
+var x2 /* ERROR initialization cycle */ = f2()
+
+// cycles through method expressions
+
+type T3 int
+func (T3) m() int { _ = x3; return 0 }
+var x3 /* ERROR initialization cycle */ = T3.m
+
+type T4 int
+func (T4) m() int { _ = x4; return 0 }
+var x4 /* ERROR initialization cycle */ = T4.m(0)
+
+type T3p int
+func (*T3p) m() int { _ = x3p; return 0 }
+var x3p /* ERROR initialization cycle */ = (*T3p).m
+
+type T4p int
+func (*T4p) m() int { _ = x4p; return 0 }
+var x4p /* ERROR initialization cycle */ = (*T4p).m(nil)
+
+// cycles through method expressions of embedded methods
+
+type T5 struct { E5 }
+type E5 int
+func (E5) m() int { _ = x5; return 0 }
+var x5 /* ERROR initialization cycle */ = T5.m
+
+type T6 struct { E6 }
+type E6 int
+func (E6) m() int { _ = x6; return 0 }
+var x6 /* ERROR initialization cycle */ = T6.m(T6{0})
+
+type T5p struct { E5p }
+type E5p int
+func (*E5p) m() int { _ = x5p; return 0 }
+var x5p /* ERROR initialization cycle */ = (*T5p).m
+
+type T6p struct { E6p }
+type E6p int
+func (*E6p) m() int { _ = x6p; return 0 }
+var x6p /* ERROR initialization cycle */ = (*T6p).m(nil)
+
+// cycles through method values
+
+type T7 int
+func (T7) m() int { _ = x7; return 0 }
+var x7 /* ERROR initialization cycle */ = T7(0).m
+
+type T8 int
+func (T8) m() int { _ = x8; return 0 }
+var x8 /* ERROR initialization cycle */ = T8(0).m()
+
+type T7p int
+func (*T7p) m() int { _ = x7p; return 0 }
+var x7p /* ERROR initialization cycle */ = new(T7p).m
+
+type T8p int
+func (*T8p) m() int { _ = x8p; return 0 }
+var x8p /* ERROR initialization cycle */ = new(T8p).m()
+
+type T7v int
+func (T7v) m() int { _ = x7v; return 0 }
+var x7var T7v
+var x7v /* ERROR initialization cycle */ = x7var.m
+
+type T8v int
+func (T8v) m() int { _ = x8v; return 0 }
+var x8var T8v
+var x8v /* ERROR initialization cycle */ = x8var.m()
+
+type T7pv int
+func (*T7pv) m() int { _ = x7pv; return 0 }
+var x7pvar *T7pv
+var x7pv /* ERROR initialization cycle */ = x7pvar.m
+
+type T8pv int
+func (*T8pv) m() int { _ = x8pv; return 0 }
+var x8pvar *T8pv
+var x8pv /* ERROR initialization cycle */ = x8pvar.m()
+
+// cycles through method values of embedded methods
+
+type T9 struct { E9 }
+type E9 int
+func (E9) m() int { _ = x9; return 0 }
+var x9 /* ERROR initialization cycle */ = T9{0}.m
+
+type T10 struct { E10 }
+type E10 int
+func (E10) m() int { _ = x10; return 0 }
+var x10 /* ERROR initialization cycle */ = T10{0}.m()
+
+type T9p struct { E9p }
+type E9p int
+func (*E9p) m() int { _ = x9p; return 0 }
+var x9p /* ERROR initialization cycle */ = new(T9p).m
+
+type T10p struct { E10p }
+type E10p int
+func (*E10p) m() int { _ = x10p; return 0 }
+var x10p /* ERROR initialization cycle */ = new(T10p).m()
+
+type T9v struct { E9v }
+type E9v int
+func (E9v) m() int { _ = x9v; return 0 }
+var x9var T9v
+var x9v /* ERROR initialization cycle */ = x9var.m
+
+type T10v struct { E10v }
+type E10v int
+func (E10v) m() int { _ = x10v; return 0 }
+var x10var T10v
+var x10v /* ERROR initialization cycle */ = x10var.m()
+
+type T9pv struct { E9pv }
+type E9pv int
+func (*E9pv) m() int { _ = x9pv; return 0 }
+var x9pvar *T9pv
+var x9pv /* ERROR initialization cycle */ = x9pvar.m
+
+type T10pv struct { E10pv }
+type E10pv int
+func (*E10pv) m() int { _ = x10pv; return 0 }
+var x10pvar *T10pv
+var x10pv /* ERROR initialization cycle */ = x10pvar.m()
diff --git a/src/go/types/testdata/issues.src b/src/go/types/testdata/issues.src
new file mode 100644
index 0000000..595a634
--- /dev/null
+++ b/src/go/types/testdata/issues.src
@@ -0,0 +1,97 @@
+// 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 issues
+
+import "fmt"
+
+func issue7035() {
+	type T struct{ X int }
+	_ = func() {
+		fmt.Println() // must refer to imported fmt rather than the fmt below
+	}
+	fmt := new(T)
+	_ = fmt.X
+}
+
+func issue8066() {
+	const (
+		// TODO(gri) Enable test below for releases 1.4 and higher
+		// _ = float32(340282356779733661637539395458142568447)
+		_ = float32(340282356779733661637539395458142568448 /* ERROR cannot convert */ )
+	)
+}
+
+// Check that a missing identifier doesn't lead to a spurious error cascade.
+func issue8799a() {
+	x, ok := missing /* ERROR undeclared */ ()
+	_ = !ok
+	_ = x
+}
+
+func issue8799b(x int, ok bool) {
+	x, ok = missing /* ERROR undeclared */ ()
+	_ = !ok
+	_ = x
+}
+
+func issue9182() {
+	type Point C /* ERROR undeclared */ .Point
+	// no error for composite literal based on unknown type
+	_ = Point{x: 1, y: 2}
+}
+
+func f0() (a []int)         { return }
+func f1() (a []int, b int)  { return }
+func f2() (a, b []int)      { return }
+
+func append_([]int, ...int) {}
+
+func issue9473(a []int, b ...int) {
+	// variadic builtin function
+	_ = append(f0())
+	_ = append(f0(), f0()...)
+	_ = append(f1())
+	_ = append(f2 /* ERROR cannot pass argument */ ())
+	_ = append(f2()... /* ERROR cannot use ... */ )
+	_ = append(f0(), f1 /* ERROR 2-valued expression */ ())
+	_ = append(f0(), f2 /* ERROR 2-valued expression */ ())
+	_ = append(f0(), f1()... /* ERROR cannot use ... */ )
+	_ = append(f0(), f2()... /* ERROR cannot use ... */ )
+
+	// variadic user-defined function
+	append_(f0())
+	append_(f0(), f0()...)
+	append_(f1())
+	append_(f2 /* ERROR cannot pass argument */ ())
+	append_(f2()... /* ERROR cannot use ... */ )
+	append_(f0(), f1 /* ERROR 2-valued expression */ ())
+	append_(f0(), f2 /* ERROR 2-valued expression */ ())
+	append_(f0(), f1()... /* ERROR cannot use */ )
+	append_(f0(), f2()... /* ERROR cannot use */ )
+}
+
+// Check that embedding a non-interface type in an interface results in a good error message.
+func issue10979() {
+	type _ interface {
+		int /* ERROR int is not an interface */
+	}
+	type T struct{}
+	type _ interface {
+		T /* ERROR T is not an interface */
+	}
+	type _ interface {
+		nosuchtype /* ERROR undeclared name: nosuchtype */
+	}
+	type _ interface {
+		fmt /* ERROR Nosuchtype not declared by package fmt */ .Nosuchtype
+	}
+	type _ interface {
+		nosuchpkg /* ERROR undeclared name: nosuchpkg */ .Nosuchtype
+	}
+	type I interface {
+		I /* ERROR I\.m \(value of type func\(I\)\) is not a type */ .m
+		m()
+	}
+}
diff --git a/src/go/types/testdata/labels.src b/src/go/types/testdata/labels.src
new file mode 100644
index 0000000..102ffc7
--- /dev/null
+++ b/src/go/types/testdata/labels.src
@@ -0,0 +1,207 @@
+// 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.
+
+// This file is a modified concatenation of the files
+// $GOROOT/test/label.go and $GOROOT/test/label1.go.
+
+package labels
+
+var x int
+
+func f0() {
+L1 /* ERROR "label L1 declared but not used" */ :
+	for {
+	}
+L2 /* ERROR "label L2 declared but not used" */ :
+	select {
+	}
+L3 /* ERROR "label L3 declared but not used" */ :
+	switch {
+	}
+L4 /* ERROR "label L4 declared but not used" */ :
+	if true {
+	}
+L5 /* ERROR "label L5 declared but not used" */ :
+	f0()
+L6:
+	f0()
+L6 /* ERROR "label L6 already declared" */ :
+	f0()
+	if x == 20 {
+		goto L6
+	}
+
+L7:
+	for {
+		break L7
+		break L8 /* ERROR "invalid break label L8" */
+	}
+
+// A label must be directly associated with a switch, select, or
+// for statement; it cannot be the label of a labeled statement.
+
+L7a /* ERROR "declared but not used" */ : L7b:
+	for {
+		break L7a /* ERROR "invalid break label L7a" */
+		continue L7a /* ERROR "invalid continue label L7a" */
+		continue L7b
+	}
+
+L8:
+	for {
+		if x == 21 {
+			continue L8
+			continue L7 /* ERROR "invalid continue label L7" */
+		}
+	}
+
+L9:
+	switch {
+	case true:
+		break L9
+	defalt /* ERROR "label defalt declared but not used" */ :
+	}
+
+L10:
+	select {
+	default:
+		break L10
+		break L9 /* ERROR "invalid break label L9" */
+	}
+
+	goto L10a
+L10a: L10b:
+	select {
+	default:
+		break L10a /* ERROR "invalid break label L10a" */
+		break L10b
+		continue L10b /* ERROR "invalid continue label L10b" */
+	}
+}
+
+func f1() {
+L1:
+	for {
+		if x == 0 {
+			break L1
+		}
+		if x == 1 {
+			continue L1
+		}
+		goto L1
+	}
+
+L2:
+	select {
+	default:
+		if x == 0 {
+			break L2
+		}
+		if x == 1 {
+			continue L2 /* ERROR "invalid continue label L2" */
+		}
+		goto L2
+	}
+
+L3:
+	switch {
+	case x > 10:
+		if x == 11 {
+			break L3
+		}
+		if x == 12 {
+			continue L3 /* ERROR "invalid continue label L3" */
+		}
+		goto L3
+	}
+
+L4:
+	if true {
+		if x == 13 {
+			break L4 /* ERROR "invalid break label L4" */
+		}
+		if x == 14 {
+			continue L4 /* ERROR "invalid continue label L4" */
+		}
+		if x == 15 {
+			goto L4
+		}
+	}
+
+L5:
+	f1()
+	if x == 16 {
+		break L5 /* ERROR "invalid break label L5" */
+	}
+	if x == 17 {
+		continue L5 /* ERROR "invalid continue label L5" */
+	}
+	if x == 18 {
+		goto L5
+	}
+
+	for {
+		if x == 19 {
+			break L1 /* ERROR "invalid break label L1" */
+		}
+		if x == 20 {
+			continue L1 /* ERROR "invalid continue label L1" */
+		}
+		if x == 21 {
+			goto L1
+		}
+	}
+}
+
+// Additional tests not in the original files.
+
+func f2() {
+L1 /* ERROR "label L1 declared but not used" */ :
+	if x == 0 {
+		for {
+			continue L1 /* ERROR "invalid continue label L1" */
+		}
+	}
+}
+
+func f3() {
+L1:
+L2:
+L3:
+	for {
+		break L1 /* ERROR "invalid break label L1" */
+		break L2 /* ERROR "invalid break label L2" */
+		break L3
+		continue L1 /* ERROR "invalid continue label L1" */
+		continue L2 /* ERROR "invalid continue label L2" */
+		continue L3
+		goto L1
+		goto L2
+		goto L3
+	}
+}
+
+// Blank labels are never declared.
+
+func f4() {
+_:
+_: // multiple blank labels are ok
+	goto _ /* ERROR "label _ not declared" */
+}
+
+func f5() {
+_:
+	for {
+		break _ /* ERROR "invalid break label _" */
+		continue _ /* ERROR "invalid continue label _" */
+	}
+}
+
+func f6() {
+_:
+	switch {
+	default:
+		break _ /* ERROR "invalid break label _" */
+	}
+}
diff --git a/src/go/types/testdata/methodsets.src b/src/go/types/testdata/methodsets.src
new file mode 100644
index 0000000..8921146
--- /dev/null
+++ b/src/go/types/testdata/methodsets.src
@@ -0,0 +1,214 @@
+// 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 methodsets
+
+type T0 struct {}
+
+func (T0) v0() {}
+func (*T0) p0() {}
+
+type T1 struct {} // like T0 with different method names
+
+func (T1) v1() {}
+func (*T1) p1() {}
+
+type T2 interface {
+	v2()
+	p2()
+}
+
+type T3 struct {
+	T0
+	*T1
+	T2
+}
+
+// Method expressions
+func _() {
+	var (
+		_ func(T0) = T0.v0
+		_ = T0 /* ERROR "not in method set" */ .p0
+
+		_ func (*T0) = (*T0).v0
+		_ func (*T0) = (*T0).p0
+
+		// T1 is like T0
+
+		_ func(T2) = T2.v2
+		_ func(T2) = T2.p2
+
+		_ func(T3) = T3.v0
+		_ func(T3) = T3 /* ERROR "not in method set" */ .p0
+		_ func(T3) = T3.v1
+		_ func(T3) = T3.p1
+		_ func(T3) = T3.v2
+		_ func(T3) = T3.p2
+
+		_ func(*T3) = (*T3).v0
+		_ func(*T3) = (*T3).p0
+		_ func(*T3) = (*T3).v1
+		_ func(*T3) = (*T3).p1
+		_ func(*T3) = (*T3).v2
+		_ func(*T3) = (*T3).p2
+	)
+}
+
+// Method values with addressable receivers
+func _() {
+	var (
+		v0 T0
+		_ func() = v0.v0
+		_ func() = v0.p0
+	)
+
+	var (
+		p0 *T0
+		_ func() = p0.v0
+		_ func() = p0.p0
+	)
+
+	// T1 is like T0
+
+	var (
+		v2 T2
+		_ func() = v2.v2
+		_ func() = v2.p2
+	)
+
+	var (
+		v4 T3
+		_ func() = v4.v0
+		_ func() = v4.p0
+		_ func() = v4.v1
+		_ func() = v4.p1
+		_ func() = v4.v2
+		_ func() = v4.p2
+	)
+
+	var (
+		p4 *T3
+		_ func() = p4.v0
+		_ func() = p4.p0
+		_ func() = p4.v1
+		_ func() = p4.p1
+		_ func() = p4.v2
+		_ func() = p4.p2
+	)
+}
+
+// Method calls with addressable receivers
+func _() {
+	var v0 T0
+	v0.v0()
+	v0.p0()
+
+	var p0 *T0
+	p0.v0()
+	p0.p0()
+
+	// T1 is like T0
+
+	var v2 T2
+	v2.v2()
+	v2.p2()
+
+	var v4 T3
+	v4.v0()
+	v4.p0()
+	v4.v1()
+	v4.p1()
+	v4.v2()
+	v4.p2()
+
+	var p4 *T3
+	p4.v0()
+	p4.p0()
+	p4.v1()
+	p4.p1()
+	p4.v2()
+	p4.p2()
+}
+
+// Method values with value receivers
+func _() {
+	var (
+		_ func() = T0{}.v0
+		_ func() = T0 /* ERROR "not in method set" */ {}.p0
+
+		_ func() = (&T0{}).v0
+		_ func() = (&T0{}).p0
+
+		// T1 is like T0
+
+		// no values for T2
+
+		_ func() = T3{}.v0
+		_ func() = T3 /* ERROR "not in method set" */ {}.p0
+		_ func() = T3{}.v1
+		_ func() = T3{}.p1
+		_ func() = T3{}.v2
+		_ func() = T3{}.p2
+
+		_ func() = (&T3{}).v0
+		_ func() = (&T3{}).p0
+		_ func() = (&T3{}).v1
+		_ func() = (&T3{}).p1
+		_ func() = (&T3{}).v2
+		_ func() = (&T3{}).p2
+	)
+}
+
+// Method calls with value receivers
+func _() {
+	T0{}.v0()
+	T0 /* ERROR "not in method set" */ {}.p0()
+
+	(&T0{}).v0()
+	(&T0{}).p0()
+
+	// T1 is like T0
+
+	// no values for T2
+
+	T3{}.v0()
+	T3 /* ERROR "not in method set" */ {}.p0()
+	T3{}.v1()
+	T3{}.p1()
+	T3{}.v2()
+	T3{}.p2()
+
+	(&T3{}).v0()
+	(&T3{}).p0()
+	(&T3{}).v1()
+	(&T3{}).p1()
+	(&T3{}).v2()
+	(&T3{}).p2()
+}
+
+// *T has no methods if T is an interface type
+func issue5918() {
+	var (
+		err error
+		_ = err.Error()
+		_ func() string = err.Error
+		_ func(error) string = error.Error
+
+		perr = &err
+		_ = perr /* ERROR "no field or method" */ .Error()
+		_ func() string = perr /* ERROR "no field or method" */ .Error
+		_ func(*error) string = ( /* ERROR "no field or method" */ *error).Error
+	)
+
+	type T *interface{ m() int }
+	var (
+		x T
+		_ = (*x).m()
+		_ = (*x).m
+
+		_ = x /* ERROR "no field or method" */ .m()
+		_ = x /* ERROR "no field or method" */ .m
+		_ = T /* ERROR "no field or method" */ .m
+	)
+}
diff --git a/src/go/types/testdata/shifts.src b/src/go/types/testdata/shifts.src
new file mode 100644
index 0000000..64865fc
--- /dev/null
+++ b/src/go/types/testdata/shifts.src
@@ -0,0 +1,341 @@
+// 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 shifts
+
+func shifts0() {
+	// basic constant shifts
+	const (
+		s = 10
+		_ = 0<<0
+		_ = 1<<s
+		_ = 1<<- /* ERROR "stupid shift" */ 1
+		_ = 1<<1075 /* ERROR "stupid shift" */
+		_ = 2.0<<1
+
+		_ int = 2<<s
+		_ float32 = 2<<s
+		_ complex64 = 2<<s
+
+		_ int = 2.0<<s
+		_ float32 = 2.0<<s
+		_ complex64 = 2.0<<s
+
+		_ int = 'a'<<s
+		_ float32 = 'a'<<s
+		_ complex64 = 'a'<<s
+	)
+}
+
+func shifts1() {
+	// basic non-constant shifts
+	var (
+		i int
+		u uint
+
+		_ = 1<<0
+		_ = 1<<i /* ERROR "must be unsigned" */
+		_ = 1<<u
+		_ = 1<<"foo" /* ERROR "cannot convert" */
+		_ = i<<0
+		_ = i<<- /* ERROR "must not be negative" */ 1
+		_ = 1 /* ERROR "overflows" */ <<100
+
+		_ uint = 1 << 0
+		_ uint = 1 << u
+		_ float32 = 1 /* ERROR "must be integer" */ << u
+	)
+}
+
+func shifts2() {
+	// from the spec
+	var (
+		s uint = 33
+		i = 1<<s           // 1 has type int
+		j int32 = 1<<s     // 1 has type int32; j == 0
+		k = uint64(1<<s)   // 1 has type uint64; k == 1<<33
+		m int = 1.0<<s     // 1.0 has type int
+		n = 1.0<<s != i    // 1.0 has type int; n == false if ints are 32bits in size
+		o = 1<<s == 2<<s   // 1 and 2 have type int; o == true if ints are 32bits in size
+		p = 1<<s == 1<<33  // illegal if ints are 32bits in size: 1 has type int, but 1<<33 overflows int
+		u = 1.0 /* ERROR "must be integer" */ <<s         // illegal: 1.0 has type float64, cannot shift
+		u1 = 1.0 /* ERROR "must be integer" */ <<s != 0   // illegal: 1.0 has type float64, cannot shift
+		u2 = 1 /* ERROR "must be integer" */ <<s != 1.0   // illegal: 1 has type float64, cannot shift
+		v float32 = 1 /* ERROR "must be integer" */ <<s   // illegal: 1 has type float32, cannot shift
+		w int64 = 1.0<<33  // 1.0<<33 is a constant shift expression
+	)
+	_, _, _, _, _, _, _, _, _, _, _, _ = i, j, k, m, n, o, p, u, u1, u2, v, w
+}
+
+func shifts3(a int16, b float32) {
+	// random tests
+	var (
+		s uint = 11
+		u = 1 /* ERROR "must be integer" */ <<s + 1.0
+		v complex128 = 1 /* ERROR "must be integer" */ << s + 1.0 /* ERROR "must be integer" */ << s + 1
+	)
+	x := 1.0 /* ERROR "must be integer" */ <<s + 1
+	shifts3(1.0 << s, 1 /* ERROR "must be integer" */ >> s)
+	_, _, _ = u, v, x
+}
+
+func shifts4() {
+	// shifts in comparisons w/ untyped operands
+	var s uint
+
+	_ = 1<<s == 1
+	_ = 1 /* ERROR "integer" */ <<s == 1.
+	_ = 1. /* ERROR "integer" */ <<s == 1
+	_ = 1. /* ERROR "integer" */ <<s == 1.
+
+	_ = 1<<s + 1 == 1
+	_ = 1 /* ERROR "integer" */ <<s + 1 == 1.
+	_ = 1 /* ERROR "integer" */ <<s + 1. == 1
+	_ = 1 /* ERROR "integer" */ <<s + 1. == 1.
+	_ = 1. /* ERROR "integer" */ <<s + 1 == 1
+	_ = 1. /* ERROR "integer" */ <<s + 1 == 1.
+	_ = 1. /* ERROR "integer" */ <<s + 1. == 1
+	_ = 1. /* ERROR "integer" */ <<s + 1. == 1.
+
+	_ = 1<<s == 1<<s
+	_ = 1 /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s
+	_ = 1. /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s
+	_ = 1. /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s
+
+	_ = 1<<s + 1<<s == 1
+	_ = 1 /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1.
+	_ = 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1
+	_ = 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1.
+	_ = 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1
+	_ = 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1.
+	_ = 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1
+	_ = 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1.
+
+	_ = 1<<s + 1<<s == 1<<s + 1<<s
+	_ = 1 /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
+	_ = 1 /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s
+	_ = 1 /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
+	_ = 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s
+	_ = 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
+	_ = 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s
+	_ = 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
+	_ = 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s
+	_ = 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
+	_ = 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s
+	_ = 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
+	_ = 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s
+	_ = 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1 /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
+	_ = 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1 /* ERROR "integer" */ <<s
+	_ = 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s == 1. /* ERROR "integer" */ <<s + 1. /* ERROR "integer" */ <<s
+}
+
+func shifts5() {
+	// shifts in comparisons w/ typed operands
+	var s uint
+	var x int
+
+	_ = 1<<s == x
+	_ = 1.<<s == x
+	_ = 1.1 /* ERROR "int" */ <<s == x
+
+	_ = 1<<s + x == 1
+	_ = 1<<s + x == 1.
+	_ = 1<<s + x == 1.1 /* ERROR "int" */
+	_ = 1.<<s + x == 1
+	_ = 1.<<s + x == 1.
+	_ = 1.<<s + x == 1.1 /* ERROR "int" */
+	_ = 1.1 /* ERROR "int" */ <<s + x == 1
+	_ = 1.1 /* ERROR "int" */ <<s + x == 1.
+	_ = 1.1 /* ERROR "int" */ <<s + x == 1.1
+
+	_ = 1<<s == x<<s
+	_ = 1.<<s == x<<s
+	_ = 1.1  /* ERROR "int" */ <<s == x<<s
+}
+
+func shifts6() {
+	// shifts as operands in non-arithmetic operations and as arguments
+	var a [10]int
+	var s uint
+
+	_ = a[1<<s]
+	_ = a[1.0]
+	_ = a[1.0<<s]
+
+	_ = make([]int, 1.0)
+	_ = make([]int, 1.0<<s)
+	_ = make([]int, 1.1 /* ERROR "must be integer" */ <<s)
+
+	_ = float32(1)
+	_ = float32(1 /* ERROR "must be integer" */ <<s)
+	_ = float32(1.0)
+	_ = float32(1.0 /* ERROR "must be integer" */ <<s)
+	_ = float32(1.1 /* ERROR "must be integer" */ <<s)
+
+	var b []int
+	_ = append(b, 1<<s)
+	_ = append(b, 1.0<<s)
+	_ = append(b, 1.1 /* ERROR "must be integer" */ <<s)
+
+	_ = append(b, 1<<s)
+	_ = append(b, 1.0<<s) // should fail - see TODO in append code
+	_ = append(b, 1.1 /* ERROR "must be integer" */ <<s)
+
+	_ = complex(1.0 /* ERROR "must be integer" */ <<s, 0)
+	_ = complex(1.1 /* ERROR "must be integer" */ <<s, 0)
+	_ = complex(0, 1.0 /* ERROR "must be integer" */ <<s)
+	_ = complex(0, 1.1 /* ERROR "must be integer" */ <<s)
+
+	// TODO(gri) The delete below is not type-checked correctly yet.
+	// var m1 map[int]string
+	// delete(m1, 1<<s)
+}
+
+func shifts7() {
+	// shifts of shifts
+	var s uint
+	var x int
+	_ = x
+
+	_ = 1<<(1<<s)
+	_ = 1<<(1.<<s)
+	_ = 1. /* ERROR "integer" */ <<(1<<s)
+	_ = 1. /* ERROR "integer" */ <<(1.<<s)
+
+	x = 1<<(1<<s)
+	x = 1<<(1.<<s)
+	x = 1.<<(1<<s)
+	x = 1.<<(1.<<s)
+
+	_ = (1<<s)<<(1<<s)
+	_ = (1<<s)<<(1.<<s)
+	_ = ( /* ERROR "integer" */ 1.<<s)<<(1<<s)
+	_ = ( /* ERROR "integer" */ 1.<<s)<<(1.<<s)
+
+	x = (1<<s)<<(1<<s)
+	x = (1<<s)<<(1.<<s)
+	x = ( /* ERROR "integer" */ 1.<<s)<<(1<<s)
+	x = ( /* ERROR "integer" */ 1.<<s)<<(1.<<s)
+}
+
+func shifts8() {
+	// shift examples from shift discussion: better error messages
+	var s uint
+	_ = 1.0 /* ERROR "shifted operand 1.0 \(type float64\) must be integer" */ <<s == 1
+	_ = 1.0 /* ERROR "shifted operand 1.0 \(type float64\) must be integer" */ <<s == 1.0
+	_ = 1 /* ERROR "shifted operand 1 \(type float64\) must be integer" */ <<s == 1.0
+	_ = 1 /* ERROR "shifted operand 1 \(type float64\) must be integer" */ <<s + 1.0 == 1
+	_ = 1 /* ERROR "shifted operand 1 \(type float64\) must be integer" */ <<s + 1.1 == 1
+	_ = 1 /* ERROR "shifted operand 1 \(type float64\) must be integer" */ <<s + 1 == 1.0
+
+	// additional cases
+	_ = complex(1.0 /* ERROR "shifted operand 1.0 \(type float64\) must be integer" */ <<s, 1)
+	_ = complex(1.0, 1 /* ERROR "shifted operand 1 \(type float64\) must be integer" */ <<s)
+
+	_ = int(1.<<s)
+	_ = int(1.1 /* ERROR "shifted operand .* must be integer" */ <<s)
+	_ = float32(1 /* ERROR "shifted operand .* must be integer" */ <<s)
+	_ = float32(1. /* ERROR "shifted operand .* must be integer" */ <<s)
+	_ = float32(1.1 /* ERROR "shifted operand .* must be integer" */ <<s)
+	// TODO(gri) the error messages for these two are incorrect - disabled for now
+	// _ = complex64(1<<s)
+	// _ = complex64(1.<<s)
+	_ = complex64(1.1 /* ERROR "shifted operand .* must be integer" */ <<s)
+}
+
+func shifts9() {
+	// various originally failing snippets of code from the std library
+	// from src/compress/lzw/reader.go:90
+	{
+		var d struct {
+			bits     uint32
+			width    uint
+		}
+		_ = uint16(d.bits & (1<<d.width - 1))
+	}
+
+	// from src/debug/dwarf/buf.go:116
+	{
+		var ux uint64
+		var bits uint
+		x := int64(ux)
+		if x&(1<<(bits-1)) != 0 {}
+	}
+
+	// from src/encoding/asn1/asn1.go:160
+	{
+		var bytes []byte
+		if bytes[len(bytes)-1]&((1<<bytes[0])-1) != 0 {}
+	}
+
+	// from src/math/big/rat.go:140
+	{
+		var exp int
+		var mantissa uint64
+		shift := uint64(-1022 - (exp - 1)) // [1..53)
+		_ = mantissa & (1<<shift - 1)
+	}
+
+	// from src/net/interface.go:51
+	{
+		type Flags uint
+		var f Flags
+		var i int
+		if f&(1<<uint(i)) != 0 {}
+	}
+
+	// from src/runtime/softfloat64.go:234
+	{
+		var gm uint64
+		var shift uint
+		_ = gm & (1<<shift - 1)
+	}
+
+	// from src/strconv/atof.go:326
+	{
+		var mant uint64
+		var mantbits uint
+		if mant == 2<<mantbits {}
+	}
+
+	// from src/route_bsd.go:82
+	{
+		var Addrs int32
+		const rtaRtMask = 1
+		var i uint
+		if Addrs&rtaRtMask&(1<<i) == 0 {}
+	}
+
+	// from src/text/scanner/scanner.go:540
+	{
+		var s struct { Whitespace uint64 }
+		var ch rune
+		for s.Whitespace&(1<<uint(ch)) != 0 {}
+	}
+}
+
+func issue5895() {
+	var x = 'a' << 1 // type of x must be rune
+	var _ rune = x
+}
+
+func issue11325() {
+	var _ = 0 >> 1.1 /* ERROR "must be unsigned integer" */ // example from issue 11325
+	_ = 0 >> 1.1 /* ERROR "must be unsigned integer" */
+	_ = 0 << 1.1 /* ERROR "must be unsigned integer" */
+	_ = 0 >> 1.
+	_ = 1 >> 1.1 /* ERROR "must be unsigned integer" */
+	_ = 1 >> 1.
+	_ = 1. >> 1
+	_ = 1. >> 1.
+	_ = 1.1 /* ERROR "must be integer" */ >> 1
+}
+
+func issue11594() {
+	var _ = complex64 /* ERROR "must be integer" */ (1) << 2 // example from issue 11594
+	_ = float32 /* ERROR "must be integer" */ (0) << 1
+	_ = float64 /* ERROR "must be integer" */ (0) >> 2
+	_ = complex64 /* ERROR "must be integer" */ (0) << 3
+	_ = complex64 /* ERROR "must be integer" */ (0) >> 4
+}
\ No newline at end of file
diff --git a/src/go/types/testdata/stmt0.src b/src/go/types/testdata/stmt0.src
new file mode 100644
index 0000000..fd1ddba
--- /dev/null
+++ b/src/go/types/testdata/stmt0.src
@@ -0,0 +1,833 @@
+// 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.
+
+// statements
+
+package stmt0
+
+func assignments0() (int, int) {
+	var a, b, c int
+	var ch chan int
+	f0 := func() {}
+	f1 := func() int { return 1 }
+	f2 := func() (int, int) { return 1, 2 }
+	f3 := func() (int, int, int) { return 1, 2, 3 }
+
+	a, b, c = 1, 2, 3
+	a, b, c = 1 /* ERROR "assignment count mismatch" */ , 2
+	a, b, c = 1 /* ERROR "assignment count mismatch" */ , 2, 3, 4
+	_, _, _ = a, b, c
+
+	a = f0 /* ERROR "used as value" */ ()
+	a = f1()
+	a = f2 /* ERROR "assignment count mismatch" */ ()
+	a, b = f2()
+	a, b, c = f2 /* ERROR "assignment count mismatch" */ ()
+	a, b, c = f3()
+	a, b = f3 /* ERROR "assignment count mismatch" */ ()
+
+	a, b, c = <- /* ERROR "assignment count mismatch" */ ch
+
+	return /* ERROR "wrong number of return values" */
+	return /* ERROR "wrong number of return values" */ 1
+	return 1, 2
+	return /* ERROR "wrong number of return values" */ 1, 2, 3
+}
+
+func assignments1() {
+	b, i, f, c, s := false, 1, 1.0, 1i, "foo"
+	b = i /* ERROR "cannot assign" */
+	i = f /* ERROR "cannot assign" */
+	f = c /* ERROR "cannot assign" */
+	c = s /* ERROR "cannot assign" */
+	s = b /* ERROR "cannot assign" */
+
+	v0, v1, v2 := 1 /* ERROR "mismatch" */ , 2, 3, 4
+	_, _, _ = v0, v1, v2
+
+	b = true
+
+	i += 1
+	i += "foo" /* ERROR "cannot convert.*int" */
+
+	f -= 1
+	f /= 0
+	f = float32(0)/0 /* ERROR "division by zero" */
+	f -= "foo" /* ERROR "cannot convert.*float64" */
+
+	c *= 1
+	c /= 0
+
+	s += "bar"
+	s += 1 /* ERROR "cannot convert.*string" */
+
+	var u64 uint64
+	u64 += 1<<u64
+
+	undeclared /* ERROR "undeclared" */ = 991
+
+	// test cases for issue 5800
+	var (
+		_ int = nil /* ERROR "untyped nil value" */
+		_ [10]int = nil /* ERROR "untyped nil value" */
+		_ []byte = nil
+		_ struct{} = nil /* ERROR "untyped nil value" */
+		_ func() = nil
+		_ map[int]string = nil
+		_ chan int = nil
+	)
+
+	// test cases for issue 5500
+	_ = func() (int, bool) {
+		var m map[int]int
+		return /* ERROR "wrong number of return values" */ m[0]
+	}
+
+	g := func(int, bool){}
+	var m map[int]int
+	g(m[0]) /* ERROR "too few arguments" */
+
+	// assignments to _
+	_ = nil /* ERROR "use of untyped nil" */
+	_ = 1 /* ERROR overflow */ <<1000
+	(_) = 0
+}
+
+func assignments2() {
+	type mybool bool
+	var m map[string][]bool
+	var s []bool
+	var b bool
+	var d mybool
+	_ = s
+	_ = b
+	_ = d
+
+	// assignments to map index expressions are ok
+	s, b = m["foo"]
+	_, d = m["bar"]
+	m["foo"] = nil
+	m["foo"] = nil /* ERROR assignment count mismatch */ , false
+	_ = append(m["foo"])
+	_ = append(m["foo"], true)
+
+	var c chan int
+	_, b = <-c
+	_, d = <-c
+	<- /* ERROR cannot assign */ c = 0
+	<-c = 0 /* ERROR assignment count mismatch */ , false
+
+	var x interface{}
+	_, b = x.(int)
+	x /* ERROR cannot assign */ .(int) = 0
+	x.(int) = 0 /* ERROR assignment count mismatch */ , false
+
+	assignments2 /* ERROR used as value */ () = nil
+	int /* ERROR not an expression */ = 0
+}
+
+func issue6487() {
+	type S struct{x int}
+	_ = &S /* ERROR "cannot take address" */ {}.x
+	_ = &( /* ERROR "cannot take address" */ S{}.x)
+	_ = (&S{}).x
+	S /* ERROR "cannot assign" */ {}.x = 0
+	(&S{}).x = 0
+
+	type M map[string]S
+	var m M
+	m /* ERROR "cannot assign" */ ["foo"].x = 0
+	_ = &( /* ERROR "cannot take address" */ m["foo"].x)
+	_ = &m /* ERROR "cannot take address" */ ["foo"].x
+}
+
+func issue6766a() {
+	a, a /* ERROR redeclared */ := 1, 2
+	_ = a
+	a, b, b /* ERROR redeclared */ := 1, 2, 3
+	_ = b
+	c, c /* ERROR redeclared */, b := 1, 2, 3
+	_ = c
+	a, b := /* ERROR no new variables */ 1, 2
+}
+
+func shortVarDecls1() {
+	const c = 0
+	type d int
+	a, b, c /* ERROR "cannot assign" */ , d /* ERROR "cannot assign" */  := 1, "zwei", 3.0, 4
+	var _ int = a // a is of type int
+	var _ string = b // b is of type string
+}
+
+func incdecs() {
+	const c = 3.14
+	c /* ERROR "cannot assign" */ ++
+	s := "foo"
+	s /* ERROR "cannot convert" */ --
+	3.14 /* ERROR "cannot assign" */ ++
+	var (
+		x int
+		y float32
+		z complex128
+	)
+	x++
+	y--
+	z++
+}
+
+func sends() {
+	var ch chan int
+	var rch <-chan int
+	var x int
+	x /* ERROR "cannot send" */ <- x
+	rch /* ERROR "cannot send" */ <- x
+	ch <- "foo" /* ERROR "cannot convert" */
+	ch <- x
+}
+
+func selects() {
+	select {}
+	var (
+		ch chan int
+		sc chan <- bool
+	)
+	select {
+	case <-ch:
+	case (<-ch):
+	case t := <-ch:
+		_ = t
+	case t := (<-ch):
+		_ = t
+	case t, ok := <-ch:
+		_, _ = t, ok
+	case t, ok := (<-ch):
+		_, _ = t, ok
+	case <-sc /* ERROR "cannot receive from send-only channel" */ :
+	}
+	select {
+	default:
+	default /* ERROR "multiple defaults" */ :
+	}
+	select {
+	case a, b := <-ch:
+		_, b = a, b
+	case x /* ERROR send or receive */ :
+	case a /* ERROR send or receive */ := ch:
+	}
+
+	// test for issue 9570: ch2 in second case falsely resolved to
+	// ch2 declared in body of first case
+	ch1 := make(chan int)
+	ch2 := make(chan int)
+	select {
+	case <-ch1:
+		var ch2 /* ERROR ch2 declared but not used */ chan bool
+	case i := <-ch2:
+		print(i + 1)
+	}
+}
+
+func gos() {
+	go 1 /* ERROR HERE "function must be invoked" */
+	go int /* ERROR "go requires function call, not conversion" */ (0)
+	go gos()
+	var c chan int
+	go close(c)
+	go len /* ERROR "go discards result" */ (c)
+}
+
+func defers() {
+	defer 1 /* ERROR HERE "function must be invoked" */
+	defer int /* ERROR "defer requires function call, not conversion" */ (0)
+	defer defers()
+	var c chan int
+	defer close(c)
+	defer len /* ERROR "defer discards result" */ (c)
+}
+
+func breaks() {
+	var x, y int
+
+	break /* ERROR "break" */
+	{
+		break /* ERROR "break" */
+	}
+	if x < y {
+		break /* ERROR "break" */
+	}
+
+	switch x {
+	case 0:
+		break
+	case 1:
+		if x == y {
+			break
+		}
+	default:
+		break
+		break
+	}
+
+	var z interface{}
+	switch z.(type) {
+	case int:
+		break
+	}
+
+	for {
+		break
+	}
+
+	var a []int
+	for _ = range a {
+		break
+	}
+
+	for {
+		if x == y {
+			break
+		}
+	}
+
+	var ch chan int
+	select {
+	case <-ch:
+		break
+	}
+
+	select {
+	case <-ch:
+		if x == y {
+			break
+		}
+	default:
+		break
+	}
+}
+
+func continues() {
+	var x, y int
+
+	continue /* ERROR "continue" */
+	{
+		continue /* ERROR "continue" */
+	}
+
+	if x < y {
+		continue /* ERROR "continue" */
+	}
+
+	switch x {
+	case 0:
+		continue /* ERROR "continue" */
+	}
+
+	var z interface{}
+	switch z.(type) {
+	case int:
+		continue /* ERROR "continue" */
+	}
+
+	var ch chan int
+	select {
+	case <-ch:
+		continue /* ERROR "continue" */
+	}
+
+	for i := 0; i < 10; i++ {
+		continue
+		if x < y {
+			continue
+			break
+		}
+		switch x {
+		case y:
+			continue
+		default:
+			break
+		}
+		select {
+		case <-ch:
+			continue
+		}
+	}
+
+	var a []int
+	for _ = range a {
+		continue
+		if x < y {
+			continue
+			break
+		}
+		switch x {
+		case y:
+			continue
+		default:
+			break
+		}
+		select {
+		case <-ch:
+			continue
+		}
+	}
+}
+
+func returns0() {
+	return
+	return 0 /* ERROR no result values expected */
+}
+
+func returns1(x float64) (int, *float64) {
+	return 0, &x
+	return /* ERROR wrong number of return values */
+	return "foo" /* ERROR "cannot convert" */, x /* ERROR "cannot return" */
+	return /* ERROR wrong number of return values */ 0, &x, 1
+}
+
+func returns2() (a, b int) {
+	return
+	return 1, "foo" /* ERROR cannot convert */
+	return /* ERROR wrong number of return values */ 1, 2, 3
+	{
+		type a int
+		return 1, 2
+		return /* ERROR a not in scope at return */
+	}
+}
+
+func returns3() (_ int) {
+	return
+	{
+		var _ int // blank (_) identifiers never shadow since they are in no scope
+		return
+	}
+}
+
+func switches0() {
+	var x int
+
+	switch x {
+	}
+
+	switch x {
+	default:
+	default /* ERROR "multiple defaults" */ :
+	}
+
+	switch {
+	case 1  /* ERROR "cannot convert" */ :
+	}
+
+	true := "false"
+	_ = true
+	// A tagless switch is equivalent to the bool 
+        // constant true, not the identifier 'true'.
+	switch {
+	case "false" /* ERROR "cannot convert" */:
+	}
+
+	switch int32(x) {
+	case 1, 2:
+	case x /* ERROR "cannot compare" */ :
+	}
+
+	switch x {
+	case 1 /* ERROR "overflows" */ << 100:
+	}
+
+	switch x {
+	case 1:
+	case 1 /* DISABLED "duplicate case" */ :
+	case 2, 3, 4:
+	case 1 /* DISABLED "duplicate case" */ :
+	}
+
+	switch uint64(x) {
+	case 1 /* DISABLED duplicate case */ <<64-1:
+	case 1 /* DISABLED duplicate case */ <<64-1:
+	}
+}
+
+func switches1() {
+	fallthrough /* ERROR "fallthrough statement out of place" */
+
+	var x int
+	switch x {
+	case 0:
+		fallthrough /* ERROR "fallthrough statement out of place" */
+		break
+	case 1:
+		fallthrough
+	case 2:
+	default:
+		fallthrough
+	case 3:
+		fallthrough /* ERROR "fallthrough statement out of place" */
+	}
+
+	var y interface{}
+	switch y.(type) {
+	case int:
+		fallthrough /* ERROR "fallthrough statement out of place" */
+	default:
+	}
+
+	switch x {
+	case 0:
+		if x == 0 {
+			fallthrough /* ERROR "fallthrough statement out of place" */
+		}
+	}
+
+	switch x {
+	case 0:
+		goto L1
+		L1: fallthrough
+	case 1:
+		goto L2
+		goto L3
+		goto L4
+		L2: L3: L4: fallthrough
+	default:
+	}
+
+	switch x {
+	case 0:
+		goto L5
+		L5: fallthrough
+	default:
+		goto L6
+		goto L7
+		goto L8
+		L6: L7: L8: fallthrough /* ERROR "fallthrough statement out of place" */
+	}
+
+	switch x {
+	case 0:
+		{
+			fallthrough /* ERROR "fallthrough statement out of place" */
+		}
+	default:
+	}
+}
+
+type I interface {
+	m()
+}
+
+type I2 interface {
+	m(int)
+}
+
+type T struct{}
+type T1 struct{}
+type T2 struct{}
+
+func (T) m() {}
+func (T2) m(int) {}
+
+func typeswitches() {
+	var i int
+	var x interface{}
+
+	switch x.(type) {}
+	switch (x /* ERROR "outside type switch" */ .(type)) {}
+
+	switch x.(type) {
+	default:
+	default /* ERROR "multiple defaults" */ :
+	}
+
+	switch x /* ERROR "declared but not used" */ := x.(type) {}
+	switch _ /* ERROR "no new variable on left side of :=" */ := x.(type) {}
+
+	switch x := x.(type) {
+	case int:
+		var y int = x
+		_ = y
+	}
+
+	switch x := i /* ERROR "not an interface" */ .(type) {}
+
+	switch t := x.(type) {
+	case nil:
+		var v bool = t /* ERROR "cannot initialize" */
+		_ = v
+	case int:
+		var v int = t
+		_ = v
+	case float32, complex64:
+		var v float32 = t /* ERROR "cannot initialize" */
+		_ = v
+	default:
+		var v float32 = t /* ERROR "cannot initialize" */
+		_ = v
+	}
+
+	var t I
+	switch t.(type) {
+	case T:
+	case T1 /* ERROR "missing method m" */ :
+	case T2 /* ERROR "wrong type for method m" */ :
+	case I2 /* STRICT "wrong type for method m" */ : // only an error in strict mode (issue 8561)
+	}
+}
+
+// Test that each case clause uses the correct type of the variable
+// declared by the type switch (issue 5504).
+func typeswitch0() {
+	switch y := interface{}(nil).(type) {
+	case int:
+		func() int { return y + 0 }()
+	case float32:
+		func() float32 { return y }()
+	}
+}
+
+// Test correct scope setup.
+// (no redeclaration errors expected in the type switch)
+func typeswitch1() {
+	var t I
+	switch t := t; t := t.(type) {
+	case nil:
+		var _ I = t
+	case T:
+		var _ T = t
+	default:
+		var _ I = t
+	}
+}
+
+// Test correct typeswitch against interface types.
+type A interface { a() }
+type B interface { b() }
+type C interface { a(int) }
+
+func typeswitch2() {
+	switch A(nil).(type) {
+	case A:
+	case B:
+	case C /* STRICT "cannot have dynamic type" */: // only an error in strict mode (issue 8561)
+	}
+}
+
+func typeswitch3(x interface{}) {
+	switch x.(type) {
+	case int:
+	case float64:
+	case int /* ERROR duplicate case */ :
+	}
+
+	switch x.(type) {
+	case nil:
+	case int:
+	case nil /* ERROR duplicate case */ , nil /* ERROR duplicate case */ :
+	}
+
+	type F func(int)
+	switch x.(type) {
+	case nil:
+	case int, func(int):
+	case float32, func /* ERROR duplicate case */ (x int):
+	case F:
+	}
+}
+
+func fors1() {
+	for {}
+	var i string
+	_ = i
+	for i := 0; i < 10; i++ {}
+	for i := 0; i < 10; j /* ERROR cannot declare */ := 0 {}
+}
+
+func rangeloops1() {
+	var (
+		x int
+		a [10]float32
+		b []string
+		p *[10]complex128
+		pp **[10]complex128
+		s string
+		m map[int]bool
+		c chan int
+		sc chan<- int
+		rc <-chan int
+	)
+
+	for range x /* ERROR "cannot range over" */ {}
+	for _ = range x /* ERROR "cannot range over" */ {}
+	for i := range x /* ERROR "cannot range over" */ {}
+
+	for range a {}
+	for i := range a {
+		var ii int
+		ii = i
+		_ = ii
+	}
+	for i, x := range a {
+		var ii int
+		ii = i
+		_ = ii
+		var xx float64
+		xx = x /* ERROR "cannot assign" */
+		_ = xx
+	}
+	var ii int
+	var xx float32
+	for ii, xx = range a {}
+	_, _ = ii, xx
+
+	for range b {}
+	for i := range b {
+		var ii int
+		ii = i
+		_ = ii
+	}
+	for i, x := range b {
+		var ii int
+		ii = i
+		_ = ii
+		var xx string
+		xx = x
+		_ = xx
+	}
+
+	for range s {}
+	for i := range s {
+		var ii int
+		ii = i
+		_ = ii
+	}
+	for i, x := range s {
+		var ii int
+		ii = i
+		_ = ii
+		var xx rune
+		xx = x
+		_ = xx
+	}
+
+	for range p {}
+	for _, x := range p {
+		var xx complex128
+		xx = x
+		_ = xx
+	}
+
+	for range pp /* ERROR "cannot range over" */ {}
+	for _, x := range pp /* ERROR "cannot range over" */ {}
+
+	for range m {}
+	for k := range m {
+		var kk int32
+		kk = k /* ERROR "cannot assign" */
+		_ = kk
+	}
+	for k, v := range m {
+		var kk int
+		kk = k
+		_ = kk
+		if v {}
+	}
+
+	for range c {}
+	for _, _ /* ERROR "only one iteration variable" */ = range c {}
+	for e := range c {
+		var ee int
+		ee = e
+		_ = ee
+	}
+	for _ = range sc /* ERROR "cannot range over send-only channel" */ {}
+	for _ = range rc {}
+
+	// constant strings
+	const cs = "foo"
+	for range cs {}
+	for range "" {}
+	for i, x := range cs { _, _ = i, x }
+	for i, x := range "" {
+		var ii int
+		ii = i
+		_ = ii
+		var xx rune
+		xx = x
+		_ = xx
+	}
+}
+
+func rangeloops2() {
+	type I int
+	type R rune
+
+	var a [10]int
+	var i I
+	_ = i
+	for i /* ERROR cannot assign */ = range a {}
+	for i /* ERROR cannot assign */ = range &a {}
+	for i /* ERROR cannot assign */ = range a[:] {}
+
+	var s string
+	var r R
+	_ = r
+	for i /* ERROR cannot assign */ = range s {}
+	for i /* ERROR cannot assign */ = range "foo" {}
+	for _, r /* ERROR cannot assign */ = range s {}
+	for _, r /* ERROR cannot assign */ = range "foo" {}
+}
+
+func issue6766b() {
+	for _ := /* ERROR no new variables */ range "" {}
+	for a, a /* ERROR redeclared */ := range "" { _ = a }
+	var a int
+	_ = a
+	for a, a /* ERROR redeclared */ := range []int{1, 2, 3} { _ = a }
+}
+
+// Test that despite errors in the range clause,
+// the loop body is still type-checked (and thus
+// errors reported).
+func issue10148() {
+	for y /* ERROR declared but not used */ := range "" {
+		_ = "" /* ERROR cannot convert */ + 1
+	}
+	for range 1 /* ERROR cannot range over 1 */ {
+		_ = "" /* ERROR cannot convert */ + 1
+	}
+	for y := range 1 /* ERROR cannot range over 1 */ {
+		_ = "" /* ERROR cannot convert */ + 1
+	}
+}
+
+func labels0() {
+	goto L0
+	goto L1
+	L0:
+	L1:
+	L1 /* ERROR "already declared" */ :
+	if true {
+		goto L2		
+		L2:
+		L0 /* ERROR "already declared" */ :
+	}
+	_ = func() {
+		goto L0
+		goto L1
+		goto L2
+		L0:
+		L1:
+		L2:
+	}
+}
+
+func expression_statements(ch chan int) {
+	expression_statements(ch)
+	<-ch
+	println()
+
+	0 /* ERROR "not used" */
+	1 /* ERROR "not used" */ +2
+	cap /* ERROR "not used" */ (ch)
+	println /* ERROR "must be called" */
+}
diff --git a/src/go/types/testdata/stmt1.src b/src/go/types/testdata/stmt1.src
new file mode 100644
index 0000000..a2955e6
--- /dev/null
+++ b/src/go/types/testdata/stmt1.src
@@ -0,0 +1,165 @@
+// 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.
+
+// terminating statements
+
+package stmt1
+
+func _() {}
+
+func _() int {} /* ERROR "missing return" */
+
+func _() int { panic(0) }
+func _() int { (panic(0)) }
+
+// block statements
+func _(x, y int) (z int) {
+	{
+		return
+	}
+}
+
+func _(x, y int) (z int) {
+	{
+	}
+} /* ERROR "missing return" */
+
+// if statements
+func _(x, y int) (z int) {
+	if x < y { return }
+	return 1
+}
+
+func _(x, y int) (z int) {
+	if x < y { return }
+} /* ERROR "missing return" */
+
+func _(x, y int) (z int) {
+	if x < y {
+	} else { return 1
+	}
+} /* ERROR "missing return" */
+
+func _(x, y int) (z int) {
+	if x < y { return
+	} else { return
+	}
+}
+
+// for statements
+func _(x, y int) (z int) {
+	for x < y {
+		return
+	}
+} /* ERROR "missing return" */
+
+func _(x, y int) (z int) {
+	for {
+		return
+	}
+}
+
+func _(x, y int) (z int) {
+	for {
+		return
+		break
+	}
+} /* ERROR "missing return" */
+
+func _(x, y int) (z int) {
+	for {
+		for { break }
+		return
+	}
+}
+
+func _(x, y int) (z int) {
+L:	for {
+		for { break L }
+		return
+	}
+} /* ERROR "missing return" */
+
+// switch statements
+func _(x, y int) (z int) {
+	switch x {
+	case 0: return
+	default: return
+	}
+}
+
+func _(x, y int) (z int) {
+	switch x {
+	case 0: return
+	}
+} /* ERROR "missing return" */
+
+func _(x, y int) (z int) {
+	switch x {
+	case 0: return
+	case 1: break
+	}
+} /* ERROR "missing return" */
+
+func _(x, y int) (z int) {
+	switch x {
+	case 0: return
+	default:
+		switch y {
+		case 0: break
+		}
+		panic(0)
+	}
+}
+
+func _(x, y int) (z int) {
+L:	switch x {
+	case 0: return
+	default:
+		switch y {
+		case 0: break L
+		}
+		panic(0)
+	}
+} /* ERROR "missing return" */
+
+// select statements
+func _(ch chan int) (z int) {
+	select {}
+} // nice!
+
+func _(ch chan int) (z int) {
+	select {
+	default: break
+	}
+} /* ERROR "missing return" */
+
+func _(ch chan int) (z int) {
+	select {
+	case <-ch: return
+	default: break
+	}
+} /* ERROR "missing return" */
+
+func _(ch chan int) (z int) {
+	select {
+	case <-ch: return
+	default:
+		for i := 0; i < 10; i++ {
+			break
+		}
+		return
+	}
+}
+
+func _(ch chan int) (z int) {
+L:	select {
+	case <-ch: return
+	default:
+		for i := 0; i < 10; i++ {
+			break L
+		}
+		return
+	}
+} /* ERROR "missing return" */
diff --git a/src/go/types/testdata/vardecl.src b/src/go/types/testdata/vardecl.src
new file mode 100644
index 0000000..fb6b5f7
--- /dev/null
+++ b/src/go/types/testdata/vardecl.src
@@ -0,0 +1,186 @@
+// 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 vardecl
+
+// Prerequisites.
+import "math"
+func f() {}
+func g() (x, y int) { return }
+var m map[string]int
+
+// Var decls must have a type or an initializer.
+var _ int
+var _, _ int
+
+// The first error message is produced by the parser.
+// In a real-world scenario, the type-checker would not be run
+// in this case and the 2nd error message would not appear.
+var _ /* ERROR "missing variable type" */ /* ERROR "missing type or init expr" */
+var _ /* ERROR "missing variable type" */ /* ERROR "missing type or init expr" */, _
+var _ /* ERROR "missing variable type" */ /* ERROR "missing type or init expr" */, _, _
+
+// The initializer must be an expression.
+var _ = int /* ERROR "not an expression" */
+var _ = f /* ERROR "used as value" */ ()
+
+// Identifier and expression arity must match.
+var _, _ = 1, 2
+var _ = 1, 2 /* ERROR "extra init expr 2" */
+var _, _ = 1 /* ERROR "assignment count mismatch" */
+var _, _, _ /* ERROR "missing init expr for _" */ = 1, 2
+
+var _ = g /* ERROR "2-valued expr" */ ()
+var _, _ = g()
+var _, _, _ = g /* ERROR "assignment count mismatch" */ ()
+
+var _ = m["foo"]
+var _, _ = m["foo"]
+var _, _, _ = m  /* ERROR "assignment count mismatch" */ ["foo"]
+
+var _, _ int = 1, 2
+var _ int = 1, 2 /* ERROR "extra init expr 2" */
+var _, _ int = 1 /* ERROR "assignment count mismatch" */
+var _, _, _ /* ERROR "missing init expr for _" */ int = 1, 2
+
+var (
+	_, _ = 1, 2
+	_ = 1, 2 /* ERROR "extra init expr 2" */
+	_, _ = 1 /* ERROR "assignment count mismatch" */
+	_, _, _ /* ERROR "missing init expr for _" */ = 1, 2
+
+	_ = g /* ERROR "2-valued expr" */ ()
+	_, _ = g()
+	_, _, _ = g /* ERROR "assignment count mismatch" */ ()
+
+	_ = m["foo"]
+	_, _ = m["foo"]
+	_, _, _ = m /* ERROR "assignment count mismatch" */ ["foo"]
+
+	_, _ int = 1, 2
+	_ int = 1, 2 /* ERROR "extra init expr 2" */
+	_, _ int = 1 /* ERROR "assignment count mismatch" */
+	_, _, _ /* ERROR "missing init expr for _" */ int = 1, 2
+)
+
+// Variables declared in function bodies must be 'used'.
+type T struct{}
+func (r T) _(a, b, c int) (u, v, w int) {
+	var x1 /* ERROR "declared but not used" */ int
+	var x2 /* ERROR "declared but not used" */ int
+	x1 = 1
+	(x2) = 2
+
+	y1 /* ERROR "declared but not used" */ := 1
+	y2 /* ERROR "declared but not used" */ := 2
+	y1 = 1
+	(y1) = 2
+
+	{
+		var x1 /* ERROR "declared but not used" */ int
+		var x2 /* ERROR "declared but not used" */ int
+		x1 = 1
+		(x2) = 2
+
+		y1 /* ERROR "declared but not used" */ := 1
+		y2 /* ERROR "declared but not used" */ := 2
+		y1 = 1
+		(y1) = 2
+	}
+
+	if x /* ERROR "declared but not used" */ := 0; a < b {}
+
+	switch x /* ERROR "declared but not used" */, y := 0, 1; a {
+	case 0:
+		_ = y
+	case 1:
+		x /* ERROR "declared but not used" */ := 0
+	}
+
+	var t interface{}
+	switch t /* ERROR "declared but not used" */ := t.(type) {}
+
+	switch t /* ERROR "declared but not used" */ := t.(type) {
+	case int:
+	}
+
+	switch t /* ERROR "declared but not used" */ := t.(type) {
+	case int:
+	case float32, complex64:
+		t = nil
+	}
+
+	switch t := t.(type) {
+	case int:
+	case float32, complex64:
+		_ = t
+	}
+
+	switch t := t.(type) {
+	case int:
+	case float32:
+	case string:
+		_ = func() string {
+			return t
+		}
+	}
+
+	switch t := t; t /* ERROR "declared but not used" */ := t.(type) {}
+
+	var z1 /* ERROR "declared but not used" */ int
+	var z2 int
+	_ = func(a, b, c int) (u, v, w int) {
+		z1 = a
+		(z1) = b
+		a = z2
+		return
+	}
+
+	var s []int
+	var i /* ERROR "declared but not used" */ , j int
+	for i, j = range s {
+		_ = j
+	}
+
+	for i, j /* ERROR "declared but not used" */ := range s {
+		_ = func() int {
+			return i
+		}
+	}
+	return
+}
+
+// Invalid (unused) expressions must not lead to spurious "declared but not used errors"
+func _() {
+	var a, b, c int
+	var x, y int
+	x, y = a /* ERROR assignment count mismatch */ , b, c
+	_ = x
+	_ = y
+}
+
+func _() {
+	var x int
+	return x /* ERROR no result values expected */
+	return math /* ERROR no result values expected */ .Sin(0)
+}
+
+func _() int {
+	var x, y int
+	return /* ERROR wrong number of return values */ x, y
+}
+
+// Short variable declarations must declare at least one new non-blank variable.
+func _() {
+	_ := /* ERROR no new variables */ 0
+	_, a := 0, 1
+	_, a := /* ERROR no new variables */ 0, 1
+	_, a, b := 0, 1, 2
+	_, _, _ := /* ERROR no new variables */ 0, 1, 2
+
+	_ = a
+	_ = b
+}
+
+// TODO(gri) consolidate other var decl checks in this file
\ No newline at end of file
diff --git a/src/go/types/token_test.go b/src/go/types/token_test.go
new file mode 100644
index 0000000..705bb29
--- /dev/null
+++ b/src/go/types/token_test.go
@@ -0,0 +1,47 @@
+// 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.
+
+// This file checks invariants of token.Token ordering that we rely on
+// since package go/token doesn't provide any guarantees at the moment.
+
+package types
+
+import (
+	"go/token"
+	"testing"
+)
+
+var assignOps = map[token.Token]token.Token{
+	token.ADD_ASSIGN:     token.ADD,
+	token.SUB_ASSIGN:     token.SUB,
+	token.MUL_ASSIGN:     token.MUL,
+	token.QUO_ASSIGN:     token.QUO,
+	token.REM_ASSIGN:     token.REM,
+	token.AND_ASSIGN:     token.AND,
+	token.OR_ASSIGN:      token.OR,
+	token.XOR_ASSIGN:     token.XOR,
+	token.SHL_ASSIGN:     token.SHL,
+	token.SHR_ASSIGN:     token.SHR,
+	token.AND_NOT_ASSIGN: token.AND_NOT,
+}
+
+func TestZeroTok(t *testing.T) {
+	// zero value for token.Token must be token.ILLEGAL
+	var zero token.Token
+	if token.ILLEGAL != zero {
+		t.Errorf("%s == %d; want 0", token.ILLEGAL, zero)
+	}
+}
+
+func TestAssignOp(t *testing.T) {
+	// there are fewer than 256 tokens
+	for i := 0; i < 256; i++ {
+		tok := token.Token(i)
+		got := assignOp(tok)
+		want := assignOps[tok]
+		if got != want {
+			t.Errorf("for assignOp(%s): got %s; want %s", tok, got, want)
+		}
+	}
+}
diff --git a/src/go/types/type.go b/src/go/types/type.go
new file mode 100644
index 0000000..1df8b45
--- /dev/null
+++ b/src/go/types/type.go
@@ -0,0 +1,454 @@
+// 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 types
+
+import "sort"
+
+// TODO(gri) Revisit factory functions - make sure they have all relevant parameters.
+
+// A Type represents a type of Go.
+// All types implement the Type interface.
+type Type interface {
+	// Underlying returns the underlying type of a type.
+	Underlying() Type
+
+	// String returns a string representation of a type.
+	String() string
+}
+
+// BasicKind describes the kind of basic type.
+type BasicKind int
+
+const (
+	Invalid BasicKind = iota // type is invalid
+
+	// predeclared types
+	Bool
+	Int
+	Int8
+	Int16
+	Int32
+	Int64
+	Uint
+	Uint8
+	Uint16
+	Uint32
+	Uint64
+	Uintptr
+	Float32
+	Float64
+	Complex64
+	Complex128
+	String
+	UnsafePointer
+
+	// types for untyped values
+	UntypedBool
+	UntypedInt
+	UntypedRune
+	UntypedFloat
+	UntypedComplex
+	UntypedString
+	UntypedNil
+
+	// aliases
+	Byte = Uint8
+	Rune = Int32
+)
+
+// BasicInfo is a set of flags describing properties of a basic type.
+type BasicInfo int
+
+// Properties of basic types.
+const (
+	IsBoolean BasicInfo = 1 << iota
+	IsInteger
+	IsUnsigned
+	IsFloat
+	IsComplex
+	IsString
+	IsUntyped
+
+	IsOrdered   = IsInteger | IsFloat | IsString
+	IsNumeric   = IsInteger | IsFloat | IsComplex
+	IsConstType = IsBoolean | IsNumeric | IsString
+)
+
+// A Basic represents a basic type.
+type Basic struct {
+	kind BasicKind
+	info BasicInfo
+	name string
+}
+
+// Kind returns the kind of basic type b.
+func (b *Basic) Kind() BasicKind { return b.kind }
+
+// Info returns information about properties of basic type b.
+func (b *Basic) Info() BasicInfo { return b.info }
+
+// Name returns the name of basic type b.
+func (b *Basic) Name() string { return b.name }
+
+// An Array represents an array type.
+type Array struct {
+	len  int64
+	elem Type
+}
+
+// NewArray returns a new array type for the given element type and length.
+func NewArray(elem Type, len int64) *Array { return &Array{len, elem} }
+
+// Len returns the length of array a.
+func (a *Array) Len() int64 { return a.len }
+
+// Elem returns element type of array a.
+func (a *Array) Elem() Type { return a.elem }
+
+// A Slice represents a slice type.
+type Slice struct {
+	elem Type
+}
+
+// NewSlice returns a new slice type for the given element type.
+func NewSlice(elem Type) *Slice { return &Slice{elem} }
+
+// Elem returns the element type of slice s.
+func (s *Slice) Elem() Type { return s.elem }
+
+// A Struct represents a struct type.
+type Struct struct {
+	fields []*Var
+	tags   []string // field tags; nil if there are no tags
+	// TODO(gri) access to offsets is not threadsafe - fix this
+	offsets []int64 // field offsets in bytes, lazily initialized
+}
+
+// NewStruct returns a new struct with the given fields and corresponding field tags.
+// If a field with index i has a tag, tags[i] must be that tag, but len(tags) may be
+// only as long as required to hold the tag with the largest index i. Consequently,
+// if no field has a tag, tags may be nil.
+func NewStruct(fields []*Var, tags []string) *Struct {
+	var fset objset
+	for _, f := range fields {
+		if f.name != "_" && fset.insert(f) != nil {
+			panic("multiple fields with the same name")
+		}
+	}
+	if len(tags) > len(fields) {
+		panic("more tags than fields")
+	}
+	return &Struct{fields: fields, tags: tags}
+}
+
+// NumFields returns the number of fields in the struct (including blank and anonymous fields).
+func (s *Struct) NumFields() int { return len(s.fields) }
+
+// Field returns the i'th field for 0 <= i < NumFields().
+func (s *Struct) Field(i int) *Var { return s.fields[i] }
+
+// Tag returns the i'th field tag for 0 <= i < NumFields().
+func (s *Struct) Tag(i int) string {
+	if i < len(s.tags) {
+		return s.tags[i]
+	}
+	return ""
+}
+
+// A Pointer represents a pointer type.
+type Pointer struct {
+	base Type // element type
+}
+
+// NewPointer returns a new pointer type for the given element (base) type.
+func NewPointer(elem Type) *Pointer { return &Pointer{base: elem} }
+
+// Elem returns the element type for the given pointer p.
+func (p *Pointer) Elem() Type { return p.base }
+
+// A Tuple represents an ordered list of variables; a nil *Tuple is a valid (empty) tuple.
+// Tuples are used as components of signatures and to represent the type of multiple
+// assignments; they are not first class types of Go.
+type Tuple struct {
+	vars []*Var
+}
+
+// NewTuple returns a new tuple for the given variables.
+func NewTuple(x ...*Var) *Tuple {
+	if len(x) > 0 {
+		return &Tuple{x}
+	}
+	return nil
+}
+
+// Len returns the number variables of tuple t.
+func (t *Tuple) Len() int {
+	if t != nil {
+		return len(t.vars)
+	}
+	return 0
+}
+
+// At returns the i'th variable of tuple t.
+func (t *Tuple) At(i int) *Var { return t.vars[i] }
+
+// A Signature represents a (non-builtin) function or method type.
+type Signature struct {
+	// We need to keep the scope in Signature (rather than passing it around
+	// and store it in the Func Object) because when type-checking a function
+	// literal we call the general type checker which returns a general Type.
+	// We then unpack the *Signature and use the scope for the literal body.
+	scope    *Scope // function scope, present for package-local signatures
+	recv     *Var   // nil if not a method
+	params   *Tuple // (incoming) parameters from left to right; or nil
+	results  *Tuple // (outgoing) results from left to right; or nil
+	variadic bool   // true if the last parameter's type is of the form ...T (or string, for append built-in only)
+}
+
+// NewSignature returns a new function type for the given receiver, parameters,
+// and results, either of which may be nil. If variadic is set, the function
+// is variadic, it must have at least one parameter, and the last parameter
+// must be of unnamed slice type.
+func NewSignature(recv *Var, params, results *Tuple, variadic bool) *Signature {
+	if variadic {
+		n := params.Len()
+		if n == 0 {
+			panic("types.NewSignature: variadic function must have at least one parameter")
+		}
+		if _, ok := params.At(n - 1).typ.(*Slice); !ok {
+			panic("types.NewSignature: variadic parameter must be of unnamed slice type")
+		}
+	}
+	return &Signature{nil, recv, params, results, variadic}
+}
+
+// Recv returns the receiver of signature s (if a method), or nil if a
+// function.
+//
+// For an abstract method, Recv returns the enclosing interface either
+// as a *Named or an *Interface.  Due to embedding, an interface may
+// contain methods whose receiver type is a different interface.
+func (s *Signature) Recv() *Var { return s.recv }
+
+// Params returns the parameters of signature s, or nil.
+func (s *Signature) Params() *Tuple { return s.params }
+
+// Results returns the results of signature s, or nil.
+func (s *Signature) Results() *Tuple { return s.results }
+
+// Variadic reports whether the signature s is variadic.
+func (s *Signature) Variadic() bool { return s.variadic }
+
+// An Interface represents an interface type.
+type Interface struct {
+	methods   []*Func  // ordered list of explicitly declared methods
+	embeddeds []*Named // ordered list of explicitly embedded types
+
+	allMethods []*Func // ordered list of methods declared with or embedded in this interface (TODO(gri): replace with mset)
+}
+
+// NewInterface returns a new interface for the given methods and embedded types.
+func NewInterface(methods []*Func, embeddeds []*Named) *Interface {
+	typ := new(Interface)
+
+	var mset objset
+	for _, m := range methods {
+		if mset.insert(m) != nil {
+			panic("multiple methods with the same name")
+		}
+		// set receiver
+		// TODO(gri) Ideally, we should use a named type here instead of
+		// typ, for less verbose printing of interface method signatures.
+		m.typ.(*Signature).recv = NewVar(m.pos, m.pkg, "", typ)
+	}
+	sort.Sort(byUniqueMethodName(methods))
+
+	if embeddeds == nil {
+		sort.Sort(byUniqueTypeName(embeddeds))
+	}
+
+	typ.methods = methods
+	typ.embeddeds = embeddeds
+	return typ
+}
+
+// NumExplicitMethods returns the number of explicitly declared methods of interface t.
+func (t *Interface) NumExplicitMethods() int { return len(t.methods) }
+
+// ExplicitMethod returns the i'th explicitly declared method of interface t for 0 <= i < t.NumExplicitMethods().
+// The methods are ordered by their unique Id.
+func (t *Interface) ExplicitMethod(i int) *Func { return t.methods[i] }
+
+// NumEmbeddeds returns the number of embedded types in interface t.
+func (t *Interface) NumEmbeddeds() int { return len(t.embeddeds) }
+
+// Embedded returns the i'th embedded type of interface t for 0 <= i < t.NumEmbeddeds().
+// The types are ordered by the corresponding TypeName's unique Id.
+func (t *Interface) Embedded(i int) *Named { return t.embeddeds[i] }
+
+// NumMethods returns the total number of methods of interface t.
+func (t *Interface) NumMethods() int { return len(t.allMethods) }
+
+// Method returns the i'th method of interface t for 0 <= i < t.NumMethods().
+// The methods are ordered by their unique Id.
+func (t *Interface) Method(i int) *Func { return t.allMethods[i] }
+
+// Empty returns true if t is the empty interface.
+func (t *Interface) Empty() bool { return len(t.allMethods) == 0 }
+
+// Complete computes the interface's method set. It must be called by users of
+// NewInterface after the interface's embedded types are fully defined and
+// before using the interface type in any way other than to form other types.
+// Complete returns the receiver.
+func (t *Interface) Complete() *Interface {
+	if t.allMethods != nil {
+		return t
+	}
+
+	var allMethods []*Func
+	if t.embeddeds == nil {
+		if t.methods == nil {
+			allMethods = make([]*Func, 0, 1)
+		} else {
+			allMethods = t.methods
+		}
+	} else {
+		allMethods = append(allMethods, t.methods...)
+		for _, et := range t.embeddeds {
+			it := et.Underlying().(*Interface)
+			it.Complete()
+			for _, tm := range it.allMethods {
+				// Make a copy of the method and adjust its receiver type.
+				newm := *tm
+				newmtyp := *tm.typ.(*Signature)
+				newm.typ = &newmtyp
+				newmtyp.recv = NewVar(newm.pos, newm.pkg, "", t)
+				allMethods = append(allMethods, &newm)
+			}
+		}
+		sort.Sort(byUniqueMethodName(allMethods))
+	}
+	t.allMethods = allMethods
+
+	return t
+}
+
+// A Map represents a map type.
+type Map struct {
+	key, elem Type
+}
+
+// NewMap returns a new map for the given key and element types.
+func NewMap(key, elem Type) *Map {
+	return &Map{key, elem}
+}
+
+// Key returns the key type of map m.
+func (m *Map) Key() Type { return m.key }
+
+// Elem returns the element type of map m.
+func (m *Map) Elem() Type { return m.elem }
+
+// A Chan represents a channel type.
+type Chan struct {
+	dir  ChanDir
+	elem Type
+}
+
+// A ChanDir value indicates a channel direction.
+type ChanDir int
+
+// The direction of a channel is indicated by one of the following constants.
+const (
+	SendRecv ChanDir = iota
+	SendOnly
+	RecvOnly
+)
+
+// NewChan returns a new channel type for the given direction and element type.
+func NewChan(dir ChanDir, elem Type) *Chan {
+	return &Chan{dir, elem}
+}
+
+// Dir returns the direction of channel c.
+func (c *Chan) Dir() ChanDir { return c.dir }
+
+// Elem returns the element type of channel c.
+func (c *Chan) Elem() Type { return c.elem }
+
+// A Named represents a named type.
+type Named struct {
+	obj        *TypeName // corresponding declared object
+	underlying Type      // possibly a *Named during setup; never a *Named once set up completely
+	methods    []*Func   // methods declared for this type (not the method set of this type)
+}
+
+// NewNamed returns a new named type for the given type name, underlying type, and associated methods.
+// The underlying type must not be a *Named.
+func NewNamed(obj *TypeName, underlying Type, methods []*Func) *Named {
+	if _, ok := underlying.(*Named); ok {
+		panic("types.NewNamed: underlying type must not be *Named")
+	}
+	typ := &Named{obj: obj, underlying: underlying, methods: methods}
+	if obj.typ == nil {
+		obj.typ = typ
+	}
+	return typ
+}
+
+// TypeName returns the type name for the named type t.
+func (t *Named) Obj() *TypeName { return t.obj }
+
+// NumMethods returns the number of explicit methods whose receiver is named type t.
+func (t *Named) NumMethods() int { return len(t.methods) }
+
+// Method returns the i'th method of named type t for 0 <= i < t.NumMethods().
+func (t *Named) Method(i int) *Func { return t.methods[i] }
+
+// SetUnderlying sets the underlying type and marks t as complete.
+// TODO(gri) determine if there's a better solution rather than providing this function
+func (t *Named) SetUnderlying(underlying Type) {
+	if underlying == nil {
+		panic("types.Named.SetUnderlying: underlying type must not be nil")
+	}
+	if _, ok := underlying.(*Named); ok {
+		panic("types.Named.SetUnderlying: underlying type must not be *Named")
+	}
+	t.underlying = underlying
+}
+
+// AddMethod adds method m unless it is already in the method list.
+// TODO(gri) find a better solution instead of providing this function
+func (t *Named) AddMethod(m *Func) {
+	if i, _ := lookupMethod(t.methods, m.pkg, m.name); i < 0 {
+		t.methods = append(t.methods, m)
+	}
+}
+
+// Implementations for Type methods.
+
+func (t *Basic) Underlying() Type     { return t }
+func (t *Array) Underlying() Type     { return t }
+func (t *Slice) Underlying() Type     { return t }
+func (t *Struct) Underlying() Type    { return t }
+func (t *Pointer) Underlying() Type   { return t }
+func (t *Tuple) Underlying() Type     { return t }
+func (t *Signature) Underlying() Type { return t }
+func (t *Interface) Underlying() Type { return t }
+func (t *Map) Underlying() Type       { return t }
+func (t *Chan) Underlying() Type      { return t }
+func (t *Named) Underlying() Type     { return t.underlying }
+
+func (t *Basic) String() string     { return TypeString(t, nil) }
+func (t *Array) String() string     { return TypeString(t, nil) }
+func (t *Slice) String() string     { return TypeString(t, nil) }
+func (t *Struct) String() string    { return TypeString(t, nil) }
+func (t *Pointer) String() string   { return TypeString(t, nil) }
+func (t *Tuple) String() string     { return TypeString(t, nil) }
+func (t *Signature) String() string { return TypeString(t, nil) }
+func (t *Interface) String() string { return TypeString(t, nil) }
+func (t *Map) String() string       { return TypeString(t, nil) }
+func (t *Chan) String() string      { return TypeString(t, nil) }
+func (t *Named) String() string     { return TypeString(t, nil) }
diff --git a/src/go/types/typestring.go b/src/go/types/typestring.go
new file mode 100644
index 0000000..bd62f4d
--- /dev/null
+++ b/src/go/types/typestring.go
@@ -0,0 +1,296 @@
+// 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.
+
+// This file implements printing of types.
+
+package types
+
+import (
+	"bytes"
+	"fmt"
+)
+
+// A Qualifier controls how named package-level objects are printed in
+// calls to TypeString, ObjectString, and SelectionString.
+//
+// These three formatting routines call the Qualifier for each
+// package-level object O, and if the Qualifier returns a non-empty
+// string p, the object is printed in the form p.O.
+// If it returns an empty string, only the object name O is printed.
+//
+// Using a nil Qualifier is equivalent to using (*Package).Path: the
+// object is qualified by the import path, e.g., "encoding/json.Marshal".
+//
+type Qualifier func(*Package) string
+
+// RelativeTo(pkg) returns a Qualifier that fully qualifies members of
+// all packages other than pkg.
+func RelativeTo(pkg *Package) Qualifier {
+	if pkg == nil {
+		return nil
+	}
+	return func(other *Package) string {
+		if pkg == other {
+			return "" // same package; unqualified
+		}
+		return other.Path()
+	}
+}
+
+// If gcCompatibilityMode is set, printing of types is modified
+// to match the representation of some types in the gc compiler:
+//
+//	- byte and rune lose their alias name and simply stand for
+//	  uint8 and int32 respectively
+//	- embedded interfaces get flattened (the embedding info is lost,
+//	  and certain recursive interface types cannot be printed anymore)
+//
+// This makes it easier to compare packages computed with the type-
+// checker vs packages imported from gc export data.
+//
+// Caution: This flag affects all uses of WriteType, globally.
+// It is only provided for testing in conjunction with
+// gc-generated data.
+//
+// This flag is exported in the x/tools/go/types package. We don't
+// need it at the moment in the std repo and so we don't export it
+// anymore. We should eventually try to remove it altogether.
+var gcCompatibilityMode bool
+
+// TypeString returns the string representation of typ.
+// The Qualifier controls the printing of
+// package-level objects, and may be nil.
+func TypeString(typ Type, qf Qualifier) string {
+	var buf bytes.Buffer
+	WriteType(&buf, typ, qf)
+	return buf.String()
+}
+
+// WriteType writes the string representation of typ to buf.
+// The Qualifier controls the printing of
+// package-level objects, and may be nil.
+func WriteType(buf *bytes.Buffer, typ Type, qf Qualifier) {
+	writeType(buf, typ, qf, make([]Type, 8))
+}
+
+func writeType(buf *bytes.Buffer, typ Type, qf Qualifier, visited []Type) {
+	// Theoretically, this is a quadratic lookup algorithm, but in
+	// practice deeply nested composite types with unnamed component
+	// types are uncommon. This code is likely more efficient than
+	// using a map.
+	for _, t := range visited {
+		if t == typ {
+			fmt.Fprintf(buf, "○%T", typ) // cycle to typ
+			return
+		}
+	}
+	visited = append(visited, typ)
+
+	switch t := typ.(type) {
+	case nil:
+		buf.WriteString("<nil>")
+
+	case *Basic:
+		if t.kind == UnsafePointer {
+			buf.WriteString("unsafe.")
+		}
+		if gcCompatibilityMode {
+			// forget the alias names
+			switch t.kind {
+			case Byte:
+				t = Typ[Uint8]
+			case Rune:
+				t = Typ[Int32]
+			}
+		}
+		buf.WriteString(t.name)
+
+	case *Array:
+		fmt.Fprintf(buf, "[%d]", t.len)
+		writeType(buf, t.elem, qf, visited)
+
+	case *Slice:
+		buf.WriteString("[]")
+		writeType(buf, t.elem, qf, visited)
+
+	case *Struct:
+		buf.WriteString("struct{")
+		for i, f := range t.fields {
+			if i > 0 {
+				buf.WriteString("; ")
+			}
+			if !f.anonymous {
+				buf.WriteString(f.name)
+				buf.WriteByte(' ')
+			}
+			writeType(buf, f.typ, qf, visited)
+			if tag := t.Tag(i); tag != "" {
+				fmt.Fprintf(buf, " %q", tag)
+			}
+		}
+		buf.WriteByte('}')
+
+	case *Pointer:
+		buf.WriteByte('*')
+		writeType(buf, t.base, qf, visited)
+
+	case *Tuple:
+		writeTuple(buf, t, false, qf, visited)
+
+	case *Signature:
+		buf.WriteString("func")
+		writeSignature(buf, t, qf, visited)
+
+	case *Interface:
+		// We write the source-level methods and embedded types rather
+		// than the actual method set since resolved method signatures
+		// may have non-printable cycles if parameters have anonymous
+		// interface types that (directly or indirectly) embed the
+		// current interface. For instance, consider the result type
+		// of m:
+		//
+		//     type T interface{
+		//         m() interface{ T }
+		//     }
+		//
+		buf.WriteString("interface{")
+		if gcCompatibilityMode {
+			// print flattened interface
+			// (useful to compare against gc-generated interfaces)
+			for i, m := range t.allMethods {
+				if i > 0 {
+					buf.WriteString("; ")
+				}
+				buf.WriteString(m.name)
+				writeSignature(buf, m.typ.(*Signature), qf, visited)
+			}
+		} else {
+			// print explicit interface methods and embedded types
+			for i, m := range t.methods {
+				if i > 0 {
+					buf.WriteString("; ")
+				}
+				buf.WriteString(m.name)
+				writeSignature(buf, m.typ.(*Signature), qf, visited)
+			}
+			for i, typ := range t.embeddeds {
+				if i > 0 || len(t.methods) > 0 {
+					buf.WriteString("; ")
+				}
+				writeType(buf, typ, qf, visited)
+			}
+		}
+		buf.WriteByte('}')
+
+	case *Map:
+		buf.WriteString("map[")
+		writeType(buf, t.key, qf, visited)
+		buf.WriteByte(']')
+		writeType(buf, t.elem, qf, visited)
+
+	case *Chan:
+		var s string
+		var parens bool
+		switch t.dir {
+		case SendRecv:
+			s = "chan "
+			// chan (<-chan T) requires parentheses
+			if c, _ := t.elem.(*Chan); c != nil && c.dir == RecvOnly {
+				parens = true
+			}
+		case SendOnly:
+			s = "chan<- "
+		case RecvOnly:
+			s = "<-chan "
+		default:
+			panic("unreachable")
+		}
+		buf.WriteString(s)
+		if parens {
+			buf.WriteByte('(')
+		}
+		writeType(buf, t.elem, qf, visited)
+		if parens {
+			buf.WriteByte(')')
+		}
+
+	case *Named:
+		s := "<Named w/o object>"
+		if obj := t.obj; obj != nil {
+			if obj.pkg != nil {
+				writePackage(buf, obj.pkg, qf)
+			}
+			// TODO(gri): function-local named types should be displayed
+			// differently from named types at package level to avoid
+			// ambiguity.
+			s = obj.name
+		}
+		buf.WriteString(s)
+
+	default:
+		// For externally defined implementations of Type.
+		buf.WriteString(t.String())
+	}
+}
+
+func writeTuple(buf *bytes.Buffer, tup *Tuple, variadic bool, qf Qualifier, visited []Type) {
+	buf.WriteByte('(')
+	if tup != nil {
+		for i, v := range tup.vars {
+			if i > 0 {
+				buf.WriteString(", ")
+			}
+			if v.name != "" {
+				buf.WriteString(v.name)
+				buf.WriteByte(' ')
+			}
+			typ := v.typ
+			if variadic && i == len(tup.vars)-1 {
+				if s, ok := typ.(*Slice); ok {
+					buf.WriteString("...")
+					typ = s.elem
+				} else {
+					// special case:
+					// append(s, "foo"...) leads to signature func([]byte, string...)
+					if t, ok := typ.Underlying().(*Basic); !ok || t.kind != String {
+						panic("internal error: string type expected")
+					}
+					writeType(buf, typ, qf, visited)
+					buf.WriteString("...")
+					continue
+				}
+			}
+			writeType(buf, typ, qf, visited)
+		}
+	}
+	buf.WriteByte(')')
+}
+
+// WriteSignature writes the representation of the signature sig to buf,
+// without a leading "func" keyword.
+// The Qualifier controls the printing of
+// package-level objects, and may be nil.
+func WriteSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier) {
+	writeSignature(buf, sig, qf, make([]Type, 8))
+}
+
+func writeSignature(buf *bytes.Buffer, sig *Signature, qf Qualifier, visited []Type) {
+	writeTuple(buf, sig.params, sig.variadic, qf, visited)
+
+	n := sig.results.Len()
+	if n == 0 {
+		// no result
+		return
+	}
+
+	buf.WriteByte(' ')
+	if n == 1 && sig.results.vars[0].name == "" {
+		// single unnamed result
+		writeType(buf, sig.results.vars[0].typ, qf, visited)
+		return
+	}
+
+	// multiple or named result(s)
+	writeTuple(buf, sig.results, false, qf, visited)
+}
diff --git a/src/go/types/typestring_test.go b/src/go/types/typestring_test.go
new file mode 100644
index 0000000..913e6c7
--- /dev/null
+++ b/src/go/types/typestring_test.go
@@ -0,0 +1,168 @@
+// 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.
+
+package types_test
+
+import (
+	"go/ast"
+	"go/importer"
+	"go/parser"
+	"go/token"
+	"internal/testenv"
+	"testing"
+
+	. "go/types"
+)
+
+const filename = "<src>"
+
+func makePkg(t *testing.T, src string) (*Package, error) {
+	fset := token.NewFileSet()
+	file, err := parser.ParseFile(fset, filename, src, parser.DeclarationErrors)
+	if err != nil {
+		return nil, err
+	}
+	// use the package name as package path
+	conf := Config{Importer: importer.Default()}
+	return conf.Check(file.Name.Name, fset, []*ast.File{file}, nil)
+}
+
+type testEntry struct {
+	src, str string
+}
+
+// dup returns a testEntry where both src and str are the same.
+func dup(s string) testEntry {
+	return testEntry{s, s}
+}
+
+// types that don't depend on any other type declarations
+var independentTestTypes = []testEntry{
+	// basic types
+	dup("int"),
+	dup("float32"),
+	dup("string"),
+
+	// arrays
+	dup("[10]int"),
+
+	// slices
+	dup("[]int"),
+	dup("[][]int"),
+
+	// structs
+	dup("struct{}"),
+	dup("struct{x int}"),
+	{`struct {
+		x, y int
+		z float32 "foo"
+	}`, `struct{x int; y int; z float32 "foo"}`},
+	{`struct {
+		string
+		elems []complex128
+	}`, `struct{string; elems []complex128}`},
+
+	// pointers
+	dup("*int"),
+	dup("***struct{}"),
+	dup("*struct{a int; b float32}"),
+
+	// functions
+	dup("func()"),
+	dup("func(x int)"),
+	{"func(x, y int)", "func(x int, y int)"},
+	{"func(x, y int, z string)", "func(x int, y int, z string)"},
+	dup("func(int)"),
+	{"func(int, string, byte)", "func(int, string, byte)"},
+
+	dup("func() int"),
+	{"func() (string)", "func() string"},
+	dup("func() (u int)"),
+	{"func() (u, v int, w string)", "func() (u int, v int, w string)"},
+
+	dup("func(int) string"),
+	dup("func(x int) string"),
+	dup("func(x int) (u string)"),
+	{"func(x, y int) (u string)", "func(x int, y int) (u string)"},
+
+	dup("func(...int) string"),
+	dup("func(x ...int) string"),
+	dup("func(x ...int) (u string)"),
+	{"func(x, y ...int) (u string)", "func(x int, y ...int) (u string)"},
+
+	// interfaces
+	dup("interface{}"),
+	dup("interface{m()}"),
+	dup(`interface{String() string; m(int) float32}`),
+
+	// maps
+	dup("map[string]int"),
+	{"map[struct{x, y int}][]byte", "map[struct{x int; y int}][]byte"},
+
+	// channels
+	dup("chan<- chan int"),
+	dup("chan<- <-chan int"),
+	dup("<-chan <-chan int"),
+	dup("chan (<-chan int)"),
+	dup("chan<- func()"),
+	dup("<-chan []func() int"),
+}
+
+// types that depend on other type declarations (src in TestTypes)
+var dependentTestTypes = []testEntry{
+	// interfaces
+	dup(`interface{io.Reader; io.Writer}`),
+	dup(`interface{m() int; io.Writer}`),
+	{`interface{m() interface{T}}`, `interface{m() interface{p.T}}`},
+}
+
+func TestTypeString(t *testing.T) {
+	testenv.MustHaveGoBuild(t)
+
+	var tests []testEntry
+	tests = append(tests, independentTestTypes...)
+	tests = append(tests, dependentTestTypes...)
+
+	for _, test := range tests {
+		src := `package p; import "io"; type _ io.Writer; type T ` + test.src
+		pkg, err := makePkg(t, src)
+		if err != nil {
+			t.Errorf("%s: %s", src, err)
+			continue
+		}
+		typ := pkg.Scope().Lookup("T").Type().Underlying()
+		if got := typ.String(); got != test.str {
+			t.Errorf("%s: got %s, want %s", test.src, got, test.str)
+		}
+	}
+}
+
+func TestQualifiedTypeString(t *testing.T) {
+	p, _ := pkgFor("p.go", "package p; type T int", nil)
+	q, _ := pkgFor("q.go", "package q", nil)
+
+	pT := p.Scope().Lookup("T").Type()
+	for _, test := range []struct {
+		typ  Type
+		this *Package
+		want string
+	}{
+		{pT, nil, "p.T"},
+		{pT, p, "T"},
+		{pT, q, "p.T"},
+		{NewPointer(pT), p, "*T"},
+		{NewPointer(pT), q, "*p.T"},
+	} {
+		qualifier := func(pkg *Package) string {
+			if pkg != test.this {
+				return pkg.Name()
+			}
+			return ""
+		}
+		if got := TypeString(test.typ, qualifier); got != test.want {
+			t.Errorf("TypeString(%s, %s) = %s, want %s",
+				test.this, test.typ, got, test.want)
+		}
+	}
+}
diff --git a/src/go/types/typexpr.go b/src/go/types/typexpr.go
new file mode 100644
index 0000000..c744eea
--- /dev/null
+++ b/src/go/types/typexpr.go
@@ -0,0 +1,712 @@
+// 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.
+
+// This file implements type-checking of identifiers and type expressions.
+
+package types
+
+import (
+	"go/ast"
+	"go/constant"
+	"go/token"
+	"sort"
+	"strconv"
+)
+
+// ident type-checks identifier e and initializes x with the value or type of e.
+// If an error occurred, x.mode is set to invalid.
+// For the meaning of def and path, see check.typ, below.
+//
+func (check *Checker) ident(x *operand, e *ast.Ident, def *Named, path []*TypeName) {
+	x.mode = invalid
+	x.expr = e
+
+	scope, obj := check.scope.LookupParent(e.Name, check.pos)
+	if obj == nil {
+		if e.Name == "_" {
+			check.errorf(e.Pos(), "cannot use _ as value or type")
+		} else {
+			check.errorf(e.Pos(), "undeclared name: %s", e.Name)
+		}
+		return
+	}
+	check.recordUse(e, obj)
+
+	check.objDecl(obj, def, path)
+	typ := obj.Type()
+	assert(typ != nil)
+
+	// The object may be dot-imported: If so, remove its package from
+	// the map of unused dot imports for the respective file scope.
+	// (This code is only needed for dot-imports. Without them,
+	// we only have to mark variables, see *Var case below).
+	if pkg := obj.Pkg(); pkg != check.pkg && pkg != nil {
+		delete(check.unusedDotImports[scope], pkg)
+	}
+
+	switch obj := obj.(type) {
+	case *PkgName:
+		check.errorf(e.Pos(), "use of package %s not in selector", obj.name)
+		return
+
+	case *Const:
+		check.addDeclDep(obj)
+		if typ == Typ[Invalid] {
+			return
+		}
+		if obj == universeIota {
+			if check.iota == nil {
+				check.errorf(e.Pos(), "cannot use iota outside constant declaration")
+				return
+			}
+			x.val = check.iota
+		} else {
+			x.val = obj.val
+		}
+		assert(x.val != nil)
+		x.mode = constant_
+
+	case *TypeName:
+		x.mode = typexpr
+		// check for cycle
+		// (it's ok to iterate forward because each named type appears at most once in path)
+		for i, prev := range path {
+			if prev == obj {
+				check.errorf(obj.pos, "illegal cycle in declaration of %s", obj.name)
+				// print cycle
+				for _, obj := range path[i:] {
+					check.errorf(obj.Pos(), "\t%s refers to", obj.Name()) // secondary error, \t indented
+				}
+				check.errorf(obj.Pos(), "\t%s", obj.Name())
+				// maintain x.mode == typexpr despite error
+				typ = Typ[Invalid]
+				break
+			}
+		}
+
+	case *Var:
+		if obj.pkg == check.pkg {
+			obj.used = true
+		}
+		check.addDeclDep(obj)
+		if typ == Typ[Invalid] {
+			return
+		}
+		x.mode = variable
+
+	case *Func:
+		check.addDeclDep(obj)
+		x.mode = value
+
+	case *Builtin:
+		x.id = obj.id
+		x.mode = builtin
+
+	case *Nil:
+		x.mode = value
+
+	default:
+		unreachable()
+	}
+
+	x.typ = typ
+}
+
+// typExpr type-checks the type expression e and returns its type, or Typ[Invalid].
+// If def != nil, e is the type specification for the named type def, declared
+// in a type declaration, and def.underlying will be set to the type of e before
+// any components of e are type-checked. Path contains the path of named types
+// referring to this type.
+//
+func (check *Checker) typExpr(e ast.Expr, def *Named, path []*TypeName) (T Type) {
+	if trace {
+		check.trace(e.Pos(), "%s", e)
+		check.indent++
+		defer func() {
+			check.indent--
+			check.trace(e.Pos(), "=> %s", T)
+		}()
+	}
+
+	T = check.typExprInternal(e, def, path)
+	assert(isTyped(T))
+	check.recordTypeAndValue(e, typexpr, T, nil)
+
+	return
+}
+
+func (check *Checker) typ(e ast.Expr) Type {
+	return check.typExpr(e, nil, nil)
+}
+
+// funcType type-checks a function or method type.
+func (check *Checker) funcType(sig *Signature, recvPar *ast.FieldList, ftyp *ast.FuncType) {
+	scope := NewScope(check.scope, token.NoPos, token.NoPos, "function")
+	check.recordScope(ftyp, scope)
+
+	recvList, _ := check.collectParams(scope, recvPar, false)
+	params, variadic := check.collectParams(scope, ftyp.Params, true)
+	results, _ := check.collectParams(scope, ftyp.Results, false)
+
+	if recvPar != nil {
+		// recv parameter list present (may be empty)
+		// spec: "The receiver is specified via an extra parameter section preceding the
+		// method name. That parameter section must declare a single parameter, the receiver."
+		var recv *Var
+		switch len(recvList) {
+		case 0:
+			check.error(recvPar.Pos(), "method is missing receiver")
+			recv = NewParam(0, nil, "", Typ[Invalid]) // ignore recv below
+		default:
+			// more than one receiver
+			check.error(recvList[len(recvList)-1].Pos(), "method must have exactly one receiver")
+			fallthrough // continue with first receiver
+		case 1:
+			recv = recvList[0]
+		}
+		// spec: "The receiver type must be of the form T or *T where T is a type name."
+		// (ignore invalid types - error was reported before)
+		if t, _ := deref(recv.typ); t != Typ[Invalid] {
+			var err string
+			if T, _ := t.(*Named); T != nil {
+				// spec: "The type denoted by T is called the receiver base type; it must not
+				// be a pointer or interface type and it must be declared in the same package
+				// as the method."
+				if T.obj.pkg != check.pkg {
+					err = "type not defined in this package"
+				} else {
+					// TODO(gri) This is not correct if the underlying type is unknown yet.
+					switch u := T.underlying.(type) {
+					case *Basic:
+						// unsafe.Pointer is treated like a regular pointer
+						if u.kind == UnsafePointer {
+							err = "unsafe.Pointer"
+						}
+					case *Pointer, *Interface:
+						err = "pointer or interface type"
+					}
+				}
+			} else {
+				err = "basic or unnamed type"
+			}
+			if err != "" {
+				check.errorf(recv.pos, "invalid receiver %s (%s)", recv.typ, err)
+				// ok to continue
+			}
+		}
+		sig.recv = recv
+	}
+
+	sig.scope = scope
+	sig.params = NewTuple(params...)
+	sig.results = NewTuple(results...)
+	sig.variadic = variadic
+}
+
+// typExprInternal drives type checking of types.
+// Must only be called by typExpr.
+//
+func (check *Checker) typExprInternal(e ast.Expr, def *Named, path []*TypeName) Type {
+	switch e := e.(type) {
+	case *ast.BadExpr:
+		// ignore - error reported before
+
+	case *ast.Ident:
+		var x operand
+		check.ident(&x, e, def, path)
+
+		switch x.mode {
+		case typexpr:
+			typ := x.typ
+			def.setUnderlying(typ)
+			return typ
+		case invalid:
+			// ignore - error reported before
+		case novalue:
+			check.errorf(x.pos(), "%s used as type", &x)
+		default:
+			check.errorf(x.pos(), "%s is not a type", &x)
+		}
+
+	case *ast.SelectorExpr:
+		var x operand
+		check.selector(&x, e)
+
+		switch x.mode {
+		case typexpr:
+			typ := x.typ
+			def.setUnderlying(typ)
+			return typ
+		case invalid:
+			// ignore - error reported before
+		case novalue:
+			check.errorf(x.pos(), "%s used as type", &x)
+		default:
+			check.errorf(x.pos(), "%s is not a type", &x)
+		}
+
+	case *ast.ParenExpr:
+		return check.typExpr(e.X, def, path)
+
+	case *ast.ArrayType:
+		if e.Len != nil {
+			typ := new(Array)
+			def.setUnderlying(typ)
+			typ.len = check.arrayLength(e.Len)
+			typ.elem = check.typExpr(e.Elt, nil, path)
+			return typ
+
+		} else {
+			typ := new(Slice)
+			def.setUnderlying(typ)
+			typ.elem = check.typ(e.Elt)
+			return typ
+		}
+
+	case *ast.StructType:
+		typ := new(Struct)
+		def.setUnderlying(typ)
+		check.structType(typ, e, path)
+		return typ
+
+	case *ast.StarExpr:
+		typ := new(Pointer)
+		def.setUnderlying(typ)
+		typ.base = check.typ(e.X)
+		return typ
+
+	case *ast.FuncType:
+		typ := new(Signature)
+		def.setUnderlying(typ)
+		check.funcType(typ, nil, e)
+		return typ
+
+	case *ast.InterfaceType:
+		typ := new(Interface)
+		def.setUnderlying(typ)
+		check.interfaceType(typ, e, def, path)
+		return typ
+
+	case *ast.MapType:
+		typ := new(Map)
+		def.setUnderlying(typ)
+
+		typ.key = check.typ(e.Key)
+		typ.elem = check.typ(e.Value)
+
+		// spec: "The comparison operators == and != must be fully defined
+		// for operands of the key type; thus the key type must not be a
+		// function, map, or slice."
+		//
+		// Delay this check because it requires fully setup types;
+		// it is safe to continue in any case (was issue 6667).
+		check.delay(func() {
+			if !Comparable(typ.key) {
+				check.errorf(e.Key.Pos(), "invalid map key type %s", typ.key)
+			}
+		})
+
+		return typ
+
+	case *ast.ChanType:
+		typ := new(Chan)
+		def.setUnderlying(typ)
+
+		dir := SendRecv
+		switch e.Dir {
+		case ast.SEND | ast.RECV:
+			// nothing to do
+		case ast.SEND:
+			dir = SendOnly
+		case ast.RECV:
+			dir = RecvOnly
+		default:
+			check.invalidAST(e.Pos(), "unknown channel direction %d", e.Dir)
+			// ok to continue
+		}
+
+		typ.dir = dir
+		typ.elem = check.typ(e.Value)
+		return typ
+
+	default:
+		check.errorf(e.Pos(), "%s is not a type", e)
+	}
+
+	typ := Typ[Invalid]
+	def.setUnderlying(typ)
+	return typ
+}
+
+// typeOrNil type-checks the type expression (or nil value) e
+// and returns the typ of e, or nil.
+// If e is neither a type nor nil, typOrNil returns Typ[Invalid].
+//
+func (check *Checker) typOrNil(e ast.Expr) Type {
+	var x operand
+	check.rawExpr(&x, e, nil)
+	switch x.mode {
+	case invalid:
+		// ignore - error reported before
+	case novalue:
+		check.errorf(x.pos(), "%s used as type", &x)
+	case typexpr:
+		return x.typ
+	case value:
+		if x.isNil() {
+			return nil
+		}
+		fallthrough
+	default:
+		check.errorf(x.pos(), "%s is not a type", &x)
+	}
+	return Typ[Invalid]
+}
+
+func (check *Checker) arrayLength(e ast.Expr) int64 {
+	var x operand
+	check.expr(&x, e)
+	if x.mode != constant_ {
+		if x.mode != invalid {
+			check.errorf(x.pos(), "array length %s must be constant", &x)
+		}
+		return 0
+	}
+	if !x.isInteger() {
+		check.errorf(x.pos(), "array length %s must be integer", &x)
+		return 0
+	}
+	n, ok := constant.Int64Val(x.val)
+	if !ok || n < 0 {
+		check.errorf(x.pos(), "invalid array length %s", &x)
+		return 0
+	}
+	return n
+}
+
+func (check *Checker) collectParams(scope *Scope, list *ast.FieldList, variadicOk bool) (params []*Var, variadic bool) {
+	if list == nil {
+		return
+	}
+
+	var named, anonymous bool
+	for i, field := range list.List {
+		ftype := field.Type
+		if t, _ := ftype.(*ast.Ellipsis); t != nil {
+			ftype = t.Elt
+			if variadicOk && i == len(list.List)-1 {
+				variadic = true
+			} else {
+				check.invalidAST(field.Pos(), "... not permitted")
+				// ignore ... and continue
+			}
+		}
+		typ := check.typ(ftype)
+		// The parser ensures that f.Tag is nil and we don't
+		// care if a constructed AST contains a non-nil tag.
+		if len(field.Names) > 0 {
+			// named parameter
+			for _, name := range field.Names {
+				if name.Name == "" {
+					check.invalidAST(name.Pos(), "anonymous parameter")
+					// ok to continue
+				}
+				par := NewParam(name.Pos(), check.pkg, name.Name, typ)
+				check.declare(scope, name, par, scope.pos)
+				params = append(params, par)
+			}
+			named = true
+		} else {
+			// anonymous parameter
+			par := NewParam(ftype.Pos(), check.pkg, "", typ)
+			check.recordImplicit(field, par)
+			params = append(params, par)
+			anonymous = true
+		}
+	}
+
+	if named && anonymous {
+		check.invalidAST(list.Pos(), "list contains both named and anonymous parameters")
+		// ok to continue
+	}
+
+	// For a variadic function, change the last parameter's type from T to []T.
+	if variadic && len(params) > 0 {
+		last := params[len(params)-1]
+		last.typ = &Slice{elem: last.typ}
+	}
+
+	return
+}
+
+func (check *Checker) declareInSet(oset *objset, pos token.Pos, obj Object) bool {
+	if alt := oset.insert(obj); alt != nil {
+		check.errorf(pos, "%s redeclared", obj.Name())
+		check.reportAltDecl(alt)
+		return false
+	}
+	return true
+}
+
+func (check *Checker) interfaceType(iface *Interface, ityp *ast.InterfaceType, def *Named, path []*TypeName) {
+	// empty interface: common case
+	if ityp.Methods == nil {
+		return
+	}
+
+	// The parser ensures that field tags are nil and we don't
+	// care if a constructed AST contains non-nil tags.
+
+	// use named receiver type if available (for better error messages)
+	var recvTyp Type = iface
+	if def != nil {
+		recvTyp = def
+	}
+
+	// Phase 1: Collect explicitly declared methods, the corresponding
+	//          signature (AST) expressions, and the list of embedded
+	//          type (AST) expressions. Do not resolve signatures or
+	//          embedded types yet to avoid cycles referring to this
+	//          interface.
+
+	var (
+		mset       objset
+		signatures []ast.Expr // list of corresponding method signatures
+		embedded   []ast.Expr // list of embedded types
+	)
+	for _, f := range ityp.Methods.List {
+		if len(f.Names) > 0 {
+			// The parser ensures that there's only one method
+			// and we don't care if a constructed AST has more.
+			name := f.Names[0]
+			pos := name.Pos()
+			// spec: "As with all method sets, in an interface type,
+			// each method must have a unique non-blank name."
+			if name.Name == "_" {
+				check.errorf(pos, "invalid method name _")
+				continue
+			}
+			// Don't type-check signature yet - use an
+			// empty signature now and update it later.
+			// Since we know the receiver, set it up now
+			// (required to avoid crash in ptrRecv; see
+			// e.g. test case for issue 6638).
+			// TODO(gri) Consider marking methods signatures
+			// as incomplete, for better error messages. See
+			// also the T4 and T5 tests in testdata/cycles2.src.
+			sig := new(Signature)
+			sig.recv = NewVar(pos, check.pkg, "", recvTyp)
+			m := NewFunc(pos, check.pkg, name.Name, sig)
+			if check.declareInSet(&mset, pos, m) {
+				iface.methods = append(iface.methods, m)
+				iface.allMethods = append(iface.allMethods, m)
+				signatures = append(signatures, f.Type)
+				check.recordDef(name, m)
+			}
+		} else {
+			// embedded type
+			embedded = append(embedded, f.Type)
+		}
+	}
+
+	// Phase 2: Resolve embedded interfaces. Because an interface must not
+	//          embed itself (directly or indirectly), each embedded interface
+	//          can be fully resolved without depending on any method of this
+	//          interface (if there is a cycle or another error, the embedded
+	//          type resolves to an invalid type and is ignored).
+	//          In particular, the list of methods for each embedded interface
+	//          must be complete (it cannot depend on this interface), and so
+	//          those methods can be added to the list of all methods of this
+	//          interface.
+
+	for _, e := range embedded {
+		pos := e.Pos()
+		typ := check.typExpr(e, nil, path)
+		// Determine underlying embedded (possibly incomplete) type
+		// by following its forward chain.
+		named, _ := typ.(*Named)
+		under := underlying(named)
+		embed, _ := under.(*Interface)
+		if embed == nil {
+			if typ != Typ[Invalid] {
+				check.errorf(pos, "%s is not an interface", typ)
+			}
+			continue
+		}
+		iface.embeddeds = append(iface.embeddeds, named)
+		// collect embedded methods
+		for _, m := range embed.allMethods {
+			if check.declareInSet(&mset, pos, m) {
+				iface.allMethods = append(iface.allMethods, m)
+			}
+		}
+	}
+
+	// Phase 3: At this point all methods have been collected for this interface.
+	//          It is now safe to type-check the signatures of all explicitly
+	//          declared methods, even if they refer to this interface via a cycle
+	//          and embed the methods of this interface in a parameter of interface
+	//          type.
+
+	for i, m := range iface.methods {
+		expr := signatures[i]
+		typ := check.typ(expr)
+		sig, _ := typ.(*Signature)
+		if sig == nil {
+			if typ != Typ[Invalid] {
+				check.invalidAST(expr.Pos(), "%s is not a method signature", typ)
+			}
+			continue // keep method with empty method signature
+		}
+		// update signature, but keep recv that was set up before
+		old := m.typ.(*Signature)
+		sig.recv = old.recv
+		*old = *sig // update signature (don't replace it!)
+	}
+
+	// TODO(gri) The list of explicit methods is only sorted for now to
+	// produce the same Interface as NewInterface. We may be able to
+	// claim source order in the future. Revisit.
+	sort.Sort(byUniqueMethodName(iface.methods))
+
+	// TODO(gri) The list of embedded types is only sorted for now to
+	// produce the same Interface as NewInterface. We may be able to
+	// claim source order in the future. Revisit.
+	sort.Sort(byUniqueTypeName(iface.embeddeds))
+
+	sort.Sort(byUniqueMethodName(iface.allMethods))
+}
+
+// byUniqueTypeName named type lists can be sorted by their unique type names.
+type byUniqueTypeName []*Named
+
+func (a byUniqueTypeName) Len() int           { return len(a) }
+func (a byUniqueTypeName) Less(i, j int) bool { return a[i].obj.Id() < a[j].obj.Id() }
+func (a byUniqueTypeName) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
+
+// byUniqueMethodName method lists can be sorted by their unique method names.
+type byUniqueMethodName []*Func
+
+func (a byUniqueMethodName) Len() int           { return len(a) }
+func (a byUniqueMethodName) Less(i, j int) bool { return a[i].Id() < a[j].Id() }
+func (a byUniqueMethodName) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
+
+func (check *Checker) tag(t *ast.BasicLit) string {
+	if t != nil {
+		if t.Kind == token.STRING {
+			if val, err := strconv.Unquote(t.Value); err == nil {
+				return val
+			}
+		}
+		check.invalidAST(t.Pos(), "incorrect tag syntax: %q", t.Value)
+	}
+	return ""
+}
+
+func (check *Checker) structType(styp *Struct, e *ast.StructType, path []*TypeName) {
+	list := e.Fields
+	if list == nil {
+		return
+	}
+
+	// struct fields and tags
+	var fields []*Var
+	var tags []string
+
+	// for double-declaration checks
+	var fset objset
+
+	// current field typ and tag
+	var typ Type
+	var tag string
+	// anonymous != nil indicates an anonymous field.
+	add := func(field *ast.Field, ident *ast.Ident, anonymous *TypeName, pos token.Pos) {
+		if tag != "" && tags == nil {
+			tags = make([]string, len(fields))
+		}
+		if tags != nil {
+			tags = append(tags, tag)
+		}
+
+		name := ident.Name
+		fld := NewField(pos, check.pkg, name, typ, anonymous != nil)
+		// spec: "Within a struct, non-blank field names must be unique."
+		if name == "_" || check.declareInSet(&fset, pos, fld) {
+			fields = append(fields, fld)
+			check.recordDef(ident, fld)
+		}
+		if anonymous != nil {
+			check.recordUse(ident, anonymous)
+		}
+	}
+
+	for _, f := range list.List {
+		typ = check.typExpr(f.Type, nil, path)
+		tag = check.tag(f.Tag)
+		if len(f.Names) > 0 {
+			// named fields
+			for _, name := range f.Names {
+				add(f, name, nil, name.Pos())
+			}
+		} else {
+			// anonymous field
+			name := anonymousFieldIdent(f.Type)
+			pos := f.Type.Pos()
+			t, isPtr := deref(typ)
+			switch t := t.(type) {
+			case *Basic:
+				if t == Typ[Invalid] {
+					// error was reported before
+					continue
+				}
+				// unsafe.Pointer is treated like a regular pointer
+				if t.kind == UnsafePointer {
+					check.errorf(pos, "anonymous field type cannot be unsafe.Pointer")
+					continue
+				}
+				add(f, name, Universe.Lookup(t.name).(*TypeName), pos)
+
+			case *Named:
+				// spec: "An embedded type must be specified as a type name
+				// T or as a pointer to a non-interface type name *T, and T
+				// itself may not be a pointer type."
+				switch u := t.underlying.(type) {
+				case *Basic:
+					// unsafe.Pointer is treated like a regular pointer
+					if u.kind == UnsafePointer {
+						check.errorf(pos, "anonymous field type cannot be unsafe.Pointer")
+						continue
+					}
+				case *Pointer:
+					check.errorf(pos, "anonymous field type cannot be a pointer")
+					continue
+				case *Interface:
+					if isPtr {
+						check.errorf(pos, "anonymous field type cannot be a pointer to an interface")
+						continue
+					}
+				}
+				add(f, name, t.obj, pos)
+
+			default:
+				check.invalidAST(pos, "anonymous field type %s must be named", typ)
+			}
+		}
+	}
+
+	styp.fields = fields
+	styp.tags = tags
+}
+
+func anonymousFieldIdent(e ast.Expr) *ast.Ident {
+	switch e := e.(type) {
+	case *ast.Ident:
+		return e
+	case *ast.StarExpr:
+		return anonymousFieldIdent(e.X)
+	case *ast.SelectorExpr:
+		return e.Sel
+	}
+	return nil // invalid anonymous field
+}
diff --git a/src/go/types/universe.go b/src/go/types/universe.go
new file mode 100644
index 0000000..40185c1
--- /dev/null
+++ b/src/go/types/universe.go
@@ -0,0 +1,223 @@
+// 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.
+
+// This file sets up the universe scope and the unsafe package.
+
+package types
+
+import (
+	"go/constant"
+	"go/token"
+	"strings"
+)
+
+var (
+	Universe     *Scope
+	Unsafe       *Package
+	universeIota *Const
+	universeByte *Basic // uint8 alias, but has name "byte"
+	universeRune *Basic // int32 alias, but has name "rune"
+)
+
+var Typ = []*Basic{
+	Invalid: {Invalid, 0, "invalid type"},
+
+	Bool:          {Bool, IsBoolean, "bool"},
+	Int:           {Int, IsInteger, "int"},
+	Int8:          {Int8, IsInteger, "int8"},
+	Int16:         {Int16, IsInteger, "int16"},
+	Int32:         {Int32, IsInteger, "int32"},
+	Int64:         {Int64, IsInteger, "int64"},
+	Uint:          {Uint, IsInteger | IsUnsigned, "uint"},
+	Uint8:         {Uint8, IsInteger | IsUnsigned, "uint8"},
+	Uint16:        {Uint16, IsInteger | IsUnsigned, "uint16"},
+	Uint32:        {Uint32, IsInteger | IsUnsigned, "uint32"},
+	Uint64:        {Uint64, IsInteger | IsUnsigned, "uint64"},
+	Uintptr:       {Uintptr, IsInteger | IsUnsigned, "uintptr"},
+	Float32:       {Float32, IsFloat, "float32"},
+	Float64:       {Float64, IsFloat, "float64"},
+	Complex64:     {Complex64, IsComplex, "complex64"},
+	Complex128:    {Complex128, IsComplex, "complex128"},
+	String:        {String, IsString, "string"},
+	UnsafePointer: {UnsafePointer, 0, "Pointer"},
+
+	UntypedBool:    {UntypedBool, IsBoolean | IsUntyped, "untyped bool"},
+	UntypedInt:     {UntypedInt, IsInteger | IsUntyped, "untyped int"},
+	UntypedRune:    {UntypedRune, IsInteger | IsUntyped, "untyped rune"},
+	UntypedFloat:   {UntypedFloat, IsFloat | IsUntyped, "untyped float"},
+	UntypedComplex: {UntypedComplex, IsComplex | IsUntyped, "untyped complex"},
+	UntypedString:  {UntypedString, IsString | IsUntyped, "untyped string"},
+	UntypedNil:     {UntypedNil, IsUntyped, "untyped nil"},
+}
+
+var aliases = [...]*Basic{
+	{Byte, IsInteger | IsUnsigned, "byte"},
+	{Rune, IsInteger, "rune"},
+}
+
+func defPredeclaredTypes() {
+	for _, t := range Typ {
+		def(NewTypeName(token.NoPos, nil, t.name, t))
+	}
+	for _, t := range aliases {
+		def(NewTypeName(token.NoPos, nil, t.name, t))
+	}
+
+	// Error has a nil package in its qualified name since it is in no package
+	res := NewVar(token.NoPos, nil, "", Typ[String])
+	sig := &Signature{results: NewTuple(res)}
+	err := NewFunc(token.NoPos, nil, "Error", sig)
+	typ := &Named{underlying: NewInterface([]*Func{err}, nil).Complete()}
+	sig.recv = NewVar(token.NoPos, nil, "", typ)
+	def(NewTypeName(token.NoPos, nil, "error", typ))
+}
+
+var predeclaredConsts = [...]struct {
+	name string
+	kind BasicKind
+	val  constant.Value
+}{
+	{"true", UntypedBool, constant.MakeBool(true)},
+	{"false", UntypedBool, constant.MakeBool(false)},
+	{"iota", UntypedInt, constant.MakeInt64(0)},
+}
+
+func defPredeclaredConsts() {
+	for _, c := range predeclaredConsts {
+		def(NewConst(token.NoPos, nil, c.name, Typ[c.kind], c.val))
+	}
+}
+
+func defPredeclaredNil() {
+	def(&Nil{object{name: "nil", typ: Typ[UntypedNil]}})
+}
+
+// A builtinId is the id of a builtin function.
+type builtinId int
+
+const (
+	// universe scope
+	_Append builtinId = iota
+	_Cap
+	_Close
+	_Complex
+	_Copy
+	_Delete
+	_Imag
+	_Len
+	_Make
+	_New
+	_Panic
+	_Print
+	_Println
+	_Real
+	_Recover
+
+	// package unsafe
+	_Alignof
+	_Offsetof
+	_Sizeof
+
+	// testing support
+	_Assert
+	_Trace
+)
+
+var predeclaredFuncs = [...]struct {
+	name     string
+	nargs    int
+	variadic bool
+	kind     exprKind
+}{
+	_Append:  {"append", 1, true, expression},
+	_Cap:     {"cap", 1, false, expression},
+	_Close:   {"close", 1, false, statement},
+	_Complex: {"complex", 2, false, expression},
+	_Copy:    {"copy", 2, false, statement},
+	_Delete:  {"delete", 2, false, statement},
+	_Imag:    {"imag", 1, false, expression},
+	_Len:     {"len", 1, false, expression},
+	_Make:    {"make", 1, true, expression},
+	_New:     {"new", 1, false, expression},
+	_Panic:   {"panic", 1, false, statement},
+	_Print:   {"print", 0, true, statement},
+	_Println: {"println", 0, true, statement},
+	_Real:    {"real", 1, false, expression},
+	_Recover: {"recover", 0, false, statement},
+
+	_Alignof:  {"Alignof", 1, false, expression},
+	_Offsetof: {"Offsetof", 1, false, expression},
+	_Sizeof:   {"Sizeof", 1, false, expression},
+
+	_Assert: {"assert", 1, false, statement},
+	_Trace:  {"trace", 0, true, statement},
+}
+
+func defPredeclaredFuncs() {
+	for i := range predeclaredFuncs {
+		id := builtinId(i)
+		if id == _Assert || id == _Trace {
+			continue // only define these in testing environment
+		}
+		def(newBuiltin(id))
+	}
+}
+
+// DefPredeclaredTestFuncs defines the assert and trace built-ins.
+// These built-ins are intended for debugging and testing of this
+// package only.
+func DefPredeclaredTestFuncs() {
+	if Universe.Lookup("assert") != nil {
+		return // already defined
+	}
+	def(newBuiltin(_Assert))
+	def(newBuiltin(_Trace))
+}
+
+func init() {
+	Universe = NewScope(nil, token.NoPos, token.NoPos, "universe")
+	Unsafe = NewPackage("unsafe", "unsafe")
+	Unsafe.complete = true
+
+	defPredeclaredTypes()
+	defPredeclaredConsts()
+	defPredeclaredNil()
+	defPredeclaredFuncs()
+
+	universeIota = Universe.Lookup("iota").(*Const)
+	universeByte = Universe.Lookup("byte").(*TypeName).typ.(*Basic)
+	universeRune = Universe.Lookup("rune").(*TypeName).typ.(*Basic)
+}
+
+// Objects with names containing blanks are internal and not entered into
+// a scope. Objects with exported names are inserted in the unsafe package
+// scope; other objects are inserted in the universe scope.
+//
+func def(obj Object) {
+	name := obj.Name()
+	if strings.Index(name, " ") >= 0 {
+		return // nothing to do
+	}
+	// fix Obj link for named types
+	if typ, ok := obj.Type().(*Named); ok {
+		typ.obj = obj.(*TypeName)
+	}
+	// exported identifiers go into package unsafe
+	scope := Universe
+	if obj.Exported() {
+		scope = Unsafe.scope
+		// set Pkg field
+		switch obj := obj.(type) {
+		case *TypeName:
+			obj.pkg = Unsafe
+		case *Builtin:
+			obj.pkg = Unsafe
+		default:
+			unreachable()
+		}
+	}
+	if scope.Insert(obj) != nil {
+		panic("internal error: double declaration")
+	}
+}
diff --git a/src/hash/crc32/crc32.go b/src/hash/crc32/crc32.go
index 6a6b947..234d929 100644
--- a/src/hash/crc32/crc32.go
+++ b/src/hash/crc32/crc32.go
@@ -5,6 +5,11 @@
 // Package crc32 implements the 32-bit cyclic redundancy check, or CRC-32,
 // checksum. See http://en.wikipedia.org/wiki/Cyclic_redundancy_check for
 // information.
+//
+// Polynomials are represented in LSB-first form also known as reversed representation.
+//
+// See http://en.wikipedia.org/wiki/Mathematics_of_cyclic_redundancy_checks#Reversed_representations_and_reciprocal_polynomials
+// for information.
 package crc32
 
 import (
@@ -49,6 +54,13 @@ func castagnoliInit() {
 // IEEETable is the table for the IEEE polynomial.
 var IEEETable = makeTable(IEEE)
 
+// slicing8Table is array of 8 Tables
+type slicing8Table [8]Table
+
+// iEEETable8 is the slicing8Table for IEEE
+var iEEETable8 *slicing8Table
+var iEEETable8Once sync.Once
+
 // MakeTable returns the Table constructed from the specified polynomial.
 func MakeTable(poly uint32) *Table {
 	switch poly {
@@ -78,6 +90,20 @@ func makeTable(poly uint32) *Table {
 	return t
 }
 
+// makeTable8 returns slicing8Table constructed from the specified polynomial.
+func makeTable8(poly uint32) *slicing8Table {
+	t := new(slicing8Table)
+	t[0] = *makeTable(poly)
+	for i := 0; i < 256; i++ {
+		crc := t[0][i]
+		for j := 1; j < 8; j++ {
+			crc = t[0][crc&0xFF] ^ (crc >> 8)
+			t[j][i] = crc
+		}
+	}
+	return t
+}
+
 // digest represents the partial evaluation of a checksum.
 type digest struct {
 	crc uint32
@@ -106,11 +132,32 @@ func update(crc uint32, tab *Table, p []byte) uint32 {
 	return ^crc
 }
 
+// updateSlicingBy8 updates CRC using Slicing-by-8
+func updateSlicingBy8(crc uint32, tab *slicing8Table, p []byte) uint32 {
+	crc = ^crc
+	for len(p) > 8 {
+		crc ^= uint32(p[0]) | uint32(p[1])<<8 | uint32(p[2])<<16 | uint32(p[3])<<24
+		crc = tab[0][p[7]] ^ tab[1][p[6]] ^ tab[2][p[5]] ^ tab[3][p[4]] ^
+			tab[4][crc>>24] ^ tab[5][(crc>>16)&0xFF] ^
+			tab[6][(crc>>8)&0xFF] ^ tab[7][crc&0xFF]
+		p = p[8:]
+	}
+	crc = ^crc
+	return update(crc, &tab[0], p)
+}
+
 // Update returns the result of adding the bytes in p to the crc.
 func Update(crc uint32, tab *Table, p []byte) uint32 {
 	if tab == castagnoliTable {
 		return updateCastagnoli(crc, p)
 	}
+	// only use slicing-by-8 when input is larger than 4KB
+	if tab == IEEETable && len(p) >= 4096 {
+		iEEETable8Once.Do(func() {
+			iEEETable8 = makeTable8(IEEE)
+		})
+		return updateSlicingBy8(crc, iEEETable8, p)
+	}
 	return update(crc, tab, p)
 }
 
@@ -132,4 +179,4 @@ func Checksum(data []byte, tab *Table) uint32 { return Update(0, tab, data) }
 
 // ChecksumIEEE returns the CRC-32 checksum of data
 // using the IEEE polynomial.
-func ChecksumIEEE(data []byte) uint32 { return update(0, IEEETable, data) }
+func ChecksumIEEE(data []byte) uint32 { return Update(0, IEEETable, data) }
diff --git a/src/hash/crc32/crc32_generic.go b/src/hash/crc32/crc32_generic.go
index c3fdcd6..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
+// +build 386 arm arm64 ppc64 ppc64le
 
 package crc32
 
diff --git a/src/hash/crc32/crc32_test.go b/src/hash/crc32/crc32_test.go
index 75dc26e..1ca3ac2 100644
--- a/src/hash/crc32/crc32_test.go
+++ b/src/hash/crc32/crc32_test.go
@@ -81,7 +81,7 @@ func TestGolden(t *testing.T) {
 	}
 }
 
-func BenchmarkCrc32KB(b *testing.B) {
+func BenchmarkIEEECrc1KB(b *testing.B) {
 	b.SetBytes(1024)
 	data := make([]byte, 1024)
 	for i := range data {
@@ -97,3 +97,37 @@ func BenchmarkCrc32KB(b *testing.B) {
 		h.Sum(in)
 	}
 }
+
+func BenchmarkIEEECrc4KB(b *testing.B) {
+	b.SetBytes(4096)
+	data := make([]byte, 4096)
+	for i := range data {
+		data[i] = byte(i)
+	}
+	h := NewIEEE()
+	in := make([]byte, 0, h.Size())
+
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		h.Reset()
+		h.Write(data)
+		h.Sum(in)
+	}
+}
+
+func BenchmarkCastagnoliCrc1KB(b *testing.B) {
+	b.SetBytes(1024)
+	data := make([]byte, 1024)
+	for i := range data {
+		data[i] = byte(i)
+	}
+	h := New(MakeTable(Castagnoli))
+	in := make([]byte, 0, h.Size())
+
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		h.Reset()
+		h.Write(data)
+		h.Sum(in)
+	}
+}
diff --git a/src/hash/crc32/example_test.go b/src/hash/crc32/example_test.go
new file mode 100644
index 0000000..621bf83
--- /dev/null
+++ b/src/hash/crc32/example_test.go
@@ -0,0 +1,28 @@
+// 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 crc32_test
+
+import (
+	"fmt"
+	"hash/crc32"
+)
+
+func ExampleMakeTable() {
+	// In this package, the CRC polynomial is represented in reversed notation,
+	// or LSB-first representation.
+	//
+	// LSB-first representation is a hexadecimal number with n bits, in which the
+	// most significant bit represents the coefficient of x⁰ and the least significant
+	// bit represents the coefficient of xⁿ⁻¹ (the coefficient for xⁿ is implicit).
+	//
+	// For example, CRC32-Q, as defined by the following polynomial,
+	//	x³²+ x³¹+ x²⁴+ x²²+ x¹⁶+ x¹⁴+ x⁸+ x⁷+ x⁵+ x³+ x¹+ x⁰
+	// has the reversed notation 0b11010101100000101000001010000001, so the value
+	// that should be passed to MakeTable is 0xD5828281.
+	crc32q := crc32.MakeTable(0xD5828281)
+	fmt.Printf("%08x\n", crc32.Checksum([]byte("Hello world"), crc32q))
+	// Output:
+	// 2964d064
+}
diff --git a/src/html/escape.go b/src/html/escape.go
index dd5dfa7..f50a4b9 100644
--- a/src/html/escape.go
+++ b/src/html/escape.go
@@ -6,7 +6,6 @@
 package html
 
 import (
-	"bytes"
 	"strings"
 	"unicode/utf8"
 )
@@ -187,52 +186,20 @@ func unescape(b []byte) []byte {
 	return b
 }
 
-const escapedChars = `&'<>"`
-
-func escape(w writer, s string) error {
-	i := strings.IndexAny(s, escapedChars)
-	for i != -1 {
-		if _, err := w.WriteString(s[:i]); err != nil {
-			return err
-		}
-		var esc string
-		switch s[i] {
-		case '&':
-			esc = "&"
-		case '\'':
-			// "'" is shorter than "'" and apos was not in HTML until HTML5.
-			esc = "'"
-		case '<':
-			esc = "<"
-		case '>':
-			esc = ">"
-		case '"':
-			// """ is shorter than """.
-			esc = """
-		default:
-			panic("unrecognized escape character")
-		}
-		s = s[i+1:]
-		if _, err := w.WriteString(esc); err != nil {
-			return err
-		}
-		i = strings.IndexAny(s, escapedChars)
-	}
-	_, err := w.WriteString(s)
-	return err
-}
+var htmlEscaper = strings.NewReplacer(
+	`&`, "&",
+	`'`, "'", // "'" is shorter than "'" and apos was not in HTML until HTML5.
+	`<`, "<",
+	`>`, ">",
+	`"`, """, // """ is shorter than """.
+)
 
 // EscapeString escapes special characters like "<" to become "<". It
 // escapes only five such characters: <, >, &, ' and ".
 // UnescapeString(EscapeString(s)) == s always holds, but the converse isn't
 // always true.
 func EscapeString(s string) string {
-	if strings.IndexAny(s, escapedChars) == -1 {
-		return s
-	}
-	var buf bytes.Buffer
-	escape(&buf, s)
-	return buf.String()
+	return htmlEscaper.Replace(s)
 }
 
 // UnescapeString unescapes entities like "<" to become "<". It unescapes a
@@ -241,10 +208,8 @@ func EscapeString(s string) string {
 // UnescapeString(EscapeString(s)) == s always holds, but the converse isn't
 // always true.
 func UnescapeString(s string) string {
-	for _, c := range s {
-		if c == '&' {
-			return string(unescape([]byte(s)))
-		}
+	if !strings.Contains(s, "&") {
+		return s
 	}
-	return s
+	return string(unescape([]byte(s)))
 }
diff --git a/src/html/escape_test.go b/src/html/escape_test.go
index 2d7ad8a..3702626 100644
--- a/src/html/escape_test.go
+++ b/src/html/escape_test.go
@@ -4,7 +4,10 @@
 
 package html
 
-import "testing"
+import (
+	"strings"
+	"testing"
+)
 
 type unescapeTest struct {
 	// A short description of the test case.
@@ -113,3 +116,38 @@ func TestUnescapeEscape(t *testing.T) {
 		}
 	}
 }
+
+var (
+	benchEscapeData = strings.Repeat("AAAAA < BBBBB > CCCCC & DDDDD ' EEEEE \" ", 100)
+	benchEscapeNone = strings.Repeat("AAAAA x BBBBB x CCCCC x DDDDD x EEEEE x ", 100)
+)
+
+func BenchmarkEscape(b *testing.B) {
+	n := 0
+	for i := 0; i < b.N; i++ {
+		n += len(EscapeString(benchEscapeData))
+	}
+}
+
+func BenchmarkEscapeNone(b *testing.B) {
+	n := 0
+	for i := 0; i < b.N; i++ {
+		n += len(EscapeString(benchEscapeNone))
+	}
+}
+
+func BenchmarkUnescape(b *testing.B) {
+	s := EscapeString(benchEscapeData)
+	n := 0
+	for i := 0; i < b.N; i++ {
+		n += len(UnescapeString(s))
+	}
+}
+
+func BenchmarkUnescapeNone(b *testing.B) {
+	s := EscapeString(benchEscapeNone)
+	n := 0
+	for i := 0; i < b.N; i++ {
+		n += len(UnescapeString(s))
+	}
+}
diff --git a/src/html/example_test.go b/src/html/example_test.go
new file mode 100644
index 0000000..0e28cac
--- /dev/null
+++ b/src/html/example_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 html_test
+
+import (
+	"fmt"
+	"html"
+)
+
+func ExampleEscapeString() {
+	const s = `"Fran & Freddie's Diner" <tasty at example.com>`
+	fmt.Println(html.EscapeString(s))
+	// Output: "Fran & Freddie's Diner" <tasty at example.com>
+}
+
+func ExampleUnescapeString() {
+	const s = `"Fran & Freddie's Diner" <tasty at example.com>`
+	fmt.Println(html.UnescapeString(s))
+	// Output: "Fran & Freddie's Diner" <tasty at example.com>
+}
diff --git a/src/html/template/clone_test.go b/src/html/template/clone_test.go
index e11bff2..c89d22a 100644
--- a/src/html/template/clone_test.go
+++ b/src/html/template/clone_test.go
@@ -142,7 +142,7 @@ func TestTemplates(t *testing.T) {
 	}
 }
 
-// This used to crash; http://golang.org/issue/3281
+// This used to crash; https://golang.org/issue/3281
 func TestCloneCrash(t *testing.T) {
 	t1 := New("all")
 	Must(t1.New("t1").Parse(`{{define "foo"}}foo{{end}}`))
@@ -166,7 +166,7 @@ func TestCloneThenParse(t *testing.T) {
 	}
 }
 
-// https://code.google.com/p/go/issues/detail?id=5980
+// https://golang.org/issue/5980
 func TestFuncMapWorksAfterClone(t *testing.T) {
 	funcs := FuncMap{"customFunc": func() (string, error) {
 		return "", errors.New("issue5980")
diff --git a/src/html/template/content_test.go b/src/html/template/content_test.go
index 5f3ffe2..e698328 100644
--- a/src/html/template/content_test.go
+++ b/src/html/template/content_test.go
@@ -260,7 +260,7 @@ func TestStringer(t *testing.T) {
 	}
 }
 
-// https://code.google.com/p/go/issues/detail?id=5982
+// https://golang.org/issue/5982
 func TestEscapingNilNonemptyInterfaces(t *testing.T) {
 	tmpl := Must(New("x").Parse("{{.E}}"))
 
diff --git a/src/html/template/css.go b/src/html/template/css.go
index 634f183..3184648 100644
--- a/src/html/template/css.go
+++ b/src/html/template/css.go
@@ -157,56 +157,20 @@ func isCSSSpace(b byte) bool {
 func cssEscaper(args ...interface{}) string {
 	s, _ := stringify(args...)
 	var b bytes.Buffer
-	written := 0
-	for i, r := range s {
+	r, w, written := rune(0), 0, 0
+	for i := 0; i < len(s); i += w {
+		// See comment in htmlEscaper.
+		r, w = utf8.DecodeRuneInString(s[i:])
 		var repl string
-		switch r {
-		case 0:
-			repl = `\0`
-		case '\t':
-			repl = `\9`
-		case '\n':
-			repl = `\a`
-		case '\f':
-			repl = `\c`
-		case '\r':
-			repl = `\d`
-		// Encode HTML specials as hex so the output can be embedded
-		// in HTML attributes without further encoding.
-		case '"':
-			repl = `\22`
-		case '&':
-			repl = `\26`
-		case '\'':
-			repl = `\27`
-		case '(':
-			repl = `\28`
-		case ')':
-			repl = `\29`
-		case '+':
-			repl = `\2b`
-		case '/':
-			repl = `\2f`
-		case ':':
-			repl = `\3a`
-		case ';':
-			repl = `\3b`
-		case '<':
-			repl = `\3c`
-		case '>':
-			repl = `\3e`
-		case '\\':
-			repl = `\\`
-		case '{':
-			repl = `\7b`
-		case '}':
-			repl = `\7d`
+		switch {
+		case int(r) < len(cssReplacementTable) && cssReplacementTable[r] != "":
+			repl = cssReplacementTable[r]
 		default:
 			continue
 		}
 		b.WriteString(s[written:i])
 		b.WriteString(repl)
-		written = i + utf8.RuneLen(r)
+		written = i + w
 		if repl != `\\` && (written == len(s) || isHex(s[written]) || isCSSSpace(s[written])) {
 			b.WriteByte(' ')
 		}
@@ -218,6 +182,30 @@ func cssEscaper(args ...interface{}) string {
 	return b.String()
 }
 
+var cssReplacementTable = []string{
+	0:    `\0`,
+	'\t': `\9`,
+	'\n': `\a`,
+	'\f': `\c`,
+	'\r': `\d`,
+	// Encode HTML specials as hex so the output can be embedded
+	// in HTML attributes without further encoding.
+	'"':  `\22`,
+	'&':  `\26`,
+	'\'': `\27`,
+	'(':  `\28`,
+	')':  `\29`,
+	'+':  `\2b`,
+	'/':  `\2f`,
+	':':  `\3a`,
+	';':  `\3b`,
+	'<':  `\3c`,
+	'>':  `\3e`,
+	'\\': `\\`,
+	'{':  `\7b`,
+	'}':  `\7d`,
+}
+
 var expressionBytes = []byte("expression")
 var mozBindingBytes = []byte("mozbinding")
 
diff --git a/src/html/template/doc.go b/src/html/template/doc.go
index d422ada..1827403 100644
--- a/src/html/template/doc.go
+++ b/src/html/template/doc.go
@@ -151,7 +151,7 @@ The template
 
 can be invoked with
 
-  tmpl.Execute(out, HTML(`<b>World</b>`))
+  tmpl.Execute(out, template.HTML(`<b>World</b>`))
 
 to produce
 
diff --git a/src/html/template/escape.go b/src/html/template/escape.go
index ee01fb1..3c18340 100644
--- a/src/html/template/escape.go
+++ b/src/html/template/escape.go
@@ -205,15 +205,17 @@ func (e *escaper) escapeAction(c context, n *parse.ActionNode) context {
 }
 
 // allIdents returns the names of the identifiers under the Ident field of the node,
-// which might be a singleton (Identifier) or a slice (Field).
+// which might be a singleton (Identifier) or a slice (Field or Chain).
 func allIdents(node parse.Node) []string {
 	switch node := node.(type) {
 	case *parse.IdentifierNode:
 		return []string{node.Ident}
 	case *parse.FieldNode:
 		return node.Ident
+	case *parse.ChainNode:
+		return node.Field
 	}
-	panic("unidentified node type in allIdents")
+	return nil
 }
 
 // ensurePipelineContains ensures that the pipeline has commands with
@@ -297,9 +299,9 @@ var redundantFuncs = map[string]map[string]bool{
 // unless it is redundant with the last command.
 func appendCmd(cmds []*parse.CommandNode, cmd *parse.CommandNode) []*parse.CommandNode {
 	if n := len(cmds); n != 0 {
-		last, ok := cmds[n-1].Args[0].(*parse.IdentifierNode)
-		next, _ := cmd.Args[0].(*parse.IdentifierNode)
-		if ok && redundantFuncs[last.Ident][next.Ident] {
+		last, okLast := cmds[n-1].Args[0].(*parse.IdentifierNode)
+		next, okNext := cmd.Args[0].(*parse.IdentifierNode)
+		if okLast && okNext && redundantFuncs[last.Ident][next.Ident] {
 			return cmds
 		}
 	}
diff --git a/src/html/template/escape_test.go b/src/html/template/escape_test.go
index ef7b877..bea2d13 100644
--- a/src/html/template/escape_test.go
+++ b/src/html/template/escape_test.go
@@ -1547,6 +1547,28 @@ func TestEnsurePipelineContains(t *testing.T) {
 			"($).X | urlquery | html | print",
 			[]string{"urlquery", "html"},
 		},
+		{
+			"{{.X | print 2 | .f 3}}",
+			".X | print 2 | .f 3 | urlquery | html",
+			[]string{"urlquery", "html"},
+		},
+		{
+			"{{.X | html | print 2 | .f 3}}",
+			".X | urlquery | html | print 2 | .f 3",
+			[]string{"urlquery", "html"},
+		},
+		{
+			// covering issue 10801
+			"{{.X | js.x }}",
+			".X | js.x | urlquery | html",
+			[]string{"urlquery", "html"},
+		},
+		{
+			// covering issue 10801
+			"{{.X | (print 12 | js).x }}",
+			".X | (print 12 | js).x | urlquery | html",
+			[]string{"urlquery", "html"},
+		},
 	}
 	for i, test := range tests {
 		tmpl := template.Must(template.New("test").Parse(test.input))
@@ -1564,6 +1586,28 @@ func TestEnsurePipelineContains(t *testing.T) {
 	}
 }
 
+func TestEscapeMalformedPipelines(t *testing.T) {
+	tests := []string{
+		"{{ 0 | $ }}",
+		"{{ 0 | $ | urlquery }}",
+		"{{ 0 | $ | urlquery | html }}",
+		"{{ 0 | (nil) }}",
+		"{{ 0 | (nil) | html }}",
+		"{{ 0 | (nil) | html | urlquery }}",
+	}
+	for _, test := range tests {
+		var b bytes.Buffer
+		tmpl, err := New("test").Parse(test)
+		if err != nil {
+			t.Errorf("failed to parse set: %q", err)
+		}
+		err = tmpl.Execute(&b, nil)
+		if err == nil {
+			t.Errorf("Expected error for %q", test)
+		}
+	}
+}
+
 func TestEscapeErrorsNotIgnorable(t *testing.T) {
 	var b bytes.Buffer
 	tmpl, _ := New("dangerous").Parse("<a")
@@ -1686,6 +1730,21 @@ func TestPipeToMethodIsEscaped(t *testing.T) {
 	}
 }
 
+// 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/example_test.go b/src/html/template/example_test.go
new file mode 100644
index 0000000..a75ceec
--- /dev/null
+++ b/src/html/template/example_test.go
@@ -0,0 +1,122 @@
+// 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 template_test
+
+import (
+	"fmt"
+	"html/template"
+	"log"
+	"os"
+)
+
+func Example() {
+	const tpl = `
+<!DOCTYPE html>
+<html>
+	<head>
+		<meta charset="UTF-8">
+		<title>{{.Title}}</title>
+	</head>
+	<body>
+		{{range .Items}}<div>{{ . }}</div>{{else}}<div><strong>no rows</strong></div>{{end}}
+	</body>
+</html>`
+
+	check := func(err error) {
+		if err != nil {
+			log.Fatal(err)
+		}
+	}
+	t, err := template.New("webpage").Parse(tpl)
+
+	data := struct {
+		Title string
+		Items []string
+	}{
+		Title: "My page",
+		Items: []string{
+			"My photos",
+			"My blog",
+		},
+	}
+
+	err = t.Execute(os.Stdout, data)
+	check(err)
+
+	noItems := struct {
+		Title string
+		Items []string
+	}{
+		Title: "My another page",
+		Items: []string{},
+	}
+
+	err = t.Execute(os.Stdout, noItems)
+	check(err)
+
+	// Output:
+	// <!DOCTYPE html>
+	// <html>
+	// 	<head>
+	// 		<meta charset="UTF-8">
+	// 		<title>My page</title>
+	// 	</head>
+	// 	<body>
+	// 		<div>My photos</div><div>My blog</div>
+	// 	</body>
+	// </html>
+	// <!DOCTYPE html>
+	// <html>
+	// 	<head>
+	// 		<meta charset="UTF-8">
+	// 		<title>My another page</title>
+	// 	</head>
+	// 	<body>
+	// 		<div><strong>no rows</strong></div>
+	// 	</body>
+	// </html>
+
+}
+
+func Example_autoescaping() {
+	check := func(err error) {
+		if err != nil {
+			log.Fatal(err)
+		}
+	}
+	t, err := template.New("foo").Parse(`{{define "T"}}Hello, {{.}}!{{end}}`)
+	check(err)
+	err = t.ExecuteTemplate(os.Stdout, "T", "<script>alert('you have been pwned')</script>")
+	check(err)
+	// Output:
+	// Hello, <script>alert('you have been pwned')</script>!
+}
+
+func Example_escape() {
+	const s = `"Fran & Freddie's Diner" <tasty at example.com>`
+	v := []interface{}{`"Fran & Freddie's Diner"`, ' ', `<tasty at example.com>`}
+
+	fmt.Println(template.HTMLEscapeString(s))
+	template.HTMLEscape(os.Stdout, []byte(s))
+	fmt.Fprintln(os.Stdout, "")
+	fmt.Println(template.HTMLEscaper(v...))
+
+	fmt.Println(template.JSEscapeString(s))
+	template.JSEscape(os.Stdout, []byte(s))
+	fmt.Fprintln(os.Stdout, "")
+	fmt.Println(template.JSEscaper(v...))
+
+	fmt.Println(template.URLQueryEscaper(v...))
+
+	// Output:
+	// "Fran & Freddie's Diner" <tasty at example.com>
+	// "Fran & Freddie's Diner" <tasty at example.com>
+	// "Fran & Freddie's Diner"32<tasty at example.com>
+	// \"Fran & Freddie\'s Diner\" \x3Ctasty at example.com\x3E
+	// \"Fran & Freddie\'s Diner\" \x3Ctasty at example.com\x3E
+	// \"Fran & Freddie\'s Diner\"32\x3Ctasty at example.com\x3E
+	// %22Fran+%26+Freddie%27s+Diner%2232%3Ctasty%40example.com%3E
+
+}
diff --git a/src/html/template/html.go b/src/html/template/html.go
index 9c069ef..de4aa4a 100644
--- a/src/html/template/html.go
+++ b/src/html/template/html.go
@@ -138,21 +138,24 @@ var htmlNospaceNormReplacementTable = []string{
 // and when badRunes is true, certain bad runes are allowed through unescaped.
 func htmlReplacer(s string, replacementTable []string, badRunes bool) string {
 	written, b := 0, new(bytes.Buffer)
-	for i, r := range s {
+	r, w := rune(0), 0
+	for i := 0; i < len(s); i += w {
+		// Cannot use 'for range s' because we need to preserve the width
+		// of the runes in the input. If we see a decoding error, the input
+		// width will not be utf8.Runelen(r) and we will overrun the buffer.
+		r, w = utf8.DecodeRuneInString(s[i:])
 		if int(r) < len(replacementTable) {
 			if repl := replacementTable[r]; len(repl) != 0 {
 				b.WriteString(s[written:i])
 				b.WriteString(repl)
-				// Valid as long as replacementTable doesn't
-				// include anything above 0x7f.
-				written = i + utf8.RuneLen(r)
+				written = i + w
 			}
 		} else if badRunes {
 			// No-op.
 			// IE does not allow these ranges in unquoted attrs.
 		} else if 0xfdd0 <= r && r <= 0xfdef || 0xfff0 <= r && r <= 0xffff {
 			fmt.Fprintf(b, "%s&#x%x;", s[written:i], r)
-			written = i + utf8.RuneLen(r)
+			written = i + w
 		}
 	}
 	if written == 0 {
diff --git a/src/html/template/html_test.go b/src/html/template/html_test.go
index b9b9703..f04ee04 100644
--- a/src/html/template/html_test.go
+++ b/src/html/template/html_test.go
@@ -19,7 +19,8 @@ func TestHTMLNospaceEscaper(t *testing.T) {
 		`PQRSTUVWXYZ[\]^_` +
 		"`abcdefghijklmno" +
 		"pqrstuvwxyz{|}~\x7f" +
-		"\u00A0\u0100\u2028\u2029\ufeff\ufdec\U0001D11E")
+		"\u00A0\u0100\u2028\u2029\ufeff\ufdec\U0001D11E" +
+		"erroneous\x960") // keep at the end
 
 	want := ("&#xfffd;\x01\x02\x03\x04\x05\x06\x07" +
 		"\x08	

\x0E\x0F" +
@@ -31,14 +32,16 @@ func TestHTMLNospaceEscaper(t *testing.T) {
 		`PQRSTUVWXYZ[\]^_` +
 		``abcdefghijklmno` +
 		`pqrstuvwxyz{|}~` + "\u007f" +
-		"\u00A0\u0100\u2028\u2029\ufeff&#xfdec;\U0001D11E")
+		"\u00A0\u0100\u2028\u2029\ufeff&#xfdec;\U0001D11E" +
+		"erroneous&#xfffd;0") // keep at the end
 
 	got := htmlNospaceEscaper(input)
 	if got != want {
 		t.Errorf("encode: want\n\t%q\nbut got\n\t%q", want, got)
 	}
 
-	got, want = html.UnescapeString(got), strings.Replace(input, "\x00", "\ufffd", 1)
+	r := strings.NewReplacer("\x00", "\ufffd", "\x96", "\ufffd")
+	got, want = html.UnescapeString(got), r.Replace(input)
 	if want != got {
 		t.Errorf("decode: want\n\t%q\nbut got\n\t%q", want, got)
 	}
diff --git a/src/html/template/js.go b/src/html/template/js.go
index 999a61e..f6d166b 100644
--- a/src/html/template/js.go
+++ b/src/html/template/js.go
@@ -246,8 +246,10 @@ func jsRegexpEscaper(args ...interface{}) string {
 // `\u2029`.
 func replace(s string, replacementTable []string) string {
 	var b bytes.Buffer
-	written := 0
-	for i, r := range s {
+	r, w, written := rune(0), 0, 0
+	for i := 0; i < len(s); i += w {
+		// See comment in htmlEscaper.
+		r, w = utf8.DecodeRuneInString(s[i:])
 		var repl string
 		switch {
 		case int(r) < len(replacementTable) && replacementTable[r] != "":
@@ -261,7 +263,7 @@ func replace(s string, replacementTable []string) string {
 		}
 		b.WriteString(s[written:i])
 		b.WriteString(repl)
-		written = i + utf8.RuneLen(r)
+		written = i + w
 	}
 	if written == 0 {
 		return s
diff --git a/src/html/template/template.go b/src/html/template/template.go
index ce61701..bb9140a 100644
--- a/src/html/template/template.go
+++ b/src/html/template/template.go
@@ -51,11 +51,37 @@ func (t *Template) Templates() []*Template {
 	return m
 }
 
+// Option sets options for the template. Options are described by
+// strings, either a simple string or "key=value". There can be at
+// most one equals sign in an option string. If the option string
+// is unrecognized or otherwise invalid, Option panics.
+//
+// Known options:
+//
+// missingkey: Control the behavior during execution if a map is
+// indexed with a key that is not present in the map.
+//	"missingkey=default" or "missingkey=invalid"
+//		The default behavior: Do nothing and continue execution.
+//		If printed, the result of the index operation is the string
+//		"<no value>".
+//	"missingkey=zero"
+//		The operation returns the zero value for the map type's element.
+//	"missingkey=error"
+//		Execution stops immediately with an error.
+//
+func (t *Template) Option(opt ...string) *Template {
+	t.text.Option(opt...)
+	return t
+}
+
 // escape escapes all associated templates.
 func (t *Template) escape() error {
 	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/html/template/transition.go b/src/html/template/transition.go
index b486fcd..d2e0287 100644
--- a/src/html/template/transition.go
+++ b/src/html/template/transition.go
@@ -183,24 +183,54 @@ func tHTMLCmt(c context, s []byte) (context, int) {
 
 // specialTagEndMarkers maps element types to the character sequence that
 // case-insensitively signals the end of the special tag body.
-var specialTagEndMarkers = [...]string{
-	elementScript:   "</script",
-	elementStyle:    "</style",
-	elementTextarea: "</textarea",
-	elementTitle:    "</title",
+var specialTagEndMarkers = [...][]byte{
+	elementScript:   []byte("script"),
+	elementStyle:    []byte("style"),
+	elementTextarea: []byte("textarea"),
+	elementTitle:    []byte("title"),
 }
 
+var (
+	specialTagEndPrefix = []byte("</")
+	tagEndSeparators    = []byte("> \t\n\f/")
+)
+
 // tSpecialTagEnd is the context transition function for raw text and RCDATA
 // element states.
 func tSpecialTagEnd(c context, s []byte) (context, int) {
 	if c.element != elementNone {
-		if i := strings.Index(strings.ToLower(string(s)), specialTagEndMarkers[c.element]); i != -1 {
+		if i := indexTagEnd(s, specialTagEndMarkers[c.element]); i != -1 {
 			return context{}, i
 		}
 	}
 	return c, len(s)
 }
 
+// indexTagEnd finds the index of a special tag end in a case insensitive way, or returns -1
+func indexTagEnd(s []byte, tag []byte) int {
+	res := 0
+	plen := len(specialTagEndPrefix)
+	for len(s) > 0 {
+		// Try to find the tag end prefix first
+		i := bytes.Index(s, specialTagEndPrefix)
+		if i == -1 {
+			return i
+		}
+		s = s[i+plen:]
+		// Try to match the actual tag if there is still space for it
+		if len(tag) <= len(s) && bytes.EqualFold(tag, s[:len(tag)]) {
+			s = s[len(tag):]
+			// Check the tag is followed by a proper separator
+			if len(s) > 0 && bytes.IndexByte(tagEndSeparators, s[0]) != -1 {
+				return res + i
+			}
+			res += len(tag)
+		}
+		res += i + plen
+	}
+	return -1
+}
+
 // tAttr is the context transition function for the attribute state.
 func tAttr(c context, s []byte) (context, int) {
 	return c, len(s)
diff --git a/src/html/template/transition_test.go b/src/html/template/transition_test.go
new file mode 100644
index 0000000..412a4c7
--- /dev/null
+++ b/src/html/template/transition_test.go
@@ -0,0 +1,60 @@
+// 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 template
+
+import (
+	"bytes"
+	"strings"
+	"testing"
+)
+
+func TestFindEndTag(t *testing.T) {
+	tests := []struct {
+		s, tag string
+		want   int
+	}{
+		{"", "tag", -1},
+		{"hello </textarea> hello", "textarea", 6},
+		{"hello </TEXTarea> hello", "textarea", 6},
+		{"hello </textAREA>", "textarea", 6},
+		{"hello </textarea", "textareax", -1},
+		{"hello </textarea>", "tag", -1},
+		{"hello tag </textarea", "tag", -1},
+		{"hello </tag> </other> </textarea> <other>", "textarea", 22},
+		{"</textarea> <other>", "textarea", 0},
+		{"<div> </div> </TEXTAREA>", "textarea", 13},
+		{"<div> </div> </TEXTAREA\t>", "textarea", 13},
+		{"<div> </div> </TEXTAREA >", "textarea", 13},
+		{"<div> </div> </TEXTAREAfoo", "textarea", -1},
+		{"</TEXTAREAfoo </textarea>", "textarea", 14},
+		{"<</script >", "script", 1},
+		{"</script>", "textarea", -1},
+	}
+	for _, test := range tests {
+		if got := indexTagEnd([]byte(test.s), []byte(test.tag)); test.want != got {
+			t.Errorf("%q/%q: want\n\t%d\nbut got\n\t%d", test.s, test.tag, test.want, got)
+		}
+	}
+}
+
+func BenchmarkTemplateSpecialTags(b *testing.B) {
+
+	r := struct {
+		Name, Gift string
+	}{"Aunt Mildred", "bone china tea set"}
+
+	h1 := "<textarea> Hello Hello Hello </textarea> "
+	h2 := "<textarea> <p> Dear {{.Name}},\n{{with .Gift}}Thank you for the lovely {{.}}. {{end}}\nBest wishes. </p>\n</textarea>"
+	html := strings.Repeat(h1, 100) + h2 + strings.Repeat(h1, 100) + h2
+
+	var buf bytes.Buffer
+	for i := 0; i < b.N; i++ {
+		tmpl := Must(New("foo").Parse(html))
+		if err := tmpl.Execute(&buf, r); err != nil {
+			b.Fatal(err)
+		}
+		buf.Reset()
+	}
+}
diff --git a/src/image/color/color.go b/src/image/color/color.go
index ff596a7..cae059b 100644
--- a/src/image/color/color.go
+++ b/src/image/color/color.go
@@ -9,14 +9,20 @@ package color
 // 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 @@ func (c RGBA) RGBA() (r, g, b, a uint32) {
 	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
 }
@@ -262,32 +271,39 @@ func (p Palette) Convert(c Color) Color {
 }
 
 // Index returns the index of the palette color closest to c in Euclidean
-// R,G,B space.
+// R,G,B,A space.
 func (p Palette) Index(c Color) int {
 	// A batch version of this computation is in image/draw/draw.go.
 
-	cr, cg, cb, _ := c.RGBA()
-	ret, bestSSD := 0, uint32(1<<32-1)
+	cr, cg, cb, ca := c.RGBA()
+	ret, bestSum := 0, uint32(1<<32-1)
 	for i, v := range p {
-		vr, vg, vb, _ := v.RGBA()
-		// We shift by 1 bit to avoid potential uint32 overflow in
-		// sum-squared-difference.
-		delta := (int32(cr) - int32(vr)) >> 1
-		ssd := uint32(delta * delta)
-		delta = (int32(cg) - int32(vg)) >> 1
-		ssd += uint32(delta * delta)
-		delta = (int32(cb) - int32(vb)) >> 1
-		ssd += uint32(delta * delta)
-		if ssd < bestSSD {
-			if ssd == 0 {
+		vr, vg, vb, va := v.RGBA()
+		sum := sqDiff(cr, vr) + sqDiff(cg, vg) + sqDiff(cb, vb) + sqDiff(ca, va)
+		if sum < bestSum {
+			if sum == 0 {
 				return i
 			}
-			ret, bestSSD = i, ssd
+			ret, bestSum = i, sum
 		}
 	}
 	return ret
 }
 
+// sqDiff returns the squared-difference of x and y, shifted by 2 so that
+// adding four of those won't overflow a uint32.
+//
+// x and y are both assumed to be in the range [0, 0xffff].
+func sqDiff(x, y uint32) uint32 {
+	var d uint32
+	if x > y {
+		d = x - y
+	} else {
+		d = y - x
+	}
+	return (d * d) >> 2
+}
+
 // Standard colors.
 var (
 	Black       = Gray16{0}
diff --git a/src/image/color/ycbcr.go b/src/image/color/ycbcr.go
index 4c2f29e..4bcb07d 100644
--- a/src/image/color/ycbcr.go
+++ b/src/image/color/ycbcr.go
@@ -11,26 +11,27 @@ func RGBToYCbCr(r, g, b uint8) (uint8, uint8, uint8) {
 	//	Cb = -0.1687*R - 0.3313*G + 0.5000*B + 128
 	//	Cr =  0.5000*R - 0.4187*G - 0.0813*B + 128
 	// http://www.w3.org/Graphics/JPEG/jfif3.pdf says Y but means Y'.
-	r1 := int(r)
-	g1 := int(g)
-	b1 := int(b)
+
+	r1 := int32(r)
+	g1 := int32(g)
+	b1 := int32(b)
 	yy := (19595*r1 + 38470*g1 + 7471*b1 + 1<<15) >> 16
 	cb := (-11056*r1 - 21712*g1 + 32768*b1 + 257<<15) >> 16
 	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)
 }
@@ -42,26 +43,27 @@ func YCbCrToRGB(y, cb, cr uint8) (uint8, uint8, uint8) {
 	//	G = Y' - 0.34414*(Cb-128) - 0.71414*(Cr-128)
 	//	B = Y' + 1.77200*(Cb-128)
 	// http://www.w3.org/Graphics/JPEG/jfif3.pdf says Y but means Y'.
-	yy1 := int(y)<<16 + 1<<15
-	cb1 := int(cb) - 128
-	cr1 := int(cr) - 128
+
+	yy1 := int32(y) * 0x10100 // Convert 0x12 to 0x121200.
+	cb1 := int32(cb) - 128
+	cr1 := int32(cr) - 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
+	} 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 +84,45 @@ type YCbCr struct {
 }
 
 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:
+	//	0x7e18 0x808e 0x7db9
+	//	0x7e7e 0x8080 0x7d7d
+
+	yy1 := int32(c.Y) * 0x10100 // Convert 0x12 to 0x121200.
+	cb1 := int32(c.Cb) - 128
+	cr1 := int32(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.
@@ -97,3 +136,64 @@ func yCbCrModel(c Color) Color {
 	y, u, v := RGBToYCbCr(uint8(r>>8), uint8(g>>8), uint8(b>>8))
 	return YCbCr{y, u, v}
 }
+
+// RGBToCMYK converts an RGB triple to a CMYK quadruple.
+func RGBToCMYK(r, g, b uint8) (uint8, uint8, uint8, uint8) {
+	rr := uint32(r)
+	gg := uint32(g)
+	bb := uint32(b)
+	w := rr
+	if w < gg {
+		w = gg
+	}
+	if w < bb {
+		w = bb
+	}
+	if w == 0 {
+		return 0, 0, 0, 0xff
+	}
+	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(0xffff - uint32(k)*0x101)
+	r := uint32(0xffff-uint32(c)*0x101) * w / 0xffff
+	g := uint32(0xffff-uint32(m)*0x101) * w / 0xffff
+	b := uint32(0xffff-uint32(y)*0x101) * w / 0xffff
+	return uint8(r >> 8), uint8(g >> 8), uint8(b >> 8)
+}
+
+// CMYK represents a fully opaque CMYK color, having 8 bits for each of cyan,
+// magenta, yellow and black.
+//
+// It is not associated with any particular color profile.
+type CMYK struct {
+	C, M, Y, K uint8
+}
+
+func (c CMYK) RGBA() (uint32, uint32, uint32, uint32) {
+	// This code is a copy of the CMYKToRGB function above, except that it
+	// returns values in the range [0, 0xffff] instead of [0, 0xff].
+
+	w := uint32(0xffff - uint32(c.K)*0x101)
+	r := uint32(0xffff-uint32(c.C)*0x101) * w / 0xffff
+	g := uint32(0xffff-uint32(c.M)*0x101) * w / 0xffff
+	b := uint32(0xffff-uint32(c.Y)*0x101) * w / 0xffff
+	return uint32(r), uint32(g), uint32(b), 0xffff
+}
+
+// CMYKModel is the Model for CMYK colors.
+var CMYKModel Model = ModelFunc(cmykModel)
+
+func cmykModel(c Color) Color {
+	if _, ok := c.(CMYK); ok {
+		return c
+	}
+	r, g, b, _ := c.RGBA()
+	cc, mm, yy, kk := RGBToCMYK(uint8(r>>8), uint8(g>>8), uint8(b>>8))
+	return CMYK{cc, mm, yy, kk}
+}
diff --git a/src/image/color/ycbcr_test.go b/src/image/color/ycbcr_test.go
index 92a0e6f..5da49d3 100644
--- a/src/image/color/ycbcr_test.go
+++ b/src/image/color/ycbcr_test.go
@@ -5,6 +5,7 @@
 package color
 
 import (
+	"fmt"
 	"testing"
 )
 
@@ -15,19 +16,134 @@ func delta(x, y uint8) uint8 {
 	return y - x
 }
 
-// Test that a subset of RGB space can be converted to YCbCr and back to within
-// 1/256 tolerance.
-func TestRoundtrip(t *testing.T) {
-	for r := 0; r < 255; r += 7 {
-		for g := 0; g < 255; g += 5 {
-			for b := 0; b < 255; b += 3 {
+func eq(c0, c1 Color) error {
+	r0, g0, b0, a0 := c0.RGBA()
+	r1, g1, b1, a1 := c1.RGBA()
+	if r0 != r1 || g0 != g1 || b0 != b1 || a0 != a1 {
+		return fmt.Errorf("got  0x%04x 0x%04x 0x%04x 0x%04x\nwant 0x%04x 0x%04x 0x%04x 0x%04x",
+			r0, g0, b0, a0, r1, g1, b1, a1)
+	}
+	return nil
+}
+
+// TestYCbCrRoundtrip tests that a subset of RGB space can be converted to YCbCr
+// and back to within 2/256 tolerance.
+func TestYCbCrRoundtrip(t *testing.T) {
+	for r := 0; r < 256; r += 7 {
+		for g := 0; g < 256; g += 5 {
+			for b := 0; b < 256; b += 3 {
 				r0, g0, b0 := uint8(r), uint8(g), uint8(b)
 				y, cb, cr := RGBToYCbCr(r0, g0, b0)
 				r1, g1, b1 := YCbCrToRGB(y, cb, cr)
+				if delta(r0, r1) > 2 || delta(g0, g1) > 2 || delta(b0, b1) > 2 {
+					t.Fatalf("\nr0, g0, b0 = %d, %d, %d\ny,  cb, cr = %d, %d, %d\nr1, g1, b1 = %d, %d, %d",
+						r0, g0, b0, y, cb, cr, r1, g1, b1)
+				}
+			}
+		}
+	}
+}
+
+// TestYCbCrToRGBConsistency tests that calling the RGBA method (16 bit color)
+// then truncating to 8 bits is equivalent to calling the YCbCrToRGB function (8
+// bit color).
+func TestYCbCrToRGBConsistency(t *testing.T) {
+	for y := 0; y < 256; y += 7 {
+		for cb := 0; cb < 256; cb += 5 {
+			for cr := 0; cr < 256; cr += 3 {
+				x := YCbCr{uint8(y), uint8(cb), uint8(cr)}
+				r0, g0, b0, _ := x.RGBA()
+				r1, g1, b1 := uint8(r0>>8), uint8(g0>>8), uint8(b0>>8)
+				r2, g2, b2 := YCbCrToRGB(x.Y, x.Cb, x.Cr)
+				if r1 != r2 || g1 != g2 || b1 != b2 {
+					t.Fatalf("y, cb, cr = %d, %d, %d\nr1, g1, b1 = %d, %d, %d\nr2, g2, b2 = %d, %d, %d",
+						y, cb, cr, r1, g1, b1, r2, g2, b2)
+				}
+			}
+		}
+	}
+}
+
+// TestYCbCrGray tests that YCbCr colors are a superset of Gray colors.
+func TestYCbCrGray(t *testing.T) {
+	for i := 0; i < 256; i++ {
+		if err := eq(YCbCr{uint8(i), 0x80, 0x80}, Gray{uint8(i)}); err != nil {
+			t.Errorf("i=0x%02x:\n%v", i, err)
+		}
+	}
+}
+
+// TestCMYKRoundtrip tests that a subset of RGB space can be converted to CMYK
+// and back to within 1/256 tolerance.
+func TestCMYKRoundtrip(t *testing.T) {
+	for r := 0; r < 256; r += 7 {
+		for g := 0; g < 256; g += 5 {
+			for b := 0; b < 256; b += 3 {
+				r0, g0, b0 := uint8(r), uint8(g), uint8(b)
+				c, m, y, k := RGBToCMYK(r0, g0, b0)
+				r1, g1, b1 := CMYKToRGB(c, m, y, k)
 				if delta(r0, r1) > 1 || delta(g0, g1) > 1 || delta(b0, b1) > 1 {
-					t.Fatalf("r0, g0, b0 = %d, %d, %d   r1, g1, b1 = %d, %d, %d", r0, g0, b0, r1, g1, b1)
+					t.Fatalf("\nr0, g0, b0 = %d, %d, %d\nc, m, y, k = %d, %d, %d, %d\nr1, g1, b1 = %d, %d, %d",
+						r0, g0, b0, c, m, y, k, r1, g1, b1)
 				}
 			}
 		}
 	}
 }
+
+// TestCMYKToRGBConsistency tests that calling the RGBA method (16 bit color)
+// then truncating to 8 bits is equivalent to calling the CMYKToRGB function (8
+// bit color).
+func TestCMYKToRGBConsistency(t *testing.T) {
+	for c := 0; c < 256; c += 7 {
+		for m := 0; m < 256; m += 5 {
+			for y := 0; y < 256; y += 3 {
+				for k := 0; k < 256; k += 11 {
+					x := CMYK{uint8(c), uint8(m), uint8(y), uint8(k)}
+					r0, g0, b0, _ := x.RGBA()
+					r1, g1, b1 := uint8(r0>>8), uint8(g0>>8), uint8(b0>>8)
+					r2, g2, b2 := CMYKToRGB(x.C, x.M, x.Y, x.K)
+					if r1 != r2 || g1 != g2 || b1 != b2 {
+						t.Fatalf("c, m, y, k = %d, %d, %d, %d\nr1, g1, b1 = %d, %d, %d\nr2, g2, b2 = %d, %d, %d",
+							c, m, y, k, r1, g1, b1, r2, g2, b2)
+					}
+				}
+			}
+		}
+	}
+}
+
+// TestCMYKGray tests that CMYK colors are a superset of Gray colors.
+func TestCMYKGray(t *testing.T) {
+	for i := 0; i < 256; i++ {
+		if err := eq(CMYK{0x00, 0x00, 0x00, uint8(255 - i)}, Gray{uint8(i)}); err != nil {
+			t.Errorf("i=0x%02x:\n%v", i, err)
+		}
+	}
+}
+
+func TestPalette(t *testing.T) {
+	p := Palette{
+		RGBA{0xff, 0xff, 0xff, 0xff},
+		RGBA{0x80, 0x00, 0x00, 0xff},
+		RGBA{0x7f, 0x00, 0x00, 0x7f},
+		RGBA{0x00, 0x00, 0x00, 0x7f},
+		RGBA{0x00, 0x00, 0x00, 0x00},
+		RGBA{0x40, 0x40, 0x40, 0x40},
+	}
+	// Check that, for a Palette with no repeated colors, the closest color to
+	// each element is itself.
+	for i, c := range p {
+		j := p.Index(c)
+		if i != j {
+			t.Errorf("Index(%v): got %d (color = %v), want %d", c, j, p[j], i)
+		}
+	}
+	// Check that finding the closest color considers alpha, not just red,
+	// green and blue.
+	got := p.Convert(RGBA{0x80, 0x00, 0x00, 0x80})
+	want := RGBA{0x7f, 0x00, 0x00, 0x7f}
+	if got != want {
+		t.Errorf("got %v, want %v", got, want)
+	}
+}
diff --git a/src/image/decode_example_test.go b/src/image/decode_example_test.go
index 21e90fe..81fa037 100644
--- a/src/image/decode_example_test.go
+++ b/src/image/decode_example_test.go
@@ -61,22 +61,22 @@ func Example() {
 	}
 	// Output:
 	// bin               red  green   blue  alpha
-	// 0x0000-0x0fff:    353    759   7228      0
-	// 0x1000-0x1fff:    629   2944   1036      0
-	// 0x2000-0x2fff:   1075   2319    984      0
-	// 0x3000-0x3fff:    838   2291    988      0
-	// 0x4000-0x4fff:    540   1302    542      0
-	// 0x5000-0x5fff:    319    971    263      0
-	// 0x6000-0x6fff:    316    377    178      0
-	// 0x7000-0x7fff:    581    280    216      0
-	// 0x8000-0x8fff:   3457    228    274      0
-	// 0x9000-0x9fff:   2294    237    334      0
-	// 0xa000-0xafff:    938    283    370      0
-	// 0xb000-0xbfff:    322    338    401      0
-	// 0xc000-0xcfff:    229    386    295      0
-	// 0xd000-0xdfff:    263    416    281      0
-	// 0xe000-0xefff:    538    433    312      0
-	// 0xf000-0xffff:   2758   1886   1748  15450
+	// 0x0000-0x0fff:    364    790   7242      0
+	// 0x1000-0x1fff:    645   2967   1039      0
+	// 0x2000-0x2fff:   1072   2299    979      0
+	// 0x3000-0x3fff:    820   2266    980      0
+	// 0x4000-0x4fff:    537   1305    541      0
+	// 0x5000-0x5fff:    319    962    261      0
+	// 0x6000-0x6fff:    322    375    177      0
+	// 0x7000-0x7fff:    601    279    214      0
+	// 0x8000-0x8fff:   3478    227    273      0
+	// 0x9000-0x9fff:   2260    234    329      0
+	// 0xa000-0xafff:    921    282    373      0
+	// 0xb000-0xbfff:    321    335    397      0
+	// 0xc000-0xcfff:    229    388    298      0
+	// 0xd000-0xdfff:    260    414    277      0
+	// 0xe000-0xefff:    516    428    298      0
+	// 0xf000-0xffff:   2785   1899   1772  15450
 }
 
 const data = `
diff --git a/src/image/decode_test.go b/src/image/decode_test.go
index 8dee57e..d16ef8a 100644
--- a/src/image/decode_test.go
+++ b/src/image/decode_test.go
@@ -6,6 +6,7 @@ package image_test
 
 import (
 	"bufio"
+	"fmt"
 	"image"
 	"image/color"
 	"os"
@@ -32,6 +33,9 @@ var imageTests = []imageTest{
 	// 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},
@@ -74,6 +78,11 @@ func withinTolerance(c0, c1 color.Color, tolerance int) bool {
 }
 
 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 {
@@ -94,13 +103,14 @@ loop:
 		}
 		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/bench_test.go b/src/image/draw/bench_test.go
index cc62e25..7b89f95 100644
--- a/src/image/draw/bench_test.go
+++ b/src/image/draw/bench_test.go
@@ -7,6 +7,7 @@ package draw
 import (
 	"image"
 	"image/color"
+	"reflect"
 	"testing"
 )
 
@@ -15,6 +16,11 @@ const (
 	srcw, srch = 400, 300
 )
 
+var palette = color.Palette{
+	color.Black,
+	color.White,
+}
+
 // bench benchmarks drawing src and mask images onto a dst image with the
 // given op and the color models to create those images from.
 // The created images' pixels are initialized to non-zero values.
@@ -50,13 +56,48 @@ func bench(b *testing.B, dcm, scm, mcm color.Model, op Op) {
 		}
 		dst = dst1
 	default:
-		b.Fatal("unknown destination color model", dcm)
+		// The == operator isn't defined on a color.Palette (a slice), so we
+		// use reflection.
+		if reflect.DeepEqual(dcm, palette) {
+			dst1 := image.NewPaletted(image.Rect(0, 0, dstw, dsth), palette)
+			for y := 0; y < dsth; y++ {
+				for x := 0; x < dstw; x++ {
+					dst1.SetColorIndex(x, y, uint8(x^y)&1)
+				}
+			}
+			dst = dst1
+		} else {
+			b.Fatal("unknown destination color model", dcm)
+		}
 	}
 
 	var src image.Image
 	switch scm {
 	case nil:
 		src = &image.Uniform{C: color.RGBA{0x11, 0x22, 0x33, 0xff}}
+	case color.CMYKModel:
+		src1 := image.NewCMYK(image.Rect(0, 0, srcw, srch))
+		for y := 0; y < srch; y++ {
+			for x := 0; x < srcw; x++ {
+				src1.SetCMYK(x, y, color.CMYK{
+					uint8(13 * x % 0x100),
+					uint8(11 * y % 0x100),
+					uint8((11*x + 13*y) % 0x100),
+					uint8((31*x + 37*y) % 0x100),
+				})
+			}
+		}
+		src = src1
+	case color.GrayModel:
+		src1 := image.NewGray(image.Rect(0, 0, srcw, srch))
+		for y := 0; y < srch; y++ {
+			for x := 0; x < srcw; x++ {
+				src1.SetGray(x, y, color.Gray{
+					uint8((11*x + 13*y) % 0x100),
+				})
+			}
+		}
+		src = src1
 	case color.RGBAModel:
 		src1 := image.NewRGBA(image.Rect(0, 0, srcw, srch))
 		for y := 0; y < srch; y++ {
@@ -179,6 +220,14 @@ func BenchmarkYCbCr(b *testing.B) {
 	bench(b, color.RGBAModel, color.YCbCrModel, nil, Over)
 }
 
+func BenchmarkGray(b *testing.B) {
+	bench(b, color.RGBAModel, color.GrayModel, nil, Over)
+}
+
+func BenchmarkCMYK(b *testing.B) {
+	bench(b, color.RGBAModel, color.CMYKModel, nil, Over)
+}
+
 func BenchmarkGlyphOver(b *testing.B) {
 	bench(b, color.RGBAModel, nil, color.AlphaModel, Over)
 }
@@ -187,6 +236,10 @@ func BenchmarkRGBA(b *testing.B) {
 	bench(b, color.RGBAModel, color.RGBA64Model, nil, Src)
 }
 
+func BenchmarkPaletted(b *testing.B) {
+	bench(b, palette, color.RGBAModel, nil, Src)
+}
+
 // The BenchmarkGenericFoo functions exercise the generic, slow-path code.
 
 func BenchmarkGenericOver(b *testing.B) {
diff --git a/src/image/draw/clip_test.go b/src/image/draw/clip_test.go
index 65381f7..0abf53e 100644
--- a/src/image/draw/clip_test.go
+++ b/src/image/draw/clip_test.go
@@ -139,7 +139,19 @@ var clipTests = []clipTest{
 		image.Pt(20, 0),
 		image.Pt(20, 0),
 	},
-	// TODO(nigeltao): write more tests.
+	{
+		"clip sr and mr",
+		image.Rect(0, 0, 100, 100),
+		image.Rect(0, 0, 100, 100),
+		image.Rect(23, 23, 55, 86),
+		image.Rect(44, 44, 87, 58),
+		image.Pt(10, 10),
+		image.Pt(11, 11),
+		false,
+		image.Rect(33, 33, 45, 47),
+		image.Pt(43, 43),
+		image.Pt(44, 44),
+	},
 }
 
 func TestClip(t *testing.T) {
@@ -149,12 +161,12 @@ func TestClip(t *testing.T) {
 	for _, c := range clipTests {
 		dst := dst0.SubImage(c.dr).(*image.RGBA)
 		src := src0.SubImage(c.sr).(*image.RGBA)
-		var mask image.Image
-		if !c.nilMask {
-			mask = mask0.SubImage(c.mr)
-		}
 		r, sp, mp := c.r, c.sp, c.mp
-		clip(dst, &r, src, &sp, mask, &mp)
+		if c.nilMask {
+			clip(dst, &r, src, &sp, nil, nil)
+		} else {
+			clip(dst, &r, src, &sp, mask0.SubImage(c.mr), &mp)
+		}
 
 		// Check that the actual results equal the expected results.
 		if !c.r0.Eq(r) {
@@ -173,17 +185,17 @@ func TestClip(t *testing.T) {
 		}
 
 		// Check that the clipped rectangle is contained by the dst / src / mask
-		// rectangles, in their respective co-ordinate spaces.
+		// rectangles, in their respective coordinate spaces.
 		if !r.In(c.dr) {
 			t.Errorf("%s: c.dr %v does not contain r %v", c.desc, c.dr, r)
 		}
-		// sr is r translated into src's co-ordinate space.
+		// sr is r translated into src's coordinate space.
 		sr := r.Add(c.sp.Sub(c.dr.Min))
 		if !sr.In(c.sr) {
 			t.Errorf("%s: c.sr %v does not contain sr %v", c.desc, c.sr, sr)
 		}
 		if !c.nilMask {
-			// mr is r translated into mask's co-ordinate space.
+			// mr is r translated into mask's coordinate space.
 			mr := r.Add(c.mp.Sub(c.dr.Min))
 			if !mr.In(c.mr) {
 				t.Errorf("%s: c.mr %v does not contain mr %v", c.desc, c.mr, mr)
diff --git a/src/image/draw/draw.go b/src/image/draw/draw.go
index 661230e..9419d5e 100644
--- a/src/image/draw/draw.go
+++ b/src/image/draw/draw.go
@@ -5,12 +5,13 @@
 // Package draw provides image composition functions.
 //
 // See "The Go image/draw package" for an introduction to this package:
-// http://golang.org/doc/articles/image_draw.html
+// https://golang.org/doc/articles/image_draw.html
 package draw
 
 import (
 	"image"
 	"image/color"
+	"image/internal/imageutil"
 )
 
 // m is the maximum color value returned by image.Color.RGBA.
@@ -67,7 +68,7 @@ func (floydSteinberg) Draw(dst Image, r image.Rectangle, src image.Image, sp ima
 }
 
 // clip clips r against each image's bounds (after translating into the
-// destination image's co-ordinate space) and shifts the points sp and mp by
+// destination image's coordinate space) and shifts the points sp and mp by
 // the same amount as the change in r.Min.
 func clip(dst Image, r *image.Rectangle, src image.Image, sp *image.Point, mask image.Image, mp *image.Point) {
 	orig := r.Min
@@ -81,10 +82,12 @@ func clip(dst Image, r *image.Rectangle, src image.Image, sp *image.Point, mask
 	if dx == 0 && dy == 0 {
 		return
 	}
-	(*sp).X += dx
-	(*sp).Y += dy
-	(*mp).X += dx
-	(*mp).Y += dy
+	sp.X += dx
+	sp.Y += dy
+	if mp != nil {
+		mp.X += dx
+		mp.Y += dy
+	}
 }
 
 func processBackward(dst Image, r image.Rectangle, src image.Image, sp image.Point) bool {
@@ -122,9 +125,19 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas
 					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:
+					drawGray(dst0, r, src0, sp)
+					return
+				case *image.CMYK:
+					drawCMYK(dst0, r, src0, sp)
+					return
 				}
 			} else if mask0, ok := mask.(*image.Alpha); ok {
 				switch src0 := src.(type) {
@@ -146,9 +159,15 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas
 					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:
+					drawGray(dst0, r, src0, sp)
+					return
+				case *image.CMYK:
+					drawCMYK(dst0, r, src0, sp)
+					return
 				}
 			}
 		}
@@ -157,6 +176,7 @@ func DrawMask(dst Image, r image.Rectangle, src image.Image, sp image.Point, mas
 	case *image.Paletted:
 		if op == Src && mask == nil && !processBackward(dst, r, src, sp) {
 			drawPaletted(dst0, r, src, sp, false)
+			return
 		}
 	}
 
@@ -237,16 +257,20 @@ func drawFillOver(dst *image.RGBA, r image.Rectangle, src *image.Uniform) {
 
 func drawFillSrc(dst *image.RGBA, r image.Rectangle, src *image.Uniform) {
 	sr, sg, sb, sa := src.RGBA()
+	sr8 := uint8(sr >> 8)
+	sg8 := uint8(sg >> 8)
+	sb8 := uint8(sb >> 8)
+	sa8 := uint8(sa >> 8)
 	// The built-in copy function is faster than a straightforward for loop to fill the destination with
 	// the color, but copy requires a slice source. We therefore use a for loop to fill the first row, and
 	// then use the first row as the slice source for the remaining rows.
 	i0 := dst.PixOffset(r.Min.X, r.Min.Y)
 	i1 := i0 + r.Dx()*4
 	for i := i0; i < i1; i += 4 {
-		dst.Pix[i+0] = uint8(sr >> 8)
-		dst.Pix[i+1] = uint8(sg >> 8)
-		dst.Pix[i+2] = uint8(sb >> 8)
-		dst.Pix[i+3] = uint8(sa >> 8)
+		dst.Pix[i+0] = sr8
+		dst.Pix[i+1] = sg8
+		dst.Pix[i+2] = sb8
+		dst.Pix[i+3] = sa8
 	}
 	firstRow := dst.Pix[i0:i1]
 	for y := r.Min.Y + 1; y < r.Max.Y; y++ {
@@ -313,9 +337,11 @@ func drawCopySrc(dst *image.RGBA, r image.Rectangle, src *image.RGBA, sp image.P
 		ddelta = dst.Stride
 		sdelta = src.Stride
 	} else {
-		// If the source start point is higher than the destination start point, then we compose the rows
-		// in bottom-up order instead of top-down. Unlike the drawCopyOver function, we don't have to
-		// check the x co-ordinates because the built-in copy function can handle overlapping slices.
+		// If the source start point is higher than the destination start
+		// point, then we compose the rows in bottom-up order instead of
+		// top-down. Unlike the drawCopyOver function, we don't have to check
+		// the x coordinates because the built-in copy function can handle
+		// overlapping slices.
 		d0 += (dy - 1) * dst.Stride
 		s0 += (dy - 1) * src.Stride
 		ddelta = -dst.Stride
@@ -390,72 +416,46 @@ func drawNRGBASrc(dst *image.RGBA, r image.Rectangle, src *image.NRGBA, sp image
 	}
 }
 
-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
-			}
+func drawGray(dst *image.RGBA, r image.Rectangle, src *image.Gray, sp image.Point) {
+	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
+	yMax := r.Max.Y - dst.Rect.Min.Y
+
+	y := r.Min.Y - dst.Rect.Min.Y
+	sy := sp.Y - src.Rect.Min.Y
+	for ; y != yMax; y, sy = y+1, sy+1 {
+		dpix := dst.Pix[y*dst.Stride:]
+		spix := src.Pix[sy*src.Stride:]
+
+		for i, si := i0, si0; i < i1; i, si = i+4, si+1 {
+			p := spix[si]
+			dpix[i+0] = p
+			dpix[i+1] = p
+			dpix[i+2] = p
+			dpix[i+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
-			}
+	}
+}
+
+func drawCMYK(dst *image.RGBA, r image.Rectangle, src *image.CMYK, sp image.Point) {
+	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
+	yMax := r.Max.Y - dst.Rect.Min.Y
+
+	y := r.Min.Y - dst.Rect.Min.Y
+	sy := sp.Y - src.Rect.Min.Y
+	for ; y != yMax; y, sy = y+1, sy+1 {
+		dpix := dst.Pix[y*dst.Stride:]
+		spix := src.Pix[sy*src.Stride:]
+
+		for i, si := i0, si0; i < i1; i, si = i+4, si+4 {
+			dpix[i+0], dpix[i+1], dpix[i+2] =
+				color.CMYKToRGB(spix[si+0], spix[si+1], spix[si+2], spix[si+3])
+			dpix[i+3] = 255
 		}
-	default:
-		return false
 	}
-	return true
 }
 
 func drawGlyphOver(dst *image.RGBA, r image.Rectangle, src *image.Uniform, mask *image.Alpha, mp image.Point) {
@@ -555,6 +555,20 @@ func clamp(i int32) int32 {
 	return i
 }
 
+// sqDiff returns the squared-difference of x and y, shifted by 2 so that
+// adding four of those won't overflow a uint32.
+//
+// x and y are both assumed to be in the range [0, 0xffff].
+func sqDiff(x, y int32) uint32 {
+	var d uint32
+	if x > y {
+		d = uint32(x - y)
+	} else {
+		d = uint32(y - x)
+	}
+	return (d * d) >> 2
+}
+
 func drawPaletted(dst Image, r image.Rectangle, src image.Image, sp image.Point, floydSteinberg bool) {
 	// TODO(nigeltao): handle the case where the dst and src overlap.
 	// Does it even make sense to try and do Floyd-Steinberg whilst
@@ -564,14 +578,15 @@ func drawPaletted(dst Image, r image.Rectangle, src image.Image, sp image.Point,
 	// dst.At. The dst.Set equivalent is a batch version of the algorithm
 	// used by color.Palette's Index method in image/color/color.go, plus
 	// optional Floyd-Steinberg error diffusion.
-	palette, pix, stride := [][3]int32(nil), []byte(nil), 0
+	palette, pix, stride := [][4]int32(nil), []byte(nil), 0
 	if p, ok := dst.(*image.Paletted); ok {
-		palette = make([][3]int32, len(p.Palette))
+		palette = make([][4]int32, len(p.Palette))
 		for i, col := range p.Palette {
-			r, g, b, _ := col.RGBA()
+			r, g, b, a := col.RGBA()
 			palette[i][0] = int32(r)
 			palette[i][1] = int32(g)
 			palette[i][2] = int32(b)
+			palette[i][3] = int32(a)
 		}
 		pix, stride = p.Pix[p.PixOffset(r.Min.X, r.Min.Y):], p.Stride
 	}
@@ -579,10 +594,10 @@ func drawPaletted(dst Image, r image.Rectangle, src image.Image, sp image.Point,
 	// quantErrorCurr and quantErrorNext are the Floyd-Steinberg quantization
 	// errors that have been propagated to the pixels in the current and next
 	// rows. The +2 simplifies calculation near the edges.
-	var quantErrorCurr, quantErrorNext [][3]int32
+	var quantErrorCurr, quantErrorNext [][4]int32
 	if floydSteinberg {
-		quantErrorCurr = make([][3]int32, r.Dx()+2)
-		quantErrorNext = make([][3]int32, r.Dx()+2)
+		quantErrorCurr = make([][4]int32, r.Dx()+2)
+		quantErrorNext = make([][4]int32, r.Dx()+2)
 	}
 
 	// Loop over each source pixel.
@@ -591,30 +606,25 @@ func drawPaletted(dst Image, r image.Rectangle, src image.Image, sp image.Point,
 		for x := 0; x != r.Dx(); x++ {
 			// er, eg and eb are the pixel's R,G,B values plus the
 			// optional Floyd-Steinberg error.
-			sr, sg, sb, _ := src.At(sp.X+x, sp.Y+y).RGBA()
-			er, eg, eb := int32(sr), int32(sg), int32(sb)
+			sr, sg, sb, sa := src.At(sp.X+x, sp.Y+y).RGBA()
+			er, eg, eb, ea := int32(sr), int32(sg), int32(sb), int32(sa)
 			if floydSteinberg {
 				er = clamp(er + quantErrorCurr[x+1][0]/16)
 				eg = clamp(eg + quantErrorCurr[x+1][1]/16)
 				eb = clamp(eb + quantErrorCurr[x+1][2]/16)
+				ea = clamp(ea + quantErrorCurr[x+1][3]/16)
 			}
 
 			if palette != nil {
-				// Find the closest palette color in Euclidean R,G,B space: the
-				// one that minimizes sum-squared-difference. We shift by 1 bit
-				// to avoid potential uint32 overflow in sum-squared-difference.
+				// Find the closest palette color in Euclidean R,G,B,A space:
+				// the one that minimizes sum-squared-difference.
 				// TODO(nigeltao): consider smarter algorithms.
-				bestIndex, bestSSD := 0, uint32(1<<32-1)
+				bestIndex, bestSum := 0, uint32(1<<32-1)
 				for index, p := range palette {
-					delta := (er - p[0]) >> 1
-					ssd := uint32(delta * delta)
-					delta = (eg - p[1]) >> 1
-					ssd += uint32(delta * delta)
-					delta = (eb - p[2]) >> 1
-					ssd += uint32(delta * delta)
-					if ssd < bestSSD {
-						bestIndex, bestSSD = index, ssd
-						if ssd == 0 {
+					sum := sqDiff(er, p[0]) + sqDiff(eg, p[1]) + sqDiff(eb, p[2]) + sqDiff(ea, p[3])
+					if sum < bestSum {
+						bestIndex, bestSum = index, sum
+						if sum == 0 {
 							break
 						}
 					}
@@ -627,11 +637,13 @@ func drawPaletted(dst Image, r image.Rectangle, src image.Image, sp image.Point,
 				er -= int32(palette[bestIndex][0])
 				eg -= int32(palette[bestIndex][1])
 				eb -= int32(palette[bestIndex][2])
+				ea -= int32(palette[bestIndex][3])
 
 			} else {
 				out.R = uint16(er)
 				out.G = uint16(eg)
 				out.B = uint16(eb)
+				out.A = uint16(ea)
 				// The third argument is &out instead of out (and out is
 				// declared outside of the inner loop) to avoid the implicit
 				// conversion to color.Color here allocating memory in the
@@ -641,32 +653,37 @@ func drawPaletted(dst Image, r image.Rectangle, src image.Image, sp image.Point,
 				if !floydSteinberg {
 					continue
 				}
-				sr, sg, sb, _ = dst.At(r.Min.X+x, r.Min.Y+y).RGBA()
+				sr, sg, sb, sa = dst.At(r.Min.X+x, r.Min.Y+y).RGBA()
 				er -= int32(sr)
 				eg -= int32(sg)
 				eb -= int32(sb)
+				ea -= int32(sa)
 			}
 
 			// Propagate the Floyd-Steinberg quantization error.
 			quantErrorNext[x+0][0] += er * 3
 			quantErrorNext[x+0][1] += eg * 3
 			quantErrorNext[x+0][2] += eb * 3
+			quantErrorNext[x+0][3] += ea * 3
 			quantErrorNext[x+1][0] += er * 5
 			quantErrorNext[x+1][1] += eg * 5
 			quantErrorNext[x+1][2] += eb * 5
+			quantErrorNext[x+1][3] += ea * 5
 			quantErrorNext[x+2][0] += er * 1
 			quantErrorNext[x+2][1] += eg * 1
 			quantErrorNext[x+2][2] += eb * 1
+			quantErrorNext[x+2][3] += ea * 1
 			quantErrorCurr[x+2][0] += er * 7
 			quantErrorCurr[x+2][1] += eg * 7
 			quantErrorCurr[x+2][2] += eb * 7
+			quantErrorCurr[x+2][3] += ea * 7
 		}
 
 		// Recycle the quantization error buffers.
 		if floydSteinberg {
 			quantErrorCurr, quantErrorNext = quantErrorNext, quantErrorCurr
 			for i := range quantErrorNext {
-				quantErrorNext[i] = [3]int32{}
+				quantErrorNext[i] = [4]int32{}
 			}
 		}
 	}
diff --git a/src/image/draw/draw_test.go b/src/image/draw/draw_test.go
index 0dd7fbd..a58f0f4 100644
--- a/src/image/draw/draw_test.go
+++ b/src/image/draw/draw_test.go
@@ -74,6 +74,26 @@ func vgradCr() image.Image {
 	return m
 }
 
+func vgradGray() image.Image {
+	m := image.NewGray(image.Rect(0, 0, 16, 16))
+	for y := 0; y < 16; y++ {
+		for x := 0; x < 16; x++ {
+			m.Set(x, y, color.Gray{uint8(y * 0x11)})
+		}
+	}
+	return m
+}
+
+func vgradMagenta() image.Image {
+	m := image.NewCMYK(image.Rect(0, 0, 16, 16))
+	for y := 0; y < 16; y++ {
+		for x := 0; x < 16; x++ {
+			m.Set(x, y, color.CMYK{0, uint8(y * 0x11), 0, 0x3f})
+		}
+	}
+	return m
+}
+
 func hgradRed(alpha int) Image {
 	m := image.NewRGBA(image.Rect(0, 0, 16, 16))
 	for y := 0; y < 16; y++ {
@@ -147,6 +167,26 @@ var drawTests = []drawTest{
 	{"ycbcrAlphaSrc", vgradCr(), fillAlpha(192), Src, color.RGBA{8, 28, 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.
+	// At (x, y) == (8, 8):
+	// The destination pixel is {136, 0, 0, 255}.
+	// The source pixel is {136} in Gray-space, which is {136, 136, 136, 255} in RGBA-space.
+	{"gray", vgradGray(), fillAlpha(255), Over, color.RGBA{136, 136, 136, 255}},
+	{"graySrc", vgradGray(), fillAlpha(255), Src, color.RGBA{136, 136, 136, 255}},
+	{"grayAlpha", vgradGray(), fillAlpha(192), Over, color.RGBA{136, 102, 102, 255}},
+	{"grayAlphaSrc", vgradGray(), fillAlpha(192), Src, color.RGBA{102, 102, 102, 192}},
+	{"grayNil", vgradGray(), nil, Over, color.RGBA{136, 136, 136, 255}},
+	{"grayNilSrc", vgradGray(), nil, Src, color.RGBA{136, 136, 136, 255}},
+	// Uniform mask (100%, 75%, nil) and variable CMYK source.
+	// At (x, y) == (8, 8):
+	// The destination pixel is {136, 0, 0, 255}.
+	// The source pixel is {0, 136, 0, 63} in CMYK-space, which is {192, 89, 192} in RGB-space.
+	{"cmyk", vgradMagenta(), fillAlpha(255), Over, color.RGBA{192, 89, 192, 255}},
+	{"cmykSrc", vgradMagenta(), fillAlpha(255), Src, color.RGBA{192, 89, 192, 255}},
+	{"cmykAlpha", vgradMagenta(), fillAlpha(192), Over, color.RGBA{178, 67, 145, 255}},
+	{"cmykAlphaSrc", vgradMagenta(), fillAlpha(192), Src, color.RGBA{145, 67, 145, 192}},
+	{"cmykNil", vgradMagenta(), nil, Over, color.RGBA{192, 89, 192, 255}},
+	{"cmykNilSrc", vgradMagenta(), nil, Src, color.RGBA{192, 89, 192, 255}},
 	// Variable mask and variable source.
 	// At (x, y) == (8, 8):
 	// The destination pixel is {136, 0, 0, 255}.
diff --git a/src/image/geom.go b/src/image/geom.go
index 6ebaf67..e1cd4dc 100644
--- a/src/image/geom.go
+++ b/src/image/geom.go
@@ -5,6 +5,7 @@
 package image
 
 import (
+	"image/color"
 	"strconv"
 )
 
@@ -62,7 +63,7 @@ func (p Point) Mod(r Rectangle) Point {
 
 // Eq reports whether p and q are equal.
 func (p Point) Eq(q Point) bool {
-	return p.X == q.X && p.Y == q.Y
+	return p == q
 }
 
 // ZP is the zero Point.
@@ -77,6 +78,10 @@ func Pt(X, Y int) Point {
 // 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
 }
@@ -164,6 +169,12 @@ func (r Rectangle) Intersect(s Rectangle) Rectangle {
 
 // Union returns the smallest rectangle that contains both r and s.
 func (r Rectangle) Union(s Rectangle) Rectangle {
+	if r.Empty() {
+		return s
+	}
+	if s.Empty() {
+		return r
+	}
 	if r.Min.X > s.Min.X {
 		r.Min.X = s.Min.X
 	}
@@ -184,15 +195,16 @@ func (r Rectangle) Empty() bool {
 	return r.Min.X >= r.Max.X || r.Min.Y >= r.Max.Y
 }
 
-// Eq reports whether r and s are equal.
+// Eq reports whether r and s contain the same set of points. All empty
+// rectangles are considered equal.
 func (r Rectangle) Eq(s Rectangle) bool {
-	return r.Min.X == s.Min.X && r.Min.Y == s.Min.Y &&
-		r.Max.X == s.Max.X && r.Max.Y == s.Max.Y
+	return r == s || r.Empty() && s.Empty()
 }
 
 // Overlaps reports whether r and s have a non-empty intersection.
 func (r Rectangle) Overlaps(s Rectangle) bool {
-	return r.Min.X < s.Max.X && s.Min.X < r.Max.X &&
+	return !r.Empty() && !s.Empty() &&
+		r.Min.X < s.Max.X && s.Min.X < r.Max.X &&
 		r.Min.Y < s.Max.Y && s.Min.Y < r.Max.Y
 }
 
@@ -219,10 +231,30 @@ func (r Rectangle) Canon() Rectangle {
 	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
 
-// Rect is shorthand for Rectangle{Pt(x0, y0), Pt(x1, y1)}.
+// Rect is shorthand for Rectangle{Pt(x0, y0), Pt(x1, y1)}. The returned
+// rectangle has minimum and maximum coordinates swapped if necessary so that
+// it is well-formed.
 func Rect(x0, y0, x1, y1 int) Rectangle {
 	if x0 > x1 {
 		x0, x1 = x1, x0
diff --git a/src/image/geom_test.go b/src/image/geom_test.go
new file mode 100644
index 0000000..6e9c6a1
--- /dev/null
+++ b/src/image/geom_test.go
@@ -0,0 +1,115 @@
+// 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 image
+
+import (
+	"fmt"
+	"testing"
+)
+
+func TestRectangle(t *testing.T) {
+	// in checks that every point in f is in g.
+	in := func(f, g Rectangle) error {
+		if !f.In(g) {
+			return fmt.Errorf("f=%s, f.In(%s): got false, want true", f, g)
+		}
+		for y := f.Min.Y; y < f.Max.Y; y++ {
+			for x := f.Min.X; x < f.Max.X; x++ {
+				p := Point{x, y}
+				if !p.In(g) {
+					return fmt.Errorf("p=%s, p.In(%s): got false, want true", p, g)
+				}
+			}
+		}
+		return nil
+	}
+
+	rects := []Rectangle{
+		Rect(0, 0, 10, 10),
+		Rect(1, 2, 3, 4),
+		Rect(4, 6, 10, 10),
+		Rect(2, 3, 12, 5),
+		Rect(-1, -2, 0, 0),
+		Rect(-1, -2, 4, 6),
+		Rect(-10, -20, 30, 40),
+		Rect(8, 8, 8, 8),
+		Rect(88, 88, 88, 88),
+		Rect(6, 5, 4, 3),
+	}
+
+	// r.Eq(s) should be equivalent to every point in r being in s, and every
+	// point in s being in r.
+	for _, r := range rects {
+		for _, s := range rects {
+			got := r.Eq(s)
+			want := in(r, s) == nil && in(s, r) == nil
+			if got != want {
+				t.Errorf("Eq: r=%s, s=%s: got %t, want %t", r, s, got, want)
+			}
+		}
+	}
+
+	// The intersection should be the largest rectangle a such that every point
+	// in a is both in r and in s.
+	for _, r := range rects {
+		for _, s := range rects {
+			a := r.Intersect(s)
+			if err := in(a, r); err != nil {
+				t.Errorf("Intersect: r=%s, s=%s, a=%s, a not in r: %v", r, s, a, err)
+			}
+			if err := in(a, s); err != nil {
+				t.Errorf("Intersect: r=%s, s=%s, a=%s, a not in s: %v", r, s, a, err)
+			}
+			if a.Empty() == r.Overlaps(s) {
+				t.Errorf("Intersect: r=%s, s=%s, a=%s: empty=%t same as overlaps=%t",
+					r, s, a, a.Empty(), r.Overlaps(s))
+			}
+			largerThanA := [4]Rectangle{a, a, a, a}
+			largerThanA[0].Min.X--
+			largerThanA[1].Min.Y--
+			largerThanA[2].Max.X++
+			largerThanA[3].Max.Y++
+			for i, b := range largerThanA {
+				if b.Empty() {
+					// b isn't actually larger than a.
+					continue
+				}
+				if in(b, r) == nil && in(b, s) == nil {
+					t.Errorf("Intersect: r=%s, s=%s, a=%s, b=%s, i=%d: intersection could be larger",
+						r, s, a, b, i)
+				}
+			}
+		}
+	}
+
+	// The union should be the smallest rectangle a such that every point in r
+	// is in a and every point in s is in a.
+	for _, r := range rects {
+		for _, s := range rects {
+			a := r.Union(s)
+			if err := in(r, a); err != nil {
+				t.Errorf("Union: r=%s, s=%s, a=%s, r not in a: %v", r, s, a, err)
+			}
+			if err := in(s, a); err != nil {
+				t.Errorf("Union: r=%s, s=%s, a=%s, s not in a: %v", r, s, a, err)
+			}
+			if a.Empty() {
+				// You can't get any smaller than a.
+				continue
+			}
+			smallerThanA := [4]Rectangle{a, a, a, a}
+			smallerThanA[0].Min.X++
+			smallerThanA[1].Min.Y++
+			smallerThanA[2].Max.X--
+			smallerThanA[3].Max.Y--
+			for i, b := range smallerThanA {
+				if in(r, b) == nil && in(s, b) == nil {
+					t.Errorf("Union: r=%s, s=%s, a=%s, b=%s, i=%d: union could be smaller",
+						r, s, a, b, i)
+				}
+			}
+		}
+	}
+}
diff --git a/src/image/gif/reader.go b/src/image/gif/reader.go
index 5a863e2..6a13312 100644
--- a/src/image/gif/reader.go
+++ b/src/image/gif/reader.go
@@ -32,15 +32,20 @@ type reader interface {
 // Masks etc.
 const (
 	// Fields.
-	fColorMapFollows = 1 << 7
-
-	// Image fields.
-	ifLocalColorTable = 1 << 7
-	ifInterlace       = 1 << 6
-	ifPixelSizeMask   = 7
+	fColorTable         = 1 << 7
+	fInterlace          = 1 << 6
+	fColorTableBitsMask = 7
 
 	// Graphic control flags.
 	gcTransparentColorSet = 1 << 0
+	gcDisposalMethodMask  = 7 << 2
+)
+
+// Disposal Methods.
+const (
+	DisposalNone       = 0x01
+	DisposalBackground = 0x02
+	DisposalPrevious   = 0x03
 )
 
 // Section indicators.
@@ -66,14 +71,10 @@ type decoder struct {
 	vers            string
 	width           int
 	height          int
-	flags           byte
-	headerFields    byte
-	backgroundIndex byte
 	loopCount       int
 	delayTime       int
-
-	// Unused from header.
-	aspect byte
+	backgroundIndex byte
+	disposalMethod  byte
 
 	// From image descriptor.
 	imageFields byte
@@ -83,13 +84,13 @@ type decoder struct {
 	hasTransparentIndex bool
 
 	// Computed.
-	pixelSize      uint
-	globalColorMap color.Palette
+	globalColorTable color.Palette
 
 	// Used when decoding.
-	delay []int
-	image []*image.Paletted
-	tmp   [1024]byte // must be at least 768 so we can read color map
+	delay    []int
+	disposal []byte
+	image    []*image.Paletted
+	tmp      [1024]byte // must be at least 768 so we can read color table
 }
 
 // blockReader parses the block structure of GIF image data, which
@@ -122,7 +123,7 @@ func (b *blockReader) Read(p []byte) (int, error) {
 			b.err = io.EOF
 			return 0, b.err
 		}
-		b.slice = b.tmp[0:blockLen]
+		b.slice = b.tmp[:blockLen]
 		if _, b.err = io.ReadFull(b.r, b.slice); b.err != nil {
 			return 0, b.err
 		}
@@ -149,12 +150,6 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error {
 		return nil
 	}
 
-	if d.headerFields&fColorMapFollows != 0 {
-		if d.globalColorMap, err = d.readColorMap(); err != nil {
-			return err
-		}
-	}
-
 	for {
 		c, err := d.r.ReadByte()
 		if err != nil {
@@ -171,19 +166,22 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error {
 			if err != nil {
 				return err
 			}
-			useLocalColorMap := d.imageFields&fColorMapFollows != 0
-			if useLocalColorMap {
-				m.Palette, err = d.readColorMap()
+			useLocalColorTable := d.imageFields&fColorTable != 0
+			if useLocalColorTable {
+				m.Palette, err = d.readColorTable(d.imageFields)
 				if err != nil {
 					return err
 				}
 			} else {
-				m.Palette = d.globalColorMap
+				if d.globalColorTable == nil {
+					return errors.New("gif: no color table")
+				}
+				m.Palette = d.globalColorTable
 			}
 			if d.hasTransparentIndex && int(d.transparentIndex) < len(m.Palette) {
-				if !useLocalColorMap {
-					// Clone the global color map.
-					m.Palette = append(color.Palette(nil), d.globalColorMap...)
+				if !useLocalColorTable {
+					// Clone the global color table.
+					m.Palette = append(color.Palette(nil), d.globalColorTable...)
 				}
 				m.Palette[d.transparentIndex] = color.RGBA{}
 			}
@@ -204,9 +202,18 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error {
 				}
 				return errNotEnough
 			}
-			// Both lzwr and br should be exhausted. Reading from them
-			// should yield (0, io.EOF).
-			if n, err := lzwr.Read(d.tmp[:1]); n != 0 || err != io.EOF {
+			// Both lzwr and br should be exhausted. Reading from them should
+			// yield (0, io.EOF).
+			//
+			// The spec (Appendix F - Compression), says that "An End of
+			// Information code... must be the last code output by the encoder
+			// for an image". In practice, though, giflib (a widely used C
+			// library) does not enforce this, so we also accept lzwr returning
+			// io.ErrUnexpectedEOF (meaning that the encoded stream hit io.EOF
+			// before the LZW decoder saw an explict end code), provided that
+			// the io.ReadFull call above successfully read len(m.Pix) bytes.
+			// See https://golang.org/issue/9856 for an example GIF.
+			if n, err := lzwr.Read(d.tmp[:1]); n != 0 || (err != io.EOF && err != io.ErrUnexpectedEOF) {
 				if err != nil {
 					return err
 				}
@@ -229,12 +236,13 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error {
 			}
 
 			// Undo the interlacing if necessary.
-			if d.imageFields&ifInterlace != 0 {
+			if d.imageFields&fInterlace != 0 {
 				uninterlace(m)
 			}
 
 			d.image = append(d.image, m)
 			d.delay = append(d.delay, d.delayTime)
+			d.disposal = append(d.disposal, d.disposalMethod)
 			// The GIF89a spec, Section 23 (Graphic Control Extension) says:
 			// "The scope of this extension is the first graphic rendering block
 			// to follow." We therefore reset the GCE fields to zero.
@@ -254,44 +262,39 @@ func (d *decoder) decode(r io.Reader, configOnly bool) error {
 }
 
 func (d *decoder) readHeaderAndScreenDescriptor() error {
-	_, err := io.ReadFull(d.r, d.tmp[0:13])
+	_, err := io.ReadFull(d.r, d.tmp[:13])
 	if err != nil {
 		return err
 	}
-	d.vers = string(d.tmp[0:6])
+	d.vers = string(d.tmp[:6])
 	if d.vers != "GIF87a" && d.vers != "GIF89a" {
 		return fmt.Errorf("gif: can't recognize format %s", d.vers)
 	}
 	d.width = int(d.tmp[6]) + int(d.tmp[7])<<8
 	d.height = int(d.tmp[8]) + int(d.tmp[9])<<8
-	d.headerFields = d.tmp[10]
-	d.backgroundIndex = d.tmp[11]
-	d.aspect = d.tmp[12]
-	d.loopCount = -1
-	d.pixelSize = uint(d.headerFields&7) + 1
+	if fields := d.tmp[10]; fields&fColorTable != 0 {
+		d.backgroundIndex = d.tmp[11]
+		// readColorTable overwrites the contents of d.tmp, but that's OK.
+		if d.globalColorTable, err = d.readColorTable(fields); err != nil {
+			return err
+		}
+	}
+	// d.tmp[12] is the Pixel Aspect Ratio, which is ignored.
 	return nil
 }
 
-func (d *decoder) readColorMap() (color.Palette, error) {
-	if d.pixelSize > 8 {
-		return nil, fmt.Errorf("gif: can't handle %d bits per pixel", d.pixelSize)
-	}
-	numColors := 1 << d.pixelSize
-	if d.imageFields&ifLocalColorTable != 0 {
-		numColors = 1 << ((d.imageFields & ifPixelSizeMask) + 1)
-	}
-	numValues := 3 * numColors
-	_, err := io.ReadFull(d.r, d.tmp[0:numValues])
+func (d *decoder) readColorTable(fields byte) (color.Palette, error) {
+	n := 1 << (1 + uint(fields&fColorTableBitsMask))
+	_, err := io.ReadFull(d.r, d.tmp[:3*n])
 	if err != nil {
-		return nil, fmt.Errorf("gif: short read on color map: %s", err)
+		return nil, fmt.Errorf("gif: short read on color table: %s", err)
 	}
-	colorMap := make(color.Palette, numColors)
-	j := 0
-	for i := range colorMap {
-		colorMap[i] = color.RGBA{d.tmp[j+0], d.tmp[j+1], d.tmp[j+2], 0xFF}
+	j, p := 0, make(color.Palette, n)
+	for i := range p {
+		p[i] = color.RGBA{d.tmp[j+0], d.tmp[j+1], d.tmp[j+2], 0xFF}
 		j += 3
 	}
-	return colorMap, nil
+	return p, nil
 }
 
 func (d *decoder) readExtension() error {
@@ -318,7 +321,7 @@ func (d *decoder) readExtension() error {
 		return fmt.Errorf("gif: unknown extension 0x%.2x", extension)
 	}
 	if size > 0 {
-		if _, err := io.ReadFull(d.r, d.tmp[0:size]); err != nil {
+		if _, err := io.ReadFull(d.r, d.tmp[:size]); err != nil {
 			return err
 		}
 	}
@@ -343,12 +346,13 @@ func (d *decoder) readExtension() error {
 }
 
 func (d *decoder) readGraphicControl() error {
-	if _, err := io.ReadFull(d.r, d.tmp[0:6]); err != nil {
+	if _, err := io.ReadFull(d.r, d.tmp[:6]); err != nil {
 		return fmt.Errorf("gif: can't read graphic control: %s", err)
 	}
-	d.flags = d.tmp[1]
+	flags := d.tmp[1]
+	d.disposalMethod = (flags & gcDisposalMethodMask) >> 2
 	d.delayTime = int(d.tmp[2]) | int(d.tmp[3])<<8
-	if d.flags&gcTransparentColorSet != 0 {
+	if flags&gcTransparentColorSet != 0 {
 		d.transparentIndex = d.tmp[4]
 		d.hasTransparentIndex = true
 	}
@@ -356,7 +360,7 @@ func (d *decoder) readGraphicControl() error {
 }
 
 func (d *decoder) newImageFromDescriptor() (*image.Paletted, error) {
-	if _, err := io.ReadFull(d.r, d.tmp[0:9]); err != nil {
+	if _, err := io.ReadFull(d.r, d.tmp[:9]); err != nil {
 		return nil, fmt.Errorf("gif: can't read image descriptor: %s", err)
 	}
 	left := int(d.tmp[0]) + int(d.tmp[1])<<8
@@ -380,7 +384,7 @@ func (d *decoder) readBlock() (int, error) {
 	if n == 0 || err != nil {
 		return 0, err
 	}
-	return io.ReadFull(d.r, d.tmp[0:n])
+	return io.ReadFull(d.r, d.tmp[:n])
 }
 
 // interlaceScan defines the ordering for a pass of the interlace algorithm.
@@ -429,6 +433,24 @@ type GIF struct {
 	Image     []*image.Paletted // The successive images.
 	Delay     []int             // The successive delay times, one per frame, in 100ths of a second.
 	LoopCount int               // The loop count.
+	// Disposal is the successive disposal methods, one per frame. For
+	// backwards compatibility, a nil Disposal is valid to pass to EncodeAll,
+	// and implies that each frame's disposal method is 0 (no disposal
+	// specified).
+	Disposal []byte
+	// Config is the global color table (palette), width and height. A nil or
+	// empty-color.Palette Config.ColorModel means that each frame has its own
+	// color table and there is no global color table. Each frame's bounds must
+	// be within the rectangle defined by the two points (0, 0) and
+	// (Config.Width, Config.Height).
+	//
+	// For backwards compatibility, a zero-valued Config is valid to pass to
+	// EncodeAll, and implies that the overall GIF's width and height equals
+	// the first frame's bounds' Rectangle.Max point.
+	Config image.Config
+	// BackgroundIndex is the background index in the global color table, for
+	// use with the DisposalBackground disposal method.
+	BackgroundIndex byte
 }
 
 // DecodeAll reads a GIF image from r and returns the sequential frames
@@ -442,6 +464,13 @@ func DecodeAll(r io.Reader) (*GIF, error) {
 		Image:     d.image,
 		LoopCount: d.loopCount,
 		Delay:     d.delay,
+		Disposal:  d.disposal,
+		Config: image.Config{
+			ColorModel: d.globalColorTable,
+			Width:      d.width,
+			Height:     d.height,
+		},
+		BackgroundIndex: d.backgroundIndex,
 	}
 	return gif, nil
 }
@@ -454,7 +483,7 @@ func DecodeConfig(r io.Reader) (image.Config, error) {
 		return image.Config{}, err
 	}
 	return image.Config{
-		ColorModel: d.globalColorMap,
+		ColorModel: d.globalColorTable,
 		Width:      d.width,
 		Height:     d.height,
 	}, nil
diff --git a/src/image/gif/reader_test.go b/src/image/gif/reader_test.go
index 7b6f504..c294195 100644
--- a/src/image/gif/reader_test.go
+++ b/src/image/gif/reader_test.go
@@ -17,8 +17,8 @@ import (
 const (
 	headerStr = "GIF89a" +
 		"\x02\x00\x01\x00" + // width=2, height=1
-		"\x80\x00\x00" // headerFields=(a color map of 2 pixels), backgroundIndex, aspect
-	paletteStr = "\x10\x20\x30\x40\x50\x60" // the color map, also known as a palette
+		"\x80\x00\x00" // headerFields=(a color table of 2 pixels), backgroundIndex, aspect
+	paletteStr = "\x10\x20\x30\x40\x50\x60" // the color table, also known as a palette
 	trailerStr = "\x3b"
 )
 
@@ -141,7 +141,7 @@ var testGIF = []byte{
 	'G', 'I', 'F', '8', '9', 'a',
 	1, 0, 1, 0, // w=1, h=1 (6)
 	128, 0, 0, // headerFields, bg, aspect (10)
-	0, 0, 0, 1, 1, 1, // color map and graphics control (13)
+	0, 0, 0, 1, 1, 1, // color table and graphics control (13)
 	0x21, 0xf9, 0x04, 0x00, 0x00, 0x00, 0xff, 0x00, // (19)
 	// frame 1 (0,0 - 1,1)
 	0x2c,
@@ -200,22 +200,26 @@ func TestNoPalette(t *testing.T) {
 	b.WriteString("\x2c\x00\x00\x00\x00\x02\x00\x01\x00\x00\x02")
 
 	// Encode the pixels: neither is in range, because there is no palette.
-	pix := []byte{0, 128}
+	pix := []byte{0, 3}
 	enc := &bytes.Buffer{}
 	w := lzw.NewWriter(enc, lzw.LSB, 2)
-	w.Write(pix)
-	w.Close()
+	if _, err := w.Write(pix); err != nil {
+		t.Fatalf("Write: %v", err)
+	}
+	if err := w.Close(); err != nil {
+		t.Fatalf("Close: %v", err)
+	}
 	b.WriteByte(byte(len(enc.Bytes())))
 	b.Write(enc.Bytes())
 	b.WriteByte(0x00) // An empty block signifies the end of the image data.
 
 	b.WriteString(trailerStr)
 
-	try(t, b.Bytes(), "gif: invalid pixel value")
+	try(t, b.Bytes(), "gif: no color table")
 }
 
 func TestPixelOutsidePaletteRange(t *testing.T) {
-	for _, pval := range []byte{0, 1, 2, 3, 255} {
+	for _, pval := range []byte{0, 1, 2, 3} {
 		b := &bytes.Buffer{}
 
 		// Manufacture a GIF with a 2 color palette.
@@ -229,8 +233,12 @@ func TestPixelOutsidePaletteRange(t *testing.T) {
 		pix := []byte{pval, pval}
 		enc := &bytes.Buffer{}
 		w := lzw.NewWriter(enc, lzw.LSB, 2)
-		w.Write(pix)
-		w.Close()
+		if _, err := w.Write(pix); err != nil {
+			t.Fatalf("Write: %v", err)
+		}
+		if err := w.Close(); err != nil {
+			t.Fatalf("Close: %v", err)
+		}
 		b.WriteByte(byte(len(enc.Bytes())))
 		b.Write(enc.Bytes())
 		b.WriteByte(0x00) // An empty block signifies the end of the image data.
@@ -245,3 +253,24 @@ func TestPixelOutsidePaletteRange(t *testing.T) {
 		try(t, b.Bytes(), want)
 	}
 }
+
+func TestLoopCount(t *testing.T) {
+	data := []byte("GIF89a000\x00000,0\x00\x00\x00\n\x00" +
+		"\n\x00\x80000000\x02\b\xf01u\xb9\xfdal\x05\x00;")
+	img, err := DecodeAll(bytes.NewReader(data))
+	if err != nil {
+		t.Fatal("DecodeAll:", err)
+	}
+	w := new(bytes.Buffer)
+	err = EncodeAll(w, img)
+	if err != nil {
+		t.Fatal("EncodeAll:", err)
+	}
+	img1, err := DecodeAll(w)
+	if err != nil {
+		t.Fatal("DecodeAll:", err)
+	}
+	if img.LoopCount != img1.LoopCount {
+		t.Errorf("loop count mismatch: %d vs %d", img.LoopCount, img1.LoopCount)
+	}
+}
diff --git a/src/image/gif/writer.go b/src/image/gif/writer.go
index 49abde7..dd31790 100644
--- a/src/image/gif/writer.go
+++ b/src/image/gif/writer.go
@@ -6,6 +6,7 @@ package gif
 
 import (
 	"bufio"
+	"bytes"
 	"compress/lzw"
 	"errors"
 	"image"
@@ -52,9 +53,13 @@ type encoder struct {
 	w   writer
 	err error
 	// g is a reference to the data that is being encoded.
-	g *GIF
-	// buf is a scratch buffer. It must be at least 768 so we can write the color map.
-	buf [1024]byte
+	g GIF
+	// globalCT is the size in bytes of the global color table.
+	globalCT int
+	// buf is a scratch buffer. It must be at least 256 for the blockWriter.
+	buf              [256]byte
+	globalColorTable [3 * 256]byte
+	localColorTable  [3 * 256]byte
 }
 
 // blockWriter writes the block structure of GIF image data, which
@@ -116,18 +121,27 @@ func (e *encoder) writeHeader() {
 		return
 	}
 
-	pm := e.g.Image[0]
 	// Logical screen width and height.
-	writeUint16(e.buf[0:2], uint16(pm.Bounds().Dx()))
-	writeUint16(e.buf[2:4], uint16(pm.Bounds().Dy()))
+	writeUint16(e.buf[0:2], uint16(e.g.Config.Width))
+	writeUint16(e.buf[2:4], uint16(e.g.Config.Height))
 	e.write(e.buf[:4])
 
-	// All frames have a local color table, so a global color table
-	// is not needed.
-	e.buf[0] = 0x00
-	e.buf[1] = 0x00 // Background Color Index.
-	e.buf[2] = 0x00 // Pixel Aspect Ratio.
-	e.write(e.buf[:3])
+	if p, ok := e.g.Config.ColorModel.(color.Palette); ok && len(p) > 0 {
+		paddedSize := log2(len(p)) // Size of Global Color Table: 2^(1+n).
+		e.buf[0] = fColorTable | uint8(paddedSize)
+		e.buf[1] = e.g.BackgroundIndex
+		e.buf[2] = 0x00 // Pixel Aspect Ratio.
+		e.write(e.buf[:3])
+		e.globalCT = encodeColorTable(e.globalColorTable[:], p, paddedSize)
+		e.write(e.globalColorTable[:e.globalCT])
+	} else {
+		// All frames have a local color table, so a global color table
+		// is not needed.
+		e.buf[0] = 0x00
+		e.buf[1] = 0x00 // Background Color Index.
+		e.buf[2] = 0x00 // Pixel Aspect Ratio.
+		e.write(e.buf[:3])
+	}
 
 	// Add animation info if necessary.
 	if len(e.g.Image) > 1 {
@@ -147,28 +161,25 @@ func (e *encoder) writeHeader() {
 	}
 }
 
-func (e *encoder) writeColorTable(p color.Palette, size int) {
-	if e.err != nil {
-		return
-	}
-
-	for i := 0; i < log2Lookup[size]; i++ {
+func encodeColorTable(dst []byte, p color.Palette, size int) int {
+	n := log2Lookup[size]
+	for i := 0; i < n; i++ {
 		if i < len(p) {
 			r, g, b, _ := p[i].RGBA()
-			e.buf[3*i+0] = uint8(r >> 8)
-			e.buf[3*i+1] = uint8(g >> 8)
-			e.buf[3*i+2] = uint8(b >> 8)
+			dst[3*i+0] = uint8(r >> 8)
+			dst[3*i+1] = uint8(g >> 8)
+			dst[3*i+2] = uint8(b >> 8)
 		} else {
 			// Pad with black.
-			e.buf[3*i+0] = 0x00
-			e.buf[3*i+1] = 0x00
-			e.buf[3*i+2] = 0x00
+			dst[3*i+0] = 0x00
+			dst[3*i+1] = 0x00
+			dst[3*i+2] = 0x00
 		}
 	}
-	e.write(e.buf[:3*log2Lookup[size]])
+	return 3 * n
 }
 
-func (e *encoder) writeImageBlock(pm *image.Paletted, delay int) {
+func (e *encoder) writeImageBlock(pm *image.Paletted, delay int, disposal byte) {
 	if e.err != nil {
 		return
 	}
@@ -179,10 +190,14 @@ func (e *encoder) writeImageBlock(pm *image.Paletted, delay int) {
 	}
 
 	b := pm.Bounds()
-	if b.Dx() >= 1<<16 || b.Dy() >= 1<<16 || b.Min.X < 0 || b.Min.X >= 1<<16 || b.Min.Y < 0 || b.Min.Y >= 1<<16 {
+	if b.Min.X < 0 || b.Max.X >= 1<<16 || b.Min.Y < 0 || b.Max.Y >= 1<<16 {
 		e.err = errors.New("gif: image block is too large to encode")
 		return
 	}
+	if !b.In(image.Rectangle{Max: image.Point{e.g.Config.Width, e.g.Config.Height}}) {
+		e.err = errors.New("gif: image block is out of bounds")
+		return
+	}
 
 	transparentIndex := -1
 	for i, c := range pm.Palette {
@@ -192,14 +207,14 @@ func (e *encoder) writeImageBlock(pm *image.Paletted, delay int) {
 		}
 	}
 
-	if delay > 0 || transparentIndex != -1 {
+	if delay > 0 || disposal != 0 || transparentIndex != -1 {
 		e.buf[0] = sExtension  // Extension Introducer.
 		e.buf[1] = gcLabel     // Graphic Control Label.
 		e.buf[2] = gcBlockSize // Block Size.
 		if transparentIndex != -1 {
-			e.buf[3] = 0x01
+			e.buf[3] = 0x01 | disposal<<2
 		} else {
-			e.buf[3] = 0x00
+			e.buf[3] = 0x00 | disposal<<2
 		}
 		writeUint16(e.buf[4:6], uint16(delay)) // Delay Time (1/100ths of a second)
 
@@ -220,11 +235,15 @@ func (e *encoder) writeImageBlock(pm *image.Paletted, delay int) {
 	e.write(e.buf[:9])
 
 	paddedSize := log2(len(pm.Palette)) // Size of Local Color Table: 2^(1+n).
-	// Interlacing is not supported.
-	e.writeByte(0x80 | uint8(paddedSize))
-
-	// Local Color Table.
-	e.writeColorTable(pm.Palette, paddedSize)
+	ct := encodeColorTable(e.localColorTable[:], pm.Palette, paddedSize)
+	if ct != e.globalCT || !bytes.Equal(e.globalColorTable[:ct], e.localColorTable[:ct]) {
+		// Use a local color table.
+		e.writeByte(fColorTable | uint8(paddedSize))
+		e.write(e.localColorTable[:ct])
+	} else {
+		// Use the global color table.
+		e.writeByte(0)
+	}
 
 	litWidth := paddedSize + 1
 	if litWidth < 2 {
@@ -281,7 +300,23 @@ func EncodeAll(w io.Writer, g *GIF) error {
 		g.LoopCount = 0
 	}
 
-	e := encoder{g: g}
+	e := encoder{g: *g}
+	// The GIF.Disposal, GIF.Config and GIF.BackgroundIndex fields were added
+	// in Go 1.5. Valid Go 1.4 code, such as when the Disposal field is omitted
+	// in a GIF struct literal, should still produce valid GIFs.
+	if e.g.Disposal != nil && len(e.g.Image) != len(e.g.Disposal) {
+		return errors.New("gif: mismatched image and disposal lengths")
+	}
+	if e.g.Config == (image.Config{}) {
+		p := g.Image[0].Bounds().Max
+		e.g.Config.Width = p.X
+		e.g.Config.Height = p.Y
+	} else if e.g.Config.ColorModel != nil {
+		if _, ok := e.g.Config.ColorModel.(color.Palette); !ok {
+			return errors.New("gif: GIF color model must be a color.Palette")
+		}
+	}
+
 	if ww, ok := w.(writer); ok {
 		e.w = ww
 	} else {
@@ -290,7 +325,11 @@ func EncodeAll(w io.Writer, g *GIF) error {
 
 	e.writeHeader()
 	for i, pm := range g.Image {
-		e.writeImageBlock(pm, g.Delay[i])
+		disposal := uint8(0)
+		if g.Disposal != nil {
+			disposal = g.Disposal[i]
+		}
+		e.writeImageBlock(pm, g.Delay[i], disposal)
 	}
 	e.writeByte(sTrailer)
 	e.flush()
@@ -326,8 +365,22 @@ func Encode(w io.Writer, m image.Image, o *Options) error {
 		opts.Drawer.Draw(pm, b, m, image.ZP)
 	}
 
+	// When calling Encode instead of EncodeAll, the single-frame image is
+	// translated such that its top-left corner is (0, 0), so that the single
+	// frame completely fills the overall GIF's bounds.
+	if pm.Rect.Min != (image.Point{}) {
+		dup := *pm
+		dup.Rect = dup.Rect.Sub(dup.Rect.Min)
+		pm = &dup
+	}
+
 	return EncodeAll(w, &GIF{
 		Image: []*image.Paletted{pm},
 		Delay: []int{0},
+		Config: image.Config{
+			ColorModel: pm.Palette,
+			Width:      b.Dx(),
+			Height:     b.Dy(),
+		},
 	})
 }
diff --git a/src/image/gif/writer_test.go b/src/image/gif/writer_test.go
index 93306ff..db61a5c 100644
--- a/src/image/gif/writer_test.go
+++ b/src/image/gif/writer_test.go
@@ -8,10 +8,12 @@ import (
 	"bytes"
 	"image"
 	"image/color"
+	"image/color/palette"
 	_ "image/png"
 	"io/ioutil"
 	"math/rand"
 	"os"
+	"reflect"
 	"testing"
 )
 
@@ -125,55 +127,317 @@ func TestSubImage(t *testing.T) {
 	}
 }
 
+// palettesEqual reports whether two color.Palette values are equal, ignoring
+// any trailing opaque-black palette entries.
+func palettesEqual(p, q color.Palette) bool {
+	n := len(p)
+	if n > len(q) {
+		n = len(q)
+	}
+	for i := 0; i < n; i++ {
+		if p[i] != q[i] {
+			return false
+		}
+	}
+	for i := n; i < len(p); i++ {
+		r, g, b, a := p[i].RGBA()
+		if r != 0 || g != 0 || b != 0 || a != 0xffff {
+			return false
+		}
+	}
+	for i := n; i < len(q); i++ {
+		r, g, b, a := q[i].RGBA()
+		if r != 0 || g != 0 || b != 0 || a != 0xffff {
+			return false
+		}
+	}
+	return true
+}
+
 var frames = []string{
 	"../testdata/video-001.gif",
 	"../testdata/video-005.gray.gif",
 }
 
-func TestEncodeAll(t *testing.T) {
+func testEncodeAll(t *testing.T, go1Dot5Fields bool, useGlobalColorModel bool) {
+	const width, height = 150, 103
+
 	g0 := &GIF{
 		Image:     make([]*image.Paletted, len(frames)),
 		Delay:     make([]int, len(frames)),
 		LoopCount: 5,
 	}
 	for i, f := range frames {
-		m, err := readGIF(f)
+		g, err := readGIF(f)
 		if err != nil {
 			t.Fatal(f, err)
 		}
-		g0.Image[i] = m.Image[0]
+		m := g.Image[0]
+		if m.Bounds().Dx() != width || m.Bounds().Dy() != height {
+			t.Fatalf("frame %d had unexpected bounds: got %v, want width/height = %d/%d",
+				i, m.Bounds(), width, height)
+		}
+		g0.Image[i] = m
 	}
+	// The GIF.Disposal, GIF.Config and GIF.BackgroundIndex fields were added
+	// in Go 1.5. Valid Go 1.4 or earlier code should still produce valid GIFs.
+	//
+	// On the following line, color.Model is an interface type, and
+	// color.Palette is a concrete (slice) type.
+	globalColorModel, backgroundIndex := color.Model(color.Palette(nil)), uint8(0)
+	if useGlobalColorModel {
+		globalColorModel, backgroundIndex = color.Palette(palette.WebSafe), uint8(1)
+	}
+	if go1Dot5Fields {
+		g0.Disposal = make([]byte, len(g0.Image))
+		for i := range g0.Disposal {
+			g0.Disposal[i] = DisposalNone
+		}
+		g0.Config = image.Config{
+			ColorModel: globalColorModel,
+			Width:      width,
+			Height:     height,
+		}
+		g0.BackgroundIndex = backgroundIndex
+	}
+
 	var buf bytes.Buffer
 	if err := EncodeAll(&buf, g0); err != nil {
 		t.Fatal("EncodeAll:", err)
 	}
-	g1, err := DecodeAll(&buf)
+	encoded := buf.Bytes()
+	config, err := DecodeConfig(bytes.NewReader(encoded))
+	if err != nil {
+		t.Fatal("DecodeConfig:", err)
+	}
+	g1, err := DecodeAll(bytes.NewReader(encoded))
 	if err != nil {
 		t.Fatal("DecodeAll:", err)
 	}
+
+	if !reflect.DeepEqual(config, g1.Config) {
+		t.Errorf("DecodeConfig inconsistent with DecodeAll")
+	}
+	if !palettesEqual(g1.Config.ColorModel.(color.Palette), globalColorModel.(color.Palette)) {
+		t.Errorf("unexpected global color model")
+	}
+	if w, h := g1.Config.Width, g1.Config.Height; w != width || h != height {
+		t.Errorf("got config width * height = %d * %d, want %d * %d", w, h, width, height)
+	}
+
 	if g0.LoopCount != g1.LoopCount {
 		t.Errorf("loop counts differ: %d and %d", g0.LoopCount, g1.LoopCount)
 	}
+	if backgroundIndex != g1.BackgroundIndex {
+		t.Errorf("background indexes differ: %d and %d", backgroundIndex, g1.BackgroundIndex)
+	}
+	if len(g0.Image) != len(g1.Image) {
+		t.Fatalf("image lengths differ: %d and %d", len(g0.Image), len(g1.Image))
+	}
+	if len(g1.Image) != len(g1.Delay) {
+		t.Fatalf("image and delay lengths differ: %d and %d", len(g1.Image), len(g1.Delay))
+	}
+	if len(g1.Image) != len(g1.Disposal) {
+		t.Fatalf("image and disposal lengths differ: %d and %d", len(g1.Image), len(g1.Disposal))
+	}
+
 	for i := range g0.Image {
 		m0, m1 := g0.Image[i], g1.Image[i]
 		if m0.Bounds() != m1.Bounds() {
-			t.Errorf("%s, bounds differ: %v and %v", frames[i], m0.Bounds(), m1.Bounds())
+			t.Errorf("frame %d: bounds differ: %v and %v", i, m0.Bounds(), m1.Bounds())
 		}
 		d0, d1 := g0.Delay[i], g1.Delay[i]
 		if d0 != d1 {
-			t.Errorf("%s: delay values differ: %d and %d", frames[i], d0, d1)
+			t.Errorf("frame %d: delay values differ: %d and %d", i, d0, d1)
+		}
+		p0, p1 := uint8(0), g1.Disposal[i]
+		if go1Dot5Fields {
+			p0 = DisposalNone
+		}
+		if p0 != p1 {
+			t.Errorf("frame %d: disposal values differ: %d and %d", i, p0, p1)
 		}
 	}
+}
 
-	g1.Delay = make([]int, 1)
-	if err := EncodeAll(ioutil.Discard, g1); err == nil {
+func TestEncodeAllGo1Dot4(t *testing.T)                 { testEncodeAll(t, false, false) }
+func TestEncodeAllGo1Dot5(t *testing.T)                 { testEncodeAll(t, true, false) }
+func TestEncodeAllGo1Dot5GlobalColorModel(t *testing.T) { testEncodeAll(t, true, true) }
+
+func TestEncodeMismatchDelay(t *testing.T) {
+	images := make([]*image.Paletted, 2)
+	for i := range images {
+		images[i] = image.NewPaletted(image.Rect(0, 0, 5, 5), palette.Plan9)
+	}
+
+	g0 := &GIF{
+		Image: images,
+		Delay: make([]int, 1),
+	}
+	if err := EncodeAll(ioutil.Discard, g0); err == nil {
 		t.Error("expected error from mismatched delay and image slice lengths")
 	}
+
+	g1 := &GIF{
+		Image:    images,
+		Delay:    make([]int, len(images)),
+		Disposal: make([]byte, 1),
+	}
+	for i := range g1.Disposal {
+		g1.Disposal[i] = DisposalNone
+	}
+	if err := EncodeAll(ioutil.Discard, g1); err == nil {
+		t.Error("expected error from mismatched disposal and image slice lengths")
+	}
+}
+
+func TestEncodeZeroGIF(t *testing.T) {
 	if err := EncodeAll(ioutil.Discard, &GIF{}); err == nil {
 		t.Error("expected error from providing empty gif")
 	}
 }
 
+func TestEncodeAllFramesOutOfBounds(t *testing.T) {
+	images := []*image.Paletted{
+		image.NewPaletted(image.Rect(0, 0, 5, 5), palette.Plan9),
+		image.NewPaletted(image.Rect(2, 2, 8, 8), palette.Plan9),
+		image.NewPaletted(image.Rect(3, 3, 4, 4), palette.Plan9),
+	}
+	for _, upperBound := range []int{6, 10} {
+		g := &GIF{
+			Image:    images,
+			Delay:    make([]int, len(images)),
+			Disposal: make([]byte, len(images)),
+			Config: image.Config{
+				Width:  upperBound,
+				Height: upperBound,
+			},
+		}
+		err := EncodeAll(ioutil.Discard, g)
+		if upperBound >= 8 {
+			if err != nil {
+				t.Errorf("upperBound=%d: %v", upperBound, err)
+			}
+		} else {
+			if err == nil {
+				t.Errorf("upperBound=%d: got nil error, want non-nil", upperBound)
+			}
+		}
+	}
+}
+
+func TestEncodeNonZeroMinPoint(t *testing.T) {
+	points := []image.Point{
+		image.Point{-8, -9},
+		image.Point{-4, -4},
+		image.Point{-3, +3},
+		image.Point{+0, +0},
+		image.Point{+2, +2},
+	}
+	for _, p := range points {
+		src := image.NewPaletted(image.Rectangle{Min: p, Max: p.Add(image.Point{6, 6})}, palette.Plan9)
+		var buf bytes.Buffer
+		if err := Encode(&buf, src, nil); err != nil {
+			t.Errorf("p=%v: Encode: %v", p, err)
+			continue
+		}
+		m, err := Decode(&buf)
+		if err != nil {
+			t.Errorf("p=%v: Decode: %v", p, err)
+			continue
+		}
+		if got, want := m.Bounds(), image.Rect(0, 0, 6, 6); got != want {
+			t.Errorf("p=%v: got %v, want %v", p, got, want)
+		}
+	}
+}
+
+func TestEncodeImplicitConfigSize(t *testing.T) {
+	// For backwards compatibility for Go 1.4 and earlier code, the Config
+	// field is optional, and if zero, the width and height is implied by the
+	// first (and in this case only) frame's width and height.
+	//
+	// A Config only specifies a width and height (two integers) while an
+	// image.Image's Bounds method returns an image.Rectangle (four integers).
+	// For a gif.GIF, the overall bounds' top-left point is always implicitly
+	// (0, 0), and any frame whose bounds have a negative X or Y will be
+	// outside those overall bounds, so encoding should fail.
+	for _, lowerBound := range []int{-1, 0, 1} {
+		images := []*image.Paletted{
+			image.NewPaletted(image.Rect(lowerBound, lowerBound, 4, 4), palette.Plan9),
+		}
+		g := &GIF{
+			Image: images,
+			Delay: make([]int, len(images)),
+		}
+		err := EncodeAll(ioutil.Discard, g)
+		if lowerBound >= 0 {
+			if err != nil {
+				t.Errorf("lowerBound=%d: %v", lowerBound, err)
+			}
+		} else {
+			if err == nil {
+				t.Errorf("lowerBound=%d: got nil error, want non-nil", lowerBound)
+			}
+		}
+	}
+}
+
+func TestEncodePalettes(t *testing.T) {
+	const w, h = 5, 5
+	pals := []color.Palette{{
+		color.RGBA{0x00, 0x00, 0x00, 0xff},
+		color.RGBA{0x01, 0x00, 0x00, 0xff},
+		color.RGBA{0x02, 0x00, 0x00, 0xff},
+	}, {
+		color.RGBA{0x00, 0x00, 0x00, 0xff},
+		color.RGBA{0x00, 0x01, 0x00, 0xff},
+	}, {
+		color.RGBA{0x00, 0x00, 0x03, 0xff},
+		color.RGBA{0x00, 0x00, 0x02, 0xff},
+		color.RGBA{0x00, 0x00, 0x01, 0xff},
+		color.RGBA{0x00, 0x00, 0x00, 0xff},
+	}, {
+		color.RGBA{0x10, 0x07, 0xf0, 0xff},
+		color.RGBA{0x20, 0x07, 0xf0, 0xff},
+		color.RGBA{0x30, 0x07, 0xf0, 0xff},
+		color.RGBA{0x40, 0x07, 0xf0, 0xff},
+		color.RGBA{0x50, 0x07, 0xf0, 0xff},
+	}}
+	g0 := &GIF{
+		Image: []*image.Paletted{
+			image.NewPaletted(image.Rect(0, 0, w, h), pals[0]),
+			image.NewPaletted(image.Rect(0, 0, w, h), pals[1]),
+			image.NewPaletted(image.Rect(0, 0, w, h), pals[2]),
+			image.NewPaletted(image.Rect(0, 0, w, h), pals[3]),
+		},
+		Delay:    make([]int, len(pals)),
+		Disposal: make([]byte, len(pals)),
+		Config: image.Config{
+			ColorModel: pals[2],
+			Width:      w,
+			Height:     h,
+		},
+	}
+
+	var buf bytes.Buffer
+	if err := EncodeAll(&buf, g0); err != nil {
+		t.Fatalf("EncodeAll: %v", err)
+	}
+	g1, err := DecodeAll(&buf)
+	if err != nil {
+		t.Fatalf("DecodeAll: %v", err)
+	}
+	if len(g0.Image) != len(g1.Image) {
+		t.Fatalf("image lengths differ: %d and %d", len(g0.Image), len(g1.Image))
+	}
+	for i, m := range g1.Image {
+		if got, want := m.Palette, pals[i]; !palettesEqual(got, want) {
+			t.Errorf("frame %d:\ngot  %v\nwant %v", i, got, want)
+		}
+	}
+}
+
 func BenchmarkEncode(b *testing.B) {
 	b.StopTimer()
 
diff --git a/src/image/image.go b/src/image/image.go
index 6b8e5c4..20b64d7 100644
--- a/src/image/image.go
+++ b/src/image/image.go
@@ -18,7 +18,7 @@
 // initialization side effects.
 //
 // See "The Go image package" for more details:
-// http://golang.org/doc/articles/image_package.html
+// https://golang.org/doc/articles/image_package.html
 package image
 
 import (
@@ -46,9 +46,9 @@ type Image interface {
 }
 
 // PalettedImage is an image whose colors may come from a limited palette.
-// If m is a PalettedImage and m.ColorModel() returns a PalettedColorModel p,
+// If m is a PalettedImage and m.ColorModel() returns a color.Palette p,
 // then m.At(x, y) should be equivalent to p[m.ColorIndexAt(x, y)]. If m's
-// color model is not a PalettedColorModel, then ColorIndexAt's behavior is
+// color model is not a color.Palette, then ColorIndexAt's behavior is
 // undefined.
 type PalettedImage interface {
 	// ColorIndexAt returns the palette index of the pixel at (x, y).
@@ -570,7 +570,7 @@ func NewAlpha(r Rectangle) *Alpha {
 	return &Alpha{pix, 1 * w, r}
 }
 
-// Alpha16 is an in-memory image whose At method returns color.Alpha64 values.
+// Alpha16 is an in-memory image whose At method returns color.Alpha16 values.
 type Alpha16 struct {
 	// Pix holds the image's pixels, as alpha values in big-endian format. The pixel at
 	// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*2].
@@ -826,6 +826,92 @@ func NewGray16(r Rectangle) *Gray16 {
 	return &Gray16{pix, 2 * w, r}
 }
 
+// CMYK is an in-memory image whose At method returns color.CMYK values.
+type CMYK struct {
+	// Pix holds the image's pixels, in C, M, Y, K order. The pixel at
+	// (x, y) starts at Pix[(y-Rect.Min.Y)*Stride + (x-Rect.Min.X)*4].
+	Pix []uint8
+	// Stride is the Pix stride (in bytes) between vertically adjacent pixels.
+	Stride int
+	// Rect is the image's bounds.
+	Rect Rectangle
+}
+
+func (p *CMYK) ColorModel() color.Model { return color.CMYKModel }
+
+func (p *CMYK) Bounds() Rectangle { return p.Rect }
+
+func (p *CMYK) At(x, y int) color.Color {
+	return p.CMYKAt(x, y)
+}
+
+func (p *CMYK) CMYKAt(x, y int) color.CMYK {
+	if !(Point{x, y}.In(p.Rect)) {
+		return color.CMYK{}
+	}
+	i := p.PixOffset(x, y)
+	return color.CMYK{p.Pix[i+0], p.Pix[i+1], p.Pix[i+2], p.Pix[i+3]}
+}
+
+// PixOffset returns the index of the first element of Pix that corresponds to
+// the pixel at (x, y).
+func (p *CMYK) PixOffset(x, y int) int {
+	return (y-p.Rect.Min.Y)*p.Stride + (x-p.Rect.Min.X)*4
+}
+
+func (p *CMYK) Set(x, y int, c color.Color) {
+	if !(Point{x, y}.In(p.Rect)) {
+		return
+	}
+	i := p.PixOffset(x, y)
+	c1 := color.CMYKModel.Convert(c).(color.CMYK)
+	p.Pix[i+0] = c1.C
+	p.Pix[i+1] = c1.M
+	p.Pix[i+2] = c1.Y
+	p.Pix[i+3] = c1.K
+}
+
+func (p *CMYK) SetCMYK(x, y int, c color.CMYK) {
+	if !(Point{x, y}.In(p.Rect)) {
+		return
+	}
+	i := p.PixOffset(x, y)
+	p.Pix[i+0] = c.C
+	p.Pix[i+1] = c.M
+	p.Pix[i+2] = c.Y
+	p.Pix[i+3] = c.K
+}
+
+// SubImage returns an image representing the portion of the image p visible
+// through r. The returned value shares pixels with the original image.
+func (p *CMYK) SubImage(r Rectangle) Image {
+	r = r.Intersect(p.Rect)
+	// If r1 and r2 are Rectangles, r1.Intersect(r2) is not guaranteed to be inside
+	// either r1 or r2 if the intersection is empty. Without explicitly checking for
+	// this, the Pix[i:] expression below can panic.
+	if r.Empty() {
+		return &CMYK{}
+	}
+	i := p.PixOffset(r.Min.X, r.Min.Y)
+	return &CMYK{
+		Pix:    p.Pix[i:],
+		Stride: p.Stride,
+		Rect:   r,
+	}
+}
+
+// Opaque scans the entire image and reports whether it is fully opaque.
+func (p *CMYK) Opaque() bool {
+	return true
+}
+
+// NewCMYK returns a new CMYK with the given bounds.
+func NewCMYK(r Rectangle) *CMYK {
+	w, h := r.Dx(), r.Dy()
+	buf := make([]uint8, 4*w*h)
+	return &CMYK{buf, 4 * w, r}
+}
+
 // Paletted is an in-memory image of uint8 indices into a given palette.
 type Paletted struct {
 	// Pix holds the image's pixels, as palette indices. The pixel at
diff --git a/src/image/internal/imageutil/gen.go b/src/image/internal/imageutil/gen.go
new file mode 100644
index 0000000..fc1e707
--- /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 coordinate space to src coordinate 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 := int32(src.Y[yi]) * 0x10100 // Convert 0x12 to 0x121200.
+				cb1 := int32(src.Cb[ci]) - 128
+				cr1 := int32(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..fd7826d
--- /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 coordinate space to src coordinate 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 := int32(src.Y[yi]) * 0x10100 // Convert 0x12 to 0x121200.
+				cb1 := int32(src.Cb[ci]) - 128
+				cr1 := int32(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 := int32(src.Y[yi]) * 0x10100 // Convert 0x12 to 0x121200.
+				cb1 := int32(src.Cb[ci]) - 128
+				cr1 := int32(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 := int32(src.Y[yi]) * 0x10100 // Convert 0x12 to 0x121200.
+				cb1 := int32(src.Cb[ci]) - 128
+				cr1 := int32(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 := int32(src.Y[yi]) * 0x10100 // Convert 0x12 to 0x121200.
+				cb1 := int32(src.Cb[ci]) - 128
+				cr1 := int32(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/huffman.go b/src/image/jpeg/huffman.go
index d4ff4cf..4f8fe8e 100644
--- a/src/image/jpeg/huffman.go
+++ b/src/image/jpeg/huffman.go
@@ -187,7 +187,9 @@ func (d *decoder) decodeHuffman(h *huffman) (uint8, error) {
 			// There are no more bytes of data in this segment, but we may still
 			// be able to read the next symbol out of the previously read bits.
 			// First, undo the readByte that the ensureNBits call made.
-			d.unreadByteStuffedByte()
+			if d.bytes.nUnreadable != 0 {
+				d.unreadByteStuffedByte()
+			}
 			goto slowPath
 		}
 	}
diff --git a/src/image/jpeg/reader.go b/src/image/jpeg/reader.go
index 6d8b1d1..adf97ab 100644
--- a/src/image/jpeg/reader.go
+++ b/src/image/jpeg/reader.go
@@ -10,6 +10,7 @@ package jpeg
 import (
 	"image"
 	"image/color"
+	"image/internal/imageutil"
 	"io"
 )
 
@@ -26,6 +27,8 @@ type UnsupportedError string
 
 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.
@@ -41,32 +44,35 @@ const (
 	maxTh   = 3
 	maxTq   = 3
 
-	// A grayscale JPEG image has only a Y component.
-	nGrayComponent = 1
-	// A color JPEG image has Y, Cb and Cr components.
-	nColorComponent = 3
+	maxComponents = 4
+)
 
-	// We only support 4:4:4, 4:4:0, 4:2:2 and 4:2:0 downsampling, and therefore the
-	// number of luma samples per chroma sample is at most 2 in the horizontal
-	// and 2 in the vertical direction.
-	maxH = 2
-	maxV = 2
+const (
+	sof0Marker = 0xc0 // Start Of Frame (Baseline).
+	sof1Marker = 0xc1 // Start Of Frame (Extended Sequential).
+	sof2Marker = 0xc2 // Start Of Frame (Progressive).
+	dhtMarker  = 0xc4 // Define Huffman Table.
+	rst0Marker = 0xd0 // ReSTart (0).
+	rst7Marker = 0xd7 // ReSTart (7).
+	soiMarker  = 0xd8 // Start Of Image.
+	eoiMarker  = 0xd9 // End Of Image.
+	sosMarker  = 0xda // Start Of Scan.
+	dqtMarker  = 0xdb // Define Quantization Table.
+	driMarker  = 0xdd // Define Restart Interval.
+	comMarker  = 0xfe // COMment.
+	// "APPlication specific" markers aren't part of the JPEG spec per se,
+	// but in practice, their use is described at
+	// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/JPEG.html
+	app0Marker  = 0xe0
+	app14Marker = 0xee
+	app15Marker = 0xef
 )
 
+// See http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/JPEG.html#Adobe
 const (
-	soiMarker   = 0xd8 // Start Of Image.
-	eoiMarker   = 0xd9 // End Of Image.
-	sof0Marker  = 0xc0 // Start Of Frame (Baseline).
-	sof2Marker  = 0xc2 // Start Of Frame (Progressive).
-	dhtMarker   = 0xc4 // Define Huffman Table.
-	dqtMarker   = 0xdb // Define Quantization Table.
-	sosMarker   = 0xda // Start Of Scan.
-	driMarker   = 0xdd // Define Restart Interval.
-	rst0Marker  = 0xd0 // ReSTart (0).
-	rst7Marker  = 0xd7 // ReSTart (7).
-	app0Marker  = 0xe0 // APPlication specific (0).
-	app15Marker = 0xef // APPlication specific (15).
-	comMarker   = 0xfe // COMment.
+	adobeTransformUnknown = 0
+	adobeTransformYCbCr   = 1
+	adobeTransformYCbCrK  = 2
 )
 
 // unzig maps from the zig-zag ordering to the natural ordering. For example,
@@ -83,7 +89,7 @@ var unzig = [blockSize]int{
 	53, 60, 61, 54, 47, 55, 62, 63,
 }
 
-// Reader is deprecated.
+// Deprecated: Reader is deprecated.
 type Reader interface {
 	io.ByteReader
 	io.Reader
@@ -114,17 +120,25 @@ type decoder struct {
 		nUnreadable int
 	}
 	width, height int
-	img1          *image.Gray
-	img3          *image.YCbCr
-	ri            int // Restart Interval.
-	nComp         int
-	progressive   bool
-	eobRun        uint16 // End-of-Band run, specified in section G.1.2.2.
-	comp          [nColorComponent]component
-	progCoeffs    [nColorComponent][]block // Saved state between progressive-mode scans.
-	huff          [maxTc + 1][maxTh + 1]huffman
-	quant         [maxTq + 1]block // Quantization tables, in zig-zag order.
-	tmp           [blockSize + 1]byte
+
+	img1        *image.Gray
+	img3        *image.YCbCr
+	blackPix    []byte
+	blackStride int
+
+	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.
+
+	comp       [maxComponents]component
+	progCoeffs [maxComponents][]block // Saved state between progressive-mode scans.
+	huff       [maxTc + 1][maxTh + 1]huffman
+	quant      [maxTq + 1]block // Quantization tables, in zig-zag order.
+	tmp        [2 * blockSize]byte
 }
 
 // fill fills up the d.bytes.buf buffer from the underlying io.Reader. It
@@ -155,9 +169,6 @@ func (d *decoder) fill() error {
 // sometimes overshoot and read one or two too many bytes. Two-byte overshoot
 // can happen when expecting to read a 0xff 0x00 byte-stuffed byte.
 func (d *decoder) unreadByteStuffedByte() {
-	if d.bytes.nUnreadable == 0 {
-		panic("jpeg: unreadByteStuffedByte call cannot be fulfilled")
-	}
 	d.bytes.i -= d.bytes.nUnreadable
 	d.bytes.nUnreadable = 0
 	if d.bits.n >= 8 {
@@ -203,18 +214,19 @@ func (d *decoder) readByteStuffedByte() (x byte, err error) {
 		return 0xff, nil
 	}
 
+	d.bytes.nUnreadable = 0
+
 	x, err = d.readByte()
 	if err != nil {
 		return 0, err
 	}
+	d.bytes.nUnreadable = 1
 	if x != 0xff {
-		d.bytes.nUnreadable = 1
 		return x, nil
 	}
 
 	x, err = d.readByte()
 	if err != nil {
-		d.bytes.nUnreadable = 1
 		return 0, err
 	}
 	d.bytes.nUnreadable = 2
@@ -284,13 +296,18 @@ func (d *decoder) ignore(n int) error {
 
 // Specified in section B.2.2.
 func (d *decoder) processSOF(n int) error {
+	if d.nComp != 0 {
+		return FormatError("multiple SOF markers")
+	}
 	switch n {
-	case 6 + 3*nGrayComponent:
-		d.nComp = nGrayComponent
-	case 6 + 3*nColorComponent:
-		d.nComp = nColorComponent
+	case 6 + 3*1: // Grayscale image.
+		d.nComp = 1
+	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
@@ -302,12 +319,34 @@ func (d *decoder) processSOF(n int) error {
 	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 == nGrayComponent {
+		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
@@ -319,45 +358,104 @@ func (d *decoder) processSOF(n int) error {
 			// 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)
-		// For color images, we only support 4:4:4, 4:4:0, 4:2:2 or 4:2:0 chroma
-		// downsampling ratios. This implies that the (h, v) values for the Y
-		// component are either (1, 1), (1, 2), (2, 1) or (2, 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 {
-				return UnsupportedError("luma/chroma downsample ratio")
+			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 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 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
+				}
+			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].
+			// Theoretically, 4-component JPEG images could mix and match hv values
+			// but in practice, those two combinations are the only ones in use,
+			// and it simplifies the applyBlack code below if we can assume that:
+			//	- for CMYK, the C and K channels have full samples, and if the M
+			//	  and Y channels subsample, they subsample both horizontally and
+			//	  vertically.
+			//	- for YCbCrK, the Y and K channels have full samples.
+			switch i {
+			case 0:
+				if hv != 0x11 && hv != 0x22 {
+					return errUnsupportedSubsamplingRatio
+				}
+			case 1, 2:
+				if hv != 0x11 {
+					return errUnsupportedSubsamplingRatio
+				}
+			case 3:
+				if d.comp[0].h != h || d.comp[0].v != v {
+					return errUnsupportedSubsamplingRatio
+				}
 			}
-		} else if hv != 0x11 {
-			return UnsupportedError("luma/chroma downsample ratio")
 		}
+
+		d.comp[i].h = h
+		d.comp[i].v = v
 	}
 	return nil
 }
 
 // Specified in section B.2.4.1.
 func (d *decoder) processDQT(n int) error {
-	const qtLength = 1 + blockSize
-	for ; n >= qtLength; n -= qtLength {
-		if err := d.readFull(d.tmp[:qtLength]); err != nil {
+loop:
+	for n > 0 {
+		n--
+		x, err := d.readByte()
+		if err != nil {
 			return err
 		}
-		pq := d.tmp[0] >> 4
-		if pq != 0 {
-			return UnsupportedError("bad Pq value")
-		}
-		tq := d.tmp[0] & 0x0f
+		tq := x & 0x0f
 		if tq > maxTq {
 			return FormatError("bad Tq value")
 		}
-		for i := range d.quant[tq] {
-			d.quant[tq][i] = int32(d.tmp[i+1])
+		switch x >> 4 {
+		default:
+			return FormatError("bad Pq value")
+		case 0:
+			if n < blockSize {
+				break loop
+			}
+			n -= blockSize
+			if err := d.readFull(d.tmp[:blockSize]); err != nil {
+				return err
+			}
+			for i := range d.quant[tq] {
+				d.quant[tq][i] = int32(d.tmp[i])
+			}
+		case 1:
+			if n < 2*blockSize {
+				break loop
+			}
+			n -= 2 * blockSize
+			if err := d.readFull(d.tmp[:2*blockSize]); err != nil {
+				return err
+			}
+			for i := range d.quant[tq] {
+				d.quant[tq][i] = int32(d.tmp[2*i])<<8 | int32(d.tmp[2*i+1])
+			}
 		}
 	}
 	if n != 0 {
@@ -378,6 +476,43 @@ func (d *decoder) processDRI(n int) error {
 	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)
+	}
+	if err := d.readFull(d.tmp[:12]); err != nil {
+		return err
+	}
+	n -= 12
+
+	if d.tmp[0] == 'A' && d.tmp[1] == 'd' && d.tmp[2] == 'o' && d.tmp[3] == 'b' && d.tmp[4] == 'e' {
+		d.adobeTransformValid = true
+		d.adobeTransform = d.tmp[11]
+	}
+
+	if n > 0 {
+		return d.ignore(n)
+	}
+	return nil
+}
+
 // decode reads a JPEG image from r and returns it as an image.Image.
 func (d *decoder) decode(r io.Reader, configOnly bool) (image.Image, error) {
 	d.r = r
@@ -459,25 +594,48 @@ func (d *decoder) decode(r io.Reader, configOnly bool) (image.Image, error) {
 			return nil, FormatError("short segment length")
 		}
 
-		switch {
-		case marker == sof0Marker || marker == sof2Marker: // Start Of Frame.
+		switch marker {
+		case sof0Marker, sof1Marker, sof2Marker:
 			d.progressive = marker == sof2Marker
 			err = d.processSOF(n)
-			if configOnly {
+			if configOnly && d.jfif {
 				return nil, err
 			}
-		case marker == dhtMarker: // Define Huffman Table.
-			err = d.processDHT(n)
-		case marker == dqtMarker: // Define Quantization Table.
-			err = d.processDQT(n)
-		case marker == sosMarker: // Start Of Scan.
+		case dhtMarker:
+			if configOnly {
+				err = d.ignore(n)
+			} else {
+				err = d.processDHT(n)
+			}
+		case dqtMarker:
+			if configOnly {
+				err = d.ignore(n)
+			} else {
+				err = d.processDQT(n)
+			}
+		case sosMarker:
+			if configOnly {
+				return nil, nil
+			}
 			err = d.processSOS(n)
-		case marker == driMarker: // Define Restart Interval.
-			err = d.processDRI(n)
-		case app0Marker <= marker && marker <= app15Marker || marker == comMarker: // APPlication specific, or COMment.
-			err = d.ignore(n)
+		case driMarker:
+			if configOnly {
+				err = d.ignore(n)
+			} else {
+				err = d.processDRI(n)
+			}
+		case app0Marker:
+			err = d.processApp0Marker(n)
+		case app14Marker:
+			err = d.processApp14Marker(n)
 		default:
-			err = UnsupportedError("unknown marker")
+			if app0Marker <= marker && marker <= app15Marker || marker == comMarker {
+				err = d.ignore(n)
+			} else if marker < 0xc0 { // See Table B.1 "Marker code assignments".
+				err = FormatError("unknown marker")
+			} else {
+				err = UnsupportedError("unknown marker")
+			}
 		}
 		if err != nil {
 			return nil, err
@@ -487,11 +645,118 @@ func (d *decoder) decode(r io.Reader, configOnly bool) (image.Image, error) {
 		return d.img1, nil
 	}
 	if d.img3 != nil {
+		if d.blackPix != nil {
+			return d.applyBlack()
+		} else if d.isRGB() {
+			return d.convertToRGB()
+		}
 		return d.img3, nil
 	}
 	return nil, FormatError("missing SOS marker")
 }
 
+// applyBlack combines d.img3 and d.blackPix into a CMYK image. The formula
+// used depends on whether the JPEG image is stored as CMYK or YCbCrK,
+// indicated by the APP14 (Adobe) metadata.
+//
+// Adobe CMYK JPEG images are inverted, where 255 means no ink instead of full
+// ink, so we apply "v = 255 - v" at various points. Note that a double
+// inversion is a no-op, so inversions might be implicit in the code below.
+func (d *decoder) applyBlack() (image.Image, error) {
+	if !d.adobeTransformValid {
+		return nil, UnsupportedError("unknown color model: 4-component JPEG doesn't have Adobe APP14 metadata")
+	}
+
+	// If the 4-component JPEG image isn't explicitly marked as "Unknown (RGB
+	// or CMYK)" as per
+	// http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/JPEG.html#Adobe
+	// we assume that it is YCbCrK. This matches libjpeg's jdapimin.c.
+	if d.adobeTransform != adobeTransformUnknown {
+		// Convert the YCbCr part of the YCbCrK to RGB, invert the RGB to get
+		// CMY, and patch in the original K. The RGB to CMY inversion cancels
+		// out the 'Adobe inversion' described in the applyBlack doc comment
+		// above, so in practice, only the fourth channel (black) is inverted.
+		bounds := d.img3.Bounds()
+		img := image.NewRGBA(bounds)
+		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)]
+			}
+		}
+		return &image.CMYK{
+			Pix:    img.Pix,
+			Stride: img.Stride,
+			Rect:   img.Rect,
+		}, nil
+	}
+
+	// The first three channels (cyan, magenta, yellow) of the CMYK
+	// were decoded into d.img3, but each channel was decoded into a separate
+	// []byte slice, and some channels may be subsampled. We interleave the
+	// separate channels into an image.CMYK's single []byte slice containing 4
+	// contiguous bytes per pixel.
+	bounds := d.img3.Bounds()
+	img := image.NewCMYK(bounds)
+
+	translations := [4]struct {
+		src    []byte
+		stride int
+	}{
+		{d.img3.Y, d.img3.YStride},
+		{d.img3.Cb, d.img3.CStride},
+		{d.img3.Cr, d.img3.CStride},
+		{d.blackPix, d.blackStride},
+	}
+	for t, translation := range translations {
+		subsample := d.comp[t].h != d.comp[0].h || d.comp[t].v != d.comp[0].v
+		for iBase, y := 0, bounds.Min.Y; y < bounds.Max.Y; iBase, y = iBase+img.Stride, y+1 {
+			sy := y - bounds.Min.Y
+			if subsample {
+				sy /= 2
+			}
+			for i, x := iBase+t, bounds.Min.X; x < bounds.Max.X; i, x = i+4, x+1 {
+				sx := x - bounds.Min.X
+				if subsample {
+					sx /= 2
+				}
+				img.Pix[i] = 255 - translation.src[sy*translation.stride+sx]
+			}
+		}
+	}
+	return img, nil
+}
+
+func (d *decoder) isRGB() bool {
+	if d.jfif {
+		return false
+	}
+	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.
 func Decode(r io.Reader) (image.Image, error) {
 	var d decoder
@@ -506,15 +771,25 @@ func DecodeConfig(r io.Reader) (image.Config, error) {
 		return image.Config{}, err
 	}
 	switch d.nComp {
-	case nGrayComponent:
+	case 1:
 		return image.Config{
 			ColorModel: color.GrayModel,
 			Width:      d.width,
 			Height:     d.height,
 		}, nil
-	case nColorComponent:
+	case 3:
+		cm := color.YCbCrModel
+		if d.isRGB() {
+			cm = color.RGBAModel
+		}
+		return image.Config{
+			ColorModel: cm,
+			Width:      d.width,
+			Height:     d.height,
+		}, nil
+	case 4:
 		return image.Config{
-			ColorModel: color.YCbCrModel,
+			ColorModel: color.CMYKModel,
 			Width:      d.width,
 			Height:     d.height,
 		}, nil
diff --git a/src/image/jpeg/reader_test.go b/src/image/jpeg/reader_test.go
index 4de2e8e..7737615 100644
--- a/src/image/jpeg/reader_test.go
+++ b/src/image/jpeg/reader_test.go
@@ -15,6 +15,7 @@ import (
 	"os"
 	"strings"
 	"testing"
+	"time"
 )
 
 // TestDecodeProgressive tests that decoding the baseline and progressive
@@ -23,6 +24,8 @@ import (
 func TestDecodeProgressive(t *testing.T) {
 	testCases := []string{
 		"../testdata/video-001",
+		"../testdata/video-001.q50.410",
+		"../testdata/video-001.q50.411",
 		"../testdata/video-001.q50.420",
 		"../testdata/video-001.q50.422",
 		"../testdata/video-001.q50.440",
@@ -184,6 +187,81 @@ func pixString(pix []byte, stride, x, y int) string {
 	return s.String()
 }
 
+func TestTruncatedSOSDataDoesntPanic(t *testing.T) {
+	b, err := ioutil.ReadFile("../testdata/video-005.gray.q50.jpeg")
+	if err != nil {
+		t.Fatal(err)
+	}
+	sosMarker := []byte{0xff, 0xda}
+	i := bytes.Index(b, sosMarker)
+	if i < 0 {
+		t.Fatal("SOS marker not found")
+	}
+	i += len(sosMarker)
+	j := i + 10
+	if j > len(b) {
+		j = len(b)
+	}
+	for ; i < j; i++ {
+		Decode(bytes.NewReader(b[:i]))
+	}
+}
+
+func TestLargeImageWithShortData(t *testing.T) {
+	// This input is an invalid JPEG image, based on the fuzzer-generated image
+	// in issue 10413. It is only 504 bytes, and shouldn't take long for Decode
+	// to return an error. The Start Of Frame marker gives the image dimensions
+	// as 8192 wide and 8192 high, so even if an unreadByteStuffedByte bug
+	// doesn't technically lead to an infinite loop, such a bug can still cause
+	// an unreasonably long loop for such a short input.
+	const input = "" +
+		"\xff\xd8\xff\xe0\x00\x10\x4a\x46\x49\x46\x00\x01\x01\x00\x00\x01" +
+		"\x00\x01\x00\x00\xff\xdb\x00\x43\x00\x10\x0b\x0c\x0e\x0c\x0a\x10" +
+		"\x0e\x89\x0e\x12\x11\x10\x13\x18\xff\xd8\xff\xe0\x00\x10\x4a\x46" +
+		"\x49\x46\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xff\xdb\x00\x43" +
+		"\x00\x10\x0b\x0c\x0e\x0c\x0a\x10\x0e\x0d\x0e\x12\x11\x10\x13\x18" +
+		"\x28\x1a\x18\x16\x16\x18\x31\x23\x25\x1d\x28\x3a\x33\x3d\x3c\x39" +
+		"\x33\x38\x37\x40\x48\x5c\x4e\x40\x44\x57\x45\x37\x38\x50\x6d\x51" +
+		"\x57\x5f\x62\x67\x68\x67\x3e\x4d\x71\x79\x70\x64\x78\x5c\x65\x67" +
+		"\x63\xff\xc0\x00\x0b\x08\x20\x00\x20\x00\x01\x01\x11\x00\xff\xc4" +
+		"\x00\x1f\x00\x00\x01\x05\x01\x01\x01\x01\x01\x01\x00\x00\x00\x00" +
+		"\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\xff" +
+		"\xc4\x00\xb5\x10\x00\x02\x01\x03\x03\x02\x04\x03\x05\x05\x04\x04" +
+		"\x00\x00\x01\x7d\x01\x02\x03\x00\x04\x11\x05\x12\x21\x31\x01\x06" +
+		"\x13\x51\x61\x07\x22\x71\x14\x32\x81\x91\xa1\x08\x23\xd8\xff\xdd" +
+		"\x42\xb1\xc1\x15\x52\xd1\xf0\x24\x33\x62\x72\x82\x09\x0a\x16\x17" +
+		"\x18\x19\x1a\x25\x26\x27\x28\x29\x2a\x34\x35\x36\x37\x38\x39\x3a" +
+		"\x43\x44\x45\x46\x47\x48\x49\x4a\x53\x54\x55\x56\x57\x58\x59\x5a" +
+		"\x00\x63\x64\x65\x66\x67\x68\x69\x6a\x73\x74\x75\x76\x77\x78\x79" +
+		"\x7a\x83\x84\x85\x86\x87\x88\x89\x8a\x92\x93\x94\x95\x96\x97\x98" +
+		"\x99\x9a\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xb2\xb3\xb4\xb5\xb6" +
+		"\xb7\xb8\xb9\xba\xc2\xc3\xc4\xc5\xc6\xc7\xff\xd8\xff\xe0\x00\x10" +
+		"\x4a\x46\x49\x46\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xff\xdb" +
+		"\x00\x43\x00\x10\x0b\x0c\x0e\x0c\x0a\x10\x0e\x0d\x0e\x12\x11\x10" +
+		"\x13\x18\x28\x1a\x18\x16\x16\x18\x31\x23\x25\x1d\xc8\xc9\xca\xd2" +
+		"\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8" +
+		"\xe9\xea\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xff\xda\x00\x08" +
+		"\x01\x01\x00\x00\x3f\x00\xb9\xeb\x50\xb0\xdb\xc8\xa8\xe4\x63\x80" +
+		"\xdd\x31\xd6\x9d\xbb\xf2\xc5\x42\x1f\x6c\x6f\xf4\x34\xdd\x3c\xfc" +
+		"\xac\xe7\x3d\x80\xa9\xcc\x87\x34\xb3\x37\xfa\x2b\x9f\x6a\xad\x63" +
+		"\x20\x36\x9f\x78\x64\x75\xe6\xab\x7d\xb2\xde\x29\x70\xd3\x20\x27" +
+		"\xde\xaf\xa4\xf0\xca\x9f\x24\xa8\xdf\x46\xa8\x24\x84\x96\xe3\x77" +
+		"\xf9\x2e\xe0\x0a\x62\x7f\xdf\xd9"
+	c := make(chan error, 1)
+	go func() {
+		_, err := Decode(strings.NewReader(input))
+		c <- err
+	}()
+	select {
+	case err := <-c:
+		if err == nil {
+			t.Fatalf("got nil error, want non-nil")
+		}
+	case <-time.After(3 * time.Second):
+		t.Fatalf("timed out")
+	}
+}
+
 func TestExtraneousData(t *testing.T) {
 	// Encode a 1x1 red image.
 	src := image.NewRGBA(image.Rect(0, 0, 1, 1))
diff --git a/src/image/jpeg/scan.go b/src/image/jpeg/scan.go
index 2bd1d9d..99734c0 100644
--- a/src/image/jpeg/scan.go
+++ b/src/image/jpeg/scan.go
@@ -9,27 +9,42 @@ import (
 )
 
 // makeImg allocates and initializes the destination image.
-func (d *decoder) makeImg(h0, v0, mxx, myy int) {
-	if d.nComp == nGrayComponent {
+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 0x41:
+		subsampleRatio = image.YCbCrSubsampleRatio411
+	case 0x42:
+		subsampleRatio = image.YCbCrSubsampleRatio410
 	default:
 		panic("unreachable")
 	}
 	m := image.NewYCbCr(image.Rect(0, 0, 8*h0*mxx, 8*v0*myy), subsampleRatio)
 	d.img3 = m.SubImage(image.Rect(0, 0, d.width, d.height)).(*image.YCbCr)
+
+	if d.nComp == 4 {
+		h3, v3 := d.comp[3].h, d.comp[3].v
+		d.blackPix = make([]byte, 8*h3*mxx*8*v3*myy)
+		d.blackStride = 8 * h3 * mxx
+	}
 }
 
 // Specified in section B.2.3.
@@ -47,15 +62,16 @@ func (d *decoder) processSOS(n int) error {
 	if n != 4+2*nComp {
 		return FormatError("SOS length inconsistent with number of components")
 	}
-	var scan [nColorComponent]struct {
+	var scan [maxComponents]struct {
 		compIndex uint8
 		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
 			}
@@ -64,6 +80,18 @@ func (d *decoder) processSOS(n int) error {
 			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")
@@ -73,6 +101,11 @@ func (d *decoder) processSOS(n int) error {
 			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.
@@ -112,7 +145,7 @@ func (d *decoder) processSOS(n int) error {
 	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++ {
@@ -128,11 +161,9 @@ func (d *decoder) processSOS(n int) error {
 	var (
 		// b is the decoded coefficients, in natural (not zig-zag) order.
 		b  block
-		dc [nColorComponent]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.
+		dc [maxComponents]int32
+		// 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
 	)
@@ -140,8 +171,10 @@ func (d *decoder) processSOS(n int) error {
 		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.
 					//
@@ -168,15 +201,10 @@ func (d *decoder) processSOS(n int) error {
 					//	0 1 2
 					//	3 4 5
 					if nComp != 1 {
-						bx, by = d.comp[compIndex].h*mx, d.comp[compIndex].v*my
-						if h0 == 1 {
-							by += j
-						} else {
-							bx += j % 2
-							by += j / 2
-						}
+						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++
@@ -187,7 +215,7 @@ func (d *decoder) processSOS(n int) error {
 
 					// 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{}
 					}
@@ -260,7 +288,7 @@ func (d *decoder) processSOS(n int) error {
 					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,
@@ -276,7 +304,7 @@ func (d *decoder) processSOS(n int) error {
 					}
 					idct(&b)
 					dst, stride := []byte(nil), 0
-					if d.nComp == nGrayComponent {
+					if d.nComp == 1 {
 						dst, stride = d.img1.Pix[8*(by*d.img1.Stride+bx):], d.img1.Stride
 					} else {
 						switch compIndex {
@@ -286,6 +314,8 @@ func (d *decoder) processSOS(n int) error {
 							dst, stride = d.img3.Cb[8*(by*d.img3.CStride+bx):], d.img3.CStride
 						case 2:
 							dst, stride = d.img3.Cr[8*(by*d.img3.CStride+bx):], d.img3.CStride
+						case 3:
+							dst, stride = d.blackPix[8*(by*d.blackStride+bx):], d.blackStride
 						default:
 							return UnsupportedError("too many components")
 						}
@@ -325,7 +355,7 @@ func (d *decoder) processSOS(n int) error {
 				// Reset the Huffman decoder.
 				d.bits = bits{}
 				// Reset the DC components, as per section F.2.1.3.1.
-				dc = [nColorComponent]int32{}
+				dc = [maxComponents]int32{}
 				// Reset the progressive decoder state, as per section G.1.2.2.
 				d.eobRun = 0
 			}
diff --git a/src/image/png/reader.go b/src/image/png/reader.go
index 0a40ca1..bbd6f75 100644
--- a/src/image/png/reader.go
+++ b/src/image/png/reader.go
@@ -47,6 +47,10 @@ const (
 	cbTCA16
 )
 
+func cbPaletted(cb int) bool {
+	return cbP1 <= cb && cb <= cbP8
+}
+
 // Filter type, as per the PNG spec.
 const (
 	ftNone    = 0
@@ -81,15 +85,16 @@ var interlacing = []interlaceScan{
 }
 
 // Decoding stage.
-// The PNG specification says that the IHDR, PLTE (if present), IDAT and IEND
-// chunks must appear in that order. There may be multiple IDAT chunks, and
-// IDAT chunks must be sequential (i.e. they may not have any other chunks
-// between them).
+// The PNG specification says that the IHDR, PLTE (if present), tRNS (if
+// present), IDAT and IEND chunks must appear in that order. There may be
+// multiple IDAT chunks, and IDAT chunks must be sequential (i.e. they may not
+// have any other chunks between them).
 // http://www.w3.org/TR/PNG/#5ChunkOrdering
 const (
 	dsStart = iota
 	dsSeenIHDR
 	dsSeenPLTE
+	dsSeentRNS
 	dsSeenIDAT
 	dsSeenIEND
 )
@@ -321,15 +326,23 @@ func (d *decoder) decode() (image.Image, error) {
 	var img image.Image
 	if d.interlace == itNone {
 		img, err = d.readImagePass(r, 0, false)
+		if err != nil {
+			return nil, err
+		}
 	} else if d.interlace == itAdam7 {
 		// Allocate a blank image of the full size.
 		img, err = d.readImagePass(nil, 0, true)
+		if err != nil {
+			return nil, err
+		}
 		for pass := 0; pass < 7; pass++ {
 			imagePass, err := d.readImagePass(r, pass, false)
 			if err != nil {
 				return nil, err
 			}
-			d.mergePassInto(img, imagePass, pass)
+			if imagePass != nil {
+				d.mergePassInto(img, imagePass, pass)
+			}
 		}
 	}
 
@@ -371,6 +384,12 @@ func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image
 		// Add the multiplication factor and subtract one, effectively rounding up.
 		width = (width - p.xOffset + p.xFactor - 1) / p.xFactor
 		height = (height - p.yOffset + p.yFactor - 1) / p.yFactor
+		// A PNG image can't have zero width or height, but for an interlaced
+		// image, an individual pass might have zero width or height. If so, we
+		// shouldn't even read a per-row filter type byte, so return early.
+		if width == 0 || height == 0 {
+			return nil, nil
+		}
 	}
 	switch d.cb {
 	case cbG1, cbG2, cbG4, cbG8:
@@ -425,6 +444,9 @@ func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image
 		// Read the decompressed bytes.
 		_, err := io.ReadFull(r, cr)
 		if err != nil {
+			if err == io.EOF || err == io.ErrUnexpectedEOF {
+				return nil, FormatError("not enough pixel data")
+			}
 			return nil, err
 		}
 
@@ -443,6 +465,9 @@ func (d *decoder) readImagePass(r io.Reader, pass int, allocateOnly bool) (image
 				cdat[i] += p
 			}
 		case ftAverage:
+			// The first column has no column to the left of it, so it is a
+			// special case. We know that the first column exists because we
+			// check above that width != 0, and so len(cdat) != 0.
 			for i := 0; i < bytesPerPixel; i++ {
 				cdat[i] += pdat[i] / 2
 			}
@@ -687,9 +712,10 @@ func (d *decoder) parseChunk() error {
 		if d.stage != dsSeenPLTE {
 			return chunkOrderError
 		}
+		d.stage = dsSeentRNS
 		return d.parsetRNS(length)
 	case "IDAT":
-		if d.stage < dsSeenIHDR || d.stage > dsSeenIDAT || (d.cb == cbP8 && d.stage == dsSeenIHDR) {
+		if d.stage < dsSeenIHDR || d.stage > dsSeenIDAT || (d.stage == dsSeenIHDR && cbPaletted(d.cb)) {
 			return chunkOrderError
 		}
 		d.stage = dsSeenIDAT
@@ -779,7 +805,7 @@ func DecodeConfig(r io.Reader) (image.Config, error) {
 			}
 			return image.Config{}, err
 		}
-		paletted := d.cb == cbP8 || d.cb == cbP4 || d.cb == cbP2 || d.cb == cbP1
+		paletted := cbPaletted(d.cb)
 		if d.stage == dsSeenIHDR && !paletted {
 			break
 		}
diff --git a/src/image/png/reader_test.go b/src/image/png/reader_test.go
index ce772eb..f89e7ef 100644
--- a/src/image/png/reader_test.go
+++ b/src/image/png/reader_test.go
@@ -6,12 +6,14 @@ package png
 
 import (
 	"bufio"
+	"bytes"
 	"fmt"
 	"image"
 	"image/color"
 	"io"
 	"io/ioutil"
 	"os"
+	"reflect"
 	"strings"
 	"testing"
 )
@@ -319,6 +321,93 @@ func TestPalettedDecodeConfig(t *testing.T) {
 	}
 }
 
+func TestInterlaced(t *testing.T) {
+	a, err := readPNG("testdata/gray-gradient.png")
+	if err != nil {
+		t.Fatal(err)
+	}
+	b, err := readPNG("testdata/gray-gradient.interlaced.png")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if !reflect.DeepEqual(a, b) {
+		t.Fatalf("decodings differ:\nnon-interlaced:\n%#v\ninterlaced:\n%#v", a, b)
+	}
+}
+
+func TestIncompleteIDATOnRowBoundary(t *testing.T) {
+	// The following is an invalid 1x2 grayscale PNG image. The header is OK,
+	// but the zlib-compressed IDAT payload contains two bytes "\x02\x00",
+	// which is only one row of data (the leading "\x02" is a row filter).
+	const (
+		ihdr = "\x00\x00\x00\x0dIHDR\x00\x00\x00\x01\x00\x00\x00\x02\x08\x00\x00\x00\x00\xbc\xea\xe9\xfb"
+		idat = "\x00\x00\x00\x0eIDAT\x78\x9c\x62\x62\x00\x04\x00\x00\xff\xff\x00\x06\x00\x03\xfa\xd0\x59\xae"
+		iend = "\x00\x00\x00\x00IEND\xae\x42\x60\x82"
+	)
+	_, err := Decode(strings.NewReader(pngHeader + ihdr + idat + iend))
+	if err == nil {
+		t.Fatal("got nil error, want non-nil")
+	}
+}
+
+func TestMultipletRNSChunks(t *testing.T) {
+	/*
+		The following is a valid 1x1 paletted PNG image with a 1-element palette
+		containing color.NRGBA{0xff, 0x00, 0x00, 0x7f}:
+			0000000: 8950 4e47 0d0a 1a0a 0000 000d 4948 4452  .PNG........IHDR
+			0000010: 0000 0001 0000 0001 0803 0000 0028 cb34  .............(.4
+			0000020: bb00 0000 0350 4c54 45ff 0000 19e2 0937  .....PLTE......7
+			0000030: 0000 0001 7452 4e53 7f80 5cb4 cb00 0000  ....tRNS..\.....
+			0000040: 0e49 4441 5478 9c62 6200 0400 00ff ff00  .IDATx.bb.......
+			0000050: 0600 03fa d059 ae00 0000 0049 454e 44ae  .....Y.....IEND.
+			0000060: 4260 82                                  B`.
+		Dropping the tRNS chunk makes that color's alpha 0xff instead of 0x7f.
+	*/
+	const (
+		ihdr = "\x00\x00\x00\x0dIHDR\x00\x00\x00\x01\x00\x00\x00\x01\x08\x03\x00\x00\x00\x28\xcb\x34\xbb"
+		plte = "\x00\x00\x00\x03PLTE\xff\x00\x00\x19\xe2\x09\x37"
+		trns = "\x00\x00\x00\x01tRNS\x7f\x80\x5c\xb4\xcb"
+		idat = "\x00\x00\x00\x0eIDAT\x78\x9c\x62\x62\x00\x04\x00\x00\xff\xff\x00\x06\x00\x03\xfa\xd0\x59\xae"
+		iend = "\x00\x00\x00\x00IEND\xae\x42\x60\x82"
+	)
+	for i := 0; i < 4; i++ {
+		var b []byte
+		b = append(b, pngHeader...)
+		b = append(b, ihdr...)
+		b = append(b, plte...)
+		for j := 0; j < i; j++ {
+			b = append(b, trns...)
+		}
+		b = append(b, idat...)
+		b = append(b, iend...)
+
+		var want color.Color
+		m, err := Decode(bytes.NewReader(b))
+		switch i {
+		case 0:
+			if err != nil {
+				t.Errorf("%d tRNS chunks: %v", i, err)
+				continue
+			}
+			want = color.RGBA{0xff, 0x00, 0x00, 0xff}
+		case 1:
+			if err != nil {
+				t.Errorf("%d tRNS chunks: %v", i, err)
+				continue
+			}
+			want = color.NRGBA{0xff, 0x00, 0x00, 0x7f}
+		default:
+			if err == nil {
+				t.Errorf("%d tRNS chunks: got nil error, want non-nil", i)
+			}
+			continue
+		}
+		if got := m.At(0, 0); got != want {
+			t.Errorf("%d tRNS chunks: got %T %v, want %T %v", i, got, got, want, want)
+		}
+	}
+}
+
 func benchmarkDecode(b *testing.B, filename string, bytesPerPixel int) {
 	b.StopTimer()
 	data, err := ioutil.ReadFile(filename)
diff --git a/src/image/png/testdata/gray-gradient.interlaced.png b/src/image/png/testdata/gray-gradient.interlaced.png
new file mode 100644
index 0000000..01f657a
Binary files /dev/null and b/src/image/png/testdata/gray-gradient.interlaced.png differ
diff --git a/src/image/png/testdata/gray-gradient.png b/src/image/png/testdata/gray-gradient.png
new file mode 100644
index 0000000..6de1cd3
Binary files /dev/null and b/src/image/png/testdata/gray-gradient.png differ
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
Binary files /dev/null and b/src/image/testdata/video-001.221212.jpeg 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
Binary files /dev/null and b/src/image/testdata/video-001.221212.png differ
diff --git a/src/image/testdata/video-001.cmyk.jpeg b/src/image/testdata/video-001.cmyk.jpeg
new file mode 100644
index 0000000..507df84
Binary files /dev/null and b/src/image/testdata/video-001.cmyk.jpeg differ
diff --git a/src/image/testdata/video-001.cmyk.png b/src/image/testdata/video-001.cmyk.png
new file mode 100644
index 0000000..ef7b2b8
Binary files /dev/null and b/src/image/testdata/video-001.cmyk.png differ
diff --git a/src/image/testdata/video-001.q50.410.jpeg b/src/image/testdata/video-001.q50.410.jpeg
new file mode 100644
index 0000000..4cebd1e
Binary files /dev/null and b/src/image/testdata/video-001.q50.410.jpeg differ
diff --git a/src/image/testdata/video-001.q50.410.progressive.jpeg b/src/image/testdata/video-001.q50.410.progressive.jpeg
new file mode 100644
index 0000000..fb71402
Binary files /dev/null and b/src/image/testdata/video-001.q50.410.progressive.jpeg differ
diff --git a/src/image/testdata/video-001.q50.411.jpeg b/src/image/testdata/video-001.q50.411.jpeg
new file mode 100644
index 0000000..b90de18
Binary files /dev/null and b/src/image/testdata/video-001.q50.411.jpeg differ
diff --git a/src/image/testdata/video-001.q50.411.progressive.jpeg b/src/image/testdata/video-001.q50.411.progressive.jpeg
new file mode 100644
index 0000000..1ddb22b
Binary files /dev/null and b/src/image/testdata/video-001.q50.411.progressive.jpeg 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..fc2ce3c
Binary files /dev/null and b/src/image/testdata/video-001.rgb.jpeg 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
Binary files /dev/null and b/src/image/testdata/video-001.rgb.png differ
diff --git a/src/image/ycbcr.go b/src/image/ycbcr.go
index 7c773f2..93c354b 100644
--- a/src/image/ycbcr.go
+++ b/src/image/ycbcr.go
@@ -16,6 +16,8 @@ const (
 	YCbCrSubsampleRatio422
 	YCbCrSubsampleRatio420
 	YCbCrSubsampleRatio440
+	YCbCrSubsampleRatio411
+	YCbCrSubsampleRatio410
 )
 
 func (s YCbCrSubsampleRatio) String() string {
@@ -28,6 +30,10 @@ func (s YCbCrSubsampleRatio) String() string {
 		return "YCbCrSubsampleRatio420"
 	case YCbCrSubsampleRatio440:
 		return "YCbCrSubsampleRatio440"
+	case YCbCrSubsampleRatio411:
+		return "YCbCrSubsampleRatio411"
+	case YCbCrSubsampleRatio410:
+		return "YCbCrSubsampleRatio410"
 	}
 	return "YCbCrSubsampleRatioUnknown"
 }
@@ -43,6 +49,8 @@ func (s YCbCrSubsampleRatio) String() string {
 //	For 4:2:2, CStride == YStride/2 && len(Cb) == len(Cr) == len(Y)/2.
 //	For 4:2:0, CStride == YStride/2 && len(Cb) == len(Cr) == len(Y)/4.
 //	For 4:4:0, CStride == YStride/1 && len(Cb) == len(Cr) == len(Y)/2.
+//	For 4:1:1, CStride == YStride/4 && len(Cb) == len(Cr) == len(Y)/4.
+//	For 4:1:0, CStride == YStride/4 && len(Cb) == len(Cr) == len(Y)/8.
 type YCbCr struct {
 	Y, Cb, Cr      []uint8
 	YStride        int
@@ -92,6 +100,10 @@ func (p *YCbCr) COffset(x, y int) int {
 		return (y/2-p.Rect.Min.Y/2)*p.CStride + (x/2 - p.Rect.Min.X/2)
 	case YCbCrSubsampleRatio440:
 		return (y/2-p.Rect.Min.Y/2)*p.CStride + (x - p.Rect.Min.X)
+	case YCbCrSubsampleRatio411:
+		return (y-p.Rect.Min.Y)*p.CStride + (x/4 - p.Rect.Min.X/4)
+	case YCbCrSubsampleRatio410:
+		return (y/2-p.Rect.Min.Y/2)*p.CStride + (x/4 - p.Rect.Min.X/4)
 	}
 	// Default to 4:4:4 subsampling.
 	return (y-p.Rect.Min.Y)*p.CStride + (x - p.Rect.Min.X)
@@ -139,16 +151,25 @@ func NewYCbCr(r Rectangle, subsampleRatio YCbCrSubsampleRatio) *YCbCr {
 	case YCbCrSubsampleRatio440:
 		cw = w
 		ch = (r.Max.Y+1)/2 - r.Min.Y/2
+	case YCbCrSubsampleRatio411:
+		cw = (r.Max.X+3)/4 - r.Min.X/4
+		ch = h
+	case YCbCrSubsampleRatio410:
+		cw = (r.Max.X+3)/4 - r.Min.X/4
+		ch = (r.Max.Y+1)/2 - r.Min.Y/2
 	default:
 		// Default to 4:4:4 subsampling.
 		cw = w
 		ch = h
 	}
-	b := make([]byte, w*h+2*cw*ch)
+	i0 := w*h + 0*cw*ch
+	i1 := w*h + 1*cw*ch
+	i2 := w*h + 2*cw*ch
+	b := make([]byte, i2)
 	return &YCbCr{
-		Y:              b[:w*h],
-		Cb:             b[w*h+0*cw*ch : w*h+1*cw*ch],
-		Cr:             b[w*h+1*cw*ch : w*h+2*cw*ch],
+		Y:              b[:i0:i0],
+		Cb:             b[i0:i1:i1],
+		Cr:             b[i1:i2:i2],
 		SubsampleRatio: subsampleRatio,
 		YStride:        w,
 		CStride:        cw,
diff --git a/src/image/ycbcr_test.go b/src/image/ycbcr_test.go
index a5f4482..4996bc8 100644
--- a/src/image/ycbcr_test.go
+++ b/src/image/ycbcr_test.go
@@ -37,6 +37,8 @@ func TestYCbCr(t *testing.T) {
 		YCbCrSubsampleRatio422,
 		YCbCrSubsampleRatio420,
 		YCbCrSubsampleRatio440,
+		YCbCrSubsampleRatio411,
+		YCbCrSubsampleRatio410,
 	}
 	deltas := []Point{
 		Pt(0, 0),
@@ -105,3 +107,27 @@ func testYCbCr(t *testing.T, r Rectangle, subsampleRatio YCbCrSubsampleRatio, de
 		}
 	}
 }
+
+func TestYCbCrSlicesDontOverlap(t *testing.T) {
+	m := NewYCbCr(Rect(0, 0, 8, 8), YCbCrSubsampleRatio420)
+	names := []string{"Y", "Cb", "Cr"}
+	slices := [][]byte{
+		m.Y[:cap(m.Y)],
+		m.Cb[:cap(m.Cb)],
+		m.Cr[:cap(m.Cr)],
+	}
+	for i, slice := range slices {
+		want := uint8(10 + i)
+		for j := range slice {
+			slice[j] = want
+		}
+	}
+	for i, slice := range slices {
+		want := uint8(10 + i)
+		for j, got := range slice {
+			if got != want {
+				t.Fatalf("m.%s[%d]: got %d, want %d", names[i], j, got, want)
+			}
+		}
+	}
+}
diff --git a/src/internal/format/format.go b/src/internal/format/format.go
new file mode 100644
index 0000000..a8270ba
--- /dev/null
+++ b/src/internal/format/format.go
@@ -0,0 +1,163 @@
+// 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. Add an extra '\n' before the '}'
+	// to make sure comments are flushed before the '}'.
+	fsrc := append(append([]byte("package p; func _() {"), src...), '\n', '\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 _() {"):]
+			// Remove only the "}\n" suffix: remaining whitespaces will be trimmed anyway
+			src = src[:len(src)-len("}\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/singleflight/singleflight.go b/src/internal/singleflight/singleflight.go
new file mode 100644
index 0000000..f4cb2d6
--- /dev/null
+++ b/src/internal/singleflight/singleflight.go
@@ -0,0 +1,111 @@
+// 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 singleflight provides a duplicate function call suppression
+// mechanism.
+package singleflight
+
+import "sync"
+
+// call is an in-flight or completed singleflight.Do call
+type call struct {
+	wg sync.WaitGroup
+
+	// These fields are written once before the WaitGroup is done
+	// and are only read after the WaitGroup is done.
+	val interface{}
+	err error
+
+	// These fields are read and written with the singleflight
+	// mutex held before the WaitGroup is done, and are read but
+	// not written after the WaitGroup is done.
+	dups  int
+	chans []chan<- Result
+}
+
+// Group represents a class of work and forms a namespace in
+// which units of work can be executed with duplicate suppression.
+type Group struct {
+	mu sync.Mutex       // protects m
+	m  map[string]*call // lazily initialized
+}
+
+// Result holds the results of Do, so they can be passed
+// on a channel.
+type Result struct {
+	Val    interface{}
+	Err    error
+	Shared bool
+}
+
+// Do executes and returns the results of the given function, making
+// sure that only one execution is in-flight for a given key at a
+// time. If a duplicate comes in, the duplicate caller waits for the
+// original to complete and receives the same results.
+// The return value shared indicates whether v was given to multiple callers.
+func (g *Group) Do(key string, fn func() (interface{}, error)) (v interface{}, err error, shared bool) {
+	g.mu.Lock()
+	if g.m == nil {
+		g.m = make(map[string]*call)
+	}
+	if c, ok := g.m[key]; ok {
+		c.dups++
+		g.mu.Unlock()
+		c.wg.Wait()
+		return c.val, c.err, true
+	}
+	c := new(call)
+	c.wg.Add(1)
+	g.m[key] = c
+	g.mu.Unlock()
+
+	g.doCall(c, key, fn)
+	return c.val, c.err, c.dups > 0
+}
+
+// DoChan is like Do but returns a channel that will receive the
+// results when they are ready.
+func (g *Group) DoChan(key string, fn func() (interface{}, error)) <-chan Result {
+	ch := make(chan Result, 1)
+	g.mu.Lock()
+	if g.m == nil {
+		g.m = make(map[string]*call)
+	}
+	if c, ok := g.m[key]; ok {
+		c.dups++
+		c.chans = append(c.chans, ch)
+		g.mu.Unlock()
+		return ch
+	}
+	c := &call{chans: []chan<- Result{ch}}
+	c.wg.Add(1)
+	g.m[key] = c
+	g.mu.Unlock()
+
+	go g.doCall(c, key, fn)
+
+	return ch
+}
+
+// doCall handles the single call for a key.
+func (g *Group) doCall(c *call, key string, fn func() (interface{}, error)) {
+	c.val, c.err = fn()
+	c.wg.Done()
+
+	g.mu.Lock()
+	delete(g.m, key)
+	for _, ch := range c.chans {
+		ch <- Result{c.val, c.err, c.dups > 0}
+	}
+	g.mu.Unlock()
+}
+
+// Forget tells the singleflight to forget about a key.  Future calls
+// to Do for this key will call the function rather than waiting for
+// an earlier call to complete.
+func (g *Group) Forget(key string) {
+	g.mu.Lock()
+	delete(g.m, key)
+	g.mu.Unlock()
+}
diff --git a/src/internal/singleflight/singleflight_test.go b/src/internal/singleflight/singleflight_test.go
new file mode 100644
index 0000000..c0ec024
--- /dev/null
+++ b/src/internal/singleflight/singleflight_test.go
@@ -0,0 +1,87 @@
+// 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 singleflight
+
+import (
+	"errors"
+	"fmt"
+	"sync"
+	"sync/atomic"
+	"testing"
+	"time"
+)
+
+func TestDo(t *testing.T) {
+	var g Group
+	v, err, _ := g.Do("key", func() (interface{}, error) {
+		return "bar", nil
+	})
+	if got, want := fmt.Sprintf("%v (%T)", v, v), "bar (string)"; got != want {
+		t.Errorf("Do = %v; want %v", got, want)
+	}
+	if err != nil {
+		t.Errorf("Do error = %v", err)
+	}
+}
+
+func TestDoErr(t *testing.T) {
+	var g Group
+	someErr := errors.New("Some error")
+	v, err, _ := g.Do("key", func() (interface{}, error) {
+		return nil, someErr
+	})
+	if err != someErr {
+		t.Errorf("Do error = %v; want someErr %v", err, someErr)
+	}
+	if v != nil {
+		t.Errorf("unexpected non-nil value %#v", v)
+	}
+}
+
+func TestDoDupSuppress(t *testing.T) {
+	var g Group
+	var wg1, wg2 sync.WaitGroup
+	c := make(chan string, 1)
+	var calls int32
+	fn := func() (interface{}, error) {
+		if atomic.AddInt32(&calls, 1) == 1 {
+			// First invocation.
+			wg1.Done()
+		}
+		v := <-c
+		c <- v // pump; make available for any future calls
+
+		time.Sleep(10 * time.Millisecond) // let more goroutines enter Do
+
+		return v, nil
+	}
+
+	const n = 10
+	wg1.Add(1)
+	for i := 0; i < n; i++ {
+		wg1.Add(1)
+		wg2.Add(1)
+		go func() {
+			defer wg2.Done()
+			wg1.Done()
+			v, err, _ := g.Do("key", fn)
+			if err != nil {
+				t.Errorf("Do error: %v", err)
+				return
+			}
+			if s, _ := v.(string); s != "bar" {
+				t.Errorf("Do = %T %v; want %q", v, v, "bar")
+			}
+		}()
+	}
+	wg1.Wait()
+	// At least one goroutine is in fn now and all of them have at
+	// least reached the line before the Do.
+	c <- "bar"
+	wg2.Wait()
+	if got := atomic.LoadInt32(&calls); got <= 0 || got >= n {
+		t.Errorf("number of calls = %d; want over 0 and less than %d", got, n)
+	}
+}
diff --git a/src/internal/syscall/getrandom_linux.go b/src/internal/syscall/getrandom_linux.go
deleted file mode 100644
index 944bab3..0000000
--- a/src/internal/syscall/getrandom_linux.go
+++ /dev/null
@@ -1,56 +0,0 @@
-// 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 syscall
-
-import (
-	"runtime"
-	"sync/atomic"
-	stdsyscall "syscall"
-	"unsafe"
-)
-
-var randomTrap = map[string]uintptr{
-	"386":   355,
-	"amd64": 318,
-	"arm":   384,
-}[runtime.GOARCH]
-
-var randomUnsupported int32 // atomic
-
-// GetRandomFlag is a flag supported by the getrandom system call.
-type GetRandomFlag uintptr
-
-const (
-	// GRND_NONBLOCK means return EAGAIN rather than blocking.
-	GRND_NONBLOCK GetRandomFlag = 0x0001
-
-	// GRND_RANDOM means use the /dev/random pool instead of /dev/urandom.
-	GRND_RANDOM GetRandomFlag = 0x0002
-)
-
-// GetRandom calls the Linux getrandom system call.
-// See https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=c6e9d6f38894798696f23c8084ca7edbf16ee895
-func GetRandom(p []byte, flags GetRandomFlag) (n int, err error) {
-	if randomTrap == 0 {
-		return 0, stdsyscall.ENOSYS
-	}
-	if len(p) == 0 {
-		return 0, nil
-	}
-	if atomic.LoadInt32(&randomUnsupported) != 0 {
-		return 0, stdsyscall.ENOSYS
-	}
-	r1, _, errno := stdsyscall.Syscall(randomTrap,
-		uintptr(unsafe.Pointer(&p[0])),
-		uintptr(len(p)),
-		uintptr(flags))
-	if errno != 0 {
-		if errno == stdsyscall.ENOSYS {
-			atomic.StoreInt32(&randomUnsupported, 1)
-		}
-		return 0, errno
-	}
-	return int(r1), nil
-}
diff --git a/src/internal/syscall/unix/getrandom_linux.go b/src/internal/syscall/unix/getrandom_linux.go
new file mode 100644
index 0000000..7388271
--- /dev/null
+++ b/src/internal/syscall/unix/getrandom_linux.go
@@ -0,0 +1,58 @@
+// 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 unix
+
+import (
+	"runtime"
+	"sync/atomic"
+	"syscall"
+	"unsafe"
+)
+
+var randomTrap = map[string]uintptr{
+	"386":     355,
+	"amd64":   318,
+	"arm":     384,
+	"ppc64":   359,
+	"ppc64le": 359,
+}[runtime.GOARCH]
+
+var randomUnsupported int32 // atomic
+
+// GetRandomFlag is a flag supported by the getrandom system call.
+type GetRandomFlag uintptr
+
+const (
+	// GRND_NONBLOCK means return EAGAIN rather than blocking.
+	GRND_NONBLOCK GetRandomFlag = 0x0001
+
+	// GRND_RANDOM means use the /dev/random pool instead of /dev/urandom.
+	GRND_RANDOM GetRandomFlag = 0x0002
+)
+
+// GetRandom calls the Linux getrandom system call.
+// See https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=c6e9d6f38894798696f23c8084ca7edbf16ee895
+func GetRandom(p []byte, flags GetRandomFlag) (n int, err error) {
+	if randomTrap == 0 {
+		return 0, syscall.ENOSYS
+	}
+	if len(p) == 0 {
+		return 0, nil
+	}
+	if atomic.LoadInt32(&randomUnsupported) != 0 {
+		return 0, syscall.ENOSYS
+	}
+	r1, _, errno := syscall.Syscall(randomTrap,
+		uintptr(unsafe.Pointer(&p[0])),
+		uintptr(len(p)),
+		uintptr(flags))
+	if errno != 0 {
+		if errno == syscall.ENOSYS {
+			atomic.StoreInt32(&randomUnsupported, 1)
+		}
+		return 0, errno
+	}
+	return int(r1), nil
+}
diff --git a/src/internal/syscall/windows/registry/export_test.go b/src/internal/syscall/windows/registry/export_test.go
new file mode 100644
index 0000000..8badf6f
--- /dev/null
+++ b/src/internal/syscall/windows/registry/export_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.
+
+// +build windows
+
+package registry
+
+func (k Key) SetValue(name string, valtype uint32, data []byte) error {
+	return k.setValue(name, valtype, data)
+}
diff --git a/src/internal/syscall/windows/registry/key.go b/src/internal/syscall/windows/registry/key.go
new file mode 100644
index 0000000..62144d3
--- /dev/null
+++ b/src/internal/syscall/windows/registry/key.go
@@ -0,0 +1,175 @@
+// 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 windows
+
+// Package registry provides access to the Windows registry.
+//
+// Here is a simple example, opening a registry key and reading a string value from it.
+//
+//	k, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion`, registry.QUERY_VALUE)
+//	if err != nil {
+//		log.Fatal(err)
+//	}
+//	defer k.Close()
+//
+//	s, _, err := k.GetStringValue("SystemRoot")
+//	if err != nil {
+//		log.Fatal(err)
+//	}
+//	fmt.Printf("Windows system root is %q\n", s)
+//
+// NOTE: This package is a copy of golang.org/x/sys/windows/registry
+// with KeyInfo.ModTime removed to prevent dependency cycles.
+//
+package registry
+
+import (
+	"io"
+	"syscall"
+)
+
+const (
+	// Registry key security and access rights.
+	// See https://msdn.microsoft.com/en-us/library/windows/desktop/ms724878.aspx
+	// for details.
+	ALL_ACCESS         = 0xf003f
+	CREATE_LINK        = 0x00020
+	CREATE_SUB_KEY     = 0x00004
+	ENUMERATE_SUB_KEYS = 0x00008
+	EXECUTE            = 0x20019
+	NOTIFY             = 0x00010
+	QUERY_VALUE        = 0x00001
+	READ               = 0x20019
+	SET_VALUE          = 0x00002
+	WOW64_32KEY        = 0x00200
+	WOW64_64KEY        = 0x00100
+	WRITE              = 0x20006
+)
+
+// Key is a handle to an open Windows registry key.
+// Keys can be obtained by calling OpenKey; there are
+// also some predefined root keys such as CURRENT_USER.
+// Keys can be used directly in the Windows API.
+type Key syscall.Handle
+
+const (
+	// Windows defines some predefined root keys that are always open.
+	// An application can use these keys as entry points to the registry.
+	// Normally these keys are used in OpenKey to open new keys,
+	// but they can also be used anywhere a Key is required.
+	CLASSES_ROOT   = Key(syscall.HKEY_CLASSES_ROOT)
+	CURRENT_USER   = Key(syscall.HKEY_CURRENT_USER)
+	LOCAL_MACHINE  = Key(syscall.HKEY_LOCAL_MACHINE)
+	USERS          = Key(syscall.HKEY_USERS)
+	CURRENT_CONFIG = Key(syscall.HKEY_CURRENT_CONFIG)
+)
+
+// Close closes open key k.
+func (k Key) Close() error {
+	return syscall.RegCloseKey(syscall.Handle(k))
+}
+
+// OpenKey opens a new key with path name relative to key k.
+// It accepts any open key, including CURRENT_USER and others,
+// and returns the new key and an error.
+// The access parameter specifies desired access rights to the
+// key to be opened.
+func OpenKey(k Key, path string, access uint32) (Key, error) {
+	p, err := syscall.UTF16PtrFromString(path)
+	if err != nil {
+		return 0, err
+	}
+	var subkey syscall.Handle
+	err = syscall.RegOpenKeyEx(syscall.Handle(k), p, 0, access, &subkey)
+	if err != nil {
+		return 0, err
+	}
+	return Key(subkey), nil
+}
+
+// ReadSubKeyNames returns the names of subkeys of key k.
+// The parameter n controls the number of returned names,
+// analogous to the way os.File.Readdirnames works.
+func (k Key) ReadSubKeyNames(n int) ([]string, error) {
+	ki, err := k.Stat()
+	if err != nil {
+		return nil, err
+	}
+	names := make([]string, 0, ki.SubKeyCount)
+	buf := make([]uint16, ki.MaxSubKeyLen+1) // extra room for terminating zero byte
+loopItems:
+	for i := uint32(0); ; i++ {
+		if n > 0 {
+			if len(names) == n {
+				return names, nil
+			}
+		}
+		l := uint32(len(buf))
+		for {
+			err := syscall.RegEnumKeyEx(syscall.Handle(k), i, &buf[0], &l, nil, nil, nil, nil)
+			if err == nil {
+				break
+			}
+			if err == syscall.ERROR_MORE_DATA {
+				// Double buffer size and try again.
+				l = uint32(2 * len(buf))
+				buf = make([]uint16, l)
+				continue
+			}
+			if err == _ERROR_NO_MORE_ITEMS {
+				break loopItems
+			}
+			return names, err
+		}
+		names = append(names, syscall.UTF16ToString(buf[:l]))
+	}
+	if n > len(names) {
+		return names, io.EOF
+	}
+	return names, nil
+}
+
+// CreateKey creates a key named path under open key k.
+// CreateKey returns the new key and a boolean flag that reports
+// whether the key already existed.
+// The access parameter specifies the access rights for the key
+// to be created.
+func CreateKey(k Key, path string, access uint32) (newk Key, openedExisting bool, err error) {
+	var h syscall.Handle
+	var d uint32
+	err = regCreateKeyEx(syscall.Handle(k), syscall.StringToUTF16Ptr(path),
+		0, nil, _REG_OPTION_NON_VOLATILE, access, nil, &h, &d)
+	if err != nil {
+		return 0, false, err
+	}
+	return Key(h), d == _REG_OPENED_EXISTING_KEY, nil
+}
+
+// DeleteKey deletes the subkey path of key k and its values.
+func DeleteKey(k Key, path string) error {
+	return regDeleteKey(syscall.Handle(k), syscall.StringToUTF16Ptr(path))
+}
+
+// A KeyInfo describes the statistics of a key. It is returned by Stat.
+type KeyInfo struct {
+	SubKeyCount     uint32
+	MaxSubKeyLen    uint32 // size of the key's subkey with the longest name, in Unicode characters, not including the terminating zero byte
+	ValueCount      uint32
+	MaxValueNameLen uint32 // size of the key's longest value name, in Unicode characters, not including the terminating zero byte
+	MaxValueLen     uint32 // longest data component among the key's values, in bytes
+	lastWriteTime   syscall.Filetime
+}
+
+// Stat retrieves information about the open key k.
+func (k Key) Stat() (*KeyInfo, error) {
+	var ki KeyInfo
+	err := syscall.RegQueryInfoKey(syscall.Handle(k), nil, nil, nil,
+		&ki.SubKeyCount, &ki.MaxSubKeyLen, nil, &ki.ValueCount,
+		&ki.MaxValueNameLen, &ki.MaxValueLen, nil, &ki.lastWriteTime)
+	if err != nil {
+		return nil, err
+	}
+	return &ki, nil
+}
diff --git a/src/internal/syscall/windows/registry/registry_test.go b/src/internal/syscall/windows/registry/registry_test.go
new file mode 100644
index 0000000..07eccb2
--- /dev/null
+++ b/src/internal/syscall/windows/registry/registry_test.go
@@ -0,0 +1,678 @@
+// 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 windows
+
+package registry_test
+
+import (
+	"bytes"
+	"crypto/rand"
+	"os"
+	"syscall"
+	"testing"
+
+	"internal/syscall/windows/registry"
+)
+
+func randKeyName(prefix string) string {
+	const numbers = "0123456789"
+	buf := make([]byte, 10)
+	rand.Read(buf)
+	for i, b := range buf {
+		buf[i] = numbers[b%byte(len(numbers))]
+	}
+	return prefix + string(buf)
+}
+
+func TestReadSubKeyNames(t *testing.T) {
+	k, err := registry.OpenKey(registry.CLASSES_ROOT, "TypeLib", registry.ENUMERATE_SUB_KEYS|registry.QUERY_VALUE)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer k.Close()
+
+	names, err := k.ReadSubKeyNames(-1)
+	if err != nil {
+		t.Fatal(err)
+	}
+	var foundStdOle bool
+	for _, name := range names {
+		// Every PC has "stdole 2.0 OLE Automation" library installed.
+		if name == "{00020430-0000-0000-C000-000000000046}" {
+			foundStdOle = true
+		}
+	}
+	if !foundStdOle {
+		t.Fatal("could not find stdole 2.0 OLE Automation")
+	}
+}
+
+func TestCreateOpenDeleteKey(t *testing.T) {
+	k, err := registry.OpenKey(registry.CURRENT_USER, "Software", registry.QUERY_VALUE)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer k.Close()
+
+	testKName := randKeyName("TestCreateOpenDeleteKey_")
+
+	testK, exist, err := registry.CreateKey(k, testKName, registry.CREATE_SUB_KEY)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer testK.Close()
+
+	if exist {
+		t.Fatalf("key %q already exists", testKName)
+	}
+
+	testKAgain, exist, err := registry.CreateKey(k, testKName, registry.CREATE_SUB_KEY)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer testKAgain.Close()
+
+	if !exist {
+		t.Fatalf("key %q should already exist", testKName)
+	}
+
+	testKOpened, err := registry.OpenKey(k, testKName, registry.ENUMERATE_SUB_KEYS)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer testKOpened.Close()
+
+	err = registry.DeleteKey(k, testKName)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	testKOpenedAgain, err := registry.OpenKey(k, testKName, registry.ENUMERATE_SUB_KEYS)
+	if err == nil {
+		defer testKOpenedAgain.Close()
+		t.Fatalf("key %q should already been deleted", testKName)
+	}
+	if err != registry.ErrNotExist {
+		t.Fatalf(`unexpected error ("not exist" expected): %v`, err)
+	}
+}
+
+func equalStringSlice(a, b []string) bool {
+	if len(a) != len(b) {
+		return false
+	}
+	if a == nil {
+		return true
+	}
+	for i := range a {
+		if a[i] != b[i] {
+			return false
+		}
+	}
+	return true
+}
+
+type ValueTest struct {
+	Type     uint32
+	Name     string
+	Value    interface{}
+	WillFail bool
+}
+
+var ValueTests = []ValueTest{
+	{Type: registry.SZ, Name: "String1", Value: ""},
+	{Type: registry.SZ, Name: "String2", Value: "\000", WillFail: true},
+	{Type: registry.SZ, Name: "String3", Value: "Hello World"},
+	{Type: registry.SZ, Name: "String4", Value: "Hello World\000", WillFail: true},
+	{Type: registry.EXPAND_SZ, Name: "ExpString1", Value: ""},
+	{Type: registry.EXPAND_SZ, Name: "ExpString2", Value: "\000", WillFail: true},
+	{Type: registry.EXPAND_SZ, Name: "ExpString3", Value: "Hello World"},
+	{Type: registry.EXPAND_SZ, Name: "ExpString4", Value: "Hello\000World", WillFail: true},
+	{Type: registry.EXPAND_SZ, Name: "ExpString5", Value: "%PATH%"},
+	{Type: registry.EXPAND_SZ, Name: "ExpString6", Value: "%NO_SUCH_VARIABLE%"},
+	{Type: registry.EXPAND_SZ, Name: "ExpString7", Value: "%PATH%;."},
+	{Type: registry.BINARY, Name: "Binary1", Value: []byte{}},
+	{Type: registry.BINARY, Name: "Binary2", Value: []byte{1, 2, 3}},
+	{Type: registry.BINARY, Name: "Binary3", Value: []byte{3, 2, 1, 0, 1, 2, 3}},
+	{Type: registry.DWORD, Name: "Dword1", Value: uint64(0)},
+	{Type: registry.DWORD, Name: "Dword2", Value: uint64(1)},
+	{Type: registry.DWORD, Name: "Dword3", Value: uint64(0xff)},
+	{Type: registry.DWORD, Name: "Dword4", Value: uint64(0xffff)},
+	{Type: registry.QWORD, Name: "Qword1", Value: uint64(0)},
+	{Type: registry.QWORD, Name: "Qword2", Value: uint64(1)},
+	{Type: registry.QWORD, Name: "Qword3", Value: uint64(0xff)},
+	{Type: registry.QWORD, Name: "Qword4", Value: uint64(0xffff)},
+	{Type: registry.QWORD, Name: "Qword5", Value: uint64(0xffffff)},
+	{Type: registry.QWORD, Name: "Qword6", Value: uint64(0xffffffff)},
+	{Type: registry.MULTI_SZ, Name: "MultiString1", Value: []string{"a", "b", "c"}},
+	{Type: registry.MULTI_SZ, Name: "MultiString2", Value: []string{"abc", "", "cba"}},
+	{Type: registry.MULTI_SZ, Name: "MultiString3", Value: []string{""}},
+	{Type: registry.MULTI_SZ, Name: "MultiString4", Value: []string{"abcdef"}},
+	{Type: registry.MULTI_SZ, Name: "MultiString5", Value: []string{"\000"}, WillFail: true},
+	{Type: registry.MULTI_SZ, Name: "MultiString6", Value: []string{"a\000b"}, WillFail: true},
+	{Type: registry.MULTI_SZ, Name: "MultiString7", Value: []string{"ab", "\000", "cd"}, WillFail: true},
+	{Type: registry.MULTI_SZ, Name: "MultiString8", Value: []string{"\000", "cd"}, WillFail: true},
+	{Type: registry.MULTI_SZ, Name: "MultiString9", Value: []string{"ab", "\000"}, WillFail: true},
+}
+
+func setValues(t *testing.T, k registry.Key) {
+	for _, test := range ValueTests {
+		var err error
+		switch test.Type {
+		case registry.SZ:
+			err = k.SetStringValue(test.Name, test.Value.(string))
+		case registry.EXPAND_SZ:
+			err = k.SetExpandStringValue(test.Name, test.Value.(string))
+		case registry.MULTI_SZ:
+			err = k.SetStringsValue(test.Name, test.Value.([]string))
+		case registry.BINARY:
+			err = k.SetBinaryValue(test.Name, test.Value.([]byte))
+		case registry.DWORD:
+			err = k.SetDWordValue(test.Name, uint32(test.Value.(uint64)))
+		case registry.QWORD:
+			err = k.SetQWordValue(test.Name, test.Value.(uint64))
+		default:
+			t.Fatalf("unsupported type %d for %s value", test.Type, test.Name)
+		}
+		if test.WillFail {
+			if err == nil {
+				t.Fatalf("setting %s value %q should fail, but succeeded", test.Name, test.Value)
+			}
+		} else {
+			if err != nil {
+				t.Fatal(err)
+			}
+		}
+	}
+}
+
+func enumerateValues(t *testing.T, k registry.Key) {
+	names, err := k.ReadValueNames(-1)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	haveNames := make(map[string]bool)
+	for _, n := range names {
+		haveNames[n] = false
+	}
+	for _, test := range ValueTests {
+		wantFound := !test.WillFail
+		_, haveFound := haveNames[test.Name]
+		if wantFound && !haveFound {
+			t.Errorf("value %s is not found while enumerating", test.Name)
+		}
+		if haveFound && !wantFound {
+			t.Errorf("value %s is found while enumerating, but expected to fail", test.Name)
+		}
+		if haveFound {
+			delete(haveNames, test.Name)
+		}
+	}
+	for n, v := range haveNames {
+		t.Errorf("value %s (%v) is found while enumerating, but has not been cretaed", n, v)
+	}
+}
+
+func testErrNotExist(t *testing.T, name string, err error) {
+	if err == nil {
+		t.Errorf("%s value should not exist", name)
+		return
+	}
+	if err != registry.ErrNotExist {
+		t.Errorf("reading %s value should return 'not exist' error, but got: %s", name, err)
+		return
+	}
+}
+
+func testErrUnexpectedType(t *testing.T, test ValueTest, gottype uint32, err error) {
+	if err == nil {
+		t.Errorf("GetXValue(%q) should not succeed", test.Name)
+		return
+	}
+	if err != registry.ErrUnexpectedType {
+		t.Errorf("reading %s value should return 'unexpected key value type' error, but got: %s", test.Name, err)
+		return
+	}
+	if gottype != test.Type {
+		t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype)
+		return
+	}
+}
+
+func testGetStringValue(t *testing.T, k registry.Key, test ValueTest) {
+	got, gottype, err := k.GetStringValue(test.Name)
+	if err != nil {
+		t.Errorf("GetStringValue(%s) failed: %v", test.Name, err)
+		return
+	}
+	if got != test.Value {
+		t.Errorf("want %s value %q, got %q", test.Name, test.Value, got)
+		return
+	}
+	if gottype != test.Type {
+		t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype)
+		return
+	}
+	if gottype == registry.EXPAND_SZ {
+		_, err = registry.ExpandString(got)
+		if err != nil {
+			t.Errorf("ExpandString(%s) failed: %v", got, err)
+			return
+		}
+	}
+}
+
+func testGetIntegerValue(t *testing.T, k registry.Key, test ValueTest) {
+	got, gottype, err := k.GetIntegerValue(test.Name)
+	if err != nil {
+		t.Errorf("GetIntegerValue(%s) failed: %v", test.Name, err)
+		return
+	}
+	if got != test.Value.(uint64) {
+		t.Errorf("want %s value %v, got %v", test.Name, test.Value, got)
+		return
+	}
+	if gottype != test.Type {
+		t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype)
+		return
+	}
+}
+
+func testGetBinaryValue(t *testing.T, k registry.Key, test ValueTest) {
+	got, gottype, err := k.GetBinaryValue(test.Name)
+	if err != nil {
+		t.Errorf("GetBinaryValue(%s) failed: %v", test.Name, err)
+		return
+	}
+	if !bytes.Equal(got, test.Value.([]byte)) {
+		t.Errorf("want %s value %v, got %v", test.Name, test.Value, got)
+		return
+	}
+	if gottype != test.Type {
+		t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype)
+		return
+	}
+}
+
+func testGetStringsValue(t *testing.T, k registry.Key, test ValueTest) {
+	got, gottype, err := k.GetStringsValue(test.Name)
+	if err != nil {
+		t.Errorf("GetStringsValue(%s) failed: %v", test.Name, err)
+		return
+	}
+	if !equalStringSlice(got, test.Value.([]string)) {
+		t.Errorf("want %s value %#v, got %#v", test.Name, test.Value, got)
+		return
+	}
+	if gottype != test.Type {
+		t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype)
+		return
+	}
+}
+
+func testGetValue(t *testing.T, k registry.Key, test ValueTest, size int) {
+	if size <= 0 {
+		return
+	}
+	// read data with no buffer
+	gotsize, gottype, err := k.GetValue(test.Name, nil)
+	if err != nil {
+		t.Errorf("GetValue(%s, [%d]byte) failed: %v", test.Name, size, err)
+		return
+	}
+	if gotsize != size {
+		t.Errorf("want %s value size of %d, got %v", test.Name, size, gotsize)
+		return
+	}
+	if gottype != test.Type {
+		t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype)
+		return
+	}
+	// read data with short buffer
+	gotsize, gottype, err = k.GetValue(test.Name, make([]byte, size-1))
+	if err == nil {
+		t.Errorf("GetValue(%s, [%d]byte) should fail, but suceeded", test.Name, size-1)
+		return
+	}
+	if err != registry.ErrShortBuffer {
+		t.Errorf("reading %s value should return 'short buffer' error, but got: %s", test.Name, err)
+		return
+	}
+	if gotsize != size {
+		t.Errorf("want %s value size of %d, got %v", test.Name, size, gotsize)
+		return
+	}
+	if gottype != test.Type {
+		t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype)
+		return
+	}
+	// read full data
+	gotsize, gottype, err = k.GetValue(test.Name, make([]byte, size))
+	if err != nil {
+		t.Errorf("GetValue(%s, [%d]byte) failed: %v", test.Name, size, err)
+		return
+	}
+	if gotsize != size {
+		t.Errorf("want %s value size of %d, got %v", test.Name, size, gotsize)
+		return
+	}
+	if gottype != test.Type {
+		t.Errorf("want %s value type %v, got %v", test.Name, test.Type, gottype)
+		return
+	}
+	// check GetValue returns ErrNotExist as required
+	_, _, err = k.GetValue(test.Name+"_not_there", make([]byte, size))
+	if err == nil {
+		t.Errorf("GetValue(%q) should not succeed", test.Name)
+		return
+	}
+	if err != registry.ErrNotExist {
+		t.Errorf("GetValue(%q) should return 'not exist' error, but got: %s", test.Name, err)
+		return
+	}
+}
+
+func testValues(t *testing.T, k registry.Key) {
+	for _, test := range ValueTests {
+		switch test.Type {
+		case registry.SZ, registry.EXPAND_SZ:
+			if test.WillFail {
+				_, _, err := k.GetStringValue(test.Name)
+				testErrNotExist(t, test.Name, err)
+			} else {
+				testGetStringValue(t, k, test)
+				_, gottype, err := k.GetIntegerValue(test.Name)
+				testErrUnexpectedType(t, test, gottype, err)
+				// Size of utf16 string in bytes is not perfect,
+				// but correct for current test values.
+				// Size also includes terminating 0.
+				testGetValue(t, k, test, (len(test.Value.(string))+1)*2)
+			}
+			_, _, err := k.GetStringValue(test.Name + "_string_not_created")
+			testErrNotExist(t, test.Name+"_string_not_created", err)
+		case registry.DWORD, registry.QWORD:
+			testGetIntegerValue(t, k, test)
+			_, gottype, err := k.GetBinaryValue(test.Name)
+			testErrUnexpectedType(t, test, gottype, err)
+			_, _, err = k.GetIntegerValue(test.Name + "_int_not_created")
+			testErrNotExist(t, test.Name+"_int_not_created", err)
+			size := 8
+			if test.Type == registry.DWORD {
+				size = 4
+			}
+			testGetValue(t, k, test, size)
+		case registry.BINARY:
+			testGetBinaryValue(t, k, test)
+			_, gottype, err := k.GetStringsValue(test.Name)
+			testErrUnexpectedType(t, test, gottype, err)
+			_, _, err = k.GetBinaryValue(test.Name + "_byte_not_created")
+			testErrNotExist(t, test.Name+"_byte_not_created", err)
+			testGetValue(t, k, test, len(test.Value.([]byte)))
+		case registry.MULTI_SZ:
+			if test.WillFail {
+				_, _, err := k.GetStringsValue(test.Name)
+				testErrNotExist(t, test.Name, err)
+			} else {
+				testGetStringsValue(t, k, test)
+				_, gottype, err := k.GetStringValue(test.Name)
+				testErrUnexpectedType(t, test, gottype, err)
+				size := 0
+				for _, s := range test.Value.([]string) {
+					size += len(s) + 1 // nil terminated
+				}
+				size += 1 // extra nil at the end
+				size *= 2 // count bytes, not uint16
+				testGetValue(t, k, test, size)
+			}
+			_, _, err := k.GetStringsValue(test.Name + "_strings_not_created")
+			testErrNotExist(t, test.Name+"_strings_not_created", err)
+		default:
+			t.Errorf("unsupported type %d for %s value", test.Type, test.Name)
+			continue
+		}
+	}
+}
+
+func testStat(t *testing.T, k registry.Key) {
+	subk, _, err := registry.CreateKey(k, "subkey", registry.CREATE_SUB_KEY)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	defer subk.Close()
+
+	defer registry.DeleteKey(k, "subkey")
+
+	ki, err := k.Stat()
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	if ki.SubKeyCount != 1 {
+		t.Error("key must have 1 subkey")
+	}
+	if ki.MaxSubKeyLen != 6 {
+		t.Error("key max subkey name length must be 6")
+	}
+	if ki.ValueCount != 24 {
+		t.Errorf("key must have 24 values, but is %d", ki.ValueCount)
+	}
+	if ki.MaxValueNameLen != 12 {
+		t.Errorf("key max value name length must be 10, but is %d", ki.MaxValueNameLen)
+	}
+	if ki.MaxValueLen != 38 {
+		t.Errorf("key max value length must be 38, but is %d", ki.MaxValueLen)
+	}
+}
+
+func deleteValues(t *testing.T, k registry.Key) {
+	for _, test := range ValueTests {
+		if test.WillFail {
+			continue
+		}
+		err := k.DeleteValue(test.Name)
+		if err != nil {
+			t.Error(err)
+			continue
+		}
+	}
+	names, err := k.ReadValueNames(-1)
+	if err != nil {
+		t.Error(err)
+		return
+	}
+	if len(names) != 0 {
+		t.Errorf("some values remain after deletion: %v", names)
+	}
+}
+
+func TestValues(t *testing.T) {
+	softwareK, err := registry.OpenKey(registry.CURRENT_USER, "Software", registry.QUERY_VALUE)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer softwareK.Close()
+
+	testKName := randKeyName("TestValues_")
+
+	k, exist, err := registry.CreateKey(softwareK, testKName, registry.CREATE_SUB_KEY|registry.QUERY_VALUE|registry.SET_VALUE)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer k.Close()
+
+	if exist {
+		t.Fatalf("key %q already exists", testKName)
+	}
+
+	defer registry.DeleteKey(softwareK, testKName)
+
+	setValues(t, k)
+
+	enumerateValues(t, k)
+
+	testValues(t, k)
+
+	testStat(t, k)
+
+	deleteValues(t, k)
+}
+
+func walkKey(t *testing.T, k registry.Key, kname string) {
+	names, err := k.ReadValueNames(-1)
+	if err != nil {
+		t.Fatalf("reading value names of %s failed: %v", kname, err)
+	}
+	for _, name := range names {
+		_, valtype, err := k.GetValue(name, nil)
+		if err != nil {
+			t.Fatalf("reading value type of %s of %s failed: %v", name, kname, err)
+		}
+		switch valtype {
+		case registry.NONE:
+		case registry.SZ:
+			_, _, err := k.GetStringValue(name)
+			if err != nil {
+				t.Error(err)
+			}
+		case registry.EXPAND_SZ:
+			s, _, err := k.GetStringValue(name)
+			if err != nil {
+				t.Error(err)
+			}
+			_, err = registry.ExpandString(s)
+			if err != nil {
+				t.Error(err)
+			}
+		case registry.DWORD, registry.QWORD:
+			_, _, err := k.GetIntegerValue(name)
+			if err != nil {
+				t.Error(err)
+			}
+		case registry.BINARY:
+			_, _, err := k.GetBinaryValue(name)
+			if err != nil {
+				t.Error(err)
+			}
+		case registry.MULTI_SZ:
+			_, _, err := k.GetStringsValue(name)
+			if err != nil {
+				t.Error(err)
+			}
+		case registry.FULL_RESOURCE_DESCRIPTOR, registry.RESOURCE_LIST, registry.RESOURCE_REQUIREMENTS_LIST:
+			// TODO: not implemented
+		default:
+			t.Fatalf("value type %d of %s of %s failed: %v", valtype, name, kname, err)
+		}
+	}
+
+	names, err = k.ReadSubKeyNames(-1)
+	if err != nil {
+		t.Fatalf("reading sub-keys of %s failed: %v", kname, err)
+	}
+	for _, name := range names {
+		func() {
+			subk, err := registry.OpenKey(k, name, registry.ENUMERATE_SUB_KEYS|registry.QUERY_VALUE)
+			if err != nil {
+				if err == syscall.ERROR_ACCESS_DENIED {
+					// ignore error, if we are not allowed to access this key
+					return
+				}
+				t.Fatalf("opening sub-keys %s of %s failed: %v", name, kname, err)
+			}
+			defer subk.Close()
+
+			walkKey(t, subk, kname+`\`+name)
+		}()
+	}
+}
+
+func TestWalkFullRegistry(t *testing.T) {
+	if testing.Short() {
+		t.Skip("skipping long running test in short mode")
+	}
+	walkKey(t, registry.CLASSES_ROOT, "CLASSES_ROOT")
+	walkKey(t, registry.CURRENT_USER, "CURRENT_USER")
+	walkKey(t, registry.LOCAL_MACHINE, "LOCAL_MACHINE")
+	walkKey(t, registry.USERS, "USERS")
+	walkKey(t, registry.CURRENT_CONFIG, "CURRENT_CONFIG")
+}
+
+func TestExpandString(t *testing.T) {
+	got, err := registry.ExpandString("%PATH%")
+	if err != nil {
+		t.Fatal(err)
+	}
+	want := os.Getenv("PATH")
+	if got != want {
+		t.Errorf("want %q string expanded, got %q", want, got)
+	}
+}
+
+func TestInvalidValues(t *testing.T) {
+	softwareK, err := registry.OpenKey(registry.CURRENT_USER, "Software", registry.QUERY_VALUE)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer softwareK.Close()
+
+	testKName := randKeyName("TestInvalidValues_")
+
+	k, exist, err := registry.CreateKey(softwareK, testKName, registry.CREATE_SUB_KEY|registry.QUERY_VALUE|registry.SET_VALUE)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer k.Close()
+
+	if exist {
+		t.Fatalf("key %q already exists", testKName)
+	}
+
+	defer registry.DeleteKey(softwareK, testKName)
+
+	var tests = []struct {
+		Type uint32
+		Name string
+		Data []byte
+	}{
+		{registry.DWORD, "Dword1", nil},
+		{registry.DWORD, "Dword2", []byte{1, 2, 3}},
+		{registry.QWORD, "Qword1", nil},
+		{registry.QWORD, "Qword2", []byte{1, 2, 3}},
+		{registry.QWORD, "Qword3", []byte{1, 2, 3, 4, 5, 6, 7}},
+		{registry.MULTI_SZ, "MultiString1", nil},
+		{registry.MULTI_SZ, "MultiString2", []byte{0}},
+		{registry.MULTI_SZ, "MultiString3", []byte{'a', 'b', 0}},
+		{registry.MULTI_SZ, "MultiString4", []byte{'a', 0, 0, 'b', 0}},
+		{registry.MULTI_SZ, "MultiString5", []byte{'a', 0, 0}},
+	}
+
+	for _, test := range tests {
+		err := k.SetValue(test.Name, test.Type, test.Data)
+		if err != nil {
+			t.Fatalf("SetValue for %q failed: %v", test.Name, err)
+		}
+	}
+
+	for _, test := range tests {
+		switch test.Type {
+		case registry.DWORD, registry.QWORD:
+			value, valType, err := k.GetIntegerValue(test.Name)
+			if err == nil {
+				t.Errorf("GetIntegerValue(%q) succeeded. Returns type=%d value=%v", test.Name, valType, value)
+			}
+		case registry.MULTI_SZ:
+			value, valType, err := k.GetStringsValue(test.Name)
+			if err == nil {
+				if len(value) != 0 {
+					t.Errorf("GetStringsValue(%q) succeeded. Returns type=%d value=%v", test.Name, valType, value)
+				}
+			}
+		default:
+			t.Errorf("unsupported type %d for %s value", test.Type, test.Name)
+		}
+	}
+}
diff --git a/src/internal/syscall/windows/registry/syscall.go b/src/internal/syscall/windows/registry/syscall.go
new file mode 100644
index 0000000..38e573f
--- /dev/null
+++ b/src/internal/syscall/windows/registry/syscall.go
@@ -0,0 +1,28 @@
+// 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 windows
+
+package registry
+
+import "syscall"
+
+//go:generate go run $GOROOT/src/syscall/mksyscall_windows.go -output zsyscall_windows.go syscall.go
+
+const (
+	_REG_OPTION_NON_VOLATILE = 0
+
+	_REG_CREATED_NEW_KEY     = 1
+	_REG_OPENED_EXISTING_KEY = 2
+
+	_ERROR_NO_MORE_ITEMS syscall.Errno = 259
+)
+
+//sys	regCreateKeyEx(key syscall.Handle, subkey *uint16, reserved uint32, class *uint16, options uint32, desired uint32, sa *syscall.SecurityAttributes, result *syscall.Handle, disposition *uint32) (regerrno error) = advapi32.RegCreateKeyExW
+//sys	regDeleteKey(key syscall.Handle, subkey *uint16) (regerrno error) = advapi32.RegDeleteKeyW
+//sys	regSetValueEx(key syscall.Handle, valueName *uint16, reserved uint32, vtype uint32, buf *byte, bufsize uint32) (regerrno error) = advapi32.RegSetValueExW
+//sys	regEnumValue(key syscall.Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, valtype *uint32, buf *byte, buflen *uint32) (regerrno error) = advapi32.RegEnumValueW
+//sys	regDeleteValue(key syscall.Handle, name *uint16) (regerrno error) = advapi32.RegDeleteValueW
+
+//sys	expandEnvironmentStrings(src *uint16, dst *uint16, size uint32) (n uint32, err error) = kernel32.ExpandEnvironmentStringsW
diff --git a/src/internal/syscall/windows/registry/value.go b/src/internal/syscall/windows/registry/value.go
new file mode 100644
index 0000000..f4bb1b3
--- /dev/null
+++ b/src/internal/syscall/windows/registry/value.go
@@ -0,0 +1,329 @@
+// 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 windows
+
+package registry
+
+import (
+	"errors"
+	"io"
+	"syscall"
+	"unicode/utf16"
+	"unsafe"
+)
+
+const (
+	// Registry value types.
+	NONE                       = 0
+	SZ                         = 1
+	EXPAND_SZ                  = 2
+	BINARY                     = 3
+	DWORD                      = 4
+	DWORD_BIG_ENDIAN           = 5
+	LINK                       = 6
+	MULTI_SZ                   = 7
+	RESOURCE_LIST              = 8
+	FULL_RESOURCE_DESCRIPTOR   = 9
+	RESOURCE_REQUIREMENTS_LIST = 10
+	QWORD                      = 11
+)
+
+var (
+	// ErrShortBuffer is returned when the buffer was too short for the operation.
+	ErrShortBuffer = syscall.ERROR_MORE_DATA
+
+	// ErrNotExist is returned when a registry key or value does not exist.
+	ErrNotExist = syscall.ERROR_FILE_NOT_FOUND
+
+	// ErrUnexpectedType is returned by Get*Value when the value's type was unexpected.
+	ErrUnexpectedType = errors.New("unexpected key value type")
+)
+
+// GetValue retrieves the type and data for the specified value associated
+// with an open key k. It fills up buffer buf and returns the retrieved
+// byte count n. If buf is too small to fit the stored value it returns
+// ErrShortBuffer error along with the required buffer size n.
+// If no buffer is provided, it returns true and actual buffer size n.
+// If no buffer is provided, GetValue returns the value's type only.
+// If the value does not exist, the error returned is ErrNotExist.
+//
+// GetValue is a low level function. If value's type is known, use the appropriate
+// Get*Value function instead.
+func (k Key) GetValue(name string, buf []byte) (n int, valtype uint32, err error) {
+	pname, err := syscall.UTF16PtrFromString(name)
+	if err != nil {
+		return 0, 0, err
+	}
+	var pbuf *byte
+	if len(buf) > 0 {
+		pbuf = (*byte)(unsafe.Pointer(&buf[0]))
+	}
+	l := uint32(len(buf))
+	err = syscall.RegQueryValueEx(syscall.Handle(k), pname, nil, &valtype, pbuf, &l)
+	if err != nil {
+		return int(l), valtype, err
+	}
+	return int(l), valtype, nil
+}
+
+func (k Key) getValue(name string, buf []byte) (date []byte, valtype uint32, err error) {
+	p, err := syscall.UTF16PtrFromString(name)
+	if err != nil {
+		return nil, 0, err
+	}
+	var t uint32
+	n := uint32(len(buf))
+	for {
+		err = syscall.RegQueryValueEx(syscall.Handle(k), p, nil, &t, (*byte)(unsafe.Pointer(&buf[0])), &n)
+		if err == nil {
+			return buf[:n], t, nil
+		}
+		if err != syscall.ERROR_MORE_DATA {
+			return nil, 0, err
+		}
+		if n <= uint32(len(buf)) {
+			return nil, 0, err
+		}
+		buf = make([]byte, n)
+	}
+}
+
+// GetStringValue retrieves the string value for the specified
+// value name associated with an open key k. It also returns the value's type.
+// If value does not exist, GetStringValue returns ErrNotExist.
+// If value is not SZ or EXPAND_SZ, it will return the correct value
+// type and ErrUnexpectedType.
+func (k Key) GetStringValue(name string) (val string, valtype uint32, err error) {
+	data, typ, err2 := k.getValue(name, make([]byte, 64))
+	if err2 != nil {
+		return "", typ, err2
+	}
+	switch typ {
+	case SZ, EXPAND_SZ:
+	default:
+		return "", typ, ErrUnexpectedType
+	}
+	if len(data) == 0 {
+		return "", typ, nil
+	}
+	u := (*[1 << 10]uint16)(unsafe.Pointer(&data[0]))[:]
+	return syscall.UTF16ToString(u), typ, nil
+}
+
+// ExpandString expands environment-variable strings and replaces
+// them with the values defined for the current user.
+// Use ExpandString to expand EXPAND_SZ strings.
+func ExpandString(value string) (string, error) {
+	if value == "" {
+		return "", nil
+	}
+	p, err := syscall.UTF16PtrFromString(value)
+	if err != nil {
+		return "", err
+	}
+	r := make([]uint16, 100)
+	for {
+		n, err := expandEnvironmentStrings(p, &r[0], uint32(len(r)))
+		if err != nil {
+			return "", err
+		}
+		if n <= uint32(len(r)) {
+			u := (*[1 << 15]uint16)(unsafe.Pointer(&r[0]))[:]
+			return syscall.UTF16ToString(u), nil
+		}
+		r = make([]uint16, n)
+	}
+}
+
+// GetStringsValue retrieves the []string value for the specified
+// value name associated with an open key k. It also returns the value's type.
+// If value does not exist, GetStringsValue returns ErrNotExist.
+// If value is not MULTI_SZ, it will return the correct value
+// type and ErrUnexpectedType.
+func (k Key) GetStringsValue(name string) (val []string, valtype uint32, err error) {
+	data, typ, err2 := k.getValue(name, make([]byte, 64))
+	if err2 != nil {
+		return nil, typ, err2
+	}
+	if typ != MULTI_SZ {
+		return nil, typ, ErrUnexpectedType
+	}
+	if len(data) == 0 {
+		return nil, typ, nil
+	}
+	p := (*[1 << 24]uint16)(unsafe.Pointer(&data[0]))[:len(data)/2]
+	if len(p) == 0 {
+		return nil, typ, nil
+	}
+	if p[len(p)-1] == 0 {
+		p = p[:len(p)-1] // remove terminating null
+	}
+	val = make([]string, 0, 5)
+	from := 0
+	for i, c := range p {
+		if c == 0 {
+			val = append(val, string(utf16.Decode(p[from:i])))
+			from = i + 1
+		}
+	}
+	return val, typ, nil
+}
+
+// GetIntegerValue retrieves the integer value for the specified
+// value name associated with an open key k. It also returns the value's type.
+// If value does not exist, GetIntegerValue returns ErrNotExist.
+// If value is not DWORD or QWORD, it will return the correct value
+// type and ErrUnexpectedType.
+func (k Key) GetIntegerValue(name string) (val uint64, valtype uint32, err error) {
+	data, typ, err2 := k.getValue(name, make([]byte, 8))
+	if err2 != nil {
+		return 0, typ, err2
+	}
+	switch typ {
+	case DWORD:
+		if len(data) != 4 {
+			return 0, typ, errors.New("DWORD value is not 4 bytes long")
+		}
+		return uint64(*(*uint32)(unsafe.Pointer(&data[0]))), DWORD, nil
+	case QWORD:
+		if len(data) != 8 {
+			return 0, typ, errors.New("QWORD value is not 8 bytes long")
+		}
+		return uint64(*(*uint64)(unsafe.Pointer(&data[0]))), QWORD, nil
+	default:
+		return 0, typ, ErrUnexpectedType
+	}
+}
+
+// GetBinaryValue retrieves the binary value for the specified
+// value name associated with an open key k. It also returns the value's type.
+// If value does not exist, GetBinaryValue returns ErrNotExist.
+// If value is not BINARY, it will return the correct value
+// type and ErrUnexpectedType.
+func (k Key) GetBinaryValue(name string) (val []byte, valtype uint32, err error) {
+	data, typ, err2 := k.getValue(name, make([]byte, 64))
+	if err2 != nil {
+		return nil, typ, err2
+	}
+	if typ != BINARY {
+		return nil, typ, ErrUnexpectedType
+	}
+	return data, typ, nil
+}
+
+func (k Key) setValue(name string, valtype uint32, data []byte) error {
+	p, err := syscall.UTF16PtrFromString(name)
+	if err != nil {
+		return err
+	}
+	if len(data) == 0 {
+		return regSetValueEx(syscall.Handle(k), p, 0, valtype, nil, 0)
+	}
+	return regSetValueEx(syscall.Handle(k), p, 0, valtype, &data[0], uint32(len(data)))
+}
+
+// SetDWordValue sets the data and type of a name value
+// under key k to value and DWORD.
+func (k Key) SetDWordValue(name string, value uint32) error {
+	return k.setValue(name, DWORD, (*[4]byte)(unsafe.Pointer(&value))[:])
+}
+
+// SetQWordValue sets the data and type of a name value
+// under key k to value and QWORD.
+func (k Key) SetQWordValue(name string, value uint64) error {
+	return k.setValue(name, QWORD, (*[8]byte)(unsafe.Pointer(&value))[:])
+}
+
+func (k Key) setStringValue(name string, valtype uint32, value string) error {
+	v, err := syscall.UTF16FromString(value)
+	if err != nil {
+		return err
+	}
+	buf := (*[1 << 10]byte)(unsafe.Pointer(&v[0]))[:len(v)*2]
+	return k.setValue(name, valtype, buf)
+}
+
+// SetStringValue sets the data and type of a name value
+// under key k to value and SZ. The value must not contain a zero byte.
+func (k Key) SetStringValue(name, value string) error {
+	return k.setStringValue(name, SZ, value)
+}
+
+// SetExpandStringValue sets the data and type of a name value
+// under key k to value and EXPAND_SZ. The value must not contain a zero byte.
+func (k Key) SetExpandStringValue(name, value string) error {
+	return k.setStringValue(name, EXPAND_SZ, value)
+}
+
+// SetStringsValue sets the data and type of a name value
+// under key k to value and MULTI_SZ. The value strings
+// must not contain a zero byte.
+func (k Key) SetStringsValue(name string, value []string) error {
+	ss := ""
+	for _, s := range value {
+		for i := 0; i < len(s); i++ {
+			if s[i] == 0 {
+				return errors.New("string cannot have 0 inside")
+			}
+		}
+		ss += s + "\x00"
+	}
+	v := utf16.Encode([]rune(ss + "\x00"))
+	buf := (*[1 << 10]byte)(unsafe.Pointer(&v[0]))[:len(v)*2]
+	return k.setValue(name, MULTI_SZ, buf)
+}
+
+// SetBinaryValue sets the data and type of a name value
+// under key k to value and BINARY.
+func (k Key) SetBinaryValue(name string, value []byte) error {
+	return k.setValue(name, BINARY, value)
+}
+
+// DeleteValue removes a named value from the key k.
+func (k Key) DeleteValue(name string) error {
+	return regDeleteValue(syscall.Handle(k), syscall.StringToUTF16Ptr(name))
+}
+
+// ReadValueNames returns the value names of key k.
+// The parameter n controls the number of returned names,
+// analogous to the way os.File.Readdirnames works.
+func (k Key) ReadValueNames(n int) ([]string, error) {
+	ki, err := k.Stat()
+	if err != nil {
+		return nil, err
+	}
+	names := make([]string, 0, ki.ValueCount)
+	buf := make([]uint16, ki.MaxValueNameLen+1) // extra room for terminating null character
+loopItems:
+	for i := uint32(0); ; i++ {
+		if n > 0 {
+			if len(names) == n {
+				return names, nil
+			}
+		}
+		l := uint32(len(buf))
+		for {
+			err := regEnumValue(syscall.Handle(k), i, &buf[0], &l, nil, nil, nil, nil)
+			if err == nil {
+				break
+			}
+			if err == syscall.ERROR_MORE_DATA {
+				// Double buffer size and try again.
+				l = uint32(2 * len(buf))
+				buf = make([]uint16, l)
+				continue
+			}
+			if err == _ERROR_NO_MORE_ITEMS {
+				break loopItems
+			}
+			return names, err
+		}
+		names = append(names, syscall.UTF16ToString(buf[:l]))
+	}
+	if n > len(names) {
+		return names, io.EOF
+	}
+	return names, nil
+}
diff --git a/src/internal/syscall/windows/registry/zsyscall_windows.go b/src/internal/syscall/windows/registry/zsyscall_windows.go
new file mode 100644
index 0000000..2b3de63
--- /dev/null
+++ b/src/internal/syscall/windows/registry/zsyscall_windows.go
@@ -0,0 +1,73 @@
+// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
+
+package registry
+
+import "unsafe"
+import "syscall"
+
+var _ unsafe.Pointer
+
+var (
+	modadvapi32 = syscall.NewLazyDLL("advapi32.dll")
+	modkernel32 = syscall.NewLazyDLL("kernel32.dll")
+
+	procRegCreateKeyExW           = modadvapi32.NewProc("RegCreateKeyExW")
+	procRegDeleteKeyW             = modadvapi32.NewProc("RegDeleteKeyW")
+	procRegSetValueExW            = modadvapi32.NewProc("RegSetValueExW")
+	procRegEnumValueW             = modadvapi32.NewProc("RegEnumValueW")
+	procRegDeleteValueW           = modadvapi32.NewProc("RegDeleteValueW")
+	procExpandEnvironmentStringsW = modkernel32.NewProc("ExpandEnvironmentStringsW")
+)
+
+func regCreateKeyEx(key syscall.Handle, subkey *uint16, reserved uint32, class *uint16, options uint32, desired uint32, sa *syscall.SecurityAttributes, result *syscall.Handle, disposition *uint32) (regerrno error) {
+	r0, _, _ := syscall.Syscall9(procRegCreateKeyExW.Addr(), 9, uintptr(key), uintptr(unsafe.Pointer(subkey)), uintptr(reserved), uintptr(unsafe.Pointer(class)), uintptr(options), uintptr(desired), uintptr(unsafe.Pointer(sa)), uintptr(unsafe.Pointer(result)), uintptr(unsafe.Pointer(disposition)))
+	if r0 != 0 {
+		regerrno = syscall.Errno(r0)
+	}
+	return
+}
+
+func regDeleteKey(key syscall.Handle, subkey *uint16) (regerrno error) {
+	r0, _, _ := syscall.Syscall(procRegDeleteKeyW.Addr(), 2, uintptr(key), uintptr(unsafe.Pointer(subkey)), 0)
+	if r0 != 0 {
+		regerrno = syscall.Errno(r0)
+	}
+	return
+}
+
+func regSetValueEx(key syscall.Handle, valueName *uint16, reserved uint32, vtype uint32, buf *byte, bufsize uint32) (regerrno error) {
+	r0, _, _ := syscall.Syscall6(procRegSetValueExW.Addr(), 6, uintptr(key), uintptr(unsafe.Pointer(valueName)), uintptr(reserved), uintptr(vtype), uintptr(unsafe.Pointer(buf)), uintptr(bufsize))
+	if r0 != 0 {
+		regerrno = syscall.Errno(r0)
+	}
+	return
+}
+
+func regEnumValue(key syscall.Handle, index uint32, name *uint16, nameLen *uint32, reserved *uint32, valtype *uint32, buf *byte, buflen *uint32) (regerrno error) {
+	r0, _, _ := syscall.Syscall9(procRegEnumValueW.Addr(), 8, uintptr(key), uintptr(index), uintptr(unsafe.Pointer(name)), uintptr(unsafe.Pointer(nameLen)), uintptr(unsafe.Pointer(reserved)), uintptr(unsafe.Pointer(valtype)), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(buflen)), 0)
+	if r0 != 0 {
+		regerrno = syscall.Errno(r0)
+	}
+	return
+}
+
+func regDeleteValue(key syscall.Handle, name *uint16) (regerrno error) {
+	r0, _, _ := syscall.Syscall(procRegDeleteValueW.Addr(), 2, uintptr(key), uintptr(unsafe.Pointer(name)), 0)
+	if r0 != 0 {
+		regerrno = syscall.Errno(r0)
+	}
+	return
+}
+
+func expandEnvironmentStrings(src *uint16, dst *uint16, size uint32) (n uint32, err error) {
+	r0, _, e1 := syscall.Syscall(procExpandEnvironmentStringsW.Addr(), 3, uintptr(unsafe.Pointer(src)), uintptr(unsafe.Pointer(dst)), uintptr(size))
+	n = uint32(r0)
+	if n == 0 {
+		if e1 != 0 {
+			err = error(e1)
+		} else {
+			err = syscall.EINVAL
+		}
+	}
+	return
+}
diff --git a/src/internal/syscall/windows/syscall_windows.go b/src/internal/syscall/windows/syscall_windows.go
new file mode 100644
index 0000000..dc8a916
--- /dev/null
+++ b/src/internal/syscall/windows/syscall_windows.go
@@ -0,0 +1,130 @@
+// 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 windows
+
+import "syscall"
+
+//go:generate go run ../../../syscall/mksyscall_windows.go -output zsyscall_windows.go syscall_windows.go
+
+const GAA_FLAG_INCLUDE_PREFIX = 0x00000010
+
+const IF_TYPE_SOFTWARE_LOOPBACK = 24
+
+type SocketAddress struct {
+	Sockaddr       *syscall.RawSockaddrAny
+	SockaddrLength int32
+}
+
+type IpAdapterUnicastAddress struct {
+	Length             uint32
+	Flags              uint32
+	Next               *IpAdapterUnicastAddress
+	Address            SocketAddress
+	PrefixOrigin       int32
+	SuffixOrigin       int32
+	DadState           int32
+	ValidLifetime      uint32
+	PreferredLifetime  uint32
+	LeaseLifetime      uint32
+	OnLinkPrefixLength uint8
+}
+
+type IpAdapterAnycastAddress struct {
+	Length  uint32
+	Flags   uint32
+	Next    *IpAdapterAnycastAddress
+	Address SocketAddress
+}
+
+type IpAdapterMulticastAddress struct {
+	Length  uint32
+	Flags   uint32
+	Next    *IpAdapterMulticastAddress
+	Address SocketAddress
+}
+
+type IpAdapterDnsServerAdapter struct {
+	Length   uint32
+	Reserved uint32
+	Next     *IpAdapterDnsServerAdapter
+	Address  SocketAddress
+}
+
+type IpAdapterPrefix struct {
+	Length       uint32
+	Flags        uint32
+	Next         *IpAdapterPrefix
+	Address      SocketAddress
+	PrefixLength uint32
+}
+
+type IpAdapterAddresses struct {
+	Length                uint32
+	IfIndex               uint32
+	Next                  *IpAdapterAddresses
+	AdapterName           *byte
+	FirstUnicastAddress   *IpAdapterUnicastAddress
+	FirstAnycastAddress   *IpAdapterAnycastAddress
+	FirstMulticastAddress *IpAdapterMulticastAddress
+	FirstDnsServerAddress *IpAdapterDnsServerAdapter
+	DnsSuffix             *uint16
+	Description           *uint16
+	FriendlyName          *uint16
+	PhysicalAddress       [syscall.MAX_ADAPTER_ADDRESS_LENGTH]byte
+	PhysicalAddressLength uint32
+	Flags                 uint32
+	Mtu                   uint32
+	IfType                uint32
+	OperStatus            uint32
+	Ipv6IfIndex           uint32
+	ZoneIndices           [16]uint32
+	FirstPrefix           *IpAdapterPrefix
+	/* more fields might be present here. */
+}
+
+const (
+	IfOperStatusUp             = 1
+	IfOperStatusDown           = 2
+	IfOperStatusTesting        = 3
+	IfOperStatusUnknown        = 4
+	IfOperStatusDormant        = 5
+	IfOperStatusNotPresent     = 6
+	IfOperStatusLowerLayerDown = 7
+)
+
+//sys GetAdaptersAddresses(family uint32, flags uint32, reserved uintptr, adapterAddresses *IpAdapterAddresses, sizeOfPointer *uint32) (errcode error) = iphlpapi.GetAdaptersAddresses
+//sys	GetComputerNameEx(nameformat uint32, buf *uint16, n *uint32) (err error) = GetComputerNameExW
+//sys	MoveFileEx(from *uint16, to *uint16, flags uint32) (err error) = MoveFileExW
+
+const (
+	ComputerNameNetBIOS                   = 0
+	ComputerNameDnsHostname               = 1
+	ComputerNameDnsDomain                 = 2
+	ComputerNameDnsFullyQualified         = 3
+	ComputerNamePhysicalNetBIOS           = 4
+	ComputerNamePhysicalDnsHostname       = 5
+	ComputerNamePhysicalDnsDomain         = 6
+	ComputerNamePhysicalDnsFullyQualified = 7
+	ComputerNameMax                       = 8
+
+	MOVEFILE_REPLACE_EXISTING      = 0x1
+	MOVEFILE_COPY_ALLOWED          = 0x2
+	MOVEFILE_DELAY_UNTIL_REBOOT    = 0x4
+	MOVEFILE_WRITE_THROUGH         = 0x8
+	MOVEFILE_CREATE_HARDLINK       = 0x10
+	MOVEFILE_FAIL_IF_NOT_TRACKABLE = 0x20
+)
+
+func Rename(oldpath, newpath string) error {
+	from, err := syscall.UTF16PtrFromString(oldpath)
+	if err != nil {
+		return err
+	}
+	to, err := syscall.UTF16PtrFromString(newpath)
+	if err != nil {
+		return err
+	}
+	return MoveFileEx(from, to, MOVEFILE_REPLACE_EXISTING)
+}
diff --git a/src/internal/syscall/windows/zsyscall_windows.go b/src/internal/syscall/windows/zsyscall_windows.go
new file mode 100644
index 0000000..c6f607a
--- /dev/null
+++ b/src/internal/syscall/windows/zsyscall_windows.go
@@ -0,0 +1,49 @@
+// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
+
+package windows
+
+import "unsafe"
+import "syscall"
+
+var _ unsafe.Pointer
+
+var (
+	modiphlpapi = syscall.NewLazyDLL("iphlpapi.dll")
+	modkernel32 = syscall.NewLazyDLL("kernel32.dll")
+
+	procGetAdaptersAddresses = modiphlpapi.NewProc("GetAdaptersAddresses")
+	procGetComputerNameExW   = modkernel32.NewProc("GetComputerNameExW")
+	procMoveFileExW          = modkernel32.NewProc("MoveFileExW")
+)
+
+func GetAdaptersAddresses(family uint32, flags uint32, reserved uintptr, adapterAddresses *IpAdapterAddresses, sizeOfPointer *uint32) (errcode error) {
+	r0, _, _ := syscall.Syscall6(procGetAdaptersAddresses.Addr(), 5, uintptr(family), uintptr(flags), uintptr(reserved), uintptr(unsafe.Pointer(adapterAddresses)), uintptr(unsafe.Pointer(sizeOfPointer)), 0)
+	if r0 != 0 {
+		errcode = syscall.Errno(r0)
+	}
+	return
+}
+
+func GetComputerNameEx(nameformat uint32, buf *uint16, n *uint32) (err error) {
+	r1, _, e1 := syscall.Syscall(procGetComputerNameExW.Addr(), 3, uintptr(nameformat), uintptr(unsafe.Pointer(buf)), uintptr(unsafe.Pointer(n)))
+	if r1 == 0 {
+		if e1 != 0 {
+			err = error(e1)
+		} else {
+			err = syscall.EINVAL
+		}
+	}
+	return
+}
+
+func MoveFileEx(from *uint16, to *uint16, flags uint32) (err error) {
+	r1, _, e1 := syscall.Syscall(procMoveFileExW.Addr(), 3, uintptr(unsafe.Pointer(from)), uintptr(unsafe.Pointer(to)), uintptr(flags))
+	if r1 == 0 {
+		if e1 != 0 {
+			err = error(e1)
+		} else {
+			err = syscall.EINVAL
+		}
+	}
+	return
+}
diff --git a/src/internal/testenv/testenv.go b/src/internal/testenv/testenv.go
new file mode 100644
index 0000000..110af3d
--- /dev/null
+++ b/src/internal/testenv/testenv.go
@@ -0,0 +1,101 @@
+// 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 testenv provides information about what functionality
+// is available in different testing environments run by the Go team.
+//
+// It is an internal package because these details are specific
+// to the Go team's test setup (on build.golang.org) and not
+// fundamental to tests in general.
+package testenv
+
+import (
+	"os"
+	"runtime"
+	"strings"
+	"testing"
+)
+
+// Builder reports the name of the builder running this test
+// (for example, "linux-amd64" or "windows-386-gce").
+// If the test is not running on the build infrastructure,
+// Builder returns the empty string.
+func Builder() string {
+	return os.Getenv("GO_BUILDER_NAME")
+}
+
+// HasGoBuild reports whether the current system can build programs with ``go build''
+// and then run them with os.StartProcess or exec.Command.
+func HasGoBuild() bool {
+	switch runtime.GOOS {
+	case "android", "nacl":
+		return false
+	case "darwin":
+		if strings.HasPrefix(runtime.GOARCH, "arm") {
+			return false
+		}
+	}
+	return true
+}
+
+// MustHaveGoBuild checks that the current system can build programs with ``go build''
+// and then run them with os.StartProcess or exec.Command.
+// If not, MustHaveGoBuild calls t.Skip with an explanation.
+func MustHaveGoBuild(t *testing.T) {
+	if !HasGoBuild() {
+		t.Skipf("skipping test: 'go build' not available on %s/%s", runtime.GOOS, runtime.GOARCH)
+	}
+}
+
+// HasGoRun reports whether the current system can run programs with ``go run.''
+func HasGoRun() bool {
+	// For now, having go run and having go build are the same.
+	return HasGoBuild()
+}
+
+// MustHaveGoRun checks that the current system can run programs with ``go run.''
+// If not, MustHaveGoRun calls t.Skip with an explanation.
+func MustHaveGoRun(t *testing.T) {
+	if !HasGoRun() {
+		t.Skipf("skipping test: 'go run' not available on %s/%s", runtime.GOOS, runtime.GOARCH)
+	}
+}
+
+// HasExec reports whether the current system can start new processes
+// using os.StartProcess or (more commonly) exec.Command.
+func HasExec() bool {
+	switch runtime.GOOS {
+	case "nacl":
+		return false
+	case "darwin":
+		if strings.HasPrefix(runtime.GOARCH, "arm") {
+			return false
+		}
+	}
+	return true
+}
+
+// MustHaveExec checks that the current system can start new processes
+// using os.StartProcess or (more commonly) exec.Command.
+// If not, MustHaveExec calls t.Skip with an explanation.
+func MustHaveExec(t *testing.T) {
+	if !HasExec() {
+		t.Skipf("skipping test: cannot exec subprocess on %s/%s", runtime.GOOS, runtime.GOARCH)
+	}
+}
+
+// HasExternalNetwork reports whether the current system can use
+// external (non-localhost) networks.
+func HasExternalNetwork() bool {
+	return !testing.Short()
+}
+
+// MustHaveExternalNetwork checks that the current system can use
+// external (non-localhost) networks.
+// If not, MustHaveExternalNetwork calls t.Skip with an explanation.
+func MustHaveExternalNetwork(t *testing.T) {
+	if testing.Short() {
+		t.Skipf("skipping test: no external network in -short mode")
+	}
+}
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
new file mode 100644
index 0000000..1eb39dd
--- /dev/null
+++ b/src/internal/trace/parser.go
@@ -0,0 +1,786 @@
+// 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
+
+import (
+	"bufio"
+	"bytes"
+	"fmt"
+	"io"
+	"os"
+	"os/exec"
+	"sort"
+	"strconv"
+	"strings"
+)
+
+// Event describes one event in the trace.
+type Event struct {
+	Off   int       // offset in input file (for debugging and error reporting)
+	Type  byte      // one of Ev*
+	Seq   int64     // sequence number
+	Ts    int64     // timestamp in nanoseconds
+	P     int       // P on which the event happened (can be one of TimerP, NetpollP, SyscallP)
+	G     uint64    // G on which the event happened
+	StkID uint64    // unique stack ID
+	Stk   []*Frame  // stack trace (can be empty)
+	Args  [3]uint64 // event-type-specific arguments
+	// linked event (can be nil), depends on event type:
+	// for GCStart: the GCStop
+	// for GCScanStart: the GCScanDone
+	// for GCSweepStart: the GCSweepDone
+	// for GoCreate: first GoStart of the created goroutine
+	// for GoStart: the associated GoEnd, GoBlock or other blocking event
+	// for GoSched/GoPreempt: the next GoStart
+	// for GoBlock and other blocking events: the unblock event
+	// for GoUnblock: the associated GoStart
+	// for blocking GoSysCall: the associated GoSysExit
+	// for GoSysExit: the next GoStart
+	Link *Event
+}
+
+// Frame is a frame in stack traces.
+type Frame struct {
+	PC   uint64
+	Fn   string
+	File string
+	Line int
+}
+
+const (
+	// Special P identifiers:
+	FakeP    = 1000000 + iota
+	TimerP   // depicts timer unblocks
+	NetpollP // depicts network unblocks
+	SyscallP // depicts returns from syscalls
+)
+
+// Parse parses, post-processes and verifies the trace.
+func Parse(r io.Reader) ([]*Event, error) {
+	rawEvents, err := readTrace(r)
+	if err != nil {
+		return nil, err
+	}
+	events, err := parseEvents(rawEvents)
+	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
+	}
+	return events, nil
+}
+
+// rawEvent is a helper type used during parsing.
+type rawEvent struct {
+	off  int
+	typ  byte
+	args []uint64
+}
+
+// readTrace does wire-format parsing and verification.
+// It does not care about specific event types and argument meaning.
+func readTrace(r io.Reader) ([]rawEvent, error) {
+	// Read and validate trace header.
+	var buf [16]byte
+	off, err := r.Read(buf[:])
+	if off != 16 || err != nil {
+		return nil, fmt.Errorf("failed to read header: read %v, err %v", off, err)
+	}
+	if bytes.Compare(buf[:], []byte("go 1.5 trace\x00\x00\x00\x00")) != 0 {
+		return nil, fmt.Errorf("not a trace file")
+	}
+
+	// Read events.
+	var events []rawEvent
+	for {
+		// Read event type and number of arguments (1 byte).
+		off0 := off
+		n, err := r.Read(buf[:1])
+		if err == io.EOF {
+			break
+		}
+		if err != nil || n != 1 {
+			return nil, fmt.Errorf("failed to read trace at offset 0x%x: n=%v err=%v", off0, n, err)
+		}
+		off += n
+		typ := buf[0] << 2 >> 2
+		narg := buf[0] >> 6
+		ev := rawEvent{typ: typ, off: off0}
+		if narg < 3 {
+			for i := 0; i < int(narg)+2; i++ { // sequence number and time stamp are present but not counted in narg
+				var v uint64
+				v, off, err = readVal(r, off)
+				if err != nil {
+					return nil, err
+				}
+				ev.args = append(ev.args, v)
+			}
+		} else {
+			// If narg == 3, the first value is length of the event in bytes.
+			var v uint64
+			v, off, err = readVal(r, off)
+			if err != nil {
+				return nil, err
+			}
+			evLen := v
+			off1 := off
+			for evLen > uint64(off-off1) {
+				v, off, err = readVal(r, off)
+				if err != nil {
+					return nil, err
+				}
+				ev.args = append(ev.args, v)
+			}
+			if evLen != uint64(off-off1) {
+				return nil, fmt.Errorf("event has wrong length at offset 0x%x: want %v, got %v", off0, evLen, off-off1)
+			}
+		}
+		events = append(events, ev)
+	}
+	return events, nil
+}
+
+// Parse events transforms raw events into events.
+// It does analyze and verify per-event-type arguments.
+func parseEvents(rawEvents []rawEvent) (events []*Event, err error) {
+	var ticksPerSec, lastSeq, lastTs int64
+	var lastG, timerGoid uint64
+	var lastP int
+	lastGs := make(map[int]uint64) // last goroutine running on P
+	stacks := make(map[uint64][]*Frame)
+	for _, raw := range rawEvents {
+		if raw.typ == EvNone || raw.typ >= EvCount {
+			err = fmt.Errorf("unknown event type %v at offset 0x%x", raw.typ, raw.off)
+			return
+		}
+		desc := EventDescriptions[raw.typ]
+		if desc.Name == "" {
+			err = fmt.Errorf("missing description for event type %v", raw.typ)
+			return
+		}
+		if raw.typ != EvStack {
+			narg := len(desc.Args)
+			if desc.Stack {
+				narg++
+			}
+			if raw.typ != EvBatch && raw.typ != EvFrequency && raw.typ != EvTimerGoroutine {
+				narg++ // sequence number
+				narg++ // timestamp
+			}
+			if len(raw.args) != narg {
+				err = fmt.Errorf("%v has wrong number of arguments at offset 0x%x: want %v, got %v",
+					desc.Name, raw.off, narg, len(raw.args))
+				return
+			}
+		}
+		switch raw.typ {
+		case EvBatch:
+			lastGs[lastP] = lastG
+			lastP = int(raw.args[0])
+			lastG = lastGs[lastP]
+			lastSeq = int64(raw.args[1])
+			lastTs = int64(raw.args[2])
+		case EvFrequency:
+			ticksPerSec = int64(raw.args[0])
+			if ticksPerSec <= 0 {
+				// The most likely cause for this is tick skew on different CPUs.
+				// For example, solaris/amd64 seems to have wildly different
+				// ticks on different CPUs.
+				err = ErrTimeOrder
+				return
+			}
+		case EvTimerGoroutine:
+			timerGoid = raw.args[0]
+		case EvStack:
+			if len(raw.args) < 2 {
+				err = fmt.Errorf("EvStack has wrong number of arguments at offset 0x%x: want at least 2, got %v",
+					raw.off, len(raw.args))
+				return
+			}
+			size := raw.args[1]
+			if size > 1000 {
+				err = fmt.Errorf("EvStack has bad number of frames at offset 0x%x: %v",
+					raw.off, size)
+				return
+			}
+			if uint64(len(raw.args)) != size+2 {
+				err = fmt.Errorf("EvStack has wrong number of arguments at offset 0x%x: want %v, got %v",
+					raw.off, size+2, len(raw.args))
+				return
+			}
+			id := raw.args[0]
+			if id != 0 && size > 0 {
+				stk := make([]*Frame, size)
+				for i := 0; i < int(size); i++ {
+					stk[i] = &Frame{PC: raw.args[i+2]}
+				}
+				stacks[id] = stk
+			}
+		default:
+			e := &Event{Off: raw.off, Type: raw.typ, P: lastP, G: lastG}
+			e.Seq = lastSeq + int64(raw.args[0])
+			e.Ts = lastTs + int64(raw.args[1])
+			lastSeq = e.Seq
+			lastTs = e.Ts
+			for i := range desc.Args {
+				e.Args[i] = raw.args[i+2]
+			}
+			if desc.Stack {
+				e.StkID = raw.args[len(desc.Args)+2]
+			}
+			switch raw.typ {
+			case EvGoStart:
+				lastG = e.Args[0]
+				e.G = lastG
+			case EvGCStart, EvGCDone, EvGCScanStart, EvGCScanDone:
+				e.G = 0
+			case EvGoEnd, EvGoStop, EvGoSched, EvGoPreempt,
+				EvGoSleep, EvGoBlock, EvGoBlockSend, EvGoBlockRecv,
+				EvGoBlockSelect, EvGoBlockSync, EvGoBlockCond, EvGoBlockNet,
+				EvGoSysBlock:
+				lastG = 0
+			case EvGoSysExit:
+				// EvGoSysExit emission is delayed until the thread has a P.
+				// Give it the real sequence number and time stamp.
+				e.Seq = int64(e.Args[1])
+				if e.Args[2] != 0 {
+					e.Ts = int64(e.Args[2])
+				}
+			}
+			events = append(events, e)
+		}
+	}
+	if len(events) == 0 {
+		err = fmt.Errorf("trace is empty")
+		return
+	}
+
+	// Attach stack traces.
+	for _, ev := range events {
+		if ev.StkID != 0 {
+			ev.Stk = stacks[ev.StkID]
+		}
+	}
+
+	// Sort by sequence number and translate cpu ticks to real time.
+	sort.Sort(eventList(events))
+	if ticksPerSec == 0 {
+		err = fmt.Errorf("no EvFrequency event")
+		return
+	}
+	minTs := events[0].Ts
+	for _, ev := range events {
+		ev.Ts = (ev.Ts - minTs) * 1e9 / ticksPerSec
+		// Move timers and syscalls to separate fake Ps.
+		if timerGoid != 0 && ev.G == timerGoid && ev.Type == EvGoUnblock {
+			ev.P = TimerP
+		}
+		if ev.Type == EvGoSysExit {
+			ev.P = SyscallP
+			ev.G = ev.Args[0]
+		}
+	}
+
+	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
+}
+
+// ErrTimeOrder is returned by Parse when the trace contains
+// time stamps that do not respect actual event ordering.
+var ErrTimeOrder = fmt.Errorf("time stamps out of order")
+
+// 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
+// blocked before an unblock event).
+func postProcessTrace(events []*Event) error {
+	const (
+		gDead = iota
+		gRunnable
+		gRunning
+		gWaiting
+	)
+	type gdesc struct {
+		state    int
+		ev       *Event
+		evStart  *Event
+		evCreate *Event
+	}
+	type pdesc struct {
+		running bool
+		g       uint64
+		evScan  *Event
+		evSweep *Event
+	}
+
+	gs := make(map[uint64]gdesc)
+	ps := make(map[int]pdesc)
+	gs[0] = gdesc{state: gRunning}
+	var evGC *Event
+
+	checkRunning := func(p pdesc, g gdesc, ev *Event, allowG0 bool) error {
+		name := EventDescriptions[ev.Type].Name
+		if g.state != gRunning {
+			return fmt.Errorf("g %v is not running while %v (offset %v, time %v)", ev.G, name, ev.Off, ev.Ts)
+		}
+		if p.g != ev.G {
+			return fmt.Errorf("p %v is not running g %v while %v (offset %v, time %v)", ev.P, ev.G, name, ev.Off, ev.Ts)
+		}
+		if !allowG0 && ev.G == 0 {
+			return fmt.Errorf("g 0 did %v (offset %v, time %v)", EventDescriptions[ev.Type].Name, ev.Off, ev.Ts)
+		}
+		return nil
+	}
+
+	for _, ev := range events {
+		g := gs[ev.G]
+		p := ps[ev.P]
+
+		switch ev.Type {
+		case EvProcStart:
+			if p.running {
+				return fmt.Errorf("p %v is running before start (offset %v, time %v)", ev.P, ev.Off, ev.Ts)
+			}
+			p.running = true
+		case EvProcStop:
+			if !p.running {
+				return fmt.Errorf("p %v is not running before stop (offset %v, time %v)", ev.P, ev.Off, ev.Ts)
+			}
+			if p.g != 0 {
+				return fmt.Errorf("p %v is running a goroutine %v during stop (offset %v, time %v)", ev.P, p.g, ev.Off, ev.Ts)
+			}
+			p.running = false
+		case EvGCStart:
+			if evGC != nil {
+				return fmt.Errorf("previous GC is not ended before a new one (offset %v, time %v)", ev.Off, ev.Ts)
+			}
+			evGC = ev
+		case EvGCDone:
+			if evGC == nil {
+				return fmt.Errorf("bogus GC end (offset %v, time %v)", ev.Off, ev.Ts)
+			}
+			evGC.Link = ev
+			evGC = nil
+		case EvGCScanStart:
+			if p.evScan != nil {
+				return fmt.Errorf("previous scanning is not ended before a new one (offset %v, time %v)", ev.Off, ev.Ts)
+			}
+			p.evScan = ev
+		case EvGCScanDone:
+			if p.evScan == nil {
+				return fmt.Errorf("bogus scanning end (offset %v, time %v)", ev.Off, ev.Ts)
+			}
+			p.evScan.Link = ev
+			p.evScan = nil
+		case EvGCSweepStart:
+			if p.evSweep != nil {
+				return fmt.Errorf("previous sweeping is not ended before a new one (offset %v, time %v)", ev.Off, ev.Ts)
+			}
+			p.evSweep = ev
+		case EvGCSweepDone:
+			if p.evSweep == nil {
+				return fmt.Errorf("bogus sweeping end (offset %v, time %v)", ev.Off, ev.Ts)
+			}
+			p.evSweep.Link = ev
+			p.evSweep = nil
+		case EvGoWaiting:
+			g1 := gs[ev.Args[0]]
+			if g1.state != gRunnable {
+				return fmt.Errorf("g %v is not runnable before EvGoWaiting (offset %v, time %v)", ev.Args[0], ev.Off, ev.Ts)
+			}
+			g1.state = gWaiting
+			gs[ev.Args[0]] = g1
+		case EvGoInSyscall:
+			g1 := gs[ev.Args[0]]
+			if g1.state != gRunnable {
+				return fmt.Errorf("g %v is not runnable before EvGoInSyscall (offset %v, time %v)", ev.Args[0], ev.Off, ev.Ts)
+			}
+			g1.state = gWaiting
+			gs[ev.Args[0]] = g1
+		case EvGoCreate:
+			if err := checkRunning(p, g, ev, true); err != nil {
+				return err
+			}
+			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, 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)
+			}
+			if p.g != 0 {
+				return fmt.Errorf("p %v is already running g %v while start g %v (offset %v, time %v)", ev.P, p.g, ev.G, ev.Off, ev.Ts)
+			}
+			g.state = gRunning
+			g.evStart = ev
+			p.g = ev.G
+			if g.evCreate != nil {
+				// +1 because symbolizer expects return pc.
+				ev.Stk = []*Frame{&Frame{PC: g.evCreate.Args[1] + 1}}
+				g.evCreate = nil
+			}
+
+			if g.ev != nil {
+				g.ev.Link = ev
+				g.ev = nil
+			}
+		case EvGoEnd, EvGoStop:
+			if err := checkRunning(p, g, ev, false); err != nil {
+				return err
+			}
+			g.evStart.Link = ev
+			g.evStart = nil
+			g.state = gDead
+			p.g = 0
+		case EvGoSched, EvGoPreempt:
+			if err := checkRunning(p, g, ev, false); err != nil {
+				return err
+			}
+			g.state = gRunnable
+			g.evStart.Link = ev
+			g.evStart = nil
+			p.g = 0
+			g.ev = ev
+		case EvGoUnblock:
+			if g.state != gRunning {
+				return fmt.Errorf("g %v is not running while unpark (offset %v, time %v)", ev.G, ev.Off, ev.Ts)
+			}
+			if ev.P != TimerP && p.g != ev.G {
+				return fmt.Errorf("p %v is not running g %v while unpark (offset %v, time %v)", ev.P, ev.G, ev.Off, ev.Ts)
+			}
+			g1 := gs[ev.Args[0]]
+			if g1.state != gWaiting {
+				return fmt.Errorf("g %v is not waiting before unpark (offset %v, time %v)", ev.Args[0], ev.Off, ev.Ts)
+			}
+			if g1.ev != nil && g1.ev.Type == EvGoBlockNet && ev.P != TimerP {
+				ev.P = NetpollP
+			}
+			if g1.ev != nil {
+				g1.ev.Link = ev
+			}
+			g1.state = gRunnable
+			g1.ev = ev
+			gs[ev.Args[0]] = g1
+		case EvGoSysCall:
+			if err := checkRunning(p, g, ev, false); err != nil {
+				return err
+			}
+			g.ev = ev
+		case EvGoSysBlock:
+			if err := checkRunning(p, g, ev, false); err != nil {
+				return err
+			}
+			g.state = gWaiting
+			g.evStart.Link = ev
+			g.evStart = nil
+			p.g = 0
+		case EvGoSysExit:
+			if g.state != gWaiting {
+				return fmt.Errorf("g %v is not waiting during syscall exit (offset %v, time %v)", ev.G, ev.Off, ev.Ts)
+			}
+			if g.ev != nil && g.ev.Type == EvGoSysCall {
+				g.ev.Link = ev
+			}
+			g.state = gRunnable
+			g.ev = ev
+		case EvGoSleep, EvGoBlock, EvGoBlockSend, EvGoBlockRecv,
+			EvGoBlockSelect, EvGoBlockSync, EvGoBlockCond, EvGoBlockNet:
+			if err := checkRunning(p, g, ev, false); err != nil {
+				return err
+			}
+			g.state = gWaiting
+			g.ev = ev
+			g.evStart.Link = ev
+			g.evStart = nil
+			p.g = 0
+		}
+
+		gs[ev.G] = g
+		ps[ev.P] = p
+	}
+
+	// TODO(dvyukov): restore stacks for EvGoStart events.
+	// TODO(dvyukov): test that all EvGoStart events has non-nil Link.
+
+	// Last, after all the other consistency checks,
+	// make sure time stamps respect sequence numbers.
+	// The tests will skip (not fail) the test case if they see this error,
+	// so check everything else that could possibly be wrong first.
+	lastTs := int64(0)
+	for _, ev := range events {
+		if ev.Ts < lastTs {
+			return ErrTimeOrder
+		}
+		lastTs = ev.Ts
+	}
+
+	return nil
+}
+
+// symbolizeTrace attaches func/file/line info to stack traces.
+func Symbolize(events []*Event, bin string) error {
+	// First, collect and dedup all pcs.
+	pcs := make(map[uint64]*Frame)
+	for _, ev := range events {
+		for _, f := range ev.Stk {
+			pcs[f.PC] = nil
+		}
+	}
+
+	// Start addr2line.
+	cmd := exec.Command("go", "tool", "addr2line", bin)
+	in, err := cmd.StdinPipe()
+	if err != nil {
+		return fmt.Errorf("failed to pipe addr2line stdin: %v", err)
+	}
+	cmd.Stderr = os.Stderr
+	out, err := cmd.StdoutPipe()
+	if err != nil {
+		return fmt.Errorf("failed to pipe addr2line stdout: %v", err)
+	}
+	err = cmd.Start()
+	if err != nil {
+		return fmt.Errorf("failed to start addr2line: %v", err)
+	}
+	outb := bufio.NewReader(out)
+
+	// Write all pcs to addr2line.
+	// Need to copy pcs to an array, because map iteration order is non-deterministic.
+	var pcArray []uint64
+	for pc := range pcs {
+		pcArray = append(pcArray, pc)
+		_, err := fmt.Fprintf(in, "0x%x\n", pc-1)
+		if err != nil {
+			return fmt.Errorf("failed to write to addr2line: %v", err)
+		}
+	}
+	in.Close()
+
+	// Read in answers.
+	for _, pc := range pcArray {
+		fn, err := outb.ReadString('\n')
+		if err != nil {
+			return fmt.Errorf("failed to read from addr2line: %v", err)
+		}
+		file, err := outb.ReadString('\n')
+		if err != nil {
+			return fmt.Errorf("failed to read from addr2line: %v", err)
+		}
+		f := &Frame{PC: pc}
+		f.Fn = fn[:len(fn)-1]
+		f.File = file[:len(file)-1]
+		if colon := strings.LastIndex(f.File, ":"); colon != -1 {
+			ln, err := strconv.Atoi(f.File[colon+1:])
+			if err == nil {
+				f.File = f.File[:colon]
+				f.Line = ln
+			}
+		}
+		pcs[pc] = f
+	}
+	cmd.Wait()
+
+	// Replace frames in events array.
+	for _, ev := range events {
+		for i, f := range ev.Stk {
+			ev.Stk[i] = pcs[f.PC]
+		}
+	}
+
+	return nil
+}
+
+// readVal reads unsigned base-128 value from r.
+func readVal(r io.Reader, off0 int) (v uint64, off int, err error) {
+	off = off0
+	for i := 0; i < 10; i++ {
+		var buf [1]byte
+		var n int
+		n, err = r.Read(buf[:])
+		if err != nil || n != 1 {
+			return 0, 0, fmt.Errorf("failed to read trace at offset %d: read %v, error %v", off0, n, err)
+		}
+		off++
+		v |= uint64(buf[0]&0x7f) << (uint(i) * 7)
+		if buf[0]&0x80 == 0 {
+			return
+		}
+	}
+	return 0, 0, fmt.Errorf("bad value at offset 0x%x", off0)
+}
+
+type eventList []*Event
+
+func (l eventList) Len() int {
+	return len(l)
+}
+
+func (l eventList) Less(i, j int) bool {
+	return l[i].Seq < l[j].Seq
+}
+
+func (l eventList) Swap(i, j int) {
+	l[i], l[j] = l[j], l[i]
+}
+
+// Print dumps events to stdout. For debugging.
+func Print(events []*Event) {
+	for _, ev := range events {
+		desc := EventDescriptions[ev.Type]
+		fmt.Printf("%v %v p=%v g=%v off=%v", ev.Ts, desc.Name, ev.P, ev.G, ev.Off)
+		for i, a := range desc.Args {
+			fmt.Printf(" %v=%v", a, ev.Args[i])
+		}
+		fmt.Printf("\n")
+	}
+}
+
+// Event types in the trace.
+// Verbatim copy from src/runtime/trace.go.
+const (
+	EvNone           = 0  // unused
+	EvBatch          = 1  // start of per-P batch of events [pid, timestamp]
+	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, thread id]
+	EvProcStop       = 6  // stop of P [timestamp]
+	EvGCStart        = 7  // GC start [timestamp, stack id]
+	EvGCDone         = 8  // GC done [timestamp]
+	EvGCScanStart    = 9  // GC scan start [timestamp]
+	EvGCScanDone     = 10 // GC scan done [timestamp]
+	EvGCSweepStart   = 11 // GC sweep start [timestamp, stack id]
+	EvGCSweepDone    = 12 // GC sweep done [timestamp]
+	EvGoCreate       = 13 // goroutine creation [timestamp, new goroutine id, start PC, stack id]
+	EvGoStart        = 14 // goroutine starts running [timestamp, goroutine id]
+	EvGoEnd          = 15 // goroutine ends [timestamp]
+	EvGoStop         = 16 // goroutine stops (like in select{}) [timestamp, stack]
+	EvGoSched        = 17 // goroutine calls Gosched [timestamp, stack]
+	EvGoPreempt      = 18 // goroutine is preempted [timestamp, stack]
+	EvGoSleep        = 19 // goroutine calls Sleep [timestamp, stack]
+	EvGoBlock        = 20 // goroutine blocks [timestamp, stack]
+	EvGoUnblock      = 21 // goroutine is unblocked [timestamp, goroutine id, stack]
+	EvGoBlockSend    = 22 // goroutine blocks on chan send [timestamp, stack]
+	EvGoBlockRecv    = 23 // goroutine blocks on chan recv [timestamp, stack]
+	EvGoBlockSelect  = 24 // goroutine blocks on select [timestamp, stack]
+	EvGoBlockSync    = 25 // goroutine blocks on Mutex/RWMutex [timestamp, stack]
+	EvGoBlockCond    = 26 // goroutine blocks on Cond [timestamp, stack]
+	EvGoBlockNet     = 27 // goroutine blocks on network [timestamp, stack]
+	EvGoSysCall      = 28 // syscall enter [timestamp, stack]
+	EvGoSysExit      = 29 // syscall exit [timestamp, goroutine id, real timestamp]
+	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]
+	EvFutileWakeup   = 36 // denotes that the previous wakeup of this goroutine was futile [timestamp]
+	EvCount          = 37
+)
+
+var EventDescriptions = [EvCount]struct {
+	Name  string
+	Stack bool
+	Args  []string
+}{
+	EvNone:           {"None", false, []string{}},
+	EvBatch:          {"Batch", false, []string{"p", "seq", "ticks"}},
+	EvFrequency:      {"Frequency", false, []string{"freq", "unused"}},
+	EvStack:          {"Stack", false, []string{"id", "siz"}},
+	EvGomaxprocs:     {"Gomaxprocs", true, []string{"procs"}},
+	EvProcStart:      {"ProcStart", false, []string{"thread"}},
+	EvProcStop:       {"ProcStop", false, []string{}},
+	EvGCStart:        {"GCStart", true, []string{}},
+	EvGCDone:         {"GCDone", false, []string{}},
+	EvGCScanStart:    {"GCScanStart", false, []string{}},
+	EvGCScanDone:     {"GCScanDone", false, []string{}},
+	EvGCSweepStart:   {"GCSweepStart", true, []string{}},
+	EvGCSweepDone:    {"GCSweepDone", false, []string{}},
+	EvGoCreate:       {"GoCreate", true, []string{"g", "pc"}},
+	EvGoStart:        {"GoStart", false, []string{"g"}},
+	EvGoEnd:          {"GoEnd", false, []string{}},
+	EvGoStop:         {"GoStop", true, []string{}},
+	EvGoSched:        {"GoSched", true, []string{}},
+	EvGoPreempt:      {"GoPreempt", true, []string{}},
+	EvGoSleep:        {"GoSleep", true, []string{}},
+	EvGoBlock:        {"GoBlock", true, []string{}},
+	EvGoUnblock:      {"GoUnblock", true, []string{"g"}},
+	EvGoBlockSend:    {"GoBlockSend", true, []string{}},
+	EvGoBlockRecv:    {"GoBlockRecv", true, []string{}},
+	EvGoBlockSelect:  {"GoBlockSelect", true, []string{}},
+	EvGoBlockSync:    {"GoBlockSync", true, []string{}},
+	EvGoBlockCond:    {"GoBlockCond", true, []string{}},
+	EvGoBlockNet:     {"GoBlockNet", true, []string{}},
+	EvGoSysCall:      {"GoSysCall", true, []string{}},
+	EvGoSysExit:      {"GoSysExit", false, []string{"g", "seq", "ts"}},
+	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", "unused"}},
+	EvFutileWakeup:   {"FutileWakeup", false, []string{}},
+}
diff --git a/src/internal/trace/parser_test.go b/src/internal/trace/parser_test.go
new file mode 100644
index 0000000..0eeb3e6
--- /dev/null
+++ b/src/internal/trace/parser_test.go
@@ -0,0 +1,30 @@
+// 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 trace
+
+import (
+	"strings"
+	"testing"
+)
+
+func TestCorruptedInputs(t *testing.T) {
+	// These inputs crashed parser previously.
+	tests := []string{
+		"gotrace\x00\x020",
+		"gotrace\x00Q00\x020",
+		"gotrace\x00T00\x020",
+		"gotrace\x00\xc3\x0200",
+		"go 1.5 trace\x00\x00\x00\x00\x020",
+		"go 1.5 trace\x00\x00\x00\x00Q00\x020",
+		"go 1.5 trace\x00\x00\x00\x00T00\x020",
+		"go 1.5 trace\x00\x00\x00\x00\xc3\x0200",
+	}
+	for _, data := range tests {
+		events, err := Parse(strings.NewReader(data))
+		if err == nil || events != nil {
+			t.Fatalf("no error on input: %q\n", t)
+		}
+	}
+}
diff --git a/src/io/io.go b/src/io/io.go
index 7507a84..8851eaf 100644
--- a/src/io/io.go
+++ b/src/io/io.go
@@ -54,7 +54,7 @@ var ErrNoProgress = errors.New("multiple Read calls return no data or error")
 // An instance of this general case is that a Reader returning
 // a non-zero number of bytes at the end of the input stream may
 // return either err == EOF or err == nil.  The next Read should
-// return 0, EOF regardless.
+// return 0, EOF.
 //
 // Callers should always process the n > 0 bytes returned before
 // considering the error err.  Doing so correctly handles I/O errors
@@ -273,8 +273,8 @@ type stringWriter interface {
 	WriteString(s string) (n int, err error)
 }
 
-// WriteString writes the contents of the string s to w, which accepts an array of bytes.
-// If w already implements a WriteString method, it is invoked directly.
+// WriteString writes the contents of the string s to w, which accepts a slice of bytes.
+// If w implements a WriteString method, it is invoked directly.
 func WriteString(w Writer, s string) (n int, err error) {
 	if sw, ok := w.(stringWriter); ok {
 		return sw.WriteString(s)
@@ -348,6 +348,23 @@ func CopyN(dst Writer, src Reader, n int64) (written int64, err error) {
 // Otherwise, if dst implements the ReaderFrom interface,
 // the copy is implemented by calling dst.ReadFrom(src).
 func Copy(dst Writer, src Reader) (written int64, err error) {
+	return copyBuffer(dst, src, nil)
+}
+
+// CopyBuffer is identical to Copy except that it stages through the
+// provided buffer (if one is required) rather than allocating a
+// temporary one. If buf is nil, one is allocated; otherwise if it has
+// zero length, CopyBuffer panics.
+func CopyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error) {
+	if buf != nil && len(buf) == 0 {
+		panic("empty buffer in io.CopyBuffer")
+	}
+	return copyBuffer(dst, src, buf)
+}
+
+// copyBuffer is the actual implementation of Copy and CopyBuffer.
+// if buf is nil, one is allocated.
+func copyBuffer(dst Writer, src Reader, buf []byte) (written int64, err error) {
 	// If the reader has a WriteTo method, use it to do the copy.
 	// Avoids an allocation and a copy.
 	if wt, ok := src.(WriterTo); ok {
@@ -357,7 +374,9 @@ func Copy(dst Writer, src Reader) (written int64, err error) {
 	if rt, ok := dst.(ReaderFrom); ok {
 		return rt.ReadFrom(src)
 	}
-	buf := make([]byte, 32*1024)
+	if buf == nil {
+		buf = make([]byte, 32*1024)
+	}
 	for {
 		nr, er := src.Read(buf)
 		if nr > 0 {
diff --git a/src/io/io_test.go b/src/io/io_test.go
index 57db1fb..e892574 100644
--- a/src/io/io_test.go
+++ b/src/io/io_test.go
@@ -20,7 +20,7 @@ type Buffer struct {
 	WriterTo   // conflicts with and hides bytes.Buffer's WriterTo.
 }
 
-// Simple tests, primarily to verify the ReadFrom and WriteTo callouts inside Copy and CopyN.
+// Simple tests, primarily to verify the ReadFrom and WriteTo callouts inside Copy, CopyBuffer and CopyN.
 
 func TestCopy(t *testing.T) {
 	rb := new(Buffer)
@@ -32,6 +32,26 @@ func TestCopy(t *testing.T) {
 	}
 }
 
+func TestCopyBuffer(t *testing.T) {
+	rb := new(Buffer)
+	wb := new(Buffer)
+	rb.WriteString("hello, world.")
+	CopyBuffer(wb, rb, make([]byte, 1)) // Tiny buffer to keep it honest.
+	if wb.String() != "hello, world." {
+		t.Errorf("CopyBuffer did not work properly")
+	}
+}
+
+func TestCopyBufferNil(t *testing.T) {
+	rb := new(Buffer)
+	wb := new(Buffer)
+	rb.WriteString("hello, world.")
+	CopyBuffer(wb, rb, nil) // Should allocate a buffer.
+	if wb.String() != "hello, world." {
+		t.Errorf("CopyBuffer did not work properly")
+	}
+}
+
 func TestCopyReadFrom(t *testing.T) {
 	rb := new(Buffer)
 	wb := new(bytes.Buffer) // implements ReadFrom.
@@ -78,6 +98,34 @@ func TestCopyPriority(t *testing.T) {
 	}
 }
 
+type zeroErrReader struct {
+	err error
+}
+
+func (r zeroErrReader) Read(p []byte) (int, error) {
+	return copy(p, []byte{0}), r.err
+}
+
+type errWriter struct {
+	err error
+}
+
+func (w errWriter) Write([]byte) (int, error) {
+	return 0, w.err
+}
+
+// In case a Read results in an error with non-zero bytes read, and
+// the subsequent Write also results in an error, the error from Write
+// is returned, as it is the one that prevented progressing further.
+func TestCopyReadErrWriteErr(t *testing.T) {
+	er, ew := errors.New("readError"), errors.New("writeError")
+	r, w := zeroErrReader{err: er}, errWriter{err: ew}
+	n, err := Copy(w, r)
+	if n != 0 || err != ew {
+		t.Errorf("Copy(zeroErrReader, errWriter) = %d, %v; want 0, writeError", n, err)
+	}
+}
+
 func TestCopyN(t *testing.T) {
 	rb := new(Buffer)
 	wb := new(Buffer)
diff --git a/src/io/ioutil/tempfile.go b/src/io/ioutil/tempfile.go
index 4a06e97..61d4a7a 100644
--- a/src/io/ioutil/tempfile.go
+++ b/src/io/ioutil/tempfile.go
@@ -55,7 +55,9 @@ func TempFile(dir, prefix string) (f *os.File, err error) {
 		f, err = os.OpenFile(name, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600)
 		if os.IsExist(err) {
 			if nconflict++; nconflict > 10 {
+				randmu.Lock()
 				rand = reseed()
+				randmu.Unlock()
 			}
 			continue
 		}
@@ -82,7 +84,9 @@ func TempDir(dir, prefix string) (name string, err error) {
 		err = os.Mkdir(try, 0700)
 		if os.IsExist(err) {
 			if nconflict++; nconflict > 10 {
+				randmu.Lock()
 				rand = reseed()
+				randmu.Unlock()
 			}
 			continue
 		}
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 @@ func (w *PipeWriter) Close() error {
 }
 
 // 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..5e09894
--- /dev/null
+++ b/src/iostest.bash
@@ -0,0 +1,69 @@
+#!/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" ] && [ "$GOARCH" != "arm64" ]; then
+	echo "iostest.bash requires GOARCH=arm or GOARCH=arm64, got GOARCH=$GOARCH" 1>&2
+	exit 1
+fi
+if [ "$GOARCH" == "arm" ]; then
+	export GOARM=7
+fi
+
+if [ "$1" == "-restart" ]; then
+	# 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
+fi
+
+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) ios-deploy 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
+
+if [ "$GOIOS_DEV_ID" == "" ]; then
+	echo "detecting iOS development identity"
+	eval $(GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH go run ../misc/ios/detect.go)
+fi
+
+# Run standard build and tests.
+./all.bash --no-clean
diff --git a/src/lib9/Makefile b/src/lib9/Makefile
deleted file mode 100644
index 62aba5d..0000000
--- a/src/lib9/Makefile
+++ /dev/null
@@ -1,5 +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.
-
-include ../Make.dist
diff --git a/src/lib9/_exits.c b/src/lib9/_exits.c
deleted file mode 100644
index af55181..0000000
--- a/src/lib9/_exits.c
+++ /dev/null
@@ -1,37 +0,0 @@
-// +build !plan9
-
-/*
-Plan 9 from User Space src/lib9/_exits.c
-http://code.swtch.com/plan9port/src/tip/src/lib9/_exits.c
-
-Copyright 2001-2007 Russ Cox.  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.
-*/
-
-#include <u.h>
-#include <libc.h>
-
-void
-_exits(char *s)
-{
-	if(s == 0 || *s == 0)
-		_exit(0);
-	_exit(exitcode(s));
-}
diff --git a/src/lib9/_p9dir.c b/src/lib9/_p9dir.c
deleted file mode 100644
index 6b5a04e..0000000
--- a/src/lib9/_p9dir.c
+++ /dev/null
@@ -1,184 +0,0 @@
-// +build !plan9
-
-/*
-Plan 9 from User Space src/lib9/_p9dir.c
-http://code.swtch.com/plan9port/src/tip/src/lib9/_p9dir.c
-
-Copyright 2001-2007 Russ Cox.  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.
-*/
-
-#include <u.h>
-#define NOPLAN9DEFINES
-#include <libc.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <dirent.h>
-
-/*
- * Caching the last group and passwd looked up is
- * a significant win (stupidly enough) on most systems.
- * It's not safe for threaded programs, but neither is using
- * getpwnam in the first place, so I'm not too worried.
- */
-int
-_p9dir(struct stat *lst, struct stat *st, char *name, Dir *d, char **str, char *estr)
-{
-	char *s;
-	char tmp[20];
-	int sz, fd;
-
-#ifdef _WIN32
-	USED(lst);
-#endif
-	fd = -1;
-	USED(fd);
-	sz = 0;
-	if(d)
-		memset(d, 0, sizeof *d);
-
-	/* name */
-	s = strrchr(name, '/');
-	if(s)
-		s++;
-	if(!s || !*s)
-		s = name;
-	if(*s == '/')
-		s++;
-	if(*s == 0)
-		s = "/";
-	if(d){
-		if(*str + strlen(s)+1 > estr)
-			d->name = "oops";
-		else{
-			strcpy(*str, s);
-			d->name = *str;
-			*str += strlen(*str)+1;
-		}
-	}
-	sz += (int)strlen(s)+1;
-
-	/* user */
-	snprint(tmp, sizeof tmp, "%d", (int)st->st_uid);
-	s = tmp;
-	sz += (int)strlen(s)+1;
-	if(d){
-		if(*str+strlen(s)+1 > estr)
-			d->uid = "oops";
-		else{
-			strcpy(*str, s);
-			d->uid = *str;
-			*str += strlen(*str)+1;
-		}
-	}
-
-	/* group */
-	snprint(tmp, sizeof tmp, "%d", (int)st->st_gid);
-	s = tmp;
-	sz += (int)strlen(s)+1;
-	if(d){
-		if(*str + strlen(s)+1 > estr)
-			d->gid = "oops";
-		else{
-			strcpy(*str, s);
-			d->gid = *str;
-			*str += strlen(*str)+1;
-		}
-	}
-
-	if(d){
-		d->type = 'M';
-
-		d->muid = "";
-		d->qid.path = ((uvlong)st->st_dev<<32) | st->st_ino;
-#ifdef _HAVESTGEN
-		d->qid.vers = st->st_gen;
-#endif
-		if(d->qid.vers == 0)
-			d->qid.vers = (ulong)(st->st_mtime + st->st_ctime);
-		d->mode = st->st_mode&0777;
-		d->atime = (ulong)st->st_atime;
-		d->mtime = (ulong)st->st_mtime;
-		d->length = st->st_size;
-
-		if(S_ISDIR(st->st_mode)){
-			d->length = 0;
-			d->mode |= DMDIR;
-			d->qid.type = QTDIR;
-		}
-#ifdef S_ISLNK
-		if(S_ISLNK(lst->st_mode))	/* yes, lst not st */
-			d->mode |= DMSYMLINK;
-#endif
-		if(S_ISFIFO(st->st_mode))
-			d->mode |= DMNAMEDPIPE;
-#ifdef S_ISSOCK
-		if(S_ISSOCK(st->st_mode))
-			d->mode |= DMSOCKET;
-#endif
-		if(S_ISBLK(st->st_mode)){
-			d->mode |= DMDEVICE;
-			d->qid.path = ('b'<<16)|st->st_rdev;
-		}
-		if(S_ISCHR(st->st_mode)){
-			d->mode |= DMDEVICE;
-			d->qid.path = ('c'<<16)|st->st_rdev;
-		}
-		/* fetch real size for disks */
-		if(S_ISBLK(st->st_mode) && (fd = open(name, O_RDONLY)) >= 0){
-			d->length = 0;
-			close(fd);
-		}
-#if defined(DIOCGMEDIASIZE)
-		if(isdisk(st)){
-			int fd;
-			off_t mediasize;
-
-			if((fd = open(name, O_RDONLY)) >= 0){
-				if(ioctl(fd, DIOCGMEDIASIZE, &mediasize) >= 0)
-					d->length = mediasize;
-				close(fd);
-			}
-		}
-#elif defined(_HAVEDISKLABEL)
-		if(isdisk(st)){
-			int fd, n;
-			struct disklabel lab;
-
-			if((fd = open(name, O_RDONLY)) < 0)
-				goto nosize;
-			if(ioctl(fd, DIOCGDINFO, &lab) < 0)
-				goto nosize;
-			n = minor(st->st_rdev)&7;
-			if(n >= lab.d_npartitions)
-				goto nosize;
-
-			d->length = (vlong)(lab.d_partitions[n].p_size) * lab.d_secsize;
-
-		nosize:
-			if(fd >= 0)
-				close(fd);
-		}
-#endif
-	}
-
-	return sz;
-}
-
diff --git a/src/lib9/atoi.c b/src/lib9/atoi.c
deleted file mode 100644
index 5b002df..0000000
--- a/src/lib9/atoi.c
+++ /dev/null
@@ -1,47 +0,0 @@
-// +build !plan9
-
-/*
-Plan 9 from User Space src/lib9/ato*.c
-http://code.swtch.com/plan9port/src/tip/src/lib9/atoi.c
-
-Copyright 2001-2007 Russ Cox.  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.
-*/
-
-#include <u.h>
-#include <libc.h>
-
-int
-atoi(char *s)
-{
-	return (int)strtol(s, 0, 0);
-}
-
-long
-atol(char *s)
-{
-	return strtol(s, 0, 0);
-}
-
-vlong
-atoll(char *s)
-{
-	return strtoll(s, 0, 0);
-}
diff --git a/src/lib9/await.c b/src/lib9/await.c
deleted file mode 100644
index dfb155b..0000000
--- a/src/lib9/await.c
+++ /dev/null
@@ -1,182 +0,0 @@
-// +build !plan9
-// +build !windows
-
-/*
-Plan 9 from User Space src/lib9/await.c
-http://code.swtch.com/plan9port/src/tip/src/lib9/await.c
-
-Copyright 2001-2007 Russ Cox.  All Rights Reserved.
-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.
-*/
-
-#define NOPLAN9DEFINES
-#include <u.h>
-#include <libc.h>
-
-#include <signal.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-
-#ifndef WCOREDUMP	/* not on Mac OS X Tiger */
-#define WCOREDUMP(status) 0
-#endif
-
-static struct {
-	int sig;
-	char *str;
-} tab[] = {
-	SIGHUP,		"hangup",
-	SIGINT,		"interrupt",
-	SIGQUIT,		"quit",
-	SIGILL,		"sys: illegal instruction",
-	SIGTRAP,		"sys: breakpoint",
-	SIGABRT,		"sys: abort",
-#ifdef SIGEMT
-	SIGEMT,		"sys: emulate instruction executed",
-#endif
-	SIGFPE,		"sys: fp: trap",
-	SIGKILL,		"sys: kill",
-	SIGBUS,		"sys: bus error",
-	SIGSEGV,		"sys: segmentation violation",
-	SIGALRM,		"alarm",
-	SIGTERM,		"kill",
-	SIGURG,		"sys: urgent condition on socket",
-	SIGSTOP,		"sys: stop",
-	SIGTSTP,		"sys: tstp",
-	SIGCONT,		"sys: cont",
-	SIGCHLD,		"sys: child",
-	SIGTTIN,		"sys: ttin",
-	SIGTTOU,		"sys: ttou",
-#ifdef SIGIO	/* not on Mac OS X Tiger */
-	SIGIO,		"sys: i/o possible on fd",
-#endif
-	SIGXCPU,		"sys: cpu time limit exceeded",
-	SIGXFSZ,		"sys: file size limit exceeded",
-	SIGVTALRM,	"sys: virtual time alarm",
-	SIGPROF,		"sys: profiling timer alarm",
-#ifdef SIGWINCH	/* not on Mac OS X Tiger */
-	SIGWINCH,	"sys: window size change",
-#endif
-#ifdef SIGINFO
-	SIGINFO,		"sys: status request",
-#endif
-	SIGUSR1,		"sys: usr1",
-	SIGUSR2,		"sys: usr2",
-	SIGPIPE,		"sys: write on closed pipe",
-};
-
-char*
-_p9sigstr(int sig, char *tmp)
-{
-	int i;
-
-	for(i=0; i<nelem(tab); i++)
-		if(tab[i].sig == sig)
-			return tab[i].str;
-	if(tmp == nil)
-		return nil;
-	sprint(tmp, "sys: signal %d", sig);
-	return tmp;
-}
-
-int
-_p9strsig(char *s)
-{
-	int i;
-
-	for(i=0; i<nelem(tab); i++)
-		if(strcmp(s, tab[i].str) == 0)
-			return tab[i].sig;
-	return 0;
-}
-
-static Waitmsg*
-_wait(int pid4, int opt)
-{
-	int pid, status, cd;
-	struct rusage ru;
-	char tmp[64];
-	ulong u, s;
-	Waitmsg *w;
-
-	w = malloc(sizeof *w + 200);
-	if(w == nil)
-		return nil;
-	memset(w, 0, sizeof *w);
-	w->msg = (char*)&w[1];
-
-	for(;;){
-		/* On Linux, pid==-1 means anyone; on SunOS, it's pid==0. */
-		if(pid4 == -1)
-			pid = wait3(&status, opt, &ru);
-		else
-			pid = wait4(pid4, &status, opt, &ru);
-		if(pid <= 0) {
-			free(w);
-			return nil;
-		}
-		u = (ulong)(ru.ru_utime.tv_sec*1000+((ru.ru_utime.tv_usec+500)/1000));
-		s = (ulong)(ru.ru_stime.tv_sec*1000+((ru.ru_stime.tv_usec+500)/1000));
-		w->pid = pid;
-		w->time[0] = u;
-		w->time[1] = s;
-		w->time[2] = u+s;
-		if(WIFEXITED(status)){
-			if(status)
-				sprint(w->msg, "%d", status);
-			return w;
-		}
-		if(WIFSIGNALED(status)){
-			cd = WCOREDUMP(status);
-			sprint(w->msg, "signal: %s", _p9sigstr(WTERMSIG(status), tmp));
-			if(cd)
-				strcat(w->msg, " (core dumped)");
-			return w;
-		}
-	}
-}
-
-Waitmsg*
-p9wait(void)
-{
-	return _wait(-1, 0);
-}
-
-Waitmsg*
-p9waitfor(int pid)
-{
-	return _wait(pid, 0);
-}
-
-Waitmsg*
-p9waitnohang(void)
-{
-	return _wait(-1, WNOHANG);
-}
-
-int
-p9waitpid(void)
-{
-	int status;
-	return wait(&status);
-}
diff --git a/src/lib9/cleanname.c b/src/lib9/cleanname.c
deleted file mode 100644
index cb8fce6..0000000
--- a/src/lib9/cleanname.c
+++ /dev/null
@@ -1,80 +0,0 @@
-// +build !plan9
-
-/*
-Inferno libkern/cleanname.c
-http://code.google.com/p/inferno-os/source/browse/libkern/cleanname.c
-
-	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  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.
-*/
-
-#include <u.h>
-#include <libc.h>
-
-/*
- * In place, rewrite name to compress multiple /, eliminate ., and process ..
- */
-#define SEP(x)	((x)=='/' || (x) == 0)
-char*
-cleanname(char *name)
-{
-	char *p, *q, *dotdot;
-	int rooted;
-
-	rooted = name[0] == '/';
-
-	/*
-	 * invariants:
-	 *	p points at beginning of path element we're considering.
-	 *	q points just past the last path element we wrote (no slash).
-	 *	dotdot points just past the point where .. cannot backtrack
-	 *		any further (no slash).
-	 */
-	p = q = dotdot = name+rooted;
-	while(*p) {
-		if(p[0] == '/')	/* null element */
-			p++;
-		else if(p[0] == '.' && SEP(p[1]))
-			p += 1;	/* don't count the separator in case it is nul */
-		else if(p[0] == '.' && p[1] == '.' && SEP(p[2])) {
-			p += 2;
-			if(q > dotdot) {	/* can backtrack */
-				while(--q > dotdot && *q != '/')
-					;
-			} else if(!rooted) {	/* /.. is / but ./../ is .. */
-				if(q != name)
-					*q++ = '/';
-				*q++ = '.';
-				*q++ = '.';
-				dotdot = q;
-			}
-		} else {	/* real path element */
-			if(q != name+rooted)
-				*q++ = '/';
-			while((*q = *p) != '/' && *q != 0)
-				p++, q++;
-		}
-	}
-	if(q == name)	/* empty string is really ``.'' */
-		*q++ = '.';
-	*q = '\0';
-	return name;
-}
diff --git a/src/lib9/create.c b/src/lib9/create.c
deleted file mode 100644
index 4ac7f7d..0000000
--- a/src/lib9/create.c
+++ /dev/null
@@ -1,85 +0,0 @@
-// +build !plan9
-
-/*
-Plan 9 from User Space src/lib9/create.c
-http://code.swtch.com/plan9port/src/tip/src/lib9/create.c
-
-Copyright 2001-2007 Russ Cox.  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.
-*/
-#define _GNU_SOURCE	/* for Linux O_DIRECT */
-#include <u.h>
-#define NOPLAN9DEFINES
-#include <sys/file.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <libc.h>
-#include <sys/stat.h>
-#ifndef O_DIRECT
-#define O_DIRECT 0
-#endif
-
-int
-p9create(char *path, int mode, ulong perm)
-{
-	int fd, umode, rclose;
-
-	rclose = mode&ORCLOSE;
-	mode &= ~ORCLOSE;
-
-	/* XXX should get mode mask right? */
-	fd = -1;
-	if(perm&DMDIR){
-		if(mode != OREAD){
-			werrstr("bad mode in directory create");
-			goto out;
-		}
-		if(mkdir(path, perm&0777) < 0)
-			goto out;
-		fd = open(path, O_RDONLY);
-	}else{
-		umode = (mode&3)|O_CREAT|O_TRUNC;
-		mode &= ~(3|OTRUNC);
-		if(mode&ODIRECT){
-			umode |= O_DIRECT;
-			mode &= ~ODIRECT;
-		}
-		if(mode&OEXCL){
-			umode |= O_EXCL;
-			mode &= ~OEXCL;
-		}
-		if(mode&OAPPEND){
-			umode |= O_APPEND;
-			mode &= ~OAPPEND;
-		}
-		if(mode){
-			werrstr("unsupported mode in create");
-			goto out;
-		}
-		umode |= O_BINARY;
-		fd = open(path, umode, perm);
-	}
-out:
-	if(fd >= 0){
-		if(rclose)
-			remove(path);
-	}
-	return fd;
-}
diff --git a/src/lib9/ctime.c b/src/lib9/ctime.c
deleted file mode 100644
index e16ad4a..0000000
--- a/src/lib9/ctime.c
+++ /dev/null
@@ -1,30 +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.
-
-// +build !plan9
-
-#define NOPLAN9DEFINES
-#include <u.h>
-#include <libc.h>
-
-char*
-p9ctime(long t)
-{
-	static char buf[100];
-	time_t tt;
-	struct tm *tm;
-	
-	tt = t;
-	tm = localtime(&tt);
-	snprint(buf, sizeof buf, "%3.3s %3.3s %02d %02d:%02d:%02d %3.3s %d\n",
-		&"SunMonTueWedThuFriSat"[tm->tm_wday*3],
-		&"JanFebMarAprMayJunJulAugSepOctNovDec"[tm->tm_mon*3],
-		tm->tm_mday,
-		tm->tm_hour,
-		tm->tm_min,
-		tm->tm_sec,
-		"XXX",  // tm_zone is unavailable on windows, and no one cares
-		tm->tm_year + 1900);
-	return buf;
-}
diff --git a/src/lib9/dirfstat.c b/src/lib9/dirfstat.c
deleted file mode 100644
index c092a2a..0000000
--- a/src/lib9/dirfstat.c
+++ /dev/null
@@ -1,56 +0,0 @@
-// +build !plan9
-
-/*
-Plan 9 from User Space src/lib9/dirfstat.c
-http://code.swtch.com/plan9port/src/tip/src/lib9/dirfstat.c
-
-Copyright 2001-2007 Russ Cox.  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.
-*/
-#include <u.h>
-#define NOPLAN9DEFINES
-#include <libc.h>
-
-#include <sys/stat.h>
-
-extern int _p9dir(struct stat*, struct stat*, char*, Dir*, char**, char*);
-
-Dir*
-dirfstat(int fd)
-{
-	struct stat st;
-	int nstr;
-	Dir *d;
-	char *str, tmp[100];
-
-	if(fstat(fd, &st) < 0)
-		return nil;
-
-	snprint(tmp, sizeof tmp, "/dev/fd/%d", fd);
-	nstr = _p9dir(&st, &st, tmp, nil, nil, nil);
-	d = malloc(sizeof(Dir)+(size_t)nstr);
-	if(d == nil)
-		return nil;
-	memset(d, 0, sizeof(Dir)+(size_t)nstr);
-	str = (char*)&d[1];
-	_p9dir(&st, &st, tmp, d, &str, str+nstr);
-	return d;
-}
-
diff --git a/src/lib9/dirfwstat.c b/src/lib9/dirfwstat.c
deleted file mode 100644
index 4666e21..0000000
--- a/src/lib9/dirfwstat.c
+++ /dev/null
@@ -1,84 +0,0 @@
-// +build !plan9
-
-/*
-Plan 9 from User Space src/lib9/dirfwstat.c
-http://code.swtch.com/plan9port/src/tip/src/lib9/dirfwstat.c
-
-Copyright 2001-2007 Russ Cox.  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.
-*/
-
-#define NOPLAN9DEFINES
-#include <u.h>
-#include <libc.h>
-#include <sys/time.h>
-#include <sys/stat.h>
-
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(__linux__)
-/* do nothing -- futimes exists and is fine */
-
-#elif defined(__SunOS5_9__)
-/* use futimesat */
-static int
-futimes(int fd, struct timeval *tv)
-{
-	return futimesat(fd, 0, tv);
-}
-
-#else
-/* provide dummy */
-/* rename just in case -- linux provides an unusable one */
-#undef futimes
-#define futimes myfutimes
-static int
-futimes(int fd, struct timeval *tv)
-{
-	USED(fd);
-	USED(tv);
-	werrstr("futimes not available");
-	return -1;
-}
-
-#endif
-
-int
-dirfwstat(int fd, Dir *dir)
-{
-	int ret;
-	struct timeval tv[2];
-
-	ret = 0;
-#ifndef _WIN32
-	if(~dir->mode != 0){
-		if(fchmod(fd, (mode_t)dir->mode) < 0)
-			ret = -1;
-	}
-#endif
-	if(~dir->mtime != 0){
-		tv[0].tv_sec = (time_t)dir->mtime;
-		tv[0].tv_usec = 0;
-		tv[1].tv_sec = (time_t)dir->mtime;
-		tv[1].tv_usec = 0;
-		if(futimes(fd, tv) < 0)
-			ret = -1;
-	}
-	return ret;
-}
-
diff --git a/src/lib9/dirstat.c b/src/lib9/dirstat.c
deleted file mode 100644
index 33f0d7c..0000000
--- a/src/lib9/dirstat.c
+++ /dev/null
@@ -1,65 +0,0 @@
-// +build !plan9
-
-/*
-Plan 9 from User Space src/lib9/dirstat.c
-http://code.swtch.com/plan9port/src/tip/src/lib9/dirstat.c
-
-Copyright 2001-2007 Russ Cox.  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.
-*/
-#include <u.h>
-#define NOPLAN9DEFINES
-#include <libc.h>
-
-#include <sys/stat.h>
-
-extern int _p9dir(struct stat*, struct stat*, char*, Dir*, char**, char*);
-
-Dir*
-dirstat(char *file)
-{
-	struct stat lst;
-	struct stat st;
-	int nstr;
-	Dir *d;
-	char *str;
-
-#ifdef _WIN32
-	if(stat(file, &st) < 0)
-		return nil;
-	lst = st;
-#else
-	if(lstat(file, &lst) < 0)
-		return nil;
-	st = lst;
-	if((lst.st_mode&S_IFMT) == S_IFLNK)
-		stat(file, &st);
-#endif
-
-	nstr = _p9dir(&lst, &st, file, nil, nil, nil);
-	d = malloc(sizeof(Dir)+(size_t)nstr);
-	if(d == nil)
-		return nil;
-	memset(d, 0, sizeof(Dir)+(size_t)nstr);
-	str = (char*)&d[1];
-	_p9dir(&lst, &st, file, d, &str, str+nstr);
-	return d;
-}
-
diff --git a/src/lib9/dirwstat.c b/src/lib9/dirwstat.c
deleted file mode 100644
index 22e25ff..0000000
--- a/src/lib9/dirwstat.c
+++ /dev/null
@@ -1,45 +0,0 @@
-// +build !plan9
-
-/*
-Plan 9 from User Space src/lib9/dirwstat.c
-http://code.swtch.com/plan9port/src/tip/src/lib9/dirwstat.c
-
-Copyright 2001-2007 Russ Cox.  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.
-*/
-#include <u.h>
-#define NOPLAN9DEFINES
-#include <libc.h>
-#include <sys/time.h>
-#include <utime.h>
-
-int
-dirwstat(char *file, Dir *dir)
-{
-	struct utimbuf ub;
-
-	/* BUG handle more */
-	if(~dir->mtime == 0)
-		return 0;
-
-	ub.actime = (time_t)dir->mtime;
-	ub.modtime = (time_t)dir->mtime;
-	return utime(file, &ub);
-}
diff --git a/src/lib9/dup.c b/src/lib9/dup.c
deleted file mode 100644
index 5cac831..0000000
--- a/src/lib9/dup.c
+++ /dev/null
@@ -1,38 +0,0 @@
-// +build !plan9
-
-/*
-Plan 9 from User Space src/lib9/dup.c
-http://code.swtch.com/plan9port/src/tip/src/lib9/dup.c
-
-Copyright 2001-2007 Russ Cox.  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.
-*/
-#include <u.h>
-#include <libc.h>
-
-#undef dup
-
-int
-p9dup(int old, int new)
-{
-	if(new == -1)
-		return dup(old);
-	return dup2(old, new);
-}
diff --git a/src/lib9/errstr.c b/src/lib9/errstr.c
deleted file mode 100644
index 9d91975..0000000
--- a/src/lib9/errstr.c
+++ /dev/null
@@ -1,107 +0,0 @@
-// +build !plan9
-
-/*
-Plan 9 from User Space src/lib9/errstr.c
-http://code.swtch.com/plan9port/src/tip/src/lib9/errstr.c
-
-Copyright 2001-2007 Russ Cox.  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.
-*/
-
-/*
- * We assume there's only one error buffer for the whole system.
- * If you use ffork, you need to provide a _syserrstr.  Since most
- * people will use libthread (which provides a _syserrstr), this is
- * okay.
- */
-
-#include <u.h>
-#include <errno.h>
-#include <libc.h>
-
-enum
-{
-	EPLAN9 = 0x19283745
-};
-
-char *(*_syserrstr)(void);
-static char xsyserr[ERRMAX];
-static char*
-getsyserr(void)
-{
-	char *s;
-
-	s = nil;
-	if(_syserrstr)
-		s = (*_syserrstr)();
-	if(s == nil)
-		s = xsyserr;
-	return s;
-}
-
-int
-errstr(char *err, uint n)
-{
-	char tmp[ERRMAX];
-	char *syserr;
-
-	strecpy(tmp, tmp+ERRMAX, err);
-	rerrstr(err, n);
-	syserr = getsyserr();
-	strecpy(syserr, syserr+ERRMAX, tmp);
-	errno = EPLAN9;
-	return 0;
-}
-
-void
-rerrstr(char *err, uint n)
-{
-	char *syserr;
-
-	syserr = getsyserr();
-	if(errno == EINTR)
-		strcpy(syserr, "interrupted");
-	else if(errno != EPLAN9)
-		strcpy(syserr, strerror(errno));
-	strecpy(err, err+n, syserr);
-}
-
-/* replaces __errfmt in libfmt */
-
-int
-__errfmt(Fmt *f)
-{
-	if(errno == EPLAN9)
-		return fmtstrcpy(f, getsyserr());
-	return fmtstrcpy(f, strerror(errno));
-}
-
-void
-werrstr(char *fmt, ...)
-{
-	va_list arg;
-	char buf[ERRMAX];
-
-	va_start(arg, fmt);
-	vseprint(buf, buf+ERRMAX, fmt, arg);
-	va_end(arg);
-	errstr(buf, ERRMAX);
-}
-
diff --git a/src/lib9/exec.c b/src/lib9/exec.c
deleted file mode 100644
index 8e5fc57..0000000
--- a/src/lib9/exec.c
+++ /dev/null
@@ -1,35 +0,0 @@
-// +build !plan9
-
-/*
-Plan 9 from User Space src/lib9/exec.c
-http://code.swtch.com/plan9port/src/tip/src/lib9/exec.c
-
-Copyright 2001-2007 Russ Cox.  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.
-*/
-#include <u.h>
-#include <libc.h>
-
-int
-exec(char *prog, char *argv[])
-{
-	/* to mimic plan 9 should be just exec, but execvp is a better fit for unix */
-	return execvp(prog, argv);
-}
diff --git a/src/lib9/execl.c b/src/lib9/execl.c
deleted file mode 100644
index fd4d23d..0000000
--- a/src/lib9/execl.c
+++ /dev/null
@@ -1,55 +0,0 @@
-// +build !plan9
-
-/*
-Plan 9 from User Space src/lib9/execl.c
-http://code.swtch.com/plan9port/src/tip/src/lib9/execl.c
-
-Copyright 2001-2007 Russ Cox.  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.
-*/
-#include <u.h>
-#include <libc.h>
-
-int
-execl(char *prog, ...)
-{
-	int i;
-	va_list arg;
-	char **argv;
-
-	va_start(arg, prog);
-	for(i=0; va_arg(arg, char*) != nil; i++)
-		;
-	va_end(arg);
-
-	argv = malloc((size_t)(i+1)*sizeof(char*));
-	if(argv == nil)
-		return -1;
-
-	va_start(arg, prog);
-	for(i=0; (argv[i] = va_arg(arg, char*)) != nil; i++)
-		;
-	va_end(arg);
-
-	exec(prog, argv);
-	free(argv);
-	return -1;
-}
-
diff --git a/src/lib9/exitcode.c b/src/lib9/exitcode.c
deleted file mode 100644
index fc86344..0000000
--- a/src/lib9/exitcode.c
+++ /dev/null
@@ -1,37 +0,0 @@
-// +build !plan9
-
-/*
-Plan 9 from User Space src/lib9/exitcode.c
-http://code.swtch.com/plan9port/src/tip/src/lib9/exitcode.c
-
-Copyright 2001-2007 Russ Cox.  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.
-*/
-
-#include <u.h>
-#include <libc.h>
-
-int
-exitcode(char *s)
-{
-	USED(s);
-	return 1;
-}
-
diff --git a/src/lib9/exits.c b/src/lib9/exits.c
deleted file mode 100644
index 0be7cb9..0000000
--- a/src/lib9/exits.c
+++ /dev/null
@@ -1,36 +0,0 @@
-// +build !plan9
-
-/*
-Plan 9 from User Space src/lib9/_exits.c
-http://code.swtch.com/plan9port/src/tip/src/lib9/_exits.c
-
-Copyright 2001-2007 Russ Cox.  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.
-*/
-#include <u.h>
-#include <libc.h>
-
-void
-exits(char *s)
-{
-	if(s == 0 || *s == 0)
-		exit(0);
-	exit(exitcode(s));
-}
diff --git a/src/lib9/flag.c b/src/lib9/flag.c
deleted file mode 100644
index db46b98..0000000
--- a/src/lib9/flag.c
+++ /dev/null
@@ -1,307 +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.
-
-#include <u.h>
-#include <libc.h>
-
-// Flag hash.
-typedef struct Flag Flag;
-
-struct Flag
-{
-	char *name;
-	int namelen;
-	char *desc;
-	int iscount;
-	void (*set)(char*, void*);
-	void (*set2)(char*, char*, void*);
-	void *arg;
-	Flag *next;
-	Flag *allnext;
-};
-
-static Flag *curflag;
-
-static Flag *fhash[512];
-static Flag *first, *last;
-
-char *argv0;
-
-/*
- * Mac OS can't deal with files that only declare data.
- * ARGBEGIN mentions this function so that this file gets pulled in.
- */
-void __fixargv0(void) { }
-
-// FNV-1 hash. http://isthe.com/chongo/tech/comp/fnv/
-static uint32
-fnv(char *p, int n)
-{
-	uint32 h;
-	
-	h = 2166136261U;
-	while(n-- > 0)
-		h = (h*16777619) ^ (uchar)*p++;
-	return h;
-}
-
-static Flag*
-lookflag(char *name, int namelen, int creat)
-{
-	uint32 h;
-	Flag *f;
-
-	h = fnv(name, namelen) & (nelem(fhash)-1);
-	for(f=fhash[h]; f; f=f->next) {
-		if(f->namelen == namelen && memcmp(f->name, name, (size_t)namelen) == 0) {
-			if(creat)
-				sysfatal("multiple definitions of flag -%s", name);
-			return f;
-		}
-	}
-	
-	if(!creat)
-		return nil;
-
-	f = malloc(sizeof *f);
-	if(f == nil)
-		sysfatal("out of memory");
-	memset(f, 0, sizeof *f);
-	f->name = name;
-	f->namelen = namelen;
-	f->next = fhash[h];
-	if(first == nil)
-		first = f;
-	else
-		last->allnext = f;
-	last = f;
-	fhash[h] = f;
-	return f;
-}
-
-static void
-count(char *arg, void *p)
-{
-	int *ip;
-	
-	ip = p;
-	if(arg != nil)
-		*ip = atoi(arg);
-	else
-		(*ip)++;
-}
-
-void
-flagcount(char *name, char *desc, int *p)
-{
-	Flag *f;
-	
-	f = lookflag(name, (int)strlen(name), 1);
-	f->desc = desc;
-	f->iscount = 1;
-	f->set = count;
-	f->arg = p;
-}
-
-static void
-atollwhex(char *s, void *p)
-{
-	char *t;
-
-	*(int64*)p = strtoll(s, &t, 0);
-	if(*s == '\0' || *t != '\0')
-		sysfatal("invalid numeric argument -%s=%s", curflag->name, s);
-}
-
-void
-flagint64(char *name, char *desc, int64 *p)
-{
-	Flag *f;
-	
-	f = lookflag(name, (int)strlen(name), 1);
-	f->desc = desc;
-	f->set = atollwhex;
-	f->arg = p;
-}
-
-static void
-atolwhex(char *s, void *p)
-{
-	char *t;
-
-	*(int32*)p = (int32)strtol(s, &t, 0);
-	if(*s == '\0' || *t != '\0')
-		sysfatal("invalid numeric argument -%s=%s", curflag->name, s);
-}
-
-void
-flagint32(char *name, char *desc, int32 *p)
-{
-	Flag *f;
-	
-	f = lookflag(name, (int)strlen(name), 1);
-	f->desc = desc;
-	f->set = atolwhex;
-	f->arg = p;
-}
-
-static void
-string(char *s, void *p)
-{
-	*(char**)p = s;
-}
-
-void
-flagstr(char *name, char *desc, char **p)
-{
-
-	Flag *f;
-	
-	f = lookflag(name, (int)strlen(name), 1);
-	f->desc = desc;
-	f->set = string;
-	f->arg = p;
-}	
-
-static void
-fn0(char *s, void *p)
-{
-	USED(s);
-	((void(*)(void))p)();
-}
-
-void
-flagfn0(char *name, char *desc, void (*fn)(void))
-{
-	Flag *f;
-	
-	f = lookflag(name, (int)strlen(name), 1);
-	f->desc = desc;
-	f->set = fn0;
-	f->arg = fn;
-	f->iscount = 1;
-}
-
-static void
-fn1(char *s, void *p)
-{
-	((void(*)(char*))p)(s);
-}
-
-void
-flagfn1(char *name, char *desc, void (*fn)(char*))
-{
-	Flag *f;
-	
-	f = lookflag(name, (int)strlen(name), 1);
-	f->desc = desc;
-	f->set = fn1;
-	f->arg = fn;
-}
-
-static void
-fn2(char *s, char *t, void *p)
-{
-	((void(*)(char*, char*))p)(s, t);
-}
-
-void
-flagfn2(char *name, char *desc, void (*fn)(char*, char*))
-{
-	Flag *f;
-	
-	f = lookflag(name, (int)strlen(name), 1);
-	f->desc = desc;
-	f->set2 = fn2;
-	f->arg = fn;
-}
-
-void
-flagparse(int *argcp, char ***argvp, void (*usage)(void))
-{
-	int argc;
-	char **argv, *p, *q;
-	char *name;
-	int namelen;
-	Flag *f;
-	
-	argc = *argcp;
-	argv = *argvp;
-
-	argv0 = argv[0];
-	argc--;
-	argv++;
-	
-	while(argc > 0) {
-		p = *argv;
-		// stop before non-flag or -
-		if(*p != '-' || p[1] == '\0')
-			break;
-		argc--;
-		argv++;
-		// stop after --
-		if(p[1] == '-' && p[2] == '\0') {
-			break;
-		}
-		
-		// turn --foo into -foo
-		if(p[1] == '-' && p[2] != '-')
-			p++;
-		
-		// allow -flag=arg if present
-		name = p+1;
-		q = strchr(name, '=');
-		if(q != nil)
-			namelen = (int)(q++ - name);
-		else
-			namelen = (int)strlen(name);
-		f = lookflag(name, namelen, 0);
-		if(f == nil) {
-			if(strcmp(p, "-h") == 0 || strcmp(p, "-help") == 0 || strcmp(p, "-?") == 0)
-				usage();
-			sysfatal("unknown flag %s", p);
-		}
-		curflag = f;
-
-		// otherwise consume next argument if non-boolean
-		if(!f->iscount && q == nil) {
-			if(argc-- == 0)
-				sysfatal("missing argument to flag %s", p);
-			q = *argv++;
-		}
-		
-		// and another if we need two
-		if(f->set2 != nil) {
-			if(argc-- == 0)
-				sysfatal("missing second argument to flag %s", p);
-			f->set2(q, *argv++, f->arg);
-			continue;
-		}
-
-		f->set(q, f->arg);			
-	}
-	
-	*argcp = argc;
-	*argvp = argv;		
-}
-
-void
-flagprint(int fd)
-{
-	Flag *f;
-	char *p, *q;
-	
-	for(f=first; f; f=f->allnext) {
-		p = f->desc;
-		if(p == nil || *p == '\0') // undocumented flag
-			continue;
-		q = strstr(p, ": ");
-		if(q)
-			fprint(fd, "  -%s %.*s\n    \t%s\n", f->name, utfnlen(p, q-p), p, q+2);
-		else if(f->namelen > 1)
-			fprint(fd, "  -%s\n    \t%s\n", f->name, p);
-		else
-			fprint(fd, "  -%s\t%s\n", f->name, p);
-	}
-}
diff --git a/src/lib9/fmt/charstod.c b/src/lib9/fmt/charstod.c
deleted file mode 100644
index b8096e8..0000000
--- a/src/lib9/fmt/charstod.c
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson,
- * with contributions from Mike Burrows and Sean Dorward.
- *
- *     Copyright (c) 2002-2006 by Lucent Technologies.
- *     Portions Copyright (c) 2004 Google Inc.
- * 
- * 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 
- * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING 
- * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
-
-#include <u.h>
-#include <libc.h>
-#include "fmtdef.h"
-
-/*
- * Reads a floating-point number by interpreting successive characters
- * returned by (*f)(vp).  The last call it makes to f terminates the
- * scan, so is not a character in the number.  It may therefore be
- * necessary to back up the input stream up one byte after calling charstod.
- */
-
-double
-fmtcharstod(int(*f)(void*), void *vp)
-{
-	double num, dem;
-	int neg, eneg, dig, exp, c;
-
-	num = 0;
-	neg = 0;
-	dig = 0;
-	exp = 0;
-	eneg = 0;
-
-	c = (*f)(vp);
-	while(c == ' ' || c == '\t')
-		c = (*f)(vp);
-	if(c == '-' || c == '+'){
-		if(c == '-')
-			neg = 1;
-		c = (*f)(vp);
-	}
-	while(c >= '0' && c <= '9'){
-		num = num*10 + c-'0';
-		c = (*f)(vp);
-	}
-	if(c == '.')
-		c = (*f)(vp);
-	while(c >= '0' && c <= '9'){
-		num = num*10 + c-'0';
-		dig++;
-		c = (*f)(vp);
-	}
-	if(c == 'e' || c == 'E'){
-		c = (*f)(vp);
-		if(c == '-' || c == '+'){
-			if(c == '-'){
-				dig = -dig;
-				eneg = 1;
-			}
-			c = (*f)(vp);
-		}
-		while(c >= '0' && c <= '9'){
-			exp = exp*10 + c-'0';
-			c = (*f)(vp);
-		}
-	}
-	exp -= dig;
-	if(exp < 0){
-		exp = -exp;
-		eneg = !eneg;
-	}
-	dem = __fmtpow10(exp);
-	if(eneg)
-		num /= dem;
-	else
-		num *= dem;
-	if(neg)
-		return -num;
-	return num;
-}
diff --git a/src/lib9/fmt/dofmt.c b/src/lib9/fmt/dofmt.c
deleted file mode 100644
index 3b9dc36..0000000
--- a/src/lib9/fmt/dofmt.c
+++ /dev/null
@@ -1,624 +0,0 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson,
- * with contributions from Mike Burrows and Sean Dorward.
- *
- *     Copyright (c) 2002-2006 by Lucent Technologies.
- *     Portions Copyright (c) 2004 Google Inc.
- *
- * 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
- * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
- * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
-
-#include <u.h>
-#include <libc.h>
-#include "fmtdef.h"
-
-/* format the output into f->to and return the number of characters fmted  */
-int
-dofmt(Fmt *f, char *fmt)
-{
-	Rune rune, *rt, *rs;
-	Rune r;
-	char *t, *s;
-	int n, nfmt;
-
-	nfmt = f->nfmt;
-	for(;;){
-		if(f->runes){
-			rt = (Rune*)f->to;
-			rs = (Rune*)f->stop;
-			while((r = (Rune)*(uchar*)fmt) && r != '%'){
-				if(r < Runeself)
-					fmt++;
-				else{
-					fmt += chartorune(&rune, fmt);
-					r = rune;
-				}
-				FMTRCHAR(f, rt, rs, r);
-			}
-			fmt++;
-			f->nfmt += (int)(rt - (Rune *)f->to);
-			f->to = rt;
-			if(!r)
-				return f->nfmt - nfmt;
-			f->stop = rs;
-		}else{
-			t = (char*)f->to;
-			s = (char*)f->stop;
-			while((r = (Rune)*(uchar*)fmt) && r != '%'){
-				if(r < Runeself){
-					FMTCHAR(f, t, s, r);
-					fmt++;
-				}else{
-					n = chartorune(&rune, fmt);
-					if(t + n > s){
-						t = (char*)__fmtflush(f, t, n);
-						if(t != nil)
-							s = (char*)f->stop;
-						else
-							return -1;
-					}
-					while(n--)
-						*t++ = *fmt++;
-				}
-			}
-			fmt++;
-			f->nfmt += (int)(t - (char *)f->to);
-			f->to = t;
-			if(!r)
-				return f->nfmt - nfmt;
-			f->stop = s;
-		}
-
-		fmt = (char*)__fmtdispatch(f, fmt, 0);
-		if(fmt == nil)
-			return -1;
-	}
-}
-
-void *
-__fmtflush(Fmt *f, void *t, int len)
-{
-	if(f->runes)
-		f->nfmt += (int)((Rune*)t - (Rune*)f->to);
-	else
-		f->nfmt += (int)((char*)t - (char *)f->to);
-	f->to = t;
-	if(f->flush == 0 || (*f->flush)(f) == 0 || (char*)f->to + len > (char*)f->stop){
-		f->stop = f->to;
-		return nil;
-	}
-	return f->to;
-}
-
-/*
- * put a formatted block of memory sz bytes long of n runes into the output buffer,
- * left/right justified in a field of at least f->width characters (if FmtWidth is set)
- */
-int
-__fmtpad(Fmt *f, int n)
-{
-	char *t, *s;
-	int i;
-
-	t = (char*)f->to;
-	s = (char*)f->stop;
-	for(i = 0; i < n; i++)
-		FMTCHAR(f, t, s, ' ');
-	f->nfmt += (int)(t - (char *)f->to);
-	f->to = t;
-	return 0;
-}
-
-int
-__rfmtpad(Fmt *f, int n)
-{
-	Rune *t, *s;
-	int i;
-
-	t = (Rune*)f->to;
-	s = (Rune*)f->stop;
-	for(i = 0; i < n; i++)
-		FMTRCHAR(f, t, s, ' ');
-	f->nfmt += (int)(t - (Rune *)f->to);
-	f->to = t;
-	return 0;
-}
-
-int
-__fmtcpy(Fmt *f, const void *vm, int n, int sz)
-{
-	Rune *rt, *rs, r;
-	char *t, *s, *m, *me;
-	ulong fl;
-	int nc, w;
-
-	m = (char*)vm;
-	me = m + sz;
-	fl = f->flags;
-	w = 0;
-	if(fl & FmtWidth)
-		w = f->width;
-	if((fl & FmtPrec) && n > f->prec)
-		n = f->prec;
-	if(f->runes){
-		if(!(fl & FmtLeft) && __rfmtpad(f, w - n) < 0)
-			return -1;
-		rt = (Rune*)f->to;
-		rs = (Rune*)f->stop;
-		for(nc = n; nc > 0; nc--){
-			r = *(uchar*)m;
-			if(r < Runeself)
-				m++;
-			else if((me - m) >= UTFmax || fullrune(m, (int)(me-m)))
-				m += chartorune(&r, m);
-			else
-				break;
-			FMTRCHAR(f, rt, rs, r);
-		}
-		f->nfmt += (int)(rt - (Rune *)f->to);
-		f->to = rt;
-		if(fl & FmtLeft && __rfmtpad(f, w - n) < 0)
-			return -1;
-	}else{
-		if(!(fl & FmtLeft) && __fmtpad(f, w - n) < 0)
-			return -1;
-		t = (char*)f->to;
-		s = (char*)f->stop;
-		for(nc = n; nc > 0; nc--){
-			r = *(uchar*)m;
-			if(r < Runeself)
-				m++;
-			else if((me - m) >= UTFmax || fullrune(m, (int)(me-m)))
-				m += chartorune(&r, m);
-			else
-				break;
-			FMTRUNE(f, t, s, r);
-		}
-		f->nfmt += (int)(t - (char *)f->to);
-		f->to = t;
-		if(fl & FmtLeft && __fmtpad(f, w - n) < 0)
-			return -1;
-	}
-	return 0;
-}
-
-int
-__fmtrcpy(Fmt *f, const void *vm, int n)
-{
-	Rune r, *m, *me, *rt, *rs;
-	char *t, *s;
-	ulong fl;
-	int w;
-
-	m = (Rune*)vm;
-	fl = f->flags;
-	w = 0;
-	if(fl & FmtWidth)
-		w = f->width;
-	if((fl & FmtPrec) && n > f->prec)
-		n = f->prec;
-	if(f->runes){
-		if(!(fl & FmtLeft) && __rfmtpad(f, w - n) < 0)
-			return -1;
-		rt = (Rune*)f->to;
-		rs = (Rune*)f->stop;
-		for(me = m + n; m < me; m++)
-			FMTRCHAR(f, rt, rs, *m);
-		f->nfmt += (int)(rt - (Rune *)f->to);
-		f->to = rt;
-		if(fl & FmtLeft && __rfmtpad(f, w - n) < 0)
-			return -1;
-	}else{
-		if(!(fl & FmtLeft) && __fmtpad(f, w - n) < 0)
-			return -1;
-		t = (char*)f->to;
-		s = (char*)f->stop;
-		for(me = m + n; m < me; m++){
-			r = *m;
-			FMTRUNE(f, t, s, r);
-		}
-		f->nfmt += (int)(t - (char *)f->to);
-		f->to = t;
-		if(fl & FmtLeft && __fmtpad(f, w - n) < 0)
-			return -1;
-	}
-	return 0;
-}
-
-/* fmt out one character */
-int
-__charfmt(Fmt *f)
-{
-	char x[1];
-
-	x[0] = (char)va_arg(f->args, int);
-	f->prec = 1;
-	return __fmtcpy(f, (const char*)x, 1, 1);
-}
-
-/* fmt out one rune */
-int
-__runefmt(Fmt *f)
-{
-	Rune x[1];
-
-	x[0] = (Rune)va_arg(f->args, int);
-	return __fmtrcpy(f, (const void*)x, 1);
-}
-
-/* public helper routine: fmt out a null terminated string already in hand */
-int
-fmtstrcpy(Fmt *f, char *s)
-{
-	int i, j;
-
-	if(!s)
-		return __fmtcpy(f, "<nil>", 5, 5);
-	/* if precision is specified, make sure we don't wander off the end */
-	if(f->flags & FmtPrec){
-#ifdef PLAN9PORT
-		Rune r;
-		i = 0;
-		for(j=0; j<f->prec && s[i]; j++)
-			i += chartorune(&r, s+i);
-#else
-		/* ANSI requires precision in bytes, not Runes */
-		for(i=0; i<f->prec; i++)
-			if(s[i] == 0)
-				break;
-		j = utfnlen(s, i);	/* won't print partial at end */
-#endif
-		return __fmtcpy(f, s, j, i);
-	}
-	return __fmtcpy(f, s, utflen(s), (int)strlen(s));
-}
-
-/* fmt out a null terminated utf string */
-int
-__strfmt(Fmt *f)
-{
-	char *s;
-
-	s = va_arg(f->args, char *);
-	return fmtstrcpy(f, s);
-}
-
-/* public helper routine: fmt out a null terminated rune string already in hand */
-int
-fmtrunestrcpy(Fmt *f, Rune *s)
-{
-	Rune *e;
-	int n, p;
-
-	if(!s)
-		return __fmtcpy(f, "<nil>", 5, 5);
-	/* if precision is specified, make sure we don't wander off the end */
-	if(f->flags & FmtPrec){
-		p = f->prec;
-		for(n = 0; n < p; n++)
-			if(s[n] == 0)
-				break;
-	}else{
-		for(e = s; *e; e++)
-			;
-		n = (int)(e - s);
-	}
-	return __fmtrcpy(f, s, n);
-}
-
-/* fmt out a null terminated rune string */
-int
-__runesfmt(Fmt *f)
-{
-	Rune *s;
-
-	s = va_arg(f->args, Rune *);
-	return fmtrunestrcpy(f, s);
-}
-
-/* fmt a % */
-int
-__percentfmt(Fmt *f)
-{
-	Rune x[1];
-
-	x[0] = f->r;
-	f->prec = 1;
-	return __fmtrcpy(f, (const void*)x, 1);
-}
-
-/* fmt an integer */
-int
-__ifmt(Fmt *f)
-{
-	char buf[140], *p, *conv;
-	/* 140: for 64 bits of binary + 3-byte sep every 4 digits */
-	uvlong vu;
-	ulong fl, u;
-	int neg, base, i, n, w, isv;
-	int ndig, len, excess, bytelen;
-	char *grouping;
-	char *thousands;
-
-	neg = 0;
-	fl = f->flags;
-	isv = 0;
-	vu = 0;
-	u = 0;
-#ifndef PLAN9PORT
-	/*
-	 * Unsigned verbs for ANSI C
-	 */
-	switch(f->r){
-	case 'o':
-	case 'p':
-	case 'u':
-	case 'x':
-	case 'X':
-		fl |= FmtUnsigned;
-		fl &= ~(FmtSign|FmtSpace);
-		break;
-	}
-#endif
-	if(f->r == 'p'){
-		u = (uintptr)va_arg(f->args, void*);
-		f->r = 'x';
-		fl |= FmtUnsigned;
-	}else if(fl & FmtVLong){
-		isv = 1;
-		if(fl & FmtUnsigned)
-			vu = va_arg(f->args, uvlong);
-		else
-			vu = (uvlong)va_arg(f->args, vlong);
-	}else if(fl & FmtLong){
-		if(fl & FmtUnsigned)
-			u = va_arg(f->args, ulong);
-		else
-			u = (ulong)va_arg(f->args, long);
-	}else if(fl & FmtByte){
-		if(fl & FmtUnsigned)
-			u = (uchar)va_arg(f->args, int);
-		else
-			u = (ulong)(char)va_arg(f->args, int);
-	}else if(fl & FmtShort){
-		if(fl & FmtUnsigned)
-			u = (ushort)va_arg(f->args, int);
-		else
-			u = (ulong)(short)va_arg(f->args, int);
-	}else{
-		if(fl & FmtUnsigned)
-			u = va_arg(f->args, uint);
-		else
-			u = (ulong)va_arg(f->args, int);
-	}
-	conv = "0123456789abcdef";
-	grouping = "\4";	/* for hex, octal etc. (undefined by spec but nice) */
-	thousands = f->thousands;
-	switch(f->r){
-	case 'd':
-	case 'i':
-	case 'u':
-		base = 10;
-		grouping = f->grouping;
-		break;
-	case 'X':
-		conv = "0123456789ABCDEF";
-		/* fall through */
-	case 'x':
-		base = 16;
-		thousands = ":";
-		break;
-	case 'b':
-		base = 2;
-		thousands = ":";
-		break;
-	case 'o':
-		base = 8;
-		break;
-	default:
-		return -1;
-	}
-	if(!(fl & FmtUnsigned)){
-		if(isv && (vlong)vu < 0){
-			vu = (uvlong)-(vlong)vu;
-			neg = 1;
-		}else if(!isv && (long)u < 0){
-			u = (ulong)-(long)u;
-			neg = 1;
-		}
-	}
-	p = buf + sizeof buf - 1;
-	n = 0;	/* in runes */
-	excess = 0;	/* number of bytes > number runes */
-	ndig = 0;
-	len = utflen(thousands);
-	bytelen = (int)strlen(thousands);
-	if(isv){
-		while(vu){
-			i = (int)(vu % (uvlong)base);
-			vu /= (uvlong)base;
-			if((fl & FmtComma) && n % 4 == 3){
-				*p-- = ',';
-				n++;
-			}
-			if((fl & FmtApost) && __needsep(&ndig, &grouping)){
-				n += len;
-				excess += bytelen - len;
-				p -= bytelen;
-				memmove(p+1, thousands, (size_t)bytelen);
-			}
-			*p-- = conv[i];
-			n++;
-		}
-	}else{
-		while(u){
-			i = (int)(u % (ulong)base);
-			u /= (ulong)base;
-			if((fl & FmtComma) && n % 4 == 3){
-				*p-- = ',';
-				n++;
-			}
-			if((fl & FmtApost) && __needsep(&ndig, &grouping)){
-				n += len;
-				excess += bytelen - len;
-				p -= bytelen;
-				memmove(p+1, thousands, (size_t)bytelen);
-			}
-			*p-- = conv[i];
-			n++;
-		}
-	}
-	if(n == 0){
-		/*
-		 * "The result of converting a zero value with
-		 * a precision of zero is no characters."  - ANSI
-		 *
-		 * "For o conversion, # increases the precision, if and only if
-		 * necessary, to force the first digit of the result to be a zero
-		 * (if the value and precision are both 0, a single 0 is printed)." - ANSI
-		 */
-		if(!(fl & FmtPrec) || f->prec != 0 || (f->r == 'o' && (fl & FmtSharp))){
-			*p-- = '0';
-			n = 1;
-			if(fl & FmtApost)
-				__needsep(&ndig, &grouping);
-		}
-	}
-	for(w = f->prec; n < w && p > buf+3; n++){
-		if((fl & FmtApost) && __needsep(&ndig, &grouping)){
-			n += len;
-			excess += bytelen - len;
-			p -= bytelen;
-			memmove(p+1, thousands, (size_t)bytelen);
-		}
-		*p-- = '0';
-	}
-	if(neg || (fl & (FmtSign|FmtSpace)))
-		n++;
-	if(fl & FmtSharp){
-		if(base == 16)
-			n += 2;
-		else if(base == 8){
-			if(p[1] == '0')
-				fl &= ~(ulong)FmtSharp;
-			else
-				n++;
-		}
-	}
-	if((fl & FmtZero) && !(fl & (FmtLeft|FmtPrec))){
-		w = 0;
-		if(fl & FmtWidth)
-			w = f->width;
-		for(; n < w && p > buf+3; n++){
-			if((fl & FmtApost) && __needsep(&ndig, &grouping)){
-				n += len;
-				excess += bytelen - len;
-				p -= bytelen;
-				memmove(p+1, thousands, (size_t)bytelen);
-			}
-			*p-- = '0';
-		}
-		f->flags &= ~(ulong)FmtWidth;
-	}
-	if(fl & FmtSharp){
-		if(base == 16)
-			*p-- = (char)f->r;
-		if(base == 16 || base == 8)
-			*p-- = '0';
-	}
-	if(neg)
-		*p-- = '-';
-	else if(fl & FmtSign)
-		*p-- = '+';
-	else if(fl & FmtSpace)
-		*p-- = ' ';
-	f->flags &= ~(ulong)FmtPrec;
-	return __fmtcpy(f, p + 1, n, n + excess);
-}
-
-int
-__countfmt(Fmt *f)
-{
-	void *p;
-	ulong fl;
-
-	fl = f->flags;
-	p = va_arg(f->args, void*);
-	if(fl & FmtVLong){
-		*(vlong*)p = f->nfmt;
-	}else if(fl & FmtLong){
-		*(long*)p = f->nfmt;
-	}else if(fl & FmtByte){
-		*(char*)p = (char)f->nfmt;
-	}else if(fl & FmtShort){
-		*(short*)p = (short)f->nfmt;
-	}else{
-		*(int*)p = f->nfmt;
-	}
-	return 0;
-}
-
-int
-__flagfmt(Fmt *f)
-{
-	switch(f->r){
-	case ',':
-		f->flags |= FmtComma;
-		break;
-	case '-':
-		f->flags |= FmtLeft;
-		break;
-	case '+':
-		f->flags |= FmtSign;
-		break;
-	case '#':
-		f->flags |= FmtSharp;
-		break;
-	case '\'':
-		f->flags |= FmtApost;
-		break;
-	case ' ':
-		f->flags |= FmtSpace;
-		break;
-	case 'u':
-		f->flags |= FmtUnsigned;
-		break;
-	case 'h':
-		if(f->flags & FmtShort)
-			f->flags |= FmtByte;
-		f->flags |= FmtShort;
-		break;
-	case 'L':
-		f->flags |= FmtLDouble;
-		break;
-	case 'l':
-		if(f->flags & FmtLong)
-			f->flags |= FmtVLong;
-		f->flags |= FmtLong;
-		break;
-	}
-	return 1;
-}
-
-/* default error format */
-int
-__badfmt(Fmt *f)
-{
-	char x[2+UTFmax];
-	int n;
-
-	x[0] = '%';
-	n = 1 + runetochar(x+1, &f->r);
-	x[n++] = '%';
-	f->prec = n;
-	__fmtcpy(f, (const void*)x, n, n);
-	return 0;
-}
diff --git a/src/lib9/fmt/dorfmt.c b/src/lib9/fmt/dorfmt.c
deleted file mode 100644
index f760d47..0000000
--- a/src/lib9/fmt/dorfmt.c
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson,
- * with contributions from Mike Burrows and Sean Dorward.
- *
- *     Copyright (c) 2002-2006 by Lucent Technologies.
- *     Portions Copyright (c) 2004 Google Inc.
- * 
- * 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 
- * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING 
- * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
-
-#include <u.h>
-#include <libc.h>
-#include "fmtdef.h"
-
-/* format the output into f->to and return the number of characters fmted  */
-
-/* BUG: THIS FILE IS NOT UPDATED TO THE  NEW SPEC */
-int
-dorfmt(Fmt *f, const Rune *fmt)
-{
-	Rune *rt, *rs;
-	Rune r;
-	char *t, *s;
-	int nfmt;
-
-	nfmt = f->nfmt;
-	for(;;){
-		if(f->runes){
-			rt = (Rune*)f->to;
-			rs = (Rune*)f->stop;
-			while((r = *fmt++) && r != '%'){
-				FMTRCHAR(f, rt, rs, r);
-			}
-			f->nfmt += (int)(rt - (Rune *)f->to);
-			f->to = rt;
-			if(!r)
-				return f->nfmt - nfmt;
-			f->stop = rs;
-		}else{
-			t = (char*)f->to;
-			s = (char*)f->stop;
-			while((r = *fmt++) && r != '%'){
-				FMTRUNE(f, t, f->stop, r);
-			}
-			f->nfmt += (int)(t - (char *)f->to);
-			f->to = t;
-			if(!r)
-				return f->nfmt - nfmt;
-			f->stop = s;
-		}
-
-		fmt = (Rune*)__fmtdispatch(f, (Rune*)fmt, 1);
-		if(fmt == nil)
-			return -1;
-	}
-}
diff --git a/src/lib9/fmt/errfmt.c b/src/lib9/fmt/errfmt.c
deleted file mode 100644
index a867093..0000000
--- a/src/lib9/fmt/errfmt.c
+++ /dev/null
@@ -1,32 +0,0 @@
-// +build plan9
-
-/*
- * The authors of this software are Rob Pike and Ken Thompson,
- * with contributions from Mike Burrows and Sean Dorward.
- *
- *     Copyright (c) 2002-2006 by Lucent Technologies.
- *     Portions Copyright (c) 2004 Google Inc.
- * 
- * 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 
- * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING 
- * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
-
-#include <u.h>
-#include <libc.h>
-#include "fmtdef.h"
-
-int
-__errfmt(Fmt *f)
-{
-	char buf[ERRMAX];
-
-	rerrstr(buf, sizeof buf);
-	return __fmtcpy(f, buf, utflen(buf), strlen(buf));
-}
diff --git a/src/lib9/fmt/fltfmt.c b/src/lib9/fmt/fltfmt.c
deleted file mode 100644
index 6fe8192..0000000
--- a/src/lib9/fmt/fltfmt.c
+++ /dev/null
@@ -1,683 +0,0 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson,
- * with contributions from Mike Burrows and Sean Dorward.
- *
- *     Copyright (c) 2002-2006 by Lucent Technologies.
- *     Portions Copyright (c) 2004 Google Inc.
- * 
- * 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 
- * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING 
- * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
-
-/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
-#include <u.h>
-#include <errno.h>
-#include <libc.h>
-#include "fmtdef.h"
-
-enum
-{
-	FDIGIT	= 30,
-	FDEFLT	= 6,
-	NSIGNIF	= 17
-};
-
-/*
- * first few powers of 10, enough for about 1/2 of the
- * total space for doubles.
- */
-static double pows10[] =
-{
-	  1e0,   1e1,   1e2,   1e3,   1e4,   1e5,   1e6,   1e7,   1e8,   1e9,
-	 1e10,  1e11,  1e12,  1e13,  1e14,  1e15,  1e16,  1e17,  1e18,  1e19,
-	 1e20,  1e21,  1e22,  1e23,  1e24,  1e25,  1e26,  1e27,  1e28,  1e29,
-	 1e30,  1e31,  1e32,  1e33,  1e34,  1e35,  1e36,  1e37,  1e38,  1e39,
-	 1e40,  1e41,  1e42,  1e43,  1e44,  1e45,  1e46,  1e47,  1e48,  1e49,
-	 1e50,  1e51,  1e52,  1e53,  1e54,  1e55,  1e56,  1e57,  1e58,  1e59,
-	 1e60,  1e61,  1e62,  1e63,  1e64,  1e65,  1e66,  1e67,  1e68,  1e69,
-	 1e70,  1e71,  1e72,  1e73,  1e74,  1e75,  1e76,  1e77,  1e78,  1e79,
-	 1e80,  1e81,  1e82,  1e83,  1e84,  1e85,  1e86,  1e87,  1e88,  1e89,
-	 1e90,  1e91,  1e92,  1e93,  1e94,  1e95,  1e96,  1e97,  1e98,  1e99,
-	1e100, 1e101, 1e102, 1e103, 1e104, 1e105, 1e106, 1e107, 1e108, 1e109,
-	1e110, 1e111, 1e112, 1e113, 1e114, 1e115, 1e116, 1e117, 1e118, 1e119,
-	1e120, 1e121, 1e122, 1e123, 1e124, 1e125, 1e126, 1e127, 1e128, 1e129,
-	1e130, 1e131, 1e132, 1e133, 1e134, 1e135, 1e136, 1e137, 1e138, 1e139,
-	1e140, 1e141, 1e142, 1e143, 1e144, 1e145, 1e146, 1e147, 1e148, 1e149,
-	1e150, 1e151, 1e152, 1e153, 1e154, 1e155, 1e156, 1e157, 1e158, 1e159,
-};
-
-#undef	pow10
-#define	npows10 ((int)(sizeof(pows10)/sizeof(pows10[0])))
-#define	pow10(x)  fmtpow10(x)
-
-static double
-pow10(int n)
-{
-	double d;
-	int neg;
-
-	neg = 0;
-	if(n < 0){
-		neg = 1;
-		n = -n;
-	}
-
-	if(n < npows10)
-		d = pows10[n];
-	else{
-		d = pows10[npows10-1];
-		for(;;){
-			n -= npows10 - 1;
-			if(n < npows10){
-				d *= pows10[n];
-				break;
-			}
-			d *= pows10[npows10 - 1];
-		}
-	}
-	if(neg)
-		return 1./d;
-	return d;
-}
-
-/*
- * add 1 to the decimal integer string a of length n.
- * if 99999 overflows into 10000, return 1 to tell caller
- * to move the virtual decimal point.
- */
-static int
-xadd1(char *a, int n)
-{
-	char *b;
-	int c;
-
-	if(n < 0 || n > NSIGNIF)
-		return 0;
-	for(b = a+n-1; b >= a; b--) {
-		c = *b + 1;
-		if(c <= '9') {
-			*b = (char)c;
-			return 0;
-		}
-		*b = '0';
-	}
-	/*
-	 * need to overflow adding digit.
-	 * shift number down and insert 1 at beginning.
-	 * decimal is known to be 0s or we wouldn't
-	 * have gotten this far.  (e.g., 99999+1 => 00000)
-	 */
-	a[0] = '1';
-	return 1;
-}
-
-/*
- * subtract 1 from the decimal integer string a.
- * if 10000 underflows into 09999, make it 99999
- * and return 1 to tell caller to move the virtual
- * decimal point.  this way, xsub1 is inverse of xadd1.
- */
-static int
-xsub1(char *a, int n)
-{
-	char *b;
-	int c;
-
-	if(n < 0 || n > NSIGNIF)
-		return 0;
-	for(b = a+n-1; b >= a; b--) {
-		c = *b - 1;
-		if(c >= '0') {
-			if(c == '0' && b == a) {
-				/*
-				 * just zeroed the top digit; shift everyone up.
-				 * decimal is known to be 9s or we wouldn't
-				 * have gotten this far.  (e.g., 10000-1 => 09999)
-				 */
-				*b = '9';
-				return 1;
-			}
-			*b = (char)c;
-			return 0;
-		}
-		*b = '9';
-	}
-	/*
-	 * can't get here.  the number a is always normalized
-	 * so that it has a nonzero first digit.
-	 */
-	abort();
-	return 0;
-}
-
-/*
- * format exponent like sprintf(p, "e%+02d", e)
- */
-static void
-xfmtexp(char *p, int e, int ucase)
-{
-	char se[9];
-	int i;
-
-	*p++ = ucase ? 'E' : 'e';
-	if(e < 0) {
-		*p++ = '-';
-		e = -e;
-	} else
-		*p++ = '+';
-	i = 0;
-	while(e) {
-		se[i++] = (char)(e % 10 + '0');
-		e /= 10;
-	}
-	while(i < 2)
-		se[i++] = '0';
-	while(i > 0)
-		*p++ = se[--i];
-	*p = '\0';
-}
-
-/*
- * compute decimal integer m, exp such that:
- *	f = m*10^exp
- *	m is as short as possible with losing exactness
- * assumes special cases (NaN, +Inf, -Inf) have been handled.
- */
-static void
-xdtoa(double f, char *s, int *exp, int *neg, int *ns)
-{
-	int d, e2, e, ee, i, ndigit;
-	int oerrno;
-	char c;
-	char tmp[NSIGNIF+10];
-	double g;
-
-	oerrno = errno; /* in case strtod smashes errno */
-
-	/*
-	 * make f non-negative.
-	 */
-	*neg = 0;
-	if(f < 0) {
-		f = -f;
-		*neg = 1;
-	}
-
-	/*
-	 * must handle zero specially.
-	 */
-	if(f == 0){
-		*exp = 0;
-		s[0] = '0';
-		s[1] = '\0';
-		*ns = 1;
-		return;
-	}
-
-	/*
-	 * find g,e such that f = g*10^e.
-	 * guess 10-exponent using 2-exponent, then fine tune.
-	 */
-	frexp(f, &e2);
-	e = (int)(e2 * .301029995664);
-	g = f * pow10(-e);
-	while(g < 1) {
-		e--;
-		g = f * pow10(-e);
-	}
-	while(g >= 10) {
-		e++;
-		g = f * pow10(-e);
-	}
-
-	/*
-	 * convert NSIGNIF digits as a first approximation.
-	 */
-	for(i=0; i<NSIGNIF; i++) {
-		d = (int)g;
-		s[i] = (char)(d+'0');
-		g = (g-d) * 10;
-	}
-	s[i] = 0;
-
-	/*
-	 * adjust e because s is 314159... not 3.14159...
-	 */
-	e -= NSIGNIF-1;
-	xfmtexp(s+NSIGNIF, e, 0);
-
-	/*
-	 * adjust conversion until strtod(s) == f exactly.
-	 */
-	for(i=0; i<10; i++) {
-		g = strtod(s, nil);
-		if(f > g) {
-			if(xadd1(s, NSIGNIF)) {
-				/* gained a digit */
-				e--;
-				xfmtexp(s+NSIGNIF, e, 0);
-			}
-			continue;
-		}
-		if(f < g) {
-			if(xsub1(s, NSIGNIF)) {
-				/* lost a digit */
-				e++;
-				xfmtexp(s+NSIGNIF, e, 0);
-			}
-			continue;
-		}
-		break;
-	}
-
-	/*
-	 * play with the decimal to try to simplify.
-	 */
-
-	/*
-	 * bump last few digits up to 9 if we can
-	 */
-	for(i=NSIGNIF-1; i>=NSIGNIF-3; i--) {
-		c = s[i];
-		if(c != '9') {
-			s[i] = '9';
-			g = strtod(s, nil);
-			if(g != f) {
-				s[i] = c;
-				break;
-			}
-		}
-	}
-
-	/*
-	 * add 1 in hopes of turning 9s to 0s
-	 */
-	if(s[NSIGNIF-1] == '9') {
-		strcpy(tmp, s);
-		ee = e;
-		if(xadd1(tmp, NSIGNIF)) {
-			ee--;
-			xfmtexp(tmp+NSIGNIF, ee, 0);
-		}
-		g = strtod(tmp, nil);
-		if(g == f) {
-			strcpy(s, tmp);
-			e = ee;
-		}
-	}
-
-	/*
-	 * bump last few digits down to 0 as we can.
-	 */
-	for(i=NSIGNIF-1; i>=NSIGNIF-3; i--) {
-		c = s[i];
-		if(c != '0') {
-			s[i] = '0';
-			g = strtod(s, nil);
-			if(g != f) {
-				s[i] = c;
-				break;
-			}
-		}
-	}
-
-	/*
-	 * remove trailing zeros.
-	 */
-	ndigit = NSIGNIF;
-	while(ndigit > 1 && s[ndigit-1] == '0'){
-		e++;
-		--ndigit;
-	}
-	s[ndigit] = 0;
-	*exp = e;
-	*ns = ndigit;
-	errno = oerrno;
-}
-
-#ifdef PLAN9PORT
-static char *special[] = { "NaN", "NaN", "+Inf", "+Inf", "-Inf", "-Inf" };
-#else
-static char *special[] = { "nan", "NAN", "inf", "INF", "-inf", "-INF" };
-#endif
-
-int
-__efgfmt(Fmt *fmt)
-{
-	char buf[NSIGNIF+10], *dot, *digits, *p, *s, suf[10], *t;
-	double f;
-	int c, chr, dotwid, e, exp, ndigits, neg, newndigits;
-	int pad, point, prec, realchr, sign, sufwid, ucase, wid, z1, z2;
-	ulong fl;
-	Rune r, *rs, *rt;
-
-	if(fmt->flags&FmtLong)
-		f = (double)va_arg(fmt->args, long double);
-	else
-		f = va_arg(fmt->args, double);
-
-	/*
-	 * extract formatting flags
-	 */
-	fl = fmt->flags;
-	fmt->flags = 0;
-	prec = FDEFLT;
-	if(fl & FmtPrec)
-		prec = fmt->prec;
-	chr = (int)fmt->r;
-	ucase = 0;
-	switch(chr) {
-	case 'A':
-	case 'E':
-	case 'F':
-	case 'G':
-		chr += 'a'-'A';
-		ucase = 1;
-		break;
-	}
-
-	/*
-	 * pick off special numbers.
-	 */
-	if(__isNaN(f)) {
-		s = special[0+ucase];
-	special:
-		fmt->flags = fl & (FmtWidth|FmtLeft);
-		return __fmtcpy(fmt, s, (int)strlen(s), (int)strlen(s));
-	}
-	if(__isInf(f, 1)) {
-		s = special[2+ucase];
-		goto special;
-	}
-	if(__isInf(f, -1)) {
-		s = special[4+ucase];
-		goto special;
-	}
-
-	/*
-	 * get exact representation.
-	 */
-	digits = buf;
-	xdtoa(f, digits, &exp, &neg, &ndigits);
-
-	/*
-	 * get locale's decimal point.
-	 */
-	dot = fmt->decimal;
-	if(dot == nil)
-		dot = ".";
-	dotwid = utflen(dot);
-
-	/*
-	 * now the formatting fun begins.
-	 * compute parameters for actual fmt:
-	 *
-	 *	pad: number of spaces to insert before/after field.
-	 *	z1: number of zeros to insert before digits
-	 *	z2: number of zeros to insert after digits
-	 *	point: number of digits to print before decimal point
-	 *	ndigits: number of digits to use from digits[]
-	 *	suf: trailing suffix, like "e-5"
-	 */
-	realchr = chr;
-	switch(chr){
-	case 'g':
-		/*
-		 * convert to at most prec significant digits. (prec=0 means 1)
-		 */
-		if(prec == 0)
-			prec = 1;
-		if(ndigits > prec) {
-			if(digits[prec] >= '5' && xadd1(digits, prec))
-				exp++;
-			exp += ndigits-prec;
-			ndigits = prec;
-		}
-
-		/*
-		 * extra rules for %g (implemented below):
-		 *	trailing zeros removed after decimal unless FmtSharp.
-		 *	decimal point only if digit follows.
-		 */
-
-		/* fall through to %e */
-	default:
-	case 'e':
-		/*
-		 * one significant digit before decimal, no leading zeros.
-		 */
-		point = 1;
-		z1 = 0;
-
-		/*
-		 * decimal point is after ndigits digits right now.
-		 * slide to be after first.
-		 */
-		e  = exp + (ndigits-1);
-
-		/*
-		 * if this is %g, check exponent and convert prec
-		 */
-		if(realchr == 'g') {
-			if(-4 <= e && e < prec)
-				goto casef;
-			prec--;	/* one digit before decimal; rest after */
-		}
-
-		/*
-		 * compute trailing zero padding or truncate digits.
-		 */
-		if(1+prec >= ndigits)
-			z2 = 1+prec - ndigits;
-		else {
-			/*
-			 * truncate digits
-			 */
-			assert(realchr != 'g');
-			newndigits = 1+prec;
-			if(digits[newndigits] >= '5' && xadd1(digits, newndigits)) {
-				/*
-				 * had 999e4, now have 100e5
-				 */
-				e++;
-			}
-			ndigits = newndigits;
-			z2 = 0;
-		}
-		xfmtexp(suf, e, ucase);
-		sufwid = (int)strlen(suf);
-		break;
-
-	casef:
-	case 'f':
-		/*
-		 * determine where digits go with respect to decimal point
-		 */
-		if(ndigits+exp > 0) {
-			point = ndigits+exp;
-			z1 = 0;
-		} else {
-			point = 1;
-			z1 = 1 + -(ndigits+exp);
-		}
-
-		/*
-		 * %g specifies prec = number of significant digits
-		 * convert to number of digits after decimal point
-		 */
-		if(realchr == 'g')
-			prec += z1 - point;
-
-		/*
-		 * compute trailing zero padding or truncate digits.
-		 */
-		if(point+prec >= z1+ndigits)
-			z2 = point+prec - (z1+ndigits);
-		else {
-			/*
-			 * truncate digits
-			 */
-			assert(realchr != 'g');
-			newndigits = point+prec - z1;
-			if(newndigits < 0) {
-				z1 += newndigits;
-				newndigits = 0;
-			} else if(newndigits == 0) {
-				/* perhaps round up */
-				if(digits[0] >= '5'){
-					digits[0] = '1';
-					newndigits = 1;
-					goto newdigit;
-				}
-			} else if(digits[newndigits] >= '5' && xadd1(digits, newndigits)) {
-				/*
-				 * digits was 999, is now 100; make it 1000
-				 */
-				digits[newndigits++] = '0';
-			newdigit:
-				/*
-				 * account for new digit
-				 */
-				if(z1)	/* 0.099 => 0.100 or 0.99 => 1.00*/
-					z1--;
-				else	/* 9.99 => 10.00 */
-					point++;
-			}
-			z2 = 0;
-			ndigits = newndigits;
-		}
-		sufwid = 0;
-		break;
-	}
-
-	/*
-	 * if %g is given without FmtSharp, remove trailing zeros.
-	 * must do after truncation, so that e.g. print %.3g 1.001
-	 * produces 1, not 1.00.  sorry, but them's the rules.
-	 */
-	if(realchr == 'g' && !(fl & FmtSharp)) {
-		if(z1+ndigits+z2 >= point) {
-			if(z1+ndigits < point)
-				z2 = point - (z1+ndigits);
-			else{
-				z2 = 0;
-				while(z1+ndigits > point && digits[ndigits-1] == '0')
-					ndigits--;
-			}
-		}
-	}
-
-	/*
-	 * compute width of all digits and decimal point and suffix if any
-	 */
-	wid = z1+ndigits+z2;
-	if(wid > point)
-		wid += dotwid;
-	else if(wid == point){
-		if(fl & FmtSharp)
-			wid += dotwid;
-		else
-			point++;	/* do not print any decimal point */
-	}
-	wid += sufwid;
-
-	/*
-	 * determine sign
-	 */
-	sign = 0;
-	if(neg)
-		sign = '-';
-	else if(fl & FmtSign)
-		sign = '+';
-	else if(fl & FmtSpace)
-		sign = ' ';
-	if(sign)
-		wid++;
-
-	/*
-	 * compute padding
-	 */
-	pad = 0;
-	if((fl & FmtWidth) && fmt->width > wid)
-		pad = fmt->width - wid;
-	if(pad && !(fl & FmtLeft) && (fl & FmtZero)){
-		z1 += pad;
-		point += pad;
-		pad = 0;
-	}
-
-	/*
-	 * format the actual field.  too bad about doing this twice.
-	 */
-	if(fmt->runes){
-		if(pad && !(fl & FmtLeft) && __rfmtpad(fmt, pad) < 0)
-			return -1;
-		rt = (Rune*)fmt->to;
-		rs = (Rune*)fmt->stop;
-		if(sign)
-			FMTRCHAR(fmt, rt, rs, sign);
-		while(z1>0 || ndigits>0 || z2>0) {
-			if(z1 > 0){
-				z1--;
-				c = '0';
-			}else if(ndigits > 0){
-				ndigits--;
-				c = *digits++;
-			}else{
-				z2--;
-				c = '0';
-			}
-			FMTRCHAR(fmt, rt, rs, c);
-			if(--point == 0) {
-				for(p = dot; *p; ){
-					p += chartorune(&r, p);
-					FMTRCHAR(fmt, rt, rs, r);
-				}
-			}
-		}
-		fmt->nfmt += (int)(rt - (Rune*)fmt->to);
-		fmt->to = rt;
-		if(sufwid && __fmtcpy(fmt, suf, sufwid, sufwid) < 0)
-			return -1;
-		if(pad && (fl & FmtLeft) && __rfmtpad(fmt, pad) < 0)
-			return -1;
-	}else{
-		if(pad && !(fl & FmtLeft) && __fmtpad(fmt, pad) < 0)
-			return -1;
-		t = (char*)fmt->to;
-		s = (char*)fmt->stop;
-		if(sign)
-			FMTCHAR(fmt, t, s, sign);
-		while(z1>0 || ndigits>0 || z2>0) {
-			if(z1 > 0){
-				z1--;
-				c = '0';
-			}else if(ndigits > 0){
-				ndigits--;
-				c = *digits++;
-			}else{
-				z2--;
-				c = '0';
-			}
-			FMTCHAR(fmt, t, s, c);
-			if(--point == 0)
-				for(p=dot; *p; p++)
-					FMTCHAR(fmt, t, s, *p);
-		}
-		fmt->nfmt += (int)(t - (char*)fmt->to);
-		fmt->to = t;
-		if(sufwid && __fmtcpy(fmt, suf, sufwid, sufwid) < 0)
-			return -1;
-		if(pad && (fl & FmtLeft) && __fmtpad(fmt, pad) < 0)
-			return -1;
-	}
-	return 0;
-}
-
diff --git a/src/lib9/fmt/fmt.c b/src/lib9/fmt/fmt.c
deleted file mode 100644
index 7e57677..0000000
--- a/src/lib9/fmt/fmt.c
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson,
- * with contributions from Mike Burrows and Sean Dorward.
- *
- *     Copyright (c) 2002-2006 by Lucent Technologies.
- *     Portions Copyright (c) 2004 Google Inc.
- * 
- * 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 
- * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING 
- * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
-
-#include <u.h>
-#include <libc.h>
-#include "fmtdef.h"
-
-enum
-{
-	Maxfmt = 64
-};
-
-typedef struct Convfmt Convfmt;
-struct Convfmt
-{
-	int	c;
-	volatile	Fmts	fmt;	/* for spin lock in fmtfmt; avoids race due to write order */
-};
-
-static struct
-{
-	/* lock by calling __fmtlock, __fmtunlock */
-	int	nfmt;
-	Convfmt	fmt[Maxfmt];
-} fmtalloc;
-
-static Convfmt knownfmt[] = {
-	' ',	__flagfmt,
-	'#',	__flagfmt,
-	'%',	__percentfmt,
-	'\'',	__flagfmt,
-	'+',	__flagfmt,
-	',',	__flagfmt,
-	'-',	__flagfmt,
-	'C',	__runefmt,	/* Plan 9 addition */
-	'E',	__efgfmt,
-#ifndef PLAN9PORT
-	'F',	__efgfmt,	/* ANSI only */
-#endif
-	'G',	__efgfmt,
-#ifndef PLAN9PORT
-	'L',	__flagfmt,	/* ANSI only */
-#endif
-	'S',	__runesfmt,	/* Plan 9 addition */
-	'X',	__ifmt,
-	'b',	__ifmt,		/* Plan 9 addition */
-	'c',	__charfmt,
-	'd',	__ifmt,
-	'e',	__efgfmt,
-	'f',	__efgfmt,
-	'g',	__efgfmt,
-	'h',	__flagfmt,
-#ifndef PLAN9PORT
-	'i',	__ifmt,		/* ANSI only */
-#endif
-	'l',	__flagfmt,
-	'n',	__countfmt,
-	'o',	__ifmt,
-	'p',	__ifmt,
-	'r',	__errfmt,
-	's',	__strfmt,
-#ifdef PLAN9PORT
-	'u',	__flagfmt,
-#else
-	'u',	__ifmt,
-#endif
-	'x',	__ifmt,
-	0,	nil,
-};
-
-
-int	(*fmtdoquote)(int);
-
-/*
- * __fmtlock() must be set
- */
-static int
-__fmtinstall(int c, Fmts f)
-{
-	Convfmt *p, *ep;
-
-	if(c<=0 || c>=65536)
-		return -1;
-	if(!f)
-		f = __badfmt;
-
-	ep = &fmtalloc.fmt[fmtalloc.nfmt];
-	for(p=fmtalloc.fmt; p<ep; p++)
-		if(p->c == c)
-			break;
-
-	if(p == &fmtalloc.fmt[Maxfmt])
-		return -1;
-
-	p->fmt = f;
-	if(p == ep){	/* installing a new format character */
-		fmtalloc.nfmt++;
-		p->c = c;
-	}
-
-	return 0;
-}
-
-int
-fmtinstall(int c, int (*f)(Fmt*))
-{
-	int ret;
-
-	__fmtlock();
-	ret = __fmtinstall(c, f);
-	__fmtunlock();
-	return ret;
-}
-
-static Fmts
-fmtfmt(int c)
-{
-	Convfmt *p, *ep;
-
-	ep = &fmtalloc.fmt[fmtalloc.nfmt];
-	for(p=fmtalloc.fmt; p<ep; p++)
-		if(p->c == c){
-			while(p->fmt == nil)	/* loop until value is updated */
-				;
-			return p->fmt;
-		}
-
-	/* is this a predefined format char? */
-	__fmtlock();
-	for(p=knownfmt; p->c; p++)
-		if(p->c == c){
-			__fmtinstall(p->c, p->fmt);
-			__fmtunlock();
-			return p->fmt;
-		}
-	__fmtunlock();
-
-	return __badfmt;
-}
-
-void*
-__fmtdispatch(Fmt *f, void *fmt, int isrunes)
-{
-	Rune rune, r;
-	int i, n;
-
-	f->flags = 0;
-	f->width = f->prec = 0;
-
-	for(;;){
-		if(isrunes){
-			r = *(Rune*)fmt;
-			fmt = (Rune*)fmt + 1;
-		}else{
-			fmt = (char*)fmt + chartorune(&rune, (char*)fmt);
-			r = rune;
-		}
-		f->r = r;
-		switch(r){
-		case '\0':
-			return nil;
-		case '.':
-			f->flags |= FmtWidth|FmtPrec;
-			continue;
-		case '0':
-			if(!(f->flags & FmtWidth)){
-				f->flags |= FmtZero;
-				continue;
-			}
-			/* fall through */
-		case '1': case '2': case '3': case '4':
-		case '5': case '6': case '7': case '8': case '9':
-			i = 0;
-			while(r >= '0' && r <= '9'){
-				i = i * 10 + (int)r - '0';
-				if(isrunes){
-					r = *(Rune*)fmt;
-					fmt = (Rune*)fmt + 1;
-				}else{
-					r = (Rune)*(char*)fmt;
-					fmt = (char*)fmt + 1;
-				}
-			}
-			if(isrunes)
-				fmt = (Rune*)fmt - 1;
-			else
-				fmt = (char*)fmt - 1;
-		numflag:
-			if(f->flags & FmtWidth){
-				f->flags |= FmtPrec;
-				f->prec = i;
-			}else{
-				f->flags |= FmtWidth;
-				f->width = i;
-			}
-			continue;
-		case '*':
-			i = va_arg(f->args, int);
-			if(i < 0){
-				/*
-				 * negative precision =>
-				 * ignore the precision.
-				 */
-				if(f->flags & FmtPrec){
-					f->flags &= ~(ulong)FmtPrec;
-					f->prec = 0;
-					continue;
-				}
-				i = -i;
-				f->flags |= FmtLeft;
-			}
-			goto numflag;
-		}
-		n = (*fmtfmt((int)r))(f);
-		if(n < 0)
-			return nil;
-		if(n == 0)
-			return fmt;
-	}
-}
diff --git a/src/lib9/fmt/fmtdef.h b/src/lib9/fmt/fmtdef.h
deleted file mode 100644
index 4bbd9f5..0000000
--- a/src/lib9/fmt/fmtdef.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- *
- *     Copyright (c) 2002-2006 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 
- * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING 
- * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
-
-/*
- * dofmt -- format to a buffer
- * the number of characters formatted is returned,
- * or -1 if there was an error.
- * if the buffer is ever filled, flush is called.
- * it should reset the buffer and return whether formatting should continue.
- */
-
-typedef int (*Fmts)(Fmt*);
-
-typedef struct Quoteinfo Quoteinfo;
-struct Quoteinfo
-{
-	int	quoted;		/* if set, string must be quoted */
-	int	nrunesin;	/* number of input runes that can be accepted */
-	int	nbytesin;	/* number of input bytes that can be accepted */
-	int	nrunesout;	/* number of runes that will be generated */
-	int	nbytesout;	/* number of bytes that will be generated */
-};
-
-/* Edit .+1,/^$/ |cfn |grep -v static | grep __ */
-double       __Inf(int sign);
-double       __NaN(void);
-int          __badfmt(Fmt *f);
-int          __charfmt(Fmt *f);
-int          __countfmt(Fmt *f);
-int          __efgfmt(Fmt *fmt);
-int          __errfmt(Fmt *f);
-int          __flagfmt(Fmt *f);
-int          __fmtFdFlush(Fmt *f);
-int          __fmtcpy(Fmt *f, const void *vm, int n, int sz);
-void*        __fmtdispatch(Fmt *f, void *fmt, int isrunes);
-void *       __fmtflush(Fmt *f, void *t, int len);
-void         __fmtlock(void);
-int          __fmtpad(Fmt *f, int n);
-double       __fmtpow10(int n);
-int          __fmtrcpy(Fmt *f, const void *vm, int n);
-void         __fmtunlock(void);
-int          __ifmt(Fmt *f);
-int          __isInf(double d, int sign);
-int          __isNaN(double d);
-int          __needsep(int*, char**);
-int          __needsquotes(char *s, int *quotelenp);
-int          __percentfmt(Fmt *f);
-void         __quotesetup(char *s, Rune *r, int nin, int nout, Quoteinfo *q, int sharp, int runesout);
-int          __quotestrfmt(int runesin, Fmt *f);
-int          __rfmtpad(Fmt *f, int n);
-int          __runefmt(Fmt *f);
-int          __runeneedsquotes(Rune *r, int *quotelenp);
-int          __runesfmt(Fmt *f);
-int          __strfmt(Fmt *f);
-
-#define FMTCHAR(f, t, s, c)\
-	do{\
-	if(t + 1 > (char*)s){\
-		t = (char*)__fmtflush(f, t, 1);\
-		if(t != nil)\
-			s = (char*)f->stop;\
-		else\
-			return -1;\
-	}\
-	*t++ = (char)c;\
-	}while(0)
-
-#define FMTRCHAR(f, t, s, c)\
-	do{\
-	if(t + 1 > (Rune*)s){\
-		t = (Rune*)__fmtflush(f, t, sizeof(Rune));\
-		if(t != nil)\
-			s = (Rune*)f->stop;\
-		else\
-			return -1;\
-	}\
-	*t++ = (Rune)c;\
-	}while(0)
-
-#define FMTRUNE(f, t, s, r)\
-	do{\
-	Rune _rune;\
-	int _runelen;\
-	if(t + UTFmax > (char*)s && t + (_runelen = runelen(r)) > (char*)s){\
-		t = (char*)__fmtflush(f, t, _runelen);\
-		if(t != nil)\
-			s = (char*)f->stop;\
-		else\
-			return -1;\
-	}\
-	if(r < Runeself)\
-		*t++ = (char)r;\
-	else{\
-		_rune = r;\
-		t += runetochar(t, &_rune);\
-	}\
-	}while(0)
-
-#ifdef va_copy
-#	define VA_COPY(a,b) va_copy(a,b)
-#	define VA_END(a) va_end(a)
-#else
-#	define VA_COPY(a,b) (a) = (b)
-#	define VA_END(a)
-#endif
-
diff --git a/src/lib9/fmt/fmtfd.c b/src/lib9/fmt/fmtfd.c
deleted file mode 100644
index dde05b7..0000000
--- a/src/lib9/fmt/fmtfd.c
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson,
- * with contributions from Mike Burrows and Sean Dorward.
- *
- *     Copyright (c) 2002-2006 by Lucent Technologies.
- *     Portions Copyright (c) 2004 Google Inc.
- * 
- * 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 
- * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING 
- * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
-
-#include <u.h>
-#include <libc.h>
-#include "fmtdef.h"
-
-/*
- * public routine for final flush of a formatting buffer
- * to a file descriptor; returns total char count.
- */
-int
-fmtfdflush(Fmt *f)
-{
-	if(__fmtFdFlush(f) <= 0)
-		return -1;
-	return f->nfmt;
-}
-
-/*
- * initialize an output buffer for buffered printing
- */
-int
-fmtfdinit(Fmt *f, int fd, char *buf, int size)
-{
-	f->runes = 0;
-	f->start = buf;
-	f->to = buf;
-	f->stop = buf + size;
-	f->flush = __fmtFdFlush;
-	f->farg = (void*)(uintptr)fd;
-	f->flags = 0;
-	f->nfmt = 0;
-	fmtlocaleinit(f, nil, nil, nil);
-	return 0;
-}
diff --git a/src/lib9/fmt/fmtfdflush.c b/src/lib9/fmt/fmtfdflush.c
deleted file mode 100644
index 401acbe..0000000
--- a/src/lib9/fmt/fmtfdflush.c
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson,
- * with contributions from Mike Burrows and Sean Dorward.
- *
- *     Copyright (c) 2002-2006 by Lucent Technologies.
- *     Portions Copyright (c) 2004 Google Inc.
- * 
- * 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 
- * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING 
- * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
-
-#include <u.h>
-#include <libc.h>
-#include "fmtdef.h"
-
-/*
- * generic routine for flushing a formatting buffer
- * to a file descriptor
- */
-int
-__fmtFdFlush(Fmt *f)
-{
-	int n;
-
-	n = (int)((char*)f->to - (char*)f->start);
-	if(n && (int)write((int)(uintptr)f->farg, f->start, (size_t)n) != n)
-		return 0;
-	f->to = f->start;
-	return 1;
-}
diff --git a/src/lib9/fmt/fmtlocale.c b/src/lib9/fmt/fmtlocale.c
deleted file mode 100644
index 64ed10f..0000000
--- a/src/lib9/fmt/fmtlocale.c
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson,
- * with contributions from Mike Burrows and Sean Dorward.
- *
- *     Copyright (c) 2002-2006 by Lucent Technologies.
- *     Portions Copyright (c) 2004 Google Inc.
- * 
- * 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 
- * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING 
- * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
-
-#include <u.h>
-#include <libc.h>
-#include "fmtdef.h"
-
-/*
- * Fill in the internationalization stuff in the State structure.
- * For nil arguments, provide the sensible defaults:
- *	decimal is a period
- *	thousands separator is a comma
- *	thousands are marked every three digits
- */
-void
-fmtlocaleinit(Fmt *f, char *decimal, char *thousands, char *grouping)
-{
-	if(decimal == nil || decimal[0] == '\0')
-		decimal = ".";
-	if(thousands == nil)
-		thousands = ",";
-	if(grouping == nil)
-		grouping = "\3";
-	f->decimal = decimal;
-	f->thousands = thousands;
-	f->grouping = grouping;
-}
-
-/*
- * We are about to emit a digit in e.g. %'d.  If that digit would
- * overflow a thousands (e.g.) grouping, tell the caller to emit
- * the thousands separator.  Always advance the digit counter
- * and pointer into the grouping descriptor.
- */
-int
-__needsep(int *ndig, char **grouping)
-{
-	int group;
-
-	(*ndig)++;
-	group = *(unsigned char*)*grouping;
-	/* CHAR_MAX means no further grouping. \0 means we got the empty string */
-	if(group == 0xFF || group == 0x7f || group == 0x00)
-		return 0;
-	if(*ndig > group){
-		/* if we're at end of string, continue with this grouping; else advance */
-		if((*grouping)[1] != '\0')
-			(*grouping)++;
-		*ndig = 1;
-		return 1;
-	}
-	return 0;
-}
-
diff --git a/src/lib9/fmt/fmtlock.c b/src/lib9/fmt/fmtlock.c
deleted file mode 100644
index 297acd8..0000000
--- a/src/lib9/fmt/fmtlock.c
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson,
- * with contributions from Mike Burrows and Sean Dorward.
- *
- *     Copyright (c) 2002-2006 by Lucent Technologies.
- *     Portions Copyright (c) 2004 Google Inc.
- * 
- * 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 
- * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING 
- * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
-
-#include <u.h>
-#include <libc.h>
-#include "fmtdef.h"
-
-void
-__fmtlock(void)
-{
-}
-
-void
-__fmtunlock(void)
-{
-}
diff --git a/src/lib9/fmt/fmtnull.c b/src/lib9/fmt/fmtnull.c
deleted file mode 100644
index b8caacb..0000000
--- a/src/lib9/fmt/fmtnull.c
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson,
- * with contributions from Mike Burrows and Sean Dorward.
- *
- *     Copyright (c) 2002-2006 by Lucent Technologies.
- *     Portions Copyright (c) 2004 Google Inc.
- * 
- * 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 
- * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING 
- * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
-
-#include <u.h>
-#include <libc.h>
-#include "fmtdef.h"
-
-/*
- * Absorb output without using resources.
- */
-static Rune nullbuf[32];
-
-static int
-__fmtnullflush(Fmt *f)
-{
-	f->to = nullbuf;
-	f->nfmt = 0;
-	return 0;
-}
-
-int
-fmtnullinit(Fmt *f)
-{
-	memset(f, 0, sizeof *f);
-	f->runes = 1;
-	f->start = nullbuf;
-	f->to = nullbuf;
-	f->stop = nullbuf+nelem(nullbuf);
-	f->flush = __fmtnullflush;
-	fmtlocaleinit(f, nil, nil, nil);
-	return 0;
-}
-
diff --git a/src/lib9/fmt/fmtprint.c b/src/lib9/fmt/fmtprint.c
deleted file mode 100644
index 6848ab4..0000000
--- a/src/lib9/fmt/fmtprint.c
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson,
- * with contributions from Mike Burrows and Sean Dorward.
- *
- *     Copyright (c) 2002-2006 by Lucent Technologies.
- *     Portions Copyright (c) 2004 Google Inc.
- * 
- * 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 
- * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING 
- * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
-
-#include <u.h>
-#include <libc.h>
-#include "fmtdef.h"
-
-/*
- * Format a string into the output buffer.
- * Designed for formats which themselves call fmt.
- * Flags, precision and width are preserved.
- */
-int
-fmtprint(Fmt *f, char *fmt, ...)
-{
-	int n;
-	va_list va;
-
-	va_start(va, fmt);
-	n = fmtvprint(f, fmt, va);
-	va_end(va);
-	return n;
-}
-
diff --git a/src/lib9/fmt/fmtquote.c b/src/lib9/fmt/fmtquote.c
deleted file mode 100644
index 93b2abb..0000000
--- a/src/lib9/fmt/fmtquote.c
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson,
- * with contributions from Mike Burrows and Sean Dorward.
- *
- *     Copyright (c) 2002-2006 by Lucent Technologies.
- *     Portions Copyright (c) 2004 Google Inc.
- * 
- * 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 
- * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING 
- * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
-
-#include <u.h>
-#include <libc.h>
-#include "fmtdef.h"
-
-/*
- * How many bytes of output UTF will be produced by quoting (if necessary) this string?
- * How many runes? How much of the input will be consumed?
- * The parameter q is filled in by __quotesetup.
- * The string may be UTF or Runes (s or r).
- * Return count does not include NUL.
- * Terminate the scan at the first of:
- *	NUL in input
- *	count exceeded in input
- *	count exceeded on output
- * *ninp is set to number of input bytes accepted.
- * nin may be <0 initially, to avoid checking input by count.
- */
-void
-__quotesetup(char *s, Rune *r, int nin, int nout, Quoteinfo *q, int sharp, int runesout)
-{
-	int w;
-	Rune c;
-
-	q->quoted = 0;
-	q->nbytesout = 0;
-	q->nrunesout = 0;
-	q->nbytesin = 0;
-	q->nrunesin = 0;
-	if(sharp || nin==0 || (s && *s=='\0') || (r && *r=='\0')){
-		if(nout < 2)
-			return;
-		q->quoted = 1;
-		q->nbytesout = 2;
-		q->nrunesout = 2;
-	}
-	for(; nin!=0; nin--){
-		if(s)
-			w = chartorune(&c, s);
-		else{
-			c = *r;
-			w = runelen(c);
-		}
-
-		if(c == '\0')
-			break;
-		if(runesout){
-			if(q->nrunesout+1 > nout)
-				break;
-		}else{
-			if(q->nbytesout+w > nout)
-				break;
-		}
-
-		if((c <= L' ') || (c == L'\'') || (fmtdoquote!=nil && fmtdoquote((int)c))){
-			if(!q->quoted){
-				if(runesout){
-					if(1+q->nrunesout+1+1 > nout)	/* no room for quotes */
-						break;
-				}else{
-					if(1+q->nbytesout+w+1 > nout)	/* no room for quotes */
-						break;
-				}
-				q->nrunesout += 2;	/* include quotes */
-				q->nbytesout += 2;	/* include quotes */
-				q->quoted = 1;
-			}
-			if(c == '\'')	{
-				if(runesout){
-					if(1+q->nrunesout+1 > nout)	/* no room for quotes */
-						break;
-				}else{
-					if(1+q->nbytesout+w > nout)	/* no room for quotes */
-						break;
-				}
-				q->nbytesout++;
-				q->nrunesout++;	/* quotes reproduce as two characters */
-			}
-		}
-
-		/* advance input */
-		if(s)
-			s += w;
-		else
-			r++;
-		q->nbytesin += w;
-		q->nrunesin++;
-
-		/* advance output */
-		q->nbytesout += w;
-		q->nrunesout++;
-
-#ifndef PLAN9PORT
-		/* ANSI requires precision in bytes, not Runes. */
-		nin-= w-1;	/* and then n-- in the loop */
-#endif
-	}
-}
-
-static int
-qstrfmt(char *sin, Rune *rin, Quoteinfo *q, Fmt *f)
-{
-	Rune r, *rm, *rme;
-	char *t, *s, *m, *me;
-	Rune *rt, *rs;
-	ulong fl;
-	int nc, w;
-
-	m = sin;
-	me = m + q->nbytesin;
-	rm = rin;
-	rme = rm + q->nrunesin;
-
-	fl = f->flags;
-	w = 0;
-	if(fl & FmtWidth)
-		w = f->width;
-	if(f->runes){
-		if(!(fl & FmtLeft) && __rfmtpad(f, w - q->nrunesout) < 0)
-			return -1;
-	}else{
-		if(!(fl & FmtLeft) && __fmtpad(f, w - q->nbytesout) < 0)
-			return -1;
-	}
-	t = (char*)f->to;
-	s = (char*)f->stop;
-	rt = (Rune*)f->to;
-	rs = (Rune*)f->stop;
-	if(f->runes)
-		FMTRCHAR(f, rt, rs, '\'');
-	else
-		FMTRUNE(f, t, s, '\'');
-	for(nc = q->nrunesin; nc > 0; nc--){
-		if(sin){
-			r = *(uchar*)m;
-			if(r < Runeself)
-				m++;
-			else if((me - m) >= UTFmax || fullrune(m, (int)(me-m)))
-				m += chartorune(&r, m);
-			else
-				break;
-		}else{
-			if(rm >= rme)
-				break;
-			r = *(uchar*)rm++;
-		}
-		if(f->runes){
-			FMTRCHAR(f, rt, rs, r);
-			if(r == '\'')
-				FMTRCHAR(f, rt, rs, r);
-		}else{
-			FMTRUNE(f, t, s, r);
-			if(r == '\'')
-				FMTRUNE(f, t, s, r);
-		}
-	}
-
-	if(f->runes){
-		FMTRCHAR(f, rt, rs, '\'');
-		USED(rs);
-		f->nfmt += (int)(rt - (Rune *)f->to);
-		f->to = rt;
-		if(fl & FmtLeft && __rfmtpad(f, w - q->nrunesout) < 0)
-			return -1;
-	}else{
-		FMTRUNE(f, t, s, '\'');
-		USED(s);
-		f->nfmt += (int)(t - (char *)f->to);
-		f->to = t;
-		if(fl & FmtLeft && __fmtpad(f, w - q->nbytesout) < 0)
-			return -1;
-	}
-	return 0;
-}
-
-int
-__quotestrfmt(int runesin, Fmt *f)
-{
-	int nin, outlen;
-	Rune *r;
-	char *s;
-	Quoteinfo q;
-
-	nin = -1;
-	if(f->flags&FmtPrec)
-		nin = f->prec;
-	if(runesin){
-		r = va_arg(f->args, Rune *);
-		s = nil;
-	}else{
-		s = va_arg(f->args, char *);
-		r = nil;
-	}
-	if(!s && !r)
-		return __fmtcpy(f, (void*)"<nil>", 5, 5);
-
-	if(f->flush)
-		outlen = 0x7FFFFFFF;	/* if we can flush, no output limit */
-	else if(f->runes)
-		outlen = (int)((Rune*)f->stop - (Rune*)f->to);
-	else
-		outlen = (int)((char*)f->stop - (char*)f->to);
-
-	__quotesetup(s, r, nin, outlen, &q, f->flags&FmtSharp, f->runes);
-/*print("bytes in %d bytes out %d runes in %d runesout %d\n", q.nbytesin, q.nbytesout, q.nrunesin, q.nrunesout); */
-
-	if(runesin){
-		if(!q.quoted)
-			return __fmtrcpy(f, r, q.nrunesin);
-		return qstrfmt(nil, r, &q, f);
-	}
-
-	if(!q.quoted)
-		return __fmtcpy(f, s, q.nrunesin, q.nbytesin);
-	return qstrfmt(s, nil, &q, f);
-}
-
-int
-quotestrfmt(Fmt *f)
-{
-	return __quotestrfmt(0, f);
-}
-
-int
-quoterunestrfmt(Fmt *f)
-{
-	return __quotestrfmt(1, f);
-}
-
-void
-quotefmtinstall(void)
-{
-	fmtinstall('q', quotestrfmt);
-	fmtinstall('Q', quoterunestrfmt);
-}
-
-int
-__needsquotes(char *s, int *quotelenp)
-{
-	Quoteinfo q;
-
-	__quotesetup(s, nil, -1, 0x7FFFFFFF, &q, 0, 0);
-	*quotelenp = q.nbytesout;
-
-	return q.quoted;
-}
-
-int
-__runeneedsquotes(Rune *r, int *quotelenp)
-{
-	Quoteinfo q;
-
-	__quotesetup(nil, r, -1, 0x7FFFFFFF, &q, 0, 0);
-	*quotelenp = q.nrunesout;
-
-	return q.quoted;
-}
diff --git a/src/lib9/fmt/fmtrune.c b/src/lib9/fmt/fmtrune.c
deleted file mode 100644
index 2bc8d28..0000000
--- a/src/lib9/fmt/fmtrune.c
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson,
- * with contributions from Mike Burrows and Sean Dorward.
- *
- *     Copyright (c) 2002-2006 by Lucent Technologies.
- *     Portions Copyright (c) 2004 Google Inc.
- * 
- * 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 
- * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING 
- * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
-
-#include <u.h>
-#include <libc.h>
-#include "fmtdef.h"
-
-int
-fmtrune(Fmt *f, int r)
-{
-	Rune *rt;
-	char *t;
-	int n;
-
-	if(f->runes){
-		rt = (Rune*)f->to;
-		FMTRCHAR(f, rt, f->stop, r);
-		f->to = rt;
-		n = 1;
-	}else{
-		t = (char*)f->to;
-		FMTRUNE(f, t, f->stop, (Rune)r);
-		n = (int)(t - (char*)f->to);
-		f->to = t;
-	}
-	f->nfmt += n;
-	return 0;
-}
diff --git a/src/lib9/fmt/fmtstr.c b/src/lib9/fmt/fmtstr.c
deleted file mode 100644
index a6ca772..0000000
--- a/src/lib9/fmt/fmtstr.c
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson,
- * with contributions from Mike Burrows and Sean Dorward.
- *
- *     Copyright (c) 2002-2006 by Lucent Technologies.
- *     Portions Copyright (c) 2004 Google Inc.
- * 
- * 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 
- * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING 
- * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
-
-#include <u.h>
-#include <libc.h>
-#include "fmtdef.h"
-
-char*
-fmtstrflush(Fmt *f)
-{
-	if(f->start == nil)
-		return nil;
-	*(char*)f->to = '\0';
-	f->to = f->start;
-	return (char*)f->start;
-}
diff --git a/src/lib9/fmt/fmtvprint.c b/src/lib9/fmt/fmtvprint.c
deleted file mode 100644
index f18d27b..0000000
--- a/src/lib9/fmt/fmtvprint.c
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson,
- * with contributions from Mike Burrows and Sean Dorward.
- *
- *     Copyright (c) 2002-2006 by Lucent Technologies.
- *     Portions Copyright (c) 2004 Google Inc.
- * 
- * 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 
- * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING 
- * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
-
-#include <u.h>
-#include <libc.h>
-#include "fmtdef.h"
-
-
-/*
- * Format a string into the output buffer.
- * Designed for formats which themselves call fmt.
- * Flags, precision and width are preserved.
- */
-int
-fmtvprint(Fmt *f, char *fmt, va_list args)
-{
-	va_list va;
-	int n, w, p;
-	unsigned long fl;
-
-	w = f->width;
-	p = f->prec;
-	fl = f->flags;
-	VA_COPY(va, f->args);
-	VA_END(f->args);
-	VA_COPY(f->args, args);
-	n = dofmt(f, fmt);
-	VA_END(f->args);
-	VA_COPY(f->args, va);
-	VA_END(va);
-	f->width = w;
-	f->prec = p;
-	f->flags = fl;
-	if(n >= 0)
-		return 0;
-	return n;
-}
diff --git a/src/lib9/fmt/fprint.c b/src/lib9/fmt/fprint.c
deleted file mode 100644
index 70cb138..0000000
--- a/src/lib9/fmt/fprint.c
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson,
- * with contributions from Mike Burrows and Sean Dorward.
- *
- *     Copyright (c) 2002-2006 by Lucent Technologies.
- *     Portions Copyright (c) 2004 Google Inc.
- * 
- * 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 
- * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING 
- * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
-
-#include <u.h>
-#include <libc.h>
-#include "fmtdef.h"
-
-int
-fprint(int fd, char *fmt, ...)
-{
-	int n;
-	va_list args;
-
-	va_start(args, fmt);
-	n = vfprint(fd, fmt, args);
-	va_end(args);
-	return n;
-}
diff --git a/src/lib9/fmt/nan64.c b/src/lib9/fmt/nan64.c
deleted file mode 100644
index 1ea7027..0000000
--- a/src/lib9/fmt/nan64.c
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson,
- * with contributions from Mike Burrows and Sean Dorward.
- *
- *     Copyright (c) 2002-2006 by Lucent Technologies.
- *     Portions Copyright (c) 2004 Google Inc.
- * 
- * 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 
- * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING 
- * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
-
-/*
- * 64-bit IEEE not-a-number routines.
- * This is big/little-endian portable assuming that
- * the 64-bit doubles and 64-bit integers have the
- * same byte ordering.
- */
-
-#include <u.h>
-#include <libc.h>
-#include "fmtdef.h"
-
-static uvlong uvnan    = ((uvlong)0x7FF00000<<32)|0x00000001;
-static uvlong uvinf    = ((uvlong)0x7FF00000<<32)|0x00000000;
-static uvlong uvneginf = ((uvlong)0xFFF00000<<32)|0x00000000;
-
-/* gcc sees through the obvious casts. */
-static uvlong
-d2u(double d)
-{
-	union {
-		uvlong v;
-		double d;
-	} u;
-	assert(sizeof(u.d) == sizeof(u.v));
-	u.d = d;
-	return u.v;
-}
-
-static double
-u2d(uvlong v)
-{
-	union {
-		uvlong v;
-		double d;
-	} u;
-	assert(sizeof(u.d) == sizeof(u.v));
-	u.v = v;
-	return u.d;
-}
-
-double
-__NaN(void)
-{
-	return u2d(uvnan);
-}
-
-int
-__isNaN(double d)
-{
-	uvlong x;
-
-	x = d2u(d);
-	/* IEEE 754: exponent bits 0x7FF and non-zero mantissa */
-	return (x&uvinf) == uvinf && (x&~uvneginf) != 0;
-}
-
-double
-__Inf(int sign)
-{
-	return u2d(sign < 0 ? uvneginf : uvinf);
-}
-
-int
-__isInf(double d, int sign)
-{
-	uvlong x;
-
-	x = d2u(d);
-	if(sign == 0)
-		return x==uvinf || x==uvneginf;
-	else if(sign > 0)
-		return x==uvinf;
-	else
-		return x==uvneginf;
-}
diff --git a/src/lib9/fmt/pow10.c b/src/lib9/fmt/pow10.c
deleted file mode 100644
index e146884..0000000
--- a/src/lib9/fmt/pow10.c
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson,
- * with contributions from Mike Burrows and Sean Dorward.
- *
- *     Copyright (c) 2002-2006 by Lucent Technologies.
- *     Portions Copyright (c) 2004 Google Inc.
- * 
- * 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 
- * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING 
- * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
-
-#include <u.h>
-#include <libc.h>
-#include "fmtdef.h"
-
-/*
- * this table might overflow 127-bit exponent representations.
- * in that case, truncate it after 1.0e38.
- * it is important to get all one can from this
- * routine since it is used in atof to scale numbers.
- * the presumption is that C converts fp numbers better
- * than multipication of lower powers of 10.
- */
-
-static
-double	tab[] =
-{
-	1.0e0, 1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5, 1.0e6, 1.0e7, 1.0e8, 1.0e9,
-	1.0e10,1.0e11,1.0e12,1.0e13,1.0e14,1.0e15,1.0e16,1.0e17,1.0e18,1.0e19,
-	1.0e20,1.0e21,1.0e22,1.0e23,1.0e24,1.0e25,1.0e26,1.0e27,1.0e28,1.0e29,
-	1.0e30,1.0e31,1.0e32,1.0e33,1.0e34,1.0e35,1.0e36,1.0e37,1.0e38,1.0e39,
-	1.0e40,1.0e41,1.0e42,1.0e43,1.0e44,1.0e45,1.0e46,1.0e47,1.0e48,1.0e49,
-	1.0e50,1.0e51,1.0e52,1.0e53,1.0e54,1.0e55,1.0e56,1.0e57,1.0e58,1.0e59,
-	1.0e60,1.0e61,1.0e62,1.0e63,1.0e64,1.0e65,1.0e66,1.0e67,1.0e68,1.0e69,
-};
-
-double
-__fmtpow10(int n)
-{
-	int m;
-
-	if(n < 0) {
-		n = -n;
-		if(n < (int)(sizeof(tab)/sizeof(tab[0])))
-			return 1/tab[n];
-		m = n/2;
-		return __fmtpow10(-m) * __fmtpow10(m-n);
-	}
-	if(n < (int)(sizeof(tab)/sizeof(tab[0])))
-		return tab[n];
-	m = n/2;
-	return __fmtpow10(m) * __fmtpow10(n-m);
-}
diff --git a/src/lib9/fmt/print.c b/src/lib9/fmt/print.c
deleted file mode 100644
index 5c39457..0000000
--- a/src/lib9/fmt/print.c
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson,
- * with contributions from Mike Burrows and Sean Dorward.
- *
- *     Copyright (c) 2002-2006 by Lucent Technologies.
- *     Portions Copyright (c) 2004 Google Inc.
- * 
- * 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 
- * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING 
- * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
-
-#include <u.h>
-#include <libc.h>
-#include "fmtdef.h"
-
-int
-print(char *fmt, ...)
-{
-	int n;
-	va_list args;
-
-	va_start(args, fmt);
-	n = vfprint(1, fmt, args);
-	va_end(args);
-	return n;
-}
diff --git a/src/lib9/fmt/seprint.c b/src/lib9/fmt/seprint.c
deleted file mode 100644
index 88779d9..0000000
--- a/src/lib9/fmt/seprint.c
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson,
- * with contributions from Mike Burrows and Sean Dorward.
- *
- *     Copyright (c) 2002-2006 by Lucent Technologies.
- *     Portions Copyright (c) 2004 Google Inc.
- * 
- * 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 
- * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING 
- * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
-
-#include <u.h>
-#include <libc.h>
-#include "fmtdef.h"
-
-char*
-seprint(char *buf, char *e, char *fmt, ...)
-{
-	char *p;
-	va_list args;
-
-	va_start(args, fmt);
-	p = vseprint(buf, e, fmt, args);
-	va_end(args);
-	return p;
-}
diff --git a/src/lib9/fmt/smprint.c b/src/lib9/fmt/smprint.c
deleted file mode 100644
index c13ffd7..0000000
--- a/src/lib9/fmt/smprint.c
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson,
- * with contributions from Mike Burrows and Sean Dorward.
- *
- *     Copyright (c) 2002-2006 by Lucent Technologies.
- *     Portions Copyright (c) 2004 Google Inc.
- * 
- * 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 
- * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING 
- * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
-
-#include <u.h>
-#include <libc.h>
-#include "fmtdef.h"
-
-char*
-smprint(char *fmt, ...)
-{
-	va_list args;
-	char *p;
-
-	va_start(args, fmt);
-	p = vsmprint(fmt, args);
-	va_end(args);
-	return p;
-}
diff --git a/src/lib9/fmt/snprint.c b/src/lib9/fmt/snprint.c
deleted file mode 100644
index 372399c..0000000
--- a/src/lib9/fmt/snprint.c
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson,
- * with contributions from Mike Burrows and Sean Dorward.
- *
- *     Copyright (c) 2002-2006 by Lucent Technologies.
- *     Portions Copyright (c) 2004 Google Inc.
- * 
- * 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 
- * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING 
- * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
-
-#include <u.h>
-#include <libc.h>
-#include "fmtdef.h"
-
-int
-snprint(char *buf, int len, char *fmt, ...)
-{
-	int n;
-	va_list args;
-
-	va_start(args, fmt);
-	n = vsnprint(buf, len, fmt, args);
-	va_end(args);
-	return n;
-}
-
diff --git a/src/lib9/fmt/sprint.c b/src/lib9/fmt/sprint.c
deleted file mode 100644
index 02655ad..0000000
--- a/src/lib9/fmt/sprint.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson,
- * with contributions from Mike Burrows and Sean Dorward.
- *
- *     Copyright (c) 2002-2006 by Lucent Technologies.
- *     Portions Copyright (c) 2004 Google Inc.
- * 
- * 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 
- * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING 
- * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
-
-#include <u.h>
-#include <libc.h>
-#include "fmtdef.h"
-
-int
-sprint(char *buf, char *fmt, ...)
-{
-	int n;
-	uint len;
-	va_list args;
-
-	len = 1<<30;  /* big number, but sprint is deprecated anyway */
-	/*
-	 * on PowerPC, the stack is near the top of memory, so
-	 * we must be sure not to overflow a 32-bit pointer.
-	 *
-	 * careful!  gcc-4.2 assumes buf+len < buf can never be true and
-	 * optimizes the test away.  casting to uintptr works around this bug.
-	 */
-	if((uintptr)buf+len < (uintptr)buf)
-		len = (uint)-(uintptr)buf-1;
-
-	va_start(args, fmt);
-	n = (int)vsnprint(buf, (int)len, fmt, args);
-	va_end(args);
-	return n;
-}
diff --git a/src/lib9/fmt/strtod.c b/src/lib9/fmt/strtod.c
deleted file mode 100644
index ec185d2..0000000
--- a/src/lib9/fmt/strtod.c
+++ /dev/null
@@ -1,533 +0,0 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson,
- * with contributions from Mike Burrows and Sean Dorward.
- *
- *     Copyright (c) 2002-2006 by Lucent Technologies.
- *     Portions Copyright (c) 2004 Google Inc.
- * 
- * 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 
- * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING 
- * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
-
-#include <u.h>
-#include <errno.h>
-#include <libc.h>
-#include "fmtdef.h"
-
-static ulong
-umuldiv(ulong a, ulong b, ulong c)
-{
-	double d;
-
-	d = ((double)a * (double)b) / (double)c;
-	if(d >= 4294967295.)
-		d = 4294967295.;
-	return (ulong)d;
-}
-
-/*
- * This routine will convert to arbitrary precision
- * floating point entirely in multi-precision fixed.
- * The answer is the closest floating point number to
- * the given decimal number. Exactly half way are
- * rounded ala ieee rules.
- * Method is to scale input decimal between .500 and .999...
- * with external power of 2, then binary search for the
- * closest mantissa to this decimal number.
- * Nmant is is the required precision. (53 for ieee dp)
- * Nbits is the max number of bits/word. (must be <= 28)
- * Prec is calculated - the number of words of fixed mantissa.
- */
-enum
-{
-	Nbits	= 28,				/* bits safely represented in a ulong */
-	Nmant	= 53,				/* bits of precision required */
-	Prec	= (Nmant+Nbits+1)/Nbits,	/* words of Nbits each to represent mantissa */
-	Sigbit	= 1<<(Prec*Nbits-Nmant),	/* first significant bit of Prec-th word */
-	Ndig	= 1500,
-	One	= (ulong)(1<<Nbits),
-	Half	= (ulong)(One>>1),
-	Maxe	= 310,
-
-	Fsign	= 1<<0,		/* found - */
-	Fesign	= 1<<1,		/* found e- */
-	Fdpoint	= 1<<2,		/* found . */
-
-	S0	= 0,		/* _		_S0	+S1	#S2	.S3 */
-	S1,			/* _+		#S2	.S3 */
-	S2,			/* _+#		#S2	.S4	eS5 */
-	S3,			/* _+.		#S4 */
-	S4,			/* _+#.#	#S4	eS5 */
-	S5,			/* _+#.#e	+S6	#S7 */
-	S6,			/* _+#.#e+	#S7 */
-	S7			/* _+#.#e+#	#S7 */
-};
-
-static	int	xcmp(char*, char*);
-static	int	fpcmp(char*, ulong*);
-static	void	frnorm(ulong*);
-static	void	divascii(char*, int*, int*, int*);
-static	void	mulascii(char*, int*, int*, int*);
-
-typedef	struct	Tab	Tab;
-struct	Tab
-{
-	int	bp;
-	int	siz;
-	char*	cmp;
-};
-
-double
-fmtstrtod(const char *as, char **aas)
-{
-	int na, ex, dp, bp, c, i, flag, state;
-	ulong low[Prec], hig[Prec], mid[Prec];
-	double d;
-	char *s, a[Ndig];
-
-	flag = 0;	/* Fsign, Fesign, Fdpoint */
-	na = 0;		/* number of digits of a[] */
-	dp = 0;		/* na of decimal point */
-	ex = 0;		/* exonent */
-
-	state = S0;
-	for(s=(char*)as;; s++) {
-		c = *s;
-		if(c >= '0' && c <= '9') {
-			switch(state) {
-			case S0:
-			case S1:
-			case S2:
-				state = S2;
-				break;
-			case S3:
-			case S4:
-				state = S4;
-				break;
-
-			case S5:
-			case S6:
-			case S7:
-				state = S7;
-				ex = ex*10 + (c-'0');
-				continue;
-			}
-			if(na == 0 && c == '0') {
-				dp--;
-				continue;
-			}
-			if(na < Ndig-50)
-				a[na++] = (char)c;
-			continue;
-		}
-		switch(c) {
-		case '\t':
-		case '\n':
-		case '\v':
-		case '\f':
-		case '\r':
-		case ' ':
-			if(state == S0)
-				continue;
-			break;
-		case '-':
-			if(state == S0)
-				flag |= Fsign;
-			else
-				flag |= Fesign;
-		case '+':
-			if(state == S0)
-				state = S1;
-			else
-			if(state == S5)
-				state = S6;
-			else
-				break;	/* syntax */
-			continue;
-		case '.':
-			flag |= Fdpoint;
-			dp = na;
-			if(state == S0 || state == S1) {
-				state = S3;
-				continue;
-			}
-			if(state == S2) {
-				state = S4;
-				continue;
-			}
-			break;
-		case 'e':
-		case 'E':
-			if(state == S2 || state == S4) {
-				state = S5;
-				continue;
-			}
-			break;
-		}
-		break;
-	}
-
-	/*
-	 * clean up return char-pointer
-	 */
-	switch(state) {
-	case S0:
-		if(xcmp(s, "nan") == 0) {
-			if(aas != nil)
-				*aas = s+3;
-			goto retnan;
-		}
-	case S1:
-		if(xcmp(s, "infinity") == 0) {
-			if(aas != nil)
-				*aas = s+8;
-			goto retinf;
-		}
-		if(xcmp(s, "inf") == 0) {
-			if(aas != nil)
-				*aas = s+3;
-			goto retinf;
-		}
-	case S3:
-		if(aas != nil)
-			*aas = (char*)as;
-		goto ret0;	/* no digits found */
-	case S6:
-		s--;		/* back over +- */
-	case S5:
-		s--;		/* back over e */
-		break;
-	}
-	if(aas != nil)
-		*aas = s;
-
-	if(flag & Fdpoint)
-	while(na > 0 && a[na-1] == '0')
-		na--;
-	if(na == 0)
-		goto ret0;	/* zero */
-	a[na] = 0;
-	if(!(flag & Fdpoint))
-		dp = na;
-	if(flag & Fesign)
-		ex = -ex;
-	dp += ex;
-	if(dp < -Maxe){
-		errno = ERANGE;
-		goto ret0;	/* underflow by exp */
-	} else
-	if(dp > +Maxe)
-		goto retinf;	/* overflow by exp */
-
-	/*
-	 * normalize the decimal ascii number
-	 * to range .[5-9][0-9]* e0
-	 */
-	bp = 0;		/* binary exponent */
-	while(dp > 0)
-		divascii(a, &na, &dp, &bp);
-	while(dp < 0 || a[0] < '5')
-		mulascii(a, &na, &dp, &bp);
-
-	/* close approx by naive conversion */
-	mid[0] = 0;
-	mid[1] = 1;
-	for(i=0; (c=a[i]) != '\0'; i++) {
-		mid[0] = mid[0]*10 + (ulong)(c-'0');
-		mid[1] = mid[1]*10;
-		if(i >= 8)
-			break;
-	}
-	low[0] = umuldiv(mid[0], One, mid[1]);
-	hig[0] = umuldiv(mid[0]+1, One, mid[1]);
-	for(i=1; i<Prec; i++) {
-		low[i] = 0;
-		hig[i] = One-1;
-	}
-
-	/* binary search for closest mantissa */
-	for(;;) {
-		/* mid = (hig + low) / 2 */
-		c = 0;
-		for(i=0; i<Prec; i++) {
-			mid[i] = hig[i] + low[i];
-			if(c)
-				mid[i] += One;
-			c = mid[i] & 1;
-			mid[i] >>= 1;
-		}
-		frnorm(mid);
-
-		/* compare */
-		c = fpcmp(a, mid);
-		if(c > 0) {
-			c = 1;
-			for(i=0; i<Prec; i++)
-				if(low[i] != mid[i]) {
-					c = 0;
-					low[i] = mid[i];
-				}
-			if(c)
-				break;	/* between mid and hig */
-			continue;
-		}
-		if(c < 0) {
-			for(i=0; i<Prec; i++)
-				hig[i] = mid[i];
-			continue;
-		}
-
-		/* only hard part is if even/odd roundings wants to go up */
-		c = mid[Prec-1] & (Sigbit-1);
-		if(c == Sigbit/2 && (mid[Prec-1]&Sigbit) == 0)
-			mid[Prec-1] -= (ulong)c;
-		break;	/* exactly mid */
-	}
-
-	/* normal rounding applies */
-	c = mid[Prec-1] & (Sigbit-1);
-	mid[Prec-1] -= (ulong)c;
-	if(c >= Sigbit/2) {
-		mid[Prec-1] += Sigbit;
-		frnorm(mid);
-	}
-	goto out;
-
-ret0:
-	return 0;
-
-retnan:
-	return __NaN();
-
-retinf:
-	/*
-	 * Unix strtod requires these.  Plan 9 would return Inf(0) or Inf(-1). */
-	errno = ERANGE;
-	if(flag & Fsign)
-		return -HUGE_VAL;
-	return HUGE_VAL;
-
-out:
-	d = 0;
-	for(i=0; i<Prec; i++)
-		d = d*One + (double)mid[i];
-	if(flag & Fsign)
-		d = -d;
-	d = ldexp(d, bp - Prec*Nbits);
-	if(d == 0){	/* underflow */
-		errno = ERANGE;
-	}
-	return d;
-}
-
-static void
-frnorm(ulong *f)
-{
-	int i;
-	ulong c;
-
-	c = 0;
-	for(i=Prec-1; i>0; i--) {
-		f[i] += c;
-		c = f[i] >> Nbits;
-		f[i] &= One-1;
-	}
-	f[0] += c;
-}
-
-static int
-fpcmp(char *a, ulong* f)
-{
-	ulong tf[Prec];
-	int i, d, c;
-
-	for(i=0; i<Prec; i++)
-		tf[i] = f[i];
-
-	for(;;) {
-		/* tf *= 10 */
-		for(i=0; i<Prec; i++)
-			tf[i] = tf[i]*10;
-		frnorm(tf);
-		d = (int)(tf[0] >> Nbits) + '0';
-		tf[0] &= One-1;
-
-		/* compare next digit */
-		c = *a;
-		if(c == 0) {
-			if('0' < d)
-				return -1;
-			if(tf[0] != 0)
-				goto cont;
-			for(i=1; i<Prec; i++)
-				if(tf[i] != 0)
-					goto cont;
-			return 0;
-		}
-		if(c > d)
-			return +1;
-		if(c < d)
-			return -1;
-		a++;
-	cont:;
-	}
-}
-
-static void
-divby(char *a, int *na, int b)
-{
-	int n, c;
-	char *p;
-
-	p = a;
-	n = 0;
-	while(n>>b == 0) {
-		c = *a++;
-		if(c == 0) {
-			while(n) {
-				c = n*10;
-				if(c>>b)
-					break;
-				n = c;
-			}
-			goto xx;
-		}
-		n = n*10 + c-'0';
-		(*na)--;
-	}
-	for(;;) {
-		c = n>>b;
-		n -= c<<b;
-		*p++ = (char)(c + '0');
-		c = *a++;
-		if(c == 0)
-			break;
-		n = n*10 + c-'0';
-	}
-	(*na)++;
-xx:
-	while(n) {
-		n = n*10;
-		c = n>>b;
-		n -= c<<b;
-		*p++ = (char)(c + '0');
-		(*na)++;
-	}
-	*p = 0;
-}
-
-static	Tab	tab1[] =
-{
-	 1,  0, "",
-	 3,  1, "7",
-	 6,  2, "63",
-	 9,  3, "511",
-	13,  4, "8191",
-	16,  5, "65535",
-	19,  6, "524287",
-	23,  7, "8388607",
-	26,  8, "67108863",
-	27,  9, "134217727",
-};
-
-static void
-divascii(char *a, int *na, int *dp, int *bp)
-{
-	int b, d;
-	Tab *t;
-
-	d = *dp;
-	if(d >= (int)(nelem(tab1)))
-		d = (int)(nelem(tab1))-1;
-	t = tab1 + d;
-	b = t->bp;
-	if(memcmp(a, t->cmp, (size_t)t->siz) > 0)
-		d--;
-	*dp -= d;
-	*bp += b;
-	divby(a, na, b);
-}
-
-static void
-mulby(char *a, char *p, char *q, int b)
-{
-	int n, c;
-
-	n = 0;
-	*p = 0;
-	for(;;) {
-		q--;
-		if(q < a)
-			break;
-		c = *q - '0';
-		c = (c<<b) + n;
-		n = c/10;
-		c -= n*10;
-		p--;
-		*p = (char)(c + '0');
-	}
-	while(n) {
-		c = n;
-		n = c/10;
-		c -= n*10;
-		p--;
-		*p = (char)(c + '0');
-	}
-}
-
-static	Tab	tab2[] =
-{
-	 1,  1, "",				/* dp = 0-0 */
-	 3,  3, "125",
-	 6,  5, "15625",
-	 9,  7, "1953125",
-	13, 10, "1220703125",
-	16, 12, "152587890625",
-	19, 14, "19073486328125",
-	23, 17, "11920928955078125",
-	26, 19, "1490116119384765625",
-	27, 19, "7450580596923828125",		/* dp 8-9 */
-};
-
-static void
-mulascii(char *a, int *na, int *dp, int *bp)
-{
-	char *p;
-	int d, b;
-	Tab *t;
-
-	d = -*dp;
-	if(d >= (int)(nelem(tab2)))
-		d = (int)(nelem(tab2))-1;
-	t = tab2 + d;
-	b = t->bp;
-	if(memcmp(a, t->cmp, (size_t)t->siz) < 0)
-		d--;
-	p = a + *na;
-	*bp -= b;
-	*dp += d;
-	*na += d;
-	mulby(a, p+d, p, b);
-}
-
-static int
-xcmp(char *a, char *b)
-{
-	int c1, c2;
-
-	while((c1 = *b++) != '\0') {
-		c2 = *a++;
-		if(isupper(c2))
-			c2 = tolower(c2);
-		if(c1 != c2)
-			return 1;
-	}
-	return 0;
-}
diff --git a/src/lib9/fmt/test.c b/src/lib9/fmt/test.c
deleted file mode 100644
index d82ff78..0000000
--- a/src/lib9/fmt/test.c
+++ /dev/null
@@ -1,67 +0,0 @@
-// +build ignore
-
-/*
- * The authors of this software are Rob Pike and Ken Thompson,
- * with contributions from Mike Burrows and Sean Dorward.
- *
- *     Copyright (c) 2002-2006 by Lucent Technologies.
- *     Portions Copyright (c) 2004 Google Inc.
- * 
- * 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 
- * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING 
- * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
-
-#include <u.h>
-#include <libc.h>
-#include "fmtdef.h"
-
-int
-main(int argc, char *argv[])
-{
-	quotefmtinstall();
-	print("hello world\n");
-	print("x: %x\n", 0x87654321);
-	print("u: %u\n", 0x87654321);
-	print("d: %d\n", 0x87654321);
-	print("s: %s\n", "hi there");
-	print("q: %q\n", "hi i'm here");
-	print("c: %c\n", '!');
-	print("g: %g %g %g\n", 3.14159, 3.14159e10, 3.14159e-10);
-	print("e: %e %e %e\n", 3.14159, 3.14159e10, 3.14159e-10);
-	print("f: %f %f %f\n", 3.14159, 3.14159e10, 3.14159e-10);
-	print("smiley: %C\n", (Rune)0x263a);
-	print("%g %.18g\n", 2e25, 2e25);
-	print("%2.18g\n", 1.0);
-	print("%2.18f\n", 1.0);
-	print("%f\n", 3.1415927/4);
-	print("%d\n", 23);
-	print("%i\n", 23);
-	print("%0.10d\n", 12345);
-
-	/* test %4$d formats */
-	print("%3$d %4$06d %2$d %1$d\n", 444, 333, 111, 222);
-	print("%3$d %4$06d %2$d %1$d\n", 444, 333, 111, 222);
-	print("%3$d %4$*5$06d %2$d %1$d\n", 444, 333, 111, 222, 20);
-	print("%3$hd %4$*5$06d %2$d %1$d\n", 444, 333, (short)111, 222, 20);
-	print("%3$lld %4$*5$06d %2$d %1$d\n", 444, 333, 111LL, 222, 20);
-
-	/* test %'d formats */
-	print("%'d %'d %'d\n", 1, 2222, 33333333);
-	print("%'019d\n", 0);
-	print("%08d %08d %08d\n", 1, 2222, 33333333);
-	print("%'08d %'08d %'08d\n", 1, 2222, 33333333);
-	print("%'x %'X %'b\n", 0x11111111, 0xabcd1234, 12345);
-	print("%'lld %'lld %'lld\n", 1LL, 222222222LL, 3333333333333LL);
-	print("%019lld %019lld %019lld\n", 1LL, 222222222LL, 3333333333333LL);
-	print("%'019lld %'019lld %'019lld\n", 1LL, 222222222LL, 3333333333333LL);
-	print("%'020lld %'020lld %'020lld\n", 1LL, 222222222LL, 3333333333333LL);
-	print("%'llx %'llX %'llb\n", 0x111111111111LL, 0xabcd12345678LL, 112342345LL);
-	return 0;
-}
diff --git a/src/lib9/fmt/vfprint.c b/src/lib9/fmt/vfprint.c
deleted file mode 100644
index a23c5a0..0000000
--- a/src/lib9/fmt/vfprint.c
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson,
- * with contributions from Mike Burrows and Sean Dorward.
- *
- *     Copyright (c) 2002-2006 by Lucent Technologies.
- *     Portions Copyright (c) 2004 Google Inc.
- * 
- * 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 
- * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING 
- * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
-
-#include <u.h>
-#include <libc.h>
-#include "fmtdef.h"
-
-int
-vfprint(int fd, char *fmt, va_list args)
-{
-	Fmt f;
-	char buf[256];
-	int n;
-
-	fmtfdinit(&f, fd, buf, sizeof(buf));
-	VA_COPY(f.args,args);
-	n = dofmt(&f, fmt);
-	VA_END(f.args);
-	if(n > 0 && __fmtFdFlush(&f) == 0)
-		return -1;
-	return n;
-}
diff --git a/src/lib9/fmt/vseprint.c b/src/lib9/fmt/vseprint.c
deleted file mode 100644
index c9fbfb9..0000000
--- a/src/lib9/fmt/vseprint.c
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson,
- * with contributions from Mike Burrows and Sean Dorward.
- *
- *     Copyright (c) 2002-2006 by Lucent Technologies.
- *     Portions Copyright (c) 2004 Google Inc.
- * 
- * 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 
- * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING 
- * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
-
-#include <u.h>
-#include <libc.h>
-#include "fmtdef.h"
-
-char*
-vseprint(char *buf, char *e, char *fmt, va_list args)
-{
-	Fmt f;
-
-	if(e <= buf)
-		return nil;
-	f.runes = 0;
-	f.start = buf;
-	f.to = buf;
-	f.stop = e - 1;
-	f.flush = 0;
-	f.farg = nil;
-	f.nfmt = 0;
-	VA_COPY(f.args,args);
-	fmtlocaleinit(&f, nil, nil, nil);
-	dofmt(&f, fmt);
-	VA_END(f.args);
-	*(char*)f.to = '\0';
-	return (char*)f.to;
-}
-
diff --git a/src/lib9/fmt/vsmprint.c b/src/lib9/fmt/vsmprint.c
deleted file mode 100644
index 46086f9..0000000
--- a/src/lib9/fmt/vsmprint.c
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson,
- * with contributions from Mike Burrows and Sean Dorward.
- *
- *     Copyright (c) 2002-2006 by Lucent Technologies.
- *     Portions Copyright (c) 2004 Google Inc.
- * 
- * 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 
- * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING 
- * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
-
-#include <u.h>
-#include <libc.h>
-#include "fmtdef.h"
-
-static int
-fmtStrFlush(Fmt *f)
-{
-	char *s;
-	int n;
-
-	if(f->start == nil)
-		return 0;
-	n = (int)(uintptr)f->farg;
-	n *= 2;
-	s = (char*)f->start;
-	f->start = realloc(s, (size_t)n);
-	if(f->start == nil){
-		f->farg = nil;
-		f->to = nil;
-		f->stop = nil;
-		free(s);
-		return 0;
-	}
-	f->farg = (void*)(uintptr)n;
-	f->to = (char*)f->start + ((char*)f->to - s);
-	f->stop = (char*)f->start + n - 1;
-	return 1;
-}
-
-int
-fmtstrinit(Fmt *f)
-{
-	int n;
-
-	memset(f, 0, sizeof *f);
-	f->runes = 0;
-	n = 32;
-	f->start = malloc((size_t)n);
-	if(f->start == nil)
-		return -1;
-	f->to = f->start;
-	f->stop = (char*)f->start + n - 1;
-	f->flush = fmtStrFlush;
-	f->farg = (void*)(uintptr)n;
-	f->nfmt = 0;
-	fmtlocaleinit(f, nil, nil, nil);
-	return 0;
-}
-
-/*
- * print into an allocated string buffer
- */
-char*
-vsmprint(char *fmt, va_list args)
-{
-	Fmt f;
-	int n;
-
-	if(fmtstrinit(&f) < 0)
-		return nil;
-	VA_COPY(f.args,args);
-	n = dofmt(&f, fmt);
-	VA_END(f.args);
-	if(n < 0){
-		free(f.start);
-		return nil;
-	}
-	return fmtstrflush(&f);
-}
diff --git a/src/lib9/fmt/vsnprint.c b/src/lib9/fmt/vsnprint.c
deleted file mode 100644
index 6b38772..0000000
--- a/src/lib9/fmt/vsnprint.c
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson,
- * with contributions from Mike Burrows and Sean Dorward.
- *
- *     Copyright (c) 2002-2006 by Lucent Technologies.
- *     Portions Copyright (c) 2004 Google Inc.
- * 
- * 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 
- * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING 
- * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
-
-#include <u.h>
-#include <libc.h>
-#include "fmtdef.h"
-
-int
-vsnprint(char *buf, int len, char *fmt, va_list args)
-{
-	Fmt f;
-
-	if(len <= 0)
-		return -1;
-	f.runes = 0;
-	f.start = buf;
-	f.to = buf;
-	f.stop = buf + len - 1;
-	f.flush = 0;
-	f.farg = nil;
-	f.nfmt = 0;
-	VA_COPY(f.args,args);
-	fmtlocaleinit(&f, nil, nil, nil);
-	dofmt(&f, fmt);
-	VA_END(f.args);
-	*(char*)f.to = '\0';
-	return (int)((char*)f.to - buf);
-}
diff --git a/src/lib9/fmtlock2.c b/src/lib9/fmtlock2.c
deleted file mode 100644
index a0e2636..0000000
--- a/src/lib9/fmtlock2.c
+++ /dev/null
@@ -1,40 +0,0 @@
-// +build !plan9
-
-/*
-Plan 9 from User Space src/lib9/fmtlock2.c
-http://code.swtch.com/plan9port/src/tip/src/lib9/fmtlock2.c
-
-Copyright 2001-2007 Russ Cox.  All Rights Reserved.
-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.
-*/
-
-#include <u.h>
-#include <libc.h>
-
-void
-__fmtlock(void)
-{
-}
-
-void
-__fmtunlock(void)
-{
-}
diff --git a/src/lib9/getenv.c b/src/lib9/getenv.c
deleted file mode 100644
index 2454b6b..0000000
--- a/src/lib9/getenv.c
+++ /dev/null
@@ -1,52 +0,0 @@
-// +build !plan9
-
-/*
-Plan 9 from User Space src/lib9/getenv.c
-http://code.swtch.com/plan9port/src/tip/src/lib9/getenv.c
-
-Copyright 2001-2007 Russ Cox.  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.
-*/
-#include <u.h>
-#define NOPLAN9DEFINES
-#include <libc.h>
-
-char*
-p9getenv(char *s)
-{
-	char *t;
-
-	t = getenv(s);
-	if(t == 0)
-		return 0;
-	return strdup(t);
-}
-
-int
-p9putenv(char *s, char *v)
-{
-	char *t;
-
-	t = smprint("%s=%s", s, v);
-	if(t == nil)
-		return -1;
-	putenv(t);
-	return 0;
-}
diff --git a/src/lib9/getfields.c b/src/lib9/getfields.c
deleted file mode 100644
index 0af8388..0000000
--- a/src/lib9/getfields.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
-Inferno libkern/getfields.c
-http://code.google.com/p/inferno-os/source/browse/libkern/getfields.c
-
-	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  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.
-*/
-
-#include <u.h>
-#include <libc.h>
-
-int
-getfields(char *str, char **args, int max, int mflag, char *set)
-{
-	Rune r;
-	int nr, intok, narg;
-
-	if(max <= 0)
-		return 0;
-
-	narg = 0;
-	args[narg] = str;
-	if(!mflag)
-		narg++;
-	intok = 0;
-	for(;; str += nr) {
-		nr = chartorune(&r, str);
-		if(r == 0)
-			break;
-		if(utfrune(set, r)) {
-			if(narg >= max)
-				break;
-			*str = 0;
-			intok = 0;
-			args[narg] = str + nr;
-			if(!mflag)
-				narg++;
-		} else {
-			if(!intok && mflag)
-				narg++;
-			intok = 1;
-		}
-	}
-	return narg;
-}
diff --git a/src/lib9/getwd.c b/src/lib9/getwd.c
deleted file mode 100644
index 03a8ff1..0000000
--- a/src/lib9/getwd.c
+++ /dev/null
@@ -1,56 +0,0 @@
-// +build !plan9
-
-/*
-Plan 9 from User Space src/lib9/getwd.c
-http://code.swtch.com/plan9port/src/tip/src/lib9/getwd.c
-
-Copyright 2001-2007 Russ Cox.  All Rights Reserved.
-Portions Copyright 2011 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.
-*/
-#include <u.h>
-#include <errno.h>
-#include <sys/stat.h>
-#define NOPLAN9DEFINES
-#include <libc.h>
-
-char*
-p9getwd(char *s, int ns)
-{
-	char *pwd;
-	struct stat st1, st2;
-
-	// Clumsy but widespread kludge:
-	// if $PWD is set and matches ".", use it.
-	// Matches glibc's get_current_dir_name and Go's os.Getwd.
-	pwd = getenv("PWD");  // note: getenv, not p9getenv, so no free
-	if(pwd != nil && pwd[0] &&
-			stat(pwd, &st1) >= 0 && stat(".", &st2) >= 0 &&
-			st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino) {
-		if(strlen(pwd) >= ns) {
-			errno = ERANGE;
-			return nil;
-		}
-		strcpy(s, pwd);
-		return s;
-	}
-
-	return getcwd(s, (size_t)ns);
-}
diff --git a/src/lib9/goos.c b/src/lib9/goos.c
deleted file mode 100644
index 2d4a800..0000000
--- a/src/lib9/goos.c
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2010 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 <u.h>
-#include <libc.h>
-
-static char*
-defgetenv(char *name, char *def)
-{
-	char *p;
-	
-	p = getenv(name);
-	if(p == nil || p[0] == '\0')
-		p = def;
-	return p;
-}
-
-char*
-getgoos(void)
-{
-	return defgetenv("GOOS", GOOS);
-}
-
-char*
-getgoarch(void)
-{
-	return defgetenv("GOARCH", GOARCH);
-}
-
-char*
-getgoroot(void)
-{
-	return defgetenv("GOROOT", GOROOT);
-}
-
-char*
-getgoversion(void)
-{
-	return GOVERSION;
-}
-
-char*
-getgoarm(void)
-{
-	return defgetenv("GOARM", GOARM);
-}
-
-char*
-getgo386(void)
-{
-	return defgetenv("GO386", GO386);
-}
-
-char *
-getgoextlinkenabled(void)
-{
-	return GO_EXTLINK_ENABLED;
-}
diff --git a/src/lib9/jmp.c b/src/lib9/jmp.c
deleted file mode 100644
index 733ed70..0000000
--- a/src/lib9/jmp.c
+++ /dev/null
@@ -1,45 +0,0 @@
-// +build !plan9
-// +build !windows
-
-/*
-Plan 9 from User Space src/lib9/jmp.c
-http://code.swtch.com/plan9port/src/tip/src/lib9/jmp.c
-
-Copyright 2001-2007 Russ Cox.  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.
-*/
-
-#include <u.h>
-#define NOPLAN9DEFINES
-#include <libc.h>
-
-void
-p9longjmp(p9jmp_buf buf, int val)
-{
-	siglongjmp((void*)buf, val);
-}
-
-void
-p9notejmp(void *x, p9jmp_buf buf, int val)
-{
-	USED(x);
-	siglongjmp((void*)buf, val);
-}
-
diff --git a/src/lib9/main.c b/src/lib9/main.c
deleted file mode 100644
index 088b095..0000000
--- a/src/lib9/main.c
+++ /dev/null
@@ -1,60 +0,0 @@
-// +build !plan9
-
-/*
-Plan 9 from User Space src/lib9/main.c
-http://code.swtch.com/plan9port/src/tip/src/lib9/main.c
-
-Copyright 2001-2007 Russ Cox.  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.
-*/
-
-#include <u.h>
-#define NOPLAN9DEFINES
-#include <libc.h>
-
-#ifdef WIN32
-#include <windows.h>
-
-static void
-crashhandler(int sig)
-{
-	USED(sig);
-	fprint(2, "%s: internal fatal error.\n", argv0);
-	exit(1);
-}
-#endif
-
-extern void p9main(int, char**);
-
-int
-main(int argc, char **argv)
-{
-#ifdef WIN32
-	signal(SIGSEGV, crashhandler);
-	signal(SIGBUS, crashhandler);
-	// don't display the crash dialog
-	DWORD mode = SetErrorMode(SEM_NOGPFAULTERRORBOX);
-	SetErrorMode(mode | SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX);
-#endif
-	argv0 = argv[0];
-	p9main(argc, argv);
-	exits("main");
-	return 99;
-}
diff --git a/src/lib9/nan.c b/src/lib9/nan.c
deleted file mode 100644
index f17b441..0000000
--- a/src/lib9/nan.c
+++ /dev/null
@@ -1,54 +0,0 @@
-// +build !plan9
-
-/*
-Plan 9 from User Space src/lib9/nan.c
-http://code.swtch.com/plan9port/src/tip/src/lib9/nan.c
-
-Copyright 2001-2007 Russ Cox.  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.
-*/
-
-#include <u.h>
-#include <libc.h>
-#include "fmt/fmtdef.h"
-
-double
-NaN(void)
-{
-	return __NaN();
-}
-
-double
-Inf(int sign)
-{
-	return __Inf(sign);
-}
-
-int
-isNaN(double x)
-{
-	return __isNaN(x);
-}
-
-int
-isInf(double x, int sign)
-{
-	return __isInf(x, sign);
-}
diff --git a/src/lib9/notify.c b/src/lib9/notify.c
deleted file mode 100644
index 7843d34..0000000
--- a/src/lib9/notify.c
+++ /dev/null
@@ -1,300 +0,0 @@
-// +build !plan9
-// +build !windows
-
-/*
-Plan 9 from User Space src/lib9/notify.c
-http://code.swtch.com/plan9port/src/tip/src/lib9/notify.c
-
-Copyright 2001-2007 Russ Cox.  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.
-*/
-
-/*
- * Signal handling for Plan 9 programs.
- * We stubbornly use the strings from Plan 9 instead
- * of the enumerated Unix constants.
- * There are some weird translations.  In particular,
- * a "kill" note is the same as SIGTERM in Unix.
- * There is no equivalent note to Unix's SIGKILL, since
- * it's not a deliverable signal anyway.
- *
- * We do not handle SIGABRT or SIGSEGV, mainly because
- * the thread library queues its notes for later, and we want
- * to dump core with the state at time of delivery.
- *
- * We have to add some extra entry points to provide the
- * ability to tweak which signals are deliverable and which
- * are acted upon.  Notifydisable and notifyenable play with
- * the process signal mask.  Notifyignore enables the signal
- * but will not call notifyf when it comes in.  This is occasionally
- * useful.
- */
-
-#include <u.h>
-#include <signal.h>
-#define NOPLAN9DEFINES
-#include <libc.h>
-
-extern char *_p9sigstr(int, char*);
-extern int _p9strsig(char*);
-
-typedef struct Sig Sig;
-struct Sig
-{
-	int sig;			/* signal number */
-	int flags;
-};
-
-enum
-{
-	Restart = 1<<0,
-	Ignore = 1<<1
-};
-
-static Sig sigs[] = {
-	SIGHUP,		0,
-	SIGINT,		0,
-	SIGQUIT,		0,
-	SIGILL,		0,
-	SIGTRAP,		0,
-/*	SIGABRT, 		0, 	*/
-#ifdef SIGEMT
-	SIGEMT,		0,
-#endif
-	SIGFPE,		0,
-	SIGBUS,		0,
-/*	SIGSEGV, 		0, 	*/
-	SIGCHLD,		Restart|Ignore,
-	SIGSYS,		0,
-	SIGPIPE,		Ignore,
-	SIGALRM,		0,
-	SIGTERM,		0,
-	SIGTSTP,		Restart|Ignore,
-/*	SIGTTIN,		Restart|Ignore, */
-/*	SIGTTOU,		Restart|Ignore, */
-	SIGXCPU,		0,
-	SIGXFSZ,		0,
-	SIGVTALRM,	0,
-	SIGUSR1,		0,
-	SIGUSR2,		0,
-#ifdef SIGWINCH
-	SIGWINCH,	Restart|Ignore,
-#endif
-#ifdef SIGINFO
-	SIGINFO,		Restart|Ignore,
-#endif
-};
-
-static Sig*
-findsig(int s)
-{
-	int i;
-
-	for(i=0; i<nelem(sigs); i++)
-		if(sigs[i].sig == s)
-			return &sigs[i];
-	return nil;
-}
-
-/*
- * The thread library initializes _notejmpbuf to its own
- * routine which provides a per-pthread jump buffer.
- * If we're not using the thread library, we assume we are
- * single-threaded.
- */
-typedef struct Jmp Jmp;
-struct Jmp
-{
-	p9jmp_buf b;
-};
-
-static Jmp onejmp;
-
-static Jmp*
-getonejmp(void)
-{
-	return &onejmp;
-}
-
-Jmp *(*_notejmpbuf)(void) = getonejmp;
-static void noteinit(void);
-
-/*
- * Actual signal handler.
- */
-
-static void (*notifyf)(void*, char*);	/* Plan 9 handler */
-
-static void
-signotify(int sig)
-{
-	char tmp[64];
-	Jmp *j;
-	Sig *s;
-
-	j = (*_notejmpbuf)();
-	switch(p9setjmp(j->b)){
-	case 0:
-		if(notifyf)
-			(*notifyf)(nil, _p9sigstr(sig, tmp));
-		/* fall through */
-	case 1:	/* noted(NDFLT) */
-		if(0)print("DEFAULT %d\n", sig);
-		s = findsig(sig);
-		if(s && (s->flags&Ignore))
-			return;
-		signal(sig, SIG_DFL);
-		raise(sig);
-		_exit(1);
-	case 2:	/* noted(NCONT) */
-		if(0)print("HANDLED %d\n", sig);
-		return;
-	}
-}
-
-static void
-signonotify(int sig)
-{
-	USED(sig);
-}
-
-int
-noted(int v)
-{
-	p9longjmp((*_notejmpbuf)()->b, v==NCONT ? 2 : 1);
-	abort();
-	return 0;
-}
-
-int
-notify(void (*f)(void*, char*))
-{
-	static int init;
-
-	notifyf = f;
-	if(!init){
-		init = 1;
-		noteinit();
-	}
-	return 0;
-}
-
-/*
- * Nonsense about enabling and disabling signals.
- */
-typedef void Sighandler(int);
-static Sighandler*
-handler(int s)
-{
-	struct sigaction sa;
-
-	sigaction(s, nil, &sa);
-	return sa.sa_handler;
-}
-
-static int
-notesetenable(int sig, int enabled)
-{
-	sigset_t mask, omask;
-
-	if(sig == 0)
-		return -1;
-
-	sigemptyset(&mask);
-	sigaddset(&mask, sig);
-	sigprocmask(enabled ? SIG_UNBLOCK : SIG_BLOCK, &mask, &omask);
-	return !sigismember(&omask, sig);
-}
-
-int
-noteenable(char *msg)
-{
-	return notesetenable(_p9strsig(msg), 1);
-}
-
-int
-notedisable(char *msg)
-{
-	return notesetenable(_p9strsig(msg), 0);
-}
-
-static int
-notifyseton(int s, int on)
-{
-	Sig *sig;
-	struct sigaction sa, osa;
-
-	sig = findsig(s);
-	if(sig == nil)
-		return -1;
-	memset(&sa, 0, sizeof sa);
-	sa.sa_handler = on ? signotify : signonotify;
-	if(sig->flags&Restart)
-		sa.sa_flags |= SA_RESTART;
-
-	/*
-	 * We can't allow signals within signals because there's
-	 * only one jump buffer.
-	 */
-	sigfillset(&sa.sa_mask);
-
-	/*
-	 * Install handler.
-	 */
-	sigaction(sig->sig, &sa, &osa);
-	return osa.sa_handler == signotify;
-}
-
-int
-notifyon(char *msg)
-{
-	return notifyseton(_p9strsig(msg), 1);
-}
-
-int
-notifyoff(char *msg)
-{
-	return notifyseton(_p9strsig(msg), 0);
-}
-
-/*
- * Initialization follows sigs table.
- */
-static void
-noteinit(void)
-{
-	int i;
-	Sig *sig;
-
-	for(i=0; i<nelem(sigs); i++){
-		sig = &sigs[i];
-		/*
-		 * If someone has already installed a handler,
-		 * It's probably some ld preload nonsense,
-		 * like pct (a SIGVTALRM-based profiler).
-		 * Or maybe someone has already called notifyon/notifyoff.
-		 * Leave it alone.
-		 */
-		if(handler(sig->sig) != SIG_DFL)
-			continue;
-		notifyseton(sig->sig, 1);
-	}
-}
-
diff --git a/src/lib9/nulldir.c b/src/lib9/nulldir.c
deleted file mode 100644
index 2157ff3..0000000
--- a/src/lib9/nulldir.c
+++ /dev/null
@@ -1,37 +0,0 @@
-// +build !plan9
-
-/*
-Inferno lib9/nulldir.c
-http://code.google.com/p/inferno-os/source/browse/lib9/nulldir.c
-
-	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  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.
-*/
-
-#include <u.h>
-#include <libc.h>
-
-void
-nulldir(Dir *d)
-{
-	memset(d, ~0, sizeof(Dir));
-	d->name = d->uid = d->gid = d->muid = "";
-}
diff --git a/src/lib9/open.c b/src/lib9/open.c
deleted file mode 100644
index 7f53c8e..0000000
--- a/src/lib9/open.c
+++ /dev/null
@@ -1,70 +0,0 @@
-// +build !plan9
-
-/*
-Plan 9 from User Space src/lib9/open.c
-http://code.swtch.com/plan9port/src/tip/src/lib9/open.c
-
-Copyright 2001-2007 Russ Cox.  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.
-*/
-
-#define _GNU_SOURCE	/* for Linux O_DIRECT */
-#include <u.h>
-#define NOPLAN9DEFINES
-#include <sys/file.h>
-#include <libc.h>
-#ifndef O_DIRECT
-#define O_DIRECT 0
-#endif
-
-int
-p9open(char *name, int mode)
-{
-	int rclose;
-	int fd, umode, rdwr;
-
-	rdwr = mode&3;
-	umode = rdwr;
-	rclose = mode&ORCLOSE;
-	mode &= ~(3|ORCLOSE);
-	if(mode&OTRUNC){
-		umode |= O_TRUNC;
-		mode ^= OTRUNC;
-	}
-	if(mode&ODIRECT){
-		umode |= O_DIRECT;
-		mode ^= ODIRECT;
-	}
-	if(mode&OAPPEND){
-		umode |= O_APPEND;
-		mode ^= OAPPEND;
-	}
-	if(mode){
-		werrstr("mode 0x%x not supported", mode);
-		return -1;
-	}
-	umode |= O_BINARY;
-	fd = open(name, umode);
-	if(fd >= 0){
-		if(rclose)
-			remove(name);
-	}
-	return fd;
-}
diff --git a/src/lib9/readn.c b/src/lib9/readn.c
deleted file mode 100644
index 7dfe9e5..0000000
--- a/src/lib9/readn.c
+++ /dev/null
@@ -1,50 +0,0 @@
-// +build !plan9
-
-/*
-Inferno lib9/readn.c
-http://code.google.com/p/inferno-os/source/browse/lib9/readn.c
-
-	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  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.
-*/
-
-#include <u.h>
-#include <libc.h>
-
-long
-readn(int f, void *av, long n)
-{
-	char *a;
-	long m, t;
-
-	a = av;
-	t = 0;
-	while(t < n){
-		m = read(f, a+t, (size_t)(n-t));
-		if(m <= 0){
-			if(t == 0)
-				return m;
-			break;
-		}
-		t += m;
-	}
-	return t;
-}
diff --git a/src/lib9/rfork.c b/src/lib9/rfork.c
deleted file mode 100644
index 23b3ee6..0000000
--- a/src/lib9/rfork.c
+++ /dev/null
@@ -1,156 +0,0 @@
-// +build !plan9
-// +build !windows
-
-/*
-Plan 9 from User Space src/lib9/rfork.c
-http://code.swtch.com/plan9port/src/tip/src/lib9/rfork.c
-
-Copyright 2001-2007 Russ Cox.  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.
-*/
-
-#include <u.h>
-#include <sys/wait.h>
-#include <signal.h>
-#include <libc.h>
-#undef rfork
-
-static void
-nop(int x)
-{
-	USED(x);
-}
-
-int
-p9rfork(int flags)
-{
-	int pid, status;
-	int p[2];
-	int n;
-	char buf[128], *q;
-	extern char **environ;
-
-	if((flags&(RFPROC|RFFDG|RFMEM)) == (RFPROC|RFFDG)){
-		/* check other flags before we commit */
-		flags &= ~(RFPROC|RFFDG|RFENVG);
-		n = (flags & ~(RFNOTEG|RFNAMEG|RFNOWAIT|RFCENVG));
-		if(n){
-			werrstr("unknown flags %08ux in rfork", n);
-			return -1;
-		}
-		if(flags&RFNOWAIT){
-			/*
-			 * BUG - should put the signal handler back after we
-			 * finish, but I just don't care.  If a program calls with
-			 * NOWAIT once, they're not likely to want child notes
-			 * after that.
-			 */
-			signal(SIGCHLD, nop);
-			if(pipe(p) < 0)
-				return -1;
-		}
-		pid = fork();
-		if(pid == -1)
-			return -1;
-		if(flags&RFNOWAIT){
-			flags &= ~RFNOWAIT;
-			if(pid){
-				/*
-				 * Parent - wait for child to fork wait-free child.
-				 * Then read pid from pipe.  Assume pipe buffer can absorb the write.
-				 */
-				close(p[1]);
-				status = 0;
-				if(wait4(pid, &status, 0, 0) < 0){
-					werrstr("pipe dance - wait4 - %r");
-					close(p[0]);
-					return -1;
-				}
-				n = (int)readn(p[0], buf, sizeof buf-1);
-				close(p[0]);
-				if(!WIFEXITED(status) || WEXITSTATUS(status)!=0 || n <= 0){
-					if(!WIFEXITED(status))
-						werrstr("pipe dance - !exited 0x%ux", status);
-					else if(WEXITSTATUS(status) != 0)
-						werrstr("pipe dance - non-zero status 0x%ux", status);
-					else if(n < 0)
-						werrstr("pipe dance - pipe read error - %r");
-					else if(n == 0)
-						werrstr("pipe dance - pipe read eof");
-					else
-						werrstr("pipe dance - unknown failure");
-					return -1;
-				}
-				buf[n] = 0;
-				if(buf[0] == 'x'){
-					werrstr("%s", buf+2);
-					return -1;
-				}
-				pid = (int)strtol(buf, &q, 0);
-			}else{
-				/*
-				 * Child - fork a new child whose wait message can't
-				 * get back to the parent because we're going to exit!
-				 */
-				signal(SIGCHLD, SIG_IGN);
-				close(p[0]);
-				pid = fork();
-				if(pid){
-					/* Child parent - send status over pipe and exit. */
-					if(pid > 0)
-						fprint(p[1], "%d", pid);
-					else
-						fprint(p[1], "x %r");
-					close(p[1]);
-					_exit(0);
-				}else{
-					/* Child child - close pipe. */
-					close(p[1]);
-				}
-			}
-		}
-		if(pid != 0)
-			return pid;
-		if(flags&RFCENVG)
-			if(environ)
-				*environ = nil;
-	}
-	if(flags&RFPROC){
-		werrstr("cannot use rfork for shared memory -- use libthread");
-		return -1;
-	}
-	if(flags&RFNAMEG){
-		/* XXX set $NAMESPACE to a new directory */
-		flags &= ~RFNAMEG;
-	}
-	if(flags&RFNOTEG){
-		setpgid(0, getpid());
-		flags &= ~RFNOTEG;
-	}
-	if(flags&RFNOWAIT){
-		werrstr("cannot use RFNOWAIT without RFPROC");
-		return -1;
-	}
-	if(flags){
-		werrstr("unknown flags %08ux in rfork", flags);
-		return -1;
-	}
-	return 0;
-}
diff --git a/src/lib9/run_plan9.c b/src/lib9/run_plan9.c
deleted file mode 100644
index 2993262..0000000
--- a/src/lib9/run_plan9.c
+++ /dev/null
@@ -1,40 +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.
-
-// +build plan9
-
-#include <u.h>
-#include <libc.h>
-
-int
-runcmd(char **argv)
-{
-	int pid;
-	Waitmsg *w;
-	
-	switch(pid = fork()) {
-	case -1:
-		return -1;
-	case 0:
-		exec(argv[0], argv);
-		fprint(2, "exec %s: %r\n", argv[0]);
-		exits("exec");
-	}
-	
-	w = wait();
-	if(w == nil)
-		return -1;
-	if(w->pid != pid) {
-		werrstr("unexpected pid in wait");
-		free(w);
-		return -1;
-	}
-	if(w->msg[0]) {
-		werrstr("unsuccessful exit status: %s", w->msg);
-		free(w);
-		return -1;
-	}
-	free(w);
-	return 0;
-}
diff --git a/src/lib9/run_unix.c b/src/lib9/run_unix.c
deleted file mode 100644
index 1acaefe..0000000
--- a/src/lib9/run_unix.c
+++ /dev/null
@@ -1,43 +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.
-
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
-
-#include <u.h>
-#include <errno.h>
-#include <sys/wait.h>
-#define NOPLAN9DEFINES
-#include <libc.h>
-
-int
-runcmd(char **argv)
-{
-	int pid, pid1, status;
-	
-	switch(pid = fork()) {
-	case -1:
-		return -1;
-	case 0:
-		execvp(argv[0], argv);
-		fprint(2, "exec %s: %r\n", argv[0]);
-		_exit(1);
-	}
-	
-	while((pid1 = wait(&status)) < 0) {
-		if(errno != EINTR) {
-			werrstr("waitpid: %r");
-			return -1;
-		}
-	}
-	if(pid1 != pid) {
-		werrstr("unexpected pid in wait");
-		return -1;
-	}
-	if(!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
-		werrstr("unsuccessful exit status %#x", status);
-		return -1;
-	}
-	return 0;
-}
-
diff --git a/src/lib9/run_windows.c b/src/lib9/run_windows.c
deleted file mode 100644
index 87875b4..0000000
--- a/src/lib9/run_windows.c
+++ /dev/null
@@ -1,83 +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.
-
-#include <u.h>
-#include <windows.h>
-#define NOPLAN9DEFINES
-#include <libc.h>
-#include "win.h"
-
-int
-runcmd(char **argv)
-{
-	// Mostly copied from ../cmd/dist/windows.c.
-	// If there's a bug here, fix the logic there too.
-	int i, j, nslash;
-	Fmt fmt;
-	char *q;
-	WinRune *r;
-	STARTUPINFOW si;
-	PROCESS_INFORMATION pi;
-	DWORD code;
-
-	fmtstrinit(&fmt);
-	for(i=0; argv[i]; i++) {
-		if(i > 0)
-			fmtprint(&fmt, " ");
-		q = argv[i];
-		if(strstr(q, " ") || strstr(q, "\t") || strstr(q, "\"") || strstr(q, "\\\\") || (strlen(q) > 0 && q[strlen(q)-1] == '\\')) {
-			fmtprint(&fmt, "\"");
-			nslash = 0;
-			for(; *q; q++) {
-				if(*q == '\\') {
-					nslash++;
-					continue;
-				}
-				if(*q == '"') {
-					for(j=0; j<2*nslash+1; j++)
-						fmtprint(&fmt, "\\");
-					nslash = 0;
-				}
-				for(j=0; j<nslash; j++)
-					fmtprint(&fmt, "\\");
-				nslash = 0;
-				fmtprint(&fmt, "\"");
-			}
-			for(j=0; j<2*nslash; j++)
-				fmtprint(&fmt, "\\");
-			fmtprint(&fmt, "\"");
-		} else {
-			fmtprint(&fmt, "%s", q);
-		}
-	}
-	
-	q = fmtstrflush(&fmt);
-	r = torune(q);
-	free(q);
-
-	memset(&si, 0, sizeof si);
-	si.cb = sizeof si;
-	si.dwFlags = STARTF_USESTDHANDLES;
-	si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
-	si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
-
-	if(!CreateProcessW(nil, r, nil, nil, TRUE, 0, nil, nil, &si, &pi)) {
-		free(r);
-		return -1;
-	}
-
-	free(r);
-	if(WaitForMultipleObjects(1, &pi.hProcess, FALSE, INFINITE) != 0)
-		return -1;
-	i = GetExitCodeProcess(pi.hProcess, &code);
-	CloseHandle(pi.hProcess);
-	CloseHandle(pi.hThread);
-	if(!i)
-		return -1;
-	if(code != 0) {
-		werrstr("unsuccessful exit status: %d", (int)code);
-		return -1;
-	}
-	return 0;
-}
diff --git a/src/lib9/seek.c b/src/lib9/seek.c
deleted file mode 100644
index 0a0706c..0000000
--- a/src/lib9/seek.c
+++ /dev/null
@@ -1,35 +0,0 @@
-// +build !plan9
-
-/*
-Plan 9 from User Space src/lib9/seek.c
-http://code.swtch.com/plan9port/src/tip/src/lib9/seek.c
-
-Copyright 2001-2007 Russ Cox.  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.
-*/
-
-#include <u.h>
-#include <libc.h>
-
-vlong
-seek(int fd, vlong offset, int whence)
-{
-	return lseek(fd, offset, whence);
-}
diff --git a/src/lib9/strecpy.c b/src/lib9/strecpy.c
deleted file mode 100644
index 4b2b92b..0000000
--- a/src/lib9/strecpy.c
+++ /dev/null
@@ -1,45 +0,0 @@
-// +build !plan9
-
-/*
-Inferno lib9/strecpy.c
-http://code.google.com/p/inferno-os/source/browse/lib9/strecpy.c
-
-	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  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.
-*/
-
-#include <u.h>
-#include <libc.h>
-
-char*
-strecpy(char *to, char *e, char *from)
-{
-	if(to >= e)
-		return to;
-	to = memccpy(to, from, '\0', (size_t)(e - to));
-	if(to == nil){
-		to = e - 1;
-		*to = '\0';
-	}else{
-		to--;
-	}
-	return to;
-}
diff --git a/src/lib9/sysfatal.c b/src/lib9/sysfatal.c
deleted file mode 100644
index 9789061..0000000
--- a/src/lib9/sysfatal.c
+++ /dev/null
@@ -1,49 +0,0 @@
-// +build !plan9
-
-/*
-Plan 9 from User Space src/lib9/sysfatal.c
-http://code.swtch.com/plan9port/src/tip/src/lib9/sysfatal.c
-
-Copyright 2001-2007 Russ Cox.  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.
-*/
-
-#include <u.h>
-#include <libc.h>
-
-void (*_sysfatal)(char*, ...);
-
-void
-sysfatal(char *fmt, ...)
-{
-	char buf[256];
-	va_list arg;
-
-	va_start(arg, fmt);
-	if(_sysfatal)
-		(*_sysfatal)(fmt, arg);
-	vseprint(buf, buf+sizeof buf, fmt, arg);
-	va_end(arg);
-
-	__fixargv0();
-	fprint(2, "%s: %s\n", argv0 ? argv0 : "<prog>", buf);
-	exits("fatal");
-}
-
diff --git a/src/lib9/tempdir_plan9.c b/src/lib9/tempdir_plan9.c
deleted file mode 100644
index 80d7ddb..0000000
--- a/src/lib9/tempdir_plan9.c
+++ /dev/null
@@ -1,56 +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.
-
-// +build plan9
-
-#include <u.h>
-#include <libc.h>
-
-char*
-mktempdir(void)
-{
-	char *p;
-	int fd, i;
-	
-	p = smprint("/tmp/go-link-XXXXXX");
-	for(i=0; i<1000; i++) {
-		sprint(p, "/tmp/go-link-%06x", nrand((1<<24)-1));
-		fd = create(p, OREAD|OEXCL, 0700|DMDIR);
-		if(fd >= 0) {
-			close(fd);
-			return p;
-		}
-	}
-	free(p);
-	return nil;
-}
-
-void
-removeall(char *p)
-{
-	int fd, n, i;
-	Dir *d;
-	char *q;
-	
-	if(remove(p) >= 0)
-		return;
-	if((d = dirstat(p)) == nil)
-		return;
-	if(!(d->mode & DMDIR)) {
-		free(d);
-		return;
-	}
-	free(d);
-	
-	if((fd = open(p, OREAD)) < 0)
-		return;
-	n = dirreadall(fd, &d);
-	close(fd);
-	for(i=0; i<n; i++) {
-		q = smprint("%s/%s", p, d[i].name);
-		removeall(q);
-		free(q);
-	}
-	free(d);
-}
diff --git a/src/lib9/tempdir_unix.c b/src/lib9/tempdir_unix.c
deleted file mode 100644
index 269d538..0000000
--- a/src/lib9/tempdir_unix.c
+++ /dev/null
@@ -1,52 +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.
-
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
-
-#include <u.h>
-#include <dirent.h>
-#include <sys/stat.h>
-#define NOPLAN9DEFINES
-#include <libc.h>
-
-char*
-mktempdir(void)
-{
-	char *tmp, *p;
-	
-	tmp = getenv("TMPDIR");
-	if(tmp == nil || strlen(tmp) == 0)
-		tmp = "/var/tmp";
-	p = smprint("%s/go-link-XXXXXX", tmp);
-	if(mkdtemp(p) == nil)
-		return nil;
-	return p;
-}
-
-void
-removeall(char *p)
-{
-	DIR *d;
-	struct dirent *dp;
-	char *q;
-	struct stat st;
-
-	if(stat(p, &st) < 0)
-		return;
-	if(!S_ISDIR(st.st_mode)) {
-		unlink(p);
-		return;
-	}
-
-	d = opendir(p);
-	while((dp = readdir(d)) != nil) {
-		if(strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0)
-			continue;
-		q = smprint("%s/%s", p, dp->d_name);
-		removeall(q);
-		free(q);
-	}
-	closedir(d);
-	rmdir(p);
-}
diff --git a/src/lib9/tempdir_windows.c b/src/lib9/tempdir_windows.c
deleted file mode 100644
index 4c3df7c..0000000
--- a/src/lib9/tempdir_windows.c
+++ /dev/null
@@ -1,113 +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.
-
-#include <u.h>
-#include <windows.h>
-#include <libc.h>
-#include "win.h"
-
-char*
-toutf(WinRune *r)
-{
-	Rune *r1;
-	int i, n;
-	char *p;
-	
-	n = 0;
-	while(r[n] != '\0')
-		n++;
-	n++;
-	r1 = malloc(n*sizeof r1[0]);
-	for(i=0; i<n; i++)
-		r1[i] = r[i];
-	p = smprint("%S", r1);
-	free(r1);
-	return p;
-}
-
-WinRune*
-torune(char *p)
-{
-	int i, n;
-	Rune rr;
-	WinRune *r;
-	
-	n = utflen(p);
-	r = malloc((n+1)*sizeof r[0]);
-	for(i=0; i<n; i++) {
-		p += chartorune(&rr, p);
-		r[i] = rr;
-	}
-	r[n] = '\0';
-	return r;
-}
-
-char*
-mktempdir(void)
-{
-	WinRune buf[1024];
-	WinRune tmp[MAX_PATH];
-	WinRune golink[] = {'g', 'o', 'l', 'i', 'n', 'k', '\0'};
-	int n;
-	
-	n = GetTempPathW(nelem(buf), buf);
-	if(n <= 0)
-		return nil;
-	buf[n] = '\0';
-	
-	if(GetTempFileNameW(buf, golink, 0, tmp) == 0)
-		return nil;
-	DeleteFileW(tmp);
-	if(!CreateDirectoryW(tmp, nil))
-		return nil;
-	
-	return toutf(tmp);
-}
-
-void
-removeall(char *p)
-{
-	WinRune *r, *r1;
-	DWORD attr;
-	char *q, *qt, *elem;
-	HANDLE h;
-	WIN32_FIND_DATAW data;
-	
-	r = torune(p);
-	attr = GetFileAttributesW(r);
-	if(attr == INVALID_FILE_ATTRIBUTES || !(attr & FILE_ATTRIBUTE_DIRECTORY)) {
-		DeleteFileW(r);
-		free(r);
-		return;
-	}
-
-	q = smprint("%s\\*", p);
-	r1 = torune(q);
-	free(q);
-	h = FindFirstFileW(r1, &data);
-	if(h == INVALID_HANDLE_VALUE)
-		goto done;
-	do{
-		q = toutf(data.cFileName);
-		elem = strrchr(q, '\\');
-		if(elem != nil)
-			elem++;
-		else
-			elem = q;
-		if(strcmp(elem, ".") == 0 || strcmp(elem, "..") == 0) {
-			free(q);
-			continue;
-		}
-		qt = smprint("%s\\%s", p, q);
-		free(q);
-		removeall(qt);
-		free(qt);
-	}while(FindNextFileW(h, &data));
-	FindClose(h);
-
-done:
-	free(r1);
-	RemoveDirectoryW(r);
-	free(r);
-}
diff --git a/src/lib9/time.c b/src/lib9/time.c
deleted file mode 100644
index e1b87a7..0000000
--- a/src/lib9/time.c
+++ /dev/null
@@ -1,68 +0,0 @@
-// +build !plan9
-
-/*
-Plan 9 from User Space src/lib9/time.c
-http://code.swtch.com/plan9port/src/tip/src/lib9/time.c
-
-Copyright 2001-2007 Russ Cox.  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.
-*/
-#include <u.h>
-#include <sys/time.h>
-#include <time.h>
-#ifndef _WIN32
-#include <sys/resource.h>
-#endif
-#define NOPLAN9DEFINES
-#include <libc.h>
-
-long
-p9times(long *t)
-{
-#ifdef _WIN32
-	memset(t, 0, 4*sizeof(long));
-#else
-	struct rusage ru, cru;
-
-	if(getrusage(0, &ru) < 0 || getrusage(-1, &cru) < 0)
-		return -1;
-
-	t[0] = ru.ru_utime.tv_sec*1000 + ru.ru_utime.tv_usec/1000;
-	t[1] = ru.ru_stime.tv_sec*1000 + ru.ru_stime.tv_usec/1000;
-	t[2] = cru.ru_utime.tv_sec*1000 + cru.ru_utime.tv_usec/1000;
-	t[3] = cru.ru_stime.tv_sec*1000 + cru.ru_stime.tv_usec/1000;
-#endif
-
-	/* BUG */
-	return t[0]+t[1]+t[2]+t[3];
-}
-
-double
-p9cputime(void)
-{
-	long t[4];
-	double d;
-
-	if(p9times(t) < 0)
-		return -1.0;
-
-	d = (double)t[0]+(double)t[1]+(double)t[2]+(double)t[3];
-	return d/1000.0;
-}
diff --git a/src/lib9/tokenize.c b/src/lib9/tokenize.c
deleted file mode 100644
index a095fcd..0000000
--- a/src/lib9/tokenize.c
+++ /dev/null
@@ -1,135 +0,0 @@
-// +build !plan9
-
-/*
-Inferno lib9/tokenize.c
-http://code.google.com/p/inferno-os/source/browse/lib9/tokenize.c
-
-	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  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.
-*/
-
-#include <u.h>
-#include <libc.h>
-
-static char qsep[] = " \t\r\n";
-
-static char*
-qtoken(char *s, char *sep)
-{
-	int quoting;
-	char *t;
-
-	quoting = 0;
-	t = s;	/* s is output string, t is input string */
-	while(*t!='\0' && (quoting || utfrune(sep, (Rune)*t)==nil)){
-		if(*t != '\''){
-			*s++ = *t++;
-			continue;
-		}
-		/* *t is a quote */
-		if(!quoting){
-			quoting = 1;
-			t++;
-			continue;
-		}
-		/* quoting and we're on a quote */
-		if(t[1] != '\''){
-			/* end of quoted section; absorb closing quote */
-			t++;
-			quoting = 0;
-			continue;
-		}
-		/* doubled quote; fold one quote into two */
-		t++;
-		*s++ = *t++;
-	}
-	if(*s != '\0'){
-		*s = '\0';
-		if(t == s)
-			t++;
-	}
-	return t;
-}
-
-static char*
-etoken(char *t, char *sep)
-{
-	int quoting;
-
-	/* move to end of next token */
-	quoting = 0;
-	while(*t!='\0' && (quoting || utfrune(sep, (Rune)*t)==nil)){
-		if(*t != '\''){
-			t++;
-			continue;
-		}
-		/* *t is a quote */
-		if(!quoting){
-			quoting = 1;
-			t++;
-			continue;
-		}
-		/* quoting and we're on a quote */
-		if(t[1] != '\''){
-			/* end of quoted section; absorb closing quote */
-			t++;
-			quoting = 0;
-			continue;
-		}
-		/* doubled quote; fold one quote into two */
-		t += 2;
-	}
-	return t;
-}
-
-int
-gettokens(char *s, char **args, int maxargs, char *sep)
-{
-	int nargs;
-
-	for(nargs=0; nargs<maxargs; nargs++){
-		while(*s!='\0' && utfrune(sep, (Rune)*s)!=nil)
-			*s++ = '\0';
-		if(*s == '\0')
-			break;
-		args[nargs] = s;
-		s = etoken(s, sep);
-	}
-
-	return nargs;
-}
-
-int
-tokenize(char *s, char **args, int maxargs)
-{
-	int nargs;
-
-	for(nargs=0; nargs<maxargs; nargs++){
-		while(*s!='\0' && utfrune(qsep, (Rune)*s)!=nil)
-			s++;
-		if(*s == '\0')
-			break;
-		args[nargs] = s;
-		s = qtoken(s, qsep);
-	}
-
-	return nargs;
-}
diff --git a/src/lib9/utf/Makefile b/src/lib9/utf/Makefile
deleted file mode 100644
index fe6f635..0000000
--- a/src/lib9/utf/Makefile
+++ /dev/null
@@ -1,30 +0,0 @@
-# Copyright 2010 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.
-
-# The library is built by the Makefile in the parent directory.
-# This Makefile only builds mkrunetype.
-# GOROOT, GOOS, and GOARCH must be set explicitly.
-
-TARG=mkrunetype
-
-UnicodeData-%.txt:
-	curl http://www.unicode.org/Public/$*/ucd/UnicodeData.txt >_$@
-	mv _$@ $@
-
-mkrunetype: mkrunetype.c
-	cc -I../../../include -o mkrunetype -L$(GOROOT)/pkg/obj/$(GOOS)_$(GOARCH)/ mkrunetype.c -l9
-
-runetypebody-%.h: mkrunetype UnicodeData-%.txt
-	mkrunetype -p UnicodeData-$*.txt >_$@
-	mv _$@ $@
-
-CLEANFILES+=UnicodeData.txt
-
-UNICODE_VERSION=6.3.0
-
-test: mkrunetype UnicodeData-$(UNICODE_VERSION).txt
-	mkrunetype -c UnicodeData-$(UNICODE_VERSION).txt
-
-clean:
-	rm -f UnicodeData.txt mkrunetype
diff --git a/src/lib9/utf/mkrunetype.c b/src/lib9/utf/mkrunetype.c
deleted file mode 100644
index 01eb6b6..0000000
--- a/src/lib9/utf/mkrunetype.c
+++ /dev/null
@@ -1,734 +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.
-
-// +build ignore
-
-/*
- * make is(upper|lower|title|space|alpha)rune and
- * to(upper|lower|title)rune from a UnicodeData.txt file.
- * these can be found at unicode.org
- *
- * with -c, runs a check of the existing runetype functions vs.
- * those extracted from UnicodeData.
- *
- * with -p, generates tables for pairs of chars, as well as for ranges
- * and singletons.
- *
- * UnicodeData defines 4 fields of interest:
- * 1) a category
- * 2) an upper case mapping
- * 3) a lower case mapping
- * 4) a title case mapping
- *
- * toupper, tolower, and totitle are defined directly from the mapping.
- *
- * isalpharune(c) is true iff c is a "letter" category
- * isupperrune(c) is true iff c is the target of toupperrune,
- *	or is in the uppercase letter category
- * similarly for islowerrune and istitlerune.
- * isspacerune is true for space category chars, "C" locale white space chars,
- *	and two additions:
- *	0085	"next line" control char
- *	feff]	"zero-width non-break space"
- * isdigitrune is true iff c is a numeric-digit category.
- */
-
-#include <u.h>
-#include <libc.h>
-#include <stdio.h>
-#include "utf.h"
-#include "utfdef.h"
-
-enum {
-	/*
-	 * fields in the unicode data file
-	 */
-	FIELD_CODE,
-	FIELD_NAME,
-	FIELD_CATEGORY,
-	FIELD_COMBINING,
-	FIELD_BIDIR,
-	FIELD_DECOMP,
-	FIELD_DECIMAL_DIG,
-	FIELD_DIG,
-	FIELD_NUMERIC_VAL,
-	FIELD_MIRRORED,
-	FIELD_UNICODE_1_NAME,
-	FIELD_COMMENT,
-	FIELD_UPPER,
-	FIELD_LOWER,
-	FIELD_TITLE,
-	NFIELDS,
-
-	MAX_LINE	= 1024,
-
-	TO_OFFSET	= 1 << 20,
-
-	NRUNES		= 1 << 21,
-};
-
-#define TO_DELTA(xmapped,x)	(TO_OFFSET + (xmapped) - (x))
-
-static char	myisspace[NRUNES];
-static char	myisalpha[NRUNES];
-static char	myisdigit[NRUNES];
-static char	myisupper[NRUNES];
-static char	myislower[NRUNES];
-static char	myistitle[NRUNES];
-
-static int	mytoupper[NRUNES];
-static int	mytolower[NRUNES];
-static int	mytotitle[NRUNES];
-
-static void	check(void);
-static void	mktables(char *src, int usepairs);
-static void	fatal(const char *fmt, ...);
-static int	mygetfields(char **fields, int nfields, char *str, const char *delim);
-static int	getunicodeline(FILE *in, char **fields, char *buf);
-static int	getcode(char *s);
-
-static void
-usage(void)
-{
-	fprintf(stderr, "usage: mktables [-cp] <UnicodeData.txt>\n");
-	exit(1);
-}
-
-void
-main(int argc, char *argv[])
-{
-	FILE *in;
-	char buf[MAX_LINE], buf2[MAX_LINE];
-	char *fields[NFIELDS + 1], *fields2[NFIELDS + 1];
-	char *p;
-	int i, code, last, docheck, usepairs;
-
-	docheck = 0;
-	usepairs = 0;
-	ARGBEGIN{
-	case 'c':
-		docheck = 1;
-		break;
-	case 'p':
-		usepairs = 1;
-		break;
-	default:
-		usage();
-	}ARGEND
-
-	if(argc != 1){
-		usage();
-	}
-
-	in = fopen(argv[0], "r");
-	if(in == NULL){
-		fatal("can't open %s", argv[0]);
-	}
-
-	for(i = 0; i < NRUNES; i++){
-		mytoupper[i] = i;
-		mytolower[i] = i;
-		mytotitle[i] = i;
-	}
-
-	/*
-	 * make sure isspace has all of the "C" locale whitespace chars
-	 */
-	myisspace['\t'] = 1;
-	myisspace['\n'] = 1;
-	myisspace['\r'] = 1;
-	myisspace['\f'] = 1;
-	myisspace['\v'] = 1;
-
-	/*
-	 * a couple of other exceptions
-	 */
-	myisspace[0x85] = 1;	/* control char, "next line" */
-	myisspace[0xfeff] = 1;	/* zero-width non-break space */
-
-	last = -1;
-	while(getunicodeline(in, fields, buf)){
-		code = getcode(fields[FIELD_CODE]);
-		if (code >= NRUNES)
-			fatal("code-point value too big: %x", code);
-		if(code <= last)
-			fatal("bad code sequence: %x then %x", last, code);
-		last = code;
-
-		/*
-		 * check for ranges
-		 */
-		p = fields[FIELD_CATEGORY];
-		if(strstr(fields[FIELD_NAME], ", First>") != NULL){
-			if(!getunicodeline(in, fields2, buf2))
-				fatal("range start at eof");
-			if (strstr(fields2[FIELD_NAME], ", Last>") == NULL)
-				fatal("range start not followed by range end");
-			last = getcode(fields2[FIELD_CODE]);
-			if(last <= code)
-				fatal("range out of sequence: %x then %x", code, last);
-			if(strcmp(p, fields2[FIELD_CATEGORY]) != 0)
-				fatal("range with mismatched category");
-		}
-
-		/*
-		 * set properties and conversions
-		 */
-		for (; code <= last; code++){
-			if(p[0] == 'L')
-				myisalpha[code] = 1;
-			if(p[0] == 'Z')
-				myisspace[code] = 1;
-
-			if(strcmp(p, "Lu") == 0)
-				myisupper[code] = 1;
-			if(strcmp(p, "Ll") == 0)
-				myislower[code] = 1;
-
-			if(strcmp(p, "Lt") == 0)
-				myistitle[code] = 1;
-
-			if(strcmp(p, "Nd") == 0)
-				myisdigit[code] = 1;
-
-			/*
-			 * when finding conversions, also need to mark
-			 * upper/lower case, since some chars, like
-			 * "III" (0x2162), aren't defined as letters but have a
-			 * lower case mapping ("iii" (0x2172)).
-			 */
-			if(fields[FIELD_UPPER][0] != '\0'){
-				mytoupper[code] = getcode(fields[FIELD_UPPER]);
-			}
-			if(fields[FIELD_LOWER][0] != '\0'){
-				mytolower[code] = getcode(fields[FIELD_LOWER]);
-			}
-			if(fields[FIELD_TITLE][0] != '\0'){
-				mytotitle[code] = getcode(fields[FIELD_TITLE]);
-			}
-		}
-	}
-
-	fclose(in);
-
-	/*
-	 * check for codes with no totitle mapping but a toupper mapping.
-	 * these appear in UnicodeData-2.0.14.txt, but are almost certainly
-	 * erroneous.
-	 */
-	for(i = 0; i < NRUNES; i++){
-		if(mytotitle[i] == i
-		&& mytoupper[i] != i
-		&& !myistitle[i])
-			fprintf(stderr, "warning: code=%.4x not istitle, totitle is same, toupper=%.4x\n", i, mytoupper[i]);
-	}
-
-	/*
-	 * make sure isupper[c] is true if for some x toupper[x]  == c
-	 * ditto for islower and istitle
-	 */
-	for(i = 0; i < NRUNES; i++) {
-		if(mytoupper[i] != i)
-			myisupper[mytoupper[i]] = 1;
-		if(mytolower[i] != i)
-			myislower[mytolower[i]] = 1;
-		if(mytotitle[i] != i)
-			myistitle[mytotitle[i]] = 1;
-	}
-
-	if(docheck){
-		check();
-	}else{
-		mktables(argv[0], usepairs);
-	}
-	exit(0);
-}
-
-/*
- * generate a properties array for ranges, clearing those cases covered.
- * if force, generate one-entry ranges for singletons.
- */
-static int
-mkisrange(const char* label, char* prop, int force)
-{
-	int start, stop, some;
-
-	/*
-	 * first, the ranges
-	 */
-	some = 0;
-	for(start = 0; start < NRUNES; ) {
-		if(!prop[start]){
-			start++;
-			continue;
-		}
-
-		for(stop = start + 1; stop < NRUNES; stop++){
-			if(!prop[stop]){
-				break;
-			}
-			prop[stop] = 0;
-		}
-		if(force || stop != start + 1){
-			if(!some){
-				printf("static Rune __is%sr[] = {\n", label);
-				some = 1;
-			}
-			prop[start] = 0;
-			printf("\t0x%.4x, 0x%.4x,\n", start, stop - 1);
-		}
-
-		start = stop;
-	}
-	if(some)
-		printf("};\n\n");
-	return some;
-}
-
-/*
- * generate a mapping array for pairs with a skip between,
- * clearing those entries covered.
- */
-static int
-mkispair(const char *label, char *prop)
-{
-	int start, stop, some;
-
-	some = 0;
-	for(start = 0; start + 2 < NRUNES; ) {
-		if(!prop[start]){
-			start++;
-			continue;
-		}
-
-		for(stop = start + 2; stop < NRUNES; stop += 2){
-			if(!prop[stop]){
-				break;
-			}
-			prop[stop] = 0;
-		}
-		if(stop != start + 2){
-			if(!some){
-				printf("static Rune __is%sp[] = {\n", label);
-				some = 1;
-			}
-			prop[start] = 0;
-			printf("\t0x%.4x, 0x%.4x,\n", start, stop - 2);
-		}
-
-		start = stop;
-	}
-	if(some)
-		printf("};\n\n");
-	return some;
-}
-
-/*
- * generate a properties array for singletons, clearing those cases covered.
- */
-static int
-mkissingle(const char *label, char *prop)
-{
-	int start, some;
-
-	some = 0;
-	for(start = 0; start < NRUNES; start++) {
-		if(!prop[start]){
-			continue;
-		}
-
-		if(!some){
-			printf("static Rune __is%ss[] = {\n", label);
-			some = 1;
-		}
-		prop[start] = 0;
-		printf("\t0x%.4x,\n", start);
-	}
-	if(some)
-		printf("};\n\n");
-	return some;
-}
-
-/*
- * generate tables and a function for is<label>rune
- */
-static void
-mkis(const char* label, char* prop, int usepairs)
-{
-	int isr, isp, iss;
-
-	isr = mkisrange(label, prop, 0);
-	isp = 0;
-	if(usepairs)
-		isp = mkispair(label, prop);
-	iss = mkissingle(label, prop);
-
-	printf(
-		"int\n"
-		"is%srune(Rune c)\n"
-		"{\n"
-		"	Rune *p;\n"
-		"\n",
-		label);
-
-	if(isr)
-		printf(
-			"	p = rbsearch(c, __is%sr, nelem(__is%sr)/2, 2);\n"
-			"	if(p && c >= p[0] && c <= p[1])\n"
-			"		return 1;\n",
-			label, label);
-
-	if(isp)
-		printf(
-			"	p = rbsearch(c, __is%sp, nelem(__is%sp)/2, 2);\n"
-			"	if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))\n"
-			"		return 1;\n",
-			label, label);
-
-	if(iss)
-		printf(
-			"	p = rbsearch(c, __is%ss, nelem(__is%ss), 1);\n"
-			"	if(p && c == p[0])\n"
-			"		return 1;\n",
-			label, label);
-
-
-	printf(
-		"	return 0;\n"
-		"}\n"
-		"\n"
-	);
-}
-
-/*
- * generate a mapping array for ranges, clearing those entries covered.
- * if force, generate one-entry ranges for singletons.
- */
-static int
-mktorange(const char* label, int* map, int force)
-{
-	int start, stop, delta, some;
-
-	some = 0;
-	for(start = 0; start < NRUNES; ) {
-		if(map[start] == start){
-			start++;
-			continue;
-		}
-
-		delta = TO_DELTA(map[start], start);
-		if(delta != (Rune)delta)
-			fatal("bad map delta %d", delta);
-		for(stop = start + 1; stop < NRUNES; stop++){
-			if(TO_DELTA(map[stop], stop) != delta){
-				break;
-			}
-			map[stop] = stop;
-		}
-		if(stop != start + 1){
-			if(!some){
-				printf("static Rune __to%sr[] = {\n", label);
-				some = 1;
-			}
-			map[start] = start;
-			printf("\t0x%.4x, 0x%.4x, %d,\n", start, stop - 1, delta);
-		}
-
-		start = stop;
-	}
-	if(some)
-		printf("};\n\n");
-	return some;
-}
-
-/*
- * generate a mapping array for pairs with a skip between,
- * clearing those entries covered.
- */
-static int
-mktopair(const char* label, int* map)
-{
-	int start, stop, delta, some;
-
-	some = 0;
-	for(start = 0; start + 2 < NRUNES; ) {
-		if(map[start] == start){
-			start++;
-			continue;
-		}
-
-		delta = TO_DELTA(map[start], start);
-		if(delta != (Rune)delta)
-			fatal("bad map delta %d", delta);
-		for(stop = start + 2; stop < NRUNES; stop += 2){
-			if(TO_DELTA(map[stop], stop) != delta){
-				break;
-			}
-			map[stop] = stop;
-		}
-		if(stop != start + 2){
-			if(!some){
-				printf("static Rune __to%sp[] = {\n", label);
-				some = 1;
-			}
-			map[start] = start;
-			printf("\t0x%.4x, 0x%.4x, %d,\n", start, stop - 2, delta);
-		}
-
-		start = stop;
-	}
-	if(some)
-		printf("};\n\n");
-	return some;
-}
-
-/*
- * generate a mapping array for singletons, clearing those entries covered.
- */
-static int
-mktosingle(const char* label, int* map)
-{
-	int start, delta, some;
-
-	some = 0;
-	for(start = 0; start < NRUNES; start++) {
-		if(map[start] == start){
-			continue;
-		}
-
-		delta = TO_DELTA(map[start], start);
-		if(delta != (Rune)delta)
-			fatal("bad map delta %d", delta);
-		if(!some){
-			printf("static Rune __to%ss[] = {\n", label);
-			some = 1;
-		}
-		map[start] = start;
-		printf("\t0x%.4x, %d,\n", start, delta);
-	}
-	if(some)
-		printf("};\n\n");
-	return some;
-}
-
-/*
- * generate tables and a function for to<label>rune
- */
-static void
-mkto(const char* label, int* map, int usepairs)
-{
-	int tor, top, tos;
-
-	tor = mktorange(label, map, 0);
-	top = 0;
-	if(usepairs)
-		top = mktopair(label, map);
-	tos = mktosingle(label, map);
-
-	printf(
-		"Rune\n"
-		"to%srune(Rune c)\n"
-		"{\n"
-		"	Rune *p;\n"
-		"\n",
-		label);
-
-	if(tor)
-		printf(
-			"	p = rbsearch(c, __to%sr, nelem(__to%sr)/3, 3);\n"
-			"	if(p && c >= p[0] && c <= p[1])\n"
-			"		return c + p[2] - %d;\n",
-			label, label, TO_OFFSET);
-
-	if(top)
-		printf(
-			"	p = rbsearch(c, __to%sp, nelem(__to%sp)/3, 3);\n"
-			"	if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))\n"
-			"		return c + p[2] - %d;\n",
-			label, label, TO_OFFSET);
-
-	if(tos)
-		printf(
-			"	p = rbsearch(c, __to%ss, nelem(__to%ss)/2, 2);\n"
-			"	if(p && c == p[0])\n"
-			"		return c + p[1] - %d;\n",
-			label, label, TO_OFFSET);
-
-
-	printf(
-		"	return c;\n"
-		"}\n"
-		"\n"
-	);
-}
-
-// Make only range tables and a function for is<label>rune.
-static void
-mkisronly(const char* label, char* prop)
-{
-	mkisrange(label, prop, 1);
-	printf(
-		"int\n"
-		"is%srune(Rune c)\n"
-		"{\n"
-		"	Rune *p;\n"
-		"\n"
-		"	p = rbsearch(c, __is%sr, nelem(__is%sr)/2, 2);\n"
-		"	if(p && c >= p[0] && c <= p[1])\n"
-		"		return 1;\n"
-		"	return 0;\n"
-		"}\n"
-		"\n",
-	        label, label, label);
-}
-
-/*
- * generate the body of runetype.
- * assumes there is a function Rune* rbsearch(Rune c, Rune *t, int n, int ne);
- */
-static void
-mktables(char *src, int usepairs)
-{
-	printf("/* generated automatically by mkrunetype.c from %s */\n\n", src);
-
-	/*
-	 * we special case the space and digit tables, since they are assumed
-	 * to be small with several ranges.
-	 */
-	mkisronly("space", myisspace);
-	mkisronly("digit", myisdigit);
-
-	mkis("alpha", myisalpha, 0);
-	mkis("upper", myisupper, usepairs);
-	mkis("lower", myislower, usepairs);
-	mkis("title", myistitle, usepairs);
-
-	mkto("upper", mytoupper, usepairs);
-	mkto("lower", mytolower, usepairs);
-	mkto("title", mytotitle, usepairs);
-}
-
-/*
- * find differences between the newly generated tables and current runetypes.
- */
-static void
-check(void)
-{
-	int i;
-
-	for(i = 0; i < NRUNES; i++){
-		if(isdigitrune(i) != myisdigit[i])
-			fprintf(stderr, "isdigit diff at %x: runetype=%x, unicode=%x\n",
-				i, isdigitrune(i), myisdigit[i]);
-
-		if(isspacerune(i) != myisspace[i])
-			fprintf(stderr, "isspace diff at %x: runetype=%x, unicode=%x\n",
-				i, isspacerune(i), myisspace[i]);
-
-		if(isupperrune(i) != myisupper[i])
-			fprintf(stderr, "isupper diff at %x: runetype=%x, unicode=%x\n",
-				i, isupperrune(i), myisupper[i]);
-
-		if(islowerrune(i) != myislower[i])
-			fprintf(stderr, "islower diff at %x: runetype=%x, unicode=%x\n",
-				i, islowerrune(i), myislower[i]);
-
-		if(isalpharune(i) != myisalpha[i])
-			fprintf(stderr, "isalpha diff at %x: runetype=%x, unicode=%x\n",
-				i, isalpharune(i), myisalpha[i]);
-
-		if(toupperrune(i) != mytoupper[i])
-			fprintf(stderr, "toupper diff at %x: runetype=%x, unicode=%x\n",
-				i, toupperrune(i), mytoupper[i]);
-
-		if(tolowerrune(i) != mytolower[i])
-			fprintf(stderr, "tolower diff at %x: runetype=%x, unicode=%x\n",
-				i, tolowerrune(i), mytolower[i]);
-
-		if(istitlerune(i) != myistitle[i])
-			fprintf(stderr, "istitle diff at %x: runetype=%x, unicode=%x\n",
-				i, istitlerune(i), myistitle[i]);
-
-		if(totitlerune(i) != mytotitle[i])
-			fprintf(stderr, "totitle diff at %x: runetype=%x, unicode=%x\n",
-				i, totitlerune(i), mytotitle[i]);
-
-
-	}
-}
-
-static int
-mygetfields(char **fields, int nfields, char *str, const char *delim)
-{
-	int nf;
-
-	fields[0] = str;
-	nf = 1;
-	if(nf >= nfields)
-		return nf;
-
-	for(; *str; str++){
-		if(strchr(delim, *str) != NULL){
-			*str = '\0';
-			fields[nf++] = str + 1;
-			if(nf >= nfields)
-				break;
-		}
-	}
-	return nf;
-}
-
-static int
-getunicodeline(FILE *in, char **fields, char *buf)
-{
-	char *p;
-
-	if(fgets(buf, MAX_LINE, in) == NULL)
-		return 0;
-
-	p = strchr(buf, '\n');
-	if (p == NULL)
-		fatal("line too long");
-	*p = '\0';
-
-	if (mygetfields(fields, NFIELDS + 1, buf, ";") != NFIELDS)
-		fatal("bad number of fields");
-
-	return 1;
-}
-
-static int
-getcode(char *s)
-{
-	int i, code;
-
-	code = 0;
-	i = 0;
-	/* Parse a hex number */
-	while(s[i]) {
-		code <<= 4;
-		if(s[i] >= '0' && s[i] <= '9')
-			code += s[i] - '0';
-		else if(s[i] >= 'A' && s[i] <= 'F')
-			code += s[i] - 'A' + 10;
-		else
-			fatal("bad code char '%c'", s[i]);
-		i++;
-	}
-	return code;
-}
-
-static void
-fatal(const char *fmt, ...)
-{
-	va_list arg;
-
-	fprintf(stderr, "%s: fatal error: ", argv0);
-	va_start(arg, fmt);
-	vfprintf(stderr, fmt, arg);
-	va_end(arg);
-	fprintf(stderr, "\n");
-
-	exit(1);
-}
diff --git a/src/lib9/utf/rune.c b/src/lib9/utf/rune.c
deleted file mode 100644
index 99f03ea..0000000
--- a/src/lib9/utf/rune.c
+++ /dev/null
@@ -1,358 +0,0 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- *              Copyright (c) 2002 by Lucent Technologies.
- *              Portions Copyright (c) 2009 The Go Authors.  All rights reserved.
- * 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.
- */
-#include "utf.h"
-#include "utfdef.h"
-
-enum
-{
-	Bit1	= 7,
-	Bitx	= 6,
-	Bit2	= 5,
-	Bit3	= 4,
-	Bit4	= 3,
-	Bit5	= 2,
-
-	T1	= ((1<<(Bit1+1))-1) ^ 0xFF,	/* 0000 0000 */
-	Tx	= ((1<<(Bitx+1))-1) ^ 0xFF,	/* 1000 0000 */
-	T2	= ((1<<(Bit2+1))-1) ^ 0xFF,	/* 1100 0000 */
-	T3	= ((1<<(Bit3+1))-1) ^ 0xFF,	/* 1110 0000 */
-	T4	= ((1<<(Bit4+1))-1) ^ 0xFF,	/* 1111 0000 */
-	T5	= ((1<<(Bit5+1))-1) ^ 0xFF,	/* 1111 1000 */
-
-	Rune1	= (1<<(Bit1+0*Bitx))-1,		/* 0000 0000 0111 1111 */
-	Rune2	= (1<<(Bit2+1*Bitx))-1,		/* 0000 0111 1111 1111 */
-	Rune3	= (1<<(Bit3+2*Bitx))-1,		/* 1111 1111 1111 1111 */
-	Rune4	= (1<<(Bit4+3*Bitx))-1,		/* 0001 1111 1111 1111 1111 1111 */
-
-	Maskx	= (1<<Bitx)-1,			/* 0011 1111 */
-	Testx	= Maskx ^ 0xFF,			/* 1100 0000 */
-
-	SurrogateMin	= 0xD800,
-	SurrogateMax	= 0xDFFF,
-
-	Bad	= Runeerror,
-};
-
-/*
- * Modified by Wei-Hwa Huang, Google Inc., on 2004-09-24
- * This is a slower but "safe" version of the old chartorune
- * that works on strings that are not necessarily null-terminated.
- *
- * If you know for sure that your string is null-terminated,
- * chartorune will be a bit faster.
- *
- * It is guaranteed not to attempt to access "length"
- * past the incoming pointer.  This is to avoid
- * possible access violations.  If the string appears to be
- * well-formed but incomplete (i.e., to get the whole Rune
- * we'd need to read past str+length) then we'll set the Rune
- * to Bad and return 0.
- *
- * Note that if we have decoding problems for other
- * reasons, we return 1 instead of 0.
- */
-int
-charntorune(Rune *rune, const char *str, int length)
-{
-	int c, c1, c2, c3;
-	long l;
-
-	/* When we're not allowed to read anything */
-	if(length <= 0) {
-		goto badlen;
-	}
-
-	/*
-	 * one character sequence (7-bit value)
-	 *	00000-0007F => T1
-	 */
-	c = *(uchar*)str;
-	if(c < Tx) {
-		*rune = (Rune)c;
-		return 1;
-	}
-
-	// If we can't read more than one character we must stop
-	if(length <= 1) {
-		goto badlen;
-	}
-
-	/*
-	 * two character sequence (11-bit value)
-	 *	0080-07FF => T2 Tx
-	 */
-	c1 = *(uchar*)(str+1) ^ Tx;
-	if(c1 & Testx)
-		goto bad;
-	if(c < T3) {
-		if(c < T2)
-			goto bad;
-		l = ((c << Bitx) | c1) & Rune2;
-		if(l <= Rune1)
-			goto bad;
-		*rune = (Rune)l;
-		return 2;
-	}
-
-	// If we can't read more than two characters we must stop
-	if(length <= 2) {
-		goto badlen;
-	}
-
-	/*
-	 * three character sequence (16-bit value)
-	 *	0800-FFFF => T3 Tx Tx
-	 */
-	c2 = *(uchar*)(str+2) ^ Tx;
-	if(c2 & Testx)
-		goto bad;
-	if(c < T4) {
-		l = ((((c << Bitx) | c1) << Bitx) | c2) & Rune3;
-		if(l <= Rune2)
-			goto bad;
-		if (SurrogateMin <= l && l <= SurrogateMax)
-			goto bad;
-		*rune = (Rune)l;
-		return 3;
-	}
-
-	if (length <= 3)
-		goto badlen;
-
-	/*
-	 * four character sequence (21-bit value)
-	 *	10000-1FFFFF => T4 Tx Tx Tx
-	 */
-	c3 = *(uchar*)(str+3) ^ Tx;
-	if (c3 & Testx)
-		goto bad;
-	if (c < T5) {
-		l = ((((((c << Bitx) | c1) << Bitx) | c2) << Bitx) | c3) & Rune4;
-		if (l <= Rune3 || l > Runemax)
-			goto bad;
-		*rune = (Rune)l;
-		return 4;
-	}
-
-	// Support for 5-byte or longer UTF-8 would go here, but
-	// since we don't have that, we'll just fall through to bad.
-
-	/*
-	 * bad decoding
-	 */
-bad:
-	*rune = Bad;
-	return 1;
-badlen:
-	*rune = Bad;
-	return 0;
-
-}
-
-
-/*
- * This is the older "unsafe" version, which works fine on
- * null-terminated strings.
- */
-int
-chartorune(Rune *rune, const char *str)
-{
-	int c, c1, c2, c3;
-	long l;
-
-	/*
-	 * one character sequence
-	 *	00000-0007F => T1
-	 */
-	c = *(uchar*)str;
-	if(c < Tx) {
-		*rune = (Rune)c;
-		return 1;
-	}
-
-	/*
-	 * two character sequence
-	 *	0080-07FF => T2 Tx
-	 */
-	c1 = *(uchar*)(str+1) ^ Tx;
-	if(c1 & Testx)
-		goto bad;
-	if(c < T3) {
-		if(c < T2)
-			goto bad;
-		l = ((c << Bitx) | c1) & Rune2;
-		if(l <= Rune1)
-			goto bad;
-		*rune = (Rune)l;
-		return 2;
-	}
-
-	/*
-	 * three character sequence
-	 *	0800-FFFF => T3 Tx Tx
-	 */
-	c2 = *(uchar*)(str+2) ^ Tx;
-	if(c2 & Testx)
-		goto bad;
-	if(c < T4) {
-		l = ((((c << Bitx) | c1) << Bitx) | c2) & Rune3;
-		if(l <= Rune2)
-			goto bad;
-		if (SurrogateMin <= l && l <= SurrogateMax)
-			goto bad;
-		*rune = (Rune)l;
-		return 3;
-	}
-
-	/*
-	 * four character sequence (21-bit value)
-	 *	10000-1FFFFF => T4 Tx Tx Tx
-	 */
-	c3 = *(uchar*)(str+3) ^ Tx;
-	if (c3 & Testx)
-		goto bad;
-	if (c < T5) {
-		l = ((((((c << Bitx) | c1) << Bitx) | c2) << Bitx) | c3) & Rune4;
-		if (l <= Rune3 || l > Runemax)
-			goto bad;
-		*rune = (Rune)l;
-		return 4;
-	}
-
-	/*
-	 * Support for 5-byte or longer UTF-8 would go here, but
-	 * since we don't have that, we'll just fall through to bad.
-	 */
-
-	/*
-	 * bad decoding
-	 */
-bad:
-	*rune = Bad;
-	return 1;
-}
-
-int
-isvalidcharntorune(const char* str, int length, Rune* rune, int* consumed)
-{
-	*consumed = charntorune(rune, str, length);
-	return *rune != Runeerror || *consumed == 3;
-}
-
-int
-runetochar(char *str, const Rune *rune)
-{
-	/* Runes are signed, so convert to unsigned for range check. */
-	unsigned long c;
-
-	/*
-	 * one character sequence
-	 *	00000-0007F => 00-7F
-	 */
-	c = *rune;
-	if(c <= Rune1) {
-		str[0] = (char)c;
-		return 1;
-	}
-
-	/*
-	 * two character sequence
-	 *	0080-07FF => T2 Tx
-	 */
-	if(c <= Rune2) {
-		str[0] = (char)(T2 | (c >> 1*Bitx));
-		str[1] = (char)(Tx | (c & Maskx));
-		return 2;
-	}
-
-	/*
-	 * If the Rune is out of range or a surrogate half, convert it to the error rune.
-	 * Do this test here because the error rune encodes to three bytes.
-	 * Doing it earlier would duplicate work, since an out of range
-	 * Rune wouldn't have fit in one or two bytes.
-	 */
-	if (c > Runemax)
-		c = Runeerror;
-	if (SurrogateMin <= c && c <= SurrogateMax)
-		c = Runeerror;
-
-	/*
-	 * three character sequence
-	 *	0800-FFFF => T3 Tx Tx
-	 */
-	if (c <= Rune3) {
-		str[0] = (char)(T3 |  (c >> 2*Bitx));
-		str[1] = (char)(Tx | ((c >> 1*Bitx) & Maskx));
-		str[2] = (char)(Tx |  (c & Maskx));
-		return 3;
-	}
-
-	/*
-	 * four character sequence (21-bit value)
-	 *     10000-1FFFFF => T4 Tx Tx Tx
-	 */
-	str[0] = (char)(T4 | (c >> 3*Bitx));
-	str[1] = (char)(Tx | ((c >> 2*Bitx) & Maskx));
-	str[2] = (char)(Tx | ((c >> 1*Bitx) & Maskx));
-	str[3] = (char)(Tx | (c & Maskx));
-	return 4;
-}
-
-int
-runelen(Rune rune)
-{
-	char str[10];
-
-	return runetochar(str, &rune);
-}
-
-int
-runenlen(const Rune *r, int nrune)
-{
-	int nb, c;
-
-	nb = 0;
-	while(nrune--) {
-		c = (int)*r++;
-		if (c <= Rune1)
-			nb++;
-		else if (c <= Rune2)
-			nb += 2;
-		else if (c <= Rune3)
-			nb += 3;
-		else /* assert(c <= Rune4) */
-			nb += 4;
-	}
-	return nb;
-}
-
-int
-fullrune(const char *str, int n)
-{
-	if (n > 0) {
-		int c = *(uchar*)str;
-		if (c < Tx)
-			return 1;
-		if (n > 1) {
-			if (c < T3)
-				return 1;
-			if (n > 2) {
-				if (c < T4 || n > 3)
-					return 1;
-			}
-		}
-	}
-	return 0;
-}
diff --git a/src/lib9/utf/runetype.c b/src/lib9/utf/runetype.c
deleted file mode 100644
index ed775af..0000000
--- a/src/lib9/utf/runetype.c
+++ /dev/null
@@ -1,38 +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.
- */
-#include "utf.h"
-#include "utfdef.h"
-
-static
-Rune*
-rbsearch(Rune c, Rune *t, int n, int ne)
-{
-	Rune *p;
-	int m;
-
-	while(n > 1) {
-		m = n >> 1;
-		p = t + m*ne;
-		if(c >= p[0]) {
-			t = p;
-			n = n-m;
-		} else
-			n = m;
-	}
-	if(n && c >= t[0])
-		return t;
-	return 0;
-}
-
-#include "runetypebody-6.3.0.h"
diff --git a/src/lib9/utf/runetypebody-6.3.0.h b/src/lib9/utf/runetypebody-6.3.0.h
deleted file mode 100644
index 5554dca..0000000
--- a/src/lib9/utf/runetypebody-6.3.0.h
+++ /dev/null
@@ -1,1638 +0,0 @@
-/* generated automatically by mkrunetype.c from UnicodeData-6.3.0.txt */
-
-static Rune __isspacer[] = {
-	0x0009, 0x000d,
-	0x0020, 0x0020,
-	0x0085, 0x0085,
-	0x00a0, 0x00a0,
-	0x1680, 0x1680,
-	0x2000, 0x200a,
-	0x2028, 0x2029,
-	0x202f, 0x202f,
-	0x205f, 0x205f,
-	0x3000, 0x3000,
-	0xfeff, 0xfeff,
-};
-
-int
-isspacerune(Rune c)
-{
-	Rune *p;
-
-	p = rbsearch(c, __isspacer, nelem(__isspacer)/2, 2);
-	if(p && c >= p[0] && c <= p[1])
-		return 1;
-	return 0;
-}
-
-static Rune __isdigitr[] = {
-	0x0030, 0x0039,
-	0x0660, 0x0669,
-	0x06f0, 0x06f9,
-	0x07c0, 0x07c9,
-	0x0966, 0x096f,
-	0x09e6, 0x09ef,
-	0x0a66, 0x0a6f,
-	0x0ae6, 0x0aef,
-	0x0b66, 0x0b6f,
-	0x0be6, 0x0bef,
-	0x0c66, 0x0c6f,
-	0x0ce6, 0x0cef,
-	0x0d66, 0x0d6f,
-	0x0e50, 0x0e59,
-	0x0ed0, 0x0ed9,
-	0x0f20, 0x0f29,
-	0x1040, 0x1049,
-	0x1090, 0x1099,
-	0x17e0, 0x17e9,
-	0x1810, 0x1819,
-	0x1946, 0x194f,
-	0x19d0, 0x19d9,
-	0x1a80, 0x1a89,
-	0x1a90, 0x1a99,
-	0x1b50, 0x1b59,
-	0x1bb0, 0x1bb9,
-	0x1c40, 0x1c49,
-	0x1c50, 0x1c59,
-	0xa620, 0xa629,
-	0xa8d0, 0xa8d9,
-	0xa900, 0xa909,
-	0xa9d0, 0xa9d9,
-	0xaa50, 0xaa59,
-	0xabf0, 0xabf9,
-	0xff10, 0xff19,
-	0x104a0, 0x104a9,
-	0x11066, 0x1106f,
-	0x110f0, 0x110f9,
-	0x11136, 0x1113f,
-	0x111d0, 0x111d9,
-	0x116c0, 0x116c9,
-	0x1d7ce, 0x1d7ff,
-};
-
-int
-isdigitrune(Rune c)
-{
-	Rune *p;
-
-	p = rbsearch(c, __isdigitr, nelem(__isdigitr)/2, 2);
-	if(p && c >= p[0] && c <= p[1])
-		return 1;
-	return 0;
-}
-
-static Rune __isalphar[] = {
-	0x0041, 0x005a,
-	0x0061, 0x007a,
-	0x00c0, 0x00d6,
-	0x00d8, 0x00f6,
-	0x00f8, 0x02c1,
-	0x02c6, 0x02d1,
-	0x02e0, 0x02e4,
-	0x0370, 0x0374,
-	0x0376, 0x0377,
-	0x037a, 0x037d,
-	0x0388, 0x038a,
-	0x038e, 0x03a1,
-	0x03a3, 0x03f5,
-	0x03f7, 0x0481,
-	0x048a, 0x0527,
-	0x0531, 0x0556,
-	0x0561, 0x0587,
-	0x05d0, 0x05ea,
-	0x05f0, 0x05f2,
-	0x0620, 0x064a,
-	0x066e, 0x066f,
-	0x0671, 0x06d3,
-	0x06e5, 0x06e6,
-	0x06ee, 0x06ef,
-	0x06fa, 0x06fc,
-	0x0712, 0x072f,
-	0x074d, 0x07a5,
-	0x07ca, 0x07ea,
-	0x07f4, 0x07f5,
-	0x0800, 0x0815,
-	0x0840, 0x0858,
-	0x08a2, 0x08ac,
-	0x0904, 0x0939,
-	0x0958, 0x0961,
-	0x0971, 0x0977,
-	0x0979, 0x097f,
-	0x0985, 0x098c,
-	0x098f, 0x0990,
-	0x0993, 0x09a8,
-	0x09aa, 0x09b0,
-	0x09b6, 0x09b9,
-	0x09dc, 0x09dd,
-	0x09df, 0x09e1,
-	0x09f0, 0x09f1,
-	0x0a05, 0x0a0a,
-	0x0a0f, 0x0a10,
-	0x0a13, 0x0a28,
-	0x0a2a, 0x0a30,
-	0x0a32, 0x0a33,
-	0x0a35, 0x0a36,
-	0x0a38, 0x0a39,
-	0x0a59, 0x0a5c,
-	0x0a72, 0x0a74,
-	0x0a85, 0x0a8d,
-	0x0a8f, 0x0a91,
-	0x0a93, 0x0aa8,
-	0x0aaa, 0x0ab0,
-	0x0ab2, 0x0ab3,
-	0x0ab5, 0x0ab9,
-	0x0ae0, 0x0ae1,
-	0x0b05, 0x0b0c,
-	0x0b0f, 0x0b10,
-	0x0b13, 0x0b28,
-	0x0b2a, 0x0b30,
-	0x0b32, 0x0b33,
-	0x0b35, 0x0b39,
-	0x0b5c, 0x0b5d,
-	0x0b5f, 0x0b61,
-	0x0b85, 0x0b8a,
-	0x0b8e, 0x0b90,
-	0x0b92, 0x0b95,
-	0x0b99, 0x0b9a,
-	0x0b9e, 0x0b9f,
-	0x0ba3, 0x0ba4,
-	0x0ba8, 0x0baa,
-	0x0bae, 0x0bb9,
-	0x0c05, 0x0c0c,
-	0x0c0e, 0x0c10,
-	0x0c12, 0x0c28,
-	0x0c2a, 0x0c33,
-	0x0c35, 0x0c39,
-	0x0c58, 0x0c59,
-	0x0c60, 0x0c61,
-	0x0c85, 0x0c8c,
-	0x0c8e, 0x0c90,
-	0x0c92, 0x0ca8,
-	0x0caa, 0x0cb3,
-	0x0cb5, 0x0cb9,
-	0x0ce0, 0x0ce1,
-	0x0cf1, 0x0cf2,
-	0x0d05, 0x0d0c,
-	0x0d0e, 0x0d10,
-	0x0d12, 0x0d3a,
-	0x0d60, 0x0d61,
-	0x0d7a, 0x0d7f,
-	0x0d85, 0x0d96,
-	0x0d9a, 0x0db1,
-	0x0db3, 0x0dbb,
-	0x0dc0, 0x0dc6,
-	0x0e01, 0x0e30,
-	0x0e32, 0x0e33,
-	0x0e40, 0x0e46,
-	0x0e81, 0x0e82,
-	0x0e87, 0x0e88,
-	0x0e94, 0x0e97,
-	0x0e99, 0x0e9f,
-	0x0ea1, 0x0ea3,
-	0x0eaa, 0x0eab,
-	0x0ead, 0x0eb0,
-	0x0eb2, 0x0eb3,
-	0x0ec0, 0x0ec4,
-	0x0edc, 0x0edf,
-	0x0f40, 0x0f47,
-	0x0f49, 0x0f6c,
-	0x0f88, 0x0f8c,
-	0x1000, 0x102a,
-	0x1050, 0x1055,
-	0x105a, 0x105d,
-	0x1065, 0x1066,
-	0x106e, 0x1070,
-	0x1075, 0x1081,
-	0x10a0, 0x10c5,
-	0x10d0, 0x10fa,
-	0x10fc, 0x1248,
-	0x124a, 0x124d,
-	0x1250, 0x1256,
-	0x125a, 0x125d,
-	0x1260, 0x1288,
-	0x128a, 0x128d,
-	0x1290, 0x12b0,
-	0x12b2, 0x12b5,
-	0x12b8, 0x12be,
-	0x12c2, 0x12c5,
-	0x12c8, 0x12d6,
-	0x12d8, 0x1310,
-	0x1312, 0x1315,
-	0x1318, 0x135a,
-	0x1380, 0x138f,
-	0x13a0, 0x13f4,
-	0x1401, 0x166c,
-	0x166f, 0x167f,
-	0x1681, 0x169a,
-	0x16a0, 0x16ea,
-	0x1700, 0x170c,
-	0x170e, 0x1711,
-	0x1720, 0x1731,
-	0x1740, 0x1751,
-	0x1760, 0x176c,
-	0x176e, 0x1770,
-	0x1780, 0x17b3,
-	0x1820, 0x1877,
-	0x1880, 0x18a8,
-	0x18b0, 0x18f5,
-	0x1900, 0x191c,
-	0x1950, 0x196d,
-	0x1970, 0x1974,
-	0x1980, 0x19ab,
-	0x19c1, 0x19c7,
-	0x1a00, 0x1a16,
-	0x1a20, 0x1a54,
-	0x1b05, 0x1b33,
-	0x1b45, 0x1b4b,
-	0x1b83, 0x1ba0,
-	0x1bae, 0x1baf,
-	0x1bba, 0x1be5,
-	0x1c00, 0x1c23,
-	0x1c4d, 0x1c4f,
-	0x1c5a, 0x1c7d,
-	0x1ce9, 0x1cec,
-	0x1cee, 0x1cf1,
-	0x1cf5, 0x1cf6,
-	0x1d00, 0x1dbf,
-	0x1e00, 0x1f15,
-	0x1f18, 0x1f1d,
-	0x1f20, 0x1f45,
-	0x1f48, 0x1f4d,
-	0x1f50, 0x1f57,
-	0x1f5f, 0x1f7d,
-	0x1f80, 0x1fb4,
-	0x1fb6, 0x1fbc,
-	0x1fc2, 0x1fc4,
-	0x1fc6, 0x1fcc,
-	0x1fd0, 0x1fd3,
-	0x1fd6, 0x1fdb,
-	0x1fe0, 0x1fec,
-	0x1ff2, 0x1ff4,
-	0x1ff6, 0x1ffc,
-	0x2090, 0x209c,
-	0x210a, 0x2113,
-	0x2119, 0x211d,
-	0x212a, 0x212d,
-	0x212f, 0x2139,
-	0x213c, 0x213f,
-	0x2145, 0x2149,
-	0x2183, 0x2184,
-	0x2c00, 0x2c2e,
-	0x2c30, 0x2c5e,
-	0x2c60, 0x2ce4,
-	0x2ceb, 0x2cee,
-	0x2cf2, 0x2cf3,
-	0x2d00, 0x2d25,
-	0x2d30, 0x2d67,
-	0x2d80, 0x2d96,
-	0x2da0, 0x2da6,
-	0x2da8, 0x2dae,
-	0x2db0, 0x2db6,
-	0x2db8, 0x2dbe,
-	0x2dc0, 0x2dc6,
-	0x2dc8, 0x2dce,
-	0x2dd0, 0x2dd6,
-	0x2dd8, 0x2dde,
-	0x3005, 0x3006,
-	0x3031, 0x3035,
-	0x303b, 0x303c,
-	0x3041, 0x3096,
-	0x309d, 0x309f,
-	0x30a1, 0x30fa,
-	0x30fc, 0x30ff,
-	0x3105, 0x312d,
-	0x3131, 0x318e,
-	0x31a0, 0x31ba,
-	0x31f0, 0x31ff,
-	0x3400, 0x4db5,
-	0x4e00, 0x9fcc,
-	0xa000, 0xa48c,
-	0xa4d0, 0xa4fd,
-	0xa500, 0xa60c,
-	0xa610, 0xa61f,
-	0xa62a, 0xa62b,
-	0xa640, 0xa66e,
-	0xa67f, 0xa697,
-	0xa6a0, 0xa6e5,
-	0xa717, 0xa71f,
-	0xa722, 0xa788,
-	0xa78b, 0xa78e,
-	0xa790, 0xa793,
-	0xa7a0, 0xa7aa,
-	0xa7f8, 0xa801,
-	0xa803, 0xa805,
-	0xa807, 0xa80a,
-	0xa80c, 0xa822,
-	0xa840, 0xa873,
-	0xa882, 0xa8b3,
-	0xa8f2, 0xa8f7,
-	0xa90a, 0xa925,
-	0xa930, 0xa946,
-	0xa960, 0xa97c,
-	0xa984, 0xa9b2,
-	0xaa00, 0xaa28,
-	0xaa40, 0xaa42,
-	0xaa44, 0xaa4b,
-	0xaa60, 0xaa76,
-	0xaa80, 0xaaaf,
-	0xaab5, 0xaab6,
-	0xaab9, 0xaabd,
-	0xaadb, 0xaadd,
-	0xaae0, 0xaaea,
-	0xaaf2, 0xaaf4,
-	0xab01, 0xab06,
-	0xab09, 0xab0e,
-	0xab11, 0xab16,
-	0xab20, 0xab26,
-	0xab28, 0xab2e,
-	0xabc0, 0xabe2,
-	0xac00, 0xd7a3,
-	0xd7b0, 0xd7c6,
-	0xd7cb, 0xd7fb,
-	0xf900, 0xfa6d,
-	0xfa70, 0xfad9,
-	0xfb00, 0xfb06,
-	0xfb13, 0xfb17,
-	0xfb1f, 0xfb28,
-	0xfb2a, 0xfb36,
-	0xfb38, 0xfb3c,
-	0xfb40, 0xfb41,
-	0xfb43, 0xfb44,
-	0xfb46, 0xfbb1,
-	0xfbd3, 0xfd3d,
-	0xfd50, 0xfd8f,
-	0xfd92, 0xfdc7,
-	0xfdf0, 0xfdfb,
-	0xfe70, 0xfe74,
-	0xfe76, 0xfefc,
-	0xff21, 0xff3a,
-	0xff41, 0xff5a,
-	0xff66, 0xffbe,
-	0xffc2, 0xffc7,
-	0xffca, 0xffcf,
-	0xffd2, 0xffd7,
-	0xffda, 0xffdc,
-	0x10000, 0x1000b,
-	0x1000d, 0x10026,
-	0x10028, 0x1003a,
-	0x1003c, 0x1003d,
-	0x1003f, 0x1004d,
-	0x10050, 0x1005d,
-	0x10080, 0x100fa,
-	0x10280, 0x1029c,
-	0x102a0, 0x102d0,
-	0x10300, 0x1031e,
-	0x10330, 0x10340,
-	0x10342, 0x10349,
-	0x10380, 0x1039d,
-	0x103a0, 0x103c3,
-	0x103c8, 0x103cf,
-	0x10400, 0x1049d,
-	0x10800, 0x10805,
-	0x1080a, 0x10835,
-	0x10837, 0x10838,
-	0x1083f, 0x10855,
-	0x10900, 0x10915,
-	0x10920, 0x10939,
-	0x10980, 0x109b7,
-	0x109be, 0x109bf,
-	0x10a10, 0x10a13,
-	0x10a15, 0x10a17,
-	0x10a19, 0x10a33,
-	0x10a60, 0x10a7c,
-	0x10b00, 0x10b35,
-	0x10b40, 0x10b55,
-	0x10b60, 0x10b72,
-	0x10c00, 0x10c48,
-	0x11003, 0x11037,
-	0x11083, 0x110af,
-	0x110d0, 0x110e8,
-	0x11103, 0x11126,
-	0x11183, 0x111b2,
-	0x111c1, 0x111c4,
-	0x11680, 0x116aa,
-	0x12000, 0x1236e,
-	0x13000, 0x1342e,
-	0x16800, 0x16a38,
-	0x16f00, 0x16f44,
-	0x16f93, 0x16f9f,
-	0x1b000, 0x1b001,
-	0x1d400, 0x1d454,
-	0x1d456, 0x1d49c,
-	0x1d49e, 0x1d49f,
-	0x1d4a5, 0x1d4a6,
-	0x1d4a9, 0x1d4ac,
-	0x1d4ae, 0x1d4b9,
-	0x1d4bd, 0x1d4c3,
-	0x1d4c5, 0x1d505,
-	0x1d507, 0x1d50a,
-	0x1d50d, 0x1d514,
-	0x1d516, 0x1d51c,
-	0x1d51e, 0x1d539,
-	0x1d53b, 0x1d53e,
-	0x1d540, 0x1d544,
-	0x1d54a, 0x1d550,
-	0x1d552, 0x1d6a5,
-	0x1d6a8, 0x1d6c0,
-	0x1d6c2, 0x1d6da,
-	0x1d6dc, 0x1d6fa,
-	0x1d6fc, 0x1d714,
-	0x1d716, 0x1d734,
-	0x1d736, 0x1d74e,
-	0x1d750, 0x1d76e,
-	0x1d770, 0x1d788,
-	0x1d78a, 0x1d7a8,
-	0x1d7aa, 0x1d7c2,
-	0x1d7c4, 0x1d7cb,
-	0x1ee00, 0x1ee03,
-	0x1ee05, 0x1ee1f,
-	0x1ee21, 0x1ee22,
-	0x1ee29, 0x1ee32,
-	0x1ee34, 0x1ee37,
-	0x1ee4d, 0x1ee4f,
-	0x1ee51, 0x1ee52,
-	0x1ee61, 0x1ee62,
-	0x1ee67, 0x1ee6a,
-	0x1ee6c, 0x1ee72,
-	0x1ee74, 0x1ee77,
-	0x1ee79, 0x1ee7c,
-	0x1ee80, 0x1ee89,
-	0x1ee8b, 0x1ee9b,
-	0x1eea1, 0x1eea3,
-	0x1eea5, 0x1eea9,
-	0x1eeab, 0x1eebb,
-	0x20000, 0x2a6d6,
-	0x2a700, 0x2b734,
-	0x2b740, 0x2b81d,
-	0x2f800, 0x2fa1d,
-};
-
-static Rune __isalphas[] = {
-	0x00aa,
-	0x00b5,
-	0x00ba,
-	0x02ec,
-	0x02ee,
-	0x0386,
-	0x038c,
-	0x0559,
-	0x06d5,
-	0x06ff,
-	0x0710,
-	0x07b1,
-	0x07fa,
-	0x081a,
-	0x0824,
-	0x0828,
-	0x08a0,
-	0x093d,
-	0x0950,
-	0x09b2,
-	0x09bd,
-	0x09ce,
-	0x0a5e,
-	0x0abd,
-	0x0ad0,
-	0x0b3d,
-	0x0b71,
-	0x0b83,
-	0x0b9c,
-	0x0bd0,
-	0x0c3d,
-	0x0cbd,
-	0x0cde,
-	0x0d3d,
-	0x0d4e,
-	0x0dbd,
-	0x0e84,
-	0x0e8a,
-	0x0e8d,
-	0x0ea5,
-	0x0ea7,
-	0x0ebd,
-	0x0ec6,
-	0x0f00,
-	0x103f,
-	0x1061,
-	0x108e,
-	0x10c7,
-	0x10cd,
-	0x1258,
-	0x12c0,
-	0x17d7,
-	0x17dc,
-	0x18aa,
-	0x1aa7,
-	0x1f59,
-	0x1f5b,
-	0x1f5d,
-	0x1fbe,
-	0x2071,
-	0x207f,
-	0x2102,
-	0x2107,
-	0x2115,
-	0x2124,
-	0x2126,
-	0x2128,
-	0x214e,
-	0x2d27,
-	0x2d2d,
-	0x2d6f,
-	0x2e2f,
-	0xa8fb,
-	0xa9cf,
-	0xaa7a,
-	0xaab1,
-	0xaac0,
-	0xaac2,
-	0xfb1d,
-	0xfb3e,
-	0x10808,
-	0x1083c,
-	0x10a00,
-	0x16f50,
-	0x1d4a2,
-	0x1d4bb,
-	0x1d546,
-	0x1ee24,
-	0x1ee27,
-	0x1ee39,
-	0x1ee3b,
-	0x1ee42,
-	0x1ee47,
-	0x1ee49,
-	0x1ee4b,
-	0x1ee54,
-	0x1ee57,
-	0x1ee59,
-	0x1ee5b,
-	0x1ee5d,
-	0x1ee5f,
-	0x1ee64,
-	0x1ee7e,
-};
-
-int
-isalpharune(Rune c)
-{
-	Rune *p;
-
-	p = rbsearch(c, __isalphar, nelem(__isalphar)/2, 2);
-	if(p && c >= p[0] && c <= p[1])
-		return 1;
-	p = rbsearch(c, __isalphas, nelem(__isalphas), 1);
-	if(p && c == p[0])
-		return 1;
-	return 0;
-}
-
-static Rune __isupperr[] = {
-	0x0041, 0x005a,
-	0x00c0, 0x00d6,
-	0x00d8, 0x00de,
-	0x0178, 0x0179,
-	0x0181, 0x0182,
-	0x0186, 0x0187,
-	0x0189, 0x018b,
-	0x018e, 0x0191,
-	0x0193, 0x0194,
-	0x0196, 0x0198,
-	0x019c, 0x019d,
-	0x019f, 0x01a0,
-	0x01a6, 0x01a7,
-	0x01ae, 0x01af,
-	0x01b1, 0x01b3,
-	0x01b7, 0x01b8,
-	0x01f6, 0x01f8,
-	0x023a, 0x023b,
-	0x023d, 0x023e,
-	0x0243, 0x0246,
-	0x0388, 0x038a,
-	0x038e, 0x038f,
-	0x0391, 0x03a1,
-	0x03a3, 0x03ab,
-	0x03d2, 0x03d4,
-	0x03f9, 0x03fa,
-	0x03fd, 0x042f,
-	0x04c0, 0x04c1,
-	0x0531, 0x0556,
-	0x10a0, 0x10c5,
-	0x1f08, 0x1f0f,
-	0x1f18, 0x1f1d,
-	0x1f28, 0x1f2f,
-	0x1f38, 0x1f3f,
-	0x1f48, 0x1f4d,
-	0x1f68, 0x1f6f,
-	0x1f88, 0x1f8f,
-	0x1f98, 0x1f9f,
-	0x1fa8, 0x1faf,
-	0x1fb8, 0x1fbc,
-	0x1fc8, 0x1fcc,
-	0x1fd8, 0x1fdb,
-	0x1fe8, 0x1fec,
-	0x1ff8, 0x1ffc,
-	0x210b, 0x210d,
-	0x2110, 0x2112,
-	0x2119, 0x211d,
-	0x212a, 0x212d,
-	0x2130, 0x2133,
-	0x213e, 0x213f,
-	0x2160, 0x216f,
-	0x24b6, 0x24cf,
-	0x2c00, 0x2c2e,
-	0x2c62, 0x2c64,
-	0x2c6d, 0x2c70,
-	0x2c7e, 0x2c80,
-	0xa77d, 0xa77e,
-	0xff21, 0xff3a,
-	0x10400, 0x10427,
-	0x1d400, 0x1d419,
-	0x1d434, 0x1d44d,
-	0x1d468, 0x1d481,
-	0x1d49e, 0x1d49f,
-	0x1d4a5, 0x1d4a6,
-	0x1d4a9, 0x1d4ac,
-	0x1d4ae, 0x1d4b5,
-	0x1d4d0, 0x1d4e9,
-	0x1d504, 0x1d505,
-	0x1d507, 0x1d50a,
-	0x1d50d, 0x1d514,
-	0x1d516, 0x1d51c,
-	0x1d538, 0x1d539,
-	0x1d53b, 0x1d53e,
-	0x1d540, 0x1d544,
-	0x1d54a, 0x1d550,
-	0x1d56c, 0x1d585,
-	0x1d5a0, 0x1d5b9,
-	0x1d5d4, 0x1d5ed,
-	0x1d608, 0x1d621,
-	0x1d63c, 0x1d655,
-	0x1d670, 0x1d689,
-	0x1d6a8, 0x1d6c0,
-	0x1d6e2, 0x1d6fa,
-	0x1d71c, 0x1d734,
-	0x1d756, 0x1d76e,
-	0x1d790, 0x1d7a8,
-};
-
-static Rune __isupperp[] = {
-	0x0100, 0x0136,
-	0x0139, 0x0147,
-	0x014a, 0x0176,
-	0x017b, 0x017d,
-	0x01a2, 0x01a4,
-	0x01cd, 0x01db,
-	0x01de, 0x01ee,
-	0x01fa, 0x0232,
-	0x0248, 0x024e,
-	0x0370, 0x0372,
-	0x03d8, 0x03ee,
-	0x0460, 0x0480,
-	0x048a, 0x04be,
-	0x04c3, 0x04cd,
-	0x04d0, 0x0526,
-	0x1e00, 0x1e94,
-	0x1e9e, 0x1efe,
-	0x1f59, 0x1f5f,
-	0x2124, 0x2128,
-	0x2c67, 0x2c6b,
-	0x2c82, 0x2ce2,
-	0x2ceb, 0x2ced,
-	0xa640, 0xa66c,
-	0xa680, 0xa696,
-	0xa722, 0xa72e,
-	0xa732, 0xa76e,
-	0xa779, 0xa77b,
-	0xa780, 0xa786,
-	0xa78b, 0xa78d,
-	0xa790, 0xa792,
-	0xa7a0, 0xa7aa,
-};
-
-static Rune __isuppers[] = {
-	0x0184,
-	0x01a9,
-	0x01ac,
-	0x01b5,
-	0x01bc,
-	0x01c4,
-	0x01c7,
-	0x01ca,
-	0x01f1,
-	0x01f4,
-	0x0241,
-	0x0376,
-	0x0386,
-	0x038c,
-	0x03cf,
-	0x03f4,
-	0x03f7,
-	0x10c7,
-	0x10cd,
-	0x2102,
-	0x2107,
-	0x2115,
-	0x2145,
-	0x2183,
-	0x2c60,
-	0x2c72,
-	0x2c75,
-	0x2cf2,
-	0x1d49c,
-	0x1d4a2,
-	0x1d546,
-	0x1d7ca,
-};
-
-int
-isupperrune(Rune c)
-{
-	Rune *p;
-
-	p = rbsearch(c, __isupperr, nelem(__isupperr)/2, 2);
-	if(p && c >= p[0] && c <= p[1])
-		return 1;
-	p = rbsearch(c, __isupperp, nelem(__isupperp)/2, 2);
-	if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))
-		return 1;
-	p = rbsearch(c, __isuppers, nelem(__isuppers), 1);
-	if(p && c == p[0])
-		return 1;
-	return 0;
-}
-
-static Rune __islowerr[] = {
-	0x0061, 0x007a,
-	0x00df, 0x00f6,
-	0x00f8, 0x00ff,
-	0x0137, 0x0138,
-	0x0148, 0x0149,
-	0x017e, 0x0180,
-	0x018c, 0x018d,
-	0x0199, 0x019b,
-	0x01aa, 0x01ab,
-	0x01b9, 0x01ba,
-	0x01bd, 0x01bf,
-	0x01dc, 0x01dd,
-	0x01ef, 0x01f0,
-	0x0233, 0x0239,
-	0x023f, 0x0240,
-	0x024f, 0x0293,
-	0x0295, 0x02af,
-	0x037b, 0x037d,
-	0x03ac, 0x03ce,
-	0x03d0, 0x03d1,
-	0x03d5, 0x03d7,
-	0x03ef, 0x03f3,
-	0x03fb, 0x03fc,
-	0x0430, 0x045f,
-	0x04ce, 0x04cf,
-	0x0561, 0x0587,
-	0x1d00, 0x1d2b,
-	0x1d6b, 0x1d77,
-	0x1d79, 0x1d9a,
-	0x1e95, 0x1e9d,
-	0x1eff, 0x1f07,
-	0x1f10, 0x1f15,
-	0x1f20, 0x1f27,
-	0x1f30, 0x1f37,
-	0x1f40, 0x1f45,
-	0x1f50, 0x1f57,
-	0x1f60, 0x1f67,
-	0x1f70, 0x1f7d,
-	0x1f80, 0x1f87,
-	0x1f90, 0x1f97,
-	0x1fa0, 0x1fa7,
-	0x1fb0, 0x1fb4,
-	0x1fb6, 0x1fb7,
-	0x1fc2, 0x1fc4,
-	0x1fc6, 0x1fc7,
-	0x1fd0, 0x1fd3,
-	0x1fd6, 0x1fd7,
-	0x1fe0, 0x1fe7,
-	0x1ff2, 0x1ff4,
-	0x1ff6, 0x1ff7,
-	0x210e, 0x210f,
-	0x213c, 0x213d,
-	0x2146, 0x2149,
-	0x2170, 0x217f,
-	0x24d0, 0x24e9,
-	0x2c30, 0x2c5e,
-	0x2c65, 0x2c66,
-	0x2c73, 0x2c74,
-	0x2c76, 0x2c7b,
-	0x2ce3, 0x2ce4,
-	0x2d00, 0x2d25,
-	0xa72f, 0xa731,
-	0xa771, 0xa778,
-	0xfb00, 0xfb06,
-	0xfb13, 0xfb17,
-	0xff41, 0xff5a,
-	0x10428, 0x1044f,
-	0x1d41a, 0x1d433,
-	0x1d44e, 0x1d454,
-	0x1d456, 0x1d467,
-	0x1d482, 0x1d49b,
-	0x1d4b6, 0x1d4b9,
-	0x1d4bd, 0x1d4c3,
-	0x1d4c5, 0x1d4cf,
-	0x1d4ea, 0x1d503,
-	0x1d51e, 0x1d537,
-	0x1d552, 0x1d56b,
-	0x1d586, 0x1d59f,
-	0x1d5ba, 0x1d5d3,
-	0x1d5ee, 0x1d607,
-	0x1d622, 0x1d63b,
-	0x1d656, 0x1d66f,
-	0x1d68a, 0x1d6a5,
-	0x1d6c2, 0x1d6da,
-	0x1d6dc, 0x1d6e1,
-	0x1d6fc, 0x1d714,
-	0x1d716, 0x1d71b,
-	0x1d736, 0x1d74e,
-	0x1d750, 0x1d755,
-	0x1d770, 0x1d788,
-	0x1d78a, 0x1d78f,
-	0x1d7aa, 0x1d7c2,
-	0x1d7c4, 0x1d7c9,
-};
-
-static Rune __islowerp[] = {
-	0x0101, 0x0135,
-	0x013a, 0x0146,
-	0x014b, 0x0177,
-	0x017a, 0x017c,
-	0x0183, 0x0185,
-	0x01a1, 0x01a5,
-	0x01b4, 0x01b6,
-	0x01cc, 0x01da,
-	0x01df, 0x01ed,
-	0x01f3, 0x01f5,
-	0x01f9, 0x0231,
-	0x0247, 0x024d,
-	0x0371, 0x0373,
-	0x03d9, 0x03ed,
-	0x0461, 0x0481,
-	0x048b, 0x04bf,
-	0x04c2, 0x04cc,
-	0x04d1, 0x0527,
-	0x1e01, 0x1e93,
-	0x1e9f, 0x1efd,
-	0x2c68, 0x2c6c,
-	0x2c81, 0x2ce1,
-	0x2cec, 0x2cee,
-	0xa641, 0xa66d,
-	0xa681, 0xa697,
-	0xa723, 0xa72d,
-	0xa733, 0xa76f,
-	0xa77a, 0xa77c,
-	0xa77f, 0xa787,
-	0xa78c, 0xa78e,
-	0xa791, 0xa793,
-	0xa7a1, 0xa7a9,
-};
-
-static Rune __islowers[] = {
-	0x00b5,
-	0x0188,
-	0x0192,
-	0x0195,
-	0x019e,
-	0x01a8,
-	0x01ad,
-	0x01b0,
-	0x01c6,
-	0x01c9,
-	0x023c,
-	0x0242,
-	0x0377,
-	0x0390,
-	0x03f5,
-	0x03f8,
-	0x1fbe,
-	0x210a,
-	0x2113,
-	0x212f,
-	0x2134,
-	0x2139,
-	0x214e,
-	0x2184,
-	0x2c61,
-	0x2c71,
-	0x2cf3,
-	0x2d27,
-	0x2d2d,
-	0xa7fa,
-	0x1d4bb,
-	0x1d7cb,
-};
-
-int
-islowerrune(Rune c)
-{
-	Rune *p;
-
-	p = rbsearch(c, __islowerr, nelem(__islowerr)/2, 2);
-	if(p && c >= p[0] && c <= p[1])
-		return 1;
-	p = rbsearch(c, __islowerp, nelem(__islowerp)/2, 2);
-	if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))
-		return 1;
-	p = rbsearch(c, __islowers, nelem(__islowers), 1);
-	if(p && c == p[0])
-		return 1;
-	return 0;
-}
-
-static Rune __istitler[] = {
-	0x0041, 0x005a,
-	0x00c0, 0x00d6,
-	0x00d8, 0x00de,
-	0x0178, 0x0179,
-	0x0181, 0x0182,
-	0x0186, 0x0187,
-	0x0189, 0x018b,
-	0x018e, 0x0191,
-	0x0193, 0x0194,
-	0x0196, 0x0198,
-	0x019c, 0x019d,
-	0x019f, 0x01a0,
-	0x01a6, 0x01a7,
-	0x01ae, 0x01af,
-	0x01b1, 0x01b3,
-	0x01b7, 0x01b8,
-	0x01f6, 0x01f8,
-	0x023a, 0x023b,
-	0x023d, 0x023e,
-	0x0243, 0x0246,
-	0x0388, 0x038a,
-	0x038e, 0x038f,
-	0x0391, 0x03a1,
-	0x03a3, 0x03ab,
-	0x03f9, 0x03fa,
-	0x03fd, 0x042f,
-	0x04c0, 0x04c1,
-	0x0531, 0x0556,
-	0x10a0, 0x10c5,
-	0x1f08, 0x1f0f,
-	0x1f18, 0x1f1d,
-	0x1f28, 0x1f2f,
-	0x1f38, 0x1f3f,
-	0x1f48, 0x1f4d,
-	0x1f68, 0x1f6f,
-	0x1f88, 0x1f8f,
-	0x1f98, 0x1f9f,
-	0x1fa8, 0x1faf,
-	0x1fb8, 0x1fbc,
-	0x1fc8, 0x1fcc,
-	0x1fd8, 0x1fdb,
-	0x1fe8, 0x1fec,
-	0x1ff8, 0x1ffc,
-	0x2160, 0x216f,
-	0x24b6, 0x24cf,
-	0x2c00, 0x2c2e,
-	0x2c62, 0x2c64,
-	0x2c6d, 0x2c70,
-	0x2c7e, 0x2c80,
-	0xa77d, 0xa77e,
-	0xff21, 0xff3a,
-	0x10400, 0x10427,
-};
-
-static Rune __istitlep[] = {
-	0x0100, 0x012e,
-	0x0132, 0x0136,
-	0x0139, 0x0147,
-	0x014a, 0x0176,
-	0x017b, 0x017d,
-	0x01a2, 0x01a4,
-	0x01cb, 0x01db,
-	0x01de, 0x01ee,
-	0x01f2, 0x01f4,
-	0x01fa, 0x0232,
-	0x0248, 0x024e,
-	0x0370, 0x0372,
-	0x03d8, 0x03ee,
-	0x0460, 0x0480,
-	0x048a, 0x04be,
-	0x04c3, 0x04cd,
-	0x04d0, 0x0526,
-	0x1e00, 0x1e94,
-	0x1ea0, 0x1efe,
-	0x1f59, 0x1f5f,
-	0x2c67, 0x2c6b,
-	0x2c82, 0x2ce2,
-	0x2ceb, 0x2ced,
-	0xa640, 0xa66c,
-	0xa680, 0xa696,
-	0xa722, 0xa72e,
-	0xa732, 0xa76e,
-	0xa779, 0xa77b,
-	0xa780, 0xa786,
-	0xa78b, 0xa78d,
-	0xa790, 0xa792,
-	0xa7a0, 0xa7aa,
-};
-
-static Rune __istitles[] = {
-	0x0184,
-	0x01a9,
-	0x01ac,
-	0x01b5,
-	0x01bc,
-	0x01c5,
-	0x01c8,
-	0x0241,
-	0x0376,
-	0x0386,
-	0x038c,
-	0x03cf,
-	0x03f7,
-	0x10c7,
-	0x10cd,
-	0x2132,
-	0x2183,
-	0x2c60,
-	0x2c72,
-	0x2c75,
-	0x2cf2,
-};
-
-int
-istitlerune(Rune c)
-{
-	Rune *p;
-
-	p = rbsearch(c, __istitler, nelem(__istitler)/2, 2);
-	if(p && c >= p[0] && c <= p[1])
-		return 1;
-	p = rbsearch(c, __istitlep, nelem(__istitlep)/2, 2);
-	if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))
-		return 1;
-	p = rbsearch(c, __istitles, nelem(__istitles), 1);
-	if(p && c == p[0])
-		return 1;
-	return 0;
-}
-
-static Rune __toupperr[] = {
-	0x0061, 0x007a, 1048544,
-	0x00e0, 0x00f6, 1048544,
-	0x00f8, 0x00fe, 1048544,
-	0x023f, 0x0240, 1059391,
-	0x0256, 0x0257, 1048371,
-	0x028a, 0x028b, 1048359,
-	0x037b, 0x037d, 1048706,
-	0x03ad, 0x03af, 1048539,
-	0x03b1, 0x03c1, 1048544,
-	0x03c3, 0x03cb, 1048544,
-	0x03cd, 0x03ce, 1048513,
-	0x0430, 0x044f, 1048544,
-	0x0450, 0x045f, 1048496,
-	0x0561, 0x0586, 1048528,
-	0x1f00, 0x1f07, 1048584,
-	0x1f10, 0x1f15, 1048584,
-	0x1f20, 0x1f27, 1048584,
-	0x1f30, 0x1f37, 1048584,
-	0x1f40, 0x1f45, 1048584,
-	0x1f60, 0x1f67, 1048584,
-	0x1f70, 0x1f71, 1048650,
-	0x1f72, 0x1f75, 1048662,
-	0x1f76, 0x1f77, 1048676,
-	0x1f78, 0x1f79, 1048704,
-	0x1f7a, 0x1f7b, 1048688,
-	0x1f7c, 0x1f7d, 1048702,
-	0x1f80, 0x1f87, 1048584,
-	0x1f90, 0x1f97, 1048584,
-	0x1fa0, 0x1fa7, 1048584,
-	0x1fb0, 0x1fb1, 1048584,
-	0x1fd0, 0x1fd1, 1048584,
-	0x1fe0, 0x1fe1, 1048584,
-	0x2170, 0x217f, 1048560,
-	0x24d0, 0x24e9, 1048550,
-	0x2c30, 0x2c5e, 1048528,
-	0x2d00, 0x2d25, 1041312,
-	0xff41, 0xff5a, 1048544,
-	0x10428, 0x1044f, 1048536,
-};
-
-static Rune __toupperp[] = {
-	0x0101, 0x012f, 1048575,
-	0x0133, 0x0137, 1048575,
-	0x013a, 0x0148, 1048575,
-	0x014b, 0x0177, 1048575,
-	0x017a, 0x017e, 1048575,
-	0x0183, 0x0185, 1048575,
-	0x01a1, 0x01a5, 1048575,
-	0x01b4, 0x01b6, 1048575,
-	0x01ce, 0x01dc, 1048575,
-	0x01df, 0x01ef, 1048575,
-	0x01f9, 0x021f, 1048575,
-	0x0223, 0x0233, 1048575,
-	0x0247, 0x024f, 1048575,
-	0x0371, 0x0373, 1048575,
-	0x03d9, 0x03ef, 1048575,
-	0x0461, 0x0481, 1048575,
-	0x048b, 0x04bf, 1048575,
-	0x04c2, 0x04ce, 1048575,
-	0x04d1, 0x0527, 1048575,
-	0x1e01, 0x1e95, 1048575,
-	0x1ea1, 0x1eff, 1048575,
-	0x1f51, 0x1f57, 1048584,
-	0x2c68, 0x2c6c, 1048575,
-	0x2c81, 0x2ce3, 1048575,
-	0x2cec, 0x2cee, 1048575,
-	0xa641, 0xa66d, 1048575,
-	0xa681, 0xa697, 1048575,
-	0xa723, 0xa72f, 1048575,
-	0xa733, 0xa76f, 1048575,
-	0xa77a, 0xa77c, 1048575,
-	0xa77f, 0xa787, 1048575,
-	0xa791, 0xa793, 1048575,
-	0xa7a1, 0xa7a9, 1048575,
-};
-
-static Rune __touppers[] = {
-	0x00b5, 1049319,
-	0x00ff, 1048697,
-	0x0131, 1048344,
-	0x017f, 1048276,
-	0x0180, 1048771,
-	0x0188, 1048575,
-	0x018c, 1048575,
-	0x0192, 1048575,
-	0x0195, 1048673,
-	0x0199, 1048575,
-	0x019a, 1048739,
-	0x019e, 1048706,
-	0x01a8, 1048575,
-	0x01ad, 1048575,
-	0x01b0, 1048575,
-	0x01b9, 1048575,
-	0x01bd, 1048575,
-	0x01bf, 1048632,
-	0x01c5, 1048575,
-	0x01c6, 1048574,
-	0x01c8, 1048575,
-	0x01c9, 1048574,
-	0x01cb, 1048575,
-	0x01cc, 1048574,
-	0x01dd, 1048497,
-	0x01f2, 1048575,
-	0x01f3, 1048574,
-	0x01f5, 1048575,
-	0x023c, 1048575,
-	0x0242, 1048575,
-	0x0250, 1059359,
-	0x0251, 1059356,
-	0x0252, 1059358,
-	0x0253, 1048366,
-	0x0254, 1048370,
-	0x0259, 1048374,
-	0x025b, 1048373,
-	0x0260, 1048371,
-	0x0263, 1048369,
-	0x0265, 1090856,
-	0x0266, 1090884,
-	0x0268, 1048367,
-	0x0269, 1048365,
-	0x026b, 1059319,
-	0x026f, 1048365,
-	0x0271, 1059325,
-	0x0272, 1048363,
-	0x0275, 1048362,
-	0x027d, 1059303,
-	0x0280, 1048358,
-	0x0283, 1048358,
-	0x0288, 1048358,
-	0x0289, 1048507,
-	0x028c, 1048505,
-	0x0292, 1048357,
-	0x0345, 1048660,
-	0x0377, 1048575,
-	0x03ac, 1048538,
-	0x03c2, 1048545,
-	0x03cc, 1048512,
-	0x03d0, 1048514,
-	0x03d1, 1048519,
-	0x03d5, 1048529,
-	0x03d6, 1048522,
-	0x03d7, 1048568,
-	0x03f0, 1048490,
-	0x03f1, 1048496,
-	0x03f2, 1048583,
-	0x03f5, 1048480,
-	0x03f8, 1048575,
-	0x03fb, 1048575,
-	0x04cf, 1048561,
-	0x1d79, 1083908,
-	0x1d7d, 1052390,
-	0x1e9b, 1048517,
-	0x1fb3, 1048585,
-	0x1fbe, 1041371,
-	0x1fc3, 1048585,
-	0x1fe5, 1048583,
-	0x1ff3, 1048585,
-	0x214e, 1048548,
-	0x2184, 1048575,
-	0x2c61, 1048575,
-	0x2c65, 1037781,
-	0x2c66, 1037784,
-	0x2c73, 1048575,
-	0x2c76, 1048575,
-	0x2cf3, 1048575,
-	0x2d27, 1041312,
-	0x2d2d, 1041312,
-	0xa78c, 1048575,
-};
-
-Rune
-toupperrune(Rune c)
-{
-	Rune *p;
-
-	p = rbsearch(c, __toupperr, nelem(__toupperr)/3, 3);
-	if(p && c >= p[0] && c <= p[1])
-		return c + p[2] - 1048576;
-	p = rbsearch(c, __toupperp, nelem(__toupperp)/3, 3);
-	if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))
-		return c + p[2] - 1048576;
-	p = rbsearch(c, __touppers, nelem(__touppers)/2, 2);
-	if(p && c == p[0])
-		return c + p[1] - 1048576;
-	return c;
-}
-
-static Rune __tolowerr[] = {
-	0x0041, 0x005a, 1048608,
-	0x00c0, 0x00d6, 1048608,
-	0x00d8, 0x00de, 1048608,
-	0x0189, 0x018a, 1048781,
-	0x01b1, 0x01b2, 1048793,
-	0x0388, 0x038a, 1048613,
-	0x038e, 0x038f, 1048639,
-	0x0391, 0x03a1, 1048608,
-	0x03a3, 0x03ab, 1048608,
-	0x03fd, 0x03ff, 1048446,
-	0x0400, 0x040f, 1048656,
-	0x0410, 0x042f, 1048608,
-	0x0531, 0x0556, 1048624,
-	0x10a0, 0x10c5, 1055840,
-	0x1f08, 0x1f0f, 1048568,
-	0x1f18, 0x1f1d, 1048568,
-	0x1f28, 0x1f2f, 1048568,
-	0x1f38, 0x1f3f, 1048568,
-	0x1f48, 0x1f4d, 1048568,
-	0x1f68, 0x1f6f, 1048568,
-	0x1f88, 0x1f8f, 1048568,
-	0x1f98, 0x1f9f, 1048568,
-	0x1fa8, 0x1faf, 1048568,
-	0x1fb8, 0x1fb9, 1048568,
-	0x1fba, 0x1fbb, 1048502,
-	0x1fc8, 0x1fcb, 1048490,
-	0x1fd8, 0x1fd9, 1048568,
-	0x1fda, 0x1fdb, 1048476,
-	0x1fe8, 0x1fe9, 1048568,
-	0x1fea, 0x1feb, 1048464,
-	0x1ff8, 0x1ff9, 1048448,
-	0x1ffa, 0x1ffb, 1048450,
-	0x2160, 0x216f, 1048592,
-	0x24b6, 0x24cf, 1048602,
-	0x2c00, 0x2c2e, 1048624,
-	0x2c7e, 0x2c7f, 1037761,
-	0xff21, 0xff3a, 1048608,
-	0x10400, 0x10427, 1048616,
-};
-
-static Rune __tolowerp[] = {
-	0x0100, 0x012e, 1048577,
-	0x0132, 0x0136, 1048577,
-	0x0139, 0x0147, 1048577,
-	0x014a, 0x0176, 1048577,
-	0x017b, 0x017d, 1048577,
-	0x01a2, 0x01a4, 1048577,
-	0x01b3, 0x01b5, 1048577,
-	0x01cd, 0x01db, 1048577,
-	0x01de, 0x01ee, 1048577,
-	0x01f8, 0x021e, 1048577,
-	0x0222, 0x0232, 1048577,
-	0x0248, 0x024e, 1048577,
-	0x0370, 0x0372, 1048577,
-	0x03d8, 0x03ee, 1048577,
-	0x0460, 0x0480, 1048577,
-	0x048a, 0x04be, 1048577,
-	0x04c3, 0x04cd, 1048577,
-	0x04d0, 0x0526, 1048577,
-	0x1e00, 0x1e94, 1048577,
-	0x1ea0, 0x1efe, 1048577,
-	0x1f59, 0x1f5f, 1048568,
-	0x2c67, 0x2c6b, 1048577,
-	0x2c80, 0x2ce2, 1048577,
-	0x2ceb, 0x2ced, 1048577,
-	0xa640, 0xa66c, 1048577,
-	0xa680, 0xa696, 1048577,
-	0xa722, 0xa72e, 1048577,
-	0xa732, 0xa76e, 1048577,
-	0xa779, 0xa77b, 1048577,
-	0xa780, 0xa786, 1048577,
-	0xa790, 0xa792, 1048577,
-	0xa7a0, 0xa7a8, 1048577,
-};
-
-static Rune __tolowers[] = {
-	0x0130, 1048377,
-	0x0178, 1048455,
-	0x0179, 1048577,
-	0x0181, 1048786,
-	0x0182, 1048577,
-	0x0184, 1048577,
-	0x0186, 1048782,
-	0x0187, 1048577,
-	0x018b, 1048577,
-	0x018e, 1048655,
-	0x018f, 1048778,
-	0x0190, 1048779,
-	0x0191, 1048577,
-	0x0193, 1048781,
-	0x0194, 1048783,
-	0x0196, 1048787,
-	0x0197, 1048785,
-	0x0198, 1048577,
-	0x019c, 1048787,
-	0x019d, 1048789,
-	0x019f, 1048790,
-	0x01a0, 1048577,
-	0x01a6, 1048794,
-	0x01a7, 1048577,
-	0x01a9, 1048794,
-	0x01ac, 1048577,
-	0x01ae, 1048794,
-	0x01af, 1048577,
-	0x01b7, 1048795,
-	0x01b8, 1048577,
-	0x01bc, 1048577,
-	0x01c4, 1048578,
-	0x01c5, 1048577,
-	0x01c7, 1048578,
-	0x01c8, 1048577,
-	0x01ca, 1048578,
-	0x01cb, 1048577,
-	0x01f1, 1048578,
-	0x01f2, 1048577,
-	0x01f4, 1048577,
-	0x01f6, 1048479,
-	0x01f7, 1048520,
-	0x0220, 1048446,
-	0x023a, 1059371,
-	0x023b, 1048577,
-	0x023d, 1048413,
-	0x023e, 1059368,
-	0x0241, 1048577,
-	0x0243, 1048381,
-	0x0244, 1048645,
-	0x0245, 1048647,
-	0x0246, 1048577,
-	0x0376, 1048577,
-	0x0386, 1048614,
-	0x038c, 1048640,
-	0x03cf, 1048584,
-	0x03f4, 1048516,
-	0x03f7, 1048577,
-	0x03f9, 1048569,
-	0x03fa, 1048577,
-	0x04c0, 1048591,
-	0x04c1, 1048577,
-	0x10c7, 1055840,
-	0x10cd, 1055840,
-	0x1e9e, 1040961,
-	0x1fbc, 1048567,
-	0x1fcc, 1048567,
-	0x1fec, 1048569,
-	0x1ffc, 1048567,
-	0x2126, 1041059,
-	0x212a, 1040193,
-	0x212b, 1040314,
-	0x2132, 1048604,
-	0x2183, 1048577,
-	0x2c60, 1048577,
-	0x2c62, 1037833,
-	0x2c63, 1044762,
-	0x2c64, 1037849,
-	0x2c6d, 1037796,
-	0x2c6e, 1037827,
-	0x2c6f, 1037793,
-	0x2c70, 1037794,
-	0x2c72, 1048577,
-	0x2c75, 1048577,
-	0x2cf2, 1048577,
-	0xa77d, 1013244,
-	0xa77e, 1048577,
-	0xa78b, 1048577,
-	0xa78d, 1006296,
-	0xa7aa, 1006268,
-};
-
-Rune
-tolowerrune(Rune c)
-{
-	Rune *p;
-
-	p = rbsearch(c, __tolowerr, nelem(__tolowerr)/3, 3);
-	if(p && c >= p[0] && c <= p[1])
-		return c + p[2] - 1048576;
-	p = rbsearch(c, __tolowerp, nelem(__tolowerp)/3, 3);
-	if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))
-		return c + p[2] - 1048576;
-	p = rbsearch(c, __tolowers, nelem(__tolowers)/2, 2);
-	if(p && c == p[0])
-		return c + p[1] - 1048576;
-	return c;
-}
-
-static Rune __totitler[] = {
-	0x0061, 0x007a, 1048544,
-	0x00e0, 0x00f6, 1048544,
-	0x00f8, 0x00fe, 1048544,
-	0x023f, 0x0240, 1059391,
-	0x0256, 0x0257, 1048371,
-	0x028a, 0x028b, 1048359,
-	0x037b, 0x037d, 1048706,
-	0x03ad, 0x03af, 1048539,
-	0x03b1, 0x03c1, 1048544,
-	0x03c3, 0x03cb, 1048544,
-	0x03cd, 0x03ce, 1048513,
-	0x0430, 0x044f, 1048544,
-	0x0450, 0x045f, 1048496,
-	0x0561, 0x0586, 1048528,
-	0x1f00, 0x1f07, 1048584,
-	0x1f10, 0x1f15, 1048584,
-	0x1f20, 0x1f27, 1048584,
-	0x1f30, 0x1f37, 1048584,
-	0x1f40, 0x1f45, 1048584,
-	0x1f60, 0x1f67, 1048584,
-	0x1f70, 0x1f71, 1048650,
-	0x1f72, 0x1f75, 1048662,
-	0x1f76, 0x1f77, 1048676,
-	0x1f78, 0x1f79, 1048704,
-	0x1f7a, 0x1f7b, 1048688,
-	0x1f7c, 0x1f7d, 1048702,
-	0x1f80, 0x1f87, 1048584,
-	0x1f90, 0x1f97, 1048584,
-	0x1fa0, 0x1fa7, 1048584,
-	0x1fb0, 0x1fb1, 1048584,
-	0x1fd0, 0x1fd1, 1048584,
-	0x1fe0, 0x1fe1, 1048584,
-	0x2170, 0x217f, 1048560,
-	0x24d0, 0x24e9, 1048550,
-	0x2c30, 0x2c5e, 1048528,
-	0x2d00, 0x2d25, 1041312,
-	0xff41, 0xff5a, 1048544,
-	0x10428, 0x1044f, 1048536,
-};
-
-static Rune __totitlep[] = {
-	0x0101, 0x012f, 1048575,
-	0x0133, 0x0137, 1048575,
-	0x013a, 0x0148, 1048575,
-	0x014b, 0x0177, 1048575,
-	0x017a, 0x017e, 1048575,
-	0x0183, 0x0185, 1048575,
-	0x01a1, 0x01a5, 1048575,
-	0x01b4, 0x01b6, 1048575,
-	0x01cc, 0x01dc, 1048575,
-	0x01df, 0x01ef, 1048575,
-	0x01f3, 0x01f5, 1048575,
-	0x01f9, 0x021f, 1048575,
-	0x0223, 0x0233, 1048575,
-	0x0247, 0x024f, 1048575,
-	0x0371, 0x0373, 1048575,
-	0x03d9, 0x03ef, 1048575,
-	0x0461, 0x0481, 1048575,
-	0x048b, 0x04bf, 1048575,
-	0x04c2, 0x04ce, 1048575,
-	0x04d1, 0x0527, 1048575,
-	0x1e01, 0x1e95, 1048575,
-	0x1ea1, 0x1eff, 1048575,
-	0x1f51, 0x1f57, 1048584,
-	0x2c68, 0x2c6c, 1048575,
-	0x2c81, 0x2ce3, 1048575,
-	0x2cec, 0x2cee, 1048575,
-	0xa641, 0xa66d, 1048575,
-	0xa681, 0xa697, 1048575,
-	0xa723, 0xa72f, 1048575,
-	0xa733, 0xa76f, 1048575,
-	0xa77a, 0xa77c, 1048575,
-	0xa77f, 0xa787, 1048575,
-	0xa791, 0xa793, 1048575,
-	0xa7a1, 0xa7a9, 1048575,
-};
-
-static Rune __totitles[] = {
-	0x00b5, 1049319,
-	0x00ff, 1048697,
-	0x0131, 1048344,
-	0x017f, 1048276,
-	0x0180, 1048771,
-	0x0188, 1048575,
-	0x018c, 1048575,
-	0x0192, 1048575,
-	0x0195, 1048673,
-	0x0199, 1048575,
-	0x019a, 1048739,
-	0x019e, 1048706,
-	0x01a8, 1048575,
-	0x01ad, 1048575,
-	0x01b0, 1048575,
-	0x01b9, 1048575,
-	0x01bd, 1048575,
-	0x01bf, 1048632,
-	0x01c4, 1048577,
-	0x01c6, 1048575,
-	0x01c7, 1048577,
-	0x01c9, 1048575,
-	0x01ca, 1048577,
-	0x01dd, 1048497,
-	0x01f1, 1048577,
-	0x023c, 1048575,
-	0x0242, 1048575,
-	0x0250, 1059359,
-	0x0251, 1059356,
-	0x0252, 1059358,
-	0x0253, 1048366,
-	0x0254, 1048370,
-	0x0259, 1048374,
-	0x025b, 1048373,
-	0x0260, 1048371,
-	0x0263, 1048369,
-	0x0265, 1090856,
-	0x0266, 1090884,
-	0x0268, 1048367,
-	0x0269, 1048365,
-	0x026b, 1059319,
-	0x026f, 1048365,
-	0x0271, 1059325,
-	0x0272, 1048363,
-	0x0275, 1048362,
-	0x027d, 1059303,
-	0x0280, 1048358,
-	0x0283, 1048358,
-	0x0288, 1048358,
-	0x0289, 1048507,
-	0x028c, 1048505,
-	0x0292, 1048357,
-	0x0345, 1048660,
-	0x0377, 1048575,
-	0x03ac, 1048538,
-	0x03c2, 1048545,
-	0x03cc, 1048512,
-	0x03d0, 1048514,
-	0x03d1, 1048519,
-	0x03d5, 1048529,
-	0x03d6, 1048522,
-	0x03d7, 1048568,
-	0x03f0, 1048490,
-	0x03f1, 1048496,
-	0x03f2, 1048583,
-	0x03f5, 1048480,
-	0x03f8, 1048575,
-	0x03fb, 1048575,
-	0x04cf, 1048561,
-	0x1d79, 1083908,
-	0x1d7d, 1052390,
-	0x1e9b, 1048517,
-	0x1fb3, 1048585,
-	0x1fbe, 1041371,
-	0x1fc3, 1048585,
-	0x1fe5, 1048583,
-	0x1ff3, 1048585,
-	0x214e, 1048548,
-	0x2184, 1048575,
-	0x2c61, 1048575,
-	0x2c65, 1037781,
-	0x2c66, 1037784,
-	0x2c73, 1048575,
-	0x2c76, 1048575,
-	0x2cf3, 1048575,
-	0x2d27, 1041312,
-	0x2d2d, 1041312,
-	0xa78c, 1048575,
-};
-
-Rune
-totitlerune(Rune c)
-{
-	Rune *p;
-
-	p = rbsearch(c, __totitler, nelem(__totitler)/3, 3);
-	if(p && c >= p[0] && c <= p[1])
-		return c + p[2] - 1048576;
-	p = rbsearch(c, __totitlep, nelem(__totitlep)/3, 3);
-	if(p && c >= p[0] && c <= p[1] && !((c - p[0]) & 1))
-		return c + p[2] - 1048576;
-	p = rbsearch(c, __totitles, nelem(__totitles)/2, 2);
-	if(p && c == p[0])
-		return c + p[1] - 1048576;
-	return c;
-}
-
diff --git a/src/lib9/utf/utf.h b/src/lib9/utf/utf.h
deleted file mode 100644
index 72d01ed..0000000
--- a/src/lib9/utf/utf.h
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- *              Copyright (c) 1998-2002 by Lucent Technologies.
- *              Portions Copyright (c) 2009 The Go Authors.  All rights reserved.
- * 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.
- */
-
-#ifndef _UTFH_
-#define _UTFH_ 1
-
-typedef unsigned int Rune;	/* Code-point values in Unicode 4.0 are 21 bits wide.*/
-
-enum
-{
-  UTFmax	= 4,		/* maximum bytes per rune */
-  Runesync	= 0x80,		/* cannot represent part of a UTF sequence (<) */
-  Runeself	= 0x80,		/* rune and UTF sequences are the same (<) */
-  Runeerror	= 0xFFFD,	/* decoding error in UTF */
-  Runemax	= 0x10FFFF,	/* maximum rune value */
-};
-
-#ifdef	__cplusplus
-extern "C" {
-#endif
-
-/*
- * rune routines
- */
-
-/*
- * These routines were written by Rob Pike and Ken Thompson
- * and first appeared in Plan 9.
- * SEE ALSO
- * utf (7)
- * tcs (1)
-*/
-
-// runetochar copies (encodes) one rune, pointed to by r, to at most
-// UTFmax bytes starting at s and returns the number of bytes generated.
-
-int runetochar(char* s, const Rune* r);
-
-
-// chartorune copies (decodes) at most UTFmax bytes starting at s to
-// one rune, pointed to by r, and returns the number of bytes consumed.
-// If the input is not exactly in UTF format, chartorune will set *r
-// to Runeerror and return 1.
-//
-// Note: There is no special case for a "null-terminated" string. A
-// string whose first byte has the value 0 is the UTF8 encoding of the
-// Unicode value 0 (i.e., ASCII NULL). A byte value of 0 is illegal
-// anywhere else in a UTF sequence.
-
-int chartorune(Rune* r, const char* s);
-
-
-// charntorune is like chartorune, except that it will access at most
-// n bytes of s.  If the UTF sequence is incomplete within n bytes,
-// charntorune will set *r to Runeerror and return 0. If it is complete
-// but not in UTF format, it will set *r to Runeerror and return 1.
-//
-// Added 2004-09-24 by Wei-Hwa Huang
-
-int charntorune(Rune* r, const char* s, int n);
-
-// isvalidcharntorune(str, n, r, consumed)
-// is a convenience function that calls "*consumed = charntorune(r, str, n)"
-// and returns an int (logically boolean) indicating whether the first
-// n bytes of str was a valid and complete UTF sequence.
-
-int isvalidcharntorune(const char* str, int n, Rune* r, int* consumed);
-
-// runelen returns the number of bytes required to convert r into UTF.
-
-int runelen(Rune r);
-
-
-// runenlen returns the number of bytes required to convert the n
-// runes pointed to by r into UTF.
-
-int runenlen(const Rune* r, int n);
-
-
-// fullrune returns 1 if the string s of length n is long enough to be
-// decoded by chartorune, and 0 otherwise. This does not guarantee
-// that the string contains a legal UTF encoding. This routine is used
-// by programs that obtain input one byte at a time and need to know
-// when a full rune has arrived.
-
-int fullrune(const char* s, int n);
-
-// The following routines are analogous to the corresponding string
-// routines with "utf" substituted for "str", and "rune" substituted
-// for "chr".
-
-// utflen returns the number of runes that are represented by the UTF
-// string s. (cf. strlen)
-
-int utflen(const char* s);
-
-
-// utfnlen returns the number of complete runes that are represented
-// by the first n bytes of the UTF string s. If the last few bytes of
-// the string contain an incompletely coded rune, utfnlen will not
-// count them; in this way, it differs from utflen, which includes
-// every byte of the string. (cf. strnlen)
-
-int utfnlen(const char* s, long n);
-
-
-// utfrune returns a pointer to the first occurrence of rune r in the
-// UTF string s, or 0 if r does not occur in the string.  The NULL
-// byte terminating a string is considered to be part of the string s.
-// (cf. strchr)
-
-/*const*/ char* utfrune(const char* s, Rune r);
-
-
-// utfrrune returns a pointer to the last occurrence of rune r in the
-// UTF string s, or 0 if r does not occur in the string.  The NULL
-// byte terminating a string is considered to be part of the string s.
-// (cf. strrchr)
-
-/*const*/ char* utfrrune(const char* s, Rune r);
-
-
-// utfutf returns a pointer to the first occurrence of the UTF string
-// s2 as a UTF substring of s1, or 0 if there is none. If s2 is the
-// null string, utfutf returns s1. (cf. strstr)
-
-const char* utfutf(const char* s1, const char* s2);
-
-
-// utfecpy copies UTF sequences until a null sequence has been copied,
-// but writes no sequences beyond es1.  If any sequences are copied,
-// s1 is terminated by a null sequence, and a pointer to that sequence
-// is returned.  Otherwise, the original s1 is returned. (cf. strecpy)
-
-char* utfecpy(char *s1, char *es1, const char *s2);
-
-
-
-// These functions are rune-string analogues of the corresponding
-// functions in strcat (3).
-//
-// These routines first appeared in Plan 9.
-// SEE ALSO
-// memmove (3)
-// rune (3)
-// strcat (2)
-//
-// BUGS: The outcome of overlapping moves varies among implementations.
-
-Rune* runestrcat(Rune* s1, const Rune* s2);
-Rune* runestrncat(Rune* s1, const Rune* s2, long n);
-
-const Rune* runestrchr(const Rune* s, Rune c);
-
-int runestrcmp(const Rune* s1, const Rune* s2);
-int runestrncmp(const Rune* s1, const Rune* s2, long n);
-
-Rune* runestrcpy(Rune* s1, const Rune* s2);
-Rune* runestrncpy(Rune* s1, const Rune* s2, long n);
-Rune* runestrecpy(Rune* s1, Rune* es1, const Rune* s2);
-
-Rune* runestrdup(const Rune* s);
-
-const Rune* runestrrchr(const Rune* s, Rune c);
-long runestrlen(const Rune* s);
-const Rune* runestrstr(const Rune* s1, const Rune* s2);
-
-
-
-// The following routines test types and modify cases for Unicode
-// characters.  Unicode defines some characters as letters and
-// specifies three cases: upper, lower, and title.  Mappings among the
-// cases are also defined, although they are not exhaustive: some
-// upper case letters have no lower case mapping, and so on.  Unicode
-// also defines several character properties, a subset of which are
-// checked by these routines.  These routines are based on Unicode
-// version 3.0.0.
-//
-// NOTE: The routines are implemented in C, so the boolean functions
-// (e.g., isupperrune) return 0 for false and 1 for true.
-//
-//
-// toupperrune, tolowerrune, and totitlerune are the Unicode case
-// mappings. These routines return the character unchanged if it has
-// no defined mapping.
-
-Rune toupperrune(Rune r);
-Rune tolowerrune(Rune r);
-Rune totitlerune(Rune r);
-
-
-// isupperrune tests for upper case characters, including Unicode
-// upper case letters and targets of the toupper mapping. islowerrune
-// and istitlerune are defined analogously.
-
-int isupperrune(Rune r);
-int islowerrune(Rune r);
-int istitlerune(Rune r);
-
-
-// isalpharune tests for Unicode letters; this includes ideographs in
-// addition to alphabetic characters.
-
-int isalpharune(Rune r);
-
-
-// isdigitrune tests for digits. Non-digit numbers, such as Roman
-// numerals, are not included.
-
-int isdigitrune(Rune r);
-
-
-// isspacerune tests for whitespace characters, including "C" locale
-// whitespace, Unicode defined whitespace, and the "zero-width
-// non-break space" character.
-
-int isspacerune(Rune r);
-
-
-// (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)
-
-#ifdef	__cplusplus
-}
-#endif
-
-#endif
diff --git a/src/lib9/utf/utfdef.h b/src/lib9/utf/utfdef.h
deleted file mode 100644
index 4bbdfc6..0000000
--- a/src/lib9/utf/utfdef.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- *              Copyright (c) 1998-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.
- */
-
-#define uchar _utfuchar
-#define ushort _utfushort
-#define uint _utfuint
-#define ulong _utfulong
-#define vlong _utfvlong
-#define uvlong _utfuvlong
-
-typedef unsigned char		uchar;
-typedef unsigned short		ushort;
-typedef unsigned int		uint;
-typedef unsigned long		ulong;
-
-#define nelem(x) (sizeof(x)/sizeof((x)[0]))
diff --git a/src/lib9/utf/utfecpy.c b/src/lib9/utf/utfecpy.c
deleted file mode 100644
index 8540664..0000000
--- a/src/lib9/utf/utfecpy.c
+++ /dev/null
@@ -1,36 +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.
- */
-#include <u.h>
-#include <libc.h>
-#include "utf.h"
-#include "utfdef.h"
-
-char*
-utfecpy(char *to, char *e, const char *from)
-{
-	char *end;
-
-	if(to >= e)
-		return to;
-	end = memccpy(to, from, '\0', (size_t)(e - to));
-	if(end == nil){
-		end = e-1;
-		while(end>to && (*--end&0xC0)==0x80)
-			;
-		*end = '\0';
-	}else{
-		end--;
-	}
-	return end;
-}
diff --git a/src/lib9/utf/utflen.c b/src/lib9/utf/utflen.c
deleted file mode 100644
index 9b96185..0000000
--- a/src/lib9/utf/utflen.c
+++ /dev/null
@@ -1,35 +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.
- */
-#include "utf.h"
-#include "utfdef.h"
-
-int
-utflen(const char *s)
-{
-	int c;
-	int n;
-	Rune rune;
-
-	n = 0;
-	for(;;) {
-		c = *(uchar*)s;
-		if(c < Runeself) {
-			if(c == 0)
-				return n;
-			s++;
-		} else
-			s += chartorune(&rune, s);
-		n++;
-	}
-}
diff --git a/src/lib9/utf/utfnlen.c b/src/lib9/utf/utfnlen.c
deleted file mode 100644
index d6ef5fa..0000000
--- a/src/lib9/utf/utfnlen.c
+++ /dev/null
@@ -1,39 +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.
- */
-#include "utf.h"
-#include "utfdef.h"
-
-int
-utfnlen(const char *s, long m)
-{
-	int c;
-	int n;
-	Rune rune;
-	const char *es;
-
-	es = s + m;
-	for(n = 0; s < es; n++) {
-		c = *(uchar*)s;
-		if(c < Runeself){
-			if(c == '\0')
-				break;
-			s++;
-			continue;
-		}
-		if(!fullrune(s, (int)(es-s)))
-			break;
-		s += chartorune(&rune, s);
-	}
-	return n;
-}
diff --git a/src/lib9/utf/utfrrune.c b/src/lib9/utf/utfrrune.c
deleted file mode 100644
index b1ea93b..0000000
--- a/src/lib9/utf/utfrrune.c
+++ /dev/null
@@ -1,46 +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.
- */
-#include <u.h>
-#include <libc.h>
-#include "utf.h"
-#include "utfdef.h"
-
-/* const - removed for go code */
-char*
-utfrrune(const char *s, Rune c)
-{
-	long c1;
-	Rune r;
-	const char *s1;
-
-	if(c < Runesync)		/* not part of utf sequence */
-		return strrchr(s, (char)c);
-
-	s1 = 0;
-	for(;;) {
-		c1 = *(uchar*)s;
-		if(c1 < Runeself) {	/* one byte rune */
-			if(c1 == 0)
-				return (char*)s1;
-			if(c1 == c)
-				s1 = s;
-			s++;
-			continue;
-		}
-		c1 = chartorune(&r, s);
-		if(r == c)
-			s1 = s;
-		s += c1;
-	}
-}
diff --git a/src/lib9/utf/utfrune.c b/src/lib9/utf/utfrune.c
deleted file mode 100644
index 44675c9..0000000
--- a/src/lib9/utf/utfrune.c
+++ /dev/null
@@ -1,45 +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.
- */
-#include <u.h>
-#include <libc.h>
-#include "utf.h"
-#include "utfdef.h"
-
-/* const - removed for go code */
-char*
-utfrune(const char *s, Rune c)
-{
-	long c1;
-	Rune r;
-	int n;
-
-	if(c < Runesync)		/* not part of utf sequence */
-		return strchr(s, (char)c);
-
-	for(;;) {
-		c1 = *(uchar*)s;
-		if(c1 < Runeself) {	/* one byte rune */
-			if(c1 == 0)
-				return 0;
-			if(c1 == c)
-				return (char*)s;
-			s++;
-			continue;
-		}
-		n = chartorune(&r, s);
-		if(r == c)
-			return (char*)s;
-		s += n;
-	}
-}
diff --git a/src/lib9/utf/utfutf.c b/src/lib9/utf/utfutf.c
deleted file mode 100644
index 05335b2..0000000
--- a/src/lib9/utf/utfutf.c
+++ /dev/null
@@ -1,43 +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.
- */
-#include <u.h>
-#include <libc.h>
-#include "utf.h"
-#include "utfdef.h"
-
-
-/*
- * Return pointer to first occurrence of s2 in s1,
- * 0 if none
- */
-const
-char*
-utfutf(const char *s1, const char *s2)
-{
-	const char *p;
-	long f, n1;
-	size_t n2;
-	Rune r;
-
-	n1 = chartorune(&r, s2);
-	f = r;
-	if(f <= Runesync)		/* represents self */
-		return strstr(s1, s2);
-
-	n2 = strlen(s2);
-	for(p=s1; (p=utfrune(p, r)) != 0; p+=n1)
-		if(strncmp(p, s2, n2) == 0)
-			return p;
-	return 0;
-}
diff --git a/src/lib9/win.h b/src/lib9/win.h
deleted file mode 100644
index d9df319..0000000
--- a/src/lib9/win.h
+++ /dev/null
@@ -1,8 +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.
-
-typedef unsigned short WinRune;
-
-WinRune* torune(char*);
-char *toutf(WinRune*);
diff --git a/src/lib9/windows.c b/src/lib9/windows.c
deleted file mode 100644
index 082f339..0000000
--- a/src/lib9/windows.c
+++ /dev/null
@@ -1,31 +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 <u.h>
-#include <libc.h>
-
-int
-fork(void)
-{
-	return -1;
-}
-
-int
-p9rfork(int flags)
-{
-	USED(flags);
-	return -1;
-}
-
-Waitmsg*
-p9wait(void)
-{
-	return 0;
-}
-
-int
-p9waitpid(void)
-{
-	return -1;
-}
diff --git a/src/libbio/Makefile b/src/libbio/Makefile
deleted file mode 100644
index 62aba5d..0000000
--- a/src/libbio/Makefile
+++ /dev/null
@@ -1,5 +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.
-
-include ../Make.dist
diff --git a/src/libbio/bbuffered.c b/src/libbio/bbuffered.c
deleted file mode 100644
index 2ddb29b..0000000
--- a/src/libbio/bbuffered.c
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
-http://code.google.com/p/inferno-os/source/browse/libbio/bbuffered.c
-
-	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  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.
-*/
-
-#include	<u.h>
-#include	<libc.h>
-#include	<bio.h>
-
-int
-Bbuffered(Biobuf *bp)
-{
-	switch(bp->state) {
-	case Bracteof:
-	case Bractive:
-		return -bp->icount;
-
-	case Bwactive:
-		return bp->bsize + bp->ocount;
-
-	case Binactive:
-		return 0;
-	}
-	fprint(2, "Bbuffered: unknown state %d\n", bp->state);
-	return 0;
-}
diff --git a/src/libbio/bfildes.c b/src/libbio/bfildes.c
deleted file mode 100644
index aef1f70..0000000
--- a/src/libbio/bfildes.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
-http://code.google.com/p/inferno-os/source/browse/libbio/bfildes.c
-
-	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  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.
-*/
-
-#include	<u.h>
-#include	<libc.h>
-#include	<bio.h>
-
-int
-Bfildes(Biobuf *bp)
-{
-
-	return bp->fid;
-}
diff --git a/src/libbio/bflush.c b/src/libbio/bflush.c
deleted file mode 100644
index ea7ae2c..0000000
--- a/src/libbio/bflush.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
-http://code.google.com/p/inferno-os/source/browse/libbio/bflush.c
-
-	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  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.
-*/
-
-#include	<u.h>
-#include	<libc.h>
-#include	<bio.h>
-
-int
-Bflush(Biobuf *bp)
-{
-	int n, c;
-
-	switch(bp->state) {
-	case Bwactive:
-		n = bp->bsize+bp->ocount;
-		if(n == 0)
-			return 0;
-		c = (int)write(bp->fid, bp->bbuf, (size_t)n);
-		if(n == c) {
-			bp->offset += n;
-			bp->ocount = -bp->bsize;
-			return 0;
-		}
-		bp->state = Binactive;
-		bp->ocount = 0;
-		break;
-
-	case Bracteof:
-		bp->state = Bractive;
-
-	case Bractive:
-		bp->icount = 0;
-		bp->gbuf = bp->ebuf;
-		return 0;
-	}
-	return Beof;
-}
diff --git a/src/libbio/bgetc.c b/src/libbio/bgetc.c
deleted file mode 100644
index ceb5cb1..0000000
--- a/src/libbio/bgetc.c
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
-http://code.google.com/p/inferno-os/source/browse/libbio/bgetc.c
-
-	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  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.
-*/
-
-#include	<u.h>
-#include	<libc.h>
-#include	<bio.h>
-
-int
-Bgetc(Biobuf *bp)
-{
-	int i;
-
-loop:
-	i = bp->icount;
-	if(i != 0) {
-		bp->icount = i+1;
-		return bp->ebuf[i];
-	}
-	if(bp->state != Bractive) {
-		if(bp->state == Bracteof)
-			bp->state = Bractive;
-		return Beof;
-	}
-	/*
-	 * get next buffer, try to keep Bungetsize
-	 * characters pre-catenated from the previous
-	 * buffer to allow that many ungets.
-	 */
-	memmove(bp->bbuf-Bungetsize, bp->ebuf-Bungetsize, Bungetsize);
-	i = (int)read(bp->fid, bp->bbuf, (size_t)bp->bsize);
-	bp->gbuf = bp->bbuf;
-	if(i <= 0) {
-		bp->state = Bracteof;
-		if(i < 0)
-			bp->state = Binactive;
-		return Beof;
-	}
-	if(i < bp->bsize) {
-		memmove(bp->ebuf-i-Bungetsize, bp->bbuf-Bungetsize, (size_t)(i+Bungetsize));
-		bp->gbuf = bp->ebuf-i;
-	}
-	bp->icount = -i;
-	bp->offset += i;
-	goto loop;
-}
-
-int
-Bgetle2(Biobuf *bp)
-{
-	int l, h;
-
-	l = Bgetc(bp);
-	h = Bgetc(bp);
-	return l|(h<<8);
-}
-
-int
-Bgetle4(Biobuf *bp)
-{
-	int l, h;
-
-	l = Bgetle2(bp);
-	h = Bgetle2(bp);
-	return (int)((uint32)l|((uint32)h<<16));
-}
-
-int
-Bungetc(Biobuf *bp)
-{
-
-	if(bp->state == Bracteof)
-		bp->state = Bractive;
-	if(bp->state != Bractive)
-		return Beof;
-	bp->icount--;
-	return 1;
-}
diff --git a/src/libbio/bgetd.c b/src/libbio/bgetd.c
deleted file mode 100644
index 12d2c5b..0000000
--- a/src/libbio/bgetd.c
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
-http://code.google.com/p/inferno-os/source/browse/libbio/bgetd.c
-
-	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  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.
-*/
-
-#include	<u.h>
-#include	<libc.h>
-#include <bio.h>
-
-struct	bgetd
-{
-	Biobuf*	b;
-	int		eof;
-};
-
-static int
-Bgetdf(void *vp)
-{
-	int c;
-	struct bgetd *bg = vp;
-
-	c = BGETC(bg->b);
-	if(c == Beof)
-		bg->eof = 1;
-	return c;
-}
-
-int
-Bgetd(Biobuf *bp, double *dp)
-{
-	double d;
-	struct bgetd b;
-
-	b.b = bp;
-	b.eof = 0;
-	d = fmtcharstod(Bgetdf, &b);
-	if(b.eof)
-		return -1;
-	Bungetc(bp);
-	*dp = d;
-	return 1;
-}
diff --git a/src/libbio/bgetrune.c b/src/libbio/bgetrune.c
deleted file mode 100644
index b5db391..0000000
--- a/src/libbio/bgetrune.c
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
-http://code.google.com/p/inferno-os/source/browse/libbio/bgetrune.c
-
-	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  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.
-*/
-
-#include	<u.h>
-#include	<libc.h>
-#include	<bio.h>
-
-long
-Bgetrune(Biobuf *bp)
-{
-	int c, i;
-	Rune rune;
-	char str[UTFmax];
-
-	c = BGETC(bp);
-	if(c < Runeself) {		/* one char */
-		bp->runesize = 1;
-		return c;
-	}
-	str[0] = (char)c;
-
-	for(i=1;;) {
-		c = BGETC(bp);
-		if(c < 0)
-			return c;
-		str[i++] = (char)c;
-
-		if(fullrune(str, i)) {
-			bp->runesize = chartorune(&rune, str);
-			while(i > bp->runesize) {
-				Bungetc(bp);
-				i--;
-			}
-			return rune;
-		}
-	}
-}
-
-int
-Bungetrune(Biobuf *bp)
-{
-
-	if(bp->state == Bracteof)
-		bp->state = Bractive;
-	if(bp->state != Bractive)
-		return Beof;
-	bp->icount -= bp->runesize;
-	bp->runesize = 0;
-	return 1;
-}
diff --git a/src/libbio/binit.c b/src/libbio/binit.c
deleted file mode 100644
index a7ade50..0000000
--- a/src/libbio/binit.c
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
-http://code.google.com/p/inferno-os/source/browse/libbio/binit.c
-
-	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  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.
-*/
-
-#include	<u.h>
-#include	<libc.h>
-#include	<bio.h>
-
-enum
-{
-	MAXBUFS	= 20
-};
-
-static	Biobuf*	wbufs[MAXBUFS];
-static	int		atexitflag;
-
-static
-void
-batexit(void)
-{
-	Biobuf *bp;
-	int i;
-
-	for(i=0; i<MAXBUFS; i++) {
-		bp = wbufs[i];
-		if(bp != 0) {
-			wbufs[i] = 0;
-			Bflush(bp);
-		}
-	}
-}
-
-static
-void
-deinstall(Biobuf *bp)
-{
-	int i;
-
-	for(i=0; i<MAXBUFS; i++)
-		if(wbufs[i] == bp)
-			wbufs[i] = 0;
-}
-
-static
-void
-install(Biobuf *bp)
-{
-	int i;
-
-	deinstall(bp);
-	for(i=0; i<MAXBUFS; i++)
-		if(wbufs[i] == 0) {
-			wbufs[i] = bp;
-			break;
-		}
-	if(atexitflag == 0) {
-		atexitflag = 1;
-		atexit(batexit);
-	}
-}
-
-int
-Binits(Biobuf *bp, int f, int mode, unsigned char *p, int size)
-{
-
-	p += Bungetsize;	/* make room for Bungets */
-	size -= Bungetsize;
-
-	switch(mode&~(ORCLOSE|OTRUNC)) {
-	default:
-		fprint(2, "Bopen: unknown mode %d\n", mode);
-		return Beof;
-
-	case OREAD:
-		bp->state = Bractive;
-		bp->ocount = 0;
-		break;
-
-	case OWRITE:
-		install(bp);
-		bp->state = Bwactive;
-		bp->ocount = -size;
-		break;
-	}
-	bp->bbuf = p;
-	bp->ebuf = p+size;
-	bp->bsize = size;
-	bp->icount = 0;
-	bp->gbuf = bp->ebuf;
-	bp->fid = f;
-	bp->flag = 0;
-	bp->rdline = 0;
-	bp->offset = 0;
-	bp->runesize = 0;
-	return 0;
-}
-
-
-int
-Binit(Biobuf *bp, int f, int mode)
-{
-	return Binits(bp, f, mode, bp->b, sizeof(bp->b));
-}
-
-Biobuf*
-Bfdopen(int f, int mode)
-{
-	Biobuf *bp;
-
-	bp = malloc(sizeof(Biobuf));
-	if(bp == 0)
-		return 0;
-	Binits(bp, f, mode, bp->b, sizeof(bp->b));
-	bp->flag = Bmagic;
-	return bp;
-}
-
-Biobuf*
-Bopen(char *name, int mode)
-{
-	Biobuf *bp;
-	int f;
-
-	switch(mode&~(ORCLOSE|OTRUNC)) {
-	default:
-		fprint(2, "Bopen: unknown mode %d\n", mode);
-		return 0;
-
-	case OREAD:
-		f = open(name, OREAD);
-		if(f < 0)
-			return 0;
-		break;
-
-	case OWRITE:
-		f = create(name, OWRITE|OTRUNC, 0666);
-		if(f < 0)
-			return 0;
-	}
-	bp = Bfdopen(f, mode);
-	if(bp == 0)
-		close(f);
-	return bp;
-}
-
-int
-Bterm(Biobuf *bp)
-{
-
-	deinstall(bp);
-	Bflush(bp);
-	if(bp->flag == Bmagic) {
-		bp->flag = 0;
-		close(bp->fid);
-		free(bp);
-	}
-	return 0;
-}
diff --git a/src/libbio/boffset.c b/src/libbio/boffset.c
deleted file mode 100644
index 15dd609..0000000
--- a/src/libbio/boffset.c
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
-http://code.google.com/p/inferno-os/source/browse/libbio/boffset.c
-
-	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  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.
-*/
-
-#include	<u.h>
-#include	<libc.h>
-#include	<bio.h>
-
-vlong
-Boffset(Biobuf *bp)
-{
-	vlong n;
-
-	switch(bp->state) {
-	default:
-		fprint(2, "Boffset: unknown state %d\n", bp->state);
-		n = Beof;
-		break;
-
-	case Bracteof:
-	case Bractive:
-		n = bp->offset + bp->icount;
-		break;
-
-	case Bwactive:
-		n = bp->offset + (bp->bsize + bp->ocount);
-		break;
-	}
-	return n;
-}
diff --git a/src/libbio/bprint.c b/src/libbio/bprint.c
deleted file mode 100644
index 301dc0c..0000000
--- a/src/libbio/bprint.c
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
-http://code.google.com/p/inferno-os/source/browse/libbio/bprint.c
-
-	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  All rights reserved.
-	Revisions Copyright © 2010 Google Inc.  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.
-*/
-
-#include	<u.h>
-#include	<libc.h>
-#include	<bio.h>
-
-int
-Bprint(Biobuf *bp, char *fmt, ...)
-{
-	int n;
-	va_list arg;
-
-	va_start(arg, fmt);
-	n = Bvprint(bp, fmt, arg);
-	va_end(arg);
-	return n;
-}
-
-static int
-bflush(Fmt *f)
-{
-	Biobuf *bp;
-	
-	if(f->stop == nil)
-		return 0;
-
-	bp = f->farg;
-	bp->ocount = (int)((char*)f->to - (char*)f->stop);
-	if(Bflush(bp) < 0) {
-		f->stop = nil;
-		f->to = nil;
-		return 0;
-	}
-	f->to = (char*)f->stop + bp->ocount;
-	
-	return 1;
-}
-
-int
-Bvprint(Biobuf *bp, char *fmt, va_list arg)
-{
-	int n;
-	Fmt f;
-	
-	memset(&f, 0, sizeof f);
-	fmtlocaleinit(&f, nil, nil, nil);
-	f.stop = bp->ebuf;
-	f.to = (char*)f.stop + bp->ocount;
-	f.flush = bflush;
-	f.farg = bp;
-
-	n = fmtvprint(&f, fmt, arg);
-
-	if(f.stop != nil)
-		bp->ocount = (int)((char*)f.to - (char*)f.stop);
-
-	return n;
-}
diff --git a/src/libbio/bputc.c b/src/libbio/bputc.c
deleted file mode 100644
index 07b4789..0000000
--- a/src/libbio/bputc.c
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
-http://code.google.com/p/inferno-os/source/browse/libbio/bputc.c
-
-	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  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.
-*/
-
-#include	<u.h>
-#include	<libc.h>
-#include	<bio.h>
-
-int
-Bputc(Biobuf *bp, int c)
-{
-	int i;
-
-	for(;;) {
-		i = bp->ocount;
-		if(i) {
-			bp->ebuf[i++] = (unsigned char)c;
-			bp->ocount = i;
-			return 0;
-		}
-		if(Bflush(bp) == Beof)
-			break;
-	}
-	return Beof;
-}
-
-int
-Bputle2(Biobuf *bp, int c)
-{
-	Bputc(bp, c);
-	return Bputc(bp, c>>8);
-}
-
-int
-Bputle4(Biobuf *bp, int c)
-{
-	Bputle2(bp, c);
-	return Bputle2(bp, c>>16);
-}
diff --git a/src/libbio/bputrune.c b/src/libbio/bputrune.c
deleted file mode 100644
index f207795..0000000
--- a/src/libbio/bputrune.c
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
-http://code.google.com/p/inferno-os/source/browse/libbio/bputrune.c
-
-	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  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.
-*/
-
-#include	<u.h>
-#include	<libc.h>
-#include	<bio.h>
-
-int
-Bputrune(Biobuf *bp, long c)
-{
-	Rune rune;
-	char str[UTFmax];
-	int n;
-
-	rune = (Rune)c;
-	if(rune < Runeself) {
-		n = BPUTC(bp, (int)rune);
-		USED(n);
-		return 1;
-	}
-	n = runetochar(str, &rune);
-	if(n == 0)
-		return Bbad;
-	if(Bwrite(bp, str, n) != n)
-		return Beof;
-	return n;
-}
diff --git a/src/libbio/brdline.c b/src/libbio/brdline.c
deleted file mode 100644
index 1c3093e..0000000
--- a/src/libbio/brdline.c
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
-http://code.google.com/p/inferno-os/source/browse/libbio/brdline.c
-
-	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  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.
-*/
-
-#include	<u.h>
-#include	<libc.h>
-#include	<bio.h>
-
-void*
-Brdline(Biobuf *bp, int delim)
-{
-	char *ip, *ep;
-	int i, j;
-
-	i = -bp->icount;
-	if(i == 0) {
-		/*
-		 * eof or other error
-		 */
-		if(bp->state != Bractive) {
-			if(bp->state == Bracteof)
-				bp->state = Bractive;
-			bp->rdline = 0;
-			bp->gbuf = bp->ebuf;
-			return 0;
-		}
-	}
-
-	/*
-	 * first try in remainder of buffer (gbuf doesn't change)
-	 */
-	ip = (char*)bp->ebuf - i;
-	ep = memchr(ip, delim, (size_t)i);
-	if(ep) {
-		j = (int)((ep - ip) + 1);
-		bp->rdline = j;
-		bp->icount += j;
-		return ip;
-	}
-
-	/*
-	 * copy data to beginning of buffer
-	 */
-	if(i < bp->bsize)
-		memmove(bp->bbuf, ip, (size_t)i);
-	bp->gbuf = bp->bbuf;
-
-	/*
-	 * append to buffer looking for the delim
-	 */
-	ip = (char*)bp->bbuf + i;
-	while(i < bp->bsize) {
-		j = (int)read(bp->fid, ip, (size_t)(bp->bsize-i));
-		if(j <= 0) {
-			/*
-			 * end of file with no delim
-			 */
-			memmove(bp->ebuf-i, bp->bbuf, (size_t)i);
-			bp->rdline = i;
-			bp->icount = -i;
-			bp->gbuf = bp->ebuf-i;
-			return 0;
-		}
-		bp->offset += j;
-		i += j;
-		ep = memchr(ip, delim, (size_t)j);
-		if(ep) {
-			/*
-			 * found in new piece
-			 * copy back up and reset everything
-			 */
-			ip = (char*)bp->ebuf - i;
-			if(i < bp->bsize){
-				memmove(ip, bp->bbuf, (size_t)i);
-				bp->gbuf = (unsigned char*)ip;
-			}
-			j = (int)((ep - (char*)bp->bbuf) + 1);
-			bp->rdline = j;
-			bp->icount = j - i;
-			return ip;
-		}
-		ip += j;
-	}
-
-	/*
-	 * full buffer without finding
-	 */
-	bp->rdline = bp->bsize;
-	bp->icount = -bp->bsize;
-	bp->gbuf = bp->bbuf;
-	return 0;
-}
-
-int
-Blinelen(Biobuf *bp)
-{
-
-	return bp->rdline;
-}
diff --git a/src/libbio/brdstr.c b/src/libbio/brdstr.c
deleted file mode 100644
index 6a90cf6..0000000
--- a/src/libbio/brdstr.c
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
-	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.
-*/
-
-#include	<u.h>
-#include	<libc.h>
-#include	<bio.h>
-
-char*
-Brdstr(Biobuf *bp, int delim, int nulldelim)
-{
-	char *p, *q, *nq;
-	int n, linelen;
-
-	q = nil;
-	n = 0;
-	for(;;) {
-		p = Brdline(bp, delim);
-		linelen = Blinelen(bp);
-		if(n == 0 && linelen == 0)
-			return nil;
-		nq = realloc(q, (size_t)(n+linelen+1));
-		if(nq == nil) {
-			free(q);
-			return nil;
-		}
-		q = nq;
-		if(p != nil) {
-			memmove(q+n, p, (size_t)linelen);
-			n += linelen;
-			if(nulldelim)
-				q[n-1] = '\0';
-			break;
-		}
-		if(linelen == 0)
-			break;
-		Bread(bp, q+n, linelen);
-		n += linelen;
-	}
-	q[n] = '\0';
-	return q;
-}
diff --git a/src/libbio/bread.c b/src/libbio/bread.c
deleted file mode 100644
index 343a0bf..0000000
--- a/src/libbio/bread.c
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
-http://code.google.com/p/inferno-os/source/browse/libbio/bread.c
-
-	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  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.
-*/
-
-#include	<u.h>
-#include	<libc.h>
-#include	<bio.h>
-
-long
-Bread(Biobuf *bp, void *ap, long count)
-{
-	long c;
-	unsigned char *p;
-	int i, n, ic;
-
-	p = ap;
-	c = count;
-	ic = bp->icount;
-
-	while(c > 0) {
-		n = -ic;
-		if(n > c)
-			n = (int)c;
-		if(n == 0) {
-			if(bp->state != Bractive)
-				break;
-			i = (int)read(bp->fid, bp->bbuf, (size_t)bp->bsize);
-			if(i <= 0) {
-				bp->state = Bracteof;
-				if(i < 0)
-					bp->state = Binactive;
-				break;
-			}
-			bp->gbuf = bp->bbuf;
-			bp->offset += i;
-			if(i < bp->bsize) {
-				memmove(bp->ebuf-i, bp->bbuf, (size_t)i);
-				bp->gbuf = bp->ebuf-i;
-			}
-			ic = -i;
-			continue;
-		}
-		memmove(p, bp->ebuf+ic, (size_t)n);
-		c -= n;
-		ic += n;
-		p += n;
-	}
-	bp->icount = ic;
-	return count-c;
-}
diff --git a/src/libbio/bseek.c b/src/libbio/bseek.c
deleted file mode 100644
index 5289585..0000000
--- a/src/libbio/bseek.c
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
-http://code.google.com/p/inferno-os/source/browse/libbio/bseek.c
-
-	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  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.
-*/
-
-#include	<u.h>
-#include	<libc.h>
-#include	<bio.h>
-
-vlong
-Bseek(Biobuf *bp, vlong offset, int base)
-{
-	vlong n, d;
-	int bufsz;
-
-#if !defined(_WIN32) && !defined(PLAN9)
-	if(sizeof(offset) != sizeof(off_t)) {
-		fprint(2, "Bseek: libbio compiled with %d-byte offset\n", sizeof(off_t));
-		abort();
-	}
-#endif
-
-	switch(bp->state) {
-	default:
-		fprint(2, "Bseek: unknown state %d\n", bp->state);
-		return Beof;
-
-	case Bracteof:
-		bp->state = Bractive;
-		bp->icount = 0;
-		bp->gbuf = bp->ebuf;
-
-	case Bractive:
-		n = offset;
-		if(base == 1) {
-			n += Boffset(bp);
-			base = 0;
-		}
-
-		/*
-		 * try to seek within buffer
-		 */
-		if(base == 0) {
-			d = n - Boffset(bp);
-			bufsz = (int)(bp->ebuf - bp->gbuf);
-			if(-bufsz <= d && d <= bufsz){
-				bp->icount += (int)d;
-				if(d >= 0) {
-					if(bp->icount <= 0)
-						return n;
-				} else {
-					if(bp->ebuf - bp->gbuf >= -bp->icount)
-						return n;
-				}
-			}
-		}
-
-		/*
-		 * reset the buffer
-		 */
-		n = lseek(bp->fid, n, base);
-		bp->icount = 0;
-		bp->gbuf = bp->ebuf;
-		break;
-
-	case Bwactive:
-		Bflush(bp);
-		n = lseek(bp->fid, offset, base);
-		break;
-	}
-	bp->offset = n;
-	return n;
-}
diff --git a/src/libbio/bwrite.c b/src/libbio/bwrite.c
deleted file mode 100644
index 8b9943a..0000000
--- a/src/libbio/bwrite.c
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
-http://code.google.com/p/inferno-os/source/browse/libbio/bwrite.c
-
-	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-	Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  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.
-*/
-
-#include	<u.h>
-#include	<libc.h>
-#include	<bio.h>
-
-long
-Bwrite(Biobuf *bp, void *ap, long count)
-{
-	long c;
-	unsigned char *p;
-	int i, n, oc;
-
-	p = ap;
-	c = count;
-	oc = bp->ocount;
-
-	while(c > 0) {
-		n = -oc;
-		if(n > c)
-			n = (int)c;
-		if(n == 0) {
-			if(bp->state != Bwactive)
-				return Beof;
-			i = (int)write(bp->fid, bp->bbuf, (size_t)bp->bsize);
-			if(i != bp->bsize) {
-				bp->state = Binactive;
-				return Beof;
-			}
-			bp->offset += i;
-			oc = -bp->bsize;
-			continue;
-		}
-		memmove(bp->ebuf+oc, p, (size_t)n);
-		oc += n;
-		c -= n;
-		p += n;
-	}
-	bp->ocount = oc;
-	return count-c;
-}
diff --git a/src/liblink/Makefile b/src/liblink/Makefile
deleted file mode 100644
index 2a31746..0000000
--- a/src/liblink/Makefile
+++ /dev/null
@@ -1,5 +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.
-
-include ../Make.dist
diff --git a/src/liblink/asm5.c b/src/liblink/asm5.c
deleted file mode 100644
index 96df9f7..0000000
--- a/src/liblink/asm5.c
+++ /dev/null
@@ -1,2696 +0,0 @@
-// Inferno utils/5l/span.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5l/span.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-// Instruction layout.
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <link.h>
-#include "../cmd/5l/5.out.h"
-#include "../runtime/stack.h"
-
-typedef	struct	Optab	Optab;
-typedef	struct	Oprang	Oprang;
-typedef	uchar	Opcross[32][2][32];
-
-struct	Optab
-{
-	uchar	as;
-	uchar	a1;
-	char	a2;
-	uchar	a3;
-	uchar	type;
-	char	size;
-	char	param;
-	char	flag;
-	uchar	pcrelsiz;
-};
-struct	Oprang
-{
-	Optab*	start;
-	Optab*	stop;
-};
-
-enum
-{
-	LFROM		= 1<<0,
-	LTO		= 1<<1,
-	LPOOL		= 1<<2,
-	LPCREL		= 1<<3,
-};
-
-static Optab	optab[] =
-{
-	/* struct Optab:
-	  OPCODE,	from, prog->reg, to,		 type,size,param,flag */
-	{ ATEXT,	C_ADDR,	C_NONE,	C_LCON, 	 0, 0, 0 },
-	{ ATEXT,	C_ADDR,	C_REG,	C_LCON, 	 0, 0, 0 },
-
-	{ AADD,		C_REG,	C_REG,	C_REG,		 1, 4, 0 },
-	{ AADD,		C_REG,	C_NONE,	C_REG,		 1, 4, 0 },
-	{ AMOVW,	C_REG,	C_NONE,	C_REG,		 1, 4, 0 },
-	{ AMVN,		C_REG,	C_NONE,	C_REG,		 1, 4, 0 },
-	{ ACMP,		C_REG,	C_REG,	C_NONE,		 1, 4, 0 },
-
-	{ AADD,		C_RCON,	C_REG,	C_REG,		 2, 4, 0 },
-	{ AADD,		C_RCON,	C_NONE,	C_REG,		 2, 4, 0 },
-	{ AMOVW,	C_RCON,	C_NONE,	C_REG,		 2, 4, 0 },
-	{ AMVN,		C_RCON,	C_NONE,	C_REG,		 2, 4, 0 },
-	{ ACMP,		C_RCON,	C_REG,	C_NONE,		 2, 4, 0 },
-
-	{ AADD,		C_SHIFT,C_REG,	C_REG,		 3, 4, 0 },
-	{ AADD,		C_SHIFT,C_NONE,	C_REG,		 3, 4, 0 },
-	{ AMVN,		C_SHIFT,C_NONE,	C_REG,		 3, 4, 0 },
-	{ ACMP,		C_SHIFT,C_REG,	C_NONE,		 3, 4, 0 },
-
-	{ AMOVW,	C_RACON,C_NONE,	C_REG,		 4, 4, REGSP },
-
-	{ AB,		C_NONE,	C_NONE,	C_SBRA,		 5, 4, 0,	LPOOL },
-	{ ABL,		C_NONE,	C_NONE,	C_SBRA,		 5, 4, 0 },
-	{ ABX,		C_NONE,	C_NONE,	C_SBRA,		 74, 20, 0 },
-	{ ABEQ,		C_NONE,	C_NONE,	C_SBRA,		 5, 4, 0 },
-
-	{ AB,		C_NONE,	C_NONE,	C_ROREG,	 6, 4, 0,	LPOOL },
-	{ ABL,		C_NONE,	C_NONE,	C_ROREG,	 7, 4, 0 },
-	{ ABL,		C_REG,	C_NONE,	C_ROREG,	 7, 4, 0 },
-	{ ABX,		C_NONE,	C_NONE,	C_ROREG,	 75, 12, 0 },
-	{ ABXRET,	C_NONE,	C_NONE,	C_ROREG,	 76, 4, 0 },
-
-	{ ASLL,		C_RCON,	C_REG,	C_REG,		 8, 4, 0 },
-	{ ASLL,		C_RCON,	C_NONE,	C_REG,		 8, 4, 0 },
-
-	{ ASLL,		C_REG,	C_NONE,	C_REG,		 9, 4, 0 },
-	{ ASLL,		C_REG,	C_REG,	C_REG,		 9, 4, 0 },
-
-	{ ASWI,		C_NONE,	C_NONE,	C_NONE,		10, 4, 0 },
-	{ ASWI,		C_NONE,	C_NONE,	C_LOREG,	10, 4, 0 },
-	{ ASWI,		C_NONE,	C_NONE,	C_LCON,		10, 4, 0 },
-
-	{ AWORD,	C_NONE,	C_NONE,	C_LCON,		11, 4, 0 },
-	{ AWORD,	C_NONE,	C_NONE,	C_LCONADDR,	11, 4, 0 },
-	{ AWORD,	C_NONE,	C_NONE,	C_ADDR,		11, 4, 0 },
-
-	{ AMOVW,	C_NCON,	C_NONE,	C_REG,		12, 4, 0 },
-	{ AMOVW,	C_LCON,	C_NONE,	C_REG,		12, 4, 0,	LFROM },
-	{ AMOVW,	C_LCONADDR,	C_NONE,	C_REG,	12, 4, 0,	LFROM | LPCREL, 4},
-
-	{ AADD,		C_NCON,	C_REG,	C_REG,		13, 8, 0 },
-	{ AADD,		C_NCON,	C_NONE,	C_REG,		13, 8, 0 },
-	{ AMVN,		C_NCON,	C_NONE,	C_REG,		13, 8, 0 },
-	{ ACMP,		C_NCON,	C_REG,	C_NONE,		13, 8, 0 },
-	{ AADD,		C_LCON,	C_REG,	C_REG,		13, 8, 0,	LFROM },
-	{ AADD,		C_LCON,	C_NONE,	C_REG,		13, 8, 0,	LFROM },
-	{ AMVN,		C_LCON,	C_NONE,	C_REG,		13, 8, 0,	LFROM },
-	{ ACMP,		C_LCON,	C_REG,	C_NONE,		13, 8, 0,	LFROM },
-
-	{ AMOVB,	C_REG,	C_NONE,	C_REG,		 1, 4, 0 },
-	{ AMOVBS,	C_REG,	C_NONE,	C_REG,		14, 8, 0 },
-	{ AMOVBU,	C_REG,	C_NONE,	C_REG,		58, 4, 0 },
-	{ AMOVH,	C_REG,	C_NONE,	C_REG,		 1, 4, 0 },
-	{ AMOVHS,	C_REG,	C_NONE,	C_REG,		14, 8, 0 },
-	{ AMOVHU,	C_REG,	C_NONE,	C_REG,		14, 8, 0 },
-
-	{ AMUL,		C_REG,	C_REG,	C_REG,		15, 4, 0 },
-	{ AMUL,		C_REG,	C_NONE,	C_REG,		15, 4, 0 },
-
-	{ ADIV,		C_REG,	C_REG,	C_REG,		16, 4, 0 },
-	{ ADIV,		C_REG,	C_NONE,	C_REG,		16, 4, 0 },
-
-	{ AMULL,	C_REG,	C_REG,	C_REGREG,	17, 4, 0 },
-	{ AMULA,	C_REG,	C_REG,	C_REGREG2,	17, 4, 0 },
-
-	{ AMOVW,	C_REG,	C_NONE,	C_SAUTO,	20, 4, REGSP },
-	{ AMOVW,	C_REG,	C_NONE,	C_SOREG,	20, 4, 0 },
-	{ AMOVB,	C_REG,	C_NONE,	C_SAUTO,	20, 4, REGSP },
-	{ AMOVB,	C_REG,	C_NONE,	C_SOREG,	20, 4, 0 },
-	{ AMOVBS,	C_REG,	C_NONE,	C_SAUTO,	20, 4, REGSP },
-	{ AMOVBS,	C_REG,	C_NONE,	C_SOREG,	20, 4, 0 },
-	{ AMOVBU,	C_REG,	C_NONE,	C_SAUTO,	20, 4, REGSP },
-	{ AMOVBU,	C_REG,	C_NONE,	C_SOREG,	20, 4, 0 },
-
-	{ AMOVW,	C_SAUTO,C_NONE,	C_REG,		21, 4, REGSP },
-	{ AMOVW,	C_SOREG,C_NONE,	C_REG,		21, 4, 0 },
-	{ AMOVBU,	C_SAUTO,C_NONE,	C_REG,		21, 4, REGSP },
-	{ AMOVBU,	C_SOREG,C_NONE,	C_REG,		21, 4, 0 },
-
-	{ AMOVW,	C_REG,	C_NONE,	C_LAUTO,	30, 8, REGSP,	LTO },
-	{ AMOVW,	C_REG,	C_NONE,	C_LOREG,	30, 8, 0,	LTO },
-	{ AMOVW,	C_REG,	C_NONE,	C_ADDR,		64, 8, 0,	LTO | LPCREL, 4 },
-	{ AMOVB,	C_REG,	C_NONE,	C_LAUTO,	30, 8, REGSP,	LTO },
-	{ AMOVB,	C_REG,	C_NONE,	C_LOREG,	30, 8, 0,	LTO },
-	{ AMOVB,	C_REG,	C_NONE,	C_ADDR,		64, 8, 0,	LTO | LPCREL, 4 },
-	{ AMOVBS,	C_REG,	C_NONE,	C_LAUTO,	30, 8, REGSP,	LTO },
-	{ AMOVBS,	C_REG,	C_NONE,	C_LOREG,	30, 8, 0,	LTO },
-	{ AMOVBS,	C_REG,	C_NONE,	C_ADDR,		64, 8, 0,	LTO | LPCREL, 4 },
-	{ AMOVBU,	C_REG,	C_NONE,	C_LAUTO,	30, 8, REGSP,	LTO },
-	{ AMOVBU,	C_REG,	C_NONE,	C_LOREG,	30, 8, 0,	LTO },
-	{ AMOVBU,	C_REG,	C_NONE,	C_ADDR,		64, 8, 0,	LTO | LPCREL, 4 },
-
-	{ AMOVW,	C_LAUTO,C_NONE,	C_REG,		31, 8, REGSP,	LFROM },
-	{ AMOVW,	C_LOREG,C_NONE,	C_REG,		31, 8, 0,	LFROM },
-	{ AMOVW,	C_ADDR,	C_NONE,	C_REG,		65, 8, 0,	LFROM | LPCREL, 4 },
-	{ AMOVBU,	C_LAUTO,C_NONE,	C_REG,		31, 8, REGSP,	LFROM },
-	{ AMOVBU,	C_LOREG,C_NONE,	C_REG,		31, 8, 0,	LFROM },
-	{ AMOVBU,	C_ADDR,	C_NONE,	C_REG,		65, 8, 0,	LFROM | LPCREL, 4 },
-
-	{ AMOVW,	C_LACON,C_NONE,	C_REG,		34, 8, REGSP,	LFROM },
-
-	{ AMOVW,	C_PSR,	C_NONE,	C_REG,		35, 4, 0 },
-	{ AMOVW,	C_REG,	C_NONE,	C_PSR,		36, 4, 0 },
-	{ AMOVW,	C_RCON,	C_NONE,	C_PSR,		37, 4, 0 },
-
-	{ AMOVM,	C_LCON,	C_NONE,	C_SOREG,	38, 4, 0 },
-	{ AMOVM,	C_SOREG,C_NONE,	C_LCON,		39, 4, 0 },
-
-	{ ASWPW,	C_SOREG,C_REG,	C_REG,		40, 4, 0 },
-
-	{ ARFE,		C_NONE,	C_NONE,	C_NONE,		41, 4, 0 },
-
-	{ AMOVF,	C_FREG,	C_NONE,	C_FAUTO,	50, 4, REGSP },
-	{ AMOVF,	C_FREG,	C_NONE,	C_FOREG,	50, 4, 0 },
-
-	{ AMOVF,	C_FAUTO,C_NONE,	C_FREG,		51, 4, REGSP },
-	{ AMOVF,	C_FOREG,C_NONE,	C_FREG,		51, 4, 0 },
-
-	{ AMOVF,	C_FREG,	C_NONE,	C_LAUTO,	52, 12, REGSP,	LTO },
-	{ AMOVF,	C_FREG,	C_NONE,	C_LOREG,	52, 12, 0,	LTO },
-
-	{ AMOVF,	C_LAUTO,C_NONE,	C_FREG,		53, 12, REGSP,	LFROM },
-	{ AMOVF,	C_LOREG,C_NONE,	C_FREG,		53, 12, 0,	LFROM },
-
-	{ AMOVF,	C_FREG,	C_NONE,	C_ADDR,		68, 8, 0,	LTO | LPCREL, 4 },
-	{ AMOVF,	C_ADDR,	C_NONE,	C_FREG,		69, 8, 0,	LFROM | LPCREL, 4},
-
-	{ AADDF,	C_FREG,	C_NONE,	C_FREG,		54, 4, 0 },
-	{ AADDF,	C_FREG,	C_REG,	C_FREG,		54, 4, 0 },
-	{ AMOVF,	C_FREG, C_NONE, C_FREG,		54, 4, 0 },
-
-	{ AMOVW,	C_REG,	C_NONE,	C_FCR,		56, 4, 0 },
-	{ AMOVW,	C_FCR,	C_NONE,	C_REG,		57, 4, 0 },
-
-	{ AMOVW,	C_SHIFT,C_NONE,	C_REG,		59, 4, 0 },
-	{ AMOVBU,	C_SHIFT,C_NONE,	C_REG,		59, 4, 0 },
-
-	{ AMOVB,	C_SHIFT,C_NONE,	C_REG,		60, 4, 0 },
-	{ AMOVBS,	C_SHIFT,C_NONE,	C_REG,		60, 4, 0 },
-
-	{ AMOVW,	C_REG,	C_NONE,	C_SHIFT,	61, 4, 0 },
-	{ AMOVB,	C_REG,	C_NONE,	C_SHIFT,	61, 4, 0 },
-	{ AMOVBS,	C_REG,	C_NONE,	C_SHIFT,	61, 4, 0 },
-	{ AMOVBU,	C_REG,	C_NONE,	C_SHIFT,	61, 4, 0 },
-
-	{ ACASE,	C_REG,	C_NONE,	C_NONE,		62, 4, 0, LPCREL, 8 },
-	{ ABCASE,	C_NONE, C_NONE, C_SBRA,		63, 4, 0, LPCREL, 0 },
-
-	{ AMOVH,	C_REG,	C_NONE, C_HAUTO,	70, 4, REGSP,	0 },
-	{ AMOVH,	C_REG,	C_NONE,	C_HOREG,	70, 4, 0,	0 },
-	{ AMOVHS,	C_REG,	C_NONE, C_HAUTO,	70, 4, REGSP,	0 },
-	{ AMOVHS,	C_REG,	C_NONE,	C_HOREG,	70, 4, 0,	0 },
-	{ AMOVHU,	C_REG,	C_NONE, C_HAUTO,	70, 4, REGSP,	0 },
-	{ AMOVHU,	C_REG,	C_NONE,	C_HOREG,	70, 4, 0,	0 },
-
-	{ AMOVB,	C_HAUTO,C_NONE,	C_REG,		71, 4, REGSP,	0 },
-	{ AMOVB,	C_HOREG,C_NONE,	C_REG,		71, 4, 0,	0 },
-	{ AMOVBS,	C_HAUTO,C_NONE,	C_REG,		71, 4, REGSP,	0 },
-	{ AMOVBS,	C_HOREG,C_NONE,	C_REG,		71, 4, 0,	0 },
-	{ AMOVH,	C_HAUTO,C_NONE, C_REG,		71, 4, REGSP,	0 },
-	{ AMOVH,	C_HOREG,C_NONE,	C_REG,		71, 4, 0,	0 },
-	{ AMOVHS,	C_HAUTO,C_NONE, C_REG,		71, 4, REGSP,	0 },
-	{ AMOVHS,	C_HOREG,C_NONE,	C_REG,		71, 4, 0,	0 },
-	{ AMOVHU,	C_HAUTO,C_NONE, C_REG,		71, 4, REGSP,	0 },
-	{ AMOVHU,	C_HOREG,C_NONE,	C_REG,		71, 4, 0,	0 },
-
-	{ AMOVH,	C_REG,	C_NONE, C_LAUTO,	72, 8, REGSP,	LTO },
-	{ AMOVH,	C_REG,	C_NONE,	C_LOREG,	72, 8, 0,	LTO },
-	{ AMOVH,	C_REG,	C_NONE,	C_ADDR,	94, 8, 0,	LTO | LPCREL, 4 },
-	{ AMOVHS,	C_REG,	C_NONE, C_LAUTO,	72, 8, REGSP,	LTO },
-	{ AMOVHS,	C_REG,	C_NONE,	C_LOREG,	72, 8, 0,	LTO },
-	{ AMOVHS,	C_REG,	C_NONE,	C_ADDR,	94, 8, 0,	LTO | LPCREL, 4 },
-	{ AMOVHU,	C_REG,	C_NONE, C_LAUTO,	72, 8, REGSP,	LTO },
-	{ AMOVHU,	C_REG,	C_NONE,	C_LOREG,	72, 8, 0,	LTO },
-	{ AMOVHU,	C_REG,	C_NONE,	C_ADDR,	94, 8, 0,	LTO | LPCREL, 4 },
-
-	{ AMOVB,	C_LAUTO,C_NONE,	C_REG,		73, 8, REGSP,	LFROM },
-	{ AMOVB,	C_LOREG,C_NONE,	C_REG,		73, 8, 0,	LFROM },
-	{ AMOVB,	C_ADDR,	C_NONE,	C_REG,		93, 8, 0,	LFROM | LPCREL, 4 },
-	{ AMOVBS,	C_LAUTO,C_NONE,	C_REG,		73, 8, REGSP,	LFROM },
-	{ AMOVBS,	C_LOREG,C_NONE,	C_REG,		73, 8, 0,	LFROM },
-	{ AMOVBS,	C_ADDR,	C_NONE,	C_REG,		93, 8, 0,	LFROM | LPCREL, 4 },
-	{ AMOVH,	C_LAUTO,C_NONE, C_REG,		73, 8, REGSP,	LFROM },
-	{ AMOVH,	C_LOREG,C_NONE,	C_REG,		73, 8, 0,	LFROM },
-	{ AMOVH,	C_ADDR,	C_NONE,	C_REG,		93, 8, 0,	LFROM | LPCREL, 4 },
-	{ AMOVHS,	C_LAUTO,C_NONE, C_REG,		73, 8, REGSP,	LFROM },
-	{ AMOVHS,	C_LOREG,C_NONE,	C_REG,		73, 8, 0,	LFROM },
-	{ AMOVHS,	C_ADDR,	C_NONE,	C_REG,		93, 8, 0,	LFROM | LPCREL, 4 },
-	{ AMOVHU,	C_LAUTO,C_NONE, C_REG,		73, 8, REGSP,	LFROM },
-	{ AMOVHU,	C_LOREG,C_NONE,	C_REG,		73, 8, 0,	LFROM },
-	{ AMOVHU,	C_ADDR,	C_NONE,	C_REG,		93, 8, 0,	LFROM | LPCREL, 4 },
-
-	{ ALDREX,	C_SOREG,C_NONE,	C_REG,		77, 4, 0 },
-	{ ASTREX,	C_SOREG,C_REG,	C_REG,		78, 4, 0 },
-
-	{ AMOVF,	C_ZFCON,C_NONE,	C_FREG,		80, 8, 0 },
-	{ AMOVF,	C_SFCON,C_NONE,	C_FREG,		81, 4, 0 },
-
-	{ ACMPF,	C_FREG,	C_REG,	C_NONE,		82, 8, 0 },
-	{ ACMPF,	C_FREG, C_NONE,	C_NONE,		83, 8, 0 },
-
-	{ AMOVFW,	C_FREG,	C_NONE,	C_FREG,		84, 4, 0 },
-	{ AMOVWF,	C_FREG,	C_NONE,	C_FREG,		85, 4, 0 },
-
-	{ AMOVFW,	C_FREG,	C_NONE,	C_REG,		86, 8, 0 },
-	{ AMOVWF,	C_REG,	C_NONE,	C_FREG,		87, 8, 0 },
-
-	{ AMOVW,	C_REG,	C_NONE,	C_FREG,		88, 4, 0 },
-	{ AMOVW,	C_FREG,	C_NONE,	C_REG,		89, 4, 0 },
-
-	{ ATST,		C_REG,	C_NONE,	C_NONE,		90, 4, 0 },
-
-	{ ALDREXD,	C_SOREG,C_NONE,	C_REG,		91, 4, 0 },
-	{ ASTREXD,	C_SOREG,C_REG,	C_REG,		92, 4, 0 },
-
-	{ APLD,		C_SOREG,C_NONE,	C_NONE,		95, 4, 0 },
-	
-	{ AUNDEF,		C_NONE,	C_NONE,	C_NONE,		96, 4, 0 },
-
-	{ ACLZ,		C_REG,	C_NONE,	C_REG,		97, 4, 0 },
-
-	{ AMULWT,	C_REG,	C_REG,	C_REG,		98, 4, 0 },
-	{ AMULAWT,	C_REG,	C_REG,	C_REGREG2,		99, 4, 0 },
-
-	{ AUSEFIELD,	C_ADDR,	C_NONE,	C_NONE, 	 0, 0, 0 },
-	{ APCDATA,	C_LCON,	C_NONE,	C_LCON,		0, 0, 0 },
-	{ AFUNCDATA,	C_LCON,	C_NONE,	C_ADDR,	0, 0, 0 },
-	{ ANOP,		C_NONE,	C_NONE,	C_NONE,		0, 0, 0 },
-
-	{ ADUFFZERO,	C_NONE,	C_NONE,	C_SBRA,		 5, 4, 0 },  // same as ABL
-	{ ADUFFCOPY,	C_NONE,	C_NONE,	C_SBRA,		 5, 4, 0 },  // same as ABL
-
-	{ ADATABUNDLE,	C_NONE, C_NONE, C_NONE,		100, 4, 0 },
-	{ ADATABUNDLEEND,	C_NONE, C_NONE, C_NONE,		100, 0, 0 },
-
-	{ AXXX,		C_NONE,	C_NONE,	C_NONE,		 0, 4, 0 },
-};
-
-static struct {
-	uint32	start;
-	uint32	size;
-	uint32	extra;
-} pool;
-
-static int	checkpool(Link*, Prog*, int);
-static int 	flushpool(Link*, Prog*, int, int);
-static void	addpool(Link*, Prog*, Addr*);
-static void	asmout(Link*, Prog*, Optab*, int32*);
-static int	asmoutnacl(Link*, int32, Prog*, Optab*, int32 *);
-static Optab*	oplook(Link*, Prog*);
-static int32	oprrr(Link*, int, int);
-static int32	olr(Link*, int32, int, int, int);
-static int32	olhr(Link*, int32, int, int, int);
-static int32	olrr(Link*, int, int, int, int);
-static int32	olhrr(Link*, int, int, int, int);
-static int32	osr(Link*, int, int, int32, int, int);
-static int32	oshr(Link*, int, int32, int, int);
-static int32	ofsr(Link*, int, int, int32, int, int, Prog*);
-static int32	osrr(Link*, int, int, int, int);
-static int32	oshrr(Link*, int, int, int, int);
-static int32	omvl(Link*, Prog*, Addr*, int);
-static int32	immaddr(int32);
-static int	aclass(Link*, Addr*);
-static int32	immrot(uint32);
-static int32	immaddr(int32);
-static int32	opbra(Link*, int, int);
-
-static	Oprang	oprange[ALAST];
-static	uchar	xcmp[C_GOK+1][C_GOK+1];
-
-static Prog zprg = {
-	.as = AGOK,
-	.scond = C_SCOND_NONE,
-	.reg = NREG,
-	.from = {
-		.name = D_NONE,
-		.type = D_NONE,
-		.reg = NREG,
-	},
-	.to = {
-		.name = D_NONE,
-		.type = D_NONE,
-		.reg = NREG,
-	},
-};
-
-static LSym *deferreturn;
-
-static void
-nocache(Prog *p)
-{
-	p->optab = 0;
-	p->from.class = 0;
-	p->to.class = 0;
-}
-
-/* size of a case statement including jump table */
-static int32
-casesz(Link *ctxt, Prog *p)
-{
-	int jt = 0;
-	int32 n = 0;
-	Optab *o;
-
-	for( ; p != nil; p = p->link){
-		if(p->as == ABCASE)
-			jt = 1;
-		else if(jt)
-			break;
-		o = oplook(ctxt, p);
-		n += o->size;
-	}
-	return n;
-}
-
-static void buildop(Link*);
-
-// asmoutnacl assembles the instruction p. It replaces asmout for NaCl.
-// It returns the total number of bytes put in out, and it can change
-// p->pc if extra padding is necessary.
-// In rare cases, asmoutnacl might split p into two instructions.
-// origPC is the PC for this Prog (no padding is taken into account).
-static int
-asmoutnacl(Link *ctxt, int32 origPC, Prog *p, Optab *o, int32 *out)
-{
-	int size, reg;
-	Prog *q;
-	Addr *a, *a2;
-
-	size = o->size;
-
-	// instruction specific
-	switch(p->as) {
-	default:
-		if(out != nil)
-			asmout(ctxt, p, o, out);
-		break;
-	case ADATABUNDLE: // align to 16-byte boundary
-	case ADATABUNDLEEND: // zero width instruction, just to align next instruction to 16-byte boundary
-		p->pc = (p->pc+15) & ~15;
-		if(out != nil)
-			asmout(ctxt, p, o, out);
-		break;
-	case AUNDEF:
-	case APLD:
-		size = 4;
-		if(out != nil) {
-			switch(p->as) {
-			case AUNDEF:
-				out[0] = 0xe7fedef0; // NACL_INSTR_ARM_ABORT_NOW (UDF #0xEDE0)
-				break;
-			case APLD:
-				out[0] = 0xe1a01001; // (MOVW R1, R1)
-				break;
-			}
-		}
-		break;
-	case AB:
-	case ABL:
-		if(p->to.type != D_OREG) {
-			if(out != nil)
-				asmout(ctxt, p, o, out);
-		} else {
-			if(p->to.offset != 0 || size != 4 || p->to.reg >= 16 || p->to.reg < 0)
-				ctxt->diag("unsupported instruction: %P", p);
-			if((p->pc&15) == 12)
-				p->pc += 4;
-			if(out != nil) {
-				out[0] = ((p->scond&C_SCOND)<<28) | 0x03c0013f | (p->to.reg << 12) | (p->to.reg << 16); // BIC $0xc000000f, Rx
-				if(p->as == AB)
-					out[1] = ((p->scond&C_SCOND)<<28) | 0x012fff10 | p->to.reg; // BX Rx
-				else // ABL
-					out[1] = ((p->scond&C_SCOND)<<28) | 0x012fff30 | p->to.reg; // BLX Rx
-			}
-			size = 8;
-		}
-		// align the last instruction (the actual BL) to the last instruction in a bundle
-		if(p->as == ABL) {
-			if(deferreturn == nil)
-				deferreturn = linklookup(ctxt, "runtime.deferreturn", 0);
-			if(p->to.sym == deferreturn)
-				p->pc = ((origPC+15) & ~15) + 16 - size;
-			else
-				p->pc += (16 - ((p->pc+size)&15)) & 15;
-		}
-		break;
-	case ALDREX:
-	case ALDREXD:
-	case AMOVB:
-	case AMOVBS:
-	case AMOVBU:
-	case AMOVD:
-	case AMOVF:
-	case AMOVH:
-	case AMOVHS:
-	case AMOVHU:
-	case AMOVM:
-	case AMOVW:
-	case ASTREX:
-	case ASTREXD:
-		if(p->to.type == D_REG && p->to.reg == 15 && p->from.reg == 13) { // MOVW.W x(R13), PC
-			if(out != nil)
-				asmout(ctxt, p, o, out);
-			if(size == 4) {
-				if(out != nil) {
-					// Note: 5c and 5g reg.c know that DIV/MOD smashes R12
-					// so that this return instruction expansion is valid.
-					out[0] = out[0] & ~0x3000; // change PC to R12
-					out[1] = ((p->scond&C_SCOND)<<28) | 0x03ccc13f; // BIC $0xc000000f, R12
-					out[2] = ((p->scond&C_SCOND)<<28) | 0x012fff1c; // BX R12
-				}
-				size += 8;
-				if(((p->pc+size) & 15) == 4)
-					p->pc += 4;
-				break;
-			} else {
-				// if the instruction used more than 4 bytes, then it must have used a very large
-				// offset to update R13, so we need to additionally mask R13.
-				if(out != nil) {
-					out[size/4-1] &= ~0x3000; // change PC to R12
-					out[size/4] = ((p->scond&C_SCOND)<<28) | 0x03cdd103; // BIC $0xc0000000, R13
-					out[size/4+1] = ((p->scond&C_SCOND)<<28) | 0x03ccc13f; // BIC $0xc000000f, R12
-					out[size/4+2] = ((p->scond&C_SCOND)<<28) | 0x012fff1c; // BX R12
-				}
-				// p->pc+size is only ok at 4 or 12 mod 16.
-				if((p->pc+size)%8 == 0)
-					p->pc += 4;
-				size += 12;
-				break;
-			}
-		}
-
-		if(p->to.type == D_REG && p->to.reg == 15)
-			ctxt->diag("unsupported instruction (move to another register and use indirect jump instead): %P", p);
-
-		if(p->to.type == D_OREG && p->to.reg == 13 && (p->scond & C_WBIT) && size > 4) {
-			// function prolog with very large frame size: MOVW.W R14,-100004(R13)
-			// split it into two instructions:
-			// 	ADD $-100004, R13
-			// 	MOVW R14, 0(R13)
-			q = ctxt->arch->prg();
-			p->scond &= ~C_WBIT;
-			*q = *p;
-			a = &p->to;
-			if(p->to.type == D_OREG)
-				a2 = &q->to;
-			else
-				a2 = &q->from;
-			nocache(q);
-			nocache(p);
-			// insert q after p
-			q->link = p->link;
-			p->link = q;
-			q->pcond = nil;
-			// make p into ADD $X, R13
-			p->as = AADD;
-			p->from = *a;
-			p->from.reg = NREG;
-			p->from.type = D_CONST;
-			p->to = zprg.to;
-			p->to.type = D_REG;
-			p->to.reg = 13;
-			// make q into p but load/store from 0(R13)
-			q->spadj = 0;
-			*a2 = zprg.from;
-			a2->type = D_OREG;
-			a2->reg = 13;
-			a2->sym = nil;
-			a2->offset = 0;
-			size = oplook(ctxt, p)->size;
-			break;
-		}
-
-		if((p->to.type == D_OREG && p->to.reg != 13 && p->to.reg != 9) || // MOVW Rx, X(Ry), y != 13 && y != 9
-		   (p->from.type == D_OREG && p->from.reg != 13 && p->from.reg != 9)) { // MOVW X(Rx), Ry, x != 13 && x != 9
-			if(p->to.type == D_OREG)
-				a = &p->to;
-			else
-				a = &p->from;
-			reg = a->reg;
-			if(size == 4) {
-				// if addr.reg == NREG, then it is probably load from x(FP) with small x, no need to modify.
-				if(reg == NREG) {
-					if(out != nil)
-						asmout(ctxt, p, o, out);
-				} else {
-					if(out != nil)
-						out[0] = ((p->scond&C_SCOND)<<28) | 0x03c00103 | (reg << 16) | (reg << 12); // BIC $0xc0000000, Rx
-					if((p->pc&15) == 12)
-						p->pc += 4;
-					size += 4;
-					if(out != nil)
-						asmout(ctxt, p, o, &out[1]);
-				}
-				break;
-			} else {
-				// if a load/store instruction takes more than 1 word to implement, then
-				// we need to seperate the instruction into two:
-				// 1. explicitly load the address into R11.
-				// 2. load/store from R11.
-				// This won't handle .W/.P, so we should reject such code.
-				if(p->scond & (C_PBIT|C_WBIT))
-					ctxt->diag("unsupported instruction (.P/.W): %P", p);
-				q = ctxt->arch->prg();
-				*q = *p;
-				if(p->to.type == D_OREG)
-					a2 = &q->to;
-				else
-					a2 = &q->from;
-				nocache(q);
-				nocache(p);
-				// insert q after p
-				q->link = p->link;
-				p->link = q;
-				q->pcond = nil;
-				// make p into MOVW $X(R), R11
-				p->as = AMOVW;
-				p->from = *a;
-				p->from.type = D_CONST;
-				p->to = zprg.to;
-				p->to.type = D_REG;
-				p->to.reg = 11;
-				// make q into p but load/store from 0(R11)
-				*a2 = zprg.from;
-				a2->type = D_OREG;
-				a2->reg = 11;
-				a2->sym = nil;
-				a2->offset = 0;
-				size = oplook(ctxt, p)->size;
-				break;
-			}
-		} else if(out != nil)
-			asmout(ctxt, p, o, out);
-		break;
-	}
-
-	// destination register specific
-	if(p->to.type == D_REG) {
-		switch(p->to.reg) {
-		case 9:
-			ctxt->diag("invalid instruction, cannot write to R9: %P", p);
-			break;
-		case 13:
-			if(out != nil)
-				out[size/4] = 0xe3cdd103; // BIC $0xc0000000, R13
-			if(((p->pc+size) & 15) == 0)
-				p->pc += 4;
-			size += 4;
-			break;
-		}
-	}
-	return size;
-}
-
-void
-span5(Link *ctxt, LSym *cursym)
-{
-	Prog *p, *op;
-	Optab *o;
-	int m, bflag, i, v, times;
-	int32 c, opc, out[6+3];
-	uchar *bp;
-
-	p = cursym->text;
-	if(p == nil || p->link == nil) // handle external functions and ELF section symbols
-		return;
- 
- 	if(oprange[AAND].start == nil)
- 		buildop(ctxt);
-
- 	ctxt->cursym = cursym;
-
-	ctxt->autosize = p->to.offset + 4;
-	c = 0;
-
-	for(op = p, p = p->link; p != nil || ctxt->blitrl != nil; op = p, p = p->link) {
-		if(p == nil) {
-		       	if(checkpool(ctxt, op, 0)) {
-				p = op;
-				continue;
-			}
-			// can't happen: blitrl is not nil, but checkpool didn't flushpool
-			ctxt->diag("internal inconsistency");
-			break;
-		}
-		ctxt->curp = p;
-		p->pc = c;
-		o = oplook(ctxt, p);
-		if(ctxt->headtype != Hnacl) {
-			m = o->size;
-		} else {
-			m = asmoutnacl(ctxt, c, p, o, nil);
-			c = p->pc; // asmoutnacl might change pc for alignment
-			o = oplook(ctxt, p); // asmoutnacl might change p in rare cases
-		}
-		if(m % 4 != 0 || p->pc % 4 != 0) {
-			ctxt->diag("!pc invalid: %P size=%d", p, m);
-		}
-		// must check literal pool here in case p generates many instructions
-		if(ctxt->blitrl){
-			if(checkpool(ctxt, op, p->as == ACASE ? casesz(ctxt, p) : m)) {
-				p = op;
-				continue;
-			}
-		}
-		if(m == 0 && (p->as != AFUNCDATA && p->as != APCDATA && p->as != ADATABUNDLEEND && p->as != ANOP)) {
-			ctxt->diag("zero-width instruction\n%P", p);
-			continue;
-		}
-		switch(o->flag & (LFROM|LTO|LPOOL)) {
-		case LFROM:
-			addpool(ctxt, p, &p->from);
-			break;
-		case LTO:
-			addpool(ctxt, p, &p->to);
-			break;
-		case LPOOL:
-			if ((p->scond&C_SCOND) == C_SCOND_NONE)
-				flushpool(ctxt, p, 0, 0);
-			break;
-		}
-		if(p->as==AMOVW && p->to.type==D_REG && p->to.reg==REGPC && (p->scond&C_SCOND) == C_SCOND_NONE)
-			flushpool(ctxt, p, 0, 0);
-		c += m;
-	}
-	cursym->size = 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.
-	 */
-	times = 0;
-	do {
-		if(ctxt->debugvlog)
-			Bprint(ctxt->bso, "%5.2f span1\n", cputime());
-		bflag = 0;
-		c = 0;
-		times++;
-		cursym->text->pc = 0; // force re-layout the code.
-		for(p = cursym->text; p != nil; p = p->link) {
-			ctxt->curp = p;
-			o = oplook(ctxt,p);
-			if(c > p->pc)
-				p->pc = c;
-/* very large branches
-			if(o->type == 6 && p->pcond) {
-				otxt = p->pcond->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 = D_BRANCH;
-					q->pcond = p->pcond;
-					p->pcond = q;
-					q = ctxt->arch->prg();
-					q->link = p->link;
-					p->link = q;
-					q->as = AB;
-					q->to.type = D_BRANCH;
-					q->pcond = q->link->link;
-					bflag = 1;
-				}
-			}
- */
-			opc = p->pc;
-			if(ctxt->headtype != Hnacl)
-				m = o->size;
-			else
-				m = asmoutnacl(ctxt, c, p, o, nil);
-			if(p->pc != opc) {
-				bflag = 1;
-				//print("%P pc changed %d to %d in iter. %d\n", p, opc, (int32)p->pc, times);
-			}
-			c = p->pc + m;
-			if(m % 4 != 0 || p->pc % 4 != 0) {
-				ctxt->diag("pc invalid: %P size=%d", p, m);
-			}
-			if(m/4 > nelem(out))
-				ctxt->diag("instruction size too large: %d > %d", m/4, nelem(out));
-			if(m == 0 && (p->as != AFUNCDATA && p->as != APCDATA && p->as != ADATABUNDLEEND && p->as != ANOP)) {
-				if(p->as == ATEXT) {
-					ctxt->autosize = p->to.offset + 4;
-					continue;
-				}
-				ctxt->diag("zero-width instruction\n%P", p);
-				continue;
-			}
-		}
-		cursym->size = c;
-	} while(bflag);
-	if(c % 4 != 0) {
-		ctxt->diag("sym->size=%d, invalid", c);
-	}
-
-	/*
-	 * lay out the code.  all the pc-relative code references,
-	 * even cross-function, are resolved now;
-	 * only data references need to be relocated.
-	 * with more work we could leave cross-function
-	 * code references to be relocated too, and then
-	 * perhaps we'd be able to parallelize the span loop above.
-	 */
-	if(ctxt->tlsg == nil)
-		ctxt->tlsg = linklookup(ctxt, "runtime.tlsg", 0);
-
-	p = cursym->text;
-	ctxt->autosize = p->to.offset + 4;
-	symgrow(ctxt, cursym, cursym->size);
-
-	bp = cursym->p;
-	c = p->pc; // even p->link might need extra padding
-	for(p = p->link; p != nil; p = p->link) {
-		ctxt->pc = p->pc;
-		ctxt->curp = p;
-		o = oplook(ctxt, p);
-		opc = p->pc;
-		if(ctxt->headtype != Hnacl) {
-			asmout(ctxt, p, o, out);
-			m = o->size;
-		} else {
-			m = asmoutnacl(ctxt, c, p, o, out);
-			if(opc != p->pc)
-				ctxt->diag("asmoutnacl broken: pc changed (%d->%d) in last stage: %P", opc, (int32)p->pc, p);
-		}
-		if(m % 4 != 0 || p->pc % 4 != 0) {
-			ctxt->diag("final stage: pc invalid: %P size=%d", p, m);
-		}
-		if(c > p->pc)
-			ctxt->diag("PC padding invalid: want %#lld, has %#d: %P", p->pc, c, p);
-		while(c != p->pc) {
-			// emit 0xe1a00000 (MOVW R0, R0)
-			*bp++ = 0x00;
-			*bp++ = 0x00;
-			*bp++ = 0xa0;
-			*bp++ = 0xe1;
-			c += 4;
-		}
-		for(i=0; i<m/4; i++) {
-			v = out[i];
-			*bp++ = v;
-			*bp++ = v>>8;
-			*bp++ = v>>16;
-			*bp++ = v>>24;
-		}
-		c += m;
-	}
-}
-
-/*
- * when the first reference to the literal pool threatens
- * to go out of range of a 12-bit PC-relative offset,
- * drop the pool now, and branch round it.
- * this happens only in extended basic blocks that exceed 4k.
- */
-static int
-checkpool(Link *ctxt, Prog *p, int sz)
-{
-	if(pool.size >= 0xff0 || immaddr((p->pc+sz+4)+4+(12+pool.size) - (pool.start+8)) == 0)
-		return flushpool(ctxt, p, 1, 0);
-	else if(p->link == nil)
-		return flushpool(ctxt, p, 2, 0);
-	return 0;
-}
-
-static int
-flushpool(Link *ctxt, Prog *p, int skip, int force)
-{
-	Prog *q;
-
-	if(ctxt->blitrl) {
-		if(skip){
-			if(0 && skip==1)print("note: flush literal pool at %llux: len=%ud ref=%ux\n", p->pc+4, pool.size, pool.start);
-			q = ctxt->arch->prg();
-			q->as = AB;
-			q->to.type = D_BRANCH;
-			q->pcond = p->link;
-			q->link = ctxt->blitrl;
-			q->lineno = p->lineno;
-			ctxt->blitrl = q;
-		}
-		else if(!force && (p->pc+(12+pool.size)-pool.start < 2048)) // 12 take into account the maximum nacl literal pool alignment padding size
-			return 0;
-		if(ctxt->headtype == Hnacl && pool.size % 16 != 0) {
-			// if pool is not multiple of 16 bytes, add an alignment marker
-			q = ctxt->arch->prg();
-			q->as = ADATABUNDLEEND;
-			ctxt->elitrl->link = q;
-			ctxt->elitrl = q;
-		}
-		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
-		while(ctxt->blitrl) {
-			ctxt->blitrl->lineno = p->lineno;
-			ctxt->blitrl = ctxt->blitrl->link;
-		}
-		ctxt->blitrl = 0;	/* BUG: should refer back to values until out-of-range */
-		ctxt->elitrl = 0;
-		pool.size = 0;
-		pool.start = 0;
-		pool.extra = 0;
-		return 1;
-	}
-	return 0;
-}
-
-static void
-addpool(Link *ctxt, Prog *p, Addr *a)
-{
-	Prog *q, t;
-	int c;
-
-	c = aclass(ctxt, a);
-
-	t = zprg;
-	t.as = AWORD;
-
-	switch(c) {
-	default:
-		t.to.offset = a->offset;
-		t.to.sym = a->sym;
-		t.to.type = a->type;
-		t.to.name = a->name;
-		
-		if(ctxt->flag_shared && t.to.sym != nil)
-			t.pcrel = p;
-		break;
-
-	case C_SROREG:
-	case C_LOREG:
-	case C_ROREG:
-	case C_FOREG:
-	case C_SOREG:
-	case C_HOREG:
-	case C_FAUTO:
-	case C_SAUTO:
-	case C_LAUTO:
-	case C_LACON:
-		t.to.type = D_CONST;
-		t.to.offset = ctxt->instoffset;
-		break;
-	}
-
-	if(t.pcrel == nil) {
-		for(q = ctxt->blitrl; q != nil; q = q->link)	/* could hash on t.t0.offset */
-			if(q->pcrel == nil && memcmp(&q->to, &t.to, sizeof(t.to)) == 0) {
-				p->pcond = q;
-				return;
-			}
-	}
-
-	if(ctxt->headtype == Hnacl && pool.size%16 == 0) {
-		// start a new data bundle
-		q = ctxt->arch->prg();
-		*q = zprg;
-		q->as = ADATABUNDLE;
-		q->pc = pool.size;
-		pool.size += 4;
-		if(ctxt->blitrl == nil) {
-			ctxt->blitrl = q;
-			pool.start = p->pc;
-		} else {
-			ctxt->elitrl->link = q;
-		}
-		ctxt->elitrl = q;
-	}
-
-	q = ctxt->arch->prg();
-	*q = t;
-	q->pc = pool.size;
-
-	if(ctxt->blitrl == nil) {
-		ctxt->blitrl = q;
-		pool.start = p->pc;
-	} else
-		ctxt->elitrl->link = q;
-	ctxt->elitrl = q;
-	pool.size += 4;
-
-	p->pcond = q;
-}
-
-static int32
-regoff(Link *ctxt, Addr *a)
-{
-
-	ctxt->instoffset = 0;
-	aclass(ctxt, a);
-	return ctxt->instoffset;
-}
-
-static int32
-immrot(uint32 v)
-{
-	int i;
-
-	for(i=0; i<16; i++) {
-		if((v & ~0xff) == 0)
-			return (i<<8) | v | (1<<25);
-		v = (v<<2) | (v>>30);
-	}
-	return 0;
-}
-
-static int32
-immaddr(int32 v)
-{
-	if(v >= 0 && v <= 0xfff)
-		return (v & 0xfff) |
-			(1<<24) |	/* pre indexing */
-			(1<<23);	/* pre indexing, up */
-	if(v >= -0xfff && v < 0)
-		return (-v & 0xfff) |
-			(1<<24);	/* pre indexing */
-	return 0;
-}
-
-static int
-immfloat(int32 v)
-{
-	return (v & 0xC03) == 0;	/* offset will fit in floating-point load/store */
-}
-
-static int
-immhalf(int32 v)
-{
-	if(v >= 0 && v <= 0xff)
-		return v|
-			(1<<24)|	/* pre indexing */
-			(1<<23);	/* pre indexing, up */
-	if(v >= -0xff && v < 0)
-		return (-v & 0xff)|
-			(1<<24);	/* pre indexing */
-	return 0;
-}
-
-static int aconsize(Link *ctxt);
-
-static int
-aclass(Link *ctxt, Addr *a)
-{
-	LSym *s;
-	int t;
-
-	switch(a->type) {
-	case D_NONE:
-		return C_NONE;
-
-	case D_REG:
-		return C_REG;
-
-	case D_REGREG:
-		return C_REGREG;
-
-	case D_REGREG2:
-		return C_REGREG2;
-
-	case D_SHIFT:
-		return C_SHIFT;
-
-	case D_FREG:
-		return C_FREG;
-
-	case D_FPCR:
-		return C_FCR;
-
-	case D_OREG:
-		switch(a->name) {
-		case D_EXTERN:
-		case D_STATIC:
-			if(a->sym == 0 || a->sym->name == 0) {
-				print("null sym external\n");
-				return C_GOK;
-			}
-			ctxt->instoffset = 0;	// s.b. unused but just in case
-			return C_ADDR;
-
-		case D_AUTO:
-			ctxt->instoffset = ctxt->autosize + a->offset;
-			t = immaddr(ctxt->instoffset);
-			if(t){
-				if(immhalf(ctxt->instoffset))
-					return immfloat(t) ? C_HFAUTO : C_HAUTO;
-				if(immfloat(t))
-					return C_FAUTO;
-				return C_SAUTO;
-			}
-			return C_LAUTO;
-
-		case D_PARAM:
-			ctxt->instoffset = ctxt->autosize + a->offset + 4L;
-			t = immaddr(ctxt->instoffset);
-			if(t){
-				if(immhalf(ctxt->instoffset))
-					return immfloat(t) ? C_HFAUTO : C_HAUTO;
-				if(immfloat(t))
-					return C_FAUTO;
-				return C_SAUTO;
-			}
-			return C_LAUTO;
-		case D_NONE:
-			ctxt->instoffset = a->offset;
-			t = immaddr(ctxt->instoffset);
-			if(t) {
-				if(immhalf(ctxt->instoffset))		 /* n.b. that it will also satisfy immrot */
-					return immfloat(t) ? C_HFOREG : C_HOREG;
-				if(immfloat(t))
-					return C_FOREG; /* n.b. that it will also satisfy immrot */
-				t = immrot(ctxt->instoffset);
-				if(t)
-					return C_SROREG;
-				if(immhalf(ctxt->instoffset))
-					return C_HOREG;
-				return C_SOREG;
-			}
-			t = immrot(ctxt->instoffset);
-			if(t)
-				return C_ROREG;
-			return C_LOREG;
-		}
-		return C_GOK;
-
-	case D_PSR:
-		return C_PSR;
-
-	case D_OCONST:
-		switch(a->name) {
-		case D_EXTERN:
-		case D_STATIC:
-			ctxt->instoffset = 0;	// s.b. unused but just in case
-			return C_ADDR;
-		}
-		return C_GOK;
-
-	case D_FCONST:
-		if(chipzero5(ctxt, a->u.dval) >= 0)
-			return C_ZFCON;
-		if(chipfloat5(ctxt, a->u.dval) >= 0)
-			return C_SFCON;
-		return C_LFCON;
-
-	case D_CONST:
-	case D_CONST2:
-		switch(a->name) {
-
-		case D_NONE:
-			ctxt->instoffset = a->offset;
-			if(a->reg != NREG)
-				return aconsize(ctxt);
-
-			t = immrot(ctxt->instoffset);
-			if(t)
-				return C_RCON;
-			t = immrot(~ctxt->instoffset);
-			if(t)
-				return C_NCON;
-			return C_LCON;
-
-		case D_EXTERN:
-		case D_STATIC:
-			s = a->sym;
-			if(s == nil)
-				break;
-			ctxt->instoffset = 0;	// s.b. unused but just in case
-			return C_LCONADDR;
-
-		case D_AUTO:
-			ctxt->instoffset = ctxt->autosize + a->offset;
-			return aconsize(ctxt);
-
-		case D_PARAM:
-			ctxt->instoffset = ctxt->autosize + a->offset + 4L;
-			return aconsize(ctxt);
-		}
-		return C_GOK;
-
-	case D_BRANCH:
-		return C_SBRA;
-	}
-	return C_GOK;
-}
-
-static int
-aconsize(Link *ctxt)
-{
-	int t;
-
-	t = immrot(ctxt->instoffset);
-	if(t)
-		return C_RACON;
-	return C_LACON;
-}
-
-static void
-prasm(Prog *p)
-{
-	print("%P\n", p);
-}
-
-static Optab*
-oplook(Link *ctxt, Prog *p)
-{
-	int a1, a2, a3, r;
-	uchar *c1, *c3;
-	Optab *o, *e;
-
-	a1 = p->optab;
-	if(a1)
-		return optab+(a1-1);
-	a1 = p->from.class;
-	if(a1 == 0) {
-		a1 = aclass(ctxt, &p->from) + 1;
-		p->from.class = a1;
-	}
-	a1--;
-	a3 = p->to.class;
-	if(a3 == 0) {
-		a3 = aclass(ctxt, &p->to) + 1;
-		p->to.class = a3;
-	}
-	a3--;
-	a2 = C_NONE;
-	if(p->reg != NREG)
-		a2 = C_REG;
-	r = p->as;
-	o = oprange[r].start;
-	if(o == 0) {
-		o = oprange[r].stop; /* just generate an error */
-	}
-	if(0 /*debug['O']*/) {
-		print("oplook %A %^ %^ %^\n",
-			(int)p->as, a1, a2, a3);
-		print("		%d %d\n", p->from.type, p->to.type);
-	}
-	e = oprange[r].stop;
-	c1 = xcmp[a1];
-	c3 = xcmp[a3];
-	for(; o<e; o++)
-		if(o->a2 == a2)
-		if(c1[o->a1])
-		if(c3[o->a3]) {
-			p->optab = (o-optab)+1;
-			return o;
-		}
-	ctxt->diag("illegal combination %P; %^ %^ %^, %d %d",
-		p, a1, a2, a3, p->from.type, p->to.type);
-	ctxt->diag("from %d %d to %d %d\n", p->from.type, p->from.name, p->to.type, p->to.name);
-	prasm(p);
-	if(o == 0)
-		o = optab;
-	return o;
-}
-
-static int
-cmp(int a, int b)
-{
-
-	if(a == b)
-		return 1;
-	switch(a) {
-	case C_LCON:
-		if(b == C_RCON || b == C_NCON)
-			return 1;
-		break;
-	case C_LACON:
-		if(b == C_RACON)
-			return 1;
-		break;
-	case C_LFCON:
-		if(b == C_ZFCON || b == C_SFCON)
-			return 1;
-		break;
-
-	case C_HFAUTO:
-		return b == C_HAUTO || b == C_FAUTO;
-	case C_FAUTO:
-	case C_HAUTO:
-		return b == C_HFAUTO;
-	case C_SAUTO:
-		return cmp(C_HFAUTO, b);
-	case C_LAUTO:
-		return cmp(C_SAUTO, b);
-
-	case C_HFOREG:
-		return b == C_HOREG || b == C_FOREG;
-	case C_FOREG:
-	case C_HOREG:
-		return b == C_HFOREG;
-	case C_SROREG:
-		return cmp(C_SOREG, b) || cmp(C_ROREG, b);
-	case C_SOREG:
-	case C_ROREG:
-		return b == C_SROREG || cmp(C_HFOREG, b);
-	case C_LOREG:
-		return cmp(C_SROREG, b);
-
-	case C_LBRA:
-		if(b == C_SBRA)
-			return 1;
-		break;
-
-	case C_HREG:
-		return cmp(C_SP, b) || cmp(C_PC, b);
-
-	}
-	return 0;
-}
-
-static int
-ocmp(const void *a1, const void *a2)
-{
-	Optab *p1, *p2;
-	int n;
-
-	p1 = (Optab*)a1;
-	p2 = (Optab*)a2;
-	n = p1->as - p2->as;
-	if(n)
-		return n;
-	n = p1->a1 - p2->a1;
-	if(n)
-		return n;
-	n = p1->a2 - p2->a2;
-	if(n)
-		return n;
-	n = p1->a3 - p2->a3;
-	if(n)
-		return n;
-	return 0;
-}
-
-static void
-buildop(Link *ctxt)
-{
-	int i, n, r;
-
-	for(i=0; i<C_GOK; i++)
-		for(n=0; n<C_GOK; n++)
-			xcmp[i][n] = cmp(n, i);
-	for(n=0; optab[n].as != AXXX; n++) {
-		if((optab[n].flag & LPCREL) != 0) {
-			if(ctxt->flag_shared)
-				optab[n].size += optab[n].pcrelsiz;
-			else
-				optab[n].flag &= ~LPCREL;
-		}
-	}
-	qsort(optab, n, sizeof(optab[0]), ocmp);
-	for(i=0; i<n; i++) {
-		r = optab[i].as;
-		oprange[r].start = optab+i;
-		while(optab[i].as == r)
-			i++;
-		oprange[r].stop = optab+i;
-		i--;
-
-		switch(r)
-		{
-		default:
-			ctxt->diag("unknown op in build: %A", r);
-			sysfatal("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];
-			break;
-		case ACMP:
-			oprange[ATEQ] = oprange[r];
-			oprange[ACMN] = oprange[r];
-			break;
-		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];
-			break;
-		case ASLL:
-			oprange[ASRL] = oprange[r];
-			oprange[ASRA] = oprange[r];
-			break;
-		case AMUL:
-			oprange[AMULU] = oprange[r];
-			break;
-		case ADIV:
-			oprange[AMOD] = oprange[r];
-			oprange[AMODU] = oprange[r];
-			oprange[ADIVU] = oprange[r];
-			break;
-		case AMOVW:
-		case AMOVB:
-		case AMOVBS:
-		case AMOVBU:
-		case AMOVH:
-		case AMOVHS:
-		case AMOVHU:
-			break;
-		case ASWPW:
-			oprange[ASWPBU] = oprange[r];
-			break;
-		case AB:
-		case ABL:
-		case ABX:
-		case ABXRET:
-		case ADUFFZERO:
-		case ADUFFCOPY:
-		case ASWI:
-		case AWORD:
-		case AMOVM:
-		case ARFE:
-		case ATEXT:
-		case AUSEFIELD:
-		case ACASE:
-		case ABCASE:
-		case ATYPE:
-			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];
-			break;
-
-		case ACMPF:
-			oprange[ACMPD] = oprange[r];
-			break;
-
-		case AMOVF:
-			oprange[AMOVD] = oprange[r];
-			break;
-
-		case AMOVFW:
-			oprange[AMOVDW] = oprange[r];
-			break;
-
-		case AMOVWF:
-			oprange[AMOVWD] = oprange[r];
-			break;
-
-		case AMULL:
-			oprange[AMULAL] = oprange[r];
-			oprange[AMULLU] = oprange[r];
-			oprange[AMULALU] = oprange[r];
-			break;
-
-		case AMULWT:
-			oprange[AMULWB] = oprange[r];
-			break;
-
-		case AMULAWT:
-			oprange[AMULAWB] = oprange[r];
-			break;
-
-		case AMULA:
-		case ALDREX:
-		case ASTREX:
-		case ALDREXD:
-		case ASTREXD:
-		case ATST:
-		case APLD:
-		case AUNDEF:
-		case ACLZ:
-		case AFUNCDATA:
-		case APCDATA:
-		case ANOP:
-		case ADATABUNDLE:
-		case ADATABUNDLEEND:
-			break;
-		}
-	}
-}
-
-static int32 mov(Link*, Prog*);
-
-static void
-asmout(Link *ctxt, Prog *p, Optab *o, int32 *out)
-{
-	int32 o1, o2, o3, o4, o5, o6, v;
-	int r, rf, rt, rt2;
-	Reloc *rel;
-
-ctxt->printp = p;
-	o1 = 0;
-	o2 = 0;
-	o3 = 0;
-	o4 = 0;
-	o5 = 0;
-	o6 = 0;
-	ctxt->armsize += o->size;
-if(0 /*debug['P']*/) print("%ux: %P	type %d\n", (uint32)(p->pc), p, o->type);
-	switch(o->type) {
-	default:
-		ctxt->diag("unknown asm %d", o->type);
-		prasm(p);
-		break;
-
-	case 0:		/* pseudo ops */
-if(0 /*debug['G']*/) print("%ux: %s: arm %d\n", (uint32)(p->pc), p->from.sym->name, p->from.sym->fnptr);
-		break;
-
-	case 1:		/* op R,[R],R */
-		o1 = oprrr(ctxt, p->as, p->scond);
-		rf = p->from.reg;
-		rt = p->to.reg;
-		r = p->reg;
-		if(p->to.type == D_NONE)
-			rt = 0;
-		if(p->as == AMOVB || p->as == AMOVH || p->as == AMOVW || p->as == AMVN)
-			r = 0;
-		else
-		if(r == NREG)
-			r = rt;
-		o1 |= rf | (r<<16) | (rt<<12);
-		break;
-
-	case 2:		/* movbu $I,[R],R */
-		aclass(ctxt, &p->from);
-		o1 = oprrr(ctxt, p->as, p->scond);
-		o1 |= immrot(ctxt->instoffset);
-		rt = p->to.reg;
-		r = p->reg;
-		if(p->to.type == D_NONE)
-			rt = 0;
-		if(p->as == AMOVW || p->as == AMVN)
-			r = 0;
-		else if(r == NREG)
-			r = rt;
-		o1 |= (r<<16) | (rt<<12);
-		break;
-
-	case 3:		/* add R<<[IR],[R],R */
-		o1 = mov(ctxt, p);
-		break;
-
-	case 4:		/* add $I,[R],R */
-		aclass(ctxt, &p->from);
-		o1 = oprrr(ctxt, AADD, p->scond);
-		o1 |= immrot(ctxt->instoffset);
-		r = p->from.reg;
-		if(r == NREG)
-			r = o->param;
-		o1 |= r << 16;
-		o1 |= p->to.reg << 12;
-		break;
-
-	case 5:		/* bra s */
-		o1 = opbra(ctxt, p->as, p->scond);
-		v = -8;
-		if(p->to.sym != nil) {
-			rel = addrel(ctxt->cursym);
-			rel->off = ctxt->pc;
-			rel->siz = 4;
-			rel->sym = p->to.sym;
-			v += p->to.offset;
-			rel->add = o1 | ((v >> 2) & 0xffffff);
-			rel->type = R_CALLARM;
-			break;
-		}
-		if(p->pcond != nil)
-			v = (p->pcond->pc - ctxt->pc) - 8;
-		o1 |= (v >> 2) & 0xffffff;
-		break;
-
-	case 6:		/* b ,O(R) -> add $O,R,PC */
-		aclass(ctxt, &p->to);
-		o1 = oprrr(ctxt, AADD, p->scond);
-		o1 |= immrot(ctxt->instoffset);
-		o1 |= p->to.reg << 16;
-		o1 |= REGPC << 12;
-		break;
-
-	case 7:		/* bl (R) -> blx R */
-		aclass(ctxt, &p->to);
-		if(ctxt->instoffset != 0)
-			ctxt->diag("%P: doesn't support BL offset(REG) where offset != 0", p);
-		o1 = oprrr(ctxt, ABL, p->scond);
-		o1 |= p->to.reg;
-		rel = addrel(ctxt->cursym);
-		rel->off = ctxt->pc;
-		rel->siz = 0;
-		rel->type = R_CALLIND;
-		break;
-
-	case 8:		/* sll $c,[R],R -> mov (R<<$c),R */
-		aclass(ctxt, &p->from);
-		o1 = oprrr(ctxt, p->as, p->scond);
-		r = p->reg;
-		if(r == NREG)
-			r = p->to.reg;
-		o1 |= r;
-		o1 |= (ctxt->instoffset&31) << 7;
-		o1 |= p->to.reg << 12;
-		break;
-
-	case 9:		/* sll R,[R],R -> mov (R<<R),R */
-		o1 = oprrr(ctxt, p->as, p->scond);
-		r = p->reg;
-		if(r == NREG)
-			r = p->to.reg;
-		o1 |= r;
-		o1 |= (p->from.reg << 8) | (1<<4);
-		o1 |= p->to.reg << 12;
-		break;
-
-	case 10:	/* swi [$con] */
-		o1 = oprrr(ctxt, p->as, p->scond);
-		if(p->to.type != D_NONE) {
-			aclass(ctxt, &p->to);
-			o1 |= ctxt->instoffset & 0xffffff;
-		}
-		break;
-
-	case 11:	/* word */
-		aclass(ctxt, &p->to);
-		o1 = ctxt->instoffset;
-		if(p->to.sym != nil) {
-			// This case happens with words generated
-			// in the PC stream as part of the literal pool.
-			rel = addrel(ctxt->cursym);
-			rel->off = ctxt->pc;
-			rel->siz = 4;
-			rel->sym = p->to.sym;
-			rel->add = p->to.offset;
-			
-			// runtime.tlsg is special.
-			// Its "address" is the offset from the TLS thread pointer
-			// to the thread-local g and m pointers.
-			// Emit a TLS relocation instead of a standard one.
-			if(rel->sym == ctxt->tlsg) {
-				rel->type = R_TLS;
-				if(ctxt->flag_shared)
-					rel->add += ctxt->pc - p->pcrel->pc - 8 - rel->siz;
-				rel->xadd = rel->add;
-				rel->xsym = rel->sym;
-			} else if(ctxt->flag_shared) {
-				rel->type = R_PCREL;
-				rel->add += ctxt->pc - p->pcrel->pc - 8;
-			} else
-				rel->type = R_ADDR;
-			o1 = 0;
-		}
-		break;
-
-	case 12:	/* movw $lcon, reg */
-		o1 = omvl(ctxt, p, &p->from, p->to.reg);
-		if(o->flag & LPCREL) {
-			o2 = oprrr(ctxt, AADD, p->scond) | p->to.reg | REGPC << 16 | p->to.reg << 12;
-		}
-		break;
-
-	case 13:	/* op $lcon, [R], R */
-		o1 = omvl(ctxt, p, &p->from, REGTMP);
-		if(!o1)
-			break;
-		o2 = oprrr(ctxt, p->as, p->scond);
-		o2 |= REGTMP;
-		r = p->reg;
-		if(p->as == AMOVW || p->as == AMVN)
-			r = 0;
-		else if(r == NREG)
-			r = p->to.reg;
-		o2 |= r << 16;
-		if(p->to.type != D_NONE)
-			o2 |= p->to.reg << 12;
-		break;
-
-	case 14:	/* movb/movbu/movh/movhu R,R */
-		o1 = oprrr(ctxt, ASLL, p->scond);
-
-		if(p->as == AMOVBU || p->as == AMOVHU)
-			o2 = oprrr(ctxt, ASRL, p->scond);
-		else
-			o2 = oprrr(ctxt, ASRA, p->scond);
-
-		r = p->to.reg;
-		o1 |= (p->from.reg)|(r<<12);
-		o2 |= (r)|(r<<12);
-		if(p->as == AMOVB || p->as == AMOVBS || p->as == AMOVBU) {
-			o1 |= (24<<7);
-			o2 |= (24<<7);
-		} else {
-			o1 |= (16<<7);
-			o2 |= (16<<7);
-		}
-		break;
-
-	case 15:	/* mul r,[r,]r */
-		o1 = oprrr(ctxt, p->as, p->scond);
-		rf = p->from.reg;
-		rt = p->to.reg;
-		r = p->reg;
-		if(r == NREG)
-			r = rt;
-		if(rt == r) {
-			r = rf;
-			rf = rt;
-		}
-		if(0)
-		if(rt == r || rf == REGPC || r == REGPC || rt == REGPC) {
-			ctxt->diag("bad registers in MUL");
-			prasm(p);
-		}
-		o1 |= (rf<<8) | r | (rt<<16);
-		break;
-
-
-	case 16:	/* div r,[r,]r */
-		o1 = 0xf << 28;
-		o2 = 0;
-		break;
-
-	case 17:
-		o1 = oprrr(ctxt, p->as, p->scond);
-		rf = p->from.reg;
-		rt = p->to.reg;
-		rt2 = p->to.offset;
-		r = p->reg;
-		o1 |= (rf<<8) | r | (rt<<16) | (rt2<<12);
-		break;
-
-	case 20:	/* mov/movb/movbu R,O(R) */
-		aclass(ctxt, &p->to);
-		r = p->to.reg;
-		if(r == NREG)
-			r = o->param;
-		o1 = osr(ctxt, p->as, p->from.reg, ctxt->instoffset, r, p->scond);
-		break;
-
-	case 21:	/* mov/movbu O(R),R -> lr */
-		aclass(ctxt, &p->from);
-		r = p->from.reg;
-		if(r == NREG)
-			r = o->param;
-		o1 = olr(ctxt, ctxt->instoffset, r, p->to.reg, p->scond);
-		if(p->as != AMOVW)
-			o1 |= 1<<22;
-		break;
-
-	case 30:	/* mov/movb/movbu R,L(R) */
-		o1 = omvl(ctxt, p, &p->to, REGTMP);
-		if(!o1)
-			break;
-		r = p->to.reg;
-		if(r == NREG)
-			r = o->param;
-		o2 = osrr(ctxt, p->from.reg, REGTMP,r, p->scond);
-		if(p->as != AMOVW)
-			o2 |= 1<<22;
-		break;
-
-	case 31:	/* mov/movbu L(R),R -> lr[b] */
-		o1 = omvl(ctxt, p, &p->from, REGTMP);
-		if(!o1)
-			break;
-		r = p->from.reg;
-		if(r == NREG)
-			r = o->param;
-		o2 = olrr(ctxt, REGTMP,r, p->to.reg, p->scond);
-		if(p->as == AMOVBU || p->as == AMOVBS || p->as == AMOVB)
-			o2 |= 1<<22;
-		break;
-
-	case 34:	/* mov $lacon,R */
-		o1 = omvl(ctxt, p, &p->from, REGTMP);
-		if(!o1)
-			break;
-
-		o2 = oprrr(ctxt, AADD, p->scond);
-		o2 |= REGTMP;
-		r = p->from.reg;
-		if(r == NREG)
-			r = o->param;
-		o2 |= r << 16;
-		if(p->to.type != D_NONE)
-			o2 |= p->to.reg << 12;
-		break;
-
-	case 35:	/* mov PSR,R */
-		o1 = (2<<23) | (0xf<<16) | (0<<0);
-		o1 |= (p->scond & C_SCOND) << 28;
-		o1 |= (p->from.reg & 1) << 22;
-		o1 |= p->to.reg << 12;
-		break;
-
-	case 36:	/* mov R,PSR */
-		o1 = (2<<23) | (0x29f<<12) | (0<<4);
-		if(p->scond & C_FBIT)
-			o1 ^= 0x010 << 12;
-		o1 |= (p->scond & C_SCOND) << 28;
-		o1 |= (p->to.reg & 1) << 22;
-		o1 |= p->from.reg << 0;
-		break;
-
-	case 37:	/* mov $con,PSR */
-		aclass(ctxt, &p->from);
-		o1 = (2<<23) | (0x29f<<12) | (0<<4);
-		if(p->scond & C_FBIT)
-			o1 ^= 0x010 << 12;
-		o1 |= (p->scond & C_SCOND) << 28;
-		o1 |= immrot(ctxt->instoffset);
-		o1 |= (p->to.reg & 1) << 22;
-		o1 |= p->from.reg << 0;
-		break;
-
-	case 38:
-	case 39:
-		switch(o->type) {
-		case 38:	/* movm $con,oreg -> stm */
-			o1 = (0x4 << 25);
-			o1 |= p->from.offset & 0xffff;
-			o1 |= p->to.reg << 16;
-			aclass(ctxt, &p->to);
-			break;
-	
-		case 39:	/* movm oreg,$con -> ldm */
-			o1 = (0x4 << 25) | (1 << 20);
-			o1 |= p->to.offset & 0xffff;
-			o1 |= p->from.reg << 16;
-			aclass(ctxt, &p->from);
-			break;
-		}
-		if(ctxt->instoffset != 0)
-			ctxt->diag("offset must be zero in MOVM; %P", p);
-		o1 |= (p->scond & C_SCOND) << 28;
-		if(p->scond & C_PBIT)
-			o1 |= 1 << 24;
-		if(p->scond & C_UBIT)
-			o1 |= 1 << 23;
-		if(p->scond & C_SBIT)
-			o1 |= 1 << 22;
-		if(p->scond & C_WBIT)
-			o1 |= 1 << 21;
-		break;
-
-	case 40:	/* swp oreg,reg,reg */
-		aclass(ctxt, &p->from);
-		if(ctxt->instoffset != 0)
-			ctxt->diag("offset must be zero in SWP");
-		o1 = (0x2<<23) | (0x9<<4);
-		if(p->as != ASWPW)
-			o1 |= 1 << 22;
-		o1 |= p->from.reg << 16;
-		o1 |= p->reg << 0;
-		o1 |= p->to.reg << 12;
-		o1 |= (p->scond & C_SCOND) << 28;
-		break;
-
-	case 41:	/* rfe -> movm.s.w.u 0(r13),[r15] */
-		o1 = 0xe8fd8000;
-		break;
-
-	case 50:	/* floating point store */
-		v = regoff(ctxt, &p->to);
-		r = p->to.reg;
-		if(r == NREG)
-			r = o->param;
-		o1 = ofsr(ctxt, p->as, p->from.reg, v, r, p->scond, p);
-		break;
-
-	case 51:	/* floating point load */
-		v = regoff(ctxt, &p->from);
-		r = p->from.reg;
-		if(r == NREG)
-			r = o->param;
-		o1 = ofsr(ctxt, p->as, p->to.reg, v, r, p->scond, p) | (1<<20);
-		break;
-
-	case 52:	/* floating point store, int32 offset UGLY */
-		o1 = omvl(ctxt, p, &p->to, REGTMP);
-		if(!o1)
-			break;
-		r = p->to.reg;
-		if(r == NREG)
-			r = o->param;
-		o2 = oprrr(ctxt, AADD, p->scond) | (REGTMP << 12) | (REGTMP << 16) | r;
-		o3 = ofsr(ctxt, p->as, p->from.reg, 0, REGTMP, p->scond, p);
-		break;
-
-	case 53:	/* floating point load, int32 offset UGLY */
-		o1 = omvl(ctxt, p, &p->from, REGTMP);
-		if(!o1)
-			break;
-		r = p->from.reg;
-		if(r == NREG)
-			r = o->param;
-		o2 = oprrr(ctxt, AADD, p->scond) | (REGTMP << 12) | (REGTMP << 16) | r;
-		o3 = ofsr(ctxt, p->as, p->to.reg, 0, REGTMP, p->scond, p) | (1<<20);
-		break;
-
-	case 54:	/* floating point arith */
-		o1 = oprrr(ctxt, p->as, p->scond);
-		rf = p->from.reg;
-		rt = p->to.reg;
-		r = p->reg;
-		if(r == NREG) {
-			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)
-				r = 0;
-		}
-		o1 |= rf | (r<<16) | (rt<<12);
-		break;
-
-	case 56:	/* move to FP[CS]R */
-		o1 = ((p->scond & C_SCOND) << 28) | (0xe << 24) | (1<<8) | (1<<4);
-		o1 |= ((p->to.reg+1)<<21) | (p->from.reg << 12);
-		break;
-
-	case 57:	/* move from FP[CS]R */
-		o1 = ((p->scond & C_SCOND) << 28) | (0xe << 24) | (1<<8) | (1<<4);
-		o1 |= ((p->from.reg+1)<<21) | (p->to.reg<<12) | (1<<20);
-		break;
-	case 58:	/* movbu R,R */
-		o1 = oprrr(ctxt, AAND, p->scond);
-		o1 |= immrot(0xff);
-		rt = p->to.reg;
-		r = p->from.reg;
-		if(p->to.type == D_NONE)
-			rt = 0;
-		if(r == NREG)
-			r = rt;
-		o1 |= (r<<16) | (rt<<12);
-		break;
-
-	case 59:	/* movw/bu R<<I(R),R -> ldr indexed */
-		if(p->from.reg == NREG) {
-			if(p->as != AMOVW)
-				ctxt->diag("byte MOV from shifter operand");
-			o1 = mov(ctxt, p);
-			break;
-		}
-		if(p->from.offset&(1<<4))
-			ctxt->diag("bad shift in LDR");
-		o1 = olrr(ctxt, p->from.offset, p->from.reg, p->to.reg, p->scond);
-		if(p->as == AMOVBU)
-			o1 |= 1<<22;
-		break;
-
-	case 60:	/* movb R(R),R -> ldrsb indexed */
-		if(p->from.reg == NREG) {
-			ctxt->diag("byte MOV from shifter operand");
-			o1 = mov(ctxt, p);
-			break;
-		}
-		if(p->from.offset&(~0xf))
-			ctxt->diag("bad shift in LDRSB");
-		o1 = olhrr(ctxt, p->from.offset, p->from.reg, p->to.reg, p->scond);
-		o1 ^= (1<<5)|(1<<6);
-		break;
-
-	case 61:	/* movw/b/bu R,R<<[IR](R) -> str indexed */
-		if(p->to.reg == NREG)
-			ctxt->diag("MOV to shifter operand");
-		o1 = osrr(ctxt, p->from.reg, p->to.offset, p->to.reg, p->scond);
-		if(p->as == AMOVB || p->as == AMOVBS || p->as == AMOVBU)
-			o1 |= 1<<22;
-		break;
-
-	case 62:	/* case R -> movw	R<<2(PC),PC */
-		if(o->flag & LPCREL) {
-			o1 = oprrr(ctxt, AADD, p->scond) | immrot(1) | p->from.reg << 16 | REGTMP << 12;
-			o2 = olrr(ctxt, REGTMP, REGPC, REGTMP, p->scond);
-			o2 |= 2<<7;
-			o3 = oprrr(ctxt, AADD, p->scond) | REGTMP | REGPC << 16 | REGPC << 12;
-		} else {
-			o1 = olrr(ctxt, p->from.reg, REGPC, REGPC, p->scond);
-			o1 |= 2<<7;
-		}
-		break;
-
-	case 63:	/* bcase */
-		if(p->pcond != nil) {
-			rel = addrel(ctxt->cursym);
-			rel->off = ctxt->pc;
-			rel->siz = 4;
-			if(p->to.sym != nil && p->to.sym->type != 0) {
-				rel->sym = p->to.sym;
-				rel->add = p->to.offset;
-			} else {
-				rel->sym = ctxt->cursym;
-				rel->add = p->pcond->pc;
-			}
-			if(o->flag & LPCREL) {
-				rel->type = R_PCREL;
-				rel->add += ctxt->pc - p->pcrel->pc - 16 + rel->siz;
-			} else
-				rel->type = R_ADDR;
-			o1 = 0;
-		}
-		break;
-
-	/* reloc ops */
-	case 64:	/* mov/movb/movbu R,addr */
-		o1 = omvl(ctxt, p, &p->to, REGTMP);
-		if(!o1)
-			break;
-		o2 = osr(ctxt, p->as, p->from.reg, 0, REGTMP, p->scond);
-		if(o->flag & LPCREL) {
-			o3 = o2;
-			o2 = oprrr(ctxt, AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12;
-		}
-		break;
-
-	case 65:	/* mov/movbu addr,R */
-		o1 = omvl(ctxt, p, &p->from, REGTMP);
-		if(!o1)
-			break;
-		o2 = olr(ctxt, 0, REGTMP, p->to.reg, p->scond);
-		if(p->as == AMOVBU || p->as == AMOVBS || p->as == AMOVB)
-			o2 |= 1<<22;
-		if(o->flag & LPCREL) {
-			o3 = o2;
-			o2 = oprrr(ctxt, AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12;
-		}
-		break;
-
-	case 68:	/* floating point store -> ADDR */
-		o1 = omvl(ctxt, p, &p->to, REGTMP);
-		if(!o1)
-			break;
-		o2 = ofsr(ctxt, p->as, p->from.reg, 0, REGTMP, p->scond, p);
-		if(o->flag & LPCREL) {
-			o3 = o2;
-			o2 = oprrr(ctxt, AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12;
-		}
-		break;
-
-	case 69:	/* floating point load <- ADDR */
-		o1 = omvl(ctxt, p, &p->from, REGTMP);
-		if(!o1)
-			break;
-		o2 = ofsr(ctxt, p->as, p->to.reg, 0, REGTMP, p->scond, p) | (1<<20);
-		if(o->flag & LPCREL) {
-			o3 = o2;
-			o2 = oprrr(ctxt, AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12;
-		}
-		break;
-
-	/* ArmV4 ops: */
-	case 70:	/* movh/movhu R,O(R) -> strh */
-		aclass(ctxt, &p->to);
-		r = p->to.reg;
-		if(r == NREG)
-			r = o->param;
-		o1 = oshr(ctxt, p->from.reg, ctxt->instoffset, r, p->scond);
-		break;
-	case 71:	/* movb/movh/movhu O(R),R -> ldrsb/ldrsh/ldrh */
-		aclass(ctxt, &p->from);
-		r = p->from.reg;
-		if(r == NREG)
-			r = o->param;
-		o1 = olhr(ctxt, ctxt->instoffset, r, p->to.reg, p->scond);
-		if(p->as == AMOVB || p->as == AMOVBS)
-			o1 ^= (1<<5)|(1<<6);
-		else if(p->as == AMOVH || p->as == AMOVHS)
-			o1 ^= (1<<6);
-		break;
-	case 72:	/* movh/movhu R,L(R) -> strh */
-		o1 = omvl(ctxt, p, &p->to, REGTMP);
-		if(!o1)
-			break;
-		r = p->to.reg;
-		if(r == NREG)
-			r = o->param;
-		o2 = oshrr(ctxt, p->from.reg, REGTMP,r, p->scond);
-		break;
-	case 73:	/* movb/movh/movhu L(R),R -> ldrsb/ldrsh/ldrh */
-		o1 = omvl(ctxt, p, &p->from, REGTMP);
-		if(!o1)
-			break;
-		r = p->from.reg;
-		if(r == NREG)
-			r = o->param;
-		o2 = olhrr(ctxt, REGTMP, r, p->to.reg, p->scond);
-		if(p->as == AMOVB || p->as == AMOVBS)
-			o2 ^= (1<<5)|(1<<6);
-		else if(p->as == AMOVH || p->as == AMOVHS)
-			o2 ^= (1<<6);
-		break;
-	case 74:	/* bx $I */
-		ctxt->diag("ABX $I");
-		break;
-	case 75:	/* bx O(R) */
-		aclass(ctxt, &p->to);
-		if(ctxt->instoffset != 0)
-			ctxt->diag("non-zero offset in ABX");
-/*
-		o1 = 	oprrr(ctxt, AADD, p->scond) | immrot(0) | (REGPC<<16) | (REGLINK<<12);	// mov PC, LR
-		o2 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | p->to.reg;		// BX R
-*/
-		// p->to.reg may be REGLINK
-		o1 = oprrr(ctxt, AADD, p->scond);
-		o1 |= immrot(ctxt->instoffset);
-		o1 |= p->to.reg << 16;
-		o1 |= REGTMP << 12;
-		o2 = oprrr(ctxt, AADD, p->scond) | immrot(0) | (REGPC<<16) | (REGLINK<<12);	// mov PC, LR
-		o3 = ((p->scond&C_SCOND)<<28) | (0x12fff<<8) | (1<<4) | REGTMP;		// BX Rtmp
-		break;
-	case 76:	/* bx O(R) when returning from fn*/
-		ctxt->diag("ABXRET");
-		break;
-	case 77:	/* ldrex oreg,reg */
-		aclass(ctxt, &p->from);
-		if(ctxt->instoffset != 0)
-			ctxt->diag("offset must be zero in LDREX");
-		o1 = (0x19<<20) | (0xf9f);
-		o1 |= p->from.reg << 16;
-		o1 |= p->to.reg << 12;
-		o1 |= (p->scond & C_SCOND) << 28;
-		break;
-	case 78:	/* strex reg,oreg,reg */
-		aclass(ctxt, &p->from);
-		if(ctxt->instoffset != 0)
-			ctxt->diag("offset must be zero in STREX");
-		o1 = (0x18<<20) | (0xf90);
-		o1 |= p->from.reg << 16;
-		o1 |= p->reg << 0;
-		o1 |= p->to.reg << 12;
-		o1 |= (p->scond & C_SCOND) << 28;
-		break;
-	case 80:	/* fmov zfcon,freg */
-		if(p->as == AMOVD) {
-			o1 = 0xeeb00b00;	// VMOV imm 64
-			o2 = oprrr(ctxt, ASUBD, p->scond);
-		} else {
-			o1 = 0x0eb00a00;	// VMOV imm 32
-			o2 = oprrr(ctxt, ASUBF, p->scond);
-		}
-		v = 0x70;	// 1.0
-		r = p->to.reg;
-
-		// movf $1.0, r
-		o1 |= (p->scond & C_SCOND) << 28;
-		o1 |= r << 12;
-		o1 |= (v&0xf) << 0;
-		o1 |= (v&0xf0) << 12;
-
-		// subf r,r,r
-		o2 |= r | (r<<16) | (r<<12);
-		break;
-	case 81:	/* fmov sfcon,freg */
-		o1 = 0x0eb00a00;		// VMOV imm 32
-		if(p->as == AMOVD)
-			o1 = 0xeeb00b00;	// VMOV imm 64
-		o1 |= (p->scond & C_SCOND) << 28;
-		o1 |= p->to.reg << 12;
-		v = chipfloat5(ctxt, p->from.u.dval);
-		o1 |= (v&0xf) << 0;
-		o1 |= (v&0xf0) << 12;
-		break;
-	case 82:	/* fcmp freg,freg, */
-		o1 = oprrr(ctxt, p->as, p->scond);
-		o1 |= (p->reg<<12) | (p->from.reg<<0);
-		o2 = 0x0ef1fa10;	// VMRS R15
-		o2 |= (p->scond & C_SCOND) << 28;
-		break;
-	case 83:	/* fcmp freg,, */
-		o1 = oprrr(ctxt, p->as, p->scond);
-		o1 |= (p->from.reg<<12) | (1<<16);
-		o2 = 0x0ef1fa10;	// VMRS R15
-		o2 |= (p->scond & C_SCOND) << 28;
-		break;
-	case 84:	/* movfw freg,freg - truncate float-to-fix */
-		o1 = oprrr(ctxt, p->as, p->scond);
-		o1 |= (p->from.reg<<0);
-		o1 |= (p->to.reg<<12);
-		break;
-	case 85:	/* movwf freg,freg - fix-to-float */
-		o1 = oprrr(ctxt, p->as, p->scond);
-		o1 |= (p->from.reg<<0);
-		o1 |= (p->to.reg<<12);
-		break;
-	case 86:	/* movfw freg,reg - truncate float-to-fix */
-		// macro for movfw freg,FTMP; movw FTMP,reg
-		o1 = oprrr(ctxt, p->as, p->scond);
-		o1 |= (p->from.reg<<0);
-		o1 |= (FREGTMP<<12);
-		o2 = oprrr(ctxt, AMOVFW+AEND, p->scond);
-		o2 |= (FREGTMP<<16);
-		o2 |= (p->to.reg<<12);
-		break;
-	case 87:	/* movwf reg,freg - fix-to-float */
-		// macro for movw reg,FTMP; movwf FTMP,freg
-		o1 = oprrr(ctxt, AMOVWF+AEND, p->scond);
-		o1 |= (p->from.reg<<12);
-		o1 |= (FREGTMP<<16);
-		o2 = oprrr(ctxt, p->as, p->scond);
-		o2 |= (FREGTMP<<0);
-		o2 |= (p->to.reg<<12);
-		break;
-	case 88:	/* movw reg,freg  */
-		o1 = oprrr(ctxt, AMOVWF+AEND, p->scond);
-		o1 |= (p->from.reg<<12);
-		o1 |= (p->to.reg<<16);
-		break;
-	case 89:	/* movw freg,reg  */
-		o1 = oprrr(ctxt, AMOVFW+AEND, p->scond);
-		o1 |= (p->from.reg<<16);
-		o1 |= (p->to.reg<<12);
-		break;
-	case 90:	/* tst reg  */
-		o1 = oprrr(ctxt, ACMP+AEND, p->scond);
-		o1 |= p->from.reg<<16;
-		break;
-	case 91:	/* ldrexd oreg,reg */
-		aclass(ctxt, &p->from);
-		if(ctxt->instoffset != 0)
-			ctxt->diag("offset must be zero in LDREX");
-		o1 = (0x1b<<20) | (0xf9f);
-		o1 |= p->from.reg << 16;
-		o1 |= p->to.reg << 12;
-		o1 |= (p->scond & C_SCOND) << 28;
-		break;
-	case 92:	/* strexd reg,oreg,reg */
-		aclass(ctxt, &p->from);
-		if(ctxt->instoffset != 0)
-			ctxt->diag("offset must be zero in STREX");
-		o1 = (0x1a<<20) | (0xf90);
-		o1 |= p->from.reg << 16;
-		o1 |= p->reg << 0;
-		o1 |= p->to.reg << 12;
-		o1 |= (p->scond & C_SCOND) << 28;
-		break;
-	case 93:	/* movb/movh/movhu addr,R -> ldrsb/ldrsh/ldrh */
-		o1 = omvl(ctxt, p, &p->from, REGTMP);
-		if(!o1)
-			break;
-		o2 = olhr(ctxt, 0, REGTMP, p->to.reg, p->scond);
-		if(p->as == AMOVB || p->as == AMOVBS)
-			o2 ^= (1<<5)|(1<<6);
-		else if(p->as == AMOVH || p->as == AMOVHS)
-			o2 ^= (1<<6);
-		if(o->flag & LPCREL) {
-			o3 = o2;
-			o2 = oprrr(ctxt, AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12;
-		}
-		break;
-	case 94:	/* movh/movhu R,addr -> strh */
-		o1 = omvl(ctxt, p, &p->to, REGTMP);
-		if(!o1)
-			break;
-		o2 = oshr(ctxt, p->from.reg, 0, REGTMP, p->scond);
-		if(o->flag & LPCREL) {
-			o3 = o2;
-			o2 = oprrr(ctxt, AADD, p->scond) | REGTMP | REGPC << 16 | REGTMP << 12;
-		}
-		break;
-	case 95:	/* PLD off(reg) */
-		o1 = 0xf5d0f000;
-		o1 |= p->from.reg << 16;
-		if(p->from.offset < 0) {
-			o1 &= ~(1 << 23);
-			o1 |= (-p->from.offset) & 0xfff;
-		} else
-			o1 |= p->from.offset & 0xfff;
-		break;
-	case 96:	/* UNDEF */
-		// 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
-		// 0xf7fabcfd which is guaranteed to raise undefined instruction
-		// exception.
-		o1 = 0xf7fabcfd;
-		break;
-	case 97:	/* CLZ Rm, Rd */
- 		o1 = oprrr(ctxt, p->as, p->scond);
- 		o1 |= p->to.reg << 12;
- 		o1 |= p->from.reg;
-		break;
-	case 98:	/* MULW{T,B} Rs, Rm, Rd */
-		o1 = oprrr(ctxt, p->as, p->scond);
-		o1 |= p->to.reg << 16;
-		o1 |= p->from.reg << 8;
-		o1 |= p->reg;
-		break;
-	case 99:	/* MULAW{T,B} Rs, Rm, Rn, Rd */
-		o1 = oprrr(ctxt, p->as, p->scond);
-		o1 |= p->to.reg << 12;
-		o1 |= p->from.reg << 8;
-		o1 |= p->reg;
-		o1 |= p->to.offset << 16;
-		break;
-	case 100:
-		// DATABUNDLE: BKPT $0x5be0, signify the start of NaCl data bundle;
-		// DATABUNDLEEND: zero width alignment marker
-		if(p->as == ADATABUNDLE)
-			o1 = 0xe125be70;
-		break;
-	}
-	
-	out[0] = o1;
-	out[1] = o2;
-	out[2] = o3;
-	out[3] = o4;
-	out[4] = o5;
-	out[5] = o6;
-	return;
-}
-
-static int32
-mov(Link *ctxt, Prog *p)
-{
-	int32 o1;
-	int rt, r;
-
-	aclass(ctxt, &p->from);
-	o1 = oprrr(ctxt, p->as, p->scond);
-	o1 |= p->from.offset;
-	rt = p->to.reg;
-	r = p->reg;
-	if(p->to.type == D_NONE)
-		rt = 0;
-	if(p->as == AMOVW || p->as == AMVN)
-		r = 0;
-	else if(r == NREG)
-		r = rt;
-	o1 |= (r<<16) | (rt<<12);
-	return o1;
-}
-
-static int32
-oprrr(Link *ctxt, int a, int sc)
-{
-	int32 o;
-
-	o = (sc & C_SCOND) << 28;
-	if(sc & C_SBIT)
-		o |= 1 << 20;
-	if(sc & (C_PBIT|C_WBIT))
-		ctxt->diag(".nil/.W on dp instruction");
-	switch(a) {
-	case AMULU:
-	case AMUL:	return o | (0x0<<21) | (0x9<<4);
-	case AMULA:	return o | (0x1<<21) | (0x9<<4);
-	case AMULLU:	return o | (0x4<<21) | (0x9<<4);
-	case AMULL:	return o | (0x6<<21) | (0x9<<4);
-	case AMULALU:	return o | (0x5<<21) | (0x9<<4);
-	case AMULAL:	return o | (0x7<<21) | (0x9<<4);
-	case AAND:	return o | (0x0<<21);
-	case AEOR:	return o | (0x1<<21);
-	case ASUB:	return o | (0x2<<21);
-	case ARSB:	return o | (0x3<<21);
-	case AADD:	return o | (0x4<<21);
-	case AADC:	return o | (0x5<<21);
-	case ASBC:	return o | (0x6<<21);
-	case ARSC:	return o | (0x7<<21);
-	case ATST:	return o | (0x8<<21) | (1<<20);
-	case ATEQ:	return o | (0x9<<21) | (1<<20);
-	case ACMP:	return o | (0xa<<21) | (1<<20);
-	case ACMN:	return o | (0xb<<21) | (1<<20);
-	case AORR:	return o | (0xc<<21);
-	case AMOVB:
-	case AMOVH:
-	case AMOVW:	return o | (0xd<<21);
-	case ABIC:	return o | (0xe<<21);
-	case AMVN:	return o | (0xf<<21);
-	case ASLL:	return o | (0xd<<21) | (0<<5);
-	case ASRL:	return o | (0xd<<21) | (1<<5);
-	case ASRA:	return o | (0xd<<21) | (2<<5);
-	case ASWI:	return o | (0xf<<24);
-
-	case AADDD:	return o | (0xe<<24) | (0x3<<20) | (0xb<<8) | (0<<4);
-	case AADDF:	return o | (0xe<<24) | (0x3<<20) | (0xa<<8) | (0<<4);
-	case ASUBD:	return o | (0xe<<24) | (0x3<<20) | (0xb<<8) | (4<<4);
-	case ASUBF:	return o | (0xe<<24) | (0x3<<20) | (0xa<<8) | (4<<4);
-	case AMULD:	return o | (0xe<<24) | (0x2<<20) | (0xb<<8) | (0<<4);
-	case AMULF:	return o | (0xe<<24) | (0x2<<20) | (0xa<<8) | (0<<4);
-	case ADIVD:	return o | (0xe<<24) | (0x8<<20) | (0xb<<8) | (0<<4);
-	case ADIVF:	return o | (0xe<<24) | (0x8<<20) | (0xa<<8) | (0<<4);
-	case ASQRTD:	return o | (0xe<<24) | (0xb<<20) | (1<<16) | (0xb<<8) | (0xc<<4);
-	case ASQRTF:	return o | (0xe<<24) | (0xb<<20) | (1<<16) | (0xa<<8) | (0xc<<4);
-	case AABSD:	return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xb<<8) | (0xc<<4);
-	case AABSF:	return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xa<<8) | (0xc<<4);
-	case ACMPD:	return o | (0xe<<24) | (0xb<<20) | (4<<16) | (0xb<<8) | (0xc<<4);
-	case ACMPF:	return o | (0xe<<24) | (0xb<<20) | (4<<16) | (0xa<<8) | (0xc<<4);
-
-	case AMOVF:	return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xa<<8) | (4<<4);
-	case AMOVD:	return o | (0xe<<24) | (0xb<<20) | (0<<16) | (0xb<<8) | (4<<4);
-
-	case AMOVDF:	return o | (0xe<<24) | (0xb<<20) | (7<<16) | (0xa<<8) | (0xc<<4) |
-			(1<<8);	// dtof
-	case AMOVFD:	return o | (0xe<<24) | (0xb<<20) | (7<<16) | (0xa<<8) | (0xc<<4) |
-			(0<<8);	// dtof
-
-	case AMOVWF:
-			if((sc & C_UBIT) == 0)
-				o |= 1<<7;	/* signed */
-			return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) |
-				(0<<18) | (0<<8);	// toint, double
-	case AMOVWD:
-			if((sc & C_UBIT) == 0)
-				o |= 1<<7;	/* signed */
-			return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) |
-				(0<<18) | (1<<8);	// toint, double
-
-	case AMOVFW:
-			if((sc & C_UBIT) == 0)
-				o |= 1<<16;	/* signed */
-			return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) |
-				(1<<18) | (0<<8) | (1<<7);	// toint, double, trunc
-	case AMOVDW:
-			if((sc & C_UBIT) == 0)
-				o |= 1<<16;	/* signed */
-			return o | (0xe<<24) | (0xb<<20) | (8<<16) | (0xa<<8) | (4<<4) |
-				(1<<18) | (1<<8) | (1<<7);	// toint, double, trunc
-
-	case AMOVWF+AEND:	// copy WtoF
-		return o | (0xe<<24) | (0x0<<20) | (0xb<<8) | (1<<4);
-	case AMOVFW+AEND:	// copy FtoW
-		return o | (0xe<<24) | (0x1<<20) | (0xb<<8) | (1<<4);
-	case ACMP+AEND:	// cmp imm
-		return o | (0x3<<24) | (0x5<<20);
-
-	case ACLZ:
-		// CLZ doesn't support .nil
-		return (o & (0xf<<28)) | (0x16f<<16) | (0xf1<<4);
-
-	case AMULWT:
-		return (o & (0xf<<28)) | (0x12 << 20) | (0xe<<4);
-	case AMULWB:
-		return (o & (0xf<<28)) | (0x12 << 20) | (0xa<<4);
-	case AMULAWT:
-		return (o & (0xf<<28)) | (0x12 << 20) | (0xc<<4);
-	case AMULAWB:
-		return (o & (0xf<<28)) | (0x12 << 20) | (0x8<<4);
-
-	case ABL: // BLX REG
-		return (o & (0xf<<28)) | (0x12fff3 << 4);
-	}
-	ctxt->diag("bad rrr %d", a);
-	prasm(ctxt->curp);
-	return 0;
-}
-
-static int32
-opbra(Link *ctxt, int a, int sc)
-{
-
-	if(sc & (C_SBIT|C_PBIT|C_WBIT))
-		ctxt->diag(".nil/.nil/.W on bra instruction");
-	sc &= C_SCOND;
-	if(a == ABL || a == ADUFFZERO || a == ADUFFCOPY)
-		return (sc<<28)|(0x5<<25)|(0x1<<24);
-	if(sc != 0xe)
-		ctxt->diag(".COND on bcond instruction");
-	switch(a) {
-	case ABEQ:	return (0x0<<28)|(0x5<<25);
-	case ABNE:	return (0x1<<28)|(0x5<<25);
-	case ABCS:	return (0x2<<28)|(0x5<<25);
-	case ABHS:	return (0x2<<28)|(0x5<<25);
-	case ABCC:	return (0x3<<28)|(0x5<<25);
-	case ABLO:	return (0x3<<28)|(0x5<<25);
-	case ABMI:	return (0x4<<28)|(0x5<<25);
-	case ABPL:	return (0x5<<28)|(0x5<<25);
-	case ABVS:	return (0x6<<28)|(0x5<<25);
-	case ABVC:	return (0x7<<28)|(0x5<<25);
-	case ABHI:	return (0x8<<28)|(0x5<<25);
-	case ABLS:	return (0x9<<28)|(0x5<<25);
-	case ABGE:	return (0xa<<28)|(0x5<<25);
-	case ABLT:	return (0xb<<28)|(0x5<<25);
-	case ABGT:	return (0xc<<28)|(0x5<<25);
-	case ABLE:	return (0xd<<28)|(0x5<<25);
-	case AB:	return (0xe<<28)|(0x5<<25);
-	}
-	ctxt->diag("bad bra %A", a);
-	prasm(ctxt->curp);
-	return 0;
-}
-
-static int32
-olr(Link *ctxt, int32 v, int b, int r, int sc)
-{
-	int32 o;
-
-	if(sc & C_SBIT)
-		ctxt->diag(".nil on LDR/STR instruction");
-	o = (sc & C_SCOND) << 28;
-	if(!(sc & C_PBIT))
-		o |= 1 << 24;
-	if(!(sc & C_UBIT))
-		o |= 1 << 23;
-	if(sc & C_WBIT)
-		o |= 1 << 21;
-	o |= (1<<26) | (1<<20);
-	if(v < 0) {
-		if(sc & C_UBIT)
-			ctxt->diag(".U on neg offset");
-		v = -v;
-		o ^= 1 << 23;
-	}
-	if(v >= (1<<12) || v < 0)
-		ctxt->diag("literal span too large: %d (R%d)\n%P", v, b, ctxt->printp);
-	o |= v;
-	o |= b << 16;
-	o |= r << 12;
-	return o;
-}
-
-static int32
-olhr(Link *ctxt, int32 v, int b, int r, int sc)
-{
-	int32 o;
-
-	if(sc & C_SBIT)
-		ctxt->diag(".nil on LDRH/STRH instruction");
-	o = (sc & C_SCOND) << 28;
-	if(!(sc & C_PBIT))
-		o |= 1 << 24;
-	if(sc & C_WBIT)
-		o |= 1 << 21;
-	o |= (1<<23) | (1<<20)|(0xb<<4);
-	if(v < 0) {
-		v = -v;
-		o ^= 1 << 23;
-	}
-	if(v >= (1<<8) || v < 0)
-		ctxt->diag("literal span too large: %d (R%d)\n%P", v, b, ctxt->printp);
-	o |= (v&0xf)|((v>>4)<<8)|(1<<22);
-	o |= b << 16;
-	o |= r << 12;
-	return o;
-}
-
-static int32
-osr(Link *ctxt, int a, int r, int32 v, int b, int sc)
-{
-	int32 o;
-
-	o = olr(ctxt, v, b, r, sc) ^ (1<<20);
-	if(a != AMOVW)
-		o |= 1<<22;
-	return o;
-}
-
-static int32
-oshr(Link *ctxt, int r, int32 v, int b, int sc)
-{
-	int32 o;
-
-	o = olhr(ctxt, v, b, r, sc) ^ (1<<20);
-	return o;
-}
-
-
-static int32
-osrr(Link *ctxt, int r, int i, int b, int sc)
-{
-
-	return olr(ctxt, i, b, r, sc) ^ ((1<<25) | (1<<20));
-}
-
-static int32
-oshrr(Link *ctxt, int r, int i, int b, int sc)
-{
-	return olhr(ctxt, i, b, r, sc) ^ ((1<<22) | (1<<20));
-}
-
-static int32
-olrr(Link *ctxt, int i, int b, int r, int sc)
-{
-
-	return olr(ctxt, i, b, r, sc) ^ (1<<25);
-}
-
-static int32
-olhrr(Link *ctxt, int i, int b, int r, int sc)
-{
-	return olhr(ctxt, i, b, r, sc) ^ (1<<22);
-}
-
-static int32
-ofsr(Link *ctxt, int a, int r, int32 v, int b, int sc, Prog *p)
-{
-	int32 o;
-
-	if(sc & C_SBIT)
-		ctxt->diag(".nil on FLDR/FSTR instruction");
-	o = (sc & C_SCOND) << 28;
-	if(!(sc & C_PBIT))
-		o |= 1 << 24;
-	if(sc & C_WBIT)
-		o |= 1 << 21;
-	o |= (6<<25) | (1<<24) | (1<<23) | (10<<8);
-	if(v < 0) {
-		v = -v;
-		o ^= 1 << 23;
-	}
-	if(v & 3)
-		ctxt->diag("odd offset for floating point op: %d\n%P", v, p);
-	else
-	if(v >= (1<<10) || v < 0)
-		ctxt->diag("literal span too large: %d\n%P", v, p);
-	o |= (v>>2) & 0xFF;
-	o |= b << 16;
-	o |= r << 12;
-
-	switch(a) {
-	default:
-		ctxt->diag("bad fst %A", a);
-	case AMOVD:
-		o |= 1 << 8;
-	case AMOVF:
-		break;
-	}
-	return o;
-}
-
-static int32
-omvl(Link *ctxt, Prog *p, Addr *a, int dr)
-{
-	int32 v, o1;
-	if(!p->pcond) {
-		aclass(ctxt, a);
-		v = immrot(~ctxt->instoffset);
-		if(v == 0) {
-			ctxt->diag("missing literal");
-			prasm(p);
-			return 0;
-		}
-		o1 = oprrr(ctxt, AMVN, p->scond&C_SCOND);
-		o1 |= v;
-		o1 |= dr << 12;
-	} else {
-		v = p->pcond->pc - p->pc - 8;
-		o1 = olr(ctxt, v, REGPC, dr, p->scond&C_SCOND);
-	}
-	return o1;
-}
-
-int
-chipzero5(Link *ctxt, float64 e)
-{
-	// We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions.
-	if(ctxt->goarm < 7 || e != 0)
-		return -1;
-	return 0;
-}
-
-int
-chipfloat5(Link *ctxt, float64 e)
-{
-	int n;
-	ulong h1;
-	int32 l, h;
-	uint64 ei;
-
-	// We use GOARM=7 to gate the use of VFPv3 vmov (imm) instructions.
-	if(ctxt->goarm < 7)
-		goto no;
-
-	memmove(&ei, &e, 8);
-	l = (int32)ei;
-	h = (int32)(ei>>32);
-
-	if(l != 0 || (h&0xffff) != 0)
-		goto no;
-	h1 = h & 0x7fc00000;
-	if(h1 != 0x40000000 && h1 != 0x3fc00000)
-		goto no;
-	n = 0;
-
-	// sign bit (a)
-	if(h & 0x80000000)
-		n |= 1<<7;
-
-	// exp sign bit (b)
-	if(h1 == 0x3fc00000)
-		n |= 1<<6;
-
-	// rest of exp and mantissa (cd-efgh)
-	n |= (h >> 16) & 0x3f;
-
-//print("match %.8lux %.8lux %d\n", l, h, n);
-	return n;
-
-no:
-	return -1;
-}
diff --git a/src/liblink/asm6.c b/src/liblink/asm6.c
deleted file mode 100644
index 428eb94..0000000
--- a/src/liblink/asm6.c
+++ /dev/null
@@ -1,3611 +0,0 @@
-// Inferno utils/6l/span.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-// Instruction layout.
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <link.h>
-#include "../cmd/6l/6.out.h"
-#include "../runtime/stack.h"
-
-enum
-{
-	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
-};
-
-typedef	struct	Optab	Optab;
-typedef	struct	Movtab	Movtab;
-
-struct	Optab
-{
-	short	as;
-	uchar*	ytab;
-	uchar	prefix;
-	uchar	op[23];
-};
-struct	Movtab
-{
-	short	as;
-	uchar	ft;
-	uchar	tt;
-	uchar	code;
-	uchar	op[4];
-};
-
-enum
-{
-	Yxxx		= 0,
-	Ynone,
-	Yi0,
-	Yi1,
-	Yi8,
-	Ys32,
-	Yi32,
-	Yi64,
-	Yiauto,
-	Yal,
-	Ycl,
-	Yax,
-	Ycx,
-	Yrb,
-	Yrl,
-	Yrf,
-	Yf0,
-	Yrx,
-	Ymb,
-	Yml,
-	Ym,
-	Ybr,
-	Ycol,
-
-	Ycs,	Yss,	Yds,	Yes,	Yfs,	Ygs,
-	Ygdtr,	Yidtr,	Yldtr,	Ymsw,	Ytask,
-	Ycr0,	Ycr1,	Ycr2,	Ycr3,	Ycr4,	Ycr5,	Ycr6,	Ycr7,	Ycr8,
-	Ydr0,	Ydr1,	Ydr2,	Ydr3,	Ydr4,	Ydr5,	Ydr6,	Ydr7,
-	Ytr0,	Ytr1,	Ytr2,	Ytr3,	Ytr4,	Ytr5,	Ytr6,	Ytr7,	Yrl32,	Yrl64,
-	Ymr, Ymm,
-	Yxr, Yxm,
-	Ytls,
-	Ymax,
-
-	Zxxx		= 0,
-
-	Zlit,
-	Zlitm_r,
-	Z_rp,
-	Zbr,
-	Zcall,
-	Zcallindreg,
-	Zib_,
-	Zib_rp,
-	Zibo_m,
-	Zibo_m_xm,
-	Zil_,
-	Zil_rp,
-	Ziq_rp,
-	Zilo_m,
-	Ziqo_m,
-	Zjmp,
-	Zloop,
-	Zo_iw,
-	Zm_o,
-	Zm_r,
-	Zm2_r,
-	Zm_r_xm,
-	Zm_r_i_xm,
-	Zm_r_3d,
-	Zm_r_xm_nr,
-	Zr_m_xm_nr,
-	Zibm_r,	/* mmx1,mmx2/mem64,imm8 */
-	Zmb_r,
-	Zaut_r,
-	Zo_m,
-	Zo_m64,
-	Zpseudo,
-	Zr_m,
-	Zr_m_xm,
-	Zr_m_i_xm,
-	Zrp_,
-	Z_ib,
-	Z_il,
-	Zm_ibo,
-	Zm_ilo,
-	Zib_rr,
-	Zil_rr,
-	Zclr,
-	Zbyte,
-	Zmax,
-
-	Px		= 0,
-	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 */
-	Py		= 0x80,	/* defaults to 64-bit mode */
-
-	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 */
-};
-
-static uchar ycover[Ymax*Ymax];
-static	int	reg[D_NONE];
-static	int	regrex[D_NONE+1];
-static	void	asmins(Link *ctxt, Prog *p);
-
-static uchar	ynone[] =
-{
-	Ynone,	Ynone,	Zlit,	1,
-	0
-};
-static uchar	ytext[] =
-{
-	Ymb,	Yi64,	Zpseudo,1,
-	0
-};
-static uchar	ynop[] =
-{
-	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,
-	0
-};
-static uchar	yfuncdata[] =
-{
-	Yi32,	Ym,	Zpseudo,	0,
-	0
-};
-static uchar	ypcdata[] = 
-{
-	Yi32,	Yi32,	Zpseudo,	0,
-	0
-};
-static uchar	yxorb[] =
-{
-	Yi32,	Yal,	Zib_,	1,
-	Yi32,	Ymb,	Zibo_m,	2,
-	Yrb,	Ymb,	Zr_m,	1,
-	Ymb,	Yrb,	Zm_r,	1,
-	0
-};
-static uchar	yxorl[] =
-{
-	Yi8,	Yml,	Zibo_m,	2,
-	Yi32,	Yax,	Zil_,	1,
-	Yi32,	Yml,	Zilo_m,	2,
-	Yrl,	Yml,	Zr_m,	1,
-	Yml,	Yrl,	Zm_r,	1,
-	0
-};
-static uchar	yaddl[] =
-{
-	Yi8,	Yml,	Zibo_m,	2,
-	Yi32,	Yax,	Zil_,	1,
-	Yi32,	Yml,	Zilo_m,	2,
-	Yrl,	Yml,	Zr_m,	1,
-	Yml,	Yrl,	Zm_r,	1,
-	0
-};
-static uchar	yincb[] =
-{
-	Ynone,	Ymb,	Zo_m,	2,
-	0
-};
-static uchar	yincw[] =
-{
-	Ynone,	Yml,	Zo_m,	2,
-	0
-};
-static uchar	yincl[] =
-{
-	Ynone,	Yml,	Zo_m,	2,
-	0
-};
-static uchar	ycmpb[] =
-{
-	Yal,	Yi32,	Z_ib,	1,
-	Ymb,	Yi32,	Zm_ibo,	2,
-	Ymb,	Yrb,	Zm_r,	1,
-	Yrb,	Ymb,	Zr_m,	1,
-	0
-};
-static uchar	ycmpl[] =
-{
-	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,
-	0
-};
-static uchar	yshb[] =
-{
-	Yi1,	Ymb,	Zo_m,	2,
-	Yi32,	Ymb,	Zibo_m,	2,
-	Ycx,	Ymb,	Zo_m,	2,
-	0
-};
-static uchar	yshl[] =
-{
-	Yi1,	Yml,	Zo_m,	2,
-	Yi32,	Yml,	Zibo_m,	2,
-	Ycl,	Yml,	Zo_m,	2,
-	Ycx,	Yml,	Zo_m,	2,
-	0
-};
-static uchar	ytestb[] =
-{
-	Yi32,	Yal,	Zib_,	1,
-	Yi32,	Ymb,	Zibo_m,	2,
-	Yrb,	Ymb,	Zr_m,	1,
-	Ymb,	Yrb,	Zm_r,	1,
-	0
-};
-static uchar	ytestl[] =
-{
-	Yi32,	Yax,	Zil_,	1,
-	Yi32,	Yml,	Zilo_m,	2,
-	Yrl,	Yml,	Zr_m,	1,
-	Yml,	Yrl,	Zm_r,	1,
-	0
-};
-static uchar	ymovb[] =
-{
-	Yrb,	Ymb,	Zr_m,	1,
-	Ymb,	Yrb,	Zm_r,	1,
-	Yi32,	Yrb,	Zib_rp,	1,
-	Yi32,	Ymb,	Zibo_m,	2,
-	0
-};
-static uchar	ymbs[] =
-{
-	Ymb,	Ynone,	Zm_o,	2,
-	0
-};
-static uchar	ybtl[] =
-{
-	Yi8,	Yml,	Zibo_m,	2,
-	Yrl,	Yml,	Zr_m,	1,
-	0
-};
-static uchar	ymovw[] =
-{
-	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,
-	0
-};
-static uchar	ymovl[] =
-{
-	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,
-	0
-};
-static uchar	yret[] =
-{
-	Ynone,	Ynone,	Zo_iw,	1,
-	Yi32,	Ynone,	Zo_iw,	1,
-	0
-};
-static uchar	ymovq[] =
-{
-	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
-	0
-};
-static uchar	ym_rl[] =
-{
-	Ym,	Yrl,	Zm_r,	1,
-	0
-};
-static uchar	yrl_m[] =
-{
-	Yrl,	Ym,	Zr_m,	1,
-	0
-};
-static uchar	ymb_rl[] =
-{
-	Ymb,	Yrl,	Zmb_r,	1,
-	0
-};
-static uchar	yml_rl[] =
-{
-	Yml,	Yrl,	Zm_r,	1,
-	0
-};
-static uchar	yrl_ml[] =
-{
-	Yrl,	Yml,	Zr_m,	1,
-	0
-};
-static uchar	yml_mb[] =
-{
-	Yrb,	Ymb,	Zr_m,	1,
-	Ymb,	Yrb,	Zm_r,	1,
-	0
-};
-static uchar	yrb_mb[] =
-{
-	Yrb,	Ymb,	Zr_m,	1,
-	0
-};
-static uchar	yxchg[] =
-{
-	Yax,	Yrl,	Z_rp,	1,
-	Yrl,	Yax,	Zrp_,	1,
-	Yrl,	Yml,	Zr_m,	1,
-	Yml,	Yrl,	Zm_r,	1,
-	0
-};
-static uchar	ydivl[] =
-{
-	Yml,	Ynone,	Zm_o,	2,
-	0
-};
-static uchar	ydivb[] =
-{
-	Ymb,	Ynone,	Zm_o,	2,
-	0
-};
-static uchar	yimul[] =
-{
-	Yml,	Ynone,	Zm_o,	2,
-	Yi8,	Yrl,	Zib_rr,	1,
-	Yi32,	Yrl,	Zil_rr,	1,
-	Yml,	Yrl,	Zm_r,	2,
-	0
-};
-static uchar	yimul3[] =
-{
-	Yml,	Yrl,	Zibm_r,	2,
-	0
-};
-static uchar	ybyte[] =
-{
-	Yi64,	Ynone,	Zbyte,	1,
-	0
-};
-static uchar	yin[] =
-{
-	Yi32,	Ynone,	Zib_,	1,
-	Ynone,	Ynone,	Zlit,	1,
-	0
-};
-static uchar	yint[] =
-{
-	Yi32,	Ynone,	Zib_,	1,
-	0
-};
-static uchar	ypushl[] =
-{
-	Yrl,	Ynone,	Zrp_,	1,
-	Ym,	Ynone,	Zm_o,	2,
-	Yi8,	Ynone,	Zib_,	1,
-	Yi32,	Ynone,	Zil_,	1,
-	0
-};
-static uchar	ypopl[] =
-{
-	Ynone,	Yrl,	Z_rp,	1,
-	Ynone,	Ym,	Zo_m,	2,
-	0
-};
-static uchar	ybswap[] =
-{
-	Ynone,	Yrl,	Z_rp,	2,
-	0,
-};
-static uchar	yscond[] =
-{
-	Ynone,	Ymb,	Zo_m,	2,
-	0
-};
-static uchar	yjcond[] =
-{
-	Ynone,	Ybr,	Zbr,	0,
-	Yi0,	Ybr,	Zbr,	0,
-	Yi1,	Ybr,	Zbr,	1,
-	0
-};
-static uchar	yloop[] =
-{
-	Ynone,	Ybr,	Zloop,	1,
-	0
-};
-static uchar	ycall[] =
-{
-	Ynone,	Yml,	Zcallindreg,	0,
-	Yrx,	Yrx,	Zcallindreg,	2,
-	Ynone,	Ybr,	Zcall,	1,
-	0
-};
-static uchar	yduff[] =
-{
-	Ynone,	Yi32,	Zcall,	1,
-	0
-};
-static uchar	yjmp[] =
-{
-	Ynone,	Yml,	Zo_m64,	2,
-	Ynone,	Ybr,	Zjmp,	1,
-	0
-};
-
-static uchar	yfmvd[] =
-{
-	Ym,	Yf0,	Zm_o,	2,
-	Yf0,	Ym,	Zo_m,	2,
-	Yrf,	Yf0,	Zm_o,	2,
-	Yf0,	Yrf,	Zo_m,	2,
-	0
-};
-static uchar	yfmvdp[] =
-{
-	Yf0,	Ym,	Zo_m,	2,
-	Yf0,	Yrf,	Zo_m,	2,
-	0
-};
-static uchar	yfmvf[] =
-{
-	Ym,	Yf0,	Zm_o,	2,
-	Yf0,	Ym,	Zo_m,	2,
-	0
-};
-static uchar	yfmvx[] =
-{
-	Ym,	Yf0,	Zm_o,	2,
-	0
-};
-static uchar	yfmvp[] =
-{
-	Yf0,	Ym,	Zo_m,	2,
-	0
-};
-static uchar	yfadd[] =
-{
-	Ym,	Yf0,	Zm_o,	2,
-	Yrf,	Yf0,	Zm_o,	2,
-	Yf0,	Yrf,	Zo_m,	2,
-	0
-};
-static uchar	yfaddp[] =
-{
-	Yf0,	Yrf,	Zo_m,	2,
-	0
-};
-static uchar	yfxch[] =
-{
-	Yf0,	Yrf,	Zo_m,	2,
-	Yrf,	Yf0,	Zm_o,	2,
-	0
-};
-static uchar	ycompp[] =
-{
-	Yf0,	Yrf,	Zo_m,	2,	/* botch is really f0,f1 */
-	0
-};
-static uchar	ystsw[] =
-{
-	Ynone,	Ym,	Zo_m,	2,
-	Ynone,	Yax,	Zlit,	1,
-	0
-};
-static uchar	ystcw[] =
-{
-	Ynone,	Ym,	Zo_m,	2,
-	Ym,	Ynone,	Zm_o,	2,
-	0
-};
-static uchar	ysvrs[] =
-{
-	Ynone,	Ym,	Zo_m,	2,
-	Ym,	Ynone,	Zm_o,	2,
-	0
-};
-static uchar	ymm[] = 
-{
-	Ymm,	Ymr,	Zm_r_xm,	1,
-	Yxm,	Yxr,	Zm_r_xm,	2,
-	0
-};
-static uchar	yxm[] = 
-{
-	Yxm,	Yxr,	Zm_r_xm,	1,
-	0
-};
-static uchar	yxcvm1[] = 
-{
-	Yxm,	Yxr,	Zm_r_xm,	2,
-	Yxm,	Ymr,	Zm_r_xm,	2,
-	0
-};
-static uchar	yxcvm2[] =
-{
-	Yxm,	Yxr,	Zm_r_xm,	2,
-	Ymm,	Yxr,	Zm_r_xm,	2,
-	0
-};
-/*
-static uchar	yxmq[] = 
-{
-	Yxm,	Yxr,	Zm_r_xm,	2,
-	0
-};
-*/
-static uchar	yxr[] = 
-{
-	Yxr,	Yxr,	Zm_r_xm,	1,
-	0
-};
-static uchar	yxr_ml[] =
-{
-	Yxr,	Yml,	Zr_m_xm,	1,
-	0
-};
-static uchar	ymr[] =
-{
-	Ymr,	Ymr,	Zm_r,	1,
-	0
-};
-static uchar	ymr_ml[] =
-{
-	Ymr,	Yml,	Zr_m_xm,	1,
-	0
-};
-static uchar	yxcmp[] =
-{
-	Yxm,	Yxr, Zm_r_xm,	1,
-	0
-};
-static uchar	yxcmpi[] =
-{
-	Yxm,	Yxr, Zm_r_i_xm,	2,
-	0
-};
-static uchar	yxmov[] =
-{
-	Yxm,	Yxr,	Zm_r_xm,	1,
-	Yxr,	Yxm,	Zr_m_xm,	1,
-	0
-};
-static uchar	yxcvfl[] = 
-{
-	Yxm,	Yrl,	Zm_r_xm,	1,
-	0
-};
-static uchar	yxcvlf[] =
-{
-	Yml,	Yxr,	Zm_r_xm,	1,
-	0
-};
-static uchar	yxcvfq[] = 
-{
-	Yxm,	Yrl,	Zm_r_xm,	2,
-	0
-};
-static uchar	yxcvqf[] =
-{
-	Yml,	Yxr,	Zm_r_xm,	2,
-	0
-};
-static uchar	yps[] = 
-{
-	Ymm,	Ymr,	Zm_r_xm,	1,
-	Yi8,	Ymr,	Zibo_m_xm,	2,
-	Yxm,	Yxr,	Zm_r_xm,	2,
-	Yi8,	Yxr,	Zibo_m_xm,	3,
-	0
-};
-static uchar	yxrrl[] =
-{
-	Yxr,	Yrl,	Zm_r,	1,
-	0
-};
-static uchar	ymfp[] =
-{
-	Ymm,	Ymr,	Zm_r_3d,	1,
-	0,
-};
-static uchar	ymrxr[] =
-{
-	Ymr,	Yxr,	Zm_r,	1,
-	Yxm,	Yxr,	Zm_r_xm,	1,
-	0
-};
-static uchar	ymshuf[] =
-{
-	Ymm,	Ymr,	Zibm_r,	2,
-	0
-};
-static uchar	ymshufb[] =
-{
-	Yxm,	Yxr,	Zm2_r,	2,
-	0
-};
-static uchar	yxshuf[] =
-{
-	Yxm,	Yxr,	Zibm_r,	2,
-	0
-};
-static uchar	yextrw[] =
-{
-	Yxr,	Yrl,	Zibm_r,	2,
-	0
-};
-static uchar	yinsrw[] =
-{
-	Yml,	Yxr,	Zibm_r,	2,
-	0
-};
-static uchar	yinsr[] =
-{
-	Ymm,	Yxr,	Zibm_r,	3,
-	0
-};
-static uchar	ypsdq[] =
-{
-	Yi8,	Yxr,	Zibo_m,	2,
-	0
-};
-static uchar	ymskb[] =
-{
-	Yxr,	Yrl,	Zm_r_xm,	2,
-	Ymr,	Yrl,	Zm_r_xm,	1,
-	0
-};
-static uchar	ycrc32l[] =
-{
-	Yml,	Yrl,	Zlitm_r,	0,
-};
-static uchar	yprefetch[] =
-{
-	Ym,	Ynone,	Zm_o,	2,
-	0,
-};
-static uchar	yaes[] =
-{
-	Yxm,	Yxr,	Zlitm_r,	2,
-	0
-};
-static uchar	yaes2[] =
-{
-	Yxm,	Yxr,	Zibm_r,	2,
-	0
-};
-
-/*
- * You are doasm, holding in your hand a Prog* with p->as set to, say, ACRC32,
- * and p->from and p->to as operands (Addr*).  The linker scans optab to find
- * the entry with the given p->as and then looks through the ytable for that
- * instruction (the second field in the optab struct) for a line whose first
- * two values match the Ytypes of the p->from and p->to operands.  The function
- * oclass in span.c computes the specific Ytype of an operand and then the set
- * of more general Ytypes that it satisfies is implied by the ycover table, set
- * up in instinit.  For example, oclass distinguishes the constants 0 and 1
- * from the more general 8-bit constants, but instinit says
- *
- *        ycover[Yi0*Ymax + Ys32] = 1;
- *        ycover[Yi1*Ymax + Ys32] = 1;
- *        ycover[Yi8*Ymax + Ys32] = 1;
- *
- * which means that Yi0, Yi1, and Yi8 all count as Ys32 (signed 32)
- * if that's what an instruction can handle.
- *
- * In parallel with the scan through the ytable for the appropriate line, there
- * is a z pointer that starts out pointing at the strange magic byte list in
- * the Optab struct.  With each step past a non-matching ytable line, z
- * advances by the 4th entry in the line.  When a matching line is found, that
- * z pointer has the extra data to use in laying down the instruction bytes.
- * The actual bytes laid down are a function of the 3rd entry in the line (that
- * is, the Ztype) and the z bytes.
- *
- * For example, let's look at AADDL.  The optab line says:
- *        { AADDL,        yaddl,  Px, 0x83,(00),0x05,0x81,(00),0x01,0x03 },
- *
- * and yaddl says
- *        uchar   yaddl[] =
- *        {
- *                Yi8,    Yml,    Zibo_m, 2,
- *                Yi32,   Yax,    Zil_,   1,
- *                Yi32,   Yml,    Zilo_m, 2,
- *                Yrl,    Yml,    Zr_m,   1,
- *                Yml,    Yrl,    Zm_r,   1,
- *                0
- *        };
- *
- * so there are 5 possible types of ADDL instruction that can be laid down, and
- * possible states used to lay them down (Ztype and z pointer, assuming z
- * points at {0x83,(00),0x05,0x81,(00),0x01,0x03}) are:
- *
- *        Yi8, Yml -> Zibo_m, z (0x83, 00)
- *        Yi32, Yax -> Zil_, z+2 (0x05)
- *        Yi32, Yml -> Zilo_m, z+2+1 (0x81, 0x00)
- *        Yrl, Yml -> Zr_m, z+2+1+2 (0x01)
- *        Yml, Yrl -> Zm_r, z+2+1+2+1 (0x03)
- *
- * The Pconstant in the optab line controls the prefix bytes to emit.  That's
- * relatively straightforward as this program goes.
- *
- * The switch on t[2] in doasm implements the various Z cases.  Zibo_m, for
- * example, is an opcode byte (z[0]) then an asmando (which is some kind of
- * encoded addressing mode for the Yml arg), and then a single immediate byte.
- * Zilo_m is the same but a long (32-bit) immediate.
- */
-static Optab optab[] =
-/*	as, ytab, andproto, opcode */
-{
-	{ AXXX },
-	{ AAAA,		ynone,	P32, {0x37} },
-	{ AAAD,		ynone,	P32, {0xd5,0x0a} },
-	{ AAAM,		ynone,	P32, {0xd4,0x0a} },
-	{ AAAS,		ynone,	P32, {0x3f} },
-	{ AADCB,	yxorb,	Pb, {0x14,0x80,(02),0x10,0x10} },
-	{ AADCL,	yxorl,	Px, {0x83,(02),0x15,0x81,(02),0x11,0x13} },
-	{ AADCQ,	yxorl,	Pw, {0x83,(02),0x15,0x81,(02),0x11,0x13} },
-	{ AADCW,	yxorl,	Pe, {0x83,(02),0x15,0x81,(02),0x11,0x13} },
-	{ AADDB,	yxorb,	Pb, {0x04,0x80,(00),0x00,0x02} },
-	{ AADDL,	yaddl,	Px, {0x83,(00),0x05,0x81,(00),0x01,0x03} },
-	{ AADDPD,	yxm,	Pq, {0x58} },
-	{ AADDPS,	yxm,	Pm, {0x58} },
-	{ AADDQ,	yaddl,	Pw, {0x83,(00),0x05,0x81,(00),0x01,0x03} },
-	{ AADDSD,	yxm,	Pf2, {0x58} },
-	{ AADDSS,	yxm,	Pf3, {0x58} },
-	{ AADDW,	yaddl,	Pe, {0x83,(00),0x05,0x81,(00),0x01,0x03} },
-	{ AADJSP },
-	{ AANDB,	yxorb,	Pb, {0x24,0x80,(04),0x20,0x22} },
-	{ AANDL,	yxorl,	Px, {0x83,(04),0x25,0x81,(04),0x21,0x23} },
-	{ AANDNPD,	yxm,	Pq, {0x55} },
-	{ AANDNPS,	yxm,	Pm, {0x55} },
-	{ AANDPD,	yxm,	Pq, {0x54} },
-	{ AANDPS,	yxm,	Pq, {0x54} },
-	{ AANDQ,	yxorl,	Pw, {0x83,(04),0x25,0x81,(04),0x21,0x23} },
-	{ AANDW,	yxorl,	Pe, {0x83,(04),0x25,0x81,(04),0x21,0x23} },
-	{ AARPL,	yrl_ml,	P32, {0x63} },
-	{ ABOUNDL,	yrl_m,	P32, {0x62} },
-	{ ABOUNDW,	yrl_m,	Pe, {0x62} },
-	{ ABSFL,	yml_rl,	Pm, {0xbc} },
-	{ ABSFQ,	yml_rl,	Pw, {0x0f,0xbc} },
-	{ ABSFW,	yml_rl,	Pq, {0xbc} },
-	{ ABSRL,	yml_rl,	Pm, {0xbd} },
-	{ ABSRQ,	yml_rl,	Pw, {0x0f,0xbd} },
-	{ ABSRW,	yml_rl,	Pq, {0xbd} },
-	{ ABSWAPL,	ybswap,	Px, {0x0f,0xc8} },
-	{ ABSWAPQ,	ybswap,	Pw, {0x0f,0xc8} },
-	{ ABTCL,	ybtl,	Pm, {0xba,(07),0xbb} },
-	{ ABTCQ,	ybtl,	Pw, {0x0f,0xba,(07),0x0f,0xbb} },
-	{ ABTCW,	ybtl,	Pq, {0xba,(07),0xbb} },
-	{ ABTL,		ybtl,	Pm, {0xba,(04),0xa3} },
-	{ ABTQ,		ybtl,	Pw, {0x0f,0xba,(04),0x0f,0xa3}},
-	{ ABTRL,	ybtl,	Pm, {0xba,(06),0xb3} },
-	{ ABTRQ,	ybtl,	Pw, {0x0f,0xba,(06),0x0f,0xb3} },
-	{ ABTRW,	ybtl,	Pq, {0xba,(06),0xb3} },
-	{ ABTSL,	ybtl,	Pm, {0xba,(05),0xab } },
-	{ ABTSQ,	ybtl,	Pw, {0x0f,0xba,(05),0x0f,0xab} },
-	{ ABTSW,	ybtl,	Pq, {0xba,(05),0xab } },
-	{ ABTW,		ybtl,	Pq, {0xba,(04),0xa3} },
-	{ ABYTE,	ybyte,	Px, {1} },
-	{ ACALL,	ycall,	Px, {0xff,(02),0xe8} },
-	{ ACDQ,		ynone,	Px, {0x99} },
-	{ ACLC,		ynone,	Px, {0xf8} },
-	{ ACLD,		ynone,	Px, {0xfc} },
-	{ ACLI,		ynone,	Px, {0xfa} },
-	{ ACLTS,	ynone,	Pm, {0x06} },
-	{ ACMC,		ynone,	Px, {0xf5} },
-	{ ACMOVLCC,	yml_rl,	Pm, {0x43} },
-	{ ACMOVLCS,	yml_rl,	Pm, {0x42} },
-	{ ACMOVLEQ,	yml_rl,	Pm, {0x44} },
-	{ ACMOVLGE,	yml_rl,	Pm, {0x4d} },
-	{ ACMOVLGT,	yml_rl,	Pm, {0x4f} },
-	{ ACMOVLHI,	yml_rl,	Pm, {0x47} },
-	{ ACMOVLLE,	yml_rl,	Pm, {0x4e} },
-	{ ACMOVLLS,	yml_rl,	Pm, {0x46} },
-	{ ACMOVLLT,	yml_rl,	Pm, {0x4c} },
-	{ ACMOVLMI,	yml_rl,	Pm, {0x48} },
-	{ ACMOVLNE,	yml_rl,	Pm, {0x45} },
-	{ ACMOVLOC,	yml_rl,	Pm, {0x41} },
-	{ ACMOVLOS,	yml_rl,	Pm, {0x40} },
-	{ ACMOVLPC,	yml_rl,	Pm, {0x4b} },
-	{ ACMOVLPL,	yml_rl,	Pm, {0x49} },
-	{ ACMOVLPS,	yml_rl,	Pm, {0x4a} },
-	{ ACMOVQCC,	yml_rl,	Pw, {0x0f,0x43} },
-	{ ACMOVQCS,	yml_rl,	Pw, {0x0f,0x42} },
-	{ ACMOVQEQ,	yml_rl,	Pw, {0x0f,0x44} },
-	{ ACMOVQGE,	yml_rl,	Pw, {0x0f,0x4d} },
-	{ ACMOVQGT,	yml_rl,	Pw, {0x0f,0x4f} },
-	{ ACMOVQHI,	yml_rl,	Pw, {0x0f,0x47} },
-	{ ACMOVQLE,	yml_rl,	Pw, {0x0f,0x4e} },
-	{ ACMOVQLS,	yml_rl,	Pw, {0x0f,0x46} },
-	{ ACMOVQLT,	yml_rl,	Pw, {0x0f,0x4c} },
-	{ ACMOVQMI,	yml_rl,	Pw, {0x0f,0x48} },
-	{ ACMOVQNE,	yml_rl,	Pw, {0x0f,0x45} },
-	{ ACMOVQOC,	yml_rl,	Pw, {0x0f,0x41} },
-	{ ACMOVQOS,	yml_rl,	Pw, {0x0f,0x40} },
-	{ ACMOVQPC,	yml_rl,	Pw, {0x0f,0x4b} },
-	{ ACMOVQPL,	yml_rl,	Pw, {0x0f,0x49} },
-	{ ACMOVQPS,	yml_rl,	Pw, {0x0f,0x4a} },
-	{ ACMOVWCC,	yml_rl,	Pq, {0x43} },
-	{ ACMOVWCS,	yml_rl,	Pq, {0x42} },
-	{ ACMOVWEQ,	yml_rl,	Pq, {0x44} },
-	{ ACMOVWGE,	yml_rl,	Pq, {0x4d} },
-	{ ACMOVWGT,	yml_rl,	Pq, {0x4f} },
-	{ ACMOVWHI,	yml_rl,	Pq, {0x47} },
-	{ ACMOVWLE,	yml_rl,	Pq, {0x4e} },
-	{ ACMOVWLS,	yml_rl,	Pq, {0x46} },
-	{ ACMOVWLT,	yml_rl,	Pq, {0x4c} },
-	{ ACMOVWMI,	yml_rl,	Pq, {0x48} },
-	{ ACMOVWNE,	yml_rl,	Pq, {0x45} },
-	{ ACMOVWOC,	yml_rl,	Pq, {0x41} },
-	{ ACMOVWOS,	yml_rl,	Pq, {0x40} },
-	{ ACMOVWPC,	yml_rl,	Pq, {0x4b} },
-	{ ACMOVWPL,	yml_rl,	Pq, {0x49} },
-	{ ACMOVWPS,	yml_rl,	Pq, {0x4a} },
-	{ ACMPB,	ycmpb,	Pb, {0x3c,0x80,(07),0x38,0x3a} },
-	{ ACMPL,	ycmpl,	Px, {0x83,(07),0x3d,0x81,(07),0x39,0x3b} },
-	{ ACMPPD,	yxcmpi,	Px, {Pe,0xc2} },
-	{ ACMPPS,	yxcmpi,	Pm, {0xc2,0} },
-	{ ACMPQ,	ycmpl,	Pw, {0x83,(07),0x3d,0x81,(07),0x39,0x3b} },
-	{ ACMPSB,	ynone,	Pb, {0xa6} },
-	{ ACMPSD,	yxcmpi,	Px, {Pf2,0xc2} },
-	{ ACMPSL,	ynone,	Px, {0xa7} },
-	{ ACMPSQ,	ynone,	Pw, {0xa7} },
-	{ ACMPSS,	yxcmpi,	Px, {Pf3,0xc2} },
-	{ ACMPSW,	ynone,	Pe, {0xa7} },
-	{ ACMPW,	ycmpl,	Pe, {0x83,(07),0x3d,0x81,(07),0x39,0x3b} },
-	{ ACOMISD,	yxcmp,	Pe, {0x2f} },
-	{ ACOMISS,	yxcmp,	Pm, {0x2f} },
-	{ ACPUID,	ynone,	Pm, {0xa2} },
-	{ ACVTPL2PD,	yxcvm2,	Px, {Pf3,0xe6,Pe,0x2a} },
-	{ ACVTPL2PS,	yxcvm2,	Pm, {0x5b,0,0x2a,0,} },
-	{ ACVTPD2PL,	yxcvm1,	Px, {Pf2,0xe6,Pe,0x2d} },
-	{ ACVTPD2PS,	yxm,	Pe, {0x5a} },
-	{ ACVTPS2PL,	yxcvm1, Px, {Pe,0x5b,Pm,0x2d} },
-	{ ACVTPS2PD,	yxm,	Pm, {0x5a} },
-	{ API2FW,	ymfp,	Px, {0x0c} },
-	{ ACVTSD2SL,	yxcvfl, Pf2, {0x2d} },
-	{ ACVTSD2SQ,	yxcvfq, Pw, {Pf2,0x2d} },
-	{ ACVTSD2SS,	yxm,	Pf2, {0x5a} },
-	{ ACVTSL2SD,	yxcvlf, Pf2, {0x2a} },
-	{ ACVTSQ2SD,	yxcvqf, Pw, {Pf2,0x2a} },
-	{ ACVTSL2SS,	yxcvlf, Pf3, {0x2a} },
-	{ ACVTSQ2SS,	yxcvqf, Pw, {Pf3,0x2a} },
-	{ ACVTSS2SD,	yxm,	Pf3, {0x5a} },
-	{ ACVTSS2SL,	yxcvfl, Pf3, {0x2d} },
-	{ ACVTSS2SQ,	yxcvfq, Pw, {Pf3,0x2d} },
-	{ ACVTTPD2PL,	yxcvm1,	Px, {Pe,0xe6,Pe,0x2c} },
-	{ ACVTTPS2PL,	yxcvm1,	Px, {Pf3,0x5b,Pm,0x2c} },
-	{ ACVTTSD2SL,	yxcvfl, Pf2, {0x2c} },
-	{ ACVTTSD2SQ,	yxcvfq, Pw, {Pf2,0x2c} },
-	{ ACVTTSS2SL,	yxcvfl,	Pf3, {0x2c} },
-	{ ACVTTSS2SQ,	yxcvfq, Pw, {Pf3,0x2c} },
-	{ ACWD,		ynone,	Pe, {0x99} },
-	{ ACQO,		ynone,	Pw, {0x99} },
-	{ ADAA,		ynone,	P32, {0x27} },
-	{ ADAS,		ynone,	P32, {0x2f} },
-	{ ADATA },
-	{ ADECB,	yincb,	Pb, {0xfe,(01)} },
-	{ ADECL,	yincl,	Px, {0xff,(01)} },
-	{ ADECQ,	yincl,	Pw, {0xff,(01)} },
-	{ ADECW,	yincw,	Pe, {0xff,(01)} },
-	{ ADIVB,	ydivb,	Pb, {0xf6,(06)} },
-	{ ADIVL,	ydivl,	Px, {0xf7,(06)} },
-	{ ADIVPD,	yxm,	Pe, {0x5e} },
-	{ ADIVPS,	yxm,	Pm, {0x5e} },
-	{ ADIVQ,	ydivl,	Pw, {0xf7,(06)} },
-	{ ADIVSD,	yxm,	Pf2, {0x5e} },
-	{ ADIVSS,	yxm,	Pf3, {0x5e} },
-	{ ADIVW,	ydivl,	Pe, {0xf7,(06)} },
-	{ AEMMS,	ynone,	Pm, {0x77} },
-	{ AENTER },				/* botch */
-	{ AFXRSTOR,	ysvrs,	Pm, {0xae,(01),0xae,(01)} },
-	{ AFXSAVE,	ysvrs,	Pm, {0xae,(00),0xae,(00)} },
-	{ AFXRSTOR64,	ysvrs,	Pw, {0x0f,0xae,(01),0x0f,0xae,(01)} },
-	{ AFXSAVE64,	ysvrs,	Pw, {0x0f,0xae,(00),0x0f,0xae,(00)} },
-	{ AGLOBL },
-	{ AGOK },
-	{ AHISTORY },
-	{ AHLT,		ynone,	Px, {0xf4} },
-	{ AIDIVB,	ydivb,	Pb, {0xf6,(07)} },
-	{ AIDIVL,	ydivl,	Px, {0xf7,(07)} },
-	{ AIDIVQ,	ydivl,	Pw, {0xf7,(07)} },
-	{ AIDIVW,	ydivl,	Pe, {0xf7,(07)} },
-	{ AIMULB,	ydivb,	Pb, {0xf6,(05)} },
-	{ AIMULL,	yimul,	Px, {0xf7,(05),0x6b,0x69,Pm,0xaf} },
-	{ AIMULQ,	yimul,	Pw, {0xf7,(05),0x6b,0x69,Pm,0xaf} },
-	{ AIMULW,	yimul,	Pe, {0xf7,(05),0x6b,0x69,Pm,0xaf} },
-	{ AIMUL3Q,	yimul3,	Pw, {0x6b,(00)} },
-	{ AINB,		yin,	Pb, {0xe4,0xec} },
-	{ AINCB,	yincb,	Pb, {0xfe,(00)} },
-	{ AINCL,	yincl,	Px, {0xff,(00)} },
-	{ AINCQ,	yincl,	Pw, {0xff,(00)} },
-	{ AINCW,	yincw,	Pe, {0xff,(00)} },
-	{ AINL,		yin,	Px, {0xe5,0xed} },
-	{ AINSB,	ynone,	Pb, {0x6c} },
-	{ AINSL,	ynone,	Px, {0x6d} },
-	{ AINSW,	ynone,	Pe, {0x6d} },
-	{ AINT,		yint,	Px, {0xcd} },
-	{ AINTO,	ynone,	P32, {0xce} },
-	{ AINW,		yin,	Pe, {0xe5,0xed} },
-	{ AIRETL,	ynone,	Px, {0xcf} },
-	{ AIRETQ,	ynone,	Pw, {0xcf} },
-	{ AIRETW,	ynone,	Pe, {0xcf} },
-	{ AJCC,		yjcond,	Px, {0x73,0x83,(00)} },
-	{ AJCS,		yjcond,	Px, {0x72,0x82} },
-	{ AJCXZL,	yloop,	Px, {0xe3} },
-	{ AJCXZQ,	yloop,	Px, {0xe3} },
-	{ AJEQ,		yjcond,	Px, {0x74,0x84} },
-	{ AJGE,		yjcond,	Px, {0x7d,0x8d} },
-	{ AJGT,		yjcond,	Px, {0x7f,0x8f} },
-	{ AJHI,		yjcond,	Px, {0x77,0x87} },
-	{ AJLE,		yjcond,	Px, {0x7e,0x8e} },
-	{ AJLS,		yjcond,	Px, {0x76,0x86} },
-	{ AJLT,		yjcond,	Px, {0x7c,0x8c} },
-	{ AJMI,		yjcond,	Px, {0x78,0x88} },
-	{ AJMP,		yjmp,	Px, {0xff,(04),0xeb,0xe9} },
-	{ AJNE,		yjcond,	Px, {0x75,0x85} },
-	{ AJOC,		yjcond,	Px, {0x71,0x81,(00)} },
-	{ AJOS,		yjcond,	Px, {0x70,0x80,(00)} },
-	{ AJPC,		yjcond,	Px, {0x7b,0x8b} },
-	{ AJPL,		yjcond,	Px, {0x79,0x89} },
-	{ AJPS,		yjcond,	Px, {0x7a,0x8a} },
-	{ ALAHF,	ynone,	Px, {0x9f} },
-	{ ALARL,	yml_rl,	Pm, {0x02} },
-	{ ALARW,	yml_rl,	Pq, {0x02} },
-	{ ALDMXCSR,	ysvrs,	Pm, {0xae,(02),0xae,(02)} },
-	{ ALEAL,	ym_rl,	Px, {0x8d} },
-	{ ALEAQ,	ym_rl,	Pw, {0x8d} },
-	{ ALEAVEL,	ynone,	P32, {0xc9} },
-	{ ALEAVEQ,	ynone,	Py, {0xc9} },
-	{ ALEAVEW,	ynone,	Pe, {0xc9} },
-	{ ALEAW,	ym_rl,	Pe, {0x8d} },
-	{ ALOCK,	ynone,	Px, {0xf0} },
-	{ ALODSB,	ynone,	Pb, {0xac} },
-	{ ALODSL,	ynone,	Px, {0xad} },
-	{ ALODSQ,	ynone,	Pw, {0xad} },
-	{ ALODSW,	ynone,	Pe, {0xad} },
-	{ ALONG,	ybyte,	Px, {4} },
-	{ ALOOP,	yloop,	Px, {0xe2} },
-	{ ALOOPEQ,	yloop,	Px, {0xe1} },
-	{ ALOOPNE,	yloop,	Px, {0xe0} },
-	{ ALSLL,	yml_rl,	Pm, {0x03 } },
-	{ ALSLW,	yml_rl,	Pq, {0x03 } },
-	{ AMASKMOVOU,	yxr,	Pe, {0xf7} },
-	{ AMASKMOVQ,	ymr,	Pm, {0xf7} },
-	{ AMAXPD,	yxm,	Pe, {0x5f} },
-	{ AMAXPS,	yxm,	Pm, {0x5f} },
-	{ AMAXSD,	yxm,	Pf2, {0x5f} },
-	{ AMAXSS,	yxm,	Pf3, {0x5f} },
-	{ AMINPD,	yxm,	Pe, {0x5d} },
-	{ AMINPS,	yxm,	Pm, {0x5d} },
-	{ AMINSD,	yxm,	Pf2, {0x5d} },
-	{ AMINSS,	yxm,	Pf3, {0x5d} },
-	{ AMOVAPD,	yxmov,	Pe, {0x28,0x29} },
-	{ AMOVAPS,	yxmov,	Pm, {0x28,0x29} },
-	{ AMOVB,	ymovb,	Pb, {0x88,0x8a,0xb0,0xc6,(00)} },
-	{ AMOVBLSX,	ymb_rl,	Pm, {0xbe} },
-	{ AMOVBLZX,	ymb_rl,	Pm, {0xb6} },
-	{ AMOVBQSX,	ymb_rl,	Pw, {0x0f,0xbe} },
-	{ AMOVBQZX,	ymb_rl,	Pm, {0xb6} },
-	{ AMOVBWSX,	ymb_rl,	Pq, {0xbe} },
-	{ AMOVBWZX,	ymb_rl,	Pq, {0xb6} },
-	{ AMOVO,	yxmov,	Pe, {0x6f,0x7f} },
-	{ AMOVOU,	yxmov,	Pf3, {0x6f,0x7f} },
-	{ AMOVHLPS,	yxr,	Pm, {0x12} },
-	{ AMOVHPD,	yxmov,	Pe, {0x16,0x17} },
-	{ AMOVHPS,	yxmov,	Pm, {0x16,0x17} },
-	{ AMOVL,	ymovl,	Px, {0x89,0x8b,0x31,0xb8,0xc7,(00),0x6e,0x7e,Pe,0x6e,Pe,0x7e,0} },
-	{ AMOVLHPS,	yxr,	Pm, {0x16} },
-	{ AMOVLPD,	yxmov,	Pe, {0x12,0x13} },
-	{ AMOVLPS,	yxmov,	Pm, {0x12,0x13} },
-	{ AMOVLQSX,	yml_rl,	Pw, {0x63} },
-	{ AMOVLQZX,	yml_rl,	Px, {0x8b} },
-	{ AMOVMSKPD,	yxrrl,	Pq, {0x50} },
-	{ AMOVMSKPS,	yxrrl,	Pm, {0x50} },
-	{ AMOVNTO,	yxr_ml,	Pe, {0xe7} },
-	{ AMOVNTPD,	yxr_ml,	Pe, {0x2b} },
-	{ AMOVNTPS,	yxr_ml,	Pm, {0x2b} },
-	{ AMOVNTQ,	ymr_ml,	Pm, {0xe7} },
-	{ AMOVQ,	ymovq,	Pw, {0x89, 0x8b, 0x31, 0xc7,(00), 0xb8, 0xc7,(00), 0x6f, 0x7f, 0x6e, 0x7e, Pf2,0xd6, Pf3,0x7e, Pe,0xd6, Pe,0x6e, Pe,0x7e,0} },
-	{ AMOVQOZX,	ymrxr,	Pf3, {0xd6,0x7e} },
-	{ AMOVSB,	ynone,	Pb, {0xa4} },
-	{ AMOVSD,	yxmov,	Pf2, {0x10,0x11} },
-	{ AMOVSL,	ynone,	Px, {0xa5} },
-	{ AMOVSQ,	ynone,	Pw, {0xa5} },
-	{ AMOVSS,	yxmov,	Pf3, {0x10,0x11} },
-	{ AMOVSW,	ynone,	Pe, {0xa5} },
-	{ AMOVUPD,	yxmov,	Pe, {0x10,0x11} },
-	{ AMOVUPS,	yxmov,	Pm, {0x10,0x11} },
-	{ AMOVW,	ymovw,	Pe, {0x89,0x8b,0x31,0xb8,0xc7,(00),0} },
-	{ AMOVWLSX,	yml_rl,	Pm, {0xbf} },
-	{ AMOVWLZX,	yml_rl,	Pm, {0xb7} },
-	{ AMOVWQSX,	yml_rl,	Pw, {0x0f,0xbf} },
-	{ AMOVWQZX,	yml_rl,	Pw, {0x0f,0xb7} },
-	{ AMULB,	ydivb,	Pb, {0xf6,(04)} },
-	{ AMULL,	ydivl,	Px, {0xf7,(04)} },
-	{ AMULPD,	yxm,	Pe, {0x59} },
-	{ AMULPS,	yxm,	Ym, {0x59} },
-	{ AMULQ,	ydivl,	Pw, {0xf7,(04)} },
-	{ AMULSD,	yxm,	Pf2, {0x59} },
-	{ AMULSS,	yxm,	Pf3, {0x59} },
-	{ AMULW,	ydivl,	Pe, {0xf7,(04)} },
-	{ ANAME },
-	{ ANEGB,	yscond,	Pb, {0xf6,(03)} },
-	{ ANEGL,	yscond,	Px, {0xf7,(03)} },
-	{ ANEGQ,	yscond,	Pw, {0xf7,(03)} },
-	{ ANEGW,	yscond,	Pe, {0xf7,(03)} },
-	{ ANOP,		ynop,	Px, {0,0} },
-	{ ANOTB,	yscond,	Pb, {0xf6,(02)} },
-	{ ANOTL,	yscond,	Px, {0xf7,(02)} },
-	{ ANOTQ,	yscond,	Pw, {0xf7,(02)} },
-	{ ANOTW,	yscond,	Pe, {0xf7,(02)} },
-	{ AORB,		yxorb,	Pb, {0x0c,0x80,(01),0x08,0x0a} },
-	{ AORL,		yxorl,	Px, {0x83,(01),0x0d,0x81,(01),0x09,0x0b} },
-	{ AORPD,	yxm,	Pq, {0x56} },
-	{ AORPS,	yxm,	Pm, {0x56} },
-	{ AORQ,		yxorl,	Pw, {0x83,(01),0x0d,0x81,(01),0x09,0x0b} },
-	{ AORW,		yxorl,	Pe, {0x83,(01),0x0d,0x81,(01),0x09,0x0b} },
-	{ AOUTB,	yin,	Pb, {0xe6,0xee} },
-	{ AOUTL,	yin,	Px, {0xe7,0xef} },
-	{ AOUTSB,	ynone,	Pb, {0x6e} },
-	{ AOUTSL,	ynone,	Px, {0x6f} },
-	{ AOUTSW,	ynone,	Pe, {0x6f} },
-	{ AOUTW,	yin,	Pe, {0xe7,0xef} },
-	{ APACKSSLW,	ymm,	Py, {0x6b,Pe,0x6b} },
-	{ APACKSSWB,	ymm,	Py, {0x63,Pe,0x63} },
-	{ APACKUSWB,	ymm,	Py, {0x67,Pe,0x67} },
-	{ APADDB,	ymm,	Py, {0xfc,Pe,0xfc} },
-	{ APADDL,	ymm,	Py, {0xfe,Pe,0xfe} },
-	{ APADDQ,	yxm,	Pe, {0xd4} },
-	{ APADDSB,	ymm,	Py, {0xec,Pe,0xec} },
-	{ APADDSW,	ymm,	Py, {0xed,Pe,0xed} },
-	{ APADDUSB,	ymm,	Py, {0xdc,Pe,0xdc} },
-	{ APADDUSW,	ymm,	Py, {0xdd,Pe,0xdd} },
-	{ APADDW,	ymm,	Py, {0xfd,Pe,0xfd} },
-	{ APAND,	ymm,	Py, {0xdb,Pe,0xdb} },
-	{ APANDN,	ymm,	Py, {0xdf,Pe,0xdf} },
-	{ APAUSE,	ynone,	Px, {0xf3,0x90} },
-	{ APAVGB,	ymm,	Py, {0xe0,Pe,0xe0} },
-	{ APAVGW,	ymm,	Py, {0xe3,Pe,0xe3} },
-	{ APCMPEQB,	ymm,	Py, {0x74,Pe,0x74} },
-	{ APCMPEQL,	ymm,	Py, {0x76,Pe,0x76} },
-	{ APCMPEQW,	ymm,	Py, {0x75,Pe,0x75} },
-	{ APCMPGTB,	ymm,	Py, {0x64,Pe,0x64} },
-	{ APCMPGTL,	ymm,	Py, {0x66,Pe,0x66} },
-	{ APCMPGTW,	ymm,	Py, {0x65,Pe,0x65} },
-	{ APEXTRW,	yextrw,	Pq, {0xc5,(00)} },
-	{ APF2IL,	ymfp,	Px, {0x1d} },
-	{ APF2IW,	ymfp,	Px, {0x1c} },
-	{ API2FL,	ymfp,	Px, {0x0d} },
-	{ APFACC,	ymfp,	Px, {0xae} },
-	{ APFADD,	ymfp,	Px, {0x9e} },
-	{ APFCMPEQ,	ymfp,	Px, {0xb0} },
-	{ APFCMPGE,	ymfp,	Px, {0x90} },
-	{ APFCMPGT,	ymfp,	Px, {0xa0} },
-	{ APFMAX,	ymfp,	Px, {0xa4} },
-	{ APFMIN,	ymfp,	Px, {0x94} },
-	{ APFMUL,	ymfp,	Px, {0xb4} },
-	{ APFNACC,	ymfp,	Px, {0x8a} },
-	{ APFPNACC,	ymfp,	Px, {0x8e} },
-	{ APFRCP,	ymfp,	Px, {0x96} },
-	{ APFRCPIT1,	ymfp,	Px, {0xa6} },
-	{ APFRCPI2T,	ymfp,	Px, {0xb6} },
-	{ APFRSQIT1,	ymfp,	Px, {0xa7} },
-	{ APFRSQRT,	ymfp,	Px, {0x97} },
-	{ APFSUB,	ymfp,	Px, {0x9a} },
-	{ APFSUBR,	ymfp,	Px, {0xaa} },
-	{ APINSRW,	yinsrw,	Pq, {0xc4,(00)} },
-	{ APINSRD,	yinsr,	Pq, {0x3a, 0x22, (00)} },
-	{ APINSRQ,	yinsr,	Pq3, {0x3a, 0x22, (00)} },
-	{ APMADDWL,	ymm,	Py, {0xf5,Pe,0xf5} },
-	{ APMAXSW,	yxm,	Pe, {0xee} },
-	{ APMAXUB,	yxm,	Pe, {0xde} },
-	{ APMINSW,	yxm,	Pe, {0xea} },
-	{ APMINUB,	yxm,	Pe, {0xda} },
-	{ APMOVMSKB,	ymskb,	Px, {Pe,0xd7,0xd7} },
-	{ APMULHRW,	ymfp,	Px, {0xb7} },
-	{ APMULHUW,	ymm,	Py, {0xe4,Pe,0xe4} },
-	{ APMULHW,	ymm,	Py, {0xe5,Pe,0xe5} },
-	{ APMULLW,	ymm,	Py, {0xd5,Pe,0xd5} },
-	{ APMULULQ,	ymm,	Py, {0xf4,Pe,0xf4} },
-	{ APOPAL,	ynone,	P32, {0x61} },
-	{ APOPAW,	ynone,	Pe, {0x61} },
-	{ APOPFL,	ynone,	P32, {0x9d} },
-	{ APOPFQ,	ynone,	Py, {0x9d} },
-	{ APOPFW,	ynone,	Pe, {0x9d} },
-	{ APOPL,	ypopl,	P32, {0x58,0x8f,(00)} },
-	{ APOPQ,	ypopl,	Py, {0x58,0x8f,(00)} },
-	{ APOPW,	ypopl,	Pe, {0x58,0x8f,(00)} },
-	{ APOR,		ymm,	Py, {0xeb,Pe,0xeb} },
-	{ APSADBW,	yxm,	Pq, {0xf6} },
-	{ APSHUFHW,	yxshuf,	Pf3, {0x70,(00)} },
-	{ APSHUFL,	yxshuf,	Pq, {0x70,(00)} },
-	{ APSHUFLW,	yxshuf,	Pf2, {0x70,(00)} },
-	{ APSHUFW,	ymshuf,	Pm, {0x70,(00)} },
-	{ APSHUFB,	ymshufb,Pq, {0x38, 0x00} },
-	{ APSLLO,	ypsdq,	Pq, {0x73,(07)} },
-	{ APSLLL,	yps,	Py, {0xf2, 0x72,(06), Pe,0xf2, Pe,0x72,(06)} },
-	{ APSLLQ,	yps,	Py, {0xf3, 0x73,(06), Pe,0xf3, Pe,0x73,(06)} },
-	{ APSLLW,	yps,	Py, {0xf1, 0x71,(06), Pe,0xf1, Pe,0x71,(06)} },
-	{ APSRAL,	yps,	Py, {0xe2, 0x72,(04), Pe,0xe2, Pe,0x72,(04)} },
-	{ APSRAW,	yps,	Py, {0xe1, 0x71,(04), Pe,0xe1, Pe,0x71,(04)} },
-	{ APSRLO,	ypsdq,	Pq, {0x73,(03)} },
-	{ APSRLL,	yps,	Py, {0xd2, 0x72,(02), Pe,0xd2, Pe,0x72,(02)} },
-	{ APSRLQ,	yps,	Py, {0xd3, 0x73,(02), Pe,0xd3, Pe,0x73,(02)} },
-	{ APSRLW,	yps,	Py, {0xd1, 0x71,(02), Pe,0xe1, Pe,0x71,(02)} },
-	{ APSUBB,	yxm,	Pe, {0xf8} },
-	{ APSUBL,	yxm,	Pe, {0xfa} },
-	{ APSUBQ,	yxm,	Pe, {0xfb} },
-	{ APSUBSB,	yxm,	Pe, {0xe8} },
-	{ APSUBSW,	yxm,	Pe, {0xe9} },
-	{ APSUBUSB,	yxm,	Pe, {0xd8} },
-	{ APSUBUSW,	yxm,	Pe, {0xd9} },
-	{ APSUBW,	yxm,	Pe, {0xf9} },
-	{ APSWAPL,	ymfp,	Px, {0xbb} },
-	{ APUNPCKHBW,	ymm,	Py, {0x68,Pe,0x68} },
-	{ APUNPCKHLQ,	ymm,	Py, {0x6a,Pe,0x6a} },
-	{ APUNPCKHQDQ,	yxm,	Pe, {0x6d} },
-	{ APUNPCKHWL,	ymm,	Py, {0x69,Pe,0x69} },
-	{ APUNPCKLBW,	ymm,	Py, {0x60,Pe,0x60} },
-	{ APUNPCKLLQ,	ymm,	Py, {0x62,Pe,0x62} },
-	{ APUNPCKLQDQ,	yxm,	Pe, {0x6c} },
-	{ APUNPCKLWL,	ymm,	Py, {0x61,Pe,0x61} },
-	{ APUSHAL,	ynone,	P32, {0x60} },
-	{ APUSHAW,	ynone,	Pe, {0x60} },
-	{ APUSHFL,	ynone,	P32, {0x9c} },
-	{ APUSHFQ,	ynone,	Py, {0x9c} },
-	{ APUSHFW,	ynone,	Pe, {0x9c} },
-	{ APUSHL,	ypushl,	P32, {0x50,0xff,(06),0x6a,0x68} },
-	{ APUSHQ,	ypushl,	Py, {0x50,0xff,(06),0x6a,0x68} },
-	{ APUSHW,	ypushl,	Pe, {0x50,0xff,(06),0x6a,0x68} },
-	{ APXOR,	ymm,	Py, {0xef,Pe,0xef} },
-	{ AQUAD,	ybyte,	Px, {8} },
-	{ ARCLB,	yshb,	Pb, {0xd0,(02),0xc0,(02),0xd2,(02)} },
-	{ ARCLL,	yshl,	Px, {0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02)} },
-	{ ARCLQ,	yshl,	Pw, {0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02)} },
-	{ ARCLW,	yshl,	Pe, {0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02)} },
-	{ ARCPPS,	yxm,	Pm, {0x53} },
-	{ ARCPSS,	yxm,	Pf3, {0x53} },
-	{ ARCRB,	yshb,	Pb, {0xd0,(03),0xc0,(03),0xd2,(03)} },
-	{ ARCRL,	yshl,	Px, {0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03)} },
-	{ ARCRQ,	yshl,	Pw, {0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03)} },
-	{ ARCRW,	yshl,	Pe, {0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03)} },
-	{ AREP,		ynone,	Px, {0xf3} },
-	{ AREPN,	ynone,	Px, {0xf2} },
-	{ ARET,		ynone,	Px, {0xc3} },
-	{ ARETFW,	yret,	Pe, {0xcb,0xca} },
-	{ ARETFL,	yret,	Px, {0xcb,0xca} },
-	{ ARETFQ,	yret,	Pw, {0xcb,0xca} },
-	{ AROLB,	yshb,	Pb, {0xd0,(00),0xc0,(00),0xd2,(00)} },
-	{ AROLL,	yshl,	Px, {0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00)} },
-	{ AROLQ,	yshl,	Pw, {0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00)} },
-	{ AROLW,	yshl,	Pe, {0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00)} },
-	{ ARORB,	yshb,	Pb, {0xd0,(01),0xc0,(01),0xd2,(01)} },
-	{ ARORL,	yshl,	Px, {0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01)} },
-	{ ARORQ,	yshl,	Pw, {0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01)} },
-	{ ARORW,	yshl,	Pe, {0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01)} },
-	{ ARSQRTPS,	yxm,	Pm, {0x52} },
-	{ ARSQRTSS,	yxm,	Pf3, {0x52} },
-	{ ASAHF,	ynone,	Px, {0x86,0xe0,0x50,0x9d} },	/* XCHGB AH,AL; PUSH AX; POPFL */
-	{ ASALB,	yshb,	Pb, {0xd0,(04),0xc0,(04),0xd2,(04)} },
-	{ ASALL,	yshl,	Px, {0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04)} },
-	{ ASALQ,	yshl,	Pw, {0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04)} },
-	{ ASALW,	yshl,	Pe, {0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04)} },
-	{ ASARB,	yshb,	Pb, {0xd0,(07),0xc0,(07),0xd2,(07)} },
-	{ ASARL,	yshl,	Px, {0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07)} },
-	{ ASARQ,	yshl,	Pw, {0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07)} },
-	{ ASARW,	yshl,	Pe, {0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07)} },
-	{ ASBBB,	yxorb,	Pb, {0x1c,0x80,(03),0x18,0x1a} },
-	{ ASBBL,	yxorl,	Px, {0x83,(03),0x1d,0x81,(03),0x19,0x1b} },
-	{ ASBBQ,	yxorl,	Pw, {0x83,(03),0x1d,0x81,(03),0x19,0x1b} },
-	{ ASBBW,	yxorl,	Pe, {0x83,(03),0x1d,0x81,(03),0x19,0x1b} },
-	{ ASCASB,	ynone,	Pb, {0xae} },
-	{ ASCASL,	ynone,	Px, {0xaf} },
-	{ ASCASQ,	ynone,	Pw, {0xaf} },
-	{ ASCASW,	ynone,	Pe, {0xaf} },
-	{ ASETCC,	yscond,	Pm, {0x93,(00)} },
-	{ ASETCS,	yscond,	Pm, {0x92,(00)} },
-	{ ASETEQ,	yscond,	Pm, {0x94,(00)} },
-	{ ASETGE,	yscond,	Pm, {0x9d,(00)} },
-	{ ASETGT,	yscond,	Pm, {0x9f,(00)} },
-	{ ASETHI,	yscond,	Pm, {0x97,(00)} },
-	{ ASETLE,	yscond,	Pm, {0x9e,(00)} },
-	{ ASETLS,	yscond,	Pm, {0x96,(00)} },
-	{ ASETLT,	yscond,	Pm, {0x9c,(00)} },
-	{ ASETMI,	yscond,	Pm, {0x98,(00)} },
-	{ ASETNE,	yscond,	Pm, {0x95,(00)} },
-	{ ASETOC,	yscond,	Pm, {0x91,(00)} },
-	{ ASETOS,	yscond,	Pm, {0x90,(00)} },
-	{ ASETPC,	yscond,	Pm, {0x9b,(00)} },
-	{ ASETPL,	yscond,	Pm, {0x99,(00)} },
-	{ ASETPS,	yscond,	Pm, {0x9a,(00)} },
-	{ ASHLB,	yshb,	Pb, {0xd0,(04),0xc0,(04),0xd2,(04)} },
-	{ ASHLL,	yshl,	Px, {0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04)} },
-	{ ASHLQ,	yshl,	Pw, {0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04)} },
-	{ ASHLW,	yshl,	Pe, {0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04)} },
-	{ ASHRB,	yshb,	Pb, {0xd0,(05),0xc0,(05),0xd2,(05)} },
-	{ ASHRL,	yshl,	Px, {0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05)} },
-	{ ASHRQ,	yshl,	Pw, {0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05)} },
-	{ ASHRW,	yshl,	Pe, {0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05)} },
-	{ ASHUFPD,	yxshuf,	Pq, {0xc6,(00)} },
-	{ ASHUFPS,	yxshuf,	Pm, {0xc6,(00)} },
-	{ ASQRTPD,	yxm,	Pe, {0x51} },
-	{ ASQRTPS,	yxm,	Pm, {0x51} },
-	{ ASQRTSD,	yxm,	Pf2, {0x51} },
-	{ ASQRTSS,	yxm,	Pf3, {0x51} },
-	{ ASTC,		ynone,	Px, {0xf9} },
-	{ ASTD,		ynone,	Px, {0xfd} },
-	{ ASTI,		ynone,	Px, {0xfb} },
-	{ ASTMXCSR,	ysvrs,	Pm, {0xae,(03),0xae,(03)} },
-	{ ASTOSB,	ynone,	Pb, {0xaa} },
-	{ ASTOSL,	ynone,	Px, {0xab} },
-	{ ASTOSQ,	ynone,	Pw, {0xab} },
-	{ ASTOSW,	ynone,	Pe, {0xab} },
-	{ ASUBB,	yxorb,	Pb, {0x2c,0x80,(05),0x28,0x2a} },
-	{ ASUBL,	yaddl,	Px, {0x83,(05),0x2d,0x81,(05),0x29,0x2b} },
-	{ ASUBPD,	yxm,	Pe, {0x5c} },
-	{ ASUBPS,	yxm,	Pm, {0x5c} },
-	{ ASUBQ,	yaddl,	Pw, {0x83,(05),0x2d,0x81,(05),0x29,0x2b} },
-	{ ASUBSD,	yxm,	Pf2, {0x5c} },
-	{ ASUBSS,	yxm,	Pf3, {0x5c} },
-	{ ASUBW,	yaddl,	Pe, {0x83,(05),0x2d,0x81,(05),0x29,0x2b} },
-	{ ASWAPGS,	ynone,	Pm, {0x01,0xf8} },
-	{ ASYSCALL,	ynone,	Px, {0x0f,0x05} },	/* fast syscall */
-	{ ATESTB,	ytestb,	Pb, {0xa8,0xf6,(00),0x84,0x84} },
-	{ ATESTL,	ytestl,	Px, {0xa9,0xf7,(00),0x85,0x85} },
-	{ ATESTQ,	ytestl,	Pw, {0xa9,0xf7,(00),0x85,0x85} },
-	{ ATESTW,	ytestl,	Pe, {0xa9,0xf7,(00),0x85,0x85} },
-	{ ATEXT,	ytext,	Px },
-	{ AUCOMISD,	yxcmp,	Pe, {0x2e} },
-	{ AUCOMISS,	yxcmp,	Pm, {0x2e} },
-	{ AUNPCKHPD,	yxm,	Pe, {0x15} },
-	{ AUNPCKHPS,	yxm,	Pm, {0x15} },
-	{ AUNPCKLPD,	yxm,	Pe, {0x14} },
-	{ AUNPCKLPS,	yxm,	Pm, {0x14} },
-	{ AVERR,	ydivl,	Pm, {0x00,(04)} },
-	{ AVERW,	ydivl,	Pm, {0x00,(05)} },
-	{ AWAIT,	ynone,	Px, {0x9b} },
-	{ AWORD,	ybyte,	Px, {2} },
-	{ AXCHGB,	yml_mb,	Pb, {0x86,0x86} },
-	{ AXCHGL,	yxchg,	Px, {0x90,0x90,0x87,0x87} },
-	{ AXCHGQ,	yxchg,	Pw, {0x90,0x90,0x87,0x87} },
-	{ AXCHGW,	yxchg,	Pe, {0x90,0x90,0x87,0x87} },
-	{ AXLAT,	ynone,	Px, {0xd7} },
-	{ AXORB,	yxorb,	Pb, {0x34,0x80,(06),0x30,0x32} },
-	{ AXORL,	yxorl,	Px, {0x83,(06),0x35,0x81,(06),0x31,0x33} },
-	{ AXORPD,	yxm,	Pe, {0x57} },
-	{ AXORPS,	yxm,	Pm, {0x57} },
-	{ AXORQ,	yxorl,	Pw, {0x83,(06),0x35,0x81,(06),0x31,0x33} },
-	{ AXORW,	yxorl,	Pe, {0x83,(06),0x35,0x81,(06),0x31,0x33} },
-
-	{ AFMOVB,	yfmvx,	Px, {0xdf,(04)} },
-	{ AFMOVBP,	yfmvp,	Px, {0xdf,(06)} },
-	{ AFMOVD,	yfmvd,	Px, {0xdd,(00),0xdd,(02),0xd9,(00),0xdd,(02)} },
-	{ AFMOVDP,	yfmvdp,	Px, {0xdd,(03),0xdd,(03)} },
-	{ AFMOVF,	yfmvf,	Px, {0xd9,(00),0xd9,(02)} },
-	{ AFMOVFP,	yfmvp,	Px, {0xd9,(03)} },
-	{ AFMOVL,	yfmvf,	Px, {0xdb,(00),0xdb,(02)} },
-	{ AFMOVLP,	yfmvp,	Px, {0xdb,(03)} },
-	{ AFMOVV,	yfmvx,	Px, {0xdf,(05)} },
-	{ AFMOVVP,	yfmvp,	Px, {0xdf,(07)} },
-	{ AFMOVW,	yfmvf,	Px, {0xdf,(00),0xdf,(02)} },
-	{ AFMOVWP,	yfmvp,	Px, {0xdf,(03)} },
-	{ AFMOVX,	yfmvx,	Px, {0xdb,(05)} },
-	{ AFMOVXP,	yfmvp,	Px, {0xdb,(07)} },
-
-	{ AFCOMB },
-	{ AFCOMBP },
-	{ AFCOMD,	yfadd,	Px, {0xdc,(02),0xd8,(02),0xdc,(02)} },	/* botch */
-	{ AFCOMDP,	yfadd,	Px, {0xdc,(03),0xd8,(03),0xdc,(03)} },	/* botch */
-	{ AFCOMDPP,	ycompp,	Px, {0xde,(03)} },
-	{ AFCOMF,	yfmvx,	Px, {0xd8,(02)} },
-	{ AFCOMFP,	yfmvx,	Px, {0xd8,(03)} },
-	{ AFCOML,	yfmvx,	Px, {0xda,(02)} },
-	{ AFCOMLP,	yfmvx,	Px, {0xda,(03)} },
-	{ AFCOMW,	yfmvx,	Px, {0xde,(02)} },
-	{ AFCOMWP,	yfmvx,	Px, {0xde,(03)} },
-
-	{ AFUCOM,	ycompp,	Px, {0xdd,(04)} },
-	{ AFUCOMP,	ycompp, Px, {0xdd,(05)} },
-	{ AFUCOMPP,	ycompp,	Px, {0xda,(13)} },
-
-	{ AFADDDP,	yfaddp,	Px, {0xde,(00)} },
-	{ AFADDW,	yfmvx,	Px, {0xde,(00)} },
-	{ AFADDL,	yfmvx,	Px, {0xda,(00)} },
-	{ AFADDF,	yfmvx,	Px, {0xd8,(00)} },
-	{ AFADDD,	yfadd,	Px, {0xdc,(00),0xd8,(00),0xdc,(00)} },
-
-	{ AFMULDP,	yfaddp,	Px, {0xde,(01)} },
-	{ AFMULW,	yfmvx,	Px, {0xde,(01)} },
-	{ AFMULL,	yfmvx,	Px, {0xda,(01)} },
-	{ AFMULF,	yfmvx,	Px, {0xd8,(01)} },
-	{ AFMULD,	yfadd,	Px, {0xdc,(01),0xd8,(01),0xdc,(01)} },
-
-	{ AFSUBDP,	yfaddp,	Px, {0xde,(05)} },
-	{ AFSUBW,	yfmvx,	Px, {0xde,(04)} },
-	{ AFSUBL,	yfmvx,	Px, {0xda,(04)} },
-	{ AFSUBF,	yfmvx,	Px, {0xd8,(04)} },
-	{ AFSUBD,	yfadd,	Px, {0xdc,(04),0xd8,(04),0xdc,(05)} },
-
-	{ AFSUBRDP,	yfaddp,	Px, {0xde,(04)} },
-	{ AFSUBRW,	yfmvx,	Px, {0xde,(05)} },
-	{ AFSUBRL,	yfmvx,	Px, {0xda,(05)} },
-	{ AFSUBRF,	yfmvx,	Px, {0xd8,(05)} },
-	{ AFSUBRD,	yfadd,	Px, {0xdc,(05),0xd8,(05),0xdc,(04)} },
-
-	{ AFDIVDP,	yfaddp,	Px, {0xde,(07)} },
-	{ AFDIVW,	yfmvx,	Px, {0xde,(06)} },
-	{ AFDIVL,	yfmvx,	Px, {0xda,(06)} },
-	{ AFDIVF,	yfmvx,	Px, {0xd8,(06)} },
-	{ AFDIVD,	yfadd,	Px, {0xdc,(06),0xd8,(06),0xdc,(07)} },
-
-	{ AFDIVRDP,	yfaddp,	Px, {0xde,(06)} },
-	{ AFDIVRW,	yfmvx,	Px, {0xde,(07)} },
-	{ AFDIVRL,	yfmvx,	Px, {0xda,(07)} },
-	{ AFDIVRF,	yfmvx,	Px, {0xd8,(07)} },
-	{ AFDIVRD,	yfadd,	Px, {0xdc,(07),0xd8,(07),0xdc,(06)} },
-
-	{ AFXCHD,	yfxch,	Px, {0xd9,(01),0xd9,(01)} },
-	{ AFFREE },
-	{ AFLDCW,	ystcw,	Px, {0xd9,(05),0xd9,(05)} },
-	{ AFLDENV,	ystcw,	Px, {0xd9,(04),0xd9,(04)} },
-	{ AFRSTOR,	ysvrs,	Px, {0xdd,(04),0xdd,(04)} },
-	{ AFSAVE,	ysvrs,	Px, {0xdd,(06),0xdd,(06)} },
-	{ AFSTCW,	ystcw,	Px, {0xd9,(07),0xd9,(07)} },
-	{ AFSTENV,	ystcw,	Px, {0xd9,(06),0xd9,(06)} },
-	{ AFSTSW,	ystsw,	Px, {0xdd,(07),0xdf,0xe0} },
-	{ AF2XM1,	ynone,	Px, {0xd9, 0xf0} },
-	{ AFABS,	ynone,	Px, {0xd9, 0xe1} },
-	{ AFCHS,	ynone,	Px, {0xd9, 0xe0} },
-	{ AFCLEX,	ynone,	Px, {0xdb, 0xe2} },
-	{ AFCOS,	ynone,	Px, {0xd9, 0xff} },
-	{ AFDECSTP,	ynone,	Px, {0xd9, 0xf6} },
-	{ AFINCSTP,	ynone,	Px, {0xd9, 0xf7} },
-	{ AFINIT,	ynone,	Px, {0xdb, 0xe3} },
-	{ AFLD1,	ynone,	Px, {0xd9, 0xe8} },
-	{ AFLDL2E,	ynone,	Px, {0xd9, 0xea} },
-	{ AFLDL2T,	ynone,	Px, {0xd9, 0xe9} },
-	{ AFLDLG2,	ynone,	Px, {0xd9, 0xec} },
-	{ AFLDLN2,	ynone,	Px, {0xd9, 0xed} },
-	{ AFLDPI,	ynone,	Px, {0xd9, 0xeb} },
-	{ AFLDZ,	ynone,	Px, {0xd9, 0xee} },
-	{ AFNOP,	ynone,	Px, {0xd9, 0xd0} },
-	{ AFPATAN,	ynone,	Px, {0xd9, 0xf3} },
-	{ AFPREM,	ynone,	Px, {0xd9, 0xf8} },
-	{ AFPREM1,	ynone,	Px, {0xd9, 0xf5} },
-	{ AFPTAN,	ynone,	Px, {0xd9, 0xf2} },
-	{ AFRNDINT,	ynone,	Px, {0xd9, 0xfc} },
-	{ AFSCALE,	ynone,	Px, {0xd9, 0xfd} },
-	{ AFSIN,	ynone,	Px, {0xd9, 0xfe} },
-	{ AFSINCOS,	ynone,	Px, {0xd9, 0xfb} },
-	{ AFSQRT,	ynone,	Px, {0xd9, 0xfa} },
-	{ AFTST,	ynone,	Px, {0xd9, 0xe4} },
-	{ AFXAM,	ynone,	Px, {0xd9, 0xe5} },
-	{ AFXTRACT,	ynone,	Px, {0xd9, 0xf4} },
-	{ AFYL2X,	ynone,	Px, {0xd9, 0xf1} },
-	{ AFYL2XP1,	ynone,	Px, {0xd9, 0xf9} },
-
-	{ ACMPXCHGB,	yrb_mb,	Pb, {0x0f,0xb0} },
-	{ ACMPXCHGL,	yrl_ml,	Px, {0x0f,0xb1} },
-	{ ACMPXCHGW,	yrl_ml,	Pe, {0x0f,0xb1} },
-	{ ACMPXCHGQ,	yrl_ml,	Pw, {0x0f,0xb1} },
-	{ ACMPXCHG8B,	yscond,	Pm, {0xc7,(01)} },
-	{ AINVD,	ynone,	Pm, {0x08} },
-	{ AINVLPG,	ymbs,	Pm, {0x01,(07)} },
-	{ ALFENCE,	ynone,	Pm, {0xae,0xe8} },
-	{ AMFENCE,	ynone,	Pm, {0xae,0xf0} },
-	{ AMOVNTIL,	yrl_ml,	Pm, {0xc3} },
-	{ AMOVNTIQ,	yrl_ml, Pw, {0x0f,0xc3} },
-	{ ARDMSR,	ynone,	Pm, {0x32} },
-	{ ARDPMC,	ynone,	Pm, {0x33} },
-	{ ARDTSC,	ynone,	Pm, {0x31} },
-	{ ARSM,		ynone,	Pm, {0xaa} },
-	{ ASFENCE,	ynone,	Pm, {0xae,0xf8} },
-	{ ASYSRET,	ynone,	Pm, {0x07} },
-	{ AWBINVD,	ynone,	Pm, {0x09} },
-	{ AWRMSR,	ynone,	Pm, {0x30} },
-
-	{ AXADDB,	yrb_mb,	Pb, {0x0f,0xc0} },
-	{ AXADDL,	yrl_ml,	Px, {0x0f,0xc1} },
-	{ AXADDQ,	yrl_ml,	Pw, {0x0f,0xc1} },
-	{ AXADDW,	yrl_ml,	Pe, {0x0f,0xc1} },
-
-	{ ACRC32B,       ycrc32l,Px, {0xf2,0x0f,0x38,0xf0,0} },
-	{ ACRC32Q,       ycrc32l,Pw, {0xf2,0x0f,0x38,0xf1,0} },
-	
-	{ APREFETCHT0,	yprefetch,	Pm,	{0x18,(01)} },
-	{ APREFETCHT1,	yprefetch,	Pm,	{0x18,(02)} },
-	{ APREFETCHT2,	yprefetch,	Pm,	{0x18,(03)} },
-	{ APREFETCHNTA,	yprefetch,	Pm,	{0x18,(00)} },
-	
-	{ AMOVQL,	yrl_ml,	Px, {0x89} },
-
-	{ AUNDEF,		ynone,	Px, {0x0f, 0x0b} },
-
-	{ AAESENC,	yaes,	Pq, {0x38,0xdc,(0)} },
-	{ AAESENCLAST,	yaes,	Pq, {0x38,0xdd,(0)} },
-	{ AAESDEC,	yaes,	Pq, {0x38,0xde,(0)} },
-	{ AAESDECLAST,	yaes,	Pq, {0x38,0xdf,(0)} },
-	{ AAESIMC,	yaes,	Pq, {0x38,0xdb,(0)} },
-	{ AAESKEYGENASSIST,	yaes2,	Pq, {0x3a,0xdf,(0)} },
-
-	{ APSHUFD,	yaes2,	Pq,	{0x70,(0)} },
-	{ APCLMULQDQ,	yxshuf,	Pq, {0x3a,0x44,0} },
-
-	{ AUSEFIELD,	ynop,	Px, {0,0} },
-	{ ATYPE },
-	{ AFUNCDATA,	yfuncdata,	Px, {0,0} },
-	{ APCDATA,	ypcdata,	Px, {0,0} },
-	{ ACHECKNIL },
-	{ AVARDEF },
-	{ AVARKILL },
-	{ ADUFFCOPY,	yduff,	Px, {0xe8} },
-	{ ADUFFZERO,	yduff,	Px, {0xe8} },
-
-	{ AEND },
-	{0}
-};
-
-static Optab*	opindex[ALAST+1];
-static vlong	vaddr(Link*, Addr*, Reloc*);
-
-// 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.
-// It does not seem to be necessary for any other systems. This is probably working
-// around a Solaris-specific bug that should be fixed differently, but we don't know
-// what that bug is. And this does fix it.
-static int
-isextern(LSym *s)
-{
-	// All the Solaris dynamic imports from libc.so begin with "libc·", which
-	// the compiler rewrites to "libc." by the time liblink gets it.
-	return strncmp(s->name, "libc.", 5) == 0;
-}
-
-// 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.
-static uchar nop[][16] = {
-	{0x90},
-	{0x66, 0x90},
-	{0x0F, 0x1F, 0x00},
-	{0x0F, 0x1F, 0x40, 0x00},
-	{0x0F, 0x1F, 0x44, 0x00, 0x00},
-	{0x66, 0x0F, 0x1F, 0x44, 0x00, 0x00},
-	{0x0F, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00},
-	{0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00},
-	{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},
-};
-
-static void
-fillnop(uchar *p, int n)
-{
-	int m;
-
-	while(n > 0) {
-		m = n;
-		if(m > nelem(nop))
-			m = nelem(nop);
-		memmove(p, nop[m-1], m);
-		p += m;
-		n -= m;
-	}
-}
-
-static void instinit(void);
-
-static int32
-naclpad(Link *ctxt, LSym *s, int32 c, int32 pad)
-{
-	symgrow(ctxt, s, c+pad);
-	fillnop(s->p+c, pad);
-	return c+pad;
-}
-
-static int
-spadjop(Link *ctxt, Prog *p, int l, int q)
-{
-	if(p->mode != 64 || ctxt->arch->ptrsize == 4)
-		return l;
-	return q;
-}
-
-void
-span6(Link *ctxt, LSym *s)
-{
-	Prog *p, *q;
-	int32 c, v, loop;
-	uchar *bp;
-	int n, m, i;
-
-	ctxt->cursym = s;
-	
-	if(s->p != nil)
-		return;
-	
-	if(ycover[0] == 0)
-		instinit();
-	
-	for(p = ctxt->cursym->text; p != nil; p = p->link) {
-		n = 0;
-		if(p->to.type == D_BRANCH)
-			if(p->pcond == nil)
-				p->pcond = p;
-		if((q = p->pcond) != nil)
-			if(q->back != 2)
-				n = 1;
-		p->back = n;
-		if(p->as == AADJSP) {
-			p->to.type = D_SP;
-			v = -p->from.offset;
-			p->from.offset = v;
-			p->as = spadjop(ctxt, p, AADDL, AADDQ);
-			if(v < 0) {
-				p->as = spadjop(ctxt, p, ASUBL, ASUBQ);
-				v = -v;
-				p->from.offset = v;
-			}
-			if(v == 0)
-				p->as = ANOP;
-		}
-	}
-
-	for(p = s->text; p != nil; p = p->link) {
-		p->back = 2;	// use short branches first time through
-		if((q = p->pcond) != nil && (q->back & 2)) {
-			p->back |= 1;	// backward jump
-			q->back |= 4;   // loop head
-		}
-
-		if(p->as == AADJSP) {
-			p->to.type = D_SP;
-			v = -p->from.offset;
-			p->from.offset = v;
-			p->as = spadjop(ctxt, p, AADDL, AADDQ);
-			if(v < 0) {
-				p->as = spadjop(ctxt, p, ASUBL, ASUBQ);
-				v = -v;
-				p->from.offset = v;
-			}
-			if(v == 0)
-				p->as = ANOP;
-		}
-	}
-	
-	n = 0;
-	do {
-		loop = 0;
-		memset(s->r, 0, s->nr*sizeof s->r[0]);
-		s->nr = 0;
-		s->np = 0;
-		c = 0;
-		for(p = s->text; p != nil; p = p->link) {
-			if(ctxt->headtype == Hnacl && p->isize > 0) {
-				static LSym *deferreturn;
-				
-				if(deferreturn == nil)
-					deferreturn = linklookup(ctxt, "runtime.deferreturn", 0);
-
-				// pad everything to avoid crossing 32-byte boundary
-				if((c>>5) != ((c+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 == ACALL && p->to.sym == deferreturn)
-					c = naclpad(ctxt, s, c, -c&31);
-				// pad call to end at 32-byte boundary
-				if(p->as == ACALL)
-					c = naclpad(ctxt, s, c, -(c+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 || p->as == AREPN) && (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);
-			}
-
-			if((p->back & 4) && (c&(LoopAlign-1)) != 0) {
-				// pad with NOPs
-				v = -c&(LoopAlign-1);
-				if(v <= MaxLoopPad) {
-					symgrow(ctxt, s, c+v);
-					fillnop(s->p+c, v);
-					c += v;
-				}
-			}
-
-			p->pc = c;
-
-			// process forward jumps to p
-			for(q = p->comefrom; q != nil; q = q->forwd) {
-				v = p->pc - (q->pc + q->mark);
-				if(q->back & 2)	{	// short
-					if(v > 127) {
-						loop++;
-						q->back ^= 2;
-					}
-					if(q->as == AJCXZL)
-						s->p[q->pc+2] = v;
-					else
-						s->p[q->pc+1] = v;
-				} else {
-					bp = s->p + q->pc + q->mark - 4;
-					*bp++ = v;
-					*bp++ = v>>8;
-					*bp++ = v>>16;
-					*bp = v>>24;
-				}	
-			}
-			p->comefrom = nil;
-
-			p->pc = c;
-			asmins(ctxt, p);
-			m = ctxt->andptr-ctxt->and;
-			if(p->isize != m) {
-				p->isize = m;
-				loop++;
-			}
-			symgrow(ctxt, s, p->pc+m);
-			memmove(s->p+p->pc, ctxt->and, m);
-			p->mark = m;
-			c += m;
-		}
-		if(++n > 20) {
-			ctxt->diag("span must be looping");
-			sysfatal("loop");
-		}
-	} while(loop);
-	
-	if(ctxt->headtype == Hnacl)
-		c = naclpad(ctxt, s, c, -c&31);
-	
-	c += -c&(FuncAlign-1);
-	s->size = c;
-
-	if(0 /* debug['a'] > 1 */) {
-		print("span1 %s %lld (%d tries)\n %.6ux", s->name, s->size, n, 0);
-		for(i=0; i<s->np; i++) {
-			print(" %.2ux", s->p[i]);
-			if(i%16 == 15)
-				print("\n  %.6ux", i+1);
-		}
-		if(i%16)
-			print("\n");
-	
-		for(i=0; i<s->nr; i++) {
-			Reloc *r;
-			
-			r = &s->r[i];
-			print(" rel %#.4ux/%d %s%+lld\n", r->off, r->siz, r->sym->name, r->add);
-		}
-	}
-}
-
-static void
-instinit(void)
-{
-	int c, i;
-
-	for(i=1; optab[i].as; i++) {
-		c = optab[i].as;
-		if(opindex[c] != nil)
-			sysfatal("phase error in optab: %d (%A)", i, 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 + Ys32] = 1;
-	ycover[Yi1*Ymax + Ys32] = 1;
-	ycover[Yi8*Ymax + Ys32] = 1;
-
-	ycover[Yi0*Ymax + Yi32] = 1;
-	ycover[Yi1*Ymax + Yi32] = 1;
-	ycover[Yi8*Ymax + Yi32] = 1;
-	ycover[Ys32*Ymax + Yi32] = 1;
-
-	ycover[Yi0*Ymax + Yi64] = 1;
-	ycover[Yi1*Ymax + Yi64] = 1;
-	ycover[Yi8*Ymax + Yi64] = 1;
-	ycover[Ys32*Ymax + Yi64] = 1;
-	ycover[Yi32*Ymax + Yi64] = 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[Yrl*Ymax + Yrb] = 1;
-
-	ycover[Ycl*Ymax + Ycx] = 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[Yrl*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<D_NONE; i++) {
-		reg[i] = -1;
-		if(i >= D_AL && i <= D_R15B) {
-			reg[i] = (i-D_AL) & 7;
-			if(i >= D_SPB && i <= D_DIB)
-				regrex[i] = 0x40;
-			if(i >= D_R8B && i <= D_R15B)
-				regrex[i] = Rxr | Rxx | Rxb;
-		}
-		if(i >= D_AH && i<= D_BH)
-			reg[i] = 4 + ((i-D_AH) & 7);
-		if(i >= D_AX && i <= D_R15) {
-			reg[i] = (i-D_AX) & 7;
-			if(i >= D_R8)
-				regrex[i] = Rxr | Rxx | Rxb;
-		}
-		if(i >= D_F0 && i <= D_F0+7)
-			reg[i] = (i-D_F0) & 7;
-		if(i >= D_M0 && i <= D_M0+7)
-			reg[i] = (i-D_M0) & 7;
-		if(i >= D_X0 && i <= D_X0+15) {
-			reg[i] = (i-D_X0) & 7;
-			if(i >= D_X0+8)
-				regrex[i] = Rxr | Rxx | Rxb;
-		}
-		if(i >= D_CR+8 && i <= D_CR+15)
-			regrex[i] = Rxr;
-	}
-}
-
-static int
-prefixof(Link *ctxt, Addr *a)
-{
-	switch(a->type) {
-	case D_INDIR+D_CS:
-		return 0x2e;
-	case D_INDIR+D_DS:
-		return 0x3e;
-	case D_INDIR+D_ES:
-		return 0x26;
-	case D_INDIR+D_FS:
-		return 0x64;
-	case D_INDIR+D_GS:
-		return 0x65;
-	case D_INDIR+D_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.
-		switch(ctxt->headtype) {
-		default:
-			sysfatal("unknown TLS base register for %s", headstr(ctxt->headtype));
-		case Hdragonfly:
-		case Hfreebsd:
-		case Hlinux:
-		case Hnetbsd:
-		case Hopenbsd:
-		case Hsolaris:
-			return 0x64; // FS
-		case Hdarwin:
-			return 0x65; // GS
-		}
-	}
-	switch(a->index) {
-	case D_CS:
-		return 0x2e;
-	case D_DS:
-		return 0x3e;
-	case D_ES:
-		return 0x26;
-	case D_FS:
-		return 0x64;
-	case D_GS:
-		return 0x65;
-	}
-	return 0;
-}
-
-static int
-oclass(Link *ctxt, Addr *a)
-{
-	vlong v;
-	int32 l;
-
-	if(a->type >= D_INDIR || a->index != D_NONE) {
-		if(a->index != D_NONE && a->scale == 0) {
-			if(a->type == D_ADDR) {
-				switch(a->index) {
-				case D_EXTERN:
-				case D_STATIC:
-					if(a->sym != nil && isextern(a->sym))
-						return Yi32;
-					return Yiauto; // use pc-relative addressing
-				case D_AUTO:
-				case D_PARAM:
-					return Yiauto;
-				}
-				return Yxxx;
-			}
-			return Ycol;
-		}
-		return Ym;
-	}
-	switch(a->type)
-	{
-	case D_AL:
-		return Yal;
-
-	case D_AX:
-		return Yax;
-
-/*
-	case D_SPB:
-*/
-	case D_BPB:
-	case D_SIB:
-	case D_DIB:
-	case D_R8B:
-	case D_R9B:
-	case D_R10B:
-	case D_R11B:
-	case D_R12B:
-	case D_R13B:
-	case D_R14B:
-	case D_R15B:
-		if(ctxt->asmode != 64)
-			return Yxxx;
-	case D_DL:
-	case D_BL:
-	case D_AH:
-	case D_CH:
-	case D_DH:
-	case D_BH:
-		return Yrb;
-
-	case D_CL:
-		return Ycl;
-
-	case D_CX:
-		return Ycx;
-
-	case D_DX:
-	case D_BX:
-		return Yrx;
-
-	case D_R8:	/* not really Yrl */
-	case D_R9:
-	case D_R10:
-	case D_R11:
-	case D_R12:
-	case D_R13:
-	case D_R14:
-	case D_R15:
-		if(ctxt->asmode != 64)
-			return Yxxx;
-	case D_SP:
-	case D_BP:
-	case D_SI:
-	case D_DI:
-		return Yrl;
-
-	case D_F0+0:
-		return	Yf0;
-
-	case D_F0+1:
-	case D_F0+2:
-	case D_F0+3:
-	case D_F0+4:
-	case D_F0+5:
-	case D_F0+6:
-	case D_F0+7:
-		return	Yrf;
-
-	case D_M0+0:
-	case D_M0+1:
-	case D_M0+2:
-	case D_M0+3:
-	case D_M0+4:
-	case D_M0+5:
-	case D_M0+6:
-	case D_M0+7:
-		return	Ymr;
-
-	case D_X0+0:
-	case D_X0+1:
-	case D_X0+2:
-	case D_X0+3:
-	case D_X0+4:
-	case D_X0+5:
-	case D_X0+6:
-	case D_X0+7:
-	case D_X0+8:
-	case D_X0+9:
-	case D_X0+10:
-	case D_X0+11:
-	case D_X0+12:
-	case D_X0+13:
-	case D_X0+14:
-	case D_X0+15:
-		return	Yxr;
-
-	case D_NONE:
-		return Ynone;
-
-	case D_CS:	return	Ycs;
-	case D_SS:	return	Yss;
-	case D_DS:	return	Yds;
-	case D_ES:	return	Yes;
-	case D_FS:	return	Yfs;
-	case D_GS:	return	Ygs;
-	case D_TLS:	return	Ytls;
-
-	case D_GDTR:	return	Ygdtr;
-	case D_IDTR:	return	Yidtr;
-	case D_LDTR:	return	Yldtr;
-	case D_MSW:	return	Ymsw;
-	case D_TASK:	return	Ytask;
-
-	case D_CR+0:	return	Ycr0;
-	case D_CR+1:	return	Ycr1;
-	case D_CR+2:	return	Ycr2;
-	case D_CR+3:	return	Ycr3;
-	case D_CR+4:	return	Ycr4;
-	case D_CR+5:	return	Ycr5;
-	case D_CR+6:	return	Ycr6;
-	case D_CR+7:	return	Ycr7;
-	case D_CR+8:	return	Ycr8;
-
-	case D_DR+0:	return	Ydr0;
-	case D_DR+1:	return	Ydr1;
-	case D_DR+2:	return	Ydr2;
-	case D_DR+3:	return	Ydr3;
-	case D_DR+4:	return	Ydr4;
-	case D_DR+5:	return	Ydr5;
-	case D_DR+6:	return	Ydr6;
-	case D_DR+7:	return	Ydr7;
-
-	case D_TR+0:	return	Ytr0;
-	case D_TR+1:	return	Ytr1;
-	case D_TR+2:	return	Ytr2;
-	case D_TR+3:	return	Ytr3;
-	case D_TR+4:	return	Ytr4;
-	case D_TR+5:	return	Ytr5;
-	case D_TR+6:	return	Ytr6;
-	case D_TR+7:	return	Ytr7;
-
-	case D_EXTERN:
-	case D_STATIC:
-	case D_AUTO:
-	case D_PARAM:
-		return Ym;
-
-	case D_CONST:
-	case D_ADDR:
-		if(a->sym == nil) {
-			v = a->offset;
-			if(v == 0)
-				return Yi0;
-			if(v == 1)
-				return Yi1;
-			if(v >= -128 && v <= 127)
-				return Yi8;
-			l = v;
-			if((vlong)l == v)
-				return Ys32;	/* can sign extend */
-			if((v>>32) == 0)
-				return Yi32;	/* unsigned */
-			return Yi64;
-		}
-		return Yi32;
-
-	case D_BRANCH:
-		return Ybr;
-	}
-	return Yxxx;
-}
-
-static void
-asmidx(Link *ctxt, int scale, int index, int base)
-{
-	int i;
-
-	switch(index) {
-	default:
-		goto bad;
-
-	case D_NONE:
-		i = 4 << 3;
-		goto bas;
-
-	case D_R8:
-	case D_R9:
-	case D_R10:
-	case D_R11:
-	case D_R12:
-	case D_R13:
-	case D_R14:
-	case D_R15:
-		if(ctxt->asmode != 64)
-			goto bad;
-	case D_AX:
-	case D_CX:
-	case D_DX:
-	case D_BX:
-	case D_BP:
-	case D_SI:
-	case D_DI:
-		i = reg[index] << 3;
-		break;
-	}
-	switch(scale) {
-	default:
-		goto bad;
-	case 1:
-		break;
-	case 2:
-		i |= (1<<6);
-		break;
-	case 4:
-		i |= (2<<6);
-		break;
-	case 8:
-		i |= (3<<6);
-		break;
-	}
-bas:
-	switch(base) {
-	default:
-		goto bad;
-	case D_NONE:	/* must be mod=00 */
-		i |= 5;
-		break;
-	case D_R8:
-	case D_R9:
-	case D_R10:
-	case D_R11:
-	case D_R12:
-	case D_R13:
-	case D_R14:
-	case D_R15:
-		if(ctxt->asmode != 64)
-			goto bad;
-	case D_AX:
-	case D_CX:
-	case D_DX:
-	case D_BX:
-	case D_SP:
-	case D_BP:
-	case D_SI:
-	case D_DI:
-		i |= reg[base];
-		break;
-	}
-	*ctxt->andptr++ = i;
-	return;
-bad:
-	ctxt->diag("asmidx: bad address %d/%d/%d", scale, index, base);
-	*ctxt->andptr++ = 0;
-	return;
-}
-
-static void
-put4(Link *ctxt, int32 v)
-{
-	ctxt->andptr[0] = v;
-	ctxt->andptr[1] = v>>8;
-	ctxt->andptr[2] = v>>16;
-	ctxt->andptr[3] = v>>24;
-	ctxt->andptr += 4;
-}
-
-static void
-relput4(Link *ctxt, Prog *p, Addr *a)
-{
-	vlong v;
-	Reloc rel, *r;
-	
-	v = vaddr(ctxt, a, &rel);
-	if(rel.siz != 0) {
-		if(rel.siz != 4)
-			ctxt->diag("bad reloc");
-		r = addrel(ctxt->cursym);
-		*r = rel;
-		r->off = p->pc + ctxt->andptr - ctxt->and;
-	}
-	put4(ctxt, v);
-}
-
-static void
-put8(Link *ctxt, vlong v)
-{
-	ctxt->andptr[0] = v;
-	ctxt->andptr[1] = v>>8;
-	ctxt->andptr[2] = v>>16;
-	ctxt->andptr[3] = v>>24;
-	ctxt->andptr[4] = v>>32;
-	ctxt->andptr[5] = v>>40;
-	ctxt->andptr[6] = v>>48;
-	ctxt->andptr[7] = v>>56;
-	ctxt->andptr += 8;
-}
-
-/*
-static void
-relput8(Prog *p, Addr *a)
-{
-	vlong v;
-	Reloc rel, *r;
-	
-	v = vaddr(ctxt, a, &rel);
-	if(rel.siz != 0) {
-		r = addrel(ctxt->cursym);
-		*r = rel;
-		r->siz = 8;
-		r->off = p->pc + ctxt->andptr - ctxt->and;
-	}
-	put8(ctxt, v);
-}
-*/
-
-static vlong
-vaddr(Link *ctxt, Addr *a, Reloc *r)
-{
-	int t;
-	vlong v;
-	LSym *s;
-	
-	if(r != nil)
-		memset(r, 0, sizeof *r);
-
-	t = a->type;
-	v = a->offset;
-	if(t == D_ADDR)
-		t = a->index;
-	switch(t) {
-	case D_STATIC:
-	case D_EXTERN:
-		s = a->sym;
-		if(r == nil) {
-			ctxt->diag("need reloc for %D", a);
-			sysfatal("reloc");
-		}
-		if(isextern(s)) {
-			r->siz = 4;
-			r->type = R_ADDR;
-		} else {
-			r->siz = 4;
-			r->type = R_PCREL;
-		}
-		r->off = -1;	// caller must fill in
-		r->sym = s;
-		r->add = v;
-		v = 0;
-		if(s->type == STLSBSS) {
-			r->xadd = r->add - r->siz;
-			r->type = R_TLS;
-			r->xsym = s;
-		}
-		break;
-	
-	case D_INDIR+D_TLS:
-		if(r == nil) {
-			ctxt->diag("need reloc for %D", a);
-			sysfatal("reloc");
-		}
-		r->type = R_TLS_LE;
-		r->siz = 4;
-		r->off = -1;	// caller must fill in
-		r->add = v;
-		v = 0;
-		break;
-	}
-	return v;
-}
-
-static void
-asmandsz(Link *ctxt, Addr *a, int r, int rex, int m64)
-{
-	int32 v;
-	int t, scale;
-	Reloc rel;
-
-	USED(m64);
-	rex &= (0x40 | Rxr);
-	v = a->offset;
-	t = a->type;
-	rel.siz = 0;
-	if(a->index != D_NONE && a->index != D_TLS) {
-		if(t < D_INDIR) { 
-			switch(t) {
-			default:
-				goto bad;
-			case D_EXTERN:
-			case D_STATIC:
-				if(!isextern(a->sym))
-					goto bad;
-				t = D_NONE;
-				v = vaddr(ctxt, a, &rel);
-				break;
-			case D_AUTO:
-			case D_PARAM:
-				t = D_SP;
-				break;
-			}
-		} else
-			t -= D_INDIR;
-		ctxt->rexflag |= (regrex[(int)a->index] & Rxx) | (regrex[t] & Rxb) | rex;
-		if(t == D_NONE) {
-			*ctxt->andptr++ = (0 << 6) | (4 << 0) | (r << 3);
-			asmidx(ctxt, a->scale, a->index, t);
-			goto putrelv;
-		}
-		if(v == 0 && rel.siz == 0 && t != D_BP && t != D_R13) {
-			*ctxt->andptr++ = (0 << 6) | (4 << 0) | (r << 3);
-			asmidx(ctxt, a->scale, a->index, t);
-			return;
-		}
-		if(v >= -128 && v < 128 && rel.siz == 0) {
-			*ctxt->andptr++ = (1 << 6) | (4 << 0) | (r << 3);
-			asmidx(ctxt, a->scale, a->index, t);
-			*ctxt->andptr++ = v;
-			return;
-		}
-		*ctxt->andptr++ = (2 << 6) | (4 << 0) | (r << 3);
-		asmidx(ctxt, a->scale, a->index, t);
-		goto putrelv;
-	}
-	if(t >= D_AL && t <= D_X0+15) {
-		if(v)
-			goto bad;
-		*ctxt->andptr++ = (3 << 6) | (reg[t] << 0) | (r << 3);
-		ctxt->rexflag |= (regrex[t] & (0x40 | Rxb)) | rex;
-		return;
-	}
-	
-	scale = a->scale;
-	if(t < D_INDIR) {
-		switch(a->type) {
-		default:
-			goto bad;
-		case D_STATIC:
-		case D_EXTERN:
-			t = D_NONE;
-			v = vaddr(ctxt, a, &rel);
-			break;
-		case D_AUTO:
-		case D_PARAM:
-			t = D_SP;
-			break;
-		}
-		scale = 1;
-	} else
-		t -= D_INDIR;
-	if(t == D_TLS)
-		v = vaddr(ctxt, a, &rel);
-
-	ctxt->rexflag |= (regrex[t] & Rxb) | rex;
-	if(t == D_NONE || (D_CS <= t && t <= D_GS) || t == D_TLS) {
-		if((a->sym == nil || !isextern(a->sym)) && t == D_NONE && (a->type == D_STATIC || a->type == D_EXTERN) || ctxt->asmode != 64) {
-			*ctxt->andptr++ = (0 << 6) | (5 << 0) | (r << 3);
-			goto putrelv;
-		}
-		/* temporary */
-		*ctxt->andptr++ = (0 <<  6) | (4 << 0) | (r << 3);	/* sib present */
-		*ctxt->andptr++ = (0 << 6) | (4 << 3) | (5 << 0);	/* DS:d32 */
-		goto putrelv;
-	}
-	if(t == D_SP || t == D_R12) {
-		if(v == 0) {
-			*ctxt->andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
-			asmidx(ctxt, scale, D_NONE, t);
-			return;
-		}
-		if(v >= -128 && v < 128) {
-			*ctxt->andptr++ = (1 << 6) | (reg[t] << 0) | (r << 3);
-			asmidx(ctxt, scale, D_NONE, t);
-			*ctxt->andptr++ = v;
-			return;
-		}
-		*ctxt->andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
-		asmidx(ctxt, scale, D_NONE, t);
-		goto putrelv;
-	}
-	if(t >= D_AX && t <= D_R15) {
-		if(a->index == D_TLS) {
-			memset(&rel, 0, sizeof rel);
-			rel.type = R_TLS_IE;
-			rel.siz = 4;
-			rel.sym = nil;
-			rel.add = v;
-			v = 0;
-		}
-		if(v == 0 && rel.siz == 0 && t != D_BP && t != D_R13) {
-			*ctxt->andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
-			return;
-		}
-		if(v >= -128 && v < 128 && rel.siz == 0) {
-			ctxt->andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3);
-			ctxt->andptr[1] = v;
-			ctxt->andptr += 2;
-			return;
-		}
-		*ctxt->andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
-		goto putrelv;
-	}
-	goto bad;
-	
-putrelv:
-	if(rel.siz != 0) {
-		Reloc *r;
-
-		if(rel.siz != 4) {
-			ctxt->diag("bad rel");
-			goto bad;
-		}
-		r = addrel(ctxt->cursym);
-		*r = rel;
-		r->off = ctxt->curp->pc + ctxt->andptr - ctxt->and;
-	}
-		
-	put4(ctxt, v);
-	return;
-
-bad:
-	ctxt->diag("asmand: bad address %D", a);
-	return;
-}
-
-static void
-asmand(Link *ctxt, Addr *a, Addr *ra)
-{
-	asmandsz(ctxt, a, reg[ra->type], regrex[ra->type], 0);
-}
-
-static void
-asmando(Link *ctxt, Addr *a, int o)
-{
-	asmandsz(ctxt, a, o, 0, 0);
-}
-
-static void
-bytereg(Addr *a, uint8 *t)
-{
-	if(a->index == D_NONE && (a->type >= D_AX && a->type <= D_R15)) {
-		a->type = D_AL + (a->type-D_AX);
-		*t = 0;
-	}
-}
-
-enum {
-	E = 0xff,
-};
-static Movtab	ymovtab[] =
-{
-/* 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}},
-	{APUSHQ,	Yfs,	Ynone,	0,	{0x0f,0xa0,E,0}},
-	{APUSHQ,	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}},
-	{APOPQ,	Ynone,	Yfs,	0,	{0x0f,0xa1,E,0}},
-	{APOPQ,	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,	Ycr8,	Yml,	3,	{0x0f,0x20,8,0}},
-	{AMOVQ,	Ycr0,	Yml,	3,	{0x0f,0x20,0,0}},
-	{AMOVQ,	Ycr2,	Yml,	3,	{0x0f,0x20,2,0}},
-	{AMOVQ,	Ycr3,	Yml,	3,	{0x0f,0x20,3,0}},
-	{AMOVQ,	Ycr4,	Yml,	3,	{0x0f,0x20,4,0}},
-	{AMOVQ,	Ycr8,	Yml,	3,	{0x0f,0x20,8,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}},
-	{AMOVL,	Yml,	Ycr8,	4,	{0x0f,0x22,8,0}},
-	{AMOVQ,	Yml,	Ycr0,	4,	{0x0f,0x22,0,0}},
-	{AMOVQ,	Yml,	Ycr2,	4,	{0x0f,0x22,2,0}},
-	{AMOVQ,	Yml,	Ycr3,	4,	{0x0f,0x22,3,0}},
-	{AMOVQ,	Yml,	Ycr4,	4,	{0x0f,0x22,4,0}},
-	{AMOVQ,	Yml,	Ycr8,	4,	{0x0f,0x22,8,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}},
-	{AMOVQ,	Ydr0,	Yml,	3,	{0x0f,0x21,0,0}},
-	{AMOVQ,	Ydr6,	Yml,	3,	{0x0f,0x21,6,0}},
-	{AMOVQ,	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}},
-	{AMOVQ,	Yml,	Ydr0,	4,	{0x0f,0x23,0,0}},
-	{AMOVQ,	Yml,	Ydr6,	4,	{0x0f,0x23,6,0}},
-	{AMOVQ,	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}},
-	{AMOVQ,	Ym,	Ygdtr,	4,	{0x0f,0x01,2,0}},
-	{AMOVQ,	Ygdtr,	Ym,	3,	{0x0f,0x01,0,0}},
-	{AMOVQ,	Ym,	Yidtr,	4,	{0x0f,0x01,3,0}},
-	{AMOVQ,	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}},
-	{ASHLQ,	Ycol,	Yml,	6,	{Pw,0xa4,0xa5,0}},
-	{ASHRQ,	Ycol,	Yml,	6,	{Pw,0xac,0xad,0}},
-	{ASHLW,	Ycol,	Yml,	6,	{Pe,0xa4,0xa5,0}},
-	{ASHRW,	Ycol,	Yml,	6,	{Pe,0xac,0xad,0}},
-
-/* load TLS base */
-	{AMOVQ,	Ytls,	Yrl,	7,	{0,0,0,0}},
-
-	{0}
-};
-
-static int
-isax(Addr *a)
-{
-
-	switch(a->type) {
-	case D_AX:
-	case D_AL:
-	case D_AH:
-	case D_INDIR+D_AX:
-		return 1;
-	}
-	if(a->index == D_AX)
-		return 1;
-	return 0;
-}
-
-static void
-subreg(Prog *p, int from, int to)
-{
-
-	if(0 /*debug['Q']*/)
-		print("\n%P	s/%R/%R/\n", p, from, to);
-
-	if(p->from.type == from)
-		p->from.type = to;
-	if(p->to.type == from)
-		p->to.type = to;
-
-	if(p->from.index == from)
-		p->from.index = to;
-	if(p->to.index == from)
-		p->to.index = to;
-
-	from += D_INDIR;
-	if(p->from.type == from)
-		p->from.type = to+D_INDIR;
-	if(p->to.type == from)
-		p->to.type = to+D_INDIR;
-
-	if(0 /*debug['Q']*/)
-		print("%P\n", p);
-}
-
-static int
-mediaop(Link *ctxt, Optab *o, int op, int osize, int z)
-{
-	switch(op){
-	case Pm:
-	case Pe:
-	case Pf2:
-	case Pf3:
-		if(osize != 1){
-			if(op != Pm)
-				*ctxt->andptr++ = op;
-			*ctxt->andptr++ = Pm;
-			op = o->op[++z];
-			break;
-		}
-	default:
-		if(ctxt->andptr == ctxt->and || ctxt->and[ctxt->andptr - ctxt->and - 1] != Pm)
-			*ctxt->andptr++ = Pm;
-		break;
-	}
-	*ctxt->andptr++ = op;
-	return z;
-}
-
-static void
-doasm(Link *ctxt, Prog *p)
-{
-	Optab *o;
-	Prog *q, pp;
-	uchar *t;
-	Movtab *mo;
-	int z, op, ft, tt, xo, l, pre;
-	vlong v;
-	Reloc rel, *r;
-	Addr *a;
-	
-	ctxt->curp = p;	// TODO
-
-	o = opindex[p->as];
-	if(o == nil) {
-		ctxt->diag("asmins: missing op %P", p);
-		return;
-	}
-	
-	pre = prefixof(ctxt, &p->from);
-	if(pre)
-		*ctxt->andptr++ = pre;
-	pre = prefixof(ctxt, &p->to);
-	if(pre)
-		*ctxt->andptr++ = pre;
-
-	if(p->ft == 0)
-		p->ft = oclass(ctxt, &p->from);
-	if(p->tt == 0)
-		p->tt = oclass(ctxt, &p->to);
-
-	ft = p->ft * Ymax;
-	tt = p->tt * Ymax;
-
-	t = o->ytab;
-	if(t == 0) {
-		ctxt->diag("asmins: noproto %P", p);
-		return;
-	}
-	xo = o->op[0] == 0x0f;
-	for(z=0; *t; z+=t[3]+xo,t+=4)
-		if(ycover[ft+t[0]])
-		if(ycover[tt+t[1]])
-			goto found;
-	goto domov;
-
-found:
-	switch(o->prefix) {
-	case Pq:	/* 16 bit escape and opcode escape */
-		*ctxt->andptr++ = Pe;
-		*ctxt->andptr++ = Pm;
-		break;
-	case Pq3:	/* 16 bit escape, Rex.w, and opcode escape */
-		*ctxt->andptr++ = Pe;
-		*ctxt->andptr++ = Pw;
-		*ctxt->andptr++ = Pm;
-		break;
-
-	case Pf2:	/* xmm opcode escape */
-	case Pf3:
-		*ctxt->andptr++ = o->prefix;
-		*ctxt->andptr++ = Pm;
-		break;
-
-	case Pm:	/* opcode escape */
-		*ctxt->andptr++ = Pm;
-		break;
-
-	case Pe:	/* 16 bit escape */
-		*ctxt->andptr++ = Pe;
-		break;
-
-	case Pw:	/* 64-bit escape */
-		if(p->mode != 64)
-			ctxt->diag("asmins: illegal 64: %P", p);
-		ctxt->rexflag |= Pw;
-		break;
-
-	case Pb:	/* botch */
-		bytereg(&p->from, &p->ft);
-		bytereg(&p->to, &p->tt);
-		break;
-
-	case P32:	/* 32 bit but illegal if 64-bit mode */
-		if(p->mode == 64)
-			ctxt->diag("asmins: illegal in 64-bit mode: %P", p);
-		break;
-
-	case Py:	/* 64-bit only, no prefix */
-		if(p->mode != 64)
-			ctxt->diag("asmins: illegal in %d-bit mode: %P", p->mode, p);
-		break;
-	}
-
-	if(z >= nelem(o->op))
-		sysfatal("asmins bad table %P", p);
-	op = o->op[z];
-	if(op == 0x0f) {
-		*ctxt->andptr++ = op;
-		op = o->op[++z];
-	}
-	switch(t[2]) {
-	default:
-		ctxt->diag("asmins: unknown z %d %P", t[2], p);
-		return;
-
-	case Zpseudo:
-		break;
-
-	case Zlit:
-		for(; op = o->op[z]; z++)
-			*ctxt->andptr++ = op;
-		break;
-
-	case Zlitm_r:
-		for(; op = o->op[z]; z++)
-			*ctxt->andptr++ = op;
-		asmand(ctxt, &p->from, &p->to);
-		break;
-
-	case Zmb_r:
-		bytereg(&p->from, &p->ft);
-		/* fall through */
-	case Zm_r:
-		*ctxt->andptr++ = op;
-		asmand(ctxt, &p->from, &p->to);
-		break;
-	case Zm2_r:
-		*ctxt->andptr++ = op;
-		*ctxt->andptr++ = o->op[z+1];
-		asmand(ctxt, &p->from, &p->to);
-		break;
-
-	case Zm_r_xm:
-		mediaop(ctxt, o, op, t[3], z);
-		asmand(ctxt, &p->from, &p->to);
-		break;
-
-	case Zm_r_xm_nr:
-		ctxt->rexflag = 0;
-		mediaop(ctxt, o, op, t[3], z);
-		asmand(ctxt, &p->from, &p->to);
-		break;
-
-	case Zm_r_i_xm:
-		mediaop(ctxt, o, op, t[3], z);
-		asmand(ctxt, &p->from, &p->to);
-		*ctxt->andptr++ = p->to.offset;
-		break;
-
-	case Zm_r_3d:
-		*ctxt->andptr++ = 0x0f;
-		*ctxt->andptr++ = 0x0f;
-		asmand(ctxt, &p->from, &p->to);
-		*ctxt->andptr++ = op;
-		break;
-
-	case Zibm_r:
-		while ((op = o->op[z++]) != 0)
-			*ctxt->andptr++ = op;
-		asmand(ctxt, &p->from, &p->to);
-		*ctxt->andptr++ = p->to.offset;
-		break;
-
-	case Zaut_r:
-		*ctxt->andptr++ = 0x8d;	/* leal */
-		if(p->from.type != D_ADDR)
-			ctxt->diag("asmins: Zaut sb type ADDR");
-		p->from.type = p->from.index;
-		p->from.index = D_NONE;
-		asmand(ctxt, &p->from, &p->to);
-		p->from.index = p->from.type;
-		p->from.type = D_ADDR;
-		break;
-
-	case Zm_o:
-		*ctxt->andptr++ = op;
-		asmando(ctxt, &p->from, o->op[z+1]);
-		break;
-
-	case Zr_m:
-		*ctxt->andptr++ = op;
-		asmand(ctxt, &p->to, &p->from);
-		break;
-
-	case Zr_m_xm:
-		mediaop(ctxt, o, op, t[3], z);
-		asmand(ctxt, &p->to, &p->from);
-		break;
-
-	case Zr_m_xm_nr:
-		ctxt->rexflag = 0;
-		mediaop(ctxt, o, op, t[3], z);
-		asmand(ctxt, &p->to, &p->from);
-		break;
-
-	case Zr_m_i_xm:
-		mediaop(ctxt, o, op, t[3], z);
-		asmand(ctxt, &p->to, &p->from);
-		*ctxt->andptr++ = p->from.offset;
-		break;
-
-	case Zo_m:
-		*ctxt->andptr++ = op;
-		asmando(ctxt, &p->to, o->op[z+1]);
-		break;
-
-	case Zcallindreg:
-		r = addrel(ctxt->cursym);
-		r->off = p->pc;
-		r->type = R_CALLIND;
-		r->siz = 0;
-		// fallthrough
-	case Zo_m64:
-		*ctxt->andptr++ = op;
-		asmandsz(ctxt, &p->to, o->op[z+1], 0, 1);
-		break;
-
-	case Zm_ibo:
-		*ctxt->andptr++ = op;
-		asmando(ctxt, &p->from, o->op[z+1]);
-		*ctxt->andptr++ = vaddr(ctxt, &p->to, nil);
-		break;
-
-	case Zibo_m:
-		*ctxt->andptr++ = op;
-		asmando(ctxt, &p->to, o->op[z+1]);
-		*ctxt->andptr++ = vaddr(ctxt, &p->from, nil);
-		break;
-
-	case Zibo_m_xm:
-		z = mediaop(ctxt, o, op, t[3], z);
-		asmando(ctxt, &p->to, o->op[z+1]);
-		*ctxt->andptr++ = vaddr(ctxt, &p->from, nil);
-		break;
-
-	case Z_ib:
-	case Zib_:
-		if(t[2] == Zib_)
-			a = &p->from;
-		else
-			a = &p->to;
-		*ctxt->andptr++ = op;
-		*ctxt->andptr++ = vaddr(ctxt, a, nil);
-		break;
-
-	case Zib_rp:
-		ctxt->rexflag |= regrex[p->to.type] & (Rxb|0x40);
-		*ctxt->andptr++ = op + reg[p->to.type];
-		*ctxt->andptr++ = vaddr(ctxt, &p->from, nil);
-		break;
-
-	case Zil_rp:
-		ctxt->rexflag |= regrex[p->to.type] & Rxb;
-		*ctxt->andptr++ = op + reg[p->to.type];
-		if(o->prefix == Pe) {
-			v = vaddr(ctxt, &p->from, nil);
-			*ctxt->andptr++ = v;
-			*ctxt->andptr++ = v>>8;
-		}
-		else
-			relput4(ctxt, p, &p->from);
-		break;
-
-	case Zo_iw:
-		*ctxt->andptr++ = op;
-		if(p->from.type != D_NONE){
-			v = vaddr(ctxt, &p->from, nil);
-			*ctxt->andptr++ = v;
-			*ctxt->andptr++ = v>>8;
-		}
-		break;
-
-	case Ziq_rp:
-		v = vaddr(ctxt, &p->from, &rel);
-		l = 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.type] & Rxb;
-			*ctxt->andptr++ = 0xb8 + reg[p->to.type];
-			if(rel.type != 0) {
-				r = addrel(ctxt->cursym);
-				*r = rel;
-				r->off = p->pc + ctxt->andptr - ctxt->and;
-			}
-			put4(ctxt, v);
-		}else if(l == -1 && (v&((uvlong)1<<31))!=0){	/* sign extend */
-			//p->mark |= 0100;
-			//print("sign: %llux %P\n", v, p);
-			*ctxt->andptr ++ = 0xc7;
-			asmando(ctxt, &p->to, 0);
-			put4(ctxt, v);
-		}else{	/* need all 8 */
-			//print("all: %llux %P\n", v, p);
-			ctxt->rexflag |= regrex[p->to.type] & Rxb;
-			*ctxt->andptr++ = op + reg[p->to.type];
-			if(rel.type != 0) {
-				r = addrel(ctxt->cursym);
-				*r = rel;
-				r->off = p->pc + ctxt->andptr - ctxt->and;
-			}
-			put8(ctxt, v);
-		}
-		break;
-
-	case Zib_rr:
-		*ctxt->andptr++ = op;
-		asmand(ctxt, &p->to, &p->to);
-		*ctxt->andptr++ = vaddr(ctxt, &p->from, nil);
-		break;
-
-	case Z_il:
-	case Zil_:
-		if(t[2] == Zil_)
-			a = &p->from;
-		else
-			a = &p->to;
-		*ctxt->andptr++ = op;
-		if(o->prefix == Pe) {
-			v = vaddr(ctxt, a, nil);
-			*ctxt->andptr++ = v;
-			*ctxt->andptr++ = v>>8;
-		}
-		else
-			relput4(ctxt, p, a);
-		break;
-
-	case Zm_ilo:
-	case Zilo_m:
-		*ctxt->andptr++ = op;
-		if(t[2] == Zilo_m) {
-			a = &p->from;
-			asmando(ctxt, &p->to, o->op[z+1]);
-		} else {
-			a = &p->to;
-			asmando(ctxt, &p->from, o->op[z+1]);
-		}
-		if(o->prefix == Pe) {
-			v = vaddr(ctxt, a, nil);
-			*ctxt->andptr++ = v;
-			*ctxt->andptr++ = v>>8;
-		}
-		else
-			relput4(ctxt, p, a);
-		break;
-
-	case Zil_rr:
-		*ctxt->andptr++ = op;
-		asmand(ctxt, &p->to, &p->to);
-		if(o->prefix == Pe) {
-			v = vaddr(ctxt, &p->from, nil);
-			*ctxt->andptr++ = v;
-			*ctxt->andptr++ = v>>8;
-		}
-		else
-			relput4(ctxt, p, &p->from);
-		break;
-
-	case Z_rp:
-		ctxt->rexflag |= regrex[p->to.type] & (Rxb|0x40);
-		*ctxt->andptr++ = op + reg[p->to.type];
-		break;
-
-	case Zrp_:
-		ctxt->rexflag |= regrex[p->from.type] & (Rxb|0x40);
-		*ctxt->andptr++ = op + reg[p->from.type];
-		break;
-
-	case Zclr:
-		ctxt->rexflag &= ~Pw;
-		*ctxt->andptr++ = op;
-		asmand(ctxt, &p->to, &p->to);
-		break;
-
-	case Zcall:
-		if(p->to.sym == nil) {
-			ctxt->diag("call without target");
-			sysfatal("bad code");
-		}
-		*ctxt->andptr++ = op;
-		r = addrel(ctxt->cursym);
-		r->off = p->pc + ctxt->andptr - ctxt->and;
-		r->sym = p->to.sym;
-		r->add = p->to.offset;
-		r->type = R_CALL;
-		r->siz = 4;
-		put4(ctxt, 0);
-		break;
-
-	case Zbr:
-	case Zjmp:
-	case Zloop:
-		// TODO: jump across functions needs reloc
-		if(p->to.sym != nil) {
-			if(t[2] != Zjmp) {
-				ctxt->diag("branch to ATEXT");
-				sysfatal("bad code");
-			}
-			*ctxt->andptr++ = o->op[z+1];
-			r = addrel(ctxt->cursym);
-			r->off = p->pc + ctxt->andptr - ctxt->and;
-			r->sym = p->to.sym;
-			r->type = 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");
-			sysfatal("bad code");
-		}
-		if(p->back & 1) {
-			v = q->pc - (p->pc + 2);
-			if(v >= -128) {
-				if(p->as == AJCXZL)
-					*ctxt->andptr++ = 0x67;
-				*ctxt->andptr++ = op;
-				*ctxt->andptr++ = v;
-			} else if(t[2] == Zloop) {
-				ctxt->diag("loop too far: %P", p);
-			} else {
-				v -= 5-2;
-				if(t[2] == 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;
-			}
-			break;
-		}
-		
-		// Annotate target; will fill in later.
-		p->forwd = q->comefrom;
-		q->comefrom = p;
-		if(p->back & 2)	{ // short
-			if(p->as == AJCXZL)
-				*ctxt->andptr++ = 0x67;
-			*ctxt->andptr++ = op;
-			*ctxt->andptr++ = 0;
-		} else if(t[2] == Zloop) {
-			ctxt->diag("loop too far: %P", p);
-		} else {
-			if(t[2] == Zbr)
-				*ctxt->andptr++ = 0x0f;
-			*ctxt->andptr++ = o->op[z+1];
-			*ctxt->andptr++ = 0;
-			*ctxt->andptr++ = 0;
-			*ctxt->andptr++ = 0;
-			*ctxt->andptr++ = 0;
-		}
-		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(t[2] == 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;
-		}
-*/
-		break;
-
-	case Zbyte:
-		v = vaddr(ctxt, &p->from, &rel);
-		if(rel.siz != 0) {
-			rel.siz = op;
-			r = addrel(ctxt->cursym);
-			*r = rel;
-			r->off = p->pc + ctxt->andptr - ctxt->and;
-		}
-		*ctxt->andptr++ = v;
-		if(op > 1) {
-			*ctxt->andptr++ = v>>8;
-			if(op > 2) {
-				*ctxt->andptr++ = v>>16;
-				*ctxt->andptr++ = v>>24;
-				if(op > 4) {
-					*ctxt->andptr++ = v>>32;
-					*ctxt->andptr++ = v>>40;
-					*ctxt->andptr++ = v>>48;
-					*ctxt->andptr++ = v>>56;
-				}
-			}
-		}
-		break;
-	}
-	return;
-
-domov:
-	for(mo=ymovtab; mo->as; mo++)
-		if(p->as == mo->as)
-		if(ycover[ft+mo->ft])
-		if(ycover[tt+mo->tt]){
-			t = mo->op;
-			goto mfound;
-		}
-bad:
-	if(p->mode != 64){
-		/*
-		 * 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.
-		 */
-		pp = *p;
-		z = p->from.type;
-		if(z >= D_BP && z <= D_DI) {
-			if(isax(&p->to) || p->to.type == D_NONE) {
-				// We certainly don't want to exchange
-				// with AX if the op is MUL or DIV.
-				*ctxt->andptr++ = 0x87;			/* xchg lhs,bx */
-				asmando(ctxt, &p->from, reg[D_BX]);
-				subreg(&pp, z, D_BX);
-				doasm(ctxt, &pp);
-				*ctxt->andptr++ = 0x87;			/* xchg lhs,bx */
-				asmando(ctxt, &p->from, reg[D_BX]);
-			} else {
-				*ctxt->andptr++ = 0x90 + reg[z];		/* xchg lsh,ax */
-				subreg(&pp, z, D_AX);
-				doasm(ctxt, &pp);
-				*ctxt->andptr++ = 0x90 + reg[z];		/* xchg lsh,ax */
-			}
-			return;
-		}
-		z = p->to.type;
-		if(z >= D_BP && z <= D_DI) {
-			if(isax(&p->from)) {
-				*ctxt->andptr++ = 0x87;			/* xchg rhs,bx */
-				asmando(ctxt, &p->to, reg[D_BX]);
-				subreg(&pp, z, D_BX);
-				doasm(ctxt, &pp);
-				*ctxt->andptr++ = 0x87;			/* xchg rhs,bx */
-				asmando(ctxt, &p->to, reg[D_BX]);
-			} else {
-				*ctxt->andptr++ = 0x90 + reg[z];		/* xchg rsh,ax */
-				subreg(&pp, z, D_AX);
-				doasm(ctxt, &pp);
-				*ctxt->andptr++ = 0x90 + reg[z];		/* xchg rsh,ax */
-			}
-			return;
-		}
-	}
-	ctxt->diag("doasm: notfound from=%ux to=%ux %P", p->from.type, p->to.type, p);
-	return;
-
-mfound:
-	switch(mo->code) {
-	default:
-		ctxt->diag("asmins: unknown mov %d %P", mo->code, p);
-		break;
-
-	case 0:	/* lit */
-		for(z=0; t[z]!=E; z++)
-			*ctxt->andptr++ = t[z];
-		break;
-
-	case 1:	/* r,m */
-		*ctxt->andptr++ = t[0];
-		asmando(ctxt, &p->to, t[1]);
-		break;
-
-	case 2:	/* m,r */
-		*ctxt->andptr++ = t[0];
-		asmando(ctxt, &p->from, t[1]);
-		break;
-
-	case 3:	/* r,m - 2op */
-		*ctxt->andptr++ = t[0];
-		*ctxt->andptr++ = t[1];
-		asmando(ctxt, &p->to, t[2]);
-		ctxt->rexflag |= regrex[p->from.type] & (Rxr|0x40);
-		break;
-
-	case 4:	/* m,r - 2op */
-		*ctxt->andptr++ = t[0];
-		*ctxt->andptr++ = t[1];
-		asmando(ctxt, &p->from, t[2]);
-		ctxt->rexflag |= regrex[p->to.type] & (Rxr|0x40);
-		break;
-
-	case 5:	/* load full pointer, trash heap */
-		if(t[0])
-			*ctxt->andptr++ = t[0];
-		switch(p->to.index) {
-		default:
-			goto bad;
-		case D_DS:
-			*ctxt->andptr++ = 0xc5;
-			break;
-		case D_SS:
-			*ctxt->andptr++ = 0x0f;
-			*ctxt->andptr++ = 0xb2;
-			break;
-		case D_ES:
-			*ctxt->andptr++ = 0xc4;
-			break;
-		case D_FS:
-			*ctxt->andptr++ = 0x0f;
-			*ctxt->andptr++ = 0xb4;
-			break;
-		case D_GS:
-			*ctxt->andptr++ = 0x0f;
-			*ctxt->andptr++ = 0xb5;
-			break;
-		}
-		asmand(ctxt, &p->from, &p->to);
-		break;
-
-	case 6:	/* double shift */
-		if(t[0] == Pw){
-			if(p->mode != 64)
-				ctxt->diag("asmins: illegal 64: %P", p);
-			ctxt->rexflag |= Pw;
-			t++;
-		}else if(t[0] == Pe){
-			*ctxt->andptr++ = Pe;
-			t++;
-		}
-		z = p->from.type;
-		switch(z) {
-		default:
-			goto bad;
-		case D_CONST:
-			*ctxt->andptr++ = 0x0f;
-			*ctxt->andptr++ = t[0];
-			asmandsz(ctxt, &p->to, reg[(int)p->from.index], regrex[(int)p->from.index], 0);
-			*ctxt->andptr++ = p->from.offset;
-			break;
-		case D_CL:
-		case D_CX:
-			*ctxt->andptr++ = 0x0f;
-			*ctxt->andptr++ = t[1];
-			asmandsz(ctxt, &p->to, reg[(int)p->from.index], regrex[(int)p->from.index], 0);
-			break;
-		}
-		break;
-	
-	case 7:	/* mov tls, r */
-		// 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:
-			sysfatal("unknown TLS base location for %s", headstr(ctxt->headtype));
-
-		case Hplan9:
-			if(ctxt->plan9privates == nil)
-				ctxt->plan9privates = linklookup(ctxt, "_privates", 0);
-			memset(&pp.from, 0, sizeof pp.from);
-			pp.from.type = D_EXTERN;
-			pp.from.sym = ctxt->plan9privates;
-			pp.from.offset = 0;
-			pp.from.index = D_NONE;
-			ctxt->rexflag |= Pw;
-			*ctxt->andptr++ = 0x8B;
-			asmand(ctxt, &pp.from, &p->to);
-			break;
-
-		case 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 = D_INDIR+D_NONE;
-			pp.from.offset = 0;
-			pp.from.index = D_NONE;
-			pp.from.scale = 0;
-			ctxt->rexflag |= Pw;
-			*ctxt->andptr++ = 0x64; // FS
-			*ctxt->andptr++ = 0x8B;
-			asmand(ctxt, &pp.from, &p->to);
-			break;
-		
-		case Hwindows:
-			// Windows TLS base is always 0x28(GS).
-			pp.from = p->from;
-			pp.from.type = D_INDIR+D_GS;
-			pp.from.offset = 0x28;
-			pp.from.index = D_NONE;
-			pp.from.scale = 0;
-			ctxt->rexflag |= Pw;
-			*ctxt->andptr++ = 0x65; // GS
-			*ctxt->andptr++ = 0x8B;
-			asmand(ctxt, &pp.from, &p->to);
-			break;
-		}
-		break;
-	}
-}
-
-static uchar naclret[] = {
-	0x5e, // POPL SI
-	// 0x8b, 0x7d, 0x00, // MOVL (BP), DI - catch return to invalid address, for debugging
-	0x83, 0xe6, 0xe0,	// ANDL $~31, SI
-	0x4c, 0x01, 0xfe,	// ADDQ R15, SI
-	0xff, 0xe6, // JMP SI
-};
-
-static uchar naclspfix[] = {
-	0x4c, 0x01, 0xfc, // ADDQ R15, SP
-};
-
-static uchar naclbpfix[] = {
-	0x4c, 0x01, 0xfd, // ADDQ R15, BP
-};
-
-static uchar naclmovs[] = {
-	0x89, 0xf6,	// MOVL SI, SI
-	0x49, 0x8d, 0x34, 0x37,	// LEAQ (R15)(SI*1), SI
-	0x89, 0xff,	// MOVL DI, DI
-	0x49, 0x8d, 0x3c, 0x3f,	// LEAQ (R15)(DI*1), DI
-};
-
-static uchar naclstos[] = {
-	0x89, 0xff,	// MOVL DI, DI
-	0x49, 0x8d, 0x3c, 0x3f,	// LEAQ (R15)(DI*1), DI
-};
-
-static void
-nacltrunc(Link *ctxt, int reg)
-{	
-	if(reg >= D_R8)
-		*ctxt->andptr++ = 0x45;
-	reg = (reg - D_AX) & 7;
-	*ctxt->andptr++ = 0x89;
-	*ctxt->andptr++ = (3<<6) | (reg<<3) | reg;
-}
-
-static void
-asmins(Link *ctxt, Prog *p)
-{
-	int i, n, np, c;
-	uchar *and0;
-	Reloc *r;
-	
-	ctxt->andptr = ctxt->and;
-	ctxt->asmode = p->mode;
-	
-	if(p->as == AUSEFIELD) {
-		r = addrel(ctxt->cursym);
-		r->off = 0;
-		r->siz = 0;
-		r->sym = p->from.sym;
-		r->type = R_USEFIELD;
-		return;
-	}
-	
-	if(ctxt->headtype == Hnacl) {
-		if(p->as == AREP) {
-			ctxt->rep++;
-			return;
-		}
-		if(p->as == AREPN) {
-			ctxt->repn++;
-			return;
-		}
-		if(p->as == ALOCK) {
-			ctxt->lock++;
-			return;
-		}
-		if(p->as != ALEAQ && p->as != ALEAL) {
-			if(p->from.index != D_NONE && p->from.scale > 0)
-				nacltrunc(ctxt, p->from.index);
-			if(p->to.index != D_NONE && p->to.scale > 0)
-				nacltrunc(ctxt, p->to.index);
-		}
-		switch(p->as) {
-		case ARET:
-			memmove(ctxt->andptr, naclret, sizeof naclret);
-			ctxt->andptr += sizeof naclret;
-			return;
-		case ACALL:
-		case AJMP:
-			if(D_AX <= p->to.type && p->to.type <= D_DI) {
-				// ANDL $~31, reg
-				*ctxt->andptr++ = 0x83;
-				*ctxt->andptr++ = 0xe0 | (p->to.type - D_AX);
-				*ctxt->andptr++ = 0xe0;
-				// ADDQ R15, reg
-				*ctxt->andptr++ = 0x4c;
-				*ctxt->andptr++ = 0x01;
-				*ctxt->andptr++ = 0xf8 | (p->to.type - D_AX);
-			}
-			if(D_R8 <= p->to.type && p->to.type <= D_R15) {
-				// ANDL $~31, reg
-				*ctxt->andptr++ = 0x41;
-				*ctxt->andptr++ = 0x83;
-				*ctxt->andptr++ = 0xe0 | (p->to.type - D_R8);
-				*ctxt->andptr++ = 0xe0;
-				// ADDQ R15, reg
-				*ctxt->andptr++ = 0x4d;
-				*ctxt->andptr++ = 0x01;
-				*ctxt->andptr++ = 0xf8 | (p->to.type - D_R8);
-			}
-			break;
-		case AINT:
-			*ctxt->andptr++ = 0xf4;
-			return;
-		case ASCASB:
-		case ASCASW:
-		case ASCASL:
-		case ASCASQ:
-		case ASTOSB:
-		case ASTOSW:
-		case ASTOSL:
-		case ASTOSQ:
-			memmove(ctxt->andptr, naclstos, sizeof naclstos);
-			ctxt->andptr += sizeof naclstos;
-			break;
-		case AMOVSB:
-		case AMOVSW:
-		case AMOVSL:
-		case AMOVSQ:
-			memmove(ctxt->andptr, naclmovs, sizeof naclmovs);
-			ctxt->andptr += sizeof naclmovs;
-			break;
-		}
-		if(ctxt->rep) {
-			*ctxt->andptr++ = 0xf3;
-			ctxt->rep = 0;
-		}
-		if(ctxt->repn) {
-			*ctxt->andptr++ = 0xf2;
-			ctxt->repn = 0;
-		}
-		if(ctxt->lock) {
-			*ctxt->andptr++ = 0xf0;
-			ctxt->lock = 0;
-		}
-	}		
-
-	ctxt->rexflag = 0;
-	and0 = ctxt->andptr;
-	ctxt->asmode = p->mode;
-	doasm(ctxt, p);
-	if(ctxt->rexflag){
-		/*
-		 * as befits the whole approach of the architecture,
-		 * the rex prefix must appear before the first opcode byte
-		 * (and thus after any 66/67/f2/f3/26/2e/3e prefix bytes, but
-		 * before the 0f opcode escape!), or it might be ignored.
-		 * note that the handbook often misleadingly shows 66/f2/f3 in `opcode'.
-		 */
-		if(p->mode != 64)
-			ctxt->diag("asmins: illegal in mode %d: %P", p->mode, p);
-		n = ctxt->andptr - and0;
-		for(np = 0; np < n; np++) {
-			c = and0[np];
-			if(c != 0xf2 && c != 0xf3 && (c < 0x64 || c > 0x67) && c != 0x2e && c != 0x3e && c != 0x26)
-				break;
-		}
-		memmove(and0+np+1, and0+np, n-np);
-		and0[np] = 0x40 | ctxt->rexflag;
-		ctxt->andptr++;
-	}
-	n = ctxt->andptr - ctxt->and;
-	for(i=ctxt->cursym->nr-1; i>=0; i--) {
-		r = ctxt->cursym->r+i;
-		if(r->off < p->pc)
-			break;
-		if(ctxt->rexflag)
-			r->off++;
-		if(r->type == R_PCREL || r->type == R_CALL)
-			r->add -= p->pc + n - (r->off + r->siz);
-	}
-
-	if(ctxt->headtype == Hnacl && p->as != ACMPL && p->as != ACMPQ) {
-		switch(p->to.type) {
-		case D_SP:
-			memmove(ctxt->andptr, naclspfix, sizeof naclspfix);
-			ctxt->andptr += sizeof naclspfix;
-			break;
-		case D_BP:
-			memmove(ctxt->andptr, naclbpfix, sizeof naclbpfix);
-			ctxt->andptr += sizeof naclbpfix;
-			break;
-		}
-	}
-}
diff --git a/src/liblink/asm8.c b/src/liblink/asm8.c
deleted file mode 100644
index b6627d5..0000000
--- a/src/liblink/asm8.c
+++ /dev/null
@@ -1,2785 +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 at 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 at 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.
-
-// Instruction layout.
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <link.h>
-#include "../cmd/8l/8.out.h"
-#include "../runtime/stack.h"
-
-enum
-{
-	MaxAlign = 32,	// max data alignment
-	FuncAlign = 16
-};
-
-typedef	struct	Optab	Optab;
-
-struct	Optab
-{
-	short	as;
-	uchar*	ytab;
-	uchar	prefix;
-	uchar	op[13];
-};
-
-enum
-{
-	Yxxx		= 0,
-	Ynone,
-	Yi0,
-	Yi1,
-	Yi8,
-	Yi32,
-	Yiauto,
-	Yal,
-	Ycl,
-	Yax,
-	Ycx,
-	Yrb,
-	Yrl,
-	Yrf,
-	Yf0,
-	Yrx,
-	Ymb,
-	Yml,
-	Ym,
-	Ybr,
-	Ycol,
-	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,
-
-	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,	/* mmx1,mmx2/mem64,imm8 */
-	Zbyte,
-	Zmov,
-	Zmax,
-
-	Px		= 0,
-	Pe		= 0x66,	/* operand escape */
-	Pm		= 0x0f,	/* 2byte opcode escape */
-	Pq		= 0xff,	/* both escape */
-	Pb		= 0xfe,	/* byte operands */
-	Pf2		= 0xf2,	/* xmm escape 1 */
-	Pf3		= 0xf3,	/* xmm escape 2 */
-};
-
-static	uchar	ycover[Ymax*Ymax];
-static	int	reg[D_NONE];
-static	void	asmins(Link *ctxt, Prog *p);
-
-static uchar	ynone[] =
-{
-	Ynone,	Ynone,	Zlit,	1,
-	0
-};
-static uchar	ytext[] =
-{
-	Ymb,	Yi32,	Zpseudo,1,
-	0
-};
-static uchar	ynop[] =
-{
-	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,
-	0
-};
-static uchar	yfuncdata[] =
-{
-	Yi32,	Ym,	Zpseudo,	0,
-	0
-};
-static uchar	ypcdata[] =
-{
-	Yi32,	Yi32,	Zpseudo,	0,
-	0,
-};
-static uchar	yxorb[] =
-{
-	Yi32,	Yal,	Zib_,	1,
-	Yi32,	Ymb,	Zibo_m,	2,
-	Yrb,	Ymb,	Zr_m,	1,
-	Ymb,	Yrb,	Zm_r,	1,
-	0
-};
-static uchar	yxorl[] =
-{
-	Yi8,	Yml,	Zibo_m,	2,
-	Yi32,	Yax,	Zil_,	1,
-	Yi32,	Yml,	Zilo_m,	2,
-	Yrl,	Yml,	Zr_m,	1,
-	Yml,	Yrl,	Zm_r,	1,
-	0
-};
-static uchar	yaddl[] =
-{
-	Yi8,	Yml,	Zibo_m,	2,
-	Yi32,	Yax,	Zil_,	1,
-	Yi32,	Yml,	Zilo_m,	2,
-	Yrl,	Yml,	Zr_m,	1,
-	Yml,	Yrl,	Zm_r,	1,
-	0
-};
-static uchar	yincb[] =
-{
-	Ynone,	Ymb,	Zo_m,	2,
-	0
-};
-static uchar	yincl[] =
-{
-	Ynone,	Yrl,	Z_rp,	1,
-	Ynone,	Yml,	Zo_m,	2,
-	0
-};
-static uchar	ycmpb[] =
-{
-	Yal,	Yi32,	Z_ib,	1,
-	Ymb,	Yi32,	Zm_ibo,	2,
-	Ymb,	Yrb,	Zm_r,	1,
-	Yrb,	Ymb,	Zr_m,	1,
-	0
-};
-static uchar	ycmpl[] =
-{
-	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,
-	0
-};
-static uchar	yshb[] =
-{
-	Yi1,	Ymb,	Zo_m,	2,
-	Yi32,	Ymb,	Zibo_m,	2,
-	Ycx,	Ymb,	Zo_m,	2,
-	0
-};
-static uchar	yshl[] =
-{
-	Yi1,	Yml,	Zo_m,	2,
-	Yi32,	Yml,	Zibo_m,	2,
-	Ycl,	Yml,	Zo_m,	2,
-	Ycx,	Yml,	Zo_m,	2,
-	0
-};
-static uchar	ytestb[] =
-{
-	Yi32,	Yal,	Zib_,	1,
-	Yi32,	Ymb,	Zibo_m,	2,
-	Yrb,	Ymb,	Zr_m,	1,
-	Ymb,	Yrb,	Zm_r,	1,
-	0
-};
-static uchar	ytestl[] =
-{
-	Yi32,	Yax,	Zil_,	1,
-	Yi32,	Yml,	Zilo_m,	2,
-	Yrl,	Yml,	Zr_m,	1,
-	Yml,	Yrl,	Zm_r,	1,
-	0
-};
-static uchar	ymovb[] =
-{
-	Yrb,	Ymb,	Zr_m,	1,
-	Ymb,	Yrb,	Zm_r,	1,
-	Yi32,	Yrb,	Zib_rp,	1,
-	Yi32,	Ymb,	Zibo_m,	2,
-	0
-};
-static uchar	ymovw[] =
-{
-	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,
-	0
-};
-static uchar	ymovl[] =
-{
-	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,
-	0
-};
-static uchar	ymovq[] =
-{
-	Yml,	Yxr,	Zm_r_xm,	2,
-	0
-};
-static uchar	ym_rl[] =
-{
-	Ym,	Yrl,	Zm_r,	1,
-	0
-};
-static uchar	yrl_m[] =
-{
-	Yrl,	Ym,	Zr_m,	1,
-	0
-};
-static uchar	ymb_rl[] =
-{
-	Ymb,	Yrl,	Zm_r,	1,
-	0
-};
-static uchar	yml_rl[] =
-{
-	Yml,	Yrl,	Zm_r,	1,
-	0
-};
-static uchar	yrb_mb[] =
-{
-	Yrb,	Ymb,	Zr_m,	1,
-	0
-};
-static uchar	yrl_ml[] =
-{
-	Yrl,	Yml,	Zr_m,	1,
-	0
-};
-static uchar	yml_mb[] =
-{
-	Yrb,	Ymb,	Zr_m,	1,
-	Ymb,	Yrb,	Zm_r,	1,
-	0
-};
-static uchar	yxchg[] =
-{
-	Yax,	Yrl,	Z_rp,	1,
-	Yrl,	Yax,	Zrp_,	1,
-	Yrl,	Yml,	Zr_m,	1,
-	Yml,	Yrl,	Zm_r,	1,
-	0
-};
-static uchar	ydivl[] =
-{
-	Yml,	Ynone,	Zm_o,	2,
-	0
-};
-static uchar	ydivb[] =
-{
-	Ymb,	Ynone,	Zm_o,	2,
-	0
-};
-static uchar	yimul[] =
-{
-	Yml,	Ynone,	Zm_o,	2,
-	Yi8,	Yrl,	Zib_rr,	1,
-	Yi32,	Yrl,	Zil_rr,	1,
-	0
-};
-static uchar	ybyte[] =
-{
-	Yi32,	Ynone,	Zbyte,	1,
-	0
-};
-static uchar	yin[] =
-{
-	Yi32,	Ynone,	Zib_,	1,
-	Ynone,	Ynone,	Zlit,	1,
-	0
-};
-static uchar	yint[] =
-{
-	Yi32,	Ynone,	Zib_,	1,
-	0
-};
-static uchar	ypushl[] =
-{
-	Yrl,	Ynone,	Zrp_,	1,
-	Ym,	Ynone,	Zm_o,	2,
-	Yi8,	Ynone,	Zib_,	1,
-	Yi32,	Ynone,	Zil_,	1,
-	0
-};
-static uchar	ypopl[] =
-{
-	Ynone,	Yrl,	Z_rp,	1,
-	Ynone,	Ym,	Zo_m,	2,
-	0
-};
-static uchar	ybswap[] =
-{
-	Ynone,	Yrl,	Z_rp,	1,
-	0,
-};
-static uchar	yscond[] =
-{
-	Ynone,	Ymb,	Zo_m,	2,
-	0
-};
-static uchar	yjcond[] =
-{
-	Ynone,	Ybr,	Zbr,	0,
-	Yi0,	Ybr,	Zbr,	0,
-	Yi1,	Ybr,	Zbr,	1,
-	0
-};
-static uchar	yloop[] =
-{
-	Ynone,	Ybr,	Zloop,	1,
-	0
-};
-static uchar	ycall[] =
-{
-	Ynone,	Yml,	Zcallindreg,	0,
-	Yrx,	Yrx,	Zcallindreg,	2,
-	Ynone,	Ycol,	Zcallind,	2,
-	Ynone,	Ybr,	Zcall,	0,
-	Ynone,	Yi32,	Zcallcon,	1,
-	0
-};
-static uchar	yduff[] =
-{
-	Ynone,	Yi32,	Zcall,	1,
-	0
-};
-static uchar	yjmp[] =
-{
-	Ynone,	Yml,	Zo_m,	2,
-	Ynone,	Ybr,	Zjmp,	0,
-	Ynone,	Yi32,	Zjmpcon,	1,
-	0
-};
-
-static uchar	yfmvd[] =
-{
-	Ym,	Yf0,	Zm_o,	2,
-	Yf0,	Ym,	Zo_m,	2,
-	Yrf,	Yf0,	Zm_o,	2,
-	Yf0,	Yrf,	Zo_m,	2,
-	0
-};
-static uchar	yfmvdp[] =
-{
-	Yf0,	Ym,	Zo_m,	2,
-	Yf0,	Yrf,	Zo_m,	2,
-	0
-};
-static uchar	yfmvf[] =
-{
-	Ym,	Yf0,	Zm_o,	2,
-	Yf0,	Ym,	Zo_m,	2,
-	0
-};
-static uchar	yfmvx[] =
-{
-	Ym,	Yf0,	Zm_o,	2,
-	0
-};
-static uchar	yfmvp[] =
-{
-	Yf0,	Ym,	Zo_m,	2,
-	0
-};
-static uchar	yfcmv[] =
-{
-	Yrf,	Yf0,	Zm_o,	2,
-	0
-};
-static uchar	yfadd[] =
-{
-	Ym,	Yf0,	Zm_o,	2,
-	Yrf,	Yf0,	Zm_o,	2,
-	Yf0,	Yrf,	Zo_m,	2,
-	0
-};
-static uchar	yfaddp[] =
-{
-	Yf0,	Yrf,	Zo_m,	2,
-	0
-};
-static uchar	yfxch[] =
-{
-	Yf0,	Yrf,	Zo_m,	2,
-	Yrf,	Yf0,	Zm_o,	2,
-	0
-};
-static uchar	ycompp[] =
-{
-	Yf0,	Yrf,	Zo_m,	2,	/* botch is really f0,f1 */
-	0
-};
-static uchar	ystsw[] =
-{
-	Ynone,	Ym,	Zo_m,	2,
-	Ynone,	Yax,	Zlit,	1,
-	0
-};
-static uchar	ystcw[] =
-{
-	Ynone,	Ym,	Zo_m,	2,
-	Ym,	Ynone,	Zm_o,	2,
-	0
-};
-static uchar	ysvrs[] =
-{
-	Ynone,	Ym,	Zo_m,	2,
-	Ym,	Ynone,	Zm_o,	2,
-	0
-};
-static uchar	ymskb[] =
-{
-	Yxr,	Yrl,	Zm_r_xm,	2,
-	Ymr,	Yrl,	Zm_r_xm,	1,
-	0
-};
-static uchar	yxm[] = 
-{
-	Yxm,	Yxr,	Zm_r_xm,	1,
-	0
-};
-static uchar	yxcvm1[] = 
-{
-	Yxm,	Yxr,	Zm_r_xm,	2,
-	Yxm,	Ymr,	Zm_r_xm,	2,
-	0
-};
-static uchar	yxcvm2[] =
-{
-	Yxm,	Yxr,	Zm_r_xm,	2,
-	Ymm,	Yxr,	Zm_r_xm,	2,
-	0
-};
-static uchar	yxmq[] = 
-{
-	Yxm,	Yxr,	Zm_r_xm,	2,
-	0
-};
-static uchar	yxr[] = 
-{
-	Yxr,	Yxr,	Zm_r_xm,	1,
-	0
-};
-static uchar	yxr_ml[] =
-{
-	Yxr,	Yml,	Zr_m_xm,	1,
-	0
-};
-static uchar	yxcmp[] =
-{
-	Yxm,	Yxr, Zm_r_xm,	1,
-	0
-};
-static uchar	yxcmpi[] =
-{
-	Yxm,	Yxr, Zm_r_i_xm,	2,
-	0
-};
-static uchar	yxmov[] =
-{
-	Yxm,	Yxr,	Zm_r_xm,	1,
-	Yxr,	Yxm,	Zr_m_xm,	1,
-	0
-};
-static uchar	yxcvfl[] = 
-{
-	Yxm,	Yrl,	Zm_r_xm,	1,
-	0
-};
-static uchar	yxcvlf[] =
-{
-	Yml,	Yxr,	Zm_r_xm,	1,
-	0
-};
-/*
-static uchar	yxcvfq[] = 
-{
-	Yxm,	Yrl,	Zm_r_xm,	2,
-	0
-};
-static uchar	yxcvqf[] =
-{
-	Yml,	Yxr,	Zm_r_xm,	2,
-	0
-};
-*/
-static uchar	yxrrl[] =
-{
-	Yxr,	Yrl,	Zm_r,	1,
-	0
-};
-static uchar	yprefetch[] =
-{
-	Ym,	Ynone,	Zm_o,	2,
-	0,
-};
-static uchar	yaes[] =
-{
-	Yxm,	Yxr,	Zlitm_r,	2,
-	0
-};
-static uchar	yinsrd[] =
-{
-	Yml,	Yxr,	Zibm_r,	2,
-	0
-};
-static uchar	ymshufb[] =
-{
-	Yxm,	Yxr,	Zm2_r,	2,
-	0
-};
-
-static Optab optab[] =
-/*	as, ytab, andproto, opcode */
-{
-	{ AXXX },
-	{ AAAA,		ynone,	Px, {0x37} },
-	{ AAAD,		ynone,	Px, {0xd5,0x0a} },
-	{ AAAM,		ynone,	Px, {0xd4,0x0a} },
-	{ AAAS,		ynone,	Px, {0x3f} },
-	{ AADCB,	yxorb,	Pb, {0x14,0x80,(02),0x10,0x10} },
-	{ AADCL,	yxorl,	Px, {0x83,(02),0x15,0x81,(02),0x11,0x13} },
-	{ AADCW,	yxorl,	Pe, {0x83,(02),0x15,0x81,(02),0x11,0x13} },
-	{ AADDB,	yxorb,	Px, {0x04,0x80,(00),0x00,0x02} },
-	{ AADDL,	yaddl,	Px, {0x83,(00),0x05,0x81,(00),0x01,0x03} },
-	{ AADDW,	yaddl,	Pe, {0x83,(00),0x05,0x81,(00),0x01,0x03} },
-	{ AADJSP },
-	{ AANDB,	yxorb,	Pb, {0x24,0x80,(04),0x20,0x22} },
-	{ AANDL,	yxorl,	Px, {0x83,(04),0x25,0x81,(04),0x21,0x23} },
-	{ AANDW,	yxorl,	Pe, {0x83,(04),0x25,0x81,(04),0x21,0x23} },
-	{ AARPL,	yrl_ml,	Px, {0x63} },
-	{ ABOUNDL,	yrl_m,	Px, {0x62} },
-	{ ABOUNDW,	yrl_m,	Pe, {0x62} },
-	{ ABSFL,	yml_rl,	Pm, {0xbc} },
-	{ ABSFW,	yml_rl,	Pq, {0xbc} },
-	{ ABSRL,	yml_rl,	Pm, {0xbd} },
-	{ ABSRW,	yml_rl,	Pq, {0xbd} },
-	{ ABTL,		yml_rl,	Pm, {0xa3} },
-	{ ABTW,		yml_rl,	Pq, {0xa3} },
-	{ ABTCL,	yml_rl,	Pm, {0xbb} },
-	{ ABTCW,	yml_rl,	Pq, {0xbb} },
-	{ ABTRL,	yml_rl,	Pm, {0xb3} },
-	{ ABTRW,	yml_rl,	Pq, {0xb3} },
-	{ ABTSL,	yml_rl,	Pm, {0xab} },
-	{ ABTSW,	yml_rl,	Pq, {0xab} },
-	{ ABYTE,	ybyte,	Px, {1} },
-	{ ACALL,	ycall,	Px, {0xff,(02),0xff,(0x15),0xe8} },
-	{ ACLC,		ynone,	Px, {0xf8} },
-	{ ACLD,		ynone,	Px, {0xfc} },
-	{ ACLI,		ynone,	Px, {0xfa} },
-	{ ACLTS,	ynone,	Pm, {0x06} },
-	{ ACMC,		ynone,	Px, {0xf5} },
-	{ ACMPB,	ycmpb,	Pb, {0x3c,0x80,(07),0x38,0x3a} },
-	{ ACMPL,	ycmpl,	Px, {0x83,(07),0x3d,0x81,(07),0x39,0x3b} },
-	{ ACMPW,	ycmpl,	Pe, {0x83,(07),0x3d,0x81,(07),0x39,0x3b} },
-	{ ACMPSB,	ynone,	Pb, {0xa6} },
-	{ ACMPSL,	ynone,	Px, {0xa7} },
-	{ ACMPSW,	ynone,	Pe, {0xa7} },
-	{ ADAA,		ynone,	Px, {0x27} },
-	{ ADAS,		ynone,	Px, {0x2f} },
-	{ ADATA },
-	{ ADECB,	yincb,	Pb, {0xfe,(01)} },
-	{ ADECL,	yincl,	Px, {0x48,0xff,(01)} },
-	{ ADECW,	yincl,	Pe, {0x48,0xff,(01)} },
-	{ ADIVB,	ydivb,	Pb, {0xf6,(06)} },
-	{ ADIVL,	ydivl,	Px, {0xf7,(06)} },
-	{ ADIVW,	ydivl,	Pe, {0xf7,(06)} },
-	{ AENTER },				/* botch */
-	{ AGLOBL },
-	{ AGOK },
-	{ AHISTORY },
-	{ AHLT,		ynone,	Px, {0xf4} },
-	{ AIDIVB,	ydivb,	Pb, {0xf6,(07)} },
-	{ AIDIVL,	ydivl,	Px, {0xf7,(07)} },
-	{ AIDIVW,	ydivl,	Pe, {0xf7,(07)} },
-	{ AIMULB,	ydivb,	Pb, {0xf6,(05)} },
-	{ AIMULL,	yimul,	Px, {0xf7,(05),0x6b,0x69} },
-	{ AIMULW,	yimul,	Pe, {0xf7,(05),0x6b,0x69} },
-	{ AINB,		yin,	Pb, {0xe4,0xec} },
-	{ AINL,		yin,	Px, {0xe5,0xed} },
-	{ AINW,		yin,	Pe, {0xe5,0xed} },
-	{ AINCB,	yincb,	Pb, {0xfe,(00)} },
-	{ AINCL,	yincl,	Px, {0x40,0xff,(00)} },
-	{ AINCW,	yincl,	Pe, {0x40,0xff,(00)} },
-	{ AINSB,	ynone,	Pb, {0x6c} },
-	{ AINSL,	ynone,	Px, {0x6d} },
-	{ AINSW,	ynone,	Pe, {0x6d} },
-	{ AINT,		yint,	Px, {0xcd} },
-	{ AINTO,	ynone,	Px, {0xce} },
-	{ AIRETL,	ynone,	Px, {0xcf} },
-	{ AIRETW,	ynone,	Pe, {0xcf} },
-	{ AJCC,		yjcond,	Px, {0x73,0x83,(00)} },
-	{ AJCS,		yjcond,	Px, {0x72,0x82} },
-	{ AJCXZL,	yloop,	Px, {0xe3} },
-	{ AJCXZW,	yloop,	Px, {0xe3} },
-	{ AJEQ,		yjcond,	Px, {0x74,0x84} },
-	{ AJGE,		yjcond,	Px, {0x7d,0x8d} },
-	{ AJGT,		yjcond,	Px, {0x7f,0x8f} },
-	{ AJHI,		yjcond,	Px, {0x77,0x87} },
-	{ AJLE,		yjcond,	Px, {0x7e,0x8e} },
-	{ AJLS,		yjcond,	Px, {0x76,0x86} },
-	{ AJLT,		yjcond,	Px, {0x7c,0x8c} },
-	{ AJMI,		yjcond,	Px, {0x78,0x88} },
-	{ AJMP,		yjmp,	Px, {0xff,(04),0xeb,0xe9} },
-	{ AJNE,		yjcond,	Px, {0x75,0x85} },
-	{ AJOC,		yjcond,	Px, {0x71,0x81,(00)} },
-	{ AJOS,		yjcond,	Px, {0x70,0x80,(00)} },
-	{ AJPC,		yjcond,	Px, {0x7b,0x8b} },
-	{ AJPL,		yjcond,	Px, {0x79,0x89} },
-	{ AJPS,		yjcond,	Px, {0x7a,0x8a} },
-	{ ALAHF,	ynone,	Px, {0x9f} },
-	{ ALARL,	yml_rl,	Pm, {0x02} },
-	{ ALARW,	yml_rl,	Pq, {0x02} },
-	{ ALEAL,	ym_rl,	Px, {0x8d} },
-	{ ALEAW,	ym_rl,	Pe, {0x8d} },
-	{ ALEAVEL,	ynone,	Px, {0xc9} },
-	{ ALEAVEW,	ynone,	Pe, {0xc9} },
-	{ ALOCK,	ynone,	Px, {0xf0} },
-	{ ALODSB,	ynone,	Pb, {0xac} },
-	{ ALODSL,	ynone,	Px, {0xad} },
-	{ ALODSW,	ynone,	Pe, {0xad} },
-	{ ALONG,	ybyte,	Px, {4} },
-	{ ALOOP,	yloop,	Px, {0xe2} },
-	{ ALOOPEQ,	yloop,	Px, {0xe1} },
-	{ ALOOPNE,	yloop,	Px, {0xe0} },
-	{ ALSLL,	yml_rl,	Pm, {0x03 } },
-	{ ALSLW,	yml_rl,	Pq, {0x03 } },
-	{ AMOVB,	ymovb,	Pb, {0x88,0x8a,0xb0,0xc6,(00)} },
-	{ AMOVL,	ymovl,	Px, {0x89,0x8b,0x31,0x83,(04),0xb8,0xc7,(00),Pe,0x6e,Pe,0x7e,0} },
-	{ AMOVW,	ymovw,	Pe, {0x89,0x8b,0x31,0x83,(04),0xb8,0xc7,(00),0} },
-	{ AMOVQ,	ymovq,	Pf3, {0x7e} },
-	{ AMOVBLSX,	ymb_rl,	Pm, {0xbe} },
-	{ AMOVBLZX,	ymb_rl,	Pm, {0xb6} },
-	{ AMOVBWSX,	ymb_rl,	Pq, {0xbe} },
-	{ AMOVBWZX,	ymb_rl,	Pq, {0xb6} },
-	{ AMOVWLSX,	yml_rl,	Pm, {0xbf} },
-	{ AMOVWLZX,	yml_rl,	Pm, {0xb7} },
-	{ AMOVSB,	ynone,	Pb, {0xa4} },
-	{ AMOVSL,	ynone,	Px, {0xa5} },
-	{ AMOVSW,	ynone,	Pe, {0xa5} },
-	{ AMULB,	ydivb,	Pb, {0xf6,(04)} },
-	{ AMULL,	ydivl,	Px, {0xf7,(04)} },
-	{ AMULW,	ydivl,	Pe, {0xf7,(04)} },
-	{ ANAME },
-	{ ANEGB,	yscond,	Px, {0xf6,(03)} },
-	{ ANEGL,	yscond,	Px, {0xf7,(03)} },
-	{ ANEGW,	yscond,	Pe, {0xf7,(03)} },
-	{ ANOP,		ynop,	Px, {0,0} },
-	{ ANOTB,	yscond,	Px, {0xf6,(02)} },
-	{ ANOTL,	yscond,	Px, {0xf7,(02)} },
-	{ ANOTW,	yscond,	Pe, {0xf7,(02)} },
-	{ AORB,		yxorb,	Pb, {0x0c,0x80,(01),0x08,0x0a} },
-	{ AORL,		yxorl,	Px, {0x83,(01),0x0d,0x81,(01),0x09,0x0b} },
-	{ AORW,		yxorl,	Pe, {0x83,(01),0x0d,0x81,(01),0x09,0x0b} },
-	{ AOUTB,	yin,	Pb, {0xe6,0xee} },
-	{ AOUTL,	yin,	Px, {0xe7,0xef} },
-	{ AOUTW,	yin,	Pe, {0xe7,0xef} },
-	{ AOUTSB,	ynone,	Pb, {0x6e} },
-	{ AOUTSL,	ynone,	Px, {0x6f} },
-	{ AOUTSW,	ynone,	Pe, {0x6f} },
-	{ APAUSE,	ynone,	Px, {0xf3,0x90} },
-	{ APOPAL,	ynone,	Px, {0x61} },
-	{ APOPAW,	ynone,	Pe, {0x61} },
-	{ APOPFL,	ynone,	Px, {0x9d} },
-	{ APOPFW,	ynone,	Pe, {0x9d} },
-	{ APOPL,	ypopl,	Px, {0x58,0x8f,(00)} },
-	{ APOPW,	ypopl,	Pe, {0x58,0x8f,(00)} },
-	{ APUSHAL,	ynone,	Px, {0x60} },
-	{ APUSHAW,	ynone,	Pe, {0x60} },
-	{ APUSHFL,	ynone,	Px, {0x9c} },
-	{ APUSHFW,	ynone,	Pe, {0x9c} },
-	{ APUSHL,	ypushl,	Px, {0x50,0xff,(06),0x6a,0x68} },
-	{ APUSHW,	ypushl,	Pe, {0x50,0xff,(06),0x6a,0x68} },
-	{ ARCLB,	yshb,	Pb, {0xd0,(02),0xc0,(02),0xd2,(02)} },
-	{ ARCLL,	yshl,	Px, {0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02)} },
-	{ ARCLW,	yshl,	Pe, {0xd1,(02),0xc1,(02),0xd3,(02),0xd3,(02)} },
-	{ ARCRB,	yshb,	Pb, {0xd0,(03),0xc0,(03),0xd2,(03)} },
-	{ ARCRL,	yshl,	Px, {0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03)} },
-	{ ARCRW,	yshl,	Pe, {0xd1,(03),0xc1,(03),0xd3,(03),0xd3,(03)} },
-	{ AREP,		ynone,	Px, {0xf3} },
-	{ AREPN,	ynone,	Px, {0xf2} },
-	{ ARET,		ynone,	Px, {0xc3} },
-	{ AROLB,	yshb,	Pb, {0xd0,(00),0xc0,(00),0xd2,(00)} },
-	{ AROLL,	yshl,	Px, {0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00)} },
-	{ AROLW,	yshl,	Pe, {0xd1,(00),0xc1,(00),0xd3,(00),0xd3,(00)} },
-	{ ARORB,	yshb,	Pb, {0xd0,(01),0xc0,(01),0xd2,(01)} },
-	{ ARORL,	yshl,	Px, {0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01)} },
-	{ ARORW,	yshl,	Pe, {0xd1,(01),0xc1,(01),0xd3,(01),0xd3,(01)} },
-	{ ASAHF,	ynone,	Px, {0x9e} },
-	{ ASALB,	yshb,	Pb, {0xd0,(04),0xc0,(04),0xd2,(04)} },
-	{ ASALL,	yshl,	Px, {0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04)} },
-	{ ASALW,	yshl,	Pe, {0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04)} },
-	{ ASARB,	yshb,	Pb, {0xd0,(07),0xc0,(07),0xd2,(07)} },
-	{ ASARL,	yshl,	Px, {0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07)} },
-	{ ASARW,	yshl,	Pe, {0xd1,(07),0xc1,(07),0xd3,(07),0xd3,(07)} },
-	{ ASBBB,	yxorb,	Pb, {0x1c,0x80,(03),0x18,0x1a} },
-	{ ASBBL,	yxorl,	Px, {0x83,(03),0x1d,0x81,(03),0x19,0x1b} },
-	{ ASBBW,	yxorl,	Pe, {0x83,(03),0x1d,0x81,(03),0x19,0x1b} },
-	{ ASCASB,	ynone,	Pb, {0xae} },
-	{ ASCASL,	ynone,	Px, {0xaf} },
-	{ ASCASW,	ynone,	Pe, {0xaf} },
-	{ ASETCC,	yscond,	Pm, {0x93,(00)} },
-	{ ASETCS,	yscond,	Pm, {0x92,(00)} },
-	{ ASETEQ,	yscond,	Pm, {0x94,(00)} },
-	{ ASETGE,	yscond,	Pm, {0x9d,(00)} },
-	{ ASETGT,	yscond,	Pm, {0x9f,(00)} },
-	{ ASETHI,	yscond,	Pm, {0x97,(00)} },
-	{ ASETLE,	yscond,	Pm, {0x9e,(00)} },
-	{ ASETLS,	yscond,	Pm, {0x96,(00)} },
-	{ ASETLT,	yscond,	Pm, {0x9c,(00)} },
-	{ ASETMI,	yscond,	Pm, {0x98,(00)} },
-	{ ASETNE,	yscond,	Pm, {0x95,(00)} },
-	{ ASETOC,	yscond,	Pm, {0x91,(00)} },
-	{ ASETOS,	yscond,	Pm, {0x90,(00)} },
-	{ ASETPC,	yscond,	Pm, {0x9b,(00)} },
-	{ ASETPL,	yscond,	Pm, {0x99,(00)} },
-	{ ASETPS,	yscond,	Pm, {0x9a,(00)} },
-	{ ACDQ,		ynone,	Px, {0x99} },
-	{ ACWD,		ynone,	Pe, {0x99} },
-	{ ASHLB,	yshb,	Pb, {0xd0,(04),0xc0,(04),0xd2,(04)} },
-	{ ASHLL,	yshl,	Px, {0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04)} },
-	{ ASHLW,	yshl,	Pe, {0xd1,(04),0xc1,(04),0xd3,(04),0xd3,(04)} },
-	{ ASHRB,	yshb,	Pb, {0xd0,(05),0xc0,(05),0xd2,(05)} },
-	{ ASHRL,	yshl,	Px, {0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05)} },
-	{ ASHRW,	yshl,	Pe, {0xd1,(05),0xc1,(05),0xd3,(05),0xd3,(05)} },
-	{ ASTC,		ynone,	Px, {0xf9} },
-	{ ASTD,		ynone,	Px, {0xfd} },
-	{ ASTI,		ynone,	Px, {0xfb} },
-	{ ASTOSB,	ynone,	Pb, {0xaa} },
-	{ ASTOSL,	ynone,	Px, {0xab} },
-	{ ASTOSW,	ynone,	Pe, {0xab} },
-	{ ASUBB,	yxorb,	Pb, {0x2c,0x80,(05),0x28,0x2a} },
-	{ ASUBL,	yaddl,	Px, {0x83,(05),0x2d,0x81,(05),0x29,0x2b} },
-	{ ASUBW,	yaddl,	Pe, {0x83,(05),0x2d,0x81,(05),0x29,0x2b} },
-	{ ASYSCALL,	ynone,	Px, {0xcd,100} },
-	{ ATESTB,	ytestb,	Pb, {0xa8,0xf6,(00),0x84,0x84} },
-	{ ATESTL,	ytestl,	Px, {0xa9,0xf7,(00),0x85,0x85} },
-	{ ATESTW,	ytestl,	Pe, {0xa9,0xf7,(00),0x85,0x85} },
-	{ ATEXT,	ytext,	Px },
-	{ AVERR,	ydivl,	Pm, {0x00,(04)} },
-	{ AVERW,	ydivl,	Pm, {0x00,(05)} },
-	{ AWAIT,	ynone,	Px, {0x9b} },
-	{ AWORD,	ybyte,	Px, {2} },
-	{ AXCHGB,	yml_mb,	Pb, {0x86,0x86} },
-	{ AXCHGL,	yxchg,	Px, {0x90,0x90,0x87,0x87} },
-	{ AXCHGW,	yxchg,	Pe, {0x90,0x90,0x87,0x87} },
-	{ AXLAT,	ynone,	Px, {0xd7} },
-	{ AXORB,	yxorb,	Pb, {0x34,0x80,(06),0x30,0x32} },
-	{ AXORL,	yxorl,	Px, {0x83,(06),0x35,0x81,(06),0x31,0x33} },
-	{ AXORW,	yxorl,	Pe, {0x83,(06),0x35,0x81,(06),0x31,0x33} },
-
-	{ AFMOVB,	yfmvx,	Px, {0xdf,(04)} },
-	{ AFMOVBP,	yfmvp,	Px, {0xdf,(06)} },
-	{ AFMOVD,	yfmvd,	Px, {0xdd,(00),0xdd,(02),0xd9,(00),0xdd,(02)} },
-	{ AFMOVDP,	yfmvdp,	Px, {0xdd,(03),0xdd,(03)} },
-	{ AFMOVF,	yfmvf,	Px, {0xd9,(00),0xd9,(02)} },
-	{ AFMOVFP,	yfmvp,	Px, {0xd9,(03)} },
-	{ AFMOVL,	yfmvf,	Px, {0xdb,(00),0xdb,(02)} },
-	{ AFMOVLP,	yfmvp,	Px, {0xdb,(03)} },
-	{ AFMOVV,	yfmvx,	Px, {0xdf,(05)} },
-	{ AFMOVVP,	yfmvp,	Px, {0xdf,(07)} },
-	{ AFMOVW,	yfmvf,	Px, {0xdf,(00),0xdf,(02)} },
-	{ AFMOVWP,	yfmvp,	Px, {0xdf,(03)} },
-	{ AFMOVX,	yfmvx,	Px, {0xdb,(05)} },
-	{ AFMOVXP,	yfmvp,	Px, {0xdb,(07)} },
-
-	{ AFCOMB },
-	{ AFCOMBP },
-	{ AFCOMD,	yfadd,	Px, {0xdc,(02),0xd8,(02),0xdc,(02)} },	/* botch */
-	{ AFCOMDP,	yfadd,	Px, {0xdc,(03),0xd8,(03),0xdc,(03)} },	/* botch */
-	{ AFCOMDPP,	ycompp,	Px, {0xde,(03)} },
-	{ AFCOMF,	yfmvx,	Px, {0xd8,(02)} },
-	{ AFCOMFP,	yfmvx,	Px, {0xd8,(03)} },
-	{ AFCOMI,	yfmvx,	Px, {0xdb,(06)} },
-	{ AFCOMIP,	yfmvx,	Px, {0xdf,(06)} },
-	{ AFCOML,	yfmvx,	Px, {0xda,(02)} },
-	{ AFCOMLP,	yfmvx,	Px, {0xda,(03)} },
-	{ AFCOMW,	yfmvx,	Px, {0xde,(02)} },
-	{ AFCOMWP,	yfmvx,	Px, {0xde,(03)} },
-
-	{ AFUCOM,	ycompp,	Px, {0xdd,(04)} },
-	{ AFUCOMI,	ycompp,	Px, {0xdb,(05)} },
-	{ AFUCOMIP,	ycompp,	Px, {0xdf,(05)} },
-	{ AFUCOMP,	ycompp,	Px, {0xdd,(05)} },
-	{ AFUCOMPP,	ycompp,	Px, {0xda,(13)} },
-
-	{ AFADDDP,	yfaddp,	Px, {0xde,(00)} },
-	{ AFADDW,	yfmvx,	Px, {0xde,(00)} },
-	{ AFADDL,	yfmvx,	Px, {0xda,(00)} },
-	{ AFADDF,	yfmvx,	Px, {0xd8,(00)} },
-	{ AFADDD,	yfadd,	Px, {0xdc,(00),0xd8,(00),0xdc,(00)} },
-
-	{ AFMULDP,	yfaddp,	Px, {0xde,(01)} },
-	{ AFMULW,	yfmvx,	Px, {0xde,(01)} },
-	{ AFMULL,	yfmvx,	Px, {0xda,(01)} },
-	{ AFMULF,	yfmvx,	Px, {0xd8,(01)} },
-	{ AFMULD,	yfadd,	Px, {0xdc,(01),0xd8,(01),0xdc,(01)} },
-
-	{ AFSUBDP,	yfaddp,	Px, {0xde,(05)} },
-	{ AFSUBW,	yfmvx,	Px, {0xde,(04)} },
-	{ AFSUBL,	yfmvx,	Px, {0xda,(04)} },
-	{ AFSUBF,	yfmvx,	Px, {0xd8,(04)} },
-	{ AFSUBD,	yfadd,	Px, {0xdc,(04),0xd8,(04),0xdc,(05)} },
-
-	{ AFSUBRDP,	yfaddp,	Px, {0xde,(04)} },
-	{ AFSUBRW,	yfmvx,	Px, {0xde,(05)} },
-	{ AFSUBRL,	yfmvx,	Px, {0xda,(05)} },
-	{ AFSUBRF,	yfmvx,	Px, {0xd8,(05)} },
-	{ AFSUBRD,	yfadd,	Px, {0xdc,(05),0xd8,(05),0xdc,(04)} },
-
-	{ AFDIVDP,	yfaddp,	Px, {0xde,(07)} },
-	{ AFDIVW,	yfmvx,	Px, {0xde,(06)} },
-	{ AFDIVL,	yfmvx,	Px, {0xda,(06)} },
-	{ AFDIVF,	yfmvx,	Px, {0xd8,(06)} },
-	{ AFDIVD,	yfadd,	Px, {0xdc,(06),0xd8,(06),0xdc,(07)} },
-
-	{ AFDIVRDP,	yfaddp,	Px, {0xde,(06)} },
-	{ AFDIVRW,	yfmvx,	Px, {0xde,(07)} },
-	{ AFDIVRL,	yfmvx,	Px, {0xda,(07)} },
-	{ AFDIVRF,	yfmvx,	Px, {0xd8,(07)} },
-	{ AFDIVRD,	yfadd,	Px, {0xdc,(07),0xd8,(07),0xdc,(06)} },
-
-	{ AFXCHD,	yfxch,	Px, {0xd9,(01),0xd9,(01)} },
-	{ AFFREE },
-	{ AFLDCW,	ystcw,	Px, {0xd9,(05),0xd9,(05)} },
-	{ AFLDENV,	ystcw,	Px, {0xd9,(04),0xd9,(04)} },
-	{ AFRSTOR,	ysvrs,	Px, {0xdd,(04),0xdd,(04)} },
-	{ AFSAVE,	ysvrs,	Px, {0xdd,(06),0xdd,(06)} },
-	{ AFSTCW,	ystcw,	Px, {0xd9,(07),0xd9,(07)} },
-	{ AFSTENV,	ystcw,	Px, {0xd9,(06),0xd9,(06)} },
-	{ AFSTSW,	ystsw,	Px, {0xdd,(07),0xdf,0xe0} },
-	{ AF2XM1,	ynone,	Px, {0xd9, 0xf0} },
-	{ AFABS,	ynone,	Px, {0xd9, 0xe1} },
-	{ AFCHS,	ynone,	Px, {0xd9, 0xe0} },
-	{ AFCLEX,	ynone,	Px, {0xdb, 0xe2} },
-	{ AFCOS,	ynone,	Px, {0xd9, 0xff} },
-	{ AFDECSTP,	ynone,	Px, {0xd9, 0xf6} },
-	{ AFINCSTP,	ynone,	Px, {0xd9, 0xf7} },
-	{ AFINIT,	ynone,	Px, {0xdb, 0xe3} },
-	{ AFLD1,	ynone,	Px, {0xd9, 0xe8} },
-	{ AFLDL2E,	ynone,	Px, {0xd9, 0xea} },
-	{ AFLDL2T,	ynone,	Px, {0xd9, 0xe9} },
-	{ AFLDLG2,	ynone,	Px, {0xd9, 0xec} },
-	{ AFLDLN2,	ynone,	Px, {0xd9, 0xed} },
-	{ AFLDPI,	ynone,	Px, {0xd9, 0xeb} },
-	{ AFLDZ,	ynone,	Px, {0xd9, 0xee} },
-	{ AFNOP,	ynone,	Px, {0xd9, 0xd0} },
-	{ AFPATAN,	ynone,	Px, {0xd9, 0xf3} },
-	{ AFPREM,	ynone,	Px, {0xd9, 0xf8} },
-	{ AFPREM1,	ynone,	Px, {0xd9, 0xf5} },
-	{ AFPTAN,	ynone,	Px, {0xd9, 0xf2} },
-	{ AFRNDINT,	ynone,	Px, {0xd9, 0xfc} },
-	{ AFSCALE,	ynone,	Px, {0xd9, 0xfd} },
-	{ AFSIN,	ynone,	Px, {0xd9, 0xfe} },
-	{ AFSINCOS,	ynone,	Px, {0xd9, 0xfb} },
-	{ AFSQRT,	ynone,	Px, {0xd9, 0xfa} },
-	{ AFTST,	ynone,	Px, {0xd9, 0xe4} },
-	{ AFXAM,	ynone,	Px, {0xd9, 0xe5} },
-	{ AFXTRACT,	ynone,	Px, {0xd9, 0xf4} },
-	{ AFYL2X,	ynone,	Px, {0xd9, 0xf1} },
-	{ AFYL2XP1,	ynone,	Px, {0xd9, 0xf9} },
-	{ AEND },
-	{ ADYNT_ },
-	{ AINIT_ },
-	{ ASIGNAME },
-	{ ACMPXCHGB,	yrb_mb,	Pm, {0xb0} },
-	{ ACMPXCHGL,	yrl_ml,	Pm, {0xb1} },
-	{ ACMPXCHGW,	yrl_ml,	Pm, {0xb1} },
-	{ ACMPXCHG8B,	yscond,	Pm, {0xc7,(01)} },
-
-	{ ACPUID,	ynone,	Pm, {0xa2} },
-	{ ARDTSC,	ynone,	Pm, {0x31} },
-
-	{ AXADDB,	yrb_mb,	Pb, {0x0f,0xc0} },
-	{ AXADDL,	yrl_ml,	Pm, {0xc1} },
-	{ AXADDW,	yrl_ml,	Pe, {0x0f,0xc1} },
-
-	{ ACMOVLCC,	yml_rl,	Pm, {0x43} },
-	{ ACMOVLCS,	yml_rl,	Pm, {0x42} },
-	{ ACMOVLEQ,	yml_rl,	Pm, {0x44} },
-	{ ACMOVLGE,	yml_rl,	Pm, {0x4d} },
-	{ ACMOVLGT,	yml_rl,	Pm, {0x4f} },
-	{ ACMOVLHI,	yml_rl,	Pm, {0x47} },
-	{ ACMOVLLE,	yml_rl,	Pm, {0x4e} },
-	{ ACMOVLLS,	yml_rl,	Pm, {0x46} },
-	{ ACMOVLLT,	yml_rl,	Pm, {0x4c} },
-	{ ACMOVLMI,	yml_rl,	Pm, {0x48} },
-	{ ACMOVLNE,	yml_rl,	Pm, {0x45} },
-	{ ACMOVLOC,	yml_rl,	Pm, {0x41} },
-	{ ACMOVLOS,	yml_rl,	Pm, {0x40} },
-	{ ACMOVLPC,	yml_rl,	Pm, {0x4b} },
-	{ ACMOVLPL,	yml_rl,	Pm, {0x49} },
-	{ ACMOVLPS,	yml_rl,	Pm, {0x4a} },
-	{ ACMOVWCC,	yml_rl,	Pq, {0x43} },
-	{ ACMOVWCS,	yml_rl,	Pq, {0x42} },
-	{ ACMOVWEQ,	yml_rl,	Pq, {0x44} },
-	{ ACMOVWGE,	yml_rl,	Pq, {0x4d} },
-	{ ACMOVWGT,	yml_rl,	Pq, {0x4f} },
-	{ ACMOVWHI,	yml_rl,	Pq, {0x47} },
-	{ ACMOVWLE,	yml_rl,	Pq, {0x4e} },
-	{ ACMOVWLS,	yml_rl,	Pq, {0x46} },
-	{ ACMOVWLT,	yml_rl,	Pq, {0x4c} },
-	{ ACMOVWMI,	yml_rl,	Pq, {0x48} },
-	{ ACMOVWNE,	yml_rl,	Pq, {0x45} },
-	{ ACMOVWOC,	yml_rl,	Pq, {0x41} },
-	{ ACMOVWOS,	yml_rl,	Pq, {0x40} },
-	{ ACMOVWPC,	yml_rl,	Pq, {0x4b} },
-	{ ACMOVWPL,	yml_rl,	Pq, {0x49} },
-	{ ACMOVWPS,	yml_rl,	Pq, {0x4a} },
-
-	{ AFCMOVCC,	yfcmv,	Px, {0xdb,(00)} },
-	{ AFCMOVCS,	yfcmv,	Px, {0xda,(00)} },
-	{ AFCMOVEQ,	yfcmv,	Px, {0xda,(01)} },
-	{ AFCMOVHI,	yfcmv,	Px, {0xdb,(02)} },
-	{ AFCMOVLS,	yfcmv,	Px, {0xda,(02)} },
-	{ AFCMOVNE,	yfcmv,	Px, {0xdb,(01)} },
-	{ AFCMOVNU,	yfcmv,	Px, {0xdb,(03)} },
-	{ AFCMOVUN,	yfcmv,	Px, {0xda,(03)} },
-
-	{ ALFENCE, ynone, Pm, {0xae,0xe8} },
-	{ AMFENCE, ynone, Pm, {0xae,0xf0} },
-	{ ASFENCE, ynone, Pm, {0xae,0xf8} },
-
-	{ AEMMS, ynone, Pm, {0x77} },
-
-	{ APREFETCHT0,	yprefetch,	Pm,	{0x18,(01)} },
-	{ APREFETCHT1,	yprefetch,	Pm,	{0x18,(02)} },
-	{ APREFETCHT2,	yprefetch,	Pm,	{0x18,(03)} },
-	{ APREFETCHNTA,	yprefetch,	Pm,	{0x18,(00)} },
-
-	{ ABSWAPL,	ybswap,	Pm,	{0xc8} },
-	
-	{ AUNDEF,		ynone,	Px,	{0x0f, 0x0b} },
-
-	{ AADDPD,	yxm,	Pq, {0x58} },
-	{ AADDPS,	yxm,	Pm, {0x58} },
-	{ AADDSD,	yxm,	Pf2, {0x58} },
-	{ AADDSS,	yxm,	Pf3, {0x58} },
-	{ AANDNPD,	yxm,	Pq, {0x55} },
-	{ AANDNPS,	yxm,	Pm, {0x55} },
-	{ AANDPD,	yxm,	Pq, {0x54} },
-	{ AANDPS,	yxm,	Pq, {0x54} },
-	{ ACMPPD,	yxcmpi,	Px, {Pe,0xc2} },
-	{ ACMPPS,	yxcmpi,	Pm, {0xc2,0} },
-	{ ACMPSD,	yxcmpi,	Px, {Pf2,0xc2} },
-	{ ACMPSS,	yxcmpi,	Px, {Pf3,0xc2} },
-	{ ACOMISD,	yxcmp,	Pe, {0x2f} },
-	{ ACOMISS,	yxcmp,	Pm, {0x2f} },
-	{ ACVTPL2PD,	yxcvm2,	Px, {Pf3,0xe6,Pe,0x2a} },
-	{ ACVTPL2PS,	yxcvm2,	Pm, {0x5b,0,0x2a,0,} },
-	{ ACVTPD2PL,	yxcvm1,	Px, {Pf2,0xe6,Pe,0x2d} },
-	{ ACVTPD2PS,	yxm,	Pe, {0x5a} },
-	{ ACVTPS2PL,	yxcvm1, Px, {Pe,0x5b,Pm,0x2d} },
-	{ ACVTPS2PD,	yxm,	Pm, {0x5a} },
-	{ ACVTSD2SL,	yxcvfl, Pf2, {0x2d} },
- 	{ ACVTSD2SS,	yxm,	Pf2, {0x5a} },
-	{ ACVTSL2SD,	yxcvlf, Pf2, {0x2a} },
-	{ ACVTSL2SS,	yxcvlf, Pf3, {0x2a} },
-	{ ACVTSS2SD,	yxm,	Pf3, {0x5a} },
-	{ ACVTSS2SL,	yxcvfl, Pf3, {0x2d} },
-	{ ACVTTPD2PL,	yxcvm1,	Px, {Pe,0xe6,Pe,0x2c} },
-	{ ACVTTPS2PL,	yxcvm1,	Px, {Pf3,0x5b,Pm,0x2c} },
-	{ ACVTTSD2SL,	yxcvfl, Pf2, {0x2c} },
-	{ ACVTTSS2SL,	yxcvfl,	Pf3, {0x2c} },
-	{ ADIVPD,	yxm,	Pe, {0x5e} },
-	{ ADIVPS,	yxm,	Pm, {0x5e} },
-	{ ADIVSD,	yxm,	Pf2, {0x5e} },
-	{ ADIVSS,	yxm,	Pf3, {0x5e} },
-	{ AMASKMOVOU,	yxr,	Pe, {0xf7} },
-	{ AMAXPD,	yxm,	Pe, {0x5f} },
-	{ AMAXPS,	yxm,	Pm, {0x5f} },
-	{ AMAXSD,	yxm,	Pf2, {0x5f} },
-	{ AMAXSS,	yxm,	Pf3, {0x5f} },
-	{ AMINPD,	yxm,	Pe, {0x5d} },
-	{ AMINPS,	yxm,	Pm, {0x5d} },
-	{ AMINSD,	yxm,	Pf2, {0x5d} },
-	{ AMINSS,	yxm,	Pf3, {0x5d} },
-	{ AMOVAPD,	yxmov,	Pe, {0x28,0x29} },
-	{ AMOVAPS,	yxmov,	Pm, {0x28,0x29} },
-	{ AMOVO,	yxmov,	Pe, {0x6f,0x7f} },
-	{ AMOVOU,	yxmov,	Pf3, {0x6f,0x7f} },
-	{ AMOVHLPS,	yxr,	Pm, {0x12} },
-	{ AMOVHPD,	yxmov,	Pe, {0x16,0x17} },
-	{ AMOVHPS,	yxmov,	Pm, {0x16,0x17} },
-	{ AMOVLHPS,	yxr,	Pm, {0x16} },
-	{ AMOVLPD,	yxmov,	Pe, {0x12,0x13} },
-	{ AMOVLPS,	yxmov,	Pm, {0x12,0x13} },
-	{ AMOVMSKPD,	yxrrl,	Pq, {0x50} },
-	{ AMOVMSKPS,	yxrrl,	Pm, {0x50} },
-	{ AMOVNTO,	yxr_ml,	Pe, {0xe7} },
-	{ AMOVNTPD,	yxr_ml,	Pe, {0x2b} },
-	{ AMOVNTPS,	yxr_ml,	Pm, {0x2b} },
-	{ AMOVSD,	yxmov,	Pf2, {0x10,0x11} },
-	{ AMOVSS,	yxmov,	Pf3, {0x10,0x11} },
-	{ AMOVUPD,	yxmov,	Pe, {0x10,0x11} },
-	{ AMOVUPS,	yxmov,	Pm, {0x10,0x11} },
-	{ AMULPD,	yxm,	Pe, {0x59} },
-	{ AMULPS,	yxm,	Ym, {0x59} },
-	{ AMULSD,	yxm,	Pf2, {0x59} },
-	{ AMULSS,	yxm,	Pf3, {0x59} },
-	{ AORPD,	yxm,	Pq, {0x56} },
-	{ AORPS,	yxm,	Pm, {0x56} },
-	{ APADDQ,	yxm,	Pe, {0xd4} },
-	{ APAND,	yxm,	Pe, {0xdb} },
-	{ APCMPEQB,	yxmq,	Pe, {0x74} },
-	{ APMAXSW,	yxm,	Pe, {0xee} },
-	{ APMAXUB,	yxm,	Pe, {0xde} },
-	{ APMINSW,	yxm,	Pe, {0xea} },
-	{ APMINUB,	yxm,	Pe, {0xda} },
-	{ APMOVMSKB,	ymskb,	Px, {Pe,0xd7,0xd7} },
-	{ APSADBW,	yxm,	Pq, {0xf6} },
-	{ APSUBB,	yxm,	Pe, {0xf8} },
-	{ APSUBL,	yxm,	Pe, {0xfa} },
-	{ APSUBQ,	yxm,	Pe, {0xfb} },
-	{ APSUBSB,	yxm,	Pe, {0xe8} },
-	{ APSUBSW,	yxm,	Pe, {0xe9} },
-	{ APSUBUSB,	yxm,	Pe, {0xd8} },
-	{ APSUBUSW,	yxm,	Pe, {0xd9} },
-	{ APSUBW,	yxm,	Pe, {0xf9} },
-	{ APUNPCKHQDQ,	yxm,	Pe, {0x6d} },
-	{ APUNPCKLQDQ,	yxm,	Pe, {0x6c} },
-	{ APXOR,	yxm,	Pe, {0xef} },
-	{ ARCPPS,	yxm,	Pm, {0x53} },
-	{ ARCPSS,	yxm,	Pf3, {0x53} },
-	{ ARSQRTPS,	yxm,	Pm, {0x52} },
-	{ ARSQRTSS,	yxm,	Pf3, {0x52} },
-	{ ASQRTPD,	yxm,	Pe, {0x51} },
-	{ ASQRTPS,	yxm,	Pm, {0x51} },
-	{ ASQRTSD,	yxm,	Pf2, {0x51} },
-	{ ASQRTSS,	yxm,	Pf3, {0x51} },
-	{ ASUBPD,	yxm,	Pe, {0x5c} },
-	{ ASUBPS,	yxm,	Pm, {0x5c} },
-	{ ASUBSD,	yxm,	Pf2, {0x5c} },
-	{ ASUBSS,	yxm,	Pf3, {0x5c} },
-	{ AUCOMISD,	yxcmp,	Pe, {0x2e} },
-	{ AUCOMISS,	yxcmp,	Pm, {0x2e} },
-	{ AUNPCKHPD,	yxm,	Pe, {0x15} },
-	{ AUNPCKHPS,	yxm,	Pm, {0x15} },
-	{ AUNPCKLPD,	yxm,	Pe, {0x14} },
-	{ AUNPCKLPS,	yxm,	Pm, {0x14} },
-	{ AXORPD,	yxm,	Pe, {0x57} },
-	{ AXORPS,	yxm,	Pm, {0x57} },
-
-	{ AAESENC,	yaes,	Pq, {0x38,0xdc,(0)} },
-	{ APINSRD,	yinsrd,	Pq, {0x3a, 0x22, (00)} },
-	{ APSHUFB,	ymshufb,Pq, {0x38, 0x00} },
-
-	{ AUSEFIELD,	ynop,	Px, {0,0} },
-	{ ATYPE },
-	{ AFUNCDATA,	yfuncdata,	Px, {0,0} },
-	{ APCDATA,	ypcdata,	Px, {0,0} },
-	{ ACHECKNIL },
-	{ AVARDEF },
-	{ AVARKILL },
-	{ ADUFFCOPY,	yduff,	Px, {0xe8} },
-	{ ADUFFZERO,	yduff,	Px, {0xe8} },
-
-	{0}
-};
-
-static int32	vaddr(Link*, Addr*, Reloc*);
-
-// 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.
-static uchar nop[][16] = {
-	{0x90},
-	{0x66, 0x90},
-	{0x0F, 0x1F, 0x00},
-	{0x0F, 0x1F, 0x40, 0x00},
-	{0x0F, 0x1F, 0x44, 0x00, 0x00},
-	{0x66, 0x0F, 0x1F, 0x44, 0x00, 0x00},
-	{0x0F, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00},
-	{0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00},
-	{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},
-};
-
-static void
-fillnop(uchar *p, int n)
-{
-	int m;
-
-	while(n > 0) {
-		m = n;
-		if(m > nelem(nop))
-			m = nelem(nop);
-		memmove(p, nop[m-1], m);
-		p += m;
-		n -= m;
-	}
-}
-
-static int32
-naclpad(Link *ctxt, LSym *s, int32 c, int32 pad)
-{
-	symgrow(ctxt, s, c+pad);
-	fillnop(s->p+c, pad);
-	return c+pad;
-}
-
-static void instinit(void);
-
-void
-span8(Link *ctxt, LSym *s)
-{
-	Prog *p, *q;
-	int32 c, v, loop;
-	uchar *bp;
-	int n, m, i;
-
-	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) {
-		n = 0;
-		if(p->to.type == D_BRANCH)
-			if(p->pcond == nil)
-				p->pcond = p;
-		if((q = p->pcond) != nil)
-			if(q->back != 2)
-				n = 1;
-		p->back = n;
-		if(p->as == AADJSP) {
-			p->to.type = D_SP;
-			v = -p->from.offset;
-			p->from.offset = v;
-			p->as = AADDL;
-			if(v < 0) {
-				p->as = ASUBL;
-				v = -v;
-				p->from.offset = v;
-			}
-			if(v == 0)
-				p->as = ANOP;
-		}
-	}
-
-	for(p = s->text; p != nil; p = p->link) {
-		p->back = 2;	// use short branches first time through
-		if((q = p->pcond) != nil && (q->back & 2))
-			p->back |= 1;	// backward jump
-
-		if(p->as == AADJSP) {
-			p->to.type = D_SP;
-			v = -p->from.offset;
-			p->from.offset = v;
-			p->as = AADDL;
-			if(v < 0) {
-				p->as = ASUBL;
-				v = -v;
-				p->from.offset = v;
-			}
-			if(v == 0)
-				p->as = ANOP;
-		}
-	}
-	
-	n = 0;
-	do {
-		loop = 0;
-		memset(s->r, 0, s->nr*sizeof s->r[0]);
-		s->nr = 0;
-		s->np = 0;
-		c = 0;
-		for(p = s->text; p != nil; p = p->link) {
-			if(ctxt->headtype == Hnacl && p->isize > 0) {
-				static LSym *deferreturn;
-				
-				if(deferreturn == nil)
-					deferreturn = linklookup(ctxt, "runtime.deferreturn", 0);
-
-				// pad everything to avoid crossing 32-byte boundary
-				if((c>>5) != ((c+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 == ACALL && p->to.sym == deferreturn)
-					c = naclpad(ctxt, s, c, -c&31);
-				// pad call to end at 32-byte boundary
-				if(p->as == ACALL)
-					c = naclpad(ctxt, s, c, -(c+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 = c;
-
-			// process forward jumps to p
-			for(q = p->comefrom; q != nil; q = q->forwd) {
-				v = p->pc - (q->pc + q->mark);
-				if(q->back & 2)	{	// short
-					if(v > 127) {
-						loop++;
-						q->back ^= 2;
-					}
-					if(q->as == AJCXZW)
-						s->p[q->pc+2] = v;
-					else
-						s->p[q->pc+1] = v;
-				} else {
-					bp = s->p + q->pc + q->mark - 4;
-					*bp++ = v;
-					*bp++ = v>>8;
-					*bp++ = v>>16;
-					*bp = v>>24;
-				}	
-			}
-			p->comefrom = nil;
-
-			p->pc = c;
-			asmins(ctxt, p);
-			m = ctxt->andptr-ctxt->and;
-			if(p->isize != m) {
-				p->isize = m;
-				loop++;
-			}
-			symgrow(ctxt, s, p->pc+m);
-			memmove(s->p+p->pc, ctxt->and, m);
-			p->mark = m;
-			c += m;
-		}
-		if(++n > 20) {
-			ctxt->diag("span must be looping");
-			sysfatal("bad code");
-		}
-	} while(loop);
-	
-	if(ctxt->headtype == Hnacl)
-		c = naclpad(ctxt, s, c, -c&31);
-	c += -c&(FuncAlign-1);
-	s->size = c;
-
-	if(0 /* debug['a'] > 1 */) {
-		print("span1 %s %lld (%d tries)\n %.6ux", s->name, s->size, n, 0);
-		for(i=0; i<s->np; i++) {
-			print(" %.2ux", s->p[i]);
-			if(i%16 == 15)
-				print("\n  %.6ux", i+1);
-		}
-		if(i%16)
-			print("\n");
-	
-		for(i=0; i<s->nr; i++) {
-			Reloc *r;
-			
-			r = &s->r[i];
-			print(" rel %#.4ux/%d %s%+lld\n", r->off, r->siz, r->sym->name, r->add);
-		}
-	}
-}
-
-static void
-instinit(void)
-{
-	int i;
-
-	for(i=1; optab[i].as; i++)
-		if(i != optab[i].as)
-			sysfatal("phase error in optab: at %A found %A", i, optab[i].as);
-
-	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<D_NONE; i++) {
-		reg[i] = -1;
-		if(i >= D_AL && i <= D_BH)
-			reg[i] = (i-D_AL) & 7;
-		if(i >= D_AX && i <= D_DI)
-			reg[i] = (i-D_AX) & 7;
-		if(i >= D_F0 && i <= D_F0+7)
-			reg[i] = (i-D_F0) & 7;
-		if(i >= D_X0 && i <= D_X0+7)
-			reg[i] = (i-D_X0) & 7;
-	}
-}
-
-static int
-prefixof(Link *ctxt, Addr *a)
-{
-	switch(a->type) {
-	case D_INDIR+D_CS:
-		return 0x2e;
-	case D_INDIR+D_DS:
-		return 0x3e;
-	case D_INDIR+D_ES:
-		return 0x26;
-	case D_INDIR+D_FS:
-		return 0x64;
-	case D_INDIR+D_GS:
-		return 0x65;
-	case D_INDIR+D_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.
-		switch(ctxt->headtype) {
-		default:
-			sysfatal("unknown TLS base register for %s", headstr(ctxt->headtype));
-		case Hdarwin:
-		case Hdragonfly:
-		case Hfreebsd:
-		case Hnetbsd:
-		case Hopenbsd:
-			return 0x65; // GS
-		}
-	}
-	return 0;
-}
-
-static int
-oclass(Addr *a)
-{
-	int32 v;
-
-	if((a->type >= D_INDIR && a->type < 2*D_INDIR) || a->index != D_NONE) {
-		if(a->index != D_NONE && a->scale == 0) {
-			if(a->type == D_ADDR) {
-				switch(a->index) {
-				case D_EXTERN:
-				case D_STATIC:
-					return Yi32;
-				case D_AUTO:
-				case D_PARAM:
-					return Yiauto;
-				}
-				return Yxxx;
-			}
-			//if(a->type == D_INDIR+D_ADDR)
-			//	print("*Ycol\n");
-			return Ycol;
-		}
-		return Ym;
-	}
-	switch(a->type)
-	{
-	case D_AL:
-		return Yal;
-
-	case D_AX:
-		return Yax;
-
-	case D_CL:
-	case D_DL:
-	case D_BL:
-	case D_AH:
-	case D_CH:
-	case D_DH:
-	case D_BH:
-		return Yrb;
-
-	case D_CX:
-		return Ycx;
-
-	case D_DX:
-	case D_BX:
-		return Yrx;
-
-	case D_SP:
-	case D_BP:
-	case D_SI:
-	case D_DI:
-		return Yrl;
-
-	case D_F0+0:
-		return	Yf0;
-
-	case D_F0+1:
-	case D_F0+2:
-	case D_F0+3:
-	case D_F0+4:
-	case D_F0+5:
-	case D_F0+6:
-	case D_F0+7:
-		return	Yrf;
-
-	case D_X0+0:
-	case D_X0+1:
-	case D_X0+2:
-	case D_X0+3:
-	case D_X0+4:
-	case D_X0+5:
-	case D_X0+6:
-	case D_X0+7:
-		return	Yxr;
-
-	case D_NONE:
-		return Ynone;
-
-	case D_CS:	return	Ycs;
-	case D_SS:	return	Yss;
-	case D_DS:	return	Yds;
-	case D_ES:	return	Yes;
-	case D_FS:	return	Yfs;
-	case D_GS:	return	Ygs;
-	case D_TLS:	return	Ytls;
-
-	case D_GDTR:	return	Ygdtr;
-	case D_IDTR:	return	Yidtr;
-	case D_LDTR:	return	Yldtr;
-	case D_MSW:	return	Ymsw;
-	case D_TASK:	return	Ytask;
-
-	case D_CR+0:	return	Ycr0;
-	case D_CR+1:	return	Ycr1;
-	case D_CR+2:	return	Ycr2;
-	case D_CR+3:	return	Ycr3;
-	case D_CR+4:	return	Ycr4;
-	case D_CR+5:	return	Ycr5;
-	case D_CR+6:	return	Ycr6;
-	case D_CR+7:	return	Ycr7;
-
-	case D_DR+0:	return	Ydr0;
-	case D_DR+1:	return	Ydr1;
-	case D_DR+2:	return	Ydr2;
-	case D_DR+3:	return	Ydr3;
-	case D_DR+4:	return	Ydr4;
-	case D_DR+5:	return	Ydr5;
-	case D_DR+6:	return	Ydr6;
-	case D_DR+7:	return	Ydr7;
-
-	case D_TR+0:	return	Ytr0;
-	case D_TR+1:	return	Ytr1;
-	case D_TR+2:	return	Ytr2;
-	case D_TR+3:	return	Ytr3;
-	case D_TR+4:	return	Ytr4;
-	case D_TR+5:	return	Ytr5;
-	case D_TR+6:	return	Ytr6;
-	case D_TR+7:	return	Ytr7;
-
-	case D_EXTERN:
-	case D_STATIC:
-	case D_AUTO:
-	case D_PARAM:
-		return Ym;
-
-	case D_CONST:
-	case D_CONST2:
-	case D_ADDR:
-		if(a->sym == nil) {
-			v = a->offset;
-			if(v == 0)
-				return Yi0;
-			if(v == 1)
-				return Yi1;
-			if(v >= -128 && v <= 127)
-				return Yi8;
-		}
-		return Yi32;
-
-	case D_BRANCH:
-		return Ybr;
-	}
-	return Yxxx;
-}
-
-static void
-asmidx(Link *ctxt, int scale, int index, int base)
-{
-	int i;
-
-	switch(index) {
-	default:
-		goto bad;
-
-	case D_NONE:
-		i = 4 << 3;
-		goto bas;
-
-	case D_AX:
-	case D_CX:
-	case D_DX:
-	case D_BX:
-	case D_BP:
-	case D_SI:
-	case D_DI:
-		i = reg[index] << 3;
-		break;
-	}
-	switch(scale) {
-	default:
-		goto bad;
-	case 1:
-		break;
-	case 2:
-		i |= (1<<6);
-		break;
-	case 4:
-		i |= (2<<6);
-		break;
-	case 8:
-		i |= (3<<6);
-		break;
-	}
-bas:
-	switch(base) {
-	default:
-		goto bad;
-	case D_NONE:	/* must be mod=00 */
-		i |= 5;
-		break;
-	case D_AX:
-	case D_CX:
-	case D_DX:
-	case D_BX:
-	case D_SP:
-	case D_BP:
-	case D_SI:
-	case D_DI:
-		i |= reg[base];
-		break;
-	}
-	*ctxt->andptr++ = i;
-	return;
-bad:
-	ctxt->diag("asmidx: bad address %d,%d,%d", scale, index, base);
-	*ctxt->andptr++ = 0;
-	return;
-}
-
-static void
-put4(Link *ctxt, int32 v)
-{
-	ctxt->andptr[0] = v;
-	ctxt->andptr[1] = v>>8;
-	ctxt->andptr[2] = v>>16;
-	ctxt->andptr[3] = v>>24;
-	ctxt->andptr += 4;
-}
-
-static void
-relput4(Link *ctxt, Prog *p, Addr *a)
-{
-	vlong v;
-	Reloc rel, *r;
-	
-	v = vaddr(ctxt, a, &rel);
-	if(rel.siz != 0) {
-		if(rel.siz != 4)
-			ctxt->diag("bad reloc");
-		r = addrel(ctxt->cursym);
-		*r = rel;
-		r->off = p->pc + ctxt->andptr - ctxt->and;
-	}
-	put4(ctxt, v);
-}
-
-static int32
-vaddr(Link *ctxt, Addr *a, Reloc *r)
-{
-	int t;
-	int32 v;
-	LSym *s;
-	
-	if(r != nil)
-		memset(r, 0, sizeof *r);
-
-	t = a->type;
-	v = a->offset;
-	if(t == D_ADDR)
-		t = a->index;
-	switch(t) {
-	case D_STATIC:
-	case D_EXTERN:
-		s = a->sym;
-		if(s != nil) {
-			if(r == nil) {
-				ctxt->diag("need reloc for %D", a);
-				sysfatal("bad code");
-			}
-			r->type = R_ADDR;
-			r->siz = 4;
-			r->off = -1;
-			r->sym = s;
-			r->add = v;
-			v = 0;
-		}
-		break;
-	
-	case D_INDIR+D_TLS:
-		if(r == nil) {
-			ctxt->diag("need reloc for %D", a);
-			sysfatal("bad code");
-		}
-		r->type = R_TLS_LE;
-		r->siz = 4;
-		r->off = -1; // caller must fill in
-		r->add = v;
-		v = 0;
-		break;
-	}
-	return v;
-}
-
-static void
-asmand(Link *ctxt, Addr *a, int r)
-{
-	int32 v;
-	int t, scale;
-	Reloc rel;
-
-	v = a->offset;
-	t = a->type;
-	rel.siz = 0;
-	if(a->index != D_NONE && a->index != D_TLS) {
-		if(t < D_INDIR || t >= 2*D_INDIR) {
-			switch(t) {
-			default:
-				goto bad;
-			case D_STATIC:
-			case D_EXTERN:
-				t = D_NONE;
-				v = vaddr(ctxt, a, &rel);
-				break;
-			case D_AUTO:
-			case D_PARAM:
-				t = D_SP;
-				break;
-			}
-		} else
-			t -= D_INDIR;
-
-		if(t == D_NONE) {
-			*ctxt->andptr++ = (0 << 6) | (4 << 0) | (r << 3);
-			asmidx(ctxt, a->scale, a->index, t);
-			goto putrelv;
-		}
-		if(v == 0 && rel.siz == 0 && t != D_BP) {
-			*ctxt->andptr++ = (0 << 6) | (4 << 0) | (r << 3);
-			asmidx(ctxt, a->scale, a->index, t);
-			return;
-		}
-		if(v >= -128 && v < 128 && rel.siz == 0) {
-			*ctxt->andptr++ = (1 << 6) | (4 << 0) | (r << 3);
-			asmidx(ctxt, a->scale, a->index, t);
-			*ctxt->andptr++ = v;
-			return;
-		}
-		*ctxt->andptr++ = (2 << 6) | (4 << 0) | (r << 3);
-		asmidx(ctxt, a->scale, a->index, t);
-		goto putrelv;
-	}
-	if(t >= D_AL && t <= D_F7 || t >= D_X0 && t <= D_X7) {
-		if(v)
-			goto bad;
-		*ctxt->andptr++ = (3 << 6) | (reg[t] << 0) | (r << 3);
-		return;
-	}
-	
-	scale = a->scale;
-	if(t < D_INDIR || t >= 2*D_INDIR) {
-		switch(a->type) {
-		default:
-			goto bad;
-		case D_STATIC:
-		case D_EXTERN:
-			t = D_NONE;
-			v = vaddr(ctxt, a, &rel);
-			break;
-		case D_AUTO:
-		case D_PARAM:
-			t = D_SP;
-			break;
-		}
-		scale = 1;
-	} else
-		t -= D_INDIR;
-	if(t == D_TLS)
-		v = vaddr(ctxt, a, &rel);
-
-	if(t == D_NONE || (D_CS <= t && t <= D_GS) || t == D_TLS) {
-		*ctxt->andptr++ = (0 << 6) | (5 << 0) | (r << 3);
-		goto putrelv;
-	}
-	if(t == D_SP) {
-		if(v == 0 && rel.siz == 0) {
-			*ctxt->andptr++ = (0 << 6) | (4 << 0) | (r << 3);
-			asmidx(ctxt, scale, D_NONE, t);
-			return;
-		}
-		if(v >= -128 && v < 128 && rel.siz == 0) {
-			*ctxt->andptr++ = (1 << 6) | (4 << 0) | (r << 3);
-			asmidx(ctxt, scale, D_NONE, t);
-			*ctxt->andptr++ = v;
-			return;
-		}
-		*ctxt->andptr++ = (2 << 6) | (4 << 0) | (r << 3);
-		asmidx(ctxt, scale, D_NONE, t);
-		goto putrelv;
-	}
-	if(t >= D_AX && t <= D_DI) {
-		if(a->index == D_TLS) {
-			memset(&rel, 0, sizeof rel);
-			rel.type = R_TLS_IE;
-			rel.siz = 4;
-			rel.sym = nil;
-			rel.add = v;
-			v = 0;
-		}
-		if(v == 0 && rel.siz == 0 && t != D_BP) {
-			*ctxt->andptr++ = (0 << 6) | (reg[t] << 0) | (r << 3);
-			return;
-		}
-		if(v >= -128 && v < 128 && rel.siz == 0)  {
-			ctxt->andptr[0] = (1 << 6) | (reg[t] << 0) | (r << 3);
-			ctxt->andptr[1] = v;
-			ctxt->andptr += 2;
-			return;
-		}
-		*ctxt->andptr++ = (2 << 6) | (reg[t] << 0) | (r << 3);
-		goto putrelv;
-	}
-	goto bad;
-
-putrelv:
-	if(rel.siz != 0) {
-		Reloc *r;
-		
-		if(rel.siz != 4) {
-			ctxt->diag("bad rel");
-			goto bad;
-		}
-		r = addrel(ctxt->cursym);
-		*r = rel;
-		r->off = ctxt->curp->pc + ctxt->andptr - ctxt->and;
-	}
-
-	put4(ctxt, v);
-	return;
-
-bad:
-	ctxt->diag("asmand: bad address %D", a);
-	return;
-}
-
-enum
-{
-	E = 0xff,
-};
-
-static uchar	ymovtab[] =
-{
-/* 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->type.
-// If a is empty, it returns BX to account for MULB-like instructions
-// that might use DX and AX.
-static int
-byteswapreg(Link *ctxt, Addr *a)
-{
-	int cana, canb, canc, cand;
-
-	cana = canb = canc = cand = 1;
-
-	switch(a->type) {
-	case D_NONE:
-		cana = cand = 0;
-		break;
-	case D_AX:
-	case D_AL:
-	case D_AH:
-	case D_INDIR+D_AX:
-		cana = 0;
-		break;
-	case D_BX:
-	case D_BL:
-	case D_BH:
-	case D_INDIR+D_BX:
-		canb = 0;
-		break;
-	case D_CX:
-	case D_CL:
-	case D_CH:
-	case D_INDIR+D_CX:
-		canc = 0;
-		break;
-	case D_DX:
-	case D_DL:
-	case D_DH:
-	case D_INDIR+D_DX:
-		cand = 0;
-		break;
-	}
-	switch(a->index) {
-	case D_AX:
-		cana = 0;
-		break;
-	case D_BX:
-		canb = 0;
-		break;
-	case D_CX:
-		canc = 0;
-		break;
-	case D_DX:
-		cand = 0;
-		break;
-	}
-	if(cana)
-		return D_AX;
-	if(canb)
-		return D_BX;
-	if(canc)
-		return D_CX;
-	if(cand)
-		return D_DX;
-
-	ctxt->diag("impossible byte register");
-	sysfatal("bad code");
-	return 0;
-}
-
-static void
-subreg(Prog *p, int from, int to)
-{
-
-	if(0 /* debug['Q'] */)
-		print("\n%P	s/%R/%R/\n", p, from, to);
-
-	if(p->from.type == from) {
-		p->from.type = to;
-		p->ft = 0;
-	}
-	if(p->to.type == from) {
-		p->to.type = to;
-		p->tt = 0;
-	}
-
-	if(p->from.index == from) {
-		p->from.index = to;
-		p->ft = 0;
-	}
-	if(p->to.index == from) {
-		p->to.index = to;
-		p->tt = 0;
-	}
-
-	from += D_INDIR;
-	if(p->from.type == from) {
-		p->from.type = to+D_INDIR;
-		p->ft = 0;
-	}
-	if(p->to.type == from) {
-		p->to.type = to+D_INDIR;
-		p->tt = 0;
-	}
-
-	if(0 /* debug['Q'] */)
-		print("%P\n", p);
-}
-
-static int
-mediaop(Link *ctxt, Optab *o, int op, int osize, int z)
-{
-	switch(op){
-	case Pm:
-	case Pe:
-	case Pf2:
-	case Pf3:
-		if(osize != 1){
-			if(op != Pm)
-				*ctxt->andptr++ = op;
-			*ctxt->andptr++ = Pm;
-			op = o->op[++z];
-			break;
-		}
-	default:
-		if(ctxt->andptr == ctxt->and || ctxt->and[ctxt->andptr - ctxt->and - 1] != Pm)
-			*ctxt->andptr++ = Pm;
-		break;
-	}
-	*ctxt->andptr++ = op;
-	return z;
-}
-
-static void
-doasm(Link *ctxt, Prog *p)
-{
-	Optab *o;
-	Prog *q, pp;
-	uchar *t;
-	int z, op, ft, tt, breg;
-	int32 v, pre;
-	Reloc rel, *r;
-	Addr *a;
-	
-	ctxt->curp = p;	// TODO
-
-	pre = prefixof(ctxt, &p->from);
-	if(pre)
-		*ctxt->andptr++ = pre;
-	pre = prefixof(ctxt, &p->to);
-	if(pre)
-		*ctxt->andptr++ = pre;
-
-	if(p->ft == 0)
-		p->ft = oclass(&p->from);
-	if(p->tt == 0)
-		p->tt = oclass(&p->to);
-
-	ft = p->ft * Ymax;
-	tt = p->tt * Ymax;
-	o = &optab[p->as];
-	t = o->ytab;
-	if(t == 0) {
-		ctxt->diag("asmins: noproto %P", p);
-		return;
-	}
-	for(z=0; *t; z+=t[3],t+=4)
-		if(ycover[ft+t[0]])
-		if(ycover[tt+t[1]])
-			goto found;
-	goto domov;
-
-found:
-	switch(o->prefix) {
-	case Pq:	/* 16 bit escape and opcode escape */
-		*ctxt->andptr++ = Pe;
-		*ctxt->andptr++ = Pm;
-		break;
-
-	case Pf2:	/* xmm opcode escape */
-	case Pf3:
-		*ctxt->andptr++ = o->prefix;
-		*ctxt->andptr++ = Pm;
-		break;
-
-	case Pm:	/* opcode escape */
-		*ctxt->andptr++ = Pm;
-		break;
-
-	case Pe:	/* 16 bit escape */
-		*ctxt->andptr++ = Pe;
-		break;
-
-	case Pb:	/* botch */
-		break;
-	}
-
-	op = o->op[z];
-	switch(t[2]) {
-	default:
-		ctxt->diag("asmins: unknown z %d %P", t[2], p);
-		return;
-
-	case Zpseudo:
-		break;
-
-	case Zlit:
-		for(; op = o->op[z]; z++)
-			*ctxt->andptr++ = op;
-		break;
-
-	case Zlitm_r:
-		for(; op = o->op[z]; z++)
-			*ctxt->andptr++ = op;
-		asmand(ctxt, &p->from, reg[p->to.type]);
-		break;
-
-	case Zm_r:
-		*ctxt->andptr++ = op;
-		asmand(ctxt, &p->from, reg[p->to.type]);
-		break;
-
-	case Zm2_r:
-		*ctxt->andptr++ = op;
-		*ctxt->andptr++ = o->op[z+1];
-		asmand(ctxt, &p->from, reg[p->to.type]);
-		break;
-
-	case Zm_r_xm:
-		mediaop(ctxt, o, op, t[3], z);
-		asmand(ctxt, &p->from, reg[p->to.type]);
-		break;
-
-	case Zm_r_i_xm:
-		mediaop(ctxt, o, op, t[3], z);
-		asmand(ctxt, &p->from, reg[p->to.type]);
-		*ctxt->andptr++ = p->to.offset;
-		break;
-
-	case Zibm_r:
-		while ((op = o->op[z++]) != 0)
-			*ctxt->andptr++ = op;
-		asmand(ctxt, &p->from, reg[p->to.type]);
-		*ctxt->andptr++ = p->to.offset;
-		break;
-
-	case Zaut_r:
-		*ctxt->andptr++ = 0x8d;	/* leal */
-		if(p->from.type != D_ADDR)
-			ctxt->diag("asmins: Zaut sb type ADDR");
-		p->from.type = p->from.index;
-		p->from.index = D_NONE;
-		p->ft = 0;
-		asmand(ctxt, &p->from, reg[p->to.type]);
-		p->from.index = p->from.type;
-		p->from.type = D_ADDR;
-		p->ft = 0;
-		break;
-
-	case Zm_o:
-		*ctxt->andptr++ = op;
-		asmand(ctxt, &p->from, o->op[z+1]);
-		break;
-
-	case Zr_m:
-		*ctxt->andptr++ = op;
-		asmand(ctxt, &p->to, reg[p->from.type]);
-		break;
-
-	case Zr_m_xm:
-		mediaop(ctxt, o, op, t[3], z);
-		asmand(ctxt, &p->to, reg[p->from.type]);
-		break;
-
-	case Zr_m_i_xm:
-		mediaop(ctxt, o, op, t[3], z);
-		asmand(ctxt, &p->to, reg[p->from.type]);
-		*ctxt->andptr++ = p->from.offset;
-		break;
-
-	case Zcallindreg:
-		r = addrel(ctxt->cursym);
-		r->off = p->pc;
-		r->type = R_CALLIND;
-		r->siz = 0;
-		// fallthrough
-	case Zo_m:
-		*ctxt->andptr++ = op;
-		asmand(ctxt, &p->to, o->op[z+1]);
-		break;
-
-	case Zm_ibo:
-		*ctxt->andptr++ = op;
-		asmand(ctxt, &p->from, o->op[z+1]);
-		*ctxt->andptr++ = vaddr(ctxt, &p->to, nil);
-		break;
-
-	case Zibo_m:
-		*ctxt->andptr++ = op;
-		asmand(ctxt, &p->to, o->op[z+1]);
-		*ctxt->andptr++ = vaddr(ctxt, &p->from, nil);
-		break;
-
-	case Z_ib:
-	case Zib_:
-		if(t[2] == Zib_)
-			a = &p->from;
-		else
-			a = &p->to;
-		v = vaddr(ctxt, a, nil);
-		*ctxt->andptr++ = op;
-		*ctxt->andptr++ = v;
-		break;
-
-	case Zib_rp:
-		*ctxt->andptr++ = op + reg[p->to.type];
-		*ctxt->andptr++ = vaddr(ctxt, &p->from, nil);
-		break;
-
-	case Zil_rp:
-		*ctxt->andptr++ = op + reg[p->to.type];
-		if(o->prefix == Pe) {
-			v = vaddr(ctxt, &p->from, nil);
-			*ctxt->andptr++ = v;
-			*ctxt->andptr++ = v>>8;
-		}
-		else
-			relput4(ctxt, p, &p->from);
-		break;
-
-	case Zib_rr:
-		*ctxt->andptr++ = op;
-		asmand(ctxt, &p->to, reg[p->to.type]);
-		*ctxt->andptr++ = vaddr(ctxt, &p->from, nil);
-		break;
-
-	case Z_il:
-	case Zil_:
-		if(t[2] == Zil_)
-			a = &p->from;
-		else
-			a = &p->to;
-		*ctxt->andptr++ = op;
-		if(o->prefix == Pe) {
-			v = vaddr(ctxt, a, nil);
-			*ctxt->andptr++ = v;
-			*ctxt->andptr++ = v>>8;
-		}
-		else
-			relput4(ctxt, p, a);
-		break;
-
-	case Zm_ilo:
-	case Zilo_m:
-		*ctxt->andptr++ = op;
-		if(t[2] == Zilo_m) {
-			a = &p->from;
-			asmand(ctxt, &p->to, o->op[z+1]);
-		} else {
-			a = &p->to;
-			asmand(ctxt, &p->from, o->op[z+1]);
-		}
-		if(o->prefix == Pe) {
-			v = vaddr(ctxt, a, nil);
-			*ctxt->andptr++ = v;
-			*ctxt->andptr++ = v>>8;
-		}
-		else
-			relput4(ctxt, p, a);
-		break;
-
-	case Zil_rr:
-		*ctxt->andptr++ = op;
-		asmand(ctxt, &p->to, reg[p->to.type]);
-		if(o->prefix == Pe) {
-			v = vaddr(ctxt, &p->from, nil);
-			*ctxt->andptr++ = v;
-			*ctxt->andptr++ = v>>8;
-		}
-		else
-			relput4(ctxt, p, &p->from);
-		break;
-
-	case Z_rp:
-		*ctxt->andptr++ = op + reg[p->to.type];
-		break;
-
-	case Zrp_:
-		*ctxt->andptr++ = op + reg[p->from.type];
-		break;
-
-	case Zclr:
-		*ctxt->andptr++ = op;
-		asmand(ctxt, &p->to, reg[p->to.type]);
-		break;
-	
-	case Zcall:
-		if(p->to.sym == nil) {
-			ctxt->diag("call without target");
-			sysfatal("bad code");
-		}
-		*ctxt->andptr++ = op;
-		r = addrel(ctxt->cursym);
-		r->off = p->pc + ctxt->andptr - ctxt->and;
-		r->type = R_CALL;
-		r->siz = 4;
-		r->sym = p->to.sym;
-		r->add = p->to.offset;
-		put4(ctxt, 0);
-		break;
-
-	case Zbr:
-	case Zjmp:
-	case Zloop:
-		if(p->to.sym != nil) {
-			if(t[2] != Zjmp) {
-				ctxt->diag("branch to ATEXT");
-				sysfatal("bad code");
-			}
-			*ctxt->andptr++ = o->op[z+1];
-			r = addrel(ctxt->cursym);
-			r->off = p->pc + ctxt->andptr - ctxt->and;
-			r->sym = p->to.sym;
-			r->type = 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");
-			sysfatal("bad code");
-		}
-		if(p->back & 1) {
-			v = q->pc - (p->pc + 2);
-			if(v >= -128) {
-				if(p->as == AJCXZW)
-					*ctxt->andptr++ = 0x67;
-				*ctxt->andptr++ = op;
-				*ctxt->andptr++ = v;
-			} else if(t[2] == Zloop) {
-				ctxt->diag("loop too far: %P", p);
-			} else {
-				v -= 5-2;
-				if(t[2] == 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;
-			}
-			break;
-		}
-
-		// Annotate target; will fill in later.
-		p->forwd = q->comefrom;
-		q->comefrom = p;
-		if(p->back & 2)	{ // short
-			if(p->as == AJCXZW)
-				*ctxt->andptr++ = 0x67;
-			*ctxt->andptr++ = op;
-			*ctxt->andptr++ = 0;
-		} else if(t[2] == Zloop) {
-			ctxt->diag("loop too far: %P", p);
-		} else {
-			if(t[2] == Zbr)
-				*ctxt->andptr++ = 0x0f;
-			*ctxt->andptr++ = o->op[z+1];
-			*ctxt->andptr++ = 0;
-			*ctxt->andptr++ = 0;
-			*ctxt->andptr++ = 0;
-			*ctxt->andptr++ = 0;
-		}
-		break;
-
-	case Zcallcon:
-	case Zjmpcon:
-		if(t[2] == Zcallcon)
-			*ctxt->andptr++ = op;
-		else
-			*ctxt->andptr++ = o->op[z+1];
-		r = addrel(ctxt->cursym);
-		r->off = p->pc + ctxt->andptr - ctxt->and;
-		r->type = R_PCREL;
-		r->siz = 4;
-		r->add = p->to.offset;
-		put4(ctxt, 0);
-		break;
-	
-	case Zcallind:
-		*ctxt->andptr++ = op;
-		*ctxt->andptr++ = o->op[z+1];
-		r = addrel(ctxt->cursym);
-		r->off = p->pc + ctxt->andptr - ctxt->and;
-		r->type = R_ADDR;
-		r->siz = 4;
-		r->add = p->to.offset;
-		r->sym = p->to.sym;
-		put4(ctxt, 0);
-		break;
-
-	case Zbyte:
-		v = vaddr(ctxt, &p->from, &rel);
-		if(rel.siz != 0) {
-			rel.siz = op;
-			r = addrel(ctxt->cursym);
-			*r = rel;
-			r->off = p->pc + ctxt->andptr - ctxt->and;
-		}
-		*ctxt->andptr++ = v;
-		if(op > 1) {
-			*ctxt->andptr++ = v>>8;
-			if(op > 2) {
-				*ctxt->andptr++ = v>>16;
-				*ctxt->andptr++ = v>>24;
-			}
-		}
-		break;
-
-	case Zmov:
-		goto domov;
-	}
-	return;
-
-domov:
-	for(t=ymovtab; *t; t+=8)
-		if(p->as == t[0])
-		if(ycover[ft+t[1]])
-		if(ycover[tt+t[2]])
-			goto mfound;
-bad:
-	/*
-	 * 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.
-	 */
-	pp = *p;
-	z = p->from.type;
-	if(z >= D_BP && z <= D_DI) {
-		if((breg = byteswapreg(ctxt, &p->to)) != D_AX) {
-			*ctxt->andptr++ = 0x87;			/* xchg lhs,bx */
-			asmand(ctxt, &p->from, reg[breg]);
-			subreg(&pp, z, breg);
-			doasm(ctxt, &pp);
-			*ctxt->andptr++ = 0x87;			/* xchg lhs,bx */
-			asmand(ctxt, &p->from, reg[breg]);
-		} else {
-			*ctxt->andptr++ = 0x90 + reg[z];		/* xchg lsh,ax */
-			subreg(&pp, z, D_AX);
-			doasm(ctxt, &pp);
-			*ctxt->andptr++ = 0x90 + reg[z];		/* xchg lsh,ax */
-		}
-		return;
-	}
-	z = p->to.type;
-	if(z >= D_BP && z <= D_DI) {
-		if((breg = byteswapreg(ctxt, &p->from)) != D_AX) {
-			*ctxt->andptr++ = 0x87;			/* xchg rhs,bx */
-			asmand(ctxt, &p->to, reg[breg]);
-			subreg(&pp, z, breg);
-			doasm(ctxt, &pp);
-			*ctxt->andptr++ = 0x87;			/* xchg rhs,bx */
-			asmand(ctxt, &p->to, reg[breg]);
-		} else {
-			*ctxt->andptr++ = 0x90 + reg[z];		/* xchg rsh,ax */
-			subreg(&pp, z, D_AX);
-			doasm(ctxt, &pp);
-			*ctxt->andptr++ = 0x90 + reg[z];		/* xchg rsh,ax */
-		}
-		return;
-	}
-	ctxt->diag("doasm: notfound t2=%ux from=%ux to=%ux %P", t[2], p->from.type, p->to.type, p);
-	return;
-
-mfound:
-	switch(t[3]) {
-	default:
-		ctxt->diag("asmins: unknown mov %d %P", t[3], p);
-		break;
-
-	case 0:	/* lit */
-		for(z=4; t[z]!=E; z++)
-			*ctxt->andptr++ = t[z];
-		break;
-
-	case 1:	/* r,m */
-		*ctxt->andptr++ = t[4];
-		asmand(ctxt, &p->to, t[5]);
-		break;
-
-	case 2:	/* m,r */
-		*ctxt->andptr++ = t[4];
-		asmand(ctxt, &p->from, t[5]);
-		break;
-
-	case 3:	/* r,m - 2op */
-		*ctxt->andptr++ = t[4];
-		*ctxt->andptr++ = t[5];
-		asmand(ctxt, &p->to, t[6]);
-		break;
-
-	case 4:	/* m,r - 2op */
-		*ctxt->andptr++ = t[4];
-		*ctxt->andptr++ = t[5];
-		asmand(ctxt, &p->from, t[6]);
-		break;
-
-	case 5:	/* load full pointer, trash heap */
-		if(t[4])
-			*ctxt->andptr++ = t[4];
-		switch(p->to.index) {
-		default:
-			goto bad;
-		case D_DS:
-			*ctxt->andptr++ = 0xc5;
-			break;
-		case D_SS:
-			*ctxt->andptr++ = 0x0f;
-			*ctxt->andptr++ = 0xb2;
-			break;
-		case D_ES:
-			*ctxt->andptr++ = 0xc4;
-			break;
-		case D_FS:
-			*ctxt->andptr++ = 0x0f;
-			*ctxt->andptr++ = 0xb4;
-			break;
-		case D_GS:
-			*ctxt->andptr++ = 0x0f;
-			*ctxt->andptr++ = 0xb5;
-			break;
-		}
-		asmand(ctxt, &p->from, reg[p->to.type]);
-		break;
-
-	case 6:	/* double shift */
-		z = p->from.type;
-		switch(z) {
-		default:
-			goto bad;
-		case D_CONST:
-			*ctxt->andptr++ = 0x0f;
-			*ctxt->andptr++ = t[4];
-			asmand(ctxt, &p->to, reg[p->from.index]);
-			*ctxt->andptr++ = p->from.offset;
-			break;
-		case D_CL:
-		case D_CX:
-			*ctxt->andptr++ = 0x0f;
-			*ctxt->andptr++ = t[5];
-			asmand(ctxt, &p->to, reg[p->from.index]);
-			break;
-		}
-		break;
-
-	case 7: /* imul rm,r */
-		if(t[4] == Pq) {
-			*ctxt->andptr++ = Pe;
-			*ctxt->andptr++ = Pm;
-		} else
-			*ctxt->andptr++ = t[4];
-		*ctxt->andptr++ = t[5];
-		asmand(ctxt, &p->from, reg[p->to.type]);
-		break;
-	
-	case 8: /* mov tls, r */
-		// 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:
-			sysfatal("unknown TLS base location for %s", headstr(ctxt->headtype));
-
-		case Hlinux:
-		case Hnacl:
-			// ELF TLS base is 0(GS).
-			pp.from = p->from;
-			pp.from.type = D_INDIR+D_GS;
-			pp.from.offset = 0;
-			pp.from.index = D_NONE;
-			pp.from.scale = 0;
-			*ctxt->andptr++ = 0x65; // GS
-			*ctxt->andptr++ = 0x8B;
-			asmand(ctxt, &pp.from, reg[p->to.type]);
-			break;
-		
-		case Hplan9:
-			if(ctxt->plan9privates == nil)
-				ctxt->plan9privates = linklookup(ctxt, "_privates", 0);
-			memset(&pp.from, 0, sizeof pp.from);
-			pp.from.type = D_EXTERN;
-			pp.from.sym = ctxt->plan9privates;
-			pp.from.offset = 0;
-			pp.from.index = D_NONE;
-			*ctxt->andptr++ = 0x8B;
-			asmand(ctxt, &pp.from, reg[p->to.type]);
-			break;
-
-		case Hwindows:
-			// Windows TLS base is always 0x14(FS).
-			pp.from = p->from;
-			pp.from.type = D_INDIR+D_FS;
-			pp.from.offset = 0x14;
-			pp.from.index = D_NONE;
-			pp.from.scale = 0;
-			*ctxt->andptr++ = 0x64; // FS
-			*ctxt->andptr++ = 0x8B;
-			asmand(ctxt, &pp.from, reg[p->to.type]);
-			break;
-		}
-		break;
-	}
-}
-
-static uchar naclret[] = {
-	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
-};
-
-static void
-asmins(Link *ctxt, Prog *p)
-{
-	Reloc *r;
-
-	ctxt->andptr = ctxt->and;
-	
-	if(p->as == AUSEFIELD) {
-		r = addrel(ctxt->cursym);
-		r->off = 0;
-		r->sym = p->from.sym;
-		r->type = R_USEFIELD;
-		r->siz = 0;
-		return;
-	}
-
-	if(ctxt->headtype == Hnacl) {
-		switch(p->as) {
-		case ARET:
-			memmove(ctxt->andptr, naclret, sizeof naclret);
-			ctxt->andptr += sizeof naclret;
-			return;
-		case ACALL:
-		case AJMP:
-			if(D_AX <= p->to.type && p->to.type <= D_DI) {
-				*ctxt->andptr++ = 0x83;
-				*ctxt->andptr++ = 0xe0 | (p->to.type - D_AX);
-				*ctxt->andptr++ = 0xe0;
-			}
-			break;
-		case AINT:
-			*ctxt->andptr++ = 0xf4;
-			return;
-		}
-	}
-
-	doasm(ctxt, p);
-	if(ctxt->andptr > ctxt->and+sizeof ctxt->and) {
-		print("and[] is too short - %ld byte instruction\n", ctxt->andptr - ctxt->and);
-		sysfatal("bad code");
-	}
-}
diff --git a/src/liblink/data.c b/src/liblink/data.c
deleted file mode 100644
index e5efa2e..0000000
--- a/src/liblink/data.c
+++ /dev/null
@@ -1,372 +0,0 @@
-// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <link.h>
-
-void
-mangle(char *file)
-{
-	sysfatal("%s: mangled input file", file);
-}
-
-void
-symgrow(Link *ctxt, LSym *s, vlong lsiz)
-{
-	int32 siz;
-
-	USED(ctxt);
-
-	siz = (int32)lsiz;
-	if((vlong)siz != lsiz)
-		sysfatal("symgrow size %lld too long", lsiz);
-
-	if(s->np >= siz)
-		return;
-
-	if(s->np > s->maxp) {
-		ctxt->cursym = s;
-		sysfatal("corrupt symbol data: np=%lld > maxp=%lld", (vlong)s->np, (vlong)s->maxp);
-	}
-
-	if(s->maxp < siz) {
-		if(s->maxp == 0)
-			s->maxp = 8;
-		while(s->maxp < siz)
-			s->maxp <<= 1;
-		s->p = erealloc(s->p, s->maxp);
-		memset(s->p+s->np, 0, s->maxp-s->np);
-	}
-	s->np = siz;
-}
-
-void
-savedata(Link *ctxt, LSym *s, Prog *p, char *pn)
-{
-	int32 off, siz, i, fl;
-	float32 flt;
-	uchar *cast;
-	vlong o;
-	Reloc *r;
-
-	off = p->from.offset;
-	siz = ctxt->arch->datasize(p);
-	if(off < 0 || siz < 0 || off >= 1<<30 || siz >= 100)
-		mangle(pn);
-	if(ctxt->enforce_data_order && off < s->np)
-		ctxt->diag("data out of order (already have %d)\n%P", p);
-	symgrow(ctxt, s, off+siz);
-
-	if(p->to.type == ctxt->arch->D_FCONST) {
-		switch(siz) {
-		default:
-		case 4:
-			flt = p->to.u.dval;
-			cast = (uchar*)&flt;
-			for(i=0; i<4; i++)
-				s->p[off+i] = cast[fnuxi4[i]];
-			break;
-		case 8:
-			cast = (uchar*)&p->to.u.dval;
-			for(i=0; i<8; i++)
-				s->p[off+i] = cast[fnuxi8[i]];
-			break;
-		}
-	} else if(p->to.type == ctxt->arch->D_SCONST) {
-		for(i=0; i<siz; i++)
-			s->p[off+i] = p->to.u.sval[i];
-	} else if(p->to.type == ctxt->arch->D_CONST) {
-		if(p->to.sym)
-			goto addr;
-		o = p->to.offset;
-		fl = o;
-		cast = (uchar*)&fl;
-		switch(siz) {
-		default:
-			ctxt->diag("bad nuxi %d\n%P", siz, p);
-			break;
-		case 1:
-			s->p[off] = cast[inuxi1[0]];
-			break;
-		case 2:
-			for(i=0; i<2; i++)
-				s->p[off+i] = cast[inuxi2[i]];
-			break;
-		case 4:
-			for(i=0; i<4; i++)
-				s->p[off+i] = cast[inuxi4[i]];
-			break;
-		case 8:
-			cast = (uchar*)&o;
-			for(i=0; i<8; i++)
-				s->p[off+i] = cast[inuxi8[i]];
-			break;
-		}
-	} else if(p->to.type == ctxt->arch->D_ADDR) {
-	addr:
-		r = addrel(s);
-		r->off = off;
-		r->siz = siz;
-		r->sym = p->to.sym;
-		r->type = R_ADDR;
-		r->add = p->to.offset;
-	} else {
-		ctxt->diag("bad data: %P", p);
-	}
-}
-
-Reloc*
-addrel(LSym *s)
-{
-	if(s->nr >= s->maxr) {
-		if(s->maxr == 0)
-			s->maxr = 4;
-		else
-			s->maxr <<= 1;
-		s->r = erealloc(s->r, s->maxr*sizeof s->r[0]);
-		memset(s->r+s->nr, 0, (s->maxr-s->nr)*sizeof s->r[0]);
-	}
-	return &s->r[s->nr++];
-}
-
-vlong
-setuintxx(Link *ctxt, LSym *s, vlong off, uint64 v, vlong wid)
-{
-	int32 i, fl;
-	vlong o;
-	uchar *cast;
-
-	if(s->type == 0)
-		s->type = SDATA;
-	s->reachable = 1;
-	if(s->size < off+wid) {
-		s->size = off+wid;
-		symgrow(ctxt, s, s->size);
-	}
-	fl = v;
-	cast = (uchar*)&fl;
-	switch(wid) {
-	case 1:
-		s->p[off] = cast[inuxi1[0]];
-		break;
-	case 2:
-		for(i=0; i<2; i++)
-			s->p[off+i] = cast[inuxi2[i]];
-		break;
-	case 4:
-		for(i=0; i<4; i++)
-			s->p[off+i] = cast[inuxi4[i]];
-		break;
-	case 8:
-		o = v;
-		cast = (uchar*)&o;
-		for(i=0; i<8; i++)
-			s->p[off+i] = cast[inuxi8[i]];
-		break;
-	}
-	return off+wid;
-}
-
-vlong
-adduintxx(Link *ctxt, LSym *s, uint64 v, int wid)
-{
-	vlong off;
-
-	off = s->size;
-	setuintxx(ctxt, s, off, v, wid);
-	return off;
-}
-
-vlong
-adduint8(Link *ctxt, LSym *s, uint8 v)
-{
-	return adduintxx(ctxt, s, v, 1);
-}
-
-vlong
-adduint16(Link *ctxt, LSym *s, uint16 v)
-{
-	return adduintxx(ctxt, s, v, 2);
-}
-
-vlong
-adduint32(Link *ctxt, LSym *s, uint32 v)
-{
-	return adduintxx(ctxt, s, v, 4);
-}
-
-vlong
-adduint64(Link *ctxt, LSym *s, uint64 v)
-{
-	return adduintxx(ctxt, s, v, 8);
-}
-
-vlong
-setuint8(Link *ctxt, LSym *s, vlong r, uint8 v)
-{
-	return setuintxx(ctxt, s, r, v, 1);
-}
-
-vlong
-setuint16(Link *ctxt, LSym *s, vlong r, uint16 v)
-{
-	return setuintxx(ctxt, s, r, v, 2);
-}
-
-vlong
-setuint32(Link *ctxt, LSym *s, vlong r, uint32 v)
-{
-	return setuintxx(ctxt, s, r, v, 4);
-}
-
-vlong
-setuint64(Link *ctxt, LSym *s, vlong r, uint64 v)
-{
-	return setuintxx(ctxt, s, r, v, 8);
-}
-
-vlong
-addaddrplus(Link *ctxt, LSym *s, LSym *t, vlong add)
-{
-	vlong i;
-	Reloc *r;
-
-	if(s->type == 0)
-		s->type = SDATA;
-	s->reachable = 1;
-	i = s->size;
-	s->size += ctxt->arch->ptrsize;
-	symgrow(ctxt, s, s->size);
-	r = addrel(s);
-	r->sym = t;
-	r->off = i;
-	r->siz = ctxt->arch->ptrsize;
-	r->type = R_ADDR;
-	r->add = add;
-	return i + r->siz;
-}
-
-vlong
-addpcrelplus(Link *ctxt, LSym *s, LSym *t, vlong add)
-{
-	vlong i;
-	Reloc *r;
-
-	if(s->type == 0)
-		s->type = SDATA;
-	s->reachable = 1;
-	i = s->size;
-	s->size += 4;
-	symgrow(ctxt, s, s->size);
-	r = addrel(s);
-	r->sym = t;
-	r->off = i;
-	r->add = add;
-	r->type = R_PCREL;
-	r->siz = 4;
-	return i + r->siz;
-}
-
-vlong
-addaddr(Link *ctxt, LSym *s, LSym *t)
-{
-	return addaddrplus(ctxt, s, t, 0);
-}
-
-vlong
-setaddrplus(Link *ctxt, LSym *s, vlong off, LSym *t, vlong add)
-{
-	Reloc *r;
-
-	if(s->type == 0)
-		s->type = SDATA;
-	s->reachable = 1;
-	if(off+ctxt->arch->ptrsize > s->size) {
-		s->size = off + ctxt->arch->ptrsize;
-		symgrow(ctxt, s, s->size);
-	}
-	r = addrel(s);
-	r->sym = t;
-	r->off = off;
-	r->siz = ctxt->arch->ptrsize;
-	r->type = R_ADDR;
-	r->add = add;
-	return off + r->siz;
-}
-
-vlong
-setaddr(Link *ctxt, LSym *s, vlong off, LSym *t)
-{
-	return setaddrplus(ctxt, s, off, t, 0);
-}
-
-vlong
-addsize(Link *ctxt, LSym *s, LSym *t)
-{
-	vlong i;
-	Reloc *r;
-
-	if(s->type == 0)
-		s->type = SDATA;
-	s->reachable = 1;
-	i = s->size;
-	s->size += ctxt->arch->ptrsize;
-	symgrow(ctxt, s, s->size);
-	r = addrel(s);
-	r->sym = t;
-	r->off = i;
-	r->siz = ctxt->arch->ptrsize;
-	r->type = R_SIZE;
-	return i + r->siz;
-}
-
-vlong
-addaddrplus4(Link *ctxt, LSym *s, LSym *t, vlong add)
-{
-	vlong i;
-	Reloc *r;
-
-	if(s->type == 0)
-		s->type = SDATA;
-	s->reachable = 1;
-	i = s->size;
-	s->size += 4;
-	symgrow(ctxt, s, s->size);
-	r = addrel(s);
-	r->sym = t;
-	r->off = i;
-	r->siz = 4;
-	r->type = R_ADDR;
-	r->add = add;
-	return i + r->siz;
-}
diff --git a/src/liblink/go.c b/src/liblink/go.c
deleted file mode 100644
index 9f5a423..0000000
--- a/src/liblink/go.c
+++ /dev/null
@@ -1,74 +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.
-
-// go-specific code shared across loaders (5l, 6l, 8l).
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <link.h>
-
-// replace all "". with pkg.
-char*
-expandpkg(char *t0, char *pkg)
-{
-	int n;
-	char *p;
-	char *w, *w0, *t;
-
-	n = 0;
-	for(p=t0; (p=strstr(p, "\"\".")) != nil; p+=3)
-		n++;
-
-	if(n == 0)
-		return estrdup(t0);
-
-	w0 = emallocz(strlen(t0) + strlen(pkg)*n);
-	w = w0;
-	for(p=t=t0; (p=strstr(p, "\"\".")) != nil; p=t) {
-		memmove(w, t, p - t);
-		w += p-t;
-		strcpy(w, pkg);
-		w += strlen(pkg);
-		t = p+2;
-	}
-	strcpy(w, t);
-	return w0;
-}
-
-void*
-emallocz(long n)
-{
-	void *p;
-
-	p = malloc(n);
-	if(p == nil)
-		sysfatal("out of memory");
-	memset(p, 0, n);
-	return p;
-}
-
-char*
-estrdup(char *p)
-{
-	p = strdup(p);
-	if(p == nil)
-		sysfatal("out of memory");
-	return p;
-}
-
-void*
-erealloc(void *p, long n)
-{
-	p = realloc(p, n);
-	if(p == nil)
-		sysfatal("out of memory");
-	return p;
-}
-
-void
-double2ieee(uint64 *ieee, float64 f)
-{
-	memmove(ieee, &f, 8);
-}
diff --git a/src/liblink/ld.c b/src/liblink/ld.c
deleted file mode 100644
index 6d0fe4a..0000000
--- a/src/liblink/ld.c
+++ /dev/null
@@ -1,276 +0,0 @@
-// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <link.h>
-
-void
-addlib(Link *ctxt, char *src, char *obj, char *pathname)
-{
-	char name[1024], pname[1024], *p;
-	int i;
-
-	if(strlen(pathname) >= sizeof name)
-		sysfatal("addlib pathname too long");
-	strcpy(name, pathname);
-	cleanname(name);
-	
-	// runtime.a -> runtime
-	p = nil;
-	if(strlen(name) > 2 && name[strlen(name)-2] == '.') {
-		p = name+strlen(name)-2;
-		*p = '\0';
-	}
-	
-	// already loaded?
-	for(i=0; i<ctxt->libraryp; i++)
-		if(strcmp(ctxt->library[i].pkg, name) == 0)
-			return;
-	
-	// runtime -> runtime.a for search
-	if(p != nil)
-		*p = '.';
-
-	if((!ctxt->windows && name[0] == '/') || (ctxt->windows && name[1] == ':'))
-		snprint(pname, sizeof pname, "%s", name);
-	else {
-		// try dot, -L "libdir", and then goroot.
-		for(i=0; i<ctxt->nlibdir; i++) {
-			snprint(pname, sizeof pname, "%s/%s", ctxt->libdir[i], name);
-			if(access(pname, AEXIST) >= 0)
-				break;
-		}
-	}
-	cleanname(pname);
-
-	/* runtime.a -> runtime */
-	if(p != nil)
-		*p = '\0';
-
-	if(ctxt->debugvlog > 1 && ctxt->bso)
-		Bprint(ctxt->bso, "%5.2f addlib: %s %s pulls in %s\n", cputime(), obj, src, pname);
-
-	addlibpath(ctxt, src, obj, pname, name);
-}
-
-/*
- * add library to library list.
- *	srcref: src file referring to package
- *	objref: object file referring to package
- *	file: object file, e.g., /home/rsc/go/pkg/container/vector.a
- *	pkg: package import path, e.g. container/vector
- */
-void
-addlibpath(Link *ctxt, char *srcref, char *objref, char *file, char *pkg)
-{
-	int i;
-	Library *l;
-
-	for(i=0; i<ctxt->libraryp; i++)
-		if(strcmp(file, ctxt->library[i].file) == 0)
-			return;
-
-	if(ctxt->debugvlog > 1 && ctxt->bso)
-		Bprint(ctxt->bso, "%5.2f addlibpath: srcref: %s objref: %s file: %s pkg: %s\n",
-			cputime(), srcref, objref, file, pkg);
-
-	if(ctxt->libraryp == ctxt->nlibrary){
-		ctxt->nlibrary = 50 + 2*ctxt->libraryp;
-		ctxt->library = erealloc(ctxt->library, sizeof ctxt->library[0] * ctxt->nlibrary);
-	}
-
-	l = &ctxt->library[ctxt->libraryp++];
-	l->objref = estrdup(objref);
-	l->srcref = estrdup(srcref);
-	l->file = estrdup(file);
-	l->pkg = estrdup(pkg);
-}
-
-int
-find1(int32 l, int c)
-{
-	char *p;
-	int i;
-
-	p = (char*)&l;
-	for(i=0; i<4; i++)
-		if(*p++ == c)
-			return i;
-	return 0;
-}
-
-void
-nuxiinit(LinkArch *arch)
-{
-	int i, c;
-
-	if(arch->endian != BigEndian && arch->endian != LittleEndian)
-		sysfatal("unknown endian (%#x) for arch %s", arch->endian, arch->name);
-
-	for(i=0; i<4; i++) {
-		c = find1(arch->endian, i+1);
-		if(arch->endian == LittleEndian) {
-			if(i < 2)
-				inuxi2[i] = c;
-			if(i < 1)
-				inuxi1[i] = c;
-		} else {
-			if(i >= 2)
-				inuxi2[i-2] = c;
-			if(i >= 3)
-				inuxi1[i-3] = c;
-		}
-		inuxi4[i] = c;
-		if(c == i) {
-			inuxi8[i] = c;
-			inuxi8[i+4] = c+4;
-		} else {
-			inuxi8[i] = c+4;
-			inuxi8[i+4] = c;
-		}
-		fnuxi4[i] = c;
-		if(c == i) {
-			fnuxi8[i] = c;
-			fnuxi8[i+4] = c+4;
-		} else {
-			fnuxi8[i] = c+4;
-			fnuxi8[i+4] = c;
-		}
-	}
-}
-
-uchar	fnuxi8[8];
-uchar	fnuxi4[4];
-uchar	inuxi1[1];
-uchar	inuxi2[2];
-uchar	inuxi4[4];
-uchar	inuxi8[8];
-
-enum
-{
-	LOG = 5,
-};
-void
-mkfwd(LSym *sym)
-{
-	Prog *p;
-	int i;
-	int32 dwn[LOG], cnt[LOG];
-	Prog *lst[LOG];
-
-	for(i=0; i<LOG; i++) {
-		if(i == 0)
-			cnt[i] = 1;
-		else
-			cnt[i] = LOG * cnt[i-1];
-		dwn[i] = 1;
-		lst[i] = nil;
-	}
-	i = 0;
-	for(p = sym->text; p != nil && p->link != nil; p = p->link) {
-		i--;
-		if(i < 0)
-			i = LOG-1;
-		p->forwd = nil;
-		dwn[i]--;
-		if(dwn[i] <= 0) {
-			dwn[i] = cnt[i];
-			if(lst[i] != nil)
-				lst[i]->forwd = p;
-			lst[i] = p;
-		}
-	}
-}
-
-Prog*
-copyp(Link *ctxt, Prog *q)
-{
-	Prog *p;
-
-	p = ctxt->arch->prg();
-	*p = *q;
-	return p;
-}
-
-Prog*
-appendp(Link *ctxt, Prog *q)
-{
-	Prog *p;
-
-	p = ctxt->arch->prg();
-	p->link = q->link;
-	q->link = p;
-	p->lineno = q->lineno;
-	p->mode = q->mode;
-	return p;
-}
-
-vlong
-atolwhex(char *s)
-{
-	vlong n;
-	int f;
-
-	n = 0;
-	f = 0;
-	while(*s == ' ' || *s == '\t')
-		s++;
-	if(*s == '-' || *s == '+') {
-		if(*s++ == '-')
-			f = 1;
-		while(*s == ' ' || *s == '\t')
-			s++;
-	}
-	if(s[0]=='0' && s[1]){
-		if(s[1]=='x' || s[1]=='X'){
-			s += 2;
-			for(;;){
-				if(*s >= '0' && *s <= '9')
-					n = n*16 + *s++ - '0';
-				else if(*s >= 'a' && *s <= 'f')
-					n = n*16 + *s++ - 'a' + 10;
-				else if(*s >= 'A' && *s <= 'F')
-					n = n*16 + *s++ - 'A' + 10;
-				else
-					break;
-			}
-		} else
-			while(*s >= '0' && *s <= '7')
-				n = n*8 + *s++ - '0';
-	} else
-		while(*s >= '0' && *s <= '9')
-			n = n*10 + *s++ - '0';
-	if(f)
-		n = -n;
-	return n;
-}
diff --git a/src/liblink/list5.c b/src/liblink/list5.c
deleted file mode 100644
index a91df55..0000000
--- a/src/liblink/list5.c
+++ /dev/null
@@ -1,373 +0,0 @@
-// Inferno utils/5c/list.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5c/list.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <link.h>
-#include "../cmd/5l/5.out.h"
-
-enum
-{
-	STRINGSZ = 1000
-};
-
-static int	Aconv(Fmt *fp);
-static int	Dconv(Fmt *fp);
-static int	Mconv(Fmt *fp);
-static int	Pconv(Fmt *fp);
-static int	Rconv(Fmt *fp);
-static int	RAconv(Fmt *fp);
-static int	DSconv(Fmt *fp);
-static int	DRconv(Fmt*);
-
-#pragma	varargck	type	"$"	char*
-#pragma	varargck	type	"M"	Addr*
-#pragma	varargck	type	"@"	Addr*
-
-void
-listinit5(void)
-{
-	fmtinstall('A', Aconv);
-	fmtinstall('D', Dconv);
-	fmtinstall('P', Pconv);
-	fmtinstall('R', Rconv);
-
-	// for liblink internal use
-	fmtinstall('^', DRconv);
-
-	// for internal use
-	fmtinstall('$', DSconv);
-	fmtinstall('M', Mconv);
-	fmtinstall('@', RAconv);
-}
-
-static char *extra [] = {
-	".EQ", ".NE", ".CS", ".CC",
-	".MI", ".PL", ".VS", ".VC",
-	".HI", ".LS", ".GE", ".LT",
-	".GT", ".LE", "", ".NV",
-};
-
-static	Prog*	bigP;
-
-static int
-Pconv(Fmt *fp)
-{
-	char str[STRINGSZ], sc[20];
-	Prog *p;
-	int a, s;
-
-	p = va_arg(fp->args, Prog*);
-	bigP = p;
-	a = p->as;
-	s = p->scond;
-	strcpy(sc, extra[s & C_SCOND]);
-	if(s & C_SBIT)
-		strcat(sc, ".S");
-	if(s & C_PBIT)
-		strcat(sc, ".P");
-	if(s & C_WBIT)
-		strcat(sc, ".W");
-	if(s & C_UBIT)		/* ambiguous with FBIT */
-		strcat(sc, ".U");
-	if(a == AMOVM) {
-		if(p->from.type == D_CONST)
-			sprint(str, "%.5lld (%L)	%A%s	%@,%D", p->pc, p->lineno, a, sc, &p->from, &p->to);
-		else
-		if(p->to.type == D_CONST)
-			sprint(str, "%.5lld (%L)	%A%s	%D,%@", p->pc, p->lineno, a, sc, &p->from, &p->to);
-		else
-			sprint(str, "%.5lld (%L)	%A%s	%D,%D", p->pc, p->lineno, a, sc, &p->from, &p->to);
-	} else
-	if(a == ADATA)
-		sprint(str, "%.5lld (%L)	%A	%D/%d,%D", p->pc, p->lineno, a, &p->from, p->reg, &p->to);
-	else
-	if(p->as == ATEXT)
-		sprint(str, "%.5lld (%L)	%A	%D,%d,%D", p->pc, p->lineno, a, &p->from, p->reg, &p->to);
-	else
-	if(p->reg == NREG)
-		sprint(str, "%.5lld (%L)	%A%s	%D,%D", p->pc, p->lineno, a, sc, &p->from, &p->to);
-	else
-	if(p->from.type != D_FREG)
-		sprint(str, "%.5lld (%L)	%A%s	%D,R%d,%D", p->pc, p->lineno, a, sc, &p->from, p->reg, &p->to);
-	else
-		sprint(str, "%.5lld (%L)	%A%s	%D,F%d,%D", p->pc, p->lineno, a, sc, &p->from, p->reg, &p->to);
-	bigP = nil;
-	return fmtstrcpy(fp, str);
-}
-
-static int
-Aconv(Fmt *fp)
-{
-	char *s;
-	int a;
-
-	a = va_arg(fp->args, int);
-	s = "???";
-	if(a >= AXXX && a < ALAST)
-		s = anames5[a];
-	return fmtstrcpy(fp, s);
-}
-
-static int
-Dconv(Fmt *fp)
-{
-	char str[STRINGSZ];
-	Addr *a;
-	const char *op;
-	int v;
-
-	a = va_arg(fp->args, Addr*);
-	switch(a->type) {
-
-	default:
-		sprint(str, "GOK-type(%d)", a->type);
-		break;
-
-	case D_NONE:
-		str[0] = 0;
-		if(a->name != D_NONE || a->reg != NREG || a->sym != nil)
-			sprint(str, "%M(R%d)(NONE)", a, a->reg);
-		break;
-
-	case D_CONST:
-		if(a->reg != NREG)
-			sprint(str, "$%M(R%d)", a, a->reg);
-		else
-			sprint(str, "$%M", a);
-		break;
-
-	case D_CONST2:
-		sprint(str, "$%lld-%d", a->offset, a->offset2);
-		break;
-
-	case D_SHIFT:
-		v = a->offset;
-		op = &"<<>>->@>"[(((v>>5) & 3) << 1)];
-		if(v & (1<<4))
-			sprint(str, "R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15);
-		else
-			sprint(str, "R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31);
-		if(a->reg != NREG)
-			sprint(str+strlen(str), "(R%d)", a->reg);
-		break;
-
-	case D_OREG:
-		if(a->reg != NREG)
-			sprint(str, "%M(R%d)", a, a->reg);
-		else
-			sprint(str, "%M", a);
-		break;
-
-	case D_REG:
-		sprint(str, "R%d", a->reg);
-		if(a->name != D_NONE || a->sym != nil)
-			sprint(str, "%M(R%d)(REG)", a, a->reg);
-		break;
-
-	case D_FREG:
-		sprint(str, "F%d", a->reg);
-		if(a->name != D_NONE || a->sym != nil)
-			sprint(str, "%M(R%d)(REG)", a, a->reg);
-		break;
-
-	case D_PSR:
-		sprint(str, "PSR");
-		if(a->name != D_NONE || a->sym != nil)
-			sprint(str, "%M(PSR)(REG)", a);
-		break;
-
-	case D_BRANCH:
-		if(a->sym != nil)
-			sprint(str, "%s(SB)", a->sym->name);
-		else if(bigP != nil && bigP->pcond != nil)
-			sprint(str, "%lld", bigP->pcond->pc);
-		else if(a->u.branch != nil)
-			sprint(str, "%lld", a->u.branch->pc);
-		else
-			sprint(str, "%lld(PC)", a->offset/*-pc*/);
-		break;
-
-	case D_FCONST:
-		sprint(str, "$%.17g", a->u.dval);
-		break;
-
-	case D_SCONST:
-		sprint(str, "$\"%$\"", a->u.sval);
-		break;
-	}
-	return fmtstrcpy(fp, str);
-}
-
-static int
-RAconv(Fmt *fp)
-{
-	char str[STRINGSZ];
-	Addr *a;
-	int i, v;
-
-	a = va_arg(fp->args, Addr*);
-	sprint(str, "GOK-reglist");
-	switch(a->type) {
-	case D_CONST:
-	case D_CONST2:
-		if(a->reg != NREG)
-			break;
-		if(a->sym != nil)
-			break;
-		v = a->offset;
-		strcpy(str, "");
-		for(i=0; i<NREG; i++) {
-			if(v & (1<<i)) {
-				if(str[0] == 0)
-					strcat(str, "[R");
-				else
-					strcat(str, ",R");
-				sprint(strchr(str, 0), "%d", i);
-			}
-		}
-		strcat(str, "]");
-	}
-	return fmtstrcpy(fp, str);
-}
-
-static int
-DSconv(Fmt *fp)
-{
-	int i, c;
-	char str[STRINGSZ], *p, *a;
-
-	a = va_arg(fp->args, char*);
-	p = str;
-	for(i=0; i<NSNAME; i++) {
-		c = a[i] & 0xff;
-		if(c >= 'a' && c <= 'z' ||
-		   c >= 'A' && c <= 'Z' ||
-		   c >= '0' && c <= '9' ||
-		   c == ' ' || c == '%') {
-			*p++ = c;
-			continue;
-		}
-		*p++ = '\\';
-		switch(c) {
-		case 0:
-			*p++ = 'z';
-			continue;
-		case '\\':
-		case '"':
-			*p++ = c;
-			continue;
-		case '\n':
-			*p++ = 'n';
-			continue;
-		case '\t':
-			*p++ = 't';
-			continue;
-		case '\r':
-			*p++ = 'r';
-			continue;
-		case '\f':
-			*p++ = 'f';
-			continue;
-		}
-		*p++ = (c>>6) + '0';
-		*p++ = ((c>>3) & 7) + '0';
-		*p++ = (c & 7) + '0';
-	}
-	*p = 0;
-	return fmtstrcpy(fp, str);
-}
-
-static int
-Rconv(Fmt *fp)
-{
-	int r;
-	char str[STRINGSZ];
-
-	r = va_arg(fp->args, int);
-	sprint(str, "R%d", r);
-	return fmtstrcpy(fp, str);
-}
-
-static int
-DRconv(Fmt *fp)
-{
-	char *s;
-	int a;
-
-	a = va_arg(fp->args, int);
-	s = "C_??";
-	if(a >= C_NONE && a <= C_NCLASS)
-		s = cnames5[a];
-	return fmtstrcpy(fp, s);
-}
-
-static int
-Mconv(Fmt *fp)
-{
-	char str[STRINGSZ];
-	Addr *a;
-	LSym *s;
-
-	a = va_arg(fp->args, Addr*);
-	s = a->sym;
-	if(s == nil) {
-		sprint(str, "%d", (int)a->offset);
-		goto out;
-	}
-	switch(a->name) {
-	default:
-		sprint(str, "GOK-name(%d)", a->name);
-		break;
-
-	case D_NONE:
-		sprint(str, "%lld", a->offset);
-		break;
-
-	case D_EXTERN:
-		sprint(str, "%s+%d(SB)", s->name, (int)a->offset);
-		break;
-
-	case D_STATIC:
-		sprint(str, "%s<>+%d(SB)", s->name, (int)a->offset);
-		break;
-
-	case D_AUTO:
-		sprint(str, "%s-%d(SP)", s->name, (int)-a->offset);
-		break;
-
-	case D_PARAM:
-		sprint(str, "%s+%d(FP)", s->name, (int)a->offset);
-		break;
-	}
-out:
-	return fmtstrcpy(fp, str);
-}
diff --git a/src/liblink/list6.c b/src/liblink/list6.c
deleted file mode 100644
index 0635fdf..0000000
--- a/src/liblink/list6.c
+++ /dev/null
@@ -1,406 +0,0 @@
-// Inferno utils/6c/list.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6c/list.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <link.h>
-#include "../cmd/6l/6.out.h"
-
-//
-// Format conversions
-//	%A int		Opcodes (instruction mnemonics)
-//
-//	%D Addr*	Addresses (instruction operands)
-//		Flags: "%lD": seperate the high and low words of a constant by "-"
-//
-//	%P Prog*	Instructions
-//
-//	%R int		Registers
-//
-//	%$ char*	String constant addresses (for internal use only)
-
-static int	Aconv(Fmt *fp);
-static int	Dconv(Fmt *fp);
-static int	Pconv(Fmt *fp);
-static int	Rconv(Fmt *fp);
-static int	DSconv(Fmt *fp);
-
-enum
-{
-	STRINGSZ = 1000
-};
-
-#pragma	varargck	type	"$"	char*
-
-void
-listinit6(void)
-{
-	fmtinstall('A', Aconv);
-	fmtinstall('D', Dconv);
-	fmtinstall('P', Pconv);
-	fmtinstall('R', Rconv);
-
-	// for internal use
-	fmtinstall('$', DSconv);
-}
-
-static	Prog*	bigP;
-
-static int
-Pconv(Fmt *fp)
-{
-	char str[STRINGSZ];
-	Prog *p;
-
-	p = va_arg(fp->args, Prog*);
-	bigP = p;
-	switch(p->as) {
-	case ADATA:
-		sprint(str, "%.5lld (%L)	%A	%D/%d,%D",
-			p->pc, p->lineno, p->as, &p->from, p->from.scale, &p->to);
-		break;
-
-	case ATEXT:
-		if(p->from.scale) {
-			sprint(str, "%.5lld (%L)	%A	%D,%d,%lD",
-				p->pc, p->lineno, p->as, &p->from, p->from.scale, &p->to);
-			break;
-		}
-		sprint(str, "%.5lld (%L)	%A	%D,%lD",
-			p->pc, p->lineno, p->as, &p->from, &p->to);
-		break;
-
-	default:
-		sprint(str, "%.5lld (%L)	%A	%D,%D",
-			p->pc, p->lineno, p->as, &p->from, &p->to);
-		break;
-	}
-	bigP = nil;
-	return fmtstrcpy(fp, str);
-}
-
-static int
-Aconv(Fmt *fp)
-{
-	int i;
-
-	i = va_arg(fp->args, int);
-	return fmtstrcpy(fp, anames6[i]);
-}
-
-static int
-Dconv(Fmt *fp)
-{
-	char str[STRINGSZ], s[STRINGSZ];
-	Addr *a;
-	int i;
-
-	a = va_arg(fp->args, Addr*);
-	i = a->type;
-
-	if(fp->flags & FmtLong) {
-		if(i == D_CONST)
-			sprint(str, "$%lld-%lld", a->offset&0xffffffffLL, a->offset>>32);
-		else {
-			// ATEXT dst is not constant
-			sprint(str, "!!%D", a);
-		}
-		goto brk;
-	}
-
-	if(i >= D_INDIR) {
-		if(a->offset)
-			sprint(str, "%lld(%R)", a->offset, i-D_INDIR);
-		else
-			sprint(str, "(%R)", i-D_INDIR);
-		goto brk;
-	}
-	switch(i) {
-	default:
-		if(a->offset)
-			sprint(str, "$%lld,%R", a->offset, i);
-		else
-			sprint(str, "%R", i);
-		break;
-
-	case D_NONE:
-		str[0] = 0;
-		break;
-
-	case D_BRANCH:
-		if(a->sym != nil)
-			sprint(str, "%s(SB)", a->sym->name);
-		else if(bigP != nil && bigP->pcond != nil)
-			sprint(str, "%lld", bigP->pcond->pc);
-		else if(a->u.branch != nil)
-			sprint(str, "%lld", a->u.branch->pc);
-		else
-			sprint(str, "%lld(PC)", a->offset);
-		break;
-
-	case D_EXTERN:
-		sprint(str, "%s+%lld(SB)", a->sym->name, a->offset);
-		break;
-
-	case D_STATIC:
-		sprint(str, "%s<>+%lld(SB)", a->sym->name, a->offset);
-		break;
-
-	case D_AUTO:
-		if(a->sym)
-			sprint(str, "%s+%lld(SP)", a->sym->name, a->offset);
-		else
-			sprint(str, "%lld(SP)", a->offset);
-		break;
-
-	case D_PARAM:
-		if(a->sym)
-			sprint(str, "%s+%lld(FP)", a->sym->name, a->offset);
-		else
-			sprint(str, "%lld(FP)", a->offset);
-		break;
-
-	case D_CONST:
-		sprint(str, "$%lld", a->offset);
-		break;
-
-	case D_FCONST:
-		sprint(str, "$(%.17g)", a->u.dval);
-		break;
-
-	case D_SCONST:
-		sprint(str, "$\"%$\"", a->u.sval);
-		break;
-
-	case D_ADDR:
-		a->type = a->index;
-		a->index = D_NONE;
-		sprint(str, "$%D", a);
-		a->index = a->type;
-		a->type = D_ADDR;
-		goto conv;
-	}
-brk:
-	if(a->index != D_NONE) {
-		sprint(s, "(%R*%d)", (int)a->index, (int)a->scale);
-		strcat(str, s);
-	}
-conv:
-	return fmtstrcpy(fp, str);
-}
-
-static char*	regstr[] =
-{
-	"AL",	/* [D_AL] */
-	"CL",
-	"DL",
-	"BL",
-	"SPB",
-	"BPB",
-	"SIB",
-	"DIB",
-	"R8B",
-	"R9B",
-	"R10B",
-	"R11B",
-	"R12B",
-	"R13B",
-	"R14B",
-	"R15B",
-
-	"AX",	/* [D_AX] */
-	"CX",
-	"DX",
-	"BX",
-	"SP",
-	"BP",
-	"SI",
-	"DI",
-	"R8",
-	"R9",
-	"R10",
-	"R11",
-	"R12",
-	"R13",
-	"R14",
-	"R15",
-
-	"AH",
-	"CH",
-	"DH",
-	"BH",
-
-	"F0",	/* [D_F0] */
-	"F1",
-	"F2",
-	"F3",
-	"F4",
-	"F5",
-	"F6",
-	"F7",
-
-	"M0",
-	"M1",
-	"M2",
-	"M3",
-	"M4",
-	"M5",
-	"M6",
-	"M7",
-
-	"X0",
-	"X1",
-	"X2",
-	"X3",
-	"X4",
-	"X5",
-	"X6",
-	"X7",
-	"X8",
-	"X9",
-	"X10",
-	"X11",
-	"X12",
-	"X13",
-	"X14",
-	"X15",
-
-	"CS",	/* [D_CS] */
-	"SS",
-	"DS",
-	"ES",
-	"FS",
-	"GS",
-
-	"GDTR",	/* [D_GDTR] */
-	"IDTR",	/* [D_IDTR] */
-	"LDTR",	/* [D_LDTR] */
-	"MSW",	/* [D_MSW] */
-	"TASK",	/* [D_TASK] */
-
-	"CR0",	/* [D_CR] */
-	"CR1",
-	"CR2",
-	"CR3",
-	"CR4",
-	"CR5",
-	"CR6",
-	"CR7",
-	"CR8",
-	"CR9",
-	"CR10",
-	"CR11",
-	"CR12",
-	"CR13",
-	"CR14",
-	"CR15",
-
-	"DR0",	/* [D_DR] */
-	"DR1",
-	"DR2",
-	"DR3",
-	"DR4",
-	"DR5",
-	"DR6",
-	"DR7",
-
-	"TR0",	/* [D_TR] */
-	"TR1",
-	"TR2",
-	"TR3",
-	"TR4",
-	"TR5",
-	"TR6",
-	"TR7",
-
-	"TLS",	/* [D_TLS] */
-	"NONE",	/* [D_NONE] */
-};
-
-static int
-Rconv(Fmt *fp)
-{
-	char str[STRINGSZ];
-	int r;
-
-	r = va_arg(fp->args, int);
-	if(r >= D_AL && r <= D_NONE)
-		sprint(str, "%s", regstr[r-D_AL]);
-	else
-		sprint(str, "gok(%d)", r);
-
-	return fmtstrcpy(fp, str);
-}
-
-static int
-DSconv(Fmt *fp)
-{
-	int i, c;
-	char str[STRINGSZ], *p, *a;
-
-	a = va_arg(fp->args, char*);
-	p = str;
-	for(i=0; i<sizeof(double); i++) {
-		c = a[i] & 0xff;
-		if(c >= 'a' && c <= 'z' ||
-		   c >= 'A' && c <= 'Z' ||
-		   c >= '0' && c <= '9') {
-			*p++ = c;
-			continue;
-		}
-		*p++ = '\\';
-		switch(c) {
-		default:
-			if(c < 040 || c >= 0177)
-				break;	/* not portable */
-			p[-1] = c;
-			continue;
-		case 0:
-			*p++ = 'z';
-			continue;
-		case '\\':
-		case '"':
-			*p++ = c;
-			continue;
-		case '\n':
-			*p++ = 'n';
-			continue;
-		case '\t':
-			*p++ = 't';
-			continue;
-		}
-		*p++ = (c>>6) + '0';
-		*p++ = ((c>>3) & 7) + '0';
-		*p++ = (c & 7) + '0';
-	}
-	*p = 0;
-	return fmtstrcpy(fp, str);
-}
diff --git a/src/liblink/list8.c b/src/liblink/list8.c
deleted file mode 100644
index 63d96b9..0000000
--- a/src/liblink/list8.c
+++ /dev/null
@@ -1,354 +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 at 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 at 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.
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <link.h>
-#include "../cmd/8l/8.out.h"
-
-static int	Aconv(Fmt *fp);
-static int	Dconv(Fmt *fp);
-static int	Pconv(Fmt *fp);
-static int	Rconv(Fmt *fp);
-static int	DSconv(Fmt *fp);
-
-enum
-{
-	STRINGSZ = 1000
-};
-
-#pragma	varargck	type	"$"	char*
-
-void
-listinit8(void)
-{
-	fmtinstall('A', Aconv);
-	fmtinstall('D', Dconv);
-	fmtinstall('P', Pconv);
-	fmtinstall('R', Rconv);
-
-	// for internal use
-	fmtinstall('$', DSconv);
-}
-
-static	Prog*	bigP;
-
-static int
-Pconv(Fmt *fp)
-{
-	char str[STRINGSZ];
-	Prog *p;
-
-	p = va_arg(fp->args, Prog*);
-	bigP = p;
-	switch(p->as) {
-	case ADATA:
-		sprint(str, "%.5lld (%L)	%A	%D/%d,%D",
-			p->pc, p->lineno, p->as, &p->from, p->from.scale, &p->to);
-		break;
-
-	case ATEXT:
-		if(p->from.scale) {
-			sprint(str, "%.5lld (%L)	%A	%D,%d,%lD",
-				p->pc, p->lineno, p->as, &p->from, p->from.scale, &p->to);
-			break;
-		}
-		sprint(str, "%.5lld (%L)	%A	%D,%lD",
-			p->pc, p->lineno, p->as, &p->from, &p->to);
-		break;
-
-	default:
-		sprint(str, "%.5lld (%L)	%A	%D,%D",
-			p->pc, p->lineno, p->as, &p->from, &p->to);
-		break;
-	}
-	bigP = nil;
-	return fmtstrcpy(fp, str);
-}
-
-static int
-Aconv(Fmt *fp)
-{
-	int i;
-
-	i = va_arg(fp->args, int);
-	return fmtstrcpy(fp, anames8[i]);
-}
-
-static int
-Dconv(Fmt *fp)
-{
-	char str[STRINGSZ], s[STRINGSZ];
-	Addr *a;
-	int i;
-
-	a = va_arg(fp->args, Addr*);
-	i = a->type;
-
-	if(fp->flags & FmtLong) {
-		if(i == D_CONST2)
-			sprint(str, "$%lld-%d", a->offset, a->offset2);
-		else {
-			// ATEXT dst is not constant
-			sprint(str, "!!%D", a);
-		}
-		goto brk;
-	}
-
-	if(i >= D_INDIR) {
-		if(a->offset)
-			sprint(str, "%lld(%R)", a->offset, i-D_INDIR);
-		else
-			sprint(str, "(%R)", i-D_INDIR);
-		goto brk;
-	}
-	switch(i) {
-	default:
-		if(a->offset)
-			sprint(str, "$%lld,%R", a->offset, i);
-		else
-			sprint(str, "%R", i);
-		break;
-
-	case D_NONE:
-		str[0] = 0;
-		break;
-
-	case D_BRANCH:
-		if(a->sym != nil)
-			sprint(str, "%s(SB)", a->sym->name);
-		else if(bigP != nil && bigP->pcond != nil)
-			sprint(str, "%lld", bigP->pcond->pc);
-		else if(a->u.branch != nil)
-			sprint(str, "%lld", a->u.branch->pc);
-		else
-			sprint(str, "%lld(PC)", a->offset);
-		break;
-
-	case D_EXTERN:
-		sprint(str, "%s+%lld(SB)", a->sym->name, a->offset);
-		break;
-
-	case D_STATIC:
-		sprint(str, "%s<>+%lld(SB)", a->sym->name, a->offset);
-		break;
-
-	case D_AUTO:
-		if(a->sym)
-			sprint(str, "%s+%lld(SP)", a->sym->name, a->offset);
-		else
-			sprint(str, "%lld(SP)", a->offset);
-		break;
-
-	case D_PARAM:
-		if(a->sym)
-			sprint(str, "%s+%lld(FP)", a->sym->name, a->offset);
-		else
-			sprint(str, "%lld(FP)", a->offset);
-		break;
-
-	case D_CONST:
-		sprint(str, "$%lld", a->offset);
-		break;
-
-	case D_CONST2:
-		if(!(fp->flags & FmtLong)) {
-			// D_CONST2 outside of ATEXT should not happen
-			sprint(str, "!!$%lld-%d", a->offset, a->offset2);
-		}
-		break;
-
-	case D_FCONST:
-		sprint(str, "$(%.17g)", a->u.dval);
-		break;
-
-	case D_SCONST:
-		sprint(str, "$\"%$\"", a->u.sval);
-		break;
-
-	case D_ADDR:
-		a->type = a->index;
-		a->index = D_NONE;
-		sprint(str, "$%D", a);
-		a->index = a->type;
-		a->type = D_ADDR;
-		goto conv;
-	}
-brk:
-	if(a->index != D_NONE) {
-		sprint(s, "(%R*%d)", (int)a->index, (int)a->scale);
-		strcat(str, s);
-	}
-conv:
-	return fmtstrcpy(fp, str);
-}
-
-static char*	regstr[] =
-{
-	"AL",	/* [D_AL] */
-	"CL",
-	"DL",
-	"BL",
-	"AH",
-	"CH",
-	"DH",
-	"BH",
-
-	"AX",	/* [D_AX] */
-	"CX",
-	"DX",
-	"BX",
-	"SP",
-	"BP",
-	"SI",
-	"DI",
-
-	"F0",	/* [D_F0] */
-	"F1",
-	"F2",
-	"F3",
-	"F4",
-	"F5",
-	"F6",
-	"F7",
-
-	"CS",	/* [D_CS] */
-	"SS",
-	"DS",
-	"ES",
-	"FS",
-	"GS",
-
-	"GDTR",	/* [D_GDTR] */
-	"IDTR",	/* [D_IDTR] */
-	"LDTR",	/* [D_LDTR] */
-	"MSW",	/* [D_MSW] */
-	"TASK",	/* [D_TASK] */
-
-	"CR0",	/* [D_CR] */
-	"CR1",
-	"CR2",
-	"CR3",
-	"CR4",
-	"CR5",
-	"CR6",
-	"CR7",
-
-	"DR0",	/* [D_DR] */
-	"DR1",
-	"DR2",
-	"DR3",
-	"DR4",
-	"DR5",
-	"DR6",
-	"DR7",
-
-	"TR0",	/* [D_TR] */
-	"TR1",
-	"TR2",
-	"TR3",
-	"TR4",
-	"TR5",
-	"TR6",
-	"TR7",
-
-	"X0",	/* [D_X0] */
-	"X1",
-	"X2",
-	"X3",
-	"X4",
-	"X5",
-	"X6",
-	"X7",
-
-	"TLS",	/* [D_TLS] */
-	"NONE",	/* [D_NONE] */
-};
-
-static int
-Rconv(Fmt *fp)
-{
-	char str[STRINGSZ];
-	int r;
-
-	r = va_arg(fp->args, int);
-	if(r >= D_AL && r <= D_NONE)
-		sprint(str, "%s", regstr[r-D_AL]);
-	else
-		sprint(str, "gok(%d)", r);
-
-	return fmtstrcpy(fp, str);
-}
-
-static int
-DSconv(Fmt *fp)
-{
-	int i, c;
-	char str[STRINGSZ], *p, *a;
-
-	a = va_arg(fp->args, char*);
-	p = str;
-	for(i=0; i<sizeof(double); i++) {
-		c = a[i] & 0xff;
-		if(c >= 'a' && c <= 'z' ||
-		   c >= 'A' && c <= 'Z' ||
-		   c >= '0' && c <= '9') {
-			*p++ = c;
-			continue;
-		}
-		*p++ = '\\';
-		switch(c) {
-		default:
-			if(c < 040 || c >= 0177)
-				break;	/* not portable */
-			p[-1] = c;
-			continue;
-		case 0:
-			*p++ = 'z';
-			continue;
-		case '\\':
-		case '"':
-			*p++ = c;
-			continue;
-		case '\n':
-			*p++ = 'n';
-			continue;
-		case '\t':
-			*p++ = 't';
-			continue;
-		}
-		*p++ = (c>>6) + '0';
-		*p++ = ((c>>3) & 7) + '0';
-		*p++ = (c & 7) + '0';
-	}
-	*p = 0;
-	return fmtstrcpy(fp, str);
-}
diff --git a/src/liblink/obj.c b/src/liblink/obj.c
deleted file mode 100644
index b8083b0..0000000
--- a/src/liblink/obj.c
+++ /dev/null
@@ -1,296 +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 <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <link.h>
-
-enum
-{
-	HISTSZ = 10,
-	NSYM = 50,
-};
-
-int
-linklinefmt(Link *ctxt, Fmt *fp)
-{
-	struct
-	{
-		Hist*	incl;	/* start of this include file */
-		int32	idel;	/* delta line number to apply to include */
-		Hist*	line;	/* start of this #line directive */
-		int32	ldel;	/* delta line number to apply to #line */
-	} a[HISTSZ];
-	int32 lno, d;
-	int i, n;
-	Hist *h;
-
-	lno = va_arg(fp->args, 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) {
-			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 = 0;
-				}
-				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;
-
-	for(i=n-1; i>=0; i--) {
-		if(i != n-1) {
-			if(fp->flags & ~(FmtWidth|FmtPrec))
-				break;
-			fmtprint(fp, " ");
-		}
-		if(ctxt->debugline || (fp->flags&FmtLong))
-			fmtprint(fp, "%s/", ctxt->pathname);
-		if(a[i].line)
-			fmtprint(fp, "%s:%d[%s:%d]",
-				a[i].line->name, lno-a[i].ldel+1,
-				a[i].incl->name, lno-a[i].idel+1);
-		else
-			fmtprint(fp, "%s:%d",
-				a[i].incl->name, lno-a[i].idel+1);
-		lno = a[i].incl->line - 1;	// now print out start of this file
-	}
-	if(n == 0)
-		fmtprint(fp, "<unknown line number>");
-
-	return 0;
-}
-
-// 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.
-static int
-haspathprefix(char *s, char *t)
-{
-	int i, cs, ct;
-
-	if(t == nil)
-		return 0;
-	for(i=0; t[i]; i++) {
-		cs = s[i];
-		ct = t[i];
-		if('A' <= cs && cs <= 'Z')
-			cs += 'a' - 'A';
-		if('A' <= ct && ct <= 'Z')
-			ct += 'a' - 'A';
-		if(cs == '\\')
-			cs = '/';
-		if(ct == '\\')
-			ct = '/';
-		if(cs != ct)
-			return 0;
-	}
-	return s[i] == '\0' || s[i] == '/' || s[i] == '\\';
-}
-
-// 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.
-void
-linkgetline(Link *ctxt, int32 line, LSym **f, int32 *l)
-{
-	struct
-	{
-		Hist*	incl;	/* start of this include file */
-		int32	idel;	/* delta line number to apply to include */
-		Hist*	line;	/* start of this #line directive */
-		int32	ldel;	/* delta line number to apply to #line */
-	} a[HISTSZ];
-	int32 lno, d, dlno;
-	int n;
-	Hist *h;
-	char buf[1024], buf1[1024], *file;
-
-	lno = 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) {
-			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 = 0;
-				}
-				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) {
-		*f = linklookup(ctxt, "??", HistVersion);
-		*l = 0;
-		return;
-	}
-	
-	n--;
-	if(a[n].line) {
-		file = a[n].line->name;
-		dlno = a[n].ldel-1;
-	} else {
-		file = a[n].incl->name;
-		dlno = a[n].idel-1;
-	}
-	if((!ctxt->windows && file[0] == '/') || (ctxt->windows && file[1] == ':') || file[0] == '<')
-		snprint(buf, sizeof buf, "%s", file);
-	else
-		snprint(buf, sizeof buf, "%s/%s", ctxt->pathname, file);
-
-	// Remove leading ctxt->trimpath, or else rewrite $GOROOT to $GOROOT_FINAL.
-	if(haspathprefix(buf, ctxt->trimpath)) {
-		if(strlen(buf) == strlen(ctxt->trimpath))
-			strcpy(buf, "??");
-		else {
-			snprint(buf1, sizeof buf1, "%s", buf+strlen(ctxt->trimpath)+1);
-			if(buf1[0] == '\0')
-				strcpy(buf1, "??");
-			strcpy(buf, buf1);
-		}
-	} else if(ctxt->goroot_final != nil && haspathprefix(buf, ctxt->goroot)) {
-		snprint(buf1, sizeof buf1, "%s%s", ctxt->goroot_final, buf+strlen(ctxt->goroot));
-		strcpy(buf, buf1);
-	}
-
-	lno -= dlno;
-	*f = linklookup(ctxt, buf, HistVersion);
-	*l = lno;
-}
-
-void
-linklinehist(Link *ctxt, int lineno, char *f, int offset)
-{
-	Hist *h;
-
-	if(0) // debug['f']
-		if(f) {
-			if(offset)
-				print("%4d: %s (#line %d)\n", lineno, f, offset);
-			else
-				print("%4d: %s\n", lineno, f);
-		} else
-			print("%4d: <pop>\n", lineno);
-
-	h = malloc(sizeof(Hist));
-	memset(h, 0, sizeof *h);
-	h->name = f;
-	h->line = lineno;
-	h->offset = offset;
-	h->link = nil;
-	if(ctxt->ehist == nil) {
-		ctxt->hist = h;
-		ctxt->ehist = h;
-		return;
-	}
-	ctxt->ehist->link = h;
-	ctxt->ehist = h;
-}
-
-void
-linkprfile(Link *ctxt, int32 l)
-{
-	int i, n;
-	Hist a[HISTSZ], *h;
-	int32 d;
-
-	n = 0;
-	for(h = ctxt->hist; h != nil; h = h->link) {
-		if(l < h->line)
-			break;
-		if(h->name) {
-			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++)
-		print("%s:%ld ", a[i].name, (long)(l-a[i].line+a[i].offset+1));
-}
-
-/*
- * start a new Prog list.
- */
-Plist*
-linknewplist(Link *ctxt)
-{
-	Plist *pl;
-
-	pl = malloc(sizeof(*pl));
-	memset(pl, 0, sizeof *pl);
-	if(ctxt->plist == nil)
-		ctxt->plist = pl;
-	else
-		ctxt->plast->link = pl;
-	ctxt->plast = pl;
-
-	return pl;
-}
diff --git a/src/liblink/obj5.c b/src/liblink/obj5.c
deleted file mode 100644
index d7f2714..0000000
--- a/src/liblink/obj5.c
+++ /dev/null
@@ -1,1094 +0,0 @@
-// Derived from Inferno utils/5c/swt.c
-// http://code.google.com/p/inferno-os/source/browse/utils/5c/swt.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <link.h>
-#include "../cmd/5l/5.out.h"
-#include "../runtime/stack.h"
-
-static Prog zprg = {
-	.as = AGOK,
-	.scond = C_SCOND_NONE,
-	.reg = NREG,
-	.from = {
-		.name = D_NONE,
-		.type = D_NONE,
-		.reg = NREG,
-	},
-	.to = {
-		.name = D_NONE,
-		.type = D_NONE,
-		.reg = NREG,
-	},
-};
-
-static int
-symtype(Addr *a)
-{
-	return a->name;
-}
-
-static int
-isdata(Prog *p)
-{
-	return p->as == ADATA || p->as == AGLOBL;
-}
-
-static int
-iscall(Prog *p)
-{
-	return p->as == ABL;
-}
-
-static int
-datasize(Prog *p)
-{
-	return p->reg;
-}
-
-static int
-textflag(Prog *p)
-{
-	return p->reg;
-}
-
-static void
-settextflag(Prog *p, int f)
-{
-	p->reg = f;
-}
-
-static void
-progedit(Link *ctxt, Prog *p)
-{
-	char literal[64];
-	LSym *s;
-	static LSym *tlsfallback;
-
-	p->from.class = 0;
-	p->to.class = 0;
-
-	// Rewrite B/BL to symbol as D_BRANCH.
-	switch(p->as) {
-	case AB:
-	case ABL:
-	case ADUFFZERO:
-	case ADUFFCOPY:
-		if(p->to.type == D_OREG && (p->to.name == D_EXTERN || p->to.name == D_STATIC) && p->to.sym != nil)
-			p->to.type = D_BRANCH;
-		break;
-	}
-
-	// Replace TLS register fetches on older ARM procesors.
-	switch(p->as) {
-	case AMRC:
-		// Treat MRC 15, 0, <reg>, C13, C0, 3 specially.
-		if((p->to.offset & 0xffff0fff) == 0xee1d0f70) {
-			// Because the instruction might be rewriten to a BL which returns in R0
-			// the register must be zero.
-		       	if ((p->to.offset & 0xf000) != 0)
-				ctxt->diag("%L: TLS MRC instruction must write to R0 as it might get translated into a BL instruction", p->lineno);
-
-			if(ctxt->goarm < 7) {
-				// Replace it with BL runtime.read_tls_fallback(SB) for ARM CPUs that lack the tls extension.
-				if(tlsfallback == nil)
-					tlsfallback = linklookup(ctxt, "runtime.read_tls_fallback", 0);
-				// MOVW	LR, R11
-				p->as = AMOVW;
-				p->from.type = D_REG;
-				p->from.reg = REGLINK;
-				p->to.type = D_REG;
-				p->to.reg = REGTMP;
-
-				// BL	runtime.read_tls_fallback(SB)
-				p = appendp(ctxt, p);
-				p->as = ABL;
-				p->to.type = D_BRANCH;
-				p->to.sym = tlsfallback;
-				p->to.offset = 0;
-
-				// MOVW	R11, LR
-				p = appendp(ctxt, p);
-				p->as = AMOVW;
-				p->from.type = D_REG;
-				p->from.reg = REGTMP;
-				p->to.type = D_REG;
-				p->to.reg = REGLINK;
-				break;
-			}
-		}
-		// Otherwise, MRC/MCR instructions need no further treatment.
-		p->as = AWORD;
-		break;
-	}
-
-	// Rewrite float constants to values stored in memory.
-	switch(p->as) {
-	case AMOVF:
-		if(p->from.type == D_FCONST && chipfloat5(ctxt, p->from.u.dval) < 0 &&
-		   (chipzero5(ctxt, p->from.u.dval) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) {
-			int32 i32;
-			float32 f32;
-			f32 = p->from.u.dval;
-			memmove(&i32, &f32, 4);
-			sprint(literal, "$f32.%08ux", (uint32)i32);
-			s = linklookup(ctxt, literal, 0);
-			if(s->type == 0) {
-				s->type = SRODATA;
-				adduint32(ctxt, s, i32);
-				s->reachable = 0;
-			}
-			p->from.type = D_OREG;
-			p->from.sym = s;
-			p->from.name = D_EXTERN;
-			p->from.offset = 0;
-		}
-		break;
-
-	case AMOVD:
-		if(p->from.type == D_FCONST && chipfloat5(ctxt, p->from.u.dval) < 0 &&
-		   (chipzero5(ctxt, p->from.u.dval) < 0 || (p->scond & C_SCOND) != C_SCOND_NONE)) {
-			int64 i64;
-			memmove(&i64, &p->from.u.dval, 8);
-			sprint(literal, "$f64.%016llux", (uvlong)i64);
-			s = linklookup(ctxt, literal, 0);
-			if(s->type == 0) {
-				s->type = SRODATA;
-				adduint64(ctxt, s, i64);
-				s->reachable = 0;
-			}
-			p->from.type = D_OREG;
-			p->from.sym = s;
-			p->from.name = D_EXTERN;
-			p->from.offset = 0;
-		}
-		break;
-	}
-
-	if(ctxt->flag_shared) {
-		// Shared libraries use R_ARM_TLS_IE32 instead of 
-		// R_ARM_TLS_LE32, replacing the link time constant TLS offset in
-		// runtime.tlsg with an address to a GOT entry containing the 
-		// offset. Rewrite $runtime.tlsg(SB) to runtime.tlsg(SB) to
-		// compensate.
-		if(ctxt->tlsg == nil)
-			ctxt->tlsg = linklookup(ctxt, "runtime.tlsg", 0);
-
-		if(p->from.type == D_CONST && p->from.name == D_EXTERN && p->from.sym == ctxt->tlsg)
-			p->from.type = D_OREG;
-		if(p->to.type == D_CONST && p->to.name == D_EXTERN && p->to.sym == ctxt->tlsg)
-			p->to.type = D_OREG;
-	}
-}
-
-static Prog*
-prg(void)
-{
-	Prog *p;
-
-	p = emallocz(sizeof(*p));
-	*p = zprg;
-	return p;
-}
-
-static	Prog*	stacksplit(Link*, Prog*, int32, int);
-static	void		initdiv(Link*);
-static	void	softfloat(Link*, LSym*);
-
-// Prog.mark
-enum
-{
-	FOLL = 1<<0,
-	LABEL = 1<<1,
-	LEAF = 1<<2,
-};
-
-static void
-linkcase(Prog *casep)
-{
-	Prog *p;
-
-	for(p = casep; p != nil; p = p->link){
-		if(p->as == ABCASE) {
-			for(; p != nil && p->as == ABCASE; p = p->link)
-				p->pcrel = casep;
-			break;
-		}
-	}
-}
-
-static void
-nocache(Prog *p)
-{
-	p->optab = 0;
-	p->from.class = 0;
-	p->to.class = 0;
-}
-
-static void
-addstacksplit(Link *ctxt, LSym *cursym)
-{
-	Prog *p, *pl, *p1, *p2, *q, *q1, *q2;
-	int o;
-	int32 autosize, autoffset;
-	
-	autosize = 0;
-
-	if(ctxt->symmorestack[0] == nil) {
-		ctxt->symmorestack[0] = linklookup(ctxt, "runtime.morestack", 0);
-		ctxt->symmorestack[1] = linklookup(ctxt, "runtime.morestack_noctxt", 0);
-	}
-
-	q = nil;
-	
-	ctxt->cursym = cursym;
-
-	if(cursym->text == nil || cursym->text->link == nil)
-		return;				
-
-	softfloat(ctxt, cursym);
-
-	p = cursym->text;
-	autoffset = p->to.offset;
-	if(autoffset < 0)
-		autoffset = 0;
-	cursym->locals = autoffset;
-	cursym->args = p->to.offset2;
-
-	if(ctxt->debugzerostack) {
-		if(autoffset && !(p->reg&NOSPLIT)) {
-			// MOVW $4(R13), R1
-			p = appendp(ctxt, p);
-			p->as = AMOVW;
-			p->from.type = D_CONST;
-			p->from.reg = 13;
-			p->from.offset = 4;
-			p->to.type = D_REG;
-			p->to.reg = 1;
-	
-			// MOVW $n(R13), R2
-			p = appendp(ctxt, p);
-			p->as = AMOVW;
-			p->from.type = D_CONST;
-			p->from.reg = 13;
-			p->from.offset = 4 + autoffset;
-			p->to.type = D_REG;
-			p->to.reg = 2;
-	
-			// MOVW $0, R3
-			p = appendp(ctxt, p);
-			p->as = AMOVW;
-			p->from.type = D_CONST;
-			p->from.offset = 0;
-			p->to.type = D_REG;
-			p->to.reg = 3;
-	
-			// L:
-			//	MOVW.nil R3, 0(R1) +4
-			//	CMP R1, R2
-			//	BNE L
-			p = pl = appendp(ctxt, p);
-			p->as = AMOVW;
-			p->from.type = D_REG;
-			p->from.reg = 3;
-			p->to.type = D_OREG;
-			p->to.reg = 1;
-			p->to.offset = 4;
-			p->scond |= C_PBIT;
-	
-			p = appendp(ctxt, p);
-			p->as = ACMP;
-			p->from.type = D_REG;
-			p->from.reg = 1;
-			p->reg = 2;
-	
-			p = appendp(ctxt, p);
-			p->as = ABNE;
-			p->to.type = D_BRANCH;
-			p->pcond = pl;
-		}
-	}
-
-	/*
-	 * find leaf subroutines
-	 * strip NOPs
-	 * expand RET
-	 * expand BECOME pseudo
-	 */
-
-	for(p = cursym->text; p != nil; p = p->link) {
-		switch(p->as) {
-		case ACASE:
-			if(ctxt->flag_shared)
-				linkcase(p);
-			break;
-
-		case ATEXT:
-			p->mark |= LEAF;
-			break;
-
-		case ARET:
-			break;
-
-		case ADIV:
-		case ADIVU:
-		case AMOD:
-		case AMODU:
-			q = p;
-			if(ctxt->sym_div == nil)
-				initdiv(ctxt);
-			cursym->text->mark &= ~LEAF;
-			continue;
-
-		case ANOP:
-			q1 = p->link;
-			q->link = q1;		/* q is non-nop */
-			if(q1 != nil)
-				q1->mark |= p->mark;
-			continue;
-
-		case ABL:
-		case ABX:
-		case ADUFFZERO:
-		case ADUFFCOPY:
-			cursym->text->mark &= ~LEAF;
-
-		case ABCASE:
-		case AB:
-
-		case ABEQ:
-		case ABNE:
-		case ABCS:
-		case ABHS:
-		case ABCC:
-		case ABLO:
-		case ABMI:
-		case ABPL:
-		case ABVS:
-		case ABVC:
-		case ABHI:
-		case ABLS:
-		case ABGE:
-		case ABLT:
-		case ABGT:
-		case ABLE:
-			q1 = p->pcond;
-			if(q1 != nil) {
-				while(q1->as == ANOP) {
-					q1 = q1->link;
-					p->pcond = q1;
-				}
-			}
-			break;
-		}
-		q = p;
-	}
-
-	for(p = cursym->text; p != nil; p = p->link) {
-		o = p->as;
-		switch(o) {
-		case ATEXT:
-			autosize = p->to.offset + 4;
-			if(autosize <= 4)
-			if(cursym->text->mark & LEAF) {
-				p->to.offset = -4;
-				autosize = 0;
-			}
-
-			if(!autosize && !(cursym->text->mark & LEAF)) {
-				if(ctxt->debugvlog) {
-					Bprint(ctxt->bso, "save suppressed in: %s\n",
-						cursym->name);
-					Bflush(ctxt->bso);
-				}
-				cursym->text->mark |= LEAF;
-			}
-			if(cursym->text->mark & LEAF) {
-				cursym->leaf = 1;
-				if(!autosize)
-					break;
-			}
-
-			if(!(p->reg & NOSPLIT))
-				p = stacksplit(ctxt, p, autosize, !(cursym->text->reg&NEEDCTXT)); // emit split check
-			
-			// MOVW.W		R14,$-autosize(SP)
-			p = appendp(ctxt, p);
-			p->as = AMOVW;
-			p->scond |= C_WBIT;
-			p->from.type = D_REG;
-			p->from.reg = REGLINK;
-			p->to.type = D_OREG;
-			p->to.offset = -autosize;
-			p->to.reg = REGSP;
-			p->spadj = autosize;
-			
-			if(cursym->text->reg & WRAPPER) {
-				// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
-				//
-				//	MOVW g_panic(g), R1
-				//	CMP $0, R1
-				//	B.EQ end
-				//	MOVW panic_argp(R1), R2
-				//	ADD $(autosize+4), R13, R3
-				//	CMP R2, R3
-				//	B.NE end
-				//	ADD $4, R13, R4
-				//	MOVW R4, panic_argp(R1)
-				// end:
-				//	NOP
-				//
-				// The NOP is needed to give the jumps somewhere to land.
-				// It is a liblink NOP, not an ARM NOP: it encodes to 0 instruction bytes.
-
-				p = appendp(ctxt, p);
-				p->as = AMOVW;
-				p->from.type = D_OREG;
-				p->from.reg = REGG;
-				p->from.offset = 4*ctxt->arch->ptrsize; // G.panic
-				p->to.type = D_REG;
-				p->to.reg = 1;
-			
-				p = appendp(ctxt, p);
-				p->as = ACMP;
-				p->from.type = D_CONST;
-				p->from.offset = 0;
-				p->reg = 1;
-			
-				p = appendp(ctxt, p);
-				p->as = ABEQ;
-				p->to.type = D_BRANCH;
-				p1 = p;
-				
-				p = appendp(ctxt, p);
-				p->as = AMOVW;
-				p->from.type = D_OREG;
-				p->from.reg = 1;
-				p->from.offset = 0; // Panic.argp
-				p->to.type = D_REG;
-				p->to.reg = 2;
-			
-				p = appendp(ctxt, p);
-				p->as = AADD;
-				p->from.type = D_CONST;
-				p->from.offset = autosize+4;
-				p->reg = 13;
-				p->to.type = D_REG;
-				p->to.reg = 3;
-
-				p = appendp(ctxt, p);
-				p->as = ACMP;
-				p->from.type = D_REG;
-				p->from.reg = 2;
-				p->reg = 3;
-
-				p = appendp(ctxt, p);
-				p->as = ABNE;
-				p->to.type = D_BRANCH;
-				p2 = p;
-			
-				p = appendp(ctxt, p);
-				p->as = AADD;
-				p->from.type = D_CONST;
-				p->from.offset = 4;
-				p->reg = 13;
-				p->to.type = D_REG;
-				p->to.reg = 4;
-
-				p = appendp(ctxt, p);
-				p->as = AMOVW;
-				p->from.type = D_REG;
-				p->from.reg = 4;
-				p->to.type = D_OREG;
-				p->to.reg = 1;
-				p->to.offset = 0; // Panic.argp
-
-				p = appendp(ctxt, p);
-				p->as = ANOP;
-				p1->pcond = p;
-				p2->pcond = p;
-			}
-			break;
-
-		case ARET:
-			nocache(p);
-			if(cursym->text->mark & LEAF) {
-				if(!autosize) {
-					p->as = AB;
-					p->from = zprg.from;
-					if(p->to.sym) { // retjmp
-						p->to.type = D_BRANCH;
-					} else {
-						p->to.type = D_OREG;
-						p->to.offset = 0;
-						p->to.reg = REGLINK;
-					}
-					break;
-				}
-			}
-
-			p->as = AMOVW;
-			p->scond |= C_PBIT;
-			p->from.type = D_OREG;
-			p->from.offset = autosize;
-			p->from.reg = REGSP;
-			p->to.type = D_REG;
-			p->to.reg = REGPC;
-			// If there are instructions following
-			// this ARET, they come from a branch
-			// with the same stackframe, so no spadj.
-			
-			if(p->to.sym) { // retjmp
-				p->to.reg = REGLINK;
-				q2 = appendp(ctxt, p);
-				q2->as = AB;
-				q2->to.type = D_BRANCH;
-				q2->to.sym = p->to.sym;
-				p->to.sym = nil;
-				p = q2;
-			}
-			break;
-
-		case AADD:
-			if(p->from.type == D_CONST && p->from.reg == NREG && p->to.type == D_REG && p->to.reg == REGSP)
-				p->spadj = -p->from.offset;
-			break;
-
-		case ASUB:
-			if(p->from.type == D_CONST && p->from.reg == NREG && p->to.type == D_REG && p->to.reg == REGSP)
-				p->spadj = p->from.offset;
-			break;
-
-		case ADIV:
-		case ADIVU:
-		case AMOD:
-		case AMODU:
-			if(ctxt->debugdivmod)
-				break;
-			if(p->from.type != D_REG)
-				break;
-			if(p->to.type != D_REG)
-				break;
-			q1 = p;
-
-			/* MOV a,4(SP) */
-			p = appendp(ctxt, p);
-			p->as = AMOVW;
-			p->lineno = q1->lineno;
-			p->from.type = D_REG;
-			p->from.reg = q1->from.reg;
-			p->to.type = D_OREG;
-			p->to.reg = REGSP;
-			p->to.offset = 4;
-
-			/* MOV b,REGTMP */
-			p = appendp(ctxt, p);
-			p->as = AMOVW;
-			p->lineno = q1->lineno;
-			p->from.type = D_REG;
-			p->from.reg = q1->reg;
-			if(q1->reg == NREG)
-				p->from.reg = q1->to.reg;
-			p->to.type = D_REG;
-			p->to.reg = REGTMP;
-			p->to.offset = 0;
-
-			/* CALL appropriate */
-			p = appendp(ctxt, p);
-			p->as = ABL;
-			p->lineno = q1->lineno;
-			p->to.type = D_BRANCH;
-			switch(o) {
-			case ADIV:
-				p->to.sym = ctxt->sym_div;
-				break;
-			case ADIVU:
-				p->to.sym = ctxt->sym_divu;
-				break;
-			case AMOD:
-				p->to.sym = ctxt->sym_mod;
-				break;
-			case AMODU:
-				p->to.sym = ctxt->sym_modu;
-				break;
-			}
-
-			/* MOV REGTMP, b */
-			p = appendp(ctxt, p);
-			p->as = AMOVW;
-			p->lineno = q1->lineno;
-			p->from.type = D_REG;
-			p->from.reg = REGTMP;
-			p->from.offset = 0;
-			p->to.type = D_REG;
-			p->to.reg = q1->to.reg;
-
-			/* ADD $8,SP */
-			p = appendp(ctxt, p);
-			p->as = AADD;
-			p->lineno = q1->lineno;
-			p->from.type = D_CONST;
-			p->from.reg = NREG;
-			p->from.offset = 8;
-			p->reg = NREG;
-			p->to.type = D_REG;
-			p->to.reg = REGSP;
-			p->spadj = -8;
-
-			/* Keep saved LR at 0(SP) after SP change. */
-			/* MOVW 0(SP), REGTMP; MOVW REGTMP, -8!(SP) */
-			/* TODO: Remove SP adjustments; see issue 6699. */
-			q1->as = AMOVW;
-			q1->from.type = D_OREG;
-			q1->from.reg = REGSP;
-			q1->from.offset = 0;
-			q1->reg = NREG;
-			q1->to.type = D_REG;
-			q1->to.reg = REGTMP;
-
-			/* SUB $8,SP */
-			q1 = appendp(ctxt, q1);
-			q1->as = AMOVW;
-			q1->from.type = D_REG;
-			q1->from.reg = REGTMP;
-			q1->reg = NREG;
-			q1->to.type = D_OREG;
-			q1->to.reg = REGSP;
-			q1->to.offset = -8;
-			q1->scond |= C_WBIT;
-			q1->spadj = 8;
-
-			break;
-		case AMOVW:
-			if((p->scond & C_WBIT) && p->to.type == D_OREG && p->to.reg == REGSP)
-				p->spadj = -p->to.offset;
-			if((p->scond & C_PBIT) && p->from.type == D_OREG && p->from.reg == REGSP && p->to.reg != REGPC)
-				p->spadj = -p->from.offset;
-			if(p->from.type == D_CONST && p->from.reg == REGSP && p->to.type == D_REG && p->to.reg == REGSP)
-				p->spadj = -p->from.offset;
-			break;
-		}
-	}
-}
-
-static void
-softfloat(Link *ctxt, LSym *cursym)
-{
-	Prog *p, *next;
-	LSym *symsfloat;
-	int wasfloat;
-
-	if(ctxt->goarm > 5)
-		return;
-
-	symsfloat = linklookup(ctxt, "_sfloat", 0);
-
-	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) {
-		switch(p->as) {
-		case AMOVW:
-			if(p->to.type == D_FREG || p->from.type == D_FREG)
-				goto soft;
-			goto notsoft;
-
-		case AMOVWD:
-		case AMOVWF:
-		case AMOVDW:
-		case AMOVFW:
-		case AMOVFD:
-		case AMOVDF:
-		case AMOVF:
-		case AMOVD:
-
-		case ACMPF:
-		case ACMPD:
-		case AADDF:
-		case AADDD:
-		case ASUBF:
-		case ASUBD:
-		case AMULF:
-		case AMULD:
-		case ADIVF:
-		case ADIVD:
-		case ASQRTF:
-		case ASQRTD:
-		case AABSF:
-		case AABSD:
-			goto soft;
-
-		default:
-			goto notsoft;
-		}
-
-	soft:
-		if (!wasfloat || (p->mark&LABEL)) {
-			next = ctxt->arch->prg();
-			*next = *p;
-
-			// BL _sfloat(SB)
-			*p = zprg;
-			p->link = next;
-			p->as = ABL;
- 				p->to.type = D_BRANCH;
-			p->to.sym = symsfloat;
-			p->lineno = next->lineno;
-
-			p = next;
-			wasfloat = 1;
-		}
-		continue;
-
-	notsoft:
-		wasfloat = 0;
-	}
-}
-
-static Prog*
-stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt)
-{
-	// MOVW			g_stackguard(g), R1
-	p = appendp(ctxt, p);
-	p->as = AMOVW;
-	p->from.type = D_OREG;
-	p->from.reg = REGG;
-	p->from.offset = 2*ctxt->arch->ptrsize;	// G.stackguard0
-	if(ctxt->cursym->cfunc)
-		p->from.offset = 3*ctxt->arch->ptrsize;	// G.stackguard1
-	p->to.type = D_REG;
-	p->to.reg = 1;
-	
-	if(framesize <= StackSmall) {
-		// small stack: SP < stackguard
-		//	CMP	stackguard, SP
-		p = appendp(ctxt, p);
-		p->as = ACMP;
-		p->from.type = D_REG;
-		p->from.reg = 1;
-		p->reg = REGSP;
-	} else if(framesize <= StackBig) {
-		// large stack: SP-framesize < stackguard-StackSmall
-		//	MOVW $-framesize(SP), R2
-		//	CMP stackguard, R2
-		p = appendp(ctxt, p);
-		p->as = AMOVW;
-		p->from.type = D_CONST;
-		p->from.reg = REGSP;
-		p->from.offset = -framesize;
-		p->to.type = D_REG;
-		p->to.reg = 2;
-		
-		p = appendp(ctxt, p);
-		p->as = ACMP;
-		p->from.type = D_REG;
-		p->from.reg = 1;
-		p->reg = 2;
-	} 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
-		//	MOVW.NE $StackGuard(SP), R2
-		//	SUB.NE R1, R2
-		//	MOVW.NE $(framesize+(StackGuard-StackSmall)), R3
-		//	CMP.NE R3, R2
-		p = appendp(ctxt, p);
-		p->as = ACMP;
-		p->from.type = D_CONST;
-		p->from.offset = (uint32)StackPreempt;
-		p->reg = 1;
-
-		p = appendp(ctxt, p);
-		p->as = AMOVW;
-		p->from.type = D_CONST;
-		p->from.reg = REGSP;
-		p->from.offset = StackGuard;
-		p->to.type = D_REG;
-		p->to.reg = 2;
-		p->scond = C_SCOND_NE;
-		
-		p = appendp(ctxt, p);
-		p->as = ASUB;
-		p->from.type = D_REG;
-		p->from.reg = 1;
-		p->to.type = D_REG;
-		p->to.reg = 2;
-		p->scond = C_SCOND_NE;
-		
-		p = appendp(ctxt, p);
-		p->as = AMOVW;
-		p->from.type = D_CONST;
-		p->from.offset = framesize + (StackGuard - StackSmall);
-		p->to.type = D_REG;
-		p->to.reg = 3;
-		p->scond = C_SCOND_NE;
-		
-		p = appendp(ctxt, p);
-		p->as = ACMP;
-		p->from.type = D_REG;
-		p->from.reg = 3;
-		p->reg = 2;
-		p->scond = C_SCOND_NE;
-	}
-	
-	// MOVW.LS	R14, R3
-	p = appendp(ctxt, p);
-	p->as = AMOVW;
-	p->scond = C_SCOND_LS;
-	p->from.type = D_REG;
-	p->from.reg = REGLINK;
-	p->to.type = D_REG;
-	p->to.reg = 3;
-
-	// BL.LS		runtime.morestack(SB) // modifies LR, returns with LO still asserted
-	p = appendp(ctxt, p);
-	p->as = ABL;
-	p->scond = C_SCOND_LS;
-	p->to.type = D_BRANCH;
-	if(ctxt->cursym->cfunc)
-		p->to.sym = linklookup(ctxt, "runtime.morestackc", 0);
-	else
-		p->to.sym = ctxt->symmorestack[noctxt];
-	
-	// BLS	start
-	p = appendp(ctxt, p);
-	p->as = ABLS;
-	p->to.type = D_BRANCH;
-	p->pcond = ctxt->cursym->text->link;
-	
-	return p;
-}
-
-static void
-initdiv(Link *ctxt)
-{
-	if(ctxt->sym_div != nil)
-		return;
-	ctxt->sym_div = linklookup(ctxt, "_div", 0);
-	ctxt->sym_divu = linklookup(ctxt, "_divu", 0);
-	ctxt->sym_mod = linklookup(ctxt, "_mod", 0);
-	ctxt->sym_modu = linklookup(ctxt, "_modu", 0);
-}
-
-static void xfol(Link*, Prog*, Prog**);
-
-static void
-follow(Link *ctxt, LSym *s)
-{
-	Prog *firstp, *lastp;
-
-	ctxt->cursym = s;
-
-	firstp = ctxt->arch->prg();
-	lastp = firstp;
-	xfol(ctxt, s->text, &lastp);
-	lastp->link = nil;
-	s->text = firstp->link;
-}
-
-static int
-relinv(int a)
-{
-	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;
-	}
-	sysfatal("unknown relation: %s", anames5[a]);
-	return 0;
-}
-
-static void
-xfol(Link *ctxt, Prog *p, Prog **last)
-{
-	Prog *q, *r;
-	int a, i;
-
-loop:
-	if(p == nil)
-		return;
-	a = p->as;
-	if(a == AB) {
-		q = p->pcond;
-		if(q != nil && q->as != ATEXT) {
-			p->mark |= FOLL;
-			p = q;
-			if(!(p->mark & FOLL))
-				goto loop;
-		}
-	}
-	if(p->mark & FOLL) {
-		for(i=0,q=p; i<4; i++,q=q->link) {
-			if(q == *last || q == nil)
-				break;
-			a = q->as;
-			if(a == ANOP) {
-				i--;
-				continue;
-			}
-			if(a == AB || (a == ARET && q->scond == C_SCOND_NONE) || a == ARFE || a == AUNDEF)
-				goto copy;
-			if(q->pcond == nil || (q->pcond->mark&FOLL))
-				continue;
-			if(a != ABEQ && a != ABNE)
-				continue;
-		copy:
-			for(;;) {
-				r = ctxt->arch->prg();
-				*r = *p;
-				if(!(r->mark&FOLL))
-					print("can't 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 == ARET && q->scond == C_SCOND_NONE) || a == ARFE || a == AUNDEF)
-					return;
-				r->as = ABNE;
-				if(a == ABNE)
-					r->as = ABEQ;
-				r->pcond = p->link;
-				r->link = p->pcond;
-				if(!(r->link->mark&FOLL))
-					xfol(ctxt, r->link, last);
-				if(!(r->pcond->mark&FOLL))
-					print("can't happen 2\n");
-				return;
-			}
-		}
-		a = AB;
-		q = ctxt->arch->prg();
-		q->as = a;
-		q->lineno = p->lineno;
-		q->to.type = D_BRANCH;
-		q->to.offset = p->pc;
-		q->pcond = p;
-		p = q;
-	}
-	p->mark |= FOLL;
-	(*last)->link = p;
-	*last = p;
-	if(a == AB || (a == ARET && p->scond == C_SCOND_NONE) || a == ARFE || a == AUNDEF){
-		return;
-	}
-	if(p->pcond != nil)
-	if(a != ABL && a != ABX && p->link != nil) {
-		q = brchain(ctxt, p->link);
-		if(a != ATEXT && a != ABCASE)
-		if(q != nil && (q->mark&FOLL)) {
-			p->as = relinv(a);
-			p->link = p->pcond;
-			p->pcond = q;
-		}
-		xfol(ctxt, p->link, last);
-		q = brchain(ctxt, p->pcond);
-		if(q == nil)
-			q = p->pcond;
-		if(q->mark&FOLL) {
-			p->pcond = q;
-			return;
-		}
-		p = q;
-		goto loop;
-	}
-	p = p->link;
-	goto loop;
-}
-
-LinkArch linkarm = {
-	.name = "arm",
-	.thechar = '5',
-	.endian = LittleEndian,
-
-	.addstacksplit = addstacksplit,
-	.assemble = span5,
-	.datasize = datasize,
-	.follow = follow,
-	.iscall = iscall,
-	.isdata = isdata,
-	.prg = prg,
-	.progedit = progedit,
-	.settextflag = settextflag,
-	.symtype = symtype,
-	.textflag = textflag,
-
-	.minlc = 4,
-	.ptrsize = 4,
-	.regsize = 4,
-
-	.D_ADDR = D_ADDR,
-	.D_AUTO = D_AUTO,
-	.D_BRANCH = D_BRANCH,
-	.D_CONST = D_CONST,
-	.D_EXTERN = D_EXTERN,
-	.D_FCONST = D_FCONST,
-	.D_NONE = D_NONE,
-	.D_PARAM = D_PARAM,
-	.D_SCONST = D_SCONST,
-	.D_STATIC = D_STATIC,
-	.D_OREG = D_OREG,
-
-	.ACALL = ABL,
-	.ADATA = ADATA,
-	.AEND = AEND,
-	.AFUNCDATA = AFUNCDATA,
-	.AGLOBL = AGLOBL,
-	.AJMP = AB,
-	.ANOP = ANOP,
-	.APCDATA = APCDATA,
-	.ARET = ARET,
-	.ATEXT = ATEXT,
-	.ATYPE = ATYPE,
-	.AUSEFIELD = AUSEFIELD,
-};
diff --git a/src/liblink/obj6.c b/src/liblink/obj6.c
deleted file mode 100644
index 2acfd2f..0000000
--- a/src/liblink/obj6.c
+++ /dev/null
@@ -1,1094 +0,0 @@
-// Inferno utils/6l/pass.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/pass.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <link.h>
-#include "../cmd/6l/6.out.h"
-#include "../runtime/stack.h"
-
-static Prog zprg = {
-	.back = 2,
-	.as = AGOK,
-	.from = {
-		.type = D_NONE,
-		.index = D_NONE,
-	},
-	.to = {
-		.type = D_NONE,
-		.index = D_NONE,
-	},
-};
-
-static void
-nopout(Prog *p)
-{
-	p->as = ANOP;
-	p->from.type = D_NONE;
-	p->to.type = D_NONE;
-}
-
-static int
-symtype(Addr *a)
-{
-	int t;
-
-	t = a->type;
-	if(t == D_ADDR)
-		t = a->index;
-	return t;
-}
-
-static int
-isdata(Prog *p)
-{
-	return p->as == ADATA || p->as == AGLOBL;
-}
-
-static int
-iscall(Prog *p)
-{
-	return p->as == ACALL;
-}
-
-static int
-datasize(Prog *p)
-{
-	return p->from.scale;
-}
-
-static int
-textflag(Prog *p)
-{
-	return p->from.scale;
-}
-
-static void
-settextflag(Prog *p, int f)
-{
-	p->from.scale = f;
-}
-
-static void nacladdr(Link*, Prog*, Addr*);
-
-static int
-canuselocaltls(Link *ctxt)
-{
-	switch(ctxt->headtype) {
-	case Hplan9:
-	case Hwindows:
-		return 0;
-	}
-	return 1;
-}
-
-static void
-progedit(Link *ctxt, Prog *p)
-{
-	char literal[64];
-	LSym *s;
-	Prog *q;
-
-	// Thread-local storage references use the TLS pseudo-register.
-	// As a register, TLS refers to the thread-local storage base, and it
-	// can only be loaded into another register:
-	//
-	//         MOVQ TLS, AX
-	//
-	// An offset from the thread-local storage base is written off(reg)(TLS*1).
-	// Semantically it is off(reg), but the (TLS*1) annotation marks this as
-	// indexing from the loaded TLS base. This emits a relocation so that
-	// if the linker needs to adjust the offset, it can. For example:
-	//
-	//         MOVQ TLS, AX
-	//         MOVQ 8(AX)(TLS*1), CX // load m into CX
-	// 
-	// On systems that support direct access to the TLS memory, this
-	// pair of instructions can be reduced to a direct TLS memory reference:
-	// 
-	//         MOVQ 8(TLS), CX // load m into CX
-	//
-	// The 2-instruction and 1-instruction forms correspond roughly to
-	// ELF TLS initial exec mode and ELF TLS local exec mode, respectively.
-	// 
-	// We applies this rewrite on systems that support the 1-instruction form.
-	// The decision is made using only the operating system (and probably
-	// the -shared flag, eventually), not the link mode. If some link modes
-	// on a particular operating system require the 2-instruction form,
-	// then all builds for that operating system will use the 2-instruction
-	// form, so that the link mode decision can be delayed to link time.
-	//
-	// In this way, all supported systems use identical instructions to
-	// access TLS, and they are rewritten appropriately first here in
-	// liblink and then finally using relocations in the linker.
-
-	if(canuselocaltls(ctxt)) {
-		// Reduce TLS initial exec model to TLS local exec model.
-		// Sequences like
-		//	MOVQ TLS, BX
-		//	... off(BX)(TLS*1) ...
-		// become
-		//	NOP
-		//	... off(TLS) ...
-		//
-		// TODO(rsc): Remove the Hsolaris special case. It exists only to
-		// guarantee we are producing byte-identical binaries as before this code.
-		// But it should be unnecessary.
-		if((p->as == AMOVQ || p->as == AMOVL) && p->from.type == D_TLS && D_AX <= p->to.type && p->to.type <= D_R15 && ctxt->headtype != Hsolaris)
-			nopout(p);
-		if(p->from.index == D_TLS && D_INDIR+D_AX <= p->from.type && p->from.type <= D_INDIR+D_R15) {
-			p->from.type = D_INDIR+D_TLS;
-			p->from.scale = 0;
-			p->from.index = D_NONE;
-		}
-		if(p->to.index == D_TLS && D_INDIR+D_AX <= p->to.type && p->to.type <= D_INDIR+D_R15) {
-			p->to.type = D_INDIR+D_TLS;
-			p->to.scale = 0;
-			p->to.index = D_NONE;
-		}
-	} else {
-		// As a courtesy to the C compilers, rewrite TLS local exec load as TLS initial exec load.
-		// The instruction
-		//	MOVQ off(TLS), BX
-		// becomes the sequence
-		//	MOVQ TLS, BX
-		//	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 == D_INDIR+D_TLS && D_AX <= p->to.type && p->to.type <= D_R15) {
-			q = appendp(ctxt, p);
-			q->as = p->as;
-			q->from = p->from;
-			q->from.type = D_INDIR + p->to.type;
-			q->from.index = D_TLS;
-			q->from.scale = 2; // TODO: use 1
-			q->to = p->to;
-			p->from.type = D_TLS;
-			p->from.index = D_NONE;
-			p->from.offset = 0;
-		}
-	}
-
-	// TODO: Remove.
-	if(ctxt->headtype == Hwindows || ctxt->headtype == Hplan9) {
-		if(p->from.scale == 1 && p->from.index == D_TLS)
-			p->from.scale = 2;
-		if(p->to.scale == 1 && p->to.index == D_TLS)
-			p->to.scale = 2;
-	}
-
-	if(ctxt->headtype == 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 = ctxt->mode;
-	
-	switch(p->as) {
-	case AMODE:
-		if(p->from.type == D_CONST || p->from.type == D_INDIR+D_NONE) {
-			switch((int)p->from.offset) {
-			case 16:
-			case 32:
-			case 64:
-				ctxt->mode = p->from.offset;
-				break;
-			}
-		}
-		nopout(p);
-		break;
-	}
-	
-	// Rewrite CALL/JMP/RET to symbol as D_BRANCH.
-	switch(p->as) {
-	case ACALL:
-	case AJMP:
-	case ARET:
-		if((p->to.type == D_EXTERN || p->to.type == D_STATIC) && p->to.sym != nil)
-			p->to.type = D_BRANCH;
-		break;
-	}
-
-	// Rewrite float constants to values stored in memory.
-	switch(p->as) {
-	case AFMOVF:
-	case AFADDF:
-	case AFSUBF:
-	case AFSUBRF:
-	case AFMULF:
-	case AFDIVF:
-	case AFDIVRF:
-	case AFCOMF:
-	case AFCOMFP:
-	case AMOVSS:
-	case AADDSS:
-	case ASUBSS:
-	case AMULSS:
-	case ADIVSS:
-	case ACOMISS:
-	case AUCOMISS:
-		if(p->from.type == D_FCONST) {
-			int32 i32;
-			float32 f32;
-			f32 = p->from.u.dval;
-			memmove(&i32, &f32, 4);
-			sprint(literal, "$f32.%08ux", (uint32)i32);
-			s = linklookup(ctxt, literal, 0);
-			if(s->type == 0) {
-				s->type = SRODATA;
-				adduint32(ctxt, s, i32);
-				s->reachable = 0;
-			}
-			p->from.type = D_EXTERN;
-			p->from.sym = s;
-			p->from.offset = 0;
-		}
-		break;
-	
-	case AFMOVD:
-	case AFADDD:
-	case AFSUBD:
-	case AFSUBRD:
-	case AFMULD:
-	case AFDIVD:
-	case AFDIVRD:
-	case AFCOMD:
-	case AFCOMDP:
-	case AMOVSD:
-	case AADDSD:
-	case ASUBSD:
-	case AMULSD:
-	case ADIVSD:
-	case ACOMISD:
-	case AUCOMISD:
-		if(p->from.type == D_FCONST) {
-			int64 i64;
-			memmove(&i64, &p->from.u.dval, 8);
-			sprint(literal, "$f64.%016llux", (uvlong)i64);
-			s = linklookup(ctxt, literal, 0);
-			if(s->type == 0) {
-				s->type = SRODATA;
-				adduint64(ctxt, s, i64);
-				s->reachable = 0;
-			}
-			p->from.type = D_EXTERN;
-			p->from.sym = s;
-			p->from.offset = 0;
-		}
-		break;
-	}
-}
-
-static void
-nacladdr(Link *ctxt, Prog *p, Addr *a)
-{
-	if(p->as == ALEAL || p->as == ALEAQ)
-		return;
-	
-	if(a->type == D_BP || a->type == D_INDIR+D_BP) {
-		ctxt->diag("invalid address: %P", p);
-		return;
-	}
-	if(a->type == D_INDIR+D_TLS)
-		a->type = D_INDIR+D_BP;
-	else if(a->type == D_TLS)
-		a->type = D_BP;
-	if(D_INDIR <= a->type && a->type <= D_INDIR+D_INDIR) {
-		switch(a->type) {
-		case D_INDIR+D_BP:
-		case D_INDIR+D_SP:
-		case D_INDIR+D_R15:
-			// all ok
-			break;
-		default:
-			if(a->index != D_NONE)
-				ctxt->diag("invalid address %P", p);
-			a->index = a->type - D_INDIR;
-			if(a->index != D_NONE)
-				a->scale = 1;
-			a->type = D_INDIR+D_R15;
-			break;
-		}
-	}
-}
-
-static Prog*	load_g_cx(Link*, Prog*);
-static Prog*	stacksplit(Link*, Prog*, int32, int32, int, Prog**);
-static void	indir_cx(Link*, Addr*);
-
-static void
-parsetextconst(vlong arg, vlong *textstksiz, vlong *textarg)
-{
-	*textstksiz = arg & 0xffffffffLL;
-	if(*textstksiz & 0x80000000LL)
-		*textstksiz = -(-*textstksiz & 0xffffffffLL);
-
-	*textarg = (arg >> 32) & 0xffffffffLL;
-	if(*textarg & 0x80000000LL)
-		*textarg = 0;
-	*textarg = (*textarg+7) & ~7LL;
-}
-
-static void
-addstacksplit(Link *ctxt, LSym *cursym)
-{
-	Prog *p, *q, *p1, *p2;
-	int32 autoffset, deltasp;
-	int a, pcsize;
-	vlong textstksiz, textarg;
-
-	if(ctxt->tlsg == nil)
-		ctxt->tlsg = linklookup(ctxt, "runtime.tlsg", 0);
-	if(ctxt->symmorestack[0] == nil) {
-		ctxt->symmorestack[0] = linklookup(ctxt, "runtime.morestack", 0);
-		ctxt->symmorestack[1] = linklookup(ctxt, "runtime.morestack_noctxt", 0);
-	}
-
-	if(ctxt->headtype == Hplan9 && ctxt->plan9privates == nil)
-		ctxt->plan9privates = linklookup(ctxt, "_privates", 0);
-
-	ctxt->cursym = cursym;
-
-	if(cursym->text == nil || cursym->text->link == nil)
-		return;				
-
-	p = cursym->text;
-	parsetextconst(p->to.offset, &textstksiz, &textarg);
-	autoffset = textstksiz;
-	if(autoffset < 0)
-		autoffset = 0;
-	
-	cursym->args = p->to.offset>>32;
-	cursym->locals = textstksiz;
-
-	if(autoffset < StackSmall && !(p->from.scale & NOSPLIT)) {
-		for(q = p; q != nil; q = q->link) {
-			if(q->as == ACALL)
-				goto noleaf;
-			if((q->as == ADUFFCOPY || q->as == ADUFFZERO) && autoffset >= StackSmall - 8)
-				goto noleaf;
-		}
-		p->from.scale |= NOSPLIT;
-	noleaf:;
-	}
-
-	q = nil;
-	if(!(p->from.scale & NOSPLIT) || (p->from.scale & WRAPPER)) {
-		p = appendp(ctxt, p);
-		p = load_g_cx(ctxt, p); // load g into CX
-	}
-	if(!(cursym->text->from.scale & NOSPLIT))
-		p = stacksplit(ctxt, p, autoffset, textarg, !(cursym->text->from.scale&NEEDCTXT), &q); // emit split check
-
-	if(autoffset) {
-		if(autoffset%ctxt->arch->regsize != 0)
-			ctxt->diag("unaligned stack size %d", autoffset);
-		p = appendp(ctxt, p);
-		p->as = AADJSP;
-		p->from.type = D_CONST;
-		p->from.offset = 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 = appendp(ctxt, p);
-		p->as = ANOP;
-		p->spadj = -ctxt->arch->ptrsize;
-		p = appendp(ctxt, p);
-		p->as = ANOP;
-		p->spadj = ctxt->arch->ptrsize;
-	}
-	if(q != nil)
-		q->pcond = p;
-	deltasp = autoffset;
-	
-	if(cursym->text->from.scale & WRAPPER) {
-		// if(g->panic != nil && g->panic->argp == FP) g->panic->argp = bottom-of-frame
-		//
-		//	MOVQ g_panic(CX), BX
-		//	TESTQ BX, BX
-		//	JEQ end
-		//	LEAQ (autoffset+8)(SP), DI
-		//	CMPQ panic_argp(BX), DI
-		//	JNE end
-		//	MOVQ 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 = appendp(ctxt, p);
-		p->as = AMOVQ;
-		p->from.type = D_INDIR+D_CX;
-		p->from.offset = 4*ctxt->arch->ptrsize; // G.panic
-		p->to.type = D_BX;
-		if(ctxt->headtype == Hnacl) {
-			p->as = AMOVL;
-			p->from.type = D_INDIR+D_R15;
-			p->from.scale = 1;
-			p->from.index = D_CX;
-		}
-
-		p = appendp(ctxt, p);
-		p->as = ATESTQ;
-		p->from.type = D_BX;
-		p->to.type = D_BX;
-		if(ctxt->headtype == Hnacl)
-			p->as = ATESTL;
-
-		p = appendp(ctxt, p);
-		p->as = AJEQ;
-		p->to.type = D_BRANCH;
-		p1 = p;
-
-		p = appendp(ctxt, p);
-		p->as = ALEAQ;
-		p->from.type = D_INDIR+D_SP;
-		p->from.offset = autoffset+8;
-		p->to.type = D_DI;
-		if(ctxt->headtype == Hnacl)
-			p->as = ALEAL;
-
-		p = appendp(ctxt, p);
-		p->as = ACMPQ;
-		p->from.type = D_INDIR+D_BX;
-		p->from.offset = 0; // Panic.argp
-		p->to.type = D_DI;
-		if(ctxt->headtype == Hnacl) {
-			p->as = ACMPL;
-			p->from.type = D_INDIR+D_R15;
-			p->from.scale = 1;
-			p->from.index = D_BX;
-		}
-
-		p = appendp(ctxt, p);
-		p->as = AJNE;
-		p->to.type = D_BRANCH;
-		p2 = p;
-
-		p = appendp(ctxt, p);
-		p->as = AMOVQ;
-		p->from.type = D_SP;
-		p->to.type = D_INDIR+D_BX;
-		p->to.offset = 0; // Panic.argp
-		if(ctxt->headtype == Hnacl) {
-			p->as = AMOVL;
-			p->to.type = D_INDIR+D_R15;
-			p->to.scale = 1;
-			p->to.index = D_BX;
-		}
-
-		p = appendp(ctxt, p);
-		p->as = ANOP;
-		p1->pcond = p;
-		p2->pcond = p;
-	}
-
-	if(ctxt->debugzerostack && autoffset && !(cursym->text->from.scale&NOSPLIT)) {
-		// 6l -Z means zero the stack frame on entry.
-		// This slows down function calls but can help avoid
-		// false positives in garbage collection.
-		p = appendp(ctxt, p);
-		p->as = AMOVQ;
-		p->from.type = D_SP;
-		p->to.type = D_DI;
-		
-		p = appendp(ctxt, p);
-		p->as = AMOVQ;
-		p->from.type = D_CONST;
-		p->from.offset = autoffset/8;
-		p->to.type = D_CX;
-		
-		p = appendp(ctxt, p);
-		p->as = AMOVQ;
-		p->from.type = D_CONST;
-		p->from.offset = 0;
-		p->to.type = D_AX;
-		
-		p = appendp(ctxt, p);
-		p->as = AREP;
-		
-		p = appendp(ctxt, p);
-		p->as = ASTOSQ;
-	}
-	
-	for(; p != nil; p = p->link) {
-		pcsize = p->mode/8;
-		a = p->from.type;
-		if(a == D_AUTO)
-			p->from.offset += deltasp;
-		if(a == D_PARAM)
-			p->from.offset += deltasp + pcsize;
-		a = p->to.type;
-		if(a == D_AUTO)
-			p->to.offset += deltasp;
-		if(a == D_PARAM)
-			p->to.offset += deltasp + pcsize;
-
-		switch(p->as) {
-		default:
-			continue;
-		case APUSHL:
-		case APUSHFL:
-			deltasp += 4;
-			p->spadj = 4;
-			continue;
-		case APUSHQ:
-		case APUSHFQ:
-			deltasp += 8;
-			p->spadj = 8;
-			continue;
-		case APUSHW:
-		case APUSHFW:
-			deltasp += 2;
-			p->spadj = 2;
-			continue;
-		case APOPL:
-		case APOPFL:
-			deltasp -= 4;
-			p->spadj = -4;
-			continue;
-		case APOPQ:
-		case APOPFQ:
-			deltasp -= 8;
-			p->spadj = -8;
-			continue;
-		case APOPW:
-		case APOPFW:
-			deltasp -= 2;
-			p->spadj = -2;
-			continue;
-		case ARET:
-			break;
-		}
-
-		if(autoffset != deltasp)
-			ctxt->diag("unbalanced PUSH/POP");
-
-		if(autoffset) {
-			p->as = AADJSP;
-			p->from.type = D_CONST;
-			p->from.offset = -autoffset;
-			p->spadj = -autoffset;
-			p = appendp(ctxt, p);
-			p->as = 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) // retjmp
-			p->as = AJMP;
-	}
-}
-
-static void
-indir_cx(Link *ctxt, Addr *a)
-{
-	if(ctxt->headtype == Hnacl) {
-		a->type = D_INDIR + D_R15;
-		a->index = D_CX;
-		a->scale = 1;
-		return;
-	}
-
-	a->type = D_INDIR+D_CX;
-}
-
-// 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.
-static Prog*
-load_g_cx(Link *ctxt, Prog *p)
-{	
-	Prog *next;
-
-	p->as = AMOVQ;
-	if(ctxt->arch->ptrsize == 4)
-		p->as = AMOVL;
-	p->from.type = D_INDIR+D_TLS;
-	p->from.offset = 0;
-	p->to.type = D_CX;
-	
-	next = p->link;
-	progedit(ctxt, p);
-	while(p->link != next)
-		p = p->link;
-	
-	if(p->from.index == D_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.
-static Prog*
-stacksplit(Link *ctxt, Prog *p, int32 framesize, int32 textarg, int noctxt, Prog **jmpok)
-{
-	Prog *q, *q1;
-	int cmp, lea, mov, sub;
-
-	USED(textarg);
-	cmp = ACMPQ;
-	lea = ALEAQ;
-	mov = AMOVQ;
-	sub = ASUBQ;
-
-	if(ctxt->headtype == Hnacl) {
-		cmp = ACMPL;
-		lea = ALEAL;
-		mov = AMOVL;
-		sub = ASUBL;
-	}
-
-	q1 = nil;
-	if(framesize <= StackSmall) {
-		// small stack: SP <= stackguard
-		//	CMPQ SP, stackguard
-		p = appendp(ctxt, p);
-		p->as = cmp;
-		p->from.type = D_SP;
-		indir_cx(ctxt, &p->to);
-		p->to.offset = 2*ctxt->arch->ptrsize;	// G.stackguard0
-		if(ctxt->cursym->cfunc)
-			p->to.offset = 3*ctxt->arch->ptrsize;	// G.stackguard1
-	} else if(framesize <= StackBig) {
-		// large stack: SP-framesize <= stackguard-StackSmall
-		//	LEAQ -xxx(SP), AX
-		//	CMPQ AX, stackguard
-		p = appendp(ctxt, p);
-		p->as = lea;
-		p->from.type = D_INDIR+D_SP;
-		p->from.offset = -(framesize-StackSmall);
-		p->to.type = D_AX;
-
-		p = appendp(ctxt, p);
-		p->as = cmp;
-		p->from.type = D_AX;
-		indir_cx(ctxt, &p->to);
-		p->to.offset = 2*ctxt->arch->ptrsize;	// G.stackguard0
-		if(ctxt->cursym->cfunc)
-			p->to.offset = 3*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.
-		//	MOVQ	stackguard, CX
-		//	CMPQ	CX, $StackPreempt
-		//	JEQ	label-of-call-to-morestack
-		//	LEAQ	StackGuard(SP), AX
-		//	SUBQ	CX, AX
-		//	CMPQ	AX, $(framesize+(StackGuard-StackSmall))
-
-		p = appendp(ctxt, p);
-		p->as = mov;
-		indir_cx(ctxt, &p->from);
-		p->from.offset = 2*ctxt->arch->ptrsize;	// G.stackguard0
-		if(ctxt->cursym->cfunc)
-			p->from.offset = 3*ctxt->arch->ptrsize;	// G.stackguard1
-		p->to.type = D_SI;
-
-		p = appendp(ctxt, p);
-		p->as = cmp;
-		p->from.type = D_SI;
-		p->to.type = D_CONST;
-		p->to.offset = StackPreempt;
-
-		p = appendp(ctxt, p);
-		p->as = AJEQ;
-		p->to.type = D_BRANCH;
-		q1 = p;
-
-		p = appendp(ctxt, p);
-		p->as = lea;
-		p->from.type = D_INDIR+D_SP;
-		p->from.offset = StackGuard;
-		p->to.type = D_AX;
-		
-		p = appendp(ctxt, p);
-		p->as = sub;
-		p->from.type = D_SI;
-		p->to.type = D_AX;
-		
-		p = appendp(ctxt, p);
-		p->as = cmp;
-		p->from.type = D_AX;
-		p->to.type = D_CONST;
-		p->to.offset = framesize+(StackGuard-StackSmall);
-	}					
-
-	// common
-	p = appendp(ctxt, p);
-	p->as = AJHI;
-	p->to.type = D_BRANCH;
-	q = p;
-
-	p = appendp(ctxt, p);
-	p->as = ACALL;
-	p->to.type = D_BRANCH;
-	if(ctxt->cursym->cfunc)
-		p->to.sym = linklookup(ctxt, "runtime.morestackc", 0);
-	else
-		p->to.sym = ctxt->symmorestack[noctxt];
-	
-	p = appendp(ctxt, p);
-	p->as = AJMP;
-	p->to.type = D_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;
-}
-
-static void xfol(Link*, Prog*, Prog**);
-
-static void
-follow(Link *ctxt, LSym *s)
-{
-	Prog *firstp, *lastp;
-
-	ctxt->cursym = s;
-
-	firstp = ctxt->arch->prg();
-	lastp = firstp;
-	xfol(ctxt, s->text, &lastp);
-	lastp->link = nil;
-	s->text = firstp->link;
-}
-
-static int
-nofollow(int a)
-{
-	switch(a) {
-	case AJMP:
-	case ARET:
-	case AIRETL:
-	case AIRETQ:
-	case AIRETW:
-	case ARETFL:
-	case ARETFQ:
-	case ARETFW:
-	case AUNDEF:
-		return 1;
-	}
-	return 0;
-}
-
-static int
-pushpop(int a)
-{
-	switch(a) {
-	case APUSHL:
-	case APUSHFL:
-	case APUSHQ:
-	case APUSHFQ:
-	case APUSHW:
-	case APUSHFW:
-	case APOPL:
-	case APOPFL:
-	case APOPQ:
-	case APOPFQ:
-	case APOPW:
-	case APOPFW:
-		return 1;
-	}
-	return 0;
-}
-
-static int
-relinv(int a)
-{
-	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;
-	}
-	sysfatal("unknown relation: %s", anames6[a]);
-	return 0;
-}
-
-static void
-xfol(Link *ctxt, Prog *p, Prog **last)
-{
-	Prog *q;
-	int i;
-	int a;
-
-loop:
-	if(p == nil)
-		return;
-	if(p->as == AJMP)
-	if((q = p->pcond) != nil && q->as != 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) {
-		/* 
-		 * p goes here, but already used it elsewhere.
-		 * copy up to 4 instructions or else branch to other copy.
-		 */
-		for(i=0,q=p; i<4; i++,q=q->link) {
-			if(q == nil)
-				break;
-			if(q == *last)
-				break;
-			a = q->as;
-			if(a == ANOP) {
-				i--;
-				continue;
-			}
-			if(nofollow(a) || pushpop(a))	
-				break;	// NOTE(rsc): arm does goto copy
-			if(q->pcond == nil || q->pcond->mark)
-				continue;
-			if(a == ACALL || a == ALOOP)
-				continue;
-			for(;;) {
-				if(p->as == ANOP) {
-					p = p->link;
-					continue;
-				}
-				q = copyp(ctxt, p);
-				p = p->link;
-				q->mark = 1;
-				(*last)->link = q;
-				*last = q;
-				if(q->as != a || q->pcond == nil || q->pcond->mark)
-					continue;
-
-				q->as = relinv(q->as);
-				p = q->pcond;
-				q->pcond = q->link;
-				q->link = p;
-				xfol(ctxt, q->link, last);
-				p = q->link;
-				if(p->mark)
-					return;
-				goto loop;
-			}
-		} /* */
-		q = ctxt->arch->prg();
-		q->as = AJMP;
-		q->lineno = p->lineno;
-		q->to.type = D_BRANCH;
-		q->to.offset = p->pc;
-		q->pcond = p;
-		p = q;
-	}
-	
-	/* emit p */
-	p->mark = 1;
-	(*last)->link = p;
-	*last = p;
-	a = p->as;
-
-	/* continue loop with what comes after p */
-	if(nofollow(a))
-		return;
-	if(p->pcond != nil && a != ACALL) {
-		/*
-		 * some kind of conditional branch.
-		 * recurse to follow one path.
-		 * continue loop on the other.
-		 */
-		if((q = brchain(ctxt, p->pcond)) != nil)
-			p->pcond = q;
-		if((q = brchain(ctxt, p->link)) != nil)
-			p->link = q;
-		if(p->from.type == D_CONST) {
-			if(p->from.offset == 1) {
-				/*
-				 * expect conditional jump to be taken.
-				 * rewrite so that's the fall-through case.
-				 */
-				p->as = relinv(a);
-				q = p->link;
-				p->link = p->pcond;
-				p->pcond = q;
-			}
-		} else {			
-			q = p->link;
-			if(q->mark)
-			if(a != ALOOP) {
-				p->as = relinv(a);
-				p->link = p->pcond;
-				p->pcond = q;
-			}
-		}
-		xfol(ctxt, p->link, last);
-		if(p->pcond->mark)
-			return;
-		p = p->pcond;
-		goto loop;
-	}
-	p = p->link;
-	goto loop;
-}
-
-static Prog*
-prg(void)
-{
-	Prog *p;
-
-	p = emallocz(sizeof(*p));
-	*p = zprg;
-	return p;
-}
-
-LinkArch linkamd64 = {
-	.name = "amd64",
-	.thechar = '6',
-	.endian = LittleEndian,
-
-	.addstacksplit = addstacksplit,
-	.assemble = span6,
-	.datasize = datasize,
-	.follow = follow,
-	.iscall = iscall,
-	.isdata = isdata,
-	.prg = prg,
-	.progedit = progedit,
-	.settextflag = settextflag,
-	.symtype = symtype,
-	.textflag = textflag,
-
-	.minlc = 1,
-	.ptrsize = 8,
-	.regsize = 8,
-
-	.D_ADDR = D_ADDR,
-	.D_AUTO = D_AUTO,
-	.D_BRANCH = D_BRANCH,
-	.D_CONST = D_CONST,
-	.D_EXTERN = D_EXTERN,
-	.D_FCONST = D_FCONST,
-	.D_NONE = D_NONE,
-	.D_PARAM = D_PARAM,
-	.D_SCONST = D_SCONST,
-	.D_STATIC = D_STATIC,
-
-	.ACALL = ACALL,
-	.ADATA = ADATA,
-	.AEND = AEND,
-	.AFUNCDATA = AFUNCDATA,
-	.AGLOBL = AGLOBL,
-	.AJMP = AJMP,
-	.ANOP = ANOP,
-	.APCDATA = APCDATA,
-	.ARET = ARET,
-	.ATEXT = ATEXT,
-	.ATYPE = ATYPE,
-	.AUSEFIELD = AUSEFIELD,
-};
-
-LinkArch linkamd64p32 = {
-	.name = "amd64p32",
-	.thechar = '6',
-	.endian = LittleEndian,
-
-	.addstacksplit = addstacksplit,
-	.assemble = span6,
-	.datasize = datasize,
-	.follow = follow,
-	.iscall = iscall,
-	.isdata = isdata,
-	.prg = prg,
-	.progedit = progedit,
-	.settextflag = settextflag,
-	.symtype = symtype,
-	.textflag = textflag,
-
-	.minlc = 1,
-	.ptrsize = 4,
-	.regsize = 8,
-
-	.D_ADDR = D_ADDR,
-	.D_AUTO = D_AUTO,
-	.D_BRANCH = D_BRANCH,
-	.D_CONST = D_CONST,
-	.D_EXTERN = D_EXTERN,
-	.D_FCONST = D_FCONST,
-	.D_NONE = D_NONE,
-	.D_PARAM = D_PARAM,
-	.D_SCONST = D_SCONST,
-	.D_STATIC = D_STATIC,
-
-	.ACALL = ACALL,
-	.ADATA = ADATA,
-	.AEND = AEND,
-	.AFUNCDATA = AFUNCDATA,
-	.AGLOBL = AGLOBL,
-	.AJMP = AJMP,
-	.ANOP = ANOP,
-	.APCDATA = APCDATA,
-	.ARET = ARET,
-	.ATEXT = ATEXT,
-	.ATYPE = ATYPE,
-	.AUSEFIELD = AUSEFIELD,
-};
diff --git a/src/liblink/obj8.c b/src/liblink/obj8.c
deleted file mode 100644
index f54153a..0000000
--- a/src/liblink/obj8.c
+++ /dev/null
@@ -1,882 +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 at 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 at 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.
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <link.h>
-#include "../cmd/8l/8.out.h"
-#include "../runtime/stack.h"
-
-static Prog zprg = {
-	.back = 2,
-	.as = AGOK,
-	.from = {
-		.type = D_NONE,
-		.index = D_NONE,
-		.scale = 1,
-	},
-	.to = {
-		.type = D_NONE,
-		.index = D_NONE,
-		.scale = 1,
-	},
-};
-
-static int
-symtype(Addr *a)
-{
-	int t;
-
-	t = a->type;
-	if(t == D_ADDR)
-		t = a->index;
-	return t;
-}
-
-static int
-isdata(Prog *p)
-{
-	return p->as == ADATA || p->as == AGLOBL;
-}
-
-static int
-iscall(Prog *p)
-{
-	return p->as == ACALL;
-}
-
-static int
-datasize(Prog *p)
-{
-	return p->from.scale;
-}
-
-static int
-textflag(Prog *p)
-{
-	return p->from.scale;
-}
-
-static void
-settextflag(Prog *p, int f)
-{
-	p->from.scale = f;
-}
-
-static int
-canuselocaltls(Link *ctxt)
-{
-	switch(ctxt->headtype) {
-	case Hlinux:
-	case Hnacl:
-	case Hplan9:
-	case Hwindows:
-		return 0;
-	}
-	return 1;
-}
-
-static void
-progedit(Link *ctxt, Prog *p)
-{
-	char literal[64];
-	LSym *s;
-	Prog *q;
-	
-	// 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 == D_TLS && D_AX <= p->to.type && p->to.type <= D_DI) {
-			p->as = ANOP;
-			p->from.type = D_NONE;
-			p->to.type = D_NONE;
-		}
-		if(p->from.index == D_TLS && D_INDIR+D_AX <= p->from.type && p->from.type <= D_INDIR+D_DI) {
-			p->from.type = D_INDIR+D_TLS;
-			p->from.scale = 0;
-			p->from.index = D_NONE;
-		}
-		if(p->to.index == D_TLS && D_INDIR+D_AX <= p->to.type && p->to.type <= D_INDIR+D_DI) {
-			p->to.type = D_INDIR+D_TLS;
-			p->to.scale = 0;
-			p->to.index = D_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 == D_INDIR+D_TLS && D_AX <= p->to.type && p->to.type <= D_DI) {
-			q = appendp(ctxt, p);
-			q->as = p->as;
-			q->from = p->from;
-			q->from.type = D_INDIR + p->to.type;
-			q->from.index = D_TLS;
-			q->from.scale = 2; // TODO: use 1
-			q->to = p->to;
-			p->from.type = D_TLS;
-			p->from.index = D_NONE;
-			p->from.offset = 0;
-		}
-	}
-
-	// TODO: Remove.
-	if(ctxt->headtype == Hplan9) {
-		if(p->from.scale == 1 && p->from.index == D_TLS)
-			p->from.scale = 2;
-		if(p->to.scale == 1 && p->to.index == D_TLS)
-			p->to.scale = 2;
-	}
-
-	// Rewrite CALL/JMP/RET to symbol as D_BRANCH.
-	switch(p->as) {
-	case ACALL:
-	case AJMP:
-	case ARET:
-		if((p->to.type == D_EXTERN || p->to.type == D_STATIC) && p->to.sym != nil)
-			p->to.type = D_BRANCH;
-		break;
-	}
-
-	// Rewrite float constants to values stored in memory.
-	switch(p->as) {
-	case AFMOVF:
-	case AFADDF:
-	case AFSUBF:
-	case AFSUBRF:
-	case AFMULF:
-	case AFDIVF:
-	case AFDIVRF:
-	case AFCOMF:
-	case AFCOMFP:
-	case AMOVSS:
-	case AADDSS:
-	case ASUBSS:
-	case AMULSS:
-	case ADIVSS:
-	case ACOMISS:
-	case AUCOMISS:
-		if(p->from.type == D_FCONST) {
-			int32 i32;
-			float32 f32;
-			f32 = p->from.u.dval;
-			memmove(&i32, &f32, 4);
-			sprint(literal, "$f32.%08ux", (uint32)i32);
-			s = linklookup(ctxt, literal, 0);
-			if(s->type == 0) {
-				s->type = SRODATA;
-				adduint32(ctxt, s, i32);
-				s->reachable = 0;
-			}
-			p->from.type = D_EXTERN;
-			p->from.sym = s;
-			p->from.offset = 0;
-		}
-		break;
-
-	case AFMOVD:
-	case AFADDD:
-	case AFSUBD:
-	case AFSUBRD:
-	case AFMULD:
-	case AFDIVD:
-	case AFDIVRD:
-	case AFCOMD:
-	case AFCOMDP:
-	case AMOVSD:
-	case AADDSD:
-	case ASUBSD:
-	case AMULSD:
-	case ADIVSD:
-	case ACOMISD:
-	case AUCOMISD:
-		if(p->from.type == D_FCONST) {
-			int64 i64;
-			memmove(&i64, &p->from.u.dval, 8);
-			sprint(literal, "$f64.%016llux", (uvlong)i64);
-			s = linklookup(ctxt, literal, 0);
-			if(s->type == 0) {
-				s->type = SRODATA;
-				adduint64(ctxt, s, i64);
-				s->reachable = 0;
-			}
-			p->from.type = D_EXTERN;
-			p->from.sym = s;
-			p->from.offset = 0;
-		}
-		break;
-	}
-}
-
-static Prog*
-prg(void)
-{
-	Prog *p;
-
-	p = emallocz(sizeof(*p));
-	*p = zprg;
-	return p;
-}
-
-static Prog*	load_g_cx(Link*, Prog*);
-static Prog*	stacksplit(Link*, Prog*, int32, int, Prog**);
-
-static void
-addstacksplit(Link *ctxt, LSym *cursym)
-{
-	Prog *p, *q, *p1, *p2;
-	int32 autoffset, deltasp;
-	int a;
-
-	if(ctxt->symmorestack[0] == nil) {
-		ctxt->symmorestack[0] = linklookup(ctxt, "runtime.morestack", 0);
-		ctxt->symmorestack[1] = linklookup(ctxt, "runtime.morestack_noctxt", 0);
-	}
-
-	if(ctxt->headtype == Hplan9 && ctxt->plan9privates == nil)
-		ctxt->plan9privates = linklookup(ctxt, "_privates", 0);
-
-	ctxt->cursym = cursym;
-
-	if(cursym->text == nil || cursym->text->link == nil)
-		return;
-
-	p = cursym->text;
-	autoffset = p->to.offset;
-	if(autoffset < 0)
-		autoffset = 0;
-	
-	cursym->locals = autoffset;
-	cursym->args = p->to.offset2;
-
-	q = nil;
-
-	if(!(p->from.scale & NOSPLIT) || (p->from.scale & WRAPPER)) {
-		p = appendp(ctxt, p);
-		p = load_g_cx(ctxt, p); // load g into CX
-	}
-	if(!(cursym->text->from.scale & NOSPLIT))
-		p = stacksplit(ctxt, p, autoffset, !(cursym->text->from.scale&NEEDCTXT), &q); // emit split check
-
-	if(autoffset) {
-		p = appendp(ctxt, p);
-		p->as = AADJSP;
-		p->from.type = D_CONST;
-		p->from.offset = 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 = appendp(ctxt, p);
-		p->as = ANOP;
-		p->spadj = -ctxt->arch->ptrsize;
-		p = appendp(ctxt, p);
-		p->as = ANOP;
-		p->spadj = ctxt->arch->ptrsize;
-	}
-	if(q != nil)
-		q->pcond = p;
-	deltasp = autoffset;
-	
-	if(cursym->text->from.scale & WRAPPER) {
-		// 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 = appendp(ctxt, p);
-		p->as = AMOVL;
-		p->from.type = D_INDIR+D_CX;
-		p->from.offset = 4*ctxt->arch->ptrsize; // G.panic
-		p->to.type = D_BX;
-
-		p = appendp(ctxt, p);
-		p->as = ATESTL;
-		p->from.type = D_BX;
-		p->to.type = D_BX;
-
-		p = appendp(ctxt, p);
-		p->as = AJEQ;
-		p->to.type = D_BRANCH;
-		p1 = p;
-
-		p = appendp(ctxt, p);
-		p->as = ALEAL;
-		p->from.type = D_INDIR+D_SP;
-		p->from.offset = autoffset+4;
-		p->to.type = D_DI;
-
-		p = appendp(ctxt, p);
-		p->as = ACMPL;
-		p->from.type = D_INDIR+D_BX;
-		p->from.offset = 0; // Panic.argp
-		p->to.type = D_DI;
-
-		p = appendp(ctxt, p);
-		p->as = AJNE;
-		p->to.type = D_BRANCH;
-		p2 = p;
-
-		p = appendp(ctxt, p);
-		p->as = AMOVL;
-		p->from.type = D_SP;
-		p->to.type = D_INDIR+D_BX;
-		p->to.offset = 0; // Panic.argp
-
-		p = appendp(ctxt, p);
-		p->as = ANOP;
-		p1->pcond = p;
-		p2->pcond = p;
-	}
-	
-	if(ctxt->debugzerostack && autoffset && !(cursym->text->from.scale&NOSPLIT)) {
-		// 8l -Z means zero the stack frame on entry.
-		// This slows down function calls but can help avoid
-		// false positives in garbage collection.
-		p = appendp(ctxt, p);
-		p->as = AMOVL;
-		p->from.type = D_SP;
-		p->to.type = D_DI;
-		
-		p = appendp(ctxt, p);
-		p->as = AMOVL;
-		p->from.type = D_CONST;
-		p->from.offset = autoffset/4;
-		p->to.type = D_CX;
-		
-		p = appendp(ctxt, p);
-		p->as = AMOVL;
-		p->from.type = D_CONST;
-		p->from.offset = 0;
-		p->to.type = D_AX;
-		
-		p = appendp(ctxt, p);
-		p->as = AREP;
-		
-		p = appendp(ctxt, p);
-		p->as = ASTOSL;
-	}
-	
-	for(; p != nil; p = p->link) {
-		a = p->from.type;
-		if(a == D_AUTO)
-			p->from.offset += deltasp;
-		if(a == D_PARAM)
-			p->from.offset += deltasp + 4;
-		a = p->to.type;
-		if(a == D_AUTO)
-			p->to.offset += deltasp;
-		if(a == D_PARAM)
-			p->to.offset += deltasp + 4;
-
-		switch(p->as) {
-		default:
-			continue;
-		case APUSHL:
-		case APUSHFL:
-			deltasp += 4;
-			p->spadj = 4;
-			continue;
-		case APUSHW:
-		case APUSHFW:
-			deltasp += 2;
-			p->spadj = 2;
-			continue;
-		case APOPL:
-		case APOPFL:
-			deltasp -= 4;
-			p->spadj = -4;
-			continue;
-		case APOPW:
-		case APOPFW:
-			deltasp -= 2;
-			p->spadj = -2;
-			continue;
-		case ARET:
-			break;
-		}
-
-		if(autoffset != deltasp)
-			ctxt->diag("unbalanced PUSH/POP");
-
-		if(autoffset) {
-			p->as = AADJSP;
-			p->from.type = D_CONST;
-			p->from.offset = -autoffset;
-			p->spadj = -autoffset;
-			p = appendp(ctxt, p);
-			p->as = 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) // retjmp
-			p->as = 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.
-static Prog*
-load_g_cx(Link *ctxt, Prog *p)
-{
-	Prog *next;
-
-	p->as = AMOVL;
-	p->from.type = D_INDIR+D_TLS;
-	p->from.offset = 0;
-	p->to.type = D_CX;
-
-	next = p->link;
-	progedit(ctxt, p);
-	while(p->link != next)
-		p = p->link;
-	
-	if(p->from.index == D_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.
-static Prog*
-stacksplit(Link *ctxt, Prog *p, int32 framesize, int noctxt, Prog **jmpok)
-{
-	Prog *q, *q1;
-
-	if(ctxt->debugstack) {
-		// 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 = appendp(ctxt, p);
-		p->as = ACMPL;
-		p->from.type = D_INDIR+D_CX;
-		p->from.offset = 4;
-		p->to.type = D_SP;
-
-		p = appendp(ctxt, p);
-		p->as = AJCC;
-		p->to.type = D_BRANCH;
-		p->to.offset = 4;
-		q1 = p;
-
-		p = appendp(ctxt, p);
-		p->as = AINT;
-		p->from.type = D_CONST;
-		p->from.offset = 3;
-		
-		p = appendp(ctxt, p);
-		p->as = ANOP;
-		q1->pcond = p;
-	}
-	q1 = nil;
-
-	if(framesize <= StackSmall) {
-		// small stack: SP <= stackguard
-		//	CMPL SP, stackguard
-		p = appendp(ctxt, p);
-		p->as = ACMPL;
-		p->from.type = D_SP;
-		p->to.type = D_INDIR+D_CX;
-		p->to.offset = 2*ctxt->arch->ptrsize;	// G.stackguard0
-		if(ctxt->cursym->cfunc)
-			p->to.offset = 3*ctxt->arch->ptrsize;	// G.stackguard1
-	} else if(framesize <= StackBig) {
-		// large stack: SP-framesize <= stackguard-StackSmall
-		//	LEAL -(framesize-StackSmall)(SP), AX
-		//	CMPL AX, stackguard
-		p = appendp(ctxt, p);
-		p->as = ALEAL;
-		p->from.type = D_INDIR+D_SP;
-		p->from.offset = -(framesize-StackSmall);
-		p->to.type = D_AX;
-
-		p = appendp(ctxt, p);
-		p->as = ACMPL;
-		p->from.type = D_AX;
-		p->to.type = D_INDIR+D_CX;
-		p->to.offset = 2*ctxt->arch->ptrsize;	// G.stackguard0
-		if(ctxt->cursym->cfunc)
-			p->to.offset = 3*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 = appendp(ctxt, p);
-		p->as = AMOVL;
-		p->from.type = D_INDIR+D_CX;
-		p->from.offset = 0;
-		p->from.offset = 2*ctxt->arch->ptrsize;	// G.stackguard0
-		if(ctxt->cursym->cfunc)
-			p->from.offset = 3*ctxt->arch->ptrsize;	// G.stackguard1
-		p->to.type = D_SI;
-
-		p = appendp(ctxt, p);
-		p->as = ACMPL;
-		p->from.type = D_SI;
-		p->to.type = D_CONST;
-		p->to.offset = (uint32)StackPreempt;
-
-		p = appendp(ctxt, p);
-		p->as = AJEQ;
-		p->to.type = D_BRANCH;
-		q1 = p;
-
-		p = appendp(ctxt, p);
-		p->as = ALEAL;
-		p->from.type = D_INDIR+D_SP;
-		p->from.offset = StackGuard;
-		p->to.type = D_AX;
-		
-		p = appendp(ctxt, p);
-		p->as = ASUBL;
-		p->from.type = D_SI;
-		p->from.offset = 0;
-		p->to.type = D_AX;
-		
-		p = appendp(ctxt, p);
-		p->as = ACMPL;
-		p->from.type = D_AX;
-		p->to.type = D_CONST;
-		p->to.offset = framesize+(StackGuard-StackSmall);
-	}		
-			
-	// common
-	p = appendp(ctxt, p);
-	p->as = AJHI;
-	p->to.type = D_BRANCH;
-	p->to.offset = 4;
-	q = p;
-
-	p = appendp(ctxt, p);
-	p->as = ACALL;
-	p->to.type = D_BRANCH;
-	if(ctxt->cursym->cfunc)
-		p->to.sym = linklookup(ctxt, "runtime.morestackc", 0);
-	else
-		p->to.sym = ctxt->symmorestack[noctxt];
-
-	p = appendp(ctxt, p);
-	p->as = AJMP;
-	p->to.type = D_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;
-}
-
-static void xfol(Link*, Prog*, Prog**);
-
-static void
-follow(Link *ctxt, LSym *s)
-{
-	Prog *firstp, *lastp;
-
-	ctxt->cursym = s;
-
-	firstp = ctxt->arch->prg();
-	lastp = firstp;
-	xfol(ctxt, s->text, &lastp);
-	lastp->link = nil;
-	s->text = firstp->link;
-}
-
-static int
-nofollow(int a)
-{
-	switch(a) {
-	case AJMP:
-	case ARET:
-	case AIRETL:
-	case AIRETW:
-	case AUNDEF:
-		return 1;
-	}
-	return 0;
-}
-
-static int
-pushpop(int a)
-{
-	switch(a) {
-	case APUSHL:
-	case APUSHFL:
-	case APUSHW:
-	case APUSHFW:
-	case APOPL:
-	case APOPFL:
-	case APOPW:
-	case APOPFW:
-		return 1;
-	}
-	return 0;
-}
-
-static int
-relinv(int a)
-{
-
-	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;
-	}
-	sysfatal("unknown relation: %s", anames8[a]);
-	return 0;
-}
-
-static void
-xfol(Link *ctxt, Prog *p, Prog **last)
-{
-	Prog *q;
-	int i;
-	int a;
-
-loop:
-	if(p == nil)
-		return;
-	if(p->as == AJMP)
-	if((q = p->pcond) != nil && q->as != 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) {
-		/* 
-		 * p goes here, but already used it elsewhere.
-		 * copy up to 4 instructions or else branch to other copy.
-		 */
-		for(i=0,q=p; i<4; i++,q=q->link) {
-			if(q == nil)
-				break;
-			if(q == *last)
-				break;
-			a = q->as;
-			if(a == ANOP) {
-				i--;
-				continue;
-			}
-			if(nofollow(a) || pushpop(a))	
-				break;	// NOTE(rsc): arm does goto copy
-			if(q->pcond == nil || q->pcond->mark)
-				continue;
-			if(a == ACALL || a == ALOOP)
-				continue;
-			for(;;) {
-				if(p->as == ANOP) {
-					p = p->link;
-					continue;
-				}
-				q = copyp(ctxt, p);
-				p = p->link;
-				q->mark = 1;
-				(*last)->link = q;
-				*last = q;
-				if(q->as != a || q->pcond == nil || q->pcond->mark)
-					continue;
-
-				q->as = relinv(q->as);
-				p = q->pcond;
-				q->pcond = q->link;
-				q->link = p;
-				xfol(ctxt, q->link, last);
-				p = q->link;
-				if(p->mark)
-					return;
-				goto loop;
-			}
-		} /* */
-		q = ctxt->arch->prg();
-		q->as = AJMP;
-		q->lineno = p->lineno;
-		q->to.type = D_BRANCH;
-		q->to.offset = p->pc;
-		q->pcond = p;
-		p = q;
-	}
-	
-	/* emit p */
-	p->mark = 1;
-	(*last)->link = p;
-	*last = p;
-	a = p->as;
-
-	/* continue loop with what comes after p */
-	if(nofollow(a))
-		return;
-	if(p->pcond != nil && a != ACALL) {
-		/*
-		 * some kind of conditional branch.
-		 * recurse to follow one path.
-		 * continue loop on the other.
-		 */
-		if((q = brchain(ctxt, p->pcond)) != nil)
-			p->pcond = q;
-		if((q = brchain(ctxt, p->link)) != nil)
-			p->link = q;
-		if(p->from.type == D_CONST) {
-			if(p->from.offset == 1) {
-				/*
-				 * expect conditional jump to be taken.
-				 * rewrite so that's the fall-through case.
-				 */
-				p->as = relinv(a);
-				q = p->link;
-				p->link = p->pcond;
-				p->pcond = q;
-			}
-		} else {
-			q = p->link;
-			if(q->mark)
-			if(a != ALOOP) {
-				p->as = relinv(a);
-				p->link = p->pcond;
-				p->pcond = q;
-			}
-		}
-		xfol(ctxt, p->link, last);
-		if(p->pcond->mark)
-			return;
-		p = p->pcond;
-		goto loop;
-	}
-	p = p->link;
-	goto loop;
-}
-
-LinkArch link386 = {
-	.name = "386",
-	.thechar = '8',
-	.endian = LittleEndian,
-
-	.addstacksplit = addstacksplit,
-	.assemble = span8,
-	.datasize = datasize,
-	.follow = follow,
-	.iscall = iscall,
-	.isdata = isdata,
-	.prg = prg,
-	.progedit = progedit,
-	.settextflag = settextflag,
-	.symtype = symtype,
-	.textflag = textflag,
-
-	.minlc = 1,
-	.ptrsize = 4,
-	.regsize = 4,
-
-	.D_ADDR = D_ADDR,
-	.D_AUTO = D_AUTO,
-	.D_BRANCH = D_BRANCH,
-	.D_CONST = D_CONST,
-	.D_EXTERN = D_EXTERN,
-	.D_FCONST = D_FCONST,
-	.D_NONE = D_NONE,
-	.D_PARAM = D_PARAM,
-	.D_SCONST = D_SCONST,
-	.D_STATIC = D_STATIC,
-
-	.ACALL = ACALL,
-	.ADATA = ADATA,
-	.AEND = AEND,
-	.AFUNCDATA = AFUNCDATA,
-	.AGLOBL = AGLOBL,
-	.AJMP = AJMP,
-	.ANOP = ANOP,
-	.APCDATA = APCDATA,
-	.ARET = ARET,
-	.ATEXT = ATEXT,
-	.ATYPE = ATYPE,
-	.AUSEFIELD = AUSEFIELD,
-};
diff --git a/src/liblink/objfile.c b/src/liblink/objfile.c
deleted file mode 100644
index b2478ec..0000000
--- a/src/liblink/objfile.c
+++ /dev/null
@@ -1,790 +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.
-
-// Writing and reading 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.
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <link.h>
-#include "../cmd/ld/textflag.h"
-#include "../runtime/funcdata.h"
-
-static void writesym(Link*, Biobuf*, LSym*);
-static void wrint(Biobuf*, int64);
-static void wrstring(Biobuf*, char*);
-static void wrpath(Link *, Biobuf*, char*);
-static void wrdata(Biobuf*, void*, int);
-static void wrsym(Biobuf*, LSym*);
-static void wrpathsym(Link *ctxt, Biobuf *b, LSym *s);
-
-static void readsym(Link*, Biobuf*, char*, char*);
-static int64 rdint(Biobuf*);
-static char *rdstring(Biobuf*);
-static void rddata(Biobuf*, uchar**, int*);
-static LSym *rdsym(Link*, Biobuf*, char*);
-
-// The Go and C compilers, and the assembler, call writeobj to write
-// out a Go object file.  The linker does not call this; the linker
-// does not write out object files.
-void
-writeobj(Link *ctxt, Biobuf *b)
-{
-	int flag, found;
-	Hist *h;
-	LSym *s, *text, *etext, *curtext, *data, *edata;
-	Plist *pl;
-	Prog *p, *plink;
-	Auto *a;
-
-	// 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 = nil;
-	curtext = nil;
-	data = nil;
-	etext = nil;
-	edata = nil;
-	for(pl = ctxt->plist; pl != nil; pl = pl->link) {
-		for(p = pl->firstpc; p != nil; p = plink) {
-			plink = p->link;
-			p->link = nil;
-
-			if(p->as == ctxt->arch->AEND)
-				continue;
-
-			if(p->as == ctxt->arch->ATYPE) {
-				// Assume each TYPE instruction describes
-				// a different local variable or parameter,
-				// so no dedup.
-				// Using only the TYPE instructions means
-				// that we discard location information about local variables
-				// in C and assembly functions; that information is inferred
-				// from ordinary references, because there are no TYPE
-				// instructions there. Without the type information, gdb can't
-				// use the locations, so we don't bother to save them.
-				// If something else could use them, we could arrange to
-				// preserve them.
-				if(curtext == nil)
-					continue;
-				a = emallocz(sizeof *a);
-				a->asym = p->from.sym;
-				a->aoffset = p->from.offset;
-				a->type = ctxt->arch->symtype(&p->from);
-				a->gotype = p->from.gotype;
-				a->link = curtext->autom;
-				curtext->autom = a;
-				continue;
-			}
-
-			if(p->as == ctxt->arch->AGLOBL) {
-				s = p->from.sym;
-				if(s->seenglobl++)
-					print("duplicate %P\n", p);
-				if(s->onlist)
-					sysfatal("symbol %s listed multiple times", s->name);
-				s->onlist = 1;
-				if(data == nil)
-					data = s;
-				else
-					edata->next = s;
-				s->next = nil;
-				s->size = p->to.offset;
-				if(s->type == 0 || s->type == SXREF)
-					s->type = SBSS;
-				flag = ctxt->arch->textflag(p);
-				if(flag & DUPOK)
-					s->dupok = 1;
-				if(flag & RODATA)
-					s->type = SRODATA;
-				else if(flag & NOPTR)
-					s->type = SNOPTRBSS;
-				edata = s;
-				continue;
-			}
-
-			if(p->as == ctxt->arch->ADATA) {
-				savedata(ctxt, p->from.sym, p, "<input>");
-				continue;
-			}
-
-			if(p->as == ctxt->arch->ATEXT) {
-				s = p->from.sym;
-				if(s == nil) {
-					// func _() { }
-					curtext = nil;
-					continue;
-				}
-				if(s->text != nil)
-					sysfatal("duplicate TEXT for %s", s->name);
-				if(s->onlist)
-					sysfatal("symbol %s listed multiple times", s->name);
-				s->onlist = 1;
-				if(text == nil)
-					text = s;
-				else
-					etext->next = s;
-				etext = s;
-				flag = ctxt->arch->textflag(p);
-				if(flag & DUPOK)
-					s->dupok = 1;
-				if(flag & NOSPLIT)
-					s->nosplit = 1;
-				s->next = nil;
-				s->type = STEXT;
-				s->text = p;
-				s->etext = p;
-				curtext = s;
-				continue;
-			}
-			
-			if(p->as == ctxt->arch->AFUNCDATA) {
-				// Rewrite reference to go_args_stackmap(SB) to the Go-provided declaration information.
-				if(curtext == nil) // func _() {}
-					continue;
-				if(strcmp(p->to.sym->name, "go_args_stackmap") == 0) {
-					if(p->from.type != ctxt->arch->D_CONST || p->from.offset != FUNCDATA_ArgsPointerMaps)
-						ctxt->diag("FUNCDATA use of go_args_stackmap(SB) without FUNCDATA_ArgsPointerMaps");
-					p->to.sym = linklookup(ctxt, smprint("%s.args_stackmap", curtext->name), curtext->version);
-				}
-			}
-			
-			if(curtext == nil)
-				continue;
-			s = curtext;
-			s->etext->link = p;
-			s->etext = p;
-		}
-	}
-	
-	// Add reference to Go arguments for C or assembly functions without them.
-	for(s = text; s != nil; s = s->next) {
-		if(strncmp(s->name, "\"\".", 3) != 0)
-			continue;
-		found = 0;
-		for(p = s->text; p != nil; p = p->link) {
-			if(p->as == ctxt->arch->AFUNCDATA && p->from.type == ctxt->arch->D_CONST && p->from.offset == FUNCDATA_ArgsPointerMaps) {
-				found = 1;
-				break;
-			}
-		}
-		if(!found) {
-			p = appendp(ctxt, s->text);
-			p->as = ctxt->arch->AFUNCDATA;
-			p->from.type = ctxt->arch->D_CONST;
-			p->from.offset = FUNCDATA_ArgsPointerMaps;
-			if(ctxt->arch->thechar == '6' || ctxt->arch->thechar == '8')
-				p->to.type = ctxt->arch->D_EXTERN;
-			else {
-				p->to.type = ctxt->arch->D_OREG;
-				p->to.name = ctxt->arch->D_EXTERN;
-			}
-			p->to.sym = linklookup(ctxt, smprint("%s.args_stackmap", s->name), s->version);
-		}
-	}
-
-	// Turn functions into machine code images.
-	for(s = text; s != nil; s = s->next) {
-		mkfwd(s);
-		linkpatch(ctxt, s);
-		ctxt->arch->follow(ctxt, s);
-		ctxt->arch->addstacksplit(ctxt, s);
-		ctxt->arch->assemble(ctxt, s);
-		linkpcln(ctxt, s);
-	}
-
-	// Emit header.
-	Bputc(b, 0);
-	Bputc(b, 0);
-	Bprint(b, "go13ld");
-	Bputc(b, 1); // version
-
-	// Emit autolib.
-	for(h = ctxt->hist; h != nil; h = h->link)
-		if(h->offset < 0)
-			wrstring(b, h->name);
-	wrstring(b, "");
-
-	// Emit symbols.
-	for(s = text; s != nil; s = s->next)
-		writesym(ctxt, b, s);
-	for(s = data; s != nil; s = s->next)
-		writesym(ctxt, b, s);
-
-	// Emit footer.
-	Bputc(b, 0xff);
-	Bputc(b, 0xff);
-	Bprint(b, "go13ld");
-}
-
-static void
-writesym(Link *ctxt, Biobuf *b, LSym *s)
-{
-	Reloc *r;
-	int i, j, c, n;
-	Pcln *pc;
-	Prog *p;
-	Auto *a;
-	char *name;
-
-	if(ctxt->debugasm) {
-		Bprint(ctxt->bso, "%s ", s->name);
-		if(s->version)
-			Bprint(ctxt->bso, "v=%d ", s->version);
-		if(s->type)
-			Bprint(ctxt->bso, "t=%d ", s->type);
-		if(s->dupok)
-			Bprint(ctxt->bso, "dupok ");
-		if(s->cfunc)
-			Bprint(ctxt->bso, "cfunc ");
-		if(s->nosplit)
-			Bprint(ctxt->bso, "nosplit ");
-		Bprint(ctxt->bso, "size=%lld value=%lld", (vlong)s->size, (vlong)s->value);
-		if(s->type == STEXT) {
-			Bprint(ctxt->bso, " args=%#llux locals=%#llux", (uvlong)s->args, (uvlong)s->locals);
-			if(s->leaf)
-				Bprint(ctxt->bso, " leaf");
-		}
-		Bprint(ctxt->bso, "\n");
-		for(p=s->text; p != nil; p = p->link)
-			Bprint(ctxt->bso, "\t%#06ux %P\n", (int)p->pc, p);
-		for(i=0; i<s->np; ) {
-			Bprint(ctxt->bso, "\t%#06ux", i);
-			for(j=i; j<i+16 && j<s->np; j++)
-				Bprint(ctxt->bso, " %02ux", s->p[j]);
-			for(; j<i+16; j++)
-				Bprint(ctxt->bso, "   ");
-			Bprint(ctxt->bso, "  ");
-			for(j=i; j<i+16 && j<s->np; j++) {
-				c = s->p[j];
-				if(' ' <= c && c <= 0x7e)
-					Bprint(ctxt->bso, "%c", c);
-				else
-					Bprint(ctxt->bso, ".");
-			}
-			Bprint(ctxt->bso, "\n");
-			i += 16;
-		}
-		for(i=0; i<s->nr; i++) {
-			r = &s->r[i];
-			name = "";
-			if(r->sym != nil)
-				name = r->sym->name;
-			Bprint(ctxt->bso, "\trel %d+%d t=%d %s+%lld\n", (int)r->off, r->siz, r->type, name, (vlong)r->add);
-		}
-	}
-
-	Bputc(b, 0xfe);
-	wrint(b, s->type);
-	wrstring(b, s->name);
-	wrint(b, s->version);
-	wrint(b, s->dupok);
-	wrint(b, s->size);
-	wrsym(b, s->gotype);
-	wrdata(b, s->p, s->np);
-
-	wrint(b, s->nr);
-	for(i=0; i<s->nr; i++) {
-		r = &s->r[i];
-		wrint(b, r->off);
-		wrint(b, r->siz);
-		wrint(b, r->type);
-		wrint(b, r->add);
-		wrint(b, r->xadd);
-		wrsym(b, r->sym);
-		wrsym(b, r->xsym);
-	}
-	
-	if(s->type == STEXT) {
-		wrint(b, s->args);
-		wrint(b, s->locals);
-		wrint(b, s->nosplit);
-		wrint(b, s->leaf | s->cfunc<<1);
-		n = 0;
-		for(a = s->autom; a != nil; a = a->link)
-			n++;
-		wrint(b, n);
-		for(a = s->autom; a != nil; a = a->link) {
-			wrsym(b, a->asym);
-			wrint(b, a->aoffset);
-			if(a->type == ctxt->arch->D_AUTO)
-				wrint(b, A_AUTO);
-			else if(a->type == ctxt->arch->D_PARAM)
-				wrint(b, A_PARAM);
-			else
-				sysfatal("%s: invalid local variable type %d", s->name, a->type);
-			wrsym(b, a->gotype);
-		}
-
-		pc = s->pcln;
-		wrdata(b, pc->pcsp.p, pc->pcsp.n);
-		wrdata(b, pc->pcfile.p, pc->pcfile.n);
-		wrdata(b, pc->pcline.p, pc->pcline.n);
-		wrint(b, pc->npcdata);
-		for(i=0; i<pc->npcdata; i++)
-			wrdata(b, pc->pcdata[i].p, pc->pcdata[i].n);
-		wrint(b, pc->nfuncdata);
-		for(i=0; i<pc->nfuncdata; i++)
-			wrsym(b, pc->funcdata[i]);
-		for(i=0; i<pc->nfuncdata; i++)
-			wrint(b, pc->funcdataoff[i]);
-		wrint(b, pc->nfile);
-		for(i=0; i<pc->nfile; i++)
-			wrpathsym(ctxt, b, pc->file[i]);
-	}
-}
-
-static void
-wrint(Biobuf *b, int64 sval)
-{
-	uint64 uv, v;
-	uchar buf[10], *p;
-
-	uv = ((uint64)sval<<1) ^ (uint64)(int64)(sval>>63);
-
-	p = buf;
-	for(v = uv; v >= 0x80; v >>= 7)
-		*p++ = v | 0x80;
-	*p++ = v;
-	
-	Bwrite(b, buf, p - buf);
-}
-
-static void
-wrstring(Biobuf *b, char *s)
-{
-	wrdata(b, s, strlen(s));
-}
-
-// wrpath writes a path just like a string, but on windows, it
-// translates '\\' to '/' in the process.
-static void
-wrpath(Link *ctxt, Biobuf *b, char *p)
-{
-	int i, n;
-	if (!ctxt->windows || strchr(p, '\\') == nil) {
-		wrstring(b, p);
-		return;
-	} else {
-		n = strlen(p);
-		wrint(b, n);
-		for (i = 0; i < n; i++)
-			Bputc(b, p[i] == '\\' ? '/' : p[i]);
-	}
-}
-
-static void
-wrdata(Biobuf *b, void *v, int n)
-{
-	wrint(b, n);
-	Bwrite(b, v, n);
-}
-
-static void
-wrpathsym(Link *ctxt, Biobuf *b, LSym *s)
-{
-	if(s == nil) {
-		wrint(b, 0);
-		wrint(b, 0);
-		return;
-	}
-	wrpath(ctxt, b, s->name);
-	wrint(b, s->version);
-}
-
-static void
-wrsym(Biobuf *b, LSym *s)
-{
-	if(s == nil) {
-		wrint(b, 0);
-		wrint(b, 0);
-		return;
-	}
-	wrstring(b, s->name);
-	wrint(b, s->version);
-}
-
-static char startmagic[] = "\x00\x00go13ld";
-static char endmagic[] = "\xff\xffgo13ld";
-
-void
-ldobjfile(Link *ctxt, Biobuf *f, char *pkg, int64 len, char *pn)
-{
-	int c;
-	uchar buf[8];
-	int64 start;
-	char *lib;
-
-	start = Boffset(f);
-	ctxt->version++;
-	memset(buf, 0, sizeof buf);
-	Bread(f, buf, sizeof buf);
-	if(memcmp(buf, startmagic, sizeof buf) != 0)
-		sysfatal("%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]);
-	if((c = Bgetc(f)) != 1)
-		sysfatal("%s: invalid file version number %d", pn, c);
-
-	for(;;) {
-		lib = rdstring(f);
-		if(lib[0] == 0)
-			break;
-		addlib(ctxt, pkg, pn, lib);
-	}
-	
-	for(;;) {
-		c = Bgetc(f);
-		Bungetc(f);
-		if(c == 0xff)
-			break;
-		readsym(ctxt, f, pkg, pn);
-	}
-	
-	memset(buf, 0, sizeof buf);
-	Bread(f, buf, sizeof buf);
-	if(memcmp(buf, endmagic, sizeof buf) != 0)
-		sysfatal("%s: invalid file end", pn);
-	
-	if(Boffset(f) != start+len)
-		sysfatal("%s: unexpected end at %lld, want %lld", pn, (vlong)Boffset(f), (vlong)(start+len));
-}
-
-static void
-readsym(Link *ctxt, Biobuf *f, char *pkg, char *pn)
-{
-	int i, j, c, t, v, n, size, dupok;
-	static int ndup;
-	char *name;
-	Reloc *r;
-	LSym *s, *dup, *typ;
-	Pcln *pc;
-	Auto *a;
-	
-	if(Bgetc(f) != 0xfe)
-		sysfatal("readsym out of sync");
-	t = rdint(f);
-	name = expandpkg(rdstring(f), pkg);
-	v = rdint(f);
-	if(v != 0 && v != 1)
-		sysfatal("invalid symbol version %d", v);
-	dupok = rdint(f);
-	dupok &= 1;
-	size = rdint(f);
-	
-	if(v != 0)
-		v = ctxt->version;
-	s = linklookup(ctxt, name, v);
-	dup = nil;
-	if(s->type != 0 && s->type != SXREF) {
-		if(s->type != SBSS && s->type != SNOPTRBSS && !dupok && !s->dupok)
-			sysfatal("duplicate symbol %s (types %d and %d) in %s and %s", s->name, s->type, t, s->file, pn);
-		if(s->np > 0) {
-			dup = s;
-			s = linknewsym(ctxt, ".dup", ndup++); // scratch
-		}
-	}
-	s->file = pkg;
-	s->dupok = dupok;
-	if(t == SXREF)
-		sysfatal("bad sxref");
-	if(t == 0)
-		sysfatal("missing type for %s in %s", name, pn);
-	s->type = t;
-	if(s->size < size)
-		s->size = size;
-	typ = rdsym(ctxt, f, pkg);
-	if(typ != nil) // if bss sym defined multiple times, take type from any one def
-		s->gotype = typ;
-	if(dup != nil && typ != nil)
-		dup->gotype = typ;
-	rddata(f, &s->p, &s->np);
-	s->maxp = s->np;
-	n = rdint(f);
-	if(n > 0) {
-		s->r = emallocz(n * sizeof s->r[0]);
-		s->nr = n;
-		s->maxr = n;
-		for(i=0; i<n; i++) {
-			r = &s->r[i];
-			r->off = rdint(f);
-			r->siz = rdint(f);
-			r->type = rdint(f);
-			r->add = rdint(f);
-			r->xadd = rdint(f);
-			r->sym = rdsym(ctxt, f, pkg);
-			r->xsym = rdsym(ctxt, f, pkg);
-		}
-	}
-	
-	if(s->np > 0 && dup != nil && dup->np > 0 && strncmp(s->name, "gclocals·", 10) == 0) {
-		// content-addressed garbage collection liveness bitmap symbol.
-		// double check for hash collisions.
-		if(s->np != dup->np || memcmp(s->p, dup->p, s->np) != 0)
-			sysfatal("dupok hash collision for %s in %s and %s", s->name, s->file, pn);
-	}
-	
-	if(s->type == STEXT) {
-		s->args = rdint(f);
-		s->locals = rdint(f);
-		s->nosplit = rdint(f);
-		v = rdint(f);
-		s->leaf = v&1;
-		s->cfunc = v&2;
-		n = rdint(f);
-		for(i=0; i<n; i++) {
-			a = emallocz(sizeof *a);
-			a->asym = rdsym(ctxt, f, pkg);
-			a->aoffset = rdint(f);
-			a->type = rdint(f);
-			a->gotype = rdsym(ctxt, f, pkg);
-			a->link = s->autom;
-			s->autom = a;
-		}
-
-		s->pcln = emallocz(sizeof *s->pcln);
-		pc = s->pcln;
-		rddata(f, &pc->pcsp.p, &pc->pcsp.n);
-		rddata(f, &pc->pcfile.p, &pc->pcfile.n);
-		rddata(f, &pc->pcline.p, &pc->pcline.n);
-		n = rdint(f);
-		pc->pcdata = emallocz(n * sizeof pc->pcdata[0]);
-		pc->npcdata = n;
-		for(i=0; i<n; i++)
-			rddata(f, &pc->pcdata[i].p, &pc->pcdata[i].n);
-		n = rdint(f);
-		pc->funcdata = emallocz(n * sizeof pc->funcdata[0]);
-		pc->funcdataoff = emallocz(n * sizeof pc->funcdataoff[0]);
-		pc->nfuncdata = n;
-		for(i=0; i<n; i++)
-			pc->funcdata[i] = rdsym(ctxt, f, pkg);
-		for(i=0; i<n; i++)
-			pc->funcdataoff[i] = rdint(f);
-		n = rdint(f);
-		pc->file = emallocz(n * sizeof pc->file[0]);
-		pc->nfile = n;
-		for(i=0; i<n; i++)
-			pc->file[i] = rdsym(ctxt, f, pkg);
-
-		if(dup == nil) {
-			if(s->onlist)
-				sysfatal("symbol %s listed multiple times", s->name);
-			s->onlist = 1;
-			if(ctxt->etextp)
-				ctxt->etextp->next = s;
-			else
-				ctxt->textp = s;
-			ctxt->etextp = s;
-		}
-	}
-
-	if(ctxt->debugasm) {
-		Bprint(ctxt->bso, "%s ", s->name);
-		if(s->version)
-			Bprint(ctxt->bso, "v=%d ", s->version);
-		if(s->type)
-			Bprint(ctxt->bso, "t=%d ", s->type);
-		if(s->dupok)
-			Bprint(ctxt->bso, "dupok ");
-		if(s->cfunc)
-			Bprint(ctxt->bso, "cfunc ");
-		if(s->nosplit)
-			Bprint(ctxt->bso, "nosplit ");
-		Bprint(ctxt->bso, "size=%lld value=%lld", (vlong)s->size, (vlong)s->value);
-		if(s->type == STEXT)
-			Bprint(ctxt->bso, " args=%#llux locals=%#llux", (uvlong)s->args, (uvlong)s->locals);
-		Bprint(ctxt->bso, "\n");
-		for(i=0; i<s->np; ) {
-			Bprint(ctxt->bso, "\t%#06ux", i);
-			for(j=i; j<i+16 && j<s->np; j++)
-				Bprint(ctxt->bso, " %02ux", s->p[j]);
-			for(; j<i+16; j++)
-				Bprint(ctxt->bso, "   ");
-			Bprint(ctxt->bso, "  ");
-			for(j=i; j<i+16 && j<s->np; j++) {
-				c = s->p[j];
-				if(' ' <= c && c <= 0x7e)
-					Bprint(ctxt->bso, "%c", c);
-				else
-					Bprint(ctxt->bso, ".");
-			}
-			Bprint(ctxt->bso, "\n");
-			i += 16;
-		}
-		for(i=0; i<s->nr; i++) {
-			r = &s->r[i];
-			Bprint(ctxt->bso, "\trel %d+%d t=%d %s+%lld\n", (int)r->off, r->siz, r->type, r->sym->name, (vlong)r->add);
-		}
-	}
-}
-
-static int64
-rdint(Biobuf *f)
-{
-	int c;
-	uint64 uv;
-	int shift;
-	
-	uv = 0;
-	for(shift = 0;; shift += 7) {
-		if(shift >= 64)
-			sysfatal("corrupt input");
-		c = Bgetc(f);
-		uv |= (uint64)(c & 0x7F) << shift;
-		if(!(c & 0x80))
-			break;
-	}
-
-	return (int64)(uv>>1) ^ ((int64)((uint64)uv<<63)>>63);
-}
-
-static char*
-rdstring(Biobuf *f)
-{
-	int n;
-	char *p;
-	
-	n = rdint(f);
-	p = emallocz(n+1);
-	Bread(f, p, n);
-	return p;
-}
-
-static void
-rddata(Biobuf *f, uchar **pp, int *np)
-{
-	*np = rdint(f);
-	*pp = emallocz(*np);
-	Bread(f, *pp, *np);
-}
-
-static LSym*
-rdsym(Link *ctxt, Biobuf *f, char *pkg)
-{
-	int n, v;
-	char *p;
-	LSym *s;
-	
-	n = rdint(f);
-	if(n == 0) {
-		rdint(f);
-		return nil;
-	}
-	p = emallocz(n+1);
-	Bread(f, p, n);
-	v = rdint(f);
-	if(v != 0)
-		v = ctxt->version;
-	s = linklookup(ctxt, expandpkg(p, pkg), v);
-	
-	if(v == 0 && s->name[0] == '$' && s->type == 0) {
-		if(strncmp(s->name, "$f32.", 5) == 0) {
-			int32 i32;
-			i32 = strtoul(s->name+5, nil, 16);
-			s->type = SRODATA;
-			adduint32(ctxt, s, i32);
-			s->reachable = 0;
-		} else if(strncmp(s->name, "$f64.", 5) == 0) {
-			int64 i64;
-			i64 = strtoull(s->name+5, nil, 16);
-			s->type = SRODATA;
-			adduint64(ctxt, s, i64);
-			s->reachable = 0;
-		}
-	}
-
-	return s;
-}
diff --git a/src/liblink/pass.c b/src/liblink/pass.c
deleted file mode 100644
index bc8eb43..0000000
--- a/src/liblink/pass.c
+++ /dev/null
@@ -1,115 +0,0 @@
-// Inferno utils/6l/pass.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/pass.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-// Code and data passes.
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <link.h>
-
-Prog*
-brchain(Link *ctxt, Prog *p)
-{
-	int i;
-
-	for(i=0; i<20; i++) {
-		if(p == nil || p->as != ctxt->arch->AJMP)
-			return p;
-		p = p->pcond;
-	}
-	return nil;
-}
-
-Prog*
-brloop(Link *ctxt, Prog *p)
-{
-	int c;
-	Prog *q;
-
-	c = 0;
-	for(q = p; q != nil; q = q->pcond) {
-		if(q->as != ctxt->arch->AJMP)
-			break;
-		c++;
-		if(c >= 5000)
-			return nil;
-	}
-	return q;
-}
-
-void
-linkpatch(Link *ctxt, LSym *sym)
-{
-	int32 c;
-	Prog *p, *q;
-
-	ctxt->cursym = sym;
-	
-	for(p = sym->text; p != nil; p = p->link) {
-		if(ctxt->arch->progedit)
-			ctxt->arch->progedit(ctxt, p);
-		if(p->to.type != ctxt->arch->D_BRANCH)
-			continue;
-		if(p->to.u.branch != nil) {
-			// TODO: Remove to.u.branch in favor of p->pcond.
-			p->pcond = p->to.u.branch;
-			continue;
-		}
-		if(p->to.sym != nil)
-			continue;
-		c = p->to.offset;
-		for(q = sym->text; q != nil;) {
-			if(c == q->pc)
-				break;
-			if(q->forwd != nil && c >= q->forwd->pc)
-				q = q->forwd;
-			else
-				q = q->link;
-		}
-		if(q == nil) {
-			ctxt->diag("branch out of range (%#ux)\n%P [%s]",
-				c, p, p->to.sym ? p->to.sym->name : "<nil>");
-			p->to.type = ctxt->arch->D_NONE;
-		}
-		p->to.u.branch = q;
-		p->pcond = q;
-	}
-	
-	for(p = sym->text; p != nil; p = p->link) {
-		p->mark = 0;	/* initialization for follow */
-		if(p->pcond != nil) {
-			p->pcond = brloop(ctxt, p->pcond);
-			if(p->pcond != nil)
-			if(p->to.type == ctxt->arch->D_BRANCH)
-				p->to.offset = p->pcond->pc;
-		}
-	}
-}
diff --git a/src/liblink/pcln.c b/src/liblink/pcln.c
deleted file mode 100644
index f0ee1dc..0000000
--- a/src/liblink/pcln.c
+++ /dev/null
@@ -1,365 +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.
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <link.h>
-
-static void
-addvarint(Link *ctxt, Pcdata *d, uint32 val)
-{
-	int32 n;
-	uint32 v;
-	uchar *p;
-
-	USED(ctxt);
-
-	n = 0;
-	for(v = val; v >= 0x80; v >>= 7)
-		n++;
-	n++;
-
-	if(d->n + n > d->m) {
-		d->m = (d->n + n)*2;
-		d->p = erealloc(d->p, d->m);
-	}
-
-	p = d->p + d->n;
-	for(v = val; v >= 0x80; v >>= 7)
-		*p++ = v | 0x80;
-	*p = v;
-	d->n += n;
-}
-
-// funcpctab writes to dst a pc-value table mapping the code in func to the values
-// returned by valfunc parameterized by arg. The invocation of valfunc to update the
-// current value is, for each p,
-//
-//	val = valfunc(func, val, p, 0, arg);
-//	record val as value at p->pc;
-//	val = valfunc(func, val, p, 1, arg);
-//
-// where func is the function, val is the current value, p is the instruction being
-// considered, and arg can be used to further parameterize valfunc.
-static void
-funcpctab(Link *ctxt, Pcdata *dst, LSym *func, char *desc, int32 (*valfunc)(Link*, LSym*, int32, Prog*, int32, void*), void* arg)
-{
-	int dbg, i;
-	int32 oldval, val, started;
-	uint32 delta;
-	vlong pc;
-	Prog *p;
-
-	// To debug a specific function, uncomment second line and change name.
-	dbg = 0;
-	//dbg = strcmp(func->name, "main.main") == 0;
-	//dbg = strcmp(desc, "pctofile") == 0;
-
-	ctxt->debugpcln += dbg;
-
-	dst->n = 0;
-
-	if(ctxt->debugpcln)
-		Bprint(ctxt->bso, "funcpctab %s [valfunc=%s]\n", func->name, desc);
-
-	val = -1;
-	oldval = val;
-	if(func->text == nil) {
-		ctxt->debugpcln -= dbg;
-		return;
-	}
-
-	pc = func->text->pc;
-	
-	if(ctxt->debugpcln)
-		Bprint(ctxt->bso, "%6llux %6d %P\n", pc, val, func->text);
-
-	started = 0;
-	for(p=func->text; p != nil; p = p->link) {
-		// Update val. If it's not changing, keep going.
-		val = valfunc(ctxt, func, val, p, 0, arg);
-		if(val == oldval && started) {
-			val = valfunc(ctxt, func, val, p, 1, arg);
-			if(ctxt->debugpcln)
-				Bprint(ctxt->bso, "%6llux %6s %P\n", (vlong)p->pc, "", p);
-			continue;
-		}
-
-		// If the pc of the next instruction is the same as the
-		// pc of this instruction, this instruction is not a real
-		// instruction. Keep going, so that we only emit a delta
-		// for a true instruction boundary in the program.
-		if(p->link && p->link->pc == p->pc) {
-			val = valfunc(ctxt, func, val, p, 1, arg);
-			if(ctxt->debugpcln)
-				Bprint(ctxt->bso, "%6llux %6s %P\n", (vlong)p->pc, "", p);
-			continue;
-		}
-
-		// The table is a sequence of (value, pc) pairs, where each
-		// pair states that the given value is in effect from the current position
-		// up to the given pc, which becomes the new current position.
-		// To generate the table as we scan over the program instructions,
-		// we emit a "(value" when pc == func->value, and then
-		// each time we observe a change in value we emit ", pc) (value".
-		// When the scan is over, we emit the closing ", pc)".
-		//
-		// The table is delta-encoded. The value deltas are signed and
-		// transmitted in zig-zag form, where a complement bit is placed in bit 0,
-		// and the pc deltas are unsigned. Both kinds of deltas are sent
-		// as variable-length little-endian base-128 integers,
-		// where the 0x80 bit indicates that the integer continues.
-
-		if(ctxt->debugpcln)
-			Bprint(ctxt->bso, "%6llux %6d %P\n", (vlong)p->pc, val, p);
-
-		if(started) {
-			addvarint(ctxt, dst, (p->pc - pc) / ctxt->arch->minlc);
-			pc = p->pc;
-		}
-		delta = val - oldval;
-		if(delta>>31)
-			delta = 1 | ~(delta<<1);
-		else
-			delta <<= 1;
-		addvarint(ctxt, dst, delta);
-		oldval = val;
-		started = 1;
-		val = valfunc(ctxt, func, val, p, 1, arg);
-	}
-
-	if(started) {
-		if(ctxt->debugpcln)
-			Bprint(ctxt->bso, "%6llux done\n", (vlong)func->text->pc+func->size);
-		addvarint(ctxt, dst, (func->value+func->size - pc) / ctxt->arch->minlc);
-		addvarint(ctxt, dst, 0); // terminator
-	}
-
-	if(ctxt->debugpcln) {
-		Bprint(ctxt->bso, "wrote %d bytes to %p\n", dst->n, dst);
-		for(i=0; i<dst->n; i++)
-			Bprint(ctxt->bso, " %02ux", dst->p[i]);
-		Bprint(ctxt->bso, "\n");
-	}
-
-	ctxt->debugpcln -= dbg;
-}
-
-// pctofileline computes either the file number (arg == 0)
-// or the line number (arg == 1) to use at p.
-// Because p->lineno applies to p, phase == 0 (before p)
-// takes care of the update.
-static int32
-pctofileline(Link *ctxt, LSym *sym, int32 oldval, Prog *p, int32 phase, void *arg)
-{
-	int32 i, l;
-	LSym *f;
-	Pcln *pcln;
-
-	USED(sym);
-
-	if(p->as == ctxt->arch->ATEXT || p->as == ctxt->arch->ANOP || p->as == ctxt->arch->AUSEFIELD || p->lineno == 0 || phase == 1)
-		return oldval;
-	linkgetline(ctxt, p->lineno, &f, &l);
-	if(f == nil) {
-	//	print("getline failed for %s %P\n", ctxt->cursym->name, p);
-		return oldval;
-	}
-	if(arg == nil)
-		return l;
-	pcln = arg;
-	
-	if(f == pcln->lastfile)
-		return pcln->lastindex;
-
-	for(i=0; i<pcln->nfile; i++) {
-		if(pcln->file[i] == f) {
-			pcln->lastfile = f;
-			pcln->lastindex = i;
-			return i;
-		}
-	}
-
-	if(pcln->nfile >= pcln->mfile) {
-		pcln->mfile = (pcln->nfile+1)*2;
-		pcln->file = erealloc(pcln->file, pcln->mfile*sizeof pcln->file[0]);
-	}
-	pcln->file[pcln->nfile++] = f;
-	pcln->lastfile = f;
-	pcln->lastindex = i;
-	return i;
-}
-
-// pctospadj computes the sp adjustment in effect.
-// It is oldval plus any adjustment made by p itself.
-// The adjustment by p takes effect only after p, so we
-// apply the change during phase == 1.
-static int32
-pctospadj(Link *ctxt, LSym *sym, int32 oldval, Prog *p, int32 phase, void *arg)
-{
-	USED(arg);
-	USED(sym);
-
-	if(oldval == -1) // starting
-		oldval = 0;
-	if(phase == 0)
-		return oldval;
-	if(oldval + p->spadj < -10000 || oldval + p->spadj > 1100000000) {
-		ctxt->diag("overflow in spadj: %d + %d = %d", oldval, p->spadj, oldval + p->spadj);
-		sysfatal("bad code");
-	}
-	return oldval + p->spadj;
-}
-
-// pctopcdata computes the pcdata value in effect at p.
-// A PCDATA instruction sets the value in effect at future
-// non-PCDATA instructions.
-// Since PCDATA instructions have no width in the final code,
-// it does not matter which phase we use for the update.
-static int32
-pctopcdata(Link *ctxt, LSym *sym, int32 oldval, Prog *p, int32 phase, void *arg)
-{
-	USED(sym);
-
-	if(phase == 0 || p->as != ctxt->arch->APCDATA || p->from.offset != (uintptr)arg)
-		return oldval;
-	if((int32)p->to.offset != p->to.offset) {
-		ctxt->diag("overflow in PCDATA instruction: %P", p);
-		sysfatal("bad code");
-	}
-	return p->to.offset;
-}
-
-void
-linkpcln(Link *ctxt, LSym *cursym)
-{
-	Prog *p;
-	Pcln *pcln;
-	int i, npcdata, nfuncdata, n;
-	uint32 *havepc, *havefunc;
-
-	ctxt->cursym = cursym;
-
-	pcln = emallocz(sizeof *pcln);
-	cursym->pcln = pcln;
-
-	npcdata = 0;
-	nfuncdata = 0;
-	for(p = cursym->text; p != nil; p = p->link) {
-		if(p->as == ctxt->arch->APCDATA && p->from.offset >= npcdata)
-			npcdata = p->from.offset+1;
-		if(p->as == ctxt->arch->AFUNCDATA && p->from.offset >= nfuncdata)
-			nfuncdata = p->from.offset+1;
-	}
-
-	pcln->pcdata = emallocz(npcdata*sizeof pcln->pcdata[0]);
-	pcln->npcdata = npcdata;
-	pcln->funcdata = emallocz(nfuncdata*sizeof pcln->funcdata[0]);
-	pcln->funcdataoff = emallocz(nfuncdata*sizeof pcln->funcdataoff[0]);
-	pcln->nfuncdata = nfuncdata;
-
-	funcpctab(ctxt, &pcln->pcsp, cursym, "pctospadj", pctospadj, nil);
-	funcpctab(ctxt, &pcln->pcfile, cursym, "pctofile", pctofileline, pcln);
-	funcpctab(ctxt, &pcln->pcline, cursym, "pctoline", pctofileline, nil);
-	
-	// tabulate which pc and func data we have.
-	n = ((npcdata+31)/32 + (nfuncdata+31)/32)*4;
-	havepc = emallocz(n);
-	havefunc = havepc + (npcdata+31)/32;
-	for(p = cursym->text; p != nil; p = p->link) {
-		if(p->as == ctxt->arch->AFUNCDATA) {
-			if((havefunc[p->from.offset/32]>>(p->from.offset%32))&1)
-				ctxt->diag("multiple definitions for FUNCDATA $%d", p->from.offset);
-			havefunc[p->from.offset/32] |= 1<<(p->from.offset%32);
-		}
-		if(p->as == ctxt->arch->APCDATA)
-			havepc[p->from.offset/32] |= 1<<(p->from.offset%32);
-	}
-	// pcdata.
-	for(i=0; i<npcdata; i++) {
-		if(((havepc[i/32]>>(i%32))&1) == 0) 
-			continue;
-		funcpctab(ctxt, &pcln->pcdata[i], cursym, "pctopcdata", pctopcdata, (void*)(uintptr)i);
-	}
-	free(havepc);
-	
-	// funcdata
-	if(nfuncdata > 0) {
-		for(p = cursym->text; p != nil; p = p->link) {
-			if(p->as == ctxt->arch->AFUNCDATA) {
-				i = p->from.offset;
-				pcln->funcdataoff[i] = p->to.offset;
-				if(p->to.type != ctxt->arch->D_CONST) {
-					// TODO: Dedup.
-					//funcdata_bytes += p->to.sym->size;
-					pcln->funcdata[i] = p->to.sym;
-				}
-			}
-		}
-	}
-}
-
-// iteration over encoded pcdata tables.
-
-static uint32
-getvarint(uchar **pp)
-{
-	uchar *p;
-	int shift;
-	uint32 v;
-
-	v = 0;
-	p = *pp;
-	for(shift = 0;; shift += 7) {
-		v |= (uint32)(*p & 0x7F) << shift;
-		if(!(*p++ & 0x80))
-			break;
-	}
-	*pp = p;
-	return v;
-}
-
-void
-pciternext(Pciter *it)
-{
-	uint32 v;
-	int32 dv;
-
-	it->pc = it->nextpc;
-	if(it->done)
-		return;
-	if(it->p >= it->d.p + it->d.n) {
-		it->done = 1;
-		return;
-	}
-
-	// value delta
-	v = getvarint(&it->p);
-	if(v == 0 && !it->start) {
-		it->done = 1;
-		return;
-	}
-	it->start = 0;
-	dv = (int32)(v>>1) ^ ((int32)(v<<31)>>31);
-	it->value += dv;
-	
-	// pc delta
-	v = getvarint(&it->p);
-	it->nextpc = it->pc + v*it->pcscale;
-}
-
-void
-pciterinit(Link *ctxt, Pciter *it, Pcdata *d)
-{
-	it->d = *d;
-	it->p = it->d.p;
-	it->pc = 0;
-	it->nextpc = 0;
-	it->value = -1;
-	it->start = 1;
-	it->done = 0;
-	it->pcscale = ctxt->arch->minlc;
-	pciternext(it);
-}
diff --git a/src/liblink/sym.c b/src/liblink/sym.c
deleted file mode 100644
index bd85518..0000000
--- a/src/liblink/sym.c
+++ /dev/null
@@ -1,268 +0,0 @@
-// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/obj.c
-// http://code.google.com/p/inferno-os/source/browse/utils/6l/span.c
-//
-//	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//	Portions Copyright © 1995-1997 C H Forsyth (forsyth at 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 at 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.
-
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <link.h>
-
-static int
-yy_isalpha(int c)
-{
-	return c >= 0 && c <= 0xFF && isalpha(c);
-}
-
-static struct {
-	char *name;
-	int val;
-} headers[] = {
-	{"android",	Hlinux},
-	{"darwin",	Hdarwin},
-	{"dragonfly",	Hdragonfly},
-	{"elf",		Helf},
-	{"freebsd",	Hfreebsd},
-	{"linux",	Hlinux},
-	{"nacl",		Hnacl},
-	{"netbsd",	Hnetbsd},
-	{"openbsd",	Hopenbsd},
-	{"plan9",	Hplan9},
-	{"solaris",	Hsolaris},
-	{"windows",	Hwindows},
-	{"windowsgui",	Hwindows},
-	{0, 0},
-};
-
-int
-headtype(char *name)
-{
-	int i;
-
-	for(i=0; headers[i].name; i++)
-		if(strcmp(name, headers[i].name) == 0)
-			return headers[i].val;
-	return -1;
-}
-
-char*
-headstr(int v)
-{
-	static char buf[20];
-	int i;
-
-	for(i=0; headers[i].name; i++)
-		if(v == headers[i].val)
-			return headers[i].name;
-	snprint(buf, sizeof buf, "%d", v);
-	return buf;
-}
-
-Link*
-linknew(LinkArch *arch)
-{
-	Link *ctxt;
-	char *p;
-	char buf[1024];
-
-	nuxiinit(arch);
-	
-	ctxt = emallocz(sizeof *ctxt);
-	ctxt->arch = arch;
-	ctxt->version = HistVersion;
-	ctxt->goroot = getgoroot();
-	ctxt->goroot_final = getenv("GOROOT_FINAL");
-	if(ctxt->goroot_final != nil && ctxt->goroot_final[0] == '\0')
-		ctxt->goroot_final = nil;
-
-	p = getgoarch();
-	if(strcmp(p, arch->name) != 0)
-		sysfatal("invalid goarch %s (want %s)", p, arch->name);
-	
-	if(getwd(buf, sizeof buf) == 0)
-		strcpy(buf, "/???");
-	if(yy_isalpha(buf[0]) && buf[1] == ':') {
-		// On Windows.
-		ctxt->windows = 1;
-
-		// Canonicalize path by converting \ to / (Windows accepts both).
-		for(p=buf; *p; p++)
-			if(*p == '\\')
-				*p = '/';
-	}
-	ctxt->pathname = strdup(buf);
-	
-	ctxt->headtype = headtype(getgoos());
-	if(ctxt->headtype < 0)
-		sysfatal("unknown goos %s", getgoos());
-	
-	// Record thread-local storage offset.
-	// TODO(rsc): Move tlsoffset back into the linker.
-	switch(ctxt->headtype) {
-	default:
-		sysfatal("unknown thread-local storage offset for %s", headstr(ctxt->headtype));
-	case Hplan9:
-	case Hwindows:
-		break;
-	case Hlinux:
-	case Hfreebsd:
-	case Hnetbsd:
-	case Hopenbsd:
-	case Hdragonfly:
-	case Hsolaris:
-		/*
-		 * ELF uses TLS offset negative from FS.
-		 * Translate 0(FS) and 8(FS) into -16(FS) and -8(FS).
-		 * Known to low-level assembly in package runtime and runtime/cgo.
-		 */
-		ctxt->tlsoffset = -2*ctxt->arch->ptrsize;
-		break;
-
-	case Hnacl:
-		switch(ctxt->arch->thechar) {
-		default:
-			sysfatal("unknown thread-local storage offset for nacl/%s", ctxt->arch->name);
-		case '6':
-			ctxt->tlsoffset = 0;
-			break;
-		case '8':
-			ctxt->tlsoffset = -8;
-			break;
-		case '5':
-			ctxt->tlsoffset = 0;
-			break;
-		}
-		break;
-
-	case Hdarwin:
-		/*
-		 * OS X system constants - offset from 0(GS) to our TLS.
-		 * Explained in ../../runtime/cgo/gcc_darwin_*.c.
-		 */
-		switch(ctxt->arch->thechar) {
-		default:
-			sysfatal("unknown thread-local storage offset for darwin/%s", ctxt->arch->name);
-		case '6':
-			ctxt->tlsoffset = 0x8a0;
-			break;
-		case '8':
-			ctxt->tlsoffset = 0x468;
-			break;
-		}
-		break;
-	}
-	
-	// On arm, record goarm.
-	if(ctxt->arch->thechar == '5') {
-		p = getgoarm();
-		if(p != nil)
-			ctxt->goarm = atoi(p);
-		else
-			ctxt->goarm = 6;
-	}
-
-	return ctxt;
-}
-
-LSym*
-linknewsym(Link *ctxt, char *symb, int v)
-{
-	LSym *s;
-
-	s = malloc(sizeof(*s));
-	memset(s, 0, sizeof(*s));
-
-	s->dynid = -1;
-	s->plt = -1;
-	s->got = -1;
-	s->name = estrdup(symb);
-	s->type = 0;
-	s->version = v;
-	s->value = 0;
-	s->sig = 0;
-	s->size = 0;
-	ctxt->nsymbol++;
-
-	s->allsym = ctxt->allsym;
-	ctxt->allsym = s;
-
-	return s;
-}
-
-static LSym*
-_lookup(Link *ctxt, char *symb, int v, int creat)
-{
-	LSym *s;
-	char *p;
-	uint32 h;
-	int c;
-
-	h = v;
-	for(p=symb; c = *p; p++)
-		h = h+h+h + c;
-	h &= 0xffffff;
-	h %= LINKHASH;
-	for(s = ctxt->hash[h]; s != nil; s = s->hash)
-		if(s->version == v && strcmp(s->name, symb) == 0)
-			return s;
-	if(!creat)
-		return nil;
-
-	s = linknewsym(ctxt, symb, v);
-	s->extname = s->name;
-	s->hash = ctxt->hash[h];
-	ctxt->hash[h] = s;
-
-	return s;
-}
-
-LSym*
-linklookup(Link *ctxt, char *name, int v)
-{
-	return _lookup(ctxt, name, v, 1);
-}
-
-// read-only lookup
-LSym*
-linkrlookup(Link *ctxt, char *name, int v)
-{
-	return _lookup(ctxt, name, v, 0);
-}
-
-int
-linksymfmt(Fmt *f)
-{
-	LSym *s;
-	
-	s = va_arg(f->args, LSym*);
-	if(s == nil)
-		return fmtstrcpy(f, "<nil>");
-	
-	return fmtstrcpy(f, s->name);
-}
diff --git a/src/log/log.go b/src/log/log.go
index d37e437..4cfe550 100644
--- a/src/log/log.go
+++ b/src/log/log.go
@@ -23,15 +23,21 @@ import (
 
 // These flags define which text to prefix to each log entry generated by the Logger.
 const (
-	// Bits or'ed together to control what's printed. There is no control over the
-	// order they appear (the order listed here) or the format they present (as
-	// described in the comments).  A colon appears after these items:
+	// Bits or'ed together to control what's printed.
+	// There is no control over the order they appear (the order listed
+	// here) or the format they present (as described in the comments).
+	// The prefix is followed by a colon only when Llongfile or Lshortfile
+	// is specified.
+	// For example, flags Ldate | Ltime (or LstdFlags) produce,
+	//	2009/01/23 01:23:23 message
+	// while flags Ldate | Ltime | Lmicroseconds | Llongfile produce,
 	//	2009/01/23 01:23:23.123123 /a/b/c/d.go:23: message
-	Ldate         = 1 << iota     // the date: 2009/01/23
-	Ltime                         // the time: 01:23:23
+	Ldate         = 1 << iota     // the date in the local time zone: 2009/01/23
+	Ltime                         // the time in the local time zone: 01:23:23
 	Lmicroseconds                 // microsecond resolution: 01:23:23.123123.  assumes Ltime.
 	Llongfile                     // full file name and line number: /a/b/c/d.go:23
 	Lshortfile                    // final file name element and line number: d.go:23. overrides Llongfile
+	LUTC                          // if Ldate or Ltime is set, use UTC rather than the local time zone
 	LstdFlags     = Ldate | Ltime // initial values for the standard logger
 )
 
@@ -55,30 +61,37 @@ func New(out io.Writer, prefix string, flag int) *Logger {
 	return &Logger{out: out, prefix: prefix, flag: flag}
 }
 
+// SetOutput sets the output destination for the logger.
+func (l *Logger) SetOutput(w io.Writer) {
+	l.mu.Lock()
+	defer l.mu.Unlock()
+	l.out = w
+}
+
 var std = New(os.Stderr, "", LstdFlags)
 
 // Cheap integer to fixed-width decimal ASCII.  Give a negative width to avoid zero-padding.
-// Knows the buffer has capacity.
 func itoa(buf *[]byte, i int, wid int) {
-	var u uint = uint(i)
-	if u == 0 && wid <= 1 {
-		*buf = append(*buf, '0')
-		return
-	}
-
 	// Assemble decimal in reverse order.
-	var b [32]byte
-	bp := len(b)
-	for ; u > 0 || wid > 0; u /= 10 {
-		bp--
+	var b [20]byte
+	bp := len(b) - 1
+	for i >= 10 || wid > 1 {
 		wid--
-		b[bp] = byte(u%10) + '0'
+		q := i / 10
+		b[bp] = byte('0' + i - q*10)
+		bp--
+		i = q
 	}
+	// i < 10
+	b[bp] = byte('0' + i)
 	*buf = append(*buf, b[bp:]...)
 }
 
 func (l *Logger) formatHeader(buf *[]byte, t time.Time, file string, line int) {
 	*buf = append(*buf, l.prefix...)
+	if l.flag&LUTC != 0 {
+		t = t.UTC()
+	}
 	if l.flag&(Ldate|Ltime|Lmicroseconds) != 0 {
 		if l.flag&Ldate != 0 {
 			year, month, day := t.Date()
@@ -147,7 +160,7 @@ func (l *Logger) Output(calldepth int, s string) error {
 	l.buf = l.buf[:0]
 	l.formatHeader(&l.buf, now, file, line)
 	l.buf = append(l.buf, s...)
-	if len(s) > 0 && s[len(s)-1] != '\n' {
+	if len(s) == 0 || s[len(s)-1] != '\n' {
 		l.buf = append(l.buf, '\n')
 	}
 	_, err := l.out.Write(l.buf)
@@ -320,3 +333,14 @@ func Panicln(v ...interface{}) {
 	std.Output(2, s)
 	panic(s)
 }
+
+// Output writes the output for a logging event.  The string s contains
+// the text to print after the prefix specified by the flags of the
+// Logger.  A newline is appended if the last character of s is not
+// already a newline.  Calldepth is the count of the number of
+// frames to skip when computing the file name and line number
+// if Llongfile or Lshortfile is set; a value of 1 will print the details
+// for the caller of Output.
+func Output(calldepth int, s string) error {
+	return std.Output(calldepth+1, s) // +1 for this frame.
+}
diff --git a/src/log/log_test.go b/src/log/log_test.go
index 158c3d9..dd16c9d 100644
--- a/src/log/log_test.go
+++ b/src/log/log_test.go
@@ -8,16 +8,19 @@ package log
 
 import (
 	"bytes"
+	"fmt"
 	"os"
 	"regexp"
+	"strings"
 	"testing"
+	"time"
 )
 
 const (
 	Rdate         = `[0-9][0-9][0-9][0-9]/[0-9][0-9]/[0-9][0-9]`
 	Rtime         = `[0-9][0-9]:[0-9][0-9]:[0-9][0-9]`
 	Rmicroseconds = `\.[0-9][0-9][0-9][0-9][0-9][0-9]`
-	Rline         = `(54|56):` // must update if the calls to l.Printf / l.Print below move
+	Rline         = `(57|59):` // must update if the calls to l.Printf / l.Print below move
 	Rlongfile     = `.*/[A-Za-z0-9_\-]+\.go:` + Rline
 	Rshortfile    = `[A-Za-z0-9_\-]+\.go:` + Rline
 )
@@ -117,3 +120,65 @@ func TestFlagAndPrefixSetting(t *testing.T) {
 		t.Error("message did not match pattern")
 	}
 }
+
+func TestUTCFlag(t *testing.T) {
+	var b bytes.Buffer
+	l := New(&b, "Test:", LstdFlags)
+	l.SetFlags(Ldate | Ltime | LUTC)
+	// Verify a log message looks right in the right time zone. Quantize to the second only.
+	now := time.Now().UTC()
+	l.Print("hello")
+	want := fmt.Sprintf("Test:%d/%.2d/%.2d %.2d:%.2d:%.2d hello\n",
+		now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second())
+	got := b.String()
+	if got == want {
+		return
+	}
+	// It's possible we crossed a second boundary between getting now and logging,
+	// so add a second and try again. This should very nearly always work.
+	now = now.Add(time.Second)
+	want = fmt.Sprintf("Test:%d/%.2d/%.2d %.2d:%.2d:%.2d hello\n",
+		now.Year(), now.Month(), now.Day(), now.Hour(), now.Minute(), now.Second())
+	if got == want {
+		return
+	}
+	t.Errorf("got %q; want %q", got, want)
+}
+
+func TestEmptyPrintCreatesLine(t *testing.T) {
+	var b bytes.Buffer
+	l := New(&b, "Header:", LstdFlags)
+	l.Print()
+	l.Println("non-empty")
+	output := b.String()
+	if n := strings.Count(output, "Header"); n != 2 {
+		t.Errorf("expected 2 headers, got %d", n)
+	}
+	if n := strings.Count(output, "\n"); n != 2 {
+		t.Errorf("expected 2 lines, got %d", n)
+	}
+}
+
+func BenchmarkItoa(b *testing.B) {
+	dst := make([]byte, 0, 64)
+	for i := 0; i < b.N; i++ {
+		dst = dst[0:0]
+		itoa(&dst, 2015, 4)   // year
+		itoa(&dst, 1, 2)      // month
+		itoa(&dst, 30, 2)     // day
+		itoa(&dst, 12, 2)     // hour
+		itoa(&dst, 56, 2)     // minute
+		itoa(&dst, 0, 2)      // second
+		itoa(&dst, 987654, 6) // microsecond
+	}
+}
+
+func BenchmarkPrintln(b *testing.B) {
+	const testString = "test"
+	var buf bytes.Buffer
+	l := New(&buf, "", LstdFlags)
+	for i := 0; i < b.N; i++ {
+		buf.Reset()
+		l.Println(testString)
+	}
+}
diff --git a/src/log/syslog/doc.go b/src/log/syslog/doc.go
new file mode 100644
index 0000000..54e76ed
--- /dev/null
+++ b/src/log/syslog/doc.go
@@ -0,0 +1,18 @@
+// 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.
+
+// Package syslog provides a simple interface to the system log
+// service. It can send messages to the syslog daemon using UNIX
+// domain sockets, UDP or TCP.
+//
+// Only one call to Dial is necessary. On write failures,
+// the syslog client will attempt to reconnect to the server
+// and write again.
+package syslog
+
+// BUG(brainman): This package is not implemented on Windows yet.
+
+// BUG(akumar): This package is not implemented on Plan 9 yet.
+
+// BUG(minux): This package is not implemented on NaCl (Native Client) yet.
diff --git a/src/log/syslog/syslog.go b/src/log/syslog/syslog.go
index 5e09599..4bf4476 100644
--- a/src/log/syslog/syslog.go
+++ b/src/log/syslog/syslog.go
@@ -4,13 +4,6 @@
 
 // +build !windows,!nacl,!plan9
 
-// Package syslog provides a simple interface to the system log
-// service. It can send messages to the syslog daemon using UNIX
-// domain sockets, UDP or TCP.
-//
-// Only one call to Dial is necessary. On write failures,
-// the syslog client will attempt to reconnect to the server
-// and write again.
 package syslog
 
 import (
diff --git a/src/log/syslog/syslog_plan9.go b/src/log/syslog/syslog_plan9.go
deleted file mode 100644
index 0c05f6f..0000000
--- a/src/log/syslog/syslog_plan9.go
+++ /dev/null
@@ -1,8 +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.
-
-// Package syslog provides a simple interface to the system log service.
-package syslog
-
-// BUG(akumar): This package is not implemented on Plan 9 yet.
diff --git a/src/log/syslog/syslog_test.go b/src/log/syslog/syslog_test.go
index 6a863fe..85aec53 100644
--- a/src/log/syslog/syslog_test.go
+++ b/src/log/syslog/syslog_test.go
@@ -14,6 +14,7 @@ import (
 	"log"
 	"net"
 	"os"
+	"runtime"
 	"sync"
 	"testing"
 	"time"
@@ -120,6 +121,13 @@ func TestWithSimulated(t *testing.T) {
 	msg := "Test 123"
 	transport := []string{"unix", "unixgram", "udp", "tcp"}
 
+	if runtime.GOOS == "darwin" {
+		switch runtime.GOARCH {
+		case "arm", "arm64":
+			transport = []string{"udp", "tcp"}
+		}
+	}
+
 	for _, tr := range transport {
 		done := make(chan string)
 		addr, sock, srvWG := startServer(tr, "", done)
@@ -142,6 +150,13 @@ func TestWithSimulated(t *testing.T) {
 }
 
 func TestFlap(t *testing.T) {
+	if runtime.GOOS == "darwin" {
+		switch runtime.GOARCH {
+		case "arm", "arm64":
+			t.Skipf("skipping on %s/%s", runtime.GOOS, runtime.GOARCH)
+		}
+	}
+
 	net := "unix"
 	done := make(chan string)
 	addr, sock, srvWG := startServer(net, "", done)
@@ -306,9 +321,17 @@ func TestConcurrentReconnect(t *testing.T) {
 	const N = 10
 	const M = 100
 	net := "unix"
+	if runtime.GOOS == "darwin" {
+		switch runtime.GOARCH {
+		case "arm", "arm64":
+			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/log/syslog/syslog_windows.go b/src/log/syslog/syslog_windows.go
deleted file mode 100644
index 8d99e2e..0000000
--- a/src/log/syslog/syslog_windows.go
+++ /dev/null
@@ -1,8 +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.
-
-// Package syslog provides a simple interface to the system log service.
-package syslog
-
-// BUG(brainman): This package is not implemented on Windows yet.
diff --git a/src/make.bash b/src/make.bash
index fbc6f5d..f17648a 100755
--- a/src/make.bash
+++ b/src/make.bash
@@ -3,6 +3,8 @@
 # Use of this source code is governed by a BSD-style
 # license that can be found in the LICENSE file.
 
+# See golang.org/s/go15bootstrap for an overview of the build process.
+
 # Environment variables that control make.bash:
 #
 # GOROOT_FINAL: The expected final Go root, baked into binaries.
@@ -17,15 +19,12 @@
 #
 # GOOS: The target operating system for installed packages and tools.
 #
-# GO_GCFLAGS: Additional 5g/6g/8g arguments to use when
+# GO_GCFLAGS: Additional go tool compile arguments to use when
 # building the packages and commands.
 #
-# GO_LDFLAGS: Additional 5l/6l/8l arguments to use when
+# GO_LDFLAGS: Additional go tool link arguments to use when
 # building the commands.
 #
-# GO_CCFLAGS: Additional 5c/6c/8c arguments to use when
-# building.
-#
 # 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.
@@ -110,26 +109,16 @@ rm -f ./runtime/runtime_defs.go
 
 # Finally!  Run the build.
 
-echo '# Building C bootstrap tool.'
+echo '##### Building Go bootstrap tool.'
 echo cmd/dist
 export GOROOT="$(cd .. && pwd)"
-GOROOT_FINAL="${GOROOT_FINAL:-$GOROOT}"
-DEFGOROOT='-DGOROOT_FINAL="'"$GOROOT_FINAL"'"'
-
-mflag=""
-case "$GOHOSTARCH" in
-386) mflag=-m32;;
-amd64) mflag=-m64;;
-esac
-if [ "$(uname)" == "Darwin" ]; then
-	# golang.org/issue/5261
-	mflag="$mflag -mmacosx-version-min=10.6"
-fi
-# if gcc does not exist and $CC is not set, try clang if available.
-if [ -z "$CC" -a -z "$(type -t gcc)" -a -n "$(type -t clang)" ]; then
-	export CC=clang CXX=clang++
+GOROOT_BOOTSTRAP=${GOROOT_BOOTSTRAP:-$HOME/go1.4}
+if [ ! -x "$GOROOT_BOOTSTRAP/bin/go" ]; then
+	echo "ERROR: Cannot find $GOROOT_BOOTSTRAP/bin/go." >&2
+	echo "Set \$GOROOT_BOOTSTRAP to a working Go tree >= Go 1.4." >&2
 fi
-${CC:-gcc} $mflag -O2 -Wall -Werror -o cmd/dist/dist -Icmd/dist "$DEFGOROOT" cmd/dist/*.c
+rm -f cmd/dist/dist
+GOROOT="$GOROOT_BOOTSTRAP" GOOS="" GOARCH="" "$GOROOT_BOOTSTRAP/bin/go" build -o cmd/dist/dist ./cmd/dist
 
 # -e doesn't propagate out of eval, so check success by hand.
 eval $(./cmd/dist/dist env -p || echo FAIL=true)
@@ -149,7 +138,6 @@ if [ "$1" = "--dist-tool" ]; then
 	exit 0
 fi
 
-echo "# Building compilers and Go bootstrap tool for host, $GOHOSTOS/$GOHOSTARCH."
 buildall="-a"
 if [ "$1" = "--no-clean" ]; then
 	buildall=""
@@ -158,20 +146,19 @@ fi
 ./cmd/dist/dist bootstrap $buildall $GO_DISTFLAGS -v # builds go_bootstrap
 # Delay move of dist tool to now, because bootstrap may clear tool directory.
 mv cmd/dist/dist "$GOTOOLDIR"/dist
-"$GOTOOLDIR"/go_bootstrap clean -i std
 echo
 
 if [ "$GOHOSTARCH" != "$GOARCH" -o "$GOHOSTOS" != "$GOOS" ]; then
-	echo "# Building packages and commands for host, $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.
 	CC=$CC GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH \
-		"$GOTOOLDIR"/go_bootstrap install -ccflags "$GO_CCFLAGS" -gcflags "$GO_GCFLAGS" -ldflags "$GO_LDFLAGS" -v std
+		"$GOTOOLDIR"/go_bootstrap install -gcflags "$GO_GCFLAGS" -ldflags "$GO_LDFLAGS" -v std cmd
 	echo
 fi
 
-echo "# Building packages and commands for $GOOS/$GOARCH."
-CC=$CC_FOR_TARGET "$GOTOOLDIR"/go_bootstrap install $GO_FLAGS -ccflags "$GO_CCFLAGS" -gcflags "$GO_GCFLAGS" -ldflags "$GO_LDFLAGS" -v std
+echo "##### Building packages and commands for $GOOS/$GOARCH."
+CC=$CC_FOR_TARGET "$GOTOOLDIR"/go_bootstrap install $GO_FLAGS -gcflags "$GO_GCFLAGS" -ldflags "$GO_LDFLAGS" -v std cmd
 echo
 
 rm -f "$GOTOOLDIR"/go_bootstrap
diff --git a/src/make.bat b/src/make.bat
index fff1eb6..0efdcc5 100644
--- a/src/make.bat
+++ b/src/make.bat
@@ -16,15 +16,21 @@
 ::
 :: GOOS: The target operating system for installed packages and tools.
 ::
-:: GO_GCFLAGS: Additional 5g/6g/8g arguments to use when
+:: GO_GCFLAGS: Additional go tool compile arguments to use when
 :: building the packages and commands.
 ::
-:: GO_LDFLAGS: Additional 5l/6l/8l arguments to use when
+:: GO_LDFLAGS: Additional go tool link arguments to use when
 :: building the commands.
 ::
 :: 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
 
@@ -45,24 +51,24 @@ goto fail
 :: Clean old generated file that will cause problems in the build.
 del /F ".\pkg\runtime\runtime_defs.go" 2>NUL
 
-:: Grab default GOROOT_FINAL and set GOROOT for build.
-:: The expression %VAR:\=\\% means to take %VAR%
-:: and apply the substitution \ = \\, escaping the
-:: backslashes.  Then we wrap that in quotes to create
-:: a C string.
+:: Set GOROOT for build.
 cd ..
 set GOROOT=%CD%
 cd src
-if "x%GOROOT_FINAL%"=="x" set GOROOT_FINAL=%GOROOT%
-set DEFGOROOT=-DGOROOT_FINAL="\"%GOROOT_FINAL:\=\\%\""
 
-echo # Building C bootstrap tool.
+echo ##### Building Go bootstrap tool.
 echo cmd/dist
 if not exist ..\bin\tool mkdir ..\bin\tool
-:: Windows has no glob expansion, so spell out cmd/dist/*.c.
-gcc -O2 -Wall -Werror -o cmd/dist/dist.exe -Icmd/dist %DEFGOROOT% cmd/dist/buf.c cmd/dist/build.c cmd/dist/buildgc.c cmd/dist/buildgo.c cmd/dist/buildruntime.c cmd/dist/main.c cmd/dist/windows.c cmd/dist/arm.c
+if "x%GOROOT_BOOTSTRAP%"=="x" set GOROOT_BOOTSTRAP=%HOMEDRIVE%%HOMEPATH%\Go1.4
+if not exist "%GOROOT_BOOTSTRAP%\bin\go.exe" goto bootstrapfail
+setlocal
+set GOROOT=%GOROOT_BOOTSTRAP%
+set GOOS=
+set GOARCH=
+"%GOROOT_BOOTSTRAP%\bin\go" build -o cmd\dist\dist.exe .\cmd\dist
+endlocal
 if errorlevel 1 goto fail
-.\cmd\dist\dist env -wp >env.bat
+.\cmd\dist\dist env -w -p >env.bat
 if errorlevel 1 goto fail
 call env.bat
 del env.bat
@@ -71,14 +77,12 @@ echo.
 if x%1==x--dist-tool goto copydist
 if x%2==x--dist-tool goto copydist
 
-echo # Building compilers and Go bootstrap tool.
 set buildall=-a
 if x%1==x--no-clean set buildall=
 .\cmd\dist\dist bootstrap %buildall% -v
 if errorlevel 1 goto fail
 :: Delay move of dist tool to now, because bootstrap cleared tool directory.
 move .\cmd\dist\dist.exe "%GOTOOLDIR%\dist.exe"
-"%GOTOOLDIR%\go_bootstrap" clean -i std
 echo.
 
 if not %GOHOSTARCH% == %GOARCH% goto localbuild
@@ -86,18 +90,23 @@ if not %GOHOSTOS% == %GOOS% goto localbuild
 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%
-"%GOTOOLDIR%\go_bootstrap" install -gcflags "%GO_GCFLAGS%" -ldflags "%GO_LDFLAGS%" -v std
+"%GOTOOLDIR%\go_bootstrap" install -gcflags "%GO_GCFLAGS%" -ldflags "%GO_LDFLAGS%" -v std cmd
 endlocal
 if errorlevel 1 goto fail
 echo.
 
 :mainbuild
-echo # Building packages and commands.
-"%GOTOOLDIR%\go_bootstrap" install -gcflags "%GO_GCFLAGS%" -ldflags "%GO_LDFLAGS%" -a -v std
+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.
@@ -113,6 +122,10 @@ mkdir "%GOTOOLDIR%" 2>NUL
 copy cmd\dist\dist.exe "%GOTOOLDIR%\"
 goto end
 
+:bootstrapfail
+echo ERROR: Cannot find %GOROOT_BOOTSTRAP%\bin\go.exe
+echo "Set GOROOT_BOOTSTRAP to a working Go tree >= Go 1.4."
+
 :fail
 set GOBUILDFAIL=1
 if x%GOBUILDEXIT%==x1 exit %GOBUILDFAIL%
diff --git a/src/make.rc b/src/make.rc
index 7a62d6a..6016204 100755
--- a/src/make.rc
+++ b/src/make.rc
@@ -3,6 +3,8 @@
 # Use of this source code is governed by a BSD-style
 # license that can be found in the LICENSE file.
 
+# See golang.org/s/go15bootstrap for an overview of the build process.
+
 # Environment variables that control make.rc:
 #
 # GOROOT_FINAL: The expected final Go root, baked into binaries.
@@ -17,15 +19,12 @@
 #
 # GOOS: The target operating system for installed packages and tools.
 #
-# GO_GCFLAGS: Additional 5g/6g/8g arguments to use when
+# GO_GCFLAGS: Additional go tool compile arguments to use when
 # building the packages and commands.
 #
-# GO_LDFLAGS: Additional 5l/6l/8l arguments to use when
+# GO_LDFLAGS: Additional go tool link arguments to use when
 # building the commands.
 #
-# GO_CCFLAGS: Additional 5c/6c/8c arguments to use when
-# building.
-#
 # 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.
@@ -36,26 +35,24 @@ if(! test -f run.rc){
 	exit wrongdir
 }
 
-# Generate libc_plan9.h.
-../include/plan9/mklibc.rc > ../include/plan9/libc_plan9.h
-
 # Clean old generated file that will cause problems in the build.
 rm -f ./runtime/runtime_defs.go
 
 # Determine the host compiler toolchain.
 eval `{grep '^(CC|LD|O)=' /$objtype/mkfile}
 
-echo '# Building C bootstrap tool.'
+echo '##### Building Go bootstrap tool.'
 echo cmd/dist
 GOROOT = `{cd .. && pwd}
-if(! ~ $#GOROOT_FINAL 1)
-	GOROOT_FINAL = $GOROOT
-DEFGOROOT='-DGOROOT_FINAL="'$GOROOT_FINAL'"'
-
-for(i in cmd/dist/*.c)
-	$CC -FTVwp+ -DPLAN9 $DEFGOROOT $i
-$LD -o cmd/dist/dist *.$O
-rm *.$O
+if(! ~ $#GOROOT_BOOTSTRAP 1)
+	GOROOT_BOOTSTRAP = $home/go1.4
+if(! test -x $GOROOT_BOOTSTRAP/bin/go){
+	echo 'ERROR: Cannot find '$GOROOT_BOOTSTRAP'/bin/go.' >[1=2]
+	echo 'Set $GOROOT_BOOTSTRAP to a working Go tree >= Go 1.4.' >[1=2]
+	exit bootstrap
+}
+rm -f cmd/dist/dist
+GOROOT=$GOROOT_BOOTSTRAP GOOS='' GOARCH='' $GOROOT_BOOTSTRAP/bin/go build -o cmd/dist/dist ./cmd/dist
 
 eval `{./cmd/dist/dist env -9}
 echo
@@ -69,14 +66,12 @@ if(~ $1 --dist-tool){
 	exit
 }
 
-echo '# Building compilers and Go bootstrap tool for host,' $GOHOSTOS/$GOHOSTARCH^.
 buildall = -a
 if(~ $1 --no-clean)
 	buildall = ()
 ./cmd/dist/dist bootstrap $buildall -v # builds go_bootstrap
 # Delay move of dist tool to now, because bootstrap may clear tool directory.
 mv cmd/dist/dist $GOTOOLDIR/dist
-$GOTOOLDIR/go_bootstrap clean -i std
 echo
 
 # Run only one process at a time on 9vx.
@@ -84,14 +79,14 @@ if(~ $sysname vx32)
 	pflag = (-p 1)
 
 if(! ~ $GOHOSTARCH $GOARCH || ! ~ $GOHOSTOS $GOOS){
-	echo '# Building packages and commands for host,' $GOHOSTOS/$GOHOSTARCH^.
+	echo '##### Building packages and commands for host,' $GOHOSTOS/$GOHOSTARCH^.
 	GOOS=$GOHOSTOS GOARCH=$GOHOSTARCH \
-		$GOTOOLDIR/go_bootstrap install -ccflags $"GO_CCFLAGS -gcflags $"GO_GCFLAGS -ldflags $"GO_LDFLAGS -v $pflag std
+		$GOTOOLDIR/go_bootstrap install -gcflags $"GO_GCFLAGS -ldflags $"GO_LDFLAGS -v $pflag std cmd
 	echo
 }
 
-echo '# Building packages and commands for' $GOOS/$GOARCH^.
-$GOTOOLDIR/go_bootstrap install -ccflags $"GO_CCFLAGS -gcflags $"GO_GCFLAGS -ldflags $"GO_LDFLAGS -v $pflag std
+echo '##### Building packages and commands for' $GOOS/$GOARCH^.
+$GOTOOLDIR/go_bootstrap install -gcflags $"GO_GCFLAGS -ldflags $"GO_LDFLAGS -v $pflag std cmd
 echo
 
 rm -f $GOTOOLDIR/go_bootstrap
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/abs_ppc64x.s b/src/math/abs_ppc64x.s
new file mode 100644
index 0000000..06effb4
--- /dev/null
+++ b/src/math/abs_ppc64x.s
@@ -0,0 +1,14 @@
+// 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.
+
+// +build ppc64 ppc64le
+
+#include "textflag.h"
+
+TEXT ·Abs(SB),NOSPLIT,$0-16
+	MOVD	x+0(FP), R3
+	MOVD 	$((1<<63)-1), R4
+	AND	R4, R3
+	MOVD	R3, ret+8(FP)
+	RET
diff --git a/src/math/all_test.go b/src/math/all_test.go
index 763efb2..e18e45e 100644
--- a/src/math/all_test.go
+++ b/src/math/all_test.go
@@ -946,16 +946,20 @@ var expSC = []float64{
 
 var vfexpm1SC = []float64{
 	Inf(-1),
+	-710,
 	Copysign(0, -1),
 	0,
+	710,
 	Inf(1),
 	NaN(),
 }
 var expm1SC = []float64{
 	-1,
+	-1,
 	Copysign(0, -1),
 	0,
 	Inf(1),
+	Inf(1),
 	NaN(),
 }
 
@@ -991,6 +995,24 @@ var vffdimSC = [][2]float64{
 	{NaN(), Inf(1)},
 	{NaN(), NaN()},
 }
+var nan = Float64frombits(0xFFF8000000000000) // SSE2 DIVSD 0/0
+var vffdim2SC = [][2]float64{
+	{Inf(-1), Inf(-1)},
+	{Inf(-1), Inf(1)},
+	{Inf(-1), nan},
+	{Copysign(0, -1), Copysign(0, -1)},
+	{Copysign(0, -1), 0},
+	{0, Copysign(0, -1)},
+	{0, 0},
+	{Inf(1), Inf(-1)},
+	{Inf(1), Inf(1)},
+	{Inf(1), nan},
+	{nan, Inf(-1)},
+	{nan, Copysign(0, -1)},
+	{nan, 0},
+	{nan, Inf(1)},
+	{nan, nan},
+}
 var fdimSC = []float64{
 	NaN(),
 	0,
@@ -1708,8 +1730,10 @@ func tolerance(a, b, e float64) bool {
 		d = -d
 	}
 
-	if a != 0 {
-		e = e * a
+	// note: b is correct (expected) value, a is actual value.
+	// make error tolerance a fraction of b, not a.
+	if b != 0 {
+		e = e * b
 		if e < 0 {
 			e = -e
 		}
@@ -2015,6 +2039,11 @@ func TestDim(t *testing.T) {
 			t.Errorf("Dim(%g, %g) = %g, want %g", vffdimSC[i][0], vffdimSC[i][1], f, fdimSC[i])
 		}
 	}
+	for i := 0; i < len(vffdim2SC); i++ {
+		if f := Dim(vffdim2SC[i][0], vffdim2SC[i][1]); !alike(fdimSC[i], f) {
+			t.Errorf("Dim(%g, %g) = %g, want %g", vffdim2SC[i][0], vffdim2SC[i][1], f, fdimSC[i])
+		}
+	}
 }
 
 func TestFloor(t *testing.T) {
@@ -2041,6 +2070,11 @@ func TestMax(t *testing.T) {
 			t.Errorf("Max(%g, %g) = %g, want %g", vffdimSC[i][0], vffdimSC[i][1], f, fmaxSC[i])
 		}
 	}
+	for i := 0; i < len(vffdim2SC); i++ {
+		if f := Max(vffdim2SC[i][0], vffdim2SC[i][1]); !alike(fmaxSC[i], f) {
+			t.Errorf("Max(%g, %g) = %g, want %g", vffdim2SC[i][0], vffdim2SC[i][1], f, fmaxSC[i])
+		}
+	}
 }
 
 func TestMin(t *testing.T) {
@@ -2054,6 +2088,11 @@ func TestMin(t *testing.T) {
 			t.Errorf("Min(%g, %g) = %g, want %g", vffdimSC[i][0], vffdimSC[i][1], f, fminSC[i])
 		}
 	}
+	for i := 0; i < len(vffdim2SC); i++ {
+		if f := Min(vffdim2SC[i][0], vffdim2SC[i][1]); !alike(fminSC[i], f) {
+			t.Errorf("Min(%g, %g) = %g, want %g", vffdim2SC[i][0], vffdim2SC[i][1], f, fminSC[i])
+		}
+	}
 }
 
 func TestMod(t *testing.T) {
@@ -2606,7 +2645,7 @@ func TestLargeTan(t *testing.T) {
 
 // Check that math constants are accepted by compiler
 // and have right value (assumes strconv.ParseFloat works).
-// http://code.google.com/p/go/issues/detail?id=201
+// https://golang.org/issue/201
 
 type floatTest struct {
 	val  interface{}
@@ -2944,15 +2983,56 @@ func BenchmarkSinh(b *testing.B) {
 	}
 }
 
+var Global float64
+
 func BenchmarkSqrt(b *testing.B) {
+	x, y := 0.0, 10.0
+	for i := 0; i < b.N; i++ {
+		x += Sqrt(y)
+	}
+	Global = x
+}
+
+func BenchmarkSqrtIndirect(b *testing.B) {
+	x, y := 0.0, 10.0
+	f := Sqrt
 	for i := 0; i < b.N; i++ {
-		Sqrt(10)
+		x += f(y)
 	}
+	Global = x
 }
 
 func BenchmarkSqrtGo(b *testing.B) {
+	x, y := 0.0, 10.0
+	for i := 0; i < b.N; i++ {
+		x += SqrtGo(y)
+	}
+	Global = x
+}
+
+func isPrime(i int) bool {
+	// Yes, this is a dumb way to write this code,
+	// but calling Sqrt repeatedly in this way demonstrates
+	// the benefit of using a direct SQRT instruction on systems
+	// that have one, whereas the obvious loop seems not to
+	// demonstrate such a benefit.
+	for j := 2; float64(j) <= Sqrt(float64(i)); j++ {
+		if i%j == 0 {
+			return false
+		}
+	}
+	return true
+}
+
+func BenchmarkSqrtPrime(b *testing.B) {
+	any := false
 	for i := 0; i < b.N; i++ {
-		SqrtGo(10)
+		if isPrime(100003) {
+			any = true
+		}
+	}
+	if any {
+		Global = 1
 	}
 }
 
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.go b/src/math/big/arith.go
index 3d5a868..d7ea838 100644
--- a/src/math/big/arith.go
+++ b/src/math/big/arith.go
@@ -70,7 +70,7 @@ func mulWW_g(x, y Word) (z1, z0 Word) {
 
 // z1<<_W + z0 = x*y + c
 func mulAddWWW_g(x, y, c Word) (z1, z0 Word) {
-	z1, zz0 := mulWW(x, y)
+	z1, zz0 := mulWW_g(x, y)
 	if z0 = zz0 + c; z0 < zz0 {
 		z1++
 	}
@@ -107,11 +107,26 @@ func log2(x Word) int {
 	return bitLen(x) - 1
 }
 
-// Number of leading zeros in x.
-func leadingZeros(x Word) uint {
+// nlz returns the number of leading zeros in x.
+func nlz(x Word) uint {
 	return uint(_W - bitLen(x))
 }
 
+// nlz64 returns the number of leading zeros in x.
+func nlz64(x uint64) uint {
+	switch _W {
+	case 32:
+		w := x >> 32
+		if w == 0 {
+			return 32 + nlz(Word(x))
+		}
+		return nlz(Word(w))
+	case 64:
+		return nlz(Word(x))
+	}
+	panic("unreachable")
+}
+
 // q = (u1<<_W + u0 - r)/y
 // Adapted from Warren, Hacker's Delight, p. 152.
 func divWW_g(u1, u0, v Word) (q, r Word) {
@@ -119,7 +134,7 @@ func divWW_g(u1, u0, v Word) (q, r Word) {
 		return 1<<_W - 1, 1<<_W - 1
 	}
 
-	s := leadingZeros(v)
+	s := nlz(v)
 	v <<= s
 
 	vn1 := v >> _W2
@@ -154,32 +169,81 @@ func divWW_g(u1, u0, v Word) (q, r Word) {
 	return q1*_B2 + q0, (un21*_B2 + un0 - q0*v) >> s
 }
 
+// Keep for performance debugging.
+// Using addWW_g is likely slower.
+const use_addWW_g = false
+
+// The resulting carry c is either 0 or 1.
 func addVV_g(z, x, y []Word) (c Word) {
-	for i := range z {
-		c, z[i] = addWW_g(x[i], y[i], c)
+	if use_addWW_g {
+		for i := range z {
+			c, z[i] = addWW_g(x[i], y[i], c)
+		}
+		return
+	}
+
+	for i, xi := range x[:len(z)] {
+		yi := y[i]
+		zi := xi + yi + c
+		z[i] = zi
+		// see "Hacker's Delight", section 2-12 (overflow detection)
+		c = (xi&yi | (xi|yi)&^zi) >> (_W - 1)
 	}
 	return
 }
 
+// The resulting carry c is either 0 or 1.
 func subVV_g(z, x, y []Word) (c Word) {
-	for i := range z {
-		c, z[i] = subWW_g(x[i], y[i], c)
+	if use_addWW_g {
+		for i := range z {
+			c, z[i] = subWW_g(x[i], y[i], c)
+		}
+		return
+	}
+
+	for i, xi := range x[:len(z)] {
+		yi := y[i]
+		zi := xi - yi - c
+		z[i] = zi
+		// see "Hacker's Delight", section 2-12 (overflow detection)
+		c = (yi&^xi | (yi|^xi)&zi) >> (_W - 1)
 	}
 	return
 }
 
+// The resulting carry c is either 0 or 1.
 func addVW_g(z, x []Word, y Word) (c Word) {
+	if use_addWW_g {
+		c = y
+		for i := range z {
+			c, z[i] = addWW_g(x[i], c, 0)
+		}
+		return
+	}
+
 	c = y
-	for i := range z {
-		c, z[i] = addWW_g(x[i], c, 0)
+	for i, xi := range x[:len(z)] {
+		zi := xi + c
+		z[i] = zi
+		c = xi &^ zi >> (_W - 1)
 	}
 	return
 }
 
 func subVW_g(z, x []Word, y Word) (c Word) {
+	if use_addWW_g {
+		c = y
+		for i := range z {
+			c, z[i] = subWW_g(x[i], c, 0)
+		}
+		return
+	}
+
 	c = y
-	for i := range z {
-		c, z[i] = subWW_g(x[i], c, 0)
+	for i, xi := range x[:len(z)] {
+		zi := xi - c
+		z[i] = zi
+		c = (zi &^ xi) >> (_W - 1)
 	}
 	return
 }
@@ -222,6 +286,7 @@ func mulAddVWW_g(z, x []Word, y, r Word) (c Word) {
 	return
 }
 
+// TODO(gri) Remove use of addWW_g here and then we can remove addWW_g and subWW_g.
 func addMulVVW_g(z, x []Word, y Word) (c Word) {
 	for i := range z {
 		z1, z0 := mulAddWWW_g(x[i], y, z[i])
diff --git a/src/math/big/arith_386.s b/src/math/big/arith_386.s
index 1b47c89..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
@@ -37,15 +39,16 @@ TEXT ·addVV(SB),NOSPLIT,$0
 	JMP E1
 
 L1:	MOVL (SI)(BX*4), AX
-	RCRL $1, DX
+	ADDL DX, DX		// restore CF
 	ADCL (CX)(BX*4), AX
-	RCLL $1, DX
+	SBBL DX, DX		// save CF
 	MOVL AX, (DI)(BX*4)
 	ADDL $1, BX		// i++
 
 E1:	CMPL BX, BP		// i < n
 	JL L1
 
+	NEGL DX
 	MOVL DX, c+36(FP)
 	RET
 
@@ -62,15 +65,16 @@ TEXT ·subVV(SB),NOSPLIT,$0
 	JMP E2
 
 L2:	MOVL (SI)(BX*4), AX
-	RCRL $1, DX
+	ADDL DX, DX		// restore CF
 	SBBL (CX)(BX*4), AX
-	RCLL $1, DX
+	SBBL DX, DX		// save CF
 	MOVL AX, (DI)(BX*4)
 	ADDL $1, BX		// i++
 
 E2:	CMPL BX, BP		// i < n
 	JL L2
 
+	NEGL DX
 	MOVL DX, c+36(FP)
 	RET
 
@@ -86,8 +90,8 @@ TEXT ·addVW(SB),NOSPLIT,$0
 
 L3:	ADDL (SI)(BX*4), AX
 	MOVL AX, (DI)(BX*4)
-	RCLL $1, AX
-	ANDL $1, AX
+	SBBL AX, AX		// save CF
+	NEGL AX
 	ADDL $1, BX		// i++
 
 E3:	CMPL BX, BP		// i < n
@@ -106,11 +110,11 @@ TEXT ·subVW(SB),NOSPLIT,$0
 	MOVL $0, BX		// i = 0
 	JMP E4
 
-L4:	MOVL (SI)(BX*4), DX	// TODO(gri) is there a reverse SUBL?
+L4:	MOVL (SI)(BX*4), DX
 	SUBL AX, DX
 	MOVL DX, (DI)(BX*4)
-	RCLL $1, AX
-	ANDL $1, AX
+	SBBL AX, AX		// save CF
+	NEGL AX
 	ADDL $1, BX		// i++
 
 E4:	CMPL BX, BP		// i < n
diff --git a/src/math/big/arith_amd64.s b/src/math/big/arith_amd64.s
index 56c4cb0..b69a2c6 100644
--- a/src/math/big/arith_amd64.s
+++ b/src/math/big/arith_amd64.s
@@ -2,21 +2,13 @@
 // 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.
 
-// Literal instruction for MOVQ $0, CX.
-// (MOVQ $0, reg is translated to XORQ reg, reg and clears CF.)
-#define ZERO_CX BYTE $0x48; \
-		BYTE $0xc7; \
-		BYTE $0xc1; \
-		BYTE $0x00; \
-		BYTE $0x00; \
-		BYTE $0x00; \
-		BYTE $0x00
-
 // func mulWW(x, y Word) (z1, z0 Word)
 TEXT ·mulWW(SB),NOSPLIT,$0
 	MOVQ x+0(FP), AX
@@ -35,6 +27,11 @@ TEXT ·divWW(SB),NOSPLIT,$0
 	MOVQ DX, r+32(FP)
 	RET
 
+// The carry bit is saved with SBBQ Rx, Rx: if the carry was set, Rx is -1, otherwise it is 0.
+// It is restored with ADDQ Rx, Rx: if Rx was -1 the carry is set, otherwise it is cleared.
+// This is faster than using rotate instructions.
+//
+// CAUTION: Note that MOVQ $0, Rx is translated to XORQ Rx, Rx which clears the carry bit!
 
 // func addVV(z, x, y []Word) (c Word)
 TEXT ·addVV(SB),NOSPLIT,$0
@@ -52,7 +49,7 @@ TEXT ·addVV(SB),NOSPLIT,$0
 
 U1:	// n >= 0
 	// regular loop body unrolled 4x
-	RCRQ $1, CX		// CF = c
+	ADDQ CX, CX		// restore CF
 	MOVQ 0(R8)(SI*8), R11
 	MOVQ 8(R8)(SI*8), R12
 	MOVQ 16(R8)(SI*8), R13
@@ -65,7 +62,7 @@ U1:	// n >= 0
 	MOVQ R12, 8(R10)(SI*8)
 	MOVQ R13, 16(R10)(SI*8)
 	MOVQ R14, 24(R10)(SI*8)
-	RCLQ $1, CX		// c = CF
+	SBBQ CX, CX		// save CF
 
 	ADDQ $4, SI		// i += 4
 	SUBQ $4, DI		// n -= 4
@@ -75,17 +72,18 @@ V1:	ADDQ $4, DI		// n += 4
 	JLE E1			// if n <= 0 goto E1
 
 L1:	// n > 0
-	RCRQ $1, CX		// CF = c
+	ADDQ CX, CX		// restore CF
 	MOVQ 0(R8)(SI*8), R11
 	ADCQ 0(R9)(SI*8), R11
 	MOVQ R11, 0(R10)(SI*8)
-	RCLQ $1, CX		// c = CF
+	SBBQ CX, CX		// save CF
 
 	ADDQ $1, SI		// i++
 	SUBQ $1, DI		// n--
 	JG L1			// if n > 0 goto L1
 
-E1:	MOVQ CX, c+72(FP)	// return c
+E1:	NEGQ CX
+	MOVQ CX, c+72(FP)	// return c
 	RET
 
 
@@ -106,7 +104,7 @@ TEXT ·subVV(SB),NOSPLIT,$0
 
 U2:	// n >= 0
 	// regular loop body unrolled 4x
-	RCRQ $1, CX		// CF = c
+	ADDQ CX, CX		// restore CF
 	MOVQ 0(R8)(SI*8), R11
 	MOVQ 8(R8)(SI*8), R12
 	MOVQ 16(R8)(SI*8), R13
@@ -119,7 +117,7 @@ U2:	// n >= 0
 	MOVQ R12, 8(R10)(SI*8)
 	MOVQ R13, 16(R10)(SI*8)
 	MOVQ R14, 24(R10)(SI*8)
-	RCLQ $1, CX		// c = CF
+	SBBQ CX, CX		// save CF
 
 	ADDQ $4, SI		// i += 4
 	SUBQ $4, DI		// n -= 4
@@ -129,17 +127,18 @@ V2:	ADDQ $4, DI		// n += 4
 	JLE E2			// if n <= 0 goto E2
 
 L2:	// n > 0
-	RCRQ $1, CX		// CF = c
+	ADDQ CX, CX		// restore CF
 	MOVQ 0(R8)(SI*8), R11
 	SBBQ 0(R9)(SI*8), R11
 	MOVQ R11, 0(R10)(SI*8)
-	RCLQ $1, CX		// c = CF
+	SBBQ CX, CX		// save CF
 
 	ADDQ $1, SI		// i++
 	SUBQ $1, DI		// n--
 	JG L2			// if n > 0 goto L2
 
-E2:	MOVQ CX, c+72(FP)	// return c
+E2:	NEGQ CX
+	MOVQ CX, c+72(FP)	// return c
 	RET
 
 
@@ -163,11 +162,11 @@ U3:	// n >= 0
 	MOVQ 16(R8)(SI*8), R13
 	MOVQ 24(R8)(SI*8), R14
 	ADDQ CX, R11
-	ZERO_CX
 	ADCQ $0, R12
 	ADCQ $0, R13
 	ADCQ $0, R14
-	SETCS CX		// c = CF
+	SBBQ CX, CX		// save CF
+	NEGQ CX
 	MOVQ R11, 0(R10)(SI*8)
 	MOVQ R12, 8(R10)(SI*8)
 	MOVQ R13, 16(R10)(SI*8)
@@ -183,8 +182,8 @@ V3:	ADDQ $4, DI		// n += 4
 L3:	// n > 0
 	ADDQ 0(R8)(SI*8), CX
 	MOVQ CX, 0(R10)(SI*8)
-	ZERO_CX
-	RCLQ $1, CX		// c = CF
+	SBBQ CX, CX		// save CF
+	NEGQ CX
 
 	ADDQ $1, SI		// i++
 	SUBQ $1, DI		// n--
@@ -201,7 +200,7 @@ TEXT ·subVW(SB),NOSPLIT,$0
 	MOVQ x+24(FP), R8
 	MOVQ y+48(FP), CX	// c = y
 	MOVQ z+0(FP), R10
-	
+
 	MOVQ $0, SI		// i = 0
 
 	// s/JL/JMP/ below to disable the unrolled loop
@@ -215,11 +214,11 @@ U4:	// n >= 0
 	MOVQ 16(R8)(SI*8), R13
 	MOVQ 24(R8)(SI*8), R14
 	SUBQ CX, R11
-	ZERO_CX
 	SBBQ $0, R12
 	SBBQ $0, R13
 	SBBQ $0, R14
-	SETCS CX		// c = CF
+	SBBQ CX, CX		// save CF
+	NEGQ CX
 	MOVQ R11, 0(R10)(SI*8)
 	MOVQ R12, 8(R10)(SI*8)
 	MOVQ R13, 16(R10)(SI*8)
@@ -236,8 +235,8 @@ L4:	// n > 0
 	MOVQ 0(R8)(SI*8), R11
 	SUBQ CX, R11
 	MOVQ R11, 0(R10)(SI*8)
-	ZERO_CX
-	RCLQ $1, CX		// c = CF
+	SBBQ CX, CX		// save CF
+	NEGQ CX
 
 	ADDQ $1, SI		// i++
 	SUBQ $1, DI		// n--
@@ -306,7 +305,7 @@ L9:	MOVQ AX, DX		// w = w1
 	SHRQ CX, DX:AX		// w>>s | w1<<ŝ
 	MOVQ DX, (R10)(BX*8)	// z[i] = w>>s | w1<<ŝ
 	ADDQ $1, BX		// i++
-	
+
 E9:	CMPQ BX, R11
 	JL L9			// i < n-1
 
@@ -352,6 +351,34 @@ TEXT ·addMulVVW(SB),NOSPLIT,$0
 	MOVQ z_len+8(FP), R11
 	MOVQ $0, BX		// i = 0
 	MOVQ $0, CX		// c = 0
+	MOVQ R11, R12
+	ANDQ $-2, R12
+	CMPQ R11, $2
+	JAE A6
+	JMP E6
+
+A6:
+	MOVQ (R8)(BX*8), AX
+	MULQ R9
+	ADDQ (R10)(BX*8), AX
+	ADCQ $0, DX
+	ADDQ CX, AX
+	ADCQ $0, DX
+	MOVQ DX, CX
+	MOVQ AX, (R10)(BX*8)
+
+	MOVQ (8)(R8)(BX*8), AX
+	MULQ R9
+	ADDQ (8)(R10)(BX*8), AX
+	ADCQ $0, DX
+	ADDQ CX, AX
+	ADCQ $0, DX
+	MOVQ DX, CX
+	MOVQ AX, (8)(R10)(BX*8)
+
+	ADDQ $2, BX
+	CMPQ BX, R12
+	JL A6
 	JMP E6
 
 L6:	MOVQ (R8)(BX*8), AX
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..24a717c
--- /dev/null
+++ b/src/math/big/arith_arm64.s
@@ -0,0 +1,177 @@
+// 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.
+
+// TODO: Consider re-implementing using Advanced SIMD
+// once the assembler supports those instructions.
+
+// func mulWW(x, y Word) (z1, z0 Word)
+TEXT ·mulWW(SB),NOSPLIT,$0
+	MOVD	x+0(FP), R0
+	MOVD	y+8(FP), R1
+	MUL	R0, R1, R2
+	UMULH	R0, R1, R3
+	MOVD	R3, z1+16(FP)
+	MOVD	R2, z0+24(FP)
+	RET
+
+
+// func divWW(x1, x0, y Word) (q, r Word)
+TEXT ·divWW(SB),NOSPLIT,$0
+	B	·divWW_g(SB) // ARM64 has no multiword division
+
+
+// func addVV(z, x, y []Word) (c Word)
+TEXT ·addVV(SB),NOSPLIT,$0
+	MOVD	z+0(FP), R3
+	MOVD	z_len+8(FP), R0
+	MOVD	x+24(FP), R1
+	MOVD	y+48(FP), R2
+	ADDS	$0, R0 // clear carry flag
+loop:
+	CBZ	R0, done // careful not to touch the carry flag
+	MOVD.P	8(R1), R4
+	MOVD.P	8(R2), R5
+	ADCS	R4, R5
+	MOVD.P	R5, 8(R3)
+	SUB	$1, R0
+	B	loop
+done:
+	CSET	HS, R0 // extract carry flag
+	MOVD	R0, c+72(FP)
+	RET
+
+
+// func subVV(z, x, y []Word) (c Word)
+TEXT ·subVV(SB),NOSPLIT,$0
+	MOVD	z+0(FP), R3
+	MOVD	z_len+8(FP), R0
+	MOVD	x+24(FP), R1
+	MOVD	y+48(FP), R2
+	CMP	R0, R0 // set carry flag
+loop:
+	CBZ	R0, done // careful not to touch the carry flag
+	MOVD.P	8(R1), R4
+	MOVD.P	8(R2), R5
+	SBCS	R5, R4
+	MOVD.P	R4, 8(R3)
+	SUB	$1, R0
+	B	loop
+done:
+	CSET	LO, R0 // extract carry flag
+	MOVD	R0, c+72(FP)
+	RET
+
+
+// func addVW(z, x []Word, y Word) (c Word)
+TEXT ·addVW(SB),NOSPLIT,$0
+	MOVD	z+0(FP), R3
+	MOVD	z_len+8(FP), R0
+	MOVD	x+24(FP), R1
+	MOVD	y+48(FP), R2
+	CBZ	R0, return_y
+	MOVD.P	8(R1), R4
+	ADDS	R2, R4
+	MOVD.P	R4, 8(R3)
+	SUB	$1, R0
+loop:
+	CBZ	R0, done // careful not to touch the carry flag
+	MOVD.P	8(R1), R4
+	ADCS	$0, R4
+	MOVD.P	R4, 8(R3)
+	SUB	$1, R0
+	B	loop
+done:
+	CSET	HS, R0 // extract carry flag
+	MOVD	R0, c+56(FP)
+	RET
+return_y: // z is empty; copy y to c
+	MOVD	R2, c+56(FP)
+	RET
+
+
+// func subVW(z, x []Word, y Word) (c Word)
+TEXT ·subVW(SB),NOSPLIT,$0
+	MOVD	z+0(FP), R3
+	MOVD	z_len+8(FP), R0
+	MOVD	x+24(FP), R1
+	MOVD	y+48(FP), R2
+	CBZ	R0, rety
+	MOVD.P	8(R1), R4
+	SUBS	R2, R4
+	MOVD.P	R4, 8(R3)
+	SUB	$1, R0
+loop:
+	CBZ	R0, done // careful not to touch the carry flag
+	MOVD.P	8(R1), R4
+	SBCS	$0, R4
+	MOVD.P	R4, 8(R3)
+	SUB	$1, R0
+	B	loop
+done:
+	CSET	LO, R0 // extract carry flag
+	MOVD	R0, c+56(FP)
+	RET
+rety: // z is empty; copy y to c
+	MOVD	R2, c+56(FP)
+	RET
+
+
+// func shlVU(z, x []Word, s uint) (c Word)
+TEXT ·shlVU(SB),NOSPLIT,$0
+	B ·shlVU_g(SB)
+
+
+// func shrVU(z, x []Word, s uint) (c Word)
+TEXT ·shrVU(SB),NOSPLIT,$0
+	B ·shrVU_g(SB)
+
+
+// func mulAddVWW(z, x []Word, y, r Word) (c Word)
+TEXT ·mulAddVWW(SB),NOSPLIT,$0
+	MOVD	z+0(FP), R1
+	MOVD	z_len+8(FP), R0
+	MOVD	x+24(FP), R2
+	MOVD	y+48(FP), R3
+	MOVD	r+56(FP), R4
+loop:
+	CBZ	R0, done
+	MOVD.P	8(R2), R5
+	UMULH	R5, R3, R7
+	MUL	R5, R3, R6
+	ADDS	R4, R6
+	ADC	$0, R7
+	MOVD.P	R6, 8(R1)
+	MOVD	R7, R4
+	SUB	$1, R0
+	B	loop
+done:
+	MOVD	R4, c+64(FP)
+	RET
+
+
+// func addMulVVW(z, x []Word, y Word) (c Word)
+TEXT ·addMulVVW(SB),NOSPLIT,$0
+	B ·addMulVVW_g(SB)
+
+
+// func divWVW(z []Word, xn Word, x []Word, y Word) (r Word)
+TEXT ·divWVW(SB),NOSPLIT,$0
+	B ·divWVW_g(SB)
+
+
+// func bitLen(x Word) (n int)
+TEXT ·bitLen(SB),NOSPLIT,$0
+	MOVD	x+0(FP), R0
+	CLZ	R0, R0
+	MOVD	$64, R1
+	SUB	R0, R1, R0
+	MOVD	R0, n+8(FP)
+	RET
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
new file mode 100644
index 0000000..d4d4171
--- /dev/null
+++ b/src/math/big/arith_ppc64x.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,ppc64 !math_big_pure_go,ppc64le
+
+#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
+	BR ·mulWW_g(SB)
+
+TEXT ·divWW(SB),NOSPLIT,$0
+	BR ·divWW_g(SB)
+
+TEXT ·addVV(SB),NOSPLIT,$0
+	BR ·addVV_g(SB)
+
+TEXT ·subVV(SB),NOSPLIT,$0
+	BR ·subVV_g(SB)
+
+TEXT ·addVW(SB),NOSPLIT,$0
+	BR ·addVW_g(SB)
+
+TEXT ·subVW(SB),NOSPLIT,$0
+	BR ·subVW_g(SB)
+
+TEXT ·shlVU(SB),NOSPLIT,$0
+	BR ·shlVU_g(SB)
+
+TEXT ·shrVU(SB),NOSPLIT,$0
+	BR ·shrVU_g(SB)
+
+TEXT ·mulAddVWW(SB),NOSPLIT,$0
+	BR ·mulAddVWW_g(SB)
+
+TEXT ·addMulVVW(SB),NOSPLIT,$0
+	BR ·addMulVVW_g(SB)
+
+TEXT ·divWVW(SB),NOSPLIT,$0
+	BR ·divWVW_g(SB)
+
+TEXT ·bitLen(SB),NOSPLIT,$0
+	BR ·bitLen_g(SB)
diff --git a/src/math/big/arith_test.go b/src/math/big/arith_test.go
index 3615a65..f46a494 100644
--- a/src/math/big/arith_test.go
+++ b/src/math/big/arith_test.go
@@ -155,6 +155,7 @@ var sumVW = []argVW{
 	{nat{1}, nat{1}, 0, 0},
 	{nat{0}, nat{_M}, 1, 1},
 	{nat{0, 0, 0, 0}, nat{_M, _M, _M, _M}, 1, 1},
+	{nat{585}, nat{314}, 271, 0},
 }
 
 var prodVW = []argVW{
@@ -254,7 +255,7 @@ func benchmarkFunVW(b *testing.B, f funVW, n int) {
 	x := rndV(n)
 	y := rndW()
 	z := make([]Word, n)
-	b.SetBytes(int64(n * _W))
+	b.SetBytes(int64(n * _S))
 	b.ResetTimer()
 	for i := 0; i < b.N; i++ {
 		f(z, x, y)
diff --git a/src/math/big/bits_test.go b/src/math/big/bits_test.go
new file mode 100644
index 0000000..985b60b
--- /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.8p+1"},
+		{Bits{1}, "0x.8p+2"},
+		{Bits{-1}, "0x.8p+0"},
+		{Bits{63}, "0x.8p+64"},
+		{Bits{33, -30}, "0x.8000000000000001p+34"},
+		{Bits{255, 0}, "0x.8000000000000000000000000000000000000000000000000000000000000001p+256"},
+
+		// multiple equal bit numbers
+		{Bits{0, 0}, "0x.8p+2"},
+		{Bits{0, 0, 0, 0}, "0x.8p+3"},
+		{Bits{0, 1, 0}, "0x.8p+3"},
+		{append(Bits{2, 1, 0} /* 7 */, Bits{3, 1} /* 10 */ ...), "0x.88p+5" /* 17 */},
+	} {
+		f := test.bits.Float()
+		if got := f.Text('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
new file mode 100644
index 0000000..2595e5f
--- /dev/null
+++ b/src/math/big/decimal.go
@@ -0,0 +1,264 @@
+// 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 multi-precision decimal numbers.
+// The implementation is for float to decimal conversion only;
+// not general purpose use.
+// The only operations are precise conversion from binary to
+// decimal and rounding.
+//
+// The key observation and some code (shr) is borrowed from
+// strconv/decimal.go: conversion of binary fractional values can be done
+// precisely in multi-precision decimal because 2 divides 10 (required for
+// >> of mantissa); but conversion of decimal floating-point values cannot
+// be done precisely in binary representation.
+//
+// In contrast to strconv/decimal.go, only right shift is implemented in
+// decimal format - left shift can be done precisely in binary format.
+
+package big
+
+// A decimal represents an unsigned floating-point number in decimal representation.
+// The value of a non-zero decimal x is x.mant * 10 ** x.exp with 0.5 <= x.mant < 1,
+// with the most-significant mantissa digit at index 0. For the zero decimal, the
+// mantissa length and exponent are 0.
+// The zero value for decimal represents a ready-to-use 0.0.
+type decimal struct {
+	mant []byte // mantissa ASCII digits, big-endian
+	exp  int    // exponent
+}
+
+// Maximum shift amount that can be done in one pass without overflow.
+// A Word has _W bits and (1<<maxShift - 1)*10 + 9 must fit into Word.
+const maxShift = _W - 4
+
+// TODO(gri) Since we know the desired decimal precision when converting
+// a floating-point number, we may be able to limit the number of decimal
+// digits that need to be computed by init by providing an additional
+// 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) {
+	// special case 0
+	if len(m) == 0 {
+		x.mant = x.mant[:0]
+		x.exp = 0
+		return
+	}
+
+	// Optimization: If we need to shift right, first remove any trailing
+	// zero bits from m to reduce shift amount that needs to be done in
+	// decimal format (since that is likely slower).
+	if shift < 0 {
+		ntz := m.trailingZeroBits()
+		s := uint(-shift)
+		if s >= ntz {
+			s = ntz // shift at most ntz bits
+		}
+		m = nat(nil).shr(m, s)
+		shift += int(s)
+	}
+
+	// Do any shift left in binary representation.
+	if shift > 0 {
+		m = nat(nil).shl(m, uint(shift))
+		shift = 0
+	}
+
+	// Convert mantissa into decimal representation.
+	s := m.decimalString() // TODO(gri) avoid string conversion here
+	n := len(s)
+	x.exp = n
+	// Trim trailing zeros; instead the exponent is tracking
+	// the decimal point independent of the number of digits.
+	for n > 0 && s[n-1] == '0' {
+		n--
+	}
+	x.mant = append(x.mant[:0], s[:n]...)
+
+	// Do any (remaining) shift right in decimal representation.
+	if shift < 0 {
+		for shift < -maxShift {
+			shr(x, maxShift)
+			shift += maxShift
+		}
+		shr(x, uint(-shift))
+	}
+}
+
+// Possibly optimization: The current implementation of nat.string takes
+// a charset argument. When a right shift is needed, we could provide
+// "\x00\x01...\x09" instead of "012..9" (as in nat.decimalString) and
+// avoid the repeated +'0' and -'0' operations in decimal.shr (and do a
+// single +'0' pass at the end).
+
+// shr implements x >> s, for s <= maxShift.
+func shr(x *decimal, s uint) {
+	// Division by 1<<s using shift-and-subtract algorithm.
+
+	// pick up enough leading digits to cover first shift
+	r := 0 // read index
+	var n Word
+	for n>>s == 0 && r < len(x.mant) {
+		ch := Word(x.mant[r])
+		r++
+		n = n*10 + ch - '0'
+	}
+	if n == 0 {
+		// x == 0; shouldn't get here, but handle anyway
+		x.mant = x.mant[:0]
+		return
+	}
+	for n>>s == 0 {
+		r++
+		n *= 10
+	}
+	x.exp += 1 - r
+
+	// read a digit, write a digit
+	w := 0 // write index
+	for r < len(x.mant) {
+		ch := Word(x.mant[r])
+		r++
+		d := n >> s
+		n -= d << s
+		x.mant[w] = byte(d + '0')
+		w++
+		n = n*10 + ch - '0'
+	}
+
+	// write extra digits that still fit
+	for n > 0 && w < len(x.mant) {
+		d := n >> s
+		n -= d << s
+		x.mant[w] = byte(d + '0')
+		w++
+		n = n * 10
+	}
+	x.mant = x.mant[:w] // the number may be shorter (e.g. 1024 >> 10)
+
+	// append additional digits that didn't fit
+	for n > 0 {
+		d := n >> s
+		n -= d << s
+		x.mant = append(x.mant, byte(d+'0'))
+		n = n * 10
+	}
+
+	trim(x)
+}
+
+func (x *decimal) String() string {
+	if len(x.mant) == 0 {
+		return "0"
+	}
+
+	var buf []byte
+	switch {
+	case x.exp <= 0:
+		// 0.00ddd
+		buf = append(buf, "0."...)
+		buf = appendZeros(buf, -x.exp)
+		buf = append(buf, x.mant...)
+
+	case /* 0 < */ x.exp < len(x.mant):
+		// dd.ddd
+		buf = append(buf, x.mant[:x.exp]...)
+		buf = append(buf, '.')
+		buf = append(buf, x.mant[x.exp:]...)
+
+	default: // len(x.mant) <= x.exp
+		// ddd00
+		buf = append(buf, x.mant...)
+		buf = appendZeros(buf, x.exp-len(x.mant))
+	}
+
+	return string(buf)
+}
+
+// appendZeros appends n 0 digits to buf and returns buf.
+func appendZeros(buf []byte, n int) []byte {
+	for ; n > 0; n-- {
+		buf = append(buf, '0')
+	}
+	return buf
+}
+
+// shouldRoundUp reports if x should be rounded up
+// if shortened to n digits. n must be a valid index
+// for x.mant.
+func shouldRoundUp(x *decimal, n int) bool {
+	if x.mant[n] == '5' && n+1 == len(x.mant) {
+		// exactly halfway - round to even
+		return n > 0 && (x.mant[n-1]-'0')&1 != 0
+	}
+	// not halfway - digit tells all (x.mant has no trailing zeros)
+	return x.mant[n] >= '5'
+}
+
+// round sets x to (at most) n mantissa digits by rounding it
+// to the nearest even value with n (or fever) mantissa digits.
+// If n < 0, x remains unchanged.
+func (x *decimal) round(n int) {
+	if n < 0 || n >= len(x.mant) {
+		return // nothing to do
+	}
+
+	if shouldRoundUp(x, n) {
+		x.roundUp(n)
+	} else {
+		x.roundDown(n)
+	}
+}
+
+func (x *decimal) roundUp(n int) {
+	if n < 0 || n >= len(x.mant) {
+		return // nothing to do
+	}
+	// 0 <= n < len(x.mant)
+
+	// find first digit < '9'
+	for n > 0 && x.mant[n-1] >= '9' {
+		n--
+	}
+
+	if n == 0 {
+		// all digits are '9's => round up to '1' and update exponent
+		x.mant[0] = '1' // ok since len(x.mant) > n
+		x.mant = x.mant[:1]
+		x.exp++
+		return
+	}
+
+	// n > 0 && x.mant[n-1] < '9'
+	x.mant[n-1]++
+	x.mant = x.mant[:n]
+	// x already trimmed
+}
+
+func (x *decimal) roundDown(n int) {
+	if n < 0 || n >= len(x.mant) {
+		return // nothing to do
+	}
+	x.mant = x.mant[:n]
+	trim(x)
+}
+
+// trim cuts off any trailing zeros from x's mantissa;
+// they are meaningless for the value of x.
+func trim(x *decimal) {
+	i := len(x.mant)
+	for i > 0 && x.mant[i-1] == '0' {
+		i--
+	}
+	x.mant = x.mant[:i]
+	if i == 0 {
+		x.exp = 0
+	}
+}
diff --git a/src/math/big/decimal_test.go b/src/math/big/decimal_test.go
new file mode 100644
index 0000000..81e022a
--- /dev/null
+++ b/src/math/big/decimal_test.go
@@ -0,0 +1,106 @@
+// 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
+
+import "testing"
+
+func TestDecimalString(t *testing.T) {
+	for _, test := range []struct {
+		x    decimal
+		want string
+	}{
+		{want: "0"},
+		{decimal{nil, 1000}, "0"}, // exponent of 0 is ignored
+		{decimal{[]byte("12345"), 0}, "0.12345"},
+		{decimal{[]byte("12345"), -3}, "0.00012345"},
+		{decimal{[]byte("12345"), +3}, "123.45"},
+		{decimal{[]byte("12345"), +10}, "1234500000"},
+	} {
+		if got := test.x.String(); got != test.want {
+			t.Errorf("%v == %s; want %s", test.x, got, test.want)
+		}
+	}
+}
+
+func TestDecimalInit(t *testing.T) {
+	for _, test := range []struct {
+		x     Word
+		shift int
+		want  string
+	}{
+		{0, 0, "0"},
+		{0, -100, "0"},
+		{0, 100, "0"},
+		{1, 0, "1"},
+		{1, 10, "1024"},
+		{1, 100, "1267650600228229401496703205376"},
+		{1, -100, "0.0000000000000000000000000000007888609052210118054117285652827862296732064351090230047702789306640625"},
+		{12345678, 8, "3160493568"},
+		{12345678, -8, "48225.3046875"},
+		{195312, 9, "99999744"},
+		{1953125, 9, "1000000000"},
+	} {
+		var d decimal
+		d.init(nat{test.x}.norm(), test.shift)
+		if got := d.String(); got != test.want {
+			t.Errorf("%d << %d == %s; want %s", test.x, test.shift, got, test.want)
+		}
+	}
+}
+
+func TestDecimalRounding(t *testing.T) {
+	for _, test := range []struct {
+		x              uint64
+		n              int
+		down, even, up string
+	}{
+		{0, 0, "0", "0", "0"},
+		{0, 1, "0", "0", "0"},
+
+		{1, 0, "0", "0", "10"},
+		{5, 0, "0", "0", "10"},
+		{9, 0, "0", "10", "10"},
+
+		{15, 1, "10", "20", "20"},
+		{45, 1, "40", "40", "50"},
+		{95, 1, "90", "100", "100"},
+
+		{12344999, 4, "12340000", "12340000", "12350000"},
+		{12345000, 4, "12340000", "12340000", "12350000"},
+		{12345001, 4, "12340000", "12350000", "12350000"},
+		{23454999, 4, "23450000", "23450000", "23460000"},
+		{23455000, 4, "23450000", "23460000", "23460000"},
+		{23455001, 4, "23450000", "23460000", "23460000"},
+
+		{99994999, 4, "99990000", "99990000", "100000000"},
+		{99995000, 4, "99990000", "100000000", "100000000"},
+		{99999999, 4, "99990000", "100000000", "100000000"},
+
+		{12994999, 4, "12990000", "12990000", "13000000"},
+		{12995000, 4, "12990000", "13000000", "13000000"},
+		{12999999, 4, "12990000", "13000000", "13000000"},
+	} {
+		x := nat(nil).setUint64(test.x)
+
+		var d decimal
+		d.init(x, 0)
+		d.roundDown(test.n)
+		if got := d.String(); got != test.down {
+			t.Errorf("roundDown(%d, %d) = %s; want %s", test.x, test.n, got, test.down)
+		}
+
+		d.init(x, 0)
+		d.round(test.n)
+		if got := d.String(); got != test.even {
+			t.Errorf("round(%d, %d) = %s; want %s", test.x, test.n, got, test.even)
+		}
+
+		d.init(x, 0)
+		d.roundUp(test.n)
+		if got := d.String(); got != test.up {
+			t.Errorf("roundUp(%d, %d) = %s; want %s", test.x, test.n, got, test.up)
+		}
+	}
+}
diff --git a/src/math/big/example_test.go b/src/math/big/example_test.go
index 078be47..ac79552 100644
--- a/src/math/big/example_test.go
+++ b/src/math/big/example_test.go
@@ -7,6 +7,7 @@ package big_test
 import (
 	"fmt"
 	"log"
+	"math"
 	"math/big"
 )
 
@@ -49,3 +50,79 @@ func ExampleInt_Scan() {
 	}
 	// Output: 18446744073709551617
 }
+
+// This example demonstrates how to use big.Int to compute the smallest
+// Fibonacci number with 100 decimal digits and to test whether it is prime.
+func Example_fibonacci() {
+	// Initialize two big ints with the first two numbers in the sequence.
+	a := big.NewInt(0)
+	b := big.NewInt(1)
+
+	// Initialize limit as 10^99, the smallest integer with 100 digits.
+	var limit big.Int
+	limit.Exp(big.NewInt(10), big.NewInt(99), nil)
+
+	// Loop while a is smaller than 1e100.
+	for a.Cmp(&limit) < 0 {
+		// Compute the next Fibonacci number, storing it in a.
+		a.Add(a, b)
+		// Swap a and b so that b is the next number in the sequence.
+		a, b = b, a
+	}
+	fmt.Println(a) // 100-digit Fibonacci number
+
+	// Test a for primality.
+	// (ProbablyPrimes' argument sets the number of Miller-Rabin
+	// rounds to be performed. 20 is a good value.)
+	fmt.Println(a.ProbablyPrime(20))
+
+	// Output:
+	// 1344719667586153181419716641724567886890850696275767987106294472017884974410332069524504824747437757
+	// false
+}
+
+// This example shows how to use big.Float to compute the square root of 2 with
+// a precision of 200 bits, and how to print the result as a decimal number.
+func Example_sqrt2() {
+	// We'll do computations with 200 bits of precision in the mantissa.
+	const prec = 200
+
+	// Compute the square root of 2 using Newton's Method. We start with
+	// an initial estimate for sqrt(2), and then iterate:
+	//     x_{n+1} = 1/2 * ( x_n + (2.0 / x_n) )
+
+	// Since Newton's Method doubles the number of correct digits at each
+	// iteration, we need at least log_2(prec) steps.
+	steps := int(math.Log2(prec))
+
+	// Initialize values we need for the computation.
+	two := new(big.Float).SetPrec(prec).SetInt64(2)
+	half := new(big.Float).SetPrec(prec).SetFloat64(0.5)
+
+	// Use 1 as the initial estimate.
+	x := new(big.Float).SetPrec(prec).SetInt64(1)
+
+	// We use t as a temporary variable. There's no need to set its precision
+	// since big.Float values with unset (== 0) precision automatically assume
+	// the largest precision of the arguments when used as the result (receiver)
+	// of a big.Float operation.
+	t := new(big.Float)
+
+	// Iterate.
+	for i := 0; i <= steps; i++ {
+		t.Quo(two, x)  // t = 2.0 / x_n
+		t.Add(x, t)    // t = x_n + (2.0 / x_n)
+		x.Mul(half, t) // x_{n+1} = 0.5 * t
+	}
+
+	// We can use the usual fmt.Printf verbs since big.Float implements fmt.Formatter
+	fmt.Printf("sqrt(2) = %.50f\n", x)
+
+	// Print the error between 2 and x*x.
+	t.Mul(x, x) // t = x*x
+	fmt.Printf("error = %e\n", t.Sub(two, t))
+
+	// Output:
+	// sqrt(2) = 1.41421356237309504880168872420969807856967187537695
+	// error = 0.000000e+00
+}
diff --git a/src/math/big/float.go b/src/math/big/float.go
new file mode 100644
index 0000000..d7aa895
--- /dev/null
+++ b/src/math/big/float.go
@@ -0,0 +1,1693 @@
+// 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.
+
+// This file implements multi-precision floating-point numbers.
+// Like in the GNU MPFR library (http://www.mpfr.org/), operands
+// can be of mixed precision. Unlike MPFR, the rounding mode is
+// not specified with each operation, but with each operand. The
+// rounding mode of the result operand determines the rounding
+// mode of an operation. This is a from-scratch implementation.
+
+package big
+
+import (
+	"fmt"
+	"math"
+)
+
+const debugFloat = false // enable for debugging
+
+// 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.
+// 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.
+//
+// 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 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 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
+}
+
+// An ErrNaN panic is raised by a Float operation that would lead to
+// a NaN under IEEE-754 rules. An ErrNaN implements the error interface.
+type ErrNaN struct {
+	msg string
+}
+
+func (err ErrNaN) Error() string {
+	return err.msg
+}
+
+// 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
+	MinExp  = math.MinInt32  // smallest supported exponent
+	MaxPrec = math.MaxUint32 // largest (theoretically) supported precision; likely memory-limited
+)
+
+// 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.
+//
+// A zero or non-finite Float x ignores x.mant and x.exp.
+//
+// x                 form      neg      mant         exp
+// ----------------------------------------------------------
+// ±0                zero      sign     -            -
+// 0 < |x| < +Inf    finite    sign     mantissa     exponent
+// ±Inf              inf       sign     -            -
+
+// A form value describes the internal representation.
+type form byte
+
+// The form value order is relevant - do not change!
+const (
+	zero form = iota
+	finite
+	inf
+)
+
+// 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 byte
+
+// The following rounding modes are supported.
+const (
+	ToNearestEven RoundingMode = iota // == IEEE 754-2008 roundTiesToEven
+	ToNearestAway                     // == IEEE 754-2008 roundTiesToAway
+	ToZero                            // == IEEE 754-2008 roundTowardZero
+	AwayFromZero                      // no IEEE 754-2008 equivalent
+	ToNegativeInf                     // == IEEE 754-2008 roundTowardNegative
+	ToPositiveInf                     // == IEEE 754-2008 roundTowardPositive
+)
+
+//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.
+// 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
+
+	// special case
+	if prec == 0 {
+		z.prec = 0
+		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
+	}
+	old := z.prec
+	z.prec = uint32(prec)
+	if z.prec < old {
+		z.round(0)
+	}
+	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.mode = mode
+	z.acc = Exact
+	return z
+}
+
+// Prec returns the mantissa precision of x in bits.
+// 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 |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()
+}
+
+// Mode returns the rounding mode of x.
+func (x *Float) Mode() RoundingMode {
+	return x.mode
+}
+
+// Acc returns the accuracy of x produced by the most recent operation.
+func (x *Float) Acc() Accuracy {
+	return x.acc
+}
+
+// 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(mant) = 0, with mant set to   ±0
+//	(±Inf).MantExp(mant) = 0, with mant set to ±Inf
+//
+// 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()
+	}
+	if x.form == finite {
+		exp = int(x.exp)
+	}
+	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:
+//
+//	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 z.form != finite {
+		return z
+	}
+	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 values are not integers.
+func (x *Float) IsInt() bool {
+	if debugFloat {
+		x.validate()
+	}
+	// special cases
+	if x.form != finite {
+		return x.form == zero
+	}
+	// x.form == finite
+	if x.exp <= 0 {
+		return false
+	}
+	// x.exp > 0
+	return x.prec <= uint32(x.exp) || x.MinPrec() <= uint(x.exp) // not enough bits for fractional mantissa
+}
+
+// debugging support
+func (x *Float) validate() {
+	if !debugFloat {
+		// avoid performance bugs
+		panic("validate called but debugFloat is not set")
+	}
+	if x.form != finite {
+		return
+	}
+	m := len(x.mant)
+	if m == 0 {
+		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.Text('p', 0)))
+	}
+	if x.prec == 0 {
+		panic("zero precision finite number")
+	}
+}
+
+// round rounds z according to z.mode to z.prec bits and sets z.acc accordingly.
+// sbit must be 0 or 1 and summarizes any "sticky bit" information one might
+// have before calling round. z's mantissa must be normalized (with the msb set)
+// or empty.
+//
+// CAUTION: The rounding modes ToNegativeInf, ToPositiveInf are affected by the
+// sign of z. For correct rounding, the sign of z must be set correctly before
+// calling round.
+func (z *Float) round(sbit uint) {
+	if debugFloat {
+		z.validate()
+	}
+
+	z.acc = Exact
+	if z.form != finite {
+		// ±0 or ±Inf => nothing left to do
+		return
+	}
+	// z.form == finite && len(z.mant) > 0
+	// m > 0 implies z.prec > 0 (checked by validate)
+
+	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
+	}
+	// bits > z.prec
+
+	n := (z.prec + (_W - 1)) / _W // mantissa length in words for desired precision
+
+	// Rounding is based on two bits: the rounding bit (rbit) and the
+	// sticky bit (sbit). The rbit is the bit immediately before the
+	// z.prec leading mantissa bits (the "0.5"). The sbit is set if any
+	// of the bits before the rbit are set (the "0.25", "0.125", etc.):
+	//
+	//   rbit  sbit  => "fractional part"
+	//
+	//   0     0        == 0
+	//   0     1        >  0  , < 0.5
+	//   1     0        == 0.5
+	//   1     1        >  0.5, < 1.0
+
+	// bits > z.prec: mantissa too large => round
+	r := uint(bits - z.prec - 1) // rounding bit position; r >= 0
+	rbit := z.mant.bit(r)        // rounding bit
+	if sbit == 0 {
+		sbit = z.mant.sticky(r)
+	}
+	if debugFloat && sbit&^1 != 0 {
+		panic(fmt.Sprintf("invalid sbit %#x", sbit))
+	}
+
+	// convert ToXInf rounding modes
+	mode := z.mode
+	switch mode {
+	case ToNegativeInf:
+		mode = ToZero
+		if z.neg {
+			mode = AwayFromZero
+		}
+	case ToPositiveInf:
+		mode = AwayFromZero
+		if z.neg {
+			mode = ToZero
+		}
+	}
+
+	// cut off extra words
+	if m > n {
+		copy(z.mant, z.mant[m-n:]) // move n last words to front
+		z.mant = z.mant[:n]
+	}
+
+	// determine number of trailing zero bits t
+	t := n*_W - z.prec // 0 <= t < _W
+	lsb := Word(1) << t
+
+	// make rounding decision
+	// TODO(gri) This can be simplified (see Bits.round in bits_test.go).
+	switch mode {
+	case ToZero:
+		// nothing to do
+	case ToNearestEven, ToNearestAway:
+		if rbit == 0 {
+			// rounding bits == 0b0x
+			mode = ToZero
+		} else if sbit == 1 {
+			// rounding bits == 0b11
+			mode = AwayFromZero
+		}
+	case AwayFromZero:
+		if rbit|sbit == 0 {
+			mode = ToZero
+		}
+	default:
+		// ToXInf modes have been converted to ToZero or AwayFromZero
+		panic("unreachable")
+	}
+
+	// round and determine accuracy
+	switch mode {
+	case ToZero:
+		if rbit|sbit != 0 {
+			z.acc = Below
+		}
+
+	case ToNearestEven, ToNearestAway:
+		if debugFloat && rbit != 1 {
+			panic("internal error in rounding")
+		}
+		if mode == ToNearestEven && sbit == 0 && z.mant[0]&lsb == 0 {
+			z.acc = Below
+			break
+		}
+		// mode == ToNearestAway || sbit == 1 || z.mant[0]&lsb != 0
+		fallthrough
+
+	case AwayFromZero:
+		// add 1 to mantissa
+		if addVW(z.mant, z.mant, lsb) != 0 {
+			// overflow => shift mantissa right by 1 and add msb
+			shrVU(z.mant, z.mant, 1)
+			z.mant[n-1] |= 1 << (_W - 1)
+			// adjust exponent
+			if z.exp < MaxExp {
+				z.exp++
+			} else {
+				// exponent overflow
+				z.acc = makeAcc(!z.neg)
+				z.form = inf
+				return
+			}
+		}
+		z.acc = Above
+	}
+
+	// zero out trailing bits in least-significant word
+	z.mant[0] &^= lsb - 1
+
+	// update accuracy
+	if z.acc != Exact && z.neg {
+		z.acc = -z.acc
+	}
+
+	if debugFloat {
+		z.validate()
+	}
+
+	return
+}
+
+func (z *Float) setBits64(neg bool, x uint64) *Float {
+	if z.prec == 0 {
+		z.prec = 64
+	}
+	z.acc = Exact
+	z.neg = neg
+	if x == 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
+	if z.prec < 64 {
+		z.round(0)
+	}
+	return z
+}
+
+// SetUint64 sets z to the (possibly rounded) value of x and returns z.
+// If z's precision is 0, it is changed to 64 (and rounding will have
+// no effect).
+func (z *Float) SetUint64(x uint64) *Float {
+	return z.setBits64(false, x)
+}
+
+// SetInt64 sets z to the (possibly rounded) value of x and returns z.
+// If z's precision is 0, it is changed to 64 (and rounding will have
+// no effect).
+func (z *Float) SetInt64(x int64) *Float {
+	u := x
+	if u < 0 {
+		u = -u
+	}
+	// We cannot simply call z.SetUint64(uint64(u)) and change
+	// the sign afterwards because the sign affects rounding.
+	return z.setBits64(x < 0, uint64(u))
+}
+
+// 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). 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, -Inf correctly
+	if x == 0 {
+		z.form = zero
+		return z
+	}
+	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
+	if z.prec < 53 {
+		z.round(0)
+	}
+	return z
+}
+
+// fnorm normalizes mantissa m by shifting it to the left
+// such that the msb of the most-significant word (msw) is 1.
+// It returns the shift amount. It assumes that len(m) != 0.
+func fnorm(m nat) int64 {
+	if debugFloat && (len(m) == 0 || m[len(m)-1] == 0) {
+		panic("msw of mantissa is 0")
+	}
+	s := nlz(m[len(m)-1])
+	if s > 0 {
+		c := shlVU(m, m, s)
+		if debugFloat && c != 0 {
+			panic("nlz or shlVU incorrect")
+		}
+	}
+	return int64(s)
+}
+
+// SetInt sets z to the (possibly rounded) value of x and returns z.
+// If z's precision is 0, it is changed to the larger of x.BitLen()
+// or 64 (and rounding will have no effect).
+func (z *Float) SetInt(x *Int) *Float {
+	// TODO(gri) can be more efficient if z.prec > 0
+	// but small compared to the size of x, or if there
+	// are many trailing 0's.
+	bits := uint32(x.BitLen())
+	if z.prec == 0 {
+		z.prec = umax32(bits, 64)
+	}
+	z.acc = Exact
+	z.neg = x.neg
+	if len(x.abs) == 0 {
+		z.form = zero
+		return z
+	}
+	// x != 0
+	z.mant = z.mant.set(x.abs)
+	fnorm(z.mant)
+	z.setExpAndRound(int64(bits), 0)
+	return z
+}
+
+// SetRat sets z to the (possibly rounded) value of x and returns z.
+// If z's precision is 0, it is changed to the largest of a.BitLen(),
+// b.BitLen(), or 64; with x = a/b.
+func (z *Float) SetRat(x *Rat) *Float {
+	if x.IsInt() {
+		return z.SetInt(x.Num())
+	}
+	var a, b Float
+	a.SetInt(x.Num())
+	b.SetInt(x.Denom())
+	if z.prec == 0 {
+		z.prec = umax32(a.prec, b.prec)
+	}
+	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).
+// 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.
+func (z *Float) Set(x *Float) *Float {
+	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
+		} else if z.prec < x.prec {
+			z.round(0)
+		}
+	}
+	return 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 {
+	if debugFloat {
+		x.validate()
+	}
+	if z != x {
+		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
+}
+
+// msb32 returns the 32 most significant bits of x.
+func msb32(x nat) uint32 {
+	i := len(x) - 1
+	if i < 0 {
+		return 0
+	}
+	if debugFloat && x[i]&(1<<(_W-1)) == 0 {
+		panic("x not normalized")
+	}
+	switch _W {
+	case 32:
+		return uint32(x[i])
+	case 64:
+		return uint32(x[i] >> 32)
+	}
+	panic("unreachable")
+}
+
+// msb64 returns the 64 most significant bits of x.
+func msb64(x nat) uint64 {
+	i := len(x) - 1
+	if i < 0 {
+		return 0
+	}
+	if debugFloat && x[i]&(1<<(_W-1)) == 0 {
+		panic("x not normalized")
+	}
+	switch _W {
+	case 32:
+		v := uint64(x[i]) << 32
+		if i > 0 {
+			v |= uint64(x[i-1])
+		}
+		return v
+	case 64:
+		return uint64(x[i])
+	}
+	panic("unreachable")
+}
+
+// Uint64 returns the unsigned integer resulting from truncating x
+// towards zero. If 0 <= x <= math.MaxUint64, the result is Exact
+// if x is an integer and Below otherwise.
+// The result is (0, Above) for x < 0, and (math.MaxUint64, Below)
+// for x > math.MaxUint64.
+func (x *Float) Uint64() (uint64, Accuracy) {
+	if debugFloat {
+		x.validate()
+	}
+
+	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
+		if x.exp <= 64 {
+			// u = trunc(x) fits into a uint64
+			u := msb64(x.mant) >> (64 - uint32(x.exp))
+			if x.MinPrec() <= 64 {
+				return u, Exact
+			}
+			return u, Below // x truncated
+		}
+		// 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.
+func (x *Float) Int64() (int64, Accuracy) {
+	if debugFloat {
+		x.validate()
+	}
+
+	switch x.form {
+	case finite:
+		// 0 < |x| < +Inf
+		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)
+			i := int64(msb64(x.mant) >> (64 - uint32(x.exp)))
+			if x.neg {
+				i = -i
+			}
+			if x.MinPrec() <= uint(x.exp) {
+				return i, Exact
+			}
+			return i, acc // x truncated
+		}
+		if x.neg {
+			// check for special case x == math.MinInt64 (i.e., x == -(0.5 << 64))
+			if x.exp == 64 && x.MinPrec() == 1 {
+				acc = Exact
+			}
+			return math.MinInt64, acc
+		}
+		// 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")
+}
+
+// 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 mantissa m is 0.5 <= m < 1.0; compute exponent for floatxx mantissa.
+		e := x.exp - 1 // exponent for mantissa m with 1.0 <= m < 2.0
+		p := mbits + 1 // precision of normal float
+
+		// If the exponent is too small, we may have a denormal number
+		// in which case we have fewer mantissa bits available: reduce
+		// precision accordingly.
+		if e < emin {
+			p -= emin - int(e)
+			// Make sure we have at least 1 bit so that we don't
+			// lose numbers rounded up to the smallest denormal.
+			if p < 1 {
+				p = 1
+			}
+		}
+
+		// round
+		var r Float
+		r.prec = uint32(p)
+		r.Set(x)
+		e = r.exp - 1
+
+		// Rounding may have caused r to overflow to ±Inf
+		// (rounding never causes underflows to 0).
+		if r.form == inf {
+			e = emax + 1 // cause overflow below
+		}
+
+		// If the exponent is too large, overflow to ±Inf.
+		if e > emax {
+			// overflow
+			if x.neg {
+				return float32(math.Inf(-1)), Below
+			}
+			return float32(math.Inf(+1)), Above
+		}
+		// e <= emax
+
+		// Determine sign, biased exponent, and mantissa.
+		var sign, bexp, mant uint32
+		if x.neg {
+			sign = 1 << (fbits - 1)
+		}
+
+		// Rounding may have caused a denormal number to
+		// become normal. Check again.
+		if e < emin {
+			// denormal number
+			if e < dmin {
+				// underflow to ±0
+				if x.neg {
+					var z float32
+					return -z, Above
+				}
+				return 0.0, Below
+			}
+			// bexp = 0
+			mant = msb32(r.mant) >> (fbits - r.prec)
+		} else {
+			// normal number: emin <= e <= emax
+			bexp = uint32(e+bias) << mbits
+			mant = msb32(r.mant) >> ebits & (1<<mbits - 1) // cut off msb (implicit 1 bit)
+		}
+
+		return math.Float32frombits(sign | bexp | mant), 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
+	}
+
+	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()
+	}
+
+	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 mantissa m is 0.5 <= m < 1.0; compute exponent for floatxx mantissa.
+		e := x.exp - 1 // exponent for mantissa m with 1.0 <= m < 2.0
+		p := mbits + 1 // precision of normal float
+
+		// If the exponent is too small, we may have a denormal number
+		// in which case we have fewer mantissa bits available: reduce
+		// precision accordingly.
+		if e < emin {
+			p -= emin - int(e)
+			// Make sure we have at least 1 bit so that we don't
+			// lose numbers rounded up to the smallest denormal.
+			if p < 1 {
+				p = 1
+			}
+		}
+
+		// round
+		var r Float
+		r.prec = uint32(p)
+		r.Set(x)
+		e = r.exp - 1
+
+		// Rounding may have caused r to overflow to ±Inf
+		// (rounding never causes underflows to 0).
+		if r.form == inf {
+			e = emax + 1 // cause overflow below
+		}
+
+		// If the exponent is too large, overflow to ±Inf.
+		if e > emax {
+			// overflow
+			if x.neg {
+				return math.Inf(-1), Below
+			}
+			return math.Inf(+1), Above
+		}
+		// e <= emax
+
+		// Determine sign, biased exponent, and mantissa.
+		var sign, bexp, mant uint64
+		if x.neg {
+			sign = 1 << (fbits - 1)
+		}
+
+		// Rounding may have caused a denormal number to
+		// become normal. Check again.
+		if e < emin {
+			// denormal number
+			if e < dmin {
+				// underflow to ±0
+				if x.neg {
+					var z float64
+					return -z, Above
+				}
+				return 0.0, Below
+			}
+			// bexp = 0
+			mant = msb64(r.mant) >> (fbits - r.prec)
+		} else {
+			// normal number: emin <= e <= emax
+			bexp = uint64(e+bias) << mbits
+			mant = msb64(r.mant) >> ebits & (1<<mbits - 1) // cut off msb (implicit 1 bit)
+		}
+
+		return math.Float64frombits(sign | bexp | mant), 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
+	}
+
+	panic("unreachable")
+}
+
+// Int returns the result of truncating x towards zero;
+// or nil if x is an infinity.
+// The result is Exact if x.IsInt(); otherwise it is Below
+// for x > 0, and Above for x < 0.
+// If a non-nil *Int argument z is provided, Int stores
+// the result in z instead of allocating a new Int.
+func (x *Float) Int(z *Int) (*Int, Accuracy) {
+	if debugFloat {
+		x.validate()
+	}
+
+	if z == nil && x.form <= finite {
+		z = new(Int)
+	}
+
+	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)
+	}
+
+	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, Accuracy) {
+	if debugFloat {
+		x.validate()
+	}
+
+	if z == nil && x.form <= finite {
+		z = new(Rat)
+	}
+
+	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)
+// and returns z.
+func (z *Float) Abs(x *Float) *Float {
+	z.Set(x)
+	z.neg = false
+	return z
+}
+
+// Neg sets z to the (possibly rounded) value of x with its sign negated,
+// and returns z.
+func (z *Float) Neg(x *Float) *Float {
+	z.Set(x)
+	z.neg = !z.neg
+	return z
+}
+
+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
+	// differ by wide margins. The following article describes
+	// an efficient (but much more complicated) implementation
+	// compatible with the internal representation used here:
+	//
+	// Vincent Lefèvre: "The Generic Multiple-Precision Floating-
+	// Point Addition With Exact Rounding (as in the MPFR Library)"
+	// http://www.vinc17.net/research/papers/rnc6.pdf
+
+	if debugFloat {
+		validateBinaryOperands(x, y)
+	}
+
+	// compute exponents ex, ey for mantissa with "binary point"
+	// on the right (mantissa.0) - use int64 to avoid overflow
+	ex := int64(x.exp) - int64(len(x.mant))*_W
+	ey := int64(y.exp) - int64(len(y.mant))*_W
+
+	// TODO(gri) having a combined add-and-shift primitive
+	//           could make this code significantly faster
+	switch {
+	case ex < ey:
+		// cannot re-use z.mant w/o testing for aliasing
+		t := nat(nil).shl(y.mant, uint(ey-ex))
+		z.mant = z.mant.add(x.mant, t)
+	default:
+		// ex == ey, no shift needed
+		z.mant = z.mant.add(x.mant, y.mant)
+	case ex > ey:
+		// cannot re-use z.mant w/o testing for aliasing
+		t := nat(nil).shl(x.mant, uint(ex-ey))
+		z.mant = z.mant.add(t, y.mant)
+		ex = ey
+	}
+	// len(z.mant) > 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 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 {
+		validateBinaryOperands(x, y)
+	}
+
+	ex := int64(x.exp) - int64(len(x.mant))*_W
+	ey := int64(y.exp) - int64(len(y.mant))*_W
+
+	switch {
+	case ex < ey:
+		// cannot re-use z.mant w/o testing for aliasing
+		t := nat(nil).shl(y.mant, uint(ey-ex))
+		z.mant = t.sub(x.mant, t)
+	default:
+		// ex == ey, no shift needed
+		z.mant = z.mant.sub(x.mant, y.mant)
+	case ex > ey:
+		// cannot re-use z.mant w/o testing for aliasing
+		t := nat(nil).shl(x.mant, uint(ex-ey))
+		z.mant = t.sub(t, y.mant)
+		ex = ey
+	}
+
+	// operands may have cancelled each other out
+	if len(z.mant) == 0 {
+		z.acc = Exact
+		z.form = zero
+		z.neg = false
+		return
+	}
+	// len(z.mant) > 0
+
+	z.setExpAndRound(ex+int64(len(z.mant))*_W-fnorm(z.mant), 0)
+}
+
+// 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 {
+		validateBinaryOperands(x, y)
+	}
+
+	// Note: This is doing too much work if the precision
+	// of z is less than the sum of the precisions of x
+	// and y which is often the case (e.g., if all floats
+	// have the same precision).
+	// TODO(gri) Optimize this for the common case.
+
+	e := int64(x.exp) + int64(y.exp)
+	z.mant = z.mant.mul(x.mant, y.mant)
+
+	z.setExpAndRound(e-fnorm(z.mant), 0)
+}
+
+// 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 {
+		validateBinaryOperands(x, y)
+	}
+
+	// mantissa length in words for desired result precision + 1
+	// (at least one extra bit so we get the rounding bit after
+	// the division)
+	n := int(z.prec/_W) + 1
+
+	// compute adjusted x.mant such that we get enough result precision
+	xadj := x.mant
+	if d := n - len(x.mant) + len(y.mant); d > 0 {
+		// d extra words needed => add d "0 digits" to x
+		xadj = make(nat, len(x.mant)+d)
+		copy(xadj[d:], x.mant)
+	}
+	// TODO(gri): If we have too many digits (d < 0), we should be able
+	// to shorten x for faster division. But we must be extra careful
+	// with rounding in that case.
+
+	// Compute d before division since there may be aliasing of x.mant
+	// (via xadj) or y.mant with z.mant.
+	d := len(xadj) - len(y.mant)
+
+	// divide
+	var r nat
+	z.mant, r = z.mant.div(nil, xadj, y.mant)
+	e := int64(x.exp) - int64(y.exp) - int64(d-len(z.mant))*_W
+
+	// 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
+	// zero, it couldn't have a non-zero remainder).
+	var sbit uint
+	if len(r) > 0 {
+		sbit = 1
+	}
+
+	z.setExpAndRound(e-fnorm(z.mant), sbit)
+}
+
+// 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 {
+		validateBinaryOperands(x, y)
+	}
+
+	switch {
+	case x.exp < y.exp:
+		return -1
+	case x.exp > y.exp:
+		return +1
+	}
+	// x.exp == y.exp
+
+	// compare mantissas
+	i := len(x.mant)
+	j := len(y.mant)
+	for i > 0 || j > 0 {
+		var xm, ym Word
+		if i > 0 {
+			i--
+			xm = x.mant[i]
+		}
+		if j > 0 {
+			j--
+			ym = y.mant[j]
+		}
+		switch {
+		case xm < ym:
+			return -1
+		case xm > ym:
+			return +1
+		}
+	}
+
+	return 0
+}
+
+// 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,
+// or of a difference x−y regarded as a sum x+(−y), differs from at most
+// one of the addends’ signs; and the sign of the result of conversions,
+// the quantize operation, the roundToIntegral operations, and the
+// roundToIntegralExact (see 5.3.1) is the sign of the first or only operand.
+// These rules shall apply even when operands or results are zero or infinite.
+//
+// When the sum of two operands with opposite signs (or the difference of
+// two operands with like signs) is exactly zero, the sign of that sum (or
+// difference) shall be +0 in all rounding-direction attributes except
+// 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: https://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)
+// result. Add panics with ErrNaN if x and y are infinities with opposite
+// signs. The value of z is undefined in that case.
+//
+// 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 {
+		x.validate()
+		y.validate()
+	}
+
+	if z.prec == 0 {
+		z.prec = umax32(x.prec, y.prec)
+	}
+
+	if x.form == finite && y.form == finite {
+		// x + y (commom case)
+		z.neg = x.neg
+		if x.neg == y.neg {
+			// x + y == x + y
+			// (-x) + (-y) == -(x + y)
+			z.uadd(x, y)
+		} else {
+			// x + (-y) == x - y == -(y - x)
+			// (-x) + y == y - x == -(x - y)
+			if x.ucmp(y) > 0 {
+				z.usub(x, y)
+			} else {
+				z.neg = !z.neg
+				z.usub(y, x)
+			}
+		}
+		return z
+	}
+
+	if x.form == inf && y.form == inf && x.neg != y.neg {
+		// +Inf + -Inf
+		// -Inf + +Inf
+		// value of z is undefined but make sure it's valid
+		z.acc = Exact
+		z.form = zero
+		z.neg = false
+		panic(ErrNaN{"addition of infinities with opposite signs"})
+	}
+
+	if x.form == zero && y.form == zero {
+		// ±0 + ±0
+		z.acc = Exact
+		z.form = zero
+		z.neg = x.neg && y.neg // -0 + -0 == -0
+		return z
+	}
+
+	if x.form == inf || y.form == zero {
+		// ±Inf + y
+		// x + ±0
+		return z.Set(x)
+	}
+
+	// ±0 + y
+	// x + ±Inf
+	return z.Set(y)
+}
+
+// Sub sets z to the rounded difference x-y and returns z.
+// Precision, rounding, and accuracy reporting are as for Add.
+// Sub panics with ErrNaN if x and y are infinities with equal
+// signs. The value of z is undefined in that case.
+func (z *Float) Sub(x, y *Float) *Float {
+	if debugFloat {
+		x.validate()
+		y.validate()
+	}
+
+	if z.prec == 0 {
+		z.prec = umax32(x.prec, y.prec)
+	}
+
+	if x.form == finite && y.form == finite {
+		// x - y (common case)
+		z.neg = x.neg
+		if x.neg != y.neg {
+			// x - (-y) == x + y
+			// (-x) - y == -(x + y)
+			z.uadd(x, y)
+		} else {
+			// x - y == x - y == -(y - x)
+			// (-x) - (-y) == y - x == -(x - y)
+			if x.ucmp(y) > 0 {
+				z.usub(x, y)
+			} else {
+				z.neg = !z.neg
+				z.usub(y, x)
+			}
+		}
+		return z
+	}
+
+	if x.form == inf && y.form == inf && x.neg == y.neg {
+		// +Inf - +Inf
+		// -Inf - -Inf
+		// value of z is undefined but make sure it's valid
+		z.acc = Exact
+		z.form = zero
+		z.neg = false
+		panic(ErrNaN{"subtraction of infinities with equal signs"})
+	}
+
+	if x.form == zero && y.form == zero {
+		// ±0 - ±0
+		z.acc = Exact
+		z.form = zero
+		z.neg = x.neg && !y.neg // -0 - +0 == -0
+		return z
+	}
+
+	if x.form == inf || y.form == zero {
+		// ±Inf - y
+		// x - ±0
+		return z.Set(x)
+	}
+
+	// ±0 - y
+	// x - ±Inf
+	return z.Neg(y)
+}
+
+// Mul sets z to the rounded product x*y and returns z.
+// Precision, rounding, and accuracy reporting are as for Add.
+// Mul panics with ErrNaN if one operand is zero and the other
+// operand an infinity. The value of z is undefined in that case.
+func (z *Float) Mul(x, y *Float) *Float {
+	if debugFloat {
+		x.validate()
+		y.validate()
+	}
+
+	if z.prec == 0 {
+		z.prec = umax32(x.prec, y.prec)
+	}
+
+	z.neg = x.neg != y.neg
+
+	if x.form == finite && y.form == finite {
+		// x * y (common case)
+		z.umul(x, y)
+		return z
+	}
+
+	z.acc = Exact
+	if x.form == zero && y.form == inf || x.form == inf && y.form == zero {
+		// ±0 * ±Inf
+		// ±Inf * ±0
+		// value of z is undefined but make sure it's valid
+		z.form = zero
+		z.neg = false
+		panic(ErrNaN{"multiplication of zero with infinity"})
+	}
+
+	if x.form == inf || y.form == inf {
+		// ±Inf * y
+		// x * ±Inf
+		z.form = inf
+		return z
+	}
+
+	// ±0 * y
+	// x * ±0
+	z.form = zero
+	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 with ErrNaN if both operands are zero or infinities.
+// The value of z is undefined in that case.
+func (z *Float) Quo(x, y *Float) *Float {
+	if debugFloat {
+		x.validate()
+		y.validate()
+	}
+
+	if z.prec == 0 {
+		z.prec = umax32(x.prec, y.prec)
+	}
+
+	z.neg = x.neg != y.neg
+
+	if x.form == finite && y.form == finite {
+		// x / y (common case)
+		z.uquo(x, y)
+		return z
+	}
+
+	z.acc = Exact
+	if x.form == zero && y.form == zero || x.form == inf && y.form == inf {
+		// ±0 / ±0
+		// ±Inf / ±Inf
+		// value of z is undefined but make sure it's valid
+		z.form = zero
+		z.neg = false
+		panic(ErrNaN{"division of zero by zero or infinity by infinity"})
+	}
+
+	if x.form == zero || y.form == inf {
+		// ±0 / y
+		// x / ±Inf
+		z.form = zero
+		return z
+	}
+
+	// x / ±0
+	// ±Inf / y
+	z.form = inf
+	return z
+}
+
+// Cmp compares x and y and returns:
+//
+//   -1 if x <  y
+//    0 if x == y (incl. -0 == 0, -Inf == -Inf, and +Inf == +Inf)
+//   +1 if x >  y
+//
+func (x *Float) Cmp(y *Float) int {
+	if debugFloat {
+		x.validate()
+		y.validate()
+	}
+
+	mx := x.ord()
+	my := y.ord()
+	switch {
+	case mx < my:
+		return -1
+	case mx > my:
+		return +1
+	}
+	// mx == my
+
+	// only if |mx| == 1 we have to compare the mantissae
+	switch mx {
+	case -1:
+		return y.ucmp(x)
+	case +1:
+		return x.ucmp(y)
+	}
+
+	return 0
+}
+
+// ord classifies x and returns:
+//
+//	-2 if -Inf == x
+//	-1 if -Inf < x < 0
+//	 0 if x == 0 (signed or unsigned)
+//	+1 if 0 < x < +Inf
+//	+2 if x == +Inf
+//
+func (x *Float) ord() int {
+	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
new file mode 100644
index 0000000..d3b214b
--- /dev/null
+++ b/src/math/big/float_test.go
@@ -0,0 +1,1694 @@
+// 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 big
+
+import (
+	"fmt"
+	"math"
+	"strconv"
+	"strings"
+	"testing"
+)
+
+// Verify that ErrNaN implements the error interface.
+var _ error = ErrNaN{}
+
+func (x *Float) uint64() uint64 {
+	u, acc := x.Uint64()
+	if acc != Exact {
+		panic(fmt.Sprintf("%s is not a uint64", x.Text('g', 10)))
+	}
+	return u
+}
+
+func (x *Float) int64() int64 {
+	i, acc := x.Int64()
+	if acc != Exact {
+		panic(fmt.Sprintf("%s is not an int64", x.Text('g', 10)))
+	}
+	return i
+}
+
+func TestFloatZeroValue(t *testing.T) {
+	// zero (uninitialized) value is a ready-to-use 0.0
+	var x Float
+	if s := x.Text('f', 1); s != "0.0" {
+		t.Errorf("zero value = %s; want 0.0", s)
+	}
+
+	// zero value has precision 0
+	if prec := x.Prec(); prec != 0 {
+		t.Errorf("prec = %d; want 0", prec)
+	}
+
+	// zero value can be used in any and all positions of binary operations
+	make := func(x int) *Float {
+		var f Float
+		if x != 0 {
+			f.SetInt64(int64(x))
+		}
+		// x == 0 translates into the zero value
+		return &f
+	}
+	for _, test := range []struct {
+		z, x, y, want int
+		opname        rune
+		op            func(z, x, y *Float) *Float
+	}{
+		{0, 0, 0, 0, '+', (*Float).Add},
+		{0, 1, 2, 3, '+', (*Float).Add},
+		{1, 2, 0, 2, '+', (*Float).Add},
+		{2, 0, 1, 1, '+', (*Float).Add},
+
+		{0, 0, 0, 0, '-', (*Float).Sub},
+		{0, 1, 2, -1, '-', (*Float).Sub},
+		{1, 2, 0, 2, '-', (*Float).Sub},
+		{2, 0, 1, -1, '-', (*Float).Sub},
+
+		{0, 0, 0, 0, '*', (*Float).Mul},
+		{0, 1, 2, 2, '*', (*Float).Mul},
+		{1, 2, 0, 0, '*', (*Float).Mul},
+		{2, 0, 1, 0, '*', (*Float).Mul},
+
+		// {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},
+	} {
+		z := make(test.z)
+		test.op(z, make(test.x), make(test.y))
+		got := 0
+		if !z.IsInf() {
+			got = int(z.int64())
+		}
+		if got != test.want {
+			t.Errorf("%d %c %d = %d; want %d", test.x, test.opname, test.y, got, test.want)
+		}
+	}
+
+	// TODO(gri) test how precision is set for zero value results
+}
+
+func makeFloat(s string) *Float {
+	x, _, err := ParseFloat(s, 0, 1000, ToNearestEven)
+	if err != nil {
+		panic(err)
+	}
+	return x
+}
+
+func TestFloatSetPrec(t *testing.T) {
+	for _, test := range []struct {
+		x    string
+		prec uint
+		want string
+		acc  Accuracy
+	}{
+		// prec 0
+		{"0", 0, "0", Exact},
+		{"-0", 0, "-0", Exact},
+		{"-Inf", 0, "-Inf", Exact},
+		{"+Inf", 0, "+Inf", Exact},
+		{"123", 0, "0", Below},
+		{"-123", 0, "-0", Above},
+
+		// prec at upper limit
+		{"0", MaxPrec, "0", Exact},
+		{"-0", MaxPrec, "-0", Exact},
+		{"-Inf", MaxPrec, "-Inf", Exact},
+		{"+Inf", MaxPrec, "+Inf", Exact},
+
+		// just a few regular cases - general rounding is tested elsewhere
+		{"1.5", 1, "2", Above},
+		{"-1.5", 1, "-2", Below},
+		{"123", 1e6, "123", Exact},
+		{"-123", 1e6, "-123", Exact},
+	} {
+		x := makeFloat(test.x).SetPrec(test.prec)
+		prec := test.prec
+		if prec > MaxPrec {
+			prec = MaxPrec
+		}
+		if got := x.Prec(); got != prec {
+			t.Errorf("%s.SetPrec(%d).Prec() == %d; want %d", test.x, test.prec, got, prec)
+		}
+		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)
+		}
+	}
+}
+
+func TestFloatMinPrec(t *testing.T) {
+	const max = 100
+	for _, test := range []struct {
+		x    string
+		want uint
+	}{
+		{"0", 0},
+		{"-0", 0},
+		{"+Inf", 0},
+		{"-Inf", 0},
+		{"1", 1},
+		{"2", 1},
+		{"3", 2},
+		{"0x8001", 16},
+		{"0x8001p-1000", 16},
+		{"0x8001p+1000", 16},
+		{"0.1", max},
+	} {
+		x := makeFloat(test.x).SetPrec(max)
+		if got := x.MinPrec(); got != test.want {
+			t.Errorf("%s.MinPrec() = %d; want %d", test.x, got, test.want)
+		}
+	}
+}
+
+func TestFloatSign(t *testing.T) {
+	for _, test := range []struct {
+		x string
+		s int
+	}{
+		{"-Inf", -1},
+		{"-1", -1},
+		{"-0", 0},
+		{"+0", 0},
+		{"+1", +1},
+		{"+Inf", +1},
+	} {
+		x := makeFloat(test.x)
+		s := x.Sign()
+		if s != test.s {
+			t.Errorf("%s.Sign() = %d; want %d", test.x, s, test.s)
+		}
+	}
+}
+
+// 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 alike32(x, y float32) bool {
+	// we can ignore NaNs
+	return x == y && math.Signbit(float64(x)) == math.Signbit(float64(y))
+
+}
+
+func alike64(x, y float64) bool {
+	// we can ignore NaNs
+	return x == y && math.Signbit(x) == math.Signbit(y)
+
+}
+
+func TestFloatMantExp(t *testing.T) {
+	for _, test := range []struct {
+		x    string
+		mant string
+		exp  int
+	}{
+		{"0", "0", 0},
+		{"+0", "0", 0},
+		{"-0", "-0", 0},
+		{"Inf", "+Inf", 0},
+		{"+Inf", "+Inf", 0},
+		{"-Inf", "-Inf", 0},
+		{"1.5", "0.75", 1},
+		{"1.024e3", "0.5", 11},
+		{"-0.125", "-0.5", -2},
+	} {
+		x := makeFloat(test.x)
+		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.Text('g', 10), e, test.mant, test.exp)
+		}
+	}
+}
+
+func TestFloatMantExpAliasing(t *testing.T) {
+	x := makeFloat("0.5p10")
+	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.Text('g', 10), want.Text('g', 10))
+	}
+}
+
+func TestFloatSetMantExp(t *testing.T) {
+	for _, test := range []struct {
+		frac string
+		exp  int
+		z    string
+	}{
+		{"0", 0, "0"},
+		{"+0", 0, "0"},
+		{"-0", 0, "-0"},
+		{"Inf", 1234, "+Inf"},
+		{"+Inf", -1234, "+Inf"},
+		{"-Inf", -1234, "-Inf"},
+		{"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"},
+		{"32", 5, "1024"},
+		{"1024", -10, "1"},
+	} {
+		frac := makeFloat(test.frac)
+		want := makeFloat(test.z)
+		var z Float
+		z.SetMantExp(frac, test.exp)
+		if !alike(&z, want) {
+			t.Errorf("SetMantExp(%s, %d) = %s; want %s", test.frac, test.exp, z.Text('g', 10), test.z)
+		}
+		// test inverse property
+		mant := new(Float)
+		if z.SetMantExp(mant, want.MantExp(mant)).Cmp(want) != 0 {
+			t.Errorf("Inverse property not satisfied: got %s; want %s", z.Text('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",
+		"-0 int",
+		"1 int",
+		"-1 int",
+		"0.5",
+		"1.23",
+		"1.23e1",
+		"1.23e2 int",
+		"0.000000001e+8",
+		"0.000000001e+9 int",
+		"1.2345e200 int",
+		"Inf",
+		"+Inf",
+		"-Inf",
+	} {
+		s := strings.TrimSuffix(test, " int")
+		want := s != test
+		if got := makeFloat(s).IsInt(); got != want {
+			t.Errorf("%s.IsInt() == %t", s, got)
+		}
+	}
+}
+
+func fromBinary(s string) int64 {
+	x, err := strconv.ParseInt(s, 2, 64)
+	if err != nil {
+		panic(err)
+	}
+	return x
+}
+
+func toBinary(x int64) string {
+	return strconv.FormatInt(x, 2)
+}
+
+func testFloatRound(t *testing.T, x, r int64, prec uint, mode RoundingMode) {
+	// verify test data
+	var ok bool
+	switch mode {
+	case ToNearestEven, ToNearestAway:
+		ok = true // nothing to do for now
+	case ToZero:
+		if x < 0 {
+			ok = r >= x
+		} else {
+			ok = r <= x
+		}
+	case AwayFromZero:
+		if x < 0 {
+			ok = r <= x
+		} else {
+			ok = r >= x
+		}
+	case ToNegativeInf:
+		ok = r <= x
+	case ToPositiveInf:
+		ok = r >= x
+	default:
+		panic("unreachable")
+	}
+	if !ok {
+		t.Fatalf("incorrect test data for prec = %d, %s: x = %s, r = %s", prec, mode, toBinary(x), toBinary(r))
+	}
+
+	// compute expected accuracy
+	a := Exact
+	switch {
+	case r < x:
+		a = Below
+	case r > x:
+		a = Above
+	}
+
+	// round
+	f := new(Float).SetMode(mode).SetInt64(x).SetPrec(prec)
+
+	// check result
+	r1 := f.int64()
+	p1 := f.Prec()
+	a1 := f.Acc()
+	if r1 != r || p1 != prec || a1 != a {
+		t.Errorf("round %s (%d bits, %s) incorrect: got %s (%d bits, %s); want %s (%d bits, %s)",
+			toBinary(x), prec, mode,
+			toBinary(r1), p1, a1,
+			toBinary(r), prec, a)
+		return
+	}
+
+	// g and f should be the same
+	// (rounding by SetPrec after SetInt64 using default precision
+	// should be the same as rounding by SetInt64 after setting the
+	// precision)
+	g := new(Float).SetMode(mode).SetPrec(prec).SetInt64(x)
+	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()),
+			toBinary(r1),
+			toBinary(r),
+		)
+		return
+	}
+
+	// h and f should be the same
+	// (repeated rounding should be idempotent)
+	h := new(Float).SetMode(mode).SetPrec(prec).Set(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()),
+			toBinary(r1),
+			toBinary(r),
+		)
+		return
+	}
+}
+
+// TestFloatRound tests basic rounding.
+func TestFloatRound(t *testing.T) {
+	for _, test := range []struct {
+		prec                        uint
+		x, zero, neven, naway, away string // input, results rounded to prec bits
+	}{
+		{5, "1000", "1000", "1000", "1000", "1000"},
+		{5, "1001", "1001", "1001", "1001", "1001"},
+		{5, "1010", "1010", "1010", "1010", "1010"},
+		{5, "1011", "1011", "1011", "1011", "1011"},
+		{5, "1100", "1100", "1100", "1100", "1100"},
+		{5, "1101", "1101", "1101", "1101", "1101"},
+		{5, "1110", "1110", "1110", "1110", "1110"},
+		{5, "1111", "1111", "1111", "1111", "1111"},
+
+		{4, "1000", "1000", "1000", "1000", "1000"},
+		{4, "1001", "1001", "1001", "1001", "1001"},
+		{4, "1010", "1010", "1010", "1010", "1010"},
+		{4, "1011", "1011", "1011", "1011", "1011"},
+		{4, "1100", "1100", "1100", "1100", "1100"},
+		{4, "1101", "1101", "1101", "1101", "1101"},
+		{4, "1110", "1110", "1110", "1110", "1110"},
+		{4, "1111", "1111", "1111", "1111", "1111"},
+
+		{3, "1000", "1000", "1000", "1000", "1000"},
+		{3, "1001", "1000", "1000", "1010", "1010"},
+		{3, "1010", "1010", "1010", "1010", "1010"},
+		{3, "1011", "1010", "1100", "1100", "1100"},
+		{3, "1100", "1100", "1100", "1100", "1100"},
+		{3, "1101", "1100", "1100", "1110", "1110"},
+		{3, "1110", "1110", "1110", "1110", "1110"},
+		{3, "1111", "1110", "10000", "10000", "10000"},
+
+		{3, "1000001", "1000000", "1000000", "1000000", "1010000"},
+		{3, "1001001", "1000000", "1010000", "1010000", "1010000"},
+		{3, "1010001", "1010000", "1010000", "1010000", "1100000"},
+		{3, "1011001", "1010000", "1100000", "1100000", "1100000"},
+		{3, "1100001", "1100000", "1100000", "1100000", "1110000"},
+		{3, "1101001", "1100000", "1110000", "1110000", "1110000"},
+		{3, "1110001", "1110000", "1110000", "1110000", "10000000"},
+		{3, "1111001", "1110000", "10000000", "10000000", "10000000"},
+
+		{2, "1000", "1000", "1000", "1000", "1000"},
+		{2, "1001", "1000", "1000", "1000", "1100"},
+		{2, "1010", "1000", "1000", "1100", "1100"},
+		{2, "1011", "1000", "1100", "1100", "1100"},
+		{2, "1100", "1100", "1100", "1100", "1100"},
+		{2, "1101", "1100", "1100", "1100", "10000"},
+		{2, "1110", "1100", "10000", "10000", "10000"},
+		{2, "1111", "1100", "10000", "10000", "10000"},
+
+		{2, "1000001", "1000000", "1000000", "1000000", "1100000"},
+		{2, "1001001", "1000000", "1000000", "1000000", "1100000"},
+		{2, "1010001", "1000000", "1100000", "1100000", "1100000"},
+		{2, "1011001", "1000000", "1100000", "1100000", "1100000"},
+		{2, "1100001", "1100000", "1100000", "1100000", "10000000"},
+		{2, "1101001", "1100000", "1100000", "1100000", "10000000"},
+		{2, "1110001", "1100000", "10000000", "10000000", "10000000"},
+		{2, "1111001", "1100000", "10000000", "10000000", "10000000"},
+
+		{1, "1000", "1000", "1000", "1000", "1000"},
+		{1, "1001", "1000", "1000", "1000", "10000"},
+		{1, "1010", "1000", "1000", "1000", "10000"},
+		{1, "1011", "1000", "1000", "1000", "10000"},
+		{1, "1100", "1000", "10000", "10000", "10000"},
+		{1, "1101", "1000", "10000", "10000", "10000"},
+		{1, "1110", "1000", "10000", "10000", "10000"},
+		{1, "1111", "1000", "10000", "10000", "10000"},
+
+		{1, "1000001", "1000000", "1000000", "1000000", "10000000"},
+		{1, "1001001", "1000000", "1000000", "1000000", "10000000"},
+		{1, "1010001", "1000000", "1000000", "1000000", "10000000"},
+		{1, "1011001", "1000000", "1000000", "1000000", "10000000"},
+		{1, "1100001", "1000000", "10000000", "10000000", "10000000"},
+		{1, "1101001", "1000000", "10000000", "10000000", "10000000"},
+		{1, "1110001", "1000000", "10000000", "10000000", "10000000"},
+		{1, "1111001", "1000000", "10000000", "10000000", "10000000"},
+	} {
+		x := fromBinary(test.x)
+		z := fromBinary(test.zero)
+		e := fromBinary(test.neven)
+		n := fromBinary(test.naway)
+		a := fromBinary(test.away)
+		prec := test.prec
+
+		testFloatRound(t, x, z, prec, ToZero)
+		testFloatRound(t, x, e, prec, ToNearestEven)
+		testFloatRound(t, x, n, prec, ToNearestAway)
+		testFloatRound(t, x, a, prec, AwayFromZero)
+
+		testFloatRound(t, x, z, prec, ToNegativeInf)
+		testFloatRound(t, x, a, prec, ToPositiveInf)
+
+		testFloatRound(t, -x, -a, prec, ToNegativeInf)
+		testFloatRound(t, -x, -z, prec, ToPositiveInf)
+	}
+}
+
+// TestFloatRound24 tests that rounding a float64 to 24 bits
+// matches IEEE-754 rounding to nearest when converting a
+// 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.Float32()
+		want := float32(x)
+		if got != want {
+			t.Errorf("Round(%g, 24) = %g; want %g", x, got, want)
+		}
+	}
+}
+
+func TestFloatSetUint64(t *testing.T) {
+	for _, want := range []uint64{
+		0,
+		1,
+		2,
+		10,
+		100,
+		1<<32 - 1,
+		1 << 32,
+		1<<64 - 1,
+	} {
+		var f Float
+		f.SetUint64(want)
+		if got := f.uint64(); got != want {
+			t.Errorf("got %#x (%s); want %#x", got, f.Text('p', 0), want)
+		}
+	}
+
+	// test basic rounding behavior (exhaustive rounding testing is done elsewhere)
+	const x uint64 = 0x8765432187654321 // 64 bits needed
+	for prec := uint(1); prec <= 64; prec++ {
+		f := new(Float).SetPrec(prec).SetMode(ToZero).SetUint64(x)
+		got := f.uint64()
+		want := x &^ (1<<(64-prec) - 1) // cut off (round to zero) low 64-prec bits
+		if got != want {
+			t.Errorf("got %#x (%s); want %#x", got, f.Text('p', 0), want)
+		}
+	}
+}
+
+func TestFloatSetInt64(t *testing.T) {
+	for _, want := range []int64{
+		0,
+		1,
+		2,
+		10,
+		100,
+		1<<32 - 1,
+		1 << 32,
+		1<<63 - 1,
+	} {
+		for i := range [2]int{} {
+			if i&1 != 0 {
+				want = -want
+			}
+			var f Float
+			f.SetInt64(want)
+			if got := f.int64(); got != want {
+				t.Errorf("got %#x (%s); want %#x", got, f.Text('p', 0), want)
+			}
+		}
+	}
+
+	// test basic rounding behavior (exhaustive rounding testing is done elsewhere)
+	const x int64 = 0x7654321076543210 // 63 bits needed
+	for prec := uint(1); prec <= 63; prec++ {
+		f := new(Float).SetPrec(prec).SetMode(ToZero).SetInt64(x)
+		got := f.int64()
+		want := x &^ (1<<(63-prec) - 1) // cut off (round to zero) low 63-prec bits
+		if got != want {
+			t.Errorf("got %#x (%s); want %#x", got, f.Text('p', 0), want)
+		}
+	}
+}
+
+func TestFloatSetFloat64(t *testing.T) {
+	for _, want := range []float64{
+		0,
+		1,
+		2,
+		12345,
+		1e10,
+		1e100,
+		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),
+	} {
+		for i := range [2]int{} {
+			if i&1 != 0 {
+				want = -want
+			}
+			var f Float
+			f.SetFloat64(want)
+			if got, acc := f.Float64(); got != want || acc != Exact {
+				t.Errorf("got %g (%s, %s); want %g (Exact)", got, f.Text('p', 0), acc, want)
+			}
+		}
+	}
+
+	// test basic rounding behavior (exhaustive rounding testing is done elsewhere)
+	const x uint64 = 0x8765432143218 // 53 bits needed
+	for prec := uint(1); prec <= 52; prec++ {
+		f := new(Float).SetPrec(prec).SetMode(ToZero).SetFloat64(float64(x))
+		got, _ := f.Float64()
+		want := float64(x &^ (1<<(52-prec) - 1)) // cut off (round to zero) low 53-prec bits
+		if got != want {
+			t.Errorf("got %g (%s); want %g", got, f.Text('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.Text('p', 0))
+}
+
+func TestFloatSetInt(t *testing.T) {
+	for _, want := range []string{
+		"0",
+		"1",
+		"-1",
+		"1234567890",
+		"123456789012345678901234567890",
+		"123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890",
+	} {
+		var x Int
+		_, ok := x.SetString(want, 0)
+		if !ok {
+			t.Errorf("invalid integer %s", want)
+			continue
+		}
+		n := x.BitLen()
+
+		var f Float
+		f.SetInt(&x)
+
+		// check precision
+		if n < 64 {
+			n = 64
+		}
+		if prec := f.Prec(); prec != uint(n) {
+			t.Errorf("got prec = %d; want %d", prec, n)
+		}
+
+		// check value
+		got := f.Text('g', 100)
+		if got != want {
+			t.Errorf("got %s (%s); want %s", got, f.Text('p', 0), want)
+		}
+	}
+
+	// TODO(gri) test basic rounding behavior
+}
+
+func TestFloatSetRat(t *testing.T) {
+	for _, want := range []string{
+		"0",
+		"1",
+		"-1",
+		"1234567890",
+		"123456789012345678901234567890",
+		"123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890",
+		"1.2",
+		"3.14159265",
+		// TODO(gri) expand
+	} {
+		var x Rat
+		_, ok := x.SetString(want)
+		if !ok {
+			t.Errorf("invalid fraction %s", want)
+			continue
+		}
+		n := max(x.Num().BitLen(), x.Denom().BitLen())
+
+		var f1, f2 Float
+		f2.SetPrec(1000)
+		f1.SetRat(&x)
+		f2.SetRat(&x)
+
+		// check precision when set automatically
+		if n < 64 {
+			n = 64
+		}
+		if prec := f1.Prec(); prec != uint(n) {
+			t.Errorf("got prec = %d; want %d", prec, n)
+		}
+
+		got := f2.Text('g', 100)
+		if got != want {
+			t.Errorf("got %s (%s); want %s", got, f2.Text('p', 0), want)
+		}
+	}
+}
+
+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
+		out uint64
+		acc Accuracy
+	}{
+		{"-Inf", 0, Above},
+		{"-1", 0, Above},
+		{"-1e-1000", 0, Above},
+		{"-0", 0, Exact},
+		{"0", 0, Exact},
+		{"1e-1000", 0, Below},
+		{"1", 1, Exact},
+		{"1.000000000000000000001", 1, Below},
+		{"12345.0", 12345, Exact},
+		{"12345.000000000000000000001", 12345, Below},
+		{"18446744073709551615", 18446744073709551615, Exact},
+		{"18446744073709551615.000000000000000000001", math.MaxUint64, Below},
+		{"18446744073709551616", math.MaxUint64, Below},
+		{"1e10000", math.MaxUint64, Below},
+		{"+Inf", math.MaxUint64, Below},
+	} {
+		x := makeFloat(test.x)
+		out, acc := x.Uint64()
+		if out != test.out || acc != test.acc {
+			t.Errorf("%s: got %d (%s); want %d (%s)", test.x, out, acc, test.out, test.acc)
+		}
+	}
+}
+
+func TestFloatInt64(t *testing.T) {
+	for _, test := range []struct {
+		x   string
+		out int64
+		acc Accuracy
+	}{
+		{"-Inf", math.MinInt64, Above},
+		{"-1e10000", math.MinInt64, Above},
+		{"-9223372036854775809", math.MinInt64, Above},
+		{"-9223372036854775808.000000000000000000001", math.MinInt64, Above},
+		{"-9223372036854775808", -9223372036854775808, Exact},
+		{"-9223372036854775807.000000000000000000001", -9223372036854775807, Above},
+		{"-9223372036854775807", -9223372036854775807, Exact},
+		{"-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},
+		{"9223372036854775807.000000000000000000001", math.MaxInt64, Below},
+		{"9223372036854775808", math.MaxInt64, Below},
+		{"1e10000", math.MaxInt64, Below},
+		{"+Inf", math.MaxInt64, Below},
+	} {
+		x := makeFloat(test.x)
+		out, acc := x.Int64()
+		if out != test.out || acc != test.acc {
+			t.Errorf("%s: got %d (%s); want %d (%s)", test.x, out, acc, test.out, test.acc)
+		}
+	}
+}
+
+func TestFloatFloat32(t *testing.T) {
+	for _, test := range []struct {
+		x   string
+		out float32
+		acc Accuracy
+	}{
+		{"0", 0, Exact},
+
+		// underflow
+		{"1e-1000", 0, Below},
+		{"0x0.000002p-127", 0, Below},
+		{"0x.0000010p-126", 0, Below},
+
+		// denormals
+		{"1.401298464e-45", math.SmallestNonzeroFloat32, Above}, // rounded up to smallest denormal
+		{"0x.ffffff8p-149", math.SmallestNonzeroFloat32, Above}, // rounded up to smallest denormal
+		{"0x.0000018p-126", math.SmallestNonzeroFloat32, Above}, // rounded up to smallest denormal
+		{"0x.0000020p-126", math.SmallestNonzeroFloat32, Exact},
+		{"0x.8p-148", math.SmallestNonzeroFloat32, Exact},
+		{"1p-149", math.SmallestNonzeroFloat32, Exact},
+		{"0x.fffffep-126", math.Float32frombits(0x7fffff), Exact}, // largest denormal
+
+		// normals
+		{"0x.ffffffp-126", math.Float32frombits(0x00800000), Above}, // rounded up to smallest normal
+		{"1p-126", math.Float32frombits(0x00800000), Exact},         // smallest normal
+		{"0x1.fffffep-126", math.Float32frombits(0x00ffffff), Exact},
+		{"0x1.ffffffp-126", math.Float32frombits(0x01000000), Above}, // rounded up
+		{"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},
+
+		// overflow
+		{"0x1.ffffff0p127", float32(math.Inf(+1)), Above},
+		{"0x1p128", float32(math.Inf(+1)), Above},
+		{"1e10000", float32(math.Inf(+1)), Above},
+		{"0x1.ffffff0p2147483646", float32(math.Inf(+1)), Above}, // overflow in rounding
+
+		// inf
+		{"Inf", float32(math.Inf(+1)), Exact},
+	} {
+		for i := 0; i < 2; i++ {
+			// test both signs
+			tx, tout, tacc := test.x, test.out, test.acc
+			if i != 0 {
+				tx = "-" + tx
+				tout = -tout
+				tacc = -tacc
+			}
+
+			// conversion should match strconv where syntax is agreeable
+			if f, err := strconv.ParseFloat(tx, 32); err == nil && !alike32(float32(f), tout) {
+				t.Errorf("%s: got %g; want %g (incorrect test data)", tx, f, tout)
+			}
+
+			x := makeFloat(tx)
+			out, acc := x.Float32()
+			if !alike32(out, tout) || acc != tacc {
+				t.Errorf("%s: got %g (%#x, %s); want %g (%#x, %s)", tx, out, math.Float32bits(out), acc, test.out, math.Float32bits(test.out), tacc)
+			}
+
+			// test that x.SetFloat64(float64(f)).Float32() == f
+			var x2 Float
+			out2, acc2 := x2.SetFloat64(float64(out)).Float32()
+			if !alike32(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
+	}{
+		{"0", 0, Exact},
+
+		// underflow
+		{"1e-1000", 0, Below},
+		{"0x0.0000000000001p-1023", 0, Below},
+		{"0x0.00000000000008p-1022", 0, Below},
+
+		// denormals
+		{"0x0.0000000000000cp-1022", math.SmallestNonzeroFloat64, Above}, // rounded up to smallest denormal
+		{"0x0.0000000000001p-1022", math.SmallestNonzeroFloat64, Exact},  // smallest denormal
+		{"0x.8p-1073", math.SmallestNonzeroFloat64, Exact},
+		{"1p-1074", math.SmallestNonzeroFloat64, Exact},
+		{"0x.fffffffffffffp-1022", math.Float64frombits(0x000fffffffffffff), Exact}, // largest denormal
+
+		// normals
+		{"0x.fffffffffffff8p-1022", math.Float64frombits(0x0010000000000000), Above}, // rounded up to smallest normal
+		{"1p-1022", math.Float64frombits(0x0010000000000000), Exact},                 // smallest normal
+		{"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},
+
+		// overflow
+		{"0x1.fffffffffffff8p1023", math.Inf(+1), Above},
+		{"0x1p1024", math.Inf(+1), Above},
+		{"1e10000", math.Inf(+1), Above},
+		{"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},
+	} {
+		for i := 0; i < 2; i++ {
+			// test both signs
+			tx, tout, tacc := test.x, test.out, test.acc
+			if i != 0 {
+				tx = "-" + tx
+				tout = -tout
+				tacc = -tacc
+			}
+
+			// conversion should match strconv where syntax is agreeable
+			if f, err := strconv.ParseFloat(tx, 64); err == nil && !alike64(f, tout) {
+				t.Errorf("%s: got %g; want %g (incorrect test data)", tx, f, tout)
+			}
+
+			x := makeFloat(tx)
+			out, acc := x.Float64()
+			if !alike64(out, tout) || acc != tacc {
+				t.Errorf("%s: got %g (%#x, %s); want %g (%#x, %s)", tx, out, math.Float64bits(out), acc, test.out, math.Float64bits(test.out), tacc)
+			}
+
+			// test that x.SetFloat64(f).Float64() == f
+			var x2 Float
+			out2, acc2 := x2.SetFloat64(out).Float64()
+			if !alike64(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
+		want string
+		acc  Accuracy
+	}{
+		{"0", "0", Exact},
+		{"+0", "0", Exact},
+		{"-0", "0", Exact},
+		{"Inf", "nil", Below},
+		{"+Inf", "nil", Below},
+		{"-Inf", "nil", Above},
+		{"1", "1", Exact},
+		{"-1", "-1", Exact},
+		{"1.23", "1", Below},
+		{"-1.23", "-1", Above},
+		{"123e-2", "1", Below},
+		{"123e-3", "0", Below},
+		{"123e-4", "0", Below},
+		{"1e-1000", "0", Below},
+		{"-1e-1000", "0", Above},
+		{"1e+10", "10000000000", Exact},
+		{"1e+100", "10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", Exact},
+	} {
+		x := makeFloat(test.x)
+		res, acc := x.Int(nil)
+		got := "nil"
+		if res != nil {
+			got = res.String()
+		}
+		if got != test.want || acc != test.acc {
+			t.Errorf("%s: got %s (%s); want %s (%s)", test.x, got, acc, test.want, test.acc)
+		}
+	}
+
+	// check that supplied *Int is used
+	for _, f := range []string{"0", "1", "-1", "1234"} {
+		x := makeFloat(f)
+		i := new(Int)
+		if res, _ := x.Int(i); res != i {
+			t.Errorf("(%s).Int is not using supplied *Int", f)
+		}
+	}
+}
+
+func TestFloatRat(t *testing.T) {
+	for _, test := range []struct {
+		x, want string
+		acc     Accuracy
+	}{
+		{"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, acc := x.Rat(nil)
+		got := "nil"
+		if res != nil {
+			got = res.String()
+		}
+		if got != test.want {
+			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 {
+			got := new(Float).SetPrec(64).SetRat(res)
+			if got.Cmp(x) != 0 {
+				t.Errorf("%s: got %s; want %s", test.x, got, x)
+			}
+		}
+	}
+
+	// check that supplied *Rat is used
+	for _, f := range []string{"0", "1", "-1", "1234"} {
+		x := makeFloat(f)
+		r := new(Rat)
+		if res, _ := x.Rat(r); res != r {
+			t.Errorf("(%s).Rat is not using supplied *Rat", f)
+		}
+	}
+}
+
+func TestFloatAbs(t *testing.T) {
+	for _, test := range []string{
+		"0",
+		"1",
+		"1234",
+		"1.23e-2",
+		"1e-1000",
+		"1e1000",
+		"Inf",
+	} {
+		p := makeFloat(test)
+		a := new(Float).Abs(p)
+		if !alike(a, p) {
+			t.Errorf("%s: got %s; want %s", test, a.Text('g', 10), test)
+		}
+
+		n := makeFloat("-" + test)
+		a.Abs(n)
+		if !alike(a, p) {
+			t.Errorf("-%s: got %s; want %s", test, a.Text('g', 10), test)
+		}
+	}
+}
+
+func TestFloatNeg(t *testing.T) {
+	for _, test := range []string{
+		"0",
+		"1",
+		"1234",
+		"1.23e-2",
+		"1e-1000",
+		"1e1000",
+		"Inf",
+	} {
+		p1 := makeFloat(test)
+		n1 := makeFloat("-" + test)
+		n2 := new(Float).Neg(p1)
+		p2 := new(Float).Neg(n2)
+		if !alike(n2, n1) {
+			t.Errorf("%s: got %s; want %s", test, n2.Text('g', 10), n1.Text('g', 10))
+		}
+		if !alike(p2, p1) {
+			t.Errorf("%s: got %s; want %s", test, p2.Text('g', 10), p1.Text('g', 10))
+		}
+	}
+}
+
+func TestFloatInc(t *testing.T) {
+	const n = 10
+	for _, prec := range precList {
+		if 1<<prec < n {
+			continue // prec must be large enough to hold all numbers from 0 to n
+		}
+		var x, one Float
+		x.SetPrec(prec)
+		one.SetInt64(1)
+		for i := 0; i < n; i++ {
+			x.Add(&x, &one)
+		}
+		if x.Cmp(new(Float).SetInt64(n)) != 0 {
+			t.Errorf("prec = %d: got %s; want %d", prec, &x, n)
+		}
+	}
+}
+
+// Selected precisions with which to run various tests.
+var precList = [...]uint{1, 2, 5, 8, 10, 16, 23, 24, 32, 50, 53, 64, 100, 128, 500, 511, 512, 513, 1000, 10000}
+
+// Selected bits with which to run various tests.
+// Each entry is a list of bits representing a floating-point number (see fromBits).
+var bitsList = [...]Bits{
+	{},           // = 0
+	{0},          // = 1
+	{1},          // = 2
+	{-1},         // = 1/2
+	{10},         // = 2**10 == 1024
+	{-10},        // = 2**-10 == 1/1024
+	{100, 10, 1}, // = 2**100 + 2**10 + 2**1
+	{0, -1, -2, -10},
+	// TODO(gri) add more test cases
+}
+
+// TestFloatAdd tests Float.Add/Sub by comparing the result of a "manual"
+// 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 := 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 := 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)
+					}
+
+					got.Sub(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)
+					}
+				}
+			}
+		}
+	}
+}
+
+// TestFloatAdd32 tests that Float.Add/Sub of numbers with
+// 24bit mantissa behaves like float32 addition/subtraction
+// (excluding denormal numbers).
+func TestFloatAdd32(t *testing.T) {
+	// 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++ {
+		for i := range [2]int{} {
+			x0, y0 := float64(base), float64(d)
+			if i&1 != 0 {
+				x0, y0 = y0, x0
+			}
+
+			x := NewFloat(x0)
+			y := NewFloat(y0)
+			z := new(Float).SetPrec(24)
+
+			z.Add(x, y)
+			got, acc := z.Float32()
+			want := float32(y0) + float32(x0)
+			if got != want || acc != Exact {
+				t.Errorf("d = %d: %g + %g = %g (%s); want %g (Exact)", d, x0, y0, got, acc, want)
+			}
+
+			z.Sub(z, y)
+			got, acc = z.Float32()
+			want = float32(want) - float32(y0)
+			if got != want || acc != Exact {
+				t.Errorf("d = %d: %g - %g = %g (%s); want %g (Exact)", d, x0+y0, y0, got, acc, want)
+			}
+		}
+	}
+}
+
+// TestFloatAdd64 tests that Float.Add/Sub of numbers with
+// 53bit mantissa behaves like float64 addition/subtraction.
+func TestFloatAdd64(t *testing.T) {
+	// chose base such that we cross the mantissa precision limit
+	const base = 1<<55 - 0x10 // 11...110000 (55 bits)
+	for d := 0; d <= 0x10; d++ {
+		for i := range [2]int{} {
+			x0, y0 := float64(base), float64(d)
+			if i&1 != 0 {
+				x0, y0 = y0, x0
+			}
+
+			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 (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 (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) {
+	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
+// 53bit mantissa behaves like float64 multiplication/division.
+func TestFloatMul64(t *testing.T) {
+	for _, test := range []struct {
+		x, y float64
+	}{
+		{0, 0},
+		{0, 1},
+		{1, 1},
+		{1, 1.5},
+		{1.234, 0.5678},
+		{2.718281828, 3.14159265358979},
+		{2.718281828e10, 3.14159265358979e-32},
+		{1.0 / 3, 1e200},
+	} {
+		for i := range [8]int{} {
+			x0, y0 := test.x, test.y
+			if i&1 != 0 {
+				x0 = -x0
+			}
+			if i&2 != 0 {
+				y0 = -y0
+			}
+			if i&4 != 0 {
+				x0, y0 = y0, x0
+			}
+
+			x := NewFloat(x0)
+			y := NewFloat(y0)
+			z := new(Float).SetPrec(53)
+
+			z.Mul(x, y)
+			got, _ := z.Float64()
+			want := x0 * y0
+			if got != want {
+				t.Errorf("%g * %g = %g; want %g", x0, y0, got, want)
+			}
+
+			if y0 == 0 {
+				continue // avoid division-by-zero
+			}
+			z.Quo(z, y)
+			got, _ = z.Float64()
+			want /= y0
+			if got != want {
+				t.Errorf("%g / %g = %g; want %g", x0*y0, y0, got, want)
+			}
+		}
+	}
+}
+
+func TestIssue6866(t *testing.T) {
+	for _, prec := range precList {
+		two := new(Float).SetPrec(prec).SetInt64(2)
+		one := new(Float).SetPrec(prec).SetInt64(1)
+		three := new(Float).SetPrec(prec).SetInt64(3)
+		msix := new(Float).SetPrec(prec).SetInt64(-6)
+		psix := new(Float).SetPrec(prec).SetInt64(+6)
+
+		p := new(Float).SetPrec(prec)
+		z1 := new(Float).SetPrec(prec)
+		z2 := new(Float).SetPrec(prec)
+
+		// z1 = 2 + 1.0/3*-6
+		p.Quo(one, three)
+		p.Mul(p, msix)
+		z1.Add(two, p)
+
+		// z2 = 2 - 1.0/3*+6
+		p.Quo(one, three)
+		p.Mul(p, psix)
+		z2.Sub(two, p)
+
+		if z1.Cmp(z2) != 0 {
+			t.Fatalf("prec %d: got z1 = %s != z2 = %s; want z1 == z2\n", prec, z1, z2)
+		}
+		if z1.Sign() != 0 {
+			t.Errorf("prec %d: got z1 = %s; want 0", prec, z1)
+		}
+		if z2.Sign() != 0 {
+			t.Errorf("prec %d: got z2 = %s; want 0", prec, z2)
+		}
+	}
+}
+
+func TestFloatQuo(t *testing.T) {
+	// TODO(gri) make the test vary these precisions
+	preci := 200 // precision of integer part
+	precf := 20  // precision of fractional part
+
+	for i := 0; i < 8; i++ {
+		// compute accurate (not rounded) result z
+		bits := Bits{preci - 1}
+		if i&3 != 0 {
+			bits = append(bits, 0)
+		}
+		if i&2 != 0 {
+			bits = append(bits, -1)
+		}
+		if i&1 != 0 {
+			bits = append(bits, -precf)
+		}
+		z := bits.Float()
+
+		// compute accurate x as z*y
+		y := NewFloat(3.14159265358979323e123)
+
+		x := new(Float).SetPrec(z.Prec() + y.Prec()).SetMode(ToZero)
+		x.Mul(z, y)
+
+		// leave for debugging
+		// fmt.Printf("x = %s\ny = %s\nz = %s\n", x, y, z)
+
+		if got := x.Acc(); got != Exact {
+			t.Errorf("got acc = %s; want exact", got)
+		}
+
+		// round accurate z for a variety of precisions and
+		// modes and compare against result of x / y.
+		for _, mode := range [...]RoundingMode{ToZero, ToNearestEven, AwayFromZero} {
+			for d := -5; d < 5; d++ {
+				prec := uint(preci + d)
+				got := new(Float).SetPrec(prec).SetMode(mode).Quo(x, y)
+				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)
+				}
+			}
+		}
+	}
+}
+
+// TestFloatQuoSmoke tests all divisions x/y for values x, y in the range [-n, +n];
+// it serves as a smoke test for basic correctness of division.
+func TestFloatQuoSmoke(t *testing.T) {
+	n := 1000
+	if testing.Short() {
+		n = 10
+	}
+
+	const dprec = 3         // max. precision variation
+	const prec = 10 + dprec // enough bits to hold n precisely
+	for x := -n; x <= n; x++ {
+		for y := -n; y < n; y++ {
+			if y == 0 {
+				continue
+			}
+
+			a := float64(x)
+			b := float64(y)
+			c := a / b
+
+			// vary operand precision (only ok as long as a, b can be represented correctly)
+			for ad := -dprec; ad <= dprec; ad++ {
+				for bd := -dprec; bd <= dprec; bd++ {
+					A := new(Float).SetPrec(uint(prec + ad)).SetFloat64(a)
+					B := new(Float).SetPrec(uint(prec + bd)).SetFloat64(b)
+					C := new(Float).SetPrec(53).Quo(A, B) // C has float64 mantissa width
+
+					cc, acc := C.Float64()
+					if cc != c {
+						t.Errorf("%g/%g = %s; want %.5g\n", a, b, C.Text('g', 5), c)
+						continue
+					}
+					if acc != Exact {
+						t.Errorf("%g/%g got %s result; want exact result", a, b, acc)
+					}
+				}
+			}
+		}
+	}
+}
+
+// TestFloatArithmeticSpecialValues tests that Float operations produce the
+// correct results for combinations of zero (±0), finite (±1 and ±2.71828),
+// and infinite (±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 {
+				yy.SetFloat64(y)
+				var (
+					op string
+					z  float64
+					f  func(z, x, y *Float) *Float
+				)
+				switch i {
+				case 0:
+					op = "+"
+					z = x + y
+					f = (*Float).Add
+				case 1:
+					op = "-"
+					z = x - y
+					f = (*Float).Sub
+				case 2:
+					op = "*"
+					z = x * y
+					f = (*Float).Mul
+				case 3:
+					op = "/"
+					z = x / y
+					f = (*Float).Quo
+				default:
+					panic("unreachable")
+				}
+				var errnan bool // set if execution of f panicked with ErrNaN
+				// protect execution of f
+				func() {
+					defer func() {
+						if p := recover(); p != nil {
+							_ = p.(ErrNaN) // re-panic if not ErrNaN
+							errnan = true
+						}
+					}()
+					f(got, xx, yy)
+				}()
+				if math.IsNaN(z) {
+					if !errnan {
+						t.Errorf("%5g %s %5g = %5s; want ErrNaN panic", x, op, y, got)
+					}
+					continue
+				}
+				if errnan {
+					t.Errorf("%5g %s %5g panicked with ErrNan; want %5s", x, op, y, want)
+					continue
+				}
+				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.8p+0", "0x.8p+0", "0x.8p+1", Exact}, // smoke test
+
+		{4, ToNearestEven, '+', "0", "0x.8p2147483647", "0x.8p+2147483647", Exact},
+		{4, ToNearestEven, '+', "0x.8p2147483500", "0x.8p2147483647", "0x.8p+2147483647", 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.fp+2147483647", 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.fp+2147483647", 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.8p+2147483647", 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.8p+0", "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.Text('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.Text('p', 0), test.op, y.Text('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
+// by the sign of the value to be rounded. Test that rounding happens after
+// the sign of a result has been set.
+// This test uses specific values that are known to fail if rounding is
+// "factored" out before setting the result sign.
+func TestFloatArithmeticRounding(t *testing.T) {
+	for _, test := range []struct {
+		mode       RoundingMode
+		prec       uint
+		x, y, want int64
+		op         byte
+	}{
+		{ToZero, 3, -0x8, -0x1, -0x8, '+'},
+		{AwayFromZero, 3, -0x8, -0x1, -0xa, '+'},
+		{ToNegativeInf, 3, -0x8, -0x1, -0xa, '+'},
+
+		{ToZero, 3, -0x8, 0x1, -0x8, '-'},
+		{AwayFromZero, 3, -0x8, 0x1, -0xa, '-'},
+		{ToNegativeInf, 3, -0x8, 0x1, -0xa, '-'},
+
+		{ToZero, 3, -0x9, 0x1, -0x8, '*'},
+		{AwayFromZero, 3, -0x9, 0x1, -0xa, '*'},
+		{ToNegativeInf, 3, -0x9, 0x1, -0xa, '*'},
+
+		{ToZero, 3, -0x9, 0x1, -0x8, '/'},
+		{AwayFromZero, 3, -0x9, 0x1, -0xa, '/'},
+		{ToNegativeInf, 3, -0x9, 0x1, -0xa, '/'},
+	} {
+		var x, y, z Float
+		x.SetInt64(test.x)
+		y.SetInt64(test.y)
+		z.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, acc := z.Int64(); got != test.want || acc != Exact {
+			t.Errorf("%s, %d bits: %d %c %d = %d (%s); want %d (Exact)",
+				test.mode, test.prec, test.x, test.op, test.y, got, acc, test.want,
+			)
+		}
+	}
+}
+
+// TestFloatCmpSpecialValues tests that Cmp produces the correct results for
+// combinations of zero (±0), finite (±1 and ±2.71828), and infinite (±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)
+			}
+			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) = %v; want %v", x, y, got, want)
+				}
+			}
+		}
+	}
+}
diff --git a/src/math/big/floatconv.go b/src/math/big/floatconv.go
new file mode 100644
index 0000000..4a070ca
--- /dev/null
+++ b/src/math/big/floatconv.go
@@ -0,0 +1,239 @@
+// 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 string-to-Float conversion functions.
+
+package big
+
+import (
+	"fmt"
+	"io"
+	"strings"
+)
+
+// SetString sets z to the value of s and returns z and a boolean indicating
+// success. s must be a floating-point number of the same format as accepted
+// by Parse, with base argument 0.
+func (z *Float) SetString(s string) (*Float, bool) {
+	if f, _, err := z.Parse(s, 0); err == nil {
+		return f, true
+	}
+	return nil, false
+}
+
+// scan is like Parse but reads the longest possible prefix representing a valid
+// floating point number from an io.ByteScanner rather than a string. It serves
+// as the implementation of Parse. It does not recognize ±Inf and does not expect
+// EOF at the end.
+func (z *Float) scan(r io.ByteScanner, base int) (f *Float, b int, err error) {
+	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 {
+		return
+	}
+
+	// mantissa
+	var fcount int // fractional digit count; valid if <= 0
+	z.mant, b, fcount, err = z.mant.scan(r, base, true)
+	if err != nil {
+		return
+	}
+
+	// exponent
+	var exp int64
+	var ebase int
+	exp, ebase, err = scanExponent(r, true)
+	if err != nil {
+		return
+	}
+
+	// special-case 0
+	if len(z.mant) == 0 {
+		z.prec = prec
+		z.acc = Exact
+		z.form = zero
+		f = z
+		return
+	}
+	// len(z.mant) > 0
+
+	// The mantissa may have a decimal point (fcount <= 0) and there
+	// may be a nonzero exponent exp. The decimal point amounts to a
+	// division by b**(-fcount). An exponent means multiplication by
+	// ebase**exp. Finally, mantissa normalization (shift left) requires
+	// a correcting multiplication by 2**(-shiftcount). Multiplications
+	// are commutative, so we can apply them in any order as long as there
+	// is no loss of precision. We only have powers of 2 and 10; keep
+	// track via separate exponents exp2 and exp10.
+
+	// normalize mantissa and get initial binary exponent
+	var exp2 = int64(len(z.mant))*_W - fnorm(z.mant)
+
+	// determine binary or decimal exponent contribution of decimal point
+	var exp10 int64
+	if fcount < 0 {
+		// The mantissa has a "decimal" point ddd.dddd; and
+		// -fcount is the number of digits to the right of '.'.
+		// Adjust relevant exponent accodingly.
+		switch b {
+		case 16:
+			fcount *= 4 // hexadecimal digits are 4 bits each
+			fallthrough
+		case 2:
+			exp2 += int64(fcount)
+		default: // b == 10
+			exp10 = int64(fcount)
+		}
+		// we don't need fcount anymore
+	}
+
+	// take actual exponent into account
+	if ebase == 2 {
+		exp2 += exp
+	} else { // ebase == 10
+		exp10 += exp
+	}
+	// we don't need exp anymore
+
+	// apply 2**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
+		z.round(0)
+		return
+	}
+	// exp10 != 0
+
+	// apply 10**exp10
+	p := new(Float).SetPrec(z.Prec() + 64) // use more bits for p -- TODO(gri) what is the right number?
+	if exp10 < 0 {
+		z.uquo(z, p.pow10(-exp10))
+	} else {
+		z.umul(z, p.pow10(exp10))
+	}
+
+	return
+}
+
+// These powers of 10 can be represented exactly as a float64.
+var pow10tab = [...]float64{
+	1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
+	1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
+}
+
+// pow10 sets z to 10**n and returns z.
+// n must not be negative.
+func (z *Float) pow10(n int64) *Float {
+	if n < 0 {
+		panic("pow10 called with negative argument")
+	}
+
+	const m = int64(len(pow10tab) - 1)
+	if n <= m {
+		return z.SetFloat64(pow10tab[n])
+	}
+	// n > m
+
+	z.SetFloat64(pow10tab[m])
+	n -= m
+
+	// use more bits for f than for z
+	// TODO(gri) what is the right number?
+	f := new(Float).SetPrec(z.Prec() + 64).SetInt64(10)
+
+	for n > 0 {
+		if n&1 != 0 {
+			z.Mul(z, f)
+		}
+		f.Mul(f, f)
+		n >>= 1
+	}
+
+	return z
+}
+
+// Parse parses s which must contain a text representation of a floating-
+// point number with a mantissa in the given conversion base (the exponent
+// is always a decimal number), or a string representing an infinite value.
+//
+// It sets z to the (possibly rounded) value of the corresponding floating-
+// point value, and returns z, the actual base b, and an error err, if any.
+// If z's precision is 0, it is changed to 64 before rounding takes effect.
+// The number must be of the form:
+//
+//	number   = [ sign ] [ prefix ] mantissa [ exponent ] | infinity .
+//	sign     = "+" | "-" .
+//      prefix   = "0" ( "x" | "X" | "b" | "B" ) .
+//	mantissa = digits | digits "." [ digits ] | "." digits .
+//	exponent = ( "E" | "e" | "p" ) [ sign ] digits .
+//	digits   = digit { digit } .
+//	digit    = "0" ... "9" | "a" ... "z" | "A" ... "Z" .
+//      infinity = [ sign ] ( "inf" | "Inf" ) .
+//
+// The base argument must be 0, 2, 10, or 16. Providing an invalid base
+// argument will lead to a run-time panic.
+//
+// For base 0, the number prefix determines the actual base: A prefix of
+// "0x" or "0X" selects base 16, and a "0b" or "0B" prefix selects
+// base 2; otherwise, the actual base is 10 and no prefix is accepted.
+// The octal prefix "0" is not supported (a leading "0" is simply
+// considered a "0").
+//
+// A "p" exponent indicates a binary (rather then decimal) exponent;
+// for instance "0x1.fffffffffffffp1023" (using base 0) represents the
+// maximum float64 value. For hexadecimal mantissae, the exponent must
+// be binary, if present (an "e" or "E" exponent indicator cannot be
+// distinguished from a mantissa digit).
+//
+// The returned *Float f is nil and the value of z is valid but not
+// defined if an error is reported.
+//
+func (z *Float) Parse(s string, base int) (f *Float, b int, err error) {
+	// scan doesn't handle ±Inf
+	if len(s) == 3 && (s == "Inf" || s == "inf") {
+		f = z.SetInf(false)
+		return
+	}
+	if len(s) == 4 && (s[0] == '+' || s[0] == '-') && (s[1:] == "Inf" || s[1:] == "inf") {
+		f = z.SetInf(s[0] == '-')
+		return
+	}
+
+	r := strings.NewReader(s)
+	if f, b, err = z.scan(r, base); err != nil {
+		return
+	}
+
+	// entire string must have been consumed
+	if ch, err2 := r.ReadByte(); err2 == nil {
+		err = fmt.Errorf("expected end of string, found %q", ch)
+	} else if err2 != io.EOF {
+		err = err2
+	}
+
+	return
+}
+
+// ParseFloat is like f.Parse(s, base) with f set to the given precision
+// and rounding mode.
+func ParseFloat(s string, base int, prec uint, mode RoundingMode) (f *Float, b int, err error) {
+	return new(Float).SetPrec(prec).SetMode(mode).Parse(s, base)
+}
diff --git a/src/math/big/floatconv_test.go b/src/math/big/floatconv_test.go
new file mode 100644
index 0000000..4f23953
--- /dev/null
+++ b/src/math/big/floatconv_test.go
@@ -0,0 +1,573 @@
+// 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
+
+import (
+	"fmt"
+	"math"
+	"strconv"
+	"testing"
+)
+
+func TestFloatSetFloat64String(t *testing.T) {
+	inf := math.Inf(0)
+	nan := math.NaN()
+
+	for _, test := range []struct {
+		s string
+		x float64 // NaNs represent invalid inputs
+	}{
+		// basics
+		{"0", 0},
+		{"-0", -0},
+		{"+0", 0},
+		{"1", 1},
+		{"-1", -1},
+		{"+1", 1},
+		{"1.234", 1.234},
+		{"-1.234", -1.234},
+		{"+1.234", 1.234},
+		{".1", 0.1},
+		{"1.", 1},
+		{"+1.", 1},
+
+		// various zeros
+		{"0e100", 0},
+		{"-0e+100", 0},
+		{"+0e-100", 0},
+		{"0E100", 0},
+		{"-0E+100", 0},
+		{"+0E-100", 0},
+
+		// various decimal exponent formats
+		{"1.e10", 1e10},
+		{"1e+10", 1e10},
+		{"+1e-10", 1e-10},
+		{"1E10", 1e10},
+		{"1.E+10", 1e10},
+		{"+1E-10", 1e-10},
+
+		// infinities
+		{"Inf", inf},
+		{"+Inf", inf},
+		{"-Inf", -inf},
+		{"inf", inf},
+		{"+inf", inf},
+		{"-inf", -inf},
+
+		// invalid numbers
+		{"", nan},
+		{"-", nan},
+		{"0x", nan},
+		{"0e", nan},
+		{"1.2ef", nan},
+		{"2..3", nan},
+		{"123..", nan},
+		{"infinity", nan},
+		{"foobar", nan},
+
+		// misc decimal values
+		{"3.14159265", 3.14159265},
+		{"-687436.79457e-245", -687436.79457e-245},
+		{"-687436.79457E245", -687436.79457e245},
+		{".0000000000000000000000000000000000000001", 1e-40},
+		{"+10000000000000000000000000000000000000000e-0", 1e40},
+
+		// decimal mantissa, binary exponent
+		{"0p0", 0},
+		{"-0p0", -0},
+		{"1p10", 1 << 10},
+		{"1p+10", 1 << 10},
+		{"+1p-10", 1.0 / (1 << 10)},
+		{"1024p-12", 0.25},
+		{"-1p10", -1024},
+		{"1.5p1", 3},
+
+		// binary mantissa, decimal exponent
+		{"0b0", 0},
+		{"-0b0", -0},
+		{"0b0e+10", 0},
+		{"-0b0e-10", -0},
+		{"0b1010", 10},
+		{"0B1010E2", 1000},
+		{"0b.1", 0.5},
+		{"0b.001", 0.125},
+		{"0b.001e3", 125},
+
+		// binary mantissa, binary exponent
+		{"0b0p+10", 0},
+		{"-0b0p-10", -0},
+		{"0b.1010p4", 10},
+		{"0b1p-1", 0.5},
+		{"0b001p-3", 0.125},
+		{"0b.001p3", 1},
+		{"0b0.01p2", 1},
+
+		// hexadecimal mantissa and exponent
+		{"0x0", 0},
+		{"-0x0", -0},
+		{"0x0p+10", 0},
+		{"-0x0p-10", -0},
+		{"0xff", 255},
+		{"0X.8p1", 1},
+		{"-0X0.00008p16", -0.5},
+		{"0x0.0000000000001p-1022", math.SmallestNonzeroFloat64},
+		{"0x1.fffffffffffffp1023", math.MaxFloat64},
+	} {
+		var x Float
+		x.SetPrec(53)
+		_, ok := x.SetString(test.s)
+		if math.IsNaN(test.x) {
+			// test.s is invalid
+			if ok {
+				t.Errorf("%s: want parse error", test.s)
+			}
+			continue
+		}
+		// test.s is valid
+		if !ok {
+			t.Errorf("%s: got parse error", test.s)
+			continue
+		}
+		f, _ := x.Float64()
+		want := new(Float).SetFloat64(test.x)
+		if x.Cmp(want) != 0 {
+			t.Errorf("%s: got %s (%v); want %v", test.s, &x, f, test.x)
+		}
+	}
+}
+
+const (
+	below1e23 = 99999999999999974834176
+	above1e23 = 100000000000000008388608
+)
+
+func TestFloat64Text(t *testing.T) {
+	for _, test := range []struct {
+		x      float64
+		format byte
+		prec   int
+		want   string
+	}{
+		{0, 'f', 0, "0"},
+		{math.Copysign(0, -1), 'f', 0, "-0"},
+		{1, 'f', 0, "1"},
+		{-1, 'f', 0, "-1"},
+
+		{0.001, 'e', 0, "1e-03"},
+		{0.459, 'e', 0, "5e-01"},
+		{1.459, 'e', 0, "1e+00"},
+		{2.459, 'e', 1, "2.5e+00"},
+		{3.459, 'e', 2, "3.46e+00"},
+		{4.459, 'e', 3, "4.459e+00"},
+		{5.459, 'e', 4, "5.4590e+00"},
+
+		{0.001, 'f', 0, "0"},
+		{0.459, 'f', 0, "0"},
+		{1.459, 'f', 0, "1"},
+		{2.459, 'f', 1, "2.5"},
+		{3.459, 'f', 2, "3.46"},
+		{4.459, 'f', 3, "4.459"},
+		{5.459, 'f', 4, "5.4590"},
+
+		{0, 'b', 0, "0"},
+		{math.Copysign(0, -1), 'b', 0, "-0"},
+		{1.0, 'b', 0, "4503599627370496p-52"},
+		{-1.0, 'b', 0, "-4503599627370496p-52"},
+		{4503599627370496, 'b', 0, "4503599627370496p+0"},
+
+		{0, 'p', 0, "0"},
+		{math.Copysign(0, -1), 'p', 0, "-0"},
+		{1024.0, 'p', 0, "0x.8p+11"},
+		{-1024.0, 'p', 0, "-0x.8p+11"},
+
+		// all test cases below from strconv/ftoa_test.go
+		{1, 'e', 5, "1.00000e+00"},
+		{1, 'f', 5, "1.00000"},
+		{1, 'g', 5, "1"},
+		// {1, 'g', -1, "1"},
+		// {20, 'g', -1, "20"},
+		// {1234567.8, 'g', -1, "1.2345678e+06"},
+		// {200000, 'g', -1, "200000"},
+		// {2000000, 'g', -1, "2e+06"},
+
+		// g conversion and zero suppression
+		{400, 'g', 2, "4e+02"},
+		{40, 'g', 2, "40"},
+		{4, 'g', 2, "4"},
+		{.4, 'g', 2, "0.4"},
+		{.04, 'g', 2, "0.04"},
+		{.004, 'g', 2, "0.004"},
+		{.0004, 'g', 2, "0.0004"},
+		{.00004, 'g', 2, "4e-05"},
+		{.000004, 'g', 2, "4e-06"},
+
+		{0, 'e', 5, "0.00000e+00"},
+		{0, 'f', 5, "0.00000"},
+		{0, 'g', 5, "0"},
+		// {0, 'g', -1, "0"},
+
+		{-1, 'e', 5, "-1.00000e+00"},
+		{-1, 'f', 5, "-1.00000"},
+		{-1, 'g', 5, "-1"},
+		// {-1, 'g', -1, "-1"},
+
+		{12, 'e', 5, "1.20000e+01"},
+		{12, 'f', 5, "12.00000"},
+		{12, 'g', 5, "12"},
+		// {12, 'g', -1, "12"},
+
+		{123456700, 'e', 5, "1.23457e+08"},
+		{123456700, 'f', 5, "123456700.00000"},
+		{123456700, 'g', 5, "1.2346e+08"},
+		// {123456700, 'g', -1, "1.234567e+08"},
+
+		{1.2345e6, 'e', 5, "1.23450e+06"},
+		{1.2345e6, 'f', 5, "1234500.00000"},
+		{1.2345e6, 'g', 5, "1.2345e+06"},
+
+		{1e23, 'e', 17, "9.99999999999999916e+22"},
+		{1e23, 'f', 17, "99999999999999991611392.00000000000000000"},
+		{1e23, 'g', 17, "9.9999999999999992e+22"},
+
+		// {1e23, 'e', -1, "1e+23"},
+		// {1e23, 'f', -1, "100000000000000000000000"},
+		// {1e23, 'g', -1, "1e+23"},
+
+		{below1e23, 'e', 17, "9.99999999999999748e+22"},
+		{below1e23, 'f', 17, "99999999999999974834176.00000000000000000"},
+		{below1e23, 'g', 17, "9.9999999999999975e+22"},
+
+		// {below1e23, 'e', -1, "9.999999999999997e+22"},
+		// {below1e23, 'f', -1, "99999999999999970000000"},
+		// {below1e23, 'g', -1, "9.999999999999997e+22"},
+
+		{above1e23, 'e', 17, "1.00000000000000008e+23"},
+		{above1e23, 'f', 17, "100000000000000008388608.00000000000000000"},
+		// {above1e23, 'g', 17, "1.0000000000000001e+23"},
+
+		// {above1e23, 'e', -1, "1.0000000000000001e+23"},
+		// {above1e23, 'f', -1, "100000000000000010000000"},
+		// {above1e23, 'g', -1, "1.0000000000000001e+23"},
+
+		// {fdiv(5e-304, 1e20), 'g', -1, "5e-324"},
+		// {fdiv(-5e-304, 1e20), 'g', -1, "-5e-324"},
+
+		// {32, 'g', -1, "32"},
+		// {32, 'g', 0, "3e+01"},
+
+		// {100, 'x', -1, "%x"},
+
+		// {math.NaN(), 'g', -1, "NaN"},
+		// {-math.NaN(), 'g', -1, "NaN"},
+		{math.Inf(0), 'g', -1, "+Inf"},
+		{math.Inf(-1), 'g', -1, "-Inf"},
+		{-math.Inf(0), 'g', -1, "-Inf"},
+
+		{-1, 'b', -1, "-4503599627370496p-52"},
+
+		// fixed bugs
+		{0.9, 'f', 1, "0.9"},
+		{0.09, 'f', 1, "0.1"},
+		{0.0999, 'f', 1, "0.1"},
+		{0.05, 'f', 1, "0.1"},
+		{0.05, 'f', 0, "0"},
+		{0.5, 'f', 1, "0.5"},
+		{0.5, 'f', 0, "0"},
+		{1.5, 'f', 0, "2"},
+
+		// http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/
+		// {2.2250738585072012e-308, 'g', -1, "2.2250738585072014e-308"},
+		// http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/
+		// {2.2250738585072011e-308, 'g', -1, "2.225073858507201e-308"},
+
+		// Issue 2625.
+		{383260575764816448, 'f', 0, "383260575764816448"},
+		// {383260575764816448, 'g', -1, "3.8326057576481645e+17"},
+	} {
+		f := new(Float).SetFloat64(test.x)
+		got := f.Text(test.format, test.prec)
+		if got != test.want {
+			t.Errorf("%v: got %s; want %s", test, got, test.want)
+		}
+
+		if test.format == 'b' && test.x == 0 {
+			continue // 'b' format in strconv.Float requires knowledge of bias for 0.0
+		}
+		if test.format == 'p' {
+			continue // 'p' format not supported in strconv.Format
+		}
+
+		// verify that Float format matches strconv format
+		want := strconv.FormatFloat(test.x, test.format, test.prec, 64)
+		if got != want {
+			t.Errorf("%v: got %s; want %s (strconv)", test, got, want)
+		}
+	}
+}
+
+func TestFloatText(t *testing.T) {
+	for _, test := range []struct {
+		x      string
+		prec   uint
+		format byte
+		digits int
+		want   string
+	}{
+		{"0", 10, 'f', 0, "0"},
+		{"-0", 10, 'f', 0, "-0"},
+		{"1", 10, 'f', 0, "1"},
+		{"-1", 10, 'f', 0, "-1"},
+
+		{"1.459", 100, 'e', 0, "1e+00"},
+		{"2.459", 100, 'e', 1, "2.5e+00"},
+		{"3.459", 100, 'e', 2, "3.46e+00"},
+		{"4.459", 100, 'e', 3, "4.459e+00"},
+		{"5.459", 100, 'e', 4, "5.4590e+00"},
+
+		{"1.459", 100, 'E', 0, "1E+00"},
+		{"2.459", 100, 'E', 1, "2.5E+00"},
+		{"3.459", 100, 'E', 2, "3.46E+00"},
+		{"4.459", 100, 'E', 3, "4.459E+00"},
+		{"5.459", 100, 'E', 4, "5.4590E+00"},
+
+		{"1.459", 100, 'f', 0, "1"},
+		{"2.459", 100, 'f', 1, "2.5"},
+		{"3.459", 100, 'f', 2, "3.46"},
+		{"4.459", 100, 'f', 3, "4.459"},
+		{"5.459", 100, 'f', 4, "5.4590"},
+
+		{"1.459", 100, 'g', 0, "1"},
+		{"2.459", 100, 'g', 1, "2"},
+		{"3.459", 100, 'g', 2, "3.5"},
+		{"4.459", 100, 'g', 3, "4.46"},
+		{"5.459", 100, 'g', 4, "5.459"},
+
+		{"1459", 53, 'g', 0, "1e+03"},
+		{"2459", 53, 'g', 1, "2e+03"},
+		{"3459", 53, 'g', 2, "3.5e+03"},
+		{"4459", 53, 'g', 3, "4.46e+03"},
+		{"5459", 53, 'g', 4, "5459"},
+
+		{"1459", 53, 'G', 0, "1E+03"},
+		{"2459", 53, 'G', 1, "2E+03"},
+		{"3459", 53, 'G', 2, "3.5E+03"},
+		{"4459", 53, 'G', 3, "4.46E+03"},
+		{"5459", 53, 'G', 4, "5459"},
+
+		{"3", 10, 'e', 40, "3.0000000000000000000000000000000000000000e+00"},
+		{"3", 10, 'f', 40, "3.0000000000000000000000000000000000000000"},
+		{"3", 10, 'g', 40, "3"},
+
+		{"3e40", 100, 'e', 40, "3.0000000000000000000000000000000000000000e+40"},
+		{"3e40", 100, 'f', 4, "30000000000000000000000000000000000000000.0000"},
+		{"3e40", 100, 'g', 40, "3e+40"},
+
+		// make sure "stupid" exponents don't stall the machine
+		{"1e1000000", 64, 'p', 0, "0x.88b3a28a05eade3ap+3321929"},
+		{"1e1000000000", 64, 'p', 0, "0x.ecc5f45aa573d3p+1538481529"},
+		{"1e-1000000", 64, 'p', 0, "0x.efb4542cc8ca418ap-3321928"},
+		{"1e-1000000000", 64, 'p', 0, "0x.8a64dd983a4c7dabp-1538481528"},
+
+		// TODO(gri) need tests for actual large Floats
+
+		{"0", 53, 'b', 0, "0"},
+		{"-0", 53, 'b', 0, "-0"},
+		{"1.0", 53, 'b', 0, "4503599627370496p-52"},
+		{"-1.0", 53, 'b', 0, "-4503599627370496p-52"},
+		{"4503599627370496", 53, 'b', 0, "4503599627370496p+0"},
+
+		// issue 9939
+		{"3", 350, 'b', 0, "1720123961992553633708115671476565205597423741876210842803191629540192157066363606052513914832594264915968p-348"},
+		{"03", 350, 'b', 0, "1720123961992553633708115671476565205597423741876210842803191629540192157066363606052513914832594264915968p-348"},
+		{"3.", 350, 'b', 0, "1720123961992553633708115671476565205597423741876210842803191629540192157066363606052513914832594264915968p-348"},
+		{"3.0", 350, 'b', 0, "1720123961992553633708115671476565205597423741876210842803191629540192157066363606052513914832594264915968p-348"},
+		{"3.00", 350, 'b', 0, "1720123961992553633708115671476565205597423741876210842803191629540192157066363606052513914832594264915968p-348"},
+		{"3.000", 350, 'b', 0, "1720123961992553633708115671476565205597423741876210842803191629540192157066363606052513914832594264915968p-348"},
+
+		{"3", 350, 'p', 0, "0x.cp+2"},
+		{"03", 350, 'p', 0, "0x.cp+2"},
+		{"3.", 350, 'p', 0, "0x.cp+2"},
+		{"3.0", 350, 'p', 0, "0x.cp+2"},
+		{"3.00", 350, 'p', 0, "0x.cp+2"},
+		{"3.000", 350, 'p', 0, "0x.cp+2"},
+
+		{"0", 64, 'p', 0, "0"},
+		{"-0", 64, 'p', 0, "-0"},
+		{"1024.0", 64, 'p', 0, "0x.8p+11"},
+		{"-1024.0", 64, 'p', 0, "-0x.8p+11"},
+
+		// unsupported format
+		{"3.14", 64, 'x', 0, "%x"},
+		{"-3.14", 64, 'x', 0, "%x"},
+	} {
+		f, _, err := ParseFloat(test.x, 0, test.prec, ToNearestEven)
+		if err != nil {
+			t.Errorf("%v: %s", test, err)
+			continue
+		}
+
+		got := f.Text(test.format, test.digits)
+		if got != test.want {
+			t.Errorf("%v: got %s; want %s", test, got, test.want)
+		}
+
+		// compare with strconv.FormatFloat output if possible
+		// ('p' format is not supported by strconv.FormatFloat,
+		// and its output for 0.0 prints a biased exponent value
+		// as in 0p-1074 which makes no sense to emulate here)
+		if test.prec == 53 && test.format != 'p' && f.Sign() != 0 {
+			f64, acc := f.Float64()
+			if acc != Exact {
+				t.Errorf("%v: expected exact conversion to float64", test)
+				continue
+			}
+			got := strconv.FormatFloat(f64, test.format, test.digits, 64)
+			if got != test.want {
+				t.Errorf("%v: got %s; want %s", test, got, test.want)
+			}
+		}
+	}
+}
+
+func TestFloatFormat(t *testing.T) {
+	for _, test := range []struct {
+		format string
+		value  interface{} // float32, float64, or string (== 512bit *Float)
+		want   string
+	}{
+		// TODO(gri) uncomment the disabled 'g'/'G' formats
+		// 	     below once (*Float).Text supports prec < 0
+
+		// from fmt/fmt_test.go
+		{"%+.3e", 0.0, "+0.000e+00"},
+		{"%+.3e", 1.0, "+1.000e+00"},
+		{"%+.3f", -1.0, "-1.000"},
+		{"%+.3F", -1.0, "-1.000"},
+		{"%+.3F", float32(-1.0), "-1.000"},
+		{"%+07.2f", 1.0, "+001.00"},
+		{"%+07.2f", -1.0, "-001.00"},
+		{"%+10.2f", +1.0, "     +1.00"},
+		{"%+10.2f", -1.0, "     -1.00"},
+		{"% .3E", -1.0, "-1.000E+00"},
+		{"% .3e", 1.0, " 1.000e+00"},
+		{"%+.3g", 0.0, "+0"},
+		{"%+.3g", 1.0, "+1"},
+		{"%+.3g", -1.0, "-1"},
+		{"% .3g", -1.0, "-1"},
+		{"% .3g", 1.0, " 1"},
+		{"%b", float32(1.0), "8388608p-23"},
+		{"%b", 1.0, "4503599627370496p-52"},
+
+		// from fmt/fmt_test.go: old test/fmt_test.go
+		{"%e", 1.0, "1.000000e+00"},
+		{"%e", 1234.5678e3, "1.234568e+06"},
+		{"%e", 1234.5678e-8, "1.234568e-05"},
+		{"%e", -7.0, "-7.000000e+00"},
+		{"%e", -1e-9, "-1.000000e-09"},
+		{"%f", 1234.5678e3, "1234567.800000"},
+		{"%f", 1234.5678e-8, "0.000012"},
+		{"%f", -7.0, "-7.000000"},
+		{"%f", -1e-9, "-0.000000"},
+		// {"%g", 1234.5678e3, "1.2345678e+06"},
+		// {"%g", float32(1234.5678e3), "1.2345678e+06"},
+		// {"%g", 1234.5678e-8, "1.2345678e-05"},
+		{"%g", -7.0, "-7"},
+		{"%g", -1e-9, "-1e-09"},
+		{"%g", float32(-1e-9), "-1e-09"},
+		{"%E", 1.0, "1.000000E+00"},
+		{"%E", 1234.5678e3, "1.234568E+06"},
+		{"%E", 1234.5678e-8, "1.234568E-05"},
+		{"%E", -7.0, "-7.000000E+00"},
+		{"%E", -1e-9, "-1.000000E-09"},
+		// {"%G", 1234.5678e3, "1.2345678E+06"},
+		// {"%G", float32(1234.5678e3), "1.2345678E+06"},
+		// {"%G", 1234.5678e-8, "1.2345678E-05"},
+		{"%G", -7.0, "-7"},
+		{"%G", -1e-9, "-1E-09"},
+		{"%G", float32(-1e-9), "-1E-09"},
+
+		{"%20.6e", 1.2345e3, "        1.234500e+03"},
+		{"%20.6e", 1.2345e-3, "        1.234500e-03"},
+		{"%20e", 1.2345e3, "        1.234500e+03"},
+		{"%20e", 1.2345e-3, "        1.234500e-03"},
+		{"%20.8e", 1.2345e3, "      1.23450000e+03"},
+		{"%20f", 1.23456789e3, "         1234.567890"},
+		{"%20f", 1.23456789e-3, "            0.001235"},
+		{"%20f", 12345678901.23456789, "  12345678901.234568"},
+		{"%-20f", 1.23456789e3, "1234.567890         "},
+		{"%20.8f", 1.23456789e3, "       1234.56789000"},
+		{"%20.8f", 1.23456789e-3, "          0.00123457"},
+		// {"%g", 1.23456789e3, "1234.56789"},
+		// {"%g", 1.23456789e-3, "0.00123456789"},
+		// {"%g", 1.23456789e20, "1.23456789e+20"},
+		{"%20e", math.Inf(1), "                +Inf"},
+		{"%-20f", math.Inf(-1), "-Inf                "},
+
+		// from fmt/fmt_test.go: comparison of padding rules with C printf
+		{"%.2f", 1.0, "1.00"},
+		{"%.2f", -1.0, "-1.00"},
+		{"% .2f", 1.0, " 1.00"},
+		{"% .2f", -1.0, "-1.00"},
+		{"%+.2f", 1.0, "+1.00"},
+		{"%+.2f", -1.0, "-1.00"},
+		{"%7.2f", 1.0, "   1.00"},
+		{"%7.2f", -1.0, "  -1.00"},
+		{"% 7.2f", 1.0, "   1.00"},
+		{"% 7.2f", -1.0, "  -1.00"},
+		{"%+7.2f", 1.0, "  +1.00"},
+		{"%+7.2f", -1.0, "  -1.00"},
+		{"%07.2f", 1.0, "0001.00"},
+		{"%07.2f", -1.0, "-001.00"},
+		{"% 07.2f", 1.0, " 001.00"},
+		{"% 07.2f", -1.0, "-001.00"},
+		{"%+07.2f", 1.0, "+001.00"},
+		{"%+07.2f", -1.0, "-001.00"},
+
+		// from fmt/fmt_test.go: zero padding does not apply to infinities
+		{"%020f", math.Inf(-1), "                -Inf"},
+		{"%020f", math.Inf(+1), "                +Inf"},
+		{"% 020f", math.Inf(-1), "                -Inf"},
+		{"% 020f", math.Inf(+1), "                 Inf"},
+		{"%+020f", math.Inf(-1), "                -Inf"},
+		{"%+020f", math.Inf(+1), "                +Inf"},
+		{"%20f", -1.0, "           -1.000000"},
+
+		// handle %v like %g
+		{"%v", 0.0, "0"},
+		{"%v", -7.0, "-7"},
+		{"%v", -1e-9, "-1e-09"},
+		{"%v", float32(-1e-9), "-1e-09"},
+		{"%010v", 0.0, "0000000000"},
+		{"%010v", 0.0, "0000000000"},
+
+		// *Float cases
+		{"%.20f", "1e-20", "0.00000000000000000001"},
+		{"%.20f", "-1e-20", "-0.00000000000000000001"},
+		{"%30.20f", "-1e-20", "       -0.00000000000000000001"},
+		{"%030.20f", "-1e-20", "-00000000.00000000000000000001"},
+		{"%030.20f", "+1e-20", "000000000.00000000000000000001"},
+		{"% 030.20f", "+1e-20", " 00000000.00000000000000000001"},
+
+		// erroneous formats
+		{"%s", 1.0, "%!s(*big.Float=1)"},
+	} {
+		value := new(Float)
+		switch v := test.value.(type) {
+		case float32:
+			value.SetPrec(24).SetFloat64(float64(v))
+		case float64:
+			value.SetPrec(53).SetFloat64(v)
+		case string:
+			value.SetPrec(512).Parse(v, 0)
+		default:
+			t.Fatalf("unsupported test value: %v (%T)", v, v)
+		}
+
+		if got := fmt.Sprintf(test.format, value); got != test.want {
+			t.Errorf("%v: got %q; want %q", test, got, test.want)
+		}
+	}
+}
diff --git a/src/math/big/floatexample_test.go b/src/math/big/floatexample_test.go
new file mode 100644
index 0000000..358776e
--- /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 = %.10g (%s, prec = %d, acc = %s)\n", &x, x.Text('p', 0), x.Prec(), x.Acc())
+	fmt.Printf("y = %.10g (%s, prec = %d, acc = %s)\n", &y, y.Text('p', 0), y.Prec(), y.Acc())
+	fmt.Printf("z = %.10g (%s, prec = %d, acc = %s)\n", &z, z.Text('p', 0), z.Prec(), z.Acc())
+	// Output:
+	// x = 1000 (0x.fap+10, prec = 64, acc = Exact)
+	// y = 2.718281828 (0x.adf85458248cd8p+2, prec = 53, acc = Exact)
+	// z = 1002.718282 (0x.faadf854p+10, 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("%4g  %4g  %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
new file mode 100644
index 0000000..5c5f2ce
--- /dev/null
+++ b/src/math/big/ftoa.go
@@ -0,0 +1,393 @@
+// 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 Float-to-string conversion functions.
+// It is closely following the corresponding implementation
+// in strconv/ftoa.go, but modified and simplified for Float.
+
+package big
+
+import (
+	"fmt"
+	"strconv"
+	"strings"
+)
+
+// Text converts the floating-point number x to a string according
+// to the given format and precision prec. The format is one of:
+//
+//	'e'	-d.dddde±dd, decimal exponent, at least two (possibly 0) exponent digits
+//	'E'	-d.ddddE±dd, decimal exponent, at least two (possibly 0) exponent digits
+//	'f'	-ddddd.dddd, no exponent
+//	'g'	like 'e' for large exponents, like 'f' otherwise
+//	'G'	like 'E' for large exponents, like 'f' otherwise
+//	'b'	-ddddddp±dd, binary exponent
+//	'p'	-0x.dddp±dd, binary exponent, hexadecimal mantissa
+//
+// For the binary exponent formats, the mantissa is printed in normalized form:
+//
+//	'b'	decimal integer mantissa using x.Prec() bits, or -0
+//	'p'	hexadecimal fraction with 0.5 <= 0.mantissa < 1.0, or -0
+//
+// If format is a different character, Text returns a "%" followed by the
+// unrecognized format character.
+//
+// The precision prec controls the number of digits (excluding the exponent)
+// printed by the 'e', 'E', 'f', 'g', and 'G' formats. For 'e', 'E', and 'f'
+// it is the number of digits after the decimal point. For 'g' and 'G' it is
+// the total number of digits. A negative precision selects the smallest
+// number of digits necessary to identify the value x uniquely.
+// The prec value is ignored for the 'b' or 'p' format.
+//
+// BUG(gri) Float.Text does not accept negative precisions (issue #10991).
+func (x *Float) Text(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))
+}
+
+// String formats x like x.Text('g', 10).
+func (x *Float) String() string {
+	return x.Text('g', 10)
+}
+
+// Append appends to buf the string form of the floating-point number x,
+// as generated by x.Text, and returns the extended buffer.
+func (x *Float) Append(buf []byte, fmt byte, prec int) []byte {
+	// sign
+	if x.neg {
+		buf = append(buf, '-')
+	}
+
+	// Inf
+	if x.form == inf {
+		if !x.neg {
+			buf = append(buf, '+')
+		}
+		return append(buf, "Inf"...)
+	}
+
+	// pick off easy formats
+	switch fmt {
+	case 'b':
+		return x.fmtB(buf)
+	case 'p':
+		return x.fmtP(buf)
+	}
+
+	// Algorithm:
+	//   1) convert Float to multiprecision decimal
+	//   2) round to desired precision
+	//   3) read digits out and format
+
+	// 1) convert Float to multiprecision decimal
+	var d decimal // == 0.0
+	if x.form == finite {
+		d.init(x.mant, int(x.exp)-x.mant.bitLen())
+	}
+
+	// 2) round to desired precision
+	shortest := false
+	if prec < 0 {
+		shortest = true
+		panic("unimplemented")
+		// TODO(gri) complete this
+		// roundShortest(&d, f.mant, int(f.exp))
+		// Precision for shortest representation mode.
+		switch fmt {
+		case 'e', 'E':
+			prec = len(d.mant) - 1
+		case 'f':
+			prec = max(len(d.mant)-d.exp, 0)
+		case 'g', 'G':
+			prec = len(d.mant)
+		}
+	} else {
+		// round appropriately
+		switch fmt {
+		case 'e', 'E':
+			// one digit before and number of digits after decimal point
+			d.round(1 + prec)
+		case 'f':
+			// number of digits before and after decimal point
+			d.round(d.exp + prec)
+		case 'g', 'G':
+			if prec == 0 {
+				prec = 1
+			}
+			d.round(prec)
+		}
+	}
+
+	// 3) read digits out and format
+	switch fmt {
+	case 'e', 'E':
+		return fmtE(buf, fmt, prec, d)
+	case 'f':
+		return fmtF(buf, prec, d)
+	case 'g', 'G':
+		// trim trailing fractional zeros in %e format
+		eprec := prec
+		if eprec > len(d.mant) && len(d.mant) >= d.exp {
+			eprec = len(d.mant)
+		}
+		// %e is used if the exponent from the conversion
+		// is less than -4 or greater than or equal to the precision.
+		// If precision was the shortest possible, use eprec = 6 for
+		// this decision.
+		if shortest {
+			eprec = 6
+		}
+		exp := d.exp - 1
+		if exp < -4 || exp >= eprec {
+			if prec > len(d.mant) {
+				prec = len(d.mant)
+			}
+			return fmtE(buf, fmt+'e'-'g', prec-1, d)
+		}
+		if prec > d.exp {
+			prec = len(d.mant)
+		}
+		return fmtF(buf, max(prec-d.exp, 0), d)
+	}
+
+	// unknown format
+	if x.neg {
+		buf = buf[:len(buf)-1] // sign was added prematurely - remove it again
+	}
+	return append(buf, '%', fmt)
+}
+
+// %e: d.ddddde±dd
+func fmtE(buf []byte, fmt byte, prec int, d decimal) []byte {
+	// first digit
+	ch := byte('0')
+	if len(d.mant) > 0 {
+		ch = d.mant[0]
+	}
+	buf = append(buf, ch)
+
+	// .moredigits
+	if prec > 0 {
+		buf = append(buf, '.')
+		i := 1
+		m := min(len(d.mant), prec+1)
+		if i < m {
+			buf = append(buf, d.mant[i:m]...)
+			i = m
+		}
+		for ; i <= prec; i++ {
+			buf = append(buf, '0')
+		}
+	}
+
+	// e±
+	buf = append(buf, fmt)
+	var exp int64
+	if len(d.mant) > 0 {
+		exp = int64(d.exp) - 1 // -1 because first digit was printed before '.'
+	}
+	if exp < 0 {
+		ch = '-'
+		exp = -exp
+	} else {
+		ch = '+'
+	}
+	buf = append(buf, ch)
+
+	// dd...d
+	if exp < 10 {
+		buf = append(buf, '0') // at least 2 exponent digits
+	}
+	return strconv.AppendInt(buf, exp, 10)
+}
+
+// %f: ddddddd.ddddd
+func fmtF(buf []byte, prec int, d decimal) []byte {
+	// integer, padded with zeros as needed
+	if d.exp > 0 {
+		m := min(len(d.mant), d.exp)
+		buf = append(buf, d.mant[:m]...)
+		for ; m < d.exp; m++ {
+			buf = append(buf, '0')
+		}
+	} else {
+		buf = append(buf, '0')
+	}
+
+	// fraction
+	if prec > 0 {
+		buf = append(buf, '.')
+		for i := 0; i < prec; i++ {
+			ch := byte('0')
+			if j := d.exp + i; 0 <= j && j < len(d.mant) {
+				ch = d.mant[j]
+			}
+			buf = append(buf, ch)
+		}
+	}
+
+	return buf
+}
+
+// fmtB appends the string of x in the format mantissa "p" exponent
+// with a decimal mantissa and a binary exponent, or 0" if x is zero,
+// and returns the extended buffer.
+// The mantissa is normalized such that is uses x.Prec() bits in binary
+// representation.
+// The sign of x is ignored, and x must not be an Inf.
+func (x *Float) fmtB(buf []byte) []byte {
+	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
+	m := x.mant
+	switch w := uint32(len(x.mant)) * _W; {
+	case w < x.prec:
+		m = nat(nil).shl(m, uint(x.prec-w))
+	case w > x.prec:
+		m = nat(nil).shr(m, uint(w-x.prec))
+	}
+
+	buf = append(buf, m.decimalString()...)
+	buf = append(buf, 'p')
+	e := int64(x.exp) - int64(x.prec)
+	if e >= 0 {
+		buf = append(buf, '+')
+	}
+	return strconv.AppendInt(buf, e, 10)
+}
+
+// fmtP appends the string of x in the format 0x." mantissa "p" exponent
+// with a hexadecimal mantissa and a binary exponent, or 0" if x is zero,
+// ad returns the extended buffer.
+// The mantissa is normalized such that 0.5 <= 0.mantissa < 1.0.
+// The sign of x is ignored, and x must not be an Inf.
+func (x *Float) fmtP(buf []byte) []byte {
+	if x.form == zero {
+		return append(buf, '0')
+	}
+
+	if debugFloat && x.form != finite {
+		panic("non-finite float")
+	}
+	// x != 0
+
+	// remove trailing 0 words early
+	// (no need to convert to hex 0's and trim later)
+	m := x.mant
+	i := 0
+	for i < len(m) && m[i] == 0 {
+		i++
+	}
+	m = m[i:]
+
+	buf = append(buf, "0x."...)
+	buf = append(buf, strings.TrimRight(m.hexString(), "0")...)
+	buf = append(buf, 'p')
+	if x.exp >= 0 {
+		buf = append(buf, '+')
+	}
+	return strconv.AppendInt(buf, int64(x.exp), 10)
+}
+
+func min(x, y int) int {
+	if x < y {
+		return x
+	}
+	return y
+}
+
+// Format implements fmt.Formatter. It accepts all the regular
+// formats for floating-point numbers ('e', 'E', 'f', 'F', 'g',
+// 'G') as well as 'b', 'p', and 'v'. See (*Float).Text for the
+// interpretation of 'b' and 'p'. The 'v' format is handled like
+// 'g'.
+// Format also supports specification of the minimum precision
+// in digits, the output field width, as well as the format verbs
+// '+' and ' ' for sign control, '0' for space or zero padding,
+// and '-' for left or right justification. See the fmt package
+// for details.
+//
+// BUG(gri) A missing precision for the 'g' format, or a negative
+//          (via '*') precision is not yet supported. Instead the
+//          default precision (6) is used in that case (issue #10991).
+func (x *Float) Format(s fmt.State, format rune) {
+	prec, hasPrec := s.Precision()
+	if !hasPrec {
+		prec = 6 // default precision for 'e', 'f'
+	}
+
+	switch format {
+	case 'e', 'E', 'f', 'b', 'p':
+		// nothing to do
+	case 'F':
+		// (*Float).Text doesn't support 'F'; handle like 'f'
+		format = 'f'
+	case 'v':
+		// handle like 'g'
+		format = 'g'
+		fallthrough
+	case 'g', 'G':
+		if !hasPrec {
+			// TODO(gri) uncomment once (*Float).Text handles prec < 0
+			// prec = -1 // default precision for 'g', 'G'
+		}
+	default:
+		fmt.Fprintf(s, "%%!%c(*big.Float=%s)", format, x.String())
+		return
+	}
+	var buf []byte
+	buf = x.Append(buf, byte(format), prec)
+	if len(buf) == 0 {
+		buf = []byte("?") // should never happen, but don't crash
+	}
+	// len(buf) > 0
+
+	var sign string
+	switch {
+	case buf[0] == '-':
+		sign = "-"
+		buf = buf[1:]
+	case buf[0] == '+':
+		// +Inf
+		sign = "+"
+		if s.Flag(' ') {
+			sign = " "
+		}
+		buf = buf[1:]
+	case s.Flag('+'):
+		sign = "+"
+	case s.Flag(' '):
+		sign = " "
+	}
+
+	var padding int
+	if width, hasWidth := s.Width(); hasWidth && width > len(sign)+len(buf) {
+		padding = width - len(sign) - len(buf)
+	}
+
+	switch {
+	case s.Flag('0') && !x.IsInf():
+		// 0-padding on left
+		writeMultiple(s, sign, 1)
+		writeMultiple(s, "0", padding)
+		s.Write(buf)
+	case s.Flag('-'):
+		// padding on right
+		writeMultiple(s, sign, 1)
+		s.Write(buf)
+		writeMultiple(s, " ", padding)
+	default:
+		// padding on left
+		writeMultiple(s, " ", padding)
+		writeMultiple(s, sign, 1)
+		s.Write(buf)
+	}
+}
diff --git a/src/math/big/int.go b/src/math/big/int.go
index ade5c2f..65334e0 100644
--- a/src/math/big/int.go
+++ b/src/math/big/int.go
@@ -7,7 +7,6 @@
 package big
 
 import (
-	"errors"
 	"fmt"
 	"io"
 	"math/rand"
@@ -184,6 +183,10 @@ func (z *Int) MulRange(a, b int64) *Int {
 
 // 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)
@@ -321,195 +324,6 @@ func (x *Int) Cmp(y *Int) (r int) {
 	return
 }
 
-func (x *Int) String() string {
-	switch {
-	case x == nil:
-		return "<nil>"
-	case x.neg:
-		return "-" + x.abs.decimalString()
-	}
-	return x.abs.decimalString()
-}
-
-func charset(ch rune) string {
-	switch ch {
-	case 'b':
-		return lowercaseDigits[0:2]
-	case 'o':
-		return lowercaseDigits[0:8]
-	case 'd', 's', 'v':
-		return lowercaseDigits[0:10]
-	case 'x':
-		return lowercaseDigits[0:16]
-	case 'X':
-		return uppercaseDigits[0:16]
-	}
-	return "" // unknown format
-}
-
-// write count copies of text to s
-func writeMultiple(s fmt.State, text string, count int) {
-	if len(text) > 0 {
-		b := []byte(text)
-		for ; count > 0; count-- {
-			s.Write(b)
-		}
-	}
-}
-
-// Format is a support routine for fmt.Formatter. It accepts
-// the formats 'b' (binary), 'o' (octal), 'd' (decimal), 'x'
-// (lowercase hexadecimal), and 'X' (uppercase hexadecimal).
-// Also supported are the full suite of package fmt's format
-// verbs for integral types, including '+', '-', and ' '
-// for sign control, '#' for leading zero in octal and for
-// hexadecimal, a leading "0x" or "0X" for "%#x" and "%#X"
-// respectively, specification of minimum digits precision,
-// output field width, space or zero padding, and left or
-// right justification.
-//
-func (x *Int) Format(s fmt.State, ch rune) {
-	cs := charset(ch)
-
-	// special cases
-	switch {
-	case cs == "":
-		// unknown format
-		fmt.Fprintf(s, "%%!%c(big.Int=%s)", ch, x.String())
-		return
-	case x == nil:
-		fmt.Fprint(s, "<nil>")
-		return
-	}
-
-	// determine sign character
-	sign := ""
-	switch {
-	case x.neg:
-		sign = "-"
-	case s.Flag('+'): // supersedes ' ' when both specified
-		sign = "+"
-	case s.Flag(' '):
-		sign = " "
-	}
-
-	// determine prefix characters for indicating output base
-	prefix := ""
-	if s.Flag('#') {
-		switch ch {
-		case 'o': // octal
-			prefix = "0"
-		case 'x': // hexadecimal
-			prefix = "0x"
-		case 'X':
-			prefix = "0X"
-		}
-	}
-
-	// determine digits with base set by len(cs) and digit characters from cs
-	digits := x.abs.string(cs)
-
-	// number of characters for the three classes of number padding
-	var left int   // space characters to left of digits for right justification ("%8d")
-	var zeroes int // zero characters (actually cs[0]) as left-most digits ("%.8d")
-	var right int  // space characters to right of digits for left justification ("%-8d")
-
-	// determine number padding from precision: the least number of digits to output
-	precision, precisionSet := s.Precision()
-	if precisionSet {
-		switch {
-		case len(digits) < precision:
-			zeroes = precision - len(digits) // count of zero padding
-		case digits == "0" && precision == 0:
-			return // print nothing if zero value (x == 0) and zero precision ("." or ".0")
-		}
-	}
-
-	// determine field pad from width: the least number of characters to output
-	length := len(sign) + len(prefix) + zeroes + len(digits)
-	if width, widthSet := s.Width(); widthSet && length < width { // pad as specified
-		switch d := width - length; {
-		case s.Flag('-'):
-			// pad on the right with spaces; supersedes '0' when both specified
-			right = d
-		case s.Flag('0') && !precisionSet:
-			// pad with zeroes unless precision also specified
-			zeroes = d
-		default:
-			// pad on the left with spaces
-			left = d
-		}
-	}
-
-	// print number as [left pad][sign][prefix][zero pad][digits][right pad]
-	writeMultiple(s, " ", left)
-	writeMultiple(s, sign, 1)
-	writeMultiple(s, prefix, 1)
-	writeMultiple(s, "0", zeroes)
-	writeMultiple(s, digits, 1)
-	writeMultiple(s, " ", right)
-}
-
-// scan sets z to the integer value corresponding to the longest possible prefix
-// read from r representing a signed integer number in a given conversion base.
-// It returns z, the actual conversion base used, and an error, if any. In the
-// error case, the value of z is undefined but the returned value is nil. The
-// syntax follows the syntax of integer literals in Go.
-//
-// The base argument must be 0 or a value from 2 through MaxBase. If the base
-// is 0, the string prefix determines the actual conversion base. A prefix of
-// ``0x'' or ``0X'' selects base 16; the ``0'' prefix selects base 8, and a
-// ``0b'' or ``0B'' prefix selects base 2. Otherwise the selected base is 10.
-//
-func (z *Int) scan(r io.RuneScanner, base int) (*Int, int, error) {
-	// determine sign
-	ch, _, err := r.ReadRune()
-	if err != nil {
-		return nil, 0, err
-	}
-	neg := false
-	switch ch {
-	case '-':
-		neg = true
-	case '+': // nothing to do
-	default:
-		r.UnreadRune()
-	}
-
-	// determine mantissa
-	z.abs, base, err = z.abs.scan(r, base)
-	if err != nil {
-		return nil, base, err
-	}
-	z.neg = len(z.abs) > 0 && neg // 0 has no sign
-
-	return z, base, nil
-}
-
-// Scan is a support routine for fmt.Scanner; it sets z to the value of
-// the scanned number. It accepts the formats 'b' (binary), 'o' (octal),
-// 'd' (decimal), 'x' (lowercase hexadecimal), and 'X' (uppercase hexadecimal).
-func (z *Int) Scan(s fmt.ScanState, ch rune) error {
-	s.SkipSpace() // skip leading space characters
-	base := 0
-	switch ch {
-	case 'b':
-		base = 2
-	case 'o':
-		base = 8
-	case 'd':
-		base = 10
-	case 'x', 'X':
-		base = 16
-	case 's', 'v':
-		// let scan determine the base
-	default:
-		return errors.New("Int.Scan: invalid verb")
-	}
-	_, _, err := z.scan(s, base)
-	return err
-}
-
 // low32 returns the least significant 32 bits of z.
 func low32(z nat) uint32 {
 	if len(z) == 0 {
@@ -550,7 +364,7 @@ func (x *Int) Uint64() uint64 {
 // and returns z and a boolean indicating success. If SetString fails,
 // the value of z is undefined but the returned value is nil.
 //
-// The base argument must be 0 or a value from 2 through MaxBase. If the base
+// The base argument must be 0 or a value between 2 and MaxBase. If the base
 // is 0, the string prefix determines the actual conversion base. A prefix of
 // ``0x'' or ``0X'' selects base 16; the ``0'' prefix selects base 8, and a
 // ``0b'' or ``0B'' prefix selects base 2. Otherwise the selected base is 10.
@@ -561,7 +375,7 @@ func (z *Int) SetString(s string, base int) (*Int, bool) {
 	if err != nil {
 		return nil, false
 	}
-	_, _, err = r.ReadRune()
+	_, err = r.ReadByte()
 	if err != io.EOF {
 		return nil, false
 	}
@@ -686,15 +500,17 @@ func (z *Int) binaryGCD(a, b *Int) *Int {
 	// use one Euclidean iteration to ensure that u and v are approx. the same size
 	switch {
 	case len(a.abs) > len(b.abs):
-		u.Set(b)
+		// must set v before u since u may be alias for a or b (was issue #11284)
 		v.Rem(a, b)
+		u.Set(b)
 	case len(a.abs) < len(b.abs):
-		u.Set(a)
 		v.Rem(b, a)
-	default:
 		u.Set(a)
+	default:
 		v.Set(b)
+		u.Set(a)
 	}
+	// a, b must not be used anymore (may be aliases with u)
 
 	// v might be 0 now
 	if len(v.abs) == 0 {
@@ -736,8 +552,11 @@ func (z *Int) binaryGCD(a, b *Int) *Int {
 
 // ProbablyPrime performs n Miller-Rabin tests to check whether x is prime.
 // If it returns true, x is prime with probability 1 - 1/4^n.
-// If it returns false, x is not prime.
+// If it returns false, x is not prime. n must be > 0.
 func (x *Int) ProbablyPrime(n int) bool {
+	if n <= 0 {
+		panic("non-positive n for ProbablyPrime")
+	}
 	return !x.neg && x.abs.probablyPrime(n)
 }
 
@@ -766,6 +585,124 @@ func (z *Int) ModInverse(g, n *Int) *Int {
 	return z
 }
 
+// Jacobi returns the Jacobi symbol (x/y), either +1, -1, or 0.
+// The y argument must be an odd integer.
+func Jacobi(x, y *Int) int {
+	if len(y.abs) == 0 || y.abs[0]&1 == 0 {
+		panic(fmt.Sprintf("big: invalid 2nd argument to Int.Jacobi: need odd integer but got %s", y))
+	}
+
+	// We use the formulation described in chapter 2, section 2.4,
+	// "The Yacas Book of Algorithms":
+	// http://yacas.sourceforge.net/Algo.book.pdf
+
+	var a, b, c Int
+	a.Set(x)
+	b.Set(y)
+	j := 1
+
+	if b.neg {
+		if a.neg {
+			j = -1
+		}
+		b.neg = false
+	}
+
+	for {
+		if b.Cmp(intOne) == 0 {
+			return j
+		}
+		if len(a.abs) == 0 {
+			return 0
+		}
+		a.Mod(&a, &b)
+		if len(a.abs) == 0 {
+			return 0
+		}
+		// a > 0
+
+		// handle factors of 2 in 'a'
+		s := a.abs.trailingZeroBits()
+		if s&1 != 0 {
+			bmod8 := b.abs[0] & 7
+			if bmod8 == 3 || bmod8 == 5 {
+				j = -j
+			}
+		}
+		c.Rsh(&a, s) // a = 2^s*c
+
+		// swap numerator and denominator
+		if b.abs[0]&3 == 3 && c.abs[0]&3 == 3 {
+			j = -j
+		}
+		a.Set(&b)
+		b.Set(&c)
+	}
+}
+
+// ModSqrt sets z to a square root of x mod p if such a square root exists, and
+// returns z. The modulus p must be an odd prime. If x is not a square mod p,
+// ModSqrt leaves z unchanged and returns nil. This function panics if p is
+// not an odd integer.
+func (z *Int) ModSqrt(x, p *Int) *Int {
+	switch Jacobi(x, p) {
+	case -1:
+		return nil // x is not a square mod p
+	case 0:
+		return z.SetInt64(0) // sqrt(0) mod p = 0
+	case 1:
+		break
+	}
+	if x.neg || x.Cmp(p) >= 0 { // ensure 0 <= x < p
+		x = new(Int).Mod(x, p)
+	}
+
+	// Break p-1 into s*2^e such that s is odd.
+	var s Int
+	s.Sub(p, intOne)
+	e := s.abs.trailingZeroBits()
+	s.Rsh(&s, e)
+
+	// find some non-square n
+	var n Int
+	n.SetInt64(2)
+	for Jacobi(&n, p) != -1 {
+		n.Add(&n, intOne)
+	}
+
+	// Core of the Tonelli-Shanks algorithm. Follows the description in
+	// section 6 of "Square roots from 1; 24, 51, 10 to Dan Shanks" by Ezra
+	// Brown:
+	// https://www.maa.org/sites/default/files/pdf/upload_library/22/Polya/07468342.di020786.02p0470a.pdf
+	var y, b, g, t Int
+	y.Add(&s, intOne)
+	y.Rsh(&y, 1)
+	y.Exp(x, &y, p)  // y = x^((s+1)/2)
+	b.Exp(x, &s, p)  // b = x^s
+	g.Exp(&n, &s, p) // g = n^s
+	r := e
+	for {
+		// find the least m such that ord_p(b) = 2^m
+		var m uint
+		t.Set(&b)
+		for t.Cmp(intOne) != 0 {
+			t.Mul(&t, &t).Mod(&t, p)
+			m++
+		}
+
+		if m == 0 {
+			return z.Set(&y)
+		}
+
+		t.SetInt64(0).SetBit(&t, int(r-m-1), 1).Exp(&g, &t, p)
+		// t = g^(2^(r-m-1)) mod p
+		g.Mul(&t, &t).Mod(&g, p) // g = g^(2^(r-m)) mod p
+		y.Mul(&y, &t).Mod(&y, p)
+		b.Mul(&b, &g).Mod(&b, p)
+		r = m
+	}
+}
+
 // Lsh sets z = x << n and returns z.
 func (z *Int) Lsh(x *Int, n uint) *Int {
 	z.abs = z.abs.shl(x.abs, n)
@@ -995,7 +932,7 @@ func (z *Int) GobDecode(buf []byte) error {
 	}
 	b := buf[0]
 	if b>>1 != intGobVersion {
-		return errors.New(fmt.Sprintf("Int.GobDecode: encoding version %d not supported", b>>1))
+		return fmt.Errorf("Int.GobDecode: encoding version %d not supported", b>>1)
 	}
 	z.neg = b&1 != 0
 	z.abs = z.abs.setBytes(buf[1:])
diff --git a/src/math/big/int_test.go b/src/math/big/int_test.go
index 2d762db..88c8c2b 100644
--- a/src/math/big/int_test.go
+++ b/src/math/big/int_test.go
@@ -219,334 +219,42 @@ func TestMulRangeZ(t *testing.T) {
 	}
 }
 
-var stringTests = []struct {
-	in   string
-	out  string
-	base int
-	val  int64
-	ok   bool
-}{
-	{in: "", ok: false},
-	{in: "a", ok: false},
-	{in: "z", ok: false},
-	{in: "+", ok: false},
-	{in: "-", ok: false},
-	{in: "0b", ok: false},
-	{in: "0x", ok: false},
-	{in: "2", base: 2, ok: false},
-	{in: "0b2", base: 0, ok: false},
-	{in: "08", ok: false},
-	{in: "8", base: 8, ok: false},
-	{in: "0xg", base: 0, ok: false},
-	{in: "g", base: 16, ok: false},
-	{"0", "0", 0, 0, true},
-	{"0", "0", 10, 0, true},
-	{"0", "0", 16, 0, true},
-	{"+0", "0", 0, 0, true},
-	{"-0", "0", 0, 0, true},
-	{"10", "10", 0, 10, true},
-	{"10", "10", 10, 10, true},
-	{"10", "10", 16, 16, true},
-	{"-10", "-10", 16, -16, true},
-	{"+10", "10", 16, 16, true},
-	{"0x10", "16", 0, 16, true},
-	{in: "0x10", base: 16, ok: false},
-	{"-0x10", "-16", 0, -16, true},
-	{"+0x10", "16", 0, 16, true},
-	{"00", "0", 0, 0, true},
-	{"0", "0", 8, 0, true},
-	{"07", "7", 0, 7, true},
-	{"7", "7", 8, 7, true},
-	{"023", "19", 0, 19, true},
-	{"23", "23", 8, 19, true},
-	{"cafebabe", "cafebabe", 16, 0xcafebabe, true},
-	{"0b0", "0", 0, 0, true},
-	{"-111", "-111", 2, -7, true},
-	{"-0b111", "-7", 0, -7, true},
-	{"0b1001010111", "599", 0, 0x257, true},
-	{"1001010111", "1001010111", 2, 0x257, true},
-}
-
-func format(base int) string {
-	switch base {
-	case 2:
-		return "%b"
-	case 8:
-		return "%o"
-	case 16:
-		return "%x"
-	}
-	return "%d"
-}
-
-func TestGetString(t *testing.T) {
-	z := new(Int)
-	for i, test := range stringTests {
-		if !test.ok {
-			continue
-		}
-		z.SetInt64(test.val)
-
-		if test.base == 10 {
-			s := z.String()
-			if s != test.out {
-				t.Errorf("#%da got %s; want %s", i, s, test.out)
-			}
-		}
-
-		s := fmt.Sprintf(format(test.base), z)
-		if s != test.out {
-			t.Errorf("#%db got %s; want %s", i, s, test.out)
-		}
-	}
-}
-
-func TestSetString(t *testing.T) {
-	tmp := new(Int)
-	for i, test := range stringTests {
-		// initialize to a non-zero value so that issues with parsing
-		// 0 are detected
-		tmp.SetInt64(1234567890)
-		n1, ok1 := new(Int).SetString(test.in, test.base)
-		n2, ok2 := tmp.SetString(test.in, test.base)
-		expected := NewInt(test.val)
-		if ok1 != test.ok || ok2 != test.ok {
-			t.Errorf("#%d (input '%s') ok incorrect (should be %t)", i, test.in, test.ok)
-			continue
-		}
-		if !ok1 {
-			if n1 != nil {
-				t.Errorf("#%d (input '%s') n1 != nil", i, test.in)
-			}
-			continue
-		}
-		if !ok2 {
-			if n2 != nil {
-				t.Errorf("#%d (input '%s') n2 != nil", i, test.in)
-			}
-			continue
-		}
-
-		if ok1 && !isNormalized(n1) {
-			t.Errorf("#%d (input '%s'): %v is not normalized", i, test.in, *n1)
-		}
-		if ok2 && !isNormalized(n2) {
-			t.Errorf("#%d (input '%s'): %v is not normalized", i, test.in, *n2)
-		}
-
-		if n1.Cmp(expected) != 0 {
-			t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n1, test.val)
-		}
-		if n2.Cmp(expected) != 0 {
-			t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n2, test.val)
-		}
-	}
-}
-
-var formatTests = []struct {
-	input  string
-	format string
-	output string
-}{
-	{"<nil>", "%x", "<nil>"},
-	{"<nil>", "%#x", "<nil>"},
-	{"<nil>", "%#y", "%!y(big.Int=<nil>)"},
-
-	{"10", "%b", "1010"},
-	{"10", "%o", "12"},
-	{"10", "%d", "10"},
-	{"10", "%v", "10"},
-	{"10", "%x", "a"},
-	{"10", "%X", "A"},
-	{"-10", "%X", "-A"},
-	{"10", "%y", "%!y(big.Int=10)"},
-	{"-10", "%y", "%!y(big.Int=-10)"},
-
-	{"10", "%#b", "1010"},
-	{"10", "%#o", "012"},
-	{"10", "%#d", "10"},
-	{"10", "%#v", "10"},
-	{"10", "%#x", "0xa"},
-	{"10", "%#X", "0XA"},
-	{"-10", "%#X", "-0XA"},
-	{"10", "%#y", "%!y(big.Int=10)"},
-	{"-10", "%#y", "%!y(big.Int=-10)"},
-
-	{"1234", "%d", "1234"},
-	{"1234", "%3d", "1234"},
-	{"1234", "%4d", "1234"},
-	{"-1234", "%d", "-1234"},
-	{"1234", "% 5d", " 1234"},
-	{"1234", "%+5d", "+1234"},
-	{"1234", "%-5d", "1234 "},
-	{"1234", "%x", "4d2"},
-	{"1234", "%X", "4D2"},
-	{"-1234", "%3x", "-4d2"},
-	{"-1234", "%4x", "-4d2"},
-	{"-1234", "%5x", " -4d2"},
-	{"-1234", "%-5x", "-4d2 "},
-	{"1234", "%03d", "1234"},
-	{"1234", "%04d", "1234"},
-	{"1234", "%05d", "01234"},
-	{"1234", "%06d", "001234"},
-	{"-1234", "%06d", "-01234"},
-	{"1234", "%+06d", "+01234"},
-	{"1234", "% 06d", " 01234"},
-	{"1234", "%-6d", "1234  "},
-	{"1234", "%-06d", "1234  "},
-	{"-1234", "%-06d", "-1234 "},
-
-	{"1234", "%.3d", "1234"},
-	{"1234", "%.4d", "1234"},
-	{"1234", "%.5d", "01234"},
-	{"1234", "%.6d", "001234"},
-	{"-1234", "%.3d", "-1234"},
-	{"-1234", "%.4d", "-1234"},
-	{"-1234", "%.5d", "-01234"},
-	{"-1234", "%.6d", "-001234"},
-
-	{"1234", "%8.3d", "    1234"},
-	{"1234", "%8.4d", "    1234"},
-	{"1234", "%8.5d", "   01234"},
-	{"1234", "%8.6d", "  001234"},
-	{"-1234", "%8.3d", "   -1234"},
-	{"-1234", "%8.4d", "   -1234"},
-	{"-1234", "%8.5d", "  -01234"},
-	{"-1234", "%8.6d", " -001234"},
-
-	{"1234", "%+8.3d", "   +1234"},
-	{"1234", "%+8.4d", "   +1234"},
-	{"1234", "%+8.5d", "  +01234"},
-	{"1234", "%+8.6d", " +001234"},
-	{"-1234", "%+8.3d", "   -1234"},
-	{"-1234", "%+8.4d", "   -1234"},
-	{"-1234", "%+8.5d", "  -01234"},
-	{"-1234", "%+8.6d", " -001234"},
-
-	{"1234", "% 8.3d", "    1234"},
-	{"1234", "% 8.4d", "    1234"},
-	{"1234", "% 8.5d", "   01234"},
-	{"1234", "% 8.6d", "  001234"},
-	{"-1234", "% 8.3d", "   -1234"},
-	{"-1234", "% 8.4d", "   -1234"},
-	{"-1234", "% 8.5d", "  -01234"},
-	{"-1234", "% 8.6d", " -001234"},
-
-	{"1234", "%.3x", "4d2"},
-	{"1234", "%.4x", "04d2"},
-	{"1234", "%.5x", "004d2"},
-	{"1234", "%.6x", "0004d2"},
-	{"-1234", "%.3x", "-4d2"},
-	{"-1234", "%.4x", "-04d2"},
-	{"-1234", "%.5x", "-004d2"},
-	{"-1234", "%.6x", "-0004d2"},
-
-	{"1234", "%8.3x", "     4d2"},
-	{"1234", "%8.4x", "    04d2"},
-	{"1234", "%8.5x", "   004d2"},
-	{"1234", "%8.6x", "  0004d2"},
-	{"-1234", "%8.3x", "    -4d2"},
-	{"-1234", "%8.4x", "   -04d2"},
-	{"-1234", "%8.5x", "  -004d2"},
-	{"-1234", "%8.6x", " -0004d2"},
-
-	{"1234", "%+8.3x", "    +4d2"},
-	{"1234", "%+8.4x", "   +04d2"},
-	{"1234", "%+8.5x", "  +004d2"},
-	{"1234", "%+8.6x", " +0004d2"},
-	{"-1234", "%+8.3x", "    -4d2"},
-	{"-1234", "%+8.4x", "   -04d2"},
-	{"-1234", "%+8.5x", "  -004d2"},
-	{"-1234", "%+8.6x", " -0004d2"},
-
-	{"1234", "% 8.3x", "     4d2"},
-	{"1234", "% 8.4x", "    04d2"},
-	{"1234", "% 8.5x", "   004d2"},
-	{"1234", "% 8.6x", "  0004d2"},
-	{"1234", "% 8.7x", " 00004d2"},
-	{"1234", "% 8.8x", " 000004d2"},
-	{"-1234", "% 8.3x", "    -4d2"},
-	{"-1234", "% 8.4x", "   -04d2"},
-	{"-1234", "% 8.5x", "  -004d2"},
-	{"-1234", "% 8.6x", " -0004d2"},
-	{"-1234", "% 8.7x", "-00004d2"},
-	{"-1234", "% 8.8x", "-000004d2"},
-
-	{"1234", "%-8.3d", "1234    "},
-	{"1234", "%-8.4d", "1234    "},
-	{"1234", "%-8.5d", "01234   "},
-	{"1234", "%-8.6d", "001234  "},
-	{"1234", "%-8.7d", "0001234 "},
-	{"1234", "%-8.8d", "00001234"},
-	{"-1234", "%-8.3d", "-1234   "},
-	{"-1234", "%-8.4d", "-1234   "},
-	{"-1234", "%-8.5d", "-01234  "},
-	{"-1234", "%-8.6d", "-001234 "},
-	{"-1234", "%-8.7d", "-0001234"},
-	{"-1234", "%-8.8d", "-00001234"},
-
-	{"16777215", "%b", "111111111111111111111111"}, // 2**24 - 1
-
-	{"0", "%.d", ""},
-	{"0", "%.0d", ""},
-	{"0", "%3.d", ""},
-}
-
-func TestFormat(t *testing.T) {
-	for i, test := range formatTests {
-		var x *Int
-		if test.input != "<nil>" {
-			var ok bool
-			x, ok = new(Int).SetString(test.input, 0)
-			if !ok {
-				t.Errorf("#%d failed reading input %s", i, test.input)
-			}
-		}
-		output := fmt.Sprintf(test.format, x)
-		if output != test.output {
-			t.Errorf("#%d got %q; want %q, {%q, %q, %q}", i, output, test.output, test.input, test.format, test.output)
-		}
-	}
-}
-
-var scanTests = []struct {
-	input     string
-	format    string
-	output    string
-	remaining int
-}{
-	{"1010", "%b", "10", 0},
-	{"0b1010", "%v", "10", 0},
-	{"12", "%o", "10", 0},
-	{"012", "%v", "10", 0},
-	{"10", "%d", "10", 0},
-	{"10", "%v", "10", 0},
-	{"a", "%x", "10", 0},
-	{"0xa", "%v", "10", 0},
-	{"A", "%X", "10", 0},
-	{"-A", "%X", "-10", 0},
-	{"+0b1011001", "%v", "89", 0},
-	{"0xA", "%v", "10", 0},
-	{"0 ", "%v", "0", 1},
-	{"2+3", "%v", "2", 2},
-	{"0XABC 12", "%v", "2748", 3},
-}
-
-func TestScan(t *testing.T) {
-	var buf bytes.Buffer
-	for i, test := range scanTests {
-		x := new(Int)
-		buf.Reset()
-		buf.WriteString(test.input)
-		if _, err := fmt.Fscanf(&buf, test.format, x); err != nil {
-			t.Errorf("#%d error: %s", i, err)
-		}
-		if x.String() != test.output {
-			t.Errorf("#%d got %s; want %s", i, x.String(), test.output)
-		}
-		if buf.Len() != test.remaining {
-			t.Errorf("#%d got %d bytes remaining; want %d", i, buf.Len(), test.remaining)
-		}
+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)
 	}
 }
 
@@ -621,6 +329,42 @@ func TestDivisionSigns(t *testing.T) {
 	}
 }
 
+func norm(x nat) nat {
+	i := len(x)
+	for i > 0 && x[i-1] == 0 {
+		i--
+	}
+	return x[:i]
+}
+
+func TestBits(t *testing.T) {
+	for _, test := range []nat{
+		nil,
+		{0},
+		{1},
+		{0, 1, 2, 3, 4},
+		{4, 3, 2, 1, 0},
+		{4, 3, 2, 1, 0, 0, 0, 0},
+	} {
+		var z Int
+		z.neg = true
+		got := z.SetBits(test)
+		want := norm(test)
+		if got.abs.cmp(want) != 0 {
+			t.Errorf("SetBits(%v) = %v; want %v", test, got.abs, want)
+		}
+
+		if got.neg {
+			t.Errorf("SetBits(%v): got negative result", test)
+		}
+
+		bits := nat(z.Bits())
+		if bits.cmp(want) != 0 {
+			t.Errorf("%v.Bits() = %v; want %v", z.abs, bits, want)
+		}
+	}
+}
+
 func checkSetBytes(b []byte) bool {
 	hex1 := hex.EncodeToString(new(Int).SetBytes(b).Bytes())
 	hex2 := hex.EncodeToString(b)
@@ -648,7 +392,7 @@ func checkBytes(b []byte) bool {
 }
 
 func TestBytes(t *testing.T) {
-	if err := quick.Check(checkSetBytes, nil); err != nil {
+	if err := quick.Check(checkBytes, nil); err != nil {
 		t.Error(err)
 	}
 }
@@ -781,6 +525,7 @@ var expTests = []struct {
 	{"1234", "-1", "1", "0"},
 
 	// misc
+	{"5", "1", "3", "2"},
 	{"5", "-7", "", "1"},
 	{"-5", "-7", "", "1"},
 	{"5", "0", "", "1"},
@@ -917,6 +662,21 @@ func testGcd(t *testing.T, d, x, y, a, b *Int) {
 	if D.Cmp(d) != 0 {
 		t.Errorf("binaryGcd(%s, %s): got d = %s, want %s", a, b, D, d)
 	}
+
+	// check results in presence of aliasing (issue #11284)
+	a2 := new(Int).Set(a)
+	b2 := new(Int).Set(b)
+	a2.binaryGCD(a2, b2) // result is same as 1st argument
+	if a2.Cmp(d) != 0 {
+		t.Errorf("binaryGcd(%s, %s): got d = %s, want %s", a, b, a2, d)
+	}
+
+	a2 = new(Int).Set(a)
+	b2 = new(Int).Set(b)
+	b2.binaryGCD(a2, b2) // result is same as 2nd argument
+	if b2.Cmp(d) != 0 {
+		t.Errorf("binaryGcd(%s, %s): got d = %s, want %s", a, b, b2, d)
+	}
 }
 
 func TestGcd(t *testing.T) {
@@ -948,7 +708,7 @@ var primes = []string{
 	"10953742525620032441",
 	"17908251027575790097",
 
-	// http://code.google.com/p/go/issues/detail?id=638
+	// https://golang.org/issue/638
 	"18699199384836356663",
 
 	"98920366548084643601728869055592650835572950932266967461790948584315647051443",
@@ -959,9 +719,18 @@ var primes = []string{
 	"230975859993204150666423538988557839555560243929065415434980904258310530753006723857139742334640122533598517597674807096648905501653461687601339782814316124971547968912893214002992086353183070342498989426570593",
 	"5521712099665906221540423207019333379125265462121169655563495403888449493493629943498064604536961775110765377745550377067893607246020694972959780839151452457728855382113555867743022746090187341871655890805971735385789993",
 	"203956878356401977405765866929034577280193993314348263094772646453283062722701277632936616063144088173312372882677123879538709400158306567338328279154499698366071906766440037074217117805690872792848149112022286332144876183376326512083574821647933992961249917319836219304274280243803104015000563790123",
+
+	// ECC primes: http://tools.ietf.org/html/draft-ladd-safecurves-02
+	"3618502788666131106986593281521497120414687020801267626233049500247285301239",                                                                                  // Curve1174: 2^251-9
+	"57896044618658097711785492504343953926634992332820282019728792003956564819949",                                                                                 // Curve25519: 2^255-19
+	"9850501549098619803069760025035903451269934817616361666987073351061430442874302652853566563721228910201656997576599",                                           // E-382: 2^382-105
+	"42307582002575910332922579714097346549017899709713998034217522897561970639123926132812109468141778230245837569601494931472367",                                 // Curve41417: 2^414-17
+	"6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151", // E-521: 2^521-1
 }
 
 var composites = []string{
+	"0",
+	"1",
 	"21284175091214687912771199898307297748211672914763848041968395774954376176754",
 	"6084766654921918907427900243509372380954290099172559290432744450051395395951",
 	"84594350493221918389213352992032324280367711247940675652888030554255915464401",
@@ -989,6 +758,21 @@ func TestProbablyPrime(t *testing.T) {
 			break
 		}
 	}
+
+	// check that ProbablyPrime panics if n <= 0
+	c := NewInt(11) // a prime
+	for _, n := range []int{-1, 0, 1} {
+		func() {
+			defer func() {
+				if n <= 0 && recover() == nil {
+					t.Fatalf("expected panic from ProbablyPrime(%d)", n)
+				}
+			}()
+			if !c.ProbablyPrime(n) {
+				t.Fatalf("%v should be a prime", c)
+			}
+		}()
+	}
 }
 
 type intShiftTest struct {
@@ -1487,6 +1271,136 @@ func TestModInverse(t *testing.T) {
 	}
 }
 
+// testModSqrt is a helper for TestModSqrt,
+// which checks that ModSqrt can compute a square-root of elt^2.
+func testModSqrt(t *testing.T, elt, mod, sq, sqrt *Int) bool {
+	var sqChk, sqrtChk, sqrtsq Int
+	sq.Mul(elt, elt)
+	sq.Mod(sq, mod)
+	z := sqrt.ModSqrt(sq, mod)
+	if z != sqrt {
+		t.Errorf("ModSqrt returned wrong value %s", z)
+	}
+
+	// test ModSqrt arguments outside the range [0,mod)
+	sqChk.Add(sq, mod)
+	z = sqrtChk.ModSqrt(&sqChk, mod)
+	if z != &sqrtChk || z.Cmp(sqrt) != 0 {
+		t.Errorf("ModSqrt returned inconsistent value %s", z)
+	}
+	sqChk.Sub(sq, mod)
+	z = sqrtChk.ModSqrt(&sqChk, mod)
+	if z != &sqrtChk || z.Cmp(sqrt) != 0 {
+		t.Errorf("ModSqrt returned inconsistent value %s", z)
+	}
+
+	// make sure we actually got a square root
+	if sqrt.Cmp(elt) == 0 {
+		return true // we found the "desired" square root
+	}
+	sqrtsq.Mul(sqrt, sqrt) // make sure we found the "other" one
+	sqrtsq.Mod(&sqrtsq, mod)
+	return sq.Cmp(&sqrtsq) == 0
+}
+
+func TestModSqrt(t *testing.T) {
+	var elt, mod, modx4, sq, sqrt Int
+	r := rand.New(rand.NewSource(9))
+	for i, s := range primes[1:] { // skip 2, use only odd primes
+		mod.SetString(s, 10)
+		modx4.Lsh(&mod, 2)
+
+		// test a few random elements per prime
+		for x := 1; x < 5; x++ {
+			elt.Rand(r, &modx4)
+			elt.Sub(&elt, &mod) // test range [-mod, 3*mod)
+			if !testModSqrt(t, &elt, &mod, &sq, &sqrt) {
+				t.Errorf("#%d: failed (sqrt(e) = %s)", i, &sqrt)
+			}
+		}
+	}
+
+	// exhaustive test for small values
+	for n := 3; n < 100; n++ {
+		mod.SetInt64(int64(n))
+		if !mod.ProbablyPrime(10) {
+			continue
+		}
+		isSquare := make([]bool, n)
+
+		// test all the squares
+		for x := 1; x < n; x++ {
+			elt.SetInt64(int64(x))
+			if !testModSqrt(t, &elt, &mod, &sq, &sqrt) {
+				t.Errorf("#%d: failed (sqrt(%d,%d) = %s)", x, &elt, &mod, &sqrt)
+			}
+			isSquare[sq.Uint64()] = true
+		}
+
+		// test all non-squares
+		for x := 1; x < n; x++ {
+			sq.SetInt64(int64(x))
+			z := sqrt.ModSqrt(&sq, &mod)
+			if !isSquare[x] && z != nil {
+				t.Errorf("#%d: failed (sqrt(%d,%d) = nil)", x, &sqrt, &mod)
+			}
+		}
+	}
+}
+
+func TestJacobi(t *testing.T) {
+	testCases := []struct {
+		x, y   int64
+		result int
+	}{
+		{0, 1, 1},
+		{0, -1, 1},
+		{1, 1, 1},
+		{1, -1, 1},
+		{0, 5, 0},
+		{1, 5, 1},
+		{2, 5, -1},
+		{-2, 5, -1},
+		{2, -5, -1},
+		{-2, -5, 1},
+		{3, 5, -1},
+		{5, 5, 0},
+		{-5, 5, 0},
+		{6, 5, 1},
+		{6, -5, 1},
+		{-6, 5, 1},
+		{-6, -5, -1},
+	}
+
+	var x, y Int
+
+	for i, test := range testCases {
+		x.SetInt64(test.x)
+		y.SetInt64(test.y)
+		expected := test.result
+		actual := Jacobi(&x, &y)
+		if actual != expected {
+			t.Errorf("#%d: Jacobi(%d, %d) = %d, but expected %d", i, test.x, test.y, actual, expected)
+		}
+	}
+}
+
+func TestJacobiPanic(t *testing.T) {
+	const failureMsg = "test failure"
+	defer func() {
+		msg := recover()
+		if msg == nil || msg == failureMsg {
+			panic(msg)
+		}
+		t.Log(msg)
+	}()
+	x := NewInt(1)
+	y := NewInt(2)
+	// Jacobi should panic when the second argument is even.
+	Jacobi(x, y)
+	panic(failureMsg)
+}
+
 var encodingTests = []string{
 	"-539345864568634858364538753846587364875430589374589",
 	"-678645873",
diff --git a/src/math/big/intconv.go b/src/math/big/intconv.go
new file mode 100644
index 0000000..9c68a22
--- /dev/null
+++ b/src/math/big/intconv.go
@@ -0,0 +1,228 @@
+// 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 int-to-string conversion functions.
+
+package big
+
+import (
+	"errors"
+	"fmt"
+	"io"
+)
+
+func (x *Int) String() string {
+	switch {
+	case x == nil:
+		return "<nil>"
+	case x.neg:
+		return "-" + x.abs.decimalString()
+	}
+	return x.abs.decimalString()
+}
+
+func charset(ch rune) string {
+	switch ch {
+	case 'b':
+		return lowercaseDigits[0:2]
+	case 'o':
+		return lowercaseDigits[0:8]
+	case 'd', 's', 'v':
+		return lowercaseDigits[0:10]
+	case 'x':
+		return lowercaseDigits[0:16]
+	case 'X':
+		return uppercaseDigits[0:16]
+	}
+	return "" // unknown format
+}
+
+// write count copies of text to s
+func writeMultiple(s fmt.State, text string, count int) {
+	if len(text) > 0 {
+		b := []byte(text)
+		for ; count > 0; count-- {
+			s.Write(b)
+		}
+	}
+}
+
+// Format is a support routine for fmt.Formatter. It accepts
+// the formats 'b' (binary), 'o' (octal), 'd' (decimal), 'x'
+// (lowercase hexadecimal), and 'X' (uppercase hexadecimal).
+// Also supported are the full suite of package fmt's format
+// verbs for integral types, including '+', '-', and ' '
+// for sign control, '#' for leading zero in octal and for
+// hexadecimal, a leading "0x" or "0X" for "%#x" and "%#X"
+// respectively, specification of minimum digits precision,
+// output field width, space or zero padding, and left or
+// right justification.
+//
+func (x *Int) Format(s fmt.State, ch rune) {
+	cs := charset(ch)
+
+	// special cases
+	switch {
+	case cs == "":
+		// unknown format
+		fmt.Fprintf(s, "%%!%c(big.Int=%s)", ch, x.String())
+		return
+	case x == nil:
+		fmt.Fprint(s, "<nil>")
+		return
+	}
+
+	// determine sign character
+	sign := ""
+	switch {
+	case x.neg:
+		sign = "-"
+	case s.Flag('+'): // supersedes ' ' when both specified
+		sign = "+"
+	case s.Flag(' '):
+		sign = " "
+	}
+
+	// determine prefix characters for indicating output base
+	prefix := ""
+	if s.Flag('#') {
+		switch ch {
+		case 'o': // octal
+			prefix = "0"
+		case 'x': // hexadecimal
+			prefix = "0x"
+		case 'X':
+			prefix = "0X"
+		}
+	}
+
+	// determine digits with base set by len(cs) and digit characters from cs
+	digits := x.abs.string(cs)
+
+	// number of characters for the three classes of number padding
+	var left int   // space characters to left of digits for right justification ("%8d")
+	var zeroes int // zero characters (actually cs[0]) as left-most digits ("%.8d")
+	var right int  // space characters to right of digits for left justification ("%-8d")
+
+	// determine number padding from precision: the least number of digits to output
+	precision, precisionSet := s.Precision()
+	if precisionSet {
+		switch {
+		case len(digits) < precision:
+			zeroes = precision - len(digits) // count of zero padding
+		case digits == "0" && precision == 0:
+			return // print nothing if zero value (x == 0) and zero precision ("." or ".0")
+		}
+	}
+
+	// determine field pad from width: the least number of characters to output
+	length := len(sign) + len(prefix) + zeroes + len(digits)
+	if width, widthSet := s.Width(); widthSet && length < width { // pad as specified
+		switch d := width - length; {
+		case s.Flag('-'):
+			// pad on the right with spaces; supersedes '0' when both specified
+			right = d
+		case s.Flag('0') && !precisionSet:
+			// pad with zeroes unless precision also specified
+			zeroes = d
+		default:
+			// pad on the left with spaces
+			left = d
+		}
+	}
+
+	// print number as [left pad][sign][prefix][zero pad][digits][right pad]
+	writeMultiple(s, " ", left)
+	writeMultiple(s, sign, 1)
+	writeMultiple(s, prefix, 1)
+	writeMultiple(s, "0", zeroes)
+	writeMultiple(s, digits, 1)
+	writeMultiple(s, " ", right)
+}
+
+// scan sets z to the integer value corresponding to the longest possible prefix
+// read from r representing a signed integer number in a given conversion base.
+// It returns z, the actual conversion base used, and an error, if any. In the
+// error case, the value of z is undefined but the returned value is nil. The
+// syntax follows the syntax of integer literals in Go.
+//
+// The base argument must be 0 or a value from 2 through MaxBase. If the base
+// is 0, the string prefix determines the actual conversion base. A prefix of
+// ``0x'' or ``0X'' selects base 16; the ``0'' prefix selects base 8, and a
+// ``0b'' or ``0B'' prefix selects base 2. Otherwise the selected base is 10.
+//
+func (z *Int) scan(r io.ByteScanner, base int) (*Int, int, error) {
+	// determine sign
+	neg, err := scanSign(r)
+	if err != nil {
+		return nil, 0, err
+	}
+
+	// determine mantissa
+	z.abs, base, _, err = z.abs.scan(r, base, false)
+	if err != nil {
+		return nil, base, err
+	}
+	z.neg = len(z.abs) > 0 && neg // 0 has no sign
+
+	return z, base, nil
+}
+
+func scanSign(r io.ByteScanner) (neg bool, err error) {
+	var ch byte
+	if ch, err = r.ReadByte(); err != nil {
+		return false, err
+	}
+	switch ch {
+	case '-':
+		neg = true
+	case '+':
+		// nothing to do
+	default:
+		r.UnreadByte()
+	}
+	return
+}
+
+// byteReader is a local wrapper around fmt.ScanState;
+// it implements the ByteReader interface.
+type byteReader struct {
+	fmt.ScanState
+}
+
+func (r byteReader) ReadByte() (byte, error) {
+	ch, size, err := r.ReadRune()
+	if size != 1 && err == nil {
+		err = fmt.Errorf("invalid rune %#U", ch)
+	}
+	return byte(ch), err
+}
+
+func (r byteReader) UnreadByte() error {
+	return r.UnreadRune()
+}
+
+// Scan is a support routine for fmt.Scanner; it sets z to the value of
+// the scanned number. It accepts the formats 'b' (binary), 'o' (octal),
+// 'd' (decimal), 'x' (lowercase hexadecimal), and 'X' (uppercase hexadecimal).
+func (z *Int) Scan(s fmt.ScanState, ch rune) error {
+	s.SkipSpace() // skip leading space characters
+	base := 0
+	switch ch {
+	case 'b':
+		base = 2
+	case 'o':
+		base = 8
+	case 'd':
+		base = 10
+	case 'x', 'X':
+		base = 16
+	case 's', 'v':
+		// let scan determine the base
+	default:
+		return errors.New("Int.Scan: invalid verb")
+	}
+	_, _, err := z.scan(byteReader{s}, base)
+	return err
+}
diff --git a/src/math/big/intconv_test.go b/src/math/big/intconv_test.go
new file mode 100644
index 0000000..2deb84b
--- /dev/null
+++ b/src/math/big/intconv_test.go
@@ -0,0 +1,342 @@
+// 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
+
+import (
+	"bytes"
+	"fmt"
+	"testing"
+)
+
+var stringTests = []struct {
+	in   string
+	out  string
+	base int
+	val  int64
+	ok   bool
+}{
+	{in: "", ok: false},
+	{in: "a", ok: false},
+	{in: "z", ok: false},
+	{in: "+", ok: false},
+	{in: "-", ok: false},
+	{in: "0b", ok: false},
+	{in: "0x", ok: false},
+	{in: "2", base: 2, ok: false},
+	{in: "0b2", base: 0, ok: false},
+	{in: "08", ok: false},
+	{in: "8", base: 8, ok: false},
+	{in: "0xg", base: 0, ok: false},
+	{in: "g", base: 16, ok: false},
+	{"0", "0", 0, 0, true},
+	{"0", "0", 10, 0, true},
+	{"0", "0", 16, 0, true},
+	{"+0", "0", 0, 0, true},
+	{"-0", "0", 0, 0, true},
+	{"10", "10", 0, 10, true},
+	{"10", "10", 10, 10, true},
+	{"10", "10", 16, 16, true},
+	{"-10", "-10", 16, -16, true},
+	{"+10", "10", 16, 16, true},
+	{"0x10", "16", 0, 16, true},
+	{in: "0x10", base: 16, ok: false},
+	{"-0x10", "-16", 0, -16, true},
+	{"+0x10", "16", 0, 16, true},
+	{"00", "0", 0, 0, true},
+	{"0", "0", 8, 0, true},
+	{"07", "7", 0, 7, true},
+	{"7", "7", 8, 7, true},
+	{"023", "19", 0, 19, true},
+	{"23", "23", 8, 19, true},
+	{"cafebabe", "cafebabe", 16, 0xcafebabe, true},
+	{"0b0", "0", 0, 0, true},
+	{"-111", "-111", 2, -7, true},
+	{"-0b111", "-7", 0, -7, true},
+	{"0b1001010111", "599", 0, 0x257, true},
+	{"1001010111", "1001010111", 2, 0x257, true},
+}
+
+func format(base int) string {
+	switch base {
+	case 2:
+		return "%b"
+	case 8:
+		return "%o"
+	case 16:
+		return "%x"
+	}
+	return "%d"
+}
+
+func TestGetString(t *testing.T) {
+	z := new(Int)
+	for i, test := range stringTests {
+		if !test.ok {
+			continue
+		}
+		z.SetInt64(test.val)
+
+		if test.base == 10 {
+			s := z.String()
+			if s != test.out {
+				t.Errorf("#%da got %s; want %s", i, s, test.out)
+			}
+		}
+
+		s := fmt.Sprintf(format(test.base), z)
+		if s != test.out {
+			t.Errorf("#%db got %s; want %s", i, s, test.out)
+		}
+	}
+}
+
+func TestSetString(t *testing.T) {
+	tmp := new(Int)
+	for i, test := range stringTests {
+		// initialize to a non-zero value so that issues with parsing
+		// 0 are detected
+		tmp.SetInt64(1234567890)
+		n1, ok1 := new(Int).SetString(test.in, test.base)
+		n2, ok2 := tmp.SetString(test.in, test.base)
+		expected := NewInt(test.val)
+		if ok1 != test.ok || ok2 != test.ok {
+			t.Errorf("#%d (input '%s') ok incorrect (should be %t)", i, test.in, test.ok)
+			continue
+		}
+		if !ok1 {
+			if n1 != nil {
+				t.Errorf("#%d (input '%s') n1 != nil", i, test.in)
+			}
+			continue
+		}
+		if !ok2 {
+			if n2 != nil {
+				t.Errorf("#%d (input '%s') n2 != nil", i, test.in)
+			}
+			continue
+		}
+
+		if ok1 && !isNormalized(n1) {
+			t.Errorf("#%d (input '%s'): %v is not normalized", i, test.in, *n1)
+		}
+		if ok2 && !isNormalized(n2) {
+			t.Errorf("#%d (input '%s'): %v is not normalized", i, test.in, *n2)
+		}
+
+		if n1.Cmp(expected) != 0 {
+			t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n1, test.val)
+		}
+		if n2.Cmp(expected) != 0 {
+			t.Errorf("#%d (input '%s') got: %s want: %d", i, test.in, n2, test.val)
+		}
+	}
+}
+
+var formatTests = []struct {
+	input  string
+	format string
+	output string
+}{
+	{"<nil>", "%x", "<nil>"},
+	{"<nil>", "%#x", "<nil>"},
+	{"<nil>", "%#y", "%!y(big.Int=<nil>)"},
+
+	{"10", "%b", "1010"},
+	{"10", "%o", "12"},
+	{"10", "%d", "10"},
+	{"10", "%v", "10"},
+	{"10", "%x", "a"},
+	{"10", "%X", "A"},
+	{"-10", "%X", "-A"},
+	{"10", "%y", "%!y(big.Int=10)"},
+	{"-10", "%y", "%!y(big.Int=-10)"},
+
+	{"10", "%#b", "1010"},
+	{"10", "%#o", "012"},
+	{"10", "%#d", "10"},
+	{"10", "%#v", "10"},
+	{"10", "%#x", "0xa"},
+	{"10", "%#X", "0XA"},
+	{"-10", "%#X", "-0XA"},
+	{"10", "%#y", "%!y(big.Int=10)"},
+	{"-10", "%#y", "%!y(big.Int=-10)"},
+
+	{"1234", "%d", "1234"},
+	{"1234", "%3d", "1234"},
+	{"1234", "%4d", "1234"},
+	{"-1234", "%d", "-1234"},
+	{"1234", "% 5d", " 1234"},
+	{"1234", "%+5d", "+1234"},
+	{"1234", "%-5d", "1234 "},
+	{"1234", "%x", "4d2"},
+	{"1234", "%X", "4D2"},
+	{"-1234", "%3x", "-4d2"},
+	{"-1234", "%4x", "-4d2"},
+	{"-1234", "%5x", " -4d2"},
+	{"-1234", "%-5x", "-4d2 "},
+	{"1234", "%03d", "1234"},
+	{"1234", "%04d", "1234"},
+	{"1234", "%05d", "01234"},
+	{"1234", "%06d", "001234"},
+	{"-1234", "%06d", "-01234"},
+	{"1234", "%+06d", "+01234"},
+	{"1234", "% 06d", " 01234"},
+	{"1234", "%-6d", "1234  "},
+	{"1234", "%-06d", "1234  "},
+	{"-1234", "%-06d", "-1234 "},
+
+	{"1234", "%.3d", "1234"},
+	{"1234", "%.4d", "1234"},
+	{"1234", "%.5d", "01234"},
+	{"1234", "%.6d", "001234"},
+	{"-1234", "%.3d", "-1234"},
+	{"-1234", "%.4d", "-1234"},
+	{"-1234", "%.5d", "-01234"},
+	{"-1234", "%.6d", "-001234"},
+
+	{"1234", "%8.3d", "    1234"},
+	{"1234", "%8.4d", "    1234"},
+	{"1234", "%8.5d", "   01234"},
+	{"1234", "%8.6d", "  001234"},
+	{"-1234", "%8.3d", "   -1234"},
+	{"-1234", "%8.4d", "   -1234"},
+	{"-1234", "%8.5d", "  -01234"},
+	{"-1234", "%8.6d", " -001234"},
+
+	{"1234", "%+8.3d", "   +1234"},
+	{"1234", "%+8.4d", "   +1234"},
+	{"1234", "%+8.5d", "  +01234"},
+	{"1234", "%+8.6d", " +001234"},
+	{"-1234", "%+8.3d", "   -1234"},
+	{"-1234", "%+8.4d", "   -1234"},
+	{"-1234", "%+8.5d", "  -01234"},
+	{"-1234", "%+8.6d", " -001234"},
+
+	{"1234", "% 8.3d", "    1234"},
+	{"1234", "% 8.4d", "    1234"},
+	{"1234", "% 8.5d", "   01234"},
+	{"1234", "% 8.6d", "  001234"},
+	{"-1234", "% 8.3d", "   -1234"},
+	{"-1234", "% 8.4d", "   -1234"},
+	{"-1234", "% 8.5d", "  -01234"},
+	{"-1234", "% 8.6d", " -001234"},
+
+	{"1234", "%.3x", "4d2"},
+	{"1234", "%.4x", "04d2"},
+	{"1234", "%.5x", "004d2"},
+	{"1234", "%.6x", "0004d2"},
+	{"-1234", "%.3x", "-4d2"},
+	{"-1234", "%.4x", "-04d2"},
+	{"-1234", "%.5x", "-004d2"},
+	{"-1234", "%.6x", "-0004d2"},
+
+	{"1234", "%8.3x", "     4d2"},
+	{"1234", "%8.4x", "    04d2"},
+	{"1234", "%8.5x", "   004d2"},
+	{"1234", "%8.6x", "  0004d2"},
+	{"-1234", "%8.3x", "    -4d2"},
+	{"-1234", "%8.4x", "   -04d2"},
+	{"-1234", "%8.5x", "  -004d2"},
+	{"-1234", "%8.6x", " -0004d2"},
+
+	{"1234", "%+8.3x", "    +4d2"},
+	{"1234", "%+8.4x", "   +04d2"},
+	{"1234", "%+8.5x", "  +004d2"},
+	{"1234", "%+8.6x", " +0004d2"},
+	{"-1234", "%+8.3x", "    -4d2"},
+	{"-1234", "%+8.4x", "   -04d2"},
+	{"-1234", "%+8.5x", "  -004d2"},
+	{"-1234", "%+8.6x", " -0004d2"},
+
+	{"1234", "% 8.3x", "     4d2"},
+	{"1234", "% 8.4x", "    04d2"},
+	{"1234", "% 8.5x", "   004d2"},
+	{"1234", "% 8.6x", "  0004d2"},
+	{"1234", "% 8.7x", " 00004d2"},
+	{"1234", "% 8.8x", " 000004d2"},
+	{"-1234", "% 8.3x", "    -4d2"},
+	{"-1234", "% 8.4x", "   -04d2"},
+	{"-1234", "% 8.5x", "  -004d2"},
+	{"-1234", "% 8.6x", " -0004d2"},
+	{"-1234", "% 8.7x", "-00004d2"},
+	{"-1234", "% 8.8x", "-000004d2"},
+
+	{"1234", "%-8.3d", "1234    "},
+	{"1234", "%-8.4d", "1234    "},
+	{"1234", "%-8.5d", "01234   "},
+	{"1234", "%-8.6d", "001234  "},
+	{"1234", "%-8.7d", "0001234 "},
+	{"1234", "%-8.8d", "00001234"},
+	{"-1234", "%-8.3d", "-1234   "},
+	{"-1234", "%-8.4d", "-1234   "},
+	{"-1234", "%-8.5d", "-01234  "},
+	{"-1234", "%-8.6d", "-001234 "},
+	{"-1234", "%-8.7d", "-0001234"},
+	{"-1234", "%-8.8d", "-00001234"},
+
+	{"16777215", "%b", "111111111111111111111111"}, // 2**24 - 1
+
+	{"0", "%.d", ""},
+	{"0", "%.0d", ""},
+	{"0", "%3.d", ""},
+}
+
+func TestFormat(t *testing.T) {
+	for i, test := range formatTests {
+		var x *Int
+		if test.input != "<nil>" {
+			var ok bool
+			x, ok = new(Int).SetString(test.input, 0)
+			if !ok {
+				t.Errorf("#%d failed reading input %s", i, test.input)
+			}
+		}
+		output := fmt.Sprintf(test.format, x)
+		if output != test.output {
+			t.Errorf("#%d got %q; want %q, {%q, %q, %q}", i, output, test.output, test.input, test.format, test.output)
+		}
+	}
+}
+
+var scanTests = []struct {
+	input     string
+	format    string
+	output    string
+	remaining int
+}{
+	{"1010", "%b", "10", 0},
+	{"0b1010", "%v", "10", 0},
+	{"12", "%o", "10", 0},
+	{"012", "%v", "10", 0},
+	{"10", "%d", "10", 0},
+	{"10", "%v", "10", 0},
+	{"a", "%x", "10", 0},
+	{"0xa", "%v", "10", 0},
+	{"A", "%X", "10", 0},
+	{"-A", "%X", "-10", 0},
+	{"+0b1011001", "%v", "89", 0},
+	{"0xA", "%v", "10", 0},
+	{"0 ", "%v", "0", 1},
+	{"2+3", "%v", "2", 2},
+	{"0XABC 12", "%v", "2748", 3},
+}
+
+func TestScan(t *testing.T) {
+	var buf bytes.Buffer
+	for i, test := range scanTests {
+		x := new(Int)
+		buf.Reset()
+		buf.WriteString(test.input)
+		if _, err := fmt.Fscanf(&buf, test.format, x); err != nil {
+			t.Errorf("#%d error: %s", i, err)
+		}
+		if x.String() != test.output {
+			t.Errorf("#%d got %s; want %s", i, x.String(), test.output)
+		}
+		if buf.Len() != test.remaining {
+			t.Errorf("#%d got %d bytes remaining; want %d", i, buf.Len(), test.remaining)
+		}
+	}
+}
diff --git a/src/math/big/nat.go b/src/math/big/nat.go
index 16a87f5..6545bc1 100644
--- a/src/math/big/nat.go
+++ b/src/math/big/nat.go
@@ -5,18 +5,22 @@
 // Package big implements multi-precision arithmetic (big numbers).
 // The following numeric types are supported:
 //
-//	- Int	signed integers
-//	- Rat	rational numbers
+//   Int    signed integers
+//   Rat    rational numbers
+//   Float  floating-point numbers
 //
 // Methods are typically of the form:
 //
-//	func (z *Int) Op(x, y *Int) *Int	(similar for *Rat)
+//   func (z *T) Unary(x *T) *T        // z = op x
+//   func (z *T) Binary(x, y *T) *T    // z = x op y
+//   func (x *T) M() T1                // v = x.M()
 //
-// and implement operations z = x Op y with the result as receiver; if it
-// is one of the operands it may be overwritten (and its memory reused).
+// with T one of Int, Rat, or Float. For unary and binary operations, the
+// result is the receiver (usually named z in that case); if it is one of
+// the operands x or y it may be overwritten (and its memory reused).
 // To enable chaining of operations, the result is also returned. Methods
-// returning a result other than *Int or *Rat take one of the operands as
-// the receiver.
+// returning a result other than *Int, *Rat, or *Float take an operand as
+// the receiver (usually named x in that case).
 //
 package big
 
@@ -24,13 +28,7 @@ package big
 // These are the building blocks for the operations on signed integers
 // and rationals.
 
-import (
-	"errors"
-	"io"
-	"math"
-	"math/rand"
-	"sync"
-)
+import "math/rand"
 
 // An unsigned integer x of the form
 //
@@ -68,7 +66,7 @@ func (z nat) norm() nat {
 
 func (z nat) make(n int) nat {
 	if n <= cap(z) {
-		return z[0:n] // reuse z
+		return z[:n] // reuse z
 	}
 	// Choosing a good value for e has significant performance impact
 	// because it increases the chance that a value can be reused.
@@ -78,7 +76,7 @@ func (z nat) make(n int) nat {
 
 func (z nat) setWord(x Word) nat {
 	if x == 0 {
-		return z.make(0)
+		return z[:0]
 	}
 	z = z.make(1)
 	z[0] = x
@@ -122,7 +120,7 @@ func (z nat) add(x, y nat) nat {
 		return z.add(y, x)
 	case m == 0:
 		// n == 0 because m >= n; result is 0
-		return z.make(0)
+		return z[:0]
 	case n == 0:
 		// result is x
 		return z.set(x)
@@ -148,7 +146,7 @@ func (z nat) sub(x, y nat) nat {
 		panic("underflow")
 	case m == 0:
 		// n == 0 because m >= n; result is 0
-		return z.make(0)
+		return z[:0]
 	case n == 0:
 		// result is x
 		return z.set(x)
@@ -218,6 +216,34 @@ func basicMul(z, x, y nat) {
 	}
 }
 
+// montgomery computes x*y*2^(-n*_W) mod m,
+// assuming k = -1/m mod 2^_W.
+// z is used for storing the result which is returned;
+// z must not alias x, y or m.
+func (z nat) montgomery(x, y, m nat, k Word, n int) nat {
+	var c1, c2 Word
+	z = z.make(n)
+	z.clear()
+	for i := 0; i < n; i++ {
+		d := y[i]
+		c1 += addMulVVW(z, x, d)
+		t := z[0] * k
+		c2 = addMulVVW(z, m, t)
+
+		copy(z, z[1:])
+		z[n-1] = c1 + c2
+		if z[n-1] < c1 {
+			c1 = 1
+		} else {
+			c1 = 0
+		}
+	}
+	if c1 != 0 {
+		subVV(z, z, m)
+	}
+	return z
+}
+
 // Fast version of z[0:n+n>>1].add(z[0:n+n>>1], x[0:n]) w/o bounds checks.
 // Factored out for readability - do not use outside karatsuba.
 func karatsubaAdd(z, x nat, n int) {
@@ -337,7 +363,7 @@ func karatsuba(z, x, y nat) {
 	}
 }
 
-// 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]
 }
@@ -384,7 +410,7 @@ func (z nat) mul(x, y nat) nat {
 	case m < n:
 		return z.mul(y, x)
 	case m == 0 || n == 0:
-		return z.make(0)
+		return z[:0]
 	case n == 1:
 		return z.mulAddWW(x, y[0], 0)
 	}
@@ -488,7 +514,7 @@ func (z nat) divW(x nat, y Word) (q nat, r Word) {
 		q = z.set(x) // result is x
 		return
 	case m == 0:
-		q = z.make(0) // result is 0
+		q = z[:0] // result is 0
 		return
 	}
 	// m > 0
@@ -504,7 +530,7 @@ func (z nat) div(z2, u, v nat) (q, r nat) {
 	}
 
 	if u.cmp(v) < 0 {
-		q = z.make(0)
+		q = z[:0]
 		r = z2.set(u)
 		return
 	}
@@ -543,10 +569,10 @@ func (z nat) divLarge(u, uIn, v nat) (q, r nat) {
 		u = nil // u is an alias for uIn or v - cannot reuse
 	}
 	u = u.make(len(uIn) + 1)
-	u.clear()
+	u.clear() // TODO(gri) no need to clear if we allocated a new u
 
 	// D1.
-	shift := leadingZeros(v[n-1])
+	shift := nlz(v[n-1])
 	if shift > 0 {
 		// do not modify v, it may be used by another goroutine simultaneously
 		v1 := make(nat, n)
@@ -606,385 +632,6 @@ func (x nat) bitLen() int {
 	return 0
 }
 
-// MaxBase is the largest number base accepted for string conversions.
-const MaxBase = 'z' - 'a' + 10 + 1 // = hexValue('z') + 1
-
-func hexValue(ch rune) Word {
-	d := int(MaxBase + 1) // illegal base
-	switch {
-	case '0' <= ch && ch <= '9':
-		d = int(ch - '0')
-	case 'a' <= ch && ch <= 'z':
-		d = int(ch - 'a' + 10)
-	case 'A' <= ch && ch <= 'Z':
-		d = int(ch - 'A' + 10)
-	}
-	return Word(d)
-}
-
-// scan sets z to the natural number corresponding to the longest possible prefix
-// read from r representing an unsigned integer in a given conversion base.
-// It returns z, the actual conversion base used, and an error, if any. In the
-// error case, the value of z is undefined. The syntax follows the syntax of
-// unsigned integer literals in Go.
-//
-// The base argument must be 0 or a value from 2 through MaxBase. If the base
-// is 0, the string prefix determines the actual conversion base. A prefix of
-// ``0x'' or ``0X'' selects base 16; the ``0'' prefix selects base 8, and a
-// ``0b'' or ``0B'' prefix selects base 2. Otherwise the selected base is 10.
-//
-func (z nat) scan(r io.RuneScanner, base int) (nat, int, error) {
-	// reject illegal bases
-	if base < 0 || base == 1 || MaxBase < base {
-		return z, 0, errors.New("illegal number base")
-	}
-
-	// one char look-ahead
-	ch, _, err := r.ReadRune()
-	if err != nil {
-		return z, 0, err
-	}
-
-	// determine base if necessary
-	b := Word(base)
-	if base == 0 {
-		b = 10
-		if ch == '0' {
-			switch ch, _, err = r.ReadRune(); err {
-			case nil:
-				b = 8
-				switch ch {
-				case 'x', 'X':
-					b = 16
-				case 'b', 'B':
-					b = 2
-				}
-				if b == 2 || b == 16 {
-					if ch, _, err = r.ReadRune(); err != nil {
-						return z, 0, err
-					}
-				}
-			case io.EOF:
-				return z.make(0), 10, nil
-			default:
-				return z, 10, err
-			}
-		}
-	}
-
-	// convert string
-	// - group as many digits d as possible together into a "super-digit" dd with "super-base" bb
-	// - only when bb does not fit into a word anymore, do a full number mulAddWW using bb and dd
-	z = z.make(0)
-	bb := Word(1)
-	dd := Word(0)
-	for max := _M / b; ; {
-		d := hexValue(ch)
-		if d >= b {
-			r.UnreadRune() // ch does not belong to number anymore
-			break
-		}
-
-		if bb <= max {
-			bb *= b
-			dd = dd*b + d
-		} else {
-			// bb * b would overflow
-			z = z.mulAddWW(z, bb, dd)
-			bb = b
-			dd = d
-		}
-
-		if ch, _, err = r.ReadRune(); err != nil {
-			if err != io.EOF {
-				return z, int(b), err
-			}
-			break
-		}
-	}
-
-	switch {
-	case bb > 1:
-		// there was at least one mantissa digit
-		z = z.mulAddWW(z, bb, dd)
-	case base == 0 && b == 8:
-		// there was only the octal prefix 0 (possibly followed by digits > 7);
-		// return base 10, not 8
-		return z, 10, nil
-	case base != 0 || b != 8:
-		// there was neither a mantissa digit nor the octal prefix 0
-		return z, int(b), errors.New("syntax error scanning number")
-	}
-
-	return z.norm(), int(b), nil
-}
-
-// Character sets for string conversion.
-const (
-	lowercaseDigits = "0123456789abcdefghijklmnopqrstuvwxyz"
-	uppercaseDigits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-)
-
-// decimalString returns a decimal representation of x.
-// It calls x.string with the charset "0123456789".
-func (x nat) decimalString() string {
-	return x.string(lowercaseDigits[0:10])
-}
-
-// string converts x to a string using digits from a charset; a digit with
-// value d is represented by charset[d]. The conversion base is determined
-// by len(charset), which must be >= 2 and <= 256.
-func (x nat) string(charset string) string {
-	b := Word(len(charset))
-
-	// special cases
-	switch {
-	case b < 2 || MaxBase > 256:
-		panic("illegal base")
-	case len(x) == 0:
-		return string(charset[0])
-	}
-
-	// allocate buffer for conversion
-	i := int(float64(x.bitLen())/math.Log2(float64(b))) + 1 // off by one at most
-	s := make([]byte, i)
-
-	// convert power of two and non power of two bases separately
-	if b == b&-b {
-		// shift is base-b digit size in bits
-		shift := trailingZeroBits(b) // shift > 0 because b >= 2
-		mask := Word(1)<<shift - 1
-		w := x[0]
-		nbits := uint(_W) // number of unprocessed bits in w
-
-		// convert less-significant words
-		for k := 1; k < len(x); k++ {
-			// convert full digits
-			for nbits >= shift {
-				i--
-				s[i] = charset[w&mask]
-				w >>= shift
-				nbits -= shift
-			}
-
-			// convert any partial leading digit and advance to next word
-			if nbits == 0 {
-				// no partial digit remaining, just advance
-				w = x[k]
-				nbits = _W
-			} else {
-				// partial digit in current (k-1) and next (k) word
-				w |= x[k] << nbits
-				i--
-				s[i] = charset[w&mask]
-
-				// advance
-				w = x[k] >> (shift - nbits)
-				nbits = _W - (shift - nbits)
-			}
-		}
-
-		// convert digits of most-significant word (omit leading zeros)
-		for nbits >= 0 && w != 0 {
-			i--
-			s[i] = charset[w&mask]
-			w >>= shift
-			nbits -= shift
-		}
-
-	} else {
-		// determine "big base"; i.e., the largest possible value bb
-		// that is a power of base b and still fits into a Word
-		// (as in 10^19 for 19 decimal digits in a 64bit Word)
-		bb := b      // big base is b**ndigits
-		ndigits := 1 // number of base b digits
-		for max := Word(_M / b); bb <= max; bb *= b {
-			ndigits++ // maximize ndigits where bb = b**ndigits, bb <= _M
-		}
-
-		// construct table of successive squares of bb*leafSize to use in subdivisions
-		// result (table != nil) <=> (len(x) > leafSize > 0)
-		table := divisors(len(x), b, ndigits, bb)
-
-		// preserve x, create local copy for use by convertWords
-		q := nat(nil).set(x)
-
-		// convert q to string s in base b
-		q.convertWords(s, charset, b, ndigits, bb, table)
-
-		// strip leading zeros
-		// (x != 0; thus s must contain at least one non-zero digit
-		// and the loop will terminate)
-		i = 0
-		for zero := charset[0]; s[i] == zero; {
-			i++
-		}
-	}
-
-	return string(s[i:])
-}
-
-// Convert words of q to base b digits in s. If q is large, it is recursively "split in half"
-// by nat/nat division using tabulated divisors. Otherwise, it is converted iteratively using
-// repeated nat/Word division.
-//
-// The iterative method processes n Words by n divW() calls, each of which visits every Word in the
-// incrementally shortened q for a total of n + (n-1) + (n-2) ... + 2 + 1, or n(n+1)/2 divW()'s.
-// Recursive conversion divides q by its approximate square root, yielding two parts, each half
-// the size of q. Using the iterative method on both halves means 2 * (n/2)(n/2 + 1)/2 divW()'s
-// plus the expensive long div(). Asymptotically, the ratio is favorable at 1/2 the divW()'s, and
-// is made better by splitting the subblocks recursively. Best is to split blocks until one more
-// split would take longer (because of the nat/nat div()) than the twice as many divW()'s of the
-// iterative approach. This threshold is represented by leafSize. Benchmarking of leafSize in the
-// range 2..64 shows that values of 8 and 16 work well, with a 4x speedup at medium lengths and
-// ~30x for 20000 digits. Use nat_test.go's BenchmarkLeafSize tests to optimize leafSize for
-// specific hardware.
-//
-func (q nat) convertWords(s []byte, charset string, b Word, ndigits int, bb Word, table []divisor) {
-	// split larger blocks recursively
-	if table != nil {
-		// len(q) > leafSize > 0
-		var r nat
-		index := len(table) - 1
-		for len(q) > leafSize {
-			// find divisor close to sqrt(q) if possible, but in any case < q
-			maxLength := q.bitLen()     // ~= log2 q, or at of least largest possible q of this bit length
-			minLength := maxLength >> 1 // ~= log2 sqrt(q)
-			for index > 0 && table[index-1].nbits > minLength {
-				index-- // desired
-			}
-			if table[index].nbits >= maxLength && table[index].bbb.cmp(q) >= 0 {
-				index--
-				if index < 0 {
-					panic("internal inconsistency")
-				}
-			}
-
-			// split q into the two digit number (q'*bbb + r) to form independent subblocks
-			q, r = q.div(r, q, table[index].bbb)
-
-			// convert subblocks and collect results in s[:h] and s[h:]
-			h := len(s) - table[index].ndigits
-			r.convertWords(s[h:], charset, b, ndigits, bb, table[0:index])
-			s = s[:h] // == q.convertWords(s, charset, b, ndigits, bb, table[0:index+1])
-		}
-	}
-
-	// having split any large blocks now process the remaining (small) block iteratively
-	i := len(s)
-	var r Word
-	if b == 10 {
-		// hard-coding for 10 here speeds this up by 1.25x (allows for / and % by constants)
-		for len(q) > 0 {
-			// extract least significant, base bb "digit"
-			q, r = q.divW(q, bb)
-			for j := 0; j < ndigits && i > 0; j++ {
-				i--
-				// avoid % computation since r%10 == r - int(r/10)*10;
-				// this appears to be faster for BenchmarkString10000Base10
-				// and smaller strings (but a bit slower for larger ones)
-				t := r / 10
-				s[i] = charset[r-t<<3-t-t] // TODO(gri) replace w/ t*10 once compiler produces better code
-				r = t
-			}
-		}
-	} else {
-		for len(q) > 0 {
-			// extract least significant, base bb "digit"
-			q, r = q.divW(q, bb)
-			for j := 0; j < ndigits && i > 0; j++ {
-				i--
-				s[i] = charset[r%b]
-				r /= b
-			}
-		}
-	}
-
-	// prepend high-order zeroes
-	zero := charset[0]
-	for i > 0 { // while need more leading zeroes
-		i--
-		s[i] = zero
-	}
-}
-
-// Split blocks greater than leafSize Words (or set to 0 to disable recursive conversion)
-// Benchmark and configure leafSize using: go test -bench="Leaf"
-//   8 and 16 effective on 3.0 GHz Xeon "Clovertown" CPU (128 byte cache lines)
-//   8 and 16 effective on 2.66 GHz Core 2 Duo "Penryn" CPU
-var leafSize int = 8 // number of Word-size binary values treat as a monolithic block
-
-type divisor struct {
-	bbb     nat // divisor
-	nbits   int // bit length of divisor (discounting leading zeroes) ~= log2(bbb)
-	ndigits int // digit length of divisor in terms of output base digits
-}
-
-var cacheBase10 struct {
-	sync.Mutex
-	table [64]divisor // cached divisors for base 10
-}
-
-// expWW computes x**y
-func (z nat) expWW(x, y Word) nat {
-	return z.expNN(nat(nil).setWord(x), nat(nil).setWord(y), nil)
-}
-
-// construct table of powers of bb*leafSize to use in subdivisions
-func divisors(m int, b Word, ndigits int, bb Word) []divisor {
-	// only compute table when recursive conversion is enabled and x is large
-	if leafSize == 0 || m <= leafSize {
-		return nil
-	}
-
-	// determine k where (bb**leafSize)**(2**k) >= sqrt(x)
-	k := 1
-	for words := leafSize; words < m>>1 && k < len(cacheBase10.table); words <<= 1 {
-		k++
-	}
-
-	// reuse and extend existing table of divisors or create new table as appropriate
-	var table []divisor // for b == 10, table overlaps with cacheBase10.table
-	if b == 10 {
-		cacheBase10.Lock()
-		table = cacheBase10.table[0:k] // reuse old table for this conversion
-	} else {
-		table = make([]divisor, k) // create new table for this conversion
-	}
-
-	// extend table
-	if table[k-1].ndigits == 0 {
-		// add new entries as needed
-		var larger nat
-		for i := 0; i < k; i++ {
-			if table[i].ndigits == 0 {
-				if i == 0 {
-					table[0].bbb = nat(nil).expWW(bb, Word(leafSize))
-					table[0].ndigits = ndigits * leafSize
-				} else {
-					table[i].bbb = nat(nil).mul(table[i-1].bbb, table[i-1].bbb)
-					table[i].ndigits = 2 * table[i-1].ndigits
-				}
-
-				// optimization: exploit aggregated extra bits in macro blocks
-				larger = nat(nil).set(table[i].bbb)
-				for mulAddVWW(larger, larger, b, 0) == 0 {
-					table[i].bbb = table[i].bbb.set(larger)
-					table[i].ndigits++
-				}
-
-				table[i].nbits = table[i].bbb.bitLen()
-			}
-		}
-	}
-
-	if b == 10 {
-		cacheBase10.Unlock()
-	}
-
-	return table
-}
-
 const deBruijn32 = 0x077CB531
 
 var deBruijn32Lookup = []byte{
@@ -1041,7 +688,7 @@ func (x nat) trailingZeroBits() uint {
 func (z nat) shl(x nat, s uint) nat {
 	m := len(x)
 	if m == 0 {
-		return z.make(0)
+		return z[:0]
 	}
 	// m > 0
 
@@ -1058,7 +705,7 @@ func (z nat) shr(x nat, s uint) nat {
 	m := len(x)
 	n := m - int(s/_W)
 	if n <= 0 {
-		return z.make(0)
+		return z[:0]
 	}
 	// n > 0
 
@@ -1097,12 +744,36 @@ func (z nat) setBit(x nat, i uint, b uint) nat {
 	panic("set bit is not 0 or 1")
 }
 
-func (z nat) bit(i uint) uint {
-	j := int(i / _W)
-	if j >= len(z) {
+// bit returns the value of the i'th bit, with lsb == bit 0.
+func (x nat) bit(i uint) uint {
+	j := i / _W
+	if j >= uint(len(x)) {
 		return 0
 	}
-	return uint(z[j] >> (i % _W) & 1)
+	// 0 <= j < len(x)
+	return uint(x[j] >> (i % _W) & 1)
+}
+
+// sticky returns 1 if there's a 1 bit within the
+// i least significant bits, otherwise it returns 0.
+func (x nat) sticky(i uint) uint {
+	j := i / _W
+	if j >= uint(len(x)) {
+		if len(x) == 0 {
+			return 0
+		}
+		return 1
+	}
+	// 0 <= j < len(x)
+	for _, x := range x[:j] {
+		if x != 0 {
+			return 1
+		}
+	}
+	if x[j]<<(_W-i%_W) != 0 {
+		return 1
+	}
+	return 0
 }
 
 func (z nat) and(x, y nat) nat {
@@ -1176,7 +847,7 @@ func (z nat) xor(x, y nat) nat {
 	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
 }
@@ -1245,6 +916,13 @@ func (z nat) expNN(x, y, m nat) nat {
 	}
 	// y > 0
 
+	// x**1 mod m == x mod m
+	if len(y) == 1 && y[0] == 1 && len(m) != 0 {
+		_, z = z.div(z, x, m)
+		return z
+	}
+	// y > 1
+
 	if len(m) != 0 {
 		// We likely end up being as long as the modulus.
 		z = z.make(len(m))
@@ -1255,13 +933,16 @@ func (z nat) expNN(x, y, m nat) nat {
 	// 4-bit, windowed exponentiation. This involves precomputing 14 values
 	// (x^2...x^15) but then reduces the number of multiply-reduces by a
 	// third. Even for a 32-bit exponent, this reduces the number of
-	// operations.
+	// operations. Uses Montgomery method for odd moduli.
 	if len(x) > 1 && len(y) > 1 && len(m) > 0 {
+		if m[0]&1 == 1 {
+			return z.expNNMontgomery(x, y, m)
+		}
 		return z.expNNWindowed(x, y, m)
 	}
 
 	v := y[len(y)-1] // v > 0 because y is normalized and y > 0
-	shift := leadingZeros(v) + 1
+	shift := nlz(v) + 1
 	v <<= shift
 	var q nat
 
@@ -1379,6 +1060,87 @@ func (z nat) expNNWindowed(x, y, m nat) nat {
 	return z.norm()
 }
 
+// expNNMontgomery calculates x**y mod m using a fixed, 4-bit window.
+// Uses Montgomery representation.
+func (z nat) expNNMontgomery(x, y, m nat) nat {
+	var zz, one, rr, RR nat
+
+	numWords := len(m)
+
+	// We want the lengths of x and m to be equal.
+	if len(x) > numWords {
+		_, rr = rr.div(rr, x, m)
+	} else if len(x) < numWords {
+		rr = rr.make(numWords)
+		rr.clear()
+		for i := range x {
+			rr[i] = x[i]
+		}
+	} else {
+		rr = x
+	}
+	x = rr
+
+	// Ideally the precomputations would be performed outside, and reused
+	// k0 = -mˆ-1 mod 2ˆ_W. Algorithm from: Dumas, J.G. "On Newton–Raphson
+	// Iteration for Multiplicative Inverses Modulo Prime Powers".
+	k0 := 2 - m[0]
+	t := m[0] - 1
+	for i := 1; i < _W; i <<= 1 {
+		t *= t
+		k0 *= (t + 1)
+	}
+	k0 = -k0
+
+	// RR = 2ˆ(2*_W*len(m)) mod m
+	RR = RR.setWord(1)
+	zz = zz.shl(RR, uint(2*numWords*_W))
+	_, RR = RR.div(RR, zz, m)
+	if len(RR) < numWords {
+		zz = zz.make(numWords)
+		copy(zz, RR)
+		RR = zz
+	}
+	// one = 1, with equal length to that of m
+	one = one.make(numWords)
+	one.clear()
+	one[0] = 1
+
+	const n = 4
+	// powers[i] contains x^i
+	var powers [1 << n]nat
+	powers[0] = powers[0].montgomery(one, RR, m, k0, numWords)
+	powers[1] = powers[1].montgomery(x, RR, m, k0, numWords)
+	for i := 2; i < 1<<n; i++ {
+		powers[i] = powers[i].montgomery(powers[i-1], powers[1], m, k0, numWords)
+	}
+
+	// initialize z = 1 (Montgomery 1)
+	z = z.make(numWords)
+	copy(z, powers[0])
+
+	zz = zz.make(numWords)
+
+	// same windowed exponent, but with Montgomery multiplications
+	for i := len(y) - 1; i >= 0; i-- {
+		yi := y[i]
+		for j := 0; j < _W; j += n {
+			if i != len(y)-1 || j != 0 {
+				zz = zz.montgomery(z, z, m, k0, numWords)
+				z = z.montgomery(zz, zz, m, k0, numWords)
+				zz = zz.montgomery(z, z, m, k0, numWords)
+				z = z.montgomery(zz, zz, m, k0, numWords)
+			}
+			zz = zz.montgomery(z, powers[yi>>(_W-n)], m, k0, numWords)
+			z, zz = zz, z
+			yi <<= n
+		}
+	}
+	// convert to regular number
+	zz = zz.montgomery(z, one, m, k0, numWords)
+	return zz.norm()
+}
+
 // probablyPrime performs reps Miller-Rabin tests to check whether n is prime.
 // If it returns true, n is prime with probability 1 - 1/4^reps.
 // If it returns false, n is not prime.
@@ -1404,6 +1166,10 @@ func (n nat) probablyPrime(reps int) bool {
 		}
 	}
 
+	if n[0]&1 == 0 {
+		return false // n is even
+	}
+
 	const primesProduct32 = 0xC0CFD797         // Π {p ∈ primes, 2 < p <= 29}
 	const primesProduct64 = 0xE221F97C30E94E1D // Π {p ∈ primes, 2 < p <= 53}
 
diff --git a/src/math/big/nat_test.go b/src/math/big/nat_test.go
index a2ae533..7ac3cb8 100644
--- a/src/math/big/nat_test.go
+++ b/src/math/big/nat_test.go
@@ -5,7 +5,6 @@
 package big
 
 import (
-	"io"
 	"runtime"
 	"strings"
 	"testing"
@@ -88,7 +87,7 @@ var prodNN = []argNN{
 }
 
 func natFromString(s string) nat {
-	x, _, err := nat(nil).scan(strings.NewReader(s), 0)
+	x, _, _, err := nat(nil).scan(strings.NewReader(s), 0, false)
 	if err != nil {
 		panic(err)
 	}
@@ -206,398 +205,11 @@ func BenchmarkMul(b *testing.B) {
 	}
 }
 
-func toString(x nat, charset string) string {
-	base := len(charset)
-
-	// special cases
-	switch {
-	case base < 2:
-		panic("illegal base")
-	case len(x) == 0:
-		return string(charset[0])
-	}
-
-	// allocate buffer for conversion
-	i := x.bitLen()/log2(Word(base)) + 1 // +1: round up
-	s := make([]byte, i)
-
-	// don't destroy x
-	q := nat(nil).set(x)
-
-	// convert
-	for len(q) > 0 {
-		i--
-		var r Word
-		q, r = q.divW(q, Word(base))
-		s[i] = charset[r]
-	}
-
-	return string(s[i:])
-}
-
-var strTests = []struct {
-	x nat    // nat value to be converted
-	c string // conversion charset
-	s string // expected result
-}{
-	{nil, "01", "0"},
-	{nat{1}, "01", "1"},
-	{nat{0xc5}, "01", "11000101"},
-	{nat{03271}, lowercaseDigits[0:8], "3271"},
-	{nat{10}, lowercaseDigits[0:10], "10"},
-	{nat{1234567890}, uppercaseDigits[0:10], "1234567890"},
-	{nat{0xdeadbeef}, lowercaseDigits[0:16], "deadbeef"},
-	{nat{0xdeadbeef}, uppercaseDigits[0:16], "DEADBEEF"},
-	{nat{0x229be7}, lowercaseDigits[0:17], "1a2b3c"},
-	{nat{0x309663e6}, uppercaseDigits[0:32], "O9COV6"},
-}
-
-func TestString(t *testing.T) {
-	for _, a := range strTests {
-		s := a.x.string(a.c)
-		if s != a.s {
-			t.Errorf("string%+v\n\tgot s = %s; want %s", a, s, a.s)
-		}
-
-		x, b, err := nat(nil).scan(strings.NewReader(a.s), len(a.c))
-		if x.cmp(a.x) != 0 {
-			t.Errorf("scan%+v\n\tgot z = %v; want %v", a, x, a.x)
-		}
-		if b != len(a.c) {
-			t.Errorf("scan%+v\n\tgot b = %d; want %d", a, b, len(a.c))
-		}
-		if err != nil {
-			t.Errorf("scan%+v\n\tgot error = %s", a, err)
-		}
-	}
-}
-
-var natScanTests = []struct {
-	s    string // string to be scanned
-	base int    // input base
-	x    nat    // expected nat
-	b    int    // expected base
-	ok   bool   // expected success
-	next rune   // next character (or 0, if at EOF)
-}{
-	// error: illegal base
-	{base: -1},
-	{base: 1},
-	{base: 37},
-
-	// error: no mantissa
-	{},
-	{s: "?"},
-	{base: 10},
-	{base: 36},
-	{s: "?", base: 10},
-	{s: "0x"},
-	{s: "345", base: 2},
-
-	// no errors
-	{"0", 0, nil, 10, true, 0},
-	{"0", 10, nil, 10, true, 0},
-	{"0", 36, nil, 36, true, 0},
-	{"1", 0, nat{1}, 10, true, 0},
-	{"1", 10, nat{1}, 10, true, 0},
-	{"0 ", 0, nil, 10, true, ' '},
-	{"08", 0, nil, 10, true, '8'},
-	{"018", 0, nat{1}, 8, true, '8'},
-	{"0b1", 0, nat{1}, 2, true, 0},
-	{"0b11000101", 0, nat{0xc5}, 2, true, 0},
-	{"03271", 0, nat{03271}, 8, true, 0},
-	{"10ab", 0, nat{10}, 10, true, 'a'},
-	{"1234567890", 0, nat{1234567890}, 10, true, 0},
-	{"xyz", 36, nat{(33*36+34)*36 + 35}, 36, true, 0},
-	{"xyz?", 36, nat{(33*36+34)*36 + 35}, 36, true, '?'},
-	{"0x", 16, nil, 16, true, 'x'},
-	{"0xdeadbeef", 0, nat{0xdeadbeef}, 16, true, 0},
-	{"0XDEADBEEF", 0, nat{0xdeadbeef}, 16, true, 0},
-}
-
-func TestScanBase(t *testing.T) {
-	for _, a := range natScanTests {
-		r := strings.NewReader(a.s)
-		x, b, err := nat(nil).scan(r, a.base)
-		if err == nil && !a.ok {
-			t.Errorf("scan%+v\n\texpected error", a)
-		}
-		if err != nil {
-			if a.ok {
-				t.Errorf("scan%+v\n\tgot error = %s", a, err)
-			}
-			continue
-		}
-		if x.cmp(a.x) != 0 {
-			t.Errorf("scan%+v\n\tgot z = %v; want %v", a, x, a.x)
-		}
-		if b != a.b {
-			t.Errorf("scan%+v\n\tgot b = %d; want %d", a, b, a.base)
-		}
-		next, _, err := r.ReadRune()
-		if err == io.EOF {
-			next = 0
-			err = nil
-		}
-		if err == nil && next != a.next {
-			t.Errorf("scan%+v\n\tgot next = %q; want %q", a, next, a.next)
-		}
-	}
-}
-
-var pi = "3" +
-	"14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651" +
-	"32823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461" +
-	"28475648233786783165271201909145648566923460348610454326648213393607260249141273724587006606315588174881520920" +
-	"96282925409171536436789259036001133053054882046652138414695194151160943305727036575959195309218611738193261179" +
-	"31051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798" +
-	"60943702770539217176293176752384674818467669405132000568127145263560827785771342757789609173637178721468440901" +
-	"22495343014654958537105079227968925892354201995611212902196086403441815981362977477130996051870721134999999837" +
-	"29780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083" +
-	"81420617177669147303598253490428755468731159562863882353787593751957781857780532171226806613001927876611195909" +
-	"21642019893809525720106548586327886593615338182796823030195203530185296899577362259941389124972177528347913151" +
-	"55748572424541506959508295331168617278558890750983817546374649393192550604009277016711390098488240128583616035" +
-	"63707660104710181942955596198946767837449448255379774726847104047534646208046684259069491293313677028989152104" +
-	"75216205696602405803815019351125338243003558764024749647326391419927260426992279678235478163600934172164121992" +
-	"45863150302861829745557067498385054945885869269956909272107975093029553211653449872027559602364806654991198818" +
-	"34797753566369807426542527862551818417574672890977772793800081647060016145249192173217214772350141441973568548" +
-	"16136115735255213347574184946843852332390739414333454776241686251898356948556209921922218427255025425688767179" +
-	"04946016534668049886272327917860857843838279679766814541009538837863609506800642251252051173929848960841284886" +
-	"26945604241965285022210661186306744278622039194945047123713786960956364371917287467764657573962413890865832645" +
-	"99581339047802759009946576407895126946839835259570982582262052248940772671947826848260147699090264013639443745" +
-	"53050682034962524517493996514314298091906592509372216964615157098583874105978859597729754989301617539284681382" +
-	"68683868942774155991855925245953959431049972524680845987273644695848653836736222626099124608051243884390451244" +
-	"13654976278079771569143599770012961608944169486855584840635342207222582848864815845602850601684273945226746767" +
-	"88952521385225499546667278239864565961163548862305774564980355936345681743241125150760694794510965960940252288" +
-	"79710893145669136867228748940560101503308617928680920874760917824938589009714909675985261365549781893129784821" +
-	"68299894872265880485756401427047755513237964145152374623436454285844479526586782105114135473573952311342716610" +
-	"21359695362314429524849371871101457654035902799344037420073105785390621983874478084784896833214457138687519435" +
-	"06430218453191048481005370614680674919278191197939952061419663428754440643745123718192179998391015919561814675" +
-	"14269123974894090718649423196156794520809514655022523160388193014209376213785595663893778708303906979207734672" +
-	"21825625996615014215030680384477345492026054146659252014974428507325186660021324340881907104863317346496514539" +
-	"05796268561005508106658796998163574736384052571459102897064140110971206280439039759515677157700420337869936007" +
-	"23055876317635942187312514712053292819182618612586732157919841484882916447060957527069572209175671167229109816" +
-	"90915280173506712748583222871835209353965725121083579151369882091444210067510334671103141267111369908658516398" +
-	"31501970165151168517143765761835155650884909989859982387345528331635507647918535893226185489632132933089857064" +
-	"20467525907091548141654985946163718027098199430992448895757128289059232332609729971208443357326548938239119325" +
-	"97463667305836041428138830320382490375898524374417029132765618093773444030707469211201913020330380197621101100" +
-	"44929321516084244485963766983895228684783123552658213144957685726243344189303968642624341077322697802807318915" +
-	"44110104468232527162010526522721116603966655730925471105578537634668206531098965269186205647693125705863566201" +
-	"85581007293606598764861179104533488503461136576867532494416680396265797877185560845529654126654085306143444318" +
-	"58676975145661406800700237877659134401712749470420562230538994561314071127000407854733269939081454664645880797" +
-	"27082668306343285878569830523580893306575740679545716377525420211495576158140025012622859413021647155097925923" +
-	"09907965473761255176567513575178296664547791745011299614890304639947132962107340437518957359614589019389713111" +
-	"79042978285647503203198691514028708085990480109412147221317947647772622414254854540332157185306142288137585043" +
-	"06332175182979866223717215916077166925474873898665494945011465406284336639379003976926567214638530673609657120" +
-	"91807638327166416274888800786925602902284721040317211860820419000422966171196377921337575114959501566049631862" +
-	"94726547364252308177036751590673502350728354056704038674351362222477158915049530984448933309634087807693259939" +
-	"78054193414473774418426312986080998886874132604721569516239658645730216315981931951673538129741677294786724229" +
-	"24654366800980676928238280689964004824354037014163149658979409243237896907069779422362508221688957383798623001" +
-	"59377647165122893578601588161755782973523344604281512627203734314653197777416031990665541876397929334419521541" +
-	"34189948544473456738316249934191318148092777710386387734317720754565453220777092120190516609628049092636019759" +
-	"88281613323166636528619326686336062735676303544776280350450777235547105859548702790814356240145171806246436267" +
-	"94561275318134078330336254232783944975382437205835311477119926063813346776879695970309833913077109870408591337"
-
-// Test case for BenchmarkScanPi.
-func TestScanPi(t *testing.T) {
-	var x nat
-	z, _, err := x.scan(strings.NewReader(pi), 10)
-	if err != nil {
-		t.Errorf("scanning pi: %s", err)
-	}
-	if s := z.decimalString(); s != pi {
-		t.Errorf("scanning pi: got %s", s)
-	}
-}
-
-func TestScanPiParallel(t *testing.T) {
-	const n = 2
-	c := make(chan int)
-	for i := 0; i < n; i++ {
-		go func() {
-			TestScanPi(t)
-			c <- 0
-		}()
-	}
-	for i := 0; i < n; i++ {
-		<-c
-	}
-}
-
-func BenchmarkScanPi(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		var x nat
-		x.scan(strings.NewReader(pi), 10)
-	}
-}
-
-func BenchmarkStringPiParallel(b *testing.B) {
-	var x nat
-	x, _, _ = x.scan(strings.NewReader(pi), 0)
-	if x.decimalString() != pi {
-		panic("benchmark incorrect: conversion failed")
-	}
-	b.RunParallel(func(pb *testing.PB) {
-		for pb.Next() {
-			x.decimalString()
-		}
-	})
-}
-
-func BenchmarkScan10Base2(b *testing.B)     { ScanHelper(b, 2, 10, 10) }
-func BenchmarkScan100Base2(b *testing.B)    { ScanHelper(b, 2, 10, 100) }
-func BenchmarkScan1000Base2(b *testing.B)   { ScanHelper(b, 2, 10, 1000) }
-func BenchmarkScan10000Base2(b *testing.B)  { ScanHelper(b, 2, 10, 10000) }
-func BenchmarkScan100000Base2(b *testing.B) { ScanHelper(b, 2, 10, 100000) }
-
-func BenchmarkScan10Base8(b *testing.B)     { ScanHelper(b, 8, 10, 10) }
-func BenchmarkScan100Base8(b *testing.B)    { ScanHelper(b, 8, 10, 100) }
-func BenchmarkScan1000Base8(b *testing.B)   { ScanHelper(b, 8, 10, 1000) }
-func BenchmarkScan10000Base8(b *testing.B)  { ScanHelper(b, 8, 10, 10000) }
-func BenchmarkScan100000Base8(b *testing.B) { ScanHelper(b, 8, 10, 100000) }
-
-func BenchmarkScan10Base10(b *testing.B)     { ScanHelper(b, 10, 10, 10) }
-func BenchmarkScan100Base10(b *testing.B)    { ScanHelper(b, 10, 10, 100) }
-func BenchmarkScan1000Base10(b *testing.B)   { ScanHelper(b, 10, 10, 1000) }
-func BenchmarkScan10000Base10(b *testing.B)  { ScanHelper(b, 10, 10, 10000) }
-func BenchmarkScan100000Base10(b *testing.B) { ScanHelper(b, 10, 10, 100000) }
-
-func BenchmarkScan10Base16(b *testing.B)     { ScanHelper(b, 16, 10, 10) }
-func BenchmarkScan100Base16(b *testing.B)    { ScanHelper(b, 16, 10, 100) }
-func BenchmarkScan1000Base16(b *testing.B)   { ScanHelper(b, 16, 10, 1000) }
-func BenchmarkScan10000Base16(b *testing.B)  { ScanHelper(b, 16, 10, 10000) }
-func BenchmarkScan100000Base16(b *testing.B) { ScanHelper(b, 16, 10, 100000) }
-
-func ScanHelper(b *testing.B, base int, x, y Word) {
-	b.StopTimer()
-	var z nat
-	z = z.expWW(x, y)
-
-	var s string
-	s = z.string(lowercaseDigits[0:base])
-	if t := toString(z, lowercaseDigits[0:base]); t != s {
-		b.Fatalf("scanning: got %s; want %s", s, t)
-	}
-	b.StartTimer()
-
-	for i := 0; i < b.N; i++ {
-		z.scan(strings.NewReader(s), base)
-	}
-}
-
-func BenchmarkString10Base2(b *testing.B)     { StringHelper(b, 2, 10, 10) }
-func BenchmarkString100Base2(b *testing.B)    { StringHelper(b, 2, 10, 100) }
-func BenchmarkString1000Base2(b *testing.B)   { StringHelper(b, 2, 10, 1000) }
-func BenchmarkString10000Base2(b *testing.B)  { StringHelper(b, 2, 10, 10000) }
-func BenchmarkString100000Base2(b *testing.B) { StringHelper(b, 2, 10, 100000) }
-
-func BenchmarkString10Base8(b *testing.B)     { StringHelper(b, 8, 10, 10) }
-func BenchmarkString100Base8(b *testing.B)    { StringHelper(b, 8, 10, 100) }
-func BenchmarkString1000Base8(b *testing.B)   { StringHelper(b, 8, 10, 1000) }
-func BenchmarkString10000Base8(b *testing.B)  { StringHelper(b, 8, 10, 10000) }
-func BenchmarkString100000Base8(b *testing.B) { StringHelper(b, 8, 10, 100000) }
-
-func BenchmarkString10Base10(b *testing.B)     { StringHelper(b, 10, 10, 10) }
-func BenchmarkString100Base10(b *testing.B)    { StringHelper(b, 10, 10, 100) }
-func BenchmarkString1000Base10(b *testing.B)   { StringHelper(b, 10, 10, 1000) }
-func BenchmarkString10000Base10(b *testing.B)  { StringHelper(b, 10, 10, 10000) }
-func BenchmarkString100000Base10(b *testing.B) { StringHelper(b, 10, 10, 100000) }
-
-func BenchmarkString10Base16(b *testing.B)     { StringHelper(b, 16, 10, 10) }
-func BenchmarkString100Base16(b *testing.B)    { StringHelper(b, 16, 10, 100) }
-func BenchmarkString1000Base16(b *testing.B)   { StringHelper(b, 16, 10, 1000) }
-func BenchmarkString10000Base16(b *testing.B)  { StringHelper(b, 16, 10, 10000) }
-func BenchmarkString100000Base16(b *testing.B) { StringHelper(b, 16, 10, 100000) }
-
-func StringHelper(b *testing.B, base int, x, y Word) {
-	b.StopTimer()
-	var z nat
-	z = z.expWW(x, y)
-	z.string(lowercaseDigits[0:base]) // warm divisor cache
-	b.StartTimer()
-
-	for i := 0; i < b.N; i++ {
-		_ = z.string(lowercaseDigits[0:base])
-	}
-}
-
-func BenchmarkLeafSize0(b *testing.B)  { LeafSizeHelper(b, 10, 0) } // test without splitting
-func BenchmarkLeafSize1(b *testing.B)  { LeafSizeHelper(b, 10, 1) }
-func BenchmarkLeafSize2(b *testing.B)  { LeafSizeHelper(b, 10, 2) }
-func BenchmarkLeafSize3(b *testing.B)  { LeafSizeHelper(b, 10, 3) }
-func BenchmarkLeafSize4(b *testing.B)  { LeafSizeHelper(b, 10, 4) }
-func BenchmarkLeafSize5(b *testing.B)  { LeafSizeHelper(b, 10, 5) }
-func BenchmarkLeafSize6(b *testing.B)  { LeafSizeHelper(b, 10, 6) }
-func BenchmarkLeafSize7(b *testing.B)  { LeafSizeHelper(b, 10, 7) }
-func BenchmarkLeafSize8(b *testing.B)  { LeafSizeHelper(b, 10, 8) }
-func BenchmarkLeafSize9(b *testing.B)  { LeafSizeHelper(b, 10, 9) }
-func BenchmarkLeafSize10(b *testing.B) { LeafSizeHelper(b, 10, 10) }
-func BenchmarkLeafSize11(b *testing.B) { LeafSizeHelper(b, 10, 11) }
-func BenchmarkLeafSize12(b *testing.B) { LeafSizeHelper(b, 10, 12) }
-func BenchmarkLeafSize13(b *testing.B) { LeafSizeHelper(b, 10, 13) }
-func BenchmarkLeafSize14(b *testing.B) { LeafSizeHelper(b, 10, 14) }
-func BenchmarkLeafSize15(b *testing.B) { LeafSizeHelper(b, 10, 15) }
-func BenchmarkLeafSize16(b *testing.B) { LeafSizeHelper(b, 10, 16) }
-func BenchmarkLeafSize32(b *testing.B) { LeafSizeHelper(b, 10, 32) } // try some large lengths
-func BenchmarkLeafSize64(b *testing.B) { LeafSizeHelper(b, 10, 64) }
-
-func LeafSizeHelper(b *testing.B, base Word, size int) {
-	b.StopTimer()
-	originalLeafSize := leafSize
-	resetTable(cacheBase10.table[:])
-	leafSize = size
-	b.StartTimer()
-
-	for d := 1; d <= 10000; d *= 10 {
-		b.StopTimer()
-		var z nat
-		z = z.expWW(base, Word(d))            // build target number
-		_ = z.string(lowercaseDigits[0:base]) // warm divisor cache
-		b.StartTimer()
-
-		for i := 0; i < b.N; i++ {
-			_ = z.string(lowercaseDigits[0:base])
-		}
-	}
-
-	b.StopTimer()
-	resetTable(cacheBase10.table[:])
-	leafSize = originalLeafSize
-	b.StartTimer()
-}
-
-func resetTable(table []divisor) {
-	if table != nil && table[0].bbb != nil {
-		for i := 0; i < len(table); i++ {
-			table[i].bbb = nil
-			table[i].nbits = 0
-			table[i].ndigits = 0
-		}
-	}
-}
-
-func TestStringPowers(t *testing.T) {
-	var b, p Word
-	for b = 2; b <= 16; b++ {
-		for p = 0; p <= 512; p++ {
-			x := nat(nil).expWW(b, p)
-			xs := x.string(lowercaseDigits[0:b])
-			xs2 := toString(x, lowercaseDigits[0:b])
-			if xs != xs2 {
-				t.Errorf("failed at %d ** %d in base %d: %s != %s", b, p, b, xs, xs2)
-			}
-		}
-		if b >= 3 && testing.Short() {
-			break
-		}
-	}
-}
-
-func TestLeadingZeros(t *testing.T) {
+func TestNLZ(t *testing.T) {
 	var x Word = _B >> 1
 	for i := 0; i <= _W; i++ {
-		if int(leadingZeros(x)) != i {
-			t.Errorf("failed at %x: got %d want %d", x, leadingZeros(x), i)
+		if int(nlz(x)) != i {
+			t.Errorf("failed at %x: got %d want %d", x, nlz(x), i)
 		}
 		x >>= 1
 	}
@@ -691,25 +303,96 @@ func TestModW(t *testing.T) {
 }
 
 func TestTrailingZeroBits(t *testing.T) {
+	// test 0 case explicitly
+	if n := trailingZeroBits(0); n != 0 {
+		t.Errorf("got trailingZeroBits(0) = %d; want 0", n)
+	}
+
 	x := Word(1)
-	for i := uint(0); i <= _W; i++ {
+	for i := uint(0); i < _W; i++ {
 		n := trailingZeroBits(x)
-		if n != i%_W {
+		if n != i {
 			t.Errorf("got trailingZeroBits(%#x) = %d; want %d", x, n, i%_W)
 		}
 		x <<= 1
 	}
 
+	// test 0 case explicitly
+	if n := nat(nil).trailingZeroBits(); n != 0 {
+		t.Errorf("got nat(nil).trailingZeroBits() = %d; want 0", n)
+	}
+
 	y := nat(nil).set(natOne)
 	for i := uint(0); i <= 3*_W; i++ {
 		n := y.trailingZeroBits()
 		if n != i {
-			t.Errorf("got 0x%s.trailingZeroBits() = %d; want %d", y.string(lowercaseDigits[0:16]), n, i)
+			t.Errorf("got 0x%s.trailingZeroBits() = %d; want %d", y.hexString(), n, i)
 		}
 		y = y.shl(y, 1)
 	}
 }
 
+var montgomeryTests = []struct {
+	x, y, m      string
+	k0           uint64
+	out32, out64 string
+}{
+	{
+		"0xffffffffffffffffffffffffffffffffffffffffffffffffe",
+		"0xffffffffffffffffffffffffffffffffffffffffffffffffe",
+		"0xfffffffffffffffffffffffffffffffffffffffffffffffff",
+		0x0000000000000000,
+		"0xffffffffffffffffffffffffffffffffffffffffff",
+		"0xffffffffffffffffffffffffffffffffff",
+	},
+	{
+		"0x0000000080000000",
+		"0x00000000ffffffff",
+		"0x0000000010000001",
+		0xff0000000fffffff,
+		"0x0000000088000000",
+		"0x0000000007800001",
+	},
+	{
+		"0xffffffffffffffffffffffffffffffff00000000000022222223333333333444444444",
+		"0xffffffffffffffffffffffffffffffff999999999999999aaabbbbbbbbcccccccccccc",
+		"0x33377fffffffffffffffffffffffffffffffffffffffffffff0000000000022222eee1",
+		0xdecc8f1249812adf,
+		"0x22bb05b6d95eaaeca2bb7c05e51f807bce9064b5fbad177161695e4558f9474e91cd79",
+		"0x14beb58d230f85b6d95eaaeca2bb7c05e51f807bce9064b5fb45669afa695f228e48cd",
+	},
+	{
+		"0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffff00000000000022222223333333333444444444",
+		"0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffff999999999999999aaabbbbbbbbcccccccccccc",
+		"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff33377fffffffffffffffffffffffffffffffffffffffffffff0000000000022222eee1",
+		0xdecc8f1249812adf,
+		"0x5c0d52f451aec609b15da8e5e5626c4eaa88723bdeac9d25ca9b961269400410ca208a16af9c2fb07d7a11c7772cba02c22f9711078d51a3797eb18e691295293284d988e349fa6deba46b25a4ecd9f715",
+		"0x92fcad4b5c0d52f451aec609b15da8e5e5626c4eaa88723bdeac9d25ca9b961269400410ca208a16af9c2fb07d799c32fe2f3cc5422f9711078d51a3797eb18e691295293284d8f5e69caf6decddfe1df6",
+	},
+}
+
+func TestMontgomery(t *testing.T) {
+	for i, test := range montgomeryTests {
+		x := natFromString(test.x)
+		y := natFromString(test.y)
+		m := natFromString(test.m)
+
+		var out nat
+		if _W == 32 {
+			out = natFromString(test.out32)
+		} else {
+			out = natFromString(test.out64)
+		}
+
+		k0 := Word(test.k0 & _M) // mask k0 to ensure that it fits for 32-bit systems.
+		z := nat(nil).montgomery(x, y, m, k0, len(m))
+		z = z.norm()
+		if z.cmp(out) != 0 {
+			t.Errorf("#%d got %s want %s", i, z.decimalString(), out.decimalString())
+		}
+	}
+}
+
 var expNNTests = []struct {
 	x, y, m string
 	out     string
@@ -735,14 +418,13 @@ var expNNTests = []struct {
 
 func TestExpNN(t *testing.T) {
 	for i, test := range expNNTests {
-		x, _, _ := nat(nil).scan(strings.NewReader(test.x), 0)
-		y, _, _ := nat(nil).scan(strings.NewReader(test.y), 0)
-		out, _, _ := nat(nil).scan(strings.NewReader(test.out), 0)
+		x := natFromString(test.x)
+		y := natFromString(test.y)
+		out := natFromString(test.out)
 
 		var m nat
-
 		if len(test.m) > 0 {
-			m, _, _ = nat(nil).scan(strings.NewReader(test.m), 0)
+			m = natFromString(test.m)
 		}
 
 		z := nat(nil).expNN(x, y, m)
@@ -769,3 +451,129 @@ func BenchmarkExp3Power0x10000(b *testing.B)  { ExpHelper(b, 3, 0x10000) }
 func BenchmarkExp3Power0x40000(b *testing.B)  { ExpHelper(b, 3, 0x40000) }
 func BenchmarkExp3Power0x100000(b *testing.B) { ExpHelper(b, 3, 0x100000) }
 func BenchmarkExp3Power0x400000(b *testing.B) { ExpHelper(b, 3, 0x400000) }
+
+func fibo(n int) nat {
+	switch n {
+	case 0:
+		return nil
+	case 1:
+		return nat{1}
+	}
+	f0 := fibo(0)
+	f1 := fibo(1)
+	var f2 nat
+	for i := 1; i < n; i++ {
+		f2 = f2.add(f0, f1)
+		f0, f1, f2 = f1, f2, f0
+	}
+	return f1
+}
+
+var fiboNums = []string{
+	"0",
+	"55",
+	"6765",
+	"832040",
+	"102334155",
+	"12586269025",
+	"1548008755920",
+	"190392490709135",
+	"23416728348467685",
+	"2880067194370816120",
+	"354224848179261915075",
+}
+
+func TestFibo(t *testing.T) {
+	for i, want := range fiboNums {
+		n := i * 10
+		got := fibo(n).decimalString()
+		if got != want {
+			t.Errorf("fibo(%d) failed: got %s want %s", n, got, want)
+		}
+	}
+}
+
+func BenchmarkFibo(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		fibo(1e0)
+		fibo(1e1)
+		fibo(1e2)
+		fibo(1e3)
+		fibo(1e4)
+		fibo(1e5)
+	}
+}
+
+var bitTests = []struct {
+	x    string
+	i    uint
+	want uint
+}{
+	{"0", 0, 0},
+	{"0", 1, 0},
+	{"0", 1000, 0},
+
+	{"0x1", 0, 1},
+	{"0x10", 0, 0},
+	{"0x10", 3, 0},
+	{"0x10", 4, 1},
+	{"0x10", 5, 0},
+
+	{"0x8000000000000000", 62, 0},
+	{"0x8000000000000000", 63, 1},
+	{"0x8000000000000000", 64, 0},
+
+	{"0x3" + strings.Repeat("0", 32), 127, 0},
+	{"0x3" + strings.Repeat("0", 32), 128, 1},
+	{"0x3" + strings.Repeat("0", 32), 129, 1},
+	{"0x3" + strings.Repeat("0", 32), 130, 0},
+}
+
+func TestBit(t *testing.T) {
+	for i, test := range bitTests {
+		x := natFromString(test.x)
+		if got := x.bit(test.i); got != test.want {
+			t.Errorf("#%d: %s.bit(%d) = %v; want %v", i, test.x, test.i, got, test.want)
+		}
+	}
+}
+
+var stickyTests = []struct {
+	x    string
+	i    uint
+	want uint
+}{
+	{"0", 0, 0},
+	{"0", 1, 0},
+	{"0", 1000, 0},
+
+	{"0x1", 0, 0},
+	{"0x1", 1, 1},
+
+	{"0x1350", 0, 0},
+	{"0x1350", 4, 0},
+	{"0x1350", 5, 1},
+
+	{"0x8000000000000000", 63, 0},
+	{"0x8000000000000000", 64, 1},
+
+	{"0x1" + strings.Repeat("0", 100), 400, 0},
+	{"0x1" + strings.Repeat("0", 100), 401, 1},
+}
+
+func TestSticky(t *testing.T) {
+	for i, test := range stickyTests {
+		x := natFromString(test.x)
+		if got := x.sticky(test.i); got != test.want {
+			t.Errorf("#%d: %s.sticky(%d) = %v; want %v", i, test.x, test.i, got, test.want)
+		}
+		if test.want == 1 {
+			// all subsequent i's should also return 1
+			for d := uint(1); d <= 3; d++ {
+				if got := x.sticky(test.i + d); got != 1 {
+					t.Errorf("#%d: %s.sticky(%d) = %v; want %v", i, test.x, test.i+d, got, 1)
+				}
+			}
+		}
+	}
+}
diff --git a/src/math/big/natconv.go b/src/math/big/natconv.go
new file mode 100644
index 0000000..022dcfe
--- /dev/null
+++ b/src/math/big/natconv.go
@@ -0,0 +1,495 @@
+// 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 nat-to-string conversion functions.
+
+package big
+
+import (
+	"errors"
+	"fmt"
+	"io"
+	"math"
+	"sync"
+)
+
+// MaxBase is the largest number base accepted for string conversions.
+const MaxBase = 'z' - 'a' + 10 + 1
+
+// maxPow returns (b**n, n) such that b**n is the largest power b**n <= _M.
+// For instance maxPow(10) == (1e19, 19) for 19 decimal digits in a 64bit Word.
+// In other words, at most n digits in base b fit into a Word.
+// TODO(gri) replace this with a table, generated at build time.
+func maxPow(b Word) (p Word, n int) {
+	p, n = b, 1 // assuming b <= _M
+	for max := _M / b; p <= max; {
+		// p == b**n && p <= max
+		p *= b
+		n++
+	}
+	// p == b**n && p <= _M
+	return
+}
+
+// pow returns x**n for n > 0, and 1 otherwise.
+func pow(x Word, n int) (p Word) {
+	// n == sum of bi * 2**i, for 0 <= i < imax, and bi is 0 or 1
+	// thus x**n == product of x**(2**i) for all i where bi == 1
+	// (Russian Peasant Method for exponentiation)
+	p = 1
+	for n > 0 {
+		if n&1 != 0 {
+			p *= x
+		}
+		x *= x
+		n >>= 1
+	}
+	return
+}
+
+// scan scans the number corresponding to the longest possible prefix
+// from r representing an unsigned number in a given conversion base.
+// It returns the corresponding natural number res, the actual base b,
+// a digit count, and a read or syntax error err, if any.
+//
+//	number   = [ prefix ] mantissa .
+//	prefix   = "0" [ "x" | "X" | "b" | "B" ] .
+//      mantissa = digits | digits "." [ digits ] | "." digits .
+//	digits   = digit { digit } .
+//	digit    = "0" ... "9" | "a" ... "z" | "A" ... "Z" .
+//
+// Unless fracOk is set, the base argument must be 0 or a value between
+// 2 and MaxBase. If fracOk is set, the base argument must be one of
+// 0, 2, 10, or 16. Providing an invalid base argument leads to a run-
+// time panic.
+//
+// For base 0, the number prefix determines the actual base: A prefix of
+// ``0x'' or ``0X'' selects base 16; if fracOk is not set, the ``0'' prefix
+// selects base 8, and a ``0b'' or ``0B'' prefix selects base 2. Otherwise
+// the selected base is 10 and no prefix is accepted.
+//
+// If fracOk is set, an octal prefix is ignored (a leading ``0'' simply
+// stands for a zero digit), and a period followed by a fractional part
+// is permitted. The result value is computed as if there were no period
+// present; and the count value is used to determine the fractional part.
+//
+// A result digit count > 0 corresponds to the number of (non-prefix) digits
+// parsed. A digit count <= 0 indicates the presence of a period (if fracOk
+// is set, only), and -count is the number of fractional digits found.
+// In this case, the actual value of the scanned number is res * b**count.
+//
+func (z nat) scan(r io.ByteScanner, base int, fracOk bool) (res nat, b, count int, err error) {
+	// reject illegal bases
+	baseOk := base == 0 ||
+		!fracOk && 2 <= base && base <= MaxBase ||
+		fracOk && (base == 2 || base == 10 || base == 16)
+	if !baseOk {
+		panic(fmt.Sprintf("illegal number base %d", base))
+	}
+
+	// one char look-ahead
+	ch, err := r.ReadByte()
+	if err != nil {
+		return
+	}
+
+	// determine actual base
+	b = base
+	if base == 0 {
+		// actual base is 10 unless there's a base prefix
+		b = 10
+		if ch == '0' {
+			count = 1
+			switch ch, err = r.ReadByte(); err {
+			case nil:
+				// possibly one of 0x, 0X, 0b, 0B
+				if !fracOk {
+					b = 8
+				}
+				switch ch {
+				case 'x', 'X':
+					b = 16
+				case 'b', 'B':
+					b = 2
+				}
+				switch b {
+				case 16, 2:
+					count = 0 // prefix is not counted
+					if ch, err = r.ReadByte(); err != nil {
+						// io.EOF is also an error in this case
+						return
+					}
+				case 8:
+					count = 0 // prefix is not counted
+				}
+			case io.EOF:
+				// input is "0"
+				res = z[:0]
+				err = nil
+				return
+			default:
+				// read error
+				return
+			}
+		}
+	}
+
+	// convert string
+	// Algorithm: Collect digits in groups of at most n digits in di
+	// and then use mulAddWW for every such group to add them to the
+	// result.
+	z = z[:0]
+	b1 := Word(b)
+	bn, n := maxPow(b1) // at most n digits in base b1 fit into Word
+	di := Word(0)       // 0 <= di < b1**i < bn
+	i := 0              // 0 <= i < n
+	dp := -1            // position of decimal point
+	for {
+		if fracOk && ch == '.' {
+			fracOk = false
+			dp = count
+			// advance
+			if ch, err = r.ReadByte(); err != nil {
+				if err == io.EOF {
+					err = nil
+					break
+				}
+				return
+			}
+		}
+
+		// convert rune into digit value d1
+		var d1 Word
+		switch {
+		case '0' <= ch && ch <= '9':
+			d1 = Word(ch - '0')
+		case 'a' <= ch && ch <= 'z':
+			d1 = Word(ch - 'a' + 10)
+		case 'A' <= ch && ch <= 'Z':
+			d1 = Word(ch - 'A' + 10)
+		default:
+			d1 = MaxBase + 1
+		}
+		if d1 >= b1 {
+			r.UnreadByte() // ch does not belong to number anymore
+			break
+		}
+		count++
+
+		// collect d1 in di
+		di = di*b1 + d1
+		i++
+
+		// if di is "full", add it to the result
+		if i == n {
+			z = z.mulAddWW(z, bn, di)
+			di = 0
+			i = 0
+		}
+
+		// advance
+		if ch, err = r.ReadByte(); err != nil {
+			if err == io.EOF {
+				err = nil
+				break
+			}
+			return
+		}
+	}
+
+	if count == 0 {
+		// no digits found
+		switch {
+		case base == 0 && b == 8:
+			// there was only the octal prefix 0 (possibly followed by digits > 7);
+			// count as one digit and return base 10, not 8
+			count = 1
+			b = 10
+		case base != 0 || b != 8:
+			// there was neither a mantissa digit nor the octal prefix 0
+			err = errors.New("syntax error scanning number")
+		}
+		return
+	}
+	// count > 0
+
+	// add remaining digits to result
+	if i > 0 {
+		z = z.mulAddWW(z, pow(b1, i), di)
+	}
+	res = z.norm()
+
+	// adjust for fraction, if any
+	if dp >= 0 {
+		// 0 <= dp <= count > 0
+		count = dp - count
+	}
+
+	return
+}
+
+// Character sets for string conversion.
+const (
+	lowercaseDigits = "0123456789abcdefghijklmnopqrstuvwxyz"
+	uppercaseDigits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+)
+
+// decimalString returns a decimal representation of x.
+// It calls x.string with the charset "0123456789".
+func (x nat) decimalString() string {
+	return x.string(lowercaseDigits[:10])
+}
+
+// hexString returns a hexadecimal representation of x.
+// It calls x.string with the charset "0123456789abcdef".
+func (x nat) hexString() string {
+	return x.string(lowercaseDigits[:16])
+}
+
+// string converts x to a string using digits from a charset; a digit with
+// value d is represented by charset[d]. The conversion base is determined
+// by len(charset), which must be >= 2 and <= 256.
+func (x nat) string(charset string) string {
+	b := Word(len(charset))
+
+	// special cases
+	switch {
+	case b < 2 || b > 256:
+		panic("invalid character set length")
+	case len(x) == 0:
+		return string(charset[0])
+	}
+
+	// allocate buffer for conversion
+	i := int(float64(x.bitLen())/math.Log2(float64(b))) + 1 // off by one at most
+	s := make([]byte, i)
+
+	// convert power of two and non power of two bases separately
+	if b == b&-b {
+		// shift is base-b digit size in bits
+		shift := trailingZeroBits(b) // shift > 0 because b >= 2
+		mask := Word(1)<<shift - 1
+		w := x[0]
+		nbits := uint(_W) // number of unprocessed bits in w
+
+		// convert less-significant words
+		for k := 1; k < len(x); k++ {
+			// convert full digits
+			for nbits >= shift {
+				i--
+				s[i] = charset[w&mask]
+				w >>= shift
+				nbits -= shift
+			}
+
+			// convert any partial leading digit and advance to next word
+			if nbits == 0 {
+				// no partial digit remaining, just advance
+				w = x[k]
+				nbits = _W
+			} else {
+				// partial digit in current (k-1) and next (k) word
+				w |= x[k] << nbits
+				i--
+				s[i] = charset[w&mask]
+
+				// advance
+				w = x[k] >> (shift - nbits)
+				nbits = _W - (shift - nbits)
+			}
+		}
+
+		// convert digits of most-significant word (omit leading zeros)
+		for nbits >= 0 && w != 0 {
+			i--
+			s[i] = charset[w&mask]
+			w >>= shift
+			nbits -= shift
+		}
+
+	} else {
+		bb, ndigits := maxPow(Word(b))
+
+		// construct table of successive squares of bb*leafSize to use in subdivisions
+		// result (table != nil) <=> (len(x) > leafSize > 0)
+		table := divisors(len(x), b, ndigits, bb)
+
+		// preserve x, create local copy for use by convertWords
+		q := nat(nil).set(x)
+
+		// convert q to string s in base b
+		q.convertWords(s, charset, b, ndigits, bb, table)
+
+		// strip leading zeros
+		// (x != 0; thus s must contain at least one non-zero digit
+		// and the loop will terminate)
+		i = 0
+		for zero := charset[0]; s[i] == zero; {
+			i++
+		}
+	}
+
+	return string(s[i:])
+}
+
+// Convert words of q to base b digits in s. If q is large, it is recursively "split in half"
+// by nat/nat division using tabulated divisors. Otherwise, it is converted iteratively using
+// repeated nat/Word division.
+//
+// The iterative method processes n Words by n divW() calls, each of which visits every Word in the
+// incrementally shortened q for a total of n + (n-1) + (n-2) ... + 2 + 1, or n(n+1)/2 divW()'s.
+// Recursive conversion divides q by its approximate square root, yielding two parts, each half
+// the size of q. Using the iterative method on both halves means 2 * (n/2)(n/2 + 1)/2 divW()'s
+// plus the expensive long div(). Asymptotically, the ratio is favorable at 1/2 the divW()'s, and
+// is made better by splitting the subblocks recursively. Best is to split blocks until one more
+// split would take longer (because of the nat/nat div()) than the twice as many divW()'s of the
+// iterative approach. This threshold is represented by leafSize. Benchmarking of leafSize in the
+// range 2..64 shows that values of 8 and 16 work well, with a 4x speedup at medium lengths and
+// ~30x for 20000 digits. Use nat_test.go's BenchmarkLeafSize tests to optimize leafSize for
+// specific hardware.
+//
+func (q nat) convertWords(s []byte, charset string, b Word, ndigits int, bb Word, table []divisor) {
+	// split larger blocks recursively
+	if table != nil {
+		// len(q) > leafSize > 0
+		var r nat
+		index := len(table) - 1
+		for len(q) > leafSize {
+			// find divisor close to sqrt(q) if possible, but in any case < q
+			maxLength := q.bitLen()     // ~= log2 q, or at of least largest possible q of this bit length
+			minLength := maxLength >> 1 // ~= log2 sqrt(q)
+			for index > 0 && table[index-1].nbits > minLength {
+				index-- // desired
+			}
+			if table[index].nbits >= maxLength && table[index].bbb.cmp(q) >= 0 {
+				index--
+				if index < 0 {
+					panic("internal inconsistency")
+				}
+			}
+
+			// split q into the two digit number (q'*bbb + r) to form independent subblocks
+			q, r = q.div(r, q, table[index].bbb)
+
+			// convert subblocks and collect results in s[:h] and s[h:]
+			h := len(s) - table[index].ndigits
+			r.convertWords(s[h:], charset, b, ndigits, bb, table[0:index])
+			s = s[:h] // == q.convertWords(s, charset, b, ndigits, bb, table[0:index+1])
+		}
+	}
+
+	// having split any large blocks now process the remaining (small) block iteratively
+	i := len(s)
+	var r Word
+	if b == 10 {
+		// hard-coding for 10 here speeds this up by 1.25x (allows for / and % by constants)
+		for len(q) > 0 {
+			// extract least significant, base bb "digit"
+			q, r = q.divW(q, bb)
+			for j := 0; j < ndigits && i > 0; j++ {
+				i--
+				// avoid % computation since r%10 == r - int(r/10)*10;
+				// this appears to be faster for BenchmarkString10000Base10
+				// and smaller strings (but a bit slower for larger ones)
+				t := r / 10
+				s[i] = charset[r-t<<3-t-t] // TODO(gri) replace w/ t*10 once compiler produces better code
+				r = t
+			}
+		}
+	} else {
+		for len(q) > 0 {
+			// extract least significant, base bb "digit"
+			q, r = q.divW(q, bb)
+			for j := 0; j < ndigits && i > 0; j++ {
+				i--
+				s[i] = charset[r%b]
+				r /= b
+			}
+		}
+	}
+
+	// prepend high-order zeroes
+	zero := charset[0]
+	for i > 0 { // while need more leading zeroes
+		i--
+		s[i] = zero
+	}
+}
+
+// Split blocks greater than leafSize Words (or set to 0 to disable recursive conversion)
+// Benchmark and configure leafSize using: go test -bench="Leaf"
+//   8 and 16 effective on 3.0 GHz Xeon "Clovertown" CPU (128 byte cache lines)
+//   8 and 16 effective on 2.66 GHz Core 2 Duo "Penryn" CPU
+var leafSize int = 8 // number of Word-size binary values treat as a monolithic block
+
+type divisor struct {
+	bbb     nat // divisor
+	nbits   int // bit length of divisor (discounting leading zeroes) ~= log2(bbb)
+	ndigits int // digit length of divisor in terms of output base digits
+}
+
+var cacheBase10 struct {
+	sync.Mutex
+	table [64]divisor // cached divisors for base 10
+}
+
+// expWW computes x**y
+func (z nat) expWW(x, y Word) nat {
+	return z.expNN(nat(nil).setWord(x), nat(nil).setWord(y), nil)
+}
+
+// construct table of powers of bb*leafSize to use in subdivisions
+func divisors(m int, b Word, ndigits int, bb Word) []divisor {
+	// only compute table when recursive conversion is enabled and x is large
+	if leafSize == 0 || m <= leafSize {
+		return nil
+	}
+
+	// determine k where (bb**leafSize)**(2**k) >= sqrt(x)
+	k := 1
+	for words := leafSize; words < m>>1 && k < len(cacheBase10.table); words <<= 1 {
+		k++
+	}
+
+	// reuse and extend existing table of divisors or create new table as appropriate
+	var table []divisor // for b == 10, table overlaps with cacheBase10.table
+	if b == 10 {
+		cacheBase10.Lock()
+		table = cacheBase10.table[0:k] // reuse old table for this conversion
+	} else {
+		table = make([]divisor, k) // create new table for this conversion
+	}
+
+	// extend table
+	if table[k-1].ndigits == 0 {
+		// add new entries as needed
+		var larger nat
+		for i := 0; i < k; i++ {
+			if table[i].ndigits == 0 {
+				if i == 0 {
+					table[0].bbb = nat(nil).expWW(bb, Word(leafSize))
+					table[0].ndigits = ndigits * leafSize
+				} else {
+					table[i].bbb = nat(nil).mul(table[i-1].bbb, table[i-1].bbb)
+					table[i].ndigits = 2 * table[i-1].ndigits
+				}
+
+				// optimization: exploit aggregated extra bits in macro blocks
+				larger = nat(nil).set(table[i].bbb)
+				for mulAddVWW(larger, larger, b, 0) == 0 {
+					table[i].bbb = table[i].bbb.set(larger)
+					table[i].ndigits++
+				}
+
+				table[i].nbits = table[i].bbb.bitLen()
+			}
+		}
+	}
+
+	if b == 10 {
+		cacheBase10.Unlock()
+	}
+
+	return table
+}
diff --git a/src/math/big/natconv_test.go b/src/math/big/natconv_test.go
new file mode 100644
index 0000000..f321fbc
--- /dev/null
+++ b/src/math/big/natconv_test.go
@@ -0,0 +1,425 @@
+// 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
+
+import (
+	"io"
+	"strings"
+	"testing"
+)
+
+func toString(x nat, charset string) string {
+	base := len(charset)
+
+	// special cases
+	switch {
+	case base < 2:
+		panic("illegal base")
+	case len(x) == 0:
+		return string(charset[0])
+	}
+
+	// allocate buffer for conversion
+	i := x.bitLen()/log2(Word(base)) + 1 // +1: round up
+	s := make([]byte, i)
+
+	// don't destroy x
+	q := nat(nil).set(x)
+
+	// convert
+	for len(q) > 0 {
+		i--
+		var r Word
+		q, r = q.divW(q, Word(base))
+		s[i] = charset[r]
+	}
+
+	return string(s[i:])
+}
+
+var strTests = []struct {
+	x nat    // nat value to be converted
+	c string // conversion charset
+	s string // expected result
+}{
+	{nil, "01", "0"},
+	{nat{1}, "01", "1"},
+	{nat{0xc5}, "01", "11000101"},
+	{nat{03271}, lowercaseDigits[:8], "3271"},
+	{nat{10}, lowercaseDigits[:10], "10"},
+	{nat{1234567890}, uppercaseDigits[:10], "1234567890"},
+	{nat{0xdeadbeef}, lowercaseDigits[:16], "deadbeef"},
+	{nat{0xdeadbeef}, uppercaseDigits[:16], "DEADBEEF"},
+	{nat{0x229be7}, lowercaseDigits[:17], "1a2b3c"},
+	{nat{0x309663e6}, uppercaseDigits[:32], "O9COV6"},
+}
+
+func TestString(t *testing.T) {
+	// test invalid character set explicitly
+	var panicStr string
+	func() {
+		defer func() {
+			panicStr = recover().(string)
+		}()
+		natOne.string("0")
+	}()
+	if panicStr != "invalid character set length" {
+		t.Errorf("expected panic for invalid character set")
+	}
+
+	for _, a := range strTests {
+		s := a.x.string(a.c)
+		if s != a.s {
+			t.Errorf("string%+v\n\tgot s = %s; want %s", a, s, a.s)
+		}
+
+		x, b, _, err := nat(nil).scan(strings.NewReader(a.s), len(a.c), false)
+		if x.cmp(a.x) != 0 {
+			t.Errorf("scan%+v\n\tgot z = %v; want %v", a, x, a.x)
+		}
+		if b != len(a.c) {
+			t.Errorf("scan%+v\n\tgot b = %d; want %d", a, b, len(a.c))
+		}
+		if err != nil {
+			t.Errorf("scan%+v\n\tgot error = %s", a, err)
+		}
+	}
+}
+
+var natScanTests = []struct {
+	s     string // string to be scanned
+	base  int    // input base
+	frac  bool   // fraction ok
+	x     nat    // expected nat
+	b     int    // expected base
+	count int    // expected digit count
+	ok    bool   // expected success
+	next  rune   // next character (or 0, if at EOF)
+}{
+	// error: no mantissa
+	{},
+	{s: "?"},
+	{base: 10},
+	{base: 36},
+	{s: "?", base: 10},
+	{s: "0x"},
+	{s: "345", base: 2},
+
+	// error: incorrect use of decimal point
+	{s: ".0"},
+	{s: ".0", base: 10},
+	{s: ".", base: 0},
+	{s: "0x.0"},
+
+	// no errors
+	{"0", 0, false, nil, 10, 1, true, 0},
+	{"0", 10, false, nil, 10, 1, true, 0},
+	{"0", 36, false, nil, 36, 1, true, 0},
+	{"1", 0, false, nat{1}, 10, 1, true, 0},
+	{"1", 10, false, nat{1}, 10, 1, true, 0},
+	{"0 ", 0, false, nil, 10, 1, true, ' '},
+	{"08", 0, false, nil, 10, 1, true, '8'},
+	{"08", 10, false, nat{8}, 10, 2, true, 0},
+	{"018", 0, false, nat{1}, 8, 1, true, '8'},
+	{"0b1", 0, false, nat{1}, 2, 1, true, 0},
+	{"0b11000101", 0, false, nat{0xc5}, 2, 8, true, 0},
+	{"03271", 0, false, nat{03271}, 8, 4, true, 0},
+	{"10ab", 0, false, nat{10}, 10, 2, true, 'a'},
+	{"1234567890", 0, false, nat{1234567890}, 10, 10, true, 0},
+	{"xyz", 36, false, nat{(33*36+34)*36 + 35}, 36, 3, true, 0},
+	{"xyz?", 36, false, nat{(33*36+34)*36 + 35}, 36, 3, true, '?'},
+	{"0x", 16, false, nil, 16, 1, true, 'x'},
+	{"0xdeadbeef", 0, false, nat{0xdeadbeef}, 16, 8, true, 0},
+	{"0XDEADBEEF", 0, false, nat{0xdeadbeef}, 16, 8, true, 0},
+
+	// no errors, decimal point
+	{"0.", 0, false, nil, 10, 1, true, '.'},
+	{"0.", 10, true, nil, 10, 0, true, 0},
+	{"0.1.2", 10, true, nat{1}, 10, -1, true, '.'},
+	{".000", 10, true, nil, 10, -3, true, 0},
+	{"12.3", 10, true, nat{123}, 10, -1, true, 0},
+	{"012.345", 10, true, nat{12345}, 10, -3, true, 0},
+}
+
+func TestScanBase(t *testing.T) {
+	for _, a := range natScanTests {
+		r := strings.NewReader(a.s)
+		x, b, count, err := nat(nil).scan(r, a.base, a.frac)
+		if err == nil && !a.ok {
+			t.Errorf("scan%+v\n\texpected error", a)
+		}
+		if err != nil {
+			if a.ok {
+				t.Errorf("scan%+v\n\tgot error = %s", a, err)
+			}
+			continue
+		}
+		if x.cmp(a.x) != 0 {
+			t.Errorf("scan%+v\n\tgot z = %v; want %v", a, x, a.x)
+		}
+		if b != a.b {
+			t.Errorf("scan%+v\n\tgot b = %d; want %d", a, b, a.base)
+		}
+		if count != a.count {
+			t.Errorf("scan%+v\n\tgot count = %d; want %d", a, count, a.count)
+		}
+		next, _, err := r.ReadRune()
+		if err == io.EOF {
+			next = 0
+			err = nil
+		}
+		if err == nil && next != a.next {
+			t.Errorf("scan%+v\n\tgot next = %q; want %q", a, next, a.next)
+		}
+	}
+}
+
+var pi = "3" +
+	"14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651" +
+	"32823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461" +
+	"28475648233786783165271201909145648566923460348610454326648213393607260249141273724587006606315588174881520920" +
+	"96282925409171536436789259036001133053054882046652138414695194151160943305727036575959195309218611738193261179" +
+	"31051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798" +
+	"60943702770539217176293176752384674818467669405132000568127145263560827785771342757789609173637178721468440901" +
+	"22495343014654958537105079227968925892354201995611212902196086403441815981362977477130996051870721134999999837" +
+	"29780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083" +
+	"81420617177669147303598253490428755468731159562863882353787593751957781857780532171226806613001927876611195909" +
+	"21642019893809525720106548586327886593615338182796823030195203530185296899577362259941389124972177528347913151" +
+	"55748572424541506959508295331168617278558890750983817546374649393192550604009277016711390098488240128583616035" +
+	"63707660104710181942955596198946767837449448255379774726847104047534646208046684259069491293313677028989152104" +
+	"75216205696602405803815019351125338243003558764024749647326391419927260426992279678235478163600934172164121992" +
+	"45863150302861829745557067498385054945885869269956909272107975093029553211653449872027559602364806654991198818" +
+	"34797753566369807426542527862551818417574672890977772793800081647060016145249192173217214772350141441973568548" +
+	"16136115735255213347574184946843852332390739414333454776241686251898356948556209921922218427255025425688767179" +
+	"04946016534668049886272327917860857843838279679766814541009538837863609506800642251252051173929848960841284886" +
+	"26945604241965285022210661186306744278622039194945047123713786960956364371917287467764657573962413890865832645" +
+	"99581339047802759009946576407895126946839835259570982582262052248940772671947826848260147699090264013639443745" +
+	"53050682034962524517493996514314298091906592509372216964615157098583874105978859597729754989301617539284681382" +
+	"68683868942774155991855925245953959431049972524680845987273644695848653836736222626099124608051243884390451244" +
+	"13654976278079771569143599770012961608944169486855584840635342207222582848864815845602850601684273945226746767" +
+	"88952521385225499546667278239864565961163548862305774564980355936345681743241125150760694794510965960940252288" +
+	"79710893145669136867228748940560101503308617928680920874760917824938589009714909675985261365549781893129784821" +
+	"68299894872265880485756401427047755513237964145152374623436454285844479526586782105114135473573952311342716610" +
+	"21359695362314429524849371871101457654035902799344037420073105785390621983874478084784896833214457138687519435" +
+	"06430218453191048481005370614680674919278191197939952061419663428754440643745123718192179998391015919561814675" +
+	"14269123974894090718649423196156794520809514655022523160388193014209376213785595663893778708303906979207734672" +
+	"21825625996615014215030680384477345492026054146659252014974428507325186660021324340881907104863317346496514539" +
+	"05796268561005508106658796998163574736384052571459102897064140110971206280439039759515677157700420337869936007" +
+	"23055876317635942187312514712053292819182618612586732157919841484882916447060957527069572209175671167229109816" +
+	"90915280173506712748583222871835209353965725121083579151369882091444210067510334671103141267111369908658516398" +
+	"31501970165151168517143765761835155650884909989859982387345528331635507647918535893226185489632132933089857064" +
+	"20467525907091548141654985946163718027098199430992448895757128289059232332609729971208443357326548938239119325" +
+	"97463667305836041428138830320382490375898524374417029132765618093773444030707469211201913020330380197621101100" +
+	"44929321516084244485963766983895228684783123552658213144957685726243344189303968642624341077322697802807318915" +
+	"44110104468232527162010526522721116603966655730925471105578537634668206531098965269186205647693125705863566201" +
+	"85581007293606598764861179104533488503461136576867532494416680396265797877185560845529654126654085306143444318" +
+	"58676975145661406800700237877659134401712749470420562230538994561314071127000407854733269939081454664645880797" +
+	"27082668306343285878569830523580893306575740679545716377525420211495576158140025012622859413021647155097925923" +
+	"09907965473761255176567513575178296664547791745011299614890304639947132962107340437518957359614589019389713111" +
+	"79042978285647503203198691514028708085990480109412147221317947647772622414254854540332157185306142288137585043" +
+	"06332175182979866223717215916077166925474873898665494945011465406284336639379003976926567214638530673609657120" +
+	"91807638327166416274888800786925602902284721040317211860820419000422966171196377921337575114959501566049631862" +
+	"94726547364252308177036751590673502350728354056704038674351362222477158915049530984448933309634087807693259939" +
+	"78054193414473774418426312986080998886874132604721569516239658645730216315981931951673538129741677294786724229" +
+	"24654366800980676928238280689964004824354037014163149658979409243237896907069779422362508221688957383798623001" +
+	"59377647165122893578601588161755782973523344604281512627203734314653197777416031990665541876397929334419521541" +
+	"34189948544473456738316249934191318148092777710386387734317720754565453220777092120190516609628049092636019759" +
+	"88281613323166636528619326686336062735676303544776280350450777235547105859548702790814356240145171806246436267" +
+	"94561275318134078330336254232783944975382437205835311477119926063813346776879695970309833913077109870408591337"
+
+// Test case for BenchmarkScanPi.
+func TestScanPi(t *testing.T) {
+	var x nat
+	z, _, _, err := x.scan(strings.NewReader(pi), 10, false)
+	if err != nil {
+		t.Errorf("scanning pi: %s", err)
+	}
+	if s := z.decimalString(); s != pi {
+		t.Errorf("scanning pi: got %s", s)
+	}
+}
+
+func TestScanPiParallel(t *testing.T) {
+	const n = 2
+	c := make(chan int)
+	for i := 0; i < n; i++ {
+		go func() {
+			TestScanPi(t)
+			c <- 0
+		}()
+	}
+	for i := 0; i < n; i++ {
+		<-c
+	}
+}
+
+func BenchmarkScanPi(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		var x nat
+		x.scan(strings.NewReader(pi), 10, false)
+	}
+}
+
+func BenchmarkStringPiParallel(b *testing.B) {
+	var x nat
+	x, _, _, _ = x.scan(strings.NewReader(pi), 0, false)
+	if x.decimalString() != pi {
+		panic("benchmark incorrect: conversion failed")
+	}
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			x.decimalString()
+		}
+	})
+}
+
+func BenchmarkScan10Base2(b *testing.B)     { ScanHelper(b, 2, 10, 10) }
+func BenchmarkScan100Base2(b *testing.B)    { ScanHelper(b, 2, 10, 100) }
+func BenchmarkScan1000Base2(b *testing.B)   { ScanHelper(b, 2, 10, 1000) }
+func BenchmarkScan10000Base2(b *testing.B)  { ScanHelper(b, 2, 10, 10000) }
+func BenchmarkScan100000Base2(b *testing.B) { ScanHelper(b, 2, 10, 100000) }
+
+func BenchmarkScan10Base8(b *testing.B)     { ScanHelper(b, 8, 10, 10) }
+func BenchmarkScan100Base8(b *testing.B)    { ScanHelper(b, 8, 10, 100) }
+func BenchmarkScan1000Base8(b *testing.B)   { ScanHelper(b, 8, 10, 1000) }
+func BenchmarkScan10000Base8(b *testing.B)  { ScanHelper(b, 8, 10, 10000) }
+func BenchmarkScan100000Base8(b *testing.B) { ScanHelper(b, 8, 10, 100000) }
+
+func BenchmarkScan10Base10(b *testing.B)     { ScanHelper(b, 10, 10, 10) }
+func BenchmarkScan100Base10(b *testing.B)    { ScanHelper(b, 10, 10, 100) }
+func BenchmarkScan1000Base10(b *testing.B)   { ScanHelper(b, 10, 10, 1000) }
+func BenchmarkScan10000Base10(b *testing.B)  { ScanHelper(b, 10, 10, 10000) }
+func BenchmarkScan100000Base10(b *testing.B) { ScanHelper(b, 10, 10, 100000) }
+
+func BenchmarkScan10Base16(b *testing.B)     { ScanHelper(b, 16, 10, 10) }
+func BenchmarkScan100Base16(b *testing.B)    { ScanHelper(b, 16, 10, 100) }
+func BenchmarkScan1000Base16(b *testing.B)   { ScanHelper(b, 16, 10, 1000) }
+func BenchmarkScan10000Base16(b *testing.B)  { ScanHelper(b, 16, 10, 10000) }
+func BenchmarkScan100000Base16(b *testing.B) { ScanHelper(b, 16, 10, 100000) }
+
+func ScanHelper(b *testing.B, base int, x, y Word) {
+	b.StopTimer()
+	var z nat
+	z = z.expWW(x, y)
+
+	var s string
+	s = z.string(lowercaseDigits[:base])
+	if t := toString(z, lowercaseDigits[:base]); t != s {
+		b.Fatalf("scanning: got %s; want %s", s, t)
+	}
+	b.StartTimer()
+
+	for i := 0; i < b.N; i++ {
+		z.scan(strings.NewReader(s), base, false)
+	}
+}
+
+func BenchmarkString10Base2(b *testing.B)     { StringHelper(b, 2, 10, 10) }
+func BenchmarkString100Base2(b *testing.B)    { StringHelper(b, 2, 10, 100) }
+func BenchmarkString1000Base2(b *testing.B)   { StringHelper(b, 2, 10, 1000) }
+func BenchmarkString10000Base2(b *testing.B)  { StringHelper(b, 2, 10, 10000) }
+func BenchmarkString100000Base2(b *testing.B) { StringHelper(b, 2, 10, 100000) }
+
+func BenchmarkString10Base8(b *testing.B)     { StringHelper(b, 8, 10, 10) }
+func BenchmarkString100Base8(b *testing.B)    { StringHelper(b, 8, 10, 100) }
+func BenchmarkString1000Base8(b *testing.B)   { StringHelper(b, 8, 10, 1000) }
+func BenchmarkString10000Base8(b *testing.B)  { StringHelper(b, 8, 10, 10000) }
+func BenchmarkString100000Base8(b *testing.B) { StringHelper(b, 8, 10, 100000) }
+
+func BenchmarkString10Base10(b *testing.B)     { StringHelper(b, 10, 10, 10) }
+func BenchmarkString100Base10(b *testing.B)    { StringHelper(b, 10, 10, 100) }
+func BenchmarkString1000Base10(b *testing.B)   { StringHelper(b, 10, 10, 1000) }
+func BenchmarkString10000Base10(b *testing.B)  { StringHelper(b, 10, 10, 10000) }
+func BenchmarkString100000Base10(b *testing.B) { StringHelper(b, 10, 10, 100000) }
+
+func BenchmarkString10Base16(b *testing.B)     { StringHelper(b, 16, 10, 10) }
+func BenchmarkString100Base16(b *testing.B)    { StringHelper(b, 16, 10, 100) }
+func BenchmarkString1000Base16(b *testing.B)   { StringHelper(b, 16, 10, 1000) }
+func BenchmarkString10000Base16(b *testing.B)  { StringHelper(b, 16, 10, 10000) }
+func BenchmarkString100000Base16(b *testing.B) { StringHelper(b, 16, 10, 100000) }
+
+func StringHelper(b *testing.B, base int, x, y Word) {
+	b.StopTimer()
+	var z nat
+	z = z.expWW(x, y)
+	z.string(lowercaseDigits[:base]) // warm divisor cache
+	b.StartTimer()
+
+	for i := 0; i < b.N; i++ {
+		_ = z.string(lowercaseDigits[:base])
+	}
+}
+
+func BenchmarkLeafSize0(b *testing.B)  { LeafSizeHelper(b, 10, 0) } // test without splitting
+func BenchmarkLeafSize1(b *testing.B)  { LeafSizeHelper(b, 10, 1) }
+func BenchmarkLeafSize2(b *testing.B)  { LeafSizeHelper(b, 10, 2) }
+func BenchmarkLeafSize3(b *testing.B)  { LeafSizeHelper(b, 10, 3) }
+func BenchmarkLeafSize4(b *testing.B)  { LeafSizeHelper(b, 10, 4) }
+func BenchmarkLeafSize5(b *testing.B)  { LeafSizeHelper(b, 10, 5) }
+func BenchmarkLeafSize6(b *testing.B)  { LeafSizeHelper(b, 10, 6) }
+func BenchmarkLeafSize7(b *testing.B)  { LeafSizeHelper(b, 10, 7) }
+func BenchmarkLeafSize8(b *testing.B)  { LeafSizeHelper(b, 10, 8) }
+func BenchmarkLeafSize9(b *testing.B)  { LeafSizeHelper(b, 10, 9) }
+func BenchmarkLeafSize10(b *testing.B) { LeafSizeHelper(b, 10, 10) }
+func BenchmarkLeafSize11(b *testing.B) { LeafSizeHelper(b, 10, 11) }
+func BenchmarkLeafSize12(b *testing.B) { LeafSizeHelper(b, 10, 12) }
+func BenchmarkLeafSize13(b *testing.B) { LeafSizeHelper(b, 10, 13) }
+func BenchmarkLeafSize14(b *testing.B) { LeafSizeHelper(b, 10, 14) }
+func BenchmarkLeafSize15(b *testing.B) { LeafSizeHelper(b, 10, 15) }
+func BenchmarkLeafSize16(b *testing.B) { LeafSizeHelper(b, 10, 16) }
+func BenchmarkLeafSize32(b *testing.B) { LeafSizeHelper(b, 10, 32) } // try some large lengths
+func BenchmarkLeafSize64(b *testing.B) { LeafSizeHelper(b, 10, 64) }
+
+func LeafSizeHelper(b *testing.B, base Word, size int) {
+	b.StopTimer()
+	originalLeafSize := leafSize
+	resetTable(cacheBase10.table[:])
+	leafSize = size
+	b.StartTimer()
+
+	for d := 1; d <= 10000; d *= 10 {
+		b.StopTimer()
+		var z nat
+		z = z.expWW(base, Word(d))           // build target number
+		_ = z.string(lowercaseDigits[:base]) // warm divisor cache
+		b.StartTimer()
+
+		for i := 0; i < b.N; i++ {
+			_ = z.string(lowercaseDigits[:base])
+		}
+	}
+
+	b.StopTimer()
+	resetTable(cacheBase10.table[:])
+	leafSize = originalLeafSize
+	b.StartTimer()
+}
+
+func resetTable(table []divisor) {
+	if table != nil && table[0].bbb != nil {
+		for i := 0; i < len(table); i++ {
+			table[i].bbb = nil
+			table[i].nbits = 0
+			table[i].ndigits = 0
+		}
+	}
+}
+
+func TestStringPowers(t *testing.T) {
+	var b, p Word
+	for b = 2; b <= 16; b++ {
+		for p = 0; p <= 512; p++ {
+			x := nat(nil).expWW(b, p)
+			xs := x.string(lowercaseDigits[:b])
+			xs2 := toString(x, lowercaseDigits[:b])
+			if xs != xs2 {
+				t.Errorf("failed at %d ** %d in base %d: %s != %s", b, p, b, xs, xs2)
+			}
+		}
+		if b >= 3 && testing.Short() {
+			break
+		}
+	}
+}
diff --git a/src/math/big/rat.go b/src/math/big/rat.go
index c5339fe..fb16f18 100644
--- a/src/math/big/rat.go
+++ b/src/math/big/rat.go
@@ -11,7 +11,6 @@ import (
 	"errors"
 	"fmt"
 	"math"
-	"strings"
 )
 
 // A Rat represents a quotient a/b of arbitrary precision.
@@ -324,14 +323,14 @@ func (z *Rat) SetFrac64(a, b int64) *Rat {
 // SetInt sets z to x (by making a copy of x) and returns z.
 func (z *Rat) SetInt(x *Int) *Rat {
 	z.a.Set(x)
-	z.b.abs = z.b.abs.make(0)
+	z.b.abs = z.b.abs[:0]
 	return z
 }
 
 // SetInt64 sets z to x and returns z.
 func (z *Rat) SetInt64(x int64) *Rat {
 	z.a.SetInt64(x)
-	z.b.abs = z.b.abs.make(0)
+	z.b.abs = z.b.abs[:0]
 	return z
 }
 
@@ -370,7 +369,7 @@ func (z *Rat) Inv(x *Rat) *Rat {
 	}
 	b := z.a.abs
 	if b.cmp(natOne) == 0 {
-		b = b.make(0) // normalize denominator
+		b = b[:0] // normalize denominator
 	}
 	z.a.abs, z.b.abs = a, b // sign doesn't change
 	return z
@@ -386,7 +385,7 @@ func (x *Rat) Sign() int {
 	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
 }
@@ -415,12 +414,12 @@ func (z *Rat) norm() *Rat {
 	case len(z.a.abs) == 0:
 		// z == 0 - normalize sign and denominator
 		z.a.neg = false
-		z.b.abs = z.b.abs.make(0)
+		z.b.abs = z.b.abs[:0]
 	case len(z.b.abs) == 0:
 		// z is normalized int - nothing to do
 	case z.b.abs.cmp(natOne) == 0:
 		// z is int - normalize denominator
-		z.b.abs = z.b.abs.make(0)
+		z.b.abs = z.b.abs[:0]
 	default:
 		neg := z.a.neg
 		z.a.neg = false
@@ -430,7 +429,7 @@ func (z *Rat) norm() *Rat {
 			z.b.abs, _ = z.b.abs.div(nil, z.b.abs, f.abs)
 			if z.b.abs.cmp(natOne) == 0 {
 				// z is int - normalize denominator
-				z.b.abs = z.b.abs.make(0)
+				z.b.abs = z.b.abs[:0]
 			}
 		}
 		z.a.neg = neg
@@ -512,151 +511,6 @@ func (z *Rat) Quo(x, y *Rat) *Rat {
 	return z.norm()
 }
 
-func ratTok(ch rune) bool {
-	return strings.IndexRune("+-/0123456789.eE", ch) >= 0
-}
-
-// Scan is a support routine for fmt.Scanner. It accepts the formats
-// 'e', 'E', 'f', 'F', 'g', 'G', and 'v'. All formats are equivalent.
-func (z *Rat) Scan(s fmt.ScanState, ch rune) error {
-	tok, err := s.Token(true, ratTok)
-	if err != nil {
-		return err
-	}
-	if strings.IndexRune("efgEFGv", ch) < 0 {
-		return errors.New("Rat.Scan: invalid verb")
-	}
-	if _, ok := z.SetString(string(tok)); !ok {
-		return errors.New("Rat.Scan: invalid syntax")
-	}
-	return nil
-}
-
-// SetString sets z to the value of s and returns z and a boolean indicating
-// success. s can be given as a fraction "a/b" or as a floating-point number
-// optionally followed by an exponent. If the operation failed, the value of
-// z is undefined but the returned value is nil.
-func (z *Rat) SetString(s string) (*Rat, bool) {
-	if len(s) == 0 {
-		return nil, false
-	}
-
-	// check for a quotient
-	sep := strings.Index(s, "/")
-	if sep >= 0 {
-		if _, ok := z.a.SetString(s[0:sep], 10); !ok {
-			return nil, false
-		}
-		s = s[sep+1:]
-		var err error
-		if z.b.abs, _, err = z.b.abs.scan(strings.NewReader(s), 10); err != nil {
-			return nil, false
-		}
-		if len(z.b.abs) == 0 {
-			return nil, false
-		}
-		return z.norm(), true
-	}
-
-	// check for a decimal point
-	sep = strings.Index(s, ".")
-	// check for an exponent
-	e := strings.IndexAny(s, "eE")
-	var exp Int
-	if e >= 0 {
-		if e < sep {
-			// The E must come after the decimal point.
-			return nil, false
-		}
-		if _, ok := exp.SetString(s[e+1:], 10); !ok {
-			return nil, false
-		}
-		s = s[0:e]
-	}
-	if sep >= 0 {
-		s = s[0:sep] + s[sep+1:]
-		exp.Sub(&exp, NewInt(int64(len(s)-sep)))
-	}
-
-	if _, ok := z.a.SetString(s, 10); !ok {
-		return nil, false
-	}
-	powTen := nat(nil).expNN(natTen, exp.abs, nil)
-	if exp.neg {
-		z.b.abs = powTen
-		z.norm()
-	} else {
-		z.a.abs = z.a.abs.mul(z.a.abs, powTen)
-		z.b.abs = z.b.abs.make(0)
-	}
-
-	return z, true
-}
-
-// String returns a string representation of x in the form "a/b" (even if b == 1).
-func (x *Rat) String() string {
-	s := "/1"
-	if len(x.b.abs) != 0 {
-		s = "/" + x.b.abs.decimalString()
-	}
-	return x.a.String() + s
-}
-
-// RatString returns a string representation of x in the form "a/b" if b != 1,
-// and in the form "a" if b == 1.
-func (x *Rat) RatString() string {
-	if x.IsInt() {
-		return x.a.String()
-	}
-	return x.String()
-}
-
-// FloatString returns a string representation of x in decimal form with prec
-// digits of precision after the decimal point and the last digit rounded.
-func (x *Rat) FloatString(prec int) string {
-	if x.IsInt() {
-		s := x.a.String()
-		if prec > 0 {
-			s += "." + strings.Repeat("0", prec)
-		}
-		return s
-	}
-	// x.b.abs != 0
-
-	q, r := nat(nil).div(nat(nil), x.a.abs, x.b.abs)
-
-	p := natOne
-	if prec > 0 {
-		p = nat(nil).expNN(natTen, nat(nil).setUint64(uint64(prec)), nil)
-	}
-
-	r = r.mul(r, p)
-	r, r2 := r.div(nat(nil), r, x.b.abs)
-
-	// see if we need to round up
-	r2 = r2.add(r2, r2)
-	if x.b.abs.cmp(r2) <= 0 {
-		r = r.add(r, natOne)
-		if r.cmp(p) >= 0 {
-			q = nat(nil).add(q, natOne)
-			r = nat(nil).sub(r, p)
-		}
-	}
-
-	s := q.decimalString()
-	if x.a.neg {
-		s = "-" + s
-	}
-
-	if prec > 0 {
-		rs := r.decimalString()
-		leadingZeros := prec - len(rs)
-		s += "." + strings.Repeat("0", leadingZeros) + rs
-	}
-
-	return s
-}
-
 // Gob codec version. Permits backward-compatible changes to the encoding.
 const ratGobVersion byte = 1
 
@@ -667,7 +521,7 @@ func (x *Rat) GobEncode() ([]byte, error) {
 	}
 	buf := make([]byte, 1+4+(len(x.a.abs)+len(x.b.abs))*_S) // extra bytes for version and sign bit (1), and numerator length (4)
 	i := x.b.abs.bytes(buf)
-	j := x.a.abs.bytes(buf[0:i])
+	j := x.a.abs.bytes(buf[:i])
 	n := i - j
 	if int(uint32(n)) != n {
 		// this should never happen
@@ -692,7 +546,7 @@ func (z *Rat) GobDecode(buf []byte) error {
 	}
 	b := buf[0]
 	if b>>1 != ratGobVersion {
-		return errors.New(fmt.Sprintf("Rat.GobDecode: encoding version %d not supported", b>>1))
+		return fmt.Errorf("Rat.GobDecode: encoding version %d not supported", b>>1)
 	}
 	const j = 1 + 4
 	i := j + binary.BigEndian.Uint32(buf[j-4:j])
diff --git a/src/math/big/rat_test.go b/src/math/big/rat_test.go
index 5dbbb35..012d0c4 100644
--- a/src/math/big/rat_test.go
+++ b/src/math/big/rat_test.go
@@ -9,10 +9,7 @@ import (
 	"encoding/gob"
 	"encoding/json"
 	"encoding/xml"
-	"fmt"
 	"math"
-	"strconv"
-	"strings"
 	"testing"
 )
 
@@ -56,112 +53,6 @@ func TestZeroRat(t *testing.T) {
 	z.Quo(&x, &y)
 }
 
-var setStringTests = []struct {
-	in, out string
-	ok      bool
-}{
-	{"0", "0", true},
-	{"-0", "0", true},
-	{"1", "1", true},
-	{"-1", "-1", true},
-	{"1.", "1", true},
-	{"1e0", "1", true},
-	{"1.e1", "10", true},
-	{in: "1e", ok: false},
-	{in: "1.e", ok: false},
-	{in: "1e+14e-5", ok: false},
-	{in: "1e4.5", ok: false},
-	{in: "r", ok: false},
-	{in: "a/b", ok: false},
-	{in: "a.b", ok: false},
-	{"-0.1", "-1/10", true},
-	{"-.1", "-1/10", true},
-	{"2/4", "1/2", true},
-	{".25", "1/4", true},
-	{"-1/5", "-1/5", true},
-	{"8129567.7690E14", "812956776900000000000", true},
-	{"78189e+4", "781890000", true},
-	{"553019.8935e+8", "55301989350000", true},
-	{"98765432109876543210987654321e-10", "98765432109876543210987654321/10000000000", true},
-	{"9877861857500000E-7", "3951144743/4", true},
-	{"2169378.417e-3", "2169378417/1000000", true},
-	{"884243222337379604041632732738665534", "884243222337379604041632732738665534", true},
-	{"53/70893980658822810696", "53/70893980658822810696", true},
-	{"106/141787961317645621392", "53/70893980658822810696", true},
-	{"204211327800791583.81095", "4084226556015831676219/20000", true},
-	{in: "1/0", ok: false},
-}
-
-func TestRatSetString(t *testing.T) {
-	for i, test := range setStringTests {
-		x, ok := new(Rat).SetString(test.in)
-
-		if ok {
-			if !test.ok {
-				t.Errorf("#%d SetString(%q) expected failure", i, test.in)
-			} else if x.RatString() != test.out {
-				t.Errorf("#%d SetString(%q) got %s want %s", i, test.in, x.RatString(), test.out)
-			}
-		} else if x != nil {
-			t.Errorf("#%d SetString(%q) got %p want nil", i, test.in, x)
-		}
-	}
-}
-
-func TestRatScan(t *testing.T) {
-	var buf bytes.Buffer
-	for i, test := range setStringTests {
-		x := new(Rat)
-		buf.Reset()
-		buf.WriteString(test.in)
-
-		_, err := fmt.Fscanf(&buf, "%v", x)
-		if err == nil != test.ok {
-			if test.ok {
-				t.Errorf("#%d error: %s", i, err)
-			} else {
-				t.Errorf("#%d expected error", i)
-			}
-			continue
-		}
-		if err == nil && x.RatString() != test.out {
-			t.Errorf("#%d got %s want %s", i, x.RatString(), test.out)
-		}
-	}
-}
-
-var floatStringTests = []struct {
-	in   string
-	prec int
-	out  string
-}{
-	{"0", 0, "0"},
-	{"0", 4, "0.0000"},
-	{"1", 0, "1"},
-	{"1", 2, "1.00"},
-	{"-1", 0, "-1"},
-	{".25", 2, "0.25"},
-	{".25", 1, "0.3"},
-	{".25", 3, "0.250"},
-	{"-1/3", 3, "-0.333"},
-	{"-2/3", 4, "-0.6667"},
-	{"0.96", 1, "1.0"},
-	{"0.999", 2, "1.00"},
-	{"0.9", 0, "1"},
-	{".25", -1, "0"},
-	{".55", -1, "1"},
-}
-
-func TestFloatString(t *testing.T) {
-	for i, test := range floatStringTests {
-		x, _ := new(Rat).SetString(test.in)
-
-		if x.FloatString(test.prec) != test.out {
-			t.Errorf("#%d got %s want %s", i, x.FloatString(test.prec), test.out)
-		}
-	}
-}
-
 func TestRatSign(t *testing.T) {
 	zero := NewRat(0, 1)
 	for _, a := range setStringTests {
@@ -592,321 +483,6 @@ func TestIssue3521(t *testing.T) {
 	}
 }
 
-// Test inputs to Rat.SetString.  The prefix "long:" causes the test
-// to be skipped in --test.short mode.  (The threshold is about 500us.)
-var float64inputs = []string{
-	// Constants plundered from strconv/testfp.txt.
-
-	// Table 1: Stress Inputs for Conversion to 53-bit Binary, < 1/2 ULP
-	"5e+125",
-	"69e+267",
-	"999e-026",
-	"7861e-034",
-	"75569e-254",
-	"928609e-261",
-	"9210917e+080",
-	"84863171e+114",
-	"653777767e+273",
-	"5232604057e-298",
-	"27235667517e-109",
-	"653532977297e-123",
-	"3142213164987e-294",
-	"46202199371337e-072",
-	"231010996856685e-073",
-	"9324754620109615e+212",
-	"78459735791271921e+049",
-	"272104041512242479e+200",
-	"6802601037806061975e+198",
-	"20505426358836677347e-221",
-	"836168422905420598437e-234",
-	"4891559871276714924261e+222",
-
-	// Table 2: Stress Inputs for Conversion to 53-bit Binary, > 1/2 ULP
-	"9e-265",
-	"85e-037",
-	"623e+100",
-	"3571e+263",
-	"81661e+153",
-	"920657e-023",
-	"4603285e-024",
-	"87575437e-309",
-	"245540327e+122",
-	"6138508175e+120",
-	"83356057653e+193",
-	"619534293513e+124",
-	"2335141086879e+218",
-	"36167929443327e-159",
-	"609610927149051e-255",
-	"3743626360493413e-165",
-	"94080055902682397e-242",
-	"899810892172646163e+283",
-	"7120190517612959703e+120",
-	"25188282901709339043e-252",
-	"308984926168550152811e-052",
-	"6372891218502368041059e+064",
-
-	// Table 14: Stress Inputs for Conversion to 24-bit Binary, <1/2 ULP
-	"5e-20",
-	"67e+14",
-	"985e+15",
-	"7693e-42",
-	"55895e-16",
-	"996622e-44",
-	"7038531e-32",
-	"60419369e-46",
-	"702990899e-20",
-	"6930161142e-48",
-	"25933168707e+13",
-	"596428896559e+20",
-
-	// Table 15: Stress Inputs for Conversion to 24-bit Binary, >1/2 ULP
-	"3e-23",
-	"57e+18",
-	"789e-35",
-	"2539e-18",
-	"76173e+28",
-	"887745e-11",
-	"5382571e-37",
-	"82381273e-35",
-	"750486563e-38",
-	"3752432815e-39",
-	"75224575729e-45",
-	"459926601011e+15",
-
-	// Constants plundered from strconv/atof_test.go.
-
-	"0",
-	"1",
-	"+1",
-	"1e23",
-	"1E23",
-	"100000000000000000000000",
-	"1e-100",
-	"123456700",
-	"99999999999999974834176",
-	"100000000000000000000001",
-	"100000000000000008388608",
-	"100000000000000016777215",
-	"100000000000000016777216",
-	"-1",
-	"-0.1",
-	"-0", // NB: exception made for this input
-	"1e-20",
-	"625e-3",
-
-	// largest float64
-	"1.7976931348623157e308",
-	"-1.7976931348623157e308",
-	// next float64 - too large
-	"1.7976931348623159e308",
-	"-1.7976931348623159e308",
-	// the border is ...158079
-	// borderline - okay
-	"1.7976931348623158e308",
-	"-1.7976931348623158e308",
-	// borderline - too large
-	"1.797693134862315808e308",
-	"-1.797693134862315808e308",
-
-	// a little too large
-	"1e308",
-	"2e308",
-	"1e309",
-
-	// way too large
-	"1e310",
-	"-1e310",
-	"1e400",
-	"-1e400",
-	"long:1e400000",
-	"long:-1e400000",
-
-	// denormalized
-	"1e-305",
-	"1e-306",
-	"1e-307",
-	"1e-308",
-	"1e-309",
-	"1e-310",
-	"1e-322",
-	// smallest denormal
-	"5e-324",
-	"4e-324",
-	"3e-324",
-	// too small
-	"2e-324",
-	// way too small
-	"1e-350",
-	"long:1e-400000",
-	// way too small, negative
-	"-1e-350",
-	"long:-1e-400000",
-
-	// try to overflow exponent
-	// [Disabled: too slow and memory-hungry with rationals.]
-	// "1e-4294967296",
-	// "1e+4294967296",
-	// "1e-18446744073709551616",
-	// "1e+18446744073709551616",
-
-	// http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/
-	"2.2250738585072012e-308",
-	// http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/
-	"2.2250738585072011e-308",
-
-	// A very large number (initially wrongly parsed by the fast algorithm).
-	"4.630813248087435e+307",
-
-	// A different kind of very large number.
-	"22.222222222222222",
-	"long:2." + strings.Repeat("2", 4000) + "e+1",
-
-	// Exactly halfway between 1 and math.Nextafter(1, 2).
-	// Round to even (down).
-	"1.00000000000000011102230246251565404236316680908203125",
-	// Slightly lower; still round down.
-	"1.00000000000000011102230246251565404236316680908203124",
-	// Slightly higher; round up.
-	"1.00000000000000011102230246251565404236316680908203126",
-	// Slightly higher, but you have to read all the way to the end.
-	"long:1.00000000000000011102230246251565404236316680908203125" + strings.Repeat("0", 10000) + "1",
-
-	// Smallest denormal, 2^(-1022-52)
-	"4.940656458412465441765687928682213723651e-324",
-	// Half of smallest denormal, 2^(-1022-53)
-	"2.470328229206232720882843964341106861825e-324",
-	// A little more than the exact half of smallest denormal
-	// 2^-1075 + 2^-1100.  (Rounds to 1p-1074.)
-	"2.470328302827751011111470718709768633275e-324",
-	// The exact halfway between smallest normal and largest denormal:
-	// 2^-1022 - 2^-1075.  (Rounds to 2^-1022.)
-	"2.225073858507201136057409796709131975935e-308",
-
-	"1152921504606846975",  //   1<<60 - 1
-	"-1152921504606846975", // -(1<<60 - 1)
-	"1152921504606846977",  //   1<<60 + 1
-	"-1152921504606846977", // -(1<<60 + 1)
-
-	"1/3",
-}
-
-// isFinite reports whether f represents a finite rational value.
-// It is equivalent to !math.IsNan(f) && !math.IsInf(f, 0).
-func isFinite(f float64) bool {
-	return math.Abs(f) <= math.MaxFloat64
-}
-
-func TestFloat32SpecialCases(t *testing.T) {
-	for _, input := range float64inputs {
-		if strings.HasPrefix(input, "long:") {
-			if testing.Short() {
-				continue
-			}
-			input = input[len("long:"):]
-		}
-
-		r, ok := new(Rat).SetString(input)
-		if !ok {
-			t.Errorf("Rat.SetString(%q) failed", input)
-			continue
-		}
-		f, exact := r.Float32()
-
-		// 1. Check string -> Rat -> float32 conversions are
-		// consistent with strconv.ParseFloat.
-		// Skip this check if the input uses "a/b" rational syntax.
-		if !strings.Contains(input, "/") {
-			e64, _ := strconv.ParseFloat(input, 32)
-			e := float32(e64)
-
-			// Careful: negative Rats too small for
-			// float64 become -0, but Rat obviously cannot
-			// preserve the sign from SetString("-0").
-			switch {
-			case math.Float32bits(e) == math.Float32bits(f):
-				// Ok: bitwise equal.
-			case f == 0 && r.Num().BitLen() == 0:
-				// Ok: Rat(0) is equivalent to both +/- float64(0).
-			default:
-				t.Errorf("strconv.ParseFloat(%q) = %g (%b), want %g (%b); delta = %g", input, e, e, f, f, f-e)
-			}
-		}
-
-		if !isFinite(float64(f)) {
-			continue
-		}
-
-		// 2. Check f is best approximation to r.
-		if !checkIsBestApprox32(t, f, r) {
-			// Append context information.
-			t.Errorf("(input was %q)", input)
-		}
-
-		// 3. Check f->R->f roundtrip is non-lossy.
-		checkNonLossyRoundtrip32(t, f)
-
-		// 4. Check exactness using slow algorithm.
-		if wasExact := new(Rat).SetFloat64(float64(f)).Cmp(r) == 0; wasExact != exact {
-			t.Errorf("Rat.SetString(%q).Float32().exact = %t, want %t", input, exact, wasExact)
-		}
-	}
-}
-
-func TestFloat64SpecialCases(t *testing.T) {
-	for _, input := range float64inputs {
-		if strings.HasPrefix(input, "long:") {
-			if testing.Short() {
-				continue
-			}
-			input = input[len("long:"):]
-		}
-
-		r, ok := new(Rat).SetString(input)
-		if !ok {
-			t.Errorf("Rat.SetString(%q) failed", input)
-			continue
-		}
-		f, exact := r.Float64()
-
-		// 1. Check string -> Rat -> float64 conversions are
-		// consistent with strconv.ParseFloat.
-		// Skip this check if the input uses "a/b" rational syntax.
-		if !strings.Contains(input, "/") {
-			e, _ := strconv.ParseFloat(input, 64)
-
-			// Careful: negative Rats too small for
-			// float64 become -0, but Rat obviously cannot
-			// preserve the sign from SetString("-0").
-			switch {
-			case math.Float64bits(e) == math.Float64bits(f):
-				// Ok: bitwise equal.
-			case f == 0 && r.Num().BitLen() == 0:
-				// Ok: Rat(0) is equivalent to both +/- float64(0).
-			default:
-				t.Errorf("strconv.ParseFloat(%q) = %g (%b), want %g (%b); delta = %g", input, e, e, f, f, f-e)
-			}
-		}
-
-		if !isFinite(f) {
-			continue
-		}
-
-		// 2. Check f is best approximation to r.
-		if !checkIsBestApprox64(t, f, r) {
-			// Append context information.
-			t.Errorf("(input was %q)", input)
-		}
-
-		// 3. Check f->R->f roundtrip is non-lossy.
-		checkNonLossyRoundtrip64(t, f)
-
-		// 4. Check exactness using slow algorithm.
-		if wasExact := new(Rat).SetFloat64(f).Cmp(r) == 0; wasExact != exact {
-			t.Errorf("Rat.SetString(%q).Float64().exact = %t, want %t", input, exact, wasExact)
-		}
-	}
-}
-
 func TestFloat32Distribution(t *testing.T) {
 	// Generate a distribution of (sign, mantissa, exp) values
 	// broader than the float32 range, and check Rat.Float32()
diff --git a/src/math/big/ratconv.go b/src/math/big/ratconv.go
new file mode 100644
index 0000000..961ff64
--- /dev/null
+++ b/src/math/big/ratconv.go
@@ -0,0 +1,252 @@
+// 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 rat-to-string conversion functions.
+
+package big
+
+import (
+	"errors"
+	"fmt"
+	"io"
+	"strconv"
+	"strings"
+)
+
+func ratTok(ch rune) bool {
+	return strings.IndexRune("+-/0123456789.eE", ch) >= 0
+}
+
+// Scan is a support routine for fmt.Scanner. It accepts the formats
+// 'e', 'E', 'f', 'F', 'g', 'G', and 'v'. All formats are equivalent.
+func (z *Rat) Scan(s fmt.ScanState, ch rune) error {
+	tok, err := s.Token(true, ratTok)
+	if err != nil {
+		return err
+	}
+	if strings.IndexRune("efgEFGv", ch) < 0 {
+		return errors.New("Rat.Scan: invalid verb")
+	}
+	if _, ok := z.SetString(string(tok)); !ok {
+		return errors.New("Rat.Scan: invalid syntax")
+	}
+	return nil
+}
+
+// SetString sets z to the value of s and returns z and a boolean indicating
+// success. s can be given as a fraction "a/b" or as a floating-point number
+// optionally followed by an exponent. If the operation failed, the value of
+// z is undefined but the returned value is nil.
+func (z *Rat) SetString(s string) (*Rat, bool) {
+	if len(s) == 0 {
+		return nil, false
+	}
+	// len(s) > 0
+
+	// parse fraction a/b, if any
+	if sep := strings.Index(s, "/"); sep >= 0 {
+		if _, ok := z.a.SetString(s[:sep], 0); !ok {
+			return nil, false
+		}
+		s = s[sep+1:]
+		var err error
+		if z.b.abs, _, _, err = z.b.abs.scan(strings.NewReader(s), 0, false); err != nil {
+			return nil, false
+		}
+		if len(z.b.abs) == 0 {
+			return nil, false
+		}
+		return z.norm(), true
+	}
+
+	// parse floating-point number
+	r := strings.NewReader(s)
+
+	// sign
+	neg, err := scanSign(r)
+	if err != nil {
+		return nil, false
+	}
+
+	// mantissa
+	var ecorr int
+	z.a.abs, _, ecorr, err = z.a.abs.scan(r, 10, true)
+	if err != nil {
+		return nil, false
+	}
+
+	// exponent
+	var exp int64
+	exp, _, err = scanExponent(r, false)
+	if err != nil {
+		return nil, false
+	}
+
+	// there should be no unread characters left
+	if _, err = r.ReadByte(); err != io.EOF {
+		return nil, false
+	}
+
+	// correct exponent
+	if ecorr < 0 {
+		exp += int64(ecorr)
+	}
+
+	// compute exponent power
+	expabs := exp
+	if expabs < 0 {
+		expabs = -expabs
+	}
+	powTen := nat(nil).expNN(natTen, nat(nil).setWord(Word(expabs)), nil)
+
+	// complete fraction
+	if exp < 0 {
+		z.b.abs = powTen
+		z.norm()
+	} else {
+		z.a.abs = z.a.abs.mul(z.a.abs, powTen)
+		z.b.abs = z.b.abs[:0]
+	}
+
+	z.a.neg = neg && len(z.a.abs) > 0 // 0 has no sign
+
+	return z, true
+}
+
+// scanExponent scans the longest possible prefix of r representing a decimal
+// ('e', 'E') or binary ('p') exponent, if any. It returns the exponent, the
+// exponent base (10 or 2), or a read or syntax error, if any.
+//
+//	exponent = ( "E" | "e" | "p" ) [ sign ] digits .
+//	sign     = "+" | "-" .
+//	digits   = digit { digit } .
+//	digit    = "0" ... "9" .
+//
+// A binary exponent is only permitted if binExpOk is set.
+func scanExponent(r io.ByteScanner, binExpOk bool) (exp int64, base int, err error) {
+	base = 10
+
+	var ch byte
+	if ch, err = r.ReadByte(); err != nil {
+		if err == io.EOF {
+			err = nil // no exponent; same as e0
+		}
+		return
+	}
+
+	switch ch {
+	case 'e', 'E':
+		// ok
+	case 'p':
+		if binExpOk {
+			base = 2
+			break // ok
+		}
+		fallthrough // binary exponent not permitted
+	default:
+		r.UnreadByte()
+		return // no exponent; same as e0
+	}
+
+	var neg bool
+	if neg, err = scanSign(r); err != nil {
+		return
+	}
+
+	var digits []byte
+	if neg {
+		digits = append(digits, '-')
+	}
+
+	// no need to use nat.scan for exponent digits
+	// since we only care about int64 values - the
+	// from-scratch scan is easy enough and faster
+	for i := 0; ; i++ {
+		if ch, err = r.ReadByte(); err != nil {
+			if err != io.EOF || i == 0 {
+				return
+			}
+			err = nil
+			break // i > 0
+		}
+		if ch < '0' || '9' < ch {
+			if i == 0 {
+				r.UnreadByte()
+				err = fmt.Errorf("invalid exponent (missing digits)")
+				return
+			}
+			break // i > 0
+		}
+		digits = append(digits, byte(ch))
+	}
+	// i > 0 => we have at least one digit
+
+	exp, err = strconv.ParseInt(string(digits), 10, 64)
+	return
+}
+
+// String returns a string representation of x in the form "a/b" (even if b == 1).
+func (x *Rat) String() string {
+	s := "/1"
+	if len(x.b.abs) != 0 {
+		s = "/" + x.b.abs.decimalString()
+	}
+	return x.a.String() + s
+}
+
+// RatString returns a string representation of x in the form "a/b" if b != 1,
+// and in the form "a" if b == 1.
+func (x *Rat) RatString() string {
+	if x.IsInt() {
+		return x.a.String()
+	}
+	return x.String()
+}
+
+// FloatString returns a string representation of x in decimal form with prec
+// digits of precision after the decimal point. The last digit is rounded to
+// nearest, with halves rounded away from zero.
+func (x *Rat) FloatString(prec int) string {
+	if x.IsInt() {
+		s := x.a.String()
+		if prec > 0 {
+			s += "." + strings.Repeat("0", prec)
+		}
+		return s
+	}
+	// x.b.abs != 0
+
+	q, r := nat(nil).div(nat(nil), x.a.abs, x.b.abs)
+
+	p := natOne
+	if prec > 0 {
+		p = nat(nil).expNN(natTen, nat(nil).setUint64(uint64(prec)), nil)
+	}
+
+	r = r.mul(r, p)
+	r, r2 := r.div(nat(nil), r, x.b.abs)
+
+	// see if we need to round up
+	r2 = r2.add(r2, r2)
+	if x.b.abs.cmp(r2) <= 0 {
+		r = r.add(r, natOne)
+		if r.cmp(p) >= 0 {
+			q = nat(nil).add(q, natOne)
+			r = nat(nil).sub(r, p)
+		}
+	}
+
+	s := q.decimalString()
+	if x.a.neg {
+		s = "-" + s
+	}
+
+	if prec > 0 {
+		rs := r.decimalString()
+		leadingZeros := prec - len(rs)
+		s += "." + strings.Repeat("0", leadingZeros) + rs
+	}
+
+	return s
+}
diff --git a/src/math/big/ratconv_test.go b/src/math/big/ratconv_test.go
new file mode 100644
index 0000000..da2fdab
--- /dev/null
+++ b/src/math/big/ratconv_test.go
@@ -0,0 +1,453 @@
+// 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
+
+import (
+	"bytes"
+	"fmt"
+	"math"
+	"strconv"
+	"strings"
+	"testing"
+)
+
+type StringTest struct {
+	in, out string
+	ok      bool
+}
+
+var setStringTests = []StringTest{
+	{"0", "0", true},
+	{"-0", "0", true},
+	{"1", "1", true},
+	{"-1", "-1", true},
+	{"1.", "1", true},
+	{"1e0", "1", true},
+	{"1.e1", "10", true},
+	{in: "1e"},
+	{in: "1.e"},
+	{in: "1e+14e-5"},
+	{in: "1e4.5"},
+	{in: "r"},
+	{in: "a/b"},
+	{in: "a.b"},
+	{"-0.1", "-1/10", true},
+	{"-.1", "-1/10", true},
+	{"2/4", "1/2", true},
+	{".25", "1/4", true},
+	{"-1/5", "-1/5", true},
+	{"8129567.7690E14", "812956776900000000000", true},
+	{"78189e+4", "781890000", true},
+	{"553019.8935e+8", "55301989350000", true},
+	{"98765432109876543210987654321e-10", "98765432109876543210987654321/10000000000", true},
+	{"9877861857500000E-7", "3951144743/4", true},
+	{"2169378.417e-3", "2169378417/1000000", true},
+	{"884243222337379604041632732738665534", "884243222337379604041632732738665534", true},
+	{"53/70893980658822810696", "53/70893980658822810696", true},
+	{"106/141787961317645621392", "53/70893980658822810696", true},
+	{"204211327800791583.81095", "4084226556015831676219/20000", true},
+	{in: "1/0"},
+}
+
+// These are not supported by fmt.Fscanf.
+var setStringTests2 = []StringTest{
+	{"0x10", "16", true},
+	{"-010/1", "-8", true}, // TODO(gri) should we even permit octal here?
+	{"-010.", "-10", true},
+	{"0x10/0x20", "1/2", true},
+	{"0b1000/3", "8/3", true},
+	// TODO(gri) add more tests
+}
+
+func TestRatSetString(t *testing.T) {
+	var tests []StringTest
+	tests = append(tests, setStringTests...)
+	tests = append(tests, setStringTests2...)
+
+	for i, test := range tests {
+		x, ok := new(Rat).SetString(test.in)
+
+		if ok {
+			if !test.ok {
+				t.Errorf("#%d SetString(%q) expected failure", i, test.in)
+			} else if x.RatString() != test.out {
+				t.Errorf("#%d SetString(%q) got %s want %s", i, test.in, x.RatString(), test.out)
+			}
+		} else if x != nil {
+			t.Errorf("#%d SetString(%q) got %p want nil", i, test.in, x)
+		}
+	}
+}
+
+func TestRatScan(t *testing.T) {
+	var buf bytes.Buffer
+	for i, test := range setStringTests {
+		x := new(Rat)
+		buf.Reset()
+		buf.WriteString(test.in)
+
+		_, err := fmt.Fscanf(&buf, "%v", x)
+		if err == nil != test.ok {
+			if test.ok {
+				t.Errorf("#%d (%s) error: %s", i, test.in, err)
+			} else {
+				t.Errorf("#%d (%s) expected error", i, test.in)
+			}
+			continue
+		}
+		if err == nil && x.RatString() != test.out {
+			t.Errorf("#%d got %s want %s", i, x.RatString(), test.out)
+		}
+	}
+}
+
+var floatStringTests = []struct {
+	in   string
+	prec int
+	out  string
+}{
+	{"0", 0, "0"},
+	{"0", 4, "0.0000"},
+	{"1", 0, "1"},
+	{"1", 2, "1.00"},
+	{"-1", 0, "-1"},
+	{"0.05", 1, "0.1"},
+	{"-0.05", 1, "-0.1"},
+	{".25", 2, "0.25"},
+	{".25", 1, "0.3"},
+	{".25", 3, "0.250"},
+	{"-1/3", 3, "-0.333"},
+	{"-2/3", 4, "-0.6667"},
+	{"0.96", 1, "1.0"},
+	{"0.999", 2, "1.00"},
+	{"0.9", 0, "1"},
+	{".25", -1, "0"},
+	{".55", -1, "1"},
+}
+
+func TestFloatString(t *testing.T) {
+	for i, test := range floatStringTests {
+		x, _ := new(Rat).SetString(test.in)
+
+		if x.FloatString(test.prec) != test.out {
+			t.Errorf("#%d got %s want %s", i, x.FloatString(test.prec), test.out)
+		}
+	}
+}
+
+// Test inputs to Rat.SetString.  The prefix "long:" causes the test
+// to be skipped in --test.short mode.  (The threshold is about 500us.)
+var float64inputs = []string{
+	// Constants plundered from strconv/testfp.txt.
+
+	// Table 1: Stress Inputs for Conversion to 53-bit Binary, < 1/2 ULP
+	"5e+125",
+	"69e+267",
+	"999e-026",
+	"7861e-034",
+	"75569e-254",
+	"928609e-261",
+	"9210917e+080",
+	"84863171e+114",
+	"653777767e+273",
+	"5232604057e-298",
+	"27235667517e-109",
+	"653532977297e-123",
+	"3142213164987e-294",
+	"46202199371337e-072",
+	"231010996856685e-073",
+	"9324754620109615e+212",
+	"78459735791271921e+049",
+	"272104041512242479e+200",
+	"6802601037806061975e+198",
+	"20505426358836677347e-221",
+	"836168422905420598437e-234",
+	"4891559871276714924261e+222",
+
+	// Table 2: Stress Inputs for Conversion to 53-bit Binary, > 1/2 ULP
+	"9e-265",
+	"85e-037",
+	"623e+100",
+	"3571e+263",
+	"81661e+153",
+	"920657e-023",
+	"4603285e-024",
+	"87575437e-309",
+	"245540327e+122",
+	"6138508175e+120",
+	"83356057653e+193",
+	"619534293513e+124",
+	"2335141086879e+218",
+	"36167929443327e-159",
+	"609610927149051e-255",
+	"3743626360493413e-165",
+	"94080055902682397e-242",
+	"899810892172646163e+283",
+	"7120190517612959703e+120",
+	"25188282901709339043e-252",
+	"308984926168550152811e-052",
+	"6372891218502368041059e+064",
+
+	// Table 14: Stress Inputs for Conversion to 24-bit Binary, <1/2 ULP
+	"5e-20",
+	"67e+14",
+	"985e+15",
+	"7693e-42",
+	"55895e-16",
+	"996622e-44",
+	"7038531e-32",
+	"60419369e-46",
+	"702990899e-20",
+	"6930161142e-48",
+	"25933168707e+13",
+	"596428896559e+20",
+
+	// Table 15: Stress Inputs for Conversion to 24-bit Binary, >1/2 ULP
+	"3e-23",
+	"57e+18",
+	"789e-35",
+	"2539e-18",
+	"76173e+28",
+	"887745e-11",
+	"5382571e-37",
+	"82381273e-35",
+	"750486563e-38",
+	"3752432815e-39",
+	"75224575729e-45",
+	"459926601011e+15",
+
+	// Constants plundered from strconv/atof_test.go.
+
+	"0",
+	"1",
+	"+1",
+	"1e23",
+	"1E23",
+	"100000000000000000000000",
+	"1e-100",
+	"123456700",
+	"99999999999999974834176",
+	"100000000000000000000001",
+	"100000000000000008388608",
+	"100000000000000016777215",
+	"100000000000000016777216",
+	"-1",
+	"-0.1",
+	"-0", // NB: exception made for this input
+	"1e-20",
+	"625e-3",
+
+	// largest float64
+	"1.7976931348623157e308",
+	"-1.7976931348623157e308",
+	// next float64 - too large
+	"1.7976931348623159e308",
+	"-1.7976931348623159e308",
+	// the border is ...158079
+	// borderline - okay
+	"1.7976931348623158e308",
+	"-1.7976931348623158e308",
+	// borderline - too large
+	"1.797693134862315808e308",
+	"-1.797693134862315808e308",
+
+	// a little too large
+	"1e308",
+	"2e308",
+	"1e309",
+
+	// way too large
+	"1e310",
+	"-1e310",
+	"1e400",
+	"-1e400",
+	"long:1e400000",
+	"long:-1e400000",
+
+	// denormalized
+	"1e-305",
+	"1e-306",
+	"1e-307",
+	"1e-308",
+	"1e-309",
+	"1e-310",
+	"1e-322",
+	// smallest denormal
+	"5e-324",
+	"4e-324",
+	"3e-324",
+	// too small
+	"2e-324",
+	// way too small
+	"1e-350",
+	"long:1e-400000",
+	// way too small, negative
+	"-1e-350",
+	"long:-1e-400000",
+
+	// try to overflow exponent
+	// [Disabled: too slow and memory-hungry with rationals.]
+	// "1e-4294967296",
+	// "1e+4294967296",
+	// "1e-18446744073709551616",
+	// "1e+18446744073709551616",
+
+	// http://www.exploringbinary.com/java-hangs-when-converting-2-2250738585072012e-308/
+	"2.2250738585072012e-308",
+	// http://www.exploringbinary.com/php-hangs-on-numeric-value-2-2250738585072011e-308/
+	"2.2250738585072011e-308",
+
+	// A very large number (initially wrongly parsed by the fast algorithm).
+	"4.630813248087435e+307",
+
+	// A different kind of very large number.
+	"22.222222222222222",
+	"long:2." + strings.Repeat("2", 4000) + "e+1",
+
+	// Exactly halfway between 1 and math.Nextafter(1, 2).
+	// Round to even (down).
+	"1.00000000000000011102230246251565404236316680908203125",
+	// Slightly lower; still round down.
+	"1.00000000000000011102230246251565404236316680908203124",
+	// Slightly higher; round up.
+	"1.00000000000000011102230246251565404236316680908203126",
+	// Slightly higher, but you have to read all the way to the end.
+	"long:1.00000000000000011102230246251565404236316680908203125" + strings.Repeat("0", 10000) + "1",
+
+	// Smallest denormal, 2^(-1022-52)
+	"4.940656458412465441765687928682213723651e-324",
+	// Half of smallest denormal, 2^(-1022-53)
+	"2.470328229206232720882843964341106861825e-324",
+	// A little more than the exact half of smallest denormal
+	// 2^-1075 + 2^-1100.  (Rounds to 1p-1074.)
+	"2.470328302827751011111470718709768633275e-324",
+	// The exact halfway between smallest normal and largest denormal:
+	// 2^-1022 - 2^-1075.  (Rounds to 2^-1022.)
+	"2.225073858507201136057409796709131975935e-308",
+
+	"1152921504606846975",  //   1<<60 - 1
+	"-1152921504606846975", // -(1<<60 - 1)
+	"1152921504606846977",  //   1<<60 + 1
+	"-1152921504606846977", // -(1<<60 + 1)
+
+	"1/3",
+}
+
+// isFinite reports whether f represents a finite rational value.
+// It is equivalent to !math.IsNan(f) && !math.IsInf(f, 0).
+func isFinite(f float64) bool {
+	return math.Abs(f) <= math.MaxFloat64
+}
+
+func TestFloat32SpecialCases(t *testing.T) {
+	for _, input := range float64inputs {
+		if strings.HasPrefix(input, "long:") {
+			if testing.Short() {
+				continue
+			}
+			input = input[len("long:"):]
+		}
+
+		r, ok := new(Rat).SetString(input)
+		if !ok {
+			t.Errorf("Rat.SetString(%q) failed", input)
+			continue
+		}
+		f, exact := r.Float32()
+
+		// 1. Check string -> Rat -> float32 conversions are
+		// consistent with strconv.ParseFloat.
+		// Skip this check if the input uses "a/b" rational syntax.
+		if !strings.Contains(input, "/") {
+			e64, _ := strconv.ParseFloat(input, 32)
+			e := float32(e64)
+
+			// Careful: negative Rats too small for
+			// float64 become -0, but Rat obviously cannot
+			// preserve the sign from SetString("-0").
+			switch {
+			case math.Float32bits(e) == math.Float32bits(f):
+				// Ok: bitwise equal.
+			case f == 0 && r.Num().BitLen() == 0:
+				// Ok: Rat(0) is equivalent to both +/- float64(0).
+			default:
+				t.Errorf("strconv.ParseFloat(%q) = %g (%b), want %g (%b); delta = %g", input, e, e, f, f, f-e)
+			}
+		}
+
+		if !isFinite(float64(f)) {
+			continue
+		}
+
+		// 2. Check f is best approximation to r.
+		if !checkIsBestApprox32(t, f, r) {
+			// Append context information.
+			t.Errorf("(input was %q)", input)
+		}
+
+		// 3. Check f->R->f roundtrip is non-lossy.
+		checkNonLossyRoundtrip32(t, f)
+
+		// 4. Check exactness using slow algorithm.
+		if wasExact := new(Rat).SetFloat64(float64(f)).Cmp(r) == 0; wasExact != exact {
+			t.Errorf("Rat.SetString(%q).Float32().exact = %t, want %t", input, exact, wasExact)
+		}
+	}
+}
+
+func TestFloat64SpecialCases(t *testing.T) {
+	for _, input := range float64inputs {
+		if strings.HasPrefix(input, "long:") {
+			if testing.Short() {
+				continue
+			}
+			input = input[len("long:"):]
+		}
+
+		r, ok := new(Rat).SetString(input)
+		if !ok {
+			t.Errorf("Rat.SetString(%q) failed", input)
+			continue
+		}
+		f, exact := r.Float64()
+
+		// 1. Check string -> Rat -> float64 conversions are
+		// consistent with strconv.ParseFloat.
+		// Skip this check if the input uses "a/b" rational syntax.
+		if !strings.Contains(input, "/") {
+			e, _ := strconv.ParseFloat(input, 64)
+
+			// Careful: negative Rats too small for
+			// float64 become -0, but Rat obviously cannot
+			// preserve the sign from SetString("-0").
+			switch {
+			case math.Float64bits(e) == math.Float64bits(f):
+				// Ok: bitwise equal.
+			case f == 0 && r.Num().BitLen() == 0:
+				// Ok: Rat(0) is equivalent to both +/- float64(0).
+			default:
+				t.Errorf("strconv.ParseFloat(%q) = %g (%b), want %g (%b); delta = %g", input, e, e, f, f, f-e)
+			}
+		}
+
+		if !isFinite(f) {
+			continue
+		}
+
+		// 2. Check f is best approximation to r.
+		if !checkIsBestApprox64(t, f, r) {
+			// Append context information.
+			t.Errorf("(input was %q)", input)
+		}
+
+		// 3. Check f->R->f roundtrip is non-lossy.
+		checkNonLossyRoundtrip64(t, f)
+
+		// 4. Check exactness using slow algorithm.
+		if wasExact := new(Rat).SetFloat64(f).Cmp(r) == 0; wasExact != exact {
+			t.Errorf("Rat.SetString(%q).Float64().exact = %t, want %t", input, exact, wasExact)
+		}
+	}
+}
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/cbrt.go b/src/math/cbrt.go
index 272e309..f009faf 100644
--- a/src/math/cbrt.go
+++ b/src/math/cbrt.go
@@ -4,13 +4,17 @@
 
 package math
 
-/*
-	The algorithm is based in part on "Optimal Partitioning of
-	Newton's Method for Calculating Roots", by Gunter Meinardus
-	and G. D. Taylor, Mathematics of Computation © 1980 American
-	Mathematical Society.
-	(http://www.jstor.org/stable/2006387?seq=9, accessed 11-Feb-2010)
-*/
+// The go code is a modified version of the original C code from
+// http://www.netlib.org/fdlibm/s_cbrt.c and came with this notice.
+//
+// ====================================================
+// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+//
+// Developed at SunSoft, a Sun Microsystems, Inc. business.
+// Permission to use, copy, modify, and distribute this
+// software is freely granted, provided that this notice
+// is preserved.
+// ====================================================
 
 // Cbrt returns the cube root of x.
 //
@@ -20,57 +24,54 @@ package math
 //	Cbrt(NaN) = NaN
 func Cbrt(x float64) float64 {
 	const (
-		A1 = 1.662848358e-01
-		A2 = 1.096040958e+00
-		A3 = 4.105032829e-01
-		A4 = 5.649335816e-01
-		B1 = 2.639607233e-01
-		B2 = 8.699282849e-01
-		B3 = 1.629083358e-01
-		B4 = 2.824667908e-01
-		C1 = 4.190115298e-01
-		C2 = 6.904625373e-01
-		C3 = 6.46502159e-02
-		C4 = 1.412333954e-01
+		B1             = 715094163                   // (682-0.03306235651)*2**20
+		B2             = 696219795                   // (664-0.03306235651)*2**20
+		C              = 5.42857142857142815906e-01  // 19/35     = 0x3FE15F15F15F15F1
+		D              = -7.05306122448979611050e-01 // -864/1225 = 0xBFE691DE2532C834
+		E              = 1.41428571428571436819e+00  // 99/70     = 0x3FF6A0EA0EA0EA0F
+		F              = 1.60714285714285720630e+00  // 45/28     = 0x3FF9B6DB6DB6DB6E
+		G              = 3.57142857142857150787e-01  // 5/14      = 0x3FD6DB6DB6DB6DB7
+		SmallestNormal = 2.22507385850720138309e-308 // 2**-1022  = 0x0010000000000000
 	)
 	// special cases
 	switch {
 	case x == 0 || IsNaN(x) || IsInf(x, 0):
 		return x
 	}
+
 	sign := false
 	if x < 0 {
 		x = -x
 		sign = true
 	}
-	// Reduce argument and estimate cube root
-	f, e := Frexp(x) // 0.5 <= f < 1.0
-	m := e % 3
-	if m > 0 {
-		m -= 3
-		e -= m // e is multiple of 3
-	}
-	switch m {
-	case 0: // 0.5 <= f < 1.0
-		f = A1*f + A2 - A3/(A4+f)
-	case -1:
-		f *= 0.5 // 0.25 <= f < 0.5
-		f = B1*f + B2 - B3/(B4+f)
-	default: // m == -2
-		f *= 0.25 // 0.125 <= f < 0.25
-		f = C1*f + C2 - C3/(C4+f)
+
+	// rough cbrt to 5 bits
+	t := Float64frombits(Float64bits(x)/3 + B1<<32)
+	if x < SmallestNormal {
+		// subnormal number
+		t = float64(1 << 54) // set t= 2**54
+		t *= x
+		t = Float64frombits(Float64bits(t)/3 + B2<<32)
 	}
-	y := Ldexp(f, e/3) // e/3 = exponent of cube root
 
-	// Iterate
-	s := y * y * y
-	t := s + x
-	y *= (t + x) / (s + t)
-	// Reiterate
-	s = (y*y*y - x) / x
-	y -= y * (((14.0/81.0)*s-(2.0/9.0))*s + (1.0 / 3.0)) * s
+	// new cbrt to 23 bits
+	r := t * t / x
+	s := C + r*t
+	t *= G + F/(s+E+D/s)
+
+	// chop to 22 bits, make larger than cbrt(x)
+	t = Float64frombits(Float64bits(t)&(0xFFFFFFFFC<<28) + 1<<30)
+
+	// one step newton iteration to 53 bits with error less than 0.667ulps
+	s = t * t // t*t is exact
+	r = x / s
+	w := t + t
+	r = (r - t) / (w + r) // r-s is exact
+	t = t + t*r
+
+	// restore the sign bit
 	if sign {
-		y = -y
+		t = -t
 	}
-	return y
+	return t
 }
diff --git a/src/math/const.go b/src/math/const.go
index f1247c3..b440538 100644
--- a/src/math/const.go
+++ b/src/math/const.go
@@ -6,20 +6,19 @@
 package math
 
 // Mathematical constants.
-// Reference: http://oeis.org/Axxxxxx
 const (
-	E   = 2.71828182845904523536028747135266249775724709369995957496696763 // A001113
-	Pi  = 3.14159265358979323846264338327950288419716939937510582097494459 // A000796
-	Phi = 1.61803398874989484820458683436563811772030917980576286213544862 // A001622
+	E   = 2.71828182845904523536028747135266249775724709369995957496696763 // http://oeis.org/A001113
+	Pi  = 3.14159265358979323846264338327950288419716939937510582097494459 // http://oeis.org/A000796
+	Phi = 1.61803398874989484820458683436563811772030917980576286213544862 // http://oeis.org/A001622
 
-	Sqrt2   = 1.41421356237309504880168872420969807856967187537694807317667974 // A002193
-	SqrtE   = 1.64872127070012814684865078781416357165377610071014801157507931 // A019774
-	SqrtPi  = 1.77245385090551602729816748334114518279754945612238712821380779 // A002161
-	SqrtPhi = 1.27201964951406896425242246173749149171560804184009624861664038 // A139339
+	Sqrt2   = 1.41421356237309504880168872420969807856967187537694807317667974 // http://oeis.org/A002193
+	SqrtE   = 1.64872127070012814684865078781416357165377610071014801157507931 // http://oeis.org/A019774
+	SqrtPi  = 1.77245385090551602729816748334114518279754945612238712821380779 // http://oeis.org/A002161
+	SqrtPhi = 1.27201964951406896425242246173749149171560804184009624861664038 // http://oeis.org/A139339
 
-	Ln2    = 0.693147180559945309417232121458176568075500134360255254120680009 // A002162
+	Ln2    = 0.693147180559945309417232121458176568075500134360255254120680009 // http://oeis.org/A002162
 	Log2E  = 1 / Ln2
-	Ln10   = 2.30258509299404568401799145468436420760110148862877297603332790 // A002392
+	Ln10   = 2.30258509299404568401799145468436420760110148862877297603332790 // http://oeis.org/A002392
 	Log10E = 1 / Ln10
 )
 
diff --git a/src/math/dim_amd64.s b/src/math/dim_amd64.s
index 622cc3f..8e6aaad 100644
--- a/src/math/dim_amd64.s
+++ b/src/math/dim_amd64.s
@@ -26,13 +26,13 @@ dim2:	// (-Inf, -Inf) special case
 	JEQ     bothInf
 dim3:	// (NaN, x) or (x, NaN)
 	MOVQ    $~(1<<63), DX
-	MOVQ    $NaN, AX
+	MOVQ    $PosInf, AX
 	ANDQ    DX, BX // x = |x|
 	CMPQ    AX, BX
-	JLE     isDimNaN
+	JLT     isDimNaN
 	ANDQ    DX, CX // y = |y|
 	CMPQ    AX, CX
-	JLE     isDimNaN
+	JLT     isDimNaN
 
 	MOVSD x+0(FP), X0
 	SUBSD y+8(FP), X0
@@ -41,8 +41,8 @@ dim3:	// (NaN, x) or (x, NaN)
 	MOVSD X0, ret+16(FP)
 	RET
 bothInf: // Dim(-Inf, -Inf) or Dim(+Inf, +Inf)
-	MOVQ    $NaN, AX
 isDimNaN:
+	MOVQ    $NaN, AX
 	MOVQ    AX, ret+16(FP)
 	RET
 
@@ -58,15 +58,15 @@ TEXT ·Max(SB),NOSPLIT,$0
 	JEQ     isPosInf
 	// NaN special cases
 	MOVQ    $~(1<<63), DX // bit mask
-	MOVQ    $NaN, AX
+	MOVQ    $PosInf, AX
 	MOVQ    R8, BX
 	ANDQ    DX, BX // x = |x|
 	CMPQ    AX, BX
-	JLE     isMaxNaN
+	JLT     isMaxNaN
 	MOVQ    R9, CX
 	ANDQ    DX, CX // y = |y|
 	CMPQ    AX, CX
-	JLE     isMaxNaN
+	JLT     isMaxNaN
 	// ±0 special cases
 	ORQ     CX, BX
 	JEQ     isMaxZero
@@ -77,6 +77,7 @@ TEXT ·Max(SB),NOSPLIT,$0
 	MOVSD   X0, ret+16(FP)
 	RET
 isMaxNaN: // return NaN
+	MOVQ	$NaN, AX
 isPosInf: // return +Inf
 	MOVQ    AX, ret+16(FP)
 	RET
@@ -89,16 +90,6 @@ isMaxZero:
 	MOVQ    R9, ret+16(FP) // return other 0
 	RET
 
-/*
-	MOVQ    $0, AX
-	CMPQ    AX, R8
-	JNE     +3(PC)
-	MOVQ    R8, ret+16(FP) // return 0
-	RET
-	MOVQ    R9, ret+16(FP) // return other 0
-	RET
-*/
-
 // func Min(x, y float64) float64
 TEXT ·Min(SB),NOSPLIT,$0
 	// -Inf special cases
@@ -111,15 +102,15 @@ TEXT ·Min(SB),NOSPLIT,$0
 	JEQ     isNegInf
 	// NaN special cases
 	MOVQ    $~(1<<63), DX
-	MOVQ    $NaN, AX
+	MOVQ    $PosInf, AX
 	MOVQ    R8, BX
 	ANDQ    DX, BX // x = |x|
 	CMPQ    AX, BX
-	JLE     isMinNaN
+	JLT     isMinNaN
 	MOVQ    R9, CX
 	ANDQ    DX, CX // y = |y|
 	CMPQ    AX, CX
-	JLE     isMinNaN
+	JLT     isMinNaN
 	// ±0 special cases
 	ORQ     CX, BX
 	JEQ     isMinZero
@@ -130,6 +121,7 @@ TEXT ·Min(SB),NOSPLIT,$0
 	MOVSD X0, ret+16(FP)
 	RET
 isMinNaN: // return NaN
+	MOVQ	$NaN, AX
 isNegInf: // return -Inf
 	MOVQ    AX, ret+16(FP)
 	RET
diff --git a/src/math/expm1.go b/src/math/expm1.go
index 8f56e15..064e131 100644
--- a/src/math/expm1.go
+++ b/src/math/expm1.go
@@ -158,11 +158,11 @@ func expm1(x float64) float64 {
 
 	// filter out huge argument
 	if absx >= Ln2X56 { // if |x| >= 56 * ln2
-		if absx >= Othreshold { // if |x| >= 709.78...
-			return Inf(1) // overflow
-		}
 		if sign {
-			return -1 // x < -56*ln2, return -1.0
+			return -1 // x < -56*ln2, return -1
+		}
+		if absx >= Othreshold { // if |x| >= 709.78...
+			return Inf(1)
 		}
 	}
 
diff --git a/src/math/log10.go b/src/math/log10.go
index 95cfbf4..ccd079d 100644
--- a/src/math/log10.go
+++ b/src/math/log10.go
@@ -18,5 +18,10 @@ func Log2(x float64) float64
 
 func log2(x float64) float64 {
 	frac, exp := Frexp(x)
+	// Make sure exact powers of two give an exact answer.
+	// Don't depend on Log(0.5)*(1/Ln2)+exp being exactly exp-1.
+	if frac == 0.5 {
+		return float64(exp - 1)
+	}
 	return Log(frac)*(1/Ln2) + float64(exp)
 }
diff --git a/src/math/nextafter.go b/src/math/nextafter.go
index bbb1399..9088e4d 100644
--- a/src/math/nextafter.go
+++ b/src/math/nextafter.go
@@ -5,10 +5,11 @@
 package math
 
 // Nextafter32 returns the next representable float32 value after x towards y.
-// Special cases:
+//
+// Special cases are:
 //	Nextafter32(x, x)   = x
-//      Nextafter32(NaN, y) = NaN
-//      Nextafter32(x, NaN) = NaN
+//	Nextafter32(NaN, y) = NaN
+//	Nextafter32(x, NaN) = NaN
 func Nextafter32(x, y float32) (r float32) {
 	switch {
 	case IsNaN(float64(x)) || IsNaN(float64(y)): // special case
@@ -26,10 +27,11 @@ func Nextafter32(x, y float32) (r float32) {
 }
 
 // Nextafter returns the next representable float64 value after x towards y.
-// Special cases:
-//	Nextafter64(x, x)   = x
-//      Nextafter64(NaN, y) = NaN
-//      Nextafter64(x, NaN) = NaN
+//
+// Special cases are:
+//	Nextafter(x, x)   = x
+//	Nextafter(NaN, y) = NaN
+//	Nextafter(x, NaN) = NaN
 func Nextafter(x, y float64) (r float64) {
 	switch {
 	case IsNaN(x) || IsNaN(y): // special case
diff --git a/src/math/rand/example_test.go b/src/math/rand/example_test.go
index f429914..e6cd4f7 100644
--- a/src/math/rand/example_test.go
+++ b/src/math/rand/example_test.go
@@ -72,7 +72,7 @@ func Example_rand() {
 	// depending on the size of 'int'.
 	show("Int31", r.Int31(), r.Int31(), r.Int31())
 	show("Int63", r.Int63(), r.Int63(), r.Int63())
-	show("Uint32", r.Int63(), r.Int63(), r.Int63())
+	show("Uint32", r.Uint32(), r.Uint32(), r.Uint32())
 
 	// Intn, Int31n, and Int63n limit their output to be < n.
 	// They do so more carefully than using r.Int()%n.
@@ -89,7 +89,7 @@ func Example_rand() {
 	// NormFloat64 0.17233959114940064 1.577014951434847   0.04259129641113857
 	// Int31       1501292890          1486668269          182840835
 	// Int63       3546343826724305832 5724354148158589552 5239846799706671610
-	// Uint32      5927547564735367388 637072299495207830  4128311955958246186
+	// Uint32      2760229429          296659907           1922395059
 	// Intn(10)    1                   2                   5
 	// Int31n(10)  4                   7                   8
 	// Int63n(10)  7                   6                   3
diff --git a/src/math/rand/rand.go b/src/math/rand/rand.go
index 3ffb5c4..6360128 100644
--- a/src/math/rand/rand.go
+++ b/src/math/rand/rand.go
@@ -9,6 +9,9 @@
 // sequence of values each time a program is run. Use the Seed function to
 // initialize the default Source if different behavior is required for each run.
 // The default Source is safe for concurrent use by multiple goroutines.
+//
+// For random numbers suitable for security-sensitive work, see the crypto/rand
+// package.
 package rand
 
 import "sync"
diff --git a/src/math/rand/rand_test.go b/src/math/rand/rand_test.go
index ab0dc49..c61494f 100644
--- a/src/math/rand/rand_test.go
+++ b/src/math/rand/rand_test.go
@@ -8,6 +8,8 @@ import (
 	"errors"
 	"fmt"
 	"math"
+	"os"
+	"runtime"
 	"testing"
 )
 
@@ -322,10 +324,17 @@ func TestExpTables(t *testing.T) {
 	}
 }
 
-// For issue 6721, the problem came after 7533753 calls, so check 10e6.
 func TestFloat32(t *testing.T) {
+	// For issue 6721, the problem came after 7533753 calls, so check 10e6.
+	num := int(10e6)
+	// But ARM5 floating point emulation is slow (Issue 10749), so
+	// do less for that builder:
+	if testing.Short() && runtime.GOARCH == "arm" && os.Getenv("GOARM") == "5" {
+		num /= 100 // 1.72 seconds instead of 172 seconds
+	}
+
 	r := New(NewSource(1))
-	for ct := 0; ct < 10e6; ct++ {
+	for ct := 0; ct < num; ct++ {
 		f := r.Float32()
 		if f >= 1 {
 			t.Fatal("Float32() should be in range [0,1). ct:", ct, "f:", f)
diff --git a/src/math/rand/zipf.go b/src/math/rand/zipf.go
index 8db2c6f..f04c814 100644
--- a/src/math/rand/zipf.go
+++ b/src/math/rand/zipf.go
@@ -32,8 +32,10 @@ func (z *Zipf) hinv(x float64) float64 {
 	return math.Exp(z.oneminusQinv*math.Log(z.oneminusQ*x)) - z.v
 }
 
-// NewZipf returns a Zipf generating variates p(k) on [0, imax]
-// proportional to (v+k)**(-s) where s>1 and k>=0, and v>=1.
+// NewZipf returns a Zipf variate generator.
+// The generator generates values k ∈ [0, imax]
+// such that P(k) is proportional to (v + k) ** (-s).
+// Requirements: s > 1 and v >= 1.
 func NewZipf(r *Rand, s float64, v float64, imax uint64) *Zipf {
 	z := new(Zipf)
 	if s <= 1.0 || v < 1 {
diff --git a/src/math/sqrt.go b/src/math/sqrt.go
index fdc8699..23cf299 100644
--- a/src/math/sqrt.go
+++ b/src/math/sqrt.go
@@ -91,6 +91,11 @@ package math
 //	Sqrt(NaN) = NaN
 func Sqrt(x float64) float64
 
+// Note: Sqrt is implemented in assembly on some systems.
+// Others have assembly stubs that jump to func sqrt below.
+// On systems where Sqrt is a single instruction, the compiler
+// may turn a direct call into a direct use of that instruction instead.
+
 func sqrt(x float64) float64 {
 	// special cases
 	switch {
diff --git a/src/math/sqrt_arm64.s b/src/math/sqrt_arm64.s
new file mode 100644
index 0000000..9861446
--- /dev/null
+++ b/src/math/sqrt_arm64.s
@@ -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.
+
+#include "textflag.h"
+
+// func Sqrt(x float64) float64
+TEXT ·Sqrt(SB),NOSPLIT,$0
+	FMOVD	x+0(FP), F0
+	FSQRTD	F0, F0
+	FMOVD	F0, ret+8(FP)
+	RET
diff --git a/src/math/stubs_arm64.s b/src/math/stubs_arm64.s
new file mode 100644
index 0000000..eea81e9
--- /dev/null
+++ b/src/math/stubs_arm64.s
@@ -0,0 +1,88 @@
+// 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 ·Tan(SB),NOSPLIT,$0
+	B ·tan(SB)
diff --git a/src/math/stubs_ppc64x.s b/src/math/stubs_ppc64x.s
new file mode 100644
index 0000000..9369c5c
--- /dev/null
+++ b/src/math/stubs_ppc64x.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 ppc64 ppc64le
+
+#include "textflag.h"
+
+TEXT ·Asin(SB),NOSPLIT,$0
+	BR ·asin(SB)
+
+TEXT ·Acos(SB),NOSPLIT,$0
+	BR ·acos(SB)
+
+TEXT ·Atan2(SB),NOSPLIT,$0
+	BR ·atan2(SB)
+
+TEXT ·Atan(SB),NOSPLIT,$0
+	BR ·atan(SB)
+
+TEXT ·Dim(SB),NOSPLIT,$0
+	BR ·dim(SB)
+
+TEXT ·Min(SB),NOSPLIT,$0
+	BR ·min(SB)
+
+TEXT ·Max(SB),NOSPLIT,$0
+	BR ·max(SB)
+
+TEXT ·Exp2(SB),NOSPLIT,$0
+	BR ·exp2(SB)
+
+TEXT ·Expm1(SB),NOSPLIT,$0
+	BR ·expm1(SB)
+
+TEXT ·Exp(SB),NOSPLIT,$0
+	BR ·exp(SB)
+
+TEXT ·Floor(SB),NOSPLIT,$0
+	BR ·floor(SB)
+
+TEXT ·Ceil(SB),NOSPLIT,$0
+	BR ·ceil(SB)
+
+TEXT ·Trunc(SB),NOSPLIT,$0
+	BR ·trunc(SB)
+
+TEXT ·Frexp(SB),NOSPLIT,$0
+	BR ·frexp(SB)
+
+TEXT ·Hypot(SB),NOSPLIT,$0
+	BR ·hypot(SB)
+
+TEXT ·Ldexp(SB),NOSPLIT,$0
+	BR ·ldexp(SB)
+
+TEXT ·Log10(SB),NOSPLIT,$0
+	BR ·log10(SB)
+
+TEXT ·Log2(SB),NOSPLIT,$0
+	BR ·log2(SB)
+
+TEXT ·Log1p(SB),NOSPLIT,$0
+	BR ·log1p(SB)
+
+TEXT ·Log(SB),NOSPLIT,$0
+	BR ·log(SB)
+
+TEXT ·Modf(SB),NOSPLIT,$0
+	BR ·modf(SB)
+
+TEXT ·Mod(SB),NOSPLIT,$0
+	BR ·mod(SB)
+
+TEXT ·Remainder(SB),NOSPLIT,$0
+	BR ·remainder(SB)
+
+TEXT ·Sincos(SB),NOSPLIT,$0
+	BR ·sincos(SB)
+
+TEXT ·Sin(SB),NOSPLIT,$0
+	BR ·sin(SB)
+
+TEXT ·Cos(SB),NOSPLIT,$0
+	BR ·cos(SB)
+
+TEXT ·Sqrt(SB),NOSPLIT,$0
+	BR ·sqrt(SB)
+
+TEXT ·Tan(SB),NOSPLIT,$0
+	BR ·tan(SB)
diff --git a/src/mime/encodedword.go b/src/mime/encodedword.go
new file mode 100644
index 0000000..9796f50
--- /dev/null
+++ b/src/mime/encodedword.go
@@ -0,0 +1,329 @@
+// 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 mime
+
+import (
+	"bytes"
+	"encoding/base64"
+	"errors"
+	"fmt"
+	"io"
+	"strings"
+	"sync"
+	"unicode"
+	"unicode/utf8"
+)
+
+// A WordEncoder is a RFC 2047 encoded-word encoder.
+type WordEncoder byte
+
+const (
+	// BEncoding represents Base64 encoding scheme as defined by RFC 2045.
+	BEncoding = WordEncoder('b')
+	// QEncoding represents the Q-encoding scheme as defined by RFC 2047.
+	QEncoding = WordEncoder('q')
+)
+
+var (
+	errInvalidWord = errors.New("mime: invalid RFC 2047 encoded-word")
+)
+
+// Encode returns the encoded-word form of s. If s is ASCII without special
+// characters, it is returned unchanged. The provided charset is the IANA
+// charset name of s. It is case insensitive.
+func (e WordEncoder) Encode(charset, s string) string {
+	if !needsEncoding(s) {
+		return s
+	}
+	return e.encodeWord(charset, s)
+}
+
+func needsEncoding(s string) bool {
+	for _, b := range s {
+		if (b < ' ' || b > '~') && b != '\t' {
+			return true
+		}
+	}
+	return false
+}
+
+// encodeWord encodes a string into an encoded-word.
+func (e WordEncoder) encodeWord(charset, s string) string {
+	buf := getBuffer()
+	defer putBuffer(buf)
+
+	buf.WriteString("=?")
+	buf.WriteString(charset)
+	buf.WriteByte('?')
+	buf.WriteByte(byte(e))
+	buf.WriteByte('?')
+
+	if e == BEncoding {
+		w := base64.NewEncoder(base64.StdEncoding, buf)
+		io.WriteString(w, s)
+		w.Close()
+	} else {
+		enc := make([]byte, 3)
+		for i := 0; i < len(s); i++ {
+			b := s[i]
+			switch {
+			case b == ' ':
+				buf.WriteByte('_')
+			case b <= '~' && b >= '!' && b != '=' && b != '?' && b != '_':
+				buf.WriteByte(b)
+			default:
+				enc[0] = '='
+				enc[1] = upperhex[b>>4]
+				enc[2] = upperhex[b&0x0f]
+				buf.Write(enc)
+			}
+		}
+	}
+	buf.WriteString("?=")
+	return buf.String()
+}
+
+const upperhex = "0123456789ABCDEF"
+
+// A WordDecoder decodes MIME headers containing RFC 2047 encoded-words.
+type WordDecoder struct {
+	// CharsetReader, if non-nil, defines a function to generate
+	// charset-conversion readers, converting from the provided
+	// charset into UTF-8.
+	// Charsets are always lower-case. utf-8, iso-8859-1 and us-ascii charsets
+	// are handled by default.
+	// One of the the CharsetReader's result values must be non-nil.
+	CharsetReader func(charset string, input io.Reader) (io.Reader, error)
+}
+
+// Decode decodes an encoded-word. If word is not a valid RFC 2047 encoded-word,
+// word is returned unchanged.
+func (d *WordDecoder) Decode(word string) (string, error) {
+	fields := strings.Split(word, "?") // TODO: remove allocation?
+	if len(fields) != 5 || fields[0] != "=" || fields[4] != "=" || len(fields[2]) != 1 {
+		return "", errInvalidWord
+	}
+
+	content, err := decode(fields[2][0], fields[3])
+	if err != nil {
+		return "", err
+	}
+
+	buf := getBuffer()
+	defer putBuffer(buf)
+
+	if err := d.convert(buf, fields[1], content); err != nil {
+		return "", err
+	}
+
+	return buf.String(), nil
+}
+
+// DecodeHeader decodes all encoded-words of the given string. It returns an
+// error if and only if CharsetReader of d returns an error.
+func (d *WordDecoder) DecodeHeader(header string) (string, error) {
+	// If there is no encoded-word, returns before creating a buffer.
+	i := strings.Index(header, "=?")
+	if i == -1 {
+		return header, nil
+	}
+
+	buf := getBuffer()
+	defer putBuffer(buf)
+
+	buf.WriteString(header[:i])
+	header = header[i:]
+
+	betweenWords := false
+	for {
+		start := strings.Index(header, "=?")
+		if start == -1 {
+			break
+		}
+		cur := start + len("=?")
+
+		i := strings.Index(header[cur:], "?")
+		if i == -1 {
+			break
+		}
+		charset := header[cur : cur+i]
+		cur += i + len("?")
+
+		if len(header) < cur+len("Q??=") {
+			break
+		}
+		encoding := header[cur]
+		cur++
+
+		if header[cur] != '?' {
+			break
+		}
+		cur++
+
+		j := strings.Index(header[cur:], "?=")
+		if j == -1 {
+			break
+		}
+		text := header[cur : cur+j]
+		end := cur + j + len("?=")
+
+		content, err := decode(encoding, text)
+		if err != nil {
+			betweenWords = false
+			buf.WriteString(header[:start+2])
+			header = header[start+2:]
+			continue
+		}
+
+		// Write characters before the encoded-word. White-space and newline
+		// characters separating two encoded-words must be deleted.
+		if start > 0 && (!betweenWords || hasNonWhitespace(header[:start])) {
+			buf.WriteString(header[:start])
+		}
+
+		if err := d.convert(buf, charset, content); err != nil {
+			return "", err
+		}
+
+		header = header[end:]
+		betweenWords = true
+	}
+
+	if len(header) > 0 {
+		buf.WriteString(header)
+	}
+
+	return buf.String(), nil
+}
+
+func decode(encoding byte, text string) ([]byte, error) {
+	switch encoding {
+	case 'B', 'b':
+		return base64.StdEncoding.DecodeString(text)
+	case 'Q', 'q':
+		return qDecode(text)
+	default:
+		return nil, errInvalidWord
+	}
+}
+
+func (d *WordDecoder) convert(buf *bytes.Buffer, charset string, content []byte) error {
+	switch {
+	case strings.EqualFold("utf-8", charset):
+		buf.Write(content)
+	case strings.EqualFold("iso-8859-1", charset):
+		for _, c := range content {
+			buf.WriteRune(rune(c))
+		}
+	case strings.EqualFold("us-ascii", charset):
+		for _, c := range content {
+			if c >= utf8.RuneSelf {
+				buf.WriteRune(unicode.ReplacementChar)
+			} else {
+				buf.WriteByte(c)
+			}
+		}
+	default:
+		if d.CharsetReader == nil {
+			return fmt.Errorf("mime: unhandled charset %q", charset)
+		}
+		r, err := d.CharsetReader(strings.ToLower(charset), bytes.NewReader(content))
+		if err != nil {
+			return err
+		}
+		if _, err = buf.ReadFrom(r); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// hasNonWhitespace reports whether s (assumed to be ASCII) contains at least
+// one byte of non-whitespace.
+func hasNonWhitespace(s string) bool {
+	for _, b := range s {
+		switch b {
+		// Encoded-words can only be separated by linear white spaces which does
+		// not include vertical tabs (\v).
+		case ' ', '\t', '\n', '\r':
+		default:
+			return true
+		}
+	}
+	return false
+}
+
+// qDecode decodes a Q encoded string.
+func qDecode(s string) ([]byte, error) {
+	dec := make([]byte, len(s))
+	n := 0
+	for i := 0; i < len(s); i++ {
+		switch c := s[i]; {
+		case c == '_':
+			dec[n] = ' '
+		case c == '=':
+			if i+2 >= len(s) {
+				return nil, errInvalidWord
+			}
+			b, err := readHexByte(s[i+1], s[i+2])
+			if err != nil {
+				return nil, err
+			}
+			dec[n] = b
+			i += 2
+		case (c <= '~' && c >= ' ') || c == '\n' || c == '\r' || c == '\t':
+			dec[n] = c
+		default:
+			return nil, errInvalidWord
+		}
+		n++
+	}
+
+	return dec[:n], nil
+}
+
+// readHexByte returns the byte from its quoted-printable representation.
+func readHexByte(a, b byte) (byte, error) {
+	var hb, lb byte
+	var err error
+	if hb, err = fromHex(a); err != nil {
+		return 0, err
+	}
+	if lb, err = fromHex(b); err != nil {
+		return 0, err
+	}
+	return hb<<4 | lb, nil
+}
+
+func fromHex(b byte) (byte, error) {
+	switch {
+	case b >= '0' && b <= '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("mime: invalid hex byte %#02x", b)
+}
+
+var bufPool = sync.Pool{
+	New: func() interface{} {
+		return new(bytes.Buffer)
+	},
+}
+
+func getBuffer() *bytes.Buffer {
+	return bufPool.Get().(*bytes.Buffer)
+}
+
+func putBuffer(buf *bytes.Buffer) {
+	if buf.Len() > 1024 {
+		return
+	}
+	buf.Reset()
+	bufPool.Put(buf)
+}
diff --git a/src/mime/encodedword_test.go b/src/mime/encodedword_test.go
new file mode 100644
index 0000000..2beff5d
--- /dev/null
+++ b/src/mime/encodedword_test.go
@@ -0,0 +1,287 @@
+// 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 mime
+
+import (
+	"bytes"
+	"errors"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"strings"
+	"testing"
+)
+
+func ExampleWordEncoder_Encode() {
+	fmt.Println(QEncoding.Encode("utf-8", "¡Hola, señor!"))
+	fmt.Println(QEncoding.Encode("utf-8", "Hello!"))
+	fmt.Println(BEncoding.Encode("UTF-8", "¡Hola, señor!"))
+	fmt.Println(QEncoding.Encode("ISO-8859-1", "Caf\xE9"))
+	// Output:
+	// =?utf-8?q?=C2=A1Hola,_se=C3=B1or!?=
+	// Hello!
+	// =?UTF-8?b?wqFIb2xhLCBzZcOxb3Ih?=
+	// =?ISO-8859-1?q?Caf=E9?=
+}
+
+func ExampleWordDecoder_Decode() {
+	dec := new(WordDecoder)
+	header, err := dec.Decode("=?utf-8?q?=C2=A1Hola,_se=C3=B1or!?=")
+	if err != nil {
+		panic(err)
+	}
+	fmt.Println(header)
+
+	dec.CharsetReader = func(charset string, input io.Reader) (io.Reader, error) {
+		switch charset {
+		case "x-case":
+			// Fake character set for example.
+			// Real use would integrate with packages such
+			// as code.google.com/p/go-charset
+			content, err := ioutil.ReadAll(input)
+			if err != nil {
+				return nil, err
+			}
+			return bytes.NewReader(bytes.ToUpper(content)), nil
+		default:
+			return nil, fmt.Errorf("unhandled charset %q", charset)
+		}
+	}
+	header, err = dec.Decode("=?x-case?q?hello!?=")
+	if err != nil {
+		panic(err)
+	}
+	fmt.Println(header)
+	// Output:
+	// ¡Hola, señor!
+	// HELLO!
+}
+
+func ExampleWordDecoder_DecodeHeader() {
+	dec := new(WordDecoder)
+	header, err := dec.DecodeHeader("=?utf-8?q?=C3=89ric?= <eric at example.org>, =?utf-8?q?Ana=C3=AFs?= <anais at example.org>")
+	if err != nil {
+		panic(err)
+	}
+	fmt.Println(header)
+
+	header, err = dec.DecodeHeader("=?utf-8?q?=C2=A1Hola,?= =?utf-8?q?_se=C3=B1or!?=")
+	if err != nil {
+		panic(err)
+	}
+	fmt.Println(header)
+
+	dec.CharsetReader = func(charset string, input io.Reader) (io.Reader, error) {
+		switch charset {
+		case "x-case":
+			// Fake character set for example.
+			// Real use would integrate with packages such
+			// as code.google.com/p/go-charset
+			content, err := ioutil.ReadAll(input)
+			if err != nil {
+				return nil, err
+			}
+			return bytes.NewReader(bytes.ToUpper(content)), nil
+		default:
+			return nil, fmt.Errorf("unhandled charset %q", charset)
+		}
+	}
+	header, err = dec.DecodeHeader("=?x-case?q?hello_?= =?x-case?q?world!?=")
+	if err != nil {
+		panic(err)
+	}
+	fmt.Println(header)
+	// Output:
+	// Éric <eric at example.org>, Anaïs <anais at example.org>
+	// ¡Hola, señor!
+	// HELLO WORLD!
+}
+
+func TestEncodeWord(t *testing.T) {
+	utf8, iso88591 := "utf-8", "iso-8859-1"
+	tests := []struct {
+		enc      WordEncoder
+		charset  string
+		src, exp string
+	}{
+		{QEncoding, utf8, "François-Jérôme", "=?utf-8?q?Fran=C3=A7ois-J=C3=A9r=C3=B4me?="},
+		{BEncoding, utf8, "Café", "=?utf-8?b?Q2Fmw6k=?="},
+		{QEncoding, iso88591, "La Seleção", "=?iso-8859-1?q?La_Sele=C3=A7=C3=A3o?="},
+		{QEncoding, utf8, "", ""},
+		{QEncoding, utf8, "A", "A"},
+		{QEncoding, iso88591, "a", "a"},
+		{QEncoding, utf8, "123 456", "123 456"},
+		{QEncoding, utf8, "\t !\"#$%&'()*+,-./ :;<>?@[\\]^_`{|}~", "\t !\"#$%&'()*+,-./ :;<>?@[\\]^_`{|}~"},
+	}
+
+	for _, test := range tests {
+		if s := test.enc.Encode(test.charset, test.src); s != test.exp {
+			t.Errorf("Encode(%q) = %q, want %q", test.src, s, test.exp)
+		}
+	}
+}
+
+func TestDecodeWord(t *testing.T) {
+	tests := []struct {
+		src, exp string
+		hasErr   bool
+	}{
+		{"=?UTF-8?Q?=C2=A1Hola,_se=C3=B1or!?=", "¡Hola, señor!", false},
+		{"=?UTF-8?Q?Fran=C3=A7ois-J=C3=A9r=C3=B4me?=", "François-Jérôme", false},
+		{"=?UTF-8?q?ascii?=", "ascii", false},
+		{"=?utf-8?B?QW5kcsOp?=", "André", false},
+		{"=?ISO-8859-1?Q?Rapha=EBl_Dupont?=", "Raphaël Dupont", false},
+		{"=?utf-8?b?IkFudG9uaW8gSm9zw6kiIDxqb3NlQGV4YW1wbGUub3JnPg==?=", `"Antonio José" <jose at example.org>`, false},
+		{"=?UTF-8?A?Test?=", "", true},
+		{"=?UTF-8?Q?A=B?=", "", true},
+		{"=?UTF-8?Q?=A?=", "", true},
+		{"=?UTF-8?A?A?=", "", true},
+	}
+
+	for _, test := range tests {
+		dec := new(WordDecoder)
+		s, err := dec.Decode(test.src)
+		if test.hasErr && err == nil {
+			t.Errorf("Decode(%q) should return an error", test.src)
+			continue
+		}
+		if !test.hasErr && err != nil {
+			t.Errorf("Decode(%q): %v", test.src, err)
+			continue
+		}
+		if s != test.exp {
+			t.Errorf("Decode(%q) = %q, want %q", test.src, s, test.exp)
+		}
+	}
+}
+
+func TestDecodeHeader(t *testing.T) {
+	tests := []struct {
+		src, exp string
+	}{
+		{"=?UTF-8?Q?=C2=A1Hola,_se=C3=B1or!?=", "¡Hola, señor!"},
+		{"=?UTF-8?Q?Fran=C3=A7ois-J=C3=A9r=C3=B4me?=", "François-Jérôme"},
+		{"=?UTF-8?q?ascii?=", "ascii"},
+		{"=?utf-8?B?QW5kcsOp?=", "André"},
+		{"=?ISO-8859-1?Q?Rapha=EBl_Dupont?=", "Raphaël Dupont"},
+		{"Jean", "Jean"},
+		{"=?utf-8?b?IkFudG9uaW8gSm9zw6kiIDxqb3NlQGV4YW1wbGUub3JnPg==?=", `"Antonio José" <jose at example.org>`},
+		{"=?UTF-8?A?Test?=", "=?UTF-8?A?Test?="},
+		{"=?UTF-8?Q?A=B?=", "=?UTF-8?Q?A=B?="},
+		{"=?UTF-8?Q?=A?=", "=?UTF-8?Q?=A?="},
+		{"=?UTF-8?A?A?=", "=?UTF-8?A?A?="},
+		// Incomplete words
+		{"=?", "=?"},
+		{"=?UTF-8?", "=?UTF-8?"},
+		{"=?UTF-8?=", "=?UTF-8?="},
+		{"=?UTF-8?Q", "=?UTF-8?Q"},
+		{"=?UTF-8?Q?", "=?UTF-8?Q?"},
+		{"=?UTF-8?Q?=", "=?UTF-8?Q?="},
+		{"=?UTF-8?Q?A", "=?UTF-8?Q?A"},
+		{"=?UTF-8?Q?A?", "=?UTF-8?Q?A?"},
+		// Tests from RFC 2047
+		{"=?ISO-8859-1?Q?a?=", "a"},
+		{"=?ISO-8859-1?Q?a?= b", "a b"},
+		{"=?ISO-8859-1?Q?a?= =?ISO-8859-1?Q?b?=", "ab"},
+		{"=?ISO-8859-1?Q?a?=  =?ISO-8859-1?Q?b?=", "ab"},
+		{"=?ISO-8859-1?Q?a?= \r\n\t =?ISO-8859-1?Q?b?=", "ab"},
+		{"=?ISO-8859-1?Q?a_b?=", "a b"},
+	}
+
+	for _, test := range tests {
+		dec := new(WordDecoder)
+		s, err := dec.DecodeHeader(test.src)
+		if err != nil {
+			t.Errorf("DecodeHeader(%q): %v", test.src, err)
+		}
+		if s != test.exp {
+			t.Errorf("DecodeHeader(%q) = %q, want %q", test.src, s, test.exp)
+		}
+	}
+}
+
+func TestCharsetDecoder(t *testing.T) {
+	tests := []struct {
+		src      string
+		want     string
+		charsets []string
+		content  []string
+	}{
+		{"=?utf-8?b?Q2Fmw6k=?=", "Café", nil, nil},
+		{"=?ISO-8859-1?Q?caf=E9?=", "café", nil, nil},
+		{"=?US-ASCII?Q?foo_bar?=", "foo bar", nil, nil},
+		{"=?utf-8?Q?=?=", "=?utf-8?Q?=?=", nil, nil},
+		{"=?utf-8?Q?=A?=", "=?utf-8?Q?=A?=", nil, nil},
+		{
+			"=?ISO-8859-15?Q?f=F5=F6?=  =?windows-1252?Q?b=E0r?=",
+			"f\xf5\xf6b\xe0r",
+			[]string{"iso-8859-15", "windows-1252"},
+			[]string{"f\xf5\xf6", "b\xe0r"},
+		},
+	}
+
+	for _, test := range tests {
+		i := 0
+		dec := &WordDecoder{
+			CharsetReader: func(charset string, input io.Reader) (io.Reader, error) {
+				if charset != test.charsets[i] {
+					t.Errorf("DecodeHeader(%q), got charset %q, want %q", test.src, charset, test.charsets[i])
+				}
+				content, err := ioutil.ReadAll(input)
+				if err != nil {
+					t.Errorf("DecodeHeader(%q), error in reader: %v", test.src, err)
+				}
+				got := string(content)
+				if got != test.content[i] {
+					t.Errorf("DecodeHeader(%q), got content %q, want %q", test.src, got, test.content[i])
+				}
+				i++
+
+				return strings.NewReader(got), nil
+			},
+		}
+		got, err := dec.DecodeHeader(test.src)
+		if err != nil {
+			t.Errorf("DecodeHeader(%q): %v", test.src, err)
+		}
+		if got != test.want {
+			t.Errorf("DecodeHeader(%q) = %q, want %q", test.src, got, test.want)
+		}
+	}
+}
+
+func TestCharsetDecoderError(t *testing.T) {
+	dec := &WordDecoder{
+		CharsetReader: func(charset string, input io.Reader) (io.Reader, error) {
+			return nil, errors.New("Test error")
+		},
+	}
+
+	if _, err := dec.DecodeHeader("=?charset?Q?foo?="); err == nil {
+		t.Error("DecodeHeader should return an error")
+	}
+}
+
+func BenchmarkQEncodeWord(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		QEncoding.Encode("UTF-8", "¡Hola, señor!")
+	}
+}
+
+func BenchmarkQDecodeWord(b *testing.B) {
+	dec := new(WordDecoder)
+
+	for i := 0; i < b.N; i++ {
+		dec.Decode("=?utf-8?q?=C2=A1Hola,_se=C3=B1or!?=")
+	}
+}
+
+func BenchmarkQDecodeHeader(b *testing.B) {
+	dec := new(WordDecoder)
+
+	for i := 0; i < b.N; i++ {
+		dec.Decode("=?utf-8?q?=C2=A1Hola,_se=C3=B1or!?=")
+	}
+}
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 @@ import (
 	"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 @@ func isTokenChar(r rune) bool {
 	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/multipart/multipart.go b/src/mime/multipart/multipart.go
index 01a667d..6f65a55 100644
--- a/src/mime/multipart/multipart.go
+++ b/src/mime/multipart/multipart.go
@@ -19,6 +19,7 @@ import (
 	"io"
 	"io/ioutil"
 	"mime"
+	"mime/quotedprintable"
 	"net/textproto"
 )
 
@@ -111,7 +112,7 @@ func newPart(mr *Reader) (*Part, error) {
 	const cte = "Content-Transfer-Encoding"
 	if bp.Header.Get(cte) == "quoted-printable" {
 		bp.Header.Del(cte)
-		bp.r = newQuotedPrintableReader(bp.r)
+		bp.r = quotedprintable.NewReader(bp.r)
 	}
 	return bp, nil
 }
@@ -164,16 +165,18 @@ func (pr partReader) Read(d []byte) (n int, err error) {
 	if peek == nil {
 		panic("nil peek buf")
 	}
-
 	// Search the peek buffer for "\r\n--boundary". If found,
 	// consume everything up to the boundary. If not, consume only
 	// as much of the peek buffer as cannot hold the boundary
 	// string.
 	nCopy := 0
 	foundBoundary := false
-	if idx := bytes.Index(peek, p.mr.nlDashBoundary); idx != -1 {
+	if idx, isEnd := p.mr.peekBufferSeparatorIndex(peek); idx != -1 {
 		nCopy = idx
-		foundBoundary = true
+		foundBoundary = isEnd
+		if !isEnd && nCopy == 0 {
+			nCopy = 1 // make some progress.
+		}
 	} else if safeCount := len(peek) - len(p.mr.nlDashBoundary); safeCount > 0 {
 		nCopy = safeCount
 	} else if unexpectedEOF {
@@ -337,6 +340,33 @@ func (mr *Reader) peekBufferIsEmptyPart(peek []byte) bool {
 	return bytes.HasPrefix(rest, mr.nl)
 }
 
+// peekBufferSeparatorIndex returns the index of mr.nlDashBoundary in
+// peek and whether it is a real boundary (and not a prefix of an
+// unrelated separator). To be the end, the peek buffer must contain a
+// newline after the boundary.
+func (mr *Reader) peekBufferSeparatorIndex(peek []byte) (idx int, isEnd bool) {
+	idx = bytes.Index(peek, mr.nlDashBoundary)
+	if idx == -1 {
+		return
+	}
+	peek = peek[idx+len(mr.nlDashBoundary):]
+	if len(peek) > 1 && peek[0] == '-' && peek[1] == '-' {
+		return idx, true
+	}
+	peek = skipLWSPChar(peek)
+	// Don't have a complete line after the peek.
+	if bytes.IndexByte(peek, '\n') == -1 {
+		return -1, false
+	}
+	if len(peek) > 0 && peek[0] == '\n' {
+		return idx, true
+	}
+	if len(peek) > 1 && peek[0] == '\r' && peek[1] == '\n' {
+		return idx, true
+	}
+	return idx, false
+}
+
 // skipLWSPChar returns b with leading spaces and tabs removed.
 // RFC 822 defines:
 //    LWSP-char = SPACE / HTAB
diff --git a/src/mime/multipart/multipart_test.go b/src/mime/multipart/multipart_test.go
index d662e83..30452d1 100644
--- a/src/mime/multipart/multipart_test.go
+++ b/src/mime/multipart/multipart_test.go
@@ -351,7 +351,7 @@ func TestLineContinuation(t *testing.T) {
 }
 
 func TestQuotedPrintableEncoding(t *testing.T) {
-	// From http://golang.org/issue/4411
+	// From https://golang.org/issue/4411
 	body := "--0016e68ee29c5d515f04cedf6733\r\nContent-Type: text/plain; charset=ISO-8859-1\r\nContent-Disposition: form-data; name=text\r\nContent-Transfer-Encoding: quoted-printable\r\n\r\nwords words words words words words words words words words words words wor=\r\nds words words words words words words words words words words words words =\r\nwords words words words words words words words words words words words wor=\r\nds words words words words words words words words words words w [...]
 	r := NewReader(strings.NewReader(body), "0016e68ee29c5d515f04cedf6733")
 	part, err := r.NextPart()
@@ -565,6 +565,58 @@ foo: bar
 		},
 	},
 
+	// Issue 10616; minimal
+	{
+		name: "issue 10616 minimal",
+		sep:  "sep",
+		in: "--sep \r\nFoo: bar\r\n\r\n" +
+			"a\r\n" +
+			"--sep_alt\r\n" +
+			"b\r\n" +
+			"\r\n--sep--",
+		want: []headerBody{
+			{textproto.MIMEHeader{"Foo": {"bar"}}, "a\r\n--sep_alt\r\nb\r\n"},
+		},
+	},
+
+	// Issue 10616; full example from bug.
+	{
+		name: "nested separator prefix is outer separator",
+		sep:  "----=_NextPart_4c2fbafd7ec4c8bf08034fe724b608d9",
+		in: strings.Replace(`------=_NextPart_4c2fbafd7ec4c8bf08034fe724b608d9
+Content-Type: multipart/alternative; boundary="----=_NextPart_4c2fbafd7ec4c8bf08034fe724b608d9_alt"
+
+------=_NextPart_4c2fbafd7ec4c8bf08034fe724b608d9_alt
+Content-Type: text/plain; charset="utf-8"
+Content-Transfer-Encoding: 8bit
+
+This is a multi-part message in MIME format.
+
+------=_NextPart_4c2fbafd7ec4c8bf08034fe724b608d9_alt
+Content-Type: text/html; charset="utf-8"
+Content-Transfer-Encoding: 8bit
+
+html things
+------=_NextPart_4c2fbafd7ec4c8bf08034fe724b608d9_alt--
+------=_NextPart_4c2fbafd7ec4c8bf08034fe724b608d9--`, "\n", "\r\n", -1),
+		want: []headerBody{
+			{textproto.MIMEHeader{"Content-Type": {`multipart/alternative; boundary="----=_NextPart_4c2fbafd7ec4c8bf08034fe724b608d9_alt"`}},
+				strings.Replace(`------=_NextPart_4c2fbafd7ec4c8bf08034fe724b608d9_alt
+Content-Type: text/plain; charset="utf-8"
+Content-Transfer-Encoding: 8bit
+
+This is a multi-part message in MIME format.
+
+------=_NextPart_4c2fbafd7ec4c8bf08034fe724b608d9_alt
+Content-Type: text/html; charset="utf-8"
+Content-Transfer-Encoding: 8bit
+
+html things
+------=_NextPart_4c2fbafd7ec4c8bf08034fe724b608d9_alt--`, "\n", "\r\n", -1),
+			},
+		},
+	},
+
 	roundTripParseTest(),
 }
 
diff --git a/src/mime/multipart/quotedprintable.go b/src/mime/multipart/quotedprintable.go
deleted file mode 100644
index 9ff4ee7..0000000
--- a/src/mime/multipart/quotedprintable.go
+++ /dev/null
@@ -1,118 +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.
-
-// The file define a quoted-printable decoder, as specified in RFC 2045.
-// Deviations:
-// 1. in addition to "=\r\n", "=\n" is also treated as soft line break.
-// 2. it will pass through a '\r' or '\n' not preceded by '=', consistent
-//    with other broken QP encoders & decoders.
-
-package multipart
-
-import (
-	"bufio"
-	"bytes"
-	"fmt"
-	"io"
-)
-
-type qpReader struct {
-	br   *bufio.Reader
-	rerr error  // last read error
-	line []byte // to be consumed before more of br
-}
-
-func newQuotedPrintableReader(r io.Reader) io.Reader {
-	return &qpReader{
-		br: bufio.NewReader(r),
-	}
-}
-
-func fromHex(b byte) (byte, error) {
-	switch {
-	case b >= '0' && b <= '9':
-		return b - '0', nil
-	case b >= 'A' && b <= 'F':
-		return b - 'A' + 10, nil
-	}
-	return 0, fmt.Errorf("multipart: invalid quoted-printable hex byte 0x%02x", b)
-}
-
-func (q *qpReader) readHexByte(v []byte) (b byte, err error) {
-	if len(v) < 2 {
-		return 0, io.ErrUnexpectedEOF
-	}
-	var hb, lb byte
-	if hb, err = fromHex(v[0]); err != nil {
-		return 0, err
-	}
-	if lb, err = fromHex(v[1]); err != nil {
-		return 0, err
-	}
-	return hb<<4 | lb, nil
-}
-
-func isQPDiscardWhitespace(r rune) bool {
-	switch r {
-	case '\n', '\r', ' ', '\t':
-		return true
-	}
-	return false
-}
-
-var (
-	crlf       = []byte("\r\n")
-	lf         = []byte("\n")
-	softSuffix = []byte("=")
-)
-
-func (q *qpReader) Read(p []byte) (n int, err error) {
-	for len(p) > 0 {
-		if len(q.line) == 0 {
-			if q.rerr != nil {
-				return n, q.rerr
-			}
-			q.line, q.rerr = q.br.ReadSlice('\n')
-
-			// Does the line end in CRLF instead of just LF?
-			hasLF := bytes.HasSuffix(q.line, lf)
-			hasCR := bytes.HasSuffix(q.line, crlf)
-			wholeLine := q.line
-			q.line = bytes.TrimRightFunc(wholeLine, isQPDiscardWhitespace)
-			if bytes.HasSuffix(q.line, softSuffix) {
-				rightStripped := wholeLine[len(q.line):]
-				q.line = q.line[:len(q.line)-1]
-				if !bytes.HasPrefix(rightStripped, lf) && !bytes.HasPrefix(rightStripped, crlf) {
-					q.rerr = fmt.Errorf("multipart: invalid bytes after =: %q", rightStripped)
-				}
-			} else if hasLF {
-				if hasCR {
-					q.line = append(q.line, '\r', '\n')
-				} else {
-					q.line = append(q.line, '\n')
-				}
-			}
-			continue
-		}
-		b := q.line[0]
-
-		switch {
-		case b == '=':
-			b, err = q.readHexByte(q.line[1:])
-			if err != nil {
-				return n, err
-			}
-			q.line = q.line[2:] // 2 of the 3; other 1 is done below
-		case b == '\t' || b == '\r' || b == '\n':
-			break
-		case b < ' ' || b > '~':
-			return n, fmt.Errorf("multipart: invalid unescaped byte 0x%02x in quoted-printable body", b)
-		}
-		p[0] = b
-		p = p[1:]
-		q.line = q.line[1:]
-		n++
-	}
-	return n, nil
-}
diff --git a/src/mime/multipart/quotedprintable_test.go b/src/mime/multipart/quotedprintable_test.go
deleted file mode 100644
index c4de3eb..0000000
--- a/src/mime/multipart/quotedprintable_test.go
+++ /dev/null
@@ -1,204 +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.
-
-package multipart
-
-import (
-	"bufio"
-	"bytes"
-	"errors"
-	"flag"
-	"fmt"
-	"io"
-	"os/exec"
-	"regexp"
-	"sort"
-	"strings"
-	"testing"
-	"time"
-)
-
-func TestQuotedPrintable(t *testing.T) {
-	tests := []struct {
-		in, want string
-		err      interface{}
-	}{
-		{in: "", want: ""},
-		{in: "foo bar", want: "foo bar"},
-		{in: "foo bar=3D", want: "foo bar="},
-		{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: "multipart: invalid quoted-printable 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"},
-		{in: " A B =\n C ", want: " A B  C"}, // lax. treating LF as CRLF
-		{in: "foo=\nbar", want: "foobar"},
-		{in: "foo\x00bar", want: "foo", err: "multipart: invalid unescaped byte 0x00 in quoted-printable body"},
-		{in: "foo bar\xff", want: "foo bar", err: "multipart: invalid unescaped byte 0xff in quoted-printable body"},
-
-		// Equal sign.
-		{in: "=3D30\n", want: "=30\n"},
-		{in: "=00=FF0=\n", want: "\x00\xff0"},
-
-		// Trailing whitespace
-		{in: "foo  \n", want: "foo\n"},
-		{in: "foo  \n\nfoo =\n\nfoo=20\n\n", want: "foo\n\nfoo \nfoo \n\n"},
-
-		// Tests that we allow bare \n and \r through, despite it being strictly
-		// not permitted per RFC 2045, Section 6.7 Page 22 bullet (4).
-		{in: "foo\nbar", want: "foo\nbar"},
-		{in: "foo\rbar", want: "foo\rbar"},
-		{in: "foo\r\nbar", want: "foo\r\nbar"},
-
-		// Different types of soft line-breaks.
-		{in: "foo=\r\nbar", want: "foobar"},
-		{in: "foo=\nbar", want: "foobar"},
-		{in: "foo=\rbar", want: "foo", err: "multipart: invalid quoted-printable hex byte 0x0d"},
-		{in: "foo=\r\r\r \nbar", want: "foo", err: `multipart: invalid bytes after =: "\r\r\r \n"`},
-
-		// Example from RFC 2045:
-		{in: "Now's the time =\n" + "for all folk to come=\n" + " to the aid of their country.",
-			want: "Now's the time for all folk to come to the aid of their country."},
-	}
-	for _, tt := range tests {
-		var buf bytes.Buffer
-		_, err := io.Copy(&buf, newQuotedPrintableReader(strings.NewReader(tt.in)))
-		if got := buf.String(); got != tt.want {
-			t.Errorf("for %q, got %q; want %q", tt.in, got, tt.want)
-		}
-		switch verr := tt.err.(type) {
-		case nil:
-			if err != nil {
-				t.Errorf("for %q, got unexpected error: %v", tt.in, err)
-			}
-		case string:
-			if got := fmt.Sprint(err); got != verr {
-				t.Errorf("for %q, got error %q; want %q", tt.in, got, verr)
-			}
-		case error:
-			if err != verr {
-				t.Errorf("for %q, got error %q; want %q", tt.in, err, verr)
-			}
-		}
-	}
-
-}
-
-func everySequence(base, alpha string, length int, fn func(string)) {
-	if len(base) == length {
-		fn(base)
-		return
-	}
-	for i := 0; i < len(alpha); i++ {
-		everySequence(base+alpha[i:i+1], alpha, length, fn)
-	}
-}
-
-var useQprint = flag.Bool("qprint", false, "Compare against the 'qprint' program.")
-
-var badSoftRx = regexp.MustCompile(`=([^\r\n]+?\n)|([^\r\n]+$)|(\r$)|(\r[^\n]+\n)|( \r\n)`)
-
-func TestQPExhaustive(t *testing.T) {
-	if *useQprint {
-		_, err := exec.LookPath("qprint")
-		if err != nil {
-			t.Fatalf("Error looking for qprint: %v", err)
-		}
-	}
-
-	var buf bytes.Buffer
-	res := make(map[string]int)
-	everySequence("", "0A \r\n=", 6, func(s string) {
-		if strings.HasSuffix(s, "=") || strings.Contains(s, "==") {
-			return
-		}
-		buf.Reset()
-		_, err := io.Copy(&buf, newQuotedPrintableReader(strings.NewReader(s)))
-		if err != nil {
-			errStr := err.Error()
-			if strings.Contains(errStr, "invalid bytes after =:") {
-				errStr = "invalid bytes after ="
-			}
-			res[errStr]++
-			if strings.Contains(errStr, "invalid quoted-printable hex byte ") {
-				if strings.HasSuffix(errStr, "0x20") && (strings.Contains(s, "=0 ") || strings.Contains(s, "=A ") || strings.Contains(s, "= ")) {
-					return
-				}
-				if strings.HasSuffix(errStr, "0x3d") && (strings.Contains(s, "=0=") || strings.Contains(s, "=A=")) {
-					return
-				}
-				if strings.HasSuffix(errStr, "0x0a") || strings.HasSuffix(errStr, "0x0d") {
-					// bunch of cases; since whitespace at the end of a line before \n is removed.
-					return
-				}
-			}
-			if strings.Contains(errStr, "unexpected EOF") {
-				return
-			}
-			if errStr == "invalid bytes after =" && badSoftRx.MatchString(s) {
-				return
-			}
-			t.Errorf("decode(%q) = %v", s, err)
-			return
-		}
-		if *useQprint {
-			cmd := exec.Command("qprint", "-d")
-			cmd.Stdin = strings.NewReader(s)
-			stderr, err := cmd.StderrPipe()
-			if err != nil {
-				panic(err)
-			}
-			qpres := make(chan interface{}, 2)
-			go func() {
-				br := bufio.NewReader(stderr)
-				s, _ := br.ReadString('\n')
-				if s != "" {
-					qpres <- errors.New(s)
-					if cmd.Process != nil {
-						// It can get stuck on invalid input, like:
-						// echo -n "0000= " | qprint -d
-						cmd.Process.Kill()
-					}
-				}
-			}()
-			go func() {
-				want, err := cmd.Output()
-				if err == nil {
-					qpres <- want
-				}
-			}()
-			select {
-			case got := <-qpres:
-				if want, ok := got.([]byte); ok {
-					if string(want) != buf.String() {
-						t.Errorf("go decode(%q) = %q; qprint = %q", s, want, buf.String())
-					}
-				} else {
-					t.Logf("qprint -d(%q) = %v", s, got)
-				}
-			case <-time.After(5 * time.Second):
-				t.Logf("qprint timeout on %q", s)
-			}
-		}
-		res["OK"]++
-	})
-	var outcomes []string
-	for k, v := range res {
-		outcomes = append(outcomes, fmt.Sprintf("%v: %d", k, v))
-	}
-	sort.Strings(outcomes)
-	got := strings.Join(outcomes, "\n")
-	want := `OK: 21576
-invalid bytes after =: 3397
-multipart: invalid quoted-printable hex byte 0x0a: 1400
-multipart: invalid quoted-printable hex byte 0x0d: 2700
-multipart: invalid quoted-printable hex byte 0x20: 2490
-multipart: invalid quoted-printable hex byte 0x3d: 440
-unexpected EOF: 3122`
-	if got != want {
-		t.Errorf("Got:\n%s\nWant:\n%s", got, want)
-	}
-}
diff --git a/src/mime/multipart/writer.go b/src/mime/multipart/writer.go
index e13a956..8096093 100644
--- a/src/mime/multipart/writer.go
+++ b/src/mime/multipart/writer.go
@@ -39,7 +39,8 @@ func (w *Writer) Boundary() string {
 // boundary separator with an explicit value.
 //
 // SetBoundary must be called before any parts are created, may only
-// contain certain ASCII characters, and must be 1-69 bytes long.
+// contain certain ASCII characters, and must be non-empty and
+// at most 69 bytes long.
 func (w *Writer) SetBoundary(boundary string) error {
 	if w.lastpart != nil {
 		return errors.New("mime: SetBoundary called after write")
diff --git a/src/mime/quotedprintable/reader.go b/src/mime/quotedprintable/reader.go
new file mode 100644
index 0000000..3bd6833
--- /dev/null
+++ b/src/mime/quotedprintable/reader.go
@@ -0,0 +1,124 @@
+// 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.
+
+// Package quotedprintable implements quoted-printable encoding as specified by
+// RFC 2045.
+package quotedprintable
+
+import (
+	"bufio"
+	"bytes"
+	"fmt"
+	"io"
+)
+
+// Reader is a quoted-printable decoder.
+type Reader struct {
+	br   *bufio.Reader
+	rerr error  // last read error
+	line []byte // to be consumed before more of br
+}
+
+// NewReader returns a quoted-printable reader, decoding from r.
+func NewReader(r io.Reader) *Reader {
+	return &Reader{
+		br: bufio.NewReader(r),
+	}
+}
+
+func fromHex(b byte) (byte, error) {
+	switch {
+	case b >= '0' && b <= '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)
+}
+
+func readHexByte(v []byte) (b byte, err error) {
+	if len(v) < 2 {
+		return 0, io.ErrUnexpectedEOF
+	}
+	var hb, lb byte
+	if hb, err = fromHex(v[0]); err != nil {
+		return 0, err
+	}
+	if lb, err = fromHex(v[1]); err != nil {
+		return 0, err
+	}
+	return hb<<4 | lb, nil
+}
+
+func isQPDiscardWhitespace(r rune) bool {
+	switch r {
+	case '\n', '\r', ' ', '\t':
+		return true
+	}
+	return false
+}
+
+var (
+	crlf       = []byte("\r\n")
+	lf         = []byte("\n")
+	softSuffix = []byte("=")
+)
+
+// Read reads and decodes quoted-printable data from the underlying reader.
+func (r *Reader) Read(p []byte) (n int, err error) {
+	// Deviations from RFC 2045:
+	// 1. in addition to "=\r\n", "=\n" is also treated as soft line break.
+	// 2. it will pass through a '\r' or '\n' not preceded by '=', consistent
+	//    with other broken QP encoders & decoders.
+	for len(p) > 0 {
+		if len(r.line) == 0 {
+			if r.rerr != nil {
+				return n, r.rerr
+			}
+			r.line, r.rerr = r.br.ReadSlice('\n')
+
+			// Does the line end in CRLF instead of just LF?
+			hasLF := bytes.HasSuffix(r.line, lf)
+			hasCR := bytes.HasSuffix(r.line, crlf)
+			wholeLine := r.line
+			r.line = bytes.TrimRightFunc(wholeLine, isQPDiscardWhitespace)
+			if bytes.HasSuffix(r.line, softSuffix) {
+				rightStripped := wholeLine[len(r.line):]
+				r.line = r.line[:len(r.line)-1]
+				if !bytes.HasPrefix(rightStripped, lf) && !bytes.HasPrefix(rightStripped, crlf) {
+					r.rerr = fmt.Errorf("quotedprintable: invalid bytes after =: %q", rightStripped)
+				}
+			} else if hasLF {
+				if hasCR {
+					r.line = append(r.line, '\r', '\n')
+				} else {
+					r.line = append(r.line, '\n')
+				}
+			}
+			continue
+		}
+		b := r.line[0]
+
+		switch {
+		case b == '=':
+			b, err = readHexByte(r.line[1:])
+			if err != nil {
+				return n, err
+			}
+			r.line = r.line[2:] // 2 of the 3; other 1 is done below
+		case b == '\t' || b == '\r' || b == '\n':
+			break
+		case b < ' ' || b > '~':
+			return n, fmt.Errorf("quotedprintable: invalid unescaped byte 0x%02x in body", b)
+		}
+		p[0] = b
+		p = p[1:]
+		r.line = r.line[1:]
+		n++
+	}
+	return n, nil
+}
diff --git a/src/mime/quotedprintable/reader_test.go b/src/mime/quotedprintable/reader_test.go
new file mode 100644
index 0000000..e77b261
--- /dev/null
+++ b/src/mime/quotedprintable/reader_test.go
@@ -0,0 +1,204 @@
+// 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.
+
+package quotedprintable
+
+import (
+	"bufio"
+	"bytes"
+	"errors"
+	"flag"
+	"fmt"
+	"io"
+	"os/exec"
+	"regexp"
+	"sort"
+	"strings"
+	"testing"
+	"time"
+)
+
+func TestReader(t *testing.T) {
+	tests := []struct {
+		in, want string
+		err      interface{}
+	}{
+		{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=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"},
+		{in: " A B =\n C ", want: " A B  C"}, // lax. treating LF as CRLF
+		{in: "foo=\nbar", want: "foobar"},
+		{in: "foo\x00bar", want: "foo", err: "quotedprintable: invalid unescaped byte 0x00 in body"},
+		{in: "foo bar\xff", want: "foo bar", err: "quotedprintable: invalid unescaped byte 0xff in body"},
+
+		// Equal sign.
+		{in: "=3D30\n", want: "=30\n"},
+		{in: "=00=FF0=\n", want: "\x00\xff0"},
+
+		// Trailing whitespace
+		{in: "foo  \n", want: "foo\n"},
+		{in: "foo  \n\nfoo =\n\nfoo=20\n\n", want: "foo\n\nfoo \nfoo \n\n"},
+
+		// Tests that we allow bare \n and \r through, despite it being strictly
+		// not permitted per RFC 2045, Section 6.7 Page 22 bullet (4).
+		{in: "foo\nbar", want: "foo\nbar"},
+		{in: "foo\rbar", want: "foo\rbar"},
+		{in: "foo\r\nbar", want: "foo\r\nbar"},
+
+		// Different types of soft line-breaks.
+		{in: "foo=\r\nbar", want: "foobar"},
+		{in: "foo=\nbar", want: "foobar"},
+		{in: "foo=\rbar", want: "foo", err: "quotedprintable: invalid hex byte 0x0d"},
+		{in: "foo=\r\r\r \nbar", want: "foo", err: `quotedprintable: invalid bytes after =: "\r\r\r \n"`},
+
+		// Example from RFC 2045:
+		{in: "Now's the time =\n" + "for all folk to come=\n" + " to the aid of their country.",
+			want: "Now's the time for all folk to come to the aid of their country."},
+	}
+	for _, tt := range tests {
+		var buf bytes.Buffer
+		_, err := io.Copy(&buf, NewReader(strings.NewReader(tt.in)))
+		if got := buf.String(); got != tt.want {
+			t.Errorf("for %q, got %q; want %q", tt.in, got, tt.want)
+		}
+		switch verr := tt.err.(type) {
+		case nil:
+			if err != nil {
+				t.Errorf("for %q, got unexpected error: %v", tt.in, err)
+			}
+		case string:
+			if got := fmt.Sprint(err); got != verr {
+				t.Errorf("for %q, got error %q; want %q", tt.in, got, verr)
+			}
+		case error:
+			if err != verr {
+				t.Errorf("for %q, got error %q; want %q", tt.in, err, verr)
+			}
+		}
+	}
+
+}
+
+func everySequence(base, alpha string, length int, fn func(string)) {
+	if len(base) == length {
+		fn(base)
+		return
+	}
+	for i := 0; i < len(alpha); i++ {
+		everySequence(base+alpha[i:i+1], alpha, length, fn)
+	}
+}
+
+var useQprint = flag.Bool("qprint", false, "Compare against the 'qprint' program.")
+
+var badSoftRx = regexp.MustCompile(`=([^\r\n]+?\n)|([^\r\n]+$)|(\r$)|(\r[^\n]+\n)|( \r\n)`)
+
+func TestExhaustive(t *testing.T) {
+	if *useQprint {
+		_, err := exec.LookPath("qprint")
+		if err != nil {
+			t.Fatalf("Error looking for qprint: %v", err)
+		}
+	}
+
+	var buf bytes.Buffer
+	res := make(map[string]int)
+	everySequence("", "0A \r\n=", 6, func(s string) {
+		if strings.HasSuffix(s, "=") || strings.Contains(s, "==") {
+			return
+		}
+		buf.Reset()
+		_, err := io.Copy(&buf, NewReader(strings.NewReader(s)))
+		if err != nil {
+			errStr := err.Error()
+			if strings.Contains(errStr, "invalid bytes after =:") {
+				errStr = "invalid bytes after ="
+			}
+			res[errStr]++
+			if strings.Contains(errStr, "invalid hex byte ") {
+				if strings.HasSuffix(errStr, "0x20") && (strings.Contains(s, "=0 ") || strings.Contains(s, "=A ") || strings.Contains(s, "= ")) {
+					return
+				}
+				if strings.HasSuffix(errStr, "0x3d") && (strings.Contains(s, "=0=") || strings.Contains(s, "=A=")) {
+					return
+				}
+				if strings.HasSuffix(errStr, "0x0a") || strings.HasSuffix(errStr, "0x0d") {
+					// bunch of cases; since whitespace at the end of a line before \n is removed.
+					return
+				}
+			}
+			if strings.Contains(errStr, "unexpected EOF") {
+				return
+			}
+			if errStr == "invalid bytes after =" && badSoftRx.MatchString(s) {
+				return
+			}
+			t.Errorf("decode(%q) = %v", s, err)
+			return
+		}
+		if *useQprint {
+			cmd := exec.Command("qprint", "-d")
+			cmd.Stdin = strings.NewReader(s)
+			stderr, err := cmd.StderrPipe()
+			if err != nil {
+				panic(err)
+			}
+			qpres := make(chan interface{}, 2)
+			go func() {
+				br := bufio.NewReader(stderr)
+				s, _ := br.ReadString('\n')
+				if s != "" {
+					qpres <- errors.New(s)
+					if cmd.Process != nil {
+						// It can get stuck on invalid input, like:
+						// echo -n "0000= " | qprint -d
+						cmd.Process.Kill()
+					}
+				}
+			}()
+			go func() {
+				want, err := cmd.Output()
+				if err == nil {
+					qpres <- want
+				}
+			}()
+			select {
+			case got := <-qpres:
+				if want, ok := got.([]byte); ok {
+					if string(want) != buf.String() {
+						t.Errorf("go decode(%q) = %q; qprint = %q", s, want, buf.String())
+					}
+				} else {
+					t.Logf("qprint -d(%q) = %v", s, got)
+				}
+			case <-time.After(5 * time.Second):
+				t.Logf("qprint timeout on %q", s)
+			}
+		}
+		res["OK"]++
+	})
+	var outcomes []string
+	for k, v := range res {
+		outcomes = append(outcomes, fmt.Sprintf("%v: %d", k, v))
+	}
+	sort.Strings(outcomes)
+	got := strings.Join(outcomes, "\n")
+	want := `OK: 21576
+invalid bytes after =: 3397
+quotedprintable: invalid hex byte 0x0a: 1400
+quotedprintable: invalid hex byte 0x0d: 2700
+quotedprintable: invalid hex byte 0x20: 2490
+quotedprintable: invalid hex byte 0x3d: 440
+unexpected EOF: 3122`
+	if got != want {
+		t.Errorf("Got:\n%s\nWant:\n%s", got, want)
+	}
+}
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 @@ import (
 )
 
 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 @@ func TypeByExtension(ext string) string {
 	defer mimeLock.RUnlock()
 
 	// Case-sensitive lookup.
-	v := mimeTypes[ext]
-	if v != "" {
+	if v := mimeTypes[ext]; v != "" {
 		return v
 	}
 
@@ -91,19 +131,39 @@ func TypeByExtension(ext string) string {
 	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 @@ func setExtensionType(extension, mimeType string) error {
 	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_dragonfly.go b/src/mime/type_dragonfly.go
new file mode 100644
index 0000000..d09d74a
--- /dev/null
+++ b/src/mime/type_dragonfly.go
@@ -0,0 +1,9 @@
+// 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 mime
+
+func init() {
+	typeFiles = append(typeFiles, "/usr/local/etc/mime.types")
+}
diff --git a/src/mime/type_freebsd.go b/src/mime/type_freebsd.go
new file mode 100644
index 0000000..d09d74a
--- /dev/null
+++ b/src/mime/type_freebsd.go
@@ -0,0 +1,9 @@
+// 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 mime
+
+func init() {
+	typeFiles = append(typeFiles, "/usr/local/etc/mime.types")
+}
diff --git a/src/mime/type_openbsd.go b/src/mime/type_openbsd.go
new file mode 100644
index 0000000..c3b1abb
--- /dev/null
+++ b/src/mime/type_openbsd.go
@@ -0,0 +1,9 @@
+// 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 mime
+
+func init() {
+	typeFiles = append(typeFiles, "/usr/share/misc/mime.types")
+}
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 @@ import (
 	"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 @@ func loadMimeFile(filename string) {
 		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(t *testing.T) {
 	}
 }
 
+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 TestTypeByExtensionCase(t *testing.T) {
 	}
 }
 
+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 @@ import (
 	"strings"
 )
 
+func init() {
+	osInitMime = initMimeUnix
+}
+
 var typeFiles = []string{
 	"/etc/mime.types",
 	"/etc/apache2/mime.types",
@@ -44,7 +48,7 @@ func loadMimeFile(filename string) {
 	}
 }
 
-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..97b9aeb 100644
--- a/src/mime/type_windows.go
+++ b/src/mime/type_windows.go
@@ -5,54 +5,32 @@
 package mime
 
 import (
-	"syscall"
-	"unsafe"
+	"internal/syscall/windows/registry"
 )
 
-func initMime() {
-	var root syscall.Handle
-	rootpathp, _ := syscall.UTF16PtrFromString(`\`)
-	if syscall.RegOpenKeyEx(syscall.HKEY_CLASSES_ROOT, rootpathp,
-		0, syscall.KEY_READ, &root) != nil {
-		return
-	}
-	defer syscall.RegCloseKey(root)
-	var count uint32
-	if syscall.RegQueryInfoKey(root, nil, nil, nil, &count, nil, nil, nil, nil, nil, nil, nil) != nil {
+func init() {
+	osInitMime = initMimeWindows
+}
+
+func initMimeWindows() {
+	names, err := registry.CLASSES_ROOT.ReadSubKeyNames(-1)
+	if err != nil {
 		return
 	}
-	var buf [1 << 10]uint16
-	for i := uint32(0); i < count; i++ {
-		n := uint32(len(buf))
-		if syscall.RegEnumKeyEx(root, i, &buf[0], &n, nil, nil, nil, nil) != nil {
-			continue
-		}
-		ext := syscall.UTF16ToString(buf[:])
-		if len(ext) < 2 || ext[0] != '.' { // looking for extensions only
-			continue
-		}
-		var h syscall.Handle
-		extpathp, _ := syscall.UTF16PtrFromString(`\` + ext)
-		if syscall.RegOpenKeyEx(
-			syscall.HKEY_CLASSES_ROOT, extpathp,
-			0, syscall.KEY_READ, &h) != nil {
+	for _, name := range names {
+		if len(name) < 2 || name[0] != '.' { // looking for extensions only
 			continue
 		}
-		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 {
-			syscall.RegCloseKey(h)
+		k, err := registry.OpenKey(registry.CLASSES_ROOT, name, registry.READ)
+		if err != nil {
 			continue
 		}
-		syscall.RegCloseKey(h)
-		if typ != syscall.REG_SZ { // null terminated strings only
+		v, _, err := k.GetStringValue("Content Type")
+		k.Close()
+		if err != nil {
 			continue
 		}
-		mimeType := syscall.UTF16ToString(buf[:])
-		setExtensionType(ext, mimeType)
+		setExtensionType(name, v)
 	}
 }
 
diff --git a/src/nacltest.bash b/src/nacltest.bash
index 6220d39..049aad2 100755
--- a/src/nacltest.bash
+++ b/src/nacltest.bash
@@ -59,22 +59,24 @@ if ! which go_nacl_${naclGOARCH}_exec >/dev/null; then
 	exit 1
 fi
 
-# Run host build to get toolchain for running zip generator.
 unset GOOS GOARCH
 if [ ! -f make.bash ]; then
-	echo 'nacl.bash must be run from $GOROOT/src' 1>&2
+	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
+
+rm -f syscall/fstest_nacl.go
diff --git a/src/net/addrselect.go b/src/net/addrselect.go
new file mode 100644
index 0000000..e22fbac
--- /dev/null
+++ b/src/net/addrselect.go
@@ -0,0 +1,388 @@
+// 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
+
+// Minimal RFC 6724 address selection.
+
+package net
+
+import "sort"
+
+func sortByRFC6724(addrs []IPAddr) {
+	if len(addrs) < 2 {
+		return
+	}
+	sortByRFC6724withSrcs(addrs, srcAddrs(addrs))
+}
+
+func sortByRFC6724withSrcs(addrs []IPAddr, srcs []IP) {
+	if len(addrs) != len(srcs) {
+		panic("internal error")
+	}
+	addrAttr := make([]ipAttr, len(addrs))
+	srcAttr := make([]ipAttr, len(srcs))
+	for i, v := range addrs {
+		addrAttr[i] = ipAttrOf(v.IP)
+		srcAttr[i] = ipAttrOf(srcs[i])
+	}
+	sort.Stable(&byRFC6724{
+		addrs:    addrs,
+		addrAttr: addrAttr,
+		srcs:     srcs,
+		srcAttr:  srcAttr,
+	})
+}
+
+// srcsAddrs tries to UDP-connect to each address to see if it has a
+// route. (This doesn't send any packets). The destination port
+// number is irrelevant.
+func srcAddrs(addrs []IPAddr) []IP {
+	srcs := make([]IP, len(addrs))
+	dst := UDPAddr{Port: 9}
+	for i := range addrs {
+		dst.IP = addrs[i].IP
+		dst.Zone = addrs[i].Zone
+		c, err := DialUDP("udp", nil, &dst)
+		if err == nil {
+			if src, ok := c.LocalAddr().(*UDPAddr); ok {
+				srcs[i] = src.IP
+			}
+			c.Close()
+		}
+	}
+	return srcs
+}
+
+type ipAttr struct {
+	Scope      scope
+	Precedence uint8
+	Label      uint8
+}
+
+func ipAttrOf(ip IP) ipAttr {
+	if ip == nil {
+		return ipAttr{}
+	}
+	match := rfc6724policyTable.Classify(ip)
+	return ipAttr{
+		Scope:      classifyScope(ip),
+		Precedence: match.Precedence,
+		Label:      match.Label,
+	}
+}
+
+type byRFC6724 struct {
+	addrs    []IPAddr // addrs to sort
+	addrAttr []ipAttr
+	srcs     []IP // or nil if unreachable
+	srcAttr  []ipAttr
+}
+
+func (s *byRFC6724) Len() int { return len(s.addrs) }
+
+func (s *byRFC6724) Swap(i, j int) {
+	s.addrs[i], s.addrs[j] = s.addrs[j], s.addrs[i]
+	s.srcs[i], s.srcs[j] = s.srcs[j], s.srcs[i]
+	s.addrAttr[i], s.addrAttr[j] = s.addrAttr[j], s.addrAttr[i]
+	s.srcAttr[i], s.srcAttr[j] = s.srcAttr[j], s.srcAttr[i]
+}
+
+// Less reports whether i is a better destination address for this
+// host than j.
+//
+// The algorithm and variable names comes from RFC 6724 section 6.
+func (s *byRFC6724) Less(i, j int) bool {
+	DA := s.addrs[i].IP
+	DB := s.addrs[j].IP
+	SourceDA := s.srcs[i]
+	SourceDB := s.srcs[j]
+	attrDA := &s.addrAttr[i]
+	attrDB := &s.addrAttr[j]
+	attrSourceDA := &s.srcAttr[i]
+	attrSourceDB := &s.srcAttr[j]
+
+	const preferDA = true
+	const preferDB = false
+
+	// Rule 1: Avoid unusable destinations.
+	// If DB is known to be unreachable or if Source(DB) is undefined, then
+	// prefer DA.  Similarly, if DA is known to be unreachable or if
+	// Source(DA) is undefined, then prefer DB.
+	if SourceDA == nil && SourceDB == nil {
+		return false // "equal"
+	}
+	if SourceDB == nil {
+		return preferDA
+	}
+	if SourceDA == nil {
+		return preferDB
+	}
+
+	// Rule 2: Prefer matching scope.
+	// If Scope(DA) = Scope(Source(DA)) and Scope(DB) <> Scope(Source(DB)),
+	// then prefer DA.  Similarly, if Scope(DA) <> Scope(Source(DA)) and
+	// Scope(DB) = Scope(Source(DB)), then prefer DB.
+	if attrDA.Scope == attrSourceDA.Scope && attrDB.Scope != attrSourceDB.Scope {
+		return preferDA
+	}
+	if attrDA.Scope != attrSourceDA.Scope && attrDB.Scope == attrSourceDB.Scope {
+		return preferDB
+	}
+
+	// Rule 3: Avoid deprecated addresses.
+	// If Source(DA) is deprecated and Source(DB) is not, then prefer DB.
+	// Similarly, if Source(DA) is not deprecated and Source(DB) is
+	// deprecated, then prefer DA.
+
+	// TODO(bradfitz): implement? low priority for now.
+
+	// Rule 4: Prefer home addresses.
+	// If Source(DA) is simultaneously a home address and care-of address
+	// and Source(DB) is not, then prefer DA.  Similarly, if Source(DB) is
+	// simultaneously a home address and care-of address and Source(DA) is
+	// not, then prefer DB.
+
+	// TODO(bradfitz): implement? low priority for now.
+
+	// Rule 5: Prefer matching label.
+	// If Label(Source(DA)) = Label(DA) and Label(Source(DB)) <> Label(DB),
+	// then prefer DA.  Similarly, if Label(Source(DA)) <> Label(DA) and
+	// Label(Source(DB)) = Label(DB), then prefer DB.
+	if attrSourceDA.Label == attrDA.Label &&
+		attrSourceDB.Label != attrDB.Label {
+		return preferDA
+	}
+	if attrSourceDA.Label != attrDA.Label &&
+		attrSourceDB.Label == attrDB.Label {
+		return preferDB
+	}
+
+	// Rule 6: Prefer higher precedence.
+	// If Precedence(DA) > Precedence(DB), then prefer DA.  Similarly, if
+	// Precedence(DA) < Precedence(DB), then prefer DB.
+	if attrDA.Precedence > attrDB.Precedence {
+		return preferDA
+	}
+	if attrDA.Precedence < attrDB.Precedence {
+		return preferDB
+	}
+
+	// Rule 7: Prefer native transport.
+	// If DA is reached via an encapsulating transition mechanism (e.g.,
+	// IPv6 in IPv4) and DB is not, then prefer DB.  Similarly, if DB is
+	// reached via encapsulation and DA is not, then prefer DA.
+
+	// TODO(bradfitz): implement? low priority for now.
+
+	// Rule 8: Prefer smaller scope.
+	// If Scope(DA) < Scope(DB), then prefer DA.  Similarly, if Scope(DA) >
+	// Scope(DB), then prefer DB.
+	if attrDA.Scope < attrDB.Scope {
+		return preferDA
+	}
+	if attrDA.Scope > attrDB.Scope {
+		return preferDB
+	}
+
+	// Rule 9: Use longest matching prefix.
+	// When DA and DB belong to the same address family (both are IPv6 or
+	// both are IPv4): If CommonPrefixLen(Source(DA), DA) >
+	// CommonPrefixLen(Source(DB), DB), then prefer DA.  Similarly, if
+	// CommonPrefixLen(Source(DA), DA) < CommonPrefixLen(Source(DB), DB),
+	// then prefer DB.
+	da4 := DA.To4() != nil
+	db4 := DB.To4() != nil
+	if da4 == db4 {
+		commonA := commonPrefixLen(SourceDA, DA)
+		commonB := commonPrefixLen(SourceDB, DB)
+		if commonA > commonB {
+			return preferDA
+		}
+		if commonA < commonB {
+			return preferDB
+		}
+	}
+
+	// Rule 10: Otherwise, leave the order unchanged.
+	// If DA preceded DB in the original list, prefer DA.
+	// Otherwise, prefer DB.
+	return false // "equal"
+}
+
+type policyTableEntry struct {
+	Prefix     *IPNet
+	Precedence uint8
+	Label      uint8
+}
+
+type policyTable []policyTableEntry
+
+// RFC 6724 section 2.1.
+var rfc6724policyTable = policyTable{
+	{
+		Prefix:     mustCIDR("::1/128"),
+		Precedence: 50,
+		Label:      0,
+	},
+	{
+		Prefix:     mustCIDR("::/0"),
+		Precedence: 40,
+		Label:      1,
+	},
+	{
+		// IPv4-compatible, etc.
+		Prefix:     mustCIDR("::ffff:0:0/96"),
+		Precedence: 35,
+		Label:      4,
+	},
+	{
+		// 6to4
+		Prefix:     mustCIDR("2002::/16"),
+		Precedence: 30,
+		Label:      2,
+	},
+	{
+		// Teredo
+		Prefix:     mustCIDR("2001::/32"),
+		Precedence: 5,
+		Label:      5,
+	},
+	{
+		Prefix:     mustCIDR("fc00::/7"),
+		Precedence: 3,
+		Label:      13,
+	},
+	{
+		Prefix:     mustCIDR("::/96"),
+		Precedence: 1,
+		Label:      3,
+	},
+	{
+		Prefix:     mustCIDR("fec0::/10"),
+		Precedence: 1,
+		Label:      11,
+	},
+	{
+		Prefix:     mustCIDR("3ffe::/16"),
+		Precedence: 1,
+		Label:      12,
+	},
+}
+
+func init() {
+	sort.Sort(sort.Reverse(byMaskLength(rfc6724policyTable)))
+}
+
+// byMaskLength sorts policyTableEntry by the size of their Prefix.Mask.Size,
+// from smallest mask, to largest.
+type byMaskLength []policyTableEntry
+
+func (s byMaskLength) Len() int      { return len(s) }
+func (s byMaskLength) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+func (s byMaskLength) Less(i, j int) bool {
+	isize, _ := s[i].Prefix.Mask.Size()
+	jsize, _ := s[j].Prefix.Mask.Size()
+	return isize < jsize
+}
+
+// mustCIDR calls ParseCIDR and panics on any error, or if the network
+// is not IPv6.
+func mustCIDR(s string) *IPNet {
+	ip, ipNet, err := ParseCIDR(s)
+	if err != nil {
+		panic(err.Error())
+	}
+	if len(ip) != IPv6len {
+		panic("unexpected IP length")
+	}
+	return ipNet
+}
+
+// Classify returns the policyTableEntry of the entry with the longest
+// matching prefix that contains ip.
+// The table t must be sorted from largest mask size to smallest.
+func (t policyTable) Classify(ip IP) policyTableEntry {
+	for _, ent := range t {
+		if ent.Prefix.Contains(ip) {
+			return ent
+		}
+	}
+	return policyTableEntry{}
+}
+
+// RFC 6724 section 3.1.
+type scope uint8
+
+const (
+	scopeInterfaceLocal scope = 0x1
+	scopeLinkLocal      scope = 0x2
+	scopeAdminLocal     scope = 0x4
+	scopeSiteLocal      scope = 0x5
+	scopeOrgLocal       scope = 0x8
+	scopeGlobal         scope = 0xe
+)
+
+func classifyScope(ip IP) scope {
+	if ip.IsLoopback() || ip.IsLinkLocalUnicast() {
+		return scopeLinkLocal
+	}
+	ipv6 := len(ip) == IPv6len && ip.To4() == nil
+	if ipv6 && ip.IsMulticast() {
+		return scope(ip[1] & 0xf)
+	}
+	// Site-local addresses are defined in RFC 3513 section 2.5.6
+	// (and deprecated in RFC 3879).
+	if ipv6 && ip[0] == 0xfe && ip[1]&0xc0 == 0xc0 {
+		return scopeSiteLocal
+	}
+	return scopeGlobal
+}
+
+// commonPrefixLen reports the length of the longest prefix (looking
+// at the most significant, or leftmost, bits) that the
+// two addresses have in common, up to the length of a's prefix (i.e.,
+// the portion of the address not including the interface ID).
+//
+// If a or b is an IPv4 address as an IPv6 address, the IPv4 addresses
+// are compared (with max common prefix length of 32).
+// If a and b are different IP versions, 0 is returned.
+//
+// See https://tools.ietf.org/html/rfc6724#section-2.2
+func commonPrefixLen(a, b IP) (cpl int) {
+	if a4 := a.To4(); a4 != nil {
+		a = a4
+	}
+	if b4 := b.To4(); b4 != nil {
+		b = b4
+	}
+	if len(a) != len(b) {
+		return 0
+	}
+	// If IPv6, only up to the prefix (first 64 bits)
+	if len(a) > 8 {
+		a = a[:8]
+		b = b[:8]
+	}
+	for len(a) > 0 {
+		if a[0] == b[0] {
+			cpl += 8
+			a = a[1:]
+			b = b[1:]
+			continue
+		}
+		bits := 8
+		ab, bb := a[0], b[0]
+		for {
+			ab >>= 1
+			bb >>= 1
+			bits--
+			if ab == bb {
+				cpl += bits
+				return
+			}
+		}
+	}
+	return
+}
diff --git a/src/net/addrselect_test.go b/src/net/addrselect_test.go
new file mode 100644
index 0000000..5620227
--- /dev/null
+++ b/src/net/addrselect_test.go
@@ -0,0 +1,219 @@
+// 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 net
+
+import (
+	"reflect"
+	"testing"
+)
+
+func TestSortByRFC6724(t *testing.T) {
+	tests := []struct {
+		in      []IPAddr
+		srcs    []IP
+		want    []IPAddr
+		reverse bool // also test it starting backwards
+	}{
+		// Examples from RFC 6724 section 10.2:
+
+		// Prefer matching scope.
+		{
+			in: []IPAddr{
+				{IP: ParseIP("2001:db8:1::1")},
+				{IP: ParseIP("198.51.100.121")},
+			},
+			srcs: []IP{
+				ParseIP("2001:db8:1::2"),
+				ParseIP("169.254.13.78"),
+			},
+			want: []IPAddr{
+				{IP: ParseIP("2001:db8:1::1")},
+				{IP: ParseIP("198.51.100.121")},
+			},
+			reverse: true,
+		},
+
+		// Prefer matching scope.
+		{
+			in: []IPAddr{
+				{IP: ParseIP("2001:db8:1::1")},
+				{IP: ParseIP("198.51.100.121")},
+			},
+			srcs: []IP{
+				ParseIP("fe80::1"),
+				ParseIP("198.51.100.117"),
+			},
+			want: []IPAddr{
+				{IP: ParseIP("198.51.100.121")},
+				{IP: ParseIP("2001:db8:1::1")},
+			},
+			reverse: true,
+		},
+
+		// Prefer higher precedence.
+		{
+			in: []IPAddr{
+				{IP: ParseIP("2001:db8:1::1")},
+				{IP: ParseIP("10.1.2.3")},
+			},
+			srcs: []IP{
+				ParseIP("2001:db8:1::2"),
+				ParseIP("10.1.2.4"),
+			},
+			want: []IPAddr{
+				{IP: ParseIP("2001:db8:1::1")},
+				{IP: ParseIP("10.1.2.3")},
+			},
+			reverse: true,
+		},
+
+		// Prefer smaller scope.
+		{
+			in: []IPAddr{
+				{IP: ParseIP("2001:db8:1::1")},
+				{IP: ParseIP("fe80::1")},
+			},
+			srcs: []IP{
+				ParseIP("2001:db8:1::2"),
+				ParseIP("fe80::2"),
+			},
+			want: []IPAddr{
+				{IP: ParseIP("fe80::1")},
+				{IP: ParseIP("2001:db8:1::1")},
+			},
+			reverse: true,
+		},
+	}
+	for i, tt := range tests {
+		inCopy := make([]IPAddr, len(tt.in))
+		copy(inCopy, tt.in)
+		srcCopy := make([]IP, len(tt.in))
+		copy(srcCopy, tt.srcs)
+		sortByRFC6724withSrcs(inCopy, srcCopy)
+		if !reflect.DeepEqual(inCopy, tt.want) {
+			t.Errorf("test %d:\nin = %s\ngot: %s\nwant: %s\n", i, tt.in, inCopy, tt.want)
+		}
+		if tt.reverse {
+			copy(inCopy, tt.in)
+			copy(srcCopy, tt.srcs)
+			for j := 0; j < len(inCopy)/2; j++ {
+				k := len(inCopy) - j - 1
+				inCopy[j], inCopy[k] = inCopy[k], inCopy[j]
+				srcCopy[j], srcCopy[k] = srcCopy[k], srcCopy[j]
+			}
+			sortByRFC6724withSrcs(inCopy, srcCopy)
+			if !reflect.DeepEqual(inCopy, tt.want) {
+				t.Errorf("test %d, starting backwards:\nin = %s\ngot: %s\nwant: %s\n", i, tt.in, inCopy, tt.want)
+			}
+		}
+
+	}
+
+}
+
+func TestRFC6724PolicyTableClassify(t *testing.T) {
+	tests := []struct {
+		ip   IP
+		want policyTableEntry
+	}{
+		{
+			ip: ParseIP("127.0.0.1"),
+			want: policyTableEntry{
+				Prefix:     &IPNet{IP: ParseIP("::ffff:0:0"), Mask: CIDRMask(96, 128)},
+				Precedence: 35,
+				Label:      4,
+			},
+		},
+		{
+			ip: ParseIP("2601:645:8002:a500:986f:1db8:c836:bd65"),
+			want: policyTableEntry{
+				Prefix:     &IPNet{IP: ParseIP("::"), Mask: CIDRMask(0, 128)},
+				Precedence: 40,
+				Label:      1,
+			},
+		},
+		{
+			ip: ParseIP("::1"),
+			want: policyTableEntry{
+				Prefix:     &IPNet{IP: ParseIP("::1"), Mask: CIDRMask(128, 128)},
+				Precedence: 50,
+				Label:      0,
+			},
+		},
+		{
+			ip: ParseIP("2002::ab12"),
+			want: policyTableEntry{
+				Prefix:     &IPNet{IP: ParseIP("2002::"), Mask: CIDRMask(16, 128)},
+				Precedence: 30,
+				Label:      2,
+			},
+		},
+	}
+	for i, tt := range tests {
+		got := rfc6724policyTable.Classify(tt.ip)
+		if !reflect.DeepEqual(got, tt.want) {
+			t.Errorf("%d. Classify(%s) = %v; want %v", i, tt.ip, got, tt.want)
+		}
+	}
+}
+
+func TestRFC6724ClassifyScope(t *testing.T) {
+	tests := []struct {
+		ip   IP
+		want scope
+	}{
+		{ParseIP("127.0.0.1"), scopeLinkLocal},   // rfc6724#section-3.2
+		{ParseIP("::1"), scopeLinkLocal},         // rfc4007#section-4
+		{ParseIP("169.254.1.2"), scopeLinkLocal}, // rfc6724#section-3.2
+		{ParseIP("fec0::1"), scopeSiteLocal},
+		{ParseIP("8.8.8.8"), scopeGlobal},
+
+		{ParseIP("ff02::"), scopeLinkLocal},  // IPv6 multicast
+		{ParseIP("ff05::"), scopeSiteLocal},  // IPv6 multicast
+		{ParseIP("ff04::"), scopeAdminLocal}, // IPv6 multicast
+		{ParseIP("ff0e::"), scopeGlobal},     // IPv6 multicast
+
+		{IPv4(0xe0, 0, 0, 0), scopeGlobal},       // IPv4 link-local multicast as 16 bytes
+		{IPv4(0xe0, 2, 2, 2), scopeGlobal},       // IPv4 global multicast as 16 bytes
+		{IPv4(0xe0, 0, 0, 0).To4(), scopeGlobal}, // IPv4 link-local multicast as 4 bytes
+		{IPv4(0xe0, 2, 2, 2).To4(), scopeGlobal}, // IPv4 global multicast as 4 bytes
+	}
+	for i, tt := range tests {
+		got := classifyScope(tt.ip)
+		if got != tt.want {
+			t.Errorf("%d. classifyScope(%s) = %x; want %x", i, tt.ip, got, tt.want)
+		}
+	}
+}
+
+func TestRFC6724CommonPrefixLength(t *testing.T) {
+	tests := []struct {
+		a, b IP
+		want int
+	}{
+		{ParseIP("fe80::1"), ParseIP("fe80::2"), 64},
+		{ParseIP("fe81::1"), ParseIP("fe80::2"), 15},
+		{ParseIP("127.0.0.1"), ParseIP("fe80::1"), 0}, // diff size
+		{IPv4(1, 2, 3, 4), IP{1, 2, 3, 4}, 32},
+		{IP{1, 2, 255, 255}, IP{1, 2, 0, 0}, 16},
+		{IP{1, 2, 127, 255}, IP{1, 2, 0, 0}, 17},
+		{IP{1, 2, 63, 255}, IP{1, 2, 0, 0}, 18},
+		{IP{1, 2, 31, 255}, IP{1, 2, 0, 0}, 19},
+		{IP{1, 2, 15, 255}, IP{1, 2, 0, 0}, 20},
+		{IP{1, 2, 7, 255}, IP{1, 2, 0, 0}, 21},
+		{IP{1, 2, 3, 255}, IP{1, 2, 0, 0}, 22},
+		{IP{1, 2, 1, 255}, IP{1, 2, 0, 0}, 23},
+		{IP{1, 2, 0, 255}, IP{1, 2, 0, 0}, 24},
+	}
+	for i, tt := range tests {
+		got := commonPrefixLen(tt.a, tt.b)
+		if got != tt.want {
+			t.Errorf("%d. commonPrefixLen(%s, %s) = %d; want %d", i, tt.a, tt.b, got, tt.want)
+		}
+	}
+
+}
diff --git a/src/net/cgo_android.go b/src/net/cgo_android.go
index 3819ce5..fe9925b 100644
--- a/src/net/cgo_android.go
+++ b/src/net/cgo_android.go
@@ -9,6 +9,4 @@ package net
 //#include <netdb.h>
 import "C"
 
-func cgoAddrInfoFlags() C.int {
-	return C.AI_CANONNAME
-}
+const cgoAddrInfoFlags = C.AI_CANONNAME
diff --git a/src/net/cgo_bsd.go b/src/net/cgo_bsd.go
index 3090d30..c5ec9dd 100644
--- a/src/net/cgo_bsd.go
+++ b/src/net/cgo_bsd.go
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build !netgo
-// +build darwin dragonfly freebsd solaris
+// +build cgo,!netgo
+// +build darwin dragonfly freebsd
 
 package net
 
@@ -12,6 +12,4 @@ package net
 */
 import "C"
 
-func cgoAddrInfoFlags() C.int {
-	return (C.AI_CANONNAME | C.AI_V4MAPPED | C.AI_ALL) & C.AI_MASK
-}
+const cgoAddrInfoFlags = (C.AI_CANONNAME | C.AI_V4MAPPED | C.AI_ALL) & C.AI_MASK
diff --git a/src/net/cgo_linux.go b/src/net/cgo_linux.go
index 4ef2d0c..9a5f898 100644
--- a/src/net/cgo_linux.go
+++ b/src/net/cgo_linux.go
@@ -11,12 +11,10 @@ package net
 */
 import "C"
 
-func cgoAddrInfoFlags() C.int {
-	// NOTE(rsc): In theory there are approximately balanced
-	// arguments for and against including AI_ADDRCONFIG
-	// in the flags (it includes IPv4 results only on IPv4 systems,
-	// and similarly for IPv6), but in practice setting it causes
-	// getaddrinfo to return the wrong canonical name on Linux.
-	// So definitely leave it out.
-	return C.AI_CANONNAME | C.AI_V4MAPPED | C.AI_ALL
-}
+// NOTE(rsc): In theory there are approximately balanced
+// arguments for and against including AI_ADDRCONFIG
+// in the flags (it includes IPv4 results only on IPv4 systems,
+// and similarly for IPv6), but in practice setting it causes
+// getaddrinfo to return the wrong canonical name on Linux.
+// So definitely leave it out.
+const cgoAddrInfoFlags = C.AI_CANONNAME | C.AI_V4MAPPED | C.AI_ALL
diff --git a/src/net/cgo_netbsd.go b/src/net/cgo_netbsd.go
index 09c5ad2..1830913 100644
--- a/src/net/cgo_netbsd.go
+++ b/src/net/cgo_netbsd.go
@@ -11,6 +11,4 @@ package net
 */
 import "C"
 
-func cgoAddrInfoFlags() C.int {
-	return C.AI_CANONNAME
-}
+const cgoAddrInfoFlags = C.AI_CANONNAME
diff --git a/src/net/cgo_openbsd.go b/src/net/cgo_openbsd.go
index 09c5ad2..1830913 100644
--- a/src/net/cgo_openbsd.go
+++ b/src/net/cgo_openbsd.go
@@ -11,6 +11,4 @@ package net
 */
 import "C"
 
-func cgoAddrInfoFlags() C.int {
-	return C.AI_CANONNAME
-}
+const cgoAddrInfoFlags = C.AI_CANONNAME
diff --git a/src/net/cgo_resnew.go b/src/net/cgo_resnew.go
new file mode 100644
index 0000000..3e3e77e
--- /dev/null
+++ b/src/net/cgo_resnew.go
@@ -0,0 +1,23 @@
+// 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 cgo,!netgo
+// +build darwin linux,!android netbsd solaris
+
+package net
+
+/*
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netdb.h>
+*/
+import "C"
+
+import "unsafe"
+
+func cgoNameinfoPTR(b []byte, sa *C.struct_sockaddr, salen C.socklen_t) (int, error) {
+	gerrno, err := C.getnameinfo(sa, salen, (*C.char)(unsafe.Pointer(&b[0])), C.socklen_t(len(b)), nil, 0, C.NI_NAMEREQD)
+	return int(gerrno), err
+}
diff --git a/src/net/cgo_resold.go b/src/net/cgo_resold.go
new file mode 100644
index 0000000..abd04a8
--- /dev/null
+++ b/src/net/cgo_resold.go
@@ -0,0 +1,23 @@
+// 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 cgo,!netgo
+// +build android freebsd dragonfly openbsd
+
+package net
+
+/*
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netdb.h>
+*/
+import "C"
+
+import "unsafe"
+
+func cgoNameinfoPTR(b []byte, sa *C.struct_sockaddr, salen C.socklen_t) (int, error) {
+	gerrno, err := C.getnameinfo(sa, salen, (*C.char)(unsafe.Pointer(&b[0])), C.size_t(len(b)), nil, 0, C.NI_NAMEREQD)
+	return int(gerrno), err
+}
diff --git a/src/net/cgo_socknew.go b/src/net/cgo_socknew.go
new file mode 100644
index 0000000..b508284
--- /dev/null
+++ b/src/net/cgo_socknew.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.
+
+// +build cgo,!netgo
+// +build android linux solaris
+
+package net
+
+/*
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+*/
+import "C"
+
+import (
+	"syscall"
+	"unsafe"
+)
+
+func cgoSockaddrInet4(ip IP) *C.struct_sockaddr {
+	sa := syscall.RawSockaddrInet4{Family: syscall.AF_INET}
+	copy(sa.Addr[:], ip)
+	return (*C.struct_sockaddr)(unsafe.Pointer(&sa))
+}
+
+func cgoSockaddrInet6(ip IP) *C.struct_sockaddr {
+	sa := syscall.RawSockaddrInet6{Family: syscall.AF_INET6}
+	copy(sa.Addr[:], ip)
+	return (*C.struct_sockaddr)(unsafe.Pointer(&sa))
+}
diff --git a/src/net/cgo_sockold.go b/src/net/cgo_sockold.go
new file mode 100644
index 0000000..522e8e5
--- /dev/null
+++ b/src/net/cgo_sockold.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.
+
+// +build cgo,!netgo
+// +build darwin dragonfly freebsd netbsd openbsd
+
+package net
+
+/*
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <netinet/in.h>
+*/
+import "C"
+
+import (
+	"syscall"
+	"unsafe"
+)
+
+func cgoSockaddrInet4(ip IP) *C.struct_sockaddr {
+	sa := syscall.RawSockaddrInet4{Len: syscall.SizeofSockaddrInet4, Family: syscall.AF_INET}
+	copy(sa.Addr[:], ip)
+	return (*C.struct_sockaddr)(unsafe.Pointer(&sa))
+}
+
+func cgoSockaddrInet6(ip IP) *C.struct_sockaddr {
+	sa := syscall.RawSockaddrInet6{Len: syscall.SizeofSockaddrInet6, Family: syscall.AF_INET6}
+	copy(sa.Addr[:], ip)
+	return (*C.struct_sockaddr)(unsafe.Pointer(&sa))
+}
diff --git a/src/net/cgo_solaris.go b/src/net/cgo_solaris.go
new file mode 100644
index 0000000..dd936dd
--- /dev/null
+++ b/src/net/cgo_solaris.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.
+
+// +build cgo,!netgo
+
+package net
+
+/*
+#cgo LDFLAGS: -lsocket -lnsl -lsendfile
+#include <netdb.h>
+*/
+import "C"
+
+const cgoAddrInfoFlags = C.AI_CANONNAME | C.AI_V4MAPPED | C.AI_ALL
diff --git a/src/net/cgo_stub.go b/src/net/cgo_stub.go
index f533c14..b86ff7d 100644
--- a/src/net/cgo_stub.go
+++ b/src/net/cgo_stub.go
@@ -4,10 +4,16 @@
 
 // +build !cgo netgo
 
-// Stub cgo routines for systems that do not use cgo to do network lookups.
-
 package net
 
+func init() { netGo = true }
+
+type addrinfoErrno int
+
+func (eai addrinfoErrno) Error() string   { return "<nil>" }
+func (eai addrinfoErrno) Temporary() bool { return false }
+func (eai addrinfoErrno) Timeout() bool   { return false }
+
 func cgoLookupHost(name string) (addrs []string, err error, completed bool) {
 	return nil, nil, false
 }
@@ -16,10 +22,14 @@ func cgoLookupPort(network, service string) (port int, err error, completed bool
 	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
 }
 
 func cgoLookupCNAME(name string) (cname string, err error, completed bool) {
 	return "", nil, false
 }
+
+func cgoLookupPTR(addr string) (ptrs []string, err error, completed bool) {
+	return nil, nil, false
+}
diff --git a/src/net/cgo_unix.go b/src/net/cgo_unix.go
index 1f366ee..cb89d65 100644
--- a/src/net/cgo_unix.go
+++ b/src/net/cgo_unix.go
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build !netgo
-// +build darwin dragonfly freebsd linux netbsd openbsd
+// +build cgo,!netgo
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package net
 
@@ -23,24 +23,30 @@ import (
 	"unsafe"
 )
 
-func cgoLookupHost(name string) (addrs []string, err error, completed bool) {
-	ip, err, completed := cgoLookupIP(name)
-	for _, p := range ip {
-		addrs = append(addrs, p.String())
+// An addrinfoErrno represents a getaddrinfo, getnameinfo-specific
+// error number. It's a signed number and a zero value is a non-error
+// by convention.
+type addrinfoErrno int
+
+func (eai addrinfoErrno) Error() string   { return C.GoString(C.gai_strerror(C.int(eai))) }
+func (eai addrinfoErrno) Temporary() bool { return eai == C.EAI_AGAIN }
+func (eai addrinfoErrno) Timeout() bool   { return false }
+
+func cgoLookupHost(name string) (hosts []string, err error, completed bool) {
+	addrs, err, completed := cgoLookupIP(name)
+	for _, addr := range addrs {
+		hosts = append(hosts, addr.String())
 	}
 	return
 }
 
-func cgoLookupPort(net, service string) (port int, err error, completed bool) {
+func cgoLookupPort(network, service string) (port int, err error, completed bool) {
 	acquireThread()
 	defer releaseThread()
 
-	var res *C.struct_addrinfo
 	var hints C.struct_addrinfo
-
-	switch net {
-	case "":
-		// no hints
+	switch network {
+	case "": // no hints
 	case "tcp", "tcp4", "tcp6":
 		hints.ai_socktype = C.SOCK_STREAM
 		hints.ai_protocol = C.IPPROTO_TCP
@@ -48,10 +54,10 @@ func cgoLookupPort(net, service string) (port int, err error, completed bool) {
 		hints.ai_socktype = C.SOCK_DGRAM
 		hints.ai_protocol = C.IPPROTO_UDP
 	default:
-		return 0, UnknownNetworkError(net), true
+		return 0, &DNSError{Err: "unknown network", Name: network + "/" + service}, true
 	}
-	if len(net) >= 4 {
-		switch net[3] {
+	if len(network) >= 4 {
+		switch network[3] {
 		case '4':
 			hints.ai_family = C.AF_INET
 		case '6':
@@ -60,45 +66,52 @@ func cgoLookupPort(net, service string) (port int, err error, completed bool) {
 	}
 
 	s := C.CString(service)
+	var res *C.struct_addrinfo
 	defer C.free(unsafe.Pointer(s))
-	if C.getaddrinfo(nil, s, &hints, &res) == 0 {
-		defer C.freeaddrinfo(res)
-		for r := res; r != nil; r = r.ai_next {
-			switch r.ai_family {
-			default:
-				continue
-			case C.AF_INET:
-				sa := (*syscall.RawSockaddrInet4)(unsafe.Pointer(r.ai_addr))
-				p := (*[2]byte)(unsafe.Pointer(&sa.Port))
-				return int(p[0])<<8 | int(p[1]), nil, true
-			case C.AF_INET6:
-				sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(r.ai_addr))
-				p := (*[2]byte)(unsafe.Pointer(&sa.Port))
-				return int(p[0])<<8 | int(p[1]), nil, true
+	gerrno, err := C.getaddrinfo(nil, s, &hints, &res)
+	if gerrno != 0 {
+		switch gerrno {
+		case C.EAI_SYSTEM:
+			if err == nil { // see golang.org/issue/6232
+				err = syscall.EMFILE
 			}
+		default:
+			err = addrinfoErrno(gerrno)
 		}
+		return 0, &DNSError{Err: err.Error(), Name: network + "/" + service}, true
 	}
-	return 0, &AddrError{"unknown port", net + "/" + service}, true
+	defer C.freeaddrinfo(res)
+
+	for r := res; r != nil; r = r.ai_next {
+		switch r.ai_family {
+		case C.AF_INET:
+			sa := (*syscall.RawSockaddrInet4)(unsafe.Pointer(r.ai_addr))
+			p := (*[2]byte)(unsafe.Pointer(&sa.Port))
+			return int(p[0])<<8 | int(p[1]), nil, true
+		case C.AF_INET6:
+			sa := (*syscall.RawSockaddrInet6)(unsafe.Pointer(r.ai_addr))
+			p := (*[2]byte)(unsafe.Pointer(&sa.Port))
+			return int(p[0])<<8 | int(p[1]), nil, true
+		}
+	}
+	return 0, &DNSError{Err: "unknown port", Name: network + "/" + 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()
 
-	var res *C.struct_addrinfo
 	var hints C.struct_addrinfo
-
-	hints.ai_flags = cgoAddrInfoFlags()
+	hints.ai_flags = cgoAddrInfoFlags
 	hints.ai_socktype = C.SOCK_STREAM
 
 	h := C.CString(name)
 	defer C.free(unsafe.Pointer(h))
+	var res *C.struct_addrinfo
 	gerrno, err := C.getaddrinfo(h, nil, &hints, &res)
 	if gerrno != 0 {
-		var str string
-		if gerrno == C.EAI_NONAME {
-			str = noSuchHost
-		} else if gerrno == C.EAI_SYSTEM {
+		switch gerrno {
+		case C.EAI_SYSTEM:
 			if err == nil {
 				// err should not be nil, but sometimes getaddrinfo returns
 				// gerrno == C.EAI_SYSTEM with err == nil on Linux.
@@ -109,13 +122,15 @@ func cgoLookupIPCNAME(name string) (addrs []IP, cname string, err error, complet
 				// comes up again. golang.org/issue/6232.
 				err = syscall.EMFILE
 			}
-			str = err.Error()
-		} else {
-			str = C.GoString(C.gai_strerror(gerrno))
+		case C.EAI_NONAME:
+			err = errNoSuchHost
+		default:
+			err = addrinfoErrno(gerrno)
 		}
-		return nil, "", &DNSError{Err: str, Name: name}, true
+		return nil, "", &DNSError{Err: err.Error(), Name: name}, true
 	}
 	defer C.freeaddrinfo(res)
+
 	if res != nil {
 		cname = C.GoString(res.ai_canonname)
 		if cname == "" {
@@ -131,20 +146,20 @@ func cgoLookupIPCNAME(name string) (addrs []IP, cname string, err error, complet
 			continue
 		}
 		switch r.ai_family {
-		default:
-			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
 }
@@ -154,6 +169,77 @@ func cgoLookupCNAME(name string) (cname string, err error, completed bool) {
 	return
 }
 
+// These are roughly enough for the following:
+//
+// Source		Encoding			Maximum length of single name entry
+// Unicast DNS		ASCII or			<=253 + a NUL terminator
+//			Unicode in RFC 5892		252 * total number of labels + delimiters + a NUL terminator
+// Multicast DNS	UTF-8 in RFC 5198 or		<=253 + a NUL terminator
+//			the same as unicast DNS ASCII	<=253 + a NUL terminator
+// Local database	various				depends on implementation
+const (
+	nameinfoLen    = 64
+	maxNameinfoLen = 4096
+)
+
+func cgoLookupPTR(addr string) ([]string, error, bool) {
+	acquireThread()
+	defer releaseThread()
+
+	ip := ParseIP(addr)
+	if ip == nil {
+		return nil, &DNSError{Err: "invalid address", Name: addr}, true
+	}
+	sa, salen := cgoSockaddr(ip)
+	if sa == nil {
+		return nil, &DNSError{Err: "invalid address " + ip.String(), Name: addr}, true
+	}
+	var err error
+	var b []byte
+	var gerrno int
+	for l := nameinfoLen; l <= maxNameinfoLen; l *= 2 {
+		b = make([]byte, l)
+		gerrno, err = cgoNameinfoPTR(b, sa, salen)
+		if gerrno == 0 || gerrno != C.EAI_OVERFLOW {
+			break
+		}
+	}
+	if gerrno != 0 {
+		switch gerrno {
+		case C.EAI_SYSTEM:
+			if err == nil { // see golang.org/issue/6232
+				err = syscall.EMFILE
+			}
+		default:
+			err = addrinfoErrno(gerrno)
+		}
+		return nil, &DNSError{Err: err.Error(), Name: addr}, true
+	}
+
+	for i := 0; i < len(b); i++ {
+		if b[i] == 0 {
+			b = b[:i]
+			break
+		}
+	}
+	// Add trailing dot to match pure Go reverse resolver
+	// and all other lookup routines. See golang.org/issue/12189.
+	if len(b) > 0 && b[len(b)-1] != '.' {
+		b = append(b, '.')
+	}
+	return []string{string(b)}, nil, true
+}
+
+func cgoSockaddr(ip IP) (*C.struct_sockaddr, C.socklen_t) {
+	if ip4 := ip.To4(); ip4 != nil {
+		return cgoSockaddrInet4(ip4), C.socklen_t(syscall.SizeofSockaddrInet4)
+	}
+	if ip6 := ip.To16(); ip6 != nil {
+		return cgoSockaddrInet6(ip6), C.socklen_t(syscall.SizeofSockaddrInet6)
+	}
+	return nil, 0
+}
+
 func copyIP(x IP) IP {
 	if len(x) < 16 {
 		return x.To16()
diff --git a/src/net/cgo_unix_test.go b/src/net/cgo_unix_test.go
index 33566ce..4d5ab23 100644
--- a/src/net/cgo_unix_test.go
+++ b/src/net/cgo_unix_test.go
@@ -3,7 +3,7 @@
 // license that can be found in the LICENSE file.
 
 // +build cgo,!netgo
-// +build darwin dragonfly freebsd linux netbsd openbsd
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
 
 package net
 
@@ -16,9 +16,9 @@ func TestCgoLookupIP(t *testing.T) {
 		t.Errorf("cgoLookupIP must not be a placeholder")
 	}
 	if err != nil {
-		t.Errorf("cgoLookupIP failed: %v", err)
+		t.Error(err)
 	}
 	if _, err := goLookupIP(host); err != nil {
-		t.Errorf("goLookupIP failed: %v", err)
+		t.Error(err)
 	}
 }
diff --git a/src/net/cgo_windows.go b/src/net/cgo_windows.go
new file mode 100644
index 0000000..8968b75
--- /dev/null
+++ b/src/net/cgo_windows.go
@@ -0,0 +1,13 @@
+// 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 cgo,!netgo
+
+package net
+
+type addrinfoErrno int
+
+func (eai addrinfoErrno) Error() string   { return "<nil>" }
+func (eai addrinfoErrno) Temporary() bool { return false }
+func (eai addrinfoErrno) Timeout() bool   { return false }
diff --git a/src/net/conf.go b/src/net/conf.go
new file mode 100644
index 0000000..c92e579
--- /dev/null
+++ b/src/net/conf.go
@@ -0,0 +1,308 @@
+// 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 net
+
+import (
+	"os"
+	"runtime"
+	"strconv"
+	"sync"
+	"syscall"
+)
+
+// conf represents a system's network configuration.
+type conf struct {
+	// forceCgoLookupHost forces CGO to always be used, if available.
+	forceCgoLookupHost bool
+
+	netGo  bool // go DNS resolution forced
+	netCgo bool // cgo DNS resolution forced
+
+	// machine has an /etc/mdns.allow file
+	hasMDNSAllow bool
+
+	goos          string // the runtime.GOOS, to ease testing
+	dnsDebugLevel int
+
+	nss    *nssConf
+	resolv *dnsConfig
+}
+
+var (
+	confOnce sync.Once // guards init of confVal via initConfVal
+	confVal  = &conf{goos: runtime.GOOS}
+)
+
+// systemConf returns the machine's network configuration.
+func systemConf() *conf {
+	confOnce.Do(initConfVal)
+	return confVal
+}
+
+func initConfVal() {
+	dnsMode, debugLevel := goDebugNetDNS()
+	confVal.dnsDebugLevel = debugLevel
+	confVal.netGo = netGo || dnsMode == "go"
+	confVal.netCgo = netCgo || dnsMode == "cgo"
+
+	if confVal.dnsDebugLevel > 0 {
+		defer func() {
+			switch {
+			case confVal.netGo:
+				if netGo {
+					println("go package net: built with netgo build tag; using Go's DNS resolver")
+				} else {
+					println("go package net: GODEBUG setting forcing use of Go's resolver")
+				}
+			case confVal.forceCgoLookupHost:
+				println("go package net: using cgo DNS resolver")
+			default:
+				println("go package net: dynamic selection of DNS resolver")
+			}
+		}()
+	}
+
+	// Darwin pops up annoying dialog boxes if programs try to do
+	// their own DNS requests. So always use cgo instead, which
+	// avoids that.
+	if runtime.GOOS == "darwin" {
+		confVal.forceCgoLookupHost = true
+		return
+	}
+
+	// If any environment-specified resolver options are specified,
+	// force cgo. Note that LOCALDOMAIN can change behavior merely
+	// by being specified with the empty string.
+	_, localDomainDefined := syscall.Getenv("LOCALDOMAIN")
+	if os.Getenv("RES_OPTIONS") != "" ||
+		os.Getenv("HOSTALIASES") != "" ||
+		confVal.netCgo ||
+		localDomainDefined {
+		confVal.forceCgoLookupHost = true
+		return
+	}
+
+	// OpenBSD apparently lets you override the location of resolv.conf
+	// with ASR_CONFIG. If we notice that, defer to libc.
+	if runtime.GOOS == "openbsd" && os.Getenv("ASR_CONFIG") != "" {
+		confVal.forceCgoLookupHost = true
+		return
+	}
+
+	if runtime.GOOS != "openbsd" {
+		confVal.nss = parseNSSConfFile("/etc/nsswitch.conf")
+	}
+
+	confVal.resolv = dnsReadConfig("/etc/resolv.conf")
+	if confVal.resolv.err != nil && !os.IsNotExist(confVal.resolv.err) &&
+		!os.IsPermission(confVal.resolv.err) {
+		// If we can't read the resolv.conf file, assume it
+		// had something important in it and defer to cgo.
+		// libc's resolver might then fail too, but at least
+		// it wasn't our fault.
+		confVal.forceCgoLookupHost = true
+	}
+
+	if _, err := os.Stat("/etc/mdns.allow"); err == nil {
+		confVal.hasMDNSAllow = true
+	}
+}
+
+// canUseCgo reports whether calling cgo functions is allowed
+// for non-hostname lookups.
+func (c *conf) canUseCgo() bool {
+	return c.hostLookupOrder("") == hostLookupCgo
+}
+
+// hostLookupOrder determines which strategy to use to resolve hostname.
+func (c *conf) hostLookupOrder(hostname string) (ret hostLookupOrder) {
+	if c.dnsDebugLevel > 1 {
+		defer func() {
+			print("go package net: hostLookupOrder(", hostname, ") = ", ret.String(), "\n")
+		}()
+	}
+	if c.netGo {
+		return hostLookupFilesDNS
+	}
+	if c.forceCgoLookupHost || c.resolv.unknownOpt || c.goos == "android" {
+		return hostLookupCgo
+	}
+	if byteIndex(hostname, '\\') != -1 || byteIndex(hostname, '%') != -1 {
+		// Don't deal with special form hostnames with backslashes
+		// or '%'.
+		return hostLookupCgo
+	}
+
+	// OpenBSD is unique and doesn't use nsswitch.conf.
+	// It also doesn't support mDNS.
+	if c.goos == "openbsd" {
+		// OpenBSD's resolv.conf manpage says that a non-existent
+		// resolv.conf means "lookup" defaults to only "files",
+		// without DNS lookups.
+		if os.IsNotExist(c.resolv.err) {
+			return hostLookupFiles
+		}
+		lookup := c.resolv.lookup
+		if len(lookup) == 0 {
+			// http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man5/resolv.conf.5
+			// "If the lookup keyword is not used in the
+			// system's resolv.conf file then the assumed
+			// order is 'bind file'"
+			return hostLookupDNSFiles
+		}
+		if len(lookup) < 1 || len(lookup) > 2 {
+			return hostLookupCgo
+		}
+		switch lookup[0] {
+		case "bind":
+			if len(lookup) == 2 {
+				if lookup[1] == "file" {
+					return hostLookupDNSFiles
+				}
+				return hostLookupCgo
+			}
+			return hostLookupDNS
+		case "file":
+			if len(lookup) == 2 {
+				if lookup[1] == "bind" {
+					return hostLookupFilesDNS
+				}
+				return hostLookupCgo
+			}
+			return hostLookupFiles
+		default:
+			return hostLookupCgo
+		}
+	}
+
+	hasDot := byteIndex(hostname, '.') != -1
+
+	// Canonicalize the hostname by removing any trailing dot.
+	if stringsHasSuffix(hostname, ".") {
+		hostname = hostname[:len(hostname)-1]
+	}
+	if stringsHasSuffixFold(hostname, ".local") {
+		// Per RFC 6762, the ".local" TLD is special.  And
+		// because Go's native resolver doesn't do mDNS or
+		// similar local resolution mechanisms, assume that
+		// libc might (via Avahi, etc) and use cgo.
+		return hostLookupCgo
+	}
+
+	nss := c.nss
+	srcs := nss.sources["hosts"]
+	// If /etc/nsswitch.conf doesn't exist or doesn't specify any
+	// sources for "hosts", assume Go's DNS will work fine.
+	if os.IsNotExist(nss.err) || (nss.err == nil && len(srcs) == 0) {
+		if c.goos == "solaris" {
+			// illumos defaults to "nis [NOTFOUND=return] files"
+			return hostLookupCgo
+		}
+		if c.goos == "linux" {
+			// glibc says the default is "dns [!UNAVAIL=return] files"
+			// http://www.gnu.org/software/libc/manual/html_node/Notes-on-NSS-Configuration-File.html.
+			return hostLookupDNSFiles
+		}
+		return hostLookupFilesDNS
+	}
+	if nss.err != nil {
+		// We failed to parse or open nsswitch.conf, so
+		// conservatively assume we should use cgo if it's
+		// available.
+		return hostLookupCgo
+	}
+
+	var mdnsSource, filesSource, dnsSource bool
+	var first string
+	for _, src := range srcs {
+		if src.source == "myhostname" {
+			if hasDot {
+				continue
+			}
+			return hostLookupCgo
+		}
+		if src.source == "files" || src.source == "dns" {
+			if !src.standardCriteria() {
+				return hostLookupCgo // non-standard; let libc deal with it.
+			}
+			if src.source == "files" {
+				filesSource = true
+			} else if src.source == "dns" {
+				dnsSource = true
+			}
+			if first == "" {
+				first = src.source
+			}
+			continue
+		}
+		if stringsHasPrefix(src.source, "mdns") {
+			// e.g. "mdns4", "mdns4_minimal"
+			// We already returned true before if it was *.local.
+			// libc wouldn't have found a hit on this anyway.
+			mdnsSource = true
+			continue
+		}
+		// Some source we don't know how to deal with.
+		return hostLookupCgo
+	}
+
+	// We don't parse mdns.allow files. They're rare. If one
+	// exists, it might list other TLDs (besides .local) or even
+	// '*', so just let libc deal with it.
+	if mdnsSource && c.hasMDNSAllow {
+		return hostLookupCgo
+	}
+
+	// Cases where Go can handle it without cgo and C thread
+	// overhead.
+	switch {
+	case filesSource && dnsSource:
+		if first == "files" {
+			return hostLookupFilesDNS
+		} else {
+			return hostLookupDNSFiles
+		}
+	case filesSource:
+		return hostLookupFiles
+	case dnsSource:
+		return hostLookupDNS
+	}
+
+	// Something weird. Let libc deal with it.
+	return hostLookupCgo
+}
+
+// goDebugNetDNS parses the value of the GODEBUG "netdns" value.
+// The netdns value can be of the form:
+//    1       // debug level 1
+//    2       // debug level 2
+//    cgo     // use cgo for DNS lookups
+//    go      // use go for DNS lookups
+//    cgo+1   // use cgo for DNS lookups + debug level 1
+//    1+cgo   // same
+//    cgo+2   // same, but debug level 2
+// etc.
+func goDebugNetDNS() (dnsMode string, debugLevel int) {
+	goDebug := goDebugString("netdns")
+	parsePart := func(s string) {
+		if s == "" {
+			return
+		}
+		if '0' <= s[0] && s[0] <= '9' {
+			debugLevel, _ = strconv.Atoi(s)
+		} else {
+			dnsMode = s
+		}
+	}
+	if i := byteIndex(goDebug, '+'); i != -1 {
+		parsePart(goDebug[:i])
+		parsePart(goDebug[i+1:])
+		return
+	}
+	parsePart(goDebug)
+	return
+}
diff --git a/src/net/conf_netcgo.go b/src/net/conf_netcgo.go
new file mode 100644
index 0000000..678361f
--- /dev/null
+++ b/src/net/conf_netcgo.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 netcgo
+
+package net
+
+/*
+
+// Fail if cgo isn't available.
+
+*/
+import "C"
+
+// The build tag "netcgo" forces use of the cgo DNS resolver.
+// It is the opposite of "netgo".
+func init() { netCgo = true }
diff --git a/src/net/conf_test.go b/src/net/conf_test.go
new file mode 100644
index 0000000..86904bf
--- /dev/null
+++ b/src/net/conf_test.go
@@ -0,0 +1,301 @@
+// 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 net
+
+import (
+	"os"
+	"strings"
+	"testing"
+)
+
+type nssHostTest struct {
+	host string
+	want hostLookupOrder
+}
+
+func nssStr(s string) *nssConf { return parseNSSConf(strings.NewReader(s)) }
+
+// represents a dnsConfig returned by parsing a nonexistent resolv.conf
+var defaultResolvConf = &dnsConfig{
+	servers:  defaultNS,
+	ndots:    1,
+	timeout:  5,
+	attempts: 2,
+	err:      os.ErrNotExist,
+}
+
+func TestConfHostLookupOrder(t *testing.T) {
+	tests := []struct {
+		name      string
+		c         *conf
+		goos      string
+		hostTests []nssHostTest
+	}{
+		{
+			name: "force",
+			c: &conf{
+				forceCgoLookupHost: true,
+				nss:                nssStr("foo: bar"),
+				resolv:             defaultResolvConf,
+			},
+			hostTests: []nssHostTest{
+				{"foo.local", hostLookupCgo},
+				{"google.com", hostLookupCgo},
+			},
+		},
+		{
+			name: "ubuntu_trusty_avahi",
+			c: &conf{
+				nss:    nssStr("hosts: files mdns4_minimal [NOTFOUND=return] dns mdns4"),
+				resolv: defaultResolvConf,
+			},
+			hostTests: []nssHostTest{
+				{"foo.local", hostLookupCgo},
+				{"foo.local.", hostLookupCgo},
+				{"foo.LOCAL", hostLookupCgo},
+				{"foo.LOCAL.", hostLookupCgo},
+				{"google.com", hostLookupFilesDNS},
+			},
+		},
+		{
+			name: "freebsdlinux_no_resolv_conf",
+			c: &conf{
+				goos:   "freebsd",
+				nss:    nssStr("foo: bar"),
+				resolv: defaultResolvConf,
+			},
+			hostTests: []nssHostTest{{"google.com", hostLookupFilesDNS}},
+		},
+		// On OpenBSD, no resolv.conf means no DNS.
+		{
+			name: "openbsd_no_resolv_conf",
+			c: &conf{
+				goos:   "openbsd",
+				resolv: defaultResolvConf,
+			},
+			hostTests: []nssHostTest{{"google.com", hostLookupFiles}},
+		},
+		{
+			name: "solaris_no_nsswitch",
+			c: &conf{
+				goos:   "solaris",
+				nss:    &nssConf{err: os.ErrNotExist},
+				resolv: defaultResolvConf,
+			},
+			hostTests: []nssHostTest{{"google.com", hostLookupCgo}},
+		},
+		{
+			name: "openbsd_lookup_bind_file",
+			c: &conf{
+				goos:   "openbsd",
+				resolv: &dnsConfig{lookup: []string{"bind", "file"}},
+			},
+			hostTests: []nssHostTest{
+				{"google.com", hostLookupDNSFiles},
+				{"foo.local", hostLookupDNSFiles},
+			},
+		},
+		{
+			name: "openbsd_lookup_file_bind",
+			c: &conf{
+				goos:   "openbsd",
+				resolv: &dnsConfig{lookup: []string{"file", "bind"}},
+			},
+			hostTests: []nssHostTest{{"google.com", hostLookupFilesDNS}},
+		},
+		{
+			name: "openbsd_lookup_bind",
+			c: &conf{
+				goos:   "openbsd",
+				resolv: &dnsConfig{lookup: []string{"bind"}},
+			},
+			hostTests: []nssHostTest{{"google.com", hostLookupDNS}},
+		},
+		{
+			name: "openbsd_lookup_file",
+			c: &conf{
+				goos:   "openbsd",
+				resolv: &dnsConfig{lookup: []string{"file"}},
+			},
+			hostTests: []nssHostTest{{"google.com", hostLookupFiles}},
+		},
+		{
+			name: "openbsd_lookup_yp",
+			c: &conf{
+				goos:   "openbsd",
+				resolv: &dnsConfig{lookup: []string{"file", "bind", "yp"}},
+			},
+			hostTests: []nssHostTest{{"google.com", hostLookupCgo}},
+		},
+		{
+			name: "openbsd_lookup_two",
+			c: &conf{
+				goos:   "openbsd",
+				resolv: &dnsConfig{lookup: []string{"file", "foo"}},
+			},
+			hostTests: []nssHostTest{{"google.com", hostLookupCgo}},
+		},
+		{
+			name: "openbsd_lookup_empty",
+			c: &conf{
+				goos:   "openbsd",
+				resolv: &dnsConfig{lookup: nil},
+			},
+			hostTests: []nssHostTest{{"google.com", hostLookupDNSFiles}},
+		},
+		// glibc lacking an nsswitch.conf, per
+		// http://www.gnu.org/software/libc/manual/html_node/Notes-on-NSS-Configuration-File.html
+		{
+			name: "linux_no_nsswitch.conf",
+			c: &conf{
+				goos:   "linux",
+				nss:    &nssConf{err: os.ErrNotExist},
+				resolv: defaultResolvConf,
+			},
+			hostTests: []nssHostTest{{"google.com", hostLookupDNSFiles}},
+		},
+		{
+			name: "files_mdns_dns",
+			c: &conf{
+				nss:    nssStr("hosts: files mdns dns"),
+				resolv: defaultResolvConf,
+			},
+			hostTests: []nssHostTest{
+				{"x.com", hostLookupFilesDNS},
+				{"x.local", hostLookupCgo},
+			},
+		},
+		{
+			name: "dns_special_hostnames",
+			c: &conf{
+				nss:    nssStr("hosts: dns"),
+				resolv: defaultResolvConf,
+			},
+			hostTests: []nssHostTest{
+				{"x.com", hostLookupDNS},
+				{"x\\.com", hostLookupCgo},     // punt on weird glibc escape
+				{"foo.com%en0", hostLookupCgo}, // and IPv6 zones
+			},
+		},
+		{
+			name: "mdns_allow",
+			c: &conf{
+				nss:          nssStr("hosts: files mdns dns"),
+				resolv:       defaultResolvConf,
+				hasMDNSAllow: true,
+			},
+			hostTests: []nssHostTest{
+				{"x.com", hostLookupCgo},
+				{"x.local", hostLookupCgo},
+			},
+		},
+		{
+			name: "files_dns",
+			c: &conf{
+				nss:    nssStr("hosts: files dns"),
+				resolv: defaultResolvConf,
+			},
+			hostTests: []nssHostTest{
+				{"x.com", hostLookupFilesDNS},
+				{"x", hostLookupFilesDNS},
+				{"x.local", hostLookupCgo},
+			},
+		},
+		{
+			name: "dns_files",
+			c: &conf{
+				nss:    nssStr("hosts: dns files"),
+				resolv: defaultResolvConf,
+			},
+			hostTests: []nssHostTest{
+				{"x.com", hostLookupDNSFiles},
+				{"x", hostLookupDNSFiles},
+				{"x.local", hostLookupCgo},
+			},
+		},
+		{
+			name: "something_custom",
+			c: &conf{
+				nss:    nssStr("hosts: dns files something_custom"),
+				resolv: defaultResolvConf,
+			},
+			hostTests: []nssHostTest{
+				{"x.com", hostLookupCgo},
+			},
+		},
+		{
+			name: "myhostname",
+			c: &conf{
+				nss:    nssStr("hosts: files dns myhostname"),
+				resolv: defaultResolvConf,
+			},
+			hostTests: []nssHostTest{
+				{"x.com", hostLookupFilesDNS},
+				{"somehostname", hostLookupCgo},
+			},
+		},
+		{
+			name: "ubuntu14.04.02",
+			c: &conf{
+				nss:    nssStr("hosts: files myhostname mdns4_minimal [NOTFOUND=return] dns mdns4"),
+				resolv: defaultResolvConf,
+			},
+			hostTests: []nssHostTest{
+				{"x.com", hostLookupFilesDNS},
+				{"somehostname", hostLookupCgo},
+			},
+		},
+		// Debian Squeeze is just "dns,files", but lists all
+		// the default criteria for dns, but then has a
+		// non-standard but redundant notfound=return for the
+		// files.
+		{
+			name: "debian_squeeze",
+			c: &conf{
+				nss:    nssStr("hosts: dns [success=return notfound=continue unavail=continue tryagain=continue] files [notfound=return]"),
+				resolv: defaultResolvConf,
+			},
+			hostTests: []nssHostTest{
+				{"x.com", hostLookupDNSFiles},
+				{"somehostname", hostLookupDNSFiles},
+			},
+		},
+		{
+			name: "resolv.conf-unknown",
+			c: &conf{
+				nss:    nssStr("foo: bar"),
+				resolv: &dnsConfig{servers: defaultNS, ndots: 1, timeout: 5, attempts: 2, unknownOpt: true},
+			},
+			hostTests: []nssHostTest{{"google.com", hostLookupCgo}},
+		},
+		// Android should always use cgo.
+		{
+			name: "android",
+			c: &conf{
+				goos:   "android",
+				nss:    nssStr(""),
+				resolv: defaultResolvConf,
+			},
+			hostTests: []nssHostTest{
+				{"x.com", hostLookupCgo},
+			},
+		},
+	}
+	for _, tt := range tests {
+		for _, ht := range tt.hostTests {
+			gotOrder := tt.c.hostLookupOrder(ht.host)
+			if gotOrder != ht.want {
+				t.Errorf("%s: hostLookupOrder(%q) = %v; want %v", tt.name, ht.host, gotOrder, ht.want)
+			}
+		}
+	}
+
+}
+
+func TestSystemConf(t *testing.T) {
+	systemConf()
+}
diff --git a/src/net/conn_test.go b/src/net/conn_test.go
index 9c9d1a8..6995c11 100644
--- a/src/net/conn_test.go
+++ b/src/net/conn_test.go
@@ -8,117 +8,58 @@
 package net
 
 import (
-	"os"
-	"runtime"
 	"testing"
 	"time"
 )
 
-var connTests = []struct {
-	net  string
-	addr string
-}{
-	{"tcp", "127.0.0.1:0"},
-	{"unix", testUnixAddr()},
-	{"unixpacket", testUnixAddr()},
-}
-
 // someTimeout is used just to test that net.Conn implementations
 // don't explode when their SetFooDeadline methods are called.
 // It isn't actually used for testing timeouts.
 const someTimeout = 10 * time.Second
 
 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
-			}
+	for i, network := range []string{"tcp", "unix", "unixpacket"} {
+		if !testableNetwork(network) {
+			t.Logf("skipping %s test", network)
+			continue
 		}
 
-		ln, err := Listen(tt.net, tt.addr)
+		ls, err := newLocalServer(network)
 		if err != nil {
-			t.Fatalf("Listen failed: %v", err)
+			t.Fatal(err)
 		}
-		defer func(ln Listener, net, addr string) {
-			ln.Close()
-			switch net {
-			case "unix", "unixpacket":
-				os.Remove(addr)
-			}
-		}(ln, tt.net, tt.addr)
-		if ln.Addr().Network() != tt.net {
-			t.Fatalf("got %v; expected %v", ln.Addr().Network(), tt.net)
+		defer ls.teardown()
+		ch := make(chan error, 1)
+		handler := func(ls *localServer, ln Listener) { transponder(ln, ch) }
+		if err := ls.buildup(handler); err != nil {
+			t.Fatal(err)
+		}
+		if ls.Listener.Addr().Network() != network {
+			t.Fatalf("got %s; want %s", ls.Listener.Addr().Network(), network)
 		}
 
-		done := make(chan int)
-		go transponder(t, ln, done)
-
-		c, err := Dial(tt.net, ln.Addr().String())
+		c, err := Dial(ls.Listener.Addr().Network(), ls.Listener.Addr().String())
 		if err != nil {
-			t.Fatalf("Dial failed: %v", err)
+			t.Fatal(err)
 		}
 		defer c.Close()
-		if c.LocalAddr().Network() != tt.net || c.LocalAddr().Network() != tt.net {
-			t.Fatalf("got %v->%v; expected %v->%v", c.LocalAddr().Network(), c.RemoteAddr().Network(), tt.net, tt.net)
+		if c.LocalAddr().Network() != network || c.LocalAddr().Network() != network {
+			t.Fatalf("got %s->%s; want %s->%s", c.LocalAddr().Network(), c.RemoteAddr().Network(), network, network)
 		}
 		c.SetDeadline(time.Now().Add(someTimeout))
 		c.SetReadDeadline(time.Now().Add(someTimeout))
 		c.SetWriteDeadline(time.Now().Add(someTimeout))
 
-		if _, err := c.Write([]byte("CONN TEST")); err != nil {
-			t.Fatalf("Conn.Write failed: %v", err)
+		if _, err := c.Write([]byte("CONN AND LISTENER TEST")); err != nil {
+			t.Fatal(err)
 		}
 		rb := make([]byte, 128)
 		if _, err := c.Read(rb); err != nil {
-			t.Fatalf("Conn.Read failed: %v", err)
+			t.Fatal(err)
 		}
 
-		<-done
-	}
-}
-
-func transponder(t *testing.T, ln Listener, done chan<- int) {
-	defer func() { done <- 1 }()
-
-	switch ln := ln.(type) {
-	case *TCPListener:
-		ln.SetDeadline(time.Now().Add(someTimeout))
-	case *UnixListener:
-		ln.SetDeadline(time.Now().Add(someTimeout))
-	}
-	c, err := ln.Accept()
-	if err != nil {
-		t.Errorf("Listener.Accept failed: %v", err)
-		return
-	}
-	defer c.Close()
-	network := ln.Addr().Network()
-	if c.LocalAddr().Network() != network || c.LocalAddr().Network() != network {
-		t.Errorf("got %v->%v; expected %v->%v", c.LocalAddr().Network(), c.RemoteAddr().Network(), network, network)
-		return
-	}
-	c.SetDeadline(time.Now().Add(someTimeout))
-	c.SetReadDeadline(time.Now().Add(someTimeout))
-	c.SetWriteDeadline(time.Now().Add(someTimeout))
-
-	b := make([]byte, 128)
-	n, err := c.Read(b)
-	if err != nil {
-		t.Errorf("Conn.Read failed: %v", err)
-		return
-	}
-	if _, err := c.Write(b[:n]); err != nil {
-		t.Errorf("Conn.Write failed: %v", err)
-		return
+		for err := range ch {
+			t.Errorf("#%d: %v", i, err)
+		}
 	}
 }
diff --git a/src/net/dial.go b/src/net/dial.go
index e6f0436..cb4ec21 100644
--- a/src/net/dial.go
+++ b/src/net/dial.go
@@ -21,6 +21,9 @@ type Dialer struct {
 	//
 	// The default is no timeout.
 	//
+	// When dialing a name with multiple IP addresses, the timeout
+	// may be divided between them.
+	//
 	// With or without a timeout, the operating system may impose
 	// its own earlier timeout. For instance, TCP timeouts are
 	// often around 3 minutes.
@@ -38,13 +41,17 @@ type Dialer struct {
 	// If nil, a local address is automatically chosen.
 	LocalAddr Addr
 
-	// DualStack allows a single dial to attempt to establish
-	// multiple IPv4 and IPv6 connections and to return the first
-	// established connection when the network is "tcp" and the
-	// destination is a host name that has multiple address family
-	// DNS records.
+	// DualStack enables RFC 6555-compliant "Happy Eyeballs" dialing
+	// when the network is "tcp" and the destination is a host name
+	// with both IPv4 and IPv6 addresses. This allows a client to
+	// tolerate networks where one address family is silently broken.
 	DualStack bool
 
+	// FallbackDelay specifies the length of time to wait before
+	// spawning a fallback connection, when DualStack is enabled.
+	// If zero, a default delay of 300ms is used.
+	FallbackDelay time.Duration
+
 	// KeepAlive specifies the keep-alive period for an active
 	// network connection.
 	// If zero, keep-alives are not enabled. Network protocols
@@ -54,11 +61,11 @@ type Dialer struct {
 
 // Return either now+Timeout or Deadline, whichever comes first.
 // Or zero, if neither is set.
-func (d *Dialer) deadline() time.Time {
+func (d *Dialer) deadline(now time.Time) time.Time {
 	if d.Timeout == 0 {
 		return d.Deadline
 	}
-	timeoutDeadline := time.Now().Add(d.Timeout)
+	timeoutDeadline := now.Add(d.Timeout)
 	if d.Deadline.IsZero() || timeoutDeadline.Before(d.Deadline) {
 		return timeoutDeadline
 	} else {
@@ -66,6 +73,38 @@ func (d *Dialer) deadline() time.Time {
 	}
 }
 
+// partialDeadline returns the deadline to use for a single address,
+// when multiple addresses are pending.
+func partialDeadline(now, deadline time.Time, addrsRemaining int) (time.Time, error) {
+	if deadline.IsZero() {
+		return deadline, nil
+	}
+	timeRemaining := deadline.Sub(now)
+	if timeRemaining <= 0 {
+		return time.Time{}, errTimeout
+	}
+	// Tentatively allocate equal time to each remaining address.
+	timeout := timeRemaining / time.Duration(addrsRemaining)
+	// If the time per address is too short, steal from the end of the list.
+	const saneMinimum = 2 * time.Second
+	if timeout < saneMinimum {
+		if timeRemaining < saneMinimum {
+			timeout = timeRemaining
+		} else {
+			timeout = saneMinimum
+		}
+	}
+	return now.Add(timeout), nil
+}
+
+func (d *Dialer) fallbackDelay() time.Duration {
+	if d.FallbackDelay > 0 {
+		return d.FallbackDelay
+	} else {
+		return 300 * time.Millisecond
+	}
+}
+
 func parseNetwork(net string) (afnet string, proto int, err error) {
 	i := last(net, ':')
 	if i < 0 { // no colon
@@ -95,7 +134,7 @@ func parseNetwork(net string) (afnet string, proto int, err error) {
 	return "", 0, UnknownNetworkError(net)
 }
 
-func resolveAddr(op, net, addr string, deadline time.Time) (netaddr, error) {
+func resolveAddrList(op, net, addr string, deadline time.Time) (addrList, error) {
 	afnet, _, err := parseNetwork(net)
 	if err != nil {
 		return nil, err
@@ -105,9 +144,13 @@ func resolveAddr(op, net, addr string, deadline time.Time) (netaddr, error) {
 	}
 	switch afnet {
 	case "unix", "unixgram", "unixpacket":
-		return ResolveUnixAddr(afnet, addr)
+		addr, err := ResolveUnixAddr(afnet, addr)
+		if err != nil {
+			return nil, err
+		}
+		return addrList{addr}, nil
 	}
-	return resolveInternetAddr(afnet, addr, deadline)
+	return internetAddrList(afnet, addr, deadline)
 }
 
 // Dial connects to the address on the named network.
@@ -150,100 +193,186 @@ func DialTimeout(network, address string, timeout time.Duration) (Conn, error) {
 	return d.Dial(network, address)
 }
 
+// dialContext holds common state for all dial operations.
+type dialContext struct {
+	Dialer
+	network, address string
+	finalDeadline    time.Time
+}
+
 // Dial connects to the address on the named network.
 //
 // See func Dial for a description of the network and address
 // parameters.
 func (d *Dialer) Dial(network, address string) (Conn, error) {
-	ra, err := resolveAddr("dial", network, address, d.deadline())
+	finalDeadline := d.deadline(time.Now())
+	addrs, err := resolveAddrList("dial", network, address, finalDeadline)
 	if err != nil {
-		return nil, &OpError{Op: "dial", Net: network, Addr: nil, Err: err}
+		return nil, &OpError{Op: "dial", Net: network, Source: nil, Addr: nil, Err: err}
 	}
-	dialer := func(deadline time.Time) (Conn, error) {
-		return dialSingle(network, address, d.LocalAddr, ra.toAddr(), deadline)
+
+	ctx := &dialContext{
+		Dialer:        *d,
+		network:       network,
+		address:       address,
+		finalDeadline: finalDeadline,
 	}
-	if ras, ok := ra.(addrList); ok && d.DualStack && network == "tcp" {
-		dialer = func(deadline time.Time) (Conn, error) {
-			return dialMulti(network, address, d.LocalAddr, ras, deadline)
-		}
+
+	var primaries, fallbacks addrList
+	if d.DualStack && network == "tcp" {
+		primaries, fallbacks = addrs.partition(isIPv4)
+	} else {
+		primaries = addrs
 	}
-	c, err := dial(network, ra.toAddr(), dialer, d.deadline())
+
+	var c Conn
+	if len(fallbacks) == 0 {
+		// dialParallel can accept an empty fallbacks list,
+		// but this shortcut avoids the goroutine/channel overhead.
+		c, err = dialSerial(ctx, primaries, nil)
+	} else {
+		c, err = dialParallel(ctx, primaries, fallbacks)
+	}
+
 	if d.KeepAlive > 0 && err == nil {
 		if tc, ok := c.(*TCPConn); ok {
-			tc.SetKeepAlive(true)
-			tc.SetKeepAlivePeriod(d.KeepAlive)
+			setKeepAlive(tc.fd, true)
+			setKeepAlivePeriod(tc.fd, d.KeepAlive)
 			testHookSetKeepAlive()
 		}
 	}
 	return c, err
 }
 
-var testHookSetKeepAlive = func() {} // changed by dial_test.go
+// dialParallel races two copies of dialSerial, giving the first a
+// head start. It returns the first established connection and
+// closes the others. Otherwise it returns an error from the first
+// primary address.
+func dialParallel(ctx *dialContext, primaries, fallbacks addrList) (Conn, error) {
+	results := make(chan dialResult) // unbuffered, so dialSerialAsync can detect race loss & cleanup
+	cancel := make(chan struct{})
+	defer close(cancel)
+
+	// Spawn the primary racer.
+	go dialSerialAsync(ctx, primaries, nil, cancel, results)
+
+	// Spawn the fallback racer.
+	fallbackTimer := time.NewTimer(ctx.fallbackDelay())
+	go dialSerialAsync(ctx, fallbacks, fallbackTimer, cancel, results)
 
-// dialMulti attempts to establish connections to each destination of
-// the list of addresses. It will return the first established
-// connection and close the other connections. Otherwise it returns
-// error on the last attempt.
-func dialMulti(net, addr string, la Addr, ras addrList, deadline time.Time) (Conn, error) {
-	type racer struct {
-		Conn
-		error
+	var primaryErr error
+	for nracers := 2; nracers > 0; nracers-- {
+		res := <-results
+		// If we're still waiting for a connection, then hasten the delay.
+		// Otherwise, disable the Timer and let cancel take over.
+		if fallbackTimer.Stop() && res.error != nil {
+			fallbackTimer.Reset(0)
+		}
+		if res.error == nil {
+			return res.Conn, nil
+		}
+		if res.primary {
+			primaryErr = res.error
+		}
 	}
-	// Sig controls the flow of dial results on lane. It passes a
-	// token to the next racer and also indicates the end of flow
-	// by using closed channel.
-	sig := make(chan bool, 1)
-	lane := make(chan racer, 1)
-	for _, ra := range ras {
-		go func(ra Addr) {
-			c, err := dialSingle(net, addr, la, ra, deadline)
-			if _, ok := <-sig; ok {
-				lane <- racer{c, err}
-			} else if err == nil {
-				// We have to return the resources
-				// that belong to the other
-				// connections here for avoiding
-				// unnecessary resource starvation.
-				c.Close()
-			}
-		}(ra.toAddr())
+	return nil, primaryErr
+}
+
+type dialResult struct {
+	Conn
+	error
+	primary bool
+}
+
+// dialSerialAsync runs dialSerial after some delay, and returns the
+// resulting connection through a channel. When racing two connections,
+// the primary goroutine uses a nil timer to omit the delay.
+func dialSerialAsync(ctx *dialContext, ras addrList, timer *time.Timer, cancel <-chan struct{}, results chan<- dialResult) {
+	if timer != nil {
+		// We're in the fallback goroutine; sleep before connecting.
+		select {
+		case <-timer.C:
+		case <-cancel:
+			return
+		}
 	}
-	defer close(sig)
-	lastErr := errTimeout
-	nracers := len(ras)
-	for nracers > 0 {
-		sig <- true
-		racer := <-lane
-		if racer.error == nil {
-			return racer.Conn, nil
+	c, err := dialSerial(ctx, ras, cancel)
+	select {
+	case results <- dialResult{c, err, timer == nil}:
+		// We won the race.
+	case <-cancel:
+		// The other goroutine won the race.
+		if c != nil {
+			c.Close()
+		}
+	}
+}
+
+// dialSerial connects to a list of addresses in sequence, returning
+// either the first successful connection, or the first error.
+func dialSerial(ctx *dialContext, ras addrList, cancel <-chan struct{}) (Conn, error) {
+	var firstErr error // The error from the first address is most relevant.
+
+	for i, ra := range ras {
+		select {
+		case <-cancel:
+			return nil, &OpError{Op: "dial", Net: ctx.network, Source: ctx.LocalAddr, Addr: ra, Err: errCanceled}
+		default:
+		}
+
+		partialDeadline, err := partialDeadline(time.Now(), ctx.finalDeadline, len(ras)-i)
+		if err != nil {
+			// Ran out of time.
+			if firstErr == nil {
+				firstErr = &OpError{Op: "dial", Net: ctx.network, Source: ctx.LocalAddr, Addr: ra, Err: err}
+			}
+			break
 		}
-		lastErr = racer.error
-		nracers--
+
+		// dialTCP does not support cancelation (see golang.org/issue/11225),
+		// so if cancel fires, we'll continue trying to connect until the next
+		// timeout, or return a spurious connection for the caller to close.
+		dialer := func(d time.Time) (Conn, error) {
+			return dialSingle(ctx, ra, d)
+		}
+		c, err := dial(ctx.network, ra, dialer, partialDeadline)
+		if err == nil {
+			return c, nil
+		}
+		if firstErr == nil {
+			firstErr = err
+		}
+	}
+
+	if firstErr == nil {
+		firstErr = &OpError{Op: "dial", Net: ctx.network, Source: nil, Addr: nil, Err: errMissingAddress}
 	}
-	return nil, lastErr
+	return nil, firstErr
 }
 
 // dialSingle attempts to establish and returns a single connection to
-// the destination address.
-func dialSingle(net, addr string, la, ra Addr, deadline time.Time) (c Conn, err error) {
+// the destination address. This must be called through the OS-specific
+// dial function, because some OSes don't implement the deadline feature.
+func dialSingle(ctx *dialContext, ra Addr, deadline time.Time) (c Conn, err error) {
+	la := ctx.LocalAddr
 	if la != nil && la.Network() != ra.Network() {
-		return nil, &OpError{Op: "dial", Net: net, Addr: ra, Err: errors.New("mismatched local address type " + la.Network())}
+		return nil, &OpError{Op: "dial", Net: ctx.network, Source: la, Addr: ra, Err: errors.New("mismatched local address type " + la.Network())}
 	}
 	switch ra := ra.(type) {
 	case *TCPAddr:
 		la, _ := la.(*TCPAddr)
-		c, err = dialTCP(net, la, ra, deadline)
+		c, err = testHookDialTCP(ctx.network, la, ra, deadline)
 	case *UDPAddr:
 		la, _ := la.(*UDPAddr)
-		c, err = dialUDP(net, la, ra, deadline)
+		c, err = dialUDP(ctx.network, la, ra, deadline)
 	case *IPAddr:
 		la, _ := la.(*IPAddr)
-		c, err = dialIP(net, la, ra, deadline)
+		c, err = dialIP(ctx.network, la, ra, deadline)
 	case *UnixAddr:
 		la, _ := la.(*UnixAddr)
-		c, err = dialUnix(net, la, ra, deadline)
+		c, err = dialUnix(ctx.network, la, ra, deadline)
 	default:
-		return nil, &OpError{Op: "dial", Net: net, Addr: ra, Err: &AddrError{Err: "unexpected address type", Addr: addr}}
+		return nil, &OpError{Op: "dial", Net: ctx.network, Source: la, Addr: ra, Err: &AddrError{Err: "unexpected address type", Addr: ctx.address}}
 	}
 	if err != nil {
 		return nil, err // c is non-nil interface containing nil pointer
@@ -256,18 +385,18 @@ func dialSingle(net, addr string, la, ra Addr, deadline time.Time) (c Conn, err
 // "tcp6", "unix" or "unixpacket".
 // See Dial for the syntax of laddr.
 func Listen(net, laddr string) (Listener, error) {
-	la, err := resolveAddr("listen", net, laddr, noDeadline)
+	addrs, err := resolveAddrList("listen", net, laddr, noDeadline)
 	if err != nil {
-		return nil, &OpError{Op: "listen", Net: net, Addr: nil, Err: err}
+		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: nil, Err: err}
 	}
 	var l Listener
-	switch la := la.toAddr().(type) {
+	switch la := addrs.first(isIPv4).(type) {
 	case *TCPAddr:
 		l, err = ListenTCP(net, la)
 	case *UnixAddr:
 		l, err = ListenUnix(net, la)
 	default:
-		return nil, &OpError{Op: "listen", Net: net, Addr: la, Err: &AddrError{Err: "unexpected address type", Addr: laddr}}
+		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: la, Err: &AddrError{Err: "unexpected address type", Addr: laddr}}
 	}
 	if err != nil {
 		return nil, err // l is non-nil interface containing nil pointer
@@ -280,12 +409,12 @@ func Listen(net, laddr string) (Listener, error) {
 // "udp6", "ip", "ip4", "ip6" or "unixgram".
 // See Dial for the syntax of laddr.
 func ListenPacket(net, laddr string) (PacketConn, error) {
-	la, err := resolveAddr("listen", net, laddr, noDeadline)
+	addrs, err := resolveAddrList("listen", net, laddr, noDeadline)
 	if err != nil {
-		return nil, &OpError{Op: "listen", Net: net, Addr: nil, Err: err}
+		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: nil, Err: err}
 	}
 	var l PacketConn
-	switch la := la.toAddr().(type) {
+	switch la := addrs.first(isIPv4).(type) {
 	case *UDPAddr:
 		l, err = ListenUDP(net, la)
 	case *IPAddr:
@@ -293,7 +422,7 @@ func ListenPacket(net, laddr string) (PacketConn, error) {
 	case *UnixAddr:
 		l, err = ListenUnixgram(net, la)
 	default:
-		return nil, &OpError{Op: "listen", Net: net, Addr: la, Err: &AddrError{Err: "unexpected address type", Addr: laddr}}
+		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: la, Err: &AddrError{Err: "unexpected address type", Addr: laddr}}
 	}
 	if err != nil {
 		return nil, err // l is non-nil interface containing nil pointer
diff --git a/src/net/dial_gen.go b/src/net/dial_gen.go
index ada6233..a628f71 100644
--- a/src/net/dial_gen.go
+++ b/src/net/dial_gen.go
@@ -6,22 +6,18 @@
 
 package net
 
-import (
-	"time"
-)
-
-var testingIssue5349 bool // used during tests
+import "time"
 
 // dialChannel is the simple pure-Go implementation of dial, still
 // used on operating systems where the deadline hasn't been pushed
 // down into the pollserver. (Plan 9 and some old versions of Windows)
 func dialChannel(net string, ra Addr, dialer func(time.Time) (Conn, error), deadline time.Time) (Conn, error) {
-	var timeout time.Duration
-	if !deadline.IsZero() {
-		timeout = deadline.Sub(time.Now())
+	if deadline.IsZero() {
+		return dialer(noDeadline)
 	}
+	timeout := deadline.Sub(time.Now())
 	if timeout <= 0 {
-		return dialer(noDeadline)
+		return nil, &OpError{Op: "dial", Net: net, Source: nil, Addr: ra, Err: errTimeout}
 	}
 	t := time.NewTimer(timeout)
 	defer t.Stop()
@@ -31,15 +27,13 @@ func dialChannel(net string, ra Addr, dialer func(time.Time) (Conn, error), dead
 	}
 	ch := make(chan racer, 1)
 	go func() {
-		if testingIssue5349 {
-			time.Sleep(time.Millisecond)
-		}
+		testHookDialChannel()
 		c, err := dialer(noDeadline)
 		ch <- racer{c, err}
 	}()
 	select {
 	case <-t.C:
-		return nil, &OpError{Op: "dial", Net: net, Addr: ra, Err: errTimeout}
+		return nil, &OpError{Op: "dial", Net: net, Source: nil, Addr: ra, Err: errTimeout}
 	case racer := <-ch:
 		return racer.Conn, racer.error
 	}
diff --git a/src/net/dial_gen_test.go b/src/net/dial_gen_test.go
deleted file mode 100644
index c857acd..0000000
--- a/src/net/dial_gen_test.go
+++ /dev/null
@@ -1,11 +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.
-
-// +build windows plan9
-
-package net
-
-func init() {
-	testingIssue5349 = true
-}
diff --git a/src/net/dial_test.go b/src/net/dial_test.go
index 42898d6..ed6d7cc 100644
--- a/src/net/dial_test.go
+++ b/src/net/dial_test.go
@@ -5,111 +5,50 @@
 package net
 
 import (
-	"bytes"
-	"flag"
-	"fmt"
 	"io"
-	"os"
-	"os/exec"
-	"reflect"
-	"regexp"
+	"net/internal/socktest"
 	"runtime"
-	"strconv"
 	"sync"
 	"testing"
 	"time"
 )
 
-func newLocalListener(t *testing.T) Listener {
-	ln, err := Listen("tcp", "127.0.0.1:0")
-	if err != nil {
-		ln, err = Listen("tcp6", "[::1]:0")
+var prohibitionaryDialArgTests = []struct {
+	network string
+	address string
+}{
+	{"tcp6", "127.0.0.1"},
+	{"tcp6", "::ffff:127.0.0.1"},
+}
+
+func TestProhibitionaryDialArg(t *testing.T) {
+	switch runtime.GOOS {
+	case "plan9":
+		t.Skipf("not supported on %s", runtime.GOOS)
+	}
+	if testing.Short() || !*testExternal {
+		t.Skip("avoid external network")
 	}
+	if !supportsIPv4map {
+		t.Skip("mapping ipv4 address inside ipv6 address not supported")
+	}
+
+	ln, err := Listen("tcp", "[::]:0")
 	if err != nil {
 		t.Fatal(err)
 	}
-	return ln
-}
-
-func TestDialTimeout(t *testing.T) {
-	origBacklog := listenerBacklog
-	defer func() {
-		listenerBacklog = origBacklog
-	}()
-	listenerBacklog = 1
-
-	ln := newLocalListener(t)
 	defer ln.Close()
 
-	errc := make(chan error)
-
-	numConns := listenerBacklog + 100
+	_, port, err := SplitHostPort(ln.Addr().String())
+	if err != nil {
+		t.Fatal(err)
+	}
 
-	// TODO(bradfitz): It's hard to test this in a portable
-	// way. This is unfortunate, but works for now.
-	switch runtime.GOOS {
-	case "linux":
-		// The kernel will start accepting TCP connections before userspace
-		// gets a chance to not accept them, so fire off a bunch to fill up
-		// the kernel's backlog.  Then we test we get a failure after that.
-		for i := 0; i < numConns; i++ {
-			go func() {
-				_, err := DialTimeout("tcp", ln.Addr().String(), 200*time.Millisecond)
-				errc <- err
-			}()
-		}
-	case "darwin", "plan9", "windows":
-		// At least OS X 10.7 seems to accept any number of
-		// connections, ignoring listen's backlog, so resort
-		// to connecting to a hopefully-dead 127/8 address.
-		// Same for windows.
-		//
-		// Use an IANA reserved port (49151) instead of 80, because
-		// on our 386 builder, this Dial succeeds, connecting
-		// to an IIS web server somewhere.  The data center
-		// or VM or firewall must be stealing the TCP connection.
-		//
-		// IANA Service Name and Transport Protocol Port Number Registry
-		// <http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xml>
-		go func() {
-			c, err := DialTimeout("tcp", "127.0.71.111:49151", 200*time.Millisecond)
-			if err == nil {
-				err = fmt.Errorf("unexpected: connected to %s!", c.RemoteAddr())
-				c.Close()
-			}
-			errc <- err
-		}()
-	default:
-		// TODO(bradfitz):
-		// OpenBSD may have a reject route to 127/8 except 127.0.0.1/32
-		// by default. FreeBSD likely works, but is untested.
-		// TODO(rsc):
-		// The timeout never happens on Windows.  Why?  Issue 3016.
-		t.Skipf("skipping test on %q; untested.", runtime.GOOS)
-	}
-
-	connected := 0
-	for {
-		select {
-		case <-time.After(15 * time.Second):
-			t.Fatal("too slow")
-		case err := <-errc:
-			if err == nil {
-				connected++
-				if connected == numConns {
-					t.Fatal("all connections connected; expected some to time out")
-				}
-			} else {
-				terr, ok := err.(timeout)
-				if !ok {
-					t.Fatalf("got error %q; want error with timeout interface", err)
-				}
-				if !terr.Timeout() {
-					t.Fatalf("got error %q; not a timeout", err)
-				}
-				// Pass. We saw a timeout error.
-				return
-			}
+	for i, tt := range prohibitionaryDialArgTests {
+		c, err := Dial(tt.network, JoinHostPort(tt.address, port))
+		if err == nil {
+			c.Close()
+			t.Errorf("#%d: %v", i, err)
 		}
 	}
 }
@@ -117,7 +56,7 @@ func TestDialTimeout(t *testing.T) {
 func TestSelfConnect(t *testing.T) {
 	if runtime.GOOS == "windows" {
 		// TODO(brainman): do not know why it hangs.
-		t.Skip("skipping known-broken test on windows")
+		t.Skip("known-broken test on windows")
 	}
 
 	// Test that Dial does not honor self-connects.
@@ -160,303 +99,518 @@ func TestSelfConnect(t *testing.T) {
 	}
 }
 
-var runErrorTest = flag.Bool("run_error_test", false, "let TestDialError check for dns errors")
+func TestDialTimeoutFDLeak(t *testing.T) {
+	switch runtime.GOOS {
+	case "plan9":
+		t.Skipf("%s does not have full support of socktest", runtime.GOOS)
+	}
 
-type DialErrorTest struct {
-	Net     string
-	Raddr   string
-	Pattern string
-}
+	const T = 100 * time.Millisecond
 
-var dialErrorTests = []DialErrorTest{
-	{
-		"datakit", "mh/astro/r70",
-		"dial datakit mh/astro/r70: unknown network datakit",
-	},
-	{
-		"tcp", "127.0.0.1:☺",
-		"dial tcp 127.0.0.1:☺: unknown port tcp/☺",
-	},
-	{
-		"tcp", "no-such-name.google.com.:80",
-		"dial tcp no-such-name.google.com.:80: lookup no-such-name.google.com.( on .*)?: no (.*)",
-	},
-	{
-		"tcp", "no-such-name.no-such-top-level-domain.:80",
-		"dial tcp no-such-name.no-such-top-level-domain.:80: lookup no-such-name.no-such-top-level-domain.( on .*)?: no (.*)",
-	},
-	{
-		"tcp", "no-such-name:80",
-		`dial tcp no-such-name:80: lookup no-such-name\.(.*\.)?( on .*)?: no (.*)`,
-	},
-	{
-		"tcp", "mh/astro/r70:http",
-		"dial tcp mh/astro/r70:http: lookup mh/astro/r70: invalid domain name",
-	},
-	{
-		"unix", "/etc/file-not-found",
-		"dial unix /etc/file-not-found: no such file or directory",
-	},
-	{
-		"unix", "/etc/",
-		"dial unix /etc/: (permission denied|socket operation on non-socket|connection refused)",
-	},
-	{
-		"unixpacket", "/etc/file-not-found",
-		"dial unixpacket /etc/file-not-found: no such file or directory",
-	},
-	{
-		"unixpacket", "/etc/",
-		"dial unixpacket /etc/: (permission denied|socket operation on non-socket|connection refused)",
-	},
-}
+	switch runtime.GOOS {
+	case "plan9", "windows":
+		origTestHookDialChannel := testHookDialChannel
+		testHookDialChannel = func() { time.Sleep(2 * T) }
+		defer func() { testHookDialChannel = origTestHookDialChannel }()
+		if runtime.GOOS == "plan9" {
+			break
+		}
+		fallthrough
+	default:
+		sw.Set(socktest.FilterConnect, func(so *socktest.Status) (socktest.AfterFilter, error) {
+			time.Sleep(2 * T)
+			return nil, errTimeout
+		})
+		defer sw.Set(socktest.FilterConnect, nil)
+	}
+
+	// Avoid tracking open-close jitterbugs between netFD and
+	// socket that leads to confusion of information inside
+	// socktest.Switch.
+	// It may happen when the Dial call bumps against TCP
+	// simultaneous open. See selfConnect in tcpsock_posix.go.
+	defer func() {
+		sw.Set(socktest.FilterClose, nil)
+		forceCloseSockets()
+	}()
+	var mu sync.Mutex
+	var attempts int
+	sw.Set(socktest.FilterClose, func(so *socktest.Status) (socktest.AfterFilter, error) {
+		mu.Lock()
+		attempts++
+		mu.Unlock()
+		return nil, errTimedout
+	})
 
-var duplicateErrorPattern = `dial (.*) dial (.*)`
+	const N = 100
+	var wg sync.WaitGroup
+	wg.Add(N)
+	for i := 0; i < N; i++ {
+		go func() {
+			defer wg.Done()
+			// This dial never starts to send any SYN
+			// segment because of above socket filter and
+			// test hook.
+			c, err := DialTimeout("tcp", "127.0.0.1:0", T)
+			if err == nil {
+				t.Errorf("unexpectedly established: tcp:%s->%s", c.LocalAddr(), c.RemoteAddr())
+				c.Close()
+			}
+		}()
+	}
+	wg.Wait()
+	if attempts < N {
+		t.Errorf("got %d; want >= %d", attempts, N)
+	}
+}
 
-func TestDialError(t *testing.T) {
-	if !*runErrorTest {
-		t.Logf("test disabled; use -run_error_test to enable")
-		return
+func TestDialerDualStackFDLeak(t *testing.T) {
+	switch runtime.GOOS {
+	case "plan9":
+		t.Skipf("%s does not have full support of socktest", runtime.GOOS)
+	case "windows":
+		t.Skipf("not implemented a way to cancel dial racers in TCP SYN-SENT state on %s", runtime.GOOS)
 	}
-	for i, tt := range dialErrorTests {
-		c, err := Dial(tt.Net, tt.Raddr)
-		if c != nil {
+	if !supportsIPv4 || !supportsIPv6 {
+		t.Skip("both IPv4 and IPv6 are required")
+	}
+
+	origTestHookLookupIP := testHookLookupIP
+	defer func() { testHookLookupIP = origTestHookLookupIP }()
+	testHookLookupIP = lookupLocalhost
+	handler := func(dss *dualStackServer, ln Listener) {
+		for {
+			c, err := ln.Accept()
+			if err != nil {
+				return
+			}
 			c.Close()
 		}
-		if err == nil {
-			t.Errorf("#%d: nil error, want match for %#q", i, tt.Pattern)
-			continue
-		}
-		s := err.Error()
-		match, _ := regexp.MatchString(tt.Pattern, s)
-		if !match {
-			t.Errorf("#%d: %q, want match for %#q", i, s, tt.Pattern)
-		}
-		match, _ = regexp.MatchString(duplicateErrorPattern, s)
-		if match {
-			t.Errorf("#%d: %q, duplicate error return from Dial", i, s)
-		}
+	}
+	dss, err := newDualStackServer([]streamListener{
+		{network: "tcp4", address: "127.0.0.1"},
+		{network: "tcp6", address: "::1"},
+	})
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer dss.teardown()
+	if err := dss.buildup(handler); err != nil {
+		t.Fatal(err)
+	}
+
+	before := sw.Sockets()
+	const T = 100 * time.Millisecond
+	const N = 10
+	var wg sync.WaitGroup
+	wg.Add(N)
+	d := &Dialer{DualStack: true, Timeout: T}
+	for i := 0; i < N; i++ {
+		go func() {
+			defer wg.Done()
+			c, err := d.Dial("tcp", JoinHostPort("localhost", dss.port))
+			if err != nil {
+				t.Error(err)
+				return
+			}
+			c.Close()
+		}()
+	}
+	wg.Wait()
+	time.Sleep(2 * T) // wait for the dial racers to stop
+	after := sw.Sockets()
+	if len(after) != len(before) {
+		t.Errorf("got %d; want %d", len(after), len(before))
 	}
 }
 
-var invalidDialAndListenArgTests = []struct {
-	net  string
-	addr string
-	err  error
-}{
-	{"foo", "bar", &OpError{Op: "dial", Net: "foo", Addr: nil, Err: UnknownNetworkError("foo")}},
-	{"baz", "", &OpError{Op: "listen", Net: "baz", Addr: nil, Err: UnknownNetworkError("baz")}},
-	{"tcp", "", &OpError{Op: "dial", Net: "tcp", Addr: nil, Err: errMissingAddress}},
+// Define a pair of blackholed (IPv4, IPv6) addresses, for which dialTCP is
+// expected to hang until the timeout elapses. These addresses are reserved
+// for benchmarking by RFC 6890.
+const (
+	slowDst4    = "192.18.0.254"
+	slowDst6    = "2001:2::254"
+	slowTimeout = 1 * time.Second
+)
+
+// In some environments, the slow IPs may be explicitly unreachable, and fail
+// more quickly than expected. This test hook prevents dialTCP from returning
+// before the deadline.
+func slowDialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time) (*TCPConn, error) {
+	c, err := dialTCP(net, laddr, raddr, deadline)
+	if ParseIP(slowDst4).Equal(raddr.IP) || ParseIP(slowDst6).Equal(raddr.IP) {
+		time.Sleep(deadline.Sub(time.Now()))
+	}
+	return c, err
 }
 
-func TestInvalidDialAndListenArgs(t *testing.T) {
-	for _, tt := range invalidDialAndListenArgTests {
-		var err error
-		switch tt.err.(*OpError).Op {
-		case "dial":
-			_, err = Dial(tt.net, tt.addr)
-		case "listen":
-			_, err = Listen(tt.net, tt.addr)
+func dialClosedPort() (actual, expected time.Duration) {
+	// Estimate the expected time for this platform.
+	// On Windows, dialing a closed port takes roughly 1 second,
+	// but other platforms should be instantaneous.
+	if runtime.GOOS == "windows" {
+		expected = 1500 * time.Millisecond
+	} else {
+		expected = 95 * time.Millisecond
+	}
+
+	l, err := Listen("tcp", "127.0.0.1:0")
+	if err != nil {
+		return 999 * time.Hour, expected
+	}
+	addr := l.Addr().String()
+	l.Close()
+	// On OpenBSD, interference from TestSelfConnect is mysteriously
+	// causing the first attempt to hang for a few seconds, so we throw
+	// away the first result and keep the second.
+	for i := 1; ; i++ {
+		startTime := time.Now()
+		c, err := Dial("tcp", addr)
+		if err == nil {
+			c.Close()
 		}
-		if !reflect.DeepEqual(tt.err, err) {
-			t.Fatalf("got %#v; expected %#v", err, tt.err)
+		elapsed := time.Now().Sub(startTime)
+		if i == 2 {
+			return elapsed, expected
 		}
 	}
 }
 
-func TestDialTimeoutFDLeak(t *testing.T) {
-	if runtime.GOOS != "linux" {
-		// TODO(bradfitz): test on other platforms
-		t.Skipf("skipping test on %q", runtime.GOOS)
+func TestDialParallel(t *testing.T) {
+	if testing.Short() || !*testExternal {
+		t.Skip("avoid external network")
+	}
+	if !supportsIPv4 || !supportsIPv6 {
+		t.Skip("both IPv4 and IPv6 are required")
 	}
 
-	ln := newLocalListener(t)
-	defer ln.Close()
-
-	type connErr struct {
-		conn Conn
-		err  error
+	closedPortDelay, expectClosedPortDelay := dialClosedPort()
+	if closedPortDelay > expectClosedPortDelay {
+		t.Errorf("got %v; want <= %v", closedPortDelay, expectClosedPortDelay)
 	}
-	dials := listenerBacklog + 100
-	// used to be listenerBacklog + 5, but was found to be unreliable, issue 4384.
-	maxGoodConnect := listenerBacklog + runtime.NumCPU()*10
-	resc := make(chan connErr)
-	for i := 0; i < dials; i++ {
-		go func() {
-			conn, err := DialTimeout("tcp", ln.Addr().String(), 500*time.Millisecond)
-			resc <- connErr{conn, err}
-		}()
+
+	const instant time.Duration = 0
+	const fallbackDelay = 200 * time.Millisecond
+
+	// Some cases will run quickly when "connection refused" is fast,
+	// or trigger the fallbackDelay on Windows.  This value holds the
+	// lesser of the two delays.
+	var closedPortOrFallbackDelay time.Duration
+	if closedPortDelay < fallbackDelay {
+		closedPortOrFallbackDelay = closedPortDelay
+	} else {
+		closedPortOrFallbackDelay = fallbackDelay
 	}
 
-	var firstErr string
-	var ngood int
-	var toClose []io.Closer
-	for i := 0; i < dials; i++ {
-		ce := <-resc
-		if ce.err == nil {
-			ngood++
-			if ngood > maxGoodConnect {
-				t.Errorf("%d good connects; expected at most %d", ngood, maxGoodConnect)
-			}
-			toClose = append(toClose, ce.conn)
-			continue
+	origTestHookDialTCP := testHookDialTCP
+	defer func() { testHookDialTCP = origTestHookDialTCP }()
+	testHookDialTCP = slowDialTCP
+
+	nCopies := func(s string, n int) []string {
+		out := make([]string, n)
+		for i := 0; i < n; i++ {
+			out[i] = s
 		}
-		err := ce.err
-		if firstErr == "" {
-			firstErr = err.Error()
-		} else if err.Error() != firstErr {
-			t.Fatalf("inconsistent error messages: first was %q, then later %q", firstErr, err)
+		return out
+	}
+
+	var testCases = []struct {
+		primaries       []string
+		fallbacks       []string
+		teardownNetwork string
+		expectOk        bool
+		expectElapsed   time.Duration
+	}{
+		// These should just work on the first try.
+		{[]string{"127.0.0.1"}, []string{}, "", true, instant},
+		{[]string{"::1"}, []string{}, "", true, instant},
+		{[]string{"127.0.0.1", "::1"}, []string{slowDst6}, "tcp6", true, instant},
+		{[]string{"::1", "127.0.0.1"}, []string{slowDst4}, "tcp4", true, instant},
+		// Primary is slow; fallback should kick in.
+		{[]string{slowDst4}, []string{"::1"}, "", true, fallbackDelay},
+		// Skip a "connection refused" in the primary thread.
+		{[]string{"127.0.0.1", "::1"}, []string{}, "tcp4", true, closedPortDelay},
+		{[]string{"::1", "127.0.0.1"}, []string{}, "tcp6", true, closedPortDelay},
+		// Skip a "connection refused" in the fallback thread.
+		{[]string{slowDst4, slowDst6}, []string{"::1", "127.0.0.1"}, "tcp6", true, fallbackDelay + closedPortDelay},
+		// Primary refused, fallback without delay.
+		{[]string{"127.0.0.1"}, []string{"::1"}, "tcp4", true, closedPortOrFallbackDelay},
+		{[]string{"::1"}, []string{"127.0.0.1"}, "tcp6", true, closedPortOrFallbackDelay},
+		// Everything is refused.
+		{[]string{"127.0.0.1"}, []string{}, "tcp4", false, closedPortDelay},
+		// Nothing to do; fail instantly.
+		{[]string{}, []string{}, "", false, instant},
+		// Connecting to tons of addresses should not trip the deadline.
+		{nCopies("::1", 1000), []string{}, "", true, instant},
+	}
+
+	handler := func(dss *dualStackServer, ln Listener) {
+		for {
+			c, err := ln.Accept()
+			if err != nil {
+				return
+			}
+			c.Close()
 		}
 	}
-	for _, c := range toClose {
-		c.Close()
-	}
-	for i := 0; i < 100; i++ {
-		if got := numFD(); got < dials {
-			// Test passes.
-			return
+
+	// Convert a list of IP strings into TCPAddrs.
+	makeAddrs := func(ips []string, port string) addrList {
+		var out addrList
+		for _, ip := range ips {
+			addr, err := ResolveTCPAddr("tcp", JoinHostPort(ip, port))
+			if err != nil {
+				t.Fatal(err)
+			}
+			out = append(out, addr)
 		}
-		time.Sleep(10 * time.Millisecond)
+		return out
 	}
-	if got := numFD(); got >= dials {
-		t.Errorf("num fds after %d timeouts = %d; want <%d", dials, got, dials)
+
+	for i, tt := range testCases {
+		dss, err := newDualStackServer([]streamListener{
+			{network: "tcp4", address: "127.0.0.1"},
+			{network: "tcp6", address: "::1"},
+		})
+		if err != nil {
+			t.Fatal(err)
+		}
+		defer dss.teardown()
+		if err := dss.buildup(handler); err != nil {
+			t.Fatal(err)
+		}
+		if tt.teardownNetwork != "" {
+			// Destroy one of the listening sockets, creating an unreachable port.
+			dss.teardownNetwork(tt.teardownNetwork)
+		}
+
+		primaries := makeAddrs(tt.primaries, dss.port)
+		fallbacks := makeAddrs(tt.fallbacks, dss.port)
+		d := Dialer{
+			FallbackDelay: fallbackDelay,
+			Timeout:       slowTimeout,
+		}
+		ctx := &dialContext{
+			Dialer:        d,
+			network:       "tcp",
+			address:       "?",
+			finalDeadline: d.deadline(time.Now()),
+		}
+		startTime := time.Now()
+		c, err := dialParallel(ctx, primaries, fallbacks)
+		elapsed := time.Now().Sub(startTime)
+
+		if c != nil {
+			c.Close()
+		}
+
+		if tt.expectOk && err != nil {
+			t.Errorf("#%d: got %v; want nil", i, err)
+		} else if !tt.expectOk && err == nil {
+			t.Errorf("#%d: got nil; want non-nil", i)
+		}
+
+		expectElapsedMin := tt.expectElapsed - 95*time.Millisecond
+		expectElapsedMax := tt.expectElapsed + 95*time.Millisecond
+		if !(elapsed >= expectElapsedMin) {
+			t.Errorf("#%d: got %v; want >= %v", i, elapsed, expectElapsedMin)
+		} else if !(elapsed <= expectElapsedMax) {
+			t.Errorf("#%d: got %v; want <= %v", i, elapsed, expectElapsedMax)
+		}
 	}
+	// Wait for any slowDst4/slowDst6 connections to timeout.
+	time.Sleep(slowTimeout * 3 / 2)
 }
 
-func numTCP() (ntcp, nopen, nclose int, err error) {
-	lsof, err := exec.Command("lsof", "-n", "-p", strconv.Itoa(os.Getpid())).Output()
-	if err != nil {
-		return 0, 0, 0, err
+func lookupSlowFast(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, error) {
+	switch host {
+	case "slow6loopback4":
+		// Returns a slow IPv6 address, and a local IPv4 address.
+		return []IPAddr{
+			{IP: ParseIP(slowDst6)},
+			{IP: ParseIP("127.0.0.1")},
+		}, nil
+	default:
+		return fn(host)
 	}
-	ntcp += bytes.Count(lsof, []byte("TCP"))
-	for _, state := range []string{"LISTEN", "SYN_SENT", "SYN_RECEIVED", "ESTABLISHED"} {
-		nopen += bytes.Count(lsof, []byte(state))
+}
+
+func TestDialerFallbackDelay(t *testing.T) {
+	if testing.Short() || !*testExternal {
+		t.Skip("avoid external network")
 	}
-	for _, state := range []string{"CLOSED", "CLOSE_WAIT", "LAST_ACK", "FIN_WAIT_1", "FIN_WAIT_2", "CLOSING", "TIME_WAIT"} {
-		nclose += bytes.Count(lsof, []byte(state))
+	if !supportsIPv4 || !supportsIPv6 {
+		t.Skip("both IPv4 and IPv6 are required")
 	}
-	return ntcp, nopen, nclose, nil
-}
 
-func TestDialMultiFDLeak(t *testing.T) {
-	t.Skip("flaky test - golang.org/issue/8764")
+	origTestHookLookupIP := testHookLookupIP
+	defer func() { testHookLookupIP = origTestHookLookupIP }()
+	testHookLookupIP = lookupSlowFast
 
-	if !supportsIPv4 || !supportsIPv6 {
-		t.Skip("neither ipv4 nor ipv6 is supported")
+	origTestHookDialTCP := testHookDialTCP
+	defer func() { testHookDialTCP = origTestHookDialTCP }()
+	testHookDialTCP = slowDialTCP
+
+	var testCases = []struct {
+		dualstack     bool
+		delay         time.Duration
+		expectElapsed time.Duration
+	}{
+		// Use a very brief delay, which should fallback immediately.
+		{true, 1 * time.Nanosecond, 0},
+		// Use a 200ms explicit timeout.
+		{true, 200 * time.Millisecond, 200 * time.Millisecond},
+		// The default is 300ms.
+		{true, 0, 300 * time.Millisecond},
+		// This case is last, in order to wait for hanging slowDst6 connections.
+		{false, 0, slowTimeout},
 	}
 
-	halfDeadServer := func(dss *dualStackServer, ln Listener) {
+	handler := func(dss *dualStackServer, ln Listener) {
 		for {
-			if c, err := ln.Accept(); err != nil {
+			c, err := ln.Accept()
+			if err != nil {
 				return
-			} else {
-				// It just keeps established
-				// connections like a half-dead server
-				// does.
-				dss.putConn(c)
 			}
+			c.Close()
 		}
 	}
 	dss, err := newDualStackServer([]streamListener{
-		{net: "tcp4", addr: "127.0.0.1"},
-		{net: "tcp6", addr: "[::1]"},
+		{network: "tcp", address: "127.0.0.1"},
 	})
 	if err != nil {
-		t.Fatalf("newDualStackServer failed: %v", err)
+		t.Fatal(err)
 	}
 	defer dss.teardown()
-	if err := dss.buildup(halfDeadServer); err != nil {
-		t.Fatalf("dualStackServer.buildup failed: %v", err)
+	if err := dss.buildup(handler); err != nil {
+		t.Fatal(err)
 	}
 
-	_, before, _, err := numTCP()
+	for i, tt := range testCases {
+		d := &Dialer{DualStack: tt.dualstack, FallbackDelay: tt.delay, Timeout: slowTimeout}
+
+		startTime := time.Now()
+		c, err := d.Dial("tcp", JoinHostPort("slow6loopback4", dss.port))
+		elapsed := time.Now().Sub(startTime)
+		if err == nil {
+			c.Close()
+		} else if tt.dualstack {
+			t.Error(err)
+		}
+		expectMin := tt.expectElapsed - 1*time.Millisecond
+		expectMax := tt.expectElapsed + 95*time.Millisecond
+		if !(elapsed >= expectMin) {
+			t.Errorf("#%d: got %v; want >= %v", i, elapsed, expectMin)
+		}
+		if !(elapsed <= expectMax) {
+			t.Errorf("#%d: got %v; want <= %v", i, elapsed, expectMax)
+		}
+	}
+}
+
+func TestDialSerialAsyncSpuriousConnection(t *testing.T) {
+	ln, err := newLocalListener("tcp")
 	if err != nil {
-		t.Skipf("skipping test; error finding or running lsof: %v", err)
+		t.Fatal(err)
 	}
+	defer ln.Close()
 
-	var wg sync.WaitGroup
-	portnum, _, _ := dtoi(dss.port, 0)
-	ras := addrList{
-		// Losers that will fail to connect, see RFC 6890.
-		&TCPAddr{IP: IPv4(198, 18, 0, 254), Port: portnum},
-		&TCPAddr{IP: ParseIP("2001:2::254"), Port: portnum},
-
-		// Winner candidates of this race.
-		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: portnum},
-		&TCPAddr{IP: IPv6loopback, Port: portnum},
-
-		// Losers that will have established connections.
-		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: portnum},
-		&TCPAddr{IP: IPv6loopback, Port: portnum},
-	}
-	const T1 = 10 * time.Millisecond
-	const T2 = 2 * T1
-	const N = 10
-	for i := 0; i < N; i++ {
-		wg.Add(1)
-		go func() {
-			defer wg.Done()
-			if c, err := dialMulti("tcp", "fast failover test", nil, ras, time.Now().Add(T1)); err == nil {
-				c.Close()
-			}
-		}()
+	d := Dialer{}
+	ctx := &dialContext{
+		Dialer:        d,
+		network:       "tcp",
+		address:       "?",
+		finalDeadline: d.deadline(time.Now()),
 	}
-	wg.Wait()
-	time.Sleep(T2)
 
-	ntcp, after, nclose, err := numTCP()
+	results := make(chan dialResult)
+	cancel := make(chan struct{})
+
+	// Spawn a connection in the background.
+	go dialSerialAsync(ctx, addrList{ln.Addr()}, nil, cancel, results)
+
+	// Receive it at the server.
+	c, err := ln.Accept()
 	if err != nil {
-		t.Skipf("skipping test; error finding or running lsof: %v", err)
+		t.Fatal(err)
 	}
-	t.Logf("tcp sessions: %v, open sessions: %v, closing sessions: %v", ntcp, after, nclose)
+	defer c.Close()
 
-	if after != before {
-		t.Fatalf("got %v open sessions; expected %v", after, before)
+	// Tell dialSerialAsync that someone else won the race.
+	close(cancel)
+
+	// The connection should close itself, without sending data.
+	c.SetReadDeadline(time.Now().Add(1 * time.Second))
+	var b [1]byte
+	if _, err := c.Read(b[:]); err != io.EOF {
+		t.Errorf("got %v; want %v", err, io.EOF)
 	}
 }
 
-func numFD() int {
-	if runtime.GOOS == "linux" {
-		f, err := os.Open("/proc/self/fd")
-		if err != nil {
-			panic(err)
+func TestDialerPartialDeadline(t *testing.T) {
+	now := time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC)
+	var testCases = []struct {
+		now            time.Time
+		deadline       time.Time
+		addrs          int
+		expectDeadline time.Time
+		expectErr      error
+	}{
+		// Regular division.
+		{now, now.Add(12 * time.Second), 1, now.Add(12 * time.Second), nil},
+		{now, now.Add(12 * time.Second), 2, now.Add(6 * time.Second), nil},
+		{now, now.Add(12 * time.Second), 3, now.Add(4 * time.Second), nil},
+		// Bump against the 2-second sane minimum.
+		{now, now.Add(12 * time.Second), 999, now.Add(2 * time.Second), nil},
+		// Total available is now below the sane minimum.
+		{now, now.Add(1900 * time.Millisecond), 999, now.Add(1900 * time.Millisecond), nil},
+		// Null deadline.
+		{now, noDeadline, 1, noDeadline, nil},
+		// Step the clock forward and cross the deadline.
+		{now.Add(-1 * time.Millisecond), now, 1, now, nil},
+		{now.Add(0 * time.Millisecond), now, 1, noDeadline, errTimeout},
+		{now.Add(1 * time.Millisecond), now, 1, noDeadline, errTimeout},
+	}
+	for i, tt := range testCases {
+		deadline, err := partialDeadline(tt.now, tt.deadline, tt.addrs)
+		if err != tt.expectErr {
+			t.Errorf("#%d: got %v; want %v", i, err, tt.expectErr)
 		}
-		defer f.Close()
-		names, err := f.Readdirnames(0)
-		if err != nil {
-			panic(err)
+		if deadline != tt.expectDeadline {
+			t.Errorf("#%d: got %v; want %v", i, deadline, tt.expectDeadline)
 		}
-		return len(names)
 	}
-	// All tests using this should be skipped anyway, but:
-	panic("numFDs not implemented on " + runtime.GOOS)
 }
 
-func TestDialer(t *testing.T) {
-	ln, err := Listen("tcp4", "127.0.0.1:0")
-	if err != nil {
-		t.Fatalf("Listen failed: %v", err)
-	}
-	defer ln.Close()
+func TestDialerLocalAddr(t *testing.T) {
 	ch := make(chan error, 1)
-	go func() {
+	handler := func(ls *localServer, ln Listener) {
 		c, err := ln.Accept()
 		if err != nil {
-			ch <- fmt.Errorf("Accept failed: %v", err)
+			ch <- err
 			return
 		}
 		defer c.Close()
 		ch <- nil
-	}()
+	}
+	ls, err := newLocalServer("tcp")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer ls.teardown()
+	if err := ls.buildup(handler); err != nil {
+		t.Fatal(err)
+	}
 
-	laddr, err := ResolveTCPAddr("tcp4", "127.0.0.1:0")
+	laddr, err := ResolveTCPAddr(ls.Listener.Addr().Network(), ls.Listener.Addr().String())
 	if err != nil {
-		t.Fatalf("ResolveTCPAddr failed: %v", err)
+		t.Fatal(err)
 	}
+	laddr.Port = 0
 	d := &Dialer{LocalAddr: laddr}
-	c, err := d.Dial("tcp4", ln.Addr().String())
+	c, err := d.Dial(ls.Listener.Addr().Network(), ls.Addr().String())
 	if err != nil {
-		t.Fatalf("Dial failed: %v", err)
+		t.Fatal(err)
 	}
 	defer c.Close()
 	c.Read(make([]byte, 1))
@@ -466,61 +620,64 @@ func TestDialer(t *testing.T) {
 	}
 }
 
-func TestDialDualStackLocalhost(t *testing.T) {
-	switch runtime.GOOS {
-	case "nacl":
-		t.Skipf("skipping test on %q", runtime.GOOS)
+func TestDialerDualStack(t *testing.T) {
+	if !supportsIPv4 || !supportsIPv6 {
+		t.Skip("both IPv4 and IPv6 are required")
 	}
 
-	if ips, err := LookupIP("localhost"); err != nil {
-		t.Fatalf("LookupIP failed: %v", err)
-	} else if len(ips) < 2 || !supportsIPv4 || !supportsIPv6 {
-		t.Skip("localhost doesn't have a pair of different address family IP addresses")
+	closedPortDelay, expectClosedPortDelay := dialClosedPort()
+	if closedPortDelay > expectClosedPortDelay {
+		t.Errorf("got %v; want <= %v", closedPortDelay, expectClosedPortDelay)
 	}
 
-	touchAndByeServer := func(dss *dualStackServer, ln Listener) {
+	origTestHookLookupIP := testHookLookupIP
+	defer func() { testHookLookupIP = origTestHookLookupIP }()
+	testHookLookupIP = lookupLocalhost
+	handler := func(dss *dualStackServer, ln Listener) {
 		for {
-			if c, err := ln.Accept(); err != nil {
+			c, err := ln.Accept()
+			if err != nil {
 				return
-			} else {
-				c.Close()
 			}
+			c.Close()
 		}
 	}
-	dss, err := newDualStackServer([]streamListener{
-		{net: "tcp4", addr: "127.0.0.1"},
-		{net: "tcp6", addr: "[::1]"},
-	})
-	if err != nil {
-		t.Fatalf("newDualStackServer failed: %v", err)
-	}
-	defer dss.teardown()
-	if err := dss.buildup(touchAndByeServer); err != nil {
-		t.Fatalf("dualStackServer.buildup failed: %v", err)
-	}
 
-	d := &Dialer{DualStack: true}
-	for range dss.lns {
-		if c, err := d.Dial("tcp", "localhost:"+dss.port); err != nil {
-			t.Errorf("Dial failed: %v", err)
-		} else {
-			if addr := c.LocalAddr().(*TCPAddr); addr.IP.To4() != nil {
+	var timeout = 100*time.Millisecond + closedPortDelay
+	for _, dualstack := range []bool{false, true} {
+		dss, err := newDualStackServer([]streamListener{
+			{network: "tcp4", address: "127.0.0.1"},
+			{network: "tcp6", address: "::1"},
+		})
+		if err != nil {
+			t.Fatal(err)
+		}
+		defer dss.teardown()
+		if err := dss.buildup(handler); err != nil {
+			t.Fatal(err)
+		}
+
+		d := &Dialer{DualStack: dualstack, Timeout: timeout}
+		for range dss.lns {
+			c, err := d.Dial("tcp", JoinHostPort("localhost", dss.port))
+			if err != nil {
+				t.Error(err)
+				continue
+			}
+			switch addr := c.LocalAddr().(*TCPAddr); {
+			case addr.IP.To4() != nil:
 				dss.teardownNetwork("tcp4")
-			} else if addr.IP.To16() != nil && addr.IP.To4() == nil {
+			case addr.IP.To16() != nil && addr.IP.To4() == nil:
 				dss.teardownNetwork("tcp6")
 			}
 			c.Close()
 		}
 	}
+	time.Sleep(timeout * 3 / 2) // wait for the dial racers to stop
 }
 
 func TestDialerKeepAlive(t *testing.T) {
-	ln := newLocalListener(t)
-	defer ln.Close()
-	defer func() {
-		testHookSetKeepAlive = func() {}
-	}()
-	go func() {
+	handler := func(ls *localServer, ln Listener) {
 		for {
 			c, err := ln.Accept()
 			if err != nil {
@@ -528,7 +685,17 @@ func TestDialerKeepAlive(t *testing.T) {
 			}
 			c.Close()
 		}
-	}()
+	}
+	ls, err := newLocalServer("tcp")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer ls.teardown()
+	if err := ls.buildup(handler); err != nil {
+		t.Fatal(err)
+	}
+	defer func() { testHookSetKeepAlive = func() {} }()
+
 	for _, keepAlive := range []bool{false, true} {
 		got := false
 		testHookSetKeepAlive = func() { got = true }
@@ -536,7 +703,7 @@ func TestDialerKeepAlive(t *testing.T) {
 		if keepAlive {
 			d.KeepAlive = 30 * time.Second
 		}
-		c, err := d.Dial("tcp", ln.Addr().String())
+		c, err := d.Dial("tcp", ls.Listener.Addr().String())
 		if err != nil {
 			t.Fatal(err)
 		}
diff --git a/src/net/dialgoogle_test.go b/src/net/dialgoogle_test.go
deleted file mode 100644
index df5895a..0000000
--- a/src/net/dialgoogle_test.go
+++ /dev/null
@@ -1,209 +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 net
-
-import (
-	"flag"
-	"fmt"
-	"io"
-	"strings"
-	"syscall"
-	"testing"
-)
-
-// If an IPv6 tunnel is running, we can try dialing a real IPv6 address.
-var testIPv6 = flag.Bool("ipv6", false, "assume ipv6 tunnel is present")
-
-func TestResolveGoogle(t *testing.T) {
-	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
-	}
-
-	for _, network := range []string{"tcp", "tcp4", "tcp6"} {
-		addr, err := ResolveTCPAddr(network, "www.google.com:http")
-		if err != nil {
-			if (network == "tcp" || network == "tcp4") && !supportsIPv4 {
-				t.Logf("ipv4 is not supported: %v", err)
-			} else if network == "tcp6" && !supportsIPv6 {
-				t.Logf("ipv6 is not supported: %v", err)
-			} else {
-				t.Errorf("ResolveTCPAddr failed: %v", err)
-			}
-			continue
-		}
-		if (network == "tcp" || network == "tcp4") && addr.IP.To4() == nil {
-			t.Errorf("got %v; expected an IPv4 address on %v", addr, network)
-		} else if network == "tcp6" && (addr.IP.To16() == nil || addr.IP.To4() != nil) {
-			t.Errorf("got %v; expected an IPv6 address on %v", addr, network)
-		}
-	}
-}
-
-func TestDialGoogle(t *testing.T) {
-	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
-	}
-
-	d := &Dialer{DualStack: true}
-	for _, network := range []string{"tcp", "tcp4", "tcp6"} {
-		if network == "tcp" && !supportsIPv4 && !supportsIPv6 {
-			t.Logf("skipping test; both ipv4 and ipv6 are not supported")
-			continue
-		} else if network == "tcp4" && !supportsIPv4 {
-			t.Logf("skipping test; ipv4 is not supported")
-			continue
-		} else if network == "tcp6" && !supportsIPv6 {
-			t.Logf("skipping test; ipv6 is not supported")
-			continue
-		} else if network == "tcp6" && !*testIPv6 {
-			t.Logf("test disabled; use -ipv6 to enable")
-			continue
-		}
-		if c, err := d.Dial(network, "www.google.com:http"); err != nil {
-			t.Errorf("Dial failed: %v", err)
-		} else {
-			c.Close()
-		}
-	}
-}
-
-// fd is already connected to the destination, port 80.
-// Run an HTTP request to fetch the appropriate page.
-func fetchGoogle(t *testing.T, fd Conn, network, addr string) {
-	req := []byte("GET /robots.txt HTTP/1.0\r\nHost: www.google.com\r\n\r\n")
-	n, err := fd.Write(req)
-
-	buf := make([]byte, 1000)
-	n, err = io.ReadFull(fd, buf)
-
-	if n < 1000 {
-		t.Errorf("fetchGoogle: short HTTP read from %s %s - %v", network, addr, err)
-		return
-	}
-}
-
-func doDial(t *testing.T, network, addr string) {
-	fd, err := Dial(network, addr)
-	if err != nil {
-		t.Errorf("Dial(%q, %q, %q) = _, %v", network, "", addr, err)
-		return
-	}
-	fetchGoogle(t, fd, network, addr)
-	fd.Close()
-}
-
-var googleaddrsipv4 = []string{
-	"%d.%d.%d.%d:80",
-	"www.google.com:80",
-	"%d.%d.%d.%d:http",
-	"www.google.com:http",
-	"%03d.%03d.%03d.%03d:0080",
-	"[::ffff:%d.%d.%d.%d]:80",
-	"[::ffff:%02x%02x:%02x%02x]:80",
-	"[0:0:0:0:0000:ffff:%d.%d.%d.%d]:80",
-	"[0:0:0:0:000000:ffff:%d.%d.%d.%d]:80",
-	"[0:0:0:0::ffff:%d.%d.%d.%d]:80",
-}
-
-func TestDialGoogleIPv4(t *testing.T) {
-	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
-	}
-
-	// Insert an actual IPv4 address for google.com
-	// into the table.
-	addrs, err := LookupIP("www.google.com")
-	if err != nil {
-		t.Fatalf("lookup www.google.com: %v", err)
-	}
-	var ip IP
-	for _, addr := range addrs {
-		if x := addr.To4(); x != nil {
-			ip = x
-			break
-		}
-	}
-	if ip == nil {
-		t.Fatalf("no IPv4 addresses for www.google.com")
-	}
-
-	for i, s := range googleaddrsipv4 {
-		if strings.Contains(s, "%") {
-			googleaddrsipv4[i] = fmt.Sprintf(s, ip[0], ip[1], ip[2], ip[3])
-		}
-	}
-
-	for i := 0; i < len(googleaddrsipv4); i++ {
-		addr := googleaddrsipv4[i]
-		if addr == "" {
-			continue
-		}
-		t.Logf("-- %s --", addr)
-		doDial(t, "tcp", addr)
-		if addr[0] != '[' {
-			doDial(t, "tcp4", addr)
-			if supportsIPv6 {
-				// make sure syscall.SocketDisableIPv6 flag works.
-				syscall.SocketDisableIPv6 = true
-				doDial(t, "tcp", addr)
-				doDial(t, "tcp4", addr)
-				syscall.SocketDisableIPv6 = false
-			}
-		}
-	}
-}
-
-var googleaddrsipv6 = []string{
-	"[%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:80",
-	"ipv6.google.com:80",
-	"[%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:http",
-	"ipv6.google.com:http",
-}
-
-func TestDialGoogleIPv6(t *testing.T) {
-	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
-	}
-	// Only run tcp6 if the kernel will take it.
-	if !supportsIPv6 {
-		t.Skip("skipping test; ipv6 is not supported")
-	}
-	if !*testIPv6 {
-		t.Skip("test disabled; use -ipv6 to enable")
-	}
-
-	// Insert an actual IPv6 address for ipv6.google.com
-	// into the table.
-	addrs, err := LookupIP("ipv6.google.com")
-	if err != nil {
-		t.Fatalf("lookup ipv6.google.com: %v", err)
-	}
-	var ip IP
-	for _, addr := range addrs {
-		if x := addr.To16(); x != nil {
-			ip = x
-			break
-		}
-	}
-	if ip == nil {
-		t.Fatalf("no IPv6 addresses for ipv6.google.com")
-	}
-
-	for i, s := range googleaddrsipv6 {
-		if strings.Contains(s, "%") {
-			googleaddrsipv6[i] = fmt.Sprintf(s, ip[0], ip[1], ip[2], ip[3], ip[4], ip[5], ip[6], ip[7], ip[8], ip[9], ip[10], ip[11], ip[12], ip[13], ip[14], ip[15])
-		}
-	}
-
-	for i := 0; i < len(googleaddrsipv6); i++ {
-		addr := googleaddrsipv6[i]
-		if addr == "" {
-			continue
-		}
-		t.Logf("-- %s --", addr)
-		doDial(t, "tcp", addr)
-		doDial(t, "tcp6", addr)
-	}
-}
diff --git a/src/net/dnsclient.go b/src/net/dnsclient.go
index e8014e4..ce48521 100644
--- a/src/net/dnsclient.go
+++ b/src/net/dnsclient.go
@@ -9,31 +9,6 @@ import (
 	"sort"
 )
 
-// DNSError represents a DNS lookup error.
-type DNSError struct {
-	Err       string // description of the error
-	Name      string // name looked for
-	Server    string // server used
-	IsTimeout bool
-}
-
-func (e *DNSError) Error() string {
-	if e == nil {
-		return "<nil>"
-	}
-	s := "lookup " + e.Name
-	if e.Server != "" {
-		s += " on " + e.Server
-	}
-	s += ": " + e.Err
-	return s
-}
-
-func (e *DNSError) Timeout() bool   { return e.IsTimeout }
-func (e *DNSError) Temporary() bool { return e.IsTimeout }
-
-const noSuchHost = "no such host"
-
 // reverseaddr returns the in-addr.arpa. or ip6.arpa. hostname of the IP
 // address addr suitable for rDNS (PTR) record lookup or an error if it fails
 // to parse the IP address.
@@ -43,8 +18,7 @@ func reverseaddr(addr string) (arpa string, err error) {
 		return "", &DNSError{Err: "unrecognized address", Name: addr}
 	}
 	if ip.To4() != nil {
-		return itoa(int(ip[15])) + "." + itoa(int(ip[14])) + "." + itoa(int(ip[13])) + "." +
-			itoa(int(ip[12])) + ".in-addr.arpa.", nil
+		return uitoa(uint(ip[15])) + "." + uitoa(uint(ip[14])) + "." + uitoa(uint(ip[13])) + "." + uitoa(uint(ip[12])) + ".in-addr.arpa.", nil
 	}
 	// Must be IPv6
 	buf := make([]byte, 0, len(ip)*4+len("ip6.arpa."))
@@ -67,7 +41,7 @@ func answer(name, server string, dns *dnsMsg, qtype uint16) (cname string, addrs
 	addrs = make([]dnsRR, 0, len(dns.answer))
 
 	if dns.rcode == dnsRcodeNameError && dns.recursion_available {
-		return "", nil, &DNSError{Err: noSuchHost, Name: name}
+		return "", nil, &DNSError{Err: errNoSuchHost.Error(), Name: name, Server: server}
 	}
 	if dns.rcode != dnsRcodeSuccess {
 		// None of the error codes make sense
@@ -94,7 +68,7 @@ Cname:
 				continue
 			}
 			h := rr.Header()
-			if h.Class == dnsClassINET && h.Name == name {
+			if h.Class == dnsClassINET && equalASCIILabel(h.Name, name) {
 				switch h.Rrtype {
 				case qtype:
 					addrs = append(addrs, rr)
@@ -106,7 +80,7 @@ Cname:
 			}
 		}
 		if len(addrs) == 0 {
-			return "", nil, &DNSError{Err: noSuchHost, Name: name, Server: server}
+			return "", nil, &DNSError{Err: errNoSuchHost.Error(), Name: name, Server: server}
 		}
 		return name, addrs, nil
 	}
@@ -114,6 +88,26 @@ Cname:
 	return "", nil, &DNSError{Err: "too many redirects", Name: name, Server: server}
 }
 
+func equalASCIILabel(x, y string) bool {
+	if len(x) != len(y) {
+		return false
+	}
+	for i := 0; i < len(x); i++ {
+		a := x[i]
+		b := y[i]
+		if 'A' <= a && a <= 'Z' {
+			a += 0x20
+		}
+		if 'A' <= b && b <= 'Z' {
+			b += 0x20
+		}
+		if a != b {
+			return false
+		}
+	}
+	return true
+}
+
 func isDomainName(s string) bool {
 	// See RFC 1035, RFC 3696.
 	if len(s) == 0 {
@@ -174,13 +168,10 @@ type SRV struct {
 type byPriorityWeight []*SRV
 
 func (s byPriorityWeight) Len() int { return len(s) }
-
-func (s byPriorityWeight) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
-
 func (s byPriorityWeight) Less(i, j int) bool {
-	return s[i].Priority < s[j].Priority ||
-		(s[i].Priority == s[j].Priority && s[i].Weight < s[j].Weight)
+	return s[i].Priority < s[j].Priority || (s[i].Priority == s[j].Priority && s[i].Weight < s[j].Weight)
 }
+func (s byPriorityWeight) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
 
 // shuffleByWeight shuffles SRV records by weight using the algorithm
 // described in RFC 2782.
@@ -228,11 +219,9 @@ type MX struct {
 // byPref implements sort.Interface to sort MX records by preference
 type byPref []*MX
 
-func (s byPref) Len() int { return len(s) }
-
+func (s byPref) Len() int           { return len(s) }
 func (s byPref) Less(i, j int) bool { return s[i].Pref < s[j].Pref }
-
-func (s byPref) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
+func (s byPref) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
 
 // sort reorders MX records as specified in RFC 5321.
 func (s byPref) sort() {
diff --git a/src/net/dnsclient_test.go b/src/net/dnsclient_test.go
index 435eb35..3ab2b83 100644
--- a/src/net/dnsclient_test.go
+++ b/src/net/dnsclient_test.go
@@ -47,7 +47,7 @@ func testUniformity(t *testing.T, size int, margin float64) {
 	checkDistribution(t, data, margin)
 }
 
-func TestUniformity(t *testing.T) {
+func TestDNSSRVUniformity(t *testing.T) {
 	testUniformity(t, 2, 0.05)
 	testUniformity(t, 3, 0.10)
 	testUniformity(t, 10, 0.20)
diff --git a/src/net/dnsclient_unix.go b/src/net/dnsclient_unix.go
index 7511083..c03c1b1 100644
--- a/src/net/dnsclient_unix.go
+++ b/src/net/dnsclient_unix.go
@@ -20,6 +20,7 @@ import (
 	"io"
 	"math/rand"
 	"os"
+	"strconv"
 	"sync"
 	"time"
 )
@@ -184,9 +185,9 @@ func tryOneName(cfg *dnsConfig, name string, qtype uint16) (string, []dnsRR, err
 				}
 				continue
 			}
-			cname, addrs, err := answer(name, server, msg, qtype)
-			if err == nil || err.(*DNSError).Err == noSuchHost {
-				return cname, addrs, err
+			cname, rrs, err := answer(name, server, msg, qtype)
+			if err == nil || msg.rcode == dnsRcodeSuccess || msg.rcode == dnsRcodeNameError && msg.recursion_available {
+				return cname, rrs, err
 			}
 			lastErr = err
 		}
@@ -194,144 +195,188 @@ func tryOneName(cfg *dnsConfig, name string, qtype uint16) (string, []dnsRR, err
 	return "", nil, lastErr
 }
 
-func convertRR_A(records []dnsRR) []IP {
-	addrs := make([]IP, len(records))
-	for i, rr := range records {
-		a := rr.(*dnsRR_A).A
-		addrs[i] = IPv4(byte(a>>24), byte(a>>16), byte(a>>8), byte(a))
+// addrRecordList converts and returns a list of IP addresses from DNS
+// address records (both A and AAAA). Other record types are ignored.
+func addrRecordList(rrs []dnsRR) []IPAddr {
+	addrs := make([]IPAddr, 0, 4)
+	for _, rr := range rrs {
+		switch rr := rr.(type) {
+		case *dnsRR_A:
+			addrs = append(addrs, IPAddr{IP: IPv4(byte(rr.A>>24), byte(rr.A>>16), byte(rr.A>>8), byte(rr.A))})
+		case *dnsRR_AAAA:
+			ip := make(IP, IPv6len)
+			copy(ip, rr.AAAA[:])
+			addrs = append(addrs, IPAddr{IP: ip})
+		}
 	}
 	return addrs
 }
 
-func convertRR_AAAA(records []dnsRR) []IP {
-	addrs := make([]IP, len(records))
-	for i, rr := range records {
-		a := make(IP, IPv6len)
-		copy(a, rr.(*dnsRR_AAAA).AAAA[:])
-		addrs[i] = a
-	}
-	return addrs
-}
+// A resolverConfig represents a DNS stub resolver configuration.
+type resolverConfig struct {
+	initOnce sync.Once // guards init of resolverConfig
 
-var cfg struct {
-	ch        chan struct{}
-	mu        sync.RWMutex // protects dnsConfig and dnserr
-	dnsConfig *dnsConfig
-	dnserr    error
-}
-var onceLoadConfig sync.Once
+	// ch is used as a semaphore that only allows one lookup at a
+	// time to recheck resolv.conf.
+	ch          chan struct{} // guards lastChecked and modTime
+	lastChecked time.Time     // last time resolv.conf was checked
+	modTime     time.Time     // time of resolv.conf modification
 
-// Assume dns config file is /etc/resolv.conf here
-func loadDefaultConfig() {
-	loadConfig("/etc/resolv.conf", 5*time.Second, nil)
+	mu        sync.RWMutex // protects dnsConfig
+	dnsConfig *dnsConfig   // parsed resolv.conf structure used in lookups
 }
 
-func loadConfig(resolvConfPath string, reloadTime time.Duration, quit <-chan chan struct{}) {
-	var mtime time.Time
-	cfg.ch = make(chan struct{}, 1)
-	if fi, err := os.Stat(resolvConfPath); err != nil {
-		cfg.dnserr = err
-	} else {
-		mtime = fi.ModTime()
-		cfg.dnsConfig, cfg.dnserr = dnsReadConfig(resolvConfPath)
-	}
-	go func() {
-		for {
-			time.Sleep(reloadTime)
-			select {
-			case qresp := <-quit:
-				qresp <- struct{}{}
-				return
-			case <-cfg.ch:
-			}
+var resolvConf resolverConfig
 
-			// In case of error, we keep the previous config
-			fi, err := os.Stat(resolvConfPath)
-			if err != nil {
-				continue
-			}
-			// If the resolv.conf mtime didn't change, do not reload
-			m := fi.ModTime()
-			if m.Equal(mtime) {
-				continue
-			}
-			mtime = m
-			// In case of error, we keep the previous config
-			ncfg, err := dnsReadConfig(resolvConfPath)
-			if err != nil || len(ncfg.servers) == 0 {
-				continue
-			}
-			cfg.mu.Lock()
-			cfg.dnsConfig = ncfg
-			cfg.dnserr = nil
-			cfg.mu.Unlock()
-		}
-	}()
-}
-
-func lookup(name string, qtype uint16) (cname string, addrs []dnsRR, err error) {
-	if !isDomainName(name) {
-		return name, nil, &DNSError{Err: "invalid domain name", Name: name}
+// init initializes conf and is only called via conf.initOnce.
+func (conf *resolverConfig) init() {
+	// Set dnsConfig, modTime, and lastChecked so we don't parse
+	// resolv.conf twice the first time.
+	conf.dnsConfig = systemConf().resolv
+	if conf.dnsConfig == nil {
+		conf.dnsConfig = dnsReadConfig("/etc/resolv.conf")
 	}
-	onceLoadConfig.Do(loadDefaultConfig)
 
-	select {
-	case cfg.ch <- struct{}{}:
-	default:
+	if fi, err := os.Stat("/etc/resolv.conf"); err == nil {
+		conf.modTime = fi.ModTime()
 	}
+	conf.lastChecked = time.Now()
+
+	// Prepare ch so that only one update of resolverConfig may
+	// run at once.
+	conf.ch = make(chan struct{}, 1)
+}
 
-	cfg.mu.RLock()
-	defer cfg.mu.RUnlock()
+// tryUpdate tries to update conf with the named resolv.conf file.
+// The name variable only exists for testing. It is otherwise always
+// "/etc/resolv.conf".
+func (conf *resolverConfig) tryUpdate(name string) {
+	conf.initOnce.Do(conf.init)
 
-	if cfg.dnserr != nil || cfg.dnsConfig == nil {
-		err = cfg.dnserr
+	// Ensure only one update at a time checks resolv.conf.
+	if !conf.tryAcquireSema() {
 		return
 	}
-	// If name is rooted (trailing dot) or has enough dots,
-	// try it by itself first.
-	rooted := len(name) > 0 && name[len(name)-1] == '.'
-	if rooted || count(name, '.') >= cfg.dnsConfig.ndots {
-		rname := name
-		if !rooted {
-			rname += "."
-		}
-		// Can try as ordinary name.
-		cname, addrs, err = tryOneName(cfg.dnsConfig, rname, qtype)
-		if rooted || err == nil {
-			return
-		}
+	defer conf.releaseSema()
+
+	now := time.Now()
+	if conf.lastChecked.After(now.Add(-5 * time.Second)) {
+		return
 	}
+	conf.lastChecked = now
 
-	// Otherwise, try suffixes.
-	for i := 0; i < len(cfg.dnsConfig.search); i++ {
-		rname := name + "." + cfg.dnsConfig.search[i]
-		if rname[len(rname)-1] != '.' {
-			rname += "."
+	if fi, err := os.Stat(name); err == nil {
+		if fi.ModTime().Equal(conf.modTime) {
+			return
 		}
-		cname, addrs, err = tryOneName(cfg.dnsConfig, rname, qtype)
-		if err == nil {
+		conf.modTime = fi.ModTime()
+	} else {
+		// If modTime wasn't set prior, assume nothing has changed.
+		if conf.modTime.IsZero() {
 			return
 		}
+		conf.modTime = time.Time{}
 	}
 
-	// Last ditch effort: try unsuffixed only if we haven't already,
-	// that is, name is not rooted and has less than ndots dots.
-	if count(name, '.') < cfg.dnsConfig.ndots {
-		cname, addrs, err = tryOneName(cfg.dnsConfig, name+".", qtype)
+	dnsConf := dnsReadConfig(name)
+	conf.mu.Lock()
+	conf.dnsConfig = dnsConf
+	conf.mu.Unlock()
+}
+
+func (conf *resolverConfig) tryAcquireSema() bool {
+	select {
+	case conf.ch <- struct{}{}:
+		return true
+	default:
+		return false
+	}
+}
+
+func (conf *resolverConfig) releaseSema() {
+	<-conf.ch
+}
+
+func lookup(name string, qtype uint16) (cname string, rrs []dnsRR, err error) {
+	if !isDomainName(name) {
+		return "", nil, &DNSError{Err: "invalid domain name", Name: name}
+	}
+	resolvConf.tryUpdate("/etc/resolv.conf")
+	resolvConf.mu.RLock()
+	conf := resolvConf.dnsConfig
+	resolvConf.mu.RUnlock()
+	for _, fqdn := range conf.nameList(name) {
+		cname, rrs, err = tryOneName(conf, fqdn, qtype)
 		if err == nil {
-			return
+			break
 		}
 	}
-
-	if e, ok := err.(*DNSError); ok {
+	if err, ok := err.(*DNSError); ok {
 		// Show original name passed to lookup, not suffixed one.
 		// In general we might have tried many suffixes; showing
 		// just one is misleading. See also golang.org/issue/6324.
-		e.Name = name
+		err.Name = name
 	}
 	return
 }
 
+// nameList returns a list of names for sequential DNS queries.
+func (conf *dnsConfig) nameList(name string) []string {
+	// If name is rooted (trailing dot), try only that name.
+	rooted := len(name) > 0 && name[len(name)-1] == '.'
+	if rooted {
+		return []string{name}
+	}
+	// Build list of search choices.
+	names := make([]string, 0, 1+len(conf.search))
+	// If name has enough dots, try unsuffixed first.
+	if count(name, '.') >= conf.ndots {
+		names = append(names, name+".")
+	}
+	// Try suffixes.
+	for _, suffix := range conf.search {
+		suffixed := name + "." + suffix
+		if suffixed[len(suffixed)-1] != '.' {
+			suffixed += "."
+		}
+		names = append(names, suffixed)
+	}
+	// Try unsuffixed, if not tried first above.
+	if count(name, '.') < conf.ndots {
+		names = append(names, name+".")
+	}
+	return names
+}
+
+// hostLookupOrder specifies the order of LookupHost lookup strategies.
+// It is basically a simplified representation of nsswitch.conf.
+// "files" means /etc/hosts.
+type hostLookupOrder int
+
+const (
+	// hostLookupCgo means defer to cgo.
+	hostLookupCgo      hostLookupOrder = iota
+	hostLookupFilesDNS                 // files first
+	hostLookupDNSFiles                 // dns first
+	hostLookupFiles                    // only files
+	hostLookupDNS                      // only DNS
+)
+
+var lookupOrderName = map[hostLookupOrder]string{
+	hostLookupCgo:      "cgo",
+	hostLookupFilesDNS: "files,dns",
+	hostLookupDNSFiles: "dns,files",
+	hostLookupFiles:    "files",
+	hostLookupDNS:      "dns",
+}
+
+func (o hostLookupOrder) String() string {
+	if s, ok := lookupOrderName[o]; ok {
+		return s
+	}
+	return "hostLookupOrder=" + strconv.Itoa(int(o)) + "??"
+}
+
 // goLookupHost is the native Go implementation of LookupHost.
 // Used only if cgoLookupHost refuses to handle the request
 // (that is, only if cgoLookupHost is the stub in cgo_stub.go).
@@ -339,12 +384,18 @@ func lookup(name string, qtype uint16) (cname string, addrs []dnsRR, err error)
 // depending on our lookup code, so that Go and C get the same
 // answers.
 func goLookupHost(name string) (addrs []string, err error) {
-	// Use entries from /etc/hosts if they match.
-	addrs = lookupStaticHost(name)
-	if len(addrs) > 0 {
-		return
+	return goLookupHostOrder(name, hostLookupFilesDNS)
+}
+
+func goLookupHostOrder(name string, order hostLookupOrder) (addrs []string, err error) {
+	if order == hostLookupFilesDNS || order == hostLookupFiles {
+		// Use entries from /etc/hosts if they match.
+		addrs = lookupStaticHost(name)
+		if len(addrs) > 0 || order == hostLookupFiles {
+			return
+		}
 	}
-	ips, err := goLookupIP(name)
+	ips, err := goLookupIPOrder(name, order)
 	if err != nil {
 		return
 	}
@@ -355,54 +406,79 @@ func goLookupHost(name string) (addrs []string, err error) {
 	return
 }
 
-// goLookupIP is the native Go implementation of LookupIP.
-// Used only if cgoLookupIP refuses to handle the request
-// (that is, only if cgoLookupIP is the stub in cgo_stub.go).
-// 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) {
-	// Use entries from /etc/hosts if possible.
-	haddrs := lookupStaticHost(name)
-	if len(haddrs) > 0 {
-		for _, haddr := range haddrs {
-			if ip := ParseIP(haddr); ip != nil {
-				addrs = append(addrs, ip)
-			}
+// lookup entries from /etc/hosts
+func goLookupIPFiles(name string) (addrs []IPAddr) {
+	for _, haddr := range lookupStaticHost(name) {
+		haddr, zone := splitHostZone(haddr)
+		if ip := ParseIP(haddr); ip != nil {
+			addr := IPAddr{IP: ip, Zone: zone}
+			addrs = append(addrs, addr)
 		}
-		if len(addrs) > 0 {
-			return
+	}
+	sortByRFC6724(addrs)
+	return
+}
+
+// goLookupIP is the native Go implementation of LookupIP.
+// The libc versions are in cgo_*.go.
+func goLookupIP(name string) (addrs []IPAddr, err error) {
+	return goLookupIPOrder(name, hostLookupFilesDNS)
+}
+
+func goLookupIPOrder(name string, order hostLookupOrder) (addrs []IPAddr, err error) {
+	if order == hostLookupFilesDNS || order == hostLookupFiles {
+		addrs = goLookupIPFiles(name)
+		if len(addrs) > 0 || order == hostLookupFiles {
+			return addrs, nil
 		}
 	}
+	if !isDomainName(name) {
+		return nil, &DNSError{Err: "invalid domain name", Name: name}
+	}
+	resolvConf.tryUpdate("/etc/resolv.conf")
+	resolvConf.mu.RLock()
+	conf := resolvConf.dnsConfig
+	resolvConf.mu.RUnlock()
 	type racer struct {
-		qtype uint16
-		rrs   []dnsRR
+		rrs []dnsRR
 		error
 	}
 	lane := make(chan racer, 1)
 	qtypes := [...]uint16{dnsTypeA, dnsTypeAAAA}
-	for _, qtype := range qtypes {
-		go func(qtype uint16) {
-			_, rrs, err := lookup(name, qtype)
-			lane <- racer{qtype, rrs, err}
-		}(qtype)
-	}
 	var lastErr error
-	for range qtypes {
-		racer := <-lane
-		if racer.error != nil {
-			lastErr = racer.error
-			continue
+	for _, fqdn := range conf.nameList(name) {
+		for _, qtype := range qtypes {
+			go func(qtype uint16) {
+				_, rrs, err := tryOneName(conf, fqdn, qtype)
+				lane <- racer{rrs, err}
+			}(qtype)
+		}
+		for range qtypes {
+			racer := <-lane
+			if racer.error != nil {
+				lastErr = racer.error
+				continue
+			}
+			addrs = append(addrs, addrRecordList(racer.rrs)...)
 		}
-		switch racer.qtype {
-		case dnsTypeA:
-			addrs = append(addrs, convertRR_A(racer.rrs)...)
-		case dnsTypeAAAA:
-			addrs = append(addrs, convertRR_AAAA(racer.rrs)...)
+		if len(addrs) > 0 {
+			break
 		}
 	}
-	if len(addrs) == 0 && lastErr != nil {
-		return nil, lastErr
+	if lastErr, ok := lastErr.(*DNSError); ok {
+		// Show original name passed to lookup, not suffixed one.
+		// In general we might have tried many suffixes; showing
+		// just one is misleading. See also golang.org/issue/6324.
+		lastErr.Name = name
+	}
+	sortByRFC6724(addrs)
+	if len(addrs) == 0 {
+		if lastErr != nil {
+			return nil, lastErr
+		}
+		if order == hostLookupDNSFiles {
+			addrs = goLookupIPFiles(name)
+		}
 	}
 	return addrs, nil
 }
@@ -414,10 +490,35 @@ func goLookupIP(name string) (addrs []IP, err error) {
 // depending on our lookup code, so that Go and C get the same
 // answers.
 func goLookupCNAME(name string) (cname string, err error) {
-	_, rr, err := lookup(name, dnsTypeCNAME)
+	_, rrs, err := lookup(name, dnsTypeCNAME)
 	if err != nil {
 		return
 	}
-	cname = rr[0].(*dnsRR_CNAME).Cname
+	cname = rrs[0].(*dnsRR_CNAME).Cname
 	return
 }
+
+// goLookupPTR is the native Go implementation of LookupAddr.
+// Used only if cgoLookupPTR refuses to handle the request (that is,
+// only if cgoLookupPTR is the stub in cgo_stub.go).
+// 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 goLookupPTR(addr string) ([]string, error) {
+	names := lookupStaticAddr(addr)
+	if len(names) > 0 {
+		return names, nil
+	}
+	arpa, err := reverseaddr(addr)
+	if err != nil {
+		return nil, err
+	}
+	_, rrs, err := lookup(arpa, dnsTypePTR)
+	if err != nil {
+		return nil, err
+	}
+	ptrs := make([]string, len(rrs))
+	for i, rr := range rrs {
+		ptrs[i] = rr.(*dnsRR_PTR).Ptr
+	}
+	return ptrs, nil
+}
diff --git a/src/net/dnsclient_unix_test.go b/src/net/dnsclient_unix_test.go
index 1167c26..a999f8f 100644
--- a/src/net/dnsclient_unix_test.go
+++ b/src/net/dnsclient_unix_test.go
@@ -7,11 +7,13 @@
 package net
 
 import (
-	"io"
+	"fmt"
 	"io/ioutil"
 	"os"
 	"path"
 	"reflect"
+	"strings"
+	"sync"
 	"testing"
 	"time"
 )
@@ -31,7 +33,7 @@ var dnsTransportFallbackTests = []struct {
 
 func TestDNSTransportFallback(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
+		t.Skip("avoid external network")
 	}
 
 	for _, tt := range dnsTransportFallbackTests {
@@ -57,13 +59,13 @@ var specialDomainNameTests = []struct {
 	qtype uint16
 	rcode int
 }{
-	// Name resoltion APIs and libraries should not recongnize the
+	// Name resolution APIs and libraries should not recognize the
 	// followings as special.
 	{"1.0.168.192.in-addr.arpa.", dnsTypePTR, dnsRcodeNameError},
 	{"test.", dnsTypeALL, dnsRcodeNameError},
 	{"example.com.", dnsTypeALL, dnsRcodeSuccess},
 
-	// Name resoltion APIs and libraries should recongnize the
+	// Name resolution APIs and libraries should recognize the
 	// followings as special and should not send any queries.
 	// Though, we test those names here for verifying nagative
 	// answers at DNS query-response interaction level.
@@ -73,7 +75,7 @@ var specialDomainNameTests = []struct {
 
 func TestSpecialDomainName(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
+		t.Skip("avoid external network")
 	}
 
 	server := "8.8.8.8:53"
@@ -93,154 +95,323 @@ func TestSpecialDomainName(t *testing.T) {
 }
 
 type resolvConfTest struct {
-	*testing.T
-	dir     string
-	path    string
-	started bool
-	quitc   chan chan struct{}
+	dir  string
+	path string
+	*resolverConfig
 }
 
-func newResolvConfTest(t *testing.T) *resolvConfTest {
-	dir, err := ioutil.TempDir("", "resolvConfTest")
+func newResolvConfTest() (*resolvConfTest, error) {
+	dir, err := ioutil.TempDir("", "go-resolvconftest")
 	if err != nil {
-		t.Fatalf("could not create temp dir: %v", err)
+		return nil, err
 	}
-
-	// Disable the default loadConfig
-	onceLoadConfig.Do(func() {})
-
-	r := &resolvConfTest{
-		T:     t,
-		dir:   dir,
-		path:  path.Join(dir, "resolv.conf"),
-		quitc: make(chan chan struct{}),
+	conf := &resolvConfTest{
+		dir:            dir,
+		path:           path.Join(dir, "resolv.conf"),
+		resolverConfig: &resolvConf,
 	}
-
-	return r
+	conf.initOnce.Do(conf.init)
+	return conf, nil
 }
 
-func (r *resolvConfTest) Start() {
-	loadConfig(r.path, 100*time.Millisecond, r.quitc)
-	r.started = true
-}
-
-func (r *resolvConfTest) SetConf(s string) {
-	// Make sure the file mtime will be different once we're done here,
-	// even on systems with coarse (1s) mtime resolution.
-	time.Sleep(time.Second)
-
-	f, err := os.OpenFile(r.path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600)
+func (conf *resolvConfTest) writeAndUpdate(lines []string) error {
+	f, err := os.OpenFile(conf.path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0600)
 	if err != nil {
-		r.Fatalf("failed to create temp file %s: %v", r.path, err)
+		return err
 	}
-	if _, err := io.WriteString(f, s); err != nil {
+	if _, err := f.WriteString(strings.Join(lines, "\n")); err != nil {
 		f.Close()
-		r.Fatalf("failed to write temp file: %v", err)
+		return err
 	}
 	f.Close()
-
-	if r.started {
-		cfg.ch <- struct{}{} // fill buffer
-		cfg.ch <- struct{}{} // wait for reload to begin
-		cfg.ch <- struct{}{} // wait for reload to complete
+	if err := conf.forceUpdate(conf.path); err != nil {
+		return err
 	}
+	return nil
 }
 
-func (r *resolvConfTest) WantServers(want []string) {
-	cfg.mu.RLock()
-	defer cfg.mu.RUnlock()
-	if got := cfg.dnsConfig.servers; !reflect.DeepEqual(got, want) {
-		r.Fatalf("Unexpected dns server loaded, got %v want %v", got, want)
+func (conf *resolvConfTest) forceUpdate(name string) error {
+	dnsConf := dnsReadConfig(name)
+	conf.mu.Lock()
+	conf.dnsConfig = dnsConf
+	conf.mu.Unlock()
+	for i := 0; i < 5; i++ {
+		if conf.tryAcquireSema() {
+			conf.lastChecked = time.Time{}
+			conf.releaseSema()
+			return nil
+		}
 	}
+	return fmt.Errorf("tryAcquireSema for %s failed", name)
 }
 
-func (r *resolvConfTest) Close() {
-	resp := make(chan struct{})
-	r.quitc <- resp
-	<-resp
-	if err := os.RemoveAll(r.dir); err != nil {
-		r.Logf("failed to remove temp dir %s: %v", r.dir, err)
-	}
+func (conf *resolvConfTest) servers() []string {
+	conf.mu.RLock()
+	servers := conf.dnsConfig.servers
+	conf.mu.RUnlock()
+	return servers
 }
 
-func TestReloadResolvConfFail(t *testing.T) {
-	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
-	}
+func (conf *resolvConfTest) teardown() error {
+	err := conf.forceUpdate("/etc/resolv.conf")
+	os.RemoveAll(conf.dir)
+	return err
+}
 
-	r := newResolvConfTest(t)
-	defer r.Close()
+var updateResolvConfTests = []struct {
+	name    string   // query name
+	lines   []string // resolver configuration lines
+	servers []string // expected name servers
+}{
+	{
+		name:    "golang.org",
+		lines:   []string{"nameserver 8.8.8.8"},
+		servers: []string{"8.8.8.8"},
+	},
+	{
+		name:    "",
+		lines:   nil, // an empty resolv.conf should use defaultNS as name servers
+		servers: defaultNS,
+	},
+	{
+		name:    "www.example.com",
+		lines:   []string{"nameserver 8.8.4.4"},
+		servers: []string{"8.8.4.4"},
+	},
+}
 
-	// resolv.conf.tmp does not exist yet
-	r.Start()
-	if _, err := goLookupIP("golang.org"); err == nil {
-		t.Fatal("goLookupIP(missing) succeeded")
+func TestUpdateResolvConf(t *testing.T) {
+	if testing.Short() || !*testExternal {
+		t.Skip("avoid external network")
 	}
 
-	r.SetConf("nameserver 8.8.8.8")
-	if _, err := goLookupIP("golang.org"); err != nil {
-		t.Fatalf("goLookupIP(missing; good) failed: %v", err)
+	conf, err := newResolvConfTest()
+	if err != nil {
+		t.Fatal(err)
 	}
+	defer conf.teardown()
 
-	// Using a bad resolv.conf while we had a good
-	// one before should not update the config
-	r.SetConf("")
-	if _, err := goLookupIP("golang.org"); err != nil {
-		t.Fatalf("goLookupIP(missing; good; bad) failed: %v", err)
+	for i, tt := range updateResolvConfTests {
+		if err := conf.writeAndUpdate(tt.lines); err != nil {
+			t.Error(err)
+			continue
+		}
+		if tt.name != "" {
+			var wg sync.WaitGroup
+			const N = 10
+			wg.Add(N)
+			for j := 0; j < N; j++ {
+				go func(name string) {
+					defer wg.Done()
+					ips, err := goLookupIP(name)
+					if err != nil {
+						t.Error(err)
+						return
+					}
+					if len(ips) == 0 {
+						t.Errorf("no records for %s", name)
+						return
+					}
+				}(tt.name)
+			}
+			wg.Wait()
+		}
+		servers := conf.servers()
+		if !reflect.DeepEqual(servers, tt.servers) {
+			t.Errorf("#%d: got %v; want %v", i, servers, tt.servers)
+			continue
+		}
 	}
 }
 
-func TestReloadResolvConfChange(t *testing.T) {
+var goLookupIPWithResolverConfigTests = []struct {
+	name  string
+	lines []string // resolver configuration lines
+	error
+	a, aaaa bool // whether response contains A, AAAA-record
+}{
+	// no records, transport timeout
+	{
+		"jgahvsekduiv9bw4b3qhn4ykdfgj0493iohkrjfhdvhjiu4j",
+		[]string{
+			"options timeout:1 attempts:1",
+			"nameserver 255.255.255.255", // please forgive us for abuse of limited broadcast address
+		},
+		&DNSError{Name: "jgahvsekduiv9bw4b3qhn4ykdfgj0493iohkrjfhdvhjiu4j", Server: "255.255.255.255:53", IsTimeout: true},
+		false, false,
+	},
+
+	// no records, non-existent domain
+	{
+		"jgahvsekduiv9bw4b3qhn4ykdfgj0493iohkrjfhdvhjiu4j",
+		[]string{
+			"options timeout:3 attempts:1",
+			"nameserver 8.8.8.8",
+		},
+		&DNSError{Name: "jgahvsekduiv9bw4b3qhn4ykdfgj0493iohkrjfhdvhjiu4j", Server: "8.8.8.8:53", IsTimeout: false},
+		false, false,
+	},
+
+	// a few A records, no AAAA records
+	{
+		"ipv4.google.com.",
+		[]string{
+			"nameserver 8.8.8.8",
+			"nameserver 2001:4860:4860::8888",
+		},
+		nil,
+		true, false,
+	},
+	{
+		"ipv4.google.com",
+		[]string{
+			"domain golang.org",
+			"nameserver 2001:4860:4860::8888",
+			"nameserver 8.8.8.8",
+		},
+		nil,
+		true, false,
+	},
+	{
+		"ipv4.google.com",
+		[]string{
+			"search x.golang.org y.golang.org",
+			"nameserver 2001:4860:4860::8888",
+			"nameserver 8.8.8.8",
+		},
+		nil,
+		true, false,
+	},
+
+	// no A records, a few AAAA records
+	{
+		"ipv6.google.com.",
+		[]string{
+			"nameserver 2001:4860:4860::8888",
+			"nameserver 8.8.8.8",
+		},
+		nil,
+		false, true,
+	},
+	{
+		"ipv6.google.com",
+		[]string{
+			"domain golang.org",
+			"nameserver 8.8.8.8",
+			"nameserver 2001:4860:4860::8888",
+		},
+		nil,
+		false, true,
+	},
+	{
+		"ipv6.google.com",
+		[]string{
+			"search x.golang.org y.golang.org",
+			"nameserver 8.8.8.8",
+			"nameserver 2001:4860:4860::8888",
+		},
+		nil,
+		false, true,
+	},
+
+	// both A and AAAA records
+	{
+		"hostname.as112.net", // see RFC 7534
+		[]string{
+			"domain golang.org",
+			"nameserver 2001:4860:4860::8888",
+			"nameserver 8.8.8.8",
+		},
+		nil,
+		true, true,
+	},
+	{
+		"hostname.as112.net", // see RFC 7534
+		[]string{
+			"search x.golang.org y.golang.org",
+			"nameserver 2001:4860:4860::8888",
+			"nameserver 8.8.8.8",
+		},
+		nil,
+		true, true,
+	},
+}
+
+func TestGoLookupIPWithResolverConfig(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
+		t.Skip("avoid external network")
 	}
 
-	r := newResolvConfTest(t)
-	defer r.Close()
-
-	r.SetConf("nameserver 8.8.8.8")
-	r.Start()
-
-	if _, err := goLookupIP("golang.org"); err != nil {
-		t.Fatalf("goLookupIP(good) failed: %v", err)
+	conf, err := newResolvConfTest()
+	if err != nil {
+		t.Fatal(err)
 	}
-	r.WantServers([]string{"8.8.8.8"})
+	defer conf.teardown()
 
-	// Using a bad resolv.conf when we had a good one
-	// before should not update the config
-	r.SetConf("")
-	if _, err := goLookupIP("golang.org"); err != nil {
-		t.Fatalf("goLookupIP(good; bad) failed: %v", err)
+	for _, tt := range goLookupIPWithResolverConfigTests {
+		if err := conf.writeAndUpdate(tt.lines); err != nil {
+			t.Error(err)
+			continue
+		}
+		conf.tryUpdate(conf.path)
+		addrs, err := goLookupIP(tt.name)
+		if err != nil {
+			if err, ok := err.(*DNSError); !ok || (err.Name != tt.error.(*DNSError).Name || err.Server != tt.error.(*DNSError).Server || err.IsTimeout != tt.error.(*DNSError).IsTimeout) {
+				t.Errorf("got %v; want %v", err, tt.error)
+			}
+			continue
+		}
+		if len(addrs) == 0 {
+			t.Errorf("no records for %s", tt.name)
+		}
+		if !tt.a && !tt.aaaa && len(addrs) > 0 {
+			t.Errorf("unexpected %v for %s", addrs, tt.name)
+		}
+		for _, addr := range addrs {
+			if !tt.a && addr.IP.To4() != nil {
+				t.Errorf("got %v; must not be IPv4 address", addr)
+			}
+			if !tt.aaaa && addr.IP.To16() != nil && addr.IP.To4() == nil {
+				t.Errorf("got %v; must not be IPv6 address", addr)
+			}
+		}
 	}
-
-	// A new good config should get picked up
-	r.SetConf("nameserver 8.8.4.4")
-	r.WantServers([]string{"8.8.4.4"})
 }
 
 func BenchmarkGoLookupIP(b *testing.B) {
+	testHookUninstaller.Do(uninstallTestHooks)
+
 	for i := 0; i < b.N; i++ {
 		goLookupIP("www.example.com")
 	}
 }
 
 func BenchmarkGoLookupIPNoSuchHost(b *testing.B) {
+	testHookUninstaller.Do(uninstallTestHooks)
+
 	for i := 0; i < b.N; i++ {
 		goLookupIP("some.nonexistent")
 	}
 }
 
 func BenchmarkGoLookupIPWithBrokenNameServer(b *testing.B) {
-	onceLoadConfig.Do(loadDefaultConfig)
-	if cfg.dnserr != nil || cfg.dnsConfig == nil {
-		b.Fatalf("loadConfig failed: %v", cfg.dnserr)
-	}
-	// This looks ugly but it's safe as long as benchmarks are run
-	// sequentially in package testing.
-	orig := cfg.dnsConfig
-	cfg.dnsConfig.servers = append([]string{"203.0.113.254"}, cfg.dnsConfig.servers...) // use TEST-NET-3 block, see RFC 5737
+	testHookUninstaller.Do(uninstallTestHooks)
+
+	conf, err := newResolvConfTest()
+	if err != nil {
+		b.Fatal(err)
+	}
+	defer conf.teardown()
+
+	lines := []string{
+		"nameserver 203.0.113.254", // use TEST-NET-3 block, see RFC 5737
+		"nameserver 8.8.8.8",
+	}
+	if err := conf.writeAndUpdate(lines); err != nil {
+		b.Fatal(err)
+	}
+
 	for i := 0; i < b.N; i++ {
 		goLookupIP("www.example.com")
 	}
-	cfg.dnsConfig = orig
 }
diff --git a/src/net/dnsconfig_unix.go b/src/net/dnsconfig_unix.go
index 66ab7c4..6073fdb 100644
--- a/src/net/dnsconfig_unix.go
+++ b/src/net/dnsconfig_unix.go
@@ -8,30 +8,41 @@
 
 package net
 
+var defaultNS = []string{"127.0.0.1", "::1"}
+
 type dnsConfig struct {
-	servers  []string // servers to use
-	search   []string // suffixes to append to local name
-	ndots    int      // number of dots in name to trigger absolute lookup
-	timeout  int      // seconds before giving up on packet
-	attempts int      // lost packets before giving up on server
-	rotate   bool     // round robin among servers
+	servers    []string // servers to use
+	search     []string // suffixes to append to local name
+	ndots      int      // number of dots in name to trigger absolute lookup
+	timeout    int      // seconds before giving up on packet
+	attempts   int      // lost packets before giving up on server
+	rotate     bool     // round robin among servers
+	unknownOpt bool     // anything unknown was encountered
+	lookup     []string // OpenBSD top-level database "lookup" order
+	err        error    // any error that occurs during open of resolv.conf
 }
 
 // See resolv.conf(5) on a Linux machine.
 // TODO(rsc): Supposed to call uname() and chop the beginning
 // of the host name to get the default search domain.
-func dnsReadConfig(filename string) (*dnsConfig, error) {
-	file, err := open(filename)
-	if err != nil {
-		return nil, &DNSConfigError{err}
-	}
-	defer file.close()
+func dnsReadConfig(filename string) *dnsConfig {
 	conf := &dnsConfig{
 		ndots:    1,
 		timeout:  5,
 		attempts: 2,
 	}
+	file, err := open(filename)
+	if err != nil {
+		conf.servers = defaultNS
+		conf.err = err
+		return conf
+	}
+	defer file.close()
 	for line, ok := file.readLine(); ok; line, ok = file.readLine() {
+		if len(line) > 0 && (line[0] == ';' || line[0] == '#') {
+			// comment.
+			continue
+		}
 		f := getFields(line)
 		if len(f) < 1 {
 			continue
@@ -61,8 +72,7 @@ func dnsReadConfig(filename string) (*dnsConfig, error) {
 			}
 
 		case "options": // magic options
-			for i := 1; i < len(f); i++ {
-				s := f[i]
+			for _, s := range f[1:] {
 				switch {
 				case hasPrefix(s, "ndots:"):
 					n, _, _ := dtoi(s, 6)
@@ -84,11 +94,25 @@ func dnsReadConfig(filename string) (*dnsConfig, error) {
 					conf.attempts = n
 				case s == "rotate":
 					conf.rotate = true
+				default:
+					conf.unknownOpt = true
 				}
 			}
+
+		case "lookup":
+			// OpenBSD option:
+			// http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man5/resolv.conf.5
+			// "the legal space-separated values are: bind, file, yp"
+			conf.lookup = f[1:]
+
+		default:
+			conf.unknownOpt = true
 		}
 	}
-	return conf, nil
+	if len(conf.servers) == 0 {
+		conf.servers = defaultNS
+	}
+	return conf
 }
 
 func hasPrefix(s, prefix string) bool {
diff --git a/src/net/dnsconfig_unix_test.go b/src/net/dnsconfig_unix_test.go
index 94fb0c3..c8eed61 100644
--- a/src/net/dnsconfig_unix_test.go
+++ b/src/net/dnsconfig_unix_test.go
@@ -7,28 +7,30 @@
 package net
 
 import (
+	"os"
 	"reflect"
 	"testing"
 )
 
 var dnsReadConfigTests = []struct {
 	name string
-	conf dnsConfig
+	want *dnsConfig
 }{
 	{
 		name: "testdata/resolv.conf",
-		conf: dnsConfig{
-			servers:  []string{"8.8.8.8", "2001:4860:4860::8888", "fe80::1%lo0"},
-			search:   []string{"localdomain"},
-			ndots:    5,
-			timeout:  10,
-			attempts: 3,
-			rotate:   true,
+		want: &dnsConfig{
+			servers:    []string{"8.8.8.8", "2001:4860:4860::8888", "fe80::1%lo0"},
+			search:     []string{"localdomain"},
+			ndots:      5,
+			timeout:    10,
+			attempts:   3,
+			rotate:     true,
+			unknownOpt: true, // the "options attempts 3" line
 		},
 	},
 	{
 		name: "testdata/domain-resolv.conf",
-		conf: dnsConfig{
+		want: &dnsConfig{
 			servers:  []string{"8.8.8.8"},
 			search:   []string{"localdomain"},
 			ndots:    1,
@@ -38,7 +40,7 @@ var dnsReadConfigTests = []struct {
 	},
 	{
 		name: "testdata/search-resolv.conf",
-		conf: dnsConfig{
+		want: &dnsConfig{
 			servers:  []string{"8.8.8.8"},
 			search:   []string{"test", "invalid"},
 			ndots:    1,
@@ -48,22 +50,51 @@ var dnsReadConfigTests = []struct {
 	},
 	{
 		name: "testdata/empty-resolv.conf",
-		conf: dnsConfig{
+		want: &dnsConfig{
+			servers:  defaultNS,
+			ndots:    1,
+			timeout:  5,
+			attempts: 2,
+		},
+	},
+	{
+		name: "testdata/openbsd-resolv.conf",
+		want: &dnsConfig{
 			ndots:    1,
 			timeout:  5,
 			attempts: 2,
+			lookup:   []string{"file", "bind"},
+			servers:  []string{"169.254.169.254", "10.240.0.1"},
+			search:   []string{"c.symbolic-datum-552.internal."},
 		},
 	},
 }
 
 func TestDNSReadConfig(t *testing.T) {
 	for _, tt := range dnsReadConfigTests {
-		conf, err := dnsReadConfig(tt.name)
-		if err != nil {
-			t.Fatal(err)
+		conf := dnsReadConfig(tt.name)
+		if conf.err != nil {
+			t.Fatal(conf.err)
 		}
-		if !reflect.DeepEqual(conf, &tt.conf) {
-			t.Errorf("got %v; want %v", conf, &tt.conf)
+		if !reflect.DeepEqual(conf, tt.want) {
+			t.Errorf("%s:\ngot: %+v\nwant: %+v", tt.name, conf, tt.want)
 		}
 	}
 }
+
+func TestDNSReadMissingFile(t *testing.T) {
+	conf := dnsReadConfig("a-nonexistent-file")
+	if !os.IsNotExist(conf.err) {
+		t.Errorf("missing resolv.conf:\ngot: %v\nwant: %v", conf.err, os.ErrNotExist)
+	}
+	conf.err = nil
+	want := &dnsConfig{
+		servers:  defaultNS,
+		ndots:    1,
+		timeout:  5,
+		attempts: 2,
+	}
+	if !reflect.DeepEqual(conf, want) {
+		t.Errorf("missing resolv.conf:\ngot: %+v\nwant: %+v", conf, want)
+	}
+}
diff --git a/src/net/dnsmsg.go b/src/net/dnsmsg.go
index 161afb2..6ecaa94 100644
--- a/src/net/dnsmsg.go
+++ b/src/net/dnsmsg.go
@@ -306,7 +306,23 @@ func (rr *dnsRR_TXT) Header() *dnsRR_Header {
 }
 
 func (rr *dnsRR_TXT) Walk(f func(v interface{}, name, tag string) bool) bool {
-	return rr.Hdr.Walk(f) && f(&rr.Txt, "Txt", "")
+	if !rr.Hdr.Walk(f) {
+		return false
+	}
+	var n uint16 = 0
+	for n < rr.Hdr.Rdlength {
+		var txt string
+		if !f(&txt, "Txt", "") {
+			return false
+		}
+		// more bytes than rr.Hdr.Rdlength said there woudld be
+		if rr.Hdr.Rdlength-n < uint16(len(txt))+1 {
+			return false
+		}
+		n += uint16(len(txt)) + 1
+		rr.Txt += txt
+	}
+	return true
 }
 
 type dnsRR_SRV struct {
diff --git a/src/net/dnsmsg_test.go b/src/net/dnsmsg_test.go
index c39dbdb..1078d77 100644
--- a/src/net/dnsmsg_test.go
+++ b/src/net/dnsmsg_test.go
@@ -18,7 +18,7 @@ func TestDNSParseSRVReply(t *testing.T) {
 	msg := new(dnsMsg)
 	ok := msg.Unpack(data)
 	if !ok {
-		t.Fatalf("unpacking packet failed")
+		t.Fatal("unpacking packet failed")
 	}
 	msg.String() // exercise this code path
 	if g, e := len(msg.answer), 5; g != e {
@@ -32,13 +32,19 @@ func TestDNSParseSRVReply(t *testing.T) {
 			t.Errorf("answer[%d] = %T; want *dnsRR_SRV", idx, rr)
 		}
 	}
-	_, addrs, err := answer("_xmpp-server._tcp.google.com.", "foo:53", msg, uint16(dnsTypeSRV))
-	if err != nil {
-		t.Fatalf("answer: %v", err)
-	}
-	if g, e := len(addrs), 5; g != e {
-		t.Errorf("len(addrs) = %d; want %d", g, e)
-		t.Logf("addrs = %#v", addrs)
+	for _, name := range [...]string{
+		"_xmpp-server._tcp.google.com.",
+		"_XMPP-Server._TCP.Google.COM.",
+		"_XMPP-SERVER._TCP.GOOGLE.COM.",
+	} {
+		_, addrs, err := answer(name, "foo:53", msg, uint16(dnsTypeSRV))
+		if err != nil {
+			t.Error(err)
+		}
+		if g, e := len(addrs), 5; g != e {
+			t.Errorf("len(addrs) = %d; want %d", g, e)
+			t.Logf("addrs = %#v", addrs)
+		}
 	}
 	// repack and unpack.
 	data2, ok := msg.Pack()
@@ -46,9 +52,9 @@ func TestDNSParseSRVReply(t *testing.T) {
 	msg2.Unpack(data2)
 	switch {
 	case !ok:
-		t.Errorf("failed to repack message")
+		t.Error("failed to repack message")
 	case !reflect.DeepEqual(msg, msg2):
-		t.Errorf("repacked message differs from original")
+		t.Error("repacked message differs from original")
 	}
 }
 
@@ -60,7 +66,7 @@ func TestDNSParseCorruptSRVReply(t *testing.T) {
 	msg := new(dnsMsg)
 	ok := msg.Unpack(data)
 	if !ok {
-		t.Fatalf("unpacking packet failed")
+		t.Fatal("unpacking packet failed")
 	}
 	msg.String() // exercise this code path
 	if g, e := len(msg.answer), 5; g != e {
@@ -90,6 +96,93 @@ func TestDNSParseCorruptSRVReply(t *testing.T) {
 	}
 }
 
+func TestDNSParseTXTReply(t *testing.T) {
+	expectedTxt1 := "v=spf1 redirect=_spf.google.com"
+	expectedTxt2 := "v=spf1 ip4:69.63.179.25 ip4:69.63.178.128/25 ip4:69.63.184.0/25 " +
+		"ip4:66.220.144.128/25 ip4:66.220.155.0/24 " +
+		"ip4:69.171.232.0/25 ip4:66.220.157.0/25 " +
+		"ip4:69.171.244.0/24 mx -all"
+
+	replies := []string{dnsTXTReply1, dnsTXTReply2}
+	expectedTxts := []string{expectedTxt1, expectedTxt2}
+
+	for i := range replies {
+		data, err := hex.DecodeString(replies[i])
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		msg := new(dnsMsg)
+		ok := msg.Unpack(data)
+		if !ok {
+			t.Errorf("test %d: unpacking packet failed", i)
+			continue
+		}
+
+		if len(msg.answer) != 1 {
+			t.Errorf("test %d: len(rr.answer) = %d; want 1", i, len(msg.answer))
+			continue
+		}
+
+		rr := msg.answer[0]
+		rrTXT, ok := rr.(*dnsRR_TXT)
+		if !ok {
+			t.Errorf("test %d: answer[0] = %T; want *dnsRR_TXT", i, rr)
+			continue
+		}
+
+		if rrTXT.Txt != expectedTxts[i] {
+			t.Errorf("test %d: Txt = %s; want %s", i, rrTXT.Txt, expectedTxts[i])
+		}
+	}
+}
+
+func TestDNSParseTXTCorruptDataLengthReply(t *testing.T) {
+	replies := []string{dnsTXTCorruptDataLengthReply1, dnsTXTCorruptDataLengthReply2}
+
+	for i := range replies {
+		data, err := hex.DecodeString(replies[i])
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		msg := new(dnsMsg)
+		ok := msg.Unpack(data)
+		if ok {
+			t.Errorf("test %d: expected to fail on unpacking corrupt packet", i)
+		}
+	}
+}
+
+func TestDNSParseTXTCorruptTXTLengthReply(t *testing.T) {
+	replies := []string{dnsTXTCorruptTXTLengthReply1, dnsTXTCorruptTXTLengthReply2}
+
+	for i := range replies {
+		data, err := hex.DecodeString(replies[i])
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		msg := new(dnsMsg)
+		ok := msg.Unpack(data)
+		// Unpacking should succeed, but we should just get the header.
+		if !ok {
+			t.Errorf("test %d: unpacking packet failed", i)
+			continue
+		}
+
+		if len(msg.answer) != 1 {
+			t.Errorf("test %d: len(rr.answer) = %d; want 1", i, len(msg.answer))
+			continue
+		}
+
+		rr := msg.answer[0]
+		if _, justHeader := rr.(*dnsRR_Header); !justHeader {
+			t.Errorf("test %d: rr = %T; expected *dnsRR_Header", i, rr)
+		}
+	}
+}
+
 // Valid DNS SRV reply
 const dnsSRVReply = "0901818000010005000000000c5f786d70702d736572766572045f74637006676f6f67" +
 	"6c6503636f6d0000210001c00c002100010000012c00210014000014950c786d70702d" +
@@ -111,3 +204,63 @@ const dnsSRVCorruptReply = "0901818000010005000000000c5f786d70702d73657276657204
 	"6503636f6d00c00c002100010000012c00200005000014950b786d70702d7365727665" +
 	"72016c06676f6f676c6503636f6d00c00c002100010000012c00FF0014000014950c78" +
 	"6d70702d73657276657231016c06676f6f676c6503636f6d00"
+
+// TXT reply with one <character-string>
+const dnsTXTReply1 = "b3458180000100010004000505676d61696c03636f6d0000100001c00c001000010000012c00" +
+	"201f763d737066312072656469726563743d5f7370662e676f6f676c652e636f6dc00" +
+	"c0002000100025d4c000d036e733406676f6f676c65c012c00c0002000100025d4c00" +
+	"06036e7331c057c00c0002000100025d4c0006036e7333c057c00c0002000100025d4" +
+	"c0006036e7332c057c06c00010001000248b50004d8ef200ac09000010001000248b5" +
+	"0004d8ef220ac07e00010001000248b50004d8ef240ac05300010001000248b50004d" +
+	"8ef260a0000291000000000000000"
+
+// TXT reply with more than one <character-string>.
+// See https://tools.ietf.org/html/rfc1035#section-3.3.14
+const dnsTXTReply2 = "a0a381800001000100020002045f7370660866616365626f6f6b03636f6d0000100001c00c0010000" +
+	"100000e1000af7f763d73706631206970343a36392e36332e3137392e3235206970343a36392e" +
+	"36332e3137382e3132382f3235206970343a36392e36332e3138342e302f3235206970343a363" +
+	"62e3232302e3134342e3132382f3235206970343a36362e3232302e3135352e302f3234206970" +
+	"343a36392e3137312e3233322e302f323520692e70343a36362e3232302e3135372e302f32352" +
+	"06970343a36392e3137312e3234342e302f3234206d78202d616c6cc0110002000100025d1500" +
+	"070161026e73c011c0110002000100025d1500040162c0ecc0ea0001000100025d15000445abe" +
+	"f0cc0fd0001000100025d15000445abff0c"
+
+// DataLength field should be sum of all TXT fields. In this case it's less.
+const dnsTXTCorruptDataLengthReply1 = "a0a381800001000100020002045f7370660866616365626f6f6b03636f6d0000100001c00c0010000" +
+	"100000e1000967f763d73706631206970343a36392e36332e3137392e3235206970343a36392e" +
+	"36332e3137382e3132382f3235206970343a36392e36332e3138342e302f3235206970343a363" +
+	"62e3232302e3134342e3132382f3235206970343a36362e3232302e3135352e302f3234206970" +
+	"343a36392e3137312e3233322e302f323520692e70343a36362e3232302e3135372e302f32352" +
+	"06970343a36392e3137312e3234342e302f3234206d78202d616c6cc0110002000100025d1500" +
+	"070161026e73c011c0110002000100025d1500040162c0ecc0ea0001000100025d15000445abe" +
+	"f0cc0fd0001000100025d15000445abff0c"
+
+// Same as above but DataLength is more than sum of TXT fields.
+const dnsTXTCorruptDataLengthReply2 = "a0a381800001000100020002045f7370660866616365626f6f6b03636f6d0000100001c00c0010000" +
+	"100000e1001227f763d73706631206970343a36392e36332e3137392e3235206970343a36392e" +
+	"36332e3137382e3132382f3235206970343a36392e36332e3138342e302f3235206970343a363" +
+	"62e3232302e3134342e3132382f3235206970343a36362e3232302e3135352e302f3234206970" +
+	"343a36392e3137312e3233322e302f323520692e70343a36362e3232302e3135372e302f32352" +
+	"06970343a36392e3137312e3234342e302f3234206d78202d616c6cc0110002000100025d1500" +
+	"070161026e73c011c0110002000100025d1500040162c0ecc0ea0001000100025d15000445abe" +
+	"f0cc0fd0001000100025d15000445abff0c"
+
+// TXT Length field is less than actual length.
+const dnsTXTCorruptTXTLengthReply1 = "a0a381800001000100020002045f7370660866616365626f6f6b03636f6d0000100001c00c0010000" +
+	"100000e1000af7f763d73706631206970343a36392e36332e3137392e3235206970343a36392e" +
+	"36332e3137382e3132382f3235206970343a36392e36332e3138342e302f3235206970343a363" +
+	"62e3232302e3134342e3132382f3235206970343a36362e3232302e3135352e302f3234206970" +
+	"343a36392e3137312e3233322e302f323520691470343a36362e3232302e3135372e302f32352" +
+	"06970343a36392e3137312e3234342e302f3234206d78202d616c6cc0110002000100025d1500" +
+	"070161026e73c011c0110002000100025d1500040162c0ecc0ea0001000100025d15000445abe" +
+	"f0cc0fd0001000100025d15000445abff0c"
+
+// TXT Length field is more than actual length.
+const dnsTXTCorruptTXTLengthReply2 = "a0a381800001000100020002045f7370660866616365626f6f6b03636f6d0000100001c00c0010000" +
+	"100000e1000af7f763d73706631206970343a36392e36332e3137392e3235206970343a36392e" +
+	"36332e3137382e3132382f3235206970343a36392e36332e3138342e302f3235206970343a363" +
+	"62e3232302e3134342e3132382f3235206970343a36362e3232302e3135352e302f3234206970" +
+	"343a36392e3137312e3233322e302f323520693370343a36362e3232302e3135372e302f32352" +
+	"06970343a36392e3137312e3234342e302f3234206d78202d616c6cc0110002000100025d1500" +
+	"070161026e73c011c0110002000100025d1500040162c0ecc0ea0001000100025d15000445abe" +
+	"f0cc0fd0001000100025d15000445abff0c"
diff --git a/src/net/dnsname_test.go b/src/net/dnsname_test.go
index 57dd25f..be07dc6 100644
--- a/src/net/dnsname_test.go
+++ b/src/net/dnsname_test.go
@@ -9,12 +9,12 @@ import (
 	"testing"
 )
 
-type testCase struct {
+type dnsNameTest struct {
 	name   string
 	result bool
 }
 
-var tests = []testCase{
+var dnsNameTests = []dnsNameTest{
 	// RFC2181, section 11.
 	{"_xmpp-server._tcp.google.com", true},
 	{"foo.com", true},
@@ -30,7 +30,7 @@ var tests = []testCase{
 	{"b.com.", true},
 }
 
-func getTestCases(ch chan<- testCase) {
+func emitDNSNameTest(ch chan<- dnsNameTest) {
 	defer close(ch)
 	var char59 = ""
 	var char63 = ""
@@ -41,35 +41,36 @@ func getTestCases(ch chan<- testCase) {
 	char63 = char59 + "aaaa"
 	char64 = char63 + "a"
 
-	for _, tc := range tests {
+	for _, tc := range dnsNameTests {
 		ch <- tc
 	}
 
-	ch <- testCase{char63 + ".com", true}
-	ch <- testCase{char64 + ".com", false}
+	ch <- dnsNameTest{char63 + ".com", true}
+	ch <- dnsNameTest{char64 + ".com", false}
 	// 255 char name is fine:
-	ch <- testCase{char59 + "." + char63 + "." + char63 + "." +
+	ch <- dnsNameTest{char59 + "." + char63 + "." + char63 + "." +
 		char63 + ".com",
 		true}
 	// 256 char name is bad:
-	ch <- testCase{char59 + "a." + char63 + "." + char63 + "." +
+	ch <- dnsNameTest{char59 + "a." + char63 + "." + char63 + "." +
 		char63 + ".com",
 		false}
 }
 
-func TestDNSNames(t *testing.T) {
-	ch := make(chan testCase)
-	go getTestCases(ch)
+func TestDNSName(t *testing.T) {
+	ch := make(chan dnsNameTest)
+	go emitDNSNameTest(ch)
 	for tc := range ch {
 		if isDomainName(tc.name) != tc.result {
-			t.Errorf("isDomainName(%v) failed: Should be %v",
-				tc.name, tc.result)
+			t.Errorf("isDomainName(%q) = %v; want %v", tc.name, !tc.result, tc.result)
 		}
 	}
 }
 
-func BenchmarkDNSNames(b *testing.B) {
-	benchmarks := append(tests, []testCase{
+func BenchmarkDNSName(b *testing.B) {
+	testHookUninstaller.Do(uninstallTestHooks)
+
+	benchmarks := append(dnsNameTests, []dnsNameTest{
 		{strings.Repeat("a", 63), true},
 		{strings.Repeat("a", 64), false},
 	}...)
diff --git a/src/net/error_plan9_test.go b/src/net/error_plan9_test.go
new file mode 100644
index 0000000..495ea96
--- /dev/null
+++ b/src/net/error_plan9_test.go
@@ -0,0 +1,17 @@
+// 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 (
+	errTimedout       = syscall.ETIMEDOUT
+	errOpNotSupported = syscall.EPLAN9
+)
+
+func isPlatformError(err error) bool {
+	_, ok := err.(syscall.ErrorString)
+	return ok
+}
diff --git a/src/net/error_posix_test.go b/src/net/error_posix_test.go
new file mode 100644
index 0000000..981cc83
--- /dev/null
+++ b/src/net/error_posix_test.go
@@ -0,0 +1,44 @@
+// 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 net
+
+import (
+	"os"
+	"syscall"
+	"testing"
+)
+
+var (
+	errTimedout       = syscall.ETIMEDOUT
+	errOpNotSupported = syscall.EOPNOTSUPP
+)
+
+func isPlatformError(err error) bool {
+	_, ok := err.(syscall.Errno)
+	return ok
+}
+
+func TestSpuriousENOTAVAIL(t *testing.T) {
+	for _, tt := range []struct {
+		error
+		ok bool
+	}{
+		{syscall.EADDRNOTAVAIL, true},
+		{&os.SyscallError{Syscall: "syscall", Err: syscall.EADDRNOTAVAIL}, true},
+		{&OpError{Op: "op", Err: syscall.EADDRNOTAVAIL}, true},
+		{&OpError{Op: "op", Err: &os.SyscallError{Syscall: "syscall", Err: syscall.EADDRNOTAVAIL}}, true},
+
+		{syscall.EINVAL, false},
+		{&os.SyscallError{Syscall: "syscall", Err: syscall.EINVAL}, false},
+		{&OpError{Op: "op", Err: syscall.EINVAL}, false},
+		{&OpError{Op: "op", Err: &os.SyscallError{Syscall: "syscall", Err: syscall.EINVAL}}, false},
+	} {
+		if ok := spuriousENOTAVAIL(tt.error); ok != tt.ok {
+			t.Errorf("spuriousENOTAVAIL(%v) = %v; want %v", tt.error, ok, tt.ok)
+		}
+	}
+}
diff --git a/src/net/error_test.go b/src/net/error_test.go
new file mode 100644
index 0000000..bf95ff6
--- /dev/null
+++ b/src/net/error_test.go
@@ -0,0 +1,673 @@
+// 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"
+	"io"
+	"io/ioutil"
+	"net/internal/socktest"
+	"os"
+	"runtime"
+	"testing"
+	"time"
+)
+
+func (e *OpError) isValid() error {
+	if e.Op == "" {
+		return fmt.Errorf("OpError.Op is empty: %v", e)
+	}
+	if e.Net == "" {
+		return fmt.Errorf("OpError.Net is empty: %v", e)
+	}
+	for _, addr := range []Addr{e.Source, e.Addr} {
+		switch addr := addr.(type) {
+		case nil:
+		case *TCPAddr:
+			if addr == nil {
+				return fmt.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr, e)
+			}
+		case *UDPAddr:
+			if addr == nil {
+				return fmt.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr, e)
+			}
+		case *IPAddr:
+			if addr == nil {
+				return fmt.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr, e)
+			}
+		case *IPNet:
+			if addr == nil {
+				return fmt.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr, e)
+			}
+		case *UnixAddr:
+			if addr == nil {
+				return fmt.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr, e)
+			}
+		case *pipeAddr:
+			if addr == nil {
+				return fmt.Errorf("OpError.Source or Addr is non-nil interface: %#v, %v", addr, e)
+			}
+		case fileAddr:
+			if addr == "" {
+				return fmt.Errorf("OpError.Source or Addr is empty: %#v, %v", addr, e)
+			}
+		default:
+			return fmt.Errorf("OpError.Source or Addr is unknown type: %T, %v", addr, e)
+		}
+	}
+	if e.Err == nil {
+		return fmt.Errorf("OpError.Err is empty: %v", e)
+	}
+	return nil
+}
+
+// parseDialError parses nestedErr and reports whether it is a valid
+// error value from Dial, Listen functions.
+// It returns nil when nestedErr is valid.
+func parseDialError(nestedErr error) error {
+	if nestedErr == nil {
+		return nil
+	}
+
+	switch err := nestedErr.(type) {
+	case *OpError:
+		if err := err.isValid(); err != nil {
+			return err
+		}
+		nestedErr = err.Err
+		goto second
+	}
+	return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr)
+
+second:
+	if isPlatformError(nestedErr) {
+		return nil
+	}
+	switch err := nestedErr.(type) {
+	case *AddrError, addrinfoErrno, *DNSError, InvalidAddrError, *ParseError, *timeoutError, UnknownNetworkError:
+		return nil
+	case *os.SyscallError:
+		nestedErr = err.Err
+		goto third
+	}
+	switch nestedErr {
+	case errClosing, errMissingAddress:
+		return nil
+	}
+	return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
+
+third:
+	if isPlatformError(nestedErr) {
+		return nil
+	}
+	return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr)
+}
+
+var dialErrorTests = []struct {
+	network, address string
+}{
+	{"foo", ""},
+	{"bar", "baz"},
+	{"datakit", "mh/astro/r70"},
+	{"tcp", ""},
+	{"tcp", "127.0.0.1:☺"},
+	{"tcp", "no-such-name:80"},
+	{"tcp", "mh/astro/r70:http"},
+
+	{"tcp", "127.0.0.1:0"},
+	{"udp", "127.0.0.1:0"},
+	{"ip:icmp", "127.0.0.1"},
+
+	{"unix", "/path/to/somewhere"},
+	{"unixgram", "/path/to/somewhere"},
+	{"unixpacket", "/path/to/somewhere"},
+}
+
+func TestDialError(t *testing.T) {
+	switch runtime.GOOS {
+	case "plan9":
+		t.Skipf("%s does not have full support of socktest", runtime.GOOS)
+	}
+
+	origTestHookLookupIP := testHookLookupIP
+	defer func() { testHookLookupIP = origTestHookLookupIP }()
+	testHookLookupIP = func(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, error) {
+		return nil, &DNSError{Err: "dial error test", Name: "name", Server: "server", IsTimeout: true}
+	}
+	sw.Set(socktest.FilterConnect, func(so *socktest.Status) (socktest.AfterFilter, error) {
+		return nil, errOpNotSupported
+	})
+	defer sw.Set(socktest.FilterConnect, nil)
+
+	d := Dialer{Timeout: someTimeout}
+	for i, tt := range dialErrorTests {
+		c, err := d.Dial(tt.network, tt.address)
+		if err == nil {
+			t.Errorf("#%d: should fail; %s:%s->%s", i, tt.network, c.LocalAddr(), c.RemoteAddr())
+			c.Close()
+			continue
+		}
+		if c != nil {
+			t.Errorf("Dial returned non-nil interface %T(%v) with err != nil", c, c)
+		}
+		if err = parseDialError(err); err != nil {
+			t.Errorf("#%d: %v", i, err)
+			continue
+		}
+	}
+}
+
+func TestProtocolDialError(t *testing.T) {
+	switch runtime.GOOS {
+	case "nacl", "solaris":
+		t.Skipf("not supported on %s", runtime.GOOS)
+	}
+
+	for _, network := range []string{"tcp", "udp", "ip:4294967296", "unix", "unixpacket", "unixgram"} {
+		var err error
+		switch network {
+		case "tcp":
+			_, err = DialTCP(network, nil, &TCPAddr{Port: 1 << 16})
+		case "udp":
+			_, err = DialUDP(network, nil, &UDPAddr{Port: 1 << 16})
+		case "ip:4294967296":
+			_, err = DialIP(network, nil, nil)
+		case "unix", "unixpacket", "unixgram":
+			_, err = DialUnix(network, nil, &UnixAddr{Name: "//"})
+		}
+		if err == nil {
+			t.Errorf("%s: should fail", network)
+			continue
+		}
+		if err = parseDialError(err); err != nil {
+			t.Errorf("%s: %v", network, err)
+			continue
+		}
+	}
+}
+
+var listenErrorTests = []struct {
+	network, address string
+}{
+	{"foo", ""},
+	{"bar", "baz"},
+	{"datakit", "mh/astro/r70"},
+	{"tcp", "127.0.0.1:☺"},
+	{"tcp", "no-such-name:80"},
+	{"tcp", "mh/astro/r70:http"},
+
+	{"tcp", "127.0.0.1:0"},
+
+	{"unix", "/path/to/somewhere"},
+	{"unixpacket", "/path/to/somewhere"},
+}
+
+func TestListenError(t *testing.T) {
+	switch runtime.GOOS {
+	case "plan9":
+		t.Skipf("%s does not have full support of socktest", runtime.GOOS)
+	}
+
+	origTestHookLookupIP := testHookLookupIP
+	defer func() { testHookLookupIP = origTestHookLookupIP }()
+	testHookLookupIP = func(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, error) {
+		return nil, &DNSError{Err: "listen error test", Name: "name", Server: "server", IsTimeout: true}
+	}
+	sw.Set(socktest.FilterListen, func(so *socktest.Status) (socktest.AfterFilter, error) {
+		return nil, errOpNotSupported
+	})
+	defer sw.Set(socktest.FilterListen, nil)
+
+	for i, tt := range listenErrorTests {
+		ln, err := Listen(tt.network, tt.address)
+		if err == nil {
+			t.Errorf("#%d: should fail; %s:%s->", i, tt.network, ln.Addr())
+			ln.Close()
+			continue
+		}
+		if ln != nil {
+			t.Errorf("Listen returned non-nil interface %T(%v) with err != nil", ln, ln)
+		}
+		if err = parseDialError(err); err != nil {
+			t.Errorf("#%d: %v", i, err)
+			continue
+		}
+	}
+}
+
+var listenPacketErrorTests = []struct {
+	network, address string
+}{
+	{"foo", ""},
+	{"bar", "baz"},
+	{"datakit", "mh/astro/r70"},
+	{"udp", "127.0.0.1:☺"},
+	{"udp", "no-such-name:80"},
+	{"udp", "mh/astro/r70:http"},
+}
+
+func TestListenPacketError(t *testing.T) {
+	switch runtime.GOOS {
+	case "plan9":
+		t.Skipf("%s does not have full support of socktest", runtime.GOOS)
+	}
+
+	origTestHookLookupIP := testHookLookupIP
+	defer func() { testHookLookupIP = origTestHookLookupIP }()
+	testHookLookupIP = func(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, error) {
+		return nil, &DNSError{Err: "listen error test", Name: "name", Server: "server", IsTimeout: true}
+	}
+
+	for i, tt := range listenPacketErrorTests {
+		c, err := ListenPacket(tt.network, tt.address)
+		if err == nil {
+			t.Errorf("#%d: should fail; %s:%s->", i, tt.network, c.LocalAddr())
+			c.Close()
+			continue
+		}
+		if c != nil {
+			t.Errorf("ListenPacket returned non-nil interface %T(%v) with err != nil", c, c)
+		}
+		if err = parseDialError(err); err != nil {
+			t.Errorf("#%d: %v", i, err)
+			continue
+		}
+	}
+}
+
+func TestProtocolListenError(t *testing.T) {
+	switch runtime.GOOS {
+	case "nacl", "plan9":
+		t.Skipf("not supported on %s", runtime.GOOS)
+	}
+
+	for _, network := range []string{"tcp", "udp", "ip:4294967296", "unix", "unixpacket", "unixgram"} {
+		var err error
+		switch network {
+		case "tcp":
+			_, err = ListenTCP(network, &TCPAddr{Port: 1 << 16})
+		case "udp":
+			_, err = ListenUDP(network, &UDPAddr{Port: 1 << 16})
+		case "ip:4294967296":
+			_, err = ListenIP(network, nil)
+		case "unix", "unixpacket":
+			_, err = ListenUnix(network, &UnixAddr{Name: "//"})
+		case "unixgram":
+			_, err = ListenUnixgram(network, &UnixAddr{Name: "//"})
+		}
+		if err == nil {
+			t.Errorf("%s: should fail", network)
+			continue
+		}
+		if err = parseDialError(err); err != nil {
+			t.Errorf("%s: %v", network, err)
+			continue
+		}
+	}
+}
+
+// parseReadError parses nestedErr and reports whether it is a valid
+// error value from Read functions.
+// It returns nil when nestedErr is valid.
+func parseReadError(nestedErr error) error {
+	if nestedErr == nil {
+		return nil
+	}
+
+	switch err := nestedErr.(type) {
+	case *OpError:
+		if err := err.isValid(); err != nil {
+			return err
+		}
+		nestedErr = err.Err
+		goto second
+	}
+	if nestedErr == io.EOF {
+		return nil
+	}
+	return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr)
+
+second:
+	if isPlatformError(nestedErr) {
+		return nil
+	}
+	switch err := nestedErr.(type) {
+	case *os.SyscallError:
+		nestedErr = err.Err
+		goto third
+	}
+	switch nestedErr {
+	case errClosing, errTimeout:
+		return nil
+	}
+	return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
+
+third:
+	if isPlatformError(nestedErr) {
+		return nil
+	}
+	return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr)
+}
+
+// parseWriteError parses nestedErr and reports whether it is a valid
+// error value from Write functions.
+// It returns nil when nestedErr is valid.
+func parseWriteError(nestedErr error) error {
+	if nestedErr == nil {
+		return nil
+	}
+
+	switch err := nestedErr.(type) {
+	case *OpError:
+		if err := err.isValid(); err != nil {
+			return err
+		}
+		nestedErr = err.Err
+		goto second
+	}
+	return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr)
+
+second:
+	if isPlatformError(nestedErr) {
+		return nil
+	}
+	switch err := nestedErr.(type) {
+	case *AddrError, addrinfoErrno, *DNSError, InvalidAddrError, *ParseError, *timeoutError, UnknownNetworkError:
+		return nil
+	case *os.SyscallError:
+		nestedErr = err.Err
+		goto third
+	}
+	switch nestedErr {
+	case errClosing, errTimeout, ErrWriteToConnected, io.ErrUnexpectedEOF:
+		return nil
+	}
+	return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
+
+third:
+	if isPlatformError(nestedErr) {
+		return nil
+	}
+	return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr)
+}
+
+// parseCloseError parses nestedErr and reports whether it is a valid
+// error value from Close functions.
+// It returns nil when nestedErr is valid.
+func parseCloseError(nestedErr error) error {
+	if nestedErr == nil {
+		return nil
+	}
+
+	switch err := nestedErr.(type) {
+	case *OpError:
+		if err := err.isValid(); err != nil {
+			return err
+		}
+		nestedErr = err.Err
+		goto second
+	}
+	return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr)
+
+second:
+	if isPlatformError(nestedErr) {
+		return nil
+	}
+	switch err := nestedErr.(type) {
+	case *os.SyscallError:
+		nestedErr = err.Err
+		goto third
+	case *os.PathError: // for Plan 9
+		nestedErr = err.Err
+		goto third
+	}
+	switch nestedErr {
+	case errClosing:
+		return nil
+	}
+	return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
+
+third:
+	if isPlatformError(nestedErr) {
+		return nil
+	}
+	return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr)
+}
+
+func TestCloseError(t *testing.T) {
+	ln, err := newLocalListener("tcp")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer ln.Close()
+	c, err := Dial(ln.Addr().Network(), ln.Addr().String())
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer c.Close()
+
+	for i := 0; i < 3; i++ {
+		err = c.(*TCPConn).CloseRead()
+		if perr := parseCloseError(err); perr != nil {
+			t.Errorf("#%d: %v", i, perr)
+		}
+	}
+	for i := 0; i < 3; i++ {
+		err = c.(*TCPConn).CloseWrite()
+		if perr := parseCloseError(err); perr != nil {
+			t.Errorf("#%d: %v", i, perr)
+		}
+	}
+	for i := 0; i < 3; i++ {
+		err = c.Close()
+		if perr := parseCloseError(err); perr != nil {
+			t.Errorf("#%d: %v", i, perr)
+		}
+		err = ln.Close()
+		if perr := parseCloseError(err); perr != nil {
+			t.Errorf("#%d: %v", i, perr)
+		}
+	}
+
+	pc, err := ListenPacket("udp", "127.0.0.1:0")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer pc.Close()
+
+	for i := 0; i < 3; i++ {
+		err = pc.Close()
+		if perr := parseCloseError(err); perr != nil {
+			t.Errorf("#%d: %v", i, perr)
+		}
+	}
+}
+
+// parseAcceptError parses nestedErr and reports whether it is a valid
+// error value from Accept functions.
+// It returns nil when nestedErr is valid.
+func parseAcceptError(nestedErr error) error {
+	if nestedErr == nil {
+		return nil
+	}
+
+	switch err := nestedErr.(type) {
+	case *OpError:
+		if err := err.isValid(); err != nil {
+			return err
+		}
+		nestedErr = err.Err
+		goto second
+	}
+	return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr)
+
+second:
+	if isPlatformError(nestedErr) {
+		return nil
+	}
+	switch err := nestedErr.(type) {
+	case *os.SyscallError:
+		nestedErr = err.Err
+		goto third
+	}
+	switch nestedErr {
+	case errClosing, errTimeout:
+		return nil
+	}
+	return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
+
+third:
+	if isPlatformError(nestedErr) {
+		return nil
+	}
+	return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr)
+}
+
+func TestAcceptError(t *testing.T) {
+	handler := func(ls *localServer, ln Listener) {
+		for {
+			ln.(*TCPListener).SetDeadline(time.Now().Add(5 * time.Millisecond))
+			c, err := ln.Accept()
+			if perr := parseAcceptError(err); perr != nil {
+				t.Error(perr)
+			}
+			if err != nil {
+				if c != nil {
+					t.Errorf("Accept returned non-nil interface %T(%v) with err != nil", c, c)
+				}
+				if nerr, ok := err.(Error); !ok || (!nerr.Timeout() && !nerr.Temporary()) {
+					return
+				}
+				continue
+			}
+			c.Close()
+		}
+	}
+	ls, err := newLocalServer("tcp")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if err := ls.buildup(handler); err != nil {
+		ls.teardown()
+		t.Fatal(err)
+	}
+
+	time.Sleep(100 * time.Millisecond)
+	ls.teardown()
+}
+
+// parseCommonError parses nestedErr and reports whether it is a valid
+// error value from miscellaneous functions.
+// It returns nil when nestedErr is valid.
+func parseCommonError(nestedErr error) error {
+	if nestedErr == nil {
+		return nil
+	}
+
+	switch err := nestedErr.(type) {
+	case *OpError:
+		if err := err.isValid(); err != nil {
+			return err
+		}
+		nestedErr = err.Err
+		goto second
+	}
+	return fmt.Errorf("unexpected type on 1st nested level: %T", nestedErr)
+
+second:
+	if isPlatformError(nestedErr) {
+		return nil
+	}
+	switch err := nestedErr.(type) {
+	case *os.SyscallError:
+		nestedErr = err.Err
+		goto third
+	case *os.LinkError:
+		nestedErr = err.Err
+		goto third
+	case *os.PathError:
+		nestedErr = err.Err
+		goto third
+	}
+	switch nestedErr {
+	case errClosing:
+		return nil
+	}
+	return fmt.Errorf("unexpected type on 2nd nested level: %T", nestedErr)
+
+third:
+	if isPlatformError(nestedErr) {
+		return nil
+	}
+	return fmt.Errorf("unexpected type on 3rd nested level: %T", nestedErr)
+}
+
+func TestFileError(t *testing.T) {
+	switch runtime.GOOS {
+	case "windows":
+		t.Skipf("not supported on %s", runtime.GOOS)
+	}
+
+	f, err := ioutil.TempFile("", "go-nettest")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.Remove(f.Name())
+	defer f.Close()
+
+	c, err := FileConn(f)
+	if err != nil {
+		if c != nil {
+			t.Errorf("FileConn returned non-nil interface %T(%v) with err != nil", c, c)
+		}
+		if perr := parseCommonError(err); perr != nil {
+			t.Error(perr)
+		}
+	} else {
+		c.Close()
+		t.Error("should fail")
+	}
+	ln, err := FileListener(f)
+	if err != nil {
+		if ln != nil {
+			t.Errorf("FileListener returned non-nil interface %T(%v) with err != nil", ln, ln)
+		}
+		if perr := parseCommonError(err); perr != nil {
+			t.Error(perr)
+		}
+	} else {
+		ln.Close()
+		t.Error("should fail")
+	}
+	pc, err := FilePacketConn(f)
+	if err != nil {
+		if pc != nil {
+			t.Errorf("FilePacketConn returned non-nil interface %T(%v) with err != nil", pc, pc)
+		}
+		if perr := parseCommonError(err); perr != nil {
+			t.Error(perr)
+		}
+	} else {
+		pc.Close()
+		t.Error("should fail")
+	}
+
+	ln, err = newLocalListener("tcp")
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	for i := 0; i < 3; i++ {
+		f, err := ln.(*TCPListener).File()
+		if err != nil {
+			if perr := parseCommonError(err); perr != nil {
+				t.Error(perr)
+			}
+		} else {
+			f.Close()
+		}
+		ln.Close()
+	}
+}
diff --git a/src/net/external_test.go b/src/net/external_test.go
new file mode 100644
index 0000000..d5ff2be
--- /dev/null
+++ b/src/net/external_test.go
@@ -0,0 +1,167 @@
+// 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 net
+
+import (
+	"fmt"
+	"io"
+	"strings"
+	"testing"
+)
+
+func TestResolveGoogle(t *testing.T) {
+	if testing.Short() || !*testExternal {
+		t.Skip("avoid external network")
+	}
+	if !supportsIPv4 || !supportsIPv6 || !*testIPv4 || !*testIPv6 {
+		t.Skip("both IPv4 and IPv6 are required")
+	}
+
+	for _, network := range []string{"tcp", "tcp4", "tcp6"} {
+		addr, err := ResolveTCPAddr(network, "www.google.com:http")
+		if err != nil {
+			t.Error(err)
+			continue
+		}
+		switch {
+		case network == "tcp" && addr.IP.To4() == nil:
+			fallthrough
+		case network == "tcp4" && addr.IP.To4() == nil:
+			t.Errorf("got %v; want an IPv4 address on %s", addr, network)
+		case network == "tcp6" && (addr.IP.To16() == nil || addr.IP.To4() != nil):
+			t.Errorf("got %v; want an IPv6 address on %s", addr, network)
+		}
+	}
+}
+
+var dialGoogleTests = []struct {
+	dial               func(string, string) (Conn, error)
+	unreachableNetwork string
+	networks           []string
+	addrs              []string
+}{
+	{
+		dial:     (&Dialer{DualStack: true}).Dial,
+		networks: []string{"tcp", "tcp4", "tcp6"},
+		addrs:    []string{"www.google.com:http"},
+	},
+	{
+		dial:               Dial,
+		unreachableNetwork: "tcp6",
+		networks:           []string{"tcp", "tcp4"},
+	},
+	{
+		dial:               Dial,
+		unreachableNetwork: "tcp4",
+		networks:           []string{"tcp", "tcp6"},
+	},
+}
+
+func TestDialGoogle(t *testing.T) {
+	if testing.Short() || !*testExternal {
+		t.Skip("avoid external network")
+	}
+	if !supportsIPv4 || !supportsIPv6 || !*testIPv4 || !*testIPv6 {
+		t.Skip("both IPv4 and IPv6 are required")
+	}
+
+	var err error
+	dialGoogleTests[1].addrs, dialGoogleTests[2].addrs, err = googleLiteralAddrs()
+	if err != nil {
+		t.Error(err)
+	}
+	for _, tt := range dialGoogleTests {
+		for _, network := range tt.networks {
+			disableSocketConnect(tt.unreachableNetwork)
+			for _, addr := range tt.addrs {
+				if err := fetchGoogle(tt.dial, network, addr); err != nil {
+					t.Error(err)
+				}
+			}
+			enableSocketConnect()
+		}
+	}
+}
+
+var (
+	literalAddrs4 = [...]string{
+		"%d.%d.%d.%d:80",
+		"www.google.com:80",
+		"%d.%d.%d.%d:http",
+		"www.google.com:http",
+		"%03d.%03d.%03d.%03d:0080",
+		"[::ffff:%d.%d.%d.%d]:80",
+		"[::ffff:%02x%02x:%02x%02x]:80",
+		"[0:0:0:0:0000:ffff:%d.%d.%d.%d]:80",
+		"[0:0:0:0:000000:ffff:%d.%d.%d.%d]:80",
+		"[0:0:0:0::ffff:%d.%d.%d.%d]:80",
+	}
+	literalAddrs6 = [...]string{
+		"[%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:80",
+		"ipv6.google.com:80",
+		"[%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:http",
+		"ipv6.google.com:http",
+	}
+)
+
+func googleLiteralAddrs() (lits4, lits6 []string, err error) {
+	ips, err := LookupIP("www.google.com")
+	if err != nil {
+		return nil, nil, err
+	}
+	if len(ips) == 0 {
+		return nil, nil, nil
+	}
+	var ip4, ip6 IP
+	for _, ip := range ips {
+		if ip4 == nil && ip.To4() != nil {
+			ip4 = ip.To4()
+		}
+		if ip6 == nil && ip.To16() != nil && ip.To4() == nil {
+			ip6 = ip.To16()
+		}
+		if ip4 != nil && ip6 != nil {
+			break
+		}
+	}
+	if ip4 != nil {
+		for i, lit4 := range literalAddrs4 {
+			if strings.Contains(lit4, "%") {
+				literalAddrs4[i] = fmt.Sprintf(lit4, ip4[0], ip4[1], ip4[2], ip4[3])
+			}
+		}
+		lits4 = literalAddrs4[:]
+	}
+	if ip6 != nil {
+		for i, lit6 := range literalAddrs6 {
+			if strings.Contains(lit6, "%") {
+				literalAddrs6[i] = fmt.Sprintf(lit6, ip6[0], ip6[1], ip6[2], ip6[3], ip6[4], ip6[5], ip6[6], ip6[7], ip6[8], ip6[9], ip6[10], ip6[11], ip6[12], ip6[13], ip6[14], ip6[15])
+			}
+		}
+		lits6 = literalAddrs6[:]
+	}
+	return
+}
+
+func fetchGoogle(dial func(string, string) (Conn, error), network, address string) error {
+	c, err := dial(network, address)
+	if err != nil {
+		return err
+	}
+	defer c.Close()
+	req := []byte("GET /robots.txt HTTP/1.0\r\nHost: www.google.com\r\n\r\n")
+	if _, err := c.Write(req); err != nil {
+		return err
+	}
+	b := make([]byte, 1000)
+	n, err := io.ReadFull(c, b)
+	if err != nil {
+		return err
+	}
+	if n < 1000 {
+		return fmt.Errorf("short read from %s:%s->%s", network, c.RemoteAddr(), c.LocalAddr())
+	}
+	return nil
+}
diff --git a/src/net/fd_plan9.go b/src/net/fd_plan9.go
index 5fe8eff..32766f5 100644
--- a/src/net/fd_plan9.go
+++ b/src/net/fd_plan9.go
@@ -11,13 +11,13 @@ import (
 	"time"
 )
 
-// Network file descritor.
+// Network file descriptor.
 type netFD struct {
 	// locking/lifetime of sysfd + serialize access to Read and Write methods
 	fdmu fdMutex
 
 	// immutable until Close
-	proto        string
+	net          string
 	n            string
 	dir          string
 	ctl, data    *os.File
@@ -38,8 +38,8 @@ func dial(net string, ra Addr, dialer func(time.Time) (Conn, error), deadline ti
 	return dialChannel(net, ra, dialer, deadline)
 }
 
-func newFD(proto, name string, ctl, data *os.File, laddr, raddr Addr) (*netFD, error) {
-	return &netFD{proto: proto, n: name, dir: netdir + "/" + proto + "/" + name, ctl: ctl, data: data, laddr: laddr, raddr: raddr}, nil
+func newFD(net, name string, ctl, data *os.File, laddr, raddr Addr) (*netFD, error) {
+	return &netFD{net: net, n: name, dir: netdir + "/" + net + "/" + name, ctl: ctl, data: data, laddr: laddr, raddr: raddr}, nil
 }
 
 func (fd *netFD) init() error {
@@ -55,7 +55,7 @@ func (fd *netFD) name() string {
 	if fd.raddr != nil {
 		rs = fd.raddr.String()
 	}
-	return fd.proto + ":" + ls + "->" + rs
+	return fd.net + ":" + ls + "->" + rs
 }
 
 func (fd *netFD) ok() bool { return fd != nil && fd.ctl != nil }
@@ -132,7 +132,7 @@ func (fd *netFD) Read(b []byte) (n int, err error) {
 	}
 	defer fd.readUnlock()
 	n, err = fd.data.Read(b)
-	if fd.proto == "udp" && err == io.EOF {
+	if fd.net == "udp" && err == io.EOF {
 		n = 0
 		err = nil
 	}
@@ -202,7 +202,7 @@ func (fd *netFD) file(f *os.File, s string) (*os.File, error) {
 	dfd, err := syscall.Dup(int(f.Fd()), -1)
 	syscall.ForkLock.RUnlock()
 	if err != nil {
-		return nil, &OpError{"dup", s, fd.laddr, err}
+		return nil, os.NewSyscallError("dup", err)
 	}
 	return os.NewFile(uintptr(dfd), s), nil
 }
@@ -226,7 +226,3 @@ func setReadBuffer(fd *netFD, bytes int) error {
 func setWriteBuffer(fd *netFD, bytes int) error {
 	return syscall.EPLAN9
 }
-
-func skipRawSocketTests() (skip bool, skipmsg string, err error) {
-	return true, "skipping test on plan9", nil
-}
diff --git a/src/net/fd_poll_nacl.go b/src/net/fd_poll_nacl.go
index a3701f8..cdf14e3 100644
--- a/src/net/fd_poll_nacl.go
+++ b/src/net/fd_poll_nacl.go
@@ -18,18 +18,11 @@ func (pd *pollDesc) Init(fd *netFD) error { pd.fd = fd; return nil }
 
 func (pd *pollDesc) Close() {}
 
-func (pd *pollDesc) Lock() {}
-
-func (pd *pollDesc) Unlock() {}
-
-func (pd *pollDesc) Wakeup() {}
-
-func (pd *pollDesc) Evict() bool {
+func (pd *pollDesc) Evict() {
 	pd.closing = true
 	if pd.fd != nil {
 		syscall.StopIO(pd.fd.sysfd)
 	}
-	return false
 }
 
 func (pd *pollDesc) Prepare(mode int) error {
diff --git a/src/net/fd_poll_runtime.go b/src/net/fd_poll_runtime.go
index 2bddc83..8522cce 100644
--- a/src/net/fd_poll_runtime.go
+++ b/src/net/fd_poll_runtime.go
@@ -48,23 +48,12 @@ func (pd *pollDesc) Close() {
 	pd.runtimeCtx = 0
 }
 
-func (pd *pollDesc) Lock() {
-}
-
-func (pd *pollDesc) Unlock() {
-}
-
-func (pd *pollDesc) Wakeup() {
-}
-
 // Evict evicts fd from the pending list, unblocking any I/O running on fd.
-// Return value is whether the pollServer should be woken up.
-func (pd *pollDesc) Evict() bool {
+func (pd *pollDesc) Evict() {
 	if pd.runtimeCtx == 0 {
-		return false
+		return
 	}
 	runtime_pollUnblock(pd.runtimeCtx)
-	return false
 }
 
 func (pd *pollDesc) Prepare(mode int) error {
diff --git a/src/net/fd_posix.go b/src/net/fd_posix.go
new file mode 100644
index 0000000..b4b908a
--- /dev/null
+++ b/src/net/fd_posix.go
@@ -0,0 +1,21 @@
+// 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.
+
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
+
+package net
+
+import (
+	"io"
+	"syscall"
+)
+
+// eofError returns io.EOF when fd is available for reading end of
+// file.
+func (fd *netFD) eofError(n int, err error) error {
+	if n == 0 && err == nil && fd.sotype != syscall.SOCK_DGRAM && fd.sotype != syscall.SOCK_RAW {
+		return io.EOF
+	}
+	return err
+}
diff --git a/src/net/fd_posix_test.go b/src/net/fd_posix_test.go
new file mode 100644
index 0000000..85711ef
--- /dev/null
+++ b/src/net/fd_posix_test.go
@@ -0,0 +1,57 @@
+// 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.
+
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
+
+package net
+
+import (
+	"io"
+	"syscall"
+	"testing"
+)
+
+var eofErrorTests = []struct {
+	n        int
+	err      error
+	fd       *netFD
+	expected error
+}{
+	{100, nil, &netFD{sotype: syscall.SOCK_STREAM}, nil},
+	{100, io.EOF, &netFD{sotype: syscall.SOCK_STREAM}, io.EOF},
+	{100, errClosing, &netFD{sotype: syscall.SOCK_STREAM}, errClosing},
+	{0, nil, &netFD{sotype: syscall.SOCK_STREAM}, io.EOF},
+	{0, io.EOF, &netFD{sotype: syscall.SOCK_STREAM}, io.EOF},
+	{0, errClosing, &netFD{sotype: syscall.SOCK_STREAM}, errClosing},
+
+	{100, nil, &netFD{sotype: syscall.SOCK_DGRAM}, nil},
+	{100, io.EOF, &netFD{sotype: syscall.SOCK_DGRAM}, io.EOF},
+	{100, errClosing, &netFD{sotype: syscall.SOCK_DGRAM}, errClosing},
+	{0, nil, &netFD{sotype: syscall.SOCK_DGRAM}, nil},
+	{0, io.EOF, &netFD{sotype: syscall.SOCK_DGRAM}, io.EOF},
+	{0, errClosing, &netFD{sotype: syscall.SOCK_DGRAM}, errClosing},
+
+	{100, nil, &netFD{sotype: syscall.SOCK_SEQPACKET}, nil},
+	{100, io.EOF, &netFD{sotype: syscall.SOCK_SEQPACKET}, io.EOF},
+	{100, errClosing, &netFD{sotype: syscall.SOCK_SEQPACKET}, errClosing},
+	{0, nil, &netFD{sotype: syscall.SOCK_SEQPACKET}, io.EOF},
+	{0, io.EOF, &netFD{sotype: syscall.SOCK_SEQPACKET}, io.EOF},
+	{0, errClosing, &netFD{sotype: syscall.SOCK_SEQPACKET}, errClosing},
+
+	{100, nil, &netFD{sotype: syscall.SOCK_RAW}, nil},
+	{100, io.EOF, &netFD{sotype: syscall.SOCK_RAW}, io.EOF},
+	{100, errClosing, &netFD{sotype: syscall.SOCK_RAW}, errClosing},
+	{0, nil, &netFD{sotype: syscall.SOCK_RAW}, nil},
+	{0, io.EOF, &netFD{sotype: syscall.SOCK_RAW}, io.EOF},
+	{0, errClosing, &netFD{sotype: syscall.SOCK_RAW}, errClosing},
+}
+
+func TestEOFError(t *testing.T) {
+	for _, tt := range eofErrorTests {
+		actual := tt.fd.eofError(tt.n, tt.err)
+		if actual != tt.expected {
+			t.Errorf("eofError(%v, %v, %v): expected %v, actual %v", tt.n, tt.err, tt.fd.sotype, tt.expected, actual)
+		}
+	}
+}
diff --git a/src/net/fd_unix.go b/src/net/fd_unix.go
index 7fa43f6..6463b0d 100644
--- a/src/net/fd_unix.go
+++ b/src/net/fd_unix.go
@@ -72,7 +72,7 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time) error {
 	// 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()) {
@@ -87,13 +87,13 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time) error {
 		// already been accepted and closed by the server.
 		// Treat this as a successful connection--writes to
 		// the socket will see EOF.  For details and a test
-		// case in C see http://golang.org/issue/6828.
+		// case in C see https://golang.org/issue/6828.
 		if runtime.GOOS == "solaris" {
 			return nil
 		}
 		fallthrough
 	default:
-		return err
+		return os.NewSyscallError("connect", err)
 	}
 	if err := fd.init(); err != nil {
 		return err
@@ -114,25 +114,25 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time) error {
 		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
+			return os.NewSyscallError("getsockopt", err)
 		}
 		switch err := syscall.Errno(nerr); err {
 		case syscall.EINPROGRESS, syscall.EALREADY, syscall.EINTR:
 		case syscall.Errno(0), syscall.EISCONN:
 			return nil
 		default:
-			return err
+			return os.NewSyscallError("getsockopt", err)
 		}
 	}
 }
 
 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)
 }
@@ -187,9 +187,7 @@ func (fd *netFD) writeUnlock() {
 }
 
 func (fd *netFD) Close() error {
-	fd.pd.Lock() // needed for both fd.incref(true) and pollDesc.Evict
 	if !fd.fdmu.IncrefAndClose() {
-		fd.pd.Unlock()
 		return errClosing
 	}
 	// Unblock any I/O.  Once it all unblocks and returns,
@@ -197,12 +195,8 @@ func (fd *netFD) Close() error {
 	// the final decref will close fd.sysfd.  This should happen
 	// fairly quickly, since all the I/O is non-blocking, and any
 	// attempts to block in the pollDesc will return errClosing.
-	doWakeup := fd.pd.Evict()
-	fd.pd.Unlock()
+	fd.pd.Evict()
 	fd.decref()
-	if doWakeup {
-		fd.pd.Wakeup()
-	}
 	return nil
 }
 
@@ -211,11 +205,7 @@ func (fd *netFD) shutdown(how int) error {
 		return err
 	}
 	defer fd.decref()
-	err := syscall.Shutdown(fd.sysfd, how)
-	if err != nil {
-		return &OpError{"shutdown", fd.net, fd.laddr, err}
-	}
-	return nil
+	return os.NewSyscallError("shutdown", syscall.Shutdown(fd.sysfd, how))
 }
 
 func (fd *netFD) closeRead() error {
@@ -232,10 +222,10 @@ func (fd *netFD) Read(p []byte) (n int, err error) {
 	}
 	defer fd.readUnlock()
 	if err := fd.pd.PrepareRead(); err != nil {
-		return 0, &OpError{"read", fd.net, fd.raddr, err}
+		return 0, err
 	}
 	for {
-		n, err = syscall.Read(int(fd.sysfd), p)
+		n, err = syscall.Read(fd.sysfd, p)
 		if err != nil {
 			n = 0
 			if err == syscall.EAGAIN {
@@ -244,11 +234,11 @@ func (fd *netFD) Read(p []byte) (n int, err error) {
 				}
 			}
 		}
-		err = chkReadErr(n, err, fd)
+		err = fd.eofError(n, err)
 		break
 	}
-	if err != nil && err != io.EOF {
-		err = &OpError{"read", fd.net, fd.raddr, err}
+	if _, ok := err.(syscall.Errno); ok {
+		err = os.NewSyscallError("read", err)
 	}
 	return
 }
@@ -259,7 +249,7 @@ func (fd *netFD) readFrom(p []byte) (n int, sa syscall.Sockaddr, err error) {
 	}
 	defer fd.readUnlock()
 	if err := fd.pd.PrepareRead(); err != nil {
-		return 0, nil, &OpError{"read", fd.net, fd.laddr, err}
+		return 0, nil, err
 	}
 	for {
 		n, sa, err = syscall.Recvfrom(fd.sysfd, p, 0)
@@ -271,11 +261,11 @@ func (fd *netFD) readFrom(p []byte) (n int, sa syscall.Sockaddr, err error) {
 				}
 			}
 		}
-		err = chkReadErr(n, err, fd)
+		err = fd.eofError(n, err)
 		break
 	}
-	if err != nil && err != io.EOF {
-		err = &OpError{"read", fd.net, fd.laddr, err}
+	if _, ok := err.(syscall.Errno); ok {
+		err = os.NewSyscallError("recvfrom", err)
 	}
 	return
 }
@@ -286,7 +276,7 @@ func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.S
 	}
 	defer fd.readUnlock()
 	if err := fd.pd.PrepareRead(); err != nil {
-		return 0, 0, 0, nil, &OpError{"read", fd.net, fd.laddr, err}
+		return 0, 0, 0, nil, err
 	}
 	for {
 		n, oobn, flags, sa, err = syscall.Recvmsg(fd.sysfd, p, oob, 0)
@@ -298,33 +288,26 @@ func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.S
 				}
 			}
 		}
-		err = chkReadErr(n, err, fd)
+		err = fd.eofError(n, err)
 		break
 	}
-	if err != nil && err != io.EOF {
-		err = &OpError{"read", fd.net, fd.laddr, err}
+	if _, ok := err.(syscall.Errno); ok {
+		err = os.NewSyscallError("recvmsg", err)
 	}
 	return
 }
 
-func chkReadErr(n int, err error, fd *netFD) error {
-	if n == 0 && err == nil && fd.sotype != syscall.SOCK_DGRAM && fd.sotype != syscall.SOCK_RAW {
-		return io.EOF
-	}
-	return err
-}
-
 func (fd *netFD) Write(p []byte) (nn int, err error) {
 	if err := fd.writeLock(); err != nil {
 		return 0, err
 	}
 	defer fd.writeUnlock()
 	if err := fd.pd.PrepareWrite(); err != nil {
-		return 0, &OpError{"write", fd.net, fd.raddr, err}
+		return 0, err
 	}
 	for {
 		var n int
-		n, err = syscall.Write(int(fd.sysfd), p[nn:])
+		n, err = syscall.Write(fd.sysfd, p[nn:])
 		if n > 0 {
 			nn += n
 		}
@@ -337,7 +320,6 @@ func (fd *netFD) Write(p []byte) (nn int, err error) {
 			}
 		}
 		if err != nil {
-			n = 0
 			break
 		}
 		if n == 0 {
@@ -345,8 +327,8 @@ func (fd *netFD) Write(p []byte) (nn int, err error) {
 			break
 		}
 	}
-	if err != nil {
-		err = &OpError{"write", fd.net, fd.raddr, err}
+	if _, ok := err.(syscall.Errno); ok {
+		err = os.NewSyscallError("write", err)
 	}
 	return nn, err
 }
@@ -357,7 +339,7 @@ func (fd *netFD) writeTo(p []byte, sa syscall.Sockaddr) (n int, err error) {
 	}
 	defer fd.writeUnlock()
 	if err := fd.pd.PrepareWrite(); err != nil {
-		return 0, &OpError{"write", fd.net, fd.raddr, err}
+		return 0, err
 	}
 	for {
 		err = syscall.Sendto(fd.sysfd, p, 0, sa)
@@ -370,8 +352,9 @@ func (fd *netFD) writeTo(p []byte, sa syscall.Sockaddr) (n int, err error) {
 	}
 	if err == nil {
 		n = len(p)
-	} else {
-		err = &OpError{"write", fd.net, fd.raddr, err}
+	}
+	if _, ok := err.(syscall.Errno); ok {
+		err = os.NewSyscallError("sendto", err)
 	}
 	return
 }
@@ -382,7 +365,7 @@ func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oob
 	}
 	defer fd.writeUnlock()
 	if err := fd.pd.PrepareWrite(); err != nil {
-		return 0, 0, &OpError{"write", fd.net, fd.raddr, err}
+		return 0, 0, err
 	}
 	for {
 		n, err = syscall.SendmsgN(fd.sysfd, p, oob, sa, 0)
@@ -395,8 +378,9 @@ func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oob
 	}
 	if err == nil {
 		oobn = len(oob)
-	} else {
-		err = &OpError{"write", fd.net, fd.raddr, err}
+	}
+	if _, ok := err.(syscall.Errno); ok {
+		err = os.NewSyscallError("sendmsg", err)
 	}
 	return
 }
@@ -410,27 +394,34 @@ func (fd *netFD) accept() (netfd *netFD, err error) {
 	var s int
 	var rsa syscall.Sockaddr
 	if err = fd.pd.PrepareRead(); err != nil {
-		return nil, &OpError{"accept", fd.net, fd.laddr, err}
+		return nil, err
 	}
 	for {
 		s, rsa, err = accept(fd.sysfd)
 		if err != nil {
-			if err == syscall.EAGAIN {
+			nerr, ok := err.(*os.SyscallError)
+			if !ok {
+				return nil, err
+			}
+			switch nerr.Err {
+			case syscall.EAGAIN:
 				if err = fd.pd.WaitRead(); err == nil {
 					continue
 				}
-			} else if err == syscall.ECONNABORTED {
-				// This means that a socket on the listen queue was closed
-				// before we Accept()ed it; it's a silly error, so try again.
+			case syscall.ECONNABORTED:
+				// This means that a socket on the
+				// listen queue was closed before we
+				// Accept()ed it; it's a silly error,
+				// so try again.
 				continue
 			}
-			return nil, &OpError{"accept", fd.net, fd.laddr, err}
+			return nil, err
 		}
 		break
 	}
 
 	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 {
@@ -470,7 +461,7 @@ func dupCloseOnExec(fd int) (newfd int, err error) {
 			// from now on.
 			atomic.StoreInt32(&tryDupCloexec, 0)
 		default:
-			return -1, e1
+			return -1, os.NewSyscallError("fcntl", e1)
 		}
 	}
 	return dupCloseOnExecOld(fd)
@@ -483,7 +474,7 @@ func dupCloseOnExecOld(fd int) (newfd int, err error) {
 	defer syscall.ForkLock.RUnlock()
 	newfd, err = syscall.Dup(fd)
 	if err != nil {
-		return -1, err
+		return -1, os.NewSyscallError("dup", err)
 	}
 	syscall.CloseOnExec(newfd)
 	return
@@ -492,7 +483,7 @@ func dupCloseOnExecOld(fd int) (newfd int, err error) {
 func (fd *netFD) dup() (f *os.File, err error) {
 	ns, err := dupCloseOnExec(fd.sysfd)
 	if err != nil {
-		return nil, &OpError{"dup", fd.net, fd.laddr, err}
+		return nil, err
 	}
 
 	// We want blocking mode for the new fd, hence the double negative.
@@ -500,19 +491,8 @@ func (fd *netFD) dup() (f *os.File, err error) {
 	// I/O will block the thread instead of letting us use the epoll server.
 	// Everything will still work, just with more threads.
 	if err = syscall.SetNonblock(ns, false); err != nil {
-		return nil, &OpError{"setnonblock", fd.net, fd.laddr, err}
+		return nil, os.NewSyscallError("setnonblock", err)
 	}
 
 	return os.NewFile(uintptr(ns), fd.name()), nil
 }
-
-func closesocket(s int) error {
-	return syscall.Close(s)
-}
-
-func skipRawSocketTests() (skip bool, skipmsg string, err error) {
-	if os.Getuid() != 0 {
-		return true, "skipping test; must be root", nil
-	}
-	return false, "", nil
-}
diff --git a/src/net/fd_unix_test.go b/src/net/fd_unix_test.go
deleted file mode 100644
index fe8e8ff..0000000
--- a/src/net/fd_unix_test.go
+++ /dev/null
@@ -1,58 +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.
-
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
-
-package net
-
-import (
-	"io"
-	"syscall"
-	"testing"
-)
-
-var chkReadErrTests = []struct {
-	n        int
-	err      error
-	fd       *netFD
-	expected error
-}{
-
-	{100, nil, &netFD{sotype: syscall.SOCK_STREAM}, nil},
-	{100, io.EOF, &netFD{sotype: syscall.SOCK_STREAM}, io.EOF},
-	{100, errClosing, &netFD{sotype: syscall.SOCK_STREAM}, errClosing},
-	{0, nil, &netFD{sotype: syscall.SOCK_STREAM}, io.EOF},
-	{0, io.EOF, &netFD{sotype: syscall.SOCK_STREAM}, io.EOF},
-	{0, errClosing, &netFD{sotype: syscall.SOCK_STREAM}, errClosing},
-
-	{100, nil, &netFD{sotype: syscall.SOCK_DGRAM}, nil},
-	{100, io.EOF, &netFD{sotype: syscall.SOCK_DGRAM}, io.EOF},
-	{100, errClosing, &netFD{sotype: syscall.SOCK_DGRAM}, errClosing},
-	{0, nil, &netFD{sotype: syscall.SOCK_DGRAM}, nil},
-	{0, io.EOF, &netFD{sotype: syscall.SOCK_DGRAM}, io.EOF},
-	{0, errClosing, &netFD{sotype: syscall.SOCK_DGRAM}, errClosing},
-
-	{100, nil, &netFD{sotype: syscall.SOCK_SEQPACKET}, nil},
-	{100, io.EOF, &netFD{sotype: syscall.SOCK_SEQPACKET}, io.EOF},
-	{100, errClosing, &netFD{sotype: syscall.SOCK_SEQPACKET}, errClosing},
-	{0, nil, &netFD{sotype: syscall.SOCK_SEQPACKET}, io.EOF},
-	{0, io.EOF, &netFD{sotype: syscall.SOCK_SEQPACKET}, io.EOF},
-	{0, errClosing, &netFD{sotype: syscall.SOCK_SEQPACKET}, errClosing},
-
-	{100, nil, &netFD{sotype: syscall.SOCK_RAW}, nil},
-	{100, io.EOF, &netFD{sotype: syscall.SOCK_RAW}, io.EOF},
-	{100, errClosing, &netFD{sotype: syscall.SOCK_RAW}, errClosing},
-	{0, nil, &netFD{sotype: syscall.SOCK_RAW}, nil},
-	{0, io.EOF, &netFD{sotype: syscall.SOCK_RAW}, io.EOF},
-	{0, errClosing, &netFD{sotype: syscall.SOCK_RAW}, errClosing},
-}
-
-func TestChkReadErr(t *testing.T) {
-	for _, tt := range chkReadErrTests {
-		actual := chkReadErr(tt.n, tt.err, tt.fd)
-		if actual != tt.expected {
-			t.Errorf("chkReadError(%v, %v, %v): expected %v, actual %v", tt.n, tt.err, tt.fd.sotype, tt.expected, actual)
-		}
-	}
-}
diff --git a/src/net/fd_windows.go b/src/net/fd_windows.go
index f3a534a..205daff 100644
--- a/src/net/fd_windows.go
+++ b/src/net/fd_windows.go
@@ -5,8 +5,6 @@
 package net
 
 import (
-	"errors"
-	"io"
 	"os"
 	"runtime"
 	"sync"
@@ -40,7 +38,7 @@ func sysInit() {
 	var d syscall.WSAData
 	e := syscall.WSAStartup(uint32(0x202), &d)
 	if e != nil {
-		initErr = os.NewSyscallError("WSAStartup", e)
+		initErr = os.NewSyscallError("wsastartup", e)
 	}
 	canCancelIO = syscall.LoadCancelIoEx() == nil
 	if syscall.LoadGetAddrInfo() == nil {
@@ -70,10 +68,6 @@ func sysInit() {
 	}
 }
 
-func closesocket(s syscall.Handle) error {
-	return syscall.Closesocket(s)
-}
-
 func canUseConnectEx(net string) bool {
 	switch net {
 	case "udp", "udp4", "udp6", "ip", "ip4", "ip6":
@@ -159,7 +153,7 @@ func (s *ioSrv) ExecIO(o *operation, name string, submit func(o *operation) erro
 	// Notify runtime netpoll about starting IO.
 	err := fd.pd.Prepare(int(o.mode))
 	if err != nil {
-		return 0, &OpError{name, fd.net, fd.laddr, err}
+		return 0, err
 	}
 	// Start IO.
 	if canCancelIO {
@@ -182,7 +176,7 @@ func (s *ioSrv) ExecIO(o *operation, name string, submit func(o *operation) erro
 		// IO started, and we have to wait for its completion.
 		err = nil
 	default:
-		return 0, &OpError{name, fd.net, fd.laddr, err}
+		return 0, err
 	}
 	// Wait for our request to complete.
 	err = fd.pd.Wait(int(o.mode))
@@ -190,7 +184,7 @@ func (s *ioSrv) ExecIO(o *operation, name string, submit func(o *operation) erro
 		// All is good. Extract our IO results and return.
 		if o.errno != 0 {
 			err = syscall.Errno(o.errno)
-			return 0, &OpError{name, fd.net, fd.laddr, err}
+			return 0, err
 		}
 		return int(o.qty), nil
 	}
@@ -221,7 +215,7 @@ func (s *ioSrv) ExecIO(o *operation, name string, submit func(o *operation) erro
 		if err == syscall.ERROR_OPERATION_ABORTED { // IO Canceled
 			err = netpollErr
 		}
-		return 0, &OpError{name, fd.net, fd.laddr, err}
+		return 0, err
 	}
 	// We issued cancellation request. But, it seems, IO operation succeeded
 	// before cancellation request run. We need to treat IO operation as
@@ -303,7 +297,7 @@ func (fd *netFD) init() error {
 		size := uint32(unsafe.Sizeof(flag))
 		err := syscall.WSAIoctl(fd.sysfd, syscall.SIO_UDP_CONNRESET, (*byte)(unsafe.Pointer(&flag)), size, nil, 0, &ret, nil, 0)
 		if err != nil {
-			return os.NewSyscallError("WSAIoctl", err)
+			return os.NewSyscallError("wsaioctl", err)
 		}
 	}
 	fd.rop.mode = 'r'
@@ -337,7 +331,7 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time) error {
 		defer fd.setWriteDeadline(noDeadline)
 	}
 	if !canUseConnectEx(fd.net) {
-		return syscall.Connect(fd.sysfd, ra)
+		return os.NewSyscallError("connect", connectFunc(fd.sysfd, ra))
 	}
 	// ConnectEx windows API requires an unconnected, previously bound socket.
 	if la == nil {
@@ -350,20 +344,23 @@ func (fd *netFD) connect(la, ra syscall.Sockaddr, deadline time.Time) error {
 			panic("unexpected type in connect")
 		}
 		if err := syscall.Bind(fd.sysfd, la); err != nil {
-			return err
+			return os.NewSyscallError("bind", err)
 		}
 	}
 	// Call ConnectEx API.
 	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 {
+		if _, ok := err.(syscall.Errno); ok {
+			err = os.NewSyscallError("connectex", err)
+		}
 		return err
 	}
 	// Refresh socket properties.
-	return syscall.Setsockopt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_UPDATE_CONNECT_CONTEXT, (*byte)(unsafe.Pointer(&fd.sysfd)), int32(unsafe.Sizeof(fd.sysfd)))
+	return os.NewSyscallError("setsockopt", syscall.Setsockopt(fd.sysfd, syscall.SOL_SOCKET, syscall.SO_UPDATE_CONNECT_CONTEXT, (*byte)(unsafe.Pointer(&fd.sysfd)), int32(unsafe.Sizeof(fd.sysfd))))
 }
 
 func (fd *netFD) destroy() {
@@ -371,9 +368,9 @@ func (fd *netFD) destroy() {
 		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)
@@ -443,11 +440,7 @@ func (fd *netFD) shutdown(how int) error {
 		return err
 	}
 	defer fd.decref()
-	err := syscall.Shutdown(fd.sysfd, how)
-	if err != nil {
-		return &OpError{"shutdown", fd.net, fd.laddr, err}
-	}
-	return nil
+	return syscall.Shutdown(fd.sysfd, how)
 }
 
 func (fd *netFD) closeRead() error {
@@ -468,16 +461,17 @@ func (fd *netFD) Read(buf []byte) (int, error) {
 	n, err := rsrv.ExecIO(o, "WSARecv", func(o *operation) error {
 		return syscall.WSARecv(o.fd.sysfd, &o.buf, 1, &o.qty, &o.flags, &o.o, nil)
 	})
-	if err == nil && n == 0 {
-		err = io.EOF
-	}
 	if raceenabled {
 		raceAcquire(unsafe.Pointer(&ioSync))
 	}
+	err = fd.eofError(n, err)
+	if _, ok := err.(syscall.Errno); ok {
+		err = os.NewSyscallError("wsarecv", err)
+	}
 	return n, err
 }
 
-func (fd *netFD) readFrom(buf []byte) (n int, sa syscall.Sockaddr, err error) {
+func (fd *netFD) readFrom(buf []byte) (int, syscall.Sockaddr, error) {
 	if len(buf) == 0 {
 		return 0, nil, nil
 	}
@@ -487,18 +481,22 @@ func (fd *netFD) readFrom(buf []byte) (n int, sa syscall.Sockaddr, err error) {
 	defer fd.readUnlock()
 	o := &fd.rop
 	o.InitBuf(buf)
-	n, err = rsrv.ExecIO(o, "WSARecvFrom", func(o *operation) error {
+	n, err := rsrv.ExecIO(o, "WSARecvFrom", func(o *operation) error {
 		if o.rsa == nil {
 			o.rsa = new(syscall.RawSockaddrAny)
 		}
 		o.rsan = int32(unsafe.Sizeof(*o.rsa))
 		return syscall.WSARecvFrom(o.fd.sysfd, &o.buf, 1, &o.qty, &o.flags, o.rsa, &o.rsan, &o.o, nil)
 	})
+	err = fd.eofError(n, err)
+	if _, ok := err.(syscall.Errno); ok {
+		err = os.NewSyscallError("wsarecvfrom", err)
+	}
 	if err != nil {
-		return 0, nil, err
+		return n, nil, err
 	}
-	sa, _ = o.rsa.Sockaddr()
-	return
+	sa, _ := o.rsa.Sockaddr()
+	return n, sa, nil
 }
 
 func (fd *netFD) Write(buf []byte) (int, error) {
@@ -511,9 +509,13 @@ func (fd *netFD) Write(buf []byte) (int, error) {
 	}
 	o := &fd.wop
 	o.InitBuf(buf)
-	return wsrv.ExecIO(o, "WSASend", func(o *operation) error {
+	n, err := wsrv.ExecIO(o, "WSASend", func(o *operation) error {
 		return syscall.WSASend(o.fd.sysfd, &o.buf, 1, &o.qty, 0, &o.o, nil)
 	})
+	if _, ok := err.(syscall.Errno); ok {
+		err = os.NewSyscallError("wsasend", err)
+	}
+	return n, err
 }
 
 func (fd *netFD) writeTo(buf []byte, sa syscall.Sockaddr) (int, error) {
@@ -527,23 +529,27 @@ func (fd *netFD) writeTo(buf []byte, sa syscall.Sockaddr) (int, error) {
 	o := &fd.wop
 	o.InitBuf(buf)
 	o.sa = sa
-	return wsrv.ExecIO(o, "WSASendto", func(o *operation) error {
+	n, err := wsrv.ExecIO(o, "WSASendto", func(o *operation) error {
 		return syscall.WSASendto(o.fd.sysfd, &o.buf, 1, &o.qty, 0, o.sa, &o.o, nil)
 	})
+	if _, ok := err.(syscall.Errno); ok {
+		err = os.NewSyscallError("wsasendto", err)
+	}
+	return n, err
 }
 
 func (fd *netFD) acceptOne(rawsa []syscall.RawSockaddrAny, o *operation) (*netFD, error) {
 	// Get new socket.
 	s, err := sysSocket(fd.family, fd.sotype, 0)
 	if err != nil {
-		return nil, &OpError{"socket", fd.net, fd.laddr, err}
+		return nil, err
 	}
 
 	// Associate our new socket with IOCP.
 	netfd, err := newFD(s, fd.family, fd.sotype, fd.net)
 	if err != nil {
-		closesocket(s)
-		return nil, &OpError{"accept", fd.net, fd.laddr, err}
+		closeFunc(s)
+		return nil, err
 	}
 	if err := netfd.init(); err != nil {
 		fd.Close()
@@ -558,6 +564,9 @@ func (fd *netFD) acceptOne(rawsa []syscall.RawSockaddrAny, o *operation) (*netFD
 	})
 	if err != nil {
 		netfd.Close()
+		if _, ok := err.(syscall.Errno); ok {
+			err = os.NewSyscallError("acceptex", err)
+		}
 		return nil, err
 	}
 
@@ -565,7 +574,7 @@ func (fd *netFD) acceptOne(rawsa []syscall.RawSockaddrAny, o *operation) (*netFD
 	err = syscall.Setsockopt(s, syscall.SOL_SOCKET, syscall.SO_UPDATE_ACCEPT_CONTEXT, (*byte)(unsafe.Pointer(&fd.sysfd)), int32(unsafe.Sizeof(fd.sysfd)))
 	if err != nil {
 		netfd.Close()
-		return nil, &OpError{"Setsockopt", fd.net, fd.laddr, err}
+		return nil, os.NewSyscallError("setsockopt", err)
 	}
 
 	return netfd, nil
@@ -591,11 +600,11 @@ func (fd *netFD) accept() (*netFD, error) {
 		// before AcceptEx could complete. These errors relate to new
 		// connection, not to AcceptEx, so ignore broken connection and
 		// try AcceptEx again for more connections.
-		operr, ok := err.(*OpError)
+		nerr, ok := err.(*os.SyscallError)
 		if !ok {
 			return nil, err
 		}
-		errno, ok := operr.Err.(syscall.Errno)
+		errno, ok := nerr.Err.(syscall.Errno)
 		if !ok {
 			return nil, err
 		}
@@ -619,38 +628,17 @@ func (fd *netFD) accept() (*netFD, error) {
 	return netfd, nil
 }
 
-func skipRawSocketTests() (skip bool, skipmsg string, err error) {
-	// From http://msdn.microsoft.com/en-us/library/windows/desktop/ms740548.aspx:
-	// Note: To use a socket of type SOCK_RAW requires administrative privileges.
-	// Users running Winsock applications that use raw sockets must be a member of
-	// the Administrators group on the local computer, otherwise raw socket calls
-	// will fail with an error code of WSAEACCES. On Windows Vista and later, access
-	// for raw sockets is enforced at socket creation. In earlier versions of Windows,
-	// access for raw sockets is enforced during other socket operations.
-	s, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, 0)
-	if err == syscall.WSAEACCES {
-		return true, "skipping test; no access to raw socket allowed", nil
-	}
-	if err != nil {
-		return true, "", err
-	}
-	defer syscall.Closesocket(s)
-	return false, "", nil
-}
-
 // Unimplemented functions.
 
 func (fd *netFD) dup() (*os.File, error) {
 	// TODO: Implement this
-	return nil, os.NewSyscallError("dup", syscall.EWINDOWS)
+	return nil, syscall.EWINDOWS
 }
 
-var errNoSupport = errors.New("address family not supported")
-
 func (fd *netFD) readMsg(p []byte, oob []byte) (n, oobn, flags int, sa syscall.Sockaddr, err error) {
-	return 0, 0, 0, nil, errNoSupport
+	return 0, 0, 0, nil, syscall.EWINDOWS
 }
 
 func (fd *netFD) writeMsg(p []byte, oob []byte, sa syscall.Sockaddr) (n int, oobn int, err error) {
-	return 0, 0, errNoSupport
+	return 0, 0, syscall.EWINDOWS
 }
diff --git a/src/net/file.go b/src/net/file.go
new file mode 100644
index 0000000..1aad477
--- /dev/null
+++ b/src/net/file.go
@@ -0,0 +1,48 @@
+// 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"
+
+type fileAddr string
+
+func (fileAddr) Network() string  { return "file+net" }
+func (f fileAddr) String() string { return string(f) }
+
+// FileConn returns a copy of the network connection corresponding to
+// the open file f.
+// It is the caller's responsibility to close f when finished.
+// Closing c does not affect f, and closing f does not affect c.
+func FileConn(f *os.File) (c Conn, err error) {
+	c, err = fileConn(f)
+	if err != nil {
+		err = &OpError{Op: "file", Net: "file+net", Source: nil, Addr: fileAddr(f.Name()), Err: err}
+	}
+	return
+}
+
+// FileListener returns a copy of the network listener corresponding
+// to the open file f.
+// It is the caller's responsibility to close ln when finished.
+// Closing ln does not affect f, and closing f does not affect ln.
+func FileListener(f *os.File) (ln Listener, err error) {
+	ln, err = fileListener(f)
+	if err != nil {
+		err = &OpError{Op: "file", Net: "file+net", Source: nil, Addr: fileAddr(f.Name()), Err: err}
+	}
+	return
+}
+
+// FilePacketConn returns a copy of the packet network connection
+// corresponding to the open file f.
+// It is the caller's responsibility to close f when finished.
+// Closing c does not affect f, and closing f does not affect c.
+func FilePacketConn(f *os.File) (c PacketConn, err error) {
+	c, err = filePacketConn(f)
+	if err != nil {
+		err = &OpError{Op: "file", Net: "file+net", Source: nil, Addr: fileAddr(f.Name()), Err: err}
+	}
+	return
+}
diff --git a/src/net/file_plan9.go b/src/net/file_plan9.go
index 068f088..892775a 100644
--- a/src/net/file_plan9.go
+++ b/src/net/file_plan9.go
@@ -86,7 +86,7 @@ func newFileFD(f *os.File) (net *netFD, err error) {
 	return newFD(comp[1], name, ctl, nil, laddr, nil)
 }
 
-func newFileConn(f *os.File) (c Conn, err error) {
+func fileConn(f *os.File) (Conn, error) {
 	fd, err := newFileFD(f)
 	if err != nil {
 		return nil, err
@@ -109,7 +109,7 @@ func newFileConn(f *os.File) (c Conn, err error) {
 	return nil, syscall.EPLAN9
 }
 
-func newFileListener(f *os.File) (l Listener, err error) {
+func fileListener(f *os.File) (Listener, error) {
 	fd, err := newFileFD(f)
 	if err != nil {
 		return nil, err
@@ -132,26 +132,6 @@ func newFileListener(f *os.File) (l Listener, err error) {
 	return &TCPListener{fd}, nil
 }
 
-// FileConn returns a copy of the network connection corresponding to
-// the open file f.  It is the caller's responsibility to close f when
-// finished.  Closing c does not affect f, and closing f does not
-// affect c.
-func FileConn(f *os.File) (c Conn, err error) {
-	return newFileConn(f)
-}
-
-// FileListener returns a copy of the network listener corresponding
-// to the open file f.  It is the caller's responsibility to close l
-// when finished.  Closing l does not affect f, and closing f does not
-// affect l.
-func FileListener(f *os.File) (l Listener, err error) {
-	return newFileListener(f)
-}
-
-// FilePacketConn returns a copy of the packet network connection
-// corresponding to the open file f.  It is the caller's
-// responsibility to close f when finished.  Closing c does not affect
-// f, and closing f does not affect c.
-func FilePacketConn(f *os.File) (c PacketConn, err error) {
+func filePacketConn(f *os.File) (PacketConn, error) {
 	return nil, syscall.EPLAN9
 }
diff --git a/src/net/file_stub.go b/src/net/file_stub.go
index 4281072..0f7460c 100644
--- a/src/net/file_stub.go
+++ b/src/net/file_stub.go
@@ -11,28 +11,6 @@ import (
 	"syscall"
 )
 
-// FileConn returns a copy of the network connection corresponding to
-// the open file f.  It is the caller's responsibility to close f when
-// finished.  Closing c does not affect f, and closing f does not
-// affect c.
-func FileConn(f *os.File) (c Conn, err error) {
-	return nil, syscall.ENOPROTOOPT
-
-}
-
-// FileListener returns a copy of the network listener corresponding
-// to the open file f.  It is the caller's responsibility to close l
-// when finished.  Closing l does not affect f, and closing f does not
-// affect l.
-func FileListener(f *os.File) (l Listener, err error) {
-	return nil, syscall.ENOPROTOOPT
-
-}
-
-// FilePacketConn returns a copy of the packet network connection
-// corresponding to the open file f.  It is the caller's
-// responsibility to close f when finished.  Closing c does not affect
-// f, and closing f does not affect c.
-func FilePacketConn(f *os.File) (c PacketConn, err error) {
-	return nil, syscall.ENOPROTOOPT
-}
+func fileConn(f *os.File) (Conn, error)             { return nil, syscall.ENOPROTOOPT }
+func fileListener(f *os.File) (Listener, error)     { return nil, syscall.ENOPROTOOPT }
+func filePacketConn(f *os.File) (PacketConn, error) { return nil, syscall.ENOPROTOOPT }
diff --git a/src/net/file_test.go b/src/net/file_test.go
index 6fab06a..003dbb2 100644
--- a/src/net/file_test.go
+++ b/src/net/file_test.go
@@ -27,77 +27,69 @@ type connFile interface {
 }
 
 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)
+		t.Fatal(err)
 	}
 	defer l.Close()
 	lf := l.(listenerFile)
 	f, err := lf.File()
 	if err != nil {
-		t.Fatalf("File failed: %v", err)
+		t.Fatal(err)
 	}
 	c, err := FileListener(f)
 	if err != nil {
-		t.Fatalf("FileListener failed: %v", err)
+		t.Fatal(err)
 	}
 	if !reflect.DeepEqual(l.Addr(), c.Addr()) {
-		t.Fatalf("Addrs not equal: %#v != %#v", l.Addr(), c.Addr())
+		t.Fatalf("got %#v; want%#v", l.Addr(), c.Addr())
 	}
 	if err := c.Close(); err != nil {
-		t.Fatalf("Close failed: %v", err)
+		t.Fatal(err)
 	}
 	if err := f.Close(); err != nil {
-		t.Fatalf("Close failed: %v", err)
+		t.Fatal(err)
 	}
 }
 
 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) {
 	switch runtime.GOOS {
 	case "nacl", "windows":
-		t.Skipf("skipping test on %q", runtime.GOOS)
+		t.Skipf("not supported on %s", runtime.GOOS)
 	}
 
 	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)
@@ -107,86 +99,78 @@ func TestFileListener(t *testing.T) {
 func testFilePacketConn(t *testing.T, pcf packetConnFile, listen bool) {
 	f, err := pcf.File()
 	if err != nil {
-		t.Fatalf("File failed: %v", err)
+		t.Fatal(err)
 	}
 	c, err := FilePacketConn(f)
 	if err != nil {
-		t.Fatalf("FilePacketConn failed: %v", err)
+		t.Fatal(err)
 	}
 	if !reflect.DeepEqual(pcf.LocalAddr(), c.LocalAddr()) {
-		t.Fatalf("LocalAddrs not equal: %#v != %#v", pcf.LocalAddr(), c.LocalAddr())
+		t.Fatalf("got %#v; want %#v", pcf.LocalAddr(), c.LocalAddr())
 	}
 	if listen {
 		if _, err := c.WriteTo([]byte{}, c.LocalAddr()); err != nil {
-			t.Fatalf("WriteTo failed: %v", err)
+			t.Fatal(err)
 		}
 	}
 	if err := c.Close(); err != nil {
-		t.Fatalf("Close failed: %v", err)
+		t.Fatal(err)
 	}
 	if err := f.Close(); err != nil {
-		t.Fatalf("Close failed: %v", err)
+		t.Fatal(err)
 	}
 }
 
 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)
+		t.Fatal(err)
 	}
 	testFilePacketConn(t, l.(packetConnFile), true)
 	if err := l.Close(); err != nil {
-		t.Fatalf("Close failed: %v", err)
+		t.Fatal(err)
 	}
 }
 
 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)
+		t.Fatal(err)
 	}
 	testFilePacketConn(t, c.(packetConnFile), false)
 	if err := c.Close(); err != nil {
-		t.Fatalf("Close failed: %v", err)
+		t.Fatal(err)
 	}
 }
 
 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"},
+	// TODO(mikioh,bradfitz): reenable once 10730 is fixed
+	// {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) {
 	switch runtime.GOOS {
 	case "nacl", "plan9", "windows":
-		t.Skipf("skipping test on %q", runtime.GOOS)
+		t.Skipf("not supported on %s", runtime.GOOS)
 	}
 
 	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 +178,16 @@ func TestFilePacketConn(t *testing.T) {
 			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..5b24c7d 100644
--- a/src/net/file_unix.go
+++ b/src/net/file_unix.go
@@ -11,75 +11,59 @@ import (
 	"syscall"
 )
 
-func newFileFD(f *os.File) (*netFD, error) {
-	fd, err := dupCloseOnExec(int(f.Fd()))
+func dupSocket(f *os.File) (int, error) {
+	s, err := dupCloseOnExec(int(f.Fd()))
 	if err != nil {
-		return nil, os.NewSyscallError("dup", err)
+		return -1, err
+	}
+	if err := syscall.SetNonblock(s, true); err != nil {
+		closeFunc(s)
+		return -1, os.NewSyscallError("setnonblock", err)
 	}
+	return s, nil
+}
 
-	if err = syscall.SetNonblock(fd, true); err != nil {
-		closesocket(fd)
+func newFileFD(f *os.File) (*netFD, error) {
+	s, err := dupSocket(f)
+	if err != nil {
 		return nil, err
 	}
-
-	sotype, err := syscall.GetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_TYPE)
+	family := syscall.AF_UNSPEC
+	sotype, err := syscall.GetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_TYPE)
 	if err != nil {
-		closesocket(fd)
+		closeFunc(s)
 		return nil, os.NewSyscallError("getsockopt", err)
 	}
-
-	family := syscall.AF_UNSPEC
-	toAddr := sockaddrToTCP
-	lsa, _ := syscall.Getsockname(fd)
+	lsa, _ := syscall.Getsockname(s)
+	rsa, _ := syscall.Getpeername(s)
 	switch lsa.(type) {
-	default:
-		closesocket(fd)
-		return nil, syscall.EINVAL
 	case *syscall.SockaddrInet4:
 		family = syscall.AF_INET
-		if sotype == syscall.SOCK_DGRAM {
-			toAddr = sockaddrToUDP
-		} else if sotype == syscall.SOCK_RAW {
-			toAddr = sockaddrToIP
-		}
 	case *syscall.SockaddrInet6:
 		family = syscall.AF_INET6
-		if sotype == syscall.SOCK_DGRAM {
-			toAddr = sockaddrToUDP
-		} else if sotype == syscall.SOCK_RAW {
-			toAddr = sockaddrToIP
-		}
 	case *syscall.SockaddrUnix:
 		family = syscall.AF_UNIX
-		toAddr = sockaddrToUnix
-		if sotype == syscall.SOCK_DGRAM {
-			toAddr = sockaddrToUnixgram
-		} else if sotype == syscall.SOCK_SEQPACKET {
-			toAddr = sockaddrToUnixpacket
-		}
+	default:
+		closeFunc(s)
+		return nil, syscall.EPROTONOSUPPORT
 	}
-	laddr := toAddr(lsa)
-	rsa, _ := syscall.Getpeername(fd)
-	raddr := toAddr(rsa)
-
-	netfd, err := newFD(fd, family, sotype, laddr.Network())
+	fd, err := newFD(s, family, sotype, "")
 	if err != nil {
-		closesocket(fd)
+		closeFunc(s)
 		return nil, err
 	}
-	if err := netfd.init(); err != nil {
-		netfd.Close()
+	laddr := fd.addrFunc()(lsa)
+	raddr := fd.addrFunc()(rsa)
+	fd.net = laddr.Network()
+	if err := fd.init(); err != nil {
+		fd.Close()
 		return nil, err
 	}
-	netfd.setAddr(laddr, raddr)
-	return netfd, nil
+	fd.setAddr(laddr, raddr)
+	return fd, nil
 }
 
-// FileConn returns a copy of the network connection corresponding to
-// the open file f.  It is the caller's responsibility to close f when
-// finished.  Closing c does not affect f, and closing f does not
-// affect c.
-func FileConn(f *os.File) (c Conn, err error) {
+func fileConn(f *os.File) (Conn, error) {
 	fd, err := newFileFD(f)
 	if err != nil {
 		return nil, err
@@ -98,11 +82,7 @@ func FileConn(f *os.File) (c Conn, err error) {
 	return nil, syscall.EINVAL
 }
 
-// FileListener returns a copy of the network listener corresponding
-// to the open file f.  It is the caller's responsibility to close l
-// when finished.  Closing l does not affect f, and closing f does not
-// affect l.
-func FileListener(f *os.File) (l Listener, err error) {
+func fileListener(f *os.File) (Listener, error) {
 	fd, err := newFileFD(f)
 	if err != nil {
 		return nil, err
@@ -117,11 +97,7 @@ func FileListener(f *os.File) (l Listener, err error) {
 	return nil, syscall.EINVAL
 }
 
-// FilePacketConn returns a copy of the packet network connection
-// corresponding to the open file f.  It is the caller's
-// responsibility to close f when finished.  Closing c does not affect
-// f, and closing f does not affect c.
-func FilePacketConn(f *os.File) (c PacketConn, err error) {
+func filePacketConn(f *os.File) (PacketConn, error) {
 	fd, err := newFileFD(f)
 	if err != nil {
 		return nil, err
diff --git a/src/net/file_windows.go b/src/net/file_windows.go
index ca2b9b2..241fa17 100644
--- a/src/net/file_windows.go
+++ b/src/net/file_windows.go
@@ -9,29 +9,17 @@ import (
 	"syscall"
 )
 
-// FileConn returns a copy of the network connection corresponding to
-// the open file f.  It is the caller's responsibility to close f when
-// finished.  Closing c does not affect f, and closing f does not
-// affect c.
-func FileConn(f *os.File) (c Conn, err error) {
+func fileConn(f *os.File) (Conn, error) {
 	// TODO: Implement this
-	return nil, os.NewSyscallError("FileConn", syscall.EWINDOWS)
+	return nil, syscall.EWINDOWS
 }
 
-// FileListener returns a copy of the network listener corresponding
-// to the open file f.  It is the caller's responsibility to close l
-// when finished.  Closing l does not affect f, and closing f does not
-// affect l.
-func FileListener(f *os.File) (l Listener, err error) {
+func fileListener(f *os.File) (Listener, error) {
 	// TODO: Implement this
-	return nil, os.NewSyscallError("FileListener", syscall.EWINDOWS)
+	return nil, syscall.EWINDOWS
 }
 
-// FilePacketConn returns a copy of the packet network connection
-// corresponding to the open file f.  It is the caller's
-// responsibility to close f when finished.  Closing c does not affect
-// f, and closing f does not affect c.
-func FilePacketConn(f *os.File) (c PacketConn, err error) {
+func filePacketConn(f *os.File) (PacketConn, error) {
 	// TODO: Implement this
-	return nil, os.NewSyscallError("FilePacketConn", syscall.EWINDOWS)
+	return nil, syscall.EWINDOWS
 }
diff --git a/src/net/hook.go b/src/net/hook.go
new file mode 100644
index 0000000..9ab34c0
--- /dev/null
+++ b/src/net/hook.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.
+
+package net
+
+var (
+	testHookDialTCP      = dialTCP
+	testHookHostsPath    = "/etc/hosts"
+	testHookLookupIP     = func(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, error) { return fn(host) }
+	testHookSetKeepAlive = func() {}
+)
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_plan9.go b/src/net/hook_plan9.go
new file mode 100644
index 0000000..e053348
--- /dev/null
+++ b/src/net/hook_plan9.go
@@ -0,0 +1,9 @@
+// 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 "time"
+
+var testHookDialChannel = func() { time.Sleep(time.Millisecond) } // see golang.org/issue/5349
diff --git a/src/net/hook_unix.go b/src/net/hook_unix.go
new file mode 100644
index 0000000..361ca59
--- /dev/null
+++ b/src/net/hook_unix.go
@@ -0,0 +1,21 @@
+// 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 (
+	testHookDialChannel = func() {} // see golang.org/issue/5349
+
+	// 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
+	listenFunc        func(int, int) error                     = syscall.Listen
+	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..126b0eb
--- /dev/null
+++ b/src/net/hook_windows.go
@@ -0,0 +1,21 @@
+// 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"
+	"time"
+)
+
+var (
+	testHookDialChannel = func() { time.Sleep(time.Millisecond) } // see golang.org/issue/5349
+
+	// 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
+	listenFunc    func(syscall.Handle, int) error                                                           = syscall.Listen
+)
diff --git a/src/net/hosts.go b/src/net/hosts.go
index 9400503..27958c7 100644
--- a/src/net/hosts.go
+++ b/src/net/hosts.go
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Read static host/IP entries from /etc/hosts.
-
 package net
 
 import (
@@ -13,8 +11,21 @@ import (
 
 const cacheMaxAge = 5 * time.Minute
 
-// hostsPath points to the file with static IP/address entries.
-var hostsPath = "/etc/hosts"
+func parseLiteralIP(addr string) string {
+	var ip IP
+	var zone string
+	ip = parseIPv4(addr)
+	if ip == nil {
+		ip, zone = parseIPv6(addr, true)
+	}
+	if ip == nil {
+		return ""
+	}
+	if zone == "" {
+		return ip.String()
+	}
+	return ip.String() + "%" + zone
+}
 
 // Simple cache.
 var hosts struct {
@@ -27,7 +38,7 @@ var hosts struct {
 
 func readHosts() {
 	now := time.Now()
-	hp := hostsPath
+	hp := testHookHostsPath
 	if len(hosts.byName) == 0 || now.After(hosts.expire) || hosts.path != hp {
 		hs := make(map[string][]string)
 		is := make(map[string][]string)
@@ -41,13 +52,17 @@ func readHosts() {
 				line = line[0:i]
 			}
 			f := getFields(line)
-			if len(f) < 2 || ParseIP(f[0]) == nil {
+			if len(f) < 2 {
+				continue
+			}
+			addr := parseLiteralIP(f[0])
+			if addr == "" {
 				continue
 			}
 			for i := 1; i < len(f); i++ {
 				h := f[i]
-				hs[h] = append(hs[h], f[0])
-				is[f[0]] = append(is[f[0]], h)
+				hs[h] = append(hs[h], addr)
+				is[addr] = append(is[addr], h)
 			}
 		}
 		// Update the data cache.
@@ -77,6 +92,10 @@ func lookupStaticAddr(addr string) []string {
 	hosts.Lock()
 	defer hosts.Unlock()
 	readHosts()
+	addr = parseLiteralIP(addr)
+	if addr == "" {
+		return nil
+	}
 	if len(hosts.byAddr) != 0 {
 		if hosts, ok := hosts.byAddr[addr]; ok {
 			return hosts
diff --git a/src/net/hosts_test.go b/src/net/hosts_test.go
index 2fe358e..aca64c3 100644
--- a/src/net/hosts_test.go
+++ b/src/net/hosts_test.go
@@ -5,77 +5,116 @@
 package net
 
 import (
-	"sort"
+	"reflect"
 	"testing"
 )
 
-type hostTest struct {
-	host string
-	ips  []IP
+type staticHostEntry struct {
+	in  string
+	out []string
 }
 
-var hosttests = []hostTest{
-	{"odin", []IP{
-		IPv4(127, 0, 0, 2),
-		IPv4(127, 0, 0, 3),
-		ParseIP("::2"),
-	}},
-	{"thor", []IP{
-		IPv4(127, 1, 1, 1),
-	}},
-	{"loki", []IP{}},
-	{"ullr", []IP{
-		IPv4(127, 1, 1, 2),
-	}},
-	{"ullrhost", []IP{
-		IPv4(127, 1, 1, 2),
-	}},
+var lookupStaticHostTests = []struct {
+	name string
+	ents []staticHostEntry
+}{
+	{
+		"testdata/hosts",
+		[]staticHostEntry{
+			{"odin", []string{"127.0.0.2", "127.0.0.3", "::2"}},
+			{"thor", []string{"127.1.1.1"}},
+			{"ullr", []string{"127.1.1.2"}},
+			{"ullrhost", []string{"127.1.1.2"}},
+			{"localhost", []string{"fe80::1%lo0"}},
+		},
+	},
+	{
+		"testdata/singleline-hosts", // see golang.org/issue/6646
+		[]staticHostEntry{
+			{"odin", []string{"127.0.0.2"}},
+		},
+	},
+	{
+		"testdata/ipv4-hosts", // see golang.org/issue/8996
+		[]staticHostEntry{
+			{"localhost", []string{"127.0.0.1", "127.0.0.2", "127.0.0.3"}},
+			{"localhost.localdomain", []string{"127.0.0.3"}},
+		},
+	},
+	{
+		"testdata/ipv6-hosts", // see golang.org/issue/8996
+		[]staticHostEntry{
+			{"localhost", []string{"::1", "fe80::1", "fe80::2%lo0", "fe80::3%lo0"}},
+			{"localhost.localdomain", []string{"fe80::3%lo0"}},
+		},
+	},
 }
 
 func TestLookupStaticHost(t *testing.T) {
-	p := hostsPath
-	hostsPath = "testdata/hosts"
-	for i := 0; i < len(hosttests); i++ {
-		tt := hosttests[i]
-		ips := lookupStaticHost(tt.host)
-		if len(ips) != len(tt.ips) {
-			t.Errorf("# of hosts = %v; want %v",
-				len(ips), len(tt.ips))
-			continue
-		}
-		for k, v := range ips {
-			if tt.ips[k].String() != v {
-				t.Errorf("lookupStaticHost(%q) = %v; want %v",
-					tt.host, v, tt.ips[k])
+	defer func(orig string) { testHookHostsPath = orig }(testHookHostsPath)
+
+	for _, tt := range lookupStaticHostTests {
+		testHookHostsPath = tt.name
+		for _, ent := range tt.ents {
+			addrs := lookupStaticHost(ent.in)
+			if !reflect.DeepEqual(addrs, ent.out) {
+				t.Errorf("%s, lookupStaticHost(%s) = %v; want %v", tt.name, ent.in, addrs, ent.out)
 			}
 		}
 	}
-	hostsPath = p
 }
 
-// https://code.google.com/p/go/issues/detail?id=6646
-func TestSingleLineHostsFile(t *testing.T) {
-	p := hostsPath
-	hostsPath = "testdata/hosts_singleline"
-
-	ips := lookupStaticHost("odin")
-	if len(ips) != 1 || ips[0] != "127.0.0.2" {
-		t.Errorf("lookupStaticHost = %v, want %v", ips, []string{"127.0.0.2"})
-	}
-
-	hostsPath = p
+var lookupStaticAddrTests = []struct {
+	name string
+	ents []staticHostEntry
+}{
+	{
+		"testdata/hosts",
+		[]staticHostEntry{
+			{"255.255.255.255", []string{"broadcasthost"}},
+			{"127.0.0.2", []string{"odin"}},
+			{"127.0.0.3", []string{"odin"}},
+			{"::2", []string{"odin"}},
+			{"127.1.1.1", []string{"thor"}},
+			{"127.1.1.2", []string{"ullr", "ullrhost"}},
+			{"fe80::1%lo0", []string{"localhost"}},
+		},
+	},
+	{
+		"testdata/singleline-hosts", // see golang.org/issue/6646
+		[]staticHostEntry{
+			{"127.0.0.2", []string{"odin"}},
+		},
+	},
+	{
+		"testdata/ipv4-hosts", // see golang.org/issue/8996
+		[]staticHostEntry{
+			{"127.0.0.1", []string{"localhost"}},
+			{"127.0.0.2", []string{"localhost"}},
+			{"127.0.0.3", []string{"localhost", "localhost.localdomain"}},
+		},
+	},
+	{
+		"testdata/ipv6-hosts", // see golang.org/issue/8996
+		[]staticHostEntry{
+			{"::1", []string{"localhost"}},
+			{"fe80::1", []string{"localhost"}},
+			{"fe80::2%lo0", []string{"localhost"}},
+			{"fe80::3%lo0", []string{"localhost", "localhost.localdomain"}},
+		},
+	},
 }
 
-func TestLookupHost(t *testing.T) {
-	// Can't depend on this to return anything in particular,
-	// but if it does return something, make sure it doesn't
-	// duplicate addresses (a common bug due to the way
-	// getaddrinfo works).
-	addrs, _ := LookupHost("localhost")
-	sort.Strings(addrs)
-	for i := 0; i+1 < len(addrs); i++ {
-		if addrs[i] == addrs[i+1] {
-			t.Fatalf("LookupHost(\"localhost\") = %v, has duplicate addresses", addrs)
+func TestLookupStaticAddr(t *testing.T) {
+	defer func(orig string) { testHookHostsPath = orig }(testHookHostsPath)
+
+	for _, tt := range lookupStaticAddrTests {
+		testHookHostsPath = tt.name
+		for _, ent := range tt.ents {
+			hosts := lookupStaticAddr(ent.in)
+			if !reflect.DeepEqual(hosts, ent.out) {
+				t.Errorf("%s, lookupStaticAddr(%s) = %v; want %v", tt.name, ent.in, hosts, ent.out)
+			}
 		}
 	}
 }
diff --git a/src/net/http/cgi/child.go b/src/net/http/cgi/child.go
index 45fc2e5..ec10108 100644
--- a/src/net/http/cgi/child.go
+++ b/src/net/http/cgi/child.go
@@ -132,9 +132,9 @@ func RequestFromMap(params map[string]string) (*http.Request, error) {
 	}
 
 	// Request.RemoteAddr has its port set by Go's standard http
-	// server, so we do here too. We don't have one, though, so we
-	// use a dummy one.
-	r.RemoteAddr = net.JoinHostPort(params["REMOTE_ADDR"], "0")
+	// server, so we do here too.
+	remotePort, _ := strconv.Atoi(params["REMOTE_PORT"]) // zero if unset or invalid
+	r.RemoteAddr = net.JoinHostPort(params["REMOTE_ADDR"], strconv.Itoa(remotePort))
 
 	return r, nil
 }
diff --git a/src/net/http/cgi/child_test.go b/src/net/http/cgi/child_test.go
index 075d841..14e0af4 100644
--- a/src/net/http/cgi/child_test.go
+++ b/src/net/http/cgi/child_test.go
@@ -22,6 +22,7 @@ func TestRequest(t *testing.T) {
 		"CONTENT_LENGTH":  "123",
 		"CONTENT_TYPE":    "text/xml",
 		"REMOTE_ADDR":     "5.6.7.8",
+		"REMOTE_PORT":     "54321",
 	}
 	req, err := RequestFromMap(env)
 	if err != nil {
@@ -60,7 +61,7 @@ func TestRequest(t *testing.T) {
 	if req.TLS != nil {
 		t.Errorf("expected nil TLS")
 	}
-	if e, g := "5.6.7.8:0", req.RemoteAddr; e != g {
+	if e, g := "5.6.7.8:54321", req.RemoteAddr; e != g {
 		t.Errorf("RemoteAddr: got %q; want %q", g, e)
 	}
 }
@@ -129,3 +130,21 @@ func TestRequestWithoutRequestURI(t *testing.T) {
 		t.Errorf("URL = %q; want %q", g, e)
 	}
 }
+
+func TestRequestWithoutRemotePort(t *testing.T) {
+	env := map[string]string{
+		"SERVER_PROTOCOL": "HTTP/1.1",
+		"HTTP_HOST":       "example.com",
+		"REQUEST_METHOD":  "GET",
+		"REQUEST_URI":     "/path?a=b",
+		"CONTENT_LENGTH":  "123",
+		"REMOTE_ADDR":     "5.6.7.8",
+	}
+	req, err := RequestFromMap(env)
+	if err != nil {
+		t.Fatalf("RequestFromMap: %v", err)
+	}
+	if e, g := "5.6.7.8:0", req.RemoteAddr; e != g {
+		t.Errorf("RemoteAddr: got %q; want %q", g, e)
+	}
+}
diff --git a/src/net/http/cgi/host.go b/src/net/http/cgi/host.go
index ec95a97..4efbe7a 100644
--- a/src/net/http/cgi/host.go
+++ b/src/net/http/cgi/host.go
@@ -19,6 +19,7 @@ import (
 	"fmt"
 	"io"
 	"log"
+	"net"
 	"net/http"
 	"os"
 	"os/exec"
@@ -128,11 +129,16 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
 		"PATH_INFO=" + pathInfo,
 		"SCRIPT_NAME=" + root,
 		"SCRIPT_FILENAME=" + h.Path,
-		"REMOTE_ADDR=" + req.RemoteAddr,
-		"REMOTE_HOST=" + req.RemoteAddr,
 		"SERVER_PORT=" + port,
 	}
 
+	if remoteIP, remotePort, err := net.SplitHostPort(req.RemoteAddr); err == nil {
+		env = append(env, "REMOTE_ADDR="+remoteIP, "REMOTE_HOST="+remoteIP, "REMOTE_PORT="+remotePort)
+	} else {
+		// could not parse ip:port, let's use whole RemoteAddr and leave REMOTE_PORT undefined
+		env = append(env, "REMOTE_ADDR="+req.RemoteAddr, "REMOTE_HOST="+req.RemoteAddr)
+	}
+
 	if req.TLS != nil {
 		env = append(env, "HTTPS=on")
 	}
diff --git a/src/net/http/cgi/host_test.go b/src/net/http/cgi/host_test.go
index 8c16e68..4aa67e4 100644
--- a/src/net/http/cgi/host_test.go
+++ b/src/net/http/cgi/host_test.go
@@ -29,7 +29,7 @@ func newRequest(httpreq string) *http.Request {
 	if err != nil {
 		panic("cgi: bogus http request in test: " + httpreq)
 	}
-	req.RemoteAddr = "1.2.3.4"
+	req.RemoteAddr = "1.2.3.4:1234"
 	return req
 }
 
@@ -37,7 +37,11 @@ func runCgiTest(t *testing.T, h *Handler, httpreq string, expectedMap map[string
 	rw := httptest.NewRecorder()
 	req := newRequest(httpreq)
 	h.ServeHTTP(rw, req)
+	runResponseChecks(t, rw, expectedMap)
+	return rw
+}
 
+func runResponseChecks(t *testing.T, rw *httptest.ResponseRecorder, expectedMap map[string]string) {
 	// Make a map to hold the test map that the CGI returns.
 	m := make(map[string]string)
 	m["_body"] = rw.Body.String()
@@ -75,7 +79,6 @@ readlines:
 			t.Errorf("for key %q got %q; expected %q", key, got, expected)
 		}
 	}
-	return rw
 }
 
 var cgiTested, cgiWorks bool
@@ -108,6 +111,7 @@ func TestCGIBasicGet(t *testing.T) {
 		"env-QUERY_STRING":      "foo=bar&a=b",
 		"env-REMOTE_ADDR":       "1.2.3.4",
 		"env-REMOTE_HOST":       "1.2.3.4",
+		"env-REMOTE_PORT":       "1234",
 		"env-REQUEST_METHOD":    "GET",
 		"env-REQUEST_URI":       "/test.cgi?foo=bar&a=b",
 		"env-SCRIPT_FILENAME":   "testdata/test.cgi",
@@ -126,6 +130,39 @@ func TestCGIBasicGet(t *testing.T) {
 	}
 }
 
+func TestCGIEnvIPv6(t *testing.T) {
+	check(t)
+	h := &Handler{
+		Path: "testdata/test.cgi",
+		Root: "/test.cgi",
+	}
+	expectedMap := map[string]string{
+		"test":                  "Hello CGI",
+		"param-a":               "b",
+		"param-foo":             "bar",
+		"env-GATEWAY_INTERFACE": "CGI/1.1",
+		"env-HTTP_HOST":         "example.com",
+		"env-PATH_INFO":         "",
+		"env-QUERY_STRING":      "foo=bar&a=b",
+		"env-REMOTE_ADDR":       "2000::3000",
+		"env-REMOTE_HOST":       "2000::3000",
+		"env-REMOTE_PORT":       "12345",
+		"env-REQUEST_METHOD":    "GET",
+		"env-REQUEST_URI":       "/test.cgi?foo=bar&a=b",
+		"env-SCRIPT_FILENAME":   "testdata/test.cgi",
+		"env-SCRIPT_NAME":       "/test.cgi",
+		"env-SERVER_NAME":       "example.com",
+		"env-SERVER_PORT":       "80",
+		"env-SERVER_SOFTWARE":   "go",
+	}
+
+	rw := httptest.NewRecorder()
+	req := newRequest("GET /test.cgi?foo=bar&a=b HTTP/1.0\nHost: example.com\n\n")
+	req.RemoteAddr = "[2000::3000]:12345"
+	h.ServeHTTP(rw, req)
+	runResponseChecks(t, rw, expectedMap)
+}
+
 func TestCGIBasicGetAbsPath(t *testing.T) {
 	check(t)
 	pwd, err := os.Getwd()
@@ -289,7 +326,7 @@ func TestInternalRedirect(t *testing.T) {
 	}
 	expectedMap := map[string]string{
 		"basepath":   "/foo",
-		"remoteaddr": "1.2.3.4",
+		"remoteaddr": "1.2.3.4:1234",
 	}
 	runCgiTest(t, h, "GET /test.cgi?loc=/foo HTTP/1.0\nHost: example.com\n\n", expectedMap)
 }
diff --git a/src/net/http/cgi/matryoshka_test.go b/src/net/http/cgi/matryoshka_test.go
index 18c4803..32d59c0 100644
--- a/src/net/http/cgi/matryoshka_test.go
+++ b/src/net/http/cgi/matryoshka_test.go
@@ -12,11 +12,11 @@ import (
 	"bytes"
 	"errors"
 	"fmt"
+	"internal/testenv"
 	"io"
 	"net/http"
 	"net/http/httptest"
 	"os"
-	"runtime"
 	"testing"
 	"time"
 )
@@ -24,9 +24,7 @@ import (
 // This test is a CGI host (testing host.go) that runs its own binary
 // as a child process testing the other half of CGI (child.go).
 func TestHostingOurselves(t *testing.T) {
-	if runtime.GOOS == "nacl" {
-		t.Skip("skipping on nacl")
-	}
+	testenv.MustHaveExec(t)
 
 	h := &Handler{
 		Path: os.Args[0],
@@ -43,6 +41,7 @@ func TestHostingOurselves(t *testing.T) {
 		"env-QUERY_STRING":      "foo=bar&a=b",
 		"env-REMOTE_ADDR":       "1.2.3.4",
 		"env-REMOTE_HOST":       "1.2.3.4",
+		"env-REMOTE_PORT":       "1234",
 		"env-REQUEST_METHOD":    "GET",
 		"env-REQUEST_URI":       "/test.go?foo=bar&a=b",
 		"env-SCRIPT_FILENAME":   os.Args[0],
@@ -92,9 +91,7 @@ func (w *limitWriter) Write(p []byte) (n int, err error) {
 // If there's an error copying the child's output to the parent, test
 // that we kill the child.
 func TestKillChildAfterCopyError(t *testing.T) {
-	if runtime.GOOS == "nacl" {
-		t.Skip("skipping on nacl")
-	}
+	testenv.MustHaveExec(t)
 
 	defer func() { testHookStartProcess = nil }()
 	proc := make(chan *os.Process, 1)
@@ -139,9 +136,7 @@ func TestKillChildAfterCopyError(t *testing.T) {
 // Test that a child handler writing only headers works.
 // golang.org/issue/7196
 func TestChildOnlyHeaders(t *testing.T) {
-	if runtime.GOOS == "nacl" {
-		t.Skip("skipping on nacl")
-	}
+	testenv.MustHaveExec(t)
 
 	h := &Handler{
 		Path: os.Args[0],
diff --git a/src/net/http/cgi/testdata/test.cgi b/src/net/http/cgi/testdata/test.cgi
index 3214df6..ec7ee6f 100755
--- a/src/net/http/cgi/testdata/test.cgi
+++ b/src/net/http/cgi/testdata/test.cgi
@@ -45,7 +45,7 @@ foreach my $k (sort keys %ENV) {
 
 # NOTE: msys perl returns /c/go/src/... not C:\go\....
 my $dir = getcwd();
-if ($^O eq 'MSWin32' || $^O eq 'msys') {
+if ($^O eq 'MSWin32' || $^O eq 'msys' || $^O eq 'cygwin') {
     if ($dir =~ /^.:/) {
         $dir =~ s!/!\\!g;
     } else {
diff --git a/src/net/http/client.go b/src/net/http/client.go
index ce884d1..7f2fbb4 100644
--- a/src/net/http/client.go
+++ b/src/net/http/client.go
@@ -19,6 +19,7 @@ import (
 	"net/url"
 	"strings"
 	"sync"
+	"sync/atomic"
 	"time"
 )
 
@@ -211,7 +212,7 @@ func send(req *Request, t RoundTripper) (resp *Response, err error) {
 		req.Header = make(Header)
 	}
 
-	if u := req.URL.User; u != nil {
+	if u := req.URL.User; u != nil && req.Header.Get("Authorization") == "" {
 		username := u.Username()
 		password, _ := u.Password()
 		req.Header.Set("Authorization", "Basic "+basicAuth(username, password))
@@ -256,8 +257,9 @@ func shouldRedirectPost(statusCode int) bool {
 	return false
 }
 
-// Get issues a GET to the specified URL.  If the response is one of the following
-// redirect codes, Get follows the redirect, up to a maximum of 10 redirects:
+// Get issues a GET to the specified URL. If the response is one of
+// the following redirect codes, Get follows the redirect, up to a
+// maximum of 10 redirects:
 //
 //    301 (Moved Permanently)
 //    302 (Found)
@@ -272,13 +274,16 @@ func shouldRedirectPost(statusCode int) bool {
 // Caller should close resp.Body when done reading from it.
 //
 // Get is a wrapper around DefaultClient.Get.
+//
+// To make a request with custom headers, use NewRequest and
+// DefaultClient.Do.
 func Get(url string) (resp *Response, err error) {
 	return DefaultClient.Get(url)
 }
 
-// Get issues a GET to the specified URL.  If the response is one of the
+// Get issues a GET to the specified URL. If the response is one of the
 // following redirect codes, Get follows the redirect after calling the
-// Client's CheckRedirect function.
+// Client's CheckRedirect function:
 //
 //    301 (Moved Permanently)
 //    302 (Found)
@@ -291,6 +296,8 @@ func Get(url string) (resp *Response, err error) {
 //
 // When err is nil, resp always contains a non-nil resp.Body.
 // Caller should close resp.Body when done reading from it.
+//
+// To make a request with custom headers, use NewRequest and Client.Do.
 func (c *Client) Get(url string) (resp *Response, err error) {
 	req, err := NewRequest("GET", url, nil)
 	if err != nil {
@@ -299,6 +306,8 @@ func (c *Client) Get(url string) (resp *Response, err error) {
 	return c.doFollowingRedirects(req, shouldRedirectGet)
 }
 
+func alwaysFalse() bool { return false }
+
 func (c *Client) doFollowingRedirects(ireq *Request, shouldRedirect func(int) bool) (resp *Response, err error) {
 	var base *url.URL
 	redirectChecker := c.CheckRedirect
@@ -316,7 +325,10 @@ func (c *Client) doFollowingRedirects(ireq *Request, shouldRedirect func(int) bo
 	req := ireq
 
 	var timer *time.Timer
+	var atomicWasCanceled int32 // atomic bool (1 or 0)
+	var wasCanceled = alwaysFalse
 	if c.Timeout > 0 {
+		wasCanceled = func() bool { return atomic.LoadInt32(&atomicWasCanceled) != 0 }
 		type canceler interface {
 			CancelRequest(*Request)
 		}
@@ -325,6 +337,7 @@ func (c *Client) doFollowingRedirects(ireq *Request, shouldRedirect func(int) bo
 			return nil, fmt.Errorf("net/http: Client Transport of type %T doesn't support CancelRequest; Timeout not supported", c.transport())
 		}
 		timer = time.AfterFunc(c.Timeout, func() {
+			atomic.StoreInt32(&atomicWasCanceled, 1)
 			reqmu.Lock()
 			defer reqmu.Unlock()
 			tr.CancelRequest(req)
@@ -365,6 +378,12 @@ func (c *Client) doFollowingRedirects(ireq *Request, shouldRedirect func(int) bo
 
 		urlStr = req.URL.String()
 		if resp, err = c.send(req); err != nil {
+			if wasCanceled() {
+				err = &httpError{
+					err:     err.Error() + " (Client.Timeout exceeded while awaiting headers)",
+					timeout: true,
+				}
+			}
 			break
 		}
 
@@ -377,7 +396,7 @@ func (c *Client) doFollowingRedirects(ireq *Request, shouldRedirect func(int) bo
 			}
 			resp.Body.Close()
 			if urlStr = resp.Header.Get("Location"); urlStr == "" {
-				err = errors.New(fmt.Sprintf("%d response missing Location header", resp.StatusCode))
+				err = fmt.Errorf("%d response missing Location header", resp.StatusCode)
 				break
 			}
 			base = req.URL
@@ -385,7 +404,11 @@ func (c *Client) doFollowingRedirects(ireq *Request, shouldRedirect func(int) bo
 			continue
 		}
 		if timer != nil {
-			resp.Body = &cancelTimerBody{timer, resp.Body}
+			resp.Body = &cancelTimerBody{
+				t:              timer,
+				rc:             resp.Body,
+				reqWasCanceled: wasCanceled,
+			}
 		}
 		return resp, nil
 	}
@@ -400,7 +423,7 @@ func (c *Client) doFollowingRedirects(ireq *Request, shouldRedirect func(int) bo
 	if redirectFailed {
 		// Special case for Go 1 compatibility: return both the response
 		// and an error if the CheckRedirect function failed.
-		// See http://golang.org/issue/3795
+		// See https://golang.org/issue/3795
 		return resp, urlErr
 	}
 
@@ -421,7 +444,12 @@ func defaultCheckRedirect(req *Request, via []*Request) error {
 //
 // Caller should close resp.Body when done reading from it.
 //
-// Post is a wrapper around DefaultClient.Post
+// If the provided body is an io.Closer, it is closed after the
+// request.
+//
+// Post is a wrapper around DefaultClient.Post.
+//
+// To set custom headers, use NewRequest and DefaultClient.Do.
 func Post(url string, bodyType string, body io.Reader) (resp *Response, err error) {
 	return DefaultClient.Post(url, bodyType, body)
 }
@@ -430,8 +458,10 @@ func Post(url string, bodyType string, body io.Reader) (resp *Response, err erro
 //
 // Caller should close resp.Body when done reading from it.
 //
-// If the provided body is also an io.Closer, it is closed after the
+// If the provided body is an io.Closer, it is closed after the
 // request.
+//
+// To set custom headers, use NewRequest and Client.Do.
 func (c *Client) Post(url string, bodyType string, body io.Reader) (resp *Response, err error) {
 	req, err := NewRequest("POST", url, body)
 	if err != nil {
@@ -444,16 +474,22 @@ func (c *Client) Post(url string, bodyType string, body io.Reader) (resp *Respon
 // PostForm issues a POST to the specified URL, with data's keys and
 // values URL-encoded as the request body.
 //
+// The Content-Type header is set to application/x-www-form-urlencoded.
+// To set other headers, use NewRequest and DefaultClient.Do.
+//
 // When err is nil, resp always contains a non-nil resp.Body.
 // Caller should close resp.Body when done reading from it.
 //
-// PostForm is a wrapper around DefaultClient.PostForm
+// PostForm is a wrapper around DefaultClient.PostForm.
 func PostForm(url string, data url.Values) (resp *Response, err error) {
 	return DefaultClient.PostForm(url, data)
 }
 
 // PostForm issues a POST to the specified URL,
-// with data's keys and values urlencoded as the request body.
+// with data's keys and values URL-encoded as the request body.
+//
+// The Content-Type header is set to application/x-www-form-urlencoded.
+// To set other headers, use NewRequest and DefaultClient.Do.
 //
 // When err is nil, resp always contains a non-nil resp.Body.
 // Caller should close resp.Body when done reading from it.
@@ -461,9 +497,9 @@ func (c *Client) PostForm(url string, data url.Values) (resp *Response, err erro
 	return c.Post(url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
 }
 
-// Head issues a HEAD to the specified URL.  If the response is one of the
-// following redirect codes, Head follows the redirect after calling the
-// Client's CheckRedirect function.
+// Head issues a HEAD to the specified URL.  If the response is one of
+// the following redirect codes, Head follows the redirect, up to a
+// maximum of 10 redirects:
 //
 //    301 (Moved Permanently)
 //    302 (Found)
@@ -477,7 +513,7 @@ func Head(url string) (resp *Response, err error) {
 
 // Head issues a HEAD to the specified URL.  If the response is one of the
 // following redirect codes, Head follows the redirect after calling the
-// Client's CheckRedirect function.
+// Client's CheckRedirect function:
 //
 //    301 (Moved Permanently)
 //    302 (Found)
@@ -491,15 +527,25 @@ func (c *Client) Head(url string) (resp *Response, err error) {
 	return c.doFollowingRedirects(req, shouldRedirectGet)
 }
 
+// cancelTimerBody is an io.ReadCloser that wraps rc with two features:
+// 1) on Read EOF or Close, the timer t is Stopped,
+// 2) On Read failure, if reqWasCanceled is true, the error is wrapped and
+//    marked as net.Error that hit its timeout.
 type cancelTimerBody struct {
-	t  *time.Timer
-	rc io.ReadCloser
+	t              *time.Timer
+	rc             io.ReadCloser
+	reqWasCanceled func() bool
 }
 
 func (b *cancelTimerBody) Read(p []byte) (n int, err error) {
 	n, err = b.rc.Read(p)
 	if err == io.EOF {
 		b.t.Stop()
+	} else if err != nil && b.reqWasCanceled() {
+		return n, &httpError{
+			err:     err.Error() + " (Client.Timeout exceeded while reading body)",
+			timeout: true,
+		}
 	}
 	return
 }
diff --git a/src/net/http/client_test.go b/src/net/http/client_test.go
index 56b6563..7b524d3 100644
--- a/src/net/http/client_test.go
+++ b/src/net/http/client_test.go
@@ -258,7 +258,7 @@ func TestClientRedirects(t *testing.T) {
 		t.Errorf("with redirects forbidden, expected a *url.Error with our 'no redirects allowed' error inside; got %#v (%q)", err, err)
 	}
 	if res == nil {
-		t.Fatalf("Expected a non-nil Response on CheckRedirect failure (http://golang.org/issue/3795)")
+		t.Fatalf("Expected a non-nil Response on CheckRedirect failure (https://golang.org/issue/3795)")
 	}
 	res.Body.Close()
 	if res.Header.Get("Location") == "" {
@@ -334,6 +334,7 @@ var echoCookiesRedirectHandler = HandlerFunc(func(w ResponseWriter, r *Request)
 })
 
 func TestClientSendsCookieFromJar(t *testing.T) {
+	defer afterTest(t)
 	tr := &recordingTransport{}
 	client := &Client{Transport: tr}
 	client.Jar = &TestJar{perURL: make(map[string][]*Cookie)}
@@ -426,7 +427,7 @@ func TestJarCalls(t *testing.T) {
 	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
 		pathSuffix := r.RequestURI[1:]
 		if r.RequestURI == "/nosetcookie" {
-			return // dont set cookies for this path
+			return // don't set cookies for this path
 		}
 		SetCookie(w, &Cookie{Name: "name" + pathSuffix, Value: "val" + pathSuffix})
 		if r.RequestURI == "/" {
@@ -738,7 +739,7 @@ func TestResponseSetsTLSConnectionState(t *testing.T) {
 	}
 }
 
-// Verify Response.ContentLength is populated. http://golang.org/issue/4126
+// Verify Response.ContentLength is populated. https://golang.org/issue/4126
 func TestClientHeadContentLength(t *testing.T) {
 	defer afterTest(t)
 	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
@@ -842,6 +843,47 @@ func TestBasicAuth(t *testing.T) {
 	}
 }
 
+func TestBasicAuthHeadersPreserved(t *testing.T) {
+	defer afterTest(t)
+	tr := &recordingTransport{}
+	client := &Client{Transport: tr}
+
+	// If Authorization header is provided, username in URL should not override it
+	url := "http://My%20User@dummy.faketld/"
+	req, err := NewRequest("GET", url, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	req.SetBasicAuth("My User", "My Pass")
+	expected := "My User:My Pass"
+	client.Do(req)
+
+	if tr.req.Method != "GET" {
+		t.Errorf("got method %q, want %q", tr.req.Method, "GET")
+	}
+	if tr.req.URL.String() != url {
+		t.Errorf("got URL %q, want %q", tr.req.URL.String(), url)
+	}
+	if tr.req.Header == nil {
+		t.Fatalf("expected non-nil request Header")
+	}
+	auth := tr.req.Header.Get("Authorization")
+	if strings.HasPrefix(auth, "Basic ") {
+		encoded := auth[6:]
+		decoded, err := base64.StdEncoding.DecodeString(encoded)
+		if err != nil {
+			t.Fatal(err)
+		}
+		s := string(decoded)
+		if expected != s {
+			t.Errorf("Invalid Authorization header. Got %q, wanted %q", s, expected)
+		}
+	} else {
+		t.Errorf("Invalid auth %q", auth)
+	}
+
+}
+
 func TestClientTimeout(t *testing.T) {
 	if testing.Short() {
 		t.Skip("skipping in short mode")
@@ -899,14 +941,64 @@ func TestClientTimeout(t *testing.T) {
 	select {
 	case err := <-errc:
 		if err == nil {
-			t.Error("expected error from ReadAll")
+			t.Fatal("expected error from ReadAll")
+		}
+		ne, ok := err.(net.Error)
+		if !ok {
+			t.Errorf("error value from ReadAll was %T; expected some net.Error", err)
+		} else if !ne.Timeout() {
+			t.Errorf("net.Error.Timeout = false; want true")
+		}
+		if got := ne.Error(); !strings.Contains(got, "Client.Timeout exceeded") {
+			t.Errorf("error string = %q; missing timeout substring", got)
 		}
-		// Expected error.
 	case <-time.After(failTime):
 		t.Errorf("timeout after %v waiting for timeout of %v", failTime, timeout)
 	}
 }
 
+// Client.Timeout firing before getting to the body
+func TestClientTimeout_Headers(t *testing.T) {
+	if testing.Short() {
+		t.Skip("skipping in short mode")
+	}
+	defer afterTest(t)
+	donec := make(chan bool)
+	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+		<-donec
+	}))
+	defer ts.Close()
+	// Note that we use a channel send here and not a close.
+	// The race detector doesn't know that we're waiting for a timeout
+	// and thinks that the waitgroup inside httptest.Server is added to concurrently
+	// with us closing it. If we timed out immediately, we could close the testserver
+	// before we entered the handler. We're not timing out immediately and there's
+	// no way we would be done before we entered the handler, but the race detector
+	// doesn't know this, so synchronize explicitly.
+	defer func() { donec <- true }()
+
+	c := &Client{Timeout: 500 * time.Millisecond}
+
+	_, err := c.Get(ts.URL)
+	if err == nil {
+		t.Fatal("got response from Get; expected error")
+	}
+	ue, ok := err.(*url.Error)
+	if !ok {
+		t.Fatalf("Got error of type %T; want *url.Error", err)
+	}
+	ne, ok := ue.Err.(net.Error)
+	if !ok {
+		t.Fatalf("Got url.Error.Err of type %T; want some net.Error", err)
+	}
+	if !ne.Timeout() {
+		t.Error("net.Error.Timeout = false; want true")
+	}
+	if got := ne.Error(); !strings.Contains(got, "Client.Timeout exceeded") {
+		t.Errorf("error string = %q; missing timeout substring", got)
+	}
+}
+
 func TestClientRedirectEatsBody(t *testing.T) {
 	defer afterTest(t)
 	saw := make(chan string, 2)
@@ -984,24 +1076,12 @@ func TestClientTrailers(t *testing.T) {
 				r.Trailer.Get("Client-Trailer-B"))
 		}
 
-		// TODO: golang.org/issue/7759: there's no way yet for
-		// the server to set trailers without hijacking, so do
-		// that for now, just to test the client.  Later, in
-		// Go 1.4, it should be implicit that any mutations
-		// to w.Header() after the initial write are the
-		// trailers to be sent, if and only if they were
-		// previously declared with w.Header().Set("Trailer",
-		// ..keys..)
-		w.(Flusher).Flush()
-		conn, buf, _ := w.(Hijacker).Hijack()
-		t := Header{}
-		t.Set("Server-Trailer-A", "valuea")
-		t.Set("Server-Trailer-C", "valuec") // skipping B
-		buf.WriteString("0\r\n")            // eof
-		t.Write(buf)
-		buf.WriteString("\r\n") // end of trailers
-		buf.Flush()
-		conn.Close()
+		// How handlers set Trailers: declare it ahead of time
+		// with the Trailer header, and then mutate the
+		// Header() of those values later, after the response
+		// has been written (we wrote to w above).
+		w.Header().Set("Server-Trailer-A", "valuea")
+		w.Header().Set("Server-Trailer-C", "valuec") // skipping B
 	}))
 	defer ts.Close()
 
diff --git a/src/net/http/cookie.go b/src/net/http/cookie.go
index a0d0fdb..648709d 100644
--- a/src/net/http/cookie.go
+++ b/src/net/http/cookie.go
@@ -14,19 +14,18 @@ import (
 	"time"
 )
 
-// This implementation is done according to RFC 6265:
-//
-//    http://tools.ietf.org/html/rfc6265
-
 // A Cookie represents an HTTP cookie as sent in the Set-Cookie header of an
 // HTTP response or the Cookie header of an HTTP request.
+//
+// See http://tools.ietf.org/html/rfc6265 for details.
 type Cookie struct {
-	Name       string
-	Value      string
-	Path       string
-	Domain     string
-	Expires    time.Time
-	RawExpires string
+	Name  string
+	Value string
+
+	Path       string    // optional
+	Domain     string    // optional
+	Expires    time.Time // optional
+	RawExpires string    // for reading cookies only
 
 	// MaxAge=0 means no 'Max-Age' attribute specified.
 	// MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0'
@@ -126,14 +125,22 @@ func readSetCookies(h Header) []*Cookie {
 }
 
 // SetCookie adds a Set-Cookie header to the provided ResponseWriter's headers.
+// The provided cookie must have a valid Name. Invalid cookies may be
+// silently dropped.
 func SetCookie(w ResponseWriter, cookie *Cookie) {
-	w.Header().Add("Set-Cookie", cookie.String())
+	if v := cookie.String(); v != "" {
+		w.Header().Add("Set-Cookie", v)
+	}
 }
 
 // String returns the serialization of the cookie for use in a Cookie
 // header (if only Name and Value are set) or a Set-Cookie response
 // header (if other fields are set).
+// If c is nil or c.Name is invalid, the empty string is returned.
 func (c *Cookie) String() string {
+	if c == nil || !isCookieNameValid(c.Name) {
+		return ""
+	}
 	var b bytes.Buffer
 	fmt.Fprintf(&b, "%s=%s", sanitizeCookieName(c.Name), sanitizeCookieValue(c.Value))
 	if len(c.Path) > 0 {
@@ -156,7 +163,7 @@ func (c *Cookie) String() string {
 		}
 	}
 	if c.Expires.Unix() > 0 {
-		fmt.Fprintf(&b, "; Expires=%s", c.Expires.UTC().Format(time.RFC1123))
+		fmt.Fprintf(&b, "; Expires=%s", c.Expires.UTC().Format(TimeFormat))
 	}
 	if c.MaxAge > 0 {
 		fmt.Fprintf(&b, "; Max-Age=%d", c.MaxAge)
@@ -297,7 +304,7 @@ func sanitizeCookieName(n string) string {
 // We loosen this as spaces and commas are common in cookie values
 // but we produce a quoted cookie-value in when value starts or ends
 // with a comma or space.
-// See http://golang.org/issue/7243 for the discussion.
+// See https://golang.org/issue/7243 for the discussion.
 func sanitizeCookieValue(v string) string {
 	v = sanitizeOrWarn("Cookie.Value", validCookieValueByte, v)
 	if len(v) == 0 {
@@ -359,5 +366,8 @@ func parseCookieValue(raw string, allowDoubleQuote bool) (string, bool) {
 }
 
 func isCookieNameValid(raw string) bool {
+	if raw == "" {
+		return false
+	}
 	return strings.IndexFunc(raw, isNotToken) < 0
 }
diff --git a/src/net/http/cookie_test.go b/src/net/http/cookie_test.go
index 98dc2fa..d474f31 100644
--- a/src/net/http/cookie_test.go
+++ b/src/net/http/cookie_test.go
@@ -52,6 +52,10 @@ var writeSetCookiesTests = []struct {
 		&Cookie{Name: "cookie-8", Value: "eight", Domain: "::1"},
 		"cookie-8=eight",
 	},
+	{
+		&Cookie{Name: "cookie-9", Value: "expiring", Expires: time.Unix(1257894000, 0)},
+		"cookie-9=expiring; Expires=Tue, 10 Nov 2009 23:00:00 GMT",
+	},
 	// The "special" cookies have values containing commas or spaces which
 	// are disallowed by RFC 6265 but are common in the wild.
 	{
@@ -90,6 +94,18 @@ var writeSetCookiesTests = []struct {
 		&Cookie{Name: "empty-value", Value: ""},
 		`empty-value=`,
 	},
+	{
+		nil,
+		``,
+	},
+	{
+		&Cookie{Name: ""},
+		``,
+	},
+	{
+		&Cookie{Name: "\t"},
+		``,
+	},
 }
 
 func TestWriteSetCookies(t *testing.T) {
@@ -349,7 +365,7 @@ func TestSetCookieDoubleQuotes(t *testing.T) {
 		{Name: "quoted3", Value: "both"},
 	}
 	if len(got) != len(want) {
-		t.Fatal("got %d cookies, want %d", len(got), len(want))
+		t.Fatalf("got %d cookies, want %d", len(got), len(want))
 	}
 	for i, w := range want {
 		g := got[i]
diff --git a/src/net/http/example_test.go b/src/net/http/example_test.go
index 88b97d9..1774795 100644
--- a/src/net/http/example_test.go
+++ b/src/net/http/example_test.go
@@ -6,6 +6,7 @@ package http_test
 
 import (
 	"fmt"
+	"io"
 	"io/ioutil"
 	"log"
 	"net/http"
@@ -86,3 +87,25 @@ func ExampleServeMux_Handle() {
 		fmt.Fprintf(w, "Welcome to the home page!")
 	})
 }
+
+// HTTP Trailers are a set of key/value pairs like headers that come
+// after the HTTP response, instead of before.
+func ExampleResponseWriter_trailers() {
+	mux := http.NewServeMux()
+	mux.HandleFunc("/sendstrailers", func(w http.ResponseWriter, req *http.Request) {
+		// Before any call to WriteHeader or Write, declare
+		// the trailers you will set during the HTTP
+		// response. These three headers are actually sent in
+		// the trailer.
+		w.Header().Set("Trailer", "AtEnd1, AtEnd2")
+		w.Header().Add("Trailer", "AtEnd3")
+
+		w.Header().Set("Content-Type", "text/plain; charset=utf-8") // normal header
+		w.WriteHeader(http.StatusOK)
+
+		w.Header().Set("AtEnd1", "value 1")
+		io.WriteString(w, "This HTTP response has both headers before this text and trailers at the end.\n")
+		w.Header().Set("AtEnd2", "value 2")
+		w.Header().Set("AtEnd3", "value 3") // These will appear as trailers.
+	})
+}
diff --git a/src/net/http/export_test.go b/src/net/http/export_test.go
index 87b6c07..0457be5 100644
--- a/src/net/http/export_test.go
+++ b/src/net/http/export_test.go
@@ -10,9 +10,17 @@ package http
 import (
 	"net"
 	"net/url"
+	"sync"
 	"time"
 )
 
+func init() {
+	// We only want to pay for this cost during testing.
+	// When not under test, these values are always nil
+	// and never assigned to.
+	testHookMu = new(sync.Mutex)
+}
+
 func NewLoggingConn(baseName string, c net.Conn) net.Conn {
 	return newLoggingConn(baseName, c)
 }
@@ -78,6 +86,20 @@ func (t *Transport) PutIdleTestConn() bool {
 	})
 }
 
+func SetInstallConnClosedHook(f func()) {
+	testHookPersistConnClosedGotRes = f
+}
+
+func SetEnterRoundTripHook(f func()) {
+	testHookEnterRoundTrip = f
+}
+
+func SetReadLoopBeforeNextReadHook(f func()) {
+	testHookMu.Lock()
+	defer testHookMu.Unlock()
+	testHookReadLoopBeforeNextRead = f
+}
+
 func NewTestTimeoutHandler(handler Handler, ch <-chan time.Time) Handler {
 	f := func() <-chan time.Time {
 		return ch
@@ -106,3 +128,5 @@ func SetPendingDialHooks(before, after func()) {
 var ExportServerNewConn = (*Server).newConn
 
 var ExportCloseWriteAndWait = (*conn).closeWriteAndWait
+
+var ExportErrRequestCanceled = errRequestCanceled
diff --git a/src/net/http/fcgi/child.go b/src/net/http/fcgi/child.go
index a3beaa3..da824ed 100644
--- a/src/net/http/fcgi/child.go
+++ b/src/net/http/fcgi/child.go
@@ -144,6 +144,7 @@ func newChild(rwc io.ReadWriteCloser, handler http.Handler) *child {
 
 func (c *child) serve() {
 	defer c.conn.Close()
+	defer c.cleanUp()
 	var rec record
 	for {
 		if err := rec.read(c.conn.rwc); err != nil {
@@ -159,6 +160,14 @@ var errCloseConn = errors.New("fcgi: connection should be closed")
 
 var emptyBody = ioutil.NopCloser(strings.NewReader(""))
 
+// ErrRequestAborted is returned by Read when a handler attempts to read the
+// body of a request that has been aborted by the web server.
+var ErrRequestAborted = errors.New("fcgi: request aborted by web server")
+
+// ErrConnClosed is returned by Read when a handler attempts to read the body of
+// a request after the connection to the web server has been closed.
+var ErrConnClosed = errors.New("fcgi: connection to web server closed")
+
 func (c *child) handleRecord(rec *record) error {
 	c.mu.Lock()
 	req, ok := c.requests[rec.h.Id]
@@ -227,11 +236,13 @@ func (c *child) handleRecord(rec *record) error {
 		// If the filter role is implemented, read the data stream here.
 		return nil
 	case typeAbortRequest:
-		println("abort")
 		c.mu.Lock()
 		delete(c.requests, rec.h.Id)
 		c.mu.Unlock()
 		c.conn.writeEndRequest(rec.h.Id, 0, statusRequestComplete)
+		if req.pw != nil {
+			req.pw.CloseWithError(ErrRequestAborted)
+		}
 		if !req.keepConn {
 			// connection will close upon return
 			return errCloseConn
@@ -277,6 +288,18 @@ func (c *child) serveRequest(req *request, body io.ReadCloser) {
 	}
 }
 
+func (c *child) cleanUp() {
+	c.mu.Lock()
+	defer c.mu.Unlock()
+	for _, req := range c.requests {
+		if req.pw != nil {
+			// race with call to Close in c.serveRequest doesn't matter because
+			// Pipe(Reader|Writer).Close are idempotent
+			req.pw.CloseWithError(ErrConnClosed)
+		}
+	}
+}
+
 // Serve accepts incoming FastCGI connections on the listener l, creating a new
 // goroutine for each. The goroutine reads requests and then calls handler
 // to reply to them.
diff --git a/src/net/http/fcgi/fcgi_test.go b/src/net/http/fcgi/fcgi_test.go
index 6c7e1a9..de0f7f8 100644
--- a/src/net/http/fcgi/fcgi_test.go
+++ b/src/net/http/fcgi/fcgi_test.go
@@ -8,6 +8,8 @@ import (
 	"bytes"
 	"errors"
 	"io"
+	"io/ioutil"
+	"net/http"
 	"testing"
 )
 
@@ -148,3 +150,107 @@ func TestGetValues(t *testing.T) {
 		t.Errorf(" got: %q\nwant: %q\n", got, want)
 	}
 }
+
+func nameValuePair11(nameData, valueData string) []byte {
+	return bytes.Join(
+		[][]byte{
+			{byte(len(nameData)), byte(len(valueData))},
+			[]byte(nameData),
+			[]byte(valueData),
+		},
+		nil,
+	)
+}
+
+func makeRecord(
+	recordType recType,
+	requestId uint16,
+	contentData []byte,
+) []byte {
+	requestIdB1 := byte(requestId >> 8)
+	requestIdB0 := byte(requestId)
+
+	contentLength := len(contentData)
+	contentLengthB1 := byte(contentLength >> 8)
+	contentLengthB0 := byte(contentLength)
+	return bytes.Join([][]byte{
+		{1, byte(recordType), requestIdB1, requestIdB0, contentLengthB1,
+			contentLengthB0, 0, 0},
+		contentData,
+	},
+		nil)
+}
+
+// a series of FastCGI records that start a request and begin sending the
+// request body
+var streamBeginTypeStdin = bytes.Join([][]byte{
+	// set up request 1
+	makeRecord(typeBeginRequest, 1,
+		[]byte{0, byte(roleResponder), 0, 0, 0, 0, 0, 0}),
+	// add required parameters to request 1
+	makeRecord(typeParams, 1, nameValuePair11("REQUEST_METHOD", "GET")),
+	makeRecord(typeParams, 1, nameValuePair11("SERVER_PROTOCOL", "HTTP/1.1")),
+	makeRecord(typeParams, 1, nil),
+	// begin sending body of request 1
+	makeRecord(typeStdin, 1, []byte("0123456789abcdef")),
+},
+	nil)
+
+var cleanUpTests = []struct {
+	input []byte
+	err   error
+}{
+	// confirm that child.handleRecord closes req.pw after aborting req
+	{
+		bytes.Join([][]byte{
+			streamBeginTypeStdin,
+			makeRecord(typeAbortRequest, 1, nil),
+		},
+			nil),
+		ErrRequestAborted,
+	},
+	// confirm that child.serve closes all pipes after error reading record
+	{
+		bytes.Join([][]byte{
+			streamBeginTypeStdin,
+			nil,
+		},
+			nil),
+		ErrConnClosed,
+	},
+}
+
+type nopWriteCloser struct {
+	io.ReadWriter
+}
+
+func (nopWriteCloser) Close() error {
+	return nil
+}
+
+// Test that child.serve closes the bodies of aborted requests and closes the
+// bodies of all requests before returning. Causes deadlock if either condition
+// isn't met. See issue 6934.
+func TestChildServeCleansUp(t *testing.T) {
+	for _, tt := range cleanUpTests {
+		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,
+			r *http.Request,
+		) {
+			// block on reading body of request
+			_, err := io.Copy(ioutil.Discard, r.Body)
+			if err != tt.err {
+				t.Errorf("Expected %#v, got %#v", tt.err, err)
+			}
+			// not reached if body of request isn't closed
+			done <- true
+		}))
+		go c.serve()
+		// wait for body of request to be closed or all goroutines to block
+		<-done
+	}
+}
diff --git a/src/net/http/fs.go b/src/net/http/fs.go
index e322f71..7572023 100644
--- a/src/net/http/fs.go
+++ b/src/net/http/fs.go
@@ -102,10 +102,10 @@ func dirList(w ResponseWriter, f File) {
 // 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 @@ func serveContent(w ResponseWriter, r *Request, name string, modtime time.Time,
 	}
 }
 
+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
 	}
 
@@ -353,16 +358,16 @@ func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirec
 
 	f, err := fs.Open(name)
 	if err != nil {
-		// TODO expose actual error?
-		NotFound(w, r)
+		msg, code := toHTTPError(err)
+		Error(w, msg, code)
 		return
 	}
 	defer f.Close()
 
 	d, err1 := f.Stat()
 	if err1 != nil {
-		// TODO expose actual error?
-		NotFound(w, r)
+		msg, code := toHTTPError(err)
+		Error(w, msg, code)
 		return
 	}
 
@@ -412,6 +417,22 @@ func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirec
 	serveContent(w, r, d.Name(), d.ModTime(), sizeFunc, f)
 }
 
+// toHTTPError returns a non-specific HTTP error message and status code
+// for a given non-nil error value. It's important that toHTTPError does not
+// actually return err.Error(), since msg and httpStatus are returned to users,
+// and historically Go's ServeContent always returned just "404 Not Found" for
+// all errors. We don't want to start leaking information in error messages.
+func toHTTPError(err error) (msg string, httpStatus int) {
+	if os.IsNotExist(err) {
+		return "404 page not found", StatusNotFound
+	}
+	if os.IsPermission(err) {
+		return "403 Forbidden", StatusForbidden
+	}
+	// Default:
+	return "500 Internal Server Error", StatusInternalServerError
+}
+
 // localRedirect gives a Moved Permanently response.
 // It does not convert relative paths to absolute paths like Redirect does.
 func localRedirect(w ResponseWriter, r *Request, newPath string) {
@@ -422,7 +443,13 @@ func localRedirect(w ResponseWriter, r *Request, newPath string) {
 	w.WriteHeader(StatusMovedPermanently)
 }
 
-// ServeFile replies to the request with the contents of the named file or directory.
+// ServeFile replies to the request with the contents of the named
+// file or directory.
+//
+// As a special case, ServeFile redirects any request where r.URL.Path
+// ends in "/index.html" to the same path, without the final
+// "index.html". To avoid such redirects either modify the path or
+// use ServeContent.
 func ServeFile(w ResponseWriter, r *Request, name string) {
 	dir, file := filepath.Split(name)
 	serveFile(w, r, Dir(dir), file, false)
@@ -439,6 +466,10 @@ type fileHandler struct {
 // use http.Dir:
 //
 //     http.Handle("/", http.FileServer(http.Dir("/tmp")))
+//
+// As a special case, the returned file server redirects any request
+// ending in "/index.html" to the same path, without the final
+// "index.html".
 func FileServer(root FileSystem) Handler {
 	return &fileHandler{root}
 }
@@ -503,7 +534,7 @@ func parseRange(s string, size int64) ([]httpRange, error) {
 			r.length = size - r.start
 		} else {
 			i, err := strconv.ParseInt(start, 10, 64)
-			if err != nil || i > size || i < 0 {
+			if err != nil || i >= size || i < 0 {
 				return nil, errors.New("invalid range")
 			}
 			r.start = i
diff --git a/src/net/http/fs_test.go b/src/net/http/fs_test.go
index 8770d9b..794dabc 100644
--- a/src/net/http/fs_test.go
+++ b/src/net/http/fs_test.go
@@ -50,15 +50,23 @@ var ServeFileRangeTests = []struct {
 	{r: "bytes=2-", code: StatusPartialContent, ranges: []wantRange{{2, testFileLen}}},
 	{r: "bytes=-5", code: StatusPartialContent, ranges: []wantRange{{testFileLen - 5, testFileLen}}},
 	{r: "bytes=3-7", code: StatusPartialContent, ranges: []wantRange{{3, 8}}},
-	{r: "bytes=20-", code: StatusRequestedRangeNotSatisfiable},
 	{r: "bytes=0-0,-2", code: StatusPartialContent, ranges: []wantRange{{0, 1}, {testFileLen - 2, testFileLen}}},
 	{r: "bytes=0-1,5-8", code: StatusPartialContent, ranges: []wantRange{{0, 2}, {5, 9}}},
 	{r: "bytes=0-1,5-", code: StatusPartialContent, ranges: []wantRange{{0, 2}, {5, testFileLen}}},
 	{r: "bytes=5-1000", code: StatusPartialContent, ranges: []wantRange{{5, testFileLen}}},
 	{r: "bytes=0-,1-,2-,3-,4-", code: StatusOK}, // ignore wasteful range request
-	{r: "bytes=0-" + itoa(testFileLen-2), code: StatusPartialContent, ranges: []wantRange{{0, testFileLen - 1}}},
-	{r: "bytes=0-" + itoa(testFileLen-1), code: StatusPartialContent, ranges: []wantRange{{0, testFileLen}}},
-	{r: "bytes=0-" + itoa(testFileLen), code: StatusPartialContent, ranges: []wantRange{{0, testFileLen}}},
+	{r: "bytes=0-9", code: StatusPartialContent, ranges: []wantRange{{0, testFileLen - 1}}},
+	{r: "bytes=0-10", code: StatusPartialContent, ranges: []wantRange{{0, testFileLen}}},
+	{r: "bytes=0-11", code: StatusPartialContent, ranges: []wantRange{{0, testFileLen}}},
+	{r: "bytes=10-11", code: StatusPartialContent, ranges: []wantRange{{testFileLen - 1, testFileLen}}},
+	{r: "bytes=10-", code: StatusPartialContent, ranges: []wantRange{{testFileLen - 1, testFileLen}}},
+	{r: "bytes=11-", code: StatusRequestedRangeNotSatisfiable},
+	{r: "bytes=11-12", code: StatusRequestedRangeNotSatisfiable},
+	{r: "bytes=12-12", code: StatusRequestedRangeNotSatisfiable},
+	{r: "bytes=11-100", code: StatusRequestedRangeNotSatisfiable},
+	{r: "bytes=12-100", code: StatusRequestedRangeNotSatisfiable},
+	{r: "bytes=100-", code: StatusRequestedRangeNotSatisfiable},
+	{r: "bytes=100-1000", code: StatusRequestedRangeNotSatisfiable},
 }
 
 func TestServeFile(t *testing.T) {
@@ -489,6 +497,7 @@ type fakeFileInfo struct {
 	modtime  time.Time
 	ents     []*fakeFileInfo
 	contents string
+	err      error
 }
 
 func (f *fakeFileInfo) Name() string       { return f.basename }
@@ -541,6 +550,9 @@ func (fs fakeFS) Open(name string) (File, error) {
 	if !ok {
 		return nil, os.ErrNotExist
 	}
+	if f.err != nil {
+		return nil, f.err
+	}
 	return &fakeFile{ReadSeeker: strings.NewReader(f.contents), fi: f, path: name}, nil
 }
 
@@ -743,6 +755,12 @@ func TestServeContent(t *testing.T) {
 			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
@@ -789,6 +807,31 @@ func TestServeContent(t *testing.T) {
 	}
 }
 
+func TestServeContentErrorMessages(t *testing.T) {
+	defer afterTest(t)
+	fs := fakeFS{
+		"/500": &fakeFileInfo{
+			err: errors.New("random error"),
+		},
+		"/403": &fakeFileInfo{
+			err: &os.PathError{Err: os.ErrPermission},
+		},
+	}
+	ts := httptest.NewServer(FileServer(fs))
+	defer ts.Close()
+	for _, code := range []int{403, 404, 500} {
+		res, err := DefaultClient.Get(fmt.Sprintf("%s/%d", ts.URL, code))
+		if err != nil {
+			t.Errorf("Error fetching /%d: %v", code, err)
+			continue
+		}
+		if res.StatusCode != code {
+			t.Errorf("For /%d, status code = %d; want %d", code, res.StatusCode, code)
+		}
+		res.Body.Close()
+	}
+}
+
 // verifies that sendfile is being used on Linux
 func TestLinuxSendfile(t *testing.T) {
 	defer afterTest(t)
diff --git a/src/net/http/http_test.go b/src/net/http/http_test.go
new file mode 100644
index 0000000..dead3b0
--- /dev/null
+++ b/src/net/http/http_test.go
@@ -0,0 +1,58 @@
+// 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.
+
+// Tests of internal functions with no better homes.
+
+package http
+
+import (
+	"reflect"
+	"testing"
+)
+
+func TestForeachHeaderElement(t *testing.T) {
+	tests := []struct {
+		in   string
+		want []string
+	}{
+		{"Foo", []string{"Foo"}},
+		{" Foo", []string{"Foo"}},
+		{"Foo ", []string{"Foo"}},
+		{" Foo ", []string{"Foo"}},
+
+		{"foo", []string{"foo"}},
+		{"anY-cAsE", []string{"anY-cAsE"}},
+
+		{"", nil},
+		{",,,,  ,  ,,   ,,, ,", nil},
+
+		{" Foo,Bar, Baz,lower,,Quux ", []string{"Foo", "Bar", "Baz", "lower", "Quux"}},
+	}
+	for _, tt := range tests {
+		var got []string
+		foreachHeaderElement(tt.in, func(v string) {
+			got = append(got, v)
+		})
+		if !reflect.DeepEqual(got, tt.want) {
+			t.Errorf("foreachHeaderElement(%q) = %q; want %q", tt.in, got, tt.want)
+		}
+	}
+}
+
+func TestCleanHost(t *testing.T) {
+	tests := []struct {
+		in, want string
+	}{
+		{"www.google.com", "www.google.com"},
+		{"www.google.com foo", "www.google.com"},
+		{"www.google.com/foo", "www.google.com"},
+		{" first character is a space", ""},
+	}
+	for _, tt := range tests {
+		got := cleanHost(tt.in)
+		if tt.want != got {
+			t.Errorf("cleanHost(%q) = %q, want %q", tt.in, got, tt.want)
+		}
+	}
+}
diff --git a/src/net/http/httptest/server.go b/src/net/http/httptest/server.go
index 789e7bf..96eb0ef 100644
--- a/src/net/http/httptest/server.go
+++ b/src/net/http/httptest/server.go
@@ -204,25 +204,35 @@ func (h *waitGroupHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 // "127.0.0.1" and "[::1]", expiring at the last second of 2049 (the end
 // of ASN.1 time).
 // generated from src/crypto/tls:
-// go run generate_cert.go  --rsa-bits 512 --host 127.0.0.1,::1,example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h
+// go run generate_cert.go  --rsa-bits 1024 --host 127.0.0.1,::1,example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h
 var localhostCert = []byte(`-----BEGIN CERTIFICATE-----
-MIIBdzCCASOgAwIBAgIBADALBgkqhkiG9w0BAQUwEjEQMA4GA1UEChMHQWNtZSBD
-bzAeFw03MDAxMDEwMDAwMDBaFw00OTEyMzEyMzU5NTlaMBIxEDAOBgNVBAoTB0Fj
-bWUgQ28wWjALBgkqhkiG9w0BAQEDSwAwSAJBAN55NcYKZeInyTuhcCwFMhDHCmwa
-IUSdtXdcbItRB/yfXGBhiex00IaLXQnSU+QZPRZWYqeTEbFSgihqi1PUDy8CAwEA
-AaNoMGYwDgYDVR0PAQH/BAQDAgCkMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA8GA1Ud
-EwEB/wQFMAMBAf8wLgYDVR0RBCcwJYILZXhhbXBsZS5jb22HBH8AAAGHEAAAAAAA
-AAAAAAAAAAAAAAEwCwYJKoZIhvcNAQEFA0EAAoQn/ytgqpiLcZu9XKbCJsJcvkgk
-Se6AbGXgSlq+ZCEVo0qIwSgeBqmsJxUu7NCSOwVJLYNEBO2DtIxoYVk+MA==
+MIICEzCCAXygAwIBAgIQMIMChMLGrR+QvmQvpwAU6zANBgkqhkiG9w0BAQsFADAS
+MRAwDgYDVQQKEwdBY21lIENvMCAXDTcwMDEwMTAwMDAwMFoYDzIwODQwMTI5MTYw
+MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCB
+iQKBgQDuLnQAI3mDgey3VBzWnB2L39JUU4txjeVE6myuDqkM/uGlfjb9SjY1bIw4
+iA5sBBZzHi3z0h1YV8QPuxEbi4nW91IJm2gsvvZhIrCHS3l6afab4pZBl2+XsDul
+rKBxKKtD1rGxlG4LjncdabFn9gvLZad2bSysqz/qTAUStTvqJQIDAQABo2gwZjAO
+BgNVHQ8BAf8EBAMCAqQwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0TAQH/BAUw
+AwEB/zAuBgNVHREEJzAlggtleGFtcGxlLmNvbYcEfwAAAYcQAAAAAAAAAAAAAAAA
+AAAAATANBgkqhkiG9w0BAQsFAAOBgQCEcetwO59EWk7WiJsG4x8SY+UIAA+flUI9
+tyC4lNhbcF2Idq9greZwbYCqTTTr2XiRNSMLCOjKyI7ukPoPjo16ocHj+P3vZGfs
+h1fIw3cSS2OolhloGw/XM6RWPWtPAlGykKLciQrBru5NAPvCMsb/I1DAceTiotQM
+fblo6RBxUQ==
 -----END CERTIFICATE-----`)
 
 // localhostKey is the private key for localhostCert.
 var localhostKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
-MIIBPAIBAAJBAN55NcYKZeInyTuhcCwFMhDHCmwaIUSdtXdcbItRB/yfXGBhiex0
-0IaLXQnSU+QZPRZWYqeTEbFSgihqi1PUDy8CAwEAAQJBAQdUx66rfh8sYsgfdcvV
-NoafYpnEcB5s4m/vSVe6SU7dCK6eYec9f9wpT353ljhDUHq3EbmE4foNzJngh35d
-AekCIQDhRQG5Li0Wj8TM4obOnnXUXf1jRv0UkzE9AHWLG5q3AwIhAPzSjpYUDjVW
-MCUXgckTpKCuGwbJk7424Nb8bLzf3kllAiA5mUBgjfr/WtFSJdWcPQ4Zt9KTMNKD
-EUO0ukpTwEIl6wIhAMbGqZK3zAAFdq8DD2jPx+UJXnh0rnOkZBzDtJ6/iN69AiEA
-1Aq8MJgTaYsDQWyU/hDq5YkDJc9e9DSCvUIzqxQWMQE=
+MIICXgIBAAKBgQDuLnQAI3mDgey3VBzWnB2L39JUU4txjeVE6myuDqkM/uGlfjb9
+SjY1bIw4iA5sBBZzHi3z0h1YV8QPuxEbi4nW91IJm2gsvvZhIrCHS3l6afab4pZB
+l2+XsDulrKBxKKtD1rGxlG4LjncdabFn9gvLZad2bSysqz/qTAUStTvqJQIDAQAB
+AoGAGRzwwir7XvBOAy5tM/uV6e+Zf6anZzus1s1Y1ClbjbE6HXbnWWF/wbZGOpet
+3Zm4vD6MXc7jpTLryzTQIvVdfQbRc6+MUVeLKwZatTXtdZrhu+Jk7hx0nTPy8Jcb
+uJqFk541aEw+mMogY/xEcfbWd6IOkp+4xqjlFLBEDytgbIECQQDvH/E6nk+hgN4H
+qzzVtxxr397vWrjrIgPbJpQvBsafG7b0dA4AFjwVbFLmQcj2PprIMmPcQrooz8vp
+jy4SHEg1AkEA/v13/5M47K9vCxmb8QeD/asydfsgS5TeuNi8DoUBEmiSJwma7FXY
+fFUtxuvL7XvjwjN5B30pNEbc6Iuyt7y4MQJBAIt21su4b3sjXNueLKH85Q+phy2U
+fQtuUE9txblTu14q3N7gHRZB4ZMhFYyDy8CKrN2cPg/Fvyt0Xlp/DoCzjA0CQQDU
+y2ptGsuSmgUtWj3NM9xuwYPm+Z/F84K6+ARYiZ6PYj013sovGKUFfYAqVXVlxtIX
+qyUBnu3X9ps8ZfjLZO7BAkEAlT4R5Yl6cGhaJQYZHOde3JEMhNRcVFMO8dJDaFeo
+f9Oeos0UUothgiDktdQHxdNEwLjQf7lJJBzV+5OtwswCWA==
 -----END RSA PRIVATE KEY-----`)
diff --git a/src/net/http/httputil/dump.go b/src/net/http/httputil/dump.go
index ac8f103..ca2d1cd 100644
--- a/src/net/http/httputil/dump.go
+++ b/src/net/http/httputil/dump.go
@@ -98,6 +98,14 @@ func DumpRequestOut(req *http.Request, body bool) ([]byte, error) {
 	defer pr.Close()
 	defer pw.Close()
 	dr := &delegateReader{c: make(chan io.Reader)}
+
+	t := &http.Transport{
+		Dial: func(net, addr string) (net.Conn, error) {
+			return &dumpConn{io.MultiWriter(&buf, pw), dr}, nil
+		},
+	}
+	defer t.CloseIdleConnections()
+
 	// Wait for the request before replying with a dummy response:
 	go func() {
 		req, err := http.ReadRequest(bufio.NewReader(pr))
@@ -107,16 +115,9 @@ func DumpRequestOut(req *http.Request, body bool) ([]byte, error) {
 			io.Copy(ioutil.Discard, req.Body)
 			req.Body.Close()
 		}
-		dr.c <- strings.NewReader("HTTP/1.1 204 No Content\r\n\r\n")
+		dr.c <- strings.NewReader("HTTP/1.1 204 No Content\r\nConnection: close\r\n\r\n")
 	}()
 
-	t := &http.Transport{
-		DisableKeepAlives: true,
-		Dial: func(net, addr string) (net.Conn, error) {
-			return &dumpConn{io.MultiWriter(&buf, pw), dr}, nil
-		},
-	}
-
 	_, err := t.RoundTrip(reqSend)
 
 	req.Body = save
diff --git a/src/net/http/httputil/dump_test.go b/src/net/http/httputil/dump_test.go
index 024ee5a..ae67e98 100644
--- a/src/net/http/httputil/dump_test.go
+++ b/src/net/http/httputil/dump_test.go
@@ -71,7 +71,7 @@ var dumpTests = []dumpTest{
 
 		WantDumpOut: "GET /foo HTTP/1.1\r\n" +
 			"Host: example.com\r\n" +
-			"User-Agent: Go 1.1 package http\r\n" +
+			"User-Agent: Go-http-client/1.1\r\n" +
 			"Accept-Encoding: gzip\r\n\r\n",
 	},
 
@@ -83,7 +83,7 @@ var dumpTests = []dumpTest{
 
 		WantDumpOut: "GET /foo HTTP/1.1\r\n" +
 			"Host: example.com\r\n" +
-			"User-Agent: Go 1.1 package http\r\n" +
+			"User-Agent: Go-http-client/1.1\r\n" +
 			"Accept-Encoding: gzip\r\n\r\n",
 	},
 
@@ -105,7 +105,7 @@ var dumpTests = []dumpTest{
 
 		WantDumpOut: "POST / HTTP/1.1\r\n" +
 			"Host: post.tld\r\n" +
-			"User-Agent: Go 1.1 package http\r\n" +
+			"User-Agent: Go-http-client/1.1\r\n" +
 			"Content-Length: 6\r\n" +
 			"Accept-Encoding: gzip\r\n\r\n",
 
@@ -130,7 +130,7 @@ var dumpTests = []dumpTest{
 
 		WantDumpOut: "POST / HTTP/1.1\r\n" +
 			"Host: post.tld\r\n" +
-			"User-Agent: Go 1.1 package http\r\n" +
+			"User-Agent: Go-http-client/1.1\r\n" +
 			"Content-Length: 8193\r\n" +
 			"Accept-Encoding: gzip\r\n\r\n" +
 			strings.Repeat("a", 8193),
diff --git a/src/net/http/httputil/reverseproxy.go b/src/net/http/httputil/reverseproxy.go
index ab46370..c8e1132 100644
--- a/src/net/http/httputil/reverseproxy.go
+++ b/src/net/http/httputil/reverseproxy.go
@@ -100,6 +100,27 @@ var hopHeaders = []string{
 	"Upgrade",
 }
 
+type requestCanceler interface {
+	CancelRequest(*http.Request)
+}
+
+type runOnFirstRead struct {
+	io.Reader // optional; nil means empty body
+
+	fn func() // Run before first Read, then set to nil
+}
+
+func (c *runOnFirstRead) Read(bs []byte) (int, error) {
+	if c.fn != nil {
+		c.fn()
+		c.fn = nil
+	}
+	if c.Reader == nil {
+		return 0, io.EOF
+	}
+	return c.Reader.Read(bs)
+}
+
 func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
 	transport := p.Transport
 	if transport == nil {
@@ -109,6 +130,34 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
 	outreq := new(http.Request)
 	*outreq = *req // includes shallow copies of maps, but okay
 
+	if closeNotifier, ok := rw.(http.CloseNotifier); ok {
+		if requestCanceler, ok := transport.(requestCanceler); ok {
+			reqDone := make(chan struct{})
+			defer close(reqDone)
+
+			clientGone := closeNotifier.CloseNotify()
+
+			outreq.Body = struct {
+				io.Reader
+				io.Closer
+			}{
+				Reader: &runOnFirstRead{
+					Reader: outreq.Body,
+					fn: func() {
+						go func() {
+							select {
+							case <-clientGone:
+								requestCanceler.CancelRequest(outreq)
+							case <-reqDone:
+							}
+						}()
+					},
+				},
+				Closer: outreq.Body,
+			}
+		}
+	}
+
 	p.Director(outreq)
 	outreq.Proto = "HTTP/1.1"
 	outreq.ProtoMajor = 1
@@ -148,7 +197,6 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
 		rw.WriteHeader(http.StatusInternalServerError)
 		return
 	}
-	defer res.Body.Close()
 
 	for _, h := range hopHeaders {
 		res.Header.Del(h)
@@ -156,8 +204,28 @@ func (p *ReverseProxy) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
 
 	copyHeader(rw.Header(), res.Header)
 
+	// The "Trailer" header isn't included in the Transport's response,
+	// at least for *http.Transport. Build it up from Trailer.
+	if len(res.Trailer) > 0 {
+		var trailerKeys []string
+		for k := range res.Trailer {
+			trailerKeys = append(trailerKeys, k)
+		}
+		rw.Header().Add("Trailer", strings.Join(trailerKeys, ", "))
+	}
+
 	rw.WriteHeader(res.StatusCode)
+	if len(res.Trailer) > 0 {
+		// Force chunking if we saw a response trailer.
+		// This prevents net/http from calculating the length for short
+		// bodies and adding a Content-Length.
+		if fl, ok := rw.(http.Flusher); ok {
+			fl.Flush()
+		}
+	}
 	p.copyResponse(rw, res.Body)
+	res.Body.Close() // close now, instead of defer, to populate res.Trailer
+	copyHeader(rw.Header(), res.Trailer)
 }
 
 func (p *ReverseProxy) copyResponse(dst io.Writer, src io.Reader) {
diff --git a/src/net/http/httputil/reverseproxy_test.go b/src/net/http/httputil/reverseproxy_test.go
index e9539b4..80a26ab 100644
--- a/src/net/http/httputil/reverseproxy_test.go
+++ b/src/net/http/httputil/reverseproxy_test.go
@@ -7,10 +7,14 @@
 package httputil
 
 import (
+	"bufio"
 	"io/ioutil"
+	"log"
 	"net/http"
 	"net/http/httptest"
 	"net/url"
+	"reflect"
+	"runtime"
 	"strings"
 	"testing"
 	"time"
@@ -41,6 +45,7 @@ func TestReverseProxy(t *testing.T) {
 		if g, e := r.Host, "some-name"; g != e {
 			t.Errorf("backend got Host header %q, want %q", g, e)
 		}
+		w.Header().Set("Trailer", "X-Trailer")
 		w.Header().Set("X-Foo", "bar")
 		w.Header().Set("Upgrade", "foo")
 		w.Header().Set(fakeHopHeader, "foo")
@@ -49,6 +54,7 @@ func TestReverseProxy(t *testing.T) {
 		http.SetCookie(w, &http.Cookie{Name: "flavor", Value: "chocolateChip"})
 		w.WriteHeader(backendStatus)
 		w.Write([]byte(backendResponse))
+		w.Header().Set("X-Trailer", "trailer_value")
 	}))
 	defer backend.Close()
 	backendURL, err := url.Parse(backend.URL)
@@ -83,6 +89,9 @@ func TestReverseProxy(t *testing.T) {
 	if g, e := len(res.Header["Set-Cookie"]), 1; g != e {
 		t.Fatalf("got %d SetCookies, want %d", g, e)
 	}
+	if g, e := res.Trailer, (http.Header{"X-Trailer": nil}); !reflect.DeepEqual(g, e) {
+		t.Errorf("before reading body, Trailer = %#v; want %#v", g, e)
+	}
 	if cookie := res.Cookies()[0]; cookie.Name != "flavor" {
 		t.Errorf("unexpected cookie %q", cookie.Name)
 	}
@@ -90,6 +99,10 @@ func TestReverseProxy(t *testing.T) {
 	if g, e := string(bodyBytes), backendResponse; g != e {
 		t.Errorf("got body %q; expected %q", g, e)
 	}
+	if g, e := res.Trailer.Get("X-Trailer"), "trailer_value"; g != e {
+		t.Errorf("Trailer(X-Trailer) = %q ; want %q", g, e)
+	}
+
 }
 
 func TestXForwardedFor(t *testing.T) {
@@ -211,3 +224,99 @@ func TestReverseProxyFlushInterval(t *testing.T) {
 		t.Error("maxLatencyWriter flushLoop() never exited")
 	}
 }
+
+func TestReverseProxyCancellation(t *testing.T) {
+	if runtime.GOOS == "plan9" {
+		t.Skip("skipping test; see https://golang.org/issue/9554")
+	}
+	const backendResponse = "I am the backend"
+
+	reqInFlight := make(chan struct{})
+	backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		close(reqInFlight)
+
+		select {
+		case <-time.After(10 * time.Second):
+			// Note: this should only happen in broken implementations, and the
+			// closenotify case should be instantaneous.
+			t.Log("Failed to close backend connection")
+			t.Fail()
+		case <-w.(http.CloseNotifier).CloseNotify():
+		}
+
+		w.WriteHeader(http.StatusOK)
+		w.Write([]byte(backendResponse))
+	}))
+
+	defer backend.Close()
+
+	backend.Config.ErrorLog = log.New(ioutil.Discard, "", 0)
+
+	backendURL, err := url.Parse(backend.URL)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	proxyHandler := NewSingleHostReverseProxy(backendURL)
+
+	// Discards errors of the form:
+	// http: proxy error: read tcp 127.0.0.1:44643: use of closed network connection
+	proxyHandler.ErrorLog = log.New(ioutil.Discard, "", 0)
+
+	frontend := httptest.NewServer(proxyHandler)
+	defer frontend.Close()
+
+	getReq, _ := http.NewRequest("GET", frontend.URL, nil)
+	go func() {
+		<-reqInFlight
+		http.DefaultTransport.(*http.Transport).CancelRequest(getReq)
+	}()
+	res, err := http.DefaultClient.Do(getReq)
+	if res != nil {
+		t.Fatal("Non-nil response")
+	}
+	if err == nil {
+		// This should be an error like:
+		// Get http://127.0.0.1:58079: read tcp 127.0.0.1:58079:
+		//    use of closed network connection
+		t.Fatal("DefaultClient.Do() returned nil error")
+	}
+}
+
+func req(t *testing.T, v string) *http.Request {
+	req, err := http.ReadRequest(bufio.NewReader(strings.NewReader(v)))
+	if err != nil {
+		t.Fatal(err)
+	}
+	return req
+}
+
+// Issue 12344
+func TestNilBody(t *testing.T) {
+	backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		w.Write([]byte("hi"))
+	}))
+	defer backend.Close()
+
+	frontend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
+		backURL, _ := url.Parse(backend.URL)
+		rp := NewSingleHostReverseProxy(backURL)
+		r := req(t, "GET / HTTP/1.0\r\n\r\n")
+		r.Body = nil // this accidentally worked in Go 1.4 and below, so keep it working
+		rp.ServeHTTP(w, r)
+	}))
+	defer frontend.Close()
+
+	res, err := http.Get(frontend.URL)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer res.Body.Close()
+	slurp, err := ioutil.ReadAll(res.Body)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if string(slurp) != "hi" {
+		t.Errorf("Got %q; want %q", slurp, "hi")
+	}
+}
diff --git a/src/net/http/internal/chunked.go b/src/net/http/internal/chunked.go
index 9294deb..6d7c698 100644
--- a/src/net/http/internal/chunked.go
+++ b/src/net/http/internal/chunked.go
@@ -173,8 +173,12 @@ func (cw *chunkedWriter) Write(data []byte) (n int, err error) {
 		err = io.ErrShortWrite
 		return
 	}
-	_, err = io.WriteString(cw.Wire, "\r\n")
-
+	if _, err = io.WriteString(cw.Wire, "\r\n"); err != nil {
+		return
+	}
+	if bw, ok := cw.Wire.(*FlushAfterChunkWriter); ok {
+		err = bw.Flush()
+	}
 	return
 }
 
@@ -183,6 +187,15 @@ func (cw *chunkedWriter) Close() error {
 	return err
 }
 
+// FlushAfterChunkWriter signals from the caller of NewChunkedWriter
+// that each chunk should be followed by a flush. It is used by the
+// http.Transport code to keep the buffering behavior for headers and
+// trailers, but flush out chunks aggressively in the middle for
+// request bodies which may be generated slowly. See Issue 6574.
+type FlushAfterChunkWriter struct {
+	*bufio.Writer
+}
+
 func parseHexUint(v []byte) (n uint64, err error) {
 	for _, b := range v {
 		n <<= 4
diff --git a/src/net/http/lex.go b/src/net/http/lex.go
index cb33318..50b14f8 100644
--- a/src/net/http/lex.go
+++ b/src/net/http/lex.go
@@ -4,6 +4,11 @@
 
 package http
 
+import (
+	"strings"
+	"unicode/utf8"
+)
+
 // This file deals with lexical matters of HTTP
 
 var isTokenTable = [127]bool{
@@ -94,3 +99,71 @@ func isToken(r rune) bool {
 func isNotToken(r rune) bool {
 	return !isToken(r)
 }
+
+// headerValuesContainsToken reports whether any string in values
+// contains the provided token, ASCII case-insensitively.
+func headerValuesContainsToken(values []string, token string) bool {
+	for _, v := range values {
+		if headerValueContainsToken(v, token) {
+			return true
+		}
+	}
+	return false
+}
+
+// isOWS reports whether b is an optional whitespace byte, as defined
+// by RFC 7230 section 3.2.3.
+func isOWS(b byte) bool { return b == ' ' || b == '\t' }
+
+// trimOWS returns x with all optional whitespace removes from the
+// beginning and end.
+func trimOWS(x string) string {
+	// TODO: consider using strings.Trim(x, " \t") instead,
+	// if and when it's fast enough. See issue 10292.
+	// But this ASCII-only code will probably always beat UTF-8
+	// aware code.
+	for len(x) > 0 && isOWS(x[0]) {
+		x = x[1:]
+	}
+	for len(x) > 0 && isOWS(x[len(x)-1]) {
+		x = x[:len(x)-1]
+	}
+	return x
+}
+
+// headerValueContainsToken reports whether v (assumed to be a
+// 0#element, in the ABNF extension described in RFC 7230 section 7)
+// contains token amongst its comma-separated tokens, ASCII
+// case-insensitively.
+func headerValueContainsToken(v string, token string) bool {
+	v = trimOWS(v)
+	if comma := strings.IndexByte(v, ','); comma != -1 {
+		return tokenEqual(trimOWS(v[:comma]), token) || headerValueContainsToken(v[comma+1:], token)
+	}
+	return tokenEqual(v, token)
+}
+
+// lowerASCII returns the ASCII lowercase version of b.
+func lowerASCII(b byte) byte {
+	if 'A' <= b && b <= 'Z' {
+		return b + ('a' - 'A')
+	}
+	return b
+}
+
+// tokenEqual reports whether t1 and t2 are equal, ASCII case-insensitively.
+func tokenEqual(t1, t2 string) bool {
+	if len(t1) != len(t2) {
+		return false
+	}
+	for i, b := range t1 {
+		if b >= utf8.RuneSelf {
+			// No UTF-8 or non-ASCII allowed in tokens.
+			return false
+		}
+		if lowerASCII(byte(b)) != lowerASCII(t2[i]) {
+			return false
+		}
+	}
+	return true
+}
diff --git a/src/net/http/lex_test.go b/src/net/http/lex_test.go
index 6d9d294..986fda1 100644
--- a/src/net/http/lex_test.go
+++ b/src/net/http/lex_test.go
@@ -29,3 +29,73 @@ func TestIsToken(t *testing.T) {
 		}
 	}
 }
+
+func TestHeaderValuesContainsToken(t *testing.T) {
+	tests := []struct {
+		vals  []string
+		token string
+		want  bool
+	}{
+		{
+			vals:  []string{"foo"},
+			token: "foo",
+			want:  true,
+		},
+		{
+			vals:  []string{"bar", "foo"},
+			token: "foo",
+			want:  true,
+		},
+		{
+			vals:  []string{"foo"},
+			token: "FOO",
+			want:  true,
+		},
+		{
+			vals:  []string{"foo"},
+			token: "bar",
+			want:  false,
+		},
+		{
+			vals:  []string{" foo "},
+			token: "FOO",
+			want:  true,
+		},
+		{
+			vals:  []string{"foo,bar"},
+			token: "FOO",
+			want:  true,
+		},
+		{
+			vals:  []string{"bar,foo,bar"},
+			token: "FOO",
+			want:  true,
+		},
+		{
+			vals:  []string{"bar , foo"},
+			token: "FOO",
+			want:  true,
+		},
+		{
+			vals:  []string{"foo ,bar "},
+			token: "FOO",
+			want:  true,
+		},
+		{
+			vals:  []string{"bar, foo ,bar"},
+			token: "FOO",
+			want:  true,
+		},
+		{
+			vals:  []string{"bar , foo"},
+			token: "FOO",
+			want:  true,
+		},
+	}
+	for _, tt := range tests {
+		got := headerValuesContainsToken(tt.vals, tt.token)
+		if got != tt.want {
+			t.Errorf("headerValuesContainsToken(%q, %q) = %v; want %v", tt.vals, tt.token, got, tt.want)
+		}
+	}
+}
diff --git a/src/net/http/main_test.go b/src/net/http/main_test.go
index b8c71fd..12eea6f 100644
--- a/src/net/http/main_test.go
+++ b/src/net/http/main_test.go
@@ -56,17 +56,21 @@ func goroutineLeaked() bool {
 		// not counting goroutines for leakage in -short mode
 		return false
 	}
-	gs := interestingGoroutines()
 
-	n := 0
-	stackCount := make(map[string]int)
-	for _, g := range gs {
-		stackCount[g]++
-		n++
-	}
-
-	if n == 0 {
-		return false
+	var stackCount map[string]int
+	for i := 0; i < 5; i++ {
+		n := 0
+		stackCount = make(map[string]int)
+		gs := interestingGoroutines()
+		for _, g := range gs {
+			stackCount[g]++
+			n++
+		}
+		if n == 0 {
+			return false
+		}
+		// Wait for goroutines to schedule and die off:
+		time.Sleep(100 * time.Millisecond)
 	}
 	fmt.Fprintf(os.Stderr, "Too many goroutines running after net/http test(s).\n")
 	for stack, count := range stackCount {
@@ -75,7 +79,7 @@ func goroutineLeaked() bool {
 	return true
 }
 
-func afterTest(t *testing.T) {
+func afterTest(t testing.TB) {
 	http.DefaultTransport.(*http.Transport).CloseIdleConnections()
 	if testing.Short() {
 		return
diff --git a/src/net/http/npn_test.go b/src/net/http/npn_test.go
index 98b8930..e2e911d 100644
--- a/src/net/http/npn_test.go
+++ b/src/net/http/npn_test.go
@@ -6,6 +6,7 @@ package http_test
 
 import (
 	"bufio"
+	"bytes"
 	"crypto/tls"
 	"fmt"
 	"io"
@@ -17,6 +18,7 @@ import (
 )
 
 func TestNextProtoUpgrade(t *testing.T) {
+	defer afterTest(t)
 	ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) {
 		fmt.Fprintf(w, "path=%s,proto=", r.URL.Path)
 		if r.TLS != nil {
@@ -38,12 +40,12 @@ func TestNextProtoUpgrade(t *testing.T) {
 	ts.StartTLS()
 	defer ts.Close()
 
-	tr := newTLSTransport(t, ts)
-	defer tr.CloseIdleConnections()
-	c := &Client{Transport: tr}
-
 	// Normal request, without NPN.
 	{
+		tr := newTLSTransport(t, ts)
+		defer tr.CloseIdleConnections()
+		c := &Client{Transport: tr}
+
 		res, err := c.Get(ts.URL)
 		if err != nil {
 			t.Fatal(err)
@@ -60,11 +62,17 @@ func TestNextProtoUpgrade(t *testing.T) {
 	// Request to an advertised but unhandled NPN protocol.
 	// Server will hang up.
 	{
-		tr.CloseIdleConnections()
+		tr := newTLSTransport(t, ts)
 		tr.TLSClientConfig.NextProtos = []string{"unhandled-proto"}
-		_, err := c.Get(ts.URL)
+		defer tr.CloseIdleConnections()
+		c := &Client{Transport: tr}
+
+		res, err := c.Get(ts.URL)
 		if err == nil {
-			t.Errorf("expected error on unhandled-proto request")
+			defer res.Body.Close()
+			var buf bytes.Buffer
+			res.Write(&buf)
+			t.Errorf("expected error on unhandled-proto request; got: %s", buf.Bytes())
 		}
 	}
 
diff --git a/src/net/http/pprof/pprof.go b/src/net/http/pprof/pprof.go
index a23f1bc..fd9154a 100644
--- a/src/net/http/pprof/pprof.go
+++ b/src/net/http/pprof/pprof.go
@@ -34,12 +34,16 @@
 //
 //	go tool pprof http://localhost:6060/debug/pprof/block
 //
+// Or to collect a 5-second execution trace:
+//
+//	wget http://localhost:6060/debug/pprof/trace?seconds=5
+//
 // To view all available profiles, open http://localhost:6060/debug/pprof/
 // in your browser.
 //
 // For a study of the facility in action, visit
 //
-//	http://blog.golang.org/2011/06/profiling-go-programs.html
+//	https://blog.golang.org/2011/06/profiling-go-programs.html
 //
 package pprof
 
@@ -54,6 +58,7 @@ import (
 	"os"
 	"runtime"
 	"runtime/pprof"
+	"runtime/trace"
 	"strconv"
 	"strings"
 	"time"
@@ -64,6 +69,7 @@ func init() {
 	http.Handle("/debug/pprof/cmdline", http.HandlerFunc(Cmdline))
 	http.Handle("/debug/pprof/profile", http.HandlerFunc(Profile))
 	http.Handle("/debug/pprof/symbol", http.HandlerFunc(Symbol))
+	http.Handle("/debug/pprof/trace", http.HandlerFunc(Trace))
 }
 
 // Cmdline responds with the running program's
@@ -98,6 +104,30 @@ func Profile(w http.ResponseWriter, r *http.Request) {
 	pprof.StopCPUProfile()
 }
 
+// Trace responds with the execution trace in binary form.
+// Tracing lasts for duration specified in seconds GET parameter, or for 1 second if not specified.
+// The package initialization registers it as /debug/pprof/trace.
+func Trace(w http.ResponseWriter, r *http.Request) {
+	sec, _ := strconv.ParseInt(r.FormValue("seconds"), 10, 64)
+	if sec == 0 {
+		sec = 1
+	}
+
+	// Set Content Type assuming trace.Start will work,
+	// because if it does it starts writing.
+	w.Header().Set("Content-Type", "application/octet-stream")
+	if err := trace.Start(w); err != nil {
+		// trace.Start failed, so no writes yet.
+		// Can change header back to text content and send error code.
+		w.Header().Set("Content-Type", "text/plain; charset=utf-8")
+		w.WriteHeader(http.StatusInternalServerError)
+		fmt.Fprintf(w, "Could not enable tracing: %s\n", err)
+		return
+	}
+	time.Sleep(time.Duration(sec) * time.Second)
+	trace.Stop()
+}
+
 // Symbol looks up the program counters listed in the request,
 // responding with a table mapping program counters to function names.
 // The package initialization registers it as /debug/pprof/symbol.
@@ -193,17 +223,17 @@ var indexTmpl = template.Must(template.New("index").Parse(`<html>
 <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/proxy_test.go b/src/net/http/proxy_test.go
index b6aed37..823d144 100644
--- a/src/net/http/proxy_test.go
+++ b/src/net/http/proxy_test.go
@@ -18,7 +18,7 @@ var UseProxyTests = []struct {
 	match bool
 }{
 	// Never proxy localhost:
-	{"localhost:80", false},
+	{"localhost", false},
 	{"127.0.0.1", false},
 	{"127.0.0.2", false},
 	{"[::1]", false},
diff --git a/src/net/http/readrequest_test.go b/src/net/http/readrequest_test.go
index 1a3cf91..60e2be4 100644
--- a/src/net/http/readrequest_test.go
+++ b/src/net/http/readrequest_test.go
@@ -178,6 +178,36 @@ var reqTests = []reqTest{
 		noError,
 	},
 
+	// Tests chunked body and a bogus Content-Length which should be deleted.
+	{
+		"POST / HTTP/1.1\r\n" +
+			"Host: foo.com\r\n" +
+			"Transfer-Encoding: chunked\r\n" +
+			"Content-Length: 9999\r\n\r\n" + // to be removed.
+			"3\r\nfoo\r\n" +
+			"3\r\nbar\r\n" +
+			"0\r\n" +
+			"\r\n",
+		&Request{
+			Method: "POST",
+			URL: &url.URL{
+				Path: "/",
+			},
+			TransferEncoding: []string{"chunked"},
+			Proto:            "HTTP/1.1",
+			ProtoMajor:       1,
+			ProtoMinor:       1,
+			Header:           Header{},
+			ContentLength:    -1,
+			Host:             "foo.com",
+			RequestURI:       "/",
+		},
+
+		"foobar",
+		noTrailer,
+		noError,
+	},
+
 	// CONNECT request with domain name:
 	{
 		"CONNECT www.google.com:443 HTTP/1.1\r\n\r\n",
@@ -400,11 +430,6 @@ Content-Length: 3
 Content-Length: 4
 
 abc`)},
-	{"smuggle_chunked_and_len", reqBytes(`POST / HTTP/1.1
-Transfer-Encoding: chunked
-Content-Length: 3
-
-abc`)},
 	{"smuggle_content_len_head", reqBytes(`HEAD / HTTP/1.1
 Host: foo
 Content-Length: 5`)},
diff --git a/src/net/http/request.go b/src/net/http/request.go
index 487eebc..31fe45a 100644
--- a/src/net/http/request.go
+++ b/src/net/http/request.go
@@ -25,9 +25,6 @@ import (
 )
 
 const (
-	maxValueLength   = 4096
-	maxHeaderLines   = 1024
-	chunkSize        = 4 << 10  // 4 KB chunks
 	defaultMaxMemory = 32 << 20 // 32 MB
 )
 
@@ -172,8 +169,9 @@ type Request struct {
 	// The HTTP client ignores Form and uses Body instead.
 	Form url.Values
 
-	// PostForm contains the parsed form data from POST or PUT
-	// body parameters.
+	// PostForm contains the parsed form data from POST, PATCH,
+	// or PUT body parameters.
+	//
 	// This field is only available after ParseForm is called.
 	// The HTTP client ignores PostForm and uses Body instead.
 	PostForm url.Values
@@ -226,6 +224,13 @@ type Request struct {
 	// otherwise it leaves the field nil.
 	// This field is ignored by the HTTP client.
 	TLS *tls.ConnectionState
+
+	// Cancel is an optional channel whose closure indicates that the client
+	// request should be regarded as canceled. Not all implementations of
+	// RoundTripper may support Cancel.
+	//
+	// For server requests, this field is not applicable.
+	Cancel <-chan struct{}
 }
 
 // ProtoAtLeast reports whether the HTTP protocol used
@@ -245,6 +250,7 @@ func (r *Request) Cookies() []*Cookie {
 	return readCookies(r.Header, "")
 }
 
+// ErrNoCookie is returned by Request's Cookie method when a cookie is not found.
 var ErrNoCookie = errors.New("http: named cookie not present")
 
 // Cookie returns the named cookie provided in the request or
@@ -329,13 +335,12 @@ func valueOrDefault(value, def string) string {
 }
 
 // NOTE: This is not intended to reflect the actual Go version being used.
-// It was changed from "Go http package" to "Go 1.1 package http" at the
-// time of the Go 1.1 release because the former User-Agent had ended up
-// on a blacklist for some intrusion detection systems.
+// It was changed at the time of Go 1.1 release because the former User-Agent
+// had ended up on a blacklist for some intrusion detection systems.
 // See https://codereview.appspot.com/7532043.
-const defaultUserAgent = "Go 1.1 package http"
+const defaultUserAgent = "Go-http-client/1.1"
 
-// Write writes an HTTP/1.1 request -- header and body -- in wire format.
+// Write writes an HTTP/1.1 request, which is the header and body, in wire format.
 // This method consults the following fields of the request:
 //	Host
 //	URL
@@ -364,14 +369,23 @@ func (r *Request) WriteProxy(w io.Writer) error {
 
 // extraHeaders may be nil
 func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header) error {
-	host := req.Host
+	// Find the target host. Prefer the Host: header, but if that
+	// is not given, use the host from the request URL.
+	//
+	// Clean the host, in case it arrives with unexpected stuff in it.
+	host := cleanHost(req.Host)
 	if host == "" {
 		if req.URL == nil {
 			return errors.New("http: Request.Write on Request with no Host or URL set")
 		}
-		host = req.URL.Host
+		host = cleanHost(req.URL.Host)
 	}
 
+	// According to RFC 6874, an HTTP client, proxy, or other
+	// intermediary must remove any IPv6 zone identifier attached
+	// to an outgoing URI.
+	host = removeZone(host)
+
 	ruri := req.URL.RequestURI()
 	if usingProxy && req.URL.Scheme != "" && req.URL.Opaque == "" {
 		ruri = req.URL.Scheme + "://" + host + ruri
@@ -456,6 +470,39 @@ func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header) err
 	return nil
 }
 
+// cleanHost strips anything after '/' or ' '.
+// Ideally we'd clean the Host header according to the spec:
+//   https://tools.ietf.org/html/rfc7230#section-5.4 (Host = uri-host [ ":" port ]")
+//   https://tools.ietf.org/html/rfc7230#section-2.7 (uri-host -> rfc3986's host)
+//   https://tools.ietf.org/html/rfc3986#section-3.2.2 (definition of host)
+// But practically, what we are trying to avoid is the situation in
+// issue 11206, where a malformed Host header used in the proxy context
+// would create a bad request. So it is enough to just truncate at the
+// first offending character.
+func cleanHost(in string) string {
+	if i := strings.IndexAny(in, " /"); i != -1 {
+		return in[:i]
+	}
+	return in
+}
+
+// removeZone removes IPv6 zone identifer from host.
+// E.g., "[fe80::1%en0]:8080" to "[fe80::1]:8080"
+func removeZone(host string) string {
+	if !strings.HasPrefix(host, "[") {
+		return host
+	}
+	i := strings.LastIndex(host, "]")
+	if i < 0 {
+		return host
+	}
+	j := strings.LastIndex(host[:i], "%")
+	if j < 0 {
+		return host
+	}
+	return host[:j] + host[i:]
+}
+
 // ParseHTTPVersion parses a HTTP version string.
 // "HTTP/1.0" returns (1, 0, true).
 func ParseHTTPVersion(vers string) (major, minor int, ok bool) {
@@ -489,6 +536,13 @@ func ParseHTTPVersion(vers string) (major, minor int, ok bool) {
 // If the provided body is also an io.Closer, the returned
 // Request.Body is set to body and will be closed by the Client
 // methods Do, Post, and PostForm, and Transport.RoundTrip.
+//
+// NewRequest returns a Request suitable for use with Client.Do or
+// Transport.RoundTrip.
+// To create a request for use with testing a Server Handler use either
+// ReadRequest or manually update the Request fields. See the Request
+// type's documentation for the difference between inbound and outbound
+// request fields.
 func NewRequest(method, urlStr string, body io.Reader) (*Request, error) {
 	u, err := url.Parse(urlStr)
 	if err != nil {
@@ -536,10 +590,11 @@ func (r *Request) BasicAuth() (username, password string, ok bool) {
 // parseBasicAuth parses an HTTP Basic Authentication string.
 // "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==" returns ("Aladdin", "open sesame", true).
 func parseBasicAuth(auth string) (username, password string, ok bool) {
-	if !strings.HasPrefix(auth, "Basic ") {
+	const prefix = "Basic "
+	if !strings.HasPrefix(auth, prefix) {
 		return
 	}
-	c, err := base64.StdEncoding.DecodeString(strings.TrimPrefix(auth, "Basic "))
+	c, err := base64.StdEncoding.DecodeString(auth[len(prefix):])
 	if err != nil {
 		return
 	}
@@ -587,7 +642,7 @@ func putTextprotoReader(r *textproto.Reader) {
 	textprotoReaderPool.Put(r)
 }
 
-// ReadRequest reads and parses a request from b.
+// ReadRequest reads and parses an incoming request from b.
 func ReadRequest(b *bufio.Reader) (req *Request, err error) {
 
 	tp := newTextprotoReader(b)
@@ -660,19 +715,20 @@ func ReadRequest(b *bufio.Reader) (req *Request, err error) {
 
 	fixPragmaCacheControl(req.Header)
 
+	req.Close = shouldClose(req.ProtoMajor, req.ProtoMinor, req.Header, false)
+
 	err = readTransfer(req, b)
 	if err != nil {
 		return nil, err
 	}
 
-	req.Close = shouldClose(req.ProtoMajor, req.ProtoMinor, req.Header, false)
 	return req, nil
 }
 
 // MaxBytesReader is similar to io.LimitReader but is intended for
 // limiting the size of incoming request bodies. In contrast to
 // io.LimitReader, MaxBytesReader's result is a ReadCloser, returns a
-// non-EOF error for a Read beyond the limit, and Closes the
+// non-EOF error for a Read beyond the limit, and closes the
 // underlying reader when its Close method is called.
 //
 // MaxBytesReader prevents clients from accidentally or maliciously
@@ -686,23 +742,52 @@ type maxBytesReader struct {
 	r       io.ReadCloser // underlying reader
 	n       int64         // max bytes remaining
 	stopped bool
+	sawEOF  bool
+}
+
+func (l *maxBytesReader) tooLarge() (n int, err error) {
+	if !l.stopped {
+		l.stopped = true
+		if res, ok := l.w.(*response); ok {
+			res.requestTooLarge()
+		}
+	}
+	return 0, errors.New("http: request body too large")
 }
 
 func (l *maxBytesReader) Read(p []byte) (n int, err error) {
-	if l.n <= 0 {
-		if !l.stopped {
-			l.stopped = true
-			if res, ok := l.w.(*response); ok {
-				res.requestTooLarge()
-			}
+	toRead := l.n
+	if l.n == 0 {
+		if l.sawEOF {
+			return l.tooLarge()
 		}
-		return 0, errors.New("http: request body too large")
+		// The underlying io.Reader may not return (0, io.EOF)
+		// at EOF if the requested size is 0, so read 1 byte
+		// instead. The io.Reader docs are a bit ambiguous
+		// about the return value of Read when 0 bytes are
+		// requested, and {bytes,strings}.Reader gets it wrong
+		// too (it returns (0, nil) even at EOF).
+		toRead = 1
 	}
-	if int64(len(p)) > l.n {
-		p = p[:l.n]
+	if int64(len(p)) > toRead {
+		p = p[:toRead]
 	}
 	n, err = l.r.Read(p)
+	if err == io.EOF {
+		l.sawEOF = true
+	}
+	if l.n == 0 {
+		// If we had zero bytes to read remaining (but hadn't seen EOF)
+		// and we get a byte here, that means we went over our limit.
+		if n > 0 {
+			return l.tooLarge()
+		}
+		return 0, err
+	}
 	l.n -= int64(n)
+	if l.n < 0 {
+		l.n = 0
+	}
 	return
 }
 
@@ -852,6 +937,7 @@ func (r *Request) ParseMultipartForm(maxMemory int64) error {
 // POST and PUT body parameters take precedence over URL query string values.
 // FormValue calls ParseMultipartForm and ParseForm if necessary and ignores
 // any errors returned by these functions.
+// If key is not present, FormValue returns the empty string.
 // To access multiple values of the same key, call ParseForm and
 // then inspect Request.Form directly.
 func (r *Request) FormValue(key string) string {
@@ -868,6 +954,7 @@ func (r *Request) FormValue(key string) string {
 // or PUT request body. URL query parameters are ignored.
 // PostFormValue calls ParseMultipartForm and ParseForm if necessary and ignores
 // any errors returned by these functions.
+// If key is not present, PostFormValue returns the empty string.
 func (r *Request) PostFormValue(key string) string {
 	if r.PostForm == nil {
 		r.ParseMultipartForm(defaultMaxMemory)
diff --git a/src/net/http/request_test.go b/src/net/http/request_test.go
index 759ea4e..627620c 100644
--- a/src/net/http/request_test.go
+++ b/src/net/http/request_test.go
@@ -178,6 +178,7 @@ func TestParseMultipartForm(t *testing.T) {
 }
 
 func TestRedirect(t *testing.T) {
+	defer afterTest(t)
 	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
 		switch r.URL.Path {
 		case "/":
@@ -326,13 +327,31 @@ func TestReadRequestErrors(t *testing.T) {
 	}
 }
 
+var newRequestHostTests = []struct {
+	in, out string
+}{
+	{"http://www.example.com/", "www.example.com"},
+	{"http://www.example.com:8080/", "www.example.com:8080"},
+
+	{"http://192.168.0.1/", "192.168.0.1"},
+	{"http://192.168.0.1:8080/", "192.168.0.1:8080"},
+
+	{"http://[fe80::1]/", "[fe80::1]"},
+	{"http://[fe80::1]:8080/", "[fe80::1]:8080"},
+	{"http://[fe80::1%25en0]/", "[fe80::1%en0]"},
+	{"http://[fe80::1%25en0]:8080/", "[fe80::1%en0]:8080"},
+}
+
 func TestNewRequestHost(t *testing.T) {
-	req, err := NewRequest("GET", "http://localhost:1234/", nil)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if req.Host != "localhost:1234" {
-		t.Errorf("Host = %q; want localhost:1234", req.Host)
+	for i, tt := range newRequestHostTests {
+		req, err := NewRequest("GET", tt.in, nil)
+		if err != nil {
+			t.Errorf("#%v: %v", i, err)
+			continue
+		}
+		if req.Host != tt.out {
+			t.Errorf("got %q; want %q", req.Host, tt.out)
+		}
 	}
 }
 
@@ -402,8 +421,6 @@ type getBasicAuthTest struct {
 	ok                 bool
 }
 
-type parseBasicAuthTest getBasicAuthTest
-
 type basicAuthCredentialsTest struct {
 	username, password string
 }
@@ -496,6 +513,82 @@ func TestRequestWriteBufferedWriter(t *testing.T) {
 	}
 }
 
+func TestRequestBadHost(t *testing.T) {
+	got := []string{}
+	req, err := NewRequest("GET", "http://foo.com with spaces/after", nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	req.Write(logWrites{t, &got})
+	want := []string{
+		"GET /after HTTP/1.1\r\n",
+		"Host: foo.com\r\n",
+		"User-Agent: " + DefaultUserAgent + "\r\n",
+		"\r\n",
+	}
+	if !reflect.DeepEqual(got, want) {
+		t.Errorf("Writes = %q\n  Want = %q", got, want)
+	}
+}
+
+func TestStarRequest(t *testing.T) {
+	req, err := ReadRequest(bufio.NewReader(strings.NewReader("M-SEARCH * HTTP/1.1\r\n\r\n")))
+	if err != nil {
+		return
+	}
+	var out bytes.Buffer
+	if err := req.Write(&out); err != nil {
+		t.Fatal(err)
+	}
+	back, err := ReadRequest(bufio.NewReader(&out))
+	if err != nil {
+		t.Fatal(err)
+	}
+	// Ignore the Headers (the User-Agent breaks the deep equal,
+	// but we don't care about it)
+	req.Header = nil
+	back.Header = nil
+	if !reflect.DeepEqual(req, back) {
+		t.Errorf("Original request doesn't match Request read back.")
+		t.Logf("Original: %#v", req)
+		t.Logf("Original.URL: %#v", req.URL)
+		t.Logf("Wrote: %s", out.Bytes())
+		t.Logf("Read back (doesn't match Original): %#v", back)
+	}
+}
+
+type responseWriterJustWriter struct {
+	io.Writer
+}
+
+func (responseWriterJustWriter) Header() Header  { panic("should not be called") }
+func (responseWriterJustWriter) WriteHeader(int) { panic("should not be called") }
+
+// delayedEOFReader never returns (n > 0, io.EOF), instead putting
+// off the io.EOF until a subsequent Read call.
+type delayedEOFReader struct {
+	r io.Reader
+}
+
+func (dr delayedEOFReader) Read(p []byte) (n int, err error) {
+	n, err = dr.r.Read(p)
+	if n > 0 && err == io.EOF {
+		err = nil
+	}
+	return
+}
+
+func TestIssue10884_MaxBytesEOF(t *testing.T) {
+	dst := ioutil.Discard
+	_, err := io.Copy(dst, MaxBytesReader(
+		responseWriterJustWriter{dst},
+		ioutil.NopCloser(delayedEOFReader{strings.NewReader("12345")}),
+		5))
+	if err != nil {
+		t.Fatal(err)
+	}
+}
+
 func testMissingFile(t *testing.T, req *Request) {
 	f, fh, err := req.FormFile("missing")
 	if f != nil {
diff --git a/src/net/http/requestwrite_test.go b/src/net/http/requestwrite_test.go
index 7a6bd58..cfb95b0 100644
--- a/src/net/http/requestwrite_test.go
+++ b/src/net/http/requestwrite_test.go
@@ -93,13 +93,13 @@ var reqWriteTests = []reqWriteTest{
 
 		WantWrite: "GET /search HTTP/1.1\r\n" +
 			"Host: www.google.com\r\n" +
-			"User-Agent: Go 1.1 package http\r\n" +
+			"User-Agent: Go-http-client/1.1\r\n" +
 			"Transfer-Encoding: chunked\r\n\r\n" +
 			chunk("abcdef") + chunk(""),
 
 		WantProxy: "GET http://www.google.com/search HTTP/1.1\r\n" +
 			"Host: www.google.com\r\n" +
-			"User-Agent: Go 1.1 package http\r\n" +
+			"User-Agent: Go-http-client/1.1\r\n" +
 			"Transfer-Encoding: chunked\r\n\r\n" +
 			chunk("abcdef") + chunk(""),
 	},
@@ -123,14 +123,14 @@ var reqWriteTests = []reqWriteTest{
 
 		WantWrite: "POST /search HTTP/1.1\r\n" +
 			"Host: www.google.com\r\n" +
-			"User-Agent: Go 1.1 package http\r\n" +
+			"User-Agent: Go-http-client/1.1\r\n" +
 			"Connection: close\r\n" +
 			"Transfer-Encoding: chunked\r\n\r\n" +
 			chunk("abcdef") + chunk(""),
 
 		WantProxy: "POST http://www.google.com/search HTTP/1.1\r\n" +
 			"Host: www.google.com\r\n" +
-			"User-Agent: Go 1.1 package http\r\n" +
+			"User-Agent: Go-http-client/1.1\r\n" +
 			"Connection: close\r\n" +
 			"Transfer-Encoding: chunked\r\n\r\n" +
 			chunk("abcdef") + chunk(""),
@@ -156,7 +156,7 @@ var reqWriteTests = []reqWriteTest{
 
 		WantWrite: "POST /search HTTP/1.1\r\n" +
 			"Host: www.google.com\r\n" +
-			"User-Agent: Go 1.1 package http\r\n" +
+			"User-Agent: Go-http-client/1.1\r\n" +
 			"Connection: close\r\n" +
 			"Content-Length: 6\r\n" +
 			"\r\n" +
@@ -164,7 +164,7 @@ var reqWriteTests = []reqWriteTest{
 
 		WantProxy: "POST http://www.google.com/search HTTP/1.1\r\n" +
 			"Host: www.google.com\r\n" +
-			"User-Agent: Go 1.1 package http\r\n" +
+			"User-Agent: Go-http-client/1.1\r\n" +
 			"Connection: close\r\n" +
 			"Content-Length: 6\r\n" +
 			"\r\n" +
@@ -187,14 +187,14 @@ var reqWriteTests = []reqWriteTest{
 
 		WantWrite: "POST / HTTP/1.1\r\n" +
 			"Host: example.com\r\n" +
-			"User-Agent: Go 1.1 package http\r\n" +
+			"User-Agent: Go-http-client/1.1\r\n" +
 			"Content-Length: 6\r\n" +
 			"\r\n" +
 			"abcdef",
 
 		WantProxy: "POST http://example.com/ HTTP/1.1\r\n" +
 			"Host: example.com\r\n" +
-			"User-Agent: Go 1.1 package http\r\n" +
+			"User-Agent: Go-http-client/1.1\r\n" +
 			"Content-Length: 6\r\n" +
 			"\r\n" +
 			"abcdef",
@@ -210,7 +210,7 @@ var reqWriteTests = []reqWriteTest{
 
 		WantWrite: "GET /search HTTP/1.1\r\n" +
 			"Host: www.google.com\r\n" +
-			"User-Agent: Go 1.1 package http\r\n" +
+			"User-Agent: Go-http-client/1.1\r\n" +
 			"\r\n",
 	},
 
@@ -232,13 +232,13 @@ var reqWriteTests = []reqWriteTest{
 		// Also, nginx expects it for POST and PUT.
 		WantWrite: "POST / HTTP/1.1\r\n" +
 			"Host: example.com\r\n" +
-			"User-Agent: Go 1.1 package http\r\n" +
+			"User-Agent: Go-http-client/1.1\r\n" +
 			"Content-Length: 0\r\n" +
 			"\r\n",
 
 		WantProxy: "POST / HTTP/1.1\r\n" +
 			"Host: example.com\r\n" +
-			"User-Agent: Go 1.1 package http\r\n" +
+			"User-Agent: Go-http-client/1.1\r\n" +
 			"Content-Length: 0\r\n" +
 			"\r\n",
 	},
@@ -258,13 +258,13 @@ var reqWriteTests = []reqWriteTest{
 
 		WantWrite: "POST / HTTP/1.1\r\n" +
 			"Host: example.com\r\n" +
-			"User-Agent: Go 1.1 package http\r\n" +
+			"User-Agent: Go-http-client/1.1\r\n" +
 			"Transfer-Encoding: chunked\r\n\r\n" +
 			chunk("x") + chunk(""),
 
 		WantProxy: "POST / HTTP/1.1\r\n" +
 			"Host: example.com\r\n" +
-			"User-Agent: Go 1.1 package http\r\n" +
+			"User-Agent: Go-http-client/1.1\r\n" +
 			"Transfer-Encoding: chunked\r\n\r\n" +
 			chunk("x") + chunk(""),
 	},
@@ -365,7 +365,7 @@ var reqWriteTests = []reqWriteTest{
 
 		WantWrite: "GET /foo HTTP/1.1\r\n" +
 			"Host: \r\n" +
-			"User-Agent: Go 1.1 package http\r\n" +
+			"User-Agent: Go-http-client/1.1\r\n" +
 			"X-Foo: X-Bar\r\n\r\n",
 	},
 
@@ -391,7 +391,7 @@ var reqWriteTests = []reqWriteTest{
 
 		WantWrite: "GET /search HTTP/1.1\r\n" +
 			"Host: \r\n" +
-			"User-Agent: Go 1.1 package http\r\n\r\n",
+			"User-Agent: Go-http-client/1.1\r\n\r\n",
 	},
 
 	// Opaque test #1 from golang.org/issue/4860
@@ -410,7 +410,7 @@ var reqWriteTests = []reqWriteTest{
 
 		WantWrite: "GET /%2F/%2F/ HTTP/1.1\r\n" +
 			"Host: www.google.com\r\n" +
-			"User-Agent: Go 1.1 package http\r\n\r\n",
+			"User-Agent: Go-http-client/1.1\r\n\r\n",
 	},
 
 	// Opaque test #2 from golang.org/issue/4860
@@ -429,7 +429,7 @@ var reqWriteTests = []reqWriteTest{
 
 		WantWrite: "GET http://y.google.com/%2F/%2F/ HTTP/1.1\r\n" +
 			"Host: x.google.com\r\n" +
-			"User-Agent: Go 1.1 package http\r\n\r\n",
+			"User-Agent: Go-http-client/1.1\r\n\r\n",
 	},
 
 	// Testing custom case in header keys. Issue 5022.
@@ -451,10 +451,41 @@ var reqWriteTests = []reqWriteTest{
 
 		WantWrite: "GET / HTTP/1.1\r\n" +
 			"Host: www.google.com\r\n" +
-			"User-Agent: Go 1.1 package http\r\n" +
+			"User-Agent: Go-http-client/1.1\r\n" +
 			"ALL-CAPS: x\r\n" +
 			"\r\n",
 	},
+
+	// Request with host header field; IPv6 address with zone identifier
+	{
+		Req: Request{
+			Method: "GET",
+			URL: &url.URL{
+				Host: "[fe80::1%en0]",
+			},
+		},
+
+		WantWrite: "GET / HTTP/1.1\r\n" +
+			"Host: [fe80::1]\r\n" +
+			"User-Agent: Go-http-client/1.1\r\n" +
+			"\r\n",
+	},
+
+	// Request with optional host header field; IPv6 address with zone identifier
+	{
+		Req: Request{
+			Method: "GET",
+			URL: &url.URL{
+				Host: "www.example.com",
+			},
+			Host: "[fe80::1%en0]:8080",
+		},
+
+		WantWrite: "GET / HTTP/1.1\r\n" +
+			"Host: [fe80::1]:8080\r\n" +
+			"User-Agent: Go-http-client/1.1\r\n" +
+			"\r\n",
+	},
 }
 
 func TestRequestWrite(t *testing.T) {
@@ -538,7 +569,7 @@ func TestRequestWriteClosesBody(t *testing.T) {
 	}
 	expected := "POST / HTTP/1.1\r\n" +
 		"Host: foo.com\r\n" +
-		"User-Agent: Go 1.1 package http\r\n" +
+		"User-Agent: Go-http-client/1.1\r\n" +
 		"Transfer-Encoding: chunked\r\n\r\n" +
 		// TODO: currently we don't buffer before chunking, so we get a
 		// single "m" chunk before the other chunks, as this was the 1-byte
diff --git a/src/net/http/response.go b/src/net/http/response.go
index 5d2c390..76b8538 100644
--- a/src/net/http/response.go
+++ b/src/net/http/response.go
@@ -48,7 +48,10 @@ type Response struct {
 	// The http Client and Transport guarantee that Body is always
 	// non-nil, even on responses without a body or responses with
 	// a zero-length body. It is the caller's responsibility to
-	// close Body.
+	// close Body. The default HTTP client's Transport does not
+	// attempt to reuse HTTP/1.0 or HTTP/1.1 TCP connections
+	// ("keep-alive") unless the Body is read to completion and is
+	// closed.
 	//
 	// The Body is automatically dechunked if the server replied
 	// with a "chunked" Transfer-Encoding.
@@ -90,6 +93,8 @@ func (r *Response) Cookies() []*Cookie {
 	return readSetCookies(r.Header)
 }
 
+// ErrNoLocation is returned by Response's Location method
+// when no Location header is present.
 var ErrNoLocation = errors.New("http: no Location header in response")
 
 // Location returns the URL of the response's "Location" header,
@@ -186,8 +191,10 @@ func (r *Response) ProtoAtLeast(major, minor int) bool {
 		r.ProtoMajor == major && r.ProtoMinor >= minor
 }
 
-// Writes the response (header, body and trailer) in wire format. This method
-// consults the following fields of the response:
+// Write writes r to w in the HTTP/1.n server response format,
+// including the status line, headers, body, and optional trailer.
+//
+// This method consults the following fields of the response r:
 //
 //  StatusCode
 //  ProtoMajor
@@ -199,7 +206,7 @@ func (r *Response) ProtoAtLeast(major, minor int) bool {
 //  ContentLength
 //  Header, values for non-canonical keys will have unpredictable behavior
 //
-// Body is closed after it is sent.
+// The Response Body is closed after it is sent.
 func (r *Response) Write(w io.Writer) error {
 	// Status line
 	text := r.Status
diff --git a/src/net/http/response_test.go b/src/net/http/response_test.go
index 06e940d..421cf55 100644
--- a/src/net/http/response_test.go
+++ b/src/net/http/response_test.go
@@ -405,6 +405,57 @@ some body`,
 
 		"foobar",
 	},
+
+	// Both keep-alive and close, on the same Connection line. (Issue 8840)
+	{
+		"HTTP/1.1 200 OK\r\n" +
+			"Content-Length: 256\r\n" +
+			"Connection: keep-alive, close\r\n" +
+			"\r\n",
+
+		Response{
+			Status:     "200 OK",
+			StatusCode: 200,
+			Proto:      "HTTP/1.1",
+			ProtoMajor: 1,
+			ProtoMinor: 1,
+			Request:    dummyReq("HEAD"),
+			Header: Header{
+				"Content-Length": {"256"},
+			},
+			TransferEncoding: nil,
+			Close:            true,
+			ContentLength:    256,
+		},
+
+		"",
+	},
+
+	// Both keep-alive and close, on different Connection lines. (Issue 8840)
+	{
+		"HTTP/1.1 200 OK\r\n" +
+			"Content-Length: 256\r\n" +
+			"Connection: keep-alive\r\n" +
+			"Connection: close\r\n" +
+			"\r\n",
+
+		Response{
+			Status:     "200 OK",
+			StatusCode: 200,
+			Proto:      "HTTP/1.1",
+			ProtoMajor: 1,
+			ProtoMinor: 1,
+			Request:    dummyReq("HEAD"),
+			Header: Header{
+				"Content-Length": {"256"},
+			},
+			TransferEncoding: nil,
+			Close:            true,
+			ContentLength:    256,
+		},
+
+		"",
+	},
 }
 
 func TestReadResponse(t *testing.T) {
diff --git a/src/net/http/responsewrite_test.go b/src/net/http/responsewrite_test.go
index 585b13b..5b8d47a 100644
--- a/src/net/http/responsewrite_test.go
+++ b/src/net/http/responsewrite_test.go
@@ -207,6 +207,21 @@ func TestResponseWrite(t *testing.T) {
 			},
 			"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n",
 		},
+
+		// When a response to a POST has Content-Length: -1, make sure we don't
+		// write the Content-Length as -1.
+		{
+			Response{
+				StatusCode:    StatusOK,
+				ProtoMajor:    1,
+				ProtoMinor:    1,
+				Request:       &Request{Method: "POST"},
+				Header:        Header{},
+				ContentLength: -1,
+				Body:          ioutil.NopCloser(strings.NewReader("abcdef")),
+			},
+			"HTTP/1.1 200 OK\r\nConnection: close\r\n\r\nabcdef",
+		},
 	}
 
 	for i := range respWriteTests {
diff --git a/src/net/http/serve_test.go b/src/net/http/serve_test.go
index c118375..d51417e 100644
--- a/src/net/http/serve_test.go
+++ b/src/net/http/serve_test.go
@@ -20,6 +20,7 @@ import (
 	. "net/http"
 	"net/http/httptest"
 	"net/http/httputil"
+	"net/http/internal"
 	"net/url"
 	"os"
 	"os/exec"
@@ -146,6 +147,7 @@ func (ht handlerTest) rawResponse(req string) string {
 }
 
 func TestConsumingBodyOnNextConn(t *testing.T) {
+	defer afterTest(t)
 	conn := new(testConn)
 	for i := 0; i < 2; i++ {
 		conn.readBuf.Write([]byte(
@@ -205,6 +207,7 @@ var handlers = []struct {
 }{
 	{"/", "Default"},
 	{"/someDir/", "someDir"},
+	{"/#/", "hash"},
 	{"someHost.com/someDir/", "someHost.com/someDir"},
 }
 
@@ -213,12 +216,14 @@ var vtests = []struct {
 	expected string
 }{
 	{"http://localhost/someDir/apage", "someDir"},
+	{"http://localhost/%23/apage", "hash"},
 	{"http://localhost/otherDir/apage", "Default"},
 	{"http://someHost.com/someDir/apage", "someHost.com/someDir"},
 	{"http://otherHost.com/someDir/apage", "someDir"},
 	{"http://otherHost.com/aDir/apage", "Default"},
 	// redirections for trees
 	{"http://localhost/someDir", "/someDir/"},
+	{"http://localhost/%23", "/%23/"},
 	{"http://someHost.com/someDir", "/someDir/"},
 }
 
@@ -416,7 +421,7 @@ func TestServeMuxHandlerRedirects(t *testing.T) {
 	}
 }
 
-// Tests for http://code.google.com/p/go/issues/detail?id=900
+// Tests for https://golang.org/issue/900
 func TestMuxRedirectLeadingSlashes(t *testing.T) {
 	paths := []string{"//foo.txt", "///foo.txt", "/../../foo.txt"}
 	for _, path := range paths {
@@ -443,7 +448,7 @@ func TestMuxRedirectLeadingSlashes(t *testing.T) {
 
 func TestServerTimeouts(t *testing.T) {
 	if runtime.GOOS == "plan9" {
-		t.Skip("skipping test; see http://golang.org/issue/7237")
+		t.Skip("skipping test; see https://golang.org/issue/7237")
 	}
 	defer afterTest(t)
 	reqNum := 0
@@ -522,7 +527,7 @@ func TestServerTimeouts(t *testing.T) {
 // request) that will never happen.
 func TestOnlyWriteTimeout(t *testing.T) {
 	if runtime.GOOS == "plan9" {
-		t.Skip("skipping test; see http://golang.org/issue/7237")
+		t.Skip("skipping test; see https://golang.org/issue/7237")
 	}
 	defer afterTest(t)
 	var conn net.Conn
@@ -877,7 +882,7 @@ func TestHeadResponses(t *testing.T) {
 
 func TestTLSHandshakeTimeout(t *testing.T) {
 	if runtime.GOOS == "plan9" {
-		t.Skip("skipping test; see http://golang.org/issue/7237")
+		t.Skip("skipping test; see https://golang.org/issue/7237")
 	}
 	defer afterTest(t)
 	ts := httptest.NewUnstartedServer(HandlerFunc(func(w ResponseWriter, r *Request) {}))
@@ -1105,6 +1110,7 @@ func TestServerExpect(t *testing.T) {
 // Under a ~256KB (maxPostHandlerReadBytes) threshold, the server
 // should consume client request bodies that a handler didn't read.
 func TestServerUnreadRequestBodyLittle(t *testing.T) {
+	defer afterTest(t)
 	conn := new(testConn)
 	body := strings.Repeat("x", 100<<10)
 	conn.readBuf.Write([]byte(fmt.Sprintf(
@@ -1166,6 +1172,164 @@ func TestServerUnreadRequestBodyLarge(t *testing.T) {
 	}
 }
 
+type handlerBodyCloseTest struct {
+	bodySize     int
+	bodyChunked  bool
+	reqConnClose bool
+
+	wantEOFSearch bool // should Handler's Body.Close do Reads, looking for EOF?
+	wantNextReq   bool // should it find the next request on the same conn?
+}
+
+func (t handlerBodyCloseTest) connectionHeader() string {
+	if t.reqConnClose {
+		return "Connection: close\r\n"
+	}
+	return ""
+}
+
+var handlerBodyCloseTests = [...]handlerBodyCloseTest{
+	// Small enough to slurp past to the next request +
+	// has Content-Length.
+	0: {
+		bodySize:      20 << 10,
+		bodyChunked:   false,
+		reqConnClose:  false,
+		wantEOFSearch: true,
+		wantNextReq:   true,
+	},
+
+	// Small enough to slurp past to the next request +
+	// is chunked.
+	1: {
+		bodySize:      20 << 10,
+		bodyChunked:   true,
+		reqConnClose:  false,
+		wantEOFSearch: true,
+		wantNextReq:   true,
+	},
+
+	// Small enough to slurp past to the next request +
+	// has Content-Length +
+	// declares Connection: close (so pointless to read more).
+	2: {
+		bodySize:      20 << 10,
+		bodyChunked:   false,
+		reqConnClose:  true,
+		wantEOFSearch: false,
+		wantNextReq:   false,
+	},
+
+	// Small enough to slurp past to the next request +
+	// declares Connection: close,
+	// but chunked, so it might have trailers.
+	// TODO: maybe skip this search if no trailers were declared
+	// in the headers.
+	3: {
+		bodySize:      20 << 10,
+		bodyChunked:   true,
+		reqConnClose:  true,
+		wantEOFSearch: true,
+		wantNextReq:   false,
+	},
+
+	// Big with Content-Length, so give up immediately if we know it's too big.
+	4: {
+		bodySize:      1 << 20,
+		bodyChunked:   false, // has a Content-Length
+		reqConnClose:  false,
+		wantEOFSearch: false,
+		wantNextReq:   false,
+	},
+
+	// Big chunked, so read a bit before giving up.
+	5: {
+		bodySize:      1 << 20,
+		bodyChunked:   true,
+		reqConnClose:  false,
+		wantEOFSearch: true,
+		wantNextReq:   false,
+	},
+
+	// Big with Connection: close, but chunked, so search for trailers.
+	// TODO: maybe skip this search if no trailers were declared
+	// in the headers.
+	6: {
+		bodySize:      1 << 20,
+		bodyChunked:   true,
+		reqConnClose:  true,
+		wantEOFSearch: true,
+		wantNextReq:   false,
+	},
+
+	// Big with Connection: close, so don't do any reads on Close.
+	// With Content-Length.
+	7: {
+		bodySize:      1 << 20,
+		bodyChunked:   false,
+		reqConnClose:  true,
+		wantEOFSearch: false,
+		wantNextReq:   false,
+	},
+}
+
+func TestHandlerBodyClose(t *testing.T) {
+	for i, tt := range handlerBodyCloseTests {
+		testHandlerBodyClose(t, i, tt)
+	}
+}
+
+func testHandlerBodyClose(t *testing.T, i int, tt handlerBodyCloseTest) {
+	conn := new(testConn)
+	body := strings.Repeat("x", tt.bodySize)
+	if tt.bodyChunked {
+		conn.readBuf.WriteString("POST / HTTP/1.1\r\n" +
+			"Host: test\r\n" +
+			tt.connectionHeader() +
+			"Transfer-Encoding: chunked\r\n" +
+			"\r\n")
+		cw := internal.NewChunkedWriter(&conn.readBuf)
+		io.WriteString(cw, body)
+		cw.Close()
+		conn.readBuf.WriteString("\r\n")
+	} else {
+		conn.readBuf.Write([]byte(fmt.Sprintf(
+			"POST / HTTP/1.1\r\n"+
+				"Host: test\r\n"+
+				tt.connectionHeader()+
+				"Content-Length: %d\r\n"+
+				"\r\n", len(body))))
+		conn.readBuf.Write([]byte(body))
+	}
+	if !tt.reqConnClose {
+		conn.readBuf.WriteString("GET / HTTP/1.1\r\nHost: test\r\n\r\n")
+	}
+	conn.closec = make(chan bool, 1)
+
+	ls := &oneConnListener{conn}
+	var numReqs int
+	var size0, size1 int
+	go Serve(ls, HandlerFunc(func(rw ResponseWriter, req *Request) {
+		numReqs++
+		if numReqs == 1 {
+			size0 = conn.readBuf.Len()
+			req.Body.Close()
+			size1 = conn.readBuf.Len()
+		}
+	}))
+	<-conn.closec
+	if numReqs < 1 || numReqs > 2 {
+		t.Fatalf("%d. bug in test. unexpected number of requests = %d", i, numReqs)
+	}
+	didSearch := size0 != size1
+	if didSearch != tt.wantEOFSearch {
+		t.Errorf("%d. did EOF search = %v; want %v (size went from %d to %d)", i, didSearch, !didSearch, size0, size1)
+	}
+	if tt.wantNextReq && numReqs != 2 {
+		t.Errorf("%d. numReq = %d; want 2", i, numReqs)
+	}
+}
+
 // testHandlerBodyConsumer represents a function injected into a test handler to
 // vary work done on a request Body.
 type testHandlerBodyConsumer struct {
@@ -1652,19 +1816,23 @@ func testHandlerPanic(t *testing.T, withHijack bool, panicValue interface{}) {
 	}
 }
 
-func TestNoDate(t *testing.T) {
+func TestServerNoDate(t *testing.T)        { testServerNoHeader(t, "Date") }
+func TestServerNoContentType(t *testing.T) { testServerNoHeader(t, "Content-Type") }
+
+func testServerNoHeader(t *testing.T, header string) {
 	defer afterTest(t)
 	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
-		w.Header()["Date"] = nil
+		w.Header()[header] = nil
+		io.WriteString(w, "<html>foo</html>") // non-empty
 	}))
 	defer ts.Close()
 	res, err := Get(ts.URL)
 	if err != nil {
 		t.Fatal(err)
 	}
-	_, present := res.Header["Date"]
-	if present {
-		t.Fatalf("Expected no Date header; got %v", res.Header["Date"])
+	res.Body.Close()
+	if got, ok := res.Header[header]; ok {
+		t.Fatalf("Expected no %s header; got %q", header, got)
 	}
 }
 
@@ -1778,7 +1946,7 @@ func TestRequestBodyLimit(t *testing.T) {
 // side of their TCP connection, the server doesn't send a 400 Bad Request.
 func TestClientWriteShutdown(t *testing.T) {
 	if runtime.GOOS == "plan9" {
-		t.Skip("skipping test; see http://golang.org/issue/7237")
+		t.Skip("skipping test; see https://golang.org/issue/7237")
 	}
 	defer afterTest(t)
 	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {}))
@@ -1833,7 +2001,7 @@ func TestServerBufferedChunking(t *testing.T) {
 // Tests that the server flushes its response headers out when it's
 // ignoring the response body and waits a bit before forcefully
 // closing the TCP connection, causing the client to get a RST.
-// See http://golang.org/issue/3595
+// See https://golang.org/issue/3595
 func TestServerGracefulClose(t *testing.T) {
 	defer afterTest(t)
 	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
@@ -2325,7 +2493,7 @@ func TestDoubleHijack(t *testing.T) {
 	<-conn.closec
 }
 
-// http://code.google.com/p/go/issues/detail?id=5955
+// https://golang.org/issue/5955
 // Note that this does not test the "request too large"
 // exit path from the http server. This is intentional;
 // not sending Connection: close is just a minor wire
@@ -2489,17 +2657,13 @@ func TestTransportAndServerSharedBodyRace(t *testing.T) {
 
 	unblockBackend := make(chan bool)
 	backend := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) {
-		io.CopyN(rw, req.Body, bodySize/2)
+		io.CopyN(rw, req.Body, bodySize)
 		<-unblockBackend
 	}))
 	defer backend.Close()
 
 	backendRespc := make(chan *Response, 1)
 	proxy := httptest.NewServer(HandlerFunc(func(rw ResponseWriter, req *Request) {
-		if req.RequestURI == "/foo" {
-			rw.Write([]byte("bar"))
-			return
-		}
 		req2, _ := NewRequest("POST", backend.URL, req.Body)
 		req2.ContentLength = bodySize
 
@@ -2508,7 +2672,7 @@ func TestTransportAndServerSharedBodyRace(t *testing.T) {
 			t.Errorf("Proxy outbound request: %v", err)
 			return
 		}
-		_, err = io.CopyN(ioutil.Discard, bresp.Body, bodySize/4)
+		_, err = io.CopyN(ioutil.Discard, bresp.Body, bodySize/2)
 		if err != nil {
 			t.Errorf("Proxy copy error: %v", err)
 			return
@@ -2522,6 +2686,7 @@ func TestTransportAndServerSharedBodyRace(t *testing.T) {
 	}))
 	defer proxy.Close()
 
+	defer close(unblockBackend)
 	req, _ := NewRequest("POST", proxy.URL, io.LimitReader(neverEnding('a'), bodySize))
 	res, err := DefaultClient.Do(req)
 	if err != nil {
@@ -2530,8 +2695,12 @@ func TestTransportAndServerSharedBodyRace(t *testing.T) {
 
 	// Cleanup, so we don't leak goroutines.
 	res.Body.Close()
-	close(unblockBackend)
-	(<-backendRespc).Body.Close()
+	select {
+	case res := <-backendRespc:
+		res.Body.Close()
+	default:
+		// We failed earlier. (e.g. on DefaultClient.Do(req2))
+	}
 }
 
 // Test that a hanging Request.Body.Read from another goroutine can't
@@ -2585,18 +2754,24 @@ func TestRequestBodyCloseDoesntBlock(t *testing.T) {
 	}
 }
 
-func TestResponseWriterWriteStringAllocs(t *testing.T) {
+// test that ResponseWriter implements io.stringWriter.
+func TestResponseWriterWriteString(t *testing.T) {
+	okc := make(chan bool, 1)
 	ht := newHandlerTest(HandlerFunc(func(w ResponseWriter, r *Request) {
-		if r.URL.Path == "/s" {
-			io.WriteString(w, "Hello world")
-		} else {
-			w.Write([]byte("Hello world"))
+		type stringWriter interface {
+			WriteString(s string) (n int, err error)
 		}
+		_, ok := w.(stringWriter)
+		okc <- ok
 	}))
-	before := testing.AllocsPerRun(50, func() { ht.rawResponse("GET / HTTP/1.0") })
-	after := testing.AllocsPerRun(50, func() { ht.rawResponse("GET /s HTTP/1.0") })
-	if int(after) >= int(before) {
-		t.Errorf("WriteString allocs of %v >= Write allocs of %v", after, before)
+	ht.rawResponse("GET / HTTP/1.0")
+	select {
+	case ok := <-okc:
+		if !ok {
+			t.Error("ResponseWriter did not implement io.stringWriter")
+		}
+	default:
+		t.Error("handler was never called")
 	}
 }
 
@@ -2957,6 +3132,134 @@ func TestServerKeepAliveAfterWriteError(t *testing.T) {
 	}
 }
 
+// Issue 9987: shouldn't add automatic Content-Length (or
+// Content-Type) if a Transfer-Encoding was set by the handler.
+func TestNoContentLengthIfTransferEncoding(t *testing.T) {
+	defer afterTest(t)
+	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+		w.Header().Set("Transfer-Encoding", "foo")
+		io.WriteString(w, "<html>")
+	}))
+	defer ts.Close()
+	c, err := net.Dial("tcp", ts.Listener.Addr().String())
+	if err != nil {
+		t.Fatalf("Dial: %v", err)
+	}
+	defer c.Close()
+	if _, err := io.WriteString(c, "GET / HTTP/1.1\r\nHost: foo\r\n\r\n"); err != nil {
+		t.Fatal(err)
+	}
+	bs := bufio.NewScanner(c)
+	var got bytes.Buffer
+	for bs.Scan() {
+		if strings.TrimSpace(bs.Text()) == "" {
+			break
+		}
+		got.WriteString(bs.Text())
+		got.WriteByte('\n')
+	}
+	if err := bs.Err(); err != nil {
+		t.Fatal(err)
+	}
+	if strings.Contains(got.String(), "Content-Length") {
+		t.Errorf("Unexpected Content-Length in response headers: %s", got.String())
+	}
+	if strings.Contains(got.String(), "Content-Type") {
+		t.Errorf("Unexpected Content-Type in response headers: %s", got.String())
+	}
+}
+
+// tolerate extra CRLF(s) before Request-Line on subsequent requests on a conn
+// Issue 10876.
+func TestTolerateCRLFBeforeRequestLine(t *testing.T) {
+	req := []byte("POST / HTTP/1.1\r\nHost: golang.org\r\nContent-Length: 3\r\n\r\nABC" +
+		"\r\n\r\n" + // <-- this stuff is bogus, but we'll ignore it
+		"GET / HTTP/1.1\r\nHost: golang.org\r\n\r\n")
+	var buf bytes.Buffer
+	conn := &rwTestConn{
+		Reader: bytes.NewReader(req),
+		Writer: &buf,
+		closec: make(chan bool, 1),
+	}
+	ln := &oneConnListener{conn: conn}
+	numReq := 0
+	go Serve(ln, HandlerFunc(func(rw ResponseWriter, r *Request) {
+		numReq++
+	}))
+	<-conn.closec
+	if numReq != 2 {
+		t.Errorf("num requests = %d; want 2", numReq)
+		t.Logf("Res: %s", buf.Bytes())
+	}
+}
+
+func TestIssue11549_Expect100(t *testing.T) {
+	req := reqBytes(`PUT /readbody HTTP/1.1
+User-Agent: PycURL/7.22.0
+Host: 127.0.0.1:9000
+Accept: */*
+Expect: 100-continue
+Content-Length: 10
+
+HelloWorldPUT /noreadbody HTTP/1.1
+User-Agent: PycURL/7.22.0
+Host: 127.0.0.1:9000
+Accept: */*
+Expect: 100-continue
+Content-Length: 10
+
+GET /should-be-ignored HTTP/1.1
+Host: foo
+
+`)
+	var buf bytes.Buffer
+	conn := &rwTestConn{
+		Reader: bytes.NewReader(req),
+		Writer: &buf,
+		closec: make(chan bool, 1),
+	}
+	ln := &oneConnListener{conn: conn}
+	numReq := 0
+	go Serve(ln, HandlerFunc(func(w ResponseWriter, r *Request) {
+		numReq++
+		if r.URL.Path == "/readbody" {
+			ioutil.ReadAll(r.Body)
+		}
+		io.WriteString(w, "Hello world!")
+	}))
+	<-conn.closec
+	if numReq != 2 {
+		t.Errorf("num requests = %d; want 2", numReq)
+	}
+	if !strings.Contains(buf.String(), "Connection: close\r\n") {
+		t.Errorf("expected 'Connection: close' in response; got: %s", buf.String())
+	}
+}
+
+// If a Handler finishes and there's an unread request body,
+// verify the server try to do implicit read on it before replying.
+func TestHandlerFinishSkipBigContentLengthRead(t *testing.T) {
+	conn := &testConn{closec: make(chan bool)}
+	conn.readBuf.Write([]byte(fmt.Sprintf(
+		"POST / HTTP/1.1\r\n" +
+			"Host: test\r\n" +
+			"Content-Length: 9999999999\r\n" +
+			"\r\n" + strings.Repeat("a", 1<<20))))
+
+	ls := &oneConnListener{conn}
+	var inHandlerLen int
+	go Serve(ls, HandlerFunc(func(rw ResponseWriter, req *Request) {
+		inHandlerLen = conn.readBuf.Len()
+		rw.WriteHeader(404)
+	}))
+	<-conn.closec
+	afterHandlerLen := conn.readBuf.Len()
+
+	if afterHandlerLen != inHandlerLen {
+		t.Errorf("unexpected implicit read. Read buffer went from %d -> %d", inHandlerLen, afterHandlerLen)
+	}
+}
+
 func BenchmarkClientServer(b *testing.B) {
 	b.ReportAllocs()
 	b.StopTimer()
@@ -3086,7 +3389,7 @@ func BenchmarkServer(b *testing.B) {
 	defer ts.Close()
 	b.StartTimer()
 
-	cmd := exec.Command(os.Args[0], "-test.run=XXXX", "-test.bench=BenchmarkServer")
+	cmd := exec.Command(os.Args[0], "-test.run=XXXX", "-test.bench=BenchmarkServer$")
 	cmd.Env = append([]string{
 		fmt.Sprintf("TEST_BENCH_CLIENT_N=%d", b.N),
 		fmt.Sprintf("TEST_BENCH_SERVER_URL=%s", ts.URL),
@@ -3097,6 +3400,95 @@ func BenchmarkServer(b *testing.B) {
 	}
 }
 
+// getNoBody wraps Get but closes any Response.Body before returning the response.
+func getNoBody(urlStr string) (*Response, error) {
+	res, err := Get(urlStr)
+	if err != nil {
+		return nil, err
+	}
+	res.Body.Close()
+	return res, nil
+}
+
+// A benchmark for profiling the client without the HTTP server code.
+// The server code runs in a subprocess.
+func BenchmarkClient(b *testing.B) {
+	b.ReportAllocs()
+	b.StopTimer()
+	defer afterTest(b)
+
+	port := os.Getenv("TEST_BENCH_SERVER_PORT") // can be set by user
+	if port == "" {
+		port = "39207"
+	}
+	var data = []byte("Hello world.\n")
+	if server := os.Getenv("TEST_BENCH_SERVER"); server != "" {
+		// Server process mode.
+		HandleFunc("/", func(w ResponseWriter, r *Request) {
+			r.ParseForm()
+			if r.Form.Get("stop") != "" {
+				os.Exit(0)
+			}
+			w.Header().Set("Content-Type", "text/html; charset=utf-8")
+			w.Write(data)
+		})
+		log.Fatal(ListenAndServe("localhost:"+port, nil))
+	}
+
+	// Start server process.
+	cmd := exec.Command(os.Args[0], "-test.run=XXXX", "-test.bench=BenchmarkClient$")
+	cmd.Env = append(os.Environ(), "TEST_BENCH_SERVER=yes")
+	if err := cmd.Start(); err != nil {
+		b.Fatalf("subprocess failed to start: %v", err)
+	}
+	defer cmd.Process.Kill()
+	done := make(chan error)
+	go func() {
+		done <- cmd.Wait()
+	}()
+
+	// Wait for the server process to respond.
+	url := "http://localhost:" + port + "/"
+	for i := 0; i < 100; i++ {
+		time.Sleep(50 * time.Millisecond)
+		if _, err := getNoBody(url); err == nil {
+			break
+		}
+		if i == 99 {
+			b.Fatalf("subprocess does not respond")
+		}
+	}
+
+	// Do b.N requests to the server.
+	b.StartTimer()
+	for i := 0; i < b.N; i++ {
+		res, err := Get(url)
+		if err != nil {
+			b.Fatalf("Get: %v", err)
+		}
+		body, err := ioutil.ReadAll(res.Body)
+		res.Body.Close()
+		if err != nil {
+			b.Fatalf("ReadAll: %v", err)
+		}
+		if bytes.Compare(body, data) != 0 {
+			b.Fatalf("Got body: %q", body)
+		}
+	}
+	b.StopTimer()
+
+	// Instruct server process to stop.
+	getNoBody(url + "?stop=yes")
+	select {
+	case err := <-done:
+		if err != nil {
+			b.Fatalf("subprocess failed: %v", err)
+		}
+	case <-time.After(5 * time.Second):
+		b.Fatalf("subprocess did not stop")
+	}
+}
+
 func BenchmarkServerFakeConnNoKeepAlive(b *testing.B) {
 	b.ReportAllocs()
 	req := reqBytes(`GET / HTTP/1.0
diff --git a/src/net/http/server.go b/src/net/http/server.go
index 500fe29..a3e4355 100644
--- a/src/net/http/server.go
+++ b/src/net/http/server.go
@@ -15,6 +15,7 @@ import (
 	"io/ioutil"
 	"log"
 	"net"
+	"net/textproto"
 	"net/url"
 	"os"
 	"path"
@@ -55,9 +56,12 @@ type Handler interface {
 // A ResponseWriter interface is used by an HTTP handler to
 // construct an HTTP response.
 type ResponseWriter interface {
-	// Header returns the header map that will be sent by WriteHeader.
-	// Changing the header after a call to WriteHeader (or Write) has
-	// no effect.
+	// Header returns the header map that will be sent by
+	// WriteHeader. Changing the header after a call to
+	// WriteHeader (or Write) has no effect unless the modified
+	// headers were declared as trailers by setting the
+	// "Trailer" header before the call to WriteHeader (see example).
+	// To suppress implicit response headers, set their value to nil.
 	Header() Header
 
 	// Write writes the data to the connection as part of an HTTP reply.
@@ -93,8 +97,14 @@ type Hijacker interface {
 	// Hijack lets the caller take over the connection.
 	// After a call to Hijack(), the HTTP server library
 	// will not do anything else with the connection.
+	//
 	// It becomes the caller's responsibility to manage
 	// and close the connection.
+	//
+	// The returned net.Conn may have read or write deadlines
+	// already set, depending on the configuration of the
+	// Server. It is the caller's responsibility to set
+	// or clear those deadlines as needed.
 	Hijack() (net.Conn, *bufio.ReadWriter, error)
 }
 
@@ -120,6 +130,7 @@ type conn struct {
 	lr         *io.LimitedReader    // io.LimitReader(sr)
 	buf        *bufio.ReadWriter    // buffered(lr,rwc), reading from bufio->limitReader->sr->rwc
 	tlsState   *tls.ConnectionState // or nil when not using TLS
+	lastMethod string               // method of previous request, or ""
 
 	mu           sync.Mutex // guards the following
 	clientGone   bool       // if client has disconnected mid-request
@@ -188,20 +199,14 @@ func (c *conn) noteClientGone() {
 	c.clientGone = true
 }
 
-// A switchReader can have its Reader changed at runtime.
-// It's not safe for concurrent Reads and switches.
-type switchReader struct {
-	io.Reader
-}
-
 // A switchWriter can have its Writer changed at runtime.
 // It's not safe for concurrent Writes and switches.
 type switchWriter struct {
 	io.Writer
 }
 
-// A liveSwitchReader is a switchReader that's safe for concurrent
-// reads and switches, if its mutex is held.
+// A liveSwitchReader can have its Reader changed at runtime. It's
+// safe for concurrent reads and switches, if its mutex is held.
 type liveSwitchReader struct {
 	sync.Mutex
 	r io.Reader
@@ -288,10 +293,21 @@ func (cw *chunkWriter) close() {
 		cw.writeHeader(nil)
 	}
 	if cw.chunking {
-		// zero EOF chunk, trailer key/value pairs (currently
-		// unsupported in Go's server), followed by a blank
-		// line.
-		cw.res.conn.buf.WriteString("0\r\n\r\n")
+		bw := cw.res.conn.buf // conn's bufio writer
+		// zero chunk to mark EOF
+		bw.WriteString("0\r\n")
+		if len(cw.res.trailers) > 0 {
+			trailers := make(Header)
+			for _, h := range cw.res.trailers {
+				if vv := cw.res.handlerHeader[h]; len(vv) > 0 {
+					trailers[h] = vv
+				}
+			}
+			trailers.Write(bw) // the writer handles noting errors
+		}
+		// final blank line after the trailers (whether
+		// present or not)
+		bw.WriteString("\r\n")
 	}
 }
 
@@ -332,6 +348,12 @@ type response struct {
 	// input from it.
 	requestBodyLimitHit bool
 
+	// trailers are the headers to be sent after the handler
+	// finishes writing the body.  This field is initialized from
+	// the Trailer response header when the response header is
+	// written.
+	trailers []string
+
 	handlerDone bool // set true when the handler exits
 
 	// Buffers for Date and Content-Length
@@ -339,6 +361,19 @@ type response struct {
 	clenBuf [10]byte
 }
 
+// declareTrailer is called for each Trailer header when the
+// response header is written. It notes that a header will need to be
+// written in the trailers at the end of the response.
+func (w *response) declareTrailer(k string) {
+	k = CanonicalHeaderKey(k)
+	switch k {
+	case "Transfer-Encoding", "Content-Length", "Trailer":
+		// Forbidden by RFC 2616 14.40.
+		return
+	}
+	w.trailers = append(w.trailers, k)
+}
+
 // requestTooLarge is called by maxBytesReader when too much input has
 // been read from the client.
 func (w *response) requestTooLarge() {
@@ -438,7 +473,7 @@ func (srv *Server) newConn(rwc net.Conn) (c *conn, err error) {
 	if debugServerConnections {
 		c.rwc = newLoggingConn("server", c.rwc)
 	}
-	c.sr = liveSwitchReader{r: c.rwc}
+	c.sr.r = c.rwc
 	c.lr = io.LimitReader(&c.sr, noLimit).(*io.LimitedReader)
 	br := newBufioReader(c.lr)
 	bw := newBufioWriterSize(checkConnErrorWriter{c}, 4<<10)
@@ -468,6 +503,8 @@ func newBufioReader(r io.Reader) *bufio.Reader {
 		br.Reset(r)
 		return br
 	}
+	// Note: if this reader size is every changed, update
+	// TestHandlerBodyClose's assumptions.
 	return bufio.NewReader(r)
 }
 
@@ -517,6 +554,7 @@ type expectContinueReader struct {
 	resp       *response
 	readCloser io.ReadCloser
 	closed     bool
+	sawEOF     bool
 }
 
 func (ecr *expectContinueReader) Read(p []byte) (n int, err error) {
@@ -528,7 +566,11 @@ func (ecr *expectContinueReader) Read(p []byte) (n int, err error) {
 		ecr.resp.conn.buf.WriteString("HTTP/1.1 100 Continue\r\n\r\n")
 		ecr.resp.conn.buf.Flush()
 	}
-	return ecr.readCloser.Read(p)
+	n, err = ecr.readCloser.Read(p)
+	if err == io.EOF {
+		ecr.sawEOF = true
+	}
+	return
 }
 
 func (ecr *expectContinueReader) Close() error {
@@ -582,6 +624,11 @@ func (c *conn) readRequest() (w *response, err error) {
 	}
 
 	c.lr.N = c.server.initialLimitedReaderSize()
+	if c.lastMethod == "POST" {
+		// RFC 2616 section 4.1 tolerance for old buggy clients.
+		peek, _ := c.buf.Reader.Peek(4) // ReadRequest will get err below
+		c.buf.Reader.Discard(numLeadingCRorLF(peek))
+	}
 	var req *Request
 	if req, err = ReadRequest(c.buf.Reader); err != nil {
 		if c.lr.N == 0 {
@@ -590,9 +637,13 @@ func (c *conn) readRequest() (w *response, err error) {
 		return nil, err
 	}
 	c.lr.N = noLimit
+	c.lastMethod = req.Method
 
 	req.RemoteAddr = c.remoteAddr
 	req.TLS = c.tlsState
+	if body, ok := req.Body.(*body); ok {
+		body.doEarlyClose = true
+	}
 
 	w = &response{
 		conn:          c,
@@ -747,6 +798,15 @@ func (cw *chunkWriter) writeHeader(p []byte) {
 	}
 	var setHeader extraHeader
 
+	trailers := false
+	for _, v := range cw.header["Trailer"] {
+		trailers = true
+		foreachHeaderElement(v, cw.res.declareTrailer)
+	}
+
+	te := header.get("Transfer-Encoding")
+	hasTE := te != ""
+
 	// If the handler is done but never sent a Content-Length
 	// response header and this is our first (and last) write, set
 	// it, even to zero. This helps HTTP/1.0 clients keep their
@@ -759,7 +819,9 @@ func (cw *chunkWriter) writeHeader(p []byte) {
 	// write non-zero bytes.  If it's actually 0 bytes and the
 	// handler never looked at the Request.Method, we just don't
 	// send a Content-Length header.
-	if w.handlerDone && bodyAllowedForStatus(w.status) && header.get("Content-Length") == "" && (!isHEAD || len(p) > 0) {
+	// Further, we don't send an automatic Content-Length if they
+	// set a Transfer-Encoding, because they're generally incompatible.
+	if w.handlerDone && !trailers && !hasTE && bodyAllowedForStatus(w.status) && header.get("Content-Length") == "" && (!isHEAD || len(p) > 0) {
 		w.contentLength = int64(len(p))
 		setHeader.contentLength = strconv.AppendInt(cw.res.clenBuf[:0], int64(len(p)), 10)
 	}
@@ -789,21 +851,78 @@ func (cw *chunkWriter) writeHeader(p []byte) {
 		w.closeAfterReply = true
 	}
 
+	// If the client wanted a 100-continue but we never sent it to
+	// them (or, more strictly: we never finished reading their
+	// request body), don't reuse this connection because it's now
+	// in an unknown state: we might be sending this response at
+	// the same time the client is now sending its request body
+	// after a timeout.  (Some HTTP clients send Expect:
+	// 100-continue but knowing that some servers don't support
+	// it, the clients set a timer and send the body later anyway)
+	// If we haven't seen EOF, we can't skip over the unread body
+	// because we don't know if the next bytes on the wire will be
+	// the body-following-the-timer or the subsequent request.
+	// See Issue 11549.
+	if ecr, ok := w.req.Body.(*expectContinueReader); ok && !ecr.sawEOF {
+		w.closeAfterReply = true
+	}
+
 	// Per RFC 2616, we should consume the request body before
 	// replying, if the handler hasn't already done so.  But we
 	// don't want to do an unbounded amount of reading here for
 	// DoS reasons, so we only try up to a threshold.
 	if w.req.ContentLength != 0 && !w.closeAfterReply {
-		ecr, isExpecter := w.req.Body.(*expectContinueReader)
-		if !isExpecter || ecr.resp.wroteContinue {
-			n, err := io.CopyN(ioutil.Discard, w.req.Body, maxPostHandlerReadBytes+1)
-			if n >= maxPostHandlerReadBytes || (err != nil && err != io.EOF) {
-				w.requestTooLarge()
-				delHeader("Connection")
-				setHeader.connection = "close"
-			} else {
-				w.req.Body.Close()
+		var discard, tooBig bool
+
+		switch bdy := w.req.Body.(type) {
+		case *expectContinueReader:
+			if bdy.resp.wroteContinue {
+				discard = true
+			}
+		case *body:
+			bdy.mu.Lock()
+			switch {
+			case bdy.closed:
+				if !bdy.sawEOF {
+					// Body was closed in handler with non-EOF error.
+					w.closeAfterReply = true
+				}
+			case bdy.unreadDataSizeLocked() >= maxPostHandlerReadBytes:
+				tooBig = true
+			default:
+				discard = true
 			}
+			bdy.mu.Unlock()
+		default:
+			discard = true
+		}
+
+		if discard {
+			_, err := io.CopyN(ioutil.Discard, w.req.Body, maxPostHandlerReadBytes+1)
+			switch err {
+			case nil:
+				// There must be even more data left over.
+				tooBig = true
+			case ErrBodyReadAfterClose:
+				// Body was already consumed and closed.
+			case io.EOF:
+				// The remaining body was just consumed, close it.
+				err = w.req.Body.Close()
+				if err != nil {
+					w.closeAfterReply = true
+				}
+			default:
+				// Some other kind of error occured, like a read timeout, or
+				// corrupt chunked encoding. In any case, whatever remains
+				// on the wire must not be parsed as another HTTP request.
+				w.closeAfterReply = true
+			}
+		}
+
+		if tooBig {
+			w.requestTooLarge()
+			delHeader("Connection")
+			setHeader.connection = "close"
 		}
 	}
 
@@ -811,7 +930,7 @@ func (cw *chunkWriter) writeHeader(p []byte) {
 	if bodyAllowedForStatus(code) {
 		// If no content type, apply sniffing algorithm to body.
 		_, haveType := header["Content-Type"]
-		if !haveType {
+		if !haveType && !hasTE {
 			setHeader.contentType = DetectContentType(p)
 		}
 	} else {
@@ -824,8 +943,6 @@ func (cw *chunkWriter) writeHeader(p []byte) {
 		setHeader.date = appendTime(cw.res.dateBuf[:0], time.Now())
 	}
 
-	te := header.get("Transfer-Encoding")
-	hasTE := te != ""
 	if hasCL && hasTE && te != "identity" {
 		// TODO: return an error if WriteHeader gets a return parameter
 		// For now just ignore the Content-Length.
@@ -885,6 +1002,24 @@ func (cw *chunkWriter) writeHeader(p []byte) {
 	w.conn.buf.Write(crlf)
 }
 
+// foreachHeaderElement splits v according to the "#rule" construction
+// in RFC 2616 section 2.1 and calls fn for each non-empty element.
+func foreachHeaderElement(v string, fn func(string)) {
+	v = textproto.TrimString(v)
+	if v == "" {
+		return
+	}
+	if !strings.Contains(v, ",") {
+		fn(v)
+		return
+	}
+	for _, f := range strings.Split(v, ",") {
+		if f = textproto.TrimString(f); f != "" {
+			fn(f)
+		}
+	}
+}
+
 // statusLines is a cache of Status-Line strings, keyed by code (for
 // HTTP/1.1) or negative code (for HTTP/1.0). This is faster than a
 // map keyed by struct of two fields. This map's max size is bounded
@@ -930,7 +1065,7 @@ func statusLine(req *Request, code int) string {
 	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 {
@@ -1027,17 +1162,39 @@ func (w *response) finishRequest() {
 	if w.req.MultipartForm != nil {
 		w.req.MultipartForm.RemoveAll()
 	}
+}
+
+// shouldReuseConnection reports whether the underlying TCP connection can be reused.
+// It must only be called after the handler is done executing.
+func (w *response) shouldReuseConnection() bool {
+	if w.closeAfterReply {
+		// The request or something set while executing the
+		// handler indicated we shouldn't reuse this
+		// connection.
+		return false
+	}
 
 	if w.req.Method != "HEAD" && w.contentLength != -1 && w.bodyAllowed() && w.contentLength != w.written {
 		// Did not write enough. Avoid getting out of sync.
-		w.closeAfterReply = true
+		return false
 	}
 
 	// There was some error writing to the underlying connection
 	// during the request, so don't re-use this conn.
 	if w.conn.werr != nil {
-		w.closeAfterReply = true
+		return false
 	}
+
+	if w.closedRequestBodyEarly() {
+		return false
+	}
+
+	return true
+}
+
+func (w *response) closedRequestBodyEarly() bool {
+	body, ok := w.req.Body.(*body)
+	return ok && body.didEarlyClose()
 }
 
 func (w *response) Flush() {
@@ -1093,7 +1250,7 @@ var _ closeWriter = (*net.TCPConn)(nil)
 // pause for a bit, hoping the client processes it before any
 // subsequent RST.
 //
-// See http://golang.org/issue/3595
+// See https://golang.org/issue/3595
 func (c *conn) closeWriteAndWait() {
 	c.finalFlush()
 	if tcp, ok := c.rwc.(closeWriter); ok {
@@ -1206,8 +1363,8 @@ func (c *conn) serve() {
 			return
 		}
 		w.finishRequest()
-		if w.closeAfterReply {
-			if w.requestBodyLimitHit {
+		if !w.shouldReuseConnection() {
+			if w.requestBodyLimitHit || w.closedRequestBodyEarly() {
 				c.closeWriteAndWait()
 			}
 			break
@@ -1271,6 +1428,7 @@ func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
 // The error message should be plain text.
 func Error(w ResponseWriter, error string, code int) {
 	w.Header().Set("Content-Type", "text/plain; charset=utf-8")
+	w.Header().Set("X-Content-Type-Options", "nosniff")
 	w.WriteHeader(code)
 	fmt.Fprintln(w, error)
 }
@@ -1576,7 +1734,8 @@ func (mux *ServeMux) Handle(pattern string, handler Handler) {
 			// strings.Index can't be -1.
 			path = pattern[strings.Index(pattern, "/"):]
 		}
-		mux.m[pattern[0:n-1]] = muxEntry{h: RedirectHandler(path, StatusMovedPermanently), pattern: pattern}
+		url := &url.URL{Path: path}
+		mux.m[pattern[0:n-1]] = muxEntry{h: RedirectHandler(url.String(), StatusMovedPermanently), pattern: pattern}
 	}
 }
 
@@ -1760,11 +1919,11 @@ func (s *Server) doKeepAlives() bool {
 // By default, keep-alives are always enabled. Only very
 // resource-constrained environments or servers in the process of
 // shutting down should disable them.
-func (s *Server) SetKeepAlivesEnabled(v bool) {
+func (srv *Server) SetKeepAlivesEnabled(v bool) {
 	if v {
-		atomic.StoreInt32(&s.disableKeepAlives, 0)
+		atomic.StoreInt32(&srv.disableKeepAlives, 0)
 	} else {
-		atomic.StoreInt32(&s.disableKeepAlives, 1)
+		atomic.StoreInt32(&srv.disableKeepAlives, 1)
 	}
 }
 
@@ -1812,7 +1971,7 @@ func ListenAndServe(addr string, handler Handler) error {
 // expects HTTPS connections. Additionally, files containing a certificate and
 // matching private key for the server must be provided. If the certificate
 // is signed by a certificate authority, the certFile should be the concatenation
-// of the server's certificate followed by the CA's certificate.
+// of the server's certificate, any intermediates, and the CA's certificate.
 //
 // A trivial example server is:
 //
@@ -1844,10 +2003,11 @@ func ListenAndServeTLS(addr string, certFile string, keyFile string, handler Han
 // ListenAndServeTLS listens on the TCP network address srv.Addr and
 // then calls Serve to handle requests on incoming TLS connections.
 //
-// Filenames containing a certificate and matching private key for
-// the server must be provided. If the certificate is signed by a
-// certificate authority, the certFile should be the concatenation
-// of the server's certificate followed by the CA's certificate.
+// Filenames containing a certificate and matching private key for the
+// server must be provided if the Server's TLSConfig.Certificates is
+// not populated. If the certificate is signed by a certificate
+// authority, the certFile should be the concatenation of the server's
+// certificate, any intermediates, and the CA's certificate.
 //
 // If srv.Addr is blank, ":https" is used.
 func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error {
@@ -1855,19 +2015,18 @@ func (srv *Server) ListenAndServeTLS(certFile, keyFile string) error {
 	if addr == "" {
 		addr = ":https"
 	}
-	config := &tls.Config{}
-	if srv.TLSConfig != nil {
-		*config = *srv.TLSConfig
-	}
+	config := cloneTLSConfig(srv.TLSConfig)
 	if config.NextProtos == nil {
 		config.NextProtos = []string{"http/1.1"}
 	}
 
-	var err error
-	config.Certificates = make([]tls.Certificate, 1)
-	config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
-	if err != nil {
-		return err
+	if len(config.Certificates) == 0 || certFile != "" || keyFile != "" {
+		var err error
+		config.Certificates = make([]tls.Certificate, 1)
+		config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
+		if err != nil {
+			return err
+		}
 	}
 
 	ln, err := net.Listen("tcp", addr)
@@ -2094,3 +2253,15 @@ func (w checkConnErrorWriter) Write(p []byte) (n int, err error) {
 	}
 	return
 }
+
+func numLeadingCRorLF(v []byte) (n int) {
+	for _, b := range v {
+		if b == '\r' || b == '\n' {
+			n++
+			continue
+		}
+		break
+	}
+	return
+
+}
diff --git a/src/net/http/sniff.go b/src/net/http/sniff.go
index 68f519b..3be8c86 100644
--- a/src/net/http/sniff.go
+++ b/src/net/http/sniff.go
@@ -38,7 +38,11 @@ func DetectContentType(data []byte) string {
 }
 
 func isWS(b byte) bool {
-	return bytes.IndexByte([]byte("\t\n\x0C\r "), b) != -1
+	switch b {
+	case '\t', '\n', '\x0c', '\r', ' ':
+		return true
+	}
+	return false
 }
 
 type sniffSig interface {
@@ -161,6 +165,8 @@ func (h htmlSig) match(data []byte, firstNonWS int) string {
 	return "text/html; charset=utf-8"
 }
 
+var mp4ftype = []byte("ftyp")
+
 type mp4Sig int
 
 func (mp4Sig) match(data []byte, firstNonWS int) string {
@@ -172,7 +178,7 @@ func (mp4Sig) match(data []byte, firstNonWS int) string {
 	if boxSize%4 != 0 || len(data) < boxSize {
 		return ""
 	}
-	if !bytes.Equal(data[4:8], []byte("ftyp")) {
+	if !bytes.Equal(data[4:8], mp4ftype) {
 		return ""
 	}
 	for st := 8; st < boxSize; st += 4 {
diff --git a/src/net/http/transfer.go b/src/net/http/transfer.go
index 39bf174..a8736b2 100644
--- a/src/net/http/transfer.go
+++ b/src/net/http/transfer.go
@@ -27,7 +27,7 @@ type errorReader struct {
 	err error
 }
 
-func (r *errorReader) Read(p []byte) (n int, err error) {
+func (r errorReader) Read(p []byte) (n int, err error) {
 	return 0, r.err
 }
 
@@ -43,6 +43,7 @@ type transferWriter struct {
 	Close            bool
 	TransferEncoding []string
 	Trailer          Header
+	IsResponse       bool
 }
 
 func newTransferWriter(r interface{}) (t *transferWriter, err error) {
@@ -70,7 +71,7 @@ func newTransferWriter(r interface{}) (t *transferWriter, err error) {
 				n, rerr := io.ReadFull(t.Body, buf[:])
 				if rerr != nil && rerr != io.EOF {
 					t.ContentLength = -1
-					t.Body = &errorReader{rerr}
+					t.Body = errorReader{rerr}
 				} else if n == 1 {
 					// Oh, guess there is data in this Body Reader after all.
 					// The ContentLength field just wasn't set.
@@ -89,6 +90,7 @@ func newTransferWriter(r interface{}) (t *transferWriter, err error) {
 			}
 		}
 	case *Response:
+		t.IsResponse = true
 		if rr.Request != nil {
 			t.Method = rr.Request.Method
 		}
@@ -138,6 +140,9 @@ func (t *transferWriter) shouldSendContentLength() bool {
 	if t.ContentLength > 0 {
 		return true
 	}
+	if t.ContentLength < 0 {
+		return false
+	}
 	// Many servers expect a Content-Length for these methods
 	if t.Method == "POST" || t.Method == "PUT" {
 		return true
@@ -206,6 +211,9 @@ func (t *transferWriter) WriteBody(w io.Writer) error {
 	// Write body
 	if t.Body != nil {
 		if chunked(t.TransferEncoding) {
+			if bw, ok := w.(*bufio.Writer); ok && !t.IsResponse {
+				w = &internal.FlushAfterChunkWriter{bw}
+			}
 			cw := internal.NewChunkedWriter(w)
 			_, err = io.Copy(cw, t.Body)
 			if err == nil {
@@ -235,7 +243,6 @@ func (t *transferWriter) WriteBody(w io.Writer) error {
 			t.ContentLength, ncopy)
 	}
 
-	// TODO(petar): Place trailer writer code here.
 	if chunked(t.TransferEncoding) {
 		// Write Trailer header
 		if t.Trailer != nil {
@@ -319,6 +326,7 @@ func readTransfer(msg interface{}, r *bufio.Reader) (err error) {
 		// Transfer semantics for Requests are exactly like those for
 		// Responses with status code 200, responding to a GET method
 		t.StatusCode = 200
+		t.Close = rr.Close
 	default:
 		panic("unexpected type")
 	}
@@ -422,7 +430,6 @@ func fixTransferEncoding(isResponse bool, requestMethod string, header Header) (
 	if !present {
 		return nil, nil
 	}
-	isRequest := !isResponse
 	delete(header, "Transfer-Encoding")
 
 	encodings := strings.Split(raw[0], ",")
@@ -450,12 +457,20 @@ func fixTransferEncoding(isResponse bool, requestMethod string, header Header) (
 		// RFC 7230 3.3.2 says "A sender MUST NOT send a
 		// Content-Length header field in any message that
 		// contains a Transfer-Encoding header field."
-		if len(header["Content-Length"]) > 0 {
-			if isRequest {
-				return nil, errors.New("http: invalid Content-Length with Transfer-Encoding")
-			}
-			delete(header, "Content-Length")
-		}
+		//
+		// but also:
+		// "If a message is received with both a
+		// Transfer-Encoding and a Content-Length header
+		// field, the Transfer-Encoding overrides the
+		// Content-Length. Such a message might indicate an
+		// attempt to perform request smuggling (Section 9.5)
+		// or response splitting (Section 9.4) and ought to be
+		// handled as an error. A sender MUST remove the
+		// received Content-Length field prior to forwarding
+		// such a message downstream."
+		//
+		// Reportedly, these appear in the wild.
+		delete(header, "Content-Length")
 		return te, nil
 	}
 
@@ -534,14 +549,13 @@ func shouldClose(major, minor int, header Header, removeCloseHeader bool) bool {
 	if major < 1 {
 		return true
 	} else if major == 1 && minor == 0 {
-		if !strings.Contains(strings.ToLower(header.get("Connection")), "keep-alive") {
+		vv := header["Connection"]
+		if headerValuesContainsToken(vv, "close") || !headerValuesContainsToken(vv, "keep-alive") {
 			return true
 		}
 		return false
 	} else {
-		// TODO: Should split on commas, toss surrounding white space,
-		// and check each field.
-		if strings.ToLower(header.get("Connection")) == "close" {
+		if headerValuesContainsToken(header["Connection"], "close") {
 			if removeCloseHeader {
 				header.Del("Connection")
 			}
@@ -583,13 +597,16 @@ func fixTrailer(header Header, te []string) (Header, error) {
 // Close ensures that the body has been fully read
 // and then reads the trailer if necessary.
 type body struct {
-	src     io.Reader
-	hdr     interface{}   // non-nil (Response or Request) value means read trailer
-	r       *bufio.Reader // underlying wire-format reader for the trailer
-	closing bool          // is the connection to be closed after reading body?
-
-	mu     sync.Mutex // guards closed, and calls to Read and Close
-	closed bool
+	src          io.Reader
+	hdr          interface{}   // non-nil (Response or Request) value means read trailer
+	r            *bufio.Reader // underlying wire-format reader for the trailer
+	closing      bool          // is the connection to be closed after reading body?
+	doEarlyClose bool          // whether Close should stop early
+
+	mu         sync.Mutex // guards closed, and calls to Read and Close
+	sawEOF     bool
+	closed     bool
+	earlyClose bool // Close called and we didn't read to the end of src
 }
 
 // ErrBodyReadAfterClose is returned when reading a Request or Response
@@ -609,13 +626,22 @@ func (b *body) Read(p []byte) (n int, err error) {
 
 // Must hold b.mu.
 func (b *body) readLocked(p []byte) (n int, err error) {
+	if b.sawEOF {
+		return 0, io.EOF
+	}
 	n, err = b.src.Read(p)
 
 	if err == io.EOF {
+		b.sawEOF = true
 		// Chunked case. Read the trailer.
 		if b.hdr != nil {
 			if e := b.readTrailer(); e != nil {
 				err = e
+				// Something went wrong in the trailer, we must not allow any
+				// further reads of any kind to succeed from body, nor any
+				// subsequent requests on the server connection. See
+				// golang.org/issue/12027
+				b.sawEOF = false
 				b.closed = true
 			}
 			b.hdr = nil
@@ -636,6 +662,7 @@ func (b *body) readLocked(p []byte) (n int, err error) {
 	if err == nil && n > 0 {
 		if lr, ok := b.src.(*io.LimitedReader); ok && lr.N == 0 {
 			err = io.EOF
+			b.sawEOF = true
 		}
 	}
 
@@ -668,8 +695,7 @@ func (b *body) readTrailer() error {
 	// The common case, since nobody uses trailers.
 	buf, err := b.r.Peek(2)
 	if bytes.Equal(buf, singleCRLF) {
-		b.r.ReadByte()
-		b.r.ReadByte()
+		b.r.Discard(2)
 		return nil
 	}
 	if len(buf) < 2 {
@@ -717,6 +743,16 @@ func mergeSetHeader(dst *Header, src Header) {
 	}
 }
 
+// unreadDataSizeLocked returns the number of bytes of unread input.
+// It returns -1 if unknown.
+// b.mu must be held.
+func (b *body) unreadDataSizeLocked() int64 {
+	if lr, ok := b.src.(*io.LimitedReader); ok {
+		return lr.N
+	}
+	return -1
+}
+
 func (b *body) Close() error {
 	b.mu.Lock()
 	defer b.mu.Unlock()
@@ -725,9 +761,30 @@ func (b *body) Close() error {
 	}
 	var err error
 	switch {
+	case b.sawEOF:
+		// Already saw EOF, so no need going to look for it.
 	case b.hdr == nil && b.closing:
 		// no trailer and closing the connection next.
 		// no point in reading to EOF.
+	case b.doEarlyClose:
+		// Read up to maxPostHandlerReadBytes bytes of the body, looking for
+		// for EOF (and trailers), so we can re-use this connection.
+		if lr, ok := b.src.(*io.LimitedReader); ok && lr.N > maxPostHandlerReadBytes {
+			// There was a declared Content-Length, and we have more bytes remaining
+			// than our maxPostHandlerReadBytes tolerance. So, give up.
+			b.earlyClose = true
+		} else {
+			var n int64
+			// Consume the body, or, which will also lead to us reading
+			// the trailer headers after the body, if present.
+			n, err = io.CopyN(ioutil.Discard, bodyLocked{b}, maxPostHandlerReadBytes)
+			if err == io.EOF {
+				err = nil
+			}
+			if n == maxPostHandlerReadBytes {
+				b.earlyClose = true
+			}
+		}
 	default:
 		// Fully consume the body, which will also lead to us reading
 		// the trailer headers after the body, if present.
@@ -737,6 +794,12 @@ func (b *body) Close() error {
 	return err
 }
 
+func (b *body) didEarlyClose() bool {
+	b.mu.Lock()
+	defer b.mu.Unlock()
+	return b.earlyClose
+}
+
 // bodyLocked is a io.Reader reading from a *body when its mutex is
 // already held.
 type bodyLocked struct {
diff --git a/src/net/http/transport.go b/src/net/http/transport.go
index 782f7cd..70d1864 100644
--- a/src/net/http/transport.go
+++ b/src/net/http/transport.go
@@ -274,11 +274,12 @@ func (t *Transport) CloseIdleConnections() {
 	}
 }
 
-// CancelRequest cancels an in-flight request by closing its
-// connection.
+// CancelRequest cancels an in-flight request by closing its connection.
+// CancelRequest should only be called after RoundTrip has returned.
 func (t *Transport) CancelRequest(req *Request) {
 	t.reqMu.Lock()
 	cancel := t.reqCanceler[req]
+	delete(t.reqCanceler, req)
 	t.reqMu.Unlock()
 	if cancel != nil {
 		cancel()
@@ -474,6 +475,25 @@ func (t *Transport) setReqCanceler(r *Request, fn func()) {
 	}
 }
 
+// replaceReqCanceler replaces an existing cancel function. If there is no cancel function
+// for the request, we don't set the function and return false.
+// Since CancelRequest will clear the canceler, we can use the return value to detect if
+// the request was canceled since the last setReqCancel call.
+func (t *Transport) replaceReqCanceler(r *Request, fn func()) bool {
+	t.reqMu.Lock()
+	defer t.reqMu.Unlock()
+	_, ok := t.reqCanceler[r]
+	if !ok {
+		return false
+	}
+	if fn != nil {
+		t.reqCanceler[r] = fn
+	} else {
+		delete(t.reqCanceler, r)
+	}
+	return true
+}
+
 func (t *Transport) dial(network, addr string) (c net.Conn, err error) {
 	if t.Dial != nil {
 		return t.Dial(network, addr)
@@ -490,6 +510,10 @@ var prePendingDial, postPendingDial func()
 // is ready to write requests to.
 func (t *Transport) getConn(req *Request, cm connectMethod) (*persistConn, error) {
 	if pc := t.getIdleConn(cm); pc != nil {
+		// set request canceler to some non-nil function so we
+		// can detect whether it was cleared between now and when
+		// we enter roundTrip
+		t.setReqCanceler(req, func() {})
 		return pc, nil
 	}
 
@@ -499,6 +523,11 @@ func (t *Transport) getConn(req *Request, cm connectMethod) (*persistConn, error
 	}
 	dialc := make(chan dialRes)
 
+	// Copy these hooks so we don't race on the postPendingDial in
+	// the goroutine we launch. Issue 11136.
+	prePendingDial := prePendingDial
+	postPendingDial := postPendingDial
+
 	handlePendingDial := func() {
 		if prePendingDial != nil {
 			prePendingDial()
@@ -534,6 +563,9 @@ func (t *Transport) getConn(req *Request, cm connectMethod) (*persistConn, error
 		// when it finishes:
 		handlePendingDial()
 		return pc, nil
+	case <-req.Cancel:
+		handlePendingDial()
+		return nil, errors.New("net/http: request canceled while waiting for connection")
 	case <-cancelc:
 		handlePendingDial()
 		return nil, errors.New("net/http: request canceled while waiting for connection")
@@ -613,16 +645,9 @@ func (t *Transport) dialConn(cm connectMethod) (*persistConn, error) {
 
 	if cm.targetScheme == "https" && !tlsDial {
 		// Initiate TLS and check remote host name against certificate.
-		cfg := t.TLSClientConfig
-		if cfg == nil || cfg.ServerName == "" {
-			host := cm.tlsHost()
-			if cfg == nil {
-				cfg = &tls.Config{ServerName: host}
-			} else {
-				clone := *cfg // shallow clone
-				clone.ServerName = host
-				cfg = &clone
-			}
+		cfg := cloneTLSClientConfig(t.TLSClientConfig)
+		if cfg.ServerName == "" {
+			cfg.ServerName = cm.tlsHost()
 		}
 		plainConn := pconn.conn
 		tlsConn := tls.Client(plainConn, cfg)
@@ -662,7 +687,7 @@ func (t *Transport) dialConn(cm connectMethod) (*persistConn, error) {
 	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 {
@@ -805,6 +830,7 @@ type persistConn struct {
 	numExpectedResponses int
 	closed               bool // whether conn has been closed
 	broken               bool // an error has happened on this connection; marked broken so it's not reused.
+	canceled             bool // whether this conn was broken due a CancelRequest
 	// mutateHeaderFunc is an optional func to modify extra
 	// headers on each outbound request before it's written. (the
 	// original Request given to RoundTrip is not modified)
@@ -819,25 +845,33 @@ func (pc *persistConn) isBroken() bool {
 	return b
 }
 
-func (pc *persistConn) cancelRequest() {
-	pc.conn.Close()
+// isCanceled reports whether this connection was closed due to CancelRequest.
+func (pc *persistConn) isCanceled() bool {
+	pc.lk.Lock()
+	defer pc.lk.Unlock()
+	return pc.canceled
 }
 
-var remoteSideClosedFunc func(error) bool // or nil to use default
-
-func remoteSideClosed(err error) bool {
-	if err == io.EOF {
-		return true
-	}
-	if remoteSideClosedFunc != nil {
-		return remoteSideClosedFunc(err)
-	}
-	return false
+func (pc *persistConn) cancelRequest() {
+	pc.lk.Lock()
+	defer pc.lk.Unlock()
+	pc.canceled = true
+	pc.closeLocked()
 }
 
 func (pc *persistConn) readLoop() {
-	alive := true
+	// eofc is used to block http.Handler goroutines reading from Response.Body
+	// at EOF until this goroutines has (potentially) added the connection
+	// back to the idle pool.
+	eofc := make(chan struct{})
+	defer close(eofc) // unblock reader on errors
+
+	// Read this once, before loop starts. (to avoid races in tests)
+	testHookMu.Lock()
+	testHookReadLoopBeforeNextRead := testHookReadLoopBeforeNextRead
+	testHookMu.Unlock()
 
+	alive := true
 	for alive {
 		pb, err := pc.br.Peek(1)
 
@@ -895,49 +929,79 @@ func (pc *persistConn) readLoop() {
 			alive = false
 		}
 
-		var waitForBodyRead chan bool
+		var waitForBodyRead chan bool // channel is nil when there's no body
 		if hasBody {
 			waitForBodyRead = make(chan bool, 2)
 			resp.Body.(*bodyEOFSignal).earlyCloseFn = func() error {
-				// Sending false here sets alive to
-				// false and closes the connection
-				// below.
 				waitForBodyRead <- false
 				return nil
 			}
-			resp.Body.(*bodyEOFSignal).fn = func(err error) {
-				waitForBodyRead <- alive &&
-					err == nil &&
-					!pc.sawEOF &&
-					pc.wroteRequest() &&
-					pc.t.putIdleConn(pc)
+			resp.Body.(*bodyEOFSignal).fn = func(err error) error {
+				isEOF := err == io.EOF
+				waitForBodyRead <- isEOF
+				if isEOF {
+					<-eofc // see comment at top
+				} else if err != nil && pc.isCanceled() {
+					return errRequestCanceled
+				}
+				return err
 			}
+		} else {
+			// Before send on rc.ch, as client might re-use the
+			// same *Request pointer, and we don't want to set this
+			// on t from this persistConn while the Transport
+			// potentially spins up a different persistConn for the
+			// caller's subsequent request.
+			pc.t.setReqCanceler(rc.req, nil)
 		}
 
-		if alive && !hasBody {
-			alive = !pc.sawEOF &&
-				pc.wroteRequest() &&
-				pc.t.putIdleConn(pc)
-		}
+		pc.lk.Lock()
+		pc.numExpectedResponses--
+		pc.lk.Unlock()
 
+		// The connection might be going away when we put the
+		// idleConn below. When that happens, we close the response channel to signal
+		// to roundTrip that the connection is gone. roundTrip waits for
+		// both closing and a response in a select, so it might choose
+		// the close channel, rather than the response.
+		// We send the response first so that roundTrip can check
+		// if there is a pending one with a non-blocking select
+		// on the response channel before erroring out.
 		rc.ch <- responseAndError{resp, err}
 
-		// Wait for the just-returned response body to be fully consumed
-		// before we race and peek on the underlying bufio reader.
-		if waitForBodyRead != nil {
+		if hasBody {
+			// To avoid a race, wait for the just-returned
+			// response body to be fully consumed before peek on
+			// the underlying bufio reader.
 			select {
-			case alive = <-waitForBodyRead:
+			case <-rc.req.Cancel:
+				alive = false
+				pc.t.CancelRequest(rc.req)
+			case bodyEOF := <-waitForBodyRead:
+				pc.t.setReqCanceler(rc.req, nil) // before pc might return to idle pool
+				alive = alive &&
+					bodyEOF &&
+					!pc.sawEOF &&
+					pc.wroteRequest() &&
+					pc.t.putIdleConn(pc)
+				if bodyEOF {
+					eofc <- struct{}{}
+				}
 			case <-pc.closech:
 				alive = false
 			}
+		} else {
+			alive = alive &&
+				!pc.sawEOF &&
+				pc.wroteRequest() &&
+				pc.t.putIdleConn(pc)
 		}
 
-		pc.t.setReqCanceler(rc.req, nil)
-
-		if !alive {
-			pc.close()
+		if hook := testHookReadLoopBeforeNextRead; hook != nil {
+			hook()
 		}
 	}
+	pc.close()
 }
 
 func (pc *persistConn) writeLoop() {
@@ -1027,9 +1091,24 @@ func (e *httpError) Temporary() bool { return true }
 
 var errTimeout error = &httpError{err: "net/http: timeout awaiting response headers", timeout: true}
 var errClosed error = &httpError{err: "net/http: transport closed before response was received"}
+var errRequestCanceled = errors.New("net/http: request canceled")
+
+// nil except for tests
+var (
+	testHookPersistConnClosedGotRes func()
+	testHookEnterRoundTrip          func()
+	testHookMu                      sync.Locker = fakeLocker{} // guards following
+	testHookReadLoopBeforeNextRead  func()
+)
 
 func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err error) {
-	pc.t.setReqCanceler(req.Request, pc.cancelRequest)
+	if hook := testHookEnterRoundTrip; hook != nil {
+		hook()
+	}
+	if !pc.t.replaceReqCanceler(req.Request, pc.cancelRequest) {
+		pc.t.putIdleConn(pc)
+		return nil, errRequestCanceled
+	}
 	pc.lk.Lock()
 	pc.numExpectedResponses++
 	headerFn := pc.mutateHeaderFunc
@@ -1055,15 +1134,19 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err
 		// Note that we don't request this for HEAD requests,
 		// due to a bug in nginx:
 		//   http://trac.nginx.org/nginx/ticket/358
-		//   http://golang.org/issue/5522
+		//   https://golang.org/issue/5522
 		//
 		// We don't request gzip if the request is for a range, since
 		// auto-decoding a portion of a gzipped document will just fail
-		// anyway. See http://golang.org/issue/8923
+		// anyway. See https://golang.org/issue/8923
 		requestedGzip = true
 		req.extraHeaders().Set("Accept-Encoding", "gzip")
 	}
 
+	if pc.t.DisableKeepAlives {
+		req.extraHeaders().Set("Connection", "close")
+	}
+
 	// Write the request concurrently with waiting for a response,
 	// in case the server decides to reply before reading our full
 	// request body.
@@ -1074,38 +1157,57 @@ func (pc *persistConn) roundTrip(req *transportRequest) (resp *Response, err err
 	pc.reqch <- requestAndChan{req.Request, resc, requestedGzip}
 
 	var re responseAndError
-	var pconnDeadCh = pc.closech
-	var failTicker <-chan time.Time
 	var respHeaderTimer <-chan time.Time
+	cancelChan := req.Request.Cancel
 WaitResponse:
 	for {
 		select {
 		case err := <-writeErrCh:
+			if isNetWriteError(err) {
+				// Issue 11745. If we failed to write the request
+				// body, it's possible the server just heard enough
+				// and already wrote to us. Prioritize the server's
+				// response over returning a body write error.
+				select {
+				case re = <-resc:
+					pc.close()
+					break WaitResponse
+				case <-time.After(50 * time.Millisecond):
+					// Fall through.
+				}
+			}
 			if err != nil {
 				re = responseAndError{nil, err}
 				pc.close()
 				break WaitResponse
 			}
 			if d := pc.t.ResponseHeaderTimeout; d > 0 {
-				respHeaderTimer = time.After(d)
+				timer := time.NewTimer(d)
+				defer timer.Stop() // prevent leaks
+				respHeaderTimer = timer.C
 			}
-		case <-pconnDeadCh:
+		case <-pc.closech:
 			// The persist connection is dead. This shouldn't
 			// usually happen (only with Connection: close responses
 			// with no response bodies), but if it does happen it
 			// means either a) the remote server hung up on us
 			// prematurely, or b) the readLoop sent us a response &
 			// closed its closech at roughly the same time, and we
-			// selected this case first, in which case a response
-			// might still be coming soon.
-			//
-			// We can't avoid the select race in b) by using a unbuffered
-			// resc channel instead, because then goroutines can
-			// leak if we exit due to other errors.
-			pconnDeadCh = nil                               // avoid spinning
-			failTicker = time.After(100 * time.Millisecond) // arbitrary time to wait for resc
-		case <-failTicker:
-			re = responseAndError{err: errClosed}
+			// selected this case first. If we got a response, readLoop makes sure
+			// to send it before it puts the conn and closes the channel.
+			// That way, we can fetch the response, if there is one,
+			// with a non-blocking receive.
+			select {
+			case re = <-resc:
+				if fn := testHookPersistConnClosedGotRes; fn != nil {
+					fn()
+				}
+			default:
+				re = responseAndError{err: errClosed}
+				if pc.isCanceled() {
+					re = responseAndError{err: errRequestCanceled}
+				}
+			}
 			break WaitResponse
 		case <-respHeaderTimer:
 			pc.close()
@@ -1113,13 +1215,12 @@ WaitResponse:
 			break WaitResponse
 		case re = <-resc:
 			break WaitResponse
+		case <-cancelChan:
+			pc.t.CancelRequest(req.Request)
+			cancelChan = nil
 		}
 	}
 
-	pc.lk.Lock()
-	pc.numExpectedResponses--
-	pc.lk.Unlock()
-
 	if re.err != nil {
 		pc.t.setReqCanceler(req.Request, nil)
 	}
@@ -1167,16 +1268,18 @@ func canonicalAddr(url *url.URL) string {
 
 // bodyEOFSignal wraps a ReadCloser but runs fn (if non-nil) at most
 // once, right before its final (error-producing) Read or Close call
-// returns. If earlyCloseFn is non-nil and Close is called before
-// io.EOF is seen, earlyCloseFn is called instead of fn, and its
-// return value is the return value from Close.
+// returns. fn should return the new error to return from Read or Close.
+//
+// If earlyCloseFn is non-nil and Close is called before io.EOF is
+// seen, earlyCloseFn is called instead of fn, and its return value is
+// the return value from Close.
 type bodyEOFSignal struct {
 	body         io.ReadCloser
-	mu           sync.Mutex   // guards following 4 fields
-	closed       bool         // whether Close has been called
-	rerr         error        // sticky Read error
-	fn           func(error)  // error will be nil on Read io.EOF
-	earlyCloseFn func() error // optional alt Close func used if io.EOF not seen
+	mu           sync.Mutex        // guards following 4 fields
+	closed       bool              // whether Close has been called
+	rerr         error             // sticky Read error
+	fn           func(error) error // err will be nil on Read io.EOF
+	earlyCloseFn func() error      // optional alt Close func used if io.EOF not seen
 }
 
 func (es *bodyEOFSignal) Read(p []byte) (n int, err error) {
@@ -1197,7 +1300,7 @@ func (es *bodyEOFSignal) Read(p []byte) (n int, err error) {
 		if es.rerr == nil {
 			es.rerr = err
 		}
-		es.condfn(err)
+		err = es.condfn(err)
 	}
 	return
 }
@@ -1213,20 +1316,17 @@ func (es *bodyEOFSignal) Close() error {
 		return es.earlyCloseFn()
 	}
 	err := es.body.Close()
-	es.condfn(err)
-	return err
+	return es.condfn(err)
 }
 
 // caller must hold es.mu.
-func (es *bodyEOFSignal) condfn(err error) {
+func (es *bodyEOFSignal) condfn(err error) error {
 	if es.fn == nil {
-		return
-	}
-	if err == io.EOF {
-		err = nil
+		return err
 	}
-	es.fn(err)
+	err = es.fn(err)
 	es.fn = nil
+	return err
 }
 
 // gzipReader wraps a response body so it can lazily
@@ -1273,3 +1373,89 @@ func (nr noteEOFReader) Read(p []byte) (n int, err error) {
 	}
 	return
 }
+
+// fakeLocker is a sync.Locker which does nothing. It's used to guard
+// test-only fields when not under test, to avoid runtime atomic
+// overhead.
+type fakeLocker struct{}
+
+func (fakeLocker) Lock()   {}
+func (fakeLocker) Unlock() {}
+
+func isNetWriteError(err error) bool {
+	switch e := err.(type) {
+	case *url.Error:
+		return isNetWriteError(e.Err)
+	case *net.OpError:
+		return e.Op == "write"
+	default:
+		return false
+	}
+}
+
+// cloneTLSConfig returns a shallow clone of the exported
+// fields of cfg, ignoring the unexported sync.Once, which
+// contains a mutex and must not be copied.
+//
+// The cfg must not be in active use by tls.Server, or else
+// there can still be a race with tls.Server updating SessionTicketKey
+// and our copying it, and also a race with the server setting
+// SessionTicketsDisabled=false on failure to set the random
+// ticket key.
+//
+// If cfg is nil, a new zero tls.Config is returned.
+func cloneTLSConfig(cfg *tls.Config) *tls.Config {
+	if cfg == nil {
+		return &tls.Config{}
+	}
+	return &tls.Config{
+		Rand:                     cfg.Rand,
+		Time:                     cfg.Time,
+		Certificates:             cfg.Certificates,
+		NameToCertificate:        cfg.NameToCertificate,
+		GetCertificate:           cfg.GetCertificate,
+		RootCAs:                  cfg.RootCAs,
+		NextProtos:               cfg.NextProtos,
+		ServerName:               cfg.ServerName,
+		ClientAuth:               cfg.ClientAuth,
+		ClientCAs:                cfg.ClientCAs,
+		InsecureSkipVerify:       cfg.InsecureSkipVerify,
+		CipherSuites:             cfg.CipherSuites,
+		PreferServerCipherSuites: cfg.PreferServerCipherSuites,
+		SessionTicketsDisabled:   cfg.SessionTicketsDisabled,
+		SessionTicketKey:         cfg.SessionTicketKey,
+		ClientSessionCache:       cfg.ClientSessionCache,
+		MinVersion:               cfg.MinVersion,
+		MaxVersion:               cfg.MaxVersion,
+		CurvePreferences:         cfg.CurvePreferences,
+	}
+}
+
+// cloneTLSClientConfig is like cloneTLSConfig but omits
+// the fields SessionTicketsDisabled and SessionTicketKey.
+// This makes it safe to call cloneTLSClientConfig on a config
+// in active use by a server.
+func cloneTLSClientConfig(cfg *tls.Config) *tls.Config {
+	if cfg == nil {
+		return &tls.Config{}
+	}
+	return &tls.Config{
+		Rand:                     cfg.Rand,
+		Time:                     cfg.Time,
+		Certificates:             cfg.Certificates,
+		NameToCertificate:        cfg.NameToCertificate,
+		GetCertificate:           cfg.GetCertificate,
+		RootCAs:                  cfg.RootCAs,
+		NextProtos:               cfg.NextProtos,
+		ServerName:               cfg.ServerName,
+		ClientAuth:               cfg.ClientAuth,
+		ClientCAs:                cfg.ClientCAs,
+		InsecureSkipVerify:       cfg.InsecureSkipVerify,
+		CipherSuites:             cfg.CipherSuites,
+		PreferServerCipherSuites: cfg.PreferServerCipherSuites,
+		ClientSessionCache:       cfg.ClientSessionCache,
+		MinVersion:               cfg.MinVersion,
+		MaxVersion:               cfg.MaxVersion,
+		CurvePreferences:         cfg.CurvePreferences,
+	}
+}
diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go
index defa633..c21d4af 100644
--- a/src/net/http/transport_test.go
+++ b/src/net/http/transport_test.go
@@ -18,11 +18,11 @@ import (
 	"io/ioutil"
 	"log"
 	"net"
-	"net/http"
 	. "net/http"
 	"net/http/httptest"
 	"net/url"
 	"os"
+	"reflect"
 	"runtime"
 	"strconv"
 	"strings"
@@ -39,6 +39,7 @@ var hostPortHandler = HandlerFunc(func(w ResponseWriter, r *Request) {
 	if r.FormValue("close") == "true" {
 		w.Header().Set("Connection", "close")
 	}
+	w.Header().Set("X-Saw-Close", fmt.Sprint(r.Close))
 	w.Write([]byte(r.RemoteAddr))
 })
 
@@ -228,6 +229,10 @@ func TestTransportConnectionCloseOnRequest(t *testing.T) {
 			if err != nil {
 				t.Fatalf("error in connectionClose=%v, req #%d, Do: %v", connectionClose, n, err)
 			}
+			if got, want := res.Header.Get("X-Saw-Close"), fmt.Sprint(connectionClose); got != want {
+				t.Errorf("For connectionClose = %v; handler's X-Saw-Close was %v; want %v",
+					connectionClose, got, !connectionClose)
+			}
 			body, err := ioutil.ReadAll(res.Body)
 			if err != nil {
 				t.Fatalf("error in connectionClose=%v, req #%d, ReadAll: %v", connectionClose, n, err)
@@ -249,6 +254,27 @@ func TestTransportConnectionCloseOnRequest(t *testing.T) {
 	connSet.check(t)
 }
 
+// if the Transport's DisableKeepAlives is set, all requests should
+// send Connection: close.
+func TestTransportConnectionCloseOnRequestDisableKeepAlive(t *testing.T) {
+	defer afterTest(t)
+	ts := httptest.NewServer(hostPortHandler)
+	defer ts.Close()
+
+	tr := &Transport{
+		DisableKeepAlives: true,
+	}
+	c := &Client{Transport: tr}
+	res, err := c.Get(ts.URL)
+	if err != nil {
+		t.Fatal(err)
+	}
+	res.Body.Close()
+	if res.Header.Get("X-Saw-Close") != "true" {
+		t.Errorf("handler didn't see Connection: close ")
+	}
+}
+
 func TestTransportIdleCacheKeys(t *testing.T) {
 	defer afterTest(t)
 	ts := httptest.NewServer(hostPortHandler)
@@ -293,7 +319,7 @@ func TestTransportReadToEndReusesConn(t *testing.T) {
 		addrSeen[r.RemoteAddr]++
 		if r.URL.Path == "/chunked/" {
 			w.WriteHeader(200)
-			w.(http.Flusher).Flush()
+			w.(Flusher).Flush()
 		} else {
 			w.Header().Set("Content-Type", strconv.Itoa(len(msg)))
 			w.WriteHeader(200)
@@ -308,7 +334,7 @@ func TestTransportReadToEndReusesConn(t *testing.T) {
 		wantLen := []int{len(msg), -1}[pi]
 		addrSeen = make(map[string]int)
 		for i := 0; i < 3; i++ {
-			res, err := http.Get(ts.URL + path)
+			res, err := Get(ts.URL + path)
 			if err != nil {
 				t.Errorf("Get %s: %v", path, err)
 				continue
@@ -459,7 +485,7 @@ func TestTransportServerClosingUnexpectedly(t *testing.T) {
 	}
 }
 
-// Test for http://golang.org/issue/2616 (appropriate issue number)
+// Test for https://golang.org/issue/2616 (appropriate issue number)
 // This fails pretty reliably with GOMAXPROCS=100 or something high.
 func TestStressSurpriseServerCloses(t *testing.T) {
 	defer afterTest(t)
@@ -479,12 +505,17 @@ func TestStressSurpriseServerCloses(t *testing.T) {
 
 	tr := &Transport{DisableKeepAlives: false}
 	c := &Client{Transport: tr}
+	defer tr.CloseIdleConnections()
 
 	// Do a bunch of traffic from different goroutines. Send to activityc
 	// after each request completes, regardless of whether it failed.
+	// If these are too high, OS X exhausts its ephemeral ports
+	// and hangs waiting for them to transition TCP states. That's
+	// not what we want to test.  TODO(bradfitz): use an io.Pipe
+	// dialer for this test instead?
 	const (
-		numClients    = 50
-		reqsPerClient = 250
+		numClients    = 20
+		reqsPerClient = 25
 	)
 	activityc := make(chan bool)
 	for i := 0; i < numClients; i++ {
@@ -567,11 +598,22 @@ func TestTransportHeadChunkedResponse(t *testing.T) {
 	tr := &Transport{DisableKeepAlives: false}
 	c := &Client{Transport: tr}
 
+	// Ensure that we wait for the readLoop to complete before
+	// calling Head again
+	didRead := make(chan bool)
+	SetReadLoopBeforeNextReadHook(func() { didRead <- true })
+	defer SetReadLoopBeforeNextReadHook(nil)
+
 	res1, err := c.Head(ts.URL)
+	<-didRead
+
 	if err != nil {
 		t.Fatalf("request 1 error: %v", err)
 	}
+
 	res2, err := c.Head(ts.URL)
+	<-didRead
+
 	if err != nil {
 		t.Fatalf("request 2 error: %v", err)
 	}
@@ -833,7 +875,7 @@ func TestTransportGzipShort(t *testing.T) {
 // tests that persistent goroutine connections shut down when no longer desired.
 func TestTransportPersistConnLeak(t *testing.T) {
 	if runtime.GOOS == "plan9" {
-		t.Skip("skipping test; see http://golang.org/issue/7237")
+		t.Skip("skipping test; see https://golang.org/issue/7237")
 	}
 	defer afterTest(t)
 	gotReqCh := make(chan bool)
@@ -902,7 +944,7 @@ func TestTransportPersistConnLeak(t *testing.T) {
 // request.ContentLength is explicitly short
 func TestTransportPersistConnLeakShortBody(t *testing.T) {
 	if runtime.GOOS == "plan9" {
-		t.Skip("skipping test; see http://golang.org/issue/7237")
+		t.Skip("skipping test; see https://golang.org/issue/7237")
 	}
 	defer afterTest(t)
 	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
@@ -941,7 +983,7 @@ func TestTransportPersistConnLeakShortBody(t *testing.T) {
 	}
 }
 
-// This used to crash; http://golang.org/issue/3266
+// This used to crash; https://golang.org/issue/3266
 func TestTransportIdleConnCrash(t *testing.T) {
 	defer afterTest(t)
 	tr := &Transport{}
@@ -1023,7 +1065,7 @@ func TestIssue3595(t *testing.T) {
 	}
 }
 
-// From http://golang.org/issue/4454 ,
+// From https://golang.org/issue/4454 ,
 // "client fails to handle requests with no body and chunked encoding"
 func TestChunkedNoContent(t *testing.T) {
 	defer afterTest(t)
@@ -1110,7 +1152,7 @@ func TestTransportConcurrency(t *testing.T) {
 
 func TestIssue4191_InfiniteGetTimeout(t *testing.T) {
 	if runtime.GOOS == "plan9" {
-		t.Skip("skipping test; see http://golang.org/issue/7237")
+		t.Skip("skipping test; see https://golang.org/issue/7237")
 	}
 	defer afterTest(t)
 	const debug = false
@@ -1174,7 +1216,7 @@ func TestIssue4191_InfiniteGetTimeout(t *testing.T) {
 
 func TestIssue4191_InfiniteGetToPutTimeout(t *testing.T) {
 	if runtime.GOOS == "plan9" {
-		t.Skip("skipping test; see http://golang.org/issue/7237")
+		t.Skip("skipping test; see https://golang.org/issue/7237")
 	}
 	defer afterTest(t)
 	const debug = false
@@ -1345,8 +1387,8 @@ func TestTransportCancelRequest(t *testing.T) {
 	body, err := ioutil.ReadAll(res.Body)
 	d := time.Since(t0)
 
-	if err == nil {
-		t.Error("expected an error reading the body")
+	if err != ExportErrRequestCanceled {
+		t.Errorf("Body.Read error = %v; want errRequestCanceled", err)
 	}
 	if string(body) != "Hello" {
 		t.Errorf("Body = %q; want Hello", body)
@@ -1356,7 +1398,7 @@ func TestTransportCancelRequest(t *testing.T) {
 	}
 	// Verify no outstanding requests after readLoop/writeLoop
 	// goroutines shut down.
-	for tries := 3; tries > 0; tries-- {
+	for tries := 5; tries > 0; tries-- {
 		n := tr.NumPendingRequestsForTesting()
 		if n == 0 {
 			break
@@ -1405,6 +1447,7 @@ func TestTransportCancelRequestInDial(t *testing.T) {
 
 	eventLog.Printf("canceling")
 	tr.CancelRequest(req)
+	tr.CancelRequest(req) // used to panic on second call
 
 	select {
 	case <-gotres:
@@ -1422,6 +1465,135 @@ Get = Get http://something.no-network.tld/: net/http: request canceled while wai
 	}
 }
 
+func TestCancelRequestWithChannel(t *testing.T) {
+	defer afterTest(t)
+	if testing.Short() {
+		t.Skip("skipping test in -short mode")
+	}
+	unblockc := make(chan bool)
+	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+		fmt.Fprintf(w, "Hello")
+		w.(Flusher).Flush() // send headers and some body
+		<-unblockc
+	}))
+	defer ts.Close()
+	defer close(unblockc)
+
+	tr := &Transport{}
+	defer tr.CloseIdleConnections()
+	c := &Client{Transport: tr}
+
+	req, _ := NewRequest("GET", ts.URL, nil)
+	ch := make(chan struct{})
+	req.Cancel = ch
+
+	res, err := c.Do(req)
+	if err != nil {
+		t.Fatal(err)
+	}
+	go func() {
+		time.Sleep(1 * time.Second)
+		close(ch)
+	}()
+	t0 := time.Now()
+	body, err := ioutil.ReadAll(res.Body)
+	d := time.Since(t0)
+
+	if err != ExportErrRequestCanceled {
+		t.Errorf("Body.Read error = %v; want errRequestCanceled", err)
+	}
+	if string(body) != "Hello" {
+		t.Errorf("Body = %q; want Hello", body)
+	}
+	if d < 500*time.Millisecond {
+		t.Errorf("expected ~1 second delay; got %v", d)
+	}
+	// Verify no outstanding requests after readLoop/writeLoop
+	// goroutines shut down.
+	for tries := 5; tries > 0; tries-- {
+		n := tr.NumPendingRequestsForTesting()
+		if n == 0 {
+			break
+		}
+		time.Sleep(100 * time.Millisecond)
+		if tries == 1 {
+			t.Errorf("pending requests = %d; want 0", n)
+		}
+	}
+}
+
+func TestCancelRequestWithChannelBeforeDo(t *testing.T) {
+	defer afterTest(t)
+	unblockc := make(chan bool)
+	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+		<-unblockc
+	}))
+	defer ts.Close()
+	defer close(unblockc)
+
+	// Don't interfere with the next test on plan9.
+	// Cf. https://golang.org/issues/11476
+	if runtime.GOOS == "plan9" {
+		defer time.Sleep(500 * time.Millisecond)
+	}
+
+	tr := &Transport{}
+	defer tr.CloseIdleConnections()
+	c := &Client{Transport: tr}
+
+	req, _ := NewRequest("GET", ts.URL, nil)
+	ch := make(chan struct{})
+	req.Cancel = ch
+	close(ch)
+
+	_, err := c.Do(req)
+	if err == nil || !strings.Contains(err.Error(), "canceled") {
+		t.Errorf("Do error = %v; want cancelation", err)
+	}
+}
+
+// Issue 11020. The returned error message should be errRequestCanceled
+func TestTransportCancelBeforeResponseHeaders(t *testing.T) {
+	t.Skip("Skipping flaky test; see Issue 11894")
+	defer afterTest(t)
+
+	serverConnCh := make(chan net.Conn, 1)
+	tr := &Transport{
+		Dial: func(network, addr string) (net.Conn, error) {
+			cc, sc := net.Pipe()
+			serverConnCh <- sc
+			return cc, nil
+		},
+	}
+	defer tr.CloseIdleConnections()
+	errc := make(chan error, 1)
+	req, _ := NewRequest("GET", "http://example.com/", nil)
+	go func() {
+		_, err := tr.RoundTrip(req)
+		errc <- err
+	}()
+
+	sc := <-serverConnCh
+	verb := make([]byte, 3)
+	if _, err := io.ReadFull(sc, verb); err != nil {
+		t.Errorf("Error reading HTTP verb from server: %v", err)
+	}
+	if string(verb) != "GET" {
+		t.Errorf("server received %q; want GET", verb)
+	}
+	defer sc.Close()
+
+	tr.CancelRequest(req)
+
+	err := <-errc
+	if err == nil {
+		t.Fatalf("unexpected success from RoundTrip")
+	}
+	if err != ExportErrRequestCanceled {
+		t.Errorf("RoundTrip error = %v; want ExportErrRequestCanceled", err)
+	}
+}
+
 // golang.org/issue/3672 -- Client can't close HTTP stream
 // Calling Close on a Response.Body used to just read until EOF.
 // Now it actually closes the TCP connection.
@@ -1795,6 +1967,11 @@ func TestIdleConnChannelLeak(t *testing.T) {
 	}))
 	defer ts.Close()
 
+	const nReqs = 5
+	didRead := make(chan bool, nReqs)
+	SetReadLoopBeforeNextReadHook(func() { didRead <- true })
+	defer SetReadLoopBeforeNextReadHook(nil)
+
 	tr := &Transport{
 		Dial: func(netw, addr string) (net.Conn, error) {
 			return net.Dial(netw, ts.Listener.Addr().String())
@@ -1807,12 +1984,28 @@ func TestIdleConnChannelLeak(t *testing.T) {
 	// First, without keep-alives.
 	for _, disableKeep := range []bool{true, false} {
 		tr.DisableKeepAlives = disableKeep
-		for i := 0; i < 5; i++ {
+		for i := 0; i < nReqs; i++ {
 			_, err := c.Get(fmt.Sprintf("http://foo-host-%d.tld/", i))
 			if err != nil {
 				t.Fatal(err)
 			}
+			// Note: no res.Body.Close is needed here, since the
+			// response Content-Length is zero. Perhaps the test
+			// should be more explicit and use a HEAD, but tests
+			// elsewhere guarantee that zero byte responses generate
+			// a "Content-Length: 0" instead of chunking.
+		}
+
+		// At this point, each of the 5 Transport.readLoop goroutines
+		// are scheduling noting that there are no response bodies (see
+		// earlier comment), and are then calling putIdleConn, which
+		// decrements this count. Usually that happens quickly, which is
+		// why this test has seemed to work for ages. But it's still
+		// racey: we have wait for them to finish first. See Issue 10427
+		for i := 0; i < nReqs; i++ {
+			<-didRead
 		}
+
 		if got := tr.IdleConnChMapSizeForTesting(); got != 0 {
 			t.Fatalf("ForDisableKeepAlives = %v, map size = %d; want 0", disableKeep, got)
 		}
@@ -1824,7 +2017,7 @@ func TestIdleConnChannelLeak(t *testing.T) {
 // then closes it.
 func TestTransportClosesRequestBody(t *testing.T) {
 	defer afterTest(t)
-	ts := httptest.NewServer(http.HandlerFunc(func(w ResponseWriter, r *Request) {
+	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
 		io.Copy(ioutil.Discard, r.Body)
 	}))
 	defer ts.Close()
@@ -2060,6 +2253,38 @@ func TestTransportNoReuseAfterEarlyResponse(t *testing.T) {
 	}
 }
 
+// Tests that we don't leak Transport persistConn.readLoop goroutines
+// when a server hangs up immediately after saying it would keep-alive.
+func TestTransportIssue10457(t *testing.T) {
+	defer afterTest(t) // used to fail in goroutine leak check
+	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+		// Send a response with no body, keep-alive
+		// (implicit), and then lie and immediately close the
+		// connection. This forces the Transport's readLoop to
+		// immediately Peek an io.EOF and get to the point
+		// that used to hang.
+		conn, _, _ := w.(Hijacker).Hijack()
+		conn.Write([]byte("HTTP/1.1 200 OK\r\nFoo: Bar\r\nContent-Length: 0\r\n\r\n")) // keep-alive
+		conn.Close()
+	}))
+	defer ts.Close()
+	tr := &Transport{}
+	defer tr.CloseIdleConnections()
+	cl := &Client{Transport: tr}
+	res, err := cl.Get(ts.URL)
+	if err != nil {
+		t.Fatalf("Get: %v", err)
+	}
+	defer res.Body.Close()
+
+	// Just a sanity check that we at least get the response. The real
+	// test here is that the "defer afterTest" above doesn't find any
+	// leaked goroutines.
+	if got, want := res.Header.Get("Foo"), "Bar"; got != want {
+		t.Errorf("Foo header = %q; want %q", got, want)
+	}
+}
+
 type errorReader struct {
 	err error
 }
@@ -2073,7 +2298,7 @@ func (f closerFunc) Close() error { return f() }
 // Issue 6981
 func TestTransportClosesBodyOnError(t *testing.T) {
 	if runtime.GOOS == "plan9" {
-		t.Skip("skipping test; see http://golang.org/issue/7782")
+		t.Skip("skipping test; see https://golang.org/issue/7782")
 	}
 	defer afterTest(t)
 	readBody := make(chan error, 1)
@@ -2162,13 +2387,13 @@ func TestTransportDialTLS(t *testing.T) {
 // Test for issue 8755
 // Ensure that if a proxy returns an error, it is exposed by RoundTrip
 func TestRoundTripReturnsProxyError(t *testing.T) {
-	badProxy := func(*http.Request) (*url.URL, error) {
+	badProxy := func(*Request) (*url.URL, error) {
 		return nil, errors.New("errorMessage")
 	}
 
 	tr := &Transport{Proxy: badProxy}
 
-	req, _ := http.NewRequest("GET", "http://example.com", nil)
+	req, _ := NewRequest("GET", "http://example.com", nil)
 
 	_, err := tr.RoundTrip(req)
 
@@ -2249,7 +2474,268 @@ func TestTransportRangeAndGzip(t *testing.T) {
 	res.Body.Close()
 }
 
-func wantBody(res *http.Response, err error, want string) error {
+// Previously, we used to handle a logical race within RoundTrip by waiting for 100ms
+// in the case of an error. Changing the order of the channel operations got rid of this
+// race.
+//
+// In order to test that the channel op reordering works, we install a hook into the
+// roundTrip function which gets called if we saw the connection go away and
+// we subsequently received a response.
+func TestTransportResponseCloseRace(t *testing.T) {
+	if testing.Short() {
+		t.Skip("skipping in short mode")
+	}
+	defer afterTest(t)
+
+	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+	}))
+	defer ts.Close()
+	sawRace := false
+	SetInstallConnClosedHook(func() {
+		sawRace = true
+	})
+	defer SetInstallConnClosedHook(nil)
+	tr := &Transport{
+		DisableKeepAlives: true,
+	}
+	req, err := NewRequest("GET", ts.URL, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	// selects are not deterministic, so do this a bunch
+	// and see if we handle the logical race at least once.
+	for i := 0; i < 10000; i++ {
+		resp, err := tr.RoundTrip(req)
+		if err != nil {
+			t.Fatalf("unexpected error: %s", err)
+			continue
+		}
+		resp.Body.Close()
+		if sawRace {
+			break
+		}
+	}
+	if !sawRace {
+		t.Errorf("didn't see response/connection going away race")
+	}
+}
+
+// Test for issue 10474
+func TestTransportResponseCancelRace(t *testing.T) {
+	defer afterTest(t)
+
+	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+		// important that this response has a body.
+		var b [1024]byte
+		w.Write(b[:])
+	}))
+	defer ts.Close()
+
+	tr := &Transport{}
+	defer tr.CloseIdleConnections()
+
+	req, err := NewRequest("GET", ts.URL, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	res, err := tr.RoundTrip(req)
+	if err != nil {
+		t.Fatal(err)
+	}
+	// If we do an early close, Transport just throws the connection away and
+	// doesn't reuse it. In order to trigger the bug, it has to reuse the connection
+	// so read the body
+	if _, err := io.Copy(ioutil.Discard, res.Body); err != nil {
+		t.Fatal(err)
+	}
+
+	req2, err := NewRequest("GET", ts.URL, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	tr.CancelRequest(req)
+	res, err = tr.RoundTrip(req2)
+	if err != nil {
+		t.Fatal(err)
+	}
+	res.Body.Close()
+}
+
+func TestTransportDialCancelRace(t *testing.T) {
+	defer afterTest(t)
+
+	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {}))
+	defer ts.Close()
+
+	tr := &Transport{}
+	defer tr.CloseIdleConnections()
+
+	req, err := NewRequest("GET", ts.URL, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	SetEnterRoundTripHook(func() {
+		tr.CancelRequest(req)
+	})
+	defer SetEnterRoundTripHook(nil)
+	res, err := tr.RoundTrip(req)
+	if err != ExportErrRequestCanceled {
+		t.Errorf("expected canceled request error; got %v", err)
+		if err == nil {
+			res.Body.Close()
+		}
+	}
+}
+
+// logWritesConn is a net.Conn that logs each Write call to writes
+// and then proxies to w.
+// It proxies Read calls to a reader it receives from rch.
+type logWritesConn struct {
+	net.Conn // nil. crash on use.
+
+	w io.Writer
+
+	rch <-chan io.Reader
+	r   io.Reader // nil until received by rch
+
+	mu     sync.Mutex
+	writes []string
+}
+
+func (c *logWritesConn) Write(p []byte) (n int, err error) {
+	c.mu.Lock()
+	defer c.mu.Unlock()
+	c.writes = append(c.writes, string(p))
+	return c.w.Write(p)
+}
+
+func (c *logWritesConn) Read(p []byte) (n int, err error) {
+	if c.r == nil {
+		c.r = <-c.rch
+	}
+	return c.r.Read(p)
+}
+
+func (c *logWritesConn) Close() error { return nil }
+
+// Issue 6574
+func TestTransportFlushesBodyChunks(t *testing.T) {
+	defer afterTest(t)
+	resBody := make(chan io.Reader, 1)
+	connr, connw := io.Pipe() // connection pipe pair
+	lw := &logWritesConn{
+		rch: resBody,
+		w:   connw,
+	}
+	tr := &Transport{
+		Dial: func(network, addr string) (net.Conn, error) {
+			return lw, nil
+		},
+	}
+	bodyr, bodyw := io.Pipe() // body pipe pair
+	go func() {
+		defer bodyw.Close()
+		for i := 0; i < 3; i++ {
+			fmt.Fprintf(bodyw, "num%d\n", i)
+		}
+	}()
+	resc := make(chan *Response)
+	go func() {
+		req, _ := NewRequest("POST", "http://localhost:8080", bodyr)
+		req.Header.Set("User-Agent", "x") // known value for test
+		res, err := tr.RoundTrip(req)
+		if err != nil {
+			t.Error("RoundTrip: %v", err)
+			close(resc)
+			return
+		}
+		resc <- res
+
+	}()
+	// Fully consume the request before checking the Write log vs. want.
+	req, err := ReadRequest(bufio.NewReader(connr))
+	if err != nil {
+		t.Fatal(err)
+	}
+	io.Copy(ioutil.Discard, req.Body)
+
+	// Unblock the transport's roundTrip goroutine.
+	resBody <- strings.NewReader("HTTP/1.1 204 No Content\r\nConnection: close\r\n\r\n")
+	res, ok := <-resc
+	if !ok {
+		return
+	}
+	defer res.Body.Close()
+
+	want := []string{
+		// Because Request.ContentLength = 0, the body is sniffed for 1 byte to determine whether there's content.
+		// That explains the initial "num0" being split into "n" and "um0".
+		// The first byte is included with the request headers Write. Perhaps in the future
+		// we will want to flush the headers out early if the first byte of the request body is
+		// taking a long time to arrive. But not yet.
+		"POST / HTTP/1.1\r\nHost: localhost:8080\r\nUser-Agent: x\r\nTransfer-Encoding: chunked\r\nAccept-Encoding: gzip\r\n\r\n" +
+			"1\r\nn\r\n",
+		"4\r\num0\n\r\n",
+		"5\r\nnum1\n\r\n",
+		"5\r\nnum2\n\r\n",
+		"0\r\n\r\n",
+	}
+	if !reflect.DeepEqual(lw.writes, want) {
+		t.Errorf("Writes differed.\n Got: %q\nWant: %q\n", lw.writes, want)
+	}
+}
+
+// Issue 11745.
+func TestTransportPrefersResponseOverWriteError(t *testing.T) {
+	if testing.Short() {
+		t.Skip("skipping in short mode")
+	}
+	defer afterTest(t)
+	const contentLengthLimit = 1024 * 1024 // 1MB
+	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+		if r.ContentLength >= contentLengthLimit {
+			w.WriteHeader(StatusBadRequest)
+			r.Body.Close()
+			return
+		}
+		w.WriteHeader(StatusOK)
+	}))
+	defer ts.Close()
+
+	fail := 0
+	count := 100
+	bigBody := strings.Repeat("a", contentLengthLimit*2)
+	for i := 0; i < count; i++ {
+		req, err := NewRequest("PUT", ts.URL, strings.NewReader(bigBody))
+		if err != nil {
+			t.Fatal(err)
+		}
+		tr := new(Transport)
+		defer tr.CloseIdleConnections()
+		client := &Client{Transport: tr}
+		resp, err := client.Do(req)
+		if err != nil {
+			fail++
+			t.Logf("%d = %#v", i, err)
+			if ue, ok := err.(*url.Error); ok {
+				t.Logf("urlErr = %#v", ue.Err)
+				if ne, ok := ue.Err.(*net.OpError); ok {
+					t.Logf("netOpError = %#v", ne.Err)
+				}
+			}
+		} else {
+			resp.Body.Close()
+			if resp.StatusCode != 400 {
+				t.Errorf("Expected status code 400, got %v", resp.Status)
+			}
+		}
+	}
+	if fail > 0 {
+		t.Errorf("Failed %v out of %v\n", fail, count)
+	}
+}
+
+func wantBody(res *Response, err error, want string) error {
 	if err != nil {
 		return err
 	}
diff --git a/src/net/interface.go b/src/net/interface.go
index 2e9f1eb..9c7b5da 100644
--- a/src/net/interface.go
+++ b/src/net/interface.go
@@ -62,41 +62,61 @@ func (f Flags) String() string {
 // Addrs returns interface addresses for a specific interface.
 func (ifi *Interface) Addrs() ([]Addr, error) {
 	if ifi == nil {
-		return nil, errInvalidInterface
+		return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterface}
 	}
-	return interfaceAddrTable(ifi)
+	ifat, err := interfaceAddrTable(ifi)
+	if err != nil {
+		err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
+	}
+	return ifat, err
 }
 
 // MulticastAddrs returns multicast, joined group addresses for
 // a specific interface.
 func (ifi *Interface) MulticastAddrs() ([]Addr, error) {
 	if ifi == nil {
-		return nil, errInvalidInterface
+		return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterface}
+	}
+	ifat, err := interfaceMulticastAddrTable(ifi)
+	if err != nil {
+		err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
 	}
-	return interfaceMulticastAddrTable(ifi)
+	return ifat, err
 }
 
 // Interfaces returns a list of the system's network interfaces.
 func Interfaces() ([]Interface, error) {
-	return interfaceTable(0)
+	ift, err := interfaceTable(0)
+	if err != nil {
+		err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
+	}
+	return ift, err
 }
 
 // InterfaceAddrs returns a list of the system's network interface
 // addresses.
 func InterfaceAddrs() ([]Addr, error) {
-	return interfaceAddrTable(nil)
+	ifat, err := interfaceAddrTable(nil)
+	if err != nil {
+		err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
+	}
+	return ifat, err
 }
 
 // InterfaceByIndex returns the interface specified by index.
 func InterfaceByIndex(index int) (*Interface, error) {
 	if index <= 0 {
-		return nil, errInvalidInterfaceIndex
+		return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterfaceIndex}
 	}
 	ift, err := interfaceTable(index)
 	if err != nil {
-		return nil, err
+		return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
 	}
-	return interfaceByIndex(ift, index)
+	ifi, err := interfaceByIndex(ift, index)
+	if err != nil {
+		err = &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
+	}
+	return ifi, err
 }
 
 func interfaceByIndex(ift []Interface, index int) (*Interface, error) {
@@ -111,16 +131,16 @@ func interfaceByIndex(ift []Interface, index int) (*Interface, error) {
 // InterfaceByName returns the interface specified by name.
 func InterfaceByName(name string) (*Interface, error) {
 	if name == "" {
-		return nil, errInvalidInterfaceName
+		return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errInvalidInterfaceName}
 	}
 	ift, err := interfaceTable(0)
 	if err != nil {
-		return nil, err
+		return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: err}
 	}
 	for _, ifi := range ift {
 		if name == ifi.Name {
 			return &ifi, nil
 		}
 	}
-	return nil, errNoSuchInterface
+	return nil, &OpError{Op: "route", Net: "ip+net", Source: nil, Addr: nil, Err: errNoSuchInterface}
 }
diff --git a/src/net/interface_bsd.go b/src/net/interface_bsd.go
index 1677557..208f37f 100644
--- a/src/net/interface_bsd.go
+++ b/src/net/interface_bsd.go
@@ -18,11 +18,11 @@ import (
 func interfaceTable(ifindex int) ([]Interface, error) {
 	tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST, ifindex)
 	if err != nil {
-		return nil, os.NewSyscallError("route rib", err)
+		return nil, os.NewSyscallError("routerib", err)
 	}
 	msgs, err := syscall.ParseRoutingMessage(tab)
 	if err != nil {
-		return nil, os.NewSyscallError("route message", err)
+		return nil, os.NewSyscallError("parseroutingmessage", err)
 	}
 	return parseInterfaceTable(ifindex, msgs)
 }
@@ -51,27 +51,25 @@ loop:
 func newLink(m *syscall.InterfaceMessage) (*Interface, error) {
 	sas, err := syscall.ParseRoutingSockaddr(m)
 	if err != nil {
-		return nil, os.NewSyscallError("route sockaddr", err)
+		return nil, os.NewSyscallError("parseroutingsockaddr", err)
 	}
 	ifi := &Interface{Index: int(m.Header.Index), Flags: linkFlags(m.Header.Flags)}
-	for _, sa := range sas {
-		switch sa := sa.(type) {
-		case *syscall.SockaddrDatalink:
-			// NOTE: SockaddrDatalink.Data is minimum work area,
-			// can be larger.
-			m.Data = m.Data[unsafe.Offsetof(sa.Data):]
-			var name [syscall.IFNAMSIZ]byte
-			for i := 0; i < int(sa.Nlen); i++ {
-				name[i] = byte(m.Data[i])
-			}
-			ifi.Name = string(name[:sa.Nlen])
-			ifi.MTU = int(m.Header.Data.Mtu)
-			addr := make([]byte, sa.Alen)
-			for i := 0; i < int(sa.Alen); i++ {
-				addr[i] = byte(m.Data[int(sa.Nlen)+i])
-			}
-			ifi.HardwareAddr = addr[:sa.Alen]
+	sa, _ := sas[syscall.RTAX_IFP].(*syscall.SockaddrDatalink)
+	if sa != nil {
+		// NOTE: SockaddrDatalink.Data is minimum work area,
+		// can be larger.
+		m.Data = m.Data[unsafe.Offsetof(sa.Data):]
+		var name [syscall.IFNAMSIZ]byte
+		for i := 0; i < int(sa.Nlen); i++ {
+			name[i] = byte(m.Data[i])
 		}
+		ifi.Name = string(name[:sa.Nlen])
+		ifi.MTU = int(m.Header.Data.Mtu)
+		addr := make([]byte, sa.Alen)
+		for i := 0; i < int(sa.Alen); i++ {
+			addr[i] = byte(m.Data[int(sa.Nlen)+i])
+		}
+		ifi.HardwareAddr = addr[:sa.Alen]
 	}
 	return ifi, nil
 }
@@ -106,11 +104,11 @@ func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
 	}
 	tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST, index)
 	if err != nil {
-		return nil, os.NewSyscallError("route rib", err)
+		return nil, os.NewSyscallError("routerib", err)
 	}
 	msgs, err := syscall.ParseRoutingMessage(tab)
 	if err != nil {
-		return nil, os.NewSyscallError("route message", err)
+		return nil, os.NewSyscallError("parseroutingmessage", err)
 	}
 	var ift []Interface
 	if index == 0 {
@@ -144,39 +142,34 @@ func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
 	return ifat, nil
 }
 
-func newAddr(ifi *Interface, m *syscall.InterfaceAddrMessage) (Addr, error) {
+func newAddr(ifi *Interface, m *syscall.InterfaceAddrMessage) (*IPNet, error) {
 	sas, err := syscall.ParseRoutingSockaddr(m)
 	if err != nil {
-		return nil, os.NewSyscallError("route sockaddr", err)
+		return nil, os.NewSyscallError("parseroutingsockaddr", err)
 	}
 	ifa := &IPNet{}
-	for i, sa := range sas {
-		switch sa := sa.(type) {
-		case *syscall.SockaddrInet4:
-			switch i {
-			case 0:
-				ifa.Mask = IPv4Mask(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])
-			case 1:
-				ifa.IP = IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])
-			}
-		case *syscall.SockaddrInet6:
-			switch i {
-			case 0:
-				ifa.Mask = make(IPMask, IPv6len)
-				copy(ifa.Mask, sa.Addr[:])
-			case 1:
-				ifa.IP = make(IP, IPv6len)
-				copy(ifa.IP, sa.Addr[:])
-				// NOTE: KAME based IPv6 protcol stack usually embeds
-				// the interface index in the interface-local or link-
-				// local address as the kernel-internal form.
-				if ifa.IP.IsLinkLocalUnicast() {
-					ifa.IP[2], ifa.IP[3] = 0, 0
-				}
-			}
-		default: // Sockaddrs contain syscall.SockaddrDatalink on NetBSD
-			return nil, nil
+	switch sa := sas[syscall.RTAX_NETMASK].(type) {
+	case *syscall.SockaddrInet4:
+		ifa.Mask = IPv4Mask(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])
+	case *syscall.SockaddrInet6:
+		ifa.Mask = make(IPMask, IPv6len)
+		copy(ifa.Mask, sa.Addr[:])
+	}
+	switch sa := sas[syscall.RTAX_IFA].(type) {
+	case *syscall.SockaddrInet4:
+		ifa.IP = IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])
+	case *syscall.SockaddrInet6:
+		ifa.IP = make(IP, IPv6len)
+		copy(ifa.IP, sa.Addr[:])
+		// NOTE: KAME based IPv6 protcol stack usually embeds
+		// the interface index in the interface-local or
+		// link-local address as the kernel-internal form.
+		if ifa.IP.IsLinkLocalUnicast() {
+			ifa.IP[2], ifa.IP[3] = 0, 0
 		}
 	}
+	if ifa.IP == nil || ifa.Mask == nil {
+		return nil, nil // Sockaddrs contain syscall.SockaddrDatalink on NetBSD
+	}
 	return ifa, nil
 }
diff --git a/src/net/interface_bsd_test.go b/src/net/interface_bsd_test.go
index 88daf73..43ccc89 100644
--- a/src/net/interface_bsd_test.go
+++ b/src/net/interface_bsd_test.go
@@ -28,10 +28,8 @@ func (ti *testInterface) setBroadcast(suffix int) error {
 	return nil
 }
 
-func (ti *testInterface) setPointToPoint(suffix int, local, remote string) error {
+func (ti *testInterface) setPointToPoint(suffix int) error {
 	ti.name = fmt.Sprintf("gif%d", suffix)
-	ti.local = local
-	ti.remote = remote
 	xname, err := exec.LookPath("ifconfig")
 	if err != nil {
 		return err
diff --git a/src/net/interface_darwin.go b/src/net/interface_darwin.go
index ad0937d..b7a3338 100644
--- a/src/net/interface_darwin.go
+++ b/src/net/interface_darwin.go
@@ -14,11 +14,11 @@ import (
 func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
 	tab, err := syscall.RouteRIB(syscall.NET_RT_IFLIST2, ifi.Index)
 	if err != nil {
-		return nil, os.NewSyscallError("route rib", err)
+		return nil, os.NewSyscallError("routerib", err)
 	}
 	msgs, err := syscall.ParseRoutingMessage(tab)
 	if err != nil {
-		return nil, os.NewSyscallError("route message", err)
+		return nil, os.NewSyscallError("parseroutingmessage", err)
 	}
 	var ifmat []Addr
 	for _, m := range msgs {
@@ -29,35 +29,34 @@ func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
 				if err != nil {
 					return nil, err
 				}
-				ifmat = append(ifmat, ifma...)
+				if ifma != nil {
+					ifmat = append(ifmat, ifma)
+				}
 			}
 		}
 	}
 	return ifmat, nil
 }
 
-func newMulticastAddr(ifi *Interface, m *syscall.InterfaceMulticastAddrMessage) ([]Addr, error) {
+func newMulticastAddr(ifi *Interface, m *syscall.InterfaceMulticastAddrMessage) (*IPAddr, error) {
 	sas, err := syscall.ParseRoutingSockaddr(m)
 	if err != nil {
-		return nil, os.NewSyscallError("route sockaddr", err)
+		return nil, os.NewSyscallError("parseroutingsockaddr", err)
 	}
-	var ifmat []Addr
-	for _, sa := range sas {
-		switch sa := sa.(type) {
-		case *syscall.SockaddrInet4:
-			ifma := &IPAddr{IP: IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])}
-			ifmat = append(ifmat, ifma.toAddr())
-		case *syscall.SockaddrInet6:
-			ifma := &IPAddr{IP: make(IP, IPv6len)}
-			copy(ifma.IP, sa.Addr[:])
-			// NOTE: KAME based IPv6 protocol stack usually embeds
-			// the interface index in the interface-local or link-
-			// local address as the kernel-internal form.
-			if ifma.IP.IsInterfaceLocalMulticast() || ifma.IP.IsLinkLocalMulticast() {
-				ifma.IP[2], ifma.IP[3] = 0, 0
-			}
-			ifmat = append(ifmat, ifma.toAddr())
+	switch sa := sas[syscall.RTAX_IFA].(type) {
+	case *syscall.SockaddrInet4:
+		return &IPAddr{IP: IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])}, nil
+	case *syscall.SockaddrInet6:
+		ifma := IPAddr{IP: make(IP, IPv6len)}
+		copy(ifma.IP, sa.Addr[:])
+		// NOTE: KAME based IPv6 protcol stack usually embeds
+		// the interface index in the interface-local or
+		// link-local address as the kernel-internal form.
+		if ifma.IP.IsInterfaceLocalMulticast() || ifma.IP.IsLinkLocalMulticast() {
+			ifma.IP[2], ifma.IP[3] = 0, 0
 		}
+		return &ifma, nil
+	default:
+		return nil, nil
 	}
-	return ifmat, nil
 }
diff --git a/src/net/interface_freebsd.go b/src/net/interface_freebsd.go
index 5df7679..c42d90b 100644
--- a/src/net/interface_freebsd.go
+++ b/src/net/interface_freebsd.go
@@ -14,11 +14,11 @@ import (
 func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
 	tab, err := syscall.RouteRIB(syscall.NET_RT_IFMALIST, ifi.Index)
 	if err != nil {
-		return nil, os.NewSyscallError("route rib", err)
+		return nil, os.NewSyscallError("routerib", err)
 	}
 	msgs, err := syscall.ParseRoutingMessage(tab)
 	if err != nil {
-		return nil, os.NewSyscallError("route message", err)
+		return nil, os.NewSyscallError("parseroutingmessage", err)
 	}
 	var ifmat []Addr
 	for _, m := range msgs {
@@ -29,35 +29,34 @@ func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
 				if err != nil {
 					return nil, err
 				}
-				ifmat = append(ifmat, ifma...)
+				if ifma != nil {
+					ifmat = append(ifmat, ifma)
+				}
 			}
 		}
 	}
 	return ifmat, nil
 }
 
-func newMulticastAddr(ifi *Interface, m *syscall.InterfaceMulticastAddrMessage) ([]Addr, error) {
+func newMulticastAddr(ifi *Interface, m *syscall.InterfaceMulticastAddrMessage) (*IPAddr, error) {
 	sas, err := syscall.ParseRoutingSockaddr(m)
 	if err != nil {
-		return nil, os.NewSyscallError("route sockaddr", err)
+		return nil, os.NewSyscallError("parseroutingsockaddr", err)
 	}
-	var ifmat []Addr
-	for _, sa := range sas {
-		switch sa := sa.(type) {
-		case *syscall.SockaddrInet4:
-			ifma := &IPAddr{IP: IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])}
-			ifmat = append(ifmat, ifma.toAddr())
-		case *syscall.SockaddrInet6:
-			ifma := &IPAddr{IP: make(IP, IPv6len)}
-			copy(ifma.IP, sa.Addr[:])
-			// NOTE: KAME based IPv6 protocol stack usually embeds
-			// the interface index in the interface-local or link-
-			// local address as the kernel-internal form.
-			if ifma.IP.IsInterfaceLocalMulticast() || ifma.IP.IsLinkLocalMulticast() {
-				ifma.IP[2], ifma.IP[3] = 0, 0
-			}
-			ifmat = append(ifmat, ifma.toAddr())
+	switch sa := sas[syscall.RTAX_IFA].(type) {
+	case *syscall.SockaddrInet4:
+		return &IPAddr{IP: IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3])}, nil
+	case *syscall.SockaddrInet6:
+		ifma := IPAddr{IP: make(IP, IPv6len)}
+		copy(ifma.IP, sa.Addr[:])
+		// NOTE: KAME based IPv6 protcol stack usually embeds
+		// the interface index in the interface-local or
+		// link-local address as the kernel-internal form.
+		if ifma.IP.IsInterfaceLocalMulticast() || ifma.IP.IsLinkLocalMulticast() {
+			ifma.IP[2], ifma.IP[3] = 0, 0
 		}
+		return &ifma, nil
+	default:
+		return nil, nil
 	}
-	return ifmat, nil
 }
diff --git a/src/net/interface_linux.go b/src/net/interface_linux.go
index 1115d0f..ef20429 100644
--- a/src/net/interface_linux.go
+++ b/src/net/interface_linux.go
@@ -16,11 +16,11 @@ import (
 func interfaceTable(ifindex int) ([]Interface, error) {
 	tab, err := syscall.NetlinkRIB(syscall.RTM_GETLINK, syscall.AF_UNSPEC)
 	if err != nil {
-		return nil, os.NewSyscallError("netlink rib", err)
+		return nil, os.NewSyscallError("netlinkrib", err)
 	}
 	msgs, err := syscall.ParseNetlinkMessage(tab)
 	if err != nil {
-		return nil, os.NewSyscallError("netlink message", err)
+		return nil, os.NewSyscallError("parsenetlinkmessage", err)
 	}
 	var ift []Interface
 loop:
@@ -33,7 +33,7 @@ loop:
 			if ifindex == 0 || ifindex == int(ifim.Index) {
 				attrs, err := syscall.ParseNetlinkRouteAttr(&m)
 				if err != nil {
-					return nil, os.NewSyscallError("netlink routeattr", err)
+					return nil, os.NewSyscallError("parsenetlinkrouteattr", err)
 				}
 				ift = append(ift, *newLink(ifim, attrs))
 				if ifindex == int(ifim.Index) {
@@ -120,11 +120,11 @@ func linkFlags(rawFlags uint32) Flags {
 func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
 	tab, err := syscall.NetlinkRIB(syscall.RTM_GETADDR, syscall.AF_UNSPEC)
 	if err != nil {
-		return nil, os.NewSyscallError("netlink rib", err)
+		return nil, os.NewSyscallError("netlinkrib", err)
 	}
 	msgs, err := syscall.ParseNetlinkMessage(tab)
 	if err != nil {
-		return nil, os.NewSyscallError("netlink message", err)
+		return nil, os.NewSyscallError("parsenetlinkmessage", err)
 	}
 	var ift []Interface
 	if ifi == nil {
@@ -160,7 +160,7 @@ loop:
 				}
 				attrs, err := syscall.ParseNetlinkRouteAttr(&m)
 				if err != nil {
-					return nil, os.NewSyscallError("netlink routeattr", err)
+					return nil, os.NewSyscallError("parsenetlinkrouteattr", err)
 				}
 				ifa := newAddr(ifi, ifam, attrs)
 				if ifa != nil {
@@ -176,17 +176,15 @@ func newAddr(ifi *Interface, ifam *syscall.IfAddrmsg, attrs []syscall.NetlinkRou
 	var ipPointToPoint bool
 	// Seems like we need to make sure whether the IP interface
 	// stack consists of IP point-to-point numbered or unnumbered
-	// addressing over point-to-point link encapsulation.
-	if ifi.Flags&FlagPointToPoint != 0 {
-		for _, a := range attrs {
-			if a.Attr.Type == syscall.IFA_LOCAL {
-				ipPointToPoint = true
-				break
-			}
+	// addressing.
+	for _, a := range attrs {
+		if a.Attr.Type == syscall.IFA_LOCAL {
+			ipPointToPoint = true
+			break
 		}
 	}
 	for _, a := range attrs {
-		if ipPointToPoint && a.Attr.Type == syscall.IFA_ADDRESS || !ipPointToPoint && a.Attr.Type == syscall.IFA_LOCAL {
+		if ipPointToPoint && a.Attr.Type == syscall.IFA_ADDRESS {
 			continue
 		}
 		switch ifam.Family {
@@ -238,8 +236,8 @@ func parseProcNetIGMP(path string, ifi *Interface) []Addr {
 					b[i/2], _ = xtoi2(f[0][i:i+2], 0)
 				}
 				i := *(*uint32)(unsafe.Pointer(&b[:4][0]))
-				ifma := IPAddr{IP: IPv4(byte(i>>24), byte(i>>16), byte(i>>8), byte(i))}
-				ifmat = append(ifmat, ifma.toAddr())
+				ifma := &IPAddr{IP: IPv4(byte(i>>24), byte(i>>16), byte(i>>8), byte(i))}
+				ifmat = append(ifmat, ifma)
 			}
 		}
 	}
@@ -263,8 +261,8 @@ func parseProcNetIGMP6(path string, ifi *Interface) []Addr {
 			for i := 0; i+1 < len(f[2]); i += 2 {
 				b[i/2], _ = xtoi2(f[2][i:i+2], 0)
 			}
-			ifma := IPAddr{IP: IP{b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15]}}
-			ifmat = append(ifmat, ifma.toAddr())
+			ifma := &IPAddr{IP: IP{b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15]}}
+			ifmat = append(ifmat, ifma)
 		}
 	}
 	return ifmat
diff --git a/src/net/interface_linux_test.go b/src/net/interface_linux_test.go
index d8800bd..6251b26 100644
--- a/src/net/interface_linux_test.go
+++ b/src/net/interface_linux_test.go
@@ -20,6 +20,14 @@ func (ti *testInterface) setBroadcast(suffix int) error {
 		Path: xname,
 		Args: []string{"ip", "link", "add", ti.name, "type", "dummy"},
 	})
+	ti.setupCmds = append(ti.setupCmds, &exec.Cmd{
+		Path: xname,
+		Args: []string{"ip", "address", "add", ti.local, "peer", ti.remote, "dev", ti.name},
+	})
+	ti.teardownCmds = append(ti.teardownCmds, &exec.Cmd{
+		Path: xname,
+		Args: []string{"ip", "address", "del", ti.local, "peer", ti.remote, "dev", ti.name},
+	})
 	ti.teardownCmds = append(ti.teardownCmds, &exec.Cmd{
 		Path: xname,
 		Args: []string{"ip", "link", "delete", ti.name, "type", "dummy"},
@@ -27,29 +35,27 @@ func (ti *testInterface) setBroadcast(suffix int) error {
 	return nil
 }
 
-func (ti *testInterface) setPointToPoint(suffix int, local, remote string) error {
+func (ti *testInterface) setPointToPoint(suffix int) error {
 	ti.name = fmt.Sprintf("gotest%d", suffix)
-	ti.local = local
-	ti.remote = remote
 	xname, err := exec.LookPath("ip")
 	if err != nil {
 		return err
 	}
 	ti.setupCmds = append(ti.setupCmds, &exec.Cmd{
 		Path: xname,
-		Args: []string{"ip", "tunnel", "add", ti.name, "mode", "gre", "local", local, "remote", remote},
+		Args: []string{"ip", "tunnel", "add", ti.name, "mode", "gre", "local", ti.local, "remote", ti.remote},
+	})
+	ti.setupCmds = append(ti.setupCmds, &exec.Cmd{
+		Path: xname,
+		Args: []string{"ip", "address", "add", ti.local, "peer", ti.remote, "dev", ti.name},
 	})
 	ti.teardownCmds = append(ti.teardownCmds, &exec.Cmd{
 		Path: xname,
-		Args: []string{"ip", "tunnel", "del", ti.name, "mode", "gre", "local", local, "remote", remote},
+		Args: []string{"ip", "address", "del", ti.local, "peer", ti.remote, "dev", ti.name},
 	})
-	xname, err = exec.LookPath("ifconfig")
-	if err != nil {
-		return err
-	}
-	ti.setupCmds = append(ti.setupCmds, &exec.Cmd{
+	ti.teardownCmds = append(ti.teardownCmds, &exec.Cmd{
 		Path: xname,
-		Args: []string{"ifconfig", ti.name, "inet", local, "dstaddr", remote},
+		Args: []string{"ip", "tunnel", "del", ti.name, "mode", "gre", "local", ti.local, "remote", ti.remote},
 	})
 	return nil
 }
@@ -78,7 +84,7 @@ var (
 func TestParseProcNet(t *testing.T) {
 	defer func() {
 		if p := recover(); p != nil {
-			t.Fatalf("parseProcNetIGMP or parseProtNetIGMP6 panicked: %v", p)
+			t.Fatalf("panicked: %v", p)
 		}
 	}()
 
@@ -88,7 +94,7 @@ func TestParseProcNet(t *testing.T) {
 		ifmat4 = append(ifmat4, ifmat...)
 	}
 	if len(ifmat4) != numOfTestIPv4MCAddrs {
-		t.Fatalf("parseProcNetIGMP returns %v addresses, expected %v", len(ifmat4), numOfTestIPv4MCAddrs)
+		t.Fatalf("got %d; want %d", len(ifmat4), numOfTestIPv4MCAddrs)
 	}
 
 	var ifmat6 []Addr
@@ -97,6 +103,6 @@ func TestParseProcNet(t *testing.T) {
 		ifmat6 = append(ifmat6, ifmat...)
 	}
 	if len(ifmat6) != numOfTestIPv6MCAddrs {
-		t.Fatalf("parseProcNetIGMP6 returns %v addresses, expected %v", len(ifmat6), numOfTestIPv6MCAddrs)
+		t.Fatalf("got %d; want %d", len(ifmat6), numOfTestIPv6MCAddrs)
 	}
 }
diff --git a/src/net/interface_test.go b/src/net/interface_test.go
index efabb5f..567d18d 100644
--- a/src/net/interface_test.go
+++ b/src/net/interface_test.go
@@ -6,6 +6,7 @@ package net
 
 import (
 	"reflect"
+	"runtime"
 	"testing"
 )
 
@@ -37,12 +38,7 @@ func ipv6LinkLocalUnicastAddr(ifi *Interface) string {
 		return ""
 	}
 	for _, ifa := range ifat {
-		switch ifa := ifa.(type) {
-		case *IPAddr:
-			if ifa.IP.To4() == nil && ifa.IP.IsLinkLocalUnicast() {
-				return ifa.IP.String()
-			}
-		case *IPNet:
+		if ifa, ok := ifa.(*IPNet); ok {
 			if ifa.IP.To4() == nil && ifa.IP.IsLinkLocalUnicast() {
 				return ifa.IP.String()
 			}
@@ -51,161 +47,259 @@ func ipv6LinkLocalUnicastAddr(ifi *Interface) string {
 	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) {
 	ift, err := Interfaces()
 	if err != nil {
-		t.Fatalf("Interfaces failed: %v", err)
+		t.Fatal(err)
 	}
-	t.Logf("table: len/cap = %v/%v", len(ift), cap(ift))
-
+	var stats routeStats
 	for _, ifi := range ift {
 		ifxi, err := InterfaceByIndex(ifi.Index)
 		if err != nil {
-			t.Fatalf("InterfaceByIndex(%v) failed: %v", ifi.Index, err)
+			t.Fatal(err)
 		}
 		if !reflect.DeepEqual(ifxi, &ifi) {
-			t.Fatalf("InterfaceByIndex(%v) = %v, want %v", ifi.Index, ifxi, ifi)
+			t.Errorf("got %v; want %v", ifxi, ifi)
 		}
 		ifxn, err := InterfaceByName(ifi.Name)
 		if err != nil {
-			t.Fatalf("InterfaceByName(%q) failed: %v", ifi.Name, err)
+			t.Fatal(err)
 		}
 		if !reflect.DeepEqual(ifxn, &ifi) {
-			t.Fatalf("InterfaceByName(%q) = %v, want %v", ifi.Name, ifxn, ifi)
+			t.Errorf("got %v; want %v", ifxn, ifi)
 		}
 		t.Logf("%q: flags %q, ifindex %v, mtu %v", ifi.Name, ifi.Flags.String(), ifi.Index, ifi.MTU)
-		t.Logf("\thardware address %q", ifi.HardwareAddr.String())
-		testInterfaceAddrs(t, &ifi)
-		testInterfaceMulticastAddrs(t, &ifi)
+		t.Logf("hardware address %q", ifi.HardwareAddr.String())
+		if ifi.Flags&FlagUp != 0 {
+			if ifi.Flags&FlagLoopback != 0 {
+				stats.loop++
+			} else {
+				stats.other++
+			}
+		}
+		n4, n6 := testInterfaceAddrs(t, &ifi)
+		stats.uni4 += n4
+		stats.uni6 += n6
+		n4, n6 = testInterfaceMulticastAddrs(t, &ifi)
+		stats.multi4 += n4
+		stats.multi6 += n6
+	}
+	switch runtime.GOOS {
+	case "nacl", "plan9", "solaris":
+	default:
+		// 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)
+		}
+		// 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:
+		// 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)
+		//}
+		// 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) {
+	ift, err := Interfaces()
+	if err != nil {
+		t.Fatal(err)
+	}
+	var stats routeStats
+	for _, ifi := range ift {
+		if ifi.Flags&FlagUp != 0 {
+			if ifi.Flags&FlagLoopback != 0 {
+				stats.loop++
+			} else {
+				stats.other++
+			}
+		}
+	}
 	ifat, err := InterfaceAddrs()
 	if err != nil {
-		t.Fatalf("InterfaceAddrs failed: %v", err)
+		t.Fatal(err)
+	}
+	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)
+	}
+	// 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)
 	}
-	t.Logf("table: len/cap = %v/%v", len(ifat), cap(ifat))
-	testAddrs(t, ifat)
 }
 
-func testInterfaceAddrs(t *testing.T, ifi *Interface) {
+func testInterfaceAddrs(t *testing.T, ifi *Interface) (naf4, naf6 int) {
 	ifat, err := ifi.Addrs()
 	if err != nil {
-		t.Fatalf("Interface.Addrs failed: %v", err)
+		t.Fatal(err)
 	}
-	testAddrs(t, ifat)
+	return testAddrs(t, ifat)
 }
 
-func testInterfaceMulticastAddrs(t *testing.T, ifi *Interface) {
+func testInterfaceMulticastAddrs(t *testing.T, ifi *Interface) (nmaf4, nmaf6 int) {
 	ifmat, err := ifi.MulticastAddrs()
 	if err != nil {
-		t.Fatalf("Interface.MulticastAddrs failed: %v", err)
+		t.Fatal(err)
 	}
-	testMulticastAddrs(t, ifmat)
+	return testMulticastAddrs(t, ifmat)
 }
 
-func testAddrs(t *testing.T, ifat []Addr) {
+func testAddrs(t *testing.T, ifat []Addr) (naf4, naf6 int) {
 	for _, ifa := range ifat {
 		switch ifa := ifa.(type) {
-		case *IPAddr:
-			if ifa == nil || ifa.IP == nil {
-				t.Errorf("\tunexpected value: %v, %v", ifa, ifa.IP)
-			} else {
-				t.Logf("\tinterface address %q", ifa.String())
-			}
 		case *IPNet:
-			if ifa == nil || ifa.IP == nil || ifa.Mask == nil {
-				t.Errorf("\tunexpected value: %v, %v, %v", ifa, ifa.IP, ifa.Mask)
-			} else {
-				_, prefixLen := ifa.Mask.Size()
-				if ifa.IP.To4() != nil && prefixLen != 8*IPv4len || ifa.IP.To16() != nil && ifa.IP.To4() == nil && prefixLen != 8*IPv6len {
-					t.Errorf("\tunexpected value: %v, %v, %v, %v", ifa, ifa.IP, ifa.Mask, prefixLen)
-				} else {
-					t.Logf("\tinterface address %q", ifa.String())
+			if ifa == nil || ifa.IP == nil || ifa.IP.IsUnspecified() || ifa.IP.IsMulticast() || ifa.Mask == nil {
+				t.Errorf("unexpected value: %#v", ifa)
+				continue
+			}
+			prefixLen, maxPrefixLen := ifa.Mask.Size()
+			if ifa.IP.To4() != nil {
+				if 0 >= prefixLen || prefixLen > 8*IPv4len || maxPrefixLen != 8*IPv4len {
+					t.Errorf("unexpected prefix length: %v/%v", prefixLen, maxPrefixLen)
+					continue
+				}
+				naf4++
+			} else if ifa.IP.To16() != nil {
+				if 0 >= prefixLen || prefixLen > 8*IPv6len || maxPrefixLen != 8*IPv6len {
+					t.Errorf("unexpected prefix length: %v/%v", prefixLen, maxPrefixLen)
+					continue
 				}
+				naf6++
 			}
+			t.Logf("interface address %q", ifa.String())
 		default:
-			t.Errorf("\tunexpected type: %T", ifa)
+			t.Errorf("unexpected type: %T", ifa)
 		}
 	}
+	return
 }
 
-func testMulticastAddrs(t *testing.T, ifmat []Addr) {
+func testMulticastAddrs(t *testing.T, ifmat []Addr) (nmaf4, nmaf6 int) {
 	for _, ifma := range ifmat {
 		switch ifma := ifma.(type) {
 		case *IPAddr:
-			if ifma == nil {
-				t.Errorf("\tunexpected value: %v", ifma)
-			} else {
-				t.Logf("\tjoined group address %q", ifma.String())
+			if ifma == nil || ifma.IP == nil || ifma.IP.IsUnspecified() || !ifma.IP.IsMulticast() {
+				t.Errorf("unexpected value: %#v", ifma)
+				continue
 			}
+			if ifma.IP.To4() != nil {
+				nmaf4++
+			} else if ifma.IP.To16() != nil {
+				nmaf6++
+			}
+			t.Logf("joined group address %q", ifma.String())
 		default:
-			t.Errorf("\tunexpected type: %T", ifma)
+			t.Errorf("unexpected type: %T", ifma)
 		}
 	}
+	return
 }
 
 func BenchmarkInterfaces(b *testing.B) {
+	testHookUninstaller.Do(uninstallTestHooks)
+
 	for i := 0; i < b.N; i++ {
 		if _, err := Interfaces(); err != nil {
-			b.Fatalf("Interfaces failed: %v", err)
+			b.Fatal(err)
 		}
 	}
 }
 
 func BenchmarkInterfaceByIndex(b *testing.B) {
+	testHookUninstaller.Do(uninstallTestHooks)
+
 	ifi := loopbackInterface()
 	if ifi == nil {
 		b.Skip("loopback interface not found")
 	}
 	for i := 0; i < b.N; i++ {
 		if _, err := InterfaceByIndex(ifi.Index); err != nil {
-			b.Fatalf("InterfaceByIndex failed: %v", err)
+			b.Fatal(err)
 		}
 	}
 }
 
 func BenchmarkInterfaceByName(b *testing.B) {
+	testHookUninstaller.Do(uninstallTestHooks)
+
 	ifi := loopbackInterface()
 	if ifi == nil {
 		b.Skip("loopback interface not found")
 	}
 	for i := 0; i < b.N; i++ {
 		if _, err := InterfaceByName(ifi.Name); err != nil {
-			b.Fatalf("InterfaceByName failed: %v", err)
+			b.Fatal(err)
 		}
 	}
 }
 
 func BenchmarkInterfaceAddrs(b *testing.B) {
+	testHookUninstaller.Do(uninstallTestHooks)
+
 	for i := 0; i < b.N; i++ {
 		if _, err := InterfaceAddrs(); err != nil {
-			b.Fatalf("InterfaceAddrs failed: %v", err)
+			b.Fatal(err)
 		}
 	}
 }
 
 func BenchmarkInterfacesAndAddrs(b *testing.B) {
+	testHookUninstaller.Do(uninstallTestHooks)
+
 	ifi := loopbackInterface()
 	if ifi == nil {
 		b.Skip("loopback interface not found")
 	}
 	for i := 0; i < b.N; i++ {
 		if _, err := ifi.Addrs(); err != nil {
-			b.Fatalf("Interface.Addrs failed: %v", err)
+			b.Fatal(err)
 		}
 	}
 }
 
 func BenchmarkInterfacesAndMulticastAddrs(b *testing.B) {
+	testHookUninstaller.Do(uninstallTestHooks)
+
 	ifi := loopbackInterface()
 	if ifi == nil {
 		b.Skip("loopback interface not found")
 	}
 	for i := 0; i < b.N; i++ {
 		if _, err := ifi.MulticastAddrs(); err != nil {
-			b.Fatalf("Interface.MulticastAddrs failed: %v", err)
+			b.Fatal(err)
 		}
 	}
 }
diff --git a/src/net/interface_unix_test.go b/src/net/interface_unix_test.go
index 01f609f..93b3b79 100644
--- a/src/net/interface_unix_test.go
+++ b/src/net/interface_unix_test.go
@@ -42,50 +42,50 @@ func (ti *testInterface) teardown() error {
 
 func TestPointToPointInterface(t *testing.T) {
 	if testing.Short() {
-		t.Skip("skipping test in short mode")
+		t.Skip("avoid external network")
 	}
-	switch {
-	case runtime.GOOS == "darwin":
-		t.Skipf("skipping read test on %q", runtime.GOOS)
+	if runtime.GOOS == "darwin" {
+		t.Skipf("not supported on %s", runtime.GOOS)
 	}
 	if os.Getuid() != 0 {
-		t.Skip("skipping test; must be root")
+		t.Skip("must be root")
 	}
 
 	local, remote := "169.254.0.1", "169.254.0.254"
 	ip := ParseIP(remote)
 	for i := 0; i < 3; i++ {
-		ti := &testInterface{}
-		if err := ti.setPointToPoint(5963+i, local, remote); err != nil {
+		ti := &testInterface{local: local, remote: remote}
+		if err := ti.setPointToPoint(5963 + i); err != nil {
 			t.Skipf("test requries external command: %v", err)
 		}
 		if err := ti.setup(); err != nil {
-			t.Fatalf("testInterface.setup failed: %v", err)
+			t.Fatal(err)
 		} else {
 			time.Sleep(3 * time.Millisecond)
 		}
 		ift, err := Interfaces()
 		if err != nil {
 			ti.teardown()
-			t.Fatalf("Interfaces failed: %v", err)
+			t.Fatal(err)
 		}
 		for _, ifi := range ift {
-			if ti.name == ifi.Name {
-				ifat, err := ifi.Addrs()
-				if err != nil {
+			if ti.name != ifi.Name {
+				continue
+			}
+			ifat, err := ifi.Addrs()
+			if err != nil {
+				ti.teardown()
+				t.Fatal(err)
+			}
+			for _, ifa := range ifat {
+				if ip.Equal(ifa.(*IPNet).IP) {
 					ti.teardown()
-					t.Fatalf("Interface.Addrs failed: %v", err)
-				}
-				for _, ifa := range ifat {
-					if ip.Equal(ifa.(*IPNet).IP) {
-						ti.teardown()
-						t.Fatalf("got %v; want %v", ip, local)
-					}
+					t.Fatalf("got %v", ifa)
 				}
 			}
 		}
 		if err := ti.teardown(); err != nil {
-			t.Fatalf("testInterface.teardown failed: %v", err)
+			t.Fatal(err)
 		} else {
 			time.Sleep(3 * time.Millisecond)
 		}
@@ -94,30 +94,32 @@ func TestPointToPointInterface(t *testing.T) {
 
 func TestInterfaceArrivalAndDeparture(t *testing.T) {
 	if testing.Short() {
-		t.Skip("skipping test in short mode")
+		t.Skip("avoid external network")
 	}
 	if os.Getuid() != 0 {
-		t.Skip("skipping test; must be root")
+		t.Skip("must be root")
 	}
 
+	local, remote := "169.254.0.1", "169.254.0.254"
+	ip := ParseIP(remote)
 	for i := 0; i < 3; i++ {
 		ift1, err := Interfaces()
 		if err != nil {
-			t.Fatalf("Interfaces failed: %v", err)
+			t.Fatal(err)
 		}
-		ti := &testInterface{}
+		ti := &testInterface{local: local, remote: remote}
 		if err := ti.setBroadcast(5682 + i); err != nil {
 			t.Skipf("test requires external command: %v", err)
 		}
 		if err := ti.setup(); err != nil {
-			t.Fatalf("testInterface.setup failed: %v", err)
+			t.Fatal(err)
 		} else {
 			time.Sleep(3 * time.Millisecond)
 		}
 		ift2, err := Interfaces()
 		if err != nil {
 			ti.teardown()
-			t.Fatalf("Interfaces failed: %v", err)
+			t.Fatal(err)
 		}
 		if len(ift2) <= len(ift1) {
 			for _, ifi := range ift1 {
@@ -129,14 +131,30 @@ func TestInterfaceArrivalAndDeparture(t *testing.T) {
 			ti.teardown()
 			t.Fatalf("got %v; want gt %v", len(ift2), len(ift1))
 		}
+		for _, ifi := range ift2 {
+			if ti.name != ifi.Name {
+				continue
+			}
+			ifat, err := ifi.Addrs()
+			if err != nil {
+				ti.teardown()
+				t.Fatal(err)
+			}
+			for _, ifa := range ifat {
+				if ip.Equal(ifa.(*IPNet).IP) {
+					ti.teardown()
+					t.Fatalf("got %v", ifa)
+				}
+			}
+		}
 		if err := ti.teardown(); err != nil {
-			t.Fatalf("testInterface.teardown failed: %v", err)
+			t.Fatal(err)
 		} else {
 			time.Sleep(3 * time.Millisecond)
 		}
 		ift3, err := Interfaces()
 		if err != nil {
-			t.Fatalf("Interfaces failed: %v", err)
+			t.Fatal(err)
 		}
 		if len(ift3) >= len(ift2) {
 			for _, ifi := range ift2 {
diff --git a/src/net/interface_windows.go b/src/net/interface_windows.go
index 0759dc2..e25c1ed 100644
--- a/src/net/interface_windows.go
+++ b/src/net/interface_windows.go
@@ -5,123 +5,139 @@
 package net
 
 import (
+	"internal/syscall/windows"
 	"os"
 	"syscall"
 	"unsafe"
 )
 
-func bytePtrToString(p *uint8) string {
-	a := (*[10000]uint8)(unsafe.Pointer(p))
-	i := 0
-	for a[i] != 0 {
-		i++
-	}
-	return string(a[:i])
-}
+func getAdapters() (*windows.IpAdapterAddresses, error) {
+	block := uint32(unsafe.Sizeof(windows.IpAdapterAddresses{}))
 
-func getAdapterList() (*syscall.IpAdapterInfo, error) {
-	b := make([]byte, 1000)
-	l := uint32(len(b))
-	a := (*syscall.IpAdapterInfo)(unsafe.Pointer(&b[0]))
-	// TODO(mikio): GetAdaptersInfo returns IP_ADAPTER_INFO that
-	// contains IPv4 address list only. We should use another API
-	// for fetching IPv6 stuff from the kernel.
-	err := syscall.GetAdaptersInfo(a, &l)
-	if err == syscall.ERROR_BUFFER_OVERFLOW {
-		b = make([]byte, l)
-		a = (*syscall.IpAdapterInfo)(unsafe.Pointer(&b[0]))
-		err = syscall.GetAdaptersInfo(a, &l)
-	}
-	if err != nil {
-		return nil, os.NewSyscallError("GetAdaptersInfo", err)
+	// pre-allocate a 15KB working buffer pointed to by the AdapterAddresses
+	// parameter.
+	// https://msdn.microsoft.com/en-us/library/windows/desktop/aa365915(v=vs.85).aspx
+	size := uint32(15000)
+
+	var addrs []windows.IpAdapterAddresses
+	for {
+		addrs = make([]windows.IpAdapterAddresses, size/block+1)
+		err := windows.GetAdaptersAddresses(syscall.AF_UNSPEC, windows.GAA_FLAG_INCLUDE_PREFIX, 0, &addrs[0], &size)
+		if err == nil {
+			break
+		}
+		if err.(syscall.Errno) != syscall.ERROR_BUFFER_OVERFLOW {
+			return nil, os.NewSyscallError("getadaptersaddresses", err)
+		}
 	}
-	return a, nil
+	return &addrs[0], nil
 }
 
-func getInterfaceList() ([]syscall.InterfaceInfo, error) {
+func getInterfaceInfos() ([]syscall.InterfaceInfo, error) {
 	s, err := sysSocket(syscall.AF_INET, syscall.SOCK_DGRAM, syscall.IPPROTO_UDP)
 	if err != nil {
-		return nil, os.NewSyscallError("Socket", err)
+		return nil, err
 	}
-	defer syscall.Closesocket(s)
+	defer closeFunc(s)
 
-	ii := [20]syscall.InterfaceInfo{}
+	iia := [20]syscall.InterfaceInfo{}
 	ret := uint32(0)
-	size := uint32(unsafe.Sizeof(ii))
-	err = syscall.WSAIoctl(s, syscall.SIO_GET_INTERFACE_LIST, nil, 0, (*byte)(unsafe.Pointer(&ii[0])), size, &ret, nil, 0)
+	size := uint32(unsafe.Sizeof(iia))
+	err = syscall.WSAIoctl(s, syscall.SIO_GET_INTERFACE_LIST, nil, 0, (*byte)(unsafe.Pointer(&iia[0])), size, &ret, nil, 0)
 	if err != nil {
-		return nil, os.NewSyscallError("WSAIoctl", err)
+		return nil, os.NewSyscallError("wsaioctl", err)
 	}
-	c := ret / uint32(unsafe.Sizeof(ii[0]))
-	return ii[:c-1], nil
+	iilen := ret / uint32(unsafe.Sizeof(iia[0]))
+	return iia[:iilen-1], nil
+}
+
+func bytesEqualIP(a []byte, b []int8) bool {
+	for i := 0; i < len(a); i++ {
+		if a[i] != byte(b[i]) {
+			return false
+		}
+	}
+	return true
+}
+
+func findInterfaceInfo(iis []syscall.InterfaceInfo, paddr *windows.IpAdapterAddresses) *syscall.InterfaceInfo {
+	for _, ii := range iis {
+		iaddr := (*syscall.RawSockaddr)(unsafe.Pointer(&ii.Address))
+		puni := paddr.FirstUnicastAddress
+		for ; puni != nil; puni = puni.Next {
+			if iaddr.Family == puni.Address.Sockaddr.Addr.Family {
+				switch iaddr.Family {
+				case syscall.AF_INET:
+					a := (*syscall.RawSockaddrInet4)(unsafe.Pointer(&ii.Address)).Addr
+					if bytesEqualIP(a[:], puni.Address.Sockaddr.Addr.Data[2:]) {
+						return &ii
+					}
+				case syscall.AF_INET6:
+					a := (*syscall.RawSockaddrInet6)(unsafe.Pointer(&ii.Address)).Addr
+					if bytesEqualIP(a[:], puni.Address.Sockaddr.Addr.Data[2:]) {
+						return &ii
+					}
+				default:
+					continue
+				}
+			}
+		}
+	}
+	return nil
 }
 
 // If the ifindex is zero, interfaceTable returns mappings of all
 // network interfaces.  Otherwise it returns a mapping of a specific
 // interface.
 func interfaceTable(ifindex int) ([]Interface, error) {
-	ai, err := getAdapterList()
+	paddr, err := getAdapters()
 	if err != nil {
 		return nil, err
 	}
 
-	ii, err := getInterfaceList()
+	iis, err := getInterfaceInfos()
 	if err != nil {
 		return nil, err
 	}
 
 	var ift []Interface
-	for ; ai != nil; ai = ai.Next {
-		index := ai.Index
+	for ; paddr != nil; paddr = paddr.Next {
+		index := paddr.IfIndex
+		if paddr.Ipv6IfIndex != 0 {
+			index = paddr.Ipv6IfIndex
+		}
 		if ifindex == 0 || ifindex == int(index) {
+			ii := findInterfaceInfo(iis, paddr)
+			if ii == nil {
+				continue
+			}
 			var flags Flags
-
-			row := syscall.MibIfRow{Index: index}
-			e := syscall.GetIfEntry(&row)
-			if e != nil {
-				return nil, os.NewSyscallError("GetIfEntry", e)
+			if paddr.Flags&windows.IfOperStatusUp != 0 {
+				flags |= FlagUp
 			}
-
-			for _, ii := range ii {
-				ip := (*syscall.RawSockaddrInet4)(unsafe.Pointer(&ii.Address)).Addr
-				ipv4 := IPv4(ip[0], ip[1], ip[2], ip[3])
-				ipl := &ai.IpAddressList
-				for ipl != nil {
-					ips := bytePtrToString(&ipl.IpAddress.String[0])
-					if ipv4.Equal(parseIPv4(ips)) {
-						break
-					}
-					ipl = ipl.Next
-				}
-				if ipl == nil {
-					continue
-				}
-				if ii.Flags&syscall.IFF_UP != 0 {
-					flags |= FlagUp
-				}
-				if ii.Flags&syscall.IFF_LOOPBACK != 0 {
-					flags |= FlagLoopback
-				}
-				if ii.Flags&syscall.IFF_BROADCAST != 0 {
-					flags |= FlagBroadcast
-				}
-				if ii.Flags&syscall.IFF_POINTTOPOINT != 0 {
-					flags |= FlagPointToPoint
-				}
-				if ii.Flags&syscall.IFF_MULTICAST != 0 {
-					flags |= FlagMulticast
-				}
+			if paddr.IfType&windows.IF_TYPE_SOFTWARE_LOOPBACK != 0 {
+				flags |= FlagLoopback
+			}
+			if ii.Flags&syscall.IFF_BROADCAST != 0 {
+				flags |= FlagBroadcast
+			}
+			if ii.Flags&syscall.IFF_POINTTOPOINT != 0 {
+				flags |= FlagPointToPoint
+			}
+			if ii.Flags&syscall.IFF_MULTICAST != 0 {
+				flags |= FlagMulticast
 			}
-
-			name := bytePtrToString(&ai.AdapterName[0])
-
 			ifi := Interface{
 				Index:        int(index),
-				MTU:          int(row.Mtu),
-				Name:         name,
-				HardwareAddr: HardwareAddr(row.PhysAddr[:row.PhysAddrLen]),
-				Flags:        flags}
+				MTU:          int(paddr.Mtu),
+				Name:         syscall.UTF16ToString((*(*[10000]uint16)(unsafe.Pointer(paddr.FriendlyName)))[:]),
+				HardwareAddr: HardwareAddr(paddr.PhysicalAddress[:]),
+				Flags:        flags,
+			}
 			ift = append(ift, ifi)
+			if ifindex == int(ifi.Index) {
+				break
+			}
 		}
 	}
 	return ift, nil
@@ -131,28 +147,86 @@ func interfaceTable(ifindex int) ([]Interface, error) {
 // network interfaces.  Otherwise it returns addresses for a specific
 // interface.
 func interfaceAddrTable(ifi *Interface) ([]Addr, error) {
-	ai, err := getAdapterList()
+	paddr, err := getAdapters()
 	if err != nil {
 		return nil, err
 	}
 
 	var ifat []Addr
-	for ; ai != nil; ai = ai.Next {
-		index := ai.Index
+	for ; paddr != nil; paddr = paddr.Next {
+		index := paddr.IfIndex
+		if paddr.Ipv6IfIndex != 0 {
+			index = paddr.Ipv6IfIndex
+		}
 		if ifi == nil || ifi.Index == int(index) {
-			ipl := &ai.IpAddressList
-			for ; ipl != nil; ipl = ipl.Next {
-				ifa := IPAddr{IP: parseIPv4(bytePtrToString(&ipl.IpAddress.String[0]))}
-				ifat = append(ifat, ifa.toAddr())
+			puni := paddr.FirstUnicastAddress
+			for ; puni != nil; puni = puni.Next {
+				if sa, err := puni.Address.Sockaddr.Sockaddr(); err == nil {
+					switch sav := sa.(type) {
+					case *syscall.SockaddrInet4:
+						ifa := &IPNet{IP: make(IP, IPv4len), Mask: CIDRMask(int(puni.Address.SockaddrLength), 8*IPv4len)}
+						copy(ifa.IP, sav.Addr[:])
+						ifat = append(ifat, ifa)
+					case *syscall.SockaddrInet6:
+						ifa := &IPNet{IP: make(IP, IPv6len), Mask: CIDRMask(int(puni.Address.SockaddrLength), 8*IPv6len)}
+						copy(ifa.IP, sav.Addr[:])
+						ifat = append(ifat, ifa)
+					}
+				}
+			}
+			pany := paddr.FirstAnycastAddress
+			for ; pany != nil; pany = pany.Next {
+				if sa, err := pany.Address.Sockaddr.Sockaddr(); err == nil {
+					switch sav := sa.(type) {
+					case *syscall.SockaddrInet4:
+						ifa := &IPNet{IP: make(IP, IPv4len), Mask: CIDRMask(int(pany.Address.SockaddrLength), 8*IPv4len)}
+						copy(ifa.IP, sav.Addr[:])
+						ifat = append(ifat, ifa)
+					case *syscall.SockaddrInet6:
+						ifa := &IPNet{IP: make(IP, IPv6len), Mask: CIDRMask(int(pany.Address.SockaddrLength), 8*IPv6len)}
+						copy(ifa.IP, sav.Addr[:])
+						ifat = append(ifat, ifa)
+					}
+				}
 			}
 		}
 	}
+
 	return ifat, nil
 }
 
 // interfaceMulticastAddrTable returns addresses for a specific
 // interface.
 func interfaceMulticastAddrTable(ifi *Interface) ([]Addr, error) {
-	// TODO(mikio): Implement this like other platforms.
-	return nil, nil
+	paddr, err := getAdapters()
+	if err != nil {
+		return nil, err
+	}
+
+	var ifat []Addr
+	for ; paddr != nil; paddr = paddr.Next {
+		index := paddr.IfIndex
+		if paddr.Ipv6IfIndex != 0 {
+			index = paddr.Ipv6IfIndex
+		}
+		if ifi == nil || ifi.Index == int(index) {
+			pmul := paddr.FirstMulticastAddress
+			for ; pmul != nil; pmul = pmul.Next {
+				if sa, err := pmul.Address.Sockaddr.Sockaddr(); err == nil {
+					switch sav := sa.(type) {
+					case *syscall.SockaddrInet4:
+						ifa := &IPAddr{IP: make(IP, IPv4len)}
+						copy(ifa.IP, sav.Addr[:])
+						ifat = append(ifat, ifa)
+					case *syscall.SockaddrInet6:
+						ifa := &IPAddr{IP: make(IP, IPv6len)}
+						copy(ifa.IP, sav.Addr[:])
+						ifat = append(ifat, ifa)
+					}
+				}
+			}
+		}
+	}
+
+	return ifat, nil
 }
diff --git a/src/net/internal/socktest/main_test.go b/src/net/internal/socktest/main_test.go
new file mode 100644
index 0000000..60e581f
--- /dev/null
+++ b/src/net/internal/socktest/main_test.go
@@ -0,0 +1,56 @@
+// 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"
+	"sync"
+	"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 TestSwitch(t *testing.T) {
+	const N = 10
+	var wg sync.WaitGroup
+	wg.Add(N)
+	for i := 0; i < N; i++ {
+		go func() {
+			defer wg.Done()
+			for _, family := range []int{syscall.AF_INET, syscall.AF_INET6} {
+				socketFunc(family, syscall.SOCK_STREAM, syscall.IPPROTO_TCP)
+			}
+		}()
+	}
+	wg.Wait()
+}
+
+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..4e38c7a
--- /dev/null
+++ b/src/net/internal/socktest/switch.go
@@ -0,0 +1,169 @@
+// 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 (
+	"fmt"
+	"sync"
+)
+
+// 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
+}
+
+func (sw *Switch) init() {
+	sw.fltab = make(map[FilterType]Filter)
+	sw.sotab = make(Sockets)
+	sw.stats = make(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 error // error status of socket by SO_ERROR
+}
+
+func (so Status) String() string {
+	return fmt.Sprintf("(%s, %s, %s): syscallerr=%v, socketerr=%v", familyString(so.Cookie.Family()), typeString(so.Cookie.Type()), protocolString(so.Cookie.Protocol()), so.Err, so.SocketErr)
+}
+
+// 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
+	Connected uint64 // number of sockets connected
+	Listened  uint64 // number of sockets listened
+	Accepted  uint64 // number of sockets accepted
+	Closed    uint64 // number of sockets closed
+
+	OpenFailed    uint64 // number of sockets open failed
+	ConnectFailed uint64 // number of sockets connect failed
+	ListenFailed  uint64 // number of sockets listen failed
+	AcceptFailed  uint64 // number of sockets accept failed
+	CloseFailed   uint64 // number of sockets close failed
+}
+
+func (st Stat) String() string {
+	return fmt.Sprintf("(%s, %s, %s): opened=%d, connected=%d, listened=%d, accepted=%d, closed=%d, openfailed=%d, connectfailed=%d, listenfailed=%d, acceptfailed=%d, closefailed=%d", familyString(st.Family), typeString(st.Type), protocolString(st.Protocol), st.Opened, st.Connected, st.Listened, st.Accepted, st.Closed, st.OpenFailed, st.ConnectFailed, st.ListenFailed, st.AcceptFailed, st.CloseFailed)
+}
+
+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
+	FilterConnect                         // for Connect or ConnectEx
+	FilterListen                          // for Listen
+	FilterAccept                          // for Accept or Accept4
+	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(sw.init)
+	sw.fmu.Lock()
+	sw.fltab[t] = f
+	sw.fmu.Unlock()
+}
diff --git a/src/net/internal/socktest/switch_posix.go b/src/net/internal/socktest/switch_posix.go
new file mode 100644
index 0000000..863edef
--- /dev/null
+++ b/src/net/internal/socktest/switch_posix.go
@@ -0,0 +1,58 @@
+// 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
+
+import (
+	"fmt"
+	"syscall"
+)
+
+func familyString(family int) string {
+	switch family {
+	case syscall.AF_INET:
+		return "inet4"
+	case syscall.AF_INET6:
+		return "inet6"
+	case syscall.AF_UNIX:
+		return "local"
+	default:
+		return fmt.Sprintf("%d", family)
+	}
+}
+
+func typeString(sotype int) string {
+	var s string
+	switch sotype & 0xff {
+	case syscall.SOCK_STREAM:
+		s = "stream"
+	case syscall.SOCK_DGRAM:
+		s = "datagram"
+	case syscall.SOCK_RAW:
+		s = "raw"
+	case syscall.SOCK_SEQPACKET:
+		s = "seqpacket"
+	default:
+		s = fmt.Sprintf("%d", sotype&0xff)
+	}
+	if flags := uint(sotype) & ^uint(0xff); flags != 0 {
+		s += fmt.Sprintf("|%#x", flags)
+	}
+	return s
+}
+
+func protocolString(proto int) string {
+	switch proto {
+	case 0:
+		return "default"
+	case syscall.IPPROTO_TCP:
+		return "tcp"
+	case syscall.IPPROTO_UDP:
+		return "udp"
+	default:
+		return fmt.Sprintf("%d", proto)
+	}
+}
diff --git a/src/net/internal/socktest/switch_stub.go b/src/net/internal/socktest/switch_stub.go
new file mode 100644
index 0000000..28ce72c
--- /dev/null
+++ b/src/net/internal/socktest/switch_stub.go
@@ -0,0 +1,16 @@
+// 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
+
+func familyString(family int) string { return "<nil>" }
+
+func typeString(sotype int) string { return "<nil>" }
+
+func protocolString(proto int) string { return "<nil>" }
diff --git a/src/net/internal/socktest/switch_unix.go b/src/net/internal/socktest/switch_unix.go
new file mode 100644
index 0000000..14c0c22
--- /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(sw.init)
+	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..4f1d597
--- /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(sw.init)
+	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..340ff07
--- /dev/null
+++ b/src/net/internal/socktest/sys_cloexec.go
@@ -0,0 +1,42 @@
+// 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
+	}
+
+	sw.smu.Lock()
+	defer sw.smu.Unlock()
+	if so.Err != nil {
+		sw.stats.getLocked(so.Cookie).AcceptFailed++
+		return -1, nil, so.Err
+	}
+	nso := sw.addLocked(ns, so.Cookie.Family(), so.Cookie.Type(), so.Cookie.Protocol())
+	sw.stats.getLocked(nso.Cookie).Accepted++
+	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..f983e26
--- /dev/null
+++ b/src/net/internal/socktest/sys_unix.go
@@ -0,0 +1,193 @@
+// 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) {
+	sw.once.Do(sw.init)
+
+	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
+	}
+
+	sw.smu.Lock()
+	defer sw.smu.Unlock()
+	if so.Err != nil {
+		sw.stats.getLocked(so.Cookie).OpenFailed++
+		return -1, so.Err
+	}
+	nso := sw.addLocked(s, family, sotype, proto)
+	sw.stats.getLocked(nso.Cookie).Opened++
+	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
+	}
+
+	sw.smu.Lock()
+	defer sw.smu.Unlock()
+	if so.Err != nil {
+		sw.stats.getLocked(so.Cookie).CloseFailed++
+		return so.Err
+	}
+	delete(sw.sotab, s)
+	sw.stats.getLocked(so.Cookie).Closed++
+	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
+	}
+
+	sw.smu.Lock()
+	defer sw.smu.Unlock()
+	if so.Err != nil {
+		sw.stats.getLocked(so.Cookie).ConnectFailed++
+		return so.Err
+	}
+	sw.stats.getLocked(so.Cookie).Connected++
+	return nil
+}
+
+// Listen wraps syscall.Listen.
+func (sw *Switch) Listen(s, backlog int) (err error) {
+	so := sw.sockso(s)
+	if so == nil {
+		return syscall.Listen(s, backlog)
+	}
+	sw.fmu.RLock()
+	f, _ := sw.fltab[FilterListen]
+	sw.fmu.RUnlock()
+
+	af, err := f.apply(so)
+	if err != nil {
+		return err
+	}
+	so.Err = syscall.Listen(s, backlog)
+	if err = af.apply(so); err != nil {
+		return err
+	}
+
+	sw.smu.Lock()
+	defer sw.smu.Unlock()
+	if so.Err != nil {
+		sw.stats.getLocked(so.Cookie).ListenFailed++
+		return so.Err
+	}
+	sw.stats.getLocked(so.Cookie).Listened++
+	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
+	}
+
+	sw.smu.Lock()
+	defer sw.smu.Unlock()
+	if so.Err != nil {
+		sw.stats.getLocked(so.Cookie).AcceptFailed++
+		return -1, nil, so.Err
+	}
+	nso := sw.addLocked(ns, so.Cookie.Family(), so.Cookie.Type(), so.Cookie.Protocol())
+	sw.stats.getLocked(nso.Cookie).Accepted++
+	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
+	}
+	soerr, so.Err = syscall.GetsockoptInt(s, level, opt)
+	so.SocketErr = syscall.Errno(soerr)
+	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 == syscall.Errno(0) || so.SocketErr == syscall.EISCONN) {
+		sw.smu.Lock()
+		sw.stats.getLocked(so.Cookie).Connected++
+		sw.smu.Unlock()
+	}
+	return soerr, 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..e61bf2b
--- /dev/null
+++ b/src/net/internal/socktest/sys_windows.go
@@ -0,0 +1,156 @@
+// 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) {
+	sw.once.Do(sw.init)
+
+	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
+	}
+
+	sw.smu.Lock()
+	defer sw.smu.Unlock()
+	if so.Err != nil {
+		sw.stats.getLocked(so.Cookie).OpenFailed++
+		return syscall.InvalidHandle, so.Err
+	}
+	nso := sw.addLocked(s, family, sotype, proto)
+	sw.stats.getLocked(nso.Cookie).Opened++
+	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
+	}
+
+	sw.smu.Lock()
+	defer sw.smu.Unlock()
+	if so.Err != nil {
+		sw.stats.getLocked(so.Cookie).CloseFailed++
+		return so.Err
+	}
+	delete(sw.sotab, s)
+	sw.stats.getLocked(so.Cookie).Closed++
+	return nil
+}
+
+// Connect 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
+	}
+
+	sw.smu.Lock()
+	defer sw.smu.Unlock()
+	if so.Err != nil {
+		sw.stats.getLocked(so.Cookie).ConnectFailed++
+		return so.Err
+	}
+	sw.stats.getLocked(so.Cookie).Connected++
+	return nil
+}
+
+// ConnectEx 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
+	}
+
+	sw.smu.Lock()
+	defer sw.smu.Unlock()
+	if so.Err != nil {
+		sw.stats.getLocked(so.Cookie).ConnectFailed++
+		return so.Err
+	}
+	sw.stats.getLocked(so.Cookie).Connected++
+	return nil
+}
+
+// Listen wraps syscall.Listen.
+func (sw *Switch) Listen(s syscall.Handle, backlog int) (err error) {
+	so := sw.sockso(s)
+	if so == nil {
+		return syscall.Listen(s, backlog)
+	}
+	sw.fmu.RLock()
+	f, _ := sw.fltab[FilterListen]
+	sw.fmu.RUnlock()
+
+	af, err := f.apply(so)
+	if err != nil {
+		return err
+	}
+	so.Err = syscall.Listen(s, backlog)
+	if err = af.apply(so); err != nil {
+		return err
+	}
+
+	sw.smu.Lock()
+	defer sw.smu.Unlock()
+	if so.Err != nil {
+		sw.stats.getLocked(so.Cookie).ListenFailed++
+		return so.Err
+	}
+	sw.stats.getLocked(so.Cookie).Listened++
+	return nil
+}
diff --git a/src/net/ip.go b/src/net/ip.go
index 4a93e97..cc004d6 100644
--- a/src/net/ip.go
+++ b/src/net/ip.go
@@ -12,8 +12,6 @@
 
 package net
 
-import "errors"
-
 // IP address lengths (bytes).
 const (
 	IPv4len = 4
@@ -108,58 +106,57 @@ var (
 	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
-	}
-	return false
+	return ip.Equal(IPv4zero) || ip.Equal(IPv6unspecified)
 }
 
-// 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
+	if ip4 := ip.To4(); ip4 != nil {
+		return ip4[0] == 127
 	}
 	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
+	if ip4 := ip.To4(); ip4 != nil {
+		return ip4[0]&0xf0 == 0xe0
 	}
-	return ip[0] == 0xff
+	return len(ip) == IPv6len && ip[0] == 0xff
 }
 
-// IsInterfaceLinkLocalMulticast 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 {
-		return true
+	if ip4 := ip.To4(); ip4 != nil {
+		return ip4[0] == 224 && ip4[1] == 0 && ip4[2] == 0
 	}
-	return ip[0] == 0xff && ip[1]&0x0f == 0x02
+	return len(ip) == IPv6len && 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 {
-		return true
+	if ip4 := ip.To4(); ip4 != nil {
+		return ip4[0] == 169 && ip4[1] == 254
 	}
-	return ip[0] == 0xfe && ip[1]&0xc0 == 0x80
+	return len(ip) == IPv6len && 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() &&
+	return (len(ip) == IPv4len || len(ip) == IPv6len) &&
+		!ip.Equal(IPv4bcast) &&
+		!ip.IsUnspecified() &&
 		!ip.IsLoopback() &&
 		!ip.IsMulticast() &&
 		!ip.IsLinkLocalUnicast()
@@ -267,10 +264,10 @@ func (ip IP) String() string {
 
 	// If IPv4, use dotted notation.
 	if p4 := p.To4(); len(p4) == IPv4len {
-		return itod(uint(p4[0])) + "." +
-			itod(uint(p4[1])) + "." +
-			itod(uint(p4[2])) + "." +
-			itod(uint(p4[3]))
+		return uitoa(uint(p4[0])) + "." +
+			uitoa(uint(p4[1])) + "." +
+			uitoa(uint(p4[2])) + "." +
+			uitoa(uint(p4[3]))
 	}
 	if len(p) != IPv6len {
 		return "?"
@@ -331,7 +328,7 @@ func (ip IP) MarshalText() ([]byte, error) {
 		return []byte(""), nil
 	}
 	if len(ip) != IPv4len && len(ip) != IPv6len {
-		return nil, errors.New("invalid IP address")
+		return nil, &AddrError{Err: "invalid IP address", Addr: ip.String()}
 	}
 	return []byte(ip.String()), nil
 }
@@ -346,13 +343,13 @@ func (ip *IP) UnmarshalText(text []byte) error {
 	s := string(text)
 	x := ParseIP(s)
 	if x == nil {
-		return &ParseError{"IP address", s}
+		return &ParseError{Type: "IP address", Text: s}
 	}
 	*ip = x
 	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 {
@@ -491,7 +488,7 @@ func (n *IPNet) String() string {
 	if l == -1 {
 		return nn.String() + "/" + m.String()
 	}
-	return nn.String() + "/" + itod(uint(l))
+	return nn.String() + "/" + uitoa(uint(l))
 }
 
 // Parse IPv4 address (d.d.d.d).
@@ -633,16 +630,6 @@ func parseIPv6(s string, zoneAllowed bool) (ip IP, zone string) {
 	return ip, zone
 }
 
-// A ParseError represents a malformed text string and the type of string that was expected.
-type ParseError struct {
-	Type string
-	Text string
-}
-
-func (e *ParseError) Error() string {
-	return "invalid " + e.Type + ": " + e.Text
-}
-
 // ParseIP parses s as an IP address, returning the result.
 // The string s can be in dotted decimal ("74.125.19.99")
 // or IPv6 ("2001:4860:0:2001::68") form.
@@ -671,7 +658,7 @@ func ParseIP(s string) IP {
 func ParseCIDR(s string) (IP, *IPNet, error) {
 	i := byteIndex(s, '/')
 	if i < 0 {
-		return nil, nil, &ParseError{"CIDR address", s}
+		return nil, nil, &ParseError{Type: "CIDR address", Text: s}
 	}
 	addr, mask := s[:i], s[i+1:]
 	iplen := IPv4len
@@ -682,7 +669,7 @@ func ParseCIDR(s string) (IP, *IPNet, error) {
 	}
 	n, i, ok := dtoi(mask, 0)
 	if ip == nil || !ok || i != len(mask) || n < 0 || n > 8*iplen {
-		return nil, nil, &ParseError{"CIDR address", s}
+		return nil, nil, &ParseError{Type: "CIDR address", Text: s}
 	}
 	m := CIDRMask(n, 8*iplen)
 	return ip, &IPNet{IP: ip.Mask(m), Mask: m}, nil
diff --git a/src/net/ip_test.go b/src/net/ip_test.go
index 485ff51..3d95a73 100644
--- a/src/net/ip_test.go
+++ b/src/net/ip_test.go
@@ -16,12 +16,20 @@ var parseIPTests = []struct {
 }{
 	{"127.0.1.2", IPv4(127, 0, 1, 2)},
 	{"127.0.0.1", IPv4(127, 0, 0, 1)},
+	{"127.001.002.003", IPv4(127, 1, 2, 3)},
+	{"::ffff:127.1.2.3", IPv4(127, 1, 2, 3)},
+	{"::ffff:127.001.002.003", IPv4(127, 1, 2, 3)},
+	{"::ffff:7f01:0203", IPv4(127, 1, 2, 3)},
+	{"0:0:0:0:0000:ffff:127.1.2.3", IPv4(127, 1, 2, 3)},
+	{"0:0:0:0:000000:ffff:127.1.2.3", IPv4(127, 1, 2, 3)},
+	{"0:0:0:0::ffff:127.1.2.3", IPv4(127, 1, 2, 3)},
+
+	{"2001:4860:0:2001::68", IP{0x20, 0x01, 0x48, 0x60, 0, 0, 0x20, 0x01, 0, 0, 0, 0, 0, 0, 0x00, 0x68}},
+	{"2001:4860:0000:2001:0000:0000:0000:0068", IP{0x20, 0x01, 0x48, 0x60, 0, 0, 0x20, 0x01, 0, 0, 0, 0, 0, 0, 0x00, 0x68}},
+
 	{"127.0.0.256", nil},
 	{"abc", nil},
 	{"123:", nil},
-	{"::ffff:127.0.0.1", IPv4(127, 0, 0, 1)},
-	{"2001:4860:0:2001::68", IP{0x20, 0x01, 0x48, 0x60, 0, 0, 0x20, 0x01, 0, 0, 0, 0, 0, 0, 0x00, 0x68}},
-	{"::ffff:4a7d:1363", IPv4(74, 125, 19, 99)},
 	{"fe80::1%lo0", nil},
 	{"fe80::1%911", nil},
 	{"", nil},
@@ -44,7 +52,52 @@ func TestParseIP(t *testing.T) {
 	}
 }
 
+func TestLookupWithIP(t *testing.T) {
+	_, err := LookupIP("")
+	if err == nil {
+		t.Errorf(`LookupIP("") succeeded, should fail`)
+	}
+	_, err = LookupHost("")
+	if err == nil {
+		t.Errorf(`LookupIP("") succeeded, should fail`)
+	}
+
+	// Test that LookupHost and LookupIP, which normally
+	// expect host names, work with IP addresses.
+	for _, tt := range parseIPTests {
+		if tt.out != nil {
+			addrs, err := LookupHost(tt.in)
+			if len(addrs) != 1 || addrs[0] != tt.in || err != nil {
+				t.Errorf("LookupHost(%q) = %v, %v, want %v, nil", tt.in, addrs, err, []string{tt.in})
+			}
+		} else if !testing.Short() {
+			// We can't control what the host resolver does; if it can resolve, say,
+			// 127.0.0.256 or fe80::1%911 or a host named 'abc', who are we to judge?
+			// Warn about these discrepancies but don't fail the test.
+			addrs, err := LookupHost(tt.in)
+			if err == nil {
+				t.Logf("warning: LookupHost(%q) = %v, want error", tt.in, addrs)
+			}
+		}
+
+		if tt.out != nil {
+			ips, err := LookupIP(tt.in)
+			if len(ips) != 1 || !reflect.DeepEqual(ips[0], tt.out) || err != nil {
+				t.Errorf("LookupIP(%q) = %v, %v, want %v, nil", tt.in, ips, err, []IP{tt.out})
+			}
+		} else if !testing.Short() {
+			ips, err := LookupIP(tt.in)
+			// We can't control what the host resolver does. See above.
+			if err == nil {
+				t.Logf("warning: LookupIP(%q) = %v, want error", tt.in, ips)
+			}
+		}
+	}
+}
+
 func BenchmarkParseIP(b *testing.B) {
+	testHookUninstaller.Do(uninstallTestHooks)
+
 	for i := 0; i < b.N; i++ {
 		for _, tt := range parseIPTests {
 			ParseIP(tt.in)
@@ -100,6 +153,8 @@ func TestIPString(t *testing.T) {
 }
 
 func BenchmarkIPString(b *testing.B) {
+	testHookUninstaller.Do(uninstallTestHooks)
+
 	for i := 0; i < b.N; i++ {
 		for _, tt := range ipStringTests {
 			if tt.in != nil {
@@ -150,6 +205,8 @@ func TestIPMaskString(t *testing.T) {
 }
 
 func BenchmarkIPMaskString(b *testing.B) {
+	testHookUninstaller.Do(uninstallTestHooks)
+
 	for i := 0; i < b.N; i++ {
 		for _, tt := range ipMaskStringTests {
 			tt.in.String()
@@ -180,10 +237,10 @@ var parseCIDRTests = []struct {
 	{"abcd:2345::/24", ParseIP("abcd:2345::"), &IPNet{IP: ParseIP("abcd:2300::"), Mask: IPMask(ParseIP("ffff:ff00::"))}, nil},
 	{"2001:DB8::/48", ParseIP("2001:DB8::"), &IPNet{IP: ParseIP("2001:DB8::"), Mask: IPMask(ParseIP("ffff:ffff:ffff::"))}, nil},
 	{"2001:DB8::1/48", ParseIP("2001:DB8::1"), &IPNet{IP: ParseIP("2001:DB8::"), Mask: IPMask(ParseIP("ffff:ffff:ffff::"))}, nil},
-	{"192.168.1.1/255.255.255.0", nil, nil, &ParseError{"CIDR address", "192.168.1.1/255.255.255.0"}},
-	{"192.168.1.1/35", nil, nil, &ParseError{"CIDR address", "192.168.1.1/35"}},
-	{"2001:db8::1/-1", nil, nil, &ParseError{"CIDR address", "2001:db8::1/-1"}},
-	{"", nil, nil, &ParseError{"CIDR address", ""}},
+	{"192.168.1.1/255.255.255.0", nil, nil, &ParseError{Type: "CIDR address", Text: "192.168.1.1/255.255.255.0"}},
+	{"192.168.1.1/35", nil, nil, &ParseError{Type: "CIDR address", Text: "192.168.1.1/35"}},
+	{"2001:db8::1/-1", nil, nil, &ParseError{Type: "CIDR address", Text: "2001:db8::1/-1"}},
+	{"", nil, nil, &ParseError{Type: "CIDR address", Text: ""}},
 }
 
 func TestParseCIDR(t *testing.T) {
@@ -425,31 +482,44 @@ var ipAddrScopeTests = []struct {
 	{IP.IsUnspecified, IPv4(127, 0, 0, 1), false},
 	{IP.IsUnspecified, IPv6unspecified, true},
 	{IP.IsUnspecified, IPv6interfacelocalallnodes, false},
+	{IP.IsUnspecified, nil, false},
 	{IP.IsLoopback, IPv4(127, 0, 0, 1), true},
 	{IP.IsLoopback, IPv4(127, 255, 255, 254), true},
 	{IP.IsLoopback, IPv4(128, 1, 2, 3), false},
 	{IP.IsLoopback, IPv6loopback, true},
 	{IP.IsLoopback, IPv6linklocalallrouters, false},
+	{IP.IsLoopback, nil, false},
 	{IP.IsMulticast, IPv4(224, 0, 0, 0), true},
 	{IP.IsMulticast, IPv4(239, 0, 0, 0), true},
 	{IP.IsMulticast, IPv4(240, 0, 0, 0), false},
 	{IP.IsMulticast, IPv6linklocalallnodes, true},
 	{IP.IsMulticast, IP{0xff, 0x05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, true},
 	{IP.IsMulticast, IP{0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, false},
+	{IP.IsMulticast, nil, false},
+	{IP.IsInterfaceLocalMulticast, IPv4(224, 0, 0, 0), false},
+	{IP.IsInterfaceLocalMulticast, IPv4(0xff, 0x01, 0, 0), false},
+	{IP.IsInterfaceLocalMulticast, IPv6interfacelocalallnodes, true},
+	{IP.IsInterfaceLocalMulticast, nil, false},
 	{IP.IsLinkLocalMulticast, IPv4(224, 0, 0, 0), true},
 	{IP.IsLinkLocalMulticast, IPv4(239, 0, 0, 0), false},
+	{IP.IsLinkLocalMulticast, IPv4(0xff, 0x02, 0, 0), false},
 	{IP.IsLinkLocalMulticast, IPv6linklocalallrouters, true},
 	{IP.IsLinkLocalMulticast, IP{0xff, 0x05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, false},
+	{IP.IsLinkLocalMulticast, nil, false},
 	{IP.IsLinkLocalUnicast, IPv4(169, 254, 0, 0), true},
 	{IP.IsLinkLocalUnicast, IPv4(169, 255, 0, 0), false},
+	{IP.IsLinkLocalUnicast, IPv4(0xfe, 0x80, 0, 0), false},
 	{IP.IsLinkLocalUnicast, IP{0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, true},
 	{IP.IsLinkLocalUnicast, IP{0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, false},
+	{IP.IsLinkLocalUnicast, nil, false},
 	{IP.IsGlobalUnicast, IPv4(240, 0, 0, 0), true},
 	{IP.IsGlobalUnicast, IPv4(232, 0, 0, 0), false},
 	{IP.IsGlobalUnicast, IPv4(169, 254, 0, 0), false},
+	{IP.IsGlobalUnicast, IPv4bcast, false},
 	{IP.IsGlobalUnicast, IP{0x20, 0x1, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0x1, 0x23, 0, 0x12, 0, 0x1}, true},
 	{IP.IsGlobalUnicast, IP{0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, false},
 	{IP.IsGlobalUnicast, IP{0xff, 0x05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, false},
+	{IP.IsGlobalUnicast, nil, false},
 }
 
 func name(f interface{}) string {
@@ -461,5 +531,12 @@ func TestIPAddrScope(t *testing.T) {
 		if ok := tt.scope(tt.in); ok != tt.ok {
 			t.Errorf("%s(%q) = %v, want %v", name(tt.scope), tt.in, ok, tt.ok)
 		}
+		ip := tt.in.To4()
+		if ip == nil {
+			continue
+		}
+		if ok := tt.scope(ip); ok != tt.ok {
+			t.Errorf("%s(%q) = %v, want %v", name(tt.scope), ip, ok, tt.ok)
+		}
 	}
 }
diff --git a/src/net/ipraw_test.go b/src/net/ipraw_test.go
index 92dc8dc..5d86a9d 100644
--- a/src/net/ipraw_test.go
+++ b/src/net/ipraw_test.go
@@ -5,17 +5,18 @@
 package net
 
 import (
-	"bytes"
-	"fmt"
-	"os"
 	"reflect"
-	"runtime"
 	"testing"
-	"time"
 )
 
+// The full stack test cases for IPConn have been moved to the
+// following:
+//	golang.org/x/net/ipv4
+//	golang.org/x/net/ipv6
+//	golang.org/x/net/icmp
+
 type resolveIPAddrTest struct {
-	net           string
+	network       string
 	litAddrOrName string
 	addr          *IPAddr
 	err           error
@@ -37,210 +38,41 @@ var resolveIPAddrTests = []resolveIPAddrTest{
 	{"", "127.0.0.1", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil}, // Go 1.0 behavior
 	{"", "::1", &IPAddr{IP: ParseIP("::1")}, nil},           // Go 1.0 behavior
 
+	{"ip4:icmp", "", &IPAddr{}, nil},
+
 	{"l2tp", "127.0.0.1", nil, UnknownNetworkError("l2tp")},
 	{"l2tp:gre", "127.0.0.1", nil, UnknownNetworkError("l2tp:gre")},
 	{"tcp", "1.2.3.4:123", nil, UnknownNetworkError("tcp")},
 }
 
-func init() {
-	if ifi := loopbackInterface(); ifi != nil {
-		index := fmt.Sprintf("%v", ifi.Index)
-		resolveIPAddrTests = append(resolveIPAddrTests, []resolveIPAddrTest{
-			{"ip6", "fe80::1%" + ifi.Name, &IPAddr{IP: ParseIP("fe80::1"), Zone: zoneToString(ifi.Index)}, nil},
-			{"ip6", "fe80::1%" + index, &IPAddr{IP: ParseIP("fe80::1"), Zone: index}, nil},
-		}...)
-	}
-	if ips, err := LookupIP("localhost"); err == nil && len(ips) > 1 && supportsIPv4 && supportsIPv6 {
-		resolveIPAddrTests = append(resolveIPAddrTests, []resolveIPAddrTest{
-			{"ip", "localhost", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil},
-			{"ip4", "localhost", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil},
-			{"ip6", "localhost", &IPAddr{IP: IPv6loopback}, nil},
-		}...)
-	}
-}
-
-func skipRawSocketTest(t *testing.T) (skip bool, skipmsg string) {
-	skip, skipmsg, err := skipRawSocketTests()
-	if err != nil {
-		t.Fatal(err)
-	}
-	return skip, skipmsg
-}
-
 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 {
-		addr, err := ResolveIPAddr(tt.net, tt.litAddrOrName)
+	origTestHookLookupIP := testHookLookupIP
+	defer func() { testHookLookupIP = origTestHookLookupIP }()
+	testHookLookupIP = lookupLocalhost
+
+	for i, tt := range resolveIPAddrTests {
+		addr, err := ResolveIPAddr(tt.network, tt.litAddrOrName)
 		if err != tt.err {
-			t.Fatalf("ResolveIPAddr(%v, %v) failed: %v", tt.net, tt.litAddrOrName, err)
+			t.Errorf("#%d: %v", i, err)
 		} else if !reflect.DeepEqual(addr, tt.addr) {
-			t.Fatalf("got %#v; expected %#v", addr, tt.addr)
+			t.Errorf("#%d: got %#v; want %#v", i, addr, tt.addr)
 		}
-	}
-}
-
-var icmpEchoTests = []struct {
-	net   string
-	laddr string
-	raddr string
-}{
-	{"ip4:icmp", "0.0.0.0", "127.0.0.1"},
-	{"ip6:ipv6-icmp", "::", "::1"},
-}
-
-func TestConnICMPEcho(t *testing.T) {
-	if skip, skipmsg := skipRawSocketTest(t); skip {
-		t.Skip(skipmsg)
-	}
-
-	for i, tt := range icmpEchoTests {
-		net, _, err := parseNetwork(tt.net)
 		if err != nil {
-			t.Fatalf("parseNetwork failed: %v", err)
-		}
-		if net == "ip6" && !supportsIPv6 {
 			continue
 		}
-
-		c, err := Dial(tt.net, tt.raddr)
-		if err != nil {
-			t.Fatalf("Dial failed: %v", err)
-		}
-		c.SetDeadline(time.Now().Add(100 * time.Millisecond))
-		defer c.Close()
-
-		typ := icmpv4EchoRequest
-		if net == "ip6" {
-			typ = icmpv6EchoRequest
-		}
-		xid, xseq := os.Getpid()&0xffff, i+1
-		wb, err := (&icmpMessage{
-			Type: typ, Code: 0,
-			Body: &icmpEcho{
-				ID: xid, Seq: xseq,
-				Data: bytes.Repeat([]byte("Go Go Gadget Ping!!!"), 3),
-			},
-		}).Marshal()
+		rtaddr, err := ResolveIPAddr(addr.Network(), addr.String())
 		if err != nil {
-			t.Fatalf("icmpMessage.Marshal failed: %v", err)
-		}
-		if _, err := c.Write(wb); err != nil {
-			t.Fatalf("Conn.Write failed: %v", err)
-		}
-		var m *icmpMessage
-		rb := make([]byte, 20+len(wb))
-		for {
-			if _, err := c.Read(rb); err != nil {
-				t.Fatalf("Conn.Read failed: %v", err)
-			}
-			if net == "ip4" {
-				rb = ipv4Payload(rb)
-			}
-			if m, err = parseICMPMessage(rb); err != nil {
-				t.Fatalf("parseICMPMessage failed: %v", err)
-			}
-			switch m.Type {
-			case icmpv4EchoRequest, icmpv6EchoRequest:
-				continue
-			}
-			break
-		}
-		switch p := m.Body.(type) {
-		case *icmpEcho:
-			if p.ID != xid || p.Seq != xseq {
-				t.Fatalf("got id=%v, seqnum=%v; expected id=%v, seqnum=%v", p.ID, p.Seq, xid, xseq)
-			}
-		default:
-			t.Fatalf("got type=%v, code=%v; expected type=%v, code=%v", m.Type, m.Code, typ, 0)
+			t.Errorf("#%d: %v", i, err)
+		} else if !reflect.DeepEqual(rtaddr, addr) {
+			t.Errorf("#%d: got %#v; want %#v", i, rtaddr, addr)
 		}
 	}
 }
 
-func TestPacketConnICMPEcho(t *testing.T) {
-	if skip, skipmsg := skipRawSocketTest(t); skip {
-		t.Skip(skipmsg)
-	}
-
-	for i, tt := range icmpEchoTests {
-		net, _, err := parseNetwork(tt.net)
-		if err != nil {
-			t.Fatalf("parseNetwork failed: %v", err)
-		}
-		if net == "ip6" && !supportsIPv6 {
-			continue
-		}
-
-		c, err := ListenPacket(tt.net, tt.laddr)
-		if err != nil {
-			t.Fatalf("ListenPacket failed: %v", err)
-		}
-		c.SetDeadline(time.Now().Add(100 * time.Millisecond))
-		defer c.Close()
-
-		ra, err := ResolveIPAddr(tt.net, tt.raddr)
-		if err != nil {
-			t.Fatalf("ResolveIPAddr failed: %v", err)
-		}
-		typ := icmpv4EchoRequest
-		if net == "ip6" {
-			typ = icmpv6EchoRequest
-		}
-		xid, xseq := os.Getpid()&0xffff, i+1
-		wb, err := (&icmpMessage{
-			Type: typ, Code: 0,
-			Body: &icmpEcho{
-				ID: xid, Seq: xseq,
-				Data: bytes.Repeat([]byte("Go Go Gadget Ping!!!"), 3),
-			},
-		}).Marshal()
-		if err != nil {
-			t.Fatalf("icmpMessage.Marshal failed: %v", err)
-		}
-		if _, err := c.WriteTo(wb, ra); err != nil {
-			t.Fatalf("PacketConn.WriteTo failed: %v", err)
-		}
-		var m *icmpMessage
-		rb := make([]byte, 20+len(wb))
-		for {
-			if _, _, err := c.ReadFrom(rb); err != nil {
-				t.Fatalf("PacketConn.ReadFrom failed: %v", err)
-			}
-			// See BUG section.
-			//if net == "ip4" {
-			//	rb = ipv4Payload(rb)
-			//}
-			if m, err = parseICMPMessage(rb); err != nil {
-				t.Fatalf("parseICMPMessage failed: %v", err)
-			}
-			switch m.Type {
-			case icmpv4EchoRequest, icmpv6EchoRequest:
-				continue
-			}
-			break
-		}
-		switch p := m.Body.(type) {
-		case *icmpEcho:
-			if p.ID != xid || p.Seq != xseq {
-				t.Fatalf("got id=%v, seqnum=%v; expected id=%v, seqnum=%v", p.ID, p.Seq, xid, xseq)
-			}
-		default:
-			t.Fatalf("got type=%v, code=%v; expected type=%v, code=%v", m.Type, m.Code, typ, 0)
-		}
-	}
-}
-
-func ipv4Payload(b []byte) []byte {
-	if len(b) < 20 {
-		return b
-	}
-	hdrlen := int(b[0]&0x0f) << 2
-	return b[hdrlen:]
-}
-
 var ipConnLocalNameTests = []struct {
 	net   string
 	laddr *IPAddr
@@ -251,44 +83,34 @@ var ipConnLocalNameTests = []struct {
 }
 
 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)
+			t.Fatal(err)
 		}
 		defer c.Close()
 		if la := c.LocalAddr(); la == nil {
-			t.Fatal("IPConn.LocalAddr failed")
+			t.Fatal("should not fail")
 		}
 	}
 }
 
 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()}
 	c, err := DialIP("ip:tcp", &IPAddr{IP: IPv4(127, 0, 0, 1)}, raddr)
 	if err != nil {
-		t.Fatalf("DialIP failed: %v", err)
+		t.Fatal(err)
 	}
 	defer c.Close()
 	if !reflect.DeepEqual(raddr, c.RemoteAddr()) {
-		t.Fatalf("got %#v, expected %#v", c.RemoteAddr(), raddr)
+		t.Fatalf("got %#v; want %#v", c.RemoteAddr(), raddr)
 	}
 }
diff --git a/src/net/iprawsock.go b/src/net/iprawsock.go
index 5cc3613..f02df7f 100644
--- a/src/net/iprawsock.go
+++ b/src/net/iprawsock.go
@@ -17,13 +17,21 @@ func (a *IPAddr) String() string {
 	if a == nil {
 		return "<nil>"
 	}
+	ip := ipEmptyString(a.IP)
 	if a.Zone != "" {
-		return a.IP.String() + "%" + a.Zone
+		return ip + "%" + a.Zone
 	}
-	return a.IP.String()
+	return ip
 }
 
-func (a *IPAddr) toAddr() Addr {
+func (a *IPAddr) isWildcard() bool {
+	if a == nil || a.IP == nil {
+		return true
+	}
+	return a.IP.IsUnspecified()
+}
+
+func (a *IPAddr) opAddr() Addr {
 	if a == nil {
 		return nil
 	}
@@ -46,9 +54,9 @@ func ResolveIPAddr(net, addr string) (*IPAddr, error) {
 	default:
 		return nil, UnknownNetworkError(net)
 	}
-	a, err := resolveInternetAddr(afnet, addr, noDeadline)
+	addrs, err := internetAddrList(afnet, addr, noDeadline)
 	if err != nil {
 		return nil, err
 	}
-	return a.toAddr().(*IPAddr), nil
+	return addrs.first(isIPv4).(*IPAddr), nil
 }
diff --git a/src/net/iprawsock_plan9.go b/src/net/iprawsock_plan9.go
index e62d116..b027adc 100644
--- a/src/net/iprawsock_plan9.go
+++ b/src/net/iprawsock_plan9.go
@@ -23,12 +23,12 @@ type IPConn struct {
 // Timeout() == true after a fixed time limit; see SetDeadline and
 // SetReadDeadline.
 func (c *IPConn) ReadFromIP(b []byte) (int, *IPAddr, error) {
-	return 0, nil, syscall.EPLAN9
+	return 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
 }
 
 // ReadFrom implements the PacketConn ReadFrom method.
 func (c *IPConn) ReadFrom(b []byte) (int, Addr, error) {
-	return 0, nil, syscall.EPLAN9
+	return 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
 }
 
 // ReadMsgIP reads a packet from c, copying the payload into b and the
@@ -36,7 +36,7 @@ func (c *IPConn) ReadFrom(b []byte) (int, Addr, error) {
 // bytes copied into b, the number of bytes copied into oob, the flags
 // that were set on the packet and the source address of the packet.
 func (c *IPConn) ReadMsgIP(b, oob []byte) (n, oobn, flags int, addr *IPAddr, err error) {
-	return 0, 0, 0, nil, syscall.EPLAN9
+	return 0, 0, 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
 }
 
 // WriteToIP writes an IP packet to addr via c, copying the payload
@@ -47,19 +47,19 @@ func (c *IPConn) ReadMsgIP(b, oob []byte) (n, oobn, flags int, addr *IPAddr, err
 // SetWriteDeadline.  On packet-oriented connections, write timeouts
 // are rare.
 func (c *IPConn) WriteToIP(b []byte, addr *IPAddr) (int, error) {
-	return 0, syscall.EPLAN9
+	return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr.opAddr(), Err: syscall.EPLAN9}
 }
 
 // WriteTo implements the PacketConn WriteTo method.
 func (c *IPConn) WriteTo(b []byte, addr Addr) (int, error) {
-	return 0, syscall.EPLAN9
+	return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr, Err: syscall.EPLAN9}
 }
 
 // WriteMsgIP writes a packet to addr via c, copying the payload from
 // b and the associated out-of-band data from oob.  It returns the
 // number of payload and out-of-band bytes written.
 func (c *IPConn) WriteMsgIP(b, oob []byte, addr *IPAddr) (n, oobn int, err error) {
-	return 0, 0, syscall.EPLAN9
+	return 0, 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr.opAddr(), Err: syscall.EPLAN9}
 }
 
 // DialIP connects to the remote address raddr on the network protocol
@@ -70,7 +70,7 @@ func DialIP(netProto string, laddr, raddr *IPAddr) (*IPConn, error) {
 }
 
 func dialIP(netProto string, laddr, raddr *IPAddr, deadline time.Time) (*IPConn, error) {
-	return nil, syscall.EPLAN9
+	return nil, &OpError{Op: "dial", Net: netProto, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: syscall.EPLAN9}
 }
 
 // ListenIP listens for incoming IP packets addressed to the local
@@ -78,5 +78,5 @@ func dialIP(netProto string, laddr, raddr *IPAddr, deadline time.Time) (*IPConn,
 // methods can be used to receive and send IP packets with per-packet
 // addressing.
 func ListenIP(netProto string, laddr *IPAddr) (*IPConn, error) {
-	return nil, syscall.EPLAN9
+	return nil, &OpError{Op: "listen", Net: netProto, Source: nil, Addr: laddr.opAddr(), Err: syscall.EPLAN9}
 }
diff --git a/src/net/iprawsock_posix.go b/src/net/iprawsock_posix.go
index 99b081b..9417606 100644
--- a/src/net/iprawsock_posix.go
+++ b/src/net/iprawsock_posix.go
@@ -43,13 +43,6 @@ func (a *IPAddr) family() int {
 	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
@@ -83,24 +76,41 @@ func (c *IPConn) ReadFromIP(b []byte) (int, *IPAddr, error) {
 	switch sa := sa.(type) {
 	case *syscall.SockaddrInet4:
 		addr = &IPAddr{IP: sa.Addr[0:]}
-		if len(b) >= IPv4len { // discard ipv4 header
-			hsize := (int(b[0]) & 0xf) * 4
-			copy(b, b[hsize:])
-			n -= hsize
-		}
+		n = stripIPv4Header(n, b)
 	case *syscall.SockaddrInet6:
 		addr = &IPAddr{IP: sa.Addr[0:], Zone: zoneToString(int(sa.ZoneId))}
 	}
+	if err != nil {
+		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
 	return n, addr, err
 }
 
+func stripIPv4Header(n int, b []byte) int {
+	if len(b) < 20 {
+		return n
+	}
+	l := int(b[0]&0x0f) << 2
+	if 20 > l || l > len(b) {
+		return n
+	}
+	if b[0]>>4 != 4 {
+		return n
+	}
+	copy(b, b[l:])
+	return n - l
+}
+
 // ReadFrom implements the PacketConn ReadFrom method.
 func (c *IPConn) ReadFrom(b []byte) (int, Addr, error) {
 	if !c.ok() {
 		return 0, nil, syscall.EINVAL
 	}
 	n, addr, err := c.ReadFromIP(b)
-	return n, addr.toAddr(), err
+	if addr == nil {
+		return n, nil, err
+	}
+	return n, addr, err
 }
 
 // ReadMsgIP reads a packet from c, copying the payload into b and the
@@ -119,6 +129,9 @@ func (c *IPConn) ReadMsgIP(b, oob []byte) (n, oobn, flags int, addr *IPAddr, err
 	case *syscall.SockaddrInet6:
 		addr = &IPAddr{IP: sa.Addr[0:], Zone: zoneToString(int(sa.ZoneId))}
 	}
+	if err != nil {
+		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
 	return
 }
 
@@ -134,16 +147,20 @@ func (c *IPConn) WriteToIP(b []byte, addr *IPAddr) (int, error) {
 		return 0, syscall.EINVAL
 	}
 	if c.fd.isConnected {
-		return 0, &OpError{Op: "write", Net: c.fd.net, Addr: addr, Err: ErrWriteToConnected}
+		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: ErrWriteToConnected}
 	}
 	if addr == nil {
-		return 0, &OpError{Op: "write", Net: c.fd.net, Addr: nil, Err: errMissingAddress}
+		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: nil, Err: errMissingAddress}
 	}
 	sa, err := addr.sockaddr(c.fd.family)
 	if err != nil {
-		return 0, &OpError{"write", c.fd.net, addr, err}
+		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
+	}
+	n, err := c.fd.writeTo(b, sa)
+	if err != nil {
+		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
 	}
-	return c.fd.writeTo(b, sa)
+	return n, err
 }
 
 // WriteTo implements the PacketConn WriteTo method.
@@ -153,7 +170,7 @@ func (c *IPConn) WriteTo(b []byte, addr Addr) (int, error) {
 	}
 	a, ok := addr.(*IPAddr)
 	if !ok {
-		return 0, &OpError{"write", c.fd.net, addr, syscall.EINVAL}
+		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: syscall.EINVAL}
 	}
 	return c.WriteToIP(b, a)
 }
@@ -166,16 +183,21 @@ func (c *IPConn) WriteMsgIP(b, oob []byte, addr *IPAddr) (n, oobn int, err error
 		return 0, 0, syscall.EINVAL
 	}
 	if c.fd.isConnected {
-		return 0, 0, &OpError{Op: "write", Net: c.fd.net, Addr: addr, Err: ErrWriteToConnected}
+		return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: ErrWriteToConnected}
 	}
 	if addr == nil {
-		return 0, 0, &OpError{Op: "write", Net: c.fd.net, Addr: nil, Err: errMissingAddress}
+		return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: nil, Err: errMissingAddress}
 	}
-	sa, err := addr.sockaddr(c.fd.family)
+	var sa syscall.Sockaddr
+	sa, err = addr.sockaddr(c.fd.family)
 	if err != nil {
-		return 0, 0, &OpError{"write", c.fd.net, addr, err}
+		return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
 	}
-	return c.fd.writeMsg(b, oob, sa)
+	n, oobn, err = c.fd.writeMsg(b, oob, sa)
+	if err != nil {
+		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
+	}
+	return
 }
 
 // DialIP connects to the remote address raddr on the network protocol
@@ -188,19 +210,19 @@ func DialIP(netProto string, laddr, raddr *IPAddr) (*IPConn, error) {
 func dialIP(netProto string, laddr, raddr *IPAddr, deadline time.Time) (*IPConn, error) {
 	net, proto, err := parseNetwork(netProto)
 	if err != nil {
-		return nil, &OpError{Op: "dial", Net: netProto, Addr: raddr, Err: err}
+		return nil, &OpError{Op: "dial", Net: netProto, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err}
 	}
 	switch net {
 	case "ip", "ip4", "ip6":
 	default:
-		return nil, &OpError{Op: "dial", Net: netProto, Addr: raddr, Err: UnknownNetworkError(netProto)}
+		return nil, &OpError{Op: "dial", Net: netProto, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(netProto)}
 	}
 	if raddr == nil {
-		return nil, &OpError{Op: "dial", Net: netProto, Addr: nil, Err: errMissingAddress}
+		return nil, &OpError{Op: "dial", Net: netProto, Source: laddr.opAddr(), Addr: nil, Err: errMissingAddress}
 	}
 	fd, err := internetSocket(net, laddr, raddr, deadline, syscall.SOCK_RAW, proto, "dial")
 	if err != nil {
-		return nil, &OpError{Op: "dial", Net: netProto, Addr: raddr, Err: err}
+		return nil, &OpError{Op: "dial", Net: netProto, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err}
 	}
 	return newIPConn(fd), nil
 }
@@ -212,16 +234,16 @@ func dialIP(netProto string, laddr, raddr *IPAddr, deadline time.Time) (*IPConn,
 func ListenIP(netProto string, laddr *IPAddr) (*IPConn, error) {
 	net, proto, err := parseNetwork(netProto)
 	if err != nil {
-		return nil, &OpError{Op: "dial", Net: netProto, Addr: laddr, Err: err}
+		return nil, &OpError{Op: "listen", Net: netProto, Source: nil, Addr: laddr.opAddr(), Err: err}
 	}
 	switch net {
 	case "ip", "ip4", "ip6":
 	default:
-		return nil, &OpError{Op: "listen", Net: netProto, Addr: laddr, Err: UnknownNetworkError(netProto)}
+		return nil, &OpError{Op: "listen", Net: netProto, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(netProto)}
 	}
 	fd, err := internetSocket(net, laddr, nil, noDeadline, syscall.SOCK_RAW, proto, "listen")
 	if err != nil {
-		return nil, &OpError{Op: "listen", Net: netProto, Addr: laddr, Err: err}
+		return nil, &OpError{Op: "listen", Net: netProto, Source: nil, Addr: laddr.opAddr(), Err: err}
 	}
 	return newIPConn(fd), nil
 }
diff --git a/src/net/ipsock.go b/src/net/ipsock.go
index dda8578..6e75c33 100644
--- a/src/net/ipsock.go
+++ b/src/net/ipsock.go
@@ -26,113 +26,82 @@ var (
 	supportsIPv4map bool
 )
 
-func init() {
-	sysInit()
-	supportsIPv4 = probeIPv4Stack()
-	supportsIPv6, supportsIPv4map = probeIPv6Stack()
-}
+// An addrList represents a list of network endpoint addresses.
+type addrList []Addr
 
-// A netaddr represents a network endpoint address or a list of
-// network endpoint addresses.
-type netaddr interface {
-	// toAddr returns the address represented in Addr interface.
-	// It returns a nil interface when the address is nil.
-	toAddr() Addr
+// isIPv4 returns true if the Addr contains an IPv4 address.
+func isIPv4(addr Addr) bool {
+	switch addr := addr.(type) {
+	case *TCPAddr:
+		return addr.IP.To4() != nil
+	case *UDPAddr:
+		return addr.IP.To4() != nil
+	case *IPAddr:
+		return addr.IP.To4() != nil
+	}
+	return false
 }
 
-// An addrList represents a list of network endpoint addresses.
-type addrList []netaddr
+// first returns the first address which satisfies strategy, or if
+// none do, then the first address of any kind.
+func (addrs addrList) first(strategy func(Addr) bool) Addr {
+	for _, addr := range addrs {
+		if strategy(addr) {
+			return addr
+		}
+	}
+	return addrs[0]
+}
 
-func (al addrList) toAddr() Addr {
-	switch len(al) {
-	case 0:
-		return nil
-	case 1:
-		return al[0].toAddr()
-	default:
-		// For now, we'll roughly pick first one without
-		// considering dealing with any preferences such as
-		// DNS TTL, transport path quality, network routing
-		// information.
-		return al[0].toAddr()
+// partition divides an address list into two categories, using a
+// strategy function to assign a boolean label to each address.
+// The first address, and any with a matching label, are returned as
+// primaries, while addresses with the opposite label are returned
+// as fallbacks. For non-empty inputs, primaries is guaranteed to be
+// non-empty.
+func (addrs addrList) partition(strategy func(Addr) bool) (primaries, fallbacks addrList) {
+	var primaryLabel bool
+	for i, addr := range addrs {
+		label := strategy(addr)
+		if i == 0 || label == primaryLabel {
+			primaryLabel = label
+			primaries = append(primaries, addr)
+		} else {
+			fallbacks = append(fallbacks, addr)
+		}
 	}
+	return
 }
 
 var errNoSuitableAddress = errors.New("no suitable address found")
 
-// firstFavoriteAddr returns an address or a list of addresses that
-// 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) {
-	if filter != nil {
-		return firstSupportedAddr(filter, ips, inetaddr)
-	}
-	var (
-		ipv4, ipv6, swap bool
-		list             addrList
-	)
+// filterAddrList applies a filter to a list of IP addresses,
+// yielding a list of Addr objects. Known filters are nil, ipv4only,
+// and ipv6only. It returns every address when the filter is nil.
+// The result contains at least one address when error is nil.
+func filterAddrList(filter func(IPAddr) bool, ips []IPAddr, inetaddr func(IPAddr) Addr) (addrList, error) {
+	var addrs addrList
 	for _, ip := range ips {
-		// We'll take any IP address, but since the dialing
-		// code does not yet try multiple addresses
-		// effectively, prefer to use an IPv4 address if
-		// 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))
-			ipv4 = true
-			if ipv6 {
-				swap = true
-			}
-		} else if ip6 := ipv6only(ip); ip6 != nil && !ipv6 {
-			list = append(list, inetaddr(ip6))
-			ipv6 = true
-		}
-		if ipv4 && ipv6 {
-			if swap {
-				list[0], list[1] = list[1], list[0]
-			}
-			break
+		if filter == nil || filter(ip) {
+			addrs = append(addrs, inetaddr(ip))
 		}
 	}
-	switch len(list) {
-	case 0:
+	if len(addrs) == 0 {
 		return nil, errNoSuitableAddress
-	case 1:
-		return list[0], nil
-	default:
-		return list, nil
-	}
-}
-
-func firstSupportedAddr(filter func(IP) IP, ips []IP, inetaddr func(IP) netaddr) (netaddr, error) {
-	for _, ip := range ips {
-		if ip := filter(ip); ip != nil {
-			return inetaddr(ip), nil
-		}
 	}
-	return nil, errNoSuitableAddress
+	return addrs, nil
 }
 
-// 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",
@@ -153,7 +122,7 @@ func SplitHostPort(hostport string) (host, port string, err error) {
 		// Expect the first ']' just before the last ':'.
 		end := byteIndex(hostport, ']')
 		if end < 0 {
-			err = &AddrError{"missing ']' in address", hostport}
+			err = &AddrError{Err: "missing ']' in address", Addr: hostport}
 			return
 		}
 		switch end + 1 {
@@ -182,11 +151,11 @@ func SplitHostPort(hostport string) (host, port string, err error) {
 		}
 	}
 	if byteIndex(hostport[j:], '[') >= 0 {
-		err = &AddrError{"unexpected '[' in address", hostport}
+		err = &AddrError{Err: "unexpected '[' in address", Addr: hostport}
 		return
 	}
 	if byteIndex(hostport[k:], ']') >= 0 {
-		err = &AddrError{"unexpected ']' in address", hostport}
+		err = &AddrError{Err: "unexpected ']' in address", Addr: hostport}
 		return
 	}
 
@@ -194,15 +163,15 @@ func SplitHostPort(hostport string) (host, port string, err error) {
 	return
 
 missingPort:
-	err = &AddrError{"missing port in address", hostport}
+	err = &AddrError{Err: "missing port in address", Addr: hostport}
 	return
 
 tooManyColons:
-	err = &AddrError{"too many colons in address", hostport}
+	err = &AddrError{Err: "too many colons in address", Addr: hostport}
 	return
 
 missingBrackets:
-	err = &AddrError{"missing brackets in address", hostport}
+	err = &AddrError{Err: "missing brackets in address", Addr: hostport}
 	return
 }
 
@@ -228,17 +197,15 @@ func JoinHostPort(host, port string) string {
 	return host + ":" + port
 }
 
-// resolveInternetAddr resolves addr that is either a literal IP
-// address or a DNS name and returns an internet protocol family
-// address. It returns a list that contains a pair of different
-// address family addresses when addr is a DNS name and the name has
-// multiple address family records. The result contains at least one
-// address when error is nil.
-func resolveInternetAddr(net, addr string, deadline time.Time) (netaddr, error) {
+// internetAddrList resolves addr, which may be a literal IP
+// address or a DNS name, and returns a list of internet protocol
+// family addresses. The result contains at least one address when
+// error is nil.
+func internetAddrList(net, addr string, deadline time.Time) (addrList, 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,43 +224,43 @@ func resolveInternetAddr(net, addr string, deadline time.Time) (netaddr, error)
 	default:
 		return nil, UnknownNetworkError(net)
 	}
-	inetaddr := func(ip IP) netaddr {
+	inetaddr := func(ip IPAddr) Addr {
 		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 addrList{inetaddr(IPAddr{})}, nil
 	}
 	// Try as a literal IP address.
 	var ip IP
 	if ip = parseIPv4(host); ip != nil {
-		return inetaddr(ip), nil
+		return addrList{inetaddr(IPAddr{IP: ip})}, nil
 	}
+	var zone string
 	if ip, zone = parseIPv6(host, true); ip != nil {
-		return inetaddr(ip), nil
+		return addrList{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)
+	return filterAddrList(filter, ips, inetaddr)
 }
 
 func zoneToString(zone int) string {
@@ -303,7 +270,7 @@ func zoneToString(zone int) string {
 	if ifi, err := InterfaceByIndex(zone); err == nil {
 		return ifi.Name
 	}
-	return itod(uint(zone))
+	return uitoa(uint(zone))
 }
 
 func zoneToInt(zone string) int {
diff --git a/src/net/ipsock_plan9.go b/src/net/ipsock_plan9.go
index 94ceea3..9da6ec3 100644
--- a/src/net/ipsock_plan9.go
+++ b/src/net/ipsock_plan9.go
@@ -7,7 +7,6 @@
 package net
 
 import (
-	"errors"
 	"os"
 	"syscall"
 )
@@ -60,15 +59,15 @@ func parsePlan9Addr(s string) (ip IP, iport int, err error) {
 	if i >= 0 {
 		addr = ParseIP(s[:i])
 		if addr == nil {
-			return nil, 0, errors.New("parsing IP failed")
+			return nil, 0, &ParseError{Type: "IP address", Text: s}
 		}
 	}
 	p, _, ok := dtoi(s[i+1:], 0)
 	if !ok {
-		return nil, 0, errors.New("parsing port failed")
+		return nil, 0, &ParseError{Type: "port", Text: s}
 	}
 	if p < 0 || p > 0xFFFF {
-		return nil, 0, &AddrError{"invalid port", string(p)}
+		return nil, 0, &AddrError{Err: "invalid port", Addr: string(p)}
 	}
 	return addr, p, nil
 }
@@ -95,7 +94,7 @@ func readPlan9Addr(proto, filename string) (addr Addr, err error) {
 	case "udp":
 		addr = &UDPAddr{IP: ip, Port: port}
 	default:
-		return nil, errors.New("unknown protocol " + proto)
+		return nil, UnknownNetworkError(proto)
 	}
 	return addr, nil
 }
@@ -141,6 +140,24 @@ func netErr(e error) {
 	if !ok {
 		return
 	}
+	nonNilInterface := func(a Addr) bool {
+		switch a := a.(type) {
+		case *TCPAddr:
+			return a == nil
+		case *UDPAddr:
+			return a == nil
+		case *IPAddr:
+			return a == nil
+		default:
+			return false
+		}
+	}
+	if nonNilInterface(oe.Source) {
+		oe.Source = nil
+	}
+	if nonNilInterface(oe.Addr) {
+		oe.Addr = nil
+	}
 	if pe, ok := oe.Err.(*os.PathError); ok {
 		if _, ok = pe.Err.(syscall.ErrorString); ok {
 			oe.Err = pe.Err
@@ -152,23 +169,23 @@ func dialPlan9(net string, laddr, raddr Addr) (fd *netFD, err error) {
 	defer func() { netErr(err) }()
 	f, dest, proto, name, err := startPlan9(net, raddr)
 	if err != nil {
-		return nil, &OpError{"dial", net, raddr, err}
+		return nil, &OpError{Op: "dial", Net: net, Source: laddr, Addr: raddr, Err: err}
 	}
 	_, err = f.WriteString("connect " + dest)
 	if err != nil {
 		f.Close()
-		return nil, &OpError{"dial", f.Name(), raddr, err}
+		return nil, &OpError{Op: "dial", Net: f.Name(), Source: laddr, Addr: raddr, Err: err}
 	}
 	data, err := os.OpenFile(netdir+"/"+proto+"/"+name+"/data", os.O_RDWR, 0)
 	if err != nil {
 		f.Close()
-		return nil, &OpError{"dial", net, raddr, err}
+		return nil, &OpError{Op: "dial", Net: net, Source: laddr, Addr: raddr, Err: err}
 	}
 	laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local")
 	if err != nil {
 		data.Close()
 		f.Close()
-		return nil, &OpError{"dial", proto, raddr, err}
+		return nil, &OpError{Op: "dial", Net: proto, Source: laddr, Addr: raddr, Err: err}
 	}
 	return newFD(proto, name, f, data, laddr, raddr)
 }
@@ -177,52 +194,52 @@ func listenPlan9(net string, laddr Addr) (fd *netFD, err error) {
 	defer func() { netErr(err) }()
 	f, dest, proto, name, err := startPlan9(net, laddr)
 	if err != nil {
-		return nil, &OpError{"listen", net, laddr, err}
+		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err}
 	}
 	_, err = f.WriteString("announce " + dest)
 	if err != nil {
 		f.Close()
-		return nil, &OpError{"announce", proto, laddr, err}
+		return nil, &OpError{Op: "announce", Net: proto, Source: nil, Addr: laddr, Err: err}
 	}
 	laddr, err = readPlan9Addr(proto, netdir+"/"+proto+"/"+name+"/local")
 	if err != nil {
 		f.Close()
-		return nil, &OpError{Op: "listen", Net: net, Err: err}
+		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err}
 	}
 	return newFD(proto, name, f, nil, laddr, nil)
 }
 
-func (l *netFD) netFD() (*netFD, error) {
-	return newFD(l.proto, l.n, l.ctl, l.data, l.laddr, l.raddr)
+func (fd *netFD) netFD() (*netFD, error) {
+	return newFD(fd.net, fd.n, fd.ctl, fd.data, fd.laddr, fd.raddr)
 }
 
-func (l *netFD) acceptPlan9() (fd *netFD, err error) {
+func (fd *netFD) acceptPlan9() (nfd *netFD, err error) {
 	defer func() { netErr(err) }()
-	if err := l.readLock(); err != nil {
+	if err := fd.readLock(); err != nil {
 		return nil, err
 	}
-	defer l.readUnlock()
-	f, err := os.Open(l.dir + "/listen")
+	defer fd.readUnlock()
+	f, err := os.Open(fd.dir + "/listen")
 	if err != nil {
-		return nil, &OpError{"accept", l.dir + "/listen", l.laddr, err}
+		return nil, &OpError{Op: "accept", Net: fd.dir + "/listen", Source: nil, Addr: fd.laddr, Err: err}
 	}
 	var buf [16]byte
 	n, err := f.Read(buf[:])
 	if err != nil {
 		f.Close()
-		return nil, &OpError{"accept", l.dir + "/listen", l.laddr, err}
+		return nil, &OpError{Op: "accept", Net: fd.dir + "/listen", Source: nil, Addr: fd.laddr, Err: err}
 	}
 	name := string(buf[:n])
-	data, err := os.OpenFile(netdir+"/"+l.proto+"/"+name+"/data", os.O_RDWR, 0)
+	data, err := os.OpenFile(netdir+"/"+fd.net+"/"+name+"/data", os.O_RDWR, 0)
 	if err != nil {
 		f.Close()
-		return nil, &OpError{"accept", l.proto, l.laddr, err}
+		return nil, &OpError{Op: "accept", Net: fd.net, Source: nil, Addr: fd.laddr, Err: err}
 	}
-	raddr, err := readPlan9Addr(l.proto, netdir+"/"+l.proto+"/"+name+"/remote")
+	raddr, err := readPlan9Addr(fd.net, netdir+"/"+fd.net+"/"+name+"/remote")
 	if err != nil {
 		data.Close()
 		f.Close()
-		return nil, &OpError{"accept", l.proto, l.laddr, err}
+		return nil, &OpError{Op: "accept", Net: fd.net, Source: nil, Addr: fd.laddr, Err: err}
 	}
-	return newFD(l.proto, name, f, data, l.laddr, raddr)
+	return newFD(fd.net, name, f, data, fd.laddr, raddr)
 }
diff --git a/src/net/ipsock_posix.go b/src/net/ipsock_posix.go
index f9ebe40..83eaf85 100644
--- a/src/net/ipsock_posix.go
+++ b/src/net/ipsock_posix.go
@@ -9,17 +9,25 @@
 package net
 
 import (
+	"runtime"
 	"syscall"
 	"time"
 )
 
+// BUG(rsc,mikio): On DragonFly BSD and OpenBSD, listening on the
+// "tcp" and "udp" networks does not listen for both IPv4 and IPv6
+// connections. This is due to the fact that IPv4 traffic will not be
+// routed to an IPv6 socket - two separate sockets are required if
+// both address families are to be supported.
+// See inet6(4) for details.
+
 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
 }
@@ -41,20 +49,35 @@ func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
 	var probes = []struct {
 		laddr TCPAddr
 		value int
-		ok    bool
 	}{
 		// IPv6 communication capability
 		{laddr: TCPAddr{IP: ParseIP("::1")}, value: 1},
 		// IPv6 IPv4-mapped address communication capability
 		{laddr: TCPAddr{IP: IPv4(127, 0, 0, 1)}, value: 0},
 	}
+	var supps [2]bool
+	switch runtime.GOOS {
+	case "dragonfly", "openbsd":
+		// Some released versions of DragonFly BSD pretend to
+		// accept IPV6_V6ONLY=0 successfully, but the state
+		// still stays IPV6_V6ONLY=1. Eventually DragonFly BSD
+		// stops preteding, but the transition period would
+		// cause unpredictable behavior and we need to avoid
+		// it.
+		//
+		// OpenBSD also doesn't support IPV6_V6ONLY=0 but it
+		// never pretends to accept IPV6_V6OLY=0. It always
+		// returns an error and we don't need to probe the
+		// capability.
+		probes = probes[:1]
+	}
 
 	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 {
@@ -63,10 +86,10 @@ func probeIPv6Stack() (supportsIPv6, supportsIPv4map bool) {
 		if err := syscall.Bind(s, sa); err != nil {
 			continue
 		}
-		probes[i].ok = true
+		supps[i] = true
 	}
 
-	return probes[0].ok, probes[1].ok
+	return supps[0], supps[1]
 }
 
 // favoriteAddrFamily returns the appropriate address family to
@@ -144,7 +167,7 @@ func ipToSockaddr(family int, ip IP, port int, zone string) (syscall.Sockaddr, e
 			ip = IPv4zero
 		}
 		if ip = ip.To4(); ip == nil {
-			return nil, InvalidAddrError("non-IPv4 address")
+			return nil, &AddrError{Err: "non-IPv4 address", Addr: ip.String()}
 		}
 		sa := new(syscall.SockaddrInet4)
 		for i := 0; i < IPv4len; i++ {
@@ -163,7 +186,7 @@ func ipToSockaddr(family int, ip IP, port int, zone string) (syscall.Sockaddr, e
 			ip = IPv6zero
 		}
 		if ip = ip.To16(); ip == nil {
-			return nil, InvalidAddrError("non-IPv6 address")
+			return nil, &AddrError{Err: "non-IPv6 address", Addr: ip.String()}
 		}
 		sa := new(syscall.SockaddrInet6)
 		for i := 0; i < IPv6len; i++ {
@@ -173,5 +196,5 @@ func ipToSockaddr(family int, ip IP, port int, zone string) (syscall.Sockaddr, e
 		sa.ZoneId = uint32(zoneToInt(zone))
 		return sa, nil
 	}
-	return nil, InvalidAddrError("unexpected socket family")
+	return nil, &AddrError{Err: "invalid address family", Addr: ip.String()}
 }
diff --git a/src/net/ipsock_test.go b/src/net/ipsock_test.go
index 9ecaaec..b36557a 100644
--- a/src/net/ipsock_test.go
+++ b/src/net/ipsock_test.go
@@ -9,185 +9,274 @@ import (
 	"testing"
 )
 
-var testInetaddr = func(ip IP) netaddr { return &TCPAddr{IP: ip, Port: 5682} }
+var testInetaddr = func(ip IPAddr) Addr { return &TCPAddr{IP: ip.IP, Port: 5682, Zone: ip.Zone} }
 
-var firstFavoriteAddrTests = []struct {
-	filter   func(IP) IP
-	ips      []IP
-	inetaddr func(IP) netaddr
-	addr     netaddr
-	err      error
+var addrListTests = []struct {
+	filter    func(IPAddr) bool
+	ips       []IPAddr
+	inetaddr  func(IPAddr) Addr
+	first     Addr
+	primaries addrList
+	fallbacks addrList
+	err       error
 }{
 	{
 		nil,
-		[]IP{
-			IPv4(127, 0, 0, 1),
-			IPv6loopback,
+		[]IPAddr{
+			{IP: IPv4(127, 0, 0, 1)},
+			{IP: IPv6loopback},
 		},
 		testInetaddr,
-		addrList{
-			&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
-			&TCPAddr{IP: IPv6loopback, Port: 5682},
-		},
+		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
+		addrList{&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682}},
+		addrList{&TCPAddr{IP: IPv6loopback, Port: 5682}},
 		nil,
 	},
 	{
 		nil,
-		[]IP{
-			IPv6loopback,
-			IPv4(127, 0, 0, 1),
+		[]IPAddr{
+			{IP: IPv6loopback},
+			{IP: IPv4(127, 0, 0, 1)},
 		},
 		testInetaddr,
-		addrList{
-			&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
-			&TCPAddr{IP: IPv6loopback, Port: 5682},
-		},
+		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
+		addrList{&TCPAddr{IP: IPv6loopback, Port: 5682}},
+		addrList{&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682}},
 		nil,
 	},
 	{
 		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},
+		addrList{
+			&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
+			&TCPAddr{IP: IPv4(192, 168, 0, 1), Port: 5682},
+		},
+		nil,
 		nil,
 	},
 	{
 		nil,
-		[]IP{
-			IPv6loopback,
-			ParseIP("fe80::1"),
+		[]IPAddr{
+			{IP: IPv6loopback},
+			{IP: ParseIP("fe80::1"), Zone: "eth0"},
 		},
 		testInetaddr,
 		&TCPAddr{IP: IPv6loopback, Port: 5682},
+		addrList{
+			&TCPAddr{IP: IPv6loopback, Port: 5682},
+			&TCPAddr{IP: ParseIP("fe80::1"), Port: 5682, Zone: "eth0"},
+		},
+		nil,
 		nil,
 	},
 	{
 		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,
+		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
 		addrList{
 			&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
+			&TCPAddr{IP: IPv4(192, 168, 0, 1), Port: 5682},
+		},
+		addrList{
 			&TCPAddr{IP: IPv6loopback, Port: 5682},
+			&TCPAddr{IP: ParseIP("fe80::1"), Port: 5682, Zone: "eth0"},
 		},
 		nil,
 	},
 	{
 		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,
+		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
 		addrList{
-			&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
 			&TCPAddr{IP: IPv6loopback, Port: 5682},
+			&TCPAddr{IP: ParseIP("fe80::1"), Port: 5682, Zone: "eth0"},
+		},
+		addrList{
+			&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
+			&TCPAddr{IP: IPv4(192, 168, 0, 1), Port: 5682},
 		},
 		nil,
 	},
 	{
 		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,
+		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
 		addrList{
 			&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
+			&TCPAddr{IP: IPv4(192, 168, 0, 1), Port: 5682},
+		},
+		addrList{
 			&TCPAddr{IP: IPv6loopback, Port: 5682},
+			&TCPAddr{IP: ParseIP("fe80::1"), Port: 5682, Zone: "eth0"},
 		},
 		nil,
 	},
 	{
 		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,
+		&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
 		addrList{
-			&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
 			&TCPAddr{IP: IPv6loopback, Port: 5682},
+			&TCPAddr{IP: ParseIP("fe80::1"), Port: 5682, Zone: "eth0"},
+		},
+		addrList{
+			&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682},
+			&TCPAddr{IP: IPv4(192, 168, 0, 1), Port: 5682},
 		},
 		nil,
 	},
 
 	{
 		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},
+		addrList{&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682}},
+		nil,
 		nil,
 	},
 	{
 		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},
+		addrList{&TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5682}},
+		nil,
 		nil,
 	},
 
 	{
 		ipv6only,
-		[]IP{
-			IPv4(127, 0, 0, 1),
-			IPv6loopback,
+		[]IPAddr{
+			{IP: IPv4(127, 0, 0, 1)},
+			{IP: IPv6loopback},
 		},
 		testInetaddr,
 		&TCPAddr{IP: IPv6loopback, Port: 5682},
+		addrList{&TCPAddr{IP: IPv6loopback, Port: 5682}},
+		nil,
 		nil,
 	},
 	{
 		ipv6only,
-		[]IP{
-			IPv6loopback,
-			IPv4(127, 0, 0, 1),
+		[]IPAddr{
+			{IP: IPv6loopback},
+			{IP: IPv4(127, 0, 0, 1)},
 		},
 		testInetaddr,
 		&TCPAddr{IP: IPv6loopback, Port: 5682},
+		addrList{&TCPAddr{IP: IPv6loopback, Port: 5682}},
+		nil,
 		nil,
 	},
 
-	{nil, nil, testInetaddr, nil, errNoSuitableAddress},
+	{nil, nil, testInetaddr, nil, nil, nil, errNoSuitableAddress},
 
-	{ipv4only, nil, testInetaddr, nil, errNoSuitableAddress},
-	{ipv4only, []IP{IPv6loopback}, testInetaddr, nil, errNoSuitableAddress},
+	{ipv4only, nil, testInetaddr, nil, nil, nil, errNoSuitableAddress},
+	{ipv4only, []IPAddr{{IP: IPv6loopback}}, testInetaddr, nil, nil, nil, errNoSuitableAddress},
 
-	{ipv6only, nil, testInetaddr, nil, errNoSuitableAddress},
-	{ipv6only, []IP{IPv4(127, 0, 0, 1)}, testInetaddr, nil, errNoSuitableAddress},
+	{ipv6only, nil, testInetaddr, nil, nil, nil, errNoSuitableAddress},
+	{ipv6only, []IPAddr{{IP: IPv4(127, 0, 0, 1)}}, testInetaddr, nil, nil, nil, errNoSuitableAddress},
 }
 
-func TestFirstFavoriteAddr(t *testing.T) {
+func TestAddrList(t *testing.T) {
 	if !supportsIPv4 || !supportsIPv6 {
-		t.Skip("ipv4 or ipv6 is not supported")
+		t.Skip("both IPv4 and IPv6 are required")
 	}
 
-	for i, tt := range firstFavoriteAddrTests {
-		addr, err := firstFavoriteAddr(tt.filter, tt.ips, tt.inetaddr)
+	for i, tt := range addrListTests {
+		addrs, err := filterAddrList(tt.filter, tt.ips, tt.inetaddr)
 		if err != tt.err {
-			t.Errorf("#%v: got %v; expected %v", i, err, tt.err)
+			t.Errorf("#%v: got %v; want %v", i, err, tt.err)
+		}
+		if tt.err != nil {
+			if len(addrs) != 0 {
+				t.Errorf("#%v: got %v; want 0", i, len(addrs))
+			}
+			continue
+		}
+		first := addrs.first(isIPv4)
+		if !reflect.DeepEqual(first, tt.first) {
+			t.Errorf("#%v: got %v; want %v", i, first, tt.first)
+		}
+		primaries, fallbacks := addrs.partition(isIPv4)
+		if !reflect.DeepEqual(primaries, tt.primaries) {
+			t.Errorf("#%v: got %v; want %v", i, primaries, tt.primaries)
+		}
+		if !reflect.DeepEqual(fallbacks, tt.fallbacks) {
+			t.Errorf("#%v: got %v; want %v", i, fallbacks, tt.fallbacks)
 		}
-		if !reflect.DeepEqual(addr, tt.addr) {
-			t.Errorf("#%v: got %v; expected %v", i, addr, tt.addr)
+		expectedLen := len(primaries) + len(fallbacks)
+		if len(addrs) != expectedLen {
+			t.Errorf("#%v: got %v; want %v", i, len(addrs), expectedLen)
+		}
+	}
+}
+
+func TestAddrListPartition(t *testing.T) {
+	addrs := addrList{
+		&IPAddr{IP: ParseIP("fe80::"), Zone: "eth0"},
+		&IPAddr{IP: ParseIP("fe80::1"), Zone: "eth0"},
+		&IPAddr{IP: ParseIP("fe80::2"), Zone: "eth0"},
+	}
+	cases := []struct {
+		lastByte  byte
+		primaries addrList
+		fallbacks addrList
+	}{
+		{0, addrList{addrs[0]}, addrList{addrs[1], addrs[2]}},
+		{1, addrList{addrs[0], addrs[2]}, addrList{addrs[1]}},
+		{2, addrList{addrs[0], addrs[1]}, addrList{addrs[2]}},
+		{3, addrList{addrs[0], addrs[1], addrs[2]}, nil},
+	}
+	for i, tt := range cases {
+		// Inverting the function's output should not affect the outcome.
+		for _, invert := range []bool{false, true} {
+			primaries, fallbacks := addrs.partition(func(a Addr) bool {
+				ip := a.(*IPAddr).IP
+				return (ip[len(ip)-1] == tt.lastByte) != invert
+			})
+			if !reflect.DeepEqual(primaries, tt.primaries) {
+				t.Errorf("#%v: got %v; want %v", i, primaries, tt.primaries)
+			}
+			if !reflect.DeepEqual(fallbacks, tt.fallbacks) {
+				t.Errorf("#%v: got %v; want %v", i, fallbacks, tt.fallbacks)
+			}
 		}
 	}
 }
diff --git a/src/net/listen_test.go b/src/net/listen_test.go
new file mode 100644
index 0000000..d5627f2
--- /dev/null
+++ b/src/net/listen_test.go
@@ -0,0 +1,685 @@
+// 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.
+
+// +build !plan9
+
+package net
+
+import (
+	"fmt"
+	"os"
+	"runtime"
+	"syscall"
+	"testing"
+)
+
+func (ln *TCPListener) port() string {
+	_, port, err := SplitHostPort(ln.Addr().String())
+	if err != nil {
+		return ""
+	}
+	return port
+}
+
+func (c *UDPConn) port() string {
+	_, port, err := SplitHostPort(c.LocalAddr().String())
+	if err != nil {
+		return ""
+	}
+	return port
+}
+
+var tcpListenerTests = []struct {
+	network string
+	address string
+}{
+	{"tcp", ""},
+	{"tcp", "0.0.0.0"},
+	{"tcp", "::ffff:0.0.0.0"},
+	{"tcp", "::"},
+
+	{"tcp", "127.0.0.1"},
+	{"tcp", "::ffff:127.0.0.1"},
+	{"tcp", "::1"},
+
+	{"tcp4", ""},
+	{"tcp4", "0.0.0.0"},
+	{"tcp4", "::ffff:0.0.0.0"},
+
+	{"tcp4", "127.0.0.1"},
+	{"tcp4", "::ffff:127.0.0.1"},
+
+	{"tcp6", ""},
+	{"tcp6", "::"},
+
+	{"tcp6", "::1"},
+}
+
+// TestTCPListener tests both single and double listen to a test
+// listener with same address family, same listening address and
+// same port.
+func TestTCPListener(t *testing.T) {
+	switch runtime.GOOS {
+	case "plan9":
+		t.Skipf("not supported on %s", runtime.GOOS)
+	}
+
+	for _, tt := range tcpListenerTests {
+		if !testableListenArgs(tt.network, JoinHostPort(tt.address, "0"), "") {
+			t.Logf("skipping %s test", tt.network+" "+tt.address)
+			continue
+		}
+
+		ln1, err := Listen(tt.network, JoinHostPort(tt.address, "0"))
+		if err != nil {
+			t.Fatal(err)
+		}
+		if err := checkFirstListener(tt.network, ln1); err != nil {
+			ln1.Close()
+			t.Fatal(err)
+		}
+		ln2, err := Listen(tt.network, JoinHostPort(tt.address, ln1.(*TCPListener).port()))
+		if err == nil {
+			ln2.Close()
+		}
+		if err := checkSecondListener(tt.network, tt.address, err); err != nil {
+			ln1.Close()
+			t.Fatal(err)
+		}
+		ln1.Close()
+	}
+}
+
+var udpListenerTests = []struct {
+	network string
+	address string
+}{
+	{"udp", ""},
+	{"udp", "0.0.0.0"},
+	{"udp", "::ffff:0.0.0.0"},
+	{"udp", "::"},
+
+	{"udp", "127.0.0.1"},
+	{"udp", "::ffff:127.0.0.1"},
+	{"udp", "::1"},
+
+	{"udp4", ""},
+	{"udp4", "0.0.0.0"},
+	{"udp4", "::ffff:0.0.0.0"},
+
+	{"udp4", "127.0.0.1"},
+	{"udp4", "::ffff:127.0.0.1"},
+
+	{"udp6", ""},
+	{"udp6", "::"},
+
+	{"udp6", "::1"},
+}
+
+// TestUDPListener tests both single and double listen to a test
+// listener with same address family, same listening address and
+// same port.
+func TestUDPListener(t *testing.T) {
+	switch runtime.GOOS {
+	case "plan9":
+		t.Skipf("not supported on %s", runtime.GOOS)
+	}
+
+	for _, tt := range udpListenerTests {
+		if !testableListenArgs(tt.network, JoinHostPort(tt.address, "0"), "") {
+			t.Logf("skipping %s test", tt.network+" "+tt.address)
+			continue
+		}
+
+		c1, err := ListenPacket(tt.network, JoinHostPort(tt.address, "0"))
+		if err != nil {
+			t.Fatal(err)
+		}
+		if err := checkFirstListener(tt.network, c1); err != nil {
+			c1.Close()
+			t.Fatal(err)
+		}
+		c2, err := ListenPacket(tt.network, JoinHostPort(tt.address, c1.(*UDPConn).port()))
+		if err == nil {
+			c2.Close()
+		}
+		if err := checkSecondListener(tt.network, tt.address, err); err != nil {
+			c1.Close()
+			t.Fatal(err)
+		}
+		c1.Close()
+	}
+}
+
+var dualStackTCPListenerTests = []struct {
+	network1, address1 string // first listener
+	network2, address2 string // second listener
+	xerr               error  // expected error value, nil or other
+}{
+	// Test cases and expected results for the attemping 2nd listen on the same port
+	// 1st listen                2nd listen                 darwin  freebsd  linux  openbsd
+	// ------------------------------------------------------------------------------------
+	// "tcp"  ""                 "tcp"  ""                    -        -       -       -
+	// "tcp"  ""                 "tcp"  "0.0.0.0"             -        -       -       -
+	// "tcp"  "0.0.0.0"          "tcp"  ""                    -        -       -       -
+	// ------------------------------------------------------------------------------------
+	// "tcp"  ""                 "tcp"  "[::]"                -        -       -       ok
+	// "tcp"  "[::]"             "tcp"  ""                    -        -       -       ok
+	// "tcp"  "0.0.0.0"          "tcp"  "[::]"                -        -       -       ok
+	// "tcp"  "[::]"             "tcp"  "0.0.0.0"             -        -       -       ok
+	// "tcp"  "[::ffff:0.0.0.0]" "tcp"  "[::]"                -        -       -       ok
+	// "tcp"  "[::]"             "tcp"  "[::ffff:0.0.0.0]"    -        -       -       ok
+	// ------------------------------------------------------------------------------------
+	// "tcp4" ""                 "tcp6" ""                    ok       ok      ok      ok
+	// "tcp6" ""                 "tcp4" ""                    ok       ok      ok      ok
+	// "tcp4" "0.0.0.0"          "tcp6" "[::]"                ok       ok      ok      ok
+	// "tcp6" "[::]"             "tcp4" "0.0.0.0"             ok       ok      ok      ok
+	// ------------------------------------------------------------------------------------
+	// "tcp"  "127.0.0.1"        "tcp"  "[::1]"               ok       ok      ok      ok
+	// "tcp"  "[::1]"            "tcp"  "127.0.0.1"           ok       ok      ok      ok
+	// "tcp4" "127.0.0.1"        "tcp6" "[::1]"               ok       ok      ok      ok
+	// "tcp6" "[::1]"            "tcp4" "127.0.0.1"           ok       ok      ok      ok
+	//
+	// Platform default configurations:
+	// darwin, kernel version 11.3.0
+	//	net.inet6.ip6.v6only=0 (overridable by sysctl or IPV6_V6ONLY option)
+	// freebsd, kernel version 8.2
+	//	net.inet6.ip6.v6only=1 (overridable by sysctl or IPV6_V6ONLY option)
+	// linux, kernel version 3.0.0
+	//	net.ipv6.bindv6only=0 (overridable by sysctl or IPV6_V6ONLY option)
+	// openbsd, kernel version 5.0
+	//	net.inet6.ip6.v6only=1 (overriding is prohibited)
+
+	{"tcp", "", "tcp", "", syscall.EADDRINUSE},
+	{"tcp", "", "tcp", "0.0.0.0", syscall.EADDRINUSE},
+	{"tcp", "0.0.0.0", "tcp", "", syscall.EADDRINUSE},
+
+	{"tcp", "", "tcp", "::", syscall.EADDRINUSE},
+	{"tcp", "::", "tcp", "", syscall.EADDRINUSE},
+	{"tcp", "0.0.0.0", "tcp", "::", syscall.EADDRINUSE},
+	{"tcp", "::", "tcp", "0.0.0.0", syscall.EADDRINUSE},
+	{"tcp", "::ffff:0.0.0.0", "tcp", "::", syscall.EADDRINUSE},
+	{"tcp", "::", "tcp", "::ffff:0.0.0.0", syscall.EADDRINUSE},
+
+	{"tcp4", "", "tcp6", "", nil},
+	{"tcp6", "", "tcp4", "", nil},
+	{"tcp4", "0.0.0.0", "tcp6", "::", nil},
+	{"tcp6", "::", "tcp4", "0.0.0.0", nil},
+
+	{"tcp", "127.0.0.1", "tcp", "::1", nil},
+	{"tcp", "::1", "tcp", "127.0.0.1", nil},
+	{"tcp4", "127.0.0.1", "tcp6", "::1", nil},
+	{"tcp6", "::1", "tcp4", "127.0.0.1", nil},
+}
+
+// TestDualStackTCPListener tests both single and double listen
+// to a test listener with various address families, different
+// listening address and same port.
+func TestDualStackTCPListener(t *testing.T) {
+	switch runtime.GOOS {
+	case "dragonfly", "nacl", "plan9": // re-enable on dragonfly once the new IP control block management has landed
+		t.Skipf("not supported on %s", runtime.GOOS)
+	}
+	if !supportsIPv4 || !supportsIPv6 {
+		t.Skip("both IPv4 and IPv6 are required")
+	}
+
+	for _, tt := range dualStackTCPListenerTests {
+		if !testableListenArgs(tt.network1, JoinHostPort(tt.address1, "0"), "") {
+			t.Logf("skipping %s test", tt.network1+" "+tt.address1)
+			continue
+		}
+
+		if !supportsIPv4map && differentWildcardAddr(tt.address1, tt.address2) {
+			tt.xerr = nil
+		}
+		var firstErr, secondErr error
+		for i := 0; i < 5; i++ {
+			lns, err := newDualStackListener()
+			if err != nil {
+				t.Fatal(err)
+			}
+			port := lns[0].port()
+			for _, ln := range lns {
+				ln.Close()
+			}
+			var ln1 Listener
+			ln1, firstErr = Listen(tt.network1, JoinHostPort(tt.address1, port))
+			if firstErr != nil {
+				continue
+			}
+			if err := checkFirstListener(tt.network1, ln1); err != nil {
+				ln1.Close()
+				t.Fatal(err)
+			}
+			ln2, err := Listen(tt.network2, JoinHostPort(tt.address2, ln1.(*TCPListener).port()))
+			if err == nil {
+				ln2.Close()
+			}
+			if secondErr = checkDualStackSecondListener(tt.network2, tt.address2, err, tt.xerr); secondErr != nil {
+				ln1.Close()
+				continue
+			}
+			ln1.Close()
+			break
+		}
+		if firstErr != nil {
+			t.Error(firstErr)
+		}
+		if secondErr != nil {
+			t.Error(secondErr)
+		}
+	}
+}
+
+var dualStackUDPListenerTests = []struct {
+	network1, address1 string // first listener
+	network2, address2 string // second listener
+	xerr               error  // expected error value, nil or other
+}{
+	{"udp", "", "udp", "", syscall.EADDRINUSE},
+	{"udp", "", "udp", "0.0.0.0", syscall.EADDRINUSE},
+	{"udp", "0.0.0.0", "udp", "", syscall.EADDRINUSE},
+
+	{"udp", "", "udp", "::", syscall.EADDRINUSE},
+	{"udp", "::", "udp", "", syscall.EADDRINUSE},
+	{"udp", "0.0.0.0", "udp", "::", syscall.EADDRINUSE},
+	{"udp", "::", "udp", "0.0.0.0", syscall.EADDRINUSE},
+	{"udp", "::ffff:0.0.0.0", "udp", "::", syscall.EADDRINUSE},
+	{"udp", "::", "udp", "::ffff:0.0.0.0", syscall.EADDRINUSE},
+
+	{"udp4", "", "udp6", "", nil},
+	{"udp6", "", "udp4", "", nil},
+	{"udp4", "0.0.0.0", "udp6", "::", nil},
+	{"udp6", "::", "udp4", "0.0.0.0", nil},
+
+	{"udp", "127.0.0.1", "udp", "::1", nil},
+	{"udp", "::1", "udp", "127.0.0.1", nil},
+	{"udp4", "127.0.0.1", "udp6", "::1", nil},
+	{"udp6", "::1", "udp4", "127.0.0.1", nil},
+}
+
+// TestDualStackUDPListener tests both single and double listen
+// to a test listener with various address families, differnet
+// listening address and same port.
+func TestDualStackUDPListener(t *testing.T) {
+	switch runtime.GOOS {
+	case "dragonfly", "nacl", "plan9": // re-enable on dragonfly once the new IP control block management has landed
+		t.Skipf("not supported on %s", runtime.GOOS)
+	}
+	if !supportsIPv4 || !supportsIPv6 {
+		t.Skip("both IPv4 and IPv6 are required")
+	}
+
+	for _, tt := range dualStackUDPListenerTests {
+		if !testableListenArgs(tt.network1, JoinHostPort(tt.address1, "0"), "") {
+			t.Logf("skipping %s test", tt.network1+" "+tt.address1)
+			continue
+		}
+
+		if !supportsIPv4map && differentWildcardAddr(tt.address1, tt.address2) {
+			tt.xerr = nil
+		}
+		var firstErr, secondErr error
+		for i := 0; i < 5; i++ {
+			cs, err := newDualStackPacketListener()
+			if err != nil {
+				t.Fatal(err)
+			}
+			port := cs[0].port()
+			for _, c := range cs {
+				c.Close()
+			}
+			var c1 PacketConn
+			c1, firstErr = ListenPacket(tt.network1, JoinHostPort(tt.address1, port))
+			if firstErr != nil {
+				continue
+			}
+			if err := checkFirstListener(tt.network1, c1); err != nil {
+				c1.Close()
+				t.Fatal(err)
+			}
+			c2, err := ListenPacket(tt.network2, JoinHostPort(tt.address2, c1.(*UDPConn).port()))
+			if err == nil {
+				c2.Close()
+			}
+			if secondErr = checkDualStackSecondListener(tt.network2, tt.address2, err, tt.xerr); secondErr != nil {
+				c1.Close()
+				continue
+			}
+			c1.Close()
+			break
+		}
+		if firstErr != nil {
+			t.Error(firstErr)
+		}
+		if secondErr != nil {
+			t.Error(secondErr)
+		}
+	}
+}
+
+func differentWildcardAddr(i, j string) bool {
+	if (i == "" || i == "0.0.0.0" || i == "::ffff:0.0.0.0") && (j == "" || j == "0.0.0.0" || j == "::ffff:0.0.0.0") {
+		return false
+	}
+	if i == "[::]" && j == "[::]" {
+		return false
+	}
+	return true
+}
+
+func checkFirstListener(network string, ln interface{}) error {
+	switch network {
+	case "tcp":
+		fd := ln.(*TCPListener).fd
+		if err := checkDualStackAddrFamily(fd); err != nil {
+			return err
+		}
+	case "tcp4":
+		fd := ln.(*TCPListener).fd
+		if fd.family != syscall.AF_INET {
+			return fmt.Errorf("%v got %v; want %v", fd.laddr, fd.family, syscall.AF_INET)
+		}
+	case "tcp6":
+		fd := ln.(*TCPListener).fd
+		if fd.family != syscall.AF_INET6 {
+			return fmt.Errorf("%v got %v; want %v", fd.laddr, fd.family, syscall.AF_INET6)
+		}
+	case "udp":
+		fd := ln.(*UDPConn).fd
+		if err := checkDualStackAddrFamily(fd); err != nil {
+			return err
+		}
+	case "udp4":
+		fd := ln.(*UDPConn).fd
+		if fd.family != syscall.AF_INET {
+			return fmt.Errorf("%v got %v; want %v", fd.laddr, fd.family, syscall.AF_INET)
+		}
+	case "udp6":
+		fd := ln.(*UDPConn).fd
+		if fd.family != syscall.AF_INET6 {
+			return fmt.Errorf("%v got %v; want %v", fd.laddr, fd.family, syscall.AF_INET6)
+		}
+	default:
+		return UnknownNetworkError(network)
+	}
+	return nil
+}
+
+func checkSecondListener(network, address string, err error) error {
+	switch network {
+	case "tcp", "tcp4", "tcp6":
+		if err == nil {
+			return fmt.Errorf("%s should fail", network+" "+address)
+		}
+	case "udp", "udp4", "udp6":
+		if err == nil {
+			return fmt.Errorf("%s should fail", network+" "+address)
+		}
+	default:
+		return UnknownNetworkError(network)
+	}
+	return nil
+}
+
+func checkDualStackSecondListener(network, address string, err, xerr error) error {
+	switch network {
+	case "tcp", "tcp4", "tcp6":
+		if xerr == nil && err != nil || xerr != nil && err == nil {
+			return fmt.Errorf("%s got %v; want %v", network+" "+address, err, xerr)
+		}
+	case "udp", "udp4", "udp6":
+		if xerr == nil && err != nil || xerr != nil && err == nil {
+			return fmt.Errorf("%s got %v; want %v", network+" "+address, err, xerr)
+		}
+	default:
+		return UnknownNetworkError(network)
+	}
+	return nil
+}
+
+func checkDualStackAddrFamily(fd *netFD) error {
+	switch a := fd.laddr.(type) {
+	case *TCPAddr:
+		// If a node under test supports both IPv6 capability
+		// and IPv6 IPv4-mapping capability, we can assume
+		// that the node listens on a wildcard address with an
+		// AF_INET6 socket.
+		if supportsIPv4map && fd.laddr.(*TCPAddr).isWildcard() {
+			if fd.family != syscall.AF_INET6 {
+				return fmt.Errorf("Listen(%s, %v) returns %v; want %v", fd.net, fd.laddr, fd.family, syscall.AF_INET6)
+			}
+		} else {
+			if fd.family != a.family() {
+				return fmt.Errorf("Listen(%s, %v) returns %v; want %v", fd.net, fd.laddr, fd.family, a.family())
+			}
+		}
+	case *UDPAddr:
+		// If a node under test supports both IPv6 capability
+		// and IPv6 IPv4-mapping capability, we can assume
+		// that the node listens on a wildcard address with an
+		// AF_INET6 socket.
+		if supportsIPv4map && fd.laddr.(*UDPAddr).isWildcard() {
+			if fd.family != syscall.AF_INET6 {
+				return fmt.Errorf("ListenPacket(%s, %v) returns %v; want %v", fd.net, fd.laddr, fd.family, syscall.AF_INET6)
+			}
+		} else {
+			if fd.family != a.family() {
+				return fmt.Errorf("ListenPacket(%s, %v) returns %v; want %v", fd.net, fd.laddr, fd.family, a.family())
+			}
+		}
+	default:
+		return fmt.Errorf("unexpected protocol address type: %T", a)
+	}
+	return nil
+}
+
+func TestWildWildcardListener(t *testing.T) {
+	switch runtime.GOOS {
+	case "plan9":
+		t.Skipf("not supported on %s", runtime.GOOS)
+	}
+	if testing.Short() || !*testExternal {
+		t.Skip("avoid external network")
+	}
+
+	defer func() {
+		if p := recover(); p != nil {
+			t.Fatalf("panicked: %v", p)
+		}
+	}()
+
+	if ln, err := Listen("tcp", ""); err == nil {
+		ln.Close()
+	}
+	if ln, err := ListenPacket("udp", ""); err == nil {
+		ln.Close()
+	}
+	if ln, err := ListenTCP("tcp", nil); err == nil {
+		ln.Close()
+	}
+	if ln, err := ListenUDP("udp", nil); err == nil {
+		ln.Close()
+	}
+	if ln, err := ListenIP("ip:icmp", nil); err == nil {
+		ln.Close()
+	}
+}
+
+var ipv4MulticastListenerTests = []struct {
+	net   string
+	gaddr *UDPAddr // see RFC 4727
+}{
+	{"udp", &UDPAddr{IP: IPv4(224, 0, 0, 254), Port: 12345}},
+
+	{"udp4", &UDPAddr{IP: IPv4(224, 0, 0, 254), Port: 12345}},
+}
+
+// TestIPv4MulticastListener tests both single and double listen to a
+// test listener with same address family, same group address and same
+// port.
+func TestIPv4MulticastListener(t *testing.T) {
+	switch runtime.GOOS {
+	case "android", "nacl", "plan9":
+		t.Skipf("not supported on %s", runtime.GOOS)
+	case "solaris":
+		t.Skipf("not supported on solaris, see golang.org/issue/7399")
+	}
+
+	closer := func(cs []*UDPConn) {
+		for _, c := range cs {
+			if c != nil {
+				c.Close()
+			}
+		}
+	}
+
+	for _, ifi := range []*Interface{loopbackInterface(), nil} {
+		// Note that multicast interface assignment by system
+		// is not recommended because it usually relies on
+		// routing stuff for finding out an appropriate
+		// nexthop containing both network and link layer
+		// adjacencies.
+		if ifi == nil && !*testExternal {
+			continue
+		}
+		for _, tt := range ipv4MulticastListenerTests {
+			var err error
+			cs := make([]*UDPConn, 2)
+			if cs[0], err = ListenMulticastUDP(tt.net, ifi, tt.gaddr); err != nil {
+				t.Fatal(err)
+			}
+			if err := checkMulticastListener(cs[0], tt.gaddr.IP); err != nil {
+				closer(cs)
+				t.Fatal(err)
+			}
+			if cs[1], err = ListenMulticastUDP(tt.net, ifi, tt.gaddr); err != nil {
+				closer(cs)
+				t.Fatal(err)
+			}
+			if err := checkMulticastListener(cs[1], tt.gaddr.IP); err != nil {
+				closer(cs)
+				t.Fatal(err)
+			}
+			closer(cs)
+		}
+	}
+}
+
+var ipv6MulticastListenerTests = []struct {
+	net   string
+	gaddr *UDPAddr // see RFC 4727
+}{
+	{"udp", &UDPAddr{IP: ParseIP("ff01::114"), Port: 12345}},
+	{"udp", &UDPAddr{IP: ParseIP("ff02::114"), Port: 12345}},
+	{"udp", &UDPAddr{IP: ParseIP("ff04::114"), Port: 12345}},
+	{"udp", &UDPAddr{IP: ParseIP("ff05::114"), Port: 12345}},
+	{"udp", &UDPAddr{IP: ParseIP("ff08::114"), Port: 12345}},
+	{"udp", &UDPAddr{IP: ParseIP("ff0e::114"), Port: 12345}},
+
+	{"udp6", &UDPAddr{IP: ParseIP("ff01::114"), Port: 12345}},
+	{"udp6", &UDPAddr{IP: ParseIP("ff02::114"), Port: 12345}},
+	{"udp6", &UDPAddr{IP: ParseIP("ff04::114"), Port: 12345}},
+	{"udp6", &UDPAddr{IP: ParseIP("ff05::114"), Port: 12345}},
+	{"udp6", &UDPAddr{IP: ParseIP("ff08::114"), Port: 12345}},
+	{"udp6", &UDPAddr{IP: ParseIP("ff0e::114"), Port: 12345}},
+}
+
+// TestIPv6MulticastListener tests both single and double listen to a
+// test listener with same address family, same group address and same
+// port.
+func TestIPv6MulticastListener(t *testing.T) {
+	switch runtime.GOOS {
+	case "plan9":
+		t.Skipf("not supported on %s", runtime.GOOS)
+	case "solaris":
+		t.Skipf("not supported on solaris, see issue 7399")
+	}
+	if !supportsIPv6 {
+		t.Skip("ipv6 is not supported")
+	}
+	if os.Getuid() != 0 {
+		t.Skip("must be root")
+	}
+
+	closer := func(cs []*UDPConn) {
+		for _, c := range cs {
+			if c != nil {
+				c.Close()
+			}
+		}
+	}
+
+	for _, ifi := range []*Interface{loopbackInterface(), nil} {
+		// Note that multicast interface assignment by system
+		// is not recommended because it usually relies on
+		// routing stuff for finding out an appropriate
+		// nexthop containing both network and link layer
+		// adjacencies.
+		if ifi == nil && (!*testExternal || !*testIPv6) {
+			continue
+		}
+		for _, tt := range ipv6MulticastListenerTests {
+			var err error
+			cs := make([]*UDPConn, 2)
+			if cs[0], err = ListenMulticastUDP(tt.net, ifi, tt.gaddr); err != nil {
+				t.Fatal(err)
+			}
+			if err := checkMulticastListener(cs[0], tt.gaddr.IP); err != nil {
+				closer(cs)
+				t.Fatal(err)
+			}
+			if cs[1], err = ListenMulticastUDP(tt.net, ifi, tt.gaddr); err != nil {
+				closer(cs)
+				t.Fatal(err)
+			}
+			if err := checkMulticastListener(cs[1], tt.gaddr.IP); err != nil {
+				closer(cs)
+				t.Fatal(err)
+			}
+			closer(cs)
+		}
+	}
+}
+
+func checkMulticastListener(c *UDPConn, ip IP) error {
+	if ok, err := multicastRIBContains(ip); err != nil {
+		return err
+	} else if !ok {
+		return fmt.Errorf("%s not found in multicast rib", ip.String())
+	}
+	la := c.LocalAddr()
+	if la, ok := la.(*UDPAddr); !ok || la.Port == 0 {
+		return fmt.Errorf("got %v; want a proper address with non-zero port number", la)
+	}
+	return nil
+}
+
+func multicastRIBContains(ip IP) (bool, error) {
+	switch runtime.GOOS {
+	case "dragonfly", "netbsd", "openbsd", "plan9", "solaris", "windows":
+		return true, nil // not implemented yet
+	case "linux":
+		if runtime.GOARCH == "arm" || runtime.GOARCH == "alpha" {
+			return true, nil // not implemented yet
+		}
+	}
+	ift, err := Interfaces()
+	if err != nil {
+		return false, err
+	}
+	for _, ifi := range ift {
+		ifmat, err := ifi.MulticastAddrs()
+		if err != nil {
+			return false, err
+		}
+		for _, ifma := range ifmat {
+			if ifma.(*IPAddr).IP.Equal(ip) {
+				return true, nil
+			}
+		}
+	}
+	return false, nil
+}
diff --git a/src/net/lookup.go b/src/net/lookup.go
index aeffe6c..9008322 100644
--- a/src/net/lookup.go
+++ b/src/net/lookup.go
@@ -4,7 +4,10 @@
 
 package net
 
-import "time"
+import (
+	"internal/singleflight"
+	"time"
+)
 
 // protocols contains minimal mappings between internet protocol
 // names and numbers for platforms that don't have a complete list of
@@ -22,36 +25,60 @@ var protocols = map[string]int{
 // LookupHost looks up the given host using the local resolver.
 // It returns an array of that host's addresses.
 func LookupHost(host string) (addrs []string, err error) {
+	// Make sure that no matter what we do later, host=="" is rejected.
+	// ParseIP, for example, does accept empty strings.
+	if host == "" {
+		return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host}
+	}
+	if ip := ParseIP(host); ip != nil {
+		return []string{host}, nil
+	}
 	return lookupHost(host)
 }
 
 // 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) {
+	// Make sure that no matter what we do later, host=="" is rejected.
+	// ParseIP, for example, does accept empty strings.
+	if host == "" {
+		return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host}
+	}
+	if ip := ParseIP(host); ip != nil {
+		return []IP{ip}, nil
+	}
+	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
+var lookupGroup singleflight.Group
 
 // 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)
+		return testHookLookupIP(lookupIP, host)
 	})
 	return lookupIPReturn(addrsi, err, shared)
 }
 
 // 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 +86,7 @@ func lookupIPReturn(addrsi interface{}, err error, shared bool) ([]IP, error) {
 }
 
 // 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)
 	}
@@ -76,7 +103,7 @@ func lookupIPDeadline(host string, deadline time.Time) (addrs []IP, err error) {
 	defer t.Stop()
 
 	ch := lookupGroup.DoChan(host, func() (interface{}, error) {
-		return lookupIP(host)
+		return testHookLookupIP(lookupIP, host)
 	})
 
 	select {
@@ -90,12 +117,15 @@ func lookupIPDeadline(host string, deadline time.Time) (addrs []IP, err error) {
 		return nil, errTimeout
 
 	case r := <-ch:
-		return lookupIPReturn(r.v, r.err, r.shared)
+		return lookupIPReturn(r.Val, r.Err, r.Shared)
 	}
 }
 
 // LookupPort looks up the port for the given network and service.
 func LookupPort(network, service string) (port int, err error) {
+	if n, i, ok := dtoi(service, 0); ok && i == len(service) {
+		return n, nil
+	}
 	return lookupPort(network, service)
 }
 
@@ -121,22 +151,22 @@ func LookupSRV(service, proto, name string) (cname string, addrs []*SRV, err err
 }
 
 // LookupMX returns the DNS MX records for the given domain name sorted by preference.
-func LookupMX(name string) (mx []*MX, err error) {
+func LookupMX(name string) (mxs []*MX, err error) {
 	return lookupMX(name)
 }
 
 // LookupNS returns the DNS NS records for the given domain name.
-func LookupNS(name string) (ns []*NS, err error) {
+func LookupNS(name string) (nss []*NS, err error) {
 	return lookupNS(name)
 }
 
 // LookupTXT returns the DNS TXT records for the given domain name.
-func LookupTXT(name string) (txt []string, err error) {
+func LookupTXT(name string) (txts []string, err error) {
 	return lookupTXT(name)
 }
 
 // LookupAddr performs a reverse lookup for the given address, returning a list
 // of names mapping to that address.
-func LookupAddr(addr string) (name []string, err error) {
+func LookupAddr(addr string) (names []string, err error) {
 	return lookupAddr(addr)
 }
diff --git a/src/net/lookup_plan9.go b/src/net/lookup_plan9.go
index b80ac10..c627464 100644
--- a/src/net/lookup_plan9.go
+++ b/src/net/lookup_plan9.go
@@ -101,19 +101,18 @@ func lookupProtocol(name string) (proto int, err error) {
 	if err != nil {
 		return 0, err
 	}
-	unknownProtoError := errors.New("unknown IP protocol specified: " + name)
 	if len(lines) == 0 {
-		return 0, unknownProtoError
+		return 0, UnknownNetworkError(name)
 	}
 	f := getFields(lines[0])
 	if len(f) < 2 {
-		return 0, unknownProtoError
+		return 0, UnknownNetworkError(name)
 	}
 	s := f[1]
 	if n, _, ok := dtoi(s, byteIndex(s, '=')+1); ok {
 		return n, nil
 	}
-	return 0, unknownProtoError
+	return 0, UnknownNetworkError(name)
 }
 
 func lookupHost(host string) (addrs []string, err error) {
@@ -147,14 +146,16 @@ loop:
 	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
@@ -171,7 +172,7 @@ func lookupPort(network, service string) (port int, err error) {
 	if err != nil {
 		return
 	}
-	unknownPortError := &AddrError{"unknown port", network + "/" + service}
+	unknownPortError := &AddrError{Err: "unknown port", Addr: network + "/" + service}
 	if len(lines) == 0 {
 		return 0, unknownPortError
 	}
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 @@ func lookupHost(host string) (addrs []string, err error) {
 	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_test.go b/src/net/lookup_test.go
index 057e132..86957b5 100644
--- a/src/net/lookup_test.go
+++ b/src/net/lookup_test.go
@@ -2,18 +2,34 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// TODO It would be nice to use a mock DNS server, to eliminate
-// external dependencies.
-
 package net
 
 import (
-	"flag"
+	"bytes"
+	"fmt"
 	"strings"
 	"testing"
+	"time"
 )
 
-var testExternal = flag.Bool("external", true, "allow use of external networks during long test")
+func lookupLocalhost(fn func(string) ([]IPAddr, error), host string) ([]IPAddr, error) {
+	switch host {
+	case "localhost":
+		return []IPAddr{
+			{IP: IPv4(127, 0, 0, 1)},
+			{IP: IPv6loopback},
+		}, nil
+	default:
+		return fn(host)
+	}
+}
+
+// The Lookup APIs use various sources such as local database, DNS or
+// mDNS, and may use platform-dependent DNS stub resolver if possible.
+// The APIs accept any of forms for a query; host name in various
+// encodings, UTF-8 encoded net name, domain name, FQDN or absolute
+// FQDN, but the result would be one of the forms and it depends on
+// the circumstances.
 
 var lookupGoogleSRVTests = []struct {
 	service, proto, name string
@@ -21,17 +37,30 @@ var lookupGoogleSRVTests = []struct {
 }{
 	{
 		"xmpp-server", "tcp", "google.com",
-		".google.com", ".google.com",
+		"google.com", "google.com",
+	},
+	{
+		"xmpp-server", "tcp", "google.com.",
+		"google.com", "google.com",
+	},
+
+	// non-standard back door
+	{
+		"", "", "_xmpp-server._tcp.google.com",
+		"google.com", "google.com",
 	},
 	{
-		"", "", "_xmpp-server._tcp.google.com", // non-standard back door
-		".google.com", ".google.com",
+		"", "", "_xmpp-server._tcp.google.com.",
+		"google.com", "google.com",
 	},
 }
 
 func TestLookupGoogleSRV(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
+		t.Skip("avoid external network")
+	}
+	if !supportsIPv4 || !*testIPv4 {
+		t.Skip("IPv4 is required")
 	}
 
 	for _, tt := range lookupGoogleSRVTests {
@@ -42,90 +71,128 @@ func TestLookupGoogleSRV(t *testing.T) {
 		if len(srvs) == 0 {
 			t.Error("got no record")
 		}
-		if !strings.Contains(cname, tt.cname) {
-			t.Errorf("got %q; want %q", cname, tt.cname)
+		if !strings.HasSuffix(cname, tt.cname) && !strings.HasSuffix(cname, tt.cname+".") {
+			t.Errorf("got %s; want %s", cname, tt.cname)
 		}
 		for _, srv := range srvs {
-			if !strings.Contains(srv.Target, tt.target) {
-				t.Errorf("got %v; want a record containing %q", srv, tt.target)
+			if !strings.HasSuffix(srv.Target, tt.target) && !strings.HasSuffix(srv.Target, tt.target+".") {
+				t.Errorf("got %v; want a record containing %s", srv, tt.target)
 			}
 		}
 	}
 }
 
+var lookupGmailMXTests = []struct {
+	name, host string
+}{
+	{"gmail.com", "google.com"},
+	{"gmail.com.", "google.com"},
+}
+
 func TestLookupGmailMX(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
+		t.Skip("avoid external network")
 	}
-
-	mxs, err := LookupMX("gmail.com")
-	if err != nil {
-		t.Fatal(err)
-	}
-	if len(mxs) == 0 {
-		t.Error("got no record")
+	if !supportsIPv4 || !*testIPv4 {
+		t.Skip("IPv4 is required")
 	}
-	for _, mx := range mxs {
-		if !strings.Contains(mx.Host, ".google.com") {
-			t.Errorf("got %v; want a record containing .google.com.", mx)
+
+	for _, tt := range lookupGmailMXTests {
+		mxs, err := LookupMX(tt.name)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if len(mxs) == 0 {
+			t.Error("got no record")
+		}
+		for _, mx := range mxs {
+			if !strings.HasSuffix(mx.Host, tt.host) && !strings.HasSuffix(mx.Host, tt.host+".") {
+				t.Errorf("got %v; want a record containing %s", mx, tt.host)
+			}
 		}
 	}
 }
 
+var lookupGmailNSTests = []struct {
+	name, host string
+}{
+	{"gmail.com", "google.com"},
+	{"gmail.com.", "google.com"},
+}
+
 func TestLookupGmailNS(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
+		t.Skip("avoid external network")
 	}
-
-	nss, err := LookupNS("gmail.com")
-	if err != nil {
-		t.Fatal(err)
-	}
-	if len(nss) == 0 {
-		t.Error("got no record")
+	if !supportsIPv4 || !*testIPv4 {
+		t.Skip("IPv4 is required")
 	}
-	for _, ns := range nss {
-		if !strings.Contains(ns.Host, ".google.com") {
-			t.Errorf("got %v; want a record containing .google.com.", ns)
+
+	for _, tt := range lookupGmailNSTests {
+		nss, err := LookupNS(tt.name)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if len(nss) == 0 {
+			t.Error("got no record")
+		}
+		for _, ns := range nss {
+			if !strings.HasSuffix(ns.Host, tt.host) && !strings.HasSuffix(ns.Host, tt.host+".") {
+				t.Errorf("got %v; want a record containing %s", ns, tt.host)
+			}
 		}
 	}
 }
 
+var lookupGmailTXTTests = []struct {
+	name, txt, host string
+}{
+	{"gmail.com", "spf", "google.com"},
+	{"gmail.com.", "spf", "google.com"},
+}
+
 func TestLookupGmailTXT(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
+		t.Skip("avoid external network")
 	}
-
-	txts, err := LookupTXT("gmail.com")
-	if err != nil {
-		t.Fatal(err)
+	if !supportsIPv4 || !*testIPv4 {
+		t.Skip("IPv4 is required")
 	}
-	if len(txts) == 0 {
-		t.Error("got no record")
-	}
-	for _, txt := range txts {
-		if !strings.Contains(txt, "spf") {
-			t.Errorf("got %q; want a spf record", txt)
+
+	for _, tt := range lookupGmailTXTTests {
+		txts, err := LookupTXT(tt.name)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if len(txts) == 0 {
+			t.Error("got no record")
+		}
+		for _, txt := range txts {
+			if !strings.Contains(txt, tt.txt) || (!strings.HasSuffix(txt, tt.host) && !strings.HasSuffix(txt, tt.host+".")) {
+				t.Errorf("got %s; want a record containing %s, %s", txt, tt.txt, tt.host)
+			}
 		}
 	}
 }
 
-var lookupGooglePublicDNSAddrs = []struct {
-	addr string
-	name string
+var lookupGooglePublicDNSAddrTests = []struct {
+	addr, name string
 }{
-	{"8.8.8.8", ".google.com."},
-	{"8.8.4.4", ".google.com."},
-	{"2001:4860:4860::8888", ".google.com."},
-	{"2001:4860:4860::8844", ".google.com."},
+	{"8.8.8.8", ".google.com"},
+	{"8.8.4.4", ".google.com"},
+	{"2001:4860:4860::8888", ".google.com"},
+	{"2001:4860:4860::8844", ".google.com"},
 }
 
 func TestLookupGooglePublicDNSAddr(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
+		t.Skip("avoid external network")
+	}
+	if !supportsIPv4 || !supportsIPv6 || !*testIPv4 || !*testIPv6 {
+		t.Skip("both IPv4 and IPv6 are required")
 	}
 
-	for _, tt := range lookupGooglePublicDNSAddrs {
+	for _, tt := range lookupGooglePublicDNSAddrTests {
 		names, err := LookupAddr(tt.addr)
 		if err != nil {
 			t.Fatal(err)
@@ -134,61 +201,97 @@ func TestLookupGooglePublicDNSAddr(t *testing.T) {
 			t.Error("got no record")
 		}
 		for _, name := range names {
-			if !strings.HasSuffix(name, tt.name) {
-				t.Errorf("got %q; want a record containing %q", name, tt.name)
+			if !strings.HasSuffix(name, tt.name) && !strings.HasSuffix(name, tt.name+".") {
+				t.Errorf("got %s; want a record containing %s", name, tt.name)
 			}
 		}
 	}
 }
 
+var lookupIANACNAMETests = []struct {
+	name, cname string
+}{
+	{"www.iana.org", "icann.org"},
+	{"www.iana.org.", "icann.org"},
+}
+
 func TestLookupIANACNAME(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
+		t.Skip("avoid external network")
 	}
-
-	cname, err := LookupCNAME("www.iana.org")
-	if err != nil {
-		t.Fatal(err)
+	if !supportsIPv4 || !*testIPv4 {
+		t.Skip("IPv4 is required")
 	}
-	if !strings.HasSuffix(cname, ".icann.org.") {
-		t.Errorf("got %q; want a record containing .icann.org.", cname)
+
+	for _, tt := range lookupIANACNAMETests {
+		cname, err := LookupCNAME(tt.name)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if !strings.HasSuffix(cname, tt.cname) && !strings.HasSuffix(cname, tt.cname+".") {
+			t.Errorf("got %s; want a record containing %s", cname, tt.cname)
+		}
 	}
 }
 
+var lookupGoogleHostTests = []struct {
+	name string
+}{
+	{"google.com"},
+	{"google.com."},
+}
+
 func TestLookupGoogleHost(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
+		t.Skip("avoid external network")
 	}
-
-	addrs, err := LookupHost("google.com")
-	if err != nil {
-		t.Fatal(err)
-	}
-	if len(addrs) == 0 {
-		t.Error("got no record")
+	if !supportsIPv4 || !*testIPv4 {
+		t.Skip("IPv4 is required")
 	}
-	for _, addr := range addrs {
-		if ParseIP(addr) == nil {
-			t.Errorf("got %q; want a literal ip address", addr)
+
+	for _, tt := range lookupGoogleHostTests {
+		addrs, err := LookupHost(tt.name)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if len(addrs) == 0 {
+			t.Error("got no record")
+		}
+		for _, addr := range addrs {
+			if ParseIP(addr) == nil {
+				t.Errorf("got %q; want a literal IP address", addr)
+			}
 		}
 	}
 }
 
+var lookupGoogleIPTests = []struct {
+	name string
+}{
+	{"google.com"},
+	{"google.com."},
+}
+
 func TestLookupGoogleIP(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
+		t.Skip("avoid external network")
 	}
-
-	ips, err := LookupIP("google.com")
-	if err != nil {
-		t.Fatal(err)
-	}
-	if len(ips) == 0 {
-		t.Error("got no record")
+	if !supportsIPv4 || !*testIPv4 {
+		t.Skip("IPv4 is required")
 	}
-	for _, ip := range ips {
-		if ip.To4() == nil && ip.To16() == nil {
-			t.Errorf("got %v; want an ip address", ip)
+
+	for _, tt := range lookupGoogleIPTests {
+		ips, err := LookupIP(tt.name)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if len(ips) == 0 {
+			t.Error("got no record")
+		}
+		for _, ip := range ips {
+			if ip.To4() == nil && ip.To16() == nil {
+				t.Errorf("got %v; want an IP address", ip)
+			}
 		}
 	}
 }
@@ -229,3 +332,172 @@ func TestReverseAddress(t *testing.T) {
 		}
 	}
 }
+
+func TestLookupIPDeadline(t *testing.T) {
+	if !*testDNSFlood {
+		t.Skip("test disabled; use -dnsflood to enable")
+	}
+
+	const N = 5000
+	const timeout = 3 * time.Second
+	c := make(chan error, 2*N)
+	for i := 0; i < N; i++ {
+		name := fmt.Sprintf("%d.net-test.golang.org", i)
+		go func() {
+			_, err := lookupIPDeadline(name, time.Now().Add(timeout/2))
+			c <- err
+		}()
+		go func() {
+			_, err := lookupIPDeadline(name, time.Now().Add(timeout))
+			c <- err
+		}()
+	}
+	qstats := struct {
+		succeeded, failed         int
+		timeout, temporary, other int
+		unknown                   int
+	}{}
+	deadline := time.After(timeout + time.Second)
+	for i := 0; i < 2*N; i++ {
+		select {
+		case <-deadline:
+			t.Fatal("deadline exceeded")
+		case err := <-c:
+			switch err := err.(type) {
+			case nil:
+				qstats.succeeded++
+			case Error:
+				qstats.failed++
+				if err.Timeout() {
+					qstats.timeout++
+				}
+				if err.Temporary() {
+					qstats.temporary++
+				}
+				if !err.Timeout() && !err.Temporary() {
+					qstats.other++
+				}
+			default:
+				qstats.failed++
+				qstats.unknown++
+			}
+		}
+	}
+
+	// A high volume of DNS queries for sub-domain of golang.org
+	// would be coordinated by authoritative or recursive server,
+	// or stub resolver which implements query-response rate
+	// limitation, so we can expect some query successes and more
+	// failures including timeout, temporary and other here.
+	// As a rule, unknown must not be shown but it might possibly
+	// happen due to issue 4856 for now.
+	t.Logf("%v succeeded, %v failed (%v timeout, %v temporary, %v other, %v unknown)", qstats.succeeded, qstats.failed, qstats.timeout, qstats.temporary, qstats.other, qstats.unknown)
+}
+
+func TestLookupDots(t *testing.T) {
+	if testing.Short() || !*testExternal {
+		t.Skipf("skipping external network test")
+	}
+
+	fixup := forceGoDNS()
+	defer fixup()
+	testDots(t, "go")
+
+	if forceCgoDNS() {
+		testDots(t, "cgo")
+	}
+}
+
+func testDots(t *testing.T, mode string) {
+	names, err := LookupAddr("8.8.8.8") // Google dns server
+	if err != nil {
+		t.Errorf("LookupAddr(8.8.8.8): %v (mode=%v)", err, mode)
+	} else {
+		for _, name := range names {
+			if !strings.HasSuffix(name, ".google.com.") {
+				t.Errorf("LookupAddr(8.8.8.8) = %v, want names ending in .google.com. with trailing dot (mode=%v)", names, mode)
+				break
+			}
+		}
+	}
+
+	cname, err := LookupCNAME("www.mit.edu")
+	if err != nil || !strings.HasSuffix(cname, ".") {
+		t.Errorf("LookupCNAME(www.mit.edu) = %v, %v, want cname ending in . with trailing dot (mode=%v)", cname, err, mode)
+	}
+
+	mxs, err := LookupMX("google.com")
+	if err != nil {
+		t.Errorf("LookupMX(google.com): %v (mode=%v)", err, mode)
+	} else {
+		for _, mx := range mxs {
+			if !strings.HasSuffix(mx.Host, ".google.com.") {
+				t.Errorf("LookupMX(google.com) = %v, want names ending in .google.com. with trailing dot (mode=%v)", mxString(mxs), mode)
+				break
+			}
+		}
+	}
+
+	nss, err := LookupNS("google.com")
+	if err != nil {
+		t.Errorf("LookupNS(google.com): %v (mode=%v)", err, mode)
+	} else {
+		for _, ns := range nss {
+			if !strings.HasSuffix(ns.Host, ".google.com.") {
+				t.Errorf("LookupNS(google.com) = %v, want names ending in .google.com. with trailing dot (mode=%v)", nsString(nss), mode)
+				break
+			}
+		}
+	}
+
+	cname, srvs, err := LookupSRV("xmpp-server", "tcp", "google.com")
+	if err != nil {
+		t.Errorf("LookupSRV(xmpp-server, tcp, google.com): %v (mode=%v)", err, mode)
+	} else {
+		if !strings.HasSuffix(cname, ".google.com.") {
+			t.Errorf("LookupSRV(xmpp-server, tcp, google.com) returned cname=%v, want name ending in .google.com. with trailing dot (mode=%v)", cname, mode)
+		}
+		for _, srv := range srvs {
+			if !strings.HasSuffix(srv.Target, ".google.com.") {
+				t.Errorf("LookupSRV(xmpp-server, tcp, google.com) returned addrs=%v, want names ending in .google.com. with trailing dot (mode=%v)", srvString(srvs), mode)
+				break
+			}
+		}
+	}
+}
+
+func mxString(mxs []*MX) string {
+	var buf bytes.Buffer
+	sep := ""
+	fmt.Fprintf(&buf, "[")
+	for _, mx := range mxs {
+		fmt.Fprintf(&buf, "%s%s:%d", sep, mx.Host, mx.Pref)
+		sep = " "
+	}
+	fmt.Fprintf(&buf, "]")
+	return buf.String()
+}
+
+func nsString(nss []*NS) string {
+	var buf bytes.Buffer
+	sep := ""
+	fmt.Fprintf(&buf, "[")
+	for _, ns := range nss {
+		fmt.Fprintf(&buf, "%s%s", sep, ns.Host)
+		sep = " "
+	}
+	fmt.Fprintf(&buf, "]")
+	return buf.String()
+}
+
+func srvString(srvs []*SRV) string {
+	var buf bytes.Buffer
+	sep := ""
+	fmt.Fprintf(&buf, "[")
+	for _, srv := range srvs {
+		fmt.Fprintf(&buf, "%s%s:%d:%d:%d", sep, srv.Target, srv.Port, srv.Priority, srv.Weight)
+		sep = " "
+	}
+	fmt.Fprintf(&buf, "]")
+	return buf.String()
+}
diff --git a/src/net/lookup_unix.go b/src/net/lookup_unix.go
index a545784..a64da8b 100644
--- a/src/net/lookup_unix.go
+++ b/src/net/lookup_unix.go
@@ -6,10 +6,7 @@
 
 package net
 
-import (
-	"errors"
-	"sync"
-)
+import "sync"
 
 var onceReadProtocols sync.Once
 
@@ -43,126 +40,120 @@ func readProtocols() {
 
 // lookupProtocol looks up IP protocol name in /etc/protocols and
 // returns correspondent protocol number.
-func lookupProtocol(name string) (proto int, err error) {
+func lookupProtocol(name string) (int, error) {
 	onceReadProtocols.Do(readProtocols)
 	proto, found := protocols[name]
 	if !found {
-		return 0, errors.New("unknown IP protocol specified: " + name)
+		return 0, &AddrError{Err: "unknown IP protocol specified", Addr: name}
 	}
-	return
+	return proto, nil
 }
 
 func lookupHost(host string) (addrs []string, err error) {
-	addrs, err, ok := cgoLookupHost(host)
-	if !ok {
-		addrs, err = goLookupHost(host)
+	order := systemConf().hostLookupOrder(host)
+	if order == hostLookupCgo {
+		if addrs, err, ok := cgoLookupHost(host); ok {
+			return addrs, err
+		}
+		// cgo not available (or netgo); fall back to Go's DNS resolver
+		order = hostLookupFilesDNS
 	}
-	return
+	return goLookupHostOrder(host, order)
 }
 
-func lookupIP(host string) (addrs []IP, err error) {
-	addrs, err, ok := cgoLookupIP(host)
-	if !ok {
-		addrs, err = goLookupIP(host)
+func lookupIP(host string) (addrs []IPAddr, err error) {
+	order := systemConf().hostLookupOrder(host)
+	if order == hostLookupCgo {
+		if addrs, err, ok := cgoLookupIP(host); ok {
+			return addrs, err
+		}
+		// cgo not available (or netgo); fall back to Go's DNS resolver
+		order = hostLookupFilesDNS
 	}
-	return
+	return goLookupIPOrder(host, order)
 }
 
-func lookupPort(network, service string) (port int, err error) {
-	port, err, ok := cgoLookupPort(network, service)
-	if !ok {
-		port, err = goLookupPort(network, service)
+func lookupPort(network, service string) (int, error) {
+	if systemConf().canUseCgo() {
+		if port, err, ok := cgoLookupPort(network, service); ok {
+			return port, err
+		}
 	}
-	return
+	return goLookupPort(network, service)
 }
 
-func lookupCNAME(name string) (cname string, err error) {
-	cname, err, ok := cgoLookupCNAME(name)
-	if !ok {
-		cname, err = goLookupCNAME(name)
+func lookupCNAME(name string) (string, error) {
+	if systemConf().canUseCgo() {
+		if cname, err, ok := cgoLookupCNAME(name); ok {
+			return cname, err
+		}
 	}
-	return
+	return goLookupCNAME(name)
 }
 
-func lookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) {
+func lookupSRV(service, proto, name string) (string, []*SRV, error) {
 	var target string
 	if service == "" && proto == "" {
 		target = name
 	} else {
 		target = "_" + service + "._" + proto + "." + name
 	}
-	var records []dnsRR
-	cname, records, err = lookup(target, dnsTypeSRV)
+	cname, rrs, err := lookup(target, dnsTypeSRV)
 	if err != nil {
-		return
+		return "", nil, err
 	}
-	addrs = make([]*SRV, len(records))
-	for i, rr := range records {
-		r := rr.(*dnsRR_SRV)
-		addrs[i] = &SRV{r.Target, r.Port, r.Priority, r.Weight}
+	srvs := make([]*SRV, len(rrs))
+	for i, rr := range rrs {
+		rr := rr.(*dnsRR_SRV)
+		srvs[i] = &SRV{Target: rr.Target, Port: rr.Port, Priority: rr.Priority, Weight: rr.Weight}
 	}
-	byPriorityWeight(addrs).sort()
-	return
+	byPriorityWeight(srvs).sort()
+	return cname, srvs, nil
 }
 
-func lookupMX(name string) (mx []*MX, err error) {
-	_, records, err := lookup(name, dnsTypeMX)
+func lookupMX(name string) ([]*MX, error) {
+	_, rrs, err := lookup(name, dnsTypeMX)
 	if err != nil {
-		return
+		return nil, err
 	}
-	mx = make([]*MX, len(records))
-	for i, rr := range records {
-		r := rr.(*dnsRR_MX)
-		mx[i] = &MX{r.Mx, r.Pref}
+	mxs := make([]*MX, len(rrs))
+	for i, rr := range rrs {
+		rr := rr.(*dnsRR_MX)
+		mxs[i] = &MX{Host: rr.Mx, Pref: rr.Pref}
 	}
-	byPref(mx).sort()
-	return
+	byPref(mxs).sort()
+	return mxs, nil
 }
 
-func lookupNS(name string) (ns []*NS, err error) {
-	_, records, err := lookup(name, dnsTypeNS)
+func lookupNS(name string) ([]*NS, error) {
+	_, rrs, err := lookup(name, dnsTypeNS)
 	if err != nil {
-		return
+		return nil, err
 	}
-	ns = make([]*NS, len(records))
-	for i, r := range records {
-		r := r.(*dnsRR_NS)
-		ns[i] = &NS{r.Ns}
+	nss := make([]*NS, len(rrs))
+	for i, rr := range rrs {
+		nss[i] = &NS{Host: rr.(*dnsRR_NS).Ns}
 	}
-	return
+	return nss, nil
 }
 
-func lookupTXT(name string) (txt []string, err error) {
-	_, records, err := lookup(name, dnsTypeTXT)
+func lookupTXT(name string) ([]string, error) {
+	_, rrs, err := lookup(name, dnsTypeTXT)
 	if err != nil {
-		return
+		return nil, err
 	}
-	txt = make([]string, len(records))
-	for i, r := range records {
-		txt[i] = r.(*dnsRR_TXT).Txt
+	txts := make([]string, len(rrs))
+	for i, rr := range rrs {
+		txts[i] = rr.(*dnsRR_TXT).Txt
 	}
-	return
+	return txts, nil
 }
 
-func lookupAddr(addr string) (name []string, err error) {
-	name = lookupStaticAddr(addr)
-	if len(name) > 0 {
-		return
-	}
-	var arpa string
-	arpa, err = reverseaddr(addr)
-	if err != nil {
-		return
-	}
-	var records []dnsRR
-	_, records, err = lookup(arpa, dnsTypePTR)
-	if err != nil {
-		return
-	}
-	name = make([]string, len(records))
-	for i := range records {
-		r := records[i].(*dnsRR_PTR)
-		name[i] = r.Ptr
+func lookupAddr(addr string) ([]string, error) {
+	if systemConf().canUseCgo() {
+		if ptrs, err, ok := cgoLookupPTR(addr); ok {
+			return ptrs, err
+		}
 	}
-	return
+	return goLookupPTR(addr)
 }
diff --git a/src/net/lookup_windows.go b/src/net/lookup_windows.go
index 6a925b0..1b6d392 100644
--- a/src/net/lookup_windows.go
+++ b/src/net/lookup_windows.go
@@ -19,13 +19,13 @@ var (
 func getprotobyname(name string) (proto int, err error) {
 	p, err := syscall.GetProtoByName(name)
 	if err != nil {
-		return 0, os.NewSyscallError("GetProtoByName", err)
+		return 0, os.NewSyscallError("getorotobyname", err)
 	}
 	return int(p.Proto), nil
 }
 
 // lookupProtocol looks up IP protocol name and returns correspondent protocol number.
-func lookupProtocol(name string) (proto int, err error) {
+func lookupProtocol(name string) (int, error) {
 	// GetProtoByName return value is stored in thread local storage.
 	// Start new os thread before the call to prevent races.
 	type result struct {
@@ -46,47 +46,48 @@ func lookupProtocol(name string) (proto int, err error) {
 		if proto, ok := protocols[name]; ok {
 			return proto, nil
 		}
+		r.err = &DNSError{Err: r.err.Error(), Name: name}
 	}
 	return r.proto, r.err
 }
 
-func lookupHost(name string) (addrs []string, err error) {
+func lookupHost(name string) ([]string, error) {
 	ips, err := LookupIP(name)
 	if err != nil {
-		return
+		return nil, err
 	}
-	addrs = make([]string, 0, len(ips))
+	addrs := make([]string, 0, len(ips))
 	for _, ip := range ips {
 		addrs = append(addrs, ip.String())
 	}
-	return
+	return addrs, nil
 }
 
-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 {
-		return nil, os.NewSyscallError("GetHostByName", err)
+		return nil, os.NewSyscallError("gethostbyname", err)
 	}
 	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.
-		return nil, os.NewSyscallError("LookupIP", syscall.EWINDOWS)
+		return nil, syscall.EWINDOWS
 	}
 	return addrs, nil
 }
 
-func oldLookupIP(name string) (addrs []IP, err error) {
+func oldLookupIP(name string) ([]IPAddr, 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 +100,13 @@ func oldLookupIP(name string) (addrs []IP, err error) {
 		ch <- result{addrs: addrs, err: err}
 	}()
 	r := <-ch
+	if r.err != nil {
+		r.err = &DNSError{Err: r.err.Error(), Name: name}
+	}
 	return r.addrs, r.err
 }
 
-func newLookupIP(name string) (addrs []IP, err error) {
+func newLookupIP(name string) ([]IPAddr, error) {
 	acquireThread()
 	defer releaseThread()
 	hints := syscall.AddrinfoW{
@@ -113,27 +117,28 @@ func newLookupIP(name string) (addrs []IP, err error) {
 	var result *syscall.AddrinfoW
 	e := syscall.GetAddrInfoW(syscall.StringToUTF16Ptr(name), nil, &hints, &result)
 	if e != nil {
-		return nil, os.NewSyscallError("GetAddrInfoW", e)
+		return nil, &DNSError{Err: os.NewSyscallError("getaddrinfow", e).Error(), Name: name}
 	}
 	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)
+			return nil, &DNSError{Err: syscall.EWINDOWS.Error(), Name: name}
 		}
 	}
 	return addrs, nil
 }
 
-func getservbyname(network, service string) (port int, err error) {
+func getservbyname(network, service string) (int, error) {
 	acquireThread()
 	defer releaseThread()
 	switch network {
@@ -144,12 +149,12 @@ func getservbyname(network, service string) (port int, err error) {
 	}
 	s, err := syscall.GetServByName(service, network)
 	if err != nil {
-		return 0, os.NewSyscallError("GetServByName", err)
+		return 0, os.NewSyscallError("getservbyname", err)
 	}
 	return int(syscall.Ntohs(s.Port)), nil
 }
 
-func oldLookupPort(network, service string) (port int, err error) {
+func oldLookupPort(network, service string) (int, error) {
 	// GetServByName return value is stored in thread local storage.
 	// Start new os thread before the call to prevent races.
 	type result struct {
@@ -166,10 +171,13 @@ func oldLookupPort(network, service string) (port int, err error) {
 		ch <- result{port: port, err: err}
 	}()
 	r := <-ch
+	if r.err != nil {
+		r.err = &DNSError{Err: r.err.Error(), Name: network + "/" + service}
+	}
 	return r.port, r.err
 }
 
-func newLookupPort(network, service string) (port int, err error) {
+func newLookupPort(network, service string) (int, error) {
 	acquireThread()
 	defer releaseThread()
 	var stype int32
@@ -187,11 +195,11 @@ func newLookupPort(network, service string) (port int, err error) {
 	var result *syscall.AddrinfoW
 	e := syscall.GetAddrInfoW(nil, syscall.StringToUTF16Ptr(service), &hints, &result)
 	if e != nil {
-		return 0, os.NewSyscallError("GetAddrInfoW", e)
+		return 0, &DNSError{Err: os.NewSyscallError("getaddrinfow", e).Error(), Name: network + "/" + service}
 	}
 	defer syscall.FreeAddrInfoW(result)
 	if result == nil {
-		return 0, os.NewSyscallError("LookupPort", syscall.EINVAL)
+		return 0, &DNSError{Err: syscall.EINVAL.Error(), Name: network + "/" + service}
 	}
 	addr := unsafe.Pointer(result.Addr)
 	switch result.Family {
@@ -202,10 +210,10 @@ func newLookupPort(network, service string) (port int, err error) {
 		a := (*syscall.RawSockaddrInet6)(addr)
 		return int(syscall.Ntohs(a.Port)), nil
 	}
-	return 0, os.NewSyscallError("LookupPort", syscall.EINVAL)
+	return 0, &DNSError{Err: syscall.EINVAL.Error(), Name: network + "/" + service}
 }
 
-func lookupCNAME(name string) (cname string, err error) {
+func lookupCNAME(name string) (string, error) {
 	acquireThread()
 	defer releaseThread()
 	var r *syscall.DNSRecord
@@ -219,16 +227,16 @@ func lookupCNAME(name string) (cname string, err error) {
 		return name, nil
 	}
 	if e != nil {
-		return "", os.NewSyscallError("LookupCNAME", e)
+		return "", &DNSError{Err: os.NewSyscallError("dnsquery", e).Error(), Name: name}
 	}
 	defer syscall.DnsRecordListFree(r, 1)
 
 	resolved := resolveCNAME(syscall.StringToUTF16Ptr(name), r)
-	cname = syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(resolved))[:]) + "."
-	return
+	cname := syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(resolved))[:]) + "."
+	return cname, nil
 }
 
-func lookupSRV(service, proto, name string) (cname string, addrs []*SRV, err error) {
+func lookupSRV(service, proto, name string) (string, []*SRV, error) {
 	acquireThread()
 	defer releaseThread()
 	var target string
@@ -240,78 +248,78 @@ func lookupSRV(service, proto, name string) (cname string, addrs []*SRV, err err
 	var r *syscall.DNSRecord
 	e := syscall.DnsQuery(target, syscall.DNS_TYPE_SRV, 0, nil, &r, nil)
 	if e != nil {
-		return "", nil, os.NewSyscallError("LookupSRV", e)
+		return "", nil, &DNSError{Err: os.NewSyscallError("dnsquery", e).Error(), Name: target}
 	}
 	defer syscall.DnsRecordListFree(r, 1)
 
-	addrs = make([]*SRV, 0, 10)
+	srvs := make([]*SRV, 0, 10)
 	for _, p := range validRecs(r, syscall.DNS_TYPE_SRV, target) {
 		v := (*syscall.DNSSRVData)(unsafe.Pointer(&p.Data[0]))
-		addrs = append(addrs, &SRV{syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Target))[:]), v.Port, v.Priority, v.Weight})
+		srvs = append(srvs, &SRV{syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Target))[:]), v.Port, v.Priority, v.Weight})
 	}
-	byPriorityWeight(addrs).sort()
-	return name, addrs, nil
+	byPriorityWeight(srvs).sort()
+	return name, srvs, nil
 }
 
-func lookupMX(name string) (mx []*MX, err error) {
+func lookupMX(name string) ([]*MX, error) {
 	acquireThread()
 	defer releaseThread()
 	var r *syscall.DNSRecord
 	e := syscall.DnsQuery(name, syscall.DNS_TYPE_MX, 0, nil, &r, nil)
 	if e != nil {
-		return nil, os.NewSyscallError("LookupMX", e)
+		return nil, &DNSError{Err: os.NewSyscallError("dnsquery", e).Error(), Name: name}
 	}
 	defer syscall.DnsRecordListFree(r, 1)
 
-	mx = make([]*MX, 0, 10)
+	mxs := make([]*MX, 0, 10)
 	for _, p := range validRecs(r, syscall.DNS_TYPE_MX, name) {
 		v := (*syscall.DNSMXData)(unsafe.Pointer(&p.Data[0]))
-		mx = append(mx, &MX{syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.NameExchange))[:]) + ".", v.Preference})
+		mxs = append(mxs, &MX{syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.NameExchange))[:]) + ".", v.Preference})
 	}
-	byPref(mx).sort()
-	return mx, nil
+	byPref(mxs).sort()
+	return mxs, nil
 }
 
-func lookupNS(name string) (ns []*NS, err error) {
+func lookupNS(name string) ([]*NS, error) {
 	acquireThread()
 	defer releaseThread()
 	var r *syscall.DNSRecord
 	e := syscall.DnsQuery(name, syscall.DNS_TYPE_NS, 0, nil, &r, nil)
 	if e != nil {
-		return nil, os.NewSyscallError("LookupNS", e)
+		return nil, &DNSError{Err: os.NewSyscallError("dnsquery", e).Error(), Name: name}
 	}
 	defer syscall.DnsRecordListFree(r, 1)
 
-	ns = make([]*NS, 0, 10)
+	nss := make([]*NS, 0, 10)
 	for _, p := range validRecs(r, syscall.DNS_TYPE_NS, name) {
 		v := (*syscall.DNSPTRData)(unsafe.Pointer(&p.Data[0]))
-		ns = append(ns, &NS{syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Host))[:]) + "."})
+		nss = append(nss, &NS{syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Host))[:]) + "."})
 	}
-	return ns, nil
+	return nss, nil
 }
 
-func lookupTXT(name string) (txt []string, err error) {
+func lookupTXT(name string) ([]string, error) {
 	acquireThread()
 	defer releaseThread()
 	var r *syscall.DNSRecord
 	e := syscall.DnsQuery(name, syscall.DNS_TYPE_TEXT, 0, nil, &r, nil)
 	if e != nil {
-		return nil, os.NewSyscallError("LookupTXT", e)
+		return nil, &DNSError{Err: os.NewSyscallError("dnsquery", e).Error(), Name: name}
 	}
 	defer syscall.DnsRecordListFree(r, 1)
 
-	txt = make([]string, 0, 10)
+	txts := make([]string, 0, 10)
 	for _, p := range validRecs(r, syscall.DNS_TYPE_TEXT, name) {
 		d := (*syscall.DNSTXTData)(unsafe.Pointer(&p.Data[0]))
 		for _, v := range (*[1 << 10]*uint16)(unsafe.Pointer(&(d.StringArray[0])))[:d.StringCount] {
 			s := syscall.UTF16ToString((*[1 << 20]uint16)(unsafe.Pointer(v))[:])
-			txt = append(txt, s)
+			txts = append(txts, s)
 		}
 	}
-	return
+	return txts, nil
 }
 
-func lookupAddr(addr string) (name []string, err error) {
+func lookupAddr(addr string) ([]string, error) {
 	acquireThread()
 	defer releaseThread()
 	arpa, err := reverseaddr(addr)
@@ -321,16 +329,16 @@ func lookupAddr(addr string) (name []string, err error) {
 	var r *syscall.DNSRecord
 	e := syscall.DnsQuery(arpa, syscall.DNS_TYPE_PTR, 0, nil, &r, nil)
 	if e != nil {
-		return nil, os.NewSyscallError("LookupAddr", e)
+		return nil, &DNSError{Err: os.NewSyscallError("dnsquery", e).Error(), Name: addr}
 	}
 	defer syscall.DnsRecordListFree(r, 1)
 
-	name = make([]string, 0, 10)
+	ptrs := make([]string, 0, 10)
 	for _, p := range validRecs(r, syscall.DNS_TYPE_PTR, arpa) {
 		v := (*syscall.DNSPTRData)(unsafe.Pointer(&p.Data[0]))
-		name = append(name, syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Host))[:]))
+		ptrs = append(ptrs, syscall.UTF16ToString((*[256]uint16)(unsafe.Pointer(v.Host))[:]))
 	}
-	return name, nil
+	return ptrs, nil
 }
 
 const dnsSectionMask = 0x0003
diff --git a/src/net/lookup_windows_test.go b/src/net/lookup_windows_test.go
index 7495b5b..3f64d8c 100644
--- a/src/net/lookup_windows_test.go
+++ b/src/net/lookup_windows_test.go
@@ -26,12 +26,13 @@ func toJson(v interface{}) string {
 
 func TestLookupMX(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
+		t.Skip("avoid external network")
 	}
+
 	for _, server := range nslookupTestServers {
 		mx, err := LookupMX(server)
 		if err != nil {
-			t.Errorf("failed %s: %s", server, err)
+			t.Error(err)
 			continue
 		}
 		if len(mx) == 0 {
@@ -52,8 +53,9 @@ func TestLookupMX(t *testing.T) {
 
 func TestLookupCNAME(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
+		t.Skip("avoid external network")
 	}
+
 	for _, server := range nslookupTestServers {
 		cname, err := LookupCNAME(server)
 		if err != nil {
@@ -76,8 +78,9 @@ func TestLookupCNAME(t *testing.T) {
 
 func TestLookupNS(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
+		t.Skip("avoid external network")
 	}
+
 	for _, server := range nslookupTestServers {
 		ns, err := LookupNS(server)
 		if err != nil {
@@ -103,8 +106,9 @@ func TestLookupNS(t *testing.T) {
 
 func TestLookupTXT(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
+		t.Skip("avoid external network")
 	}
+
 	for _, server := range nslookupTestServers {
 		txt, err := LookupTXT(server)
 		if err != nil {
diff --git a/src/net/mac.go b/src/net/mac.go
index d616b1f..8594a91 100644
--- a/src/net/mac.go
+++ b/src/net/mac.go
@@ -2,12 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// MAC address manipulations
-
 package net
 
-import "errors"
-
 const hexDigit = "0123456789abcdef"
 
 // A HardwareAddr represents a physical hardware address.
@@ -82,5 +78,5 @@ func ParseMAC(s string) (hw HardwareAddr, err error) {
 	return hw, nil
 
 error:
-	return nil, errors.New("invalid MAC address: " + s)
+	return nil, &AddrError{Err: "invalid MAC address", Addr: s}
 }
diff --git a/src/net/mac_test.go b/src/net/mac_test.go
index 8f9dc66..0af0c01 100644
--- a/src/net/mac_test.go
+++ b/src/net/mac_test.go
@@ -10,7 +10,7 @@ import (
 	"testing"
 )
 
-var mactests = []struct {
+var parseMACTests = []struct {
 	in  string
 	out HardwareAddr
 	err string
@@ -36,19 +36,18 @@ var mactests = []struct {
 	{"0123.4567.89AB.CDEF", HardwareAddr{1, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, ""},
 }
 
-func match(err error, s string) bool {
-	if s == "" {
-		return err == nil
+func TestParseMAC(t *testing.T) {
+	match := func(err error, s string) bool {
+		if s == "" {
+			return err == nil
+		}
+		return err != nil && strings.Contains(err.Error(), s)
 	}
-	return err != nil && strings.Contains(err.Error(), s)
-}
 
-func TestMACParseString(t *testing.T) {
-	for i, tt := range mactests {
+	for i, tt := range parseMACTests {
 		out, err := ParseMAC(tt.in)
 		if !reflect.DeepEqual(out, tt.out) || !match(err, tt.err) {
-			t.Errorf("ParseMAC(%q) = %v, %v, want %v, %v", tt.in, out, err, tt.out,
-				tt.err)
+			t.Errorf("ParseMAC(%q) = %v, %v, want %v, %v", tt.in, out, err, tt.out, tt.err)
 		}
 		if tt.err == "" {
 			// Verify that serialization works too, and that it round-trips.
diff --git a/src/net/mail/example_test.go b/src/net/mail/example_test.go
new file mode 100644
index 0000000..c336564
--- /dev/null
+++ b/src/net/mail/example_test.go
@@ -0,0 +1,77 @@
+// 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 mail_test
+
+import (
+	"fmt"
+	"io/ioutil"
+	"log"
+	"net/mail"
+	"strings"
+)
+
+func ExampleParseAddressList() {
+	const list = "Alice <alice at example.com>, Bob <bob at example.com>, Eve <eve at example.com>"
+	emails, err := mail.ParseAddressList(list)
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	for _, v := range emails {
+		fmt.Println(v.Name, v.Address)
+	}
+
+	// Output:
+	// Alice alice at example.com
+	// Bob bob at example.com
+	// Eve eve at example.com
+}
+
+func ExampleParseAddress() {
+	e, err := mail.ParseAddress("Alice <alice at example.com>")
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	fmt.Println(e.Name, e.Address)
+
+	// Output:
+	// Alice alice at example.com
+}
+
+func ExampleReadMessage() {
+	msg := `Date: Mon, 23 Jun 2015 11:40:36 -0400
+From: Gopher <from at example.com>
+To: Another Gopher <to at example.com>
+Subject: Gophers at Gophercon
+
+Message body
+`
+
+	r := strings.NewReader(msg)
+	m, err := mail.ReadMessage(r)
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	header := m.Header
+	fmt.Println("Date:", header.Get("Date"))
+	fmt.Println("From:", header.Get("From"))
+	fmt.Println("To:", header.Get("To"))
+	fmt.Println("Subject:", header.Get("Subject"))
+
+	body, err := ioutil.ReadAll(m.Body)
+	if err != nil {
+		log.Fatal(err)
+	}
+	fmt.Printf("%s", body)
+
+	// Output:
+	// Date: Mon, 23 Jun 2015 11:40:36 -0400
+	// From: Gopher <from at example.com>
+	// To: Another Gopher <to at example.com>
+	// Subject: Gophers at Gophercon
+	// Message body
+}
diff --git a/src/net/mail/message.go b/src/net/mail/message.go
index 19aa888..266ac50 100644
--- a/src/net/mail/message.go
+++ b/src/net/mail/message.go
@@ -18,17 +18,14 @@ package mail
 import (
 	"bufio"
 	"bytes"
-	"encoding/base64"
 	"errors"
 	"fmt"
 	"io"
-	"io/ioutil"
 	"log"
+	"mime"
 	"net/textproto"
-	"strconv"
 	"strings"
 	"time"
-	"unicode"
 )
 
 var debug = debugT(false)
@@ -141,22 +138,79 @@ type Address struct {
 
 // Parses a single RFC 5322 address, e.g. "Barry Gibbs <bg at example.com>"
 func ParseAddress(address string) (*Address, error) {
-	return newAddrParser(address).parseAddress()
+	return (&addrParser{s: address}).parseAddress()
 }
 
 // ParseAddressList parses the given string as a list of addresses.
 func ParseAddressList(list string) ([]*Address, error) {
-	return newAddrParser(list).parseAddressList()
+	return (&addrParser{s: list}).parseAddressList()
+}
+
+// An AddressParser is an RFC 5322 address parser.
+type AddressParser struct {
+	// WordDecoder optionally specifies a decoder for RFC 2047 encoded-words.
+	WordDecoder *mime.WordDecoder
+}
+
+// Parse parses a single RFC 5322 address of the
+// form "Gogh Fir <gf at example.com>" or "foo at example.com".
+func (p *AddressParser) Parse(address string) (*Address, error) {
+	return (&addrParser{s: address, dec: p.WordDecoder}).parseAddress()
+}
+
+// ParseList parses the given string as a list of comma-separated addresses
+// of the form "Gogh Fir <gf at example.com>" or "foo at example.com".
+func (p *AddressParser) ParseList(list string) ([]*Address, error) {
+	return (&addrParser{s: list, dec: p.WordDecoder}).parseAddressList()
 }
 
 // String formats the address as a valid RFC 5322 address.
 // If the address's name contains non-ASCII characters
 // the name will be rendered according to RFC 2047.
 func (a *Address) String() string {
-	s := "<" + a.Address + ">"
+
+	// Format address local at domain
+	at := strings.LastIndex(a.Address, "@")
+	var local, domain string
+	if at < 0 {
+		// This is a malformed address ("@" is required in addr-spec);
+		// treat the whole address as local-part.
+		local = a.Address
+	} else {
+		local, domain = a.Address[:at], a.Address[at+1:]
+	}
+
+	// Add quotes if needed
+	// TODO: rendering quoted local part and rendering printable name
+	//       should be merged in helper function.
+	quoteLocal := false
+	for i := 0; i < len(local); i++ {
+		ch := local[i]
+		if isAtext(ch, false) {
+			continue
+		}
+		if ch == '.' {
+			// Dots are okay if they are surrounded by atext.
+			// We only need to check that the previous byte is
+			// not a dot, and this isn't the end of the string.
+			if i > 0 && local[i-1] != '.' && i < len(local)-1 {
+				continue
+			}
+		}
+		quoteLocal = true
+		break
+	}
+	if quoteLocal {
+		local = quoteString(local)
+
+	}
+
+	s := "<" + local + "@" + domain + ">"
+
 	if a.Name == "" {
 		return s
 	}
+
 	// If every character is printable ASCII, quoting is simple.
 	allPrintable := true
 	for i := 0; i < len(a.Name); i++ {
@@ -180,28 +234,12 @@ func (a *Address) String() string {
 		return b.String()
 	}
 
-	// UTF-8 "Q" encoding
-	b := bytes.NewBufferString("=?utf-8?q?")
-	for i := 0; i < len(a.Name); i++ {
-		switch c := a.Name[i]; {
-		case c == ' ':
-			b.WriteByte('_')
-		case isVchar(c) && c != '=' && c != '?' && c != '_':
-			b.WriteByte(c)
-		default:
-			fmt.Fprintf(b, "=%02X", c)
-		}
-	}
-	b.WriteString("?= ")
-	b.WriteString(s)
-	return b.String()
+	return mime.QEncoding.Encode("utf-8", a.Name) + " " + s
 }
 
-type addrParser []byte
-
-func newAddrParser(s string) *addrParser {
-	p := addrParser(s)
-	return &p
+type addrParser struct {
+	s   string
+	dec *mime.WordDecoder // may be nil
 }
 
 func (p *addrParser) parseAddressList() ([]*Address, error) {
@@ -227,7 +265,7 @@ func (p *addrParser) parseAddressList() ([]*Address, error) {
 
 // parseAddress parses a single RFC 5322 address at the start of p.
 func (p *addrParser) parseAddress() (addr *Address, err error) {
-	debug.Printf("parseAddress: %q", *p)
+	debug.Printf("parseAddress: %q", p.s)
 	p.skipSpace()
 	if p.empty() {
 		return nil, errors.New("mail: no address")
@@ -246,7 +284,7 @@ func (p *addrParser) parseAddress() (addr *Address, err error) {
 		}, err
 	}
 	debug.Printf("parseAddress: not an addr-spec: %v", err)
-	debug.Printf("parseAddress: state is now %q", *p)
+	debug.Printf("parseAddress: state is now %q", p.s)
 
 	// display-name
 	var displayName string
@@ -280,7 +318,7 @@ func (p *addrParser) parseAddress() (addr *Address, err error) {
 
 // consumeAddrSpec parses a single RFC 5322 addr-spec at the start of p.
 func (p *addrParser) consumeAddrSpec() (spec string, err error) {
-	debug.Printf("consumeAddrSpec: %q", *p)
+	debug.Printf("consumeAddrSpec: %q", p.s)
 
 	orig := *p
 	defer func() {
@@ -302,7 +340,7 @@ func (p *addrParser) consumeAddrSpec() (spec string, err error) {
 	} else {
 		// dot-atom
 		debug.Printf("consumeAddrSpec: parsing dot-atom")
-		localPart, err = p.consumeAtom(true)
+		localPart, err = p.consumeAtom(true, false)
 	}
 	if err != nil {
 		debug.Printf("consumeAddrSpec: failed: %v", err)
@@ -320,7 +358,7 @@ func (p *addrParser) consumeAddrSpec() (spec string, err error) {
 		return "", errors.New("mail: no domain in addr-spec")
 	}
 	// TODO(dsymonds): Handle domain-literal
-	domain, err = p.consumeAtom(true)
+	domain, err = p.consumeAtom(true, false)
 	if err != nil {
 		return "", err
 	}
@@ -330,7 +368,7 @@ func (p *addrParser) consumeAddrSpec() (spec string, err error) {
 
 // consumePhrase parses the RFC 5322 phrase at the start of p.
 func (p *addrParser) consumePhrase() (phrase string, err error) {
-	debug.Printf("consumePhrase: [%s]", *p)
+	debug.Printf("consumePhrase: [%s]", p.s)
 	// phrase = 1*word
 	var words []string
 	for {
@@ -347,12 +385,11 @@ func (p *addrParser) consumePhrase() (phrase string, err error) {
 			// atom
 			// We actually parse dot-atom here to be more permissive
 			// than what RFC 5322 specifies.
-			word, err = p.consumeAtom(true)
+			word, err = p.consumeAtom(true, true)
 		}
 
-		// RFC 2047 encoded-word starts with =?, ends with ?=, and has two other ?s.
-		if err == nil && strings.HasPrefix(word, "=?") && strings.HasSuffix(word, "?=") && strings.Count(word, "?") == 4 {
-			word, err = decodeRFC2047Word(word)
+		if err == nil {
+			word, err = p.decodeRFC2047Word(word)
 		}
 
 		if err != nil {
@@ -380,16 +417,16 @@ Loop:
 		if i >= p.len() {
 			return "", errors.New("mail: unclosed quoted-string")
 		}
-		switch c := (*p)[i]; {
+		switch c := p.s[i]; {
 		case c == '"':
 			break Loop
 		case c == '\\':
 			if i+1 == p.len() {
 				return "", errors.New("mail: unclosed quoted-string")
 			}
-			qsb = append(qsb, (*p)[i+1])
+			qsb = append(qsb, p.s[i+1])
 			i += 2
-		case isQtext(c), c == ' ' || c == '\t':
+		case isQtext(c), c == ' ':
 			// qtext (printable US-ASCII excluding " and \), or
 			// FWS (almost; we're ignoring CRLF)
 			qsb = append(qsb, c)
@@ -398,20 +435,36 @@ Loop:
 			return "", fmt.Errorf("mail: bad character in quoted-string: %q", c)
 		}
 	}
-	*p = (*p)[i+1:]
+	p.s = p.s[i+1:]
+	if len(qsb) == 0 {
+		return "", errors.New("mail: empty quoted-string")
+	}
 	return string(qsb), nil
 }
 
 // consumeAtom parses an RFC 5322 atom at the start of p.
 // If dot is true, consumeAtom parses an RFC 5322 dot-atom instead.
-func (p *addrParser) consumeAtom(dot bool) (atom string, err error) {
+// If permissive is true, consumeAtom will not fail on
+// leading/trailing/double dots in the atom (see golang.org/issue/4938).
+func (p *addrParser) consumeAtom(dot bool, permissive bool) (atom string, err error) {
 	if !isAtext(p.peek(), false) {
 		return "", errors.New("mail: invalid string")
 	}
 	i := 1
-	for ; i < p.len() && isAtext((*p)[i], dot); i++ {
+	for ; i < p.len() && isAtext(p.s[i], dot); i++ {
+	}
+	atom, p.s = string(p.s[:i]), p.s[i:]
+	if !permissive {
+		if strings.HasPrefix(atom, ".") {
+			return "", errors.New("mail: leading dot in atom")
+		}
+		if strings.Contains(atom, "..") {
+			return "", errors.New("mail: double dot in atom")
+		}
+		if strings.HasSuffix(atom, ".") {
+			return "", errors.New("mail: trailing dot in atom")
+		}
 	}
-	atom, *p = string((*p)[:i]), (*p)[i:]
 	return atom, nil
 }
 
@@ -419,17 +472,17 @@ func (p *addrParser) consume(c byte) bool {
 	if p.empty() || p.peek() != c {
 		return false
 	}
-	*p = (*p)[1:]
+	p.s = p.s[1:]
 	return true
 }
 
 // skipSpace skips the leading space and tab characters.
 func (p *addrParser) skipSpace() {
-	*p = bytes.TrimLeft(*p, " \t")
+	p.s = strings.TrimLeft(p.s, " \t")
 }
 
 func (p *addrParser) peek() byte {
-	return (*p)[0]
+	return p.s[0]
 }
 
 func (p *addrParser) empty() bool {
@@ -437,87 +490,37 @@ func (p *addrParser) empty() bool {
 }
 
 func (p *addrParser) len() int {
-	return len(*p)
+	return len(p.s)
 }
 
-func decodeRFC2047Word(s string) (string, error) {
-	fields := strings.Split(s, "?")
-	if len(fields) != 5 || fields[0] != "=" || fields[4] != "=" {
-		return "", errors.New("address not RFC 2047 encoded")
-	}
-	charset, enc := strings.ToLower(fields[1]), strings.ToLower(fields[2])
-	if charset != "us-ascii" && charset != "iso-8859-1" && charset != "utf-8" {
-		return "", fmt.Errorf("charset not supported: %q", charset)
+func (p *addrParser) decodeRFC2047Word(s string) (string, error) {
+	if p.dec != nil {
+		return p.dec.DecodeHeader(s)
 	}
 
-	in := bytes.NewBufferString(fields[3])
-	var r io.Reader
-	switch enc {
-	case "b":
-		r = base64.NewDecoder(base64.StdEncoding, in)
-	case "q":
-		r = qDecoder{r: in}
-	default:
-		return "", fmt.Errorf("RFC 2047 encoding not supported: %q", enc)
+	dec, err := rfc2047Decoder.Decode(s)
+	if err == nil {
+		return dec, nil
 	}
 
-	dec, err := ioutil.ReadAll(r)
-	if err != nil {
-		return "", err
+	if _, ok := err.(charsetError); ok {
+		return s, err
 	}
 
-	switch charset {
-	case "us-ascii":
-		b := new(bytes.Buffer)
-		for _, c := range dec {
-			if c >= 0x80 {
-				b.WriteRune(unicode.ReplacementChar)
-			} else {
-				b.WriteRune(rune(c))
-			}
-		}
-		return b.String(), nil
-	case "iso-8859-1":
-		b := new(bytes.Buffer)
-		for _, c := range dec {
-			b.WriteRune(rune(c))
-		}
-		return b.String(), nil
-	case "utf-8":
-		return string(dec), nil
-	}
-	panic("unreachable")
+	// Ignore invalid RFC 2047 encoded-word errors.
+	return s, nil
 }
 
-type qDecoder struct {
-	r       io.Reader
-	scratch [2]byte
+var rfc2047Decoder = mime.WordDecoder{
+	CharsetReader: func(charset string, input io.Reader) (io.Reader, error) {
+		return nil, charsetError(charset)
+	},
 }
 
-func (qd qDecoder) Read(p []byte) (n int, err error) {
-	// This method writes at most one byte into p.
-	if len(p) == 0 {
-		return 0, nil
-	}
-	if _, err := qd.r.Read(qd.scratch[:1]); err != nil {
-		return 0, err
-	}
-	switch c := qd.scratch[0]; {
-	case c == '=':
-		if _, err := io.ReadFull(qd.r, qd.scratch[:2]); err != nil {
-			return 0, err
-		}
-		x, err := strconv.ParseInt(string(qd.scratch[:2]), 16, 64)
-		if err != nil {
-			return 0, fmt.Errorf("mail: invalid RFC 2047 encoding: %q", qd.scratch[:2])
-		}
-		p[0] = byte(x)
-	case c == '_':
-		p[0] = ' '
-	default:
-		p[0] = c
-	}
-	return 1, nil
+type charsetError string
+
+func (e charsetError) Error() string {
+	return fmt.Sprintf("charset not supported: %q", string(e))
 }
 
 var atextChars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
@@ -525,7 +528,7 @@ var atextChars = []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
 	"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 == '.' {
@@ -534,7 +537,7 @@ func isAtext(c byte, dot bool) bool {
 	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 == '"' {
@@ -543,13 +546,30 @@ func isQtext(c byte) bool {
 	return '!' <= c && c <= '~'
 }
 
-// isVchar returns true if c is an RFC 5322 VCHAR character.
+// quoteString renders a string as a RFC5322 quoted-string.
+func quoteString(s string) string {
+	var buf bytes.Buffer
+	buf.WriteByte('"')
+	for _, c := range s {
+		ch := byte(c)
+		if isQtext(ch) || isWSP(ch) {
+			buf.WriteByte(ch)
+		} else if isVchar(ch) {
+			buf.WriteByte('\\')
+			buf.WriteByte(ch)
+		}
+	}
+	buf.WriteByte('"')
+	return buf.String()
+}
+
+// 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/mail/message_test.go b/src/net/mail/message_test.go
index 6ba48be..1b42274 100644
--- a/src/net/mail/message_test.go
+++ b/src/net/mail/message_test.go
@@ -6,7 +6,9 @@ package mail
 
 import (
 	"bytes"
+	"io"
 	"io/ioutil"
+	"mime"
 	"reflect"
 	"strings"
 	"testing"
@@ -278,6 +280,175 @@ func TestAddressParsing(t *testing.T) {
 	}
 }
 
+func TestAddressParser(t *testing.T) {
+	tests := []struct {
+		addrsStr string
+		exp      []*Address
+	}{
+		// Bare address
+		{
+			`jdoe at machine.example`,
+			[]*Address{{
+				Address: "jdoe at machine.example",
+			}},
+		},
+		// RFC 5322, Appendix A.1.1
+		{
+			`John Doe <jdoe at machine.example>`,
+			[]*Address{{
+				Name:    "John Doe",
+				Address: "jdoe at machine.example",
+			}},
+		},
+		// RFC 5322, Appendix A.1.2
+		{
+			`"Joe Q. Public" <john.q.public at example.com>`,
+			[]*Address{{
+				Name:    "Joe Q. Public",
+				Address: "john.q.public at example.com",
+			}},
+		},
+		{
+			`Mary Smith <mary at x.test>, jdoe at example.org, Who? <one at y.test>`,
+			[]*Address{
+				{
+					Name:    "Mary Smith",
+					Address: "mary at x.test",
+				},
+				{
+					Address: "jdoe at example.org",
+				},
+				{
+					Name:    "Who?",
+					Address: "one at y.test",
+				},
+			},
+		},
+		{
+			`<boss at nil.test>, "Giant; \"Big\" Box" <sysservices at example.net>`,
+			[]*Address{
+				{
+					Address: "boss at nil.test",
+				},
+				{
+					Name:    `Giant; "Big" Box`,
+					Address: "sysservices at example.net",
+				},
+			},
+		},
+		// RFC 2047 "Q"-encoded ISO-8859-1 address.
+		{
+			`=?iso-8859-1?q?J=F6rg_Doe?= <joerg at example.com>`,
+			[]*Address{
+				{
+					Name:    `Jörg Doe`,
+					Address: "joerg at example.com",
+				},
+			},
+		},
+		// RFC 2047 "Q"-encoded US-ASCII address. Dumb but legal.
+		{
+			`=?us-ascii?q?J=6Frg_Doe?= <joerg at example.com>`,
+			[]*Address{
+				{
+					Name:    `Jorg Doe`,
+					Address: "joerg at example.com",
+				},
+			},
+		},
+		// RFC 2047 "Q"-encoded ISO-8859-15 address.
+		{
+			`=?ISO-8859-15?Q?J=F6rg_Doe?= <joerg at example.com>`,
+			[]*Address{
+				{
+					Name:    `Jörg Doe`,
+					Address: "joerg at example.com",
+				},
+			},
+		},
+		// RFC 2047 "B"-encoded windows-1252 address.
+		{
+			`=?windows-1252?q?Andr=E9?= Pirard <PIRARD at vm1.ulg.ac.be>`,
+			[]*Address{
+				{
+					Name:    `André Pirard`,
+					Address: "PIRARD at vm1.ulg.ac.be",
+				},
+			},
+		},
+		// Custom example of RFC 2047 "B"-encoded ISO-8859-15 address.
+		{
+			`=?ISO-8859-15?B?SvZyZw==?= <joerg at example.com>`,
+			[]*Address{
+				{
+					Name:    `Jörg`,
+					Address: "joerg at example.com",
+				},
+			},
+		},
+		// Custom example of RFC 2047 "B"-encoded UTF-8 address.
+		{
+			`=?UTF-8?B?SsO2cmc=?= <joerg at example.com>`,
+			[]*Address{
+				{
+					Name:    `Jörg`,
+					Address: "joerg at example.com",
+				},
+			},
+		},
+		// Custom example with "." in name. For issue 4938
+		{
+			`Asem H. <noreply at example.com>`,
+			[]*Address{
+				{
+					Name:    `Asem H.`,
+					Address: "noreply at example.com",
+				},
+			},
+		},
+	}
+
+	ap := AddressParser{WordDecoder: &mime.WordDecoder{
+		CharsetReader: func(charset string, input io.Reader) (io.Reader, error) {
+			in, err := ioutil.ReadAll(input)
+			if err != nil {
+				return nil, err
+			}
+
+			switch charset {
+			case "iso-8859-15":
+				in = bytes.Replace(in, []byte("\xf6"), []byte("ö"), -1)
+			case "windows-1252":
+				in = bytes.Replace(in, []byte("\xe9"), []byte("é"), -1)
+			}
+
+			return bytes.NewReader(in), nil
+		},
+	}}
+
+	for _, test := range tests {
+		if len(test.exp) == 1 {
+			addr, err := ap.Parse(test.addrsStr)
+			if err != nil {
+				t.Errorf("Failed parsing (single) %q: %v", test.addrsStr, err)
+				continue
+			}
+			if !reflect.DeepEqual([]*Address{addr}, test.exp) {
+				t.Errorf("Parse (single) of %q: got %+v, want %+v", test.addrsStr, addr, test.exp)
+			}
+		}
+
+		addrs, err := ap.ParseList(test.addrsStr)
+		if err != nil {
+			t.Errorf("Failed parsing (list) %q: %v", test.addrsStr, err)
+			continue
+		}
+		if !reflect.DeepEqual(addrs, test.exp) {
+			t.Errorf("Parse (list) of %q: got %+v, want %+v", test.addrsStr, addrs, test.exp)
+		}
+	}
+}
+
 func TestAddressFormatting(t *testing.T) {
 	tests := []struct {
 		addr *Address
@@ -287,6 +458,14 @@ func TestAddressFormatting(t *testing.T) {
 			&Address{Address: "bob at example.com"},
 			"<bob at example.com>",
 		},
+		{ // quoted local parts: RFC 5322, 3.4.1. and 3.2.4.
+			&Address{Address: `my at idiot@address at example.com`},
+			`<"my at idiot@address"@example.com>`,
+		},
+		{ // quoted local parts
+			&Address{Address: ` @example.com`},
+			`<" "@example.com>`,
+		},
 		{
 			&Address{Name: "Bob", Address: "bob at example.com"},
 			`"Bob" <bob at example.com>`,
@@ -304,6 +483,14 @@ func TestAddressFormatting(t *testing.T) {
 			&Address{Name: "Böb Jacöb", Address: "bob at example.com"},
 			`=?utf-8?q?B=C3=B6b_Jac=C3=B6b?= <bob at example.com>`,
 		},
+		{ // https://golang.org/issue/12098
+			&Address{Name: "Rob", Address: ""},
+			`"Rob" <@>`,
+		},
+		{ // https://golang.org/issue/12098
+			&Address{Name: "Rob", Address: "@"},
+			`"Rob" <@>`,
+		},
 	}
 	for _, test := range tests {
 		s := test.addr.String()
@@ -312,3 +499,90 @@ func TestAddressFormatting(t *testing.T) {
 		}
 	}
 }
+
+// Check if all valid addresses can be parsed, formatted and parsed again
+func TestAddressParsingAndFormatting(t *testing.T) {
+
+	// Should pass
+	tests := []string{
+		`<Bob at example.com>`,
+		`<bob.bob at example.com>`,
+		`<".bob"@example.com>`,
+		`<" "@example.com>`,
+		`<some.mail-with-dash at example.com>`,
+		`<"dot.and space"@example.com>`,
+		`<"very.unusual. at .unusual.com"@example.com>`,
+		`<admin at mailserver1>`,
+		`<postmaster at localhost>`,
+		"<#!$%&'*+-/=?^_`{}|~@example.org>",
+		`<"very.(),:;<>[]\".VERY.\"very@\\ \"very\".unusual"@strange.example.com>`, // escaped quotes
+		`<"()<>[]:,;@\\\"!#$%&'*+-/=?^_{}| ~.a"@example.org>`,                      // escaped backslashes
+		`<"Abc\\@def"@example.com>`,
+		`<"Joe\\Blow"@example.com>`,
+		`<test1/test2=test3 at example.com>`,
+		`<def!xyz%abc at example.com>`,
+		`<_somename at example.com>`,
+		`<joe at uk>`,
+		`<~@example.com>`,
+		`<"..."@test.com>`,
+		`<"john..doe"@example.com>`,
+		`<"john.doe."@example.com>`,
+		`<".john.doe"@example.com>`,
+		`<"."@example.com>`,
+		`<".."@example.com>`,
+		`<"0:"@0>`,
+	}
+
+	for _, test := range tests {
+		addr, err := ParseAddress(test)
+		if err != nil {
+			t.Errorf("Couldn't parse address %s: %s", test, err.Error())
+			continue
+		}
+		str := addr.String()
+		addr, err = ParseAddress(str)
+		if err != nil {
+			t.Errorf("ParseAddr(%q) error: %v", test, err)
+			continue
+		}
+
+		if addr.String() != test {
+			t.Errorf("String() round-trip = %q; want %q", addr, test)
+			continue
+		}
+
+	}
+
+	// Should fail
+	badTests := []string{
+		`<Abc.example.com>`,
+		`<A at b@c at example.com>`,
+		`<a"b(c)d,e:f;g<h>i[j\k]l at example.com>`,
+		`<just"not"right at example.com>`,
+		`<this is"not\allowed at example.com>`,
+		`<this\ still\"not\\allowed at example.com>`,
+		`<john..doe at example.com>`,
+		`<john.doe at example..com>`,
+		`<john.doe at example..com>`,
+		`<john.doe. at example.com>`,
+		`<john.doe. at .example.com>`,
+		`<.john.doe at example.com>`,
+		`<@example.com>`,
+		`<. at example.com>`,
+		`<test at .>`,
+		`< @example.com>`,
+		`<""test""blah""@example.com>`,
+		`<""@0>`,
+		"<\"\t0\"@0>",
+	}
+
+	for _, test := range badTests {
+		_, err := ParseAddress(test)
+		if err == nil {
+			t.Errorf("Should have failed to parse address: %s", test)
+			continue
+		}
+
+	}
+
+}
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..94501ca
--- /dev/null
+++ b/src/net/main_plan9_test.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
+
+func installTestHooks() {}
+
+func uninstallTestHooks() {}
+
+func forceCloseSockets() {}
+
+func enableSocketConnect() {}
+
+func disableSocketConnect(network string) {}
diff --git a/src/net/main_posix_test.go b/src/net/main_posix_test.go
new file mode 100644
index 0000000..ead311c
--- /dev/null
+++ b/src/net/main_posix_test.go
@@ -0,0 +1,50 @@
+// 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 net
+
+import (
+	"net/internal/socktest"
+	"strings"
+	"syscall"
+)
+
+func enableSocketConnect() {
+	sw.Set(socktest.FilterConnect, nil)
+}
+
+func disableSocketConnect(network string) {
+	ss := strings.Split(network, ":")
+	sw.Set(socktest.FilterConnect, func(so *socktest.Status) (socktest.AfterFilter, error) {
+		switch ss[0] {
+		case "tcp4":
+			if so.Cookie.Family() == syscall.AF_INET && so.Cookie.Type() == syscall.SOCK_STREAM {
+				return nil, syscall.EHOSTUNREACH
+			}
+		case "udp4":
+			if so.Cookie.Family() == syscall.AF_INET && so.Cookie.Type() == syscall.SOCK_DGRAM {
+				return nil, syscall.EHOSTUNREACH
+			}
+		case "ip4":
+			if so.Cookie.Family() == syscall.AF_INET && so.Cookie.Type() == syscall.SOCK_RAW {
+				return nil, syscall.EHOSTUNREACH
+			}
+		case "tcp6":
+			if so.Cookie.Family() == syscall.AF_INET6 && so.Cookie.Type() == syscall.SOCK_STREAM {
+				return nil, syscall.EHOSTUNREACH
+			}
+		case "udp6":
+			if so.Cookie.Family() == syscall.AF_INET6 && so.Cookie.Type() == syscall.SOCK_DGRAM {
+				return nil, syscall.EHOSTUNREACH
+			}
+		case "ip6":
+			if so.Cookie.Family() == syscall.AF_INET6 && so.Cookie.Type() == syscall.SOCK_RAW {
+				return nil, syscall.EHOSTUNREACH
+			}
+		}
+		return nil, nil
+	})
+}
diff --git a/src/net/main_test.go b/src/net/main_test.go
new file mode 100644
index 0000000..f3f8b1a9
--- /dev/null
+++ b/src/net/main_test.go
@@ -0,0 +1,204 @@
+// 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 (
+	"flag"
+	"fmt"
+	"net/internal/socktest"
+	"os"
+	"runtime"
+	"sort"
+	"strings"
+	"sync"
+	"testing"
+)
+
+var (
+	sw socktest.Switch
+
+	// uninstallTestHooks runs just before a run of benchmarks.
+	testHookUninstaller sync.Once
+)
+
+var (
+	testDNSFlood = flag.Bool("dnsflood", false, "whether to test DNS query flooding")
+
+	testExternal = flag.Bool("external", true, "allow use of external networks during long test")
+
+	// If external IPv4 connectivity exists, we can try dialing
+	// non-node/interface local scope IPv4 addresses.
+	// On Windows, Lookup APIs may not return IPv4-related
+	// resource records when a node has no external IPv4
+	// connectivity.
+	testIPv4 = flag.Bool("ipv4", true, "assume external IPv4 connectivity exists")
+
+	// If external IPv6 connectivity exists, we can try dialing
+	// non-node/interface local scope IPv6 addresses.
+	// On Windows, Lookup APIs may not return IPv6-related
+	// resource records when a node has no external IPv6
+	// connectivity.
+	testIPv6 = flag.Bool("ipv6", false, "assume external IPv6 connectivity exists")
+)
+
+func TestMain(m *testing.M) {
+	setupTestData()
+	installTestHooks()
+
+	st := m.Run()
+
+	testHookUninstaller.Do(uninstallTestHooks)
+	if testing.Verbose() {
+		printRunningGoroutines()
+		printInflightSockets()
+		printSocketStats()
+	}
+	forceCloseSockets()
+	os.Exit(st)
+}
+
+type ipv6LinkLocalUnicastTest struct {
+	network, address string
+	nameLookup       bool
+}
+
+var (
+	ipv6LinkLocalUnicastTCPTests []ipv6LinkLocalUnicastTest
+	ipv6LinkLocalUnicastUDPTests []ipv6LinkLocalUnicastTest
+)
+
+func setupTestData() {
+	if supportsIPv4 {
+		resolveTCPAddrTests = append(resolveTCPAddrTests, []resolveTCPAddrTest{
+			{"tcp", "localhost:1", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 1}, nil},
+			{"tcp4", "localhost:2", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 2}, nil},
+		}...)
+		resolveUDPAddrTests = append(resolveUDPAddrTests, []resolveUDPAddrTest{
+			{"udp", "localhost:1", &UDPAddr{IP: IPv4(127, 0, 0, 1), Port: 1}, nil},
+			{"udp4", "localhost:2", &UDPAddr{IP: IPv4(127, 0, 0, 1), Port: 2}, nil},
+		}...)
+		resolveIPAddrTests = append(resolveIPAddrTests, []resolveIPAddrTest{
+			{"ip", "localhost", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil},
+			{"ip4", "localhost", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil},
+		}...)
+	}
+
+	if supportsIPv6 {
+		resolveTCPAddrTests = append(resolveTCPAddrTests, resolveTCPAddrTest{"tcp6", "localhost:3", &TCPAddr{IP: IPv6loopback, Port: 3}, nil})
+		resolveUDPAddrTests = append(resolveUDPAddrTests, resolveUDPAddrTest{"udp6", "localhost:3", &UDPAddr{IP: IPv6loopback, Port: 3}, nil})
+		resolveIPAddrTests = append(resolveIPAddrTests, resolveIPAddrTest{"ip6", "localhost", &IPAddr{IP: IPv6loopback}, nil})
+	}
+
+	ifi := loopbackInterface()
+	if ifi != nil {
+		index := fmt.Sprintf("%v", ifi.Index)
+		resolveTCPAddrTests = append(resolveTCPAddrTests, []resolveTCPAddrTest{
+			{"tcp6", "[fe80::1%" + ifi.Name + "]:1", &TCPAddr{IP: ParseIP("fe80::1"), Port: 1, Zone: zoneToString(ifi.Index)}, nil},
+			{"tcp6", "[fe80::1%" + index + "]:2", &TCPAddr{IP: ParseIP("fe80::1"), Port: 2, Zone: index}, nil},
+		}...)
+		resolveUDPAddrTests = append(resolveUDPAddrTests, []resolveUDPAddrTest{
+			{"udp6", "[fe80::1%" + ifi.Name + "]:1", &UDPAddr{IP: ParseIP("fe80::1"), Port: 1, Zone: zoneToString(ifi.Index)}, nil},
+			{"udp6", "[fe80::1%" + index + "]:2", &UDPAddr{IP: ParseIP("fe80::1"), Port: 2, Zone: index}, nil},
+		}...)
+		resolveIPAddrTests = append(resolveIPAddrTests, []resolveIPAddrTest{
+			{"ip6", "fe80::1%" + ifi.Name, &IPAddr{IP: ParseIP("fe80::1"), Zone: zoneToString(ifi.Index)}, nil},
+			{"ip6", "fe80::1%" + index, &IPAddr{IP: ParseIP("fe80::1"), Zone: index}, nil},
+		}...)
+	}
+
+	addr := ipv6LinkLocalUnicastAddr(ifi)
+	if addr != "" {
+		if runtime.GOOS != "dragonfly" {
+			ipv6LinkLocalUnicastTCPTests = append(ipv6LinkLocalUnicastTCPTests, []ipv6LinkLocalUnicastTest{
+				{"tcp", "[" + addr + "%" + ifi.Name + "]:0", false},
+			}...)
+			ipv6LinkLocalUnicastUDPTests = append(ipv6LinkLocalUnicastUDPTests, []ipv6LinkLocalUnicastTest{
+				{"udp", "[" + addr + "%" + ifi.Name + "]:0", false},
+			}...)
+		}
+		ipv6LinkLocalUnicastTCPTests = append(ipv6LinkLocalUnicastTCPTests, []ipv6LinkLocalUnicastTest{
+			{"tcp6", "[" + addr + "%" + ifi.Name + "]:0", false},
+		}...)
+		ipv6LinkLocalUnicastUDPTests = append(ipv6LinkLocalUnicastUDPTests, []ipv6LinkLocalUnicastTest{
+			{"udp6", "[" + addr + "%" + ifi.Name + "]:0", false},
+		}...)
+		switch runtime.GOOS {
+		case "darwin", "dragonfly", "freebsd", "openbsd", "netbsd":
+			ipv6LinkLocalUnicastTCPTests = append(ipv6LinkLocalUnicastTCPTests, []ipv6LinkLocalUnicastTest{
+				{"tcp", "[localhost%" + ifi.Name + "]:0", true},
+				{"tcp6", "[localhost%" + ifi.Name + "]:0", true},
+			}...)
+			ipv6LinkLocalUnicastUDPTests = append(ipv6LinkLocalUnicastUDPTests, []ipv6LinkLocalUnicastTest{
+				{"udp", "[localhost%" + ifi.Name + "]:0", true},
+				{"udp6", "[localhost%" + ifi.Name + "]:0", true},
+			}...)
+		case "linux":
+			ipv6LinkLocalUnicastTCPTests = append(ipv6LinkLocalUnicastTCPTests, []ipv6LinkLocalUnicastTest{
+				{"tcp", "[ip6-localhost%" + ifi.Name + "]:0", true},
+				{"tcp6", "[ip6-localhost%" + ifi.Name + "]:0", true},
+			}...)
+			ipv6LinkLocalUnicastUDPTests = append(ipv6LinkLocalUnicastUDPTests, []ipv6LinkLocalUnicastTest{
+				{"udp", "[ip6-localhost%" + ifi.Name + "]:0", true},
+				{"udp6", "[ip6-localhost%" + ifi.Name + "]:0", true},
+			}...)
+		}
+	}
+}
+
+func printRunningGoroutines() {
+	gss := runningGoroutines()
+	if len(gss) == 0 {
+		return
+	}
+	fmt.Fprintf(os.Stderr, "Running goroutines:\n")
+	for _, gs := range gss {
+		fmt.Fprintf(os.Stderr, "%v\n", gs)
+	}
+	fmt.Fprintf(os.Stderr, "\n")
+}
+
+// runningGoroutines returns a list of remaining goroutines.
+func runningGoroutines() []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 printInflightSockets() {
+	sos := sw.Sockets()
+	if len(sos) == 0 {
+		return
+	}
+	fmt.Fprintf(os.Stderr, "Inflight 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..bfb4cd0
--- /dev/null
+++ b/src/net/main_unix_test.go
@@ -0,0 +1,52 @@
+// 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
+	origListen        = listenFunc
+	origAccept        = acceptFunc
+	origGetsockoptInt = getsockoptIntFunc
+
+	extraTestHookInstallers   []func()
+	extraTestHookUninstallers []func()
+)
+
+func installTestHooks() {
+	socketFunc = sw.Socket
+	closeFunc = sw.Close
+	connectFunc = sw.Connect
+	listenFunc = sw.Listen
+	acceptFunc = sw.Accept
+	getsockoptIntFunc = sw.GetsockoptInt
+
+	for _, fn := range extraTestHookInstallers {
+		fn()
+	}
+}
+
+func uninstallTestHooks() {
+	socketFunc = origSocket
+	closeFunc = origClose
+	connectFunc = origConnect
+	listenFunc = origListen
+	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..2d82974
--- /dev/null
+++ b/src/net/main_windows_test.go
@@ -0,0 +1,36 @@
+// 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
+	origListen      = listenFunc
+)
+
+func installTestHooks() {
+	socketFunc = sw.Socket
+	closeFunc = sw.Closesocket
+	connectFunc = sw.Connect
+	connectExFunc = sw.ConnectEx
+	listenFunc = sw.Listen
+}
+
+func uninstallTestHooks() {
+	socketFunc = origSocket
+	closeFunc = origClosesocket
+	connectFunc = origConnect
+	connectExFunc = origConnectEx
+	listenFunc = origListen
+}
+
+func forceCloseSockets() {
+	for s := range sw.Sockets() {
+		closeFunc(s)
+	}
+}
diff --git a/src/net/mockicmp_test.go b/src/net/mockicmp_test.go
deleted file mode 100644
index e742365..0000000
--- a/src/net/mockicmp_test.go
+++ /dev/null
@@ -1,116 +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 net
-
-import "errors"
-
-const (
-	icmpv4EchoRequest = 8
-	icmpv4EchoReply   = 0
-	icmpv6EchoRequest = 128
-	icmpv6EchoReply   = 129
-)
-
-// icmpMessage represents an ICMP message.
-type icmpMessage struct {
-	Type     int             // type
-	Code     int             // code
-	Checksum int             // checksum
-	Body     icmpMessageBody // body
-}
-
-// icmpMessageBody represents an ICMP message body.
-type icmpMessageBody interface {
-	Len() int
-	Marshal() ([]byte, error)
-}
-
-// Marshal returns the binary enconding of the ICMP echo request or
-// reply message m.
-func (m *icmpMessage) Marshal() ([]byte, error) {
-	b := []byte{byte(m.Type), byte(m.Code), 0, 0}
-	if m.Body != nil && m.Body.Len() != 0 {
-		mb, err := m.Body.Marshal()
-		if err != nil {
-			return nil, err
-		}
-		b = append(b, mb...)
-	}
-	switch m.Type {
-	case icmpv6EchoRequest, icmpv6EchoReply:
-		return b, nil
-	}
-	csumcv := len(b) - 1 // checksum coverage
-	s := uint32(0)
-	for i := 0; i < csumcv; i += 2 {
-		s += uint32(b[i+1])<<8 | uint32(b[i])
-	}
-	if csumcv&1 == 0 {
-		s += uint32(b[csumcv])
-	}
-	s = s>>16 + s&0xffff
-	s = s + s>>16
-	// Place checksum back in header; using ^= avoids the
-	// assumption the checksum bytes are zero.
-	b[2] ^= byte(^s)
-	b[3] ^= byte(^s >> 8)
-	return b, nil
-}
-
-// parseICMPMessage parses b as an ICMP message.
-func parseICMPMessage(b []byte) (*icmpMessage, error) {
-	msglen := len(b)
-	if msglen < 4 {
-		return nil, errors.New("message too short")
-	}
-	m := &icmpMessage{Type: int(b[0]), Code: int(b[1]), Checksum: int(b[2])<<8 | int(b[3])}
-	if msglen > 4 {
-		var err error
-		switch m.Type {
-		case icmpv4EchoRequest, icmpv4EchoReply, icmpv6EchoRequest, icmpv6EchoReply:
-			m.Body, err = parseICMPEcho(b[4:])
-			if err != nil {
-				return nil, err
-			}
-		}
-	}
-	return m, nil
-}
-
-// imcpEcho represenets an ICMP echo request or reply message body.
-type icmpEcho struct {
-	ID   int    // identifier
-	Seq  int    // sequence number
-	Data []byte // data
-}
-
-func (p *icmpEcho) Len() int {
-	if p == nil {
-		return 0
-	}
-	return 4 + len(p.Data)
-}
-
-// Marshal returns the binary enconding of the ICMP echo request or
-// reply message body p.
-func (p *icmpEcho) Marshal() ([]byte, error) {
-	b := make([]byte, 4+len(p.Data))
-	b[0], b[1] = byte(p.ID>>8), byte(p.ID)
-	b[2], b[3] = byte(p.Seq>>8), byte(p.Seq)
-	copy(b[4:], p.Data)
-	return b, nil
-}
-
-// parseICMPEcho parses b as an ICMP echo request or reply message
-// body.
-func parseICMPEcho(b []byte) (*icmpEcho, error) {
-	bodylen := len(b)
-	p := &icmpEcho{ID: int(b[0])<<8 | int(b[1]), Seq: int(b[2])<<8 | int(b[3])}
-	if bodylen > 4 {
-		p.Data = make([]byte, bodylen-4)
-		copy(p.Data, b[4:])
-	}
-	return p, nil
-}
diff --git a/src/net/mockserver_test.go b/src/net/mockserver_test.go
index 68ded5d..dd6f4df 100644
--- a/src/net/mockserver_test.go
+++ b/src/net/mockserver_test.go
@@ -4,11 +4,123 @@
 
 package net
 
-import "sync"
+import (
+	"errors"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"sync"
+	"testing"
+	"time"
+)
+
+// testUnixAddr uses ioutil.TempFile to get a name that is unique.
+// It also uses /tmp directory in case it is prohibited to create UNIX
+// sockets in TMPDIR.
+func testUnixAddr() string {
+	f, err := ioutil.TempFile("", "go-nettest")
+	if err != nil {
+		panic(err)
+	}
+	addr := f.Name()
+	f.Close()
+	os.Remove(addr)
+	return addr
+}
+
+func newLocalListener(network string) (Listener, error) {
+	switch network {
+	case "tcp", "tcp4", "tcp6":
+		if supportsIPv4 {
+			return Listen("tcp4", "127.0.0.1:0")
+		}
+		if supportsIPv6 {
+			return Listen("tcp6", "[::1]:0")
+		}
+	case "unix", "unixpacket":
+		return Listen(network, testUnixAddr())
+	}
+	return nil, fmt.Errorf("%s is not supported", network)
+}
+
+func newDualStackListener() (lns []*TCPListener, err error) {
+	var args = []struct {
+		network string
+		TCPAddr
+	}{
+		{"tcp4", TCPAddr{IP: IPv4(127, 0, 0, 1)}},
+		{"tcp6", TCPAddr{IP: IPv6loopback}},
+	}
+	for i := 0; i < 64; i++ {
+		var port int
+		var lns []*TCPListener
+		for _, arg := range args {
+			arg.TCPAddr.Port = port
+			ln, err := ListenTCP(arg.network, &arg.TCPAddr)
+			if err != nil {
+				continue
+			}
+			port = ln.Addr().(*TCPAddr).Port
+			lns = append(lns, ln)
+		}
+		if len(lns) != len(args) {
+			for _, ln := range lns {
+				ln.Close()
+			}
+			continue
+		}
+		return lns, nil
+	}
+	return nil, errors.New("no dualstack port available")
+}
+
+type localServer struct {
+	lnmu sync.RWMutex
+	Listener
+	done chan bool // signal that indicates server stopped
+}
+
+func (ls *localServer) buildup(handler func(*localServer, Listener)) error {
+	go func() {
+		handler(ls, ls.Listener)
+		close(ls.done)
+	}()
+	return nil
+}
+
+func (ls *localServer) teardown() error {
+	ls.lnmu.Lock()
+	if ls.Listener != nil {
+		network := ls.Listener.Addr().Network()
+		address := ls.Listener.Addr().String()
+		ls.Listener.Close()
+		<-ls.done
+		ls.Listener = nil
+		switch network {
+		case "unix", "unixpacket":
+			os.Remove(address)
+		}
+	}
+	ls.lnmu.Unlock()
+	return nil
+}
+
+func newLocalServer(network string) (*localServer, error) {
+	ln, err := newLocalListener(network)
+	if err != nil {
+		return nil, err
+	}
+	return &localServer{Listener: ln, done: make(chan bool)}, nil
+}
 
 type streamListener struct {
-	net, addr string
-	ln        Listener
+	network, address string
+	Listener
+	done chan bool // signal that indicates server stopped
+}
+
+func (sl *streamListener) newLocalServer() (*localServer, error) {
+	return &localServer{Listener: sl.Listener, done: make(chan bool)}, nil
 }
 
 type dualStackServer struct {
@@ -20,9 +132,12 @@ type dualStackServer struct {
 	cs  []Conn // established connections at the passive open side
 }
 
-func (dss *dualStackServer) buildup(server func(*dualStackServer, Listener)) error {
+func (dss *dualStackServer) buildup(handler func(*dualStackServer, Listener)) error {
 	for i := range dss.lns {
-		go server(dss, dss.lns[i].ln)
+		go func(i int) {
+			handler(dss, dss.lns[i].Listener)
+			close(dss.lns[i].done)
+		}(i)
 	}
 	return nil
 }
@@ -34,12 +149,13 @@ func (dss *dualStackServer) putConn(c Conn) error {
 	return nil
 }
 
-func (dss *dualStackServer) teardownNetwork(net string) error {
+func (dss *dualStackServer) teardownNetwork(network string) error {
 	dss.lnmu.Lock()
 	for i := range dss.lns {
-		if net == dss.lns[i].net && dss.lns[i].ln != nil {
-			dss.lns[i].ln.Close()
-			dss.lns[i].ln = nil
+		if network == dss.lns[i].network && dss.lns[i].Listener != nil {
+			dss.lns[i].Listener.Close()
+			<-dss.lns[i].done
+			dss.lns[i].Listener = nil
 		}
 	}
 	dss.lnmu.Unlock()
@@ -49,15 +165,18 @@ func (dss *dualStackServer) teardownNetwork(net string) error {
 func (dss *dualStackServer) teardown() error {
 	dss.lnmu.Lock()
 	for i := range dss.lns {
-		if dss.lns[i].ln != nil {
-			dss.lns[i].ln.Close()
+		if dss.lns[i].Listener != nil {
+			dss.lns[i].Listener.Close()
+			<-dss.lns[i].done
 		}
 	}
+	dss.lns = dss.lns[:0]
 	dss.lnmu.Unlock()
 	dss.cmu.Lock()
 	for _, c := range dss.cs {
 		c.Close()
 	}
+	dss.cs = dss.cs[:0]
 	dss.cmu.Unlock()
 	return nil
 }
@@ -65,18 +184,333 @@ func (dss *dualStackServer) teardown() error {
 func newDualStackServer(lns []streamListener) (*dualStackServer, error) {
 	dss := &dualStackServer{lns: lns, port: "0"}
 	for i := range dss.lns {
-		ln, err := Listen(dss.lns[i].net, dss.lns[i].addr+":"+dss.port)
+		ln, err := Listen(dss.lns[i].network, JoinHostPort(dss.lns[i].address, dss.port))
 		if err != nil {
-			dss.teardown()
+			for _, ln := range dss.lns[:i] {
+				ln.Listener.Close()
+			}
 			return nil, err
 		}
-		dss.lns[i].ln = ln
+		dss.lns[i].Listener = ln
+		dss.lns[i].done = make(chan bool)
 		if dss.port == "0" {
 			if _, dss.port, err = SplitHostPort(ln.Addr().String()); err != nil {
-				dss.teardown()
+				for _, ln := range dss.lns {
+					ln.Listener.Close()
+				}
 				return nil, err
 			}
 		}
 	}
 	return dss, nil
 }
+
+func transponder(ln Listener, ch chan<- error) {
+	defer close(ch)
+
+	switch ln := ln.(type) {
+	case *TCPListener:
+		ln.SetDeadline(time.Now().Add(someTimeout))
+	case *UnixListener:
+		ln.SetDeadline(time.Now().Add(someTimeout))
+	}
+	c, err := ln.Accept()
+	if err != nil {
+		if perr := parseAcceptError(err); perr != nil {
+			ch <- perr
+		}
+		ch <- err
+		return
+	}
+	defer c.Close()
+
+	network := ln.Addr().Network()
+	if c.LocalAddr().Network() != network || c.LocalAddr().Network() != network {
+		ch <- fmt.Errorf("got %v->%v; expected %v->%v", c.LocalAddr().Network(), c.RemoteAddr().Network(), network, network)
+		return
+	}
+	c.SetDeadline(time.Now().Add(someTimeout))
+	c.SetReadDeadline(time.Now().Add(someTimeout))
+	c.SetWriteDeadline(time.Now().Add(someTimeout))
+
+	b := make([]byte, 256)
+	n, err := c.Read(b)
+	if err != nil {
+		if perr := parseReadError(err); perr != nil {
+			ch <- perr
+		}
+		ch <- err
+		return
+	}
+	if _, err := c.Write(b[:n]); err != nil {
+		if perr := parseWriteError(err); perr != nil {
+			ch <- perr
+		}
+		ch <- err
+		return
+	}
+}
+
+func transceiver(c Conn, wb []byte, ch chan<- error) {
+	defer close(ch)
+
+	c.SetDeadline(time.Now().Add(someTimeout))
+	c.SetReadDeadline(time.Now().Add(someTimeout))
+	c.SetWriteDeadline(time.Now().Add(someTimeout))
+
+	n, err := c.Write(wb)
+	if err != nil {
+		if perr := parseWriteError(err); perr != nil {
+			ch <- perr
+		}
+		ch <- err
+		return
+	}
+	if n != len(wb) {
+		ch <- fmt.Errorf("wrote %d; want %d", n, len(wb))
+	}
+	rb := make([]byte, len(wb))
+	n, err = c.Read(rb)
+	if err != nil {
+		if perr := parseReadError(err); perr != nil {
+			ch <- perr
+		}
+		ch <- err
+		return
+	}
+	if n != len(wb) {
+		ch <- fmt.Errorf("read %d; want %d", n, len(wb))
+	}
+}
+
+func timeoutReceiver(c Conn, d, min, max time.Duration, ch chan<- error) {
+	var err error
+	defer func() { ch <- err }()
+
+	t0 := time.Now()
+	if err = c.SetReadDeadline(time.Now().Add(d)); err != nil {
+		return
+	}
+	b := make([]byte, 256)
+	var n int
+	n, err = c.Read(b)
+	t1 := time.Now()
+	if n != 0 || err == nil || !err.(Error).Timeout() {
+		err = fmt.Errorf("Read did not return (0, timeout): (%d, %v)", n, err)
+		return
+	}
+	if dt := t1.Sub(t0); min > dt || dt > max && !testing.Short() {
+		err = fmt.Errorf("Read took %s; expected %s", dt, d)
+		return
+	}
+}
+
+func timeoutTransmitter(c Conn, d, min, max time.Duration, ch chan<- error) {
+	var err error
+	defer func() { ch <- err }()
+
+	t0 := time.Now()
+	if err = c.SetWriteDeadline(time.Now().Add(d)); err != nil {
+		return
+	}
+	var n int
+	for {
+		n, err = c.Write([]byte("TIMEOUT TRANSMITTER"))
+		if err != nil {
+			break
+		}
+	}
+	t1 := time.Now()
+	if err == nil || !err.(Error).Timeout() {
+		err = fmt.Errorf("Write did not return (any, timeout): (%d, %v)", n, err)
+		return
+	}
+	if dt := t1.Sub(t0); min > dt || dt > max && !testing.Short() {
+		err = fmt.Errorf("Write took %s; expected %s", dt, d)
+		return
+	}
+}
+
+func newLocalPacketListener(network string) (PacketConn, error) {
+	switch network {
+	case "udp", "udp4", "udp6":
+		if supportsIPv4 {
+			return ListenPacket("udp4", "127.0.0.1:0")
+		}
+		if supportsIPv6 {
+			return ListenPacket("udp6", "[::1]:0")
+		}
+	case "unixgram":
+		return ListenPacket(network, testUnixAddr())
+	}
+	return nil, fmt.Errorf("%s is not supported", network)
+}
+
+func newDualStackPacketListener() (cs []*UDPConn, err error) {
+	var args = []struct {
+		network string
+		UDPAddr
+	}{
+		{"udp4", UDPAddr{IP: IPv4(127, 0, 0, 1)}},
+		{"udp6", UDPAddr{IP: IPv6loopback}},
+	}
+	for i := 0; i < 64; i++ {
+		var port int
+		var cs []*UDPConn
+		for _, arg := range args {
+			arg.UDPAddr.Port = port
+			c, err := ListenUDP(arg.network, &arg.UDPAddr)
+			if err != nil {
+				continue
+			}
+			port = c.LocalAddr().(*UDPAddr).Port
+			cs = append(cs, c)
+		}
+		if len(cs) != len(args) {
+			for _, c := range cs {
+				c.Close()
+			}
+			continue
+		}
+		return cs, nil
+	}
+	return nil, errors.New("no dualstack port available")
+}
+
+type localPacketServer struct {
+	pcmu sync.RWMutex
+	PacketConn
+	done chan bool // signal that indicates server stopped
+}
+
+func (ls *localPacketServer) buildup(handler func(*localPacketServer, PacketConn)) error {
+	go func() {
+		handler(ls, ls.PacketConn)
+		close(ls.done)
+	}()
+	return nil
+}
+
+func (ls *localPacketServer) teardown() error {
+	ls.pcmu.Lock()
+	if ls.PacketConn != nil {
+		network := ls.PacketConn.LocalAddr().Network()
+		address := ls.PacketConn.LocalAddr().String()
+		ls.PacketConn.Close()
+		<-ls.done
+		ls.PacketConn = nil
+		switch network {
+		case "unixgram":
+			os.Remove(address)
+		}
+	}
+	ls.pcmu.Unlock()
+	return nil
+}
+
+func newLocalPacketServer(network string) (*localPacketServer, error) {
+	c, err := newLocalPacketListener(network)
+	if err != nil {
+		return nil, err
+	}
+	return &localPacketServer{PacketConn: c, done: make(chan bool)}, nil
+}
+
+type packetListener struct {
+	PacketConn
+}
+
+func (pl *packetListener) newLocalServer() (*localPacketServer, error) {
+	return &localPacketServer{PacketConn: pl.PacketConn, done: make(chan bool)}, nil
+}
+
+func packetTransponder(c PacketConn, ch chan<- error) {
+	defer close(ch)
+
+	c.SetDeadline(time.Now().Add(someTimeout))
+	c.SetReadDeadline(time.Now().Add(someTimeout))
+	c.SetWriteDeadline(time.Now().Add(someTimeout))
+
+	b := make([]byte, 256)
+	n, peer, err := c.ReadFrom(b)
+	if err != nil {
+		if perr := parseReadError(err); perr != nil {
+			ch <- perr
+		}
+		ch <- err
+		return
+	}
+	if peer == nil { // for connected-mode sockets
+		switch c.LocalAddr().Network() {
+		case "udp":
+			peer, err = ResolveUDPAddr("udp", string(b[:n]))
+		case "unixgram":
+			peer, err = ResolveUnixAddr("unixgram", string(b[:n]))
+		}
+		if err != nil {
+			ch <- err
+			return
+		}
+	}
+	if _, err := c.WriteTo(b[:n], peer); err != nil {
+		if perr := parseWriteError(err); perr != nil {
+			ch <- perr
+		}
+		ch <- err
+		return
+	}
+}
+
+func packetTransceiver(c PacketConn, wb []byte, dst Addr, ch chan<- error) {
+	defer close(ch)
+
+	c.SetDeadline(time.Now().Add(someTimeout))
+	c.SetReadDeadline(time.Now().Add(someTimeout))
+	c.SetWriteDeadline(time.Now().Add(someTimeout))
+
+	n, err := c.WriteTo(wb, dst)
+	if err != nil {
+		if perr := parseWriteError(err); perr != nil {
+			ch <- perr
+		}
+		ch <- err
+		return
+	}
+	if n != len(wb) {
+		ch <- fmt.Errorf("wrote %d; want %d", n, len(wb))
+	}
+	rb := make([]byte, len(wb))
+	n, _, err = c.ReadFrom(rb)
+	if err != nil {
+		if perr := parseReadError(err); perr != nil {
+			ch <- perr
+		}
+		ch <- err
+		return
+	}
+	if n != len(wb) {
+		ch <- fmt.Errorf("read %d; want %d", n, len(wb))
+	}
+}
+
+func timeoutPacketReceiver(c PacketConn, d, min, max time.Duration, ch chan<- error) {
+	var err error
+	defer func() { ch <- err }()
+
+	t0 := time.Now()
+	if err = c.SetReadDeadline(time.Now().Add(d)); err != nil {
+		return
+	}
+	b := make([]byte, 256)
+	var n int
+	n, _, err = c.ReadFrom(b)
+	t1 := time.Now()
+	if n != 0 || err == nil || !err.(Error).Timeout() {
+		err = fmt.Errorf("ReadFrom did not return (0, timeout): (%d, %v)", n, err)
+		return
+	}
+	if dt := t1.Sub(t0); min > dt || dt > max && !testing.Short() {
+		err = fmt.Errorf("ReadFrom took %s; expected %s", dt, d)
+		return
+	}
+}
diff --git a/src/net/multicast_test.go b/src/net/multicast_test.go
deleted file mode 100644
index 5f253f4..0000000
--- a/src/net/multicast_test.go
+++ /dev/null
@@ -1,188 +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.
-
-package net
-
-import (
-	"fmt"
-	"os"
-	"runtime"
-	"testing"
-)
-
-var ipv4MulticastListenerTests = []struct {
-	net   string
-	gaddr *UDPAddr // see RFC 4727
-}{
-	{"udp", &UDPAddr{IP: IPv4(224, 0, 0, 254), Port: 12345}},
-
-	{"udp4", &UDPAddr{IP: IPv4(224, 0, 0, 254), Port: 12345}},
-}
-
-// TestIPv4MulticastListener tests both single and double listen to a
-// test listener with same address family, same group address and same
-// port.
-func TestIPv4MulticastListener(t *testing.T) {
-	switch runtime.GOOS {
-	case "android", "nacl", "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
-	case "solaris":
-		t.Skipf("skipping test on solaris, see issue 7399")
-	}
-
-	closer := func(cs []*UDPConn) {
-		for _, c := range cs {
-			if c != nil {
-				c.Close()
-			}
-		}
-	}
-
-	for _, ifi := range []*Interface{loopbackInterface(), nil} {
-		// Note that multicast interface assignment by system
-		// is not recommended because it usually relies on
-		// routing stuff for finding out an appropriate
-		// nexthop containing both network and link layer
-		// adjacencies.
-		if ifi == nil && !*testExternal {
-			continue
-		}
-		for _, tt := range ipv4MulticastListenerTests {
-			var err error
-			cs := make([]*UDPConn, 2)
-			if cs[0], err = ListenMulticastUDP(tt.net, ifi, tt.gaddr); err != nil {
-				t.Fatalf("First ListenMulticastUDP on %v failed: %v", ifi, err)
-			}
-			if err := checkMulticastListener(cs[0], tt.gaddr.IP); err != nil {
-				closer(cs)
-				t.Fatal(err)
-			}
-			if cs[1], err = ListenMulticastUDP(tt.net, ifi, tt.gaddr); err != nil {
-				closer(cs)
-				t.Fatalf("Second ListenMulticastUDP on %v failed: %v", ifi, err)
-			}
-			if err := checkMulticastListener(cs[1], tt.gaddr.IP); err != nil {
-				closer(cs)
-				t.Fatal(err)
-			}
-			closer(cs)
-		}
-	}
-}
-
-var ipv6MulticastListenerTests = []struct {
-	net   string
-	gaddr *UDPAddr // see RFC 4727
-}{
-	{"udp", &UDPAddr{IP: ParseIP("ff01::114"), Port: 12345}},
-	{"udp", &UDPAddr{IP: ParseIP("ff02::114"), Port: 12345}},
-	{"udp", &UDPAddr{IP: ParseIP("ff04::114"), Port: 12345}},
-	{"udp", &UDPAddr{IP: ParseIP("ff05::114"), Port: 12345}},
-	{"udp", &UDPAddr{IP: ParseIP("ff08::114"), Port: 12345}},
-	{"udp", &UDPAddr{IP: ParseIP("ff0e::114"), Port: 12345}},
-
-	{"udp6", &UDPAddr{IP: ParseIP("ff01::114"), Port: 12345}},
-	{"udp6", &UDPAddr{IP: ParseIP("ff02::114"), Port: 12345}},
-	{"udp6", &UDPAddr{IP: ParseIP("ff04::114"), Port: 12345}},
-	{"udp6", &UDPAddr{IP: ParseIP("ff05::114"), Port: 12345}},
-	{"udp6", &UDPAddr{IP: ParseIP("ff08::114"), Port: 12345}},
-	{"udp6", &UDPAddr{IP: ParseIP("ff0e::114"), Port: 12345}},
-}
-
-// TestIPv6MulticastListener tests both single and double listen to a
-// test listener with same address family, same group address and same
-// port.
-func TestIPv6MulticastListener(t *testing.T) {
-	switch runtime.GOOS {
-	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
-	case "solaris":
-		t.Skipf("skipping test on solaris, see issue 7399")
-	}
-	if !supportsIPv6 {
-		t.Skip("ipv6 is not supported")
-	}
-	if os.Getuid() != 0 {
-		t.Skip("skipping test; must be root")
-	}
-
-	closer := func(cs []*UDPConn) {
-		for _, c := range cs {
-			if c != nil {
-				c.Close()
-			}
-		}
-	}
-
-	for _, ifi := range []*Interface{loopbackInterface(), nil} {
-		// Note that multicast interface assignment by system
-		// is not recommended because it usually relies on
-		// routing stuff for finding out an appropriate
-		// nexthop containing both network and link layer
-		// adjacencies.
-		if ifi == nil && (!*testExternal || !*testIPv6) {
-			continue
-		}
-		for _, tt := range ipv6MulticastListenerTests {
-			var err error
-			cs := make([]*UDPConn, 2)
-			if cs[0], err = ListenMulticastUDP(tt.net, ifi, tt.gaddr); err != nil {
-				t.Fatalf("First ListenMulticastUDP on %v failed: %v", ifi, err)
-			}
-			if err := checkMulticastListener(cs[0], tt.gaddr.IP); err != nil {
-				closer(cs)
-				t.Fatal(err)
-			}
-			if cs[1], err = ListenMulticastUDP(tt.net, ifi, tt.gaddr); err != nil {
-				closer(cs)
-				t.Fatalf("Second ListenMulticastUDP on %v failed: %v", ifi, err)
-			}
-			if err := checkMulticastListener(cs[1], tt.gaddr.IP); err != nil {
-				closer(cs)
-				t.Fatal(err)
-			}
-			closer(cs)
-		}
-	}
-}
-
-func checkMulticastListener(c *UDPConn, ip IP) error {
-	if ok, err := multicastRIBContains(ip); err != nil {
-		return err
-	} else if !ok {
-		return fmt.Errorf("%q not found in multicast RIB", ip.String())
-	}
-	la := c.LocalAddr()
-	if la, ok := la.(*UDPAddr); !ok || la.Port == 0 {
-		return fmt.Errorf("got %v; expected a proper address with non-zero port number", la)
-	}
-	return nil
-}
-
-func multicastRIBContains(ip IP) (bool, error) {
-	switch runtime.GOOS {
-	case "dragonfly", "netbsd", "openbsd", "plan9", "solaris", "windows":
-		return true, nil // not implemented yet
-	case "linux":
-		if runtime.GOARCH == "arm" || runtime.GOARCH == "alpha" {
-			return true, nil // not implemented yet
-		}
-	}
-	ift, err := Interfaces()
-	if err != nil {
-		return false, err
-	}
-	for _, ifi := range ift {
-		ifmat, err := ifi.MulticastAddrs()
-		if err != nil {
-			return false, err
-		}
-		for _, ifma := range ifmat {
-			if ifma.(*IPAddr).IP.Equal(ip) {
-				return true, nil
-			}
-		}
-	}
-	return false, nil
-}
diff --git a/src/net/net.go b/src/net/net.go
index cb31af5..6e84c3a 100644
--- a/src/net/net.go
+++ b/src/net/net.go
@@ -35,12 +35,49 @@ The Listen function creates servers:
 		}
 		go handleConnection(conn)
 	}
+
+Name Resolution
+
+The method for resolving domain names, whether indirectly with functions like Dial
+or directly with functions like LookupHost and LookupAddr, varies by operating system.
+
+On Unix systems, the resolver has two options for resolving names.
+It can use a pure Go resolver that sends DNS requests directly to the servers
+listed in /etc/resolv.conf, or it can use a cgo-based resolver that calls C
+library routines such as getaddrinfo and getnameinfo.
+
+By default the pure Go resolver is used, because a blocked DNS request consumes
+only a goroutine, while a blocked C call consumes an operating system thread.
+When cgo is available, the cgo-based resolver is used instead under a variety of
+conditions: on systems that do not let programs make direct DNS requests (OS X),
+when the LOCALDOMAIN environment variable is present (even if empty),
+when the RES_OPTIONS or HOSTALIASES environment variable is non-empty,
+when the ASR_CONFIG environment variable is non-empty (OpenBSD only),
+when /etc/resolv.conf or /etc/nsswitch.conf specify the use of features that the
+Go resolver does not implement, and when the name being looked up ends in .local
+or is an mDNS name.
+
+The resolver decision can be overridden by setting the netdns value of the
+GODEBUG environment variable (see package runtime) to go or cgo, as in:
+
+	export GODEBUG=netdns=go    # force pure Go resolver
+	export GODEBUG=netdns=cgo   # force cgo resolver
+
+The decision can also be forced while building the Go source tree
+by setting the netgo or netcgo build tag.
+
+A numeric netdns setting, as in GODEBUG=netdns=1, causes the resolver
+to print debugging information about its decisions.
+To force a particular resolver while also printing debugging information,
+join the two settings by a plus sign, as in GODEBUG=netdns=go+1.
+
+On Plan 9, the resolver always accesses /net/cs and /net/dns.
+
+On Windows, the resolver always uses C library functions, such as GetAddrInfo and DnsQuery.
+
 */
 package net
 
-// TODO(rsc):
-//	support for raw ethernet sockets
-
 import (
 	"errors"
 	"io"
@@ -49,6 +86,20 @@ import (
 	"time"
 )
 
+// netGo and netCgo contain the state of the build tags used
+// to build this binary, and whether cgo is available.
+// conf.go mirrors these into conf for easier testing.
+var (
+	netGo  bool // set true in cgo_stub.go for build tag "netgo" (or no cgo)
+	netCgo bool // set true in conf_netcgo.go for build tag "netcgo"
+)
+
+func init() {
+	sysInit()
+	supportsIPv4 = probeIPv4Stack()
+	supportsIPv6, supportsIPv4map = probeIPv6Stack()
+}
+
 // Addr represents a network end point address.
 type Addr interface {
 	Network() string // name of the network
@@ -118,7 +169,11 @@ func (c *conn) Read(b []byte) (int, error) {
 	if !c.ok() {
 		return 0, syscall.EINVAL
 	}
-	return c.fd.Read(b)
+	n, err := c.fd.Read(b)
+	if err != nil && err != io.EOF {
+		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return n, err
 }
 
 // Write implements the Conn Write method.
@@ -126,7 +181,11 @@ func (c *conn) Write(b []byte) (int, error) {
 	if !c.ok() {
 		return 0, syscall.EINVAL
 	}
-	return c.fd.Write(b)
+	n, err := c.fd.Write(b)
+	if err != nil {
+		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return n, err
 }
 
 // Close closes the connection.
@@ -134,10 +193,16 @@ func (c *conn) Close() error {
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	return c.fd.Close()
+	err := c.fd.Close()
+	if err != nil {
+		err = &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return err
 }
 
 // LocalAddr returns the local network address.
+// The Addr returned is shared by all invocations of LocalAddr, so
+// do not modify it.
 func (c *conn) LocalAddr() Addr {
 	if !c.ok() {
 		return nil
@@ -146,6 +211,8 @@ func (c *conn) LocalAddr() Addr {
 }
 
 // RemoteAddr returns the remote network address.
+// The Addr returned is shared by all invocations of RemoteAddr, so
+// do not modify it.
 func (c *conn) RemoteAddr() Addr {
 	if !c.ok() {
 		return nil
@@ -158,7 +225,10 @@ func (c *conn) SetDeadline(t time.Time) error {
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	return c.fd.setDeadline(t)
+	if err := c.fd.setDeadline(t); err != nil {
+		return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
+	}
+	return nil
 }
 
 // SetReadDeadline implements the Conn SetReadDeadline method.
@@ -166,7 +236,10 @@ func (c *conn) SetReadDeadline(t time.Time) error {
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	return c.fd.setReadDeadline(t)
+	if err := c.fd.setReadDeadline(t); err != nil {
+		return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
+	}
+	return nil
 }
 
 // SetWriteDeadline implements the Conn SetWriteDeadline method.
@@ -174,7 +247,10 @@ func (c *conn) SetWriteDeadline(t time.Time) error {
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	return c.fd.setWriteDeadline(t)
+	if err := c.fd.setWriteDeadline(t); err != nil {
+		return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
+	}
+	return nil
 }
 
 // SetReadBuffer sets the size of the operating system's
@@ -183,7 +259,10 @@ func (c *conn) SetReadBuffer(bytes int) error {
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	return setReadBuffer(c.fd, bytes)
+	if err := setReadBuffer(c.fd, bytes); err != nil {
+		return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
+	}
+	return nil
 }
 
 // SetWriteBuffer sets the size of the operating system's
@@ -192,7 +271,10 @@ func (c *conn) SetWriteBuffer(bytes int) error {
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	return setWriteBuffer(c.fd, bytes)
+	if err := setWriteBuffer(c.fd, bytes); err != nil {
+		return &OpError{Op: "set", Net: c.fd.net, Source: nil, Addr: c.fd.laddr, Err: err}
+	}
+	return nil
 }
 
 // File sets the underlying os.File to blocking mode and returns a copy.
@@ -202,13 +284,12 @@ func (c *conn) SetWriteBuffer(bytes int) error {
 // The returned os.File's file descriptor is different from the connection's.
 // Attempting to change properties of the original using this duplicate
 // may or may not have the desired effect.
-func (c *conn) File() (f *os.File, err error) { return c.fd.dup() }
-
-// An Error represents a network error.
-type Error interface {
-	error
-	Timeout() bool   // Is the error a timeout?
-	Temporary() bool // Is the error temporary?
+func (c *conn) File() (f *os.File, err error) {
+	f, err = c.fd.dup()
+	if err != nil {
+		err = &OpError{Op: "file", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return
 }
 
 // PacketConn is a generic packet-oriented network connection.
@@ -274,6 +355,13 @@ type Listener interface {
 	Addr() Addr
 }
 
+// An Error represents a network error.
+type Error interface {
+	error
+	Timeout() bool   // Is the error a timeout?
+	Temporary() bool // Is the error temporary?
+}
+
 // Various errors contained in OpError.
 var (
 	// For connection setup and write operations.
@@ -281,6 +369,7 @@ var (
 
 	// For both read and write operations.
 	errTimeout          error = &timeoutError{}
+	errCanceled               = errors.New("operation was canceled")
 	errClosing                = errors.New("use of closed network connection")
 	ErrWriteToConnected       = errors.New("use of WriteTo with pre-connected connection")
 )
@@ -297,7 +386,17 @@ type OpError struct {
 	// such as "tcp" or "udp6".
 	Net string
 
-	// Addr is the network address on which this error occurred.
+	// For operations involving a remote network connection, like
+	// Dial, Read, or Write, Source is the corresponding local
+	// network address.
+	Source Addr
+
+	// Addr is the network address for which this error occurred.
+	// For local operations, like Listen or SetDeadline, Addr is
+	// the address of the local endpoint being manipulated.
+	// For operations involving a remote network connection, like
+	// Dial, Read, or Write, Addr is the remote address of that
+	// connection.
 	Addr Addr
 
 	// Err is the error that occurred during the operation.
@@ -312,22 +411,21 @@ func (e *OpError) Error() string {
 	if e.Net != "" {
 		s += " " + e.Net
 	}
+	if e.Source != nil {
+		s += " " + e.Source.String()
+	}
 	if e.Addr != nil {
-		s += " " + e.Addr.String()
+		if e.Source != nil {
+			s += "->"
+		} else {
+			s += " "
+		}
+		s += e.Addr.String()
 	}
 	s += ": " + e.Err.Error()
 	return s
 }
 
-type temporary interface {
-	Temporary() bool
-}
-
-func (e *OpError) Temporary() bool {
-	t, ok := e.Err.(temporary)
-	return ok && t.Temporary()
-}
-
 var noDeadline = time.Time{}
 
 type timeout interface {
@@ -335,16 +433,45 @@ type timeout interface {
 }
 
 func (e *OpError) Timeout() bool {
+	if ne, ok := e.Err.(*os.SyscallError); ok {
+		t, ok := ne.Err.(timeout)
+		return ok && t.Timeout()
+	}
 	t, ok := e.Err.(timeout)
 	return ok && t.Timeout()
 }
 
+type temporary interface {
+	Temporary() bool
+}
+
+func (e *OpError) Temporary() bool {
+	if ne, ok := e.Err.(*os.SyscallError); ok {
+		t, ok := ne.Err.(temporary)
+		return ok && t.Temporary()
+	}
+	t, ok := e.Err.(temporary)
+	return ok && t.Temporary()
+}
+
 type timeoutError struct{}
 
 func (e *timeoutError) Error() string   { return "i/o timeout" }
 func (e *timeoutError) Timeout() bool   { return true }
 func (e *timeoutError) Temporary() bool { return true }
 
+// A ParseError is the error type of literal network address parsers.
+type ParseError struct {
+	// Type is the type of string that was expected, such as
+	// "IP address", "CIDR address".
+	Type string
+
+	// Text is the malformed text string.
+	Text string
+}
+
+func (e *ParseError) Error() string { return "invalid " + e.Type + ": " + e.Text }
+
 type AddrError struct {
 	Err  string
 	Addr string
@@ -361,19 +488,14 @@ func (e *AddrError) Error() string {
 	return s
 }
 
-func (e *AddrError) Temporary() bool {
-	return false
-}
-
-func (e *AddrError) Timeout() bool {
-	return false
-}
+func (e *AddrError) Timeout() bool   { return false }
+func (e *AddrError) Temporary() bool { return false }
 
 type UnknownNetworkError string
 
 func (e UnknownNetworkError) Error() string   { return "unknown network " + string(e) }
-func (e UnknownNetworkError) Temporary() bool { return false }
 func (e UnknownNetworkError) Timeout() bool   { return false }
+func (e UnknownNetworkError) Temporary() bool { return false }
 
 type InvalidAddrError string
 
@@ -382,17 +504,50 @@ func (e InvalidAddrError) Timeout() bool   { return false }
 func (e InvalidAddrError) Temporary() bool { return false }
 
 // DNSConfigError represents an error reading the machine's DNS configuration.
+// (No longer used; kept for compatibility.)
 type DNSConfigError struct {
 	Err error
 }
 
-func (e *DNSConfigError) Error() string {
-	return "error reading DNS config: " + e.Err.Error()
-}
-
+func (e *DNSConfigError) Error() string   { return "error reading DNS config: " + e.Err.Error() }
 func (e *DNSConfigError) Timeout() bool   { return false }
 func (e *DNSConfigError) Temporary() bool { return false }
 
+// Various errors contained in DNSError.
+var (
+	errNoSuchHost = errors.New("no such host")
+)
+
+// DNSError represents a DNS lookup error.
+type DNSError struct {
+	Err       string // description of the error
+	Name      string // name looked for
+	Server    string // server used
+	IsTimeout bool   // if true, timed out; not all timeouts set this
+}
+
+func (e *DNSError) Error() string {
+	if e == nil {
+		return "<nil>"
+	}
+	s := "lookup " + e.Name
+	if e.Server != "" {
+		s += " on " + e.Server
+	}
+	s += ": " + e.Err
+	return s
+}
+
+// Timeout reports whether the DNS lookup is known to have timed out.
+// This is not always known; a DNS lookup may fail due to a timeout
+// and return a DNSError for which Timeout returns false.
+func (e *DNSError) Timeout() bool { return e.IsTimeout }
+
+// Temporary reports whether the DNS error is known to be temporary.
+// This is not always known; a DNS lookup may fail due to a temporary
+// error and return a DNSError for which Temporary returns false.
+func (e *DNSError) Temporary() bool { return e.IsTimeout }
+
 type writerOnly struct {
 	io.Writer
 }
@@ -412,10 +567,6 @@ func genericReadFrom(w io.Writer, r io.Reader) (n int64, err error) {
 
 var threadLimit = make(chan struct{}, 500)
 
-// Using send for acquire is fine here because we are not using this
-// to protect any memory. All we care about is the number of goroutines
-// making calls at a time.
-
 func acquireThread() {
 	threadLimit <- struct{}{}
 }
diff --git a/src/net/net_test.go b/src/net/net_test.go
index bfed4d6..3907ce4 100644
--- a/src/net/net_test.go
+++ b/src/net/net_test.go
@@ -6,258 +6,251 @@ package net
 
 import (
 	"io"
-	"io/ioutil"
 	"os"
 	"runtime"
 	"testing"
-	"time"
 )
 
-func TestShutdown(t *testing.T) {
-	if runtime.GOOS == "plan9" {
-		t.Skipf("skipping test on %q", runtime.GOOS)
+func TestCloseRead(t *testing.T) {
+	switch runtime.GOOS {
+	case "nacl", "plan9":
+		t.Skipf("not supported on %s", runtime.GOOS)
 	}
-	ln, err := Listen("tcp", "127.0.0.1:0")
-	if err != nil {
-		if ln, err = Listen("tcp6", "[::1]:0"); err != nil {
-			t.Fatalf("ListenTCP on :0: %v", err)
+
+	for _, network := range []string{"tcp", "unix", "unixpacket"} {
+		if !testableNetwork(network) {
+			t.Logf("skipping %s test", network)
+			continue
 		}
-	}
 
-	go func() {
-		defer ln.Close()
-		c, err := ln.Accept()
+		ln, err := newLocalListener(network)
 		if err != nil {
-			t.Errorf("Accept: %v", err)
-			return
+			t.Fatal(err)
 		}
-		var buf [10]byte
-		n, err := c.Read(buf[:])
-		if n != 0 || err != io.EOF {
-			t.Errorf("server Read = %d, %v; want 0, io.EOF", n, err)
-			return
+		switch network {
+		case "unix", "unixpacket":
+			defer os.Remove(ln.Addr().String())
 		}
-		c.Write([]byte("response"))
-		c.Close()
-	}()
+		defer ln.Close()
 
-	c, err := Dial("tcp", ln.Addr().String())
-	if err != nil {
-		t.Fatalf("Dial: %v", err)
-	}
-	defer c.Close()
+		c, err := Dial(ln.Addr().Network(), ln.Addr().String())
+		if err != nil {
+			t.Fatal(err)
+		}
+		switch network {
+		case "unix", "unixpacket":
+			defer os.Remove(c.LocalAddr().String())
+		}
+		defer c.Close()
 
-	err = c.(*TCPConn).CloseWrite()
-	if err != nil {
-		t.Fatalf("CloseWrite: %v", err)
-	}
-	var buf [10]byte
-	n, err := c.Read(buf[:])
-	if err != nil {
-		t.Fatalf("client Read: %d, %v", n, err)
-	}
-	got := string(buf[:n])
-	if got != "response" {
-		t.Errorf("read = %q, want \"response\"", got)
+		switch c := c.(type) {
+		case *TCPConn:
+			err = c.CloseRead()
+		case *UnixConn:
+			err = c.CloseRead()
+		}
+		if err != nil {
+			if perr := parseCloseError(err); perr != nil {
+				t.Error(perr)
+			}
+			t.Fatal(err)
+		}
+		var b [1]byte
+		n, err := c.Read(b[:])
+		if n != 0 || err == nil {
+			t.Fatalf("got (%d, %v); want (0, error)", n, err)
+		}
 	}
 }
 
-func TestShutdownUnix(t *testing.T) {
+func TestCloseWrite(t *testing.T) {
 	switch runtime.GOOS {
-	case "nacl", "plan9", "windows":
-		t.Skipf("skipping test on %q", runtime.GOOS)
+	case "nacl", "plan9":
+		t.Skipf("not supported on %s", runtime.GOOS)
 	}
-	f, err := ioutil.TempFile("", "go_net_unixtest")
-	if err != nil {
-		t.Fatalf("TempFile: %s", err)
-	}
-	f.Close()
-	tmpname := f.Name()
-	os.Remove(tmpname)
-	ln, err := Listen("unix", tmpname)
-	if err != nil {
-		t.Fatalf("ListenUnix on %s: %s", tmpname, err)
-	}
-	defer func() {
-		ln.Close()
-		os.Remove(tmpname)
-	}()
 
-	go func() {
+	handler := func(ls *localServer, ln Listener) {
 		c, err := ln.Accept()
 		if err != nil {
-			t.Errorf("Accept: %v", err)
+			t.Error(err)
 			return
 		}
-		var buf [10]byte
-		n, err := c.Read(buf[:])
+		defer c.Close()
+
+		var b [1]byte
+		n, err := c.Read(b[:])
 		if n != 0 || err != io.EOF {
-			t.Errorf("server Read = %d, %v; want 0, io.EOF", n, err)
+			t.Errorf("got (%d, %v); want (0, io.EOF)", n, err)
+			return
+		}
+		switch c := c.(type) {
+		case *TCPConn:
+			err = c.CloseWrite()
+		case *UnixConn:
+			err = c.CloseWrite()
+		}
+		if err != nil {
+			if perr := parseCloseError(err); perr != nil {
+				t.Error(perr)
+			}
+			t.Error(err)
+			return
+		}
+		n, err = c.Write(b[:])
+		if err == nil {
+			t.Errorf("got (%d, %v); want (any, error)", n, err)
 			return
 		}
-		c.Write([]byte("response"))
-		c.Close()
-	}()
-
-	c, err := Dial("unix", tmpname)
-	if err != nil {
-		t.Fatalf("Dial: %v", err)
-	}
-	defer c.Close()
-
-	err = c.(*UnixConn).CloseWrite()
-	if err != nil {
-		t.Fatalf("CloseWrite: %v", err)
-	}
-	var buf [10]byte
-	n, err := c.Read(buf[:])
-	if err != nil {
-		t.Fatalf("client Read: %d, %v", n, err)
-	}
-	got := string(buf[:n])
-	if got != "response" {
-		t.Errorf("read = %q, want \"response\"", got)
 	}
-}
 
-func TestTCPListenClose(t *testing.T) {
-	ln, err := Listen("tcp", "127.0.0.1:0")
-	if err != nil {
-		t.Fatalf("Listen failed: %v", err)
-	}
+	for _, network := range []string{"tcp", "unix", "unixpacket"} {
+		if !testableNetwork(network) {
+			t.Logf("skipping %s test", network)
+			continue
+		}
 
-	done := make(chan bool, 1)
-	go func() {
-		time.Sleep(100 * time.Millisecond)
-		ln.Close()
-	}()
-	go func() {
-		c, err := ln.Accept()
-		if err == nil {
-			c.Close()
-			t.Error("Accept succeeded")
-		} else {
-			t.Logf("Accept timeout error: %s (any error is fine)", err)
-		}
-		done <- true
-	}()
-	select {
-	case <-done:
-	case <-time.After(2 * time.Second):
-		t.Fatal("timeout waiting for TCP close")
-	}
-}
+		ls, err := newLocalServer(network)
+		if err != nil {
+			t.Fatal(err)
+		}
+		defer ls.teardown()
+		if err := ls.buildup(handler); err != nil {
+			t.Fatal(err)
+		}
 
-func TestUDPListenClose(t *testing.T) {
-	switch runtime.GOOS {
-	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
-	}
-	ln, err := ListenPacket("udp", "127.0.0.1:0")
-	if err != nil {
-		t.Fatalf("Listen failed: %v", err)
-	}
+		c, err := Dial(ls.Listener.Addr().Network(), ls.Listener.Addr().String())
+		if err != nil {
+			t.Fatal(err)
+		}
+		switch network {
+		case "unix", "unixpacket":
+			defer os.Remove(c.LocalAddr().String())
+		}
+		defer c.Close()
 
-	buf := make([]byte, 1000)
-	done := make(chan bool, 1)
-	go func() {
-		time.Sleep(100 * time.Millisecond)
-		ln.Close()
-	}()
-	go func() {
-		_, _, err = ln.ReadFrom(buf)
+		switch c := c.(type) {
+		case *TCPConn:
+			err = c.CloseWrite()
+		case *UnixConn:
+			err = c.CloseWrite()
+		}
+		if err != nil {
+			if perr := parseCloseError(err); perr != nil {
+				t.Error(perr)
+			}
+			t.Fatal(err)
+		}
+		var b [1]byte
+		n, err := c.Read(b[:])
+		if n != 0 || err != io.EOF {
+			t.Fatalf("got (%d, %v); want (0, io.EOF)", n, err)
+		}
+		n, err = c.Write(b[:])
 		if err == nil {
-			t.Error("ReadFrom succeeded")
-		} else {
-			t.Logf("ReadFrom timeout error: %s (any error is fine)", err)
-		}
-		done <- true
-	}()
-	select {
-	case <-done:
-	case <-time.After(2 * time.Second):
-		t.Fatal("timeout waiting for UDP close")
+			t.Fatalf("got (%d, %v); want (any, error)", n, err)
+		}
 	}
 }
 
-func TestTCPClose(t *testing.T) {
-	switch runtime.GOOS {
-	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
-	}
-	l, err := Listen("tcp", "127.0.0.1:0")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer l.Close()
+func TestConnClose(t *testing.T) {
+	for _, network := range []string{"tcp", "unix", "unixpacket"} {
+		if !testableNetwork(network) {
+			t.Logf("skipping %s test", network)
+			continue
+		}
 
-	read := func(r io.Reader) error {
-		var m [1]byte
-		_, err := r.Read(m[:])
-		return err
-	}
+		ln, err := newLocalListener(network)
+		if err != nil {
+			t.Fatal(err)
+		}
+		switch network {
+		case "unix", "unixpacket":
+			defer os.Remove(ln.Addr().String())
+		}
+		defer ln.Close()
 
-	go func() {
-		c, err := Dial("tcp", l.Addr().String())
+		c, err := Dial(ln.Addr().Network(), ln.Addr().String())
 		if err != nil {
-			t.Errorf("Dial: %v", err)
-			return
+			t.Fatal(err)
 		}
+		switch network {
+		case "unix", "unixpacket":
+			defer os.Remove(c.LocalAddr().String())
+		}
+		defer c.Close()
 
-		go read(c)
+		if err := c.Close(); err != nil {
+			if perr := parseCloseError(err); perr != nil {
+				t.Error(perr)
+			}
+			t.Fatal(err)
+		}
+		var b [1]byte
+		n, err := c.Read(b[:])
+		if n != 0 || err == nil {
+			t.Fatalf("got (%d, %v); want (0, error)", n, err)
+		}
+	}
+}
 
-		time.Sleep(10 * time.Millisecond)
-		c.Close()
-	}()
+func TestListenerClose(t *testing.T) {
+	for _, network := range []string{"tcp", "unix", "unixpacket"} {
+		if !testableNetwork(network) {
+			t.Logf("skipping %s test", network)
+			continue
+		}
 
-	c, err := l.Accept()
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer c.Close()
+		ln, err := newLocalListener(network)
+		if err != nil {
+			t.Fatal(err)
+		}
+		switch network {
+		case "unix", "unixpacket":
+			defer os.Remove(ln.Addr().String())
+		}
+		defer ln.Close()
 
-	for err == nil {
-		err = read(c)
-	}
-	if err != nil && err != io.EOF {
-		t.Fatal(err)
+		if err := ln.Close(); err != nil {
+			if perr := parseCloseError(err); perr != nil {
+				t.Error(perr)
+			}
+			t.Fatal(err)
+		}
+		c, err := ln.Accept()
+		if err == nil {
+			c.Close()
+			t.Fatal("should fail")
+		}
 	}
 }
 
-func TestErrorNil(t *testing.T) {
-	c, err := Dial("tcp", "127.0.0.1:65535")
-	if err == nil {
-		t.Fatal("Dial 127.0.0.1:65535 succeeded")
-	}
-	if c != nil {
-		t.Fatalf("Dial returned non-nil interface %T(%v) with err != nil", c, c)
-	}
+func TestPacketConnClose(t *testing.T) {
+	for _, network := range []string{"udp", "unixgram"} {
+		if !testableNetwork(network) {
+			t.Logf("skipping %s test", network)
+			continue
+		}
 
-	// Make Listen fail by relistening on the same address.
-	l, err := Listen("tcp", "127.0.0.1:0")
-	if err != nil {
-		t.Fatalf("Listen 127.0.0.1:0: %v", err)
-	}
-	defer l.Close()
-	l1, err := Listen("tcp", l.Addr().String())
-	if err == nil {
-		t.Fatalf("second Listen %v: %v", l.Addr(), err)
-	}
-	if l1 != nil {
-		t.Fatalf("Listen returned non-nil interface %T(%v) with err != nil", l1, l1)
-	}
+		c, err := newLocalPacketListener(network)
+		if err != nil {
+			t.Fatal(err)
+		}
+		switch network {
+		case "unixgram":
+			defer os.Remove(c.LocalAddr().String())
+		}
+		defer c.Close()
 
-	// Make ListenPacket fail by relistening on the same address.
-	lp, err := ListenPacket("udp", "127.0.0.1:0")
-	if err != nil {
-		t.Fatalf("Listen 127.0.0.1:0: %v", err)
-	}
-	defer lp.Close()
-	lp1, err := ListenPacket("udp", lp.LocalAddr().String())
-	if err == nil {
-		t.Fatalf("second Listen %v: %v", lp.LocalAddr(), err)
-	}
-	if lp1 != nil {
-		t.Fatalf("ListenPacket returned non-nil interface %T(%v) with err != nil", lp1, lp1)
+		if err := c.Close(); err != nil {
+			if perr := parseCloseError(err); perr != nil {
+				t.Error(perr)
+			}
+			t.Fatal(err)
+		}
+		var b [1]byte
+		n, _, err := c.ReadFrom(b[:])
+		if n != 0 || err == nil {
+			t.Fatalf("got (%d, %v); want (0, error)", n, err)
+		}
 	}
 }
diff --git a/src/net/net_windows_test.go b/src/net/net_windows_test.go
index 750a430..da03e10 100644
--- a/src/net/net_windows_test.go
+++ b/src/net/net_windows_test.go
@@ -15,18 +15,31 @@ import (
 	"time"
 )
 
-func TestAcceptIgnoreSomeErrors(t *testing.T) {
-	t.Skip("skipping temporarily, see issue 8662")
+func toErrno(err error) (syscall.Errno, bool) {
+	operr, ok := err.(*OpError)
+	if !ok {
+		return 0, false
+	}
+	syserr, ok := operr.Err.(*os.SyscallError)
+	if !ok {
+		return 0, false
+	}
+	errno, ok := syserr.Err.(syscall.Errno)
+	if !ok {
+		return 0, false
+	}
+	return errno, true
+}
 
-	recv := func(ln Listener) (string, error) {
+// TestAcceptIgnoreSomeErrors tests that windows TCPListener.AcceptTCP
+// handles broken connections. It verifies that broken connections do
+// not affect future connections.
+func TestAcceptIgnoreSomeErrors(t *testing.T) {
+	recv := func(ln Listener, ignoreSomeReadErrors bool) (string, error) {
 		c, err := ln.Accept()
 		if err != nil {
 			// Display windows errno in error message.
-			operr, ok := err.(*OpError)
-			if !ok {
-				return "", err
-			}
-			errno, ok := operr.Err.(syscall.Errno)
+			errno, ok := toErrno(err)
 			if !ok {
 				return "", err
 			}
@@ -36,10 +49,14 @@ func TestAcceptIgnoreSomeErrors(t *testing.T) {
 
 		b := make([]byte, 100)
 		n, err := c.Read(b)
-		if err != nil && err != io.EOF {
-			return "", err
+		if err == nil || err == io.EOF {
+			return string(b[:n]), nil
+		}
+		errno, ok := toErrno(err)
+		if ok && ignoreSomeReadErrors && (errno == syscall.ERROR_NETNAME_DELETED || errno == syscall.WSAECONNRESET) {
+			return "", nil
 		}
-		return string(b[:n]), nil
+		return "", err
 	}
 
 	send := func(addr string, data string) error {
@@ -64,7 +81,7 @@ func TestAcceptIgnoreSomeErrors(t *testing.T) {
 		// In child process.
 		c, err := Dial("tcp", envaddr)
 		if err != nil {
-			t.Fatalf("Dial failed: %v", err)
+			t.Fatal(err)
 		}
 		fmt.Printf("sleeping\n")
 		time.Sleep(time.Minute) // process will be killed here
@@ -73,7 +90,7 @@ func TestAcceptIgnoreSomeErrors(t *testing.T) {
 
 	ln, err := Listen("tcp", "127.0.0.1:0")
 	if err != nil {
-		t.Fatalf("Listen failed: %v", err)
+		t.Fatal(err)
 	}
 	defer ln.Close()
 
@@ -123,13 +140,13 @@ func TestAcceptIgnoreSomeErrors(t *testing.T) {
 	}()
 
 	// Receive first or second connection.
-	s, err := recv(ln)
+	s, err := recv(ln, true)
 	if err != nil {
 		t.Fatalf("recv failed: %v", err)
 	}
 	switch s {
 	case "":
-		// First connection data is received, lets get second connection data.
+		// First connection data is received, let's get second connection data.
 	case "abc":
 		// First connection is lost forever, but that is ok.
 		return
@@ -138,7 +155,7 @@ func TestAcceptIgnoreSomeErrors(t *testing.T) {
 	}
 
 	// Get second connection data.
-	s, err = recv(ln)
+	s, err = recv(ln, false)
 	if err != nil {
 		t.Fatalf("recv failed: %v", err)
 	}
diff --git a/src/net/netgo_unix_test.go b/src/net/netgo_unix_test.go
index 9fb2a56..1d950d6 100644
--- a/src/net/netgo_unix_test.go
+++ b/src/net/netgo_unix_test.go
@@ -16,9 +16,9 @@ func TestGoLookupIP(t *testing.T) {
 		t.Errorf("cgoLookupIP must be a placeholder")
 	}
 	if err != nil {
-		t.Errorf("cgoLookupIP failed: %v", err)
+		t.Error(err)
 	}
 	if _, err := goLookupIP(host); err != nil {
-		t.Errorf("goLookupIP failed: %v", err)
+		t.Error(err)
 	}
 }
diff --git a/src/net/non_unix_test.go b/src/net/non_unix_test.go
new file mode 100644
index 0000000..eddca56
--- /dev/null
+++ b/src/net/non_unix_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.
+
+// +build nacl plan9 windows
+
+package net
+
+// See unix_test.go for what these (don't) do.
+func forceGoDNS() func() { return func() {} }
+func forceCgoDNS() bool  { return false }
diff --git a/src/net/nss.go b/src/net/nss.go
new file mode 100644
index 0000000..08c3e6a
--- /dev/null
+++ b/src/net/nss.go
@@ -0,0 +1,159 @@
+// 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 net
+
+import (
+	"errors"
+	"io"
+	"os"
+)
+
+// nssConf represents the state of the machine's /etc/nsswitch.conf file.
+type nssConf struct {
+	err     error                  // any error encountered opening or parsing the file
+	sources map[string][]nssSource // keyed by database (e.g. "hosts")
+}
+
+type nssSource struct {
+	source   string // e.g. "compat", "files", "mdns4_minimal"
+	criteria []nssCriterion
+}
+
+// standardCriteria reports all specified criteria have the default
+// status actions.
+func (s nssSource) standardCriteria() bool {
+	for i, crit := range s.criteria {
+		if !crit.standardStatusAction(i == len(s.criteria)-1) {
+			return false
+		}
+	}
+	return true
+}
+
+// nssCriterion is the parsed structure of one of the criteria in brackets
+// after an NSS source name.
+type nssCriterion struct {
+	negate bool   // if "!" was present
+	status string // e.g. "success", "unavail" (lowercase)
+	action string // e.g. "return", "continue" (lowercase)
+}
+
+// standardStatusAction reports whether c is equivalent to not
+// specifying the criterion at all. last is whether this criteria is the
+// last in the list.
+func (c nssCriterion) standardStatusAction(last bool) bool {
+	if c.negate {
+		return false
+	}
+	var def string
+	switch c.status {
+	case "success":
+		def = "return"
+	case "notfound", "unavail", "tryagain":
+		def = "continue"
+	default:
+		// Unknown status
+		return false
+	}
+	if last && c.action == "return" {
+		return true
+	}
+	return c.action == def
+}
+
+func parseNSSConfFile(file string) *nssConf {
+	f, err := os.Open(file)
+	if err != nil {
+		return &nssConf{err: err}
+	}
+	defer f.Close()
+	return parseNSSConf(f)
+}
+
+func parseNSSConf(r io.Reader) *nssConf {
+	slurp, err := readFull(r)
+	if err != nil {
+		return &nssConf{err: err}
+	}
+	conf := new(nssConf)
+	conf.err = foreachLine(slurp, func(line []byte) error {
+		line = trimSpace(removeComment(line))
+		if len(line) == 0 {
+			return nil
+		}
+		colon := bytesIndexByte(line, ':')
+		if colon == -1 {
+			return errors.New("no colon on line")
+		}
+		db := string(trimSpace(line[:colon]))
+		srcs := line[colon+1:]
+		for {
+			srcs = trimSpace(srcs)
+			if len(srcs) == 0 {
+				break
+			}
+			sp := bytesIndexByte(srcs, ' ')
+			var src string
+			if sp == -1 {
+				src = string(srcs)
+				srcs = nil // done
+			} else {
+				src = string(srcs[:sp])
+				srcs = trimSpace(srcs[sp+1:])
+			}
+			var criteria []nssCriterion
+			// See if there's a criteria block in brackets.
+			if len(srcs) > 0 && srcs[0] == '[' {
+				bclose := bytesIndexByte(srcs, ']')
+				if bclose == -1 {
+					return errors.New("unclosed criterion bracket")
+				}
+				var err error
+				criteria, err = parseCriteria(srcs[1:bclose])
+				if err != nil {
+					return errors.New("invalid criteria: " + string(srcs[1:bclose]))
+				}
+				srcs = srcs[bclose+1:]
+			}
+			if conf.sources == nil {
+				conf.sources = make(map[string][]nssSource)
+			}
+			conf.sources[db] = append(conf.sources[db], nssSource{
+				source:   src,
+				criteria: criteria,
+			})
+		}
+		return nil
+	})
+	return conf
+}
+
+// parses "foo=bar !foo=bar"
+func parseCriteria(x []byte) (c []nssCriterion, err error) {
+	err = foreachField(x, func(f []byte) error {
+		not := false
+		if len(f) > 0 && f[0] == '!' {
+			not = true
+			f = f[1:]
+		}
+		if len(f) < 3 {
+			return errors.New("criterion too short")
+		}
+		eq := bytesIndexByte(f, '=')
+		if eq == -1 {
+			return errors.New("criterion lacks equal sign")
+		}
+		lowerASCIIBytes(f)
+		c = append(c, nssCriterion{
+			negate: not,
+			status: string(f[:eq]),
+			action: string(f[eq+1:]),
+		})
+		return nil
+	})
+	return
+}
diff --git a/src/net/nss_test.go b/src/net/nss_test.go
new file mode 100644
index 0000000..371deb5
--- /dev/null
+++ b/src/net/nss_test.go
@@ -0,0 +1,169 @@
+// 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 net
+
+import (
+	"reflect"
+	"strings"
+	"testing"
+)
+
+const ubuntuTrustyAvahi = `# /etc/nsswitch.conf
+#
+# Example configuration of GNU Name Service Switch functionality.
+# If you have the libc-doc-reference' and nfo' packages installed, try:
+# nfo libc "Name Service Switch"' for information about this file.
+
+passwd:         compat
+group:          compat
+shadow:         compat
+
+hosts:          files mdns4_minimal [NOTFOUND=return] dns mdns4
+networks:       files
+
+protocols:      db files
+services:       db files
+ethers:         db files
+rpc:            db files
+
+netgroup:       nis
+`
+
+func TestParseNSSConf(t *testing.T) {
+	tests := []struct {
+		name string
+		in   string
+		want *nssConf
+	}{
+		{
+			name: "no_newline",
+			in:   "foo: a b",
+			want: &nssConf{
+				sources: map[string][]nssSource{
+					"foo": {{source: "a"}, {source: "b"}},
+				},
+			},
+		},
+		{
+			name: "newline",
+			in:   "foo: a b\n",
+			want: &nssConf{
+				sources: map[string][]nssSource{
+					"foo": {{source: "a"}, {source: "b"}},
+				},
+			},
+		},
+		{
+			name: "whitespace",
+			in:   "   foo:a    b    \n",
+			want: &nssConf{
+				sources: map[string][]nssSource{
+					"foo": {{source: "a"}, {source: "b"}},
+				},
+			},
+		},
+		{
+			name: "comment1",
+			in:   "   foo:a    b#c\n",
+			want: &nssConf{
+				sources: map[string][]nssSource{
+					"foo": {{source: "a"}, {source: "b"}},
+				},
+			},
+		},
+		{
+			name: "comment2",
+			in:   "   foo:a    b #c \n",
+			want: &nssConf{
+				sources: map[string][]nssSource{
+					"foo": {{source: "a"}, {source: "b"}},
+				},
+			},
+		},
+		{
+			name: "crit",
+			in:   "   foo:a    b [!a=b    X=Y ] c#d \n",
+			want: &nssConf{
+				sources: map[string][]nssSource{
+					"foo": {
+						{source: "a"},
+						{
+							source: "b",
+							criteria: []nssCriterion{
+								{
+									negate: true,
+									status: "a",
+									action: "b",
+								},
+								{
+									status: "x",
+									action: "y",
+								},
+							},
+						},
+						{source: "c"},
+					},
+				},
+			},
+		},
+
+		// Ubuntu Trusty w/ avahi-daemon, libavahi-* etc installed.
+		{
+			name: "ubuntu_trusty_avahi",
+			in:   ubuntuTrustyAvahi,
+			want: &nssConf{
+				sources: map[string][]nssSource{
+					"passwd": {{source: "compat"}},
+					"group":  {{source: "compat"}},
+					"shadow": {{source: "compat"}},
+					"hosts": {
+						{source: "files"},
+						{
+							source: "mdns4_minimal",
+							criteria: []nssCriterion{
+								{
+									negate: false,
+									status: "notfound",
+									action: "return",
+								},
+							},
+						},
+						{source: "dns"},
+						{source: "mdns4"},
+					},
+					"networks": {{source: "files"}},
+					"protocols": {
+						{source: "db"},
+						{source: "files"},
+					},
+					"services": {
+						{source: "db"},
+						{source: "files"},
+					},
+					"ethers": {
+						{source: "db"},
+						{source: "files"},
+					},
+					"rpc": {
+						{source: "db"},
+						{source: "files"},
+					},
+					"netgroup": {
+						{source: "nis"},
+					},
+				},
+			},
+		},
+	}
+
+	for _, tt := range tests {
+		gotConf := parseNSSConf(strings.NewReader(tt.in))
+		if !reflect.DeepEqual(gotConf, tt.want) {
+			t.Errorf("%s: mismatch\n got %#v\nwant %#v", tt.name, gotConf, tt.want)
+		}
+	}
+}
diff --git a/src/net/packetconn_test.go b/src/net/packetconn_test.go
index b6e4e76..7f3ea8a 100644
--- a/src/net/packetconn_test.go
+++ b/src/net/packetconn_test.go
@@ -9,49 +9,21 @@ package net
 
 import (
 	"os"
-	"runtime"
-	"strings"
 	"testing"
 	"time"
 )
 
-func packetConnTestData(t *testing.T, net string, i int) ([]byte, func()) {
-	switch net {
-	case "udp":
-		return []byte("UDP PACKETCONN TEST"), nil
-	case "ip":
-		if skip, skipmsg := skipRawSocketTest(t); skip {
-			return nil, func() {
-				t.Logf(skipmsg)
-			}
-		}
-		b, err := (&icmpMessage{
-			Type: icmpv4EchoRequest, Code: 0,
-			Body: &icmpEcho{
-				ID: os.Getpid() & 0xffff, Seq: i + 1,
-				Data: []byte("IP PACKETCONN TEST"),
-			},
-		}).Marshal()
-		if err != nil {
-			return nil, func() {
-				t.Fatalf("icmpMessage.Marshal failed: %v", err)
-			}
-		}
-		return b, 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)
-		}
+// The full stack test cases for IPConn have been moved to the
+// following:
+//	golang.org/x/net/ipv4
+//	golang.org/x/net/ipv6
+//	golang.org/x/net/icmp
+
+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,7 +32,6 @@ var packetConnTests = []struct {
 	addr2 string
 }{
 	{"udp", "127.0.0.1:0", "127.0.0.1:0"},
-	{"ip:icmp", "127.0.0.1", "127.0.0.1"},
 	{"unixgram", testUnixAddr(), testUnixAddr()},
 }
 
@@ -74,9 +45,8 @@ func TestPacketConn(t *testing.T) {
 		}
 	}
 
-	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
@@ -84,37 +54,37 @@ func TestPacketConn(t *testing.T) {
 
 		c1, err := ListenPacket(tt.net, tt.addr1)
 		if err != nil {
-			t.Fatalf("ListenPacket failed: %v", err)
+			t.Fatal(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(100 * time.Millisecond))
-		c1.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
-		c1.SetWriteDeadline(time.Now().Add(100 * time.Millisecond))
+		c1.SetDeadline(time.Now().Add(500 * time.Millisecond))
+		c1.SetReadDeadline(time.Now().Add(500 * time.Millisecond))
+		c1.SetWriteDeadline(time.Now().Add(500 * time.Millisecond))
 
 		c2, err := ListenPacket(tt.net, tt.addr2)
 		if err != nil {
-			t.Fatalf("ListenPacket failed: %v", err)
+			t.Fatal(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(100 * time.Millisecond))
-		c2.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
-		c2.SetWriteDeadline(time.Now().Add(100 * time.Millisecond))
+		c2.SetDeadline(time.Now().Add(500 * time.Millisecond))
+		c2.SetReadDeadline(time.Now().Add(500 * time.Millisecond))
+		c2.SetWriteDeadline(time.Now().Add(500 * time.Millisecond))
+		rb2 := make([]byte, 128)
 
 		if _, err := c1.WriteTo(wb, c2.LocalAddr()); err != nil {
-			t.Fatalf("PacketConn.WriteTo failed: %v", err)
+			t.Fatal(err)
 		}
-		rb2 := make([]byte, 128)
 		if _, _, err := c2.ReadFrom(rb2); err != nil {
-			t.Fatalf("PacketConn.ReadFrom failed: %v", err)
+			t.Fatal(err)
 		}
 		if _, err := c2.WriteTo(wb, c1.LocalAddr()); err != nil {
-			t.Fatalf("PacketConn.WriteTo failed: %v", err)
+			t.Fatal(err)
 		}
 		rb1 := make([]byte, 128)
 		if _, _, err := c1.ReadFrom(rb1); err != nil {
-			t.Fatalf("PacketConn.ReadFrom failed: %v", err)
+			t.Fatal(err)
 		}
 	}
 }
@@ -129,10 +99,9 @@ func TestConnAndPacketConn(t *testing.T) {
 		}
 	}
 
-	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
@@ -140,47 +109,45 @@ func TestConnAndPacketConn(t *testing.T) {
 
 		c1, err := ListenPacket(tt.net, tt.addr1)
 		if err != nil {
-			t.Fatalf("ListenPacket failed: %v", err)
+			t.Fatal(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(100 * time.Millisecond))
-		c1.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
-		c1.SetWriteDeadline(time.Now().Add(100 * time.Millisecond))
+		c1.SetDeadline(time.Now().Add(500 * time.Millisecond))
+		c1.SetReadDeadline(time.Now().Add(500 * time.Millisecond))
+		c1.SetWriteDeadline(time.Now().Add(500 * time.Millisecond))
 
 		c2, err := Dial(tt.net, c1.LocalAddr().String())
 		if err != nil {
-			t.Fatalf("Dial failed: %v", err)
+			t.Fatal(err)
 		}
 		defer c2.Close()
 		c2.LocalAddr()
 		c2.RemoteAddr()
-		c2.SetDeadline(time.Now().Add(100 * time.Millisecond))
-		c2.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
-		c2.SetWriteDeadline(time.Now().Add(100 * time.Millisecond))
+		c2.SetDeadline(time.Now().Add(500 * time.Millisecond))
+		c2.SetReadDeadline(time.Now().Add(500 * time.Millisecond))
+		c2.SetWriteDeadline(time.Now().Add(500 * time.Millisecond))
 
 		if _, err := c2.Write(wb); err != nil {
-			t.Fatalf("Conn.Write failed: %v", err)
+			t.Fatal(err)
 		}
 		rb1 := make([]byte, 128)
 		if _, _, err := c1.ReadFrom(rb1); err != nil {
-			t.Fatalf("PacketConn.ReadFrom failed: %v", err)
+			t.Fatal(err)
 		}
 		var dst Addr
-		switch netstr[0] {
-		case "ip":
-			dst = &IPAddr{IP: IPv4(127, 0, 0, 1)}
+		switch tt.net {
 		case "unixgram":
 			continue
 		default:
 			dst = c2.LocalAddr()
 		}
 		if _, err := c1.WriteTo(wb, dst); err != nil {
-			t.Fatalf("PacketConn.WriteTo failed: %v", err)
+			t.Fatal(err)
 		}
 		rb2 := make([]byte, 128)
 		if _, err := c2.Read(rb2); err != nil {
-			t.Fatalf("Conn.Read failed: %v", err)
+			t.Fatal(err)
 		}
 	}
 }
diff --git a/src/net/parse.go b/src/net/parse.go
index e1d0130..c72e1c2 100644
--- a/src/net/parse.go
+++ b/src/net/parse.go
@@ -171,43 +171,30 @@ func xtoi2(s string, e byte) (byte, bool) {
 	return byte(n), ok && ei == 2
 }
 
-// Integer to decimal.
-func itoa(i int) string {
-	var buf [30]byte
-	n := len(buf)
-	neg := false
-	if i < 0 {
-		i = -i
-		neg = true
-	}
-	ui := uint(i)
-	for ui > 0 || n == len(buf) {
-		n--
-		buf[n] = byte('0' + ui%10)
-		ui /= 10
-	}
-	if neg {
-		n--
-		buf[n] = '-'
-	}
-	return string(buf[n:])
-}
-
-// Convert i to decimal string.
-func itod(i uint) string {
-	if i == 0 {
-		return "0"
+// Convert integer to decimal string.
+func itoa(val int) string {
+	if val < 0 {
+		return "-" + uitoa(uint(-val))
 	}
+	return uitoa(uint(val))
+}
 
-	// Assemble decimal in reverse order.
-	var b [32]byte
-	bp := len(b)
-	for ; i > 0; i /= 10 {
-		bp--
-		b[bp] = byte(i%10) + '0'
+// Convert unsigned integer to decimal string.
+func uitoa(val uint) string {
+	if val == 0 { // avoid string allocation
+		return "0"
 	}
-
-	return string(b[bp:])
+	var buf [20]byte // big enough for 64bit value base 10
+	i := len(buf) - 1
+	for val >= 10 {
+		q := val / 10
+		buf[i] = byte('0' + val - q*10)
+		i--
+		val = q
+	}
+	// val < 10
+	buf[i] = byte('0' + val)
+	return string(buf[i:])
 }
 
 // Convert i to a hexadecimal string. Leading zeros are not printed.
@@ -245,3 +232,155 @@ func last(s string, b byte) int {
 	}
 	return i
 }
+
+// lowerASCIIBytes makes x ASCII lowercase in-place.
+func lowerASCIIBytes(x []byte) {
+	for i, b := range x {
+		if 'A' <= b && b <= 'Z' {
+			x[i] += 'a' - 'A'
+		}
+	}
+}
+
+// lowerASCII returns the ASCII lowercase version of b.
+func lowerASCII(b byte) byte {
+	if 'A' <= b && b <= 'Z' {
+		return b + ('a' - 'A')
+	}
+	return b
+}
+
+// trimSpace returns x without any leading or trailing ASCII whitespace.
+func trimSpace(x []byte) []byte {
+	for len(x) > 0 && isSpace(x[0]) {
+		x = x[1:]
+	}
+	for len(x) > 0 && isSpace(x[len(x)-1]) {
+		x = x[:len(x)-1]
+	}
+	return x
+}
+
+// isSpace reports whether b is an ASCII space character.
+func isSpace(b byte) bool {
+	return b == ' ' || b == '\t' || b == '\n' || b == '\r'
+}
+
+// removeComment returns line, removing any '#' byte and any following
+// bytes.
+func removeComment(line []byte) []byte {
+	if i := bytesIndexByte(line, '#'); i != -1 {
+		return line[:i]
+	}
+	return line
+}
+
+// foreachLine runs fn on each line of x.
+// Each line (except for possibly the last) ends in '\n'.
+// It returns the first non-nil error returned by fn.
+func foreachLine(x []byte, fn func(line []byte) error) error {
+	for len(x) > 0 {
+		nl := bytesIndexByte(x, '\n')
+		if nl == -1 {
+			return fn(x)
+		}
+		line := x[:nl+1]
+		x = x[nl+1:]
+		if err := fn(line); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// foreachField runs fn on each non-empty run of non-space bytes in x.
+// It returns the first non-nil error returned by fn.
+func foreachField(x []byte, fn func(field []byte) error) error {
+	x = trimSpace(x)
+	for len(x) > 0 {
+		sp := bytesIndexByte(x, ' ')
+		if sp == -1 {
+			return fn(x)
+		}
+		if field := trimSpace(x[:sp]); len(field) > 0 {
+			if err := fn(field); err != nil {
+				return err
+			}
+		}
+		x = trimSpace(x[sp+1:])
+	}
+	return nil
+}
+
+// bytesIndexByte is bytes.IndexByte. It returns the index of the
+// first instance of c in s, or -1 if c is not present in s.
+func bytesIndexByte(s []byte, c byte) int {
+	for i, b := range s {
+		if b == c {
+			return i
+		}
+	}
+	return -1
+}
+
+// stringsHasSuffix is strings.HasSuffix. It reports whether s ends in
+// suffix.
+func stringsHasSuffix(s, suffix string) bool {
+	return len(s) >= len(suffix) && s[len(s)-len(suffix):] == suffix
+}
+
+// stringsHasSuffixFold reports whether s ends in suffix,
+// ASCII-case-insensitively.
+func stringsHasSuffixFold(s, suffix string) bool {
+	if len(suffix) > len(s) {
+		return false
+	}
+	for i := 0; i < len(suffix); i++ {
+		if lowerASCII(suffix[i]) != lowerASCII(s[len(s)-len(suffix)+i]) {
+			return false
+		}
+	}
+	return true
+}
+
+// stringsHasPrefix is strings.HasPrefix. It reports whether s begins with prefix.
+func stringsHasPrefix(s, prefix string) bool {
+	return len(s) >= len(prefix) && s[:len(prefix)] == prefix
+}
+
+func readFull(r io.Reader) (all []byte, err error) {
+	buf := make([]byte, 1024)
+	for {
+		n, err := r.Read(buf)
+		all = append(all, buf[:n]...)
+		if err == io.EOF {
+			return all, nil
+		}
+		if err != nil {
+			return nil, err
+		}
+	}
+}
+
+// goDebugString returns the value of the named GODEBUG key.
+// GODEBUG is of the form "key=val,key2=val2"
+func goDebugString(key string) string {
+	s := os.Getenv("GODEBUG")
+	for i := 0; i < len(s)-len(key)-1; i++ {
+		if i > 0 && s[i-1] != ',' {
+			continue
+		}
+		afterKey := s[i+len(key):]
+		if afterKey[0] != '=' || s[i:i+len(key)] != key {
+			continue
+		}
+		val := afterKey[1:]
+		for i, b := range val {
+			if b == ',' {
+				return val[:i]
+			}
+		}
+		return val
+	}
+	return ""
+}
diff --git a/src/net/parse_test.go b/src/net/parse_test.go
index 7b213b7..0f048fc 100644
--- a/src/net/parse_test.go
+++ b/src/net/parse_test.go
@@ -15,20 +15,20 @@ func TestReadLine(t *testing.T) {
 	// /etc/services file does not exist on android, plan9, windows.
 	switch runtime.GOOS {
 	case "android", "plan9", "windows":
-		t.Skipf("skipping test on %q", runtime.GOOS)
+		t.Skipf("not supported on %s", runtime.GOOS)
 	}
 	filename := "/etc/services" // a nice big file
 
 	fd, err := os.Open(filename)
 	if err != nil {
-		t.Fatalf("open %s: %v", filename, err)
+		t.Fatal(err)
 	}
 	defer fd.Close()
 	br := bufio.NewReader(fd)
 
 	file, err := open(filename)
 	if file == nil {
-		t.Fatalf("net.open(%s) = nil", filename)
+		t.Fatal(err)
 	}
 	defer file.close()
 
@@ -41,8 +41,7 @@ func TestReadLine(t *testing.T) {
 		}
 		line, ok := file.readLine()
 		if (berr != nil) != !ok || bline != line {
-			t.Fatalf("%s:%d (#%d)\nbufio => %q, %v\nnet => %q, %v",
-				filename, lineno, byteno, bline, berr, line, ok)
+			t.Fatalf("%s:%d (#%d)\nbufio => %q, %v\nnet => %q, %v", filename, lineno, byteno, bline, berr, line, ok)
 		}
 		if !ok {
 			break
@@ -51,3 +50,30 @@ func TestReadLine(t *testing.T) {
 		byteno += len(line) + 1
 	}
 }
+
+func TestGoDebugString(t *testing.T) {
+	defer os.Setenv("GODEBUG", os.Getenv("GODEBUG"))
+	tests := []struct {
+		godebug string
+		key     string
+		want    string
+	}{
+		{"", "foo", ""},
+		{"foo=", "foo", ""},
+		{"foo=bar", "foo", "bar"},
+		{"foo=bar,", "foo", "bar"},
+		{"foo,foo=bar,", "foo", "bar"},
+		{"foo1=bar,foo=bar,", "foo", "bar"},
+		{"foo=bar,foo=bar,", "foo", "bar"},
+		{"foo=", "foo", ""},
+		{"foo", "foo", ""},
+		{",foo", "foo", ""},
+		{"foo=bar,baz", "loooooooong", ""},
+	}
+	for _, tt := range tests {
+		os.Setenv("GODEBUG", tt.godebug)
+		if got := goDebugString(tt.key); got != tt.want {
+			t.Errorf("for %q, goDebugString(%q) = %q; want %q", tt.godebug, tt.key, got, tt.want)
+		}
+	}
+}
diff --git a/src/net/pipe.go b/src/net/pipe.go
index f1a2eca..5fc830b 100644
--- a/src/net/pipe.go
+++ b/src/net/pipe.go
@@ -55,13 +55,13 @@ func (p *pipe) RemoteAddr() Addr {
 }
 
 func (p *pipe) SetDeadline(t time.Time) error {
-	return errors.New("net.Pipe does not support deadlines")
+	return &OpError{Op: "set", Net: "pipe", Source: nil, Addr: nil, Err: errors.New("deadline not supported")}
 }
 
 func (p *pipe) SetReadDeadline(t time.Time) error {
-	return errors.New("net.Pipe does not support deadlines")
+	return &OpError{Op: "set", Net: "pipe", Source: nil, Addr: nil, Err: errors.New("deadline not supported")}
 }
 
 func (p *pipe) SetWriteDeadline(t time.Time) error {
-	return errors.New("net.Pipe does not support deadlines")
+	return &OpError{Op: "set", Net: "pipe", Source: nil, Addr: nil, Err: errors.New("deadline not supported")}
 }
diff --git a/src/net/pipe_test.go b/src/net/pipe_test.go
index afe4f24..60c3920 100644
--- a/src/net/pipe_test.go
+++ b/src/net/pipe_test.go
@@ -10,10 +10,10 @@ import (
 	"testing"
 )
 
-func checkWrite(t *testing.T, w io.Writer, data []byte, c chan int) {
+func checkPipeWrite(t *testing.T, w io.Writer, data []byte, c chan int) {
 	n, err := w.Write(data)
 	if err != nil {
-		t.Errorf("write: %v", err)
+		t.Error(err)
 	}
 	if n != len(data) {
 		t.Errorf("short write: %d != %d", n, len(data))
@@ -21,11 +21,11 @@ func checkWrite(t *testing.T, w io.Writer, data []byte, c chan int) {
 	c <- 0
 }
 
-func checkRead(t *testing.T, r io.Reader, data []byte, wantErr error) {
+func checkPipeRead(t *testing.T, r io.Reader, data []byte, wantErr error) {
 	buf := make([]byte, len(data)+10)
 	n, err := r.Read(buf)
 	if err != wantErr {
-		t.Errorf("read: %v", err)
+		t.Error(err)
 		return
 	}
 	if n != len(data) || !bytes.Equal(buf[0:n], data) {
@@ -34,23 +34,22 @@ func checkRead(t *testing.T, r io.Reader, data []byte, wantErr error) {
 	}
 }
 
-// Test a simple read/write/close sequence.
+// TestPipe tests a simple read/write/close sequence.
 // Assumes that the underlying io.Pipe implementation
 // is solid and we're just testing the net wrapping.
-
 func TestPipe(t *testing.T) {
 	c := make(chan int)
 	cli, srv := Pipe()
-	go checkWrite(t, cli, []byte("hello, world"), c)
-	checkRead(t, srv, []byte("hello, world"), nil)
+	go checkPipeWrite(t, cli, []byte("hello, world"), c)
+	checkPipeRead(t, srv, []byte("hello, world"), nil)
 	<-c
-	go checkWrite(t, srv, []byte("line 2"), c)
-	checkRead(t, cli, []byte("line 2"), nil)
+	go checkPipeWrite(t, srv, []byte("line 2"), c)
+	checkPipeRead(t, cli, []byte("line 2"), nil)
 	<-c
-	go checkWrite(t, cli, []byte("a third line"), c)
-	checkRead(t, srv, []byte("a third line"), nil)
+	go checkPipeWrite(t, cli, []byte("a third line"), c)
+	checkPipeRead(t, srv, []byte("a third line"), nil)
 	<-c
 	go srv.Close()
-	checkRead(t, cli, nil, io.EOF)
+	checkPipeRead(t, cli, nil, io.EOF)
 	cli.Close()
 }
diff --git a/src/net/platform_test.go b/src/net/platform_test.go
new file mode 100644
index 0000000..d624852
--- /dev/null
+++ b/src/net/platform_test.go
@@ -0,0 +1,159 @@
+// 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 {
+	ss := strings.Split(network, ":")
+	switch 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", "plan9", "windows":
+			fallthrough
+		case "freebsd": // FreeBSD 8 and below don't support unixpacket
+			return false
+		}
+	}
+	switch ss[0] {
+	case "tcp4", "udp4", "ip4":
+		if !supportsIPv4 {
+			return false
+		}
+	case "tcp6", "udp6", "ip6":
+		if !supportsIPv6 {
+			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 IPv4 communication using AF_INET and
+	// IPv6 communication using AF_INET6 sockets.
+	if !supportsIPv4 && ip.To4() != nil {
+		return false
+	}
+	if !supportsIPv6 && ip.To16() != nil && ip.To4() == nil {
+		return false
+	}
+	cip := ParseIP(client)
+	if cip != nil {
+		if !supportsIPv4 && cip.To4() != nil {
+			return false
+		}
+		if !supportsIPv6 && cip.To16() != nil && cip.To4() == nil {
+			return false
+		}
+	}
+
+	// Test functionality of IPv4 communication using AF_INET6
+	// sockets.
+	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/port.go b/src/net/port.go
index c24f4ed..a2a5387 100644
--- a/src/net/port.go
+++ b/src/net/port.go
@@ -18,7 +18,7 @@ func parsePort(net, port string) (int, error) {
 		}
 	}
 	if p < 0 || p > 0xFFFF {
-		return 0, &AddrError{"invalid port", port}
+		return 0, &AddrError{Err: "invalid port", Addr: port}
 	}
 	return p, nil
 }
diff --git a/src/net/port_test.go b/src/net/port_test.go
index 4811ade..258a5bd 100644
--- a/src/net/port_test.go
+++ b/src/net/port_test.go
@@ -9,14 +9,12 @@ import (
 	"testing"
 )
 
-type portTest struct {
-	netw string
-	name string
-	port int
-	ok   bool
-}
-
-var porttests = []portTest{
+var portTests = []struct {
+	network string
+	name    string
+	port    int
+	ok      bool
+}{
 	{"tcp", "echo", 7, true},
 	{"tcp", "discard", 9, true},
 	{"tcp", "systat", 11, true},
@@ -29,6 +27,7 @@ var porttests = []portTest{
 	{"tcp", "time", 37, true},
 	{"tcp", "domain", 53, true},
 	{"tcp", "finger", 79, true},
+	{"tcp", "42", 42, true},
 
 	{"udp", "echo", 7, true},
 	{"udp", "tftp", 69, true},
@@ -38,6 +37,7 @@ var porttests = []portTest{
 	{"udp", "ntp", 123, true},
 	{"udp", "snmp", 161, true},
 	{"udp", "syslog", 514, true},
+	{"udp", "42", 42, true},
 
 	{"--badnet--", "zzz", 0, false},
 	{"tcp", "--badport--", 0, false},
@@ -46,14 +46,12 @@ var porttests = []portTest{
 func TestLookupPort(t *testing.T) {
 	switch runtime.GOOS {
 	case "nacl":
-		t.Skipf("skipping test on %q", runtime.GOOS)
+		t.Skipf("not supported on %s", runtime.GOOS)
 	}
 
-	for i := 0; i < len(porttests); i++ {
-		tt := porttests[i]
-		if port, err := LookupPort(tt.netw, tt.name); port != tt.port || (err == nil) != tt.ok {
-			t.Errorf("LookupPort(%q, %q) = %v, %v; want %v",
-				tt.netw, tt.name, port, err, tt.port)
+	for _, tt := range portTests {
+		if port, err := LookupPort(tt.network, tt.name); port != tt.port || (err == nil) != tt.ok {
+			t.Errorf("LookupPort(%q, %q) = %v, %v; want %v", tt.network, tt.name, port, err, tt.port)
 		}
 	}
 }
diff --git a/src/net/port_unix.go b/src/net/port_unix.go
index 348c771..badf8ab 100644
--- a/src/net/port_unix.go
+++ b/src/net/port_unix.go
@@ -69,5 +69,5 @@ func goLookupPort(network, service string) (port int, err error) {
 			return
 		}
 	}
-	return 0, &AddrError{"unknown port", network + "/" + service}
+	return 0, &AddrError{Err: "unknown port", Addr: network + "/" + service}
 }
diff --git a/src/net/protoconn_test.go b/src/net/protoconn_test.go
index 12856b6..c6ef23b 100644
--- a/src/net/protoconn_test.go
+++ b/src/net/protoconn_test.go
@@ -8,49 +8,31 @@
 package net
 
 import (
-	"io/ioutil"
 	"os"
 	"runtime"
 	"testing"
 	"time"
 )
 
-// testUnixAddr uses ioutil.TempFile to get a name that is unique. It
-// also uses /tmp directory in case it is prohibited to create UNIX
-// sockets in TMPDIR.
-func testUnixAddr() string {
-	f, err := ioutil.TempFile("", "nettest")
-	if err != nil {
-		panic(err)
-	}
-	addr := f.Name()
-	f.Close()
-	os.Remove(addr)
-	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
-}()
+// The full stack test cases for IPConn have been moved to the
+// following:
+//	golang.org/x/net/ipv4
+//	golang.org/x/net/ipv6
+//	golang.org/x/net/icmp
 
 func TestTCPListenerSpecificMethods(t *testing.T) {
 	switch runtime.GOOS {
 	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
+		t.Skipf("not supported on %s", runtime.GOOS)
 	}
 
 	la, err := ResolveTCPAddr("tcp4", "127.0.0.1:0")
 	if err != nil {
-		t.Fatalf("ResolveTCPAddr failed: %v", err)
+		t.Fatal(err)
 	}
 	ln, err := ListenTCP("tcp4", la)
 	if err != nil {
-		t.Fatalf("ListenTCP failed: %v", err)
+		t.Fatal(err)
 	}
 	defer ln.Close()
 	ln.Addr()
@@ -58,21 +40,21 @@ func TestTCPListenerSpecificMethods(t *testing.T) {
 
 	if c, err := ln.Accept(); err != nil {
 		if !err.(Error).Timeout() {
-			t.Fatalf("TCPListener.Accept failed: %v", err)
+			t.Fatal(err)
 		}
 	} else {
 		c.Close()
 	}
 	if c, err := ln.AcceptTCP(); err != nil {
 		if !err.(Error).Timeout() {
-			t.Fatalf("TCPListener.AcceptTCP failed: %v", err)
+			t.Fatal(err)
 		}
 	} else {
 		c.Close()
 	}
 
 	if f, err := ln.File(); err != nil {
-		condFatalf(t, "TCPListener.File failed: %v", err)
+		condFatalf(t, "%v", err)
 	} else {
 		f.Close()
 	}
@@ -81,25 +63,30 @@ func TestTCPListenerSpecificMethods(t *testing.T) {
 func TestTCPConnSpecificMethods(t *testing.T) {
 	la, err := ResolveTCPAddr("tcp4", "127.0.0.1:0")
 	if err != nil {
-		t.Fatalf("ResolveTCPAddr failed: %v", err)
+		t.Fatal(err)
 	}
 	ln, err := ListenTCP("tcp4", la)
 	if err != nil {
-		t.Fatalf("ListenTCP failed: %v", err)
+		t.Fatal(err)
+	}
+	ch := make(chan error, 1)
+	handler := func(ls *localServer, ln Listener) { transponder(ls.Listener, ch) }
+	ls, err := (&streamListener{Listener: ln}).newLocalServer()
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer ls.teardown()
+	if err := ls.buildup(handler); err != nil {
+		t.Fatal(err)
 	}
-	defer ln.Close()
-	ln.Addr()
-
-	done := make(chan int)
-	go transponder(t, ln, done)
 
-	ra, err := ResolveTCPAddr("tcp4", ln.Addr().String())
+	ra, err := ResolveTCPAddr("tcp4", ls.Listener.Addr().String())
 	if err != nil {
-		t.Fatalf("ResolveTCPAddr failed: %v", err)
+		t.Fatal(err)
 	}
 	c, err := DialTCP("tcp4", nil, ra)
 	if err != nil {
-		t.Fatalf("DialTCP failed: %v", err)
+		t.Fatal(err)
 	}
 	defer c.Close()
 	c.SetKeepAlive(false)
@@ -113,24 +100,26 @@ func TestTCPConnSpecificMethods(t *testing.T) {
 	c.SetWriteDeadline(time.Now().Add(someTimeout))
 
 	if _, err := c.Write([]byte("TCPCONN TEST")); err != nil {
-		t.Fatalf("TCPConn.Write failed: %v", err)
+		t.Fatal(err)
 	}
 	rb := make([]byte, 128)
 	if _, err := c.Read(rb); err != nil {
-		t.Fatalf("TCPConn.Read failed: %v", err)
+		t.Fatal(err)
 	}
 
-	<-done
+	for err := range ch {
+		t.Error(err)
+	}
 }
 
 func TestUDPConnSpecificMethods(t *testing.T) {
 	la, err := ResolveUDPAddr("udp4", "127.0.0.1:0")
 	if err != nil {
-		t.Fatalf("ResolveUDPAddr failed: %v", err)
+		t.Fatal(err)
 	}
 	c, err := ListenUDP("udp4", la)
 	if err != nil {
-		t.Fatalf("ListenUDP failed: %v", err)
+		t.Fatal(err)
 	}
 	defer c.Close()
 	c.LocalAddr()
@@ -144,27 +133,27 @@ func TestUDPConnSpecificMethods(t *testing.T) {
 	wb := []byte("UDPCONN TEST")
 	rb := make([]byte, 128)
 	if _, err := c.WriteToUDP(wb, c.LocalAddr().(*UDPAddr)); err != nil {
-		t.Fatalf("UDPConn.WriteToUDP failed: %v", err)
+		t.Fatal(err)
 	}
 	if _, _, err := c.ReadFromUDP(rb); err != nil {
-		t.Fatalf("UDPConn.ReadFromUDP failed: %v", err)
+		t.Fatal(err)
 	}
 	if _, _, err := c.WriteMsgUDP(wb, nil, c.LocalAddr().(*UDPAddr)); err != nil {
-		condFatalf(t, "UDPConn.WriteMsgUDP failed: %v", err)
+		condFatalf(t, "%v", err)
 	}
 	if _, _, _, _, err := c.ReadMsgUDP(rb, nil); err != nil {
-		condFatalf(t, "UDPConn.ReadMsgUDP failed: %v", err)
+		condFatalf(t, "%v", err)
 	}
 
 	if f, err := c.File(); err != nil {
-		condFatalf(t, "UDPConn.File failed: %v", err)
+		condFatalf(t, "%v", err)
 	} else {
 		f.Close()
 	}
 
 	defer func() {
 		if p := recover(); p != nil {
-			t.Fatalf("UDPConn.WriteToUDP or WriteMsgUDP panicked: %v", p)
+			t.Fatalf("panicked: %v", p)
 		}
 	}()
 
@@ -173,17 +162,17 @@ func TestUDPConnSpecificMethods(t *testing.T) {
 }
 
 func TestIPConnSpecificMethods(t *testing.T) {
-	if skip, skipmsg := skipRawSocketTest(t); skip {
-		t.Skip(skipmsg)
+	if os.Getuid() != 0 {
+		t.Skip("must be root")
 	}
 
 	la, err := ResolveIPAddr("ip4", "127.0.0.1")
 	if err != nil {
-		t.Fatalf("ResolveIPAddr failed: %v", err)
+		t.Fatal(err)
 	}
 	c, err := ListenIP("ip4:icmp", la)
 	if err != nil {
-		t.Fatalf("ListenIP failed: %v", err)
+		t.Fatal(err)
 	}
 	defer c.Close()
 	c.LocalAddr()
@@ -194,60 +183,36 @@ func TestIPConnSpecificMethods(t *testing.T) {
 	c.SetReadBuffer(2048)
 	c.SetWriteBuffer(2048)
 
-	wb, err := (&icmpMessage{
-		Type: icmpv4EchoRequest, Code: 0,
-		Body: &icmpEcho{
-			ID: os.Getpid() & 0xffff, Seq: 1,
-			Data: []byte("IPCONN TEST "),
-		},
-	}).Marshal()
-	if err != nil {
-		t.Fatalf("icmpMessage.Marshal failed: %v", err)
-	}
-	rb := make([]byte, 20+len(wb))
-	if _, err := c.WriteToIP(wb, c.LocalAddr().(*IPAddr)); err != nil {
-		t.Fatalf("IPConn.WriteToIP failed: %v", err)
-	}
-	if _, _, err := c.ReadFromIP(rb); err != nil {
-		t.Fatalf("IPConn.ReadFromIP failed: %v", err)
-	}
-	if _, _, err := c.WriteMsgIP(wb, nil, c.LocalAddr().(*IPAddr)); err != nil {
-		condFatalf(t, "IPConn.WriteMsgIP failed: %v", err)
-	}
-	if _, _, _, _, err := c.ReadMsgIP(rb, nil); err != nil {
-		condFatalf(t, "IPConn.ReadMsgIP failed: %v", err)
-	}
-
 	if f, err := c.File(); err != nil {
-		condFatalf(t, "IPConn.File failed: %v", err)
+		condFatalf(t, "%v", err)
 	} else {
 		f.Close()
 	}
 
 	defer func() {
 		if p := recover(); p != nil {
-			t.Fatalf("IPConn.WriteToIP or WriteMsgIP panicked: %v", p)
+			t.Fatalf("panicked: %v", p)
 		}
 	}()
 
+	wb := []byte("IPCONN TEST")
 	c.WriteToIP(wb, nil)
 	c.WriteMsgIP(wb, nil, nil)
 }
 
 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()
 	la, err := ResolveUnixAddr("unix", addr)
 	if err != nil {
-		t.Fatalf("ResolveUnixAddr failed: %v", err)
+		t.Fatal(err)
 	}
 	ln, err := ListenUnix("unix", la)
 	if err != nil {
-		t.Fatalf("ListenUnix failed: %v", err)
+		t.Fatal(err)
 	}
 	defer ln.Close()
 	defer os.Remove(addr)
@@ -256,41 +221,40 @@ func TestUnixListenerSpecificMethods(t *testing.T) {
 
 	if c, err := ln.Accept(); err != nil {
 		if !err.(Error).Timeout() {
-			t.Fatalf("UnixListener.Accept failed: %v", err)
+			t.Fatal(err)
 		}
 	} else {
 		c.Close()
 	}
 	if c, err := ln.AcceptUnix(); err != nil {
 		if !err.(Error).Timeout() {
-			t.Fatalf("UnixListener.AcceptUnix failed: %v", err)
+			t.Fatal(err)
 		}
 	} else {
 		c.Close()
 	}
 
 	if f, err := ln.File(); err != nil {
-		t.Fatalf("UnixListener.File failed: %v", err)
+		t.Fatal(err)
 	} else {
 		f.Close()
 	}
 }
 
 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()
 
 	a1, err := ResolveUnixAddr("unixgram", addr1)
 	if err != nil {
-		t.Fatalf("ResolveUnixAddr failed: %v", err)
+		t.Fatal(err)
 	}
 	c1, err := DialUnix("unixgram", a1, nil)
 	if err != nil {
-		t.Fatalf("DialUnix failed: %v", err)
+		t.Fatal(err)
 	}
 	defer c1.Close()
 	defer os.Remove(addr1)
@@ -304,11 +268,11 @@ func TestUnixConnSpecificMethods(t *testing.T) {
 
 	a2, err := ResolveUnixAddr("unixgram", addr2)
 	if err != nil {
-		t.Fatalf("ResolveUnixAddr failed: %v", err)
+		t.Fatal(err)
 	}
 	c2, err := DialUnix("unixgram", a2, nil)
 	if err != nil {
-		t.Fatalf("DialUnix failed: %v", err)
+		t.Fatal(err)
 	}
 	defer c2.Close()
 	defer os.Remove(addr2)
@@ -322,11 +286,11 @@ func TestUnixConnSpecificMethods(t *testing.T) {
 
 	a3, err := ResolveUnixAddr("unixgram", addr3)
 	if err != nil {
-		t.Fatalf("ResolveUnixAddr failed: %v", err)
+		t.Fatal(err)
 	}
 	c3, err := ListenUnixgram("unixgram", a3)
 	if err != nil {
-		t.Fatalf("ListenUnixgram failed: %v", err)
+		t.Fatal(err)
 	}
 	defer c3.Close()
 	defer os.Remove(addr3)
@@ -343,39 +307,39 @@ func TestUnixConnSpecificMethods(t *testing.T) {
 	rb2 := make([]byte, 128)
 	rb3 := make([]byte, 128)
 	if _, _, err := c1.WriteMsgUnix(wb, nil, a2); err != nil {
-		t.Fatalf("UnixConn.WriteMsgUnix failed: %v", err)
+		t.Fatal(err)
 	}
 	if _, _, _, _, err := c2.ReadMsgUnix(rb2, nil); err != nil {
-		t.Fatalf("UnixConn.ReadMsgUnix failed: %v", err)
+		t.Fatal(err)
 	}
 	if _, err := c2.WriteToUnix(wb, a1); err != nil {
-		t.Fatalf("UnixConn.WriteToUnix failed: %v", err)
+		t.Fatal(err)
 	}
 	if _, _, err := c1.ReadFromUnix(rb1); err != nil {
-		t.Fatalf("UnixConn.ReadFromUnix failed: %v", err)
+		t.Fatal(err)
 	}
 	if _, err := c3.WriteToUnix(wb, a1); err != nil {
-		t.Fatalf("UnixConn.WriteToUnix failed: %v", err)
+		t.Fatal(err)
 	}
 	if _, _, err := c1.ReadFromUnix(rb1); err != nil {
-		t.Fatalf("UnixConn.ReadFromUnix failed: %v", err)
+		t.Fatal(err)
 	}
 	if _, err := c2.WriteToUnix(wb, a3); err != nil {
-		t.Fatalf("UnixConn.WriteToUnix failed: %v", err)
+		t.Fatal(err)
 	}
 	if _, _, err := c3.ReadFromUnix(rb3); err != nil {
-		t.Fatalf("UnixConn.ReadFromUnix failed: %v", err)
+		t.Fatal(err)
 	}
 
 	if f, err := c1.File(); err != nil {
-		t.Fatalf("UnixConn.File failed: %v", err)
+		t.Fatal(err)
 	} else {
 		f.Close()
 	}
 
 	defer func() {
 		if p := recover(); p != nil {
-			t.Fatalf("UnixConn.WriteToUnix or WriteMsgUnix panicked: %v", p)
+			t.Fatalf("panicked: %v", p)
 		}
 	}()
 
diff --git a/src/net/rpc/client_test.go b/src/net/rpc/client_test.go
index 5dd111b..ba11ff8 100644
--- a/src/net/rpc/client_test.go
+++ b/src/net/rpc/client_test.go
@@ -54,7 +54,7 @@ func (s *S) Recv(nul *struct{}, reply *R) error {
 
 func TestGobError(t *testing.T) {
 	if runtime.GOOS == "plan9" {
-		t.Skip("skipping test; see http://golang.org/issue/8908")
+		t.Skip("skipping test; see https://golang.org/issue/8908")
 	}
 	defer func() {
 		err := recover()
diff --git a/src/net/rpc/server.go b/src/net/rpc/server.go
index 83728d5..6e6e881 100644
--- a/src/net/rpc/server.go
+++ b/src/net/rpc/server.go
@@ -13,6 +13,7 @@
 	Only methods that satisfy these criteria will be made available for remote access;
 	other methods will be ignored:
 
+		- the method's type is exported.
 		- the method is exported.
 		- the method has two arguments, both exported (or builtin) types.
 		- the method's second argument is a pointer.
@@ -216,7 +217,7 @@ func isExportedOrBuiltinType(t reflect.Type) bool {
 
 // Register publishes in the server the set of methods of the
 // receiver value that satisfy the following conditions:
-//	- exported method
+//	- exported method of exported type
 //	- two arguments, both of exported type
 //	- the second argument is a pointer
 //	- one return value, of type error
diff --git a/src/net/sendfile_dragonfly.go b/src/net/sendfile_dragonfly.go
index bc88fd3..a9cf3fe 100644
--- a/src/net/sendfile_dragonfly.go
+++ b/src/net/sendfile_dragonfly.go
@@ -91,13 +91,16 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
 		if err1 != nil {
 			// This includes syscall.ENOSYS (no kernel
 			// support) and syscall.EINVAL (fd types which
-			// don't implement sendfile together)
-			err = &OpError{"sendfile", c.net, c.raddr, err1}
+			// don't implement sendfile)
+			err = err1
 			break
 		}
 	}
 	if lr != nil {
 		lr.N = remain
 	}
+	if err != nil {
+		err = os.NewSyscallError("sendfile", err)
+	}
 	return written, err, written > 0
 }
diff --git a/src/net/sendfile_freebsd.go b/src/net/sendfile_freebsd.go
index ffc1472..d0bf603 100644
--- a/src/net/sendfile_freebsd.go
+++ b/src/net/sendfile_freebsd.go
@@ -91,13 +91,16 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
 		if err1 != nil {
 			// This includes syscall.ENOSYS (no kernel
 			// support) and syscall.EINVAL (fd types which
-			// don't implement sendfile together)
-			err = &OpError{"sendfile", c.net, c.raddr, err1}
+			// don't implement sendfile)
+			err = err1
 			break
 		}
 	}
 	if lr != nil {
 		lr.N = remain
 	}
+	if err != nil {
+		err = os.NewSyscallError("sendfile", err)
+	}
 	return written, err, written > 0
 }
diff --git a/src/net/sendfile_linux.go b/src/net/sendfile_linux.go
index 5e11763..5ca41c3 100644
--- a/src/net/sendfile_linux.go
+++ b/src/net/sendfile_linux.go
@@ -64,13 +64,16 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
 		if err1 != nil {
 			// This includes syscall.ENOSYS (no kernel
 			// support) and syscall.EINVAL (fd types which
-			// don't implement sendfile together)
-			err = &OpError{"sendfile", c.net, c.raddr, err1}
+			// don't implement sendfile)
+			err = err1
 			break
 		}
 	}
 	if lr != nil {
 		lr.N = remain
 	}
+	if err != nil {
+		err = os.NewSyscallError("sendfile", err)
+	}
 	return written, err, written > 0
 }
diff --git a/src/net/sendfile_solaris.go b/src/net/sendfile_solaris.go
new file mode 100644
index 0000000..0966575
--- /dev/null
+++ b/src/net/sendfile_solaris.go
@@ -0,0 +1,110 @@
+// 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 (
+	"io"
+	"os"
+	"syscall"
+)
+
+// Not strictly needed, but very helpful for debugging, see issue #10221.
+//go:cgo_import_dynamic _ _ "libsendfile.so"
+//go:cgo_import_dynamic _ _ "libsocket.so"
+
+// maxSendfileSize is the largest chunk size we ask the kernel to copy
+// at a time.
+const maxSendfileSize int = 4 << 20
+
+// sendFile copies the contents of r to c using the sendfile
+// system call to minimize copies.
+//
+// if handled == true, sendFile returns the number of bytes copied and any
+// non-EOF error.
+//
+// if handled == false, sendFile performed no work.
+func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
+	// Solaris uses 0 as the "until EOF" value. If you pass in more bytes than the
+	// file contains, it will loop back to the beginning ad nauseam until it's sent
+	// exactly the number of bytes told to. As such, we need to know exactly how many
+	// bytes to send.
+	var remain int64 = 0
+
+	lr, ok := r.(*io.LimitedReader)
+	if ok {
+		remain, r = lr.N, lr.R
+		if remain <= 0 {
+			return 0, nil, true
+		}
+	}
+	f, ok := r.(*os.File)
+	if !ok {
+		return 0, nil, false
+	}
+
+	if remain == 0 {
+		fi, err := f.Stat()
+		if err != nil {
+			return 0, err, false
+		}
+
+		remain = fi.Size()
+	}
+
+	// The other quirk with Solaris's sendfile implementation is that it doesn't
+	// use the current position of the file -- if you pass it offset 0, it starts
+	// from offset 0. There's no way to tell it "start from current position", so
+	// we have to manage that explicitly.
+	pos, err := f.Seek(0, os.SEEK_CUR)
+	if err != nil {
+		return 0, err, false
+	}
+
+	if err := c.writeLock(); err != nil {
+		return 0, err, true
+	}
+	defer c.writeUnlock()
+
+	dst := c.sysfd
+	src := int(f.Fd())
+	for remain > 0 {
+		n := maxSendfileSize
+		if int64(n) > remain {
+			n = int(remain)
+		}
+		pos1 := pos
+		n, err1 := syscall.Sendfile(dst, src, &pos1, n)
+		if n > 0 {
+			pos += int64(n)
+			written += int64(n)
+			remain -= int64(n)
+		}
+		if n == 0 && err1 == nil {
+			break
+		}
+		if err1 == syscall.EAGAIN {
+			if err1 = c.pd.WaitWrite(); err1 == nil {
+				continue
+			}
+		}
+		if err1 == syscall.EINTR {
+			continue
+		}
+		if err1 != nil {
+			// This includes syscall.ENOSYS (no kernel
+			// support) and syscall.EINVAL (fd types which
+			// don't implement sendfile)
+			err = err1
+			break
+		}
+	}
+	if lr != nil {
+		lr.N = remain
+	}
+	if err != nil {
+		err = os.NewSyscallError("sendfile", err)
+	}
+	return written, err, written > 0
+}
diff --git a/src/net/sendfile_stub.go b/src/net/sendfile_stub.go
index 03426ef..a0760b4 100644
--- a/src/net/sendfile_stub.go
+++ b/src/net/sendfile_stub.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 nacl netbsd openbsd solaris
+// +build darwin nacl netbsd openbsd
 
 package net
 
diff --git a/src/net/sendfile_windows.go b/src/net/sendfile_windows.go
index b128ba2..f3f3b54 100644
--- a/src/net/sendfile_windows.go
+++ b/src/net/sendfile_windows.go
@@ -46,7 +46,7 @@ func sendFile(fd *netFD, r io.Reader) (written int64, err error, handled bool) {
 		return syscall.TransmitFile(o.fd.sysfd, o.handle, o.qty, 0, &o.o, nil, syscall.TF_WRITE_BEHIND)
 	})
 	if err != nil {
-		return 0, err, false
+		return 0, os.NewSyscallError("transmitfile", err), false
 	}
 	if lr != nil {
 		lr.N -= int64(done)
diff --git a/src/net/server_test.go b/src/net/server_test.go
index 6a2bb92..fe0006b 100644
--- a/src/net/server_test.go
+++ b/src/net/server_test.go
@@ -5,457 +5,384 @@
 package net
 
 import (
-	"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
+var tcpServerTests = []struct {
+	snet, saddr string // server endpoint
+	tnet, taddr string // target endpoint for client
 }{
-	{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", tnet: "tcp", taddr: "127.0.0.1"},
+	{snet: "tcp", saddr: "0.0.0.0:0", tnet: "tcp", taddr: "127.0.0.1"},
+	{snet: "tcp", saddr: "[::ffff:0.0.0.0]:0", tnet: "tcp", taddr: "127.0.0.1"},
+	{snet: "tcp", saddr: "[::]:0", tnet: "tcp", taddr: "::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", tnet: "tcp", taddr: "::1"},
+	{snet: "tcp", saddr: "0.0.0.0:0", tnet: "tcp", taddr: "::1"},
+	{snet: "tcp", saddr: "[::ffff:0.0.0.0]:0", tnet: "tcp", taddr: "::1"},
+	{snet: "tcp", saddr: "[::]:0", tnet: "tcp", taddr: "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", tnet: "tcp4", taddr: "127.0.0.1"},
+	{snet: "tcp", saddr: "0.0.0.0:0", tnet: "tcp4", taddr: "127.0.0.1"},
+	{snet: "tcp", saddr: "[::ffff:0.0.0.0]:0", tnet: "tcp4", taddr: "127.0.0.1"},
+	{snet: "tcp", saddr: "[::]:0", tnet: "tcp6", taddr: "::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", tnet: "tcp6", taddr: "::1"},
+	{snet: "tcp", saddr: "0.0.0.0:0", tnet: "tcp6", taddr: "::1"},
+	{snet: "tcp", saddr: "[::ffff:0.0.0.0]:0", tnet: "tcp6", taddr: "::1"},
+	{snet: "tcp", saddr: "[::]:0", tnet: "tcp4", taddr: "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", tnet: "tcp", taddr: "127.0.0.1"},
+	{snet: "tcp", saddr: "[::ffff:127.0.0.1]:0", tnet: "tcp", taddr: "127.0.0.1"},
+	{snet: "tcp", saddr: "[::1]:0", tnet: "tcp", taddr: "::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", tnet: "tcp4", taddr: "127.0.0.1"},
+	{snet: "tcp4", saddr: "0.0.0.0:0", tnet: "tcp4", taddr: "127.0.0.1"},
+	{snet: "tcp4", saddr: "[::ffff:0.0.0.0]:0", tnet: "tcp4", taddr: "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", tnet: "tcp4", taddr: "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", tnet: "tcp6", taddr: "::1"},
+	{snet: "tcp6", saddr: "[::]:0", tnet: "tcp6", taddr: "::1"},
 
-	{snet: "tcp6", saddr: "[::1]", cnet: "tcp6", caddr: "[::1]", ipv6: true},
-
-	{snet: "unix", saddr: testUnixAddr(), cnet: "unix", caddr: testUnixAddr()},
-	{snet: "unix", saddr: "@gotest2/net", cnet: "unix", caddr: "@gotest2/net.local", linuxOnly: true},
+	{snet: "tcp6", saddr: "[::1]:0", tnet: "tcp6", taddr: "::1"},
 }
 
-func TestStreamConnServer(t *testing.T) {
-	for _, tt := range streamConnServerTests {
-		if skipServerTest(tt.snet, "unix", tt.saddr, tt.ipv6, tt.ipv4map, tt.linuxOnly) {
+// TestTCPServer tests concurrent accept-read-write servers.
+func TestTCPServer(t *testing.T) {
+	const N = 3
+
+	for i, tt := range tcpServerTests {
+		if !testableListenArgs(tt.snet, tt.saddr, tt.taddr) {
+			t.Logf("skipping %s test", tt.snet+" "+tt.saddr+"->"+tt.taddr)
 			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)
+		ln, err := Listen(tt.snet, tt.saddr)
+		if err != nil {
+			if perr := parseDialError(err); perr != nil {
+				t.Error(perr)
+			}
+			t.Fatal(err)
 		}
 
-		go runStreamConnServer(t, tt.snet, tt.saddr, listening, done)
-		taddr := <-listening // wait for server to start
-
-		switch tt.cnet {
-		case "tcp", "tcp4", "tcp6":
-			_, port, err := SplitHostPort(taddr)
+		var lss []*localServer
+		var tpchs []chan error
+		defer func() {
+			for _, ls := range lss {
+				ls.teardown()
+			}
+		}()
+		for i := 0; i < N; i++ {
+			ls, err := (&streamListener{Listener: ln}).newLocalServer()
 			if err != nil {
-				t.Fatalf("SplitHostPort(%q) failed: %v", taddr, err)
+				t.Fatal(err)
+			}
+			lss = append(lss, ls)
+			tpchs = append(tpchs, make(chan error, 1))
+		}
+		for i := 0; i < N; i++ {
+			ch := tpchs[i]
+			handler := func(ls *localServer, ln Listener) { transponder(ln, ch) }
+			if err := lss[i].buildup(handler); err != nil {
+				t.Fatal(err)
 			}
-			taddr = tt.caddr + ":" + port
 		}
 
-		runStreamConnClient(t, tt.cnet, taddr, tt.empty)
-		<-done // make sure server stopped
+		var trchs []chan error
+		for i := 0; i < N; i++ {
+			_, port, err := SplitHostPort(lss[i].Listener.Addr().String())
+			if err != nil {
+				t.Fatal(err)
+			}
+			d := Dialer{Timeout: someTimeout}
+			c, err := d.Dial(tt.tnet, JoinHostPort(tt.taddr, port))
+			if err != nil {
+				if perr := parseDialError(err); perr != nil {
+					t.Error(perr)
+				}
+				t.Fatal(err)
+			}
+			defer c.Close()
+			trchs = append(trchs, make(chan error, 1))
+			go transceiver(c, []byte("TCP SERVER TEST"), trchs[i])
+		}
 
-		switch tt.snet {
-		case "unix":
-			os.Remove(tt.saddr)
-			os.Remove(tt.caddr)
+		for _, ch := range trchs {
+			for err := range ch {
+				t.Errorf("#%d: %v", i, err)
+			}
+		}
+		for _, ch := range tpchs {
+			for err := range ch {
+				t.Errorf("#%d: %v", i, err)
+			}
 		}
 	}
 }
 
-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
+var unixAndUnixpacketServerTests = []struct {
+	network, address string
 }{
-	{net: "unixpacket", saddr: testUnixAddr(), caddr: testUnixAddr()},
-	{net: "unixpacket", saddr: "@gotest4/net", caddr: "@gotest4/net.local", linuxOnly: true},
+	{"unix", testUnixAddr()},
+	{"unix", "@nettest/go/unix"},
+
+	{"unixpacket", testUnixAddr()},
+	{"unixpacket", "@nettest/go/unixpacket"},
 }
 
-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)
-	}
+// TestUnixAndUnixpacketServer tests concurrent accept-read-write
+// servers
+func TestUnixAndUnixpacketServer(t *testing.T) {
+	const N = 3
 
-	for _, tt := range seqpacketConnServerTests {
-		if runtime.GOOS != "linux" && tt.linuxOnly {
+	for i, tt := range unixAndUnixpacketServerTests {
+		if !testableListenArgs(tt.network, tt.address, "") {
+			t.Logf("skipping %s test", tt.network+" "+tt.address)
 			continue
 		}
-		listening := make(chan string)
-		done := make(chan int)
-		switch tt.net {
-		case "unixpacket":
-			os.Remove(tt.saddr)
-			os.Remove(tt.caddr)
-		}
 
-		go runStreamConnServer(t, tt.net, tt.saddr, listening, done)
-		taddr := <-listening // wait for server to start
-
-		runStreamConnClient(t, tt.net, taddr, tt.empty)
-		<-done // make sure server stopped
-
-		switch tt.net {
-		case "unixpacket":
-			os.Remove(tt.saddr)
-			os.Remove(tt.caddr)
+		ln, err := Listen(tt.network, tt.address)
+		if err != nil {
+			if perr := parseDialError(err); perr != nil {
+				t.Error(perr)
+			}
+			t.Fatal(err)
 		}
-	}
-}
 
-func runStreamConnServer(t *testing.T, net, laddr string, listening chan<- string, done chan<- int) {
-	defer close(done)
-	l, err := Listen(net, laddr)
-	if err != nil {
-		t.Errorf("Listen(%q, %q) failed: %v", net, laddr, err)
-		listening <- "<nil>"
-		return
-	}
-	defer l.Close()
-	listening <- l.Addr().String()
-
-	echo := func(rw io.ReadWriter, done chan<- int) {
-		buf := make([]byte, 1024)
-		for {
-			n, err := rw.Read(buf[0:])
-			if err != nil || n == 0 || string(buf[:n]) == "END" {
-				break
+		var lss []*localServer
+		var tpchs []chan error
+		defer func() {
+			for _, ls := range lss {
+				ls.teardown()
 			}
-			rw.Write(buf[0:n])
+		}()
+		for i := 0; i < N; i++ {
+			ls, err := (&streamListener{Listener: ln}).newLocalServer()
+			if err != nil {
+				t.Fatal(err)
+			}
+			lss = append(lss, ls)
+			tpchs = append(tpchs, make(chan error, 1))
 		}
-		close(done)
-	}
-
-run:
-	for {
-		c, err := l.Accept()
-		if err != nil {
-			t.Logf("Accept failed: %v", err)
-			continue run
+		for i := 0; i < N; i++ {
+			ch := tpchs[i]
+			handler := func(ls *localServer, ln Listener) { transponder(ln, ch) }
+			if err := lss[i].buildup(handler); err != nil {
+				t.Fatal(err)
+			}
 		}
-		echodone := make(chan int)
-		go echo(c, echodone)
-		<-echodone // make sure echo stopped
-		c.Close()
-		break run
-	}
-}
-
-func runStreamConnClient(t *testing.T, net, taddr string, isEmpty bool) {
-	c, err := Dial(net, taddr)
-	if err != nil {
-		t.Fatalf("Dial(%q, %q) failed: %v", net, taddr, err)
-	}
-	defer c.Close()
-	c.SetReadDeadline(time.Now().Add(1 * time.Second))
 
-	var wb []byte
-	if !isEmpty {
-		wb = []byte("StreamConnClient by Dial\n")
-	}
-	if n, err := c.Write(wb); err != nil || n != len(wb) {
-		t.Fatalf("Write failed: %v, %v; want %v, <nil>", n, err, len(wb))
-	}
-
-	rb := make([]byte, 1024)
-	if n, err := c.Read(rb[0:]); err != nil || n != len(wb) {
-		t.Fatalf("Read failed: %v, %v; want %v, <nil>", n, err, len(wb))
-	}
+		var trchs []chan error
+		for i := 0; i < N; i++ {
+			d := Dialer{Timeout: someTimeout}
+			c, err := d.Dial(lss[i].Listener.Addr().Network(), lss[i].Listener.Addr().String())
+			if err != nil {
+				if perr := parseDialError(err); perr != nil {
+					t.Error(perr)
+				}
+				t.Fatal(err)
+			}
+			defer os.Remove(c.LocalAddr().String())
+			defer c.Close()
+			trchs = append(trchs, make(chan error, 1))
+			go transceiver(c, []byte("UNIX AND UNIXPACKET SERVER TEST"), trchs[i])
+		}
 
-	// Send explicit ending for unixpacket.
-	// Older Linux kernels do not stop reads on close.
-	switch net {
-	case "unixpacket":
-		c.Write([]byte("END"))
+		for _, ch := range trchs {
+			for err := range ch {
+				t.Errorf("#%d: %v", i, err)
+			}
+		}
+		for _, ch := range tpchs {
+			for err := range ch {
+				t.Errorf("#%d: %v", i, err)
+			}
+		}
 	}
 }
 
-// Do not test empty datagrams by default.
-// It causes unexplained timeouts on some systems,
-// including Snow Leopard.  I think that the kernel
-// doesn't quite expect them.
-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
+var udpServerTests = []struct {
+	snet, saddr string // server endpoint
+	tnet, taddr string // target endpoint for client
+	dial        bool   // test with Dial
 }{
-	{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: "", 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", tnet: "udp", taddr: "127.0.0.1"},
+	{snet: "udp", saddr: "0.0.0.0:0", tnet: "udp", taddr: "127.0.0.1"},
+	{snet: "udp", saddr: "[::ffff:0.0.0.0]:0", tnet: "udp", taddr: "127.0.0.1"},
+	{snet: "udp", saddr: "[::]:0", tnet: "udp", taddr: "::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", tnet: "udp", taddr: "::1"},
+	{snet: "udp", saddr: "0.0.0.0:0", tnet: "udp", taddr: "::1"},
+	{snet: "udp", saddr: "[::ffff:0.0.0.0]:0", tnet: "udp", taddr: "::1"},
+	{snet: "udp", saddr: "[::]:0", tnet: "udp", taddr: "127.0.0.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", tnet: "udp4", taddr: "127.0.0.1"},
+	{snet: "udp", saddr: "0.0.0.0:0", tnet: "udp4", taddr: "127.0.0.1"},
+	{snet: "udp", saddr: "[::ffff:0.0.0.0]:0", tnet: "udp4", taddr: "127.0.0.1"},
+	{snet: "udp", saddr: "[::]:0", tnet: "udp6", taddr: "::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: ":0", tnet: "udp6", taddr: "::1"},
+	{snet: "udp", saddr: "0.0.0.0:0", tnet: "udp6", taddr: "::1"},
+	{snet: "udp", saddr: "[::ffff:0.0.0.0]:0", tnet: "udp6", taddr: "::1"},
+	{snet: "udp", saddr: "[::]:0", tnet: "udp4", taddr: "127.0.0.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: "udp", saddr: "127.0.0.1:0", tnet: "udp", taddr: "127.0.0.1"},
+	{snet: "udp", saddr: "[::ffff:127.0.0.1]:0", tnet: "udp", taddr: "127.0.0.1"},
+	{snet: "udp", saddr: "[::1]:0", tnet: "udp", taddr: "::1"},
 
-	{snet: "udp4", saddr: "127.0.0.1", cnet: "udp4", caddr: "127.0.0.1"},
+	{snet: "udp4", saddr: ":0", tnet: "udp4", taddr: "127.0.0.1"},
+	{snet: "udp4", saddr: "0.0.0.0:0", tnet: "udp4", taddr: "127.0.0.1"},
+	{snet: "udp4", saddr: "[::ffff:0.0.0.0]:0", tnet: "udp4", taddr: "127.0.0.1"},
 
-	{snet: "udp6", saddr: "", cnet: "udp6", caddr: "[::1]", ipv6: true},
-	{snet: "udp6", saddr: "[::]", cnet: "udp6", caddr: "[::1]", ipv6: true},
+	{snet: "udp4", saddr: "127.0.0.1:0", tnet: "udp4", taddr: "127.0.0.1"},
 
-	{snet: "udp6", saddr: "[::1]", cnet: "udp6", caddr: "[::1]", ipv6: true},
+	{snet: "udp6", saddr: ":0", tnet: "udp6", taddr: "::1"},
+	{snet: "udp6", saddr: "[::]:0", tnet: "udp6", taddr: "::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: "udp6", saddr: "[::1]:0", tnet: "udp6", taddr: "::1"},
 
-	{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: "127.0.0.1:0", tnet: "udp", taddr: "127.0.0.1", dial: 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: "udp", saddr: "[::1]:0", tnet: "udp", taddr: "::1", dial: true},
 }
 
-func TestDatagramPacketConnServer(t *testing.T) {
-	if !*testDatagram {
-		return
-	}
-
-	for _, tt := range datagramPacketConnServerTests {
-		if skipServerTest(tt.snet, "unixgram", tt.saddr, tt.ipv6, tt.ipv4map, tt.linuxOnly) {
+func TestUDPServer(t *testing.T) {
+	for i, tt := range udpServerTests {
+		if !testableListenArgs(tt.snet, tt.saddr, tt.taddr) {
+			t.Logf("skipping %s test", tt.snet+" "+tt.saddr+"->"+tt.taddr)
 			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)
+		c1, err := ListenPacket(tt.snet, tt.saddr)
+		if err != nil {
+			if perr := parseDialError(err); perr != nil {
+				t.Error(perr)
+			}
+			t.Fatal(err)
 		}
 
-		go runDatagramPacketConnServer(t, tt.snet, tt.saddr, listening, done)
-		taddr := <-listening // wait for server to start
+		ls, err := (&packetListener{PacketConn: c1}).newLocalServer()
+		if err != nil {
+			t.Fatal(err)
+		}
+		defer ls.teardown()
+		tpch := make(chan error, 1)
+		handler := func(ls *localPacketServer, c PacketConn) { packetTransponder(c, tpch) }
+		if err := ls.buildup(handler); err != nil {
+			t.Fatal(err)
+		}
 
-		switch tt.cnet {
-		case "udp", "udp4", "udp6":
-			_, port, err := SplitHostPort(taddr)
-			if err != nil {
-				t.Fatalf("SplitHostPort(%q) failed: %v", taddr, err)
-			}
-			taddr = tt.caddr + ":" + port
-			tt.caddr += ":0"
+		trch := make(chan error, 1)
+		_, port, err := SplitHostPort(ls.PacketConn.LocalAddr().String())
+		if err != nil {
+			t.Fatal(err)
 		}
 		if tt.dial {
-			runDatagramConnClient(t, tt.cnet, tt.caddr, taddr, tt.empty)
+			d := Dialer{Timeout: someTimeout}
+			c2, err := d.Dial(tt.tnet, JoinHostPort(tt.taddr, port))
+			if err != nil {
+				if perr := parseDialError(err); perr != nil {
+					t.Error(perr)
+				}
+				t.Fatal(err)
+			}
+			defer c2.Close()
+			go transceiver(c2, []byte("UDP SERVER TEST"), trch)
 		} else {
-			runDatagramPacketConnClient(t, tt.cnet, tt.caddr, taddr, tt.empty)
+			c2, err := ListenPacket(tt.tnet, JoinHostPort(tt.taddr, "0"))
+			if err != nil {
+				if perr := parseDialError(err); perr != nil {
+					t.Error(perr)
+				}
+				t.Fatal(err)
+			}
+			defer c2.Close()
+			dst, err := ResolveUDPAddr(tt.tnet, JoinHostPort(tt.taddr, port))
+			if err != nil {
+				t.Fatal(err)
+			}
+			go packetTransceiver(c2, []byte("UDP SERVER TEST"), dst, trch)
 		}
-		<-done // tell server to stop
-		<-done // make sure server stopped
 
-		switch tt.snet {
-		case "unixgram":
-			os.Remove(tt.saddr)
-			os.Remove(tt.caddr)
+		for err := range trch {
+			t.Errorf("#%d: %v", i, err)
+		}
+		for err := range tpch {
+			t.Errorf("#%d: %v", i, err)
 		}
 	}
 }
 
-func runDatagramPacketConnServer(t *testing.T, net, laddr string, listening chan<- string, done chan<- int) {
-	c, err := ListenPacket(net, laddr)
-	if err != nil {
-		t.Errorf("ListenPacket(%q, %q) failed: %v", net, laddr, err)
-		listening <- "<nil>"
-		done <- 1
-		return
-	}
-	defer c.Close()
-	listening <- c.LocalAddr().String()
-
-	buf := make([]byte, 1024)
-run:
-	for {
-		c.SetReadDeadline(time.Now().Add(10 * time.Millisecond))
-		n, ra, err := c.ReadFrom(buf[0:])
-		if nerr, ok := err.(Error); ok && nerr.Timeout() {
-			select {
-			case done <- 1:
-				break run
-			default:
-				continue run
-			}
-		}
-		if err != nil {
-			break run
-		}
-		if _, err = c.WriteTo(buf[0:n], ra); err != nil {
-			t.Errorf("WriteTo(%v) failed: %v", ra, err)
-			break run
-		}
-	}
-	done <- 1
+var unixgramServerTests = []struct {
+	saddr string // server endpoint
+	caddr string // client endpoint
+	dial  bool   // test with Dial
+}{
+	{saddr: testUnixAddr(), caddr: testUnixAddr()},
+	{saddr: testUnixAddr(), caddr: testUnixAddr(), dial: true},
+
+	{saddr: "@nettest/go/unixgram/server", caddr: "@nettest/go/unixgram/client"},
 }
 
-func runDatagramConnClient(t *testing.T, net, laddr, taddr string, isEmpty bool) {
-	var c Conn
-	var err error
-	switch net {
-	case "udp", "udp4", "udp6":
-		c, err = Dial(net, taddr)
-		if err != nil {
-			t.Fatalf("Dial(%q, %q) failed: %v", net, taddr, err)
+func TestUnixgramServer(t *testing.T) {
+	for i, tt := range unixgramServerTests {
+		if !testableListenArgs("unixgram", tt.saddr, "") {
+			t.Logf("skipping %s test", "unixgram "+tt.saddr+"->"+tt.caddr)
+			continue
 		}
-	case "unixgram":
-		c, err = DialUnix(net, &UnixAddr{Name: laddr, Net: net}, &UnixAddr{Name: taddr, Net: net})
+
+		c1, err := ListenPacket("unixgram", tt.saddr)
 		if err != nil {
-			t.Fatalf("DialUnix(%q, {%q, %q}) failed: %v", net, laddr, taddr, err)
+			if perr := parseDialError(err); perr != nil {
+				t.Error(perr)
+			}
+			t.Fatal(err)
 		}
-	}
-	defer c.Close()
-	c.SetReadDeadline(time.Now().Add(1 * time.Second))
 
-	var wb []byte
-	if !isEmpty {
-		wb = []byte("DatagramConnClient by Dial\n")
-	}
-	if n, err := c.Write(wb[0:]); err != nil || n != len(wb) {
-		t.Fatalf("Write failed: %v, %v; want %v, <nil>", n, err, len(wb))
-	}
-
-	rb := make([]byte, 1024)
-	if n, err := c.Read(rb[0:]); err != nil || n != len(wb) {
-		t.Fatalf("Read failed: %v, %v; want %v, <nil>", n, err, len(wb))
-	}
-}
-
-func runDatagramPacketConnClient(t *testing.T, net, laddr, taddr string, isEmpty bool) {
-	var ra Addr
-	var err error
-	switch net {
-	case "udp", "udp4", "udp6":
-		ra, err = ResolveUDPAddr(net, taddr)
+		ls, err := (&packetListener{PacketConn: c1}).newLocalServer()
 		if err != nil {
-			t.Fatalf("ResolveUDPAddr(%q, %q) failed: %v", net, taddr, err)
+			t.Fatal(err)
 		}
-	case "unixgram":
-		ra, err = ResolveUnixAddr(net, taddr)
-		if err != nil {
-			t.Fatalf("ResolveUxixAddr(%q, %q) failed: %v", net, taddr, err)
+		defer ls.teardown()
+		tpch := make(chan error, 1)
+		handler := func(ls *localPacketServer, c PacketConn) { packetTransponder(c, tpch) }
+		if err := ls.buildup(handler); err != nil {
+			t.Fatal(err)
 		}
-	}
-	c, err := ListenPacket(net, laddr)
-	if err != nil {
-		t.Fatalf("ListenPacket(%q, %q) faild: %v", net, laddr, err)
-	}
-	defer c.Close()
-	c.SetReadDeadline(time.Now().Add(1 * time.Second))
 
-	var wb []byte
-	if !isEmpty {
-		wb = []byte("DatagramPacketConnClient by ListenPacket\n")
-	}
-	if n, err := c.WriteTo(wb[0:], ra); err != nil || n != len(wb) {
-		t.Fatalf("WriteTo(%v) failed: %v, %v; want %v, <nil>", ra, n, err, len(wb))
-	}
+		trch := make(chan error, 1)
+		if tt.dial {
+			d := Dialer{Timeout: someTimeout, LocalAddr: &UnixAddr{Net: "unixgram", Name: tt.caddr}}
+			c2, err := d.Dial("unixgram", ls.PacketConn.LocalAddr().String())
+			if err != nil {
+				if perr := parseDialError(err); perr != nil {
+					t.Error(perr)
+				}
+				t.Fatal(err)
+			}
+			defer os.Remove(c2.LocalAddr().String())
+			defer c2.Close()
+			go transceiver(c2, []byte(c2.LocalAddr().String()), trch)
+		} else {
+			c2, err := ListenPacket("unixgram", tt.caddr)
+			if err != nil {
+				if perr := parseDialError(err); perr != nil {
+					t.Error(perr)
+				}
+				t.Fatal(err)
+			}
+			defer os.Remove(c2.LocalAddr().String())
+			defer c2.Close()
+			go packetTransceiver(c2, []byte("UNIXGRAM SERVER TEST"), ls.PacketConn.LocalAddr(), trch)
+		}
 
-	rb := make([]byte, 1024)
-	if n, _, err := c.ReadFrom(rb[0:]); err != nil || n != len(wb) {
-		t.Fatalf("ReadFrom failed: %v, %v; want %v, <nil>", n, err, len(wb))
+		for err := range trch {
+			t.Errorf("#%d: %v", i, err)
+		}
+		for err := range tpch {
+			t.Errorf("#%d: %v", i, err)
+		}
 	}
 }
diff --git a/src/net/singleflight.go b/src/net/singleflight.go
deleted file mode 100644
index bf599f0..0000000
--- a/src/net/singleflight.go
+++ /dev/null
@@ -1,109 +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 net
-
-import "sync"
-
-// call is an in-flight or completed singleflight.Do call
-type call struct {
-	wg sync.WaitGroup
-
-	// These fields are written once before the WaitGroup is done
-	// and are only read after the WaitGroup is done.
-	val interface{}
-	err error
-
-	// These fields are read and written with the singleflight
-	// mutex held before the WaitGroup is done, and are read but
-	// not written after the WaitGroup is done.
-	dups  int
-	chans []chan<- singleflightResult
-}
-
-// singleflight represents a class of work and forms a namespace in
-// which units of work can be executed with duplicate suppression.
-type singleflight struct {
-	mu sync.Mutex       // protects m
-	m  map[string]*call // lazily initialized
-}
-
-// singleflightResult holds the results of Do, so they can be passed
-// on a channel.
-type singleflightResult struct {
-	v      interface{}
-	err    error
-	shared bool
-}
-
-// Do executes and returns the results of the given function, making
-// sure that only one execution is in-flight for a given key at a
-// time. If a duplicate comes in, the duplicate caller waits for the
-// original to complete and receives the same results.
-// The return value shared indicates whether v was given to multiple callers.
-func (g *singleflight) Do(key string, fn func() (interface{}, error)) (v interface{}, err error, shared bool) {
-	g.mu.Lock()
-	if g.m == nil {
-		g.m = make(map[string]*call)
-	}
-	if c, ok := g.m[key]; ok {
-		c.dups++
-		g.mu.Unlock()
-		c.wg.Wait()
-		return c.val, c.err, true
-	}
-	c := new(call)
-	c.wg.Add(1)
-	g.m[key] = c
-	g.mu.Unlock()
-
-	g.doCall(c, key, fn)
-	return c.val, c.err, c.dups > 0
-}
-
-// DoChan is like Do but returns a channel that will receive the
-// results when they are ready.
-func (g *singleflight) DoChan(key string, fn func() (interface{}, error)) <-chan singleflightResult {
-	ch := make(chan singleflightResult, 1)
-	g.mu.Lock()
-	if g.m == nil {
-		g.m = make(map[string]*call)
-	}
-	if c, ok := g.m[key]; ok {
-		c.dups++
-		c.chans = append(c.chans, ch)
-		g.mu.Unlock()
-		return ch
-	}
-	c := &call{chans: []chan<- singleflightResult{ch}}
-	c.wg.Add(1)
-	g.m[key] = c
-	g.mu.Unlock()
-
-	go g.doCall(c, key, fn)
-
-	return ch
-}
-
-// doCall handles the single call for a key.
-func (g *singleflight) doCall(c *call, key string, fn func() (interface{}, error)) {
-	c.val, c.err = fn()
-	c.wg.Done()
-
-	g.mu.Lock()
-	delete(g.m, key)
-	for _, ch := range c.chans {
-		ch <- singleflightResult{c.val, c.err, c.dups > 0}
-	}
-	g.mu.Unlock()
-}
-
-// Forget tells the singleflight to forget about a key.  Future calls
-// to Do for this key will call the function rather than waiting for
-// an earlier call to complete.
-func (g *singleflight) Forget(key string) {
-	g.mu.Lock()
-	delete(g.m, key)
-	g.mu.Unlock()
-}
diff --git a/src/net/smtp/example_test.go b/src/net/smtp/example_test.go
index d551e36..16419f4 100644
--- a/src/net/smtp/example_test.go
+++ b/src/net/smtp/example_test.go
@@ -46,14 +46,36 @@ func Example() {
 	}
 }
 
+// variables to make ExamplePlainAuth compile, without adding
+// unnecessary noise there.
+var (
+	from       = "gopher at example.net"
+	msg        = []byte("dummy message")
+	recipients = []string{"foo at example.com"}
+)
+
 func ExamplePlainAuth() {
+	// hostname is used by PlainAuth to validate the TLS certificate.
+	hostname := "mail.example.com"
+	auth := smtp.PlainAuth("", "user at example.com", "password", hostname)
+
+	err := smtp.SendMail(hostname+":25", auth, from, recipients, msg)
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+
+func ExampleSendMail() {
 	// Set up authentication information.
 	auth := smtp.PlainAuth("", "user at example.com", "password", "mail.example.com")
 
 	// Connect to the server, authenticate, set the sender and recipient,
 	// and send the email all in one step.
 	to := []string{"recipient at example.net"}
-	msg := []byte("This is the email body.")
+	msg := []byte("To: recipient at example.net\r\n" +
+		"Subject: discount Gophers!\r\n" +
+		"\r\n" +
+		"This is the email body.\r\n")
 	err := smtp.SendMail("mail.example.com:25", auth, "sender at example.org", to, msg)
 	if err != nil {
 		log.Fatal(err)
diff --git a/src/net/smtp/smtp.go b/src/net/smtp/smtp.go
index 87dea44..0988350 100644
--- a/src/net/smtp/smtp.go
+++ b/src/net/smtp/smtp.go
@@ -41,7 +41,7 @@ type Client struct {
 }
 
 // Dial returns a new Client connected to an SMTP server at addr.
-// The addr must include a port number.
+// The addr must include a port, as in "mail.example.com:smtp".
 func Dial(addr string) (*Client, error) {
 	conn, err := net.Dial("tcp", addr)
 	if err != nil {
@@ -157,6 +157,17 @@ func (c *Client) StartTLS(config *tls.Config) error {
 	return c.ehlo()
 }
 
+// TLSConnectionState returns the client's TLS connection state.
+// The return values are their zero values if StartTLS did
+// not succeed.
+func (c *Client) TLSConnectionState() (state tls.ConnectionState, ok bool) {
+	tc, ok := c.conn.(*tls.Conn)
+	if !ok {
+		return
+	}
+	return tc.ConnectionState(), true
+}
+
 // Verify checks the validity of an email address on the server.
 // If Verify returns nil, the address is valid. A non-nil return
 // does not necessarily indicate an invalid address. Many servers
@@ -253,9 +264,9 @@ func (d *dataCloser) Close() error {
 }
 
 // Data issues a DATA command to the server and returns a writer that
-// can be used to write the data. The caller should close the writer
-// before calling any more methods on c.
-// A call to Data must be preceded by one or more calls to Rcpt.
+// can be used to write the mail headers and body. The caller should
+// close the writer before calling any more methods on c.  A call to
+// Data must be preceded by one or more calls to Rcpt.
 func (c *Client) Data() (io.WriteCloser, error) {
 	_, _, err := c.cmd(354, "DATA")
 	if err != nil {
@@ -270,6 +281,22 @@ var testHookStartTLS func(*tls.Config) // nil, except for tests
 // possible, authenticates with the optional mechanism a if possible,
 // and then sends an email from address from, to addresses to, with
 // message msg.
+// The addr must include a port, as in "mail.example.com:smtp".
+//
+// The addresses in the to parameter are the SMTP RCPT addresses.
+//
+// The msg parameter should be an RFC 822-style email with headers
+// first, a blank line, and then the message body. The lines of msg
+// should be CRLF terminated.  The msg headers should usually include
+// fields such as "From", "To", "Subject", and "Cc".  Sending "Bcc"
+// messages is accomplished by including an email address in the to
+// parameter but not including it in the msg headers.
+//
+// The SendMail function and the the net/smtp package are low-level
+// mechanisms and provide no support for DKIM signing, MIME
+// attachments (see the mime/multipart package), or other mail
+// functionality. Higher-level packages exist outside of the standard
+// library.
 func SendMail(addr string, a Auth, from string, to []string, msg []byte) error {
 	c, err := Dial(addr)
 	if err != nil {
diff --git a/src/net/smtp/smtp_test.go b/src/net/smtp/smtp_test.go
index 5c659e8..3ae0d5b 100644
--- a/src/net/smtp/smtp_test.go
+++ b/src/net/smtp/smtp_test.go
@@ -571,6 +571,50 @@ func TestTLSClient(t *testing.T) {
 	}
 }
 
+func TestTLSConnState(t *testing.T) {
+	ln := newLocalListener(t)
+	defer ln.Close()
+	clientDone := make(chan bool)
+	serverDone := make(chan bool)
+	go func() {
+		defer close(serverDone)
+		c, err := ln.Accept()
+		if err != nil {
+			t.Errorf("Server accept: %v", err)
+			return
+		}
+		defer c.Close()
+		if err := serverHandle(c, t); err != nil {
+			t.Errorf("server error: %v", err)
+		}
+	}()
+	go func() {
+		defer close(clientDone)
+		c, err := Dial(ln.Addr().String())
+		if err != nil {
+			t.Errorf("Client dial: %v", err)
+			return
+		}
+		defer c.Quit()
+		cfg := &tls.Config{ServerName: "example.com"}
+		testHookStartTLS(cfg) // set the RootCAs
+		if err := c.StartTLS(cfg); err != nil {
+			t.Errorf("StartTLS: %v", err)
+			return
+		}
+		cs, ok := c.TLSConnectionState()
+		if !ok {
+			t.Errorf("TLSConnectionState returned ok == false; want true")
+			return
+		}
+		if cs.Version == 0 || !cs.HandshakeComplete {
+			t.Errorf("ConnectionState = %#v; expect non-zero Version and HandshakeComplete", cs)
+		}
+	}()
+	<-clientDone
+	<-serverDone
+}
+
 func newLocalListener(t *testing.T) net.Listener {
 	ln, err := net.Listen("tcp", "127.0.0.1:0")
 	if err != nil {
diff --git a/src/net/sock_cloexec.go b/src/net/sock_cloexec.go
index dec8185..616a101 100644
--- a/src/net/sock_cloexec.go
+++ b/src/net/sock_cloexec.go
@@ -9,34 +9,41 @@
 
 package net
 
-import "syscall"
+import (
+	"os"
+	"syscall"
+)
 
 // 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
 	// or EPROTONOSUPPORT error on FreeBSD, fall back to using
 	// socket without them.
-	if err == nil || (err != syscall.EPROTONOSUPPORT && err != syscall.EINVAL) {
-		return s, err
+	switch err {
+	case nil:
+		return s, nil
+	default:
+		return -1, os.NewSyscallError("socket", err)
+	case syscall.EPROTONOSUPPORT, syscall.EINVAL:
 	}
 
 	// 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)
 	}
 	syscall.ForkLock.RUnlock()
 	if err != nil {
-		return -1, err
+		return -1, os.NewSyscallError("socket", err)
 	}
 	if err = syscall.SetNonblock(s, true); err != nil {
-		syscall.Close(s)
-		return -1, err
+		closeFunc(s)
+		return -1, os.NewSyscallError("setnonblock", err)
 	}
 	return s, nil
 }
@@ -44,14 +51,16 @@ func sysSocket(family, sotype, proto int) (int, error) {
 // 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
 	// error on Linux, fall back to using accept.
 	switch err {
-	default: // nil and errors other than the ones listed
-		return ns, sa, err
+	case nil:
+		return ns, sa, nil
+	default: // errors other than the ones listed
+		return -1, sa, os.NewSyscallError("accept4", err)
 	case syscall.ENOSYS: // syscall missing
 	case syscall.EINVAL: // some Linux use this instead of ENOSYS
 	case syscall.EACCES: // some Linux use this instead of ENOSYS
@@ -63,16 +72,16 @@ func accept(s int) (int, syscall.Sockaddr, error) {
 	// 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)
 	}
 	if err != nil {
-		return -1, nil, err
+		return -1, nil, os.NewSyscallError("accept", err)
 	}
 	if err = syscall.SetNonblock(ns, true); err != nil {
-		syscall.Close(ns)
-		return -1, nil, err
+		closeFunc(ns)
+		return -1, nil, os.NewSyscallError("setnonblock", err)
 	}
 	return ns, sa, nil
 }
diff --git a/src/net/sock_posix.go b/src/net/sock_posix.go
index 3f956df..4d2cfde 100644
--- a/src/net/sock_posix.go
+++ b/src/net/sock_posix.go
@@ -17,8 +17,6 @@ import (
 type sockaddr interface {
 	Addr
 
-	netaddr
-
 	// family returns the platform-dependent address family
 	// identifier.
 	family() int
@@ -42,11 +40,11 @@ func socket(net string, family, sotype, proto int, ipv6only bool, laddr, raddr s
 		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
 	}
 
@@ -54,7 +52,7 @@ func socket(net string, family, sotype, proto int, ipv6only bool, laddr, raddr s
 	// following applications:
 	//
 	// - An endpoint holder that opens a passive stream
-	//   connenction, known as a stream listener
+	//   connection, known as a stream listener
 	//
 	// - An endpoint holder that opens a destination-unspecific
 	//   datagram connection, known as a datagram listener
@@ -165,7 +163,7 @@ func (fd *netFD) listenStream(laddr sockaddr, backlog int) error {
 			return os.NewSyscallError("bind", err)
 		}
 	}
-	if err := syscall.Listen(fd.sysfd, backlog); err != nil {
+	if err := listenFunc(fd.sysfd, backlog); err != nil {
 		return os.NewSyscallError("listen", err)
 	}
 	if err := fd.init(); err != nil {
diff --git a/src/net/sock_windows.go b/src/net/sock_windows.go
index 6ccde3a..888e70b 100644
--- a/src/net/sock_windows.go
+++ b/src/net/sock_windows.go
@@ -4,7 +4,10 @@
 
 package net
 
-import "syscall"
+import (
+	"os"
+	"syscall"
+)
 
 func maxListenerBacklog() int {
 	// TODO: Implement this
@@ -12,13 +15,16 @@ func maxListenerBacklog() int {
 	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)
 	}
 	syscall.ForkLock.RUnlock()
-	return s, err
+	if err != nil {
+		return syscall.InvalidHandle, os.NewSyscallError("socket", err)
+	}
+	return s, nil
 }
diff --git a/src/net/sockopt_bsd.go b/src/net/sockopt_bsd.go
index 00e4dbf..1b4a586 100644
--- a/src/net/sockopt_bsd.go
+++ b/src/net/sockopt_bsd.go
@@ -25,7 +25,7 @@ func setDefaultSockopts(s, family, sotype int, ipv6only bool) error {
 			syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_PORTRANGE, syscall.IPV6_PORTRANGE_HIGH)
 		}
 	}
-	if family == syscall.AF_INET6 && sotype != syscall.SOCK_RAW {
+	if supportsIPv4map && family == syscall.AF_INET6 && sotype != syscall.SOCK_RAW {
 		// Allow both IP versions even if the OS default
 		// is otherwise.  Note that some operating systems
 		// never admit this option.
diff --git a/src/net/sys_cloexec.go b/src/net/sys_cloexec.go
index 898fb7c..ba266e6 100644
--- a/src/net/sys_cloexec.go
+++ b/src/net/sys_cloexec.go
@@ -9,24 +9,27 @@
 
 package net
 
-import "syscall"
+import (
+	"os"
+	"syscall"
+)
 
 // 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) {
 	// 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)
 	}
 	syscall.ForkLock.RUnlock()
 	if err != nil {
-		return -1, err
+		return -1, os.NewSyscallError("socket", err)
 	}
 	if err = syscall.SetNonblock(s, true); err != nil {
-		syscall.Close(s)
-		return -1, err
+		closeFunc(s)
+		return -1, os.NewSyscallError("setnonblock", err)
 	}
 	return s, nil
 }
@@ -39,16 +42,16 @@ func accept(s int) (int, syscall.Sockaddr, error) {
 	// 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)
 	}
 	if err != nil {
-		return -1, nil, err
+		return -1, nil, os.NewSyscallError("accept", err)
 	}
 	if err = syscall.SetNonblock(ns, true); err != nil {
-		syscall.Close(ns)
-		return -1, nil, err
+		closeFunc(ns)
+		return -1, nil, os.NewSyscallError("setnonblock", err)
 	}
 	return ns, sa, nil
 }
diff --git a/src/net/tcp_test.go b/src/net/tcp_test.go
index c04198e..2191c91 100644
--- a/src/net/tcp_test.go
+++ b/src/net/tcp_test.go
@@ -5,7 +5,6 @@
 package net
 
 import (
-	"fmt"
 	"io"
 	"reflect"
 	"runtime"
@@ -59,6 +58,8 @@ func BenchmarkTCP6PersistentTimeout(b *testing.B) {
 }
 
 func benchmarkTCP(b *testing.B, persistent, timeout bool, laddr string) {
+	testHookUninstaller.Do(uninstallTestHooks)
+
 	const msgLen = 512
 	conns := b.N
 	numConcurrent := runtime.GOMAXPROCS(-1) * 2
@@ -76,7 +77,7 @@ func benchmarkTCP(b *testing.B, persistent, timeout bool, laddr string) {
 	sendMsg := func(c Conn, buf []byte) bool {
 		n, err := c.Write(buf)
 		if n != len(buf) || err != nil {
-			b.Logf("Write failed: %v", err)
+			b.Log(err)
 			return false
 		}
 		return true
@@ -86,7 +87,7 @@ func benchmarkTCP(b *testing.B, persistent, timeout bool, laddr string) {
 			n, err := c.Read(buf)
 			read += n
 			if err != nil {
-				b.Logf("Read failed: %v", err)
+				b.Log(err)
 				return false
 			}
 		}
@@ -94,7 +95,7 @@ func benchmarkTCP(b *testing.B, persistent, timeout bool, laddr string) {
 	}
 	ln, err := Listen("tcp", laddr)
 	if err != nil {
-		b.Fatalf("Listen failed: %v", err)
+		b.Fatal(err)
 	}
 	defer ln.Close()
 	serverSem := make(chan bool, numConcurrent)
@@ -134,7 +135,7 @@ func benchmarkTCP(b *testing.B, persistent, timeout bool, laddr string) {
 			}()
 			c, err := Dial("tcp", ln.Addr().String())
 			if err != nil {
-				b.Logf("Dial failed: %v", err)
+				b.Log(err)
 				return
 			}
 			defer c.Close()
@@ -167,6 +168,8 @@ func BenchmarkTCP6ConcurrentReadWrite(b *testing.B) {
 }
 
 func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) {
+	testHookUninstaller.Do(uninstallTestHooks)
+
 	// The benchmark creates GOMAXPROCS client/server pairs.
 	// Each pair creates 4 goroutines: client reader/writer and server reader/writer.
 	// The benchmark stresses concurrent reading and writing to the same connection.
@@ -183,7 +186,7 @@ func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) {
 	servers := make([]Conn, P)
 	ln, err := Listen("tcp", laddr)
 	if err != nil {
-		b.Fatalf("Listen failed: %v", err)
+		b.Fatal(err)
 	}
 	defer ln.Close()
 	done := make(chan bool)
@@ -191,7 +194,7 @@ func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) {
 		for p := 0; p < P; p++ {
 			s, err := ln.Accept()
 			if err != nil {
-				b.Errorf("Accept failed: %v", err)
+				b.Error(err)
 				return
 			}
 			servers[p] = s
@@ -201,7 +204,7 @@ func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) {
 	for p := 0; p < P; p++ {
 		c, err := Dial("tcp", ln.Addr().String())
 		if err != nil {
-			b.Fatalf("Dial failed: %v", err)
+			b.Fatal(err)
 		}
 		clients[p] = c
 	}
@@ -224,7 +227,7 @@ func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) {
 				buf[0] = v
 				_, err := c.Write(buf[:])
 				if err != nil {
-					b.Errorf("Write failed: %v", err)
+					b.Error(err)
 					return
 				}
 			}
@@ -240,7 +243,7 @@ func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) {
 			for i := 0; i < N; i++ {
 				_, err := s.Read(buf[:])
 				if err != nil {
-					b.Errorf("Read failed: %v", err)
+					b.Error(err)
 					return
 				}
 				pipe <- buf[0]
@@ -259,7 +262,7 @@ func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) {
 				buf[0] = v
 				_, err := s.Write(buf[:])
 				if err != nil {
-					b.Errorf("Write failed: %v", err)
+					b.Error(err)
 					return
 				}
 			}
@@ -273,7 +276,7 @@ func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) {
 			for i := 0; i < N; i++ {
 				_, err := c.Read(buf[:])
 				if err != nil {
-					b.Errorf("Read failed: %v", err)
+					b.Error(err)
 					return
 				}
 			}
@@ -284,7 +287,7 @@ func benchmarkTCPConcurrentReadWrite(b *testing.B, laddr string) {
 }
 
 type resolveTCPAddrTest struct {
-	net           string
+	network       string
 	litAddrOrName string
 	addr          *TCPAddr
 	err           error
@@ -294,8 +297,8 @@ var resolveTCPAddrTests = []resolveTCPAddrTest{
 	{"tcp", "127.0.0.1:0", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 0}, nil},
 	{"tcp4", "127.0.0.1:65535", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 65535}, nil},
 
-	{"tcp", "[::1]:1", &TCPAddr{IP: ParseIP("::1"), Port: 1}, nil},
-	{"tcp6", "[::1]:65534", &TCPAddr{IP: ParseIP("::1"), Port: 65534}, nil},
+	{"tcp", "[::1]:0", &TCPAddr{IP: ParseIP("::1"), Port: 0}, nil},
+	{"tcp6", "[::1]:65535", &TCPAddr{IP: ParseIP("::1"), Port: 65535}, nil},
 
 	{"tcp", "[::1%en0]:1", &TCPAddr{IP: ParseIP("::1"), Port: 1, Zone: "en0"}, nil},
 	{"tcp6", "[::1%911]:2", &TCPAddr{IP: ParseIP("::1"), Port: 2, Zone: "911"}, nil},
@@ -308,41 +311,26 @@ var resolveTCPAddrTests = []resolveTCPAddrTest{
 	{"http", "127.0.0.1:0", nil, UnknownNetworkError("http")},
 }
 
-func init() {
-	if ifi := loopbackInterface(); ifi != nil {
-		index := fmt.Sprintf("%v", ifi.Index)
-		resolveTCPAddrTests = append(resolveTCPAddrTests, []resolveTCPAddrTest{
-			{"tcp6", "[fe80::1%" + ifi.Name + "]:3", &TCPAddr{IP: ParseIP("fe80::1"), Port: 3, Zone: zoneToString(ifi.Index)}, nil},
-			{"tcp6", "[fe80::1%" + index + "]:4", &TCPAddr{IP: ParseIP("fe80::1"), Port: 4, Zone: index}, nil},
-		}...)
-	}
-	if ips, err := LookupIP("localhost"); err == nil && len(ips) > 1 && supportsIPv4 && supportsIPv6 {
-		resolveTCPAddrTests = append(resolveTCPAddrTests, []resolveTCPAddrTest{
-			{"tcp", "localhost:5", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 5}, nil},
-			{"tcp4", "localhost:6", &TCPAddr{IP: IPv4(127, 0, 0, 1), Port: 6}, nil},
-			{"tcp6", "localhost:7", &TCPAddr{IP: IPv6loopback, Port: 7}, nil},
-		}...)
-	}
-}
-
 func TestResolveTCPAddr(t *testing.T) {
-	for _, tt := range resolveTCPAddrTests {
-		addr, err := ResolveTCPAddr(tt.net, tt.litAddrOrName)
+	origTestHookLookupIP := testHookLookupIP
+	defer func() { testHookLookupIP = origTestHookLookupIP }()
+	testHookLookupIP = lookupLocalhost
+
+	for i, tt := range resolveTCPAddrTests {
+		addr, err := ResolveTCPAddr(tt.network, tt.litAddrOrName)
 		if err != tt.err {
-			t.Fatalf("ResolveTCPAddr(%q, %q) failed: %v", tt.net, tt.litAddrOrName, err)
+			t.Errorf("#%d: %v", i, err)
+		} else if !reflect.DeepEqual(addr, tt.addr) {
+			t.Errorf("#%d: got %#v; want %#v", i, addr, tt.addr)
 		}
-		if !reflect.DeepEqual(addr, tt.addr) {
-			t.Fatalf("ResolveTCPAddr(%q, %q) = %#v, want %#v", tt.net, tt.litAddrOrName, addr, tt.addr)
+		if err != nil {
+			continue
 		}
-		if err == nil {
-			str := addr.String()
-			addr1, err := ResolveTCPAddr(tt.net, str)
-			if err != nil {
-				t.Fatalf("ResolveTCPAddr(%q, %q) [from %q]: %v", tt.net, str, tt.litAddrOrName, err)
-			}
-			if !reflect.DeepEqual(addr1, addr) {
-				t.Fatalf("ResolveTCPAddr(%q, %q) [from %q] = %#v, want %#v", tt.net, str, tt.litAddrOrName, addr1, addr)
-			}
+		rtaddr, err := ResolveTCPAddr(addr.Network(), addr.String())
+		if err != nil {
+			t.Errorf("#%d: %v", i, err)
+		} else if !reflect.DeepEqual(rtaddr, addr) {
+			t.Errorf("#%d: got %#v; want %#v", i, rtaddr, addr)
 		}
 	}
 }
@@ -358,13 +346,13 @@ var tcpListenerNameTests = []struct {
 
 func TestTCPListenerName(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
+		t.Skip("avoid external network")
 	}
 
 	for _, tt := range tcpListenerNameTests {
 		ln, err := ListenTCP(tt.net, tt.laddr)
 		if err != nil {
-			t.Fatalf("ListenTCP failed: %v", err)
+			t.Fatal(err)
 		}
 		defer ln.Close()
 		la := ln.Addr()
@@ -376,59 +364,37 @@ func TestTCPListenerName(t *testing.T) {
 
 func TestIPv6LinkLocalUnicastTCP(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
+		t.Skip("avoid external network")
 	}
 	if !supportsIPv6 {
-		t.Skip("ipv6 is not supported")
-	}
-	ifi := loopbackInterface()
-	if ifi == nil {
-		t.Skip("loopback interface not found")
-	}
-	laddr := ipv6LinkLocalUnicastAddr(ifi)
-	if laddr == "" {
-		t.Skip("ipv6 unicast address on loopback not found")
+		t.Skip("IPv6 is not supported")
 	}
 
-	type test struct {
-		net, addr  string
-		nameLookup bool
-	}
-	var tests = []test{
-		{"tcp", "[" + laddr + "%" + ifi.Name + "]:0", false},
-		{"tcp6", "[" + laddr + "%" + ifi.Name + "]:0", false},
-	}
-	switch runtime.GOOS {
-	case "darwin", "freebsd", "openbsd", "netbsd":
-		tests = append(tests, []test{
-			{"tcp", "[localhost%" + ifi.Name + "]:0", true},
-			{"tcp6", "[localhost%" + ifi.Name + "]:0", true},
-		}...)
-	case "linux":
-		tests = append(tests, []test{
-			{"tcp", "[ip6-localhost%" + ifi.Name + "]:0", true},
-			{"tcp6", "[ip6-localhost%" + ifi.Name + "]:0", true},
-		}...)
-	}
-	for _, tt := range tests {
-		ln, err := Listen(tt.net, tt.addr)
+	for i, tt := range ipv6LinkLocalUnicastTCPTests {
+		ln, err := Listen(tt.network, tt.address)
 		if err != nil {
 			// It might return "LookupHost returned no
 			// suitable address" error on some platforms.
-			t.Logf("Listen failed: %v", err)
+			t.Log(err)
 			continue
 		}
-		defer ln.Close()
+		ls, err := (&streamListener{Listener: ln}).newLocalServer()
+		if err != nil {
+			t.Fatal(err)
+		}
+		defer ls.teardown()
+		ch := make(chan error, 1)
+		handler := func(ls *localServer, ln Listener) { transponder(ln, ch) }
+		if err := ls.buildup(handler); err != nil {
+			t.Fatal(err)
+		}
 		if la, ok := ln.Addr().(*TCPAddr); !ok || !tt.nameLookup && la.Zone == "" {
 			t.Fatalf("got %v; expected a proper address with zone identifier", la)
 		}
 
-		done := make(chan int)
-		go transponder(t, ln, done)
-
-		c, err := Dial(tt.net, ln.Addr().String())
+		c, err := Dial(tt.network, ls.Listener.Addr().String())
 		if err != nil {
-			t.Fatalf("Dial failed: %v", err)
+			t.Fatal(err)
 		}
 		defer c.Close()
 		if la, ok := c.LocalAddr().(*TCPAddr); !ok || !tt.nameLookup && la.Zone == "" {
@@ -439,14 +405,16 @@ func TestIPv6LinkLocalUnicastTCP(t *testing.T) {
 		}
 
 		if _, err := c.Write([]byte("TCP OVER IPV6 LINKLOCAL TEST")); err != nil {
-			t.Fatalf("Conn.Write failed: %v", err)
+			t.Fatal(err)
 		}
 		b := make([]byte, 32)
 		if _, err := c.Read(b); err != nil {
-			t.Fatalf("Conn.Read failed: %v", err)
+			t.Fatal(err)
 		}
 
-		<-done
+		for err := range ch {
+			t.Errorf("#%d: %v", i, err)
+		}
 	}
 }
 
@@ -454,7 +422,7 @@ func TestTCPConcurrentAccept(t *testing.T) {
 	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
 	ln, err := Listen("tcp", "127.0.0.1:0")
 	if err != nil {
-		t.Fatalf("Listen failed: %v", err)
+		t.Fatal(err)
 	}
 	const N = 10
 	var wg sync.WaitGroup
@@ -492,13 +460,19 @@ func TestTCPConcurrentAccept(t *testing.T) {
 	}
 }
 
-func TestTCPReadWriteMallocs(t *testing.T) {
-	if testing.Short() {
-		t.Skip("skipping malloc count in short mode")
+func TestTCPReadWriteAllocs(t *testing.T) {
+	switch runtime.GOOS {
+	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.
+		t.Skipf("not supported on %s", runtime.GOOS)
 	}
+
 	ln, err := Listen("tcp", "127.0.0.1:0")
 	if err != nil {
-		t.Fatalf("Listen failed: %v", err)
+		t.Fatal(err)
 	}
 	defer ln.Close()
 	var server Conn
@@ -510,25 +484,26 @@ func TestTCPReadWriteMallocs(t *testing.T) {
 	}()
 	client, err := Dial("tcp", ln.Addr().String())
 	if err != nil {
-		t.Fatalf("Dial failed: %v", err)
+		t.Fatal(err)
 	}
+	defer client.Close()
 	if err := <-errc; err != nil {
-		t.Fatalf("Accept failed: %v", err)
+		t.Fatal(err)
 	}
 	defer server.Close()
 	var buf [128]byte
-	mallocs := testing.AllocsPerRun(1000, func() {
+	allocs := testing.AllocsPerRun(1000, func() {
 		_, err := server.Write(buf[:])
 		if err != nil {
-			t.Fatalf("Write failed: %v", err)
+			t.Fatal(err)
 		}
 		_, err = io.ReadFull(client, buf[:])
 		if err != nil {
-			t.Fatalf("Read failed: %v", err)
+			t.Fatal(err)
 		}
 	})
-	if mallocs > 0 {
-		t.Fatalf("Got %v allocs, want 0", mallocs)
+	if allocs > 0 {
+		t.Fatalf("got %v; want 0", allocs)
 	}
 }
 
@@ -543,7 +518,7 @@ func TestTCPStress(t *testing.T) {
 	sendMsg := func(c Conn, buf []byte) bool {
 		n, err := c.Write(buf)
 		if n != len(buf) || err != nil {
-			t.Logf("Write failed: %v", err)
+			t.Log(err)
 			return false
 		}
 		return true
@@ -553,7 +528,7 @@ func TestTCPStress(t *testing.T) {
 			n, err := c.Read(buf)
 			read += n
 			if err != nil {
-				t.Logf("Read failed: %v", err)
+				t.Log(err)
 				return false
 			}
 		}
@@ -562,7 +537,7 @@ func TestTCPStress(t *testing.T) {
 
 	ln, err := Listen("tcp", "127.0.0.1:0")
 	if err != nil {
-		t.Fatalf("Listen failed: %v", err)
+		t.Fatal(err)
 	}
 	defer ln.Close()
 	// Acceptor.
@@ -593,7 +568,7 @@ func TestTCPStress(t *testing.T) {
 			}()
 			c, err := Dial("tcp", ln.Addr().String())
 			if err != nil {
-				t.Logf("Dial failed: %v", err)
+				t.Log(err)
 				return
 			}
 			defer c.Close()
diff --git a/src/net/tcpsock.go b/src/net/tcpsock.go
index f3dfbd2..8765aff 100644
--- a/src/net/tcpsock.go
+++ b/src/net/tcpsock.go
@@ -25,7 +25,14 @@ func (a *TCPAddr) String() string {
 	return JoinHostPort(ip, itoa(a.Port))
 }
 
-func (a *TCPAddr) toAddr() Addr {
+func (a *TCPAddr) isWildcard() bool {
+	if a == nil || a.IP == nil {
+		return true
+	}
+	return a.IP.IsUnspecified()
+}
+
+func (a *TCPAddr) opAddr() Addr {
 	if a == nil {
 		return nil
 	}
@@ -46,9 +53,9 @@ func ResolveTCPAddr(net, addr string) (*TCPAddr, error) {
 	default:
 		return nil, UnknownNetworkError(net)
 	}
-	a, err := resolveInternetAddr(net, addr, noDeadline)
+	addrs, err := internetAddrList(net, addr, noDeadline)
 	if err != nil {
 		return nil, err
 	}
-	return a.toAddr().(*TCPAddr), nil
+	return addrs.first(isIPv4).(*TCPAddr), nil
 }
diff --git a/src/net/tcpsock_plan9.go b/src/net/tcpsock_plan9.go
index 52019d7..9f23703 100644
--- a/src/net/tcpsock_plan9.go
+++ b/src/net/tcpsock_plan9.go
@@ -23,7 +23,11 @@ func newTCPConn(fd *netFD) *TCPConn {
 
 // ReadFrom implements the io.ReaderFrom ReadFrom method.
 func (c *TCPConn) ReadFrom(r io.Reader) (int64, error) {
-	return genericReadFrom(c, r)
+	n, err := genericReadFrom(c, r)
+	if err != nil && err != io.EOF {
+		err = &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return n, err
 }
 
 // CloseRead shuts down the reading side of the TCP connection.
@@ -32,7 +36,11 @@ func (c *TCPConn) CloseRead() error {
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	return c.fd.closeRead()
+	err := c.fd.closeRead()
+	if err != nil {
+		err = &OpError{Op: "close", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return err
 }
 
 // CloseWrite shuts down the writing side of the TCP connection.
@@ -41,7 +49,11 @@ func (c *TCPConn) CloseWrite() error {
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	return c.fd.closeWrite()
+	err := c.fd.closeWrite()
+	if err != nil {
+		err = &OpError{Op: "close", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return err
 }
 
 // SetLinger sets the behavior of Close on a connection which still
@@ -57,7 +69,7 @@ func (c *TCPConn) CloseWrite() error {
 // some operating systems after sec seconds have elapsed any remaining
 // unsent data may be discarded.
 func (c *TCPConn) SetLinger(sec int) error {
-	return syscall.EPLAN9
+	return &OpError{Op: "set", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
 }
 
 // SetKeepAlive sets whether the operating system should send
@@ -66,7 +78,10 @@ func (c *TCPConn) SetKeepAlive(keepalive bool) error {
 	if !c.ok() {
 		return syscall.EPLAN9
 	}
-	return setKeepAlive(c.fd, keepalive)
+	if err := setKeepAlive(c.fd, keepalive); err != nil {
+		return &OpError{Op: "set", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return nil
 }
 
 // SetKeepAlivePeriod sets period between keep alives.
@@ -74,7 +89,10 @@ func (c *TCPConn) SetKeepAlivePeriod(d time.Duration) error {
 	if !c.ok() {
 		return syscall.EPLAN9
 	}
-	return setKeepAlivePeriod(c.fd, d)
+	if err := setKeepAlivePeriod(c.fd, d); err != nil {
+		return &OpError{Op: "set", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return nil
 }
 
 // SetNoDelay controls whether the operating system should delay
@@ -82,7 +100,7 @@ func (c *TCPConn) SetKeepAlivePeriod(d time.Duration) error {
 // algorithm).  The default is true (no delay), meaning that data is
 // sent as soon as possible after a Write.
 func (c *TCPConn) SetNoDelay(noDelay bool) error {
-	return syscall.EPLAN9
+	return &OpError{Op: "set", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
 }
 
 // DialTCP connects to the remote address raddr on the network net,
@@ -99,10 +117,10 @@ func dialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time) (*TCPConn, e
 	switch net {
 	case "tcp", "tcp4", "tcp6":
 	default:
-		return nil, &OpError{"dial", net, raddr, UnknownNetworkError(net)}
+		return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(net)}
 	}
 	if raddr == nil {
-		return nil, &OpError{"dial", net, nil, errMissingAddress}
+		return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: nil, Err: errMissingAddress}
 	}
 	fd, err := dialPlan9(net, laddr, raddr)
 	if err != nil {
@@ -151,12 +169,18 @@ func (l *TCPListener) Close() error {
 	}
 	if _, err := l.fd.ctl.WriteString("hangup"); err != nil {
 		l.fd.ctl.Close()
-		return &OpError{"close", l.fd.ctl.Name(), l.fd.laddr, err}
+		return &OpError{Op: "close", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: err}
 	}
-	return l.fd.ctl.Close()
+	err := l.fd.ctl.Close()
+	if err != nil {
+		err = &OpError{Op: "close", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: err}
+	}
+	return err
 }
 
 // Addr returns the listener's network address, a *TCPAddr.
+// The Addr returned is shared by all invocations of Addr, so
+// do not modify it.
 func (l *TCPListener) Addr() Addr { return l.fd.laddr }
 
 // SetDeadline sets the deadline associated with the listener.
@@ -165,7 +189,10 @@ func (l *TCPListener) SetDeadline(t time.Time) error {
 	if l == nil || l.fd == nil || l.fd.ctl == nil {
 		return syscall.EINVAL
 	}
-	return l.fd.setDeadline(t)
+	if err := l.fd.setDeadline(t); err != nil {
+		return &OpError{Op: "set", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: err}
+	}
+	return nil
 }
 
 // File returns a copy of the underlying os.File, set to blocking
@@ -175,7 +202,13 @@ func (l *TCPListener) SetDeadline(t time.Time) error {
 // The returned os.File's file descriptor is different from the
 // connection's.  Attempting to change properties of the original
 // using this duplicate may or may not have the desired effect.
-func (l *TCPListener) File() (f *os.File, err error) { return l.dup() }
+func (l *TCPListener) File() (f *os.File, err error) {
+	f, err = l.dup()
+	if err != nil {
+		err = &OpError{Op: "file", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: err}
+	}
+	return
+}
 
 // ListenTCP announces on the TCP address laddr and returns a TCP
 // listener.  Net must be "tcp", "tcp4", or "tcp6".  If laddr has a
@@ -185,7 +218,7 @@ func ListenTCP(net string, laddr *TCPAddr) (*TCPListener, error) {
 	switch net {
 	case "tcp", "tcp4", "tcp6":
 	default:
-		return nil, &OpError{"listen", net, laddr, UnknownNetworkError(net)}
+		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(net)}
 	}
 	if laddr == nil {
 		laddr = &TCPAddr{}
diff --git a/src/net/tcpsock_posix.go b/src/net/tcpsock_posix.go
index dd78aef..7e49b76 100644
--- a/src/net/tcpsock_posix.go
+++ b/src/net/tcpsock_posix.go
@@ -13,11 +13,6 @@ import (
 	"time"
 )
 
-// BUG(rsc): On OpenBSD, listening on the "tcp" network does not listen for
-// both IPv4 and IPv6 connections. This is due to the fact that IPv4 traffic
-// will not be routed to an IPv6 socket - two separate sockets are required
-// if both AFs are to be supported. See inet6(4) on OpenBSD for details.
-
 func sockaddrToTCP(sa syscall.Sockaddr) Addr {
 	switch sa := sa.(type) {
 	case *syscall.SockaddrInet4:
@@ -38,13 +33,6 @@ func (a *TCPAddr) family() int {
 	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
@@ -60,16 +48,23 @@ type TCPConn struct {
 
 func newTCPConn(fd *netFD) *TCPConn {
 	c := &TCPConn{conn{fd}}
-	c.SetNoDelay(true)
+	setNoDelay(c.fd, true)
 	return c
 }
 
 // ReadFrom implements the io.ReaderFrom ReadFrom method.
 func (c *TCPConn) ReadFrom(r io.Reader) (int64, error) {
 	if n, err, handled := sendFile(c.fd, r); handled {
+		if err != nil && err != io.EOF {
+			err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+		}
 		return n, err
 	}
-	return genericReadFrom(c, r)
+	n, err := genericReadFrom(c, r)
+	if err != nil && err != io.EOF {
+		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return n, err
 }
 
 // CloseRead shuts down the reading side of the TCP connection.
@@ -78,7 +73,11 @@ func (c *TCPConn) CloseRead() error {
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	return c.fd.closeRead()
+	err := c.fd.closeRead()
+	if err != nil {
+		err = &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return err
 }
 
 // CloseWrite shuts down the writing side of the TCP connection.
@@ -87,7 +86,11 @@ func (c *TCPConn) CloseWrite() error {
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	return c.fd.closeWrite()
+	err := c.fd.closeWrite()
+	if err != nil {
+		err = &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return err
 }
 
 // SetLinger sets the behavior of Close on a connection which still
@@ -106,7 +109,10 @@ func (c *TCPConn) SetLinger(sec int) error {
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	return setLinger(c.fd, sec)
+	if err := setLinger(c.fd, sec); err != nil {
+		return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return nil
 }
 
 // SetKeepAlive sets whether the operating system should send
@@ -115,7 +121,10 @@ func (c *TCPConn) SetKeepAlive(keepalive bool) error {
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	return setKeepAlive(c.fd, keepalive)
+	if err := setKeepAlive(c.fd, keepalive); err != nil {
+		return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return nil
 }
 
 // SetKeepAlivePeriod sets period between keep alives.
@@ -123,7 +132,10 @@ func (c *TCPConn) SetKeepAlivePeriod(d time.Duration) error {
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	return setKeepAlivePeriod(c.fd, d)
+	if err := setKeepAlivePeriod(c.fd, d); err != nil {
+		return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return nil
 }
 
 // SetNoDelay controls whether the operating system should delay
@@ -134,7 +146,10 @@ func (c *TCPConn) SetNoDelay(noDelay bool) error {
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	return setNoDelay(c.fd, noDelay)
+	if err := setNoDelay(c.fd, noDelay); err != nil {
+		return &OpError{Op: "set", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return nil
 }
 
 // DialTCP connects to the remote address raddr on the network net,
@@ -144,10 +159,10 @@ func DialTCP(net string, laddr, raddr *TCPAddr) (*TCPConn, error) {
 	switch net {
 	case "tcp", "tcp4", "tcp6":
 	default:
-		return nil, &OpError{Op: "dial", Net: net, Addr: raddr, Err: UnknownNetworkError(net)}
+		return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(net)}
 	}
 	if raddr == nil {
-		return nil, &OpError{Op: "dial", Net: net, Addr: nil, Err: errMissingAddress}
+		return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: nil, Err: errMissingAddress}
 	}
 	return dialTCP(net, laddr, raddr, noDeadline)
 }
@@ -170,7 +185,7 @@ func dialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time) (*TCPConn, e
 	// see this happen, rather than expose the buggy effect to users, we
 	// close the fd and try again.  If it happens twice more, we relent and
 	// use the result.  See also:
-	//	http://golang.org/issue/2690
+	//	https://golang.org/issue/2690
 	//	http://stackoverflow.com/questions/4949858/
 	//
 	// The opposite can also happen: if we ask the kernel to pick an appropriate
@@ -187,7 +202,7 @@ func dialTCP(net string, laddr, raddr *TCPAddr, deadline time.Time) (*TCPConn, e
 	}
 
 	if err != nil {
-		return nil, &OpError{Op: "dial", Net: net, Addr: raddr, Err: err}
+		return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err}
 	}
 	return newTCPConn(fd), nil
 }
@@ -215,8 +230,13 @@ func selfConnect(fd *netFD, err error) bool {
 }
 
 func spuriousENOTAVAIL(err error) bool {
-	e, ok := err.(*OpError)
-	return ok && e.Err == syscall.EADDRNOTAVAIL
+	if op, ok := err.(*OpError); ok {
+		err = op.Err
+	}
+	if sys, ok := err.(*os.SyscallError); ok {
+		err = sys.Err
+	}
+	return err == syscall.EADDRNOTAVAIL
 }
 
 // TCPListener is a TCP network listener.  Clients should typically
@@ -233,7 +253,7 @@ func (l *TCPListener) AcceptTCP() (*TCPConn, error) {
 	}
 	fd, err := l.fd.accept()
 	if err != nil {
-		return nil, err
+		return nil, &OpError{Op: "accept", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
 	}
 	return newTCPConn(fd), nil
 }
@@ -254,10 +274,16 @@ func (l *TCPListener) Close() error {
 	if l == nil || l.fd == nil {
 		return syscall.EINVAL
 	}
-	return l.fd.Close()
+	err := l.fd.Close()
+	if err != nil {
+		err = &OpError{Op: "close", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
+	}
+	return err
 }
 
 // Addr returns the listener's network address, a *TCPAddr.
+// The Addr returned is shared by all invocations of Addr, so
+// do not modify it.
 func (l *TCPListener) Addr() Addr { return l.fd.laddr }
 
 // SetDeadline sets the deadline associated with the listener.
@@ -266,7 +292,10 @@ func (l *TCPListener) SetDeadline(t time.Time) error {
 	if l == nil || l.fd == nil {
 		return syscall.EINVAL
 	}
-	return l.fd.setDeadline(t)
+	if err := l.fd.setDeadline(t); err != nil {
+		return &OpError{Op: "set", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
+	}
+	return nil
 }
 
 // File returns a copy of the underlying os.File, set to blocking
@@ -276,7 +305,13 @@ func (l *TCPListener) SetDeadline(t time.Time) error {
 // The returned os.File's file descriptor is different from the
 // connection's.  Attempting to change properties of the original
 // using this duplicate may or may not have the desired effect.
-func (l *TCPListener) File() (f *os.File, err error) { return l.fd.dup() }
+func (l *TCPListener) File() (f *os.File, err error) {
+	f, err = l.fd.dup()
+	if err != nil {
+		err = &OpError{Op: "file", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
+	}
+	return
+}
 
 // ListenTCP announces on the TCP address laddr and returns a TCP
 // listener.  Net must be "tcp", "tcp4", or "tcp6".  If laddr has a
@@ -286,14 +321,14 @@ func ListenTCP(net string, laddr *TCPAddr) (*TCPListener, error) {
 	switch net {
 	case "tcp", "tcp4", "tcp6":
 	default:
-		return nil, &OpError{Op: "listen", Net: net, Addr: laddr, Err: UnknownNetworkError(net)}
+		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(net)}
 	}
 	if laddr == nil {
 		laddr = &TCPAddr{}
 	}
 	fd, err := internetSocket(net, laddr, nil, noDeadline, syscall.SOCK_STREAM, 0, "listen")
 	if err != nil {
-		return nil, &OpError{Op: "listen", Net: net, Addr: laddr, Err: err}
+		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err}
 	}
 	return &TCPListener{fd}, nil
 }
diff --git a/src/net/tcpsockopt_plan9.go b/src/net/tcpsockopt_plan9.go
index 0e7a664..9abe186 100644
--- a/src/net/tcpsockopt_plan9.go
+++ b/src/net/tcpsockopt_plan9.go
@@ -7,12 +7,13 @@
 package net
 
 import (
+	"strconv"
 	"time"
 )
 
 // Set keep alive period.
 func setKeepAlivePeriod(fd *netFD, d time.Duration) error {
-	cmd := "keepalive " + string(int64(d/time.Millisecond))
+	cmd := "keepalive " + strconv.Itoa(int(d/time.Millisecond))
 	_, e := fd.ctl.WriteAt([]byte(cmd), 0)
 	return e
 }
diff --git a/src/net/tcpsockopt_solaris.go b/src/net/tcpsockopt_solaris.go
new file mode 100644
index 0000000..31f5df0
--- /dev/null
+++ b/src/net/tcpsockopt_solaris.go
@@ -0,0 +1,35 @@
+// 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"
+	"syscall"
+	"time"
+)
+
+func setKeepAlivePeriod(fd *netFD, d time.Duration) error {
+	if err := fd.incref(); err != nil {
+		return err
+	}
+	defer fd.decref()
+	// The kernel expects milliseconds so round to next highest
+	// millisecond.
+	d += (time.Millisecond - time.Nanosecond)
+	msecs := int(d / time.Millisecond)
+
+	// Normally we'd do
+	//	syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_KEEPINTVL, secs)
+	// here, but we can't because Solaris does not have TCP_KEEPINTVL.
+	// Solaris has TCP_KEEPALIVE_ABORT_THRESHOLD, but it's not the same
+	// thing, it refers to the total time until aborting (not between
+	// probes), and it uses an exponential backoff algorithm instead of
+	// waiting the same time between probes. We can't hope for the best
+	// and do it anyway, like on Darwin, because Solaris might eventually
+	// allocate a constant with a different meaning for the value of
+	// TCP_KEEPINTVL on illumos.
+
+	return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(fd.sysfd, syscall.IPPROTO_TCP, syscall.TCP_KEEPALIVE_THRESHOLD, msecs))
+}
diff --git a/src/net/tcpsockopt_unix.go b/src/net/tcpsockopt_unix.go
index c9f604c..c8970d1 100644
--- a/src/net/tcpsockopt_unix.go
+++ b/src/net/tcpsockopt_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 freebsd linux netbsd solaris
+// +build freebsd linux netbsd
 
 package net
 
diff --git a/src/net/tcpsockopt_windows.go b/src/net/tcpsockopt_windows.go
index 091f523..ae2d7c8 100644
--- a/src/net/tcpsockopt_windows.go
+++ b/src/net/tcpsockopt_windows.go
@@ -28,5 +28,5 @@ func setKeepAlivePeriod(fd *netFD, d time.Duration) error {
 	ret := uint32(0)
 	size := uint32(unsafe.Sizeof(ka))
 	err := syscall.WSAIoctl(fd.sysfd, syscall.SIO_KEEPALIVE_VALS, (*byte)(unsafe.Pointer(&ka)), size, nil, 0, &ret, nil, 0)
-	return os.NewSyscallError("WSAIoctl", err)
+	return os.NewSyscallError("wsaioctl", err)
 }
diff --git a/src/net/testdata/ipv4-hosts b/src/net/testdata/ipv4-hosts
new file mode 100644
index 0000000..5208bb4
--- /dev/null
+++ b/src/net/testdata/ipv4-hosts
@@ -0,0 +1,12 @@
+# See https://tools.ietf.org/html/rfc1123.
+#
+# The literal IPv4 address parser in the net package is a relaxed
+# one. It may accept a literal IPv4 address in dotted-decimal notation
+# with leading zeros such as "001.2.003.4".
+
+# internet address and host name
+127.0.0.1	localhost	# inline comment separated by tab
+127.000.000.002	localhost       # inline comment separated by space
+
+# internet address, host name and aliases
+127.000.000.003	localhost	localhost.localdomain
diff --git a/src/net/testdata/ipv6-hosts b/src/net/testdata/ipv6-hosts
new file mode 100644
index 0000000..f78b7fc
--- /dev/null
+++ b/src/net/testdata/ipv6-hosts
@@ -0,0 +1,11 @@
+# See https://tools.ietf.org/html/rfc5952, https://tools.ietf.org/html/rfc4007.
+
+# internet address and host name
+::1						localhost	# inline comment separated by tab
+fe80:0000:0000:0000:0000:0000:0000:0001		localhost       # inline comment separated by space
+
+# internet address with zone identifier and host name
+fe80:0000:0000:0000:0000:0000:0000:0002%lo0	localhost
+
+# internet address, host name and aliases
+fe80::3%lo0					localhost	localhost.localdomain
diff --git a/src/net/testdata/openbsd-resolv.conf b/src/net/testdata/openbsd-resolv.conf
new file mode 100644
index 0000000..8281a91
--- /dev/null
+++ b/src/net/testdata/openbsd-resolv.conf
@@ -0,0 +1,5 @@
+# Generated by vio0 dhclient
+search c.symbolic-datum-552.internal.
+nameserver 169.254.169.254
+nameserver 10.240.0.1
+lookup file bind
diff --git a/src/net/testdata/hosts_singleline b/src/net/testdata/singleline-hosts
similarity index 100%
rename from src/net/testdata/hosts_singleline
rename to src/net/testdata/singleline-hosts
diff --git a/src/net/textproto/reader.go b/src/net/textproto/reader.go
index e10efcd..91303fe 100644
--- a/src/net/textproto/reader.go
+++ b/src/net/textproto/reader.go
@@ -13,10 +13,6 @@ import (
 	"strings"
 )
 
-// BUG(rsc): To let callers manage exposure to denial of service
-// attacks, Reader should allow them to set and reset a limit on
-// the number of bytes read from the connection.
-
 // A Reader implements convenience methods for reading requests
 // or responses from a text protocol network connection.
 type Reader struct {
@@ -26,6 +22,10 @@ type Reader struct {
 }
 
 // NewReader returns a new Reader reading from r.
+//
+// To avoid denial of service attacks, the provided bufio.Reader
+// should be reading from an io.LimitReader or similar Reader to bound
+// the size of responses.
 func NewReader(r *bufio.Reader) *Reader {
 	return &Reader{R: r}
 }
@@ -485,6 +485,13 @@ func (r *Reader) ReadMIMEHeader() (MIMEHeader, error) {
 		}
 		key := canonicalMIMEHeaderKey(kv[:endKey])
 
+		// As per RFC 7230 field-name is a token, tokens consist of one or more chars.
+		// We could return a ProtocolError here, but better to be liberal in what we
+		// accept, so if we get an empty key, skip it.
+		if key == "" {
+			continue
+		}
+
 		// Skip initial spaces in value.
 		i++ // skip colon
 		for i < len(kv) && (kv[i] == ' ' || kv[i] == '\t') {
diff --git a/src/net/textproto/reader_test.go b/src/net/textproto/reader_test.go
index 706ab6e..8fce7dd 100644
--- a/src/net/textproto/reader_test.go
+++ b/src/net/textproto/reader_test.go
@@ -156,6 +156,15 @@ func TestReadMIMEHeaderSingle(t *testing.T) {
 	}
 }
 
+func TestReadMIMEHeaderNoKey(t *testing.T) {
+	r := reader(": bar\ntest-1: 1\n\n")
+	m, err := r.ReadMIMEHeader()
+	want := MIMEHeader{"Test-1": {"1"}}
+	if !reflect.DeepEqual(m, want) || err != nil {
+		t.Fatalf("ReadMIMEHeader: %v, %v; want %v", m, err, want)
+	}
+}
+
 func TestLargeReadMIMEHeader(t *testing.T) {
 	data := make([]byte, 16*1024)
 	for i := 0; i < len(data); i++ {
diff --git a/src/net/timeout_test.go b/src/net/timeout_test.go
index 9ef0c4d..ca94e24 100644
--- a/src/net/timeout_test.go
+++ b/src/net/timeout_test.go
@@ -8,408 +8,727 @@ import (
 	"fmt"
 	"io"
 	"io/ioutil"
+	"net/internal/socktest"
 	"runtime"
+	"sync"
 	"testing"
 	"time"
 )
 
-func isTimeout(err error) bool {
-	e, ok := err.(Error)
-	return ok && e.Timeout()
+var dialTimeoutTests = []struct {
+	timeout time.Duration
+	delta   time.Duration // for deadline
+
+	guard time.Duration
+	max   time.Duration
+}{
+	// Tests that dial timeouts, deadlines in the past work.
+	{-5 * time.Second, 0, -5 * time.Second, 100 * time.Millisecond},
+	{0, -5 * time.Second, -5 * time.Second, 100 * time.Millisecond},
+	{-5 * time.Second, 5 * time.Second, -5 * time.Second, 100 * time.Millisecond}, // timeout over deadline
+
+	{50 * time.Millisecond, 0, 100 * time.Millisecond, time.Second},
+	{0, 50 * time.Millisecond, 100 * time.Millisecond, time.Second},
+	{50 * time.Millisecond, 5 * time.Second, 100 * time.Millisecond, time.Second}, // timeout over deadline
 }
 
-type copyRes struct {
-	n   int64
-	err error
-	d   time.Duration
+func TestDialTimeout(t *testing.T) {
+	origTestHookDialChannel := testHookDialChannel
+	defer func() { testHookDialChannel = origTestHookDialChannel }()
+	defer sw.Set(socktest.FilterConnect, nil)
+
+	// Avoid tracking open-close jitterbugs between netFD and
+	// socket that leads to confusion of information inside
+	// socktest.Switch.
+	// It may happen when the Dial call bumps against TCP
+	// simultaneous open. See selfConnect in tcpsock_posix.go.
+	defer func() {
+		sw.Set(socktest.FilterClose, nil)
+		forceCloseSockets()
+	}()
+	sw.Set(socktest.FilterClose, func(so *socktest.Status) (socktest.AfterFilter, error) {
+		return nil, errTimedout
+	})
+
+	for i, tt := range dialTimeoutTests {
+		switch runtime.GOOS {
+		case "plan9", "windows":
+			testHookDialChannel = func() { time.Sleep(tt.guard) }
+			if runtime.GOOS == "plan9" {
+				break
+			}
+			fallthrough
+		default:
+			sw.Set(socktest.FilterConnect, func(so *socktest.Status) (socktest.AfterFilter, error) {
+				time.Sleep(tt.guard)
+				return nil, errTimedout
+			})
+		}
+
+		ch := make(chan error)
+		d := Dialer{Timeout: tt.timeout}
+		if tt.delta != 0 {
+			d.Deadline = time.Now().Add(tt.delta)
+		}
+		max := time.NewTimer(tt.max)
+		defer max.Stop()
+		go func() {
+			// This dial never starts to send any TCP SYN
+			// segment because of above socket filter and
+			// test hook.
+			c, err := d.Dial("tcp", "127.0.0.1:0")
+			if err == nil {
+				err = fmt.Errorf("unexpectedly established: tcp:%s->%s", c.LocalAddr(), c.RemoteAddr())
+				c.Close()
+			}
+			ch <- err
+		}()
+
+		select {
+		case <-max.C:
+			t.Fatalf("#%d: Dial didn't return in an expected time", i)
+		case err := <-ch:
+			if perr := parseDialError(err); perr != nil {
+				t.Errorf("#%d: %v", i, perr)
+			}
+			if nerr, ok := err.(Error); !ok || !nerr.Timeout() {
+				t.Fatalf("#%d: %v", i, err)
+			}
+		}
+	}
+}
+
+var acceptTimeoutTests = []struct {
+	timeout time.Duration
+	xerrs   [2]error // expected errors in transition
+}{
+	// Tests that accept deadlines in the past work, even if
+	// there's incoming connections available.
+	{-5 * time.Second, [2]error{errTimeout, errTimeout}},
+
+	{50 * time.Millisecond, [2]error{nil, errTimeout}},
 }
 
 func TestAcceptTimeout(t *testing.T) {
 	switch runtime.GOOS {
 	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
+		t.Skipf("not supported on %s", runtime.GOOS)
 	}
 
-	ln := newLocalListener(t).(*TCPListener)
-	defer ln.Close()
-	ln.SetDeadline(time.Now().Add(-1 * time.Second))
-	if _, err := ln.Accept(); !isTimeout(err) {
-		t.Fatalf("Accept: expected err %v, got %v", errTimeout, err)
+	ln, err := newLocalListener("tcp")
+	if err != nil {
+		t.Fatal(err)
 	}
-	if _, err := ln.Accept(); !isTimeout(err) {
-		t.Fatalf("Accept: expected err %v, got %v", errTimeout, err)
+	defer ln.Close()
+
+	for i, tt := range acceptTimeoutTests {
+		if tt.timeout < 0 {
+			go func() {
+				c, err := Dial(ln.Addr().Network(), ln.Addr().String())
+				if err != nil {
+					t.Error(err)
+					return
+				}
+				var b [1]byte
+				c.Read(b[:])
+				c.Close()
+			}()
+		}
+
+		if err := ln.(*TCPListener).SetDeadline(time.Now().Add(tt.timeout)); err != nil {
+			t.Fatalf("$%d: %v", i, err)
+		}
+		for j, xerr := range tt.xerrs {
+			for {
+				c, err := ln.Accept()
+				if xerr != nil {
+					if perr := parseAcceptError(err); perr != nil {
+						t.Errorf("#%d/%d: %v", i, j, perr)
+					}
+					if nerr, ok := err.(Error); !ok || !nerr.Timeout() {
+						t.Fatalf("#%d/%d: %v", i, j, err)
+					}
+				}
+				if err == nil {
+					c.Close()
+					time.Sleep(tt.timeout / 3)
+					continue
+				}
+				break
+			}
+		}
 	}
-	ln.SetDeadline(time.Now().Add(100 * time.Millisecond))
-	if _, err := ln.Accept(); !isTimeout(err) {
-		t.Fatalf("Accept: expected err %v, got %v", errTimeout, err)
+}
+
+func TestAcceptTimeoutMustReturn(t *testing.T) {
+	switch runtime.GOOS {
+	case "plan9":
+		t.Skipf("not supported on %s", runtime.GOOS)
 	}
-	if _, err := ln.Accept(); !isTimeout(err) {
-		t.Fatalf("Accept: expected err %v, got %v", errTimeout, err)
+
+	ln, err := newLocalListener("tcp")
+	if err != nil {
+		t.Fatal(err)
 	}
-	ln.SetDeadline(noDeadline)
-	errc := make(chan error)
+	defer ln.Close()
+
+	max := time.NewTimer(time.Second)
+	defer max.Stop()
+	ch := make(chan error)
 	go func() {
-		_, err := ln.Accept()
-		errc <- err
+		if err := ln.(*TCPListener).SetDeadline(noDeadline); err != nil {
+			t.Error(err)
+		}
+		if err := ln.(*TCPListener).SetDeadline(time.Now().Add(10 * time.Millisecond)); err != nil {
+			t.Error(err)
+		}
+		c, err := ln.Accept()
+		if err == nil {
+			c.Close()
+		}
+		ch <- err
 	}()
-	time.Sleep(100 * time.Millisecond)
+
 	select {
-	case err := <-errc:
-		t.Fatalf("Expected Accept() to not return, but it returned with %v\n", err)
-	default:
-	}
-	ln.Close()
-	switch nerr := <-errc; err := nerr.(type) {
-	case *OpError:
-		if err.Err != errClosing {
-			t.Fatalf("Accept: expected err %v, got %v", errClosing, err)
+	case <-max.C:
+		ln.Close()
+		<-ch // wait for tester goroutine to stop
+		t.Fatal("Accept didn't return in an expected time")
+	case err := <-ch:
+		if perr := parseAcceptError(err); perr != nil {
+			t.Error(perr)
 		}
-	default:
-		if err != errClosing {
-			t.Fatalf("Accept: expected err %v, got %v", errClosing, err)
+		if nerr, ok := err.(Error); !ok || !nerr.Timeout() {
+			t.Fatal(err)
 		}
 	}
 }
 
-func TestReadTimeout(t *testing.T) {
+func TestAcceptTimeoutMustNotReturn(t *testing.T) {
 	switch runtime.GOOS {
 	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
+		t.Skipf("not supported on %s", runtime.GOOS)
 	}
 
-	ln := newLocalListener(t)
-	defer ln.Close()
-	c, err := DialTCP("tcp", nil, ln.Addr().(*TCPAddr))
+	ln, err := newLocalListener("tcp")
 	if err != nil {
-		t.Fatalf("Connect: %v", err)
-	}
-	defer c.Close()
-	c.SetDeadline(time.Now().Add(time.Hour))
-	c.SetReadDeadline(time.Now().Add(-1 * time.Second))
-	buf := make([]byte, 1)
-	if _, err = c.Read(buf); !isTimeout(err) {
-		t.Fatalf("Read: expected err %v, got %v", errTimeout, err)
-	}
-	if _, err = c.Read(buf); !isTimeout(err) {
-		t.Fatalf("Read: expected err %v, got %v", errTimeout, err)
-	}
-	c.SetDeadline(time.Now().Add(100 * time.Millisecond))
-	if _, err = c.Read(buf); !isTimeout(err) {
-		t.Fatalf("Read: expected err %v, got %v", errTimeout, err)
-	}
-	if _, err = c.Read(buf); !isTimeout(err) {
-		t.Fatalf("Read: expected err %v, got %v", errTimeout, err)
+		t.Fatal(err)
 	}
-	c.SetReadDeadline(noDeadline)
-	c.SetWriteDeadline(time.Now().Add(-1 * time.Second))
-	errc := make(chan error)
+	defer ln.Close()
+
+	max := time.NewTimer(100 * time.Millisecond)
+	defer max.Stop()
+	ch := make(chan error)
 	go func() {
-		_, err := c.Read(buf)
-		errc <- err
-	}()
-	time.Sleep(100 * time.Millisecond)
-	select {
-	case err := <-errc:
-		t.Fatalf("Expected Read() to not return, but it returned with %v\n", err)
-	default:
-	}
-	c.Close()
-	switch nerr := <-errc; err := nerr.(type) {
-	case *OpError:
-		if err.Err != errClosing {
-			t.Fatalf("Read: expected err %v, got %v", errClosing, err)
+		if err := ln.(*TCPListener).SetDeadline(time.Now().Add(-5 * time.Second)); err != nil {
+			t.Error(err)
 		}
-	default:
-		if err == io.EOF && runtime.GOOS == "nacl" { // close enough; golang.org/issue/8044
-			break
+		if err := ln.(*TCPListener).SetDeadline(noDeadline); err != nil {
+			t.Error(err)
 		}
-		if err != errClosing {
-			t.Fatalf("Read: expected err %v, got %v", errClosing, err)
+		_, err := ln.Accept()
+		ch <- err
+	}()
+
+	select {
+	case err := <-ch:
+		if perr := parseAcceptError(err); perr != nil {
+			t.Error(perr)
 		}
+		t.Fatalf("expected Accept to not return, but it returned with %v", err)
+	case <-max.C:
+		ln.Close()
+		<-ch // wait for tester goroutine to stop
 	}
 }
 
-func TestWriteTimeout(t *testing.T) {
+var readTimeoutTests = []struct {
+	timeout time.Duration
+	xerrs   [2]error // expected errors in transition
+}{
+	// Tests that read deadlines work, even if there's data ready
+	// to be read.
+	{-5 * time.Second, [2]error{errTimeout, errTimeout}},
+
+	{50 * time.Millisecond, [2]error{nil, errTimeout}},
+}
+
+func TestReadTimeout(t *testing.T) {
 	switch runtime.GOOS {
 	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
+		t.Skipf("not supported on %s", runtime.GOOS)
 	}
 
-	ln := newLocalListener(t)
-	defer ln.Close()
-	c, err := DialTCP("tcp", nil, ln.Addr().(*TCPAddr))
+	handler := func(ls *localServer, ln Listener) {
+		c, err := ln.Accept()
+		if err != nil {
+			t.Error(err)
+			return
+		}
+		c.Write([]byte("READ TIMEOUT TEST"))
+		defer c.Close()
+	}
+	ls, err := newLocalServer("tcp")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer ls.teardown()
+	if err := ls.buildup(handler); err != nil {
+		t.Fatal(err)
+	}
+
+	c, err := Dial(ls.Listener.Addr().Network(), ls.Listener.Addr().String())
 	if err != nil {
-		t.Fatalf("Connect: %v", err)
+		t.Fatal(err)
 	}
 	defer c.Close()
-	c.SetDeadline(time.Now().Add(time.Hour))
-	c.SetWriteDeadline(time.Now().Add(-1 * time.Second))
-	buf := make([]byte, 4096)
-	writeUntilTimeout := func() {
-		for {
-			_, err := c.Write(buf)
-			if err != nil {
-				if isTimeout(err) {
-					return
+
+	for i, tt := range readTimeoutTests {
+		if err := c.SetReadDeadline(time.Now().Add(tt.timeout)); err != nil {
+			t.Fatalf("#%d: %v", i, err)
+		}
+		var b [1]byte
+		for j, xerr := range tt.xerrs {
+			for {
+				n, err := c.Read(b[:])
+				if xerr != nil {
+					if perr := parseReadError(err); perr != nil {
+						t.Errorf("#%d/%d: %v", i, j, perr)
+					}
+					if nerr, ok := err.(Error); !ok || !nerr.Timeout() {
+						t.Fatalf("#%d/%d: %v", i, j, err)
+					}
+				}
+				if err == nil {
+					time.Sleep(tt.timeout / 3)
+					continue
+				}
+				if n != 0 {
+					t.Fatalf("#%d/%d: read %d; want 0", i, j, n)
 				}
-				t.Fatalf("Write: expected err %v, got %v", errTimeout, err)
+				break
 			}
 		}
 	}
-	writeUntilTimeout()
-	c.SetDeadline(time.Now().Add(10 * time.Millisecond))
-	writeUntilTimeout()
-	writeUntilTimeout()
-	c.SetWriteDeadline(noDeadline)
-	c.SetReadDeadline(time.Now().Add(-1 * time.Second))
-	errc := make(chan error)
-	go func() {
-		for {
-			_, err := c.Write(buf)
-			if err != nil {
-				errc <- err
-			}
-		}
-	}()
-	time.Sleep(100 * time.Millisecond)
-	select {
-	case err := <-errc:
-		t.Fatalf("Expected Write() to not return, but it returned with %v\n", err)
-	default:
+}
+
+func TestReadTimeoutMustNotReturn(t *testing.T) {
+	switch runtime.GOOS {
+	case "plan9":
+		t.Skipf("not supported on %s", runtime.GOOS)
 	}
-	c.Close()
-	switch nerr := <-errc; err := nerr.(type) {
-	case *OpError:
-		if err.Err != errClosing {
-			t.Fatalf("Write: expected err %v, got %v", errClosing, err)
-		}
-	default:
-		if err != errClosing {
-			t.Fatalf("Write: expected err %v, got %v", errClosing, err)
-		}
+
+	ln, err := newLocalListener("tcp")
+	if err != nil {
+		t.Fatal(err)
 	}
-}
+	defer ln.Close()
 
-func testTimeout(t *testing.T, net, addr string, readFrom bool) {
-	c, err := Dial(net, addr)
+	c, err := Dial(ln.Addr().Network(), ln.Addr().String())
 	if err != nil {
-		t.Errorf("Dial(%q, %q) failed: %v", net, addr, err)
-		return
+		t.Fatal(err)
 	}
 	defer c.Close()
-	what := "Read"
-	if readFrom {
-		what = "ReadFrom"
-	}
 
-	errc := make(chan error, 1)
+	max := time.NewTimer(100 * time.Millisecond)
+	defer max.Stop()
+	ch := make(chan error)
 	go func() {
-		t0 := time.Now()
-		c.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
-		var b [100]byte
-		var n int
-		var err error
-		if readFrom {
-			n, _, err = c.(PacketConn).ReadFrom(b[0:])
-		} else {
-			n, err = c.Read(b[0:])
-		}
-		t1 := time.Now()
-		if n != 0 || err == nil || !err.(Error).Timeout() {
-			errc <- fmt.Errorf("%s(%q, %q) did not return 0, timeout: %v, %v", what, net, addr, n, err)
-			return
+		if err := c.SetDeadline(time.Now().Add(-5 * time.Second)); err != nil {
+			t.Error(err)
 		}
-		if dt := t1.Sub(t0); dt < 50*time.Millisecond || !testing.Short() && dt > 250*time.Millisecond {
-			errc <- fmt.Errorf("%s(%q, %q) took %s, expected 0.1s", what, net, addr, dt)
-			return
+		if err := c.SetWriteDeadline(time.Now().Add(-5 * time.Second)); err != nil {
+			t.Error(err)
+		}
+		if err := c.SetReadDeadline(noDeadline); err != nil {
+			t.Error(err)
 		}
-		errc <- nil
+		var b [1]byte
+		_, err := c.Read(b[:])
+		ch <- err
 	}()
+
 	select {
-	case err := <-errc:
-		if err != nil {
-			t.Error(err)
+	case err := <-ch:
+		if perr := parseReadError(err); perr != nil {
+			t.Error(perr)
+		}
+		t.Fatalf("expected Read to not return, but it returned with %v", err)
+	case <-max.C:
+		c.Close()
+		err := <-ch // wait for tester goroutine to stop
+		if perr := parseReadError(err); perr != nil {
+			t.Error(perr)
+		}
+		if err == io.EOF && runtime.GOOS == "nacl" { // see golang.org/issue/8044
+			return
+		}
+		if nerr, ok := err.(Error); !ok || nerr.Timeout() || nerr.Temporary() {
+			t.Fatal(err)
 		}
-	case <-time.After(1 * time.Second):
-		t.Errorf("%s(%q, %q) took over 1 second, expected 0.1s", what, net, addr)
 	}
 }
 
-func TestTimeoutUDP(t *testing.T) {
+var readFromTimeoutTests = []struct {
+	timeout time.Duration
+	xerrs   [2]error // expected errors in transition
+}{
+	// Tests that read deadlines work, even if there's data ready
+	// to be read.
+	{-5 * time.Second, [2]error{errTimeout, errTimeout}},
+
+	{50 * time.Millisecond, [2]error{nil, errTimeout}},
+}
+
+func TestReadFromTimeout(t *testing.T) {
 	switch runtime.GOOS {
-	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
+	case "nacl", "plan9":
+		t.Skipf("not supported on %s", runtime.GOOS) // see golang.org/issue/8916
 	}
 
-	// set up a listener that won't talk back
-	listening := make(chan string)
-	done := make(chan int)
-	go runDatagramPacketConnServer(t, "udp", "127.0.0.1:0", listening, done)
-	addr := <-listening
+	ch := make(chan Addr)
+	defer close(ch)
+	handler := func(ls *localPacketServer, c PacketConn) {
+		if dst, ok := <-ch; ok {
+			c.WriteTo([]byte("READFROM TIMEOUT TEST"), dst)
+		}
+	}
+	ls, err := newLocalPacketServer("udp")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer ls.teardown()
+	if err := ls.buildup(handler); err != nil {
+		t.Fatal(err)
+	}
 
-	testTimeout(t, "udp", addr, false)
-	testTimeout(t, "udp", addr, true)
-	<-done
-}
+	host, _, err := SplitHostPort(ls.PacketConn.LocalAddr().String())
+	if err != nil {
+		t.Fatal(err)
+	}
+	c, err := ListenPacket(ls.PacketConn.LocalAddr().Network(), JoinHostPort(host, "0"))
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer c.Close()
+	ch <- c.LocalAddr()
 
-func TestTimeoutTCP(t *testing.T) {
-	switch runtime.GOOS {
-	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
+	for i, tt := range readFromTimeoutTests {
+		if err := c.SetReadDeadline(time.Now().Add(tt.timeout)); err != nil {
+			t.Fatalf("#%d: %v", i, err)
+		}
+		var b [1]byte
+		for j, xerr := range tt.xerrs {
+			for {
+				n, _, err := c.ReadFrom(b[:])
+				if xerr != nil {
+					if perr := parseReadError(err); perr != nil {
+						t.Errorf("#%d/%d: %v", i, j, perr)
+					}
+					if nerr, ok := err.(Error); !ok || !nerr.Timeout() {
+						t.Fatalf("#%d/%d: %v", i, j, err)
+					}
+				}
+				if err == nil {
+					time.Sleep(tt.timeout / 3)
+					continue
+				}
+				if n != 0 {
+					t.Fatalf("#%d/%d: read %d; want 0", i, j, n)
+				}
+				break
+			}
+		}
 	}
+}
 
-	// set up a listener that won't talk back
-	listening := make(chan string)
-	done := make(chan int)
-	go runStreamConnServer(t, "tcp", "127.0.0.1:0", listening, done)
-	addr := <-listening
+var writeTimeoutTests = []struct {
+	timeout time.Duration
+	xerrs   [2]error // expected errors in transition
+}{
+	// Tests that write deadlines work, even if there's buffer
+	// space available to write.
+	{-5 * time.Second, [2]error{errTimeout, errTimeout}},
 
-	testTimeout(t, "tcp", addr, false)
-	<-done
+	{10 * time.Millisecond, [2]error{nil, errTimeout}},
 }
 
-func TestDeadlineReset(t *testing.T) {
+func TestWriteTimeout(t *testing.T) {
 	switch runtime.GOOS {
 	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
+		t.Skipf("not supported on %s", runtime.GOOS)
 	}
-	ln, err := Listen("tcp", "127.0.0.1:0")
+
+	ln, err := newLocalListener("tcp")
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer ln.Close()
-	tl := ln.(*TCPListener)
-	tl.SetDeadline(time.Now().Add(1 * time.Minute))
-	tl.SetDeadline(noDeadline) // reset it
-	errc := make(chan error, 1)
-	go func() {
-		_, err := ln.Accept()
-		errc <- err
-	}()
-	select {
-	case <-time.After(50 * time.Millisecond):
-		// Pass.
-	case err := <-errc:
-		// Accept should never return; we never
-		// connected to it.
-		t.Errorf("unexpected return from Accept; err=%v", err)
+
+	for i, tt := range writeTimeoutTests {
+		c, err := Dial(ln.Addr().Network(), ln.Addr().String())
+		if err != nil {
+			t.Fatal(err)
+		}
+		defer c.Close()
+
+		if err := c.SetWriteDeadline(time.Now().Add(tt.timeout)); err != nil {
+			t.Fatalf("#%d: %v", i, err)
+		}
+		for j, xerr := range tt.xerrs {
+			for {
+				n, err := c.Write([]byte("WRITE TIMEOUT TEST"))
+				if xerr != nil {
+					if perr := parseWriteError(err); perr != nil {
+						t.Errorf("#%d/%d: %v", i, j, perr)
+					}
+					if nerr, ok := err.(Error); !ok || !nerr.Timeout() {
+						t.Fatalf("#%d/%d: %v", i, j, err)
+					}
+				}
+				if err == nil {
+					time.Sleep(tt.timeout / 3)
+					continue
+				}
+				if n != 0 {
+					t.Fatalf("#%d/%d: wrote %d; want 0", i, j, n)
+				}
+				break
+			}
+		}
 	}
 }
 
-func TestTimeoutAccept(t *testing.T) {
+func TestWriteTimeoutMustNotReturn(t *testing.T) {
 	switch runtime.GOOS {
 	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
+		t.Skipf("not supported on %s", runtime.GOOS)
 	}
-	ln, err := Listen("tcp", "127.0.0.1:0")
+
+	ln, err := newLocalListener("tcp")
 	if err != nil {
 		t.Fatal(err)
 	}
 	defer ln.Close()
-	tl := ln.(*TCPListener)
-	tl.SetDeadline(time.Now().Add(100 * time.Millisecond))
-	errc := make(chan error, 1)
+
+	c, err := Dial(ln.Addr().Network(), ln.Addr().String())
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer c.Close()
+
+	max := time.NewTimer(100 * time.Millisecond)
+	defer max.Stop()
+	ch := make(chan error)
 	go func() {
-		_, err := ln.Accept()
-		errc <- err
+		if err := c.SetDeadline(time.Now().Add(-5 * time.Second)); err != nil {
+			t.Error(err)
+		}
+		if err := c.SetReadDeadline(time.Now().Add(-5 * time.Second)); err != nil {
+			t.Error(err)
+		}
+		if err := c.SetWriteDeadline(noDeadline); err != nil {
+			t.Error(err)
+		}
+		var b [1]byte
+		for {
+			if _, err := c.Write(b[:]); err != nil {
+				ch <- err
+				break
+			}
+		}
 	}()
+
 	select {
-	case <-time.After(1 * time.Second):
-		// Accept shouldn't block indefinitely
-		t.Errorf("Accept didn't return in an expected time")
-	case <-errc:
-		// Pass.
+	case err := <-ch:
+		if perr := parseWriteError(err); perr != nil {
+			t.Error(perr)
+		}
+		t.Fatalf("expected Write to not return, but it returned with %v", err)
+	case <-max.C:
+		c.Close()
+		err := <-ch // wait for tester goroutine to stop
+		if perr := parseWriteError(err); perr != nil {
+			t.Error(perr)
+		}
+		if nerr, ok := err.(Error); !ok || nerr.Timeout() || nerr.Temporary() {
+			t.Fatal(err)
+		}
 	}
 }
 
-func TestReadWriteDeadline(t *testing.T) {
+var writeToTimeoutTests = []struct {
+	timeout time.Duration
+	xerrs   [2]error // expected errors in transition
+}{
+	// Tests that write deadlines work, even if there's buffer
+	// space available to write.
+	{-5 * time.Second, [2]error{errTimeout, errTimeout}},
+
+	{10 * time.Millisecond, [2]error{nil, errTimeout}},
+}
+
+func TestWriteToTimeout(t *testing.T) {
 	switch runtime.GOOS {
-	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
+	case "nacl", "plan9":
+		t.Skipf("not supported on %s", runtime.GOOS)
 	}
 
-	const (
-		readTimeout  = 50 * time.Millisecond
-		writeTimeout = 250 * time.Millisecond
-	)
-	checkTimeout := func(command string, start time.Time, should time.Duration) {
-		is := time.Now().Sub(start)
-		d := is - should
-		if d < -30*time.Millisecond || !testing.Short() && 150*time.Millisecond < d {
-			t.Errorf("%s timeout test failed: is=%v should=%v\n", command, is, should)
-		}
+	c1, err := newLocalPacketListener("udp")
+	if err != nil {
+		t.Fatal(err)
 	}
+	defer c1.Close()
 
-	ln, err := Listen("tcp", "127.0.0.1:0")
+	host, _, err := SplitHostPort(c1.LocalAddr().String())
 	if err != nil {
-		t.Fatalf("ListenTCP on :0: %v", err)
+		t.Fatal(err)
 	}
-	defer ln.Close()
 
-	lnquit := make(chan bool)
-
-	go func() {
-		c, err := ln.Accept()
+	for i, tt := range writeToTimeoutTests {
+		c2, err := ListenPacket(c1.LocalAddr().Network(), JoinHostPort(host, "0"))
 		if err != nil {
-			t.Errorf("Accept: %v", err)
-			return
+			t.Fatal(err)
 		}
-		defer c.Close()
-		lnquit <- true
-	}()
+		defer c2.Close()
+
+		if err := c2.SetWriteDeadline(time.Now().Add(tt.timeout)); err != nil {
+			t.Fatalf("#%d: %v", i, err)
+		}
+		for j, xerr := range tt.xerrs {
+			for {
+				n, err := c2.WriteTo([]byte("WRITETO TIMEOUT TEST"), c1.LocalAddr())
+				if xerr != nil {
+					if perr := parseWriteError(err); perr != nil {
+						t.Errorf("#%d/%d: %v", i, j, perr)
+					}
+					if nerr, ok := err.(Error); !ok || !nerr.Timeout() {
+						t.Fatalf("#%d/%d: %v", i, j, err)
+					}
+				}
+				if err == nil {
+					time.Sleep(tt.timeout / 3)
+					continue
+				}
+				if n != 0 {
+					t.Fatalf("#%d/%d: wrote %d; want 0", i, j, n)
+				}
+				break
+			}
+		}
+	}
+}
+
+func TestReadTimeoutFluctuation(t *testing.T) {
+	switch runtime.GOOS {
+	case "plan9":
+		t.Skipf("not supported on %s", runtime.GOOS)
+	}
 
-	c, err := Dial("tcp", ln.Addr().String())
+	ln, err := newLocalListener("tcp")
 	if err != nil {
-		t.Fatalf("Dial: %v", err)
+		t.Fatal(err)
+	}
+	defer ln.Close()
+
+	c, err := Dial(ln.Addr().Network(), ln.Addr().String())
+	if err != nil {
+		t.Fatal(err)
 	}
 	defer c.Close()
 
-	start := time.Now()
-	err = c.SetReadDeadline(start.Add(readTimeout))
+	max := time.NewTimer(time.Second)
+	defer max.Stop()
+	ch := make(chan error)
+	go timeoutReceiver(c, 100*time.Millisecond, 50*time.Millisecond, 250*time.Millisecond, ch)
+
+	select {
+	case <-max.C:
+		t.Fatal("Read took over 1s; expected 0.1s")
+	case err := <-ch:
+		if perr := parseReadError(err); perr != nil {
+			t.Error(perr)
+		}
+		if nerr, ok := err.(Error); !ok || !nerr.Timeout() {
+			t.Fatal(err)
+		}
+	}
+}
+
+func TestReadFromTimeoutFluctuation(t *testing.T) {
+	switch runtime.GOOS {
+	case "plan9":
+		t.Skipf("not supported on %s", runtime.GOOS)
+	}
+
+	c1, err := newLocalPacketListener("udp")
 	if err != nil {
-		t.Fatalf("SetReadDeadline: %v", err)
+		t.Fatal(err)
 	}
-	err = c.SetWriteDeadline(start.Add(writeTimeout))
+	defer c1.Close()
+
+	c2, err := Dial(c1.LocalAddr().Network(), c1.LocalAddr().String())
 	if err != nil {
-		t.Fatalf("SetWriteDeadline: %v", err)
+		t.Fatal(err)
 	}
+	defer c2.Close()
 
-	quit := make(chan bool)
+	max := time.NewTimer(time.Second)
+	defer max.Stop()
+	ch := make(chan error)
+	go timeoutPacketReceiver(c2.(PacketConn), 100*time.Millisecond, 50*time.Millisecond, 250*time.Millisecond, ch)
 
-	go func() {
-		var buf [10]byte
-		_, err := c.Read(buf[:])
-		if err == nil {
-			t.Errorf("Read should not succeed")
+	select {
+	case <-max.C:
+		t.Fatal("ReadFrom took over 1s; expected 0.1s")
+	case err := <-ch:
+		if perr := parseReadError(err); perr != nil {
+			t.Error(perr)
 		}
-		checkTimeout("Read", start, readTimeout)
-		quit <- true
-	}()
-
-	go func() {
-		var buf [10000]byte
-		for {
-			_, err := c.Write(buf[:])
-			if err != nil {
-				break
-			}
+		if nerr, ok := err.(Error); !ok || !nerr.Timeout() {
+			t.Fatal(err)
 		}
-		checkTimeout("Write", start, writeTimeout)
-		quit <- true
-	}()
-
-	<-quit
-	<-quit
-	<-lnquit
+	}
 }
 
-type neverEnding byte
+func TestWriteTimeoutFluctuation(t *testing.T) {
+	switch runtime.GOOS {
+	case "plan9":
+		t.Skipf("not supported on %s", runtime.GOOS)
+	}
 
-func (b neverEnding) Read(p []byte) (n int, err error) {
-	for i := range p {
-		p[i] = byte(b)
+	ln, err := newLocalListener("tcp")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer ln.Close()
+
+	c, err := Dial(ln.Addr().Network(), ln.Addr().String())
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer c.Close()
+
+	d := time.Second
+	if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") {
+		d = 3 * time.Second // see golang.org/issue/10775
+	}
+	max := time.NewTimer(d)
+	defer max.Stop()
+	ch := make(chan error)
+	go timeoutTransmitter(c, 100*time.Millisecond, 50*time.Millisecond, 250*time.Millisecond, ch)
+
+	select {
+	case <-max.C:
+		t.Fatalf("Write took over %v; expected 0.1s", d)
+	case err := <-ch:
+		if perr := parseWriteError(err); perr != nil {
+			t.Error(perr)
+		}
+		if nerr, ok := err.(Error); !ok || !nerr.Timeout() {
+			t.Fatal(err)
+		}
 	}
-	return len(p), nil
 }
 
 func TestVariousDeadlines1Proc(t *testing.T) {
@@ -420,36 +739,57 @@ func TestVariousDeadlines4Proc(t *testing.T) {
 	testVariousDeadlines(t, 4)
 }
 
+type neverEnding byte
+
+func (b neverEnding) Read(p []byte) (int, error) {
+	for i := range p {
+		p[i] = byte(b)
+	}
+	return len(p), nil
+}
+
 func testVariousDeadlines(t *testing.T, maxProcs int) {
 	switch runtime.GOOS {
 	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
+		t.Skipf("not supported on %s", runtime.GOOS)
 	}
 
 	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(maxProcs))
-	ln := newLocalListener(t)
-	defer ln.Close()
-	acceptc := make(chan error, 1)
 
-	// The server, with no timeouts of its own, sending bytes to clients
-	// as fast as it can.
-	servec := make(chan copyRes)
-	go func() {
+	type result struct {
+		n   int64
+		err error
+		d   time.Duration
+	}
+
+	ch := make(chan error, 1)
+	pasvch := make(chan result)
+	handler := func(ls *localServer, ln Listener) {
 		for {
 			c, err := ln.Accept()
 			if err != nil {
-				acceptc <- err
+				ch <- err
 				return
 			}
+			// The server, with no timeouts of its own,
+			// sending bytes to clients as fast as it can.
 			go func() {
 				t0 := time.Now()
 				n, err := io.Copy(c, neverEnding('a'))
-				d := time.Since(t0)
+				dt := time.Since(t0)
 				c.Close()
-				servec <- copyRes{n, err, d}
+				pasvch <- result{n, err, dt}
 			}()
 		}
-	}()
+	}
+	ls, err := newLocalServer("tcp")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer ls.teardown()
+	if err := ls.buildup(handler); err != nil {
+		t.Fatal(err)
+	}
 
 	for _, timeout := range []time.Duration{
 		1 * time.Nanosecond,
@@ -483,236 +823,133 @@ func testVariousDeadlines(t *testing.T, maxProcs int) {
 			name := fmt.Sprintf("%v run %d/%d", timeout, run+1, numRuns)
 			t.Log(name)
 
-			c, err := Dial("tcp", ln.Addr().String())
+			c, err := Dial(ls.Listener.Addr().Network(), ls.Listener.Addr().String())
 			if err != nil {
-				t.Fatalf("Dial: %v", err)
+				t.Fatal(err)
 			}
-			clientc := make(chan copyRes)
+
+			tooLong := 5 * time.Second
+			max := time.NewTimer(tooLong)
+			defer max.Stop()
+			actvch := make(chan result)
 			go func() {
 				t0 := time.Now()
-				c.SetDeadline(t0.Add(timeout))
+				if err := c.SetDeadline(t0.Add(timeout)); err != nil {
+					t.Error(err)
+				}
 				n, err := io.Copy(ioutil.Discard, c)
-				d := time.Since(t0)
+				dt := time.Since(t0)
 				c.Close()
-				clientc <- copyRes{n, err, d}
+				actvch <- result{n, err, dt}
 			}()
 
-			tooLong := 5 * time.Second
 			select {
-			case res := <-clientc:
-				if isTimeout(res.err) {
+			case res := <-actvch:
+				if nerr, ok := res.err.(Error); ok && nerr.Timeout() {
 					t.Logf("for %v, good client timeout after %v, reading %d bytes", name, res.d, res.n)
 				} else {
-					t.Fatalf("for %v: client Copy = %d, %v (want timeout)", name, res.n, res.err)
+					t.Fatalf("for %v, client Copy = %d, %v; want timeout", name, res.n, res.err)
 				}
-			case <-time.After(tooLong):
-				t.Fatalf("for %v: timeout (%v) waiting for client to timeout (%v) reading", name, tooLong, timeout)
+			case <-max.C:
+				t.Fatalf("for %v, timeout (%v) waiting for client to timeout (%v) reading", name, tooLong, timeout)
 			}
 
 			select {
-			case res := <-servec:
-				t.Logf("for %v: server in %v wrote %d, %v", name, res.d, res.n, res.err)
-			case err := <-acceptc:
-				t.Fatalf("for %v: server Accept = %v", name, err)
-			case <-time.After(tooLong):
+			case res := <-pasvch:
+				t.Logf("for %v, server in %v wrote %d: %v", name, res.d, res.n, res.err)
+			case err := <-ch:
+				t.Fatalf("for %v, Accept = %v", name, err)
+			case <-max.C:
 				t.Fatalf("for %v, timeout waiting for server to finish writing", name)
 			}
 		}
 	}
 }
 
-// TestReadDeadlineDataAvailable tests that read deadlines work, even
-// if there's data ready to be read.
-func TestReadDeadlineDataAvailable(t *testing.T) {
+// TestReadWriteProlongedTimeout tests concurrent deadline
+// modification. Known to cause data races in the past.
+func TestReadWriteProlongedTimeout(t *testing.T) {
 	switch runtime.GOOS {
 	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
+		t.Skipf("not supported on %s", runtime.GOOS)
 	}
 
-	ln := newLocalListener(t)
-	defer ln.Close()
-
-	servec := make(chan copyRes)
-	const msg = "data client shouldn't read, even though it'll be waiting"
-	go func() {
+	handler := func(ls *localServer, ln Listener) {
 		c, err := ln.Accept()
 		if err != nil {
-			t.Errorf("Accept: %v", err)
-			return
-		}
-		defer c.Close()
-		n, err := c.Write([]byte(msg))
-		servec <- copyRes{n: int64(n), err: err}
-	}()
-
-	c, err := Dial("tcp", ln.Addr().String())
-	if err != nil {
-		t.Fatalf("Dial: %v", err)
-	}
-	defer c.Close()
-	if res := <-servec; res.err != nil || res.n != int64(len(msg)) {
-		t.Fatalf("unexpected server Write: n=%d, err=%v; want n=%d, err=nil", res.n, res.err, len(msg))
-	}
-	c.SetReadDeadline(time.Now().Add(-5 * time.Second)) // in the psat.
-	buf := make([]byte, len(msg)/2)
-	n, err := c.Read(buf)
-	if n > 0 || !isTimeout(err) {
-		t.Fatalf("client read = %d (%q) err=%v; want 0, timeout", n, buf[:n], err)
-	}
-}
-
-// TestWriteDeadlineBufferAvailable tests that write deadlines work, even
-// if there's buffer space available to write.
-func TestWriteDeadlineBufferAvailable(t *testing.T) {
-	switch runtime.GOOS {
-	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
-	}
-
-	ln := newLocalListener(t)
-	defer ln.Close()
-
-	servec := make(chan copyRes)
-	go func() {
-		c, err := ln.Accept()
-		if err != nil {
-			t.Errorf("Accept: %v", err)
-			return
-		}
-		defer c.Close()
-		c.SetWriteDeadline(time.Now().Add(-5 * time.Second)) // in the past
-		n, err := c.Write([]byte{'x'})
-		servec <- copyRes{n: int64(n), err: err}
-	}()
-
-	c, err := Dial("tcp", ln.Addr().String())
-	if err != nil {
-		t.Fatalf("Dial: %v", err)
-	}
-	defer c.Close()
-	res := <-servec
-	if res.n != 0 {
-		t.Errorf("Write = %d; want 0", res.n)
-	}
-	if !isTimeout(res.err) {
-		t.Errorf("Write error = %v; want timeout", res.err)
-	}
-}
-
-// TestAcceptDeadlineConnectionAvailable tests that accept deadlines work, even
-// if there's incoming connections available.
-func TestAcceptDeadlineConnectionAvailable(t *testing.T) {
-	switch runtime.GOOS {
-	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
-	}
-
-	ln := newLocalListener(t).(*TCPListener)
-	defer ln.Close()
-
-	go func() {
-		c, err := Dial("tcp", ln.Addr().String())
-		if err != nil {
-			t.Errorf("Dial: %v", err)
+			t.Error(err)
 			return
 		}
 		defer c.Close()
-		var buf [1]byte
-		c.Read(buf[:]) // block until the connection or listener is closed
-	}()
-	time.Sleep(10 * time.Millisecond)
-	ln.SetDeadline(time.Now().Add(-5 * time.Second)) // in the past
-	c, err := ln.Accept()
-	if err == nil {
-		defer c.Close()
-	}
-	if !isTimeout(err) {
-		t.Fatalf("Accept: got %v; want timeout", err)
-	}
-}
-
-// TestConnectDeadlineInThePast tests that connect deadlines work, even
-// if the connection can be established w/o blocking.
-func TestConnectDeadlineInThePast(t *testing.T) {
-	switch runtime.GOOS {
-	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
-	}
-
-	ln := newLocalListener(t).(*TCPListener)
-	defer ln.Close()
-
-	go func() {
-		c, err := ln.Accept()
-		if err == nil {
-			defer c.Close()
-		}
-	}()
-	time.Sleep(10 * time.Millisecond)
-	c, err := DialTimeout("tcp", ln.Addr().String(), -5*time.Second) // in the past
-	if err == nil {
-		defer c.Close()
-	}
-	if !isTimeout(err) {
-		t.Fatalf("DialTimeout: got %v; want timeout", err)
-	}
-}
 
-// TestProlongTimeout tests concurrent deadline modification.
-// Known to cause data races in the past.
-func TestProlongTimeout(t *testing.T) {
-	switch runtime.GOOS {
-	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
-	}
-
-	ln := newLocalListener(t)
-	defer ln.Close()
-	connected := make(chan bool)
-	go func() {
-		s, err := ln.Accept()
-		connected <- true
-		if err != nil {
-			t.Errorf("ln.Accept: %v", err)
-			return
-		}
-		defer s.Close()
-		s.SetDeadline(time.Now().Add(time.Hour))
+		var wg sync.WaitGroup
+		wg.Add(2)
 		go func() {
-			var buf [4096]byte
+			defer wg.Done()
+			var b [1]byte
 			for {
-				_, err := s.Write(buf[:])
-				if err != nil {
-					break
+				if err := c.SetReadDeadline(time.Now().Add(time.Hour)); err != nil {
+					if perr := parseCommonError(err); perr != nil {
+						t.Error(perr)
+					}
+					t.Error(err)
+					return
+				}
+				if _, err := c.Read(b[:]); err != nil {
+					if perr := parseReadError(err); perr != nil {
+						t.Error(perr)
+					}
+					return
 				}
-				s.SetDeadline(time.Now().Add(time.Hour))
 			}
 		}()
-		buf := make([]byte, 1)
-		for {
-			_, err := s.Read(buf)
-			if err != nil {
-				break
+		go func() {
+			defer wg.Done()
+			var b [1]byte
+			for {
+				if err := c.SetWriteDeadline(time.Now().Add(time.Hour)); err != nil {
+					if perr := parseCommonError(err); perr != nil {
+						t.Error(perr)
+					}
+					t.Error(err)
+					return
+				}
+				if _, err := c.Write(b[:]); err != nil {
+					if perr := parseWriteError(err); perr != nil {
+						t.Error(perr)
+					}
+					return
+				}
 			}
-			s.SetDeadline(time.Now().Add(time.Hour))
-		}
-	}()
-	c, err := Dial("tcp", ln.Addr().String())
+		}()
+		wg.Wait()
+	}
+	ls, err := newLocalServer("tcp")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer ls.teardown()
+	if err := ls.buildup(handler); err != nil {
+		t.Fatal(err)
+	}
+
+	c, err := Dial(ls.Listener.Addr().Network(), ls.Listener.Addr().String())
 	if err != nil {
-		t.Fatalf("DialTCP: %v", err)
+		t.Fatal(err)
 	}
 	defer c.Close()
-	<-connected
-	for i := 0; i < 1024; i++ {
-		var buf [1]byte
-		c.Write(buf[:])
+
+	var b [1]byte
+	for i := 0; i < 1000; i++ {
+		c.Write(b[:])
+		c.Read(b[:])
 	}
 }
 
-func TestDeadlineRace(t *testing.T) {
+func TestReadWriteDeadlineRace(t *testing.T) {
 	switch runtime.GOOS {
 	case "nacl", "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
+		t.Skipf("not supported on %s", runtime.GOOS)
 	}
 
 	N := 1000
@@ -720,28 +957,54 @@ func TestDeadlineRace(t *testing.T) {
 		N = 50
 	}
 	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
-	ln := newLocalListener(t)
+
+	ln, err := newLocalListener("tcp")
+	if err != nil {
+		t.Fatal(err)
+	}
 	defer ln.Close()
-	c, err := Dial("tcp", ln.Addr().String())
+
+	c, err := Dial(ln.Addr().Network(), ln.Addr().String())
 	if err != nil {
-		t.Fatalf("Dial: %v", err)
+		t.Fatal(err)
 	}
 	defer c.Close()
-	done := make(chan bool)
+
+	var wg sync.WaitGroup
+	wg.Add(3)
 	go func() {
-		t := time.NewTicker(2 * time.Microsecond).C
+		defer wg.Done()
+		tic := time.NewTicker(2 * time.Microsecond)
+		defer tic.Stop()
 		for i := 0; i < N; i++ {
-			if err := c.SetDeadline(time.Now().Add(2 * time.Microsecond)); err != nil {
+			if err := c.SetReadDeadline(time.Now().Add(2 * time.Microsecond)); err != nil {
+				if perr := parseCommonError(err); perr != nil {
+					t.Error(perr)
+				}
+				break
+			}
+			if err := c.SetWriteDeadline(time.Now().Add(2 * time.Microsecond)); err != nil {
+				if perr := parseCommonError(err); perr != nil {
+					t.Error(perr)
+				}
 				break
 			}
-			<-t
+			<-tic.C
 		}
-		done <- true
 	}()
-	var buf [1]byte
-	for i := 0; i < N; i++ {
-		c.Read(buf[:]) // ignore possible timeout errors
-	}
-	c.Close()
-	<-done
+	go func() {
+		defer wg.Done()
+		var b [1]byte
+		for i := 0; i < N; i++ {
+			c.Read(b[:]) // ignore possible timeout errors
+		}
+	}()
+	go func() {
+		defer wg.Done()
+		var b [1]byte
+		for i := 0; i < N; i++ {
+			c.Write(b[:]) // ignore possible timeout errors
+		}
+	}()
+	wg.Wait() // wait for tester goroutine to stop
 }
diff --git a/src/net/udp_test.go b/src/net/udp_test.go
index 125bbca..b25f96a 100644
--- a/src/net/udp_test.go
+++ b/src/net/udp_test.go
@@ -7,149 +7,164 @@ package net
 import (
 	"reflect"
 	"runtime"
-	"strings"
 	"testing"
 	"time"
 )
 
-func TestResolveUDPAddr(t *testing.T) {
-	for _, tt := range resolveTCPAddrTests {
-		net := strings.Replace(tt.net, "tcp", "udp", -1)
-		addr, err := ResolveUDPAddr(net, tt.litAddrOrName)
-		if err != tt.err {
-			t.Fatalf("ResolveUDPAddr(%q, %q) failed: %v", net, tt.litAddrOrName, err)
-		}
-		if !reflect.DeepEqual(addr, (*UDPAddr)(tt.addr)) {
-			t.Fatalf("ResolveUDPAddr(%q, %q) = %#v, want %#v", net, tt.litAddrOrName, addr, tt.addr)
-		}
-		if err == nil {
-			str := addr.String()
-			addr1, err := ResolveUDPAddr(net, str)
-			if err != nil {
-				t.Fatalf("ResolveUDPAddr(%q, %q) [from %q]: %v", net, str, tt.litAddrOrName, err)
-			}
-			if !reflect.DeepEqual(addr1, addr) {
-				t.Fatalf("ResolveUDPAddr(%q, %q) [from %q] = %#v, want %#v", net, str, tt.litAddrOrName, addr1, addr)
-			}
-		}
-	}
+type resolveUDPAddrTest struct {
+	network       string
+	litAddrOrName string
+	addr          *UDPAddr
+	err           error
 }
 
-func TestReadFromUDP(t *testing.T) {
-	switch runtime.GOOS {
-	case "nacl", "plan9":
-		t.Skipf("skipping test on %q, see issue 8916", runtime.GOOS)
-	}
+var resolveUDPAddrTests = []resolveUDPAddrTest{
+	{"udp", "127.0.0.1:0", &UDPAddr{IP: IPv4(127, 0, 0, 1), Port: 0}, nil},
+	{"udp4", "127.0.0.1:65535", &UDPAddr{IP: IPv4(127, 0, 0, 1), Port: 65535}, nil},
 
-	ra, err := ResolveUDPAddr("udp", "127.0.0.1:7")
-	if err != nil {
-		t.Fatal(err)
-	}
+	{"udp", "[::1]:0", &UDPAddr{IP: ParseIP("::1"), Port: 0}, nil},
+	{"udp6", "[::1]:65535", &UDPAddr{IP: ParseIP("::1"), Port: 65535}, nil},
 
-	la, err := ResolveUDPAddr("udp", "127.0.0.1:0")
-	if err != nil {
-		t.Fatal(err)
-	}
+	{"udp", "[::1%en0]:1", &UDPAddr{IP: ParseIP("::1"), Port: 1, Zone: "en0"}, nil},
+	{"udp6", "[::1%911]:2", &UDPAddr{IP: ParseIP("::1"), Port: 2, Zone: "911"}, nil},
 
-	c, err := ListenUDP("udp", la)
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer c.Close()
+	{"", "127.0.0.1:0", &UDPAddr{IP: IPv4(127, 0, 0, 1), Port: 0}, nil}, // Go 1.0 behavior
+	{"", "[::1]:0", &UDPAddr{IP: ParseIP("::1"), Port: 0}, nil},         // Go 1.0 behavior
 
-	_, err = c.WriteToUDP([]byte("a"), ra)
-	if err != nil {
-		t.Fatal(err)
-	}
+	{"udp", ":12345", &UDPAddr{Port: 12345}, nil},
 
-	err = c.SetDeadline(time.Now().Add(100 * time.Millisecond))
-	if err != nil {
-		t.Fatal(err)
-	}
-	b := make([]byte, 1)
-	_, _, err = c.ReadFromUDP(b)
-	if err == nil {
-		t.Fatal("ReadFromUDP should fail")
-	} else if !isTimeout(err) {
-		t.Fatal(err)
+	{"http", "127.0.0.1:0", nil, UnknownNetworkError("http")},
+}
+
+func TestResolveUDPAddr(t *testing.T) {
+	origTestHookLookupIP := testHookLookupIP
+	defer func() { testHookLookupIP = origTestHookLookupIP }()
+	testHookLookupIP = lookupLocalhost
+
+	for i, tt := range resolveUDPAddrTests {
+		addr, err := ResolveUDPAddr(tt.network, tt.litAddrOrName)
+		if err != tt.err {
+			t.Errorf("#%d: %v", i, err)
+		} else if !reflect.DeepEqual(addr, tt.addr) {
+			t.Errorf("#%d: got %#v; want %#v", i, addr, tt.addr)
+		}
+		if err != nil {
+			continue
+		}
+		rtaddr, err := ResolveUDPAddr(addr.Network(), addr.String())
+		if err != nil {
+			t.Errorf("#%d: %v", i, err)
+		} else if !reflect.DeepEqual(rtaddr, addr) {
+			t.Errorf("#%d: got %#v; want %#v", i, rtaddr, addr)
+		}
 	}
 }
 
 func TestWriteToUDP(t *testing.T) {
 	switch runtime.GOOS {
 	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
+		t.Skipf("not supported on %s", runtime.GOOS)
 	}
 
-	l, err := ListenPacket("udp", "127.0.0.1:0")
+	c, err := ListenPacket("udp", "127.0.0.1:0")
 	if err != nil {
-		t.Fatalf("Listen failed: %v", err)
+		t.Fatal(err)
 	}
-	defer l.Close()
+	defer c.Close()
 
-	testWriteToConn(t, l.LocalAddr().String())
-	testWriteToPacketConn(t, l.LocalAddr().String())
+	testWriteToConn(t, c.LocalAddr().String())
+	testWriteToPacketConn(t, c.LocalAddr().String())
 }
 
 func testWriteToConn(t *testing.T, raddr string) {
 	c, err := Dial("udp", raddr)
 	if err != nil {
-		t.Fatalf("Dial failed: %v", err)
+		t.Fatal(err)
 	}
 	defer c.Close()
 
 	ra, err := ResolveUDPAddr("udp", raddr)
 	if err != nil {
-		t.Fatalf("ResolveUDPAddr failed: %v", err)
+		t.Fatal(err)
 	}
 
-	_, err = c.(*UDPConn).WriteToUDP([]byte("Connection-oriented mode socket"), ra)
+	b := []byte("CONNECTED-MODE SOCKET")
+	_, err = c.(*UDPConn).WriteToUDP(b, ra)
 	if err == nil {
-		t.Fatal("WriteToUDP should fail")
+		t.Fatal("should fail")
 	}
 	if err != nil && err.(*OpError).Err != ErrWriteToConnected {
-		t.Fatalf("WriteToUDP should fail as ErrWriteToConnected: %v", err)
+		t.Fatalf("should fail as ErrWriteToConnected: %v", err)
 	}
-
-	_, err = c.(*UDPConn).WriteTo([]byte("Connection-oriented mode socket"), ra)
+	_, err = c.(*UDPConn).WriteTo(b, ra)
 	if err == nil {
-		t.Fatal("WriteTo should fail")
+		t.Fatal("should fail")
 	}
 	if err != nil && err.(*OpError).Err != ErrWriteToConnected {
-		t.Fatalf("WriteTo should fail as ErrWriteToConnected: %v", err)
+		t.Fatalf("should fail as ErrWriteToConnected: %v", err)
 	}
-
-	_, err = c.Write([]byte("Connection-oriented mode socket"))
+	_, err = c.Write(b)
 	if err != nil {
-		t.Fatalf("Write failed: %v", err)
+		t.Fatal(err)
+	}
+	_, _, err = c.(*UDPConn).WriteMsgUDP(b, nil, ra)
+	if err == nil {
+		t.Fatal("should fail")
+	}
+	if err != nil && err.(*OpError).Err != ErrWriteToConnected {
+		t.Fatalf("should fail as ErrWriteToConnected: %v", err)
+	}
+	_, _, err = c.(*UDPConn).WriteMsgUDP(b, nil, nil)
+	switch runtime.GOOS {
+	case "nacl", "windows": // see golang.org/issue/9252
+		t.Skipf("not implemented yet on %s", runtime.GOOS)
+	default:
+		if err != nil {
+			t.Fatal(err)
+		}
 	}
 }
 
 func testWriteToPacketConn(t *testing.T, raddr string) {
 	c, err := ListenPacket("udp", "127.0.0.1:0")
 	if err != nil {
-		t.Fatalf("ListenPacket failed: %v", err)
+		t.Fatal(err)
 	}
 	defer c.Close()
 
 	ra, err := ResolveUDPAddr("udp", raddr)
 	if err != nil {
-		t.Fatalf("ResolveUDPAddr failed: %v", err)
+		t.Fatal(err)
 	}
 
-	_, err = c.(*UDPConn).WriteToUDP([]byte("Connection-less mode socket"), ra)
+	b := []byte("UNCONNECTED-MODE SOCKET")
+	_, err = c.(*UDPConn).WriteToUDP(b, ra)
 	if err != nil {
-		t.Fatalf("WriteToUDP failed: %v", err)
+		t.Fatal(err)
 	}
-
-	_, err = c.WriteTo([]byte("Connection-less mode socket"), ra)
+	_, err = c.WriteTo(b, ra)
 	if err != nil {
-		t.Fatalf("WriteTo failed: %v", err)
+		t.Fatal(err)
 	}
-
-	_, err = c.(*UDPConn).Write([]byte("Connection-less mode socket"))
+	_, err = c.(*UDPConn).Write(b)
+	if err == nil {
+		t.Fatal("should fail")
+	}
+	_, _, err = c.(*UDPConn).WriteMsgUDP(b, nil, nil)
 	if err == nil {
-		t.Fatal("Write should fail")
+		t.Fatal("should fail")
+	}
+	if err != nil && err.(*OpError).Err != errMissingAddress {
+		t.Fatalf("should fail as errMissingAddress: %v", err)
+	}
+	_, _, err = c.(*UDPConn).WriteMsgUDP(b, nil, ra)
+	switch runtime.GOOS {
+	case "nacl", "windows": // see golang.org/issue/9252
+		t.Skipf("not implemented yet on %s", runtime.GOOS)
+	default:
+		if err != nil {
+			t.Fatal(err)
+		}
 	}
 }
 
@@ -164,13 +179,13 @@ var udpConnLocalNameTests = []struct {
 
 func TestUDPConnLocalName(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
+		t.Skip("avoid external network")
 	}
 
 	for _, tt := range udpConnLocalNameTests {
 		c, err := ListenUDP(tt.net, tt.laddr)
 		if err != nil {
-			t.Fatalf("ListenUDP failed: %v", err)
+			t.Fatal(err)
 		}
 		defer c.Close()
 		la := c.LocalAddr()
@@ -184,7 +199,7 @@ func TestUDPConnLocalAndRemoteNames(t *testing.T) {
 	for _, laddr := range []string{"", "127.0.0.1:0"} {
 		c1, err := ListenPacket("udp", "127.0.0.1:0")
 		if err != nil {
-			t.Fatalf("ListenUDP failed: %v", err)
+			t.Fatal(err)
 		}
 		defer c1.Close()
 
@@ -192,12 +207,12 @@ func TestUDPConnLocalAndRemoteNames(t *testing.T) {
 		if laddr != "" {
 			var err error
 			if la, err = ResolveUDPAddr("udp", laddr); err != nil {
-				t.Fatalf("ResolveUDPAddr failed: %v", err)
+				t.Fatal(err)
 			}
 		}
 		c2, err := DialUDP("udp", la, c1.LocalAddr().(*UDPAddr))
 		if err != nil {
-			t.Fatalf("DialUDP failed: %v", err)
+			t.Fatal(err)
 		}
 		defer c2.Close()
 
@@ -220,60 +235,37 @@ func TestUDPConnLocalAndRemoteNames(t *testing.T) {
 
 func TestIPv6LinkLocalUnicastUDP(t *testing.T) {
 	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
+		t.Skip("avoid external network")
 	}
 	if !supportsIPv6 {
-		t.Skip("ipv6 is not supported")
-	}
-	ifi := loopbackInterface()
-	if ifi == nil {
-		t.Skip("loopback interface not found")
-	}
-	laddr := ipv6LinkLocalUnicastAddr(ifi)
-	if laddr == "" {
-		t.Skip("ipv6 unicast address on loopback not found")
+		t.Skip("IPv6 is not supported")
 	}
 
-	type test struct {
-		net, addr  string
-		nameLookup bool
-	}
-	var tests = []test{
-		{"udp", "[" + laddr + "%" + ifi.Name + "]:0", false},
-		{"udp6", "[" + laddr + "%" + ifi.Name + "]:0", false},
-	}
-	// The first udp test fails on DragonFly - see issue 7473.
-	if runtime.GOOS == "dragonfly" {
-		tests = tests[1:]
-	}
-	switch runtime.GOOS {
-	case "darwin", "dragonfly", "freebsd", "openbsd", "netbsd":
-		tests = append(tests, []test{
-			{"udp", "[localhost%" + ifi.Name + "]:0", true},
-			{"udp6", "[localhost%" + ifi.Name + "]:0", true},
-		}...)
-	case "linux":
-		tests = append(tests, []test{
-			{"udp", "[ip6-localhost%" + ifi.Name + "]:0", true},
-			{"udp6", "[ip6-localhost%" + ifi.Name + "]:0", true},
-		}...)
-	}
-	for _, tt := range tests {
-		c1, err := ListenPacket(tt.net, tt.addr)
+	for i, tt := range ipv6LinkLocalUnicastUDPTests {
+		c1, err := ListenPacket(tt.network, tt.address)
 		if err != nil {
 			// It might return "LookupHost returned no
 			// suitable address" error on some platforms.
-			t.Logf("ListenPacket failed: %v", err)
+			t.Log(err)
 			continue
 		}
-		defer c1.Close()
+		ls, err := (&packetListener{PacketConn: c1}).newLocalServer()
+		if err != nil {
+			t.Fatal(err)
+		}
+		defer ls.teardown()
+		ch := make(chan error, 1)
+		handler := func(ls *localPacketServer, c PacketConn) { packetTransponder(c, ch) }
+		if err := ls.buildup(handler); err != nil {
+			t.Fatal(err)
+		}
 		if la, ok := c1.LocalAddr().(*UDPAddr); !ok || !tt.nameLookup && la.Zone == "" {
 			t.Fatalf("got %v; expected a proper address with zone identifier", la)
 		}
 
-		c2, err := Dial(tt.net, c1.LocalAddr().String())
+		c2, err := Dial(tt.network, ls.PacketConn.LocalAddr().String())
 		if err != nil {
-			t.Fatalf("Dial failed: %v", err)
+			t.Fatal(err)
 		}
 		defer c2.Close()
 		if la, ok := c2.LocalAddr().(*UDPAddr); !ok || !tt.nameLookup && la.Zone == "" {
@@ -284,14 +276,88 @@ func TestIPv6LinkLocalUnicastUDP(t *testing.T) {
 		}
 
 		if _, err := c2.Write([]byte("UDP OVER IPV6 LINKLOCAL TEST")); err != nil {
-			t.Fatalf("Conn.Write failed: %v", err)
+			t.Fatal(err)
 		}
 		b := make([]byte, 32)
-		if _, from, err := c1.ReadFrom(b); err != nil {
-			t.Fatalf("PacketConn.ReadFrom failed: %v", err)
+		if _, err := c2.Read(b); err != nil {
+			t.Fatal(err)
+		}
+
+		for err := range ch {
+			t.Errorf("#%d: %v", i, err)
+		}
+	}
+}
+
+func TestUDPZeroBytePayload(t *testing.T) {
+	switch runtime.GOOS {
+	case "nacl", "plan9":
+		t.Skipf("not supported on %s", runtime.GOOS)
+	}
+
+	c, err := newLocalPacketListener("udp")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer c.Close()
+
+	for _, genericRead := range []bool{false, true} {
+		n, err := c.WriteTo(nil, c.LocalAddr())
+		if err != nil {
+			t.Fatal(err)
+		}
+		if n != 0 {
+			t.Errorf("got %d; want 0", n)
+		}
+		c.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
+		var b [1]byte
+		if genericRead {
+			_, err = c.(Conn).Read(b[:])
 		} else {
-			if ra, ok := from.(*UDPAddr); !ok || !tt.nameLookup && ra.Zone == "" {
-				t.Fatalf("got %v; expected a proper address with zone identifier", ra)
+			_, _, err = c.ReadFrom(b[:])
+		}
+		switch err {
+		case nil: // ReadFrom succeeds
+		default: // Read may timeout, it depends on the platform
+			if nerr, ok := err.(Error); !ok || !nerr.Timeout() {
+				t.Fatal(err)
+			}
+		}
+	}
+}
+
+func TestUDPZeroByteBuffer(t *testing.T) {
+	switch runtime.GOOS {
+	case "nacl", "plan9":
+		t.Skipf("not supported on %s", runtime.GOOS)
+	}
+
+	c, err := newLocalPacketListener("udp")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer c.Close()
+
+	b := []byte("UDP ZERO BYTE BUFFER TEST")
+	for _, genericRead := range []bool{false, true} {
+		n, err := c.WriteTo(b, c.LocalAddr())
+		if err != nil {
+			t.Fatal(err)
+		}
+		if n != len(b) {
+			t.Errorf("got %d; want %d", n, len(b))
+		}
+		c.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
+		if genericRead {
+			_, err = c.(Conn).Read(nil)
+		} else {
+			_, _, err = c.ReadFrom(nil)
+		}
+		switch err {
+		case nil: // ReadFrom succeeds
+		default: // Read may timeout, it depends on the platform
+			if nerr, ok := err.(Error); (!ok || !nerr.Timeout()) && runtime.GOOS != "windows" { // Windows retruns WSAEMSGSIZ
+				t.Fatal(err)
 			}
 		}
 	}
diff --git a/src/net/udpsock.go b/src/net/udpsock.go
index 4c99ae4..9292133 100644
--- a/src/net/udpsock.go
+++ b/src/net/udpsock.go
@@ -25,7 +25,14 @@ func (a *UDPAddr) String() string {
 	return JoinHostPort(ip, itoa(a.Port))
 }
 
-func (a *UDPAddr) toAddr() Addr {
+func (a *UDPAddr) isWildcard() bool {
+	if a == nil || a.IP == nil {
+		return true
+	}
+	return a.IP.IsUnspecified()
+}
+
+func (a *UDPAddr) opAddr() Addr {
 	if a == nil {
 		return nil
 	}
@@ -46,9 +53,9 @@ func ResolveUDPAddr(net, addr string) (*UDPAddr, error) {
 	default:
 		return nil, UnknownNetworkError(net)
 	}
-	a, err := resolveInternetAddr(net, addr, noDeadline)
+	addrs, err := internetAddrList(net, addr, noDeadline)
 	if err != nil {
 		return nil, err
 	}
-	return a.toAddr().(*UDPAddr), nil
+	return addrs.first(isIPv4).(*UDPAddr), nil
 }
diff --git a/src/net/udpsock_plan9.go b/src/net/udpsock_plan9.go
index 510ac5e..1ba57a2 100644
--- a/src/net/udpsock_plan9.go
+++ b/src/net/udpsock_plan9.go
@@ -33,10 +33,10 @@ func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) {
 	buf := make([]byte, udpHeaderSize+len(b))
 	m, err := c.fd.data.Read(buf)
 	if err != nil {
-		return
+		return 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
 	}
 	if m < udpHeaderSize {
-		return 0, nil, errors.New("short read reading UDP header")
+		return 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: errors.New("short read reading UDP header")}
 	}
 	buf = buf[:m]
 
@@ -59,7 +59,7 @@ func (c *UDPConn) ReadFrom(b []byte) (int, Addr, error) {
 // flags that were set on the packet and the source address of the
 // packet.
 func (c *UDPConn) ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *UDPAddr, err error) {
-	return 0, 0, 0, nil, syscall.EPLAN9
+	return 0, 0, 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
 }
 
 // WriteToUDP writes a UDP packet to addr via c, copying the payload
@@ -74,7 +74,7 @@ func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (int, error) {
 		return 0, syscall.EINVAL
 	}
 	if addr == nil {
-		return 0, &OpError{Op: "write", Net: c.fd.dir, Addr: nil, Err: errMissingAddress}
+		return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: nil, Err: errMissingAddress}
 	}
 	h := new(udpHeader)
 	h.raddr = addr.IP.To16()
@@ -86,7 +86,10 @@ func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (int, error) {
 	buf := make([]byte, udpHeaderSize+len(b))
 	i := copy(buf, h.Bytes())
 	copy(buf[i:], b)
-	return c.fd.data.Write(buf)
+	if _, err := c.fd.data.Write(buf); err != nil {
+		return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
+	}
+	return len(b), nil
 }
 
 // WriteTo implements the PacketConn WriteTo method.
@@ -96,16 +99,18 @@ func (c *UDPConn) WriteTo(b []byte, addr Addr) (int, error) {
 	}
 	a, ok := addr.(*UDPAddr)
 	if !ok {
-		return 0, &OpError{"write", c.fd.dir, addr, syscall.EINVAL}
+		return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr, Err: syscall.EINVAL}
 	}
 	return c.WriteToUDP(b, a)
 }
 
-// WriteMsgUDP writes a packet to addr via c, copying the payload from
-// b and the associated out-of-band data from oob.  It returns the
-// number of payload and out-of-band bytes written.
+// WriteMsgUDP writes a packet to addr via c if c isn't connected, or
+// to c's remote destination address if c is connected (in which case
+// addr must be nil).  The payload is copied from b and the associated
+// out-of-band data is copied from oob.  It returns the number of
+// payload and out-of-band bytes written.
 func (c *UDPConn) WriteMsgUDP(b, oob []byte, addr *UDPAddr) (n, oobn int, err error) {
-	return 0, 0, syscall.EPLAN9
+	return 0, 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr.opAddr(), Err: syscall.EPLAN9}
 }
 
 // DialUDP connects to the remote address raddr on the network net,
@@ -122,10 +127,10 @@ func dialUDP(net string, laddr, raddr *UDPAddr, deadline time.Time) (*UDPConn, e
 	switch net {
 	case "udp", "udp4", "udp6":
 	default:
-		return nil, UnknownNetworkError(net)
+		return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(net)}
 	}
 	if raddr == nil {
-		return nil, &OpError{"dial", net, nil, errMissingAddress}
+		return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: nil, Err: errMissingAddress}
 	}
 	fd, err := dialPlan9(net, laddr, raddr)
 	if err != nil {
@@ -173,7 +178,7 @@ func ListenUDP(net string, laddr *UDPAddr) (*UDPConn, error) {
 	switch net {
 	case "udp", "udp4", "udp6":
 	default:
-		return nil, UnknownNetworkError(net)
+		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(net)}
 	}
 	if laddr == nil {
 		laddr = &UDPAddr{}
@@ -184,20 +189,27 @@ func ListenUDP(net string, laddr *UDPAddr) (*UDPConn, error) {
 	}
 	_, err = l.ctl.WriteString("headers")
 	if err != nil {
-		return nil, err
+		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err}
 	}
 	l.data, err = os.OpenFile(l.dir+"/data", os.O_RDWR, 0)
 	if err != nil {
-		return nil, err
+		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err}
 	}
 	fd, err := l.netFD()
 	return newUDPConn(fd), err
 }
 
 // ListenMulticastUDP listens for incoming multicast UDP packets
-// addressed to the group address gaddr on ifi, which specifies the
-// interface to join.  ListenMulticastUDP uses default multicast
-// interface if ifi is nil.
-func ListenMulticastUDP(net string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) {
-	return nil, syscall.EPLAN9
+// addressed to the group address gaddr on the interface ifi.
+// Network must be "udp", "udp4" or "udp6".
+// ListenMulticastUDP uses the system-assigned multicast interface
+// when ifi is nil, although this is not recommended because the
+// assignment depends on platforms and sometimes it might require
+// routing configuration.
+//
+// ListenMulticastUDP is just for convenience of simple, small
+// applications. There are golang.org/x/net/ipv4 and
+// golang.org/x/net/ipv6 packages for general purpose uses.
+func ListenMulticastUDP(network string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) {
+	return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: gaddr.opAddr(), Err: syscall.EPLAN9}
 }
diff --git a/src/net/udpsock_posix.go b/src/net/udpsock_posix.go
index a053336..61868c4 100644
--- a/src/net/udpsock_posix.go
+++ b/src/net/udpsock_posix.go
@@ -31,13 +31,6 @@ func (a *UDPAddr) family() int {
 	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
@@ -60,10 +53,11 @@ func newUDPConn(fd *netFD) *UDPConn { return &UDPConn{conn{fd}} }
 // ReadFromUDP can be made to time out and return an error with
 // Timeout() == true after a fixed time limit; see SetDeadline and
 // SetReadDeadline.
-func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) {
+func (c *UDPConn) ReadFromUDP(b []byte) (int, *UDPAddr, error) {
 	if !c.ok() {
 		return 0, nil, syscall.EINVAL
 	}
+	var addr *UDPAddr
 	n, sa, err := c.fd.readFrom(b)
 	switch sa := sa.(type) {
 	case *syscall.SockaddrInet4:
@@ -71,7 +65,10 @@ func (c *UDPConn) ReadFromUDP(b []byte) (n int, addr *UDPAddr, err error) {
 	case *syscall.SockaddrInet6:
 		addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneToString(int(sa.ZoneId))}
 	}
-	return
+	if err != nil {
+		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return n, addr, err
 }
 
 // ReadFrom implements the PacketConn ReadFrom method.
@@ -80,7 +77,10 @@ func (c *UDPConn) ReadFrom(b []byte) (int, Addr, error) {
 		return 0, nil, syscall.EINVAL
 	}
 	n, addr, err := c.ReadFromUDP(b)
-	return n, addr.toAddr(), err
+	if addr == nil {
+		return n, nil, err
+	}
+	return n, addr, err
 }
 
 // ReadMsgUDP reads a packet from c, copying the payload into b and
@@ -100,6 +100,9 @@ func (c *UDPConn) ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *UDPAddr,
 	case *syscall.SockaddrInet6:
 		addr = &UDPAddr{IP: sa.Addr[0:], Port: sa.Port, Zone: zoneToString(int(sa.ZoneId))}
 	}
+	if err != nil {
+		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
 	return
 }
 
@@ -115,16 +118,20 @@ func (c *UDPConn) WriteToUDP(b []byte, addr *UDPAddr) (int, error) {
 		return 0, syscall.EINVAL
 	}
 	if c.fd.isConnected {
-		return 0, &OpError{"write", c.fd.net, addr, ErrWriteToConnected}
+		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: ErrWriteToConnected}
 	}
 	if addr == nil {
-		return 0, &OpError{Op: "write", Net: c.fd.net, Addr: nil, Err: errMissingAddress}
+		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: nil, Err: errMissingAddress}
 	}
 	sa, err := addr.sockaddr(c.fd.family)
 	if err != nil {
-		return 0, &OpError{"write", c.fd.net, addr, err}
+		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
 	}
-	return c.fd.writeTo(b, sa)
+	n, err := c.fd.writeTo(b, sa)
+	if err != nil {
+		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
+	}
+	return n, err
 }
 
 // WriteTo implements the PacketConn WriteTo method.
@@ -134,29 +141,36 @@ func (c *UDPConn) WriteTo(b []byte, addr Addr) (int, error) {
 	}
 	a, ok := addr.(*UDPAddr)
 	if !ok {
-		return 0, &OpError{"write", c.fd.net, addr, syscall.EINVAL}
+		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: syscall.EINVAL}
 	}
 	return c.WriteToUDP(b, a)
 }
 
-// WriteMsgUDP writes a packet to addr via c, copying the payload from
-// b and the associated out-of-band data from oob.  It returns the
-// number of payload and out-of-band bytes written.
+// WriteMsgUDP writes a packet to addr via c if c isn't connected, or
+// to c's remote destination address if c is connected (in which case
+// addr must be nil).  The payload is copied from b and the associated
+// out-of-band data is copied from oob.  It returns the number of
+// payload and out-of-band bytes written.
 func (c *UDPConn) WriteMsgUDP(b, oob []byte, addr *UDPAddr) (n, oobn int, err error) {
 	if !c.ok() {
 		return 0, 0, syscall.EINVAL
 	}
-	if c.fd.isConnected {
-		return 0, 0, &OpError{"write", c.fd.net, addr, ErrWriteToConnected}
+	if c.fd.isConnected && addr != nil {
+		return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: ErrWriteToConnected}
 	}
-	if addr == nil {
-		return 0, 0, &OpError{Op: "write", Net: c.fd.net, Addr: nil, Err: errMissingAddress}
+	if !c.fd.isConnected && addr == nil {
+		return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: errMissingAddress}
 	}
-	sa, err := addr.sockaddr(c.fd.family)
+	var sa syscall.Sockaddr
+	sa, err = addr.sockaddr(c.fd.family)
 	if err != nil {
-		return 0, 0, &OpError{"write", c.fd.net, addr, err}
+		return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
 	}
-	return c.fd.writeMsg(b, oob, sa)
+	n, oobn, err = c.fd.writeMsg(b, oob, sa)
+	if err != nil {
+		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
+	}
+	return
 }
 
 // DialUDP connects to the remote address raddr on the network net,
@@ -166,10 +180,10 @@ func DialUDP(net string, laddr, raddr *UDPAddr) (*UDPConn, error) {
 	switch net {
 	case "udp", "udp4", "udp6":
 	default:
-		return nil, &OpError{Op: "dial", Net: net, Addr: raddr, Err: UnknownNetworkError(net)}
+		return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(net)}
 	}
 	if raddr == nil {
-		return nil, &OpError{Op: "dial", Net: net, Addr: nil, Err: errMissingAddress}
+		return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: nil, Err: errMissingAddress}
 	}
 	return dialUDP(net, laddr, raddr, noDeadline)
 }
@@ -177,7 +191,7 @@ func DialUDP(net string, laddr, raddr *UDPAddr) (*UDPConn, error) {
 func dialUDP(net string, laddr, raddr *UDPAddr, deadline time.Time) (*UDPConn, error) {
 	fd, err := internetSocket(net, laddr, raddr, deadline, syscall.SOCK_DGRAM, 0, "dial")
 	if err != nil {
-		return nil, &OpError{Op: "dial", Net: net, Addr: raddr, Err: err}
+		return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err}
 	}
 	return newUDPConn(fd), nil
 }
@@ -193,45 +207,52 @@ func ListenUDP(net string, laddr *UDPAddr) (*UDPConn, error) {
 	switch net {
 	case "udp", "udp4", "udp6":
 	default:
-		return nil, &OpError{Op: "listen", Net: net, Addr: laddr, Err: UnknownNetworkError(net)}
+		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(net)}
 	}
 	if laddr == nil {
 		laddr = &UDPAddr{}
 	}
 	fd, err := internetSocket(net, laddr, nil, noDeadline, syscall.SOCK_DGRAM, 0, "listen")
 	if err != nil {
-		return nil, &OpError{Op: "listen", Net: net, Addr: laddr, Err: err}
+		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr, Err: err}
 	}
 	return newUDPConn(fd), nil
 }
 
 // ListenMulticastUDP listens for incoming multicast UDP packets
-// addressed to the group address gaddr on ifi, which specifies the
-// interface to join.  ListenMulticastUDP uses default multicast
-// interface if ifi is nil.
-func ListenMulticastUDP(net string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) {
-	switch net {
+// addressed to the group address gaddr on the interface ifi.
+// Network must be "udp", "udp4" or "udp6".
+// ListenMulticastUDP uses the system-assigned multicast interface
+// when ifi is nil, although this is not recommended because the
+// assignment depends on platforms and sometimes it might require
+// routing configuration.
+//
+// ListenMulticastUDP is just for convenience of simple, small
+// applications. There are golang.org/x/net/ipv4 and
+// golang.org/x/net/ipv6 packages for general purpose uses.
+func ListenMulticastUDP(network string, ifi *Interface, gaddr *UDPAddr) (*UDPConn, error) {
+	switch network {
 	case "udp", "udp4", "udp6":
 	default:
-		return nil, &OpError{Op: "listen", Net: net, Addr: gaddr, Err: UnknownNetworkError(net)}
+		return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: gaddr.opAddr(), Err: UnknownNetworkError(network)}
 	}
 	if gaddr == nil || gaddr.IP == nil {
-		return nil, &OpError{Op: "listen", Net: net, Addr: nil, Err: errMissingAddress}
+		return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: gaddr.opAddr(), Err: errMissingAddress}
 	}
-	fd, err := internetSocket(net, gaddr, nil, noDeadline, syscall.SOCK_DGRAM, 0, "listen")
+	fd, err := internetSocket(network, gaddr, nil, noDeadline, syscall.SOCK_DGRAM, 0, "listen")
 	if err != nil {
-		return nil, &OpError{Op: "listen", Net: net, Addr: gaddr, Err: err}
+		return nil, &OpError{Op: "listen", Net: network, Source: nil, Addr: gaddr, Err: err}
 	}
 	c := newUDPConn(fd)
 	if ip4 := gaddr.IP.To4(); ip4 != nil {
 		if err := listenIPv4MulticastUDP(c, ifi, ip4); err != nil {
 			c.Close()
-			return nil, &OpError{Op: "listen", Net: net, Addr: &IPAddr{IP: ip4}, Err: err}
+			return nil, &OpError{Op: "listen", Net: network, Source: c.fd.laddr, Addr: &IPAddr{IP: ip4}, Err: err}
 		}
 	} else {
 		if err := listenIPv6MulticastUDP(c, ifi, gaddr.IP); err != nil {
 			c.Close()
-			return nil, &OpError{Op: "listen", Net: net, Addr: &IPAddr{IP: gaddr.IP}, Err: err}
+			return nil, &OpError{Op: "listen", Net: network, Source: c.fd.laddr, Addr: &IPAddr{IP: gaddr.IP}, Err: err}
 		}
 	}
 	return c, nil
diff --git a/src/net/unicast_posix_test.go b/src/net/unicast_posix_test.go
deleted file mode 100644
index ab7ef40..0000000
--- a/src/net/unicast_posix_test.go
+++ /dev/null
@@ -1,469 +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.
-
-// +build !plan9
-
-package net
-
-import (
-	"runtime"
-	"syscall"
-	"testing"
-)
-
-var listenerTests = []struct {
-	net      string
-	laddr    string
-	ipv6     bool // test with underlying AF_INET6 socket
-	wildcard bool // test with wildcard address
-}{
-	{net: "tcp", laddr: "", wildcard: true},
-	{net: "tcp", laddr: "0.0.0.0", wildcard: true},
-	{net: "tcp", laddr: "[::ffff:0.0.0.0]", wildcard: true},
-	{net: "tcp", laddr: "[::]", ipv6: true, wildcard: true},
-
-	{net: "tcp", laddr: "127.0.0.1"},
-	{net: "tcp", laddr: "[::ffff:127.0.0.1]"},
-	{net: "tcp", laddr: "[::1]", ipv6: true},
-
-	{net: "tcp4", laddr: "", wildcard: true},
-	{net: "tcp4", laddr: "0.0.0.0", wildcard: true},
-	{net: "tcp4", laddr: "[::ffff:0.0.0.0]", wildcard: true},
-
-	{net: "tcp4", laddr: "127.0.0.1"},
-	{net: "tcp4", laddr: "[::ffff:127.0.0.1]"},
-
-	{net: "tcp6", laddr: "", ipv6: true, wildcard: true},
-	{net: "tcp6", laddr: "[::]", ipv6: true, wildcard: true},
-
-	{net: "tcp6", laddr: "[::1]", ipv6: true},
-}
-
-// TestTCPListener tests both single and double listen to a test
-// listener with same address family, same listening address and
-// same port.
-func TestTCPListener(t *testing.T) {
-	switch runtime.GOOS {
-	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
-	}
-
-	for _, tt := range listenerTests {
-		if tt.wildcard && (testing.Short() || !*testExternal) {
-			continue
-		}
-		if tt.ipv6 && !supportsIPv6 {
-			continue
-		}
-		l1, port := usableListenPort(t, tt.net, tt.laddr)
-		checkFirstListener(t, tt.net, tt.laddr+":"+port, l1)
-		l2, err := Listen(tt.net, tt.laddr+":"+port)
-		checkSecondListener(t, tt.net, tt.laddr+":"+port, err, l2)
-		l1.Close()
-	}
-}
-
-// TestUDPListener tests both single and double listen to a test
-// listener with same address family, same listening address and
-// same port.
-func TestUDPListener(t *testing.T) {
-	switch runtime.GOOS {
-	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
-	}
-
-	toudpnet := func(net string) string {
-		switch net {
-		case "tcp":
-			return "udp"
-		case "tcp4":
-			return "udp4"
-		case "tcp6":
-			return "udp6"
-		}
-		return "<nil>"
-	}
-
-	for _, tt := range listenerTests {
-		if tt.wildcard && (testing.Short() || !*testExternal) {
-			continue
-		}
-		if tt.ipv6 && !supportsIPv6 {
-			continue
-		}
-		tt.net = toudpnet(tt.net)
-		l1, port := usableListenPacketPort(t, tt.net, tt.laddr)
-		checkFirstListener(t, tt.net, tt.laddr+":"+port, l1)
-		l2, err := ListenPacket(tt.net, tt.laddr+":"+port)
-		checkSecondListener(t, tt.net, tt.laddr+":"+port, err, l2)
-		l1.Close()
-	}
-}
-
-var dualStackListenerTests = []struct {
-	net1     string // first listener
-	laddr1   string
-	net2     string // second listener
-	laddr2   string
-	wildcard bool  // test with wildcard address
-	xerr     error // expected error value, nil or other
-}{
-	// Test cases and expected results for the attemping 2nd listen on the same port
-	// 1st listen                2nd listen                 darwin  freebsd  linux  openbsd
-	// ------------------------------------------------------------------------------------
-	// "tcp"  ""                 "tcp"  ""                    -        -       -       -
-	// "tcp"  ""                 "tcp"  "0.0.0.0"             -        -       -       -
-	// "tcp"  "0.0.0.0"          "tcp"  ""                    -        -       -       -
-	// ------------------------------------------------------------------------------------
-	// "tcp"  ""                 "tcp"  "[::]"                -        -       -       ok
-	// "tcp"  "[::]"             "tcp"  ""                    -        -       -       ok
-	// "tcp"  "0.0.0.0"          "tcp"  "[::]"                -        -       -       ok
-	// "tcp"  "[::]"             "tcp"  "0.0.0.0"             -        -       -       ok
-	// "tcp"  "[::ffff:0.0.0.0]" "tcp"  "[::]"                -        -       -       ok
-	// "tcp"  "[::]"             "tcp"  "[::ffff:0.0.0.0]"    -        -       -       ok
-	// ------------------------------------------------------------------------------------
-	// "tcp4" ""                 "tcp6" ""                    ok       ok      ok      ok
-	// "tcp6" ""                 "tcp4" ""                    ok       ok      ok      ok
-	// "tcp4" "0.0.0.0"          "tcp6" "[::]"                ok       ok      ok      ok
-	// "tcp6" "[::]"             "tcp4" "0.0.0.0"             ok       ok      ok      ok
-	// ------------------------------------------------------------------------------------
-	// "tcp"  "127.0.0.1"        "tcp"  "[::1]"               ok       ok      ok      ok
-	// "tcp"  "[::1]"            "tcp"  "127.0.0.1"           ok       ok      ok      ok
-	// "tcp4" "127.0.0.1"        "tcp6" "[::1]"               ok       ok      ok      ok
-	// "tcp6" "[::1]"            "tcp4" "127.0.0.1"           ok       ok      ok      ok
-	//
-	// Platform default configurations:
-	// darwin, kernel version 11.3.0
-	//	net.inet6.ip6.v6only=0 (overridable by sysctl or IPV6_V6ONLY option)
-	// freebsd, kernel version 8.2
-	//	net.inet6.ip6.v6only=1 (overridable by sysctl or IPV6_V6ONLY option)
-	// linux, kernel version 3.0.0
-	//	net.ipv6.bindv6only=0 (overridable by sysctl or IPV6_V6ONLY option)
-	// openbsd, kernel version 5.0
-	//	net.inet6.ip6.v6only=1 (overriding is prohibited)
-
-	{net1: "tcp", laddr1: "", net2: "tcp", laddr2: "", wildcard: true, xerr: syscall.EADDRINUSE},
-	{net1: "tcp", laddr1: "", net2: "tcp", laddr2: "0.0.0.0", wildcard: true, xerr: syscall.EADDRINUSE},
-	{net1: "tcp", laddr1: "0.0.0.0", net2: "tcp", laddr2: "", wildcard: true, xerr: syscall.EADDRINUSE},
-
-	{net1: "tcp", laddr1: "", net2: "tcp", laddr2: "[::]", wildcard: true, xerr: syscall.EADDRINUSE},
-	{net1: "tcp", laddr1: "[::]", net2: "tcp", laddr2: "", wildcard: true, xerr: syscall.EADDRINUSE},
-	{net1: "tcp", laddr1: "0.0.0.0", net2: "tcp", laddr2: "[::]", wildcard: true, xerr: syscall.EADDRINUSE},
-	{net1: "tcp", laddr1: "[::]", net2: "tcp", laddr2: "0.0.0.0", wildcard: true, xerr: syscall.EADDRINUSE},
-	{net1: "tcp", laddr1: "[::ffff:0.0.0.0]", net2: "tcp", laddr2: "[::]", wildcard: true, xerr: syscall.EADDRINUSE},
-	{net1: "tcp", laddr1: "[::]", net2: "tcp", laddr2: "[::ffff:0.0.0.0]", wildcard: true, xerr: syscall.EADDRINUSE},
-
-	{net1: "tcp4", laddr1: "", net2: "tcp6", laddr2: "", wildcard: true},
-	{net1: "tcp6", laddr1: "", net2: "tcp4", laddr2: "", wildcard: true},
-	{net1: "tcp4", laddr1: "0.0.0.0", net2: "tcp6", laddr2: "[::]", wildcard: true},
-	{net1: "tcp6", laddr1: "[::]", net2: "tcp4", laddr2: "0.0.0.0", wildcard: true},
-
-	{net1: "tcp", laddr1: "127.0.0.1", net2: "tcp", laddr2: "[::1]"},
-	{net1: "tcp", laddr1: "[::1]", net2: "tcp", laddr2: "127.0.0.1"},
-	{net1: "tcp4", laddr1: "127.0.0.1", net2: "tcp6", laddr2: "[::1]"},
-	{net1: "tcp6", laddr1: "[::1]", net2: "tcp4", laddr2: "127.0.0.1"},
-}
-
-// TestDualStackTCPListener tests both single and double listen
-// to a test listener with various address families, different
-// listening address and same port.
-func TestDualStackTCPListener(t *testing.T) {
-	if testing.Short() {
-		t.Skip("skipping in -short mode, see issue 5001")
-	}
-	switch runtime.GOOS {
-	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
-	}
-	if !supportsIPv6 {
-		t.Skip("ipv6 is not supported")
-	}
-
-	for _, tt := range dualStackListenerTests {
-		if tt.wildcard && !*testExternal {
-			continue
-		}
-		switch runtime.GOOS {
-		case "openbsd":
-			if tt.wildcard && differentWildcardAddr(tt.laddr1, tt.laddr2) {
-				tt.xerr = nil
-			}
-		}
-		l1, port := usableListenPort(t, tt.net1, tt.laddr1)
-		laddr := tt.laddr1 + ":" + port
-		checkFirstListener(t, tt.net1, laddr, l1)
-		laddr = tt.laddr2 + ":" + port
-		l2, err := Listen(tt.net2, laddr)
-		checkDualStackSecondListener(t, tt.net2, laddr, tt.xerr, err, l2)
-		l1.Close()
-	}
-}
-
-// TestDualStackUDPListener tests both single and double listen
-// to a test listener with various address families, differnet
-// listening address and same port.
-func TestDualStackUDPListener(t *testing.T) {
-	if testing.Short() {
-		t.Skip("skipping in -short mode, see issue 5001")
-	}
-	switch runtime.GOOS {
-	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
-	}
-	if !supportsIPv6 {
-		t.Skip("ipv6 is not supported")
-	}
-
-	toudpnet := func(net string) string {
-		switch net {
-		case "tcp":
-			return "udp"
-		case "tcp4":
-			return "udp4"
-		case "tcp6":
-			return "udp6"
-		}
-		return "<nil>"
-	}
-
-	for _, tt := range dualStackListenerTests {
-		if tt.wildcard && (testing.Short() || !*testExternal) {
-			continue
-		}
-		tt.net1 = toudpnet(tt.net1)
-		tt.net2 = toudpnet(tt.net2)
-		switch runtime.GOOS {
-		case "openbsd":
-			if tt.wildcard && differentWildcardAddr(tt.laddr1, tt.laddr2) {
-				tt.xerr = nil
-			}
-		}
-		l1, port := usableListenPacketPort(t, tt.net1, tt.laddr1)
-		laddr := tt.laddr1 + ":" + port
-		checkFirstListener(t, tt.net1, laddr, l1)
-		laddr = tt.laddr2 + ":" + port
-		l2, err := ListenPacket(tt.net2, laddr)
-		checkDualStackSecondListener(t, tt.net2, laddr, tt.xerr, err, l2)
-		l1.Close()
-	}
-}
-
-func usableListenPort(t *testing.T, net, laddr string) (l Listener, port string) {
-	var nladdr string
-	var err error
-	switch net {
-	default:
-		panic("usableListenPort net=" + net)
-	case "tcp", "tcp4", "tcp6":
-		l, err = Listen(net, laddr+":0")
-		if err != nil {
-			t.Fatalf("Probe Listen(%q, %q) failed: %v", net, laddr, err)
-		}
-		nladdr = l.(*TCPListener).Addr().String()
-	}
-	_, port, err = SplitHostPort(nladdr)
-	if err != nil {
-		t.Fatalf("SplitHostPort failed: %v", err)
-	}
-	return l, port
-}
-
-func usableListenPacketPort(t *testing.T, net, laddr string) (l PacketConn, port string) {
-	var nladdr string
-	var err error
-	switch net {
-	default:
-		panic("usableListenPacketPort net=" + net)
-	case "udp", "udp4", "udp6":
-		l, err = ListenPacket(net, laddr+":0")
-		if err != nil {
-			t.Fatalf("Probe ListenPacket(%q, %q) failed: %v", net, laddr, err)
-		}
-		nladdr = l.(*UDPConn).LocalAddr().String()
-	}
-	_, port, err = SplitHostPort(nladdr)
-	if err != nil {
-		t.Fatalf("SplitHostPort failed: %v", err)
-	}
-	return l, port
-}
-
-func differentWildcardAddr(i, j string) bool {
-	if (i == "" || i == "0.0.0.0" || i == "::ffff:0.0.0.0") && (j == "" || j == "0.0.0.0" || j == "::ffff:0.0.0.0") {
-		return false
-	}
-	if i == "[::]" && j == "[::]" {
-		return false
-	}
-	return true
-}
-
-func checkFirstListener(t *testing.T, net, laddr string, l interface{}) {
-	switch net {
-	case "tcp":
-		fd := l.(*TCPListener).fd
-		checkDualStackAddrFamily(t, net, laddr, fd)
-	case "tcp4":
-		fd := l.(*TCPListener).fd
-		if fd.family != syscall.AF_INET {
-			t.Fatalf("First Listen(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, syscall.AF_INET)
-		}
-	case "tcp6":
-		fd := l.(*TCPListener).fd
-		if fd.family != syscall.AF_INET6 {
-			t.Fatalf("First Listen(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, syscall.AF_INET6)
-		}
-	case "udp":
-		fd := l.(*UDPConn).fd
-		checkDualStackAddrFamily(t, net, laddr, fd)
-	case "udp4":
-		fd := l.(*UDPConn).fd
-		if fd.family != syscall.AF_INET {
-			t.Fatalf("First ListenPacket(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, syscall.AF_INET)
-		}
-	case "udp6":
-		fd := l.(*UDPConn).fd
-		if fd.family != syscall.AF_INET6 {
-			t.Fatalf("First ListenPacket(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, syscall.AF_INET6)
-		}
-	default:
-		t.Fatalf("Unexpected network: %q", net)
-	}
-}
-
-func checkSecondListener(t *testing.T, net, laddr string, err error, l interface{}) {
-	switch net {
-	case "tcp", "tcp4", "tcp6":
-		if err == nil {
-			l.(*TCPListener).Close()
-			t.Fatalf("Second Listen(%q, %q) should fail", net, laddr)
-		}
-	case "udp", "udp4", "udp6":
-		if err == nil {
-			l.(*UDPConn).Close()
-			t.Fatalf("Second ListenPacket(%q, %q) should fail", net, laddr)
-		}
-	default:
-		t.Fatalf("Unexpected network: %q", net)
-	}
-}
-
-func checkDualStackSecondListener(t *testing.T, net, laddr string, xerr, err error, l interface{}) {
-	switch net {
-	case "tcp", "tcp4", "tcp6":
-		if xerr == nil && err != nil || xerr != nil && err == nil {
-			t.Fatalf("Second Listen(%q, %q) returns %v, expected %v", net, laddr, err, xerr)
-		}
-		if err == nil {
-			l.(*TCPListener).Close()
-		}
-	case "udp", "udp4", "udp6":
-		if xerr == nil && err != nil || xerr != nil && err == nil {
-			t.Fatalf("Second ListenPacket(%q, %q) returns %v, expected %v", net, laddr, err, xerr)
-		}
-		if err == nil {
-			l.(*UDPConn).Close()
-		}
-	default:
-		t.Fatalf("Unexpected network: %q", net)
-	}
-}
-
-func checkDualStackAddrFamily(t *testing.T, net, laddr string, fd *netFD) {
-	switch a := fd.laddr.(type) {
-	case *TCPAddr:
-		// If a node under test supports both IPv6 capability
-		// and IPv6 IPv4-mapping capability, we can assume
-		// that the node listens on a wildcard address with an
-		// AF_INET6 socket.
-		if supportsIPv4map && fd.laddr.(*TCPAddr).isWildcard() {
-			if fd.family != syscall.AF_INET6 {
-				t.Fatalf("Listen(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, syscall.AF_INET6)
-			}
-		} else {
-			if fd.family != a.family() {
-				t.Fatalf("Listen(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, a.family())
-			}
-		}
-	case *UDPAddr:
-		// If a node under test supports both IPv6 capability
-		// and IPv6 IPv4-mapping capability, we can assume
-		// that the node listens on a wildcard address with an
-		// AF_INET6 socket.
-		if supportsIPv4map && fd.laddr.(*UDPAddr).isWildcard() {
-			if fd.family != syscall.AF_INET6 {
-				t.Fatalf("ListenPacket(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, syscall.AF_INET6)
-			}
-		} else {
-			if fd.family != a.family() {
-				t.Fatalf("ListenPacket(%q, %q) returns address family %v, expected %v", net, laddr, fd.family, a.family())
-			}
-		}
-	default:
-		t.Fatalf("Unexpected protocol address type: %T", a)
-	}
-}
-
-var prohibitionaryDialArgTests = []struct {
-	net  string
-	addr string
-}{
-	{"tcp6", "127.0.0.1"},
-	{"tcp6", "[::ffff:127.0.0.1]"},
-}
-
-func TestProhibitionaryDialArgs(t *testing.T) {
-	switch runtime.GOOS {
-	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
-	}
-	// This test requires both IPv6 and IPv6 IPv4-mapping functionality.
-	if !supportsIPv4map || testing.Short() || !*testExternal {
-		return
-	}
-
-	l, port := usableListenPort(t, "tcp", "[::]")
-	defer l.Close()
-
-	for _, tt := range prohibitionaryDialArgTests {
-		c, err := Dial(tt.net, tt.addr+":"+port)
-		if err == nil {
-			c.Close()
-			t.Fatalf("Dial(%q, %q) should fail", tt.net, tt.addr)
-		}
-	}
-}
-
-func TestWildWildcardListener(t *testing.T) {
-	switch runtime.GOOS {
-	case "plan9":
-		t.Skipf("skipping test on %q", runtime.GOOS)
-	}
-
-	if testing.Short() || !*testExternal {
-		t.Skip("skipping test to avoid external network")
-	}
-
-	defer func() {
-		if p := recover(); p != nil {
-			t.Fatalf("Listen, ListenPacket or protocol-specific Listen panicked: %v", p)
-		}
-	}()
-
-	if ln, err := Listen("tcp", ""); err == nil {
-		ln.Close()
-	}
-	if ln, err := ListenPacket("udp", ""); err == nil {
-		ln.Close()
-	}
-	if ln, err := ListenTCP("tcp", nil); err == nil {
-		ln.Close()
-	}
-	if ln, err := ListenUDP("udp", nil); err == nil {
-		ln.Close()
-	}
-	if ln, err := ListenIP("ip:icmp", nil); err == nil {
-		ln.Close()
-	}
-}
diff --git a/src/net/unix_test.go b/src/net/unix_test.go
index 1cdff39..358ff31 100644
--- a/src/net/unix_test.go
+++ b/src/net/unix_test.go
@@ -17,14 +17,18 @@ import (
 )
 
 func TestReadUnixgramWithUnnamedSocket(t *testing.T) {
+	if !testableNetwork("unixgram") {
+		t.Skip("unixgram test")
+	}
+
 	addr := testUnixAddr()
 	la, err := ResolveUnixAddr("unixgram", addr)
 	if err != nil {
-		t.Fatalf("ResolveUnixAddr failed: %v", err)
+		t.Fatal(err)
 	}
 	c, err := ListenUnixgram("unixgram", la)
 	if err != nil {
-		t.Fatalf("ListenUnixgram failed: %v", err)
+		t.Fatal(err)
 	}
 	defer func() {
 		c.Close()
@@ -37,13 +41,13 @@ func TestReadUnixgramWithUnnamedSocket(t *testing.T) {
 		defer func() { off <- true }()
 		s, err := syscall.Socket(syscall.AF_UNIX, syscall.SOCK_DGRAM, 0)
 		if err != nil {
-			t.Errorf("syscall.Socket failed: %v", err)
+			t.Error(err)
 			return
 		}
 		defer syscall.Close(s)
 		rsa := &syscall.SockaddrUnix{Name: addr}
 		if err := syscall.Sendto(s, data[:], 0, rsa); err != nil {
-			t.Errorf("syscall.Sendto failed: %v", err)
+			t.Error(err)
 			return
 		}
 	}()
@@ -53,69 +57,123 @@ func TestReadUnixgramWithUnnamedSocket(t *testing.T) {
 	c.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
 	n, from, err := c.ReadFrom(b)
 	if err != nil {
-		t.Fatalf("UnixConn.ReadFrom failed: %v", err)
+		t.Fatal(err)
 	}
 	if from != nil {
-		t.Fatalf("neighbor address is %v", from)
+		t.Fatalf("unexpected peer address: %v", from)
 	}
 	if !bytes.Equal(b[:n], data[:]) {
-		t.Fatalf("got %v, want %v", b[:n], data[:])
+		t.Fatalf("got %v; want %v", b[:n], data[:])
 	}
 }
 
-func TestReadUnixgramWithZeroBytesBuffer(t *testing.T) {
-	// issue 4352: Recvfrom failed with "address family not
-	// supported by protocol family" if zero-length buffer provided
+func TestUnixgramZeroBytePayload(t *testing.T) {
+	if !testableNetwork("unixgram") {
+		t.Skip("unixgram test")
+	}
 
-	addr := testUnixAddr()
-	la, err := ResolveUnixAddr("unixgram", addr)
+	c1, err := newLocalPacketListener("unixgram")
 	if err != nil {
-		t.Fatalf("ResolveUnixAddr failed: %v", err)
+		t.Fatal(err)
 	}
-	c, err := ListenUnixgram("unixgram", la)
+	defer os.Remove(c1.LocalAddr().String())
+	defer c1.Close()
+
+	c2, err := Dial("unixgram", c1.LocalAddr().String())
 	if err != nil {
-		t.Fatalf("ListenUnixgram failed: %v", err)
+		t.Fatal(err)
 	}
-	defer func() {
-		c.Close()
-		os.Remove(addr)
-	}()
+	defer os.Remove(c2.LocalAddr().String())
+	defer c2.Close()
 
-	off := make(chan bool)
-	go func() {
-		defer func() { off <- true }()
-		c, err := DialUnix("unixgram", nil, la)
+	for _, genericRead := range []bool{false, true} {
+		n, err := c2.Write(nil)
 		if err != nil {
-			t.Errorf("DialUnix failed: %v", err)
-			return
+			t.Fatal(err)
 		}
-		defer c.Close()
-		if _, err := c.Write([]byte{1, 2, 3, 4, 5}); err != nil {
-			t.Errorf("UnixConn.Write failed: %v", err)
-			return
+		if n != 0 {
+			t.Errorf("got %d; want 0", n)
 		}
-	}()
+		c1.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
+		var b [1]byte
+		var peer Addr
+		if genericRead {
+			_, err = c1.(Conn).Read(b[:])
+		} else {
+			_, peer, err = c1.ReadFrom(b[:])
+		}
+		switch err {
+		case nil: // ReadFrom succeeds
+			if peer != nil { // peer is connected-mode
+				t.Fatalf("unexpected peer address: %v", peer)
+			}
+		default: // Read may timeout, it depends on the platform
+			if nerr, ok := err.(Error); !ok || !nerr.Timeout() {
+				t.Fatal(err)
+			}
+		}
+	}
+}
 
-	<-off
-	c.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
-	_, from, err := c.ReadFrom(nil)
+func TestUnixgramZeroByteBuffer(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
+
+	c1, err := newLocalPacketListener("unixgram")
 	if err != nil {
-		t.Fatalf("UnixConn.ReadFrom failed: %v", err)
+		t.Fatal(err)
 	}
-	if from != nil {
-		t.Fatalf("neighbor address is %v", from)
+	defer os.Remove(c1.LocalAddr().String())
+	defer c1.Close()
+
+	c2, err := Dial("unixgram", c1.LocalAddr().String())
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.Remove(c2.LocalAddr().String())
+	defer c2.Close()
+
+	b := []byte("UNIXGRAM ZERO BYTE BUFFER TEST")
+	for _, genericRead := range []bool{false, true} {
+		n, err := c2.Write(b)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if n != len(b) {
+			t.Errorf("got %d; want %d", n, len(b))
+		}
+		c1.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
+		var peer Addr
+		if genericRead {
+			_, err = c1.(Conn).Read(nil)
+		} else {
+			_, peer, err = c1.ReadFrom(nil)
+		}
+		switch err {
+		case nil: // ReadFrom succeeds
+			if peer != nil { // peer is connected-mode
+				t.Fatalf("unexpected peer address: %v", peer)
+			}
+		default: // Read may timeout, it depends on the platform
+			if nerr, ok := err.(Error); !ok || !nerr.Timeout() {
+				t.Fatal(err)
+			}
+		}
 	}
 }
 
 func TestUnixgramAutobind(t *testing.T) {
 	if runtime.GOOS != "linux" {
-		t.Skip("skipping: autobind is linux only")
+		t.Skip("autobind is linux only")
 	}
 
 	laddr := &UnixAddr{Name: "", Net: "unixgram"}
 	c1, err := ListenUnixgram("unixgram", laddr)
 	if err != nil {
-		t.Fatalf("ListenUnixgram failed: %v", err)
+		t.Fatal(err)
 	}
 	defer c1.Close()
 
@@ -130,7 +188,7 @@ func TestUnixgramAutobind(t *testing.T) {
 
 	c2, err := DialUnix("unixgram", nil, autoAddr)
 	if err != nil {
-		t.Fatalf("DialUnix failed: %v", err)
+		t.Fatal(err)
 	}
 	defer c2.Close()
 
@@ -141,25 +199,30 @@ func TestUnixgramAutobind(t *testing.T) {
 
 func TestUnixAutobindClose(t *testing.T) {
 	if runtime.GOOS != "linux" {
-		t.Skip("skipping: autobind is linux only")
+		t.Skip("autobind is linux only")
 	}
+
 	laddr := &UnixAddr{Name: "", Net: "unix"}
 	ln, err := ListenUnix("unix", laddr)
 	if err != nil {
-		t.Fatalf("ListenUnix failed: %v", err)
+		t.Fatal(err)
 	}
 	ln.Close()
 }
 
 func TestUnixgramWrite(t *testing.T) {
+	if !testableNetwork("unixgram") {
+		t.Skip("unixgram test")
+	}
+
 	addr := testUnixAddr()
 	laddr, err := ResolveUnixAddr("unixgram", addr)
 	if err != nil {
-		t.Fatalf("ResolveUnixAddr failed: %v", err)
+		t.Fatal(err)
 	}
 	c, err := ListenPacket("unixgram", addr)
 	if err != nil {
-		t.Fatalf("ListenPacket failed: %v", err)
+		t.Fatal(err)
 	}
 	defer os.Remove(addr)
 	defer c.Close()
@@ -171,27 +234,28 @@ func TestUnixgramWrite(t *testing.T) {
 func testUnixgramWriteConn(t *testing.T, raddr *UnixAddr) {
 	c, err := Dial("unixgram", raddr.String())
 	if err != nil {
-		t.Fatalf("Dial failed: %v", err)
+		t.Fatal(err)
 	}
 	defer c.Close()
 
-	if _, err := c.(*UnixConn).WriteToUnix([]byte("Connection-oriented mode socket"), raddr); err == nil {
-		t.Fatal("WriteToUnix should fail")
+	b := []byte("CONNECTED-MODE SOCKET")
+	if _, err := c.(*UnixConn).WriteToUnix(b, raddr); err == nil {
+		t.Fatal("should fail")
 	} else if err.(*OpError).Err != ErrWriteToConnected {
-		t.Fatalf("WriteToUnix should fail as ErrWriteToConnected: %v", err)
+		t.Fatalf("should fail as ErrWriteToConnected: %v", err)
 	}
-	if _, err = c.(*UnixConn).WriteTo([]byte("Connection-oriented mode socket"), raddr); err == nil {
-		t.Fatal("WriteTo should fail")
+	if _, err = c.(*UnixConn).WriteTo(b, raddr); err == nil {
+		t.Fatal("should fail")
 	} else if err.(*OpError).Err != ErrWriteToConnected {
-		t.Fatalf("WriteTo should fail as ErrWriteToConnected: %v", err)
+		t.Fatalf("should fail as ErrWriteToConnected: %v", err)
 	}
-	if _, _, err = c.(*UnixConn).WriteMsgUnix([]byte("Connection-oriented mode socket"), nil, raddr); err == nil {
-		t.Fatal("WriteTo should fail")
+	if _, _, err = c.(*UnixConn).WriteMsgUnix(b, nil, raddr); err == nil {
+		t.Fatal("should fail")
 	} else if err.(*OpError).Err != ErrWriteToConnected {
-		t.Fatalf("WriteMsgUnix should fail as ErrWriteToConnected: %v", err)
+		t.Fatalf("should fail as ErrWriteToConnected: %v", err)
 	}
-	if _, err := c.Write([]byte("Connection-oriented mode socket")); err != nil {
-		t.Fatalf("Write failed: %v", err)
+	if _, err := c.Write(b); err != nil {
+		t.Fatal(err)
 	}
 }
 
@@ -199,52 +263,59 @@ func testUnixgramWritePacketConn(t *testing.T, raddr *UnixAddr) {
 	addr := testUnixAddr()
 	c, err := ListenPacket("unixgram", addr)
 	if err != nil {
-		t.Fatalf("ListenPacket failed: %v", err)
+		t.Fatal(err)
 	}
 	defer os.Remove(addr)
 	defer c.Close()
 
-	if _, err := c.(*UnixConn).WriteToUnix([]byte("Connectionless mode socket"), raddr); err != nil {
-		t.Fatalf("WriteToUnix failed: %v", err)
+	b := []byte("UNCONNECTED-MODE SOCKET")
+	if _, err := c.(*UnixConn).WriteToUnix(b, raddr); err != nil {
+		t.Fatal(err)
 	}
-	if _, err := c.WriteTo([]byte("Connectionless mode socket"), raddr); err != nil {
-		t.Fatalf("WriteTo failed: %v", err)
+	if _, err := c.WriteTo(b, raddr); err != nil {
+		t.Fatal(err)
 	}
-	if _, _, err := c.(*UnixConn).WriteMsgUnix([]byte("Connectionless mode socket"), nil, raddr); err != nil {
-		t.Fatalf("WriteMsgUnix failed: %v", err)
+	if _, _, err := c.(*UnixConn).WriteMsgUnix(b, nil, raddr); err != nil {
+		t.Fatal(err)
 	}
-	if _, err := c.(*UnixConn).Write([]byte("Connectionless mode socket")); err == nil {
-		t.Fatal("Write should fail")
+	if _, err := c.(*UnixConn).Write(b); err == nil {
+		t.Fatal("should fail")
 	}
 }
 
 func TestUnixConnLocalAndRemoteNames(t *testing.T) {
+	if !testableNetwork("unix") {
+		t.Skip("unix test")
+	}
+
+	handler := func(ls *localServer, ln Listener) {}
 	for _, laddr := range []string{"", testUnixAddr()} {
 		laddr := laddr
 		taddr := testUnixAddr()
 		ta, err := ResolveUnixAddr("unix", taddr)
 		if err != nil {
-			t.Fatalf("ResolveUnixAddr failed: %v", err)
+			t.Fatal(err)
 		}
 		ln, err := ListenUnix("unix", ta)
 		if err != nil {
-			t.Fatalf("ListenUnix failed: %v", err)
+			t.Fatal(err)
+		}
+		ls, err := (&streamListener{Listener: ln}).newLocalServer()
+		if err != nil {
+			t.Fatal(err)
+		}
+		defer ls.teardown()
+		if err := ls.buildup(handler); err != nil {
+			t.Fatal(err)
 		}
-		defer func() {
-			ln.Close()
-			os.Remove(taddr)
-		}()
-
-		done := make(chan int)
-		go transponder(t, ln, done)
 
 		la, err := ResolveUnixAddr("unix", laddr)
 		if err != nil {
-			t.Fatalf("ResolveUnixAddr failed: %v", err)
+			t.Fatal(err)
 		}
 		c, err := DialUnix("unix", la, ta)
 		if err != nil {
-			t.Fatalf("DialUnix failed: %v", err)
+			t.Fatal(err)
 		}
 		defer func() {
 			c.Close()
@@ -253,7 +324,7 @@ func TestUnixConnLocalAndRemoteNames(t *testing.T) {
 			}
 		}()
 		if _, err := c.Write([]byte("UNIXCONN LOCAL AND REMOTE NAME TEST")); err != nil {
-			t.Fatalf("UnixConn.Write failed: %v", err)
+			t.Fatal(err)
 		}
 
 		switch runtime.GOOS {
@@ -272,22 +343,24 @@ func TestUnixConnLocalAndRemoteNames(t *testing.T) {
 				t.Fatalf("got %#v, expected %#v", ca.got, ca.want)
 			}
 		}
-
-		<-done
 	}
 }
 
 func TestUnixgramConnLocalAndRemoteNames(t *testing.T) {
+	if !testableNetwork("unixgram") {
+		t.Skip("unixgram test")
+	}
+
 	for _, laddr := range []string{"", testUnixAddr()} {
 		laddr := laddr
 		taddr := testUnixAddr()
 		ta, err := ResolveUnixAddr("unixgram", taddr)
 		if err != nil {
-			t.Fatalf("ResolveUnixAddr failed: %v", err)
+			t.Fatal(err)
 		}
 		c1, err := ListenUnixgram("unixgram", ta)
 		if err != nil {
-			t.Fatalf("ListenUnixgram failed: %v", err)
+			t.Fatal(err)
 		}
 		defer func() {
 			c1.Close()
@@ -297,12 +370,12 @@ func TestUnixgramConnLocalAndRemoteNames(t *testing.T) {
 		var la *UnixAddr
 		if laddr != "" {
 			if la, err = ResolveUnixAddr("unixgram", laddr); err != nil {
-				t.Fatalf("ResolveUnixAddr failed: %v", err)
+				t.Fatal(err)
 			}
 		}
 		c2, err := DialUnix("unixgram", la, ta)
 		if err != nil {
-			t.Fatalf("DialUnix failed: %v", err)
+			t.Fatal(err)
 		}
 		defer func() {
 			c2.Close()
@@ -326,8 +399,33 @@ func TestUnixgramConnLocalAndRemoteNames(t *testing.T) {
 		}
 		for _, ca := range connAddrs {
 			if !reflect.DeepEqual(ca.got, ca.want) {
-				t.Fatalf("got %#v, expected %#v", ca.got, ca.want)
+				t.Fatalf("got %#v; want %#v", ca.got, ca.want)
 			}
 		}
 	}
 }
+
+// forceGoDNS forces the resolver configuration to use the pure Go resolver
+// and returns a fixup function to restore the old settings.
+func forceGoDNS() func() {
+	c := systemConf()
+	oldGo := c.netGo
+	oldCgo := c.netCgo
+	fixup := func() {
+		c.netGo = oldGo
+		c.netCgo = oldCgo
+	}
+	c.netGo = true
+	c.netCgo = false
+	return fixup
+}
+
+// forceCgoDNS forces the resolver configuration to use the cgo resolver
+// and returns true to indicate that it did so.
+// (On non-Unix systems forceCgoDNS returns false.)
+func forceCgoDNS() bool {
+	c := systemConf()
+	c.netGo = false
+	c.netCgo = true
+	return true
+}
diff --git a/src/net/unixsock.go b/src/net/unixsock.go
index 8595584..eb91d0d 100644
--- a/src/net/unixsock.go
+++ b/src/net/unixsock.go
@@ -23,7 +23,11 @@ func (a *UnixAddr) String() string {
 	return a.Name
 }
 
-func (a *UnixAddr) toAddr() Addr {
+func (a *UnixAddr) isWildcard() bool {
+	return a == nil || a.Name == ""
+}
+
+func (a *UnixAddr) opAddr() Addr {
 	if a == nil {
 		return nil
 	}
diff --git a/src/net/unixsock_plan9.go b/src/net/unixsock_plan9.go
index c60c1d8..84b6b60 100644
--- a/src/net/unixsock_plan9.go
+++ b/src/net/unixsock_plan9.go
@@ -24,12 +24,12 @@ type UnixConn struct {
 // Timeout() == true after a fixed time limit; see SetDeadline and
 // SetReadDeadline.
 func (c *UnixConn) ReadFromUnix(b []byte) (int, *UnixAddr, error) {
-	return 0, nil, syscall.EPLAN9
+	return 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
 }
 
 // ReadFrom implements the PacketConn ReadFrom method.
 func (c *UnixConn) ReadFrom(b []byte) (int, Addr, error) {
-	return 0, nil, syscall.EPLAN9
+	return 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
 }
 
 // ReadMsgUnix reads a packet from c, copying the payload into b and
@@ -37,7 +37,7 @@ func (c *UnixConn) ReadFrom(b []byte) (int, Addr, error) {
 // bytes copied into b, the number of bytes copied into oob, the flags
 // that were set on the packet, and the source address of the packet.
 func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAddr, err error) {
-	return 0, 0, 0, nil, syscall.EPLAN9
+	return 0, 0, 0, nil, &OpError{Op: "read", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
 }
 
 // WriteToUnix writes a packet to addr via c, copying the payload from b.
@@ -47,31 +47,31 @@ func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAdd
 // SetWriteDeadline.  On packet-oriented connections, write timeouts
 // are rare.
 func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (int, error) {
-	return 0, syscall.EPLAN9
+	return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr.opAddr(), Err: syscall.EPLAN9}
 }
 
 // WriteTo implements the PacketConn WriteTo method.
 func (c *UnixConn) WriteTo(b []byte, addr Addr) (int, error) {
-	return 0, syscall.EPLAN9
+	return 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr, Err: syscall.EPLAN9}
 }
 
 // WriteMsgUnix writes a packet to addr via c, copying the payload
 // from b and the associated out-of-band data from oob.  It returns
 // the number of payload and out-of-band bytes written.
 func (c *UnixConn) WriteMsgUnix(b, oob []byte, addr *UnixAddr) (n, oobn int, err error) {
-	return 0, 0, syscall.EPLAN9
+	return 0, 0, &OpError{Op: "write", Net: c.fd.dir, Source: c.fd.laddr, Addr: addr.opAddr(), Err: syscall.EPLAN9}
 }
 
 // CloseRead shuts down the reading side of the Unix domain connection.
 // Most callers should just use Close.
 func (c *UnixConn) CloseRead() error {
-	return syscall.EPLAN9
+	return &OpError{Op: "close", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
 }
 
 // CloseWrite shuts down the writing side of the Unix domain connection.
 // Most callers should just use Close.
 func (c *UnixConn) CloseWrite() error {
-	return syscall.EPLAN9
+	return &OpError{Op: "close", Net: c.fd.dir, Source: c.fd.laddr, Addr: c.fd.raddr, Err: syscall.EPLAN9}
 }
 
 // DialUnix connects to the remote address raddr on the network net,
@@ -82,45 +82,49 @@ func DialUnix(net string, laddr, raddr *UnixAddr) (*UnixConn, error) {
 }
 
 func dialUnix(net string, laddr, raddr *UnixAddr, deadline time.Time) (*UnixConn, error) {
-	return nil, syscall.EPLAN9
+	return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: syscall.EPLAN9}
 }
 
 // UnixListener is a Unix domain socket listener.  Clients should
 // typically use variables of type Listener instead of assuming Unix
 // domain sockets.
-type UnixListener struct{}
+type UnixListener struct {
+	fd *netFD
+}
 
 // ListenUnix announces on the Unix domain socket laddr and returns a
 // Unix listener.  The network net must be "unix" or "unixpacket".
 func ListenUnix(net string, laddr *UnixAddr) (*UnixListener, error) {
-	return nil, syscall.EPLAN9
+	return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: syscall.EPLAN9}
 }
 
 // AcceptUnix accepts the next incoming call and returns the new
 // connection.
 func (l *UnixListener) AcceptUnix() (*UnixConn, error) {
-	return nil, syscall.EPLAN9
+	return nil, &OpError{Op: "accept", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: syscall.EPLAN9}
 }
 
 // Accept implements the Accept method in the Listener interface; it
 // waits for the next call and returns a generic Conn.
 func (l *UnixListener) Accept() (Conn, error) {
-	return nil, syscall.EPLAN9
+	return nil, &OpError{Op: "accept", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: syscall.EPLAN9}
 }
 
 // Close stops listening on the Unix address.  Already accepted
 // connections are not closed.
 func (l *UnixListener) Close() error {
-	return syscall.EPLAN9
+	return &OpError{Op: "close", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: syscall.EPLAN9}
 }
 
 // Addr returns the listener's network address.
+// The Addr returned is shared by all invocations of Addr, so
+// do not modify it.
 func (l *UnixListener) Addr() Addr { return nil }
 
 // SetDeadline sets the deadline associated with the listener.
 // A zero time value disables the deadline.
 func (l *UnixListener) SetDeadline(t time.Time) error {
-	return syscall.EPLAN9
+	return &OpError{Op: "set", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: syscall.EPLAN9}
 }
 
 // File returns a copy of the underlying os.File, set to blocking
@@ -131,7 +135,7 @@ func (l *UnixListener) SetDeadline(t time.Time) error {
 // connection's.  Attempting to change properties of the original
 // using this duplicate may or may not have the desired effect.
 func (l *UnixListener) File() (*os.File, error) {
-	return nil, syscall.EPLAN9
+	return nil, &OpError{Op: "file", Net: l.fd.dir, Source: nil, Addr: l.fd.laddr, Err: syscall.EPLAN9}
 }
 
 // ListenUnixgram listens for incoming Unix datagram packets addressed
@@ -139,5 +143,5 @@ func (l *UnixListener) File() (*os.File, error) {
 // The returned connection's ReadFrom and WriteTo methods can be used
 // to receive and send packets with per-packet addressing.
 func ListenUnixgram(net string, laddr *UnixAddr) (*UnixConn, error) {
-	return nil, syscall.EPLAN9
+	return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: syscall.EPLAN9}
 }
diff --git a/src/net/unixsock_posix.go b/src/net/unixsock_posix.go
index 3c2e78b..351d9b3 100644
--- a/src/net/unixsock_posix.go
+++ b/src/net/unixsock_posix.go
@@ -87,10 +87,6 @@ func (a *UnixAddr) family() int {
 	return syscall.AF_UNIX
 }
 
-func (a *UnixAddr) isWildcard() bool {
-	return a == nil || a.Name == ""
-}
-
 func (a *UnixAddr) sockaddr(family int) (syscall.Sockaddr, error) {
 	if a == nil {
 		return nil, nil
@@ -113,10 +109,11 @@ func newUnixConn(fd *netFD) *UnixConn { return &UnixConn{conn{fd}} }
 // ReadFromUnix can be made to time out and return an error with
 // Timeout() == true after a fixed time limit; see SetDeadline and
 // SetReadDeadline.
-func (c *UnixConn) ReadFromUnix(b []byte) (n int, addr *UnixAddr, err error) {
+func (c *UnixConn) ReadFromUnix(b []byte) (int, *UnixAddr, error) {
 	if !c.ok() {
 		return 0, nil, syscall.EINVAL
 	}
+	var addr *UnixAddr
 	n, sa, err := c.fd.readFrom(b)
 	switch sa := sa.(type) {
 	case *syscall.SockaddrUnix:
@@ -124,7 +121,10 @@ func (c *UnixConn) ReadFromUnix(b []byte) (n int, addr *UnixAddr, err error) {
 			addr = &UnixAddr{Name: sa.Name, Net: sotypeToNet(c.fd.sotype)}
 		}
 	}
-	return
+	if err != nil {
+		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return n, addr, err
 }
 
 // ReadFrom implements the PacketConn ReadFrom method.
@@ -133,7 +133,10 @@ func (c *UnixConn) ReadFrom(b []byte) (int, Addr, error) {
 		return 0, nil, syscall.EINVAL
 	}
 	n, addr, err := c.ReadFromUnix(b)
-	return n, addr.toAddr(), err
+	if addr == nil {
+		return n, nil, err
+	}
+	return n, addr, err
 }
 
 // ReadMsgUnix reads a packet from c, copying the payload into b and
@@ -151,6 +154,9 @@ func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAdd
 			addr = &UnixAddr{Name: sa.Name, Net: sotypeToNet(c.fd.sotype)}
 		}
 	}
+	if err != nil {
+		err = &OpError{Op: "read", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
 	return
 }
 
@@ -160,21 +166,25 @@ func (c *UnixConn) ReadMsgUnix(b, oob []byte) (n, oobn, flags int, addr *UnixAdd
 // Timeout() == true after a fixed time limit; see SetDeadline and
 // SetWriteDeadline.  On packet-oriented connections, write timeouts
 // are rare.
-func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (n int, err error) {
+func (c *UnixConn) WriteToUnix(b []byte, addr *UnixAddr) (int, error) {
 	if !c.ok() {
 		return 0, syscall.EINVAL
 	}
 	if c.fd.isConnected {
-		return 0, &OpError{Op: "write", Net: c.fd.net, Addr: addr, Err: ErrWriteToConnected}
+		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: ErrWriteToConnected}
 	}
 	if addr == nil {
-		return 0, &OpError{Op: "write", Net: c.fd.net, Addr: nil, Err: errMissingAddress}
+		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: nil, Err: errMissingAddress}
 	}
 	if addr.Net != sotypeToNet(c.fd.sotype) {
-		return 0, syscall.EAFNOSUPPORT
+		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: syscall.EAFNOSUPPORT}
 	}
 	sa := &syscall.SockaddrUnix{Name: addr.Name}
-	return c.fd.writeTo(b, sa)
+	n, err := c.fd.writeTo(b, sa)
+	if err != nil {
+		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
+	}
+	return n, err
 }
 
 // WriteTo implements the PacketConn WriteTo method.
@@ -184,7 +194,7 @@ func (c *UnixConn) WriteTo(b []byte, addr Addr) (n int, err error) {
 	}
 	a, ok := addr.(*UnixAddr)
 	if !ok {
-		return 0, &OpError{"write", c.fd.net, addr, syscall.EINVAL}
+		return 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr, Err: syscall.EINVAL}
 	}
 	return c.WriteToUnix(b, a)
 }
@@ -197,16 +207,20 @@ func (c *UnixConn) WriteMsgUnix(b, oob []byte, addr *UnixAddr) (n, oobn int, err
 		return 0, 0, syscall.EINVAL
 	}
 	if c.fd.sotype == syscall.SOCK_DGRAM && c.fd.isConnected {
-		return 0, 0, &OpError{Op: "write", Net: c.fd.net, Addr: addr, Err: ErrWriteToConnected}
+		return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: ErrWriteToConnected}
 	}
+	var sa syscall.Sockaddr
 	if addr != nil {
 		if addr.Net != sotypeToNet(c.fd.sotype) {
-			return 0, 0, syscall.EAFNOSUPPORT
+			return 0, 0, &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: syscall.EAFNOSUPPORT}
 		}
-		sa := &syscall.SockaddrUnix{Name: addr.Name}
-		return c.fd.writeMsg(b, oob, sa)
+		sa = &syscall.SockaddrUnix{Name: addr.Name}
 	}
-	return c.fd.writeMsg(b, oob, nil)
+	n, oobn, err = c.fd.writeMsg(b, oob, sa)
+	if err != nil {
+		err = &OpError{Op: "write", Net: c.fd.net, Source: c.fd.laddr, Addr: addr.opAddr(), Err: err}
+	}
+	return
 }
 
 // CloseRead shuts down the reading side of the Unix domain connection.
@@ -215,7 +229,11 @@ func (c *UnixConn) CloseRead() error {
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	return c.fd.closeRead()
+	err := c.fd.closeRead()
+	if err != nil {
+		err = &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return err
 }
 
 // CloseWrite shuts down the writing side of the Unix domain connection.
@@ -224,7 +242,11 @@ func (c *UnixConn) CloseWrite() error {
 	if !c.ok() {
 		return syscall.EINVAL
 	}
-	return c.fd.closeWrite()
+	err := c.fd.closeWrite()
+	if err != nil {
+		err = &OpError{Op: "close", Net: c.fd.net, Source: c.fd.laddr, Addr: c.fd.raddr, Err: err}
+	}
+	return err
 }
 
 // DialUnix connects to the remote address raddr on the network net,
@@ -234,7 +256,7 @@ func DialUnix(net string, laddr, raddr *UnixAddr) (*UnixConn, error) {
 	switch net {
 	case "unix", "unixgram", "unixpacket":
 	default:
-		return nil, &OpError{Op: "dial", Net: net, Addr: raddr, Err: UnknownNetworkError(net)}
+		return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: UnknownNetworkError(net)}
 	}
 	return dialUnix(net, laddr, raddr, noDeadline)
 }
@@ -242,7 +264,7 @@ func DialUnix(net string, laddr, raddr *UnixAddr) (*UnixConn, error) {
 func dialUnix(net string, laddr, raddr *UnixAddr, deadline time.Time) (*UnixConn, error) {
 	fd, err := unixSocket(net, laddr, raddr, "dial", deadline)
 	if err != nil {
-		return nil, &OpError{Op: "dial", Net: net, Addr: raddr, Err: err}
+		return nil, &OpError{Op: "dial", Net: net, Source: laddr.opAddr(), Addr: raddr.opAddr(), Err: err}
 	}
 	return newUnixConn(fd), nil
 }
@@ -261,16 +283,16 @@ func ListenUnix(net string, laddr *UnixAddr) (*UnixListener, error) {
 	switch net {
 	case "unix", "unixpacket":
 	default:
-		return nil, &OpError{Op: "listen", Net: net, Addr: laddr, Err: UnknownNetworkError(net)}
+		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(net)}
 	}
 	if laddr == nil {
-		return nil, &OpError{Op: "listen", Net: net, Addr: nil, Err: errMissingAddress}
+		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: errMissingAddress}
 	}
 	fd, err := unixSocket(net, laddr, nil, "listen", noDeadline)
 	if err != nil {
-		return nil, &OpError{Op: "listen", Net: net, Addr: laddr, Err: err}
+		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: err}
 	}
-	return &UnixListener{fd, fd.laddr.String()}, nil
+	return &UnixListener{fd: fd, path: fd.laddr.String()}, nil
 }
 
 // AcceptUnix accepts the next incoming call and returns the new
@@ -281,10 +303,9 @@ func (l *UnixListener) AcceptUnix() (*UnixConn, error) {
 	}
 	fd, err := l.fd.accept()
 	if err != nil {
-		return nil, err
+		return nil, &OpError{Op: "accept", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
 	}
-	c := newUnixConn(fd)
-	return c, nil
+	return newUnixConn(fd), nil
 }
 
 // Accept implements the Accept method in the Listener interface; it
@@ -317,19 +338,28 @@ func (l *UnixListener) Close() error {
 	if l.path[0] != '@' {
 		syscall.Unlink(l.path)
 	}
-	return l.fd.Close()
+	err := l.fd.Close()
+	if err != nil {
+		err = &OpError{Op: "close", Net: l.fd.net, Source: l.fd.laddr, Addr: l.fd.raddr, Err: err}
+	}
+	return err
 }
 
 // Addr returns the listener's network address.
+// The Addr returned is shared by all invocations of Addr, so
+// do not modify it.
 func (l *UnixListener) Addr() Addr { return l.fd.laddr }
 
 // SetDeadline sets the deadline associated with the listener.
 // A zero time value disables the deadline.
-func (l *UnixListener) SetDeadline(t time.Time) (err error) {
+func (l *UnixListener) SetDeadline(t time.Time) error {
 	if l == nil || l.fd == nil {
 		return syscall.EINVAL
 	}
-	return l.fd.setDeadline(t)
+	if err := l.fd.setDeadline(t); err != nil {
+		return &OpError{Op: "set", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
+	}
+	return nil
 }
 
 // File returns a copy of the underlying os.File, set to blocking
@@ -339,7 +369,13 @@ func (l *UnixListener) SetDeadline(t time.Time) (err error) {
 // The returned os.File's file descriptor is different from the
 // connection's.  Attempting to change properties of the original
 // using this duplicate may or may not have the desired effect.
-func (l *UnixListener) File() (f *os.File, err error) { return l.fd.dup() }
+func (l *UnixListener) File() (f *os.File, err error) {
+	f, err = l.fd.dup()
+	if err != nil {
+		err = &OpError{Op: "file", Net: l.fd.net, Source: nil, Addr: l.fd.laddr, Err: err}
+	}
+	return
+}
 
 // ListenUnixgram listens for incoming Unix datagram packets addressed
 // to the local address laddr.  The network net must be "unixgram".
@@ -349,14 +385,14 @@ func ListenUnixgram(net string, laddr *UnixAddr) (*UnixConn, error) {
 	switch net {
 	case "unixgram":
 	default:
-		return nil, &OpError{Op: "listen", Net: net, Addr: laddr, Err: UnknownNetworkError(net)}
+		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: UnknownNetworkError(net)}
 	}
 	if laddr == nil {
-		return nil, &OpError{Op: "listen", Net: net, Addr: nil, Err: errMissingAddress}
+		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: nil, Err: errMissingAddress}
 	}
 	fd, err := unixSocket(net, laddr, nil, "listen", noDeadline)
 	if err != nil {
-		return nil, &OpError{Op: "listen", Net: net, Addr: laddr, Err: err}
+		return nil, &OpError{Op: "listen", Net: net, Source: nil, Addr: laddr.opAddr(), Err: err}
 	}
 	return newUnixConn(fd), nil
 }
diff --git a/src/net/url/example_test.go b/src/net/url/example_test.go
index e55c1aa..645de2e 100644
--- a/src/net/url/example_test.go
+++ b/src/net/url/example_test.go
@@ -43,11 +43,26 @@ func ExampleURL() {
 	// Output: https://google.com/search?q=golang
 }
 
+func ExampleURL_roundtrip() {
+	// Parse + String preserve the original encoding.
+	u, err := url.Parse("https://example.com/foo%2fbar")
+	if err != nil {
+		log.Fatal(err)
+	}
+	fmt.Println(u.Path)
+	fmt.Println(u.RawPath)
+	fmt.Println(u.String())
+	// Output:
+	// /foo/bar
+	// /foo%2fbar
+	// https://example.com/foo%2fbar
+}
+
 func ExampleURL_opaque() {
 	// Sending a literal '%' in an HTTP request's Path
 	req := &http.Request{
 		Method: "GET",
-		Host:   "example.com", // takes precendence over URL.Host
+		Host:   "example.com", // takes precedence over URL.Host
 		URL: &url.URL{
 			Host:   "ignored",
 			Scheme: "https",
@@ -69,3 +84,17 @@ func ExampleURL_opaque() {
 	// Accept-Encoding: gzip
 	//
 }
+
+func ExampleURL_ResolveReference() {
+	u, err := url.Parse("../../..//search?q=dotnet")
+	if err != nil {
+		log.Fatal(err)
+	}
+	base, err := url.Parse("http://example.com/directory/")
+	if err != nil {
+		log.Fatal(err)
+	}
+	fmt.Println(base.ResolveReference(u))
+	// Output:
+	// http://example.com/search?q=dotnet
+}
diff --git a/src/net/url/url.go b/src/net/url/url.go
index f167408..8ffad66 100644
--- a/src/net/url/url.go
+++ b/src/net/url/url.go
@@ -9,6 +9,7 @@ package url
 import (
 	"bytes"
 	"errors"
+	"fmt"
 	"sort"
 	"strconv"
 	"strings"
@@ -51,6 +52,7 @@ type encoding int
 
 const (
 	encodePath encoding = 1 + iota
+	encodeHost
 	encodeUserPassword
 	encodeQueryComponent
 	encodeFragment
@@ -64,12 +66,27 @@ func (e EscapeError) Error() string {
 
 // Return true if the specified character should be escaped when
 // appearing in a URL string, according to RFC 3986.
+//
+// Please be informed that for now shouldEscape does not check all
+// reserved characters correctly. See golang.org/issue/5684.
 func shouldEscape(c byte, mode encoding) bool {
 	// §2.3 Unreserved characters (alphanum)
 	if 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' {
 		return false
 	}
 
+	if mode == encodeHost {
+		// §3.2.2 Host allows
+		//	sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "="
+		// as part of reg-name.
+		// We add : because we include :port as part of host.
+		// We add [ ] because we include [ipv6]:port as part of host
+		switch c {
+		case '!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=', ':', '[', ']':
+			return false
+		}
+	}
+
 	switch c {
 	case '-', '_', '.', '~': // §2.3 Unreserved characters (mark)
 		return false
@@ -127,7 +144,7 @@ func unescape(s string, mode encoding) (string, error) {
 			if i+2 >= len(s) || !ishex(s[i+1]) || !ishex(s[i+2]) {
 				s = s[i:]
 				if len(s) > 3 {
-					s = s[0:3]
+					s = s[:3]
 				}
 				return "", EscapeError(s)
 			}
@@ -224,16 +241,24 @@ func escape(s string, mode encoding) string {
 // Note that the Path field is stored in decoded form: /%47%6f%2f becomes /Go/.
 // A consequence is that it is impossible to tell which slashes in the Path were
 // slashes in the raw URL and which were %2f. This distinction is rarely important,
-// but when it is a client must use other routines to parse the raw URL or construct
-// the parsed URL. For example, an HTTP server can consult req.RequestURI, and
-// an HTTP client can use URL{Host: "example.com", Opaque: "//example.com/Go%2f"}
-// instead of URL{Host: "example.com", Path: "/Go/"}.
+// but when it is, code must not use Path directly.
+//
+// Go 1.5 introduced the RawPath field to hold the encoded form of Path.
+// The Parse function sets both Path and RawPath in the URL it returns,
+// and URL's String method uses RawPath if it is a valid encoding of Path,
+// by calling the EncodedPath method.
+//
+// In earlier versions of Go, the more indirect workarounds were that an
+// HTTP server could consult req.RequestURI and an HTTP client could
+// construct a URL struct directly and set the Opaque field instead of Path.
+// These still work as well.
 type URL struct {
 	Scheme   string
 	Opaque   string    // encoded opaque data
 	User     *Userinfo // username and password information
 	Host     string    // host or host:port
 	Path     string
+	RawPath  string // encoded path hint (Go 1.5 and later only; see EscapedPath method)
 	RawQuery string // encoded query values, without '?'
 	Fragment string // fragment for references, without '#'
 }
@@ -305,7 +330,7 @@ func getscheme(rawurl string) (scheme, path string, err error) {
 			if i == 0 {
 				return "", "", errors.New("missing protocol scheme")
 			}
-			return rawurl[0:i], rawurl[i+1:], nil
+			return rawurl[:i], rawurl[i+1:], nil
 		default:
 			// we have encountered an invalid character,
 			// so there is no valid scheme
@@ -324,9 +349,9 @@ func split(s string, c string, cutc bool) (string, string) {
 		return s, ""
 	}
 	if cutc {
-		return s[0:i], s[i+len(c):]
+		return s[:i], s[i+len(c):]
 	}
-	return s[0:i], s[i:]
+	return s[:i], s[i:]
 }
 
 // Parse parses rawurl into a URL structure.
@@ -401,14 +426,17 @@ func parse(rawurl string, viaRequest bool) (url *URL, err error) {
 		if err != nil {
 			goto Error
 		}
-		if strings.Contains(url.Host, "%") {
-			err = errors.New("hexadecimal escape in host")
-			goto Error
-		}
 	}
 	if url.Path, err = unescape(rest, encodePath); err != nil {
 		goto Error
 	}
+	// RawPath is a hint as to the encoding of Path to use
+	// in url.EncodedPath. If that method already gets the
+	// right answer without RawPath, leave it empty.
+	// This will help make sure that people don't rely on it in general.
+	if url.EscapedPath() != rest && validEncodedPath(rest) {
+		url.RawPath = rest
+	}
 	return url, nil
 
 Error:
@@ -418,36 +446,157 @@ Error:
 func parseAuthority(authority string) (user *Userinfo, host string, err error) {
 	i := strings.LastIndex(authority, "@")
 	if i < 0 {
-		host = authority
-		return
+		host, err = parseHost(authority)
+	} else {
+		host, err = parseHost(authority[i+1:])
 	}
-	userinfo, host := authority[:i], authority[i+1:]
+	if err != nil {
+		return nil, "", err
+	}
+	if i < 0 {
+		return nil, host, nil
+	}
+	userinfo := authority[:i]
 	if strings.Index(userinfo, ":") < 0 {
 		if userinfo, err = unescape(userinfo, encodeUserPassword); err != nil {
-			return
+			return nil, "", err
 		}
 		user = User(userinfo)
 	} else {
 		username, password := split(userinfo, ":", true)
 		if username, err = unescape(username, encodeUserPassword); err != nil {
-			return
+			return nil, "", err
 		}
 		if password, err = unescape(password, encodeUserPassword); err != nil {
-			return
+			return nil, "", err
 		}
 		user = UserPassword(username, password)
 	}
-	return
+	return user, host, nil
+}
+
+// parseHost parses host as an authority without user
+// information. That is, as host[:port].
+func parseHost(host string) (string, error) {
+	litOrName := host
+	if strings.HasPrefix(host, "[") {
+		// Parse an IP-Literal in RFC 3986 and RFC 6874.
+		// E.g., "[fe80::1], "[fe80::1%25en0]"
+		//
+		// RFC 4007 defines "%" as a delimiter character in
+		// the textual representation of IPv6 addresses.
+		// Per RFC 6874, in URIs that "%" is encoded as "%25".
+		i := strings.LastIndex(host, "]")
+		if i < 0 {
+			return "", errors.New("missing ']' in host")
+		}
+		colonPort := host[i+1:]
+		if !validOptionalPort(colonPort) {
+			return "", fmt.Errorf("invalid port %q after host", colonPort)
+		}
+		// Parse a host subcomponent without a ZoneID in RFC
+		// 6874 because the ZoneID is allowed to use the
+		// percent encoded form.
+		j := strings.Index(host[:i], "%25")
+		if j < 0 {
+			litOrName = host[1:i]
+		} else {
+			litOrName = host[1:j]
+		}
+	}
+
+	// A URI containing an IP-Literal without a ZoneID or
+	// IPv4address in RFC 3986 and RFC 6847 must not be
+	// percent-encoded.
+	//
+	// A URI containing a DNS registered name in RFC 3986 is
+	// allowed to be percent-encoded, though we don't use it for
+	// now to avoid messing up with the gap between allowed
+	// characters in URI and allowed characters in DNS.
+	// See golang.org/issue/7991.
+	if strings.Contains(litOrName, "%") {
+		return "", errors.New("percent-encoded characters in host")
+	}
+	var err error
+	if host, err = unescape(host, encodeHost); err != nil {
+		return "", err
+	}
+	return host, nil
+}
+
+// EscapedPath returns the escaped form of u.Path.
+// In general there are multiple possible escaped forms of any path.
+// EscapedPath returns u.RawPath when it is a valid escaping of u.Path.
+// Otherwise EscapedPath ignores u.RawPath and computes an escaped
+// form on its own.
+// The String and RequestURI methods use EscapedPath to construct
+// their results.
+// In general, code should call EscapedPath instead of
+// reading u.RawPath directly.
+func (u *URL) EscapedPath() string {
+	if u.RawPath != "" && validEncodedPath(u.RawPath) {
+		p, err := unescape(u.RawPath, encodePath)
+		if err == nil && p == u.Path {
+			return u.RawPath
+		}
+	}
+	if u.Path == "*" {
+		return "*" // don't escape (Issue 11202)
+	}
+	return escape(u.Path, encodePath)
+}
+
+// validEncodedPath reports whether s is a valid encoded path.
+// It must not contain any bytes that require escaping during path encoding.
+func validEncodedPath(s string) bool {
+	for i := 0; i < len(s); i++ {
+		// RFC 3986, Appendix A.
+		// pchar = unreserved / pct-encoded / sub-delims / ":" / "@".
+		// shouldEscape is not quite compliant with the RFC,
+		// so we check the sub-delims ourselves and let
+		// shouldEscape handle the others.
+		switch s[i] {
+		case '!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=', ':', '@':
+			// ok
+		case '[', ']':
+			// ok - not specified in RFC 3986 but left alone by modern browsers
+		case '%':
+			// ok - percent encoded, will decode
+		default:
+			if shouldEscape(s[i], encodePath) {
+				return false
+			}
+		}
+	}
+	return true
+}
+
+// validOptionalPort reports whether port is either an empty string
+// or matches /^:\d+$/
+func validOptionalPort(port string) bool {
+	if port == "" {
+		return true
+	}
+	if port[0] != ':' || len(port) == 1 {
+		return false
+	}
+	for _, b := range port[1:] {
+		if b < '0' || b > '9' {
+			return false
+		}
+	}
+	return true
 }
 
 // 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;
 // otherwise it uses the second form.
+// To obtain the path, String uses u.EncodedPath().
 //
 // In the second form, the following rules apply:
 //	- if u.Scheme is empty, scheme: is omitted.
@@ -475,13 +624,14 @@ func (u *URL) String() string {
 				buf.WriteByte('@')
 			}
 			if h := u.Host; h != "" {
-				buf.WriteString(h)
+				buf.WriteString(escape(h, encodeHost))
 			}
 		}
-		if u.Path != "" && u.Path[0] != '/' && u.Host != "" {
+		path := u.EscapedPath()
+		if path != "" && path[0] != '/' && u.Host != "" {
 			buf.WriteByte('/')
 		}
-		buf.WriteString(escape(u.Path, encodePath))
+		buf.WriteString(path)
 	}
 	if u.RawQuery != "" {
 		buf.WriteByte('?')
@@ -639,7 +789,7 @@ func resolvePath(base, ref string) string {
 	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 != ""
 }
@@ -703,7 +853,7 @@ func (u *URL) Query() Values {
 func (u *URL) RequestURI() string {
 	result := u.Opaque
 	if result == "" {
-		result = escape(u.Path, encodePath)
+		result = u.EscapedPath()
 		if result == "" {
 			result = "/"
 		}
diff --git a/src/net/url/url_test.go b/src/net/url/url_test.go
index d8b19d8..ff6e9e4 100644
--- a/src/net/url/url_test.go
+++ b/src/net/url/url_test.go
@@ -13,7 +13,7 @@ import (
 
 type URLTest struct {
 	in        string
-	out       *URL
+	out       *URL   // expected parse; RawPath="" means same as Path
 	roundtrip string // expected result of reserializing the URL; empty means same as "in".
 }
 
@@ -41,11 +41,12 @@ var urltests = []URLTest{
 	{
 		"http://www.google.com/file%20one%26two",
 		&URL{
-			Scheme: "http",
-			Host:   "www.google.com",
-			Path:   "/file one&two",
+			Scheme:  "http",
+			Host:    "www.google.com",
+			Path:    "/file one&two",
+			RawPath: "/file%20one%26two",
 		},
-		"http://www.google.com/file%20one&two",
+		"",
 	},
 	// user
 	{
@@ -289,6 +290,140 @@ var urltests = []URLTest{
 		},
 		"",
 	},
+	// host subcomponent; IPv4 address in RFC 3986
+	{
+		"http://192.168.0.1/",
+		&URL{
+			Scheme: "http",
+			Host:   "192.168.0.1",
+			Path:   "/",
+		},
+		"",
+	},
+	// host and port subcomponents; IPv4 address in RFC 3986
+	{
+		"http://192.168.0.1:8080/",
+		&URL{
+			Scheme: "http",
+			Host:   "192.168.0.1:8080",
+			Path:   "/",
+		},
+		"",
+	},
+	// host subcomponent; IPv6 address in RFC 3986
+	{
+		"http://[fe80::1]/",
+		&URL{
+			Scheme: "http",
+			Host:   "[fe80::1]",
+			Path:   "/",
+		},
+		"",
+	},
+	// host and port subcomponents; IPv6 address in RFC 3986
+	{
+		"http://[fe80::1]:8080/",
+		&URL{
+			Scheme: "http",
+			Host:   "[fe80::1]:8080",
+			Path:   "/",
+		},
+		"",
+	},
+	// host subcomponent; IPv6 address with zone identifier in RFC 6847
+	{
+		"http://[fe80::1%25en0]/", // alphanum zone identifier
+		&URL{
+			Scheme: "http",
+			Host:   "[fe80::1%en0]",
+			Path:   "/",
+		},
+		"",
+	},
+	// host and port subcomponents; IPv6 address with zone identifier in RFC 6847
+	{
+		"http://[fe80::1%25en0]:8080/", // alphanum zone identifier
+		&URL{
+			Scheme: "http",
+			Host:   "[fe80::1%en0]:8080",
+			Path:   "/",
+		},
+		"",
+	},
+	// host subcomponent; IPv6 address with zone identifier in RFC 6847
+	{
+		"http://[fe80::1%25%65%6e%301-._~]/", // percent-encoded+unreserved zone identifier
+		&URL{
+			Scheme: "http",
+			Host:   "[fe80::1%en01-._~]",
+			Path:   "/",
+		},
+		"http://[fe80::1%25en01-._~]/",
+	},
+	// host and port subcomponents; IPv6 address with zone identifier in RFC 6847
+	{
+		"http://[fe80::1%25%65%6e%301-._~]:8080/", // percent-encoded+unreserved zone identifier
+		&URL{
+			Scheme: "http",
+			Host:   "[fe80::1%en01-._~]:8080",
+			Path:   "/",
+		},
+		"http://[fe80::1%25en01-._~]:8080/",
+	},
+	// alternate escapings of path survive round trip
+	{
+		"http://rest.rsc.io/foo%2fbar/baz%2Fquux?alt=media",
+		&URL{
+			Scheme:   "http",
+			Host:     "rest.rsc.io",
+			Path:     "/foo/bar/baz/quux",
+			RawPath:  "/foo%2fbar/baz%2Fquux",
+			RawQuery: "alt=media",
+		},
+		"",
+	},
+	// issue 12036
+	{
+		"mysql://a,b,c/bar",
+		&URL{
+			Scheme: "mysql",
+			Host:   "a,b,c",
+			Path:   "/bar",
+		},
+		"",
+	},
+	// worst case host, still round trips
+	{
+		"scheme://!$&'()*+,;=hello!:port/path",
+		&URL{
+			Scheme: "scheme",
+			Host:   "!$&'()*+,;=hello!:port",
+			Path:   "/path",
+		},
+		"",
+	},
+	// worst case path, still round trips
+	{
+		"http://host/!$&'()*+,;=:@[hello]",
+		&URL{
+			Scheme:  "http",
+			Host:    "host",
+			Path:    "/!$&'()*+,;=:@[hello]",
+			RawPath: "/!$&'()*+,;=:@[hello]",
+		},
+		"",
+	},
+	// golang.org/issue/5684
+	{
+		"http://example.com/oid/[order_id]",
+		&URL{
+			Scheme:  "http",
+			Host:    "example.com",
+			Path:    "/oid/[order_id]",
+			RawPath: "/oid/[order_id]",
+		},
+		"",
+	},
 }
 
 // more useful string for debugging than fmt's struct printer
@@ -300,8 +435,8 @@ func ufmt(u *URL) string {
 			pass = p
 		}
 	}
-	return fmt.Sprintf("opaque=%q, scheme=%q, user=%#v, pass=%#v, host=%q, path=%q, rawq=%q, frag=%q",
-		u.Opaque, u.Scheme, user, pass, u.Host, u.Path, u.RawQuery, u.Fragment)
+	return fmt.Sprintf("opaque=%q, scheme=%q, user=%#v, pass=%#v, host=%q, path=%q, rawpath=%q, rawq=%q, frag=%q",
+		u.Opaque, u.Scheme, user, pass, u.Host, u.Path, u.RawPath, u.RawQuery, u.Fragment)
 }
 
 func DoTest(t *testing.T, parse func(string) (*URL, error), name string, tests []URLTest) {
@@ -358,9 +493,33 @@ var parseRequestURLTests = []struct {
 	{"/", true},
 	{pathThatLooksSchemeRelative, true},
 	{"//not.a.user@%66%6f%6f.com/just/a/path/also", true},
+	{"*", true},
+	{"http://192.168.0.1/", true},
+	{"http://192.168.0.1:8080/", true},
+	{"http://[fe80::1]/", true},
+	{"http://[fe80::1]:8080/", true},
+
+	// Tests exercising RFC 6874 compliance:
+	{"http://[fe80::1%25en0]/", true},                 // with alphanum zone identifier
+	{"http://[fe80::1%25en0]:8080/", true},            // with alphanum zone identifier
+	{"http://[fe80::1%25%65%6e%301-._~]/", true},      // with percent-encoded+unreserved zone identifier
+	{"http://[fe80::1%25%65%6e%301-._~]:8080/", true}, // with percent-encoded+unreserved zone identifier
+
 	{"foo.html", false},
 	{"../dir/", false},
-	{"*", true},
+	{"http://192.168.0.%31/", false},
+	{"http://192.168.0.%31:8080/", false},
+	{"http://[fe80::%31]/", false},
+	{"http://[fe80::%31]:8080/", false},
+	{"http://[fe80::%31%25en0]/", false},
+	{"http://[fe80::%31%25en0]:8080/", false},
+
+	// These two cases are valid as textual representations as
+	// described in RFC 4007, but are not valid as address
+	// literals with IPv6 zone identifiers in URIs as described in
+	// RFC 6874.
+	{"http://[fe80::1%en0]/", false},
+	{"http://[fe80::1%en0]:8080/", false},
 }
 
 func TestParseRequestURI(t *testing.T) {
@@ -869,6 +1028,25 @@ var requritests = []RequestURITest{
 		},
 		"http://other.example.com/%2F/%2F/",
 	},
+	// better fix for issue 4860
+	{
+		&URL{
+			Scheme:  "http",
+			Host:    "example.com",
+			Path:    "/////",
+			RawPath: "/%2F/%2F/",
+		},
+		"/%2F/%2F/",
+	},
+	{
+		&URL{
+			Scheme:  "http",
+			Host:    "example.com",
+			Path:    "/////",
+			RawPath: "/WRONG/", // ignored because doesn't match Path
+		},
+		"/////",
+	},
 	{
 		&URL{
 			Scheme:   "http",
@@ -880,6 +1058,26 @@ var requritests = []RequestURITest{
 	},
 	{
 		&URL{
+			Scheme:   "http",
+			Host:     "example.com",
+			Path:     "/a b",
+			RawPath:  "/a b", // ignored because invalid
+			RawQuery: "q=go+language",
+		},
+		"/a%20b?q=go+language",
+	},
+	{
+		&URL{
+			Scheme:   "http",
+			Host:     "example.com",
+			Path:     "/a?b",
+			RawPath:  "/a?b", // ignored because invalid
+			RawQuery: "q=go+language",
+		},
+		"/a%3Fb?q=go+language",
+	},
+	{
+		&URL{
 			Scheme: "myschema",
 			Opaque: "opaque",
 		},
@@ -914,6 +1112,54 @@ func TestParseFailure(t *testing.T) {
 	}
 }
 
+func TestParseAuthority(t *testing.T) {
+	tests := []struct {
+		in      string
+		wantErr bool
+	}{
+		{"http://[::1]", false},
+		{"http://[::1]:80", false},
+		{"http://[::1]:namedport", true}, // rfc3986 3.2.3
+		{"http://[::1]/", false},
+		{"http://[::1]a", true},
+		{"http://[::1]%23", true},
+		{"http://[::1%25en0]", false},     // valid zone id
+		{"http://[::1]:", true},           // colon, but no port
+		{"http://[::1]:%38%30", true},     // no hex in port
+		{"http://[::1%25%10]", false},     // TODO: reject the %10 after the valid zone %25 separator?
+		{"http://[%10::1]", true},         // no %xx escapes in IP address
+		{"http://[::1]/%48", false},       // %xx in path is fine
+		{"http://%41:8080/", true},        // TODO: arguably we should accept reg-name with %xx
+		{"mysql://x@y(z:123)/foo", false}, // golang.org/issue/12023
+		{"mysql://x@y(1.2.3.4:123)/foo", false},
+		{"mysql://x@y([2001:db8::1]:123)/foo", false},
+		{"http://[]%20%48%54%54%50%2f%31%2e%31%0a%4d%79%48%65%61%64%65%72%3a%20%31%32%33%0a%0a/", true}, // golang.org/issue/11208
+	}
+	for _, tt := range tests {
+		u, err := Parse(tt.in)
+		if tt.wantErr {
+			if err == nil {
+				t.Errorf("Parse(%q) = %#v; want an error", tt.in, u)
+			}
+			continue
+		}
+		if err != nil {
+			t.Logf("Parse(%q) = %v; want no error", tt.in, err)
+		}
+	}
+}
+
+// Issue 11202
+func TestStarRequest(t *testing.T) {
+	u, err := Parse("*")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if got, want := u.RequestURI(), "*"; got != want {
+		t.Errorf("RequestURI = %q; want %q", got, want)
+	}
+}
+
 type shouldEscapeTest struct {
 	in     byte
 	mode   encoding
@@ -926,6 +1172,7 @@ var shouldEscapeTests = []shouldEscapeTest{
 	{'a', encodeUserPassword, false},
 	{'a', encodeQueryComponent, false},
 	{'a', encodeFragment, false},
+	{'a', encodeHost, false},
 	{'z', encodePath, false},
 	{'A', encodePath, false},
 	{'Z', encodePath, false},
@@ -950,6 +1197,29 @@ var shouldEscapeTests = []shouldEscapeTest{
 	{',', encodeUserPassword, false},
 	{';', encodeUserPassword, false},
 	{'=', encodeUserPassword, false},
+
+	// Host (IP address, IPv6 address, registered name, port suffix; §3.2.2)
+	{'!', encodeHost, false},
+	{'$', encodeHost, false},
+	{'&', encodeHost, false},
+	{'\'', encodeHost, false},
+	{'(', encodeHost, false},
+	{')', encodeHost, false},
+	{'*', encodeHost, false},
+	{'+', encodeHost, false},
+	{',', encodeHost, false},
+	{';', encodeHost, false},
+	{'=', encodeHost, false},
+	{':', encodeHost, false},
+	{'[', encodeHost, false},
+	{']', encodeHost, false},
+	{'0', encodeHost, false},
+	{'9', encodeHost, false},
+	{'A', encodeHost, false},
+	{'z', encodeHost, false},
+	{'_', encodeHost, false},
+	{'-', encodeHost, false},
+	{'.', encodeHost, false},
 }
 
 func TestShouldEscape(t *testing.T) {
diff --git a/src/net/z_last_test.go b/src/net/z_last_test.go
deleted file mode 100644
index 716c103..0000000
--- a/src/net/z_last_test.go
+++ /dev/null
@@ -1,99 +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 net
-
-import (
-	"flag"
-	"fmt"
-	"testing"
-	"time"
-)
-
-var testDNSFlood = flag.Bool("dnsflood", false, "whether to test dns query flooding")
-
-func TestDNSThreadLimit(t *testing.T) {
-	if !*testDNSFlood {
-		t.Skip("test disabled; use -dnsflood to enable")
-	}
-
-	const N = 10000
-	c := make(chan int, N)
-	for i := 0; i < N; i++ {
-		go func(i int) {
-			LookupIP(fmt.Sprintf("%d.net-test.golang.org", i))
-			c <- 1
-		}(i)
-	}
-	// Don't bother waiting for the stragglers; stop at 0.9 N.
-	for i := 0; i < N*9/10; i++ {
-		if i%100 == 0 {
-			//println("TestDNSThreadLimit:", i)
-		}
-		<-c
-	}
-
-	// If we're still here, it worked.
-}
-
-func TestLookupIPDeadline(t *testing.T) {
-	if !*testDNSFlood {
-		t.Skip("test disabled; use -dnsflood to enable")
-	}
-
-	const N = 5000
-	const timeout = 3 * time.Second
-	c := make(chan error, 2*N)
-	for i := 0; i < N; i++ {
-		name := fmt.Sprintf("%d.net-test.golang.org", i)
-		go func() {
-			_, err := lookupIPDeadline(name, time.Now().Add(timeout/2))
-			c <- err
-		}()
-		go func() {
-			_, err := lookupIPDeadline(name, time.Now().Add(timeout))
-			c <- err
-		}()
-	}
-	qstats := struct {
-		succeeded, failed         int
-		timeout, temporary, other int
-		unknown                   int
-	}{}
-	deadline := time.After(timeout + time.Second)
-	for i := 0; i < 2*N; i++ {
-		select {
-		case <-deadline:
-			t.Fatal("deadline exceeded")
-		case err := <-c:
-			switch err := err.(type) {
-			case nil:
-				qstats.succeeded++
-			case Error:
-				qstats.failed++
-				if err.Timeout() {
-					qstats.timeout++
-				}
-				if err.Temporary() {
-					qstats.temporary++
-				}
-				if !err.Timeout() && !err.Temporary() {
-					qstats.other++
-				}
-			default:
-				qstats.failed++
-				qstats.unknown++
-			}
-		}
-	}
-
-	// A high volume of DNS queries for sub-domain of golang.org
-	// would be coordinated by authoritative or recursive server,
-	// or stub resolver which implements query-response rate
-	// limitation, so we can expect some query successes and more
-	// failures including timeout, temporary and other here.
-	// As a rule, unknown must not be shown but it might possibly
-	// happen due to issue 4856 for now.
-	t.Logf("%v succeeded, %v failed (%v timeout, %v temporary, %v other, %v unknown)", qstats.succeeded, qstats.failed, qstats.timeout, qstats.temporary, qstats.other, qstats.unknown)
-}
diff --git a/src/os/env.go b/src/os/env.go
index d0494a4..a4ede15 100644
--- a/src/os/env.go
+++ b/src/os/env.go
@@ -33,7 +33,7 @@ func ExpandEnv(s string) string {
 	return Expand(s, Getenv)
 }
 
-// isSpellSpecialVar reports whether the character identifies a special
+// isShellSpecialVar reports whether the character identifies a special
 // shell variable such as $*.
 func isShellSpecialVar(c uint8) bool {
 	switch c {
@@ -48,7 +48,7 @@ func isAlphaNum(c uint8) bool {
 	return c == '_' || '0' <= c && c <= '9' || 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z'
 }
 
-// getName returns the name that begins the string and the number of bytes
+// getShellName returns the name that begins the string and the number of bytes
 // consumed to extract it.  If the name is enclosed in {}, it's part of a ${}
 // expansion and two more bytes are needed than the length of the name.
 func getShellName(s string) (string, int) {
@@ -81,6 +81,15 @@ func Getenv(key string) string {
 	return v
 }
 
+// LookupEnv retrieves the value of the environment variable named
+// by the key. If the variable is present in the environment the
+// value (which may be empty) is returned and the boolean is true.
+// Otherwise the returned value will be empty and the boolean will
+// be false.
+func LookupEnv(key string) (string, bool) {
+	return syscall.Getenv(key)
+}
+
 // Setenv sets the value of the environment variable named by the key.
 // It returns an error, if any.
 func Setenv(key, value string) error {
diff --git a/src/os/env_test.go b/src/os/env_test.go
index e618067..d1074cd 100644
--- a/src/os/env_test.go
+++ b/src/os/env_test.go
@@ -94,3 +94,20 @@ func TestUnsetenv(t *testing.T) {
 		t.Fatal("Unsetenv didn't clear TestUnsetenv")
 	}
 }
+
+func TestLookupEnv(t *testing.T) {
+	const smallpox = "SMALLPOX"      // No one has smallpox.
+	value, ok := LookupEnv(smallpox) // Should not exist.
+	if ok || value != "" {
+		t.Fatalf("%s=%q", smallpox, value)
+	}
+	defer Unsetenv(smallpox)
+	err := Setenv(smallpox, "virus")
+	if err != nil {
+		t.Fatalf("failed to release smallpox virus")
+	}
+	value, ok = LookupEnv(smallpox)
+	if !ok {
+		t.Errorf("smallpox release failed; world remains safe but LookupEnv is broken")
+	}
+}
diff --git a/src/os/error_windows_test.go b/src/os/error_windows_test.go
deleted file mode 100644
index 3e6504f..0000000
--- a/src/os/error_windows_test.go
+++ /dev/null
@@ -1,47 +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.
-
-package os_test
-
-import (
-	"io/ioutil"
-	"os"
-	"path/filepath"
-	"testing"
-)
-
-func TestErrIsExistAfterRename(t *testing.T) {
-	dir, err := ioutil.TempDir("", "go-build")
-	if err != nil {
-		t.Fatalf("Create temp directory: %v", err)
-	}
-	defer os.RemoveAll(dir)
-
-	src := filepath.Join(dir, "src")
-	dest := filepath.Join(dir, "dest")
-
-	f, err := os.Create(src)
-	if err != nil {
-		t.Fatalf("Create file %v: %v", src, err)
-	}
-	f.Close()
-	err = os.Rename(src, dest)
-	if err != nil {
-		t.Fatalf("Rename %v to %v: %v", src, dest, err)
-	}
-
-	f, err = os.Create(src)
-	if err != nil {
-		t.Fatalf("Create file %v: %v", src, err)
-	}
-	f.Close()
-	err = os.Rename(src, dest)
-	if err == nil {
-		t.Fatal("Rename should have failed")
-	}
-	if s := checkErrorPredicate("os.IsExist", os.IsExist, err); s != "" {
-		t.Fatal(s)
-		return
-	}
-}
diff --git a/src/os/exec.go b/src/os/exec.go
index 5aea309..15e95b9 100644
--- a/src/os/exec.go
+++ b/src/os/exec.go
@@ -13,8 +13,8 @@ import (
 // Process stores the information about a process created by StartProcess.
 type Process struct {
 	Pid    int
-	handle uintptr
-	isdone uint32 // process has been successfully waited on, non zero if true
+	handle uintptr // handle is accessed atomically on Windows
+	isdone uint32  // process has been successfully waited on, non zero if true
 }
 
 func newProcess(pid int, handle uintptr) *Process {
diff --git a/src/os/exec/exec.go b/src/os/exec/exec.go
index 72b4905..8a84e26 100644
--- a/src/os/exec/exec.go
+++ b/src/os/exec/exec.go
@@ -32,6 +32,9 @@ func (e *Error) Error() string {
 }
 
 // Cmd represents an external command being prepared or run.
+//
+// A Cmd cannot be reused after calling its Run, Output or CombinedOutput
+// methods.
 type Cmd struct {
 	// Path is the path of the command to run.
 	//
@@ -80,8 +83,8 @@ type Cmd struct {
 	// 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.
-	// http://golang.org/issue/2603
+	// BUG(rsc): On OS X 10.6, child processes may sometimes inherit unwanted fds.
+	// https://golang.org/issue/2603
 	ExtraFiles []*os.File
 
 	// SysProcAttr holds optional, operating system-specific attributes.
@@ -154,6 +157,11 @@ func (c *Cmd) argv() []string {
 	return []string{c.Path}
 }
 
+// skipStdinCopyError optionally specifies a function which reports
+// whether the provided the stdin copy error should be ignored.
+// It is non-nil everywhere but Plan 9, which lacks EPIPE. See exec_posix.go.
+var skipStdinCopyError func(error) bool
+
 func (c *Cmd) stdin() (f *os.File, err error) {
 	if c.Stdin == nil {
 		f, err = os.Open(os.DevNull)
@@ -177,6 +185,9 @@ func (c *Cmd) stdin() (f *os.File, err error) {
 	c.closeAfterWait = append(c.closeAfterWait, pw)
 	c.goroutine = append(c.goroutine, func() error {
 		_, err := io.Copy(pw, c.Stdin)
+		if skip := skipStdinCopyError; skip != nil && skip(err) {
+			err = nil
+		}
 		if err1 := pw.Close(); err == nil {
 			err = err1
 		}
@@ -219,6 +230,7 @@ func (c *Cmd) writerDescriptor(w io.Writer) (f *os.File, err error) {
 	c.closeAfterWait = append(c.closeAfterWait, pr)
 	c.goroutine = append(c.goroutine, func() error {
 		_, err := io.Copy(w, pr)
+		pr.Close() // in case io.Copy stopped due to write error
 		return err
 	})
 	return pw, nil
@@ -352,6 +364,10 @@ func (e *ExitError) Error() string {
 // error is of type *ExitError. Other error types may be
 // returned for I/O problems.
 //
+// If c.Stdin is not an *os.File, Wait also waits for the I/O loop
+// copying from c.Stdin into the process's standard input
+// to complete.
+//
 // Wait releases any resources associated with the Cmd.
 func (c *Cmd) Wait() error {
 	if c.Process == nil {
diff --git a/src/os/exec/exec_posix.go b/src/os/exec/exec_posix.go
new file mode 100644
index 0000000..5e11137
--- /dev/null
+++ b/src/os/exec/exec_posix.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
+
+package exec
+
+import (
+	"os"
+	"syscall"
+)
+
+func init() {
+	skipStdinCopyError = func(err error) bool {
+		// Ignore EPIPE errors copying to stdin if the program
+		// completed successfully otherwise.
+		// See Issue 9173.
+		pe, ok := err.(*os.PathError)
+		return ok &&
+			pe.Op == "write" && pe.Path == "|1" &&
+			pe.Err == syscall.EPIPE
+	}
+}
diff --git a/src/os/exec/exec_test.go b/src/os/exec/exec_test.go
index 197d3e8..28be21c 100644
--- a/src/os/exec/exec_test.go
+++ b/src/os/exec/exec_test.go
@@ -11,6 +11,7 @@ import (
 	"bufio"
 	"bytes"
 	"fmt"
+	"internal/testenv"
 	"io"
 	"io/ioutil"
 	"log"
@@ -28,9 +29,8 @@ import (
 )
 
 func helperCommand(t *testing.T, s ...string) *exec.Cmd {
-	if runtime.GOOS == "nacl" {
-		t.Skip("skipping on nacl")
-	}
+	testenv.MustHaveExec(t)
+
 	cs := []string{"-test.run=TestHelperProcess", "--"}
 	cs = append(cs, s...)
 	cmd := exec.Command(os.Args[0], cs...)
@@ -49,6 +49,8 @@ func TestEcho(t *testing.T) {
 }
 
 func TestCommandRelativeName(t *testing.T) {
+	testenv.MustHaveExec(t)
+
 	// Run our own binary as a relative path
 	// (e.g. "_test/exec.test") our parent directory.
 	base := filepath.Base(os.Args[0]) // "exec.test"
@@ -246,6 +248,12 @@ func TestPipeLookPathLeak(t *testing.T) {
 }
 
 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")
@@ -253,6 +261,45 @@ func numOpenFDS(t *testing.T) (n int, lsof []byte) {
 	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
@@ -271,15 +318,15 @@ func closeUnexpectedFds(t *testing.T, m string) {
 }
 
 func TestExtraFilesFDShuffle(t *testing.T) {
-	t.Skip("flaky test; see http://golang.org/issue/5780")
+	t.Skip("flaky test; see https://golang.org/issue/5780")
 	switch runtime.GOOS {
 	case "darwin":
-		// TODO(cnicolaou): http://golang.org/issue/2603
+		// TODO(cnicolaou): https://golang.org/issue/2603
 		// leads to leaked file descriptors in this test when it's
 		// run from a builder.
 		closeUnexpectedFds(t, "TestExtraFilesFDShuffle")
 	case "netbsd":
-		// http://golang.org/issue/3955
+		// https://golang.org/issue/3955
 		closeUnexpectedFds(t, "TestExtraFilesFDShuffle")
 	case "windows":
 		t.Skip("no operating system support; skipping")
@@ -375,8 +422,9 @@ func TestExtraFilesFDShuffle(t *testing.T) {
 }
 
 func TestExtraFiles(t *testing.T) {
-	switch runtime.GOOS {
-	case "nacl", "windows":
+	testenv.MustHaveExec(t)
+
+	if runtime.GOOS == "windows" {
 		t.Skipf("skipping test on %q", runtime.GOOS)
 	}
 
@@ -604,21 +652,21 @@ func TestHelperProcess(*testing.T) {
 			// file descriptors...
 		case "darwin":
 			// TODO(bradfitz): broken? Sometimes.
-			// http://golang.org/issue/2603
+			// https://golang.org/issue/2603
 			// Skip this additional part of the test for now.
 		case "netbsd":
 			// TODO(jsing): This currently fails on NetBSD due to
 			// the cloned file descriptors that result from opening
 			// /dev/urandom.
-			// http://golang.org/issue/3955
+			// https://golang.org/issue/3955
 		case "plan9":
 			// TODO(0intro): Determine why Plan 9 is leaking
 			// file descriptors.
-			// http://golang.org/issue/7118
+			// https://golang.org/issue/7118
 		case "solaris":
 			// TODO(aram): This fails on Solaris because libc opens
 			// its own files, as it sees fit. Darwin does the same,
-			// see: http://golang.org/issue/2603
+			// see: https://golang.org/issue/2603
 		default:
 			// Now verify that there are no other open fds.
 			var files []*os.File
@@ -717,3 +765,54 @@ func TestHelperProcess(*testing.T) {
 		os.Exit(2)
 	}
 }
+
+// Issue 9173: ignore stdin pipe writes if the program completes successfully.
+func TestIgnorePipeErrorOnSuccess(t *testing.T) {
+	testenv.MustHaveExec(t)
+
+	// We really only care about testing this on Unixy things.
+	if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
+		t.Skipf("skipping test on %q", runtime.GOOS)
+	}
+
+	cmd := helperCommand(t, "echo", "foo")
+	var out bytes.Buffer
+	cmd.Stdin = strings.NewReader(strings.Repeat("x", 10<<20))
+	cmd.Stdout = &out
+	if err := cmd.Run(); err != nil {
+		t.Fatal(err)
+	}
+	if got, want := out.String(), "foo\n"; got != want {
+		t.Errorf("output = %q; want %q", got, want)
+	}
+}
+
+type badWriter struct{}
+
+func (w *badWriter) Write(data []byte) (int, error) {
+	return 0, io.ErrUnexpectedEOF
+}
+
+func TestClosePipeOnCopyError(t *testing.T) {
+	testenv.MustHaveExec(t)
+
+	if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
+		t.Skipf("skipping test on %s - no yes command", runtime.GOOS)
+	}
+	cmd := exec.Command("yes")
+	cmd.Stdout = new(badWriter)
+	c := make(chan int, 1)
+	go func() {
+		err := cmd.Run()
+		if err == nil {
+			t.Errorf("yes completed successfully")
+		}
+		c <- 1
+	}()
+	select {
+	case <-c:
+		// ok
+	case <-time.After(5 * time.Second):
+		t.Fatalf("yes got stuck writing to bad writer")
+	}
+}
diff --git a/src/os/exec/lp_windows_test.go b/src/os/exec/lp_windows_test.go
index 72df03e..8e1d423 100644
--- a/src/os/exec/lp_windows_test.go
+++ b/src/os/exec/lp_windows_test.go
@@ -422,7 +422,7 @@ var commandTests = []commandTest{
 	},
 	// tests commands, like `a.exe`, with c.Dir set
 	{
-		// should not find a.exe in p, becasue LookPath(`a.exe`) will fail
+		// should not find a.exe in p, because LookPath(`a.exe`) will fail
 		files: []string{`p\a.exe`},
 		dir:   `p`,
 		arg0:  `a.exe`,
diff --git a/src/os/exec_posix.go b/src/os/exec_posix.go
index fb9d291..94dd04b 100644
--- a/src/os/exec_posix.go
+++ b/src/os/exec_posix.go
@@ -81,33 +81,6 @@ func (p *ProcessState) sysUsage() interface{} {
 	return p.rusage
 }
 
-// Convert i to decimal string.
-func itod(i int) string {
-	if i == 0 {
-		return "0"
-	}
-
-	u := uint64(i)
-	if i < 0 {
-		u = -u
-	}
-
-	// Assemble decimal in reverse order.
-	var b [32]byte
-	bp := len(b)
-	for ; u > 0; u /= 10 {
-		bp--
-		b[bp] = byte(u%10) + '0'
-	}
-
-	if i < 0 {
-		bp--
-		b[bp] = '-'
-	}
-
-	return string(b[bp:])
-}
-
 func (p *ProcessState) String() string {
 	if p == nil {
 		return "<nil>"
@@ -116,13 +89,13 @@ func (p *ProcessState) String() string {
 	res := ""
 	switch {
 	case status.Exited():
-		res = "exit status " + itod(status.ExitStatus())
+		res = "exit status " + itoa(status.ExitStatus())
 	case status.Signaled():
 		res = "signal: " + status.Signal().String()
 	case status.Stopped():
 		res = "stop signal: " + status.StopSignal().String()
 		if status.StopSignal() == syscall.SIGTRAP && status.TrapCause() != 0 {
-			res += " (trap " + itod(status.TrapCause()) + ")"
+			res += " (trap " + itoa(status.TrapCause()) + ")"
 		}
 	case status.Continued():
 		res = "continued"
diff --git a/src/os/exec_windows.go b/src/os/exec_windows.go
index 393393b..3264271 100644
--- a/src/os/exec_windows.go
+++ b/src/os/exec_windows.go
@@ -7,13 +7,15 @@ package os
 import (
 	"errors"
 	"runtime"
+	"sync/atomic"
 	"syscall"
 	"time"
 	"unsafe"
 )
 
 func (p *Process) wait() (ps *ProcessState, err error) {
-	s, e := syscall.WaitForSingleObject(syscall.Handle(p.handle), syscall.INFINITE)
+	handle := atomic.LoadUintptr(&p.handle)
+	s, e := syscall.WaitForSingleObject(syscall.Handle(handle), syscall.INFINITE)
 	switch s {
 	case syscall.WAIT_OBJECT_0:
 		break
@@ -23,12 +25,12 @@ func (p *Process) wait() (ps *ProcessState, err error) {
 		return nil, errors.New("os: unexpected result from WaitForSingleObject")
 	}
 	var ec uint32
-	e = syscall.GetExitCodeProcess(syscall.Handle(p.handle), &ec)
+	e = syscall.GetExitCodeProcess(syscall.Handle(handle), &ec)
 	if e != nil {
 		return nil, NewSyscallError("GetExitCodeProcess", e)
 	}
 	var u syscall.Rusage
-	e = syscall.GetProcessTimes(syscall.Handle(p.handle), &u.CreationTime, &u.ExitTime, &u.KernelTime, &u.UserTime)
+	e = syscall.GetProcessTimes(syscall.Handle(handle), &u.CreationTime, &u.ExitTime, &u.KernelTime, &u.UserTime)
 	if e != nil {
 		return nil, NewSyscallError("GetProcessTimes", e)
 	}
@@ -53,7 +55,8 @@ func terminateProcess(pid, exitcode int) error {
 }
 
 func (p *Process) signal(sig Signal) error {
-	if p.handle == uintptr(syscall.InvalidHandle) {
+	handle := atomic.LoadUintptr(&p.handle)
+	if handle == uintptr(syscall.InvalidHandle) {
 		return syscall.EINVAL
 	}
 	if p.done() {
@@ -67,14 +70,15 @@ func (p *Process) signal(sig Signal) error {
 }
 
 func (p *Process) release() error {
-	if p.handle == uintptr(syscall.InvalidHandle) {
+	handle := atomic.LoadUintptr(&p.handle)
+	if handle == uintptr(syscall.InvalidHandle) {
 		return syscall.EINVAL
 	}
-	e := syscall.CloseHandle(syscall.Handle(p.handle))
+	e := syscall.CloseHandle(syscall.Handle(handle))
 	if e != nil {
 		return NewSyscallError("CloseHandle", e)
 	}
-	p.handle = uintptr(syscall.InvalidHandle)
+	atomic.StoreUintptr(&p.handle, uintptr(syscall.InvalidHandle))
 	// no need for a finalizer anymore
 	runtime.SetFinalizer(p, nil)
 	return nil
diff --git a/src/os/file.go b/src/os/file.go
index e12428c..8c0e3ff 100644
--- a/src/os/file.go
+++ b/src/os/file.go
@@ -192,7 +192,7 @@ func (f *File) Seek(offset int64, whence int) (ret int64, err error) {
 
 // WriteString is like Write, but writes the contents of string s rather than
 // a slice of bytes.
-func (f *File) WriteString(s string) (ret int, err error) {
+func (f *File) WriteString(s string) (n int, err error) {
 	if f == nil {
 		return 0, ErrInvalid
 	}
@@ -203,9 +203,16 @@ func (f *File) WriteString(s string) (ret int, err error) {
 // If there is an error, it will be of type *PathError.
 func Mkdir(name string, perm FileMode) error {
 	e := syscall.Mkdir(name, syscallMode(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
 }
 
@@ -235,16 +242,16 @@ func (f *File) Chdir() error {
 // the returned file can be used for reading; the associated file
 // descriptor has mode O_RDONLY.
 // If there is an error, it will be of type *PathError.
-func Open(name string) (file *File, err error) {
+func Open(name string) (*File, error) {
 	return OpenFile(name, O_RDONLY, 0)
 }
 
-// Create creates the named file mode 0666 (before umask), truncating
-// it if it already exists.  If successful, methods on the returned
+// Create creates the named file with mode 0666 (before umask), truncating
+// it if it already exists. If successful, methods on the returned
 // File can be used for I/O; the associated file descriptor has mode
 // O_RDWR.
 // If there is an error, it will be of type *PathError.
-func Create(name string) (file *File, err error) {
+func Create(name string) (*File, error) {
 	return OpenFile(name, O_RDWR|O_CREATE|O_TRUNC, 0666)
 }
 
@@ -252,6 +259,7 @@ func Create(name string) (file *File, err error) {
 var lstat = Lstat
 
 // Rename renames (moves) a file. OS-specific restrictions might apply.
+// If there is an error, it will be of type *LinkError.
 func Rename(oldpath, newpath string) error {
 	return rename(oldpath, newpath)
 }
diff --git a/src/os/file_plan9.go b/src/os/file_plan9.go
index 132594e..085ebc4 100644
--- a/src/os/file_plan9.go
+++ b/src/os/file_plan9.go
@@ -79,7 +79,7 @@ func syscallMode(i FileMode) (o uint32) {
 // (O_RDONLY etc.) and perm, (0666 etc.) if applicable.  If successful,
 // methods on the returned File can be used for I/O.
 // If there is an error, it will be of type *PathError.
-func OpenFile(name string, flag int, perm FileMode) (file *File, err error) {
+func OpenFile(name string, flag int, perm FileMode) (*File, error) {
 	var (
 		fd     int
 		e      error
@@ -159,7 +159,7 @@ func (file *file) close() error {
 
 // Stat returns the FileInfo structure describing file.
 // If there is an error, it will be of type *PathError.
-func (f *File) Stat() (fi FileInfo, err error) {
+func (f *File) Stat() (FileInfo, error) {
 	if f == nil {
 		return nil, ErrInvalid
 	}
@@ -224,7 +224,7 @@ func (f *File) Chmod(mode FileMode) error {
 // Sync commits the current contents of the file to stable storage.
 // Typically, this means flushing the file system's in-memory copy
 // of recently written data to disk.
-func (f *File) Sync() (err error) {
+func (f *File) Sync() error {
 	if f == nil {
 		return ErrInvalid
 	}
@@ -319,7 +319,7 @@ func hasPrefix(s, prefix string) bool {
 	return len(s) >= len(prefix) && s[0:len(prefix)] == prefix
 }
 
-// Variant of LastIndex from the strings package.
+// LastIndexByte from the strings package.
 func lastIndex(s string, sep byte) int {
 	for i := len(s) - 1; i >= 0; i-- {
 		if s[i] == sep {
diff --git a/src/os/file_posix.go b/src/os/file_posix.go
index fbb3b5e..6d8076f 100644
--- a/src/os/file_posix.go
+++ b/src/os/file_posix.go
@@ -28,14 +28,6 @@ func Readlink(name string) (string, error) {
 	}
 }
 
-func rename(oldname, newname string) error {
-	e := syscall.Rename(oldname, newname)
-	if e != nil {
-		return &LinkError{"rename", oldname, newname, e}
-	}
-	return nil
-}
-
 // syscallMode returns the syscall-specific mode bits from Go's portable mode bits.
 func syscallMode(i FileMode) (o uint32) {
 	o |= uint32(i.Perm())
@@ -122,7 +114,7 @@ func (f *File) Truncate(size int64) error {
 // Sync commits the current contents of the file to stable storage.
 // Typically, this means flushing the file system's in-memory copy
 // of recently written data to disk.
-func (f *File) Sync() (err error) {
+func (f *File) Sync() error {
 	if f == nil {
 		return ErrInvalid
 	}
diff --git a/src/os/file_unix.go b/src/os/file_unix.go
index ff4fc7d..0677707 100644
--- a/src/os/file_unix.go
+++ b/src/os/file_unix.go
@@ -12,6 +12,14 @@ import (
 	"syscall"
 )
 
+func rename(oldname, newname string) error {
+	e := syscall.Rename(oldname, newname)
+	if e != nil {
+		return &LinkError{"rename", oldname, newname, e}
+	}
+	return nil
+}
+
 // File represents an open file descriptor.
 type File struct {
 	*file
@@ -74,12 +82,24 @@ const DevNull = "/dev/null"
 // (O_RDONLY etc.) and perm, (0666 etc.) if applicable.  If successful,
 // methods on the returned File can be used for I/O.
 // If there is an error, it will be of type *PathError.
-func OpenFile(name string, flag int, perm FileMode) (file *File, err error) {
+func OpenFile(name string, flag int, perm FileMode) (*File, error) {
+	chmod := false
+	if !supportsCreateWithStickyBit && flag&O_CREATE != 0 && perm&ModeSticky != 0 {
+		if _, err := Stat(name); IsNotExist(err) {
+			chmod = true
+		}
+	}
+
 	r, e := syscall.Open(name, flag|syscall.O_CLOEXEC, syscallMode(perm))
 	if e != nil {
 		return nil, &PathError{"open", name, e}
 	}
 
+	// open(2) itself won't handle the sticky bit on *BSD and Solaris
+	if chmod {
+		Chmod(name, perm)
+	}
+
 	// There's a race here with fork/exec, which we are
 	// content to live with.  See ../syscall/exec_unix.go.
 	if !supportsCloseOnExec {
@@ -115,12 +135,12 @@ func (file *file) close() error {
 
 // Stat returns the FileInfo structure describing file.
 // If there is an error, it will be of type *PathError.
-func (f *File) Stat() (fi FileInfo, err error) {
+func (f *File) Stat() (FileInfo, error) {
 	if f == nil {
 		return nil, ErrInvalid
 	}
 	var stat syscall.Stat_t
-	err = syscall.Fstat(f.fd, &stat)
+	err := syscall.Fstat(f.fd, &stat)
 	if err != nil {
 		return nil, &PathError{"stat", f.name, err}
 	}
@@ -129,9 +149,9 @@ func (f *File) Stat() (fi FileInfo, err error) {
 
 // Stat returns a FileInfo describing the named file.
 // If there is an error, it will be of type *PathError.
-func Stat(name string) (fi FileInfo, err error) {
+func Stat(name string) (FileInfo, error) {
 	var stat syscall.Stat_t
-	err = syscall.Stat(name, &stat)
+	err := syscall.Stat(name, &stat)
 	if err != nil {
 		return nil, &PathError{"stat", name, err}
 	}
@@ -142,9 +162,9 @@ func Stat(name string) (fi FileInfo, err error) {
 // If the file is a symbolic link, the returned FileInfo
 // describes the symbolic link.  Lstat makes no attempt to follow the link.
 // If there is an error, it will be of type *PathError.
-func Lstat(name string) (fi FileInfo, err error) {
+func Lstat(name string) (FileInfo, error) {
 	var stat syscall.Stat_t
-	err = syscall.Lstat(name, &stat)
+	err := syscall.Lstat(name, &stat)
 	if err != nil {
 		return nil, &PathError{"lstat", name, err}
 	}
diff --git a/src/os/file_windows.go b/src/os/file_windows.go
index 2a90a50..89b1d27 100644
--- a/src/os/file_windows.go
+++ b/src/os/file_windows.go
@@ -5,6 +5,7 @@
 package os
 
 import (
+	"internal/syscall/windows"
 	"io"
 	"runtime"
 	"sync"
@@ -133,7 +134,7 @@ func openDir(name string) (file *File, err error) {
 // (O_RDONLY etc.) and perm, (0666 etc.) if applicable.  If successful,
 // methods on the returned File can be used for I/O.
 // If there is an error, it will be of type *PathError.
-func OpenFile(name string, flag int, perm FileMode) (file *File, err error) {
+func OpenFile(name string, flag int, perm FileMode) (*File, error) {
 	if name == "" {
 		return nil, &PathError{"open", name, syscall.ENOENT}
 	}
@@ -460,6 +461,14 @@ func Remove(name string) error {
 	return &PathError{"remove", name, e}
 }
 
+func rename(oldname, newname string) error {
+	e := windows.Rename(oldname, newname)
+	if e != nil {
+		return &LinkError{"rename", oldname, newname, e}
+	}
+	return nil
+}
+
 // Pipe returns a connected pair of Files; reads from r return bytes written to w.
 // It returns the files and an error, if any.
 func Pipe() (r *File, w *File, err error) {
@@ -481,20 +490,18 @@ func Pipe() (r *File, w *File, err error) {
 
 // TempDir returns the default directory to use for temporary files.
 func TempDir() string {
-	const pathSep = '\\'
-	dirw := make([]uint16, syscall.MAX_PATH)
-	n, _ := syscall.GetTempPath(uint32(len(dirw)), &dirw[0])
-	if n > uint32(len(dirw)) {
-		dirw = make([]uint16, n)
-		n, _ = syscall.GetTempPath(uint32(len(dirw)), &dirw[0])
-		if n > uint32(len(dirw)) {
-			n = 0
+	n := uint32(syscall.MAX_PATH)
+	for {
+		b := make([]uint16, n)
+		n, _ = syscall.GetTempPath(uint32(len(b)), &b[0])
+		if n > uint32(len(b)) {
+			continue
 		}
+		if n > 0 && b[n-1] == '\\' {
+			n--
+		}
+		return string(utf16.Decode(b[:n]))
 	}
-	if n > 0 && dirw[n-1] == pathSep {
-		n--
-	}
-	return string(utf16.Decode(dirw[0:n]))
 }
 
 // Link creates newname as a hard link to the oldname file.
@@ -508,9 +515,8 @@ func Link(oldname, newname string) error {
 	if err != nil {
 		return &LinkError{"link", oldname, newname, err}
 	}
-
-	e := syscall.CreateHardLink(n, o, 0)
-	if e != nil {
+	err = syscall.CreateHardLink(n, o, 0)
+	if err != nil {
 		return &LinkError{"link", oldname, newname, err}
 	}
 	return nil
diff --git a/src/os/os_test.go b/src/os/os_test.go
index a30a2b0..6b72674 100644
--- a/src/os/os_test.go
+++ b/src/os/os_test.go
@@ -9,6 +9,7 @@ import (
 	"errors"
 	"flag"
 	"fmt"
+	"internal/testenv"
 	"io"
 	"io/ioutil"
 	. "os"
@@ -21,7 +22,6 @@ import (
 	"sync"
 	"syscall"
 	"testing"
-	"text/template"
 	"time"
 )
 
@@ -43,18 +43,33 @@ type sysDir struct {
 	files []string
 }
 
-var sysdir = func() (sd *sysDir) {
+var sysdir = func() *sysDir {
 	switch runtime.GOOS {
 	case "android":
-		sd = &sysDir{
+		return &sysDir{
 			"/system/etc",
 			[]string{
 				"audio_policy.conf",
 				"system_fonts.xml",
 			},
 		}
+	case "darwin":
+		switch runtime.GOARCH {
+		case "arm", "arm64":
+			wd, err := syscall.Getwd()
+			if err != nil {
+				wd = err.Error()
+			}
+			return &sysDir{
+				filepath.Join(wd, "..", ".."),
+				[]string{
+					"ResourceRules.plist",
+					"Info.plist",
+				},
+			}
+		}
 	case "windows":
-		sd = &sysDir{
+		return &sysDir{
 			Getenv("SystemRoot") + "\\system32\\drivers\\etc",
 			[]string{
 				"networks",
@@ -63,24 +78,22 @@ var sysdir = func() (sd *sysDir) {
 			},
 		}
 	case "plan9":
-		sd = &sysDir{
+		return &sysDir{
 			"/lib/ndb",
 			[]string{
 				"common",
 				"local",
 			},
 		}
-	default:
-		sd = &sysDir{
-			"/etc",
-			[]string{
-				"group",
-				"hosts",
-				"passwd",
-			},
-		}
 	}
-	return
+	return &sysDir{
+		"/etc",
+		[]string{
+			"group",
+			"hosts",
+			"passwd",
+		},
+	}
 }()
 
 func size(name string, t *testing.T) int64 {
@@ -114,15 +127,22 @@ func equal(name1, name2 string) (r bool) {
 	return
 }
 
-func newFile(testName string, t *testing.T) (f *File) {
-	// Use a local file system, not NFS.
-	// On Unix, override $TMPDIR in case the user
-	// has it set to an NFS-mounted directory.
-	dir := ""
-	if runtime.GOOS != "android" && runtime.GOOS != "windows" {
-		dir = "/tmp"
+// localTmp returns a local temporary directory not on NFS.
+func localTmp() string {
+	switch runtime.GOOS {
+	case "android", "windows":
+		return TempDir()
+	case "darwin":
+		switch runtime.GOARCH {
+		case "arm", "arm64":
+			return TempDir()
+		}
 	}
-	f, err := ioutil.TempFile(dir, "_Go_"+testName)
+	return "/tmp"
+}
+
+func newFile(testName string, t *testing.T) (f *File) {
+	f, err := ioutil.TempFile(localTmp(), "_Go_"+testName)
 	if err != nil {
 		t.Fatalf("TempFile %s: %s", testName, err)
 	}
@@ -130,14 +150,7 @@ func newFile(testName string, t *testing.T) (f *File) {
 }
 
 func newDir(testName string, t *testing.T) (name string) {
-	// Use a local file system, not NFS.
-	// On Unix, override $TMPDIR in case the user
-	// has it set to an NFS-mounted directory.
-	dir := ""
-	if runtime.GOOS != "android" && runtime.GOOS != "windows" {
-		dir = "/tmp"
-	}
-	name, err := ioutil.TempDir(dir, "_Go_"+testName)
+	name, err := ioutil.TempDir(localTmp(), "_Go_"+testName)
 	if err != nil {
 		t.Fatalf("TempDir %s: %s", testName, err)
 	}
@@ -312,6 +325,15 @@ func TestReaddirnamesOneAtATime(t *testing.T) {
 	switch runtime.GOOS {
 	case "android":
 		dir = "/system/bin"
+	case "darwin":
+		switch runtime.GOARCH {
+		case "arm", "arm64":
+			wd, err := Getwd()
+			if err != nil {
+				t.Fatal(err)
+			}
+			dir = wd
+		}
 	case "plan9":
 		dir = "/bin"
 	case "windows":
@@ -491,11 +513,35 @@ func TestReaddirStatFailures(t *testing.T) {
 	}
 }
 
+// Readdir on a regular file should fail.
+func TestReaddirOfFile(t *testing.T) {
+	f, err := ioutil.TempFile("", "_Go_ReaddirOfFile")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer Remove(f.Name())
+	f.Write([]byte("foo"))
+	f.Close()
+	reg, err := Open(f.Name())
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer reg.Close()
+
+	names, err := reg.Readdirnames(-1)
+	if err == nil {
+		t.Error("Readdirnames succeeded; want non-nil error")
+	}
+	if len(names) > 0 {
+		t.Errorf("unexpected dir names in regular file: %q", names)
+	}
+}
+
 func TestHardLink(t *testing.T) {
-	// Hardlinks are not supported under windows or Plan 9.
 	if runtime.GOOS == "plan9" {
-		return
+		t.Skip("skipping on plan9, hardlinks not supported")
 	}
+	defer chtmpdir(t)()
 	from, to := "hardlinktestfrom", "hardlinktestto"
 	Remove(from) // Just in case.
 	file, err := Create(to)
@@ -510,6 +556,14 @@ func TestHardLink(t *testing.T) {
 	if err != nil {
 		t.Fatalf("link %q, %q failed: %v", to, from, err)
 	}
+
+	none := "hardlinktestnone"
+	err = Link(none, none)
+	// Check the returned error is well-formed.
+	if lerr, ok := err.(*LinkError); !ok || lerr.Error() == "" {
+		t.Errorf("link %q, %q failed to return a valid error", none, none)
+	}
+
 	defer Remove(from)
 	tostat, err := Stat(to)
 	if err != nil {
@@ -524,6 +578,31 @@ func TestHardLink(t *testing.T) {
 	}
 }
 
+// chtmpdir changes the working directory to a new temporary directory and
+// provides a cleanup function. Used when PWD is read-only.
+func chtmpdir(t *testing.T) func() {
+	if runtime.GOOS != "darwin" || (runtime.GOARCH != "arm" && runtime.GOARCH != "arm64") {
+		return func() {} // only needed on darwin/arm{,64}
+	}
+	oldwd, err := Getwd()
+	if err != nil {
+		t.Fatalf("chtmpdir: %v", err)
+	}
+	d, err := ioutil.TempDir("", "test")
+	if err != nil {
+		t.Fatalf("chtmpdir: %v", err)
+	}
+	if err := Chdir(d); err != nil {
+		t.Fatalf("chtmpdir: %v", err)
+	}
+	return func() {
+		if err := Chdir(oldwd); err != nil {
+			t.Fatalf("chtmpdir: %v", err)
+		}
+		RemoveAll(d)
+	}
+}
+
 func TestSymlink(t *testing.T) {
 	switch runtime.GOOS {
 	case "android", "nacl", "plan9":
@@ -533,6 +612,7 @@ func TestSymlink(t *testing.T) {
 			t.Skipf("skipping on %s", runtime.GOOS)
 		}
 	}
+	defer chtmpdir(t)()
 	from, to := "symlinktestfrom", "symlinktestto"
 	Remove(from) // Just in case.
 	file, err := Create(to)
@@ -599,6 +679,7 @@ func TestLongSymlink(t *testing.T) {
 			t.Skipf("skipping on %s", runtime.GOOS)
 		}
 	}
+	defer chtmpdir(t)()
 	s := "0123456789abcdef"
 	// Long, but not too long: a common limit is 255.
 	s = s + s + s + s + s + s + s + s + s + s + s + s + s + s + s
@@ -619,14 +700,18 @@ func TestLongSymlink(t *testing.T) {
 }
 
 func TestRename(t *testing.T) {
+	defer chtmpdir(t)()
 	from, to := "renamefrom", "renameto"
-	Remove(to) // Just in case.
+	// Ensure we are not testing the overwrite case here.
+	Remove(from)
+	Remove(to)
+
 	file, err := Create(from)
 	if err != nil {
-		t.Fatalf("open %q failed: %v", to, err)
+		t.Fatalf("open %q failed: %v", from, err)
 	}
 	if err = file.Close(); err != nil {
-		t.Errorf("close %q failed: %v", to, err)
+		t.Errorf("close %q failed: %v", from, err)
 	}
 	err = Rename(from, to)
 	if err != nil {
@@ -639,6 +724,79 @@ func TestRename(t *testing.T) {
 	}
 }
 
+func TestRenameOverwriteDest(t *testing.T) {
+	if runtime.GOOS == "plan9" {
+		t.Skip("skipping on plan9")
+	}
+	defer chtmpdir(t)()
+	from, to := "renamefrom", "renameto"
+	// Just in case.
+	Remove(from)
+	Remove(to)
+
+	toData := []byte("to")
+	fromData := []byte("from")
+
+	err := ioutil.WriteFile(to, toData, 0777)
+	if err != nil {
+		t.Fatalf("write file %q failed: %v", to, err)
+	}
+
+	err = ioutil.WriteFile(from, fromData, 0777)
+	if err != nil {
+		t.Fatalf("write file %q failed: %v", from, err)
+	}
+	err = Rename(from, to)
+	if err != nil {
+		t.Fatalf("rename %q, %q failed: %v", to, from, err)
+	}
+	defer Remove(to)
+
+	_, err = Stat(from)
+	if err == nil {
+		t.Errorf("from file %q still exists", from)
+	}
+	if err != nil && !IsNotExist(err) {
+		t.Fatalf("stat from: %v", err)
+	}
+	toFi, err := Stat(to)
+	if err != nil {
+		t.Fatalf("stat %q failed: %v", to, err)
+	}
+	if toFi.Size() != int64(len(fromData)) {
+		t.Errorf(`"to" size = %d; want %d (old "from" size)`, toFi.Size(), len(fromData))
+	}
+}
+
+func TestRenameFailed(t *testing.T) {
+	defer chtmpdir(t)()
+	from, to := "renamefrom", "renameto"
+	// Ensure we are not testing the overwrite case here.
+	Remove(from)
+	Remove(to)
+
+	err := Rename(from, to)
+	switch err := err.(type) {
+	case *LinkError:
+		if err.Op != "rename" {
+			t.Errorf("rename %q, %q: err.Op: want %q, got %q", from, to, "rename", err.Op)
+		}
+		if err.Old != from {
+			t.Errorf("rename %q, %q: err.Old: want %q, got %q", from, to, from, err.Old)
+		}
+		if err.New != to {
+			t.Errorf("rename %q, %q: err.New: want %q, got %q", from, to, to, err.New)
+		}
+	case nil:
+		t.Errorf("rename %q, %q: expected error, got nil", from, to)
+
+		// cleanup whatever was placed in "renameto"
+		Remove(to)
+	default:
+		t.Errorf("rename %q, %q: expected %T, got %T %v", from, to, new(LinkError), err, err)
+	}
+}
+
 func exec(t *testing.T, dir, cmd string, args []string, expect string) {
 	r, w, err := Pipe()
 	if err != nil {
@@ -666,18 +824,18 @@ func exec(t *testing.T, dir, cmd string, args []string, expect string) {
 }
 
 func TestStartProcess(t *testing.T) {
-	switch runtime.GOOS {
-	case "android", "nacl":
-		t.Skipf("skipping on %s", runtime.GOOS)
-	}
+	testenv.MustHaveExec(t)
 
 	var dir, cmd string
 	var args []string
-	if runtime.GOOS == "windows" {
+	switch runtime.GOOS {
+	case "android":
+		t.Skip("android doesn't have /bin/pwd")
+	case "windows":
 		cmd = Getenv("COMSPEC")
 		dir = Getenv("SystemRoot")
 		args = []string{"/c", "cd"}
-	} else {
+	default:
 		cmd = "/bin/pwd"
 		dir = "/"
 		args = []string{}
@@ -849,6 +1007,19 @@ func TestChdirAndGetwd(t *testing.T) {
 		dirs = []string{"/", "/system/bin"}
 	case "plan9":
 		dirs = []string{"/", "/usr"}
+	case "darwin":
+		switch runtime.GOARCH {
+		case "arm", "arm64":
+			d1, err := ioutil.TempDir("", "d1")
+			if err != nil {
+				t.Fatalf("TempDir: %v", err)
+			}
+			d2, err := ioutil.TempDir("", "d2")
+			if err != nil {
+				t.Fatalf("TempDir: %v", err)
+			}
+			dirs = []string{d1, d2}
+		}
 	}
 	oldwd := Getenv("PWD")
 	for mode := 0; mode < 2; mode++ {
@@ -894,6 +1065,64 @@ func TestChdirAndGetwd(t *testing.T) {
 	fd.Close()
 }
 
+// Test that Chdir+Getwd is program-wide.
+func TestProgWideChdir(t *testing.T) {
+	const N = 10
+	c := make(chan bool)
+	cpwd := make(chan string)
+	for i := 0; i < N; i++ {
+		go func(i int) {
+			// Lock half the goroutines in their own operating system
+			// thread to exercise more scheduler possibilities.
+			if i%2 == 1 {
+				// On Plan 9, after calling LockOSThread, the goroutines
+				// run on different processes which don't share the working
+				// directory. This used to be an issue because Go expects
+				// the working directory to be program-wide.
+				// See issue 9428.
+				runtime.LockOSThread()
+			}
+			<-c
+			pwd, err := Getwd()
+			if err != nil {
+				t.Errorf("Getwd on goroutine %d: %v", i, err)
+				return
+			}
+			cpwd <- pwd
+		}(i)
+	}
+	oldwd, err := Getwd()
+	if err != nil {
+		t.Fatalf("Getwd: %v", err)
+	}
+	d, err := ioutil.TempDir("", "test")
+	if err != nil {
+		t.Fatalf("TempDir: %v", err)
+	}
+	defer func() {
+		if err := Chdir(oldwd); err != nil {
+			t.Fatalf("Chdir: %v", err)
+		}
+		RemoveAll(d)
+	}()
+	if err := Chdir(d); err != nil {
+		t.Fatalf("Chdir: %v", err)
+	}
+	// OS X sets TMPDIR to a symbolic link.
+	// So we resolve our working directory again before the test.
+	d, err = Getwd()
+	if err != nil {
+		t.Fatalf("Getwd: %v", err)
+	}
+	close(c)
+	for i := 0; i < N; i++ {
+		pwd := <-cpwd
+		if pwd != d {
+			t.Errorf("Getwd returned %q; want %q", pwd, d)
+		}
+	}
+}
+
 func TestSeek(t *testing.T) {
 	f := newFile("TestSeek", t)
 	defer Remove(f.Name())
@@ -922,7 +1151,7 @@ func TestSeek(t *testing.T) {
 		if off != tt.out || err != nil {
 			if e, ok := err.(*PathError); ok && e.Err == syscall.EINVAL && tt.out > 1<<32 {
 				// Reiserfs rejects the big seeks.
-				// http://code.google.com/p/go/issues/detail?id=91
+				// https://golang.org/issue/91
 				break
 			}
 			t.Errorf("#%d: Seek(%v, %v) = %v, %v want %v, nil", i, tt.in, tt.whence, off, err, tt.out)
@@ -1035,14 +1264,35 @@ func run(t *testing.T, cmd []string) string {
 	return output
 }
 
+func testWindowsHostname(t *testing.T) {
+	hostname, err := Hostname()
+	if err != nil {
+		t.Fatal(err)
+	}
+	cmd := osexec.Command("hostname")
+	out, err := cmd.CombinedOutput()
+	if err != nil {
+		t.Fatalf("Failed to execute hostname command: %v %s", err, out)
+	}
+	want := strings.Trim(string(out), "\r\n")
+	if hostname != want {
+		t.Fatalf("Hostname() = %q, want %q", hostname, want)
+	}
+}
+
 func TestHostname(t *testing.T) {
 	// There is no other way to fetch hostname on windows, but via winapi.
 	// On Plan 9 it can be taken from #c/sysname as Hostname() does.
 	switch runtime.GOOS {
-	case "android", "nacl", "plan9", "windows":
-		t.Skipf("skipping on %s", runtime.GOOS)
+	case "android", "plan9":
+		t.Skipf("%s doesn't have /bin/hostname", runtime.GOOS)
+	case "windows":
+		testWindowsHostname(t)
+		return
 	}
 
+	testenv.MustHaveExec(t)
+
 	// Check internal Hostname() against the output of /bin/hostname.
 	// Allow that the internal Hostname returns a Fully Qualified Domain Name
 	// and the /bin/hostname only returns the first component
@@ -1117,6 +1367,7 @@ func writeFile(t *testing.T, fname string, flag int, text string) string {
 }
 
 func TestAppend(t *testing.T) {
+	defer chtmpdir(t)()
 	const f = "append.txt"
 	defer Remove(f)
 	s := writeFile(t, f, O_CREATE|O_TRUNC|O_RDWR, "new")
@@ -1180,6 +1431,7 @@ func TestNilProcessStateString(t *testing.T) {
 }
 
 func TestSameFile(t *testing.T) {
+	defer chtmpdir(t)()
 	fa, err := Create("a")
 	if err != nil {
 		t.Fatalf("Create(a): %v", err)
@@ -1299,44 +1551,11 @@ func TestReadAtEOF(t *testing.T) {
 }
 
 func testKillProcess(t *testing.T, processKiller func(p *Process)) {
-	switch runtime.GOOS {
-	case "android", "nacl":
-		t.Skipf("skipping on %s", runtime.GOOS)
-	}
-
-	dir, err := ioutil.TempDir("", "go-build")
-	if err != nil {
-		t.Fatalf("Failed to create temp directory: %v", err)
-	}
-	defer RemoveAll(dir)
-
-	src := filepath.Join(dir, "main.go")
-	f, err := Create(src)
-	if err != nil {
-		t.Fatalf("Failed to create %v: %v", src, err)
-	}
-	st := template.Must(template.New("source").Parse(`
-package main
-import "time"
-func main() {
-	time.Sleep(time.Second)
-}
-`))
-	err = st.Execute(f, nil)
-	if err != nil {
-		f.Close()
-		t.Fatalf("Failed to execute template: %v", err)
-	}
-	f.Close()
-
-	exe := filepath.Join(dir, "main.exe")
-	output, err := osexec.Command("go", "build", "-o", exe, src).CombinedOutput()
-	if err != nil {
-		t.Fatalf("Failed to build exe %v: %v %v", exe, err, string(output))
-	}
+	testenv.MustHaveExec(t)
 
-	cmd := osexec.Command(exe)
-	err = cmd.Start()
+	// Re-exec the test binary itself to emulate "sleep 1".
+	cmd := osexec.Command(Args[0], "-test.run", "TestSleep")
+	err := cmd.Start()
 	if err != nil {
 		t.Fatalf("Failed to start test process: %v", err)
 	}
@@ -1350,6 +1569,15 @@ func main() {
 	}
 }
 
+// TestSleep emulates "sleep 1". It is a helper for testKillProcess, so we
+// don't have to rely on an external "sleep" command being available.
+func TestSleep(t *testing.T) {
+	if testing.Short() {
+		t.Skip("Skipping in short mode")
+	}
+	time.Sleep(time.Second)
+}
+
 func TestKillStartProcess(t *testing.T) {
 	testKillProcess(t, func(p *Process) {
 		err := p.Kill()
@@ -1360,14 +1588,13 @@ func TestKillStartProcess(t *testing.T) {
 }
 
 func TestGetppid(t *testing.T) {
-	switch runtime.GOOS {
-	case "nacl":
-		t.Skip("skipping on nacl")
-	case "plan9":
+	if runtime.GOOS == "plan9" {
 		// TODO: golang.org/issue/8206
 		t.Skipf("skipping test on plan9; see issue 8206")
 	}
 
+	testenv.MustHaveExec(t)
+
 	if Getenv("GO_WANT_HELPER_PROCESS") == "1" {
 		fmt.Print(Getppid())
 		Exit(0)
diff --git a/src/os/os_unix_test.go b/src/os/os_unix_test.go
index 21d40cc..2adc3b5 100644
--- a/src/os/os_unix_test.go
+++ b/src/os/os_unix_test.go
@@ -13,6 +13,10 @@ import (
 	"testing"
 )
 
+func init() {
+	isReadonlyError = func(err error) bool { return err == syscall.EROFS }
+}
+
 func checkUidGid(t *testing.T, path string, uid, gid int) {
 	dir, err := Stat(path)
 	if err != nil {
@@ -28,10 +32,10 @@ func checkUidGid(t *testing.T, path string, uid, gid int) {
 }
 
 func TestChown(t *testing.T) {
-	// Chown is not supported under windows os Plan 9.
+	// Chown is not supported under windows or Plan 9.
 	// Plan9 provides a native ChownPlan9 version instead.
 	if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
-		return
+		t.Skipf("%s does not support syscall.Chown", runtime.GOOS)
 	}
 	// Use TempDir() to make sure we're on a local file system,
 	// so that the group ids returned by Getgroups will be allowed
@@ -74,3 +78,109 @@ func TestChown(t *testing.T) {
 		checkUidGid(t, f.Name(), int(sys.Uid), gid)
 	}
 }
+
+func TestFileChown(t *testing.T) {
+	// Fchown is not supported under windows or Plan 9.
+	if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
+		t.Skipf("%s does not support syscall.Fchown", runtime.GOOS)
+	}
+	// Use TempDir() to make sure we're on a local file system,
+	// so that the group ids returned by Getgroups will be allowed
+	// on the file.  On NFS, the Getgroups groups are
+	// basically useless.
+	f := newFile("TestFileChown", t)
+	defer Remove(f.Name())
+	defer f.Close()
+	dir, err := f.Stat()
+	if err != nil {
+		t.Fatalf("stat %s: %s", f.Name(), err)
+	}
+
+	// Can't change uid unless root, but can try
+	// changing the group id.  First try our current group.
+	gid := Getgid()
+	t.Log("gid:", gid)
+	if err = f.Chown(-1, gid); err != nil {
+		t.Fatalf("fchown %s -1 %d: %s", f.Name(), gid, err)
+	}
+	sys := dir.Sys().(*syscall.Stat_t)
+	checkUidGid(t, f.Name(), int(sys.Uid), gid)
+
+	// Then try all the auxiliary groups.
+	groups, err := Getgroups()
+	if err != nil {
+		t.Fatalf("getgroups: %s", err)
+	}
+	t.Log("groups: ", groups)
+	for _, g := range groups {
+		if err = f.Chown(-1, g); err != nil {
+			t.Fatalf("fchown %s -1 %d: %s", f.Name(), g, err)
+		}
+		checkUidGid(t, f.Name(), int(sys.Uid), g)
+
+		// change back to gid to test fd.Chown
+		if err = f.Chown(-1, gid); err != nil {
+			t.Fatalf("fchown %s -1 %d: %s", f.Name(), gid, err)
+		}
+		checkUidGid(t, f.Name(), int(sys.Uid), gid)
+	}
+}
+
+func TestLchown(t *testing.T) {
+	// Lchown is not supported under windows or Plan 9.
+	if runtime.GOOS == "windows" || runtime.GOOS == "plan9" {
+		t.Skipf("%s does not support syscall.Lchown", runtime.GOOS)
+	}
+	// Use TempDir() to make sure we're on a local file system,
+	// so that the group ids returned by Getgroups will be allowed
+	// on the file.  On NFS, the Getgroups groups are
+	// basically useless.
+	f := newFile("TestLchown", t)
+	defer Remove(f.Name())
+	defer f.Close()
+	dir, err := f.Stat()
+	if err != nil {
+		t.Fatalf("stat %s: %s", f.Name(), err)
+	}
+
+	linkname := f.Name() + "2"
+	if err := Link(f.Name(), linkname); err != nil {
+		t.Fatalf("link %s -> %s: %v", f.Name(), linkname, err)
+	}
+	defer Remove(linkname)
+
+	f2, err := Open(linkname)
+	if err != nil {
+		t.Fatalf("open %s: %v", linkname, err)
+	}
+	defer f2.Close()
+
+	// Can't change uid unless root, but can try
+	// changing the group id.  First try our current group.
+	gid := Getgid()
+	t.Log("gid:", gid)
+	if err = Lchown(linkname, -1, gid); err != nil {
+		t.Fatalf("lchown %s -1 %d: %s", linkname, gid, err)
+	}
+	sys := dir.Sys().(*syscall.Stat_t)
+	checkUidGid(t, linkname, int(sys.Uid), gid)
+
+	// Then try all the auxiliary groups.
+	groups, err := Getgroups()
+	if err != nil {
+		t.Fatalf("getgroups: %s", err)
+	}
+	t.Log("groups: ", groups)
+	for _, g := range groups {
+		if err = Lchown(linkname, -1, g); err != nil {
+			t.Fatalf("lchown %s -1 %d: %s", linkname, g, err)
+		}
+		checkUidGid(t, linkname, int(sys.Uid), g)
+
+		// change back to gid to test fd.Chown
+		if err = f2.Chown(-1, gid); err != nil {
+			t.Fatalf("fchown %s -1 %d: %s", linkname, gid, err)
+		}
+		checkUidGid(t, linkname, int(sys.Uid), gid)
+	}
+}
diff --git a/src/os/os_windows_test.go b/src/os/os_windows_test.go
index fd96713..ee19b2b 100644
--- a/src/os/os_windows_test.go
+++ b/src/os/os_windows_test.go
@@ -3,11 +3,15 @@ package os_test
 import (
 	"io/ioutil"
 	"os"
+	osexec "os/exec"
 	"path/filepath"
+	"strings"
 	"syscall"
 	"testing"
 )
 
+var supportJunctionLinks = true
+
 func init() {
 	tmpdir, err := ioutil.TempDir("", "symtest")
 	if err != nil {
@@ -16,14 +20,18 @@ func init() {
 	defer os.RemoveAll(tmpdir)
 
 	err = os.Symlink("target", filepath.Join(tmpdir, "symlink"))
-	if err == nil {
-		return
+	if err != nil {
+		err = err.(*os.LinkError).Err
+		switch err {
+		case syscall.EWINDOWS, syscall.ERROR_PRIVILEGE_NOT_HELD:
+			supportsSymlinks = false
+		}
 	}
+	defer os.Remove("target")
 
-	err = err.(*os.LinkError).Err
-	switch err {
-	case syscall.EWINDOWS, syscall.ERROR_PRIVILEGE_NOT_HELD:
-		supportsSymlinks = false
+	b, _ := osexec.Command("cmd", "/c", "mklink", "/?").Output()
+	if !strings.Contains(string(b), " /J ") {
+		supportJunctionLinks = false
 	}
 }
 
@@ -79,3 +87,42 @@ func TestSameWindowsFile(t *testing.T) {
 		t.Errorf("files should be same")
 	}
 }
+
+func TestStatJunctionLink(t *testing.T) {
+	if !supportJunctionLinks {
+		t.Skip("skipping because junction links are not supported")
+	}
+
+	dir, err := ioutil.TempDir("", "go-build")
+	if err != nil {
+		t.Fatalf("failed to create temp directory: %v", err)
+	}
+	defer os.RemoveAll(dir)
+
+	link := filepath.Join(filepath.Dir(dir), filepath.Base(dir)+"-link")
+
+	output, err := osexec.Command("cmd", "/c", "mklink", "/J", link, dir).CombinedOutput()
+	if err != nil {
+		t.Fatalf("failed to run mklink %v %v: %v %q", link, dir, err, output)
+	}
+	defer os.Remove(link)
+
+	fi, err := os.Stat(link)
+	if err != nil {
+		t.Fatalf("failed to stat link %v: %v", link, err)
+	}
+	expected := filepath.Base(dir)
+	got := fi.Name()
+	if !fi.IsDir() || expected != got {
+		t.Fatalf("link should point to %v but points to %v instead", expected, got)
+	}
+}
+
+func TestStartProcessAttr(t *testing.T) {
+	p, err := os.StartProcess(os.Getenv("COMSPEC"), []string{"/c", "cd"}, new(os.ProcAttr))
+	if err != nil {
+		return
+	}
+	defer p.Wait()
+	t.Fatalf("StartProcess expected to fail, but succeeded.")
+}
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 @@ const (
 	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 6f24a43..f985381 100644
--- a/src/os/path_test.go
+++ b/src/os/path_test.go
@@ -13,6 +13,8 @@ import (
 	"testing"
 )
 
+var isReadonlyError = func(error) bool { return false }
+
 func TestMkdirAll(t *testing.T) {
 	tmpDir := TempDir()
 	path := tmpDir + "/_TestMkdirAll_/dir/./dir2"
@@ -205,16 +207,22 @@ func TestMkdirAllAtSlash(t *testing.T) {
 	switch runtime.GOOS {
 	case "android", "plan9", "windows":
 		t.Skipf("skipping on %s", runtime.GOOS)
+	case "darwin":
+		switch runtime.GOARCH {
+		case "arm", "arm64":
+			t.Skipf("skipping on darwin/%s, mkdir returns EPERM", runtime.GOARCH)
+		}
 	}
 	RemoveAll("/_go_os_test")
-	err := MkdirAll("/_go_os_test/dir", 0777)
+	const dir = "/_go_os_test/dir"
+	err := MkdirAll(dir, 0777)
 	if err != nil {
 		pathErr, ok := err.(*PathError)
 		// common for users not to be able to write to /
-		if ok && pathErr.Err == syscall.EACCES {
-			return
+		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`, 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 @@ const (
 	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 @@ const (
 	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 @@ func Getgroups() ([]int, error) {
 
 // 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 d54c284..7fa6c92 100644
--- a/src/os/signal/sig.s
+++ b/src/os/signal/sig.s
@@ -4,13 +4,19 @@
 
 // Assembly to get into package runtime without using exported symbols.
 
-// +build amd64 amd64p32 arm 386
+// +build amd64 amd64p32 arm arm64 386 ppc64 ppc64le
 
 #include "textflag.h"
 
 #ifdef GOARCH_arm
 #define JMP B
 #endif
+#ifdef GOARCH_ppc64
+#define JMP BR
+#endif
+#ifdef GOARCH_ppc64le
+#define JMP BR
+#endif
 
 TEXT ·signal_disable(SB),NOSPLIT,$0
 	JMP runtime·signal_disable(SB)
@@ -18,6 +24,9 @@ TEXT ·signal_disable(SB),NOSPLIT,$0
 TEXT ·signal_enable(SB),NOSPLIT,$0
 	JMP runtime·signal_enable(SB)
 
+TEXT ·signal_ignore(SB),NOSPLIT,$0
+	JMP runtime·signal_ignore(SB)
+
 TEXT ·signal_recv(SB),NOSPLIT,$0
 	JMP runtime·signal_recv(SB)
 
diff --git a/src/os/signal/signal.go b/src/os/signal/signal.go
index 3004275..1625786 100644
--- a/src/os/signal/signal.go
+++ b/src/os/signal/signal.go
@@ -5,8 +5,6 @@
 // Package signal implements access to incoming signals.
 package signal
 
-// BUG(rsc): This package is not yet implemented on Plan 9.
-
 import (
 	"os"
 	"sync"
@@ -30,9 +28,55 @@ func (h *handler) set(sig int) {
 	h.mask[sig/32] |= 1 << uint(sig&31)
 }
 
+func (h *handler) clear(sig int) {
+	h.mask[sig/32] &^= 1 << uint(sig&31)
+}
+
+// Stop relaying the signals, sigs, to any channels previously registered to
+// receive them and either reset the signal handlers to their original values
+// (action=disableSignal) or ignore the signals (action=ignoreSignal).
+func cancel(sigs []os.Signal, action func(int)) {
+	handlers.Lock()
+	defer handlers.Unlock()
+
+	remove := func(n int) {
+		var zerohandler handler
+
+		for c, h := range handlers.m {
+			if h.want(n) {
+				handlers.ref[n]--
+				h.clear(n)
+				if h.mask == zerohandler.mask {
+					delete(handlers.m, c)
+				}
+			}
+		}
+
+		action(n)
+	}
+
+	if len(sigs) == 0 {
+		for n := 0; n < numSig; n++ {
+			remove(n)
+		}
+	} else {
+		for _, s := range sigs {
+			remove(signum(s))
+		}
+	}
+}
+
+// Ignore causes the provided signals to be ignored. If they are received by
+// the program, nothing will happen. Ignore undoes the effect of any prior
+// calls to Notify for the provided signals.
+// If no signals are provided, all incoming signals will be ignored.
+func Ignore(sig ...os.Signal) {
+	cancel(sig, ignoreSignal)
+}
+
 // Notify causes package signal to relay incoming signals to c.
-// If no signals are listed, all incoming signals will be relayed to c.
-// Otherwise, just the listed signals will.
+// If no signals are provided, all incoming signals will be relayed to c.
+// Otherwise, just the provided signals will.
 //
 // Package signal will not block sending to c: the caller must ensure
 // that c has sufficient buffer space to keep up with the expected
@@ -87,6 +131,13 @@ func Notify(c chan<- os.Signal, sig ...os.Signal) {
 	}
 }
 
+// Reset undoes the effect of any prior calls to Notify for the provided
+// signals.
+// If no signals are provided, all signal handlers will be reset.
+func Reset(sig ...os.Signal) {
+	cancel(sig, disableSignal)
+}
+
 // Stop causes package signal to stop relaying incoming signals to c.
 // It undoes the effect of all prior calls to Notify using c.
 // When Stop returns, it is guaranteed that c will receive no more signals.
diff --git a/src/os/signal/signal_plan9.go b/src/os/signal/signal_plan9.go
new file mode 100644
index 0000000..b065ae5
--- /dev/null
+++ b/src/os/signal/signal_plan9.go
@@ -0,0 +1,60 @@
+// 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.
+
+package signal
+
+import (
+	"os"
+	"syscall"
+)
+
+var sigtab = make(map[os.Signal]int)
+
+// In sig.s; jumps to runtime.
+func signal_disable(uint32)
+func signal_enable(uint32)
+func signal_ignore(uint32)
+func signal_recv() string
+
+func init() {
+	signal_enable(0) // first call - initialize
+	go loop()
+}
+
+func loop() {
+	for {
+		process(syscall.Note(signal_recv()))
+	}
+}
+
+const numSig = 256
+
+func signum(sig os.Signal) int {
+	switch sig := sig.(type) {
+	case syscall.Note:
+		n, ok := sigtab[sig]
+		if !ok {
+			n = len(sigtab) + 1
+			if n > numSig {
+				return -1
+			}
+			sigtab[sig] = n
+		}
+		return n
+	default:
+		return -1
+	}
+}
+
+func enableSignal(sig int) {
+	signal_enable(uint32(sig))
+}
+
+func disableSignal(sig int) {
+	signal_disable(uint32(sig))
+}
+
+func ignoreSignal(sig int) {
+	signal_ignore(uint32(sig))
+}
diff --git a/src/os/signal/signal_plan9_test.go b/src/os/signal/signal_plan9_test.go
new file mode 100644
index 0000000..10bfdc3
--- /dev/null
+++ b/src/os/signal/signal_plan9_test.go
@@ -0,0 +1,181 @@
+// 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 signal
+
+import (
+	"os"
+	"runtime"
+	"syscall"
+	"testing"
+	"time"
+)
+
+func waitSig(t *testing.T, c <-chan os.Signal, sig os.Signal) {
+	select {
+	case s := <-c:
+		if s != sig {
+			t.Fatalf("signal was %v, want %v", s, sig)
+		}
+	case <-time.After(1 * time.Second):
+		t.Fatalf("timeout waiting for %v", sig)
+	}
+}
+
+// Test that basic signal handling works.
+func TestSignal(t *testing.T) {
+	// Ask for hangup
+	c := make(chan os.Signal, 1)
+	Notify(c, syscall.Note("hangup"))
+	defer Stop(c)
+
+	// Send this process a hangup
+	t.Logf("hangup...")
+	postNote(syscall.Getpid(), "hangup")
+	waitSig(t, c, syscall.Note("hangup"))
+
+	// Ask for everything we can get.
+	c1 := make(chan os.Signal, 1)
+	Notify(c1)
+
+	// Send this process an alarm
+	t.Logf("alarm...")
+	postNote(syscall.Getpid(), "alarm")
+	waitSig(t, c1, syscall.Note("alarm"))
+
+	// Send two more hangups, to make sure that
+	// they get delivered on c1 and that not reading
+	// from c does not block everything.
+	t.Logf("hangup...")
+	postNote(syscall.Getpid(), "hangup")
+	waitSig(t, c1, syscall.Note("hangup"))
+	t.Logf("hangup...")
+	postNote(syscall.Getpid(), "hangup")
+	waitSig(t, c1, syscall.Note("hangup"))
+
+	// The first SIGHUP should be waiting for us on c.
+	waitSig(t, c, syscall.Note("hangup"))
+}
+
+func TestStress(t *testing.T) {
+	dur := 3 * time.Second
+	if testing.Short() {
+		dur = 100 * time.Millisecond
+	}
+	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
+	done := make(chan bool)
+	finished := make(chan bool)
+	go func() {
+		sig := make(chan os.Signal, 1)
+		Notify(sig, syscall.Note("alarm"))
+		defer Stop(sig)
+	Loop:
+		for {
+			select {
+			case <-sig:
+			case <-done:
+				break Loop
+			}
+		}
+		finished <- true
+	}()
+	go func() {
+	Loop:
+		for {
+			select {
+			case <-done:
+				break Loop
+			default:
+				postNote(syscall.Getpid(), "alarm")
+				runtime.Gosched()
+			}
+		}
+		finished <- true
+	}()
+	time.Sleep(dur)
+	close(done)
+	<-finished
+	<-finished
+	// When run with 'go test -cpu=1,2,4' alarm from this test can slip
+	// into subsequent TestSignal() causing failure.
+	// Sleep for a while to reduce the possibility of the failure.
+	time.Sleep(10 * time.Millisecond)
+}
+
+// Test that Stop cancels the channel's registrations.
+func TestStop(t *testing.T) {
+	if testing.Short() {
+		t.Skip("skipping in short mode")
+	}
+	sigs := []string{
+		"alarm",
+		"hangup",
+	}
+
+	for _, sig := range sigs {
+		// Send the signal.
+		// If it's alarm, we should not see it.
+		// If it's hangup, maybe we'll die. Let the flag tell us what to do.
+		if sig != "hangup" {
+			postNote(syscall.Getpid(), sig)
+		}
+		time.Sleep(100 * time.Millisecond)
+
+		// Ask for signal
+		c := make(chan os.Signal, 1)
+		Notify(c, syscall.Note(sig))
+		defer Stop(c)
+
+		// Send this process that signal
+		postNote(syscall.Getpid(), sig)
+		waitSig(t, c, syscall.Note(sig))
+
+		Stop(c)
+		select {
+		case s := <-c:
+			t.Fatalf("unexpected signal %v", s)
+		case <-time.After(100 * time.Millisecond):
+			// nothing to read - good
+		}
+
+		// Send the signal.
+		// If it's alarm, we should not see it.
+		// If it's hangup, maybe we'll die. Let the flag tell us what to do.
+		if sig != "hangup" {
+			postNote(syscall.Getpid(), sig)
+		}
+
+		select {
+		case s := <-c:
+			t.Fatalf("unexpected signal %v", s)
+		case <-time.After(100 * time.Millisecond):
+			// nothing to read - good
+		}
+	}
+}
+
+func itoa(val int) string {
+	if val < 0 {
+		return "-" + itoa(-val)
+	}
+	var buf [32]byte // big enough for int64
+	i := len(buf) - 1
+	for val >= 10 {
+		buf[i] = byte(val%10 + '0')
+		i--
+		val /= 10
+	}
+	buf[i] = byte(val + '0')
+	return string(buf[i:])
+}
+
+func postNote(pid int, note string) error {
+	f, err := os.OpenFile("/proc/"+itoa(pid)+"/note", os.O_WRONLY, 0)
+	if err != nil {
+		return err
+	}
+	defer f.Close()
+	_, err = f.Write([]byte(note))
+	return err
+}
diff --git a/src/os/signal/signal_stub.go b/src/os/signal/signal_stub.go
deleted file mode 100644
index d0a6935..0000000
--- a/src/os/signal/signal_stub.go
+++ /dev/null
@@ -1,17 +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.
-
-// +build plan9
-
-package signal
-
-import "os"
-
-const numSig = 0
-
-func signum(sig os.Signal) int { return -1 }
-
-func disableSignal(int) {}
-
-func enableSignal(int) {}
diff --git a/src/os/signal/signal_test.go b/src/os/signal/signal_test.go
index 22337a7..a71633c 100644
--- a/src/os/signal/signal_test.go
+++ b/src/os/signal/signal_test.go
@@ -109,6 +109,72 @@ func TestStress(t *testing.T) {
 	time.Sleep(10 * time.Millisecond)
 }
 
+func testCancel(t *testing.T, ignore bool) {
+	// Send SIGWINCH. By default this signal should be ignored.
+	syscall.Kill(syscall.Getpid(), syscall.SIGWINCH)
+	time.Sleep(100 * time.Millisecond)
+
+	// Ask to be notified on c1 when a SIGWINCH is received.
+	c1 := make(chan os.Signal, 1)
+	Notify(c1, syscall.SIGWINCH)
+	defer Stop(c1)
+
+	// Ask to be notified on c2 when a SIGHUP is received.
+	c2 := make(chan os.Signal, 1)
+	Notify(c2, syscall.SIGHUP)
+	defer Stop(c2)
+
+	// Send this process a SIGWINCH and wait for notification on c1.
+	syscall.Kill(syscall.Getpid(), syscall.SIGWINCH)
+	waitSig(t, c1, syscall.SIGWINCH)
+
+	// Send this process a SIGHUP and wait for notification on c2.
+	syscall.Kill(syscall.Getpid(), syscall.SIGHUP)
+	waitSig(t, c2, syscall.SIGHUP)
+
+	// Ignore, or reset the signal handlers for, SIGWINCH and SIGHUP.
+	if ignore {
+		Ignore(syscall.SIGWINCH, syscall.SIGHUP)
+	} else {
+		Reset(syscall.SIGWINCH, syscall.SIGHUP)
+	}
+
+	// Send this process a SIGWINCH. It should be ignored.
+	syscall.Kill(syscall.Getpid(), syscall.SIGWINCH)
+
+	// If ignoring, Send this process a SIGHUP. It should be ignored.
+	if ignore {
+		syscall.Kill(syscall.Getpid(), syscall.SIGHUP)
+	}
+
+	select {
+	case s := <-c1:
+		t.Fatalf("unexpected signal %v", s)
+	case <-time.After(100 * time.Millisecond):
+		// nothing to read - good
+	}
+
+	select {
+	case s := <-c2:
+		t.Fatalf("unexpected signal %v", s)
+	case <-time.After(100 * time.Millisecond):
+		// nothing to read - good
+	}
+
+	// Reset the signal handlers for all signals.
+	Reset()
+}
+
+// Test that Reset cancels registration for listed signals on all channels.
+func TestReset(t *testing.T) {
+	testCancel(t, false)
+}
+
+// Test that Ignore cancels registration for listed signals on all channels.
+func TestIgnore(t *testing.T) {
+	testCancel(t, true)
+}
+
 var sendUncaughtSighup = flag.Int("send_uncaught_sighup", 0, "send uncaught SIGHUP during TestStop")
 
 // Test that Stop cancels the channel's registrations.
diff --git a/src/os/signal/signal_unix.go b/src/os/signal/signal_unix.go
index 94b8ab3..1bdf1d7 100644
--- a/src/os/signal/signal_unix.go
+++ b/src/os/signal/signal_unix.go
@@ -14,6 +14,7 @@ import (
 // In assembly.
 func signal_disable(uint32)
 func signal_enable(uint32)
+func signal_ignore(uint32)
 func signal_recv() uint32
 
 func loop() {
@@ -51,3 +52,7 @@ func enableSignal(sig int) {
 func disableSignal(sig int) {
 	signal_disable(uint32(sig))
 }
+
+func ignoreSignal(sig int) {
+	signal_ignore(uint32(sig))
+}
diff --git a/src/os/stat_plan9.go b/src/os/stat_plan9.go
index 25c9a8c..fa4bd83 100644
--- a/src/os/stat_plan9.go
+++ b/src/os/stat_plan9.go
@@ -9,6 +9,8 @@ import (
 	"time"
 )
 
+const _BIT16SZ = 2
+
 func sameFile(fs1, fs2 *fileStat) bool {
 	a := fs1.sys.(*syscall.Dir)
 	b := fs2.sys.(*syscall.Dir)
@@ -41,16 +43,14 @@ func fileInfoFromStat(d *syscall.Dir) FileInfo {
 // arg is an open *File or a path string.
 func dirstat(arg interface{}) (*syscall.Dir, error) {
 	var name string
+	var err error
 
-	// This is big enough for most stat messages
-	// and rounded to a multiple of 128 bytes.
-	size := (syscall.STATFIXLEN + 16*4 + 128) &^ 128
+	size := syscall.STATFIXLEN + 16*4
 
 	for i := 0; i < 2; i++ {
-		buf := make([]byte, size)
+		buf := make([]byte, _BIT16SZ+size)
 
 		var n int
-		var err error
 		switch a := arg.(type) {
 		case *File:
 			name = a.name
@@ -61,34 +61,36 @@ func dirstat(arg interface{}) (*syscall.Dir, error) {
 		default:
 			panic("phase error in dirstat")
 		}
-		if err != nil {
+
+		if n < _BIT16SZ {
 			return nil, &PathError{"stat", name, err}
 		}
-		if n < syscall.STATFIXLEN {
-			return nil, &PathError{"stat", name, syscall.ErrShortStat}
-		}
 
 		// Pull the real size out of the stat message.
 		size = int(uint16(buf[0]) | uint16(buf[1])<<8)
 
 		// If the stat message is larger than our buffer we will
 		// go around the loop and allocate one that is big enough.
-		if size > n {
-			continue
+		if size <= n {
+			d, err := syscall.UnmarshalDir(buf[:n])
+			if err != nil {
+				return nil, &PathError{"stat", name, err}
+			}
+			return d, nil
 		}
 
-		d, err := syscall.UnmarshalDir(buf[:n])
-		if err != nil {
-			return nil, &PathError{"stat", name, err}
-		}
-		return d, nil
 	}
-	return nil, &PathError{"stat", name, syscall.ErrBadStat}
+
+	if err == nil {
+		err = syscall.ErrBadStat
+	}
+
+	return nil, &PathError{"stat", name, err}
 }
 
 // Stat returns a FileInfo describing the named file.
 // If there is an error, it will be of type *PathError.
-func Stat(name string) (fi FileInfo, err error) {
+func Stat(name string) (FileInfo, error) {
 	d, err := dirstat(name)
 	if err != nil {
 		return nil, err
@@ -100,7 +102,7 @@ func Stat(name string) (fi FileInfo, err error) {
 // If the file is a symbolic link, the returned FileInfo
 // describes the symbolic link.  Lstat makes no attempt to follow the link.
 // If there is an error, it will be of type *PathError.
-func Lstat(name string) (fi FileInfo, err error) {
+func Lstat(name string) (FileInfo, error) {
 	return Stat(name)
 }
 
diff --git a/src/os/stat_windows.go b/src/os/stat_windows.go
index f396c1d..966163b 100644
--- a/src/os/stat_windows.go
+++ b/src/os/stat_windows.go
@@ -11,7 +11,7 @@ import (
 
 // Stat returns the FileInfo structure describing file.
 // If there is an error, it will be of type *PathError.
-func (file *File) Stat() (fi FileInfo, err error) {
+func (file *File) Stat() (FileInfo, error) {
 	if file == nil {
 		return nil, ErrInvalid
 	}
@@ -48,28 +48,29 @@ func (file *File) Stat() (fi FileInfo, err error) {
 
 // Stat returns a FileInfo structure describing the named file.
 // If there is an error, it will be of type *PathError.
-func Stat(name string) (fi FileInfo, err error) {
+func Stat(name string) (FileInfo, error) {
+	var fi FileInfo
+	var err error
 	for {
 		fi, err = Lstat(name)
 		if err != nil {
-			return
+			return fi, err
 		}
 		if fi.Mode()&ModeSymlink == 0 {
-			return
+			return fi, nil
 		}
 		name, err = Readlink(name)
 		if err != nil {
-			return
+			return fi, err
 		}
 	}
-	return fi, err
 }
 
 // Lstat returns the FileInfo structure describing the named file.
 // If the file is a symbolic link, the returned FileInfo
 // describes the symbolic link.  Lstat makes no attempt to follow the link.
 // If there is an error, it will be of type *PathError.
-func Lstat(name string) (fi FileInfo, err error) {
+func Lstat(name string) (FileInfo, error) {
 	if len(name) == 0 {
 		return nil, &PathError{"Lstat", name, syscall.Errno(syscall.ERROR_PATH_NOT_FOUND)}
 	}
diff --git a/src/os/sticky_bsd.go b/src/os/sticky_bsd.go
new file mode 100644
index 0000000..6b54c75
--- /dev/null
+++ b/src/os/sticky_bsd.go
@@ -0,0 +1,11 @@
+// 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 darwin dragonfly freebsd netbsd openbsd solaris
+
+package os
+
+// According to sticky(8), neither open(2) nor mkdir(2) will create
+// a file with the sticky bit set.
+const supportsCreateWithStickyBit = false
diff --git a/src/os/sticky_notbsd.go b/src/os/sticky_notbsd.go
new file mode 100644
index 0000000..834e79b
--- /dev/null
+++ b/src/os/sticky_notbsd.go
@@ -0,0 +1,14 @@
+// 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 !darwin
+// +build !dragonfly
+// +build !freebsd
+// +build !netbsd
+// +build !openbsd
+// +build !solaris
+
+package os
+
+const supportsCreateWithStickyBit = true
diff --git a/src/os/str.go b/src/os/str.go
index e3606b6..d3e03e9 100644
--- a/src/os/str.go
+++ b/src/os/str.go
@@ -2,21 +2,32 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build plan9
+// Simple converions to avoid depending on strconv.
 
 package os
 
-func itoa(val int) string { // do it here rather than with fmt to avoid dependency
+// Convert integer to decimal string
+func itoa(val int) string {
 	if val < 0 {
-		return "-" + itoa(-val)
+		return "-" + uitoa(uint(-val))
 	}
-	var buf [32]byte // big enough for int64
+	return uitoa(uint(val))
+}
+
+// Convert unsigned integer to decimal string
+func uitoa(val uint) string {
+	if val == 0 { // avoid string allocation
+		return "0"
+	}
+	var buf [20]byte // big enough for 64bit value base 10
 	i := len(buf) - 1
 	for val >= 10 {
-		buf[i] = byte(val%10 + '0')
+		q := val / 10
+		buf[i] = byte('0' + val - q*10)
 		i--
-		val /= 10
+		val = q
 	}
-	buf[i] = byte(val + '0')
+	// val < 10
+	buf[i] = byte('0' + val)
 	return string(buf[i:])
 }
diff --git a/src/os/sys_windows.go b/src/os/sys_windows.go
index 92617de..9490ea6 100644
--- a/src/os/sys_windows.go
+++ b/src/os/sys_windows.go
@@ -4,12 +4,30 @@
 
 package os
 
-import "syscall"
+import (
+	"internal/syscall/windows"
+	"syscall"
+)
 
 func hostname() (name string, err error) {
-	s, e := syscall.ComputerName()
-	if e != nil {
-		return "", NewSyscallError("ComputerName", e)
+	// Use PhysicalDnsHostname to uniquely identify host in a cluster
+	const format = windows.ComputerNamePhysicalDnsHostname
+
+	n := uint32(64)
+	for {
+		b := make([]uint16, n)
+		err := windows.GetComputerNameEx(format, &b[0], &n)
+		if err == nil {
+			return syscall.UTF16ToString(b[:n]), nil
+		}
+		if err != syscall.ERROR_MORE_DATA {
+			return "", NewSyscallError("ComputerNameEx", err)
+		}
+
+		// If we received a ERROR_MORE_DATA, but n doesn't get larger,
+		// something has gone wrong and we may be in an infinite loop
+		if n <= uint32(len(b)) {
+			return "", NewSyscallError("ComputerNameEx", err)
+		}
 	}
-	return s, nil
 }
diff --git a/src/os/types.go b/src/os/types.go
index 473d431..9d6f8e1 100644
--- a/src/os/types.go
+++ b/src/os/types.go
@@ -53,7 +53,7 @@ const (
 	// Mask for the type bits. For regular files, none will be set.
 	ModeType = ModeDir | ModeSymlink | ModeNamedPipe | ModeSocket | ModeDevice
 
-	ModePerm FileMode = 0777 // permission bits
+	ModePerm FileMode = 0777 // Unix permission bits
 )
 
 func (m FileMode) String() string {
diff --git a/src/os/user/lookup_unix.go b/src/os/user/lookup_unix.go
index 0871473..f4f603e 100644
--- a/src/os/user/lookup_unix.go
+++ b/src/os/user/lookup_unix.go
@@ -17,6 +17,7 @@ import (
 )
 
 /*
+#cgo solaris CFLAGS: -D_POSIX_PTHREAD_SEMANTICS
 #include <unistd.h>
 #include <sys/types.h>
 #include <pwd.h>
@@ -24,7 +25,12 @@ import (
 
 static int mygetpwuid_r(int uid, struct passwd *pwd,
 	char *buf, size_t buflen, struct passwd **result) {
- return getpwuid_r(uid, pwd, buf, buflen, result);
+	return getpwuid_r(uid, pwd, buf, buflen, result);
+}
+
+static int mygetpwnam_r(const char *name, struct passwd *pwd,
+	char *buf, size_t buflen, struct passwd **result) {
+	return getpwnam_r(name, pwd, buf, buflen, result);
 }
 */
 import "C"
@@ -67,7 +73,11 @@ func lookupUnix(uid int, username string, lookupByName bool) (*User, error) {
 	if lookupByName {
 		nameC := C.CString(username)
 		defer C.free(unsafe.Pointer(nameC))
-		rv = C.getpwnam_r(nameC,
+		// mygetpwnam_r is a wrapper around getpwnam_r to avoid
+		// passing a size_t to getpwnam_r, because for unknown
+		// reasons passing a size_t to getpwnam_r doesn't work on
+		// Solaris.
+		rv = C.mygetpwnam_r(nameC,
 			&pwd,
 			(*C.char)(buf),
 			C.size_t(bufSize),
diff --git a/src/path/filepath/example_unix_test.go b/src/path/filepath/example_unix_test.go
index f3fe076..27d85d1 100644
--- a/src/path/filepath/example_unix_test.go
+++ b/src/path/filepath/example_unix_test.go
@@ -37,3 +37,31 @@ func ExampleRel() {
 	// "/b/c": "../b/c" <nil>
 	// "./b/c": "" Rel: can't make b/c relative to /a
 }
+
+func ExampleSplit() {
+	paths := []string{
+		"/home/arnie/amelia.jpg",
+		"/mnt/photos/",
+		"rabbit.jpg",
+		"/usr/local//go",
+	}
+	fmt.Println("On Unix:")
+	for _, p := range paths {
+		dir, file := filepath.Split(p)
+		fmt.Printf("input: %q\n\tdir: %q\n\tfile: %q\n", p, dir, file)
+	}
+	// Output:
+	// On Unix:
+	// input: "/home/arnie/amelia.jpg"
+	// 	dir: "/home/arnie/"
+	// 	file: "amelia.jpg"
+	// input: "/mnt/photos/"
+	// 	dir: "/mnt/photos/"
+	// 	file: ""
+	// input: "rabbit.jpg"
+	// 	dir: ""
+	// 	file: "rabbit.jpg"
+	// input: "/usr/local//go"
+	// 	dir: "/usr/local//"
+	// 	file: "go"
+}
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 @@ import (
 // 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 @@ func glob(dir, pattern string, matches []string) (m []string, e error) {
 	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 d37fc9d..5dc5cfd 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 @@ func FromSlash(path string) string {
 
 // 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)
 }
@@ -196,13 +200,10 @@ func Split(path string) (dir, file string) {
 // Join joins any number of path elements into a single path, adding
 // a Separator if necessary. The result is Cleaned, in particular
 // all empty strings are ignored.
+// On Windows, the result is a UNC path if and only if the first path
+// element is a UNC path.
 func Join(elem ...string) string {
-	for i, e := range elem {
-		if e != "" {
-			return Clean(strings.Join(elem[i:], string(Separator)))
-		}
-	}
-	return ""
+	return join(elem)
 }
 
 // Ext returns the file name extension used by path.
@@ -334,10 +335,11 @@ var SkipDir = errors.New("skip this directory")
 // If there was a problem walking to the file or directory named by path, the
 // incoming error will describe the problem and the function can decide how
 // to handle that error (and Walk will not descend into that directory). If
-// an error is returned, processing stops. The sole exception is that if path
-// is a directory and the function returns the special value SkipDir, the
-// contents of the directory are skipped and processing continues as usual on
-// the next file.
+// an error is returned, processing stops. The sole exception is when the function
+// returns the special value SkipDir. If the function returns SkipDir when invoked
+// on a directory, Walk skips the directory's contents entirely.
+// If the function returns SkipDir when invoked on a non-directory file,
+// Walk skips the remaining files in the containing directory.
 type WalkFunc func(path string, info os.FileInfo, err error) error
 
 var lstat = os.Lstat // for testing
@@ -456,9 +458,9 @@ func Dir(path string) string {
 }
 
 // VolumeName returns leading volume name.
-// Given "C:\foo\bar" it returns "C:" under windows.
+// Given "C:\foo\bar" it returns "C:" on Windows.
 // Given "\\host\share\foo" it returns "\\host\share".
 // On other platforms it returns "".
-func VolumeName(path string) (v string) {
+func VolumeName(path string) string {
 	return path[:volumeNameLen(path)]
 }
diff --git a/src/path/filepath/path_plan9.go b/src/path/filepath/path_plan9.go
index ee8912d..962774e 100644
--- a/src/path/filepath/path_plan9.go
+++ b/src/path/filepath/path_plan9.go
@@ -6,7 +6,7 @@ package filepath
 
 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, "#")
 }
@@ -32,3 +32,13 @@ func splitList(path string) []string {
 func abs(path string) (string, error) {
 	return unixAbs(path)
 }
+
+func join(elem []string) string {
+	// If there's a bug here, fix the logic in ./path_unix.go too.
+	for i, e := range elem {
+		if e != "" {
+			return Clean(strings.Join(elem[i:], string(Separator)))
+		}
+	}
+	return ""
+}
diff --git a/src/path/filepath/path_test.go b/src/path/filepath/path_test.go
index 399284b..1c32e27 100644
--- a/src/path/filepath/path_test.go
+++ b/src/path/filepath/path_test.go
@@ -242,6 +242,7 @@ var jointests = []JoinTest{
 
 	// one parameter
 	{[]string{""}, ""},
+	{[]string{"/"}, "/"},
 	{[]string{"a"}, "a"},
 
 	// two parameters
@@ -249,10 +250,16 @@ var jointests = []JoinTest{
 	{[]string{"a", ""}, "a"},
 	{[]string{"", "b"}, "b"},
 	{[]string{"/", "a"}, "/a"},
+	{[]string{"/", "a/b"}, "/a/b"},
 	{[]string{"/", ""}, "/"},
+	{[]string{"//", "a"}, "/a"},
+	{[]string{"/a", "b"}, "/a/b"},
 	{[]string{"a/", "b"}, "a/b"},
 	{[]string{"a/", ""}, "a"},
 	{[]string{"", ""}, ""},
+
+	// three parameters
+	{[]string{"/", "a", "b"}, "/a/b"},
 }
 
 var winjointests = []JoinTest{
@@ -262,13 +269,17 @@ var winjointests = []JoinTest{
 	{[]string{`C:\`, `Windows`}, `C:\Windows`},
 	{[]string{`C:`, `Windows`}, `C:\Windows`},
 	{[]string{`\\host\share`, `foo`}, `\\host\share\foo`},
+	{[]string{`\\host\share\foo`}, `\\host\share\foo`},
 	{[]string{`//host/share`, `foo/bar`}, `\\host\share\foo\bar`},
-}
-
-// join takes a []string and passes it to Join.
-func join(elem []string, args ...string) string {
-	args = elem
-	return filepath.Join(args...)
+	{[]string{`\`}, `\`},
+	{[]string{`\`, ``}, `\`},
+	{[]string{`\`, `a`}, `\a`},
+	{[]string{`\\`, `a`}, `\a`},
+	{[]string{`\`, `a`, `b`}, `\a\b`},
+	{[]string{`\\`, `a`, `b`}, `\a\b`},
+	{[]string{`\`, `\\a\b`, `c`}, `\a\b\c`},
+	{[]string{`\\a`, `b`, `c`}, `\a\b\c`},
+	{[]string{`\\a\`, `b`, `c`}, `\a\b\c`},
 }
 
 func TestJoin(t *testing.T) {
@@ -276,8 +287,9 @@ func TestJoin(t *testing.T) {
 		jointests = append(jointests, winjointests...)
 	}
 	for _, test := range jointests {
-		if p := join(test.elem); p != filepath.FromSlash(test.path) {
-			t.Errorf("join(%q) = %q, want %q", test.elem, p, test.path)
+		expected := filepath.FromSlash(test.path)
+		if p := filepath.Join(test.elem...); p != expected {
+			t.Errorf("join(%q) = %q, want %q", test.elem, p, expected)
 		}
 	}
 }
@@ -387,7 +399,34 @@ func mark(path string, info os.FileInfo, err error, errors *[]error, clear bool)
 	return nil
 }
 
+func chtmpdir(t *testing.T) (restore func()) {
+	oldwd, err := os.Getwd()
+	if err != nil {
+		t.Fatal("chtmpdir: %v", err)
+	}
+	d, err := ioutil.TempDir("", "test")
+	if err != nil {
+		t.Fatal("chtmpdir: %v", err)
+	}
+	if err := os.Chdir(d); err != nil {
+		t.Fatal("chtmpdir: %v", err)
+	}
+	return func() {
+		if err := os.Chdir(oldwd); err != nil {
+			t.Fatal("chtmpdir: %v", err)
+		}
+		os.RemoveAll(d)
+	}
+}
+
 func TestWalk(t *testing.T) {
+	if runtime.GOOS == "darwin" {
+		switch runtime.GOARCH {
+		case "arm", "arm64":
+			restore := chtmpdir(t)
+			defer restore()
+		}
+	}
 	makeTree(t)
 	errors := make([]error, 0, 10)
 	clear := true
@@ -471,6 +510,35 @@ func touch(t *testing.T, name string) {
 	}
 }
 
+func TestWalkSkipDirOnFile(t *testing.T) {
+	td, err := ioutil.TempDir("", "walktest")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(td)
+
+	if err := os.MkdirAll(filepath.Join(td, "dir"), 0755); err != nil {
+		t.Fatal(err)
+	}
+	touch(t, filepath.Join(td, "dir/foo1"))
+	touch(t, filepath.Join(td, "dir/foo2"))
+
+	sawFoo2 := false
+	filepath.Walk(td, func(path string, info os.FileInfo, err error) error {
+		if strings.HasSuffix(path, "foo2") {
+			sawFoo2 = true
+		}
+		if strings.HasSuffix(path, "foo1") {
+			return filepath.SkipDir
+		}
+		return nil
+	})
+
+	if sawFoo2 {
+		t.Errorf("SkipDir on file foo1 did not block processing of foo2")
+	}
+}
+
 func TestWalkFileError(t *testing.T) {
 	td, err := ioutil.TempDir("", "walktest")
 	if err != nil {
@@ -996,7 +1064,13 @@ func TestDriveLetterInEvalSymlinks(t *testing.T) {
 	}
 }
 
-func TestBug3486(t *testing.T) { // http://code.google.com/p/go/issues/detail?id=3486
+func TestBug3486(t *testing.T) { // https://golang.org/issue/3486
+	if runtime.GOOS == "darwin" {
+		switch runtime.GOARCH {
+		case "arm", "arm64":
+			t.Skipf("skipping on %s/%s", runtime.GOOS, runtime.GOARCH)
+		}
+	}
 	root, err := filepath.EvalSymlinks(runtime.GOROOT() + "/test")
 	if err != nil {
 		t.Fatal(err)
diff --git a/src/path/filepath/path_unix.go b/src/path/filepath/path_unix.go
index 4e7d0d1..d241d78 100644
--- a/src/path/filepath/path_unix.go
+++ b/src/path/filepath/path_unix.go
@@ -8,7 +8,7 @@ package filepath
 
 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, "/")
 }
@@ -34,3 +34,13 @@ func splitList(path string) []string {
 func abs(path string) (string, error) {
 	return unixAbs(path)
 }
+
+func join(elem []string) string {
+	// If there's a bug here, fix the logic in ./path_plan9.go too.
+	for i, e := range elem {
+		if e != "" {
+			return Clean(strings.Join(elem[i:], string(Separator)))
+		}
+	}
+	return ""
+}
diff --git a/src/path/filepath/path_windows.go b/src/path/filepath/path_windows.go
index ec50f6b..bcfe0a3 100644
--- a/src/path/filepath/path_windows.go
+++ b/src/path/filepath/path_windows.go
@@ -13,7 +13,7 @@ func isSlash(c uint8) bool {
 	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 {
@@ -108,3 +108,40 @@ func splitList(path string) []string {
 func abs(path string) (string, error) {
 	return syscall.FullPath(path)
 }
+
+func join(elem []string) string {
+	for i, e := range elem {
+		if e != "" {
+			return joinNonEmpty(elem[i:])
+		}
+	}
+	return ""
+}
+
+// joinNonEmpty is like join, but it assumes that the first element is non-empty.
+func joinNonEmpty(elem []string) string {
+	// The following logic prevents Join from inadvertently creating a
+	// UNC path on Windows. Unless the first element is a UNC path, Join
+	// shouldn't create a UNC path. See golang.org/issue/9167.
+	p := Clean(strings.Join(elem, string(Separator)))
+	if !isUNC(p) {
+		return p
+	}
+	// p == UNC only allowed when the first element is a UNC path.
+	head := Clean(elem[0])
+	if isUNC(head) {
+		return p
+	}
+	// head + tail == UNC, but joining two non-UNC paths should not result
+	// in a UNC path. Undo creation of UNC path.
+	tail := Clean(strings.Join(elem[1:], string(Separator)))
+	if head[len(head)-1] == Separator {
+		return head + tail
+	}
+	return head + string(Separator) + tail
+}
+
+// isUNC reports whether path is a UNC path.
+func isUNC(path string) bool {
+	return volumeNameLen(path) > 2
+}
diff --git a/src/path/filepath/symlink_windows.go b/src/path/filepath/symlink_windows.go
index 327c2c8..4b38f6f 100644
--- a/src/path/filepath/symlink_windows.go
+++ b/src/path/filepath/symlink_windows.go
@@ -14,18 +14,17 @@ func toShort(path string) (string, error) {
 		return "", err
 	}
 	b := p // GetShortPathName says we can reuse buffer
-	n, err := syscall.GetShortPathName(&p[0], &b[0], uint32(len(b)))
-	if err != nil {
-		return "", err
-	}
-	if n > uint32(len(b)) {
-		b = make([]uint16, n)
+	n := uint32(len(b))
+	for {
 		n, err = syscall.GetShortPathName(&p[0], &b[0], uint32(len(b)))
 		if err != nil {
 			return "", err
 		}
+		if n <= uint32(len(b)) {
+			return syscall.UTF16ToString(b[:n]), nil
+		}
+		b = make([]uint16, n)
 	}
-	return syscall.UTF16ToString(b), nil
 }
 
 func toLong(path string) (string, error) {
@@ -34,19 +33,17 @@ func toLong(path string) (string, error) {
 		return "", err
 	}
 	b := p // GetLongPathName says we can reuse buffer
-	n, err := syscall.GetLongPathName(&p[0], &b[0], uint32(len(b)))
-	if err != nil {
-		return "", err
-	}
-	if n > uint32(len(b)) {
-		b = make([]uint16, n)
+	n := uint32(len(b))
+	for {
 		n, err = syscall.GetLongPathName(&p[0], &b[0], uint32(len(b)))
 		if err != nil {
 			return "", err
 		}
+		if n <= uint32(len(b)) {
+			return syscall.UTF16ToString(b[:n]), nil
+		}
+		b = make([]uint16, n)
 	}
-	b = b[:n]
-	return syscall.UTF16ToString(b), nil
 }
 
 func evalSymlinks(path string) (string, error) {
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 @@ import (
 // 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..77f2185 100644
--- a/src/path/path.go
+++ b/src/path/path.go
@@ -134,7 +134,7 @@ func Clean(path string) string {
 	return out.string()
 }
 
-// Split splits path immediately following the final slash.
+// Split splits path immediately following the final slash,
 // separating it into a directory and file name component.
 // If there is no slash path, Split returns an empty dir and
 // file set to path.
@@ -192,7 +192,7 @@ func Base(path string) string {
 	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/race.bash b/src/race.bash
index 6225840..e091736 100755
--- a/src/race.bash
+++ b/src/race.bash
@@ -4,7 +4,7 @@
 # license that can be found in the LICENSE file.
 
 # race.bash tests the standard library under the race detector.
-# http://golang.org/doc/articles/race_detector.html
+# https://golang.org/doc/articles/race_detector.html
 
 set -e
 
@@ -40,14 +40,5 @@ if [ ! -f make.bash ]; then
 	exit 1
 fi
 . ./make.bash --no-banner
-# golang.org/issue/5537 - we must build a race enabled cmd/cgo before trying to use it.
-go install -race cmd/cgo
 go install -race std
-
-# 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
-
-go test -race -short std
-go test -race -run=nothingplease -bench=.* -benchtime=.1s -cpu=4 std
+go tool dist test -no-rebuild -race
diff --git a/src/race.bat b/src/race.bat
index 8858c57..33db692 100644
--- a/src/race.bat
+++ b/src/race.bat
@@ -3,7 +3,7 @@
 :: license that can be found in the LICENSE file.
 
 :: race.bash tests the standard library under the race detector.
-:: http://golang.org/doc/articles/race_detector.html
+:: https://golang.org/doc/articles/race_detector.html
 
 @echo off
 
@@ -18,7 +18,7 @@ goto end
 set GOROOT=%CD%\..
 call make.bat --dist-tool >NUL
 if errorlevel 1 goto fail
-.\cmd\dist\dist env -wp >env.bat
+.\cmd\dist\dist env -w -p >env.bat
 if errorlevel 1 goto fail
 call env.bat
 del env.bat
@@ -30,23 +30,12 @@ goto fail
 :continue
 call make.bat --no-banner --no-local
 if %GOBUILDFAIL%==1 goto end
-:: golang.org/issue/5537 - we must build a race enabled cmd/cgo before trying to use it.
-echo # go install -race cmd/cgo
-go install -race cmd/cgo
 echo # go install -race std
 go install -race std
 if errorlevel 1 goto fail
 
-:: 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.
-set GOROOT_FINAL=
+go tool dist test -no-rebuild -race
 
-echo # go test -race -short std
-go test -race -short std
-if errorlevel 1 goto fail
-echo # go test -race -run=nothingplease -bench=.* -benchtime=.1s -cpu=4 std
-go test -race -run=nothingplease -bench=.* -benchtime=.1s -cpu=4 std
 if errorlevel 1 goto fail
 goto succ
 
diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go
index 7a01c95..1748bf6 100644
--- a/src/reflect/all_test.go
+++ b/src/reflect/all_test.go
@@ -15,6 +15,7 @@ import (
 	. "reflect"
 	"runtime"
 	"sort"
+	"strconv"
 	"strings"
 	"sync"
 	"testing"
@@ -1052,6 +1053,11 @@ func TestChan(t *testing.T) {
 		ok = cv.TrySend(ValueOf(6))
 		if !ok {
 			t.Errorf("TrySend on empty chan failed")
+			select {
+			case x := <-c:
+				t.Errorf("TrySend failed but it did send %d", x)
+			default:
+			}
 		} else {
 			if i = <-c; i != 6 {
 				t.Errorf("TrySend 6, recv %d", i)
@@ -1376,7 +1382,7 @@ func selectWatcher() {
 	for {
 		time.Sleep(1 * time.Second)
 		selectWatch.Lock()
-		if selectWatch.info != nil && time.Since(selectWatch.now) > 1*time.Second {
+		if selectWatch.info != nil && time.Since(selectWatch.now) > 10*time.Second {
 			fmt.Fprintf(os.Stderr, "TestSelect:\n%s blocked indefinitely\n", fmtSelect(selectWatch.info))
 			panic("select stuck")
 		}
@@ -1501,6 +1507,17 @@ func TestCallWithStruct(t *testing.T) {
 	}
 }
 
+func BenchmarkCall(b *testing.B) {
+	fv := ValueOf(func(a, b string) {})
+	b.ReportAllocs()
+	b.RunParallel(func(pb *testing.PB) {
+		args := []Value{ValueOf("a"), ValueOf("b")}
+		for pb.Next() {
+			fv.Call(args)
+		}
+	})
+}
+
 func TestMakeFunc(t *testing.T) {
 	f := dummy
 	fv := MakeFunc(TypeOf(f), func(in []Value) []Value { return in })
@@ -2719,6 +2736,8 @@ var tagGetTests = []struct {
 	{`protobuf:"PB(1,2)"`, `rotobuf`, ``},
 	{`protobuf:"PB(1,2)" json:"name"`, `json`, `name`},
 	{`protobuf:"PB(1,2)" json:"name"`, `protobuf`, `PB(1,2)`},
+	{`k0:"values contain spaces" k1:"and\ttabs"`, "k0", "values contain spaces"},
+	{`k0:"values contain spaces" k1:"and\ttabs"`, "k1", "and\ttabs"},
 }
 
 func TestTagGet(t *testing.T) {
@@ -3370,26 +3389,242 @@ func checkSameType(t *testing.T, x, y interface{}) {
 }
 
 func TestArrayOf(t *testing.T) {
-	// TODO(rsc): Finish ArrayOf and enable-test.
-	t.Skip("ArrayOf is not finished (and not exported)")
-
 	// check construction and use of type not in binary
-	type T int
-	at := ArrayOf(10, TypeOf(T(1)))
-	v := New(at).Elem()
-	for i := 0; i < v.Len(); i++ {
-		v.Index(i).Set(ValueOf(T(i)))
-	}
-	s := fmt.Sprint(v.Interface())
-	want := "[0 1 2 3 4 5 6 7 8 9]"
-	if s != want {
-		t.Errorf("constructed array = %s, want %s", s, want)
+	for _, table := range []struct {
+		n          int
+		value      func(i int) interface{}
+		comparable bool
+		want       string
+	}{
+		{
+			n:          0,
+			value:      func(i int) interface{} { type Tint int; return Tint(i) },
+			comparable: true,
+			want:       "[]",
+		},
+		{
+			n:          10,
+			value:      func(i int) interface{} { type Tint int; return Tint(i) },
+			comparable: true,
+			want:       "[0 1 2 3 4 5 6 7 8 9]",
+		},
+		{
+			n:          10,
+			value:      func(i int) interface{} { type Tfloat float64; return Tfloat(i) },
+			comparable: true,
+			want:       "[0 1 2 3 4 5 6 7 8 9]",
+		},
+		{
+			n:          10,
+			value:      func(i int) interface{} { type Tstring string; return Tstring(strconv.Itoa(i)) },
+			comparable: true,
+			want:       "[0 1 2 3 4 5 6 7 8 9]",
+		},
+		{
+			n:          10,
+			value:      func(i int) interface{} { type Tstruct struct{ V int }; return Tstruct{i} },
+			comparable: true,
+			want:       "[{0} {1} {2} {3} {4} {5} {6} {7} {8} {9}]",
+		},
+		{
+			n:          10,
+			value:      func(i int) interface{} { type Tint int; return []Tint{Tint(i)} },
+			comparable: false,
+			want:       "[[0] [1] [2] [3] [4] [5] [6] [7] [8] [9]]",
+		},
+		{
+			n:          10,
+			value:      func(i int) interface{} { type Tint int; return [1]Tint{Tint(i)} },
+			comparable: true,
+			want:       "[[0] [1] [2] [3] [4] [5] [6] [7] [8] [9]]",
+		},
+		{
+			n:          10,
+			value:      func(i int) interface{} { type Tstruct struct{ V [1]int }; return Tstruct{[1]int{i}} },
+			comparable: true,
+			want:       "[{[0]} {[1]} {[2]} {[3]} {[4]} {[5]} {[6]} {[7]} {[8]} {[9]}]",
+		},
+		{
+			n:          10,
+			value:      func(i int) interface{} { type Tstruct struct{ V []int }; return Tstruct{[]int{i}} },
+			comparable: false,
+			want:       "[{[0]} {[1]} {[2]} {[3]} {[4]} {[5]} {[6]} {[7]} {[8]} {[9]}]",
+		},
+		{
+			n:          10,
+			value:      func(i int) interface{} { type TstructUV struct{ U, V int }; return TstructUV{i, i} },
+			comparable: true,
+			want:       "[{0 0} {1 1} {2 2} {3 3} {4 4} {5 5} {6 6} {7 7} {8 8} {9 9}]",
+		},
+		{
+			n: 10,
+			value: func(i int) interface{} {
+				type TstructUV struct {
+					U int
+					V float64
+				}
+				return TstructUV{i, float64(i)}
+			},
+			comparable: true,
+			want:       "[{0 0} {1 1} {2 2} {3 3} {4 4} {5 5} {6 6} {7 7} {8 8} {9 9}]",
+		},
+	} {
+		at := ArrayOf(table.n, TypeOf(table.value(0)))
+		v := New(at).Elem()
+		vok := New(at).Elem()
+		vnot := New(at).Elem()
+		for i := 0; i < v.Len(); i++ {
+			v.Index(i).Set(ValueOf(table.value(i)))
+			vok.Index(i).Set(ValueOf(table.value(i)))
+			j := i
+			if i+1 == v.Len() {
+				j = i + 1
+			}
+			vnot.Index(i).Set(ValueOf(table.value(j))) // make it differ only by last element
+		}
+		s := fmt.Sprint(v.Interface())
+		if s != table.want {
+			t.Errorf("constructed array = %s, want %s", s, table.want)
+		}
+
+		if table.comparable != at.Comparable() {
+			t.Errorf("constructed array (%#v) is comparable=%v, want=%v", v.Interface(), at.Comparable(), table.comparable)
+		}
+		if table.comparable {
+			if table.n > 0 {
+				if DeepEqual(vnot.Interface(), v.Interface()) {
+					t.Errorf(
+						"arrays (%#v) compare ok (but should not)",
+						v.Interface(),
+					)
+				}
+			}
+			if !DeepEqual(vok.Interface(), v.Interface()) {
+				t.Errorf(
+					"arrays (%#v) compare NOT-ok (but should)",
+					v.Interface(),
+				)
+			}
+		}
 	}
 
 	// check that type already in binary is found
+	type T int
 	checkSameType(t, Zero(ArrayOf(5, TypeOf(T(1)))).Interface(), [5]T{})
 }
 
+func TestArrayOfGC(t *testing.T) {
+	type T *uintptr
+	tt := TypeOf(T(nil))
+	const n = 100
+	var x []interface{}
+	for i := 0; i < n; i++ {
+		v := New(ArrayOf(n, tt)).Elem()
+		for j := 0; j < v.Len(); j++ {
+			p := new(uintptr)
+			*p = uintptr(i*n + j)
+			v.Index(j).Set(ValueOf(p).Convert(tt))
+		}
+		x = append(x, v.Interface())
+	}
+	runtime.GC()
+
+	for i, xi := range x {
+		v := ValueOf(xi)
+		for j := 0; j < v.Len(); j++ {
+			k := v.Index(j).Elem().Interface()
+			if k != uintptr(i*n+j) {
+				t.Errorf("lost x[%d][%d] = %d, want %d", i, j, k, i*n+j)
+			}
+		}
+	}
+}
+
+func TestArrayOfAlg(t *testing.T) {
+	at := ArrayOf(6, TypeOf(byte(0)))
+	v1 := New(at).Elem()
+	v2 := New(at).Elem()
+	if v1.Interface() != v1.Interface() {
+		t.Errorf("constructed array %v not equal to itself", v1.Interface())
+	}
+	v1.Index(5).Set(ValueOf(byte(1)))
+	if i1, i2 := v1.Interface(), v2.Interface(); i1 == i2 {
+		t.Errorf("constructed arrays %v and %v should not be equal", i1, i2)
+	}
+
+	at = ArrayOf(6, TypeOf([]int(nil)))
+	v1 = New(at).Elem()
+	shouldPanic(func() { _ = v1.Interface() == v1.Interface() })
+}
+
+func TestArrayOfGenericAlg(t *testing.T) {
+	at1 := ArrayOf(5, TypeOf(string("")))
+	at := ArrayOf(6, at1)
+	v1 := New(at).Elem()
+	v2 := New(at).Elem()
+	if v1.Interface() != v1.Interface() {
+		t.Errorf("constructed array %v not equal to itself", v1.Interface())
+	}
+
+	v1.Index(0).Index(0).Set(ValueOf("abc"))
+	v2.Index(0).Index(0).Set(ValueOf("efg"))
+	if i1, i2 := v1.Interface(), v2.Interface(); i1 == i2 {
+		t.Errorf("constructed arrays %v and %v should not be equal", i1, i2)
+	}
+
+	v1.Index(0).Index(0).Set(ValueOf("abc"))
+	v2.Index(0).Index(0).Set(ValueOf((v1.Index(0).Index(0).String() + " ")[:3]))
+	if i1, i2 := v1.Interface(), v2.Interface(); i1 != i2 {
+		t.Errorf("constructed arrays %v and %v should be equal", i1, i2)
+	}
+
+	// Test hash
+	m := MakeMap(MapOf(at, TypeOf(int(0))))
+	m.SetMapIndex(v1, ValueOf(1))
+	if i1, i2 := v1.Interface(), v2.Interface(); !m.MapIndex(v2).IsValid() {
+		t.Errorf("constructed arrays %v and %v have different hashes", i1, i2)
+	}
+}
+
+func TestArrayOfDirectIface(t *testing.T) {
+	{
+		type T [1]*byte
+		i1 := Zero(TypeOf(T{})).Interface()
+		v1 := ValueOf(&i1).Elem()
+		p1 := v1.InterfaceData()[1]
+
+		i2 := Zero(ArrayOf(1, PtrTo(TypeOf(int8(0))))).Interface()
+		v2 := ValueOf(&i2).Elem()
+		p2 := v2.InterfaceData()[1]
+
+		if p1 != 0 {
+			t.Errorf("got p1=%v. want=%v", p1, nil)
+		}
+
+		if p2 != 0 {
+			t.Errorf("got p2=%v. want=%v", p2, nil)
+		}
+	}
+	{
+		type T [0]*byte
+		i1 := Zero(TypeOf(T{})).Interface()
+		v1 := ValueOf(&i1).Elem()
+		p1 := v1.InterfaceData()[1]
+
+		i2 := Zero(ArrayOf(0, PtrTo(TypeOf(int8(0))))).Interface()
+		v2 := ValueOf(&i2).Elem()
+		p2 := v2.InterfaceData()[1]
+
+		if p1 == 0 {
+			t.Errorf("got p1=%v. want=not-%v", p1, nil)
+		}
+
+		if p2 == 0 {
+			t.Errorf("got p2=%v. want=not-%v", p2, nil)
+		}
+	}
+}
+
 func TestSliceOf(t *testing.T) {
 	// check construction and use of type not in binary
 	type T int
@@ -3482,6 +3717,26 @@ func TestChanOf(t *testing.T) {
 	checkSameType(t, Zero(ChanOf(BothDir, TypeOf(T1(1)))).Interface(), (chan T1)(nil))
 }
 
+func TestChanOfDir(t *testing.T) {
+	// check construction and use of type not in binary
+	type T string
+	crt := ChanOf(RecvDir, TypeOf(T("")))
+	cst := ChanOf(SendDir, TypeOf(T("")))
+
+	// check that type already in binary is found
+	type T1 int
+	checkSameType(t, Zero(ChanOf(RecvDir, TypeOf(T1(1)))).Interface(), (<-chan T1)(nil))
+	checkSameType(t, Zero(ChanOf(SendDir, TypeOf(T1(1)))).Interface(), (chan<- T1)(nil))
+
+	// check String form of ChanDir
+	if crt.ChanDir().String() != "<-chan" {
+		t.Errorf("chan dir: have %q, want %q", crt.ChanDir().String(), "<-chan")
+	}
+	if cst.ChanDir().String() != "chan<-" {
+		t.Errorf("chan dir: have %q, want %q", cst.ChanDir().String(), "chan<-")
+	}
+}
+
 func TestChanOfGC(t *testing.T) {
 	done := make(chan bool, 1)
 	go func() {
@@ -3625,6 +3880,67 @@ func TestMapOfGCValues(t *testing.T) {
 	}
 }
 
+func TestTypelinksSorted(t *testing.T) {
+	var last string
+	for i, n := range TypeLinks() {
+		if n < last {
+			t.Errorf("typelinks not sorted: %q [%d] > %q [%d]", last, i-1, n, i)
+		}
+		last = n
+	}
+}
+
+func TestFuncOf(t *testing.T) {
+	// check construction and use of type not in binary
+	type K string
+	type V float64
+
+	fn := func(args []Value) []Value {
+		if len(args) != 1 {
+			t.Errorf("args == %v, want exactly one arg", args)
+		} else if args[0].Type() != TypeOf(K("")) {
+			t.Errorf("args[0] is type %v, want %v", args[0].Type, TypeOf(K("")))
+		} else if args[0].String() != "gopher" {
+			t.Errorf("args[0] = %q, want %q", args[0].String(), "gopher")
+		}
+		return []Value{ValueOf(V(3.14))}
+	}
+	v := MakeFunc(FuncOf([]Type{TypeOf(K(""))}, []Type{TypeOf(V(0))}, false), fn)
+
+	outs := v.Call([]Value{ValueOf(K("gopher"))})
+	if len(outs) != 1 {
+		t.Fatalf("v.Call returned %v, want exactly one result", outs)
+	} else if outs[0].Type() != TypeOf(V(0)) {
+		t.Fatalf("c.Call[0] is type %v, want %v", outs[0].Type, TypeOf(V(0)))
+	}
+	f := outs[0].Float()
+	if f != 3.14 {
+		t.Errorf("constructed func returned %f, want %f", f, 3.14)
+	}
+
+	// check that types already in binary are found
+	type T1 int
+	testCases := []struct {
+		in, out  []Type
+		variadic bool
+		want     interface{}
+	}{
+		{in: []Type{TypeOf(T1(0))}, want: (func(T1))(nil)},
+		{in: []Type{TypeOf(int(0))}, want: (func(int))(nil)},
+		{in: []Type{SliceOf(TypeOf(int(0)))}, variadic: true, want: (func(...int))(nil)},
+		{in: []Type{TypeOf(int(0))}, out: []Type{TypeOf(false)}, want: (func(int) bool)(nil)},
+		{in: []Type{TypeOf(int(0))}, out: []Type{TypeOf(false), TypeOf("")}, want: (func(int) (bool, string))(nil)},
+	}
+	for _, tt := range testCases {
+		checkSameType(t, Zero(FuncOf(tt.in, tt.out, tt.variadic)).Interface(), tt.want)
+	}
+
+	// check that variadic requires last element be a slice.
+	FuncOf([]Type{TypeOf(1), TypeOf(""), SliceOf(TypeOf(false))}, nil, true)
+	shouldPanic(func() { FuncOf([]Type{TypeOf(0), TypeOf(""), TypeOf(false)}, nil, true) })
+	shouldPanic(func() { FuncOf(nil, nil, true) })
+}
+
 type B1 struct {
 	X int
 	Y int
@@ -4070,15 +4386,16 @@ func TestCallGC(t *testing.T) {
 }
 
 type funcLayoutTest struct {
-	rcvr, t            Type
-	argsize, retOffset uintptr
-	stack              []byte
+	rcvr, t                  Type
+	size, argsize, retOffset uintptr
+	stack                    []byte // pointer bitmap: 1 is pointer, 0 is scalar (or uninitialized)
+	gc                       []byte
 }
 
 var funcLayoutTests []funcLayoutTest
 
 func init() {
-	var argAlign = PtrSize
+	var argAlign uintptr = PtrSize
 	if runtime.GOARCH == "amd64p32" {
 		argAlign = 2 * PtrSize
 	}
@@ -4090,24 +4407,28 @@ func init() {
 		funcLayoutTest{
 			nil,
 			ValueOf(func(a, b string) string { return "" }).Type(),
+			6 * PtrSize,
 			4 * PtrSize,
 			4 * PtrSize,
-			[]byte{BitsPointer, BitsScalar, BitsPointer},
+			[]byte{1, 0, 1},
+			[]byte{1, 0, 1, 0, 1},
 		})
 
 	var r []byte
 	if PtrSize == 4 {
-		r = []byte{BitsScalar, BitsScalar, BitsScalar, BitsPointer}
+		r = []byte{0, 0, 0, 1}
 	} else {
-		r = []byte{BitsScalar, BitsScalar, BitsPointer}
+		r = []byte{0, 0, 1}
 	}
 	funcLayoutTests = append(funcLayoutTests,
 		funcLayoutTest{
 			nil,
 			ValueOf(func(a, b, c uint32, p *byte, d uint16) {}).Type(),
+			roundup(roundup(3*4, PtrSize)+PtrSize+2, argAlign),
 			roundup(3*4, PtrSize) + PtrSize + 2,
 			roundup(roundup(3*4, PtrSize)+PtrSize+2, argAlign),
 			r,
+			r,
 		})
 
 	funcLayoutTests = append(funcLayoutTests,
@@ -4116,7 +4437,9 @@ func init() {
 			ValueOf(func(a map[int]int, b uintptr, c interface{}) {}).Type(),
 			4 * PtrSize,
 			4 * PtrSize,
-			[]byte{BitsPointer, BitsScalar, BitsPointer, BitsPointer},
+			4 * PtrSize,
+			[]byte{1, 0, 1, 1},
+			[]byte{1, 0, 1, 1},
 		})
 
 	type S struct {
@@ -4129,22 +4452,65 @@ func init() {
 			ValueOf(func(a S) {}).Type(),
 			4 * PtrSize,
 			4 * PtrSize,
-			[]byte{BitsScalar, BitsScalar, BitsPointer, BitsPointer},
+			4 * PtrSize,
+			[]byte{0, 0, 1, 1},
+			[]byte{0, 0, 1, 1},
 		})
 
 	funcLayoutTests = append(funcLayoutTests,
 		funcLayoutTest{
 			ValueOf((*byte)(nil)).Type(),
 			ValueOf(func(a uintptr, b *int) {}).Type(),
+			roundup(3*PtrSize, argAlign),
 			3 * PtrSize,
 			roundup(3*PtrSize, argAlign),
-			[]byte{BitsPointer, BitsScalar, BitsPointer},
+			[]byte{1, 0, 1},
+			[]byte{1, 0, 1},
+		})
+
+	funcLayoutTests = append(funcLayoutTests,
+		funcLayoutTest{
+			nil,
+			ValueOf(func(a uintptr) {}).Type(),
+			roundup(PtrSize, argAlign),
+			PtrSize,
+			roundup(PtrSize, argAlign),
+			[]byte{},
+			[]byte{},
+		})
+
+	funcLayoutTests = append(funcLayoutTests,
+		funcLayoutTest{
+			nil,
+			ValueOf(func() uintptr { return 0 }).Type(),
+			PtrSize,
+			0,
+			0,
+			[]byte{},
+			[]byte{},
+		})
+
+	funcLayoutTests = append(funcLayoutTests,
+		funcLayoutTest{
+			ValueOf(uintptr(0)).Type(),
+			ValueOf(func(a uintptr) {}).Type(),
+			2 * PtrSize,
+			2 * PtrSize,
+			2 * PtrSize,
+			[]byte{1},
+			[]byte{1},
+			// Note: this one is tricky, as the receiver is not a pointer.  But we
+			// pass the receiver by reference to the autogenerated pointer-receiver
+			// version of the function.
 		})
 }
 
 func TestFuncLayout(t *testing.T) {
 	for _, lt := range funcLayoutTests {
-		_, argsize, retOffset, stack := FuncLayout(lt.t, lt.rcvr)
+		typ, argsize, retOffset, stack, gc, ptrs := FuncLayout(lt.t, lt.rcvr)
+		if typ.Size() != lt.size {
+			t.Errorf("funcLayout(%v, %v).size=%d, want %d", lt.t, lt.rcvr, typ.Size(), lt.size)
+		}
 		if argsize != lt.argsize {
 			t.Errorf("funcLayout(%v, %v).argsize=%d, want %d", lt.t, lt.rcvr, argsize, lt.argsize)
 		}
@@ -4154,5 +4520,258 @@ func TestFuncLayout(t *testing.T) {
 		if !bytes.Equal(stack, lt.stack) {
 			t.Errorf("funcLayout(%v, %v).stack=%v, want %v", lt.t, lt.rcvr, stack, lt.stack)
 		}
+		if !bytes.Equal(gc, lt.gc) {
+			t.Errorf("funcLayout(%v, %v).gc=%v, want %v", lt.t, lt.rcvr, gc, lt.gc)
+		}
+		if ptrs && len(stack) == 0 || !ptrs && len(stack) > 0 {
+			t.Errorf("funcLayout(%v, %v) pointers flag=%v, want %v", lt.t, lt.rcvr, ptrs, !ptrs)
+		}
+	}
+}
+
+func verifyGCBits(t *testing.T, typ Type, bits []byte) {
+	heapBits := GCBits(New(typ).Interface())
+	if !bytes.Equal(heapBits, bits) {
+		t.Errorf("heapBits incorrect for %v\nhave %v\nwant %v", typ, heapBits, bits)
+	}
+}
+
+func verifyGCBitsSlice(t *testing.T, typ Type, cap int, bits []byte) {
+	// Creating a slice causes the runtime to repeat a bitmap,
+	// which exercises a different path from making the compiler
+	// repeat a bitmap for a small array or executing a repeat in
+	// a GC program.
+	val := MakeSlice(typ, 0, cap)
+	data := NewAt(ArrayOf(cap, typ), unsafe.Pointer(val.Pointer()))
+	heapBits := GCBits(data.Interface())
+	// Repeat the bitmap for the slice size, trimming scalars in
+	// the last element.
+	bits = rep(cap, bits)
+	for len(bits) > 2 && bits[len(bits)-1] == 0 {
+		bits = bits[:len(bits)-1]
+	}
+	if !bytes.Equal(heapBits, bits) {
+		t.Errorf("heapBits incorrect for make(%v, 0, %v)\nhave %v\nwant %v", typ, cap, heapBits, bits)
+	}
+}
+
+func TestGCBits(t *testing.T) {
+	verifyGCBits(t, TypeOf((*byte)(nil)), []byte{1})
+
+	// Building blocks for types seen by the compiler (like [2]Xscalar).
+	// The compiler will create the type structures for the derived types,
+	// including their GC metadata.
+	type Xscalar struct{ x uintptr }
+	type Xptr struct{ x *byte }
+	type Xptrscalar struct {
+		*byte
+		uintptr
+	}
+	type Xscalarptr struct {
+		uintptr
+		*byte
+	}
+	type Xbigptrscalar struct {
+		_ [100]*byte
+		_ [100]uintptr
+	}
+
+	var Tscalar, Tint64, Tptr, Tscalarptr, Tptrscalar, Tbigptrscalar Type
+	{
+		// Building blocks for types constructed by reflect.
+		// This code is in a separate block so that code below
+		// cannot accidentally refer to these.
+		// The compiler must NOT see types derived from these
+		// (for example, [2]Scalar must NOT appear in the program),
+		// or else reflect will use it instead of having to construct one.
+		// The goal is to test the construction.
+		type Scalar struct{ x uintptr }
+		type Ptr struct{ x *byte }
+		type Ptrscalar struct {
+			*byte
+			uintptr
+		}
+		type Scalarptr struct {
+			uintptr
+			*byte
+		}
+		type Bigptrscalar struct {
+			_ [100]*byte
+			_ [100]uintptr
+		}
+		type Int64 int64
+		Tscalar = TypeOf(Scalar{})
+		Tint64 = TypeOf(Int64(0))
+		Tptr = TypeOf(Ptr{})
+		Tscalarptr = TypeOf(Scalarptr{})
+		Tptrscalar = TypeOf(Ptrscalar{})
+		Tbigptrscalar = TypeOf(Bigptrscalar{})
+	}
+
+	empty := []byte{}
+
+	verifyGCBits(t, TypeOf(Xscalar{}), empty)
+	verifyGCBits(t, Tscalar, empty)
+	verifyGCBits(t, TypeOf(Xptr{}), lit(1))
+	verifyGCBits(t, Tptr, lit(1))
+	verifyGCBits(t, TypeOf(Xscalarptr{}), lit(0, 1))
+	verifyGCBits(t, Tscalarptr, lit(0, 1))
+	verifyGCBits(t, TypeOf(Xptrscalar{}), lit(1))
+	verifyGCBits(t, Tptrscalar, lit(1))
+
+	verifyGCBits(t, TypeOf([0]Xptr{}), empty)
+	verifyGCBits(t, ArrayOf(0, Tptr), empty)
+	verifyGCBits(t, TypeOf([1]Xptrscalar{}), lit(1))
+	verifyGCBits(t, ArrayOf(1, Tptrscalar), lit(1))
+	verifyGCBits(t, TypeOf([2]Xscalar{}), empty)
+	verifyGCBits(t, ArrayOf(2, Tscalar), empty)
+	verifyGCBits(t, TypeOf([10000]Xscalar{}), empty)
+	verifyGCBits(t, ArrayOf(10000, Tscalar), empty)
+	verifyGCBits(t, TypeOf([2]Xptr{}), lit(1, 1))
+	verifyGCBits(t, ArrayOf(2, Tptr), lit(1, 1))
+	verifyGCBits(t, TypeOf([10000]Xptr{}), rep(10000, lit(1)))
+	verifyGCBits(t, ArrayOf(10000, Tptr), rep(10000, lit(1)))
+	verifyGCBits(t, TypeOf([2]Xscalarptr{}), lit(0, 1, 0, 1))
+	verifyGCBits(t, ArrayOf(2, Tscalarptr), lit(0, 1, 0, 1))
+	verifyGCBits(t, TypeOf([10000]Xscalarptr{}), rep(10000, lit(0, 1)))
+	verifyGCBits(t, ArrayOf(10000, Tscalarptr), rep(10000, lit(0, 1)))
+	verifyGCBits(t, TypeOf([2]Xptrscalar{}), lit(1, 0, 1))
+	verifyGCBits(t, ArrayOf(2, Tptrscalar), lit(1, 0, 1))
+	verifyGCBits(t, TypeOf([10000]Xptrscalar{}), rep(10000, lit(1, 0)))
+	verifyGCBits(t, ArrayOf(10000, Tptrscalar), rep(10000, lit(1, 0)))
+	verifyGCBits(t, TypeOf([1][10000]Xptrscalar{}), rep(10000, lit(1, 0)))
+	verifyGCBits(t, ArrayOf(1, ArrayOf(10000, Tptrscalar)), rep(10000, lit(1, 0)))
+	verifyGCBits(t, TypeOf([2][10000]Xptrscalar{}), rep(2*10000, lit(1, 0)))
+	verifyGCBits(t, ArrayOf(2, ArrayOf(10000, Tptrscalar)), rep(2*10000, lit(1, 0)))
+	verifyGCBits(t, TypeOf([4]Xbigptrscalar{}), join(rep(3, join(rep(100, lit(1)), rep(100, lit(0)))), rep(100, lit(1))))
+	verifyGCBits(t, ArrayOf(4, Tbigptrscalar), join(rep(3, join(rep(100, lit(1)), rep(100, lit(0)))), rep(100, lit(1))))
+
+	verifyGCBitsSlice(t, TypeOf([]Xptr{}), 0, empty)
+	verifyGCBitsSlice(t, SliceOf(Tptr), 0, empty)
+	verifyGCBitsSlice(t, TypeOf([]Xptrscalar{}), 1, lit(1))
+	verifyGCBitsSlice(t, SliceOf(Tptrscalar), 1, lit(1))
+	verifyGCBitsSlice(t, TypeOf([]Xscalar{}), 2, lit(0))
+	verifyGCBitsSlice(t, SliceOf(Tscalar), 2, lit(0))
+	verifyGCBitsSlice(t, TypeOf([]Xscalar{}), 10000, lit(0))
+	verifyGCBitsSlice(t, SliceOf(Tscalar), 10000, lit(0))
+	verifyGCBitsSlice(t, TypeOf([]Xptr{}), 2, lit(1))
+	verifyGCBitsSlice(t, SliceOf(Tptr), 2, lit(1))
+	verifyGCBitsSlice(t, TypeOf([]Xptr{}), 10000, lit(1))
+	verifyGCBitsSlice(t, SliceOf(Tptr), 10000, lit(1))
+	verifyGCBitsSlice(t, TypeOf([]Xscalarptr{}), 2, lit(0, 1))
+	verifyGCBitsSlice(t, SliceOf(Tscalarptr), 2, lit(0, 1))
+	verifyGCBitsSlice(t, TypeOf([]Xscalarptr{}), 10000, lit(0, 1))
+	verifyGCBitsSlice(t, SliceOf(Tscalarptr), 10000, lit(0, 1))
+	verifyGCBitsSlice(t, TypeOf([]Xptrscalar{}), 2, lit(1, 0))
+	verifyGCBitsSlice(t, SliceOf(Tptrscalar), 2, lit(1, 0))
+	verifyGCBitsSlice(t, TypeOf([]Xptrscalar{}), 10000, lit(1, 0))
+	verifyGCBitsSlice(t, SliceOf(Tptrscalar), 10000, lit(1, 0))
+	verifyGCBitsSlice(t, TypeOf([][10000]Xptrscalar{}), 1, rep(10000, lit(1, 0)))
+	verifyGCBitsSlice(t, SliceOf(ArrayOf(10000, Tptrscalar)), 1, rep(10000, lit(1, 0)))
+	verifyGCBitsSlice(t, TypeOf([][10000]Xptrscalar{}), 2, rep(10000, lit(1, 0)))
+	verifyGCBitsSlice(t, SliceOf(ArrayOf(10000, Tptrscalar)), 2, rep(10000, lit(1, 0)))
+	verifyGCBitsSlice(t, TypeOf([]Xbigptrscalar{}), 4, join(rep(100, lit(1)), rep(100, lit(0))))
+	verifyGCBitsSlice(t, SliceOf(Tbigptrscalar), 4, join(rep(100, lit(1)), rep(100, lit(0))))
+
+	verifyGCBits(t, TypeOf((chan [100]Xscalar)(nil)), lit(1))
+	verifyGCBits(t, ChanOf(BothDir, ArrayOf(100, Tscalar)), lit(1))
+
+	verifyGCBits(t, TypeOf((func([10000]Xscalarptr))(nil)), lit(1))
+	verifyGCBits(t, FuncOf([]Type{ArrayOf(10000, Tscalarptr)}, nil, false), lit(1))
+
+	verifyGCBits(t, TypeOf((map[[10000]Xscalarptr]Xscalar)(nil)), lit(1))
+	verifyGCBits(t, MapOf(ArrayOf(10000, Tscalarptr), Tscalar), lit(1))
+
+	verifyGCBits(t, TypeOf((*[10000]Xscalar)(nil)), lit(1))
+	verifyGCBits(t, PtrTo(ArrayOf(10000, Tscalar)), lit(1))
+
+	verifyGCBits(t, TypeOf(([][10000]Xscalar)(nil)), lit(1))
+	verifyGCBits(t, SliceOf(ArrayOf(10000, Tscalar)), lit(1))
+
+	hdr := make([]byte, 8/PtrSize)
+
+	verifyMapBucket := func(t *testing.T, k, e Type, m interface{}, want []byte) {
+		verifyGCBits(t, MapBucketOf(k, e), want)
+		verifyGCBits(t, CachedBucketOf(TypeOf(m)), want)
+	}
+	verifyMapBucket(t,
+		Tscalar, Tptr,
+		map[Xscalar]Xptr(nil),
+		join(hdr, rep(8, lit(0)), rep(8, lit(1)), lit(1)))
+	verifyMapBucket(t,
+		Tscalarptr, Tptr,
+		map[Xscalarptr]Xptr(nil),
+		join(hdr, rep(8, lit(0, 1)), rep(8, lit(1)), lit(1)))
+	verifyMapBucket(t, Tint64, Tptr,
+		map[int64]Xptr(nil),
+		join(hdr, rep(8, rep(8/PtrSize, lit(0))), rep(8, lit(1)), naclpad(), lit(1)))
+	verifyMapBucket(t,
+		Tscalar, Tscalar,
+		map[Xscalar]Xscalar(nil),
+		empty)
+	verifyMapBucket(t,
+		ArrayOf(2, Tscalarptr), ArrayOf(3, Tptrscalar),
+		map[[2]Xscalarptr][3]Xptrscalar(nil),
+		join(hdr, rep(8*2, lit(0, 1)), rep(8*3, lit(1, 0)), lit(1)))
+	verifyMapBucket(t,
+		ArrayOf(64/PtrSize, Tscalarptr), ArrayOf(64/PtrSize, Tptrscalar),
+		map[[64 / PtrSize]Xscalarptr][64 / PtrSize]Xptrscalar(nil),
+		join(hdr, rep(8*64/PtrSize, lit(0, 1)), rep(8*64/PtrSize, lit(1, 0)), lit(1)))
+	verifyMapBucket(t,
+		ArrayOf(64/PtrSize+1, Tscalarptr), ArrayOf(64/PtrSize, Tptrscalar),
+		map[[64/PtrSize + 1]Xscalarptr][64 / PtrSize]Xptrscalar(nil),
+		join(hdr, rep(8, lit(1)), rep(8*64/PtrSize, lit(1, 0)), lit(1)))
+	verifyMapBucket(t,
+		ArrayOf(64/PtrSize, Tscalarptr), ArrayOf(64/PtrSize+1, Tptrscalar),
+		map[[64 / PtrSize]Xscalarptr][64/PtrSize + 1]Xptrscalar(nil),
+		join(hdr, rep(8*64/PtrSize, lit(0, 1)), rep(8, lit(1)), lit(1)))
+	verifyMapBucket(t,
+		ArrayOf(64/PtrSize+1, Tscalarptr), ArrayOf(64/PtrSize+1, Tptrscalar),
+		map[[64/PtrSize + 1]Xscalarptr][64/PtrSize + 1]Xptrscalar(nil),
+		join(hdr, rep(8, lit(1)), rep(8, lit(1)), lit(1)))
+}
+
+func naclpad() []byte {
+	if runtime.GOARCH == "amd64p32" {
+		return lit(0)
+	}
+	return nil
+}
+
+func rep(n int, b []byte) []byte { return bytes.Repeat(b, n) }
+func join(b ...[]byte) []byte    { return bytes.Join(b, nil) }
+func lit(x ...byte) []byte       { return x }
+
+func TestTypeOfTypeOf(t *testing.T) {
+	// Check that all the type constructors return concrete *rtype implementations.
+	// It's difficult to test directly because the reflect package is only at arm's length.
+	// The easiest thing to do is just call a function that crashes if it doesn't get an *rtype.
+	check := func(name string, typ Type) {
+		if underlying := TypeOf(typ).String(); underlying != "*reflect.rtype" {
+			t.Errorf("%v returned %v, not *reflect.rtype", name, underlying)
+		}
+	}
+
+	type T struct{ int }
+	check("TypeOf", TypeOf(T{}))
+
+	check("ArrayOf", ArrayOf(10, TypeOf(T{})))
+	check("ChanOf", ChanOf(BothDir, TypeOf(T{})))
+	check("FuncOf", FuncOf([]Type{TypeOf(T{})}, nil, false))
+	check("MapOf", MapOf(TypeOf(T{}), TypeOf(T{})))
+	check("PtrTo", PtrTo(TypeOf(T{})))
+	check("SliceOf", SliceOf(TypeOf(T{})))
+}
+
+type XM struct{}
+
+func (*XM) String() string { return "" }
+
+func TestPtrToMethods(t *testing.T) {
+	var y struct{ XM }
+	yp := New(TypeOf(y)).Interface()
+	_, ok := yp.(fmt.Stringer)
+	if !ok {
+		t.Fatal("does not implement Stringer, but should")
 	}
 }
diff --git a/src/reflect/asm_arm64.s b/src/reflect/asm_arm64.s
new file mode 100644
index 0000000..bdd3843
--- /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),$24
+	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),$24
+	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/asm_ppc64x.s b/src/reflect/asm_ppc64x.s
new file mode 100644
index 0000000..d5f7f8f
--- /dev/null
+++ b/src/reflect/asm_ppc64x.s
@@ -0,0 +1,32 @@
+// 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.
+
+// +build ppc64 ppc64le
+
+#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	R11, 8(R1)
+	MOVD	$argframe+0(FP), R3
+	MOVD	R3, 16(R1)
+	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	R11, 8(R1)
+	MOVD	$argframe+0(FP), R3
+	MOVD	R3, 16(R1)
+	BL	·callMethod(SB)
+	RET
diff --git a/src/reflect/example_test.go b/src/reflect/example_test.go
index cca28ee..8ebf976 100644
--- a/src/reflect/example_test.go
+++ b/src/reflect/example_test.go
@@ -6,6 +6,8 @@ package reflect_test
 
 import (
 	"fmt"
+	"io"
+	"os"
 	"reflect"
 )
 
@@ -64,3 +66,16 @@ func ExampleStructTag() {
 	// Output:
 	// blue gopher
 }
+
+func ExampleTypeOf() {
+	// As interface types are only used for static typing, a
+	// common idiom to find the reflection Type for an interface
+	// type Foo is to use a *Foo value.
+	writerType := reflect.TypeOf((*io.Writer)(nil)).Elem()
+
+	fileType := reflect.TypeOf((*os.File)(nil))
+	fmt.Println(fileType.Implements(writerType))
+
+	// Output:
+	// true
+}
diff --git a/src/reflect/export_test.go b/src/reflect/export_test.go
index caaf51a..0b9d0fd 100644
--- a/src/reflect/export_test.go
+++ b/src/reflect/export_test.go
@@ -4,6 +4,8 @@
 
 package reflect
 
+import "unsafe"
+
 // MakeRO returns a copy of v with the read-only flag set.
 func MakeRO(v Value) Value {
 	v.flag |= flagRO
@@ -15,24 +17,56 @@ func IsRO(v Value) bool {
 	return v.flag&flagRO != 0
 }
 
-var ArrayOf = arrayOf
 var CallGC = &callGC
 
 const PtrSize = ptrSize
-const BitsPointer = bitsPointer
-const BitsScalar = bitsScalar
 
-func FuncLayout(t Type, rcvr Type) (frametype Type, argSize, retOffset uintptr, stack []byte) {
+func FuncLayout(t Type, rcvr Type) (frametype Type, argSize, retOffset uintptr, stack []byte, gc []byte, ptrs bool) {
 	var ft *rtype
 	var s *bitVector
 	if rcvr != nil {
-		ft, argSize, retOffset, s = funcLayout(t.(*rtype), rcvr.(*rtype))
+		ft, argSize, retOffset, s, _ = funcLayout(t.(*rtype), rcvr.(*rtype))
 	} else {
-		ft, argSize, retOffset, s = funcLayout(t.(*rtype), nil)
+		ft, argSize, retOffset, s, _ = funcLayout(t.(*rtype), nil)
 	}
 	frametype = ft
-	for i := uint32(0); i < s.n; i += 2 {
-		stack = append(stack, s.data[i/8]>>(i%8)&3)
+	for i := uint32(0); i < s.n; i++ {
+		stack = append(stack, s.data[i/8]>>(i%8)&1)
+	}
+	if ft.kind&kindGCProg != 0 {
+		panic("can't handle gc programs")
 	}
+	gcdata := (*[1000]byte)(unsafe.Pointer(ft.gcdata))
+	for i := uintptr(0); i < ft.ptrdata/ptrSize; i++ {
+		gc = append(gc, gcdata[i/8]>>(i%8)&1)
+	}
+	ptrs = ft.kind&kindNoPointers == 0
 	return
 }
+
+func TypeLinks() []string {
+	var r []string
+	for _, m := range typelinks() {
+		for _, t := range m {
+			r = append(r, *t.string)
+		}
+	}
+	return r
+}
+
+var GCBits = gcbits
+
+func gcbits(interface{}) []byte // provided by runtime
+
+func MapBucketOf(x, y Type) Type {
+	return bucketOf(x.(*rtype), y.(*rtype))
+}
+
+func CachedBucketOf(m Type) Type {
+	t := m.(*rtype)
+	if Kind(t.kind&kindMask) != Map {
+		panic("not map")
+	}
+	tt := (*mapType)(unsafe.Pointer(t))
+	return tt.bucket
+}
diff --git a/src/reflect/makefunc.go b/src/reflect/makefunc.go
index d89f7f6..032057d 100644
--- a/src/reflect/makefunc.go
+++ b/src/reflect/makefunc.go
@@ -51,12 +51,12 @@ func MakeFunc(typ Type, fn func(args []Value) (results []Value)) Value {
 
 	// Indirect Go func value (dummy) to obtain
 	// actual code address. (A Go func value is a pointer
-	// to a C function pointer. http://golang.org/s/go11func.)
+	// to a C function pointer. https://golang.org/s/go11func.)
 	dummy := makeFuncStub
 	code := **(**uintptr)(unsafe.Pointer(&dummy))
 
 	// makeFuncImpl contains a stack map for use by the runtime
-	_, _, _, stack := funcLayout(t, nil)
+	_, _, _, stack, _ := funcLayout(t, nil)
 
 	impl := &makeFuncImpl{code: code, stack: stack, typ: ftyp, fn: fn}
 
@@ -99,12 +99,12 @@ func makeMethodValue(op string, v Value) Value {
 
 	// Indirect Go func value (dummy) to obtain
 	// actual code address. (A Go func value is a pointer
-	// to a C function pointer. http://golang.org/s/go11func.)
+	// to a C function pointer. https://golang.org/s/go11func.)
 	dummy := methodValueCall
 	code := **(**uintptr)(unsafe.Pointer(&dummy))
 
 	// methodValue contains a stack map for use by the runtime
-	_, _, _, stack := funcLayout(funcType, nil)
+	_, _, _, stack, _ := funcLayout(funcType, nil)
 
 	fv := &methodValue{
 		fn:     code,
diff --git a/src/reflect/type.go b/src/reflect/type.go
index 6fd6894..e20e5cf 100644
--- a/src/reflect/type.go
+++ b/src/reflect/type.go
@@ -12,7 +12,7 @@
 // for that type.
 //
 // See "The Laws of Reflection" for an introduction to reflection in Go:
-// http://golang.org/doc/articles/laws_of_reflection.html
+// https://golang.org/doc/articles/laws_of_reflection.html
 package reflect
 
 import (
@@ -87,16 +87,16 @@ type Type interface {
 	// 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 @@ type Type interface {
 	// 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 @@ type Type interface {
 // 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.
@@ -246,26 +246,28 @@ const (
 // so that code cannot convert from, say, *arrayType to *ptrType.
 type rtype struct {
 	size          uintptr
-	hash          uint32            // hash of type; avoids computation in hash tables
-	_             uint8             // unused/padding
-	align         uint8             // alignment of variable with this type
-	fieldAlign    uint8             // alignment of struct field with this type
-	kind          uint8             // enumeration for C
-	alg           *typeAlg          // algorithm table (../runtime/runtime.h:/Alg)
-	gc            [2]unsafe.Pointer // garbage collection data
-	string        *string           // string form; unnecessary but undeniably useful
-	*uncommonType                   // (relatively) uncommon fields
-	ptrToThis     *rtype            // type for pointer to this type, if used in binary or has methods
-	zero          unsafe.Pointer    // pointer to zero value
-}
-
+	ptrdata       uintptr
+	hash          uint32         // hash of type; avoids computation in hash tables
+	_             uint8          // unused/padding
+	align         uint8          // alignment of variable with this type
+	fieldAlign    uint8          // alignment of struct field with this type
+	kind          uint8          // enumeration for C
+	alg           *typeAlg       // algorithm table
+	gcdata        *byte          // garbage collection data
+	string        *string        // string form; unnecessary but undeniably useful
+	*uncommonType                // (relatively) uncommon fields
+	ptrToThis     *rtype         // type for pointer to this type, if used in binary or has methods
+	zero          unsafe.Pointer // pointer to zero value
+}
+
+// a copy of runtime.typeAlg
 type typeAlg struct {
 	// function for hashing objects of this type
-	// (ptr to object, size, seed) -> hash
-	hash func(unsafe.Pointer, uintptr, uintptr) uintptr
+	// (ptr to object, seed) -> hash
+	hash func(unsafe.Pointer, uintptr) uintptr
 	// function for comparing objects of this type
-	// (ptr to object A, ptr to object B, size) -> ==?
-	equal func(unsafe.Pointer, unsafe.Pointer, uintptr) bool
+	// (ptr to object A, ptr to object B) -> ==?
+	equal func(unsafe.Pointer, unsafe.Pointer) bool
 }
 
 // Method on non-interface type
@@ -345,6 +347,7 @@ type mapType struct {
 	valuesize     uint8  // size of value slot
 	indirectvalue uint8  // store ptr to value instead of value itself
 	bucketsize    uint16 // size of bucket
+	reflexivekey  bool   // true if k==k for all keys
 }
 
 // ptrType represents a pointer type.
@@ -386,7 +389,7 @@ type Method struct {
 	// method name.  It is empty for upper case (exported) method names.
 	// The combination of PkgPath and Name uniquely identifies a method
 	// in a method set.
-	// See http://golang.org/ref/spec#Uniqueness_of_identifiers
+	// See https://golang.org/ref/spec#Uniqueness_of_identifiers
 	Name    string
 	PkgPath string
 
@@ -524,7 +527,7 @@ func (t *uncommonType) MethodByName(name string) (m Method, ok bool) {
 	return
 }
 
-// TODO(rsc): 6g supplies these, but they are not
+// TODO(rsc): gc supplies these, but they are not
 // as efficient as they could be: they have commonType
 // as the receiver instead of *rtype.
 func (t *rtype) NumMethod() int {
@@ -734,7 +737,7 @@ type StructField struct {
 	// Name is the field name.
 	// PkgPath is the package path that qualifies a lower case (unexported)
 	// field name.  It is empty for upper case (exported) field names.
-	// See http://golang.org/ref/spec#Uniqueness_of_identifiers
+	// See https://golang.org/ref/spec#Uniqueness_of_identifiers
 	Name    string
 	PkgPath string
 
@@ -760,8 +763,11 @@ type StructTag string
 // If the tag does not have the conventional format, the value
 // returned by Get is unspecified.
 func (tag StructTag) Get(key string) string {
+	// When modifying this code, also update the validateStructTag code
+	// in golang.org/x/tools/cmd/vet/structtag.go.
+
 	for tag != "" {
-		// skip leading space
+		// Skip leading space.
 		i := 0
 		for i < len(tag) && tag[i] == ' ' {
 			i++
@@ -771,19 +777,21 @@ func (tag StructTag) Get(key string) string {
 			break
 		}
 
-		// scan to colon.
-		// a space or a quote is a syntax error
+		// Scan to colon. A space, a quote or a control character is a syntax error.
+		// Strictly speaking, control chars include the range [0x7f, 0x9f], not just
+		// [0x00, 0x1f], but in practice, we ignore the multi-byte control characters
+		// as it is simpler to inspect the tag's bytes than the tag's runes.
 		i = 0
-		for i < len(tag) && tag[i] != ' ' && tag[i] != ':' && tag[i] != '"' {
+		for i < len(tag) && tag[i] > ' ' && tag[i] != ':' && tag[i] != '"' && tag[i] != 0x7f {
 			i++
 		}
-		if i+1 >= len(tag) || tag[i] != ':' || tag[i+1] != '"' {
+		if i == 0 || i+1 >= len(tag) || tag[i] != ':' || tag[i+1] != '"' {
 			break
 		}
 		name := string(tag[:i])
 		tag = tag[i+1:]
 
-		// scan quoted string to find value
+		// Scan quoted string to find value.
 		i = 1
 		for i < len(tag) && tag[i] != '"' {
 			if tag[i] == '\\' {
@@ -798,7 +806,10 @@ func (tag StructTag) Get(key string) string {
 		tag = tag[i+1:]
 
 		if key == name {
-			value, _ := strconv.Unquote(qvalue)
+			value, err := strconv.Unquote(qvalue)
+			if err != nil {
+				break
+			}
 			return value
 		}
 	}
@@ -999,8 +1010,8 @@ func (t *structType) FieldByName(name string) (f StructField, present bool) {
 	return t.FieldByNameFunc(func(s string) bool { return s == name })
 }
 
-// TypeOf returns the reflection Type of the value in the interface{}.
-// TypeOf(nil) returns nil.
+// TypeOf returns the reflection Type that represents the dynamic type of i.
+// If i is a nil interface value, TypeOf returns nil.
 func TypeOf(i interface{}) Type {
 	eface := *(*emptyInterface)(unsafe.Pointer(&i))
 	return toType(eface.typ)
@@ -1047,6 +1058,17 @@ func (t *rtype) ptrTo() *rtype {
 		return &p.rtype
 	}
 
+	// Look in known types.
+	s := "*" + *t.string
+	for _, tt := range typesByString(s) {
+		p = (*ptrType)(unsafe.Pointer(tt))
+		if p.elem == t {
+			ptrMap.m[t] = p
+			ptrMap.Unlock()
+			return &p.rtype
+		}
+	}
+
 	// Create a new ptrType starting with the description
 	// of an *unsafe.Pointer.
 	p = new(ptrType)
@@ -1054,7 +1076,6 @@ func (t *rtype) ptrTo() *rtype {
 	prototype := *(**ptrType)(unsafe.Pointer(&iptr))
 	*p = *prototype
 
-	s := "*" + *t.string
 	p.string = &s
 
 	// For the type structures linked into the binary, the
@@ -1066,7 +1087,6 @@ func (t *rtype) ptrTo() *rtype {
 
 	p.uncommonType = nil
 	p.ptrToThis = nil
-	p.zero = unsafe.Pointer(&make([]byte, p.size)[0])
 	p.elem = t
 
 	ptrMap.m[t] = p
@@ -1112,7 +1132,7 @@ func (t *rtype) Comparable() bool {
 	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
@@ -1133,14 +1153,14 @@ func implements(T, V *rtype) bool {
 	// 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
 		for j := 0; j < len(v.methods); j++ {
 			tm := &t.methods[i]
 			vm := &v.methods[j]
-			if vm.name == tm.name && vm.pkgPath == tm.pkgPath && vm.typ == tm.typ {
+			if *vm.name == *tm.name && vm.pkgPath == tm.pkgPath && vm.typ == tm.typ {
 				if i++; i >= len(t.methods) {
 					return true
 				}
@@ -1157,7 +1177,7 @@ func implements(T, V *rtype) bool {
 	for j := 0; j < len(v.methods); j++ {
 		tm := &t.methods[i]
 		vm := &v.methods[j]
-		if vm.name == tm.name && vm.pkgPath == tm.pkgPath && vm.mtyp == tm.typ {
+		if *vm.name == *tm.name && vm.pkgPath == tm.pkgPath && vm.mtyp == tm.typ {
 			if i++; i >= len(t.methods) {
 				return true
 			}
@@ -1166,9 +1186,9 @@ func implements(T, V *rtype) bool {
 	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
+// https://golang.org/doc/go_spec.html#Assignability
 // Ignoring the interface rules (implemented elsewhere)
 // and the ideal constant rules (no ideal constants at run time).
 func directlyAssignable(T, V *rtype) bool {
@@ -1291,39 +1311,48 @@ func haveIdenticalUnderlyingType(T, V *rtype) bool {
 // there can be more than one with a given string.
 // Only types we might want to look up are included:
 // channels, maps, slices, and arrays.
-func typelinks() []*rtype
+func typelinks() [][]*rtype
 
 // typesByString returns the subslice of typelinks() whose elements have
 // the given string representation.
 // It may be empty (no known types with that string) or may have
 // multiple elements (multiple types with that string).
 func typesByString(s string) []*rtype {
-	typ := typelinks()
-
-	// We are looking for the first index i where the string becomes >= s.
-	// This is a copy of sort.Search, with f(h) replaced by (*typ[h].string >= s).
-	i, j := 0, len(typ)
-	for i < j {
-		h := i + (j-i)/2 // avoid overflow when computing h
-		// i ≤ h < j
-		if !(*typ[h].string >= s) {
-			i = h + 1 // preserves f(i-1) == false
-		} else {
-			j = h // preserves f(j) == true
+	typs := typelinks()
+	var ret []*rtype
+
+	for _, typ := range typs {
+		// We are looking for the first index i where the string becomes >= s.
+		// This is a copy of sort.Search, with f(h) replaced by (*typ[h].string >= s).
+		i, j := 0, len(typ)
+		for i < j {
+			h := i + (j-i)/2 // avoid overflow when computing h
+			// i ≤ h < j
+			if !(*typ[h].string >= s) {
+				i = h + 1 // preserves f(i-1) == false
+			} else {
+				j = h // preserves f(j) == true
+			}
+		}
+		// i == j, f(i-1) == false, and f(j) (= f(i)) == true  =>  answer is i.
+
+		// Having found the first, linear scan forward to find the last.
+		// We could do a second binary search, but the caller is going
+		// to do a linear scan anyway.
+		j = i
+		for j < len(typ) && *typ[j].string == s {
+			j++
 		}
-	}
-	// i == j, f(i-1) == false, and f(j) (= f(i)) == true  =>  answer is i.
 
-	// Having found the first, linear scan forward to find the last.
-	// We could do a second binary search, but the caller is going
-	// to do a linear scan anyway.
-	j = i
-	for j < len(typ) && *typ[j].string == s {
-		j++
+		if j > i {
+			if ret == nil {
+				ret = typ[i:j:j]
+			} else {
+				ret = append(ret, typ[i:j]...)
+			}
+		}
 	}
-
-	// This slice will be empty if the string is not found.
-	return typ[i:j]
+	return ret
 }
 
 // The lookupCache caches ChanOf, MapOf, and SliceOf lookups.
@@ -1377,6 +1406,14 @@ func cachePut(k cacheKey, t *rtype) Type {
 	return t
 }
 
+// The funcLookupCache caches FuncOf lookups.
+// FuncOf does not share the common lookupCache since cacheKey is not
+// sufficient to represent functions unambiguously.
+var funcLookupCache struct {
+	sync.RWMutex
+	m map[uint32][]*rtype // keyed by hash calculated in FuncOf
+}
+
 // ChanOf returns the channel type with the given direction and element type.
 // For example, if t represents int, ChanOf(RecvDir, t) represents <-chan int.
 //
@@ -1423,12 +1460,12 @@ func ChanOf(dir ChanDir, t Type) Type {
 	prototype := *(**chanType)(unsafe.Pointer(&ichan))
 	ch := new(chanType)
 	*ch = *prototype
+	ch.dir = uintptr(dir)
 	ch.string = &s
 	ch.hash = fnv1(typ.hash, 'c', byte(dir))
 	ch.elem = typ
 	ch.uncommonType = nil
 	ch.ptrToThis = nil
-	ch.zero = unsafe.Pointer(&make([]byte, ch.size)[0])
 
 	return cachePut(ckey, &ch.rtype)
 }
@@ -1466,9 +1503,8 @@ func MapOf(key, elem Type) Type {
 
 	// Make a map type.
 	var imap interface{} = (map[unsafe.Pointer]unsafe.Pointer)(nil)
-	prototype := *(**mapType)(unsafe.Pointer(&imap))
 	mt := new(mapType)
-	*mt = *prototype
+	*mt = **(**mapType)(unsafe.Pointer(&imap))
 	mt.string = &s
 	mt.hash = fnv1(etyp.hash, 'm', byte(ktyp.hash>>24), byte(ktyp.hash>>16), byte(ktyp.hash>>8), byte(ktyp.hash))
 	mt.key = ktyp
@@ -1489,162 +1525,256 @@ func MapOf(key, elem Type) Type {
 		mt.indirectvalue = 0
 	}
 	mt.bucketsize = uint16(mt.bucket.size)
+	mt.reflexivekey = isReflexive(ktyp)
 	mt.uncommonType = nil
 	mt.ptrToThis = nil
-	mt.zero = unsafe.Pointer(&make([]byte, mt.size)[0])
 
 	return cachePut(ckey, &mt.rtype)
 }
 
-// gcProg is a helper type for generatation of GC pointer info.
-type gcProg struct {
-	gc     []byte
-	size   uintptr // size of type in bytes
-	hasPtr bool
-}
-
-func (gc *gcProg) append(v byte) {
-	gc.align(unsafe.Sizeof(uintptr(0)))
-	gc.appendWord(v)
-}
+// FuncOf returns the function type with the given argument and result types.
+// For example if k represents int and e represents string,
+// FuncOf([]Type{k}, []Type{e}, false) represents func(int) string.
+//
+// The variadic argument controls whether the function is variadic. FuncOf
+// panics if the in[len(in)-1] does not represent a slice and variadic is
+// true.
+func FuncOf(in, out []Type, variadic bool) Type {
+	if variadic && (len(in) == 0 || in[len(in)-1].Kind() != Slice) {
+		panic("reflect.FuncOf: last arg of variadic func must be slice")
+	}
+
+	// Make a func type.
+	var ifunc interface{} = (func())(nil)
+	prototype := *(**funcType)(unsafe.Pointer(&ifunc))
+	ft := new(funcType)
+	*ft = *prototype
+
+	// Build a hash and minimally populate ft.
+	var hash uint32
+	var fin, fout []*rtype
+	for _, in := range in {
+		t := in.(*rtype)
+		fin = append(fin, t)
+		hash = fnv1(hash, byte(t.hash>>24), byte(t.hash>>16), byte(t.hash>>8), byte(t.hash))
+	}
+	if variadic {
+		hash = fnv1(hash, 'v')
+	}
+	hash = fnv1(hash, '.')
+	for _, out := range out {
+		t := out.(*rtype)
+		fout = append(fout, t)
+		hash = fnv1(hash, byte(t.hash>>24), byte(t.hash>>16), byte(t.hash>>8), byte(t.hash))
+	}
+	ft.hash = hash
+	ft.in = fin
+	ft.out = fout
+	ft.dotdotdot = variadic
 
-// Appends t's type info to the current program.
-func (gc *gcProg) appendProg(t *rtype) {
-	gc.align(uintptr(t.align))
-	if !t.pointers() {
-		gc.size += t.size
-		return
-	}
-	switch t.Kind() {
-	default:
-		panic("reflect: non-pointer type marked as having pointers")
-	case Ptr, UnsafePointer, Chan, Func, Map:
-		gc.appendWord(bitsPointer)
-	case Slice:
-		gc.appendWord(bitsPointer)
-		gc.appendWord(bitsScalar)
-		gc.appendWord(bitsScalar)
-	case String:
-		gc.appendWord(bitsPointer)
-		gc.appendWord(bitsScalar)
-	case Array:
-		c := t.Len()
-		e := t.Elem().common()
-		for i := 0; i < c; i++ {
-			gc.appendProg(e)
-		}
-	case Interface:
-		gc.appendWord(bitsMultiWord)
-		if t.NumMethod() == 0 {
-			gc.appendWord(bitsEface)
-		} else {
-			gc.appendWord(bitsIface)
-		}
-	case Struct:
-		c := t.NumField()
-		for i := 0; i < c; i++ {
-			gc.appendProg(t.Field(i).Type.common())
+	// Look in cache.
+	funcLookupCache.RLock()
+	for _, t := range funcLookupCache.m[hash] {
+		if haveIdenticalUnderlyingType(&ft.rtype, t) {
+			funcLookupCache.RUnlock()
+			return t
 		}
-		gc.align(uintptr(t.align))
 	}
-}
+	funcLookupCache.RUnlock()
 
-func (gc *gcProg) appendWord(v byte) {
-	ptrsize := unsafe.Sizeof(uintptr(0))
-	if gc.size%ptrsize != 0 {
-		panic("reflect: unaligned GC program")
+	// Not in cache, lock and retry.
+	funcLookupCache.Lock()
+	defer funcLookupCache.Unlock()
+	if funcLookupCache.m == nil {
+		funcLookupCache.m = make(map[uint32][]*rtype)
 	}
-	nptr := gc.size / ptrsize
-	for uintptr(len(gc.gc)) < nptr/2+1 {
-		gc.gc = append(gc.gc, 0x44) // BitsScalar
+	for _, t := range funcLookupCache.m[hash] {
+		if haveIdenticalUnderlyingType(&ft.rtype, t) {
+			return t
+		}
 	}
-	gc.gc[nptr/2] &= ^(3 << ((nptr%2)*4 + 2))
-	gc.gc[nptr/2] |= v << ((nptr%2)*4 + 2)
-	gc.size += ptrsize
-	if v == bitsPointer {
-		gc.hasPtr = true
+
+	// Look in known types for the same string representation.
+	str := funcStr(ft)
+	for _, tt := range typesByString(str) {
+		if haveIdenticalUnderlyingType(&ft.rtype, tt) {
+			funcLookupCache.m[hash] = append(funcLookupCache.m[hash], tt)
+			return tt
+		}
 	}
+
+	// Populate the remaining fields of ft and store in cache.
+	ft.string = &str
+	ft.uncommonType = nil
+	ft.ptrToThis = nil
+	funcLookupCache.m[hash] = append(funcLookupCache.m[hash], &ft.rtype)
+
+	return &ft.rtype
 }
 
-func (gc *gcProg) finalize() (unsafe.Pointer, bool) {
-	if gc.size == 0 {
-		return nil, false
+// funcStr builds a string representation of a funcType.
+func funcStr(ft *funcType) string {
+	repr := make([]byte, 0, 64)
+	repr = append(repr, "func("...)
+	for i, t := range ft.in {
+		if i > 0 {
+			repr = append(repr, ", "...)
+		}
+		if ft.dotdotdot && i == len(ft.in)-1 {
+			repr = append(repr, "..."...)
+			repr = append(repr, *(*sliceType)(unsafe.Pointer(t)).elem.string...)
+		} else {
+			repr = append(repr, *t.string...)
+		}
 	}
-	ptrsize := unsafe.Sizeof(uintptr(0))
-	gc.align(ptrsize)
-	nptr := gc.size / ptrsize
-	for uintptr(len(gc.gc)) < nptr/2+1 {
-		gc.gc = append(gc.gc, 0x44) // BitsScalar
+	repr = append(repr, ')')
+	if l := len(ft.out); l == 1 {
+		repr = append(repr, ' ')
+	} else if l > 1 {
+		repr = append(repr, " ("...)
 	}
-	// If number of words is odd, repeat the mask twice.
-	// Compiler does the same.
-	if nptr%2 != 0 {
-		for i := uintptr(0); i < nptr; i++ {
-			gc.appendWord(extractGCWord(gc.gc, i))
+	for i, t := range ft.out {
+		if i > 0 {
+			repr = append(repr, ", "...)
 		}
+		repr = append(repr, *t.string...)
 	}
-	return unsafe.Pointer(&gc.gc[0]), gc.hasPtr
-}
-
-func extractGCWord(gc []byte, i uintptr) byte {
-	return (gc[i/2] >> ((i%2)*4 + 2)) & 3
+	if len(ft.out) > 1 {
+		repr = append(repr, ')')
+	}
+	return string(repr)
 }
 
-func (gc *gcProg) align(a uintptr) {
-	gc.size = align(gc.size, a)
+// isReflexive reports whether the == operation on the type is reflexive.
+// That is, x == x for all values x of type t.
+func isReflexive(t *rtype) bool {
+	switch t.Kind() {
+	case Bool, Int, Int8, Int16, Int32, Int64, Uint, Uint8, Uint16, Uint32, Uint64, Uintptr, Chan, Ptr, String, UnsafePointer:
+		return true
+	case Float32, Float64, Complex64, Complex128, Interface:
+		return false
+	case Array:
+		tt := (*arrayType)(unsafe.Pointer(t))
+		return isReflexive(tt.elem)
+	case Struct:
+		tt := (*structType)(unsafe.Pointer(t))
+		for _, f := range tt.fields {
+			if !isReflexive(f.typ) {
+				return false
+			}
+		}
+		return true
+	default:
+		// Func, Map, Slice, Invalid
+		panic("isReflexive called on non-key type " + t.String())
+	}
 }
 
-// These constants must stay in sync with ../runtime/mgc0.h.
-const (
-	bitsScalar    = 1
-	bitsPointer   = 2
-	bitsMultiWord = 3
-
-	bitsIface = 2
-	bitsEface = 3
-)
-
 // Make sure these routines stay in sync with ../../runtime/hashmap.go!
 // These types exist only for GC, so we only fill out GC relevant info.
 // Currently, that's just size and the GC program.  We also fill in string
 // for possible debugging use.
 const (
-	bucketSize = 8
-	maxKeySize = 128
-	maxValSize = 128
+	bucketSize uintptr = 8
+	maxKeySize uintptr = 128
+	maxValSize uintptr = 128
 )
 
 func bucketOf(ktyp, etyp *rtype) *rtype {
+	// See comment on hmap.overflow in ../runtime/hashmap.go.
+	var kind uint8
+	if ktyp.kind&kindNoPointers != 0 && etyp.kind&kindNoPointers != 0 &&
+		ktyp.size <= maxKeySize && etyp.size <= maxValSize {
+		kind = kindNoPointers
+	}
+
 	if ktyp.size > maxKeySize {
 		ktyp = PtrTo(ktyp).(*rtype)
 	}
 	if etyp.size > maxValSize {
 		etyp = PtrTo(etyp).(*rtype)
 	}
-	ptrsize := unsafe.Sizeof(uintptr(0))
 
-	var gc gcProg
-	// topbits
-	for i := 0; i < int(bucketSize*unsafe.Sizeof(uint8(0))/ptrsize); i++ {
-		gc.append(bitsScalar)
-	}
-	// keys
-	for i := 0; i < bucketSize; i++ {
-		gc.appendProg(ktyp)
-	}
-	// values
-	for i := 0; i < bucketSize; i++ {
-		gc.appendProg(etyp)
-	}
-	// overflow
-	gc.append(bitsPointer)
-	if runtime.GOARCH == "amd64p32" {
-		gc.append(bitsScalar)
+	// Prepare GC data if any.
+	// A bucket is at most bucketSize*(1+maxKeySize+maxValSize)+2*ptrSize bytes,
+	// or 2072 bytes, or 259 pointer-size words, or 33 bytes of pointer bitmap.
+	// Normally the enforced limit on pointer maps is 16 bytes,
+	// but larger ones are acceptable, 33 bytes isn't too too big,
+	// and it's easier to generate a pointer bitmap than a GC program.
+	// Note that since the key and value are known to be <= 128 bytes,
+	// they're guaranteed to have bitmaps instead of GC programs.
+	var gcdata *byte
+	var ptrdata uintptr
+	var overflowPad uintptr
+
+	// On NaCl, pad if needed to make overflow end at the proper struct alignment.
+	// On other systems, align > ptrSize is not possible.
+	if runtime.GOARCH == "amd64p32" && (ktyp.align > ptrSize || etyp.align > ptrSize) {
+		overflowPad = ptrSize
+	}
+	size := bucketSize*(1+ktyp.size+etyp.size) + overflowPad + ptrSize
+	if size&uintptr(ktyp.align-1) != 0 || size&uintptr(etyp.align-1) != 0 {
+		panic("reflect: bad size computation in MapOf")
+	}
+
+	if kind != kindNoPointers {
+		nptr := (bucketSize*(1+ktyp.size+etyp.size) + ptrSize) / ptrSize
+		mask := make([]byte, (nptr+7)/8)
+		base := bucketSize / ptrSize
+
+		if ktyp.kind&kindNoPointers == 0 {
+			if ktyp.kind&kindGCProg != 0 {
+				panic("reflect: unexpected GC program in MapOf")
+			}
+			kmask := (*[16]byte)(unsafe.Pointer(ktyp.gcdata))
+			for i := uintptr(0); i < ktyp.size/ptrSize; i++ {
+				if (kmask[i/8]>>(i%8))&1 != 0 {
+					for j := uintptr(0); j < bucketSize; j++ {
+						word := base + j*ktyp.size/ptrSize + i
+						mask[word/8] |= 1 << (word % 8)
+					}
+				}
+			}
+		}
+		base += bucketSize * ktyp.size / ptrSize
+
+		if etyp.kind&kindNoPointers == 0 {
+			if etyp.kind&kindGCProg != 0 {
+				panic("reflect: unexpected GC program in MapOf")
+			}
+			emask := (*[16]byte)(unsafe.Pointer(etyp.gcdata))
+			for i := uintptr(0); i < etyp.size/ptrSize; i++ {
+				if (emask[i/8]>>(i%8))&1 != 0 {
+					for j := uintptr(0); j < bucketSize; j++ {
+						word := base + j*etyp.size/ptrSize + i
+						mask[word/8] |= 1 << (word % 8)
+					}
+				}
+			}
+		}
+		base += bucketSize * etyp.size / ptrSize
+		base += overflowPad / ptrSize
+
+		word := base
+		mask[word/8] |= 1 << (word % 8)
+		gcdata = &mask[0]
+		ptrdata = (word + 1) * ptrSize
+
+		// overflow word must be last
+		if ptrdata != size {
+			panic("reflect: bad layout computation in MapOf")
+		}
 	}
 
 	b := new(rtype)
-	b.size = gc.size
-	b.gc[0], _ = gc.finalize()
+	b.align = ptrSize
+	if overflowPad > 0 {
+		b.align = 8
+	}
+	b.size = size
+	b.ptrdata = ptrdata
+	b.kind = kind
+	b.gcdata = gcdata
 	s := "bucket(" + *ktyp.string + "," + *etyp.string + ")"
 	b.string = &s
 	return b
@@ -1680,36 +1810,36 @@ func SliceOf(t Type) Type {
 	slice.elem = typ
 	slice.uncommonType = nil
 	slice.ptrToThis = nil
-	slice.zero = unsafe.Pointer(&make([]byte, slice.size)[0])
 
 	return cachePut(ckey, &slice.rtype)
 }
 
+// See cmd/compile/internal/gc/reflect.go for derivation of constant.
+const maxPtrmaskBytes = 2048
+
 // ArrayOf returns the array type with the given count and element type.
 // For example, if t represents int, ArrayOf(5, t) represents [5]int.
 //
 // If the resulting type would be larger than the available address space,
 // ArrayOf panics.
-//
-// TODO(rsc): Unexported for now. Export once the alg field is set correctly
-// for the type. This may require significant work.
-//
-// TODO(rsc): TestArrayOf is also disabled. Re-enable.
-func arrayOf(count int, elem Type) Type {
+func ArrayOf(count int, elem Type) Type {
 	typ := elem.(*rtype)
+	// call SliceOf here as it calls cacheGet/cachePut.
+	// ArrayOf also calls cacheGet/cachePut and thus may modify the state of
+	// the lookupCache mutex.
 	slice := SliceOf(elem)
 
 	// Look in cache.
 	ckey := cacheKey{Array, typ, nil, uintptr(count)}
-	if slice := cacheGet(ckey); slice != nil {
-		return slice
+	if array := cacheGet(ckey); array != nil {
+		return array
 	}
 
 	// Look in known types.
 	s := "[" + strconv.Itoa(count) + "]" + *typ.string
 	for _, tt := range typesByString(s) {
-		slice := (*sliceType)(unsafe.Pointer(tt))
-		if slice.elem == typ {
+		array := (*arrayType)(unsafe.Pointer(tt))
+		if array.elem == typ {
 			return cachePut(ckey, tt)
 		}
 	}
@@ -1719,7 +1849,6 @@ func arrayOf(count int, elem Type) Type {
 	prototype := *(**arrayType)(unsafe.Pointer(&iarray))
 	array := new(arrayType)
 	*array = *prototype
-	// TODO: Set extra kind bits correctly.
 	array.string = &s
 	array.hash = fnv1(typ.hash, '[')
 	for n := uint32(count); n > 0; n >>= 8 {
@@ -1732,20 +1861,144 @@ func arrayOf(count int, elem Type) Type {
 		panic("reflect.ArrayOf: array size would exceed virtual address space")
 	}
 	array.size = typ.size * uintptr(count)
+	if count > 0 && typ.ptrdata != 0 {
+		array.ptrdata = typ.size*uintptr(count-1) + typ.ptrdata
+	}
 	array.align = typ.align
 	array.fieldAlign = typ.fieldAlign
-	// TODO: array.alg
-	// TODO: array.gc
-	// TODO:
 	array.uncommonType = nil
 	array.ptrToThis = nil
-	array.zero = unsafe.Pointer(&make([]byte, array.size)[0])
 	array.len = uintptr(count)
 	array.slice = slice.(*rtype)
 
+	array.kind &^= kindNoPointers
+	switch {
+	case typ.kind&kindNoPointers != 0 || array.size == 0:
+		// No pointers.
+		array.kind |= kindNoPointers
+		array.gcdata = nil
+		array.ptrdata = 0
+
+	case count == 1:
+		// In memory, 1-element array looks just like the element.
+		array.kind |= typ.kind & kindGCProg
+		array.gcdata = typ.gcdata
+		array.ptrdata = typ.ptrdata
+
+	case typ.kind&kindGCProg == 0 && array.size <= maxPtrmaskBytes*8*ptrSize:
+		// Element is small with pointer mask; array is still small.
+		// Create direct pointer mask by turning each 1 bit in elem
+		// into count 1 bits in larger mask.
+		mask := make([]byte, (array.ptrdata/ptrSize+7)/8)
+		elemMask := (*[1 << 30]byte)(unsafe.Pointer(typ.gcdata))[:]
+		elemWords := typ.size / ptrSize
+		for j := uintptr(0); j < typ.ptrdata/ptrSize; j++ {
+			if (elemMask[j/8]>>(j%8))&1 != 0 {
+				for i := uintptr(0); i < array.len; i++ {
+					k := i*elemWords + j
+					mask[k/8] |= 1 << (k % 8)
+				}
+			}
+		}
+		array.gcdata = &mask[0]
+
+	default:
+		// Create program that emits one element
+		// and then repeats to make the array.
+		prog := []byte{0, 0, 0, 0} // will be length of prog
+		elemGC := (*[1 << 30]byte)(unsafe.Pointer(typ.gcdata))[:]
+		elemPtrs := typ.ptrdata / ptrSize
+		if typ.kind&kindGCProg == 0 {
+			// Element is small with pointer mask; use as literal bits.
+			mask := elemGC
+			// Emit 120-bit chunks of full bytes (max is 127 but we avoid using partial bytes).
+			var n uintptr
+			for n = elemPtrs; n > 120; n -= 120 {
+				prog = append(prog, 120)
+				prog = append(prog, mask[:15]...)
+				mask = mask[15:]
+			}
+			prog = append(prog, byte(n))
+			prog = append(prog, mask[:(n+7)/8]...)
+		} else {
+			// Element has GC program; emit one element.
+			elemProg := elemGC[4 : 4+*(*uint32)(unsafe.Pointer(&elemGC[0]))-1]
+			prog = append(prog, elemProg...)
+		}
+		// Pad from ptrdata to size.
+		elemWords := typ.size / ptrSize
+		if elemPtrs < elemWords {
+			// Emit literal 0 bit, then repeat as needed.
+			prog = append(prog, 0x01, 0x00)
+			if elemPtrs+1 < elemWords {
+				prog = append(prog, 0x81)
+				prog = appendVarint(prog, elemWords-elemPtrs-1)
+			}
+		}
+		// Repeat count-1 times.
+		if elemWords < 0x80 {
+			prog = append(prog, byte(elemWords|0x80))
+		} else {
+			prog = append(prog, 0x80)
+			prog = appendVarint(prog, elemWords)
+		}
+		prog = appendVarint(prog, uintptr(count)-1)
+		prog = append(prog, 0)
+		*(*uint32)(unsafe.Pointer(&prog[0])) = uint32(len(prog) - 4)
+		array.kind |= kindGCProg
+		array.gcdata = &prog[0]
+		array.ptrdata = array.size // overestimate but ok; must match program
+	}
+
+	etyp := typ.common()
+	esize := etyp.Size()
+	ealg := etyp.alg
+
+	array.alg = new(typeAlg)
+	if ealg.equal != nil {
+		eequal := ealg.equal
+		array.alg.equal = func(p, q unsafe.Pointer) bool {
+			for i := 0; i < count; i++ {
+				pi := arrayAt(p, i, esize)
+				qi := arrayAt(q, i, esize)
+				if !eequal(pi, qi) {
+					return false
+				}
+
+			}
+			return true
+		}
+	}
+	if ealg.hash != nil {
+		ehash := ealg.hash
+		array.alg.hash = func(ptr unsafe.Pointer, seed uintptr) uintptr {
+			o := seed
+			for i := 0; i < count; i++ {
+				o = ehash(arrayAt(ptr, i, esize), o)
+			}
+			return o
+		}
+	}
+
+	switch {
+	case count == 1 && !ifaceIndir(typ):
+		// array of 1 direct iface type can be direct
+		array.kind |= kindDirectIface
+	default:
+		array.kind &^= kindDirectIface
+	}
+
 	return cachePut(ckey, &array.rtype)
 }
 
+func appendVarint(x []byte, v uintptr) []byte {
+	for ; v >= 0x80; v >>= 7 {
+		x = append(x, byte(v|0x80))
+	}
+	x = append(x, byte(v))
+	return x
+}
+
 // toType converts from a *rtype to a Type that can be returned
 // to the client of package reflect. In gc, the only concern is that
 // a nil *rtype must be replaced by a nil Type, but in gccgo this
@@ -1768,6 +2021,7 @@ type layoutType struct {
 	argSize   uintptr // size of arguments
 	retOffset uintptr // offset of return values.
 	stack     *bitVector
+	framePool *sync.Pool
 }
 
 var layoutCache struct {
@@ -1781,7 +2035,7 @@ var layoutCache struct {
 // The returned type exists only for GC, so we only fill out GC relevant info.
 // Currently, that's just size and the GC program.  We also fill in
 // the name for possible debugging use.
-func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uintptr, stack *bitVector) {
+func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uintptr, stk *bitVector, framePool *sync.Pool) {
 	if t.Kind() != Func {
 		panic("reflect: funcLayout of non-func type")
 	}
@@ -1792,64 +2046,63 @@ func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uin
 	layoutCache.RLock()
 	if x := layoutCache.m[k]; x.t != nil {
 		layoutCache.RUnlock()
-		return x.t, x.argSize, x.retOffset, x.stack
+		return x.t, x.argSize, x.retOffset, x.stack, x.framePool
 	}
 	layoutCache.RUnlock()
 	layoutCache.Lock()
 	if x := layoutCache.m[k]; x.t != nil {
 		layoutCache.Unlock()
-		return x.t, x.argSize, x.retOffset, x.stack
+		return x.t, x.argSize, x.retOffset, x.stack, x.framePool
 	}
 
 	tt := (*funcType)(unsafe.Pointer(t))
 
 	// compute gc program & stack bitmap for arguments
-	stack = new(bitVector)
-	var gc gcProg
+	ptrmap := new(bitVector)
 	var offset uintptr
 	if rcvr != nil {
 		// Reflect uses the "interface" calling convention for
 		// methods, where receivers take one word of argument
 		// space no matter how big they actually are.
-		if ifaceIndir(rcvr) {
-			// we pass a pointer to the receiver.
-			gc.append(bitsPointer)
-			stack.append2(bitsPointer)
-		} else if rcvr.pointers() {
-			// rcvr is a one-word pointer object.  Its gc program
-			// is just what we need here.
-			gc.append(bitsPointer)
-			stack.append2(bitsPointer)
-		} else {
-			gc.append(bitsScalar)
-			stack.append2(bitsScalar)
+		if ifaceIndir(rcvr) || rcvr.pointers() {
+			ptrmap.append(1)
 		}
 		offset += ptrSize
 	}
 	for _, arg := range tt.in {
-		gc.appendProg(arg)
-		addTypeBits(stack, &offset, arg)
+		offset += -offset & uintptr(arg.align-1)
+		addTypeBits(ptrmap, offset, arg)
+		offset += arg.size
 	}
-	argSize = gc.size
+	argN := ptrmap.n
+	argSize = offset
 	if runtime.GOARCH == "amd64p32" {
-		gc.align(8)
+		offset += -offset & (8 - 1)
 	}
-	gc.align(ptrSize)
-	retOffset = gc.size
+	offset += -offset & (ptrSize - 1)
+	retOffset = offset
 	for _, res := range tt.out {
-		gc.appendProg(res)
-		// stack map does not need result bits
+		offset += -offset & uintptr(res.align-1)
+		addTypeBits(ptrmap, offset, res)
+		offset += res.size
 	}
-	gc.align(ptrSize)
+	offset += -offset & (ptrSize - 1)
 
 	// build dummy rtype holding gc program
 	x := new(rtype)
-	x.size = gc.size
-	var hasPtr bool
-	x.gc[0], hasPtr = gc.finalize()
-	if !hasPtr {
+	x.align = ptrSize
+	if runtime.GOARCH == "amd64p32" {
+		x.align = 8
+	}
+	x.size = offset
+	x.ptrdata = uintptr(ptrmap.n) * ptrSize
+	if ptrmap.n > 0 {
+		x.gcdata = &ptrmap.data[0]
+	} else {
 		x.kind |= kindNoPointers
 	}
+	ptrmap.n = argN
+
 	var s string
 	if rcvr != nil {
 		s = "methodargs(" + *rcvr.string + ")(" + *t.string + ")"
@@ -1862,14 +2115,18 @@ func funcLayout(t *rtype, rcvr *rtype) (frametype *rtype, argSize, retOffset uin
 	if layoutCache.m == nil {
 		layoutCache.m = make(map[layoutKey]layoutType)
 	}
+	framePool = &sync.Pool{New: func() interface{} {
+		return unsafe_New(x)
+	}}
 	layoutCache.m[k] = layoutType{
 		t:         x,
 		argSize:   argSize,
 		retOffset: retOffset,
-		stack:     stack,
+		stack:     ptrmap,
+		framePool: framePool,
 	}
 	layoutCache.Unlock()
-	return x, argSize, retOffset, stack
+	return x, argSize, retOffset, ptrmap, framePool
 }
 
 // ifaceIndir reports whether t is stored indirectly in an interface value.
@@ -1883,56 +2140,49 @@ type bitVector struct {
 	data []byte
 }
 
-// append a bit pair to the bitmap.
-func (bv *bitVector) append2(bits uint8) {
-	// assume bv.n is a multiple of 2, since append2 is the only operation.
+// append a bit to the bitmap.
+func (bv *bitVector) append(bit uint8) {
 	if bv.n%8 == 0 {
 		bv.data = append(bv.data, 0)
 	}
-	bv.data[bv.n/8] |= bits << (bv.n % 8)
-	bv.n += 2
+	bv.data[bv.n/8] |= bit << (bv.n % 8)
+	bv.n++
 }
 
-func addTypeBits(bv *bitVector, offset *uintptr, t *rtype) {
-	*offset = align(*offset, uintptr(t.align))
+func addTypeBits(bv *bitVector, offset uintptr, t *rtype) {
 	if t.kind&kindNoPointers != 0 {
-		*offset += t.size
 		return
 	}
 
 	switch Kind(t.kind & kindMask) {
 	case Chan, Func, Map, Ptr, Slice, String, UnsafePointer:
 		// 1 pointer at start of representation
-		for bv.n < 2*uint32(*offset/uintptr(ptrSize)) {
-			bv.append2(bitsScalar)
+		for bv.n < uint32(offset/uintptr(ptrSize)) {
+			bv.append(0)
 		}
-		bv.append2(bitsPointer)
+		bv.append(1)
 
 	case Interface:
 		// 2 pointers
-		for bv.n < 2*uint32(*offset/uintptr(ptrSize)) {
-			bv.append2(bitsScalar)
+		for bv.n < uint32(offset/uintptr(ptrSize)) {
+			bv.append(0)
 		}
-		bv.append2(bitsPointer)
-		bv.append2(bitsPointer)
+		bv.append(1)
+		bv.append(1)
 
 	case Array:
 		// repeat inner type
 		tt := (*arrayType)(unsafe.Pointer(t))
 		for i := 0; i < int(tt.len); i++ {
-			addTypeBits(bv, offset, tt.elem)
+			addTypeBits(bv, offset+uintptr(i)*tt.elem.size, tt.elem)
 		}
 
 	case Struct:
 		// apply fields
 		tt := (*structType)(unsafe.Pointer(t))
-		start := *offset
 		for i := range tt.fields {
 			f := &tt.fields[i]
-			off := start + f.offset
-			addTypeBits(bv, &off, f.typ)
+			addTypeBits(bv, offset+f.offset, f.typ)
 		}
 	}
-
-	*offset += t.size
 }
diff --git a/src/reflect/value.go b/src/reflect/value.go
index 43843e9..001d027 100644
--- a/src/reflect/value.go
+++ b/src/reflect/value.go
@@ -10,7 +10,7 @@ import (
 	"unsafe"
 )
 
-const ptrSize = unsafe.Sizeof((*byte)(nil))
+const ptrSize = 4 << (^uintptr(0) >> 63) // unsafe.Sizeof(uintptr(0)) but an ideal const
 const cannotSet = "cannot set value obtained from unexported struct field"
 
 // Value is the reflection interface to a Go value.
@@ -30,6 +30,10 @@ const cannotSet = "cannot set value obtained from unexported struct field"
 // A Value can be used concurrently by multiple goroutines provided that
 // the underlying Go value can be used concurrently for the equivalent
 // direct operations.
+//
+// Using == on two Values does not compare the underlying values
+// they represent, but rather the contents of the Value structs.
+// To compare two Values, compare the results of the Interface method.
 type Value struct {
 	// typ holds the type of the value represented by a Value.
 	typ *rtype
@@ -103,7 +107,7 @@ func packEface(v Value) interface{} {
 			// TODO: pass safe boolean from valueInterface so
 			// we don't need to copy if safe==true?
 			c := unsafe_New(t)
-			memmove(c, ptr, t.size)
+			typedmemmove(t, c, ptr)
 			ptr = c
 		}
 		e.word = ptr
@@ -172,7 +176,7 @@ type emptyInterface struct {
 
 // 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
@@ -264,7 +268,7 @@ func (v Value) runes() []rune {
 	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.
@@ -273,11 +277,11 @@ func (v Value) CanAddr() bool {
 	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
-// setter (e.g., SetBool, SetInt64) will panic.
+// setter (e.g., SetBool, SetInt) will panic.
 func (v Value) CanSet() bool {
 	return v.flag&(flagAddr|flagRO) == flagAddr
 }
@@ -298,8 +302,8 @@ func (v Value) Call(in []Value) []Value {
 
 // CallSlice calls the variadic function v with the input arguments in,
 // assigning the slice in[len(in)-1] to v's final variadic argument.
-// For example, if len(in) == 3, v.Call(in) represents the Go call v(in[0], in[1], in[2]...).
-// Call panics if v's Kind is not Func or if v is not variadic.
+// For example, if len(in) == 3, v.CallSlice(in) represents the Go call v(in[0], in[1], in[2]...).
+// CallSlice panics if v's Kind is not Func or if v is not variadic.
 // It returns the output results as Values.
 // As in Go, each input argument must be assignable to the
 // type of the function's corresponding input parameter.
@@ -389,9 +393,18 @@ func (v Value) call(op string, in []Value) []Value {
 	}
 	nout := t.NumOut()
 
-	// Compute frame type, allocate a chunk of memory for frame
-	frametype, _, retOffset, _ := funcLayout(t, rcvrtype)
-	args := unsafe_New(frametype)
+	// Compute frame type.
+	frametype, _, retOffset, _, framePool := funcLayout(t, rcvrtype)
+
+	// Allocate a chunk of memory for frame.
+	var args unsafe.Pointer
+	if nout == 0 {
+		args = framePool.Get().(unsafe.Pointer)
+	} else {
+		// Can't use pool if the function has return values.
+		// We will leak pointer to args in ret, so its lifetime is not scoped.
+		args = unsafe_New(frametype)
+	}
 	off := uintptr(0)
 
 	// Copy inputs into args.
@@ -408,7 +421,7 @@ func (v Value) call(op string, in []Value) []Value {
 		addr := unsafe.Pointer(uintptr(args) + off)
 		v = v.assignTo("reflect.Value.Call", targ, addr)
 		if v.flag&flagIndir != 0 {
-			memmove(addr, v.ptr, n)
+			typedmemmove(targ, addr, v.ptr)
 		} else {
 			*(*unsafe.Pointer)(addr) = v.ptr
 		}
@@ -416,23 +429,33 @@ func (v Value) call(op string, in []Value) []Value {
 	}
 
 	// Call.
-	call(fn, args, uint32(frametype.size), uint32(retOffset))
+	call(frametype, fn, args, uint32(frametype.size), uint32(retOffset))
 
 	// For testing; see TestCallMethodJump.
 	if callGC {
 		runtime.GC()
 	}
 
-	// Copy return values out of args.
-	ret := make([]Value, nout)
-	off = retOffset
-	for i := 0; i < nout; i++ {
-		tv := t.Out(i)
-		a := uintptr(tv.Align())
-		off = (off + a - 1) &^ (a - 1)
-		fl := flagIndir | flag(tv.Kind())
-		ret[i] = Value{tv.common(), unsafe.Pointer(uintptr(args) + off), fl}
-		off += tv.Size()
+	var ret []Value
+	if nout == 0 {
+		memclr(args, frametype.size)
+		framePool.Put(args)
+	} else {
+		// Zero the now unused input area of args,
+		// because the Values returned by this function contain pointers to the args object,
+		// and will thus keep the args object alive indefinitely.
+		memclr(args, retOffset)
+		// Copy return values out of args.
+		ret = make([]Value, nout)
+		off = retOffset
+		for i := 0; i < nout; i++ {
+			tv := t.Out(i)
+			a := uintptr(tv.Align())
+			off = (off + a - 1) &^ (a - 1)
+			fl := flagIndir | flag(tv.Kind())
+			ret[i] = Value{tv.common(), unsafe.Pointer(uintptr(args) + off), fl}
+			off += tv.Size()
+		}
 	}
 
 	return ret
@@ -469,7 +492,7 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) {
 			// and we cannot let f keep a reference to the stack frame
 			// after this function returns, not even a read-only reference.
 			v.ptr = unsafe_New(typ)
-			memmove(v.ptr, addr, typ.size)
+			typedmemmove(typ, v.ptr, addr)
 			v.flag |= flagIndir
 		} else {
 			v.ptr = *(*unsafe.Pointer)(addr)
@@ -505,7 +528,7 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer) {
 			off += -off & uintptr(typ.align-1)
 			addr := unsafe.Pointer(uintptr(ptr) + off)
 			if v.flag&flagIndir != 0 {
-				memmove(addr, v.ptr, typ.size)
+				typedmemmove(typ, addr, v.ptr)
 			} else {
 				*(*unsafe.Pointer)(addr) = v.ptr
 			}
@@ -592,17 +615,17 @@ func align(x, n uintptr) uintptr {
 func callMethod(ctxt *methodValue, frame unsafe.Pointer) {
 	rcvr := ctxt.rcvr
 	rcvrtype, t, fn := methodReceiver("call", rcvr, ctxt.method)
-	frametype, argSize, retOffset, _ := funcLayout(t, rcvrtype)
+	frametype, argSize, retOffset, _, framePool := funcLayout(t, rcvrtype)
 
 	// Make a new frame that is one word bigger so we can store the receiver.
-	args := unsafe_New(frametype)
+	args := framePool.Get().(unsafe.Pointer)
 
 	// Copy in receiver and rest of args.
 	storeRcvr(rcvr, args)
-	memmove(unsafe.Pointer(uintptr(args)+ptrSize), frame, argSize-ptrSize)
+	typedmemmovepartial(frametype, unsafe.Pointer(uintptr(args)+ptrSize), frame, ptrSize, argSize-ptrSize)
 
 	// Call.
-	call(fn, args, uint32(frametype.size), uint32(retOffset))
+	call(frametype, fn, args, uint32(frametype.size), uint32(retOffset))
 
 	// Copy return values. On amd64p32, the beginning of return values
 	// is 64-bit aligned, so the caller's frame layout (which doesn't have
@@ -613,8 +636,14 @@ func callMethod(ctxt *methodValue, frame unsafe.Pointer) {
 	if runtime.GOARCH == "amd64p32" {
 		callerRetOffset = align(argSize-ptrSize, 8)
 	}
-	memmove(unsafe.Pointer(uintptr(frame)+callerRetOffset),
-		unsafe.Pointer(uintptr(args)+retOffset), frametype.size-retOffset)
+	typedmemmovepartial(frametype,
+		unsafe.Pointer(uintptr(frame)+callerRetOffset),
+		unsafe.Pointer(uintptr(args)+retOffset),
+		retOffset,
+		frametype.size-retOffset)
+
+	memclr(args, frametype.size)
+	framePool.Put(args)
 }
 
 // funcName returns the name of f, for use in error messages.
@@ -725,7 +754,7 @@ func (v Value) Field(i int) Value {
 	// Either flagIndir is set and v.ptr points at struct,
 	// or flagIndir is not set and v.ptr is the actual struct data.
 	// In the former case, we want v.ptr + offset.
-	// In the latter case, we must be have field.offset = 0,
+	// In the latter case, we must have field.offset = 0,
 	// so v.ptr + field.offset is still okay.
 	ptr := unsafe.Pointer(uintptr(v.ptr) + field.offset)
 	return Value{typ, ptr, fl}
@@ -819,7 +848,7 @@ func (v Value) Index(i int) Value {
 		}
 		tt := (*sliceType)(unsafe.Pointer(v.typ))
 		typ := tt.elem
-		val := unsafe.Pointer(uintptr(s.Data) + uintptr(i)*typ.size)
+		val := arrayAt(s.Data, i, typ.size)
 		fl := flagAddr | flagIndir | v.flag&flagRO | flag(typ.Kind())
 		return Value{typ, val, fl}
 
@@ -828,7 +857,7 @@ func (v Value) Index(i int) Value {
 		if uint(i) >= uint(s.Len) {
 			panic("reflect: string index out of range")
 		}
-		p := unsafe.Pointer(uintptr(s.Data) + uintptr(i))
+		p := arrayAt(s.Data, i, 1)
 		fl := v.flag&flagRO | flag(Uint8) | flagIndir
 		return Value{uint8Type, p, fl}
 	}
@@ -855,7 +884,7 @@ func (v Value) Int() int64 {
 	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})
@@ -942,7 +971,7 @@ func (v Value) IsNil() bool {
 	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.
@@ -1013,7 +1042,7 @@ func (v Value) MapIndex(key Value) Value {
 		// Copy result so future changes to the map
 		// won't change the underlying value.
 		c := unsafe_New(typ)
-		memmove(c, e, typ.size)
+		typedmemmove(typ, c, e)
 		return Value{typ, c, fl | flagIndir}
 	} else {
 		return Value{typ, *(*unsafe.Pointer)(e), fl}
@@ -1051,7 +1080,7 @@ func (v Value) MapKeys() []Value {
 			// Copy result so future changes to the map
 			// won't change the underlying value.
 			c := unsafe_New(keyType)
-			memmove(c, key, keyType.size)
+			typedmemmove(keyType, c, key)
 			a[i] = Value{keyType, c, fl | flagIndir}
 		} else {
 			a[i] = Value{keyType, *(*unsafe.Pointer)(key), fl}
@@ -1119,7 +1148,7 @@ func (v Value) NumField() int {
 	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()
@@ -1132,7 +1161,7 @@ func (v Value) OverflowComplex(x complex128) bool {
 	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()
@@ -1152,7 +1181,7 @@ func overflowFloat32(x float64) bool {
 	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()
@@ -1165,7 +1194,7 @@ func (v Value) OverflowInt(x int64) bool {
 	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()
@@ -1297,7 +1326,7 @@ func (v Value) Set(x Value) {
 	}
 	x = x.assignTo("reflect.Set", v.typ, target)
 	if x.flag&flagIndir != 0 {
-		memmove(v.ptr, x.ptr, v.typ.size)
+		typedmemmove(v.typ, v.ptr, x.ptr)
 	} else {
 		*(*unsafe.Pointer)(v.ptr) = x.ptr
 	}
@@ -1511,7 +1540,7 @@ func (v Value) Slice(i, j int) Value {
 		if i < 0 || j < i || j > s.Len {
 			panic("reflect.Value.Slice: string slice index out of bounds")
 		}
-		t := stringHeader{unsafe.Pointer(uintptr(s.Data) + uintptr(i)), j - i}
+		t := stringHeader{arrayAt(s.Data, i, 1), j - i}
 		return Value{v.typ, unsafe.Pointer(&t), v.flag}
 	}
 
@@ -1527,7 +1556,7 @@ func (v Value) Slice(i, j int) Value {
 	s.Len = j - i
 	s.Cap = cap - i
 	if cap-i > 0 {
-		s.Data = unsafe.Pointer(uintptr(base) + uintptr(i)*typ.elem.Size())
+		s.Data = arrayAt(base, i, typ.elem.Size())
 	} else {
 		// do not advance pointer, to avoid pointing beyond end of slice
 		s.Data = base
@@ -1579,7 +1608,7 @@ func (v Value) Slice3(i, j, k int) Value {
 	s.Len = j - i
 	s.Cap = k - i
 	if k-i > 0 {
-		s.Data = unsafe.Pointer(uintptr(base) + uintptr(i)*typ.elem.Size())
+		s.Data = arrayAt(base, i, typ.elem.Size())
 	} else {
 		// do not advance pointer, to avoid pointing beyond end of slice
 		s.Data = base
@@ -1593,6 +1622,8 @@ func (v Value) Slice3(i, j, k int) Value {
 // String is a special case because of Go's String method convention.
 // Unlike the other getters, it does not panic if v's Kind is not String.
 // Instead, it returns a string of the form "<T value>" where T is v's type.
+// The fmt package treats Values specially. It does not call their String
+// method implicitly but instead prints the concrete values they hold.
 func (v Value) String() string {
 	switch k := v.kind(); k {
 	case Invalid:
@@ -1618,7 +1649,7 @@ func (v Value) TryRecv() (x Value, ok bool) {
 
 // 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)
@@ -1736,6 +1767,12 @@ func typesMustMatch(what string, t1, t2 Type) {
 	}
 }
 
+// arrayAt returns the i-th element of p, a C-array whose elements are
+// eltSize wide (in bytes).
+func arrayAt(p unsafe.Pointer, i int, eltSize uintptr) unsafe.Pointer {
+	return unsafe.Pointer(uintptr(p) + uintptr(i)*eltSize)
+}
+
 // grow grows the slice s so that it can hold extra more values, allocating
 // more capacity if needed. It also returns the old and new slice lengths.
 func grow(s Value, extra int) (Value, int, int) {
@@ -1811,27 +1848,23 @@ func Copy(dst, src Value) int {
 	se := src.typ.Elem()
 	typesMustMatch("reflect.Copy", de, se)
 
-	n := dst.Len()
-	if sn := src.Len(); n > sn {
-		n = sn
-	}
-
-	// Copy via memmove.
-	var da, sa unsafe.Pointer
+	var ds, ss sliceHeader
 	if dk == Array {
-		da = dst.ptr
+		ds.Data = dst.ptr
+		ds.Len = dst.Len()
+		ds.Cap = ds.Len
 	} else {
-		da = (*sliceHeader)(dst.ptr).Data
+		ds = *(*sliceHeader)(dst.ptr)
 	}
-	if src.flag&flagIndir == 0 {
-		sa = unsafe.Pointer(&src.ptr)
-	} else if sk == Array {
-		sa = src.ptr
+	if sk == Array {
+		ss.Data = src.ptr
+		ss.Len = src.Len()
+		ss.Cap = ss.Len
 	} else {
-		sa = (*sliceHeader)(src.ptr).Data
+		ss = *(*sliceHeader)(src.ptr)
 	}
-	memmove(da, sa, uintptr(n)*de.Size())
-	return n
+
+	return typedslicecopy(de.common(), ds, ss)
 }
 
 // A runtimeSelect is a single case passed to rselect.
@@ -2372,7 +2405,7 @@ func cvtDirect(v Value, typ Type) Value {
 	if f&flagAddr != 0 {
 		// indirect, mutable word - make a copy
 		c := unsafe_New(t)
-		memmove(c, ptr, t.size)
+		typedmemmove(t, c, ptr)
 		ptr = c
 		f &^= flagAddr
 	}
@@ -2414,19 +2447,54 @@ func chansend(t *rtype, ch unsafe.Pointer, val unsafe.Pointer, nb bool) bool
 
 func makechan(typ *rtype, size uint64) (ch unsafe.Pointer)
 func makemap(t *rtype) (m unsafe.Pointer)
+
+//go:noescape
 func mapaccess(t *rtype, m unsafe.Pointer, key unsafe.Pointer) (val unsafe.Pointer)
+
 func mapassign(t *rtype, m unsafe.Pointer, key, val unsafe.Pointer)
+
+//go:noescape
 func mapdelete(t *rtype, m unsafe.Pointer, key unsafe.Pointer)
+
+// m escapes into the return value, but the caller of mapiterinit
+// doesn't let the return value escape.
+//go:noescape
 func mapiterinit(t *rtype, m unsafe.Pointer) unsafe.Pointer
+
+//go:noescape
 func mapiterkey(it unsafe.Pointer) (key unsafe.Pointer)
+
+//go:noescape
 func mapiternext(it unsafe.Pointer)
+
+//go:noescape
 func maplen(m unsafe.Pointer) int
-func call(fn, arg unsafe.Pointer, n uint32, retoffset uint32)
+
+// call calls fn with a copy of the n argument bytes pointed at by arg.
+// After fn returns, reflectcall copies n-retoffset result bytes
+// back into arg+retoffset before returning. If copying result bytes back,
+// the caller must pass the argument frame type as argtype, so that
+// call can execute appropriate write barriers during the copy.
+func call(argtype *rtype, fn, arg unsafe.Pointer, n uint32, retoffset uint32)
 
 func ifaceE2I(t *rtype, src interface{}, dst unsafe.Pointer)
 
+// typedmemmove copies a value of type t to dst from src.
+//go:noescape
+func typedmemmove(t *rtype, dst, src unsafe.Pointer)
+
+// typedmemmovepartial is like typedmemmove but assumes that
+// dst and src point off bytes into the value and only copies size bytes.
+//go:noescape
+func typedmemmovepartial(t *rtype, dst, src unsafe.Pointer, off, size uintptr)
+
+// typedslicecopy copies a slice of elemType values from src to dst,
+// returning the number of elements copied.
+//go:noescape
+func typedslicecopy(elemType *rtype, dst, src sliceHeader) int
+
 //go:noescape
-func memmove(adst, asrc unsafe.Pointer, n uintptr)
+func memclr(ptr unsafe.Pointer, n uintptr)
 
 // Dummy annotation marking that the value x escapes,
 // for use in cases where the reflect code is so clever that
diff --git a/src/regexp/all_test.go b/src/regexp/all_test.go
index 01ea374..d78ae6a 100644
--- a/src/regexp/all_test.go
+++ b/src/regexp/all_test.go
@@ -489,6 +489,17 @@ func TestOnePassCutoff(t *testing.T) {
 	}
 }
 
+// Check that the same machine can be used with the standard matcher
+// and then the backtracker when there are no captures.
+func TestSwitchBacktrack(t *testing.T) {
+	re := MustCompile(`a|b`)
+	long := make([]byte, maxBacktrackVector+1)
+
+	// The following sequence of Match calls used to panic. See issue #10319.
+	re.Match(long)     // triggers standard matcher
+	re.Match(long[:1]) // triggers backtracker
+}
+
 func BenchmarkLiteral(b *testing.B) {
 	x := strings.Repeat("x", 50) + "y"
 	b.StopTimer()
diff --git a/src/regexp/backtrack.go b/src/regexp/backtrack.go
new file mode 100644
index 0000000..fd95604
--- /dev/null
+++ b/src/regexp/backtrack.go
@@ -0,0 +1,366 @@
+// 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
+	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 {
+	if !shouldBacktrack(prog) {
+		return 0
+	}
+	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 !shouldBacktrack(prog) {
+		return notBacktrack
+	}
+	return &bitState{
+		prog: prog,
+	}
+}
+
+// shouldBacktrack reports whether the program is too
+// long for the backtracker to run.
+func shouldBacktrack(prog *syntax.Prog) bool {
+	return len(prog.Inst) <= maxBacktrackProg
+}
+
+// reset resets the state of the backtracker.
+// end is the end position in the input.
+// ncap is the number of captures.
+func (b *bitState) reset(end int, ncap int) {
+	b.end = end
+
+	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 cap(b.cap) < ncap {
+		b.cap = make([]int, ncap)
+	} else {
+		b.cap = b.cap[: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 len(b.cap) == 0 {
+				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.
+			if len(b.cap) > 1 {
+				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, ncap 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, ncap)
+
+	m.matchcap = m.matchcap[:ncap]
+	for i := range m.matchcap {
+		m.matchcap[i] = -1
+	}
+
+	// Anchored search must start at the beginning of the input
+	if startCond&syntax.EmptyBeginText != 0 {
+		if len(b.cap) > 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
+		}
+
+		if len(b.cap) > 0 {
+			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 @@ type thread struct {
 
 // 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 @@ func progMachine(p *syntax.Prog, op *onePassProg) *machine {
 	if ncap < 2 {
 		ncap = 2
 	}
+	if op == notOnePass {
+		m.maxBitStateLen = maxBitStateLen(p)
+	}
 	m.matchcap = make([]int, ncap)
 	return m
 }
@@ -422,18 +427,29 @@ var empty = make([]int, 0)
 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/exec_test.go b/src/regexp/exec_test.go
index 70d069c..4872cb3 100644
--- a/src/regexp/exec_test.go
+++ b/src/regexp/exec_test.go
@@ -24,8 +24,8 @@ import (
 // complexity, over all possible strings over a given alphabet,
 // up to a given size.  Rather than try to link with RE2, we read a
 // log file containing the test cases and the expected matches.
-// The log file, re2.txt, is generated by running 'make exhaustive-log'
-// in the open source RE2 distribution.  http://code.google.com/p/re2/
+// The log file, re2-exhaustive.txt, is generated by running 'make log'
+// in the open source RE2 distribution https://github.com/google/re2/.
 //
 // The test file format is a sequence of stanzas like:
 //
@@ -59,8 +59,8 @@ import (
 // a capital letter are test names printed during RE2's test suite
 // and are echoed into t but otherwise ignored.
 //
-// At time of writing, re2.txt is 32 MB but compresses to 760 kB,
-// so we store re2.txt.gz in the repository and decompress it on the fly.
+// At time of writing, re2-exhaustive.txt is 59 MB but compresses to 385 kB,
+// so we store re2-exhaustive.txt.bz2 in the repository and decompress it on the fly.
 //
 func TestRE2Search(t *testing.T) {
 	testRE2(t, "testdata/re2-search.txt")
@@ -326,7 +326,7 @@ func same(x, y []int) bool {
 
 // TestFowler runs this package's regexp API against the
 // POSIX regular expression tests collected by Glenn Fowler
-// at http://www2.research.att.com/~gsf/testregex/.
+// at http://www2.research.att.com/~astopen/testregex/testregex.html.
 func TestFowler(t *testing.T) {
 	files, err := filepath.Glob("testdata/*.dat")
 	if err != nil {
@@ -361,7 +361,7 @@ Reading:
 			break Reading
 		}
 
-		// http://www2.research.att.com/~gsf/man/man1/testregex.html
+		// http://www2.research.att.com/~astopen/man/man1/testregex.html
 		//
 		// INPUT FORMAT
 		//   Input lines may be blank, a comment beginning with #, or a test
@@ -713,3 +713,15 @@ func TestLongest(t *testing.T) {
 		t.Errorf("longest match was %q, want %q", g, w)
 	}
 }
+
+// TestProgramTooLongForBacktrack tests that a regex which is too long
+// for the backtracker still executes properly.
+func TestProgramTooLongForBacktrack(t *testing.T) {
+	longRegex := MustCompile(`(one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve|thirteen|fourteen|fifteen|sixteen|seventeen|eighteen|nineteen|twenty|twentyone|twentytwo|twentythree|twentyfour|twentyfive|twentysix|twentyseven|twentyeight|twentynine|thirty|thirtyone|thirtytwo|thirtythree|thirtyfour|thirtyfive|thirtysix|thirtyseven|thirtyeight|thirtynine|forty|fortyone|fortytwo|fortythree|fortyfour|fortyfive|fortysix|fortyseven|fortyeight|fortynine|fifty|fiftyone|fiftytwo|fiftyth [...]
+	if !longRegex.MatchString("two") {
+		t.Errorf("longRegex.MatchString(\"two\") was false, want true")
+	}
+	if longRegex.MatchString("xxx") {
+		t.Errorf("longRegex.MatchString(\"xxx\") was true, want false")
+	}
+}
diff --git a/src/regexp/regexp.go b/src/regexp/regexp.go
index b615acd..4e4b412 100644
--- a/src/regexp/regexp.go
+++ b/src/regexp/regexp.go
@@ -7,9 +7,9 @@
 // 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
+//   go doc regexp/syntax
 //
 // The regexp implementation provided by this package is
 // guaranteed to run in time linear in the size of the input.
@@ -83,7 +83,7 @@ type Regexp struct {
 	// read-only after Compile
 	expr           string         // as passed to Compile
 	prog           *syntax.Prog   // compiled program
-	onepass        *onePassProg   // onpass program or nil
+	onepass        *onePassProg   // onepass program or nil
 	prefix         string         // required prefix in unanchored matches
 	prefixBytes    []byte         // prefix, as a []byte
 	prefixComplete bool           // prefix is the entire regexp
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 @@ Loop:
 
 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 @@ func wordRune(r rune) bool {
 		('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/regexp/testdata/README b/src/regexp/testdata/README
index b1b301b..58cec82 100644
--- a/src/regexp/testdata/README
+++ b/src/regexp/testdata/README
@@ -19,5 +19,6 @@ Such changes are marked with 'RE2/Go'.
 RE2 Test Files
 
 re2-exhaustive.txt.bz2 and re2-search.txt are built by running
-'make log' in the RE2 distribution.  http://code.google.com/p/re2/.
+'make log' in the RE2 distribution https://github.com/google/re2/
+
 The exhaustive file is compressed because it is huge.
diff --git a/src/run.bash b/src/run.bash
index 5f20451..f35ec78 100755
--- a/src/run.bash
+++ b/src/run.bash
@@ -12,6 +12,9 @@ unset CDPATH	# in case user has it set
 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,232 +35,4 @@ if ulimit -T &> /dev/null; then
 	[ "$(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
-	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
-
-# increase timeout for ARM up to 3 times the normal value
-timeout_scale=1
-[ "$GOARCH" == "arm" ] && timeout_scale=3
-
-echo '# Testing packages.'
-time go test std -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
-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
-
-# This tests cgo -cdefs. That mode is not supported,
-# so it's okay if it doesn't work on some systems.
-# In particular, it works badly with clang on OS X.
-# It doesn't work at all now that we disallow C code
-# outside runtime. Once runtime has no C code it won't
-# even be necessary.
-# [ "$CGO_ENABLED" != 1 ] || [ "$GOOS" == darwin ] ||
-# (xcd ../misc/cgo/testcdefs
-# ./test.bash || exit 1
-# ) || exit $?
-
-[ "$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
-echo '# Checking API compatibility.'
-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 14c1b45..4957111 100644
--- a/src/run.bat
+++ b/src/run.bat
@@ -19,8 +19,8 @@ set GOPATH=
 rem TODO avoid rebuild if possible
 
 if x%1==x--no-rebuild goto norebuild
-echo # Building packages and commands.
-go install -a -v std
+echo ##### Building packages and commands.
+go install -a -v std cmd
 if errorlevel 1 goto fail
 echo.
 :norebuild
@@ -37,109 +37,10 @@ call env.bat
 del env.bat
 echo.
 
-echo # Testing packages.
-go test std -short -timeout=120s
+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=300s -cpu=1,2,4
-if errorlevel 1 goto fail
-echo.
-
-set GOMAXPROCS=%OLDGOMAXPROCS%
-set OLDGOMAXPROCS=
-
-echo # sync -cpu=10
-go test sync -short -timeout=120s -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 b0995d8..d0ba866 100755
--- a/src/run.rc
+++ b/src/run.rc
@@ -10,52 +10,4 @@ eval `{go env}
 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
-	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 -short -timeout 120s
-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 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/alg.go b/src/runtime/alg.go
index e9ed595..c666836 100644
--- a/src/runtime/alg.go
+++ b/src/runtime/alg.go
@@ -38,23 +38,49 @@ const (
 	alg_max
 )
 
+// typeAlg is also copied/used in reflect/type.go.
+// keep them in sync.
 type typeAlg struct {
 	// function for hashing objects of this type
-	// (ptr to object, size, seed) -> hash
-	hash func(unsafe.Pointer, uintptr, uintptr) uintptr
+	// (ptr to object, seed) -> hash
+	hash func(unsafe.Pointer, uintptr) uintptr
 	// function for comparing objects of this type
-	// (ptr to object A, ptr to object B, size) -> ==?
-	equal func(unsafe.Pointer, unsafe.Pointer, uintptr) bool
+	// (ptr to object A, ptr to object B) -> ==?
+	equal func(unsafe.Pointer, unsafe.Pointer) bool
 }
 
+func memhash0(p unsafe.Pointer, h uintptr) uintptr {
+	return h
+}
+func memhash8(p unsafe.Pointer, h uintptr) uintptr {
+	return memhash(p, h, 1)
+}
+func memhash16(p unsafe.Pointer, h uintptr) uintptr {
+	return memhash(p, h, 2)
+}
+func memhash32(p unsafe.Pointer, h uintptr) uintptr {
+	return memhash(p, h, 4)
+}
+func memhash64(p unsafe.Pointer, h uintptr) uintptr {
+	return memhash(p, h, 8)
+}
+func memhash128(p unsafe.Pointer, h uintptr) uintptr {
+	return memhash(p, h, 16)
+}
+
+// memhash_varlen is defined in assembly because it needs access
+// to the closure.  It appears here to provide an argument
+// signature for the assembly routine.
+func memhash_varlen(p unsafe.Pointer, h uintptr) uintptr
+
 var algarray = [alg_max]typeAlg{
-	alg_MEM:      {memhash, memequal},
-	alg_MEM0:     {memhash, memequal0},
-	alg_MEM8:     {memhash, memequal8},
-	alg_MEM16:    {memhash, memequal16},
-	alg_MEM32:    {memhash, memequal32},
-	alg_MEM64:    {memhash, memequal64},
-	alg_MEM128:   {memhash, memequal128},
+	alg_MEM:      {nil, nil}, // not used
+	alg_MEM0:     {memhash0, memequal0},
+	alg_MEM8:     {memhash8, memequal8},
+	alg_MEM16:    {memhash16, memequal16},
+	alg_MEM32:    {memhash32, memequal32},
+	alg_MEM64:    {memhash64, memequal64},
+	alg_MEM128:   {memhash128, memequal128},
 	alg_NOEQ:     {nil, nil},
 	alg_NOEQ0:    {nil, nil},
 	alg_NOEQ8:    {nil, nil},
@@ -72,32 +98,17 @@ var algarray = [alg_max]typeAlg{
 	alg_CPLX128:  {c128hash, c128equal},
 }
 
-const nacl = GOOS == "nacl"
-
 var useAeshash bool
 
 // in asm_*.s
-func aeshash(p unsafe.Pointer, s, h uintptr) uintptr
-func aeshash32(p unsafe.Pointer, s, h uintptr) uintptr
-func aeshash64(p unsafe.Pointer, s, h uintptr) uintptr
-func aeshashstr(p unsafe.Pointer, s, h uintptr) uintptr
-
-func memhash(p unsafe.Pointer, s, h uintptr) uintptr {
-	if !nacl && useAeshash {
-		return aeshash(p, s, h)
-	}
+func aeshash(p unsafe.Pointer, h, s uintptr) uintptr
+func aeshash32(p unsafe.Pointer, h uintptr) uintptr
+func aeshash64(p unsafe.Pointer, h uintptr) uintptr
+func aeshashstr(p unsafe.Pointer, h uintptr) uintptr
 
-	h ^= c0
-	for s > 0 {
-		h = (h ^ uintptr(*(*byte)(p))) * c1
-		p = add(p, 1)
-		s--
-	}
-	return h
-}
-
-func strhash(a unsafe.Pointer, s, h uintptr) uintptr {
-	return memhash((*stringStruct)(a).str, uintptr(len(*(*string)(a))), h)
+func strhash(a unsafe.Pointer, h uintptr) uintptr {
+	x := (*stringStruct)(a)
+	return memhash(x.str, h, uintptr(x.len))
 }
 
 // NOTE: Because NaN != NaN, a map can contain any
@@ -105,7 +116,7 @@ func strhash(a unsafe.Pointer, s, h uintptr) uintptr {
 // To avoid long hash chains, we assign a random number
 // as the hash value for a NaN.
 
-func f32hash(p unsafe.Pointer, s, h uintptr) uintptr {
+func f32hash(p unsafe.Pointer, h uintptr) uintptr {
 	f := *(*float32)(p)
 	switch {
 	case f == 0:
@@ -113,11 +124,11 @@ func f32hash(p unsafe.Pointer, s, h uintptr) uintptr {
 	case f != f:
 		return c1 * (c0 ^ h ^ uintptr(fastrand1())) // any kind of NaN
 	default:
-		return memhash(p, 4, h)
+		return memhash(p, h, 4)
 	}
 }
 
-func f64hash(p unsafe.Pointer, s, h uintptr) uintptr {
+func f64hash(p unsafe.Pointer, h uintptr) uintptr {
 	f := *(*float64)(p)
 	switch {
 	case f == 0:
@@ -125,52 +136,52 @@ func f64hash(p unsafe.Pointer, s, h uintptr) uintptr {
 	case f != f:
 		return c1 * (c0 ^ h ^ uintptr(fastrand1())) // any kind of NaN
 	default:
-		return memhash(p, 8, h)
+		return memhash(p, h, 8)
 	}
 }
 
-func c64hash(p unsafe.Pointer, s, h uintptr) uintptr {
+func c64hash(p unsafe.Pointer, h uintptr) uintptr {
 	x := (*[2]float32)(p)
-	return f32hash(unsafe.Pointer(&x[1]), 4, f32hash(unsafe.Pointer(&x[0]), 4, h))
+	return f32hash(unsafe.Pointer(&x[1]), f32hash(unsafe.Pointer(&x[0]), h))
 }
 
-func c128hash(p unsafe.Pointer, s, h uintptr) uintptr {
+func c128hash(p unsafe.Pointer, h uintptr) uintptr {
 	x := (*[2]float64)(p)
-	return f64hash(unsafe.Pointer(&x[1]), 8, f64hash(unsafe.Pointer(&x[0]), 8, h))
+	return f64hash(unsafe.Pointer(&x[1]), f64hash(unsafe.Pointer(&x[0]), h))
 }
 
-func interhash(p unsafe.Pointer, s, h uintptr) uintptr {
+func interhash(p unsafe.Pointer, h uintptr) uintptr {
 	a := (*iface)(p)
 	tab := a.tab
 	if tab == nil {
 		return h
 	}
 	t := tab._type
-	fn := goalg(t.alg).hash
+	fn := t.alg.hash
 	if fn == nil {
 		panic(errorString("hash of unhashable type " + *t._string))
 	}
 	if isDirectIface(t) {
-		return c1 * fn(unsafe.Pointer(&a.data), uintptr(t.size), h^c0)
+		return c1 * fn(unsafe.Pointer(&a.data), h^c0)
 	} else {
-		return c1 * fn(a.data, uintptr(t.size), h^c0)
+		return c1 * fn(a.data, h^c0)
 	}
 }
 
-func nilinterhash(p unsafe.Pointer, s, h uintptr) uintptr {
+func nilinterhash(p unsafe.Pointer, h uintptr) uintptr {
 	a := (*eface)(p)
 	t := a._type
 	if t == nil {
 		return h
 	}
-	fn := goalg(t.alg).hash
+	fn := t.alg.hash
 	if fn == nil {
 		panic(errorString("hash of unhashable type " + *t._string))
 	}
 	if isDirectIface(t) {
-		return c1 * fn(unsafe.Pointer(&a.data), uintptr(t.size), h^c0)
+		return c1 * fn(unsafe.Pointer(&a.data), h^c0)
 	} else {
-		return c1 * fn(a.data, uintptr(t.size), h^c0)
+		return c1 * fn(a.data, h^c0)
 	}
 }
 
@@ -181,47 +192,47 @@ func memequal(p, q unsafe.Pointer, size uintptr) bool {
 	return memeq(p, q, size)
 }
 
-func memequal0(p, q unsafe.Pointer, size uintptr) bool {
+func memequal0(p, q unsafe.Pointer) bool {
 	return true
 }
-func memequal8(p, q unsafe.Pointer, size uintptr) bool {
+func memequal8(p, q unsafe.Pointer) bool {
 	return *(*int8)(p) == *(*int8)(q)
 }
-func memequal16(p, q unsafe.Pointer, size uintptr) bool {
+func memequal16(p, q unsafe.Pointer) bool {
 	return *(*int16)(p) == *(*int16)(q)
 }
-func memequal32(p, q unsafe.Pointer, size uintptr) bool {
+func memequal32(p, q unsafe.Pointer) bool {
 	return *(*int32)(p) == *(*int32)(q)
 }
-func memequal64(p, q unsafe.Pointer, size uintptr) bool {
+func memequal64(p, q unsafe.Pointer) bool {
 	return *(*int64)(p) == *(*int64)(q)
 }
-func memequal128(p, q unsafe.Pointer, size uintptr) bool {
+func memequal128(p, q unsafe.Pointer) bool {
 	return *(*[2]int64)(p) == *(*[2]int64)(q)
 }
-func f32equal(p, q unsafe.Pointer, size uintptr) bool {
+func f32equal(p, q unsafe.Pointer) bool {
 	return *(*float32)(p) == *(*float32)(q)
 }
-func f64equal(p, q unsafe.Pointer, size uintptr) bool {
+func f64equal(p, q unsafe.Pointer) bool {
 	return *(*float64)(p) == *(*float64)(q)
 }
-func c64equal(p, q unsafe.Pointer, size uintptr) bool {
+func c64equal(p, q unsafe.Pointer) bool {
 	return *(*complex64)(p) == *(*complex64)(q)
 }
-func c128equal(p, q unsafe.Pointer, size uintptr) bool {
+func c128equal(p, q unsafe.Pointer) bool {
 	return *(*complex128)(p) == *(*complex128)(q)
 }
-func strequal(p, q unsafe.Pointer, size uintptr) bool {
+func strequal(p, q unsafe.Pointer) bool {
 	return *(*string)(p) == *(*string)(q)
 }
-func interequal(p, q unsafe.Pointer, size uintptr) bool {
+func interequal(p, q unsafe.Pointer) bool {
 	return ifaceeq(*(*interface {
 		f()
 	})(p), *(*interface {
 		f()
 	})(q))
 }
-func nilinterequal(p, q unsafe.Pointer, size uintptr) bool {
+func nilinterequal(p, q unsafe.Pointer) bool {
 	return efaceeq(*(*interface{})(p), *(*interface{})(q))
 }
 func efaceeq(p, q interface{}) bool {
@@ -234,14 +245,14 @@ func efaceeq(p, q interface{}) bool {
 	if t == nil {
 		return true
 	}
-	eq := goalg(t.alg).equal
+	eq := t.alg.equal
 	if eq == nil {
 		panic(errorString("comparing uncomparable type " + *t._string))
 	}
 	if isDirectIface(t) {
-		return eq(noescape(unsafe.Pointer(&x.data)), noescape(unsafe.Pointer(&y.data)), uintptr(t.size))
+		return eq(noescape(unsafe.Pointer(&x.data)), noescape(unsafe.Pointer(&y.data)))
 	}
-	return eq(x.data, y.data, uintptr(t.size))
+	return eq(x.data, y.data)
 }
 func ifaceeq(p, q interface {
 	f()
@@ -256,97 +267,73 @@ func ifaceeq(p, q interface {
 		return true
 	}
 	t := xtab._type
-	eq := goalg(t.alg).equal
+	eq := t.alg.equal
 	if eq == nil {
 		panic(errorString("comparing uncomparable type " + *t._string))
 	}
 	if isDirectIface(t) {
-		return eq(noescape(unsafe.Pointer(&x.data)), noescape(unsafe.Pointer(&y.data)), uintptr(t.size))
+		return eq(noescape(unsafe.Pointer(&x.data)), noescape(unsafe.Pointer(&y.data)))
 	}
-	return eq(x.data, y.data, uintptr(t.size))
+	return eq(x.data, y.data)
 }
 
 // Testing adapters for hash quality tests (see hash_test.go)
-func haveGoodHash() bool {
-	return useAeshash
-}
-
 func stringHash(s string, seed uintptr) uintptr {
-	return algarray[alg_STRING].hash(noescape(unsafe.Pointer(&s)), unsafe.Sizeof(s), seed)
+	return algarray[alg_STRING].hash(noescape(unsafe.Pointer(&s)), seed)
 }
 
 func bytesHash(b []byte, seed uintptr) uintptr {
-	s := (*sliceStruct)(unsafe.Pointer(&b))
-	return algarray[alg_MEM].hash(s.array, uintptr(s.len), seed)
+	s := (*slice)(unsafe.Pointer(&b))
+	return memhash(s.array, seed, uintptr(s.len))
 }
 
 func int32Hash(i uint32, seed uintptr) uintptr {
-	return algarray[alg_MEM32].hash(noescape(unsafe.Pointer(&i)), 4, seed)
+	return algarray[alg_MEM32].hash(noescape(unsafe.Pointer(&i)), seed)
 }
 
 func int64Hash(i uint64, seed uintptr) uintptr {
-	return algarray[alg_MEM64].hash(noescape(unsafe.Pointer(&i)), 8, seed)
+	return algarray[alg_MEM64].hash(noescape(unsafe.Pointer(&i)), seed)
 }
 
 func efaceHash(i interface{}, seed uintptr) uintptr {
-	return algarray[alg_NILINTER].hash(noescape(unsafe.Pointer(&i)), unsafe.Sizeof(i), seed)
+	return algarray[alg_NILINTER].hash(noescape(unsafe.Pointer(&i)), seed)
 }
 
 func ifaceHash(i interface {
 	F()
 }, seed uintptr) uintptr {
-	return algarray[alg_INTER].hash(noescape(unsafe.Pointer(&i)), unsafe.Sizeof(i), seed)
+	return algarray[alg_INTER].hash(noescape(unsafe.Pointer(&i)), seed)
 }
 
 // Testing adapter for memclr
 func memclrBytes(b []byte) {
-	s := (*sliceStruct)(unsafe.Pointer(&b))
+	s := (*slice)(unsafe.Pointer(&b))
 	memclr(s.array, uintptr(s.len))
 }
 
-// TODO(dvyukov): remove when Type is converted to Go and contains *typeAlg.
-func goalg(a unsafe.Pointer) *typeAlg {
-	return (*typeAlg)(a)
-}
-
-// used in asm_{386,amd64}.s
-const hashRandomBytes = 32
+const hashRandomBytes = ptrSize / 4 * 64
 
+// used in asm_{386,amd64}.s to seed the hash function
 var aeskeysched [hashRandomBytes]byte
 
-//go:noescape
-func get_random_data(rnd *unsafe.Pointer, n *int32)
+// used in hash{32,64}.go to seed the hash function
+var hashkey [4]uintptr
 
 func init() {
-	if theGoos == "nacl" {
-		return
-	}
-
 	// Install aes hash algorithm if we have the instructions we need
-	if (cpuid_ecx&(1<<25)) != 0 && // aes (aesenc)
-		(cpuid_ecx&(1<<9)) != 0 && // sse3 (pshufb)
-		(cpuid_ecx&(1<<19)) != 0 { // sse4.1 (pinsr{d,q})
+	if (GOARCH == "386" || GOARCH == "amd64") &&
+		GOOS != "nacl" &&
+		cpuid_ecx&(1<<25) != 0 && // aes (aesenc)
+		cpuid_ecx&(1<<9) != 0 && // sse3 (pshufb)
+		cpuid_ecx&(1<<19) != 0 { // sse4.1 (pinsr{d,q})
 		useAeshash = true
-		algarray[alg_MEM].hash = aeshash
-		algarray[alg_MEM8].hash = aeshash
-		algarray[alg_MEM16].hash = aeshash
 		algarray[alg_MEM32].hash = aeshash32
 		algarray[alg_MEM64].hash = aeshash64
-		algarray[alg_MEM128].hash = aeshash
 		algarray[alg_STRING].hash = aeshashstr
 		// Initialize with random data so hash collisions will be hard to engineer.
-		var rnd unsafe.Pointer
-		var n int32
-		get_random_data(&rnd, &n)
-		if n > hashRandomBytes {
-			n = hashRandomBytes
-		}
-		memmove(unsafe.Pointer(&aeskeysched[0]), rnd, uintptr(n))
-		if n < hashRandomBytes {
-			// Not very random, but better than nothing.
-			for t := nanotime(); n < hashRandomBytes; n++ {
-				aeskeysched[n] = byte(t >> uint(8*(n%8)))
-			}
-		}
+		getRandomData(aeskeysched[:])
+		return
 	}
+	getRandomData((*[len(hashkey) * ptrSize]byte)(unsafe.Pointer(&hashkey))[:])
+	hashkey[0] |= 1 // make sure this number is odd
 }
diff --git a/src/runtime/arch1_386.go b/src/runtime/arch1_386.go
new file mode 100644
index 0000000..d41696a
--- /dev/null
+++ b/src/runtime/arch1_386.go
@@ -0,0 +1,15 @@
+// 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        = '8'
+	_BigEndian     = 0
+	_CacheLineSize = 64
+	_PhysPageSize  = goos_nacl*65536 + (1-goos_nacl)*4096 // 4k normally; 64k on NaCl
+	_PCQuantum     = 1
+	_Int64Align    = 4
+	hugePageSize   = 1 << 21
+)
diff --git a/src/runtime/arch1_amd64.go b/src/runtime/arch1_amd64.go
new file mode 100644
index 0000000..15f4cc6
--- /dev/null
+++ b/src/runtime/arch1_amd64.go
@@ -0,0 +1,15 @@
+// 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        = '6'
+	_BigEndian     = 0
+	_CacheLineSize = 64
+	_PhysPageSize  = 4096
+	_PCQuantum     = 1
+	_Int64Align    = 8
+	hugePageSize   = 1 << 21
+)
diff --git a/src/runtime/arch1_amd64p32.go b/src/runtime/arch1_amd64p32.go
new file mode 100644
index 0000000..3c5456f
--- /dev/null
+++ b/src/runtime/arch1_amd64p32.go
@@ -0,0 +1,15 @@
+// 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        = '6'
+	_BigEndian     = 0
+	_CacheLineSize = 64
+	_PhysPageSize  = 65536*goos_nacl + 4096*(1-goos_nacl)
+	_PCQuantum     = 1
+	_Int64Align    = 8
+	hugePageSize   = 1 << 21
+)
diff --git a/src/runtime/arch1_arm.go b/src/runtime/arch1_arm.go
new file mode 100644
index 0000000..0ec2093
--- /dev/null
+++ b/src/runtime/arch1_arm.go
@@ -0,0 +1,15 @@
+// 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        = '5'
+	_BigEndian     = 0
+	_CacheLineSize = 32
+	_PhysPageSize  = 65536*goos_nacl + 4096*(1-goos_nacl)
+	_PCQuantum     = 4
+	_Int64Align    = 4
+	hugePageSize   = 0
+)
diff --git a/src/runtime/arch1_arm64.go b/src/runtime/arch1_arm64.go
new file mode 100644
index 0000000..29a87db
--- /dev/null
+++ b/src/runtime/arch1_arm64.go
@@ -0,0 +1,15 @@
+// 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
+	_PhysPageSize  = 65536
+	_PCQuantum     = 4
+	_Int64Align    = 8
+	hugePageSize   = 0
+)
diff --git a/src/runtime/arch1_ppc64.go b/src/runtime/arch1_ppc64.go
new file mode 100644
index 0000000..de6dd91
--- /dev/null
+++ b/src/runtime/arch1_ppc64.go
@@ -0,0 +1,15 @@
+// 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
+
+const (
+	thechar        = '9'
+	_BigEndian     = 1
+	_CacheLineSize = 64
+	_PhysPageSize  = 65536
+	_PCQuantum     = 4
+	_Int64Align    = 8
+	hugePageSize   = 0
+)
diff --git a/src/runtime/arch1_ppc64le.go b/src/runtime/arch1_ppc64le.go
new file mode 100644
index 0000000..9a55c71
--- /dev/null
+++ b/src/runtime/arch1_ppc64le.go
@@ -0,0 +1,15 @@
+// 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
+
+const (
+	thechar        = '9'
+	_BigEndian     = 0
+	_CacheLineSize = 64
+	_PhysPageSize  = 65536
+	_PCQuantum     = 4
+	_Int64Align    = 8
+	hugePageSize   = 0
+)
diff --git a/src/runtime/arch_386.h b/src/runtime/arch_386.h
deleted file mode 100644
index 75a5ba7..0000000
--- a/src/runtime/arch_386.h
+++ /dev/null
@@ -1,17 +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.
-
-enum {
-	thechar = '8',
-	BigEndian = 0,
-	CacheLineSize = 64,
-	RuntimeGogoBytes = 64,
-#ifdef GOOS_nacl
-	PhysPageSize = 65536,
-#else
-	PhysPageSize = 4096,
-#endif
-	PCQuantum = 1,
-	Int64Align = 4
-};
diff --git a/src/runtime/arch_amd64.h b/src/runtime/arch_amd64.h
deleted file mode 100644
index d7b81ee..0000000
--- a/src/runtime/arch_amd64.h
+++ /dev/null
@@ -1,25 +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.
-
-enum {
-	thechar = '6',
-	BigEndian = 0,
-	CacheLineSize = 64,
-#ifdef GOOS_solaris
-	RuntimeGogoBytes = 80,
-#else
-#ifdef GOOS_windows
-	RuntimeGogoBytes = 80,
-#else
-#ifdef GOOS_plan9
-	RuntimeGogoBytes = 80,
-#else
-	RuntimeGogoBytes = 64,
-#endif	// Plan 9
-#endif	// Windows
-#endif	// Solaris
-	PhysPageSize = 4096,
-	PCQuantum = 1,
-	Int64Align = 8
-};
diff --git a/src/runtime/arch_amd64p32.h b/src/runtime/arch_amd64p32.h
deleted file mode 100644
index d3e8649..0000000
--- a/src/runtime/arch_amd64p32.h
+++ /dev/null
@@ -1,17 +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.
-
-enum {
-	thechar = '6',
-	BigEndian = 0,
-	CacheLineSize = 64,
-	RuntimeGogoBytes = 64,
-#ifdef GOOS_nacl
-	PhysPageSize = 65536,
-#else
-	PhysPageSize = 4096,
-#endif
-	PCQuantum = 1,
-	Int64Align = 8
-};
diff --git a/src/runtime/arch_arm.h b/src/runtime/arch_arm.h
deleted file mode 100644
index 637a334..0000000
--- a/src/runtime/arch_arm.h
+++ /dev/null
@@ -1,17 +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.
-
-enum {
-	thechar = '5',
-	BigEndian = 0,
-	CacheLineSize = 32,
-	RuntimeGogoBytes = 60,
-#ifdef GOOS_nacl
-	PhysPageSize = 65536,
-#else
-	PhysPageSize = 4096,
-#endif
-	PCQuantum = 4,
-	Int64Align = 4
-};
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/arch_ppc64.go b/src/runtime/arch_ppc64.go
new file mode 100644
index 0000000..270cd7b
--- /dev/null
+++ b/src/runtime/arch_ppc64.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/arch_ppc64le.go b/src/runtime/arch_ppc64le.go
new file mode 100644
index 0000000..270cd7b
--- /dev/null
+++ b/src/runtime/arch_ppc64le.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.s b/src/runtime/asm.s
index e6d782f..f1c812b 100644
--- a/src/runtime/asm.s
+++ b/src/runtime/asm.s
@@ -12,3 +12,8 @@ DATA runtime·no_pointers_stackmap+0x00(SB)/4, $2
 DATA runtime·no_pointers_stackmap+0x04(SB)/4, $0
 GLOBL runtime·no_pointers_stackmap(SB),RODATA, $8
 
+TEXT runtime·nop(SB),NOSPLIT,$0-0
+	RET
+
+GLOBL runtime·mheap_(SB), NOPTR, $0
+GLOBL runtime·memstats(SB), NOPTR, $0
diff --git a/src/runtime/asm_386.s b/src/runtime/asm_386.s
index b4b81d7..eb9ca63 100644
--- a/src/runtime/asm_386.s
+++ b/src/runtime/asm_386.s
@@ -2,7 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
 #include "funcdata.h"
 #include "textflag.h"
 
@@ -29,6 +30,19 @@ TEXT runtime·rt0_go(SB),NOSPLIT,$0
 	CPUID
 	CMPL	AX, $0
 	JE	nocpuinfo
+
+	// Figure out how to serialize RDTSC.
+	// On Intel processors LFENCE is enough. AMD requires MFENCE.
+	// Don't know about the rest, so let's do MFENCE.
+	CMPL	BX, $0x756E6547  // "Genu"
+	JNE	notintel
+	CMPL	DX, $0x49656E69  // "ineI"
+	JNE	notintel
+	CMPL	CX, $0x6C65746E  // "ntel"
+	JNE	notintel
+	MOVB	$1, runtime·lfenceBeforeRdtsc(SB)
+notintel:
+
 	MOVL	$1, AX
 	CPUID
 	MOVL	CX, runtime·cpuid_ecx(SB)
@@ -49,7 +63,7 @@ nocpuinfo:
 	// update stackguard after _cgo_init
 	MOVL	$runtime·g0(SB), CX
 	MOVL	(g_stack+stack_lo)(CX), AX
-	ADDL	$const_StackGuard, AX
+	ADDL	$const__StackGuard, AX
 	MOVL	AX, g_stackguard0(CX)
 	MOVL	AX, g_stackguard1(CX)
 
@@ -100,7 +114,7 @@ ok:
 	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
@@ -112,8 +126,8 @@ ok:
 	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
@@ -199,62 +213,49 @@ TEXT runtime·mcall(SB), NOSPLIT, $0-4
 	JMP	AX
 	RET
 
-// switchtoM is a dummy routine that onM leaves at the bottom
+// 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 M stack because the one at the top of
-// the M stack terminates the stack walk (see topofstack()).
-TEXT runtime·switchtoM(SB), NOSPLIT, $0-0
+// 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
 	RET
 
-// func onM_signalok(fn func())
-TEXT runtime·onM_signalok(SB), NOSPLIT, $0-4
+// func systemstack(fn func())
+TEXT runtime·systemstack(SB), NOSPLIT, $0-4
+	MOVL	fn+0(FP), DI	// DI = fn
 	get_tls(CX)
 	MOVL	g(CX), AX	// AX = g
 	MOVL	g_m(AX), BX	// BX = m
+
 	MOVL	m_gsignal(BX), DX	// DX = gsignal
 	CMPL	AX, DX
-	JEQ	ongsignal
-	JMP	runtime·onM(SB)
-
-ongsignal:
-	MOVL	fn+0(FP), DI	// DI = fn
-	MOVL	DI, DX
-	MOVL	0(DI), DI
-	CALL	DI
-	RET
-
-// func onM(fn func())
-TEXT runtime·onM(SB), NOSPLIT, $0-4
-	MOVL	fn+0(FP), DI	// DI = fn
-	get_tls(CX)
-	MOVL	g(CX), AX	// AX = g
-	MOVL	g_m(AX), BX	// BX = m
+	JEQ	noswitch
 
 	MOVL	m_g0(BX), DX	// DX = g0
 	CMPL	AX, DX
-	JEQ	onm
+	JEQ	noswitch
 
 	MOVL	m_curg(BX), BP
 	CMPL	AX, BP
-	JEQ	oncurg
+	JEQ	switch
 	
-	// Not g0, not curg. Must be gsignal, but that's not allowed.
+	// Bad: g is not gsignal, not g0, not curg. What is it?
 	// Hide call from linker nosplit analysis.
-	MOVL	$runtime·badonm(SB), AX
+	MOVL	$runtime·badsystemstack(SB), AX
 	CALL	AX
 
-oncurg:
+switch:
 	// save our state in g->sched.  Pretend to
-	// be switchtoM if the G stack is scanned.
-	MOVL	$runtime·switchtoM(SB), (g_sched+gobuf_pc)(AX)
+	// be systemstack_switch if the G stack is scanned.
+	MOVL	$runtime·systemstack_switch(SB), (g_sched+gobuf_pc)(AX)
 	MOVL	SP, (g_sched+gobuf_sp)(AX)
 	MOVL	AX, (g_sched+gobuf_g)(AX)
 
 	// switch to g0
 	MOVL	DX, g(CX)
 	MOVL	(g_sched+gobuf_sp)(DX), BX
-	// make it look like mstart called onM on g0, to stop traceback
+	// make it look like mstart called systemstack on g0, to stop traceback
 	SUBL	$4, BX
 	MOVL	$runtime·mstart(SB), DX
 	MOVL	DX, 0(BX)
@@ -275,8 +276,8 @@ oncurg:
 	MOVL	$0, (g_sched+gobuf_sp)(AX)
 	RET
 
-onm:
-	// already on m stack, just call directly
+noswitch:
+	// already on system stack, just call directly
 	MOVL	DI, DX
 	MOVL	0(DI), DI
 	CALL	DI
@@ -340,8 +341,24 @@ TEXT runtime·morestack_noctxt(SB),NOSPLIT,$0-0
 	MOVL	$0, DX
 	JMP runtime·morestack(SB)
 
+TEXT runtime·stackBarrier(SB),NOSPLIT,$0
+	// We came here via a RET to an overwritten return PC.
+	// AX may be live. Other registers are available.
+
+	// Get the original return PC, g.stkbar[g.stkbarPos].savedLRVal.
+	get_tls(CX)
+	MOVL	g(CX), CX
+	MOVL	(g_stkbar+slice_array)(CX), DX
+	MOVL	g_stkbarPos(CX), BX
+	IMULL	$stkbar__size, BX	// Too big for SIB.
+	MOVL	stkbar_savedLRVal(DX)(BX*1), BX
+	// Record that this stack barrier was hit.
+	ADDL	$1, g_stkbarPos(CX)
+	// Jump to the original return PC.
+	JMP	BX
+
 // reflectcall: call a function with the given argument list
-// func call(f *FuncVal, arg *byte, argsize, retoffset uint32).
+// 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!
@@ -353,8 +370,11 @@ TEXT runtime·morestack_noctxt(SB),NOSPLIT,$0-0
 	JMP	AX
 // Note: can't just "JMP NAME(SB)" - bad inlining results.
 
-TEXT ·reflectcall(SB), NOSPLIT, $0-16
-	MOVL	argsize+8(FP), CX
+TEXT reflect·call(SB), NOSPLIT, $0-0
+	JMP	·reflectcall(SB)
+
+TEXT ·reflectcall(SB), NOSPLIT, $0-20
+	MOVL	argsize+12(FP), CX
 	DISPATCH(runtime·call16, 16)
 	DISPATCH(runtime·call32, 32)
 	DISPATCH(runtime·call64, 64)
@@ -386,27 +406,37 @@ TEXT ·reflectcall(SB), NOSPLIT, $0-16
 	JMP	AX
 
 #define CALLFN(NAME,MAXSIZE)			\
-TEXT NAME(SB), WRAPPER, $MAXSIZE-16;		\
+TEXT NAME(SB), WRAPPER, $MAXSIZE-20;		\
 	NO_LOCAL_POINTERS;			\
 	/* copy arguments to stack */		\
-	MOVL	argptr+4(FP), SI;		\
-	MOVL	argsize+8(FP), CX;		\
+	MOVL	argptr+8(FP), SI;		\
+	MOVL	argsize+12(FP), CX;		\
 	MOVL	SP, DI;				\
 	REP;MOVSB;				\
 	/* call function */			\
-	MOVL	f+0(FP), DX;			\
+	MOVL	f+4(FP), DX;			\
 	MOVL	(DX), AX; 			\
 	PCDATA  $PCDATA_StackMapIndex, $0;	\
 	CALL	AX;				\
 	/* copy return values back */		\
-	MOVL	argptr+4(FP), DI;		\
-	MOVL	argsize+8(FP), CX;		\
-	MOVL	retoffset+12(FP), BX;		\
+	MOVL	argptr+8(FP), DI;		\
+	MOVL	argsize+12(FP), CX;		\
+	MOVL	retoffset+16(FP), BX;		\
 	MOVL	SP, SI;				\
 	ADDL	BX, DI;				\
 	ADDL	BX, SI;				\
 	SUBL	BX, CX;				\
 	REP;MOVSB;				\
+	/* execute write barrier updates */	\
+	MOVL	argtype+0(FP), DX;		\
+	MOVL	argptr+8(FP), DI;		\
+	MOVL	argsize+12(FP), CX;		\
+	MOVL	retoffset+16(FP), BX;		\
+	MOVL	DX, 0(SP);			\
+	MOVL	DI, 4(SP);			\
+	MOVL	CX, 8(SP);			\
+	MOVL	BX, 12(SP);			\
+	CALL	runtime·callwritebarrier(SB);	\
 	RET
 
 CALLFN(·call16, 16)
@@ -450,12 +480,7 @@ TEXT runtime·cas(SB), NOSPLIT, $0-13
 	MOVL	new+8(FP), CX
 	LOCK
 	CMPXCHGL	CX, 0(BX)
-	JZ 4(PC)
-	MOVL	$0, AX
-	MOVB	AX, ret+12(FP)
-	RET
-	MOVL	$1, AX
-	MOVB	AX, ret+12(FP)
+	SETEQ	ret+12(FP)
 	RET
 
 TEXT runtime·casuintptr(SB), NOSPLIT, $0-13
@@ -486,13 +511,7 @@ TEXT runtime·cas64(SB), NOSPLIT, $0-21
 	MOVL	new_hi+16(FP), CX
 	LOCK
 	CMPXCHG8B	0(BP)
-	JNZ	cas64_fail
-	MOVL	$1, AX
-	MOVB	AX, ret+20(FP)
-	RET
-cas64_fail:
-	MOVL	$0, AX
-	MOVB	AX, ret+20(FP)
+	SETEQ	ret+20(FP)
 	RET
 
 // bool casp(void **p, void *old, void *new)
@@ -502,18 +521,13 @@ cas64_fail:
 //		return 1;
 //	}else
 //		return 0;
-TEXT runtime·casp(SB), NOSPLIT, $0-13
+TEXT runtime·casp1(SB), NOSPLIT, $0-13
 	MOVL	ptr+0(FP), BX
 	MOVL	old+4(FP), AX
 	MOVL	new+8(FP), CX
 	LOCK
 	CMPXCHGL	CX, 0(BX)
-	JZ 4(PC)
-	MOVL	$0, AX
-	MOVB	AX, ret+12(FP)
-	RET
-	MOVL	$1, AX
-	MOVB	AX, ret+12(FP)
+	SETEQ	ret+12(FP)
 	RET
 
 // uint32 xadd(uint32 volatile *val, int32 delta)
@@ -537,7 +551,7 @@ TEXT runtime·xchg(SB), NOSPLIT, $0-12
 	MOVL	AX, ret+8(FP)
 	RET
 
-TEXT runtime·xchgp(SB), NOSPLIT, $0-12
+TEXT runtime·xchgp1(SB), NOSPLIT, $0-12
 	MOVL	ptr+0(FP), BX
 	MOVL	new+4(FP), AX
 	XCHGL	AX, 0(BX)
@@ -555,7 +569,7 @@ again:
 	JNZ	again
 	RET
 
-TEXT runtime·atomicstorep(SB), NOSPLIT, $0-8
+TEXT runtime·atomicstorep1(SB), NOSPLIT, $0-8
 	MOVL	ptr+0(FP), BX
 	MOVL	val+4(FP), AX
 	XCHGL	AX, 0(BX)
@@ -570,6 +584,9 @@ TEXT runtime·atomicstore(SB), NOSPLIT, $0-8
 // uint64 atomicload64(uint64 volatile* addr);
 TEXT runtime·atomicload64(SB), NOSPLIT, $0-12
 	MOVL	ptr+0(FP), AX
+	TESTL	$7, AX
+	JZ	2(PC)
+	MOVL	0, AX // crash with nil ptr deref
 	LEAL	ret_lo+4(FP), BX
 	// MOVQ (%EAX), %MM0
 	BYTE $0x0f; BYTE $0x6f; BYTE $0x00
@@ -582,6 +599,9 @@ TEXT runtime·atomicload64(SB), NOSPLIT, $0-12
 // void runtime·atomicstore64(uint64 volatile* addr, uint64 v);
 TEXT runtime·atomicstore64(SB), NOSPLIT, $0-12
 	MOVL	ptr+0(FP), AX
+	TESTL	$7, AX
+	JZ	2(PC)
+	MOVL	0, AX // crash with nil ptr deref
 	// MOVQ and EMMS were introduced on the Pentium MMX.
 	// MOVQ 0x8(%ESP), %MM0
 	BYTE $0x0f; BYTE $0x6f; BYTE $0x44; BYTE $0x24; BYTE $0x08
@@ -604,6 +624,19 @@ TEXT runtime·atomicor8(SB), NOSPLIT, $0-5
 	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
+
+TEXT ·publicationBarrier(SB),NOSPLIT,$0-0
+	// Stores are already ordered on x86, so this is just a
+	// compile barrier.
+	RET
+
 // void jmpdefer(fn, sp);
 // called from deferreturn.
 // 1. pop the caller
@@ -633,25 +666,14 @@ TEXT gosave<>(SB),NOSPLIT,$0
 	POPL	AX
 	RET
 
-// asmcgocall(void(*fn)(void*), void *arg)
+// func asmcgocall(fn, arg unsafe.Pointer) int32
 // Call fn(arg) on the scheduler stack,
 // aligned appropriately for the gcc ABI.
-// See cgocall.c for more details.
-TEXT ·asmcgocall(SB),NOSPLIT,$0-8
+// See cgocall.go for more details.
+TEXT ·asmcgocall(SB),NOSPLIT,$0-12
 	MOVL	fn+0(FP), AX
 	MOVL	arg+4(FP), BX
-	CALL	asmcgocall<>(SB)
-	RET
 
-TEXT ·asmcgocall_errno(SB),NOSPLIT,$0-12
-	MOVL	fn+0(FP), AX
-	MOVL	arg+4(FP), BX
-	CALL	asmcgocall<>(SB)
-	MOVL	AX, ret+8(FP)
-	RET
-
-TEXT asmcgocall<>(SB),NOSPLIT,$0-0
-	// fn in AX, arg in BX
 	MOVL	SP, DX
 
 	// Figure out if we need to switch to m->g0 stack.
@@ -685,6 +707,8 @@ TEXT asmcgocall<>(SB),NOSPLIT,$0-0
 	SUBL	4(SP), SI
 	MOVL	DI, g(CX)
 	MOVL	SI, SP
+
+	MOVL	AX, ret+8(FP)
 	RET
 
 // cgocallback(void (*fn)(void*), void *frame, uintptr framesize)
@@ -702,7 +726,7 @@ TEXT runtime·cgocallback(SB),NOSPLIT,$12-12
 	RET
 
 // cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize)
-// See cgocall.c for more details.
+// See cgocall.go for more details.
 TEXT ·cgocallback_gofunc(SB),NOSPLIT,$12-12
 	NO_LOCAL_POINTERS
 
@@ -740,7 +764,7 @@ needm:
 	// 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 onM will try to use it. If we don't set it here,
+	// 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.
 	MOVL	m_g0(BP), SI
@@ -848,38 +872,48 @@ TEXT runtime·stackcheck(SB), NOSPLIT, $0-0
 	INT	$3
 	RET
 
-TEXT runtime·getcallerpc(SB),NOSPLIT,$0-8
+TEXT runtime·getcallerpc(SB),NOSPLIT,$4-8
 	MOVL	argp+0(FP),AX		// addr of first arg
 	MOVL	-4(AX),AX		// get calling pc
+	CMPL	AX, runtime·stackBarrierPC(SB)
+	JNE	nobar
+	// Get original return PC.
+	CALL	runtime·nextBarrierPC(SB)
+	MOVL	0(SP), AX
+nobar:
 	MOVL	AX, ret+4(FP)
 	RET
 
-TEXT runtime·gogetcallerpc(SB),NOSPLIT,$0-8
-	MOVL	p+0(FP),AX		// addr of first arg
-	MOVL	-4(AX),AX		// get calling pc
-	MOVL	AX, ret+4(FP)
-	RET
-
-TEXT runtime·setcallerpc(SB),NOSPLIT,$0-8
+TEXT runtime·setcallerpc(SB),NOSPLIT,$4-8
 	MOVL	argp+0(FP),AX		// addr of first arg
 	MOVL	pc+4(FP), BX
+	MOVL	-4(AX), CX
+	CMPL	CX, runtime·stackBarrierPC(SB)
+	JEQ	setbar
 	MOVL	BX, -4(AX)		// set calling pc
 	RET
+setbar:
+	// Set the stack barrier return PC.
+	MOVL	BX, 0(SP)
+	CALL	runtime·setNextBarrierPC(SB)
+	RET
 
 TEXT runtime·getcallersp(SB), NOSPLIT, $0-8
 	MOVL	argp+0(FP), AX
 	MOVL	AX, ret+4(FP)
 	RET
 
-// func gogetcallersp(p unsafe.Pointer) uintptr
-TEXT runtime·gogetcallersp(SB),NOSPLIT,$0-8
-	MOVL	p+0(FP),AX		// addr of first arg
-	MOVL	AX, ret+4(FP)
-	RET
-
-// int64 runtime·cputicks(void), so really
-// void runtime·cputicks(int64 *ticks)
+// func cputicks() int64
 TEXT runtime·cputicks(SB),NOSPLIT,$0-8
+	TESTL	$0x4000000, runtime·cpuid_edx(SB) // no sse2, no mfence
+	JEQ	done
+	CMPB	runtime·lfenceBeforeRdtsc(SB), $1
+	JNE	mfence
+	BYTE	$0x0f; BYTE $0xae; BYTE $0xe8 // LFENCE
+	JMP	done
+mfence:
+	BYTE	$0x0f; BYTE $0xae; BYTE $0xf0 // MFENCE
+done:
 	RDTSC
 	MOVL	AX, ret_lo+0(FP)
 	MOVL	DX, ret_hi+4(FP)
@@ -902,96 +936,218 @@ TEXT runtime·emptyfunc(SB),0,$0-0
 TEXT runtime·abort(SB),NOSPLIT,$0-0
 	INT $0x3
 
+// 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,$16-12
+	GO_ARGS
+	NO_LOCAL_POINTERS
+	MOVL	p+0(FP), AX
+	MOVL	h+4(FP), BX
+	MOVL	4(DX), CX
+	MOVL	AX, 0(SP)
+	MOVL	BX, 4(SP)
+	MOVL	CX, 8(SP)
+	CALL	runtime·memhash(SB)
+	MOVL	12(SP), AX
+	MOVL	AX, ret+8(FP)
+	RET
+
 // hash function using AES hardware instructions
 TEXT runtime·aeshash(SB),NOSPLIT,$0-16
 	MOVL	p+0(FP), AX	// ptr to data
-	MOVL	s+4(FP), CX	// size
+	MOVL	s+8(FP), CX	// size
+	LEAL	ret+12(FP), DX
 	JMP	runtime·aeshashbody(SB)
 
-TEXT runtime·aeshashstr(SB),NOSPLIT,$0-16
+TEXT runtime·aeshashstr(SB),NOSPLIT,$0-12
 	MOVL	p+0(FP), AX	// ptr to string object
-	// s+4(FP) is ignored, it is always sizeof(String)
 	MOVL	4(AX), CX	// length of string
 	MOVL	(AX), AX	// string data
+	LEAL	ret+8(FP), DX
 	JMP	runtime·aeshashbody(SB)
 
 // AX: data
 // CX: length
-TEXT runtime·aeshashbody(SB),NOSPLIT,$0-16
-	MOVL	h+8(FP), X0	// seed to low 32 bits of xmm0
-	PINSRD	$1, CX, X0	// size to next 32 bits of xmm0
-	MOVO	runtime·aeskeysched+0(SB), X2
-	MOVO	runtime·aeskeysched+16(SB), X3
+// DX: address to put return value
+TEXT runtime·aeshashbody(SB),NOSPLIT,$0-0
+	MOVL	h+4(FP), X6	// seed to low 64 bits of xmm6
+	PINSRD	$2, CX, X6	// size to high 64 bits of xmm6
+	PSHUFHW	$0, X6, X6	// replace size with its low 2 bytes repeated 4 times
+	MOVO	runtime·aeskeysched(SB), X7
 	CMPL	CX, $16
-	JB	aessmall
-aesloop:
-	CMPL	CX, $16
-	JBE	aesloopend
-	MOVOU	(AX), X1
-	AESENC	X2, X0
-	AESENC	X1, X0
-	SUBL	$16, CX
-	ADDL	$16, AX
-	JMP	aesloop
-// 1-16 bytes remaining
-aesloopend:
-	// This load may overlap with the previous load above.
-	// We'll hash some bytes twice, but that's ok.
-	MOVOU	-16(AX)(CX*1), X1
-	JMP	partial
-// 0-15 bytes
-aessmall:
+	JB	aes0to15
+	JE	aes16
+	CMPL	CX, $32
+	JBE	aes17to32
+	CMPL	CX, $64
+	JBE	aes33to64
+	JMP	aes65plus
+	
+aes0to15:
 	TESTL	CX, CX
-	JE	finalize	// 0 bytes
+	JE	aes0
 
-	CMPB	AX, $0xf0
-	JA	highpartial
+	ADDL	$16, AX
+	TESTW	$0xff0, AX
+	JE	endofpage
 
 	// 16 bytes loaded at this address won't cross
 	// a page boundary, so we can load it directly.
-	MOVOU	(AX), X1
+	MOVOU	-16(AX), X0
 	ADDL	CX, CX
-	PAND	masks<>(SB)(CX*8), X1
-	JMP	partial
-highpartial:
+	PAND	masks<>(SB)(CX*8), X0
+
+	// scramble 3 times
+	AESENC	X6, X0
+	AESENC	X7, X0
+	AESENC	X7, X0
+	MOVL	X0, (DX)
+	RET
+
+endofpage:
 	// address ends in 1111xxxx.  Might be up against
 	// a page boundary, so load ending at last byte.
 	// Then shift bytes down using pshufb.
-	MOVOU	-16(AX)(CX*1), X1
+	MOVOU	-32(AX)(CX*1), X0
 	ADDL	CX, CX
-	PSHUFB	shifts<>(SB)(CX*8), X1
-partial:
-	// incorporate partial block into hash
-	AESENC	X3, X0
-	AESENC	X1, X0
-finalize:	
-	// finalize hash
-	AESENC	X2, X0
-	AESENC	X3, X0
-	AESENC	X2, X0
-	MOVL	X0, ret+12(FP)
-	RET
-
-TEXT runtime·aeshash32(SB),NOSPLIT,$0-16
+	PSHUFB	shifts<>(SB)(CX*8), X0
+	AESENC	X6, X0
+	AESENC	X7, X0
+	AESENC	X7, X0
+	MOVL	X0, (DX)
+	RET
+
+aes0:
+	// return input seed
+	MOVL	h+4(FP), AX
+	MOVL	AX, (DX)
+	RET
+
+aes16:
+	MOVOU	(AX), X0
+	AESENC	X6, X0
+	AESENC	X7, X0
+	AESENC	X7, X0
+	MOVL	X0, (DX)
+	RET
+
+
+aes17to32:
+	// load data to be hashed
+	MOVOU	(AX), X0
+	MOVOU	-16(AX)(CX*1), X1
+
+	// scramble 3 times
+	AESENC	X6, X0
+	AESENC	runtime·aeskeysched+16(SB), X1
+	AESENC	X7, X0
+	AESENC	X7, X1
+	AESENC	X7, X0
+	AESENC	X7, X1
+
+	// combine results
+	PXOR	X1, X0
+	MOVL	X0, (DX)
+	RET
+
+aes33to64:
+	MOVOU	(AX), X0
+	MOVOU	16(AX), X1
+	MOVOU	-32(AX)(CX*1), X2
+	MOVOU	-16(AX)(CX*1), X3
+	
+	AESENC	X6, X0
+	AESENC	runtime·aeskeysched+16(SB), X1
+	AESENC	runtime·aeskeysched+32(SB), X2
+	AESENC	runtime·aeskeysched+48(SB), X3
+	AESENC	X7, X0
+	AESENC	X7, X1
+	AESENC	X7, X2
+	AESENC	X7, X3
+	AESENC	X7, X0
+	AESENC	X7, X1
+	AESENC	X7, X2
+	AESENC	X7, X3
+
+	PXOR	X2, X0
+	PXOR	X3, X1
+	PXOR	X1, X0
+	MOVL	X0, (DX)
+	RET
+
+aes65plus:
+	// start with last (possibly overlapping) block
+	MOVOU	-64(AX)(CX*1), X0
+	MOVOU	-48(AX)(CX*1), X1
+	MOVOU	-32(AX)(CX*1), X2
+	MOVOU	-16(AX)(CX*1), X3
+
+	// scramble state once
+	AESENC	X6, X0
+	AESENC	runtime·aeskeysched+16(SB), X1
+	AESENC	runtime·aeskeysched+32(SB), X2
+	AESENC	runtime·aeskeysched+48(SB), X3
+
+	// compute number of remaining 64-byte blocks
+	DECL	CX
+	SHRL	$6, CX
+	
+aesloop:
+	// scramble state, xor in a block
+	MOVOU	(AX), X4
+	MOVOU	16(AX), X5
+	AESENC	X4, X0
+	AESENC	X5, X1
+	MOVOU	32(AX), X4
+	MOVOU	48(AX), X5
+	AESENC	X4, X2
+	AESENC	X5, X3
+
+	// scramble state
+	AESENC	X7, X0
+	AESENC	X7, X1
+	AESENC	X7, X2
+	AESENC	X7, X3
+
+	ADDL	$64, AX
+	DECL	CX
+	JNE	aesloop
+
+	// 2 more scrambles to finish
+	AESENC	X7, X0
+	AESENC	X7, X1
+	AESENC	X7, X2
+	AESENC	X7, X3
+	AESENC	X7, X0
+	AESENC	X7, X1
+	AESENC	X7, X2
+	AESENC	X7, X3
+
+	PXOR	X2, X0
+	PXOR	X3, X1
+	PXOR	X1, X0
+	MOVL	X0, (DX)
+	RET
+
+TEXT runtime·aeshash32(SB),NOSPLIT,$0-12
 	MOVL	p+0(FP), AX	// ptr to data
-	// s+4(FP) is ignored, it is always sizeof(int32)
-	MOVL	h+8(FP), X0	// seed
+	MOVL	h+4(FP), X0	// seed
 	PINSRD	$1, (AX), X0	// data
 	AESENC	runtime·aeskeysched+0(SB), X0
 	AESENC	runtime·aeskeysched+16(SB), X0
-	AESENC	runtime·aeskeysched+0(SB), X0
-	MOVL	X0, ret+12(FP)
+	AESENC	runtime·aeskeysched+32(SB), X0
+	MOVL	X0, ret+8(FP)
 	RET
 
-TEXT runtime·aeshash64(SB),NOSPLIT,$0-16
+TEXT runtime·aeshash64(SB),NOSPLIT,$0-12
 	MOVL	p+0(FP), AX	// ptr to data
-	// s+4(FP) is ignored, it is always sizeof(int64)
 	MOVQ	(AX), X0	// data
-	PINSRD	$2, h+8(FP), X0	// seed
+	PINSRD	$2, h+4(FP), X0	// seed
 	AESENC	runtime·aeskeysched+0(SB), X0
 	AESENC	runtime·aeskeysched+16(SB), X0
-	AESENC	runtime·aeskeysched+0(SB), X0
-	MOVL	X0, ret+12(FP)
+	AESENC	runtime·aeskeysched+32(SB), X0
+	MOVL	X0, ret+8(FP)
 	RET
 
 // simple mask to get rid of data in the high part of the register.
@@ -1166,51 +1322,57 @@ TEXT runtime·memeq(SB),NOSPLIT,$0-13
 	MOVL	a+0(FP), SI
 	MOVL	b+4(FP), DI
 	MOVL	size+8(FP), BX
-	CALL	runtime·memeqbody(SB)
-	MOVB	AX, ret+12(FP)
+	LEAL	ret+12(FP), AX
+	JMP	runtime·memeqbody(SB)
+
+// memequal_varlen(a, b unsafe.Pointer) bool
+TEXT runtime·memequal_varlen(SB),NOSPLIT,$0-9
+	MOVL    a+0(FP), SI
+	MOVL    b+4(FP), DI
+	CMPL    SI, DI
+	JEQ     eq
+	MOVL    4(DX), BX    // compiler stores size at offset 4 in the closure
+	LEAL	ret+8(FP), AX
+	JMP	runtime·memeqbody(SB)
+eq:
+	MOVB    $1, ret+8(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-17
-	MOVL	s1len+4(FP), AX
-	MOVL	s2len+12(FP), BX
-	CMPL	AX, BX
-	JNE	different
 	MOVL	s1str+0(FP), SI
 	MOVL	s2str+8(FP), DI
 	CMPL	SI, DI
 	JEQ	same
-	CALL	runtime·memeqbody(SB)
-	MOVB	AX, v+16(FP)
-	RET
+	MOVL	s1len+4(FP), BX
+	LEAL	v+16(FP), AX
+	JMP	runtime·memeqbody(SB)
 same:
 	MOVB	$1, v+16(FP)
 	RET
-different:
-	MOVB	$0, v+16(FP)
-	RET
 
 TEXT bytes·Equal(SB),NOSPLIT,$0-25
 	MOVL	a_len+4(FP), BX
 	MOVL	b_len+16(FP), CX
-	XORL	AX, AX
 	CMPL	BX, CX
 	JNE	eqret
 	MOVL	a+0(FP), SI
 	MOVL	b+12(FP), DI
-	CALL	runtime·memeqbody(SB)
+	LEAL	ret+24(FP), AX
+	JMP	runtime·memeqbody(SB)
 eqret:
-	MOVB	AX, ret+24(FP)
+	MOVB	$0, ret+24(FP)
 	RET
 
 // a in SI
 // b in DI
 // count in BX
+// address of result byte in AX
 TEXT runtime·memeqbody(SB),NOSPLIT,$0-0
-	XORL	AX, AX
-
 	CMPL	BX, $4
 	JB	small
 
@@ -1241,6 +1403,7 @@ hugeloop:
 	SUBL	$64, BX
 	CMPL	DX, $0xffff
 	JEQ	hugeloop
+	MOVB	$0, (AX)
 	RET
 
 	// 4 bytes at a time using 32-bit register
@@ -1254,6 +1417,7 @@ bigloop:
 	SUBL	$4, BX
 	CMPL	CX, DX
 	JEQ	bigloop
+	MOVB	$0, (AX)
 	RET
 
 	// remaining 0-4 bytes
@@ -1261,7 +1425,7 @@ leftover:
 	MOVL	-4(SI)(BX*1), CX
 	MOVL	-4(DI)(BX*1), DX
 	CMPL	CX, DX
-	SETEQ	AX
+	SETEQ	(AX)
 	RET
 
 small:
@@ -1298,7 +1462,7 @@ di_finish:
 	SUBL	SI, DI
 	SHLL	CX, DI
 equal:
-	SETEQ	AX
+	SETEQ	(AX)
 	RET
 
 TEXT runtime·cmpstring(SB),NOSPLIT,$0-20
@@ -1306,20 +1470,18 @@ TEXT runtime·cmpstring(SB),NOSPLIT,$0-20
 	MOVL	s1_len+4(FP), BX
 	MOVL	s2_base+8(FP), DI
 	MOVL	s2_len+12(FP), DX
-	CALL	runtime·cmpbody(SB)
-	MOVL	AX, ret+16(FP)
-	RET
+	LEAL	ret+16(FP), AX
+	JMP	runtime·cmpbody(SB)
 
-TEXT runtime·cmpbytes(SB),NOSPLIT,$0-28
+TEXT bytes·Compare(SB),NOSPLIT,$0-28
 	MOVL	s1+0(FP), SI
 	MOVL	s1+4(FP), BX
 	MOVL	s2+12(FP), DI
 	MOVL	s2+16(FP), DX
-	CALL	runtime·cmpbody(SB)
-	MOVL	AX, ret+24(FP)
-	RET
+	LEAL	ret+24(FP), AX
+	JMP	runtime·cmpbody(SB)
 
-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
@@ -1333,7 +1495,7 @@ TEXT bytes·IndexByte(SB),NOSPLIT,$0
 	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
@@ -1352,910 +1514,119 @@ TEXT strings·IndexByte(SB),NOSPLIT,$0
 //   DI = b
 //   BX = alen
 //   DX = blen
-// output:
-//   AX = 1/0/-1
+//   AX = address of return word (set to 1/0/-1)
 TEXT runtime·cmpbody(SB),NOSPLIT,$0-0
-	CMPL	SI, DI
-	JEQ	cmp_allsame
-	CMPL	BX, DX
 	MOVL	DX, BP
-	CMOVLLT	BX, BP // BP = min(alen, blen)
+	SUBL	BX, DX // DX = blen-alen
+	CMOVLGT	BX, BP // BP = min(alen, blen)
+	CMPL	SI, DI
+	JEQ	allsame
 	CMPL	BP, $4
-	JB	cmp_small
+	JB	small
 	TESTL	$0x4000000, runtime·cpuid_edx(SB) // check for sse2
-	JE	cmp_mediumloop
-cmp_largeloop:
+	JE	mediumloop
+largeloop:
 	CMPL	BP, $16
-	JB	cmp_mediumloop
+	JB	mediumloop
 	MOVOU	(SI), X0
 	MOVOU	(DI), X1
 	PCMPEQB X0, X1
-	PMOVMSKB X1, AX
-	XORL	$0xffff, AX	// convert EQ to NE
-	JNE	cmp_diff16	// branch if at least one byte is not equal
+	PMOVMSKB X1, BX
+	XORL	$0xffff, BX	// convert EQ to NE
+	JNE	diff16	// branch if at least one byte is not equal
 	ADDL	$16, SI
 	ADDL	$16, DI
 	SUBL	$16, BP
-	JMP	cmp_largeloop
+	JMP	largeloop
 
-cmp_diff16:
-	BSFL	AX, BX	// index of first byte that differs
-	XORL	AX, AX
+diff16:
+	BSFL	BX, BX	// index of first byte that differs
+	XORL	DX, DX
 	MOVB	(SI)(BX*1), CX
 	CMPB	CX, (DI)(BX*1)
-	SETHI	AX
-	LEAL	-1(AX*2), AX	// convert 1/0 to +1/-1
+	SETHI	DX
+	LEAL	-1(DX*2), DX	// convert 1/0 to +1/-1
+	MOVL	DX, (AX)
 	RET
 
-cmp_mediumloop:
+mediumloop:
 	CMPL	BP, $4
-	JBE	cmp_0through4
-	MOVL	(SI), AX
+	JBE	_0through4
+	MOVL	(SI), BX
 	MOVL	(DI), CX
-	CMPL	AX, CX
-	JNE	cmp_diff4
+	CMPL	BX, CX
+	JNE	diff4
 	ADDL	$4, SI
 	ADDL	$4, DI
 	SUBL	$4, BP
-	JMP	cmp_mediumloop
+	JMP	mediumloop
 
-cmp_0through4:
-	MOVL	-4(SI)(BP*1), AX
+_0through4:
+	MOVL	-4(SI)(BP*1), BX
 	MOVL	-4(DI)(BP*1), CX
-	CMPL	AX, CX
-	JEQ	cmp_allsame
+	CMPL	BX, CX
+	JEQ	allsame
 
-cmp_diff4:
-	BSWAPL	AX	// reverse order of bytes
+diff4:
+	BSWAPL	BX	// reverse order of bytes
 	BSWAPL	CX
-	XORL	AX, CX	// find bit differences
+	XORL	BX, CX	// find bit differences
 	BSRL	CX, CX	// index of highest bit difference
-	SHRL	CX, AX	// move a's bit to bottom
-	ANDL	$1, AX	// mask bit
-	LEAL	-1(AX*2), AX // 1/0 => +1/-1
+	SHRL	CX, BX	// move a's bit to bottom
+	ANDL	$1, BX	// mask bit
+	LEAL	-1(BX*2), BX // 1/0 => +1/-1
+	MOVL	BX, (AX)
 	RET
 
 	// 0-3 bytes in common
-cmp_small:
+small:
 	LEAL	(BP*8), CX
 	NEGL	CX
-	JEQ	cmp_allsame
+	JEQ	allsame
 
 	// load si
 	CMPB	SI, $0xfc
-	JA	cmp_si_high
+	JA	si_high
 	MOVL	(SI), SI
-	JMP	cmp_si_finish
-cmp_si_high:
+	JMP	si_finish
+si_high:
 	MOVL	-4(SI)(BP*1), SI
 	SHRL	CX, SI
-cmp_si_finish:
+si_finish:
 	SHLL	CX, SI
 
 	// same for di
 	CMPB	DI, $0xfc
-	JA	cmp_di_high
+	JA	di_high
 	MOVL	(DI), DI
-	JMP	cmp_di_finish
-cmp_di_high:
+	JMP	di_finish
+di_high:
 	MOVL	-4(DI)(BP*1), DI
 	SHRL	CX, DI
-cmp_di_finish:
+di_finish:
 	SHLL	CX, DI
 
 	BSWAPL	SI	// reverse order of bytes
 	BSWAPL	DI
 	XORL	SI, DI	// find bit differences
-	JEQ	cmp_allsame
+	JEQ	allsame
 	BSRL	DI, CX	// index of highest bit difference
 	SHRL	CX, SI	// move a's bit to bottom
 	ANDL	$1, SI	// mask bit
-	LEAL	-1(SI*2), AX // 1/0 => +1/-1
+	LEAL	-1(SI*2), BX // 1/0 => +1/-1
+	MOVL	BX, (AX)
 	RET
 
 	// all the bytes in common are the same, so we just need
 	// to compare the lengths.
-cmp_allsame:
-	XORL	AX, AX
+allsame:
+	XORL	BX, BX
 	XORL	CX, CX
-	CMPL	BX, DX
-	SETGT	AX	// 1 if alen > blen
+	TESTL	DX, DX
+	SETLT	BX	// 1 if alen > blen
 	SETEQ	CX	// 1 if alen == blen
-	LEAL	-1(CX)(AX*2), AX	// 1,0,-1 result
-	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/8g/ggen.c:clearfat.
-// AX: zero
-// DI: ptr to memory to be zeroed
-// DI is updated as a side effect.
-TEXT runtime·duffzero(SB), NOSPLIT, $0-0
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	STOSL
-	RET
-
-// A Duff's device for copying memory.
-// The compiler jumps to computed addresses within
-// this routine to copy chunks of memory.  Source
-// and destination must not overlap.  Do not
-// change this code without also changing the code
-// in ../../cmd/6g/cgen.c:sgen.
-// SI: ptr to source memory
-// DI: ptr to destination memory
-// SI and DI are updated as a side effect.
-
-// NOTE: this is equivalent to a sequence of MOVSL but
-// for some reason MOVSL is really slow.
-TEXT runtime·duffcopy(SB), NOSPLIT, $0-0
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
-	MOVL	(SI),CX
-	ADDL	$4,SI
-	MOVL	CX,(DI)
-	ADDL	$4,DI
-	
+	LEAL	-1(CX)(BX*2), BX	// 1,0,-1 result
+	MOVL	BX, (AX)
 	RET
 
 TEXT runtime·fastrand1(SB), NOSPLIT, $0-4
@@ -2290,3 +1661,26 @@ TEXT _cgo_topofstack(SB),NOSPLIT,$0
 TEXT runtime·goexit(SB),NOSPLIT,$0-0
 	BYTE	$0x90	// NOP
 	CALL	runtime·goexit1(SB)	// does not return
+	// traceback from goexit1 must hit code range of goexit
+	BYTE	$0x90	// NOP
+
+TEXT runtime·prefetcht0(SB),NOSPLIT,$0-4
+	MOVL	addr+0(FP), AX
+	PREFETCHT0	(AX)
+	RET
+
+TEXT runtime·prefetcht1(SB),NOSPLIT,$0-4
+	MOVL	addr+0(FP), AX
+	PREFETCHT1	(AX)
+	RET
+
+
+TEXT runtime·prefetcht2(SB),NOSPLIT,$0-4
+	MOVL	addr+0(FP), AX
+	PREFETCHT2	(AX)
+	RET
+
+TEXT runtime·prefetchnta(SB),NOSPLIT,$0-4
+	MOVL	addr+0(FP), AX
+	PREFETCHNTA	(AX)
+	RET
diff --git a/src/runtime/asm_amd64.s b/src/runtime/asm_amd64.s
index 39d7c78..3b4ca4d 100644
--- a/src/runtime/asm_amd64.s
+++ b/src/runtime/asm_amd64.s
@@ -2,7 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
 #include "funcdata.h"
 #include "textflag.h"
 
@@ -29,6 +30,19 @@ TEXT runtime·rt0_go(SB),NOSPLIT,$0
 	CPUID
 	CMPQ	AX, $0
 	JE	nocpuinfo
+
+	// Figure out how to serialize RDTSC.
+	// On Intel processors LFENCE is enough. AMD requires MFENCE.
+	// Don't know about the rest, so let's do MFENCE.
+	CMPL	BX, $0x756E6547  // "Genu"
+	JNE	notintel
+	CMPL	DX, $0x49656E69  // "ineI"
+	JNE	notintel
+	CMPL	CX, $0x6C65746E  // "ntel"
+	JNE	notintel
+	MOVB	$1, runtime·lfenceBeforeRdtsc(SB)
+notintel:
+
 	MOVQ	$1, AX
 	CPUID
 	MOVL	CX, runtime·cpuid_ecx(SB)
@@ -47,7 +61,7 @@ nocpuinfo:
 	// update stackguard after _cgo_init
 	MOVQ	$runtime·g0(SB), CX
 	MOVQ	(g_stack+stack_lo)(CX), AX
-	ADDQ	$const_StackGuard, AX
+	ADDQ	$const__StackGuard, AX
 	MOVQ	AX, g_stackguard0(CX)
 	MOVQ	AX, g_stackguard1(CX)
 
@@ -95,8 +109,8 @@ ok:
 	CALL	runtime·schedinit(SB)
 
 	// create a new goroutine to start program
-	MOVQ	$runtime·main·f(SB), BP		// entry
-	PUSHQ	BP
+	MOVQ	$runtime·mainPC(SB), AX		// entry
+	PUSHQ	AX
 	PUSHQ	$0			// arg size
 	CALL	runtime·newproc(SB)
 	POPQ	AX
@@ -108,8 +122,8 @@ ok:
 	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
@@ -133,6 +147,7 @@ TEXT runtime·gosave(SB), NOSPLIT, $0-8
 	MOVQ	BX, gobuf_pc(AX)
 	MOVQ	$0, gobuf_ret(AX)
 	MOVQ	$0, gobuf_ctxt(AX)
+	MOVQ	BP, gobuf_bp(AX)
 	get_tls(CX)
 	MOVQ	g(CX), BX
 	MOVQ	BX, gobuf_g(AX)
@@ -149,9 +164,11 @@ TEXT runtime·gogo(SB), NOSPLIT, $0-8
 	MOVQ	gobuf_sp(BX), SP	// restore SP
 	MOVQ	gobuf_ret(BX), AX
 	MOVQ	gobuf_ctxt(BX), DX
+	MOVQ	gobuf_bp(BX), BP
 	MOVQ	$0, gobuf_sp(BX)	// clear to help garbage collector
 	MOVQ	$0, gobuf_ret(BX)
 	MOVQ	$0, gobuf_ctxt(BX)
+	MOVQ	$0, gobuf_bp(BX)
 	MOVQ	gobuf_pc(BX), BX
 	JMP	BX
 
@@ -169,6 +186,7 @@ TEXT runtime·mcall(SB), NOSPLIT, $0-8
 	LEAQ	fn+0(FP), BX	// caller's SP
 	MOVQ	BX, (g_sched+gobuf_sp)(AX)
 	MOVQ	AX, (g_sched+gobuf_g)(AX)
+	MOVQ	BP, (g_sched+gobuf_bp)(AX)
 
 	// switch to m->g0 & its stack, call fn
 	MOVQ	g(CX), BX
@@ -189,63 +207,50 @@ TEXT runtime·mcall(SB), NOSPLIT, $0-8
 	JMP	AX
 	RET
 
-// switchtoM is a dummy routine that onM leaves at the bottom
+// 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 M stack because the one at the top of
-// the M stack terminates the stack walk (see topofstack()).
-TEXT runtime·switchtoM(SB), NOSPLIT, $0-0
+// 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
 	RET
 
-// func onM_signalok(fn func())
-TEXT runtime·onM_signalok(SB), NOSPLIT, $0-8
+// func systemstack(fn func())
+TEXT runtime·systemstack(SB), NOSPLIT, $0-8
+	MOVQ	fn+0(FP), DI	// DI = fn
 	get_tls(CX)
 	MOVQ	g(CX), AX	// AX = g
 	MOVQ	g_m(AX), BX	// BX = m
+
 	MOVQ	m_gsignal(BX), DX	// DX = gsignal
 	CMPQ	AX, DX
-	JEQ	ongsignal
-	JMP	runtime·onM(SB)
-
-ongsignal:
-	MOVQ	fn+0(FP), DI	// DI = fn
-	MOVQ	DI, DX
-	MOVQ	0(DI), DI
-	CALL	DI
-	RET
-
-// func onM(fn func())
-TEXT runtime·onM(SB), NOSPLIT, $0-8
-	MOVQ	fn+0(FP), DI	// DI = fn
-	get_tls(CX)
-	MOVQ	g(CX), AX	// AX = g
-	MOVQ	g_m(AX), BX	// BX = m
+	JEQ	noswitch
 
 	MOVQ	m_g0(BX), DX	// DX = g0
 	CMPQ	AX, DX
-	JEQ	onm
+	JEQ	noswitch
 
-	MOVQ	m_curg(BX), BP
-	CMPQ	AX, BP
-	JEQ	oncurg
+	MOVQ	m_curg(BX), R8
+	CMPQ	AX, R8
+	JEQ	switch
 	
-	// Not g0, not curg. Must be gsignal, but that's not allowed.
-	// Hide call from linker nosplit analysis.
-	MOVQ	$runtime·badonm(SB), AX
+	// Bad: g is not gsignal, not g0, not curg. What is it?
+	MOVQ	$runtime·badsystemstack(SB), AX
 	CALL	AX
 
-oncurg:
+switch:
 	// save our state in g->sched.  Pretend to
-	// be switchtoM if the G stack is scanned.
-	MOVQ	$runtime·switchtoM(SB), BP
-	MOVQ	BP, (g_sched+gobuf_pc)(AX)
+	// be systemstack_switch if the G stack is scanned.
+	MOVQ	$runtime·systemstack_switch(SB), SI
+	MOVQ	SI, (g_sched+gobuf_pc)(AX)
 	MOVQ	SP, (g_sched+gobuf_sp)(AX)
 	MOVQ	AX, (g_sched+gobuf_g)(AX)
+	MOVQ	BP, (g_sched+gobuf_bp)(AX)
 
 	// switch to g0
 	MOVQ	DX, g(CX)
 	MOVQ	(g_sched+gobuf_sp)(DX), BX
-	// make it look like mstart called onM on g0, to stop traceback
+	// make it look like mstart called systemstack on g0, to stop traceback
 	SUBQ	$8, BX
 	MOVQ	$runtime·mstart(SB), DX
 	MOVQ	DX, 0(BX)
@@ -266,7 +271,7 @@ oncurg:
 	MOVQ	$0, (g_sched+gobuf_sp)(AX)
 	RET
 
-onm:
+noswitch:
 	// already on m stack, just call directly
 	MOVQ	DI, DX
 	MOVQ	0(DI), DI
@@ -316,11 +321,12 @@ TEXT runtime·morestack(SB),NOSPLIT,$0-0
 	LEAQ	8(SP), AX // f's SP
 	MOVQ	AX, (g_sched+gobuf_sp)(SI)
 	MOVQ	DX, (g_sched+gobuf_ctxt)(SI)
+	MOVQ	BP, (g_sched+gobuf_bp)(SI)
 
 	// Call newstack on m->g0's stack.
-	MOVQ	m_g0(BX), BP
-	MOVQ	BP, g(CX)
-	MOVQ	(g_sched+gobuf_sp)(BP), SP
+	MOVQ	m_g0(BX), BX
+	MOVQ	BX, g(CX)
+	MOVQ	(g_sched+gobuf_sp)(BX), SP
 	CALL	runtime·newstack(SB)
 	MOVQ	$0, 0x1003	// crash if newstack returns
 	RET
@@ -330,8 +336,24 @@ TEXT runtime·morestack_noctxt(SB),NOSPLIT,$0
 	MOVL	$0, DX
 	JMP	runtime·morestack(SB)
 
+TEXT runtime·stackBarrier(SB),NOSPLIT,$0
+	// We came here via a RET to an overwritten return PC.
+	// AX may be live. Other registers are available.
+
+	// Get the original return PC, g.stkbar[g.stkbarPos].savedLRVal.
+	get_tls(CX)
+	MOVQ	g(CX), CX
+	MOVQ	(g_stkbar+slice_array)(CX), DX
+	MOVQ	g_stkbarPos(CX), BX
+	IMULQ	$stkbar__size, BX	// Too big for SIB.
+	MOVQ	stkbar_savedLRVal(DX)(BX*1), BX
+	// Record that this stack barrier was hit.
+	ADDQ	$1, g_stkbarPos(CX)
+	// Jump to the original return PC.
+	JMP	BX
+
 // reflectcall: call a function with the given argument list
-// func call(f *FuncVal, arg *byte, argsize, retoffset uint32).
+// 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!
@@ -343,9 +365,13 @@ TEXT runtime·morestack_noctxt(SB),NOSPLIT,$0
 	JMP	AX
 // Note: can't just "JMP NAME(SB)" - bad inlining results.
 
-TEXT ·reflectcall(SB), NOSPLIT, $0-24
-	MOVLQZX argsize+16(FP), CX
-	DISPATCH(runtime·call16, 16)
+TEXT reflect·call(SB), NOSPLIT, $0-0
+	JMP	·reflectcall(SB)
+
+TEXT ·reflectcall(SB), NOSPLIT, $0-32
+	MOVLQZX argsize+24(FP), CX
+	// 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)
@@ -376,29 +402,38 @@ TEXT ·reflectcall(SB), NOSPLIT, $0-24
 	JMP	AX
 
 #define CALLFN(NAME,MAXSIZE)			\
-TEXT NAME(SB), WRAPPER, $MAXSIZE-24;		\
+TEXT NAME(SB), WRAPPER, $MAXSIZE-32;		\
 	NO_LOCAL_POINTERS;			\
 	/* copy arguments to stack */		\
-	MOVQ	argptr+8(FP), SI;		\
-	MOVLQZX argsize+16(FP), CX;		\
+	MOVQ	argptr+16(FP), SI;		\
+	MOVLQZX argsize+24(FP), CX;		\
 	MOVQ	SP, DI;				\
 	REP;MOVSB;				\
 	/* call function */			\
-	MOVQ	f+0(FP), DX;			\
+	MOVQ	f+8(FP), DX;			\
 	PCDATA  $PCDATA_StackMapIndex, $0;	\
 	CALL	(DX);				\
 	/* copy return values back */		\
-	MOVQ	argptr+8(FP), DI;		\
-	MOVLQZX	argsize+16(FP), CX;		\
-	MOVLQZX retoffset+20(FP), BX;		\
+	MOVQ	argptr+16(FP), DI;		\
+	MOVLQZX	argsize+24(FP), CX;		\
+	MOVLQZX retoffset+28(FP), BX;		\
 	MOVQ	SP, SI;				\
 	ADDQ	BX, DI;				\
 	ADDQ	BX, SI;				\
 	SUBQ	BX, CX;				\
 	REP;MOVSB;				\
+	/* execute write barrier updates */	\
+	MOVQ	argtype+0(FP), DX;		\
+	MOVQ	argptr+16(FP), DI;		\
+	MOVLQZX	argsize+24(FP), CX;		\
+	MOVLQZX retoffset+28(FP), BX;		\
+	MOVQ	DX, 0(SP);			\
+	MOVQ	DI, 8(SP);			\
+	MOVQ	CX, 16(SP);			\
+	MOVQ	BX, 24(SP);			\
+	CALL	runtime·callwritebarrier(SB);	\
 	RET
 
-CALLFN(·call16, 16)
 CALLFN(·call32, 32)
 CALLFN(·call64, 64)
 CALLFN(·call128, 128)
@@ -439,12 +474,7 @@ TEXT runtime·cas(SB), NOSPLIT, $0-17
 	MOVL	new+12(FP), CX
 	LOCK
 	CMPXCHGL	CX, 0(BX)
-	JZ 4(PC)
-	MOVL	$0, AX
-	MOVB	AX, ret+16(FP)
-	RET
-	MOVL	$1, AX
-	MOVB	AX, ret+16(FP)
+	SETEQ	ret+16(FP)
 	RET
 
 // bool	runtime·cas64(uint64 *val, uint64 old, uint64 new)
@@ -461,13 +491,7 @@ TEXT runtime·cas64(SB), NOSPLIT, $0-25
 	MOVQ	new+16(FP), CX
 	LOCK
 	CMPXCHGQ	CX, 0(BX)
-	JNZ	cas64_fail
-	MOVL	$1, AX
-	MOVB	AX, ret+24(FP)
-	RET
-cas64_fail:
-	MOVL	$0, AX
-	MOVB	AX, ret+24(FP)
+	SETEQ	ret+24(FP)
 	RET
 	
 TEXT runtime·casuintptr(SB), NOSPLIT, $0-25
@@ -489,18 +513,13 @@ TEXT runtime·atomicstoreuintptr(SB), NOSPLIT, $0-16
 //		return 1;
 //	} else
 //		return 0;
-TEXT runtime·casp(SB), NOSPLIT, $0-25
+TEXT runtime·casp1(SB), NOSPLIT, $0-25
 	MOVQ	ptr+0(FP), BX
 	MOVQ	old+8(FP), AX
 	MOVQ	new+16(FP), CX
 	LOCK
 	CMPXCHGQ	CX, 0(BX)
-	JZ 4(PC)
-	MOVL	$0, AX
-	MOVB	AX, ret+24(FP)
-	RET
-	MOVL	$1, AX
-	MOVB	AX, ret+24(FP)
+	SETEQ	ret+24(FP)
 	RET
 
 // uint32 xadd(uint32 volatile *val, int32 delta)
@@ -527,6 +546,9 @@ TEXT runtime·xadd64(SB), NOSPLIT, $0-24
 	MOVQ	AX, ret+16(FP)
 	RET
 
+TEXT runtime·xadduintptr(SB), NOSPLIT, $0-24
+	JMP	runtime·xadd64(SB)
+
 TEXT runtime·xchg(SB), NOSPLIT, $0-20
 	MOVQ	ptr+0(FP), BX
 	MOVL	new+8(FP), AX
@@ -541,7 +563,7 @@ TEXT runtime·xchg64(SB), NOSPLIT, $0-24
 	MOVQ	AX, ret+16(FP)
 	RET
 
-TEXT runtime·xchgp(SB), NOSPLIT, $0-24
+TEXT runtime·xchgp1(SB), NOSPLIT, $0-24
 	MOVQ	ptr+0(FP), BX
 	MOVQ	new+8(FP), AX
 	XCHGQ	AX, 0(BX)
@@ -559,7 +581,7 @@ again:
 	JNZ	again
 	RET
 
-TEXT runtime·atomicstorep(SB), NOSPLIT, $0-16
+TEXT runtime·atomicstorep1(SB), NOSPLIT, $0-16
 	MOVQ	ptr+0(FP), BX
 	MOVQ	val+8(FP), AX
 	XCHGQ	AX, 0(BX)
@@ -585,6 +607,19 @@ TEXT runtime·atomicor8(SB), NOSPLIT, $0-9
 	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
+
+TEXT ·publicationBarrier(SB),NOSPLIT,$0-0
+	// Stores are already ordered on x86, so this is just a
+	// compile barrier.
+	RET
+
 // void jmpdefer(fn, sp);
 // called from deferreturn.
 // 1. pop the caller
@@ -608,44 +643,34 @@ TEXT gosave<>(SB),NOSPLIT,$0
 	MOVQ	R9, (g_sched+gobuf_sp)(R8)
 	MOVQ	$0, (g_sched+gobuf_ret)(R8)
 	MOVQ	$0, (g_sched+gobuf_ctxt)(R8)
+	MOVQ	BP, (g_sched+gobuf_bp)(R8)
 	RET
 
-// asmcgocall(void(*fn)(void*), void *arg)
+// func asmcgocall(fn, arg unsafe.Pointer) int32
 // 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
+// See cgocall.go for more details.
+TEXT ·asmcgocall(SB),NOSPLIT,$0-20
 	MOVQ	fn+0(FP), AX
 	MOVQ	arg+8(FP), BX
-	CALL	asmcgocall<>(SB)
-	RET
 
-TEXT ·asmcgocall_errno(SB),NOSPLIT,$0-20
-	MOVQ	fn+0(FP), AX
-	MOVQ	arg+8(FP), BX
-	CALL	asmcgocall<>(SB)
-	MOVL	AX, ret+16(FP)
-	RET
-
-// asmcgocall common code. fn in AX, arg in BX. returns errno in AX.
-TEXT asmcgocall<>(SB),NOSPLIT,$0-0
 	MOVQ	SP, DX
 
 	// 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.
 	get_tls(CX)
-	MOVQ	g(CX), BP
-	MOVQ	g_m(BP), BP
-	MOVQ	m_g0(BP), SI
+	MOVQ	g(CX), R8
+	MOVQ	g_m(R8), R8
+	MOVQ	m_g0(R8), SI
 	MOVQ	g(CX), DI
 	CMPQ	SI, DI
 	JEQ	nosave
-	MOVQ	m_gsignal(BP), SI
+	MOVQ	m_gsignal(R8), SI
 	CMPQ	SI, DI
 	JEQ	nosave
 	
-	MOVQ	m_g0(BP), SI
+	MOVQ	m_g0(R8), SI
 	CALL	gosave<>(SB)
 	MOVQ	SI, g(CX)
 	MOVQ	(g_sched+gobuf_sp)(SI), SP
@@ -671,6 +696,8 @@ nosave:
 	SUBQ	40(SP), SI
 	MOVQ	DI, g(CX)
 	MOVQ	SI, SP
+
+	MOVL	AX, ret+16(FP)
 	RET
 
 // cgocallback(void (*fn)(void*), void *frame, uintptr framesize)
@@ -688,7 +715,7 @@ TEXT runtime·cgocallback(SB),NOSPLIT,$24-24
 	RET
 
 // cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize)
-// See cgocall.c for more details.
+// See cgocall.go for more details.
 TEXT ·cgocallback_gofunc(SB),NOSPLIT,$8-24
 	NO_LOCAL_POINTERS
 
@@ -699,15 +726,15 @@ TEXT ·cgocallback_gofunc(SB),NOSPLIT,$8-24
 	// the linker analysis by using an indirect call through AX.
 	get_tls(CX)
 #ifdef GOOS_windows
-	MOVL	$0, BP
+	MOVL	$0, BX
 	CMPQ	CX, $0
 	JEQ	2(PC)
 #endif
-	MOVQ	g(CX), BP
-	CMPQ	BP, $0
+	MOVQ	g(CX), BX
+	CMPQ	BX, $0
 	JEQ	needm
-	MOVQ	g_m(BP), BP
-	MOVQ	BP, R8 // holds oldm until end of function
+	MOVQ	g_m(BX), BX
+	MOVQ	BX, R8 // holds oldm until end of function
 	JMP	havem
 needm:
 	MOVQ	$0, 0(SP)
@@ -715,8 +742,8 @@ needm:
 	CALL	AX
 	MOVQ	0(SP), R8
 	get_tls(CX)
-	MOVQ	g(CX), BP
-	MOVQ	g_m(BP), BP
+	MOVQ	g(CX), BX
+	MOVQ	g_m(BX), BX
 	
 	// Set m->sched.sp = SP, so that if a panic happens
 	// during the function we are about to execute, it will
@@ -726,10 +753,10 @@ needm:
 	// 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 onM will try to use it. If we don't set it here,
+	// 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.
-	MOVQ	m_g0(BP), SI
+	MOVQ	m_g0(BX), SI
 	MOVQ	SP, (g_sched+gobuf_sp)(SI)
 
 havem:
@@ -738,7 +765,7 @@ havem:
 	// 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 0(SP).
-	MOVQ	m_g0(BP), SI
+	MOVQ	m_g0(BX), SI
 	MOVQ	(g_sched+gobuf_sp)(SI), AX
 	MOVQ	AX, 0(SP)
 	MOVQ	SP, (g_sched+gobuf_sp)(SI)
@@ -758,30 +785,43 @@ havem:
 	// the earlier calls.
 	//
 	// In the new goroutine, 0(SP) holds the saved R8.
-	MOVQ	m_curg(BP), SI
+	MOVQ	m_curg(BX), SI
 	MOVQ	SI, g(CX)
 	MOVQ	(g_sched+gobuf_sp)(SI), DI  // prepare stack as DI
-	MOVQ	(g_sched+gobuf_pc)(SI), BP
-	MOVQ	BP, -8(DI)
-	LEAQ	-(8+8)(DI), SP
+	MOVQ	(g_sched+gobuf_pc)(SI), BX
+	MOVQ	BX, -8(DI)
+	// Compute the size of the frame, including return PC and, if
+	// GOEXPERIMENT=framepointer, the saved based pointer
+	LEAQ	fv+0(FP), AX
+	SUBQ	SP, AX
+	SUBQ	AX, DI
+	MOVQ	DI, SP
+
 	MOVQ	R8, 0(SP)
 	CALL	runtime·cgocallbackg(SB)
 	MOVQ	0(SP), R8
 
+	// Compute the size of the frame again.  FP and SP have
+	// completely different values here than they did above,
+	// but only their difference matters.
+	LEAQ	fv+0(FP), AX
+	SUBQ	SP, AX
+
 	// Restore g->sched (== m->curg->sched) from saved values.
 	get_tls(CX)
 	MOVQ	g(CX), SI
-	MOVQ	8(SP), BP
-	MOVQ	BP, (g_sched+gobuf_pc)(SI)
-	LEAQ	(8+8)(SP), DI
+	MOVQ	SP, DI
+	ADDQ	AX, DI
+	MOVQ	-8(DI), BX
+	MOVQ	BX, (g_sched+gobuf_pc)(SI)
 	MOVQ	DI, (g_sched+gobuf_sp)(SI)
 
 	// 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.)
-	MOVQ	g(CX), BP
-	MOVQ	g_m(BP), BP
-	MOVQ	m_g0(BP), SI
+	MOVQ	g(CX), BX
+	MOVQ	g_m(BX), BX
+	MOVQ	m_g0(BX), SI
 	MOVQ	SI, g(CX)
 	MOVQ	(g_sched+gobuf_sp)(SI), SP
 	MOVQ	0(SP), AX
@@ -832,135 +872,344 @@ TEXT runtime·stackcheck(SB), NOSPLIT, $0-0
 	INT	$3
 	RET
 
-TEXT runtime·getcallerpc(SB),NOSPLIT,$0-16
+TEXT runtime·getcallerpc(SB),NOSPLIT,$8-16
 	MOVQ	argp+0(FP),AX		// addr of first arg
 	MOVQ	-8(AX),AX		// get calling pc
+	CMPQ	AX, runtime·stackBarrierPC(SB)
+	JNE	nobar
+	// Get original return PC.
+	CALL	runtime·nextBarrierPC(SB)
+	MOVQ	0(SP), AX
+nobar:
 	MOVQ	AX, ret+8(FP)
 	RET
 
-TEXT runtime·gogetcallerpc(SB),NOSPLIT,$0-16
-	MOVQ	p+0(FP),AX		// addr of first arg
-	MOVQ	-8(AX),AX		// get calling pc
-	MOVQ	AX,ret+8(FP)
-	RET
-
-TEXT runtime·setcallerpc(SB),NOSPLIT,$0-16
+TEXT runtime·setcallerpc(SB),NOSPLIT,$8-16
 	MOVQ	argp+0(FP),AX		// addr of first arg
 	MOVQ	pc+8(FP), BX
+	MOVQ	-8(AX), CX
+	CMPQ	CX, runtime·stackBarrierPC(SB)
+	JEQ	setbar
 	MOVQ	BX, -8(AX)		// set calling pc
 	RET
+setbar:
+	// Set the stack barrier return PC.
+	MOVQ	BX, 0(SP)
+	CALL	runtime·setNextBarrierPC(SB)
+	RET
 
 TEXT runtime·getcallersp(SB),NOSPLIT,$0-16
 	MOVQ	argp+0(FP), AX
 	MOVQ	AX, ret+8(FP)
 	RET
 
-// func gogetcallersp(p unsafe.Pointer) uintptr
-TEXT runtime·gogetcallersp(SB),NOSPLIT,$0-16
-	MOVQ	p+0(FP),AX		// addr of first arg
-	MOVQ	AX, ret+8(FP)
-	RET
-
-// int64 runtime·cputicks(void)
+// func cputicks() int64
 TEXT runtime·cputicks(SB),NOSPLIT,$0-0
+	CMPB	runtime·lfenceBeforeRdtsc(SB), $1
+	JNE	mfence
+	BYTE	$0x0f; BYTE $0xae; BYTE $0xe8 // LFENCE
+	JMP	done
+mfence:
+	BYTE	$0x0f; BYTE $0xae; BYTE $0xf0 // MFENCE
+done:
 	RDTSC
 	SHLQ	$32, DX
 	ADDQ	DX, AX
 	MOVQ	AX, ret+0(FP)
 	RET
 
+// 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,$32-24
+	GO_ARGS
+	NO_LOCAL_POINTERS
+	MOVQ	p+0(FP), AX
+	MOVQ	h+8(FP), BX
+	MOVQ	8(DX), CX
+	MOVQ	AX, 0(SP)
+	MOVQ	BX, 8(SP)
+	MOVQ	CX, 16(SP)
+	CALL	runtime·memhash(SB)
+	MOVQ	24(SP), AX
+	MOVQ	AX, ret+16(FP)
+	RET
+
 // hash function using AES hardware instructions
 TEXT runtime·aeshash(SB),NOSPLIT,$0-32
 	MOVQ	p+0(FP), AX	// ptr to data
-	MOVQ	s+8(FP), CX	// size
+	MOVQ	s+16(FP), CX	// size
+	LEAQ	ret+24(FP), DX
 	JMP	runtime·aeshashbody(SB)
 
-TEXT runtime·aeshashstr(SB),NOSPLIT,$0-32
+TEXT runtime·aeshashstr(SB),NOSPLIT,$0-24
 	MOVQ	p+0(FP), AX	// ptr to string struct
-	// s+8(FP) is ignored, it is always sizeof(String)
 	MOVQ	8(AX), CX	// length of string
 	MOVQ	(AX), AX	// string data
+	LEAQ	ret+16(FP), DX
 	JMP	runtime·aeshashbody(SB)
 
 // AX: data
 // CX: length
-TEXT runtime·aeshashbody(SB),NOSPLIT,$0-32
-	MOVQ	h+16(FP), X0	// seed to low 64 bits of xmm0
-	PINSRQ	$1, CX, X0	// size to high 64 bits of xmm0
-	MOVO	runtime·aeskeysched+0(SB), X2
-	MOVO	runtime·aeskeysched+16(SB), X3
+// DX: address to put return value
+TEXT runtime·aeshashbody(SB),NOSPLIT,$0-0
+	MOVQ	h+8(FP), X6	// seed to low 64 bits of xmm6
+	PINSRQ	$1, CX, X6	// size to high 64 bits of xmm6
+	PSHUFHW	$0, X6, X6	// replace size with its low 2 bytes repeated 4 times
+	MOVO	runtime·aeskeysched(SB), X7
 	CMPQ	CX, $16
-	JB	aessmall
-aesloop:
-	CMPQ	CX, $16
-	JBE	aesloopend
-	MOVOU	(AX), X1
-	AESENC	X2, X0
-	AESENC	X1, X0
-	SUBQ	$16, CX
-	ADDQ	$16, AX
-	JMP	aesloop
-// 1-16 bytes remaining
-aesloopend:
-	// This load may overlap with the previous load above.
-	// We'll hash some bytes twice, but that's ok.
-	MOVOU	-16(AX)(CX*1), X1
-	JMP	partial
-// 0-15 bytes
-aessmall:
+	JB	aes0to15
+	JE	aes16
+	CMPQ	CX, $32
+	JBE	aes17to32
+	CMPQ	CX, $64
+	JBE	aes33to64
+	CMPQ	CX, $128
+	JBE	aes65to128
+	JMP	aes129plus
+
+aes0to15:
 	TESTQ	CX, CX
-	JE	finalize	// 0 bytes
+	JE	aes0
 
-	CMPB	AX, $0xf0
-	JA	highpartial
+	ADDQ	$16, AX
+	TESTW	$0xff0, AX
+	JE	endofpage
 
 	// 16 bytes loaded at this address won't cross
 	// a page boundary, so we can load it directly.
-	MOVOU	(AX), X1
+	MOVOU	-16(AX), X0
 	ADDQ	CX, CX
-	MOVQ	$masks<>(SB), BP
-	PAND	(BP)(CX*8), X1
-	JMP	partial
-highpartial:
+	MOVQ	$masks<>(SB), AX
+	PAND	(AX)(CX*8), X0
+
+	// scramble 3 times
+	AESENC	X6, X0
+	AESENC	X7, X0
+	AESENC	X7, X0
+	MOVQ	X0, (DX)
+	RET
+
+endofpage:
 	// address ends in 1111xxxx.  Might be up against
 	// a page boundary, so load ending at last byte.
 	// Then shift bytes down using pshufb.
-	MOVOU	-16(AX)(CX*1), X1
+	MOVOU	-32(AX)(CX*1), X0
 	ADDQ	CX, CX
-	MOVQ	$shifts<>(SB), BP
-	PSHUFB	(BP)(CX*8), X1
-partial:
-	// incorporate partial block into hash
-	AESENC	X3, X0
-	AESENC	X1, X0
-finalize:	
-	// finalize hash
-	AESENC	X2, X0
-	AESENC	X3, X0
-	AESENC	X2, X0
-	MOVQ	X0, res+24(FP)
-	RET
-
-TEXT runtime·aeshash32(SB),NOSPLIT,$0-32
+	MOVQ	$shifts<>(SB), AX
+	PSHUFB	(AX)(CX*8), X0
+	AESENC	X6, X0
+	AESENC	X7, X0
+	AESENC	X7, X0
+	MOVQ	X0, (DX)
+	RET
+
+aes0:
+	// return input seed
+	MOVQ	h+8(FP), AX
+	MOVQ	AX, (DX)
+	RET
+
+aes16:
+	MOVOU	(AX), X0
+	AESENC	X6, X0
+	AESENC	X7, X0
+	AESENC	X7, X0
+	MOVQ	X0, (DX)
+	RET
+
+aes17to32:
+	// load data to be hashed
+	MOVOU	(AX), X0
+	MOVOU	-16(AX)(CX*1), X1
+
+	// scramble 3 times
+	AESENC	X6, X0
+	AESENC	runtime·aeskeysched+16(SB), X1
+	AESENC	X7, X0
+	AESENC	X7, X1
+	AESENC	X7, X0
+	AESENC	X7, X1
+
+	// combine results
+	PXOR	X1, X0
+	MOVQ	X0, (DX)
+	RET
+
+aes33to64:
+	MOVOU	(AX), X0
+	MOVOU	16(AX), X1
+	MOVOU	-32(AX)(CX*1), X2
+	MOVOU	-16(AX)(CX*1), X3
+	
+	AESENC	X6, X0
+	AESENC	runtime·aeskeysched+16(SB), X1
+	AESENC	runtime·aeskeysched+32(SB), X2
+	AESENC	runtime·aeskeysched+48(SB), X3
+	AESENC	X7, X0
+	AESENC	X7, X1
+	AESENC	X7, X2
+	AESENC	X7, X3
+	AESENC	X7, X0
+	AESENC	X7, X1
+	AESENC	X7, X2
+	AESENC	X7, X3
+
+	PXOR	X2, X0
+	PXOR	X3, X1
+	PXOR	X1, X0
+	MOVQ	X0, (DX)
+	RET
+
+aes65to128:
+	MOVOU	(AX), X0
+	MOVOU	16(AX), X1
+	MOVOU	32(AX), X2
+	MOVOU	48(AX), X3
+	MOVOU	-64(AX)(CX*1), X4
+	MOVOU	-48(AX)(CX*1), X5
+	MOVOU	-32(AX)(CX*1), X8
+	MOVOU	-16(AX)(CX*1), X9
+	
+	AESENC	X6, X0
+	AESENC	runtime·aeskeysched+16(SB), X1
+	AESENC	runtime·aeskeysched+32(SB), X2
+	AESENC	runtime·aeskeysched+48(SB), X3
+	AESENC	runtime·aeskeysched+64(SB), X4
+	AESENC	runtime·aeskeysched+80(SB), X5
+	AESENC	runtime·aeskeysched+96(SB), X8
+	AESENC	runtime·aeskeysched+112(SB), X9
+	AESENC	X7, X0
+	AESENC	X7, X1
+	AESENC	X7, X2
+	AESENC	X7, X3
+	AESENC	X7, X4
+	AESENC	X7, X5
+	AESENC	X7, X8
+	AESENC	X7, X9
+	AESENC	X7, X0
+	AESENC	X7, X1
+	AESENC	X7, X2
+	AESENC	X7, X3
+	AESENC	X7, X4
+	AESENC	X7, X5
+	AESENC	X7, X8
+	AESENC	X7, X9
+
+	PXOR	X4, X0
+	PXOR	X5, X1
+	PXOR	X8, X2
+	PXOR	X9, X3
+	PXOR	X2, X0
+	PXOR	X3, X1
+	PXOR	X1, X0
+	MOVQ	X0, (DX)
+	RET
+
+aes129plus:
+	// start with last (possibly overlapping) block
+	MOVOU	-128(AX)(CX*1), X0
+	MOVOU	-112(AX)(CX*1), X1
+	MOVOU	-96(AX)(CX*1), X2
+	MOVOU	-80(AX)(CX*1), X3
+	MOVOU	-64(AX)(CX*1), X4
+	MOVOU	-48(AX)(CX*1), X5
+	MOVOU	-32(AX)(CX*1), X8
+	MOVOU	-16(AX)(CX*1), X9
+
+	// scramble state once
+	AESENC	X6, X0
+	AESENC	runtime·aeskeysched+16(SB), X1
+	AESENC	runtime·aeskeysched+32(SB), X2
+	AESENC	runtime·aeskeysched+48(SB), X3
+	AESENC	runtime·aeskeysched+64(SB), X4
+	AESENC	runtime·aeskeysched+80(SB), X5
+	AESENC	runtime·aeskeysched+96(SB), X8
+	AESENC	runtime·aeskeysched+112(SB), X9
+
+	// compute number of remaining 128-byte blocks
+	DECQ	CX
+	SHRQ	$7, CX
+	
+aesloop:
+	// scramble state, xor in a block
+	MOVOU	(AX), X10
+	MOVOU	16(AX), X11
+	MOVOU	32(AX), X12
+	MOVOU	48(AX), X13
+	AESENC	X10, X0
+	AESENC	X11, X1
+	AESENC	X12, X2
+	AESENC	X13, X3
+	MOVOU	64(AX), X10
+	MOVOU	80(AX), X11
+	MOVOU	96(AX), X12
+	MOVOU	112(AX), X13
+	AESENC	X10, X4
+	AESENC	X11, X5
+	AESENC	X12, X8
+	AESENC	X13, X9
+
+	// scramble state
+	AESENC	X7, X0
+	AESENC	X7, X1
+	AESENC	X7, X2
+	AESENC	X7, X3
+	AESENC	X7, X4
+	AESENC	X7, X5
+	AESENC	X7, X8
+	AESENC	X7, X9
+
+	ADDQ	$128, AX
+	DECQ	CX
+	JNE	aesloop
+
+	// 2 more scrambles to finish
+	AESENC	X7, X0
+	AESENC	X7, X1
+	AESENC	X7, X2
+	AESENC	X7, X3
+	AESENC	X7, X4
+	AESENC	X7, X5
+	AESENC	X7, X8
+	AESENC	X7, X9
+	AESENC	X7, X0
+	AESENC	X7, X1
+	AESENC	X7, X2
+	AESENC	X7, X3
+	AESENC	X7, X4
+	AESENC	X7, X5
+	AESENC	X7, X8
+	AESENC	X7, X9
+
+	PXOR	X4, X0
+	PXOR	X5, X1
+	PXOR	X8, X2
+	PXOR	X9, X3
+	PXOR	X2, X0
+	PXOR	X3, X1
+	PXOR	X1, X0
+	MOVQ	X0, (DX)
+	RET
+	
+TEXT runtime·aeshash32(SB),NOSPLIT,$0-24
 	MOVQ	p+0(FP), AX	// ptr to data
-	// s+8(FP) is ignored, it is always sizeof(int32)
-	MOVQ	h+16(FP), X0	// seed
+	MOVQ	h+8(FP), X0	// seed
 	PINSRD	$2, (AX), X0	// data
 	AESENC	runtime·aeskeysched+0(SB), X0
 	AESENC	runtime·aeskeysched+16(SB), X0
-	AESENC	runtime·aeskeysched+0(SB), X0
-	MOVQ	X0, ret+24(FP)
+	AESENC	runtime·aeskeysched+32(SB), X0
+	MOVQ	X0, ret+16(FP)
 	RET
 
-TEXT runtime·aeshash64(SB),NOSPLIT,$0-32
+TEXT runtime·aeshash64(SB),NOSPLIT,$0-24
 	MOVQ	p+0(FP), AX	// ptr to data
-	// s+8(FP) is ignored, it is always sizeof(int64)
-	MOVQ	h+16(FP), X0	// seed
+	MOVQ	h+8(FP), X0	// seed
 	PINSRQ	$1, (AX), X0	// data
 	AESENC	runtime·aeskeysched+0(SB), X0
 	AESENC	runtime·aeskeysched+16(SB), X0
-	AESENC	runtime·aeskeysched+0(SB), X0
-	MOVQ	X0, ret+24(FP)
+	AESENC	runtime·aeskeysched+32(SB), X0
+	MOVQ	X0, ret+16(FP)
 	RET
 
 // simple mask to get rid of data in the high part of the register.
@@ -1039,38 +1288,44 @@ TEXT runtime·memeq(SB),NOSPLIT,$0-25
 	MOVQ	a+0(FP), SI
 	MOVQ	b+8(FP), DI
 	MOVQ	size+16(FP), BX
-	CALL	runtime·memeqbody(SB)
-	MOVB	AX, ret+24(FP)
+	LEAQ	ret+24(FP), AX
+	JMP	runtime·memeqbody(SB)
+
+// memequal_varlen(a, b unsafe.Pointer) bool
+TEXT runtime·memequal_varlen(SB),NOSPLIT,$0-17
+	MOVQ	a+0(FP), SI
+	MOVQ	b+8(FP), DI
+	CMPQ	SI, DI
+	JEQ	eq
+	MOVQ	8(DX), BX    // compiler stores size at offset 8 in the closure
+	LEAQ	ret+16(FP), AX
+	JMP	runtime·memeqbody(SB)
+eq:
+	MOVB	$1, 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
-	MOVQ	s1len+8(FP), AX
-	MOVQ	s2len+24(FP), BX
-	CMPQ	AX, BX
-	JNE	different
 	MOVQ	s1str+0(FP), SI
 	MOVQ	s2str+16(FP), DI
 	CMPQ	SI, DI
-	JEQ	same
-	CALL	runtime·memeqbody(SB)
-	MOVB	AX, v+32(FP)
-	RET
-same:
+	JEQ	eq
+	MOVQ	s1len+8(FP), BX
+	LEAQ	v+32(FP), AX
+	JMP	runtime·memeqbody(SB)
+eq:
 	MOVB	$1, v+32(FP)
 	RET
-different:
-	MOVB	$0, v+32(FP)
-	RET
 
 // a in SI
 // b in DI
 // count in BX
+// address of result byte in AX
 TEXT runtime·memeqbody(SB),NOSPLIT,$0-0
-	XORQ	AX, AX
-
 	CMPQ	BX, $8
 	JB	small
 	
@@ -1099,6 +1354,7 @@ hugeloop:
 	SUBQ	$64, BX
 	CMPL	DX, $0xffff
 	JEQ	hugeloop
+	MOVB	$0, (AX)
 	RET
 
 	// 8 bytes at a time using 64-bit register
@@ -1112,6 +1368,7 @@ bigloop:
 	SUBQ	$8, BX
 	CMPQ	CX, DX
 	JEQ	bigloop
+	MOVB	$0, (AX)
 	RET
 
 	// remaining 0-8 bytes
@@ -1119,7 +1376,7 @@ leftover:
 	MOVQ	-8(SI)(BX*1), CX
 	MOVQ	-8(DI)(BX*1), DX
 	CMPQ	CX, DX
-	SETEQ	AX
+	SETEQ	(AX)
 	RET
 
 small:
@@ -1154,7 +1411,7 @@ di_finish:
 	SUBQ	SI, DI
 	SHLQ	CX, DI
 equal:
-	SETEQ	AX
+	SETEQ	(AX)
 	RET
 
 TEXT runtime·cmpstring(SB),NOSPLIT,$0-40
@@ -1162,75 +1419,73 @@ TEXT runtime·cmpstring(SB),NOSPLIT,$0-40
 	MOVQ	s1_len+8(FP), BX
 	MOVQ	s2_base+16(FP), DI
 	MOVQ	s2_len+24(FP), DX
-	CALL	runtime·cmpbody(SB)
-	MOVQ	AX, ret+32(FP)
-	RET
+	LEAQ	ret+32(FP), R9
+	JMP	runtime·cmpbody(SB)
 
-TEXT runtime·cmpbytes(SB),NOSPLIT,$0-56
+TEXT bytes·Compare(SB),NOSPLIT,$0-56
 	MOVQ	s1+0(FP), SI
 	MOVQ	s1+8(FP), BX
 	MOVQ	s2+24(FP), DI
 	MOVQ	s2+32(FP), DX
-	CALL	runtime·cmpbody(SB)
-	MOVQ	AX, res+48(FP)
-	RET
+	LEAQ	res+48(FP), R9
+	JMP	runtime·cmpbody(SB)
 
 // input:
 //   SI = a
 //   DI = b
 //   BX = alen
 //   DX = blen
-// output:
-//   AX = 1/0/-1
+//   R9 = address of output word (stores -1/0/1 here)
 TEXT runtime·cmpbody(SB),NOSPLIT,$0-0
 	CMPQ	SI, DI
-	JEQ	cmp_allsame
+	JEQ	allsame
 	CMPQ	BX, DX
-	MOVQ	DX, BP
-	CMOVQLT	BX, BP // BP = min(alen, blen) = # of bytes to compare
-	CMPQ	BP, $8
-	JB	cmp_small
-
-cmp_loop:
-	CMPQ	BP, $16
-	JBE	cmp_0through16
+	MOVQ	DX, R8
+	CMOVQLT	BX, R8 // R8 = min(alen, blen) = # of bytes to compare
+	CMPQ	R8, $8
+	JB	small
+
+loop:
+	CMPQ	R8, $16
+	JBE	_0through16
 	MOVOU	(SI), X0
 	MOVOU	(DI), X1
 	PCMPEQB X0, X1
 	PMOVMSKB X1, AX
 	XORQ	$0xffff, AX	// convert EQ to NE
-	JNE	cmp_diff16	// branch if at least one byte is not equal
+	JNE	diff16	// branch if at least one byte is not equal
 	ADDQ	$16, SI
 	ADDQ	$16, DI
-	SUBQ	$16, BP
-	JMP	cmp_loop
+	SUBQ	$16, R8
+	JMP	loop
 	
 	// AX = bit mask of differences
-cmp_diff16:
+diff16:
 	BSFQ	AX, BX	// index of first byte that differs
 	XORQ	AX, AX
 	MOVB	(SI)(BX*1), CX
 	CMPB	CX, (DI)(BX*1)
 	SETHI	AX
 	LEAQ	-1(AX*2), AX	// convert 1/0 to +1/-1
+	MOVQ	AX, (R9)
 	RET
 
 	// 0 through 16 bytes left, alen>=8, blen>=8
-cmp_0through16:
-	CMPQ	BP, $8
-	JBE	cmp_0through8
+_0through16:
+	CMPQ	R8, $8
+	JBE	_0through8
 	MOVQ	(SI), AX
 	MOVQ	(DI), CX
 	CMPQ	AX, CX
-	JNE	cmp_diff8
-cmp_0through8:
-	MOVQ	-8(SI)(BP*1), AX
-	MOVQ	-8(DI)(BP*1), CX
+	JNE	diff8
+_0through8:
+	MOVQ	-8(SI)(R8*1), AX
+	MOVQ	-8(DI)(R8*1), CX
 	CMPQ	AX, CX
-	JEQ	cmp_allsame
+	JEQ	allsame
 
 	// AX and CX contain parts of a and b that differ.
-cmp_diff8:
+diff8:
 	BSWAPQ	AX	// reverse order of bytes
 	BSWAPQ	CX
 	XORQ	AX, CX
@@ -1238,82 +1493,82 @@ cmp_diff8:
 	SHRQ	CX, AX	// move a's bit to bottom
 	ANDQ	$1, AX	// mask bit
 	LEAQ	-1(AX*2), AX // 1/0 => +1/-1
+	MOVQ	AX, (R9)
 	RET
 
 	// 0-7 bytes in common
-cmp_small:
-	LEAQ	(BP*8), CX	// bytes left -> bits left
+small:
+	LEAQ	(R8*8), CX	// bytes left -> bits left
 	NEGQ	CX		//  - bits lift (== 64 - bits left mod 64)
-	JEQ	cmp_allsame
+	JEQ	allsame
 
 	// load bytes of a into high bytes of AX
 	CMPB	SI, $0xf8
-	JA	cmp_si_high
+	JA	si_high
 	MOVQ	(SI), SI
-	JMP	cmp_si_finish
-cmp_si_high:
-	MOVQ	-8(SI)(BP*1), SI
+	JMP	si_finish
+si_high:
+	MOVQ	-8(SI)(R8*1), SI
 	SHRQ	CX, SI
-cmp_si_finish:
+si_finish:
 	SHLQ	CX, SI
 
 	// load bytes of b in to high bytes of BX
 	CMPB	DI, $0xf8
-	JA	cmp_di_high
+	JA	di_high
 	MOVQ	(DI), DI
-	JMP	cmp_di_finish
-cmp_di_high:
-	MOVQ	-8(DI)(BP*1), DI
+	JMP	di_finish
+di_high:
+	MOVQ	-8(DI)(R8*1), DI
 	SHRQ	CX, DI
-cmp_di_finish:
+di_finish:
 	SHLQ	CX, DI
 
 	BSWAPQ	SI	// reverse order of bytes
 	BSWAPQ	DI
 	XORQ	SI, DI	// find bit differences
-	JEQ	cmp_allsame
+	JEQ	allsame
 	BSRQ	DI, CX	// index of highest bit difference
 	SHRQ	CX, SI	// move a's bit to bottom
 	ANDQ	$1, SI	// mask bit
 	LEAQ	-1(SI*2), AX // 1/0 => +1/-1
+	MOVQ	AX, (R9)
 	RET
 
-cmp_allsame:
+allsame:
 	XORQ	AX, AX
 	XORQ	CX, CX
 	CMPQ	BX, DX
 	SETGT	AX	// 1 if alen > blen
 	SETEQ	CX	// 1 if alen == blen
 	LEAQ	-1(CX)(AX*2), AX	// 1,0,-1 result
+	MOVQ	AX, (R9)
 	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
-	CALL runtime·indexbytebody(SB)
-	MOVQ AX, ret+32(FP)
-	RET
+	LEAQ ret+32(FP), R8
+	JMP  runtime·indexbytebody(SB)
 
-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
-	CALL runtime·indexbytebody(SB)
-	MOVQ AX, ret+24(FP)
-	RET
+	LEAQ ret+24(FP), R8
+	JMP  runtime·indexbytebody(SB)
 
 // input:
 //   SI: data
 //   BX: data len
 //   AL: byte sought
-// output:
-//   AX
+//   R8: address to put result
 TEXT runtime·indexbytebody(SB),NOSPLIT,$0
 	MOVQ SI, DI
 
 	CMPQ BX, $16
-	JLT indexbyte_small
+	JLT small
 
 	// round up to first 16-byte boundary
 	TESTQ $15, SI
@@ -1367,15 +1622,15 @@ condition:
 	JZ success
 
 failure:
-	MOVQ $-1, AX
+	MOVQ $-1, (R8)
 	RET
 
 // handle for lengths < 16
-indexbyte_small:
+small:
 	MOVQ BX, CX
 	REPN; SCASB
 	JZ success
-	MOVQ $-1, AX
+	MOVQ $-1, (R8)
 	RET
 
 // we've found the chunk containing the byte
@@ -1385,821 +1640,26 @@ ssesuccess:
 	BSFW DX, DX
 	SUBQ SI, DI
 	ADDQ DI, DX
-	MOVQ DX, AX
+	MOVQ DX, (R8)
 	RET
 
 success:
 	SUBQ SI, DI
 	SUBL $1, DI
-	MOVQ DI, AX
+	MOVQ DI, (R8)
 	RET
 
 TEXT bytes·Equal(SB),NOSPLIT,$0-49
 	MOVQ	a_len+8(FP), BX
 	MOVQ	b_len+32(FP), CX
-	XORQ	AX, AX
 	CMPQ	BX, CX
 	JNE	eqret
 	MOVQ	a+0(FP), SI
 	MOVQ	b+24(FP), DI
-	CALL	runtime·memeqbody(SB)
+	LEAQ	ret+48(FP), AX
+	JMP	runtime·memeqbody(SB)
 eqret:
-	MOVB	AX, 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/6g/ggen.c:clearfat.
-// AX: zero
-// DI: ptr to memory to be zeroed
-// DI is updated as a side effect.
-TEXT runtime·duffzero(SB), NOSPLIT, $0-0
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	STOSQ
-	RET
-
-// A Duff's device for copying memory.
-// The compiler jumps to computed addresses within
-// this routine to copy chunks of memory.  Source
-// and destination must not overlap.  Do not
-// change this code without also changing the code
-// in ../../cmd/6g/cgen.c:sgen.
-// SI: ptr to source memory
-// DI: ptr to destination memory
-// SI and DI are updated as a side effect.
-
-// NOTE: this is equivalent to a sequence of MOVSQ but
-// for some reason that is 3.5x slower than this code.
-// The STOSQ above seem fine, though.
-TEXT runtime·duffcopy(SB), NOSPLIT, $0-0
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
-	MOVQ	(SI),CX
-	ADDQ	$8,SI
-	MOVQ	CX,(DI)
-	ADDQ	$8,DI
-
+	MOVB	$0, ret+48(FP)
 	RET
 
 TEXT runtime·fastrand1(SB), NOSPLIT, $0-4
@@ -2235,3 +1695,34 @@ TEXT _cgo_topofstack(SB),NOSPLIT,$0
 TEXT runtime·goexit(SB),NOSPLIT,$0-0
 	BYTE	$0x90	// NOP
 	CALL	runtime·goexit1(SB)	// does not return
+	// traceback from goexit1 must hit code range of goexit
+	BYTE	$0x90	// NOP
+
+TEXT runtime·prefetcht0(SB),NOSPLIT,$0-8
+	MOVQ	addr+0(FP), AX
+	PREFETCHT0	(AX)
+	RET
+
+TEXT runtime·prefetcht1(SB),NOSPLIT,$0-8
+	MOVQ	addr+0(FP), AX
+	PREFETCHT1	(AX)
+	RET
+
+TEXT runtime·prefetcht2(SB),NOSPLIT,$0-8
+	MOVQ	addr+0(FP), AX
+	PREFETCHT2	(AX)
+	RET
+
+TEXT runtime·prefetchnta(SB),NOSPLIT,$0-8
+	MOVQ	addr+0(FP), AX
+	PREFETCHNTA	(AX)
+	RET
+
+// This is called from .init_array and follows the platform, not Go, ABI.
+TEXT runtime·addmoduledata(SB),NOSPLIT,$0-0
+	PUSHQ	R15 // The access to global variables below implicitly uses R15, which is callee-save
+	MOVQ	runtime·lastmoduledatap(SB), AX
+	MOVQ	DI, moduledata_next(AX)
+	MOVQ	DI, runtime·lastmoduledatap(SB)
+	POPQ	R15
+	RET
diff --git a/src/runtime/asm_amd64p32.s b/src/runtime/asm_amd64p32.s
index a1116b5..6e97256 100644
--- a/src/runtime/asm_amd64p32.s
+++ b/src/runtime/asm_amd64p32.s
@@ -2,7 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
 #include "funcdata.h"
 #include "textflag.h"
 
@@ -72,7 +73,7 @@ ok:
 	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)
@@ -83,8 +84,8 @@ ok:
 	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
@@ -164,55 +165,42 @@ TEXT runtime·mcall(SB), NOSPLIT, $0-4
 	JMP	AX
 	RET
 
-// switchtoM is a dummy routine that onM leaves at the bottom
+// 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 M stack because the one at the top of
-// the M stack terminates the stack walk (see topofstack()).
-TEXT runtime·switchtoM(SB), NOSPLIT, $0-0
+// 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
 	RET
 
-// func onM_signalok(fn func())
-TEXT runtime·onM_signalok(SB), NOSPLIT, $0-4
+// func systemstack(fn func())
+TEXT runtime·systemstack(SB), NOSPLIT, $0-4
+	MOVL	fn+0(FP), DI	// DI = fn
 	get_tls(CX)
 	MOVL	g(CX), AX	// AX = g
 	MOVL	g_m(AX), BX	// BX = m
+
 	MOVL	m_gsignal(BX), DX	// DX = gsignal
 	CMPL	AX, DX
-	JEQ	ongsignal
-	JMP	runtime·onM(SB)
-
-ongsignal:
-	MOVL	fn+0(FP), DI	// DI = fn
-	MOVL	DI, DX
-	MOVL	0(DI), DI
-	CALL	DI
-	RET
-
-// func onM(fn func())
-TEXT runtime·onM(SB), NOSPLIT, $0-4
-	MOVL	fn+0(FP), DI	// DI = fn
-	get_tls(CX)
-	MOVL	g(CX), AX	// AX = g
-	MOVL	g_m(AX), BX	// BX = m
+	JEQ	noswitch
 
 	MOVL	m_g0(BX), DX	// DX = g0
 	CMPL	AX, DX
-	JEQ	onm
+	JEQ	noswitch
 
 	MOVL	m_curg(BX), R8
 	CMPL	AX, R8
-	JEQ	oncurg
+	JEQ	switch
 	
 	// Not g0, not curg. Must be gsignal, but that's not allowed.
 	// Hide call from linker nosplit analysis.
-	MOVL	$runtime·badonm(SB), AX
+	MOVL	$runtime·badsystemstack(SB), AX
 	CALL	AX
 
-oncurg:
+switch:
 	// save our state in g->sched.  Pretend to
-	// be switchtoM if the G stack is scanned.
-	MOVL	$runtime·switchtoM(SB), SI
+	// be systemstack_switch if the G stack is scanned.
+	MOVL	$runtime·systemstack_switch(SB), SI
 	MOVL	SI, (g_sched+gobuf_pc)(AX)
 	MOVL	SP, (g_sched+gobuf_sp)(AX)
 	MOVL	AX, (g_sched+gobuf_g)(AX)
@@ -236,7 +224,7 @@ oncurg:
 	MOVL	$0, (g_sched+gobuf_sp)(AX)
 	RET
 
-onm:
+noswitch:
 	// already on m stack, just call directly
 	MOVL	DI, DX
 	MOVL	0(DI), DI
@@ -301,8 +289,25 @@ TEXT runtime·morestack_noctxt(SB),NOSPLIT,$0
 	MOVL	$0, DX
 	JMP	runtime·morestack(SB)
 
+TEXT runtime·stackBarrier(SB),NOSPLIT,$0
+	// We came here via a RET to an overwritten return PC.
+	// AX may be live. Other registers are available.
+
+	// Get the original return PC, g.stkbar[g.stkbarPos].savedLRVal.
+	get_tls(CX)
+	MOVL	g(CX), CX
+	MOVL	(g_stkbar+slice_array)(CX), DX
+	MOVL	g_stkbarPos(CX), BX
+	IMULL	$stkbar__size, BX	// Too big for SIB.
+	ADDL	DX, BX
+	MOVL	stkbar_savedLRVal(BX), BX
+	// Record that this stack barrier was hit.
+	ADDL	$1, g_stkbarPos(CX)
+	// Jump to the original return PC.
+	JMP	BX
+
 // reflectcall: call a function with the given argument list
-// func call(f *FuncVal, arg *byte, argsize, retoffset uint32).
+// 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!
@@ -314,8 +319,11 @@ TEXT runtime·morestack_noctxt(SB),NOSPLIT,$0
 	JMP	AX
 // Note: can't just "JMP NAME(SB)" - bad inlining results.
 
-TEXT ·reflectcall(SB), NOSPLIT, $0-16
-	MOVLQZX argsize+8(FP), CX
+TEXT reflect·call(SB), NOSPLIT, $0-0
+	JMP	·reflectcall(SB)
+
+TEXT ·reflectcall(SB), NOSPLIT, $0-20
+	MOVLQZX argsize+12(FP), CX
 	DISPATCH(runtime·call16, 16)
 	DISPATCH(runtime·call32, 32)
 	DISPATCH(runtime·call64, 64)
@@ -347,26 +355,36 @@ TEXT ·reflectcall(SB), NOSPLIT, $0-16
 	JMP	AX
 
 #define CALLFN(NAME,MAXSIZE)			\
-TEXT NAME(SB), WRAPPER, $MAXSIZE-16;		\
+TEXT NAME(SB), WRAPPER, $MAXSIZE-20;		\
 	NO_LOCAL_POINTERS;			\
 	/* copy arguments to stack */		\
-	MOVL	argptr+4(FP), SI;		\
-	MOVL	argsize+8(FP), CX;		\
+	MOVL	argptr+8(FP), SI;		\
+	MOVL	argsize+12(FP), CX;		\
 	MOVL	SP, DI;				\
 	REP;MOVSB;				\
 	/* call function */			\
-	MOVL	f+0(FP), DX;			\
+	MOVL	f+4(FP), DX;			\
 	MOVL	(DX), AX;			\
 	CALL	AX;				\
 	/* copy return values back */		\
-	MOVL	argptr+4(FP), DI;		\
-	MOVL	argsize+8(FP), CX;		\
-	MOVL	retoffset+12(FP), BX;		\
+	MOVL	argptr+8(FP), DI;		\
+	MOVL	argsize+12(FP), CX;		\
+	MOVL	retoffset+16(FP), BX;		\
 	MOVL	SP, SI;				\
 	ADDL	BX, DI;				\
 	ADDL	BX, SI;				\
 	SUBL	BX, CX;				\
 	REP;MOVSB;				\
+	/* execute write barrier updates */	\
+	MOVL	argtype+0(FP), DX;		\
+	MOVL	argptr+8(FP), DI;		\
+	MOVL	argsize+12(FP), CX;		\
+	MOVL	retoffset+16(FP), BX;		\
+	MOVL	DX, 0(SP);			\
+	MOVL	DI, 4(SP);			\
+	MOVL	CX, 8(SP);			\
+	MOVL	BX, 12(SP);			\
+	CALL	runtime·callwritebarrier(SB);	\
 	RET
 
 CALLFN(·call16, 16)
@@ -410,12 +428,7 @@ TEXT runtime·cas(SB), NOSPLIT, $0-17
 	MOVL	new+8(FP), CX
 	LOCK
 	CMPXCHGL	CX, 0(BX)
-	JZ 4(PC)
-	MOVL	$0, AX
-	MOVB	AX, ret+16(FP)
-	RET
-	MOVL	$1, AX
-	MOVB	AX, ret+16(FP)
+	SETEQ	ret+16(FP)
 	RET
 
 TEXT runtime·casuintptr(SB), NOSPLIT, $0-17
@@ -444,13 +457,7 @@ TEXT runtime·cas64(SB), NOSPLIT, $0-25
 	MOVQ	new+16(FP), CX
 	LOCK
 	CMPXCHGQ	CX, 0(BX)
-	JNZ	cas64_fail
-	MOVL	$1, AX
-	MOVB	AX, ret+24(FP)
-	RET
-cas64_fail:
-	MOVL	$0, AX
-	MOVB	AX, ret+24(FP)
+	SETEQ	ret+24(FP)
 	RET
 
 // bool casp(void **val, void *old, void *new)
@@ -460,18 +467,13 @@ cas64_fail:
 //		return 1;
 //	} else
 //		return 0;
-TEXT runtime·casp(SB), NOSPLIT, $0-17
+TEXT runtime·casp1(SB), NOSPLIT, $0-17
 	MOVL	ptr+0(FP), BX
 	MOVL	old+4(FP), AX
 	MOVL	new+8(FP), CX
 	LOCK
 	CMPXCHGL	CX, 0(BX)
-	JZ 4(PC)
-	MOVL	$0, AX
-	MOVB	AX, ret+16(FP)
-	RET
-	MOVL	$1, AX
-	MOVB	AX, ret+16(FP)
+	SETEQ	ret+16(FP)
 	RET
 
 // uint32 xadd(uint32 volatile *val, int32 delta)
@@ -498,6 +500,9 @@ TEXT runtime·xadd64(SB), NOSPLIT, $0-24
 	MOVQ	AX, ret+16(FP)
 	RET
 
+TEXT runtime·xadduintptr(SB), NOSPLIT, $0-12
+	JMP	runtime·xadd(SB)
+
 TEXT runtime·xchg(SB), NOSPLIT, $0-12
 	MOVL	ptr+0(FP), BX
 	MOVL	new+4(FP), AX
@@ -512,7 +517,7 @@ TEXT runtime·xchg64(SB), NOSPLIT, $0-24
 	MOVQ	AX, ret+16(FP)
 	RET
 
-TEXT runtime·xchgp(SB), NOSPLIT, $0-12
+TEXT runtime·xchgp1(SB), NOSPLIT, $0-12
 	MOVL	ptr+0(FP), BX
 	MOVL	new+4(FP), AX
 	XCHGL	AX, 0(BX)
@@ -530,7 +535,7 @@ again:
 	JNZ	again
 	RET
 
-TEXT runtime·atomicstorep(SB), NOSPLIT, $0-8
+TEXT runtime·atomicstorep1(SB), NOSPLIT, $0-8
 	MOVL	ptr+0(FP), BX
 	MOVL	val+4(FP), AX
 	XCHGL	AX, 0(BX)
@@ -556,6 +561,19 @@ TEXT runtime·atomicor8(SB), NOSPLIT, $0-5
 	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
+
+TEXT ·publicationBarrier(SB),NOSPLIT,$0-0
+	// Stores are already ordered on x86, so this is just a
+	// compile barrier.
+	RET
+
 // void jmpdefer(fn, sp);
 // called from deferreturn.
 // 1. pop the caller
@@ -569,21 +587,21 @@ TEXT runtime·jmpdefer(SB), NOSPLIT, $0-8
 	MOVL	0(DX), BX
 	JMP	BX	// but first run the deferred function
 
-// asmcgocall(void(*fn)(void*), void *arg)
+// func asmcgocall(fn, arg unsafe.Pointer) int32
 // Not implemented.
-TEXT runtime·asmcgocall(SB),NOSPLIT,$0-8
+TEXT runtime·asmcgocall(SB),NOSPLIT,$0-12
 	MOVL	0, AX
 	RET
 
-// asmcgocall(void(*fn)(void*), void *arg)
+// cgocallback(void (*fn)(void*), void *frame, uintptr framesize)
 // Not implemented.
-TEXT runtime·asmcgocall_errno(SB),NOSPLIT,$0-12
+TEXT runtime·cgocallback(SB),NOSPLIT,$0-12
 	MOVL	0, AX
 	RET
 
-// cgocallback(void (*fn)(void*), void *frame, uintptr framesize)
+// cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize)
 // Not implemented.
-TEXT runtime·cgocallback(SB),NOSPLIT,$0-12
+TEXT ·cgocallback_gofunc(SB),NOSPLIT,$0-12
 	MOVL	0, AX
 	RET
 
@@ -620,35 +638,37 @@ TEXT runtime·memclr(SB),NOSPLIT,$0-8
 	STOSB
 	RET
 
-TEXT runtime·getcallerpc(SB),NOSPLIT,$0-12
+TEXT runtime·getcallerpc(SB),NOSPLIT,$8-12
 	MOVL	argp+0(FP),AX		// addr of first arg
 	MOVL	-8(AX),AX		// get calling pc
+	CMPL	AX, runtime·stackBarrierPC(SB)
+	JNE	nobar
+	// Get original return PC.
+	CALL	runtime·nextBarrierPC(SB)
+	MOVL	0(SP), AX
+nobar:
 	MOVL	AX, ret+8(FP)
 	RET
 
-TEXT runtime·gogetcallerpc(SB),NOSPLIT,$0-12
-	MOVL	p+0(FP),AX		// addr of first arg
-	MOVL	-8(AX),AX		// get calling pc
-	MOVL	AX, ret+8(FP)
-	RET
-
-TEXT runtime·setcallerpc(SB),NOSPLIT,$0-8
+TEXT runtime·setcallerpc(SB),NOSPLIT,$8-8
 	MOVL	argp+0(FP),AX		// addr of first arg
 	MOVL	pc+4(FP), BX		// pc to set
+	MOVL	-8(AX), CX
+	CMPL	CX, runtime·stackBarrierPC(SB)
+	JEQ	setbar
 	MOVQ	BX, -8(AX)		// set calling pc
 	RET
+setbar:
+	// Set the stack barrier return PC.
+	MOVL	BX, 0(SP)
+	CALL	runtime·setNextBarrierPC(SB)
+	RET
 
 TEXT runtime·getcallersp(SB),NOSPLIT,$0-12
 	MOVL	argp+0(FP), AX
 	MOVL	AX, ret+8(FP)
 	RET
 
-// func gogetcallersp(p unsafe.Pointer) uintptr
-TEXT runtime·gogetcallersp(SB),NOSPLIT,$0-12
-	MOVL	p+0(FP),AX		// addr of first arg
-	MOVL	AX, ret+8(FP)
-	RET
-
 // int64 runtime·cputicks(void)
 TEXT runtime·cputicks(SB),NOSPLIT,$0-0
 	RDTSC
@@ -657,6 +677,23 @@ TEXT runtime·cputicks(SB),NOSPLIT,$0-0
 	MOVQ	AX, ret+0(FP)
 	RET
 
+// 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,$24-12
+	GO_ARGS
+	NO_LOCAL_POINTERS
+	MOVL	p+0(FP), AX
+	MOVL	h+4(FP), BX
+	MOVL	4(DX), CX
+	MOVL	AX, 0(SP)
+	MOVL	BX, 4(SP)
+	MOVL	CX, 8(SP)
+	CALL	runtime·memhash(SB)
+	MOVL	16(SP), AX
+	MOVL	AX, ret+8(FP)
+	RET
+
 // hash function using AES hardware instructions
 // For now, our one amd64p32 system (NaCl) does not
 // support using AES instructions, so have not bothered to
@@ -687,27 +724,37 @@ TEXT runtime·memeq(SB),NOSPLIT,$0-17
 	MOVB	AX, ret+16(FP)
 	RET
 
+// memequal_varlen(a, b unsafe.Pointer) bool
+TEXT runtime·memequal_varlen(SB),NOSPLIT,$0-9
+	MOVL    a+0(FP), SI
+	MOVL    b+4(FP), DI
+	CMPL    SI, DI
+	JEQ     eq
+	MOVL    4(DX), BX    // compiler stores size at offset 4 in the closure
+	CALL    runtime·memeqbody(SB)
+	MOVB    AX, ret+8(FP)
+	RET
+eq:
+	MOVB    $1, ret+8(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-17
-	MOVL	s1len+4(FP), AX
-	MOVL	s2len+12(FP), BX
-	CMPL	AX, BX
-	JNE	different
 	MOVL	s1str+0(FP), SI
 	MOVL	s2str+8(FP), DI
 	CMPL	SI, DI
 	JEQ	same
+	MOVL	s1len+4(FP), BX
 	CALL	runtime·memeqbody(SB)
 	MOVB	AX, v+16(FP)
 	RET
 same:
 	MOVB	$1, v+16(FP)
 	RET
-different:
-	MOVB	$0, v+16(FP)
-	RET
 
 // a in SI
 // b in DI
@@ -816,13 +863,13 @@ TEXT runtime·cmpstring(SB),NOSPLIT,$0-20
 	MOVL	AX, ret+16(FP)
 	RET
 
-TEXT runtime·cmpbytes(SB),NOSPLIT,$0-28
+TEXT bytes·Compare(SB),NOSPLIT,$0-28
 	MOVL	s1+0(FP), SI
 	MOVL	s1+4(FP), BX
 	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:
@@ -834,29 +881,29 @@ TEXT runtime·cmpbytes(SB),NOSPLIT,$0-28
 //   AX = 1/0/-1
 TEXT runtime·cmpbody(SB),NOSPLIT,$0-0
 	CMPQ	SI, DI
-	JEQ	cmp_allsame
+	JEQ	allsame
 	CMPQ	BX, DX
 	MOVQ	DX, R8
 	CMOVQLT	BX, R8 // R8 = min(alen, blen) = # of bytes to compare
 	CMPQ	R8, $8
-	JB	cmp_small
+	JB	small
 
-cmp_loop:
+loop:
 	CMPQ	R8, $16
-	JBE	cmp_0through16
+	JBE	_0through16
 	MOVOU	(SI), X0
 	MOVOU	(DI), X1
 	PCMPEQB X0, X1
 	PMOVMSKB X1, AX
 	XORQ	$0xffff, AX	// convert EQ to NE
-	JNE	cmp_diff16	// branch if at least one byte is not equal
+	JNE	diff16	// branch if at least one byte is not equal
 	ADDQ	$16, SI
 	ADDQ	$16, DI
 	SUBQ	$16, R8
-	JMP	cmp_loop
+	JMP	loop
 	
 	// AX = bit mask of differences
-cmp_diff16:
+diff16:
 	BSFQ	AX, BX	// index of first byte that differs
 	XORQ	AX, AX
 	ADDQ	BX, SI
@@ -868,23 +915,23 @@ cmp_diff16:
 	RET
 
 	// 0 through 16 bytes left, alen>=8, blen>=8
-cmp_0through16:
+_0through16:
 	CMPQ	R8, $8
-	JBE	cmp_0through8
+	JBE	_0through8
 	MOVQ	(SI), AX
 	MOVQ	(DI), CX
 	CMPQ	AX, CX
-	JNE	cmp_diff8
-cmp_0through8:
+	JNE	diff8
+_0through8:
 	ADDQ	R8, SI
 	ADDQ	R8, DI
 	MOVQ	-8(SI), AX
 	MOVQ	-8(DI), CX
 	CMPQ	AX, CX
-	JEQ	cmp_allsame
+	JEQ	allsame
 
 	// AX and CX contain parts of a and b that differ.
-cmp_diff8:
+diff8:
 	BSWAPQ	AX	// reverse order of bytes
 	BSWAPQ	CX
 	XORQ	AX, CX
@@ -895,46 +942,46 @@ cmp_diff8:
 	RET
 
 	// 0-7 bytes in common
-cmp_small:
+small:
 	LEAQ	(R8*8), CX	// bytes left -> bits left
 	NEGQ	CX		//  - bits lift (== 64 - bits left mod 64)
-	JEQ	cmp_allsame
+	JEQ	allsame
 
 	// load bytes of a into high bytes of AX
 	CMPB	SI, $0xf8
-	JA	cmp_si_high
+	JA	si_high
 	MOVQ	(SI), SI
-	JMP	cmp_si_finish
-cmp_si_high:
+	JMP	si_finish
+si_high:
 	ADDQ	R8, SI
 	MOVQ	-8(SI), SI
 	SHRQ	CX, SI
-cmp_si_finish:
+si_finish:
 	SHLQ	CX, SI
 
 	// load bytes of b in to high bytes of BX
 	CMPB	DI, $0xf8
-	JA	cmp_di_high
+	JA	di_high
 	MOVQ	(DI), DI
-	JMP	cmp_di_finish
-cmp_di_high:
+	JMP	di_finish
+di_high:
 	ADDQ	R8, DI
 	MOVQ	-8(DI), DI
 	SHRQ	CX, DI
-cmp_di_finish:
+di_finish:
 	SHLQ	CX, DI
 
 	BSWAPQ	SI	// reverse order of bytes
 	BSWAPQ	DI
 	XORQ	SI, DI	// find bit differences
-	JEQ	cmp_allsame
+	JEQ	allsame
 	BSRQ	DI, CX	// index of highest bit difference
 	SHRQ	CX, SI	// move a's bit to bottom
 	ANDQ	$1, SI	// mask bit
 	LEAQ	-1(SI*2), AX // 1/0 => +1/-1
 	RET
 
-cmp_allsame:
+allsame:
 	XORQ	AX, AX
 	XORQ	CX, CX
 	CMPQ	BX, DX
@@ -943,7 +990,7 @@ cmp_allsame:
 	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 +998,7 @@ TEXT bytes·IndexByte(SB),NOSPLIT,$0
 	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
@@ -969,7 +1016,7 @@ TEXT runtime·indexbytebody(SB),NOSPLIT,$0
 	MOVL SI, DI
 
 	CMPL BX, $16
-	JLT indexbyte_small
+	JLT small
 
 	// round up to first 16-byte boundary
 	TESTL $15, SI
@@ -1027,7 +1074,7 @@ failure:
 	RET
 
 // handle for lengths < 16
-indexbyte_small:
+small:
 	MOVL BX, CX
 	REPN; SCASB
 	JZ success
@@ -1085,3 +1132,26 @@ TEXT runtime·return0(SB), NOSPLIT, $0
 TEXT runtime·goexit(SB),NOSPLIT,$0-0
 	BYTE	$0x90	// NOP
 	CALL	runtime·goexit1(SB)	// does not return
+	// traceback from goexit1 must hit code range of goexit
+	BYTE	$0x90	// NOP
+
+TEXT runtime·prefetcht0(SB),NOSPLIT,$0-4
+	MOVL	addr+0(FP), AX
+	PREFETCHT0	(AX)
+	RET
+
+TEXT runtime·prefetcht1(SB),NOSPLIT,$0-4
+	MOVL	addr+0(FP), AX
+	PREFETCHT1	(AX)
+	RET
+
+
+TEXT runtime·prefetcht2(SB),NOSPLIT,$0-4
+	MOVL	addr+0(FP), AX
+	PREFETCHT2	(AX)
+	RET
+
+TEXT runtime·prefetchnta(SB),NOSPLIT,$0-4
+	MOVL	addr+0(FP), AX
+	PREFETCHNTA	(AX)
+	RET
diff --git a/src/runtime/asm_arm.s b/src/runtime/asm_arm.s
index 0f3b5ee..9c32e42 100644
--- a/src/runtime/asm_arm.s
+++ b/src/runtime/asm_arm.s
@@ -2,7 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
 #include "funcdata.h"
 #include "textflag.h"
 
@@ -38,27 +39,14 @@ TEXT runtime·rt0_go(SB),NOSPLIT,$-4
 
 	BL	runtime·emptyfunc(SB)	// fault if stack check is wrong
 
-#ifndef GOOS_nacl
-	// if there is an _cgo_init, call it.
-	MOVW	_cgo_init(SB), R4
-	CMP	$0, R4
-	B.EQ	nocgo
-	MRC     15, 0, R0, C13, C0, 3 	// load TLS base pointer
-	MOVW 	R0, R3 			// arg 3: TLS base pointer
-	MOVW 	$runtime·tlsg(SB), R2 	// arg 2: tlsg
-	MOVW	$setg_gcc<>(SB), R1 	// arg 1: setg
-	MOVW	g, R0 			// arg 0: G
-	BL	(R4) // will clobber R0-R3
-#endif
+	BL	runtime·_initcgo(SB)	// will clobber R0-R3
 
-nocgo:
 	// update stackguard after _cgo_init
 	MOVW	(g_stack+stack_lo)(g), R0
-	ADD	$const_StackGuard, R0
+	ADD	$const__StackGuard, R0
 	MOVW	R0, g_stackguard0(g)
 	MOVW	R0, g_stackguard1(g)
 
-	BL	runtime·checkgoarm(SB)
 	BL	runtime·check(SB)
 
 	// saved argc, argv
@@ -67,11 +55,12 @@ nocgo:
 	MOVW	64(R13), R1
 	MOVW	R1, 8(R13)
 	BL	runtime·args(SB)
+	BL	runtime·checkgoarm(SB)
 	BL	runtime·osinit(SB)
 	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)
@@ -87,8 +76,8 @@ nocgo:
 	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,
@@ -117,8 +106,8 @@ TEXT runtime·asminit(SB),NOSPLIT,$0-0
 // void gosave(Gobuf*)
 // save state in Gobuf; setjmp
 TEXT runtime·gosave(SB),NOSPLIT,$-4-4
-	MOVW	0(FP), R0		// gobuf
-	MOVW	SP, gobuf_sp(R0)
+	MOVW	buf+0(FP), R0
+	MOVW	R13, gobuf_sp(R0)
 	MOVW	LR, gobuf_pc(R0)
 	MOVW	g, gobuf_g(R0)
 	MOVW	$0, R11
@@ -130,7 +119,7 @@ TEXT runtime·gosave(SB),NOSPLIT,$-4-4
 // void gogo(Gobuf*)
 // restore state from Gobuf; longjmp
 TEXT runtime·gogo(SB),NOSPLIT,$-4-4
-	MOVW	0(FP), R1		// gobuf
+	MOVW	buf+0(FP), R1
 	MOVW	gobuf_g(R1), R0
 	BL	setg<>(SB)
 
@@ -144,7 +133,7 @@ TEXT runtime·gogo(SB),NOSPLIT,$-4-4
 	// after this point: it must be straight-line code until the
 	// final B instruction.
 	// See large comment in sigprof for more details.
-	MOVW	gobuf_sp(R1), SP	// restore SP
+	MOVW	gobuf_sp(R1), R13	// restore SP==R13
 	MOVW	gobuf_lr(R1), LR
 	MOVW	gobuf_ret(R1), R0
 	MOVW	gobuf_ctxt(R1), R7
@@ -163,7 +152,7 @@ TEXT runtime·gogo(SB),NOSPLIT,$-4-4
 // to keep running g.
 TEXT runtime·mcall(SB),NOSPLIT,$-4-4
 	// Save caller state in g->sched.
-	MOVW	SP, (g_sched+gobuf_sp)(g)
+	MOVW	R13, (g_sched+gobuf_sp)(g)
 	MOVW	LR, (g_sched+gobuf_pc)(g)
 	MOVW	$0, R11
 	MOVW	R11, (g_sched+gobuf_lr)(g)
@@ -181,65 +170,57 @@ TEXT runtime·mcall(SB),NOSPLIT,$-4-4
 	CMP	$0, R11
 	BL.NE	runtime·save_g(SB)
 	MOVW	fn+0(FP), R0
-	MOVW	(g_sched+gobuf_sp)(g), SP
-	SUB	$8, SP
-	MOVW	R1, 4(SP)
+	MOVW	(g_sched+gobuf_sp)(g), R13
+	SUB	$8, R13
+	MOVW	R1, 4(R13)
 	MOVW	R0, R7
 	MOVW	0(R0), R0
 	BL	(R0)
 	B	runtime·badmcall2(SB)
 	RET
 
-// switchtoM is a dummy routine that onM leaves at the bottom
+// 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 M stack because the one at the top of
-// the M stack terminates the stack walk (see topofstack()).
-TEXT runtime·switchtoM(SB),NOSPLIT,$0-0
+// 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
 	MOVW	$0, R0
 	BL	(R0) // clobber lr to ensure push {lr} is kept
 	RET
 
-// func onM_signalok(fn func())
-TEXT runtime·onM_signalok(SB), NOSPLIT, $-4-4
-	MOVW	g_m(g), R1
-	MOVW	m_gsignal(R1), R2
-	CMP	g, R2
-	B.EQ	ongsignal
-	B	runtime·onM(SB)
-
-ongsignal:
-	MOVW	fn+0(FP), R0
-	MOVW	R0, R7
-	MOVW	0(R0), R0
-	BL	(R0)
-	RET
-
-// func onM(fn func())
-TEXT runtime·onM(SB),NOSPLIT,$0-4
+// func systemstack(fn func())
+TEXT runtime·systemstack(SB),NOSPLIT,$0-4
 	MOVW	fn+0(FP), R0	// R0 = fn
 	MOVW	g_m(g), R1	// R1 = m
 
+	MOVW	m_gsignal(R1), R2	// R2 = gsignal
+	CMP	g, R2
+	B.EQ	noswitch
+
 	MOVW	m_g0(R1), R2	// R2 = g0
 	CMP	g, R2
-	B.EQ	onm
+	B.EQ	noswitch
 
 	MOVW	m_curg(R1), R3
 	CMP	g, R3
-	B.EQ	oncurg
+	B.EQ	switch
 
-	// Not g0, not curg. Must be gsignal, but that's not allowed.
+	// Bad: g is not gsignal, not g0, not curg. What is it?
 	// Hide call from linker nosplit analysis.
-	MOVW	$runtime·badonm(SB), R0
+	MOVW	$runtime·badsystemstack(SB), R0
 	BL	(R0)
 
-oncurg:
+switch:
 	// save our state in g->sched.  Pretend to
-	// be switchtoM if the G stack is scanned.
-	MOVW	$runtime·switchtoM(SB), R3
+	// be systemstack_switch if the G stack is scanned.
+	MOVW	$runtime·systemstack_switch(SB), R3
+#ifdef GOOS_nacl
+	ADD	$4, R3, R3 // get past nacl-insert bic instruction
+#endif
 	ADD	$4, R3, R3 // get past push {lr}
 	MOVW	R3, (g_sched+gobuf_pc)(g)
-	MOVW	SP, (g_sched+gobuf_sp)(g)
+	MOVW	R13, (g_sched+gobuf_sp)(g)
 	MOVW	LR, (g_sched+gobuf_lr)(g)
 	MOVW	g, (g_sched+gobuf_g)(g)
 
@@ -249,11 +230,11 @@ oncurg:
 	BL	setg<>(SB)
 	MOVW	R5, R0
 	MOVW	(g_sched+gobuf_sp)(R2), R3
-	// make it look like mstart called onM on g0, to stop traceback
+	// make it look like mstart called systemstack on g0, to stop traceback
 	SUB	$4, R3, R3
 	MOVW	$runtime·mstart(SB), R4
 	MOVW	R4, 0(R3)
-	MOVW	R3, SP
+	MOVW	R3, R13
 
 	// call target function
 	MOVW	R0, R7
@@ -264,12 +245,12 @@ oncurg:
 	MOVW	g_m(g), R1
 	MOVW	m_curg(R1), R0
 	BL	setg<>(SB)
-	MOVW	(g_sched+gobuf_sp)(g), SP
+	MOVW	(g_sched+gobuf_sp)(g), R13
 	MOVW	$0, R3
 	MOVW	R3, (g_sched+gobuf_sp)(g)
 	RET
 
-onm:
+noswitch:
 	MOVW	R0, R7
 	MOVW	0(R0), R0
 	BL	(R0)
@@ -281,7 +262,6 @@ onm:
 
 // Called during function prolog when more stack is needed.
 // R1 frame size
-// R2 arg size
 // R3 prolog's LR
 // NB. we do not save R0 because we've forced 5c to pass all arguments
 // on the stack.
@@ -306,21 +286,21 @@ TEXT runtime·morestack(SB),NOSPLIT,$-4-0
 	// Called from f.
 	// Set g->sched to context in f.
 	MOVW	R7, (g_sched+gobuf_ctxt)(g)
-	MOVW	SP, (g_sched+gobuf_sp)(g)
+	MOVW	R13, (g_sched+gobuf_sp)(g)
 	MOVW	LR, (g_sched+gobuf_pc)(g)
 	MOVW	R3, (g_sched+gobuf_lr)(g)
 
 	// Called from f.
 	// Set m->morebuf to f's caller.
 	MOVW	R3, (m_morebuf+gobuf_pc)(R8)	// f's caller's PC
-	MOVW	SP, (m_morebuf+gobuf_sp)(R8)	// f's caller's SP
-	MOVW	$4(SP), R3			// f's argument pointer
+	MOVW	R13, (m_morebuf+gobuf_sp)(R8)	// f's caller's SP
+	MOVW	$4(R13), R3			// f's argument pointer
 	MOVW	g, (m_morebuf+gobuf_g)(R8)
 
 	// Call newstack on m->g0's stack.
 	MOVW	m_g0(R8), R0
 	BL	setg<>(SB)
-	MOVW	(g_sched+gobuf_sp)(g), SP
+	MOVW	(g_sched+gobuf_sp)(g), R13
 	BL	runtime·newstack(SB)
 
 	// Not reached, but make sure the return PC from the call to newstack
@@ -331,8 +311,25 @@ TEXT runtime·morestack_noctxt(SB),NOSPLIT,$-4-0
 	MOVW	$0, R7
 	B runtime·morestack(SB)
 
+TEXT runtime·stackBarrier(SB),NOSPLIT,$0
+	// We came here via a RET to an overwritten LR.
+	// R0 may be live. Other registers are available.
+
+	// Get the original return PC, g.stkbar[g.stkbarPos].savedLRVal.
+	MOVW	(g_stkbar+slice_array)(g), R4
+	MOVW	g_stkbarPos(g), R5
+	MOVW	$stkbar__size, R6
+	MUL	R5, R6
+	ADD	R4, R6
+	MOVW	stkbar_savedLRVal(R6), R6
+	// Record that this stack barrier was hit.
+	ADD	$1, R5
+	MOVW	R5, g_stkbarPos(g)
+	// Jump to the original return PC.
+	B	(R6)
+
 // reflectcall: call a function with the given argument list
-// func call(f *FuncVal, arg *byte, argsize, retoffset uint32).
+// 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!
@@ -343,8 +340,11 @@ TEXT runtime·morestack_noctxt(SB),NOSPLIT,$-4-0
 	MOVW	$NAME(SB), R1;		\
 	B	(R1)
 
-TEXT ·reflectcall(SB),NOSPLIT,$-4-16
-	MOVW	argsize+8(FP), R0
+TEXT reflect·call(SB), NOSPLIT, $0-0
+	B	·reflectcall(SB)
+
+TEXT ·reflectcall(SB),NOSPLIT,$-4-20
+	MOVW	argsize+12(FP), R0
 	DISPATCH(runtime·call16, 16)
 	DISPATCH(runtime·call32, 32)
 	DISPATCH(runtime·call64, 64)
@@ -376,12 +376,12 @@ TEXT ·reflectcall(SB),NOSPLIT,$-4-16
 	B	(R1)
 
 #define CALLFN(NAME,MAXSIZE)			\
-TEXT NAME(SB), WRAPPER, $MAXSIZE-16;		\
+TEXT NAME(SB), WRAPPER, $MAXSIZE-20;		\
 	NO_LOCAL_POINTERS;			\
 	/* copy arguments to stack */		\
-	MOVW	argptr+4(FP), R0;		\
-	MOVW	argsize+8(FP), R2;		\
-	ADD	$4, SP, R1;			\
+	MOVW	argptr+8(FP), R0;		\
+	MOVW	argsize+12(FP), R2;		\
+	ADD	$4, R13, R1;			\
 	CMP	$0, R2;				\
 	B.EQ	5(PC);				\
 	MOVBU.P	1(R0), R5;			\
@@ -389,24 +389,37 @@ TEXT NAME(SB), WRAPPER, $MAXSIZE-16;		\
 	SUB	$1, R2, R2;			\
 	B	-5(PC);				\
 	/* call function */			\
-	MOVW	f+0(FP), R7;			\
+	MOVW	f+4(FP), R7;			\
 	MOVW	(R7), R0;			\
 	PCDATA  $PCDATA_StackMapIndex, $0;	\
 	BL	(R0);				\
 	/* copy return values back */		\
-	MOVW	argptr+4(FP), R0;		\
-	MOVW	argsize+8(FP), R2;		\
-	MOVW	retoffset+12(FP), R3;		\
-	ADD	$4, SP, R1;			\
+	MOVW	argptr+8(FP), R0;		\
+	MOVW	argsize+12(FP), R2;		\
+	MOVW	retoffset+16(FP), R3;		\
+	ADD	$4, R13, R1;			\
 	ADD	R3, R1;				\
 	ADD	R3, R0;				\
 	SUB	R3, R2;				\
+loop:						\
 	CMP	$0, R2;				\
-	RET.EQ	;				\
+	B.EQ	end;				\
 	MOVBU.P	1(R1), R5;			\
 	MOVBU.P R5, 1(R0);			\
 	SUB	$1, R2, R2;			\
-	B	-5(PC)				\
+	B	loop;				\
+end:						\
+	/* execute write barrier updates */	\
+	MOVW	argtype+0(FP), R1;		\
+	MOVW	argptr+8(FP), R0;		\
+	MOVW	argsize+12(FP), R2;		\
+	MOVW	retoffset+16(FP), R3;		\
+	MOVW	R1, 4(R13);			\
+	MOVW	R0, 8(R13);			\
+	MOVW	R2, 12(R13);			\
+	MOVW	R3, 16(R13);			\
+	BL	runtime·callwritebarrier(SB);	\
+	RET	
 
 CALLFN(·call16, 16)
 CALLFN(·call32, 32)
@@ -446,11 +459,11 @@ CALLFN(·call1073741824, 1073741824)
 // interrupt can never see mismatched SP/LR/PC.
 // (And double-check that pop is atomic in that way.)
 TEXT runtime·jmpdefer(SB),NOSPLIT,$0-8
-	MOVW	0(SP), LR
+	MOVW	0(R13), LR
 	MOVW	$-4(LR), LR	// BL deferreturn
 	MOVW	fv+0(FP), R7
-	MOVW	argp+4(FP), SP
-	MOVW	$-4(SP), SP	// SP is 4 below argp, due to saved LR
+	MOVW	argp+4(FP), R13
+	MOVW	$-4(R13), R13	// SP is 4 below argp, due to saved LR
 	MOVW	0(R7), R1
 	B	(R1)
 
@@ -464,25 +477,14 @@ TEXT gosave<>(SB),NOSPLIT,$0
 	MOVW	R11, (g_sched+gobuf_ctxt)(g)
 	RET
 
-// asmcgocall(void(*fn)(void*), void *arg)
+// func asmcgocall(fn, arg unsafe.Pointer) int32
 // Call fn(arg) on the scheduler stack,
 // aligned appropriately for the gcc ABI.
-// See cgocall.c for more details.
-TEXT	·asmcgocall(SB),NOSPLIT,$0-8
-	MOVW	fn+0(FP), R1
-	MOVW	arg+4(FP), R0
-	BL	asmcgocall<>(SB)
-	RET
-
-TEXT ·asmcgocall_errno(SB),NOSPLIT,$0-12
+// See cgocall.go for more details.
+TEXT ·asmcgocall(SB),NOSPLIT,$0-12
 	MOVW	fn+0(FP), R1
 	MOVW	arg+4(FP), R0
-	BL	asmcgocall<>(SB)
-	MOVW	R0, ret+8(FP)
-	RET
 
-TEXT asmcgocall<>(SB),NOSPLIT,$0-0
-	// fn in R1, arg in R0.
 	MOVW	R13, R2
 	MOVW	g, R4
 
@@ -492,7 +494,7 @@ TEXT asmcgocall<>(SB),NOSPLIT,$0-0
 	MOVW	g_m(g), R8
 	MOVW	m_g0(R8), R3
 	CMP	R3, g
-	BEQ	asmcgocall_g0
+	BEQ	g0
 	BL	gosave<>(SB)
 	MOVW	R0, R5
 	MOVW	R3, R0
@@ -501,7 +503,7 @@ TEXT asmcgocall<>(SB),NOSPLIT,$0-0
 	MOVW	(g_sched+gobuf_sp)(g), R13
 
 	// Now on a scheduling stack (a pthread-created stack).
-asmcgocall_g0:
+g0:
 	SUB	$24, R13
 	BIC	$0x7, R13	// alignment for gcc ABI
 	MOVW	R4, 20(R13) // save old g
@@ -519,6 +521,8 @@ asmcgocall_g0:
 	SUB	R2, R1
 	MOVW	R5, R0
 	MOVW	R1, R13
+
+	MOVW	R0, ret+8(FP)
 	RET
 
 // cgocallback(void (*fn)(void*), void *frame, uintptr framesize)
@@ -536,7 +540,7 @@ TEXT runtime·cgocallback(SB),NOSPLIT,$12-12
 	RET
 
 // cgocallback_gofunc(void (*fn)(void*), void *frame, uintptr framesize)
-// See cgocall.c for more details.
+// See cgocall.go for more details.
 TEXT	·cgocallback_gofunc(SB),NOSPLIT,$8-12
 	NO_LOCAL_POINTERS
 	
@@ -564,7 +568,7 @@ TEXT	·cgocallback_gofunc(SB),NOSPLIT,$8-12
 	// 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 onM will try to use it. If we don't set it here,
+	// 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.
 	MOVW	g_m(g), R8
@@ -651,29 +655,34 @@ TEXT setg<>(SB),NOSPLIT,$-4-0
 	MOVW	g, R0
 	RET
 
-TEXT runtime·getcallerpc(SB),NOSPLIT,$-4-4
-	MOVW	0(SP), R0
+TEXT runtime·getcallerpc(SB),NOSPLIT,$4-8
+	MOVW	8(R13), R0		// LR saved by caller
+	MOVW	runtime·stackBarrierPC(SB), R1
+	CMP	R0, R1
+	BNE	nobar
+	// Get original return PC.
+	BL	runtime·nextBarrierPC(SB)
+	MOVW	4(R13), R0
+nobar:
 	MOVW	R0, ret+4(FP)
 	RET
 
-TEXT runtime·gogetcallerpc(SB),NOSPLIT,$-4-8
-	MOVW	R14, ret+4(FP)
-	RET
-
-TEXT runtime·setcallerpc(SB),NOSPLIT,$-4-8
+TEXT runtime·setcallerpc(SB),NOSPLIT,$4-8
 	MOVW	pc+4(FP), R0
-	MOVW	R0, 0(SP)
+	MOVW	8(R13), R1
+	MOVW	runtime·stackBarrierPC(SB), R2
+	CMP	R1, R2
+	BEQ	setbar
+	MOVW	R0, 8(R13)		// set LR in caller
 	RET
-
-TEXT runtime·getcallersp(SB),NOSPLIT,$-4-4
-	MOVW	0(FP), R0
-	MOVW	$-4(R0), R0
-	MOVW	R0, ret+4(FP)
+setbar:
+	// Set the stack barrier return PC.
+	MOVW	R0, 4(R13)
+	BL	runtime·setNextBarrierPC(SB)
 	RET
 
-// func gogetcallersp(p unsafe.Pointer) uintptr
-TEXT runtime·gogetcallersp(SB),NOSPLIT,$-4-8
-	MOVW	0(FP), R0
+TEXT runtime·getcallersp(SB),NOSPLIT,$-4-8
+	MOVW	argp+0(FP), R0
 	MOVW	$-4(R0), R0
 	MOVW	R0, ret+4(FP)
 	RET
@@ -707,10 +716,22 @@ casl:
 	LDREX	(R1), R0
 	CMP	R0, R2
 	BNE	casfail
+
+	MOVB	runtime·goarm(SB), R11
+	CMP	$7, R11
+	BLT	2(PC)
+	WORD	$0xf57ff05a	// dmb ishst
+
 	STREX	R3, (R1), R0
 	CMP	$0, R0
 	BNE	casl
 	MOVW	$1, R0
+
+	MOVB	runtime·goarm(SB), R11
+	CMP	$7, R11
+	BLT	2(PC)
+	WORD	$0xf57ff05b	// dmb ish
+
 	MOVB	R0, ret+12(FP)
 	RET
 casfail:
@@ -730,6 +751,22 @@ TEXT runtime·atomicloaduint(SB),NOSPLIT,$0-8
 TEXT runtime·atomicstoreuintptr(SB),NOSPLIT,$0-8
 	B	runtime·atomicstore(SB)
 
+// armPublicationBarrier is a native store/store barrier for ARMv7+.
+// On earlier ARM revisions, armPublicationBarrier is a no-op.
+// This will not work on SMP ARMv6 machines, if any are in use.
+// To implement publiationBarrier in sys_$GOOS_arm.s using the native
+// instructions, use:
+//
+//	TEXT ·publicationBarrier(SB),NOSPLIT,$-4-0
+//		B	runtime·armPublicationBarrier(SB)
+//
+TEXT runtime·armPublicationBarrier(SB),NOSPLIT,$-4-0
+	MOVB	runtime·goarm(SB), R11
+	CMP	$7, R11
+	BLT	2(PC)
+	WORD $0xf57ff05e	// DMB ST
+	RET
+
 // AES hashing not implemented for ARM
 TEXT runtime·aeshash(SB),NOSPLIT,$-4-0
 	MOVW	$0, R0
@@ -744,6 +781,23 @@ TEXT runtime·aeshashstr(SB),NOSPLIT,$-4-0
 	MOVW	$0, R0
 	MOVW	(R0), R1
 
+// 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,$16-12
+	GO_ARGS
+	NO_LOCAL_POINTERS
+	MOVW	p+0(FP), R0
+	MOVW	h+4(FP), R1
+	MOVW	4(R7), R2
+	MOVW	R0, 4(R13)
+	MOVW	R1, 8(R13)
+	MOVW	R2, 12(R13)
+	BL	runtime·memhash(SB)
+	MOVW	16(R13), R0
+	MOVW	R0, ret+8(FP)
+	RET
+
 TEXT runtime·memeq(SB),NOSPLIT,$-4-13
 	MOVW	a+0(FP), R1
 	MOVW	b+4(FP), R2
@@ -751,86 +805,149 @@ TEXT runtime·memeq(SB),NOSPLIT,$-4-13
 	ADD	R1, R3, R6
 	MOVW	$1, R0
 	MOVB	R0, ret+12(FP)
-_next2:
+loop:
 	CMP	R1, R6
 	RET.EQ
 	MOVBU.P	1(R1), R4
 	MOVBU.P	1(R2), R5
 	CMP	R4, R5
-	BEQ	_next2
+	BEQ	loop
 
 	MOVW	$0, R0
 	MOVB	R0, ret+12(FP)
 	RET
 
+// memequal_varlen(a, b unsafe.Pointer) bool
+TEXT runtime·memequal_varlen(SB),NOSPLIT,$16-9
+	MOVW	a+0(FP), R0
+	MOVW	b+4(FP), R1
+	CMP	R0, R1
+	BEQ	eq
+	MOVW	4(R7), R2    // compiler stores size at offset 4 in the closure
+	MOVW	R0, 4(R13)
+	MOVW	R1, 8(R13)
+	MOVW	R2, 12(R13)
+	BL	runtime·memeq(SB)
+	MOVB	16(R13), R0
+	MOVB	R0, ret+8(FP)
+	RET
+eq:
+	MOVW	$1, R0
+	MOVB	R0, ret+8(FP)
+	RET
+
+TEXT runtime·cmpstring(SB),NOSPLIT,$-4-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
+	ADD	$20, R13, R7
+	B	runtime·cmpbody(SB)
+
+TEXT bytes·Compare(SB),NOSPLIT,$-4-28
+	MOVW	s1+0(FP), R2
+	MOVW	s1+4(FP), R0
+	MOVW	s2+12(FP), R3
+	MOVW	s2+16(FP), R1
+	ADD	$28, R13, R7
+	B	runtime·cmpbody(SB)
+
+// 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
+// R7 points to return value (-1/0/1 will be written here)
+//
+// On exit:
+// R4, R5, 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, R0
+	MOVW.GT	$-1, R0
+	MOVW	R0, (R7)
+	RET
+samebytes:
+	CMP	R0, R1
+	MOVW.LT	$1, R0
+	MOVW.GT	$-1, R0
+	MOVW.EQ	$0, R0
+	MOVW	R0, (R7)
+	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,$-4-17
-	MOVW	s1len+4(FP), R0
-	MOVW	s2len+12(FP), R1
-	MOVW	$0, R7
-	CMP	R0, R1
-	MOVB.NE R7, v+16(FP)
-	RET.NE
 	MOVW	s1str+0(FP), R2
 	MOVW	s2str+8(FP), R3
 	MOVW	$1, R8
 	MOVB	R8, v+16(FP)
 	CMP	R2, R3
 	RET.EQ
+	MOVW	s1len+4(FP), R0
 	ADD	R2, R0, R6
-_eqnext:
+loop:
 	CMP	R2, R6
 	RET.EQ
 	MOVBU.P	1(R2), R4
 	MOVBU.P	1(R3), R5
 	CMP	R4, R5
-	BEQ	_eqnext
-	MOVB	R7, v+16(FP)
+	BEQ	loop
+	MOVW	$0, R8
+	MOVB	R8, v+16(FP)
 	RET
 
-// void setg_gcc(G*); set g called from gcc.
-TEXT setg_gcc<>(SB),NOSPLIT,$0
-	MOVW	R0, g
-	B		runtime·save_g(SB)
-
 // 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
 	
 	CMP	R1, R3		// unequal lengths are not equal
-	B.NE	_notequal
+	B.NE	notequal
 
 	MOVW	a+0(FP), R0
 	MOVW	b+12(FP), R2
 	ADD	R0, R1		// end
 
-_byteseq_next:
+loop:
 	CMP	R0, R1
-	B.EQ	_equal		// reached the end
+	B.EQ	equal		// reached the end
 	MOVBU.P	1(R0), R4
 	MOVBU.P	1(R2), R5
 	CMP	R4, R5
-	B.EQ	_byteseq_next
+	B.EQ	loop
 
-_notequal:
+notequal:
 	MOVW	$0, R0
 	MOVBU	R0, ret+24(FP)
 	RET
 
-_equal:
+equal:
 	MOVW	$1, R0
 	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
@@ -841,7 +958,7 @@ _loop:
 
 	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:
@@ -849,12 +966,12 @@ _notfound:
 	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
@@ -865,7 +982,7 @@ _sib_loop:
 
 	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:
@@ -873,414 +990,6 @@ _sib_notfound:
 	MOVW	R0, ret+12(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/5g/ggen.c:clearfat.
-// R0: zero
-// R1: ptr to memory to be zeroed
-// R1 is updated as a side effect.
-TEXT runtime·duffzero(SB),NOSPLIT,$0-0
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	MOVW.P	R0, 4(R1)
-	RET
-
-// A Duff's device for copying memory.
-// The compiler jumps to computed addresses within
-// this routine to copy chunks of memory.  Source
-// and destination must not overlap.  Do not
-// change this code without also changing the code
-// in ../../cmd/5g/cgen.c:sgen.
-// R0: scratch space
-// R1: ptr to source memory
-// R2: ptr to destination memory
-// R1 and R2 are updated as a side effect
-TEXT runtime·duffcopy(SB),NOSPLIT,$0-0
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	MOVW.P	4(R1), R0
-	MOVW.P	R0, 4(R2)
-	RET
-
 TEXT runtime·fastrand1(SB),NOSPLIT,$-4-4
 	MOVW	g_m(g), R1
 	MOVW	m_fastrand(R1), R0
@@ -1326,3 +1035,38 @@ TEXT _cgo_topofstack(SB),NOSPLIT,$8
 TEXT runtime·goexit(SB),NOSPLIT,$-4-0
 	MOVW	R0, R0	// NOP
 	BL	runtime·goexit1(SB)	// does not return
+	// traceback from goexit1 must hit code range of goexit
+	MOVW	R0, R0	// NOP
+
+TEXT runtime·prefetcht0(SB),NOSPLIT,$0-4
+	RET
+
+TEXT runtime·prefetcht1(SB),NOSPLIT,$0-4
+	RET
+
+TEXT runtime·prefetcht2(SB),NOSPLIT,$0-4
+	RET
+
+TEXT runtime·prefetchnta(SB),NOSPLIT,$0-4
+	RET
+
+// x -> x/1000000, x%1000000, called from Go with args, results on stack.
+TEXT runtime·usplit(SB),NOSPLIT,$0-12
+	MOVW	x+0(FP), R0
+	CALL	runtime·usplitR0(SB)
+	MOVW	R0, q+4(FP)
+	MOVW	R1, r+8(FP)
+	RET
+
+// R0, R1 = R0/1000000, R0%1000000
+TEXT runtime·usplitR0(SB),NOSPLIT,$0
+	// magic multiply to avoid software divide without available m.
+	// see output of go tool compile -S for x/1000000.
+	MOVW	R0, R3
+	MOVW	$1125899907, R1
+	MULLU	R1, R0, (R0, R1)
+	MOVW	R0>>18, R0
+	MOVW	$1000000, R1
+	MULU	R0, R1
+	SUB	R1, R3, R1
+	RET
diff --git a/src/runtime/asm_arm64.s b/src/runtime/asm_arm64.s
new file mode 100644
index 0000000..9aff9c7
--- /dev/null
+++ b/src/runtime/asm_arm64.s
@@ -0,0 +1,1029 @@
+// 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 "tls_arm64.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
+
+	MRS_TPIDR_R0			// load TLS base pointer
+	MOVD	R0, R3			// arg 3: TLS base pointer
+#ifdef TLSG_IS_VARIABLE
+	MOVD	$runtime·tls_g(SB), R2 	// arg 2: tlsg
+#else
+	MOVD	$0x10, R2		// arg 2: tlsg TODO(minux): hardcoded for linux
+#endif
+	MOVD	$setg_gcc<>(SB), R1	// arg 1: setg
+	MOVD	g, R0			// arg 0: G
+	BL	(R12)
+	MOVD	_cgo_init(SB), R12
+	CMP	$0, R12
+	BEQ	nocgo
+
+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)
+
+TEXT runtime·stackBarrier(SB),NOSPLIT,$0
+	// We came here via a RET to an overwritten LR.
+	// R0 may be live (see return0). Other registers are available.
+
+	// Get the original return PC, g.stkbar[g.stkbarPos].savedLRVal.
+	MOVD	(g_stkbar+slice_array)(g), R4
+	MOVD	g_stkbarPos(g), R5
+	MOVD	$stkbar__size, R6
+	MUL	R5, R6
+	ADD	R4, R6
+	MOVD	stkbar_savedLRVal(R6), R6
+	// Record that this stack barrier was hit.
+	ADD	$1, R5
+	MOVD	R5, g_stkbarPos(g)
+	// Jump to the original return PC.
+	B	(R6)
+
+// 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
+
+// These have 8 added to make the overall frame size a multiple of 16,
+// as required by the ABI. (There is another +8 for the saved LR.)
+CALLFN(·call16, 24 )
+CALLFN(·call32, 40 )
+CALLFN(·call64, 72 )
+CALLFN(·call128, 136 )
+CALLFN(·call256, 264 )
+CALLFN(·call512, 520 )
+CALLFN(·call1024, 1032 )
+CALLFN(·call2048, 2056 )
+CALLFN(·call4096, 4104 )
+CALLFN(·call8192, 8200 )
+CALLFN(·call16384, 16392 )
+CALLFN(·call32768, 32776 )
+CALLFN(·call65536, 65544 )
+CALLFN(·call131072, 131080 )
+CALLFN(·call262144, 262152 )
+CALLFN(·call524288, 524296 )
+CALLFN(·call1048576, 1048584 )
+CALLFN(·call2097152, 2097160 )
+CALLFN(·call4194304, 4194312 )
+CALLFN(·call8388608, 8388616 )
+CALLFN(·call16777216, 16777224 )
+CALLFN(·call33554432, 33554440 )
+CALLFN(·call67108864, 67108872 )
+CALLFN(·call134217728, 134217736 )
+CALLFN(·call268435456, 268435464 )
+CALLFN(·call536870912, 536870920 )
+CALLFN(·call1073741824, 1073741832 )
+
+// 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)
+
+// AES hashing not implemented for ARM64, issue #10109.
+TEXT runtime·aeshash(SB),NOSPLIT,$-8-0
+	MOVW	$0, R0
+	MOVW	(R0), R1
+TEXT runtime·aeshash32(SB),NOSPLIT,$-8-0
+	MOVW	$0, R0
+	MOVW	(R0), R1
+TEXT runtime·aeshash64(SB),NOSPLIT,$-8-0
+	MOVW	$0, R0
+	MOVW	(R0), R1
+TEXT runtime·aeshashstr(SB),NOSPLIT,$-8-0
+	MOVW	$0, R0
+	MOVW	(R0), R1
+
+// 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
+
+// func asmcgocall(fn, arg unsafe.Pointer) int32
+// Call fn(arg) on the scheduler stack,
+// aligned appropriately for the gcc ABI.
+// See cgocall.go for more details.
+TEXT ·asmcgocall(SB),NOSPLIT,$0-20
+	MOVD	fn+0(FP), R1
+	MOVD	arg+8(FP), R0
+
+	MOVD	RSP, R2		// save original stack pointer
+	MOVD	g, R4
+
+	// 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), R8
+	MOVD	m_g0(R8), R3
+	CMP	R3, g
+	BEQ	g0
+	MOVD	R0, R9	// gosave<> and save_g might clobber R0
+	BL	gosave<>(SB)
+	MOVD	R3, g
+	BL	runtime·save_g(SB)
+	MOVD	(g_sched+gobuf_sp)(g), R0
+	MOVD	R0, RSP
+	MOVD	R9, R0
+
+	// 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	$16, R13
+	MOVD	R13, RSP
+	MOVD	R4, 0(RSP)	// save old g on stack
+	MOVD	(g_stack+stack_hi)(R4), R4
+	SUB	R2, R4
+	MOVD	R4, 8(RSP)	// save depth in old g stack (can't just save SP, as stack might be copied during a callback)
+	BL	(R1)
+	MOVD	R0, R9
+
+	// Restore g, stack pointer.  R0 is errno, so don't touch it
+	MOVD	0(RSP), g
+	BL	runtime·save_g(SB)
+	MOVD	(g_stack+stack_hi)(g), R5
+	MOVD	8(RSP), R6
+	SUB	R6, R5
+	MOVD	R9, R0
+	MOVD	R5, RSP
+
+	MOVW	R0, ret+16(FP)
+	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), R0
+	MOVD	R0, 8(RSP)
+	MOVD	frame+8(FP), R0
+	MOVD	R0, 16(RSP)
+	MOVD	framesize+16(FP), R0
+	MOVD	R0, 24(RSP)
+	MOVD	$runtime·cgocallback_gofunc(SB), R0
+	BL	(R0)
+	RET
+
+// cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize)
+// See cgocall.go for more details.
+TEXT ·cgocallback_gofunc(SB),NOSPLIT,$24-24
+	NO_LOCAL_POINTERS
+
+	// Load g from thread-local storage.
+	MOVB	runtime·iscgo(SB), R3
+	CMP	$0, R3
+	BEQ	nocgo
+	BL	runtime·load_g(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), R0
+	BL	(R0)
+
+	// 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), R8
+	MOVD	m_g0(R8), 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 16(RSP) aka savedsp-16(SP).
+	// Beware that the frame size is actually 32.
+	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+8)(R4)	// maintain 16-byte SP alignment
+	MOVD	$-(24+8)(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	RSP, R4
+	ADD	$(24+8), R4, 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), R0
+	BL	(R0)
+droppedm:
+
+	// Done!
+	RET
+
+// Called from cgo wrappers, this function returns g->m->curg.stack.hi.
+// Must obey the gcc calling convention.
+TEXT _cgo_topofstack(SB),NOSPLIT,$24
+	// g (R28) and REGTMP (R27)  might be clobbered by load_g. They
+	// are callee-save in the gcc calling convention, so save them.
+	MOVD	R27, savedR27-8(SP)
+	MOVD	g, saveG-16(SP)
+
+	BL	runtime·load_g(SB)
+	MOVD	g_m(g), R0
+	MOVD	m_curg(R0), R0
+	MOVD	(g_stack+stack_hi)(R0), R0
+
+	MOVD	saveG-16(SP), g
+	MOVD	savedR28-8(SP), R27
+	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
+
+// void setg_gcc(G*); set g called from gcc
+TEXT setg_gcc<>(SB),NOSPLIT,$8
+	MOVD	R0, g
+	MOVD	R27, savedR27-8(SP)
+	BL	runtime·save_g(SB)
+	MOVD	savedR27-8(SP), R27
+	RET
+
+TEXT runtime·getcallerpc(SB),NOSPLIT,$8-16
+	MOVD	16(RSP), R0		// LR saved by caller
+	MOVD	runtime·stackBarrierPC(SB), R1
+	CMP	R0, R1
+	BNE	nobar
+	// Get original return PC.
+	BL	runtime·nextBarrierPC(SB)
+	MOVD	8(RSP), R0
+nobar:
+	MOVD	R0, ret+8(FP)
+	RET
+
+TEXT runtime·setcallerpc(SB),NOSPLIT,$8-16
+	MOVD	pc+8(FP), R0
+	MOVD	16(RSP), R1
+	MOVD	runtime·stackBarrierPC(SB), R2
+	CMP	R1, R2
+	BEQ	setbar
+	MOVD	R0, 16(RSP)		// set LR in caller
+	RET
+setbar:
+	// Set the stack barrier return PC.
+	MOVD	R0, 8(RSP)
+	BL	runtime·setNextBarrierPC(SB)
+	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
+
+TEXT runtime·cmpstring(SB),NOSPLIT,$-4-40
+	MOVD	s1_base+0(FP), R2
+	MOVD	s1_len+8(FP), R0
+	MOVD	s2_base+16(FP), R3
+	MOVD	s2_len+24(FP), R1
+	ADD	$40, RSP, R7
+	B	runtime·cmpbody<>(SB)
+
+TEXT bytes·Compare(SB),NOSPLIT,$-4-56
+	MOVD	s1+0(FP), R2
+	MOVD	s1+8(FP), R0
+	MOVD	s2+24(FP), R3
+	MOVD	s2+32(FP), R1
+	ADD	$56, RSP, R7
+	B	runtime·cmpbody<>(SB)
+
+// 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
+// R7 points to return value (-1/0/1 will be written here)
+//
+// On exit:
+// R4, R5, and R6 are clobbered
+TEXT runtime·cmpbody<>(SB),NOSPLIT,$-4-0
+	CMP	R0, R1
+	CSEL    LT, R1, R0, 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
+	MOVD	$1, R4
+	CSNEG	LT, R4, R4, R4
+	MOVD	R4, (R7)
+	RET
+samebytes:
+	MOVD	$1, R4
+	CMP	R0, R1
+	CSNEG	LT, R4, R4, R4
+	CSEL	EQ, ZR, R4, R4
+	MOVD	R4, (R7)
+	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
+
+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
+
+// 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
new file mode 100644
index 0000000..0404124
--- /dev/null
+++ b/src/runtime/asm_ppc64x.s
@@ -0,0 +1,1172 @@
+// 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 ppc64 ppc64le
+
+#include "go_asm.h"
+#include "go_tls.h"
+#include "funcdata.h"
+#include "textflag.h"
+
+TEXT runtime·rt0_go(SB),NOSPLIT,$0
+	// R1 = stack; R3 = argc; R4 = argv; R13 = C TLS base pointer
+
+	// initialize essential registers
+	BL	runtime·reginit(SB)
+
+	SUB	$24, R1
+	MOVW	R3, 8(R1) // argc
+	MOVD	R4, 16(R1) // argv
+
+	// create istack out of the given (operating system) stack.
+	// _cgo_init may update stackguard.
+	MOVD	$runtime·g0(SB), g
+	MOVD	$(-64*1024), R31
+	ADD	R31, R1, R3
+	MOVD	R3, g_stackguard0(g)
+	MOVD	R3, g_stackguard1(g)
+	MOVD	R3, (g_stack+stack_lo)(g)
+	MOVD	R1, (g_stack+stack_hi)(g)
+
+	// if there is a _cgo_init, call it using the gcc ABI.
+	MOVD	_cgo_init(SB), R12
+	CMP	R0, R12
+	BEQ	nocgo
+	MOVD	R12, CTR		// r12 = "global function entry point"
+	MOVD	R13, R5			// arg 2: TLS base pointer
+	MOVD	$setg_gcc<>(SB), R4 	// arg 1: setg
+	MOVD	g, R3			// arg 0: G
+	// C functions expect 32 bytes of space on caller stack frame
+	// and a 16-byte aligned R1
+	MOVD	R1, R14			// save current stack
+	SUB	$32, R1			// reserve 32 bytes
+	RLDCR	$0, R1, $~15, R1	// 16-byte align
+	BL	(CTR)			// may clobber R0, R3-R12
+	MOVD	R14, R1			// restore stack
+	XOR	R0, R0			// fix R0
+
+nocgo:
+	// update stackguard after _cgo_init
+	MOVD	(g_stack+stack_lo)(g), R3
+	ADD	$const__StackGuard, R3
+	MOVD	R3, g_stackguard0(g)
+	MOVD	R3, g_stackguard1(g)
+
+	// set the per-goroutine and per-mach "registers"
+	MOVD	$runtime·m0(SB), R3
+
+	// save m->g0 = g0
+	MOVD	g, m_g0(R3)
+	// save m0 to g0->m
+	MOVD	R3, g_m(g)
+
+	BL	runtime·check(SB)
+
+	// args are already prepared
+	BL	runtime·args(SB)
+	BL	runtime·osinit(SB)
+	BL	runtime·schedinit(SB)
+
+	// create a new goroutine to start program
+	MOVD	$runtime·mainPC(SB), R3		// entry
+	MOVDU	R3, -8(R1)
+	MOVDU	R0, -8(R1)
+	MOVDU	R0, -8(R1)
+	BL	runtime·newproc(SB)
+	ADD	$24, R1
+
+	// start this M
+	BL	runtime·mstart(SB)
+
+	MOVD	R0, 1(R0)
+	RET
+
+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
+	RET
+
+TEXT runtime·asminit(SB),NOSPLIT,$-8-0
+	RET
+
+TEXT _cgo_reginit(SB),NOSPLIT,$-8-0
+	// crosscall_ppc64 and crosscall2 need to reginit, but can't
+	// get at the 'runtime.reginit' symbol.
+	BR	runtime·reginit(SB)
+
+TEXT runtime·reginit(SB),NOSPLIT,$-8-0
+	// set R0 to zero, it's expected by the toolchain
+	XOR R0, R0
+	// initialize essential FP registers
+	FMOVD	$4503601774854144.0, F27
+	FMOVD	$0.5, F29
+	FSUB	F29, F29, F28
+	FADD	F29, F29, F30
+	FADD	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	R1, gobuf_sp(R3)
+	MOVD	LR, R31
+	MOVD	R31, gobuf_pc(R3)
+	MOVD	g, gobuf_g(R3)
+	MOVD	R0, gobuf_lr(R3)
+	MOVD	R0, gobuf_ret(R3)
+	MOVD	R0, 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	// make sure g is not nil
+	BL	runtime·save_g(SB)
+
+	MOVD	0(g), R4
+	MOVD	gobuf_sp(R5), R1
+	MOVD	gobuf_lr(R5), R31
+	MOVD	R31, LR
+	MOVD	gobuf_ret(R5), R3
+	MOVD	gobuf_ctxt(R5), R11
+	MOVD	R0, gobuf_sp(R5)
+	MOVD	R0, gobuf_ret(R5)
+	MOVD	R0, gobuf_lr(R5)
+	MOVD	R0, gobuf_ctxt(R5)
+	CMP	R0, R0 // set condition codes for == test, needed by stack split
+	MOVD	gobuf_pc(R5), R31
+	MOVD	R31, CTR
+	BR	(CTR)
+
+// 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	R1, (g_sched+gobuf_sp)(g)
+	MOVD	LR, R31
+	MOVD	R31, (g_sched+gobuf_pc)(g)
+	MOVD	R0, (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)
+	BR	runtime·badmcall(SB)
+	MOVD	fn+0(FP), R11			// context
+	MOVD	0(R11), R4			// code pointer
+	MOVD	R4, CTR
+	MOVD	(g_sched+gobuf_sp)(g), R1	// sp = m->g0->sched.sp
+	MOVDU	R3, -8(R1)
+	MOVDU	R0, -8(R1)
+	BL	(CTR)
+	BR	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, R11		// 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
+	MOVD	R3, CTR
+	BL	(CTR)
+
+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	R1, (g_sched+gobuf_sp)(g)
+	MOVD	R0, (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	$8, R3
+	MOVD	$runtime·mstart(SB), R4
+	MOVD	R4, 0(R3)
+	MOVD	R3, R1
+
+	// call target function
+	MOVD	0(R11), R3	// code pointer
+	MOVD	R3, CTR
+	BL	(CTR)
+
+	// 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), R1
+	MOVD	R0, (g_sched+gobuf_sp)(g)
+	RET
+
+noswitch:
+	// already on m stack, just call directly
+	MOVD	0(R11), R3	// code pointer
+	MOVD	R3, CTR
+	BL	(CTR)
+	RET
+
+/*
+ * support for morestack
+ */
+
+// Called during function prolog when more stack is needed.
+// Caller has already loaded:
+// R3: framesize, R4: argsize, R5: LR
+//
+// 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), R7
+	MOVD	m_g0(R7), R8
+	CMP	g, R8
+	BNE	2(PC)
+	BL	runtime·abort(SB)
+
+	// Cannot grow signal stack (m->gsignal).
+	MOVD	m_gsignal(R7), R8
+	CMP	g, R8
+	BNE	2(PC)
+	BL	runtime·abort(SB)
+
+	// Called from f.
+	// Set g->sched to context in f.
+	MOVD	R11, (g_sched+gobuf_ctxt)(g)
+	MOVD	R1, (g_sched+gobuf_sp)(g)
+	MOVD	LR, R8
+	MOVD	R8, (g_sched+gobuf_pc)(g)
+	MOVD	R5, (g_sched+gobuf_lr)(g)
+
+	// Called from f.
+	// Set m->morebuf to f's caller.
+	MOVD	R5, (m_morebuf+gobuf_pc)(R7)	// f's caller's PC
+	MOVD	R1, (m_morebuf+gobuf_sp)(R7)	// f's caller's SP
+	MOVD	g, (m_morebuf+gobuf_g)(R7)
+
+	// Call newstack on m->g0's stack.
+	MOVD	m_g0(R7), g
+	BL	runtime·save_g(SB)
+	MOVD	(g_sched+gobuf_sp)(g), R1
+	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,$-8-0
+	MOVD	R0, R11
+	BR	runtime·morestack(SB)
+
+TEXT runtime·stackBarrier(SB),NOSPLIT,$0
+	// We came here via a RET to an overwritten LR.
+	// R3 may be live. Other registers are available.
+
+	// Get the original return PC, g.stkbar[g.stkbarPos].savedLRVal.
+	MOVD	(g_stkbar+slice_array)(g), R4
+	MOVD	g_stkbarPos(g), R5
+	MOVD	$stkbar__size, R6
+	MULLD	R5, R6
+	ADD	R4, R6
+	MOVD	stkbar_savedLRVal(R6), R6
+	// Record that this stack barrier was hit.
+	ADD	$1, R5
+	MOVD	R5, g_stkbarPos(g)
+	// Jump to the original return PC.
+	MOVD	R6, CTR
+	BR	(CTR)
+
+// 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, R31;		\
+	CMP	R3, R31;		\
+	BGT	4(PC);			\
+	MOVD	$NAME(SB), R31;	\
+	MOVD	R31, CTR;		\
+	BR	(CTR)
+// Note: can't just "BR NAME(SB)" - bad inlining results.
+
+TEXT reflect·call(SB), NOSPLIT, $0-0
+	BR	·reflectcall(SB)
+
+TEXT ·reflectcall(SB), NOSPLIT, $-8-32
+	MOVWZ argsize+24(FP), R3
+	// 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), R31
+	MOVD	R31, CTR
+	BR	(CTR)
+
+#define CALLFN(NAME,MAXSIZE)			\
+TEXT NAME(SB), WRAPPER, $MAXSIZE-24;		\
+	NO_LOCAL_POINTERS;			\
+	/* copy arguments to stack */		\
+	MOVD	arg+16(FP), R3;			\
+	MOVWZ	argsize+24(FP), R4;			\
+	MOVD	R1, R5;				\
+	ADD	$(8-1), R5;			\
+	SUB	$1, R3;				\
+	ADD	R5, R4;				\
+	CMP	R5, R4;				\
+	BEQ	4(PC);				\
+	MOVBZU	1(R3), R6;			\
+	MOVBZU	R6, 1(R5);			\
+	BR	-4(PC);				\
+	/* call function */			\
+	MOVD	f+8(FP), R11;			\
+	MOVD	(R11), R31;			\
+	MOVD	R31, CTR;			\
+	PCDATA  $PCDATA_StackMapIndex, $0;	\
+	BL	(CTR);				\
+	/* copy return values back */		\
+	MOVD	arg+16(FP), R3;			\
+	MOVWZ	n+24(FP), R4;			\
+	MOVWZ	retoffset+28(FP), R6;		\
+	MOVD	R1, 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;				\
+	MOVBZU	1(R5), R6;			\
+	MOVBZU	R6, 1(R3);			\
+	BR	loop;				\
+end:						\
+	/* execute write barrier updates */	\
+	MOVD	argtype+0(FP), R7;		\
+	MOVD	arg+16(FP), R3;			\
+	MOVWZ	n+24(FP), R4;			\
+	MOVWZ	retoffset+28(FP), R6;		\
+	MOVD	R7, 8(R1);			\
+	MOVD	R3, 16(R1);			\
+	MOVD	R4, 24(R1);			\
+	MOVD	R6, 32(R1);			\
+	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), R3
+	MOVWZ	old+8(FP), R4
+	MOVWZ	new+12(FP), R5
+cas_again:
+	SYNC
+	LWAR	(R3), R6
+	CMPW	R6, R4
+	BNE	cas_fail
+	STWCCC	R5, (R3)
+	BNE	cas_again
+	MOVD	$1, R3
+	SYNC
+	ISYNC
+	MOVB	R3, ret+16(FP)
+	RET
+cas_fail:
+	MOVD	$0, R3
+	BR	-5(PC)
+
+// 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), R3
+	MOVD	old+8(FP), R4
+	MOVD	new+16(FP), R5
+cas64_again:
+	SYNC
+	LDAR	(R3), R6
+	CMP	R6, R4
+	BNE	cas64_fail
+	STDCCC	R5, (R3)
+	BNE	cas64_again
+	MOVD	$1, R3
+	SYNC
+	ISYNC
+	MOVB	R3, ret+24(FP)
+	RET
+cas64_fail:
+	MOVD	$0, R3
+	BR	-5(PC)
+
+TEXT runtime·casuintptr(SB), NOSPLIT, $0-25
+	BR	runtime·cas64(SB)
+
+TEXT runtime·atomicloaduintptr(SB), NOSPLIT, $-8-16
+	BR	runtime·atomicload64(SB)
+
+TEXT runtime·atomicloaduint(SB), NOSPLIT, $-8-16
+	BR	runtime·atomicload64(SB)
+
+TEXT runtime·atomicstoreuintptr(SB), NOSPLIT, $0-16
+	BR	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
+	BR runtime·cas64(SB)
+
+// uint32 xadd(uint32 volatile *ptr, int32 delta)
+// Atomically:
+//	*val += delta;
+//	return *val;
+TEXT runtime·xadd(SB), NOSPLIT, $0-20
+	MOVD	ptr+0(FP), R4
+	MOVW	delta+8(FP), R5
+	SYNC
+	LWAR	(R4), R3
+	ADD	R5, R3
+	STWCCC	R3, (R4)
+	BNE	-4(PC)
+	SYNC
+	ISYNC
+	MOVW	R3, ret+16(FP)
+	RET
+
+TEXT runtime·xadd64(SB), NOSPLIT, $0-24
+	MOVD	ptr+0(FP), R4
+	MOVD	delta+8(FP), R5
+	SYNC
+	LDAR	(R4), R3
+	ADD	R5, R3
+	STDCCC	R3, (R4)
+	BNE	-4(PC)
+	SYNC
+	ISYNC
+	MOVD	R3, ret+16(FP)
+	RET
+
+TEXT runtime·xchg(SB), NOSPLIT, $0-20
+	MOVD	ptr+0(FP), R4
+	MOVW	new+8(FP), R5
+	SYNC
+	LWAR	(R4), R3
+	STWCCC	R5, (R4)
+	BNE	-3(PC)
+	SYNC
+	ISYNC
+	MOVW	R3, ret+16(FP)
+	RET
+
+TEXT runtime·xchg64(SB), NOSPLIT, $0-24
+	MOVD	ptr+0(FP), R4
+	MOVD	new+8(FP), R5
+	SYNC
+	LDAR	(R4), R3
+	STDCCC	R5, (R4)
+	BNE	-3(PC)
+	SYNC
+	ISYNC
+	MOVD	R3, ret+16(FP)
+	RET
+
+TEXT runtime·xchgp1(SB), NOSPLIT, $0-24
+	BR	runtime·xchg64(SB)
+
+TEXT runtime·xchguintptr(SB), NOSPLIT, $0-24
+	BR	runtime·xchg64(SB)
+
+TEXT runtime·procyield(SB),NOSPLIT,$0-0
+	RET
+
+TEXT runtime·atomicstorep1(SB), NOSPLIT, $0-16
+	BR	runtime·atomicstore64(SB)
+
+TEXT runtime·atomicstore(SB), NOSPLIT, $0-12
+	MOVD	ptr+0(FP), R3
+	MOVW	val+8(FP), R4
+	SYNC
+	MOVW	R4, 0(R3)
+	RET
+
+TEXT runtime·atomicstore64(SB), NOSPLIT, $0-16
+	MOVD	ptr+0(FP), R3
+	MOVD	val+8(FP), R4
+	SYNC
+	MOVD	R4, 0(R3)
+	RET
+
+// void	runtime·atomicor8(byte volatile*, byte);
+TEXT runtime·atomicor8(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
+	SLD	R6, R4, R4
+
+again:
+	SYNC
+	LWAR	(R5), R6
+	OR	R4, R6
+	STWCCC	R6, (R5)
+	BNE	again
+	SYNC
+	ISYNC
+	RET
+
+// 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
+	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(R1), R31
+	SUB	$4, R31
+	MOVD	R31, LR
+
+	MOVD	fv+0(FP), R11
+	MOVD	argp+8(FP), R1
+	SUB	$8, R1
+	MOVD	0(R11), R3
+	MOVD	R3, CTR
+	BR	(CTR)
+
+// Save state of caller into g->sched. Smashes R31.
+TEXT gosave<>(SB),NOSPLIT,$-8
+	MOVD	LR, R31
+	MOVD	R31, (g_sched+gobuf_pc)(g)
+	MOVD	R1, (g_sched+gobuf_sp)(g)
+	MOVD	R0, (g_sched+gobuf_lr)(g)
+	MOVD	R0, (g_sched+gobuf_ret)(g)
+	MOVD	R0, (g_sched+gobuf_ctxt)(g)
+	RET
+
+// func asmcgocall(fn, arg unsafe.Pointer) int32
+// Call fn(arg) on the scheduler stack,
+// aligned appropriately for the gcc ABI.
+// See cgocall.go for more details.
+TEXT ·asmcgocall(SB),NOSPLIT,$0-20
+	MOVD	fn+0(FP), R3
+	MOVD	arg+8(FP), R4
+
+	MOVD	R1, 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), R1
+
+	// 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.
+	SUB	$48, R1
+	RLDCR	$0, R1, $~15, R1	// 16-byte alignment for gcc ABI
+	MOVD	R5, 40(R1)	// save old g on stack
+	MOVD	(g_stack+stack_hi)(R5), R5
+	SUB	R2, R5
+	MOVD	R5, 32(R1)	// save depth in old g stack (can't just save SP, as stack might be copied during a callback)
+	MOVD	R0, 0(R1)	// 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	R12, CTR
+	MOVD	R4, R3		// arg in r3
+	BL	(CTR)
+
+	// C code can clobber R0, so set it back to 0.  F27-F31 are
+	// callee save, so we don't need to recover those.
+	XOR	R0, R0
+	// Restore g, stack pointer.  R3 is errno, so don't touch it
+	MOVD	40(R1), g
+	BL	runtime·save_g(SB)
+	MOVD	(g_stack+stack_hi)(g), R5
+	MOVD	32(R1), R6
+	SUB	R6, R5
+	MOVD	R5, R1
+
+	MOVW	R3, ret+16(FP)
+	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(R1)
+	MOVD	frame+8(FP), R3
+	MOVD	R3, 16(R1)
+	MOVD	framesize+16(FP), R3
+	MOVD	R3, 24(R1)
+	MOVD	$runtime·cgocallback_gofunc(SB), R3
+	MOVD	R3, CTR
+	BL	(CTR)
+	RET
+
+// cgocallback_gofunc(FuncVal*, void *frame, uintptr framesize)
+// See cgocall.go 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	R3, $0
+	BEQ	nocgo
+	BL	runtime·load_g(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	g, $0
+	BNE	havem
+	MOVD	g, savedm-8(SP) // g is zero, so is m.
+	MOVD	$runtime·needm(SB), R3
+	MOVD	R3, CTR
+	BL	(CTR)
+
+	// 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	R1, (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	R1, (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), R1
+	BL	runtime·cgocallbackg(SB)
+
+	// Restore g->sched (== m->curg->sched) from saved values.
+	MOVD	0(R1), R5
+	MOVD	R5, (g_sched+gobuf_pc)(g)
+	MOVD	$24(R1), 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), R1
+	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	R6, $0
+	BNE	droppedm
+	MOVD	$runtime·dropm(SB), R3
+	MOVD	R3, CTR
+	BL	(CTR)
+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
+
+// void setg_gcc(G*); set g in C TLS.
+// Must obey the gcc calling convention.
+TEXT setg_gcc<>(SB),NOSPLIT,$-8-0
+	// The standard prologue clobbers R31, which is callee-save in
+	// the C ABI, so we have to use $-8-0 and save LR ourselves.
+	MOVD	LR, R4
+	// Also save g and R31, since they're callee-save in C ABI
+	MOVD	R31, R5
+	MOVD	g, R6
+
+	MOVD	R3, g
+	BL	runtime·save_g(SB)
+
+	MOVD	R6, g
+	MOVD	R5, R31
+	MOVD	R4, LR
+	RET
+
+TEXT runtime·getcallerpc(SB),NOSPLIT,$8-16
+	MOVD	16(R1), R3		// LR saved by caller
+	MOVD	runtime·stackBarrierPC(SB), R4
+	CMP	R3, R4
+	BNE	nobar
+	// Get original return PC.
+	BL	runtime·nextBarrierPC(SB)
+	MOVD	8(R1), R3
+nobar:
+	MOVD	R3, ret+8(FP)
+	RET
+
+TEXT runtime·setcallerpc(SB),NOSPLIT,$8-16
+	MOVD	pc+8(FP), R3
+	MOVD	16(R1), R4
+	MOVD	runtime·stackBarrierPC(SB), R5
+	CMP	R4, R5
+	BEQ	setbar
+	MOVD	R3, 16(R1)		// set LR in caller
+	RET
+setbar:
+	// Set the stack barrier return PC.
+	MOVD	R3, 8(R1)
+	BL	runtime·setNextBarrierPC(SB)
+	RET
+
+TEXT runtime·getcallersp(SB),NOSPLIT,$0-16
+	MOVD	argp+0(FP), R3
+	SUB	$8, R3
+	MOVD	R3, ret+8(FP)
+	RET
+
+TEXT runtime·abort(SB),NOSPLIT,$-8-0
+	MOVW	(R0), R0
+	UNDEF
+
+#define	TBRL	268
+#define	TBRU	269		/* Time base Upper/Lower */
+
+// int64 runtime·cputicks(void)
+TEXT runtime·cputicks(SB),NOSPLIT,$0-8
+	MOVW	SPR(TBRU), R4
+	MOVW	SPR(TBRL), R3
+	MOVW	SPR(TBRU), R5
+	CMPW	R4, R5
+	BNE	-4(PC)
+	SLD	$32, R5
+	OR	R5, R3
+	MOVD	R3, ret+0(FP)
+	RET
+
+// 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(R11), R5
+	MOVD	R3, 8(R1)
+	MOVD	R4, 16(R1)
+	MOVD	R5, 24(R1)
+	BL	runtime·memhash(SB)
+	MOVD	32(R1), R3
+	MOVD	R3, ret+16(FP)
+	RET
+
+// AES hashing not implemented for ppc64
+TEXT runtime·aeshash(SB),NOSPLIT,$-8-0
+	MOVW	(R0), R1
+TEXT runtime·aeshash32(SB),NOSPLIT,$-8-0
+	MOVW	(R0), R1
+TEXT runtime·aeshash64(SB),NOSPLIT,$-8-0
+	MOVW	(R0), R1
+TEXT runtime·aeshashstr(SB),NOSPLIT,$-8-0
+	MOVW	(R0), R1
+
+TEXT runtime·memeq(SB),NOSPLIT,$-8-25
+	MOVD	a+0(FP), R3
+	MOVD	b+8(FP), R4
+	MOVD	size+16(FP), R5
+	SUB	$1, R3
+	SUB	$1, R4
+	ADD	R3, R5, R8
+loop:
+	CMP	R3, R8
+	BNE	test
+	MOVD	$1, R3
+	MOVB	R3, ret+24(FP)
+	RET
+test:
+	MOVBZU	1(R3), R6
+	MOVBZU	1(R4), R7
+	CMP	R6, R7
+	BEQ	loop
+
+	MOVB	R0, ret+24(FP)
+	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(R11), R5    // compiler stores size at offset 8 in the closure
+	MOVD	R3, 8(R1)
+	MOVD	R4, 16(R1)
+	MOVD	R5, 24(R1)
+	BL	runtime·memeq(SB)
+	MOVBZ	32(R1), 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), R3
+	MOVD	s2str+16(FP), R4
+	MOVD	$1, R5
+	MOVB	R5, ret+32(FP)
+	CMP	R3, R4
+	BNE	2(PC)
+	RET
+	MOVD	s1len+8(FP), R5
+	SUB	$1, R3
+	SUB	$1, R4
+	ADD	R3, R5, R8
+loop:
+	CMP	R3, R8
+	BNE	2(PC)
+	RET
+	MOVBZU	1(R3), R6
+	MOVBZU	1(R4), R7
+	CMP	R6, R7
+	BEQ	loop
+	MOVB	R0, ret+32(FP)
+	RET
+
+// TODO: share code with memeq?
+TEXT bytes·Equal(SB),NOSPLIT,$0-49
+	MOVD	a_len+8(FP), R3
+	MOVD	b_len+32(FP), R4
+
+	CMP	R3, R4		// unequal lengths are not equal
+	BNE	noteq
+
+	MOVD	a+0(FP), R5
+	MOVD	b+24(FP), R6
+	SUB	$1, R5
+	SUB	$1, R6
+	ADD	R5, R3		// end-1
+
+loop:
+	CMP	R5, R3
+	BEQ	equal		// reached the end
+	MOVBZU	1(R5), R4
+	MOVBZU	1(R6), R7
+	CMP	R4, R7
+	BEQ	loop
+
+noteq:
+	MOVBZ	R0, ret+48(FP)
+	RET
+
+equal:
+	MOVD	$1, R3
+	MOVBZ	R3, ret+48(FP)
+	RET
+
+TEXT bytes·IndexByte(SB),NOSPLIT,$0-40
+	MOVD	s+0(FP), R3
+	MOVD	s_len+8(FP), R4
+	MOVBZ	c+24(FP), R5	// byte to find
+	MOVD	R3, R6		// store base for later
+	SUB	$1, R3
+	ADD	R3, R4		// end-1
+
+loop:
+	CMP	R3, R4
+	BEQ	notfound
+	MOVBZU	1(R3), R7
+	CMP	R7, R5
+	BNE	loop
+
+	SUB	R6, R3		// remove base
+	MOVD	R3, ret+32(FP)
+	RET
+
+notfound:
+	MOVD	$-1, R3
+	MOVD	R3, ret+32(FP)
+	RET
+
+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
+	MOVD	R3, R6		// store base for later
+	SUB	$1, R3
+	ADD	R3, R4		// end-1
+
+loop:
+	CMP	R3, R4
+	BEQ	notfound
+	MOVBZU	1(R3), R7
+	CMP	R7, R5
+	BNE	loop
+
+	SUB	R6, R3		// remove base
+	MOVD	R3, ret+24(FP)
+	RET
+
+notfound:
+	MOVD	$-1, R3
+	MOVD	R3, ret+24(FP)
+	RET
+
+TEXT runtime·fastrand1(SB), NOSPLIT, $0-4
+	MOVD	g_m(g), R4
+	MOVWZ	m_fastrand(R4), R3
+	ADD	R3, R3
+	CMPW	R3, $0
+	BGE	2(PC)
+	XOR	$0x88888eef, R3
+	MOVW	R3, m_fastrand(R4)
+	MOVW	R3, ret+0(FP)
+	RET
+
+TEXT runtime·return0(SB), NOSPLIT, $0
+	MOVW	$0, R3
+	RET
+
+// Called from cgo wrappers, this function returns g->m->curg.stack.hi.
+// Must obey the gcc calling convention.
+TEXT _cgo_topofstack(SB),NOSPLIT,$-8
+	// g (R30) and R31 are callee-save in the C ABI, so save them
+	MOVD	g, R4
+	MOVD	R31, R5
+	MOVD	LR, R6
+
+	BL	runtime·load_g(SB)	// clobbers g (R30), R31
+	MOVD	g_m(g), R3
+	MOVD	m_curg(R3), R3
+	MOVD	(g_stack+stack_hi)(R3), R3
+
+	MOVD	R4, g
+	MOVD	R5, R31
+	MOVD	R6, LR
+	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
+	// traceback from goexit1 must hit code range of goexit
+	MOVD	R0, R0	// NOP
+
+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/atomic.go b/src/runtime/atomic.go
deleted file mode 100644
index 7e9d9b3..0000000
--- a/src/runtime/atomic.go
+++ /dev/null
@@ -1,51 +0,0 @@
-// 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 !arm
-
-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
-
-//go:noescape
-func xchgp(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:noescape
-func atomicor8(ptr *uint8, val uint8)
-
-//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)
-
-//go:noescape
-func atomicstorep(ptr unsafe.Pointer, val unsafe.Pointer)
diff --git a/src/runtime/atomic_386.c b/src/runtime/atomic_386.c
deleted file mode 100644
index 82d36f2..0000000
--- a/src/runtime/atomic_386.c
+++ /dev/null
@@ -1,46 +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 "runtime.h"
-#include "textflag.h"
-
-#pragma textflag NOSPLIT
-uint32
-runtime·atomicload(uint32 volatile* addr)
-{
-	return *addr;
-}
-
-#pragma textflag NOSPLIT
-void*
-runtime·atomicloadp(void* volatile* addr)
-{
-	return *addr;
-}
-
-#pragma textflag NOSPLIT
-uint64
-runtime·xadd64(uint64 volatile* addr, int64 v)
-{
-	uint64 old;
-
-	do
-		old = *addr;
-	while(!runtime·cas64(addr, old, old+v));
-
-	return old+v;
-}
-
-#pragma textflag NOSPLIT
-uint64
-runtime·xchg64(uint64 volatile* addr, uint64 v)
-{
-	uint64 old;
-
-	do
-		old = *addr;
-	while(!runtime·cas64(addr, old, v));
-
-	return old;
-}
diff --git a/src/runtime/atomic_386.go b/src/runtime/atomic_386.go
new file mode 100644
index 0000000..f8d589e
--- /dev/null
+++ b/src/runtime/atomic_386.go
@@ -0,0 +1,82 @@
+// 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"
+
+// The calls to nop are to keep these functions from being inlined.
+// If they are inlined we have no guarantee that later rewrites of the
+// code by optimizers will preserve the relative order of memory accesses.
+
+//go:nosplit
+func atomicload(ptr *uint32) uint32 {
+	nop()
+	return *ptr
+}
+
+//go:nosplit
+func atomicloadp(ptr unsafe.Pointer) unsafe.Pointer {
+	nop()
+	return *(*unsafe.Pointer)(ptr)
+}
+
+//go:nosplit
+func xadd64(ptr *uint64, delta int64) uint64 {
+	for {
+		old := *ptr
+		if cas64(ptr, old, old+uint64(delta)) {
+			return old + uint64(delta)
+		}
+	}
+}
+
+//go:noescape
+//go:linkname xadduintptr runtime.xadd
+func xadduintptr(ptr *uintptr, delta uintptr) uintptr
+
+//go:nosplit
+func xchg64(ptr *uint64, new uint64) uint64 {
+	for {
+		old := *ptr
+		if cas64(ptr, old, new) {
+			return old
+		}
+	}
+}
+
+//go:noescape
+func xadd(ptr *uint32, delta int32) uint32
+
+//go:noescape
+func xchg(ptr *uint32, new uint32) uint32
+
+// 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 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
+
+//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_amd64x.c b/src/runtime/atomic_amd64x.c
deleted file mode 100644
index 7be57ac..0000000
--- a/src/runtime/atomic_amd64x.c
+++ /dev/null
@@ -1,29 +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.
-
-// +build amd64 amd64p32
-
-#include "runtime.h"
-#include "textflag.h"
-
-#pragma textflag NOSPLIT
-uint32
-runtime·atomicload(uint32 volatile* addr)
-{
-	return *addr;
-}
-
-#pragma textflag NOSPLIT
-uint64
-runtime·atomicload64(uint64 volatile* addr)
-{
-	return *addr;
-}
-
-#pragma textflag NOSPLIT
-void*
-runtime·atomicloadp(void* volatile* addr)
-{
-	return *addr;
-}
diff --git a/src/runtime/atomic_amd64x.go b/src/runtime/atomic_amd64x.go
new file mode 100644
index 0000000..edcc6d6
--- /dev/null
+++ b/src/runtime/atomic_amd64x.go
@@ -0,0 +1,72 @@
+// 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.
+
+// +build amd64 amd64p32
+
+package runtime
+
+import "unsafe"
+
+// The calls to nop are to keep these functions from being inlined.
+// If they are inlined we have no guarantee that later rewrites of the
+// code by optimizers will preserve the relative order of memory accesses.
+
+//go:nosplit
+func atomicload(ptr *uint32) uint32 {
+	nop()
+	return *ptr
+}
+
+//go:nosplit
+func atomicloadp(ptr unsafe.Pointer) unsafe.Pointer {
+	nop()
+	return *(*unsafe.Pointer)(ptr)
+}
+
+//go:nosplit
+func atomicload64(ptr *uint64) uint64 {
+	nop()
+	return *ptr
+}
+
+//go:noescape
+func xadd(ptr *uint32, delta int32) uint32
+
+//go:noescape
+func xadd64(ptr *uint64, delta int64) uint64
+
+//go:noescape
+func xadduintptr(ptr *uintptr, delta uintptr) uintptr
+
+//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 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
+
+//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_arm.go b/src/runtime/atomic_arm.go
index b1632cd..02a1f35 100644
--- a/src/runtime/atomic_arm.go
+++ b/src/runtime/atomic_arm.go
@@ -27,6 +27,10 @@ func xadd(val *uint32, delta int32) uint32 {
 	}
 }
 
+//go:noescape
+//go:linkname xadduintptr runtime.xadd
+func xadduintptr(ptr *uintptr, delta uintptr) uintptr
+
 //go:nosplit
 func xchg(addr *uint32, v uint32) uint32 {
 	for {
@@ -38,10 +42,10 @@ func xchg(addr *uint32, v uint32) uint32 {
 }
 
 //go:nosplit
-func xchgp(addr *unsafe.Pointer, v unsafe.Pointer) unsafe.Pointer {
+func xchgp1(addr unsafe.Pointer, v unsafe.Pointer) unsafe.Pointer {
 	for {
-		old := *addr
-		if casp(addr, old, v) {
+		old := *(*unsafe.Pointer)(addr)
+		if casp1((*unsafe.Pointer)(addr), old, v) {
 			return old
 		}
 	}
@@ -63,10 +67,10 @@ func atomicloadp(addr unsafe.Pointer) unsafe.Pointer {
 }
 
 //go:nosplit
-func atomicstorep(addr unsafe.Pointer, v unsafe.Pointer) {
+func atomicstorep1(addr unsafe.Pointer, v unsafe.Pointer) {
 	for {
 		old := *(*unsafe.Pointer)(addr)
-		if casp((*unsafe.Pointer)(addr), old, v) {
+		if casp1((*unsafe.Pointer)(addr), old, v) {
 			return
 		}
 	}
@@ -85,7 +89,7 @@ func atomicstore(addr *uint32, v uint32) {
 //go:nosplit
 func cas64(addr *uint64, old, new uint64) bool {
 	var ok bool
-	onM(func() {
+	systemstack(func() {
 		lock(addrLock(addr))
 		if *addr == old {
 			*addr = new
@@ -99,7 +103,7 @@ func cas64(addr *uint64, old, new uint64) bool {
 //go:nosplit
 func xadd64(addr *uint64, delta int64) uint64 {
 	var r uint64
-	onM(func() {
+	systemstack(func() {
 		lock(addrLock(addr))
 		r = *addr + uint64(delta)
 		*addr = r
@@ -111,7 +115,7 @@ func xadd64(addr *uint64, delta int64) uint64 {
 //go:nosplit
 func xchg64(addr *uint64, v uint64) uint64 {
 	var r uint64
-	onM(func() {
+	systemstack(func() {
 		lock(addrLock(addr))
 		r = *addr
 		*addr = v
@@ -123,7 +127,7 @@ func xchg64(addr *uint64, v uint64) uint64 {
 //go:nosplit
 func atomicload64(addr *uint64) uint64 {
 	var r uint64
-	onM(func() {
+	systemstack(func() {
 		lock(addrLock(addr))
 		r = *addr
 		unlock(addrLock(addr))
@@ -133,7 +137,7 @@ func atomicload64(addr *uint64) uint64 {
 
 //go:nosplit
 func atomicstore64(addr *uint64, v uint64) {
-	onM(func() {
+	systemstack(func() {
 		lock(addrLock(addr))
 		*addr = v
 		unlock(addrLock(addr))
@@ -153,3 +157,19 @@ func atomicor8(addr *uint8, v uint8) {
 		}
 	}
 }
+
+//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..a377e3e
--- /dev/null
+++ b/src/runtime/atomic_arm64.go
@@ -0,0 +1,82 @@
+// 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
+//go:linkname xadduintptr runtime.xadd64
+func xadduintptr(ptr *uintptr, delta uintptr) uintptr
+
+//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..d3ab2a1
--- /dev/null
+++ b/src/runtime/atomic_arm64.s
@@ -0,0 +1,117 @@
+// 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)
+
+TEXT ·publicationBarrier(SB),NOSPLIT,$-8-0
+	DMB	$0xe	// DMB ST
+	RET
diff --git a/src/runtime/atomic_pointer.go b/src/runtime/atomic_pointer.go
new file mode 100644
index 0000000..f84afe0
--- /dev/null
+++ b/src/runtime/atomic_pointer.go
@@ -0,0 +1,78 @@
+// 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"
+
+// These functions cannot have go:noescape annotations,
+// because while ptr does not escape, new does.
+// If new is marked as not escaping, the compiler will make incorrect
+// escape analysis decisions about the pointer value being stored.
+// Instead, these are wrappers around the actual atomics (xchgp1 and so on)
+// that use noescape to convey which arguments do not escape.
+//
+// Additionally, these functions must update the shadow heap for
+// write barrier checking.
+
+//go:nosplit
+func atomicstorep(ptr unsafe.Pointer, new unsafe.Pointer) {
+	atomicstorep1(noescape(ptr), new)
+	writebarrierptr_nostore((*uintptr)(ptr), uintptr(new))
+}
+
+//go:nosplit
+func xchgp(ptr unsafe.Pointer, new unsafe.Pointer) unsafe.Pointer {
+	old := xchgp1(noescape(ptr), new)
+	writebarrierptr_nostore((*uintptr)(ptr), uintptr(new))
+	return old
+}
+
+//go:nosplit
+func casp(ptr *unsafe.Pointer, old, new unsafe.Pointer) bool {
+	if !casp1((*unsafe.Pointer)(noescape(unsafe.Pointer(ptr))), noescape(old), new) {
+		return false
+	}
+	writebarrierptr_nostore((*uintptr)(unsafe.Pointer(ptr)), uintptr(new))
+	return true
+}
+
+// Like above, but implement in terms of sync/atomic's uintptr operations.
+// We cannot just call the runtime routines, because the race detector expects
+// to be able to intercept the sync/atomic forms but not the runtime forms.
+
+//go:linkname sync_atomic_StoreUintptr sync/atomic.StoreUintptr
+func sync_atomic_StoreUintptr(ptr *uintptr, new uintptr)
+
+//go:linkname sync_atomic_StorePointer sync/atomic.StorePointer
+//go:nosplit
+func sync_atomic_StorePointer(ptr *unsafe.Pointer, new unsafe.Pointer) {
+	sync_atomic_StoreUintptr((*uintptr)(unsafe.Pointer(ptr)), uintptr(new))
+	atomicstorep1(noescape(unsafe.Pointer(ptr)), new)
+	writebarrierptr_nostore((*uintptr)(unsafe.Pointer(ptr)), uintptr(new))
+}
+
+//go:linkname sync_atomic_SwapUintptr sync/atomic.SwapUintptr
+func sync_atomic_SwapUintptr(ptr *uintptr, new uintptr) uintptr
+
+//go:linkname sync_atomic_SwapPointer sync/atomic.SwapPointer
+//go:nosplit
+func sync_atomic_SwapPointer(ptr unsafe.Pointer, new unsafe.Pointer) unsafe.Pointer {
+	old := unsafe.Pointer(sync_atomic_SwapUintptr((*uintptr)(noescape(ptr)), uintptr(new)))
+	writebarrierptr_nostore((*uintptr)(ptr), uintptr(new))
+	return old
+}
+
+//go:linkname sync_atomic_CompareAndSwapUintptr sync/atomic.CompareAndSwapUintptr
+func sync_atomic_CompareAndSwapUintptr(ptr *uintptr, old, new uintptr) bool
+
+//go:linkname sync_atomic_CompareAndSwapPointer sync/atomic.CompareAndSwapPointer
+//go:nosplit
+func sync_atomic_CompareAndSwapPointer(ptr *unsafe.Pointer, old, new unsafe.Pointer) bool {
+	if !sync_atomic_CompareAndSwapUintptr((*uintptr)(noescape(unsafe.Pointer(ptr))), uintptr(old), uintptr(new)) {
+		return false
+	}
+	writebarrierptr_nostore((*uintptr)(unsafe.Pointer(ptr)), uintptr(new))
+	return true
+}
diff --git a/src/runtime/atomic_ppc64x.go b/src/runtime/atomic_ppc64x.go
new file mode 100644
index 0000000..b58ee5a
--- /dev/null
+++ b/src/runtime/atomic_ppc64x.go
@@ -0,0 +1,60 @@
+// 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 ppc64 ppc64le
+
+package runtime
+
+import "unsafe"
+
+//go:noescape
+func xadd(ptr *uint32, delta int32) uint32
+
+//go:noescape
+func xadd64(ptr *uint64, delta int64) uint64
+
+//go:noescape
+//go:linkname xadduintptr runtime.xadd64
+func xadduintptr(ptr *uintptr, delta uintptr) uintptr
+
+//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: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
+
+//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_ppc64x.s b/src/runtime/atomic_ppc64x.s
new file mode 100644
index 0000000..28c5bf3
--- /dev/null
+++ b/src/runtime/atomic_ppc64x.s
@@ -0,0 +1,47 @@
+// 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 ppc64 ppc64le
+
+#include "textflag.h"
+
+// uint32 runtime·atomicload(uint32 volatile* addr)
+TEXT ·atomicload(SB),NOSPLIT,$-8-12
+	MOVD	addr+0(FP), R3
+	SYNC
+	MOVWZ	0(R3), R3
+	CMPW	R3, R3, CR7
+	BC	4, 30, 1(PC) // bne- cr7,0x4
+	ISYNC
+	MOVW	R3, ret+8(FP)
+	RET
+
+// uint64 runtime·atomicload64(uint64 volatile* addr)
+TEXT ·atomicload64(SB),NOSPLIT,$-8-16
+	MOVD	addr+0(FP), R3
+	SYNC
+	MOVD	0(R3), R3
+	CMP	R3, R3, CR7
+	BC	4, 30, 1(PC) // bne- cr7,0x4
+	ISYNC
+	MOVD	R3, ret+8(FP)
+	RET
+
+// void *runtime·atomicloadp(void *volatile *addr)
+TEXT ·atomicloadp(SB),NOSPLIT,$-8-16
+	MOVD	addr+0(FP), R3
+	SYNC
+	MOVD	0(R3), R3
+	CMP	R3, R3, CR7
+	BC	4, 30, 1(PC) // bne- cr7,0x4
+	ISYNC
+	MOVD	R3, ret+8(FP)
+	RET
+
+TEXT ·publicationBarrier(SB),NOSPLIT,$-8-0
+	// LWSYNC is the "export" barrier recommended by Power ISA
+	// v2.07 book II, appendix B.2.2.2.
+	// LWSYNC is a load/load, load/store, and store/store barrier.
+	WORD $0x7c2004ac	// LWSYNC
+	RET
diff --git a/src/runtime/atomic_test.go b/src/runtime/atomic_test.go
new file mode 100644
index 0000000..2699103
--- /dev/null
+++ b/src/runtime/atomic_test.go
@@ -0,0 +1,66 @@
+// 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"
+	"testing"
+	"unsafe"
+)
+
+func runParallel(N, iter int, f func()) {
+	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(int(N)))
+	done := make(chan bool)
+	for i := 0; i < N; i++ {
+		go func() {
+			for j := 0; j < iter; j++ {
+				f()
+			}
+			done <- true
+		}()
+	}
+	for i := 0; i < N; i++ {
+		<-done
+	}
+}
+
+func TestXadduintptr(t *testing.T) {
+	const N = 20
+	const iter = 100000
+	inc := uintptr(100)
+	total := uintptr(0)
+	runParallel(N, iter, func() {
+		runtime.Xadduintptr(&total, inc)
+	})
+	if want := uintptr(N * iter * inc); want != total {
+		t.Fatalf("xadduintpr error, want %d, got %d", want, total)
+	}
+	total = 0
+	runParallel(N, iter, func() {
+		runtime.Xadduintptr(&total, inc)
+		runtime.Xadduintptr(&total, uintptr(-int64(inc)))
+	})
+	if total != 0 {
+		t.Fatalf("xadduintpr total error, want %d, got %d", 0, total)
+	}
+}
+
+// Tests that xadduintptr correctly updates 64-bit values.  The place where
+// we actually do so is mstats.go, functions mSysStat{Inc,Dec}.
+func TestXadduintptrOnUint64(t *testing.T) {
+	if runtime.BigEndian != 0 {
+		// On big endian architectures, we never use xadduintptr to update
+		// 64-bit values and hence we skip the test.  (Note that functions
+		// mSysStat{Inc,Dec} in mstats.go have explicit checks for
+		// big-endianness.)
+		return
+	}
+	const inc = 100
+	val := uint64(0)
+	runtime.Xadduintptr((*uintptr)(unsafe.Pointer(&val)), inc)
+	if inc != val {
+		t.Fatalf("xadduintptr should increase lower-order bits, want %d, got %d", inc, val)
+	}
+}
diff --git a/src/runtime/cgo.go b/src/runtime/cgo.go
new file mode 100644
index 0000000..169a31d
--- /dev/null
+++ b/src/runtime/cgo.go
@@ -0,0 +1,50 @@
+// 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"
+
+//go:cgo_export_static main
+
+// Filled in by runtime/cgo when linked into binary.
+
+//go:linkname _cgo_init _cgo_init
+//go:linkname _cgo_malloc _cgo_malloc
+//go:linkname _cgo_free _cgo_free
+//go:linkname _cgo_thread_start _cgo_thread_start
+//go:linkname _cgo_sys_thread_create _cgo_sys_thread_create
+//go:linkname _cgo_notify_runtime_init_done _cgo_notify_runtime_init_done
+
+var (
+	_cgo_init                     unsafe.Pointer
+	_cgo_malloc                   unsafe.Pointer
+	_cgo_free                     unsafe.Pointer
+	_cgo_thread_start             unsafe.Pointer
+	_cgo_sys_thread_create        unsafe.Pointer
+	_cgo_notify_runtime_init_done 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
+
+// cgoUse is called by cgo-generated code (using go:linkname to get at
+// an unexported name). The calls serve two purposes:
+// 1) they are opaque to escape analysis, so the argument is considered to
+// escape to the heap.
+// 2) they keep the argument alive until the call site; the call is emitted after
+// the end of the (presumed) use of the argument by C.
+// cgoUse should not actually be called (see cgoAlwaysFalse).
+func cgoUse(interface{}) { throw("cgoUse should not be called") }
+
+// cgoAlwaysFalse is a boolean value that is always false.
+// The cgo-generated code says if cgoAlwaysFalse { cgoUse(p) }.
+// The compiler cannot see that cgoAlwaysFalse is always false,
+// so it emits the test and keeps the call, giving the desired
+// escape analysis result. The test is cheaper than the call.
+var cgoAlwaysFalse bool
diff --git a/src/runtime/cgo/asm_arm.s b/src/runtime/cgo/asm_arm.s
index 6e57432..9aeaf9a 100644
--- a/src/runtime/cgo/asm_arm.s
+++ b/src/runtime/cgo/asm_arm.s
@@ -12,13 +12,13 @@ TEXT crosscall2(SB),NOSPLIT,$-4
 	/* 
 	 * We still need to save all callee save register as before, and then
 	 *  push 2 args for fn (R1 and R2).
-	 * Also note that at procedure entry in 5c/5g world, 4(R13) will be the
+	 * Also note that at procedure entry in gc world, 4(R13) will be the
 	 *  first arg, so we must push another dummy reg (R0) for 0(R13).
 	 *  Additionally, runtime·load_g will clobber R0, so we need to save R0
 	 *  nevertheless.
 	 */
 	MOVM.WP	[R0, R1, R2, R4, R5, R6, R7, R8, R9, g, R11, R12, R14], (R13)
 	BL	runtime·load_g(SB)
-	MOVW	PC, R14
-	MOVW	0(R13), PC
-	MOVM.IAW	(R13), [R0, R1, R2, R4, R5, R6, R7, R8, R9, g, R11, R12, PC]
+	MOVW	R15, R14 // R15 is PC.
+	MOVW	0(R13), R15
+	MOVM.IAW	(R13), [R0, R1, R2, R4, R5, R6, R7, R8, R9, g, R11, R12, R15]
diff --git a/src/runtime/cgo/asm_arm64.s b/src/runtime/cgo/asm_arm64.s
new file mode 100644
index 0000000..c6f98fa
--- /dev/null
+++ b/src/runtime/cgo/asm_arm64.s
@@ -0,0 +1,57 @@
+// 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"
+
+/*
+ * void crosscall2(void (*fn)(void*, int32), void*, int32)
+ * Save registers and call fn with two arguments.
+ */
+TEXT crosscall2(SB),NOSPLIT,$-8
+	/*
+	 * We still need to save all callee save register as before, and then
+	 *  push 2 args for fn (R1 and R2).
+	 * Also note that at procedure entry in gc world, 8(RSP) will be the
+	 *  first arg.
+	 * TODO(minux): use LDP/STP here if it matters.
+	 */
+	SUB	$128, RSP
+	MOVD	R1, (8*1)(RSP)
+	MOVD	R2, (8*2)(RSP)
+	MOVD	R19, (8*3)(RSP)
+	MOVD	R20, (8*4)(RSP)
+	MOVD	R21, (8*5)(RSP)
+	MOVD	R22, (8*6)(RSP)
+	MOVD	R23, (8*7)(RSP)
+	MOVD	R24, (8*8)(RSP)
+	MOVD	R25, (8*9)(RSP)
+	MOVD	R26, (8*10)(RSP)
+	MOVD	R27, (8*11)(RSP)
+	MOVD	g, (8*12)(RSP)
+	MOVD	R29, (8*13)(RSP)
+	MOVD	R30, (8*14)(RSP)
+
+	MOVD	R0, R19
+
+	// Initialize Go ABI environment
+	BL      runtime·reginit(SB)
+	BL	runtime·load_g(SB)
+	BL	(R19)
+
+	MOVD	(8*1)(RSP), R1
+	MOVD	(8*2)(RSP), R2
+	MOVD	(8*3)(RSP), R19
+	MOVD	(8*4)(RSP), R20
+	MOVD	(8*5)(RSP), R21
+	MOVD	(8*6)(RSP), R22
+	MOVD	(8*7)(RSP), R23
+	MOVD	(8*8)(RSP), R24
+	MOVD	(8*9)(RSP), R25
+	MOVD	(8*10)(RSP), R26
+	MOVD	(8*11)(RSP), R27
+	MOVD	(8*12)(RSP), g
+	MOVD	(8*13)(RSP), R29
+	MOVD	(8*14)(RSP), R30
+	ADD	$128, RSP
+	RET
diff --git a/src/runtime/cgo/asm_ppc64x.s b/src/runtime/cgo/asm_ppc64x.s
new file mode 100644
index 0000000..0c08a1d
--- /dev/null
+++ b/src/runtime/cgo/asm_ppc64x.s
@@ -0,0 +1,124 @@
+// 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 ppc64 ppc64le
+
+#include "textflag.h"
+
+/*
+ * void crosscall2(void (*fn)(void*, int32), void*, int32)
+ * Save registers and call fn with two arguments.
+ * crosscall2 obeys the C ABI; fn obeys the Go ABI.
+ */
+TEXT crosscall2(SB),NOSPLIT,$-8
+	// TODO(austin): ABI v1 (fn is probably a function descriptor)
+
+	// Start with standard C stack frame layout and linkage
+	MOVD	LR, R0
+	MOVD	R0, 16(R1)	// Save LR in caller's frame
+	MOVD	R2, 24(R1)	// Save TOC in caller's frame
+
+	BL	saveregs2<>(SB)
+
+	MOVDU	R1, (-288-3*8)(R1)
+
+	// Initialize Go ABI environment
+	BL	runtime·reginit(SB)
+	BL	runtime·load_g(SB)
+
+	MOVD	R3, CTR
+	MOVD	R4, 8(R1)
+	MOVD	R5, 16(R1)
+	BL	(CTR)
+
+	ADD	$(288+3*8), R1
+
+	BL	restoreregs2<>(SB)
+
+	MOVD	24(R1), R2
+	MOVD	16(R1), R0
+	MOVD	R0, LR
+	RET
+
+TEXT saveregs2<>(SB),NOSPLIT,$-8
+	// O=-288; for R in R{14..31}; do echo "\tMOVD\t$R, $O(R1)"|sed s/R30/g/; ((O+=8)); done; for F in F{14..31}; do echo "\tFMOVD\t$F, $O(R1)"; ((O+=8)); done
+	MOVD	R14, -288(R1)
+	MOVD	R15, -280(R1)
+	MOVD	R16, -272(R1)
+	MOVD	R17, -264(R1)
+	MOVD	R18, -256(R1)
+	MOVD	R19, -248(R1)
+	MOVD	R20, -240(R1)
+	MOVD	R21, -232(R1)
+	MOVD	R22, -224(R1)
+	MOVD	R23, -216(R1)
+	MOVD	R24, -208(R1)
+	MOVD	R25, -200(R1)
+	MOVD	R26, -192(R1)
+	MOVD	R27, -184(R1)
+	MOVD	R28, -176(R1)
+	MOVD	R29, -168(R1)
+	MOVD	g, -160(R1)
+	MOVD	R31, -152(R1)
+	FMOVD	F14, -144(R1)
+	FMOVD	F15, -136(R1)
+	FMOVD	F16, -128(R1)
+	FMOVD	F17, -120(R1)
+	FMOVD	F18, -112(R1)
+	FMOVD	F19, -104(R1)
+	FMOVD	F20, -96(R1)
+	FMOVD	F21, -88(R1)
+	FMOVD	F22, -80(R1)
+	FMOVD	F23, -72(R1)
+	FMOVD	F24, -64(R1)
+	FMOVD	F25, -56(R1)
+	FMOVD	F26, -48(R1)
+	FMOVD	F27, -40(R1)
+	FMOVD	F28, -32(R1)
+	FMOVD	F29, -24(R1)
+	FMOVD	F30, -16(R1)
+	FMOVD	F31, -8(R1)
+
+	RET
+
+TEXT restoreregs2<>(SB),NOSPLIT,$-8
+	// O=-288; for R in R{14..31}; do echo "\tMOVD\t$O(R1), $R"|sed s/R30/g/; ((O+=8)); done; for F in F{14..31}; do echo "\tFMOVD\t$O(R1), $F"; ((O+=8)); done
+	MOVD	-288(R1), R14
+	MOVD	-280(R1), R15
+	MOVD	-272(R1), R16
+	MOVD	-264(R1), R17
+	MOVD	-256(R1), R18
+	MOVD	-248(R1), R19
+	MOVD	-240(R1), R20
+	MOVD	-232(R1), R21
+	MOVD	-224(R1), R22
+	MOVD	-216(R1), R23
+	MOVD	-208(R1), R24
+	MOVD	-200(R1), R25
+	MOVD	-192(R1), R26
+	MOVD	-184(R1), R27
+	MOVD	-176(R1), R28
+	MOVD	-168(R1), R29
+	MOVD	-160(R1), g
+	MOVD	-152(R1), R31
+	FMOVD	-144(R1), F14
+	FMOVD	-136(R1), F15
+	FMOVD	-128(R1), F16
+	FMOVD	-120(R1), F17
+	FMOVD	-112(R1), F18
+	FMOVD	-104(R1), F19
+	FMOVD	-96(R1), F20
+	FMOVD	-88(R1), F21
+	FMOVD	-80(R1), F22
+	FMOVD	-72(R1), F23
+	FMOVD	-64(R1), F24
+	FMOVD	-56(R1), F25
+	FMOVD	-48(R1), F26
+	FMOVD	-40(R1), F27
+	FMOVD	-32(R1), F28
+	FMOVD	-24(R1), F29
+	FMOVD	-16(R1), F30
+	FMOVD	-8(R1), F31
+
+	RET
diff --git a/src/runtime/cgo/callbacks.c b/src/runtime/cgo/callbacks.c
deleted file mode 100644
index 282beee..0000000
--- a/src/runtime/cgo/callbacks.c
+++ /dev/null
@@ -1,83 +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.
-
-#include "../runtime.h"
-#include "../cgocall.h"
-#include "textflag.h"
-
-// These utility functions are available to be called from code
-// compiled with gcc via crosscall2.
-
-// The declaration of crosscall2 is:
-//   void crosscall2(void (*fn)(void *, int), void *, int);
-// 
-// We need to export the symbol crosscall2 in order to support
-// callbacks from shared libraries. This applies regardless of
-// linking mode.
-#pragma cgo_export_static crosscall2
-#pragma cgo_export_dynamic crosscall2
-
-// Allocate memory.  This allocates the requested number of bytes in
-// memory controlled by the Go runtime.  The allocated memory will be
-// zeroed.  You are responsible for ensuring that the Go garbage
-// collector can see a pointer to the allocated memory for as long as
-// it is valid, e.g., by storing a pointer in a local variable in your
-// C function, or in memory allocated by the Go runtime.  If the only
-// pointers are in a C global variable or in memory allocated via
-// malloc, then the Go garbage collector may collect the memory.
-
-// Call like this in code compiled with gcc:
-//   struct { size_t len; void *ret; } a;
-//   a.len = /* number of bytes to allocate */;
-//   crosscall2(_cgo_allocate, &a, sizeof a);
-//   /* Here a.ret is a pointer to the allocated memory.  */
-
-void runtime·_cgo_allocate_internal(void);
-
-#pragma cgo_export_static _cgo_allocate
-#pragma cgo_export_dynamic _cgo_allocate
-#pragma textflag NOSPLIT
-void
-_cgo_allocate(void *a, int32 n)
-{
-	runtime·cgocallback((void(*)(void))runtime·_cgo_allocate_internal, a, n);
-}
-
-// Panic.  The argument is converted into a Go string.
-
-// Call like this in code compiled with gcc:
-//   struct { const char *p; } a;
-//   a.p = /* string to pass to panic */;
-//   crosscall2(_cgo_panic, &a, sizeof a);
-//   /* The function call will not return.  */
-
-void runtime·_cgo_panic_internal(void);
-
-#pragma cgo_export_static _cgo_panic
-#pragma cgo_export_dynamic _cgo_panic
-#pragma textflag NOSPLIT
-void
-_cgo_panic(void *a, int32 n)
-{
-	runtime·cgocallback((void(*)(void))runtime·_cgo_panic_internal, a, n);
-}
-
-#pragma cgo_import_static x_cgo_init
-extern void x_cgo_init(G*);
-void (*_cgo_init)(G*) = x_cgo_init;
-
-#pragma cgo_import_static x_cgo_malloc
-extern void x_cgo_malloc(void*);
-void (*_cgo_malloc)(void*) = x_cgo_malloc;
-
-#pragma cgo_import_static x_cgo_free
-extern void x_cgo_free(void*);
-void (*_cgo_free)(void*) = x_cgo_free;
-
-#pragma cgo_import_static x_cgo_thread_start
-extern void x_cgo_thread_start(void*);
-void (*_cgo_thread_start)(void*) = x_cgo_thread_start;
-
-#pragma cgo_export_static _cgo_topofstack
-#pragma cgo_export_dynamic _cgo_topofstack
diff --git a/src/runtime/cgo/callbacks.go b/src/runtime/cgo/callbacks.go
new file mode 100644
index 0000000..08f230d
--- /dev/null
+++ b/src/runtime/cgo/callbacks.go
@@ -0,0 +1,96 @@
+// 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 cgo
+
+import "unsafe"
+
+// These utility functions are available to be called from code
+// compiled with gcc via crosscall2.
+
+// cgocallback is defined in runtime
+//go:linkname _runtime_cgocallback runtime.cgocallback
+func _runtime_cgocallback(unsafe.Pointer, unsafe.Pointer, uintptr)
+
+// The declaration of crosscall2 is:
+//   void crosscall2(void (*fn)(void *, int), void *, int);
+//
+// We need to export the symbol crosscall2 in order to support
+// callbacks from shared libraries. This applies regardless of
+// linking mode.
+//go:cgo_export_static crosscall2
+//go:cgo_export_dynamic crosscall2
+
+// Panic.  The argument is converted into a Go string.
+
+// Call like this in code compiled with gcc:
+//   struct { const char *p; } a;
+//   a.p = /* string to pass to panic */;
+//   crosscall2(_cgo_panic, &a, sizeof a);
+//   /* The function call will not return.  */
+
+//go:linkname _runtime_cgo_panic_internal runtime._cgo_panic_internal
+var _runtime_cgo_panic_internal byte
+
+//go:linkname _cgo_panic _cgo_panic
+//go:cgo_export_static _cgo_panic
+//go:cgo_export_dynamic _cgo_panic
+//go:nosplit
+//go:norace
+func _cgo_panic(a unsafe.Pointer, n int32) {
+	_runtime_cgocallback(unsafe.Pointer(&_runtime_cgo_panic_internal), a, uintptr(n))
+}
+
+//go:cgo_import_static x_cgo_init
+//go:linkname x_cgo_init x_cgo_init
+//go:linkname _cgo_init _cgo_init
+var x_cgo_init byte
+var _cgo_init = &x_cgo_init
+
+//go:cgo_import_static x_cgo_malloc
+//go:linkname x_cgo_malloc x_cgo_malloc
+//go:linkname _cgo_malloc _cgo_malloc
+var x_cgo_malloc byte
+var _cgo_malloc = &x_cgo_malloc
+
+//go:cgo_import_static x_cgo_free
+//go:linkname x_cgo_free x_cgo_free
+//go:linkname _cgo_free _cgo_free
+var x_cgo_free byte
+var _cgo_free = &x_cgo_free
+
+//go:cgo_import_static x_cgo_thread_start
+//go:linkname x_cgo_thread_start x_cgo_thread_start
+//go:linkname _cgo_thread_start _cgo_thread_start
+var x_cgo_thread_start byte
+var _cgo_thread_start = &x_cgo_thread_start
+
+// Creates a new system thread without updating any Go state.
+//
+// This method is invoked during shared library loading to create a new OS
+// thread to perform the runtime initialization.  This method is similar to
+// _cgo_sys_thread_start except that it doesn't update any Go state.
+
+//go:cgo_import_static x_cgo_sys_thread_create
+//go:linkname x_cgo_sys_thread_create x_cgo_sys_thread_create
+//go:linkname _cgo_sys_thread_create _cgo_sys_thread_create
+var x_cgo_sys_thread_create byte
+var _cgo_sys_thread_create = &x_cgo_sys_thread_create
+
+// Notifies that the runtime has been intialized.
+//
+// We currently block at every CGO entry point (via _cgo_wait_runtime_init_done)
+// to ensure that the runtime has been initialized before the CGO call is
+// executed.  This is necessary for shared libraries where we kickoff runtime
+// initialization in a separate thread and return without waiting for this
+// thread to complete the init.
+
+//go:cgo_import_static x_cgo_notify_runtime_init_done
+//go:linkname x_cgo_notify_runtime_init_done x_cgo_notify_runtime_init_done
+//go:linkname _cgo_notify_runtime_init_done _cgo_notify_runtime_init_done
+var x_cgo_notify_runtime_init_done byte
+var _cgo_notify_runtime_init_done = &x_cgo_notify_runtime_init_done
+
+//go:cgo_export_static _cgo_topofstack
+//go:cgo_export_dynamic _cgo_topofstack
diff --git a/src/runtime/cgo/cgo.go b/src/runtime/cgo/cgo.go
index 8528692..cb24678 100644
--- a/src/runtime/cgo/cgo.go
+++ b/src/runtime/cgo/cgo.go
@@ -11,7 +11,9 @@ package cgo
 
 /*
 
-#cgo darwin LDFLAGS: -lpthread
+#cgo darwin,!arm,!arm64 LDFLAGS: -lpthread
+#cgo darwin,arm LDFLAGS: -framework CoreFoundation
+#cgo darwin,arm64 LDFLAGS: -framework CoreFoundation
 #cgo dragonfly LDFLAGS: -lpthread
 #cgo freebsd LDFLAGS: -lpthread
 #cgo android LDFLAGS: -llog
@@ -22,5 +24,7 @@ package cgo
 
 #cgo CFLAGS: -Wall -Werror
 
+#cgo solaris CPPFLAGS: -D_POSIX_PTHREAD_SEMANTICS
+
 */
 import "C"
diff --git a/src/runtime/cgo/dragonfly.c b/src/runtime/cgo/dragonfly.c
deleted file mode 100644
index c233c8b..0000000
--- a/src/runtime/cgo/dragonfly.c
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2010 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 dragonfly
-
-#include "textflag.h"
-
-// Supply environ and __progname, because we don't
-// link against the standard DragonFly crt0.o and the
-// libc dynamic library needs them.
-
-#pragma dataflag NOPTR
-char *environ[1];
-#pragma dataflag NOPTR
-char *__progname;
-
-#pragma dynexport environ environ
-#pragma dynexport __progname __progname
diff --git a/src/runtime/cgo/dragonfly.go b/src/runtime/cgo/dragonfly.go
new file mode 100644
index 0000000..69d52b5
--- /dev/null
+++ b/src/runtime/cgo/dragonfly.go
@@ -0,0 +1,19 @@
+// Copyright 2010 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 dragonfly
+
+package cgo
+
+import _ "unsafe" // for go:linkname
+
+// Supply environ and __progname, because we don't
+// link against the standard DragonFly crt0.o and the
+// libc dynamic library needs them.
+
+//go:linkname _environ environ
+//go:linkname _progname __progname
+
+var _environ uintptr
+var _progname uintptr
diff --git a/src/runtime/cgo/freebsd.c b/src/runtime/cgo/freebsd.c
deleted file mode 100644
index 4876b2a..0000000
--- a/src/runtime/cgo/freebsd.c
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2010 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
-
-#include "textflag.h"
-
-// Supply environ and __progname, because we don't
-// link against the standard FreeBSD crt0.o and the
-// libc dynamic library needs them.
-
-#pragma dataflag NOPTR
-char *environ[1];
-#pragma dataflag NOPTR
-char *__progname;
-
-#pragma dynexport environ environ
-#pragma dynexport __progname __progname
diff --git a/src/runtime/cgo/freebsd.go b/src/runtime/cgo/freebsd.go
new file mode 100644
index 0000000..99cf3fb
--- /dev/null
+++ b/src/runtime/cgo/freebsd.go
@@ -0,0 +1,22 @@
+// Copyright 2010 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
+
+package cgo
+
+import _ "unsafe" // for go:linkname
+
+// Supply environ and __progname, because we don't
+// link against the standard FreeBSD crt0.o and the
+// libc dynamic library needs them.
+
+//go:linkname _environ environ
+//go:linkname _progname __progname
+
+//go:cgo_export_dynamic environ
+//go:cgo_export_dynamic __progname
+
+var _environ uintptr
+var _progname uintptr
diff --git a/src/runtime/cgo/gcc_android_arm.c b/src/runtime/cgo/gcc_android_arm.c
index 07f7e72..85cd244 100644
--- a/src/runtime/cgo/gcc_android_arm.c
+++ b/src/runtime/cgo/gcc_android_arm.c
@@ -12,8 +12,10 @@
 
 // PTHREAD_KEYS_MAX has been added to sys/limits.h at head in bionic:
 // https://android.googlesource.com/platform/bionic/+/master/libc/include/sys/limits.h
-// TODO(crawshaw): remove this definition when a new NDK is released.
+// TODO(crawshaw): remove this definition when NDK r10d is required.
+#ifndef PTHREAD_KEYS_MAX
 #define PTHREAD_KEYS_MAX 128
+#endif
 
 // inittls allocates a thread-local storage slot for g.
 //
diff --git a/src/runtime/cgo/gcc_arm.S b/src/runtime/cgo/gcc_arm.S
index d5833bf..980ab57 100644
--- a/src/runtime/cgo/gcc_arm.S
+++ b/src/runtime/cgo/gcc_arm.S
@@ -11,6 +11,10 @@
 #define EXT(s) s
 #endif
 
+// Apple's ld64 wants 4-byte alignment for ARM code sections.
+// .align in both Apple as and GNU as treat n as aligning to 2**n bytes.
+.align	2
+
 /*
  * void crosscall_arm1(void (*fn)(void), void (*setg_gcc)(void *g), void *g)
  *
diff --git a/src/runtime/cgo/gcc_arm64.S b/src/runtime/cgo/gcc_arm64.S
new file mode 100644
index 0000000..b7379d1
--- /dev/null
+++ b/src/runtime/cgo/gcc_arm64.S
@@ -0,0 +1,57 @@
+// 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.
+
+/*
+ * Apple still insists on underscore prefixes for C function names.
+ */
+#if defined(__APPLE__)
+#define EXT(s) _##s
+#else
+#define EXT(s) s
+#endif
+
+// Apple's ld64 wants 4-byte alignment for ARM code sections.
+// .align in both Apple as and GNU as treat n as aligning to 2**n bytes.
+.align	2
+
+/*
+ * void crosscall1(void (*fn)(void), void (*setg_gcc)(void *g), void *g)
+ *
+ * Calling into the gc tool chain, where all registers are caller save.
+ * Called from standard ARM EABI, where x19-x29 are callee-save, so they
+ * must be saved explicitly, along with x30 (LR).
+ */
+.globl EXT(crosscall1)
+EXT(crosscall1):
+	stp x19, x20, [sp, #-16]!
+	stp x21, x22, [sp, #-16]!
+	stp x23, x24, [sp, #-16]!
+	stp x25, x26, [sp, #-16]!
+	stp x27, x28, [sp, #-16]!
+	stp x29, x30, [sp, #-16]!
+	mov x29, sp
+
+	mov x19, x0
+	mov x20, x1
+	mov x0, x2
+
+	blr x20
+	blr x19
+
+	ldp x29, x30, [sp], #16
+	ldp x27, x28, [sp], #16
+	ldp x25, x26, [sp], #16
+	ldp x23, x24, [sp], #16
+	ldp x21, x22, [sp], #16
+	ldp x19, x20, [sp], #16
+	ret
+
+.globl EXT(__stack_chk_fail_local)
+EXT(__stack_chk_fail_local):
+1:
+	b 1b
+
+#ifdef __ELF__
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/src/runtime/cgo/gcc_darwin_arm.c b/src/runtime/cgo/gcc_darwin_arm.c
new file mode 100644
index 0000000..c303b91
--- /dev/null
+++ b/src/runtime/cgo/gcc_darwin_arm.c
@@ -0,0 +1,153 @@
+// 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 <limits.h>
+#include <pthread.h>
+#include <signal.h>
+#include <string.h> /* for strerror */
+#include <sys/param.h>
+#include <unistd.h>
+
+#include "libcgo.h"
+
+#include <CoreFoundation/CFBundle.h>
+#include <CoreFoundation/CFString.h>
+
+#define magic (0xe696c4f4U)
+
+// inittls allocates a thread-local storage slot for g.
+//
+// It finds the first available slot using pthread_key_create and uses
+// it as the offset value for runtime.tlsg.
+static void
+inittls(void **tlsg, void **tlsbase)
+{
+	pthread_key_t k;
+	int i, err;
+
+	err = pthread_key_create(&k, nil);
+	if(err != 0) {
+		fprintf(stderr, "runtime/cgo: pthread_key_create failed: %d\n", err);
+		abort();
+	}
+	//fprintf(stderr, "runtime/cgo: k = %d, tlsbase = %p\n", (int)k, tlsbase); // debug
+	pthread_setspecific(k, (void*)magic);
+	// The first key should be at 258.
+	for (i=0; i<PTHREAD_KEYS_MAX; i++) {
+		if (*(tlsbase+i) == (void*)magic) {
+			*tlsg = (void*)(i*sizeof(void *));
+			pthread_setspecific(k, 0);
+			return;
+		}
+	}
+	fprintf(stderr, "runtime/cgo: could not find pthread key.\n");
+	abort();
+}
+
+static void *threadentry(void*);
+void (*setg_gcc)(void*);
+
+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);
+	size = 0;
+	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();
+	}
+}
+
+extern void crosscall_arm1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
+static void*
+threadentry(void *v)
+{
+	ThreadStart ts;
+
+	ts = *(ThreadStart*)v;
+	free(v);
+
+	darwin_arm_init_thread_exception_port();
+
+	crosscall_arm1(ts.fn, setg_gcc, (void*)ts.g);
+	return nil;
+}
+
+// init_working_dir sets the current working directory to the app root.
+// By default darwin/arm processes start in "/".
+static void
+init_working_dir()
+{
+	CFBundleRef bundle = CFBundleGetMainBundle();
+	if (bundle == NULL) {
+		fprintf(stderr, "runtime/cgo: no main bundle\n");
+		return;
+	}
+	CFURLRef url_ref = CFBundleCopyResourceURL(bundle, CFSTR("Info"), CFSTR("plist"), NULL);
+	if (url_ref == NULL) {
+		fprintf(stderr, "runtime/cgo: no Info.plist URL\n");
+		return;
+	}
+	CFStringRef url_str_ref = CFURLGetString(url_ref);
+	char url[MAXPATHLEN];
+        if (!CFStringGetCString(url_str_ref, url, sizeof(url), kCFStringEncodingUTF8)) {
+		fprintf(stderr, "runtime/cgo: cannot get URL string\n");
+		return;
+	}
+
+	// url is of the form "file:///path/to/Info.plist".
+	// strip it down to the working directory "/path/to".
+	int url_len = strlen(url);
+	if (url_len < sizeof("file://")+sizeof("/Info.plist")) {
+		fprintf(stderr, "runtime/cgo: bad URL: %s\n", url);
+		return;
+	}
+	url[url_len-sizeof("/Info.plist")+1] = 0;
+	char *dir = &url[0] + sizeof("file://")-1;
+
+	if (chdir(dir) != 0) {
+		fprintf(stderr, "runtime/cgo: chdir(%s) failed\n", dir);
+	}
+
+	// No-op to set a breakpoint on, immediately after the real chdir.
+	// Gives the test harness in go_darwin_arm_exec (which uses lldb) a
+	// chance to move the working directory.
+	getwd(dir);
+}
+
+void
+x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase)
+{
+	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);
+
+	// 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_darwin_arm64.c b/src/runtime/cgo/gcc_darwin_arm64.c
new file mode 100644
index 0000000..b64a063
--- /dev/null
+++ b/src/runtime/cgo/gcc_darwin_arm64.c
@@ -0,0 +1,157 @@
+// 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 <limits.h>
+#include <pthread.h>
+#include <signal.h>
+#include <string.h> /* for strerror */
+#include <sys/param.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "libcgo.h"
+
+#include <CoreFoundation/CFBundle.h>
+#include <CoreFoundation/CFString.h>
+
+#define magic (0xc476c475c47957UL)
+
+// inittls allocates a thread-local storage slot for g.
+//
+// It finds the first available slot using pthread_key_create and uses
+// it as the offset value for runtime.tlsg.
+static void
+inittls(void **tlsg, void **tlsbase)
+{
+	pthread_key_t k;
+	int i, err;
+
+	err = pthread_key_create(&k, nil);
+	if(err != 0) {
+		fprintf(stderr, "runtime/cgo: pthread_key_create failed: %d\n", err);
+		abort();
+	}
+	//fprintf(stderr, "runtime/cgo: k = %d, tlsbase = %p\n", (int)k, tlsbase); // debug
+	pthread_setspecific(k, (void*)magic);
+	// The first key should be at 257.
+	for (i=0; i<PTHREAD_KEYS_MAX; i++) {
+		if (*(tlsbase+i) == (void*)magic) {
+			*tlsg = (void*)(i*sizeof(void *));
+			pthread_setspecific(k, 0);
+			return;
+		}
+	}
+	fprintf(stderr, "runtime/cgo: could not find pthread key.\n");
+	abort();
+}
+
+static void *threadentry(void*);
+void (*setg_gcc)(void*);
+
+void
+_cgo_sys_thread_start(ThreadStart *ts)
+{
+	pthread_attr_t attr;
+	sigset_t ign, oset;
+	pthread_t p;
+	size_t size;
+	int err;
+
+	//fprintf(stderr, "runtime/cgo: _cgo_sys_thread_start: fn=%p, g=%p\n", ts->fn, ts->g); // debug
+	sigfillset(&ign);
+	pthread_sigmask(SIG_SETMASK, &ign, &oset);
+
+	pthread_attr_init(&attr);
+	size = 0;
+	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();
+	}
+}
+
+extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
+static void*
+threadentry(void *v)
+{
+	ThreadStart ts;
+
+	ts = *(ThreadStart*)v;
+	free(v);
+
+	darwin_arm_init_thread_exception_port();
+
+	crosscall1(ts.fn, setg_gcc, (void*)ts.g);
+	return nil;
+}
+
+// init_working_dir sets the current working directory to the app root.
+// By default darwin/arm processes start in "/".
+static void
+init_working_dir()
+{
+	CFBundleRef bundle = CFBundleGetMainBundle();
+	if (bundle == NULL) {
+		fprintf(stderr, "runtime/cgo: no main bundle\n");
+		return;
+	}
+	CFURLRef url_ref = CFBundleCopyResourceURL(bundle, CFSTR("Info"), CFSTR("plist"), NULL);
+	if (url_ref == NULL) {
+		fprintf(stderr, "runtime/cgo: no Info.plist URL\n");
+		return;
+	}
+	CFStringRef url_str_ref = CFURLGetString(url_ref);
+	char url[MAXPATHLEN];
+        if (!CFStringGetCString(url_str_ref, url, sizeof(url), kCFStringEncodingUTF8)) {
+		fprintf(stderr, "runtime/cgo: cannot get URL string\n");
+		return;
+	}
+
+	// url is of the form "file:///path/to/Info.plist".
+	// strip it down to the working directory "/path/to".
+	int url_len = strlen(url);
+	if (url_len < sizeof("file://")+sizeof("/Info.plist")) {
+		fprintf(stderr, "runtime/cgo: bad URL: %s\n", url);
+		return;
+	}
+	url[url_len-sizeof("/Info.plist")+1] = 0;
+	char *dir = &url[0] + sizeof("file://")-1;
+
+	if (chdir(dir) != 0) {
+		fprintf(stderr, "runtime/cgo: chdir(%s) failed\n", dir);
+	}
+
+	// No-op to set a breakpoint on, immediately after the real chdir.
+	// Gives the test harness in go_darwin_arm_exec (which uses lldb) a
+	// chance to move the working directory.
+	getwd(dir);
+}
+
+void
+x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase)
+{
+	pthread_attr_t attr;
+	size_t size;
+
+	//fprintf(stderr, "x_cgo_init = %p\n", &x_cgo_init); // aid debugging in presence of ASLR
+	setg_gcc = setg;
+	pthread_attr_init(&attr);
+	pthread_attr_getstacksize(&attr, &size);
+	g->stacklo = (uintptr)&attr - size + 4096;
+	pthread_attr_destroy(&attr);
+
+	// yes, tlsbase from mrs might not be correctly aligned.
+	inittls(tlsg, (void**)((uintptr)tlsbase & ~7));
+
+	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_libinit.c b/src/runtime/cgo/gcc_libinit.c
new file mode 100644
index 0000000..c3e94f5
--- /dev/null
+++ b/src/runtime/cgo/gcc_libinit.c
@@ -0,0 +1,42 @@
+// 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 solaris
+// +build !ppc64,!ppc64le
+
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h> // strerror
+
+static pthread_cond_t runtime_init_cond = PTHREAD_COND_INITIALIZER;
+static pthread_mutex_t runtime_init_mu = PTHREAD_MUTEX_INITIALIZER;
+static int runtime_init_done;
+
+void
+x_cgo_sys_thread_create(void* (*func)(void*), void* arg) {
+	pthread_t p;
+	int err = pthread_create(&p, NULL, func, arg);
+	if (err != 0) {
+		fprintf(stderr, "pthread_create failed: %s", strerror(err));
+		abort();
+	}
+}
+
+void
+_cgo_wait_runtime_init_done() {
+	pthread_mutex_lock(&runtime_init_mu);
+	while (runtime_init_done == 0) {
+		pthread_cond_wait(&runtime_init_cond, &runtime_init_mu);
+	}
+	pthread_mutex_unlock(&runtime_init_mu);
+}
+
+void
+x_cgo_notify_runtime_init_done(void* dummy) {
+	pthread_mutex_lock(&runtime_init_mu);
+	runtime_init_done = 1;
+	pthread_cond_broadcast(&runtime_init_cond);
+	pthread_mutex_unlock(&runtime_init_mu);
+}
diff --git a/src/runtime/cgo/gcc_libinit_linux_ppc64x.c b/src/runtime/cgo/gcc_libinit_linux_ppc64x.c
new file mode 100644
index 0000000..82413a5
--- /dev/null
+++ b/src/runtime/cgo/gcc_libinit_linux_ppc64x.c
@@ -0,0 +1,26 @@
+// 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.
+
+// TODO: see issue #10410
+// +build linux
+// +build ppc64 ppc64le
+
+#include <stdio.h>
+#include <stdlib.h>
+
+void
+x_cgo_sys_thread_create(void* (*func)(void*), void* arg) {
+	fprintf(stderr, "x_cgo_sys_thread_create not implemented");
+	abort();
+}
+
+void
+_cgo_wait_runtime_init_done() {
+	// TODO(spetrovic): implement this method.
+}
+
+void
+x_cgo_notify_runtime_init_done(void* dummy) {
+	// TODO(spetrovic): implement this method.
+}
\ No newline at end of file
diff --git a/src/runtime/cgo/gcc_libinit_openbsd.c b/src/runtime/cgo/gcc_libinit_openbsd.c
new file mode 100644
index 0000000..7e5b646
--- /dev/null
+++ b/src/runtime/cgo/gcc_libinit_openbsd.c
@@ -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.
+
+#include <stdio.h>
+#include <stdlib.h>
+
+void
+x_cgo_sys_thread_create(void* (*func)(void*), void* arg) {
+	fprintf(stderr, "x_cgo_sys_thread_create not implemented");
+	abort();
+}
+
+void
+_cgo_wait_runtime_init_done() {
+	// TODO(spetrovic): implement this method.
+}
+
+void
+x_cgo_notify_runtime_init_done(void* dummy) {
+	// TODO(spetrovic): implement this method.
+}
\ No newline at end of file
diff --git a/src/runtime/cgo/gcc_libinit_windows.c b/src/runtime/cgo/gcc_libinit_windows.c
new file mode 100644
index 0000000..7e5b646
--- /dev/null
+++ b/src/runtime/cgo/gcc_libinit_windows.c
@@ -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.
+
+#include <stdio.h>
+#include <stdlib.h>
+
+void
+x_cgo_sys_thread_create(void* (*func)(void*), void* arg) {
+	fprintf(stderr, "x_cgo_sys_thread_create not implemented");
+	abort();
+}
+
+void
+_cgo_wait_runtime_init_done() {
+	// TODO(spetrovic): implement this method.
+}
+
+void
+x_cgo_notify_runtime_init_done(void* dummy) {
+	// TODO(spetrovic): implement this method.
+}
\ No newline at end of file
diff --git a/src/runtime/cgo/gcc_linux_arm64.c b/src/runtime/cgo/gcc_linux_arm64.c
new file mode 100644
index 0000000..ea11cf5
--- /dev/null
+++ b/src/runtime/cgo/gcc_linux_arm64.c
@@ -0,0 +1,73 @@
+// 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 <pthread.h>
+#include <string.h>
+#include <signal.h>
+#include "libcgo.h"
+
+static void *threadentry(void*);
+
+void (*x_cgo_inittls)(void **tlsg, void **tlsbase);
+void (*setg_gcc)(void*);
+
+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);
+
+	// Not sure why the memset is necessary here,
+	// but without it, we get a bogus stack size
+	// out of pthread_attr_getstacksize.  C'est la Linux.
+	memset(&attr, 0, sizeof attr);
+	pthread_attr_init(&attr);
+	size = 0;
+	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) {
+		fatalf("pthread_create failed: %s", strerror(err));
+	}
+}
+
+extern void crosscall1(void (*fn)(void), void (*setg_gcc)(void*), void *g);
+static void*
+threadentry(void *v)
+{
+	ThreadStart ts;
+
+	ts = *(ThreadStart*)v;
+	free(v);
+
+	crosscall1(ts.fn, setg_gcc, (void*)ts.g);
+	return nil;
+}
+
+void
+x_cgo_init(G *g, void (*setg)(void*), void **tlsg, void **tlsbase)
+{
+	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);
+
+	if (x_cgo_inittls) {
+		x_cgo_inittls(tlsg, tlsbase);
+	}
+}
diff --git a/src/runtime/cgo/gcc_linux_ppc64x.c b/src/runtime/cgo/gcc_linux_ppc64x.c
new file mode 100644
index 0000000..b176295
--- /dev/null
+++ b/src/runtime/cgo/gcc_linux_ppc64x.c
@@ -0,0 +1,70 @@
+// 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 ppc64 ppc64le
+
+#include <pthread.h>
+#include <string.h>
+#include <signal.h>
+#include "libcgo.h"
+
+static void *threadentry(void*);
+
+void (*x_cgo_inittls)(void **tlsg, void **tlsbase);
+static void (*setg_gcc)(void*);
+
+void
+x_cgo_init(G *g, void (*setg)(void*), void **tlsbase)
+{
+	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) {
+		fatalf("pthread_create failed: %s", strerror(err));
+	}
+}
+
+extern void crosscall_ppc64(void (*fn)(void), void *g);
+
+static void*
+threadentry(void *v)
+{
+	ThreadStart ts;
+
+	ts = *(ThreadStart*)v;
+	free(v);
+
+	// Save g for this thread in C TLS
+	setg_gcc((void*)ts.g);
+
+	crosscall_ppc64(ts.fn, (void*)ts.g);
+	return nil;
+}
diff --git a/src/runtime/cgo/gcc_ppc64x.S b/src/runtime/cgo/gcc_ppc64x.S
new file mode 100644
index 0000000..05af070
--- /dev/null
+++ b/src/runtime/cgo/gcc_ppc64x.S
@@ -0,0 +1,140 @@
+// 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 ppc64 ppc64le
+
+/*
+ * Apple still insists on underscore prefixes for C function names.
+ */
+#if defined(__APPLE__)
+#define EXT(s) _##s
+#else
+#define EXT(s) s
+#endif
+
+/*
+ * void crosscall_ppc64(void (*fn)(void), void *g)
+ *
+ * Calling into the gc tool chain, where all registers are caller save.
+ * Called from standard ppc64 C ABI, where r2, r14-r31, f14-f31 are
+ * callee-save, so they must be saved explicitly.
+ */
+.globl EXT(crosscall_ppc64)
+EXT(crosscall_ppc64):
+	// Start with standard C stack frame layout and linkage
+	mflr	%r0
+	std	%r0, 16(%r1)	// Save LR in caller's frame
+	std	%r2, 24(%r1)	// Save TOC in caller's frame
+	bl	saveregs
+	stdu	%r1, -296(%r1)
+
+	// Set up Go ABI constant registers
+	bl	_cgo_reginit
+
+	// Restore g pointer (r30 in Go ABI, which may have been clobbered by C)
+	mr	%r30, %r4
+
+	// Call fn
+	mtctr	%r3
+	bctrl
+
+	addi	%r1, %r1, 296
+	bl	restoreregs
+	ld	%r2, 24(%r1)
+	ld	%r0, 16(%r1)
+	mtlr	%r0
+	blr
+
+saveregs:
+	// Save callee-save registers
+	// O=-288; for R in %r{14..31}; do echo "\tstd\t$R, $O(%r1)"; ((O+=8)); done; for F in f{14..31}; do echo "\tstfd\t$F, $O(%r1)"; ((O+=8)); done
+	std	%r14, -288(%r1)
+	std	%r15, -280(%r1)
+	std	%r16, -272(%r1)
+	std	%r17, -264(%r1)
+	std	%r18, -256(%r1)
+	std	%r19, -248(%r1)
+	std	%r20, -240(%r1)
+	std	%r21, -232(%r1)
+	std	%r22, -224(%r1)
+	std	%r23, -216(%r1)
+	std	%r24, -208(%r1)
+	std	%r25, -200(%r1)
+	std	%r26, -192(%r1)
+	std	%r27, -184(%r1)
+	std	%r28, -176(%r1)
+	std	%r29, -168(%r1)
+	std	%r30, -160(%r1)
+	std	%r31, -152(%r1)
+	stfd	%f14, -144(%r1)
+	stfd	%f15, -136(%r1)
+	stfd	%f16, -128(%r1)
+	stfd	%f17, -120(%r1)
+	stfd	%f18, -112(%r1)
+	stfd	%f19, -104(%r1)
+	stfd	%f20, -96(%r1)
+	stfd	%f21, -88(%r1)
+	stfd	%f22, -80(%r1)
+	stfd	%f23, -72(%r1)
+	stfd	%f24, -64(%r1)
+	stfd	%f25, -56(%r1)
+	stfd	%f26, -48(%r1)
+	stfd	%f27, -40(%r1)
+	stfd	%f28, -32(%r1)
+	stfd	%f29, -24(%r1)
+	stfd	%f30, -16(%r1)
+	stfd	%f31, -8(%r1)
+
+	blr
+
+restoreregs:
+	// O=-288; for R in %r{14..31}; do echo "\tld\t$R, $O(%r1)"; ((O+=8)); done; for F in %f{14..31}; do echo "\tlfd\t$F, $O(%r1)"; ((O+=8)); done
+	ld	%r14, -288(%r1)
+	ld	%r15, -280(%r1)
+	ld	%r16, -272(%r1)
+	ld	%r17, -264(%r1)
+	ld	%r18, -256(%r1)
+	ld	%r19, -248(%r1)
+	ld	%r20, -240(%r1)
+	ld	%r21, -232(%r1)
+	ld	%r22, -224(%r1)
+	ld	%r23, -216(%r1)
+	ld	%r24, -208(%r1)
+	ld	%r25, -200(%r1)
+	ld	%r26, -192(%r1)
+	ld	%r27, -184(%r1)
+	ld	%r28, -176(%r1)
+	ld	%r29, -168(%r1)
+	ld	%r30, -160(%r1)
+	ld	%r31, -152(%r1)
+	lfd	%f14, -144(%r1)
+	lfd	%f15, -136(%r1)
+	lfd	%f16, -128(%r1)
+	lfd	%f17, -120(%r1)
+	lfd	%f18, -112(%r1)
+	lfd	%f19, -104(%r1)
+	lfd	%f20, -96(%r1)
+	lfd	%f21, -88(%r1)
+	lfd	%f22, -80(%r1)
+	lfd	%f23, -72(%r1)
+	lfd	%f24, -64(%r1)
+	lfd	%f25, -56(%r1)
+	lfd	%f26, -48(%r1)
+	lfd	%f27, -40(%r1)
+	lfd	%f28, -32(%r1)
+	lfd	%f29, -24(%r1)
+	lfd	%f30, -16(%r1)
+	lfd	%f31, -8(%r1)
+
+	blr
+
+.globl EXT(__stack_chk_fail_local)
+EXT(__stack_chk_fail_local):
+1:
+	// TODO(austin)
+	b 1b
+
+#ifdef __ELF__
+.section .note.GNU-stack,"",%progbits
+#endif
diff --git a/src/runtime/cgo/gcc_setenv.c b/src/runtime/cgo/gcc_setenv.c
index af0fc5d..ca29dcb 100644
--- a/src/runtime/cgo/gcc_setenv.c
+++ b/src/runtime/cgo/gcc_setenv.c
@@ -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 netbsd openbsd
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
 
 #include "libcgo.h"
 
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..e36fe26
--- /dev/null
+++ b/src/runtime/cgo/gcc_signal_darwin_armx.c
@@ -0,0 +1,205 @@
+// 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.
+//
+// The dist tool enables this by build flag when testing.
+
+// +build lldb
+// +build darwin
+// +build arm arm64
+
+#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.
+#ifdef __arm64__
+	thread_state.ts_64.__x[1] = thread_state.ts_64.__lr;
+	thread_state.ts_64.__x[2] = thread_state.ts_64.__pc;
+	thread_state.ts_64.__pc = x_cgo_panicmem;
+#else
+	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;
+#endif
+
+	if (0) {
+		// Useful debugging logic when panicmem is broken.
+		//
+		// Sends the first SIGSEGV and lets lldb catch the
+		// second one, avoiding a loop that locks up iOS
+		// devices requiring a hard reboot.
+		fprintf(stderr, "runtime/cgo: caught exc_bad_access\n");
+		fprintf(stderr, "__lr = %llx\n", thread_state.ts_64.__lr);
+		fprintf(stderr, "__pc = %llx\n", thread_state.ts_64.__pc);
+		static int pass1 = 0;
+		if (pass1) {
+			return KERN_FAILURE;
+		}
+		pass1 = 1;
+	}
+
+	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.
+	uintptr_t port_set = (uintptr_t)mach_exception_handler_port_set;
+	pthread_attr_init(&attr);
+	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+	ret = pthread_create(&thr, &attr, mach_exception_handler, (void*)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..b26315f
--- /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 !lldb
+// +build darwin
+// +build arm arm64
+
+#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/gcc_solaris_amd64.c b/src/runtime/cgo/gcc_solaris_amd64.c
new file mode 100644
index 0000000..72ace56
--- /dev/null
+++ b/src/runtime/cgo/gcc_solaris_amd64.c
@@ -0,0 +1,75 @@
+// 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 <pthread.h>
+#include <string.h>
+#include <signal.h>
+#include <ucontext.h>
+#include "libcgo.h"
+
+static void* threadentry(void*);
+static void (*setg_gcc)(void*);
+
+void
+x_cgo_init(G *g, void (*setg)(void*))
+{
+	ucontext_t ctx;
+
+	setg_gcc = setg;
+	if (getcontext(&ctx) != 0)
+		perror("runtime/cgo: getcontext failed");
+	g->stacklo = (uintptr_t)ctx.uc_stack.ss_sp;
+}
+
+void
+_cgo_sys_thread_start(ThreadStart *ts)
+{
+	pthread_attr_t attr;
+	sigset_t ign, oset;
+	pthread_t p;
+	void *base;
+	size_t size;
+	int err;
+
+	sigfillset(&ign);
+	pthread_sigmask(SIG_SETMASK, &ign, &oset);
+
+	pthread_attr_init(&attr);
+
+	if (pthread_attr_getstack(&attr, &base, &size) != 0)
+		perror("runtime/cgo: pthread_attr_getstack failed");
+	if (size == 0) {
+		ts->g->stackhi = 2 << 20;
+		if (pthread_attr_setstack(&attr, NULL, ts->g->stackhi) != 0)
+			perror("runtime/cgo: pthread_attr_setstack failed");
+	} else {
+		ts->g->stackhi = size;
+	}
+	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+	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_amd64(ts.fn);
+	return nil;
+}
diff --git a/src/runtime/cgo/iscgo.c b/src/runtime/cgo/iscgo.c
deleted file mode 100644
index 0907a19..0000000
--- a/src/runtime/cgo/iscgo.c
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright 2010 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.
-
-// The runtime package contains an uninitialized definition
-// for runtime·iscgo.  Override it to tell the runtime we're here.
-// There are various function pointers that should be set too,
-// but those depend on dynamic linker magic to get initialized
-// correctly, and sometimes they break.  This variable is a
-// backup: it depends only on old C style static linking rules.
-
-#include "../runtime.h"
-
-bool runtime·iscgo = 1;
-uint32 runtime·needextram = 1;  // create an extra M on first cgo call
diff --git a/src/runtime/cgo/iscgo.go b/src/runtime/cgo/iscgo.go
new file mode 100644
index 0000000..54f0a13
--- /dev/null
+++ b/src/runtime/cgo/iscgo.go
@@ -0,0 +1,17 @@
+// Copyright 2010 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.
+
+// The runtime package contains an uninitialized definition
+// for runtime·iscgo.  Override it to tell the runtime we're here.
+// There are various function pointers that should be set too,
+// but those depend on dynamic linker magic to get initialized
+// correctly, and sometimes they break.  This variable is a
+// backup: it depends only on old C style static linking rules.
+
+package cgo
+
+import _ "unsafe" // for go:linkname
+
+//go:linkname _iscgo runtime.iscgo
+var _iscgo bool = true
diff --git a/src/runtime/cgo/libcgo.h b/src/runtime/cgo/libcgo.h
index 9d918fd..bda2499 100644
--- a/src/runtime/cgo/libcgo.h
+++ b/src/runtime/cgo/libcgo.h
@@ -45,11 +45,22 @@ struct ThreadStart
 extern void (*_cgo_thread_start)(ThreadStart *ts);
 
 /*
+ * Creates a new operating system thread without updating any Go state
+ * (OS dependent).
+ */
+extern void (*_cgo_sys_thread_create)(void* (*func)(void*), void* arg);
+
+/*
  * Creates the new operating system thread (OS, arch dependent).
  */
 void _cgo_sys_thread_start(ThreadStart *ts);
 
 /*
+ * Waits for the Go runtime to be initialized (OS dependent).
+ */
+void _cgo_wait_runtime_init_done();
+
+/*
  * Call fn in the 6c world.
  */
 void crosscall_amd64(void (*fn)(void));
@@ -63,3 +74,13 @@ void crosscall_386(void (*fn)(void));
  * 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/netbsd.c b/src/runtime/cgo/netbsd.c
deleted file mode 100644
index 076cc87..0000000
--- a/src/runtime/cgo/netbsd.c
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2010 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 netbsd
-
-#include "textflag.h"
-
-// Supply environ and __progname, because we don't
-// link against the standard NetBSD crt0.o and the
-// libc dynamic library needs them.
-
-#pragma dataflag NOPTR
-char *environ[1];
-#pragma dataflag NOPTR
-char *__progname;
-
-#pragma dynexport environ environ
-#pragma dynexport __progname __progname
diff --git a/src/runtime/cgo/netbsd.go b/src/runtime/cgo/netbsd.go
new file mode 100644
index 0000000..ac6b18a
--- /dev/null
+++ b/src/runtime/cgo/netbsd.go
@@ -0,0 +1,19 @@
+// Copyright 2010 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 netbsd
+
+package cgo
+
+import _ "unsafe" // for go:linkname
+
+// Supply environ and __progname, because we don't
+// link against the standard NetBSD crt0.o and the
+// libc dynamic library needs them.
+
+//go:linkname _environ environ
+//go:linkname _progname __progname
+
+var _environ uintptr
+var _progname uintptr
diff --git a/src/runtime/cgo/openbsd.c b/src/runtime/cgo/openbsd.c
deleted file mode 100644
index 4766495..0000000
--- a/src/runtime/cgo/openbsd.c
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2010 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 openbsd
-
-#include "textflag.h"
-
-// Supply environ, __progname and __guard_local, because
-// we don't link against the standard OpenBSD crt0.o and
-// the libc dynamic library needs them.
-
-#pragma dataflag NOPTR
-char *environ[1];
-#pragma dataflag NOPTR
-char *__progname;
-long __guard_local;
-
-#pragma dynexport environ environ
-#pragma dynexport __progname __progname
-
-// This is normally marked as hidden and placed in the
-// .openbsd.randomdata section.
-#pragma dynexport __guard_local __guard_local
-
-// We override pthread_create to support PT_TLS.
-#pragma dynexport pthread_create pthread_create
diff --git a/src/runtime/cgo/openbsd.go b/src/runtime/cgo/openbsd.go
new file mode 100644
index 0000000..61af3a8
--- /dev/null
+++ b/src/runtime/cgo/openbsd.go
@@ -0,0 +1,31 @@
+// Copyright 2010 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 openbsd
+
+package cgo
+
+import _ "unsafe" // for go:linkname
+
+// Supply environ, __progname and __guard_local, because
+// we don't link against the standard OpenBSD crt0.o and
+// the libc dynamic library needs them.
+
+//go:linkname _environ environ
+//go:linkname _progname __progname
+//go:linkname _guard_local __guard_local
+
+var _environ uintptr
+var _progname uintptr
+var _guard_local uintptr
+
+//go:cgo_export_dynamic environ environ
+//go:cgo_export_dynamic __progname __progname
+
+// This is normally marked as hidden and placed in the
+// .openbsd.randomdata section.
+//go:cgo_export_dynamic __guard_local __guard_local
+
+// We override pthread_create to support PT_TLS.
+//go:cgo_export_dynamic pthread_create pthread_create
diff --git a/src/runtime/cgo/setenv.c b/src/runtime/cgo/setenv.c
deleted file mode 100644
index 76d88cb..0000000
--- a/src/runtime/cgo/setenv.c
+++ /dev/null
@@ -1,13 +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.
-
-// +build darwin dragonfly freebsd linux netbsd openbsd
-
-#pragma cgo_import_static x_cgo_setenv
-#pragma cgo_import_static x_cgo_unsetenv
-
-void x_cgo_setenv(char**);
-void (*runtime·_cgo_setenv)(char**) = x_cgo_setenv;
-void x_cgo_unsetenv(char**);
-void (*runtime·_cgo_unsetenv)(char**) = x_cgo_unsetenv;
diff --git a/src/runtime/cgo/setenv.go b/src/runtime/cgo/setenv.go
new file mode 100644
index 0000000..20d5703
--- /dev/null
+++ b/src/runtime/cgo/setenv.go
@@ -0,0 +1,21 @@
+// 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.
+
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+
+package cgo
+
+import _ "unsafe" // for go:linkname
+
+//go:cgo_import_static x_cgo_setenv
+//go:linkname x_cgo_setenv x_cgo_setenv
+//go:linkname _cgo_setenv runtime._cgo_setenv
+var x_cgo_setenv byte
+var _cgo_setenv = &x_cgo_setenv
+
+//go:cgo_import_static x_cgo_unsetenv
+//go:linkname x_cgo_unsetenv x_cgo_unsetenv
+//go:linkname _cgo_unsetenv runtime._cgo_unsetenv
+var x_cgo_unsetenv byte
+var _cgo_unsetenv = &x_cgo_unsetenv
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_arm64.s b/src/runtime/cgo/signal_darwin_arm64.s
new file mode 100644
index 0000000..75aefd4
--- /dev/null
+++ b/src/runtime/cgo/signal_darwin_arm64.s
@@ -0,0 +1,56 @@
+// 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,$-8
+	// 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.
+	// TODO(crawshaw): call badsignal
+	MOVD.W $0, -16(RSP)
+	MOVW $139, R1
+	MOVW R1, 8(RSP)
+	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.
+
+	// Build a 32-byte stack frame for us for this call.
+	// Saved LR (none available) is at the bottom,
+	// then the PC argument for setsigsegv, 
+	// then a copy of the LR for us to restore.
+	MOVD.W $0, -32(RSP)
+	MOVD R1, 8(RSP)
+	MOVD R2, 16(RSP)
+	BL runtime·setsigsegv(SB)
+	MOVD 8(RSP), R1
+	MOVD 16(RSP), R2
+
+	// Build a 16-byte stack frame for the simulated
+	// call to sigpanic, by taking 16 bytes away from the
+	// 32-byte stack frame above.
+	// The saved LR in this frame is the LR at time of fault,
+	// and the LR on entry to sigpanic is the PC at time of fault.
+	MOVD.W R1, 16(RSP)
+	MOVD R2, R30
+	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 7fd9146..f09a66a 100644
--- a/src/runtime/cgocall.go
+++ b/src/runtime/cgocall.go
@@ -83,29 +83,19 @@ import "unsafe"
 
 // Call from Go to C.
 //go:nosplit
-func cgocall(fn, arg unsafe.Pointer) {
-	cgocall_errno(fn, arg)
-}
-
-//go:nosplit
-func cgocall_errno(fn, arg unsafe.Pointer) int32 {
+func cgocall(fn, arg unsafe.Pointer) int32 {
 	if !iscgo && GOOS != "solaris" && GOOS != "windows" {
-		gothrow("cgocall unavailable")
+		throw("cgocall unavailable")
 	}
 
 	if fn == nil {
-		gothrow("cgocall nil")
+		throw("cgocall nil")
 	}
 
 	if raceenabled {
 		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) {
-		onM(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.
@@ -127,9 +117,9 @@ func cgocall_errno(fn, arg unsafe.Pointer) int32 {
 	 * so it is safe to call while "in a system call", outside
 	 * the $GOMAXPROCS accounting.
 	 */
-	entersyscall()
-	errno := asmcgocall_errno(fn, arg)
-	exitsyscall()
+	entersyscall(0)
+	errno := asmcgocall(fn, arg)
+	exitsyscall(0)
 
 	return errno
 }
@@ -137,12 +127,6 @@ func cgocall_errno(fn, arg unsafe.Pointer) int32 {
 //go:nosplit
 func endcgo(mp *m) {
 	mp.ncgo--
-	if mp.ncgo == 0 {
-		// We are going back to Go and are not in a recursive
-		// call.  Let the GC collect any memory allocated via
-		// _cgo_allocate that is no longer referenced.
-		mp.cgomal = nil
-	}
 
 	if raceenabled {
 		raceacquire(unsafe.Pointer(&racecgosync))
@@ -153,25 +137,21 @@ func endcgo(mp *m) {
 
 // Helper functions for cgo code.
 
-// Filled by schedinit from corresponding C variables,
-// which are in turn filled in by dynamic linker when Cgo is available.
-var cgoMalloc, cgoFree unsafe.Pointer
-
 func cmalloc(n uintptr) unsafe.Pointer {
 	var args struct {
 		n   uint64
 		ret unsafe.Pointer
 	}
 	args.n = uint64(n)
-	cgocall(cgoMalloc, unsafe.Pointer(&args))
+	cgocall(_cgo_malloc, unsafe.Pointer(&args))
 	if args.ret == nil {
-		gothrow("C malloc failed")
+		throw("C malloc failed")
 	}
 	return args.ret
 }
 
 func cfree(p unsafe.Pointer) {
-	cgocall(cgoFree, p)
+	cgocall(_cgo_free, p)
 }
 
 // Call from C back to Go.
@@ -183,23 +163,37 @@ func cgocallbackg() {
 		exit(2)
 	}
 
+	// Save current syscall parameters, so m.syscall can be
+	// used again if callback decide to make syscall.
+	syscall := gp.m.syscall
+
 	// entersyscall saves the caller's SP to allow the GC to trace the Go
 	// stack. However, since we're returning to an earlier stack frame and
 	// need to pair with the entersyscall() call made by cgocall, we must
 	// save syscall* and let reentersyscall restore them.
 	savedsp := unsafe.Pointer(gp.syscallsp)
 	savedpc := gp.syscallpc
-	exitsyscall() // coming out of cgo call
+	exitsyscall(0) // coming out of cgo call
 	cgocallbackg1()
 	// going back to cgo call
-	reentersyscall(savedpc, savedsp)
+	reentersyscall(savedpc, uintptr(savedsp))
+
+	gp.m.syscall = syscall
 }
 
 func cgocallbackg1() {
 	gp := getg()
 	if gp.m.needextram {
 		gp.m.needextram = false
-		onM(newextram)
+		systemstack(newextram)
+	}
+
+	if gp.m.ncgo == 0 {
+		// The C call to Go came from a thread not currently running
+		// any Go. In the case of -buildmode=c-archive or c-shared,
+		// this call may be coming in before package initialization
+		// is complete. Wait until it is.
+		<-main_init_done
 	}
 
 	// Add entry to defer stack in case of panic.
@@ -222,21 +216,40 @@ func cgocallbackg1() {
 	sp := gp.m.g0.sched.sp
 	switch GOARCH {
 	default:
-		gothrow("cgocallbackg is unimplemented on arch")
+		throw("cgocallbackg is unimplemented on arch")
 	case "arm":
 		// On arm, stack frame is two words and there's a saved LR between
 		// SP and the stack frame and between the stack frame and the arguments.
 		cb = (*args)(unsafe.Pointer(sp + 4*ptrSize))
+	case "arm64":
+		// On arm64, stack frame is four words and there's a saved LR between
+		// SP and the stack frame and between the stack frame and the arguments.
+		cb = (*args)(unsafe.Pointer(sp + 5*ptrSize))
 	case "amd64":
 		// On amd64, stack frame is one word, plus caller PC.
+		if framepointer_enabled {
+			// In this case, there's also saved BP.
+			cb = (*args)(unsafe.Pointer(sp + 3*ptrSize))
+			break
+		}
 		cb = (*args)(unsafe.Pointer(sp + 2*ptrSize))
 	case "386":
 		// On 386, stack frame is three words, plus caller PC.
 		cb = (*args)(unsafe.Pointer(sp + 4*ptrSize))
+	case "ppc64", "ppc64le":
+		// On ppc64, stack frame is two words and there's a
+		// saved LR between SP and the stack frame and between
+		// the stack frame and the arguments.
+		cb = (*args)(unsafe.Pointer(sp + 4*ptrSize))
 	}
 
 	// Invoke callback.
-	reflectcall(unsafe.Pointer(cb.fn), unsafe.Pointer(cb.arg), uint32(cb.argsize), 0)
+	// NOTE(rsc): passing nil for argtype means that the copying of the
+	// results back into cb.arg happens without any corresponding write barriers.
+	// For cgo, cb.arg points into a C stack frame and therefore doesn't
+	// hold any pointers that the GC can find anyway - the write barrier
+	// would be a no-op.
+	reflectcall(nil, unsafe.Pointer(cb.fn), unsafe.Pointer(cb.arg), uint32(cb.argsize), 0)
 
 	if raceenabled {
 		racereleasemerge(unsafe.Pointer(&racecgosync))
@@ -257,23 +270,27 @@ func unwindm(restore *bool) {
 	sched := &mp.g0.sched
 	switch GOARCH {
 	default:
-		gothrow("unwindm not implemented")
+		throw("unwindm not implemented")
 	case "386", "amd64":
 		sched.sp = *(*uintptr)(unsafe.Pointer(sched.sp))
 	case "arm":
 		sched.sp = *(*uintptr)(unsafe.Pointer(sched.sp + 4))
+	case "arm64":
+		sched.sp = *(*uintptr)(unsafe.Pointer(sched.sp + 16))
+	case "ppc64", "ppc64le":
+		sched.sp = *(*uintptr)(unsafe.Pointer(sched.sp + 8))
 	}
 	releasem(mp)
 }
 
 // called from assembly
 func badcgocallback() {
-	gothrow("misaligned stack in cgocallback")
+	throw("misaligned stack in cgocallback")
 }
 
 // called from (incomplete) assembly
 func cgounimpl() {
-	gothrow("cgo not implemented")
+	throw("cgo not implemented")
 }
 
 var racecgosync uint64 // represents possible synchronization in C code
diff --git a/src/runtime/cgocall.h b/src/runtime/cgocall.h
deleted file mode 100644
index c87a9cd..0000000
--- a/src/runtime/cgocall.h
+++ /dev/null
@@ -1,13 +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.
-
-/*
- * Cgo interface.
- */
-
-void runtime·cgocall(void (*fn)(void*), void*);
-int32 runtime·cgocall_errno(void (*fn)(void*), void*);
-void runtime·cgocallback(void (*fn)(void), void*, uintptr);
-void *runtime·cmalloc(uintptr);
-void runtime·cfree(void*);
diff --git a/src/runtime/cgocallback.go b/src/runtime/cgocallback.go
index 2c89143..f93acab 100644
--- a/src/runtime/cgocallback.go
+++ b/src/runtime/cgocallback.go
@@ -4,34 +4,7 @@
 
 package runtime
 
-import "unsafe"
-
-// These functions are called from C code via cgo/callbacks.c.
-
-// Allocate memory.  This allocates the requested number of bytes in
-// memory controlled by the Go runtime.  The allocated memory will be
-// zeroed.  You are responsible for ensuring that the Go garbage
-// collector can see a pointer to the allocated memory for as long as
-// it is valid, e.g., by storing a pointer in a local variable in your
-// C function, or in memory allocated by the Go runtime.  If the only
-// pointers are in a C global variable or in memory allocated via
-// malloc, then the Go garbage collector may collect the memory.
-//
-// TODO(rsc,iant): This memory is untyped.
-// Either we need to add types or we need to stop using it.
-
-func _cgo_allocate_internal(len uintptr) unsafe.Pointer {
-	if len == 0 {
-		len = 1
-	}
-	ret := unsafe.Pointer(&make([]unsafe.Pointer, (len+ptrSize-1)/ptrSize)[0])
-	c := new(cgomal)
-	c.alloc = ret
-	gp := getg()
-	c.next = gp.m.cgomal
-	gp.m.cgomal = c
-	return ret
-}
+// These functions are called from C code via cgo/callbacks.go.
 
 // Panic.
 
diff --git a/src/runtime/chan.go b/src/runtime/chan.go
index 0eb87df..cfee12a 100644
--- a/src/runtime/chan.go
+++ b/src/runtime/chan.go
@@ -14,19 +14,41 @@ const (
 	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 {
+	return makechan(t, size)
+}
 
 func makechan(t *chantype, size int64) *hchan {
 	elem := t.elem
 
 	// compiler checks this but be safe.
 	if elem.size >= 1<<16 {
-		gothrow("makechan: invalid channel element type")
+		throw("makechan: invalid channel element type")
 	}
 	if hchanSize%maxAlign != 0 || elem.align > maxAlign {
-		gothrow("makechan: bad alignment")
+		throw("makechan: bad alignment")
 	}
-	if size < 0 || int64(uintptr(size)) != size || (elem.size > 0 && uintptr(size) > (maxmem-hchanSize)/uintptr(elem.size)) {
+	if size < 0 || int64(uintptr(size)) != size || (elem.size > 0 && uintptr(size) > (_MaxMem-hchanSize)/uintptr(elem.size)) {
 		panic("makechan: size out of range")
 	}
 
@@ -39,13 +61,15 @@ func makechan(t *chantype, size int64) *hchan {
 		// 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 {
-			c.buf = (*uint8)(unsafe.Pointer(c)) // race detector uses this location for synchronization
+			// race detector uses this location for synchronization
+			// Also prevents us from pointing beyond the allocation (see issue 9401).
+			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
@@ -59,7 +83,7 @@ func makechan(t *chantype, size int64) *hchan {
 
 // 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
@@ -89,8 +113,8 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin
 		if !block {
 			return false
 		}
-		gopark(nil, nil, "chan send (nil chan)")
-		gothrow("unreachable")
+		gopark(nil, nil, "chan send (nil chan)", traceEvGoStop, 2)
+		throw("unreachable")
 	}
 
 	if debugChan {
@@ -141,14 +165,13 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin
 
 			recvg := sg.g
 			if sg.elem != nil {
-				memmove(unsafe.Pointer(sg.elem), ep, uintptr(c.elemsize))
-				sg.elem = nil
+				syncsend(c, sg, ep)
 			}
 			recvg.param = unsafe.Pointer(sg)
 			if sg.releasetime != 0 {
 				sg.releasetime = cputicks()
 			}
-			goready(recvg)
+			goready(recvg, 3)
 			return true
 		}
 
@@ -171,16 +194,16 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin
 		mysg.selectdone = nil
 		gp.param = nil
 		c.sendq.enqueue(mysg)
-		goparkunlock(&c.lock, "chan send")
+		goparkunlock(&c.lock, "chan send", traceEvGoBlockSend, 3)
 
 		// someone woke us up.
 		if mysg != gp.waiting {
-			gothrow("G waiting list is corrupted!")
+			throw("G waiting list is corrupted!")
 		}
 		gp.waiting = nil
 		if gp.param == nil {
 			if c.closed == 0 {
-				gothrow("chansend: spurious wakeup")
+				throw("chansend: spurious wakeup")
 			}
 			panic("send on closed channel")
 		}
@@ -195,7 +218,7 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin
 	// 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
@@ -210,7 +233,7 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin
 		mysg.elem = nil
 		mysg.selectdone = nil
 		c.sendq.enqueue(mysg)
-		goparkunlock(&c.lock, "chan send")
+		goparkunlock(&c.lock, "chan send", traceEvGoBlockSend|futile, 3)
 
 		// someone woke us up - try again
 		if mysg.releasetime > 0 {
@@ -229,7 +252,7 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin
 		raceacquire(chanbuf(c, c.sendx))
 		racerelease(chanbuf(c, c.sendx))
 	}
-	memmove(chanbuf(c, c.sendx), ep, uintptr(c.elemsize))
+	typedmemmove(c.elemtype, chanbuf(c, c.sendx), ep)
 	c.sendx++
 	if c.sendx == c.dataqsiz {
 		c.sendx = 0
@@ -244,7 +267,7 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin
 		if sg.releasetime != 0 {
 			sg.releasetime = cputicks()
 		}
-		goready(recvg)
+		goready(recvg, 3)
 	} else {
 		unlock(&c.lock)
 	}
@@ -254,6 +277,21 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin
 	return true
 }
 
+func syncsend(c *hchan, sg *sudog, elem unsafe.Pointer) {
+	// Send on unbuffered channel is the only operation
+	// in the entire runtime where one goroutine
+	// writes to the stack of another goroutine. The GC assumes that
+	// stack writes only happen when the goroutine is running and are
+	// only done by that goroutine. Using a write barrier is sufficient to
+	// make up for violating that assumption, but the write barrier has to work.
+	// typedmemmove will call heapBitsBulkBarrier, but the target bytes
+	// are not in the heap, so that will not help. We arrange to call
+	// memmove and typeBitsBulkBarrier instead.
+	memmove(sg.elem, elem, c.elemtype.size)
+	typeBitsBulkBarrier(c.elemtype, uintptr(sg.elem), c.elemtype.size)
+	sg.elem = nil
+}
+
 func closechan(c *hchan) {
 	if c == nil {
 		panic("close of nil channel")
@@ -285,7 +323,7 @@ func closechan(c *hchan) {
 		if sg.releasetime != 0 {
 			sg.releasetime = cputicks()
 		}
-		goready(gp)
+		goready(gp, 3)
 	}
 
 	// release all writers
@@ -300,7 +338,7 @@ func closechan(c *hchan) {
 		if sg.releasetime != 0 {
 			sg.releasetime = cputicks()
 		}
-		goready(gp)
+		goready(gp, 3)
 	}
 	unlock(&c.lock)
 }
@@ -333,8 +371,8 @@ func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, r
 		if !block {
 			return
 		}
-		gopark(nil, nil, "chan receive (nil chan)")
-		gothrow("unreachable")
+		gopark(nil, nil, "chan receive (nil chan)", traceEvGoStop, 2)
+		throw("unreachable")
 	}
 
 	// Fast path: check for failed non-blocking operation without acquiring the lock.
@@ -374,7 +412,7 @@ func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, r
 			unlock(&c.lock)
 
 			if ep != nil {
-				memmove(ep, sg.elem, uintptr(c.elemsize))
+				typedmemmove(c.elemtype, ep, sg.elem)
 			}
 			sg.elem = nil
 			gp := sg.g
@@ -382,7 +420,7 @@ func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, r
 			if sg.releasetime != 0 {
 				sg.releasetime = cputicks()
 			}
-			goready(gp)
+			goready(gp, 3)
 			selected = true
 			received = true
 			return
@@ -407,11 +445,11 @@ func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, r
 		mysg.selectdone = nil
 		gp.param = nil
 		c.recvq.enqueue(mysg)
-		goparkunlock(&c.lock, "chan receive")
+		goparkunlock(&c.lock, "chan receive", traceEvGoBlockRecv, 3)
 
 		// someone woke us up
 		if mysg != gp.waiting {
-			gothrow("G waiting list is corrupted!")
+			throw("G waiting list is corrupted!")
 		}
 		gp.waiting = nil
 		if mysg.releasetime > 0 {
@@ -430,7 +468,7 @@ func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, r
 
 		lock(&c.lock)
 		if c.closed == 0 {
-			gothrow("chanrecv: spurious wakeup")
+			throw("chanrecv: spurious wakeup")
 		}
 		return recvclosed(c, ep)
 	}
@@ -438,7 +476,7 @@ func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, r
 	// 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 {
@@ -464,7 +502,7 @@ func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, r
 		mysg.selectdone = nil
 
 		c.recvq.enqueue(mysg)
-		goparkunlock(&c.lock, "chan receive")
+		goparkunlock(&c.lock, "chan receive", traceEvGoBlockRecv|futile, 3)
 
 		// someone woke us up - try again
 		if mysg.releasetime > 0 {
@@ -479,7 +517,7 @@ func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, r
 		racerelease(chanbuf(c, c.recvx))
 	}
 	if ep != nil {
-		memmove(ep, chanbuf(c, c.recvx), uintptr(c.elemsize))
+		typedmemmove(c.elemtype, ep, chanbuf(c, c.recvx))
 	}
 	memclr(chanbuf(c, c.recvx), uintptr(c.elemsize))
 
@@ -497,7 +535,7 @@ func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, r
 		if sg.releasetime != 0 {
 			sg.releasetime = cputicks()
 		}
-		goready(gp)
+		goready(gp, 3)
 	} else {
 		unlock(&c.lock)
 	}
@@ -590,14 +628,17 @@ func selectnbrecv2(t *chantype, elem unsafe.Pointer, received *bool, c *hchan) (
 	return
 }
 
+//go:linkname reflect_chansend reflect.chansend
 func reflect_chansend(t *chantype, c *hchan, elem unsafe.Pointer, nb bool) (selected bool) {
 	return chansend(t, c, elem, !nb, getcallerpc(unsafe.Pointer(&t)))
 }
 
+//go:linkname reflect_chanrecv reflect.chanrecv
 func reflect_chanrecv(t *chantype, c *hchan, nb bool, elem unsafe.Pointer) (selected bool, received bool) {
 	return chanrecv(t, c, elem, !nb)
 }
 
+//go:linkname reflect_chanlen reflect.chanlen
 func reflect_chanlen(c *hchan) int {
 	if c == nil {
 		return 0
@@ -605,6 +646,7 @@ func reflect_chanlen(c *hchan) int {
 	return int(c.qcount)
 }
 
+//go:linkname reflect_chancap reflect.chancap
 func reflect_chancap(c *hchan) int {
 	if c == nil {
 		return 0
@@ -612,14 +654,22 @@ func reflect_chancap(c *hchan) int {
 	return int(c.dataqsiz)
 }
 
+//go:linkname reflect_chanclose reflect.chanclose
+func reflect_chanclose(c *hchan) {
+	closechan(c)
+}
+
 func (q *waitq) enqueue(sgp *sudog) {
 	sgp.next = nil
-	if q.first == nil {
+	x := q.last
+	if x == nil {
+		sgp.prev = nil
 		q.first = sgp
 		q.last = sgp
 		return
 	}
-	q.last.next = sgp
+	sgp.prev = x
+	x.next = sgp
 	q.last = sgp
 }
 
@@ -629,10 +679,14 @@ func (q *waitq) dequeue() *sudog {
 		if sgp == nil {
 			return nil
 		}
-		q.first = sgp.next
-		sgp.next = nil
-		if q.last == sgp {
+		y := sgp.next
+		if y == nil {
+			q.first = nil
 			q.last = nil
+		} else {
+			y.prev = nil
+			q.first = y
+			sgp.next = nil // mark as removed (see dequeueSudog)
 		}
 
 		// if sgp participates in a select and is already signaled, ignore it
diff --git a/src/runtime/chan.h b/src/runtime/chan.h
deleted file mode 100644
index c34ff15..0000000
--- a/src/runtime/chan.h
+++ /dev/null
@@ -1,68 +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.
-
-#define	MAXALIGN	8
-
-typedef	struct	WaitQ	WaitQ;
-typedef	struct	Select	Select;
-typedef	struct	Scase	Scase;
-
-struct	WaitQ
-{
-	SudoG*	first;
-	SudoG*	last;
-};
-
-struct	Hchan
-{
-	uintgo	qcount;			// total data in the q
-	uintgo	dataqsiz;		// size of the circular q
-	byte*	buf;
-	uint16	elemsize;
-	uint32	closed;
-	Type*	elemtype;		// element type
-	uintgo	sendx;			// send index
-	uintgo	recvx;			// receive index
-	WaitQ	recvq;			// list of recv waiters
-	WaitQ	sendq;			// list of send waiters
-	Mutex	lock;
-};
-
-// 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))
-
-enum
-{
-	debug = 0,
-
-	// Scase.kind
-	CaseRecv,
-	CaseSend,
-	CaseDefault,
-};
-
-// Known to compiler.
-// Changes here must also be made in src/cmd/gc/select.c's selecttype.
-struct	Scase
-{
-	void*	elem;			// data element
-	Hchan*	chan;			// chan
-	uintptr	pc;			// return pc
-	uint16	kind;
-	uint16	so;			// vararg of selected bool
-	bool*	receivedp;		// pointer to received bool (recv2)
-	int64	releasetime;
-};
-
-// Known to compiler.
-// Changes here must also be made in src/cmd/gc/select.c's selecttype.
-struct	Select
-{
-	uint16	tcase;			// total count of scase[]
-	uint16	ncase;			// currently filled scase[]
-	uint16*	pollorder;		// case poll order
-	Hchan**	lockorder;		// channel lock order
-	Scase	scase[1];		// one per case (in order of appearance)
-};
diff --git a/src/runtime/chan_test.go b/src/runtime/chan_test.go
index e689cea..497e87f 100644
--- a/src/runtime/chan_test.go
+++ b/src/runtime/chan_test.go
@@ -218,6 +218,81 @@ func TestNonblockRecvRace(t *testing.T) {
 	}
 }
 
+// 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 TestMultiConsumer(t *testing.T) {
 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)
@@ -818,3 +893,30 @@ func BenchmarkChanSem(b *testing.B) {
 		}
 	})
 }
+
+func BenchmarkChanPopular(b *testing.B) {
+	const n = 1000
+	c := make(chan bool)
+	var a []chan bool
+	var wg sync.WaitGroup
+	wg.Add(n)
+	for j := 0; j < n; j++ {
+		d := make(chan bool)
+		a = append(a, d)
+		go func() {
+			for i := 0; i < b.N; i++ {
+				select {
+				case <-c:
+				case <-d:
+				}
+			}
+			wg.Done()
+		}()
+	}
+	for i := 0; i < b.N; i++ {
+		for _, d := range a {
+			d <- true
+		}
+	}
+	wg.Wait()
+}
diff --git a/src/runtime/chanbarrier_test.go b/src/runtime/chanbarrier_test.go
new file mode 100644
index 0000000..770b850
--- /dev/null
+++ b/src/runtime/chanbarrier_test.go
@@ -0,0 +1,83 @@
+// 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"
+	"sync"
+	"testing"
+)
+
+type response struct {
+}
+
+type myError struct {
+}
+
+func (myError) Error() string { return "" }
+
+func doRequest(useSelect bool) (*response, error) {
+	type async struct {
+		resp *response
+		err  error
+	}
+	ch := make(chan *async, 0)
+	done := make(chan struct{}, 0)
+
+	if useSelect {
+		go func() {
+			select {
+			case ch <- &async{resp: nil, err: myError{}}:
+			case <-done:
+			}
+		}()
+	} else {
+		go func() {
+			ch <- &async{resp: nil, err: myError{}}
+		}()
+	}
+
+	r := <-ch
+	runtime.Gosched()
+	return r.resp, r.err
+}
+
+func TestChanSendSelectBarrier(t *testing.T) {
+	testChanSendBarrier(true)
+}
+
+func TestChanSendBarrier(t *testing.T) {
+	testChanSendBarrier(false)
+}
+
+func testChanSendBarrier(useSelect bool) {
+	var wg sync.WaitGroup
+	var globalMu sync.Mutex
+	outer := 100
+	inner := 100000
+	if testing.Short() {
+		outer = 10
+		inner = 1000
+	}
+	for i := 0; i < outer; i++ {
+		wg.Add(1)
+		go func() {
+			defer wg.Done()
+			var garbage []byte
+			for j := 0; j < inner; j++ {
+				_, err := doRequest(useSelect)
+				_, ok := err.(myError)
+				if !ok {
+					panic(1)
+				}
+				garbage = make([]byte, 1<<10)
+			}
+			globalMu.Lock()
+			global = garbage
+			globalMu.Unlock()
+		}()
+	}
+	wg.Wait()
+}
diff --git a/src/runtime/compiler.go b/src/runtime/compiler.go
index 562a460..5f1e8d8 100644
--- a/src/runtime/compiler.go
+++ b/src/runtime/compiler.go
@@ -7,7 +7,7 @@ package runtime
 // Compiler is the name of the compiler toolchain that built the
 // running binary.  Known toolchains are:
 //
-//	gc      The 5g/6g/8g compiler suite at code.google.com/p/go.
+//	gc      Also known as cmd/compile.
 //	gccgo   The gccgo front end, part of the GCC compiler suite.
 //
 const Compiler = "gc"
diff --git a/src/runtime/complex.go b/src/runtime/complex.go
index ec50f89..73f1161 100644
--- a/src/runtime/complex.go
+++ b/src/runtime/complex.go
@@ -4,28 +4,47 @@
 
 package runtime
 
+func isposinf(f float64) bool { return f > maxFloat64 }
+func isneginf(f float64) bool { return f < -maxFloat64 }
+func isnan(f float64) bool    { return f != f }
+
+func nan() float64 {
+	var f float64 = 0
+	return f / f
+}
+
+func posinf() float64 {
+	var f float64 = maxFloat64
+	return f * f
+}
+
+func neginf() float64 {
+	var f float64 = maxFloat64
+	return -f * f
+}
+
 func complex128div(n complex128, d complex128) complex128 {
 	// Special cases as in C99.
-	ninf := real(n) == posinf || real(n) == neginf ||
-		imag(n) == posinf || imag(n) == neginf
-	dinf := real(d) == posinf || real(d) == neginf ||
-		imag(d) == posinf || imag(d) == neginf
+	ninf := isposinf(real(n)) || isneginf(real(n)) ||
+		isposinf(imag(n)) || isneginf(imag(n))
+	dinf := isposinf(real(d)) || isneginf(real(d)) ||
+		isposinf(imag(d)) || isneginf(imag(d))
 
-	nnan := !ninf && (real(n) != real(n) || imag(n) != imag(n))
-	dnan := !dinf && (real(d) != real(d) || imag(d) != imag(d))
+	nnan := !ninf && (isnan(real(n)) || isnan(imag(n)))
+	dnan := !dinf && (isnan(real(d)) || isnan(imag(d)))
 
 	switch {
 	case nnan || dnan:
-		return complex(nan, nan)
+		return complex(nan(), nan())
 	case ninf && !dinf:
-		return complex(posinf, posinf)
+		return complex(posinf(), posinf())
 	case !ninf && dinf:
 		return complex(0, 0)
 	case real(d) == 0 && imag(d) == 0:
 		if real(n) == 0 && imag(n) == 0 {
-			return complex(nan, nan)
+			return complex(nan(), nan())
 		} else {
-			return complex(posinf, posinf)
+			return complex(posinf(), posinf())
 		}
 	default:
 		// Standard complex arithmetic, factored to avoid unnecessary overflow.
diff --git a/src/runtime/cpuprof.go b/src/runtime/cpuprof.go
index 8b1c1c6..0790852 100644
--- a/src/runtime/cpuprof.go
+++ b/src/runtime/cpuprof.go
@@ -30,8 +30,8 @@
 // The state of this dance between the signal handler and the goroutine
 // is encoded in the Profile.handoff field.  If handoff == 0, then the goroutine
 // is not using either log half and is waiting (or will soon be waiting) for
-// a new piece by calling notesleep(&p->wait).  If the signal handler
-// changes handoff from 0 to non-zero, it must call notewakeup(&p->wait)
+// a new piece by calling notesleep(&p.wait).  If the signal handler
+// changes handoff from 0 to non-zero, it must call notewakeup(&p.wait)
 // to wake the goroutine.  The value indicates the number of entries in the
 // log half being handed off.  The goroutine leaves the non-zero value in
 // place until it has finished processing the log half and then flips the number
@@ -61,7 +61,7 @@ const (
 
 type cpuprofEntry struct {
 	count uintptr
-	depth uintptr
+	depth int
 	stack [maxCPUProfStack]uintptr
 }
 
@@ -81,7 +81,7 @@ type cpuProfile struct {
 	// Signal handler has filled log[toggle][:nlog].
 	// Goroutine is writing log[1-toggle][:handoff].
 	log     [2][logSize / 2]uintptr
-	nlog    uintptr
+	nlog    int
 	toggle  int32
 	handoff uint32
 
@@ -101,12 +101,10 @@ var (
 	eod = [3]uintptr{0, 1, 0}
 )
 
-func setcpuprofilerate_m() // proc.c
-
 func setcpuprofilerate(hz int32) {
-	g := getg()
-	g.m.scalararg[0] = uintptr(hz)
-	onM(setcpuprofilerate_m)
+	systemstack(func() {
+		setcpuprofilerate_m(hz)
+	})
 }
 
 // lostProfileData is a no-op function used in profiles
@@ -169,7 +167,7 @@ func SetCPUProfileRate(hz int) {
 		cpuprof.on = false
 
 		// Now add is not running anymore, and getprofile owns the entire log.
-		// Set the high bit in prof->handoff to tell getprofile.
+		// Set the high bit in cpuprof.handoff to tell getprofile.
 		for {
 			n := cpuprof.handoff
 			if n&0x80000000 != 0 {
@@ -187,25 +185,21 @@ func SetCPUProfileRate(hz int) {
 	unlock(&cpuprofLock)
 }
 
-func cpuproftick(pc *uintptr, n int32) {
-	if n > maxCPUProfStack {
-		n = maxCPUProfStack
-	}
-	s := (*[maxCPUProfStack]uintptr)(unsafe.Pointer(pc))[:n]
-	cpuprof.add(s)
-}
-
 // add adds the stack trace to the profile.
 // It is called from signal handlers and other limited environments
 // and cannot allocate memory or acquire locks that might be
 // held at the time of the signal, nor can it use substantial amounts
 // of stack.  It is allowed to call evict.
 func (p *cpuProfile) add(pc []uintptr) {
+	if len(pc) > maxCPUProfStack {
+		pc = pc[:maxCPUProfStack]
+	}
+
 	// Compute hash.
 	h := uintptr(0)
 	for _, x := range pc {
 		h = h<<8 | (h >> (8 * (unsafe.Sizeof(h) - 1)))
-		h += x*31 + x*7 + x*3
+		h += x * 41
 	}
 	p.count++
 
@@ -214,7 +208,7 @@ func (p *cpuProfile) add(pc []uintptr) {
 Assoc:
 	for i := range b.entry {
 		e := &b.entry[i]
-		if e.depth != uintptr(len(pc)) {
+		if e.depth != len(pc) {
 			continue
 		}
 		for j := range pc {
@@ -243,7 +237,7 @@ Assoc:
 	}
 
 	// Reuse the newly evicted entry.
-	e.depth = uintptr(len(pc))
+	e.depth = len(pc)
 	e.count = 1
 	copy(e.stack[:], pc)
 }
@@ -258,7 +252,7 @@ func (p *cpuProfile) evict(e *cpuprofEntry) bool {
 	d := e.depth
 	nslot := d + 2
 	log := &p.log[p.toggle]
-	if p.nlog+nslot > uintptr(len(p.log[0])) {
+	if p.nlog+nslot > len(log) {
 		if !p.flushlog() {
 			return false
 		}
@@ -268,7 +262,7 @@ func (p *cpuProfile) evict(e *cpuprofEntry) bool {
 	q := p.nlog
 	log[q] = e.count
 	q++
-	log[q] = d
+	log[q] = uintptr(d)
 	q++
 	copy(log[q:], e.stack[:d])
 	q += d
@@ -289,7 +283,7 @@ func (p *cpuProfile) flushlog() bool {
 
 	p.toggle = 1 - p.toggle
 	log := &p.log[p.toggle]
-	q := uintptr(0)
+	q := 0
 	if p.lost > 0 {
 		lostPC := funcPC(lostProfileData)
 		log[0] = p.lost
@@ -362,7 +356,7 @@ func (p *cpuProfile) getprofile() []byte {
 
 	// In flush mode.
 	// Add is no longer being called.  We own the log.
-	// Also, p->handoff is non-zero, so flushlog will return false.
+	// Also, p.handoff is non-zero, so flushlog will return false.
 	// Evict the hash table into the log and return it.
 Flush:
 	for i := range p.hash {
@@ -402,8 +396,8 @@ Flush:
 }
 
 func uintptrBytes(p []uintptr) (ret []byte) {
-	pp := (*sliceStruct)(unsafe.Pointer(&p))
-	rp := (*sliceStruct)(unsafe.Pointer(&ret))
+	pp := (*slice)(unsafe.Pointer(&p))
+	rp := (*slice)(unsafe.Pointer(&ret))
 
 	rp.array = pp.array
 	rp.len = pp.len * int(unsafe.Sizeof(p[0]))
@@ -423,3 +417,8 @@ func uintptrBytes(p []uintptr) (ret []byte) {
 func CPUProfile() []byte {
 	return cpuprof.getprofile()
 }
+
+//go:linkname runtime_pprof_runtime_cyclesPerSecond runtime/pprof.runtime_cyclesPerSecond
+func runtime_pprof_runtime_cyclesPerSecond() int64 {
+	return tickspersecond()
+}
diff --git a/src/runtime/cputicks.go b/src/runtime/cputicks.go
new file mode 100644
index 0000000..162e026
--- /dev/null
+++ b/src/runtime/cputicks.go
@@ -0,0 +1,12 @@
+// 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 !arm
+// +build !arm64
+
+package runtime
+
+// careful: cputicks is not guaranteed to be monotonic!  In particular, we have
+// noticed drift between cpus on certain os/arch combinations.  See issue 8976.
+func cputicks() int64
diff --git a/src/runtime/crash_cgo_test.go b/src/runtime/crash_cgo_test.go
index 29f90fa..2e65e4c 100644
--- a/src/runtime/crash_cgo_test.go
+++ b/src/runtime/crash_cgo_test.go
@@ -36,6 +36,20 @@ func TestCgoTraceback(t *testing.T) {
 	}
 }
 
+func TestCgoCallbackGC(t *testing.T) {
+	if runtime.GOOS == "plan9" || runtime.GOOS == "windows" {
+		t.Skipf("no pthreads on %s", runtime.GOOS)
+	}
+	if testing.Short() && runtime.GOOS == "dragonfly" {
+		t.Skip("see golang.org/issue/11990")
+	}
+	got := executeTest(t, cgoCallbackGCSource, nil)
+	want := "OK\n"
+	if got != want {
+		t.Fatalf("expected %q, but got %q", want, got)
+	}
+}
+
 func TestCgoExternalThreadPanic(t *testing.T) {
 	if runtime.GOOS == "plan9" {
 		t.Skipf("no pthreads on %s", runtime.GOOS)
@@ -57,17 +71,24 @@ func TestCgoExternalThreadSIGPROF(t *testing.T) {
 	case "plan9", "windows":
 		t.Skipf("no pthreads on %s", runtime.GOOS)
 	case "darwin":
-		// static constructor needs external linking, but we don't support
-		// external linking on OS X 10.6.
-		out, err := exec.Command("uname", "-r").Output()
-		if err != nil {
-			t.Fatalf("uname -r failed: %v", err)
-		}
-		// OS X 10.6 == Darwin 10.x
-		if strings.HasPrefix(string(out), "10.") {
-			t.Skipf("no external linking on OS X 10.6")
+		if runtime.GOARCH != "arm" && runtime.GOARCH != "arm64" {
+			// static constructor needs external linking, but we don't support
+			// external linking on OS X 10.6.
+			out, err := exec.Command("uname", "-r").Output()
+			if err != nil {
+				t.Fatalf("uname -r failed: %v", err)
+			}
+			// OS X 10.6 == Darwin 10.x
+			if strings.HasPrefix(string(out), "10.") {
+				t.Skipf("no external linking on OS X 10.6")
+			}
 		}
 	}
+	if runtime.GOARCH == "ppc64" || runtime.GOARCH == "ppc64le" {
+		// TODO(austin) External linking not implemented on
+		// ppc64 (issue #8912)
+		t.Skipf("no external linking on ppc64")
+	}
 	got := executeTest(t, cgoExternalThreadSIGPROFSource, nil)
 	want := "OK\n"
 	if got != want {
@@ -75,6 +96,31 @@ func TestCgoExternalThreadSIGPROF(t *testing.T) {
 	}
 }
 
+func TestCgoExternalThreadSignal(t *testing.T) {
+	// issue 10139
+	switch runtime.GOOS {
+	case "plan9", "windows":
+		t.Skipf("no pthreads on %s", runtime.GOOS)
+	}
+	got := executeTest(t, cgoExternalThreadSignalSource, nil)
+	want := "OK\n"
+	if got != want {
+		t.Fatalf("expected %q, but got %q", want, got)
+	}
+}
+
+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
 
@@ -159,6 +205,83 @@ func main() {
 }
 `
 
+const cgoCallbackGCSource = `
+package main
+
+import "runtime"
+
+/*
+#include <pthread.h>
+
+void go_callback();
+
+static void *thr(void *arg) {
+    go_callback();
+    return 0;
+}
+
+static void foo() {
+    pthread_t th;
+    pthread_create(&th, 0, thr, 0);
+    pthread_join(th, 0);
+}
+*/
+import "C"
+import "fmt"
+
+//export go_callback
+func go_callback() {
+	runtime.GC()
+	grow()
+	runtime.GC()
+}
+
+var cnt int
+
+func grow() {
+	x := 10000
+	sum := 0
+	if grow1(&x, &sum) == 0 {
+		panic("bad")
+	}
+}
+
+func grow1(x, sum *int) int {
+	if *x == 0 {
+		return *sum + 1
+	}
+	*x--
+	sum1 := *sum + *x
+	return grow1(x, &sum1)
+}
+
+func main() {
+	const P = 100
+	done := make(chan bool)
+	// allocate a bunch of stack frames and spray them with pointers
+	for i := 0; i < P; i++ {
+		go func() {
+			grow()
+			done <- true
+		}()
+	}
+	for i := 0; i < P; i++ {
+		<-done
+	}
+	// now give these stack frames to cgo callbacks
+	for i := 0; i < P; i++ {
+		go func() {
+			C.foo()
+			done <- true
+		}()
+	}
+	for i := 0; i < P; i++ {
+		<-done
+	}
+	fmt.Printf("OK\n")
+}
+`
+
 const cgoExternalThreadPanicSource = `
 package main
 
@@ -254,7 +377,7 @@ import (
 func main() {
 	// This test intends to test that sending SIGPROF to foreign threads
 	// before we make any cgo call will not abort the whole process, so
-	// we cannot make any cgo call here. See http://golang.org/issue/9456.
+	// we cannot make any cgo call here. See https://golang.org/issue/9456.
 	atomic.StoreInt32((*int32)(unsafe.Pointer(&C.spinlock)), 1)
 	for atomic.LoadInt32((*int32)(unsafe.Pointer(&C.spinlock))) == 1 {
 		runtime.Gosched()
@@ -262,3 +385,97 @@ func main() {
 	println("OK")
 }
 `
+
+const cgoExternalThreadSignalSource = `
+package main
+
+/*
+#include <pthread.h>
+
+void **nullptr;
+
+void *crash(void *p) {
+	*nullptr = p;
+	return 0;
+}
+
+int start_crashing_thread(void) {
+	pthread_t tid;
+	return pthread_create(&tid, 0, crash, 0);
+}
+*/
+import "C"
+
+import (
+	"fmt"
+	"os"
+	"os/exec"
+	"time"
+)
+
+func main() {
+	if len(os.Args) > 1 && os.Args[1] == "crash" {
+		i := C.start_crashing_thread()
+		if i != 0 {
+			fmt.Println("pthread_create failed:", i)
+			// Exit with 0 because parent expects us to crash.
+			return
+		}
+
+		// We should crash immediately, but give it plenty of
+		// time before failing (by exiting 0) in case we are
+		// running on a slow system.
+		time.Sleep(5 * time.Second)
+		return
+	}
+
+	out, err := exec.Command(os.Args[0], "crash").CombinedOutput()
+	if err == nil {
+		fmt.Println("C signal did not crash as expected\n")
+		fmt.Printf("%s\n", out)
+		os.Exit(1)
+	}
+
+	fmt.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 211a047..8efce4d 100644
--- a/src/runtime/crash_test.go
+++ b/src/runtime/crash_test.go
@@ -5,37 +5,41 @@
 package runtime_test
 
 import (
+	"fmt"
+	"internal/testenv"
 	"io/ioutil"
 	"os"
 	"os/exec"
 	"path/filepath"
+	"regexp"
 	"runtime"
 	"strings"
+	"sync"
 	"testing"
 	"text/template"
 )
 
-// testEnv excludes GODEBUG from the environment
-// to prevent its output from breaking tests that
-// are trying to parse other command output.
 func testEnv(cmd *exec.Cmd) *exec.Cmd {
 	if cmd.Env != nil {
 		panic("environment already set")
 	}
 	for _, env := range os.Environ() {
+		// Exclude GODEBUG from the environment to prevent its output
+		// from breaking tests that are trying to parse other command output.
 		if strings.HasPrefix(env, "GODEBUG=") {
 			continue
 		}
+		// Exclude GOTRACEBACK for the same reason.
+		if strings.HasPrefix(env, "GOTRACEBACK=") {
+			continue
+		}
 		cmd.Env = append(cmd.Env, env)
 	}
 	return cmd
 }
 
 func executeTest(t *testing.T, templ string, data interface{}, extra ...string) string {
-	switch runtime.GOOS {
-	case "android", "nacl":
-		t.Skipf("skipping on %s", runtime.GOOS)
-	}
+	testenv.MustHaveGoBuild(t)
 
 	checkStaleRuntime(t)
 
@@ -62,7 +66,14 @@ func executeTest(t *testing.T, templ string, data interface{}, extra ...string)
 	}
 
 	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)
 		}
 	}
@@ -78,14 +89,25 @@ func executeTest(t *testing.T, templ string, data interface{}, extra ...string)
 	return string(got)
 }
 
+var (
+	staleRuntimeOnce sync.Once // guards init of staleRuntimeErr
+	staleRuntimeErr  error
+)
+
 func checkStaleRuntime(t *testing.T) {
-	// 'go run' uses the installed copy of runtime.a, which may be out of date.
-	out, err := testEnv(exec.Command("go", "list", "-f", "{{.Stale}}", "runtime")).CombinedOutput()
-	if err != nil {
-		t.Fatalf("failed to execute 'go list': %v\n%v", err, string(out))
-	}
-	if string(out) != "false\n" {
-		t.Fatalf("Stale runtime.a. Run 'go install runtime'.")
+	staleRuntimeOnce.Do(func() {
+		// 'go run' uses the installed copy of runtime.a, which may be out of date.
+		out, err := testEnv(exec.Command("go", "list", "-f", "{{.Stale}}", "runtime")).CombinedOutput()
+		if err != nil {
+			staleRuntimeErr = fmt.Errorf("failed to execute 'go list': %v\n%v", err, string(out))
+			return
+		}
+		if string(out) != "false\n" {
+			staleRuntimeErr = fmt.Errorf("Stale runtime.a. Run 'go install runtime'.")
+		}
+	})
+	if staleRuntimeErr != nil {
+		t.Fatal(staleRuntimeErr)
 	}
 }
 
@@ -204,6 +226,14 @@ func TestMainGoroutineId(t *testing.T) {
 	}
 }
 
+func TestNoHelperGoroutines(t *testing.T) {
+	output := executeTest(t, noHelperGoroutinesSource, nil)
+	matches := regexp.MustCompile(`goroutine [0-9]+ \[`).FindAllStringSubmatch(output, -1)
+	if len(matches) != 1 || matches[0][0] != "goroutine 1 [" {
+		t.Fatalf("want to see only goroutine 1, see:\n%s", output)
+	}
+}
+
 func TestBreakpoint(t *testing.T) {
 	output := executeTest(t, breakpointSource, nil)
 	want := "runtime.Breakpoint()"
@@ -418,6 +448,22 @@ func main() {
 }
 `
 
+const noHelperGoroutinesSource = `
+package main
+import (
+	"runtime"
+	"time"
+)
+func init() {
+	i := 0
+	runtime.SetFinalizer(&i, func(p *int) {})
+	time.AfterFunc(time.Hour, func() {})
+	panic("oops")
+}
+func main() {
+}
+`
+
 const breakpointSource = `
 package main
 import "runtime"
@@ -513,3 +559,31 @@ func TestRecoverBeforePanicAfterGoexit(t *testing.T) {
 	}()
 	runtime.Goexit()
 }
+
+func TestNetpollDeadlock(t *testing.T) {
+	output := executeTest(t, netpollDeadlockSource, nil)
+	want := "done\n"
+	if !strings.HasSuffix(output, want) {
+		t.Fatalf("output does not start with %q:\n%s", want, output)
+	}
+}
+
+const netpollDeadlockSource = `
+package main
+import (
+	"fmt"
+	"net"
+)
+func init() {
+	fmt.Println("dialing")
+	c, err := net.Dial("tcp", "localhost:14356")
+	if err == nil {
+		c.Close()
+	} else {
+		fmt.Println("error: ", err)
+	}
+}
+func main() {
+	fmt.Println("done")
+}
+`
diff --git a/src/runtime/crash_unix_test.go b/src/runtime/crash_unix_test.go
new file mode 100644
index 0000000..b925d02
--- /dev/null
+++ b/src/runtime/crash_unix_test.go
@@ -0,0 +1,135 @@
+// 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.
+
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+
+package runtime_test
+
+import (
+	"bytes"
+	"internal/testenv"
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"runtime"
+	"syscall"
+	"testing"
+)
+
+func TestCrashDumpsAllThreads(t *testing.T) {
+	switch runtime.GOOS {
+	case "darwin", "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "solaris":
+	default:
+		t.Skipf("skipping; not supported on %v", runtime.GOOS)
+	}
+
+	// We don't use executeTest because we need to kill the
+	// program while it is running.
+
+	testenv.MustHaveGoBuild(t)
+
+	checkStaleRuntime(t)
+
+	dir, err := ioutil.TempDir("", "go-build")
+	if err != nil {
+		t.Fatalf("failed to create temp directory: %v", err)
+	}
+	defer os.RemoveAll(dir)
+
+	if err := ioutil.WriteFile(filepath.Join(dir, "main.go"), []byte(crashDumpsAllThreadsSource), 0666); err != nil {
+		t.Fatalf("failed to create Go file: %v", err)
+	}
+
+	cmd := exec.Command("go", "build", "-o", "a.exe")
+	cmd.Dir = dir
+	out, err := testEnv(cmd).CombinedOutput()
+	if err != nil {
+		t.Fatalf("building source: %v\n%s", err, out)
+	}
+
+	cmd = exec.Command(filepath.Join(dir, "a.exe"))
+	cmd = testEnv(cmd)
+	cmd.Env = append(cmd.Env, "GOTRACEBACK=crash")
+	var outbuf bytes.Buffer
+	cmd.Stdout = &outbuf
+	cmd.Stderr = &outbuf
+
+	rp, wp, err := os.Pipe()
+	if err != nil {
+		t.Fatal(err)
+	}
+	cmd.ExtraFiles = []*os.File{wp}
+
+	if err := cmd.Start(); err != nil {
+		t.Fatalf("starting program: %v", err)
+	}
+
+	if err := wp.Close(); err != nil {
+		t.Logf("closing write pipe: %v", err)
+	}
+	if _, err := rp.Read(make([]byte, 1)); err != nil {
+		t.Fatalf("reading from pipe: %v", err)
+	}
+
+	if err := cmd.Process.Signal(syscall.SIGQUIT); err != nil {
+		t.Fatalf("signal: %v", err)
+	}
+
+	// No point in checking the error return from Wait--we expect
+	// it to fail.
+	cmd.Wait()
+
+	// We want to see a stack trace for each thread.
+	// Before https://golang.org/cl/2811 running threads would say
+	// "goroutine running on other thread; stack unavailable".
+	out = outbuf.Bytes()
+	n := bytes.Count(out, []byte("main.loop("))
+	if n != 4 {
+		t.Errorf("found %d instances of main.loop; expected 4", n)
+		t.Logf("%s", out)
+	}
+}
+
+const crashDumpsAllThreadsSource = `
+package main
+
+import (
+	"fmt"
+	"os"
+	"runtime"
+)
+
+func main() {
+	const count = 4
+	runtime.GOMAXPROCS(count + 1)
+
+	chans := make([]chan bool, count)
+	for i := range chans {
+		chans[i] = make(chan bool)
+		go loop(i, chans[i])
+	}
+
+	// Wait for all the goroutines to start executing.
+	for _, c := range chans {
+		<-c
+	}
+
+	// Tell our parent that all the goroutines are executing.
+	if _, err := os.NewFile(3, "pipe").WriteString("x"); err != nil {
+		fmt.Fprintf(os.Stderr, "write to pipe failed: %v\n", err)
+		os.Exit(2)
+	}
+
+	select {}
+}
+
+func loop(i int, c chan bool) {
+	close(c)
+	for {
+		for j := 0; j < 0x7fffffff; j++ {
+		}
+	}
+}
+`
diff --git a/src/runtime/debug.go b/src/runtime/debug.go
index 4414dd5..b7e7971 100644
--- a/src/runtime/debug.go
+++ b/src/runtime/debug.go
@@ -6,18 +6,6 @@ package runtime
 
 import "unsafe"
 
-// Breakpoint executes a breakpoint trap.
-func Breakpoint()
-
-// LockOSThread wires the calling goroutine to its current operating system thread.
-// Until the calling goroutine exits or calls UnlockOSThread, it will always
-// execute in that thread, and no other goroutine can.
-func LockOSThread()
-
-// UnlockOSThread unwires the calling goroutine from its fixed operating system thread.
-// If the calling goroutine has not called LockOSThread, UnlockOSThread is a no-op.
-func UnlockOSThread()
-
 // GOMAXPROCS sets the maximum number of CPUs that can be executing
 // simultaneously and returns the previous setting.  If n < 1, it does not
 // change the current setting.
@@ -34,21 +22,16 @@ func GOMAXPROCS(n int) int {
 		return ret
 	}
 
-	semacquire(&worldsema, false)
-	gp := getg()
-	gp.m.gcing = 1
-	onM(stoptheworld)
+	stopTheWorld("GOMAXPROCS")
 
-	// newprocs will be processed by starttheworld
+	// newprocs will be processed by startTheWorld
 	newprocs = int32(n)
 
-	gp.m.gcing = 0
-	semrelease(&worldsema)
-	onM(starttheworld)
+	startTheWorld()
 	return ret
 }
 
-// NumCPU returns the number of logical CPUs on the local machine.
+// NumCPU returns the number of logical CPUs usable by the current process.
 func NumCPU() int {
 	return int(ncpu)
 }
@@ -66,5 +49,3 @@ func NumCgoCall() int64 {
 func NumGoroutine() int {
 	return int(gcount())
 }
-
-func gcount() int32
diff --git a/src/runtime/debug/garbage.go b/src/runtime/debug/garbage.go
index 4a77dcf..41202f9 100644
--- a/src/runtime/debug/garbage.go
+++ b/src/runtime/debug/garbage.go
@@ -155,5 +155,5 @@ func SetPanicOnFault(enabled bool) bool {
 
 // WriteHeapDump writes a description of the heap and the objects in
 // it to the given file descriptor.
-// The heap dump format is defined at http://golang.org/s/go13heapdump.
+// The heap dump format is defined at https://golang.org/s/go13heapdump.
 func WriteHeapDump(fd uintptr)
diff --git a/src/runtime/debug/garbage_test.go b/src/runtime/debug/garbage_test.go
index 54c33bd..3e3483d 100644
--- a/src/runtime/debug/garbage_test.go
+++ b/src/runtime/debug/garbage_test.go
@@ -88,6 +88,10 @@ func TestReadGCStats(t *testing.T) {
 var big = make([]byte, 1<<20)
 
 func TestFreeOSMemory(t *testing.T) {
+	if runtime.GOARCH == "arm64" || runtime.GOARCH == "ppc64" || runtime.GOARCH == "ppc64le" ||
+		runtime.GOOS == "nacl" {
+		t.Skip("issue 9993; scavenger temporarily disabled on systems with physical pages larger than logical pages")
+	}
 	var ms1, ms2 runtime.MemStats
 
 	if big == nil {
diff --git a/src/runtime/debug/heapdump_test.go b/src/runtime/debug/heapdump_test.go
index 9201901..cb2f2f0 100644
--- a/src/runtime/debug/heapdump_test.go
+++ b/src/runtime/debug/heapdump_test.go
@@ -31,3 +31,39 @@ func TestWriteHeapDumpNonempty(t *testing.T) {
 		t.Fatalf("Heap dump size %d bytes, expected at least %d bytes", size, minSize)
 	}
 }
+
+type Obj struct {
+	x, y int
+}
+
+func objfin(x *Obj) {
+	println("finalized", x)
+}
+
+func TestWriteHeapDumpFinalizers(t *testing.T) {
+	if runtime.GOOS == "nacl" {
+		t.Skip("WriteHeapDump is not available on NaCl.")
+	}
+	f, err := ioutil.TempFile("", "heapdumptest")
+	if err != nil {
+		t.Fatalf("TempFile failed: %v", err)
+	}
+	defer os.Remove(f.Name())
+	defer f.Close()
+
+	// bug 9172: WriteHeapDump couldn't handle more than one finalizer
+	println("allocating objects")
+	x := &Obj{}
+	runtime.SetFinalizer(x, objfin)
+	y := &Obj{}
+	runtime.SetFinalizer(y, objfin)
+
+	// Trigger collection of x and y, queueing of their finalizers.
+	println("starting gc")
+	runtime.GC()
+
+	// Make sure WriteHeapDump doesn't fail with multiple queued finalizers.
+	println("starting dump")
+	WriteHeapDump(f.Fd())
+	println("done dump")
+}
diff --git a/src/runtime/debug/stack.go b/src/runtime/debug/stack.go
index c29b0a2..ab12bff 100644
--- a/src/runtime/debug/stack.go
+++ b/src/runtime/debug/stack.go
@@ -31,7 +31,7 @@ func PrintStack() {
 // then attempts to discover, for Go functions, the calling function or
 // method and the text of the line containing the invocation.
 //
-// This function is deprecated. Use package runtime's Stack instead.
+// Deprecated: Use package runtime's Stack instead.
 func Stack() []byte {
 	return stack()
 }
diff --git a/src/runtime/debug/stubs.go b/src/runtime/debug/stubs.go
index 8fba6cf..95b33e4 100644
--- a/src/runtime/debug/stubs.go
+++ b/src/runtime/debug/stubs.go
@@ -16,5 +16,4 @@ func setMaxThreads(int) int
 
 // Implemented in package runtime.
 func readGCStats(*[]time.Duration)
-func enableGC(bool) bool
 func freeOSMemory()
diff --git a/src/runtime/debug/stubs.s b/src/runtime/debug/stubs.s
index d56274f..9dc8e54 100644
--- a/src/runtime/debug/stubs.s
+++ b/src/runtime/debug/stubs.s
@@ -7,6 +7,15 @@
 #ifdef GOARCH_arm
 #define JMP B
 #endif
+#ifdef GOARCH_arm64
+#define JMP B
+#endif
+#ifdef GOARCH_ppc64
+#define JMP BR
+#endif
+#ifdef GOARCH_ppc64le
+#define JMP BR
+#endif
 
 TEXT ·setMaxStack(SB),NOSPLIT,$0-0
   JMP runtime·setMaxStack(SB)
diff --git a/src/runtime/defs.c b/src/runtime/defs.c
deleted file mode 100644
index b0a9b20..0000000
--- a/src/runtime/defs.c
+++ /dev/null
@@ -1,15 +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.
-
-// This file is compiled by cmd/dist to obtain debug information
-// about the given header files.
-
-#include "runtime.h"
-#include "arch_GOARCH.h"
-#include "malloc.h"
-#include "type.h"
-#include "race.h"
-#include "chan.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
diff --git a/src/runtime/defs1_linux.go b/src/runtime/defs1_linux.go
index 392cc4a..87c6e02 100644
--- a/src/runtime/defs1_linux.go
+++ b/src/runtime/defs1_linux.go
@@ -15,12 +15,14 @@ package runtime
 /*
 #include <ucontext.h>
 #include <fcntl.h>
+#include <asm/signal.h>
 */
 import "C"
 
 const (
-	O_RDONLY  = C.O_RDONLY
-	O_CLOEXEC = C.O_CLOEXEC
+	O_RDONLY    = C.O_RDONLY
+	O_CLOEXEC   = C.O_CLOEXEC
+	SA_RESTORER = C.SA_RESTORER
 )
 
 type Usigset C.__sigset_t
diff --git a/src/runtime/defs1_netbsd_386.go b/src/runtime/defs1_netbsd_386.go
new file mode 100644
index 0000000..f222bed
--- /dev/null
+++ b/src/runtime/defs1_netbsd_386.go
@@ -0,0 +1,183 @@
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_netbsd.go defs_netbsd_386.go
+
+package runtime
+
+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_RECEIPT   = 0
+	_EV_ERROR     = 0x4000
+	_EVFILT_READ  = 0x0
+	_EVFILT_WRITE = 0x1
+)
+
+type sigaltstackt struct {
+	ss_sp    uintptr
+	ss_size  uintptr
+	ss_flags int32
+}
+
+type sigset struct {
+	__bits [4]uint32
+}
+
+type siginfo struct {
+	_signo  int32
+	_code   int32
+	_errno  int32
+	_reason [20]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 int32) {
+	ts.tv_sec = int64(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 mcontextt struct {
+	__gregs     [19]uint32
+	__fpregs    [644]byte
+	_mc_tlsbase int32
+}
+
+type ucontextt struct {
+	uc_flags    uint32
+	uc_link     *ucontextt
+	uc_sigmask  sigset
+	uc_stack    stackt
+	uc_mcontext mcontextt
+	__uc_pad    [4]int32
+}
+
+type keventt struct {
+	ident  uint32
+	filter uint32
+	flags  uint32
+	fflags uint32
+	data   int64
+	udata  *byte
+}
+
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_netbsd.go defs_netbsd_386.go
+
+const (
+	_REG_GS     = 0x0
+	_REG_FS     = 0x1
+	_REG_ES     = 0x2
+	_REG_DS     = 0x3
+	_REG_EDI    = 0x4
+	_REG_ESI    = 0x5
+	_REG_EBP    = 0x6
+	_REG_ESP    = 0x7
+	_REG_EBX    = 0x8
+	_REG_EDX    = 0x9
+	_REG_ECX    = 0xa
+	_REG_EAX    = 0xb
+	_REG_TRAPNO = 0xc
+	_REG_ERR    = 0xd
+	_REG_EIP    = 0xe
+	_REG_CS     = 0xf
+	_REG_EFL    = 0x10
+	_REG_UESP   = 0x11
+	_REG_SS     = 0x12
+)
diff --git a/src/runtime/defs1_netbsd_amd64.go b/src/runtime/defs1_netbsd_amd64.go
new file mode 100644
index 0000000..c2bde4d
--- /dev/null
+++ b/src/runtime/defs1_netbsd_amd64.go
@@ -0,0 +1,195 @@
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_netbsd.go defs_netbsd_amd64.go
+
+package runtime
+
+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_RECEIPT   = 0
+	_EV_ERROR     = 0x4000
+	_EVFILT_READ  = 0x0
+	_EVFILT_WRITE = 0x1
+)
+
+type sigaltstackt struct {
+	ss_sp     uintptr
+	ss_size   uintptr
+	ss_flags  int32
+	pad_cgo_0 [4]byte
+}
+
+type sigset struct {
+	__bits [4]uint32
+}
+
+type siginfo struct {
+	_signo  int32
+	_code   int32
+	_errno  int32
+	_pad    int32
+	_reason [24]byte
+}
+
+type stackt struct {
+	ss_sp     uintptr
+	ss_size   uintptr
+	ss_flags  int32
+	pad_cgo_0 [4]byte
+}
+
+type timespec struct {
+	tv_sec  int64
+	tv_nsec int64
+}
+
+func (ts *timespec) set_sec(x int32) {
+	ts.tv_sec = int64(x)
+}
+
+func (ts *timespec) set_nsec(x int32) {
+	ts.tv_nsec = int64(x)
+}
+
+type timeval struct {
+	tv_sec    int64
+	tv_usec   int32
+	pad_cgo_0 [4]byte
+}
+
+func (tv *timeval) set_usec(x int32) {
+	tv.tv_usec = x
+}
+
+type itimerval struct {
+	it_interval timeval
+	it_value    timeval
+}
+
+type mcontextt struct {
+	__gregs     [26]uint64
+	_mc_tlsbase uint64
+	__fpregs    [512]int8
+}
+
+type ucontextt struct {
+	uc_flags    uint32
+	pad_cgo_0   [4]byte
+	uc_link     *ucontextt
+	uc_sigmask  sigset
+	uc_stack    stackt
+	uc_mcontext mcontextt
+}
+
+type keventt struct {
+	ident     uint64
+	filter    uint32
+	flags     uint32
+	fflags    uint32
+	pad_cgo_0 [4]byte
+	data      int64
+	udata     *byte
+}
+
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_netbsd.go defs_netbsd_amd64.go
+
+const (
+	_REG_RDI    = 0x0
+	_REG_RSI    = 0x1
+	_REG_RDX    = 0x2
+	_REG_RCX    = 0x3
+	_REG_R8     = 0x4
+	_REG_R9     = 0x5
+	_REG_R10    = 0x6
+	_REG_R11    = 0x7
+	_REG_R12    = 0x8
+	_REG_R13    = 0x9
+	_REG_R14    = 0xa
+	_REG_R15    = 0xb
+	_REG_RBP    = 0xc
+	_REG_RBX    = 0xd
+	_REG_RAX    = 0xe
+	_REG_GS     = 0xf
+	_REG_FS     = 0x10
+	_REG_ES     = 0x11
+	_REG_DS     = 0x12
+	_REG_TRAPNO = 0x13
+	_REG_ERR    = 0x14
+	_REG_RIP    = 0x15
+	_REG_CS     = 0x16
+	_REG_RFLAGS = 0x17
+	_REG_RSP    = 0x18
+	_REG_SS     = 0x19
+)
diff --git a/src/runtime/defs1_netbsd_arm.go b/src/runtime/defs1_netbsd_arm.go
new file mode 100644
index 0000000..c976351
--- /dev/null
+++ b/src/runtime/defs1_netbsd_arm.go
@@ -0,0 +1,183 @@
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_netbsd.go defs_netbsd_arm.go
+
+package runtime
+
+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_RECEIPT   = 0
+	_EV_ERROR     = 0x4000
+	_EVFILT_READ  = 0x0
+	_EVFILT_WRITE = 0x1
+)
+
+type sigaltstackt struct {
+	ss_sp    uintptr
+	ss_size  uintptr
+	ss_flags int32
+}
+
+type sigset struct {
+	__bits [4]uint32
+}
+
+type siginfo struct {
+	_signo   int32
+	_code    int32
+	_errno   int32
+	_reason  uintptr
+	_reasonx [16]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 int32) {
+	ts.tv_sec = int64(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 mcontextt struct {
+	__gregs [17]uint32
+	__fpu   [4 + 8*32 + 4]byte // EABI
+	// __fpu [4+4*33+4]byte // not EABI
+	_mc_tlsbase uint32
+}
+
+type ucontextt struct {
+	uc_flags    uint32
+	uc_link     *ucontextt
+	uc_sigmask  sigset
+	uc_stack    stackt
+	uc_mcontext mcontextt
+	__uc_pad    [2]int32
+}
+
+type keventt struct {
+	ident  uint32
+	filter uint32
+	flags  uint32
+	fflags uint32
+	data   int64
+	udata  *byte
+}
+
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_netbsd.go defs_netbsd_arm.go
+
+const (
+	_REG_R0   = 0x0
+	_REG_R1   = 0x1
+	_REG_R2   = 0x2
+	_REG_R3   = 0x3
+	_REG_R4   = 0x4
+	_REG_R5   = 0x5
+	_REG_R6   = 0x6
+	_REG_R7   = 0x7
+	_REG_R8   = 0x8
+	_REG_R9   = 0x9
+	_REG_R10  = 0xa
+	_REG_R11  = 0xb
+	_REG_R12  = 0xc
+	_REG_R13  = 0xd
+	_REG_R14  = 0xe
+	_REG_R15  = 0xf
+	_REG_CPSR = 0x10
+)
diff --git a/src/runtime/defs1_solaris_amd64.go b/src/runtime/defs1_solaris_amd64.go
new file mode 100644
index 0000000..3bb6f69
--- /dev/null
+++ b/src/runtime/defs1_solaris_amd64.go
@@ -0,0 +1,245 @@
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_solaris.go defs_solaris_amd64.go
+
+package runtime
+
+const (
+	_EINTR       = 0x4
+	_EBADF       = 0x9
+	_EFAULT      = 0xe
+	_EAGAIN      = 0xb
+	_ETIMEDOUT   = 0x91
+	_EWOULDBLOCK = 0xb
+	_EINPROGRESS = 0x96
+
+	_PROT_NONE  = 0x0
+	_PROT_READ  = 0x1
+	_PROT_WRITE = 0x2
+	_PROT_EXEC  = 0x4
+
+	_MAP_ANON    = 0x100
+	_MAP_PRIVATE = 0x2
+	_MAP_FIXED   = 0x10
+
+	_MADV_FREE = 0x5
+
+	_SA_SIGINFO = 0x8
+	_SA_RESTART = 0x4
+	_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    = 0x15
+	_SIGSTOP   = 0x17
+	_SIGTSTP   = 0x18
+	_SIGCONT   = 0x19
+	_SIGCHLD   = 0x12
+	_SIGTTIN   = 0x1a
+	_SIGTTOU   = 0x1b
+	_SIGIO     = 0x16
+	_SIGXCPU   = 0x1e
+	_SIGXFSZ   = 0x1f
+	_SIGVTALRM = 0x1c
+	_SIGPROF   = 0x1d
+	_SIGWINCH  = 0x14
+	_SIGUSR1   = 0x10
+	_SIGUSR2   = 0x11
+
+	_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
+
+	__SC_NPROCESSORS_ONLN = 0xf
+
+	_PTHREAD_CREATE_DETACHED = 0x40
+
+	_FORK_NOSIGCHLD = 0x1
+	_FORK_WAITPID   = 0x2
+
+	_MAXHOSTNAMELEN = 0x100
+
+	_O_NONBLOCK = 0x80
+	_FD_CLOEXEC = 0x1
+	_F_GETFL    = 0x3
+	_F_SETFL    = 0x4
+	_F_SETFD    = 0x2
+
+	_POLLIN  = 0x1
+	_POLLOUT = 0x4
+	_POLLHUP = 0x10
+	_POLLERR = 0x8
+
+	_PORT_SOURCE_FD = 0x4
+)
+
+type semt struct {
+	sem_count uint32
+	sem_type  uint16
+	sem_magic uint16
+	sem_pad1  [3]uint64
+	sem_pad2  [2]uint64
+}
+
+type sigaltstackt struct {
+	ss_sp     *byte
+	ss_size   uint64
+	ss_flags  int32
+	pad_cgo_0 [4]byte
+}
+
+type sigset struct {
+	__sigbits [4]uint32
+}
+
+type stackt struct {
+	ss_sp     *byte
+	ss_size   uint64
+	ss_flags  int32
+	pad_cgo_0 [4]byte
+}
+
+type siginfo struct {
+	si_signo int32
+	si_code  int32
+	si_errno int32
+	si_pad   int32
+	__data   [240]byte
+}
+
+type sigactiont struct {
+	sa_flags  int32
+	pad_cgo_0 [4]byte
+	_funcptr  [8]byte
+	sa_mask   sigset
+}
+
+type fpregset struct {
+	fp_reg_set [528]byte
+}
+
+type mcontext struct {
+	gregs  [28]int64
+	fpregs fpregset
+}
+
+type ucontext struct {
+	uc_flags    uint64
+	uc_link     *ucontext
+	uc_sigmask  sigset
+	uc_stack    stackt
+	pad_cgo_0   [8]byte
+	uc_mcontext mcontext
+	uc_filler   [5]int64
+	pad_cgo_1   [8]byte
+}
+
+type timespec struct {
+	tv_sec  int64
+	tv_nsec int64
+}
+
+type timeval struct {
+	tv_sec  int64
+	tv_usec int64
+}
+
+func (tv *timeval) set_usec(x int32) {
+	tv.tv_usec = int64(x)
+}
+
+type itimerval struct {
+	it_interval timeval
+	it_value    timeval
+}
+
+type portevent struct {
+	portev_events int32
+	portev_source uint16
+	portev_pad    uint16
+	portev_object uint64
+	portev_user   *byte
+}
+
+type pthread uint32
+type pthreadattr struct {
+	__pthread_attrp *byte
+}
+
+type stat struct {
+	st_dev     uint64
+	st_ino     uint64
+	st_mode    uint32
+	st_nlink   uint32
+	st_uid     uint32
+	st_gid     uint32
+	st_rdev    uint64
+	st_size    int64
+	st_atim    timespec
+	st_mtim    timespec
+	st_ctim    timespec
+	st_blksize int32
+	pad_cgo_0  [4]byte
+	st_blocks  int64
+	st_fstype  [16]int8
+}
+
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_solaris.go defs_solaris_amd64.go
+
+const (
+	_REG_RDI    = 0x8
+	_REG_RSI    = 0x9
+	_REG_RDX    = 0xc
+	_REG_RCX    = 0xd
+	_REG_R8     = 0x7
+	_REG_R9     = 0x6
+	_REG_R10    = 0x5
+	_REG_R11    = 0x4
+	_REG_R12    = 0x3
+	_REG_R13    = 0x2
+	_REG_R14    = 0x1
+	_REG_R15    = 0x0
+	_REG_RBP    = 0xa
+	_REG_RBX    = 0xb
+	_REG_RAX    = 0xe
+	_REG_GS     = 0x17
+	_REG_FS     = 0x16
+	_REG_ES     = 0x18
+	_REG_DS     = 0x19
+	_REG_TRAPNO = 0xf
+	_REG_ERR    = 0x10
+	_REG_RIP    = 0x11
+	_REG_CS     = 0x12
+	_REG_RFLAGS = 0x13
+	_REG_RSP    = 0x14
+	_REG_SS     = 0x15
+)
diff --git a/src/runtime/defs3_linux.go b/src/runtime/defs3_linux.go
new file mode 100644
index 0000000..489c130
--- /dev/null
+++ b/src/runtime/defs3_linux.go
@@ -0,0 +1,43 @@
+// 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 ignore
+
+/*
+Input to cgo -cdefs
+
+GOARCH=ppc64 cgo -cdefs defs_linux.go defs3_linux.go > defs_linux_ppc64.h
+*/
+
+package runtime
+
+/*
+#define size_t __kernel_size_t
+#define sigset_t __sigset_t // rename the sigset_t here otherwise cgo will complain about "inconsistent definitions for C.sigset_t"
+#define	_SYS_TYPES_H	// avoid inclusion of sys/types.h
+#include <asm/ucontext.h>
+#include <asm-generic/fcntl.h>
+*/
+import "C"
+
+const (
+	O_RDONLY    = C.O_RDONLY
+	O_CLOEXEC   = C.O_CLOEXEC
+	SA_RESTORER = 0 // unused
+)
+
+type Usigset C.__sigset_t
+
+// types used in sigcontext
+type Ptregs C.struct_pt_regs
+type Gregset C.elf_gregset_t
+type FPregset C.elf_fpregset_t
+type Vreg C.elf_vrreg_t
+
+type SigaltstackT C.struct_sigaltstack
+
+// PPC64 uses sigcontext in place of mcontext in ucontext.
+// see http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/arch/powerpc/include/uapi/asm/ucontext.h
+type Sigcontext C.struct_sigcontext
+type Ucontext C.struct_ucontext
diff --git a/src/runtime/defs_android_arm.h b/src/runtime/defs_android_arm.h
deleted file mode 100644
index 3611b3a..0000000
--- a/src/runtime/defs_android_arm.h
+++ /dev/null
@@ -1,3 +0,0 @@
-// TODO: Generate using cgo like defs_linux_{386,amd64}.h
-
-#include "defs_linux_arm.h"
diff --git a/src/runtime/defs_darwin_386.go b/src/runtime/defs_darwin_386.go
new file mode 100644
index 0000000..e051301
--- /dev/null
+++ b/src/runtime/defs_darwin_386.go
@@ -0,0 +1,382 @@
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_darwin.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_DONTNEED = 0x4
+	_MADV_FREE     = 0x5
+
+	_MACH_MSG_TYPE_MOVE_RECEIVE   = 0x10
+	_MACH_MSG_TYPE_MOVE_SEND      = 0x11
+	_MACH_MSG_TYPE_MOVE_SEND_ONCE = 0x12
+	_MACH_MSG_TYPE_COPY_SEND      = 0x13
+	_MACH_MSG_TYPE_MAKE_SEND      = 0x14
+	_MACH_MSG_TYPE_MAKE_SEND_ONCE = 0x15
+	_MACH_MSG_TYPE_COPY_RECEIVE   = 0x16
+
+	_MACH_MSG_PORT_DESCRIPTOR         = 0x0
+	_MACH_MSG_OOL_DESCRIPTOR          = 0x1
+	_MACH_MSG_OOL_PORTS_DESCRIPTOR    = 0x2
+	_MACH_MSG_OOL_VOLATILE_DESCRIPTOR = 0x3
+
+	_MACH_MSGH_BITS_COMPLEX = 0x80000000
+
+	_MACH_SEND_MSG  = 0x1
+	_MACH_RCV_MSG   = 0x2
+	_MACH_RCV_LARGE = 0x4
+
+	_MACH_SEND_TIMEOUT   = 0x10
+	_MACH_SEND_INTERRUPT = 0x40
+	_MACH_SEND_ALWAYS    = 0x10000
+	_MACH_SEND_TRAILER   = 0x20000
+	_MACH_RCV_TIMEOUT    = 0x100
+	_MACH_RCV_NOTIFY     = 0x200
+	_MACH_RCV_INTERRUPT  = 0x400
+	_MACH_RCV_OVERWRITE  = 0x1000
+
+	_NDR_PROTOCOL_2_0      = 0x0
+	_NDR_INT_BIG_ENDIAN    = 0x0
+	_NDR_INT_LITTLE_ENDIAN = 0x1
+	_NDR_FLOAT_IEEE        = 0x0
+	_NDR_CHAR_ASCII        = 0x0
+
+	_SA_SIGINFO   = 0x40
+	_SA_RESTART   = 0x2
+	_SA_ONSTACK   = 0x1
+	_SA_USERTRAMP = 0x100
+	_SA_64REGSET  = 0x200
+
+	_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 = 0x7
+	_FPE_INTOVF = 0x8
+	_FPE_FLTDIV = 0x1
+	_FPE_FLTOVF = 0x2
+	_FPE_FLTUND = 0x3
+	_FPE_FLTRES = 0x4
+	_FPE_FLTINV = 0x5
+	_FPE_FLTSUB = 0x6
+
+	_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_RECEIPT   = 0x40
+	_EV_ERROR     = 0x4000
+	_EVFILT_READ  = -0x1
+	_EVFILT_WRITE = -0x2
+)
+
+type machbody struct {
+	msgh_descriptor_count uint32
+}
+
+type machheader struct {
+	msgh_bits        uint32
+	msgh_size        uint32
+	msgh_remote_port uint32
+	msgh_local_port  uint32
+	msgh_reserved    uint32
+	msgh_id          int32
+}
+
+type machndr struct {
+	mig_vers     uint8
+	if_vers      uint8
+	reserved1    uint8
+	mig_encoding uint8
+	int_rep      uint8
+	char_rep     uint8
+	float_rep    uint8
+	reserved2    uint8
+}
+
+type machport struct {
+	name        uint32
+	pad1        uint32
+	pad2        uint16
+	disposition uint8
+	_type       uint8
+}
+
+type stackt struct {
+	ss_sp    *byte
+	ss_size  uintptr
+	ss_flags int32
+}
+
+type sigactiont struct {
+	__sigaction_u [4]byte
+	sa_tramp      unsafe.Pointer
+	sa_mask       uint32
+	sa_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   uint32
+	si_value  [4]byte
+	si_band   int32
+	__pad     [7]uint32
+}
+
+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 timespec struct {
+	tv_sec  int32
+	tv_nsec int32
+}
+
+type fpcontrol struct {
+	pad_cgo_0 [2]byte
+}
+
+type fpstatus struct {
+	pad_cgo_0 [2]byte
+}
+
+type regmmst struct {
+	mmst_reg  [10]int8
+	mmst_rsrv [6]int8
+}
+
+type regxmm struct {
+	xmm_reg [16]int8
+}
+
+type regs64 struct {
+	rax    uint64
+	rbx    uint64
+	rcx    uint64
+	rdx    uint64
+	rdi    uint64
+	rsi    uint64
+	rbp    uint64
+	rsp    uint64
+	r8     uint64
+	r9     uint64
+	r10    uint64
+	r11    uint64
+	r12    uint64
+	r13    uint64
+	r14    uint64
+	r15    uint64
+	rip    uint64
+	rflags uint64
+	cs     uint64
+	fs     uint64
+	gs     uint64
+}
+
+type floatstate64 struct {
+	fpu_reserved  [2]int32
+	fpu_fcw       fpcontrol
+	fpu_fsw       fpstatus
+	fpu_ftw       uint8
+	fpu_rsrv1     uint8
+	fpu_fop       uint16
+	fpu_ip        uint32
+	fpu_cs        uint16
+	fpu_rsrv2     uint16
+	fpu_dp        uint32
+	fpu_ds        uint16
+	fpu_rsrv3     uint16
+	fpu_mxcsr     uint32
+	fpu_mxcsrmask uint32
+	fpu_stmm0     regmmst
+	fpu_stmm1     regmmst
+	fpu_stmm2     regmmst
+	fpu_stmm3     regmmst
+	fpu_stmm4     regmmst
+	fpu_stmm5     regmmst
+	fpu_stmm6     regmmst
+	fpu_stmm7     regmmst
+	fpu_xmm0      regxmm
+	fpu_xmm1      regxmm
+	fpu_xmm2      regxmm
+	fpu_xmm3      regxmm
+	fpu_xmm4      regxmm
+	fpu_xmm5      regxmm
+	fpu_xmm6      regxmm
+	fpu_xmm7      regxmm
+	fpu_xmm8      regxmm
+	fpu_xmm9      regxmm
+	fpu_xmm10     regxmm
+	fpu_xmm11     regxmm
+	fpu_xmm12     regxmm
+	fpu_xmm13     regxmm
+	fpu_xmm14     regxmm
+	fpu_xmm15     regxmm
+	fpu_rsrv4     [96]int8
+	fpu_reserved1 int32
+}
+
+type exceptionstate64 struct {
+	trapno     uint16
+	cpu        uint16
+	err        uint32
+	faultvaddr uint64
+}
+
+type mcontext64 struct {
+	es exceptionstate64
+	ss regs64
+	fs floatstate64
+}
+
+type regs32 struct {
+	eax    uint32
+	ebx    uint32
+	ecx    uint32
+	edx    uint32
+	edi    uint32
+	esi    uint32
+	ebp    uint32
+	esp    uint32
+	ss     uint32
+	eflags uint32
+	eip    uint32
+	cs     uint32
+	ds     uint32
+	es     uint32
+	fs     uint32
+	gs     uint32
+}
+
+type floatstate32 struct {
+	fpu_reserved  [2]int32
+	fpu_fcw       fpcontrol
+	fpu_fsw       fpstatus
+	fpu_ftw       uint8
+	fpu_rsrv1     uint8
+	fpu_fop       uint16
+	fpu_ip        uint32
+	fpu_cs        uint16
+	fpu_rsrv2     uint16
+	fpu_dp        uint32
+	fpu_ds        uint16
+	fpu_rsrv3     uint16
+	fpu_mxcsr     uint32
+	fpu_mxcsrmask uint32
+	fpu_stmm0     regmmst
+	fpu_stmm1     regmmst
+	fpu_stmm2     regmmst
+	fpu_stmm3     regmmst
+	fpu_stmm4     regmmst
+	fpu_stmm5     regmmst
+	fpu_stmm6     regmmst
+	fpu_stmm7     regmmst
+	fpu_xmm0      regxmm
+	fpu_xmm1      regxmm
+	fpu_xmm2      regxmm
+	fpu_xmm3      regxmm
+	fpu_xmm4      regxmm
+	fpu_xmm5      regxmm
+	fpu_xmm6      regxmm
+	fpu_xmm7      regxmm
+	fpu_rsrv4     [224]int8
+	fpu_reserved1 int32
+}
+
+type exceptionstate32 struct {
+	trapno     uint16
+	cpu        uint16
+	err        uint32
+	faultvaddr uint32
+}
+
+type mcontext32 struct {
+	es exceptionstate32
+	ss regs32
+	fs floatstate32
+}
+
+type ucontext struct {
+	uc_onstack  int32
+	uc_sigmask  uint32
+	uc_stack    stackt
+	uc_link     *ucontext
+	uc_mcsize   uint32
+	uc_mcontext *mcontext32
+}
+
+type keventt struct {
+	ident  uint32
+	filter int16
+	flags  uint16
+	fflags uint32
+	data   int32
+	udata  *byte
+}
diff --git a/src/runtime/defs_darwin_386.h b/src/runtime/defs_darwin_386.h
deleted file mode 100644
index 0e0b4fb..0000000
--- a/src/runtime/defs_darwin_386.h
+++ /dev/null
@@ -1,392 +0,0 @@
-// Created by cgo -cdefs - DO NOT EDIT
-// cgo -cdefs defs_darwin.go
-
-
-enum {
-	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_DONTNEED	= 0x4,
-	MADV_FREE	= 0x5,
-
-	MACH_MSG_TYPE_MOVE_RECEIVE	= 0x10,
-	MACH_MSG_TYPE_MOVE_SEND		= 0x11,
-	MACH_MSG_TYPE_MOVE_SEND_ONCE	= 0x12,
-	MACH_MSG_TYPE_COPY_SEND		= 0x13,
-	MACH_MSG_TYPE_MAKE_SEND		= 0x14,
-	MACH_MSG_TYPE_MAKE_SEND_ONCE	= 0x15,
-	MACH_MSG_TYPE_COPY_RECEIVE	= 0x16,
-
-	MACH_MSG_PORT_DESCRIPTOR		= 0x0,
-	MACH_MSG_OOL_DESCRIPTOR			= 0x1,
-	MACH_MSG_OOL_PORTS_DESCRIPTOR		= 0x2,
-	MACH_MSG_OOL_VOLATILE_DESCRIPTOR	= 0x3,
-
-	MACH_MSGH_BITS_COMPLEX	= 0x80000000,
-
-	MACH_SEND_MSG	= 0x1,
-	MACH_RCV_MSG	= 0x2,
-	MACH_RCV_LARGE	= 0x4,
-
-	MACH_SEND_TIMEOUT	= 0x10,
-	MACH_SEND_INTERRUPT	= 0x40,
-	MACH_SEND_ALWAYS	= 0x10000,
-	MACH_SEND_TRAILER	= 0x20000,
-	MACH_RCV_TIMEOUT	= 0x100,
-	MACH_RCV_NOTIFY		= 0x200,
-	MACH_RCV_INTERRUPT	= 0x400,
-	MACH_RCV_OVERWRITE	= 0x1000,
-
-	NDR_PROTOCOL_2_0	= 0x0,
-	NDR_INT_BIG_ENDIAN	= 0x0,
-	NDR_INT_LITTLE_ENDIAN	= 0x1,
-	NDR_FLOAT_IEEE		= 0x0,
-	NDR_CHAR_ASCII		= 0x0,
-
-	SA_SIGINFO	= 0x40,
-	SA_RESTART	= 0x2,
-	SA_ONSTACK	= 0x1,
-	SA_USERTRAMP	= 0x100,
-	SA_64REGSET	= 0x200,
-
-	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	= 0x7,
-	FPE_INTOVF	= 0x8,
-	FPE_FLTDIV	= 0x1,
-	FPE_FLTOVF	= 0x2,
-	FPE_FLTUND	= 0x3,
-	FPE_FLTRES	= 0x4,
-	FPE_FLTINV	= 0x5,
-	FPE_FLTSUB	= 0x6,
-
-	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_RECEIPT	= 0x40,
-	EV_ERROR	= 0x4000,
-	EVFILT_READ	= -0x1,
-	EVFILT_WRITE	= -0x2,
-};
-
-typedef struct MachBody MachBody;
-typedef struct MachHeader MachHeader;
-typedef struct MachNDR MachNDR;
-typedef struct MachPort MachPort;
-typedef struct StackT StackT;
-typedef struct SigactionT SigactionT;
-typedef struct Siginfo Siginfo;
-typedef struct Timeval Timeval;
-typedef struct Itimerval Itimerval;
-typedef struct Timespec Timespec;
-typedef struct FPControl FPControl;
-typedef struct FPStatus FPStatus;
-typedef struct RegMMST RegMMST;
-typedef struct RegXMM RegXMM;
-typedef struct Regs64 Regs64;
-typedef struct FloatState64 FloatState64;
-typedef struct ExceptionState64 ExceptionState64;
-typedef struct Mcontext64 Mcontext64;
-typedef struct Regs32 Regs32;
-typedef struct FloatState32 FloatState32;
-typedef struct ExceptionState32 ExceptionState32;
-typedef struct Mcontext32 Mcontext32;
-typedef struct Ucontext Ucontext;
-typedef struct KeventT KeventT;
-
-#pragma pack on
-
-struct MachBody {
-	uint32	msgh_descriptor_count;
-};
-struct MachHeader {
-	uint32	msgh_bits;
-	uint32	msgh_size;
-	uint32	msgh_remote_port;
-	uint32	msgh_local_port;
-	uint32	msgh_reserved;
-	int32	msgh_id;
-};
-struct MachNDR {
-	uint8	mig_vers;
-	uint8	if_vers;
-	uint8	reserved1;
-	uint8	mig_encoding;
-	uint8	int_rep;
-	uint8	char_rep;
-	uint8	float_rep;
-	uint8	reserved2;
-};
-struct MachPort {
-	uint32	name;
-	uint32	pad1;
-	uint16	pad2;
-	uint8	disposition;
-	uint8	type;
-};
-
-struct StackT {
-	byte	*ss_sp;
-	uint32	ss_size;
-	int32	ss_flags;
-};
-typedef	byte	Sighandler[4];
-
-struct SigactionT {
-	byte	__sigaction_u[4];
-	void	*sa_tramp;
-	uint32	sa_mask;
-	int32	sa_flags;
-};
-
-typedef	byte	Sigval[4];
-struct Siginfo {
-	int32	si_signo;
-	int32	si_errno;
-	int32	si_code;
-	int32	si_pid;
-	uint32	si_uid;
-	int32	si_status;
-	byte	*si_addr;
-	byte	si_value[4];
-	int32	si_band;
-	uint32	__pad[7];
-};
-struct Timeval {
-	int32	tv_sec;
-	int32	tv_usec;
-};
-struct Itimerval {
-	Timeval	it_interval;
-	Timeval	it_value;
-};
-struct Timespec {
-	int32	tv_sec;
-	int32	tv_nsec;
-};
-
-struct FPControl {
-	byte	Pad_cgo_0[2];
-};
-struct FPStatus {
-	byte	Pad_cgo_0[2];
-};
-struct RegMMST {
-	int8	mmst_reg[10];
-	int8	mmst_rsrv[6];
-};
-struct RegXMM {
-	int8	xmm_reg[16];
-};
-
-struct Regs64 {
-	uint64	rax;
-	uint64	rbx;
-	uint64	rcx;
-	uint64	rdx;
-	uint64	rdi;
-	uint64	rsi;
-	uint64	rbp;
-	uint64	rsp;
-	uint64	r8;
-	uint64	r9;
-	uint64	r10;
-	uint64	r11;
-	uint64	r12;
-	uint64	r13;
-	uint64	r14;
-	uint64	r15;
-	uint64	rip;
-	uint64	rflags;
-	uint64	cs;
-	uint64	fs;
-	uint64	gs;
-};
-struct FloatState64 {
-	int32	fpu_reserved[2];
-	FPControl	fpu_fcw;
-	FPStatus	fpu_fsw;
-	uint8	fpu_ftw;
-	uint8	fpu_rsrv1;
-	uint16	fpu_fop;
-	uint32	fpu_ip;
-	uint16	fpu_cs;
-	uint16	fpu_rsrv2;
-	uint32	fpu_dp;
-	uint16	fpu_ds;
-	uint16	fpu_rsrv3;
-	uint32	fpu_mxcsr;
-	uint32	fpu_mxcsrmask;
-	RegMMST	fpu_stmm0;
-	RegMMST	fpu_stmm1;
-	RegMMST	fpu_stmm2;
-	RegMMST	fpu_stmm3;
-	RegMMST	fpu_stmm4;
-	RegMMST	fpu_stmm5;
-	RegMMST	fpu_stmm6;
-	RegMMST	fpu_stmm7;
-	RegXMM	fpu_xmm0;
-	RegXMM	fpu_xmm1;
-	RegXMM	fpu_xmm2;
-	RegXMM	fpu_xmm3;
-	RegXMM	fpu_xmm4;
-	RegXMM	fpu_xmm5;
-	RegXMM	fpu_xmm6;
-	RegXMM	fpu_xmm7;
-	RegXMM	fpu_xmm8;
-	RegXMM	fpu_xmm9;
-	RegXMM	fpu_xmm10;
-	RegXMM	fpu_xmm11;
-	RegXMM	fpu_xmm12;
-	RegXMM	fpu_xmm13;
-	RegXMM	fpu_xmm14;
-	RegXMM	fpu_xmm15;
-	int8	fpu_rsrv4[96];
-	int32	fpu_reserved1;
-};
-struct ExceptionState64 {
-	uint16	trapno;
-	uint16	cpu;
-	uint32	err;
-	uint64	faultvaddr;
-};
-struct Mcontext64 {
-	ExceptionState64	es;
-	Regs64	ss;
-	FloatState64	fs;
-};
-
-struct Regs32 {
-	uint32	eax;
-	uint32	ebx;
-	uint32	ecx;
-	uint32	edx;
-	uint32	edi;
-	uint32	esi;
-	uint32	ebp;
-	uint32	esp;
-	uint32	ss;
-	uint32	eflags;
-	uint32	eip;
-	uint32	cs;
-	uint32	ds;
-	uint32	es;
-	uint32	fs;
-	uint32	gs;
-};
-struct FloatState32 {
-	int32	fpu_reserved[2];
-	FPControl	fpu_fcw;
-	FPStatus	fpu_fsw;
-	uint8	fpu_ftw;
-	uint8	fpu_rsrv1;
-	uint16	fpu_fop;
-	uint32	fpu_ip;
-	uint16	fpu_cs;
-	uint16	fpu_rsrv2;
-	uint32	fpu_dp;
-	uint16	fpu_ds;
-	uint16	fpu_rsrv3;
-	uint32	fpu_mxcsr;
-	uint32	fpu_mxcsrmask;
-	RegMMST	fpu_stmm0;
-	RegMMST	fpu_stmm1;
-	RegMMST	fpu_stmm2;
-	RegMMST	fpu_stmm3;
-	RegMMST	fpu_stmm4;
-	RegMMST	fpu_stmm5;
-	RegMMST	fpu_stmm6;
-	RegMMST	fpu_stmm7;
-	RegXMM	fpu_xmm0;
-	RegXMM	fpu_xmm1;
-	RegXMM	fpu_xmm2;
-	RegXMM	fpu_xmm3;
-	RegXMM	fpu_xmm4;
-	RegXMM	fpu_xmm5;
-	RegXMM	fpu_xmm6;
-	RegXMM	fpu_xmm7;
-	int8	fpu_rsrv4[224];
-	int32	fpu_reserved1;
-};
-struct ExceptionState32 {
-	uint16	trapno;
-	uint16	cpu;
-	uint32	err;
-	uint32	faultvaddr;
-};
-struct Mcontext32 {
-	ExceptionState32	es;
-	Regs32	ss;
-	FloatState32	fs;
-};
-
-struct Ucontext {
-	int32	uc_onstack;
-	uint32	uc_sigmask;
-	StackT	uc_stack;
-	Ucontext	*uc_link;
-	uint32	uc_mcsize;
-	Mcontext32	*uc_mcontext;
-};
-
-struct KeventT {
-	uint32	ident;
-	int16	filter;
-	uint16	flags;
-	uint32	fflags;
-	int32	data;
-	byte	*udata;
-};
-
-
-#pragma pack off
diff --git a/src/runtime/defs_darwin_amd64.go b/src/runtime/defs_darwin_amd64.go
new file mode 100644
index 0000000..d9d9fc5
--- /dev/null
+++ b/src/runtime/defs_darwin_amd64.go
@@ -0,0 +1,385 @@
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_darwin.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_DONTNEED = 0x4
+	_MADV_FREE     = 0x5
+
+	_MACH_MSG_TYPE_MOVE_RECEIVE   = 0x10
+	_MACH_MSG_TYPE_MOVE_SEND      = 0x11
+	_MACH_MSG_TYPE_MOVE_SEND_ONCE = 0x12
+	_MACH_MSG_TYPE_COPY_SEND      = 0x13
+	_MACH_MSG_TYPE_MAKE_SEND      = 0x14
+	_MACH_MSG_TYPE_MAKE_SEND_ONCE = 0x15
+	_MACH_MSG_TYPE_COPY_RECEIVE   = 0x16
+
+	_MACH_MSG_PORT_DESCRIPTOR         = 0x0
+	_MACH_MSG_OOL_DESCRIPTOR          = 0x1
+	_MACH_MSG_OOL_PORTS_DESCRIPTOR    = 0x2
+	_MACH_MSG_OOL_VOLATILE_DESCRIPTOR = 0x3
+
+	_MACH_MSGH_BITS_COMPLEX = 0x80000000
+
+	_MACH_SEND_MSG  = 0x1
+	_MACH_RCV_MSG   = 0x2
+	_MACH_RCV_LARGE = 0x4
+
+	_MACH_SEND_TIMEOUT   = 0x10
+	_MACH_SEND_INTERRUPT = 0x40
+	_MACH_SEND_ALWAYS    = 0x10000
+	_MACH_SEND_TRAILER   = 0x20000
+	_MACH_RCV_TIMEOUT    = 0x100
+	_MACH_RCV_NOTIFY     = 0x200
+	_MACH_RCV_INTERRUPT  = 0x400
+	_MACH_RCV_OVERWRITE  = 0x1000
+
+	_NDR_PROTOCOL_2_0      = 0x0
+	_NDR_INT_BIG_ENDIAN    = 0x0
+	_NDR_INT_LITTLE_ENDIAN = 0x1
+	_NDR_FLOAT_IEEE        = 0x0
+	_NDR_CHAR_ASCII        = 0x0
+
+	_SA_SIGINFO   = 0x40
+	_SA_RESTART   = 0x2
+	_SA_ONSTACK   = 0x1
+	_SA_USERTRAMP = 0x100
+	_SA_64REGSET  = 0x200
+
+	_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 = 0x7
+	_FPE_INTOVF = 0x8
+	_FPE_FLTDIV = 0x1
+	_FPE_FLTOVF = 0x2
+	_FPE_FLTUND = 0x3
+	_FPE_FLTRES = 0x4
+	_FPE_FLTINV = 0x5
+	_FPE_FLTSUB = 0x6
+
+	_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_RECEIPT   = 0x40
+	_EV_ERROR     = 0x4000
+	_EVFILT_READ  = -0x1
+	_EVFILT_WRITE = -0x2
+)
+
+type machbody struct {
+	msgh_descriptor_count uint32
+}
+
+type machheader struct {
+	msgh_bits        uint32
+	msgh_size        uint32
+	msgh_remote_port uint32
+	msgh_local_port  uint32
+	msgh_reserved    uint32
+	msgh_id          int32
+}
+
+type machndr struct {
+	mig_vers     uint8
+	if_vers      uint8
+	reserved1    uint8
+	mig_encoding uint8
+	int_rep      uint8
+	char_rep     uint8
+	float_rep    uint8
+	reserved2    uint8
+}
+
+type machport struct {
+	name        uint32
+	pad1        uint32
+	pad2        uint16
+	disposition uint8
+	_type       uint8
+}
+
+type stackt struct {
+	ss_sp     *byte
+	ss_size   uintptr
+	ss_flags  int32
+	pad_cgo_0 [4]byte
+}
+
+type sigactiont struct {
+	__sigaction_u [8]byte
+	sa_tramp      unsafe.Pointer
+	sa_mask       uint32
+	sa_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   uint64
+	si_value  [8]byte
+	si_band   int64
+	__pad     [7]uint64
+}
+
+type timeval struct {
+	tv_sec    int64
+	tv_usec   int32
+	pad_cgo_0 [4]byte
+}
+
+func (tv *timeval) set_usec(x int32) {
+	tv.tv_usec = x
+}
+
+type itimerval struct {
+	it_interval timeval
+	it_value    timeval
+}
+
+type timespec struct {
+	tv_sec  int64
+	tv_nsec int64
+}
+
+type fpcontrol struct {
+	pad_cgo_0 [2]byte
+}
+
+type fpstatus struct {
+	pad_cgo_0 [2]byte
+}
+
+type regmmst struct {
+	mmst_reg  [10]int8
+	mmst_rsrv [6]int8
+}
+
+type regxmm struct {
+	xmm_reg [16]int8
+}
+
+type regs64 struct {
+	rax    uint64
+	rbx    uint64
+	rcx    uint64
+	rdx    uint64
+	rdi    uint64
+	rsi    uint64
+	rbp    uint64
+	rsp    uint64
+	r8     uint64
+	r9     uint64
+	r10    uint64
+	r11    uint64
+	r12    uint64
+	r13    uint64
+	r14    uint64
+	r15    uint64
+	rip    uint64
+	rflags uint64
+	cs     uint64
+	fs     uint64
+	gs     uint64
+}
+
+type floatstate64 struct {
+	fpu_reserved  [2]int32
+	fpu_fcw       fpcontrol
+	fpu_fsw       fpstatus
+	fpu_ftw       uint8
+	fpu_rsrv1     uint8
+	fpu_fop       uint16
+	fpu_ip        uint32
+	fpu_cs        uint16
+	fpu_rsrv2     uint16
+	fpu_dp        uint32
+	fpu_ds        uint16
+	fpu_rsrv3     uint16
+	fpu_mxcsr     uint32
+	fpu_mxcsrmask uint32
+	fpu_stmm0     regmmst
+	fpu_stmm1     regmmst
+	fpu_stmm2     regmmst
+	fpu_stmm3     regmmst
+	fpu_stmm4     regmmst
+	fpu_stmm5     regmmst
+	fpu_stmm6     regmmst
+	fpu_stmm7     regmmst
+	fpu_xmm0      regxmm
+	fpu_xmm1      regxmm
+	fpu_xmm2      regxmm
+	fpu_xmm3      regxmm
+	fpu_xmm4      regxmm
+	fpu_xmm5      regxmm
+	fpu_xmm6      regxmm
+	fpu_xmm7      regxmm
+	fpu_xmm8      regxmm
+	fpu_xmm9      regxmm
+	fpu_xmm10     regxmm
+	fpu_xmm11     regxmm
+	fpu_xmm12     regxmm
+	fpu_xmm13     regxmm
+	fpu_xmm14     regxmm
+	fpu_xmm15     regxmm
+	fpu_rsrv4     [96]int8
+	fpu_reserved1 int32
+}
+
+type exceptionstate64 struct {
+	trapno     uint16
+	cpu        uint16
+	err        uint32
+	faultvaddr uint64
+}
+
+type mcontext64 struct {
+	es        exceptionstate64
+	ss        regs64
+	fs        floatstate64
+	pad_cgo_0 [4]byte
+}
+
+type regs32 struct {
+	eax    uint32
+	ebx    uint32
+	ecx    uint32
+	edx    uint32
+	edi    uint32
+	esi    uint32
+	ebp    uint32
+	esp    uint32
+	ss     uint32
+	eflags uint32
+	eip    uint32
+	cs     uint32
+	ds     uint32
+	es     uint32
+	fs     uint32
+	gs     uint32
+}
+
+type floatstate32 struct {
+	fpu_reserved  [2]int32
+	fpu_fcw       fpcontrol
+	fpu_fsw       fpstatus
+	fpu_ftw       uint8
+	fpu_rsrv1     uint8
+	fpu_fop       uint16
+	fpu_ip        uint32
+	fpu_cs        uint16
+	fpu_rsrv2     uint16
+	fpu_dp        uint32
+	fpu_ds        uint16
+	fpu_rsrv3     uint16
+	fpu_mxcsr     uint32
+	fpu_mxcsrmask uint32
+	fpu_stmm0     regmmst
+	fpu_stmm1     regmmst
+	fpu_stmm2     regmmst
+	fpu_stmm3     regmmst
+	fpu_stmm4     regmmst
+	fpu_stmm5     regmmst
+	fpu_stmm6     regmmst
+	fpu_stmm7     regmmst
+	fpu_xmm0      regxmm
+	fpu_xmm1      regxmm
+	fpu_xmm2      regxmm
+	fpu_xmm3      regxmm
+	fpu_xmm4      regxmm
+	fpu_xmm5      regxmm
+	fpu_xmm6      regxmm
+	fpu_xmm7      regxmm
+	fpu_rsrv4     [224]int8
+	fpu_reserved1 int32
+}
+
+type exceptionstate32 struct {
+	trapno     uint16
+	cpu        uint16
+	err        uint32
+	faultvaddr uint32
+}
+
+type mcontext32 struct {
+	es exceptionstate32
+	ss regs32
+	fs floatstate32
+}
+
+type ucontext struct {
+	uc_onstack  int32
+	uc_sigmask  uint32
+	uc_stack    stackt
+	uc_link     *ucontext
+	uc_mcsize   uint64
+	uc_mcontext *mcontext64
+}
+
+type keventt struct {
+	ident  uint64
+	filter int16
+	flags  uint16
+	fflags uint32
+	data   int64
+	udata  *byte
+}
diff --git a/src/runtime/defs_darwin_amd64.h b/src/runtime/defs_darwin_amd64.h
deleted file mode 100644
index 4bf83c1..0000000
--- a/src/runtime/defs_darwin_amd64.h
+++ /dev/null
@@ -1,395 +0,0 @@
-// Created by cgo -cdefs - DO NOT EDIT
-// cgo -cdefs defs_darwin.go
-
-
-enum {
-	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_DONTNEED	= 0x4,
-	MADV_FREE	= 0x5,
-
-	MACH_MSG_TYPE_MOVE_RECEIVE	= 0x10,
-	MACH_MSG_TYPE_MOVE_SEND		= 0x11,
-	MACH_MSG_TYPE_MOVE_SEND_ONCE	= 0x12,
-	MACH_MSG_TYPE_COPY_SEND		= 0x13,
-	MACH_MSG_TYPE_MAKE_SEND		= 0x14,
-	MACH_MSG_TYPE_MAKE_SEND_ONCE	= 0x15,
-	MACH_MSG_TYPE_COPY_RECEIVE	= 0x16,
-
-	MACH_MSG_PORT_DESCRIPTOR		= 0x0,
-	MACH_MSG_OOL_DESCRIPTOR			= 0x1,
-	MACH_MSG_OOL_PORTS_DESCRIPTOR		= 0x2,
-	MACH_MSG_OOL_VOLATILE_DESCRIPTOR	= 0x3,
-
-	MACH_MSGH_BITS_COMPLEX	= 0x80000000,
-
-	MACH_SEND_MSG	= 0x1,
-	MACH_RCV_MSG	= 0x2,
-	MACH_RCV_LARGE	= 0x4,
-
-	MACH_SEND_TIMEOUT	= 0x10,
-	MACH_SEND_INTERRUPT	= 0x40,
-	MACH_SEND_ALWAYS	= 0x10000,
-	MACH_SEND_TRAILER	= 0x20000,
-	MACH_RCV_TIMEOUT	= 0x100,
-	MACH_RCV_NOTIFY		= 0x200,
-	MACH_RCV_INTERRUPT	= 0x400,
-	MACH_RCV_OVERWRITE	= 0x1000,
-
-	NDR_PROTOCOL_2_0	= 0x0,
-	NDR_INT_BIG_ENDIAN	= 0x0,
-	NDR_INT_LITTLE_ENDIAN	= 0x1,
-	NDR_FLOAT_IEEE		= 0x0,
-	NDR_CHAR_ASCII		= 0x0,
-
-	SA_SIGINFO	= 0x40,
-	SA_RESTART	= 0x2,
-	SA_ONSTACK	= 0x1,
-	SA_USERTRAMP	= 0x100,
-	SA_64REGSET	= 0x200,
-
-	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	= 0x7,
-	FPE_INTOVF	= 0x8,
-	FPE_FLTDIV	= 0x1,
-	FPE_FLTOVF	= 0x2,
-	FPE_FLTUND	= 0x3,
-	FPE_FLTRES	= 0x4,
-	FPE_FLTINV	= 0x5,
-	FPE_FLTSUB	= 0x6,
-
-	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_RECEIPT	= 0x40,
-	EV_ERROR	= 0x4000,
-	EVFILT_READ	= -0x1,
-	EVFILT_WRITE	= -0x2,
-};
-
-typedef struct MachBody MachBody;
-typedef struct MachHeader MachHeader;
-typedef struct MachNDR MachNDR;
-typedef struct MachPort MachPort;
-typedef struct StackT StackT;
-typedef struct SigactionT SigactionT;
-typedef struct Siginfo Siginfo;
-typedef struct Timeval Timeval;
-typedef struct Itimerval Itimerval;
-typedef struct Timespec Timespec;
-typedef struct FPControl FPControl;
-typedef struct FPStatus FPStatus;
-typedef struct RegMMST RegMMST;
-typedef struct RegXMM RegXMM;
-typedef struct Regs64 Regs64;
-typedef struct FloatState64 FloatState64;
-typedef struct ExceptionState64 ExceptionState64;
-typedef struct Mcontext64 Mcontext64;
-typedef struct Regs32 Regs32;
-typedef struct FloatState32 FloatState32;
-typedef struct ExceptionState32 ExceptionState32;
-typedef struct Mcontext32 Mcontext32;
-typedef struct Ucontext Ucontext;
-typedef struct KeventT KeventT;
-
-#pragma pack on
-
-struct MachBody {
-	uint32	msgh_descriptor_count;
-};
-struct MachHeader {
-	uint32	msgh_bits;
-	uint32	msgh_size;
-	uint32	msgh_remote_port;
-	uint32	msgh_local_port;
-	uint32	msgh_reserved;
-	int32	msgh_id;
-};
-struct MachNDR {
-	uint8	mig_vers;
-	uint8	if_vers;
-	uint8	reserved1;
-	uint8	mig_encoding;
-	uint8	int_rep;
-	uint8	char_rep;
-	uint8	float_rep;
-	uint8	reserved2;
-};
-struct MachPort {
-	uint32	name;
-	uint32	pad1;
-	uint16	pad2;
-	uint8	disposition;
-	uint8	type;
-};
-
-struct StackT {
-	byte	*ss_sp;
-	uint64	ss_size;
-	int32	ss_flags;
-	byte	Pad_cgo_0[4];
-};
-typedef	byte	Sighandler[8];
-
-struct SigactionT {
-	byte	__sigaction_u[8];
-	void	*sa_tramp;
-	uint32	sa_mask;
-	int32	sa_flags;
-};
-
-typedef	byte	Sigval[8];
-struct Siginfo {
-	int32	si_signo;
-	int32	si_errno;
-	int32	si_code;
-	int32	si_pid;
-	uint32	si_uid;
-	int32	si_status;
-	byte	*si_addr;
-	byte	si_value[8];
-	int64	si_band;
-	uint64	__pad[7];
-};
-struct Timeval {
-	int64	tv_sec;
-	int32	tv_usec;
-	byte	Pad_cgo_0[4];
-};
-struct Itimerval {
-	Timeval	it_interval;
-	Timeval	it_value;
-};
-struct Timespec {
-	int64	tv_sec;
-	int64	tv_nsec;
-};
-
-struct FPControl {
-	byte	Pad_cgo_0[2];
-};
-struct FPStatus {
-	byte	Pad_cgo_0[2];
-};
-struct RegMMST {
-	int8	mmst_reg[10];
-	int8	mmst_rsrv[6];
-};
-struct RegXMM {
-	int8	xmm_reg[16];
-};
-
-struct Regs64 {
-	uint64	rax;
-	uint64	rbx;
-	uint64	rcx;
-	uint64	rdx;
-	uint64	rdi;
-	uint64	rsi;
-	uint64	rbp;
-	uint64	rsp;
-	uint64	r8;
-	uint64	r9;
-	uint64	r10;
-	uint64	r11;
-	uint64	r12;
-	uint64	r13;
-	uint64	r14;
-	uint64	r15;
-	uint64	rip;
-	uint64	rflags;
-	uint64	cs;
-	uint64	fs;
-	uint64	gs;
-};
-struct FloatState64 {
-	int32	fpu_reserved[2];
-	FPControl	fpu_fcw;
-	FPStatus	fpu_fsw;
-	uint8	fpu_ftw;
-	uint8	fpu_rsrv1;
-	uint16	fpu_fop;
-	uint32	fpu_ip;
-	uint16	fpu_cs;
-	uint16	fpu_rsrv2;
-	uint32	fpu_dp;
-	uint16	fpu_ds;
-	uint16	fpu_rsrv3;
-	uint32	fpu_mxcsr;
-	uint32	fpu_mxcsrmask;
-	RegMMST	fpu_stmm0;
-	RegMMST	fpu_stmm1;
-	RegMMST	fpu_stmm2;
-	RegMMST	fpu_stmm3;
-	RegMMST	fpu_stmm4;
-	RegMMST	fpu_stmm5;
-	RegMMST	fpu_stmm6;
-	RegMMST	fpu_stmm7;
-	RegXMM	fpu_xmm0;
-	RegXMM	fpu_xmm1;
-	RegXMM	fpu_xmm2;
-	RegXMM	fpu_xmm3;
-	RegXMM	fpu_xmm4;
-	RegXMM	fpu_xmm5;
-	RegXMM	fpu_xmm6;
-	RegXMM	fpu_xmm7;
-	RegXMM	fpu_xmm8;
-	RegXMM	fpu_xmm9;
-	RegXMM	fpu_xmm10;
-	RegXMM	fpu_xmm11;
-	RegXMM	fpu_xmm12;
-	RegXMM	fpu_xmm13;
-	RegXMM	fpu_xmm14;
-	RegXMM	fpu_xmm15;
-	int8	fpu_rsrv4[96];
-	int32	fpu_reserved1;
-};
-struct ExceptionState64 {
-	uint16	trapno;
-	uint16	cpu;
-	uint32	err;
-	uint64	faultvaddr;
-};
-struct Mcontext64 {
-	ExceptionState64	es;
-	Regs64	ss;
-	FloatState64	fs;
-	byte	Pad_cgo_0[4];
-};
-
-struct Regs32 {
-	uint32	eax;
-	uint32	ebx;
-	uint32	ecx;
-	uint32	edx;
-	uint32	edi;
-	uint32	esi;
-	uint32	ebp;
-	uint32	esp;
-	uint32	ss;
-	uint32	eflags;
-	uint32	eip;
-	uint32	cs;
-	uint32	ds;
-	uint32	es;
-	uint32	fs;
-	uint32	gs;
-};
-struct FloatState32 {
-	int32	fpu_reserved[2];
-	FPControl	fpu_fcw;
-	FPStatus	fpu_fsw;
-	uint8	fpu_ftw;
-	uint8	fpu_rsrv1;
-	uint16	fpu_fop;
-	uint32	fpu_ip;
-	uint16	fpu_cs;
-	uint16	fpu_rsrv2;
-	uint32	fpu_dp;
-	uint16	fpu_ds;
-	uint16	fpu_rsrv3;
-	uint32	fpu_mxcsr;
-	uint32	fpu_mxcsrmask;
-	RegMMST	fpu_stmm0;
-	RegMMST	fpu_stmm1;
-	RegMMST	fpu_stmm2;
-	RegMMST	fpu_stmm3;
-	RegMMST	fpu_stmm4;
-	RegMMST	fpu_stmm5;
-	RegMMST	fpu_stmm6;
-	RegMMST	fpu_stmm7;
-	RegXMM	fpu_xmm0;
-	RegXMM	fpu_xmm1;
-	RegXMM	fpu_xmm2;
-	RegXMM	fpu_xmm3;
-	RegXMM	fpu_xmm4;
-	RegXMM	fpu_xmm5;
-	RegXMM	fpu_xmm6;
-	RegXMM	fpu_xmm7;
-	int8	fpu_rsrv4[224];
-	int32	fpu_reserved1;
-};
-struct ExceptionState32 {
-	uint16	trapno;
-	uint16	cpu;
-	uint32	err;
-	uint32	faultvaddr;
-};
-struct Mcontext32 {
-	ExceptionState32	es;
-	Regs32	ss;
-	FloatState32	fs;
-};
-
-struct Ucontext {
-	int32	uc_onstack;
-	uint32	uc_sigmask;
-	StackT	uc_stack;
-	Ucontext	*uc_link;
-	uint64	uc_mcsize;
-	Mcontext64	*uc_mcontext;
-};
-
-struct KeventT {
-	uint64	ident;
-	int16	filter;
-	uint16	flags;
-	uint32	fflags;
-	int64	data;
-	byte	*udata;
-};
-
-
-#pragma pack off
diff --git a/src/runtime/defs_darwin_arm.go b/src/runtime/defs_darwin_arm.go
new file mode 100644
index 0000000..b53336c
--- /dev/null
+++ b/src/runtime/defs_darwin_arm.go
@@ -0,0 +1,245 @@
+// Note: cgo can't handle some Darwin/ARM structures, so this file can't
+// be auto generated by cgo yet.
+// Created based on output of `cgo -cdefs defs_darwin.go` and Darwin/ARM
+// specific header (mainly mcontext and ucontext related stuff)
+
+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_DONTNEED = 0x4
+	_MADV_FREE     = 0x5
+
+	_MACH_MSG_TYPE_MOVE_RECEIVE   = 0x10
+	_MACH_MSG_TYPE_MOVE_SEND      = 0x11
+	_MACH_MSG_TYPE_MOVE_SEND_ONCE = 0x12
+	_MACH_MSG_TYPE_COPY_SEND      = 0x13
+	_MACH_MSG_TYPE_MAKE_SEND      = 0x14
+	_MACH_MSG_TYPE_MAKE_SEND_ONCE = 0x15
+	_MACH_MSG_TYPE_COPY_RECEIVE   = 0x16
+
+	_MACH_MSG_PORT_DESCRIPTOR         = 0x0
+	_MACH_MSG_OOL_DESCRIPTOR          = 0x1
+	_MACH_MSG_OOL_PORTS_DESCRIPTOR    = 0x2
+	_MACH_MSG_OOL_VOLATILE_DESCRIPTOR = 0x3
+
+	_MACH_MSGH_BITS_COMPLEX = 0x80000000
+
+	_MACH_SEND_MSG  = 0x1
+	_MACH_RCV_MSG   = 0x2
+	_MACH_RCV_LARGE = 0x4
+
+	_MACH_SEND_TIMEOUT   = 0x10
+	_MACH_SEND_INTERRUPT = 0x40
+	_MACH_SEND_ALWAYS    = 0x10000
+	_MACH_SEND_TRAILER   = 0x20000
+	_MACH_RCV_TIMEOUT    = 0x100
+	_MACH_RCV_NOTIFY     = 0x200
+	_MACH_RCV_INTERRUPT  = 0x400
+	_MACH_RCV_OVERWRITE  = 0x1000
+
+	_NDR_PROTOCOL_2_0      = 0x0
+	_NDR_INT_BIG_ENDIAN    = 0x0
+	_NDR_INT_LITTLE_ENDIAN = 0x1
+	_NDR_FLOAT_IEEE        = 0x0
+	_NDR_CHAR_ASCII        = 0x0
+
+	_SA_SIGINFO   = 0x40
+	_SA_RESTART   = 0x2
+	_SA_ONSTACK   = 0x1
+	_SA_USERTRAMP = 0x100
+	_SA_64REGSET  = 0x200
+
+	_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 = 0x7
+	_FPE_INTOVF = 0x8
+	_FPE_FLTDIV = 0x1
+	_FPE_FLTOVF = 0x2
+	_FPE_FLTUND = 0x3
+	_FPE_FLTRES = 0x4
+	_FPE_FLTINV = 0x5
+	_FPE_FLTSUB = 0x6
+
+	_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_RECEIPT   = 0x40
+	_EV_ERROR     = 0x4000
+	_EVFILT_READ  = -0x1
+	_EVFILT_WRITE = -0x2
+)
+
+type machbody struct {
+	msgh_descriptor_count uint32
+}
+
+type machheader struct {
+	msgh_bits        uint32
+	msgh_size        uint32
+	msgh_remote_port uint32
+	msgh_local_port  uint32
+	msgh_reserved    uint32
+	msgh_id          int32
+}
+
+type machndr struct {
+	mig_vers     uint8
+	if_vers      uint8
+	reserved1    uint8
+	mig_encoding uint8
+	int_rep      uint8
+	char_rep     uint8
+	float_rep    uint8
+	reserved2    uint8
+}
+
+type machport struct {
+	name        uint32
+	pad1        uint32
+	pad2        uint16
+	disposition uint8
+	_type       uint8
+}
+
+type stackt struct {
+	ss_sp    *byte
+	ss_size  uintptr
+	ss_flags int32
+}
+
+type sigactiont struct {
+	__sigaction_u [4]byte
+	sa_tramp      unsafe.Pointer
+	sa_mask       uint32
+	sa_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   uint32
+	si_value  [4]byte
+	si_band   int32
+	__pad     [7]uint32
+}
+
+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 timespec struct {
+	tv_sec  int32
+	tv_nsec int32
+}
+
+type floatstate32 struct {
+	r     [32]uint32
+	fpscr uint32
+}
+
+type regs32 struct {
+	r    [13]uint32 // r0 to r12
+	sp   uint32     // r13
+	lr   uint32     // r14
+	pc   uint32     // r15
+	cpsr uint32
+}
+
+type exceptionstate32 struct {
+	trapno     uint32 // NOTE: on 386, the trapno field is split into trapno and cpu
+	err        uint32
+	faultvaddr uint32
+}
+
+type mcontext32 struct {
+	es exceptionstate32
+	ss regs32
+	fs floatstate32
+}
+
+type ucontext struct {
+	uc_onstack  int32
+	uc_sigmask  uint32
+	uc_stack    stackt
+	uc_link     *ucontext
+	uc_mcsize   uint32
+	uc_mcontext *mcontext32
+}
+
+type keventt struct {
+	ident  uint32
+	filter int16
+	flags  uint16
+	fflags uint32
+	data   int32
+	udata  *byte
+}
diff --git a/src/runtime/defs_darwin_arm64.go b/src/runtime/defs_darwin_arm64.go
new file mode 100644
index 0000000..3cc77c1
--- /dev/null
+++ b/src/runtime/defs_darwin_arm64.go
@@ -0,0 +1,248 @@
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_darwin.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_DONTNEED = 0x4
+	_MADV_FREE     = 0x5
+
+	_MACH_MSG_TYPE_MOVE_RECEIVE   = 0x10
+	_MACH_MSG_TYPE_MOVE_SEND      = 0x11
+	_MACH_MSG_TYPE_MOVE_SEND_ONCE = 0x12
+	_MACH_MSG_TYPE_COPY_SEND      = 0x13
+	_MACH_MSG_TYPE_MAKE_SEND      = 0x14
+	_MACH_MSG_TYPE_MAKE_SEND_ONCE = 0x15
+	_MACH_MSG_TYPE_COPY_RECEIVE   = 0x16
+
+	_MACH_MSG_PORT_DESCRIPTOR         = 0x0
+	_MACH_MSG_OOL_DESCRIPTOR          = 0x1
+	_MACH_MSG_OOL_PORTS_DESCRIPTOR    = 0x2
+	_MACH_MSG_OOL_VOLATILE_DESCRIPTOR = 0x3
+
+	_MACH_MSGH_BITS_COMPLEX = 0x80000000
+
+	_MACH_SEND_MSG  = 0x1
+	_MACH_RCV_MSG   = 0x2
+	_MACH_RCV_LARGE = 0x4
+
+	_MACH_SEND_TIMEOUT   = 0x10
+	_MACH_SEND_INTERRUPT = 0x40
+	_MACH_SEND_ALWAYS    = 0x10000
+	_MACH_SEND_TRAILER   = 0x20000
+	_MACH_RCV_TIMEOUT    = 0x100
+	_MACH_RCV_NOTIFY     = 0x200
+	_MACH_RCV_INTERRUPT  = 0x400
+	_MACH_RCV_OVERWRITE  = 0x1000
+
+	_NDR_PROTOCOL_2_0      = 0x0
+	_NDR_INT_BIG_ENDIAN    = 0x0
+	_NDR_INT_LITTLE_ENDIAN = 0x1
+	_NDR_FLOAT_IEEE        = 0x0
+	_NDR_CHAR_ASCII        = 0x0
+
+	_SA_SIGINFO   = 0x40
+	_SA_RESTART   = 0x2
+	_SA_ONSTACK   = 0x1
+	_SA_USERTRAMP = 0x100
+	_SA_64REGSET  = 0x200
+
+	_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 = 0x7
+	_FPE_INTOVF = 0x8
+	_FPE_FLTDIV = 0x1
+	_FPE_FLTOVF = 0x2
+	_FPE_FLTUND = 0x3
+	_FPE_FLTRES = 0x4
+	_FPE_FLTINV = 0x5
+	_FPE_FLTSUB = 0x6
+
+	_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_RECEIPT   = 0x40
+	_EV_ERROR     = 0x4000
+	_EVFILT_READ  = -0x1
+	_EVFILT_WRITE = -0x2
+)
+
+type machbody struct {
+	msgh_descriptor_count uint32
+}
+
+type machheader struct {
+	msgh_bits        uint32
+	msgh_size        uint32
+	msgh_remote_port uint32
+	msgh_local_port  uint32
+	msgh_reserved    uint32
+	msgh_id          int32
+}
+
+type machndr struct {
+	mig_vers     uint8
+	if_vers      uint8
+	reserved1    uint8
+	mig_encoding uint8
+	int_rep      uint8
+	char_rep     uint8
+	float_rep    uint8
+	reserved2    uint8
+}
+
+type machport struct {
+	name        uint32
+	pad1        uint32
+	pad2        uint16
+	disposition uint8
+	_type       uint8
+}
+
+type stackt struct {
+	ss_sp     *byte
+	ss_size   uintptr
+	ss_flags  int32
+	pad_cgo_0 [4]byte
+}
+
+type sigactiont struct {
+	__sigaction_u [8]byte
+	sa_tramp      unsafe.Pointer
+	sa_mask       uint32
+	sa_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   *byte
+	si_value  [8]byte
+	si_band   int64
+	__pad     [7]uint64
+}
+
+type timeval struct {
+	tv_sec    int64
+	tv_usec   int32
+	pad_cgo_0 [4]byte
+}
+
+func (tv *timeval) set_usec(x int32) {
+	tv.tv_usec = x
+}
+
+type itimerval struct {
+	it_interval timeval
+	it_value    timeval
+}
+
+type timespec struct {
+	tv_sec  int64
+	tv_nsec int64
+}
+
+type exceptionstate64 struct {
+	far uint64 // virtual fault addr
+	esr uint32 // exception syndrome
+	exc uint32 // number of arm exception taken
+}
+
+type regs64 struct {
+	x     [29]uint64 // registers x0 to x28
+	fp    uint64     // frame register, x29
+	lr    uint64     // link register, x30
+	sp    uint64     // stack pointer, x31
+	pc    uint64     // program counter
+	cpsr  uint32     // current program status register
+	__pad uint32
+}
+
+type neonstate64 struct {
+	v    [64]uint64 // actually [32]uint128
+	fpsr uint32
+	fpcr uint32
+}
+
+type mcontext64 struct {
+	es exceptionstate64
+	ss regs64
+	ns neonstate64
+}
+
+type ucontext struct {
+	uc_onstack  int32
+	uc_sigmask  uint32
+	uc_stack    stackt
+	uc_link     *ucontext
+	uc_mcsize   uint64
+	uc_mcontext *mcontext64
+}
+
+type keventt struct {
+	ident  uint64
+	filter int16
+	flags  uint16
+	fflags uint32
+	data   int64
+	udata  *byte
+}
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.h b/src/runtime/defs_dragonfly_386.h
deleted file mode 100644
index f86b9c6..0000000
--- a/src/runtime/defs_dragonfly_386.h
+++ /dev/null
@@ -1,198 +0,0 @@
-// Created by cgo -cdefs - DO NOT EDIT
-// cgo -cdefs defs_dragonfly.go
-
-
-enum {
-	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,
-};
-
-typedef struct Rtprio Rtprio;
-typedef struct Lwpparams Lwpparams;
-typedef struct SigaltstackT SigaltstackT;
-typedef struct Sigset Sigset;
-typedef struct StackT StackT;
-typedef struct Siginfo Siginfo;
-typedef struct Mcontext Mcontext;
-typedef struct Ucontext Ucontext;
-typedef struct Timespec Timespec;
-typedef struct Timeval Timeval;
-typedef struct Itimerval Itimerval;
-typedef struct KeventT KeventT;
-
-#pragma pack on
-
-struct Rtprio {
-	uint16	type;
-	uint16	prio;
-};
-struct Lwpparams {
-	void	*func;
-	byte	*arg;
-	byte	*stack;
-	int32	*tid1;
-	int32	*tid2;
-};
-struct SigaltstackT {
-	int8	*ss_sp;
-	uint32	ss_size;
-	int32	ss_flags;
-};
-struct Sigset {
-	uint32	__bits[4];
-};
-struct StackT {
-	int8	*ss_sp;
-	uint32	ss_size;
-	int32	ss_flags;
-};
-
-struct Siginfo {
-	int32	si_signo;
-	int32	si_errno;
-	int32	si_code;
-	int32	si_pid;
-	uint32	si_uid;
-	int32	si_status;
-	byte	*si_addr;
-	byte	si_value[4];
-	int32	si_band;
-	int32	__spare__[7];
-};
-
-struct Mcontext {
-	int32	mc_onstack;
-	int32	mc_gs;
-	int32	mc_fs;
-	int32	mc_es;
-	int32	mc_ds;
-	int32	mc_edi;
-	int32	mc_esi;
-	int32	mc_ebp;
-	int32	mc_isp;
-	int32	mc_ebx;
-	int32	mc_edx;
-	int32	mc_ecx;
-	int32	mc_eax;
-	int32	mc_xflags;
-	int32	mc_trapno;
-	int32	mc_err;
-	int32	mc_eip;
-	int32	mc_cs;
-	int32	mc_eflags;
-	int32	mc_esp;
-	int32	mc_ss;
-	int32	mc_len;
-	int32	mc_fpformat;
-	int32	mc_ownedfp;
-	int32	mc_fpregs[128];
-	int32	__spare__[16];
-};
-struct Ucontext {
-	Sigset	uc_sigmask;
-	Mcontext	uc_mcontext;
-	Ucontext	*uc_link;
-	StackT	uc_stack;
-	int32	__spare__[8];
-};
-
-struct Timespec {
-	int32	tv_sec;
-	int32	tv_nsec;
-};
-struct Timeval {
-	int32	tv_sec;
-	int32	tv_usec;
-};
-struct Itimerval {
-	Timeval	it_interval;
-	Timeval	it_value;
-};
-
-struct KeventT {
-	uint32	ident;
-	int16	filter;
-	uint16	flags;
-	uint32	fflags;
-	int32	data;
-	byte	*udata;
-};
-
-
-#pragma pack off
diff --git a/src/runtime/defs_dragonfly_amd64.go b/src/runtime/defs_dragonfly_amd64.go
new file mode 100644
index 0000000..3ac10b0
--- /dev/null
+++ b/src/runtime/defs_dragonfly_amd64.go
@@ -0,0 +1,208 @@
+// 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
+	pad_cgo_0 [4]byte
+}
+
+type sigset struct {
+	__bits [4]uint32
+}
+
+type stackt struct {
+	ss_sp     uintptr
+	ss_size   uintptr
+	ss_flags  int32
+	pad_cgo_0 [4]byte
+}
+
+type siginfo struct {
+	si_signo  int32
+	si_errno  int32
+	si_code   int32
+	si_pid    int32
+	si_uid    uint32
+	si_status int32
+	si_addr   uint64
+	si_value  [8]byte
+	si_band   int64
+	__spare__ [7]int32
+	pad_cgo_0 [4]byte
+}
+
+type mcontext struct {
+	mc_onstack  uint64
+	mc_rdi      uint64
+	mc_rsi      uint64
+	mc_rdx      uint64
+	mc_rcx      uint64
+	mc_r8       uint64
+	mc_r9       uint64
+	mc_rax      uint64
+	mc_rbx      uint64
+	mc_rbp      uint64
+	mc_r10      uint64
+	mc_r11      uint64
+	mc_r12      uint64
+	mc_r13      uint64
+	mc_r14      uint64
+	mc_r15      uint64
+	mc_xflags   uint64
+	mc_trapno   uint64
+	mc_addr     uint64
+	mc_flags    uint64
+	mc_err      uint64
+	mc_rip      uint64
+	mc_cs       uint64
+	mc_rflags   uint64
+	mc_rsp      uint64
+	mc_ss       uint64
+	mc_len      uint32
+	mc_fpformat uint32
+	mc_ownedfp  uint32
+	mc_reserved uint32
+	mc_unused   [8]uint32
+	mc_fpregs   [256]int32
+}
+
+type ucontext struct {
+	uc_sigmask  sigset
+	pad_cgo_0   [48]byte
+	uc_mcontext mcontext
+	uc_link     *ucontext
+	uc_stack    stackt
+	__spare__   [8]int32
+}
+
+type timespec struct {
+	tv_sec  int64
+	tv_nsec int64
+}
+
+func (ts *timespec) set_sec(x int64) {
+	ts.tv_sec = x
+}
+
+type timeval struct {
+	tv_sec  int64
+	tv_usec int64
+}
+
+func (tv *timeval) set_usec(x int32) {
+	tv.tv_usec = int64(x)
+}
+
+type itimerval struct {
+	it_interval timeval
+	it_value    timeval
+}
+
+type keventt struct {
+	ident  uint64
+	filter int16
+	flags  uint16
+	fflags uint32
+	data   int64
+	udata  *byte
+}
diff --git a/src/runtime/defs_dragonfly_amd64.h b/src/runtime/defs_dragonfly_amd64.h
deleted file mode 100644
index 6715552..0000000
--- a/src/runtime/defs_dragonfly_amd64.h
+++ /dev/null
@@ -1,208 +0,0 @@
-// Created by cgo -cdefs - DO NOT EDIT
-// cgo -cdefs defs_dragonfly.go
-
-
-enum {
-	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,
-};
-
-typedef struct Rtprio Rtprio;
-typedef struct Lwpparams Lwpparams;
-typedef struct SigaltstackT SigaltstackT;
-typedef struct Sigset Sigset;
-typedef struct StackT StackT;
-typedef struct Siginfo Siginfo;
-typedef struct Mcontext Mcontext;
-typedef struct Ucontext Ucontext;
-typedef struct Timespec Timespec;
-typedef struct Timeval Timeval;
-typedef struct Itimerval Itimerval;
-typedef struct KeventT KeventT;
-
-#pragma pack on
-
-struct Rtprio {
-	uint16	type;
-	uint16	prio;
-};
-struct Lwpparams {
-	void	*func;
-	byte	*arg;
-	byte	*stack;
-	int32	*tid1;
-	int32	*tid2;
-};
-struct SigaltstackT {
-	int8	*ss_sp;
-	uint64	ss_size;
-	int32	ss_flags;
-	byte	Pad_cgo_0[4];
-};
-struct Sigset {
-	uint32	__bits[4];
-};
-struct StackT {
-	int8	*ss_sp;
-	uint64	ss_size;
-	int32	ss_flags;
-	byte	Pad_cgo_0[4];
-};
-
-struct Siginfo {
-	int32	si_signo;
-	int32	si_errno;
-	int32	si_code;
-	int32	si_pid;
-	uint32	si_uid;
-	int32	si_status;
-	byte	*si_addr;
-	byte	si_value[8];
-	int64	si_band;
-	int32	__spare__[7];
-	byte	Pad_cgo_0[4];
-};
-
-struct Mcontext {
-	int64	mc_onstack;
-	int64	mc_rdi;
-	int64	mc_rsi;
-	int64	mc_rdx;
-	int64	mc_rcx;
-	int64	mc_r8;
-	int64	mc_r9;
-	int64	mc_rax;
-	int64	mc_rbx;
-	int64	mc_rbp;
-	int64	mc_r10;
-	int64	mc_r11;
-	int64	mc_r12;
-	int64	mc_r13;
-	int64	mc_r14;
-	int64	mc_r15;
-	int64	mc_xflags;
-	int64	mc_trapno;
-	int64	mc_addr;
-	int64	mc_flags;
-	int64	mc_err;
-	int64	mc_rip;
-	int64	mc_cs;
-	int64	mc_rflags;
-	int64	mc_rsp;
-	int64	mc_ss;
-	uint32	mc_len;
-	uint32	mc_fpformat;
-	uint32	mc_ownedfp;
-	uint32	mc_reserved;
-	uint32	mc_unused[8];
-	int32	mc_fpregs[256];
-};
-struct Ucontext {
-	Sigset	uc_sigmask;
-	byte	Pad_cgo_0[48];
-	Mcontext	uc_mcontext;
-	Ucontext	*uc_link;
-	StackT	uc_stack;
-	int32	__spare__[8];
-};
-
-struct Timespec {
-	int64	tv_sec;
-	int64	tv_nsec;
-};
-struct Timeval {
-	int64	tv_sec;
-	int64	tv_usec;
-};
-struct Itimerval {
-	Timeval	it_interval;
-	Timeval	it_value;
-};
-
-struct KeventT {
-	uint64	ident;
-	int16	filter;
-	uint16	flags;
-	uint32	fflags;
-	int64	data;
-	byte	*udata;
-};
-
-
-#pragma pack off
diff --git a/src/runtime/defs_freebsd_386.go b/src/runtime/defs_freebsd_386.go
new file mode 100644
index 0000000..6938c18
--- /dev/null
+++ b/src/runtime/defs_freebsd_386.go
@@ -0,0 +1,213 @@
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_freebsd.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 = 0x5
+
+	_SA_SIGINFO = 0x40
+	_SA_RESTART = 0x2
+	_SA_ONSTACK = 0x1
+
+	_UMTX_OP_WAIT_UINT         = 0xb
+	_UMTX_OP_WAIT_UINT_PRIVATE = 0xf
+	_UMTX_OP_WAKE              = 0x3
+	_UMTX_OP_WAKE_PRIVATE      = 0x10
+
+	_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_RECEIPT   = 0x40
+	_EV_ERROR     = 0x4000
+	_EVFILT_READ  = -0x1
+	_EVFILT_WRITE = -0x2
+)
+
+type rtprio struct {
+	_type uint16
+	prio  uint16
+}
+
+type thrparam struct {
+	start_func uintptr
+	arg        unsafe.Pointer
+	stack_base uintptr
+	stack_size uintptr
+	tls_base   unsafe.Pointer
+	tls_size   uintptr
+	child_tid  unsafe.Pointer // *int32
+	parent_tid *int32
+	flags      int32
+	rtp        *rtprio
+	spare      [3]uintptr
+}
+
+type sigaltstackt struct {
+	ss_sp    *int8
+	ss_size  uint32
+	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
+	_reason   [32]byte
+}
+
+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_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_flags         uint32
+	mc_fpstate       [128]uint32
+	mc_fsbase        uint32
+	mc_gsbase        uint32
+	mc_xfpustate     uint32
+	mc_xfpustate_len uint32
+	mc_spare2        [4]uint32
+}
+
+type ucontext struct {
+	uc_sigmask  sigset
+	uc_mcontext mcontext
+	uc_link     *ucontext
+	uc_stack    stackt
+	uc_flags    int32
+	__spare__   [4]int32
+	pad_cgo_0   [12]byte
+}
+
+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_freebsd_386.h b/src/runtime/defs_freebsd_386.h
deleted file mode 100644
index 156dccb..0000000
--- a/src/runtime/defs_freebsd_386.h
+++ /dev/null
@@ -1,213 +0,0 @@
-// Created by cgo -cdefs - DO NOT EDIT
-// cgo -cdefs defs_freebsd.go
-
-
-enum {
-	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	= 0x5,
-
-	SA_SIGINFO	= 0x40,
-	SA_RESTART	= 0x2,
-	SA_ONSTACK	= 0x1,
-
-	UMTX_OP_WAIT_UINT		= 0xb,
-	UMTX_OP_WAIT_UINT_PRIVATE	= 0xf,
-	UMTX_OP_WAKE			= 0x3,
-	UMTX_OP_WAKE_PRIVATE		= 0x10,
-
-	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_RECEIPT	= 0x40,
-	EV_ERROR	= 0x4000,
-	EVFILT_READ	= -0x1,
-	EVFILT_WRITE	= -0x2,
-};
-
-typedef struct Rtprio Rtprio;
-typedef struct ThrParam ThrParam;
-typedef struct SigaltstackT SigaltstackT;
-typedef struct Sigset Sigset;
-typedef struct StackT StackT;
-typedef struct Siginfo Siginfo;
-typedef struct Mcontext Mcontext;
-typedef struct Ucontext Ucontext;
-typedef struct Timespec Timespec;
-typedef struct Timeval Timeval;
-typedef struct Itimerval Itimerval;
-typedef struct KeventT KeventT;
-
-#pragma pack on
-
-struct Rtprio {
-	uint16	type;
-	uint16	prio;
-};
-struct ThrParam {
-	void	*start_func;
-	byte	*arg;
-	int8	*stack_base;
-	uint32	stack_size;
-	int8	*tls_base;
-	uint32	tls_size;
-	int32	*child_tid;
-	int32	*parent_tid;
-	int32	flags;
-	Rtprio	*rtp;
-	void	*spare[3];
-};
-struct SigaltstackT {
-	int8	*ss_sp;
-	uint32	ss_size;
-	int32	ss_flags;
-};
-struct Sigset {
-	uint32	__bits[4];
-};
-struct StackT {
-	int8	*ss_sp;
-	uint32	ss_size;
-	int32	ss_flags;
-};
-
-struct Siginfo {
-	int32	si_signo;
-	int32	si_errno;
-	int32	si_code;
-	int32	si_pid;
-	uint32	si_uid;
-	int32	si_status;
-	byte	*si_addr;
-	byte	si_value[4];
-	byte	_reason[32];
-};
-
-struct Mcontext {
-	int32	mc_onstack;
-	int32	mc_gs;
-	int32	mc_fs;
-	int32	mc_es;
-	int32	mc_ds;
-	int32	mc_edi;
-	int32	mc_esi;
-	int32	mc_ebp;
-	int32	mc_isp;
-	int32	mc_ebx;
-	int32	mc_edx;
-	int32	mc_ecx;
-	int32	mc_eax;
-	int32	mc_trapno;
-	int32	mc_err;
-	int32	mc_eip;
-	int32	mc_cs;
-	int32	mc_eflags;
-	int32	mc_esp;
-	int32	mc_ss;
-	int32	mc_len;
-	int32	mc_fpformat;
-	int32	mc_ownedfp;
-	int32	mc_flags;
-	int32	mc_fpstate[128];
-	int32	mc_fsbase;
-	int32	mc_gsbase;
-	int32	mc_xfpustate;
-	int32	mc_xfpustate_len;
-	int32	mc_spare2[4];
-};
-struct Ucontext {
-	Sigset	uc_sigmask;
-	Mcontext	uc_mcontext;
-	Ucontext	*uc_link;
-	StackT	uc_stack;
-	int32	uc_flags;
-	int32	__spare__[4];
-	byte	Pad_cgo_0[12];
-};
-
-struct Timespec {
-	int32	tv_sec;
-	int32	tv_nsec;
-};
-struct Timeval {
-	int32	tv_sec;
-	int32	tv_usec;
-};
-struct Itimerval {
-	Timeval	it_interval;
-	Timeval	it_value;
-};
-
-struct KeventT {
-	uint32	ident;
-	int16	filter;
-	uint16	flags;
-	uint32	fflags;
-	int32	data;
-	byte	*udata;
-};
-
-
-#pragma pack off
diff --git a/src/runtime/defs_freebsd_amd64.go b/src/runtime/defs_freebsd_amd64.go
new file mode 100644
index 0000000..de98e7a
--- /dev/null
+++ b/src/runtime/defs_freebsd_amd64.go
@@ -0,0 +1,224 @@
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_freebsd.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 = 0x5
+
+	_SA_SIGINFO = 0x40
+	_SA_RESTART = 0x2
+	_SA_ONSTACK = 0x1
+
+	_UMTX_OP_WAIT_UINT         = 0xb
+	_UMTX_OP_WAIT_UINT_PRIVATE = 0xf
+	_UMTX_OP_WAKE              = 0x3
+	_UMTX_OP_WAKE_PRIVATE      = 0x10
+
+	_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_RECEIPT   = 0x40
+	_EV_ERROR     = 0x4000
+	_EVFILT_READ  = -0x1
+	_EVFILT_WRITE = -0x2
+)
+
+type rtprio struct {
+	_type uint16
+	prio  uint16
+}
+
+type thrparam struct {
+	start_func uintptr
+	arg        unsafe.Pointer
+	stack_base uintptr
+	stack_size uintptr
+	tls_base   unsafe.Pointer
+	tls_size   uintptr
+	child_tid  unsafe.Pointer // *int64
+	parent_tid *int64
+	flags      int32
+	pad_cgo_0  [4]byte
+	rtp        *rtprio
+	spare      [3]uintptr
+}
+
+type sigaltstackt struct {
+	ss_sp     *int8
+	ss_size   uint64
+	ss_flags  int32
+	pad_cgo_0 [4]byte
+}
+
+type sigset struct {
+	__bits [4]uint32
+}
+
+type stackt struct {
+	ss_sp     uintptr
+	ss_size   uintptr
+	ss_flags  int32
+	pad_cgo_0 [4]byte
+}
+
+type siginfo struct {
+	si_signo  int32
+	si_errno  int32
+	si_code   int32
+	si_pid    int32
+	si_uid    uint32
+	si_status int32
+	si_addr   uint64
+	si_value  [8]byte
+	_reason   [40]byte
+}
+
+type mcontext struct {
+	mc_onstack       uint64
+	mc_rdi           uint64
+	mc_rsi           uint64
+	mc_rdx           uint64
+	mc_rcx           uint64
+	mc_r8            uint64
+	mc_r9            uint64
+	mc_rax           uint64
+	mc_rbx           uint64
+	mc_rbp           uint64
+	mc_r10           uint64
+	mc_r11           uint64
+	mc_r12           uint64
+	mc_r13           uint64
+	mc_r14           uint64
+	mc_r15           uint64
+	mc_trapno        uint32
+	mc_fs            uint16
+	mc_gs            uint16
+	mc_addr          uint64
+	mc_flags         uint32
+	mc_es            uint16
+	mc_ds            uint16
+	mc_err           uint64
+	mc_rip           uint64
+	mc_cs            uint64
+	mc_rflags        uint64
+	mc_rsp           uint64
+	mc_ss            uint64
+	mc_len           uint64
+	mc_fpformat      uint64
+	mc_ownedfp       uint64
+	mc_fpstate       [64]uint64
+	mc_fsbase        uint64
+	mc_gsbase        uint64
+	mc_xfpustate     uint64
+	mc_xfpustate_len uint64
+	mc_spare         [4]uint64
+}
+
+type ucontext struct {
+	uc_sigmask  sigset
+	uc_mcontext mcontext
+	uc_link     *ucontext
+	uc_stack    stackt
+	uc_flags    int32
+	__spare__   [4]int32
+	pad_cgo_0   [12]byte
+}
+
+type timespec struct {
+	tv_sec  int64
+	tv_nsec int64
+}
+
+func (ts *timespec) set_sec(x int64) {
+	ts.tv_sec = x
+}
+
+type timeval struct {
+	tv_sec  int64
+	tv_usec int64
+}
+
+func (tv *timeval) set_usec(x int32) {
+	tv.tv_usec = int64(x)
+}
+
+type itimerval struct {
+	it_interval timeval
+	it_value    timeval
+}
+
+type keventt struct {
+	ident  uint64
+	filter int16
+	flags  uint16
+	fflags uint32
+	data   int64
+	udata  *byte
+}
diff --git a/src/runtime/defs_freebsd_amd64.h b/src/runtime/defs_freebsd_amd64.h
deleted file mode 100644
index 4ba8956..0000000
--- a/src/runtime/defs_freebsd_amd64.h
+++ /dev/null
@@ -1,224 +0,0 @@
-// Created by cgo -cdefs - DO NOT EDIT
-// cgo -cdefs defs_freebsd.go
-
-
-enum {
-	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	= 0x5,
-
-	SA_SIGINFO	= 0x40,
-	SA_RESTART	= 0x2,
-	SA_ONSTACK	= 0x1,
-
-	UMTX_OP_WAIT_UINT		= 0xb,
-	UMTX_OP_WAIT_UINT_PRIVATE	= 0xf,
-	UMTX_OP_WAKE			= 0x3,
-	UMTX_OP_WAKE_PRIVATE		= 0x10,
-
-	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_RECEIPT	= 0x40,
-	EV_ERROR	= 0x4000,
-	EVFILT_READ	= -0x1,
-	EVFILT_WRITE	= -0x2,
-};
-
-typedef struct Rtprio Rtprio;
-typedef struct ThrParam ThrParam;
-typedef struct SigaltstackT SigaltstackT;
-typedef struct Sigset Sigset;
-typedef struct StackT StackT;
-typedef struct Siginfo Siginfo;
-typedef struct Mcontext Mcontext;
-typedef struct Ucontext Ucontext;
-typedef struct Timespec Timespec;
-typedef struct Timeval Timeval;
-typedef struct Itimerval Itimerval;
-typedef struct KeventT KeventT;
-
-#pragma pack on
-
-struct Rtprio {
-	uint16	type;
-	uint16	prio;
-};
-struct ThrParam {
-	void	*start_func;
-	byte	*arg;
-	int8	*stack_base;
-	uint64	stack_size;
-	int8	*tls_base;
-	uint64	tls_size;
-	int64	*child_tid;
-	int64	*parent_tid;
-	int32	flags;
-	byte	Pad_cgo_0[4];
-	Rtprio	*rtp;
-	void	*spare[3];
-};
-struct SigaltstackT {
-	int8	*ss_sp;
-	uint64	ss_size;
-	int32	ss_flags;
-	byte	Pad_cgo_0[4];
-};
-struct Sigset {
-	uint32	__bits[4];
-};
-struct StackT {
-	int8	*ss_sp;
-	uint64	ss_size;
-	int32	ss_flags;
-	byte	Pad_cgo_0[4];
-};
-
-struct Siginfo {
-	int32	si_signo;
-	int32	si_errno;
-	int32	si_code;
-	int32	si_pid;
-	uint32	si_uid;
-	int32	si_status;
-	byte	*si_addr;
-	byte	si_value[8];
-	byte	_reason[40];
-};
-
-struct Mcontext {
-	int64	mc_onstack;
-	int64	mc_rdi;
-	int64	mc_rsi;
-	int64	mc_rdx;
-	int64	mc_rcx;
-	int64	mc_r8;
-	int64	mc_r9;
-	int64	mc_rax;
-	int64	mc_rbx;
-	int64	mc_rbp;
-	int64	mc_r10;
-	int64	mc_r11;
-	int64	mc_r12;
-	int64	mc_r13;
-	int64	mc_r14;
-	int64	mc_r15;
-	uint32	mc_trapno;
-	uint16	mc_fs;
-	uint16	mc_gs;
-	int64	mc_addr;
-	uint32	mc_flags;
-	uint16	mc_es;
-	uint16	mc_ds;
-	int64	mc_err;
-	int64	mc_rip;
-	int64	mc_cs;
-	int64	mc_rflags;
-	int64	mc_rsp;
-	int64	mc_ss;
-	int64	mc_len;
-	int64	mc_fpformat;
-	int64	mc_ownedfp;
-	int64	mc_fpstate[64];
-	int64	mc_fsbase;
-	int64	mc_gsbase;
-	int64	mc_xfpustate;
-	int64	mc_xfpustate_len;
-	int64	mc_spare[4];
-};
-struct Ucontext {
-	Sigset	uc_sigmask;
-	Mcontext	uc_mcontext;
-	Ucontext	*uc_link;
-	StackT	uc_stack;
-	int32	uc_flags;
-	int32	__spare__[4];
-	byte	Pad_cgo_0[12];
-};
-
-struct Timespec {
-	int64	tv_sec;
-	int64	tv_nsec;
-};
-struct Timeval {
-	int64	tv_sec;
-	int64	tv_usec;
-};
-struct Itimerval {
-	Timeval	it_interval;
-	Timeval	it_value;
-};
-
-struct KeventT {
-	uint64	ident;
-	int16	filter;
-	uint16	flags;
-	uint32	fflags;
-	int64	data;
-	byte	*udata;
-};
-
-
-#pragma pack off
diff --git a/src/runtime/defs_freebsd_arm.go b/src/runtime/defs_freebsd_arm.go
new file mode 100644
index 0000000..744330f
--- /dev/null
+++ b/src/runtime/defs_freebsd_arm.go
@@ -0,0 +1,186 @@
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_freebsd.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 = 0x5
+
+	_SA_SIGINFO = 0x40
+	_SA_RESTART = 0x2
+	_SA_ONSTACK = 0x1
+
+	_UMTX_OP_WAIT_UINT         = 0xb
+	_UMTX_OP_WAIT_UINT_PRIVATE = 0xf
+	_UMTX_OP_WAKE              = 0x3
+	_UMTX_OP_WAKE_PRIVATE      = 0x10
+
+	_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_RECEIPT   = 0x40
+	_EV_ERROR     = 0x4000
+	_EVFILT_READ  = -0x1
+	_EVFILT_WRITE = -0x2
+)
+
+type rtprio struct {
+	_type uint16
+	prio  uint16
+}
+
+type thrparam struct {
+	start_func uintptr
+	arg        unsafe.Pointer
+	stack_base uintptr
+	stack_size uintptr
+	tls_base   unsafe.Pointer
+	tls_size   uintptr
+	child_tid  unsafe.Pointer // *int32
+	parent_tid *int32
+	flags      int32
+	rtp        *rtprio
+	spare      [3]uintptr
+}
+
+type sigaltstackt struct {
+	ss_sp    *uint8
+	ss_size  uint32
+	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
+	_reason   [32]byte
+}
+
+type mcontext struct {
+	__gregs [17]uint32
+	__fpu   [140]byte
+}
+
+type ucontext struct {
+	uc_sigmask  sigset
+	uc_mcontext mcontext
+	uc_link     *ucontext
+	uc_stack    stackt
+	uc_flags    int32
+	__spare__   [4]int32
+}
+
+type timespec struct {
+	tv_sec    int64
+	tv_nsec   int32
+	pad_cgo_0 [4]byte
+}
+
+func (ts *timespec) set_sec(x int64) {
+	ts.tv_sec = x
+}
+
+type timeval struct {
+	tv_sec    int64
+	tv_usec   int32
+	pad_cgo_0 [4]byte
+}
+
+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_freebsd_arm.h b/src/runtime/defs_freebsd_arm.h
deleted file mode 100644
index 17deba6..0000000
--- a/src/runtime/defs_freebsd_arm.h
+++ /dev/null
@@ -1,186 +0,0 @@
-// Created by cgo -cdefs - DO NOT EDIT
-// cgo -cdefs defs_freebsd.go
-
-
-enum {
-	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	= 0x5,
-
-	SA_SIGINFO	= 0x40,
-	SA_RESTART	= 0x2,
-	SA_ONSTACK	= 0x1,
-
-	UMTX_OP_WAIT_UINT		= 0xb,
-	UMTX_OP_WAIT_UINT_PRIVATE	= 0xf,
-	UMTX_OP_WAKE			= 0x3,
-	UMTX_OP_WAKE_PRIVATE		= 0x10,
-
-	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_RECEIPT	= 0x40,
-	EV_ERROR	= 0x4000,
-	EVFILT_READ	= -0x1,
-	EVFILT_WRITE	= -0x2,
-};
-
-typedef struct Rtprio Rtprio;
-typedef struct ThrParam ThrParam;
-typedef struct SigaltstackT SigaltstackT;
-typedef struct Sigset Sigset;
-typedef struct StackT StackT;
-typedef struct Siginfo Siginfo;
-typedef struct Mcontext Mcontext;
-typedef struct Ucontext Ucontext;
-typedef struct Timespec Timespec;
-typedef struct Timeval Timeval;
-typedef struct Itimerval Itimerval;
-typedef struct KeventT KeventT;
-
-#pragma pack on
-
-struct Rtprio {
-	uint16	type;
-	uint16	prio;
-};
-struct ThrParam {
-	void	*start_func;
-	byte	*arg;
-	uint8	*stack_base;
-	uint32	stack_size;
-	uint8	*tls_base;
-	uint32	tls_size;
-	int32	*child_tid;
-	int32	*parent_tid;
-	int32	flags;
-	Rtprio	*rtp;
-	void	*spare[3];
-};
-struct SigaltstackT {
-	uint8	*ss_sp;
-	uint32	ss_size;
-	int32	ss_flags;
-};
-struct Sigset {
-	uint32	__bits[4];
-};
-struct StackT {
-	uint8	*ss_sp;
-	uint32	ss_size;
-	int32	ss_flags;
-};
-
-struct Siginfo {
-	int32	si_signo;
-	int32	si_errno;
-	int32	si_code;
-	int32	si_pid;
-	uint32	si_uid;
-	int32	si_status;
-	byte	*si_addr;
-	byte	si_value[4];
-	byte	_reason[32];
-};
-
-struct Mcontext {
-	uint32	__gregs[17];
-	byte	__fpu[140];
-};
-struct Ucontext {
-	Sigset	uc_sigmask;
-	Mcontext	uc_mcontext;
-	Ucontext	*uc_link;
-	StackT	uc_stack;
-	int32	uc_flags;
-	int32	__spare__[4];
-};
-
-struct Timespec {
-	int64	tv_sec;
-	int32	tv_nsec;
-	byte	Pad_cgo_0[4];
-};
-struct Timeval {
-	int64	tv_sec;
-	int32	tv_usec;
-	byte	Pad_cgo_0[4];
-};
-struct Itimerval {
-	Timeval	it_interval;
-	Timeval	it_value;
-};
-
-struct KeventT {
-	uint32	ident;
-	int16	filter;
-	uint16	flags;
-	uint32	fflags;
-	int32	data;
-	byte	*udata;
-};
-
-
-#pragma pack off
diff --git a/src/runtime/defs_linux.go b/src/runtime/defs_linux.go
index 8657dbb..553366a 100644
--- a/src/runtime/defs_linux.go
+++ b/src/runtime/defs_linux.go
@@ -20,6 +20,7 @@ package runtime
 // headers for things like ucontext_t, so that happens in
 // a separate file, defs1.go.
 
+#define	_SYS_TYPES_H	// avoid inclusion of sys/types.h
 #include <asm/posix_types.h>
 #define size_t __kernel_size_t
 #include <asm/signal.h>
@@ -28,7 +29,7 @@ package runtime
 #include <asm-generic/errno.h>
 #include <asm-generic/poll.h>
 #include <linux/eventpoll.h>
-#undef size_t
+#include <linux/time.h>
 */
 import "C"
 
@@ -48,10 +49,9 @@ const (
 
 	MADV_DONTNEED = C.MADV_DONTNEED
 
-	SA_RESTART  = C.SA_RESTART
-	SA_ONSTACK  = C.SA_ONSTACK
-	SA_RESTORER = C.SA_RESTORER
-	SA_SIGINFO  = C.SA_SIGINFO
+	SA_RESTART = C.SA_RESTART
+	SA_ONSTACK = C.SA_ONSTACK
+	SA_SIGINFO = C.SA_SIGINFO
 
 	SIGHUP    = C.SIGHUP
 	SIGINT    = C.SIGINT
@@ -116,6 +116,7 @@ const (
 	EPOLL_CTL_MOD = C.EPOLL_CTL_MOD
 )
 
+type Sigset C.sigset_t
 type Timespec C.struct_timespec
 type Timeval C.struct_timeval
 type Sigaction C.struct_sigaction
diff --git a/src/runtime/defs_linux_386.go b/src/runtime/defs_linux_386.go
new file mode 100644
index 0000000..7cf57c8
--- /dev/null
+++ b/src/runtime/defs_linux_386.go
@@ -0,0 +1,220 @@
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs 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 = 0x4000000
+	_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
+
+	_O_RDONLY  = 0x0
+	_O_CLOEXEC = 0x80000
+
+	_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 fpreg struct {
+	significand [4]uint16
+	exponent    uint16
+}
+
+type fpxreg struct {
+	significand [4]uint16
+	exponent    uint16
+	padding     [3]uint16
+}
+
+type xmmreg struct {
+	element [4]uint32
+}
+
+type fpstate struct {
+	cw        uint32
+	sw        uint32
+	tag       uint32
+	ipoff     uint32
+	cssel     uint32
+	dataoff   uint32
+	datasel   uint32
+	_st       [8]fpreg
+	status    uint16
+	magic     uint16
+	_fxsr_env [6]uint32
+	mxcsr     uint32
+	reserved  uint32
+	_fxsr_st  [8]fpxreg
+	_xmm      [8]xmmreg
+	padding1  [44]uint32
+	anon0     [48]byte
+}
+
+type timespec struct {
+	tv_sec  int32
+	tv_nsec int32
+}
+
+func (ts *timespec) set_sec(x int64) {
+	ts.tv_sec = int32(x)
+}
+
+func (ts *timespec) set_nsec(x int32) {
+	ts.tv_nsec = x
+}
+
+type timeval struct {
+	tv_sec  int32
+	tv_usec int32
+}
+
+func (tv *timeval) set_usec(x int32) {
+	tv.tv_usec = x
+}
+
+type sigactiont struct {
+	sa_handler  uintptr
+	sa_flags    uint32
+	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 uint32
+}
+
+type sigaltstackt struct {
+	ss_sp    *byte
+	ss_flags int32
+	ss_size  uintptr
+}
+
+type sigcontext struct {
+	gs            uint16
+	__gsh         uint16
+	fs            uint16
+	__fsh         uint16
+	es            uint16
+	__esh         uint16
+	ds            uint16
+	__dsh         uint16
+	edi           uint32
+	esi           uint32
+	ebp           uint32
+	esp           uint32
+	ebx           uint32
+	edx           uint32
+	ecx           uint32
+	eax           uint32
+	trapno        uint32
+	err           uint32
+	eip           uint32
+	cs            uint16
+	__csh         uint16
+	eflags        uint32
+	esp_at_signal uint32
+	ss            uint16
+	__ssh         uint16
+	fpstate       *fpstate
+	oldmask       uint32
+	cr2           uint32
+}
+
+type ucontext struct {
+	uc_flags    uint32
+	uc_link     *ucontext
+	uc_stack    sigaltstackt
+	uc_mcontext sigcontext
+	uc_sigmask  uint32
+}
+
+type itimerval struct {
+	it_interval timeval
+	it_value    timeval
+}
+
+type epollevent struct {
+	events uint32
+	data   [8]byte // to match amd64
+}
diff --git a/src/runtime/defs_linux_386.h b/src/runtime/defs_linux_386.h
deleted file mode 100644
index 24a05d8..0000000
--- a/src/runtime/defs_linux_386.h
+++ /dev/null
@@ -1,211 +0,0 @@
-// Created by cgo -cdefs - DO NOT EDIT
-// cgo -cdefs defs2_linux.go
-
-
-enum {
-	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,
-
-	SA_RESTART	= 0x10000000,
-	SA_ONSTACK	= 0x8000000,
-	SA_RESTORER	= 0x4000000,
-	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,
-
-	O_RDONLY	= 0x0,
-	O_CLOEXEC	= 0x80000,
-
-	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,
-};
-
-typedef struct Fpreg Fpreg;
-typedef struct Fpxreg Fpxreg;
-typedef struct Xmmreg Xmmreg;
-typedef struct Fpstate Fpstate;
-typedef struct Timespec Timespec;
-typedef struct Timeval Timeval;
-typedef struct SigactionT SigactionT;
-typedef struct Siginfo Siginfo;
-typedef struct SigaltstackT SigaltstackT;
-typedef struct Sigcontext Sigcontext;
-typedef struct Ucontext Ucontext;
-typedef struct Itimerval Itimerval;
-typedef struct EpollEvent EpollEvent;
-
-#pragma pack on
-
-struct Fpreg {
-	uint16	significand[4];
-	uint16	exponent;
-};
-struct Fpxreg {
-	uint16	significand[4];
-	uint16	exponent;
-	uint16	padding[3];
-};
-struct Xmmreg {
-	uint32	element[4];
-};
-struct Fpstate {
-	uint32	cw;
-	uint32	sw;
-	uint32	tag;
-	uint32	ipoff;
-	uint32	cssel;
-	uint32	dataoff;
-	uint32	datasel;
-	Fpreg	_st[8];
-	uint16	status;
-	uint16	magic;
-	uint32	_fxsr_env[6];
-	uint32	mxcsr;
-	uint32	reserved;
-	Fpxreg	_fxsr_st[8];
-	Xmmreg	_xmm[8];
-	uint32	padding1[44];
-	byte	anon0[48];
-};
-struct Timespec {
-	int32	tv_sec;
-	int32	tv_nsec;
-};
-struct Timeval {
-	int32	tv_sec;
-	int32	tv_usec;
-};
-struct SigactionT {
-	void	*k_sa_handler;
-	uint32	sa_flags;
-	void	*sa_restorer;
-	uint64	sa_mask;
-};
-struct Siginfo {
-	int32	si_signo;
-	int32	si_errno;
-	int32	si_code;
-	byte	_sifields[116];
-};
-struct SigaltstackT {
-	byte	*ss_sp;
-	int32	ss_flags;
-	uint32	ss_size;
-};
-struct Sigcontext {
-	uint16	gs;
-	uint16	__gsh;
-	uint16	fs;
-	uint16	__fsh;
-	uint16	es;
-	uint16	__esh;
-	uint16	ds;
-	uint16	__dsh;
-	uint32	edi;
-	uint32	esi;
-	uint32	ebp;
-	uint32	esp;
-	uint32	ebx;
-	uint32	edx;
-	uint32	ecx;
-	uint32	eax;
-	uint32	trapno;
-	uint32	err;
-	uint32	eip;
-	uint16	cs;
-	uint16	__csh;
-	uint32	eflags;
-	uint32	esp_at_signal;
-	uint16	ss;
-	uint16	__ssh;
-	Fpstate	*fpstate;
-	uint32	oldmask;
-	uint32	cr2;
-};
-struct Ucontext {
-	uint32	uc_flags;
-	Ucontext	*uc_link;
-	SigaltstackT	uc_stack;
-	Sigcontext	uc_mcontext;
-	uint32	uc_sigmask;
-};
-struct Itimerval {
-	Timeval	it_interval;
-	Timeval	it_value;
-};
-struct EpollEvent {
-	uint32	events;
-	byte	data[8]; // to match amd64
-};
-
-
-#pragma pack off
diff --git a/src/runtime/defs_linux_amd64.go b/src/runtime/defs_linux_amd64.go
new file mode 100644
index 0000000..48aeb80
--- /dev/null
+++ b/src/runtime/defs_linux_amd64.go
@@ -0,0 +1,255 @@
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_linux.go defs1_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 = 0x4000000
+	_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
+	data   [8]byte // unaligned uintptr
+}
+
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_linux.go defs1_linux.go
+
+const (
+	_O_RDONLY  = 0x0
+	_O_CLOEXEC = 0x80000
+)
+
+type usigset struct {
+	__val [16]uint64
+}
+
+type fpxreg struct {
+	significand [4]uint16
+	exponent    uint16
+	padding     [3]uint16
+}
+
+type xmmreg struct {
+	element [4]uint32
+}
+
+type fpstate struct {
+	cwd       uint16
+	swd       uint16
+	ftw       uint16
+	fop       uint16
+	rip       uint64
+	rdp       uint64
+	mxcsr     uint32
+	mxcr_mask uint32
+	_st       [8]fpxreg
+	_xmm      [16]xmmreg
+	padding   [24]uint32
+}
+
+type fpxreg1 struct {
+	significand [4]uint16
+	exponent    uint16
+	padding     [3]uint16
+}
+
+type xmmreg1 struct {
+	element [4]uint32
+}
+
+type fpstate1 struct {
+	cwd       uint16
+	swd       uint16
+	ftw       uint16
+	fop       uint16
+	rip       uint64
+	rdp       uint64
+	mxcsr     uint32
+	mxcr_mask uint32
+	_st       [8]fpxreg1
+	_xmm      [16]xmmreg1
+	padding   [24]uint32
+}
+
+type fpreg1 struct {
+	significand [4]uint16
+	exponent    uint16
+}
+
+type sigaltstackt struct {
+	ss_sp     *byte
+	ss_flags  int32
+	pad_cgo_0 [4]byte
+	ss_size   uintptr
+}
+
+type mcontext struct {
+	gregs       [23]uint64
+	fpregs      *fpstate
+	__reserved1 [8]uint64
+}
+
+type ucontext struct {
+	uc_flags     uint64
+	uc_link      *ucontext
+	uc_stack     sigaltstackt
+	uc_mcontext  mcontext
+	uc_sigmask   usigset
+	__fpregs_mem fpstate
+}
+
+type sigcontext struct {
+	r8          uint64
+	r9          uint64
+	r10         uint64
+	r11         uint64
+	r12         uint64
+	r13         uint64
+	r14         uint64
+	r15         uint64
+	rdi         uint64
+	rsi         uint64
+	rbp         uint64
+	rbx         uint64
+	rdx         uint64
+	rax         uint64
+	rcx         uint64
+	rsp         uint64
+	rip         uint64
+	eflags      uint64
+	cs          uint16
+	gs          uint16
+	fs          uint16
+	__pad0      uint16
+	err         uint64
+	trapno      uint64
+	oldmask     uint64
+	cr2         uint64
+	fpstate     *fpstate1
+	__reserved1 [8]uint64
+}
diff --git a/src/runtime/defs_linux_amd64.h b/src/runtime/defs_linux_amd64.h
deleted file mode 100644
index 14616df..0000000
--- a/src/runtime/defs_linux_amd64.h
+++ /dev/null
@@ -1,254 +0,0 @@
-// Created by cgo -cdefs - DO NOT EDIT
-// cgo -cdefs defs_linux.go defs1_linux.go
-
-
-enum {
-	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,
-
-	SA_RESTART	= 0x10000000,
-	SA_ONSTACK	= 0x8000000,
-	SA_RESTORER	= 0x4000000,
-	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,
-};
-
-typedef struct Timespec Timespec;
-typedef struct Timeval Timeval;
-typedef struct SigactionT SigactionT;
-typedef struct Siginfo Siginfo;
-typedef struct Itimerval Itimerval;
-typedef struct EpollEvent EpollEvent;
-
-#pragma pack on
-
-struct Timespec {
-	int64	tv_sec;
-	int64	tv_nsec;
-};
-struct Timeval {
-	int64	tv_sec;
-	int64	tv_usec;
-};
-struct SigactionT {
-	void	*sa_handler;
-	uint64	sa_flags;
-	void	*sa_restorer;
-	uint64	sa_mask;
-};
-struct Siginfo {
-	int32	si_signo;
-	int32	si_errno;
-	int32	si_code;
-	byte	Pad_cgo_0[4];
-	byte	_sifields[112];
-};
-struct Itimerval {
-	Timeval	it_interval;
-	Timeval	it_value;
-};
-struct EpollEvent {
-	uint32	events;
-	byte	data[8]; // unaligned uintptr
-};
-
-
-#pragma pack off
-// Created by cgo -cdefs - DO NOT EDIT
-// cgo -cdefs defs_linux.go defs1_linux.go
-
-
-enum {
-	O_RDONLY	= 0x0,
-	O_CLOEXEC	= 0x80000,
-};
-
-typedef struct Usigset Usigset;
-typedef struct Fpxreg Fpxreg;
-typedef struct Xmmreg Xmmreg;
-typedef struct Fpstate Fpstate;
-typedef struct Fpxreg1 Fpxreg1;
-typedef struct Xmmreg1 Xmmreg1;
-typedef struct Fpstate1 Fpstate1;
-typedef struct Fpreg1 Fpreg1;
-typedef struct SigaltstackT SigaltstackT;
-typedef struct Mcontext Mcontext;
-typedef struct Ucontext Ucontext;
-typedef struct Sigcontext Sigcontext;
-
-#pragma pack on
-
-struct Usigset {
-	uint64	__val[16];
-};
-struct Fpxreg {
-	uint16	significand[4];
-	uint16	exponent;
-	uint16	padding[3];
-};
-struct Xmmreg {
-	uint32	element[4];
-};
-struct Fpstate {
-	uint16	cwd;
-	uint16	swd;
-	uint16	ftw;
-	uint16	fop;
-	uint64	rip;
-	uint64	rdp;
-	uint32	mxcsr;
-	uint32	mxcr_mask;
-	Fpxreg	_st[8];
-	Xmmreg	_xmm[16];
-	uint32	padding[24];
-};
-struct Fpxreg1 {
-	uint16	significand[4];
-	uint16	exponent;
-	uint16	padding[3];
-};
-struct Xmmreg1 {
-	uint32	element[4];
-};
-struct Fpstate1 {
-	uint16	cwd;
-	uint16	swd;
-	uint16	ftw;
-	uint16	fop;
-	uint64	rip;
-	uint64	rdp;
-	uint32	mxcsr;
-	uint32	mxcr_mask;
-	Fpxreg1	_st[8];
-	Xmmreg1	_xmm[16];
-	uint32	padding[24];
-};
-struct Fpreg1 {
-	uint16	significand[4];
-	uint16	exponent;
-};
-struct SigaltstackT {
-	byte	*ss_sp;
-	int32	ss_flags;
-	byte	Pad_cgo_0[4];
-	uint64	ss_size;
-};
-struct Mcontext {
-	int64	gregs[23];
-	Fpstate	*fpregs;
-	uint64	__reserved1[8];
-};
-struct Ucontext {
-	uint64	uc_flags;
-	Ucontext	*uc_link;
-	SigaltstackT	uc_stack;
-	Mcontext	uc_mcontext;
-	Usigset	uc_sigmask;
-	Fpstate	__fpregs_mem;
-};
-struct Sigcontext {
-	uint64	r8;
-	uint64	r9;
-	uint64	r10;
-	uint64	r11;
-	uint64	r12;
-	uint64	r13;
-	uint64	r14;
-	uint64	r15;
-	uint64	rdi;
-	uint64	rsi;
-	uint64	rbp;
-	uint64	rbx;
-	uint64	rdx;
-	uint64	rax;
-	uint64	rcx;
-	uint64	rsp;
-	uint64	rip;
-	uint64	eflags;
-	uint16	cs;
-	uint16	gs;
-	uint16	fs;
-	uint16	__pad0;
-	uint64	err;
-	uint64	trapno;
-	uint64	oldmask;
-	uint64	cr2;
-	Fpstate1	*fpstate;
-	uint64	__reserved1[8];
-};
-
-
-#pragma pack off
diff --git a/src/runtime/defs_linux_arm.go b/src/runtime/defs_linux_arm.go
new file mode 100644
index 0000000..b68b964
--- /dev/null
+++ b/src/runtime/defs_linux_arm.go
@@ -0,0 +1,182 @@
+package runtime
+
+// Constants
+const (
+	_EINTR  = 0x4
+	_ENOMEM = 0xc
+	_EAGAIN = 0xb
+
+	_PROT_NONE  = 0
+	_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    = 0 // unused on ARM
+	_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    = 0
+	_ITIMER_PROF    = 0x2
+	_ITIMER_VIRTUAL = 0x1
+	_O_RDONLY       = 0
+	_O_CLOEXEC      = 0x80000
+
+	_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
+
+	_AF_UNIX    = 0x1
+	_F_SETFL    = 0x4
+	_SOCK_DGRAM = 0x2
+)
+
+type timespec struct {
+	tv_sec  int32
+	tv_nsec int32
+}
+
+func (ts *timespec) set_sec(x int64) {
+	ts.tv_sec = int32(x)
+}
+
+func (ts *timespec) set_nsec(x int32) {
+	ts.tv_nsec = x
+}
+
+type sigaltstackt struct {
+	ss_sp    *byte
+	ss_flags int32
+	ss_size  uintptr
+}
+
+type sigcontext struct {
+	trap_no       uint32
+	error_code    uint32
+	oldmask       uint32
+	r0            uint32
+	r1            uint32
+	r2            uint32
+	r3            uint32
+	r4            uint32
+	r5            uint32
+	r6            uint32
+	r7            uint32
+	r8            uint32
+	r9            uint32
+	r10           uint32
+	fp            uint32
+	ip            uint32
+	sp            uint32
+	lr            uint32
+	pc            uint32
+	cpsr          uint32
+	fault_address uint32
+}
+
+type ucontext struct {
+	uc_flags    uint32
+	uc_link     *ucontext
+	uc_stack    sigaltstackt
+	uc_mcontext sigcontext
+	uc_sigmask  uint32
+	__unused    [31]int32
+	uc_regspace [128]uint32
+}
+
+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 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 uint32
+}
+
+type sigactiont struct {
+	sa_handler  uintptr
+	sa_flags    uint32
+	sa_restorer uintptr
+	sa_mask     uint64
+}
+
+type epollevent struct {
+	events uint32
+	_pad   uint32
+	data   [8]byte // to match amd64
+}
+
+type sockaddr_un struct {
+	family uint16
+	path   [108]byte
+}
diff --git a/src/runtime/defs_linux_arm.h b/src/runtime/defs_linux_arm.h
deleted file mode 100644
index 50b3c91..0000000
--- a/src/runtime/defs_linux_arm.h
+++ /dev/null
@@ -1,168 +0,0 @@
-// TODO: Generate using cgo like defs_linux_{386,amd64}.h
-
-// Constants
-enum {
-	EINTR  = 0x4,
-	ENOMEM = 0xc,
-	EAGAIN = 0xb,
-
-	PROT_NONE = 0,
-	PROT_READ = 0x1,
-	PROT_WRITE = 0x2,
-	PROT_EXEC = 0x4,
-	MAP_ANON = 0x20,
-	MAP_PRIVATE = 0x2,
-	MAP_FIXED = 0x10,
-	MADV_DONTNEED = 0x4,
-	SA_RESTART = 0x10000000,
-	SA_ONSTACK = 0x8000000,
-	SA_RESTORER = 0, // unused on ARM
-	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 = 0,
-	ITIMER_PROF = 0x2,
-	ITIMER_VIRTUAL = 0x1,
-	O_RDONLY = 0,
-	O_CLOEXEC = 02000000,
-
-	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,
-};
-
-// Types
-#pragma pack on
-
-typedef struct Timespec Timespec;
-struct Timespec {
-	int32 tv_sec;
-	int32 tv_nsec;
-};
-
-typedef struct SigaltstackT SigaltstackT;
-struct SigaltstackT {
-	void *ss_sp;
-	int32 ss_flags;
-	uint32 ss_size;
-};
-
-typedef struct Sigcontext Sigcontext;
-struct Sigcontext {
-	uint32 trap_no;
-	uint32 error_code;
-	uint32 oldmask;
-	uint32 arm_r0;
-	uint32 arm_r1;
-	uint32 arm_r2;
-	uint32 arm_r3;
-	uint32 arm_r4;
-	uint32 arm_r5;
-	uint32 arm_r6;
-	uint32 arm_r7;
-	uint32 arm_r8;
-	uint32 arm_r9;
-	uint32 arm_r10;
-	uint32 arm_fp;
-	uint32 arm_ip;
-	uint32 arm_sp;
-	uint32 arm_lr;
-	uint32 arm_pc;
-	uint32 arm_cpsr;
-	uint32 fault_address;
-};
-
-typedef struct Ucontext Ucontext;
-struct Ucontext {
-	uint32 uc_flags;
-	Ucontext *uc_link;
-	SigaltstackT uc_stack;
-	Sigcontext uc_mcontext;
-	uint32 uc_sigmask;
-	int32 __unused[31];
-	uint32 uc_regspace[128];
-};
-
-typedef struct Timeval Timeval;
-struct Timeval {
-	int32 tv_sec;
-	int32 tv_usec;
-};
-
-typedef struct Itimerval Itimerval;
-struct Itimerval {
-	Timeval it_interval;
-	Timeval it_value;
-};
-
-typedef struct Siginfo Siginfo;
-struct Siginfo {
-	int32 si_signo;
-	int32 si_errno;
-	int32 si_code;
-	uint8 _sifields[4];
-};
-
-typedef struct SigactionT SigactionT;
-struct SigactionT {
-	void *sa_handler;
-	uint32 sa_flags;
-	void *sa_restorer;
-	uint64 sa_mask;
-};
-
-typedef struct EpollEvent EpollEvent;
-struct EpollEvent {
-	uint32	events;
-	uint32	_pad;
-	byte	data[8]; // to match amd64
-};
-#pragma pack off
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_linux_ppc64.go b/src/runtime/defs_linux_ppc64.go
new file mode 100644
index 0000000..317a764
--- /dev/null
+++ b/src/runtime/defs_linux_ppc64.go
@@ -0,0 +1,200 @@
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_linux.go defs3_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_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
+)
+
+//struct Sigset {
+//	uint64	sig[1];
+//};
+//typedef uint64 Sigset;
+
+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_cgo_0 [4]byte
+	data      [8]byte // unaligned uintptr
+}
+
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_linux.go defs3_linux.go
+
+const (
+	_O_RDONLY    = 0x0
+	_O_CLOEXEC   = 0x80000
+	_SA_RESTORER = 0
+)
+
+type ptregs struct {
+	gpr       [32]uint64
+	nip       uint64
+	msr       uint64
+	orig_gpr3 uint64
+	ctr       uint64
+	link      uint64
+	xer       uint64
+	ccr       uint64
+	softe     uint64
+	trap      uint64
+	dar       uint64
+	dsisr     uint64
+	result    uint64
+}
+
+type vreg struct {
+	u [4]uint32
+}
+
+type sigaltstackt struct {
+	ss_sp     *byte
+	ss_flags  int32
+	pad_cgo_0 [4]byte
+	ss_size   uintptr
+}
+
+type sigcontext struct {
+	_unused     [4]uint64
+	signal      int32
+	_pad0       int32
+	handler     uint64
+	oldmask     uint64
+	regs        *ptregs
+	gp_regs     [48]uint64
+	fp_regs     [33]float64
+	v_regs      *vreg
+	vmx_reserve [101]int64
+}
+
+type ucontext struct {
+	uc_flags    uint64
+	uc_link     *ucontext
+	uc_stack    sigaltstackt
+	uc_sigmask  uint64
+	__unused    [15]uint64
+	uc_mcontext sigcontext
+}
diff --git a/src/runtime/defs_linux_ppc64le.go b/src/runtime/defs_linux_ppc64le.go
new file mode 100644
index 0000000..317a764
--- /dev/null
+++ b/src/runtime/defs_linux_ppc64le.go
@@ -0,0 +1,200 @@
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_linux.go defs3_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_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
+)
+
+//struct Sigset {
+//	uint64	sig[1];
+//};
+//typedef uint64 Sigset;
+
+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_cgo_0 [4]byte
+	data      [8]byte // unaligned uintptr
+}
+
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_linux.go defs3_linux.go
+
+const (
+	_O_RDONLY    = 0x0
+	_O_CLOEXEC   = 0x80000
+	_SA_RESTORER = 0
+)
+
+type ptregs struct {
+	gpr       [32]uint64
+	nip       uint64
+	msr       uint64
+	orig_gpr3 uint64
+	ctr       uint64
+	link      uint64
+	xer       uint64
+	ccr       uint64
+	softe     uint64
+	trap      uint64
+	dar       uint64
+	dsisr     uint64
+	result    uint64
+}
+
+type vreg struct {
+	u [4]uint32
+}
+
+type sigaltstackt struct {
+	ss_sp     *byte
+	ss_flags  int32
+	pad_cgo_0 [4]byte
+	ss_size   uintptr
+}
+
+type sigcontext struct {
+	_unused     [4]uint64
+	signal      int32
+	_pad0       int32
+	handler     uint64
+	oldmask     uint64
+	regs        *ptregs
+	gp_regs     [48]uint64
+	fp_regs     [33]float64
+	v_regs      *vreg
+	vmx_reserve [101]int64
+}
+
+type ucontext struct {
+	uc_flags    uint64
+	uc_link     *ucontext
+	uc_stack    sigaltstackt
+	uc_sigmask  uint64
+	__unused    [15]uint64
+	uc_mcontext sigcontext
+}
diff --git a/src/runtime/defs_nacl_386.go b/src/runtime/defs_nacl_386.go
new file mode 100644
index 0000000..b041336
--- /dev/null
+++ b/src/runtime/defs_nacl_386.go
@@ -0,0 +1,43 @@
+package runtime
+
+const (
+	// These values are referred to in the source code
+	// but really don't matter. Even so, use the standard numbers.
+	_SIGQUIT = 3
+	_SIGSEGV = 11
+	_SIGPROF = 27
+)
+
+type timespec struct {
+	tv_sec  int64
+	tv_nsec int32
+}
+
+type excregs386 struct {
+	eax    uint32
+	ecx    uint32
+	edx    uint32
+	ebx    uint32
+	esp    uint32
+	ebp    uint32
+	esi    uint32
+	edi    uint32
+	eip    uint32
+	eflags uint32
+}
+
+type exccontext struct {
+	size                    uint32
+	portable_context_offset uint32
+	portable_context_size   uint32
+	arch                    uint32
+	regs_size               uint32
+	reserved                [11]uint32
+	regs                    excregs386
+}
+
+type excportablecontext struct {
+	pc uint32
+	sp uint32
+	fp uint32
+}
diff --git a/src/runtime/defs_nacl_386.h b/src/runtime/defs_nacl_386.h
deleted file mode 100644
index e8fbb38..0000000
--- a/src/runtime/defs_nacl_386.h
+++ /dev/null
@@ -1,63 +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.
-
-// Created by hand, not machine generated.
-
-enum
-{
-	// These values are referred to in the source code
-	// but really don't matter. Even so, use the standard numbers.
-	SIGSEGV = 11,
-	SIGPROF = 27,
-};
-
-typedef struct Siginfo Siginfo;
-
-// native_client/src/trusted/service_runtime/include/machine/_types.h
-typedef struct Timespec Timespec;
-
-struct Timespec
-{
-	int64 tv_sec;
-	int32 tv_nsec;
-};
-
-// native_client/src/trusted/service_runtime/nacl_exception.h
-// native_client/src/include/nacl/nacl_exception.h
-
-typedef struct ExcContext ExcContext;
-typedef struct ExcPortable ExcPortable;
-typedef struct ExcRegs386 ExcRegs386;
-
-struct ExcRegs386
-{
-	uint32	eax;
-	uint32	ecx;
-	uint32	edx;
-	uint32	ebx;
-	uint32	esp;
-	uint32	ebp;
-	uint32	esi;
-	uint32	edi;
-	uint32	eip;
-	uint32	eflags;
-};
-
-struct ExcContext
-{
-	uint32	size;
-	uint32	portable_context_offset;
-	uint32	portable_context_size;
-	uint32	arch;
-	uint32	regs_size;
-	uint32	reserved[11];
-	ExcRegs386	regs;
-};
-
-struct ExcPortableContext
-{
-	uint32	pc;
-	uint32	sp;
-	uint32	fp;
-};
diff --git a/src/runtime/defs_nacl_amd64p32.go b/src/runtime/defs_nacl_amd64p32.go
new file mode 100644
index 0000000..7e0b867
--- /dev/null
+++ b/src/runtime/defs_nacl_amd64p32.go
@@ -0,0 +1,64 @@
+package runtime
+
+const (
+	// These values are referred to in the source code
+	// but really don't matter. Even so, use the standard numbers.
+	_SIGQUIT = 3
+	_SIGSEGV = 11
+	_SIGPROF = 27
+)
+
+type timespec struct {
+	tv_sec  int64
+	tv_nsec int32
+}
+
+type excregs386 struct {
+	eax    uint32
+	ecx    uint32
+	edx    uint32
+	ebx    uint32
+	esp    uint32
+	ebp    uint32
+	esi    uint32
+	edi    uint32
+	eip    uint32
+	eflags uint32
+}
+
+type excregsamd64 struct {
+	rax    uint64
+	rcx    uint64
+	rdx    uint64
+	rbx    uint64
+	rsp    uint64
+	rbp    uint64
+	rsi    uint64
+	rdi    uint64
+	r8     uint64
+	r9     uint64
+	r10    uint64
+	r11    uint64
+	r12    uint64
+	r13    uint64
+	r14    uint64
+	r15    uint64
+	rip    uint64
+	rflags uint32
+}
+
+type exccontext struct {
+	size                    uint32
+	portable_context_offset uint32
+	portable_context_size   uint32
+	arch                    uint32
+	regs_size               uint32
+	reserved                [11]uint32
+	regs                    excregsamd64
+}
+
+type excportablecontext struct {
+	pc uint32
+	sp uint32
+	fp uint32
+}
diff --git a/src/runtime/defs_nacl_amd64p32.h b/src/runtime/defs_nacl_amd64p32.h
deleted file mode 100644
index 45663d4..0000000
--- a/src/runtime/defs_nacl_amd64p32.h
+++ /dev/null
@@ -1,90 +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.
-
-// Created by hand, not machine generated.
-
-enum
-{
-	// These values are referred to in the source code
-	// but really don't matter. Even so, use the standard numbers.
-	SIGSEGV = 11,
-	SIGPROF = 27,
-};
-
-typedef struct Siginfo Siginfo;
-
-
-// native_client/src/trusted/service_runtime/include/machine/_types.h
-typedef struct Timespec Timespec;
-
-struct Timespec
-{
-	int64 tv_sec;
-	int32 tv_nsec;
-};
-
-// native_client/src/trusted/service_runtime/nacl_exception.h
-// native_client/src/include/nacl/nacl_exception.h
-
-typedef struct ExcContext ExcContext;
-typedef struct ExcPortable ExcPortable;
-typedef struct ExcRegs386 ExcRegs386;
-typedef struct ExcRegsAmd64 ExcRegsAmd64;
-
-struct ExcRegs386
-{
-	uint32	eax;
-	uint32	ecx;
-	uint32	edx;
-	uint32	ebx;
-	uint32	esp;
-	uint32	ebp;
-	uint32	esi;
-	uint32	edi;
-	uint32	eip;
-	uint32	eflags;
-};
-
-struct ExcRegsAmd64
-{
-	uint64	rax;
-	uint64	rcx;
-	uint64	rdx;
-	uint64	rbx;
-	uint64	rsp;
-	uint64	rbp;
-	uint64	rsi;
-	uint64	rdi;
-	uint64	r8;
-	uint64	r9;
-	uint64	r10;
-	uint64	r11;
-	uint64	r12;
-	uint64	r13;
-	uint64	r14;
-	uint64	r15;
-	uint64	rip;
-	uint32	rflags;
-};
-
-struct ExcContext
-{
-	uint32	size;
-	uint32	portable_context_offset;
-	uint32	portable_context_size;
-	uint32	arch;
-	uint32	regs_size;
-	uint32	reserved[11];
-	union {
-		ExcRegs386	regs;
-		ExcRegsAmd64	regs64;
-	} regs;
-};
-
-struct ExcPortableContext
-{
-	uint32	pc;
-	uint32	sp;
-	uint32	fp;
-};
diff --git a/src/runtime/defs_nacl_arm.go b/src/runtime/defs_nacl_arm.go
new file mode 100644
index 0000000..6032156
--- /dev/null
+++ b/src/runtime/defs_nacl_arm.go
@@ -0,0 +1,50 @@
+package runtime
+
+const (
+	// These values are referred to in the source code
+	// but really don't matter. Even so, use the standard numbers.
+	_SIGQUIT = 3
+	_SIGSEGV = 11
+	_SIGPROF = 27
+)
+
+type timespec struct {
+	tv_sec  int64
+	tv_nsec int32
+}
+
+type excregsarm struct {
+	r0   uint32
+	r1   uint32
+	r2   uint32
+	r3   uint32
+	r4   uint32
+	r5   uint32
+	r6   uint32
+	r7   uint32
+	r8   uint32
+	r9   uint32 // the value reported here is undefined.
+	r10  uint32
+	r11  uint32
+	r12  uint32
+	sp   uint32 /* r13 */
+	lr   uint32 /* r14 */
+	pc   uint32 /* r15 */
+	cpsr uint32
+}
+
+type exccontext struct {
+	size                    uint32
+	portable_context_offset uint32
+	portable_context_size   uint32
+	arch                    uint32
+	regs_size               uint32
+	reserved                [11]uint32
+	regs                    excregsarm
+}
+
+type excportablecontext struct {
+	pc uint32
+	sp uint32
+	fp uint32
+}
diff --git a/src/runtime/defs_nacl_arm.h b/src/runtime/defs_nacl_arm.h
deleted file mode 100644
index 9ce07cc..0000000
--- a/src/runtime/defs_nacl_arm.h
+++ /dev/null
@@ -1,70 +0,0 @@
-// 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.
-
-// Created by hand, not machine generated.
-
-enum
-{
-	// These values are referred to in the source code
-	// but really don't matter. Even so, use the standard numbers.
-	SIGSEGV = 11,
-	SIGPROF = 27,
-};
-
-typedef struct Siginfo Siginfo;
-
-// native_client/src/trusted/service_runtime/include/machine/_types.h
-typedef struct Timespec Timespec;
-
-struct Timespec
-{
-	int64 tv_sec;
-	int32 tv_nsec;
-};
-
-// native_client/src/trusted/service_runtime/nacl_exception.h
-// native_client/src/include/nacl/nacl_exception.h
-
-typedef struct ExcContext ExcContext;
-typedef struct ExcPortable ExcPortable;
-typedef struct ExcRegsARM ExcRegsARM;
-
-struct ExcRegsARM
-{
-	uint32	r0;
-	uint32	r1;
-	uint32	r2;
-	uint32	r3;
-	uint32	r4;
-	uint32	r5;
-	uint32	r6;
-	uint32	r7;
-	uint32	r8;
-	uint32	r9;	// the value reported here is undefined.
-	uint32	r10;
-	uint32	r11;
-	uint32	r12;
-	uint32	sp;	/* r13 */
-	uint32	lr;	/* r14 */
-	uint32	pc;	/* r15 */
-	uint32	cpsr;
-};
-
-struct ExcContext
-{
-	uint32	size;
-	uint32	portable_context_offset;
-	uint32	portable_context_size;
-	uint32	arch;
-	uint32	regs_size;
-	uint32	reserved[11];
-	ExcRegsARM	regs;
-};
-
-struct ExcPortableContext
-{
-	uint32	pc;
-	uint32	sp;
-	uint32	fp;
-};
diff --git a/src/runtime/defs_netbsd_386.h b/src/runtime/defs_netbsd_386.h
deleted file mode 100644
index fd87804..0000000
--- a/src/runtime/defs_netbsd_386.h
+++ /dev/null
@@ -1,182 +0,0 @@
-// Created by cgo -cdefs - DO NOT EDIT
-// cgo -cdefs defs_netbsd.go defs_netbsd_386.go
-
-
-enum {
-	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_RECEIPT	= 0,
-	EV_ERROR	= 0x4000,
-	EVFILT_READ	= 0x0,
-	EVFILT_WRITE	= 0x1,
-};
-
-typedef struct SigaltstackT SigaltstackT;
-typedef struct Sigset Sigset;
-typedef struct Siginfo Siginfo;
-typedef struct StackT StackT;
-typedef struct Timespec Timespec;
-typedef struct Timeval Timeval;
-typedef struct Itimerval Itimerval;
-typedef struct McontextT McontextT;
-typedef struct UcontextT UcontextT;
-typedef struct KeventT KeventT;
-
-#pragma pack on
-
-struct SigaltstackT {
-	byte	*ss_sp;
-	uint32	ss_size;
-	int32	ss_flags;
-};
-struct Sigset {
-	uint32	__bits[4];
-};
-struct Siginfo {
-	int32	_signo;
-	int32	_code;
-	int32	_errno;
-	byte	_reason[20];
-};
-
-struct StackT {
-	byte	*ss_sp;
-	uint32	ss_size;
-	int32	ss_flags;
-};
-
-struct Timespec {
-	int64	tv_sec;
-	int32	tv_nsec;
-};
-struct Timeval {
-	int64	tv_sec;
-	int32	tv_usec;
-};
-struct Itimerval {
-	Timeval	it_interval;
-	Timeval	it_value;
-};
-
-struct McontextT {
-	int32	__gregs[19];
-	byte	__fpregs[644];
-	int32	_mc_tlsbase;
-};
-struct UcontextT {
-	uint32	uc_flags;
-	UcontextT	*uc_link;
-	Sigset	uc_sigmask;
-	StackT	uc_stack;
-	McontextT	uc_mcontext;
-	int32	__uc_pad[4];
-};
-
-struct KeventT {
-	uint32	ident;
-	uint32	filter;
-	uint32	flags;
-	uint32	fflags;
-	int64	data;
-	byte	*udata;
-};
-
-
-#pragma pack off
-// Created by cgo -cdefs - DO NOT EDIT
-// cgo -cdefs defs_netbsd.go defs_netbsd_386.go
-
-
-enum {
-	REG_GS		= 0x0,
-	REG_FS		= 0x1,
-	REG_ES		= 0x2,
-	REG_DS		= 0x3,
-	REG_EDI		= 0x4,
-	REG_ESI		= 0x5,
-	REG_EBP		= 0x6,
-	REG_ESP		= 0x7,
-	REG_EBX		= 0x8,
-	REG_EDX		= 0x9,
-	REG_ECX		= 0xa,
-	REG_EAX		= 0xb,
-	REG_TRAPNO	= 0xc,
-	REG_ERR		= 0xd,
-	REG_EIP		= 0xe,
-	REG_CS		= 0xf,
-	REG_EFL		= 0x10,
-	REG_UESP	= 0x11,
-	REG_SS		= 0x12,
-};
-
diff --git a/src/runtime/defs_netbsd_amd64.h b/src/runtime/defs_netbsd_amd64.h
deleted file mode 100644
index dac94b1..0000000
--- a/src/runtime/defs_netbsd_amd64.h
+++ /dev/null
@@ -1,194 +0,0 @@
-// Created by cgo -cdefs - DO NOT EDIT
-// cgo -cdefs defs_netbsd.go defs_netbsd_amd64.go
-
-
-enum {
-	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_RECEIPT	= 0,
-	EV_ERROR	= 0x4000,
-	EVFILT_READ	= 0x0,
-	EVFILT_WRITE	= 0x1,
-};
-
-typedef struct SigaltstackT SigaltstackT;
-typedef struct Sigset Sigset;
-typedef struct Siginfo Siginfo;
-typedef struct StackT StackT;
-typedef struct Timespec Timespec;
-typedef struct Timeval Timeval;
-typedef struct Itimerval Itimerval;
-typedef struct McontextT McontextT;
-typedef struct UcontextT UcontextT;
-typedef struct KeventT KeventT;
-
-#pragma pack on
-
-struct SigaltstackT {
-	byte	*ss_sp;
-	uint64	ss_size;
-	int32	ss_flags;
-	byte	Pad_cgo_0[4];
-};
-struct Sigset {
-	uint32	__bits[4];
-};
-struct Siginfo {
-	int32	_signo;
-	int32	_code;
-	int32	_errno;
-	int32	_pad;
-	byte	_reason[24];
-};
-
-struct StackT {
-	byte	*ss_sp;
-	uint64	ss_size;
-	int32	ss_flags;
-	byte	Pad_cgo_0[4];
-};
-
-struct Timespec {
-	int64	tv_sec;
-	int64	tv_nsec;
-};
-struct Timeval {
-	int64	tv_sec;
-	int32	tv_usec;
-	byte	Pad_cgo_0[4];
-};
-struct Itimerval {
-	Timeval	it_interval;
-	Timeval	it_value;
-};
-
-struct McontextT {
-	uint64	__gregs[26];
-	uint64	_mc_tlsbase;
-	int8	__fpregs[512];
-};
-struct UcontextT {
-	uint32	uc_flags;
-	byte	Pad_cgo_0[4];
-	UcontextT	*uc_link;
-	Sigset	uc_sigmask;
-	StackT	uc_stack;
-	McontextT	uc_mcontext;
-};
-
-struct KeventT {
-	uint64	ident;
-	uint32	filter;
-	uint32	flags;
-	uint32	fflags;
-	byte	Pad_cgo_0[4];
-	int64	data;
-	byte	*udata;
-};
-
-
-#pragma pack off
-// Created by cgo -cdefs - DO NOT EDIT
-// cgo -cdefs defs_netbsd.go defs_netbsd_amd64.go
-
-
-enum {
-	REG_RDI		= 0x0,
-	REG_RSI		= 0x1,
-	REG_RDX		= 0x2,
-	REG_RCX		= 0x3,
-	REG_R8		= 0x4,
-	REG_R9		= 0x5,
-	REG_R10		= 0x6,
-	REG_R11		= 0x7,
-	REG_R12		= 0x8,
-	REG_R13		= 0x9,
-	REG_R14		= 0xa,
-	REG_R15		= 0xb,
-	REG_RBP		= 0xc,
-	REG_RBX		= 0xd,
-	REG_RAX		= 0xe,
-	REG_GS		= 0xf,
-	REG_FS		= 0x10,
-	REG_ES		= 0x11,
-	REG_DS		= 0x12,
-	REG_TRAPNO	= 0x13,
-	REG_ERR		= 0x14,
-	REG_RIP		= 0x15,
-	REG_CS		= 0x16,
-	REG_RFLAGS	= 0x17,
-	REG_RSP		= 0x18,
-	REG_SS		= 0x19,
-};
-
diff --git a/src/runtime/defs_netbsd_arm.h b/src/runtime/defs_netbsd_arm.h
deleted file mode 100644
index 70f34af..0000000
--- a/src/runtime/defs_netbsd_arm.h
+++ /dev/null
@@ -1,184 +0,0 @@
-// Created by cgo -cdefs - DO NOT EDIT
-// cgo -cdefs defs_netbsd.go defs_netbsd_arm.go
-
-
-enum {
-	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_RECEIPT	= 0,
-	EV_ERROR	= 0x4000,
-	EVFILT_READ	= 0x0,
-	EVFILT_WRITE	= 0x1,
-};
-
-typedef struct SigaltstackT SigaltstackT;
-typedef struct Sigset Sigset;
-typedef struct Siginfo Siginfo;
-typedef struct StackT StackT;
-typedef struct Timespec Timespec;
-typedef struct Timeval Timeval;
-typedef struct Itimerval Itimerval;
-typedef struct McontextT McontextT;
-typedef struct UcontextT UcontextT;
-typedef struct KeventT KeventT;
-
-#pragma pack on
-
-struct SigaltstackT {
-	byte	*ss_sp;
-	uint32	ss_size;
-	int32	ss_flags;
-};
-struct Sigset {
-	uint32	__bits[4];
-};
-struct Siginfo {
-	int32	_signo;
-	int32	_code;
-	int32	_errno;
-	byte	_reason[20];
-};
-
-struct StackT {
-	byte	*ss_sp;
-	uint32	ss_size;
-	int32	ss_flags;
-};
-
-struct Timespec {
-	int64	tv_sec;
-	int32	tv_nsec;
-};
-struct Timeval {
-	int64	tv_sec;
-	int32	tv_usec;
-};
-struct Itimerval {
-	Timeval	it_interval;
-	Timeval	it_value;
-};
-
-struct McontextT {
-	uint32	__gregs[17];
-#ifdef __ARM_EABI__
-	byte	__fpu[4+8*32+4];
-#else
-	byte	__fpu[4+4*33+4];
-#endif
-	uint32	_mc_tlsbase;
-};
-struct UcontextT {
-	uint32	uc_flags;
-	UcontextT	*uc_link;
-	Sigset	uc_sigmask;
-	StackT	uc_stack;
-	McontextT	uc_mcontext;
-	int32	__uc_pad[2];
-};
-
-struct KeventT {
-	uint32	ident;
-	uint32	filter;
-	uint32	flags;
-	uint32	fflags;
-	int64	data;
-	byte	*udata;
-};
-
-
-#pragma pack off
-// Created by cgo -cdefs - DO NOT EDIT
-// cgo -cdefs defs_netbsd.go defs_netbsd_arm.go
-
-
-enum {
-	REG_R0		= 0x0,
-	REG_R1		= 0x1,
-	REG_R2		= 0x2,
-	REG_R3		= 0x3,
-	REG_R4		= 0x4,
-	REG_R5		= 0x5,
-	REG_R6		= 0x6,
-	REG_R7		= 0x7,
-	REG_R8		= 0x8,
-	REG_R9		= 0x9,
-	REG_R10		= 0xa,
-	REG_R11		= 0xb,
-	REG_R12		= 0xc,
-	REG_R13		= 0xd,
-	REG_R14		= 0xe,
-	REG_R15		= 0xf,
-	REG_CPSR	= 0x10,
-};
-
diff --git a/src/runtime/defs_openbsd_386.go b/src/runtime/defs_openbsd_386.go
new file mode 100644
index 0000000..4b60158
--- /dev/null
+++ b/src/runtime/defs_openbsd_386.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_gs       uint32
+	sc_fs       uint32
+	sc_es       uint32
+	sc_ds       uint32
+	sc_edi      uint32
+	sc_esi      uint32
+	sc_ebp      uint32
+	sc_ebx      uint32
+	sc_edx      uint32
+	sc_ecx      uint32
+	sc_eax      uint32
+	sc_eip      uint32
+	sc_cs       uint32
+	sc_eflags   uint32
+	sc_esp      uint32
+	sc_ss       uint32
+	__sc_unused uint32
+	sc_mask     uint32
+	sc_trapno   uint32
+	sc_err      uint32
+	sc_fpstate  unsafe.Pointer
+}
+
+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/defs_openbsd_386.h b/src/runtime/defs_openbsd_386.h
deleted file mode 100644
index 6b77e00..0000000
--- a/src/runtime/defs_openbsd_386.h
+++ /dev/null
@@ -1,168 +0,0 @@
-// Created by cgo -cdefs - DO NOT EDIT
-// cgo -cdefs defs_openbsd.go
-
-
-enum {
-	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,
-};
-
-typedef struct TforkT TforkT;
-typedef struct SigaltstackT SigaltstackT;
-typedef struct Sigcontext Sigcontext;
-typedef struct Siginfo Siginfo;
-typedef struct StackT StackT;
-typedef struct Timespec Timespec;
-typedef struct Timeval Timeval;
-typedef struct Itimerval Itimerval;
-typedef struct KeventT KeventT;
-
-#pragma pack on
-
-struct TforkT {
-	byte	*tf_tcb;
-	int32	*tf_tid;
-	byte	*tf_stack;
-};
-
-struct SigaltstackT {
-	byte	*ss_sp;
-	uint32	ss_size;
-	int32	ss_flags;
-};
-struct Sigcontext {
-	int32	sc_gs;
-	int32	sc_fs;
-	int32	sc_es;
-	int32	sc_ds;
-	int32	sc_edi;
-	int32	sc_esi;
-	int32	sc_ebp;
-	int32	sc_ebx;
-	int32	sc_edx;
-	int32	sc_ecx;
-	int32	sc_eax;
-	int32	sc_eip;
-	int32	sc_cs;
-	int32	sc_eflags;
-	int32	sc_esp;
-	int32	sc_ss;
-	int32	__sc_unused;
-	int32	sc_mask;
-	int32	sc_trapno;
-	int32	sc_err;
-	void	*sc_fpstate;
-};
-struct Siginfo {
-	int32	si_signo;
-	int32	si_code;
-	int32	si_errno;
-	byte	_data[116];
-};
-typedef	uint32	Sigset;
-typedef	byte	Sigval[4];
-
-struct StackT {
-	byte	*ss_sp;
-	uint32	ss_size;
-	int32	ss_flags;
-};
-
-struct Timespec {
-	int64	tv_sec;
-	int32	tv_nsec;
-};
-struct Timeval {
-	int64	tv_sec;
-	int32	tv_usec;
-};
-struct Itimerval {
-	Timeval	it_interval;
-	Timeval	it_value;
-};
-
-struct KeventT {
-	uint32	ident;
-	int16	filter;
-	uint16	flags;
-	uint32	fflags;
-	int64	data;
-	byte	*udata;
-};
-
-
-#pragma pack off
diff --git a/src/runtime/defs_openbsd_amd64.go b/src/runtime/defs_openbsd_amd64.go
new file mode 100644
index 0000000..3c27c91
--- /dev/null
+++ b/src/runtime/defs_openbsd_amd64.go
@@ -0,0 +1,181 @@
+// 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
+	pad_cgo_0 [4]byte
+}
+
+type sigcontext struct {
+	sc_rdi      uint64
+	sc_rsi      uint64
+	sc_rdx      uint64
+	sc_rcx      uint64
+	sc_r8       uint64
+	sc_r9       uint64
+	sc_r10      uint64
+	sc_r11      uint64
+	sc_r12      uint64
+	sc_r13      uint64
+	sc_r14      uint64
+	sc_r15      uint64
+	sc_rbp      uint64
+	sc_rbx      uint64
+	sc_rax      uint64
+	sc_gs       uint64
+	sc_fs       uint64
+	sc_es       uint64
+	sc_ds       uint64
+	sc_trapno   uint64
+	sc_err      uint64
+	sc_rip      uint64
+	sc_cs       uint64
+	sc_rflags   uint64
+	sc_rsp      uint64
+	sc_ss       uint64
+	sc_fpstate  unsafe.Pointer
+	__sc_unused int32
+	sc_mask     int32
+}
+
+type siginfo struct {
+	si_signo  int32
+	si_code   int32
+	si_errno  int32
+	pad_cgo_0 [4]byte
+	_data     [120]byte
+}
+
+type stackt struct {
+	ss_sp     uintptr
+	ss_size   uintptr
+	ss_flags  int32
+	pad_cgo_0 [4]byte
+}
+
+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 itimerval struct {
+	it_interval timeval
+	it_value    timeval
+}
+
+type keventt struct {
+	ident  uint64
+	filter int16
+	flags  uint16
+	fflags uint32
+	data   int64
+	udata  *byte
+}
diff --git a/src/runtime/defs_openbsd_amd64.h b/src/runtime/defs_openbsd_amd64.h
deleted file mode 100644
index 761e8e4..0000000
--- a/src/runtime/defs_openbsd_amd64.h
+++ /dev/null
@@ -1,179 +0,0 @@
-// Created by cgo -cdefs - DO NOT EDIT
-// cgo -cdefs defs_openbsd.go
-
-
-enum {
-	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,
-};
-
-typedef struct TforkT TforkT;
-typedef struct SigaltstackT SigaltstackT;
-typedef struct Sigcontext Sigcontext;
-typedef struct Siginfo Siginfo;
-typedef struct StackT StackT;
-typedef struct Timespec Timespec;
-typedef struct Timeval Timeval;
-typedef struct Itimerval Itimerval;
-typedef struct KeventT KeventT;
-
-#pragma pack on
-
-struct TforkT {
-	byte	*tf_tcb;
-	int32	*tf_tid;
-	byte	*tf_stack;
-};
-
-struct SigaltstackT {
-	byte	*ss_sp;
-	uint64	ss_size;
-	int32	ss_flags;
-	byte	Pad_cgo_0[4];
-};
-struct Sigcontext {
-	int64	sc_rdi;
-	int64	sc_rsi;
-	int64	sc_rdx;
-	int64	sc_rcx;
-	int64	sc_r8;
-	int64	sc_r9;
-	int64	sc_r10;
-	int64	sc_r11;
-	int64	sc_r12;
-	int64	sc_r13;
-	int64	sc_r14;
-	int64	sc_r15;
-	int64	sc_rbp;
-	int64	sc_rbx;
-	int64	sc_rax;
-	int64	sc_gs;
-	int64	sc_fs;
-	int64	sc_es;
-	int64	sc_ds;
-	int64	sc_trapno;
-	int64	sc_err;
-	int64	sc_rip;
-	int64	sc_cs;
-	int64	sc_rflags;
-	int64	sc_rsp;
-	int64	sc_ss;
-	void	*sc_fpstate;
-	int32	__sc_unused;
-	int32	sc_mask;
-};
-struct Siginfo {
-	int32	si_signo;
-	int32	si_code;
-	int32	si_errno;
-	byte	Pad_cgo_0[4];
-	byte	_data[120];
-};
-typedef	uint32	Sigset;
-typedef	byte	Sigval[8];
-
-struct StackT {
-	byte	*ss_sp;
-	uint64	ss_size;
-	int32	ss_flags;
-	byte	Pad_cgo_0[4];
-};
-
-struct Timespec {
-	int64	tv_sec;
-	int64	tv_nsec;
-};
-struct Timeval {
-	int64	tv_sec;
-	int64	tv_usec;
-};
-struct Itimerval {
-	Timeval	it_interval;
-	Timeval	it_value;
-};
-
-struct KeventT {
-	uint64	ident;
-	int16	filter;
-	uint16	flags;
-	uint32	fflags;
-	int64	data;
-	byte	*udata;
-};
-
-
-#pragma pack off
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/defs_plan9_386.go b/src/runtime/defs_plan9_386.go
new file mode 100644
index 0000000..3574cb6
--- /dev/null
+++ b/src/runtime/defs_plan9_386.go
@@ -0,0 +1,51 @@
+package runtime
+
+const _PAGESIZE = 0x1000
+
+type ureg struct {
+	di    uint32 /* general registers */
+	si    uint32 /* ... */
+	bp    uint32 /* ... */
+	nsp   uint32
+	bx    uint32 /* ... */
+	dx    uint32 /* ... */
+	cx    uint32 /* ... */
+	ax    uint32 /* ... */
+	gs    uint32 /* data segments */
+	fs    uint32 /* ... */
+	es    uint32 /* ... */
+	ds    uint32 /* ... */
+	trap  uint32 /* trap _type */
+	ecode uint32 /* error code (or zero) */
+	pc    uint32 /* pc */
+	cs    uint32 /* old context */
+	flags uint32 /* old flags */
+	sp    uint32
+	ss    uint32 /* old stack segment */
+}
+
+type sigctxt struct {
+	u *ureg
+}
+
+func (c *sigctxt) pc() uintptr { return uintptr(c.u.pc) }
+func (c *sigctxt) sp() uintptr { return uintptr(c.u.sp) }
+
+func (c *sigctxt) setpc(x uintptr) { c.u.pc = uint32(x) }
+func (c *sigctxt) setsp(x uintptr) { c.u.sp = uint32(x) }
+
+func dumpregs(u *ureg) {
+	print("ax    ", hex(u.ax), "\n")
+	print("bx    ", hex(u.bx), "\n")
+	print("cx    ", hex(u.cx), "\n")
+	print("dx    ", hex(u.dx), "\n")
+	print("di    ", hex(u.di), "\n")
+	print("si    ", hex(u.si), "\n")
+	print("bp    ", hex(u.bp), "\n")
+	print("sp    ", hex(u.sp), "\n")
+	print("pc    ", hex(u.pc), "\n")
+	print("flags ", hex(u.flags), "\n")
+	print("cs    ", hex(u.cs), "\n")
+	print("fs    ", hex(u.fs), "\n")
+	print("gs    ", hex(u.gs), "\n")
+}
diff --git a/src/runtime/defs_plan9_386.h b/src/runtime/defs_plan9_386.h
deleted file mode 100644
index a762b85..0000000
--- a/src/runtime/defs_plan9_386.h
+++ /dev/null
@@ -1,26 +0,0 @@
-#define PAGESIZE 0x1000
-
-typedef struct Ureg Ureg;
-
-struct Ureg
-{
-	uint32	di;		/* general registers */
-	uint32	si;		/* ... */
-	uint32	bp;		/* ... */
-	uint32	nsp;
-	uint32	bx;		/* ... */
-	uint32	dx;		/* ... */
-	uint32	cx;		/* ... */
-	uint32	ax;		/* ... */
-	uint32	gs;		/* data segments */
-	uint32	fs;		/* ... */
-	uint32	es;		/* ... */
-	uint32	ds;		/* ... */
-	uint32	trap;		/* trap type */
-	uint32	ecode;		/* error code (or zero) */
-	uint32	pc;		/* pc */
-	uint32	cs;		/* old context */
-	uint32	flags;		/* old flags */
-	uint32	sp;
-	uint32	ss;		/* old stack segment */
-};
diff --git a/src/runtime/defs_plan9_amd64.go b/src/runtime/defs_plan9_amd64.go
new file mode 100644
index 0000000..54b4d39
--- /dev/null
+++ b/src/runtime/defs_plan9_amd64.go
@@ -0,0 +1,68 @@
+package runtime
+
+const _PAGESIZE = 0x1000
+
+type ureg struct {
+	ax  uint64
+	bx  uint64
+	cx  uint64
+	dx  uint64
+	si  uint64
+	di  uint64
+	bp  uint64
+	r8  uint64
+	r9  uint64
+	r10 uint64
+	r11 uint64
+	r12 uint64
+	r13 uint64
+	r14 uint64
+	r15 uint64
+
+	ds uint16
+	es uint16
+	fs uint16
+	gs uint16
+
+	_type uint64
+	error uint64 /* error code (or zero) */
+	ip    uint64 /* pc */
+	cs    uint64 /* old context */
+	flags uint64 /* old flags */
+	sp    uint64 /* sp */
+	ss    uint64 /* old stack segment */
+}
+
+type sigctxt struct {
+	u *ureg
+}
+
+func (c *sigctxt) pc() uintptr { return uintptr(c.u.ip) }
+func (c *sigctxt) sp() uintptr { return uintptr(c.u.sp) }
+
+func (c *sigctxt) setpc(x uintptr) { c.u.ip = uint64(x) }
+func (c *sigctxt) setsp(x uintptr) { c.u.sp = uint64(x) }
+
+func dumpregs(u *ureg) {
+	print("ax    ", hex(u.ax), "\n")
+	print("bx    ", hex(u.bx), "\n")
+	print("cx    ", hex(u.cx), "\n")
+	print("dx    ", hex(u.dx), "\n")
+	print("di    ", hex(u.di), "\n")
+	print("si    ", hex(u.si), "\n")
+	print("bp    ", hex(u.bp), "\n")
+	print("sp    ", hex(u.sp), "\n")
+	print("r8    ", hex(u.r8), "\n")
+	print("r9    ", hex(u.r9), "\n")
+	print("r10   ", hex(u.r10), "\n")
+	print("r11   ", hex(u.r11), "\n")
+	print("r12   ", hex(u.r12), "\n")
+	print("r13   ", hex(u.r13), "\n")
+	print("r14   ", hex(u.r14), "\n")
+	print("r15   ", hex(u.r15), "\n")
+	print("ip    ", hex(u.ip), "\n")
+	print("flags ", hex(u.flags), "\n")
+	print("cs    ", hex(u.cs), "\n")
+	print("fs    ", hex(u.fs), "\n")
+	print("gs    ", hex(u.gs), "\n")
+}
diff --git a/src/runtime/defs_plan9_amd64.h b/src/runtime/defs_plan9_amd64.h
deleted file mode 100644
index 20bca47..0000000
--- a/src/runtime/defs_plan9_amd64.h
+++ /dev/null
@@ -1,34 +0,0 @@
-#define PAGESIZE 0x1000
-
-typedef struct Ureg Ureg;
-
-struct Ureg {
-	uint64	ax;
-	uint64	bx;
-	uint64	cx;
-	uint64	dx;
-	uint64	si;
-	uint64	di;
-	uint64	bp;
-	uint64	r8;
-	uint64	r9;
-	uint64	r10;
-	uint64	r11;
-	uint64	r12;
-	uint64	r13;
-	uint64	r14;
-	uint64	r15;
-
-	uint16	ds;
-	uint16	es;
-	uint16	fs;
-	uint16	gs;
-
-	uint64	type;
-	uint64	error;				/* error code (or zero) */
-	uint64	ip;				/* pc */
-	uint64	cs;				/* old context */
-	uint64	flags;				/* old flags */
-	uint64	sp;				/* sp */
-	uint64	ss;				/* old stack segment */
-};
diff --git a/src/runtime/defs_solaris_amd64.h b/src/runtime/defs_solaris_amd64.h
deleted file mode 100644
index cb1cfea..0000000
--- a/src/runtime/defs_solaris_amd64.h
+++ /dev/null
@@ -1,254 +0,0 @@
-// Created by cgo -cdefs - DO NOT EDIT
-// cgo -cdefs defs_solaris.go defs_solaris_amd64.go
-
-
-enum {
-	EINTR		= 0x4,
-	EBADF		= 0x9,
-	EFAULT		= 0xe,
-	EAGAIN		= 0xb,
-	ETIMEDOUT	= 0x91,
-	EWOULDBLOCK	= 0xb,
-	EINPROGRESS	= 0x96,
-
-	PROT_NONE	= 0x0,
-	PROT_READ	= 0x1,
-	PROT_WRITE	= 0x2,
-	PROT_EXEC	= 0x4,
-
-	MAP_ANON	= 0x100,
-	MAP_PRIVATE	= 0x2,
-	MAP_FIXED	= 0x10,
-
-	MADV_FREE	= 0x5,
-
-	SA_SIGINFO	= 0x8,
-	SA_RESTART	= 0x4,
-	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		= 0x15,
-	SIGSTOP		= 0x17,
-	SIGTSTP		= 0x18,
-	SIGCONT		= 0x19,
-	SIGCHLD		= 0x12,
-	SIGTTIN		= 0x1a,
-	SIGTTOU		= 0x1b,
-	SIGIO		= 0x16,
-	SIGXCPU		= 0x1e,
-	SIGXFSZ		= 0x1f,
-	SIGVTALRM	= 0x1c,
-	SIGPROF		= 0x1d,
-	SIGWINCH	= 0x14,
-	SIGUSR1		= 0x10,
-	SIGUSR2		= 0x11,
-
-	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,
-
-	_SC_NPROCESSORS_ONLN	= 0xf,
-
-	PTHREAD_CREATE_DETACHED	= 0x40,
-
-	FORK_NOSIGCHLD	= 0x1,
-	FORK_WAITPID	= 0x2,
-
-	MAXHOSTNAMELEN	= 0x100,
-
-	O_NONBLOCK	= 0x80,
-	FD_CLOEXEC	= 0x1,
-	F_GETFL		= 0x3,
-	F_SETFL		= 0x4,
-	F_SETFD		= 0x2,
-
-	POLLIN	= 0x1,
-	POLLOUT	= 0x4,
-	POLLHUP	= 0x10,
-	POLLERR	= 0x8,
-
-	PORT_SOURCE_FD	= 0x4,
-};
-
-typedef struct SemT SemT;
-typedef struct SigaltstackT SigaltstackT;
-typedef struct Sigset Sigset;
-typedef struct StackT StackT;
-typedef struct Siginfo Siginfo;
-typedef struct SigactionT SigactionT;
-typedef struct Fpregset Fpregset;
-typedef struct Mcontext Mcontext;
-typedef struct Ucontext Ucontext;
-typedef struct Timespec Timespec;
-typedef struct Timeval Timeval;
-typedef struct Itimerval Itimerval;
-typedef struct PortEvent PortEvent;
-typedef struct PthreadAttr PthreadAttr;
-typedef struct Stat Stat;
-
-#pragma pack on
-
-struct SemT {
-	uint32	sem_count;
-	uint16	sem_type;
-	uint16	sem_magic;
-	uint64	sem_pad1[3];
-	uint64	sem_pad2[2];
-};
-
-struct SigaltstackT {
-	byte	*ss_sp;
-	uint64	ss_size;
-	int32	ss_flags;
-	byte	Pad_cgo_0[4];
-};
-struct Sigset {
-	uint32	__sigbits[4];
-};
-struct StackT {
-	byte	*ss_sp;
-	uint64	ss_size;
-	int32	ss_flags;
-	byte	Pad_cgo_0[4];
-};
-
-struct Siginfo {
-	int32	si_signo;
-	int32	si_code;
-	int32	si_errno;
-	int32	si_pad;
-	byte	__data[240];
-};
-struct SigactionT {
-	int32	sa_flags;
-	byte	Pad_cgo_0[4];
-	byte	_funcptr[8];
-	Sigset	sa_mask;
-};
-
-struct Fpregset {
-	byte	fp_reg_set[528];
-};
-struct Mcontext {
-	int64	gregs[28];
-	Fpregset	fpregs;
-};
-struct Ucontext {
-	uint64	uc_flags;
-	Ucontext	*uc_link;
-	Sigset	uc_sigmask;
-	StackT	uc_stack;
-	byte	Pad_cgo_0[8];
-	Mcontext	uc_mcontext;
-	int64	uc_filler[5];
-	byte	Pad_cgo_1[8];
-};
-
-struct Timespec {
-	int64	tv_sec;
-	int64	tv_nsec;
-};
-struct Timeval {
-	int64	tv_sec;
-	int64	tv_usec;
-};
-struct Itimerval {
-	Timeval	it_interval;
-	Timeval	it_value;
-};
-
-struct PortEvent {
-	int32	portev_events;
-	uint16	portev_source;
-	uint16	portev_pad;
-	uint64	portev_object;
-	byte	*portev_user;
-};
-typedef	uint32	Pthread;
-struct PthreadAttr {
-	byte	*__pthread_attrp;
-};
-
-struct Stat {
-	uint64	st_dev;
-	uint64	st_ino;
-	uint32	st_mode;
-	uint32	st_nlink;
-	uint32	st_uid;
-	uint32	st_gid;
-	uint64	st_rdev;
-	int64	st_size;
-	Timespec	st_atim;
-	Timespec	st_mtim;
-	Timespec	st_ctim;
-	int32	st_blksize;
-	byte	Pad_cgo_0[4];
-	int64	st_blocks;
-	int8	st_fstype[16];
-};
-
-
-#pragma pack off
-// Created by cgo -cdefs - DO NOT EDIT
-// cgo -cdefs defs_solaris.go defs_solaris_amd64.go
-
-
-enum {
-	REG_RDI		= 0x8,
-	REG_RSI		= 0x9,
-	REG_RDX		= 0xc,
-	REG_RCX		= 0xd,
-	REG_R8		= 0x7,
-	REG_R9		= 0x6,
-	REG_R10		= 0x5,
-	REG_R11		= 0x4,
-	REG_R12		= 0x3,
-	REG_R13		= 0x2,
-	REG_R14		= 0x1,
-	REG_R15		= 0x0,
-	REG_RBP		= 0xa,
-	REG_RBX		= 0xb,
-	REG_RAX		= 0xe,
-	REG_GS		= 0x17,
-	REG_FS		= 0x16,
-	REG_ES		= 0x18,
-	REG_DS		= 0x19,
-	REG_TRAPNO	= 0xf,
-	REG_ERR		= 0x10,
-	REG_RIP		= 0x11,
-	REG_CS		= 0x12,
-	REG_RFLAGS	= 0x13,
-	REG_RSP		= 0x14,
-	REG_SS		= 0x15,
-};
-
diff --git a/src/runtime/defs_windows.go b/src/runtime/defs_windows.go
index 5dfb83a..7ce6797 100644
--- a/src/runtime/defs_windows.go
+++ b/src/runtime/defs_windows.go
@@ -41,7 +41,6 @@ const (
 	DUPLICATE_SAME_ACCESS   = C.DUPLICATE_SAME_ACCESS
 	THREAD_PRIORITY_HIGHEST = C.THREAD_PRIORITY_HIGHEST
 
-	SIGPROF          = 0 // dummy value for badsignal
 	SIGINT           = C.SIGINT
 	CTRL_C_EVENT     = C.CTRL_C_EVENT
 	CTRL_BREAK_EVENT = C.CTRL_BREAK_EVENT
diff --git a/src/runtime/defs_windows_386.go b/src/runtime/defs_windows_386.go
new file mode 100644
index 0000000..bac6ce7
--- /dev/null
+++ b/src/runtime/defs_windows_386.go
@@ -0,0 +1,131 @@
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_windows.go
+
+package runtime
+
+const (
+	_PROT_NONE  = 0
+	_PROT_READ  = 1
+	_PROT_WRITE = 2
+	_PROT_EXEC  = 4
+
+	_MAP_ANON    = 1
+	_MAP_PRIVATE = 2
+
+	_DUPLICATE_SAME_ACCESS   = 0x2
+	_THREAD_PRIORITY_HIGHEST = 0x2
+
+	_SIGINT           = 0x2
+	_CTRL_C_EVENT     = 0x0
+	_CTRL_BREAK_EVENT = 0x1
+
+	_CONTEXT_CONTROL = 0x10001
+	_CONTEXT_FULL    = 0x10007
+
+	_EXCEPTION_ACCESS_VIOLATION     = 0xc0000005
+	_EXCEPTION_BREAKPOINT           = 0x80000003
+	_EXCEPTION_FLT_DENORMAL_OPERAND = 0xc000008d
+	_EXCEPTION_FLT_DIVIDE_BY_ZERO   = 0xc000008e
+	_EXCEPTION_FLT_INEXACT_RESULT   = 0xc000008f
+	_EXCEPTION_FLT_OVERFLOW         = 0xc0000091
+	_EXCEPTION_FLT_UNDERFLOW        = 0xc0000093
+	_EXCEPTION_INT_DIVIDE_BY_ZERO   = 0xc0000094
+	_EXCEPTION_INT_OVERFLOW         = 0xc0000095
+
+	_INFINITE     = 0xffffffff
+	_WAIT_TIMEOUT = 0x102
+
+	_EXCEPTION_CONTINUE_EXECUTION = -0x1
+	_EXCEPTION_CONTINUE_SEARCH    = 0x0
+)
+
+type systeminfo struct {
+	anon0                       [4]byte
+	dwpagesize                  uint32
+	lpminimumapplicationaddress *byte
+	lpmaximumapplicationaddress *byte
+	dwactiveprocessormask       uint32
+	dwnumberofprocessors        uint32
+	dwprocessortype             uint32
+	dwallocationgranularity     uint32
+	wprocessorlevel             uint16
+	wprocessorrevision          uint16
+}
+
+type exceptionrecord struct {
+	exceptioncode        uint32
+	exceptionflags       uint32
+	exceptionrecord      *exceptionrecord
+	exceptionaddress     *byte
+	numberparameters     uint32
+	exceptioninformation [15]uint32
+}
+
+type floatingsavearea struct {
+	controlword   uint32
+	statusword    uint32
+	tagword       uint32
+	erroroffset   uint32
+	errorselector uint32
+	dataoffset    uint32
+	dataselector  uint32
+	registerarea  [80]uint8
+	cr0npxstate   uint32
+}
+
+type context struct {
+	contextflags      uint32
+	dr0               uint32
+	dr1               uint32
+	dr2               uint32
+	dr3               uint32
+	dr6               uint32
+	dr7               uint32
+	floatsave         floatingsavearea
+	seggs             uint32
+	segfs             uint32
+	seges             uint32
+	segds             uint32
+	edi               uint32
+	esi               uint32
+	ebx               uint32
+	edx               uint32
+	ecx               uint32
+	eax               uint32
+	ebp               uint32
+	eip               uint32
+	segcs             uint32
+	eflags            uint32
+	esp               uint32
+	segss             uint32
+	extendedregisters [512]uint8
+}
+
+func (c *context) ip() uintptr { return uintptr(c.eip) }
+func (c *context) sp() uintptr { return uintptr(c.esp) }
+
+func (c *context) setip(x uintptr) { c.eip = uint32(x) }
+func (c *context) setsp(x uintptr) { c.esp = uint32(x) }
+
+func dumpregs(r *context) {
+	print("eax     ", hex(r.eax), "\n")
+	print("ebx     ", hex(r.ebx), "\n")
+	print("ecx     ", hex(r.ecx), "\n")
+	print("edx     ", hex(r.edx), "\n")
+	print("edi     ", hex(r.edi), "\n")
+	print("esi     ", hex(r.esi), "\n")
+	print("ebp     ", hex(r.ebp), "\n")
+	print("esp     ", hex(r.esp), "\n")
+	print("eip     ", hex(r.eip), "\n")
+	print("eflags  ", hex(r.eflags), "\n")
+	print("cs      ", hex(r.segcs), "\n")
+	print("fs      ", hex(r.segfs), "\n")
+	print("gs      ", hex(r.seggs), "\n")
+}
+
+type overlapped struct {
+	internal     uint32
+	internalhigh uint32
+	anon0        [8]byte
+	hevent       *byte
+}
diff --git a/src/runtime/defs_windows_386.h b/src/runtime/defs_windows_386.h
deleted file mode 100644
index 2317c04..0000000
--- a/src/runtime/defs_windows_386.h
+++ /dev/null
@@ -1,116 +0,0 @@
-// Created by cgo -cdefs - DO NOT EDIT
-// cgo -cdefs defs_windows.go
-
-
-enum {
-	PROT_NONE	= 0,
-	PROT_READ	= 1,
-	PROT_WRITE	= 2,
-	PROT_EXEC	= 4,
-
-	MAP_ANON	= 1,
-	MAP_PRIVATE	= 2,
-
-	DUPLICATE_SAME_ACCESS	= 0x2,
-	THREAD_PRIORITY_HIGHEST	= 0x2,
-
-	SIGINT			= 0x2,
-	CTRL_C_EVENT		= 0x0,
-	CTRL_BREAK_EVENT	= 0x1,
-
-	CONTEXT_CONTROL	= 0x10001,
-	CONTEXT_FULL	= 0x10007,
-
-	EXCEPTION_ACCESS_VIOLATION	= 0xc0000005,
-	EXCEPTION_BREAKPOINT		= 0x80000003,
-	EXCEPTION_FLT_DENORMAL_OPERAND	= 0xc000008d,
-	EXCEPTION_FLT_DIVIDE_BY_ZERO	= 0xc000008e,
-	EXCEPTION_FLT_INEXACT_RESULT	= 0xc000008f,
-	EXCEPTION_FLT_OVERFLOW		= 0xc0000091,
-	EXCEPTION_FLT_UNDERFLOW		= 0xc0000093,
-	EXCEPTION_INT_DIVIDE_BY_ZERO	= 0xc0000094,
-	EXCEPTION_INT_OVERFLOW		= 0xc0000095,
-
-	INFINITE	= 0xffffffff,
-	WAIT_TIMEOUT	= 0x102,
-
-	EXCEPTION_CONTINUE_EXECUTION	= -0x1,
-	EXCEPTION_CONTINUE_SEARCH	= 0x0,
-};
-
-typedef struct SystemInfo SystemInfo;
-typedef struct ExceptionRecord ExceptionRecord;
-typedef struct FloatingSaveArea FloatingSaveArea;
-typedef struct M128a M128a;
-typedef struct Context Context;
-typedef struct Overlapped Overlapped;
-
-#pragma pack on
-
-struct SystemInfo {
-	byte	anon0[4];
-	uint32	dwPageSize;
-	byte	*lpMinimumApplicationAddress;
-	byte	*lpMaximumApplicationAddress;
-	uint32	dwActiveProcessorMask;
-	uint32	dwNumberOfProcessors;
-	uint32	dwProcessorType;
-	uint32	dwAllocationGranularity;
-	uint16	wProcessorLevel;
-	uint16	wProcessorRevision;
-};
-struct ExceptionRecord {
-	uint32	ExceptionCode;
-	uint32	ExceptionFlags;
-	ExceptionRecord	*ExceptionRecord;
-	byte	*ExceptionAddress;
-	uint32	NumberParameters;
-	uint32	ExceptionInformation[15];
-};
-struct FloatingSaveArea {
-	uint32	ControlWord;
-	uint32	StatusWord;
-	uint32	TagWord;
-	uint32	ErrorOffset;
-	uint32	ErrorSelector;
-	uint32	DataOffset;
-	uint32	DataSelector;
-	uint8	RegisterArea[80];
-	uint32	Cr0NpxState;
-};
-struct Context {
-	uint32	ContextFlags;
-	uint32	Dr0;
-	uint32	Dr1;
-	uint32	Dr2;
-	uint32	Dr3;
-	uint32	Dr6;
-	uint32	Dr7;
-	FloatingSaveArea	FloatSave;
-	uint32	SegGs;
-	uint32	SegFs;
-	uint32	SegEs;
-	uint32	SegDs;
-	uint32	Edi;
-	uint32	Esi;
-	uint32	Ebx;
-	uint32	Edx;
-	uint32	Ecx;
-	uint32	Eax;
-	uint32	Ebp;
-	uint32	Eip;
-	uint32	SegCs;
-	uint32	EFlags;
-	uint32	Esp;
-	uint32	SegSs;
-	uint8	ExtendedRegisters[512];
-};
-struct Overlapped {
-	uint32	Internal;
-	uint32	InternalHigh;
-	byte	anon0[8];
-	byte	*hEvent;
-};
-
-
-#pragma pack off
diff --git a/src/runtime/defs_windows_amd64.go b/src/runtime/defs_windows_amd64.go
new file mode 100644
index 0000000..6e04568
--- /dev/null
+++ b/src/runtime/defs_windows_amd64.go
@@ -0,0 +1,153 @@
+// created by cgo -cdefs and then converted to Go
+// cgo -cdefs defs_windows.go
+
+package runtime
+
+const (
+	_PROT_NONE  = 0
+	_PROT_READ  = 1
+	_PROT_WRITE = 2
+	_PROT_EXEC  = 4
+
+	_MAP_ANON    = 1
+	_MAP_PRIVATE = 2
+
+	_DUPLICATE_SAME_ACCESS   = 0x2
+	_THREAD_PRIORITY_HIGHEST = 0x2
+
+	_SIGINT           = 0x2
+	_CTRL_C_EVENT     = 0x0
+	_CTRL_BREAK_EVENT = 0x1
+
+	_CONTEXT_CONTROL = 0x100001
+	_CONTEXT_FULL    = 0x10000b
+
+	_EXCEPTION_ACCESS_VIOLATION     = 0xc0000005
+	_EXCEPTION_BREAKPOINT           = 0x80000003
+	_EXCEPTION_FLT_DENORMAL_OPERAND = 0xc000008d
+	_EXCEPTION_FLT_DIVIDE_BY_ZERO   = 0xc000008e
+	_EXCEPTION_FLT_INEXACT_RESULT   = 0xc000008f
+	_EXCEPTION_FLT_OVERFLOW         = 0xc0000091
+	_EXCEPTION_FLT_UNDERFLOW        = 0xc0000093
+	_EXCEPTION_INT_DIVIDE_BY_ZERO   = 0xc0000094
+	_EXCEPTION_INT_OVERFLOW         = 0xc0000095
+
+	_INFINITE     = 0xffffffff
+	_WAIT_TIMEOUT = 0x102
+
+	_EXCEPTION_CONTINUE_EXECUTION = -0x1
+	_EXCEPTION_CONTINUE_SEARCH    = 0x0
+)
+
+type systeminfo struct {
+	anon0                       [4]byte
+	dwpagesize                  uint32
+	lpminimumapplicationaddress *byte
+	lpmaximumapplicationaddress *byte
+	dwactiveprocessormask       uint64
+	dwnumberofprocessors        uint32
+	dwprocessortype             uint32
+	dwallocationgranularity     uint32
+	wprocessorlevel             uint16
+	wprocessorrevision          uint16
+}
+
+type exceptionrecord struct {
+	exceptioncode        uint32
+	exceptionflags       uint32
+	exceptionrecord      *exceptionrecord
+	exceptionaddress     *byte
+	numberparameters     uint32
+	pad_cgo_0            [4]byte
+	exceptioninformation [15]uint64
+}
+
+type m128a struct {
+	low  uint64
+	high int64
+}
+
+type context struct {
+	p1home               uint64
+	p2home               uint64
+	p3home               uint64
+	p4home               uint64
+	p5home               uint64
+	p6home               uint64
+	contextflags         uint32
+	mxcsr                uint32
+	segcs                uint16
+	segds                uint16
+	seges                uint16
+	segfs                uint16
+	seggs                uint16
+	segss                uint16
+	eflags               uint32
+	dr0                  uint64
+	dr1                  uint64
+	dr2                  uint64
+	dr3                  uint64
+	dr6                  uint64
+	dr7                  uint64
+	rax                  uint64
+	rcx                  uint64
+	rdx                  uint64
+	rbx                  uint64
+	rsp                  uint64
+	rbp                  uint64
+	rsi                  uint64
+	rdi                  uint64
+	r8                   uint64
+	r9                   uint64
+	r10                  uint64
+	r11                  uint64
+	r12                  uint64
+	r13                  uint64
+	r14                  uint64
+	r15                  uint64
+	rip                  uint64
+	anon0                [512]byte
+	vectorregister       [26]m128a
+	vectorcontrol        uint64
+	debugcontrol         uint64
+	lastbranchtorip      uint64
+	lastbranchfromrip    uint64
+	lastexceptiontorip   uint64
+	lastexceptionfromrip uint64
+}
+
+func (c *context) ip() uintptr { return uintptr(c.rip) }
+func (c *context) sp() uintptr { return uintptr(c.rsp) }
+
+func (c *context) setip(x uintptr) { c.rip = uint64(x) }
+func (c *context) setsp(x uintptr) { c.rsp = uint64(x) }
+
+func dumpregs(r *context) {
+	print("rax     ", hex(r.rax), "\n")
+	print("rbx     ", hex(r.rbx), "\n")
+	print("rcx     ", hex(r.rcx), "\n")
+	print("rdi     ", hex(r.rdi), "\n")
+	print("rsi     ", hex(r.rsi), "\n")
+	print("rbp     ", hex(r.rbp), "\n")
+	print("rsp     ", hex(r.rsp), "\n")
+	print("r8      ", hex(r.r8), "\n")
+	print("r9      ", hex(r.r9), "\n")
+	print("r10     ", hex(r.r10), "\n")
+	print("r11     ", hex(r.r11), "\n")
+	print("r12     ", hex(r.r12), "\n")
+	print("r13     ", hex(r.r13), "\n")
+	print("r14     ", hex(r.r14), "\n")
+	print("r15     ", hex(r.r15), "\n")
+	print("rip     ", hex(r.rip), "\n")
+	print("rflags  ", hex(r.eflags), "\n")
+	print("cs      ", hex(r.segcs), "\n")
+	print("fs      ", hex(r.segfs), "\n")
+	print("gs      ", hex(r.seggs), "\n")
+}
+
+type overlapped struct {
+	internal     uint64
+	internalhigh uint64
+	anon0        [8]byte
+	hevent       *byte
+}
diff --git a/src/runtime/defs_windows_amd64.h b/src/runtime/defs_windows_amd64.h
deleted file mode 100644
index 7f37a7a..0000000
--- a/src/runtime/defs_windows_amd64.h
+++ /dev/null
@@ -1,131 +0,0 @@
-// Created by cgo -cdefs - DO NOT EDIT
-// cgo -cdefs defs_windows.go
-
-
-enum {
-	PROT_NONE	= 0,
-	PROT_READ	= 1,
-	PROT_WRITE	= 2,
-	PROT_EXEC	= 4,
-
-	MAP_ANON	= 1,
-	MAP_PRIVATE	= 2,
-
-	DUPLICATE_SAME_ACCESS	= 0x2,
-	THREAD_PRIORITY_HIGHEST	= 0x2,
-
-	SIGINT			= 0x2,
-	CTRL_C_EVENT		= 0x0,
-	CTRL_BREAK_EVENT	= 0x1,
-
-	CONTEXT_CONTROL	= 0x100001,
-	CONTEXT_FULL	= 0x10000b,
-
-	EXCEPTION_ACCESS_VIOLATION	= 0xc0000005,
-	EXCEPTION_BREAKPOINT		= 0x80000003,
-	EXCEPTION_FLT_DENORMAL_OPERAND	= 0xc000008d,
-	EXCEPTION_FLT_DIVIDE_BY_ZERO	= 0xc000008e,
-	EXCEPTION_FLT_INEXACT_RESULT	= 0xc000008f,
-	EXCEPTION_FLT_OVERFLOW		= 0xc0000091,
-	EXCEPTION_FLT_UNDERFLOW		= 0xc0000093,
-	EXCEPTION_INT_DIVIDE_BY_ZERO	= 0xc0000094,
-	EXCEPTION_INT_OVERFLOW		= 0xc0000095,
-
-	INFINITE	= 0xffffffff,
-	WAIT_TIMEOUT	= 0x102,
-
-	EXCEPTION_CONTINUE_EXECUTION	= -0x1,
-	EXCEPTION_CONTINUE_SEARCH	= 0x0,
-};
-
-typedef struct SystemInfo SystemInfo;
-typedef struct ExceptionRecord ExceptionRecord;
-typedef struct FloatingSaveArea FloatingSaveArea;
-typedef struct M128a M128a;
-typedef struct Context Context;
-typedef struct Overlapped Overlapped;
-
-#pragma pack on
-
-struct SystemInfo {
-	byte	anon0[4];
-	uint32	dwPageSize;
-	byte	*lpMinimumApplicationAddress;
-	byte	*lpMaximumApplicationAddress;
-	uint64	dwActiveProcessorMask;
-	uint32	dwNumberOfProcessors;
-	uint32	dwProcessorType;
-	uint32	dwAllocationGranularity;
-	uint16	wProcessorLevel;
-	uint16	wProcessorRevision;
-};
-struct ExceptionRecord {
-	uint32	ExceptionCode;
-	uint32	ExceptionFlags;
-	ExceptionRecord	*ExceptionRecord;
-	byte	*ExceptionAddress;
-	uint32	NumberParameters;
-	byte	Pad_cgo_0[4];
-	uint64	ExceptionInformation[15];
-};
-struct M128a {
-	uint64	Low;
-	int64	High;
-};
-struct Context {
-	uint64	P1Home;
-	uint64	P2Home;
-	uint64	P3Home;
-	uint64	P4Home;
-	uint64	P5Home;
-	uint64	P6Home;
-	uint32	ContextFlags;
-	uint32	MxCsr;
-	uint16	SegCs;
-	uint16	SegDs;
-	uint16	SegEs;
-	uint16	SegFs;
-	uint16	SegGs;
-	uint16	SegSs;
-	uint32	EFlags;
-	uint64	Dr0;
-	uint64	Dr1;
-	uint64	Dr2;
-	uint64	Dr3;
-	uint64	Dr6;
-	uint64	Dr7;
-	uint64	Rax;
-	uint64	Rcx;
-	uint64	Rdx;
-	uint64	Rbx;
-	uint64	Rsp;
-	uint64	Rbp;
-	uint64	Rsi;
-	uint64	Rdi;
-	uint64	R8;
-	uint64	R9;
-	uint64	R10;
-	uint64	R11;
-	uint64	R12;
-	uint64	R13;
-	uint64	R14;
-	uint64	R15;
-	uint64	Rip;
-	byte	anon0[512];
-	M128a	VectorRegister[26];
-	uint64	VectorControl;
-	uint64	DebugControl;
-	uint64	LastBranchToRip;
-	uint64	LastBranchFromRip;
-	uint64	LastExceptionToRip;
-	uint64	LastExceptionFromRip;
-};
-struct Overlapped {
-	uint64	Internal;
-	uint64	InternalHigh;
-	byte	anon0[8];
-	byte	*hEvent;
-};
-
-
-#pragma pack off
diff --git a/src/runtime/duff_386.s b/src/runtime/duff_386.s
new file mode 100644
index 0000000..5575455
--- /dev/null
+++ b/src/runtime/duff_386.s
@@ -0,0 +1,779 @@
+// AUTO-GENERATED by mkduff.go
+// Run go generate from src/runtime to update.
+// See mkduff.go for comments.
+
+#include "textflag.h"
+
+TEXT runtime·duffzero(SB), NOSPLIT, $0-0
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	STOSL
+	RET
+
+TEXT runtime·duffcopy(SB), NOSPLIT, $0-0
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	MOVL	(SI), CX
+	ADDL	$4, SI
+	MOVL	CX, (DI)
+	ADDL	$4, DI
+
+	RET
diff --git a/src/runtime/duff_amd64.s b/src/runtime/duff_amd64.s
new file mode 100644
index 0000000..0b51228
--- /dev/null
+++ b/src/runtime/duff_amd64.s
@@ -0,0 +1,841 @@
+// AUTO-GENERATED by mkduff.go
+// Run go generate from src/runtime to update.
+// See mkduff.go for comments.
+
+#include "textflag.h"
+
+TEXT runtime·duffzero(SB), NOSPLIT, $0-0
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	MOVQ	AX,(DI)
+	MOVQ	AX,8(DI)
+	MOVQ	AX,16(DI)
+	MOVQ	AX,24(DI)
+	ADDQ	$32,DI
+
+	STOSQ
+	STOSQ
+	STOSQ
+	STOSQ
+	RET
+
+TEXT runtime·duffcopy(SB), NOSPLIT, $0-0
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	MOVQ	(SI), CX
+	ADDQ	$8, SI
+	MOVQ	CX, (DI)
+	ADDQ	$8, DI
+
+	RET
diff --git a/src/runtime/duff_arm.s b/src/runtime/duff_arm.s
new file mode 100644
index 0000000..da9f0cb
--- /dev/null
+++ b/src/runtime/duff_arm.s
@@ -0,0 +1,523 @@
+// AUTO-GENERATED by mkduff.go
+// Run go generate from src/runtime to update.
+// See mkduff.go for comments.
+
+#include "textflag.h"
+
+TEXT runtime·duffzero(SB), NOSPLIT, $0-0
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	MOVW.P	R0, 4(R1)
+	RET
+
+TEXT runtime·duffcopy(SB), NOSPLIT, $0-0
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	MOVW.P	4(R1), R0
+	MOVW.P	R0, 4(R2)
+
+	RET
diff --git a/src/runtime/duff_arm64.s b/src/runtime/duff_arm64.s
new file mode 100644
index 0000000..6d4bb15
--- /dev/null
+++ b/src/runtime/duff_arm64.s
@@ -0,0 +1,138 @@
+// AUTO-GENERATED by mkduff.go
+// Run go generate from src/runtime to update.
+// See mkduff.go for comments.
+
+#include "textflag.h"
+
+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
+
+// TODO: Implement runtime·duffcopy.
diff --git a/src/runtime/duff_ppc64x.s b/src/runtime/duff_ppc64x.s
new file mode 100644
index 0000000..14bc33e
--- /dev/null
+++ b/src/runtime/duff_ppc64x.s
@@ -0,0 +1,140 @@
+// AUTO-GENERATED by mkduff.go
+// Run go generate from src/runtime to update.
+// See mkduff.go for comments.
+
+// +build ppc64 ppc64le
+
+#include "textflag.h"
+
+TEXT runtime·duffzero(SB), NOSPLIT, $-8-0
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	MOVDU	R0, 8(R3)
+	RET
+
+// TODO: Implement runtime·duffcopy.
diff --git a/src/runtime/env_plan9.go b/src/runtime/env_plan9.go
index e442c34..0e2588b 100644
--- a/src/runtime/env_plan9.go
+++ b/src/runtime/env_plan9.go
@@ -6,15 +6,6 @@ package runtime
 
 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 {
@@ -32,14 +23,14 @@ func gogetenv(key string) string {
 	}
 	n := seek(fd, 0, 2)
 	if n <= 0 {
-		close(fd)
+		closefd(fd)
 		return ""
 	}
 
 	p := make([]byte, n)
 
 	r := pread(fd, unsafe.Pointer(&p[0]), int32(n), 0)
-	close(fd)
+	closefd(fd)
 	if r < 0 {
 		return ""
 	}
@@ -54,3 +45,6 @@ func gogetenv(key string) string {
 	sp.len = int(r)
 	return s
 }
+
+var _cgo_setenv unsafe.Pointer   // pointer to C function
+var _cgo_unsetenv unsafe.Pointer // pointer to C function
diff --git a/src/runtime/env_posix.go b/src/runtime/env_posix.go
index dd57872..5e49287 100644
--- a/src/runtime/env_posix.go
+++ b/src/runtime/env_posix.go
@@ -8,21 +8,10 @@ package runtime
 
 import "unsafe"
 
-func environ() []string
-
-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 {
-		gothrow("getenv before env init")
+		throw("getenv before env init")
 	}
 	for _, s := range environ() {
 		if len(s) > len(key) && s[len(key)] == '=' && s[:len(key)] == key {
@@ -32,13 +21,14 @@ func gogetenv(key string) string {
 	return ""
 }
 
-var _cgo_setenv uintptr   // pointer to C function
-var _cgo_unsetenv uintptr // pointer to C function
+var _cgo_setenv unsafe.Pointer   // pointer to C function
+var _cgo_unsetenv unsafe.Pointer // pointer to C function
 
 // Update the C environment if cgo is loaded.
 // Called from syscall.Setenv.
+//go:linkname syscall_setenv_c syscall.setenv_c
 func syscall_setenv_c(k string, v string) {
-	if _cgo_setenv == 0 {
+	if _cgo_setenv == nil {
 		return
 	}
 	arg := [2]unsafe.Pointer{cstring(k), cstring(v)}
@@ -47,8 +37,9 @@ func syscall_setenv_c(k string, v string) {
 
 // Update the C environment if cgo is loaded.
 // Called from syscall.unsetenv.
+//go:linkname syscall_unsetenv_c syscall.unsetenv_c
 func syscall_unsetenv_c(k string) {
-	if _cgo_unsetenv == 0 {
+	if _cgo_unsetenv == nil {
 		return
 	}
 	arg := [1]unsafe.Pointer{cstring(k)}
diff --git a/src/runtime/env_test.go b/src/runtime/env_test.go
new file mode 100644
index 0000000..2399e46
--- /dev/null
+++ b/src/runtime/env_test.go
@@ -0,0 +1,47 @@
+// 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")
+	}
+
+	// Restore both the real GOROOT environment variable, and runtime's copies:
+	if orig, ok := syscall.Getenv("GOROOT"); ok {
+		defer syscall.Setenv("GOROOT", orig)
+	} else {
+		defer syscall.Unsetenv("GOROOT")
+	}
+	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 @@ type Error interface {
 	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 @@ func (e *TypeAssertionError) Error() string {
 		": 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_arm_test.go b/src/runtime/export_arm_test.go
new file mode 100644
index 0000000..446d264
--- /dev/null
+++ b/src/runtime/export_arm_test.go
@@ -0,0 +1,9 @@
+// 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.
+
+// Export guts for testing.
+
+package runtime
+
+var Usplit = usplit
diff --git a/src/runtime/export_linux_test.go b/src/runtime/export_linux_test.go
new file mode 100644
index 0000000..c8b9746
--- /dev/null
+++ b/src/runtime/export_linux_test.go
@@ -0,0 +1,9 @@
+// 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.
+
+// Export guts for testing.
+
+package runtime
+
+var NewOSProc0 = newosproc0
diff --git a/src/runtime/export_test.go b/src/runtime/export_test.go
index be35255..f14dc30 100644
--- a/src/runtime/export_test.go
+++ b/src/runtime/export_test.go
@@ -17,123 +17,78 @@ var F32to64 = f32to64
 var Fcmp64 = fcmp64
 var Fintto64 = fintto64
 var F64toint = f64toint
-
-// in asm_*.s
-func stackguard() (sp, limit uintptr)
+var Sqrt = sqrt
 
 var Entersyscall = entersyscall
 var Exitsyscall = exitsyscall
 var LockedOSThread = lockedOSThread
+var Xadduintptr = xadduintptr
+
+var FuncPC = funcPC
 
 type LFNode struct {
-	Next    *LFNode
+	Next    uint64
 	Pushcnt uintptr
 }
 
-func lfstackpush_m()
-func lfstackpop_m()
-
 func LFStackPush(head *uint64, node *LFNode) {
-	mp := acquirem()
-	mp.ptrarg[0] = unsafe.Pointer(head)
-	mp.ptrarg[1] = unsafe.Pointer(node)
-	onM(lfstackpush_m)
-	releasem(mp)
+	lfstackpush(head, (*lfnode)(unsafe.Pointer(node)))
 }
 
 func LFStackPop(head *uint64) *LFNode {
-	mp := acquirem()
-	mp.ptrarg[0] = unsafe.Pointer(head)
-	onM(lfstackpop_m)
-	node := (*LFNode)(unsafe.Pointer(mp.ptrarg[0]))
-	mp.ptrarg[0] = nil
-	releasem(mp)
-	return node
+	return (*LFNode)(unsafe.Pointer(lfstackpop(head)))
 }
 
 type ParFor struct {
-	body    *byte
-	done    uint32
-	Nthr    uint32
-	nthrmax uint32
-	thrseq  uint32
-	Cnt     uint32
-	Ctx     *byte
-	wait    bool
+	body   func(*ParFor, uint32)
+	done   uint32
+	Nthr   uint32
+	thrseq uint32
+	Cnt    uint32
+	wait   bool
 }
 
-func newparfor_m()
-func parforsetup_m()
-func parfordo_m()
-func parforiters_m()
-
 func NewParFor(nthrmax uint32) *ParFor {
-	mp := acquirem()
-	mp.scalararg[0] = uintptr(nthrmax)
-	onM(newparfor_m)
-	desc := (*ParFor)(mp.ptrarg[0])
-	mp.ptrarg[0] = nil
-	releasem(mp)
+	var desc *ParFor
+	systemstack(func() {
+		desc = (*ParFor)(unsafe.Pointer(parforalloc(nthrmax)))
+	})
 	return desc
 }
 
-func ParForSetup(desc *ParFor, nthr, n uint32, ctx *byte, wait bool, body func(*ParFor, uint32)) {
-	mp := acquirem()
-	mp.ptrarg[0] = unsafe.Pointer(desc)
-	mp.ptrarg[1] = unsafe.Pointer(ctx)
-	mp.ptrarg[2] = unsafe.Pointer(funcPC(body)) // TODO(rsc): Should be a scalar.
-	mp.scalararg[0] = uintptr(nthr)
-	mp.scalararg[1] = uintptr(n)
-	mp.scalararg[2] = 0
-	if wait {
-		mp.scalararg[2] = 1
-	}
-	onM(parforsetup_m)
-	releasem(mp)
+func ParForSetup(desc *ParFor, nthr, n uint32, wait bool, body func(*ParFor, uint32)) {
+	systemstack(func() {
+		parforsetup((*parfor)(unsafe.Pointer(desc)), nthr, n, wait,
+			*(*func(*parfor, uint32))(unsafe.Pointer(&body)))
+	})
 }
 
 func ParForDo(desc *ParFor) {
-	mp := acquirem()
-	mp.ptrarg[0] = unsafe.Pointer(desc)
-	onM(parfordo_m)
-	releasem(mp)
+	systemstack(func() {
+		parfordo((*parfor)(unsafe.Pointer(desc)))
+	})
 }
 
 func ParForIters(desc *ParFor, tid uint32) (uint32, uint32) {
-	mp := acquirem()
-	mp.ptrarg[0] = unsafe.Pointer(desc)
-	mp.scalararg[0] = uintptr(tid)
-	onM(parforiters_m)
-	begin := uint32(mp.scalararg[0])
-	end := uint32(mp.scalararg[1])
-	releasem(mp)
-	return begin, end
+	desc1 := (*parfor)(unsafe.Pointer(desc))
+	pos := desc1.thr[tid].pos
+	return uint32(pos), uint32(pos >> 32)
 }
 
-// in mgc0.c
-//go:noescape
-func getgcmask(data unsafe.Pointer, typ *_type, array **byte, len *uint)
-
 func GCMask(x interface{}) (ret []byte) {
-	e := (*eface)(unsafe.Pointer(&x))
-	s := (*slice)(unsafe.Pointer(&ret))
-	onM(func() {
-		getgcmask(e.data, e._type, &s.array, &s.len)
-		s.cap = s.len
+	systemstack(func() {
+		ret = getgcmask(x)
 	})
 	return
 }
 
-func testSchedLocalQueue()
-func testSchedLocalQueueSteal()
 func RunSchedLocalQueueTest() {
-	onM(testSchedLocalQueue)
+	testSchedLocalQueue()
 }
 func RunSchedLocalQueueStealTest() {
-	onM(testSchedLocalQueueSteal)
+	testSchedLocalQueueSteal()
 }
 
-var HaveGoodHash = haveGoodHash
 var StringHash = stringHash
 var BytesHash = bytesHash
 var Int32Hash = int32Hash
@@ -144,18 +99,9 @@ var MemclrBytes = memclrBytes
 
 var HashLoad = &hashLoad
 
-// For testing.
-func GogoBytes() int32 {
-	return _RuntimeGogoBytes
-}
-
-// in string.c
-//go:noescape
-func gostringw(w *uint16) string
-
 // entry point for testing
 func GostringW(w []uint16) (s string) {
-	onM(func() {
+	systemstack(func() {
 		s = gostringw(&w[0])
 	})
 	return
@@ -163,3 +109,49 @@ func GostringW(w []uint16) (s string) {
 
 var Gostringnocopy = gostringnocopy
 var Maxstring = &maxstring
+
+type Uintreg uintreg
+
+var Open = open
+var Close = closefd
+var Read = read
+var Write = write
+
+func Envs() []string     { return envs }
+func SetEnvs(e []string) { envs = e }
+
+var BigEndian = _BigEndian
+
+// For benchmarking.
+
+func BenchSetType(n int, x interface{}) {
+	e := *(*eface)(unsafe.Pointer(&x))
+	t := e._type
+	var size uintptr
+	var p unsafe.Pointer
+	switch t.kind & kindMask {
+	case _KindPtr:
+		t = (*ptrtype)(unsafe.Pointer(t)).elem
+		size = t.size
+		p = e.data
+	case _KindSlice:
+		slice := *(*struct {
+			ptr      unsafe.Pointer
+			len, cap uintptr
+		})(e.data)
+		t = (*slicetype)(unsafe.Pointer(t)).elem
+		size = t.size * slice.len
+		p = slice.ptr
+	}
+	allocSize := roundupsize(size)
+	systemstack(func() {
+		for i := 0; i < n; i++ {
+			heapBitsSetType(uintptr(p), allocSize, size, t)
+		}
+	})
+}
+
+const PtrSize = ptrSize
+
+var TestingAssertE2I2GC = &testingAssertE2I2GC
+var TestingAssertE2T2GC = &testingAssertE2T2GC
diff --git a/src/runtime/export_windows_test.go b/src/runtime/export_windows_test.go
new file mode 100644
index 0000000..61fcef9
--- /dev/null
+++ b/src/runtime/export_windows_test.go
@@ -0,0 +1,9 @@
+// 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.
+
+// Export guts for testing.
+
+package runtime
+
+var TestingWER = &testingWER
diff --git a/src/runtime/extern.go b/src/runtime/extern.go
index 6cc5df8..cdb66ba 100644
--- a/src/runtime/extern.go
+++ b/src/runtime/extern.go
@@ -19,10 +19,10 @@ A collection is triggered when the ratio of freshly allocated data to live data
 remaining after the previous collection reaches this percentage. The default
 is GOGC=100. Setting GOGC=off disables the garbage collector entirely.
 The runtime/debug package's SetGCPercent function allows changing this
-percentage at run time. See http://golang.org/pkg/runtime/debug/#SetGCPercent.
+percentage at run time. See https://golang.org/pkg/runtime/debug/#SetGCPercent.
 
-The GODEBUG variable controls debug output from the runtime. GODEBUG value is
-a comma-separated list of name=val pairs. Supported names are:
+The GODEBUG variable controls debugging variables within the runtime.
+It is a comma-separated list of name=val pairs setting these named variables:
 
 	allocfreetrace: setting allocfreetrace=1 causes every allocation to be
 	profiled and a stack trace printed on each object's allocation and free.
@@ -31,13 +31,53 @@ a comma-separated list of name=val pairs. Supported names are:
 	where each object is allocated on a unique page and addresses are
 	never recycled.
 
+	gccheckmark: setting gccheckmark=1 enables verification of the
+	garbage collector's concurrent mark phase by performing a
+	second mark pass while the world is stopped.  If the second
+	pass finds a reachable object that was not found by concurrent
+	mark, the garbage collector will panic.
+
+	gcpacertrace: setting gcpacertrace=1 causes the garbage collector to
+	print information about the internal state of the concurrent pacer.
+
+	gcshrinkstackoff: setting gcshrinkstackoff=1 disables moving goroutines
+	onto smaller stacks. In this mode, a goroutine's stack can only grow.
+
+	gcstackbarrieroff: setting gcstackbarrieroff=1 disables the use of stack barriers
+	that allow the garbage collector to avoid repeating a stack scan during the
+	mark termination phase.
+
+	gcstackbarrierall: setting gcstackbarrierall=1 installs stack barriers
+	in every stack frame, rather than in exponentially-spaced frames.
+
+	gcstoptheworld: setting gcstoptheworld=1 disables concurrent garbage collection,
+	making every garbage collection a stop-the-world event. Setting gcstoptheworld=2
+	also disables concurrent sweeping after the garbage collection finishes.
+
 	gctrace: setting gctrace=1 causes the garbage collector to emit a single line to standard
 	error at each collection, summarizing the amount of memory collected and the
 	length of the pause. Setting gctrace=2 emits the same summary but also
-	repeats each collection.
-
-	gcdead: setting gcdead=1 causes the garbage collector to clobber all stack slots
-	that it thinks are dead.
+	repeats each collection. The format of this line is subject to change.
+	Currently, it is:
+		gc # @#s #%: #+...+# ms clock, #+...+# ms cpu, #->#-># MB, # MB goal, # P
+	where the fields are as follows:
+		gc #        the GC number, incremented at each GC
+		@#s         time in seconds since program start
+		#%          percentage of time spent in GC since program start
+		#+...+#     wall-clock/CPU times for the phases of the GC
+		#->#-># MB  heap size at GC start, at GC end, and live heap
+		# MB goal   goal heap size
+		# P         number of processors used
+	The phases are stop-the-world (STW) sweep termination, scan,
+	synchronize Ps, mark, and STW mark termination. The CPU times
+	for mark are broken down in to assist time (GC performed in
+	line with allocation), background GC time, and idle GC time.
+	If the line ends with "(forced)", this GC was forced by a
+	runtime.GC() call and all phases are STW.
+
+	memprofilerate: setting memprofilerate=X will update the value of runtime.MemProfileRate.
+	When set to 0 memory profiling is disabled.  Refer to the description of
+	MemProfileRate for the default value.
 
 	invalidptr: defaults to invalidptr=1, causing the garbage collector and stack
 	copier to crash the program if an invalid pointer value (for example, 1)
@@ -45,6 +85,12 @@ a comma-separated list of name=val pairs. Supported names are:
 	This should only be used as a temporary workaround to diagnose buggy code.
 	The real fix is to not store integers in pointer-typed locations.
 
+	sbrk: setting sbrk=1 replaces the memory allocator and garbage collector
+	with a trivial allocator that obtains memory from the operating system and
+	never reclaims any memory.
+
+	scavenge: scavenge=1 enables debugging mode of heap scavenger.
+
 	scheddetail: setting schedtrace=X and scheddetail=1 causes the scheduler to emit
 	detailed multiline info every X milliseconds, describing state of the scheduler,
 	processors, threads and goroutines.
@@ -52,8 +98,6 @@ a comma-separated list of name=val pairs. Supported names are:
 	schedtrace: setting schedtrace=X causes the scheduler to emit a single line to standard
 	error every X milliseconds, summarizing the scheduler state.
 
-	scavenge: scavenge=1 enables debugging mode of heap scavenger.
-
 The GOMAXPROCS variable limits the number of operating system threads that
 can execute user-level Go code simultaneously. There is no limit to the number of threads
 that can be blocked in system calls on behalf of Go code; those do not count against
@@ -74,7 +118,7 @@ core dump.
 
 The GOARCH, GOOS, GOPATH, and GOROOT environment variables complete
 the set of Go environment variables. They influence the building of Go programs
-(see http://golang.org/cmd/go and http://golang.org/pkg/go/build).
+(see https://golang.org/cmd/go and https://golang.org/pkg/go/build).
 GOARCH, GOOS, and GOROOT are recorded at compile time and made available by
 constants or functions in this package, but they do not influence the execution
 of the run-time system.
@@ -92,7 +136,7 @@ func Caller(skip int) (pc uintptr, file string, line int, ok bool) {
 	// and what it called, so that we can see if it
 	// "called" sigpanic.
 	var rpc [2]uintptr
-	if callers(1+skip-1, &rpc[0], 2) < 2 {
+	if callers(1+skip-1, rpc[:]) < 2 {
 		return
 	}
 	f := findfunc(rpc[1])
@@ -112,7 +156,8 @@ func Caller(skip int) (pc uintptr, file string, line int, ok bool) {
 	if xpc > f.entry && (g == nil || g.entry != funcPC(sigpanic)) {
 		xpc--
 	}
-	line = int(funcline(f, xpc, &file))
+	file, line32 := funcline(f, xpc)
+	line = int(line32)
 	ok = true
 	return
 }
@@ -138,7 +183,7 @@ func Callers(skip int, pc []uintptr) int {
 	if len(pc) == 0 {
 		return 0
 	}
-	return callers(skip, &pc[0], len(pc))
+	return callers(skip, pc)
 }
 
 // GOROOT returns the root of the Go tree.
diff --git a/src/runtime/float.c b/src/runtime/float.c
deleted file mode 100644
index 42082e4..0000000
--- a/src/runtime/float.c
+++ /dev/null
@@ -1,10 +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 "runtime.h"
-
-// used as float64 via runtime· names
-uint64	·nan		= 0x7FF8000000000001ULL;
-uint64	·posinf	= 0x7FF0000000000000ULL;
-uint64	·neginf	= 0xFFF0000000000000ULL;
diff --git a/src/runtime/funcdata.h b/src/runtime/funcdata.h
index d6c14fc..ce62dab 100644
--- a/src/runtime/funcdata.h
+++ b/src/runtime/funcdata.h
@@ -3,9 +3,10 @@
 // license that can be found in the LICENSE file.
 
 // This file defines the IDs for PCDATA and FUNCDATA instructions
-// in Go binaries. It is included by both C and assembly, so it must
-// be written using #defines. It is included by the runtime package
-// as well as the compilers.
+// in Go binaries. It is included by assembly sources, so it must
+// be written using #defines.
+//
+// The Go compiler also #includes this file, for now.
 //
 // symtab.go also contains a copy of these constants.
 
@@ -50,8 +51,7 @@
 
 /*c2go
 enum {
-	PCDATA_ArgSize = 0,
-	PCDATA_StackMapIndex = 1,
+	PCDATA_StackMapIndex = 0,
 	FUNCDATA_ArgsPointerMaps = 0,
 	FUNCDATA_LocalsPointerMaps = 1,
 	FUNCDATA_DeadValueMaps = 2,
diff --git a/src/runtime/futex_test.go b/src/runtime/futex_test.go
index f57fc52..b85249a 100644
--- a/src/runtime/futex_test.go
+++ b/src/runtime/futex_test.go
@@ -44,9 +44,9 @@ func TestFutexsleep(t *testing.T) {
 	start := time.Now()
 	for _, tt := range futexsleepTests {
 		go func(tt futexsleepTest) {
-			runtime.Entersyscall()
+			runtime.Entersyscall(0)
 			runtime.Futexsleep(&tt.mtx, tt.mtx, tt.ns)
-			runtime.Exitsyscall()
+			runtime.Exitsyscall(0)
 			tt.ch <- tt
 		}(tt)
 	}
diff --git a/src/runtime/gc_test.go b/src/runtime/gc_test.go
index 6abec4c..6c9b314 100644
--- a/src/runtime/gc_test.go
+++ b/src/runtime/gc_test.go
@@ -5,7 +5,9 @@
 package runtime_test
 
 import (
+	"io"
 	"os"
+	"reflect"
 	"runtime"
 	"runtime/debug"
 	"testing"
@@ -197,45 +199,166 @@ func TestHugeGCInfo(t *testing.T) {
 	}
 }
 
-func BenchmarkSetTypeNoPtr1(b *testing.B) {
-	type NoPtr1 struct {
-		p uintptr
-	}
-	var p *NoPtr1
-	for i := 0; i < b.N; i++ {
-		p = &NoPtr1{}
-	}
-	_ = p
+func BenchmarkSetTypePtr(b *testing.B) {
+	benchSetType(b, new(*byte))
 }
-func BenchmarkSetTypeNoPtr2(b *testing.B) {
-	type NoPtr2 struct {
-		p, q uintptr
-	}
-	var p *NoPtr2
-	for i := 0; i < b.N; i++ {
-		p = &NoPtr2{}
-	}
-	_ = p
+
+func BenchmarkSetTypePtr8(b *testing.B) {
+	benchSetType(b, new([8]*byte))
 }
-func BenchmarkSetTypePtr1(b *testing.B) {
-	type Ptr1 struct {
-		p *byte
-	}
-	var p *Ptr1
-	for i := 0; i < b.N; i++ {
-		p = &Ptr1{}
-	}
-	_ = p
+
+func BenchmarkSetTypePtr16(b *testing.B) {
+	benchSetType(b, new([16]*byte))
 }
-func BenchmarkSetTypePtr2(b *testing.B) {
-	type Ptr2 struct {
-		p, q *byte
-	}
-	var p *Ptr2
-	for i := 0; i < b.N; i++ {
-		p = &Ptr2{}
-	}
-	_ = p
+
+func BenchmarkSetTypePtr32(b *testing.B) {
+	benchSetType(b, new([32]*byte))
+}
+
+func BenchmarkSetTypePtr64(b *testing.B) {
+	benchSetType(b, new([64]*byte))
+}
+
+func BenchmarkSetTypePtr126(b *testing.B) {
+	benchSetType(b, new([126]*byte))
+}
+
+func BenchmarkSetTypePtr128(b *testing.B) {
+	benchSetType(b, new([128]*byte))
+}
+
+func BenchmarkSetTypePtrSlice(b *testing.B) {
+	benchSetType(b, make([]*byte, 1<<10))
+}
+
+type Node1 struct {
+	Value       [1]uintptr
+	Left, Right *byte
+}
+
+func BenchmarkSetTypeNode1(b *testing.B) {
+	benchSetType(b, new(Node1))
+}
+
+func BenchmarkSetTypeNode1Slice(b *testing.B) {
+	benchSetType(b, make([]Node1, 32))
+}
+
+type Node8 struct {
+	Value       [8]uintptr
+	Left, Right *byte
+}
+
+func BenchmarkSetTypeNode8(b *testing.B) {
+	benchSetType(b, new(Node8))
+}
+
+func BenchmarkSetTypeNode8Slice(b *testing.B) {
+	benchSetType(b, make([]Node8, 32))
+}
+
+type Node64 struct {
+	Value       [64]uintptr
+	Left, Right *byte
+}
+
+func BenchmarkSetTypeNode64(b *testing.B) {
+	benchSetType(b, new(Node64))
+}
+
+func BenchmarkSetTypeNode64Slice(b *testing.B) {
+	benchSetType(b, make([]Node64, 32))
+}
+
+type Node64Dead struct {
+	Left, Right *byte
+	Value       [64]uintptr
+}
+
+func BenchmarkSetTypeNode64Dead(b *testing.B) {
+	benchSetType(b, new(Node64Dead))
+}
+
+func BenchmarkSetTypeNode64DeadSlice(b *testing.B) {
+	benchSetType(b, make([]Node64Dead, 32))
+}
+
+type Node124 struct {
+	Value       [124]uintptr
+	Left, Right *byte
+}
+
+func BenchmarkSetTypeNode124(b *testing.B) {
+	benchSetType(b, new(Node124))
+}
+
+func BenchmarkSetTypeNode124Slice(b *testing.B) {
+	benchSetType(b, make([]Node124, 32))
+}
+
+type Node126 struct {
+	Value       [126]uintptr
+	Left, Right *byte
+}
+
+func BenchmarkSetTypeNode126(b *testing.B) {
+	benchSetType(b, new(Node126))
+}
+
+func BenchmarkSetTypeNode126Slice(b *testing.B) {
+	benchSetType(b, make([]Node126, 32))
+}
+
+type Node128 struct {
+	Value       [128]uintptr
+	Left, Right *byte
+}
+
+func BenchmarkSetTypeNode128(b *testing.B) {
+	benchSetType(b, new(Node128))
+}
+
+func BenchmarkSetTypeNode128Slice(b *testing.B) {
+	benchSetType(b, make([]Node128, 32))
+}
+
+type Node130 struct {
+	Value       [130]uintptr
+	Left, Right *byte
+}
+
+func BenchmarkSetTypeNode130(b *testing.B) {
+	benchSetType(b, new(Node130))
+}
+
+func BenchmarkSetTypeNode130Slice(b *testing.B) {
+	benchSetType(b, make([]Node130, 32))
+}
+
+type Node1024 struct {
+	Value       [1024]uintptr
+	Left, Right *byte
+}
+
+func BenchmarkSetTypeNode1024(b *testing.B) {
+	benchSetType(b, new(Node1024))
+}
+
+func BenchmarkSetTypeNode1024Slice(b *testing.B) {
+	benchSetType(b, make([]Node1024, 32))
+}
+
+func benchSetType(b *testing.B, x interface{}) {
+	v := reflect.ValueOf(x)
+	t := v.Type()
+	switch t.Kind() {
+	case reflect.Ptr:
+		b.SetBytes(int64(t.Elem().Size()))
+	case reflect.Slice:
+		b.SetBytes(int64(t.Elem().Size()) * int64(v.Len()))
+	}
+	b.ResetTimer()
+	runtime.BenchSetType(b.N, x)
 }
 
 func BenchmarkAllocation(b *testing.B) {
@@ -290,3 +413,76 @@ func TestPrintGC(t *testing.T) {
 	}
 	close(done)
 }
+
+// The implicit y, ok := x.(error) for the case error
+// in testTypeSwitch used to not initialize the result y
+// before passing &y to assertE2I2GC.
+// Catch this by making assertE2I2 call runtime.GC,
+// which will force a stack scan and failure if there are
+// bad pointers, and then fill the stack with bad pointers
+// and run the type switch.
+func TestAssertE2I2Liveness(t *testing.T) {
+	// Note that this flag is defined in export_test.go
+	// and is not available to ordinary imports of runtime.
+	*runtime.TestingAssertE2I2GC = true
+	defer func() {
+		*runtime.TestingAssertE2I2GC = false
+	}()
+
+	poisonStack()
+	testTypeSwitch(io.EOF)
+	poisonStack()
+	testAssert(io.EOF)
+	poisonStack()
+	testAssertVar(io.EOF)
+}
+
+func poisonStack() uintptr {
+	var x [1000]uintptr
+	for i := range x {
+		x[i] = 0xff
+	}
+	return x[123]
+}
+
+func testTypeSwitch(x interface{}) error {
+	switch y := x.(type) {
+	case nil:
+		// ok
+	case error:
+		return y
+	}
+	return nil
+}
+
+func testAssert(x interface{}) error {
+	if y, ok := x.(error); ok {
+		return y
+	}
+	return nil
+}
+
+func testAssertVar(x interface{}) error {
+	var y, ok = x.(error)
+	if ok {
+		return y
+	}
+	return nil
+}
+
+func TestAssertE2T2Liveness(t *testing.T) {
+	*runtime.TestingAssertE2T2GC = true
+	defer func() {
+		*runtime.TestingAssertE2T2GC = false
+	}()
+
+	poisonStack()
+	testIfaceEqual(io.EOF)
+}
+
+func testIfaceEqual(x interface{}) {
+	if x == "abc" {
+		// Prevent inlining
+		panic("")
+	}
+}
diff --git a/src/runtime/gcinfo_test.go b/src/runtime/gcinfo_test.go
index 88f6703..f330bf2 100644
--- a/src/runtime/gcinfo_test.go
+++ b/src/runtime/gcinfo_test.go
@@ -10,24 +10,32 @@ import (
 	"testing"
 )
 
+const (
+	typeScalar  = 0
+	typePointer = 1
+)
+
 // TestGCInfo tests that various objects in heap, data and bss receive correct GC pointer type info.
 func TestGCInfo(t *testing.T) {
-	verifyGCInfo(t, "bss ScalarPtr", &bssScalarPtr, nonStackInfo(infoScalarPtr))
-	verifyGCInfo(t, "bss PtrScalar", &bssPtrScalar, nonStackInfo(infoPtrScalar))
-	verifyGCInfo(t, "bss BigStruct", &bssBigStruct, nonStackInfo(infoBigStruct()))
-	verifyGCInfo(t, "bss string", &bssString, nonStackInfo(infoString))
-	verifyGCInfo(t, "bss slice", &bssSlice, nonStackInfo(infoSlice))
-	verifyGCInfo(t, "bss eface", &bssEface, nonStackInfo(infoEface))
-	verifyGCInfo(t, "bss iface", &bssIface, nonStackInfo(infoIface))
-
-	verifyGCInfo(t, "data ScalarPtr", &dataScalarPtr, nonStackInfo(infoScalarPtr))
-	verifyGCInfo(t, "data PtrScalar", &dataPtrScalar, nonStackInfo(infoPtrScalar))
-	verifyGCInfo(t, "data BigStruct", &dataBigStruct, nonStackInfo(infoBigStruct()))
-	verifyGCInfo(t, "data string", &dataString, nonStackInfo(infoString))
-	verifyGCInfo(t, "data slice", &dataSlice, nonStackInfo(infoSlice))
-	verifyGCInfo(t, "data eface", &dataEface, nonStackInfo(infoEface))
-	verifyGCInfo(t, "data iface", &dataIface, nonStackInfo(infoIface))
-
+	verifyGCInfo(t, "bss Ptr", &bssPtr, infoPtr)
+	verifyGCInfo(t, "bss ScalarPtr", &bssScalarPtr, infoScalarPtr)
+	verifyGCInfo(t, "bss PtrScalar", &bssPtrScalar, infoPtrScalar)
+	verifyGCInfo(t, "bss BigStruct", &bssBigStruct, infoBigStruct())
+	verifyGCInfo(t, "bss string", &bssString, infoString)
+	verifyGCInfo(t, "bss slice", &bssSlice, infoSlice)
+	verifyGCInfo(t, "bss eface", &bssEface, infoEface)
+	verifyGCInfo(t, "bss iface", &bssIface, infoIface)
+
+	verifyGCInfo(t, "data Ptr", &dataPtr, infoPtr)
+	verifyGCInfo(t, "data ScalarPtr", &dataScalarPtr, infoScalarPtr)
+	verifyGCInfo(t, "data PtrScalar", &dataPtrScalar, infoPtrScalar)
+	verifyGCInfo(t, "data BigStruct", &dataBigStruct, infoBigStruct())
+	verifyGCInfo(t, "data string", &dataString, infoString)
+	verifyGCInfo(t, "data slice", &dataSlice, infoSlice)
+	verifyGCInfo(t, "data eface", &dataEface, infoEface)
+	verifyGCInfo(t, "data iface", &dataIface, infoIface)
+
+	verifyGCInfo(t, "stack Ptr", new(Ptr), infoPtr)
 	verifyGCInfo(t, "stack ScalarPtr", new(ScalarPtr), infoScalarPtr)
 	verifyGCInfo(t, "stack PtrScalar", new(PtrScalar), infoPtrScalar)
 	verifyGCInfo(t, "stack BigStruct", new(BigStruct), infoBigStruct())
@@ -37,40 +45,43 @@ func TestGCInfo(t *testing.T) {
 	verifyGCInfo(t, "stack iface", new(Iface), infoIface)
 
 	for i := 0; i < 10; i++ {
-		verifyGCInfo(t, "heap ScalarPtr", escape(new(ScalarPtr)), nonStackInfo(infoScalarPtr))
-		verifyGCInfo(t, "heap PtrScalar", escape(new(PtrScalar)), nonStackInfo(infoPtrScalar))
-		verifyGCInfo(t, "heap BigStruct", escape(new(BigStruct)), nonStackInfo(infoBigStruct()))
-		verifyGCInfo(t, "heap string", escape(new(string)), nonStackInfo(infoString))
-		verifyGCInfo(t, "heap eface", escape(new(interface{})), nonStackInfo(infoEface))
-		verifyGCInfo(t, "heap iface", escape(new(Iface)), nonStackInfo(infoIface))
+		verifyGCInfo(t, "heap Ptr", escape(new(Ptr)), trimDead(padDead(infoPtr)))
+		verifyGCInfo(t, "heap PtrSlice", escape(&make([]*byte, 10)[0]), trimDead(infoPtr10))
+		verifyGCInfo(t, "heap ScalarPtr", escape(new(ScalarPtr)), trimDead(infoScalarPtr))
+		verifyGCInfo(t, "heap ScalarPtrSlice", escape(&make([]ScalarPtr, 4)[0]), trimDead(infoScalarPtr4))
+		verifyGCInfo(t, "heap PtrScalar", escape(new(PtrScalar)), trimDead(infoPtrScalar))
+		verifyGCInfo(t, "heap BigStruct", escape(new(BigStruct)), trimDead(infoBigStruct()))
+		verifyGCInfo(t, "heap string", escape(new(string)), trimDead(infoString))
+		verifyGCInfo(t, "heap eface", escape(new(interface{})), trimDead(infoEface))
+		verifyGCInfo(t, "heap iface", escape(new(Iface)), trimDead(infoIface))
 	}
-
 }
 
 func verifyGCInfo(t *testing.T, name string, p interface{}, mask0 []byte) {
 	mask := runtime.GCMask(p)
-	if len(mask) > len(mask0) {
-		mask0 = append(mask0, BitsDead)
-		mask = mask[:len(mask0)]
-	}
 	if bytes.Compare(mask, mask0) != 0 {
 		t.Errorf("bad GC program for %v:\nwant %+v\ngot  %+v", name, mask0, mask)
 		return
 	}
 }
 
-func nonStackInfo(mask []byte) []byte {
-	// BitsDead is replaced with BitsScalar everywhere except stacks.
-	mask1 := make([]byte, len(mask))
-	mw := false
-	for i, v := range mask {
-		if !mw && v == BitsDead {
-			v = BitsScalar
-		}
-		mw = !mw && v == BitsMultiWord
-		mask1[i] = v
+func padDead(mask []byte) []byte {
+	// Because the dead bit isn't encoded until the third word,
+	// and because on 32-bit systems a one-word allocation
+	// uses a two-word block, the pointer info for a one-word
+	// object needs to be expanded to include an extra scalar
+	// on 32-bit systems to match the heap bitmap.
+	if runtime.PtrSize == 4 && len(mask) == 1 {
+		return []byte{mask[0], 0}
 	}
-	return mask1
+	return mask
+}
+
+func trimDead(mask []byte) []byte {
+	for len(mask) > 2 && mask[len(mask)-1] == typeScalar {
+		mask = mask[:len(mask)-1]
+	}
+	return mask
 }
 
 var gcinfoSink interface{}
@@ -80,19 +91,13 @@ func escape(p interface{}) interface{} {
 	return p
 }
 
-const (
-	BitsDead = iota
-	BitsScalar
-	BitsPointer
-	BitsMultiWord
-)
+var infoPtr = []byte{typePointer}
 
-const (
-	BitsString = iota // unused
-	BitsSlice         // unused
-	BitsIface
-	BitsEface
-)
+type Ptr struct {
+	*byte
+}
+
+var infoPtr10 = []byte{typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer, typePointer}
 
 type ScalarPtr struct {
 	q int
@@ -103,7 +108,9 @@ type ScalarPtr struct {
 	y *int
 }
 
-var infoScalarPtr = []byte{BitsScalar, BitsPointer, BitsScalar, BitsPointer, BitsScalar, BitsPointer}
+var infoScalarPtr = []byte{typeScalar, typePointer, typeScalar, typePointer, typeScalar, typePointer}
+
+var infoScalarPtr4 = append(append(append(append([]byte(nil), infoScalarPtr...), infoScalarPtr...), infoScalarPtr...), infoScalarPtr...)
 
 type PtrScalar struct {
 	q *int
@@ -114,7 +121,7 @@ type PtrScalar struct {
 	y int
 }
 
-var infoPtrScalar = []byte{BitsPointer, BitsScalar, BitsPointer, BitsScalar, BitsPointer, BitsScalar}
+var infoPtrScalar = []byte{typePointer, typeScalar, typePointer, typeScalar, typePointer, typeScalar}
 
 type BigStruct struct {
 	q *int
@@ -131,27 +138,27 @@ func infoBigStruct() []byte {
 	switch runtime.GOARCH {
 	case "386", "arm":
 		return []byte{
-			BitsPointer,                                                // q *int
-			BitsScalar, BitsScalar, BitsScalar, BitsScalar, BitsScalar, // w byte; e [17]byte
-			BitsPointer, BitsDead, BitsDead, // r []byte
-			BitsScalar, BitsScalar, BitsScalar, BitsScalar, // t int; y uint16; u uint64
-			BitsPointer, BitsDead, // i string
+			typePointer,                                                // q *int
+			typeScalar, typeScalar, typeScalar, typeScalar, typeScalar, // w byte; e [17]byte
+			typePointer, typeScalar, typeScalar, // r []byte
+			typeScalar, typeScalar, typeScalar, typeScalar, // t int; y uint16; u uint64
+			typePointer, typeScalar, // i string
 		}
-	case "amd64":
+	case "arm64", "amd64", "ppc64", "ppc64le":
 		return []byte{
-			BitsPointer,                        // q *int
-			BitsScalar, BitsScalar, BitsScalar, // w byte; e [17]byte
-			BitsPointer, BitsDead, BitsDead, // r []byte
-			BitsScalar, BitsScalar, BitsScalar, // t int; y uint16; u uint64
-			BitsPointer, BitsDead, // i string
+			typePointer,                        // q *int
+			typeScalar, typeScalar, typeScalar, // w byte; e [17]byte
+			typePointer, typeScalar, typeScalar, // r []byte
+			typeScalar, typeScalar, typeScalar, // t int; y uint16; u uint64
+			typePointer, typeScalar, // i string
 		}
 	case "amd64p32":
 		return []byte{
-			BitsPointer,                                                // q *int
-			BitsScalar, BitsScalar, BitsScalar, BitsScalar, BitsScalar, // w byte; e [17]byte
-			BitsPointer, BitsDead, BitsDead, // r []byte
-			BitsScalar, BitsScalar, BitsDead, BitsScalar, BitsScalar, // t int; y uint16; u uint64
-			BitsPointer, BitsDead, // i string
+			typePointer,                                                // q *int
+			typeScalar, typeScalar, typeScalar, typeScalar, typeScalar, // w byte; e [17]byte
+			typePointer, typeScalar, typeScalar, // r []byte
+			typeScalar, typeScalar, typeScalar, typeScalar, typeScalar, // t int; y uint16; u uint64
+			typePointer, typeScalar, // i string
 		}
 	default:
 		panic("unknown arch")
@@ -169,6 +176,7 @@ func (IfaceImpl) f() {
 
 var (
 	// BSS
+	bssPtr       Ptr
 	bssScalarPtr ScalarPtr
 	bssPtrScalar PtrScalar
 	bssBigStruct BigStruct
@@ -178,6 +186,7 @@ var (
 	bssIface     Iface
 
 	// DATA
+	dataPtr                   = Ptr{new(byte)}
 	dataScalarPtr             = ScalarPtr{q: 1}
 	dataPtrScalar             = PtrScalar{w: 1}
 	dataBigStruct             = BigStruct{w: 1}
@@ -186,8 +195,8 @@ var (
 	dataEface     interface{} = 42
 	dataIface     Iface       = IfaceImpl(42)
 
-	infoString = []byte{BitsPointer, BitsDead}
-	infoSlice  = []byte{BitsPointer, BitsDead, BitsDead}
-	infoEface  = []byte{BitsMultiWord, BitsEface}
-	infoIface  = []byte{BitsMultiWord, BitsIface}
+	infoString = []byte{typePointer, typeScalar}
+	infoSlice  = []byte{typePointer, typeScalar, typeScalar}
+	infoEface  = []byte{typePointer, typePointer}
+	infoIface  = []byte{typePointer, typePointer}
 )
diff --git a/src/runtime/gengoos.go b/src/runtime/gengoos.go
new file mode 100644
index 0000000..06621c8
--- /dev/null
+++ b/src/runtime/gengoos.go
@@ -0,0 +1,84 @@
+// 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 ignore
+
+package main
+
+import (
+	"bytes"
+	"fmt"
+	"io/ioutil"
+	"log"
+	"strconv"
+	"strings"
+)
+
+var gooses, goarches []string
+
+func main() {
+	data, err := ioutil.ReadFile("../go/build/syslist.go")
+	if err != nil {
+		log.Fatal(err)
+	}
+	const (
+		goosPrefix   = `const goosList = `
+		goarchPrefix = `const goarchList = `
+	)
+	for _, line := range strings.Split(string(data), "\n") {
+		if strings.HasPrefix(line, goosPrefix) {
+			text, err := strconv.Unquote(strings.TrimPrefix(line, goosPrefix))
+			if err != nil {
+				log.Fatalf("parsing goosList %#q: %v", strings.TrimPrefix(line, goosPrefix), err)
+			}
+			gooses = strings.Fields(text)
+		}
+		if strings.HasPrefix(line, goarchPrefix) {
+			text, err := strconv.Unquote(strings.TrimPrefix(line, goarchPrefix))
+			if err != nil {
+				log.Fatal("parsing goarchList: %v", err)
+			}
+			goarches = strings.Fields(text)
+		}
+	}
+
+	for _, target := range gooses {
+		var buf bytes.Buffer
+		fmt.Fprintf(&buf, "// generated by gengoos.go using 'go generate'\n\n")
+		if target == "linux" {
+			fmt.Fprintf(&buf, "// +build !android\n\n") // must explicitly exclude android for linux
+		}
+		fmt.Fprintf(&buf, "package runtime\n\n")
+		fmt.Fprintf(&buf, "const theGoos = `%s`\n\n", target)
+		for _, goos := range gooses {
+			value := 0
+			if goos == target {
+				value = 1
+			}
+			fmt.Fprintf(&buf, "const goos_%s = %d\n", goos, value)
+		}
+		err := ioutil.WriteFile("zgoos_"+target+".go", buf.Bytes(), 0666)
+		if err != nil {
+			log.Fatal(err)
+		}
+	}
+
+	for _, target := range goarches {
+		var buf bytes.Buffer
+		fmt.Fprintf(&buf, "// generated by gengoos.go using 'go generate'\n\n")
+		fmt.Fprintf(&buf, "package runtime\n\n")
+		fmt.Fprintf(&buf, "const theGoarch = `%s`\n\n", target)
+		for _, goarch := range goarches {
+			value := 0
+			if goarch == target {
+				value = 1
+			}
+			fmt.Fprintf(&buf, "const goarch_%s = %d\n", goarch, value)
+		}
+		err := ioutil.WriteFile("zgoarch_"+target+".go", buf.Bytes(), 0666)
+		if err != nil {
+			log.Fatal(err)
+		}
+	}
+}
diff --git a/src/runtime/go_tls.h b/src/runtime/go_tls.h
new file mode 100644
index 0000000..6a707cf
--- /dev/null
+++ b/src/runtime/go_tls.h
@@ -0,0 +1,22 @@
+// 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.
+
+#ifdef GOARCH_arm
+#define LR R14
+#endif
+
+#ifdef GOARCH_amd64
+#define	get_tls(r)	MOVQ TLS, r
+#define	g(r)	0(r)(TLS*1)
+#endif
+
+#ifdef GOARCH_amd64p32
+#define	get_tls(r)	MOVL TLS, r
+#define	g(r)	0(r)(TLS*1)
+#endif
+
+#ifdef GOARCH_386
+#define	get_tls(r)	MOVL TLS, r
+#define	g(r)	0(r)(TLS*1)
+#endif
diff --git a/src/runtime/hash32.go b/src/runtime/hash32.go
new file mode 100644
index 0000000..79fb15c
--- /dev/null
+++ b/src/runtime/hash32.go
@@ -0,0 +1,89 @@
+// 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.
+
+// Hashing algorithm inspired by
+//   xxhash: https://code.google.com/p/xxhash/
+// cityhash: https://code.google.com/p/cityhash/
+
+// +build 386 arm
+
+package runtime
+
+import "unsafe"
+
+const (
+	// Constants for multiplication: four random odd 32-bit numbers.
+	m1 = 3168982561
+	m2 = 3339683297
+	m3 = 832293441
+	m4 = 2336365089
+)
+
+func memhash(p unsafe.Pointer, seed, s uintptr) uintptr {
+	if GOARCH == "386" && GOOS != "nacl" && useAeshash {
+		return aeshash(p, seed, s)
+	}
+	h := uint32(seed + s*hashkey[0])
+tail:
+	switch {
+	case s == 0:
+	case s < 4:
+		h ^= uint32(*(*byte)(p))
+		h ^= uint32(*(*byte)(add(p, s>>1))) << 8
+		h ^= uint32(*(*byte)(add(p, s-1))) << 16
+		h = rotl_15(h*m1) * m2
+	case s == 4:
+		h ^= readUnaligned32(p)
+		h = rotl_15(h*m1) * m2
+	case s <= 8:
+		h ^= readUnaligned32(p)
+		h = rotl_15(h*m1) * m2
+		h ^= readUnaligned32(add(p, s-4))
+		h = rotl_15(h*m1) * m2
+	case s <= 16:
+		h ^= readUnaligned32(p)
+		h = rotl_15(h*m1) * m2
+		h ^= readUnaligned32(add(p, 4))
+		h = rotl_15(h*m1) * m2
+		h ^= readUnaligned32(add(p, s-8))
+		h = rotl_15(h*m1) * m2
+		h ^= readUnaligned32(add(p, s-4))
+		h = rotl_15(h*m1) * m2
+	default:
+		v1 := h
+		v2 := uint32(hashkey[1])
+		v3 := uint32(hashkey[2])
+		v4 := uint32(hashkey[3])
+		for s >= 16 {
+			v1 ^= readUnaligned32(p)
+			v1 = rotl_15(v1*m1) * m2
+			p = add(p, 4)
+			v2 ^= readUnaligned32(p)
+			v2 = rotl_15(v2*m2) * m3
+			p = add(p, 4)
+			v3 ^= readUnaligned32(p)
+			v3 = rotl_15(v3*m3) * m4
+			p = add(p, 4)
+			v4 ^= readUnaligned32(p)
+			v4 = rotl_15(v4*m4) * m1
+			p = add(p, 4)
+			s -= 16
+		}
+		h = v1 ^ v2 ^ v3 ^ v4
+		goto tail
+	}
+	h ^= h >> 17
+	h *= m3
+	h ^= h >> 13
+	h *= m4
+	h ^= h >> 16
+	return uintptr(h)
+}
+
+// Note: in order to get the compiler to issue rotl instructions, we
+// need to constant fold the shift amount by hand.
+// TODO: convince the compiler to issue rotl instructions after inlining.
+func rotl_15(x uint32) uint32 {
+	return (x << 15) | (x >> (32 - 15))
+}
diff --git a/src/runtime/hash64.go b/src/runtime/hash64.go
new file mode 100644
index 0000000..716db61
--- /dev/null
+++ b/src/runtime/hash64.go
@@ -0,0 +1,89 @@
+// 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.
+
+// Hashing algorithm inspired by
+//   xxhash: https://code.google.com/p/xxhash/
+// cityhash: https://code.google.com/p/cityhash/
+
+// +build amd64 amd64p32 arm64 ppc64 ppc64le
+
+package runtime
+
+import "unsafe"
+
+const (
+	// Constants for multiplication: four random odd 64-bit numbers.
+	m1 = 16877499708836156737
+	m2 = 2820277070424839065
+	m3 = 9497967016996688599
+	m4 = 15839092249703872147
+)
+
+func memhash(p unsafe.Pointer, seed, s uintptr) uintptr {
+	if GOARCH == "amd64" && GOOS != "nacl" && useAeshash {
+		return aeshash(p, seed, s)
+	}
+	h := uint64(seed + s*hashkey[0])
+tail:
+	switch {
+	case s == 0:
+	case s < 4:
+		h ^= uint64(*(*byte)(p))
+		h ^= uint64(*(*byte)(add(p, s>>1))) << 8
+		h ^= uint64(*(*byte)(add(p, s-1))) << 16
+		h = rotl_31(h*m1) * m2
+	case s <= 8:
+		h ^= uint64(readUnaligned32(p))
+		h ^= uint64(readUnaligned32(add(p, s-4))) << 32
+		h = rotl_31(h*m1) * m2
+	case s <= 16:
+		h ^= readUnaligned64(p)
+		h = rotl_31(h*m1) * m2
+		h ^= readUnaligned64(add(p, s-8))
+		h = rotl_31(h*m1) * m2
+	case s <= 32:
+		h ^= readUnaligned64(p)
+		h = rotl_31(h*m1) * m2
+		h ^= readUnaligned64(add(p, 8))
+		h = rotl_31(h*m1) * m2
+		h ^= readUnaligned64(add(p, s-16))
+		h = rotl_31(h*m1) * m2
+		h ^= readUnaligned64(add(p, s-8))
+		h = rotl_31(h*m1) * m2
+	default:
+		v1 := h
+		v2 := uint64(hashkey[1])
+		v3 := uint64(hashkey[2])
+		v4 := uint64(hashkey[3])
+		for s >= 32 {
+			v1 ^= readUnaligned64(p)
+			v1 = rotl_31(v1*m1) * m2
+			p = add(p, 8)
+			v2 ^= readUnaligned64(p)
+			v2 = rotl_31(v2*m2) * m3
+			p = add(p, 8)
+			v3 ^= readUnaligned64(p)
+			v3 = rotl_31(v3*m3) * m4
+			p = add(p, 8)
+			v4 ^= readUnaligned64(p)
+			v4 = rotl_31(v4*m4) * m1
+			p = add(p, 8)
+			s -= 32
+		}
+		h = v1 ^ v2 ^ v3 ^ v4
+		goto tail
+	}
+
+	h ^= h >> 29
+	h *= m3
+	h ^= h >> 32
+	return uintptr(h)
+}
+
+// Note: in order to get the compiler to issue rotl instructions, we
+// need to constant fold the shift amount by hand.
+// TODO: convince the compiler to issue rotl instructions after inlining.
+func rotl_31(x uint64) uint64 {
+	return (x << 31) | (x >> (64 - 31))
+}
diff --git a/src/runtime/hash_test.go b/src/runtime/hash_test.go
index 41fff98..6b229bd 100644
--- a/src/runtime/hash_test.go
+++ b/src/runtime/hash_test.go
@@ -171,9 +171,6 @@ func TestSmhasherCyclic(t *testing.T) {
 	if testing.Short() {
 		t.Skip("Skipping in short mode")
 	}
-	if !HaveGoodHash() {
-		t.Skip("fallback hash not good enough for this test")
-	}
 	r := rand.New(rand.NewSource(1234))
 	const REPEAT = 8
 	const N = 1000000
@@ -235,9 +232,6 @@ func TestSmhasherPermutation(t *testing.T) {
 	if testing.Short() {
 		t.Skip("Skipping in short mode")
 	}
-	if !HaveGoodHash() {
-		t.Skip("fallback hash not good enough for this test")
-	}
 	permutation(t, []uint32{0, 1, 2, 3, 4, 5, 6, 7}, 8)
 	permutation(t, []uint32{0, 1 << 29, 2 << 29, 3 << 29, 4 << 29, 5 << 29, 6 << 29, 7 << 29}, 8)
 	permutation(t, []uint32{0, 1}, 20)
@@ -404,9 +398,6 @@ func (k *IfaceKey) name() string {
 
 // Flipping a single bit of a key should flip each output bit with 50% probability.
 func TestSmhasherAvalanche(t *testing.T) {
-	if !HaveGoodHash() {
-		t.Skip("fallback hash not good enough for this test")
-	}
 	if testing.Short() {
 		t.Skip("Skipping in short mode")
 	}
diff --git a/src/runtime/hashmap.go b/src/runtime/hashmap.go
index 791af8c..917ed21 100644
--- a/src/runtime/hashmap.go
+++ b/src/runtime/hashmap.go
@@ -68,7 +68,7 @@ const (
 	// 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
 
@@ -96,23 +96,31 @@ const (
 
 	// sentinel bucket ID for iterator checks
 	noCheck = 1<<(8*ptrSize) - 1
-
-	// trigger a garbage collection at every alloc called from this code
-	checkgc = false
 )
 
 // 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 uint32
-	hash0 uint32 // hash seed
+	flags uint8
 	B     uint8  // log_2 of # of buckets (can hold up to loadFactor * 2^B items)
+	hash0 uint32 // hash seed
 
 	buckets    unsafe.Pointer // array of 2^B Buckets. may be nil if count==0.
 	oldbuckets unsafe.Pointer // previous bucket array of half the size, non-nil only when growing
 	nevacuate  uintptr        // progress counter for evacuation (buckets less than this have been evacuated)
+
+	// If both key and value do not contain pointers and are inline, then we mark bucket
+	// type as containing no pointers. This avoids scanning such maps.
+	// However, bmap.overflow is a pointer. In order to keep overflow buckets
+	// alive, we store pointers to all overflow buckets in hmap.overflow.
+	// Overflow is used only if key and value do not contain pointers.
+	// overflow[0] contains overflow buckets for hmap.buckets.
+	// overflow[1] contains overflow buckets for hmap.oldbuckets.
+	// The first indirection allows us to reduce static size of hmap.
+	// The second indirection allows to store a pointer to the slice in hiter.
+	overflow *[2]*[]*bmap
 }
 
 // A bucket for a Go map.
@@ -126,15 +134,16 @@ type bmap struct {
 }
 
 // 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
 	bptr        *bmap          // current bucket
+	overflow    [2]*[]*bmap    // keeps overflow buckets alive
 	startBucket uintptr        // bucket iteration started at
 	offset      uint8          // intra-bucket offset to start from during iteration (should be big enough to hold bucketCnt-1)
 	wrapped     bool           // already wrapped around from end of bucket array to beginning
@@ -150,15 +159,35 @@ func evacuated(b *bmap) bool {
 }
 
 func (b *bmap) overflow(t *maptype) *bmap {
-	return *(**bmap)(add(unsafe.Pointer(b), uintptr(t.bucketsize)-regSize))
+	return *(**bmap)(add(unsafe.Pointer(b), uintptr(t.bucketsize)-ptrSize))
+}
+
+func (h *hmap) setoverflow(t *maptype, b, ovf *bmap) {
+	if t.bucket.kind&kindNoPointers != 0 {
+		h.createOverflow()
+		*h.overflow[0] = append(*h.overflow[0], ovf)
+	}
+	*(**bmap)(add(unsafe.Pointer(b), uintptr(t.bucketsize)-ptrSize)) = ovf
 }
-func (b *bmap) setoverflow(t *maptype, ovf *bmap) {
-	*(**bmap)(add(unsafe.Pointer(b), uintptr(t.bucketsize)-regSize)) = ovf
+
+func (h *hmap) createOverflow() {
+	if h.overflow == nil {
+		h.overflow = new([2]*[]*bmap)
+	}
+	if h.overflow[0] == nil {
+		h.overflow[0] = new([]*bmap)
+	}
 }
 
-func makemap(t *maptype, hint int64) *hmap {
+// makemap implements a Go map creation make(map[k]v, hint)
+// If the compiler has determined that the map or the first bucket
+// can be created on the stack, h and/or bucket may be non-nil.
+// If h != nil, the map can be created directly in h.
+// If bucket != nil, bucket can be used as the first bucket.
+func makemap(t *maptype, hint int64, h *hmap, bucket unsafe.Pointer) *hmap {
 	if sz := unsafe.Sizeof(hmap{}); sz > 48 || sz != uintptr(t.hmap.size) {
-		gothrow("bad hmap size")
+		println("runtime: sizeof(hmap) =", sz, ", t.hmap.size =", t.hmap.size)
+		throw("bad hmap size")
 	}
 
 	if hint < 0 || int64(int32(hint)) != hint {
@@ -167,43 +196,46 @@ func makemap(t *maptype, hint int64) *hmap {
 	}
 
 	if !ismapkey(t.key) {
-		gothrow("runtime.makemap: unsupported map key type")
+		throw("runtime.makemap: unsupported map key type")
 	}
 
 	// check compiler's and reflect's math
 	if t.key.size > maxKeySize && (!t.indirectkey || t.keysize != uint8(ptrSize)) ||
 		t.key.size <= maxKeySize && (t.indirectkey || t.keysize != uint8(t.key.size)) {
-		gothrow("key size wrong")
+		throw("key size wrong")
 	}
 	if t.elem.size > maxValueSize && (!t.indirectvalue || t.valuesize != uint8(ptrSize)) ||
 		t.elem.size <= maxValueSize && (t.indirectvalue || t.valuesize != uint8(t.elem.size)) {
-		gothrow("value size wrong")
+		throw("value size wrong")
 	}
 
 	// invariants we depend on.  We should probably check these at compile time
 	// somewhere, but for now we'll do it here.
 	if t.key.align > bucketCnt {
-		gothrow("key align too big")
+		throw("key align too big")
 	}
 	if t.elem.align > bucketCnt {
-		gothrow("value align too big")
+		throw("value align too big")
 	}
 	if uintptr(t.key.size)%uintptr(t.key.align) != 0 {
-		gothrow("key size not a multiple of key align")
+		throw("key size not a multiple of key align")
 	}
 	if uintptr(t.elem.size)%uintptr(t.elem.align) != 0 {
-		gothrow("value size not a multiple of value align")
+		throw("value size not a multiple of value align")
 	}
 	if bucketCnt < 8 {
-		gothrow("bucketsize too small for proper alignment")
+		throw("bucketsize too small for proper alignment")
 	}
 	if dataOffset%uintptr(t.key.align) != 0 {
-		gothrow("need padding in bucket (key)")
+		throw("need padding in bucket (key)")
 	}
 	if dataOffset%uintptr(t.elem.align) != 0 {
-		gothrow("need padding in bucket (value)")
+		throw("need padding in bucket (value)")
 	}
 
+	// make sure zero of element type is available.
+	mapzero(t.elem)
+
 	// find size parameter which will hold the requested # of elements
 	B := uint8(0)
 	for ; hint > bucketCnt && float32(hint) > loadFactor*float32(uintptr(1)<<B); B++ {
@@ -212,19 +244,15 @@ func makemap(t *maptype, hint int64) *hmap {
 	// allocate initial hash table
 	// if B == 0, the buckets field is allocated lazily later (in mapassign)
 	// If hint is large zeroing this memory could take a while.
-	var buckets unsafe.Pointer
+	buckets := bucket
 	if B != 0 {
-		if checkgc {
-			memstats.next_gc = memstats.heap_alloc
-		}
 		buckets = newarray(t.bucket, uintptr(1)<<B)
 	}
 
 	// initialize Hmap
-	if checkgc {
-		memstats.next_gc = memstats.heap_alloc
+	if h == nil {
+		h = (*hmap)(newobject(t.hmap))
 	}
-	h := (*hmap)(newobject(t.hmap))
 	h.count = 0
 	h.B = B
 	h.flags = 0
@@ -251,8 +279,8 @@ func mapaccess1(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {
 	if h == nil || h.count == 0 {
 		return unsafe.Pointer(t.elem.zero)
 	}
-	alg := goalg(t.key.alg)
-	hash := alg.hash(key, uintptr(t.key.size), uintptr(h.hash0))
+	alg := t.key.alg
+	hash := alg.hash(key, uintptr(h.hash0))
 	m := uintptr(1)<<h.B - 1
 	b := (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
 	if c := h.oldbuckets; c != nil {
@@ -274,7 +302,7 @@ func mapaccess1(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {
 			if t.indirectkey {
 				k = *((*unsafe.Pointer)(k))
 			}
-			if alg.equal(key, k, uintptr(t.key.size)) {
+			if alg.equal(key, k) {
 				v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize))
 				if t.indirectvalue {
 					v = *((*unsafe.Pointer)(v))
@@ -299,8 +327,8 @@ func mapaccess2(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, bool)
 	if h == nil || h.count == 0 {
 		return unsafe.Pointer(t.elem.zero), false
 	}
-	alg := goalg(t.key.alg)
-	hash := alg.hash(key, uintptr(t.key.size), uintptr(h.hash0))
+	alg := t.key.alg
+	hash := alg.hash(key, uintptr(h.hash0))
 	m := uintptr(1)<<h.B - 1
 	b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + (hash&m)*uintptr(t.bucketsize)))
 	if c := h.oldbuckets; c != nil {
@@ -322,7 +350,7 @@ func mapaccess2(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, bool)
 			if t.indirectkey {
 				k = *((*unsafe.Pointer)(k))
 			}
-			if alg.equal(key, k, uintptr(t.key.size)) {
+			if alg.equal(key, k) {
 				v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize))
 				if t.indirectvalue {
 					v = *((*unsafe.Pointer)(v))
@@ -342,8 +370,8 @@ func mapaccessK(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, unsafe
 	if h == nil || h.count == 0 {
 		return nil, nil
 	}
-	alg := goalg(t.key.alg)
-	hash := alg.hash(key, uintptr(t.key.size), uintptr(h.hash0))
+	alg := t.key.alg
+	hash := alg.hash(key, uintptr(h.hash0))
 	m := uintptr(1)<<h.B - 1
 	b := (*bmap)(unsafe.Pointer(uintptr(h.buckets) + (hash&m)*uintptr(t.bucketsize)))
 	if c := h.oldbuckets; c != nil {
@@ -365,7 +393,7 @@ func mapaccessK(t *maptype, h *hmap, key unsafe.Pointer) (unsafe.Pointer, unsafe
 			if t.indirectkey {
 				k = *((*unsafe.Pointer)(k))
 			}
-			if alg.equal(key, k, uintptr(t.key.size)) {
+			if alg.equal(key, k) {
 				v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize))
 				if t.indirectvalue {
 					v = *((*unsafe.Pointer)(v))
@@ -392,13 +420,10 @@ func mapassign1(t *maptype, h *hmap, key unsafe.Pointer, val unsafe.Pointer) {
 		raceReadObjectPC(t.elem, val, callerpc, pc)
 	}
 
-	alg := goalg(t.key.alg)
-	hash := alg.hash(key, uintptr(t.key.size), uintptr(h.hash0))
+	alg := t.key.alg
+	hash := alg.hash(key, uintptr(h.hash0))
 
 	if h.buckets == nil {
-		if checkgc {
-			memstats.next_gc = memstats.heap_alloc
-		}
 		h.buckets = newarray(t.bucket, 1)
 	}
 
@@ -431,17 +456,17 @@ again:
 			if t.indirectkey {
 				k2 = *((*unsafe.Pointer)(k2))
 			}
-			if !alg.equal(key, k2, uintptr(t.key.size)) {
+			if !alg.equal(key, k2) {
 				continue
 			}
 			// already have a mapping for key.  Update it.
-			memmove(k2, key, uintptr(t.key.size))
+			typedmemmove(t.key, k2, key)
 			v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize))
 			v2 := v
 			if t.indirectvalue {
 				v2 = *((*unsafe.Pointer)(v2))
 			}
-			memmove(v2, val, uintptr(t.elem.size))
+			typedmemmove(t.elem, v2, val)
 			return
 		}
 		ovf := b.overflow(t)
@@ -459,11 +484,8 @@ again:
 
 	if inserti == nil {
 		// all current buckets are full, allocate a new one.
-		if checkgc {
-			memstats.next_gc = memstats.heap_alloc
-		}
 		newb := (*bmap)(newobject(t.bucket))
-		b.setoverflow(t, newb)
+		h.setoverflow(t, b, newb)
 		inserti = &newb.tophash[0]
 		insertk = add(unsafe.Pointer(newb), dataOffset)
 		insertv = add(insertk, bucketCnt*uintptr(t.keysize))
@@ -471,23 +493,17 @@ again:
 
 	// store new key/value at insert position
 	if t.indirectkey {
-		if checkgc {
-			memstats.next_gc = memstats.heap_alloc
-		}
 		kmem := newobject(t.key)
 		*(*unsafe.Pointer)(insertk) = kmem
 		insertk = kmem
 	}
 	if t.indirectvalue {
-		if checkgc {
-			memstats.next_gc = memstats.heap_alloc
-		}
 		vmem := newobject(t.elem)
 		*(*unsafe.Pointer)(insertv) = vmem
 		insertv = vmem
 	}
-	memmove(insertk, key, uintptr(t.key.size))
-	memmove(insertv, val, uintptr(t.elem.size))
+	typedmemmove(t.key, insertk, key)
+	typedmemmove(t.elem, insertv, val)
 	*inserti = top
 	h.count++
 }
@@ -502,8 +518,8 @@ func mapdelete(t *maptype, h *hmap, key unsafe.Pointer) {
 	if h == nil || h.count == 0 {
 		return
 	}
-	alg := goalg(t.key.alg)
-	hash := alg.hash(key, uintptr(t.key.size), uintptr(h.hash0))
+	alg := t.key.alg
+	hash := alg.hash(key, uintptr(h.hash0))
 	bucket := hash & (uintptr(1)<<h.B - 1)
 	if h.oldbuckets != nil {
 		growWork(t, h, bucket)
@@ -523,7 +539,7 @@ func mapdelete(t *maptype, h *hmap, key unsafe.Pointer) {
 			if t.indirectkey {
 				k2 = *((*unsafe.Pointer)(k2))
 			}
-			if !alg.equal(key, k2, uintptr(t.key.size)) {
+			if !alg.equal(key, k2) {
 				continue
 			}
 			memclr(k, uintptr(t.keysize))
@@ -548,6 +564,8 @@ func mapiterinit(t *maptype, h *hmap, it *hiter) {
 	it.h = nil
 	it.buckets = nil
 	it.bptr = nil
+	it.overflow[0] = nil
+	it.overflow[1] = nil
 
 	if raceenabled && h != nil {
 		callerpc := getcallerpc(unsafe.Pointer(&t))
@@ -560,8 +578,8 @@ func mapiterinit(t *maptype, h *hmap, it *hiter) {
 		return
 	}
 
-	if unsafe.Sizeof(hiter{})/ptrSize != 10 {
-		gothrow("hash_iter size incorrect") // see ../../cmd/gc/reflect.c
+	if unsafe.Sizeof(hiter{})/ptrSize != 12 {
+		throw("hash_iter size incorrect") // see ../../cmd/internal/gc/reflect.go
 	}
 	it.t = t
 	it.h = h
@@ -569,6 +587,14 @@ func mapiterinit(t *maptype, h *hmap, it *hiter) {
 	// grab snapshot of bucket state
 	it.B = h.B
 	it.buckets = h.buckets
+	if t.bucket.kind&kindNoPointers != 0 {
+		// Allocate the current slice and remember pointers to both current and old.
+		// This preserves all relevant overflow buckets alive even if
+		// the table grows and/or overflow buckets are added to the table
+		// while we are iterating.
+		h.createOverflow()
+		it.overflow = *h.overflow
+	}
 
 	// decide where to start
 	r := uintptr(fastrand1())
@@ -585,14 +611,8 @@ func mapiterinit(t *maptype, h *hmap, it *hiter) {
 
 	// Remember we have an iterator.
 	// Can run concurrently with another hash_iter_init().
-	for {
-		old := h.flags
-		if old == old|iterator|oldIterator {
-			break
-		}
-		if cas(&h.flags, old, old|iterator|oldIterator) {
-			break
-		}
+	if old := h.flags; old&(iterator|oldIterator) != iterator|oldIterator {
+		atomicor8(&h.flags, iterator|oldIterator)
 	}
 
 	mapiternext(it)
@@ -609,7 +629,7 @@ func mapiternext(it *hiter) {
 	b := it.bptr
 	i := it.i
 	checkBucket := it.checkBucket
-	alg := goalg(t.key.alg)
+	alg := t.key.alg
 
 next:
 	if b == nil {
@@ -660,10 +680,10 @@ next:
 				if t.indirectkey {
 					k2 = *((*unsafe.Pointer)(k2))
 				}
-				if alg.equal(k2, k2, uintptr(t.key.size)) {
+				if t.reflexivekey || alg.equal(k2, k2) {
 					// If the item in the oldbucket is not destined for
 					// the current new bucket in the iteration, skip it.
-					hash := alg.hash(k2, uintptr(t.key.size), uintptr(h.hash0))
+					hash := alg.hash(k2, uintptr(h.hash0))
 					if hash&(uintptr(1)<<it.B-1) != checkBucket {
 						continue
 					}
@@ -697,7 +717,7 @@ next:
 				if t.indirectkey {
 					k2 = *((*unsafe.Pointer)(k2))
 				}
-				if alg.equal(k2, k2, uintptr(t.key.size)) {
+				if t.reflexivekey || alg.equal(k2, k2) {
 					// Check the current hash table for the data.
 					// This code handles the case where the key
 					// has been deleted, updated, or deleted and reinserted.
@@ -735,12 +755,9 @@ next:
 
 func hashGrow(t *maptype, h *hmap) {
 	if h.oldbuckets != nil {
-		gothrow("evacuation not done in time")
+		throw("evacuation not done in time")
 	}
 	oldbuckets := h.buckets
-	if checkgc {
-		memstats.next_gc = memstats.heap_alloc
-	}
 	newbuckets := newarray(t.bucket, uintptr(1)<<(h.B+1))
 	flags := h.flags &^ (iterator | oldIterator)
 	if h.flags&iterator != 0 {
@@ -753,6 +770,15 @@ func hashGrow(t *maptype, h *hmap) {
 	h.buckets = newbuckets
 	h.nevacuate = 0
 
+	if h.overflow != nil {
+		// Promote current overflow buckets to the old generation.
+		if h.overflow[1] != nil {
+			throw("overflow is not nil")
+		}
+		h.overflow[1] = h.overflow[0]
+		h.overflow[0] = nil
+	}
+
 	// the actual copying of the hash table data is done incrementally
 	// by growWork() and evacuate().
 }
@@ -773,7 +799,7 @@ func growWork(t *maptype, h *hmap, bucket uintptr) {
 func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
 	b := (*bmap)(add(h.oldbuckets, oldbucket*uintptr(t.bucketsize)))
 	newbit := uintptr(1) << (h.B - 1)
-	alg := goalg(t.key.alg)
+	alg := t.key.alg
 	if !evacuated(b) {
 		// TODO: reuse overflow buckets instead of using new ones, if there
 		// is no iterator using the old buckets.  (If !oldIterator.)
@@ -796,7 +822,7 @@ func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
 					continue
 				}
 				if top < minTopHash {
-					gothrow("bad map state")
+					throw("bad map state")
 				}
 				k2 := k
 				if t.indirectkey {
@@ -804,9 +830,9 @@ func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
 				}
 				// Compute hash to make our evacuation decision (whether we need
 				// to send this key/value to bucket x or bucket y).
-				hash := alg.hash(k2, uintptr(t.key.size), uintptr(h.hash0))
+				hash := alg.hash(k2, uintptr(h.hash0))
 				if h.flags&iterator != 0 {
-					if !alg.equal(k2, k2, uintptr(t.key.size)) {
+					if !t.reflexivekey && !alg.equal(k2, k2) {
 						// If key != key (NaNs), then the hash could be (and probably
 						// will be) entirely different from the old hash.  Moreover,
 						// it isn't reproducible.  Reproducibility is required in the
@@ -832,11 +858,8 @@ func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
 				if (hash & newbit) == 0 {
 					b.tophash[i] = evacuatedX
 					if xi == bucketCnt {
-						if checkgc {
-							memstats.next_gc = memstats.heap_alloc
-						}
 						newx := (*bmap)(newobject(t.bucket))
-						x.setoverflow(t, newx)
+						h.setoverflow(t, x, newx)
 						x = newx
 						xi = 0
 						xk = add(unsafe.Pointer(x), dataOffset)
@@ -846,12 +869,12 @@ func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
 					if t.indirectkey {
 						*(*unsafe.Pointer)(xk) = k2 // copy pointer
 					} else {
-						memmove(xk, k, uintptr(t.key.size)) // copy value
+						typedmemmove(t.key, xk, k) // copy value
 					}
 					if t.indirectvalue {
 						*(*unsafe.Pointer)(xv) = *(*unsafe.Pointer)(v)
 					} else {
-						memmove(xv, v, uintptr(t.elem.size))
+						typedmemmove(t.elem, xv, v)
 					}
 					xi++
 					xk = add(xk, uintptr(t.keysize))
@@ -859,11 +882,8 @@ func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
 				} else {
 					b.tophash[i] = evacuatedY
 					if yi == bucketCnt {
-						if checkgc {
-							memstats.next_gc = memstats.heap_alloc
-						}
 						newy := (*bmap)(newobject(t.bucket))
-						y.setoverflow(t, newy)
+						h.setoverflow(t, y, newy)
 						y = newy
 						yi = 0
 						yk = add(unsafe.Pointer(y), dataOffset)
@@ -873,12 +893,12 @@ func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
 					if t.indirectkey {
 						*(*unsafe.Pointer)(yk) = k2
 					} else {
-						memmove(yk, k, uintptr(t.key.size))
+						typedmemmove(t.key, yk, k)
 					}
 					if t.indirectvalue {
 						*(*unsafe.Pointer)(yv) = *(*unsafe.Pointer)(v)
 					} else {
-						memmove(yv, v, uintptr(t.elem.size))
+						typedmemmove(t.elem, yv, v)
 					}
 					yi++
 					yk = add(yk, uintptr(t.keysize))
@@ -899,20 +919,28 @@ func evacuate(t *maptype, h *hmap, oldbucket uintptr) {
 		if oldbucket+1 == newbit { // newbit == # of oldbuckets
 			// Growing is all done.  Free old main bucket array.
 			h.oldbuckets = nil
+			// Can discard old overflow buckets as well.
+			// If they are still referenced by an iterator,
+			// then the iterator holds a pointers to the slice.
+			if h.overflow != nil {
+				h.overflow[1] = nil
+			}
 		}
 	}
 }
 
 func ismapkey(t *_type) bool {
-	return goalg(t.alg).hash != nil
+	return t.alg.hash != nil
 }
 
 // Reflect stubs.  Called from ../reflect/asm_*.s
 
+//go:linkname reflect_makemap reflect.makemap
 func reflect_makemap(t *maptype) *hmap {
-	return makemap(t, 0)
+	return makemap(t, 0, nil, nil)
 }
 
+//go:linkname reflect_mapaccess reflect.mapaccess
 func reflect_mapaccess(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {
 	val, ok := mapaccess2(t, h, key)
 	if !ok {
@@ -922,28 +950,34 @@ func reflect_mapaccess(t *maptype, h *hmap, key unsafe.Pointer) unsafe.Pointer {
 	return val
 }
 
+//go:linkname reflect_mapassign reflect.mapassign
 func reflect_mapassign(t *maptype, h *hmap, key unsafe.Pointer, val unsafe.Pointer) {
 	mapassign1(t, h, key, val)
 }
 
+//go:linkname reflect_mapdelete reflect.mapdelete
 func reflect_mapdelete(t *maptype, h *hmap, key unsafe.Pointer) {
 	mapdelete(t, h, key)
 }
 
+//go:linkname reflect_mapiterinit reflect.mapiterinit
 func reflect_mapiterinit(t *maptype, h *hmap) *hiter {
 	it := new(hiter)
 	mapiterinit(t, h, it)
 	return it
 }
 
+//go:linkname reflect_mapiternext reflect.mapiternext
 func reflect_mapiternext(it *hiter) {
 	mapiternext(it)
 }
 
+//go:linkname reflect_mapiterkey reflect.mapiterkey
 func reflect_mapiterkey(it *hiter) unsafe.Pointer {
 	return it.key
 }
 
+//go:linkname reflect_maplen reflect.maplen
 func reflect_maplen(h *hmap) int {
 	if h == nil {
 		return 0
@@ -955,6 +989,64 @@ func reflect_maplen(h *hmap) int {
 	return h.count
 }
 
+//go:linkname reflect_ismapkey reflect.ismapkey
 func reflect_ismapkey(t *_type) bool {
 	return ismapkey(t)
 }
+
+var zerobuf struct {
+	lock mutex
+	p    *byte
+	size uintptr
+}
+
+var zerotiny [1024]byte
+
+// mapzero ensures that t.zero points at a zero value for type t.
+// Types known to the compiler are in read-only memory and all point
+// to a single zero in the bss of a large enough size.
+// Types allocated by package reflect are in writable memory and
+// start out with zero set to nil; we initialize those on demand.
+func mapzero(t *_type) {
+	// On ARM, atomicloadp is implemented as xadd(p, 0),
+	// so we cannot use atomicloadp on read-only memory.
+	// Check whether the pointer is in the heap; if not, it's not writable
+	// so the zero value must already be set.
+	if GOARCH == "arm" && !inheap(uintptr(unsafe.Pointer(t))) {
+		if t.zero == nil {
+			print("runtime: map element ", *t._string, " missing zero value\n")
+			throw("mapzero")
+		}
+		return
+	}
+
+	// Already done?
+	// Check without lock, so must use atomicload to sync with atomicstore in allocation case below.
+	if atomicloadp(unsafe.Pointer(&t.zero)) != nil {
+		return
+	}
+
+	// Small enough for static buffer?
+	if t.size <= uintptr(len(zerotiny)) {
+		atomicstorep(unsafe.Pointer(&t.zero), unsafe.Pointer(&zerotiny[0]))
+		return
+	}
+
+	// Use allocated buffer.
+	lock(&zerobuf.lock)
+	if zerobuf.size < t.size {
+		if zerobuf.size == 0 {
+			zerobuf.size = 4 * 1024
+		}
+		for zerobuf.size < t.size {
+			zerobuf.size *= 2
+			if zerobuf.size == 0 {
+				// need >2GB zero on 32-bit machine
+				throw("map element too large")
+			}
+		}
+		zerobuf.p = (*byte)(persistentalloc(zerobuf.size, 64, &memstats.other_sys))
+	}
+	atomicstorep(unsafe.Pointer(&t.zero), unsafe.Pointer(zerobuf.p))
+	unlock(&zerobuf.lock)
+}
diff --git a/src/runtime/hashmap_fast.go b/src/runtime/hashmap_fast.go
index afa6ecc..02c51a2 100644
--- a/src/runtime/hashmap_fast.go
+++ b/src/runtime/hashmap_fast.go
@@ -21,7 +21,7 @@ func mapaccess1_fast32(t *maptype, h *hmap, key uint32) unsafe.Pointer {
 		// One-bucket table.  No need to hash.
 		b = (*bmap)(h.buckets)
 	} else {
-		hash := goalg(t.key.alg).hash(noescape(unsafe.Pointer(&key)), 4, uintptr(h.hash0))
+		hash := t.key.alg.hash(noescape(unsafe.Pointer(&key)), uintptr(h.hash0))
 		m := uintptr(1)<<h.B - 1
 		b = (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
 		if c := h.oldbuckets; c != nil {
@@ -63,7 +63,7 @@ func mapaccess2_fast32(t *maptype, h *hmap, key uint32) (unsafe.Pointer, bool) {
 		// One-bucket table.  No need to hash.
 		b = (*bmap)(h.buckets)
 	} else {
-		hash := goalg(t.key.alg).hash(noescape(unsafe.Pointer(&key)), 4, uintptr(h.hash0))
+		hash := t.key.alg.hash(noescape(unsafe.Pointer(&key)), uintptr(h.hash0))
 		m := uintptr(1)<<h.B - 1
 		b = (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
 		if c := h.oldbuckets; c != nil {
@@ -105,7 +105,7 @@ func mapaccess1_fast64(t *maptype, h *hmap, key uint64) unsafe.Pointer {
 		// One-bucket table.  No need to hash.
 		b = (*bmap)(h.buckets)
 	} else {
-		hash := goalg(t.key.alg).hash(noescape(unsafe.Pointer(&key)), 8, uintptr(h.hash0))
+		hash := t.key.alg.hash(noescape(unsafe.Pointer(&key)), uintptr(h.hash0))
 		m := uintptr(1)<<h.B - 1
 		b = (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
 		if c := h.oldbuckets; c != nil {
@@ -147,7 +147,7 @@ func mapaccess2_fast64(t *maptype, h *hmap, key uint64) (unsafe.Pointer, bool) {
 		// One-bucket table.  No need to hash.
 		b = (*bmap)(h.buckets)
 	} else {
-		hash := goalg(t.key.alg).hash(noescape(unsafe.Pointer(&key)), 8, uintptr(h.hash0))
+		hash := t.key.alg.hash(noescape(unsafe.Pointer(&key)), uintptr(h.hash0))
 		m := uintptr(1)<<h.B - 1
 		b = (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
 		if c := h.oldbuckets; c != nil {
@@ -244,7 +244,7 @@ func mapaccess1_faststr(t *maptype, h *hmap, ky string) unsafe.Pointer {
 		return unsafe.Pointer(t.elem.zero)
 	}
 dohash:
-	hash := goalg(t.key.alg).hash(noescape(unsafe.Pointer(&ky)), 2*ptrSize, uintptr(h.hash0))
+	hash := t.key.alg.hash(noescape(unsafe.Pointer(&ky)), uintptr(h.hash0))
 	m := uintptr(1)<<h.B - 1
 	b := (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
 	if c := h.oldbuckets; c != nil {
@@ -344,7 +344,7 @@ func mapaccess2_faststr(t *maptype, h *hmap, ky string) (unsafe.Pointer, bool) {
 		return unsafe.Pointer(t.elem.zero), false
 	}
 dohash:
-	hash := goalg(t.key.alg).hash(noescape(unsafe.Pointer(&ky)), 2*ptrSize, uintptr(h.hash0))
+	hash := t.key.alg.hash(noescape(unsafe.Pointer(&ky)), uintptr(h.hash0))
 	m := uintptr(1)<<h.B - 1
 	b := (*bmap)(add(h.buckets, (hash&m)*uintptr(t.bucketsize)))
 	if c := h.oldbuckets; c != nil {
diff --git a/src/runtime/heapdump.c b/src/runtime/heapdump.c
deleted file mode 100644
index 7eba8c0..0000000
--- a/src/runtime/heapdump.c
+++ /dev/null
@@ -1,864 +0,0 @@
-// 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.
-
-// Implementation of runtime/debug.WriteHeapDump.  Writes all
-// objects in the heap plus additional info (roots, threads,
-// finalizers, etc.) to a file.
-
-// The format of the dumped file is described at
-// http://golang.org/s/go14heapdump.
-
-#include "runtime.h"
-#include "arch_GOARCH.h"
-#include "malloc.h"
-#include "mgc0.h"
-#include "type.h"
-#include "typekind.h"
-#include "funcdata.h"
-#include "zaexperiment.h"
-#include "textflag.h"
-
-extern byte runtime·data[];
-extern byte runtime·edata[];
-extern byte runtime·bss[];
-extern byte runtime·ebss[];
-
-enum {
-	FieldKindEol = 0,
-	FieldKindPtr = 1,
-	FieldKindIface = 2,
-	FieldKindEface = 3,
-
-	TagEOF = 0,
-	TagObject = 1,
-	TagOtherRoot = 2,
-	TagType = 3,
-	TagGoRoutine = 4,
-	TagStackFrame = 5,
-	TagParams = 6,
-	TagFinalizer = 7,
-	TagItab = 8,
-	TagOSThread = 9,
-	TagMemStats = 10,
-	TagQueuedFinalizer = 11,
-	TagData = 12,
-	TagBss = 13,
-	TagDefer = 14,
-	TagPanic = 15,
-	TagMemProf = 16,
-	TagAllocSample = 17,
-};
-
-static uintptr* playgcprog(uintptr offset, uintptr *prog, void (*callback)(void*,uintptr,uintptr), void *arg);
-static void dumpfields(BitVector bv);
-static void dumpbvtypes(BitVector *bv, byte *base);
-static BitVector makeheapobjbv(byte *p, uintptr size);
-
-// fd to write the dump to.
-static uintptr	dumpfd;
-
-#pragma dataflag NOPTR /* tmpbuf not a heap pointer at least */
-static byte	*tmpbuf;
-static uintptr	tmpbufsize;
-
-// buffer of pending write data
-enum {
-	BufSize = 4096,
-};
-#pragma dataflag NOPTR
-static byte buf[BufSize];
-static uintptr nbuf;
-
-static void
-write(byte *data, uintptr len)
-{
-	if(len + nbuf <= BufSize) {
-		runtime·memmove(buf + nbuf, data, len);
-		nbuf += len;
-		return;
-	}
-	runtime·write(dumpfd, buf, nbuf);
-	if(len >= BufSize) {
-		runtime·write(dumpfd, data, len);
-		nbuf = 0;
-	} else {
-		runtime·memmove(buf, data, len);
-		nbuf = len;
-	}
-}
-
-static void
-flush(void)
-{
-	runtime·write(dumpfd, buf, nbuf);
-	nbuf = 0;
-}
-
-// Cache of types that have been serialized already.
-// We use a type's hash field to pick a bucket.
-// Inside a bucket, we keep a list of types that
-// have been serialized so far, most recently used first.
-// Note: when a bucket overflows we may end up
-// serializing a type more than once.  That's ok.
-enum {
-	TypeCacheBuckets = 256, // must be a power of 2
-	TypeCacheAssoc = 4,
-};
-typedef struct TypeCacheBucket TypeCacheBucket;
-struct TypeCacheBucket {
-	Type *t[TypeCacheAssoc];
-};
-#pragma dataflag NOPTR /* only initialized and used while world is stopped */
-static TypeCacheBucket typecache[TypeCacheBuckets];
-
-// dump a uint64 in a varint format parseable by encoding/binary
-static void
-dumpint(uint64 v)
-{
-	byte buf[10];
-	int32 n;
-	n = 0;
-	while(v >= 0x80) {
-		buf[n++] = v | 0x80;
-		v >>= 7;
-	}
-	buf[n++] = v;
-	write(buf, n);
-}
-
-static void
-dumpbool(bool b)
-{
-	dumpint(b ? 1 : 0);
-}
-
-// dump varint uint64 length followed by memory contents
-static void
-dumpmemrange(byte *data, uintptr len)
-{
-	dumpint(len);
-	write(data, len);
-}
-
-static void
-dumpstr(String s)
-{
-	dumpmemrange(s.str, s.len);
-}
-
-static void
-dumpcstr(int8 *c)
-{
-	dumpmemrange((byte*)c, runtime·findnull((byte*)c));
-}
-
-// dump information for a type
-static void
-dumptype(Type *t)
-{
-	TypeCacheBucket *b;
-	int32 i, j;
-
-	if(t == nil) {
-		return;
-	}
-
-	// If we've definitely serialized the type before,
-	// no need to do it again.
-	b = &typecache[t->hash & (TypeCacheBuckets-1)];
-	if(t == b->t[0]) return;
-	for(i = 1; i < TypeCacheAssoc; i++) {
-		if(t == b->t[i]) {
-			// Move-to-front
-			for(j = i; j > 0; j--) {
-				b->t[j] = b->t[j-1];
-			}
-			b->t[0] = t;
-			return;
-		}
-	}
-	// Might not have been dumped yet.  Dump it and
-	// remember we did so.
-	for(j = TypeCacheAssoc-1; j > 0; j--) {
-		b->t[j] = b->t[j-1];
-	}
-	b->t[0] = t;
-	
-	// dump the type
-	dumpint(TagType);
-	dumpint((uintptr)t);
-	dumpint(t->size);
-	if(t->x == nil || t->x->pkgPath == nil || t->x->name == nil) {
-		dumpstr(*t->string);
-	} else {
-		dumpint(t->x->pkgPath->len + 1 + t->x->name->len);
-		write(t->x->pkgPath->str, t->x->pkgPath->len);
-		write((byte*)".", 1);
-		write(t->x->name->str, t->x->name->len);
-	}
-	dumpbool((t->kind & KindDirectIface) == 0 || (t->kind & KindNoPointers) == 0);
-}
-
-// dump an object
-static void
-dumpobj(byte *obj, uintptr size, BitVector bv)
-{
-	dumpbvtypes(&bv, obj);
-	dumpint(TagObject);
-	dumpint((uintptr)obj);
-	dumpmemrange(obj, size);
-	dumpfields(bv);
-}
-
-static void
-dumpotherroot(int8 *description, byte *to)
-{
-	dumpint(TagOtherRoot);
-	dumpcstr(description);
-	dumpint((uintptr)to);
-}
-
-static void
-dumpfinalizer(byte *obj, FuncVal *fn, Type* fint, PtrType *ot)
-{
-	dumpint(TagFinalizer);
-	dumpint((uintptr)obj);
-	dumpint((uintptr)fn);
-	dumpint((uintptr)fn->fn);
-	dumpint((uintptr)fint);
-	dumpint((uintptr)ot);
-}
-
-typedef struct ChildInfo ChildInfo;
-struct ChildInfo {
-	// Information passed up from the callee frame about
-	// the layout of the outargs region.
-	uintptr argoff;     // where the arguments start in the frame
-	uintptr arglen;     // size of args region
-	BitVector args;    // if args.n >= 0, pointer map of args region
-
-	byte *sp;           // callee sp
-	uintptr depth;      // depth in call stack (0 == most recent)
-};
-
-// dump kinds & offsets of interesting fields in bv
-static void
-dumpbv(BitVector *bv, uintptr offset)
-{
-	uintptr i;
-
-	for(i = 0; i < bv->n; i += BitsPerPointer) {
-		switch(bv->bytedata[i/8] >> i%8 & 3) {
-		case BitsDead:
-			// BitsDead has already been processed in makeheapobjbv.
-			// We should only see it in stack maps, in which case we should continue processing.
-			break;
-		case BitsScalar:
-			break;
-		case BitsPointer:
-			dumpint(FieldKindPtr);
-			dumpint(offset + i / BitsPerPointer * PtrSize);
-			break;
-		case BitsMultiWord:
-			switch(bv->bytedata[(i+BitsPerPointer)/8] >> (i+BitsPerPointer)%8 & 3) {
-			default:
-				runtime·throw("unexpected garbage collection bits");
-			case BitsIface:
-				dumpint(FieldKindIface);
-				dumpint(offset + i / BitsPerPointer * PtrSize);
-				i += BitsPerPointer;
-				break;
-			case BitsEface:
-				dumpint(FieldKindEface);
-				dumpint(offset + i / BitsPerPointer * PtrSize);
-				i += BitsPerPointer;
-				break;
-			}
-		}
-	}
-}
-
-static bool
-dumpframe(Stkframe *s, void *arg)
-{
-	Func *f;
-	ChildInfo *child;
-	uintptr pc, off, size;
-	int32 pcdata;
-	StackMap *stackmap;
-	int8 *name;
-	BitVector bv;
-
-	child = (ChildInfo*)arg;
-	f = s->fn;
-
-	// Figure out what we can about our stack map
-	pc = s->pc;
-	if(pc != f->entry)
-		pc--;
-	pcdata = runtime·pcdatavalue(f, PCDATA_StackMapIndex, pc);
-	if(pcdata == -1) {
-		// We do not have a valid pcdata value but there might be a
-		// stackmap for this function.  It is likely that we are looking
-		// at the function prologue, assume so and hope for the best.
-		pcdata = 0;
-	}
-	stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps);
-
-	// Dump any types we will need to resolve Efaces.
-	if(child->args.n >= 0)
-		dumpbvtypes(&child->args, (byte*)s->sp + child->argoff);
-	if(stackmap != nil && stackmap->n > 0) {
-		bv = runtime·stackmapdata(stackmap, pcdata);
-		dumpbvtypes(&bv, (byte*)(s->varp - bv.n / BitsPerPointer * PtrSize));
-	} else {
-		bv.n = -1;
-	}
-
-	// Dump main body of stack frame.
-	dumpint(TagStackFrame);
-	dumpint(s->sp); // lowest address in frame
-	dumpint(child->depth); // # of frames deep on the stack
-	dumpint((uintptr)child->sp); // sp of child, or 0 if bottom of stack
-	dumpmemrange((byte*)s->sp, s->fp - s->sp);  // frame contents
-	dumpint(f->entry);
-	dumpint(s->pc);
-	dumpint(s->continpc);
-	name = runtime·funcname(f);
-	if(name == nil)
-		name = "unknown function";
-	dumpcstr(name);
-
-	// Dump fields in the outargs section
-	if(child->args.n >= 0) {
-		dumpbv(&child->args, child->argoff);
-	} else {
-		// conservative - everything might be a pointer
-		for(off = child->argoff; off < child->argoff + child->arglen; off += PtrSize) {
-			dumpint(FieldKindPtr);
-			dumpint(off);
-		}
-	}
-
-	// Dump fields in the local vars section
-	if(stackmap == nil) {
-		// No locals information, dump everything.
-		for(off = child->arglen; off < s->varp - s->sp; off += PtrSize) {
-			dumpint(FieldKindPtr);
-			dumpint(off);
-		}
-	} else if(stackmap->n < 0) {
-		// Locals size information, dump just the locals.
-		size = -stackmap->n;
-		for(off = s->varp - size - s->sp; off <  s->varp - s->sp; off += PtrSize) {
-			dumpint(FieldKindPtr);
-			dumpint(off);
-		}
-	} else if(stackmap->n > 0) {
-		// Locals bitmap information, scan just the pointers in
-		// locals.
-		dumpbv(&bv, s->varp - bv.n / BitsPerPointer * PtrSize - s->sp);
-	}
-	dumpint(FieldKindEol);
-
-	// Record arg info for parent.
-	child->argoff = s->argp - s->fp;
-	child->arglen = s->arglen;
-	child->sp = (byte*)s->sp;
-	child->depth++;
-	stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps);
-	if(stackmap != nil)
-		child->args = runtime·stackmapdata(stackmap, pcdata);
-	else
-		child->args.n = -1;
-	return true;
-}
-
-static void
-dumpgoroutine(G *gp)
-{
-	uintptr sp, pc, lr;
-	ChildInfo child;
-	Defer *d;
-	Panic *p;
-	bool (*fn)(Stkframe*, void*);
-
-	if(gp->syscallsp != (uintptr)nil) {
-		sp = gp->syscallsp;
-		pc = gp->syscallpc;
-		lr = 0;
-	} else {
-		sp = gp->sched.sp;
-		pc = gp->sched.pc;
-		lr = gp->sched.lr;
-	}
-
-	dumpint(TagGoRoutine);
-	dumpint((uintptr)gp);
-	dumpint((uintptr)sp);
-	dumpint(gp->goid);
-	dumpint(gp->gopc);
-	dumpint(runtime·readgstatus(gp));
-	dumpbool(gp->issystem);
-	dumpbool(false);  // isbackground
-	dumpint(gp->waitsince);
-	dumpstr(gp->waitreason);
-	dumpint((uintptr)gp->sched.ctxt);
-	dumpint((uintptr)gp->m);
-	dumpint((uintptr)gp->defer);
-	dumpint((uintptr)gp->panic);
-
-	// dump stack
-	child.args.n = -1;
-	child.arglen = 0;
-	child.sp = nil;
-	child.depth = 0;
-	fn = dumpframe;
-	runtime·gentraceback(pc, sp, lr, gp, 0, nil, 0x7fffffff, &fn, &child, 0);
-
-	// dump defer & panic records
-	for(d = gp->defer; d != nil; d = d->link) {
-		dumpint(TagDefer);
-		dumpint((uintptr)d);
-		dumpint((uintptr)gp);
-		dumpint((uintptr)d->argp);
-		dumpint((uintptr)d->pc);
-		dumpint((uintptr)d->fn);
-		dumpint((uintptr)d->fn->fn);
-		dumpint((uintptr)d->link);
-	}
-	for (p = gp->panic; p != nil; p = p->link) {
-		dumpint(TagPanic);
-		dumpint((uintptr)p);
-		dumpint((uintptr)gp);
-		dumpint((uintptr)p->arg.type);
-		dumpint((uintptr)p->arg.data);
-		dumpint(0); // was p->defer, no longer recorded
-		dumpint((uintptr)p->link);
-	}
-}
-
-static void
-dumpgs(void)
-{
-	G *gp;
-	uint32 i;
-	uint32 status;
-
-	// goroutines & stacks
-	for(i = 0; i < runtime·allglen; i++) {
-		gp = runtime·allg[i];
-		status = runtime·readgstatus(gp); // The world is stopped so gp will not be in a scan state.
-		switch(status){
-		default:
-			runtime·printf("runtime: unexpected G.status %d\n", status);
-			runtime·throw("dumpgs in STW - bad status");
-		case Gdead:
-			break;
-		case Grunnable:
-		case Gsyscall:
-		case Gwaiting:
-			dumpgoroutine(gp);
-			break;
-		}
-	}
-}
-
-static void
-finq_callback(FuncVal *fn, byte *obj, uintptr nret, Type *fint, PtrType *ot)
-{
-	dumpint(TagQueuedFinalizer);
-	dumpint((uintptr)obj);
-	dumpint((uintptr)fn);
-	dumpint((uintptr)fn->fn);
-	dumpint((uintptr)fint);
-	dumpint((uintptr)ot);
-	USED(&nret);
-}
-
-
-static void
-dumproots(void)
-{
-	MSpan *s, **allspans;
-	uint32 spanidx;
-	Special *sp;
-	SpecialFinalizer *spf;
-	byte *p;
-
-	// data segment
-	dumpbvtypes(&runtime·gcdatamask, runtime·data);
-	dumpint(TagData);
-	dumpint((uintptr)runtime·data);
-	dumpmemrange(runtime·data, runtime·edata - runtime·data);
-	dumpfields(runtime·gcdatamask);
-
-	// bss segment
-	dumpbvtypes(&runtime·gcbssmask, runtime·bss);
-	dumpint(TagBss);
-	dumpint((uintptr)runtime·bss);
-	dumpmemrange(runtime·bss, runtime·ebss - runtime·bss);
-	dumpfields(runtime·gcbssmask);
-
-	// MSpan.types
-	allspans = runtime·mheap.allspans;
-	for(spanidx=0; spanidx<runtime·mheap.nspan; spanidx++) {
-		s = allspans[spanidx];
-		if(s->state == MSpanInUse) {
-			// Finalizers
-			for(sp = s->specials; sp != nil; sp = sp->next) {
-				if(sp->kind != KindSpecialFinalizer)
-					continue;
-				spf = (SpecialFinalizer*)sp;
-				p = (byte*)((s->start << PageShift) + spf->special.offset);
-				dumpfinalizer(p, spf->fn, spf->fint, spf->ot);
-			}
-		}
-	}
-
-	// Finalizer queue
-	runtime·iterate_finq(finq_callback);
-}
-
-// Bit vector of free marks.	
-// Needs to be as big as the largest number of objects per span.	
-#pragma dataflag NOPTR
-static byte free[PageSize/8];	
-
-static void
-dumpobjs(void)
-{
-	uintptr i, j, size, n;
-	MSpan *s;
-	MLink *l;
-	byte *p;
-
-	for(i = 0; i < runtime·mheap.nspan; i++) {
-		s = runtime·mheap.allspans[i];
-		if(s->state != MSpanInUse)
-			continue;
-		p = (byte*)(s->start << PageShift);
-		size = s->elemsize;
-		n = (s->npages << PageShift) / size;
-		if(n > nelem(free))	
-			runtime·throw("free array doesn't have enough entries");	
-		for(l = s->freelist; l != nil; l = l->next)
-			free[((byte*)l - p) / size] = true;	
-		for(j = 0; j < n; j++, p += size) {
-			if(free[j]) {	
-				free[j] = false;	
-				continue;	
-			}
-			dumpobj(p, size, makeheapobjbv(p, size));
-		}
-	}
-}
-
-static void
-dumpparams(void)
-{
-	byte *x;
-
-	dumpint(TagParams);
-	x = (byte*)1;
-	if(*(byte*)&x == 1)
-		dumpbool(false); // little-endian ptrs
-	else
-		dumpbool(true); // big-endian ptrs
-	dumpint(PtrSize);
-	dumpint((uintptr)runtime·mheap.arena_start);
-	dumpint((uintptr)runtime·mheap.arena_used);
-	dumpint(thechar);
-	dumpcstr(GOEXPERIMENT);
-	dumpint(runtime·ncpu);
-}
-
-static void
-itab_callback(Itab *tab)
-{
-	Type *t;
-
-	t = tab->type;
-	// Dump a map from itab* to the type of its data field.
-	// We want this map so we can deduce types of interface referents.
-	if((t->kind & KindDirectIface) == 0) {
-		// indirect - data slot is a pointer to t.
-		dumptype(t->ptrto);
-		dumpint(TagItab);
-		dumpint((uintptr)tab);
-		dumpint((uintptr)t->ptrto);
-	} else if((t->kind & KindNoPointers) == 0) {
-		// t is pointer-like - data slot is a t.
-		dumptype(t);
-		dumpint(TagItab);
-		dumpint((uintptr)tab);
-		dumpint((uintptr)t);
-	} else {
-		// Data slot is a scalar.  Dump type just for fun.
-		// With pointer-only interfaces, this shouldn't happen.
-		dumptype(t);
-		dumpint(TagItab);
-		dumpint((uintptr)tab);
-		dumpint((uintptr)t);
-	}
-}
-
-static void
-dumpitabs(void)
-{
-	void (*fn)(Itab*);
-	
-	fn = itab_callback;
-	runtime·iterate_itabs(&fn);
-}
-
-static void
-dumpms(void)
-{
-	M *mp;
-
-	for(mp = runtime·allm; mp != nil; mp = mp->alllink) {
-		dumpint(TagOSThread);
-		dumpint((uintptr)mp);
-		dumpint(mp->id);
-		dumpint(mp->procid);
-	}
-}
-
-static void
-dumpmemstats(void)
-{
-	int32 i;
-
-	dumpint(TagMemStats);
-	dumpint(mstats.alloc);
-	dumpint(mstats.total_alloc);
-	dumpint(mstats.sys);
-	dumpint(mstats.nlookup);
-	dumpint(mstats.nmalloc);
-	dumpint(mstats.nfree);
-	dumpint(mstats.heap_alloc);
-	dumpint(mstats.heap_sys);
-	dumpint(mstats.heap_idle);
-	dumpint(mstats.heap_inuse);
-	dumpint(mstats.heap_released);
-	dumpint(mstats.heap_objects);
-	dumpint(mstats.stacks_inuse);
-	dumpint(mstats.stacks_sys);
-	dumpint(mstats.mspan_inuse);
-	dumpint(mstats.mspan_sys);
-	dumpint(mstats.mcache_inuse);
-	dumpint(mstats.mcache_sys);
-	dumpint(mstats.buckhash_sys);
-	dumpint(mstats.gc_sys);
-	dumpint(mstats.other_sys);
-	dumpint(mstats.next_gc);
-	dumpint(mstats.last_gc);
-	dumpint(mstats.pause_total_ns);
-	for(i = 0; i < 256; i++)
-		dumpint(mstats.pause_ns[i]);
-	dumpint(mstats.numgc);
-}
-
-static void
-dumpmemprof_callback(Bucket *b, uintptr nstk, uintptr *stk, uintptr size, uintptr allocs, uintptr frees)
-{
-	uintptr i, pc;
-	Func *f;
-	byte buf[20];
-	String file;
-	int32 line;
-
-	dumpint(TagMemProf);
-	dumpint((uintptr)b);
-	dumpint(size);
-	dumpint(nstk);
-	for(i = 0; i < nstk; i++) {
-		pc = stk[i];
-		f = runtime·findfunc(pc);
-		if(f == nil) {
-			runtime·snprintf(buf, sizeof(buf), "%X", (uint64)pc);
-			dumpcstr((int8*)buf);
-			dumpcstr("?");
-			dumpint(0);
-		} else {
-			dumpcstr(runtime·funcname(f));
-			// TODO: Why do we need to back up to a call instruction here?
-			// Maybe profiler should do this.
-			if(i > 0 && pc > f->entry) {
-				if(thechar == '6' || thechar == '8')
-					pc--;
-				else
-					pc -= 4; // arm, etc
-			}
-			line = runtime·funcline(f, pc, &file);
-			dumpstr(file);
-			dumpint(line);
-		}
-	}
-	dumpint(allocs);
-	dumpint(frees);
-}
-
-static void
-dumpmemprof(void)
-{
-	MSpan *s, **allspans;
-	uint32 spanidx;
-	Special *sp;
-	SpecialProfile *spp;
-	byte *p;
-	void (*fn)(Bucket*, uintptr, uintptr*, uintptr, uintptr, uintptr);
-	
-	fn = dumpmemprof_callback;
-	runtime·iterate_memprof(&fn);
-
-	allspans = runtime·mheap.allspans;
-	for(spanidx=0; spanidx<runtime·mheap.nspan; spanidx++) {
-		s = allspans[spanidx];
-		if(s->state != MSpanInUse)
-			continue;
-		for(sp = s->specials; sp != nil; sp = sp->next) {
-			if(sp->kind != KindSpecialProfile)
-				continue;
-			spp = (SpecialProfile*)sp;
-			p = (byte*)((s->start << PageShift) + spp->special.offset);
-			dumpint(TagAllocSample);
-			dumpint((uintptr)p);
-			dumpint((uintptr)spp->b);
-		}
-	}
-}
-
-static void
-mdump(void)
-{
-	byte *hdr;
-	uintptr i;
-	MSpan *s;
-
-	// make sure we're done sweeping
-	for(i = 0; i < runtime·mheap.nspan; i++) {
-		s = runtime·mheap.allspans[i];
-		if(s->state == MSpanInUse)
-			runtime·MSpan_EnsureSwept(s);
-	}
-
-	runtime·memclr((byte*)&typecache[0], sizeof(typecache));
-	hdr = (byte*)"go1.4 heap dump\n";
-	write(hdr, runtime·findnull(hdr));
-	dumpparams();
-	dumpitabs();
-	dumpobjs();
-	dumpgs();
-	dumpms();
-	dumproots();
-	dumpmemstats();
-	dumpmemprof();
-	dumpint(TagEOF);
-	flush();
-}
-
-void
-runtime·writeheapdump_m(void)
-{
-	uintptr fd;
-	
-	fd = g->m->scalararg[0];
-	g->m->scalararg[0] = 0;
-
-	runtime·casgstatus(g->m->curg, Grunning, Gwaiting);
-	g->waitreason = runtime·gostringnocopy((byte*)"dumping heap");
-
-	// Update stats so we can dump them.
-	// As a side effect, flushes all the MCaches so the MSpan.freelist
-	// lists contain all the free objects.
-	runtime·updatememstats(nil);
-
-	// Set dump file.
-	dumpfd = fd;
-
-	// Call dump routine.
-	mdump();
-
-	// Reset dump file.
-	dumpfd = 0;
-	if(tmpbuf != nil) {
-		runtime·SysFree(tmpbuf, tmpbufsize, &mstats.other_sys);
-		tmpbuf = nil;
-		tmpbufsize = 0;
-	}
-
-	runtime·casgstatus(g->m->curg, Gwaiting, Grunning);
-}
-
-// dumpint() the kind & offset of each field in an object.
-static void
-dumpfields(BitVector bv)
-{
-	dumpbv(&bv, 0);
-	dumpint(FieldKindEol);
-}
-
-// The heap dump reader needs to be able to disambiguate
-// Eface entries.  So it needs to know every type that might
-// appear in such an entry.  The following routine accomplishes that.
-
-// Dump all the types that appear in the type field of
-// any Eface described by this bit vector.
-static void
-dumpbvtypes(BitVector *bv, byte *base)
-{
-	uintptr i;
-
-	for(i = 0; i < bv->n; i += BitsPerPointer) {
-		if((bv->bytedata[i/8] >> i%8 & 3) != BitsMultiWord)
-			continue;
-		switch(bv->bytedata[(i+BitsPerPointer)/8] >> (i+BitsPerPointer)%8 & 3) {
-		default:
-			runtime·throw("unexpected garbage collection bits");
-		case BitsIface:
-			i += BitsPerPointer;
-			break;
-		case BitsEface:
-			dumptype(*(Type**)(base + i / BitsPerPointer * PtrSize));
-			i += BitsPerPointer;
-			break;
-		}
-	}
-}
-
-static BitVector
-makeheapobjbv(byte *p, uintptr size)
-{
-	uintptr off, nptr, i;
-	byte shift, *bitp, bits;
-	bool mw;
-
-	// Extend the temp buffer if necessary.
-	nptr = size/PtrSize;
-	if(tmpbufsize < nptr*BitsPerPointer/8+1) {
-		if(tmpbuf != nil)
-			runtime·SysFree(tmpbuf, tmpbufsize, &mstats.other_sys);
-		tmpbufsize = nptr*BitsPerPointer/8+1;
-		tmpbuf = runtime·sysAlloc(tmpbufsize, &mstats.other_sys);
-		if(tmpbuf == nil)
-			runtime·throw("heapdump: out of memory");
-	}
-
-	// Copy and compact the bitmap.
-	mw = false;
-	for(i = 0; i < nptr; i++) {
-		off = (uintptr*)(p + i*PtrSize) - (uintptr*)runtime·mheap.arena_start;
-		bitp = runtime·mheap.arena_start - off/wordsPerBitmapByte - 1;
-		shift = (off % wordsPerBitmapByte) * gcBits;
-		bits = (*bitp >> (shift + 2)) & BitsMask;
-		if(!mw && bits == BitsDead)
-			break;  // end of heap object
-		mw = !mw && bits == BitsMultiWord;
-		tmpbuf[i*BitsPerPointer/8] &= ~(BitsMask<<((i*BitsPerPointer)%8));
-		tmpbuf[i*BitsPerPointer/8] |= bits<<((i*BitsPerPointer)%8);
-	}
-	return (BitVector){i*BitsPerPointer, tmpbuf};
-}
diff --git a/src/runtime/heapdump.go b/src/runtime/heapdump.go
new file mode 100644
index 0000000..492ea92
--- /dev/null
+++ b/src/runtime/heapdump.go
@@ -0,0 +1,735 @@
+// 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.
+
+// Implementation of runtime/debug.WriteHeapDump.  Writes all
+// objects in the heap plus additional info (roots, threads,
+// finalizers, etc.) to a file.
+
+// The format of the dumped file is described at
+// https://golang.org/s/go14heapdump.
+
+package runtime
+
+import "unsafe"
+
+//go:linkname runtime_debug_WriteHeapDump runtime/debug.WriteHeapDump
+func runtime_debug_WriteHeapDump(fd uintptr) {
+	stopTheWorld("write heap dump")
+
+	systemstack(func() {
+		writeheapdump_m(fd)
+	})
+
+	startTheWorld()
+}
+
+const (
+	fieldKindEol       = 0
+	fieldKindPtr       = 1
+	fieldKindIface     = 2
+	fieldKindEface     = 3
+	tagEOF             = 0
+	tagObject          = 1
+	tagOtherRoot       = 2
+	tagType            = 3
+	tagGoroutine       = 4
+	tagStackFrame      = 5
+	tagParams          = 6
+	tagFinalizer       = 7
+	tagItab            = 8
+	tagOSThread        = 9
+	tagMemStats        = 10
+	tagQueuedFinalizer = 11
+	tagData            = 12
+	tagBSS             = 13
+	tagDefer           = 14
+	tagPanic           = 15
+	tagMemProf         = 16
+	tagAllocSample     = 17
+)
+
+var dumpfd uintptr // fd to write the dump to.
+var tmpbuf []byte
+
+// buffer of pending write data
+const (
+	bufSize = 4096
+)
+
+var buf [bufSize]byte
+var nbuf uintptr
+
+func dwrite(data unsafe.Pointer, len uintptr) {
+	if len == 0 {
+		return
+	}
+	if nbuf+len <= bufSize {
+		copy(buf[nbuf:], (*[bufSize]byte)(data)[:len])
+		nbuf += len
+		return
+	}
+
+	write(dumpfd, (unsafe.Pointer)(&buf), int32(nbuf))
+	if len >= bufSize {
+		write(dumpfd, data, int32(len))
+		nbuf = 0
+	} else {
+		copy(buf[:], (*[bufSize]byte)(data)[:len])
+		nbuf = len
+	}
+}
+
+func dwritebyte(b byte) {
+	dwrite(unsafe.Pointer(&b), 1)
+}
+
+func flush() {
+	write(dumpfd, (unsafe.Pointer)(&buf), int32(nbuf))
+	nbuf = 0
+}
+
+// Cache of types that have been serialized already.
+// We use a type's hash field to pick a bucket.
+// Inside a bucket, we keep a list of types that
+// have been serialized so far, most recently used first.
+// Note: when a bucket overflows we may end up
+// serializing a type more than once.  That's ok.
+const (
+	typeCacheBuckets = 256
+	typeCacheAssoc   = 4
+)
+
+type typeCacheBucket struct {
+	t [typeCacheAssoc]*_type
+}
+
+var typecache [typeCacheBuckets]typeCacheBucket
+
+// dump a uint64 in a varint format parseable by encoding/binary
+func dumpint(v uint64) {
+	var buf [10]byte
+	var n int
+	for v >= 0x80 {
+		buf[n] = byte(v | 0x80)
+		n++
+		v >>= 7
+	}
+	buf[n] = byte(v)
+	n++
+	dwrite(unsafe.Pointer(&buf), uintptr(n))
+}
+
+func dumpbool(b bool) {
+	if b {
+		dumpint(1)
+	} else {
+		dumpint(0)
+	}
+}
+
+// dump varint uint64 length followed by memory contents
+func dumpmemrange(data unsafe.Pointer, len uintptr) {
+	dumpint(uint64(len))
+	dwrite(data, len)
+}
+
+func dumpslice(b []byte) {
+	dumpint(uint64(len(b)))
+	if len(b) > 0 {
+		dwrite(unsafe.Pointer(&b[0]), uintptr(len(b)))
+	}
+}
+
+func dumpstr(s string) {
+	sp := (*stringStruct)(unsafe.Pointer(&s))
+	dumpmemrange(sp.str, uintptr(sp.len))
+}
+
+// dump information for a type
+func dumptype(t *_type) {
+	if t == nil {
+		return
+	}
+
+	// If we've definitely serialized the type before,
+	// no need to do it again.
+	b := &typecache[t.hash&(typeCacheBuckets-1)]
+	if t == b.t[0] {
+		return
+	}
+	for i := 1; i < typeCacheAssoc; i++ {
+		if t == b.t[i] {
+			// Move-to-front
+			for j := i; j > 0; j-- {
+				b.t[j] = b.t[j-1]
+			}
+			b.t[0] = t
+			return
+		}
+	}
+
+	// Might not have been dumped yet.  Dump it and
+	// remember we did so.
+	for j := typeCacheAssoc - 1; j > 0; j-- {
+		b.t[j] = b.t[j-1]
+	}
+	b.t[0] = t
+
+	// dump the type
+	dumpint(tagType)
+	dumpint(uint64(uintptr(unsafe.Pointer(t))))
+	dumpint(uint64(t.size))
+	if t.x == nil || t.x.pkgpath == nil || t.x.name == nil {
+		dumpstr(*t._string)
+	} else {
+		pkgpath := (*stringStruct)(unsafe.Pointer(&t.x.pkgpath))
+		name := (*stringStruct)(unsafe.Pointer(&t.x.name))
+		dumpint(uint64(uintptr(pkgpath.len) + 1 + uintptr(name.len)))
+		dwrite(pkgpath.str, uintptr(pkgpath.len))
+		dwritebyte('.')
+		dwrite(name.str, uintptr(name.len))
+	}
+	dumpbool(t.kind&kindDirectIface == 0 || t.kind&kindNoPointers == 0)
+}
+
+// dump an object
+func dumpobj(obj unsafe.Pointer, size uintptr, bv bitvector) {
+	dumpbvtypes(&bv, obj)
+	dumpint(tagObject)
+	dumpint(uint64(uintptr(obj)))
+	dumpmemrange(obj, size)
+	dumpfields(bv)
+}
+
+func dumpotherroot(description string, to unsafe.Pointer) {
+	dumpint(tagOtherRoot)
+	dumpstr(description)
+	dumpint(uint64(uintptr(to)))
+}
+
+func dumpfinalizer(obj unsafe.Pointer, fn *funcval, fint *_type, ot *ptrtype) {
+	dumpint(tagFinalizer)
+	dumpint(uint64(uintptr(obj)))
+	dumpint(uint64(uintptr(unsafe.Pointer(fn))))
+	dumpint(uint64(uintptr(unsafe.Pointer(fn.fn))))
+	dumpint(uint64(uintptr(unsafe.Pointer(fint))))
+	dumpint(uint64(uintptr(unsafe.Pointer(ot))))
+}
+
+type childInfo struct {
+	// Information passed up from the callee frame about
+	// the layout of the outargs region.
+	argoff uintptr   // where the arguments start in the frame
+	arglen uintptr   // size of args region
+	args   bitvector // if args.n >= 0, pointer map of args region
+	sp     *uint8    // callee sp
+	depth  uintptr   // depth in call stack (0 == most recent)
+}
+
+// dump kinds & offsets of interesting fields in bv
+func dumpbv(cbv *bitvector, offset uintptr) {
+	bv := gobv(*cbv)
+	for i := uintptr(0); i < uintptr(bv.n); i++ {
+		if bv.bytedata[i/8]>>(i%8)&1 == 1 {
+			dumpint(fieldKindPtr)
+			dumpint(uint64(offset + i*ptrSize))
+		}
+	}
+}
+
+func dumpframe(s *stkframe, arg unsafe.Pointer) bool {
+	child := (*childInfo)(arg)
+	f := s.fn
+
+	// Figure out what we can about our stack map
+	pc := s.pc
+	if pc != f.entry {
+		pc--
+	}
+	pcdata := pcdatavalue(f, _PCDATA_StackMapIndex, pc)
+	if pcdata == -1 {
+		// We do not have a valid pcdata value but there might be a
+		// stackmap for this function.  It is likely that we are looking
+		// at the function prologue, assume so and hope for the best.
+		pcdata = 0
+	}
+	stkmap := (*stackmap)(funcdata(f, _FUNCDATA_LocalsPointerMaps))
+
+	// Dump any types we will need to resolve Efaces.
+	if child.args.n >= 0 {
+		dumpbvtypes(&child.args, unsafe.Pointer(s.sp+child.argoff))
+	}
+	var bv bitvector
+	if stkmap != nil && stkmap.n > 0 {
+		bv = stackmapdata(stkmap, pcdata)
+		dumpbvtypes(&bv, unsafe.Pointer(s.varp-uintptr(bv.n*ptrSize)))
+	} else {
+		bv.n = -1
+	}
+
+	// Dump main body of stack frame.
+	dumpint(tagStackFrame)
+	dumpint(uint64(s.sp))                              // lowest address in frame
+	dumpint(uint64(child.depth))                       // # of frames deep on the stack
+	dumpint(uint64(uintptr(unsafe.Pointer(child.sp)))) // sp of child, or 0 if bottom of stack
+	dumpmemrange(unsafe.Pointer(s.sp), s.fp-s.sp)      // frame contents
+	dumpint(uint64(f.entry))
+	dumpint(uint64(s.pc))
+	dumpint(uint64(s.continpc))
+	name := funcname(f)
+	if name == "" {
+		name = "unknown function"
+	}
+	dumpstr(name)
+
+	// Dump fields in the outargs section
+	if child.args.n >= 0 {
+		dumpbv(&child.args, child.argoff)
+	} else {
+		// conservative - everything might be a pointer
+		for off := child.argoff; off < child.argoff+child.arglen; off += ptrSize {
+			dumpint(fieldKindPtr)
+			dumpint(uint64(off))
+		}
+	}
+
+	// Dump fields in the local vars section
+	if stkmap == nil {
+		// No locals information, dump everything.
+		for off := child.arglen; off < s.varp-s.sp; off += ptrSize {
+			dumpint(fieldKindPtr)
+			dumpint(uint64(off))
+		}
+	} else if stkmap.n < 0 {
+		// Locals size information, dump just the locals.
+		size := uintptr(-stkmap.n)
+		for off := s.varp - size - s.sp; off < s.varp-s.sp; off += ptrSize {
+			dumpint(fieldKindPtr)
+			dumpint(uint64(off))
+		}
+	} else if stkmap.n > 0 {
+		// Locals bitmap information, scan just the pointers in
+		// locals.
+		dumpbv(&bv, s.varp-uintptr(bv.n)*ptrSize-s.sp)
+	}
+	dumpint(fieldKindEol)
+
+	// Record arg info for parent.
+	child.argoff = s.argp - s.fp
+	child.arglen = s.arglen
+	child.sp = (*uint8)(unsafe.Pointer(s.sp))
+	child.depth++
+	stkmap = (*stackmap)(funcdata(f, _FUNCDATA_ArgsPointerMaps))
+	if stkmap != nil {
+		child.args = stackmapdata(stkmap, pcdata)
+	} else {
+		child.args.n = -1
+	}
+	return true
+}
+
+func dumpgoroutine(gp *g) {
+	var sp, pc, lr uintptr
+	if gp.syscallsp != 0 {
+		sp = gp.syscallsp
+		pc = gp.syscallpc
+		lr = 0
+	} else {
+		sp = gp.sched.sp
+		pc = gp.sched.pc
+		lr = gp.sched.lr
+	}
+
+	dumpint(tagGoroutine)
+	dumpint(uint64(uintptr(unsafe.Pointer(gp))))
+	dumpint(uint64(sp))
+	dumpint(uint64(gp.goid))
+	dumpint(uint64(gp.gopc))
+	dumpint(uint64(readgstatus(gp)))
+	dumpbool(isSystemGoroutine(gp))
+	dumpbool(false) // isbackground
+	dumpint(uint64(gp.waitsince))
+	dumpstr(gp.waitreason)
+	dumpint(uint64(uintptr(gp.sched.ctxt)))
+	dumpint(uint64(uintptr(unsafe.Pointer(gp.m))))
+	dumpint(uint64(uintptr(unsafe.Pointer(gp._defer))))
+	dumpint(uint64(uintptr(unsafe.Pointer(gp._panic))))
+
+	// dump stack
+	var child childInfo
+	child.args.n = -1
+	child.arglen = 0
+	child.sp = nil
+	child.depth = 0
+	gentraceback(pc, sp, lr, gp, 0, nil, 0x7fffffff, dumpframe, noescape(unsafe.Pointer(&child)), 0)
+
+	// dump defer & panic records
+	for d := gp._defer; d != nil; d = d.link {
+		dumpint(tagDefer)
+		dumpint(uint64(uintptr(unsafe.Pointer(d))))
+		dumpint(uint64(uintptr(unsafe.Pointer(gp))))
+		dumpint(uint64(d.sp))
+		dumpint(uint64(d.pc))
+		dumpint(uint64(uintptr(unsafe.Pointer(d.fn))))
+		dumpint(uint64(uintptr(unsafe.Pointer(d.fn.fn))))
+		dumpint(uint64(uintptr(unsafe.Pointer(d.link))))
+	}
+	for p := gp._panic; p != nil; p = p.link {
+		dumpint(tagPanic)
+		dumpint(uint64(uintptr(unsafe.Pointer(p))))
+		dumpint(uint64(uintptr(unsafe.Pointer(gp))))
+		eface := (*eface)(unsafe.Pointer(&p.arg))
+		dumpint(uint64(uintptr(unsafe.Pointer(eface._type))))
+		dumpint(uint64(uintptr(unsafe.Pointer(eface.data))))
+		dumpint(0) // was p->defer, no longer recorded
+		dumpint(uint64(uintptr(unsafe.Pointer(p.link))))
+	}
+}
+
+func dumpgs() {
+	// goroutines & stacks
+	for i := 0; uintptr(i) < allglen; i++ {
+		gp := allgs[i]
+		status := readgstatus(gp) // The world is stopped so gp will not be in a scan state.
+		switch status {
+		default:
+			print("runtime: unexpected G.status ", hex(status), "\n")
+			throw("dumpgs in STW - bad status")
+		case _Gdead:
+			// ok
+		case _Grunnable,
+			_Gsyscall,
+			_Gwaiting:
+			dumpgoroutine(gp)
+		}
+	}
+}
+
+func finq_callback(fn *funcval, obj unsafe.Pointer, nret uintptr, fint *_type, ot *ptrtype) {
+	dumpint(tagQueuedFinalizer)
+	dumpint(uint64(uintptr(obj)))
+	dumpint(uint64(uintptr(unsafe.Pointer(fn))))
+	dumpint(uint64(uintptr(unsafe.Pointer(fn.fn))))
+	dumpint(uint64(uintptr(unsafe.Pointer(fint))))
+	dumpint(uint64(uintptr(unsafe.Pointer(ot))))
+}
+
+func dumproots() {
+	// TODO(mwhudson): dump datamask etc from all objects
+	// data segment
+	dumpbvtypes(&firstmoduledata.gcdatamask, unsafe.Pointer(firstmoduledata.data))
+	dumpint(tagData)
+	dumpint(uint64(firstmoduledata.data))
+	dumpmemrange(unsafe.Pointer(firstmoduledata.data), firstmoduledata.edata-firstmoduledata.data)
+	dumpfields(firstmoduledata.gcdatamask)
+
+	// bss segment
+	dumpbvtypes(&firstmoduledata.gcbssmask, unsafe.Pointer(firstmoduledata.bss))
+	dumpint(tagBSS)
+	dumpint(uint64(firstmoduledata.bss))
+	dumpmemrange(unsafe.Pointer(firstmoduledata.bss), firstmoduledata.ebss-firstmoduledata.bss)
+	dumpfields(firstmoduledata.gcbssmask)
+
+	// MSpan.types
+	allspans := h_allspans
+	for spanidx := uint32(0); spanidx < mheap_.nspan; spanidx++ {
+		s := allspans[spanidx]
+		if s.state == _MSpanInUse {
+			// Finalizers
+			for sp := s.specials; sp != nil; sp = sp.next {
+				if sp.kind != _KindSpecialFinalizer {
+					continue
+				}
+				spf := (*specialfinalizer)(unsafe.Pointer(sp))
+				p := unsafe.Pointer((uintptr(s.start) << _PageShift) + uintptr(spf.special.offset))
+				dumpfinalizer(p, spf.fn, spf.fint, spf.ot)
+			}
+		}
+	}
+
+	// Finalizer queue
+	iterate_finq(finq_callback)
+}
+
+// Bit vector of free marks.
+// Needs to be as big as the largest number of objects per span.
+var freemark [_PageSize / 8]bool
+
+func dumpobjs() {
+	for i := uintptr(0); i < uintptr(mheap_.nspan); i++ {
+		s := h_allspans[i]
+		if s.state != _MSpanInUse {
+			continue
+		}
+		p := uintptr(s.start << _PageShift)
+		size := s.elemsize
+		n := (s.npages << _PageShift) / size
+		if n > uintptr(len(freemark)) {
+			throw("freemark array doesn't have enough entries")
+		}
+		for l := s.freelist; l.ptr() != nil; l = l.ptr().next {
+			freemark[(uintptr(l)-p)/size] = true
+		}
+		for j := uintptr(0); j < n; j, p = j+1, p+size {
+			if freemark[j] {
+				freemark[j] = false
+				continue
+			}
+			dumpobj(unsafe.Pointer(p), size, makeheapobjbv(p, size))
+		}
+	}
+}
+
+func dumpparams() {
+	dumpint(tagParams)
+	x := uintptr(1)
+	if *(*byte)(unsafe.Pointer(&x)) == 1 {
+		dumpbool(false) // little-endian ptrs
+	} else {
+		dumpbool(true) // big-endian ptrs
+	}
+	dumpint(ptrSize)
+	dumpint(uint64(mheap_.arena_start))
+	dumpint(uint64(mheap_.arena_used))
+	dumpint(thechar)
+	dumpstr(goexperiment)
+	dumpint(uint64(ncpu))
+}
+
+func itab_callback(tab *itab) {
+	t := tab._type
+	// Dump a map from itab* to the type of its data field.
+	// We want this map so we can deduce types of interface referents.
+	if t.kind&kindDirectIface == 0 {
+		// indirect - data slot is a pointer to t.
+		dumptype(t.ptrto)
+		dumpint(tagItab)
+		dumpint(uint64(uintptr(unsafe.Pointer(tab))))
+		dumpint(uint64(uintptr(unsafe.Pointer(t.ptrto))))
+	} else if t.kind&kindNoPointers == 0 {
+		// t is pointer-like - data slot is a t.
+		dumptype(t)
+		dumpint(tagItab)
+		dumpint(uint64(uintptr(unsafe.Pointer(tab))))
+		dumpint(uint64(uintptr(unsafe.Pointer(t))))
+	} else {
+		// Data slot is a scalar.  Dump type just for fun.
+		// With pointer-only interfaces, this shouldn't happen.
+		dumptype(t)
+		dumpint(tagItab)
+		dumpint(uint64(uintptr(unsafe.Pointer(tab))))
+		dumpint(uint64(uintptr(unsafe.Pointer(t))))
+	}
+}
+
+func dumpitabs() {
+	iterate_itabs(itab_callback)
+}
+
+func dumpms() {
+	for mp := allm; mp != nil; mp = mp.alllink {
+		dumpint(tagOSThread)
+		dumpint(uint64(uintptr(unsafe.Pointer(mp))))
+		dumpint(uint64(mp.id))
+		dumpint(mp.procid)
+	}
+}
+
+func dumpmemstats() {
+	dumpint(tagMemStats)
+	dumpint(memstats.alloc)
+	dumpint(memstats.total_alloc)
+	dumpint(memstats.sys)
+	dumpint(memstats.nlookup)
+	dumpint(memstats.nmalloc)
+	dumpint(memstats.nfree)
+	dumpint(memstats.heap_alloc)
+	dumpint(memstats.heap_sys)
+	dumpint(memstats.heap_idle)
+	dumpint(memstats.heap_inuse)
+	dumpint(memstats.heap_released)
+	dumpint(memstats.heap_objects)
+	dumpint(memstats.stacks_inuse)
+	dumpint(memstats.stacks_sys)
+	dumpint(memstats.mspan_inuse)
+	dumpint(memstats.mspan_sys)
+	dumpint(memstats.mcache_inuse)
+	dumpint(memstats.mcache_sys)
+	dumpint(memstats.buckhash_sys)
+	dumpint(memstats.gc_sys)
+	dumpint(memstats.other_sys)
+	dumpint(memstats.next_gc)
+	dumpint(memstats.last_gc)
+	dumpint(memstats.pause_total_ns)
+	for i := 0; i < 256; i++ {
+		dumpint(memstats.pause_ns[i])
+	}
+	dumpint(uint64(memstats.numgc))
+}
+
+func dumpmemprof_callback(b *bucket, nstk uintptr, pstk *uintptr, size, allocs, frees uintptr) {
+	stk := (*[100000]uintptr)(unsafe.Pointer(pstk))
+	dumpint(tagMemProf)
+	dumpint(uint64(uintptr(unsafe.Pointer(b))))
+	dumpint(uint64(size))
+	dumpint(uint64(nstk))
+	for i := uintptr(0); i < nstk; i++ {
+		pc := stk[i]
+		f := findfunc(pc)
+		if f == nil {
+			var buf [64]byte
+			n := len(buf)
+			n--
+			buf[n] = ')'
+			if pc == 0 {
+				n--
+				buf[n] = '0'
+			} else {
+				for pc > 0 {
+					n--
+					buf[n] = "0123456789abcdef"[pc&15]
+					pc >>= 4
+				}
+			}
+			n--
+			buf[n] = 'x'
+			n--
+			buf[n] = '0'
+			n--
+			buf[n] = '('
+			dumpslice(buf[n:])
+			dumpstr("?")
+			dumpint(0)
+		} else {
+			dumpstr(funcname(f))
+			if i > 0 && pc > f.entry {
+				pc--
+			}
+			file, line := funcline(f, pc)
+			dumpstr(file)
+			dumpint(uint64(line))
+		}
+	}
+	dumpint(uint64(allocs))
+	dumpint(uint64(frees))
+}
+
+func dumpmemprof() {
+	iterate_memprof(dumpmemprof_callback)
+	allspans := h_allspans
+	for spanidx := uint32(0); spanidx < mheap_.nspan; spanidx++ {
+		s := allspans[spanidx]
+		if s.state != _MSpanInUse {
+			continue
+		}
+		for sp := s.specials; sp != nil; sp = sp.next {
+			if sp.kind != _KindSpecialProfile {
+				continue
+			}
+			spp := (*specialprofile)(unsafe.Pointer(sp))
+			p := uintptr(s.start<<_PageShift) + uintptr(spp.special.offset)
+			dumpint(tagAllocSample)
+			dumpint(uint64(p))
+			dumpint(uint64(uintptr(unsafe.Pointer(spp.b))))
+		}
+	}
+}
+
+var dumphdr = []byte("go1.5 heap dump\n")
+
+func mdump() {
+	// make sure we're done sweeping
+	for i := uintptr(0); i < uintptr(mheap_.nspan); i++ {
+		s := h_allspans[i]
+		if s.state == _MSpanInUse {
+			mSpan_EnsureSwept(s)
+		}
+	}
+	memclr(unsafe.Pointer(&typecache), unsafe.Sizeof(typecache))
+	dwrite(unsafe.Pointer(&dumphdr[0]), uintptr(len(dumphdr)))
+	dumpparams()
+	dumpitabs()
+	dumpobjs()
+	dumpgs()
+	dumpms()
+	dumproots()
+	dumpmemstats()
+	dumpmemprof()
+	dumpint(tagEOF)
+	flush()
+}
+
+func writeheapdump_m(fd uintptr) {
+	_g_ := getg()
+	casgstatus(_g_.m.curg, _Grunning, _Gwaiting)
+	_g_.waitreason = "dumping heap"
+
+	// Update stats so we can dump them.
+	// As a side effect, flushes all the MCaches so the MSpan.freelist
+	// lists contain all the free objects.
+	updatememstats(nil)
+
+	// Set dump file.
+	dumpfd = fd
+
+	// Call dump routine.
+	mdump()
+
+	// Reset dump file.
+	dumpfd = 0
+	if tmpbuf != nil {
+		sysFree(unsafe.Pointer(&tmpbuf[0]), uintptr(len(tmpbuf)), &memstats.other_sys)
+		tmpbuf = nil
+	}
+
+	casgstatus(_g_.m.curg, _Gwaiting, _Grunning)
+}
+
+// dumpint() the kind & offset of each field in an object.
+func dumpfields(bv bitvector) {
+	dumpbv(&bv, 0)
+	dumpint(fieldKindEol)
+}
+
+// The heap dump reader needs to be able to disambiguate
+// Eface entries.  So it needs to know every type that might
+// appear in such an entry.  The following routine accomplishes that.
+// TODO(rsc, khr): Delete - no longer possible.
+
+// Dump all the types that appear in the type field of
+// any Eface described by this bit vector.
+func dumpbvtypes(bv *bitvector, base unsafe.Pointer) {
+}
+
+func makeheapobjbv(p uintptr, size uintptr) bitvector {
+	// Extend the temp buffer if necessary.
+	nptr := size / ptrSize
+	if uintptr(len(tmpbuf)) < nptr/8+1 {
+		if tmpbuf != nil {
+			sysFree(unsafe.Pointer(&tmpbuf[0]), uintptr(len(tmpbuf)), &memstats.other_sys)
+		}
+		n := nptr/8 + 1
+		p := sysAlloc(n, &memstats.other_sys)
+		if p == nil {
+			throw("heapdump: out of memory")
+		}
+		tmpbuf = (*[1 << 30]byte)(p)[:n]
+	}
+	// Convert heap bitmap to pointer bitmap.
+	for i := uintptr(0); i < nptr/8+1; i++ {
+		tmpbuf[i] = 0
+	}
+	i := uintptr(0)
+	hbits := heapBitsForAddr(p)
+	for ; i < nptr; i++ {
+		if i >= 2 && !hbits.isMarked() {
+			break // end of object
+		}
+		if hbits.isPointer() {
+			tmpbuf[i/8] |= 1 << (i % 8)
+		}
+		hbits = hbits.next()
+	}
+	return bitvector{int32(i), &tmpbuf[0]}
+}
diff --git a/src/runtime/iface.go b/src/runtime/iface.go
index f60b6a7..332b7d5 100644
--- a/src/runtime/iface.go
+++ b/src/runtime/iface.go
@@ -4,9 +4,7 @@
 
 package runtime
 
-import (
-	"unsafe"
-)
+import "unsafe"
 
 const (
 	hashSize = 1009
@@ -26,7 +24,7 @@ type fInterface interface {
 
 func getitab(inter *interfacetype, typ *_type, canfail bool) *itab {
 	if len(inter.mhdr) == 0 {
-		gothrow("internal error - misuse of itab")
+		throw("internal error - misuse of itab")
 	}
 
 	// easy case
@@ -35,8 +33,7 @@ func getitab(inter *interfacetype, typ *_type, canfail bool) *itab {
 		if canfail {
 			return nil
 		}
-		i := (*imethod)(add(unsafe.Pointer(inter), unsafe.Sizeof(interfacetype{})))
-		panic(&TypeAssertionError{"", *typ._string, *inter.typ._string, *i.name})
+		panic(&TypeAssertionError{"", *typ._string, *inter.typ._string, *inter.mhdr[0].name})
 	}
 
 	// compiler has provided some good hash codes for us.
@@ -76,7 +73,7 @@ func getitab(inter *interfacetype, typ *_type, canfail bool) *itab {
 		}
 	}
 
-	m = (*itab)(persistentalloc(unsafe.Sizeof(itab{})+uintptr(len(inter.mhdr))*ptrSize, 0, &memstats.other_sys))
+	m = (*itab)(persistentalloc(unsafe.Sizeof(itab{})+uintptr(len(inter.mhdr)-1)*ptrSize, 0, &memstats.other_sys))
 	m.inter = inter
 	m._type = typ
 
@@ -89,15 +86,15 @@ search:
 	nt := len(x.mhdr)
 	j := 0
 	for k := 0; k < ni; k++ {
-		i := (*imethod)(add(unsafe.Pointer(inter), unsafe.Sizeof(interfacetype{})+uintptr(k)*unsafe.Sizeof(imethod{})))
+		i := &inter.mhdr[k]
 		iname := i.name
 		ipkgpath := i.pkgpath
 		itype := i._type
 		for ; j < nt; j++ {
-			t := (*method)(add(unsafe.Pointer(x), unsafe.Sizeof(uncommontype{})+uintptr(j)*unsafe.Sizeof(method{})))
-			if t.mtyp == itype && t.name == iname && t.pkgpath == ipkgpath {
+			t := &x.mhdr[j]
+			if t.mtyp == itype && (t.name == iname || *t.name == *iname) && t.pkgpath == ipkgpath {
 				if m != nil {
-					*(*unsafe.Pointer)(add(unsafe.Pointer(m), unsafe.Sizeof(itab{})+uintptr(k)*ptrSize)) = t.ifn
+					*(*unsafe.Pointer)(add(unsafe.Pointer(&m.fun[0]), uintptr(k)*ptrSize)) = t.ifn
 				}
 				goto nextimethod
 			}
@@ -114,7 +111,7 @@ search:
 	nextimethod:
 	}
 	if locked == 0 {
-		gothrow("invalid itab locking")
+		throw("invalid itab locking")
 	}
 	m.link = hash[h]
 	atomicstorep(unsafe.Pointer(&hash[h]), unsafe.Pointer(m))
@@ -131,47 +128,54 @@ func typ2Itab(t *_type, inter *interfacetype, cache **itab) *itab {
 	return tab
 }
 
-func convT2E(t *_type, elem unsafe.Pointer) (e interface{}) {
-	size := uintptr(t.size)
+func convT2E(t *_type, elem unsafe.Pointer, x unsafe.Pointer) (e interface{}) {
 	ep := (*eface)(unsafe.Pointer(&e))
 	if isDirectIface(t) {
 		ep._type = t
-		memmove(unsafe.Pointer(&ep.data), elem, size)
+		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.
-		memmove(x, elem, size)
+		typedmemmove(t, x, elem)
 		ep._type = t
 		ep.data = x
 	}
 	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)
 		atomicstorep(unsafe.Pointer(cache), unsafe.Pointer(tab))
 	}
-	size := uintptr(t.size)
 	pi := (*iface)(unsafe.Pointer(&i))
 	if isDirectIface(t) {
 		pi.tab = tab
-		memmove(unsafe.Pointer(&pi.data), elem, size)
+		typedmemmove(t, unsafe.Pointer(&pi.data), elem)
 	} else {
-		x := newobject(t)
-		memmove(x, elem, size)
+		if x == nil {
+			x = newobject(t)
+		}
+		typedmemmove(t, x, elem)
 		pi.tab = tab
 		pi.data = x
 	}
 	return
 }
 
-// TODO: give these routines a pointer to the result area instead of writing
-// extra data in the outargs section.  Then we can get rid of go:nosplit.
-//go:nosplit
-func assertI2T(t *_type, i fInterface) (r struct{}) {
+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
 	if tab == nil {
@@ -180,43 +184,35 @@ func assertI2T(t *_type, i fInterface) (r struct{}) {
 	if tab._type != t {
 		panic(&TypeAssertionError{*tab.inter.typ._string, *tab._type._string, *t._string, ""})
 	}
-	size := uintptr(t.size)
-	if isDirectIface(t) {
-		memmove(unsafe.Pointer(&r), unsafe.Pointer(&ip.data), size)
-	} else {
-		memmove(unsafe.Pointer(&r), ip.data, size)
+	if r != nil {
+		if isDirectIface(t) {
+			writebarrierptr((*uintptr)(r), uintptr(ip.data))
+		} else {
+			typedmemmove(t, r, ip.data)
+		}
 	}
-	return
 }
 
-//go:nosplit
-func assertI2T2(t *_type, i fInterface) (r byte) {
+func assertI2T2(t *_type, i fInterface, r unsafe.Pointer) bool {
 	ip := (*iface)(unsafe.Pointer(&i))
-	size := uintptr(t.size)
-	ok := (*bool)(add(unsafe.Pointer(&r), size))
 	tab := ip.tab
 	if tab == nil || tab._type != t {
-		*ok = false
-		memclr(unsafe.Pointer(&r), size)
-		return
+		if r != nil {
+			memclr(r, uintptr(t.size))
+		}
+		return false
 	}
-	*ok = true
-	if isDirectIface(t) {
-		memmove(unsafe.Pointer(&r), unsafe.Pointer(&ip.data), size)
-	} else {
-		memmove(unsafe.Pointer(&r), ip.data, size)
+	if r != nil {
+		if isDirectIface(t) {
+			writebarrierptr((*uintptr)(r), uintptr(ip.data))
+		} else {
+			typedmemmove(t, r, ip.data)
+		}
 	}
-	return
+	return true
 }
 
-func assertI2TOK(t *_type, i fInterface) bool {
-	ip := (*iface)(unsafe.Pointer(&i))
-	tab := ip.tab
-	return tab != nil && tab._type == t
-}
-
-//go:nosplit
-func assertE2T(t *_type, e interface{}) (r struct{}) {
+func assertE2T(t *_type, e interface{}, r unsafe.Pointer) {
 	ep := (*eface)(unsafe.Pointer(&e))
 	if ep._type == nil {
 		panic(&TypeAssertionError{"", "", *t._string, ""})
@@ -224,37 +220,33 @@ func assertE2T(t *_type, e interface{}) (r struct{}) {
 	if ep._type != t {
 		panic(&TypeAssertionError{"", *ep._type._string, *t._string, ""})
 	}
-	size := uintptr(t.size)
-	if isDirectIface(t) {
-		memmove(unsafe.Pointer(&r), unsafe.Pointer(&ep.data), size)
-	} else {
-		memmove(unsafe.Pointer(&r), ep.data, size)
+	if r != nil {
+		if isDirectIface(t) {
+			writebarrierptr((*uintptr)(r), uintptr(ep.data))
+		} else {
+			typedmemmove(t, r, ep.data)
+		}
 	}
-	return
 }
 
-//go:nosplit
-func assertE2T2(t *_type, e interface{}) (r byte) {
+var testingAssertE2T2GC bool
+
+// The compiler ensures that r is non-nil.
+func assertE2T2(t *_type, e interface{}, r unsafe.Pointer) bool {
+	if testingAssertE2T2GC {
+		GC()
+	}
 	ep := (*eface)(unsafe.Pointer(&e))
-	size := uintptr(t.size)
-	ok := (*bool)(add(unsafe.Pointer(&r), size))
 	if ep._type != t {
-		*ok = false
-		memclr(unsafe.Pointer(&r), size)
-		return
+		memclr(r, uintptr(t.size))
+		return false
 	}
-	*ok = true
 	if isDirectIface(t) {
-		memmove(unsafe.Pointer(&r), unsafe.Pointer(&ep.data), size)
+		writebarrierptr((*uintptr)(r), uintptr(ep.data))
 	} else {
-		memmove(unsafe.Pointer(&r), ep.data, size)
+		typedmemmove(t, r, ep.data)
 	}
-	return
-}
-
-func assertE2TOK(t *_type, e interface{}) bool {
-	ep := (*eface)(unsafe.Pointer(&e))
-	return t == ep._type
+	return true
 }
 
 func convI2E(i fInterface) (r interface{}) {
@@ -269,30 +261,30 @@ func convI2E(i fInterface) (r interface{}) {
 	return
 }
 
-func assertI2E(inter *interfacetype, i fInterface) (r interface{}) {
+func assertI2E(inter *interfacetype, i fInterface, r *interface{}) {
 	ip := (*iface)(unsafe.Pointer(&i))
 	tab := ip.tab
 	if tab == nil {
 		// explicit conversions require non-nil interface value.
 		panic(&TypeAssertionError{"", "", *inter.typ._string, ""})
 	}
-	rp := (*eface)(unsafe.Pointer(&r))
+	rp := (*eface)(unsafe.Pointer(r))
 	rp._type = tab._type
 	rp.data = ip.data
 	return
 }
 
-func assertI2E2(inter *interfacetype, i fInterface) (r interface{}, ok bool) {
+// 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
+		return false
 	}
-	rp := (*eface)(unsafe.Pointer(&r))
+	rp := (*eface)(unsafe.Pointer(r))
 	rp._type = tab._type
 	rp.data = ip.data
-	ok = true
-	return
+	return true
 }
 
 func convI2I(inter *interfacetype, i fInterface) (r fInterface) {
@@ -312,14 +304,14 @@ func convI2I(inter *interfacetype, i fInterface) (r fInterface) {
 	return
 }
 
-func assertI2I(inter *interfacetype, i fInterface) (r fInterface) {
+func assertI2I(inter *interfacetype, i fInterface, r *fInterface) {
 	ip := (*iface)(unsafe.Pointer(&i))
 	tab := ip.tab
 	if tab == nil {
 		// explicit conversions require non-nil interface value.
 		panic(&TypeAssertionError{"", "", *inter.typ._string, ""})
 	}
-	rp := (*iface)(unsafe.Pointer(&r))
+	rp := (*iface)(unsafe.Pointer(r))
 	if tab.inter == inter {
 		rp.tab = tab
 		rp.data = ip.data
@@ -327,84 +319,98 @@ func assertI2I(inter *interfacetype, i fInterface) (r fInterface) {
 	}
 	rp.tab = getitab(inter, tab._type, false)
 	rp.data = ip.data
-	return
 }
 
-func assertI2I2(inter *interfacetype, i fInterface) (r fInterface, ok bool) {
+func assertI2I2(inter *interfacetype, i fInterface, r *fInterface) bool {
 	ip := (*iface)(unsafe.Pointer(&i))
 	tab := ip.tab
 	if tab == nil {
-		return
+		if r != nil {
+			*r = nil
+		}
+		return false
 	}
-	rp := (*iface)(unsafe.Pointer(&r))
-	if tab.inter == inter {
+	if tab.inter != inter {
+		tab = getitab(inter, tab._type, true)
+		if tab == nil {
+			if r != nil {
+				*r = nil
+			}
+			return false
+		}
+	}
+	if r != nil {
+		rp := (*iface)(unsafe.Pointer(r))
 		rp.tab = tab
 		rp.data = ip.data
-		ok = true
-		return
-	}
-	tab = getitab(inter, tab._type, true)
-	if tab == nil {
-		rp.data = nil
-		rp.tab = nil
-		ok = false
-		return
 	}
-	rp.tab = tab
-	rp.data = ip.data
-	ok = true
-	return
+	return true
 }
 
-func assertE2I(inter *interfacetype, e interface{}) (r fInterface) {
+func assertE2I(inter *interfacetype, e interface{}, r *fInterface) {
 	ep := (*eface)(unsafe.Pointer(&e))
 	t := ep._type
 	if t == nil {
 		// explicit conversions require non-nil interface value.
 		panic(&TypeAssertionError{"", "", *inter.typ._string, ""})
 	}
-	rp := (*iface)(unsafe.Pointer(&r))
+	rp := (*iface)(unsafe.Pointer(r))
 	rp.tab = getitab(inter, t, false)
 	rp.data = ep.data
-	return
 }
 
-func assertE2I2(inter *interfacetype, e interface{}) (r fInterface, ok bool) {
+var testingAssertE2I2GC bool
+
+func assertE2I2(inter *interfacetype, e interface{}, r *fInterface) bool {
+	if testingAssertE2I2GC {
+		GC()
+	}
 	ep := (*eface)(unsafe.Pointer(&e))
 	t := ep._type
 	if t == nil {
-		return
+		if r != nil {
+			*r = nil
+		}
+		return false
 	}
 	tab := getitab(inter, t, true)
 	if tab == nil {
-		return
+		if r != nil {
+			*r = nil
+		}
+		return false
 	}
-	rp := (*iface)(unsafe.Pointer(&r))
-	rp.tab = tab
-	rp.data = ep.data
-	ok = true
-	return
+	if r != nil {
+		rp := (*iface)(unsafe.Pointer(r))
+		rp.tab = tab
+		rp.data = ep.data
+	}
+	return true
 }
 
+//go:linkname reflect_ifaceE2I reflect.ifaceE2I
 func reflect_ifaceE2I(inter *interfacetype, e interface{}, dst *fInterface) {
-	*dst = assertE2I(inter, e)
+	assertE2I(inter, e, dst)
 }
 
-func assertE2E(inter *interfacetype, e interface{}) interface{} {
+func assertE2E(inter *interfacetype, e interface{}, r *interface{}) {
 	ep := (*eface)(unsafe.Pointer(&e))
 	if ep._type == nil {
 		// explicit conversions require non-nil interface value.
 		panic(&TypeAssertionError{"", "", *inter.typ._string, ""})
 	}
-	return e
+	*r = e
 }
 
-func assertE2E2(inter *interfacetype, e interface{}) (interface{}, bool) {
+// 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 {
-		return nil, false
+		*r = nil
+		return false
 	}
-	return e, true
+	*r = e
+	return true
 }
 
 func ifacethash(i fInterface) uint32 {
@@ -432,8 +438,3 @@ func iterate_itabs(fn func(*itab)) {
 		}
 	}
 }
-
-func ifaceE2I2(inter *interfacetype, e interface{}, r *fInterface) (ok bool) {
-	*r, ok = assertE2I2(inter, e)
-	return
-}
diff --git a/src/runtime/iface_test.go b/src/runtime/iface_test.go
index bca0ea0..7f27baa 100644
--- a/src/runtime/iface_test.go
+++ b/src/runtime/iface_test.go
@@ -5,6 +5,7 @@
 package runtime_test
 
 import (
+	"runtime"
 	"testing"
 )
 
@@ -36,8 +37,50 @@ var (
 	ts TS
 	tm TM
 	tl TL
+	ok bool
 )
 
+// Issue 9370
+func TestCmpIfaceConcreteAlloc(t *testing.T) {
+	if runtime.Compiler != "gc" {
+		t.Skip("skipping on non-gc compiler")
+	}
+
+	n := testing.AllocsPerRun(1, func() {
+		_ = e == ts
+		_ = i1 == ts
+		_ = e == 1
+	})
+
+	if n > 0 {
+		t.Fatalf("iface cmp allocs=%v; want 0", n)
+	}
+}
+
+func BenchmarkEqEfaceConcrete(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		_ = e == ts
+	}
+}
+
+func BenchmarkEqIfaceConcrete(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		_ = i1 == ts
+	}
+}
+
+func BenchmarkNeEfaceConcrete(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		_ = e != ts
+	}
+}
+
+func BenchmarkNeIfaceConcrete(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		_ = i1 != ts
+	}
+}
+
 func BenchmarkConvT2ESmall(b *testing.B) {
 	for i := 0; i < b.N; i++ {
 		e = ts
@@ -136,3 +179,85 @@ func BenchmarkAssertE2E(b *testing.B) {
 		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.c b/src/runtime/lfstack.c
deleted file mode 100644
index 57e0af2..0000000
--- a/src/runtime/lfstack.c
+++ /dev/null
@@ -1,87 +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.
-
-// Lock-free stack.
-// The following code runs only on g0 stack.
-
-#include "runtime.h"
-#include "arch_GOARCH.h"
-
-#ifdef _64BIT
-// Amd64 uses 48-bit virtual addresses, 47-th bit is used as kernel/user flag.
-// So we use 17msb of pointers as ABA counter.
-# define PTR_BITS 47
-#else
-# define PTR_BITS 32
-#endif
-#define PTR_MASK ((1ull<<PTR_BITS)-1)
-#define CNT_MASK (0ull-1)
-
-#ifdef _64BIT
-#ifdef GOOS_solaris
-// SPARC64 and Solaris on AMD64 uses all 64 bits of virtual addresses.
-// Use low-order three bits as ABA counter.
-// http://docs.oracle.com/cd/E19120-01/open.solaris/816-5138/6mba6ua5p/index.html
-#undef PTR_BITS
-#undef CNT_MASK
-#undef PTR_MASK
-#define PTR_BITS 0
-#define CNT_MASK 7
-#define PTR_MASK ((0ull-1)<<3)
-#endif
-#endif
-
-void
-runtime·lfstackpush(uint64 *head, LFNode *node)
-{
-	uint64 old, new;
-
-	if((uintptr)node != ((uintptr)node&PTR_MASK)) {
-		runtime·printf("p=%p\n", node);
-		runtime·throw("runtime·lfstackpush: invalid pointer");
-	}
-
-	node->pushcnt++;
-	new = (uint64)(uintptr)node|(((uint64)node->pushcnt&CNT_MASK)<<PTR_BITS);
-	for(;;) {
-		old = runtime·atomicload64(head);
-		node->next = (LFNode*)(uintptr)(old&PTR_MASK);
-		if(runtime·cas64(head, old, new))
-			break;
-	}
-}
-
-LFNode*
-runtime·lfstackpop(uint64 *head)
-{
-	LFNode *node, *node2;
-	uint64 old, new;
-
-	for(;;) {
-		old = runtime·atomicload64(head);
-		if(old == 0)
-			return nil;
-		node = (LFNode*)(uintptr)(old&PTR_MASK);
-		node2 = runtime·atomicloadp(&node->next);
-		new = 0;
-		if(node2 != nil)
-			new = (uint64)(uintptr)node2|(((uint64)node2->pushcnt&CNT_MASK)<<PTR_BITS);
-		if(runtime·cas64(head, old, new))
-			return node;
-	}
-}
-
-void
-runtime·lfstackpush_m(void)
-{
-	runtime·lfstackpush(g->m->ptrarg[0], g->m->ptrarg[1]);
-	g->m->ptrarg[0] = nil;
-	g->m->ptrarg[1] = nil;
-}
-
-void
-runtime·lfstackpop_m(void)
-{
-	g->m->ptrarg[0] = runtime·lfstackpop(g->m->ptrarg[0]);
-}
diff --git a/src/runtime/lfstack.go b/src/runtime/lfstack.go
new file mode 100644
index 0000000..5838c1d
--- /dev/null
+++ b/src/runtime/lfstack.go
@@ -0,0 +1,40 @@
+// 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.
+
+// Lock-free stack.
+// The following code runs only on g0 stack.
+
+package runtime
+
+import "unsafe"
+
+func lfstackpush(head *uint64, node *lfnode) {
+	node.pushcnt++
+	new := lfstackPack(node, node.pushcnt)
+	if node1, _ := lfstackUnpack(new); node1 != node {
+		println("runtime: lfstackpush invalid packing: node=", node, " cnt=", hex(node.pushcnt), " packed=", hex(new), " -> node=", node1, "\n")
+		throw("lfstackpush")
+	}
+	for {
+		old := atomicload64(head)
+		node.next = old
+		if cas64(head, old, new) {
+			break
+		}
+	}
+}
+
+func lfstackpop(head *uint64) unsafe.Pointer {
+	for {
+		old := atomicload64(head)
+		if old == 0 {
+			return nil
+		}
+		node, _ := lfstackUnpack(old)
+		next := atomicload64(&node.next)
+		if cas64(head, old, next) {
+			return unsafe.Pointer(node)
+		}
+	}
+}
diff --git a/src/runtime/lfstack_32bit.go b/src/runtime/lfstack_32bit.go
new file mode 100644
index 0000000..4b8bcba
--- /dev/null
+++ b/src/runtime/lfstack_32bit.go
@@ -0,0 +1,21 @@
+// 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 386 arm nacl
+
+package runtime
+
+import "unsafe"
+
+// On 32-bit systems, the stored uint64 has a 32-bit pointer and 32-bit count.
+
+func lfstackPack(node *lfnode, cnt uintptr) uint64 {
+	return uint64(uintptr(unsafe.Pointer(node)))<<32 | uint64(cnt)
+}
+
+func lfstackUnpack(val uint64) (node *lfnode, cnt uintptr) {
+	node = (*lfnode)(unsafe.Pointer(uintptr(val >> 32)))
+	cnt = uintptr(val)
+	return
+}
diff --git a/src/runtime/lfstack_amd64.go b/src/runtime/lfstack_amd64.go
new file mode 100644
index 0000000..84e2851
--- /dev/null
+++ b/src/runtime/lfstack_amd64.go
@@ -0,0 +1,24 @@
+// 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"
+
+// On AMD64, virtual addresses are 48-bit numbers sign extended to 64.
+// We shift the address left 16 to eliminate the sign extended part and make
+// room in the bottom for the count.
+// 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.
+
+func lfstackPack(node *lfnode, cnt uintptr) uint64 {
+	return uint64(uintptr(unsafe.Pointer(node)))<<16 | uint64(cnt&(1<<19-1))
+}
+
+func lfstackUnpack(val uint64) (node *lfnode, cnt uintptr) {
+	node = (*lfnode)(unsafe.Pointer(uintptr(int64(val) >> 19 << 3)))
+	cnt = uintptr(val & (1<<19 - 1))
+	return
+}
diff --git a/src/runtime/lfstack_darwin_arm64.go b/src/runtime/lfstack_darwin_arm64.go
new file mode 100644
index 0000000..54cae39
--- /dev/null
+++ b/src/runtime/lfstack_darwin_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/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/lfstack_linux_ppc64x.go b/src/runtime/lfstack_linux_ppc64x.go
new file mode 100644
index 0000000..7ed5025
--- /dev/null
+++ b/src/runtime/lfstack_linux_ppc64x.go
@@ -0,0 +1,32 @@
+// 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 ppc64 ppc64le
+// +build linux
+
+package runtime
+
+import "unsafe"
+
+// On ppc64, Linux limits the user address space to 46 bits (see
+// TASK_SIZE_USER64 in the Linux kernel).  This has grown over time,
+// so here we allow 48 bit addresses.
+//
+// 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/lfstack_test.go b/src/runtime/lfstack_test.go
index e518777..fb4b459 100644
--- a/src/runtime/lfstack_test.go
+++ b/src/runtime/lfstack_test.go
@@ -24,9 +24,13 @@ func toMyNode(node *LFNode) *MyNode {
 	return (*MyNode)(unsafe.Pointer(node))
 }
 
+var global interface{}
+
 func TestLFStack(t *testing.T) {
 	stack := new(uint64)
-	// Need to keep additional referenfces to nodes, the stack is not all that type-safe.
+	global = stack // force heap allocation
+
+	// Need to keep additional references to nodes, the stack is not all that type-safe.
 	var nodes []*MyNode
 
 	// Check the stack is initially empty.
@@ -121,7 +125,7 @@ func TestLFStackStress(t *testing.T) {
 			}
 			cnt++
 			sum2 += node.data
-			node.Next = nil
+			node.Next = 0
 		}
 	}
 	if cnt != K {
diff --git a/src/runtime/lock_futex.go b/src/runtime/lock_futex.go
index 7259623..768fd57 100644
--- a/src/runtime/lock_futex.go
+++ b/src/runtime/lock_futex.go
@@ -34,9 +34,6 @@ const (
 // Note that there can be spinning threads during all states - they do not
 // affect mutex's state.
 
-func futexsleep(addr *uint32, val uint32, ns int64)
-func futexwakeup(addr *uint32, cnt uint32)
-
 // We use the uintptr mutex.key and note.key as a uint32.
 func key32(p *uintptr) *uint32 {
 	return (*uint32)(unsafe.Pointer(p))
@@ -46,7 +43,7 @@ func lock(l *mutex) {
 	gp := getg()
 
 	if gp.m.locks < 0 {
-		gothrow("runtime·lock: lock count")
+		throw("runtime·lock: lock count")
 	}
 	gp.m.locks++
 
@@ -105,7 +102,7 @@ func lock(l *mutex) {
 func unlock(l *mutex) {
 	v := xchg(key32(&l.key), mutex_unlocked)
 	if v == mutex_unlocked {
-		gothrow("unlock of unlocked lock")
+		throw("unlock of unlocked lock")
 	}
 	if v == mutex_sleeping {
 		futexwakeup(key32(&l.key), 1)
@@ -114,7 +111,7 @@ func unlock(l *mutex) {
 	gp := getg()
 	gp.m.locks--
 	if gp.m.locks < 0 {
-		gothrow("runtime·unlock: lock count")
+		throw("runtime·unlock: lock count")
 	}
 	if gp.m.locks == 0 && gp.preempt { // restore the preemption request in case we've cleared it in newstack
 		gp.stackguard0 = stackPreempt
@@ -130,7 +127,7 @@ func notewakeup(n *note) {
 	old := xchg(key32(&n.key), 1)
 	if old != 0 {
 		print("notewakeup - double wakeup (", old, ")\n")
-		gothrow("notewakeup - double wakeup")
+		throw("notewakeup - double wakeup")
 	}
 	futexwakeup(key32(&n.key), 1)
 }
@@ -138,7 +135,7 @@ func notewakeup(n *note) {
 func notesleep(n *note) {
 	gp := getg()
 	if gp != gp.m.g0 {
-		gothrow("notesleep not on g0")
+		throw("notesleep not on g0")
 	}
 	for atomicload(key32(&n.key)) == 0 {
 		gp.m.blocked = true
@@ -147,7 +144,11 @@ func notesleep(n *note) {
 	}
 }
 
+// May run with m.p==nil if called from notetsleep, so write barriers
+// are not allowed.
+//
 //go:nosplit
+//go:nowritebarrier
 func notetsleep_internal(n *note, ns int64) bool {
 	gp := getg()
 
@@ -183,8 +184,8 @@ func notetsleep_internal(n *note, ns int64) bool {
 
 func notetsleep(n *note, ns int64) bool {
 	gp := getg()
-	if gp != gp.m.g0 && gp.m.gcing == 0 {
-		gothrow("notetsleep not on g0")
+	if gp != gp.m.g0 && gp.m.preemptoff != "" {
+		throw("notetsleep not on g0")
 	}
 
 	return notetsleep_internal(n, ns)
@@ -195,11 +196,11 @@ func notetsleep(n *note, ns int64) bool {
 func notetsleepg(n *note, ns int64) bool {
 	gp := getg()
 	if gp == gp.m.g0 {
-		gothrow("notetsleepg on g0")
+		throw("notetsleepg on g0")
 	}
 
-	entersyscallblock()
+	entersyscallblock(0)
 	ok := notetsleep_internal(n, ns)
-	exitsyscall()
+	exitsyscall(0)
 	return ok
 }
diff --git a/src/runtime/lock_sema.go b/src/runtime/lock_sema.go
index d136b82..d9d91c9 100644
--- a/src/runtime/lock_sema.go
+++ b/src/runtime/lock_sema.go
@@ -31,14 +31,10 @@ const (
 	passive_spin    = 1
 )
 
-func semacreate() uintptr
-func semasleep(int64) int32
-func semawakeup(mp *m)
-
 func lock(l *mutex) {
 	gp := getg()
 	if gp.m.locks < 0 {
-		gothrow("runtime·lock: lock count")
+		throw("runtime·lock: lock count")
 	}
 	gp.m.locks++
 
@@ -76,7 +72,7 @@ Loop:
 			// 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
 				}
@@ -94,6 +90,8 @@ Loop:
 	}
 }
 
+//go:nowritebarrier
+// We might not be holding a p in this code.
 func unlock(l *mutex) {
 	gp := getg()
 	var mp *m
@@ -107,7 +105,7 @@ func unlock(l *mutex) {
 			// 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
@@ -116,7 +114,7 @@ func unlock(l *mutex) {
 	}
 	gp.m.locks--
 	if gp.m.locks < 0 {
-		gothrow("runtime·unlock: lock count")
+		throw("runtime·unlock: lock count")
 	}
 	if gp.m.locks == 0 && gp.preempt { // restore the preemption request in case we've cleared it in newstack
 		gp.stackguard0 = stackPreempt
@@ -144,7 +142,7 @@ func notewakeup(n *note) {
 		// Nothing was waiting. Done.
 	case v == locked:
 		// Two notewakeups!  Not allowed.
-		gothrow("notewakeup - double wakeup")
+		throw("notewakeup - double wakeup")
 	default:
 		// Must be the waiting m.  Wake it up.
 		semawakeup((*m)(unsafe.Pointer(v)))
@@ -154,7 +152,7 @@ func notewakeup(n *note) {
 func notesleep(n *note) {
 	gp := getg()
 	if gp != gp.m.g0 {
-		gothrow("notesleep not on g0")
+		throw("notesleep not on g0")
 	}
 	if gp.m.waitsema == 0 {
 		gp.m.waitsema = semacreate()
@@ -162,7 +160,7 @@ func notesleep(n *note) {
 	if !casuintptr(&n.key, 0, uintptr(unsafe.Pointer(gp.m))) {
 		// Must be locked (got wakeup).
 		if n.key != locked {
-			gothrow("notesleep - waitm out of sync")
+			throw("notesleep - waitm out of sync")
 		}
 		return
 	}
@@ -184,7 +182,7 @@ func notetsleep_internal(n *note, ns int64, gp *g, deadline int64) bool {
 	if !casuintptr(&n.key, 0, uintptr(unsafe.Pointer(gp.m))) {
 		// Must be locked (got wakeup).
 		if n.key != locked {
-			gothrow("notetsleep - waitm out of sync")
+			throw("notetsleep - waitm out of sync")
 		}
 		return true
 	}
@@ -232,20 +230,20 @@ func notetsleep_internal(n *note, ns int64, gp *g, deadline int64) bool {
 			// Grab it to avoid getting out of sync.
 			gp.m.blocked = true
 			if semasleep(-1) < 0 {
-				gothrow("runtime: unable to acquire - semaphore out of sync")
+				throw("runtime: unable to acquire - semaphore out of sync")
 			}
 			gp.m.blocked = false
 			return true
 		default:
-			gothrow("runtime: unexpected waitm - semaphore out of sync")
+			throw("runtime: unexpected waitm - semaphore out of sync")
 		}
 	}
 }
 
 func notetsleep(n *note, ns int64) bool {
 	gp := getg()
-	if gp != gp.m.g0 && gp.m.gcing == 0 {
-		gothrow("notetsleep not on g0")
+	if gp != gp.m.g0 && gp.m.preemptoff != "" {
+		throw("notetsleep not on g0")
 	}
 	if gp.m.waitsema == 0 {
 		gp.m.waitsema = semacreate()
@@ -258,13 +256,13 @@ func notetsleep(n *note, ns int64) bool {
 func notetsleepg(n *note, ns int64) bool {
 	gp := getg()
 	if gp == gp.m.g0 {
-		gothrow("notetsleepg on g0")
+		throw("notetsleepg on g0")
 	}
 	if gp.m.waitsema == 0 {
 		gp.m.waitsema = semacreate()
 	}
-	entersyscallblock()
+	entersyscallblock(0)
 	ok := notetsleep_internal(n, ns, nil, 0)
-	exitsyscall()
+	exitsyscall(0)
 	return ok
 }
diff --git a/src/runtime/malloc.c b/src/runtime/malloc.c
deleted file mode 100644
index b79c30b..0000000
--- a/src/runtime/malloc.c
+++ /dev/null
@@ -1,396 +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.
-
-// See malloc.h for overview.
-//
-// TODO(rsc): double-check stats.
-
-#include "runtime.h"
-#include "arch_GOARCH.h"
-#include "malloc.h"
-#include "type.h"
-#include "typekind.h"
-#include "race.h"
-#include "stack.h"
-#include "textflag.h"
-
-// Mark mheap as 'no pointers', it does not contain interesting pointers but occupies ~45K.
-#pragma dataflag NOPTR
-MHeap runtime·mheap;
-#pragma dataflag NOPTR
-MStats runtime·memstats;
-
-int32
-runtime·mlookup(void *v, byte **base, uintptr *size, MSpan **sp)
-{
-	uintptr n, i;
-	byte *p;
-	MSpan *s;
-
-	g->m->mcache->local_nlookup++;
-	if (sizeof(void*) == 4 && g->m->mcache->local_nlookup >= (1<<30)) {
-		// purge cache stats to prevent overflow
-		runtime·lock(&runtime·mheap.lock);
-		runtime·purgecachedstats(g->m->mcache);
-		runtime·unlock(&runtime·mheap.lock);
-	}
-
-	s = runtime·MHeap_LookupMaybe(&runtime·mheap, v);
-	if(sp)
-		*sp = s;
-	if(s == nil) {
-		if(base)
-			*base = nil;
-		if(size)
-			*size = 0;
-		return 0;
-	}
-
-	p = (byte*)((uintptr)s->start<<PageShift);
-	if(s->sizeclass == 0) {
-		// Large object.
-		if(base)
-			*base = p;
-		if(size)
-			*size = s->npages<<PageShift;
-		return 1;
-	}
-
-	n = s->elemsize;
-	if(base) {
-		i = ((byte*)v - p)/n;
-		*base = p + i*n;
-	}
-	if(size)
-		*size = n;
-
-	return 1;
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·purgecachedstats(MCache *c)
-{
-	MHeap *h;
-	int32 i;
-
-	// Protected by either heap or GC lock.
-	h = &runtime·mheap;
-	mstats.heap_alloc += c->local_cachealloc;
-	c->local_cachealloc = 0;
-	mstats.tinyallocs += c->local_tinyallocs;
-	c->local_tinyallocs = 0;
-	mstats.nlookup += c->local_nlookup;
-	c->local_nlookup = 0;
-	h->largefree += c->local_largefree;
-	c->local_largefree = 0;
-	h->nlargefree += c->local_nlargefree;
-	c->local_nlargefree = 0;
-	for(i=0; i<nelem(c->local_nsmallfree); i++) {
-		h->nsmallfree[i] += c->local_nsmallfree[i];
-		c->local_nsmallfree[i] = 0;
-	}
-}
-
-// Size of the trailing by_size array differs between Go and C,
-// and all data after by_size is local to C, not exported to Go.
-// NumSizeClasses was changed, but we can not change Go struct because of backward compatibility.
-// sizeof_C_MStats is what C thinks about size of Go struct.
-uintptr runtime·sizeof_C_MStats = offsetof(MStats, by_size[61]);
-
-#define MaxArena32 (2U<<30)
-
-// For use by Go. If it were a C enum it would be made available automatically,
-// but the value of MaxMem is too large for enum.
-uintptr runtime·maxmem = MaxMem;
-
-void
-runtime·mallocinit(void)
-{
-	byte *p, *p1;
-	uintptr arena_size, bitmap_size, spans_size, p_size;
-	extern byte runtime·end[];
-	uintptr limit;
-	uint64 i;
-	bool reserved;
-
-	p = nil;
-	p_size = 0;
-	arena_size = 0;
-	bitmap_size = 0;
-	spans_size = 0;
-	reserved = false;
-
-	// for 64-bit build
-	USED(p);
-	USED(p_size);
-	USED(arena_size);
-	USED(bitmap_size);
-	USED(spans_size);
-
-	runtime·InitSizes();
-
-	if(runtime·class_to_size[TinySizeClass] != TinySize)
-		runtime·throw("bad TinySizeClass");
-
-	// limit = runtime·memlimit();
-	// See https://code.google.com/p/go/issues/detail?id=5049
-	// TODO(rsc): Fix after 1.1.
-	limit = 0;
-
-	// Set up the allocation arena, a contiguous area of memory where
-	// allocated data will be found.  The arena begins with a bitmap large
-	// enough to hold 4 bits per allocated word.
-	if(sizeof(void*) == 8 && (limit == 0 || limit > (1<<30))) {
-		// On a 64-bit machine, allocate from a single contiguous reservation.
-		// 128 GB (MaxMem) should be big enough for now.
-		//
-		// The code will work with the reservation at any address, but ask
-		// SysReserve to use 0x0000XXc000000000 if possible (XX=00...7f).
-		// Allocating a 128 GB region takes away 37 bits, and the amd64
-		// doesn't let us choose the top 17 bits, so that leaves the 11 bits
-		// in the middle of 0x00c0 for us to choose.  Choosing 0x00c0 means
-		// that the valid memory addresses will begin 0x00c0, 0x00c1, ..., 0x00df.
-		// In little-endian, that's c0 00, c1 00, ..., df 00. None of those are valid
-		// UTF-8 sequences, and they are otherwise as far away from 
-		// ff (likely a common byte) as possible.  If that fails, we try other 0xXXc0
-		// addresses.  An earlier attempt to use 0x11f8 caused out of memory errors
-		// on OS X during thread allocations.  0x00c0 causes conflicts with
-		// AddressSanitizer which reserves all memory up to 0x0100.
-		// These choices are both for debuggability and to reduce the
-		// odds of the conservative garbage collector not collecting memory
-		// because some non-pointer block of memory had a bit pattern
-		// that matched a memory address.
-		//
-		// Actually we reserve 136 GB (because the bitmap ends up being 8 GB)
-		// but it hardly matters: e0 00 is not valid UTF-8 either.
-		//
-		// If this fails we fall back to the 32 bit memory mechanism
-		arena_size = MaxMem;
-		bitmap_size = arena_size / (sizeof(void*)*8/4);
-		spans_size = arena_size / PageSize * sizeof(runtime·mheap.spans[0]);
-		spans_size = ROUND(spans_size, PageSize);
-		for(i = 0; i <= 0x7f; i++) {
-			p = (void*)(i<<40 | 0x00c0ULL<<32);
-			p_size = bitmap_size + spans_size + arena_size + PageSize;
-			p = runtime·SysReserve(p, p_size, &reserved);
-			if(p != nil)
-				break;
-		}
-	}
-	if (p == nil) {
-		// On a 32-bit machine, we can't typically get away
-		// with a giant virtual address space reservation.
-		// Instead we map the memory information bitmap
-		// immediately after the data segment, large enough
-		// to handle another 2GB of mappings (256 MB),
-		// along with a reservation for another 512 MB of memory.
-		// When that gets used up, we'll start asking the kernel
-		// for any memory anywhere and hope it's in the 2GB
-		// following the bitmap (presumably the executable begins
-		// near the bottom of memory, so we'll have to use up
-		// most of memory before the kernel resorts to giving out
-		// memory before the beginning of the text segment).
-		//
-		// Alternatively we could reserve 512 MB bitmap, enough
-		// for 4GB of mappings, and then accept any memory the
-		// kernel threw at us, but normally that's a waste of 512 MB
-		// of address space, which is probably too much in a 32-bit world.
-		bitmap_size = MaxArena32 / (sizeof(void*)*8/4);
-		arena_size = 512<<20;
-		spans_size = MaxArena32 / PageSize * sizeof(runtime·mheap.spans[0]);
-		if(limit > 0 && arena_size+bitmap_size+spans_size > limit) {
-			bitmap_size = (limit / 9) & ~((1<<PageShift) - 1);
-			arena_size = bitmap_size * 8;
-			spans_size = arena_size / PageSize * sizeof(runtime·mheap.spans[0]);
-		}
-		spans_size = ROUND(spans_size, PageSize);
-
-		// SysReserve treats the address we ask for, end, as a hint,
-		// not as an absolute requirement.  If we ask for the end
-		// of the data segment but the operating system requires
-		// a little more space before we can start allocating, it will
-		// give out a slightly higher pointer.  Except QEMU, which
-		// is buggy, as usual: it won't adjust the pointer upward.
-		// 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 = (byte*)ROUND((uintptr)runtime·end + (1<<18), 1<<20);
-		p_size = bitmap_size + spans_size + arena_size + PageSize;
-		p = runtime·SysReserve(p, p_size, &reserved);
-		if(p == nil)
-			runtime·throw("runtime: cannot reserve arena virtual address space");
-	}
-
-	// PageSize can be larger than OS definition of page size,
-	// so SysReserve can give us a PageSize-unaligned pointer.
-	// To overcome this we ask for PageSize more and round up the pointer.
-	p1 = (byte*)ROUND((uintptr)p, PageSize);
-
-	runtime·mheap.spans = (MSpan**)p1;
-	runtime·mheap.bitmap = p1 + spans_size;
-	runtime·mheap.arena_start = p1 + spans_size + bitmap_size;
-	runtime·mheap.arena_used = runtime·mheap.arena_start;
-	runtime·mheap.arena_end = p + p_size;
-	runtime·mheap.arena_reserved = reserved;
-
-	if(((uintptr)runtime·mheap.arena_start & (PageSize-1)) != 0)
-		runtime·throw("misrounded allocation in mallocinit");
-
-	// Initialize the rest of the allocator.	
-	runtime·MHeap_Init(&runtime·mheap);
-	g->m->mcache = runtime·allocmcache();
-}
-
-void*
-runtime·MHeap_SysAlloc(MHeap *h, uintptr n)
-{
-	byte *p, *p_end;
-	uintptr p_size;
-	bool reserved;
-
-	if(n > h->arena_end - h->arena_used) {
-		// We are in 32-bit mode, maybe we didn't use all possible address space yet.
-		// Reserve some more space.
-		byte *new_end;
-
-		p_size = ROUND(n + PageSize, 256<<20);
-		new_end = h->arena_end + p_size;
-		if(new_end <= h->arena_start + MaxArena32) {
-			// TODO: It would be bad if part of the arena
-			// is reserved and part is not.
-			p = runtime·SysReserve(h->arena_end, p_size, &reserved);
-			if(p == h->arena_end) {
-				h->arena_end = new_end;
-				h->arena_reserved = reserved;
-			}
-			else if(p+p_size <= h->arena_start + MaxArena32) {
-				// Keep everything page-aligned.
-				// Our pages are bigger than hardware pages.
-				h->arena_end = p+p_size;
-				h->arena_used = p + (-(uintptr)p&(PageSize-1));
-				h->arena_reserved = reserved;
-			} else {
-				uint64 stat;
-				stat = 0;
-				runtime·SysFree(p, p_size, &stat);
-			}
-		}
-	}
-	if(n <= h->arena_end - h->arena_used) {
-		// Keep taking from our reservation.
-		p = h->arena_used;
-		runtime·SysMap(p, n, h->arena_reserved, &mstats.heap_sys);
-		h->arena_used += n;
-		runtime·MHeap_MapBits(h);
-		runtime·MHeap_MapSpans(h);
-		if(raceenabled)
-			runtime·racemapshadow(p, n);
-		
-		if(((uintptr)p & (PageSize-1)) != 0)
-			runtime·throw("misrounded allocation in MHeap_SysAlloc");
-		return p;
-	}
-	
-	// If using 64-bit, our reservation is all we have.
-	if(h->arena_end - h->arena_start >= MaxArena32)
-		return nil;
-
-	// On 32-bit, once the reservation is gone we can
-	// try to get memory at a location chosen by the OS
-	// and hope that it is in the range we allocated bitmap for.
-	p_size = ROUND(n, PageSize) + PageSize;
-	p = runtime·sysAlloc(p_size, &mstats.heap_sys);
-	if(p == nil)
-		return nil;
-
-	if(p < h->arena_start || p+p_size - h->arena_start >= MaxArena32) {
-		runtime·printf("runtime: memory allocated by OS (%p) not in usable range [%p,%p)\n",
-			p, h->arena_start, h->arena_start+MaxArena32);
-		runtime·SysFree(p, p_size, &mstats.heap_sys);
-		return nil;
-	}
-	
-	p_end = p + p_size;
-	p += -(uintptr)p & (PageSize-1);
-	if(p+n > h->arena_used) {
-		h->arena_used = p+n;
-		if(p_end > h->arena_end)
-			h->arena_end = p_end;
-		runtime·MHeap_MapBits(h);
-		runtime·MHeap_MapSpans(h);
-		if(raceenabled)
-			runtime·racemapshadow(p, n);
-	}
-	
-	if(((uintptr)p & (PageSize-1)) != 0)
-		runtime·throw("misrounded allocation in MHeap_SysAlloc");
-	return p;
-}
-
-void
-runtime·setFinalizer_m(void)
-{
-	FuncVal *fn;
-	void *arg;
-	uintptr nret;
-	Type *fint;
-	PtrType *ot;
-
-	fn = g->m->ptrarg[0];
-	arg = g->m->ptrarg[1];
-	nret = g->m->scalararg[0];
-	fint = g->m->ptrarg[2];
-	ot = g->m->ptrarg[3];
-	g->m->ptrarg[0] = nil;
-	g->m->ptrarg[1] = nil;
-	g->m->ptrarg[2] = nil;
-	g->m->ptrarg[3] = nil;
-
-	g->m->scalararg[0] = runtime·addfinalizer(arg, fn, nret, fint, ot);
-}
-
-void
-runtime·removeFinalizer_m(void)
-{
-	void *p;
-
-	p = g->m->ptrarg[0];
-	g->m->ptrarg[0] = nil;
-	runtime·removefinalizer(p);
-}
-
-// mcallable cache refill
-void 
-runtime·mcacheRefill_m(void)
-{
-	runtime·MCache_Refill(g->m->mcache, (int32)g->m->scalararg[0]);
-}
-
-void
-runtime·largeAlloc_m(void)
-{
-	uintptr npages, size;
-	MSpan *s;
-	void *v;
-	int32 flag;
-
-	//runtime·printf("largeAlloc size=%D\n", g->m->scalararg[0]);
-	// Allocate directly from heap.
-	size = g->m->scalararg[0];
-	flag = (int32)g->m->scalararg[1];
-	if(size + PageSize < size)
-		runtime·throw("out of memory");
-	npages = size >> PageShift;
-	if((size & PageMask) != 0)
-		npages++;
-	s = runtime·MHeap_Alloc(&runtime·mheap, npages, 0, 1, !(flag & FlagNoZero));
-	if(s == nil)
-		runtime·throw("out of memory");
-	s->limit = (byte*)(s->start<<PageShift) + size;
-	v = (void*)(s->start << PageShift);
-	// setup for mark sweep
-	runtime·markspan(v, 0, 0, true);
-	g->m->ptrarg[0] = s;
-}
diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go
index 1170449..353f840 100644
--- a/src/runtime/malloc.go
+++ b/src/runtime/malloc.go
@@ -2,11 +2,87 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
+// Memory allocator, based on tcmalloc.
+// http://goog-perftools.sourceforge.net/doc/tcmalloc.html
+
+// The main allocator works in runs of pages.
+// Small allocation sizes (up to and including 32 kB) are
+// rounded to one of about 100 size classes, each of which
+// has its own free list of objects of exactly that size.
+// Any free page of memory can be split into a set of objects
+// of one size class, which are then managed using free list
+// allocators.
+//
+// The allocator's data structures are:
+//
+//	FixAlloc: a free-list allocator for fixed-size objects,
+//		used to manage storage used by the allocator.
+//	MHeap: the malloc heap, managed at page (4096-byte) granularity.
+//	MSpan: a run of pages managed by the MHeap.
+//	MCentral: a shared free list for a given size class.
+//	MCache: a per-thread (in Go, per-P) cache for small objects.
+//	MStats: allocation statistics.
+//
+// Allocating a small object proceeds up a hierarchy of caches:
+//
+//	1. Round the size up to one of the small size classes
+//	   and look in the corresponding MCache free list.
+//	   If the list is not empty, allocate an object from it.
+//	   This can all be done without acquiring a lock.
+//
+//	2. If the MCache free list is empty, replenish it by
+//	   taking a bunch of objects from the MCentral free list.
+//	   Moving a bunch amortizes the cost of acquiring the MCentral lock.
+//
+//	3. If the MCentral free list is empty, replenish it by
+//	   allocating a run of pages from the MHeap and then
+//	   chopping that memory into objects of the given size.
+//	   Allocating many objects amortizes the cost of locking
+//	   the heap.
+//
+//	4. If the MHeap is empty or has no page runs large enough,
+//	   allocate a new group of pages (at least 1MB) from the
+//	   operating system.  Allocating a large run of pages
+//	   amortizes the cost of talking to the operating system.
+//
+// Freeing a small object proceeds up the same hierarchy:
+//
+//	1. Look up the size class for the object and add it to
+//	   the MCache free list.
+//
+//	2. If the MCache free list is too long or the MCache has
+//	   too much memory, return some to the MCentral free lists.
+//
+//	3. If all the objects in a given span have returned to
+//	   the MCentral list, return that span to the page heap.
+//
+//	4. If the heap has too much memory, return some to the
+//	   operating system.
+//
+//	TODO(rsc): Step 4 is not implemented.
+//
+// Allocating and freeing a large object uses the page heap
+// directly, bypassing the MCache and MCentral free lists.
+//
+// The small objects on the MCache and MCentral free lists
+// may or may not be zeroed.  They are zeroed if and only if
+// the second word of the object is zero.  A span in the
+// page heap is zeroed unless s->needzero is set. When a span
+// is allocated to break into small objects, it is zeroed if needed
+// and s->needzero is set. There are two main benefits to delaying the
+// zeroing this way:
+//
+//	1. stack frames allocated from the small object lists
+//	   or the page heap can avoid zeroing altogether.
+//	2. the cost of zeroing when reusing a small object is
+//	   charged to the mutator, not the garbage collector.
+//
+// This code was written with an eye toward translating to Go
+// in the future.  Methods have the form Type_Method(Type *t, ...).
+
 package runtime
 
-import (
-	"unsafe"
-)
+import "unsafe"
 
 const (
 	debugMalloc = false
@@ -22,53 +98,427 @@ const (
 	pageSize  = _PageSize
 	pageMask  = _PageMask
 
-	bitsPerPointer  = _BitsPerPointer
-	bitsMask        = _BitsMask
-	pointersPerByte = _PointersPerByte
-	maxGCMask       = _MaxGCMask
-	bitsDead        = _BitsDead
-	bitsPointer     = _BitsPointer
-
 	mSpanInUse = _MSpanInUse
 
-	concurrentSweep = _ConcurrentSweep != 0
+	concurrentSweep = _ConcurrentSweep
+)
+
+const (
+	_PageShift = 13
+	_PageSize  = 1 << _PageShift
+	_PageMask  = _PageSize - 1
+)
+
+const (
+	// _64bit = 1 on 64-bit systems, 0 on 32-bit systems
+	_64bit = 1 << (^uintptr(0) >> 63) / 2
+
+	// Computed constant.  The definition of MaxSmallSize and the
+	// 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.
+	_NumSizeClasses = 67
+
+	// Tunable constants.
+	_MaxSmallSize = 32 << 10
+
+	// Tiny allocator parameters, see "Tiny allocator" comment in malloc.go.
+	_TinySize      = 16
+	_TinySizeClass = 2
+
+	_FixAllocChunk  = 16 << 10               // Chunk size for FixAlloc
+	_MaxMHeapList   = 1 << (20 - _PageShift) // Maximum page length for fixed-size list in MHeap.
+	_HeapAllocChunk = 1 << 20                // Chunk size for heap growth
+
+	// Per-P, per order stack segment cache size.
+	_StackCacheSize = 32 * 1024
+
+	// Number of orders that get caching.  Order 0 is FixedStack
+	// and each successive order is twice as large.
+	// We want to cache 2KB, 4KB, 8KB, and 16KB stacks.  Larger stacks
+	// will be allocated directly.
+	// Since FixedStack is different on different systems, we
+	// must vary NumStackOrders to keep the same maximum cached size.
+	//   OS               | FixedStack | NumStackOrders
+	//   -----------------+------------+---------------
+	//   linux/darwin/bsd | 2KB        | 4
+	//   windows/32       | 4KB        | 3
+	//   windows/64       | 8KB        | 2
+	//   plan9            | 4KB        | 3
+	_NumStackOrders = 4 - ptrSize/4*goos_windows - 1*goos_plan9
+
+	// Number of bits in page to span calculations (4k pages).
+	// On Windows 64-bit we limit the arena to 32GB or 35 bits.
+	// Windows counts memory used by page table into committed memory
+	// of the process, so we can't reserve too much memory.
+	// See https://golang.org/issue/5402 and https://golang.org/issue/5236.
+	// On other 64-bit platforms, we limit the arena to 512GB, or 39 bits.
+	// On 32-bit, we don't bother limiting anything, so we use the full 32-bit address.
+	// On Darwin/arm64, we cannot reserve more than ~5GB of virtual memory,
+	// but as most devices have less than 4GB of physical memory anyway, we
+	// try to be conservative here, and only ask for a 2GB heap.
+	_MHeapMap_TotalBits = (_64bit*goos_windows)*35 + (_64bit*(1-goos_windows)*(1-goos_darwin*goarch_arm64))*39 + goos_darwin*goarch_arm64*31 + (1-_64bit)*32
+	_MHeapMap_Bits      = _MHeapMap_TotalBits - _PageShift
+
+	_MaxMem = uintptr(1<<_MHeapMap_TotalBits - 1)
+
+	// Max number of threads to run garbage collection.
+	// 2, 3, and 4 are all plausible maximums depending
+	// on the hardware details of the machine.  The garbage
+	// collector scales well to 32 cpus.
+	_MaxGcproc = 32
 )
 
 // Page number (address>>pageShift)
 type pageID uintptr
 
+const _MaxArena32 = 2 << 30
+
+// OS-defined helpers:
+//
+// sysAlloc obtains a large chunk of zeroed memory from the
+// operating system, typically on the order of a hundred kilobytes
+// or a megabyte.
+// NOTE: sysAlloc returns OS-aligned memory, but the heap allocator
+// may use larger alignment, so the caller must be careful to realign the
+// memory obtained by sysAlloc.
+//
+// SysUnused notifies the operating system that the contents
+// of the memory region are no longer needed and can be reused
+// for other purposes.
+// SysUsed notifies the operating system that the contents
+// of the memory region are needed again.
+//
+// SysFree returns it unconditionally; this is only used if
+// an out-of-memory error has been detected midway through
+// an allocation.  It is okay if SysFree is a no-op.
+//
+// SysReserve reserves address space without allocating memory.
+// If the pointer passed to it is non-nil, the caller wants the
+// reservation there, but SysReserve can still choose another
+// location if that one is unavailable.  On some systems and in some
+// cases SysReserve will simply check that the address space is
+// available and not actually reserve it.  If SysReserve returns
+// non-nil, it sets *reserved to true if the address space is
+// reserved, false if it has merely been checked.
+// NOTE: SysReserve returns OS-aligned memory, but the heap allocator
+// may use larger alignment, so the caller must be careful to realign the
+// memory obtained by sysAlloc.
+//
+// SysMap maps previously reserved address space for use.
+// The reserved argument is true if the address space was really
+// reserved, not merely checked.
+//
+// SysFault marks a (already sysAlloc'd) region to fault
+// if accessed.  Used only for debugging the runtime.
+
+func mallocinit() {
+	initSizes()
+
+	if class_to_size[_TinySizeClass] != _TinySize {
+		throw("bad TinySizeClass")
+	}
+
+	var p, bitmapSize, spansSize, pSize, limit uintptr
+	var reserved bool
+
+	// limit = runtime.memlimit();
+	// See https://golang.org/issue/5049
+	// TODO(rsc): Fix after 1.1.
+	limit = 0
+
+	// Set up the allocation arena, a contiguous area of memory where
+	// allocated data will be found.  The arena begins with a bitmap large
+	// enough to hold 4 bits per allocated word.
+	if ptrSize == 8 && (limit == 0 || limit > 1<<30) {
+		// On a 64-bit machine, allocate from a single contiguous reservation.
+		// 512 GB (MaxMem) should be big enough for now.
+		//
+		// The code will work with the reservation at any address, but ask
+		// SysReserve to use 0x0000XXc000000000 if possible (XX=00...7f).
+		// Allocating a 512 GB region takes away 39 bits, and the amd64
+		// doesn't let us choose the top 17 bits, so that leaves the 9 bits
+		// in the middle of 0x00c0 for us to choose.  Choosing 0x00c0 means
+		// that the valid memory addresses will begin 0x00c0, 0x00c1, ..., 0x00df.
+		// In little-endian, that's c0 00, c1 00, ..., df 00. None of those are valid
+		// UTF-8 sequences, and they are otherwise as far away from
+		// ff (likely a common byte) as possible.  If that fails, we try other 0xXXc0
+		// addresses.  An earlier attempt to use 0x11f8 caused out of memory errors
+		// on OS X during thread allocations.  0x00c0 causes conflicts with
+		// AddressSanitizer which reserves all memory up to 0x0100.
+		// These choices are both for debuggability and to reduce the
+		// odds of a conservative garbage collector (as is still used in gccgo)
+		// not collecting memory because some non-pointer block of memory
+		// had a bit pattern that matched a memory address.
+		//
+		// Actually we reserve 544 GB (because the bitmap ends up being 32 GB)
+		// 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
+		// On darwin/arm64, the address space is even smaller.
+		arenaSize := round(_MaxMem, _PageSize)
+		bitmapSize = arenaSize / (ptrSize * 8 / 4)
+		spansSize = arenaSize / _PageSize * ptrSize
+		spansSize = round(spansSize, _PageSize)
+		for i := 0; i <= 0x7f; i++ {
+			switch {
+			case GOARCH == "arm64" && GOOS == "darwin":
+				p = uintptr(i)<<40 | uintptrMask&(0x0013<<28)
+			case GOARCH == "arm64":
+				p = uintptr(i)<<40 | uintptrMask&(0x0040<<32)
+			default:
+				p = uintptr(i)<<40 | uintptrMask&(0x00c0<<32)
+			}
+			pSize = bitmapSize + spansSize + arenaSize + _PageSize
+			p = uintptr(sysReserve(unsafe.Pointer(p), pSize, &reserved))
+			if p != 0 {
+				break
+			}
+		}
+	}
+
+	if p == 0 {
+		// On a 32-bit machine, we can't typically get away
+		// with a giant virtual address space reservation.
+		// Instead we map the memory information bitmap
+		// immediately after the data segment, large enough
+		// to handle another 2GB of mappings (256 MB),
+		// along with a reservation for an initial arena.
+		// When that gets used up, we'll start asking the kernel
+		// for any memory anywhere and hope it's in the 2GB
+		// following the bitmap (presumably the executable begins
+		// near the bottom of memory, so we'll have to use up
+		// most of memory before the kernel resorts to giving out
+		// memory before the beginning of the text segment).
+		//
+		// Alternatively we could reserve 512 MB bitmap, enough
+		// for 4GB of mappings, and then accept any memory the
+		// kernel threw at us, but normally that's a waste of 512 MB
+		// of address space, which is probably too much in a 32-bit world.
+
+		// If we fail to allocate, try again with a smaller arena.
+		// This is necessary on Android L where we share a process
+		// with ART, which reserves virtual memory aggressively.
+		arenaSizes := []uintptr{
+			512 << 20,
+			256 << 20,
+			128 << 20,
+		}
+
+		for _, arenaSize := range arenaSizes {
+			bitmapSize = _MaxArena32 / (ptrSize * 8 / 4)
+			spansSize = _MaxArena32 / _PageSize * ptrSize
+			if limit > 0 && arenaSize+bitmapSize+spansSize > limit {
+				bitmapSize = (limit / 9) &^ ((1 << _PageShift) - 1)
+				arenaSize = bitmapSize * 8
+				spansSize = arenaSize / _PageSize * ptrSize
+			}
+			spansSize = round(spansSize, _PageSize)
+
+			// SysReserve treats the address we ask for, end, as a hint,
+			// not as an absolute requirement.  If we ask for the end
+			// of the data segment but the operating system requires
+			// a little more space before we can start allocating, it will
+			// give out a slightly higher pointer.  Except QEMU, which
+			// is buggy, as usual: it won't adjust the pointer upward.
+			// 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(firstmoduledata.end+(1<<18), 1<<20)
+			pSize = bitmapSize + spansSize + arenaSize + _PageSize
+			p = uintptr(sysReserve(unsafe.Pointer(p), pSize, &reserved))
+			if p != 0 {
+				break
+			}
+		}
+		if p == 0 {
+			throw("runtime: cannot reserve arena virtual address space")
+		}
+	}
+
+	// PageSize can be larger than OS definition of page size,
+	// so SysReserve can give us a PageSize-unaligned pointer.
+	// To overcome this we ask for PageSize more and round up the pointer.
+	p1 := round(p, _PageSize)
+
+	mheap_.spans = (**mspan)(unsafe.Pointer(p1))
+	mheap_.bitmap = p1 + spansSize
+	mheap_.arena_start = p1 + (spansSize + bitmapSize)
+	mheap_.arena_used = mheap_.arena_start
+	mheap_.arena_end = p + pSize
+	mheap_.arena_reserved = reserved
+
+	if mheap_.arena_start&(_PageSize-1) != 0 {
+		println("bad pagesize", hex(p), hex(p1), hex(spansSize), hex(bitmapSize), hex(_PageSize), "start", hex(mheap_.arena_start))
+		throw("misrounded allocation in mallocinit")
+	}
+
+	// Initialize the rest of the allocator.
+	mHeap_Init(&mheap_, spansSize)
+	_g_ := getg()
+	_g_.m.mcache = allocmcache()
+}
+
+// sysReserveHigh reserves space somewhere high in the address space.
+// sysReserve doesn't actually reserve the full amount requested on
+// 64-bit systems, because of problems with ulimit. Instead it checks
+// that it can get the first 64 kB and assumes it can grab the rest as
+// needed. This doesn't work well with the "let the kernel pick an address"
+// mode, so don't do that. Pick a high address instead.
+func sysReserveHigh(n uintptr, reserved *bool) unsafe.Pointer {
+	if ptrSize == 4 {
+		return sysReserve(nil, n, reserved)
+	}
+
+	for i := 0; i <= 0x7f; i++ {
+		p := uintptr(i)<<40 | uintptrMask&(0x00c0<<32)
+		*reserved = false
+		p = uintptr(sysReserve(unsafe.Pointer(p), n, reserved))
+		if p != 0 {
+			return unsafe.Pointer(p)
+		}
+	}
+
+	return sysReserve(nil, n, reserved)
+}
+
+func mHeap_SysAlloc(h *mheap, n uintptr) unsafe.Pointer {
+	if n > uintptr(h.arena_end)-uintptr(h.arena_used) {
+		// We are in 32-bit mode, maybe we didn't use all possible address space yet.
+		// Reserve some more space.
+		p_size := round(n+_PageSize, 256<<20)
+		new_end := h.arena_end + p_size
+		if new_end <= h.arena_start+_MaxArena32 {
+			// TODO: It would be bad if part of the arena
+			// is reserved and part is not.
+			var reserved bool
+			p := uintptr(sysReserve((unsafe.Pointer)(h.arena_end), p_size, &reserved))
+			if p == h.arena_end {
+				h.arena_end = new_end
+				h.arena_reserved = reserved
+			} else if p+p_size <= h.arena_start+_MaxArena32 {
+				// Keep everything page-aligned.
+				// Our pages are bigger than hardware pages.
+				h.arena_end = p + p_size
+				used := p + (-uintptr(p) & (_PageSize - 1))
+				mHeap_MapBits(h, used)
+				mHeap_MapSpans(h, used)
+				h.arena_used = used
+				h.arena_reserved = reserved
+			} else {
+				var stat uint64
+				sysFree((unsafe.Pointer)(p), p_size, &stat)
+			}
+		}
+	}
+
+	if n <= uintptr(h.arena_end)-uintptr(h.arena_used) {
+		// Keep taking from our reservation.
+		p := h.arena_used
+		sysMap((unsafe.Pointer)(p), n, h.arena_reserved, &memstats.heap_sys)
+		mHeap_MapBits(h, p+n)
+		mHeap_MapSpans(h, p+n)
+		h.arena_used = p + n
+		if raceenabled {
+			racemapshadow((unsafe.Pointer)(p), n)
+		}
+
+		if uintptr(p)&(_PageSize-1) != 0 {
+			throw("misrounded allocation in MHeap_SysAlloc")
+		}
+		return (unsafe.Pointer)(p)
+	}
+
+	// If using 64-bit, our reservation is all we have.
+	if uintptr(h.arena_end)-uintptr(h.arena_start) >= _MaxArena32 {
+		return nil
+	}
+
+	// On 32-bit, once the reservation is gone we can
+	// try to get memory at a location chosen by the OS
+	// and hope that it is in the range we allocated bitmap for.
+	p_size := round(n, _PageSize) + _PageSize
+	p := uintptr(sysAlloc(p_size, &memstats.heap_sys))
+	if p == 0 {
+		return nil
+	}
+
+	if p < h.arena_start || uintptr(p)+p_size-uintptr(h.arena_start) >= _MaxArena32 {
+		print("runtime: memory allocated by OS (", p, ") not in usable range [", hex(h.arena_start), ",", hex(h.arena_start+_MaxArena32), ")\n")
+		sysFree((unsafe.Pointer)(p), p_size, &memstats.heap_sys)
+		return nil
+	}
+
+	p_end := p + p_size
+	p += -p & (_PageSize - 1)
+	if uintptr(p)+n > uintptr(h.arena_used) {
+		mHeap_MapBits(h, p+n)
+		mHeap_MapSpans(h, p+n)
+		h.arena_used = p + n
+		if p_end > h.arena_end {
+			h.arena_end = p_end
+		}
+		if raceenabled {
+			racemapshadow((unsafe.Pointer)(p), n)
+		}
+	}
+
+	if uintptr(p)&(_PageSize-1) != 0 {
+		throw("misrounded allocation in MHeap_SysAlloc")
+	}
+	return (unsafe.Pointer)(p)
+}
+
 // base address for all 0-byte allocations
 var zerobase uintptr
 
+const (
+	// flags to malloc
+	_FlagNoScan = 1 << 0 // GC doesn't have to scan object
+	_FlagNoZero = 1 << 1 // don't zero memory
+)
+
 // Allocate an object of size bytes.
 // 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 {
+	if gcphase == _GCmarktermination {
+		throw("mallocgc called with gcphase == _GCmarktermination")
+	}
+
 	if size == 0 {
 		return unsafe.Pointer(&zerobase)
 	}
-	size0 := size
 
 	if flags&flagNoScan == 0 && typ == nil {
-		gothrow("malloc missing type")
-	}
-
-	// This function must be atomic wrt GC, but for performance reasons
-	// we don't acquirem/releasem on fast path. The code below does not have
-	// split stack checks, so it can't be preempted by GC.
-	// Functions like roundup/add are inlined. And onM/racemalloc are nosplit.
-	// If debugMalloc = true, these assumptions are checked below.
-	if debugMalloc {
-		mp := acquirem()
-		if mp.mallocing != 0 {
-			gothrow("malloc deadlock")
-		}
-		mp.mallocing = 1
-		if mp.curg != nil {
-			mp.curg.stackguard0 = ^uintptr(0xfff) | 0xbad
+		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 {
+		throw("malloc deadlock")
+	}
+	if mp.gsignal == getg() {
+		throw("malloc during signal")
 	}
+	mp.mallocing = 1
 
+	shouldhelpgc := false
+	dataSize := size
 	c := gomcache()
 	var s *mspan
 	var x unsafe.Pointer
@@ -103,63 +553,47 @@ func mallocgc(size uintptr, typ *_type, flags uint32) unsafe.Pointer {
 			// standalone escaping variables. On a json benchmark
 			// the allocator reduces number of allocations by ~12% and
 			// reduces heap size by ~20%.
-			tinysize := uintptr(c.tinysize)
-			if size <= tinysize {
-				tiny := unsafe.Pointer(c.tiny)
-				// Align tiny pointer for required (conservative) alignment.
-				if size&7 == 0 {
-					tiny = roundup(tiny, 8)
-				} else if size&3 == 0 {
-					tiny = roundup(tiny, 4)
-				} else if size&1 == 0 {
-					tiny = roundup(tiny, 2)
-				}
-				size1 := size + (uintptr(tiny) - uintptr(unsafe.Pointer(c.tiny)))
-				if size1 <= tinysize {
-					// The object fits into existing tiny block.
-					x = tiny
-					c.tiny = (*byte)(add(x, size))
-					c.tinysize -= uintptr(size1)
-					c.local_tinyallocs++
-					if debugMalloc {
-						mp := acquirem()
-						if mp.mallocing == 0 {
-							gothrow("bad malloc")
-						}
-						mp.mallocing = 0
-						if mp.curg != nil {
-							mp.curg.stackguard0 = mp.curg.stack.lo + _StackGuard
-						}
-						// Note: one releasem for the acquirem just above.
-						// The other for the acquirem at start of malloc.
-						releasem(mp)
-						releasem(mp)
-					}
-					return x
-				}
+			off := c.tinyoffset
+			// Align tiny pointer for required (conservative) alignment.
+			if size&7 == 0 {
+				off = round(off, 8)
+			} else if size&3 == 0 {
+				off = round(off, 4)
+			} else if size&1 == 0 {
+				off = round(off, 2)
+			}
+			if off+size <= maxTinySize && c.tiny != nil {
+				// The object fits into existing tiny block.
+				x = add(c.tiny, off)
+				c.tinyoffset = off + size
+				c.local_tinyallocs++
+				mp.mallocing = 0
+				releasem(mp)
+				return x
 			}
 			// Allocate a new maxTinySize block.
 			s = c.alloc[tinySizeClass]
 			v := s.freelist
-			if v == nil {
-				mp := acquirem()
-				mp.scalararg[0] = tinySizeClass
-				onM(mcacheRefill_m)
-				releasem(mp)
+			if v.ptr() == nil {
+				systemstack(func() {
+					mCache_Refill(c, tinySizeClass)
+				})
+				shouldhelpgc = true
 				s = c.alloc[tinySizeClass]
 				v = s.freelist
 			}
-			s.freelist = v.next
+			s.freelist = v.ptr().next
 			s.ref++
-			//TODO: prefetch v.next
+			// prefetchnta offers best performance, see change list message.
+			prefetchnta(uintptr(v.ptr().next))
 			x = unsafe.Pointer(v)
 			(*[2]uint64)(x)[0] = 0
 			(*[2]uint64)(x)[1] = 0
 			// See if we need to replace the existing tiny block with the new one
 			// based on amount of remaining free space.
-			if maxTinySize-size > tinysize {
-				c.tiny = (*byte)(add(x, size))
-				c.tinysize = uintptr(maxTinySize - size)
+			if size < c.tinyoffset {
+				c.tiny = x
+				c.tinyoffset = size
 			}
 			size = maxTinySize
 		} else {
@@ -172,156 +606,86 @@ func mallocgc(size uintptr, typ *_type, flags uint32) unsafe.Pointer {
 			size = uintptr(class_to_size[sizeclass])
 			s = c.alloc[sizeclass]
 			v := s.freelist
-			if v == nil {
-				mp := acquirem()
-				mp.scalararg[0] = uintptr(sizeclass)
-				onM(mcacheRefill_m)
-				releasem(mp)
+			if v.ptr() == nil {
+				systemstack(func() {
+					mCache_Refill(c, int32(sizeclass))
+				})
+				shouldhelpgc = true
 				s = c.alloc[sizeclass]
 				v = s.freelist
 			}
-			s.freelist = v.next
+			s.freelist = v.ptr().next
 			s.ref++
-			//TODO: prefetch
+			// prefetchnta offers best performance, see change list message.
+			prefetchnta(uintptr(v.ptr().next))
 			x = unsafe.Pointer(v)
 			if flags&flagNoZero == 0 {
-				v.next = nil
+				v.ptr().next = 0
 				if size > 2*ptrSize && ((*[2]uintptr)(x))[1] != 0 {
 					memclr(unsafe.Pointer(v), size)
 				}
 			}
 		}
-		c.local_cachealloc += intptr(size)
+		c.local_cachealloc += size
 	} else {
-		mp := acquirem()
-		mp.scalararg[0] = uintptr(size)
-		mp.scalararg[1] = uintptr(flags)
-		onM(largeAlloc_m)
-		s = (*mspan)(mp.ptrarg[0])
-		mp.ptrarg[0] = nil
-		releasem(mp)
+		var s *mspan
+		shouldhelpgc = true
+		systemstack(func() {
+			s = largeAlloc(size, uint32(flags))
+		})
 		x = unsafe.Pointer(uintptr(s.start << pageShift))
 		size = uintptr(s.elemsize)
 	}
 
 	if flags&flagNoScan != 0 {
-		// All objects are pre-marked as noscan.
-		goto marked
-	}
-
-	// If allocating a defer+arg block, now that we've picked a malloc size
-	// large enough to hold everything, cut the "asked for" size down to
-	// just the defer header, so that the GC bitmap will record the arg block
-	// as containing nothing at all (as if it were unused space at the end of
-	// a malloc block caused by size rounding).
-	// The defer arg areas are scanned as part of scanstack.
-	if typ == deferType {
-		size0 = unsafe.Sizeof(_defer{})
-	}
-
-	// From here till marked label marking the object as allocated
-	// and storing type info in the GC bitmap.
-	{
-		arena_start := uintptr(unsafe.Pointer(mheap_.arena_start))
-		off := (uintptr(x) - arena_start) / ptrSize
-		xbits := (*uint8)(unsafe.Pointer(arena_start - off/wordsPerBitmapByte - 1))
-		shift := (off % wordsPerBitmapByte) * gcBits
-		if debugMalloc && ((*xbits>>shift)&(bitMask|bitPtrMask)) != bitBoundary {
-			println("runtime: bits =", (*xbits>>shift)&(bitMask|bitPtrMask))
-			gothrow("bad bits in markallocated")
-		}
-
-		var ti, te uintptr
-		var ptrmask *uint8
-		if size == ptrSize {
-			// It's one word and it has pointers, it must be a pointer.
-			*xbits |= (bitsPointer << 2) << shift
-			goto marked
+		// All objects are pre-marked as noscan. Nothing to do.
+	} else {
+		// If allocating a defer+arg block, now that we've picked a malloc size
+		// large enough to hold everything, cut the "asked for" size down to
+		// just the defer header, so that the GC bitmap will record the arg block
+		// as containing nothing at all (as if it were unused space at the end of
+		// a malloc block caused by size rounding).
+		// The defer arg areas are scanned as part of scanstack.
+		if typ == deferType {
+			dataSize = unsafe.Sizeof(_defer{})
 		}
-		if typ.kind&kindGCProg != 0 {
-			nptr := (uintptr(typ.size) + ptrSize - 1) / ptrSize
-			masksize := nptr
-			if masksize%2 != 0 {
-				masksize *= 2 // repeated
-			}
-			masksize = masksize * pointersPerByte / 8 // 4 bits per word
-			masksize++                                // unroll flag in the beginning
-			if masksize > maxGCMask && typ.gc[1] != 0 {
-				// If the mask is too large, unroll the program directly
-				// into the GC bitmap. It's 7 times slower than copying
-				// from the pre-unrolled mask, but saves 1/16 of type size
-				// memory for the mask.
-				mp := acquirem()
-				mp.ptrarg[0] = x
-				mp.ptrarg[1] = unsafe.Pointer(typ)
-				mp.scalararg[0] = uintptr(size)
-				mp.scalararg[1] = uintptr(size0)
-				onM(unrollgcproginplace_m)
-				releasem(mp)
-				goto marked
+		heapBitsSetType(uintptr(x), size, dataSize, typ)
+		if dataSize > typ.size {
+			// Array allocation. If there are any
+			// pointers, GC has to scan to the last
+			// element.
+			if typ.ptrdata != 0 {
+				c.local_scan += dataSize - typ.size + typ.ptrdata
 			}
-			ptrmask = (*uint8)(unsafe.Pointer(uintptr(typ.gc[0])))
-			// Check whether the program is already unrolled.
-			if uintptr(atomicloadp(unsafe.Pointer(ptrmask)))&0xff == 0 {
-				mp := acquirem()
-				mp.ptrarg[0] = unsafe.Pointer(typ)
-				onM(unrollgcprog_m)
-				releasem(mp)
-			}
-			ptrmask = (*uint8)(add(unsafe.Pointer(ptrmask), 1)) // skip the unroll flag byte
 		} else {
-			ptrmask = (*uint8)(unsafe.Pointer(typ.gc[0])) // pointer to unrolled mask
-		}
-		if size == 2*ptrSize {
-			*xbits = *ptrmask | bitBoundary
-			goto marked
+			c.local_scan += typ.ptrdata
 		}
-		te = uintptr(typ.size) / ptrSize
-		// If the type occupies odd number of words, its mask is repeated.
-		if te%2 == 0 {
-			te /= 2
-		}
-		// Copy pointer bitmask into the bitmap.
-		for i := uintptr(0); i < size0; i += 2 * ptrSize {
-			v := *(*uint8)(add(unsafe.Pointer(ptrmask), ti))
-			ti++
-			if ti == te {
-				ti = 0
-			}
-			if i == 0 {
-				v |= bitBoundary
-			}
-			if i+ptrSize == size0 {
-				v &^= uint8(bitPtrMask << 4)
-			}
 
-			*xbits = v
-			xbits = (*byte)(add(unsafe.Pointer(xbits), ^uintptr(0)))
-		}
-		if size0%(2*ptrSize) == 0 && size0 < size {
-			// Mark the word after last object's word as bitsDead.
-			*xbits = bitsDead << 2
-		}
+		// Ensure that the stores above that initialize x to
+		// type-safe memory and set the heap bits occur before
+		// the caller can make x observable to the garbage
+		// collector. Otherwise, on weakly ordered machines,
+		// the garbage collector could follow a pointer to x,
+		// but see uninitialized memory or stale heap bits.
+		publicationBarrier()
 	}
-marked:
+
+	// GCmarkterminate allocates black
+	// All slots hold nil so no scanning is needed.
+	// This may be racing with GC so do it atomically if there can be
+	// a race marking the bit.
+	if gcphase == _GCmarktermination || gcBlackenPromptly {
+		systemstack(func() {
+			gcmarknewobject_m(uintptr(x), size)
+		})
+	}
+
 	if raceenabled {
 		racemalloc(x, size)
 	}
 
-	if debugMalloc {
-		mp := acquirem()
-		if mp.mallocing == 0 {
-			gothrow("bad malloc")
-		}
-		mp.mallocing = 0
-		if mp.curg != nil {
-			mp.curg.stackguard0 = mp.curg.stack.lo + _StackGuard
-		}
-		// Note: one releasem for the acquirem just above.
-		// The other for the acquirem at start of malloc.
-		releasem(mp)
-		releasem(mp)
-	}
+	mp.mallocing = 0
+	releasem(mp)
 
 	if debug.allocfreetrace != 0 {
 		tracealloc(x, size, typ)
@@ -337,13 +701,56 @@ marked:
 		}
 	}
 
-	if memstats.heap_alloc >= memstats.next_gc {
-		gogc(0)
+	if shouldhelpgc && shouldtriggergc() {
+		startGC(gcBackgroundMode, false)
+	} else if gcBlackenEnabled != 0 {
+		// Assist garbage collector. We delay this until the
+		// epilogue so that it doesn't interfere with the
+		// inner working of malloc such as mcache refills that
+		// might happen while doing the gcAssistAlloc.
+		gcAssistAlloc(size, shouldhelpgc)
+	} else if shouldhelpgc && bggc.working != 0 {
+		// The GC is starting up or shutting down, so we can't
+		// assist, but we also can't allocate unabated. Slow
+		// down this G's allocation and help the GC stay
+		// scheduled by yielding.
+		//
+		// TODO: This is a workaround. Either help the GC make
+		// the transition or block.
+		gp := getg()
+		if gp != gp.m.g0 && gp.m.locks == 0 && gp.m.preemptoff == "" {
+			Gosched()
+		}
 	}
 
 	return x
 }
 
+func largeAlloc(size uintptr, flag uint32) *mspan {
+	// print("largeAlloc size=", size, "\n")
+
+	if size+_PageSize < size {
+		throw("out of memory")
+	}
+	npages := size >> _PageShift
+	if size&_PageMask != 0 {
+		npages++
+	}
+
+	// Deduct credit for this span allocation and sweep if
+	// necessary. mHeap_Alloc will also sweep npages, so this only
+	// pays the debt down to npage pages.
+	deductSweepCredit(npages*_PageSize, npages)
+
+	s := mHeap_Alloc(&mheap_, npages, 0, true, flag&_FlagNoZero == 0)
+	if s == nil {
+		throw("out of memory")
+	}
+	s.limit = uintptr(s.start)<<_PageShift + size
+	heapBitsForSpan(s.base()).initSpan(s.layout())
+	return s
+}
+
 // implementation of new builtin
 func newobject(typ *_type) unsafe.Pointer {
 	flags := uint32(0)
@@ -353,38 +760,34 @@ func newobject(typ *_type) unsafe.Pointer {
 	return mallocgc(uintptr(typ.size), typ, flags)
 }
 
+//go:linkname reflect_unsafe_New reflect.unsafe_New
+func reflect_unsafe_New(typ *_type) unsafe.Pointer {
+	return newobject(typ)
+}
+
 // implementation of make builtin for slices
 func newarray(typ *_type, n uintptr) unsafe.Pointer {
 	flags := uint32(0)
 	if typ.kind&kindNoPointers != 0 {
 		flags |= flagNoScan
 	}
-	if int(n) < 0 || (typ.size > 0 && n > maxmem/uintptr(typ.size)) {
+	if int(n) < 0 || (typ.size > 0 && n > _MaxMem/uintptr(typ.size)) {
 		panic("runtime: allocation size out of range")
 	}
 	return mallocgc(uintptr(typ.size)*n, typ, flags)
 }
 
+//go:linkname reflect_unsafe_NewArray reflect.unsafe_NewArray
+func reflect_unsafe_NewArray(typ *_type, n uintptr) unsafe.Pointer {
+	return newarray(typ, n)
+}
+
 // rawmem returns a chunk of pointerless memory.  It is
 // not zeroed.
 func rawmem(size uintptr) unsafe.Pointer {
 	return mallocgc(size, nil, flagNoScan|flagNoZero)
 }
 
-// round size up to next size class
-func goroundupsize(size uintptr) uintptr {
-	if size < maxSmallSize {
-		if size <= 1024-8 {
-			return uintptr(class_to_size[size_to_class8[(size+7)>>3]])
-		}
-		return uintptr(class_to_size[size_to_class128[(size-1024+127)>>7]])
-	}
-	if size+pageSize < size {
-		return size
-	}
-	return (size + pageSize - 1) &^ pageMask
-}
-
 func profilealloc(mp *m, x unsafe.Pointer, size uintptr) {
 	c := mp.mcache
 	rate := MemProfileRate
@@ -408,430 +811,84 @@ func profilealloc(mp *m, x unsafe.Pointer, size uintptr) {
 	mProf_Malloc(x, size)
 }
 
-// force = 1 - do GC regardless of current heap usage
-// force = 2 - go GC and eager sweep
-func gogc(force int32) {
-	// The gc is turned off (via enablegc) until the bootstrap has completed.
-	// Also, malloc gets called in the guts of a number of libraries that might be
-	// holding locks. To avoid deadlocks during stoptheworld, don't bother
-	// trying to run gc while holding a lock. The next mallocgc without a lock
-	// will do the gc instead.
-	mp := acquirem()
-	if gp := getg(); gp == mp.g0 || mp.locks > 1 || !memstats.enablegc || panicking != 0 || gcpercent < 0 {
-		releasem(mp)
-		return
-	}
-	releasem(mp)
-	mp = nil
-
-	semacquire(&worldsema, false)
-
-	if force == 0 && memstats.heap_alloc < memstats.next_gc {
-		// typically threads which lost the race to grab
-		// worldsema exit here when gc is done.
-		semrelease(&worldsema)
-		return
-	}
-
-	// Ok, we're doing it!  Stop everybody else
-	startTime := nanotime()
-	mp = acquirem()
-	mp.gcing = 1
-	releasem(mp)
-	onM(stoptheworld)
-	if mp != acquirem() {
-		gothrow("gogc: rescheduled")
-	}
-
-	clearpools()
-
-	// Run gc on the g0 stack.  We do this so that the g stack
-	// we're currently running on will no longer change.  Cuts
-	// the root set down a bit (g0 stacks are not scanned, and
-	// we don't need to scan gc's internal state).  We also
-	// need to switch to g0 so we can shrink the stack.
-	n := 1
-	if debug.gctrace > 1 {
-		n = 2
-	}
-	for i := 0; i < n; i++ {
-		if i > 0 {
-			startTime = nanotime()
-		}
-		// switch to g0, call gc, then switch back
-		mp.scalararg[0] = uintptr(uint32(startTime)) // low 32 bits
-		mp.scalararg[1] = uintptr(startTime >> 32)   // high 32 bits
-		if force >= 2 {
-			mp.scalararg[2] = 1 // eagersweep
-		} else {
-			mp.scalararg[2] = 0
-		}
-		onM(gc_m)
-	}
-
-	// all done
-	mp.gcing = 0
-	semrelease(&worldsema)
-	onM(starttheworld)
-	releasem(mp)
-	mp = nil
-
-	// now that gc is done, kick off finalizer thread if needed
-	if !concurrentSweep {
-		// give the queued finalizers, if any, a chance to run
-		Gosched()
-	}
-}
-
-// GC runs a garbage collection.
-func GC() {
-	gogc(2)
-}
-
-// linker-provided
-var noptrdata struct{}
-var enoptrdata struct{}
-var noptrbss struct{}
-var enoptrbss struct{}
-
-// SetFinalizer sets the finalizer associated with x to f.
-// When the garbage collector finds an unreachable block
-// with an associated finalizer, it clears the association and runs
-// f(x) in a separate goroutine.  This makes x reachable again, but
-// now without an associated finalizer.  Assuming that SetFinalizer
-// is not called again, the next time the garbage collector sees
-// that x is unreachable, it will free x.
-//
-// SetFinalizer(x, nil) clears any finalizer associated with x.
-//
-// The argument x must be a pointer to an object allocated by
-// calling new or by taking the address of a composite literal.
-// The argument f must be a function that takes a single argument
-// to which x's type can be assigned, and can have arbitrary ignored return
-// values. If either of these is not true, SetFinalizer aborts the
-// program.
-//
-// Finalizers are run in dependency order: if A points at B, both have
-// finalizers, and they are otherwise unreachable, only the finalizer
-// for A runs; once A is freed, the finalizer for B can run.
-// If a cyclic structure includes a block with a finalizer, that
-// cycle is not guaranteed to be garbage collected and the finalizer
-// is not guaranteed to run, because there is no ordering that
-// respects the dependencies.
-//
-// The finalizer for x is scheduled to run at some arbitrary time after
-// x becomes unreachable.
-// There is no guarantee that finalizers will run before a program exits,
-// so typically they are useful only for releasing non-memory resources
-// associated with an object during a long-running program.
-// For example, an os.File object could use a finalizer to close the
-// associated operating system file descriptor when a program discards
-// an os.File without calling Close, but it would be a mistake
-// to depend on a finalizer to flush an in-memory I/O buffer such as a
-// bufio.Writer, because the buffer would not be flushed at program exit.
-//
-// It is not guaranteed that a finalizer will run if the size of *x is
-// zero bytes.
-//
-// It is not guaranteed that a finalizer will run for objects allocated
-// in initializers for package-level variables. Such objects may be
-// linker-allocated, not heap-allocated.
-//
-// A single goroutine runs all finalizers for a program, sequentially.
-// If a finalizer must run for a long time, it should do so by starting
-// a new goroutine.
-func SetFinalizer(obj interface{}, finalizer interface{}) {
-	e := (*eface)(unsafe.Pointer(&obj))
-	etyp := e._type
-	if etyp == nil {
-		gothrow("runtime.SetFinalizer: first argument is nil")
-	}
-	if etyp.kind&kindMask != kindPtr {
-		gothrow("runtime.SetFinalizer: first argument is " + *etyp._string + ", not pointer")
-	}
-	ot := (*ptrtype)(unsafe.Pointer(etyp))
-	if ot.elem == nil {
-		gothrow("nil elem type!")
-	}
-
-	// find the containing object
-	_, base, _ := findObject(e.data)
-
-	if base == nil {
-		// 0-length objects are okay.
-		if e.data == unsafe.Pointer(&zerobase) {
-			return
-		}
-
-		// Global initializers might be linker-allocated.
-		//	var Foo = &Object{}
-		//	func main() {
-		//		runtime.SetFinalizer(Foo, nil)
-		//	}
-		// 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)) {
-			return
-		}
-		gothrow("runtime.SetFinalizer: pointer not in allocated block")
-	}
-
-	if e.data != base {
-		// As an implementation detail we allow to set finalizers for an inner byte
-		// of an object if it could come from tiny alloc (see mallocgc for details).
-		if ot.elem == nil || ot.elem.kind&kindNoPointers == 0 || ot.elem.size >= maxTinySize {
-			gothrow("runtime.SetFinalizer: pointer not at beginning of allocated block")
-		}
-	}
-
-	f := (*eface)(unsafe.Pointer(&finalizer))
-	ftyp := f._type
-	if ftyp == nil {
-		// switch to M stack and remove finalizer
-		mp := acquirem()
-		mp.ptrarg[0] = e.data
-		onM(removeFinalizer_m)
-		releasem(mp)
-		return
-	}
-
-	if ftyp.kind&kindMask != kindFunc {
-		gothrow("runtime.SetFinalizer: second argument is " + *ftyp._string + ", not a function")
-	}
-	ft := (*functype)(unsafe.Pointer(ftyp))
-	ins := *(*[]*_type)(unsafe.Pointer(&ft.in))
-	if ft.dotdotdot || len(ins) != 1 {
-		gothrow("runtime.SetFinalizer: cannot pass " + *etyp._string + " to finalizer " + *ftyp._string)
-	}
-	fint := ins[0]
-	switch {
-	case fint == etyp:
-		// ok - same type
-		goto okarg
-	case fint.kind&kindMask == kindPtr:
-		if (fint.x == nil || fint.x.name == nil || etyp.x == nil || etyp.x.name == nil) && (*ptrtype)(unsafe.Pointer(fint)).elem == ot.elem {
-			// ok - not same type, but both pointers,
-			// one or the other is unnamed, and same element type, so assignable.
-			goto okarg
-		}
-	case fint.kind&kindMask == kindInterface:
-		ityp := (*interfacetype)(unsafe.Pointer(fint))
-		if len(ityp.mhdr) == 0 {
-			// ok - satisfies empty interface
-			goto okarg
-		}
-		if _, ok := assertE2I2(ityp, obj); ok {
-			goto okarg
-		}
-	}
-	gothrow("runtime.SetFinalizer: cannot pass " + *etyp._string + " to finalizer " + *ftyp._string)
-okarg:
-	// compute size needed for return parameters
-	nret := uintptr(0)
-	for _, t := range *(*[]*_type)(unsafe.Pointer(&ft.out)) {
-		nret = round(nret, uintptr(t.align)) + uintptr(t.size)
-	}
-	nret = round(nret, ptrSize)
-
-	// make sure we have a finalizer goroutine
-	createfing()
-
-	// switch to M stack to add finalizer record
-	mp := acquirem()
-	mp.ptrarg[0] = f.data
-	mp.ptrarg[1] = e.data
-	mp.scalararg[0] = nret
-	mp.ptrarg[2] = unsafe.Pointer(fint)
-	mp.ptrarg[3] = unsafe.Pointer(ot)
-	onM(setFinalizer_m)
-	if mp.scalararg[0] != 1 {
-		gothrow("runtime.SetFinalizer: finalizer already set")
-	}
-	releasem(mp)
-}
-
-// round n up to a multiple of a.  a must be a power of 2.
-func round(n, a uintptr) uintptr {
-	return (n + a - 1) &^ (a - 1)
+type persistentAlloc struct {
+	base unsafe.Pointer
+	off  uintptr
 }
 
-// Look up pointer v in heap.  Return the span containing the object,
-// the start of the object, and the size of the object.  If the object
-// does not exist, return nil, nil, 0.
-func findObject(v unsafe.Pointer) (s *mspan, x unsafe.Pointer, n uintptr) {
-	c := gomcache()
-	c.local_nlookup++
-	if ptrSize == 4 && c.local_nlookup >= 1<<30 {
-		// purge cache stats to prevent overflow
-		lock(&mheap_.lock)
-		purgecachedstats(c)
-		unlock(&mheap_.lock)
-	}
-
-	// find span
-	arena_start := uintptr(unsafe.Pointer(mheap_.arena_start))
-	arena_used := uintptr(unsafe.Pointer(mheap_.arena_used))
-	if uintptr(v) < arena_start || uintptr(v) >= arena_used {
-		return
-	}
-	p := uintptr(v) >> pageShift
-	q := p - arena_start>>pageShift
-	s = *(**mspan)(add(unsafe.Pointer(mheap_.spans), q*ptrSize))
-	if s == nil {
-		return
-	}
-	x = unsafe.Pointer(uintptr(s.start) << pageShift)
-
-	if uintptr(v) < uintptr(x) || uintptr(v) >= uintptr(unsafe.Pointer(s.limit)) || s.state != mSpanInUse {
-		s = nil
-		x = nil
-		return
-	}
-
-	n = uintptr(s.elemsize)
-	if s.sizeclass != 0 {
-		x = add(x, (uintptr(v)-uintptr(x))/n*n)
-	}
-	return
-}
-
-var fingCreate uint32
-
-func createfing() {
-	// start the finalizer goroutine exactly once
-	if fingCreate == 0 && cas(&fingCreate, 0, 1) {
-		go runfinq()
-	}
-}
-
-// This is the goroutine that runs all of the finalizers
-func runfinq() {
-	var (
-		frame    unsafe.Pointer
-		framecap uintptr
-	)
-
-	for {
-		lock(&finlock)
-		fb := finq
-		finq = nil
-		if fb == nil {
-			gp := getg()
-			fing = gp
-			fingwait = true
-			gp.issystem = true
-			goparkunlock(&finlock, "finalizer wait")
-			gp.issystem = false
-			continue
-		}
-		unlock(&finlock)
-		if raceenabled {
-			racefingo()
-		}
-		for fb != nil {
-			for i := int32(0); i < fb.cnt; i++ {
-				f := (*finalizer)(add(unsafe.Pointer(&fb.fin), uintptr(i)*unsafe.Sizeof(finalizer{})))
-
-				framesz := unsafe.Sizeof((interface{})(nil)) + uintptr(f.nret)
-				if framecap < framesz {
-					// The frame does not contain pointers interesting for GC,
-					// all not yet finalized objects are stored in finq.
-					// If we do not mark it as FlagNoScan,
-					// the last finalized object is not collected.
-					frame = mallocgc(framesz, nil, flagNoScan)
-					framecap = framesz
-				}
-
-				if f.fint == nil {
-					gothrow("missing type in runfinq")
-				}
-				switch f.fint.kind & kindMask {
-				case kindPtr:
-					// direct use of pointer
-					*(*unsafe.Pointer)(frame) = f.arg
-				case kindInterface:
-					ityp := (*interfacetype)(unsafe.Pointer(f.fint))
-					// set up with empty interface
-					(*eface)(frame)._type = &f.ot.typ
-					(*eface)(frame).data = f.arg
-					if len(ityp.mhdr) != 0 {
-						// convert to interface with methods
-						// this conversion is guaranteed to succeed - we checked in SetFinalizer
-						*(*fInterface)(frame) = assertE2I(ityp, *(*interface{})(frame))
-					}
-				default:
-					gothrow("bad kind in runfinq")
-				}
-				reflectcall(unsafe.Pointer(f.fn), frame, uint32(framesz), uint32(framesz))
-
-				// drop finalizer queue references to finalized object
-				f.fn = nil
-				f.arg = nil
-				f.ot = nil
-			}
-			fb.cnt = 0
-			next := fb.next
-			lock(&finlock)
-			fb.next = finc
-			finc = fb
-			unlock(&finlock)
-			fb = next
-		}
-	}
-}
-
-var persistent struct {
-	lock mutex
-	pos  unsafe.Pointer
-	end  unsafe.Pointer
+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.
 // If align is 0, uses default align (currently 8).
-func persistentalloc(size, align uintptr, stat *uint64) unsafe.Pointer {
+func persistentalloc(size, align uintptr, sysStat *uint64) unsafe.Pointer {
+	var p unsafe.Pointer
+	systemstack(func() {
+		p = persistentalloc1(size, align, sysStat)
+	})
+	return p
+}
+
+// Must run on system stack because stack growth can (re)invoke it.
+// See issue 9174.
+//go:systemstack
+func persistentalloc1(size, align uintptr, sysStat *uint64) unsafe.Pointer {
 	const (
 		chunk    = 256 << 10
 		maxBlock = 64 << 10 // VM reservation granularity is 64K on windows
 	)
 
+	if size == 0 {
+		throw("persistentalloc: size == 0")
+	}
 	if align != 0 {
 		if align&(align-1) != 0 {
-			gothrow("persistentalloc: align is not a power of 2")
+			throw("persistentalloc: align is not a power of 2")
 		}
 		if align > _PageSize {
-			gothrow("persistentalloc: align is too large")
+			throw("persistentalloc: align is too large")
 		}
 	} else {
 		align = 8
 	}
 
 	if size >= maxBlock {
-		return sysAlloc(size, stat)
+		return sysAlloc(size, sysStat)
 	}
 
-	lock(&persistent.lock)
-	persistent.pos = roundup(persistent.pos, align)
-	if uintptr(persistent.pos)+size > uintptr(persistent.end) {
-		persistent.pos = sysAlloc(chunk, &memstats.other_sys)
-		if persistent.pos == nil {
-			unlock(&persistent.lock)
-			gothrow("runtime: cannot allocate memory")
+	mp := acquirem()
+	var persistent *persistentAlloc
+	if mp != nil && mp.p != 0 {
+		persistent = &mp.p.ptr().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 {
+			if persistent == &globalAlloc.persistentAlloc {
+				unlock(&globalAlloc.mutex)
+			}
+			throw("runtime: cannot allocate memory")
 		}
-		persistent.end = add(persistent.pos, chunk)
+		persistent.off = 0
+	}
+	p := add(persistent.base, persistent.off)
+	persistent.off += size
+	releasem(mp)
+	if persistent == &globalAlloc.persistentAlloc {
+		unlock(&globalAlloc.mutex)
 	}
-	p := persistent.pos
-	persistent.pos = add(persistent.pos, size)
-	unlock(&persistent.lock)
 
-	if stat != &memstats.other_sys {
-		xadd64(stat, int64(size))
-		xadd64(&memstats.other_sys, -int64(size))
+	if sysStat != &memstats.other_sys {
+		mSysStatInc(sysStat, size)
+		mSysStatDec(&memstats.other_sys, size)
 	}
 	return p
 }
diff --git a/src/runtime/malloc.h b/src/runtime/malloc.h
deleted file mode 100644
index adb8d3d..0000000
--- a/src/runtime/malloc.h
+++ /dev/null
@@ -1,621 +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.
-
-// Memory allocator, based on tcmalloc.
-// http://goog-perftools.sourceforge.net/doc/tcmalloc.html
-
-// The main allocator works in runs of pages.
-// Small allocation sizes (up to and including 32 kB) are
-// rounded to one of about 100 size classes, each of which
-// has its own free list of objects of exactly that size.
-// Any free page of memory can be split into a set of objects
-// of one size class, which are then managed using free list
-// allocators.
-//
-// The allocator's data structures are:
-//
-//	FixAlloc: a free-list allocator for fixed-size objects,
-//		used to manage storage used by the allocator.
-//	MHeap: the malloc heap, managed at page (4096-byte) granularity.
-//	MSpan: a run of pages managed by the MHeap.
-//	MCentral: a shared free list for a given size class.
-//	MCache: a per-thread (in Go, per-P) cache for small objects.
-//	MStats: allocation statistics.
-//
-// Allocating a small object proceeds up a hierarchy of caches:
-//
-//	1. Round the size up to one of the small size classes
-//	   and look in the corresponding MCache free list.
-//	   If the list is not empty, allocate an object from it.
-//	   This can all be done without acquiring a lock.
-//
-//	2. If the MCache free list is empty, replenish it by
-//	   taking a bunch of objects from the MCentral free list.
-//	   Moving a bunch amortizes the cost of acquiring the MCentral lock.
-//
-//	3. If the MCentral free list is empty, replenish it by
-//	   allocating a run of pages from the MHeap and then
-//	   chopping that memory into a objects of the given size.
-//	   Allocating many objects amortizes the cost of locking
-//	   the heap.
-//
-//	4. If the MHeap is empty or has no page runs large enough,
-//	   allocate a new group of pages (at least 1MB) from the
-//	   operating system.  Allocating a large run of pages
-//	   amortizes the cost of talking to the operating system.
-//
-// Freeing a small object proceeds up the same hierarchy:
-//
-//	1. Look up the size class for the object and add it to
-//	   the MCache free list.
-//
-//	2. If the MCache free list is too long or the MCache has
-//	   too much memory, return some to the MCentral free lists.
-//
-//	3. If all the objects in a given span have returned to
-//	   the MCentral list, return that span to the page heap.
-//
-//	4. If the heap has too much memory, return some to the
-//	   operating system.
-//
-//	TODO(rsc): Step 4 is not implemented.
-//
-// Allocating and freeing a large object uses the page heap
-// directly, bypassing the MCache and MCentral free lists.
-//
-// The small objects on the MCache and MCentral free lists
-// may or may not be zeroed.  They are zeroed if and only if
-// the second word of the object is zero.  A span in the
-// page heap is zeroed unless s->needzero is set. When a span
-// is allocated to break into small objects, it is zeroed if needed
-// and s->needzero is set. There are two main benefits to delaying the
-// zeroing this way:
-//
-//	1. stack frames allocated from the small object lists
-//	   or the page heap can avoid zeroing altogether.
-//	2. the cost of zeroing when reusing a small object is
-//	   charged to the mutator, not the garbage collector.
-//
-// This C code was written with an eye toward translating to Go
-// in the future.  Methods have the form Type_Method(Type *t, ...).
-
-typedef struct MCentral	MCentral;
-typedef struct MHeap	MHeap;
-typedef struct MSpan	MSpan;
-typedef struct MStats	MStats;
-typedef struct MLink	MLink;
-typedef struct GCStats	GCStats;
-
-enum
-{
-	PageShift	= 13,
-	PageSize	= 1<<PageShift,
-	PageMask	= PageSize - 1,
-};
-typedef	uintptr	pageID;		// address >> PageShift
-
-enum
-{
-	// Computed constant.  The definition of MaxSmallSize and the
-	// algorithm in msize.c produce 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.
-	NumSizeClasses = 67,
-
-	// Tunable constants.
-	MaxSmallSize = 32<<10,
-
-	// Tiny allocator parameters, see "Tiny allocator" comment in malloc.goc.
-	TinySize = 16,
-	TinySizeClass = 2,
-
-	FixAllocChunk = 16<<10,		// Chunk size for FixAlloc
-	MaxMHeapList = 1<<(20 - PageShift),	// Maximum page length for fixed-size list in MHeap.
-	HeapAllocChunk = 1<<20,		// Chunk size for heap growth
-
-	// Per-P, per order stack segment cache size.
-	StackCacheSize = 32*1024,
-	// Number of orders that get caching.  Order 0 is FixedStack
-	// and each successive order is twice as large.
-	NumStackOrders = 3,
-
-	// Number of bits in page to span calculations (4k pages).
-	// On Windows 64-bit we limit the arena to 32GB or 35 bits (see below for reason).
-	// On other 64-bit platforms, we limit the arena to 128GB, or 37 bits.
-	// On 32-bit, we don't bother limiting anything, so we use the full 32-bit address.
-#ifdef _64BIT
-#ifdef GOOS_windows
-	// Windows counts memory used by page table into committed memory
-	// of the process, so we can't reserve too much memory.
-	// See http://golang.org/issue/5402 and http://golang.org/issue/5236.
-	MHeapMap_Bits = 35 - PageShift,
-#else
-	MHeapMap_Bits = 37 - PageShift,
-#endif
-#else
-	MHeapMap_Bits = 32 - PageShift,
-#endif
-
-	// Max number of threads to run garbage collection.
-	// 2, 3, and 4 are all plausible maximums depending
-	// on the hardware details of the machine.  The garbage
-	// collector scales well to 32 cpus.
-	MaxGcproc = 32,
-};
-
-// Maximum memory allocation size, a hint for callers.
-// This must be a #define instead of an enum because it
-// is so large.
-#ifdef _64BIT
-#define	MaxMem	(1ULL<<(MHeapMap_Bits+PageShift))	/* 128 GB or 32 GB */
-#else
-#define	MaxMem	((uintptr)-1)
-#endif
-
-// A generic linked list of blocks.  (Typically the block is bigger than sizeof(MLink).)
-struct MLink
-{
-	MLink *next;
-};
-
-// sysAlloc obtains a large chunk of zeroed memory from the
-// operating system, typically on the order of a hundred kilobytes
-// or a megabyte.
-// NOTE: sysAlloc returns OS-aligned memory, but the heap allocator
-// may use larger alignment, so the caller must be careful to realign the
-// memory obtained by sysAlloc.
-//
-// SysUnused notifies the operating system that the contents
-// of the memory region are no longer needed and can be reused
-// for other purposes.
-// SysUsed notifies the operating system that the contents
-// of the memory region are needed again.
-//
-// SysFree returns it unconditionally; this is only used if
-// an out-of-memory error has been detected midway through
-// an allocation.  It is okay if SysFree is a no-op.
-//
-// SysReserve reserves address space without allocating memory.
-// If the pointer passed to it is non-nil, the caller wants the
-// reservation there, but SysReserve can still choose another
-// location if that one is unavailable.  On some systems and in some
-// cases SysReserve will simply check that the address space is
-// available and not actually reserve it.  If SysReserve returns
-// non-nil, it sets *reserved to true if the address space is
-// reserved, false if it has merely been checked.
-// NOTE: SysReserve returns OS-aligned memory, but the heap allocator
-// may use larger alignment, so the caller must be careful to realign the
-// memory obtained by sysAlloc.
-//
-// SysMap maps previously reserved address space for use.
-// The reserved argument is true if the address space was really
-// reserved, not merely checked.
-//
-// SysFault marks a (already sysAlloc'd) region to fault
-// if accessed.  Used only for debugging the runtime.
-
-void*	runtime·sysAlloc(uintptr nbytes, uint64 *stat);
-void	runtime·SysFree(void *v, uintptr nbytes, uint64 *stat);
-void	runtime·SysUnused(void *v, uintptr nbytes);
-void	runtime·SysUsed(void *v, uintptr nbytes);
-void	runtime·SysMap(void *v, uintptr nbytes, bool reserved, uint64 *stat);
-void*	runtime·SysReserve(void *v, uintptr nbytes, bool *reserved);
-void	runtime·SysFault(void *v, uintptr nbytes);
-
-// FixAlloc is a simple free-list allocator for fixed size objects.
-// Malloc uses a FixAlloc wrapped around sysAlloc to manages its
-// MCache and MSpan objects.
-//
-// Memory returned by FixAlloc_Alloc is not zeroed.
-// The caller is responsible for locking around FixAlloc calls.
-// Callers can keep state in the object but the first word is
-// smashed by freeing and reallocating.
-struct FixAlloc
-{
-	uintptr	size;
-	void	(*first)(void *arg, byte *p);	// called first time p is returned
-	void*	arg;
-	MLink*	list;
-	byte*	chunk;
-	uint32	nchunk;
-	uintptr	inuse;	// in-use bytes now
-	uint64*	stat;
-};
-
-void	runtime·FixAlloc_Init(FixAlloc *f, uintptr size, void (*first)(void*, byte*), void *arg, uint64 *stat);
-void*	runtime·FixAlloc_Alloc(FixAlloc *f);
-void	runtime·FixAlloc_Free(FixAlloc *f, void *p);
-
-
-// Statistics.
-// Shared with Go: if you edit this structure, also edit type MemStats in mem.go.
-struct MStats
-{
-	// General statistics.
-	uint64	alloc;		// bytes allocated and still in use
-	uint64	total_alloc;	// bytes allocated (even if freed)
-	uint64	sys;		// bytes obtained from system (should be sum of xxx_sys below, no locking, approximate)
-	uint64	nlookup;	// number of pointer lookups
-	uint64	nmalloc;	// number of mallocs
-	uint64	nfree;  // number of frees
-
-	// Statistics about malloc heap.
-	// protected by mheap.lock
-	uint64	heap_alloc;	// bytes allocated and still in use
-	uint64	heap_sys;	// bytes obtained from system
-	uint64	heap_idle;	// bytes in idle spans
-	uint64	heap_inuse;	// bytes in non-idle spans
-	uint64	heap_released;	// bytes released to the OS
-	uint64	heap_objects;	// total number of allocated objects
-
-	// Statistics about allocation of low-level fixed-size structures.
-	// Protected by FixAlloc locks.
-	uint64	stacks_inuse;	// this number is included in heap_inuse above
-	uint64	stacks_sys;	// always 0 in mstats
-	uint64	mspan_inuse;	// MSpan structures
-	uint64	mspan_sys;
-	uint64	mcache_inuse;	// MCache structures
-	uint64	mcache_sys;
-	uint64	buckhash_sys;	// profiling bucket hash table
-	uint64	gc_sys;
-	uint64	other_sys;
-
-	// Statistics about garbage collector.
-	// Protected by mheap or stopping the world during GC.
-	uint64	next_gc;	// next GC (in heap_alloc time)
-	uint64  last_gc;	// last GC (in absolute time)
-	uint64	pause_total_ns;
-	uint64	pause_ns[256];  // circular buffer of recent GC pause lengths
-	uint64	pause_end[256]; // circular buffer of recent GC end times (nanoseconds since 1970)
-	uint32	numgc;
-	bool	enablegc;
-	bool	debuggc;
-
-	// Statistics about allocation size classes.
-	
-	struct MStatsBySize {
-		uint32 size;
-		uint64 nmalloc;
-		uint64 nfree;
-	} by_size[NumSizeClasses];
-	
-	uint64	tinyallocs;	// number of tiny allocations that didn't cause actual allocation; not exported to Go directly
-};
-
-
-#define mstats runtime·memstats
-extern MStats mstats;
-void	runtime·updatememstats(GCStats *stats);
-void	runtime·ReadMemStats(MStats *stats);
-
-// Size classes.  Computed and initialized by InitSizes.
-//
-// SizeToClass(0 <= n <= MaxSmallSize) returns the size class,
-//	1 <= sizeclass < NumSizeClasses, for n.
-//	Size class 0 is reserved to mean "not small".
-//
-// class_to_size[i] = largest size in class i
-// class_to_allocnpages[i] = number of pages to allocate when
-//	making new objects in class i
-
-int32	runtime·SizeToClass(int32);
-uintptr	runtime·roundupsize(uintptr);
-extern	int32	runtime·class_to_size[NumSizeClasses];
-extern	int32	runtime·class_to_allocnpages[NumSizeClasses];
-extern	int8	runtime·size_to_class8[1024/8 + 1];
-extern	int8	runtime·size_to_class128[(MaxSmallSize-1024)/128 + 1];
-extern	void	runtime·InitSizes(void);
-
-typedef struct MCacheList MCacheList;
-struct MCacheList
-{
-	MLink *list;
-	uint32 nlist;
-};
-
-typedef struct StackFreeList StackFreeList;
-struct StackFreeList
-{
-	MLink *list;  // linked list of free stacks
-	uintptr size; // total size of stacks in list
-};
-
-typedef struct SudoG SudoG;
-
-// Per-thread (in Go, per-P) cache for small objects.
-// No locking needed because it is per-thread (per-P).
-struct MCache
-{
-	// The following members are accessed on every malloc,
-	// so they are grouped here for better caching.
-	int32 next_sample;		// trigger heap sample after allocating this many bytes
-	intptr local_cachealloc;	// bytes allocated (or freed) from cache since last lock of heap
-	// Allocator cache for tiny objects w/o pointers.
-	// See "Tiny allocator" comment in malloc.goc.
-	byte*	tiny;
-	uintptr	tinysize;
-	uintptr	local_tinyallocs;	// number of tiny allocs not counted in other stats
-	// The rest is not accessed on every malloc.
-	MSpan*	alloc[NumSizeClasses];	// spans to allocate from
-
-	StackFreeList stackcache[NumStackOrders];
-
-	SudoG*	sudogcache;
-
-	void*	gcworkbuf;
-
-	// Local allocator stats, flushed during GC.
-	uintptr local_nlookup;		// number of pointer lookups
-	uintptr local_largefree;	// bytes freed for large objects (>MaxSmallSize)
-	uintptr local_nlargefree;	// number of frees for large objects (>MaxSmallSize)
-	uintptr local_nsmallfree[NumSizeClasses];	// number of frees for small objects (<=MaxSmallSize)
-};
-
-MSpan*	runtime·MCache_Refill(MCache *c, int32 sizeclass);
-void	runtime·MCache_ReleaseAll(MCache *c);
-void	runtime·stackcache_clear(MCache *c);
-void	runtime·gcworkbuffree(void *b);
-
-enum
-{
-	KindSpecialFinalizer = 1,
-	KindSpecialProfile = 2,
-	// Note: The finalizer special must be first because if we're freeing
-	// an object, a finalizer special will cause the freeing operation
-	// to abort, and we want to keep the other special records around
-	// if that happens.
-};
-
-typedef struct Special Special;
-struct Special
-{
-	Special*	next;	// linked list in span
-	uint16		offset;	// span offset of object
-	byte		kind;	// kind of Special
-};
-
-// The described object has a finalizer set for it.
-typedef struct SpecialFinalizer SpecialFinalizer;
-struct SpecialFinalizer
-{
-	Special		special;
-	FuncVal*	fn;
-	uintptr		nret;
-	Type*		fint;
-	PtrType*	ot;
-};
-
-// The described object is being heap profiled.
-typedef struct Bucket Bucket; // from mprof.h
-typedef struct SpecialProfile SpecialProfile;
-struct SpecialProfile
-{
-	Special	special;
-	Bucket*	b;
-};
-
-// An MSpan is a run of pages.
-enum
-{
-	MSpanInUse = 0, // allocated for garbage collected heap
-	MSpanStack,     // allocated for use by stack allocator
-	MSpanFree,
-	MSpanListHead,
-	MSpanDead,
-};
-struct MSpan
-{
-	MSpan	*next;		// in a span linked list
-	MSpan	*prev;		// in a span linked list
-	pageID	start;		// starting page number
-	uintptr	npages;		// number of pages in span
-	MLink	*freelist;	// list of free objects
-	// sweep generation:
-	// if sweepgen == h->sweepgen - 2, the span needs sweeping
-	// if sweepgen == h->sweepgen - 1, the span is currently being swept
-	// if sweepgen == h->sweepgen, the span is swept and ready to use
-	// h->sweepgen is incremented by 2 after every GC
-	uint32	sweepgen;
-	uint16	ref;		// capacity - number of objects in freelist
-	uint8	sizeclass;	// size class
-	bool	incache;	// being used by an MCache
-	uint8	state;		// MSpanInUse etc
-	uint8	needzero;	// needs to be zeroed before allocation
-	uintptr	elemsize;	// computed from sizeclass or from npages
-	int64   unusedsince;	// First time spotted by GC in MSpanFree state
-	uintptr npreleased;	// number of pages released to the OS
-	byte	*limit;		// end of data in span
-	Mutex	specialLock;	// guards specials list
-	Special	*specials;	// linked list of special records sorted by offset.
-};
-
-void	runtime·MSpan_Init(MSpan *span, pageID start, uintptr npages);
-void	runtime·MSpan_EnsureSwept(MSpan *span);
-bool	runtime·MSpan_Sweep(MSpan *span, bool preserve);
-
-// Every MSpan is in one doubly-linked list,
-// either one of the MHeap's free lists or one of the
-// MCentral's span lists.  We use empty MSpan structures as list heads.
-void	runtime·MSpanList_Init(MSpan *list);
-bool	runtime·MSpanList_IsEmpty(MSpan *list);
-void	runtime·MSpanList_Insert(MSpan *list, MSpan *span);
-void	runtime·MSpanList_InsertBack(MSpan *list, MSpan *span);
-void	runtime·MSpanList_Remove(MSpan *span);	// from whatever list it is in
-
-
-// Central list of free objects of a given size.
-struct MCentral
-{
-	Mutex  lock;
-	int32 sizeclass;
-	MSpan nonempty;	// list of spans with a free object
-	MSpan empty;	// list of spans with no free objects (or cached in an MCache)
-};
-
-void	runtime·MCentral_Init(MCentral *c, int32 sizeclass);
-MSpan*	runtime·MCentral_CacheSpan(MCentral *c);
-void	runtime·MCentral_UncacheSpan(MCentral *c, MSpan *s);
-bool	runtime·MCentral_FreeSpan(MCentral *c, MSpan *s, int32 n, MLink *start, MLink *end, bool preserve);
-
-// Main malloc heap.
-// The heap itself is the "free[]" and "large" arrays,
-// but all the other global data is here too.
-struct MHeap
-{
-	Mutex  lock;
-	MSpan free[MaxMHeapList];	// free lists of given length
-	MSpan freelarge;		// free lists length >= MaxMHeapList
-	MSpan busy[MaxMHeapList];	// busy lists of large objects of given length
-	MSpan busylarge;		// busy lists of large objects length >= MaxMHeapList
-	MSpan **allspans;		// all spans out there
-	MSpan **gcspans;		// copy of allspans referenced by GC marker or sweeper
-	uint32	nspan;
-	uint32	nspancap;
-	uint32	sweepgen;		// sweep generation, see comment in MSpan
-	uint32	sweepdone;		// all spans are swept
-
-	// span lookup
-	MSpan**	spans;
-	uintptr	spans_mapped;
-
-	// range of addresses we might see in the heap
-	byte *bitmap;
-	uintptr bitmap_mapped;
-	byte *arena_start;
-	byte *arena_used;
-	byte *arena_end;
-	bool arena_reserved;
-
-	// central free lists for small size classes.
-	// the padding makes sure that the MCentrals are
-	// spaced CacheLineSize bytes apart, so that each MCentral.lock
-	// gets its own cache line.
-	struct MHeapCentral {
-		MCentral mcentral;
-		byte pad[CacheLineSize];
-	} central[NumSizeClasses];
-
-	FixAlloc spanalloc;	// allocator for Span*
-	FixAlloc cachealloc;	// allocator for MCache*
-	FixAlloc specialfinalizeralloc;	// allocator for SpecialFinalizer*
-	FixAlloc specialprofilealloc;	// allocator for SpecialProfile*
-	Mutex speciallock; // lock for sepcial record allocators.
-
-	// Malloc stats.
-	uint64 largefree;	// bytes freed for large objects (>MaxSmallSize)
-	uint64 nlargefree;	// number of frees for large objects (>MaxSmallSize)
-	uint64 nsmallfree[NumSizeClasses];	// number of frees for small objects (<=MaxSmallSize)
-};
-#define runtime·mheap runtime·mheap_
-extern MHeap runtime·mheap;
-
-void	runtime·MHeap_Init(MHeap *h);
-MSpan*	runtime·MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass, bool large, bool needzero);
-MSpan*	runtime·MHeap_AllocStack(MHeap *h, uintptr npage);
-void	runtime·MHeap_Free(MHeap *h, MSpan *s, int32 acct);
-void	runtime·MHeap_FreeStack(MHeap *h, MSpan *s);
-MSpan*	runtime·MHeap_Lookup(MHeap *h, void *v);
-MSpan*	runtime·MHeap_LookupMaybe(MHeap *h, void *v);
-void*	runtime·MHeap_SysAlloc(MHeap *h, uintptr n);
-void	runtime·MHeap_MapBits(MHeap *h);
-void	runtime·MHeap_MapSpans(MHeap *h);
-void	runtime·MHeap_Scavenge(int32 k, uint64 now, uint64 limit);
-
-void*	runtime·persistentalloc(uintptr size, uintptr align, uint64 *stat);
-int32	runtime·mlookup(void *v, byte **base, uintptr *size, MSpan **s);
-uintptr	runtime·sweepone(void);
-void	runtime·markspan(void *v, uintptr size, uintptr n, bool leftover);
-void	runtime·unmarkspan(void *v, uintptr size);
-void	runtime·purgecachedstats(MCache*);
-void	runtime·tracealloc(void*, uintptr, Type*);
-void	runtime·tracefree(void*, uintptr);
-void	runtime·tracegc(void);
-
-int32	runtime·gcpercent;
-int32	runtime·readgogc(void);
-void	runtime·clearpools(void);
-
-enum
-{
-	// flags to malloc
-	FlagNoScan	= 1<<0,	// GC doesn't have to scan object
-	FlagNoZero	= 1<<1, // don't zero memory
-};
-
-void	runtime·mProf_Malloc(void*, uintptr);
-void	runtime·mProf_Free(Bucket*, uintptr, bool);
-void	runtime·mProf_GC(void);
-void	runtime·iterate_memprof(void (**callback)(Bucket*, uintptr, uintptr*, uintptr, uintptr, uintptr));
-int32	runtime·gcprocs(void);
-void	runtime·helpgc(int32 nproc);
-void	runtime·gchelper(void);
-void	runtime·createfing(void);
-G*	runtime·wakefing(void);
-void	runtime·getgcmask(byte*, Type*, byte**, uintptr*);
-
-// NOTE: Layout known to queuefinalizer.
-typedef struct Finalizer Finalizer;
-struct Finalizer
-{
-	FuncVal *fn;	// function to call
-	void *arg;	// ptr to object
-	uintptr nret;	// bytes of return values from fn
-	Type *fint;	// type of first argument of fn
-	PtrType *ot;	// type of ptr to object
-};
-
-typedef struct FinBlock FinBlock;
-struct FinBlock
-{
-	FinBlock *alllink;
-	FinBlock *next;
-	int32 cnt;
-	int32 cap;
-	Finalizer fin[1];
-};
-extern Mutex	runtime·finlock;	// protects the following variables
-extern G*	runtime·fing;
-extern bool	runtime·fingwait;
-extern bool	runtime·fingwake;
-extern FinBlock	*runtime·finq;		// list of finalizers that are to be executed
-extern FinBlock	*runtime·finc;		// cache of free blocks
-
-void	runtime·setprofilebucket_m(void);
-
-bool	runtime·addfinalizer(void*, FuncVal *fn, uintptr, Type*, PtrType*);
-void	runtime·removefinalizer(void*);
-void	runtime·queuefinalizer(byte *p, FuncVal *fn, uintptr nret, Type *fint, PtrType *ot);
-bool	runtime·freespecial(Special *s, void *p, uintptr size, bool freed);
-
-// Information from the compiler about the layout of stack frames.
-struct BitVector
-{
-	int32 n; // # of bits
-	uint8 *bytedata;
-};
-typedef struct StackMap StackMap;
-struct StackMap
-{
-	int32 n; // number of bitmaps
-	int32 nbit; // number of bits in each bitmap
-	uint8 bytedata[]; // bitmaps, each starting on a 32-bit boundary
-};
-// Returns pointer map data for the given stackmap index
-// (the index is encoded in PCDATA_StackMapIndex).
-BitVector	runtime·stackmapdata(StackMap *stackmap, int32 n);
-
-extern	BitVector	runtime·gcdatamask;
-extern	BitVector	runtime·gcbssmask;
-
-// defined in mgc0.go
-void	runtime·gc_m_ptr(Eface*);
-void	runtime·gc_g_ptr(Eface*);
-void	runtime·gc_itab_ptr(Eface*);
-
-void  runtime·setgcpercent_m(void);
-
-// Value we use to mark dead pointers when GODEBUG=gcdead=1.
-#define PoisonGC ((uintptr)0xf969696969696969ULL)
-#define PoisonStack ((uintptr)0x6868686868686868ULL)
diff --git a/src/runtime/malloc_test.go b/src/runtime/malloc_test.go
index b7795aa..f0e73ba 100644
--- a/src/runtime/malloc_test.go
+++ b/src/runtime/malloc_test.go
@@ -32,7 +32,7 @@ func TestMemStats(t *testing.T) {
 		st.HeapIdle > 1e10 || st.HeapInuse > 1e10 || st.HeapObjects > 1e10 || st.StackInuse > 1e10 ||
 		st.StackSys > 1e10 || st.MSpanInuse > 1e10 || st.MSpanSys > 1e10 || st.MCacheInuse > 1e10 ||
 		st.MCacheSys > 1e10 || st.BuckHashSys > 1e10 || st.GCSys > 1e10 || st.OtherSys > 1e10 ||
-		st.NextGC > 1e10 || st.NumGC > 1e9 {
+		st.NextGC > 1e10 || st.NumGC > 1e9 || st.PauseTotalNs > 1e11 {
 		t.Fatalf("Insanely high value (overflow?): %+v", *st)
 	}
 
@@ -44,6 +44,42 @@ func TestMemStats(t *testing.T) {
 	if st.HeapIdle+st.HeapInuse != st.HeapSys {
 		t.Fatalf("HeapIdle(%d) + HeapInuse(%d) should be equal to HeapSys(%d), but isn't.", st.HeapIdle, st.HeapInuse, st.HeapSys)
 	}
+
+	if lpe := st.PauseEnd[int(st.NumGC+255)%len(st.PauseEnd)]; st.LastGC != lpe {
+		t.Fatalf("LastGC(%d) != last PauseEnd(%d)", st.LastGC, lpe)
+	}
+
+	var pauseTotal uint64
+	for _, pause := range st.PauseNs {
+		pauseTotal += pause
+	}
+	if int(st.NumGC) < len(st.PauseNs) {
+		// We have all pauses, so this should be exact.
+		if st.PauseTotalNs != pauseTotal {
+			t.Fatalf("PauseTotalNs(%d) != sum PauseNs(%d)", st.PauseTotalNs, pauseTotal)
+		}
+	} else {
+		if st.PauseTotalNs < pauseTotal {
+			t.Fatalf("PauseTotalNs(%d) < sum PauseNs(%d)", st.PauseTotalNs, pauseTotal)
+		}
+	}
+}
+
+func TestStringConcatenationAllocs(t *testing.T) {
+	n := testing.AllocsPerRun(1e3, func() {
+		b := make([]byte, 10)
+		for i := 0; i < 10; i++ {
+			b[i] = byte(i) + '0'
+		}
+		s := "foo" + string(b)
+		if want := "foo0123456789"; s != want {
+			t.Fatalf("want %v, got %v", want, s)
+		}
+	})
+	// Only string concatenation allocates.
+	if n != 1 {
+		t.Fatalf("want 1 allocation, got %v", n)
+	}
 }
 
 var mallocSink uintptr
diff --git a/src/runtime/map_test.go b/src/runtime/map_test.go
index 92da2d8..9d2894c 100644
--- a/src/runtime/map_test.go
+++ b/src/runtime/map_test.go
@@ -515,6 +515,61 @@ func TestMapStringBytesLookup(t *testing.T) {
 	}
 }
 
+func TestMapLargeKeyNoPointer(t *testing.T) {
+	const (
+		I = 1000
+		N = 64
+	)
+	type T [N]int
+	m := make(map[T]int)
+	for i := 0; i < I; i++ {
+		var v T
+		for j := 0; j < N; j++ {
+			v[j] = i + j
+		}
+		m[v] = i
+	}
+	runtime.GC()
+	for i := 0; i < I; i++ {
+		var v T
+		for j := 0; j < N; j++ {
+			v[j] = i + j
+		}
+		if m[v] != i {
+			t.Fatalf("corrupted map: want %+v, got %+v", i, m[v])
+		}
+	}
+}
+
+func TestMapLargeValNoPointer(t *testing.T) {
+	const (
+		I = 1000
+		N = 64
+	)
+	type T [N]int
+	m := make(map[int]T)
+	for i := 0; i < I; i++ {
+		var v T
+		for j := 0; j < N; j++ {
+			v[j] = i + j
+		}
+		m[i] = v
+	}
+	runtime.GC()
+	for i := 0; i < I; i++ {
+		var v T
+		for j := 0; j < N; j++ {
+			v[j] = i + j
+		}
+		v1 := m[i]
+		for j := 0; j < N; j++ {
+			if v1[j] != v[j] {
+				t.Fatalf("corrupted map: want %+v, got %+v", v, v1)
+			}
+		}
+	}
+}
+
 func benchmarkMapPop(b *testing.B, n int) {
 	m := map[int]int{}
 	for i := 0; i < b.N; i++ {
@@ -535,3 +590,13 @@ func benchmarkMapPop(b *testing.B, n int) {
 func BenchmarkMapPop100(b *testing.B)   { benchmarkMapPop(b, 100) }
 func BenchmarkMapPop1000(b *testing.B)  { benchmarkMapPop(b, 1000) }
 func BenchmarkMapPop10000(b *testing.B) { benchmarkMapPop(b, 10000) }
+
+func TestNonEscapingMap(t *testing.T) {
+	n := testing.AllocsPerRun(1000, func() {
+		m := make(map[int]int)
+		m[0] = 0
+	})
+	if n != 0 {
+		t.Fatalf("want 0 allocs, got %v", n)
+	}
+}
diff --git a/src/runtime/mapspeed_test.go b/src/runtime/mapspeed_test.go
index 119eb3f..ac93119 100644
--- a/src/runtime/mapspeed_test.go
+++ b/src/runtime/mapspeed_test.go
@@ -234,6 +234,15 @@ func BenchmarkNewEmptyMap(b *testing.B) {
 	}
 }
 
+func BenchmarkNewSmallMap(b *testing.B) {
+	b.ReportAllocs()
+	for i := 0; i < b.N; i++ {
+		m := make(map[int]int)
+		m[0] = 0
+		m[1] = 1
+	}
+}
+
 func BenchmarkMapIter(b *testing.B) {
 	m := make(map[int]bool)
 	for i := 0; i < 8; i++ {
@@ -298,3 +307,22 @@ func BenchmarkSmallKeyMap(b *testing.B) {
 		_ = m[5]
 	}
 }
+
+type ComplexAlgKey struct {
+	a, b, c int64
+	_       int
+	d       int32
+	_       int
+	e       string
+	_       int
+	f, g, h int64
+}
+
+func BenchmarkComplexAlgMap(b *testing.B) {
+	m := make(map[ComplexAlgKey]bool)
+	var k ComplexAlgKey
+	m[k] = true
+	for i := 0; i < b.N; i++ {
+		_ = m[k]
+	}
+}
diff --git a/src/runtime/mbarrier.go b/src/runtime/mbarrier.go
new file mode 100644
index 0000000..0dbe1ff
--- /dev/null
+++ b/src/runtime/mbarrier.go
@@ -0,0 +1,298 @@
+// 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.
+
+// Garbage collector: write barriers.
+//
+// For the concurrent garbage collector, the Go compiler implements
+// updates to pointer-valued fields that may be in heap objects by
+// emitting calls to write barriers. This file contains the actual write barrier
+// implementation, markwb, and the various wrappers called by the
+// compiler to implement pointer assignment, slice assignment,
+// typed memmove, and so on.
+
+package runtime
+
+import "unsafe"
+
+// markwb is the mark-phase write barrier, the only barrier we have.
+// The rest of this file exists only to make calls to this function.
+//
+// This is the Dijkstra barrier coarsened to always shade the ptr (dst) object.
+// The original Dijkstra barrier only shaded ptrs being placed in black slots.
+//
+// Shade indicates that it has seen a white pointer by adding the referent
+// to wbuf as well as marking it.
+//
+// slot is the destination (dst) in go code
+// ptr is the value that goes into the slot (src) in the go code
+//
+//
+// Dealing with memory ordering:
+//
+// Dijkstra pointed out that maintaining the no black to white
+// pointers means that white to white pointers not need
+// to be noted by the write barrier. Furthermore if either
+// white object dies before it is reached by the
+// GC then the object can be collected during this GC cycle
+// instead of waiting for the next cycle. Unfortunately the cost of
+// ensure that the object holding the slot doesn't concurrently
+// change to black without the mutator noticing seems prohibitive.
+//
+// Consider the following example where the mutator writes into
+// a slot and then loads the slot's mark bit while the GC thread
+// writes to the slot's mark bit and then as part of scanning reads
+// the slot.
+//
+// Initially both [slot] and [slotmark] are 0 (nil)
+// Mutator thread          GC thread
+// st [slot], ptr          st [slotmark], 1
+//
+// ld r1, [slotmark]       ld r2, [slot]
+//
+// 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.
+//
+// Another place where we intentionally omit memory barriers is when
+// accessing mheap_.arena_used to check if a pointer points into the
+// heap. On relaxed memory machines, it's possible for a mutator to
+// extend the size of the heap by updating arena_used, allocate an
+// object from this new region, and publish a pointer to that object,
+// but for tracing running on another processor to observe the pointer
+// but use the old value of arena_used. In this case, tracing will not
+// mark the object, even though it's reachable. However, the mutator
+// is guaranteed to execute a write barrier when it publishes the
+// pointer, so it will take care of marking the object. A general
+// consequence of this is that the garbage collector may cache the
+// value of mheap_.arena_used. (See issue #9984.)
+//
+//
+// Stack writes:
+//
+// The compiler omits write barriers for writes to the current frame,
+// but if a stack pointer has been passed down the call stack, the
+// compiler will generate a write barrier for writes through that
+// pointer (because it doesn't know it's not a heap pointer).
+//
+// One might be tempted to ignore the write barrier if slot points
+// into to the stack. Don't do it! Mark termination only re-scans
+// frames that have potentially been active since the concurrent scan,
+// so it depends on write barriers to track changes to pointers in
+// stack frames that have not been active.
+//go:nowritebarrier
+func gcmarkwb_m(slot *uintptr, ptr uintptr) {
+	if writeBarrierEnabled {
+		if ptr != 0 && inheap(ptr) {
+			shade(ptr)
+		}
+	}
+}
+
+// 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.
+//go:nosplit
+func writebarrierptr_nostore1(dst *uintptr, src uintptr) {
+	mp := acquirem()
+	if mp.inwb || mp.dying > 0 {
+		releasem(mp)
+		return
+	}
+	systemstack(func() {
+		if mp.p == 0 && memstats.enablegc && !mp.inwb && inheap(src) {
+			throw("writebarrierptr_nostore1 called with mp.p == nil")
+		}
+		mp.inwb = true
+		gcmarkwb_m(dst, src)
+	})
+	mp.inwb = false
+	releasem(mp)
+}
+
+// NOTE: Really dst *unsafe.Pointer, src unsafe.Pointer,
+// but if we do that, Go inserts a write barrier on *dst = src.
+//go:nosplit
+func writebarrierptr(dst *uintptr, src uintptr) {
+	*dst = src
+	if !writeBarrierEnabled {
+		return
+	}
+	if src != 0 && (src < _PhysPageSize || src == poisonStack) {
+		systemstack(func() {
+			print("runtime: writebarrierptr *", dst, " = ", hex(src), "\n")
+			throw("bad pointer in write barrier")
+		})
+	}
+	writebarrierptr_nostore1(dst, src)
+}
+
+// Like writebarrierptr, but the store has already been applied.
+// Do not reapply.
+//go:nosplit
+func writebarrierptr_nostore(dst *uintptr, src uintptr) {
+	if !writeBarrierEnabled {
+		return
+	}
+	if src != 0 && (src < _PhysPageSize || src == poisonStack) {
+		systemstack(func() { throw("bad pointer in write barrier") })
+	}
+	writebarrierptr_nostore1(dst, src)
+}
+
+//go:nosplit
+func writebarrierstring(dst *[2]uintptr, src [2]uintptr) {
+	writebarrierptr(&dst[0], src[0])
+	dst[1] = src[1]
+}
+
+//go:nosplit
+func writebarrierslice(dst *[3]uintptr, src [3]uintptr) {
+	writebarrierptr(&dst[0], src[0])
+	dst[1] = src[1]
+	dst[2] = src[2]
+}
+
+//go:nosplit
+func writebarrieriface(dst *[2]uintptr, src [2]uintptr) {
+	writebarrierptr(&dst[0], src[0])
+	writebarrierptr(&dst[1], src[1])
+}
+
+//go:generate go run wbfat_gen.go -- wbfat.go
+//
+// The above line generates multiword write barriers for
+// all the combinations of ptr+scalar up to four words.
+// The implementations are written to wbfat.go.
+
+// typedmemmove copies a value of type t to dst from src.
+//go:nosplit
+func typedmemmove(typ *_type, dst, src unsafe.Pointer) {
+	memmove(dst, src, typ.size)
+	if typ.kind&kindNoPointers != 0 {
+		return
+	}
+	heapBitsBulkBarrier(uintptr(dst), typ.size)
+}
+
+//go:linkname reflect_typedmemmove reflect.typedmemmove
+func reflect_typedmemmove(typ *_type, dst, src unsafe.Pointer) {
+	typedmemmove(typ, dst, src)
+}
+
+// typedmemmovepartial is like typedmemmove but assumes that
+// dst and src point off bytes into the value and only copies size bytes.
+//go:linkname reflect_typedmemmovepartial reflect.typedmemmovepartial
+func reflect_typedmemmovepartial(typ *_type, dst, src unsafe.Pointer, off, size uintptr) {
+	memmove(dst, src, size)
+	if !writeBarrierEnabled || typ.kind&kindNoPointers != 0 || size < ptrSize || !inheap(uintptr(dst)) {
+		return
+	}
+
+	if frag := -off & (ptrSize - 1); frag != 0 {
+		dst = add(dst, frag)
+		size -= frag
+	}
+	heapBitsBulkBarrier(uintptr(dst), size&^(ptrSize-1))
+}
+
+// callwritebarrier is invoked at the end of reflectcall, to execute
+// write barrier operations to record the fact that a call's return
+// values have just been copied to frame, starting at retoffset
+// and continuing to framesize. The entire frame (not just the return
+// values) is described by typ. Because the copy has already
+// happened, we call writebarrierptr_nostore, and we must be careful
+// not to be preempted before the write barriers have been run.
+//go:nosplit
+func callwritebarrier(typ *_type, frame unsafe.Pointer, framesize, retoffset uintptr) {
+	if !writeBarrierEnabled || typ == nil || typ.kind&kindNoPointers != 0 || framesize-retoffset < ptrSize || !inheap(uintptr(frame)) {
+		return
+	}
+	heapBitsBulkBarrier(uintptr(add(frame, retoffset)), framesize-retoffset)
+}
+
+//go:nosplit
+func typedslicecopy(typ *_type, dst, src slice) int {
+	// TODO(rsc): If typedslicecopy becomes faster than calling
+	// typedmemmove repeatedly, consider using during func growslice.
+	n := dst.len
+	if n > src.len {
+		n = src.len
+	}
+	if n == 0 {
+		return 0
+	}
+	dstp := unsafe.Pointer(dst.array)
+	srcp := unsafe.Pointer(src.array)
+
+	if raceenabled {
+		callerpc := getcallerpc(unsafe.Pointer(&typ))
+		pc := funcPC(slicecopy)
+		racewriterangepc(dstp, uintptr(n)*typ.size, callerpc, pc)
+		racereadrangepc(srcp, uintptr(n)*typ.size, callerpc, pc)
+	}
+
+	// Note: No point in checking typ.kind&kindNoPointers here:
+	// compiler only emits calls to typedslicecopy for types with pointers,
+	// and growslice and reflect_typedslicecopy check for pointers
+	// before calling typedslicecopy.
+	if !writeBarrierEnabled {
+		memmove(dstp, srcp, uintptr(n)*typ.size)
+		return n
+	}
+
+	systemstack(func() {
+		if uintptr(srcp) < uintptr(dstp) && uintptr(srcp)+uintptr(n)*typ.size > uintptr(dstp) {
+			// Overlap with src before dst.
+			// Copy backward, being careful not to move dstp/srcp
+			// out of the array they point into.
+			dstp = add(dstp, uintptr(n-1)*typ.size)
+			srcp = add(srcp, uintptr(n-1)*typ.size)
+			i := 0
+			for {
+				typedmemmove(typ, dstp, srcp)
+				if i++; i >= n {
+					break
+				}
+				dstp = add(dstp, -typ.size)
+				srcp = add(srcp, -typ.size)
+			}
+		} else {
+			// Copy forward, being careful not to move dstp/srcp
+			// out of the array they point into.
+			i := 0
+			for {
+				typedmemmove(typ, dstp, srcp)
+				if i++; i >= n {
+					break
+				}
+				dstp = add(dstp, typ.size)
+				srcp = add(srcp, typ.size)
+			}
+		}
+	})
+	return int(n)
+}
+
+//go:linkname reflect_typedslicecopy reflect.typedslicecopy
+func reflect_typedslicecopy(elemType *_type, dst, src slice) int {
+	if elemType.kind&kindNoPointers != 0 {
+		n := dst.len
+		if n > src.len {
+			n = src.len
+		}
+		memmove(dst.array, src.array, uintptr(n)*elemType.size)
+		return n
+	}
+	return typedslicecopy(elemType, dst, src)
+}
diff --git a/src/runtime/mbitmap.go b/src/runtime/mbitmap.go
new file mode 100644
index 0000000..fd6b4b1
--- /dev/null
+++ b/src/runtime/mbitmap.go
@@ -0,0 +1,1710 @@
+// 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.
+
+// Garbage collector: type and heap bitmaps.
+//
+// Stack, data, and bss bitmaps
+//
+// Stack frames and global variables in the data and bss sections are described
+// by 1-bit bitmaps in which 0 means uninteresting and 1 means live pointer
+// to be visited during GC. The bits in each byte are consumed starting with
+// the low bit: 1<<0, 1<<1, and so on.
+//
+// Heap bitmap
+//
+// The allocated heap comes from a subset of the memory in the range [start, used),
+// where start == mheap_.arena_start and used == mheap_.arena_used.
+// The heap bitmap comprises 2 bits for each pointer-sized word in that range,
+// stored in bytes indexed backward in memory from start.
+// That is, the byte at address start-1 holds the 2-bit entries for the four words
+// start through start+3*ptrSize, the byte at start-2 holds the entries for
+// start+4*ptrSize through start+7*ptrSize, and so on.
+//
+// In each 2-bit entry, the lower bit holds the same information as in the 1-bit
+// bitmaps: 0 means uninteresting and 1 means live pointer to be visited during GC.
+// The meaning of the high bit depends on the position of the word being described
+// in its allocated object. In the first word, the high bit is the GC ``marked'' bit.
+// In the second word, the high bit is the GC ``checkmarked'' bit (see below).
+// In the third and later words, the high bit indicates that the object is still
+// being described. In these words, if a bit pair with a high bit 0 is encountered,
+// the low bit can also be assumed to be 0, and the object description is over.
+// This 00 is called the ``dead'' encoding: it signals that the rest of the words
+// in the object are uninteresting to the garbage collector.
+//
+// The 2-bit entries are split when written into the byte, so that the top half
+// of the byte contains 4 mark bits and the bottom half contains 4 pointer bits.
+// This form allows a copy from the 1-bit to the 4-bit form to keep the
+// pointer bits contiguous, instead of having to space them out.
+//
+// The code makes use of the fact that the zero value for a heap bitmap
+// has no live pointer bit set and is (depending on position), not marked,
+// not checkmarked, and is the dead encoding.
+// These properties must be preserved when modifying the encoding.
+//
+// Checkmarks
+//
+// In a concurrent garbage collector, one worries about failing to mark
+// a live object due to mutations without write barriers or bugs in the
+// collector implementation. As a sanity check, the GC has a 'checkmark'
+// mode that retraverses the object graph with the world stopped, to make
+// sure that everything that should be marked is marked.
+// In checkmark mode, in the heap bitmap, the high bit of the 2-bit entry
+// for the second word of the object holds the checkmark bit.
+// When not in checkmark mode, this bit is set to 1.
+//
+// The smallest possible allocation is 8 bytes. On a 32-bit machine, that
+// means every allocated object has two words, so there is room for the
+// checkmark bit. On a 64-bit machine, however, the 8-byte allocation is
+// just one word, so the second bit pair is not available for encoding the
+// checkmark. However, because non-pointer allocations are combined
+// into larger 16-byte (maxTinySize) allocations, a plain 8-byte allocation
+// must be a pointer, so the type bit in the first word is not actually needed.
+// It is still used in general, except in checkmark the type bit is repurposed
+// as the checkmark bit and then reinitialized (to 1) as the type bit when
+// finished.
+
+package runtime
+
+import "unsafe"
+
+const (
+	bitPointer = 1 << 0
+	bitMarked  = 1 << 4
+
+	heapBitsShift   = 1                 // shift offset between successive bitPointer or bitMarked entries
+	heapBitmapScale = ptrSize * (8 / 2) // number of data bytes described by one heap bitmap byte
+
+	// all mark/pointer bits in a byte
+	bitMarkedAll  = bitMarked | bitMarked<<heapBitsShift | bitMarked<<(2*heapBitsShift) | bitMarked<<(3*heapBitsShift)
+	bitPointerAll = bitPointer | bitPointer<<heapBitsShift | bitPointer<<(2*heapBitsShift) | bitPointer<<(3*heapBitsShift)
+)
+
+// addb returns the byte pointer p+n.
+//go:nowritebarrier
+func addb(p *byte, n uintptr) *byte {
+	// Note: wrote out full expression instead of calling add(p, n)
+	// to reduce the number of temporaries generated by the
+	// compiler for this trivial expression during inlining.
+	return (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) + n))
+}
+
+// subtractb returns the byte pointer p-n.
+//go:nowritebarrier
+func subtractb(p *byte, n uintptr) *byte {
+	// Note: wrote out full expression instead of calling add(p, -n)
+	// to reduce the number of temporaries generated by the
+	// compiler for this trivial expression during inlining.
+	return (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) - n))
+}
+
+// add1 returns the byte pointer p+1.
+//go:nowritebarrier
+func add1(p *byte) *byte {
+	// Note: wrote out full expression instead of calling addb(p, 1)
+	// to reduce the number of temporaries generated by the
+	// compiler for this trivial expression during inlining.
+	return (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) + 1))
+}
+
+// subtract1 returns the byte pointer p-1.
+//go:nowritebarrier
+//
+// nosplit because it is used during write barriers and must not be preempted.
+//go:nosplit
+func subtract1(p *byte) *byte {
+	// Note: wrote out full expression instead of calling subtractb(p, 1)
+	// to reduce the number of temporaries generated by the
+	// compiler for this trivial expression during inlining.
+	return (*byte)(unsafe.Pointer(uintptr(unsafe.Pointer(p)) - 1))
+}
+
+// mHeap_MapBits is called each time arena_used is extended.
+// It maps any additional bitmap memory needed for the new arena memory.
+// It must be called with the expected new value of arena_used,
+// *before* h.arena_used has been updated.
+// Waiting to update arena_used until after the memory has been mapped
+// avoids faults when other threads try access the bitmap immediately
+// after observing the change to arena_used.
+//
+//go:nowritebarrier
+func mHeap_MapBits(h *mheap, arena_used uintptr) {
+	// Caller has added extra mappings to the arena.
+	// Add extra mappings of bitmap words as needed.
+	// We allocate extra bitmap pieces in chunks of bitmapChunk.
+	const bitmapChunk = 8192
+
+	n := (arena_used - mheap_.arena_start) / heapBitmapScale
+	n = round(n, bitmapChunk)
+	n = round(n, _PhysPageSize)
+	if h.bitmap_mapped >= n {
+		return
+	}
+
+	sysMap(unsafe.Pointer(h.arena_start-n), n-h.bitmap_mapped, h.arena_reserved, &memstats.gc_sys)
+	h.bitmap_mapped = n
+}
+
+// heapBits provides access to the bitmap bits for a single heap word.
+// The methods on heapBits take value receivers so that the compiler
+// can more easily inline calls to those methods and registerize the
+// struct fields independently.
+type heapBits struct {
+	bitp  *uint8
+	shift uint32
+}
+
+// heapBitsForAddr returns the heapBits for the address addr.
+// The caller must have already checked that addr is in the range [mheap_.arena_start, mheap_.arena_used).
+//
+// nosplit because it is used during write barriers and must not be preempted.
+//go:nosplit
+func heapBitsForAddr(addr uintptr) heapBits {
+	// 2 bits per work, 4 pairs per byte, and a mask is hard coded.
+	off := (addr - mheap_.arena_start) / ptrSize
+	return heapBits{(*uint8)(unsafe.Pointer(mheap_.arena_start - off/4 - 1)), uint32(off & 3)}
+}
+
+// heapBitsForSpan returns the heapBits for the span base address base.
+func heapBitsForSpan(base uintptr) (hbits heapBits) {
+	if base < mheap_.arena_start || base >= mheap_.arena_used {
+		throw("heapBitsForSpan: base out of range")
+	}
+	hbits = heapBitsForAddr(base)
+	if hbits.shift != 0 {
+		throw("heapBitsForSpan: unaligned start")
+	}
+	return hbits
+}
+
+// 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,
+// return base == 0
+// otherwise return the base of the object.
+func heapBitsForObject(p uintptr) (base uintptr, hbits heapBits, s *mspan) {
+	arenaStart := mheap_.arena_start
+	if p < arenaStart || p >= mheap_.arena_used {
+		return
+	}
+	off := p - arenaStart
+	idx := off >> _PageShift
+	// p points into the heap, but possibly to the middle of an object.
+	// Consult the span table to find the block beginning.
+	k := p >> _PageShift
+	s = h_spans[idx]
+	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.
+			// This pointer may be to some mmap'd region, so we allow it.
+			// Pointers into stacks are also ok, the runtime manages these explicitly.
+			return
+		}
+
+		// The following ensures that we are rigorous about what data
+		// structures hold valid pointers.
+		// TODO(rsc): Check if this still happens.
+		if debug.invalidptr != 0 {
+			// Still happens sometimes. We don't know why.
+			printlock()
+			print("runtime:objectstart Span weird: p=", hex(p), " k=", hex(k))
+			if s == nil {
+				print(" s=nil\n")
+			} else {
+				print(" s.start=", hex(s.start<<_PageShift), " s.limit=", hex(s.limit), " s.state=", s.state, "\n")
+			}
+			printunlock()
+			throw("objectstart: bad pointer in unexpected span")
+		}
+		return
+	}
+	// If this span holds object of a power of 2 size, just mask off the bits to
+	// the interior of the object. Otherwise use the size to get the base.
+	if s.baseMask != 0 {
+		// optimize for power of 2 sized objects.
+		base = s.base()
+		base = base + (p-base)&s.baseMask
+		// base = p & s.baseMask is faster for small spans,
+		// but doesn't work for large spans.
+		// Overall, it's faster to use the more general computation above.
+	} else {
+		base = s.base()
+		if p-base >= s.elemsize {
+			// n := (p - base) / s.elemsize, using division by multiplication
+			n := uintptr(uint64(p-base) >> s.divShift * uint64(s.divMul) >> s.divShift2)
+			base += n * s.elemsize
+		}
+	}
+	// Now that we know the actual base, compute heapBits to return to caller.
+	hbits = heapBitsForAddr(base)
+	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.
+//
+// nosplit because it is used during write barriers and must not be preempted.
+//go:nosplit
+func (h heapBits) next() heapBits {
+	if h.shift < 3*heapBitsShift {
+		return heapBits{h.bitp, h.shift + heapBitsShift}
+	}
+	return heapBits{subtract1(h.bitp), 0}
+}
+
+// forward returns the heapBits describing n pointer-sized words ahead of h in memory.
+// That is, if h describes address p, h.forward(n) describes p+n*ptrSize.
+// h.forward(1) is equivalent to h.next(), just slower.
+// Note that forward does not modify h. The caller must record the result.
+// bits returns the heap bits for the current word.
+func (h heapBits) forward(n uintptr) heapBits {
+	n += uintptr(h.shift) / heapBitsShift
+	return heapBits{subtractb(h.bitp, n/4), uint32(n%4) * heapBitsShift}
+}
+
+// The caller can test isMarked and isPointer by &-ing with bitMarked and bitPointer.
+// The result includes in its higher bits the bits for subsequent words
+// described by the same bitmap byte.
+func (h heapBits) bits() uint32 {
+	return uint32(*h.bitp) >> h.shift
+}
+
+// isMarked reports whether the heap bits have the marked bit set.
+// h must describe the initial word of the object.
+func (h heapBits) isMarked() bool {
+	return *h.bitp&(bitMarked<<h.shift) != 0
+}
+
+// setMarked sets the marked bit in the heap bits, atomically.
+// h must describe the initial word of the object.
+func (h heapBits) setMarked() {
+	// Each byte of GC bitmap holds info for four words.
+	// Might be racing with other updates, so use atomic update always.
+	// We used to be clever here and use a non-atomic update in certain
+	// cases, but it's not worth the risk.
+	atomicor8(h.bitp, bitMarked<<h.shift)
+}
+
+// setMarkedNonAtomic sets the marked bit in the heap bits, non-atomically.
+// h must describe the initial word of the object.
+func (h heapBits) setMarkedNonAtomic() {
+	*h.bitp |= bitMarked << h.shift
+}
+
+// isPointer reports whether the heap bits describe a pointer word.
+// h must describe the initial word of the object.
+//
+// nosplit because it is used during write barriers and must not be preempted.
+//go:nosplit
+func (h heapBits) isPointer() bool {
+	return (*h.bitp>>h.shift)&bitPointer != 0
+}
+
+// hasPointers reports whether the given object has any pointers.
+// It must be told how large the object at h is, so that it does not read too
+// far into the bitmap.
+// h must describe the initial word of the object.
+func (h heapBits) hasPointers(size uintptr) bool {
+	if size == ptrSize { // 1-word objects are always pointers
+		return true
+	}
+	// Otherwise, at least a 2-word object, and at least 2-word aligned,
+	// so h.shift is either 0 or 4, so we know we can get the bits for the
+	// first two words out of *h.bitp.
+	// If either of the first two words is a pointer, not pointer free.
+	b := uint32(*h.bitp >> h.shift)
+	if b&(bitPointer|bitPointer<<heapBitsShift) != 0 {
+		return true
+	}
+	if size == 2*ptrSize {
+		return false
+	}
+	// At least a 4-word object. Check scan bit (aka marked bit) in third word.
+	if h.shift == 0 {
+		return b&(bitMarked<<(2*heapBitsShift)) != 0
+	}
+	return uint32(*subtract1(h.bitp))&bitMarked != 0
+}
+
+// isCheckmarked reports whether the heap bits have the checkmarked bit set.
+// It must be told how large the object at h is, because the encoding of the
+// checkmark bit varies by size.
+// h must describe the initial word of the object.
+func (h heapBits) isCheckmarked(size uintptr) bool {
+	if size == ptrSize {
+		return (*h.bitp>>h.shift)&bitPointer != 0
+	}
+	// All multiword objects are 2-word aligned,
+	// so we know that the initial word's 2-bit pair
+	// and the second word's 2-bit pair are in the
+	// same heap bitmap byte, *h.bitp.
+	return (*h.bitp>>(heapBitsShift+h.shift))&bitMarked != 0
+}
+
+// setCheckmarked sets the checkmarked bit.
+// It must be told how large the object at h is, because the encoding of the
+// checkmark bit varies by size.
+// h must describe the initial word of the object.
+func (h heapBits) setCheckmarked(size uintptr) {
+	if size == ptrSize {
+		atomicor8(h.bitp, bitPointer<<h.shift)
+		return
+	}
+	atomicor8(h.bitp, bitMarked<<(heapBitsShift+h.shift))
+}
+
+// heapBitsBulkBarrier executes writebarrierptr_nostore
+// for every pointer slot in the memory range [p, p+size),
+// using the heap bitmap to locate those pointer slots.
+// This executes the write barriers necessary after a memmove.
+// Both p and size must be pointer-aligned.
+// The range [p, p+size) must lie within a single allocation.
+//
+// Callers should call heapBitsBulkBarrier immediately after
+// calling memmove(p, src, size). This function is marked nosplit
+// to avoid being preempted; the GC must not stop the goroutine
+// between the memmove and the execution of the barriers.
+//
+// The heap bitmap is not maintained for allocations containing
+// no pointers at all; any caller of heapBitsBulkBarrier must first
+// make sure the underlying allocation contains pointers, usually
+// by checking typ.kind&kindNoPointers.
+//
+//go:nosplit
+func heapBitsBulkBarrier(p, size uintptr) {
+	if (p|size)&(ptrSize-1) != 0 {
+		throw("heapBitsBulkBarrier: unaligned arguments")
+	}
+	if !writeBarrierEnabled {
+		return
+	}
+	if !inheap(p) {
+		// If p is on the stack and in a higher frame than the
+		// caller, we either need to execute write barriers on
+		// it (which is what happens for normal stack writes
+		// through pointers to higher frames), or we need to
+		// force the mark termination stack scan to scan the
+		// frame containing p.
+		//
+		// Executing write barriers on p is complicated in the
+		// general case because we either need to unwind the
+		// stack to get the stack map, or we need the type's
+		// bitmap, which may be a GC program.
+		//
+		// Hence, we opt for forcing the re-scan to scan the
+		// frame containing p, which we can do by simply
+		// unwinding the stack barriers between the current SP
+		// and p's frame.
+		gp := getg().m.curg
+		if gp != nil && gp.stack.lo <= p && p < gp.stack.hi {
+			// Run on the system stack to give it more
+			// stack space.
+			systemstack(func() {
+				gcUnwindBarriers(gp, p)
+			})
+		}
+		return
+	}
+
+	h := heapBitsForAddr(p)
+	for i := uintptr(0); i < size; i += ptrSize {
+		if h.isPointer() {
+			x := (*uintptr)(unsafe.Pointer(p + i))
+			writebarrierptr_nostore(x, *x)
+		}
+		h = h.next()
+	}
+}
+
+// typeBitsBulkBarrier executes writebarrierptr_nostore
+// for every pointer slot in the memory range [p, p+size),
+// using the type bitmap to locate those pointer slots.
+// The type typ must correspond exactly to [p, p+size).
+// This executes the write barriers necessary after a copy.
+// Both p and size must be pointer-aligned.
+// The type typ must have a plain bitmap, not a GC program.
+// The only use of this function is in channel sends, and the
+// 64 kB channel element limit takes care of this for us.
+//
+// Must not be preempted because it typically runs right after memmove,
+// and the GC must not complete between those two.
+//
+//go:nosplit
+func typeBitsBulkBarrier(typ *_type, p, size uintptr) {
+	if typ == nil {
+		throw("runtime: typeBitsBulkBarrier without type")
+	}
+	if typ.size != size {
+		println("runtime: typeBitsBulkBarrier with type ", *typ._string, " of size ", typ.size, " but memory size", size)
+		throw("runtime: invalid typeBitsBulkBarrier")
+	}
+	if typ.kind&kindGCProg != 0 {
+		println("runtime: typeBitsBulkBarrier with type ", *typ._string, " with GC prog")
+		throw("runtime: invalid typeBitsBulkBarrier")
+	}
+	if !writeBarrierEnabled {
+		return
+	}
+	ptrmask := typ.gcdata
+	var bits uint32
+	for i := uintptr(0); i < typ.ptrdata; i += ptrSize {
+		if i&(ptrSize*8-1) == 0 {
+			bits = uint32(*ptrmask)
+			ptrmask = addb(ptrmask, 1)
+		} else {
+			bits = bits >> 1
+		}
+		if bits&1 != 0 {
+			x := (*uintptr)(unsafe.Pointer(p + i))
+			writebarrierptr_nostore(x, *x)
+		}
+	}
+}
+
+// The methods operating on spans all require that h has been returned
+// by heapBitsForSpan and that size, n, total are the span layout description
+// returned by the mspan's layout method.
+// If total > size*n, it means that there is extra leftover memory in the span,
+// usually due to rounding.
+//
+// TODO(rsc): Perhaps introduce a different heapBitsSpan type.
+
+// initSpan initializes the heap bitmap for a span.
+func (h heapBits) initSpan(size, n, total uintptr) {
+	if total%heapBitmapScale != 0 {
+		throw("initSpan: unaligned length")
+	}
+	nbyte := total / heapBitmapScale
+	if ptrSize == 8 && size == ptrSize {
+		end := h.bitp
+		bitp := subtractb(end, nbyte-1)
+		for {
+			*bitp = bitPointerAll
+			if bitp == end {
+				break
+			}
+			bitp = add1(bitp)
+		}
+		return
+	}
+	memclr(unsafe.Pointer(subtractb(h.bitp, nbyte-1)), nbyte)
+}
+
+// initCheckmarkSpan initializes a span for being checkmarked.
+// It clears the checkmark bits, which are set to 1 in normal operation.
+func (h heapBits) initCheckmarkSpan(size, n, total uintptr) {
+	// The ptrSize == 8 is a compile-time constant false on 32-bit and eliminates this code entirely.
+	if ptrSize == 8 && size == ptrSize {
+		// Checkmark bit is type bit, bottom bit of every 2-bit entry.
+		// Only possible on 64-bit system, since minimum size is 8.
+		// Must clear type bit (checkmark bit) of every word.
+		// The type bit is the lower of every two-bit pair.
+		bitp := h.bitp
+		for i := uintptr(0); i < n; i += 4 {
+			*bitp &^= bitPointerAll
+			bitp = subtract1(bitp)
+		}
+		return
+	}
+	for i := uintptr(0); i < n; i++ {
+		*h.bitp &^= bitMarked << (heapBitsShift + h.shift)
+		h = h.forward(size / ptrSize)
+	}
+}
+
+// clearCheckmarkSpan undoes all the checkmarking in a span.
+// The actual checkmark bits are ignored, so the only work to do
+// is to fix the pointer bits. (Pointer bits are ignored by scanobject
+// but consulted by typedmemmove.)
+func (h heapBits) clearCheckmarkSpan(size, n, total uintptr) {
+	// The ptrSize == 8 is a compile-time constant false on 32-bit and eliminates this code entirely.
+	if ptrSize == 8 && size == ptrSize {
+		// Checkmark bit is type bit, bottom bit of every 2-bit entry.
+		// Only possible on 64-bit system, since minimum size is 8.
+		// Must clear type bit (checkmark bit) of every word.
+		// The type bit is the lower of every two-bit pair.
+		bitp := h.bitp
+		for i := uintptr(0); i < n; i += 4 {
+			*bitp |= bitPointerAll
+			bitp = subtract1(bitp)
+		}
+	}
+}
+
+// heapBitsSweepSpan coordinates the sweeping of a span by reading
+// and updating the corresponding heap bitmap entries.
+// For each free object in the span, heapBitsSweepSpan sets the type
+// bits for the first two words (or one for single-word objects) to typeDead
+// and then calls f(p), where p is the object's base address.
+// f is expected to add the object to a free list.
+// For non-free objects, heapBitsSweepSpan turns off the marked bit.
+func heapBitsSweepSpan(base, size, n uintptr, f func(uintptr)) {
+	h := heapBitsForSpan(base)
+	switch {
+	default:
+		throw("heapBitsSweepSpan")
+	case ptrSize == 8 && size == ptrSize:
+		// Consider mark bits in all four 2-bit entries of each bitmap byte.
+		bitp := h.bitp
+		for i := uintptr(0); i < n; i += 4 {
+			x := uint32(*bitp)
+			// Note that unlike the other size cases, we leave the pointer bits set here.
+			// These are initialized during initSpan when the span is created and left
+			// in place the whole time the span is used for pointer-sized objects.
+			// That lets heapBitsSetType avoid an atomic update to set the pointer bit
+			// during allocation.
+			if x&bitMarked != 0 {
+				x &^= bitMarked
+			} else {
+				f(base + i*ptrSize)
+			}
+			if x&(bitMarked<<heapBitsShift) != 0 {
+				x &^= bitMarked << heapBitsShift
+			} else {
+				f(base + (i+1)*ptrSize)
+			}
+			if x&(bitMarked<<(2*heapBitsShift)) != 0 {
+				x &^= bitMarked << (2 * heapBitsShift)
+			} else {
+				f(base + (i+2)*ptrSize)
+			}
+			if x&(bitMarked<<(3*heapBitsShift)) != 0 {
+				x &^= bitMarked << (3 * heapBitsShift)
+			} else {
+				f(base + (i+3)*ptrSize)
+			}
+			*bitp = uint8(x)
+			bitp = subtract1(bitp)
+		}
+
+	case size%(4*ptrSize) == 0:
+		// Mark bit is in first word of each object.
+		// Each object starts at bit 0 of a heap bitmap byte.
+		bitp := h.bitp
+		step := size / heapBitmapScale
+		for i := uintptr(0); i < n; i++ {
+			x := uint32(*bitp)
+			if x&bitMarked != 0 {
+				x &^= bitMarked
+			} else {
+				x = 0
+				f(base + i*size)
+			}
+			*bitp = uint8(x)
+			bitp = subtractb(bitp, step)
+		}
+
+	case size%(4*ptrSize) == 2*ptrSize:
+		// Mark bit is in first word of each object,
+		// but every other object starts halfway through a heap bitmap byte.
+		// Unroll loop 2x to handle alternating shift count and step size.
+		bitp := h.bitp
+		step := size / heapBitmapScale
+		var i uintptr
+		for i = uintptr(0); i < n; i += 2 {
+			x := uint32(*bitp)
+			if x&bitMarked != 0 {
+				x &^= bitMarked
+			} else {
+				x &^= bitMarked | bitPointer | (bitMarked|bitPointer)<<heapBitsShift
+				f(base + i*size)
+				if size > 2*ptrSize {
+					x = 0
+				}
+			}
+			*bitp = uint8(x)
+			if i+1 >= n {
+				break
+			}
+			bitp = subtractb(bitp, step)
+			x = uint32(*bitp)
+			if x&(bitMarked<<(2*heapBitsShift)) != 0 {
+				x &^= bitMarked << (2 * heapBitsShift)
+			} else {
+				x &^= (bitMarked|bitPointer)<<(2*heapBitsShift) | (bitMarked|bitPointer)<<(3*heapBitsShift)
+				f(base + (i+1)*size)
+				if size > 2*ptrSize {
+					*subtract1(bitp) = 0
+				}
+			}
+			*bitp = uint8(x)
+			bitp = subtractb(bitp, step+1)
+		}
+	}
+}
+
+// heapBitsSetType records that the new allocation [x, x+size)
+// holds in [x, x+dataSize) one or more values of type typ.
+// (The number of values is given by dataSize / typ.size.)
+// If dataSize < size, the fragment [x+dataSize, x+size) is
+// recorded as non-pointer data.
+// It is known that the type has pointers somewhere;
+// malloc does not call heapBitsSetType when there are no pointers,
+// because all free objects are marked as noscan during
+// heapBitsSweepSpan.
+// There can only be one allocation from a given span active at a time,
+// so this code is not racing with other instances of itself,
+// and we don't allocate from a span until it has been swept,
+// so this code is not racing with heapBitsSweepSpan.
+// It is, however, racing with the concurrent GC mark phase,
+// which can be setting the mark bit in the leading 2-bit entry
+// of an allocated block. The block we are modifying is not quite
+// allocated yet, so the GC marker is not racing with updates to x's bits,
+// but if the start or end of x shares a bitmap byte with an adjacent
+// object, the GC marker is racing with updates to those object's mark bits.
+func heapBitsSetType(x, size, dataSize uintptr, typ *_type) {
+	const doubleCheck = false // slow but helpful; enable to test modifications to this code
+
+	// dataSize is always size rounded up to the next malloc size class,
+	// except in the case of allocating a defer block, in which case
+	// size is sizeof(_defer{}) (at least 6 words) and dataSize may be
+	// arbitrarily larger.
+	//
+	// The checks for size == ptrSize and size == 2*ptrSize can therefore
+	// assume that dataSize == size without checking it explicitly.
+
+	if ptrSize == 8 && size == ptrSize {
+		// It's one word and it has pointers, it must be a pointer.
+		// In general we'd need an atomic update here if the
+		// concurrent GC were marking objects in this span,
+		// because each bitmap byte describes 3 other objects
+		// in addition to the one being allocated.
+		// However, since all allocated one-word objects are pointers
+		// (non-pointers are aggregated into tinySize allocations),
+		// initSpan sets the pointer bits for us. Nothing to do here.
+		if doubleCheck {
+			h := heapBitsForAddr(x)
+			if !h.isPointer() {
+				throw("heapBitsSetType: pointer bit missing")
+			}
+		}
+		return
+	}
+
+	h := heapBitsForAddr(x)
+	ptrmask := typ.gcdata // start of 1-bit pointer mask (or GC program, handled below)
+
+	// Heap bitmap bits for 2-word object are only 4 bits,
+	// so also shared with objects next to it; use atomic updates.
+	// This is called out as a special case primarily for 32-bit systems,
+	// so that on 32-bit systems the code below can assume all objects
+	// are 4-word aligned (because they're all 16-byte aligned).
+	if size == 2*ptrSize {
+		if typ.size == ptrSize {
+			// We're allocating a block big enough to hold two pointers.
+			// On 64-bit, that means the actual object must be two pointers,
+			// or else we'd have used the one-pointer-sized block.
+			// On 32-bit, however, this is the 8-byte block, the smallest one.
+			// So it could be that we're allocating one pointer and this was
+			// just the smallest block available. Distinguish by checking dataSize.
+			// (In general the number of instances of typ being allocated is
+			// dataSize/typ.size.)
+			if ptrSize == 4 && dataSize == ptrSize {
+				// 1 pointer.
+				if gcphase == _GCoff {
+					*h.bitp |= bitPointer << h.shift
+				} else {
+					atomicor8(h.bitp, bitPointer<<h.shift)
+				}
+			} else {
+				// 2-element slice of pointer.
+				if gcphase == _GCoff {
+					*h.bitp |= (bitPointer | bitPointer<<heapBitsShift) << h.shift
+				} else {
+					atomicor8(h.bitp, (bitPointer|bitPointer<<heapBitsShift)<<h.shift)
+				}
+			}
+			return
+		}
+		// Otherwise typ.size must be 2*ptrSize, and typ.kind&kindGCProg == 0.
+		if doubleCheck {
+			if typ.size != 2*ptrSize || typ.kind&kindGCProg != 0 {
+				print("runtime: heapBitsSetType size=", size, " but typ.size=", typ.size, " gcprog=", typ.kind&kindGCProg != 0, "\n")
+				throw("heapBitsSetType")
+			}
+		}
+		b := uint32(*ptrmask)
+		hb := b & 3
+		if gcphase == _GCoff {
+			*h.bitp |= uint8(hb << h.shift)
+		} else {
+			atomicor8(h.bitp, uint8(hb<<h.shift))
+		}
+		return
+	}
+
+	// Copy from 1-bit ptrmask into 2-bit bitmap.
+	// The basic approach is to use a single uintptr as a bit buffer,
+	// alternating between reloading the buffer and writing bitmap bytes.
+	// In general, one load can supply two bitmap byte writes.
+	// This is a lot of lines of code, but it compiles into relatively few
+	// machine instructions.
+
+	var (
+		// Ptrmask input.
+		p     *byte   // last ptrmask byte read
+		b     uintptr // ptrmask bits already loaded
+		nb    uintptr // number of bits in b at next read
+		endp  *byte   // final ptrmask byte to read (then repeat)
+		endnb uintptr // number of valid bits in *endp
+		pbits uintptr // alternate source of bits
+
+		// Heap bitmap output.
+		w     uintptr // words processed
+		nw    uintptr // number of words to process
+		hbitp *byte   // next heap bitmap byte to write
+		hb    uintptr // bits being prepared for *hbitp
+	)
+
+	hbitp = h.bitp
+
+	// Handle GC program. Delayed until this part of the code
+	// so that we can use the same double-checking mechanism
+	// as the 1-bit case. Nothing above could have encountered
+	// GC programs: the cases were all too small.
+	if typ.kind&kindGCProg != 0 {
+		heapBitsSetTypeGCProg(h, typ.ptrdata, typ.size, dataSize, size, addb(typ.gcdata, 4))
+		if doubleCheck {
+			// Double-check the heap bits written by GC program
+			// by running the GC program to create a 1-bit pointer mask
+			// and then jumping to the double-check code below.
+			// This doesn't catch bugs shared between the 1-bit and 4-bit
+			// GC program execution, but it does catch mistakes specific
+			// to just one of those and bugs in heapBitsSetTypeGCProg's
+			// implementation of arrays.
+			lock(&debugPtrmask.lock)
+			if debugPtrmask.data == nil {
+				debugPtrmask.data = (*byte)(persistentalloc(1<<20, 1, &memstats.other_sys))
+			}
+			ptrmask = debugPtrmask.data
+			runGCProg(addb(typ.gcdata, 4), nil, ptrmask, 1)
+			goto Phase4
+		}
+		return
+	}
+
+	// Note about sizes:
+	//
+	// typ.size is the number of words in the object,
+	// and typ.ptrdata is the number of words in the prefix
+	// of the object that contains pointers. That is, the final
+	// typ.size - typ.ptrdata words contain no pointers.
+	// This allows optimization of a common pattern where
+	// an object has a small header followed by a large scalar
+	// buffer. If we know the pointers are over, we don't have
+	// to scan the buffer's heap bitmap at all.
+	// The 1-bit ptrmasks are sized to contain only bits for
+	// the typ.ptrdata prefix, zero padded out to a full byte
+	// of bitmap. This code sets nw (below) so that heap bitmap
+	// bits are only written for the typ.ptrdata prefix; if there is
+	// more room in the allocated object, the next heap bitmap
+	// entry is a 00, indicating that there are no more pointers
+	// to scan. So only the ptrmask for the ptrdata bytes is needed.
+	//
+	// Replicated copies are not as nice: if there is an array of
+	// objects with scalar tails, all but the last tail does have to
+	// be initialized, because there is no way to say "skip forward".
+	// However, because of the possibility of a repeated type with
+	// size not a multiple of 4 pointers (one heap bitmap byte),
+	// the code already must handle the last ptrmask byte specially
+	// by treating it as containing only the bits for endnb pointers,
+	// where endnb <= 4. We represent large scalar tails that must
+	// be expanded in the replication by setting endnb larger than 4.
+	// This will have the effect of reading many bits out of b,
+	// but once the real bits are shifted out, b will supply as many
+	// zero bits as we try to read, which is exactly what we need.
+
+	p = ptrmask
+	if typ.size < dataSize {
+		// Filling in bits for an array of typ.
+		// Set up for repetition of ptrmask during main loop.
+		// Note that ptrmask describes only a prefix of
+		const maxBits = ptrSize*8 - 7
+		if typ.ptrdata/ptrSize <= maxBits {
+			// Entire ptrmask fits in uintptr with room for a byte fragment.
+			// Load into pbits and never read from ptrmask again.
+			// This is especially important when the ptrmask has
+			// fewer than 8 bits in it; otherwise the reload in the middle
+			// of the Phase 2 loop would itself need to loop to gather
+			// at least 8 bits.
+
+			// Accumulate ptrmask into b.
+			// ptrmask is sized to describe only typ.ptrdata, but we record
+			// it as describing typ.size bytes, since all the high bits are zero.
+			nb = typ.ptrdata / ptrSize
+			for i := uintptr(0); i < nb; i += 8 {
+				b |= uintptr(*p) << i
+				p = add1(p)
+			}
+			nb = typ.size / ptrSize
+
+			// Replicate ptrmask to fill entire pbits uintptr.
+			// Doubling and truncating is fewer steps than
+			// iterating by nb each time. (nb could be 1.)
+			// Since we loaded typ.ptrdata/ptrSize bits
+			// but are pretending to have typ.size/ptrSize,
+			// there might be no replication necessary/possible.
+			pbits = b
+			endnb = nb
+			if nb+nb <= maxBits {
+				for endnb <= ptrSize*8 {
+					pbits |= pbits << endnb
+					endnb += endnb
+				}
+				// Truncate to a multiple of original ptrmask.
+				endnb = maxBits / nb * nb
+				pbits &= 1<<endnb - 1
+				b = pbits
+				nb = endnb
+			}
+
+			// Clear p and endp as sentinel for using pbits.
+			// Checked during Phase 2 loop.
+			p = nil
+			endp = nil
+		} else {
+			// Ptrmask is larger. Read it multiple times.
+			n := (typ.ptrdata/ptrSize+7)/8 - 1
+			endp = addb(ptrmask, n)
+			endnb = typ.size/ptrSize - n*8
+		}
+	}
+	if p != nil {
+		b = uintptr(*p)
+		p = add1(p)
+		nb = 8
+	}
+
+	if typ.size == dataSize {
+		// Single entry: can stop once we reach the non-pointer data.
+		nw = typ.ptrdata / ptrSize
+	} else {
+		// Repeated instances of typ in an array.
+		// Have to process first N-1 entries in full, but can stop
+		// once we reach the non-pointer data in the final entry.
+		nw = ((dataSize/typ.size-1)*typ.size + typ.ptrdata) / ptrSize
+	}
+	if nw == 0 {
+		// No pointers! Caller was supposed to check.
+		println("runtime: invalid type ", *typ._string)
+		throw("heapBitsSetType: called with non-pointer type")
+		return
+	}
+	if nw < 2 {
+		// Must write at least 2 words, because the "no scan"
+		// encoding doesn't take effect until the third word.
+		nw = 2
+	}
+
+	// Phase 1: Special case for leading byte (shift==0) or half-byte (shift==4).
+	// The leading byte is special because it contains the bits for words 0 and 1,
+	// which do not have the marked bits set.
+	// The leading half-byte is special because it's a half a byte and must be
+	// manipulated atomically.
+	switch {
+	default:
+		throw("heapBitsSetType: unexpected shift")
+
+	case h.shift == 0:
+		// Ptrmask and heap bitmap are aligned.
+		// Handle first byte of bitmap specially.
+		// The first byte we write out contains the first two words of the object.
+		// In those words, the mark bits are mark and checkmark, respectively,
+		// and must not be set. In all following words, we want to set the mark bit
+		// as a signal that the object continues to the next 2-bit entry in the bitmap.
+		hb = b & bitPointerAll
+		hb |= bitMarked<<(2*heapBitsShift) | bitMarked<<(3*heapBitsShift)
+		if w += 4; w >= nw {
+			goto Phase3
+		}
+		*hbitp = uint8(hb)
+		hbitp = subtract1(hbitp)
+		b >>= 4
+		nb -= 4
+
+	case ptrSize == 8 && h.shift == 2:
+		// Ptrmask and heap bitmap are misaligned.
+		// The bits for the first two words are in a byte shared with another object
+		// and must be updated atomically.
+		// NOTE(rsc): The atomic here may not be necessary.
+		// We took care of 1-word and 2-word objects above,
+		// so this is at least a 6-word object, so our start bits
+		// are shared only with the type bits of another object,
+		// not with its mark bit. Since there is only one allocation
+		// from a given span at a time, we should be able to set
+		// these bits non-atomically. Not worth the risk right now.
+		hb = (b & 3) << (2 * heapBitsShift)
+		b >>= 2
+		nb -= 2
+		// Note: no bitMarker in hb because the first two words don't get markers from us.
+		if gcphase == _GCoff {
+			*hbitp |= uint8(hb)
+		} else {
+			atomicor8(hbitp, uint8(hb))
+		}
+		hbitp = subtract1(hbitp)
+		if w += 2; w >= nw {
+			// We know that there is more data, because we handled 2-word objects above.
+			// This must be at least a 6-word object. If we're out of pointer words,
+			// mark no scan in next bitmap byte and finish.
+			hb = 0
+			w += 4
+			goto Phase3
+		}
+	}
+
+	// Phase 2: Full bytes in bitmap, up to but not including write to last byte (full or partial) in bitmap.
+	// The loop computes the bits for that last write but does not execute the write;
+	// it leaves the bits in hb for processing by phase 3.
+	// To avoid repeated adjustment of nb, we subtract out the 4 bits we're going to
+	// use in the first half of the loop right now, and then we only adjust nb explicitly
+	// if the 8 bits used by each iteration isn't balanced by 8 bits loaded mid-loop.
+	nb -= 4
+	for {
+		// Emit bitmap byte.
+		// b has at least nb+4 bits, with one exception:
+		// if w+4 >= nw, then b has only nw-w bits,
+		// but we'll stop at the break and then truncate
+		// appropriately in Phase 3.
+		hb = b & bitPointerAll
+		hb |= bitMarkedAll
+		if w += 4; w >= nw {
+			break
+		}
+		*hbitp = uint8(hb)
+		hbitp = subtract1(hbitp)
+		b >>= 4
+
+		// Load more bits. b has nb right now.
+		if p != endp {
+			// Fast path: keep reading from ptrmask.
+			// nb unmodified: we just loaded 8 bits,
+			// and the next iteration will consume 8 bits,
+			// leaving us with the same nb the next time we're here.
+			if nb < 8 {
+				b |= uintptr(*p) << nb
+				p = add1(p)
+			} else {
+				// Reduce the number of bits in b.
+				// This is important if we skipped
+				// over a scalar tail, since nb could
+				// be larger than the bit width of b.
+				nb -= 8
+			}
+		} else if p == nil {
+			// Almost as fast path: track bit count and refill from pbits.
+			// For short repetitions.
+			if nb < 8 {
+				b |= pbits << nb
+				nb += endnb
+			}
+			nb -= 8 // for next iteration
+		} else {
+			// Slow path: reached end of ptrmask.
+			// Process final partial byte and rewind to start.
+			b |= uintptr(*p) << nb
+			nb += endnb
+			if nb < 8 {
+				b |= uintptr(*ptrmask) << nb
+				p = add1(ptrmask)
+			} else {
+				nb -= 8
+				p = ptrmask
+			}
+		}
+
+		// Emit bitmap byte.
+		hb = b & bitPointerAll
+		hb |= bitMarkedAll
+		if w += 4; w >= nw {
+			break
+		}
+		*hbitp = uint8(hb)
+		hbitp = subtract1(hbitp)
+		b >>= 4
+	}
+
+Phase3:
+	// Phase 3: Write last byte or partial byte and zero the rest of the bitmap entries.
+	if w > nw {
+		// Counting the 4 entries in hb not yet written to memory,
+		// there are more entries than possible pointer slots.
+		// Discard the excess entries (can't be more than 3).
+		mask := uintptr(1)<<(4-(w-nw)) - 1
+		hb &= mask | mask<<4 // apply mask to both pointer bits and mark bits
+	}
+
+	// Change nw from counting possibly-pointer words to total words in allocation.
+	nw = size / ptrSize
+
+	// Write whole bitmap bytes.
+	// The first is hb, the rest are zero.
+	if w <= nw {
+		*hbitp = uint8(hb)
+		hbitp = subtract1(hbitp)
+		hb = 0 // for possible final half-byte below
+		for w += 4; w <= nw; w += 4 {
+			*hbitp = 0
+			hbitp = subtract1(hbitp)
+		}
+	}
+
+	// Write final partial bitmap byte if any.
+	// We know w > nw, or else we'd still be in the loop above.
+	// It can be bigger only due to the 4 entries in hb that it counts.
+	// If w == nw+4 then there's nothing left to do: we wrote all nw entries
+	// and can discard the 4 sitting in hb.
+	// But if w == nw+2, we need to write first two in hb.
+	// The byte is shared with the next object so we may need an atomic.
+	if w == nw+2 {
+		if gcphase == _GCoff {
+			*hbitp = *hbitp&^(bitPointer|bitMarked|(bitPointer|bitMarked)<<heapBitsShift) | uint8(hb)
+		} else {
+			atomicand8(hbitp, ^uint8(bitPointer|bitMarked|(bitPointer|bitMarked)<<heapBitsShift))
+			atomicor8(hbitp, uint8(hb))
+		}
+	}
+
+Phase4:
+	// Phase 4: all done, but perhaps double check.
+	if doubleCheck {
+		end := heapBitsForAddr(x + size)
+		if typ.kind&kindGCProg == 0 && (hbitp != end.bitp || (w == nw+2) != (end.shift == 2)) {
+			println("ended at wrong bitmap byte for", *typ._string, "x", dataSize/typ.size)
+			print("typ.size=", typ.size, " typ.ptrdata=", typ.ptrdata, " dataSize=", dataSize, " size=", size, "\n")
+			print("w=", w, " nw=", nw, " b=", hex(b), " nb=", nb, " hb=", hex(hb), "\n")
+			h0 := heapBitsForAddr(x)
+			print("initial bits h0.bitp=", h0.bitp, " h0.shift=", h0.shift, "\n")
+			print("ended at hbitp=", hbitp, " but next starts at bitp=", end.bitp, " shift=", end.shift, "\n")
+			throw("bad heapBitsSetType")
+		}
+
+		// Double-check that bits to be written were written correctly.
+		// Does not check that other bits were not written, unfortunately.
+		h := heapBitsForAddr(x)
+		nptr := typ.ptrdata / ptrSize
+		ndata := typ.size / ptrSize
+		count := dataSize / typ.size
+		totalptr := ((count-1)*typ.size + typ.ptrdata) / ptrSize
+		for i := uintptr(0); i < size/ptrSize; i++ {
+			j := i % ndata
+			var have, want uint8
+			have = (*h.bitp >> h.shift) & (bitPointer | bitMarked)
+			if i >= totalptr {
+				want = 0 // deadmarker
+				if typ.kind&kindGCProg != 0 && i < (totalptr+3)/4*4 {
+					want = bitMarked
+				}
+			} else {
+				if j < nptr && (*addb(ptrmask, j/8)>>(j%8))&1 != 0 {
+					want |= bitPointer
+				}
+				if i >= 2 {
+					want |= bitMarked
+				} else {
+					have &^= bitMarked
+				}
+			}
+			if have != want {
+				println("mismatch writing bits for", *typ._string, "x", dataSize/typ.size)
+				print("typ.size=", typ.size, " typ.ptrdata=", typ.ptrdata, " dataSize=", dataSize, " size=", size, "\n")
+				print("kindGCProg=", typ.kind&kindGCProg != 0, "\n")
+				print("w=", w, " nw=", nw, " b=", hex(b), " nb=", nb, " hb=", hex(hb), "\n")
+				h0 := heapBitsForAddr(x)
+				print("initial bits h0.bitp=", h0.bitp, " h0.shift=", h0.shift, "\n")
+				print("current bits h.bitp=", h.bitp, " h.shift=", h.shift, " *h.bitp=", hex(*h.bitp), "\n")
+				print("ptrmask=", ptrmask, " p=", p, " endp=", endp, " endnb=", endnb, " pbits=", hex(pbits), " b=", hex(b), " nb=", nb, "\n")
+				println("at word", i, "offset", i*ptrSize, "have", have, "want", want)
+				if typ.kind&kindGCProg != 0 {
+					println("GC program:")
+					dumpGCProg(addb(typ.gcdata, 4))
+				}
+				throw("bad heapBitsSetType")
+			}
+			h = h.next()
+		}
+		if ptrmask == debugPtrmask.data {
+			unlock(&debugPtrmask.lock)
+		}
+	}
+}
+
+var debugPtrmask struct {
+	lock mutex
+	data *byte
+}
+
+// heapBitsSetTypeGCProg implements heapBitsSetType using a GC program.
+// progSize is the size of the memory described by the program.
+// elemSize is the size of the element that the GC program describes (a prefix of).
+// dataSize is the total size of the intended data, a multiple of elemSize.
+// allocSize is the total size of the allocated memory.
+//
+// GC programs are only used for large allocations.
+// heapBitsSetType requires that allocSize is a multiple of 4 words,
+// so that the relevant bitmap bytes are not shared with surrounding
+// objects and need not be accessed with atomic instructions.
+func heapBitsSetTypeGCProg(h heapBits, progSize, elemSize, dataSize, allocSize uintptr, prog *byte) {
+	if ptrSize == 8 && allocSize%(4*ptrSize) != 0 {
+		// Alignment will be wrong.
+		throw("heapBitsSetTypeGCProg: small allocation")
+	}
+	var totalBits uintptr
+	if elemSize == dataSize {
+		totalBits = runGCProg(prog, nil, h.bitp, 2)
+		if totalBits*ptrSize != progSize {
+			println("runtime: heapBitsSetTypeGCProg: total bits", totalBits, "but progSize", progSize)
+			throw("heapBitsSetTypeGCProg: unexpected bit count")
+		}
+	} else {
+		count := dataSize / elemSize
+
+		// Piece together program trailer to run after prog that does:
+		//	literal(0)
+		//	repeat(1, elemSize-progSize-1) // zeros to fill element size
+		//	repeat(elemSize, count-1) // repeat that element for count
+		// This zero-pads the data remaining in the first element and then
+		// repeats that first element to fill the array.
+		var trailer [40]byte // 3 varints (max 10 each) + some bytes
+		i := 0
+		if n := elemSize/ptrSize - progSize/ptrSize; n > 0 {
+			// literal(0)
+			trailer[i] = 0x01
+			i++
+			trailer[i] = 0
+			i++
+			if n > 1 {
+				// repeat(1, n-1)
+				trailer[i] = 0x81
+				i++
+				n--
+				for ; n >= 0x80; n >>= 7 {
+					trailer[i] = byte(n | 0x80)
+					i++
+				}
+				trailer[i] = byte(n)
+				i++
+			}
+		}
+		// repeat(elemSize/ptrSize, count-1)
+		trailer[i] = 0x80
+		i++
+		n := elemSize / ptrSize
+		for ; n >= 0x80; n >>= 7 {
+			trailer[i] = byte(n | 0x80)
+			i++
+		}
+		trailer[i] = byte(n)
+		i++
+		n = count - 1
+		for ; n >= 0x80; n >>= 7 {
+			trailer[i] = byte(n | 0x80)
+			i++
+		}
+		trailer[i] = byte(n)
+		i++
+		trailer[i] = 0
+		i++
+
+		runGCProg(prog, &trailer[0], h.bitp, 2)
+
+		// Even though we filled in the full array just now,
+		// record that we only filled in up to the ptrdata of the
+		// last element. This will cause the code below to
+		// memclr the dead section of the final array element,
+		// so that scanobject can stop early in the final element.
+		totalBits = (elemSize*(count-1) + progSize) / ptrSize
+	}
+	endProg := unsafe.Pointer(subtractb(h.bitp, (totalBits+3)/4))
+	endAlloc := unsafe.Pointer(subtractb(h.bitp, allocSize/heapBitmapScale))
+	memclr(add(endAlloc, 1), uintptr(endProg)-uintptr(endAlloc))
+}
+
+// progToPointerMask returns the 1-bit pointer mask output by the GC program prog.
+// size the size of the region described by prog, in bytes.
+// The resulting bitvector will have no more than size/ptrSize bits.
+func progToPointerMask(prog *byte, size uintptr) bitvector {
+	n := (size/ptrSize + 7) / 8
+	x := (*[1 << 30]byte)(persistentalloc(n+1, 1, &memstats.buckhash_sys))[:n+1]
+	x[len(x)-1] = 0xa1 // overflow check sentinel
+	n = runGCProg(prog, nil, &x[0], 1)
+	if x[len(x)-1] != 0xa1 {
+		throw("progToPointerMask: overflow")
+	}
+	return bitvector{int32(n), &x[0]}
+}
+
+// Packed GC pointer bitmaps, aka GC programs.
+//
+// For large types containing arrays, the type information has a
+// natural repetition that can be encoded to save space in the
+// binary and in the memory representation of the type information.
+//
+// The encoding is a simple Lempel-Ziv style bytecode machine
+// with the following instructions:
+//
+//	00000000: stop
+//	0nnnnnnn: emit n bits copied from the next (n+7)/8 bytes
+//	10000000 n c: repeat the previous n bits c times; n, c are varints
+//	1nnnnnnn c: repeat the previous n bits c times; c is a varint
+
+// runGCProg executes the GC program prog, and then trailer if non-nil,
+// writing to dst with entries of the given size.
+// If size == 1, dst is a 1-bit pointer mask laid out moving forward from dst.
+// If size == 2, dst is the 2-bit heap bitmap, and writes move backward
+// starting at dst (because the heap bitmap does). In this case, the caller guarantees
+// that only whole bytes in dst need to be written.
+//
+// runGCProg returns the number of 1- or 2-bit entries written to memory.
+func runGCProg(prog, trailer, dst *byte, size int) uintptr {
+	dstStart := dst
+
+	// Bits waiting to be written to memory.
+	var bits uintptr
+	var nbits uintptr
+
+	p := prog
+Run:
+	for {
+		// Flush accumulated full bytes.
+		// The rest of the loop assumes that nbits <= 7.
+		for ; nbits >= 8; nbits -= 8 {
+			if size == 1 {
+				*dst = uint8(bits)
+				dst = add1(dst)
+				bits >>= 8
+			} else {
+				v := bits&bitPointerAll | bitMarkedAll
+				*dst = uint8(v)
+				dst = subtract1(dst)
+				bits >>= 4
+				v = bits&bitPointerAll | bitMarkedAll
+				*dst = uint8(v)
+				dst = subtract1(dst)
+				bits >>= 4
+			}
+		}
+
+		// Process one instruction.
+		inst := uintptr(*p)
+		p = add1(p)
+		n := inst & 0x7F
+		if inst&0x80 == 0 {
+			// Literal bits; n == 0 means end of program.
+			if n == 0 {
+				// Program is over; continue in trailer if present.
+				if trailer != nil {
+					//println("trailer")
+					p = trailer
+					trailer = nil
+					continue
+				}
+				//println("done")
+				break Run
+			}
+			//println("lit", n, dst)
+			nbyte := n / 8
+			for i := uintptr(0); i < nbyte; i++ {
+				bits |= uintptr(*p) << nbits
+				p = add1(p)
+				if size == 1 {
+					*dst = uint8(bits)
+					dst = add1(dst)
+					bits >>= 8
+				} else {
+					v := bits&0xf | bitMarkedAll
+					*dst = uint8(v)
+					dst = subtract1(dst)
+					bits >>= 4
+					v = bits&0xf | bitMarkedAll
+					*dst = uint8(v)
+					dst = subtract1(dst)
+					bits >>= 4
+				}
+			}
+			if n %= 8; n > 0 {
+				bits |= uintptr(*p) << nbits
+				p = add1(p)
+				nbits += n
+			}
+			continue Run
+		}
+
+		// Repeat. If n == 0, it is encoded in a varint in the next bytes.
+		if n == 0 {
+			for off := uint(0); ; off += 7 {
+				x := uintptr(*p)
+				p = add1(p)
+				n |= (x & 0x7F) << off
+				if x&0x80 == 0 {
+					break
+				}
+			}
+		}
+
+		// Count is encoded in a varint in the next bytes.
+		c := uintptr(0)
+		for off := uint(0); ; off += 7 {
+			x := uintptr(*p)
+			p = add1(p)
+			c |= (x & 0x7F) << off
+			if x&0x80 == 0 {
+				break
+			}
+		}
+		c *= n // now total number of bits to copy
+
+		// If the number of bits being repeated is small, load them
+		// into a register and use that register for the entire loop
+		// instead of repeatedly reading from memory.
+		// Handling fewer than 8 bits here makes the general loop simpler.
+		// The cutoff is ptrSize*8 - 7 to guarantee that when we add
+		// the pattern to a bit buffer holding at most 7 bits (a partial byte)
+		// it will not overflow.
+		src := dst
+		const maxBits = ptrSize*8 - 7
+		if n <= maxBits {
+			// Start with bits in output buffer.
+			pattern := bits
+			npattern := nbits
+
+			// If we need more bits, fetch them from memory.
+			if size == 1 {
+				src = subtract1(src)
+				for npattern < n {
+					pattern <<= 8
+					pattern |= uintptr(*src)
+					src = subtract1(src)
+					npattern += 8
+				}
+			} else {
+				src = add1(src)
+				for npattern < n {
+					pattern <<= 4
+					pattern |= uintptr(*src) & 0xf
+					src = add1(src)
+					npattern += 4
+				}
+			}
+
+			// We started with the whole bit output buffer,
+			// and then we loaded bits from whole bytes.
+			// Either way, we might now have too many instead of too few.
+			// Discard the extra.
+			if npattern > n {
+				pattern >>= npattern - n
+				npattern = n
+			}
+
+			// Replicate pattern to at most maxBits.
+			if npattern == 1 {
+				// One bit being repeated.
+				// If the bit is 1, make the pattern all 1s.
+				// If the bit is 0, the pattern is already all 0s,
+				// but we can claim that the number of bits
+				// in the word is equal to the number we need (c),
+				// because right shift of bits will zero fill.
+				if pattern == 1 {
+					pattern = 1<<maxBits - 1
+					npattern = maxBits
+				} else {
+					npattern = c
+				}
+			} else {
+				b := pattern
+				nb := npattern
+				if nb+nb <= maxBits {
+					// Double pattern until the whole uintptr is filled.
+					for nb <= ptrSize*8 {
+						b |= b << nb
+						nb += nb
+					}
+					// Trim away incomplete copy of original pattern in high bits.
+					// TODO(rsc): Replace with table lookup or loop on systems without divide?
+					nb = maxBits / npattern * npattern
+					b &= 1<<nb - 1
+					pattern = b
+					npattern = nb
+				}
+			}
+
+			// Add pattern to bit buffer and flush bit buffer, c/npattern times.
+			// Since pattern contains >8 bits, there will be full bytes to flush
+			// on each iteration.
+			for ; c >= npattern; c -= npattern {
+				bits |= pattern << nbits
+				nbits += npattern
+				if size == 1 {
+					for nbits >= 8 {
+						*dst = uint8(bits)
+						dst = add1(dst)
+						bits >>= 8
+						nbits -= 8
+					}
+				} else {
+					for nbits >= 4 {
+						*dst = uint8(bits&0xf | bitMarkedAll)
+						dst = subtract1(dst)
+						bits >>= 4
+						nbits -= 4
+					}
+				}
+			}
+
+			// Add final fragment to bit buffer.
+			if c > 0 {
+				pattern &= 1<<c - 1
+				bits |= pattern << nbits
+				nbits += c
+			}
+			continue Run
+		}
+
+		// Repeat; n too large to fit in a register.
+		// Since nbits <= 7, we know the first few bytes of repeated data
+		// are already written to memory.
+		off := n - nbits // n > nbits because n > maxBits and nbits <= 7
+		if size == 1 {
+			// Leading src fragment.
+			src = subtractb(src, (off+7)/8)
+			if frag := off & 7; frag != 0 {
+				bits |= uintptr(*src) >> (8 - frag) << nbits
+				src = add1(src)
+				nbits += frag
+				c -= frag
+			}
+			// Main loop: load one byte, write another.
+			// The bits are rotating through the bit buffer.
+			for i := c / 8; i > 0; i-- {
+				bits |= uintptr(*src) << nbits
+				src = add1(src)
+				*dst = uint8(bits)
+				dst = add1(dst)
+				bits >>= 8
+			}
+			// Final src fragment.
+			if c %= 8; c > 0 {
+				bits |= (uintptr(*src) & (1<<c - 1)) << nbits
+				nbits += c
+			}
+		} else {
+			// Leading src fragment.
+			src = addb(src, (off+3)/4)
+			if frag := off & 3; frag != 0 {
+				bits |= (uintptr(*src) & 0xf) >> (4 - frag) << nbits
+				src = subtract1(src)
+				nbits += frag
+				c -= frag
+			}
+			// Main loop: load one byte, write another.
+			// The bits are rotating through the bit buffer.
+			for i := c / 4; i > 0; i-- {
+				bits |= (uintptr(*src) & 0xf) << nbits
+				src = subtract1(src)
+				*dst = uint8(bits&0xf | bitMarkedAll)
+				dst = subtract1(dst)
+				bits >>= 4
+			}
+			// Final src fragment.
+			if c %= 4; c > 0 {
+				bits |= (uintptr(*src) & (1<<c - 1)) << nbits
+				nbits += c
+			}
+		}
+	}
+
+	// Write any final bits out, using full-byte writes, even for the final byte.
+	var totalBits uintptr
+	if size == 1 {
+		totalBits = (uintptr(unsafe.Pointer(dst))-uintptr(unsafe.Pointer(dstStart)))*8 + nbits
+		nbits += -nbits & 7
+		for ; nbits > 0; nbits -= 8 {
+			*dst = uint8(bits)
+			dst = add1(dst)
+			bits >>= 8
+		}
+	} else {
+		totalBits = (uintptr(unsafe.Pointer(dstStart))-uintptr(unsafe.Pointer(dst)))*4 + nbits
+		nbits += -nbits & 3
+		for ; nbits > 0; nbits -= 4 {
+			v := bits&0xf | bitMarkedAll
+			*dst = uint8(v)
+			dst = subtract1(dst)
+			bits >>= 4
+		}
+		// Clear the mark bits in the first two entries.
+		// They are the actual mark and checkmark bits,
+		// not non-dead markers. It simplified the code
+		// above to set the marker in every bit written and
+		// then clear these two as a special case at the end.
+		*dstStart &^= bitMarked | bitMarked<<heapBitsShift
+	}
+	return totalBits
+}
+
+func dumpGCProg(p *byte) {
+	nptr := 0
+	for {
+		x := *p
+		p = add1(p)
+		if x == 0 {
+			print("\t", nptr, " end\n")
+			break
+		}
+		if x&0x80 == 0 {
+			print("\t", nptr, " lit ", x, ":")
+			n := int(x+7) / 8
+			for i := 0; i < n; i++ {
+				print(" ", hex(*p))
+				p = add1(p)
+			}
+			print("\n")
+			nptr += int(x)
+		} else {
+			nbit := int(x &^ 0x80)
+			if nbit == 0 {
+				for nb := uint(0); ; nb += 7 {
+					x := *p
+					p = add1(p)
+					nbit |= int(x&0x7f) << nb
+					if x&0x80 == 0 {
+						break
+					}
+				}
+			}
+			count := 0
+			for nb := uint(0); ; nb += 7 {
+				x := *p
+				p = add1(p)
+				count |= int(x&0x7f) << nb
+				if x&0x80 == 0 {
+					break
+				}
+			}
+			print("\t", nptr, " repeat ", nbit, " × ", count, "\n")
+			nptr += nbit * count
+		}
+	}
+}
+
+// Testing.
+
+func getgcmaskcb(frame *stkframe, ctxt unsafe.Pointer) bool {
+	target := (*stkframe)(ctxt)
+	if frame.sp <= target.sp && target.sp < frame.varp {
+		*target = *frame
+		return false
+	}
+	return true
+}
+
+// gcbits returns the GC type info for x, for testing.
+// The result is the bitmap entries (0 or 1), one entry per byte.
+//go:linkname reflect_gcbits reflect.gcbits
+func reflect_gcbits(x interface{}) []byte {
+	ret := getgcmask(x)
+	typ := (*ptrtype)(unsafe.Pointer((*eface)(unsafe.Pointer(&x))._type)).elem
+	nptr := typ.ptrdata / ptrSize
+	for uintptr(len(ret)) > nptr && ret[len(ret)-1] == 0 {
+		ret = ret[:len(ret)-1]
+	}
+	return ret
+}
+
+// Returns GC type info for object p for testing.
+func getgcmask(ep interface{}) (mask []byte) {
+	e := *(*eface)(unsafe.Pointer(&ep))
+	p := e.data
+	t := e._type
+	// data or bss
+	for datap := &firstmoduledata; datap != nil; datap = datap.next {
+		// data
+		if datap.data <= uintptr(p) && uintptr(p) < datap.edata {
+			bitmap := datap.gcdatamask.bytedata
+			n := (*ptrtype)(unsafe.Pointer(t)).elem.size
+			mask = make([]byte, n/ptrSize)
+			for i := uintptr(0); i < n; i += ptrSize {
+				off := (uintptr(p) + i - datap.data) / ptrSize
+				mask[i/ptrSize] = (*addb(bitmap, off/8) >> (off % 8)) & 1
+			}
+			return
+		}
+
+		// bss
+		if datap.bss <= uintptr(p) && uintptr(p) < datap.ebss {
+			bitmap := datap.gcbssmask.bytedata
+			n := (*ptrtype)(unsafe.Pointer(t)).elem.size
+			mask = make([]byte, n/ptrSize)
+			for i := uintptr(0); i < n; i += ptrSize {
+				off := (uintptr(p) + i - datap.bss) / ptrSize
+				mask[i/ptrSize] = (*addb(bitmap, off/8) >> (off % 8)) & 1
+			}
+			return
+		}
+	}
+
+	// heap
+	var n uintptr
+	var base uintptr
+	if mlookup(uintptr(p), &base, &n, nil) != 0 {
+		mask = make([]byte, n/ptrSize)
+		for i := uintptr(0); i < n; i += ptrSize {
+			hbits := heapBitsForAddr(base + i)
+			if hbits.isPointer() {
+				mask[i/ptrSize] = 1
+			}
+			if i >= 2*ptrSize && !hbits.isMarked() {
+				mask = mask[:i/ptrSize]
+				break
+			}
+		}
+		return
+	}
+
+	// stack
+	if _g_ := getg(); _g_.m.curg.stack.lo <= uintptr(p) && uintptr(p) < _g_.m.curg.stack.hi {
+		var frame stkframe
+		frame.sp = uintptr(p)
+		_g_ := getg()
+		gentraceback(_g_.m.curg.sched.pc, _g_.m.curg.sched.sp, 0, _g_.m.curg, 0, nil, 1000, getgcmaskcb, noescape(unsafe.Pointer(&frame)), 0)
+		if frame.fn != nil {
+			f := frame.fn
+			targetpc := frame.continpc
+			if targetpc == 0 {
+				return
+			}
+			if targetpc != f.entry {
+				targetpc--
+			}
+			pcdata := pcdatavalue(f, _PCDATA_StackMapIndex, targetpc)
+			if pcdata == -1 {
+				return
+			}
+			stkmap := (*stackmap)(funcdata(f, _FUNCDATA_LocalsPointerMaps))
+			if stkmap == nil || stkmap.n <= 0 {
+				return
+			}
+			bv := stackmapdata(stkmap, pcdata)
+			size := uintptr(bv.n) * ptrSize
+			n := (*ptrtype)(unsafe.Pointer(t)).elem.size
+			mask = make([]byte, n/ptrSize)
+			for i := uintptr(0); i < n; i += ptrSize {
+				bitmap := bv.bytedata
+				off := (uintptr(p) + i - frame.varp + size) / ptrSize
+				mask[i/ptrSize] = (*addb(bitmap, off/8) >> (off % 8)) & 1
+			}
+		}
+		return
+	}
+
+	// otherwise, not something the GC knows about.
+	// possibly read-only data, like malloc(0).
+	// must not have pointers
+	return
+}
diff --git a/src/runtime/mcache.c b/src/runtime/mcache.c
deleted file mode 100644
index 5fdbe32..0000000
--- a/src/runtime/mcache.c
+++ /dev/null
@@ -1,115 +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.
-
-// Per-P malloc cache for small objects.
-//
-// See malloc.h for an overview.
-
-#include "runtime.h"
-#include "arch_GOARCH.h"
-#include "malloc.h"
-
-extern volatile intgo runtime·MemProfileRate;
-
-// dummy MSpan that contains no free objects.
-MSpan runtime·emptymspan;
-
-MCache*
-runtime·allocmcache(void)
-{
-	intgo rate;
-	MCache *c;
-	int32 i;
-
-	runtime·lock(&runtime·mheap.lock);
-	c = runtime·FixAlloc_Alloc(&runtime·mheap.cachealloc);
-	runtime·unlock(&runtime·mheap.lock);
-	runtime·memclr((byte*)c, sizeof(*c));
-	for(i = 0; i < NumSizeClasses; i++)
-		c->alloc[i] = &runtime·emptymspan;
-
-	// Set first allocation sample size.
-	rate = runtime·MemProfileRate;
-	if(rate > 0x3fffffff)	// make 2*rate not overflow
-		rate = 0x3fffffff;
-	if(rate != 0)
-		c->next_sample = runtime·fastrand1() % (2*rate);
-
-	return c;
-}
-
-static void
-freemcache(MCache *c)
-{
-	runtime·MCache_ReleaseAll(c);
-	runtime·stackcache_clear(c);
-	runtime·gcworkbuffree(c->gcworkbuf);
-	runtime·lock(&runtime·mheap.lock);
-	runtime·purgecachedstats(c);
-	runtime·FixAlloc_Free(&runtime·mheap.cachealloc, c);
-	runtime·unlock(&runtime·mheap.lock);
-}
-
-static void
-freemcache_m(void)
-{
-	MCache *c;
-
-	c = g->m->ptrarg[0];
-	g->m->ptrarg[0] = nil;
-	freemcache(c);
-}
-
-void
-runtime·freemcache(MCache *c)
-{
-	void (*fn)(void);
-
-	g->m->ptrarg[0] = c;
-	fn = freemcache_m;
-	runtime·onM(&fn);
-}
-
-// Gets a span that has a free object in it and assigns it
-// to be the cached span for the given sizeclass.  Returns this span.
-MSpan*
-runtime·MCache_Refill(MCache *c, int32 sizeclass)
-{
-	MSpan *s;
-
-	g->m->locks++;
-	// Return the current cached span to the central lists.
-	s = c->alloc[sizeclass];
-	if(s->freelist != nil)
-		runtime·throw("refill on a nonempty span");
-	if(s != &runtime·emptymspan)
-		s->incache = false;
-
-	// Get a new cached span from the central lists.
-	s = runtime·MCentral_CacheSpan(&runtime·mheap.central[sizeclass].mcentral);
-	if(s == nil)
-		runtime·throw("out of memory");
-	if(s->freelist == nil) {
-		runtime·printf("%d %d\n", s->ref, (int32)((s->npages << PageShift) / s->elemsize));
-		runtime·throw("empty span");
-	}
-	c->alloc[sizeclass] = s;
-	g->m->locks--;
-	return s;
-}
-
-void
-runtime·MCache_ReleaseAll(MCache *c)
-{
-	int32 i;
-	MSpan *s;
-
-	for(i=0; i<NumSizeClasses; i++) {
-		s = c->alloc[i];
-		if(s != &runtime·emptymspan) {
-			runtime·MCentral_UncacheSpan(&runtime·mheap.central[i].mcentral, s);
-			c->alloc[i] = &runtime·emptymspan;
-		}
-	}
-}
diff --git a/src/runtime/mcache.go b/src/runtime/mcache.go
new file mode 100644
index 0000000..8c2a6b0
--- /dev/null
+++ b/src/runtime/mcache.go
@@ -0,0 +1,139 @@
+// 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"
+
+// Per-thread (in Go, per-P) cache for small objects.
+// No locking needed because it is per-thread (per-P).
+type mcache struct {
+	// The following members are accessed on every malloc,
+	// so they are grouped here for better caching.
+	next_sample      int32   // trigger heap sample after allocating this many bytes
+	local_cachealloc uintptr // bytes allocated from cache since last lock of heap
+	local_scan       uintptr // bytes of scannable heap allocated
+	// Allocator cache for tiny objects w/o pointers.
+	// See "Tiny allocator" comment in malloc.go.
+	tiny             unsafe.Pointer
+	tinyoffset       uintptr
+	local_tinyallocs uintptr // number of tiny allocs not counted in other stats
+
+	// The rest is not accessed on every malloc.
+	alloc [_NumSizeClasses]*mspan // spans to allocate from
+
+	stackcache [_NumStackOrders]stackfreelist
+
+	// Local allocator stats, flushed during GC.
+	local_nlookup    uintptr                  // number of pointer lookups
+	local_largefree  uintptr                  // bytes freed for large objects (>maxsmallsize)
+	local_nlargefree uintptr                  // number of frees for large objects (>maxsmallsize)
+	local_nsmallfree [_NumSizeClasses]uintptr // number of frees for small objects (<=maxsmallsize)
+}
+
+// A gclink is a node in a linked list of blocks, like mlink,
+// but it is opaque to the garbage collector.
+// The GC does not trace the pointers during collection,
+// and the compiler does not emit write barriers for assignments
+// of gclinkptr values. Code should store references to gclinks
+// as gclinkptr, not as *gclink.
+type gclink struct {
+	next gclinkptr
+}
+
+// A gclinkptr is a pointer to a gclink, but it is opaque
+// to the garbage collector.
+type gclinkptr uintptr
+
+// ptr returns the *gclink form of p.
+// The result should be used for accessing fields, not stored
+// in other data structures.
+func (p gclinkptr) ptr() *gclink {
+	return (*gclink)(unsafe.Pointer(p))
+}
+
+type stackfreelist struct {
+	list gclinkptr // linked list of free stacks
+	size uintptr   // total size of stacks in list
+}
+
+// dummy MSpan that contains no free objects.
+var emptymspan mspan
+
+func allocmcache() *mcache {
+	lock(&mheap_.lock)
+	c := (*mcache)(fixAlloc_Alloc(&mheap_.cachealloc))
+	unlock(&mheap_.lock)
+	memclr(unsafe.Pointer(c), unsafe.Sizeof(*c))
+	for i := 0; i < _NumSizeClasses; i++ {
+		c.alloc[i] = &emptymspan
+	}
+
+	// Set first allocation sample size.
+	rate := MemProfileRate
+	if rate > 0x3fffffff { // make 2*rate not overflow
+		rate = 0x3fffffff
+	}
+	if rate != 0 {
+		c.next_sample = int32(int(fastrand1()) % (2 * rate))
+	}
+
+	return c
+}
+
+func freemcache(c *mcache) {
+	systemstack(func() {
+		mCache_ReleaseAll(c)
+		stackcache_clear(c)
+
+		// NOTE(rsc,rlh): If gcworkbuffree comes back, we need to coordinate
+		// with the stealing of gcworkbufs during garbage collection to avoid
+		// a race where the workbuf is double-freed.
+		// gcworkbuffree(c.gcworkbuf)
+
+		lock(&mheap_.lock)
+		purgecachedstats(c)
+		fixAlloc_Free(&mheap_.cachealloc, unsafe.Pointer(c))
+		unlock(&mheap_.lock)
+	})
+}
+
+// Gets a span that has a free object in it and assigns it
+// to be the cached span for the given sizeclass.  Returns this span.
+func mCache_Refill(c *mcache, sizeclass int32) *mspan {
+	_g_ := getg()
+
+	_g_.m.locks++
+	// Return the current cached span to the central lists.
+	s := c.alloc[sizeclass]
+	if s.freelist.ptr() != nil {
+		throw("refill on a nonempty span")
+	}
+	if s != &emptymspan {
+		s.incache = false
+	}
+
+	// Get a new cached span from the central lists.
+	s = mCentral_CacheSpan(&mheap_.central[sizeclass].mcentral)
+	if s == nil {
+		throw("out of memory")
+	}
+	if s.freelist.ptr() == nil {
+		println(s.ref, (s.npages<<_PageShift)/s.elemsize)
+		throw("empty span")
+	}
+	c.alloc[sizeclass] = s
+	_g_.m.locks--
+	return s
+}
+
+func mCache_ReleaseAll(c *mcache) {
+	for i := 0; i < _NumSizeClasses; i++ {
+		s := c.alloc[i]
+		if s != &emptymspan {
+			mCentral_UncacheSpan(&mheap_.central[i].mcentral, s)
+			c.alloc[i] = &emptymspan
+		}
+	}
+}
diff --git a/src/runtime/mcentral.c b/src/runtime/mcentral.c
deleted file mode 100644
index fe6bcfe..0000000
--- a/src/runtime/mcentral.c
+++ /dev/null
@@ -1,214 +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.
-
-// Central free lists.
-//
-// See malloc.h 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)
-// and those that are completely allocated (c->empty).
-
-#include "runtime.h"
-#include "arch_GOARCH.h"
-#include "malloc.h"
-
-static MSpan* MCentral_Grow(MCentral *c);
-
-// Initialize a single central free list.
-void
-runtime·MCentral_Init(MCentral *c, int32 sizeclass)
-{
-	c->sizeclass = sizeclass;
-	runtime·MSpanList_Init(&c->nonempty);
-	runtime·MSpanList_Init(&c->empty);
-}
-
-// Allocate a span to use in an MCache.
-MSpan*
-runtime·MCentral_CacheSpan(MCentral *c)
-{
-	MSpan *s;
-	int32 cap, n;
-	uint32 sg;
-
-	runtime·lock(&c->lock);
-	sg = runtime·mheap.sweepgen;
-retry:
-	for(s = c->nonempty.next; s != &c->nonempty; s = s->next) {
-		if(s->sweepgen == sg-2 && runtime·cas(&s->sweepgen, sg-2, sg-1)) {
-			runtime·MSpanList_Remove(s);
-			runtime·MSpanList_InsertBack(&c->empty, s);
-			runtime·unlock(&c->lock);
-			runtime·MSpan_Sweep(s, true);
-			goto havespan;
-		}
-		if(s->sweepgen == sg-1) {
-			// the span is being swept by background sweeper, skip
-			continue;
-		}
-		// we have a nonempty span that does not require sweeping, allocate from it
-		runtime·MSpanList_Remove(s);
-		runtime·MSpanList_InsertBack(&c->empty, s);
-		runtime·unlock(&c->lock);
-		goto havespan;
-	}
-
-	for(s = c->empty.next; s != &c->empty; s = s->next) {
-		if(s->sweepgen == sg-2 && runtime·cas(&s->sweepgen, sg-2, sg-1)) {
-			// we have an empty span that requires sweeping,
-			// sweep it and see if we can free some space in it
-			runtime·MSpanList_Remove(s);
-			// swept spans are at the end of the list
-			runtime·MSpanList_InsertBack(&c->empty, s);
-			runtime·unlock(&c->lock);
-			runtime·MSpan_Sweep(s, true);
-			if(s->freelist != nil)
-				goto havespan;
-			runtime·lock(&c->lock);
-			// the span is still empty after sweep
-			// it is already in the empty list, so just retry
-			goto retry;
-		}
-		if(s->sweepgen == sg-1) {
-			// the span is being swept by background sweeper, skip
-			continue;
-		}
-		// already swept empty span,
-		// all subsequent ones must also be either swept or in process of sweeping
-		break;
-	}
-	runtime·unlock(&c->lock);
-
-	// Replenish central list if empty.
-	s = MCentral_Grow(c);
-	if(s == nil)
-		return nil;
-	runtime·lock(&c->lock);
-	runtime·MSpanList_InsertBack(&c->empty, s);
-	runtime·unlock(&c->lock);
-
-havespan:
-	// At this point s is a non-empty span, queued at the end of the empty list,
-	// c is unlocked.
-	cap = (s->npages << PageShift) / s->elemsize;
-	n = cap - s->ref;
-	if(n == 0)
-		runtime·throw("empty span");
-	if(s->freelist == nil)
-		runtime·throw("freelist empty");
-	s->incache = true;
-	return s;
-}
-
-// Return span from an MCache.
-void
-runtime·MCentral_UncacheSpan(MCentral *c, MSpan *s)
-{
-	int32 cap, n;
-
-	runtime·lock(&c->lock);
-
-	s->incache = false;
-
-	if(s->ref == 0)
-		runtime·throw("uncaching full span");
-
-	cap = (s->npages << PageShift) / s->elemsize;
-	n = cap - s->ref;
-	if(n > 0) {
-		runtime·MSpanList_Remove(s);
-		runtime·MSpanList_Insert(&c->nonempty, s);
-	}
-	runtime·unlock(&c->lock);
-}
-
-// Free n objects from a span s back into the central free list c.
-// Called during sweep.
-// Returns true if the span was returned to heap.  Sets sweepgen to
-// the latest generation.
-// If preserve=true, don't return the span to heap nor relink in MCentral lists;
-// caller takes care of it.
-bool
-runtime·MCentral_FreeSpan(MCentral *c, MSpan *s, int32 n, MLink *start, MLink *end, bool preserve)
-{
-	bool wasempty;
-
-	if(s->incache)
-		runtime·throw("freespan into cached span");
-
-	// Add the objects back to s's free list.
-	wasempty = s->freelist == nil;
-	end->next = s->freelist;
-	s->freelist = start;
-	s->ref -= n;
-
-	if(preserve) {
-		// preserve is set only when called from MCentral_CacheSpan above,
-		// the span must be in the empty list.
-		if(s->next == nil)
-			runtime·throw("can't preserve unlinked span");
-		runtime·atomicstore(&s->sweepgen, runtime·mheap.sweepgen);
-		return false;
-	}
-
-	runtime·lock(&c->lock);
-
-	// Move to nonempty if necessary.
-	if(wasempty) {
-		runtime·MSpanList_Remove(s);
-		runtime·MSpanList_Insert(&c->nonempty, s);
-	}
-
-	// delay updating sweepgen until here.  This is the signal that
-	// the span may be used in an MCache, so it must come after the
-	// linked list operations above (actually, just after the
-	// lock of c above.)
-	runtime·atomicstore(&s->sweepgen, runtime·mheap.sweepgen);
-
-	if(s->ref != 0) {
-		runtime·unlock(&c->lock);
-		return false;
-	}
-
-	// s is completely freed, return it to the heap.
-	runtime·MSpanList_Remove(s);
-	s->needzero = 1;
-	s->freelist = nil;
-	runtime·unlock(&c->lock);
-	runtime·unmarkspan((byte*)(s->start<<PageShift), s->npages<<PageShift);
-	runtime·MHeap_Free(&runtime·mheap, s, 0);
-	return true;
-}
-
-// Fetch a new span from the heap and carve into objects for the free list.
-static MSpan*
-MCentral_Grow(MCentral *c)
-{
-	uintptr size, npages, i, n;
-	MLink **tailp, *v;
-	byte *p;
-	MSpan *s;
-
-	npages = runtime·class_to_allocnpages[c->sizeclass];
-	size = runtime·class_to_size[c->sizeclass];
-	n = (npages << PageShift) / size;
-	s = runtime·MHeap_Alloc(&runtime·mheap, npages, c->sizeclass, 0, 1);
-	if(s == nil)
-		return nil;
-
-	// Carve span into sequence of blocks.
-	tailp = &s->freelist;
-	p = (byte*)(s->start << PageShift);
-	s->limit = p + size*n;
-	for(i=0; i<n; i++) {
-		v = (MLink*)p;
-		*tailp = v;
-		tailp = &v->next;
-		p += size;
-	}
-	*tailp = nil;
-	runtime·markspan((byte*)(s->start<<PageShift), size, n, size*n < (s->npages<<PageShift));
-	return s;
-}
diff --git a/src/runtime/mcentral.go b/src/runtime/mcentral.go
new file mode 100644
index 0000000..161af99
--- /dev/null
+++ b/src/runtime/mcentral.go
@@ -0,0 +1,212 @@
+// 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.
+
+// Central free lists.
+//
+// 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)
+// and those that are completely allocated (c->empty).
+
+package runtime
+
+// Central list of free objects of a given size.
+type mcentral struct {
+	lock      mutex
+	sizeclass int32
+	nonempty  mspan // list of spans with a free object
+	empty     mspan // list of spans with no free objects (or cached in an mcache)
+}
+
+// Initialize a single central free list.
+func mCentral_Init(c *mcentral, sizeclass int32) {
+	c.sizeclass = sizeclass
+	mSpanList_Init(&c.nonempty)
+	mSpanList_Init(&c.empty)
+}
+
+// Allocate a span to use in an MCache.
+func mCentral_CacheSpan(c *mcentral) *mspan {
+	// Deduct credit for this span allocation and sweep if necessary.
+	deductSweepCredit(uintptr(class_to_size[c.sizeclass]), 0)
+
+	lock(&c.lock)
+	sg := mheap_.sweepgen
+retry:
+	var s *mspan
+	for s = c.nonempty.next; s != &c.nonempty; s = s.next {
+		if s.sweepgen == sg-2 && cas(&s.sweepgen, sg-2, sg-1) {
+			mSpanList_Remove(s)
+			mSpanList_InsertBack(&c.empty, s)
+			unlock(&c.lock)
+			mSpan_Sweep(s, true)
+			goto havespan
+		}
+		if s.sweepgen == sg-1 {
+			// the span is being swept by background sweeper, skip
+			continue
+		}
+		// we have a nonempty span that does not require sweeping, allocate from it
+		mSpanList_Remove(s)
+		mSpanList_InsertBack(&c.empty, s)
+		unlock(&c.lock)
+		goto havespan
+	}
+
+	for s = c.empty.next; s != &c.empty; s = s.next {
+		if s.sweepgen == sg-2 && cas(&s.sweepgen, sg-2, sg-1) {
+			// we have an empty span that requires sweeping,
+			// sweep it and see if we can free some space in it
+			mSpanList_Remove(s)
+			// swept spans are at the end of the list
+			mSpanList_InsertBack(&c.empty, s)
+			unlock(&c.lock)
+			mSpan_Sweep(s, true)
+			if s.freelist.ptr() != nil {
+				goto havespan
+			}
+			lock(&c.lock)
+			// the span is still empty after sweep
+			// it is already in the empty list, so just retry
+			goto retry
+		}
+		if s.sweepgen == sg-1 {
+			// the span is being swept by background sweeper, skip
+			continue
+		}
+		// already swept empty span,
+		// all subsequent ones must also be either swept or in process of sweeping
+		break
+	}
+	unlock(&c.lock)
+
+	// Replenish central list if empty.
+	s = mCentral_Grow(c)
+	if s == nil {
+		return nil
+	}
+	lock(&c.lock)
+	mSpanList_InsertBack(&c.empty, s)
+	unlock(&c.lock)
+
+	// At this point s is a non-empty span, queued at the end of the empty list,
+	// c is unlocked.
+havespan:
+	cap := int32((s.npages << _PageShift) / s.elemsize)
+	n := cap - int32(s.ref)
+	if n == 0 {
+		throw("empty span")
+	}
+	if s.freelist.ptr() == nil {
+		throw("freelist empty")
+	}
+	s.incache = true
+	return s
+}
+
+// Return span from an MCache.
+func mCentral_UncacheSpan(c *mcentral, s *mspan) {
+	lock(&c.lock)
+
+	s.incache = false
+
+	if s.ref == 0 {
+		throw("uncaching full span")
+	}
+
+	cap := int32((s.npages << _PageShift) / s.elemsize)
+	n := cap - int32(s.ref)
+	if n > 0 {
+		mSpanList_Remove(s)
+		mSpanList_Insert(&c.nonempty, s)
+	}
+	unlock(&c.lock)
+}
+
+// Free n objects from a span s back into the central free list c.
+// Called during sweep.
+// Returns true if the span was returned to heap.  Sets sweepgen to
+// the latest generation.
+// If preserve=true, don't return the span to heap nor relink in MCentral lists;
+// caller takes care of it.
+func mCentral_FreeSpan(c *mcentral, s *mspan, n int32, start gclinkptr, end gclinkptr, preserve bool) bool {
+	if s.incache {
+		throw("freespan into cached span")
+	}
+
+	// Add the objects back to s's free list.
+	wasempty := s.freelist.ptr() == nil
+	end.ptr().next = s.freelist
+	s.freelist = start
+	s.ref -= uint16(n)
+
+	if preserve {
+		// preserve is set only when called from MCentral_CacheSpan above,
+		// the span must be in the empty list.
+		if s.next == nil {
+			throw("can't preserve unlinked span")
+		}
+		atomicstore(&s.sweepgen, mheap_.sweepgen)
+		return false
+	}
+
+	lock(&c.lock)
+
+	// Move to nonempty if necessary.
+	if wasempty {
+		mSpanList_Remove(s)
+		mSpanList_Insert(&c.nonempty, s)
+	}
+
+	// delay updating sweepgen until here.  This is the signal that
+	// the span may be used in an MCache, so it must come after the
+	// linked list operations above (actually, just after the
+	// lock of c above.)
+	atomicstore(&s.sweepgen, mheap_.sweepgen)
+
+	if s.ref != 0 {
+		unlock(&c.lock)
+		return false
+	}
+
+	// s is completely freed, return it to the heap.
+	mSpanList_Remove(s)
+	s.needzero = 1
+	s.freelist = 0
+	unlock(&c.lock)
+	heapBitsForSpan(s.base()).initSpan(s.layout())
+	mHeap_Free(&mheap_, s, 0)
+	return true
+}
+
+// Fetch a new span from the heap and carve into objects for the free list.
+func mCentral_Grow(c *mcentral) *mspan {
+	npages := uintptr(class_to_allocnpages[c.sizeclass])
+	size := uintptr(class_to_size[c.sizeclass])
+	n := (npages << _PageShift) / size
+
+	s := mHeap_Alloc(&mheap_, npages, c.sizeclass, false, true)
+	if s == nil {
+		return nil
+	}
+
+	p := uintptr(s.start << _PageShift)
+	s.limit = p + size*n
+	head := gclinkptr(p)
+	tail := gclinkptr(p)
+	// i==0 iteration already done
+	for i := uintptr(1); i < n; i++ {
+		p += size
+		tail.ptr().next = gclinkptr(p)
+		tail = gclinkptr(p)
+	}
+	if s.freelist.ptr() != nil {
+		throw("freelist not empty")
+	}
+	tail.ptr().next = 0
+	s.freelist = head
+	heapBitsForSpan(s.base()).initSpan(s.layout())
+	return s
+}
diff --git a/src/runtime/mem.go b/src/runtime/mem.go
deleted file mode 100644
index e6f1eb0..0000000
--- a/src/runtime/mem.go
+++ /dev/null
@@ -1,108 +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"
-
-// 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.
-	Alloc      uint64 // bytes allocated and still in use
-	TotalAlloc uint64 // bytes allocated (even if freed)
-	Sys        uint64 // bytes obtained from system (sum of XxxSys below)
-	Lookups    uint64 // number of pointer lookups
-	Mallocs    uint64 // number of mallocs
-	Frees      uint64 // number of frees
-
-	// Main allocation heap statistics.
-	HeapAlloc    uint64 // bytes allocated and still in use
-	HeapSys      uint64 // bytes obtained from system
-	HeapIdle     uint64 // bytes in idle spans
-	HeapInuse    uint64 // bytes in non-idle span
-	HeapReleased uint64 // bytes released to the OS
-	HeapObjects  uint64 // total number of allocated objects
-
-	// Low-level fixed-size structure allocator statistics.
-	//	Inuse is bytes used now.
-	//	Sys is bytes obtained from system.
-	StackInuse  uint64 // bytes used by stack allocator
-	StackSys    uint64
-	MSpanInuse  uint64 // mspan structures
-	MSpanSys    uint64
-	MCacheInuse uint64 // mcache structures
-	MCacheSys   uint64
-	BuckHashSys uint64 // profiling bucket hash table
-	GCSys       uint64 // GC metadata
-	OtherSys    uint64 // other system allocations
-
-	// Garbage collector statistics.
-	NextGC       uint64 // next collection will happen when HeapAlloc ≥ this amount
-	LastGC       uint64 // end time of last collection (nanoseconds since 1970)
-	PauseTotalNs uint64
-	PauseNs      [256]uint64 // circular buffer of recent GC pause durations, most recent at [(NumGC+255)%256]
-	PauseEnd     [256]uint64 // circular buffer of recent GC pause end times
-	NumGC        uint32
-	EnableGC     bool
-	DebugGC      bool
-
-	// Per-size allocation statistics.
-	// 61 is NumSizeClasses in the C code.
-	BySize [61]struct {
-		Size    uint32
-		Mallocs uint64
-		Frees   uint64
-	}
-}
-
-var sizeof_C_MStats uintptr // filled in by malloc.goc
-
-func init() {
-	var memStats MemStats
-	if sizeof_C_MStats != unsafe.Sizeof(memStats) {
-		println(sizeof_C_MStats, unsafe.Sizeof(memStats))
-		gothrow("MStats vs MemStatsType size mismatch")
-	}
-}
-
-// ReadMemStats populates m with memory allocator statistics.
-func ReadMemStats(m *MemStats) {
-	// Have to acquire worldsema to stop the world,
-	// because stoptheworld can only be used by
-	// one goroutine at a time, and there might be
-	// a pending garbage collection already calling it.
-	semacquire(&worldsema, false)
-	gp := getg()
-	gp.m.gcing = 1
-	onM(stoptheworld)
-
-	gp.m.ptrarg[0] = noescape(unsafe.Pointer(m))
-	onM(readmemstats_m)
-
-	gp.m.gcing = 0
-	gp.m.locks++
-	semrelease(&worldsema)
-	onM(starttheworld)
-	gp.m.locks--
-}
-
-// Implementation of runtime/debug.WriteHeapDump
-func writeHeapDump(fd uintptr) {
-	semacquire(&worldsema, false)
-	gp := getg()
-	gp.m.gcing = 1
-	onM(stoptheworld)
-
-	gp.m.scalararg[0] = fd
-	onM(writeheapdump_m)
-
-	gp.m.gcing = 0
-	gp.m.locks++
-	semrelease(&worldsema)
-	onM(starttheworld)
-	gp.m.locks--
-}
diff --git a/src/runtime/mem_bsd.go b/src/runtime/mem_bsd.go
new file mode 100644
index 0000000..ecab584
--- /dev/null
+++ b/src/runtime/mem_bsd.go
@@ -0,0 +1,93 @@
+// Copyright 2010 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 dragonfly freebsd nacl netbsd openbsd solaris
+
+package runtime
+
+import "unsafe"
+
+// Don't split the stack as this function may be invoked without a valid G,
+// which prevents us from allocating more stack.
+//go:nosplit
+func sysAlloc(n uintptr, sysStat *uint64) unsafe.Pointer {
+	v := unsafe.Pointer(mmap(nil, n, _PROT_READ|_PROT_WRITE, _MAP_ANON|_MAP_PRIVATE, -1, 0))
+	if uintptr(v) < 4096 {
+		return nil
+	}
+	mSysStatInc(sysStat, n)
+	return v
+}
+
+func sysUnused(v unsafe.Pointer, n uintptr) {
+	madvise(v, n, _MADV_FREE)
+}
+
+func sysUsed(v unsafe.Pointer, n uintptr) {
+}
+
+// Don't split the stack as this function may be invoked without a valid G,
+// which prevents us from allocating more stack.
+//go:nosplit
+func sysFree(v unsafe.Pointer, n uintptr, sysStat *uint64) {
+	mSysStatDec(sysStat, n)
+	munmap(v, n)
+}
+
+func sysFault(v unsafe.Pointer, n uintptr) {
+	mmap(v, n, _PROT_NONE, _MAP_ANON|_MAP_PRIVATE|_MAP_FIXED, -1, 0)
+}
+
+func sysReserve(v unsafe.Pointer, n uintptr, reserved *bool) unsafe.Pointer {
+	// On 64-bit, people with ulimit -v set complain if we reserve too
+	// much address space.  Instead, assume that the reservation is okay
+	// and check the assumption in SysMap.
+	if ptrSize == 8 && uint64(n) > 1<<32 || goos_nacl != 0 {
+		*reserved = false
+		return v
+	}
+
+	p := unsafe.Pointer(mmap(v, n, _PROT_NONE, _MAP_ANON|_MAP_PRIVATE, -1, 0))
+	if uintptr(p) < 4096 {
+		return nil
+	}
+	*reserved = true
+	return p
+}
+
+func sysMap(v unsafe.Pointer, n uintptr, reserved bool, sysStat *uint64) {
+	const _ENOMEM = 12
+
+	mSysStatInc(sysStat, n)
+
+	// On 64-bit, we don't actually have v reserved, so tread carefully.
+	if !reserved {
+		flags := int32(_MAP_ANON | _MAP_PRIVATE)
+		if GOOS == "dragonfly" {
+			// TODO(jsing): For some reason DragonFly seems to return
+			// memory at a different address than we requested, even when
+			// there should be no reason for it to do so. This can be
+			// avoided by using MAP_FIXED, but I'm not sure we should need
+			// to do this - we do not on other platforms.
+			flags |= _MAP_FIXED
+		}
+		p := mmap(v, n, _PROT_READ|_PROT_WRITE, flags, -1, 0)
+		if uintptr(p) == _ENOMEM {
+			throw("runtime: out of memory")
+		}
+		if p != v {
+			print("runtime: address space conflict: map(", v, ") = ", p, "\n")
+			throw("runtime: address space conflict")
+		}
+		return
+	}
+
+	p := mmap(v, n, _PROT_READ|_PROT_WRITE, _MAP_ANON|_MAP_FIXED|_MAP_PRIVATE, -1, 0)
+	if uintptr(p) == _ENOMEM {
+		throw("runtime: out of memory")
+	}
+	if p != v {
+		throw("runtime: cannot map pages in arena address space")
+	}
+}
diff --git a/src/runtime/mem_darwin.c b/src/runtime/mem_darwin.c
deleted file mode 100644
index bf3ede5..0000000
--- a/src/runtime/mem_darwin.c
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2010 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 "runtime.h"
-#include "arch_GOARCH.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "malloc.h"
-#include "textflag.h"
-
-#pragma textflag NOSPLIT
-void*
-runtime·sysAlloc(uintptr n, uint64 *stat)
-{
-	void *v;
-
-	v = runtime·mmap(nil, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
-	if(v < (void*)4096)
-		return nil;
-	runtime·xadd64(stat, n);
-	return v;
-}
-
-void
-runtime·SysUnused(void *v, uintptr n)
-{
-	// Linux's MADV_DONTNEED is like BSD's MADV_FREE.
-	runtime·madvise(v, n, MADV_FREE);
-}
-
-void
-runtime·SysUsed(void *v, uintptr n)
-{
-	USED(v);
-	USED(n);
-}
-
-void
-runtime·SysFree(void *v, uintptr n, uint64 *stat)
-{
-	runtime·xadd64(stat, -(uint64)n);
-	runtime·munmap(v, n);
-}
-
-void
-runtime·SysFault(void *v, uintptr n)
-{
-	runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
-}
-
-void*
-runtime·SysReserve(void *v, uintptr n, bool *reserved)
-{
-	void *p;
-
-	*reserved = true;
-	p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
-	if(p < (void*)4096)
-		return nil;
-	return p;
-}
-
-enum
-{
-	ENOMEM = 12,
-};
-
-void
-runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
-{
-	void *p;
-	
-	USED(reserved);
-
-	runtime·xadd64(stat, n);
-	p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
-	if(p == (void*)ENOMEM)
-		runtime·throw("runtime: out of memory");
-	if(p != v)
-		runtime·throw("runtime: cannot map pages in arena address space");
-}
diff --git a/src/runtime/mem_darwin.go b/src/runtime/mem_darwin.go
new file mode 100644
index 0000000..3bebd97
--- /dev/null
+++ b/src/runtime/mem_darwin.go
@@ -0,0 +1,63 @@
+// Copyright 2010 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"
+
+// Don't split the stack as this function may be invoked without a valid G,
+// which prevents us from allocating more stack.
+//go:nosplit
+func sysAlloc(n uintptr, sysStat *uint64) unsafe.Pointer {
+	v := (unsafe.Pointer)(mmap(nil, n, _PROT_READ|_PROT_WRITE, _MAP_ANON|_MAP_PRIVATE, -1, 0))
+	if uintptr(v) < 4096 {
+		return nil
+	}
+	mSysStatInc(sysStat, n)
+	return v
+}
+
+func sysUnused(v unsafe.Pointer, n uintptr) {
+	// Linux's MADV_DONTNEED is like BSD's MADV_FREE.
+	madvise(v, n, _MADV_FREE)
+}
+
+func sysUsed(v unsafe.Pointer, n uintptr) {
+}
+
+// Don't split the stack as this function may be invoked without a valid G,
+// which prevents us from allocating more stack.
+//go:nosplit
+func sysFree(v unsafe.Pointer, n uintptr, sysStat *uint64) {
+	mSysStatDec(sysStat, n)
+	munmap(v, n)
+}
+
+func sysFault(v unsafe.Pointer, n uintptr) {
+	mmap(v, n, _PROT_NONE, _MAP_ANON|_MAP_PRIVATE|_MAP_FIXED, -1, 0)
+}
+
+func sysReserve(v unsafe.Pointer, n uintptr, reserved *bool) unsafe.Pointer {
+	*reserved = true
+	p := (unsafe.Pointer)(mmap(v, n, _PROT_NONE, _MAP_ANON|_MAP_PRIVATE, -1, 0))
+	if uintptr(p) < 4096 {
+		return nil
+	}
+	return p
+}
+
+const (
+	_ENOMEM = 12
+)
+
+func sysMap(v unsafe.Pointer, n uintptr, reserved bool, sysStat *uint64) {
+	mSysStatInc(sysStat, n)
+	p := (unsafe.Pointer)(mmap(v, n, _PROT_READ|_PROT_WRITE, _MAP_ANON|_MAP_FIXED|_MAP_PRIVATE, -1, 0))
+	if uintptr(p) == _ENOMEM {
+		throw("runtime: out of memory")
+	}
+	if p != v {
+		throw("runtime: cannot map pages in arena address space")
+	}
+}
diff --git a/src/runtime/mem_dragonfly.c b/src/runtime/mem_dragonfly.c
deleted file mode 100644
index 11457b2..0000000
--- a/src/runtime/mem_dragonfly.c
+++ /dev/null
@@ -1,105 +0,0 @@
-// Copyright 2010 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 "runtime.h"
-#include "arch_GOARCH.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "malloc.h"
-#include "textflag.h"
-
-enum
-{
-	ENOMEM = 12,
-};
-
-#pragma textflag NOSPLIT
-void*
-runtime·sysAlloc(uintptr n, uint64 *stat)
-{
-	void *v;
-
-	v = runtime·mmap(nil, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
-	if(v < (void*)4096)
-		return nil;
-	runtime·xadd64(stat, n);
-	return v;
-}
-
-void
-runtime·SysUnused(void *v, uintptr n)
-{
-	runtime·madvise(v, n, MADV_FREE);
-}
-
-void
-runtime·SysUsed(void *v, uintptr n)
-{
-	USED(v);
-	USED(n);
-}
-
-void
-runtime·SysFree(void *v, uintptr n, uint64 *stat)
-{
-	runtime·xadd64(stat, -(uint64)n);
-	runtime·munmap(v, n);
-}
-
-void
-runtime·SysFault(void *v, uintptr n)
-{
-	runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
-}
-
-void*
-runtime·SysReserve(void *v, uintptr n, bool *reserved)
-{
-	void *p;
-
-	// On 64-bit, people with ulimit -v set complain if we reserve too
-	// much address space.  Instead, assume that the reservation is okay
-	// and check the assumption in SysMap.
-	if(sizeof(void*) == 8 && n > 1LL<<32) {
-		*reserved = false;
-		return v;
-	}
-
-	*reserved = true;
-	p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
-	if(p < (void*)4096)
-		return nil;
-	return p;
-}
-
-void
-runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
-{
-	void *p;
-	
-	runtime·xadd64(stat, n);
-
-	// On 64-bit, we don't actually have v reserved, so tread carefully.
-	if(!reserved) {
-		// TODO(jsing): For some reason DragonFly seems to return
-		// memory at a different address than we requested, even when
-		// there should be no reason for it to do so. This can be
-		// avoided by using MAP_FIXED, but I'm not sure we should need
-		// to do this - we do not on other platforms.
-		p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
-		if(p == (void*)ENOMEM)
-			runtime·throw("runtime: out of memory");
-		if(p != v) {
-			runtime·printf("runtime: address space conflict: map(%p) = %p\n", v, p);
-			runtime·throw("runtime: address space conflict");
-		}
-		return;
-	}
-
-	p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
-	if(p == (void*)ENOMEM)
-		runtime·throw("runtime: out of memory");
-	if(p != v)
-		runtime·throw("runtime: cannot map pages in arena address space");
-}
diff --git a/src/runtime/mem_freebsd.c b/src/runtime/mem_freebsd.c
deleted file mode 100644
index 18a9a2f..0000000
--- a/src/runtime/mem_freebsd.c
+++ /dev/null
@@ -1,100 +0,0 @@
-// Copyright 2010 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 "runtime.h"
-#include "arch_GOARCH.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "malloc.h"
-#include "textflag.h"
-
-enum
-{
-	ENOMEM = 12,
-};
-
-#pragma textflag NOSPLIT
-void*
-runtime·sysAlloc(uintptr n, uint64 *stat)
-{
-	void *v;
-
-	v = runtime·mmap(nil, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
-	if(v < (void*)4096)
-		return nil;
-	runtime·xadd64(stat, n);
-	return v;
-}
-
-void
-runtime·SysUnused(void *v, uintptr n)
-{
-	runtime·madvise(v, n, MADV_FREE);
-}
-
-void
-runtime·SysUsed(void *v, uintptr n)
-{
-	USED(v);
-	USED(n);
-}
-
-void
-runtime·SysFree(void *v, uintptr n, uint64 *stat)
-{
-	runtime·xadd64(stat, -(uint64)n);
-	runtime·munmap(v, n);
-}
-
-void
-runtime·SysFault(void *v, uintptr n)
-{
-	runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
-}
-
-void*
-runtime·SysReserve(void *v, uintptr n, bool *reserved)
-{
-	void *p;
-
-	// On 64-bit, people with ulimit -v set complain if we reserve too
-	// much address space.  Instead, assume that the reservation is okay
-	// and check the assumption in SysMap.
-	if(sizeof(void*) == 8 && n > 1LL<<32) {
-		*reserved = false;
-		return v;
-	}
-
-	*reserved = true;
-	p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
-	if(p < (void*)4096)
-		return nil;
-	return p;
-}
-
-void
-runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
-{
-	void *p;
-	
-	runtime·xadd64(stat, n);
-
-	// On 64-bit, we don't actually have v reserved, so tread carefully.
-	if(!reserved) {
-		p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
-		if(p == (void*)ENOMEM)
-			runtime·throw("runtime: out of memory");
-		if(p != v) {
-			runtime·printf("runtime: address space conflict: map(%p) = %p\n", v, p);
-			runtime·throw("runtime: address space conflict");
-		}
-		return;
-	}
-
-	p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
-	if(p == (void*)ENOMEM)
-		runtime·throw("runtime: out of memory");
-	if(p != v)
-		runtime·throw("runtime: cannot map pages in arena address space");
-}
diff --git a/src/runtime/mem_linux.c b/src/runtime/mem_linux.c
deleted file mode 100644
index bfb4056..0000000
--- a/src/runtime/mem_linux.c
+++ /dev/null
@@ -1,162 +0,0 @@
-// Copyright 2010 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 "runtime.h"
-#include "arch_GOARCH.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "malloc.h"
-#include "textflag.h"
-
-enum
-{
-	_PAGE_SIZE = 4096,
-	EACCES = 13,
-};
-
-static int32
-addrspace_free(void *v, uintptr n)
-{
-	int32 errval;
-	uintptr chunk;
-	uintptr off;
-	
-	// NOTE: vec must be just 1 byte long here.
-	// Mincore returns ENOMEM if any of the pages are unmapped,
-	// but we want to know that all of the pages are unmapped.
-	// To make these the same, we can only ask about one page
-	// at a time. See golang.org/issue/7476.
-	static byte vec[1];
-
-	for(off = 0; off < n; off += chunk) {
-		chunk = _PAGE_SIZE * sizeof vec;
-		if(chunk > (n - off))
-			chunk = n - off;
-		errval = runtime·mincore((int8*)v + off, chunk, vec);
-		// ENOMEM means unmapped, which is what we want.
-		// Anything else we assume means the pages are mapped.
-		if (errval != -ENOMEM)
-			return 0;
-	}
-	return 1;
-}
-
-static void *
-mmap_fixed(byte *v, uintptr n, int32 prot, int32 flags, int32 fd, uint32 offset)
-{
-	void *p;
-
-	p = runtime·mmap(v, n, prot, flags, fd, offset);
-	if(p != v && addrspace_free(v, n)) {
-		// On some systems, mmap ignores v without
-		// MAP_FIXED, so retry if the address space is free.
-		if(p > (void*)4096)
-			runtime·munmap(p, n);
-		p = runtime·mmap(v, n, prot, flags|MAP_FIXED, fd, offset);
-	}
-	return p;
-}
-
-#pragma textflag NOSPLIT
-void*
-runtime·sysAlloc(uintptr n, uint64 *stat)
-{
-	void *p;
-
-	p = runtime·mmap(nil, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
-	if(p < (void*)4096) {
-		if(p == (void*)EACCES) {
-			runtime·printf("runtime: mmap: access denied\n");
-			runtime·printf("if you're running SELinux, enable execmem for this process.\n");
-			runtime·exit(2);
-		}
-		if(p == (void*)EAGAIN) {
-			runtime·printf("runtime: mmap: too much locked memory (check 'ulimit -l').\n");
-			runtime·exit(2);
-		}
-		return nil;
-	}
-	runtime·xadd64(stat, n);
-	return p;
-}
-
-void
-runtime·SysUnused(void *v, uintptr n)
-{
-	runtime·madvise(v, n, MADV_DONTNEED);
-}
-
-void
-runtime·SysUsed(void *v, uintptr n)
-{
-	USED(v);
-	USED(n);
-}
-
-void
-runtime·SysFree(void *v, uintptr n, uint64 *stat)
-{
-	runtime·xadd64(stat, -(uint64)n);
-	runtime·munmap(v, n);
-}
-
-void
-runtime·SysFault(void *v, uintptr n)
-{
-	runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
-}
-
-void*
-runtime·SysReserve(void *v, uintptr n, bool *reserved)
-{
-	void *p;
-
-	// On 64-bit, people with ulimit -v set complain if we reserve too
-	// much address space.  Instead, assume that the reservation is okay
-	// if we can reserve at least 64K and check the assumption in SysMap.
-	// Only user-mode Linux (UML) rejects these requests.
-	if(sizeof(void*) == 8 && n > 1LL<<32) {
-		p = mmap_fixed(v, 64<<10, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
-		if (p != v) {
-			if(p >= (void*)4096)
-				runtime·munmap(p, 64<<10);
-			return nil;
-		}
-		runtime·munmap(p, 64<<10);
-		*reserved = false;
-		return v;
-	}
-
-	p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
-	if((uintptr)p < 4096)
-		return nil;
-	*reserved = true;
-	return p;
-}
-
-void
-runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
-{
-	void *p;
-	
-	runtime·xadd64(stat, n);
-
-	// On 64-bit, we don't actually have v reserved, so tread carefully.
-	if(!reserved) {
-		p = mmap_fixed(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
-		if(p == (void*)ENOMEM)
-			runtime·throw("runtime: out of memory");
-		if(p != v) {
-			runtime·printf("runtime: address space conflict: map(%p) = %p\n", v, p);
-			runtime·throw("runtime: address space conflict");
-		}
-		return;
-	}
-
-	p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
-	if(p == (void*)ENOMEM)
-		runtime·throw("runtime: out of memory");
-	if(p != v)
-		runtime·throw("runtime: cannot map pages in arena address space");
-}
diff --git a/src/runtime/mem_linux.go b/src/runtime/mem_linux.go
new file mode 100644
index 0000000..f988e75
--- /dev/null
+++ b/src/runtime/mem_linux.go
@@ -0,0 +1,159 @@
+// Copyright 2010 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"
+
+const (
+	_PAGE_SIZE = _PhysPageSize
+	_EACCES    = 13
+)
+
+// NOTE: vec must be just 1 byte long here.
+// Mincore returns ENOMEM if any of the pages are unmapped,
+// but we want to know that all of the pages are unmapped.
+// To make these the same, we can only ask about one page
+// at a time. See golang.org/issue/7476.
+var addrspace_vec [1]byte
+
+func addrspace_free(v unsafe.Pointer, n uintptr) bool {
+	var chunk uintptr
+	for off := uintptr(0); off < n; off += chunk {
+		chunk = _PAGE_SIZE * uintptr(len(addrspace_vec))
+		if chunk > (n - off) {
+			chunk = n - off
+		}
+		errval := mincore(unsafe.Pointer(uintptr(v)+off), chunk, &addrspace_vec[0])
+		// ENOMEM means unmapped, which is what we want.
+		// Anything else we assume means the pages are mapped.
+		if errval != -_ENOMEM {
+			return false
+		}
+	}
+	return true
+}
+
+func mmap_fixed(v unsafe.Pointer, n uintptr, prot, flags, fd int32, offset uint32) unsafe.Pointer {
+	p := mmap(v, n, prot, flags, fd, offset)
+	// On some systems, mmap ignores v without
+	// MAP_FIXED, so retry if the address space is free.
+	if p != v && addrspace_free(v, n) {
+		if uintptr(p) > 4096 {
+			munmap(p, n)
+		}
+		p = mmap(v, n, prot, flags|_MAP_FIXED, fd, offset)
+	}
+	return p
+}
+
+// Don't split the stack as this method may be invoked without a valid G, which
+// prevents us from allocating more stack.
+//go:nosplit
+func sysAlloc(n uintptr, sysStat *uint64) unsafe.Pointer {
+	p := mmap(nil, n, _PROT_READ|_PROT_WRITE, _MAP_ANON|_MAP_PRIVATE, -1, 0)
+	if uintptr(p) < 4096 {
+		if uintptr(p) == _EACCES {
+			print("runtime: mmap: access denied\n")
+			exit(2)
+		}
+		if uintptr(p) == _EAGAIN {
+			print("runtime: mmap: too much locked memory (check 'ulimit -l').\n")
+			exit(2)
+		}
+		return nil
+	}
+	mSysStatInc(sysStat, n)
+	return p
+}
+
+func sysUnused(v unsafe.Pointer, n uintptr) {
+	var s uintptr = hugePageSize // division by constant 0 is a compile-time error :(
+	if s != 0 && (uintptr(v)%s != 0 || n%s != 0) {
+		// See issue 8832
+		// Linux kernel bug: https://bugzilla.kernel.org/show_bug.cgi?id=93111
+		// Mark the region as NOHUGEPAGE so the kernel's khugepaged
+		// doesn't undo our DONTNEED request.  khugepaged likes to migrate
+		// regions which are only partially mapped to huge pages, including
+		// regions with some DONTNEED marks.  That needlessly allocates physical
+		// memory for our DONTNEED regions.
+		madvise(v, n, _MADV_NOHUGEPAGE)
+	}
+	madvise(v, n, _MADV_DONTNEED)
+}
+
+func sysUsed(v unsafe.Pointer, n uintptr) {
+	if hugePageSize != 0 {
+		// Undo the NOHUGEPAGE marks from sysUnused.  There is no alignment check
+		// around this call as spans may have been merged in the interim.
+		// Note that this might enable huge pages for regions which were
+		// previously disabled.  Unfortunately there is no easy way to detect
+		// what the previous state was, and in any case we probably want huge
+		// pages to back our heap if the kernel can arrange that.
+		madvise(v, n, _MADV_HUGEPAGE)
+	}
+}
+
+// Don't split the stack as this function may be invoked without a valid G,
+// which prevents us from allocating more stack.
+//go:nosplit
+func sysFree(v unsafe.Pointer, n uintptr, sysStat *uint64) {
+	mSysStatDec(sysStat, n)
+	munmap(v, n)
+}
+
+func sysFault(v unsafe.Pointer, n uintptr) {
+	mmap(v, n, _PROT_NONE, _MAP_ANON|_MAP_PRIVATE|_MAP_FIXED, -1, 0)
+}
+
+func sysReserve(v unsafe.Pointer, n uintptr, reserved *bool) unsafe.Pointer {
+	// On 64-bit, people with ulimit -v set complain if we reserve too
+	// much address space.  Instead, assume that the reservation is okay
+	// if we can reserve at least 64K and check the assumption in SysMap.
+	// Only user-mode Linux (UML) rejects these requests.
+	if ptrSize == 8 && uint64(n) > 1<<32 {
+		p := mmap_fixed(v, 64<<10, _PROT_NONE, _MAP_ANON|_MAP_PRIVATE, -1, 0)
+		if p != v {
+			if uintptr(p) >= 4096 {
+				munmap(p, 64<<10)
+			}
+			return nil
+		}
+		munmap(p, 64<<10)
+		*reserved = false
+		return v
+	}
+
+	p := mmap(v, n, _PROT_NONE, _MAP_ANON|_MAP_PRIVATE, -1, 0)
+	if uintptr(p) < 4096 {
+		return nil
+	}
+	*reserved = true
+	return p
+}
+
+func sysMap(v unsafe.Pointer, n uintptr, reserved bool, sysStat *uint64) {
+	mSysStatInc(sysStat, n)
+
+	// On 64-bit, we don't actually have v reserved, so tread carefully.
+	if !reserved {
+		p := mmap_fixed(v, n, _PROT_READ|_PROT_WRITE, _MAP_ANON|_MAP_PRIVATE, -1, 0)
+		if uintptr(p) == _ENOMEM {
+			throw("runtime: out of memory")
+		}
+		if p != v {
+			print("runtime: address space conflict: map(", v, ") = ", p, "\n")
+			throw("runtime: address space conflict")
+		}
+		return
+	}
+
+	p := mmap(v, n, _PROT_READ|_PROT_WRITE, _MAP_ANON|_MAP_FIXED|_MAP_PRIVATE, -1, 0)
+	if uintptr(p) == _ENOMEM {
+		throw("runtime: out of memory")
+	}
+	if p != v {
+		throw("runtime: cannot map pages in arena address space")
+	}
+}
diff --git a/src/runtime/mem_nacl.c b/src/runtime/mem_nacl.c
deleted file mode 100644
index 6c836f1..0000000
--- a/src/runtime/mem_nacl.c
+++ /dev/null
@@ -1,120 +0,0 @@
-// Copyright 2010 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 "runtime.h"
-#include "arch_GOARCH.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "malloc.h"
-#include "textflag.h"
-
-enum
-{
-	Debug = 0,
-};
-
-#pragma textflag NOSPLIT
-void*
-runtime·sysAlloc(uintptr n, uint64 *stat)
-{
-	void *v;
-
-	v = runtime·mmap(nil, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
-	if(v < (void*)4096) {
-		if(Debug)
-			runtime·printf("sysAlloc(%p): %p\n", n, v);
-		return nil;
-	}
-	runtime·xadd64(stat, n);
-	if(Debug)
-		runtime·printf("sysAlloc(%p) = %p\n", n, v);
-	return v;
-}
-
-void
-runtime·SysUnused(void *v, uintptr n)
-{
-	if(Debug)
-		runtime·printf("SysUnused(%p, %p)\n", v, n);
-}
-
-void
-runtime·SysUsed(void *v, uintptr n)
-{
-	USED(v);
-	USED(n);
-}
-
-void
-runtime·SysFree(void *v, uintptr n, uint64 *stat)
-{
-	if(Debug)
-		runtime·printf("SysFree(%p, %p)\n", v, n);
-	runtime·xadd64(stat, -(uint64)n);
-	runtime·munmap(v, n);
-}
-
-void
-runtime·SysFault(void *v, uintptr n)
-{
-	runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
-}
-
-void*
-runtime·SysReserve(void *v, uintptr n, bool *reserved)
-{
-	void *p;
-
-	// On 64-bit, people with ulimit -v set complain if we reserve too
-	// much address space.  Instead, assume that the reservation is okay
-	// and check the assumption in SysMap.
-	if(NaCl || sizeof(void*) == 8) {
-		*reserved = false;
-		return v;
-	}
-	
-	p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
-	if(p < (void*)4096)
-		return nil;
-	*reserved = true;
-	return p;
-}
-
-void
-runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
-{
-	void *p;
-	
-	runtime·xadd64(stat, n);
-
-	// On 64-bit, we don't actually have v reserved, so tread carefully.
-	if(!reserved) {
-		p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
-		if(p == (void*)ENOMEM) {
-			runtime·printf("SysMap(%p, %p): %p\n", v, n, p);
-			runtime·throw("runtime: out of memory");
-		}
-		if(p != v) {
-			runtime·printf("SysMap(%p, %p): %p\n", v, n, p);
-			runtime·printf("runtime: address space conflict: map(%p) = %p\n", v, p);
-			runtime·throw("runtime: address space conflict");
-		}
-		if(Debug)
-			runtime·printf("SysMap(%p, %p) = %p\n", v, n, p);
-		return;
-	}
-
-	p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
-	if(p == (void*)ENOMEM) {
-		runtime·printf("SysMap(%p, %p): %p\n", v, n, p);
-		runtime·throw("runtime: out of memory");
-	}
-	if(p != v) {
-		runtime·printf("SysMap(%p, %p): %p\n", v, n, p);
-		runtime·printf("mmap MAP_FIXED %p returned %p\n", v, p);
-		runtime·throw("runtime: cannot map pages in arena address space");
-	}
-	if(Debug)
-		runtime·printf("SysMap(%p, %p) = %p\n", v, n, p);
-}
diff --git a/src/runtime/mem_netbsd.c b/src/runtime/mem_netbsd.c
deleted file mode 100644
index 31820e5..0000000
--- a/src/runtime/mem_netbsd.c
+++ /dev/null
@@ -1,100 +0,0 @@
-// Copyright 2010 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 "runtime.h"
-#include "arch_GOARCH.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "malloc.h"
-#include "textflag.h"
-
-enum
-{
-	ENOMEM = 12,
-};
-
-#pragma textflag NOSPLIT
-void*
-runtime·sysAlloc(uintptr n, uint64 *stat)
-{
-	void *v;
-
-	v = runtime·mmap(nil, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
-	if(v < (void*)4096)
-		return nil;
-	runtime·xadd64(stat, n);
-	return v;
-}
-
-void
-runtime·SysUnused(void *v, uintptr n)
-{
-	runtime·madvise(v, n, MADV_FREE);
-}
-
-void
-runtime·SysUsed(void *v, uintptr n)
-{
-	USED(v);
-	USED(n);
-}
-
-void
-runtime·SysFree(void *v, uintptr n, uint64 *stat)
-{
-	runtime·xadd64(stat, -(uint64)n);
-	runtime·munmap(v, n);
-}
-
-void
-runtime·SysFault(void *v, uintptr n)
-{
-	runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
-}
-
-void*
-runtime·SysReserve(void *v, uintptr n, bool *reserved)
-{
-	void *p;
-
-	// On 64-bit, people with ulimit -v set complain if we reserve too
-	// much address space.  Instead, assume that the reservation is okay
-	// and check the assumption in SysMap.
-	if(sizeof(void*) == 8 && n > 1LL<<32) {
-		*reserved = false;
-		return v;
-	}
-
-	p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
-	if(p < (void*)4096)
-		return nil;
-	*reserved = true;
-	return p;
-}
-
-void
-runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
-{
-	void *p;
-	
-	runtime·xadd64(stat, n);
-
-	// On 64-bit, we don't actually have v reserved, so tread carefully.
-	if(!reserved) {
-		p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
-		if(p == (void*)ENOMEM)
-			runtime·throw("runtime: out of memory");
-		if(p != v) {
-			runtime·printf("runtime: address space conflict: map(%p) = %p\n", v, p);
-			runtime·throw("runtime: address space conflict");
-		}
-		return;
-	}
-
-	p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
-	if(p == (void*)ENOMEM)
-		runtime·throw("runtime: out of memory");
-	if(p != v)
-		runtime·throw("runtime: cannot map pages in arena address space");
-}
diff --git a/src/runtime/mem_openbsd.c b/src/runtime/mem_openbsd.c
deleted file mode 100644
index 31820e5..0000000
--- a/src/runtime/mem_openbsd.c
+++ /dev/null
@@ -1,100 +0,0 @@
-// Copyright 2010 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 "runtime.h"
-#include "arch_GOARCH.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "malloc.h"
-#include "textflag.h"
-
-enum
-{
-	ENOMEM = 12,
-};
-
-#pragma textflag NOSPLIT
-void*
-runtime·sysAlloc(uintptr n, uint64 *stat)
-{
-	void *v;
-
-	v = runtime·mmap(nil, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
-	if(v < (void*)4096)
-		return nil;
-	runtime·xadd64(stat, n);
-	return v;
-}
-
-void
-runtime·SysUnused(void *v, uintptr n)
-{
-	runtime·madvise(v, n, MADV_FREE);
-}
-
-void
-runtime·SysUsed(void *v, uintptr n)
-{
-	USED(v);
-	USED(n);
-}
-
-void
-runtime·SysFree(void *v, uintptr n, uint64 *stat)
-{
-	runtime·xadd64(stat, -(uint64)n);
-	runtime·munmap(v, n);
-}
-
-void
-runtime·SysFault(void *v, uintptr n)
-{
-	runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
-}
-
-void*
-runtime·SysReserve(void *v, uintptr n, bool *reserved)
-{
-	void *p;
-
-	// On 64-bit, people with ulimit -v set complain if we reserve too
-	// much address space.  Instead, assume that the reservation is okay
-	// and check the assumption in SysMap.
-	if(sizeof(void*) == 8 && n > 1LL<<32) {
-		*reserved = false;
-		return v;
-	}
-
-	p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
-	if(p < (void*)4096)
-		return nil;
-	*reserved = true;
-	return p;
-}
-
-void
-runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
-{
-	void *p;
-	
-	runtime·xadd64(stat, n);
-
-	// On 64-bit, we don't actually have v reserved, so tread carefully.
-	if(!reserved) {
-		p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
-		if(p == (void*)ENOMEM)
-			runtime·throw("runtime: out of memory");
-		if(p != v) {
-			runtime·printf("runtime: address space conflict: map(%p) = %p\n", v, p);
-			runtime·throw("runtime: address space conflict");
-		}
-		return;
-	}
-
-	p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
-	if(p == (void*)ENOMEM)
-		runtime·throw("runtime: out of memory");
-	if(p != v)
-		runtime·throw("runtime: cannot map pages in arena address space");
-}
diff --git a/src/runtime/mem_plan9.c b/src/runtime/mem_plan9.c
deleted file mode 100644
index d673d6f..0000000
--- a/src/runtime/mem_plan9.c
+++ /dev/null
@@ -1,121 +0,0 @@
-// Copyright 2010 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 "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "arch_GOARCH.h"
-#include "malloc.h"
-#include "os_GOOS.h"
-#include "textflag.h"
-
-extern byte runtime·end[];
-#pragma dataflag NOPTR
-static byte *bloc = { runtime·end };
-static Mutex memlock;
-
-enum
-{
-	Round = PAGESIZE-1
-};
-
-static void*
-brk(uintptr nbytes)
-{
-	uintptr bl;
-
-	runtime·lock(&memlock);
-	// Plan 9 sbrk from /sys/src/libc/9sys/sbrk.c
-	bl = ((uintptr)bloc + Round) & ~Round;
-	if(runtime·brk_((void*)(bl + nbytes)) < 0) {
-		runtime·unlock(&memlock);
-		return nil;
-	}
-	bloc = (byte*)bl + nbytes;
-	runtime·unlock(&memlock);
-	return (void*)bl;	
-}
-
-static void
-sysalloc(void)
-{
-	uintptr nbytes;
-	uint64 *stat;
-	void *p;
-
-	nbytes = g->m->scalararg[0];
-	stat = g->m->ptrarg[0];
-	g->m->scalararg[0] = 0;
-	g->m->ptrarg[0] = nil;
-
-	p = brk(nbytes);
-	if(p != nil)
-		runtime·xadd64(stat, nbytes);
-
-	g->m->ptrarg[0] = p;
-}
-
-#pragma textflag NOSPLIT
-void*
-runtime·sysAlloc(uintptr nbytes, uint64 *stat)
-{
-	void (*fn)(void);
-	void *p;
-
-	g->m->scalararg[0] = nbytes;
-	g->m->ptrarg[0] = stat;
-	fn = sysalloc;
-	runtime·onM(&fn);
-	p = g->m->ptrarg[0];
-	g->m->ptrarg[0] = nil;
-	return p;
-}
-
-void
-runtime·SysFree(void *v, uintptr nbytes, uint64 *stat)
-{
-	runtime·xadd64(stat, -(uint64)nbytes);
-	runtime·lock(&memlock);
-	// from tiny/mem.c
-	// Push pointer back if this is a free
-	// of the most recent sysAlloc.
-	nbytes += (nbytes + Round) & ~Round;
-	if(bloc == (byte*)v+nbytes)
-		bloc -= nbytes;
-	runtime·unlock(&memlock);
-}
-
-void
-runtime·SysUnused(void *v, uintptr nbytes)
-{
-	USED(v, nbytes);
-}
-
-void
-runtime·SysUsed(void *v, uintptr nbytes)
-{
-	USED(v, nbytes);
-}
-
-void
-runtime·SysMap(void *v, uintptr nbytes, bool reserved, uint64 *stat)
-{
-	// SysReserve has already allocated all heap memory,
-	// but has not adjusted stats.
-	USED(v, reserved);
-	runtime·xadd64(stat, nbytes);
-}
-
-void
-runtime·SysFault(void *v, uintptr nbytes)
-{
-	USED(v, nbytes);
-}
-
-void*
-runtime·SysReserve(void *v, uintptr nbytes, bool *reserved)
-{
-	USED(v);
-	*reserved = true;
-	return brk(nbytes);
-}
diff --git a/src/runtime/mem_plan9.go b/src/runtime/mem_plan9.go
new file mode 100644
index 0000000..755887f
--- /dev/null
+++ b/src/runtime/mem_plan9.go
@@ -0,0 +1,174 @@
+// Copyright 2010 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"
+
+const memDebug = false
+
+var bloc uintptr
+var memlock mutex
+
+type memHdr struct {
+	next *memHdr
+	size uintptr
+}
+
+var memFreelist *memHdr // sorted in ascending order
+
+func memAlloc(n uintptr) unsafe.Pointer {
+	n = memRound(n)
+	var prevp *memHdr
+	for p := memFreelist; p != nil; p = p.next {
+		if p.size >= n {
+			if p.size == n {
+				if prevp != nil {
+					prevp.next = p.next
+				} else {
+					memFreelist = p.next
+				}
+			} else {
+				p.size -= n
+				p = (*memHdr)(add(unsafe.Pointer(p), p.size))
+			}
+			memclr(unsafe.Pointer(p), unsafe.Sizeof(memHdr{}))
+			return unsafe.Pointer(p)
+		}
+		prevp = p
+	}
+	return sbrk(n)
+}
+
+func memFree(ap unsafe.Pointer, n uintptr) {
+	n = memRound(n)
+	memclr(ap, n)
+	bp := (*memHdr)(ap)
+	bp.size = n
+	bpn := uintptr(ap)
+	if memFreelist == nil {
+		bp.next = nil
+		memFreelist = bp
+		return
+	}
+	p := memFreelist
+	if bpn < uintptr(unsafe.Pointer(p)) {
+		memFreelist = bp
+		if bpn+bp.size == uintptr(unsafe.Pointer(p)) {
+			bp.size += p.size
+			bp.next = p.next
+			memclr(unsafe.Pointer(p), unsafe.Sizeof(memHdr{}))
+		} else {
+			bp.next = p
+		}
+		return
+	}
+	for ; p.next != nil; p = p.next {
+		if bpn > uintptr(unsafe.Pointer(p)) && bpn < uintptr(unsafe.Pointer(p.next)) {
+			break
+		}
+	}
+	if bpn+bp.size == uintptr(unsafe.Pointer(p.next)) {
+		bp.size += p.next.size
+		bp.next = p.next.next
+		memclr(unsafe.Pointer(p.next), unsafe.Sizeof(memHdr{}))
+	} else {
+		bp.next = p.next
+	}
+	if uintptr(unsafe.Pointer(p))+p.size == bpn {
+		p.size += bp.size
+		p.next = bp.next
+		memclr(unsafe.Pointer(bp), unsafe.Sizeof(memHdr{}))
+	} else {
+		p.next = bp
+	}
+}
+
+func memCheck() {
+	if memDebug == false {
+		return
+	}
+	for p := memFreelist; p != nil && p.next != nil; p = p.next {
+		if uintptr(unsafe.Pointer(p)) == uintptr(unsafe.Pointer(p.next)) {
+			print("runtime: ", unsafe.Pointer(p), " == ", unsafe.Pointer(p.next), "\n")
+			throw("mem: infinite loop")
+		}
+		if uintptr(unsafe.Pointer(p)) > uintptr(unsafe.Pointer(p.next)) {
+			print("runtime: ", unsafe.Pointer(p), " > ", unsafe.Pointer(p.next), "\n")
+			throw("mem: unordered list")
+		}
+		if uintptr(unsafe.Pointer(p))+p.size > uintptr(unsafe.Pointer(p.next)) {
+			print("runtime: ", unsafe.Pointer(p), "+", p.size, " > ", unsafe.Pointer(p.next), "\n")
+			throw("mem: overlapping blocks")
+		}
+		for b := add(unsafe.Pointer(p), unsafe.Sizeof(memHdr{})); uintptr(b) < uintptr(unsafe.Pointer(p))+p.size; b = add(b, 1) {
+			if *(*byte)(b) != 0 {
+				print("runtime: value at addr ", b, " with offset ", uintptr(b)-uintptr(unsafe.Pointer(p)), " in block ", p, " of size ", p.size, " is not zero\n")
+				throw("mem: uninitialised memory")
+			}
+		}
+	}
+}
+
+func memRound(p uintptr) uintptr {
+	return (p + _PAGESIZE - 1) &^ (_PAGESIZE - 1)
+}
+
+func initBloc() {
+	bloc = memRound(firstmoduledata.end)
+}
+
+func sbrk(n uintptr) unsafe.Pointer {
+	// Plan 9 sbrk from /sys/src/libc/9sys/sbrk.c
+	bl := bloc
+	n = memRound(n)
+	if brk_(unsafe.Pointer(bl+n)) < 0 {
+		return nil
+	}
+	bloc += n
+	return unsafe.Pointer(bl)
+}
+
+func sysAlloc(n uintptr, sysStat *uint64) unsafe.Pointer {
+	lock(&memlock)
+	p := memAlloc(n)
+	memCheck()
+	unlock(&memlock)
+	if p != nil {
+		mSysStatInc(sysStat, n)
+	}
+	return p
+}
+
+func sysFree(v unsafe.Pointer, n uintptr, sysStat *uint64) {
+	mSysStatDec(sysStat, n)
+	lock(&memlock)
+	memFree(v, n)
+	memCheck()
+	unlock(&memlock)
+}
+
+func sysUnused(v unsafe.Pointer, n uintptr) {
+}
+
+func sysUsed(v unsafe.Pointer, n uintptr) {
+}
+
+func sysMap(v unsafe.Pointer, n uintptr, reserved bool, sysStat *uint64) {
+	// sysReserve has already allocated all heap memory,
+	// but has not adjusted stats.
+	mSysStatInc(sysStat, n)
+}
+
+func sysFault(v unsafe.Pointer, n uintptr) {
+}
+
+func sysReserve(v unsafe.Pointer, n uintptr, reserved *bool) unsafe.Pointer {
+	*reserved = true
+	lock(&memlock)
+	p := memAlloc(n)
+	memCheck()
+	unlock(&memlock)
+	return p
+}
diff --git a/src/runtime/mem_solaris.c b/src/runtime/mem_solaris.c
deleted file mode 100644
index 8e90ba1..0000000
--- a/src/runtime/mem_solaris.c
+++ /dev/null
@@ -1,101 +0,0 @@
-// Copyright 2010 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 "runtime.h"
-#include "arch_GOARCH.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "malloc.h"
-#include "textflag.h"
-
-enum
-{
-	ENOMEM = 12,
-};
-
-#pragma textflag NOSPLIT
-void*
-runtime·sysAlloc(uintptr n, uint64 *stat)
-{
-	void *v;
-
-	v = runtime·mmap(nil, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
-	if(v < (void*)4096)
-		return nil;
-	runtime·xadd64(stat, n);
-	return v;
-}
-
-void
-runtime·SysUnused(void *v, uintptr n)
-{
-	USED(v);
-	USED(n);
-}
-
-void
-runtime·SysUsed(void *v, uintptr n)
-{
-	USED(v);
-	USED(n);
-}
-
-void
-runtime·SysFree(void *v, uintptr n, uint64 *stat)
-{
-	runtime·xadd64(stat, -(uint64)n);
-	runtime·munmap(v, n);
-}
-
-void
-runtime·SysFault(void *v, uintptr n)
-{
-	runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0);
-}
-
-void*
-runtime·SysReserve(void *v, uintptr n, bool *reserved)
-{
-	void *p;
-
-	// On 64-bit, people with ulimit -v set complain if we reserve too
-	// much address space.  Instead, assume that the reservation is okay
-	// and check the assumption in SysMap.
-	if(sizeof(void*) == 8 && n > 1LL<<32) {
-		*reserved = false;
-		return v;
-	}
-	
-	p = runtime·mmap(v, n, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
-	if(p < (void*)4096)
-		return nil;
-	*reserved = true;
-	return p;
-}
-
-void
-runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
-{
-	void *p;
-	
-	runtime·xadd64(stat, n);
-
-	// On 64-bit, we don't actually have v reserved, so tread carefully.
-	if(!reserved) {
-		p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
-		if(p == (void*)ENOMEM)
-			runtime·throw("runtime: out of memory");
-		if(p != v) {
-			runtime·printf("runtime: address space conflict: map(%p) = %p\n", v, p);
-			runtime·throw("runtime: address space conflict");
-		}
-		return;
-	}
-
-	p = runtime·mmap(v, n, PROT_READ|PROT_WRITE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0);
-	if(p == (void*)ENOMEM)
-		runtime·throw("runtime: out of memory");
-	if(p != v)
-		runtime·throw("runtime: cannot map pages in arena address space");
-}
diff --git a/src/runtime/mem_windows.c b/src/runtime/mem_windows.c
deleted file mode 100644
index 6ea9920..0000000
--- a/src/runtime/mem_windows.c
+++ /dev/null
@@ -1,132 +0,0 @@
-// Copyright 2010 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 "runtime.h"
-#include "arch_GOARCH.h"
-#include "os_GOOS.h"
-#include "defs_GOOS_GOARCH.h"
-#include "malloc.h"
-#include "textflag.h"
-
-enum {
-	MEM_COMMIT = 0x1000,
-	MEM_RESERVE = 0x2000,
-	MEM_DECOMMIT = 0x4000,
-	MEM_RELEASE = 0x8000,
-	
-	PAGE_READWRITE = 0x0004,
-	PAGE_NOACCESS = 0x0001,
-};
-
-#pragma dynimport runtime·VirtualAlloc VirtualAlloc "kernel32.dll"
-#pragma dynimport runtime·VirtualFree VirtualFree "kernel32.dll"
-#pragma dynimport runtime·VirtualProtect VirtualProtect "kernel32.dll"
-extern void *runtime·VirtualAlloc;
-extern void *runtime·VirtualFree;
-extern void *runtime·VirtualProtect;
-
-#pragma textflag NOSPLIT
-void*
-runtime·sysAlloc(uintptr n, uint64 *stat)
-{
-	runtime·xadd64(stat, n);
-	return runtime·stdcall4(runtime·VirtualAlloc, 0, n, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE);
-}
-
-void
-runtime·SysUnused(void *v, uintptr n)
-{
-	void *r;
-	uintptr small;
-
-	r = runtime·stdcall3(runtime·VirtualFree, (uintptr)v, n, MEM_DECOMMIT);
-	if(r != nil)
-		return;
-
-	// Decommit failed. Usual reason is that we've merged memory from two different
-	// VirtualAlloc calls, and Windows will only let each VirtualFree handle pages from
-	// a single VirtualAlloc. It is okay to specify a subset of the pages from a single alloc,
-	// just not pages from multiple allocs. This is a rare case, arising only when we're
-	// trying to give memory back to the operating system, which happens on a time
-	// scale of minutes. It doesn't have to be terribly fast. Instead of extra bookkeeping
-	// on all our VirtualAlloc calls, try freeing successively smaller pieces until
-	// we manage to free something, and then repeat. This ends up being O(n log n)
-	// in the worst case, but that's fast enough.
-	while(n > 0) {
-		small = n;
-		while(small >= 4096 && runtime·stdcall3(runtime·VirtualFree, (uintptr)v, small, MEM_DECOMMIT) == nil)
-			small = (small / 2) & ~(4096-1);
-		if(small < 4096)
-			runtime·throw("runtime: failed to decommit pages");
-		v = (byte*)v + small;
-		n -= small;
-	}
-}
-
-void
-runtime·SysUsed(void *v, uintptr n)
-{
-	void *r;
-	uintptr small;
-
-	r = runtime·stdcall4(runtime·VirtualAlloc, (uintptr)v, n, MEM_COMMIT, PAGE_READWRITE);
-	if(r != v)
-		runtime·throw("runtime: failed to commit pages");
-
-	// Commit failed. See SysUnused.
-	while(n > 0) {
-		small = n;
-		while(small >= 4096 && runtime·stdcall4(runtime·VirtualAlloc, (uintptr)v, small, MEM_COMMIT, PAGE_READWRITE) == nil)
-			small = (small / 2) & ~(4096-1);
-		if(small < 4096)
-			runtime·throw("runtime: failed to decommit pages");
-		v = (byte*)v + small;
-		n -= small;
-	}
-}
-
-void
-runtime·SysFree(void *v, uintptr n, uint64 *stat)
-{
-	uintptr r;
-
-	runtime·xadd64(stat, -(uint64)n);
-	r = (uintptr)runtime·stdcall3(runtime·VirtualFree, (uintptr)v, 0, MEM_RELEASE);
-	if(r == 0)
-		runtime·throw("runtime: failed to release pages");
-}
-
-void
-runtime·SysFault(void *v, uintptr n)
-{
-	// SysUnused makes the memory inaccessible and prevents its reuse
-	runtime·SysUnused(v, n);
-}
-
-void*
-runtime·SysReserve(void *v, uintptr n, bool *reserved)
-{
-	*reserved = true;
-	// v is just a hint.
-	// First try at v.
-	v = runtime·stdcall4(runtime·VirtualAlloc, (uintptr)v, n, MEM_RESERVE, PAGE_READWRITE);
-	if(v != nil)
-		return v;
-	
-	// Next let the kernel choose the address.
-	return runtime·stdcall4(runtime·VirtualAlloc, 0, n, MEM_RESERVE, PAGE_READWRITE);
-}
-
-void
-runtime·SysMap(void *v, uintptr n, bool reserved, uint64 *stat)
-{
-	void *p;
-
-	USED(reserved);
-
-	runtime·xadd64(stat, n);
-	p = runtime·stdcall4(runtime·VirtualAlloc, (uintptr)v, n, MEM_COMMIT, PAGE_READWRITE);
-	if(p != v)
-		runtime·throw("runtime: cannot map pages in arena address space");
-}
diff --git a/src/runtime/mem_windows.go b/src/runtime/mem_windows.go
new file mode 100644
index 0000000..42aa7fb
--- /dev/null
+++ b/src/runtime/mem_windows.go
@@ -0,0 +1,114 @@
+// Copyright 2010 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"
+)
+
+const (
+	_MEM_COMMIT   = 0x1000
+	_MEM_RESERVE  = 0x2000
+	_MEM_DECOMMIT = 0x4000
+	_MEM_RELEASE  = 0x8000
+
+	_PAGE_READWRITE = 0x0004
+	_PAGE_NOACCESS  = 0x0001
+)
+
+// Don't split the stack as this function may be invoked without a valid G,
+// which prevents us from allocating more stack.
+//go:nosplit
+func sysAlloc(n uintptr, sysStat *uint64) unsafe.Pointer {
+	mSysStatInc(sysStat, n)
+	return unsafe.Pointer(stdcall4(_VirtualAlloc, 0, n, _MEM_COMMIT|_MEM_RESERVE, _PAGE_READWRITE))
+}
+
+func sysUnused(v unsafe.Pointer, n uintptr) {
+	r := stdcall3(_VirtualFree, uintptr(v), n, _MEM_DECOMMIT)
+	if r != 0 {
+		return
+	}
+
+	// Decommit failed. Usual reason is that we've merged memory from two different
+	// VirtualAlloc calls, and Windows will only let each VirtualFree handle pages from
+	// a single VirtualAlloc. It is okay to specify a subset of the pages from a single alloc,
+	// just not pages from multiple allocs. This is a rare case, arising only when we're
+	// trying to give memory back to the operating system, which happens on a time
+	// scale of minutes. It doesn't have to be terribly fast. Instead of extra bookkeeping
+	// on all our VirtualAlloc calls, try freeing successively smaller pieces until
+	// we manage to free something, and then repeat. This ends up being O(n log n)
+	// in the worst case, but that's fast enough.
+	for n > 0 {
+		small := n
+		for small >= 4096 && stdcall3(_VirtualFree, uintptr(v), small, _MEM_DECOMMIT) == 0 {
+			small /= 2
+			small &^= 4096 - 1
+		}
+		if small < 4096 {
+			throw("runtime: failed to decommit pages")
+		}
+		v = add(v, small)
+		n -= small
+	}
+}
+
+func sysUsed(v unsafe.Pointer, n uintptr) {
+	r := stdcall4(_VirtualAlloc, uintptr(v), n, _MEM_COMMIT, _PAGE_READWRITE)
+	if r != uintptr(v) {
+		throw("runtime: failed to commit pages")
+	}
+
+	// Commit failed. See SysUnused.
+	for n > 0 {
+		small := n
+		for small >= 4096 && stdcall4(_VirtualAlloc, uintptr(v), small, _MEM_COMMIT, _PAGE_READWRITE) == 0 {
+			small /= 2
+			small &^= 4096 - 1
+		}
+		if small < 4096 {
+			throw("runtime: failed to decommit pages")
+		}
+		v = add(v, small)
+		n -= small
+	}
+}
+
+// Don't split the stack as this function may be invoked without a valid G,
+// which prevents us from allocating more stack.
+//go:nosplit
+func sysFree(v unsafe.Pointer, n uintptr, sysStat *uint64) {
+	mSysStatDec(sysStat, n)
+	r := stdcall3(_VirtualFree, uintptr(v), 0, _MEM_RELEASE)
+	if r == 0 {
+		throw("runtime: failed to release pages")
+	}
+}
+
+func sysFault(v unsafe.Pointer, n uintptr) {
+	// SysUnused makes the memory inaccessible and prevents its reuse
+	sysUnused(v, n)
+}
+
+func sysReserve(v unsafe.Pointer, n uintptr, reserved *bool) unsafe.Pointer {
+	*reserved = true
+	// v is just a hint.
+	// First try at v.
+	v = unsafe.Pointer(stdcall4(_VirtualAlloc, uintptr(v), n, _MEM_RESERVE, _PAGE_READWRITE))
+	if v != nil {
+		return v
+	}
+
+	// Next let the kernel choose the address.
+	return unsafe.Pointer(stdcall4(_VirtualAlloc, 0, n, _MEM_RESERVE, _PAGE_READWRITE))
+}
+
+func sysMap(v unsafe.Pointer, n uintptr, reserved bool, sysStat *uint64) {
+	mSysStatInc(sysStat, n)
+	p := stdcall4(_VirtualAlloc, uintptr(v), n, _MEM_COMMIT, _PAGE_READWRITE)
+	if p != uintptr(v) {
+		throw("runtime: cannot map pages in arena address space")
+	}
+}
diff --git a/src/runtime/memclr_386.s b/src/runtime/memclr_386.s
index 1520aea..3f20b69 100644
--- a/src/runtime/memclr_386.s
+++ b/src/runtime/memclr_386.s
@@ -15,31 +15,31 @@ TEXT runtime·memclr(SB), NOSPLIT, $0-8
 	XORL	AX, AX
 
 	// MOVOU seems always faster than REP STOSL.
-clr_tail:
+tail:
 	TESTL	BX, BX
-	JEQ	clr_0
+	JEQ	_0
 	CMPL	BX, $2
-	JBE	clr_1or2
+	JBE	_1or2
 	CMPL	BX, $4
-	JBE	clr_3or4
+	JBE	_3or4
 	CMPL	BX, $8
-	JBE	clr_5through8
+	JBE	_5through8
 	CMPL	BX, $16
-	JBE	clr_9through16
+	JBE	_9through16
 	TESTL	$0x4000000, runtime·cpuid_edx(SB) // check for sse2
 	JEQ	nosse2
 	PXOR	X0, X0
 	CMPL	BX, $32
-	JBE	clr_17through32
+	JBE	_17through32
 	CMPL	BX, $64
-	JBE	clr_33through64
+	JBE	_33through64
 	CMPL	BX, $128
-	JBE	clr_65through128
+	JBE	_65through128
 	CMPL	BX, $256
-	JBE	clr_129through256
+	JBE	_129through256
 	// TODO: use branch table and BSR to make this just a single dispatch
 
-clr_loop:
+loop:
 	MOVOU	X0, 0(DI)
 	MOVOU	X0, 16(DI)
 	MOVOU	X0, 32(DI)
@@ -59,40 +59,40 @@ clr_loop:
 	SUBL	$256, BX
 	ADDL	$256, DI
 	CMPL	BX, $256
-	JAE	clr_loop
-	JMP	clr_tail
+	JAE	loop
+	JMP	tail
 
-clr_1or2:
+_1or2:
 	MOVB	AX, (DI)
 	MOVB	AX, -1(DI)(BX*1)
 	RET
-clr_0:
+_0:
 	RET
-clr_3or4:
+_3or4:
 	MOVW	AX, (DI)
 	MOVW	AX, -2(DI)(BX*1)
 	RET
-clr_5through8:
+_5through8:
 	MOVL	AX, (DI)
 	MOVL	AX, -4(DI)(BX*1)
 	RET
-clr_9through16:
+_9through16:
 	MOVL	AX, (DI)
 	MOVL	AX, 4(DI)
 	MOVL	AX, -8(DI)(BX*1)
 	MOVL	AX, -4(DI)(BX*1)
 	RET
-clr_17through32:
+_17through32:
 	MOVOU	X0, (DI)
 	MOVOU	X0, -16(DI)(BX*1)
 	RET
-clr_33through64:
+_33through64:
 	MOVOU	X0, (DI)
 	MOVOU	X0, 16(DI)
 	MOVOU	X0, -32(DI)(BX*1)
 	MOVOU	X0, -16(DI)(BX*1)
 	RET
-clr_65through128:
+_65through128:
 	MOVOU	X0, (DI)
 	MOVOU	X0, 16(DI)
 	MOVOU	X0, 32(DI)
@@ -102,7 +102,7 @@ clr_65through128:
 	MOVOU	X0, -32(DI)(BX*1)
 	MOVOU	X0, -16(DI)(BX*1)
 	RET
-clr_129through256:
+_129through256:
 	MOVOU	X0, (DI)
 	MOVOU	X0, 16(DI)
 	MOVOU	X0, 32(DI)
@@ -126,5 +126,5 @@ nosse2:
 	REP
 	STOSL
 	ANDL	$3, BX
-	JNE	clr_tail
+	JNE	tail
 	RET
diff --git a/src/runtime/memclr_amd64.s b/src/runtime/memclr_amd64.s
index 94a2c7f..ec24f1d 100644
--- a/src/runtime/memclr_amd64.s
+++ b/src/runtime/memclr_amd64.s
@@ -15,30 +15,30 @@ TEXT runtime·memclr(SB), NOSPLIT, $0-16
 	XORQ	AX, AX
 
 	// MOVOU seems always faster than REP STOSQ.
-clr_tail:
+tail:
 	TESTQ	BX, BX
-	JEQ	clr_0
+	JEQ	_0
 	CMPQ	BX, $2
-	JBE	clr_1or2
+	JBE	_1or2
 	CMPQ	BX, $4
-	JBE	clr_3or4
+	JBE	_3or4
 	CMPQ	BX, $8
-	JBE	clr_5through8
+	JBE	_5through8
 	CMPQ	BX, $16
-	JBE	clr_9through16
+	JBE	_9through16
 	PXOR	X0, X0
 	CMPQ	BX, $32
-	JBE	clr_17through32
+	JBE	_17through32
 	CMPQ	BX, $64
-	JBE	clr_33through64
+	JBE	_33through64
 	CMPQ	BX, $128
-	JBE	clr_65through128
+	JBE	_65through128
 	CMPQ	BX, $256
-	JBE	clr_129through256
+	JBE	_129through256
 	// TODO: use branch table and BSR to make this just a single dispatch
 	// TODO: for really big clears, use MOVNTDQ.
 
-clr_loop:
+loop:
 	MOVOU	X0, 0(DI)
 	MOVOU	X0, 16(DI)
 	MOVOU	X0, 32(DI)
@@ -58,38 +58,38 @@ clr_loop:
 	SUBQ	$256, BX
 	ADDQ	$256, DI
 	CMPQ	BX, $256
-	JAE	clr_loop
-	JMP	clr_tail
+	JAE	loop
+	JMP	tail
 
-clr_1or2:
+_1or2:
 	MOVB	AX, (DI)
 	MOVB	AX, -1(DI)(BX*1)
 	RET
-clr_0:
+_0:
 	RET
-clr_3or4:
+_3or4:
 	MOVW	AX, (DI)
 	MOVW	AX, -2(DI)(BX*1)
 	RET
-clr_5through8:
+_5through8:
 	MOVL	AX, (DI)
 	MOVL	AX, -4(DI)(BX*1)
 	RET
-clr_9through16:
+_9through16:
 	MOVQ	AX, (DI)
 	MOVQ	AX, -8(DI)(BX*1)
 	RET
-clr_17through32:
+_17through32:
 	MOVOU	X0, (DI)
 	MOVOU	X0, -16(DI)(BX*1)
 	RET
-clr_33through64:
+_33through64:
 	MOVOU	X0, (DI)
 	MOVOU	X0, 16(DI)
 	MOVOU	X0, -32(DI)(BX*1)
 	MOVOU	X0, -16(DI)(BX*1)
 	RET
-clr_65through128:
+_65through128:
 	MOVOU	X0, (DI)
 	MOVOU	X0, 16(DI)
 	MOVOU	X0, 32(DI)
@@ -99,7 +99,7 @@ clr_65through128:
 	MOVOU	X0, -32(DI)(BX*1)
 	MOVOU	X0, -16(DI)(BX*1)
 	RET
-clr_129through256:
+_129through256:
 	MOVOU	X0, (DI)
 	MOVOU	X0, 16(DI)
 	MOVOU	X0, 32(DI)
diff --git a/src/runtime/memclr_arm.s b/src/runtime/memclr_arm.s
index 1824d33..8b5fe31 100644
--- a/src/runtime/memclr_arm.s
+++ b/src/runtime/memclr_arm.s
@@ -25,31 +25,31 @@
 
 #include "textflag.h"
 
-TO = 8
-TOE = 11
-N = 12
-TMP = 12				/* N and TMP don't overlap */
+#define TO	R8
+#define TOE	R11
+#define N	R12
+#define TMP	R12				/* N and TMP don't overlap */
 
 TEXT runtime·memclr(SB),NOSPLIT,$0-8
-	MOVW	ptr+0(FP), R(TO)
-	MOVW	n+4(FP), R(N)
-	MOVW	$0, R(0)
+	MOVW	ptr+0(FP), TO
+	MOVW	n+4(FP), N
+	MOVW	$0, R0
 
-	ADD	R(N), R(TO), R(TOE)	/* to end pointer */
+	ADD	N, TO, TOE	/* to end pointer */
 
-	CMP	$4, R(N)		/* need at least 4 bytes to copy */
+	CMP	$4, N		/* need at least 4 bytes to copy */
 	BLT	_1tail
 
 _4align:				/* align on 4 */
-	AND.S	$3, R(TO), R(TMP)
+	AND.S	$3, TO, TMP
 	BEQ	_4aligned
 
-	MOVBU.P	R(0), 1(R(TO))		/* implicit write back */
+	MOVBU.P	R0, 1(TO)		/* implicit write back */
 	B	_4align
 
 _4aligned:
-	SUB	$31, R(TOE), R(TMP)	/* do 32-byte chunks if possible */
-	CMP	R(TMP), R(TO)
+	SUB	$31, TOE, TMP	/* do 32-byte chunks if possible */
+	CMP	TMP, TO
 	BHS	_4tail
 
 	MOVW	R0, R1			/* replicate */
@@ -61,26 +61,26 @@ _4aligned:
 	MOVW	R0, R7
 
 _f32loop:
-	CMP	R(TMP), R(TO)
+	CMP	TMP, TO
 	BHS	_4tail
 
-	MOVM.IA.W [R0-R7], (R(TO))
+	MOVM.IA.W [R0-R7], (TO)
 	B	_f32loop
 
 _4tail:
-	SUB	$3, R(TOE), R(TMP)	/* do remaining words if possible */
+	SUB	$3, TOE, TMP	/* do remaining words if possible */
 _4loop:
-	CMP	R(TMP), R(TO)
+	CMP	TMP, TO
 	BHS	_1tail
 
-	MOVW.P	R(0), 4(R(TO))		/* implicit write back */
+	MOVW.P	R0, 4(TO)		/* implicit write back */
 	B	_4loop
 
 _1tail:
-	CMP	R(TO), R(TOE)
+	CMP	TO, TOE
 	BEQ	_return
 
-	MOVBU.P	R(0), 1(R(TO))		/* implicit write back */
+	MOVBU.P	R0, 1(TO)		/* implicit write back */
 	B	_1tail
 
 _return:
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/memclr_plan9_386.s b/src/runtime/memclr_plan9_386.s
index b4b671f..50f327b 100644
--- a/src/runtime/memclr_plan9_386.s
+++ b/src/runtime/memclr_plan9_386.s
@@ -10,40 +10,40 @@ TEXT runtime·memclr(SB), NOSPLIT, $0-8
 	MOVL	n+4(FP), BX
 	XORL	AX, AX
 
-clr_tail:
+tail:
 	TESTL	BX, BX
-	JEQ	clr_0
+	JEQ	_0
 	CMPL	BX, $2
-	JBE	clr_1or2
+	JBE	_1or2
 	CMPL	BX, $4
-	JBE	clr_3or4
+	JBE	_3or4
 	CMPL	BX, $8
-	JBE	clr_5through8
+	JBE	_5through8
 	CMPL	BX, $16
-	JBE	clr_9through16
+	JBE	_9through16
 	MOVL	BX, CX
 	SHRL	$2, CX
 	REP
 	STOSL
 	ANDL	$3, BX
-	JNE	clr_tail
+	JNE	tail
 	RET
 
-clr_1or2:
+_1or2:
 	MOVB	AX, (DI)
 	MOVB	AX, -1(DI)(BX*1)
 	RET
-clr_0:
+_0:
 	RET
-clr_3or4:
+_3or4:
 	MOVW	AX, (DI)
 	MOVW	AX, -2(DI)(BX*1)
 	RET
-clr_5through8:
+_5through8:
 	MOVL	AX, (DI)
 	MOVL	AX, -4(DI)(BX*1)
 	RET
-clr_9through16:
+_9through16:
 	MOVL	AX, (DI)
 	MOVL	AX, 4(DI)
 	MOVL	AX, -8(DI)(BX*1)
diff --git a/src/runtime/memclr_ppc64x.s b/src/runtime/memclr_ppc64x.s
new file mode 100644
index 0000000..cea42cb
--- /dev/null
+++ b/src/runtime/memclr_ppc64x.s
@@ -0,0 +1,20 @@
+// 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 ppc64 ppc64le
+
+#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	R4, $0
+	BEQ	done
+	SUB	$1, R3
+	MOVD	R4, CTR
+	MOVBU	R0, 1(R3)
+	BC	25, 0, -1(PC) // bdnz+ $-4
+done:
+	RET
diff --git a/src/runtime/memmove_arm.s b/src/runtime/memmove_arm.s
index f187d42..35f04a8 100644
--- a/src/runtime/memmove_arm.s
+++ b/src/runtime/memmove_arm.s
@@ -26,138 +26,138 @@
 #include "textflag.h"
 
 // TE or TS are spilled to the stack during bulk register moves.
-TS = 0
-TE = 8
+#define TS	R0
+#define TE	R8
 
 // Warning: the linker will use R11 to synthesize certain instructions. Please
 // take care and double check with objdump.
-FROM = 11
-N = 12
-TMP = 12				/* N and TMP don't overlap */
-TMP1 = 5
-
-RSHIFT = 5
-LSHIFT = 6
-OFFSET = 7
-
-BR0 = 0					/* shared with TS */
-BW0 = 1
-BR1 = 1
-BW1 = 2
-BR2 = 2
-BW2 = 3
-BR3 = 3
-BW3 = 4
-
-FW0 = 1
-FR0 = 2
-FW1 = 2
-FR1 = 3
-FW2 = 3
-FR2 = 4
-FW3 = 4
-FR3 = 8					/* shared with TE */
+#define FROM	R11
+#define N	R12
+#define TMP	R12				/* N and TMP don't overlap */
+#define TMP1	R5
+
+#define RSHIFT	R5
+#define LSHIFT	R6
+#define OFFSET	R7
+
+#define BR0	R0					/* shared with TS */
+#define BW0	R1
+#define BR1	R1
+#define BW1	R2
+#define BR2	R2
+#define BW2	R3
+#define BR3	R3
+#define BW3	R4
+
+#define FW0	R1
+#define FR0	R2
+#define FW1	R2
+#define FR1	R3
+#define FW2	R3
+#define FR2	R4
+#define FW3	R4
+#define FR3	R8					/* shared with TE */
 
 TEXT runtime·memmove(SB), NOSPLIT, $4-12
 _memmove:
-	MOVW	to+0(FP), R(TS)
-	MOVW	from+4(FP), R(FROM)
-	MOVW	n+8(FP), R(N)
+	MOVW	to+0(FP), TS
+	MOVW	from+4(FP), FROM
+	MOVW	n+8(FP), N
 
-	ADD	R(N), R(TS), R(TE)	/* to end pointer */
+	ADD	N, TS, TE	/* to end pointer */
 
-	CMP	R(FROM), R(TS)
+	CMP	FROM, TS
 	BLS	_forward
 
 _back:
-	ADD	R(N), R(FROM)		/* from end pointer */
-	CMP	$4, R(N)		/* need at least 4 bytes to copy */
+	ADD	N, FROM		/* from end pointer */
+	CMP	$4, N		/* need at least 4 bytes to copy */
 	BLT	_b1tail
 
 _b4align:				/* align destination on 4 */
-	AND.S	$3, R(TE), R(TMP)
+	AND.S	$3, TE, TMP
 	BEQ	_b4aligned
 
-	MOVBU.W	-1(R(FROM)), R(TMP)	/* pre-indexed */
-	MOVBU.W	R(TMP), -1(R(TE))	/* pre-indexed */
+	MOVBU.W	-1(FROM), TMP	/* pre-indexed */
+	MOVBU.W	TMP, -1(TE)	/* pre-indexed */
 	B	_b4align
 
 _b4aligned:				/* is source now aligned? */
-	AND.S	$3, R(FROM), R(TMP)
+	AND.S	$3, FROM, TMP
 	BNE	_bunaligned
 
-	ADD	$31, R(TS), R(TMP)	/* do 32-byte chunks if possible */
-	MOVW	R(TS), savedts-4(SP)
+	ADD	$31, TS, TMP	/* do 32-byte chunks if possible */
+	MOVW	TS, savedts-4(SP)
 _b32loop:
-	CMP	R(TMP), R(TE)
+	CMP	TMP, TE
 	BLS	_b4tail
 
-	MOVM.DB.W (R(FROM)), [R0-R7]
-	MOVM.DB.W [R0-R7], (R(TE))
+	MOVM.DB.W (FROM), [R0-R7]
+	MOVM.DB.W [R0-R7], (TE)
 	B	_b32loop
 
 _b4tail:				/* do remaining words if possible */
-	MOVW	savedts-4(SP), R(TS)
-	ADD	$3, R(TS), R(TMP)
+	MOVW	savedts-4(SP), TS
+	ADD	$3, TS, TMP
 _b4loop:
-	CMP	R(TMP), R(TE)
+	CMP	TMP, TE
 	BLS	_b1tail
 
-	MOVW.W	-4(R(FROM)), R(TMP1)	/* pre-indexed */
-	MOVW.W	R(TMP1), -4(R(TE))	/* pre-indexed */
+	MOVW.W	-4(FROM), TMP1	/* pre-indexed */
+	MOVW.W	TMP1, -4(TE)	/* pre-indexed */
 	B	_b4loop
 
 _b1tail:				/* remaining bytes */
-	CMP	R(TE), R(TS)
+	CMP	TE, TS
 	BEQ	_return
 
-	MOVBU.W	-1(R(FROM)), R(TMP)	/* pre-indexed */
-	MOVBU.W	R(TMP), -1(R(TE))	/* pre-indexed */
+	MOVBU.W	-1(FROM), TMP	/* pre-indexed */
+	MOVBU.W	TMP, -1(TE)	/* pre-indexed */
 	B	_b1tail
 
 _forward:
-	CMP	$4, R(N)		/* need at least 4 bytes to copy */
+	CMP	$4, N		/* need at least 4 bytes to copy */
 	BLT	_f1tail
 
 _f4align:				/* align destination on 4 */
-	AND.S	$3, R(TS), R(TMP)
+	AND.S	$3, TS, TMP
 	BEQ	_f4aligned
 
-	MOVBU.P	1(R(FROM)), R(TMP)	/* implicit write back */
-	MOVBU.P	R(TMP), 1(R(TS))	/* implicit write back */
+	MOVBU.P	1(FROM), TMP	/* implicit write back */
+	MOVBU.P	TMP, 1(TS)	/* implicit write back */
 	B	_f4align
 
 _f4aligned:				/* is source now aligned? */
-	AND.S	$3, R(FROM), R(TMP)
+	AND.S	$3, FROM, TMP
 	BNE	_funaligned
 
-	SUB	$31, R(TE), R(TMP)	/* do 32-byte chunks if possible */
-	MOVW	R(TE), savedte-4(SP)
+	SUB	$31, TE, TMP	/* do 32-byte chunks if possible */
+	MOVW	TE, savedte-4(SP)
 _f32loop:
-	CMP	R(TMP), R(TS)
+	CMP	TMP, TS
 	BHS	_f4tail
 
-	MOVM.IA.W (R(FROM)), [R1-R8] 
-	MOVM.IA.W [R1-R8], (R(TS))
+	MOVM.IA.W (FROM), [R1-R8] 
+	MOVM.IA.W [R1-R8], (TS)
 	B	_f32loop
 
 _f4tail:
-	MOVW	savedte-4(SP), R(TE)
-	SUB	$3, R(TE), R(TMP)	/* do remaining words if possible */
+	MOVW	savedte-4(SP), TE
+	SUB	$3, TE, TMP	/* do remaining words if possible */
 _f4loop:
-	CMP	R(TMP), R(TS)
+	CMP	TMP, TS
 	BHS	_f1tail
 
-	MOVW.P	4(R(FROM)), R(TMP1)	/* implicit write back */
-	MOVW.P	R(TMP1), 4(R(TS))	/* implicit write back */
+	MOVW.P	4(FROM), TMP1	/* implicit write back */
+	MOVW.P	TMP1, 4(TS)	/* implicit write back */
 	B	_f4loop
 
 _f1tail:
-	CMP	R(TS), R(TE)
+	CMP	TS, TE
 	BEQ	_return
 
-	MOVBU.P	1(R(FROM)), R(TMP)	/* implicit write back */
-	MOVBU.P	R(TMP), 1(R(TS))	/* implicit write back */
+	MOVBU.P	1(FROM), TMP	/* implicit write back */
+	MOVBU.P	TMP, 1(TS)	/* implicit write back */
 	B	_f1tail
 
 _return:
@@ -165,97 +165,97 @@ _return:
 	RET
 
 _bunaligned:
-	CMP	$2, R(TMP)		/* is R(TMP) < 2 ? */
+	CMP	$2, TMP		/* is TMP < 2 ? */
 
-	MOVW.LT	$8, R(RSHIFT)		/* (R(n)<<24)|(R(n-1)>>8) */
-	MOVW.LT	$24, R(LSHIFT)
-	MOVW.LT	$1, R(OFFSET)
+	MOVW.LT	$8, RSHIFT		/* (R(n)<<24)|(R(n-1)>>8) */
+	MOVW.LT	$24, LSHIFT
+	MOVW.LT	$1, OFFSET
 
-	MOVW.EQ	$16, R(RSHIFT)		/* (R(n)<<16)|(R(n-1)>>16) */
-	MOVW.EQ	$16, R(LSHIFT)
-	MOVW.EQ	$2, R(OFFSET)
+	MOVW.EQ	$16, RSHIFT		/* (R(n)<<16)|(R(n-1)>>16) */
+	MOVW.EQ	$16, LSHIFT
+	MOVW.EQ	$2, OFFSET
 
-	MOVW.GT	$24, R(RSHIFT)		/* (R(n)<<8)|(R(n-1)>>24) */
-	MOVW.GT	$8, R(LSHIFT)
-	MOVW.GT	$3, R(OFFSET)
+	MOVW.GT	$24, RSHIFT		/* (R(n)<<8)|(R(n-1)>>24) */
+	MOVW.GT	$8, LSHIFT
+	MOVW.GT	$3, OFFSET
 
-	ADD	$16, R(TS), R(TMP)	/* do 16-byte chunks if possible */
-	CMP	R(TMP), R(TE)
+	ADD	$16, TS, TMP	/* do 16-byte chunks if possible */
+	CMP	TMP, TE
 	BLS	_b1tail
 
-	BIC	$3, R(FROM)		/* align source */
-	MOVW	R(TS), savedts-4(SP)
-	MOVW	(R(FROM)), R(BR0)	/* prime first block register */
+	BIC	$3, FROM		/* align source */
+	MOVW	TS, savedts-4(SP)
+	MOVW	(FROM), BR0	/* prime first block register */
 
 _bu16loop:
-	CMP	R(TMP), R(TE)
+	CMP	TMP, TE
 	BLS	_bu1tail
 
-	MOVW	R(BR0)<<R(LSHIFT), R(BW3)
-	MOVM.DB.W (R(FROM)), [R(BR0)-R(BR3)]
-	ORR	R(BR3)>>R(RSHIFT), R(BW3)
+	MOVW	BR0<<LSHIFT, BW3
+	MOVM.DB.W (FROM), [BR0-BR3]
+	ORR	BR3>>RSHIFT, BW3
 
-	MOVW	R(BR3)<<R(LSHIFT), R(BW2)
-	ORR	R(BR2)>>R(RSHIFT), R(BW2)
+	MOVW	BR3<<LSHIFT, BW2
+	ORR	BR2>>RSHIFT, BW2
 
-	MOVW	R(BR2)<<R(LSHIFT), R(BW1)
-	ORR	R(BR1)>>R(RSHIFT), R(BW1)
+	MOVW	BR2<<LSHIFT, BW1
+	ORR	BR1>>RSHIFT, BW1
 
-	MOVW	R(BR1)<<R(LSHIFT), R(BW0)
-	ORR	R(BR0)>>R(RSHIFT), R(BW0)
+	MOVW	BR1<<LSHIFT, BW0
+	ORR	BR0>>RSHIFT, BW0
 
-	MOVM.DB.W [R(BW0)-R(BW3)], (R(TE))
+	MOVM.DB.W [BW0-BW3], (TE)
 	B	_bu16loop
 
 _bu1tail:
-	MOVW	savedts-4(SP), R(TS)
-	ADD	R(OFFSET), R(FROM)
+	MOVW	savedts-4(SP), TS
+	ADD	OFFSET, FROM
 	B	_b1tail
 
 _funaligned:
-	CMP	$2, R(TMP)
+	CMP	$2, TMP
 
-	MOVW.LT	$8, R(RSHIFT)		/* (R(n+1)<<24)|(R(n)>>8) */
-	MOVW.LT	$24, R(LSHIFT)
-	MOVW.LT	$3, R(OFFSET)
+	MOVW.LT	$8, RSHIFT		/* (R(n+1)<<24)|(R(n)>>8) */
+	MOVW.LT	$24, LSHIFT
+	MOVW.LT	$3, OFFSET
 
-	MOVW.EQ	$16, R(RSHIFT)		/* (R(n+1)<<16)|(R(n)>>16) */
-	MOVW.EQ	$16, R(LSHIFT)
-	MOVW.EQ	$2, R(OFFSET)
+	MOVW.EQ	$16, RSHIFT		/* (R(n+1)<<16)|(R(n)>>16) */
+	MOVW.EQ	$16, LSHIFT
+	MOVW.EQ	$2, OFFSET
 
-	MOVW.GT	$24, R(RSHIFT)		/* (R(n+1)<<8)|(R(n)>>24) */
-	MOVW.GT	$8, R(LSHIFT)
-	MOVW.GT	$1, R(OFFSET)
+	MOVW.GT	$24, RSHIFT		/* (R(n+1)<<8)|(R(n)>>24) */
+	MOVW.GT	$8, LSHIFT
+	MOVW.GT	$1, OFFSET
 
-	SUB	$16, R(TE), R(TMP)	/* do 16-byte chunks if possible */
-	CMP	R(TMP), R(TS)
+	SUB	$16, TE, TMP	/* do 16-byte chunks if possible */
+	CMP	TMP, TS
 	BHS	_f1tail
 
-	BIC	$3, R(FROM)		/* align source */
-	MOVW	R(TE), savedte-4(SP)
-	MOVW.P	4(R(FROM)), R(FR3)	/* prime last block register, implicit write back */
+	BIC	$3, FROM		/* align source */
+	MOVW	TE, savedte-4(SP)
+	MOVW.P	4(FROM), FR3	/* prime last block register, implicit write back */
 
 _fu16loop:
-	CMP	R(TMP), R(TS)
+	CMP	TMP, TS
 	BHS	_fu1tail
 
-	MOVW	R(FR3)>>R(RSHIFT), R(FW0)
-	MOVM.IA.W (R(FROM)), [R(FR0),R(FR1),R(FR2),R(FR3)]
-	ORR	R(FR0)<<R(LSHIFT), R(FW0)
+	MOVW	FR3>>RSHIFT, FW0
+	MOVM.IA.W (FROM), [FR0,FR1,FR2,FR3]
+	ORR	FR0<<LSHIFT, FW0
 
-	MOVW	R(FR0)>>R(RSHIFT), R(FW1)
-	ORR	R(FR1)<<R(LSHIFT), R(FW1)
+	MOVW	FR0>>RSHIFT, FW1
+	ORR	FR1<<LSHIFT, FW1
 
-	MOVW	R(FR1)>>R(RSHIFT), R(FW2)
-	ORR	R(FR2)<<R(LSHIFT), R(FW2)
+	MOVW	FR1>>RSHIFT, FW2
+	ORR	FR2<<LSHIFT, FW2
 
-	MOVW	R(FR2)>>R(RSHIFT), R(FW3)
-	ORR	R(FR3)<<R(LSHIFT), R(FW3)
+	MOVW	FR2>>RSHIFT, FW3
+	ORR	FR3<<LSHIFT, FW3
 
-	MOVM.IA.W [R(FW0),R(FW1),R(FW2),R(FW3)], (R(TS))
+	MOVM.IA.W [FW0,FW1,FW2,FW3], (TS)
 	B	_fu16loop
 
 _fu1tail:
-	MOVW	savedte-4(SP), R(TE)
-	SUB	R(OFFSET), R(FROM)
+	MOVW	savedte-4(SP), TE
+	SUB	OFFSET, FROM
 	B	_f1tail
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/memmove_ppc64x.s b/src/runtime/memmove_ppc64x.s
new file mode 100644
index 0000000..3ada63e
--- /dev/null
+++ b/src/runtime/memmove_ppc64x.s
@@ -0,0 +1,40 @@
+// 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 ppc64 ppc64le
+
+#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	R5, $0
+	BNE	check
+	RET
+
+check:
+	CMP	R3, R4
+	BGT	backward
+
+	SUB	$1, R3
+	ADD	R3, R5
+	SUB	$1, R4
+loop:
+	MOVBU	1(R4), R6
+	MOVBU	R6, 1(R3)
+	CMP	R3, R5
+	BNE	loop
+	RET
+
+backward:
+	ADD	R5, R4
+	ADD	R3, R5
+loop1:
+	MOVBU	-1(R4), R6
+	MOVBU	R6, -1(R5)
+	CMP	R3, R5
+	BNE	loop1
+	RET
diff --git a/src/runtime/memmove_test.go b/src/runtime/memmove_test.go
index ffda4fe..857f99b 100644
--- a/src/runtime/memmove_test.go
+++ b/src/runtime/memmove_test.go
@@ -162,6 +162,20 @@ func BenchmarkMemclr256(b *testing.B)   { bmMemclr(b, 256) }
 func BenchmarkMemclr4096(b *testing.B)  { bmMemclr(b, 4096) }
 func BenchmarkMemclr65536(b *testing.B) { bmMemclr(b, 65536) }
 
+func bmGoMemclr(b *testing.B, n int) {
+	x := make([]byte, n)
+	b.SetBytes(int64(n))
+	for i := 0; i < b.N; i++ {
+		for j := range x {
+			x[j] = 0
+		}
+	}
+}
+func BenchmarkGoMemclr5(b *testing.B)   { bmGoMemclr(b, 5) }
+func BenchmarkGoMemclr16(b *testing.B)  { bmGoMemclr(b, 16) }
+func BenchmarkGoMemclr64(b *testing.B)  { bmGoMemclr(b, 64) }
+func BenchmarkGoMemclr256(b *testing.B) { bmGoMemclr(b, 256) }
+
 func BenchmarkClearFat8(b *testing.B) {
 	for i := 0; i < b.N; i++ {
 		var x [8 / 4]uint32
@@ -192,6 +206,24 @@ func BenchmarkClearFat32(b *testing.B) {
 		_ = x
 	}
 }
+func BenchmarkClearFat40(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		var x [40 / 4]uint32
+		_ = x
+	}
+}
+func BenchmarkClearFat48(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		var x [48 / 4]uint32
+		_ = x
+	}
+}
+func BenchmarkClearFat56(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		var x [56 / 4]uint32
+		_ = x
+	}
+}
 func BenchmarkClearFat64(b *testing.B) {
 	for i := 0; i < b.N; i++ {
 		var x [64 / 4]uint32
diff --git a/src/runtime/mfinal.go b/src/runtime/mfinal.go
new file mode 100644
index 0000000..7e1773c
--- /dev/null
+++ b/src/runtime/mfinal.go
@@ -0,0 +1,412 @@
+// 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.
+
+// Garbage collector: finalizers and block profiling.
+
+package runtime
+
+import "unsafe"
+
+type finblock struct {
+	alllink *finblock
+	next    *finblock
+	cnt     int32
+	_       int32
+	fin     [(_FinBlockSize - 2*ptrSize - 2*4) / unsafe.Sizeof(finalizer{})]finalizer
+}
+
+var finlock mutex  // protects the following variables
+var fing *g        // goroutine that runs finalizers
+var finq *finblock // list of finalizers that are to be executed
+var finc *finblock // cache of free blocks
+var finptrmask [_FinBlockSize / ptrSize / 8]byte
+var fingwait bool
+var fingwake bool
+var allfin *finblock // list of all blocks
+
+// NOTE: Layout known to queuefinalizer.
+type finalizer struct {
+	fn   *funcval       // function to call
+	arg  unsafe.Pointer // ptr to object
+	nret uintptr        // bytes of return values from fn
+	fint *_type         // type of first argument of fn
+	ot   *ptrtype       // type of ptr to object
+}
+
+var finalizer1 = [...]byte{
+	// Each Finalizer is 5 words, ptr ptr INT ptr ptr (INT = uintptr here)
+	// Each byte describes 8 words.
+	// Need 8 Finalizers described by 5 bytes before pattern repeats:
+	//	ptr ptr INT ptr ptr
+	//	ptr ptr INT ptr ptr
+	//	ptr ptr INT ptr ptr
+	//	ptr ptr INT ptr ptr
+	//	ptr ptr INT ptr ptr
+	//	ptr ptr INT ptr ptr
+	//	ptr ptr INT ptr ptr
+	//	ptr ptr INT ptr ptr
+	// aka
+	//
+	//	ptr ptr INT ptr ptr ptr ptr INT
+	//	ptr ptr ptr ptr INT ptr ptr ptr
+	//	ptr INT ptr ptr ptr ptr INT ptr
+	//	ptr ptr ptr INT ptr ptr ptr ptr
+	//	INT ptr ptr ptr ptr INT ptr ptr
+	//
+	// Assumptions about Finalizer layout checked below.
+	1<<0 | 1<<1 | 0<<2 | 1<<3 | 1<<4 | 1<<5 | 1<<6 | 0<<7,
+	1<<0 | 1<<1 | 1<<2 | 1<<3 | 0<<4 | 1<<5 | 1<<6 | 1<<7,
+	1<<0 | 0<<1 | 1<<2 | 1<<3 | 1<<4 | 1<<5 | 0<<6 | 1<<7,
+	1<<0 | 1<<1 | 1<<2 | 0<<3 | 1<<4 | 1<<5 | 1<<6 | 1<<7,
+	0<<0 | 1<<1 | 1<<2 | 1<<3 | 1<<4 | 0<<5 | 1<<6 | 1<<7,
+}
+
+func queuefinalizer(p unsafe.Pointer, fn *funcval, nret uintptr, fint *_type, ot *ptrtype) {
+	lock(&finlock)
+	if finq == nil || finq.cnt == int32(len(finq.fin)) {
+		if finc == nil {
+			// Note: write barrier here, assigning to finc, but should be okay.
+			finc = (*finblock)(persistentalloc(_FinBlockSize, 0, &memstats.gc_sys))
+			finc.alllink = allfin
+			allfin = finc
+			if finptrmask[0] == 0 {
+				// Build pointer mask for Finalizer array in block.
+				// Check assumptions made in finalizer1 array above.
+				if (unsafe.Sizeof(finalizer{}) != 5*ptrSize ||
+					unsafe.Offsetof(finalizer{}.fn) != 0 ||
+					unsafe.Offsetof(finalizer{}.arg) != ptrSize ||
+					unsafe.Offsetof(finalizer{}.nret) != 2*ptrSize ||
+					unsafe.Offsetof(finalizer{}.fint) != 3*ptrSize ||
+					unsafe.Offsetof(finalizer{}.ot) != 4*ptrSize) {
+					throw("finalizer out of sync")
+				}
+				for i := range finptrmask {
+					finptrmask[i] = finalizer1[i%len(finalizer1)]
+				}
+			}
+		}
+		block := finc
+		finc = block.next
+		block.next = finq
+		finq = block
+	}
+	f := &finq.fin[finq.cnt]
+	finq.cnt++
+	f.fn = fn
+	f.nret = nret
+	f.fint = fint
+	f.ot = ot
+	f.arg = p
+	fingwake = true
+	unlock(&finlock)
+}
+
+//go:nowritebarrier
+func iterate_finq(callback func(*funcval, unsafe.Pointer, uintptr, *_type, *ptrtype)) {
+	for fb := allfin; fb != nil; fb = fb.alllink {
+		for i := int32(0); i < fb.cnt; i++ {
+			f := &fb.fin[i]
+			callback(f.fn, f.arg, f.nret, f.fint, f.ot)
+		}
+	}
+}
+
+func wakefing() *g {
+	var res *g
+	lock(&finlock)
+	if fingwait && fingwake {
+		fingwait = false
+		fingwake = false
+		res = fing
+	}
+	unlock(&finlock)
+	return res
+}
+
+var (
+	fingCreate  uint32
+	fingRunning bool
+)
+
+func createfing() {
+	// start the finalizer goroutine exactly once
+	if fingCreate == 0 && cas(&fingCreate, 0, 1) {
+		go runfinq()
+	}
+}
+
+// This is the goroutine that runs all of the finalizers
+func runfinq() {
+	var (
+		frame    unsafe.Pointer
+		framecap uintptr
+	)
+
+	for {
+		lock(&finlock)
+		fb := finq
+		finq = nil
+		if fb == nil {
+			gp := getg()
+			fing = gp
+			fingwait = true
+			goparkunlock(&finlock, "finalizer wait", traceEvGoBlock, 1)
+			continue
+		}
+		unlock(&finlock)
+		if raceenabled {
+			racefingo()
+		}
+		for fb != nil {
+			for i := fb.cnt; i > 0; i-- {
+				f := (*finalizer)(add(unsafe.Pointer(&fb.fin), uintptr(i-1)*unsafe.Sizeof(finalizer{})))
+
+				framesz := unsafe.Sizeof((interface{})(nil)) + uintptr(f.nret)
+				if framecap < framesz {
+					// The frame does not contain pointers interesting for GC,
+					// all not yet finalized objects are stored in finq.
+					// If we do not mark it as FlagNoScan,
+					// the last finalized object is not collected.
+					frame = mallocgc(framesz, nil, flagNoScan)
+					framecap = framesz
+				}
+
+				if f.fint == nil {
+					throw("missing type in runfinq")
+				}
+				switch f.fint.kind & kindMask {
+				case kindPtr:
+					// direct use of pointer
+					*(*unsafe.Pointer)(frame) = f.arg
+				case kindInterface:
+					ityp := (*interfacetype)(unsafe.Pointer(f.fint))
+					// set up with empty interface
+					(*eface)(frame)._type = &f.ot.typ
+					(*eface)(frame).data = f.arg
+					if len(ityp.mhdr) != 0 {
+						// convert to interface with methods
+						// this conversion is guaranteed to succeed - we checked in SetFinalizer
+						assertE2I(ityp, *(*interface{})(frame), (*fInterface)(frame))
+					}
+				default:
+					throw("bad kind in runfinq")
+				}
+				fingRunning = true
+				reflectcall(nil, unsafe.Pointer(f.fn), frame, uint32(framesz), uint32(framesz))
+				fingRunning = false
+
+				// drop finalizer queue references to finalized object
+				f.fn = nil
+				f.arg = nil
+				f.ot = nil
+				fb.cnt = i - 1
+			}
+			next := fb.next
+			lock(&finlock)
+			fb.next = finc
+			finc = fb
+			unlock(&finlock)
+			fb = next
+		}
+	}
+}
+
+// SetFinalizer sets the finalizer associated with x to f.
+// When the garbage collector finds an unreachable block
+// with an associated finalizer, it clears the association and runs
+// f(x) in a separate goroutine.  This makes x reachable again, but
+// now without an associated finalizer.  Assuming that SetFinalizer
+// is not called again, the next time the garbage collector sees
+// that x is unreachable, it will free x.
+//
+// SetFinalizer(x, nil) clears any finalizer associated with x.
+//
+// The argument x must be a pointer to an object allocated by
+// calling new or by taking the address of a composite literal.
+// The argument f must be a function that takes a single argument
+// to which x's type can be assigned, and can have arbitrary ignored return
+// values. If either of these is not true, SetFinalizer aborts the
+// program.
+//
+// Finalizers are run in dependency order: if A points at B, both have
+// finalizers, and they are otherwise unreachable, only the finalizer
+// for A runs; once A is freed, the finalizer for B can run.
+// If a cyclic structure includes a block with a finalizer, that
+// cycle is not guaranteed to be garbage collected and the finalizer
+// is not guaranteed to run, because there is no ordering that
+// respects the dependencies.
+//
+// The finalizer for x is scheduled to run at some arbitrary time after
+// x becomes unreachable.
+// There is no guarantee that finalizers will run before a program exits,
+// so typically they are useful only for releasing non-memory resources
+// associated with an object during a long-running program.
+// For example, an os.File object could use a finalizer to close the
+// associated operating system file descriptor when a program discards
+// an os.File without calling Close, but it would be a mistake
+// to depend on a finalizer to flush an in-memory I/O buffer such as a
+// bufio.Writer, because the buffer would not be flushed at program exit.
+//
+// It is not guaranteed that a finalizer will run if the size of *x is
+// zero bytes.
+//
+// It is not guaranteed that a finalizer will run for objects allocated
+// in initializers for package-level variables. Such objects may be
+// linker-allocated, not heap-allocated.
+//
+// A single goroutine runs all finalizers for a program, sequentially.
+// 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 {
+		throw("runtime.SetFinalizer: first argument is nil")
+	}
+	if etyp.kind&kindMask != kindPtr {
+		throw("runtime.SetFinalizer: first argument is " + *etyp._string + ", not pointer")
+	}
+	ot := (*ptrtype)(unsafe.Pointer(etyp))
+	if ot.elem == nil {
+		throw("nil elem type!")
+	}
+
+	// find the containing object
+	_, base, _ := findObject(e.data)
+
+	if base == nil {
+		// 0-length objects are okay.
+		if e.data == unsafe.Pointer(&zerobase) {
+			return
+		}
+
+		// Global initializers might be linker-allocated.
+		//	var Foo = &Object{}
+		//	func main() {
+		//		runtime.SetFinalizer(Foo, nil)
+		//	}
+		// The relevant segments are: noptrdata, data, bss, noptrbss.
+		// We cannot assume they are in any order or even contiguous,
+		// due to external linking.
+		for datap := &firstmoduledata; datap != nil; datap = datap.next {
+			if datap.noptrdata <= uintptr(e.data) && uintptr(e.data) < datap.enoptrdata ||
+				datap.data <= uintptr(e.data) && uintptr(e.data) < datap.edata ||
+				datap.bss <= uintptr(e.data) && uintptr(e.data) < datap.ebss ||
+				datap.noptrbss <= uintptr(e.data) && uintptr(e.data) < datap.enoptrbss {
+				return
+			}
+		}
+		throw("runtime.SetFinalizer: pointer not in allocated block")
+	}
+
+	if e.data != base {
+		// As an implementation detail we allow to set finalizers for an inner byte
+		// of an object if it could come from tiny alloc (see mallocgc for details).
+		if ot.elem == nil || ot.elem.kind&kindNoPointers == 0 || ot.elem.size >= maxTinySize {
+			throw("runtime.SetFinalizer: pointer not at beginning of allocated block")
+		}
+	}
+
+	f := (*eface)(unsafe.Pointer(&finalizer))
+	ftyp := f._type
+	if ftyp == nil {
+		// switch to system stack and remove finalizer
+		systemstack(func() {
+			removefinalizer(e.data)
+		})
+		return
+	}
+
+	if ftyp.kind&kindMask != kindFunc {
+		throw("runtime.SetFinalizer: second argument is " + *ftyp._string + ", not a function")
+	}
+	ft := (*functype)(unsafe.Pointer(ftyp))
+	ins := *(*[]*_type)(unsafe.Pointer(&ft.in))
+	if ft.dotdotdot || len(ins) != 1 {
+		throw("runtime.SetFinalizer: cannot pass " + *etyp._string + " to finalizer " + *ftyp._string)
+	}
+	fint := ins[0]
+	switch {
+	case fint == etyp:
+		// ok - same type
+		goto okarg
+	case fint.kind&kindMask == kindPtr:
+		if (fint.x == nil || fint.x.name == nil || etyp.x == nil || etyp.x.name == nil) && (*ptrtype)(unsafe.Pointer(fint)).elem == ot.elem {
+			// ok - not same type, but both pointers,
+			// one or the other is unnamed, and same element type, so assignable.
+			goto okarg
+		}
+	case fint.kind&kindMask == kindInterface:
+		ityp := (*interfacetype)(unsafe.Pointer(fint))
+		if len(ityp.mhdr) == 0 {
+			// ok - satisfies empty interface
+			goto okarg
+		}
+		if assertE2I2(ityp, obj, nil) {
+			goto okarg
+		}
+	}
+	throw("runtime.SetFinalizer: cannot pass " + *etyp._string + " to finalizer " + *ftyp._string)
+okarg:
+	// compute size needed for return parameters
+	nret := uintptr(0)
+	for _, t := range *(*[]*_type)(unsafe.Pointer(&ft.out)) {
+		nret = round(nret, uintptr(t.align)) + uintptr(t.size)
+	}
+	nret = round(nret, ptrSize)
+
+	// make sure we have a finalizer goroutine
+	createfing()
+
+	systemstack(func() {
+		if !addfinalizer(e.data, (*funcval)(f.data), nret, fint, ot) {
+			throw("runtime.SetFinalizer: finalizer already set")
+		}
+	})
+}
+
+// Look up pointer v in heap.  Return the span containing the object,
+// the start of the object, and the size of the object.  If the object
+// does not exist, return nil, nil, 0.
+func findObject(v unsafe.Pointer) (s *mspan, x unsafe.Pointer, n uintptr) {
+	c := gomcache()
+	c.local_nlookup++
+	if ptrSize == 4 && c.local_nlookup >= 1<<30 {
+		// purge cache stats to prevent overflow
+		lock(&mheap_.lock)
+		purgecachedstats(c)
+		unlock(&mheap_.lock)
+	}
+
+	// find span
+	arena_start := uintptr(unsafe.Pointer(mheap_.arena_start))
+	arena_used := uintptr(unsafe.Pointer(mheap_.arena_used))
+	if uintptr(v) < arena_start || uintptr(v) >= arena_used {
+		return
+	}
+	p := uintptr(v) >> pageShift
+	q := p - arena_start>>pageShift
+	s = *(**mspan)(add(unsafe.Pointer(mheap_.spans), q*ptrSize))
+	if s == nil {
+		return
+	}
+	x = unsafe.Pointer(uintptr(s.start) << pageShift)
+
+	if uintptr(v) < uintptr(x) || uintptr(v) >= uintptr(unsafe.Pointer(s.limit)) || s.state != mSpanInUse {
+		s = nil
+		x = nil
+		return
+	}
+
+	n = uintptr(s.elemsize)
+	if s.sizeclass != 0 {
+		x = add(x, (uintptr(v)-uintptr(x))/n*n)
+	}
+	return
+}
diff --git a/src/runtime/mfinal_test.go b/src/runtime/mfinal_test.go
index d2cead2..e9e3601 100644
--- a/src/runtime/mfinal_test.go
+++ b/src/runtime/mfinal_test.go
@@ -171,9 +171,6 @@ func adjChunks() (*objtype, *objtype) {
 
 // Make sure an empty slice on the stack doesn't pin the next object in memory.
 func TestEmptySlice(t *testing.T) {
-	if true { // disable until bug 7564 is fixed.
-		return
-	}
 	x, y := adjChunks()
 
 	// the pointer inside xs points to y.
diff --git a/src/runtime/mfixalloc.c b/src/runtime/mfixalloc.c
deleted file mode 100644
index d670629..0000000
--- a/src/runtime/mfixalloc.c
+++ /dev/null
@@ -1,64 +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.
-
-// Fixed-size object allocator.  Returned memory is not zeroed.
-//
-// See malloc.h for overview.
-
-#include "runtime.h"
-#include "arch_GOARCH.h"
-#include "malloc.h"
-
-// Initialize f to allocate objects of the given size,
-// using the allocator to obtain chunks of memory.
-void
-runtime·FixAlloc_Init(FixAlloc *f, uintptr size, void (*first)(void*, byte*), void *arg, uint64 *stat)
-{
-	f->size = size;
-	f->first = first;
-	f->arg = arg;
-	f->list = nil;
-	f->chunk = nil;
-	f->nchunk = 0;
-	f->inuse = 0;
-	f->stat = stat;
-}
-
-void*
-runtime·FixAlloc_Alloc(FixAlloc *f)
-{
-	void *v;
-	
-	if(f->size == 0) {
-		runtime·printf("runtime: use of FixAlloc_Alloc before FixAlloc_Init\n");
-		runtime·throw("runtime: internal error");
-	}
-
-	if(f->list) {
-		v = f->list;
-		f->list = *(void**)f->list;
-		f->inuse += f->size;
-		return v;
-	}
-	if(f->nchunk < f->size) {
-		f->chunk = runtime·persistentalloc(FixAllocChunk, 0, f->stat);
-		f->nchunk = FixAllocChunk;
-	}
-	v = f->chunk;
-	if(f->first)
-		f->first(f->arg, v);
-	f->chunk += f->size;
-	f->nchunk -= f->size;
-	f->inuse += f->size;
-	return v;
-}
-
-void
-runtime·FixAlloc_Free(FixAlloc *f, void *p)
-{
-	f->inuse -= f->size;
-	*(void**)p = f->list;
-	f->list = p;
-}
-
diff --git a/src/runtime/mfixalloc.go b/src/runtime/mfixalloc.go
new file mode 100644
index 0000000..bb2f4e7
--- /dev/null
+++ b/src/runtime/mfixalloc.go
@@ -0,0 +1,87 @@
+// 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.
+
+// Fixed-size object allocator.  Returned memory is not zeroed.
+//
+// See malloc.go for overview.
+
+package runtime
+
+import "unsafe"
+
+// FixAlloc is a simple free-list allocator for fixed size objects.
+// Malloc uses a FixAlloc wrapped around sysAlloc to manages its
+// MCache and MSpan objects.
+//
+// Memory returned by FixAlloc_Alloc is not zeroed.
+// The caller is responsible for locking around FixAlloc calls.
+// Callers can keep state in the object but the first word is
+// smashed by freeing and reallocating.
+type fixalloc struct {
+	size   uintptr
+	first  unsafe.Pointer // go func(unsafe.pointer, unsafe.pointer); f(arg, p) called first time p is returned
+	arg    unsafe.Pointer
+	list   *mlink
+	chunk  *byte
+	nchunk uint32
+	inuse  uintptr // in-use bytes now
+	stat   *uint64
+}
+
+// A generic linked list of blocks.  (Typically the block is bigger than sizeof(MLink).)
+// Since assignments to mlink.next will result in a write barrier being preformed
+// this can not be used by some of the internal GC structures. For example when
+// the sweeper is placing an unmarked object on the free list it does not want the
+// write barrier to be called since that could result in the object being reachable.
+type mlink struct {
+	next *mlink
+}
+
+// Initialize f to allocate objects of the given size,
+// using the allocator to obtain chunks of memory.
+func fixAlloc_Init(f *fixalloc, size uintptr, first func(unsafe.Pointer, unsafe.Pointer), arg unsafe.Pointer, stat *uint64) {
+	f.size = size
+	f.first = *(*unsafe.Pointer)(unsafe.Pointer(&first))
+	f.arg = arg
+	f.list = nil
+	f.chunk = nil
+	f.nchunk = 0
+	f.inuse = 0
+	f.stat = stat
+}
+
+func fixAlloc_Alloc(f *fixalloc) unsafe.Pointer {
+	if f.size == 0 {
+		print("runtime: use of FixAlloc_Alloc before FixAlloc_Init\n")
+		throw("runtime: internal error")
+	}
+
+	if f.list != nil {
+		v := unsafe.Pointer(f.list)
+		f.list = f.list.next
+		f.inuse += f.size
+		return v
+	}
+	if uintptr(f.nchunk) < f.size {
+		f.chunk = (*uint8)(persistentalloc(_FixAllocChunk, 0, f.stat))
+		f.nchunk = _FixAllocChunk
+	}
+
+	v := (unsafe.Pointer)(f.chunk)
+	if f.first != nil {
+		fn := *(*func(unsafe.Pointer, unsafe.Pointer))(unsafe.Pointer(&f.first))
+		fn(f.arg, v)
+	}
+	f.chunk = (*byte)(add(unsafe.Pointer(f.chunk), f.size))
+	f.nchunk -= uint32(f.size)
+	f.inuse += f.size
+	return v
+}
+
+func fixAlloc_Free(f *fixalloc, p unsafe.Pointer) {
+	f.inuse -= f.size
+	v := (*mlink)(p)
+	v.next = f.list
+	f.list = v
+}
diff --git a/src/runtime/mgc.go b/src/runtime/mgc.go
new file mode 100644
index 0000000..82b12b6
--- /dev/null
+++ b/src/runtime/mgc.go
@@ -0,0 +1,1765 @@
+// 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.
+
+// TODO(rsc): The code having to do with the heap bitmap needs very serious cleanup.
+// It has gotten completely out of control.
+
+// Garbage collector (GC).
+//
+// The GC runs concurrently with mutator threads, is type accurate (aka precise), allows multiple
+// GC thread to run in parallel. It is a concurrent mark and sweep that uses a write barrier. It is
+// non-generational and non-compacting. Allocation is done using size segregated per P allocation
+// areas to minimize fragmentation while eliminating locks in the common case.
+//
+// The algorithm decomposes into several steps.
+// This is a high level description of the algorithm being used. For an overview of GC a good
+// place to start is Richard Jones' gchandbook.org.
+//
+// The algorithm's intellectual heritage includes Dijkstra's on-the-fly algorithm, see
+// Edsger W. Dijkstra, Leslie Lamport, A. J. Martin, C. S. Scholten, and E. F. M. Steffens. 1978.
+// On-the-fly garbage collection: an exercise in cooperation. Commun. ACM 21, 11 (November 1978),
+// 966-975.
+// For journal quality proofs that these steps are complete, correct, and terminate see
+// Hudson, R., and Moss, J.E.B. Copying Garbage Collection without stopping the world.
+// Concurrency and Computation: Practice and Experience 15(3-5), 2003.
+//
+//  0. Set phase = GCscan from GCoff.
+//  1. Wait for all P's to acknowledge phase change.
+//         At this point all goroutines have passed through a GC safepoint and
+//         know we are in the GCscan phase.
+//  2. GC scans all goroutine stacks, mark and enqueues all encountered pointers
+//       (marking avoids most duplicate enqueuing but races may produce benign duplication).
+//       Preempted goroutines are scanned before P schedules next goroutine.
+//  3. Set phase = GCmark.
+//  4. Wait for all P's to acknowledge phase change.
+//  5. Now write barrier marks and enqueues black, grey, or white to white pointers.
+//       Malloc still allocates white (non-marked) objects.
+//  6. Meanwhile GC transitively walks the heap marking reachable objects.
+//  7. When GC finishes marking heap, it preempts P's one-by-one and
+//       retakes partial wbufs (filled by write barrier or during a stack scan of the goroutine
+//       currently scheduled on the P).
+//  8. Once the GC has exhausted all available marking work it sets phase = marktermination.
+//  9. Wait for all P's to acknowledge phase change.
+// 10. Malloc now allocates black objects, so number of unmarked reachable objects
+//        monotonically decreases.
+// 11. GC preempts P's one-by-one taking partial wbufs and marks all unmarked yet
+//        reachable objects.
+// 12. When GC completes a full cycle over P's and discovers no new grey
+//         objects, (which means all reachable objects are marked) set phase = GCoff.
+// 13. Wait for all P's to acknowledge phase change.
+// 14. Now malloc allocates white (but sweeps spans before use).
+//         Write barrier becomes nop.
+// 15. GC does background sweeping, see description below.
+// 16. When sufficient allocation has taken place replay the sequence starting at 0 above,
+//         see discussion of GC rate below.
+
+// Changing phases.
+// Phases are changed by setting the gcphase to the next phase and possibly calling ackgcphase.
+// All phase action must be benign in the presence of a change.
+// Starting with GCoff
+// GCoff to GCscan
+//     GSscan scans stacks and globals greying them and never marks an object black.
+//     Once all the P's are aware of the new phase they will scan gs on preemption.
+//     This means that the scanning of preempted gs can't start until all the Ps
+//     have acknowledged.
+//     When a stack is scanned, this phase also installs stack barriers to
+//     track how much of the stack has been active.
+//     This transition enables write barriers because stack barriers
+//     assume that writes to higher frames will be tracked by write
+//     barriers. Technically this only needs write barriers for writes
+//     to stack slots, but we enable write barriers in general.
+// GCscan to GCmark
+//     In GCmark, work buffers are drained until there are no more
+//     pointers to scan.
+//     No scanning of objects (making them black) can happen until all
+//     Ps have enabled the write barrier, but that already happened in
+//     the transition to GCscan.
+// GCmark to GCmarktermination
+//     The only change here is that we start allocating black so the Ps must acknowledge
+//     the change before we begin the termination algorithm
+// GCmarktermination to GSsweep
+//     Object currently on the freelist must be marked black for this to work.
+//     Are things on the free lists black or white? How does the sweep phase work?
+
+// Concurrent sweep.
+//
+// The sweep phase proceeds concurrently with normal program execution.
+// The heap is swept span-by-span both lazily (when a goroutine needs another span)
+// and concurrently in a background goroutine (this helps programs that are not CPU bound).
+// At the end of STW mark termination all spans are marked as "needs sweeping".
+//
+// The background sweeper goroutine simply sweeps spans one-by-one.
+//
+// To avoid requesting more OS memory while there are unswept spans, when a
+// goroutine needs another span, it first attempts to reclaim that much memory
+// by sweeping. When a goroutine needs to allocate a new small-object span, it
+// sweeps small-object spans for the same object size until it frees at least
+// one object. When a goroutine needs to allocate large-object span from heap,
+// it sweeps spans until it frees at least that many pages into heap. There is
+// one case where this may not suffice: if a goroutine sweeps and frees two
+// nonadjacent one-page spans to the heap, it will allocate a new two-page
+// span, but there can still be other one-page unswept spans which could be
+// combined into a two-page span.
+//
+// It's critical to ensure that no operations proceed on unswept spans (that would corrupt
+// mark bits in GC bitmap). During GC all mcaches are flushed into the central cache,
+// so they are empty. When a goroutine grabs a new span into mcache, it sweeps it.
+// When a goroutine explicitly frees an object or sets a finalizer, it ensures that
+// the span is swept (either by sweeping it, or by waiting for the concurrent sweep to finish).
+// The finalizer goroutine is kicked off only when all spans are swept.
+// When the next GC starts, it sweeps all not-yet-swept spans (if any).
+
+// GC rate.
+// Next GC is after we've allocated an extra amount of memory proportional to
+// the amount already in use. The proportion is controlled by GOGC environment variable
+// (100 by default). If GOGC=100 and we're using 4M, we'll GC again when we get to 8M
+// (this mark is tracked in next_gc variable). This keeps the GC cost in linear
+// proportion to the allocation cost. Adjusting GOGC just changes the linear constant
+// (and also the amount of extra memory used).
+
+package runtime
+
+import "unsafe"
+
+const (
+	_DebugGC         = 0
+	_ConcurrentSweep = true
+	_FinBlockSize    = 4 * 1024
+	_RootData        = 0
+	_RootBss         = 1
+	_RootFinalizers  = 2
+	_RootSpans       = 3
+	_RootFlushCaches = 4
+	_RootCount       = 5
+
+	debugStackBarrier = false
+
+	// sweepMinHeapDistance is a lower bound on the heap distance
+	// (in bytes) reserved for concurrent sweeping between GC
+	// cycles. This will be scaled by gcpercent/100.
+	sweepMinHeapDistance = 1024 * 1024
+)
+
+// firstStackBarrierOffset is the approximate byte offset at
+// which to place the first stack barrier from the current SP.
+// This is a lower bound on how much stack will have to be
+// re-scanned during mark termination. Subsequent barriers are
+// placed at firstStackBarrierOffset * 2^n offsets.
+//
+// For debugging, this can be set to 0, which will install a
+// stack barrier at every frame. If you do this, you may also
+// have to raise _StackMin, since the stack barrier
+// bookkeeping will use a large amount of each stack.
+var firstStackBarrierOffset = 1024
+
+// heapminimum is the minimum heap size at which to trigger GC.
+// For small heaps, this overrides the usual GOGC*live set rule.
+//
+// When there is a very small live set but a lot of allocation, simply
+// collecting when the heap reaches GOGC*live results in many GC
+// cycles and high total per-GC overhead. This minimum amortizes this
+// per-GC overhead while keeping the heap reasonably small.
+//
+// During initialization this is set to 4MB*GOGC/100. In the case of
+// GOGC==0, this will set heapminimum to 0, resulting in constant
+// collection even when the heap size is small, which is useful for
+// debugging.
+var heapminimum uint64 = defaultHeapMinimum
+
+// defaultHeapMinimum is the value of heapminimum for GOGC==100.
+const defaultHeapMinimum = 4 << 20
+
+// Initialized from $GOGC.  GOGC=off means no GC.
+var gcpercent int32
+
+func gcinit() {
+	if unsafe.Sizeof(workbuf{}) != _WorkbufSize {
+		throw("size of Workbuf is suboptimal")
+	}
+
+	work.markfor = parforalloc(_MaxGcproc)
+	_ = setGCPercent(readgogc())
+	for datap := &firstmoduledata; datap != nil; datap = datap.next {
+		datap.gcdatamask = progToPointerMask((*byte)(unsafe.Pointer(datap.gcdata)), datap.edata-datap.data)
+		datap.gcbssmask = progToPointerMask((*byte)(unsafe.Pointer(datap.gcbss)), datap.ebss-datap.bss)
+	}
+	memstats.next_gc = heapminimum
+}
+
+func readgogc() int32 {
+	p := gogetenv("GOGC")
+	if p == "" {
+		return 100
+	}
+	if p == "off" {
+		return -1
+	}
+	return int32(atoi(p))
+}
+
+// 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
+	if in < 0 {
+		in = -1
+	}
+	gcpercent = in
+	heapminimum = defaultHeapMinimum * uint64(gcpercent) / 100
+	unlock(&mheap_.lock)
+	return out
+}
+
+// Garbage collector phase.
+// Indicates to write barrier and sychronization task to preform.
+var gcphase uint32
+var writeBarrierEnabled bool // compiler emits references to this in write barriers
+
+// gcBlackenEnabled is 1 if mutator assists and background mark
+// workers are allowed to blacken objects. This must only be set when
+// gcphase == _GCmark.
+var gcBlackenEnabled uint32
+
+// gcBlackenPromptly indicates that optimizations that may
+// hide work from the global work queue should be disabled.
+//
+// If gcBlackenPromptly is true, per-P gcWork caches should
+// be flushed immediately and new objects should be allocated black.
+//
+// There is a tension between allocating objects white and
+// allocating them black. If white and the objects die before being
+// marked they can be collected during this GC cycle. On the other
+// hand allocating them black will reduce _GCmarktermination latency
+// since more work is done in the mark phase. This tension is resolved
+// by allocating white until the mark phase is approaching its end and
+// then allocating black for the remainder of the mark phase.
+var gcBlackenPromptly bool
+
+const (
+	_GCoff             = iota // GC not running; sweeping in background, write barrier disabled
+	_GCstw                    // unused state
+	_GCscan                   // GC collecting roots into workbufs, write barrier ENABLED
+	_GCmark                   // GC marking from workbufs, write barrier ENABLED
+	_GCmarktermination        // GC mark termination: allocate black, P's help GC, write barrier ENABLED
+)
+
+//go:nosplit
+func setGCPhase(x uint32) {
+	atomicstore(&gcphase, x)
+	writeBarrierEnabled = gcphase == _GCmark || gcphase == _GCmarktermination || gcphase == _GCscan
+}
+
+// gcMarkWorkerMode represents the mode that a concurrent mark worker
+// should operate in.
+//
+// Concurrent marking happens through four different mechanisms. One
+// is mutator assists, which happen in response to allocations and are
+// not scheduled. The other three are variations in the per-P mark
+// workers and are distinguished by gcMarkWorkerMode.
+type gcMarkWorkerMode int
+
+const (
+	// gcMarkWorkerDedicatedMode indicates that the P of a mark
+	// worker is dedicated to running that mark worker. The mark
+	// worker should run without preemption until concurrent mark
+	// is done.
+	gcMarkWorkerDedicatedMode gcMarkWorkerMode = iota
+
+	// gcMarkWorkerFractionalMode indicates that a P is currently
+	// running the "fractional" mark worker. The fractional worker
+	// is necessary when GOMAXPROCS*gcGoalUtilization is not an
+	// integer. The fractional worker should run until it is
+	// preempted and will be scheduled to pick up the fractional
+	// part of GOMAXPROCS*gcGoalUtilization.
+	gcMarkWorkerFractionalMode
+
+	// gcMarkWorkerIdleMode indicates that a P is running the mark
+	// worker because it has nothing else to do. The idle worker
+	// should run until it is preempted and account its time
+	// against gcController.idleMarkTime.
+	gcMarkWorkerIdleMode
+)
+
+// gcController implements the GC pacing controller that determines
+// when to trigger concurrent garbage collection and how much marking
+// work to do in mutator assists and background marking.
+//
+// It uses a feedback control algorithm to adjust the memstats.next_gc
+// trigger based on the heap growth and GC CPU utilization each cycle.
+// This algorithm optimizes for heap growth to match GOGC and for CPU
+// utilization between assist and background marking to be 25% of
+// GOMAXPROCS. The high-level design of this algorithm is documented
+// at https://golang.org/s/go15gcpacing.
+var gcController = gcControllerState{
+	// Initial trigger ratio guess.
+	triggerRatio: 7 / 8.0,
+}
+
+type gcControllerState struct {
+	// scanWork is the total scan work performed this cycle. This
+	// is updated atomically during the cycle. Updates may be
+	// batched arbitrarily, since the value is only read at the
+	// end of the cycle.
+	//
+	// Currently this is the bytes of heap scanned. For most uses,
+	// this is an opaque unit of work, but for estimation the
+	// definition is important.
+	scanWork int64
+
+	// bgScanCredit is the scan work credit accumulated by the
+	// concurrent background scan. This credit is accumulated by
+	// the background scan and stolen by mutator assists. This is
+	// updated atomically. Updates occur in bounded batches, since
+	// it is both written and read throughout the cycle.
+	bgScanCredit int64
+
+	// assistTime is the nanoseconds spent in mutator assists
+	// during this cycle. This is updated atomically. Updates
+	// occur in bounded batches, since it is both written and read
+	// throughout the cycle.
+	assistTime int64
+
+	// dedicatedMarkTime is the nanoseconds spent in dedicated
+	// mark workers during this cycle. This is updated atomically
+	// at the end of the concurrent mark phase.
+	dedicatedMarkTime int64
+
+	// fractionalMarkTime is the nanoseconds spent in the
+	// fractional mark worker during this cycle. This is updated
+	// atomically throughout the cycle and will be up-to-date if
+	// the fractional mark worker is not currently running.
+	fractionalMarkTime int64
+
+	// idleMarkTime is the nanoseconds spent in idle marking
+	// during this cycle. This is updated atomically throughout
+	// the cycle.
+	idleMarkTime int64
+
+	// bgMarkStartTime is the absolute start time in nanoseconds
+	// that the background mark phase started.
+	bgMarkStartTime int64
+
+	// assistTime is the absolute start time in nanoseconds that
+	// mutator assists were enabled.
+	assistStartTime int64
+
+	// heapGoal is the goal memstats.heap_live for when this cycle
+	// ends. This is computed at the beginning of each cycle.
+	heapGoal uint64
+
+	// dedicatedMarkWorkersNeeded is the number of dedicated mark
+	// workers that need to be started. This is computed at the
+	// beginning of each cycle and decremented atomically as
+	// dedicated mark workers get started.
+	dedicatedMarkWorkersNeeded int64
+
+	// assistRatio is the ratio of allocated bytes to scan work
+	// that should be performed by mutator assists. This is
+	// computed at the beginning of each cycle and updated every
+	// time heap_scan is updated.
+	assistRatio float64
+
+	// fractionalUtilizationGoal is the fraction of wall clock
+	// time that should be spent in the fractional mark worker.
+	// For example, if the overall mark utilization goal is 25%
+	// and GOMAXPROCS is 6, one P will be a dedicated mark worker
+	// and this will be set to 0.5 so that 50% of the time some P
+	// is in a fractional mark worker. This is computed at the
+	// beginning of each cycle.
+	fractionalUtilizationGoal float64
+
+	// triggerRatio is the heap growth ratio at which the garbage
+	// collection cycle should start. E.g., if this is 0.6, then
+	// GC should start when the live heap has reached 1.6 times
+	// the heap size marked by the previous cycle. This is updated
+	// at the end of of each cycle.
+	triggerRatio float64
+
+	_ [_CacheLineSize]byte
+
+	// fractionalMarkWorkersNeeded is the number of fractional
+	// mark workers that need to be started. This is either 0 or
+	// 1. This is potentially updated atomically at every
+	// scheduling point (hence it gets its own cache line).
+	fractionalMarkWorkersNeeded int64
+
+	_ [_CacheLineSize]byte
+}
+
+// startCycle resets the GC controller's state and computes estimates
+// for a new GC cycle. The caller must hold worldsema.
+func (c *gcControllerState) startCycle() {
+	c.scanWork = 0
+	c.bgScanCredit = 0
+	c.assistTime = 0
+	c.dedicatedMarkTime = 0
+	c.fractionalMarkTime = 0
+	c.idleMarkTime = 0
+
+	// If this is the first GC cycle or we're operating on a very
+	// small heap, fake heap_marked so it looks like next_gc is
+	// the appropriate growth from heap_marked, even though the
+	// real heap_marked may not have a meaningful value (on the
+	// first cycle) or may be much smaller (resulting in a large
+	// error response).
+	if memstats.next_gc <= heapminimum {
+		memstats.heap_marked = uint64(float64(memstats.next_gc) / (1 + c.triggerRatio))
+		memstats.heap_reachable = memstats.heap_marked
+	}
+
+	// Compute the heap goal for this cycle
+	c.heapGoal = memstats.heap_reachable + memstats.heap_reachable*uint64(gcpercent)/100
+
+	// Compute the total mark utilization goal and divide it among
+	// dedicated and fractional workers.
+	totalUtilizationGoal := float64(gomaxprocs) * gcGoalUtilization
+	c.dedicatedMarkWorkersNeeded = int64(totalUtilizationGoal)
+	c.fractionalUtilizationGoal = totalUtilizationGoal - float64(c.dedicatedMarkWorkersNeeded)
+	if c.fractionalUtilizationGoal > 0 {
+		c.fractionalMarkWorkersNeeded = 1
+	} else {
+		c.fractionalMarkWorkersNeeded = 0
+	}
+
+	// Clear per-P state
+	for _, p := range &allp {
+		if p == nil {
+			break
+		}
+		p.gcAssistTime = 0
+	}
+
+	// Compute initial values for controls that are updated
+	// throughout the cycle.
+	c.revise()
+
+	if debug.gcpacertrace > 0 {
+		print("pacer: assist ratio=", c.assistRatio,
+			" (scan ", memstats.heap_scan>>20, " MB in ",
+			work.initialHeapLive>>20, "->",
+			c.heapGoal>>20, " MB)",
+			" workers=", c.dedicatedMarkWorkersNeeded,
+			"+", c.fractionalMarkWorkersNeeded, "\n")
+	}
+}
+
+// revise updates the assist ratio during the GC cycle to account for
+// improved estimates. This should be called either under STW or
+// whenever memstats.heap_scan is updated (with mheap_.lock held).
+func (c *gcControllerState) revise() {
+	// Compute the expected scan work. This is a strict upper
+	// bound on the possible scan work in the current heap.
+	//
+	// You might consider dividing this by 2 (or by
+	// (100+GOGC)/100) to counter this over-estimation, but
+	// benchmarks show that this has almost no effect on mean
+	// mutator utilization, heap size, or assist time and it
+	// introduces the danger of under-estimating and letting the
+	// mutator outpace the garbage collector.
+	scanWorkExpected := memstats.heap_scan
+
+	// Compute the mutator assist ratio so by the time the mutator
+	// allocates the remaining heap bytes up to next_gc, it will
+	// have done (or stolen) the estimated amount of scan work.
+	heapDistance := int64(c.heapGoal) - int64(work.initialHeapLive)
+	if heapDistance <= 1024*1024 {
+		// heapDistance can be negative if GC start is delayed
+		// or if the allocation that pushed heap_live over
+		// next_gc is large or if the trigger is really close
+		// to GOGC. We don't want to set the assist negative
+		// (or divide by zero, or set it really high), so
+		// enforce a minimum on the distance.
+		heapDistance = 1024 * 1024
+	}
+	c.assistRatio = float64(scanWorkExpected) / float64(heapDistance)
+}
+
+// endCycle updates the GC controller state at the end of the
+// concurrent part of the GC cycle.
+func (c *gcControllerState) endCycle() {
+	h_t := c.triggerRatio // For debugging
+
+	// Proportional response gain for the trigger controller. Must
+	// be in [0, 1]. Lower values smooth out transient effects but
+	// take longer to respond to phase changes. Higher values
+	// react to phase changes quickly, but are more affected by
+	// transient changes. Values near 1 may be unstable.
+	const triggerGain = 0.5
+
+	// Compute next cycle trigger ratio. First, this computes the
+	// "error" for this cycle; that is, how far off the trigger
+	// was from what it should have been, accounting for both heap
+	// growth and GC CPU utilization. We compute the actual heap
+	// growth during this cycle and scale that by how far off from
+	// the goal CPU utilization we were (to estimate the heap
+	// growth if we had the desired CPU utilization). The
+	// difference between this estimate and the GOGC-based goal
+	// heap growth is the error.
+	//
+	// TODO(austin): next_gc is based on heap_reachable, not
+	// heap_marked, which means the actual growth ratio
+	// technically isn't comparable to the trigger ratio.
+	goalGrowthRatio := float64(gcpercent) / 100
+	actualGrowthRatio := float64(memstats.heap_live)/float64(memstats.heap_marked) - 1
+	assistDuration := nanotime() - c.assistStartTime
+
+	// Assume background mark hit its utilization goal.
+	utilization := gcGoalUtilization
+	// Add assist utilization; avoid divide by zero.
+	if assistDuration > 0 {
+		utilization += float64(c.assistTime) / float64(assistDuration*int64(gomaxprocs))
+	}
+
+	triggerError := goalGrowthRatio - c.triggerRatio - utilization/gcGoalUtilization*(actualGrowthRatio-c.triggerRatio)
+
+	// Finally, we adjust the trigger for next time by this error,
+	// damped by the proportional gain.
+	c.triggerRatio += triggerGain * triggerError
+	if c.triggerRatio < 0 {
+		// This can happen if the mutator is allocating very
+		// quickly or the GC is scanning very slowly.
+		c.triggerRatio = 0
+	} else if c.triggerRatio > goalGrowthRatio*0.95 {
+		// Ensure there's always a little margin so that the
+		// mutator assist ratio isn't infinity.
+		c.triggerRatio = goalGrowthRatio * 0.95
+	}
+
+	if debug.gcpacertrace > 0 {
+		// Print controller state in terms of the design
+		// document.
+		H_m_prev := memstats.heap_marked
+		H_T := memstats.next_gc
+		h_a := actualGrowthRatio
+		H_a := memstats.heap_live
+		h_g := goalGrowthRatio
+		H_g := int64(float64(H_m_prev) * (1 + h_g))
+		u_a := utilization
+		u_g := gcGoalUtilization
+		W_a := c.scanWork
+		print("pacer: H_m_prev=", H_m_prev,
+			" h_t=", h_t, " H_T=", H_T,
+			" h_a=", h_a, " H_a=", H_a,
+			" h_g=", h_g, " H_g=", H_g,
+			" u_a=", u_a, " u_g=", u_g,
+			" W_a=", W_a,
+			" goalΔ=", goalGrowthRatio-h_t,
+			" actualΔ=", h_a-h_t,
+			" u_a/u_g=", u_a/u_g,
+			"\n")
+	}
+}
+
+// findRunnableGCWorker returns the background mark worker for _p_ if it
+// should be run. This must only be called when gcBlackenEnabled != 0.
+func (c *gcControllerState) findRunnableGCWorker(_p_ *p) *g {
+	if gcBlackenEnabled == 0 {
+		throw("gcControllerState.findRunnable: blackening not enabled")
+	}
+	if _p_.gcBgMarkWorker == nil {
+		throw("gcControllerState.findRunnable: no background mark worker")
+	}
+	if work.bgMark1.done != 0 && work.bgMark2.done != 0 {
+		// Background mark is done. Don't schedule background
+		// mark worker any more. (This is not just an
+		// optimization. Without this we can spin scheduling
+		// the background worker and having it return
+		// immediately with no work to do.)
+		return nil
+	}
+
+	decIfPositive := func(ptr *int64) bool {
+		if *ptr > 0 {
+			if xaddint64(ptr, -1) >= 0 {
+				return true
+			}
+			// We lost a race
+			xaddint64(ptr, +1)
+		}
+		return false
+	}
+
+	if decIfPositive(&c.dedicatedMarkWorkersNeeded) {
+		// This P is now dedicated to marking until the end of
+		// the concurrent mark phase.
+		_p_.gcMarkWorkerMode = gcMarkWorkerDedicatedMode
+		// TODO(austin): This P isn't going to run anything
+		// else for a while, so kick everything out of its run
+		// queue.
+	} else {
+		if _p_.gcw.wbuf == 0 && work.full == 0 && work.partial == 0 {
+			// No work to be done right now. This can
+			// happen at the end of the mark phase when
+			// there are still assists tapering off. Don't
+			// bother running background mark because
+			// it'll just return immediately.
+			if work.nwait == work.nproc {
+				// There are also no workers, which
+				// means we've reached a completion point.
+				// There may not be any workers to
+				// signal it, so signal it here.
+				readied := false
+				if gcBlackenPromptly {
+					if work.bgMark1.done == 0 {
+						throw("completing mark 2, but bgMark1.done == 0")
+					}
+					readied = work.bgMark2.complete()
+				} else {
+					readied = work.bgMark1.complete()
+				}
+				if readied {
+					// complete just called ready,
+					// but we're inside the
+					// scheduler. Let it know that
+					// that's okay.
+					resetspinning()
+				}
+			}
+			return nil
+		}
+		if !decIfPositive(&c.fractionalMarkWorkersNeeded) {
+			// No more workers are need right now.
+			return nil
+		}
+
+		// This P has picked the token for the fractional worker.
+		// Is the GC currently under or at the utilization goal?
+		// If so, do more work.
+		//
+		// We used to check whether doing one time slice of work
+		// would remain under the utilization goal, but that has the
+		// effect of delaying work until the mutator has run for
+		// enough time slices to pay for the work. During those time
+		// slices, write barriers are enabled, so the mutator is running slower.
+		// Now instead we do the work whenever we're under or at the
+		// utilization work and pay for it by letting the mutator run later.
+		// This doesn't change the overall utilization averages, but it
+		// front loads the GC work so that the GC finishes earlier and
+		// write barriers can be turned off sooner, effectively giving
+		// the mutator a faster machine.
+		//
+		// The old, slower behavior can be restored by setting
+		//	gcForcePreemptNS = forcePreemptNS.
+		const gcForcePreemptNS = 0
+
+		// TODO(austin): We could fast path this and basically
+		// eliminate contention on c.fractionalMarkWorkersNeeded by
+		// precomputing the minimum time at which it's worth
+		// next scheduling the fractional worker. Then Ps
+		// don't have to fight in the window where we've
+		// passed that deadline and no one has started the
+		// worker yet.
+		//
+		// TODO(austin): Shorter preemption interval for mark
+		// worker to improve fairness and give this
+		// finer-grained control over schedule?
+		now := nanotime() - gcController.bgMarkStartTime
+		then := now + gcForcePreemptNS
+		timeUsed := c.fractionalMarkTime + gcForcePreemptNS
+		if then > 0 && float64(timeUsed)/float64(then) > c.fractionalUtilizationGoal {
+			// Nope, we'd overshoot the utilization goal
+			xaddint64(&c.fractionalMarkWorkersNeeded, +1)
+			return nil
+		}
+		_p_.gcMarkWorkerMode = gcMarkWorkerFractionalMode
+	}
+
+	// Run the background mark worker
+	gp := _p_.gcBgMarkWorker
+	casgstatus(gp, _Gwaiting, _Grunnable)
+	if trace.enabled {
+		traceGoUnpark(gp, 0)
+	}
+	return gp
+}
+
+// gcGoalUtilization is the goal CPU utilization for background
+// marking as a fraction of GOMAXPROCS.
+const gcGoalUtilization = 0.25
+
+// gcBgCreditSlack is the amount of scan work credit background
+// scanning can accumulate locally before updating
+// gcController.bgScanCredit. Lower values give mutator assists more
+// accurate accounting of background scanning. Higher values reduce
+// memory contention.
+const gcBgCreditSlack = 2000
+
+// gcAssistTimeSlack is the nanoseconds of mutator assist time that
+// can accumulate on a P before updating gcController.assistTime.
+const gcAssistTimeSlack = 5000
+
+// Determine whether to initiate a GC.
+// If the GC is already working no need to trigger another one.
+// This should establish a feedback loop where if the GC does not
+// have sufficient time to complete then more memory will be
+// requested from the OS increasing heap size thus allow future
+// GCs more time to complete.
+// memstat.heap_live read has a benign race.
+// A false negative simple does not start a GC, a false positive
+// will start a GC needlessly. Neither have correctness issues.
+func shouldtriggergc() bool {
+	return memstats.heap_live >= memstats.next_gc && atomicloaduint(&bggc.working) == 0
+}
+
+// bgMarkSignal synchronizes the GC coordinator and background mark workers.
+type bgMarkSignal struct {
+	// Workers race to cas to 1. Winner signals coordinator.
+	done uint32
+	// Coordinator to wake up.
+	lock mutex
+	g    *g
+	wake bool
+}
+
+func (s *bgMarkSignal) wait() {
+	lock(&s.lock)
+	if s.wake {
+		// Wakeup already happened
+		unlock(&s.lock)
+	} else {
+		s.g = getg()
+		goparkunlock(&s.lock, "mark wait (idle)", traceEvGoBlock, 1)
+	}
+	s.wake = false
+	s.g = nil
+}
+
+// complete signals the completion of this phase of marking. This can
+// be called multiple times during a cycle; only the first call has
+// any effect.
+//
+// The caller should arrange to deschedule itself as soon as possible
+// after calling complete in order to let the coordinator goroutine
+// run.
+func (s *bgMarkSignal) complete() bool {
+	if cas(&s.done, 0, 1) {
+		// This is the first worker to reach this completion point.
+		// Signal the main GC goroutine.
+		lock(&s.lock)
+		if s.g == nil {
+			// It hasn't parked yet.
+			s.wake = true
+		} else {
+			ready(s.g, 0)
+		}
+		unlock(&s.lock)
+		return true
+	}
+	return false
+}
+
+func (s *bgMarkSignal) clear() {
+	s.done = 0
+}
+
+var work struct {
+	full  uint64 // lock-free list of full blocks workbuf
+	empty uint64 // lock-free list of empty blocks workbuf
+	// TODO(rlh): partial no longer used, remove. (issue #11922)
+	partial uint64                // lock-free list of partially filled blocks workbuf
+	pad0    [_CacheLineSize]uint8 // prevents false-sharing between full/empty and nproc/nwait
+	nproc   uint32
+	tstart  int64
+	nwait   uint32
+	ndone   uint32
+	alldone note
+	markfor *parfor
+
+	bgMarkReady note   // signal background mark worker has started
+	bgMarkDone  uint32 // cas to 1 when at a background mark completion point
+	// Background mark completion signaling
+
+	// Coordination for the 2 parts of the mark phase.
+	bgMark1 bgMarkSignal
+	bgMark2 bgMarkSignal
+
+	// Copy of mheap.allspans for marker or sweeper.
+	spans []*mspan
+
+	// totaltime is the CPU nanoseconds spent in GC since the
+	// program started if debug.gctrace > 0.
+	totaltime int64
+
+	// bytesMarked is the number of bytes marked this cycle. This
+	// includes bytes blackened in scanned objects, noscan objects
+	// that go straight to black, and permagrey objects scanned by
+	// markroot during the concurrent scan phase. This is updated
+	// atomically during the cycle. Updates may be batched
+	// arbitrarily, since the value is only read at the end of the
+	// cycle.
+	//
+	// Because of benign races during marking, this number may not
+	// be the exact number of marked bytes, but it should be very
+	// close.
+	bytesMarked uint64
+
+	// initialHeapLive is the value of memstats.heap_live at the
+	// beginning of this GC cycle.
+	initialHeapLive uint64
+}
+
+// GC runs a garbage collection and blocks the caller until the
+// garbage collection is complete. It may also block the entire
+// program.
+func GC() {
+	startGC(gcForceBlockMode, false)
+}
+
+const (
+	gcBackgroundMode = iota // concurrent GC
+	gcForceMode             // stop-the-world GC now
+	gcForceBlockMode        // stop-the-world GC now and wait for sweep
+)
+
+// startGC starts a GC cycle. If mode is gcBackgroundMode, this will
+// start GC in the background and return. Otherwise, this will block
+// until the new GC cycle is started and finishes. If forceTrigger is
+// true, it indicates that GC should be started regardless of the
+// current heap size.
+func startGC(mode int, forceTrigger bool) {
+	// The gc is turned off (via enablegc) until the bootstrap has completed.
+	// Also, malloc gets called in the guts of a number of libraries that might be
+	// holding locks. To avoid deadlocks during stop-the-world, don't bother
+	// trying to run gc while holding a lock. The next mallocgc without a lock
+	// will do the gc instead.
+	mp := acquirem()
+	if gp := getg(); gp == mp.g0 || mp.locks > 1 || mp.preemptoff != "" || !memstats.enablegc || panicking != 0 || gcpercent < 0 {
+		releasem(mp)
+		return
+	}
+	releasem(mp)
+	mp = nil
+
+	if debug.gcstoptheworld == 1 {
+		mode = gcForceMode
+	} else if debug.gcstoptheworld == 2 {
+		mode = gcForceBlockMode
+	}
+
+	if mode != gcBackgroundMode {
+		// special synchronous cases
+		gc(mode)
+		return
+	}
+
+	// trigger concurrent GC
+	readied := false
+	lock(&bggc.lock)
+	// The trigger was originally checked speculatively, so
+	// recheck that this really should trigger GC. (For example,
+	// we may have gone through a whole GC cycle since the
+	// speculative check.)
+	if !(forceTrigger || shouldtriggergc()) {
+		unlock(&bggc.lock)
+		return
+	}
+	if !bggc.started {
+		bggc.working = 1
+		bggc.started = true
+		readied = true
+		go backgroundgc()
+	} else if bggc.working == 0 {
+		bggc.working = 1
+		readied = true
+		ready(bggc.g, 0)
+	}
+	unlock(&bggc.lock)
+	if readied {
+		// This G just started or ready()d the GC goroutine.
+		// Switch directly to it by yielding.
+		Gosched()
+	}
+}
+
+// State of the background concurrent GC goroutine.
+var bggc struct {
+	lock    mutex
+	g       *g
+	working uint
+	started bool
+}
+
+// backgroundgc is running in a goroutine and does the concurrent GC work.
+// bggc holds the state of the backgroundgc.
+func backgroundgc() {
+	bggc.g = getg()
+	for {
+		gc(gcBackgroundMode)
+		lock(&bggc.lock)
+		bggc.working = 0
+		goparkunlock(&bggc.lock, "Concurrent GC wait", traceEvGoBlock, 1)
+	}
+}
+
+func gc(mode int) {
+	// Timing/utilization tracking
+	var stwprocs, maxprocs int32
+	var tSweepTerm, tScan, tInstallWB, tMark, tMarkTerm int64
+
+	// debug.gctrace variables
+	var heap0, heap1, heap2, heapGoal uint64
+
+	// memstats statistics
+	var now, pauseStart, pauseNS int64
+
+	// Ok, we're doing it!  Stop everybody else
+	semacquire(&worldsema, false)
+
+	// Pick up the remaining unswept/not being swept spans concurrently
+	//
+	// This shouldn't happen if we're being invoked in background
+	// mode since proportional sweep should have just finished
+	// sweeping everything, but rounding errors, etc, may leave a
+	// few spans unswept. In forced mode, this is necessary since
+	// GC can be forced at any point in the sweeping cycle.
+	for gosweepone() != ^uintptr(0) {
+		sweep.nbgsweep++
+	}
+
+	if trace.enabled {
+		traceGCStart()
+	}
+
+	if mode == gcBackgroundMode {
+		gcBgMarkStartWorkers()
+	}
+	now = nanotime()
+	stwprocs, maxprocs = gcprocs(), gomaxprocs
+	tSweepTerm = now
+	heap0 = memstats.heap_live
+
+	pauseStart = now
+	systemstack(stopTheWorldWithSema)
+	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()
+
+	gcResetMarkState()
+
+	if mode == gcBackgroundMode { // Do as much work concurrently as possible
+		gcController.startCycle()
+		heapGoal = gcController.heapGoal
+
+		systemstack(func() {
+			// Enter scan phase. This enables write
+			// barriers to track changes to stack frames
+			// above the stack barrier.
+			//
+			// TODO: This has evolved to the point where
+			// we carefully ensure invariants we no longer
+			// depend on. Either:
+			//
+			// 1) Enable full write barriers for the scan,
+			// but eliminate the ragged barrier below
+			// (since the start the world ensures all Ps
+			// have observed the write barrier enable) and
+			// consider draining during the scan.
+			//
+			// 2) Only enable write barriers for writes to
+			// the stack at this point, and then enable
+			// write barriers for heap writes when we
+			// enter the mark phase. This means we cannot
+			// drain in the scan phase and must perform a
+			// ragged barrier to ensure all Ps have
+			// enabled heap write barriers before we drain
+			// or enable assists.
+			//
+			// 3) Don't install stack barriers over frame
+			// boundaries where there are up-pointers.
+			setGCPhase(_GCscan)
+
+			gcBgMarkPrepare() // Must happen before assist enable.
+
+			// At this point all Ps have enabled the write
+			// barrier, thus maintaining the no white to
+			// black invariant. Enable mutator assists to
+			// put back-pressure on fast allocating
+			// mutators.
+			atomicstore(&gcBlackenEnabled, 1)
+
+			// Concurrent scan.
+			startTheWorldWithSema()
+			now = nanotime()
+			pauseNS += now - pauseStart
+			tScan = now
+			gcController.assistStartTime = now
+			gcscan_m()
+
+			// Enter mark phase.
+			tInstallWB = nanotime()
+			setGCPhase(_GCmark)
+			// Ensure all Ps have observed the phase
+			// change and have write barriers enabled
+			// before any blackening occurs.
+			forEachP(func(*p) {})
+		})
+		// Concurrent mark.
+		tMark = nanotime()
+
+		// Enable background mark workers and wait for
+		// background mark completion.
+		gcController.bgMarkStartTime = nanotime()
+		work.bgMark1.clear()
+		work.bgMark1.wait()
+
+		// The global work list is empty, but there can still be work
+		// sitting in the per-P work caches and there can be more
+		// objects reachable from global roots since they don't have write
+		// barriers. Rescan some roots and flush work caches.
+		systemstack(func() {
+			// rescan global data and bss.
+			markroot(nil, _RootData)
+			markroot(nil, _RootBss)
+
+			// Disallow caching workbufs.
+			gcBlackenPromptly = true
+
+			// Flush all currently cached workbufs. This
+			// also forces any remaining background
+			// workers out of their loop.
+			forEachP(func(_p_ *p) {
+				_p_.gcw.dispose()
+			})
+		})
+
+		// Wait for this more aggressive background mark to complete.
+		work.bgMark2.clear()
+		work.bgMark2.wait()
+
+		// Begin mark termination.
+		now = nanotime()
+		tMarkTerm = now
+		pauseStart = now
+		systemstack(stopTheWorldWithSema)
+		// 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.
+
+		// Flush the gcWork caches. This must be done before
+		// endCycle since endCycle depends on statistics kept
+		// in these caches.
+		gcFlushGCWork()
+
+		gcController.endCycle()
+	} else {
+		// For non-concurrent GC (mode != gcBackgroundMode)
+		// The g stacks have not been scanned so clear g state
+		// such that mark termination scans all stacks.
+		gcResetGState()
+
+		t := nanotime()
+		tScan, tInstallWB, tMark, tMarkTerm = t, t, t, t
+		heapGoal = heap0
+	}
+
+	// World is stopped.
+	// Start marktermination which includes enabling the write barrier.
+	atomicstore(&gcBlackenEnabled, 0)
+	gcBlackenPromptly = false
+	setGCPhase(_GCmarktermination)
+
+	heap1 = memstats.heap_live
+	startTime := nanotime()
+
+	mp := acquirem()
+	mp.preemptoff = "gcing"
+	_g_ := getg()
+	_g_.m.traceback = 2
+	gp := _g_.m.curg
+	casgstatus(gp, _Grunning, _Gwaiting)
+	gp.waitreason = "garbage collection"
+
+	// Run gc on the g0 stack.  We do this so that the g stack
+	// we're currently running on will no longer change.  Cuts
+	// the root set down a bit (g0 stacks are not scanned, and
+	// we don't need to scan gc's internal state).  We also
+	// need to switch to g0 so we can shrink the stack.
+	systemstack(func() {
+		gcMark(startTime)
+		// Must return immediately.
+		// The outer function's stack may have moved
+		// during gcMark (it shrinks stacks, including the
+		// outer function's stack), so we must not refer
+		// to any of its variables. Return back to the
+		// non-system stack to pick up the new addresses
+		// before continuing.
+	})
+
+	systemstack(func() {
+		heap2 = work.bytesMarked
+		if debug.gccheckmark > 0 {
+			// Run a full stop-the-world mark using checkmark bits,
+			// to check that we didn't forget to mark anything during
+			// the concurrent mark process.
+			gcResetGState() // Rescan stacks
+			gcResetMarkState()
+			initCheckmarks()
+			gcMark(startTime)
+			clearCheckmarks()
+		}
+
+		// marking is complete so we can turn the write barrier off
+		setGCPhase(_GCoff)
+		gcSweep(mode)
+
+		if debug.gctrace > 1 {
+			startTime = nanotime()
+			// The g stacks have been scanned so
+			// they have gcscanvalid==true and gcworkdone==true.
+			// Reset these so that all stacks will be rescanned.
+			gcResetGState()
+			gcResetMarkState()
+			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.
+			setGCPhase(_GCmarktermination)
+			gcMark(startTime)
+			setGCPhase(_GCoff) // marking is done, turn off wb.
+			gcSweep(mode)
+		}
+	})
+
+	_g_.m.traceback = 0
+	casgstatus(gp, _Gwaiting, _Grunning)
+
+	if trace.enabled {
+		traceGCDone()
+	}
+
+	// all done
+	mp.preemptoff = ""
+
+	if gcphase != _GCoff {
+		throw("gc done but gcphase != _GCoff")
+	}
+
+	// Update timing memstats
+	now, unixNow := nanotime(), unixnanotime()
+	pauseNS += now - pauseStart
+	atomicstore64(&memstats.last_gc, uint64(unixNow)) // must be Unix time to make sense to user
+	memstats.pause_ns[memstats.numgc%uint32(len(memstats.pause_ns))] = uint64(pauseNS)
+	memstats.pause_end[memstats.numgc%uint32(len(memstats.pause_end))] = uint64(unixNow)
+	memstats.pause_total_ns += uint64(pauseNS)
+
+	// Update work.totaltime.
+	sweepTermCpu := int64(stwprocs) * (tScan - tSweepTerm)
+	scanCpu := tInstallWB - tScan
+	installWBCpu := int64(0)
+	// We report idle marking time below, but omit it from the
+	// overall utilization here since it's "free".
+	markCpu := gcController.assistTime + gcController.dedicatedMarkTime + gcController.fractionalMarkTime
+	markTermCpu := int64(stwprocs) * (now - tMarkTerm)
+	cycleCpu := sweepTermCpu + scanCpu + installWBCpu + markCpu + markTermCpu
+	work.totaltime += cycleCpu
+
+	// Compute overall GC CPU utilization.
+	totalCpu := sched.totaltime + (now-sched.procresizetime)*int64(gomaxprocs)
+	memstats.gc_cpu_fraction = float64(work.totaltime) / float64(totalCpu)
+
+	memstats.numgc++
+
+	systemstack(startTheWorldWithSema)
+	semrelease(&worldsema)
+
+	releasem(mp)
+	mp = nil
+
+	if debug.gctrace > 0 {
+		tEnd := now
+		util := int(memstats.gc_cpu_fraction * 100)
+
+		var sbuf [24]byte
+		printlock()
+		print("gc ", memstats.numgc,
+			" @", string(itoaDiv(sbuf[:], uint64(tSweepTerm-runtimeInitTime)/1e6, 3)), "s ",
+			util, "%: ")
+		prev := tSweepTerm
+		for i, ns := range []int64{tScan, tInstallWB, tMark, tMarkTerm, tEnd} {
+			if i != 0 {
+				print("+")
+			}
+			print(string(fmtNSAsMS(sbuf[:], uint64(ns-prev))))
+			prev = ns
+		}
+		print(" ms clock, ")
+		for i, ns := range []int64{sweepTermCpu, scanCpu, installWBCpu, gcController.assistTime, gcController.dedicatedMarkTime + gcController.fractionalMarkTime, gcController.idleMarkTime, markTermCpu} {
+			if i == 4 || i == 5 {
+				// Separate mark time components with /.
+				print("/")
+			} else if i != 0 {
+				print("+")
+			}
+			print(string(fmtNSAsMS(sbuf[:], uint64(ns))))
+		}
+		print(" ms cpu, ",
+			heap0>>20, "->", heap1>>20, "->", heap2>>20, " MB, ",
+			heapGoal>>20, " MB goal, ",
+			maxprocs, " P")
+		if mode != gcBackgroundMode {
+			print(" (forced)")
+		}
+		print("\n")
+		printunlock()
+	}
+	sweep.nbgsweep = 0
+	sweep.npausesweep = 0
+
+	// now that gc is done, kick off finalizer thread if needed
+	if !concurrentSweep {
+		// give the queued finalizers, if any, a chance to run
+		Gosched()
+	}
+}
+
+// gcBgMarkStartWorkers prepares background mark worker goroutines.
+// These goroutines will not run until the mark phase, but they must
+// be started while the work is not stopped and from a regular G
+// stack. The caller must hold worldsema.
+func gcBgMarkStartWorkers() {
+	// Background marking is performed by per-P G's. Ensure that
+	// each P has a background GC G.
+	for _, p := range &allp {
+		if p == nil || p.status == _Pdead {
+			break
+		}
+		if p.gcBgMarkWorker == nil {
+			go gcBgMarkWorker(p)
+			notetsleepg(&work.bgMarkReady, -1)
+			noteclear(&work.bgMarkReady)
+		}
+	}
+}
+
+// gcBgMarkPrepare sets up state for background marking.
+// Mutator assists must not yet be enabled.
+func gcBgMarkPrepare() {
+	// Background marking will stop when the work queues are empty
+	// and there are no more workers (note that, since this is
+	// concurrent, this may be a transient state, but mark
+	// termination will clean it up). Between background workers
+	// and assists, we don't really know how many workers there
+	// will be, so we pretend to have an arbitrarily large number
+	// of workers, almost all of which are "waiting". While a
+	// worker is working it decrements nwait. If nproc == nwait,
+	// there are no workers.
+	work.nproc = ^uint32(0)
+	work.nwait = ^uint32(0)
+
+	// Reset background mark completion points.
+	work.bgMark1.done = 1
+	work.bgMark2.done = 1
+}
+
+func gcBgMarkWorker(p *p) {
+	// Register this G as the background mark worker for p.
+	if p.gcBgMarkWorker != nil {
+		throw("P already has a background mark worker")
+	}
+	gp := getg()
+
+	mp := acquirem()
+	p.gcBgMarkWorker = gp
+	// After this point, the background mark worker is scheduled
+	// cooperatively by gcController.findRunnable. Hence, it must
+	// never be preempted, as this would put it into _Grunnable
+	// and put it on a run queue. Instead, when the preempt flag
+	// is set, this puts itself into _Gwaiting to be woken up by
+	// gcController.findRunnable at the appropriate time.
+	notewakeup(&work.bgMarkReady)
+	for {
+		// Go to sleep until woken by gcContoller.findRunnable.
+		// We can't releasem yet since even the call to gopark
+		// may be preempted.
+		gopark(func(g *g, mp unsafe.Pointer) bool {
+			releasem((*m)(mp))
+			return true
+		}, unsafe.Pointer(mp), "mark worker (idle)", traceEvGoBlock, 0)
+
+		// Loop until the P dies and disassociates this
+		// worker. (The P may later be reused, in which case
+		// it will get a new worker.)
+		if p.gcBgMarkWorker != gp {
+			break
+		}
+
+		// Disable preemption so we can use the gcw. If the
+		// scheduler wants to preempt us, we'll stop draining,
+		// dispose the gcw, and then preempt.
+		mp = acquirem()
+
+		if gcBlackenEnabled == 0 {
+			throw("gcBgMarkWorker: blackening not enabled")
+		}
+
+		startTime := nanotime()
+
+		decnwait := xadd(&work.nwait, -1)
+		if decnwait == work.nproc {
+			println("runtime: work.nwait=", decnwait, "work.nproc=", work.nproc)
+			throw("work.nwait was > work.nproc")
+		}
+
+		done := false
+		switch p.gcMarkWorkerMode {
+		default:
+			throw("gcBgMarkWorker: unexpected gcMarkWorkerMode")
+		case gcMarkWorkerDedicatedMode:
+			gcDrain(&p.gcw, gcBgCreditSlack)
+			// gcDrain did the xadd(&work.nwait +1) to
+			// match the decrement above. It only returns
+			// at a mark completion point.
+			done = true
+			if !p.gcw.empty() {
+				throw("gcDrain returned with buffer")
+			}
+		case gcMarkWorkerFractionalMode, gcMarkWorkerIdleMode:
+			gcDrainUntilPreempt(&p.gcw, gcBgCreditSlack)
+
+			// If we are nearing the end of mark, dispose
+			// of the cache promptly. We must do this
+			// before signaling that we're no longer
+			// working so that other workers can't observe
+			// no workers and no work while we have this
+			// cached, and before we compute done.
+			if gcBlackenPromptly {
+				p.gcw.dispose()
+			}
+
+			// Was this the last worker and did we run out
+			// of work?
+			incnwait := xadd(&work.nwait, +1)
+			if incnwait > work.nproc {
+				println("runtime: p.gcMarkWorkerMode=", p.gcMarkWorkerMode,
+					"work.nwait=", incnwait, "work.nproc=", work.nproc)
+				throw("work.nwait > work.nproc")
+			}
+			done = incnwait == work.nproc && work.full == 0 && work.partial == 0
+		}
+
+		// If this worker reached a background mark completion
+		// point, signal the main GC goroutine.
+		if done {
+			if gcBlackenPromptly {
+				if work.bgMark1.done == 0 {
+					throw("completing mark 2, but bgMark1.done == 0")
+				}
+				work.bgMark2.complete()
+			} else {
+				work.bgMark1.complete()
+			}
+		}
+
+		duration := nanotime() - startTime
+		switch p.gcMarkWorkerMode {
+		case gcMarkWorkerDedicatedMode:
+			xaddint64(&gcController.dedicatedMarkTime, duration)
+			xaddint64(&gcController.dedicatedMarkWorkersNeeded, 1)
+		case gcMarkWorkerFractionalMode:
+			xaddint64(&gcController.fractionalMarkTime, duration)
+			xaddint64(&gcController.fractionalMarkWorkersNeeded, 1)
+		case gcMarkWorkerIdleMode:
+			xaddint64(&gcController.idleMarkTime, duration)
+		}
+	}
+}
+
+// gcMarkWorkAvailable returns true if executing a mark worker
+// on p is potentially useful.
+func gcMarkWorkAvailable(p *p) bool {
+	if !p.gcw.empty() {
+		return true
+	}
+	if atomicload64(&work.full) != 0 || atomicload64(&work.partial) != 0 {
+		return true // global work available
+	}
+	return false
+}
+
+// gcFlushGCWork disposes the gcWork caches of all Ps. The world must
+// be stopped.
+//go:nowritebarrier
+func gcFlushGCWork() {
+	// Gather all cached GC work. All other Ps are stopped, so
+	// it's safe to manipulate their GC work caches.
+	for i := 0; i < int(gomaxprocs); i++ {
+		allp[i].gcw.dispose()
+	}
+}
+
+// gcMark runs the mark (or, for concurrent GC, mark termination)
+// STW is in effect at this point.
+//TODO go:nowritebarrier
+func gcMark(start_time int64) {
+	if debug.allocfreetrace > 0 {
+		tracegc()
+	}
+
+	if gcphase != _GCmarktermination {
+		throw("in gcMark expecting to see gcphase as _GCmarktermination")
+	}
+	work.tstart = start_time
+
+	gcCopySpans() // TODO(rlh): should this be hoisted and done only once? Right now it is done for normal marking and also for checkmarking.
+
+	// Make sure the per-P gcWork caches are empty. During mark
+	// termination, these caches can still be used temporarily,
+	// but must be disposed to the global lists immediately.
+	gcFlushGCWork()
+
+	work.nwait = 0
+	work.ndone = 0
+	work.nproc = uint32(gcprocs())
+
+	if trace.enabled {
+		traceGCScanStart()
+	}
+
+	parforsetup(work.markfor, work.nproc, uint32(_RootCount+allglen), false, markroot)
+	if work.nproc > 1 {
+		noteclear(&work.alldone)
+		helpgc(int32(work.nproc))
+	}
+
+	gchelperstart()
+	parfordo(work.markfor)
+
+	var gcw gcWork
+	gcDrain(&gcw, -1)
+	gcw.dispose()
+
+	if work.full != 0 {
+		throw("work.full != 0")
+	}
+	if work.partial != 0 {
+		throw("work.partial != 0")
+	}
+
+	if work.nproc > 1 {
+		notesleep(&work.alldone)
+	}
+
+	for i := 0; i < int(gomaxprocs); i++ {
+		if allp[i].gcw.wbuf != 0 {
+			throw("P has cached GC work at end of mark termination")
+		}
+	}
+
+	if trace.enabled {
+		traceGCScanDone()
+	}
+
+	// TODO(austin): This doesn't have to be done during STW, as
+	// long as we block the next GC cycle until this is done. Move
+	// it after we start the world, but before dropping worldsema.
+	// (See issue #11465.)
+	freeStackSpans()
+
+	cachestats()
+
+	// Compute the reachable heap size at the beginning of the
+	// cycle. This is approximately the marked heap size at the
+	// end (which we know) minus the amount of marked heap that
+	// was allocated after marking began (which we don't know, but
+	// is approximately the amount of heap that was allocated
+	// since marking began).
+	allocatedDuringCycle := memstats.heap_live - work.initialHeapLive
+	if work.bytesMarked >= allocatedDuringCycle {
+		memstats.heap_reachable = work.bytesMarked - allocatedDuringCycle
+	} else {
+		// This can happen if most of the allocation during
+		// the cycle never became reachable from the heap.
+		// Just set the reachable heap approximation to 0 and
+		// let the heapminimum kick in below.
+		memstats.heap_reachable = 0
+	}
+
+	// Trigger the next GC cycle when the allocated heap has grown
+	// by triggerRatio over the reachable heap size. Assume that
+	// we're in steady state, so the reachable heap size is the
+	// same now as it was at the beginning of the GC cycle.
+	memstats.next_gc = uint64(float64(memstats.heap_reachable) * (1 + gcController.triggerRatio))
+	if memstats.next_gc < heapminimum {
+		memstats.next_gc = heapminimum
+	}
+	if int64(memstats.next_gc) < 0 {
+		print("next_gc=", memstats.next_gc, " bytesMarked=", work.bytesMarked, " heap_live=", memstats.heap_live, " initialHeapLive=", work.initialHeapLive, "\n")
+		throw("next_gc underflow")
+	}
+
+	// Update other GC heap size stats.
+	memstats.heap_live = work.bytesMarked
+	memstats.heap_marked = work.bytesMarked
+	memstats.heap_scan = uint64(gcController.scanWork)
+
+	minNextGC := memstats.heap_live + sweepMinHeapDistance*uint64(gcpercent)/100
+	if memstats.next_gc < minNextGC {
+		// The allocated heap is already past the trigger.
+		// This can happen if the triggerRatio is very low and
+		// the reachable heap estimate is less than the live
+		// heap size.
+		//
+		// Concurrent sweep happens in the heap growth from
+		// heap_live to next_gc, so bump next_gc up to ensure
+		// that concurrent sweep has some heap growth in which
+		// to perform sweeping before we start the next GC
+		// cycle.
+		memstats.next_gc = minNextGC
+	}
+
+	if trace.enabled {
+		traceHeapAlloc()
+		traceNextGC()
+	}
+}
+
+func gcSweep(mode int) {
+	if gcphase != _GCoff {
+		throw("gcSweep being done but phase is not GCoff")
+	}
+	gcCopySpans()
+
+	lock(&mheap_.lock)
+	mheap_.sweepgen += 2
+	mheap_.sweepdone = 0
+	sweep.spanidx = 0
+	unlock(&mheap_.lock)
+
+	if !_ConcurrentSweep || mode == gcForceBlockMode {
+		// Special case synchronous sweep.
+		// Record that no proportional sweeping has to happen.
+		lock(&mheap_.lock)
+		mheap_.sweepPagesPerByte = 0
+		mheap_.pagesSwept = 0
+		unlock(&mheap_.lock)
+		// Sweep all spans eagerly.
+		for sweepone() != ^uintptr(0) {
+			sweep.npausesweep++
+		}
+		// Do an additional mProf_GC, because all 'free' events are now real as well.
+		mProf_GC()
+		mProf_GC()
+		return
+	}
+
+	// Account how much sweeping needs to be done before the next
+	// GC cycle and set up proportional sweep statistics.
+	var pagesToSweep uintptr
+	for _, s := range work.spans {
+		if s.state == mSpanInUse {
+			pagesToSweep += s.npages
+		}
+	}
+	heapDistance := int64(memstats.next_gc) - int64(memstats.heap_live)
+	// Add a little margin so rounding errors and concurrent
+	// sweep are less likely to leave pages unswept when GC starts.
+	heapDistance -= 1024 * 1024
+	if heapDistance < _PageSize {
+		// Avoid setting the sweep ratio extremely high
+		heapDistance = _PageSize
+	}
+	lock(&mheap_.lock)
+	mheap_.sweepPagesPerByte = float64(pagesToSweep) / float64(heapDistance)
+	mheap_.pagesSwept = 0
+	mheap_.spanBytesAlloc = 0
+	unlock(&mheap_.lock)
+
+	// Background sweep.
+	lock(&sweep.lock)
+	if sweep.parked {
+		sweep.parked = false
+		ready(sweep.g, 0)
+	}
+	unlock(&sweep.lock)
+	mProf_GC()
+}
+
+func gcCopySpans() {
+	// Cache runtime.mheap_.allspans in work.spans to avoid conflicts with
+	// resizing/freeing allspans.
+	// New spans can be created while GC progresses, but they are not garbage for
+	// this round:
+	//  - new stack spans can be created even while the world is stopped.
+	//  - new malloc spans can be created during the concurrent sweep
+	// Even if this is stop-the-world, a concurrent exitsyscall can allocate a stack from heap.
+	lock(&mheap_.lock)
+	// Free the old cached mark array if necessary.
+	if work.spans != nil && &work.spans[0] != &h_allspans[0] {
+		sysFree(unsafe.Pointer(&work.spans[0]), uintptr(len(work.spans))*unsafe.Sizeof(work.spans[0]), &memstats.other_sys)
+	}
+	// Cache the current array for sweeping.
+	mheap_.gcspans = mheap_.allspans
+	work.spans = h_allspans
+	unlock(&mheap_.lock)
+}
+
+// gcResetGState resets the GC state of all G's and returns the length
+// of allgs.
+func gcResetGState() (numgs int) {
+	// This may be called during a concurrent phase, so make sure
+	// allgs doesn't change.
+	lock(&allglock)
+	for _, gp := range allgs {
+		gp.gcscandone = false  // set to true in gcphasework
+		gp.gcscanvalid = false // stack has not been scanned
+		gp.gcalloc = 0
+		gp.gcscanwork = 0
+	}
+	numgs = len(allgs)
+	unlock(&allglock)
+	return
+}
+
+// gcResetMarkState resets state prior to marking (concurrent or STW).
+//
+// TODO(austin): Merge with gcResetGState. See issue #11427.
+func gcResetMarkState() {
+	work.bytesMarked = 0
+	work.initialHeapLive = memstats.heap_live
+}
+
+// Hooks for other packages
+
+var poolcleanup func()
+
+//go:linkname sync_runtime_registerPoolCleanup sync.runtime_registerPoolCleanup
+func sync_runtime_registerPoolCleanup(f func()) {
+	poolcleanup = f
+}
+
+func clearpools() {
+	// clear sync.Pools
+	if poolcleanup != nil {
+		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
+		}
+		// clear tinyalloc pool
+		if c := p.mcache; c != nil {
+			c.tiny = nil
+			c.tinyoffset = 0
+		}
+	}
+}
+
+// Timing
+
+//go:nowritebarrier
+func gchelper() {
+	_g_ := getg()
+	_g_.m.traceback = 2
+	gchelperstart()
+
+	if trace.enabled {
+		traceGCScanStart()
+	}
+
+	// parallel mark for over GC roots
+	parfordo(work.markfor)
+	if gcphase != _GCscan {
+		var gcw gcWork
+		gcDrain(&gcw, -1) // blocks in getfull
+		gcw.dispose()
+	}
+
+	if trace.enabled {
+		traceGCScanDone()
+	}
+
+	nproc := work.nproc // work.nproc can change right after we increment work.ndone
+	if xadd(&work.ndone, +1) == nproc-1 {
+		notewakeup(&work.alldone)
+	}
+	_g_.m.traceback = 0
+}
+
+func gchelperstart() {
+	_g_ := getg()
+
+	if _g_.m.helpgc < 0 || _g_.m.helpgc >= _MaxGcproc {
+		throw("gchelperstart: bad m->helpgc")
+	}
+	if _g_ != _g_.m.g0 {
+		throw("gchelper not running on g0 stack")
+	}
+}
+
+// itoaDiv formats val/(10**dec) into buf.
+func itoaDiv(buf []byte, val uint64, dec int) []byte {
+	i := len(buf) - 1
+	idec := i - dec
+	for val >= 10 || i >= idec {
+		buf[i] = byte(val%10 + '0')
+		i--
+		if i == idec {
+			buf[i] = '.'
+			i--
+		}
+		val /= 10
+	}
+	buf[i] = byte(val + '0')
+	return buf[i:]
+}
+
+// fmtNSAsMS nicely formats ns nanoseconds as milliseconds.
+func fmtNSAsMS(buf []byte, ns uint64) []byte {
+	if ns >= 10e6 {
+		// Format as whole milliseconds.
+		return itoaDiv(buf, ns/1e6, 0)
+	}
+	// Format two digits of precision, with at most three decimal places.
+	x := ns / 1e3
+	if x == 0 {
+		buf[0] = '0'
+		return buf[:1]
+	}
+	dec := 3
+	for x >= 100 {
+		x /= 10
+		dec--
+	}
+	return itoaDiv(buf, x, dec)
+}
diff --git a/src/runtime/mgc0.c b/src/runtime/mgc0.c
deleted file mode 100644
index 083beec..0000000
--- a/src/runtime/mgc0.c
+++ /dev/null
@@ -1,2013 +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.
-
-// Garbage collector (GC).
-//
-// GC is:
-// - mark&sweep
-// - mostly precise (with the exception of some C-allocated objects, assembly frames/arguments, etc)
-// - parallel (up to MaxGcproc threads)
-// - partially concurrent (mark is stop-the-world, while sweep is concurrent)
-// - non-moving/non-compacting
-// - full (non-partial)
-//
-// GC rate.
-// Next GC is after we've allocated an extra amount of memory proportional to
-// the amount already in use. The proportion is controlled by GOGC environment variable
-// (100 by default). If GOGC=100 and we're using 4M, we'll GC again when we get to 8M
-// (this mark is tracked in next_gc variable). This keeps the GC cost in linear
-// proportion to the allocation cost. Adjusting GOGC just changes the linear constant
-// (and also the amount of extra memory used).
-//
-// Concurrent sweep.
-// The sweep phase proceeds concurrently with normal program execution.
-// The heap is swept span-by-span both lazily (when a goroutine needs another span)
-// and concurrently in a background goroutine (this helps programs that are not CPU bound).
-// However, at the end of the stop-the-world GC phase we don't know the size of the live heap,
-// and so next_gc calculation is tricky and happens as follows.
-// At the end of the stop-the-world phase next_gc is conservatively set based on total
-// heap size; all spans are marked as "needs sweeping".
-// Whenever a span is swept, next_gc is decremented by GOGC*newly_freed_memory.
-// The background sweeper goroutine simply sweeps spans one-by-one bringing next_gc
-// closer to the target value. However, this is not enough to avoid over-allocating memory.
-// Consider that a goroutine wants to allocate a new span for a large object and
-// there are no free swept spans, but there are small-object unswept spans.
-// If the goroutine naively allocates a new span, it can surpass the yet-unknown
-// target next_gc value. In order to prevent such cases (1) when a goroutine needs
-// to allocate a new small-object span, it sweeps small-object spans for the same
-// object size until it frees at least one object; (2) when a goroutine needs to
-// allocate large-object span from heap, it sweeps spans until it frees at least
-// that many pages into heap. Together these two measures ensure that we don't surpass
-// target next_gc value by a large margin. There is an exception: if a goroutine sweeps
-// and frees two nonadjacent one-page spans to the heap, it will allocate a new two-page span,
-// but there can still be other one-page unswept spans which could be combined into a two-page span.
-// It's critical to ensure that no operations proceed on unswept spans (that would corrupt
-// mark bits in GC bitmap). During GC all mcaches are flushed into the central cache,
-// so they are empty. When a goroutine grabs a new span into mcache, it sweeps it.
-// When a goroutine explicitly frees an object or sets a finalizer, it ensures that
-// the span is swept (either by sweeping it, or by waiting for the concurrent sweep to finish).
-// The finalizer goroutine is kicked off only when all spans are swept.
-// When the next GC starts, it sweeps all not-yet-swept spans (if any).
-
-#include "runtime.h"
-#include "arch_GOARCH.h"
-#include "malloc.h"
-#include "stack.h"
-#include "mgc0.h"
-#include "chan.h"
-#include "race.h"
-#include "type.h"
-#include "typekind.h"
-#include "funcdata.h"
-#include "textflag.h"
-
-enum {
-	Debug		= 0,
-	DebugPtrs	= 0, // if 1, print trace of every pointer load during GC
-	ConcurrentSweep	= 1,
-
-	WorkbufSize	= 4*1024,
-	FinBlockSize	= 4*1024,
-	RootData	= 0,
-	RootBss		= 1,
-	RootFinalizers	= 2,
-	RootSpans	= 3,
-	RootFlushCaches = 4,
-	RootCount	= 5,
-};
-
-// ptrmask for an allocation containing a single pointer.
-static byte oneptr[] = {BitsPointer};
-
-// Initialized from $GOGC.  GOGC=off means no gc.
-extern int32 runtime·gcpercent;
-
-// Holding worldsema grants an M the right to try to stop the world.
-// The procedure is:
-//
-//	runtime·semacquire(&runtime·worldsema);
-//	m->gcing = 1;
-//	runtime·stoptheworld();
-//
-//	... do stuff ...
-//
-//	m->gcing = 0;
-//	runtime·semrelease(&runtime·worldsema);
-//	runtime·starttheworld();
-//
-uint32 runtime·worldsema = 1;
-
-typedef struct Workbuf Workbuf;
-struct Workbuf
-{
-	LFNode	node; // must be first
-	uintptr	nobj;
-	byte*	obj[(WorkbufSize-sizeof(LFNode)-sizeof(uintptr))/PtrSize];
-};
-
-extern byte runtime·data[];
-extern byte runtime·edata[];
-extern byte runtime·bss[];
-extern byte runtime·ebss[];
-
-extern byte runtime·gcdata[];
-extern byte runtime·gcbss[];
-
-Mutex	runtime·finlock;	// protects the following variables
-G*	runtime·fing;		// goroutine that runs finalizers
-FinBlock*	runtime·finq;	// list of finalizers that are to be executed
-FinBlock*	runtime·finc;	// cache of free blocks
-static byte finptrmask[FinBlockSize/PtrSize/PointersPerByte];
-bool	runtime·fingwait;
-bool	runtime·fingwake;
-FinBlock	*runtime·allfin;	// list of all blocks
-
-BitVector	runtime·gcdatamask;
-BitVector	runtime·gcbssmask;
-
-Mutex	runtime·gclock;
-
-static	uintptr	badblock[1024];
-static	int32	nbadblock;
-
-static Workbuf* getempty(Workbuf*);
-static Workbuf* getfull(Workbuf*);
-static void	putempty(Workbuf*);
-static Workbuf* handoff(Workbuf*);
-static void	gchelperstart(void);
-static void	flushallmcaches(void);
-static bool	scanframe(Stkframe *frame, void *unused);
-static void	scanstack(G *gp);
-static BitVector	unrollglobgcprog(byte *prog, uintptr size);
-
-void runtime·bgsweep(void);
-static FuncVal bgsweepv = {runtime·bgsweep};
-
-typedef struct WorkData WorkData;
-struct WorkData {
-	uint64	full;  // lock-free list of full blocks
-	uint64	empty; // lock-free list of empty blocks
-	byte	pad0[CacheLineSize]; // prevents false-sharing between full/empty and nproc/nwait
-	uint32	nproc;
-	int64	tstart;
-	volatile uint32	nwait;
-	volatile uint32	ndone;
-	Note	alldone;
-	ParFor*	markfor;
-
-	// Copy of mheap.allspans for marker or sweeper.
-	MSpan**	spans;
-	uint32	nspan;
-};
-WorkData runtime·work;
-
-// Is _cgo_allocate linked into the binary?
-static bool
-have_cgo_allocate(void)
-{
-	extern	byte	go·weak·runtime·_cgo_allocate_internal[1];
-	return go·weak·runtime·_cgo_allocate_internal != nil;
-}
-
-// scanblock scans a block of n bytes starting at pointer b for references
-// to other objects, scanning any it finds recursively until there are no
-// unscanned objects left.  Instead of using an explicit recursion, it keeps
-// a work list in the Workbuf* structures and loops in the main function
-// body.  Keeping an explicit work list is easier on the stack allocator and
-// more efficient.
-static void
-scanblock(byte *b, uintptr n, byte *ptrmask)
-{
-	byte *obj, *obj0, *p, *arena_start, *arena_used, **wp, *scanbuf[8], *ptrbitp, *bitp;
-	uintptr i, j, nobj, size, idx, x, off, scanbufpos, bits, xbits, shift;
-	Workbuf *wbuf;
-	Iface *iface;
-	Eface *eface;
-	Type *typ;
-	MSpan *s;
-	pageID k;
-	bool keepworking;
-
-	// Cache memory arena parameters in local vars.
-	arena_start = runtime·mheap.arena_start;
-	arena_used = runtime·mheap.arena_used;
-
-	wbuf = getempty(nil);
-	nobj = wbuf->nobj;
-	wp = &wbuf->obj[nobj];
-	keepworking = b == nil;
-	scanbufpos = 0;
-	for(i = 0; i < nelem(scanbuf); i++)
-		scanbuf[i] = nil;
-
-	ptrbitp = nil;
-
-	// ptrmask can have 2 possible values:
-	// 1. nil - obtain pointer mask from GC bitmap.
-	// 2. pointer to a compact mask (for stacks and data).
-	if(b != nil)
-		goto scanobj;
-	for(;;) {
-		if(nobj == 0) {
-			// Out of work in workbuf.
-			// First, see is there is any work in scanbuf.
-			for(i = 0; i < nelem(scanbuf); i++) {
-				b = scanbuf[scanbufpos];
-				scanbuf[scanbufpos++] = nil;
-				scanbufpos %= nelem(scanbuf);
-				if(b != nil) {
-					n = arena_used - b; // scan until bitBoundary or BitsDead
-					ptrmask = nil; // use GC bitmap for pointer info
-					goto scanobj;
-				}
-			}
-			if(!keepworking) {
-				putempty(wbuf);
-				return;
-			}
-			// Refill workbuf from global queue.
-			wbuf = getfull(wbuf);
-			if(wbuf == nil)
-				return;
-			nobj = wbuf->nobj;
-			wp = &wbuf->obj[nobj];
-		}
-
-		// If another proc wants a pointer, give it some.
-		if(runtime·work.nwait > 0 && nobj > 4 && runtime·work.full == 0) {
-			wbuf->nobj = nobj;
-			wbuf = handoff(wbuf);
-			nobj = wbuf->nobj;
-			wp = &wbuf->obj[nobj];
-		}
-
-		wp--;
-		nobj--;
-		b = *wp;
-		n = arena_used - b; // scan until next bitBoundary or BitsDead
-		ptrmask = nil; // use GC bitmap for pointer info
-
-	scanobj:
-		if(DebugPtrs)
-			runtime·printf("scanblock %p +%p %p\n", b, n, ptrmask);
-		// Find bits of the beginning of the object.
-		if(ptrmask == nil) {
-			off = (uintptr*)b - (uintptr*)arena_start;
-			ptrbitp = arena_start - off/wordsPerBitmapByte - 1;
-		}
-		for(i = 0; i < n; i += PtrSize) {
-			obj = nil;
-			// Find bits for this word.
-			if(ptrmask == nil) {
-				// Check is we have reached end of span.
-				if((((uintptr)b+i)%PageSize) == 0 &&
-					runtime·mheap.spans[(b-arena_start)>>PageShift] != runtime·mheap.spans[(b+i-arena_start)>>PageShift])
-					break;
-				// Consult GC bitmap.
-				bits = *ptrbitp;
-
-				if(wordsPerBitmapByte != 2)
-					runtime·throw("alg doesn't work for wordsPerBitmapByte != 2");
-				j = ((uintptr)b+i)/PtrSize & 1;
-				ptrbitp -= j;
-				bits >>= gcBits*j;
-
-				if((bits&bitBoundary) != 0 && i != 0)
-					break; // reached beginning of the next object
-				bits = (bits>>2)&BitsMask;
-				if(bits == BitsDead)
-					break; // reached no-scan part of the object
-			} else // dense mask (stack or data)
-				bits = (ptrmask[(i/PtrSize)/4]>>(((i/PtrSize)%4)*BitsPerPointer))&BitsMask;
-
-			if(bits <= BitsScalar) // BitsScalar || BitsDead
-				continue;
-			if(bits == BitsPointer) {
-				obj = *(byte**)(b+i);
-				obj0 = obj;
-				goto markobj;
-			}
-
-			// With those three out of the way, must be multi-word.
-			if(Debug && bits != BitsMultiWord)
-				runtime·throw("unexpected garbage collection bits");
-			// Find the next pair of bits.
-			if(ptrmask == nil) {
-				bits = *ptrbitp;
-				j = ((uintptr)b+i+PtrSize)/PtrSize & 1;
-				ptrbitp -= j;
-				bits >>= gcBits*j;
-				bits = (bits>>2)&BitsMask;
-			} else
-				bits = (ptrmask[((i+PtrSize)/PtrSize)/4]>>((((i+PtrSize)/PtrSize)%4)*BitsPerPointer))&BitsMask;
-
-			if(Debug && bits != BitsIface && bits != BitsEface)
-				runtime·throw("unexpected garbage collection bits");
-
-			if(bits == BitsIface) {
-				iface = (Iface*)(b+i);
-				if(iface->tab != nil) {
-					typ = iface->tab->type;
-					if(!(typ->kind&KindDirectIface) || !(typ->kind&KindNoPointers))
-						obj = iface->data;
-				}
-			} else {
-				eface = (Eface*)(b+i);
-				typ = eface->type;
-				if(typ != nil) {
-					if(!(typ->kind&KindDirectIface) || !(typ->kind&KindNoPointers))
-						obj = eface->data;
-				}
-			}
-
-			i += PtrSize;
-
-			obj0 = obj;
-		markobj:
-			// At this point we have extracted the next potential pointer.
-			// Check if it points into heap.
-			if(obj == nil)
-				continue;
-			if(obj < arena_start || obj >= arena_used) {
-				if((uintptr)obj < PhysPageSize && runtime·invalidptr) {
-					s = nil;
-					goto badobj;
-				}
-				continue;
-			}
-			// Mark the object.
-			obj = (byte*)((uintptr)obj & ~(PtrSize-1));
-			off = (uintptr*)obj - (uintptr*)arena_start;
-			bitp = arena_start - off/wordsPerBitmapByte - 1;
-			shift = (off % wordsPerBitmapByte) * gcBits;
-			xbits = *bitp;
-			bits = (xbits >> shift) & bitMask;
-			if((bits&bitBoundary) == 0) {
-				// Not a beginning of a block, consult span table to find the block beginning.
-				k = (uintptr)obj>>PageShift;
-				x = k;
-				x -= (uintptr)arena_start>>PageShift;
-				s = runtime·mheap.spans[x];
-				if(s == nil || k < s->start || obj >= s->limit || s->state != MSpanInUse) {
-					// Sometimes 32-bit heaps have holes.  See issue 9872
-					if(PtrSize == 4 && s == nil)
-						continue;
-					// Stack pointers lie within the arena bounds but are not part of the GC heap.
-					// Ignore them.
-					if(s != nil && s->state == MSpanStack)
-						continue;
-				
-				badobj:
-					// If cgo_allocate is linked into the binary, it can allocate
-					// memory as []unsafe.Pointer that may not contain actual
-					// pointers and must be scanned conservatively.
-					// In this case alone, allow the bad pointer.
-					if(have_cgo_allocate() && ptrmask == nil)
-						continue;
-
-					// Anything else indicates a bug somewhere.
-					// If we're in the middle of chasing down a different bad pointer,
-					// don't confuse the trace by printing about this one.
-					if(nbadblock > 0)
-						continue;
-
-					runtime·printf("runtime: garbage collector found invalid heap pointer *(%p+%p)=%p", b, i, obj);
-					if(s == nil)
-						runtime·printf(" s=nil\n");
-					else
-						runtime·printf(" span=%p-%p-%p state=%d\n", (uintptr)s->start<<PageShift, s->limit, (uintptr)(s->start+s->npages)<<PageShift, s->state);
-					if(ptrmask != nil)
-						runtime·throw("invalid heap pointer");
-					// Add to badblock list, which will cause the garbage collection
-					// to keep repeating until it has traced the chain of pointers
-					// leading to obj all the way back to a root.
-					if(nbadblock == 0)
-						badblock[nbadblock++] = (uintptr)b;
-					continue;
-				}
-				p = (byte*)((uintptr)s->start<<PageShift);
-				if(s->sizeclass != 0) {
-					size = s->elemsize;
-					idx = ((byte*)obj - p)/size;
-					p = p+idx*size;
-				}
-				if(p == obj) {
-					runtime·printf("runtime: failed to find block beginning for %p s=%p s->limit=%p\n",
-						p, s->start*PageSize, s->limit);
-					runtime·throw("failed to find block beginning");
-				}
-				obj = p;
-				goto markobj;
-			}
-			if(DebugPtrs)
-				runtime·printf("scan *%p = %p => base %p\n", b+i, obj0, obj);
-
-			if(nbadblock > 0 && (uintptr)obj == badblock[nbadblock-1]) {
-				// Running garbage collection again because
-				// we want to find the path from a root to a bad pointer.
-				// Found possible next step; extend or finish path.
-				for(j=0; j<nbadblock; j++)
-					if(badblock[j] == (uintptr)b)
-						goto AlreadyBad;
-				runtime·printf("runtime: found *(%p+%p) = %p+%p\n", b, i, obj0, (uintptr)(obj-obj0));
-				if(ptrmask != nil)
-					runtime·throw("bad pointer");
-				if(nbadblock >= nelem(badblock))
-					runtime·throw("badblock trace too long");
-				badblock[nbadblock++] = (uintptr)b;
-			AlreadyBad:;
-			}
-
-			// Now we have bits, bitp, and shift correct for
-			// obj pointing at the base of the object.
-			// Only care about not marked objects.
-			if((bits&bitMarked) != 0)
-				continue;
-			// If obj size is greater than 8, then each byte of GC bitmap
-			// contains info for at most one object. In such case we use
-			// non-atomic byte store to mark the object. This can lead
-			// to double enqueue of the object for scanning, but scanning
-			// is an idempotent operation, so it is OK. This cannot lead
-			// to bitmap corruption because the single marked bit is the
-			// only thing that can change in the byte.
-			// For 8-byte objects we use non-atomic store, if the other
-			// quadruple is already marked. Otherwise we resort to CAS
-			// loop for marking.
-			if((xbits&(bitMask|(bitMask<<gcBits))) != (bitBoundary|(bitBoundary<<gcBits)) ||
-				runtime·work.nproc == 1)
-				*bitp = xbits | (bitMarked<<shift);
-			else
-				runtime·atomicor8(bitp, bitMarked<<shift);
-
-			if(((xbits>>(shift+2))&BitsMask) == BitsDead)
-				continue;  // noscan object
-
-			// Queue the obj for scanning.
-			PREFETCH(obj);
-			p = scanbuf[scanbufpos];
-			scanbuf[scanbufpos++] = obj;
-			scanbufpos %= nelem(scanbuf);
-			if(p == nil)
-				continue;
-
-			// If workbuf is full, obtain an empty one.
-			if(nobj >= nelem(wbuf->obj)) {
-				wbuf->nobj = nobj;
-				wbuf = getempty(wbuf);
-				nobj = wbuf->nobj;
-				wp = &wbuf->obj[nobj];
-			}
-			*wp = p;
-			wp++;
-			nobj++;
-		}
-		if(DebugPtrs)
-			runtime·printf("end scanblock %p +%p %p\n", b, n, ptrmask);
-
-		if(Debug && ptrmask == nil) {
-			// For heap objects ensure that we did not overscan.
-			n = 0;
-			p = nil;
-			if(!runtime·mlookup(b, &p, &n, nil) || b != p || i > n) {
-				runtime·printf("runtime: scanned (%p,%p), heap object (%p,%p)\n", b, i, p, n);
-				runtime·throw("scanblock: scanned invalid object");
-			}
-		}
-	}
-}
-
-static void
-markroot(ParFor *desc, uint32 i)
-{
-	FinBlock *fb;
-	MSpan *s;
-	uint32 spanidx, sg;
-	G *gp;
-	void *p;
-	uint32 status;
-	bool restart;
-
-	USED(&desc);
-	// Note: if you add a case here, please also update heapdump.c:dumproots.
-	switch(i) {
-	case RootData:
-		scanblock(runtime·data, runtime·edata - runtime·data, runtime·gcdatamask.bytedata);
-		break;
-
-	case RootBss:
-		scanblock(runtime·bss, runtime·ebss - runtime·bss, runtime·gcbssmask.bytedata);
-		break;
-
-	case RootFinalizers:
-		for(fb=runtime·allfin; fb; fb=fb->alllink)
-			scanblock((byte*)fb->fin, fb->cnt*sizeof(fb->fin[0]), finptrmask);
-		break;
-
-	case RootSpans:
-		// mark MSpan.specials
-		sg = runtime·mheap.sweepgen;
-		for(spanidx=0; spanidx<runtime·work.nspan; spanidx++) {
-			Special *sp;
-			SpecialFinalizer *spf;
-
-			s = runtime·work.spans[spanidx];
-			if(s->state != MSpanInUse)
-				continue;
-			if(s->sweepgen != sg) {
-				runtime·printf("sweep %d %d\n", s->sweepgen, sg);
-				runtime·throw("gc: unswept span");
-			}
-			for(sp = s->specials; sp != nil; sp = sp->next) {
-				if(sp->kind != KindSpecialFinalizer)
-					continue;
-				// don't mark finalized object, but scan it so we
-				// retain everything it points to.
-				spf = (SpecialFinalizer*)sp;
-				// A finalizer can be set for an inner byte of an object, find object beginning.
-				p = (void*)((s->start << PageShift) + spf->special.offset/s->elemsize*s->elemsize);
-				scanblock(p, s->elemsize, nil);
-				scanblock((void*)&spf->fn, PtrSize, oneptr);
-			}
-		}
-		break;
-
-	case RootFlushCaches:
-		flushallmcaches();
-		break;
-
-	default:
-		// the rest is scanning goroutine stacks
-		if(i - RootCount >= runtime·allglen)
-			runtime·throw("markroot: bad index");
-		gp = runtime·allg[i - RootCount];
-		// remember when we've first observed the G blocked
-		// needed only to output in traceback
-		status = runtime·readgstatus(gp);
-		if((status == Gwaiting || status == Gsyscall) && gp->waitsince == 0)
-			gp->waitsince = runtime·work.tstart;
-		// Shrink a stack if not much of it is being used.
-		runtime·shrinkstack(gp);
-		if(runtime·readgstatus(gp) == Gdead) 
-			gp->gcworkdone = true;
-		else 
-			gp->gcworkdone = false; 
-		restart = runtime·stopg(gp);
-		scanstack(gp);
-		if(restart)
-			runtime·restartg(gp);
-		break;
-	}
-}
-
-// Get an empty work buffer off the work.empty list,
-// allocating new buffers as needed.
-static Workbuf*
-getempty(Workbuf *b)
-{
-	MCache *c;
-
-	if(b != nil)
-		runtime·lfstackpush(&runtime·work.full, &b->node);
-	b = nil;
-	c = g->m->mcache;
-	if(c->gcworkbuf != nil) {
-		b = c->gcworkbuf;
-		c->gcworkbuf = nil;
-	}
-	if(b == nil)
-		b = (Workbuf*)runtime·lfstackpop(&runtime·work.empty);
-	if(b == nil)
-		b = runtime·persistentalloc(sizeof(*b), CacheLineSize, &mstats.gc_sys);
-	b->nobj = 0;
-	return b;
-}
-
-static void
-putempty(Workbuf *b)
-{
-	MCache *c;
-
-	c = g->m->mcache;
-	if(c->gcworkbuf == nil) {
-		c->gcworkbuf = b;
-		return;
-	}
-	runtime·lfstackpush(&runtime·work.empty, &b->node);
-}
-
-void
-runtime·gcworkbuffree(void *b)
-{
-	if(b != nil)
-		putempty(b);
-}
-
-// Get a full work buffer off the work.full list, or return nil.
-static Workbuf*
-getfull(Workbuf *b)
-{
-	int32 i;
-
-	if(b != nil)
-		runtime·lfstackpush(&runtime·work.empty, &b->node);
-	b = (Workbuf*)runtime·lfstackpop(&runtime·work.full);
-	if(b != nil || runtime·work.nproc == 1)
-		return b;
-
-	runtime·xadd(&runtime·work.nwait, +1);
-	for(i=0;; i++) {
-		if(runtime·work.full != 0) {
-			runtime·xadd(&runtime·work.nwait, -1);
-			b = (Workbuf*)runtime·lfstackpop(&runtime·work.full);
-			if(b != nil)
-				return b;
-			runtime·xadd(&runtime·work.nwait, +1);
-		}
-		if(runtime·work.nwait == runtime·work.nproc)
-			return nil;
-		if(i < 10) {
-			g->m->gcstats.nprocyield++;
-			runtime·procyield(20);
-		} else if(i < 20) {
-			g->m->gcstats.nosyield++;
-			runtime·osyield();
-		} else {
-			g->m->gcstats.nsleep++;
-			runtime·usleep(100);
-		}
-	}
-}
-
-static Workbuf*
-handoff(Workbuf *b)
-{
-	int32 n;
-	Workbuf *b1;
-
-	// Make new buffer with half of b's pointers.
-	b1 = getempty(nil);
-	n = b->nobj/2;
-	b->nobj -= n;
-	b1->nobj = n;
-	runtime·memmove(b1->obj, b->obj+b->nobj, n*sizeof b1->obj[0]);
-	g->m->gcstats.nhandoff++;
-	g->m->gcstats.nhandoffcnt += n;
-
-	// Put b on full list - let first half of b get stolen.
-	runtime·lfstackpush(&runtime·work.full, &b->node);
-	return b1;
-}
-
-BitVector
-runtime·stackmapdata(StackMap *stackmap, int32 n)
-{
-	if(n < 0 || n >= stackmap->n)
-		runtime·throw("stackmapdata: index out of range");
-	return (BitVector){stackmap->nbit, stackmap->bytedata + n*((stackmap->nbit+31)/32*4)};
-}
-
-// Scan a stack frame: local variables and function arguments/results.
-static bool
-scanframe(Stkframe *frame, void *unused)
-{
-	Func *f;
-	StackMap *stackmap;
-	BitVector bv;
-	uintptr size, minsize;
-	uintptr targetpc;
-	int32 pcdata;
-
-	USED(unused);
-	f = frame->fn;
-	targetpc = frame->continpc;
-	if(targetpc == 0) {
-		// Frame is dead.
-		return true;
-	}
-	if(Debug > 1)
-		runtime·printf("scanframe %s\n", runtime·funcname(f));
-	if(targetpc != f->entry)
-		targetpc--;
-	pcdata = runtime·pcdatavalue(f, PCDATA_StackMapIndex, targetpc);
-	if(pcdata == -1) {
-		// We do not have a valid pcdata value but there might be a
-		// stackmap for this function.  It is likely that we are looking
-		// at the function prologue, assume so and hope for the best.
-		pcdata = 0;
-	}
-
-	// Scan local variables if stack frame has been allocated.
-	size = frame->varp - frame->sp;
-	if(thechar != '6' && thechar != '8')
-		minsize = sizeof(uintptr);
-	else
-		minsize = 0;
-	if(size > minsize) {
-		stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps);
-		if(stackmap == nil || stackmap->n <= 0) {
-			runtime·printf("runtime: frame %s untyped locals %p+%p\n", runtime·funcname(f), (byte*)(frame->varp-size), size);
-			runtime·throw("missing stackmap");
-		}
-
-		// Locals bitmap information, scan just the pointers in locals.
-		if(pcdata < 0 || pcdata >= stackmap->n) {
-			// don't know where we are
-			runtime·printf("runtime: pcdata is %d and %d locals stack map entries for %s (targetpc=%p)\n",
-				pcdata, stackmap->n, runtime·funcname(f), targetpc);
-			runtime·throw("scanframe: bad symbol table");
-		}
-		bv = runtime·stackmapdata(stackmap, pcdata);
-		size = (bv.n * PtrSize) / BitsPerPointer;
-		scanblock((byte*)(frame->varp - size), bv.n/BitsPerPointer*PtrSize, bv.bytedata);
-	}
-
-	// Scan arguments.
-	if(frame->arglen > 0) {
-		if(frame->argmap != nil)
-			bv = *frame->argmap;
-		else {
-			stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps);
-			if(stackmap == nil || stackmap->n <= 0) {
-				runtime·printf("runtime: frame %s untyped args %p+%p\n", runtime·funcname(f), frame->argp, (uintptr)frame->arglen);
-				runtime·throw("missing stackmap");
-			}
-			if(pcdata < 0 || pcdata >= stackmap->n) {
-				// don't know where we are
-				runtime·printf("runtime: pcdata is %d and %d args stack map entries for %s (targetpc=%p)\n",
-					pcdata, stackmap->n, runtime·funcname(f), targetpc);
-				runtime·throw("scanframe: bad symbol table");
-			}
- 			bv = runtime·stackmapdata(stackmap, pcdata);
-		}
- 		scanblock((byte*)frame->argp, bv.n/BitsPerPointer*PtrSize, bv.bytedata);
- 	}
- 	return true;
-}
-
-static void
-scanstack(G *gp)
-{
-	M *mp;
-	bool (*fn)(Stkframe*, void*);
-
-	if(runtime·readgstatus(gp)&Gscan == 0) {
-		runtime·printf("runtime: gp=%p, goid=%D, gp->atomicstatus=%d\n", gp, gp->goid, runtime·readgstatus(gp));
-		runtime·throw("mark - bad status");
-	}
-
-	switch(runtime·readgstatus(gp)&~Gscan) {
-	default:
-		runtime·printf("runtime: gp=%p, goid=%D, gp->atomicstatus=%d\n", gp, gp->goid, runtime·readgstatus(gp));
-		runtime·throw("mark - bad status");
-	case Gdead:
-		return;
-	case Grunning:
-		runtime·printf("runtime: gp=%p, goid=%D, gp->atomicstatus=%d\n", gp, gp->goid, runtime·readgstatus(gp));
-		runtime·throw("mark - world not stopped");
-	case Grunnable:
-	case Gsyscall:
-	case Gwaiting:
-		break;
-	}
-
-	if(gp == g)
-		runtime·throw("can't scan our own stack");
-	if((mp = gp->m) != nil && mp->helpgc)
-		runtime·throw("can't scan gchelper stack");
-
-	fn = scanframe;
-	runtime·gentraceback(~(uintptr)0, ~(uintptr)0, 0, gp, 0, nil, 0x7fffffff, &fn, nil, 0);
-	runtime·tracebackdefers(gp, &fn, nil);
-}
-
-// The gp has been moved to a gc safepoint. If there is gcphase specific
-// work it is done here. 
-void
-runtime·gcphasework(G *gp)
-{
-	switch(runtime·gcphase) {
-	default:
-		runtime·throw("gcphasework in bad gcphase");
-	case GCoff:
-	case GCquiesce:
-	case GCstw:
-	case GCsweep:
-		// No work for now.
-		break;
-	case GCmark:
-		// Disabled until concurrent GC is implemented
-		// but indicate the scan has been done. 
-		// scanstack(gp);
-		break;
-	}
-	gp->gcworkdone = true;
-}
-
-#pragma dataflag NOPTR
-static byte finalizer1[] = {
-	// Each Finalizer is 5 words, ptr ptr uintptr ptr ptr.
-	// Each byte describes 4 words.
-	// Need 4 Finalizers described by 5 bytes before pattern repeats:
-	//	ptr ptr uintptr ptr ptr
-	//	ptr ptr uintptr ptr ptr
-	//	ptr ptr uintptr ptr ptr
-	//	ptr ptr uintptr ptr ptr
-	// aka
-	//	ptr ptr uintptr ptr
-	//	ptr ptr ptr uintptr
-	//	ptr ptr ptr ptr
-	//	uintptr ptr ptr ptr
-	//	ptr uintptr ptr ptr
-	// Assumptions about Finalizer layout checked below.
-	BitsPointer | BitsPointer<<2 | BitsScalar<<4 | BitsPointer<<6,
-	BitsPointer | BitsPointer<<2 | BitsPointer<<4 | BitsScalar<<6,
-	BitsPointer | BitsPointer<<2 | BitsPointer<<4 | BitsPointer<<6,
-	BitsScalar | BitsPointer<<2 | BitsPointer<<4 | BitsPointer<<6,
-	BitsPointer | BitsScalar<<2 | BitsPointer<<4 | BitsPointer<<6,
-};
-
-void
-runtime·queuefinalizer(byte *p, FuncVal *fn, uintptr nret, Type *fint, PtrType *ot)
-{
-	FinBlock *block;
-	Finalizer *f;
-	int32 i;
-
-	runtime·lock(&runtime·finlock);
-	if(runtime·finq == nil || runtime·finq->cnt == runtime·finq->cap) {
-		if(runtime·finc == nil) {
-			runtime·finc = runtime·persistentalloc(FinBlockSize, 0, &mstats.gc_sys);
-			runtime·finc->cap = (FinBlockSize - sizeof(FinBlock)) / sizeof(Finalizer) + 1;
-			runtime·finc->alllink = runtime·allfin;
-			runtime·allfin = runtime·finc;
-			if(finptrmask[0] == 0) {
-				// Build pointer mask for Finalizer array in block.
-				// Check assumptions made in finalizer1 array above.
-				if(sizeof(Finalizer) != 5*PtrSize ||
-					offsetof(Finalizer, fn) != 0 ||
-					offsetof(Finalizer, arg) != PtrSize ||
-					offsetof(Finalizer, nret) != 2*PtrSize ||
-					offsetof(Finalizer, fint) != 3*PtrSize ||
-					offsetof(Finalizer, ot) != 4*PtrSize ||
-					BitsPerPointer != 2) {
-					runtime·throw("finalizer out of sync");
-				}
-				for(i=0; i<nelem(finptrmask); i++)
-					finptrmask[i] = finalizer1[i%nelem(finalizer1)];
-			}
-		}
-		block = runtime·finc;
-		runtime·finc = block->next;
-		block->next = runtime·finq;
-		runtime·finq = block;
-	}
-	f = &runtime·finq->fin[runtime·finq->cnt];
-	runtime·finq->cnt++;
-	f->fn = fn;
-	f->nret = nret;
-	f->fint = fint;
-	f->ot = ot;
-	f->arg = p;
-	runtime·fingwake = true;
-	runtime·unlock(&runtime·finlock);
-}
-
-void
-runtime·iterate_finq(void (*callback)(FuncVal*, byte*, uintptr, Type*, PtrType*))
-{
-	FinBlock *fb;
-	Finalizer *f;
-	uintptr i;
-
-	for(fb = runtime·allfin; fb; fb = fb->alllink) {
-		for(i = 0; i < fb->cnt; i++) {
-			f = &fb->fin[i];
-			callback(f->fn, f->arg, f->nret, f->fint, f->ot);
-		}
-	}
-}
-
-void
-runtime·MSpan_EnsureSwept(MSpan *s)
-{
-	uint32 sg;
-
-	// Caller must disable preemption.
-	// Otherwise when this function returns the span can become unswept again
-	// (if GC is triggered on another goroutine).
-	if(g->m->locks == 0 && g->m->mallocing == 0 && g != g->m->g0)
-		runtime·throw("MSpan_EnsureSwept: m is not locked");
-
-	sg = runtime·mheap.sweepgen;
-	if(runtime·atomicload(&s->sweepgen) == sg)
-		return;
-	if(runtime·cas(&s->sweepgen, sg-2, sg-1)) {
-		runtime·MSpan_Sweep(s, false);
-		return;
-	}
-	// unfortunate condition, and we don't have efficient means to wait
-	while(runtime·atomicload(&s->sweepgen) != sg)
-		runtime·osyield();
-}
-
-// Sweep frees or collects finalizers for blocks not marked in the mark phase.
-// It clears the mark bits in preparation for the next GC round.
-// Returns true if the span was returned to heap.
-// If preserve=true, don't return it to heap nor relink in MCentral lists;
-// caller takes care of it.
-bool
-runtime·MSpan_Sweep(MSpan *s, bool preserve)
-{
-	int32 cl, n, npages, nfree;
-	uintptr size, off, step;
-	uint32 sweepgen;
-	byte *p, *bitp, shift, xbits, bits;
-	MCache *c;
-	byte *arena_start;
-	MLink head, *end, *link;
-	Special *special, **specialp, *y;
-	bool res, sweepgenset;
-
-	// It's critical that we enter this function with preemption disabled,
-	// GC must not start while we are in the middle of this function.
-	if(g->m->locks == 0 && g->m->mallocing == 0 && g != g->m->g0)
-		runtime·throw("MSpan_Sweep: m is not locked");
-	sweepgen = runtime·mheap.sweepgen;
-	if(s->state != MSpanInUse || s->sweepgen != sweepgen-1) {
-		runtime·printf("MSpan_Sweep: state=%d sweepgen=%d mheap.sweepgen=%d\n",
-			s->state, s->sweepgen, sweepgen);
-		runtime·throw("MSpan_Sweep: bad span state");
-	}
-	arena_start = runtime·mheap.arena_start;
-	cl = s->sizeclass;
-	size = s->elemsize;
-	if(cl == 0) {
-		n = 1;
-	} else {
-		// Chunk full of small blocks.
-		npages = runtime·class_to_allocnpages[cl];
-		n = (npages << PageShift) / size;
-	}
-	res = false;
-	nfree = 0;
-	end = &head;
-	c = g->m->mcache;
-	sweepgenset = false;
-
-	// Mark any free objects in this span so we don't collect them.
-	for(link = s->freelist; link != nil; link = link->next) {
-		off = (uintptr*)link - (uintptr*)arena_start;
-		bitp = arena_start - off/wordsPerBitmapByte - 1;
-		shift = (off % wordsPerBitmapByte) * gcBits;
-		*bitp |= bitMarked<<shift;
-	}
-
-	// Unlink & free special records for any objects we're about to free.
-	specialp = &s->specials;
-	special = *specialp;
-	while(special != nil) {
-		// A finalizer can be set for an inner byte of an object, find object beginning.
-		p = (byte*)(s->start << PageShift) + special->offset/size*size;
-		off = (uintptr*)p - (uintptr*)arena_start;
-		bitp = arena_start - off/wordsPerBitmapByte - 1;
-		shift = (off % wordsPerBitmapByte) * gcBits;
-		bits = (*bitp>>shift) & bitMask;
-		if((bits&bitMarked) == 0) {
-			// Find the exact byte for which the special was setup
-			// (as opposed to object beginning).
-			p = (byte*)(s->start << PageShift) + special->offset;
-			// about to free object: splice out special record
-			y = special;
-			special = special->next;
-			*specialp = special;
-			if(!runtime·freespecial(y, p, size, false)) {
-				// stop freeing of object if it has a finalizer
-				*bitp |= bitMarked << shift;
-			}
-		} else {
-			// object is still live: keep special record
-			specialp = &special->next;
-			special = *specialp;
-		}
-	}
-
-	// Sweep through n objects of given size starting at p.
-	// This thread owns the span now, so it can manipulate
-	// the block bitmap without atomic operations.
-	p = (byte*)(s->start << PageShift);
-	// Find bits for the beginning of the span.
-	off = (uintptr*)p - (uintptr*)arena_start;
-	bitp = arena_start - off/wordsPerBitmapByte - 1;
-	shift = 0;
-	step = size/(PtrSize*wordsPerBitmapByte);
-	// Rewind to the previous quadruple as we move to the next
-	// in the beginning of the loop.
-	bitp += step;
-	if(step == 0) {
-		// 8-byte objects.
-		bitp++;
-		shift = gcBits;
-	}
-	for(; n > 0; n--, p += size) {
-		bitp -= step;
-		if(step == 0) {
-			if(shift != 0)
-				bitp--;
-			shift = gcBits - shift;
-		}
-
-		xbits = *bitp;
-		bits = (xbits>>shift) & bitMask;
-
-		// Allocated and marked object, reset bits to allocated.
-		if((bits&bitMarked) != 0) {
-			*bitp &= ~(bitMarked<<shift);
-			continue;
-		}
-		// At this point we know that we are looking at garbage object
-		// that needs to be collected.
-		if(runtime·debug.allocfreetrace)
-			runtime·tracefree(p, size);
-		// Reset to allocated+noscan.
-		*bitp = (xbits & ~((bitMarked|(BitsMask<<2))<<shift)) | ((uintptr)BitsDead<<(shift+2));
-		if(cl == 0) {
-			// Free large span.
-			if(preserve)
-				runtime·throw("can't preserve large span");
-			runtime·unmarkspan(p, s->npages<<PageShift);
-			s->needzero = 1;
-			// important to set sweepgen before returning it to heap
-			runtime·atomicstore(&s->sweepgen, sweepgen);
-			sweepgenset = true;
-			// NOTE(rsc,dvyukov): The original implementation of efence
-			// in CL 22060046 used SysFree instead of SysFault, so that
-			// the operating system would eventually give the memory
-			// back to us again, so that an efence program could run
-			// longer without running out of memory. Unfortunately,
-			// calling SysFree here without any kind of adjustment of the
-			// heap data structures means that when the memory does
-			// come back to us, we have the wrong metadata for it, either in
-			// the MSpan structures or in the garbage collection bitmap.
-			// Using SysFault here means that the program will run out of
-			// memory fairly quickly in efence mode, but at least it won't
-			// have mysterious crashes due to confused memory reuse.
-			// It should be possible to switch back to SysFree if we also
-			// implement and then call some kind of MHeap_DeleteSpan.
-			if(runtime·debug.efence) {
-				s->limit = nil;	// prevent mlookup from finding this span
-				runtime·SysFault(p, size);
-			} else
-				runtime·MHeap_Free(&runtime·mheap, s, 1);
-			c->local_nlargefree++;
-			c->local_largefree += size;
-			runtime·xadd64(&mstats.next_gc, -(uint64)(size * (runtime·gcpercent + 100)/100));
-			res = true;
-		} else {
-			// Free small object.
-			if(size > 2*sizeof(uintptr))
-				((uintptr*)p)[1] = (uintptr)0xdeaddeaddeaddeadll;	// mark as "needs to be zeroed"
-			else if(size > sizeof(uintptr))
-				((uintptr*)p)[1] = 0;
-
-			end->next = (MLink*)p;
-			end = (MLink*)p;
-			nfree++;
-		}
-	}
-
-	// We need to set s->sweepgen = h->sweepgen only when all blocks are swept,
-	// because of the potential for a concurrent free/SetFinalizer.
-	// But we need to set it before we make the span available for allocation
-	// (return it to heap or mcentral), because allocation code assumes that a
-	// span is already swept if available for allocation.
-
-	if(!sweepgenset && nfree == 0) {
-		// The span must be in our exclusive ownership until we update sweepgen,
-		// check for potential races.
-		if(s->state != MSpanInUse || s->sweepgen != sweepgen-1) {
-			runtime·printf("MSpan_Sweep: state=%d sweepgen=%d mheap.sweepgen=%d\n",
-				s->state, s->sweepgen, sweepgen);
-			runtime·throw("MSpan_Sweep: bad span state after sweep");
-		}
-		runtime·atomicstore(&s->sweepgen, sweepgen);
-	}
-	if(nfree > 0) {
-		c->local_nsmallfree[cl] += nfree;
-		c->local_cachealloc -= nfree * size;
-		runtime·xadd64(&mstats.next_gc, -(uint64)(nfree * size * (runtime·gcpercent + 100)/100));
-		res = runtime·MCentral_FreeSpan(&runtime·mheap.central[cl].mcentral, s, nfree, head.next, end, preserve);
-		// MCentral_FreeSpan updates sweepgen
-	}
-	return res;
-}
-
-// State of background runtime·sweep.
-// Protected by runtime·gclock.
-typedef struct SweepData SweepData;
-struct SweepData
-{
-	G*	g;
-	bool	parked;
-
-	uint32	spanidx;	// background sweeper position
-
-	uint32	nbgsweep;
-	uint32	npausesweep;
-};
-SweepData runtime·sweep;
-
-// sweeps one span
-// returns number of pages returned to heap, or -1 if there is nothing to sweep
-uintptr
-runtime·sweepone(void)
-{
-	MSpan *s;
-	uint32 idx, sg;
-	uintptr npages;
-
-	// increment locks to ensure that the goroutine is not preempted
-	// in the middle of sweep thus leaving the span in an inconsistent state for next GC
-	g->m->locks++;
-	sg = runtime·mheap.sweepgen;
-	for(;;) {
-		idx = runtime·xadd(&runtime·sweep.spanidx, 1) - 1;
-		if(idx >= runtime·work.nspan) {
-			runtime·mheap.sweepdone = true;
-			g->m->locks--;
-			return -1;
-		}
-		s = runtime·work.spans[idx];
-		if(s->state != MSpanInUse) {
-			s->sweepgen = sg;
-			continue;
-		}
-		if(s->sweepgen != sg-2 || !runtime·cas(&s->sweepgen, sg-2, sg-1))
-			continue;
-		npages = s->npages;
-		if(!runtime·MSpan_Sweep(s, false))
-			npages = 0;
-		g->m->locks--;
-		return npages;
-	}
-}
-
-static void
-sweepone_m(void)
-{
-	g->m->scalararg[0] = runtime·sweepone();
-}
-
-#pragma textflag NOSPLIT
-uintptr
-runtime·gosweepone(void)
-{
-	void (*fn)(void);
-	
-	fn = sweepone_m;
-	runtime·onM(&fn);
-	return g->m->scalararg[0];
-}
-
-#pragma textflag NOSPLIT
-bool
-runtime·gosweepdone(void)
-{
-	return runtime·mheap.sweepdone;
-}
-
-void
-runtime·gchelper(void)
-{
-	uint32 nproc;
-
-	g->m->traceback = 2;
-	gchelperstart();
-
-	// parallel mark for over gc roots
-	runtime·parfordo(runtime·work.markfor);
-
-	// help other threads scan secondary blocks
-	scanblock(nil, 0, nil);
-
-	nproc = runtime·work.nproc;  // runtime·work.nproc can change right after we increment runtime·work.ndone
-	if(runtime·xadd(&runtime·work.ndone, +1) == nproc-1)
-		runtime·notewakeup(&runtime·work.alldone);
-	g->m->traceback = 0;
-}
-
-static void
-cachestats(void)
-{
-	MCache *c;
-	P *p, **pp;
-
-	for(pp=runtime·allp; p=*pp; pp++) {
-		c = p->mcache;
-		if(c==nil)
-			continue;
-		runtime·purgecachedstats(c);
-	}
-}
-
-static void
-flushallmcaches(void)
-{
-	P *p, **pp;
-	MCache *c;
-
-	// Flush MCache's to MCentral.
-	for(pp=runtime·allp; p=*pp; pp++) {
-		c = p->mcache;
-		if(c==nil)
-			continue;
-		runtime·MCache_ReleaseAll(c);
-		runtime·stackcache_clear(c);
-	}
-}
-
-static void
-flushallmcaches_m(G *gp)
-{
-	flushallmcaches();
-	runtime·gogo(&gp->sched);
-}
-
-void
-runtime·updatememstats(GCStats *stats)
-{
-	M *mp;
-	MSpan *s;
-	int32 i;
-	uint64 smallfree;
-	uint64 *src, *dst;
-	void (*fn)(G*);
-
-	if(stats)
-		runtime·memclr((byte*)stats, sizeof(*stats));
-	for(mp=runtime·allm; mp; mp=mp->alllink) {
-		if(stats) {
-			src = (uint64*)&mp->gcstats;
-			dst = (uint64*)stats;
-			for(i=0; i<sizeof(*stats)/sizeof(uint64); i++)
-				dst[i] += src[i];
-			runtime·memclr((byte*)&mp->gcstats, sizeof(mp->gcstats));
-		}
-	}
-	mstats.mcache_inuse = runtime·mheap.cachealloc.inuse;
-	mstats.mspan_inuse = runtime·mheap.spanalloc.inuse;
-	mstats.sys = mstats.heap_sys + mstats.stacks_sys + mstats.mspan_sys +
-		mstats.mcache_sys + mstats.buckhash_sys + mstats.gc_sys + mstats.other_sys;
-	
-	// Calculate memory allocator stats.
-	// During program execution we only count number of frees and amount of freed memory.
-	// Current number of alive object in the heap and amount of alive heap memory
-	// are calculated by scanning all spans.
-	// Total number of mallocs is calculated as number of frees plus number of alive objects.
-	// Similarly, total amount of allocated memory is calculated as amount of freed memory
-	// plus amount of alive heap memory.
-	mstats.alloc = 0;
-	mstats.total_alloc = 0;
-	mstats.nmalloc = 0;
-	mstats.nfree = 0;
-	for(i = 0; i < nelem(mstats.by_size); i++) {
-		mstats.by_size[i].nmalloc = 0;
-		mstats.by_size[i].nfree = 0;
-	}
-
-	// Flush MCache's to MCentral.
-	if(g == g->m->g0)
-		flushallmcaches();
-	else {
-		fn = flushallmcaches_m;
-		runtime·mcall(&fn);
-	}
-
-	// Aggregate local stats.
-	cachestats();
-
-	// Scan all spans and count number of alive objects.
-	runtime·lock(&runtime·mheap.lock);
-	for(i = 0; i < runtime·mheap.nspan; i++) {
-		s = runtime·mheap.allspans[i];
-		if(s->state != MSpanInUse)
-			continue;
-		if(s->sizeclass == 0) {
-			mstats.nmalloc++;
-			mstats.alloc += s->elemsize;
-		} else {
-			mstats.nmalloc += s->ref;
-			mstats.by_size[s->sizeclass].nmalloc += s->ref;
-			mstats.alloc += s->ref*s->elemsize;
-		}
-	}
-	runtime·unlock(&runtime·mheap.lock);
-
-	// Aggregate by size class.
-	smallfree = 0;
-	mstats.nfree = runtime·mheap.nlargefree;
-	for(i = 0; i < nelem(mstats.by_size); i++) {
-		mstats.nfree += runtime·mheap.nsmallfree[i];
-		mstats.by_size[i].nfree = runtime·mheap.nsmallfree[i];
-		mstats.by_size[i].nmalloc += runtime·mheap.nsmallfree[i];
-		smallfree += runtime·mheap.nsmallfree[i] * runtime·class_to_size[i];
-	}
-	mstats.nfree += mstats.tinyallocs;
-	mstats.nmalloc += mstats.nfree;
-
-	// Calculate derived stats.
-	mstats.total_alloc = mstats.alloc + runtime·mheap.largefree + smallfree;
-	mstats.heap_alloc = mstats.alloc;
-	mstats.heap_objects = mstats.nmalloc - mstats.nfree;
-}
-
-// Structure of arguments passed to function gc().
-// This allows the arguments to be passed via runtime·mcall.
-struct gc_args
-{
-	int64 start_time; // start time of GC in ns (just before stoptheworld)
-	bool  eagersweep;
-};
-
-static void gc(struct gc_args *args);
-
-int32
-runtime·readgogc(void)
-{
-	byte *p;
-
-	p = runtime·getenv("GOGC");
-	if(p == nil || p[0] == '\0')
-		return 100;
-	if(runtime·strcmp(p, (byte*)"off") == 0)
-		return -1;
-	return runtime·atoi(p);
-}
-
-void
-runtime·gcinit(void)
-{
-	if(sizeof(Workbuf) != WorkbufSize)
-		runtime·throw("runtime: size of Workbuf is suboptimal");
-
-	runtime·work.markfor = runtime·parforalloc(MaxGcproc);
-	runtime·gcpercent = runtime·readgogc();
-	runtime·gcdatamask = unrollglobgcprog(runtime·gcdata, runtime·edata - runtime·data);
-	runtime·gcbssmask = unrollglobgcprog(runtime·gcbss, runtime·ebss - runtime·bss);
-}
-
-void
-runtime·gc_m(void)
-{
-	struct gc_args a;
-	G *gp;
-
-	gp = g->m->curg;
-	runtime·casgstatus(gp, Grunning, Gwaiting);
-	gp->waitreason = runtime·gostringnocopy((byte*)"garbage collection");
-
-	a.start_time = (uint64)(g->m->scalararg[0]) | ((uint64)(g->m->scalararg[1]) << 32);
-	a.eagersweep = g->m->scalararg[2];
-	gc(&a);
-
-	if(nbadblock > 0) {
-		// Work out path from root to bad block.
-		for(;;) {
-			gc(&a);
-			if(nbadblock >= nelem(badblock))
-				runtime·throw("cannot find path to bad pointer");
-		}
-	}
-
-	runtime·casgstatus(gp, Gwaiting, Grunning);
-}
-
-static void
-gc(struct gc_args *args)
-{
-	int64 t0, t1, t2, t3, t4;
-	uint64 heap0, heap1, obj;
-	GCStats stats;
-
-	if(DebugPtrs)
-		runtime·printf("GC start\n");
-
-	if(runtime·debug.allocfreetrace)
-		runtime·tracegc();
-
-	g->m->traceback = 2;
-	t0 = args->start_time;
-	runtime·work.tstart = args->start_time; 
-
-	t1 = 0;
-	if(runtime·debug.gctrace)
-		t1 = runtime·nanotime();
-
-	// Sweep what is not sweeped by bgsweep.
-	while(runtime·sweepone() != -1)
-		runtime·sweep.npausesweep++;
-
-	// Cache runtime.mheap.allspans in work.spans to avoid conflicts with
-	// resizing/freeing allspans.
-	// New spans can be created while GC progresses, but they are not garbage for
-	// this round:
-	//  - new stack spans can be created even while the world is stopped.
-	//  - new malloc spans can be created during the concurrent sweep
-
-	// Even if this is stop-the-world, a concurrent exitsyscall can allocate a stack from heap.
-	runtime·lock(&runtime·mheap.lock);
-	// Free the old cached sweep array if necessary.
-	if(runtime·work.spans != nil && runtime·work.spans != runtime·mheap.allspans)
-		runtime·SysFree(runtime·work.spans, runtime·work.nspan*sizeof(runtime·work.spans[0]), &mstats.other_sys);
-	// Cache the current array for marking.
-	runtime·mheap.gcspans = runtime·mheap.allspans;
-	runtime·work.spans = runtime·mheap.allspans;
-	runtime·work.nspan = runtime·mheap.nspan;
-	runtime·unlock(&runtime·mheap.lock);
-
-	runtime·work.nwait = 0;
-	runtime·work.ndone = 0;
-	runtime·work.nproc = runtime·gcprocs();
-	runtime·parforsetup(runtime·work.markfor, runtime·work.nproc, RootCount + runtime·allglen, nil, false, markroot);
-	if(runtime·work.nproc > 1) {
-		runtime·noteclear(&runtime·work.alldone);
-		runtime·helpgc(runtime·work.nproc);
-	}
-
-	t2 = 0;
-	if(runtime·debug.gctrace)
-		t2 = runtime·nanotime();
-
-	gchelperstart();
-	runtime·parfordo(runtime·work.markfor);
-	scanblock(nil, 0, nil);
-
-	t3 = 0;
-	if(runtime·debug.gctrace)
-		t3 = runtime·nanotime();
-
-	if(runtime·work.nproc > 1)
-		runtime·notesleep(&runtime·work.alldone);
-
-	runtime·shrinkfinish();
-
-	cachestats();
-	// next_gc calculation is tricky with concurrent sweep since we don't know size of live heap
-	// estimate what was live heap size after previous GC (for tracing only)
-	heap0 = mstats.next_gc*100/(runtime·gcpercent+100);
-	// conservatively set next_gc to high value assuming that everything is live
-	// concurrent/lazy sweep will reduce this number while discovering new garbage
-	mstats.next_gc = mstats.heap_alloc+mstats.heap_alloc*runtime·gcpercent/100;
-
-	t4 = runtime·nanotime();
-	runtime·atomicstore64(&mstats.last_gc, runtime·unixnanotime());  // must be Unix time to make sense to user
-	mstats.pause_ns[mstats.numgc%nelem(mstats.pause_ns)] = t4 - t0;
-	mstats.pause_end[mstats.numgc%nelem(mstats.pause_end)] = t4;
-	mstats.pause_total_ns += t4 - t0;
-	mstats.numgc++;
-	if(mstats.debuggc)
-		runtime·printf("pause %D\n", t4-t0);
-
-	if(runtime·debug.gctrace) {
-		heap1 = mstats.heap_alloc;
-		runtime·updatememstats(&stats);
-		if(heap1 != mstats.heap_alloc) {
-			runtime·printf("runtime: mstats skew: heap=%D/%D\n", heap1, mstats.heap_alloc);
-			runtime·throw("mstats skew");
-		}
-		obj = mstats.nmalloc - mstats.nfree;
-
-		stats.nprocyield += runtime·work.markfor->nprocyield;
-		stats.nosyield += runtime·work.markfor->nosyield;
-		stats.nsleep += runtime·work.markfor->nsleep;
-
-		runtime·printf("gc%d(%d): %D+%D+%D+%D us, %D -> %D MB, %D (%D-%D) objects,"
-				" %d goroutines,"
-				" %d/%d/%d sweeps,"
-				" %D(%D) handoff, %D(%D) steal, %D/%D/%D yields\n",
-			mstats.numgc, runtime·work.nproc, (t1-t0)/1000, (t2-t1)/1000, (t3-t2)/1000, (t4-t3)/1000,
-			heap0>>20, heap1>>20, obj,
-			mstats.nmalloc, mstats.nfree,
-			runtime·gcount(),
-			runtime·work.nspan, runtime·sweep.nbgsweep, runtime·sweep.npausesweep,
-			stats.nhandoff, stats.nhandoffcnt,
-			runtime·work.markfor->nsteal, runtime·work.markfor->nstealcnt,
-			stats.nprocyield, stats.nosyield, stats.nsleep);
-		runtime·sweep.nbgsweep = runtime·sweep.npausesweep = 0;
-	}
-
-	// See the comment in the beginning of this function as to why we need the following.
-	// Even if this is still stop-the-world, a concurrent exitsyscall can allocate a stack from heap.
-	runtime·lock(&runtime·mheap.lock);
-	// Free the old cached mark array if necessary.
-	if(runtime·work.spans != nil && runtime·work.spans != runtime·mheap.allspans)
-		runtime·SysFree(runtime·work.spans, runtime·work.nspan*sizeof(runtime·work.spans[0]), &mstats.other_sys);
-	// Cache the current array for sweeping.
-	runtime·mheap.gcspans = runtime·mheap.allspans;
-	runtime·mheap.sweepgen += 2;
-	runtime·mheap.sweepdone = false;
-	runtime·work.spans = runtime·mheap.allspans;
-	runtime·work.nspan = runtime·mheap.nspan;
-	runtime·sweep.spanidx = 0;
-	runtime·unlock(&runtime·mheap.lock);
-
-	if(ConcurrentSweep && !args->eagersweep) {
-		runtime·lock(&runtime·gclock);
-		if(runtime·sweep.g == nil)
-			runtime·sweep.g = runtime·newproc1(&bgsweepv, nil, 0, 0, gc);
-		else if(runtime·sweep.parked) {
-			runtime·sweep.parked = false;
-			runtime·ready(runtime·sweep.g);
-		}
-		runtime·unlock(&runtime·gclock);
-	} else {
-		// Sweep all spans eagerly.
-		while(runtime·sweepone() != -1)
-			runtime·sweep.npausesweep++;
-		// Do an additional mProf_GC, because all 'free' events are now real as well.
-		runtime·mProf_GC();
-	}
-
-	runtime·mProf_GC();
-	g->m->traceback = 0;
-
-	if(DebugPtrs)
-		runtime·printf("GC end\n");
-}
-
-extern uintptr runtime·sizeof_C_MStats;
-
-static void readmemstats_m(void);
-
-void
-runtime·readmemstats_m(void)
-{
-	MStats *stats;
-	
-	stats = g->m->ptrarg[0];
-	g->m->ptrarg[0] = nil;
-
-	runtime·updatememstats(nil);
-	// Size of the trailing by_size array differs between Go and C,
-	// NumSizeClasses was changed, but we can not change Go struct because of backward compatibility.
-	runtime·memmove(stats, &mstats, runtime·sizeof_C_MStats);
-
-	// Stack numbers are part of the heap numbers, separate those out for user consumption
-	stats->stacks_sys = stats->stacks_inuse;
-	stats->heap_inuse -= stats->stacks_inuse;
-	stats->heap_sys -= stats->stacks_inuse;
-}
-
-static void readgcstats_m(void);
-
-#pragma textflag NOSPLIT
-void
-runtime∕debug·readGCStats(Slice *pauses)
-{
-	void (*fn)(void);
-	
-	g->m->ptrarg[0] = pauses;
-	fn = readgcstats_m;
-	runtime·onM(&fn);
-}
-
-static void
-readgcstats_m(void)
-{
-	Slice *pauses;	
-	uint64 *p;
-	uint32 i, j, n;
-	
-	pauses = g->m->ptrarg[0];
-	g->m->ptrarg[0] = nil;
-
-	// Calling code in runtime/debug should make the slice large enough.
-	if(pauses->cap < nelem(mstats.pause_ns)+3)
-		runtime·throw("runtime: short slice passed to readGCStats");
-
-	// Pass back: pauses, pause ends, last gc (absolute time), number of gc, total pause ns.
-	p = (uint64*)pauses->array;
-	runtime·lock(&runtime·mheap.lock);
-
-	n = mstats.numgc;
-	if(n > nelem(mstats.pause_ns))
-		n = nelem(mstats.pause_ns);
-
-	// The pause buffer is circular. The most recent pause is at
-	// pause_ns[(numgc-1)%nelem(pause_ns)], and then backward
-	// from there to go back farther in time. We deliver the times
-	// most recent first (in p[0]).
-	for(i=0; i<n; i++) {
-		j = (mstats.numgc-1-i)%nelem(mstats.pause_ns);
-		p[i] = mstats.pause_ns[j];
-		p[n+i] = mstats.pause_end[j];
-	}
-
-	p[n+n] = mstats.last_gc;
-	p[n+n+1] = mstats.numgc;
-	p[n+n+2] = mstats.pause_total_ns;	
-	runtime·unlock(&runtime·mheap.lock);
-	pauses->len = n+n+3;
-}
-
-void
-runtime·setgcpercent_m(void)
-{
-	int32 in;
-	int32 out;
-
-	in = (int32)(intptr)g->m->scalararg[0];
-
-	runtime·lock(&runtime·mheap.lock);
-	out = runtime·gcpercent;
-	if(in < 0)
-		in = -1;
-	runtime·gcpercent = in;
-	runtime·unlock(&runtime·mheap.lock);
-
-	g->m->scalararg[0] = (uintptr)(intptr)out;
-}
-
-static void
-gchelperstart(void)
-{
-	if(g->m->helpgc < 0 || g->m->helpgc >= MaxGcproc)
-		runtime·throw("gchelperstart: bad m->helpgc");
-	if(g != g->m->g0)
-		runtime·throw("gchelper not running on g0 stack");
-}
-
-G*
-runtime·wakefing(void)
-{
-	G *res;
-
-	res = nil;
-	runtime·lock(&runtime·finlock);
-	if(runtime·fingwait && runtime·fingwake) {
-		runtime·fingwait = false;
-		runtime·fingwake = false;
-		res = runtime·fing;
-	}
-	runtime·unlock(&runtime·finlock);
-	return res;
-}
-
-// Recursively unrolls GC program in prog.
-// mask is where to store the result.
-// ppos is a pointer to position in mask, in bits.
-// sparse says to generate 4-bits per word mask for heap (2-bits for data/bss otherwise).
-static byte*
-unrollgcprog1(byte *mask, byte *prog, uintptr *ppos, bool inplace, bool sparse)
-{
-	uintptr pos, siz, i, off;
-	byte *arena_start, *prog1, v, *bitp, shift;
-
-	arena_start = runtime·mheap.arena_start;
-	pos = *ppos;
-	for(;;) {
-		switch(prog[0]) {
-		case insData:
-			prog++;
-			siz = prog[0];
-			prog++;
-			for(i = 0; i < siz; i++) {
-				v = prog[i/PointersPerByte];
-				v >>= (i%PointersPerByte)*BitsPerPointer;
-				v &= BitsMask;
-				if(inplace) {
-					// Store directly into GC bitmap.
-					off = (uintptr*)(mask+pos) - (uintptr*)arena_start;
-					bitp = arena_start - off/wordsPerBitmapByte - 1;
-					shift = (off % wordsPerBitmapByte) * gcBits;
-					if(shift==0)
-						*bitp = 0;
-					*bitp |= v<<(shift+2);
-					pos += PtrSize;
-				} else if(sparse) {
-					// 4-bits per word
-					v <<= (pos%8)+2;
-					mask[pos/8] |= v;
-					pos += gcBits;
-				} else {
-					// 2-bits per word
-					v <<= pos%8;
-					mask[pos/8] |= v;
-					pos += BitsPerPointer;
-				}
-			}
-			prog += ROUND(siz*BitsPerPointer, 8)/8;
-			break;
-		case insArray:
-			prog++;
-			siz = 0;
-			for(i = 0; i < PtrSize; i++)
-				siz = (siz<<8) + prog[PtrSize-i-1];
-			prog += PtrSize;
-			prog1 = nil;
-			for(i = 0; i < siz; i++)
-				prog1 = unrollgcprog1(mask, prog, &pos, inplace, sparse);
-			if(prog1[0] != insArrayEnd)
-				runtime·throw("unrollgcprog: array does not end with insArrayEnd");
-			prog = prog1+1;
-			break;
-		case insArrayEnd:
-		case insEnd:
-			*ppos = pos;
-			return prog;
-		default:
-			runtime·throw("unrollgcprog: unknown instruction");
-		}
-	}
-}
-
-// Unrolls GC program prog for data/bss, returns dense GC mask.
-static BitVector
-unrollglobgcprog(byte *prog, uintptr size)
-{
-	byte *mask;
-	uintptr pos, masksize;
-
-	masksize = ROUND(ROUND(size, PtrSize)/PtrSize*BitsPerPointer, 8)/8;
-	mask = runtime·persistentalloc(masksize+1, 0, &mstats.gc_sys);
-	mask[masksize] = 0xa1;
-	pos = 0;
-	prog = unrollgcprog1(mask, prog, &pos, false, false);
-	if(pos != size/PtrSize*BitsPerPointer) {
-		runtime·printf("unrollglobgcprog: bad program size, got %D, expect %D\n",
-			(uint64)pos, (uint64)size/PtrSize*BitsPerPointer);
-		runtime·throw("unrollglobgcprog: bad program size");
-	}
-	if(prog[0] != insEnd)
-		runtime·throw("unrollglobgcprog: program does not end with insEnd");
-	if(mask[masksize] != 0xa1)
-		runtime·throw("unrollglobgcprog: overflow");
-	return (BitVector){masksize*8, mask};
-}
-
-void
-runtime·unrollgcproginplace_m(void)
-{
-	uintptr size, size0, pos, off;
-	byte *arena_start, *prog, *bitp, shift;
-	Type *typ;
-	void *v;
-
-	v = g->m->ptrarg[0];
-	typ = g->m->ptrarg[1];
-	size = g->m->scalararg[0];
-	size0 = g->m->scalararg[1];
-	g->m->ptrarg[0] = nil;
-	g->m->ptrarg[1] = nil;
-
-	pos = 0;
-	prog = (byte*)typ->gc[1];
-	while(pos != size0)
-		unrollgcprog1(v, prog, &pos, true, true);
-	// Mark first word as bitAllocated.
-	arena_start = runtime·mheap.arena_start;
-	off = (uintptr*)v - (uintptr*)arena_start;
-	bitp = arena_start - off/wordsPerBitmapByte - 1;
-	shift = (off % wordsPerBitmapByte) * gcBits;
-	*bitp |= bitBoundary<<shift;
-	// Mark word after last as BitsDead.
-	if(size0 < size) {
-		off = (uintptr*)((byte*)v + size0) - (uintptr*)arena_start;
-		bitp = arena_start - off/wordsPerBitmapByte - 1;
-		shift = (off % wordsPerBitmapByte) * gcBits;
-		*bitp &= ~(bitPtrMask<<shift) | ((uintptr)BitsDead<<(shift+2));
-	}
-}
-
-// Unrolls GC program in typ->gc[1] into typ->gc[0]
-void
-runtime·unrollgcprog_m(void)
-{
-	static Mutex lock;
-	Type *typ;
-	byte *mask, *prog;
-	uintptr pos;
-	uint32 x;
-
-	typ = g->m->ptrarg[0];
-	g->m->ptrarg[0] = nil;
-
-	runtime·lock(&lock);
-	mask = (byte*)typ->gc[0];
-	if(mask[0] == 0) {
-		pos = 8;  // skip the unroll flag
-		prog = (byte*)typ->gc[1];
-		prog = unrollgcprog1(mask, prog, &pos, false, true);
-		if(prog[0] != insEnd)
-			runtime·throw("unrollgcprog: program does not end with insEnd");
-		if(((typ->size/PtrSize)%2) != 0) {
-			// repeat the program twice
-			prog = (byte*)typ->gc[1];
-			unrollgcprog1(mask, prog, &pos, false, true);
-		}
-		// atomic way to say mask[0] = 1
-		x = ((uint32*)mask)[0];
-		runtime·atomicstore((uint32*)mask, x|1);
-	}
-	runtime·unlock(&lock);
-}
-
-// mark the span of memory at v as having n blocks of the given size.
-// if leftover is true, there is left over space at the end of the span.
-void
-runtime·markspan(void *v, uintptr size, uintptr n, bool leftover)
-{
-	uintptr i, off, step;
-	byte *b;
-
-	if((byte*)v+size*n > (byte*)runtime·mheap.arena_used || (byte*)v < runtime·mheap.arena_start)
-		runtime·throw("markspan: bad pointer");
-
-	// Find bits of the beginning of the span.
-	off = (uintptr*)v - (uintptr*)runtime·mheap.arena_start;  // word offset
-	b = runtime·mheap.arena_start - off/wordsPerBitmapByte - 1;
-	if((off%wordsPerBitmapByte) != 0)
-		runtime·throw("markspan: unaligned length");
-
-	// Okay to use non-atomic ops here, because we control
-	// the entire span, and each bitmap byte has bits for only
-	// one span, so no other goroutines are changing these bitmap words.
-
-	if(size == PtrSize) {
-		// Possible only on 64-bits (minimal size class is 8 bytes).
-		// Poor man's memset(0x11).
-		if(0x11 != ((bitBoundary+BitsDead)<<gcBits) + (bitBoundary+BitsDead))
-			runtime·throw("markspan: bad bits");
-		if((n%(wordsPerBitmapByte*PtrSize)) != 0)
-			runtime·throw("markspan: unaligned length");
-		b = b - n/wordsPerBitmapByte + 1;	// find first byte
-		if(((uintptr)b%PtrSize) != 0)
-			runtime·throw("markspan: unaligned pointer");
-		for(i = 0; i != n; i += wordsPerBitmapByte*PtrSize, b += PtrSize)
-			*(uintptr*)b = (uintptr)0x1111111111111111ULL;  // bitBoundary+BitsDead
-		return;
-	}
-
-	if(leftover)
-		n++;	// mark a boundary just past end of last block too
-	step = size/(PtrSize*wordsPerBitmapByte);
-	for(i = 0; i != n; i++, b -= step)
-		*b = bitBoundary|(BitsDead<<2);
-}
-
-// unmark the span of memory at v of length n bytes.
-void
-runtime·unmarkspan(void *v, uintptr n)
-{
-	uintptr off;
-	byte *b;
-
-	if((byte*)v+n > (byte*)runtime·mheap.arena_used || (byte*)v < runtime·mheap.arena_start)
-		runtime·throw("markspan: bad pointer");
-
-	off = (uintptr*)v - (uintptr*)runtime·mheap.arena_start;  // word offset
-	if((off % (PtrSize*wordsPerBitmapByte)) != 0)
-		runtime·throw("markspan: unaligned pointer");
-	b = runtime·mheap.arena_start - off/wordsPerBitmapByte - 1;
-	n /= PtrSize;
-	if(n%(PtrSize*wordsPerBitmapByte) != 0)
-		runtime·throw("unmarkspan: unaligned length");
-	// Okay to use non-atomic ops here, because we control
-	// the entire span, and each bitmap word has bits for only
-	// one span, so no other goroutines are changing these
-	// bitmap words.
-	n /= wordsPerBitmapByte;
-	runtime·memclr(b - n + 1, n);
-}
-
-void
-runtime·MHeap_MapBits(MHeap *h)
-{
-	// Caller has added extra mappings to the arena.
-	// Add extra mappings of bitmap words as needed.
-	// We allocate extra bitmap pieces in chunks of bitmapChunk.
-	enum {
-		bitmapChunk = 8192
-	};
-	uintptr n;
-
-	n = (h->arena_used - h->arena_start) / (PtrSize*wordsPerBitmapByte);
-	n = ROUND(n, bitmapChunk);
-	n = ROUND(n, PhysPageSize);
-	if(h->bitmap_mapped >= n)
-		return;
-
-	runtime·SysMap(h->arena_start - n, n - h->bitmap_mapped, h->arena_reserved, &mstats.gc_sys);
-	h->bitmap_mapped = n;
-}
-
-static bool
-getgcmaskcb(Stkframe *frame, void *ctxt)
-{
-	Stkframe *frame0;
-
-	frame0 = ctxt;
-	if(frame->sp <= frame0->sp && frame0->sp < frame->varp) {
-		*frame0 = *frame;
-		return false;
-	}
-	return true;
-}
-
-// Returns GC type info for object p for testing.
-void
-runtime·getgcmask(byte *p, Type *t, byte **mask, uintptr *len)
-{
-	Stkframe frame;
-	uintptr i, n, off;
-	byte *base, bits, shift, *b;
-	bool (*cb)(Stkframe*, void*);
-
-	*mask = nil;
-	*len = 0;
-
-	// data
-	if(p >= runtime·data && p < runtime·edata) {
-		n = ((PtrType*)t)->elem->size;
-		*len = n/PtrSize;
-		*mask = runtime·mallocgc(*len, nil, FlagNoScan);
-		for(i = 0; i < n; i += PtrSize) {
-			off = (p+i-runtime·data)/PtrSize;
-			bits = (runtime·gcdatamask.bytedata[off/PointersPerByte] >> ((off%PointersPerByte)*BitsPerPointer))&BitsMask;
-			(*mask)[i/PtrSize] = bits;
-		}
-		return;
-	}
-	// bss
-	if(p >= runtime·bss && p < runtime·ebss) {
-		n = ((PtrType*)t)->elem->size;
-		*len = n/PtrSize;
-		*mask = runtime·mallocgc(*len, nil, FlagNoScan);
-		for(i = 0; i < n; i += PtrSize) {
-			off = (p+i-runtime·bss)/PtrSize;
-			bits = (runtime·gcbssmask.bytedata[off/PointersPerByte] >> ((off%PointersPerByte)*BitsPerPointer))&BitsMask;
-			(*mask)[i/PtrSize] = bits;
-		}
-		return;
-	}
-	// heap
-	if(runtime·mlookup(p, &base, &n, nil)) {
-		*len = n/PtrSize;
-		*mask = runtime·mallocgc(*len, nil, FlagNoScan);
-		for(i = 0; i < n; i += PtrSize) {
-			off = (uintptr*)(base+i) - (uintptr*)runtime·mheap.arena_start;
-			b = runtime·mheap.arena_start - off/wordsPerBitmapByte - 1;
-			shift = (off % wordsPerBitmapByte) * gcBits;
-			bits = (*b >> (shift+2))&BitsMask;
-			(*mask)[i/PtrSize] = bits;
-		}
-		return;
-	}
-	// stack
-	frame.fn = nil;
-	frame.sp = (uintptr)p;
-	cb = getgcmaskcb;
-	runtime·gentraceback(g->m->curg->sched.pc, g->m->curg->sched.sp, 0, g->m->curg, 0, nil, 1000, &cb, &frame, 0);
-	if(frame.fn != nil) {
-		Func *f;
-		StackMap *stackmap;
-		BitVector bv;
-		uintptr size;
-		uintptr targetpc;
-		int32 pcdata;
-
-		f = frame.fn;
-		targetpc = frame.continpc;
-		if(targetpc == 0)
-			return;
-		if(targetpc != f->entry)
-			targetpc--;
-		pcdata = runtime·pcdatavalue(f, PCDATA_StackMapIndex, targetpc);
-		if(pcdata == -1)
-			return;
-		stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps);
-		if(stackmap == nil || stackmap->n <= 0)
-			return;
-		bv = runtime·stackmapdata(stackmap, pcdata);
-		size = bv.n/BitsPerPointer*PtrSize;
-		n = ((PtrType*)t)->elem->size;
-		*len = n/PtrSize;
-		*mask = runtime·mallocgc(*len, nil, FlagNoScan);
-		for(i = 0; i < n; i += PtrSize) {
-			off = (p+i-(byte*)frame.varp+size)/PtrSize;
-			bits = (bv.bytedata[off*BitsPerPointer/8] >> ((off*BitsPerPointer)%8))&BitsMask;
-			(*mask)[i/PtrSize] = bits;
-		}
-	}
-}
-
-void runtime·gc_unixnanotime(int64 *now);
-
-int64
-runtime·unixnanotime(void)
-{
-	int64 now;
-
-	runtime·gc_unixnanotime(&now);
-	return now;
-}
diff --git a/src/runtime/mgc0.go b/src/runtime/mgc0.go
deleted file mode 100644
index cbf5e9c..0000000
--- a/src/runtime/mgc0.go
+++ /dev/null
@@ -1,152 +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.
-
-package runtime
-
-import "unsafe"
-
-// Called from C. Returns the Go type *m.
-func gc_m_ptr(ret *interface{}) {
-	*ret = (*m)(nil)
-}
-
-// Called from C. Returns the Go type *g.
-func gc_g_ptr(ret *interface{}) {
-	*ret = (*g)(nil)
-}
-
-// Called from C. Returns the Go type *itab.
-func gc_itab_ptr(ret *interface{}) {
-	*ret = (*itab)(nil)
-}
-
-func gc_unixnanotime(now *int64) {
-	sec, nsec := timenow()
-	*now = sec*1e9 + int64(nsec)
-}
-
-func freeOSMemory() {
-	gogc(2) // force GC and do eager sweep
-	onM(scavenge_m)
-}
-
-var poolcleanup func()
-
-func registerPoolCleanup(f func()) {
-	poolcleanup = f
-}
-
-func clearpools() {
-	// clear sync.Pools
-	if poolcleanup != nil {
-		poolcleanup()
-	}
-
-	for _, p := range &allp {
-		if p == nil {
-			break
-		}
-		// clear tinyalloc pool
-		if c := p.mcache; c != nil {
-			c.tiny = nil
-			c.tinysize = 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
-		}
-	}
-}
-
-func gosweepone() uintptr
-func gosweepdone() bool
-
-func bgsweep() {
-	getg().issystem = true
-	for {
-		for gosweepone() != ^uintptr(0) {
-			sweep.nbgsweep++
-			Gosched()
-		}
-		lock(&gclock)
-		if !gosweepdone() {
-			// This can happen if a GC runs between
-			// gosweepone returning ^0 above
-			// and the lock being acquired.
-			unlock(&gclock)
-			continue
-		}
-		sweep.parked = true
-		goparkunlock(&gclock, "GC sweep wait")
-	}
-}
-
-// NOTE: Really dst *unsafe.Pointer, src unsafe.Pointer,
-// but if we do that, Go inserts a write barrier on *dst = src.
-//go:nosplit
-func writebarrierptr(dst *uintptr, src uintptr) {
-	*dst = src
-}
-
-//go:nosplit
-func writebarrierstring(dst *[2]uintptr, src [2]uintptr) {
-	dst[0] = src[0]
-	dst[1] = src[1]
-}
-
-//go:nosplit
-func writebarrierslice(dst *[3]uintptr, src [3]uintptr) {
-	dst[0] = src[0]
-	dst[1] = src[1]
-	dst[2] = src[2]
-}
-
-//go:nosplit
-func writebarrieriface(dst *[2]uintptr, src [2]uintptr) {
-	dst[0] = src[0]
-	dst[1] = src[1]
-}
-
-//go:nosplit
-func writebarrierfat2(dst *[2]uintptr, _ *byte, src [2]uintptr) {
-	dst[0] = src[0]
-	dst[1] = src[1]
-}
-
-//go:nosplit
-func writebarrierfat3(dst *[3]uintptr, _ *byte, src [3]uintptr) {
-	dst[0] = src[0]
-	dst[1] = src[1]
-	dst[2] = src[2]
-}
-
-//go:nosplit
-func writebarrierfat4(dst *[4]uintptr, _ *byte, src [4]uintptr) {
-	dst[0] = src[0]
-	dst[1] = src[1]
-	dst[2] = src[2]
-	dst[3] = src[3]
-}
-
-//go:nosplit
-func writebarrierfat(typ *_type, dst, src unsafe.Pointer) {
-	memmove(dst, src, typ.size)
-}
diff --git a/src/runtime/mgc0.h b/src/runtime/mgc0.h
deleted file mode 100644
index 64f8189..0000000
--- a/src/runtime/mgc0.h
+++ /dev/null
@@ -1,78 +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.
-
-// Garbage collector (GC)
-
-enum {
-	// Four bits per word (see #defines below).
-	gcBits = 4,
-	wordsPerBitmapByte = 8/gcBits,
-
-	// GC type info programs.
-	// The programs allow to store type info required for GC in a compact form.
-	// Most importantly arrays take O(1) space instead of O(n).
-	// The program grammar is:
-	//
-	// Program = {Block} "insEnd"
-	// Block = Data | Array
-	// Data = "insData" DataSize DataBlock
-	// DataSize = int // size of the DataBlock in bit pairs, 1 byte
-	// DataBlock = binary // dense GC mask (2 bits per word) of size ]DataSize/4[ bytes
-	// Array = "insArray" ArrayLen Block "insArrayEnd"
-	// ArrayLen = int // length of the array, 8 bytes (4 bytes for 32-bit arch)
-	//
-	// Each instruction (insData, insArray, etc) is 1 byte.
-	// For example, for type struct { x []byte; y [20]struct{ z int; w *byte }; }
-	// the program looks as:
-	//
-	// insData 3 (BitsMultiWord BitsSlice BitsScalar)
-	//	insArray 20 insData 2 (BitsScalar BitsPointer) insArrayEnd insEnd
-	//
-	// Total size of the program is 17 bytes (13 bytes on 32-bits).
-	// The corresponding GC mask would take 43 bytes (it would be repeated
-	// because the type has odd number of words).
-	insData = 1,
-	insArray,
-	insArrayEnd,
-	insEnd,
-
-	// Pointer map
-	BitsPerPointer	= 2,
-	BitsMask	= (1<<BitsPerPointer)-1,
-	PointersPerByte	= 8/BitsPerPointer,
-
-	// If you change these, also change scanblock.
-	// scanblock does "if(bits == BitsScalar || bits == BitsDead)" as "if(bits <= BitsScalar)".
-	BitsDead	= 0,
-	BitsScalar	= 1,
-	BitsPointer	= 2,
-	BitsMultiWord	= 3,
-	// BitsMultiWord will be set for the first word of a multi-word item.
-	// When it is set, one of the following will be set for the second word.
-	// NOT USED ANYMORE: BitsString	= 0,
-	// NOT USED ANYMORE: BitsSlice	= 1,
-	BitsIface	= 2,
-	BitsEface	= 3,
-
-	// 64 bytes cover objects of size 1024/512 on 64/32 bits, respectively.
-	MaxGCMask	= 64,
-};
-
-// Bits in per-word bitmap.
-// #defines because we shift the values beyond 32 bits.
-//
-// Each word in the bitmap describes wordsPerBitmapWord words
-// of heap memory.  There are 4 bitmap bits dedicated to each heap word,
-// so on a 64-bit system there is one bitmap word per 16 heap words.
-//
-// The bitmap starts at mheap.arena_start and extends *backward* from
-// there.  On a 64-bit system the off'th word in the arena is tracked by
-// the off/16+1'th word before mheap.arena_start.  (On a 32-bit system,
-// the only difference is that the divisor is 8.)
-enum {
-	bitBoundary = 1, // boundary of an object
-	bitMarked = 2, // marked object
-	bitMask = bitBoundary | bitMarked,
-	bitPtrMask = BitsMask<<2,
-};
diff --git a/src/runtime/mgcmark.go b/src/runtime/mgcmark.go
new file mode 100644
index 0000000..44f9512
--- /dev/null
+++ b/src/runtime/mgcmark.go
@@ -0,0 +1,1035 @@
+// 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.
+
+// Garbage collector: marking and scanning
+
+package runtime
+
+import "unsafe"
+
+// Scan all of the stacks, greying (or graying if in America) the referents
+// but not blackening them since the mark write barrier isn't installed.
+//go:nowritebarrier
+func gcscan_m() {
+	_g_ := getg()
+
+	// Grab the g that called us and potentially allow rescheduling.
+	// This allows it to be scanned like other goroutines.
+	mastergp := _g_.m.curg
+	casgstatus(mastergp, _Grunning, _Gwaiting)
+	mastergp.waitreason = "garbage collection scan"
+
+	// Span sweeping has been done by finishsweep_m.
+	// Long term we will want to make this goroutine runnable
+	// by placing it onto a scanenqueue state and then calling
+	// runtime·restartg(mastergp) to make it Grunnable.
+	// At the bottom we will want to return this p back to the scheduler.
+
+	// Prepare flag indicating that the scan has not been completed.
+	local_allglen := gcResetGState()
+
+	work.ndone = 0
+	useOneP := uint32(1) // For now do not do this in parallel.
+	//	ackgcphase is not needed since we are not scanning running goroutines.
+	parforsetup(work.markfor, useOneP, uint32(_RootCount+local_allglen), false, markroot)
+	parfordo(work.markfor)
+
+	lock(&allglock)
+	// Check that gc work is done.
+	for i := 0; i < local_allglen; i++ {
+		gp := allgs[i]
+		if !gp.gcscandone {
+			throw("scan missed a g")
+		}
+	}
+	unlock(&allglock)
+
+	casgstatus(mastergp, _Gwaiting, _Grunning)
+	// Let the g that called us continue to run.
+}
+
+// ptrmask for an allocation containing a single pointer.
+var oneptrmask = [...]uint8{1}
+
+//go:nowritebarrier
+func markroot(desc *parfor, i uint32) {
+	// TODO: Consider using getg().m.p.ptr().gcw.
+	var gcw gcWork
+
+	// Note: if you add a case here, please also update heapdump.go:dumproots.
+	switch i {
+	case _RootData:
+		for datap := &firstmoduledata; datap != nil; datap = datap.next {
+			scanblock(datap.data, datap.edata-datap.data, datap.gcdatamask.bytedata, &gcw)
+		}
+
+	case _RootBss:
+		for datap := &firstmoduledata; datap != nil; datap = datap.next {
+			scanblock(datap.bss, datap.ebss-datap.bss, datap.gcbssmask.bytedata, &gcw)
+		}
+
+	case _RootFinalizers:
+		for fb := allfin; fb != nil; fb = fb.alllink {
+			scanblock(uintptr(unsafe.Pointer(&fb.fin[0])), uintptr(fb.cnt)*unsafe.Sizeof(fb.fin[0]), &finptrmask[0], &gcw)
+		}
+
+	case _RootSpans:
+		// mark MSpan.specials
+		sg := mheap_.sweepgen
+		for spanidx := uint32(0); spanidx < uint32(len(work.spans)); spanidx++ {
+			s := work.spans[spanidx]
+			if s.state != mSpanInUse {
+				continue
+			}
+			if !useCheckmark && s.sweepgen != sg {
+				// sweepgen was updated (+2) during non-checkmark GC pass
+				print("sweep ", s.sweepgen, " ", sg, "\n")
+				throw("gc: unswept span")
+			}
+			for sp := s.specials; sp != nil; sp = sp.next {
+				if sp.kind != _KindSpecialFinalizer {
+					continue
+				}
+				// don't mark finalized object, but scan it so we
+				// retain everything it points to.
+				spf := (*specialfinalizer)(unsafe.Pointer(sp))
+				// A finalizer can be set for an inner byte of an object, find object beginning.
+				p := uintptr(s.start<<_PageShift) + uintptr(spf.special.offset)/s.elemsize*s.elemsize
+				if gcphase != _GCscan {
+					scanobject(p, &gcw) // scanned during mark termination
+				}
+				scanblock(uintptr(unsafe.Pointer(&spf.fn)), ptrSize, &oneptrmask[0], &gcw)
+			}
+		}
+
+	case _RootFlushCaches:
+		if gcphase != _GCscan { // Do not flush mcaches during GCscan phase.
+			flushallmcaches()
+		}
+
+	default:
+		// the rest is scanning goroutine stacks
+		if uintptr(i-_RootCount) >= allglen {
+			throw("markroot: bad index")
+		}
+		gp := allgs[i-_RootCount]
+
+		// remember when we've first observed the G blocked
+		// needed only to output in traceback
+		status := readgstatus(gp) // We are not in a scan state
+		if (status == _Gwaiting || status == _Gsyscall) && gp.waitsince == 0 {
+			gp.waitsince = work.tstart
+		}
+
+		// Shrink a stack if not much of it is being used but not in the scan phase.
+		if gcphase == _GCmarktermination {
+			// Shrink during STW GCmarktermination phase thus avoiding
+			// complications introduced by shrinking during
+			// non-STW phases.
+			shrinkstack(gp)
+		}
+
+		scang(gp)
+	}
+
+	gcw.dispose()
+}
+
+// gcAssistAlloc records and allocation of size bytes and, if
+// allowAssist is true, may assist GC scanning in proportion to the
+// allocations performed by this mutator since the last assist.
+//
+// It should only be called if gcAssistAlloc != 0.
+//
+// This must be called with preemption disabled.
+//go:nowritebarrier
+func gcAssistAlloc(size uintptr, allowAssist bool) {
+	// Find the G responsible for this assist.
+	gp := getg()
+	if gp.m.curg != nil {
+		gp = gp.m.curg
+	}
+
+	// Record allocation.
+	gp.gcalloc += size
+
+	if !allowAssist {
+		return
+	}
+
+	// Don't assist in non-preemptible contexts. These are
+	// generally fragile and won't allow the assist to block.
+	if getg() == gp.m.g0 {
+		return
+	}
+	if mp := getg().m; mp.locks > 0 || mp.preemptoff != "" {
+		return
+	}
+
+	// Compute the amount of assist scan work we need to do.
+	scanWork := int64(gcController.assistRatio*float64(gp.gcalloc)) - gp.gcscanwork
+	// scanWork can be negative if the last assist scanned a large
+	// object and we're still ahead of our assist goal.
+	if scanWork <= 0 {
+		return
+	}
+
+retry:
+	// Steal as much credit as we can from the background GC's
+	// scan credit. This is racy and may drop the background
+	// credit below 0 if two mutators steal at the same time. This
+	// will just cause steals to fail until credit is accumulated
+	// again, so in the long run it doesn't really matter, but we
+	// do have to handle the negative credit case.
+	bgScanCredit := atomicloadint64(&gcController.bgScanCredit)
+	stolen := int64(0)
+	if bgScanCredit > 0 {
+		if bgScanCredit < scanWork {
+			stolen = bgScanCredit
+		} else {
+			stolen = scanWork
+		}
+		xaddint64(&gcController.bgScanCredit, -stolen)
+
+		scanWork -= stolen
+		gp.gcscanwork += stolen
+
+		if scanWork == 0 {
+			return
+		}
+	}
+
+	// Perform assist work
+	completed := false
+	systemstack(func() {
+		if atomicload(&gcBlackenEnabled) == 0 {
+			// The gcBlackenEnabled check in malloc races with the
+			// store that clears it but an atomic check in every malloc
+			// would be a performance hit.
+			// Instead we recheck it here on the non-preemptable system
+			// stack to determine if we should preform an assist.
+
+			// GC is done, so ignore any remaining debt.
+			scanWork = 0
+			return
+		}
+		// Track time spent in this assist. Since we're on the
+		// system stack, this is non-preemptible, so we can
+		// just measure start and end time.
+		startTime := nanotime()
+
+		decnwait := xadd(&work.nwait, -1)
+		if decnwait == work.nproc {
+			println("runtime: work.nwait =", decnwait, "work.nproc=", work.nproc)
+			throw("nwait > work.nprocs")
+		}
+
+		// drain own cached work first in the hopes that it
+		// will be more cache friendly.
+		gcw := &getg().m.p.ptr().gcw
+		startScanWork := gcw.scanWork
+		gcDrainN(gcw, scanWork)
+		// Record that we did this much scan work.
+		workDone := gcw.scanWork - startScanWork
+		gp.gcscanwork += workDone
+		scanWork -= workDone
+		// If we are near the end of the mark phase
+		// dispose of the gcw.
+		if gcBlackenPromptly {
+			gcw.dispose()
+		}
+		// If this is the last worker and we ran out of work,
+		// signal a completion point.
+		incnwait := xadd(&work.nwait, +1)
+		if incnwait > work.nproc {
+			println("runtime: work.nwait=", incnwait,
+				"work.nproc=", work.nproc,
+				"gcBlackenPromptly=", gcBlackenPromptly)
+			throw("work.nwait > work.nproc")
+		}
+
+		if incnwait == work.nproc && work.full == 0 && work.partial == 0 {
+			// This has reached a background completion
+			// point.
+			if gcBlackenPromptly {
+				if work.bgMark1.done == 0 {
+					throw("completing mark 2, but bgMark1.done == 0")
+				}
+				work.bgMark2.complete()
+			} else {
+				work.bgMark1.complete()
+			}
+			completed = true
+		}
+		duration := nanotime() - startTime
+		_p_ := gp.m.p.ptr()
+		_p_.gcAssistTime += duration
+		if _p_.gcAssistTime > gcAssistTimeSlack {
+			xaddint64(&gcController.assistTime, _p_.gcAssistTime)
+			_p_.gcAssistTime = 0
+		}
+	})
+
+	if completed {
+		// We called complete() above, so we should yield to
+		// the now-runnable GC coordinator.
+		Gosched()
+
+		// It's likely that this assist wasn't able to pay off
+		// its debt, but it's also likely that the Gosched let
+		// the GC finish this cycle and there's no point in
+		// waiting. If the GC finished, skip the delay below.
+		if atomicload(&gcBlackenEnabled) == 0 {
+			scanWork = 0
+		}
+	}
+
+	if scanWork > 0 {
+		// We were unable steal enough credit or perform
+		// enough work to pay off the assist debt. We need to
+		// do one of these before letting the mutator allocate
+		// more, so go around again after performing an
+		// interruptible sleep for 100 us (the same as the
+		// getfull barrier) to let other mutators run.
+		timeSleep(100 * 1000)
+		goto retry
+	}
+}
+
+//go:nowritebarrier
+func scanstack(gp *g) {
+	if gp.gcscanvalid {
+		if gcphase == _GCmarktermination {
+			gcRemoveStackBarriers(gp)
+		}
+		return
+	}
+
+	if readgstatus(gp)&_Gscan == 0 {
+		print("runtime:scanstack: gp=", gp, ", goid=", gp.goid, ", gp->atomicstatus=", hex(readgstatus(gp)), "\n")
+		throw("scanstack - bad status")
+	}
+
+	switch readgstatus(gp) &^ _Gscan {
+	default:
+		print("runtime: gp=", gp, ", goid=", gp.goid, ", gp->atomicstatus=", readgstatus(gp), "\n")
+		throw("mark - bad status")
+	case _Gdead:
+		return
+	case _Grunning:
+		print("runtime: gp=", gp, ", goid=", gp.goid, ", gp->atomicstatus=", readgstatus(gp), "\n")
+		throw("scanstack: goroutine not stopped")
+	case _Grunnable, _Gsyscall, _Gwaiting:
+		// ok
+	}
+
+	if gp == getg() {
+		throw("can't scan our own stack")
+	}
+	mp := gp.m
+	if mp != nil && mp.helpgc != 0 {
+		throw("can't scan gchelper stack")
+	}
+
+	var sp, barrierOffset, nextBarrier uintptr
+	if gp.syscallsp != 0 {
+		sp = gp.syscallsp
+	} else {
+		sp = gp.sched.sp
+	}
+	switch gcphase {
+	case _GCscan:
+		// Install stack barriers during stack scan.
+		barrierOffset = uintptr(firstStackBarrierOffset)
+		nextBarrier = sp + barrierOffset
+
+		if debug.gcstackbarrieroff > 0 {
+			nextBarrier = ^uintptr(0)
+		}
+
+		if gp.stkbarPos != 0 || len(gp.stkbar) != 0 {
+			// If this happens, it's probably because we
+			// scanned a stack twice in the same phase.
+			print("stkbarPos=", gp.stkbarPos, " len(stkbar)=", len(gp.stkbar), " goid=", gp.goid, " gcphase=", gcphase, "\n")
+			throw("g already has stack barriers")
+		}
+
+	case _GCmarktermination:
+		if int(gp.stkbarPos) == len(gp.stkbar) {
+			// gp hit all of the stack barriers (or there
+			// were none). Re-scan the whole stack.
+			nextBarrier = ^uintptr(0)
+		} else {
+			// Only re-scan up to the lowest un-hit
+			// barrier. Any frames above this have not
+			// executed since the _GCscan scan of gp and
+			// any writes through up-pointers to above
+			// this barrier had write barriers.
+			nextBarrier = gp.stkbar[gp.stkbarPos].savedLRPtr
+			if debugStackBarrier {
+				print("rescan below ", hex(nextBarrier), " in [", hex(sp), ",", hex(gp.stack.hi), ") goid=", gp.goid, "\n")
+			}
+		}
+
+		gcRemoveStackBarriers(gp)
+
+	default:
+		throw("scanstack in wrong phase")
+	}
+
+	gcw := &getg().m.p.ptr().gcw
+	n := 0
+	scanframe := func(frame *stkframe, unused unsafe.Pointer) bool {
+		scanframeworker(frame, unused, gcw)
+
+		if frame.fp > nextBarrier {
+			// We skip installing a barrier on bottom-most
+			// frame because on LR machines this LR is not
+			// on the stack.
+			if gcphase == _GCscan && n != 0 {
+				if gcInstallStackBarrier(gp, frame) {
+					barrierOffset *= 2
+					nextBarrier = sp + barrierOffset
+				}
+			} else if gcphase == _GCmarktermination {
+				// We just scanned a frame containing
+				// a return to a stack barrier. Since
+				// this frame never returned, we can
+				// stop scanning.
+				return false
+			}
+		}
+		n++
+
+		return true
+	}
+	gentraceback(^uintptr(0), ^uintptr(0), 0, gp, 0, nil, 0x7fffffff, scanframe, nil, 0)
+	tracebackdefers(gp, scanframe, nil)
+	if gcphase == _GCmarktermination {
+		gcw.dispose()
+	}
+	gp.gcscanvalid = true
+}
+
+// Scan a stack frame: local variables and function arguments/results.
+//go:nowritebarrier
+func scanframeworker(frame *stkframe, unused unsafe.Pointer, gcw *gcWork) {
+
+	f := frame.fn
+	targetpc := frame.continpc
+	if targetpc == 0 {
+		// Frame is dead.
+		return
+	}
+	if _DebugGC > 1 {
+		print("scanframe ", funcname(f), "\n")
+	}
+	if targetpc != f.entry {
+		targetpc--
+	}
+	pcdata := pcdatavalue(f, _PCDATA_StackMapIndex, targetpc)
+	if pcdata == -1 {
+		// We do not have a valid pcdata value but there might be a
+		// stackmap for this function.  It is likely that we are looking
+		// at the function prologue, assume so and hope for the best.
+		pcdata = 0
+	}
+
+	// Scan local variables if stack frame has been allocated.
+	size := frame.varp - frame.sp
+	var minsize uintptr
+	switch thechar {
+	case '6', '8':
+		minsize = 0
+	case '7':
+		minsize = spAlign
+	default:
+		minsize = ptrSize
+	}
+	if size > minsize {
+		stkmap := (*stackmap)(funcdata(f, _FUNCDATA_LocalsPointerMaps))
+		if stkmap == nil || stkmap.n <= 0 {
+			print("runtime: frame ", funcname(f), " untyped locals ", hex(frame.varp-size), "+", hex(size), "\n")
+			throw("missing stackmap")
+		}
+
+		// Locals bitmap information, scan just the pointers in locals.
+		if pcdata < 0 || pcdata >= stkmap.n {
+			// don't know where we are
+			print("runtime: pcdata is ", pcdata, " and ", stkmap.n, " locals stack map entries for ", funcname(f), " (targetpc=", targetpc, ")\n")
+			throw("scanframe: bad symbol table")
+		}
+		bv := stackmapdata(stkmap, pcdata)
+		size = uintptr(bv.n) * ptrSize
+		scanblock(frame.varp-size, size, bv.bytedata, gcw)
+	}
+
+	// Scan arguments.
+	if frame.arglen > 0 {
+		var bv bitvector
+		if frame.argmap != nil {
+			bv = *frame.argmap
+		} else {
+			stkmap := (*stackmap)(funcdata(f, _FUNCDATA_ArgsPointerMaps))
+			if stkmap == nil || stkmap.n <= 0 {
+				print("runtime: frame ", funcname(f), " untyped args ", hex(frame.argp), "+", hex(frame.arglen), "\n")
+				throw("missing stackmap")
+			}
+			if pcdata < 0 || pcdata >= stkmap.n {
+				// don't know where we are
+				print("runtime: pcdata is ", pcdata, " and ", stkmap.n, " args stack map entries for ", funcname(f), " (targetpc=", targetpc, ")\n")
+				throw("scanframe: bad symbol table")
+			}
+			bv = stackmapdata(stkmap, pcdata)
+		}
+		scanblock(frame.argp, uintptr(bv.n)*ptrSize, bv.bytedata, gcw)
+	}
+}
+
+// gcMaxStackBarriers returns the maximum number of stack barriers
+// that can be installed in a stack of stackSize bytes.
+func gcMaxStackBarriers(stackSize int) (n int) {
+	if firstStackBarrierOffset == 0 {
+		// Special debugging case for inserting stack barriers
+		// at every frame. Steal half of the stack for the
+		// []stkbar. Technically, if the stack were to consist
+		// solely of return PCs we would need two thirds of
+		// the stack, but stealing that much breaks things and
+		// this doesn't happen in practice.
+		return stackSize / 2 / int(unsafe.Sizeof(stkbar{}))
+	}
+
+	offset := firstStackBarrierOffset
+	for offset < stackSize {
+		n++
+		offset *= 2
+	}
+	return n + 1
+}
+
+// gcInstallStackBarrier installs a stack barrier over the return PC of frame.
+//go:nowritebarrier
+func gcInstallStackBarrier(gp *g, frame *stkframe) bool {
+	if frame.lr == 0 {
+		if debugStackBarrier {
+			print("not installing stack barrier with no LR, goid=", gp.goid, "\n")
+		}
+		return false
+	}
+
+	if frame.fn.entry == cgocallback_gofuncPC {
+		// cgocallback_gofunc doesn't return to its LR;
+		// instead, its return path puts LR in g.sched.pc and
+		// switches back to the system stack on which
+		// cgocallback_gofunc was originally called. We can't
+		// have a stack barrier in g.sched.pc, so don't
+		// install one in this frame.
+		if debugStackBarrier {
+			print("not installing stack barrier over LR of cgocallback_gofunc, goid=", gp.goid, "\n")
+		}
+		return false
+	}
+
+	// Save the return PC and overwrite it with stackBarrier.
+	var lrUintptr uintptr
+	if usesLR {
+		lrUintptr = frame.sp
+	} else {
+		lrUintptr = frame.fp - regSize
+	}
+	lrPtr := (*uintreg)(unsafe.Pointer(lrUintptr))
+	if debugStackBarrier {
+		print("install stack barrier at ", hex(lrUintptr), " over ", hex(*lrPtr), ", goid=", gp.goid, "\n")
+		if uintptr(*lrPtr) != frame.lr {
+			print("frame.lr=", hex(frame.lr))
+			throw("frame.lr differs from stack LR")
+		}
+	}
+
+	gp.stkbar = gp.stkbar[:len(gp.stkbar)+1]
+	stkbar := &gp.stkbar[len(gp.stkbar)-1]
+	stkbar.savedLRPtr = lrUintptr
+	stkbar.savedLRVal = uintptr(*lrPtr)
+	*lrPtr = uintreg(stackBarrierPC)
+	return true
+}
+
+// gcRemoveStackBarriers removes all stack barriers installed in gp's stack.
+//go:nowritebarrier
+func gcRemoveStackBarriers(gp *g) {
+	if debugStackBarrier && gp.stkbarPos != 0 {
+		print("hit ", gp.stkbarPos, " stack barriers, goid=", gp.goid, "\n")
+	}
+
+	// Remove stack barriers that we didn't hit.
+	for _, stkbar := range gp.stkbar[gp.stkbarPos:] {
+		gcRemoveStackBarrier(gp, stkbar)
+	}
+
+	// Clear recorded stack barriers so copystack doesn't try to
+	// adjust them.
+	gp.stkbarPos = 0
+	gp.stkbar = gp.stkbar[:0]
+}
+
+// gcRemoveStackBarrier removes a single stack barrier. It is the
+// inverse operation of gcInstallStackBarrier.
+//
+// This is nosplit to ensure gp's stack does not move.
+//
+//go:nowritebarrier
+//go:nosplit
+func gcRemoveStackBarrier(gp *g, stkbar stkbar) {
+	if debugStackBarrier {
+		print("remove stack barrier at ", hex(stkbar.savedLRPtr), " with ", hex(stkbar.savedLRVal), ", goid=", gp.goid, "\n")
+	}
+	lrPtr := (*uintreg)(unsafe.Pointer(stkbar.savedLRPtr))
+	if val := *lrPtr; val != uintreg(stackBarrierPC) {
+		printlock()
+		print("at *", hex(stkbar.savedLRPtr), " expected stack barrier PC ", hex(stackBarrierPC), ", found ", hex(val), ", goid=", gp.goid, "\n")
+		print("gp.stkbar=")
+		gcPrintStkbars(gp.stkbar)
+		print(", gp.stkbarPos=", gp.stkbarPos, ", gp.stack=[", hex(gp.stack.lo), ",", hex(gp.stack.hi), ")\n")
+		throw("stack barrier lost")
+	}
+	*lrPtr = uintreg(stkbar.savedLRVal)
+}
+
+// gcPrintStkbars prints a []stkbar for debugging.
+func gcPrintStkbars(stkbar []stkbar) {
+	print("[")
+	for i, s := range stkbar {
+		if i > 0 {
+			print(" ")
+		}
+		print("*", hex(s.savedLRPtr), "=", hex(s.savedLRVal))
+	}
+	print("]")
+}
+
+// gcUnwindBarriers marks all stack barriers up the frame containing
+// sp as hit and removes them. This is used during stack unwinding for
+// panic/recover and by heapBitsBulkBarrier to force stack re-scanning
+// when its destination is on the stack.
+//
+// This is nosplit to ensure gp's stack does not move.
+//
+//go:nosplit
+func gcUnwindBarriers(gp *g, sp uintptr) {
+	// On LR machines, if there is a stack barrier on the return
+	// from the frame containing sp, this will mark it as hit even
+	// though it isn't, but it's okay to be conservative.
+	before := gp.stkbarPos
+	for int(gp.stkbarPos) < len(gp.stkbar) && gp.stkbar[gp.stkbarPos].savedLRPtr < sp {
+		gcRemoveStackBarrier(gp, gp.stkbar[gp.stkbarPos])
+		gp.stkbarPos++
+	}
+	if debugStackBarrier && gp.stkbarPos != before {
+		print("skip barriers below ", hex(sp), " in goid=", gp.goid, ": ")
+		gcPrintStkbars(gp.stkbar[before:gp.stkbarPos])
+		print("\n")
+	}
+}
+
+// nextBarrierPC returns the original return PC of the next stack barrier.
+// Used by getcallerpc, so it must be nosplit.
+//go:nosplit
+func nextBarrierPC() uintptr {
+	gp := getg()
+	return gp.stkbar[gp.stkbarPos].savedLRVal
+}
+
+// setNextBarrierPC sets the return PC of the next stack barrier.
+// Used by setcallerpc, so it must be nosplit.
+//go:nosplit
+func setNextBarrierPC(pc uintptr) {
+	gp := getg()
+	gp.stkbar[gp.stkbarPos].savedLRVal = pc
+}
+
+// TODO(austin): Can we consolidate the gcDrain* functions?
+
+// gcDrain scans objects in work buffers, blackening grey
+// objects until all work buffers have been drained.
+// If flushScanCredit != -1, gcDrain flushes accumulated scan work
+// credit to gcController.bgScanCredit whenever gcw's local scan work
+// credit exceeds flushScanCredit.
+//go:nowritebarrier
+func gcDrain(gcw *gcWork, flushScanCredit int64) {
+	if !writeBarrierEnabled {
+		throw("gcDrain phase incorrect")
+	}
+
+	var lastScanFlush, nextScanFlush int64
+	if flushScanCredit != -1 {
+		lastScanFlush = gcw.scanWork
+		nextScanFlush = lastScanFlush + flushScanCredit
+	} else {
+		nextScanFlush = int64(^uint64(0) >> 1)
+	}
+
+	for {
+		// If another proc wants a pointer, give it some.
+		if work.nwait > 0 && work.full == 0 {
+			gcw.balance()
+		}
+
+		b := gcw.get()
+		if b == 0 {
+			// work barrier reached
+			break
+		}
+		// If the current wbuf is filled by the scan a new wbuf might be
+		// returned that could possibly hold only a single object. This
+		// could result in each iteration draining only a single object
+		// 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, gcw)
+
+		// Flush background scan work credit to the global
+		// account if we've accumulated enough locally so
+		// mutator assists can draw on it.
+		if gcw.scanWork >= nextScanFlush {
+			credit := gcw.scanWork - lastScanFlush
+			xaddint64(&gcController.bgScanCredit, credit)
+			lastScanFlush = gcw.scanWork
+			nextScanFlush = lastScanFlush + flushScanCredit
+		}
+	}
+	if flushScanCredit != -1 {
+		credit := gcw.scanWork - lastScanFlush
+		xaddint64(&gcController.bgScanCredit, credit)
+	}
+}
+
+// gcDrainUntilPreempt blackens grey objects until g.preempt is set.
+// This is best-effort, so it will return as soon as it is unable to
+// get work, even though there may be more work in the system.
+//go:nowritebarrier
+func gcDrainUntilPreempt(gcw *gcWork, flushScanCredit int64) {
+	if !writeBarrierEnabled {
+		println("gcphase =", gcphase)
+		throw("gcDrainUntilPreempt phase incorrect")
+	}
+
+	var lastScanFlush, nextScanFlush int64
+	if flushScanCredit != -1 {
+		lastScanFlush = gcw.scanWork
+		nextScanFlush = lastScanFlush + flushScanCredit
+	} else {
+		nextScanFlush = int64(^uint64(0) >> 1)
+	}
+
+	gp := getg()
+	for !gp.preempt {
+		// If the work queue is empty, balance. During
+		// concurrent mark we don't really know if anyone else
+		// can make use of this work, but even if we're the
+		// only worker, the total cost of this per cycle is
+		// only O(_WorkbufSize) pointer copies.
+		if work.full == 0 && work.partial == 0 {
+			gcw.balance()
+		}
+
+		b := gcw.tryGet()
+		if b == 0 {
+			// No more work
+			break
+		}
+		scanobject(b, gcw)
+
+		// Flush background scan work credit to the global
+		// account if we've accumulated enough locally so
+		// mutator assists can draw on it.
+		if gcw.scanWork >= nextScanFlush {
+			credit := gcw.scanWork - lastScanFlush
+			xaddint64(&gcController.bgScanCredit, credit)
+			lastScanFlush = gcw.scanWork
+			nextScanFlush = lastScanFlush + flushScanCredit
+		}
+	}
+	if flushScanCredit != -1 {
+		credit := gcw.scanWork - lastScanFlush
+		xaddint64(&gcController.bgScanCredit, credit)
+	}
+}
+
+// gcDrainN blackens grey objects until it has performed roughly
+// scanWork units of scan work. This is best-effort, so it may perform
+// less work if it fails to get a work buffer. Otherwise, it will
+// perform at least n units of work, but may perform more because
+// scanning is always done in whole object increments.
+//go:nowritebarrier
+func gcDrainN(gcw *gcWork, scanWork int64) {
+	if !writeBarrierEnabled {
+		throw("gcDrainN phase incorrect")
+	}
+	targetScanWork := gcw.scanWork + scanWork
+	for gcw.scanWork < targetScanWork {
+		// This might be a good place to add prefetch code...
+		// if(wbuf.nobj > 4) {
+		//         PREFETCH(wbuf->obj[wbuf.nobj - 3];
+		//  }
+		b := gcw.tryGet()
+		if b == 0 {
+			return
+		}
+		scanobject(b, gcw)
+	}
+}
+
+// scanblock scans b as scanobject would, but using an explicit
+// pointer bitmap instead of the heap bitmap.
+//
+// This is used to scan non-heap roots, so it does not update
+// gcw.bytesMarked or gcw.scanWork.
+//
+//go:nowritebarrier
+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.
+	b := b0
+	n := n0
+
+	arena_start := mheap_.arena_start
+	arena_used := mheap_.arena_used
+
+	for i := uintptr(0); i < n; {
+		// Find bits for the next word.
+		bits := uint32(*addb(ptrmask, i/(ptrSize*8)))
+		if bits == 0 {
+			i += ptrSize * 8
+			continue
+		}
+		for j := 0; j < 8 && i < n; j++ {
+			if bits&1 != 0 {
+				// Same work as in scanobject; see comments there.
+				obj := *(*uintptr)(unsafe.Pointer(b + i))
+				if obj != 0 && arena_start <= obj && obj < arena_used {
+					if obj, hbits, span := heapBitsForObject(obj); obj != 0 {
+						greyobject(obj, b, i, hbits, span, gcw)
+					}
+				}
+			}
+			bits >>= 1
+			i += ptrSize
+		}
+	}
+}
+
+// scanobject scans the object starting at b, adding pointers to gcw.
+// b must point to the beginning of a heap object; scanobject consults
+// the GC bitmap for the pointer mask and the spans for the size of the
+// object (it ignores n).
+//go:nowritebarrier
+func scanobject(b uintptr, gcw *gcWork) {
+	// Note that arena_used may change concurrently during
+	// scanobject and hence scanobject may encounter a pointer to
+	// a newly allocated heap object that is *not* in
+	// [start,used). It will not mark this object; however, we
+	// know that it was just installed by a mutator, which means
+	// that mutator will execute a write barrier and take care of
+	// marking it. This is even more pronounced on relaxed memory
+	// architectures since we access arena_used without barriers
+	// or synchronization, but the same logic applies.
+	arena_start := mheap_.arena_start
+	arena_used := mheap_.arena_used
+
+	// Find bits of the beginning of the object.
+	// b must point to the beginning of a heap object, so
+	// we can get its bits and span directly.
+	hbits := heapBitsForAddr(b)
+	s := spanOfUnchecked(b)
+	n := s.elemsize
+	if n == 0 {
+		throw("scanobject n == 0")
+	}
+
+	var i uintptr
+	for i = 0; i < n; i += ptrSize {
+		// Find bits for this word.
+		if i != 0 {
+			// Avoid needless hbits.next() on last iteration.
+			hbits = hbits.next()
+		}
+		// During checkmarking, 1-word objects store the checkmark
+		// in the type bit for the one word. The only one-word objects
+		// are pointers, or else they'd be merged with other non-pointer
+		// data into larger allocations.
+		bits := hbits.bits()
+		if i >= 2*ptrSize && bits&bitMarked == 0 {
+			break // no more pointers in this object
+		}
+		if bits&bitPointer == 0 {
+			continue // not a pointer
+		}
+
+		// Work here is duplicated in scanblock and above.
+		// If you make changes here, make changes there too.
+		obj := *(*uintptr)(unsafe.Pointer(b + i))
+
+		// At this point we have extracted the next potential pointer.
+		// Check if it points into heap and not back at the current object.
+		if obj != 0 && arena_start <= obj && obj < arena_used && obj-b >= n {
+			// Mark the object.
+			if obj, hbits, span := heapBitsForObject(obj); obj != 0 {
+				greyobject(obj, b, i, hbits, span, gcw)
+			}
+		}
+	}
+	gcw.bytesMarked += uint64(n)
+	gcw.scanWork += int64(i)
+}
+
+// Shade the object if it isn't already.
+// The object is not nil and known to be in the heap.
+// Preemption must be disabled.
+//go:nowritebarrier
+func shade(b uintptr) {
+	if obj, hbits, span := heapBitsForObject(b); obj != 0 {
+		gcw := &getg().m.p.ptr().gcw
+		greyobject(obj, 0, 0, hbits, span, gcw)
+		if gcphase == _GCmarktermination || gcBlackenPromptly {
+			// Ps aren't allowed to cache work during mark
+			// termination.
+			gcw.dispose()
+		}
+	}
+}
+
+// obj is the start of an object with mark mbits.
+// If it isn't already marked, mark it and enqueue into gcw.
+// base and off are for debugging only and could be removed.
+//go:nowritebarrier
+func greyobject(obj, base, off uintptr, hbits heapBits, span *mspan, 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")
+	}
+
+	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
+			gcDumpObject("base", base, off)
+
+			// Dump the object
+			gcDumpObject("obj", obj, ^uintptr(0))
+
+			throw("checkmark found unmarked object")
+		}
+		if hbits.isCheckmarked(span.elemsize) {
+			return
+		}
+		hbits.setCheckmarked(span.elemsize)
+		if !hbits.isCheckmarked(span.elemsize) {
+			throw("setCheckmarked and isCheckmarked disagree")
+		}
+	} else {
+		// If marked we have nothing to do.
+		if hbits.isMarked() {
+			return
+		}
+		hbits.setMarked()
+
+		// If this is a noscan object, fast-track it to black
+		// instead of greying it.
+		if !hbits.hasPointers(span.elemsize) {
+			gcw.bytesMarked += uint64(span.elemsize)
+			return
+		}
+	}
+
+	// Queue the obj for scanning. The PREFETCH(obj) logic has been removed but
+	// seems like a nice optimization that can be added back in.
+	// There needs to be time between the PREFETCH and the use.
+	// Previously we put the obj in an 8 element buffer that is drained at a rate
+	// to give the PREFETCH time to do its work.
+	// Use of PREFETCHNTA might be more appropriate than PREFETCH
+
+	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) {
+	if obj < mheap_.arena_start || obj >= mheap_.arena_used {
+		print(label, "=", hex(obj), " is not a heap object\n")
+		return
+	}
+	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")
+	}
+}
+
+// If gcBlackenPromptly is true we are in the second mark phase phase so we allocate black.
+//go:nowritebarrier
+func gcmarknewobject_m(obj, size uintptr) {
+	if useCheckmark && !gcBlackenPromptly { // The world should be stopped so this should not happen.
+		throw("gcmarknewobject called while doing checkmark")
+	}
+	heapBitsForAddr(obj).setMarked()
+	xadd64(&work.bytesMarked, int64(size))
+}
+
+// Checkmarking
+
+// To help debug the concurrent GC we remark with the world
+// stopped ensuring that any object encountered has their normal
+// mark bit set. To do this we use an orthogonal bit
+// pattern to indicate the object is marked. The following pattern
+// uses the upper two bits in the object's boundary nibble.
+// 01: scalar  not marked
+// 10: pointer not marked
+// 11: pointer     marked
+// 00: scalar      marked
+// Xoring with 01 will flip the pattern from marked to unmarked and vica versa.
+// The higher bit is 1 for pointers and 0 for scalars, whether the object
+// is marked or not.
+// The first nibble no longer holds the typeDead pattern indicating that the
+// there are no more pointers in the object. This information is held
+// in the second nibble.
+
+// If useCheckmark is true, marking of an object uses the
+// checkmark bits (encoding above) instead of the standard
+// mark bits.
+var useCheckmark = false
+
+//go:nowritebarrier
+func initCheckmarks() {
+	useCheckmark = true
+	for _, s := range work.spans {
+		if s.state == _MSpanInUse {
+			heapBitsForSpan(s.base()).initCheckmarkSpan(s.layout())
+		}
+	}
+}
+
+func clearCheckmarks() {
+	useCheckmark = false
+	for _, s := range work.spans {
+		if s.state == _MSpanInUse {
+			heapBitsForSpan(s.base()).clearCheckmarkSpan(s.layout())
+		}
+	}
+}
diff --git a/src/runtime/mgcsweep.go b/src/runtime/mgcsweep.go
new file mode 100644
index 0000000..eaa4463
--- /dev/null
+++ b/src/runtime/mgcsweep.go
@@ -0,0 +1,370 @@
+// 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.
+
+// Garbage collector: sweeping
+
+package runtime
+
+import "unsafe"
+
+var sweep sweepdata
+
+// State of background sweep.
+type sweepdata struct {
+	lock    mutex
+	g       *g
+	parked  bool
+	started bool
+
+	spanidx uint32 // background sweeper position
+
+	nbgsweep    uint32
+	npausesweep uint32
+}
+
+//go:nowritebarrier
+func finishsweep_m() {
+	// The world is stopped so we should be able to complete the sweeps
+	// quickly.
+	for sweepone() != ^uintptr(0) {
+		sweep.npausesweep++
+	}
+
+	// There may be some other spans being swept concurrently that
+	// we need to wait for. If finishsweep_m is done with the world stopped
+	// this code is not required.
+	sg := mheap_.sweepgen
+	for _, s := range work.spans {
+		if s.sweepgen != sg && s.state == _MSpanInUse {
+			mSpan_EnsureSwept(s)
+		}
+	}
+}
+
+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++
+			Gosched()
+		}
+		lock(&sweep.lock)
+		if !gosweepdone() {
+			// This can happen if a GC runs between
+			// gosweepone returning ^0 above
+			// and the lock being acquired.
+			unlock(&sweep.lock)
+			continue
+		}
+		sweep.parked = true
+		goparkunlock(&sweep.lock, "GC sweep wait", traceEvGoBlock, 1)
+	}
+}
+
+// sweeps one span
+// returns number of pages returned to heap, or ^uintptr(0) if there is nothing to sweep
+//go:nowritebarrier
+func sweepone() uintptr {
+	_g_ := getg()
+
+	// increment locks to ensure that the goroutine is not preempted
+	// in the middle of sweep thus leaving the span in an inconsistent state for next GC
+	_g_.m.locks++
+	sg := mheap_.sweepgen
+	for {
+		idx := xadd(&sweep.spanidx, 1) - 1
+		if idx >= uint32(len(work.spans)) {
+			mheap_.sweepdone = 1
+			_g_.m.locks--
+			return ^uintptr(0)
+		}
+		s := work.spans[idx]
+		if s.state != mSpanInUse {
+			s.sweepgen = sg
+			continue
+		}
+		if s.sweepgen != sg-2 || !cas(&s.sweepgen, sg-2, sg-1) {
+			continue
+		}
+		npages := s.npages
+		if !mSpan_Sweep(s, false) {
+			npages = 0
+		}
+		_g_.m.locks--
+		return npages
+	}
+}
+
+//go:nowritebarrier
+func gosweepone() uintptr {
+	var ret uintptr
+	systemstack(func() {
+		ret = sweepone()
+	})
+	return ret
+}
+
+//go:nowritebarrier
+func gosweepdone() bool {
+	return mheap_.sweepdone != 0
+}
+
+// Returns only when span s has been swept.
+//go:nowritebarrier
+func mSpan_EnsureSwept(s *mspan) {
+	// Caller must disable preemption.
+	// Otherwise when this function returns the span can become unswept again
+	// (if GC is triggered on another goroutine).
+	_g_ := getg()
+	if _g_.m.locks == 0 && _g_.m.mallocing == 0 && _g_ != _g_.m.g0 {
+		throw("MSpan_EnsureSwept: m is not locked")
+	}
+
+	sg := mheap_.sweepgen
+	if atomicload(&s.sweepgen) == sg {
+		return
+	}
+	// The caller must be sure that the span is a MSpanInUse span.
+	if cas(&s.sweepgen, sg-2, sg-1) {
+		mSpan_Sweep(s, false)
+		return
+	}
+	// unfortunate condition, and we don't have efficient means to wait
+	for atomicload(&s.sweepgen) != sg {
+		osyield()
+	}
+}
+
+// Sweep frees or collects finalizers for blocks not marked in the mark phase.
+// It clears the mark bits in preparation for the next GC round.
+// Returns true if the span was returned to heap.
+// If preserve=true, don't return it to heap nor relink in MCentral lists;
+// caller takes care of it.
+//TODO go:nowritebarrier
+func mSpan_Sweep(s *mspan, preserve bool) bool {
+	// It's critical that we enter this function with preemption disabled,
+	// GC must not start while we are in the middle of this function.
+	_g_ := getg()
+	if _g_.m.locks == 0 && _g_.m.mallocing == 0 && _g_ != _g_.m.g0 {
+		throw("MSpan_Sweep: m is not locked")
+	}
+	sweepgen := mheap_.sweepgen
+	if s.state != mSpanInUse || s.sweepgen != sweepgen-1 {
+		print("MSpan_Sweep: state=", s.state, " sweepgen=", s.sweepgen, " mheap.sweepgen=", sweepgen, "\n")
+		throw("MSpan_Sweep: bad span state")
+	}
+
+	if trace.enabled {
+		traceGCSweepStart()
+	}
+
+	xadd64(&mheap_.pagesSwept, int64(s.npages))
+
+	cl := s.sizeclass
+	size := s.elemsize
+	res := false
+	nfree := 0
+
+	var head, end gclinkptr
+
+	c := _g_.m.mcache
+	freeToHeap := false
+
+	// Mark any free objects in this span so we don't collect them.
+	sstart := uintptr(s.start << _PageShift)
+	for link := s.freelist; link.ptr() != nil; link = link.ptr().next {
+		if uintptr(link) < sstart || s.limit <= uintptr(link) {
+			// Free list is corrupted.
+			dumpFreeList(s)
+			throw("free list corrupted")
+		}
+		heapBitsForAddr(uintptr(link)).setMarkedNonAtomic()
+	}
+
+	// Unlink & free special records for any objects we're about to free.
+	specialp := &s.specials
+	special := *specialp
+	for special != nil {
+		// A finalizer can be set for an inner byte of an object, find object beginning.
+		p := uintptr(s.start<<_PageShift) + uintptr(special.offset)/size*size
+		hbits := heapBitsForAddr(p)
+		if !hbits.isMarked() {
+			// Find the exact byte for which the special was setup
+			// (as opposed to object beginning).
+			p := uintptr(s.start<<_PageShift) + uintptr(special.offset)
+			// about to free object: splice out special record
+			y := special
+			special = special.next
+			*specialp = special
+			if !freespecial(y, unsafe.Pointer(p), size, false) {
+				// stop freeing of object if it has a finalizer
+				hbits.setMarkedNonAtomic()
+			}
+		} else {
+			// object is still live: keep special record
+			specialp = &special.next
+			special = *specialp
+		}
+	}
+
+	// Sweep through n objects of given size starting at p.
+	// This thread owns the span now, so it can manipulate
+	// the block bitmap without atomic operations.
+
+	size, n, _ := s.layout()
+	heapBitsSweepSpan(s.base(), size, n, func(p uintptr) {
+		// At this point we know that we are looking at garbage object
+		// that needs to be collected.
+		if debug.allocfreetrace != 0 {
+			tracefree(unsafe.Pointer(p), size)
+		}
+
+		// Reset to allocated+noscan.
+		if cl == 0 {
+			// Free large span.
+			if preserve {
+				throw("can't preserve large span")
+			}
+			heapBitsForSpan(p).initSpan(s.layout())
+			s.needzero = 1
+
+			// important to set sweepgen before returning it to heap
+			atomicstore(&s.sweepgen, sweepgen)
+
+			// Free the span after heapBitsSweepSpan
+			// returns, since it's not done with the span.
+			freeToHeap = true
+		} else {
+			// Free small object.
+			if size > 2*ptrSize {
+				*(*uintptr)(unsafe.Pointer(p + ptrSize)) = uintptrMask & 0xdeaddeaddeaddead // mark as "needs to be zeroed"
+			} else if size > ptrSize {
+				*(*uintptr)(unsafe.Pointer(p + ptrSize)) = 0
+			}
+			if head.ptr() == nil {
+				head = gclinkptr(p)
+			} else {
+				end.ptr().next = gclinkptr(p)
+			}
+			end = gclinkptr(p)
+			end.ptr().next = gclinkptr(0x0bade5)
+			nfree++
+		}
+	})
+
+	// We need to set s.sweepgen = h.sweepgen only when all blocks are swept,
+	// because of the potential for a concurrent free/SetFinalizer.
+	// But we need to set it before we make the span available for allocation
+	// (return it to heap or mcentral), because allocation code assumes that a
+	// span is already swept if available for allocation.
+	//
+	// TODO(austin): Clean this up by consolidating atomicstore in
+	// large span path above with this.
+	if !freeToHeap && nfree == 0 {
+		// The span must be in our exclusive ownership until we update sweepgen,
+		// check for potential races.
+		if s.state != mSpanInUse || s.sweepgen != sweepgen-1 {
+			print("MSpan_Sweep: state=", s.state, " sweepgen=", s.sweepgen, " mheap.sweepgen=", sweepgen, "\n")
+			throw("MSpan_Sweep: bad span state after sweep")
+		}
+		atomicstore(&s.sweepgen, sweepgen)
+	}
+	if nfree > 0 {
+		c.local_nsmallfree[cl] += uintptr(nfree)
+		res = mCentral_FreeSpan(&mheap_.central[cl].mcentral, s, int32(nfree), head, end, preserve)
+		// MCentral_FreeSpan updates sweepgen
+	} else if freeToHeap {
+		// Free large span to heap
+
+		// NOTE(rsc,dvyukov): The original implementation of efence
+		// in CL 22060046 used SysFree instead of SysFault, so that
+		// the operating system would eventually give the memory
+		// back to us again, so that an efence program could run
+		// longer without running out of memory. Unfortunately,
+		// calling SysFree here without any kind of adjustment of the
+		// heap data structures means that when the memory does
+		// come back to us, we have the wrong metadata for it, either in
+		// the MSpan structures or in the garbage collection bitmap.
+		// Using SysFault here means that the program will run out of
+		// memory fairly quickly in efence mode, but at least it won't
+		// have mysterious crashes due to confused memory reuse.
+		// It should be possible to switch back to SysFree if we also
+		// implement and then call some kind of MHeap_DeleteSpan.
+		if debug.efence > 0 {
+			s.limit = 0 // prevent mlookup from finding this span
+			sysFault(unsafe.Pointer(uintptr(s.start<<_PageShift)), size)
+		} else {
+			mHeap_Free(&mheap_, s, 1)
+		}
+		c.local_nlargefree++
+		c.local_largefree += size
+		res = true
+	}
+	if trace.enabled {
+		traceGCSweepDone()
+	}
+	return res
+}
+
+// deductSweepCredit deducts sweep credit for allocating a span of
+// size spanBytes. This must be performed *before* the span is
+// allocated to ensure the system has enough credit. If necessary, it
+// performs sweeping to prevent going in to debt. If the caller will
+// also sweep pages (e.g., for a large allocation), it can pass a
+// non-zero callerSweepPages to leave that many pages unswept.
+//
+// deductSweepCredit is the core of the "proportional sweep" system.
+// It uses statistics gathered by the garbage collector to perform
+// enough sweeping so that all pages are swept during the concurrent
+// sweep phase between GC cycles.
+//
+// mheap_ must NOT be locked.
+func deductSweepCredit(spanBytes uintptr, callerSweepPages uintptr) {
+	if mheap_.sweepPagesPerByte == 0 {
+		// Proportional sweep is done or disabled.
+		return
+	}
+
+	// Account for this span allocation.
+	spanBytesAlloc := xadd64(&mheap_.spanBytesAlloc, int64(spanBytes))
+
+	// Fix debt if necessary.
+	pagesOwed := int64(mheap_.sweepPagesPerByte * float64(spanBytesAlloc))
+	for pagesOwed-int64(atomicload64(&mheap_.pagesSwept)) > int64(callerSweepPages) {
+		if gosweepone() == ^uintptr(0) {
+			mheap_.sweepPagesPerByte = 0
+			break
+		}
+	}
+}
+
+func dumpFreeList(s *mspan) {
+	printlock()
+	print("runtime: free list of span ", s, ":\n")
+	sstart := uintptr(s.start << _PageShift)
+	link := s.freelist
+	for i := 0; i < int(s.npages*_PageSize/s.elemsize); i++ {
+		if i != 0 {
+			print(" -> ")
+		}
+		print(hex(link))
+		if link.ptr() == nil {
+			break
+		}
+		if uintptr(link) < sstart || s.limit <= uintptr(link) {
+			// Bad link. Stop walking before we crash.
+			print(" (BAD)")
+			break
+		}
+		link = link.ptr().next
+	}
+	print("\n")
+	printunlock()
+}
diff --git a/src/runtime/mgcwork.go b/src/runtime/mgcwork.go
new file mode 100644
index 0000000..b18eaaf
--- /dev/null
+++ b/src/runtime/mgcwork.go
@@ -0,0 +1,458 @@
+// 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"
+
+const (
+	_Debugwbufs  = false   // if true check wbufs consistency
+	_WorkbufSize = 1 * 256 // in bytes - if small wbufs are passed to GC in a timely fashion.
+)
+
+// Garbage collector work pool abstraction.
+//
+// This implements a producer/consumer model for pointers to grey
+// objects.  A grey object is one that is marked and on a work
+// queue.  A black object is marked and not on a work queue.
+//
+// Write barriers, root discovery, stack scanning, and object scanning
+// produce pointers to grey objects.  Scanning consumes pointers to
+// grey objects, thus blackening them, and then scans them,
+// potentially producing new pointers to grey objects.
+
+// A wbufptr holds a workbuf*, but protects it from write barriers.
+// workbufs never live on the heap, so write barriers are unnecessary.
+// Write barriers on workbuf pointers may also be dangerous in the GC.
+type wbufptr uintptr
+
+func wbufptrOf(w *workbuf) wbufptr {
+	return wbufptr(unsafe.Pointer(w))
+}
+
+func (wp wbufptr) ptr() *workbuf {
+	return (*workbuf)(unsafe.Pointer(wp))
+}
+
+// A gcWork provides the interface to produce and consume work for the
+// garbage collector.
+//
+// A gcWork can be used on the stack as follows:
+//
+//     var gcw gcWork
+//     disable preemption
+//     .. call gcw.put() to produce and gcw.get() to consume ..
+//     gcw.dispose()
+//     enable preemption
+//
+// Or from the per-P gcWork cache:
+//
+//     (preemption must be disabled)
+//     gcw := &getg().m.p.ptr().gcw
+//     .. call gcw.put() to produce and gcw.get() to consume ..
+//     if gcphase == _GCmarktermination {
+//         gcw.dispose()
+//     }
+//
+// 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
+
+	// Bytes marked (blackened) on this gcWork. This is aggregated
+	// into work.bytesMarked by dispose.
+	bytesMarked uint64
+
+	// Scan work performed on this gcWork. This is aggregated into
+	// gcController by dispose.
+	scanWork int64
+}
+
+// put enqueues a pointer for the garbage collector to trace.
+// obj must point to the beginning of a heap object.
+//go:nowritebarrier
+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 {
+		wbuf = getpartialorempty(42)
+		w.wbuf = wbufptrOf(wbuf)
+	}
+
+	wbuf.obj[wbuf.nobj] = obj
+	wbuf.nobj++
+
+	if wbuf.nobj == len(wbuf.obj) {
+		putfull(wbuf, 50)
+		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
+// queue, tryGet returns 0.  Note that there may still be pointers in
+// other gcWork instances or other caches.
+//go:nowritebarrier
+func (ww *gcWork) tryGet() uintptr {
+	w := (*gcWork)(noescape(unsafe.Pointer(ww))) // TODO: remove when escape analysis is fixed
+
+	wbuf := w.wbuf.ptr()
+	if wbuf == nil {
+		wbuf = trygetfull(74)
+		if wbuf == nil {
+			return 0
+		}
+		w.wbuf = wbufptrOf(wbuf)
+	}
+
+	wbuf.nobj--
+	obj := wbuf.obj[wbuf.nobj]
+
+	if wbuf.nobj == 0 {
+		putempty(wbuf, 86)
+		w.wbuf = 0
+	}
+
+	return obj
+}
+
+// get dequeues a pointer for the garbage collector to trace, blocking
+// if necessary to ensure all pointers from all queues and caches have
+// been retrieved.  get returns 0 if there are no pointers remaining.
+//go:nowritebarrier
+func (ww *gcWork) get() uintptr {
+	w := (*gcWork)(noescape(unsafe.Pointer(ww))) // TODO: remove when escape analysis is fixed
+
+	wbuf := w.wbuf.ptr()
+	if wbuf == nil {
+		wbuf = getfull(103)
+		if wbuf == nil {
+			return 0
+		}
+		wbuf.checknonempty()
+		w.wbuf = wbufptrOf(wbuf)
+	}
+
+	// TODO: This might be a good place to add prefetch code
+
+	wbuf.nobj--
+	obj := wbuf.obj[wbuf.nobj]
+
+	if wbuf.nobj == 0 {
+		putempty(wbuf, 115)
+		w.wbuf = 0
+	}
+
+	return obj
+}
+
+// dispose returns any cached pointers to the global queue.
+// The buffers are being put on the full queue so that the
+// write barriers will not simply reacquire them before the
+// GC can inspect them. This helps reduce the mutator's
+// ability to hide pointers during the concurrent mark phase.
+//
+//go:nowritebarrier
+func (w *gcWork) dispose() {
+	if wbuf := w.wbuf; wbuf != 0 {
+		if wbuf.ptr().nobj == 0 {
+			throw("dispose: workbuf is empty")
+		}
+		putfull(wbuf.ptr(), 166)
+		w.wbuf = 0
+	}
+	if w.bytesMarked != 0 {
+		// dispose happens relatively infrequently. If this
+		// atomic becomes a problem, we should first try to
+		// dispose less and if necessary aggregate in a per-P
+		// counter.
+		xadd64(&work.bytesMarked, int64(w.bytesMarked))
+		w.bytesMarked = 0
+	}
+	if w.scanWork != 0 {
+		xaddint64(&gcController.scanWork, w.scanWork)
+		w.scanWork = 0
+	}
+}
+
+// balance moves some work that's cached in this gcWork back on the
+// global queue.
+//go:nowritebarrier
+func (w *gcWork) balance() {
+	if wbuf := w.wbuf; wbuf != 0 && wbuf.ptr().nobj > 4 {
+		w.wbuf = wbufptrOf(handoff(wbuf.ptr()))
+	}
+}
+
+// empty returns true if w has no mark work available.
+//go:nowritebarrier
+func (w *gcWork) empty() bool {
+	wbuf := w.wbuf
+	return wbuf == 0 || wbuf.ptr().nobj == 0
+}
+
+// Internally, the GC work pool is kept in arrays in work buffers.
+// The gcWork interface caches a work buffer until full (or empty) to
+// avoid contending on the global work buffer lists.
+
+type workbufhdr struct {
+	node  lfnode // must be first
+	nobj  int
+	inuse bool   // This workbuf is in use by some gorotuine and is not on the work.empty/partial/full queues.
+	log   [4]int // line numbers forming a history of ownership changes to workbuf
+}
+
+type workbuf struct {
+	workbufhdr
+	// account for the above fields
+	obj [(_WorkbufSize - unsafe.Sizeof(workbufhdr{})) / ptrSize]uintptr
+}
+
+// workbuf factory routines. These funcs are used to manage the
+// workbufs.
+// If the GC asks for some work these are the only routines that
+// make partially full wbufs available to the GC.
+// Each of the gets and puts also take an distinct integer that is used
+// to record a brief history of changes to ownership of the workbuf.
+// The convention is to use a unique line number but any encoding
+// is permissible. For example if you want to pass in 2 bits of information
+// you could simple add lineno1*100000+lineno2.
+
+// logget records the past few values of entry to aid in debugging.
+// logget checks the buffer b is not currently in use.
+func (b *workbuf) logget(entry int) {
+	if !_Debugwbufs {
+		return
+	}
+	if b.inuse {
+		println("runtime: logget fails log entry=", entry,
+			"b.log[0]=", b.log[0], "b.log[1]=", b.log[1],
+			"b.log[2]=", b.log[2], "b.log[3]=", b.log[3])
+		throw("logget: get not legal")
+	}
+	b.inuse = true
+	copy(b.log[1:], b.log[:])
+	b.log[0] = entry
+}
+
+// logput records the past few values of entry to aid in debugging.
+// logput checks the buffer b is currently in use.
+func (b *workbuf) logput(entry int) {
+	if !_Debugwbufs {
+		return
+	}
+	if !b.inuse {
+		println("runtime: logput fails log entry=", entry,
+			"b.log[0]=", b.log[0], "b.log[1]=", b.log[1],
+			"b.log[2]=", b.log[2], "b.log[3]=", b.log[3])
+		throw("logput: put not legal")
+	}
+	b.inuse = false
+	copy(b.log[1:], b.log[:])
+	b.log[0] = entry
+}
+
+func (b *workbuf) checknonempty() {
+	if b.nobj == 0 {
+		println("runtime: nonempty check fails",
+			"b.log[0]=", b.log[0], "b.log[1]=", b.log[1],
+			"b.log[2]=", b.log[2], "b.log[3]=", b.log[3])
+		throw("workbuf is empty")
+	}
+}
+
+func (b *workbuf) checkempty() {
+	if b.nobj != 0 {
+		println("runtime: empty check fails",
+			"b.log[0]=", b.log[0], "b.log[1]=", b.log[1],
+			"b.log[2]=", b.log[2], "b.log[3]=", b.log[3])
+		throw("workbuf is not empty")
+	}
+}
+
+// getempty pops an empty work buffer off the work.empty list,
+// allocating new buffers if none are available.
+// entry is used to record a brief history of ownership.
+//go:nowritebarrier
+func getempty(entry int) *workbuf {
+	var b *workbuf
+	if work.empty != 0 {
+		b = (*workbuf)(lfstackpop(&work.empty))
+		if b != nil {
+			b.checkempty()
+		}
+	}
+	if b == nil {
+		b = (*workbuf)(persistentalloc(unsafe.Sizeof(*b), _CacheLineSize, &memstats.gc_sys))
+	}
+	b.logget(entry)
+	return b
+}
+
+// putempty puts a workbuf onto the work.empty list.
+// Upon entry this go routine owns b. The lfstackpush relinquishes ownership.
+//go:nowritebarrier
+func putempty(b *workbuf, entry int) {
+	b.checkempty()
+	b.logput(entry)
+	lfstackpush(&work.empty, &b.node)
+}
+
+// putfull puts the workbuf on the work.full list for the GC.
+// putfull accepts partially full buffers so the GC can avoid competing
+// with the mutators for ownership of partially full buffers.
+//go:nowritebarrier
+func putfull(b *workbuf, entry int) {
+	b.checknonempty()
+	b.logput(entry)
+	lfstackpush(&work.full, &b.node)
+}
+
+// getpartialorempty tries to return a partially empty
+// and if none are available returns an empty one.
+// entry is used to provide a brief history of ownership
+// using entry + xxx00000 to
+// indicating that two line numbers in the call chain.
+//go:nowritebarrier
+func getpartialorempty(entry int) *workbuf {
+	b := (*workbuf)(lfstackpop(&work.partial))
+	if b != nil {
+		b.logget(entry)
+		return b
+	}
+	// Let getempty do the logget check but
+	// use the entry to encode that it passed
+	// through this routine.
+	b = getempty(entry + 80700000)
+	return b
+}
+
+// putpartial puts empty buffers on the work.empty queue,
+// full buffers on the work.full queue and
+// others on the work.partial queue.
+// entry is used to provide a brief history of ownership
+// using entry + xxx00000 to
+// indicating that two call chain line numbers.
+//go:nowritebarrier
+func putpartial(b *workbuf, entry int) {
+	if b.nobj == 0 {
+		putempty(b, entry+81500000)
+	} else if b.nobj < len(b.obj) {
+		b.logput(entry)
+		lfstackpush(&work.partial, &b.node)
+	} else if b.nobj == len(b.obj) {
+		b.logput(entry)
+		lfstackpush(&work.full, &b.node)
+	} else {
+		throw("putpartial: bad Workbuf b.nobj")
+	}
+}
+
+// trygetfull tries to get a full or partially empty workbuffer.
+// If one is not immediately available return nil
+//go:nowritebarrier
+func trygetfull(entry int) *workbuf {
+	b := (*workbuf)(lfstackpop(&work.full))
+	if b == nil {
+		b = (*workbuf)(lfstackpop(&work.partial))
+	}
+	if b != nil {
+		b.logget(entry)
+		b.checknonempty()
+		return b
+	}
+	return b
+}
+
+// Get a full work buffer off the work.full or a partially
+// filled one off the work.partial list. If nothing is available
+// wait until all the other gc helpers have finished and then
+// return nil.
+// getfull acts as a barrier for work.nproc helpers. As long as one
+// gchelper is actively marking objects it
+// may create a workbuffer that the other helpers can work on.
+// The for loop either exits when a work buffer is found
+// or when _all_ of the work.nproc GC helpers are in the loop
+// looking for work and thus not capable of creating new work.
+// This is in fact the termination condition for the STW mark
+// phase.
+//go:nowritebarrier
+func getfull(entry int) *workbuf {
+	b := (*workbuf)(lfstackpop(&work.full))
+	if b != nil {
+		b.logget(entry)
+		b.checknonempty()
+		return b
+	}
+	b = (*workbuf)(lfstackpop(&work.partial))
+	if b != nil {
+		b.logget(entry)
+		return b
+	}
+
+	incnwait := xadd(&work.nwait, +1)
+	if incnwait > work.nproc {
+		println("runtime: work.nwait=", incnwait, "work.nproc=", work.nproc)
+		throw("work.nwait > work.nproc")
+	}
+	for i := 0; ; i++ {
+		if work.full != 0 || work.partial != 0 {
+			decnwait := xadd(&work.nwait, -1)
+			if decnwait == work.nproc {
+				println("runtime: work.nwait=", decnwait, "work.nproc=", work.nproc)
+				throw("work.nwait > work.nproc")
+			}
+			b = (*workbuf)(lfstackpop(&work.full))
+			if b == nil {
+				b = (*workbuf)(lfstackpop(&work.partial))
+			}
+			if b != nil {
+				b.logget(entry)
+				b.checknonempty()
+				return b
+			}
+			incnwait := xadd(&work.nwait, +1)
+			if incnwait > work.nproc {
+				println("runtime: work.nwait=", incnwait, "work.nproc=", work.nproc)
+				throw("work.nwait > work.nproc")
+			}
+		}
+		if work.nwait == work.nproc {
+			return nil
+		}
+		_g_ := getg()
+		if i < 10 {
+			_g_.m.gcstats.nprocyield++
+			procyield(20)
+		} else if i < 20 {
+			_g_.m.gcstats.nosyield++
+			osyield()
+		} else {
+			_g_.m.gcstats.nsleep++
+			usleep(100)
+		}
+	}
+}
+
+//go:nowritebarrier
+func handoff(b *workbuf) *workbuf {
+	// Make new buffer with half of b's pointers.
+	b1 := getempty(915)
+	n := b.nobj / 2
+	b.nobj -= n
+	b1.nobj = n
+	memmove(unsafe.Pointer(&b1.obj[0]), unsafe.Pointer(&b.obj[b.nobj]), uintptr(n)*unsafe.Sizeof(b1.obj[0]))
+	_g_ := getg()
+	_g_.m.gcstats.nhandoff++
+	_g_.m.gcstats.nhandoffcnt += uint64(n)
+
+	// Put b on full list - let first half of b get stolen.
+	putfull(b, 942)
+	return b1
+}
diff --git a/src/runtime/mheap.c b/src/runtime/mheap.c
deleted file mode 100644
index bb203d5..0000000
--- a/src/runtime/mheap.c
+++ /dev/null
@@ -1,889 +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.
-
-// Page heap.
-//
-// See malloc.h for overview.
-//
-// When a MSpan is in the heap free list, state == MSpanFree
-// and heapmap(s->start) == span, heapmap(s->start+s->npages-1) == span.
-//
-// When a MSpan is allocated, state == MSpanInUse or MSpanStack
-// and heapmap(i) == span for all s->start <= i < s->start+s->npages.
-
-#include "runtime.h"
-#include "arch_GOARCH.h"
-#include "malloc.h"
-
-static MSpan *MHeap_AllocSpanLocked(MHeap*, uintptr);
-static void MHeap_FreeSpanLocked(MHeap*, MSpan*, bool, bool);
-static bool MHeap_Grow(MHeap*, uintptr);
-static MSpan *MHeap_AllocLarge(MHeap*, uintptr);
-static MSpan *BestFit(MSpan*, uintptr, MSpan*);
-
-static void
-RecordSpan(void *vh, byte *p)
-{
-	MHeap *h;
-	MSpan *s;
-	MSpan **all;
-	uint32 cap;
-
-	h = vh;
-	s = (MSpan*)p;
-	if(h->nspan >= h->nspancap) {
-		cap = 64*1024/sizeof(all[0]);
-		if(cap < h->nspancap*3/2)
-			cap = h->nspancap*3/2;
-		all = (MSpan**)runtime·sysAlloc(cap*sizeof(all[0]), &mstats.other_sys);
-		if(all == nil)
-			runtime·throw("runtime: cannot allocate memory");
-		if(h->allspans) {
-			runtime·memmove(all, h->allspans, h->nspancap*sizeof(all[0]));
-			// Don't free the old array if it's referenced by sweep.
-			// See the comment in mgc0.c.
-			if(h->allspans != runtime·mheap.gcspans)
-				runtime·SysFree(h->allspans, h->nspancap*sizeof(all[0]), &mstats.other_sys);
-		}
-		h->allspans = all;
-		h->nspancap = cap;
-	}
-	h->allspans[h->nspan++] = s;
-}
-
-// Initialize the heap; fetch memory using alloc.
-void
-runtime·MHeap_Init(MHeap *h)
-{
-	uint32 i;
-
-	runtime·FixAlloc_Init(&h->spanalloc, sizeof(MSpan), RecordSpan, h, &mstats.mspan_sys);
-	runtime·FixAlloc_Init(&h->cachealloc, sizeof(MCache), nil, nil, &mstats.mcache_sys);
-	runtime·FixAlloc_Init(&h->specialfinalizeralloc, sizeof(SpecialFinalizer), nil, nil, &mstats.other_sys);
-	runtime·FixAlloc_Init(&h->specialprofilealloc, sizeof(SpecialProfile), nil, nil, &mstats.other_sys);
-	// h->mapcache needs no init
-	for(i=0; i<nelem(h->free); i++) {
-		runtime·MSpanList_Init(&h->free[i]);
-		runtime·MSpanList_Init(&h->busy[i]);
-	}
-	runtime·MSpanList_Init(&h->freelarge);
-	runtime·MSpanList_Init(&h->busylarge);
-	for(i=0; i<nelem(h->central); i++)
-		runtime·MCentral_Init(&h->central[i].mcentral, i);
-}
-
-void
-runtime·MHeap_MapSpans(MHeap *h)
-{
-	uintptr n;
-
-	// Map spans array, PageSize at a time.
-	n = (uintptr)h->arena_used;
-	n -= (uintptr)h->arena_start;
-	n = n / PageSize * sizeof(h->spans[0]);
-	n = ROUND(n, PhysPageSize);
-	if(h->spans_mapped >= n)
-		return;
-	runtime·SysMap((byte*)h->spans + h->spans_mapped, n - h->spans_mapped, h->arena_reserved, &mstats.other_sys);
-	h->spans_mapped = n;
-}
-
-// Sweeps spans in list until reclaims at least npages into heap.
-// Returns the actual number of pages reclaimed.
-static uintptr
-MHeap_ReclaimList(MHeap *h, MSpan *list, uintptr npages)
-{
-	MSpan *s;
-	uintptr n;
-	uint32 sg;
-
-	n = 0;
-	sg = runtime·mheap.sweepgen;
-retry:
-	for(s = list->next; s != list; s = s->next) {
-		if(s->sweepgen == sg-2 && runtime·cas(&s->sweepgen, sg-2, sg-1)) {
-			runtime·MSpanList_Remove(s);
-			// swept spans are at the end of the list
-			runtime·MSpanList_InsertBack(list, s);
-			runtime·unlock(&h->lock);
-			n += runtime·MSpan_Sweep(s, false);
-			runtime·lock(&h->lock);
-			if(n >= npages)
-				return n;
-			// the span could have been moved elsewhere
-			goto retry;
-		}
-		if(s->sweepgen == sg-1) {
-			// the span is being sweept by background sweeper, skip
-			continue;
-		}
-		// already swept empty span,
-		// all subsequent ones must also be either swept or in process of sweeping
-		break;
-	}
-	return n;
-}
-
-// Sweeps and reclaims at least npage pages into heap.
-// Called before allocating npage pages.
-static void
-MHeap_Reclaim(MHeap *h, uintptr npage)
-{
-	uintptr reclaimed, n;
-
-	// First try to sweep busy spans with large objects of size >= npage,
-	// this has good chances of reclaiming the necessary space.
-	for(n=npage; n < nelem(h->busy); n++) {
-		if(MHeap_ReclaimList(h, &h->busy[n], npage))
-			return;  // Bingo!
-	}
-
-	// Then -- even larger objects.
-	if(MHeap_ReclaimList(h, &h->busylarge, npage))
-		return;  // Bingo!
-
-	// Now try smaller objects.
-	// One such object is not enough, so we need to reclaim several of them.
-	reclaimed = 0;
-	for(n=0; n < npage && n < nelem(h->busy); n++) {
-		reclaimed += MHeap_ReclaimList(h, &h->busy[n], npage-reclaimed);
-		if(reclaimed >= npage)
-			return;
-	}
-
-	// Now sweep everything that is not yet swept.
-	runtime·unlock(&h->lock);
-	for(;;) {
-		n = runtime·sweepone();
-		if(n == -1)  // all spans are swept
-			break;
-		reclaimed += n;
-		if(reclaimed >= npage)
-			break;
-	}
-	runtime·lock(&h->lock);
-}
-
-// Allocate a new span of npage pages from the heap for GC'd memory
-// and record its size class in the HeapMap and HeapMapCache.
-static MSpan*
-mheap_alloc(MHeap *h, uintptr npage, int32 sizeclass, bool large)
-{
-	MSpan *s;
-
-	if(g != g->m->g0)
-		runtime·throw("mheap_alloc not on M stack");
-	runtime·lock(&h->lock);
-
-	// To prevent excessive heap growth, before allocating n pages
-	// we need to sweep and reclaim at least n pages.
-	if(!h->sweepdone)
-		MHeap_Reclaim(h, npage);
-
-	// transfer stats from cache to global
-	mstats.heap_alloc += g->m->mcache->local_cachealloc;
-	g->m->mcache->local_cachealloc = 0;
-	mstats.tinyallocs += g->m->mcache->local_tinyallocs;
-	g->m->mcache->local_tinyallocs = 0;
-
-	s = MHeap_AllocSpanLocked(h, npage);
-	if(s != nil) {
-		// Record span info, because gc needs to be
-		// able to map interior pointer to containing span.
-		runtime·atomicstore(&s->sweepgen, h->sweepgen);
-		s->state = MSpanInUse;
-		s->freelist = nil;
-		s->ref = 0;
-		s->sizeclass = sizeclass;
-		s->elemsize = (sizeclass==0 ? s->npages<<PageShift : runtime·class_to_size[sizeclass]);
-
-		// update stats, sweep lists
-		if(large) {
-			mstats.heap_objects++;
-			mstats.heap_alloc += npage<<PageShift;
-			// Swept spans are at the end of lists.
-			if(s->npages < nelem(h->free))
-				runtime·MSpanList_InsertBack(&h->busy[s->npages], s);
-			else
-				runtime·MSpanList_InsertBack(&h->busylarge, s);
-		}
-	}
-	runtime·unlock(&h->lock);
-	return s;
-}
-
-static void
-mheap_alloc_m(G *gp)
-{
-	MHeap *h;
-	MSpan *s;
-
-	h = g->m->ptrarg[0];
-	g->m->ptrarg[0] = nil;
-	s = mheap_alloc(h, g->m->scalararg[0], g->m->scalararg[1], g->m->scalararg[2]);
-	g->m->ptrarg[0] = s;
-
-	runtime·gogo(&gp->sched);
-}
-
-MSpan*
-runtime·MHeap_Alloc(MHeap *h, uintptr npage, int32 sizeclass, bool large, bool needzero)
-{
-	MSpan *s;
-	void (*fn)(G*);
-
-	// Don't do any operations that lock the heap on the G stack.
-	// It might trigger stack growth, and the stack growth code needs
-	// to be able to allocate heap.
-	if(g == g->m->g0) {
-		s = mheap_alloc(h, npage, sizeclass, large);
-	} else {
-		g->m->ptrarg[0] = h;
-		g->m->scalararg[0] = npage;
-		g->m->scalararg[1] = sizeclass;
-		g->m->scalararg[2] = large;
-		fn = mheap_alloc_m;
-		runtime·mcall(&fn);
-		s = g->m->ptrarg[0];
-		g->m->ptrarg[0] = nil;
-	}
-	if(s != nil) {
-		if(needzero && s->needzero)
-			runtime·memclr((byte*)(s->start<<PageShift), s->npages<<PageShift);
-		s->needzero = 0;
-	}
-	return s;
-}
-
-MSpan*
-runtime·MHeap_AllocStack(MHeap *h, uintptr npage)
-{
-	MSpan *s;
-
-	if(g != g->m->g0)
-		runtime·throw("mheap_allocstack not on M stack");
-	runtime·lock(&h->lock);
-	s = MHeap_AllocSpanLocked(h, npage);
-	if(s != nil) {
-		s->state = MSpanStack;
-		s->freelist = nil;
-		s->ref = 0;
-		mstats.stacks_inuse += s->npages<<PageShift;
-	}
-	runtime·unlock(&h->lock);
-	return s;
-}
-
-// Allocates a span of the given size.  h must be locked.
-// The returned span has been removed from the
-// free list, but its state is still MSpanFree.
-static MSpan*
-MHeap_AllocSpanLocked(MHeap *h, uintptr npage)
-{
-	uintptr n;
-	MSpan *s, *t;
-	pageID p;
-
-	// Try in fixed-size lists up to max.
-	for(n=npage; n < nelem(h->free); n++) {
-		if(!runtime·MSpanList_IsEmpty(&h->free[n])) {
-			s = h->free[n].next;
-			goto HaveSpan;
-		}
-	}
-
-	// Best fit in list of large spans.
-	if((s = MHeap_AllocLarge(h, npage)) == nil) {
-		if(!MHeap_Grow(h, npage))
-			return nil;
-		if((s = MHeap_AllocLarge(h, npage)) == nil)
-			return nil;
-	}
-
-HaveSpan:
-	// Mark span in use.
-	if(s->state != MSpanFree)
-		runtime·throw("MHeap_AllocLocked - MSpan not free");
-	if(s->npages < npage)
-		runtime·throw("MHeap_AllocLocked - bad npages");
-	runtime·MSpanList_Remove(s);
-	if(s->next != nil || s->prev != nil)
-		runtime·throw("still in list");
-	if(s->npreleased > 0) {
-		runtime·SysUsed((void*)(s->start<<PageShift), s->npages<<PageShift);
-		mstats.heap_released -= s->npreleased<<PageShift;
-		s->npreleased = 0;
-	}
-
-	if(s->npages > npage) {
-		// Trim extra and put it back in the heap.
-		t = runtime·FixAlloc_Alloc(&h->spanalloc);
-		runtime·MSpan_Init(t, s->start + npage, s->npages - npage);
-		s->npages = npage;
-		p = t->start;
-		p -= ((uintptr)h->arena_start>>PageShift);
-		if(p > 0)
-			h->spans[p-1] = s;
-		h->spans[p] = t;
-		h->spans[p+t->npages-1] = t;
-		t->needzero = s->needzero;
-		s->state = MSpanStack; // prevent coalescing with s
-		t->state = MSpanStack;
-		MHeap_FreeSpanLocked(h, t, false, false);
-		t->unusedsince = s->unusedsince; // preserve age (TODO: wrong: t is possibly merged and/or deallocated at this point)
-		s->state = MSpanFree;
-	}
-	s->unusedsince = 0;
-
-	p = s->start;
-	p -= ((uintptr)h->arena_start>>PageShift);
-	for(n=0; n<npage; n++)
-		h->spans[p+n] = s;
-
-	mstats.heap_inuse += npage<<PageShift;
-	mstats.heap_idle -= npage<<PageShift;
-
-	//runtime·printf("spanalloc %p\n", s->start << PageShift);
-	if(s->next != nil || s->prev != nil)
-		runtime·throw("still in list");
-	return s;
-}
-
-// Allocate a span of exactly npage pages from the list of large spans.
-static MSpan*
-MHeap_AllocLarge(MHeap *h, uintptr npage)
-{
-	return BestFit(&h->freelarge, npage, nil);
-}
-
-// Search list for smallest span with >= npage pages.
-// If there are multiple smallest spans, take the one
-// with the earliest starting address.
-static MSpan*
-BestFit(MSpan *list, uintptr npage, MSpan *best)
-{
-	MSpan *s;
-
-	for(s=list->next; s != list; s=s->next) {
-		if(s->npages < npage)
-			continue;
-		if(best == nil
-		|| s->npages < best->npages
-		|| (s->npages == best->npages && s->start < best->start))
-			best = s;
-	}
-	return best;
-}
-
-// Try to add at least npage pages of memory to the heap,
-// returning whether it worked.
-static bool
-MHeap_Grow(MHeap *h, uintptr npage)
-{
-	uintptr ask;
-	void *v;
-	MSpan *s;
-	pageID p;
-
-	// Ask for a big chunk, to reduce the number of mappings
-	// the operating system needs to track; also amortizes
-	// the overhead of an operating system mapping.
-	// Allocate a multiple of 64kB.
-	npage = ROUND(npage, (64<<10)/PageSize);
-	ask = npage<<PageShift;
-	if(ask < HeapAllocChunk)
-		ask = HeapAllocChunk;
-
-	v = runtime·MHeap_SysAlloc(h, ask);
-	if(v == nil) {
-		if(ask > (npage<<PageShift)) {
-			ask = npage<<PageShift;
-			v = runtime·MHeap_SysAlloc(h, ask);
-		}
-		if(v == nil) {
-			runtime·printf("runtime: out of memory: cannot allocate %D-byte block (%D in use)\n", (uint64)ask, mstats.heap_sys);
-			return false;
-		}
-	}
-
-	// Create a fake "in use" span and free it, so that the
-	// right coalescing happens.
-	s = runtime·FixAlloc_Alloc(&h->spanalloc);
-	runtime·MSpan_Init(s, (uintptr)v>>PageShift, ask>>PageShift);
-	p = s->start;
-	p -= ((uintptr)h->arena_start>>PageShift);
-	h->spans[p] = s;
-	h->spans[p + s->npages - 1] = s;
-	runtime·atomicstore(&s->sweepgen, h->sweepgen);
-	s->state = MSpanInUse;
-	MHeap_FreeSpanLocked(h, s, false, true);
-	return true;
-}
-
-// Look up the span at the given address.
-// Address is guaranteed to be in map
-// and is guaranteed to be start or end of span.
-MSpan*
-runtime·MHeap_Lookup(MHeap *h, void *v)
-{
-	uintptr p;
-	
-	p = (uintptr)v;
-	p -= (uintptr)h->arena_start;
-	return h->spans[p >> PageShift];
-}
-
-// Look up the span at the given address.
-// Address is *not* guaranteed to be in map
-// and may be anywhere in the span.
-// Map entries for the middle of a span are only
-// valid for allocated spans.  Free spans may have
-// other garbage in their middles, so we have to
-// check for that.
-MSpan*
-runtime·MHeap_LookupMaybe(MHeap *h, void *v)
-{
-	MSpan *s;
-	pageID p, q;
-
-	if((byte*)v < h->arena_start || (byte*)v >= h->arena_used)
-		return nil;
-	p = (uintptr)v>>PageShift;
-	q = p;
-	q -= (uintptr)h->arena_start >> PageShift;
-	s = h->spans[q];
-	if(s == nil || p < s->start || v >= s->limit || s->state != MSpanInUse)
-		return nil;
-	return s;
-}
-
-// Free the span back into the heap.
-static void
-mheap_free(MHeap *h, MSpan *s, int32 acct)
-{
-	if(g != g->m->g0)
-		runtime·throw("mheap_free not on M stack");
-	runtime·lock(&h->lock);
-	mstats.heap_alloc += g->m->mcache->local_cachealloc;
-	g->m->mcache->local_cachealloc = 0;
-	mstats.tinyallocs += g->m->mcache->local_tinyallocs;
-	g->m->mcache->local_tinyallocs = 0;
-	if(acct) {
-		mstats.heap_alloc -= s->npages<<PageShift;
-		mstats.heap_objects--;
-	}
-	MHeap_FreeSpanLocked(h, s, true, true);
-	runtime·unlock(&h->lock);
-}
-
-static void
-mheap_free_m(G *gp)
-{
-	MHeap *h;
-	MSpan *s;
-	
-	h = g->m->ptrarg[0];
-	s = g->m->ptrarg[1];
-	g->m->ptrarg[0] = nil;
-	g->m->ptrarg[1] = nil;
-	mheap_free(h, s, g->m->scalararg[0]);
-	runtime·gogo(&gp->sched);
-}
-
-void
-runtime·MHeap_Free(MHeap *h, MSpan *s, int32 acct)
-{
-	void (*fn)(G*);
-
-	if(g == g->m->g0) {
-		mheap_free(h, s, acct);
-	} else {
-		g->m->ptrarg[0] = h;
-		g->m->ptrarg[1] = s;
-		g->m->scalararg[0] = acct;
-		fn = mheap_free_m;
-		runtime·mcall(&fn);
-	}
-}
-
-void
-runtime·MHeap_FreeStack(MHeap *h, MSpan *s)
-{
-	if(g != g->m->g0)
-		runtime·throw("mheap_freestack not on M stack");
-	s->needzero = 1;
-	runtime·lock(&h->lock);
-	mstats.stacks_inuse -= s->npages<<PageShift;
-	MHeap_FreeSpanLocked(h, s, true, true);
-	runtime·unlock(&h->lock);
-}
-
-static void
-MHeap_FreeSpanLocked(MHeap *h, MSpan *s, bool acctinuse, bool acctidle)
-{
-	MSpan *t;
-	pageID p;
-
-	switch(s->state) {
-	case MSpanStack:
-		if(s->ref != 0)
-			runtime·throw("MHeap_FreeSpanLocked - invalid stack free");
-		break;
-	case MSpanInUse:
-		if(s->ref != 0 || s->sweepgen != h->sweepgen) {
-			runtime·printf("MHeap_FreeSpanLocked - span %p ptr %p ref %d sweepgen %d/%d\n",
-				       s, s->start<<PageShift, s->ref, s->sweepgen, h->sweepgen);
-			runtime·throw("MHeap_FreeSpanLocked - invalid free");
-		}
-		break;
-	default:
-		runtime·throw("MHeap_FreeSpanLocked - invalid span state");
-		break;
-	}
-	if(acctinuse)
-		mstats.heap_inuse -= s->npages<<PageShift;
-	if(acctidle)
-		mstats.heap_idle += s->npages<<PageShift;
-	s->state = MSpanFree;
-	runtime·MSpanList_Remove(s);
-	// Stamp newly unused spans. The scavenger will use that
-	// info to potentially give back some pages to the OS.
-	s->unusedsince = runtime·nanotime();
-	s->npreleased = 0;
-
-	// Coalesce with earlier, later spans.
-	p = s->start;
-	p -= (uintptr)h->arena_start >> PageShift;
-	if(p > 0 && (t = h->spans[p-1]) != nil && t->state != MSpanInUse && t->state != MSpanStack) {
-		s->start = t->start;
-		s->npages += t->npages;
-		s->npreleased = t->npreleased; // absorb released pages
-		s->needzero |= t->needzero;
-		p -= t->npages;
-		h->spans[p] = s;
-		runtime·MSpanList_Remove(t);
-		t->state = MSpanDead;
-		runtime·FixAlloc_Free(&h->spanalloc, t);
-	}
-	if((p+s->npages)*sizeof(h->spans[0]) < h->spans_mapped && (t = h->spans[p+s->npages]) != nil && t->state != MSpanInUse && t->state != MSpanStack) {
-		s->npages += t->npages;
-		s->npreleased += t->npreleased;
-		s->needzero |= t->needzero;
-		h->spans[p + s->npages - 1] = s;
-		runtime·MSpanList_Remove(t);
-		t->state = MSpanDead;
-		runtime·FixAlloc_Free(&h->spanalloc, t);
-	}
-
-	// Insert s into appropriate list.
-	if(s->npages < nelem(h->free))
-		runtime·MSpanList_Insert(&h->free[s->npages], s);
-	else
-		runtime·MSpanList_Insert(&h->freelarge, s);
-}
-
-static uintptr
-scavengelist(MSpan *list, uint64 now, uint64 limit)
-{
-	uintptr released, sumreleased;
-	MSpan *s;
-
-	if(runtime·MSpanList_IsEmpty(list))
-		return 0;
-
-	sumreleased = 0;
-	for(s=list->next; s != list; s=s->next) {
-		if((now - s->unusedsince) > limit && s->npreleased != s->npages) {
-			released = (s->npages - s->npreleased) << PageShift;
-			mstats.heap_released += released;
-			sumreleased += released;
-			s->npreleased = s->npages;
-			runtime·SysUnused((void*)(s->start << PageShift), s->npages << PageShift);
-		}
-	}
-	return sumreleased;
-}
-
-void
-runtime·MHeap_Scavenge(int32 k, uint64 now, uint64 limit)
-{
-	uint32 i;
-	uintptr sumreleased;
-	MHeap *h;
-	
-	h = &runtime·mheap;
-	runtime·lock(&h->lock);
-	sumreleased = 0;
-	for(i=0; i < nelem(h->free); i++)
-		sumreleased += scavengelist(&h->free[i], now, limit);
-	sumreleased += scavengelist(&h->freelarge, now, limit);
-	runtime·unlock(&h->lock);
-
-	if(runtime·debug.gctrace > 0) {
-		if(sumreleased > 0)
-			runtime·printf("scvg%d: %D MB released\n", k, (uint64)sumreleased>>20);
-		// TODO(dvyukov): these stats are incorrect as we don't subtract stack usage from heap.
-		// But we can't call ReadMemStats on g0 holding locks.
-		runtime·printf("scvg%d: inuse: %D, idle: %D, sys: %D, released: %D, consumed: %D (MB)\n",
-			k, mstats.heap_inuse>>20, mstats.heap_idle>>20, mstats.heap_sys>>20,
-			mstats.heap_released>>20, (mstats.heap_sys - mstats.heap_released)>>20);
-	}
-}
-
-void
-runtime·scavenge_m(void)
-{
-	runtime·MHeap_Scavenge(-1, ~(uintptr)0, 0);
-}
-
-// Initialize a new span with the given start and npages.
-void
-runtime·MSpan_Init(MSpan *span, pageID start, uintptr npages)
-{
-	span->next = nil;
-	span->prev = nil;
-	span->start = start;
-	span->npages = npages;
-	span->freelist = nil;
-	span->ref = 0;
-	span->sizeclass = 0;
-	span->incache = false;
-	span->elemsize = 0;
-	span->state = MSpanDead;
-	span->unusedsince = 0;
-	span->npreleased = 0;
-	span->specialLock.key = 0;
-	span->specials = nil;
-	span->needzero = 0;
-}
-
-// Initialize an empty doubly-linked list.
-void
-runtime·MSpanList_Init(MSpan *list)
-{
-	list->state = MSpanListHead;
-	list->next = list;
-	list->prev = list;
-}
-
-void
-runtime·MSpanList_Remove(MSpan *span)
-{
-	if(span->prev == nil && span->next == nil)
-		return;
-	span->prev->next = span->next;
-	span->next->prev = span->prev;
-	span->prev = nil;
-	span->next = nil;
-}
-
-bool
-runtime·MSpanList_IsEmpty(MSpan *list)
-{
-	return list->next == list;
-}
-
-void
-runtime·MSpanList_Insert(MSpan *list, MSpan *span)
-{
-	if(span->next != nil || span->prev != nil) {
-		runtime·printf("failed MSpanList_Insert %p %p %p\n", span, span->next, span->prev);
-		runtime·throw("MSpanList_Insert");
-	}
-	span->next = list->next;
-	span->prev = list;
-	span->next->prev = span;
-	span->prev->next = span;
-}
-
-void
-runtime·MSpanList_InsertBack(MSpan *list, MSpan *span)
-{
-	if(span->next != nil || span->prev != nil) {
-		runtime·printf("failed MSpanList_Insert %p %p %p\n", span, span->next, span->prev);
-		runtime·throw("MSpanList_Insert");
-	}
-	span->next = list;
-	span->prev = list->prev;
-	span->next->prev = span;
-	span->prev->next = span;
-}
-
-// Adds the special record s to the list of special records for
-// the object p.  All fields of s should be filled in except for
-// offset & next, which this routine will fill in.
-// Returns true if the special was successfully added, false otherwise.
-// (The add will fail only if a record with the same p and s->kind
-//  already exists.)
-static bool
-addspecial(void *p, Special *s)
-{
-	MSpan *span;
-	Special **t, *x;
-	uintptr offset;
-	byte kind;
-
-	span = runtime·MHeap_LookupMaybe(&runtime·mheap, p);
-	if(span == nil)
-		runtime·throw("addspecial on invalid pointer");
-
-	// Ensure that the span is swept.
-	// GC accesses specials list w/o locks. And it's just much safer.
-	g->m->locks++;
-	runtime·MSpan_EnsureSwept(span);
-
-	offset = (uintptr)p - (span->start << PageShift);
-	kind = s->kind;
-
-	runtime·lock(&span->specialLock);
-
-	// Find splice point, check for existing record.
-	t = &span->specials;
-	while((x = *t) != nil) {
-		if(offset == x->offset && kind == x->kind) {
-			runtime·unlock(&span->specialLock);
-			g->m->locks--;
-			return false; // already exists
-		}
-		if(offset < x->offset || (offset == x->offset && kind < x->kind))
-			break;
-		t = &x->next;
-	}
-	// Splice in record, fill in offset.
-	s->offset = offset;
-	s->next = x;
-	*t = s;
-	runtime·unlock(&span->specialLock);
-	g->m->locks--;
-	return true;
-}
-
-// Removes the Special record of the given kind for the object p.
-// Returns the record if the record existed, nil otherwise.
-// The caller must FixAlloc_Free the result.
-static Special*
-removespecial(void *p, byte kind)
-{
-	MSpan *span;
-	Special *s, **t;
-	uintptr offset;
-
-	span = runtime·MHeap_LookupMaybe(&runtime·mheap, p);
-	if(span == nil)
-		runtime·throw("removespecial on invalid pointer");
-
-	// Ensure that the span is swept.
-	// GC accesses specials list w/o locks. And it's just much safer.
-	g->m->locks++;
-	runtime·MSpan_EnsureSwept(span);
-
-	offset = (uintptr)p - (span->start << PageShift);
-
-	runtime·lock(&span->specialLock);
-	t = &span->specials;
-	while((s = *t) != nil) {
-		// This function is used for finalizers only, so we don't check for
-		// "interior" specials (p must be exactly equal to s->offset).
-		if(offset == s->offset && kind == s->kind) {
-			*t = s->next;
-			runtime·unlock(&span->specialLock);
-			g->m->locks--;
-			return s;
-		}
-		t = &s->next;
-	}
-	runtime·unlock(&span->specialLock);
-	g->m->locks--;
-	return nil;
-}
-
-// Adds a finalizer to the object p.  Returns true if it succeeded.
-bool
-runtime·addfinalizer(void *p, FuncVal *f, uintptr nret, Type *fint, PtrType *ot)
-{
-	SpecialFinalizer *s;
-
-	runtime·lock(&runtime·mheap.speciallock);
-	s = runtime·FixAlloc_Alloc(&runtime·mheap.specialfinalizeralloc);
-	runtime·unlock(&runtime·mheap.speciallock);
-	s->special.kind = KindSpecialFinalizer;
-	s->fn = f;
-	s->nret = nret;
-	s->fint = fint;
-	s->ot = ot;
-	if(addspecial(p, &s->special))
-		return true;
-
-	// There was an old finalizer
-	runtime·lock(&runtime·mheap.speciallock);
-	runtime·FixAlloc_Free(&runtime·mheap.specialfinalizeralloc, s);
-	runtime·unlock(&runtime·mheap.speciallock);
-	return false;
-}
-
-// Removes the finalizer (if any) from the object p.
-void
-runtime·removefinalizer(void *p)
-{
-	SpecialFinalizer *s;
-
-	s = (SpecialFinalizer*)removespecial(p, KindSpecialFinalizer);
-	if(s == nil)
-		return; // there wasn't a finalizer to remove
-	runtime·lock(&runtime·mheap.speciallock);
-	runtime·FixAlloc_Free(&runtime·mheap.specialfinalizeralloc, s);
-	runtime·unlock(&runtime·mheap.speciallock);
-}
-
-// Set the heap profile bucket associated with addr to b.
-void
-runtime·setprofilebucket_m(void)
-{	
-	void *p;
-	Bucket *b;
-	SpecialProfile *s;
-	
-	p = g->m->ptrarg[0];
-	b = g->m->ptrarg[1];
-	g->m->ptrarg[0] = nil;
-	g->m->ptrarg[1] = nil;
-
-	runtime·lock(&runtime·mheap.speciallock);
-	s = runtime·FixAlloc_Alloc(&runtime·mheap.specialprofilealloc);
-	runtime·unlock(&runtime·mheap.speciallock);
-	s->special.kind = KindSpecialProfile;
-	s->b = b;
-	if(!addspecial(p, &s->special))
-		runtime·throw("setprofilebucket: profile already set");
-}
-
-// Do whatever cleanup needs to be done to deallocate s.  It has
-// already been unlinked from the MSpan specials list.
-// Returns true if we should keep working on deallocating p.
-bool
-runtime·freespecial(Special *s, void *p, uintptr size, bool freed)
-{
-	SpecialFinalizer *sf;
-	SpecialProfile *sp;
-
-	switch(s->kind) {
-	case KindSpecialFinalizer:
-		sf = (SpecialFinalizer*)s;
-		runtime·queuefinalizer(p, sf->fn, sf->nret, sf->fint, sf->ot);
-		runtime·lock(&runtime·mheap.speciallock);
-		runtime·FixAlloc_Free(&runtime·mheap.specialfinalizeralloc, sf);
-		runtime·unlock(&runtime·mheap.speciallock);
-		return false; // don't free p until finalizer is done
-	case KindSpecialProfile:
-		sp = (SpecialProfile*)s;
-		runtime·mProf_Free(sp->b, size, freed);
-		runtime·lock(&runtime·mheap.speciallock);
-		runtime·FixAlloc_Free(&runtime·mheap.specialprofilealloc, sp);
-		runtime·unlock(&runtime·mheap.speciallock);
-		return true;
-	default:
-		runtime·throw("bad special kind");
-		return true;
-	}
-}
diff --git a/src/runtime/mheap.go b/src/runtime/mheap.go
new file mode 100644
index 0000000..bc4e7c1
--- /dev/null
+++ b/src/runtime/mheap.go
@@ -0,0 +1,1090 @@
+// 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.
+
+// Page heap.
+//
+// See malloc.go for overview.
+
+package runtime
+
+import "unsafe"
+
+// Main malloc heap.
+// The heap itself is the "free[]" and "large" arrays,
+// but all the other global data is here too.
+type mheap struct {
+	lock      mutex
+	free      [_MaxMHeapList]mspan // free lists of given length
+	freelarge mspan                // free lists length >= _MaxMHeapList
+	busy      [_MaxMHeapList]mspan // busy lists of large objects of given length
+	busylarge mspan                // busy lists of large objects length >= _MaxMHeapList
+	allspans  **mspan              // all spans out there
+	gcspans   **mspan              // copy of allspans referenced by gc marker or sweeper
+	nspan     uint32
+	sweepgen  uint32 // sweep generation, see comment in mspan
+	sweepdone uint32 // all spans are swept
+	// span lookup
+	spans        **mspan
+	spans_mapped uintptr
+
+	// Proportional sweep
+	spanBytesAlloc    uint64  // bytes of spans allocated this cycle; updated atomically
+	pagesSwept        uint64  // pages swept this cycle; updated atomically
+	sweepPagesPerByte float64 // proportional sweep ratio; written with lock, read without
+
+	// Malloc stats.
+	largefree  uint64                  // bytes freed for large objects (>maxsmallsize)
+	nlargefree uint64                  // number of frees for large objects (>maxsmallsize)
+	nsmallfree [_NumSizeClasses]uint64 // number of frees for small objects (<=maxsmallsize)
+
+	// range of addresses we might see in the heap
+	bitmap         uintptr
+	bitmap_mapped  uintptr
+	arena_start    uintptr
+	arena_used     uintptr // always mHeap_Map{Bits,Spans} before updating
+	arena_end      uintptr
+	arena_reserved bool
+
+	// central free lists for small size classes.
+	// the padding makes sure that the MCentrals are
+	// spaced CacheLineSize bytes apart, so that each MCentral.lock
+	// gets its own cache line.
+	central [_NumSizeClasses]struct {
+		mcentral mcentral
+		pad      [_CacheLineSize]byte
+	}
+
+	spanalloc             fixalloc // allocator for span*
+	cachealloc            fixalloc // allocator for mcache*
+	specialfinalizeralloc fixalloc // allocator for specialfinalizer*
+	specialprofilealloc   fixalloc // allocator for specialprofile*
+	speciallock           mutex    // lock for special record allocators.
+}
+
+var mheap_ mheap
+
+// An MSpan is a run of pages.
+//
+// When a MSpan is in the heap free list, state == MSpanFree
+// and heapmap(s->start) == span, heapmap(s->start+s->npages-1) == span.
+//
+// When a MSpan is allocated, state == MSpanInUse or MSpanStack
+// and heapmap(i) == span for all s->start <= i < s->start+s->npages.
+
+// Every MSpan is in one doubly-linked list,
+// either one of the MHeap's free lists or one of the
+// MCentral's span lists.  We use empty MSpan structures as list heads.
+
+// An MSpan representing actual memory has state _MSpanInUse,
+// _MSpanStack, or _MSpanFree. Transitions between these states are
+// constrained as follows:
+//
+// * A span may transition from free to in-use or stack during any GC
+//   phase.
+//
+// * During sweeping (gcphase == _GCoff), a span may transition from
+//   in-use to free (as a result of sweeping) or stack to free (as a
+//   result of stacks being freed).
+//
+// * During GC (gcphase != _GCoff), a span *must not* transition from
+//   stack or in-use to free. Because concurrent GC may read a pointer
+//   and then look up its span, the span state must be monotonic.
+const (
+	_MSpanInUse = iota // allocated for garbage collected heap
+	_MSpanStack        // allocated for use by stack allocator
+	_MSpanFree
+	_MSpanListHead
+	_MSpanDead
+)
+
+type mspan struct {
+	next     *mspan    // in a span linked list
+	prev     *mspan    // in a span linked list
+	start    pageID    // starting page number
+	npages   uintptr   // number of pages in span
+	freelist gclinkptr // list of free objects
+	// sweep generation:
+	// if sweepgen == h->sweepgen - 2, the span needs sweeping
+	// if sweepgen == h->sweepgen - 1, the span is currently being swept
+	// 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
+	limit       uintptr  // end of data in span
+	speciallock mutex    // guards specials list
+	specials    *special // linked list of special records sorted by offset.
+	baseMask    uintptr  // if non-0, elemsize is a power of 2, & this will get object allocation base
+}
+
+func (s *mspan) base() uintptr {
+	return uintptr(s.start << _PageShift)
+}
+
+func (s *mspan) layout() (size, n, total uintptr) {
+	total = s.npages << _PageShift
+	size = s.elemsize
+	if size > 0 {
+		n = total / size
+	}
+	return
+}
+
+var h_allspans []*mspan // TODO: make this h.allspans once mheap can be defined in Go
+
+// h_spans is a lookup table to map virtual address page IDs to *mspan.
+// For allocated spans, their pages map to the span itself.
+// For free spans, only the lowest and highest pages map to the span itself.  Internal
+// pages map to an arbitrary span.
+// For pages that have never been allocated, h_spans entries are nil.
+var h_spans []*mspan // TODO: make this h.spans once mheap can be defined in Go
+
+func recordspan(vh unsafe.Pointer, p unsafe.Pointer) {
+	h := (*mheap)(vh)
+	s := (*mspan)(p)
+	if len(h_allspans) >= cap(h_allspans) {
+		n := 64 * 1024 / ptrSize
+		if n < cap(h_allspans)*3/2 {
+			n = cap(h_allspans) * 3 / 2
+		}
+		var new []*mspan
+		sp := (*slice)(unsafe.Pointer(&new))
+		sp.array = sysAlloc(uintptr(n)*ptrSize, &memstats.other_sys)
+		if sp.array == nil {
+			throw("runtime: cannot allocate memory")
+		}
+		sp.len = len(h_allspans)
+		sp.cap = n
+		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 mgc.go.
+			if h.allspans != mheap_.gcspans {
+				sysFree(unsafe.Pointer(h.allspans), uintptr(cap(h_allspans))*ptrSize, &memstats.other_sys)
+			}
+		}
+		h_allspans = new
+		h.allspans = (**mspan)(unsafe.Pointer(sp.array))
+	}
+	h_allspans = append(h_allspans, s)
+	h.nspan = uint32(len(h_allspans))
+}
+
+// inheap reports whether b is a pointer into a (potentially dead) heap object.
+// It returns false for pointers into stack spans.
+// Non-preemptible because it is used by write barriers.
+//go:nowritebarrier
+//go:nosplit
+func inheap(b uintptr) bool {
+	if b == 0 || b < mheap_.arena_start || b >= mheap_.arena_used {
+		return false
+	}
+	// Not a beginning of a block, consult span table to find the block beginning.
+	k := b >> _PageShift
+	x := k
+	x -= mheap_.arena_start >> _PageShift
+	s := h_spans[x]
+	if s == nil || pageID(k) < s.start || b >= s.limit || s.state != mSpanInUse {
+		return false
+	}
+	return true
+}
+
+// TODO: spanOf and spanOfUnchecked are open-coded in a lot of places.
+// Use the functions instead.
+
+// spanOf returns the span of p. If p does not point into the heap or
+// no span contains p, spanOf returns nil.
+func spanOf(p uintptr) *mspan {
+	if p == 0 || p < mheap_.arena_start || p >= mheap_.arena_used {
+		return nil
+	}
+	return spanOfUnchecked(p)
+}
+
+// spanOfUnchecked is equivalent to spanOf, but the caller must ensure
+// that p points into the heap (that is, mheap_.arena_start <= p <
+// mheap_.arena_used).
+func spanOfUnchecked(p uintptr) *mspan {
+	return h_spans[(p-mheap_.arena_start)>>_PageShift]
+}
+
+func mlookup(v uintptr, base *uintptr, size *uintptr, sp **mspan) int32 {
+	_g_ := getg()
+
+	_g_.m.mcache.local_nlookup++
+	if ptrSize == 4 && _g_.m.mcache.local_nlookup >= 1<<30 {
+		// purge cache stats to prevent overflow
+		lock(&mheap_.lock)
+		purgecachedstats(_g_.m.mcache)
+		unlock(&mheap_.lock)
+	}
+
+	s := mHeap_LookupMaybe(&mheap_, unsafe.Pointer(v))
+	if sp != nil {
+		*sp = s
+	}
+	if s == nil {
+		if base != nil {
+			*base = 0
+		}
+		if size != nil {
+			*size = 0
+		}
+		return 0
+	}
+
+	p := uintptr(s.start) << _PageShift
+	if s.sizeclass == 0 {
+		// Large object.
+		if base != nil {
+			*base = p
+		}
+		if size != nil {
+			*size = s.npages << _PageShift
+		}
+		return 1
+	}
+
+	n := s.elemsize
+	if base != nil {
+		i := (uintptr(v) - uintptr(p)) / n
+		*base = p + i*n
+	}
+	if size != nil {
+		*size = n
+	}
+
+	return 1
+}
+
+// Initialize the heap.
+func mHeap_Init(h *mheap, spans_size uintptr) {
+	fixAlloc_Init(&h.spanalloc, unsafe.Sizeof(mspan{}), recordspan, unsafe.Pointer(h), &memstats.mspan_sys)
+	fixAlloc_Init(&h.cachealloc, unsafe.Sizeof(mcache{}), nil, nil, &memstats.mcache_sys)
+	fixAlloc_Init(&h.specialfinalizeralloc, unsafe.Sizeof(specialfinalizer{}), nil, nil, &memstats.other_sys)
+	fixAlloc_Init(&h.specialprofilealloc, unsafe.Sizeof(specialprofile{}), nil, nil, &memstats.other_sys)
+
+	// h->mapcache needs no init
+	for i := range h.free {
+		mSpanList_Init(&h.free[i])
+		mSpanList_Init(&h.busy[i])
+	}
+
+	mSpanList_Init(&h.freelarge)
+	mSpanList_Init(&h.busylarge)
+	for i := range h.central {
+		mCentral_Init(&h.central[i].mcentral, int32(i))
+	}
+
+	sp := (*slice)(unsafe.Pointer(&h_spans))
+	sp.array = unsafe.Pointer(h.spans)
+	sp.len = int(spans_size / ptrSize)
+	sp.cap = int(spans_size / ptrSize)
+}
+
+// mHeap_MapSpans makes sure that the spans are mapped
+// up to the new value of arena_used.
+//
+// It must be called with the expected new value of arena_used,
+// *before* h.arena_used has been updated.
+// Waiting to update arena_used until after the memory has been mapped
+// avoids faults when other threads try access the bitmap immediately
+// after observing the change to arena_used.
+func mHeap_MapSpans(h *mheap, arena_used uintptr) {
+	// Map spans array, PageSize at a time.
+	n := arena_used
+	n -= h.arena_start
+	n = n / _PageSize * ptrSize
+	n = round(n, _PhysPageSize)
+	if h.spans_mapped >= n {
+		return
+	}
+	sysMap(add(unsafe.Pointer(h.spans), h.spans_mapped), n-h.spans_mapped, h.arena_reserved, &memstats.other_sys)
+	h.spans_mapped = n
+}
+
+// Sweeps spans in list until reclaims at least npages into heap.
+// Returns the actual number of pages reclaimed.
+func mHeap_ReclaimList(h *mheap, list *mspan, npages uintptr) uintptr {
+	n := uintptr(0)
+	sg := mheap_.sweepgen
+retry:
+	for s := list.next; s != list; s = s.next {
+		if s.sweepgen == sg-2 && cas(&s.sweepgen, sg-2, sg-1) {
+			mSpanList_Remove(s)
+			// swept spans are at the end of the list
+			mSpanList_InsertBack(list, s)
+			unlock(&h.lock)
+			snpages := s.npages
+			if mSpan_Sweep(s, false) {
+				n += snpages
+			}
+			lock(&h.lock)
+			if n >= npages {
+				return n
+			}
+			// the span could have been moved elsewhere
+			goto retry
+		}
+		if s.sweepgen == sg-1 {
+			// the span is being sweept by background sweeper, skip
+			continue
+		}
+		// already swept empty span,
+		// all subsequent ones must also be either swept or in process of sweeping
+		break
+	}
+	return n
+}
+
+// Sweeps and reclaims at least npage pages into heap.
+// Called before allocating npage pages.
+func mHeap_Reclaim(h *mheap, npage uintptr) {
+	// First try to sweep busy spans with large objects of size >= npage,
+	// this has good chances of reclaiming the necessary space.
+	for i := int(npage); i < len(h.busy); i++ {
+		if mHeap_ReclaimList(h, &h.busy[i], npage) != 0 {
+			return // Bingo!
+		}
+	}
+
+	// Then -- even larger objects.
+	if mHeap_ReclaimList(h, &h.busylarge, npage) != 0 {
+		return // Bingo!
+	}
+
+	// Now try smaller objects.
+	// One such object is not enough, so we need to reclaim several of them.
+	reclaimed := uintptr(0)
+	for i := 0; i < int(npage) && i < len(h.busy); i++ {
+		reclaimed += mHeap_ReclaimList(h, &h.busy[i], npage-reclaimed)
+		if reclaimed >= npage {
+			return
+		}
+	}
+
+	// Now sweep everything that is not yet swept.
+	unlock(&h.lock)
+	for {
+		n := sweepone()
+		if n == ^uintptr(0) { // all spans are swept
+			break
+		}
+		reclaimed += n
+		if reclaimed >= npage {
+			break
+		}
+	}
+	lock(&h.lock)
+}
+
+// Allocate a new span of npage pages from the heap for GC'd memory
+// and record its size class in the HeapMap and HeapMapCache.
+func mHeap_Alloc_m(h *mheap, npage uintptr, sizeclass int32, large bool) *mspan {
+	_g_ := getg()
+	if _g_ != _g_.m.g0 {
+		throw("_mheap_alloc not on g0 stack")
+	}
+	lock(&h.lock)
+
+	// To prevent excessive heap growth, before allocating n pages
+	// we need to sweep and reclaim at least n pages.
+	if h.sweepdone == 0 {
+		// TODO(austin): This tends to sweep a large number of
+		// spans in order to find a few completely free spans
+		// (for example, in the garbage benchmark, this sweeps
+		// ~30x the number of pages its trying to allocate).
+		// If GC kept a bit for whether there were any marks
+		// in a span, we could release these free spans
+		// at the end of GC and eliminate this entirely.
+		mHeap_Reclaim(h, npage)
+	}
+
+	// transfer stats from cache to global
+	memstats.heap_live += uint64(_g_.m.mcache.local_cachealloc)
+	_g_.m.mcache.local_cachealloc = 0
+	memstats.heap_scan += uint64(_g_.m.mcache.local_scan)
+	_g_.m.mcache.local_scan = 0
+	memstats.tinyallocs += uint64(_g_.m.mcache.local_tinyallocs)
+	_g_.m.mcache.local_tinyallocs = 0
+
+	gcController.revise()
+
+	s := mHeap_AllocSpanLocked(h, npage)
+	if s != nil {
+		// Record span info, because gc needs to be
+		// able to map interior pointer to containing span.
+		atomicstore(&s.sweepgen, h.sweepgen)
+		s.state = _MSpanInUse
+		s.freelist = 0
+		s.ref = 0
+		s.sizeclass = uint8(sizeclass)
+		if sizeclass == 0 {
+			s.elemsize = s.npages << _PageShift
+			s.divShift = 0
+			s.divMul = 0
+			s.divShift2 = 0
+			s.baseMask = 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
+			s.baseMask = m.baseMask
+		}
+
+		// update stats, sweep lists
+		if large {
+			memstats.heap_objects++
+			memstats.heap_live += uint64(npage << _PageShift)
+			// Swept spans are at the end of lists.
+			if s.npages < uintptr(len(h.free)) {
+				mSpanList_InsertBack(&h.busy[s.npages], s)
+			} else {
+				mSpanList_InsertBack(&h.busylarge, s)
+			}
+		}
+	}
+	if trace.enabled {
+		traceHeapAlloc()
+	}
+
+	// h_spans is accessed concurrently without synchronization
+	// from other threads. Hence, there must be a store/store
+	// barrier here to ensure the writes to h_spans above happen
+	// before the caller can publish a pointer p to an object
+	// allocated from s. As soon as this happens, the garbage
+	// collector running on another processor could read p and
+	// look up s in h_spans. The unlock acts as the barrier to
+	// order these writes. On the read side, the data dependency
+	// between p and the index in h_spans orders the reads.
+	unlock(&h.lock)
+	return s
+}
+
+func mHeap_Alloc(h *mheap, npage uintptr, sizeclass int32, large bool, needzero bool) *mspan {
+	// Don't do any operations that lock the heap on the G stack.
+	// It might trigger stack growth, and the stack growth code needs
+	// to be able to allocate heap.
+	var s *mspan
+	systemstack(func() {
+		s = mHeap_Alloc_m(h, npage, sizeclass, large)
+	})
+
+	if s != nil {
+		if needzero && s.needzero != 0 {
+			memclr(unsafe.Pointer(s.start<<_PageShift), s.npages<<_PageShift)
+		}
+		s.needzero = 0
+	}
+	return s
+}
+
+func mHeap_AllocStack(h *mheap, npage uintptr) *mspan {
+	_g_ := getg()
+	if _g_ != _g_.m.g0 {
+		throw("mheap_allocstack not on g0 stack")
+	}
+	lock(&h.lock)
+	s := mHeap_AllocSpanLocked(h, npage)
+	if s != nil {
+		s.state = _MSpanStack
+		s.freelist = 0
+		s.ref = 0
+		memstats.stacks_inuse += uint64(s.npages << _PageShift)
+	}
+
+	// This unlock acts as a release barrier. See mHeap_Alloc_m.
+	unlock(&h.lock)
+	return s
+}
+
+// Allocates a span of the given size.  h must be locked.
+// The returned span has been removed from the
+// free list, but its state is still MSpanFree.
+func mHeap_AllocSpanLocked(h *mheap, npage uintptr) *mspan {
+	var s *mspan
+
+	// Try in fixed-size lists up to max.
+	for i := int(npage); i < len(h.free); i++ {
+		if !mSpanList_IsEmpty(&h.free[i]) {
+			s = h.free[i].next
+			goto HaveSpan
+		}
+	}
+
+	// Best fit in list of large spans.
+	s = mHeap_AllocLarge(h, npage)
+	if s == nil {
+		if !mHeap_Grow(h, npage) {
+			return nil
+		}
+		s = mHeap_AllocLarge(h, npage)
+		if s == nil {
+			return nil
+		}
+	}
+
+HaveSpan:
+	// Mark span in use.
+	if s.state != _MSpanFree {
+		throw("MHeap_AllocLocked - MSpan not free")
+	}
+	if s.npages < npage {
+		throw("MHeap_AllocLocked - bad npages")
+	}
+	mSpanList_Remove(s)
+	if s.next != nil || s.prev != nil {
+		throw("still in list")
+	}
+	if s.npreleased > 0 {
+		sysUsed((unsafe.Pointer)(s.start<<_PageShift), s.npages<<_PageShift)
+		memstats.heap_released -= uint64(s.npreleased << _PageShift)
+		s.npreleased = 0
+	}
+
+	if s.npages > npage {
+		// Trim extra and put it back in the heap.
+		t := (*mspan)(fixAlloc_Alloc(&h.spanalloc))
+		mSpan_Init(t, s.start+pageID(npage), s.npages-npage)
+		s.npages = npage
+		p := uintptr(t.start)
+		p -= (uintptr(unsafe.Pointer(h.arena_start)) >> _PageShift)
+		if p > 0 {
+			h_spans[p-1] = s
+		}
+		h_spans[p] = t
+		h_spans[p+t.npages-1] = t
+		t.needzero = s.needzero
+		s.state = _MSpanStack // prevent coalescing with s
+		t.state = _MSpanStack
+		mHeap_FreeSpanLocked(h, t, false, false, s.unusedsince)
+		s.state = _MSpanFree
+	}
+	s.unusedsince = 0
+
+	p := uintptr(s.start)
+	p -= (uintptr(unsafe.Pointer(h.arena_start)) >> _PageShift)
+	for n := uintptr(0); n < npage; n++ {
+		h_spans[p+n] = s
+	}
+
+	memstats.heap_inuse += uint64(npage << _PageShift)
+	memstats.heap_idle -= uint64(npage << _PageShift)
+
+	//println("spanalloc", hex(s.start<<_PageShift))
+	if s.next != nil || s.prev != nil {
+		throw("still in list")
+	}
+	return s
+}
+
+// Allocate a span of exactly npage pages from the list of large spans.
+func mHeap_AllocLarge(h *mheap, npage uintptr) *mspan {
+	return bestFit(&h.freelarge, npage, nil)
+}
+
+// Search list for smallest span with >= npage pages.
+// If there are multiple smallest spans, take the one
+// with the earliest starting address.
+func bestFit(list *mspan, npage uintptr, best *mspan) *mspan {
+	for s := list.next; s != list; s = s.next {
+		if s.npages < npage {
+			continue
+		}
+		if best == nil || s.npages < best.npages || (s.npages == best.npages && s.start < best.start) {
+			best = s
+		}
+	}
+	return best
+}
+
+// Try to add at least npage pages of memory to the heap,
+// returning whether it worked.
+func mHeap_Grow(h *mheap, npage uintptr) bool {
+	// Ask for a big chunk, to reduce the number of mappings
+	// the operating system needs to track; also amortizes
+	// the overhead of an operating system mapping.
+	// Allocate a multiple of 64kB.
+	npage = round(npage, (64<<10)/_PageSize)
+	ask := npage << _PageShift
+	if ask < _HeapAllocChunk {
+		ask = _HeapAllocChunk
+	}
+
+	v := mHeap_SysAlloc(h, ask)
+	if v == nil {
+		if ask > npage<<_PageShift {
+			ask = npage << _PageShift
+			v = mHeap_SysAlloc(h, ask)
+		}
+		if v == nil {
+			print("runtime: out of memory: cannot allocate ", ask, "-byte block (", memstats.heap_sys, " in use)\n")
+			return false
+		}
+	}
+
+	// Create a fake "in use" span and free it, so that the
+	// right coalescing happens.
+	s := (*mspan)(fixAlloc_Alloc(&h.spanalloc))
+	mSpan_Init(s, pageID(uintptr(v)>>_PageShift), ask>>_PageShift)
+	p := uintptr(s.start)
+	p -= (uintptr(unsafe.Pointer(h.arena_start)) >> _PageShift)
+	for i := p; i < p+s.npages; i++ {
+		h_spans[i] = s
+	}
+	atomicstore(&s.sweepgen, h.sweepgen)
+	s.state = _MSpanInUse
+	mHeap_FreeSpanLocked(h, s, false, true, 0)
+	return true
+}
+
+// Look up the span at the given address.
+// Address is guaranteed to be in map
+// and is guaranteed to be start or end of span.
+func mHeap_Lookup(h *mheap, v unsafe.Pointer) *mspan {
+	p := uintptr(v)
+	p -= uintptr(unsafe.Pointer(h.arena_start))
+	return h_spans[p>>_PageShift]
+}
+
+// Look up the span at the given address.
+// Address is *not* guaranteed to be in map
+// and may be anywhere in the span.
+// Map entries for the middle of a span are only
+// valid for allocated spans.  Free spans may have
+// other garbage in their middles, so we have to
+// check for that.
+func mHeap_LookupMaybe(h *mheap, v unsafe.Pointer) *mspan {
+	if uintptr(v) < uintptr(unsafe.Pointer(h.arena_start)) || uintptr(v) >= uintptr(unsafe.Pointer(h.arena_used)) {
+		return nil
+	}
+	p := uintptr(v) >> _PageShift
+	q := p
+	q -= uintptr(unsafe.Pointer(h.arena_start)) >> _PageShift
+	s := h_spans[q]
+	if s == nil || p < uintptr(s.start) || uintptr(v) >= uintptr(unsafe.Pointer(s.limit)) || s.state != _MSpanInUse {
+		return nil
+	}
+	return s
+}
+
+// Free the span back into the heap.
+func mHeap_Free(h *mheap, s *mspan, acct int32) {
+	systemstack(func() {
+		mp := getg().m
+		lock(&h.lock)
+		memstats.heap_live += uint64(mp.mcache.local_cachealloc)
+		mp.mcache.local_cachealloc = 0
+		memstats.heap_scan += uint64(mp.mcache.local_scan)
+		mp.mcache.local_scan = 0
+		memstats.tinyallocs += uint64(mp.mcache.local_tinyallocs)
+		mp.mcache.local_tinyallocs = 0
+		if acct != 0 {
+			memstats.heap_objects--
+		}
+		gcController.revise()
+		mHeap_FreeSpanLocked(h, s, true, true, 0)
+		if trace.enabled {
+			traceHeapAlloc()
+		}
+		unlock(&h.lock)
+	})
+}
+
+func mHeap_FreeStack(h *mheap, s *mspan) {
+	_g_ := getg()
+	if _g_ != _g_.m.g0 {
+		throw("mheap_freestack not on g0 stack")
+	}
+	s.needzero = 1
+	lock(&h.lock)
+	memstats.stacks_inuse -= uint64(s.npages << _PageShift)
+	mHeap_FreeSpanLocked(h, s, true, true, 0)
+	unlock(&h.lock)
+}
+
+func mHeap_FreeSpanLocked(h *mheap, s *mspan, acctinuse, acctidle bool, unusedsince int64) {
+	switch s.state {
+	case _MSpanStack:
+		if s.ref != 0 {
+			throw("MHeap_FreeSpanLocked - invalid stack free")
+		}
+	case _MSpanInUse:
+		if s.ref != 0 || s.sweepgen != h.sweepgen {
+			print("MHeap_FreeSpanLocked - span ", s, " ptr ", hex(s.start<<_PageShift), " ref ", s.ref, " sweepgen ", s.sweepgen, "/", h.sweepgen, "\n")
+			throw("MHeap_FreeSpanLocked - invalid free")
+		}
+	default:
+		throw("MHeap_FreeSpanLocked - invalid span state")
+	}
+
+	if acctinuse {
+		memstats.heap_inuse -= uint64(s.npages << _PageShift)
+	}
+	if acctidle {
+		memstats.heap_idle += uint64(s.npages << _PageShift)
+	}
+	s.state = _MSpanFree
+	mSpanList_Remove(s)
+
+	// Stamp newly unused spans. The scavenger will use that
+	// info to potentially give back some pages to the OS.
+	s.unusedsince = unusedsince
+	if unusedsince == 0 {
+		s.unusedsince = nanotime()
+	}
+	s.npreleased = 0
+
+	// Coalesce with earlier, later spans.
+	p := uintptr(s.start)
+	p -= uintptr(unsafe.Pointer(h.arena_start)) >> _PageShift
+	if p > 0 {
+		t := h_spans[p-1]
+		if t != nil && t.state != _MSpanInUse && t.state != _MSpanStack {
+			s.start = t.start
+			s.npages += t.npages
+			s.npreleased = t.npreleased // absorb released pages
+			s.needzero |= t.needzero
+			p -= t.npages
+			h_spans[p] = s
+			mSpanList_Remove(t)
+			t.state = _MSpanDead
+			fixAlloc_Free(&h.spanalloc, (unsafe.Pointer)(t))
+		}
+	}
+	if (p+s.npages)*ptrSize < h.spans_mapped {
+		t := h_spans[p+s.npages]
+		if t != nil && t.state != _MSpanInUse && t.state != _MSpanStack {
+			s.npages += t.npages
+			s.npreleased += t.npreleased
+			s.needzero |= t.needzero
+			h_spans[p+s.npages-1] = s
+			mSpanList_Remove(t)
+			t.state = _MSpanDead
+			fixAlloc_Free(&h.spanalloc, (unsafe.Pointer)(t))
+		}
+	}
+
+	// Insert s into appropriate list.
+	if s.npages < uintptr(len(h.free)) {
+		mSpanList_Insert(&h.free[s.npages], s)
+	} else {
+		mSpanList_Insert(&h.freelarge, s)
+	}
+}
+
+func scavengelist(list *mspan, now, limit uint64) uintptr {
+	if _PhysPageSize > _PageSize {
+		// golang.org/issue/9993
+		// If the physical page size of the machine is larger than
+		// our logical heap page size the kernel may round up the
+		// amount to be freed to its page size and corrupt the heap
+		// pages surrounding the unused block.
+		return 0
+	}
+
+	if mSpanList_IsEmpty(list) {
+		return 0
+	}
+
+	var sumreleased uintptr
+	for s := list.next; s != list; s = s.next {
+		if (now-uint64(s.unusedsince)) > limit && s.npreleased != s.npages {
+			released := (s.npages - s.npreleased) << _PageShift
+			memstats.heap_released += uint64(released)
+			sumreleased += released
+			s.npreleased = s.npages
+			sysUnused((unsafe.Pointer)(s.start<<_PageShift), s.npages<<_PageShift)
+		}
+	}
+	return sumreleased
+}
+
+func mHeap_Scavenge(k int32, now, limit uint64) {
+	h := &mheap_
+	lock(&h.lock)
+	var sumreleased uintptr
+	for i := 0; i < len(h.free); i++ {
+		sumreleased += scavengelist(&h.free[i], now, limit)
+	}
+	sumreleased += scavengelist(&h.freelarge, now, limit)
+	unlock(&h.lock)
+
+	if debug.gctrace > 0 {
+		if sumreleased > 0 {
+			print("scvg", k, ": ", sumreleased>>20, " MB released\n")
+		}
+		// TODO(dvyukov): these stats are incorrect as we don't subtract stack usage from heap.
+		// But we can't call ReadMemStats on g0 holding locks.
+		print("scvg", k, ": inuse: ", memstats.heap_inuse>>20, ", idle: ", memstats.heap_idle>>20, ", sys: ", memstats.heap_sys>>20, ", released: ", memstats.heap_released>>20, ", consumed: ", (memstats.heap_sys-memstats.heap_released)>>20, " (MB)\n")
+	}
+}
+
+//go:linkname runtime_debug_freeOSMemory runtime/debug.freeOSMemory
+func runtime_debug_freeOSMemory() {
+	startGC(gcForceBlockMode, false)
+	systemstack(func() { mHeap_Scavenge(-1, ^uint64(0), 0) })
+}
+
+// Initialize a new span with the given start and npages.
+func mSpan_Init(span *mspan, start pageID, npages uintptr) {
+	span.next = nil
+	span.prev = nil
+	span.start = start
+	span.npages = npages
+	span.freelist = 0
+	span.ref = 0
+	span.sizeclass = 0
+	span.incache = false
+	span.elemsize = 0
+	span.state = _MSpanDead
+	span.unusedsince = 0
+	span.npreleased = 0
+	span.speciallock.key = 0
+	span.specials = nil
+	span.needzero = 0
+}
+
+// Initialize an empty doubly-linked list.
+func mSpanList_Init(list *mspan) {
+	list.state = _MSpanListHead
+	list.next = list
+	list.prev = list
+}
+
+func mSpanList_Remove(span *mspan) {
+	if span.prev == nil && span.next == nil {
+		return
+	}
+	span.prev.next = span.next
+	span.next.prev = span.prev
+	span.prev = nil
+	span.next = nil
+}
+
+func mSpanList_IsEmpty(list *mspan) bool {
+	return list.next == list
+}
+
+func mSpanList_Insert(list *mspan, span *mspan) {
+	if span.next != nil || span.prev != nil {
+		println("failed MSpanList_Insert", span, span.next, span.prev)
+		throw("MSpanList_Insert")
+	}
+	span.next = list.next
+	span.prev = list
+	span.next.prev = span
+	span.prev.next = span
+}
+
+func mSpanList_InsertBack(list *mspan, span *mspan) {
+	if span.next != nil || span.prev != nil {
+		println("failed MSpanList_InsertBack", span, span.next, span.prev)
+		throw("MSpanList_InsertBack")
+	}
+	span.next = list
+	span.prev = list.prev
+	span.next.prev = span
+	span.prev.next = span
+}
+
+const (
+	_KindSpecialFinalizer = 1
+	_KindSpecialProfile   = 2
+	// Note: The finalizer special must be first because if we're freeing
+	// an object, a finalizer special will cause the freeing operation
+	// to abort, and we want to keep the other special records around
+	// if that happens.
+)
+
+type special struct {
+	next   *special // linked list in span
+	offset uint16   // span offset of object
+	kind   byte     // kind of special
+}
+
+// Adds the special record s to the list of special records for
+// the object p.  All fields of s should be filled in except for
+// offset & next, which this routine will fill in.
+// Returns true if the special was successfully added, false otherwise.
+// (The add will fail only if a record with the same p and s->kind
+//  already exists.)
+func addspecial(p unsafe.Pointer, s *special) bool {
+	span := mHeap_LookupMaybe(&mheap_, p)
+	if span == nil {
+		throw("addspecial on invalid pointer")
+	}
+
+	// Ensure that the span is swept.
+	// GC accesses specials list w/o locks. And it's just much safer.
+	mp := acquirem()
+	mSpan_EnsureSwept(span)
+
+	offset := uintptr(p) - uintptr(span.start<<_PageShift)
+	kind := s.kind
+
+	lock(&span.speciallock)
+
+	// Find splice point, check for existing record.
+	t := &span.specials
+	for {
+		x := *t
+		if x == nil {
+			break
+		}
+		if offset == uintptr(x.offset) && kind == x.kind {
+			unlock(&span.speciallock)
+			releasem(mp)
+			return false // already exists
+		}
+		if offset < uintptr(x.offset) || (offset == uintptr(x.offset) && kind < x.kind) {
+			break
+		}
+		t = &x.next
+	}
+
+	// Splice in record, fill in offset.
+	s.offset = uint16(offset)
+	s.next = *t
+	*t = s
+	unlock(&span.speciallock)
+	releasem(mp)
+
+	return true
+}
+
+// Removes the Special record of the given kind for the object p.
+// Returns the record if the record existed, nil otherwise.
+// The caller must FixAlloc_Free the result.
+func removespecial(p unsafe.Pointer, kind uint8) *special {
+	span := mHeap_LookupMaybe(&mheap_, p)
+	if span == nil {
+		throw("removespecial on invalid pointer")
+	}
+
+	// Ensure that the span is swept.
+	// GC accesses specials list w/o locks. And it's just much safer.
+	mp := acquirem()
+	mSpan_EnsureSwept(span)
+
+	offset := uintptr(p) - uintptr(span.start<<_PageShift)
+
+	lock(&span.speciallock)
+	t := &span.specials
+	for {
+		s := *t
+		if s == nil {
+			break
+		}
+		// This function is used for finalizers only, so we don't check for
+		// "interior" specials (p must be exactly equal to s->offset).
+		if offset == uintptr(s.offset) && kind == s.kind {
+			*t = s.next
+			unlock(&span.speciallock)
+			releasem(mp)
+			return s
+		}
+		t = &s.next
+	}
+	unlock(&span.speciallock)
+	releasem(mp)
+	return nil
+}
+
+// The described object has a finalizer set for it.
+type specialfinalizer struct {
+	special special
+	fn      *funcval
+	nret    uintptr
+	fint    *_type
+	ot      *ptrtype
+}
+
+// Adds a finalizer to the object p.  Returns true if it succeeded.
+func addfinalizer(p unsafe.Pointer, f *funcval, nret uintptr, fint *_type, ot *ptrtype) bool {
+	lock(&mheap_.speciallock)
+	s := (*specialfinalizer)(fixAlloc_Alloc(&mheap_.specialfinalizeralloc))
+	unlock(&mheap_.speciallock)
+	s.special.kind = _KindSpecialFinalizer
+	s.fn = f
+	s.nret = nret
+	s.fint = fint
+	s.ot = ot
+	if addspecial(p, &s.special) {
+		return true
+	}
+
+	// There was an old finalizer
+	lock(&mheap_.speciallock)
+	fixAlloc_Free(&mheap_.specialfinalizeralloc, (unsafe.Pointer)(s))
+	unlock(&mheap_.speciallock)
+	return false
+}
+
+// Removes the finalizer (if any) from the object p.
+func removefinalizer(p unsafe.Pointer) {
+	s := (*specialfinalizer)(unsafe.Pointer(removespecial(p, _KindSpecialFinalizer)))
+	if s == nil {
+		return // there wasn't a finalizer to remove
+	}
+	lock(&mheap_.speciallock)
+	fixAlloc_Free(&mheap_.specialfinalizeralloc, (unsafe.Pointer)(s))
+	unlock(&mheap_.speciallock)
+}
+
+// The described object is being heap profiled.
+type specialprofile struct {
+	special special
+	b       *bucket
+}
+
+// Set the heap profile bucket associated with addr to b.
+func setprofilebucket(p unsafe.Pointer, b *bucket) {
+	lock(&mheap_.speciallock)
+	s := (*specialprofile)(fixAlloc_Alloc(&mheap_.specialprofilealloc))
+	unlock(&mheap_.speciallock)
+	s.special.kind = _KindSpecialProfile
+	s.b = b
+	if !addspecial(p, &s.special) {
+		throw("setprofilebucket: profile already set")
+	}
+}
+
+// Do whatever cleanup needs to be done to deallocate s.  It has
+// already been unlinked from the MSpan specials list.
+// Returns true if we should keep working on deallocating p.
+func freespecial(s *special, p unsafe.Pointer, size uintptr, freed bool) bool {
+	switch s.kind {
+	case _KindSpecialFinalizer:
+		sf := (*specialfinalizer)(unsafe.Pointer(s))
+		queuefinalizer(p, sf.fn, sf.nret, sf.fint, sf.ot)
+		lock(&mheap_.speciallock)
+		fixAlloc_Free(&mheap_.specialfinalizeralloc, (unsafe.Pointer)(sf))
+		unlock(&mheap_.speciallock)
+		return false // don't free p until finalizer is done
+	case _KindSpecialProfile:
+		sp := (*specialprofile)(unsafe.Pointer(s))
+		mProf_Free(sp.b, size, freed)
+		lock(&mheap_.speciallock)
+		fixAlloc_Free(&mheap_.specialprofilealloc, (unsafe.Pointer)(sp))
+		unlock(&mheap_.speciallock)
+		return true
+	default:
+		throw("bad special kind")
+		panic("not reached")
+	}
+}
diff --git a/src/runtime/mkduff.go b/src/runtime/mkduff.go
new file mode 100644
index 0000000..dc94cee
--- /dev/null
+++ b/src/runtime/mkduff.go
@@ -0,0 +1,188 @@
+// 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
+
+// runtime·duffzero is a Duff's device for zeroing memory.
+// The compiler jumps to computed addresses within
+// the routine to zero chunks of memory.
+// Do not change duffzero without also
+// changing clearfat in cmd/?g/ggen.go.
+
+// runtime·duffcopy is a Duff's device for copying memory.
+// The compiler jumps to computed addresses within
+// the routine to copy chunks of memory.
+// Source and destination must not overlap.
+// Do not change duffcopy without also
+// changing blockcopy in cmd/?g/cgen.go.
+
+// See the zero* and copy* generators below
+// for architecture-specific comments.
+
+// mkduff generates duff_*.s.
+package main
+
+import (
+	"bytes"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"log"
+)
+
+func main() {
+	gen("amd64", notags, zeroAMD64, copyAMD64)
+	gen("386", notags, zero386, copy386)
+	gen("arm", notags, zeroARM, copyARM)
+	gen("arm64", notags, zeroARM64, copyARM64)
+	gen("ppc64x", tagsPPC64x, zeroPPC64x, copyPPC64x)
+}
+
+func gen(arch string, tags, zero, copy func(io.Writer)) {
+	var buf bytes.Buffer
+
+	fmt.Fprintln(&buf, "// AUTO-GENERATED by mkduff.go")
+	fmt.Fprintln(&buf, "// Run go generate from src/runtime to update.")
+	fmt.Fprintln(&buf, "// See mkduff.go for comments.")
+	tags(&buf)
+	fmt.Fprintln(&buf, "#include \"textflag.h\"")
+	fmt.Fprintln(&buf)
+	zero(&buf)
+	fmt.Fprintln(&buf)
+	copy(&buf)
+
+	if err := ioutil.WriteFile("duff_"+arch+".s", buf.Bytes(), 0644); err != nil {
+		log.Fatalln(err)
+	}
+}
+
+func notags(w io.Writer) { fmt.Fprintln(w) }
+
+func zeroAMD64(w io.Writer) {
+	// AX: zero
+	// DI: ptr to memory to be zeroed
+	// DI is updated as a side effect.
+	fmt.Fprintln(w, "TEXT runtime·duffzero(SB), NOSPLIT, $0-0")
+	for i := 0; i < 31; i++ {
+		fmt.Fprintln(w, "\tMOVQ\tAX,(DI)")
+		fmt.Fprintln(w, "\tMOVQ\tAX,8(DI)")
+		fmt.Fprintln(w, "\tMOVQ\tAX,16(DI)")
+		fmt.Fprintln(w, "\tMOVQ\tAX,24(DI)")
+		fmt.Fprintln(w, "\tADDQ\t$32,DI")
+		fmt.Fprintln(w)
+	}
+	for i := 0; i < 4; i++ {
+		fmt.Fprintln(w, "\tSTOSQ")
+	}
+	fmt.Fprintln(w, "\tRET")
+}
+
+func copyAMD64(w io.Writer) {
+	// SI: ptr to source memory
+	// DI: ptr to destination memory
+	// SI and DI are updated as a side effect.
+	//
+	// This is equivalent to a sequence of MOVSQ but
+	// for some reason that is 3.5x slower than this code.
+	// The STOSQ in duffzero seem fine, though.
+	fmt.Fprintln(w, "TEXT runtime·duffcopy(SB), NOSPLIT, $0-0")
+	for i := 0; i < 128; i++ {
+		fmt.Fprintln(w, "\tMOVQ\t(SI), CX")
+		fmt.Fprintln(w, "\tADDQ\t$8, SI")
+		fmt.Fprintln(w, "\tMOVQ\tCX, (DI)")
+		fmt.Fprintln(w, "\tADDQ\t$8, DI")
+		fmt.Fprintln(w)
+	}
+	fmt.Fprintln(w, "\tRET")
+}
+
+func zero386(w io.Writer) {
+	// AX: zero
+	// DI: ptr to memory to be zeroed
+	// DI is updated as a side effect.
+	fmt.Fprintln(w, "TEXT runtime·duffzero(SB), NOSPLIT, $0-0")
+	for i := 0; i < 128; i++ {
+		fmt.Fprintln(w, "\tSTOSL")
+	}
+	fmt.Fprintln(w, "\tRET")
+}
+
+func copy386(w io.Writer) {
+	// SI: ptr to source memory
+	// DI: ptr to destination memory
+	// SI and DI are updated as a side effect.
+	//
+	// This is equivalent to a sequence of MOVSL but
+	// for some reason MOVSL is really slow.
+	fmt.Fprintln(w, "TEXT runtime·duffcopy(SB), NOSPLIT, $0-0")
+	for i := 0; i < 128; i++ {
+		fmt.Fprintln(w, "\tMOVL\t(SI), CX")
+		fmt.Fprintln(w, "\tADDL\t$4, SI")
+		fmt.Fprintln(w, "\tMOVL\tCX, (DI)")
+		fmt.Fprintln(w, "\tADDL\t$4, DI")
+		fmt.Fprintln(w)
+	}
+	fmt.Fprintln(w, "\tRET")
+}
+
+func zeroARM(w io.Writer) {
+	// R0: zero
+	// R1: ptr to memory to be zeroed
+	// R1 is updated as a side effect.
+	fmt.Fprintln(w, "TEXT runtime·duffzero(SB), NOSPLIT, $0-0")
+	for i := 0; i < 128; i++ {
+		fmt.Fprintln(w, "\tMOVW.P\tR0, 4(R1)")
+	}
+	fmt.Fprintln(w, "\tRET")
+}
+
+func copyARM(w io.Writer) {
+	// R0: scratch space
+	// R1: ptr to source memory
+	// R2: ptr to destination memory
+	// R1 and R2 are updated as a side effect
+	fmt.Fprintln(w, "TEXT runtime·duffcopy(SB), NOSPLIT, $0-0")
+	for i := 0; i < 128; i++ {
+		fmt.Fprintln(w, "\tMOVW.P\t4(R1), R0")
+		fmt.Fprintln(w, "\tMOVW.P\tR0, 4(R2)")
+		fmt.Fprintln(w)
+	}
+	fmt.Fprintln(w, "\tRET")
+}
+
+func zeroARM64(w io.Writer) {
+	// ZR: always zero
+	// R16 (aka REGRT1): ptr to memory to be zeroed - 8
+	// On return, R16 points to the last zeroed dword.
+	fmt.Fprintln(w, "TEXT runtime·duffzero(SB), NOSPLIT, $-8-0")
+	for i := 0; i < 128; i++ {
+		fmt.Fprintln(w, "\tMOVD.W\tZR, 8(R16)")
+	}
+	fmt.Fprintln(w, "\tRET")
+}
+
+func copyARM64(w io.Writer) {
+	fmt.Fprintln(w, "// TODO: Implement runtime·duffcopy.")
+}
+
+func tagsPPC64x(w io.Writer) {
+	fmt.Fprintln(w)
+	fmt.Fprintln(w, "// +build ppc64 ppc64le")
+	fmt.Fprintln(w)
+}
+
+func zeroPPC64x(w io.Writer) {
+	// R0: always zero
+	// R3 (aka REGRT1): ptr to memory to be zeroed - 8
+	// On return, R3 points to the last zeroed dword.
+	fmt.Fprintln(w, "TEXT runtime·duffzero(SB), NOSPLIT, $-8-0")
+	for i := 0; i < 128; i++ {
+		fmt.Fprintln(w, "\tMOVDU\tR0, 8(R3)")
+	}
+	fmt.Fprintln(w, "\tRETURN")
+}
+
+func copyPPC64x(w io.Writer) {
+	fmt.Fprintln(w, "// TODO: Implement runtime·duffcopy.")
+}
diff --git a/src/runtime/mprof.go b/src/runtime/mprof.go
index f4da45f..a618bd5 100644
--- a/src/runtime/mprof.go
+++ b/src/runtime/mprof.go
@@ -100,7 +100,7 @@ func newBucket(typ bucketType, nstk int) *bucket {
 	size := unsafe.Sizeof(bucket{}) + uintptr(nstk)*unsafe.Sizeof(uintptr(0))
 	switch typ {
 	default:
-		gothrow("invalid profile bucket type")
+		throw("invalid profile bucket type")
 	case memProfile:
 		size += unsafe.Sizeof(memRecord{})
 	case blockProfile:
@@ -123,7 +123,7 @@ func (b *bucket) stk() []uintptr {
 // mp returns the memRecord associated with the memProfile bucket b.
 func (b *bucket) mp() *memRecord {
 	if b.typ != memProfile {
-		gothrow("bad use of bucket.mp")
+		throw("bad use of bucket.mp")
 	}
 	data := add(unsafe.Pointer(b), unsafe.Sizeof(*b)+b.nstk*unsafe.Sizeof(uintptr(0)))
 	return (*memRecord)(data)
@@ -132,7 +132,7 @@ func (b *bucket) mp() *memRecord {
 // bp returns the blockRecord associated with the blockProfile bucket b.
 func (b *bucket) bp() *blockRecord {
 	if b.typ != blockProfile {
-		gothrow("bad use of bucket.bp")
+		throw("bad use of bucket.bp")
 	}
 	data := add(unsafe.Pointer(b), unsafe.Sizeof(*b)+b.nstk*unsafe.Sizeof(uintptr(0)))
 	return (*blockRecord)(data)
@@ -143,7 +143,7 @@ func stkbucket(typ bucketType, size uintptr, stk []uintptr, alloc bool) *bucket
 	if buckhash == nil {
 		buckhash = (*[buckHashSize]*bucket)(sysAlloc(unsafe.Sizeof(*buckhash), &memstats.buckhash_sys))
 		if buckhash == nil {
-			gothrow("runtime: cannot allocate memory")
+			throw("runtime: cannot allocate memory")
 		}
 	}
 
@@ -190,8 +190,6 @@ func stkbucket(typ bucketType, size uintptr, stk []uintptr, alloc bool) *bucket
 	return b
 }
 
-func sysAlloc(n uintptr, stat *uint64) unsafe.Pointer
-
 func eqslice(x, y []uintptr) bool {
 	if len(x) != len(y) {
 		return false
@@ -234,7 +232,7 @@ func mProf_GC() {
 // Called by malloc to record a profiled block.
 func mProf_Malloc(p unsafe.Pointer, size uintptr) {
 	var stk [maxStack]uintptr
-	nstk := callers(4, &stk[0], len(stk))
+	nstk := callers(4, stk[:])
 	lock(&proflock)
 	b := stkbucket(memProfile, size, stk[:nstk], true)
 	mp := b.mp()
@@ -246,16 +244,9 @@ func mProf_Malloc(p unsafe.Pointer, size uintptr) {
 	// This reduces potential contention and chances of deadlocks.
 	// Since the object must be alive during call to mProf_Malloc,
 	// it's fine to do this non-atomically.
-	setprofilebucket(p, b)
-}
-
-func setprofilebucket_m() // mheap.c
-
-func setprofilebucket(p unsafe.Pointer, b *bucket) {
-	g := getg()
-	g.m.ptrarg[0] = p
-	g.m.ptrarg[1] = unsafe.Pointer(b)
-	onM(setprofilebucket_m)
+	systemstack(func() {
+		setprofilebucket(p, b)
+	})
 }
 
 // Called when freeing a profiled block.
@@ -309,9 +300,9 @@ func blockevent(cycles int64, skip int) {
 	var nstk int
 	var stk [maxStack]uintptr
 	if gp.m.curg == nil || gp.m.curg == gp {
-		nstk = callers(skip, &stk[0], len(stk))
+		nstk = callers(skip, stk[:])
 	} else {
-		nstk = gcallers(gp.m.curg, skip, &stk[0], len(stk))
+		nstk = gcallers(gp.m.curg, skip, stk[:])
 	}
 	lock(&proflock)
 	b := stkbucket(blockProfile, 0, stk[:nstk], true)
@@ -519,8 +510,6 @@ func ThreadCreateProfile(p []StackRecord) (n int, ok bool) {
 	return
 }
 
-var allgs []*g // proc.c
-
 // GoroutineProfile returns n, the number of records in the active goroutine stack profile.
 // If len(p) >= n, GoroutineProfile copies the profile into p and returns n, true.
 // If len(p) < n, GoroutineProfile does not change p and returns n, false.
@@ -532,9 +521,7 @@ func GoroutineProfile(p []StackRecord) (n int, ok bool) {
 	n = NumGoroutine()
 	if n <= len(p) {
 		gp := getg()
-		semacquire(&worldsema, false)
-		gp.m.gcing = 1
-		onM(stoptheworld)
+		stopTheWorld("profile")
 
 		n = NumGoroutine()
 		if n <= len(p) {
@@ -542,7 +529,7 @@ func GoroutineProfile(p []StackRecord) (n int, ok bool) {
 			r := p
 			sp := getcallersp(unsafe.Pointer(&p))
 			pc := getcallerpc(unsafe.Pointer(&p))
-			onM(func() {
+			systemstack(func() {
 				saveg(pc, sp, gp, &r[0])
 			})
 			r = r[1:]
@@ -555,9 +542,7 @@ func GoroutineProfile(p []StackRecord) (n int, ok bool) {
 			}
 		}
 
-		gp.m.gcing = 0
-		semrelease(&worldsema)
-		onM(starttheworld)
+		startTheWorld()
 	}
 
 	return n, ok
@@ -576,10 +561,7 @@ func saveg(pc, sp uintptr, gp *g, r *StackRecord) {
 // into buf after the trace for the current goroutine.
 func Stack(buf []byte, all bool) int {
 	if all {
-		semacquire(&worldsema, false)
-		gp := getg()
-		gp.m.gcing = 1
-		onM(stoptheworld)
+		stopTheWorld("stack trace")
 	}
 
 	n := 0
@@ -587,7 +569,7 @@ func Stack(buf []byte, all bool) int {
 		gp := getg()
 		sp := getcallersp(unsafe.Pointer(&buf))
 		pc := getcallerpc(unsafe.Pointer(&buf))
-		onM(func() {
+		systemstack(func() {
 			g0 := getg()
 			g0.writebuf = buf[0:0:len(buf)]
 			goroutineheader(gp)
@@ -601,10 +583,7 @@ func Stack(buf []byte, all bool) int {
 	}
 
 	if all {
-		gp := getg()
-		gp.m.gcing = 0
-		semrelease(&worldsema)
-		onM(starttheworld)
+		startTheWorld()
 	}
 	return n
 }
@@ -626,7 +605,7 @@ func tracealloc(p unsafe.Pointer, size uintptr, typ *_type) {
 		goroutineheader(gp)
 		pc := getcallerpc(unsafe.Pointer(&p))
 		sp := getcallersp(unsafe.Pointer(&p))
-		onM(func() {
+		systemstack(func() {
 			traceback(pc, sp, 0, gp)
 		})
 	} else {
@@ -646,7 +625,7 @@ func tracefree(p unsafe.Pointer, size uintptr) {
 	goroutineheader(gp)
 	pc := getcallerpc(unsafe.Pointer(&p))
 	sp := getcallersp(unsafe.Pointer(&p))
-	onM(func() {
+	systemstack(func() {
 		traceback(pc, sp, 0, gp)
 	})
 	print("\n")
diff --git a/src/runtime/msize.c b/src/runtime/msize.c
deleted file mode 100644
index 7cb65da..0000000
--- a/src/runtime/msize.c
+++ /dev/null
@@ -1,184 +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.
-
-// Malloc small size classes.
-//
-// See malloc.h 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).
-//
-// Each size class has its own page count that gets allocated
-// and chopped up when new objects of the size class are needed.
-// That page count is chosen so that chopping up the run of
-// pages into objects of the given size wastes at most 12.5% (1.125x)
-// of the memory.  It is not necessary that the cutoff here be
-// the same as above.
-//
-// The two sources of waste multiply, so the worst possible case
-// for the above constraints would be that allocations of some
-// size might have a 26.6% (1.266x) overhead.
-// In practice, only one of the wastes comes into play for a
-// given size (sizes < 512 waste mainly on the round-up,
-// sizes > 512 waste mainly on the page chopping).
-//
-// TODO(rsc): Compute max waste for any given size.
-
-#include "runtime.h"
-#include "arch_GOARCH.h"
-#include "malloc.h"
-#include "textflag.h"
-
-#pragma dataflag NOPTR
-int32 runtime·class_to_size[NumSizeClasses];
-#pragma dataflag NOPTR
-int32 runtime·class_to_allocnpages[NumSizeClasses];
-
-// The SizeToClass lookup is implemented using two arrays,
-// one mapping sizes <= 1024 to their class and one mapping
-// sizes >= 1024 and <= MaxSmallSize to their class.
-// All objects are 8-aligned, so the first array is indexed by
-// the size divided by 8 (rounded up).  Objects >= 1024 bytes
-// are 128-aligned, so the second array is indexed by the
-// size divided by 128 (rounded up).  The arrays are filled in
-// by InitSizes.
-
-#pragma dataflag NOPTR
-int8 runtime·size_to_class8[1024/8 + 1];
-#pragma dataflag NOPTR
-int8 runtime·size_to_class128[(MaxSmallSize-1024)/128 + 1];
-
-void runtime·testdefersizes(void);
-
-int32
-runtime·SizeToClass(int32 size)
-{
-	if(size > MaxSmallSize)
-		runtime·throw("SizeToClass - invalid size");
-	if(size > 1024-8)
-		return runtime·size_to_class128[(size-1024+127) >> 7];
-	return runtime·size_to_class8[(size+7)>>3];
-}
-
-void
-runtime·InitSizes(void)
-{
-	int32 align, sizeclass, size, nextsize, n;
-	uint32 i;
-	uintptr allocsize, npages;
-
-	// Initialize the runtime·class_to_size table (and choose class sizes in the process).
-	runtime·class_to_size[0] = 0;
-	sizeclass = 1;	// 0 means no class
-	align = 8;
-	for(size = align; size <= MaxSmallSize; size += align) {
-		if((size&(size-1)) == 0) {	// bump alignment once in a while
-			if(size >= 2048)
-				align = 256;
-			else if(size >= 128)
-				align = size / 8;
-			else if(size >= 16)
-				align = 16;	// required for x86 SSE instructions, if we want to use them
-		}
-		if((align&(align-1)) != 0)
-			runtime·throw("InitSizes - bug");
-
-		// Make the allocnpages big enough that
-		// the leftover is less than 1/8 of the total,
-		// so wasted space is at most 12.5%.
-		allocsize = PageSize;
-		while(allocsize%size > allocsize/8)
-			allocsize += PageSize;
-		npages = allocsize >> PageShift;
-
-		// If the previous sizeclass chose the same
-		// allocation size and fit the same number of
-		// objects into the page, we might as well
-		// use just this size instead of having two
-		// different sizes.
-		if(sizeclass > 1 &&
-			npages == runtime·class_to_allocnpages[sizeclass-1] &&
-			allocsize/size == allocsize/runtime·class_to_size[sizeclass-1]) {
-			runtime·class_to_size[sizeclass-1] = size;
-			continue;
-		}
-
-		runtime·class_to_allocnpages[sizeclass] = npages;
-		runtime·class_to_size[sizeclass] = size;
-		sizeclass++;
-	}
-	if(sizeclass != NumSizeClasses) {
-		runtime·printf("sizeclass=%d NumSizeClasses=%d\n", sizeclass, NumSizeClasses);
-		runtime·throw("InitSizes - bad NumSizeClasses");
-	}
-
-	// Initialize the size_to_class tables.
-	nextsize = 0;
-	for (sizeclass = 1; sizeclass < NumSizeClasses; sizeclass++) {
-		for(; nextsize < 1024 && nextsize <= runtime·class_to_size[sizeclass]; nextsize+=8)
-			runtime·size_to_class8[nextsize/8] = sizeclass;
-		if(nextsize >= 1024)
-			for(; nextsize <= runtime·class_to_size[sizeclass]; nextsize += 128)
-				runtime·size_to_class128[(nextsize-1024)/128] = sizeclass;
-	}
-
-	// Double-check SizeToClass.
-	if(0) {
-		for(n=0; n < MaxSmallSize; n++) {
-			sizeclass = runtime·SizeToClass(n);
-			if(sizeclass < 1 || sizeclass >= NumSizeClasses || runtime·class_to_size[sizeclass] < n) {
-				runtime·printf("size=%d sizeclass=%d runtime·class_to_size=%d\n", n, sizeclass, runtime·class_to_size[sizeclass]);
-				runtime·printf("incorrect SizeToClass");
-				goto dump;
-			}
-			if(sizeclass > 1 && runtime·class_to_size[sizeclass-1] >= n) {
-				runtime·printf("size=%d sizeclass=%d runtime·class_to_size=%d\n", n, sizeclass, runtime·class_to_size[sizeclass]);
-				runtime·printf("SizeToClass too big");
-				goto dump;
-			}
-		}
-	}
-
-	runtime·testdefersizes();
-
-	// Copy out for statistics table.
-	for(i=0; i<nelem(runtime·class_to_size); i++)
-		mstats.by_size[i].size = runtime·class_to_size[i];
-	return;
-
-dump:
-	if(1){
-		runtime·printf("NumSizeClasses=%d\n", NumSizeClasses);
-		runtime·printf("runtime·class_to_size:");
-		for(sizeclass=0; sizeclass<NumSizeClasses; sizeclass++)
-			runtime·printf(" %d", runtime·class_to_size[sizeclass]);
-		runtime·printf("\n\n");
-		runtime·printf("size_to_class8:");
-		for(i=0; i<nelem(runtime·size_to_class8); i++)
-			runtime·printf(" %d=>%d(%d)\n", i*8, runtime·size_to_class8[i],
-				runtime·class_to_size[runtime·size_to_class8[i]]);
-		runtime·printf("\n");
-		runtime·printf("size_to_class128:");
-		for(i=0; i<nelem(runtime·size_to_class128); i++)
-			runtime·printf(" %d=>%d(%d)\n", i*128, runtime·size_to_class128[i],
-				runtime·class_to_size[runtime·size_to_class128[i]]);
-		runtime·printf("\n");
-	}
-	runtime·throw("InitSizes failed");
-}
-
-// Returns size of the memory block that mallocgc will allocate if you ask for the size.
-uintptr
-runtime·roundupsize(uintptr size)
-{
-	if(size < MaxSmallSize) {
-		if(size <= 1024-8)
-			return runtime·class_to_size[runtime·size_to_class8[(size+7)>>3]];
-		else
-			return runtime·class_to_size[runtime·size_to_class128[(size-1024+127) >> 7]];
-	}
-	if(size + PageSize < size)
-		return size;
-	return ROUND(size, PageSize);
-}
diff --git a/src/runtime/msize.go b/src/runtime/msize.go
new file mode 100644
index 0000000..bc735be
--- /dev/null
+++ b/src/runtime/msize.go
@@ -0,0 +1,254 @@
+// 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.
+
+// Malloc small size classes.
+//
+// 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).
+//
+// Each size class has its own page count that gets allocated
+// and chopped up when new objects of the size class are needed.
+// That page count is chosen so that chopping up the run of
+// pages into objects of the given size wastes at most 12.5% (1.125x)
+// of the memory.  It is not necessary that the cutoff here be
+// the same as above.
+//
+// The two sources of waste multiply, so the worst possible case
+// for the above constraints would be that allocations of some
+// size might have a 26.6% (1.266x) overhead.
+// In practice, only one of the wastes comes into play for a
+// given size (sizes < 512 waste mainly on the round-up,
+// sizes > 512 waste mainly on the page chopping).
+//
+// TODO(rsc): Compute max waste for any given size.
+
+package runtime
+
+// Size classes.  Computed and initialized by InitSizes.
+//
+// SizeToClass(0 <= n <= MaxSmallSize) returns the size class,
+//	1 <= sizeclass < NumSizeClasses, for n.
+//	Size class 0 is reserved to mean "not small".
+//
+// class_to_size[i] = largest size in class i
+// class_to_allocnpages[i] = number of pages to allocate when
+//	making new objects in class i
+
+// The SizeToClass lookup is implemented using two arrays,
+// one mapping sizes <= 1024 to their class and one mapping
+// sizes >= 1024 and <= MaxSmallSize to their class.
+// All objects are 8-aligned, so the first array is indexed by
+// the size divided by 8 (rounded up).  Objects >= 1024 bytes
+// are 128-aligned, so the second array is indexed by the
+// size divided by 128 (rounded up).  The arrays are filled in
+// by InitSizes.
+
+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
+
+func sizeToClass(size int32) int32 {
+	if size > _MaxSmallSize {
+		throw("SizeToClass - invalid size")
+	}
+	if size > 1024-8 {
+		return int32(size_to_class128[(size-1024+127)>>7])
+	}
+	return int32(size_to_class8[(size+7)>>3])
+}
+
+func initSizes() {
+	// Initialize the runtime·class_to_size table (and choose class sizes in the process).
+	class_to_size[0] = 0
+	sizeclass := 1 // 0 means no class
+	align := 8
+	for size := align; size <= _MaxSmallSize; size += align {
+		if size&(size-1) == 0 { // bump alignment once in a while
+			if size >= 2048 {
+				align = 256
+			} else if size >= 128 {
+				align = size / 8
+			} else if size >= 16 {
+				align = 16 // required for x86 SSE instructions, if we want to use them
+			}
+		}
+		if align&(align-1) != 0 {
+			throw("InitSizes - bug")
+		}
+
+		// Make the allocnpages big enough that
+		// the leftover is less than 1/8 of the total,
+		// so wasted space is at most 12.5%.
+		allocsize := _PageSize
+		for allocsize%size > allocsize/8 {
+			allocsize += _PageSize
+		}
+		npages := allocsize >> _PageShift
+
+		// If the previous sizeclass chose the same
+		// allocation size and fit the same number of
+		// objects into the page, we might as well
+		// use just this size instead of having two
+		// different sizes.
+		if sizeclass > 1 && npages == int(class_to_allocnpages[sizeclass-1]) && allocsize/size == allocsize/int(class_to_size[sizeclass-1]) {
+			class_to_size[sizeclass-1] = int32(size)
+			continue
+		}
+
+		class_to_allocnpages[sizeclass] = int32(npages)
+		class_to_size[sizeclass] = int32(size)
+		sizeclass++
+	}
+	if sizeclass != _NumSizeClasses {
+		print("sizeclass=", sizeclass, " NumSizeClasses=", _NumSizeClasses, "\n")
+		throw("InitSizes - bad NumSizeClasses")
+	}
+
+	// Initialize the size_to_class tables.
+	nextsize := 0
+	for sizeclass = 1; sizeclass < _NumSizeClasses; sizeclass++ {
+		for ; nextsize < 1024 && nextsize <= int(class_to_size[sizeclass]); nextsize += 8 {
+			size_to_class8[nextsize/8] = int8(sizeclass)
+		}
+		if nextsize >= 1024 {
+			for ; nextsize <= int(class_to_size[sizeclass]); nextsize += 128 {
+				size_to_class128[(nextsize-1024)/128] = int8(sizeclass)
+			}
+		}
+	}
+
+	// Double-check SizeToClass.
+	if false {
+		for n := int32(0); n < _MaxSmallSize; n++ {
+			sizeclass := sizeToClass(n)
+			if sizeclass < 1 || sizeclass >= _NumSizeClasses || class_to_size[sizeclass] < n {
+				print("size=", n, " sizeclass=", sizeclass, " runtime·class_to_size=", class_to_size[sizeclass], "\n")
+				print("incorrect SizeToClass\n")
+				goto dump
+			}
+			if sizeclass > 1 && class_to_size[sizeclass-1] >= n {
+				print("size=", n, " sizeclass=", sizeclass, " runtime·class_to_size=", class_to_size[sizeclass], "\n")
+				print("SizeToClass too big\n")
+				goto dump
+			}
+		}
+	}
+
+	testdefersizes()
+
+	// Copy out for statistics table.
+	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:
+	if true {
+		print("NumSizeClasses=", _NumSizeClasses, "\n")
+		print("runtime·class_to_size:")
+		for sizeclass = 0; sizeclass < _NumSizeClasses; sizeclass++ {
+			print(" ", class_to_size[sizeclass], "")
+		}
+		print("\n\n")
+		print("size_to_class8:")
+		for i := 0; i < len(size_to_class8); i++ {
+			print(" ", i*8, "=>", size_to_class8[i], "(", class_to_size[size_to_class8[i]], ")\n")
+		}
+		print("\n")
+		print("size_to_class128:")
+		for i := 0; i < len(size_to_class128); i++ {
+			print(" ", i*128, "=>", size_to_class128[i], "(", class_to_size[size_to_class128[i]], ")\n")
+		}
+		print("\n")
+	}
+	throw("InitSizes failed")
+}
+
+// Returns size of the memory block that mallocgc will allocate if you ask for the size.
+func roundupsize(size uintptr) uintptr {
+	if size < _MaxSmallSize {
+		if size <= 1024-8 {
+			return uintptr(class_to_size[size_to_class8[(size+7)>>3]])
+		} else {
+			return uintptr(class_to_size[size_to_class128[(size-1024+127)>>7]])
+		}
+	}
+	if size+_PageSize < size {
+		return size
+	}
+	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
+	baseMask uintptr
+}
+
+func computeDivMagic(d uint32) divMagic {
+	var m divMagic
+
+	// If the size is a power of two, heapBitsForObject can divide even faster by masking.
+	// Compute this mask.
+	if d&(d-1) == 0 {
+		// It is a power of 2 (assuming dinptr != 1)
+		m.baseMask = ^(uintptr(d) - 1)
+	} else {
+		m.baseMask = 0
+	}
+
+	// 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
new file mode 100644
index 0000000..08b82e0
--- /dev/null
+++ b/src/runtime/mstats.go
@@ -0,0 +1,391 @@
+// 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.
+
+// Memory statistics
+
+package runtime
+
+import "unsafe"
+
+// Statistics.
+// If you edit this structure, also edit type MemStats below.
+type mstats struct {
+	// General statistics.
+	alloc       uint64 // bytes allocated and not yet freed
+	total_alloc uint64 // bytes allocated (even if freed)
+	sys         uint64 // bytes obtained from system (should be sum of xxx_sys below, no locking, approximate)
+	nlookup     uint64 // number of pointer lookups
+	nmalloc     uint64 // number of mallocs
+	nfree       uint64 // number of frees
+
+	// Statistics about malloc heap.
+	// protected by mheap.lock
+	heap_alloc    uint64 // bytes allocated and not yet freed (same as alloc above)
+	heap_sys      uint64 // bytes obtained from system
+	heap_idle     uint64 // bytes in idle spans
+	heap_inuse    uint64 // bytes in non-idle spans
+	heap_released uint64 // bytes released to the os
+	heap_objects  uint64 // total number of allocated objects
+
+	// Statistics about allocation of low-level fixed-size structures.
+	// Protected by FixAlloc locks.
+	stacks_inuse uint64 // this number is included in heap_inuse above
+	stacks_sys   uint64 // always 0 in mstats
+	mspan_inuse  uint64 // mspan structures
+	mspan_sys    uint64
+	mcache_inuse uint64 // mcache structures
+	mcache_sys   uint64
+	buckhash_sys uint64 // profiling bucket hash table
+	gc_sys       uint64
+	other_sys    uint64
+
+	// Statistics about garbage collector.
+	// Protected by mheap or stopping the world during GC.
+	next_gc         uint64 // next gc (in heap_alloc time)
+	last_gc         uint64 // last gc (in absolute time)
+	pause_total_ns  uint64
+	pause_ns        [256]uint64 // circular buffer of recent gc pause lengths
+	pause_end       [256]uint64 // circular buffer of recent gc end times (nanoseconds since 1970)
+	numgc           uint32
+	gc_cpu_fraction float64 // fraction of CPU time used by GC
+	enablegc        bool
+	debuggc         bool
+
+	// Statistics about allocation size classes.
+
+	by_size [_NumSizeClasses]struct {
+		size    uint32
+		nmalloc uint64
+		nfree   uint64
+	}
+
+	// Statistics below here are not exported to Go directly.
+
+	tinyallocs uint64 // number of tiny allocations that didn't cause actual allocation; not exported to go directly
+
+	// heap_live is the number of bytes considered live by the GC.
+	// That is: retained by the most recent GC plus allocated
+	// since then. heap_live <= heap_alloc, since heap_live
+	// excludes unmarked objects that have not yet been swept.
+	heap_live uint64
+
+	// heap_scan is the number of bytes of "scannable" heap. This
+	// is the live heap (as counted by heap_live), but omitting
+	// no-scan objects and no-scan tails of objects.
+	heap_scan uint64
+
+	// heap_marked is the number of bytes marked by the previous
+	// GC. After mark termination, heap_live == heap_marked, but
+	// unlike heap_live, heap_marked does not change until the
+	// next mark termination.
+	heap_marked uint64
+
+	// heap_reachable is an estimate of the reachable heap bytes
+	// at the end of the previous GC.
+	heap_reachable uint64
+}
+
+var memstats mstats
+
+// A MemStats records statistics about the memory allocator.
+type MemStats struct {
+	// General statistics.
+	Alloc      uint64 // bytes allocated and not yet freed
+	TotalAlloc uint64 // bytes allocated (even if freed)
+	Sys        uint64 // bytes obtained from system (sum of XxxSys below)
+	Lookups    uint64 // number of pointer lookups
+	Mallocs    uint64 // number of mallocs
+	Frees      uint64 // number of frees
+
+	// Main allocation heap statistics.
+	HeapAlloc    uint64 // bytes allocated and not yet freed (same as Alloc above)
+	HeapSys      uint64 // bytes obtained from system
+	HeapIdle     uint64 // bytes in idle spans
+	HeapInuse    uint64 // bytes in non-idle span
+	HeapReleased uint64 // bytes released to the OS
+	HeapObjects  uint64 // total number of allocated objects
+
+	// Low-level fixed-size structure allocator statistics.
+	//	Inuse is bytes used now.
+	//	Sys is bytes obtained from system.
+	StackInuse  uint64 // bytes used by stack allocator
+	StackSys    uint64
+	MSpanInuse  uint64 // mspan structures
+	MSpanSys    uint64
+	MCacheInuse uint64 // mcache structures
+	MCacheSys   uint64
+	BuckHashSys uint64 // profiling bucket hash table
+	GCSys       uint64 // GC metadata
+	OtherSys    uint64 // other system allocations
+
+	// Garbage collector statistics.
+	NextGC        uint64 // next collection will happen when HeapAlloc ≥ this amount
+	LastGC        uint64 // end time of last collection (nanoseconds since 1970)
+	PauseTotalNs  uint64
+	PauseNs       [256]uint64 // circular buffer of recent GC pause durations, most recent at [(NumGC+255)%256]
+	PauseEnd      [256]uint64 // circular buffer of recent GC pause end times
+	NumGC         uint32
+	GCCPUFraction float64 // fraction of CPU time used by GC
+	EnableGC      bool
+	DebugGC       bool
+
+	// Per-size allocation statistics.
+	// 61 is NumSizeClasses in the C code.
+	BySize [61]struct {
+		Size    uint32
+		Mallocs uint64
+		Frees   uint64
+	}
+}
+
+// Size of the trailing by_size array differs between Go and C,
+// and all data after by_size is local to runtime, not exported.
+// NumSizeClasses was changed, but we can not change Go struct because of backward compatibility.
+// sizeof_C_MStats is what C thinks about size of Go struct.
+var sizeof_C_MStats = unsafe.Offsetof(memstats.by_size) + 61*unsafe.Sizeof(memstats.by_size[0])
+
+func init() {
+	var memStats MemStats
+	if sizeof_C_MStats != unsafe.Sizeof(memStats) {
+		println(sizeof_C_MStats, unsafe.Sizeof(memStats))
+		throw("MStats vs MemStatsType size mismatch")
+	}
+}
+
+// ReadMemStats populates m with memory allocator statistics.
+func ReadMemStats(m *MemStats) {
+	stopTheWorld("read mem stats")
+
+	systemstack(func() {
+		readmemstats_m(m)
+	})
+
+	startTheWorld()
+}
+
+func readmemstats_m(stats *MemStats) {
+	updatememstats(nil)
+
+	// Size of the trailing by_size array differs between Go and C,
+	// NumSizeClasses was changed, but we can not change Go struct because of backward compatibility.
+	memmove(unsafe.Pointer(stats), unsafe.Pointer(&memstats), sizeof_C_MStats)
+
+	// Stack numbers are part of the heap numbers, separate those out for user consumption
+	stats.StackSys += stats.StackInuse
+	stats.HeapInuse -= stats.StackInuse
+	stats.HeapSys -= stats.StackInuse
+}
+
+//go:linkname readGCStats runtime/debug.readGCStats
+func readGCStats(pauses *[]uint64) {
+	systemstack(func() {
+		readGCStats_m(pauses)
+	})
+}
+
+func readGCStats_m(pauses *[]uint64) {
+	p := *pauses
+	// Calling code in runtime/debug should make the slice large enough.
+	if cap(p) < len(memstats.pause_ns)+3 {
+		throw("short slice passed to readGCStats")
+	}
+
+	// Pass back: pauses, pause ends, last gc (absolute time), number of gc, total pause ns.
+	lock(&mheap_.lock)
+
+	n := memstats.numgc
+	if n > uint32(len(memstats.pause_ns)) {
+		n = uint32(len(memstats.pause_ns))
+	}
+
+	// The pause buffer is circular. The most recent pause is at
+	// pause_ns[(numgc-1)%len(pause_ns)], and then backward
+	// from there to go back farther in time. We deliver the times
+	// most recent first (in p[0]).
+	p = p[:cap(p)]
+	for i := uint32(0); i < n; i++ {
+		j := (memstats.numgc - 1 - i) % uint32(len(memstats.pause_ns))
+		p[i] = memstats.pause_ns[j]
+		p[n+i] = memstats.pause_end[j]
+	}
+
+	p[n+n] = memstats.last_gc
+	p[n+n+1] = uint64(memstats.numgc)
+	p[n+n+2] = memstats.pause_total_ns
+	unlock(&mheap_.lock)
+	*pauses = p[:n+n+3]
+}
+
+//go:nowritebarrier
+func updatememstats(stats *gcstats) {
+	if stats != nil {
+		*stats = gcstats{}
+	}
+	for mp := allm; mp != nil; mp = mp.alllink {
+		if stats != nil {
+			src := (*[unsafe.Sizeof(gcstats{}) / 8]uint64)(unsafe.Pointer(&mp.gcstats))
+			dst := (*[unsafe.Sizeof(gcstats{}) / 8]uint64)(unsafe.Pointer(stats))
+			for i, v := range src {
+				dst[i] += v
+			}
+			mp.gcstats = gcstats{}
+		}
+	}
+
+	memstats.mcache_inuse = uint64(mheap_.cachealloc.inuse)
+	memstats.mspan_inuse = uint64(mheap_.spanalloc.inuse)
+	memstats.sys = memstats.heap_sys + memstats.stacks_sys + memstats.mspan_sys +
+		memstats.mcache_sys + memstats.buckhash_sys + memstats.gc_sys + memstats.other_sys
+
+	// Calculate memory allocator stats.
+	// During program execution we only count number of frees and amount of freed memory.
+	// Current number of alive object in the heap and amount of alive heap memory
+	// are calculated by scanning all spans.
+	// Total number of mallocs is calculated as number of frees plus number of alive objects.
+	// Similarly, total amount of allocated memory is calculated as amount of freed memory
+	// plus amount of alive heap memory.
+	memstats.alloc = 0
+	memstats.total_alloc = 0
+	memstats.nmalloc = 0
+	memstats.nfree = 0
+	for i := 0; i < len(memstats.by_size); i++ {
+		memstats.by_size[i].nmalloc = 0
+		memstats.by_size[i].nfree = 0
+	}
+
+	// Flush MCache's to MCentral.
+	systemstack(flushallmcaches)
+
+	// Aggregate local stats.
+	cachestats()
+
+	// Scan all spans and count number of alive objects.
+	lock(&mheap_.lock)
+	for i := uint32(0); i < mheap_.nspan; i++ {
+		s := h_allspans[i]
+		if s.state != mSpanInUse {
+			continue
+		}
+		if s.sizeclass == 0 {
+			memstats.nmalloc++
+			memstats.alloc += uint64(s.elemsize)
+		} else {
+			memstats.nmalloc += uint64(s.ref)
+			memstats.by_size[s.sizeclass].nmalloc += uint64(s.ref)
+			memstats.alloc += uint64(s.ref) * uint64(s.elemsize)
+		}
+	}
+	unlock(&mheap_.lock)
+
+	// Aggregate by size class.
+	smallfree := uint64(0)
+	memstats.nfree = mheap_.nlargefree
+	for i := 0; i < len(memstats.by_size); i++ {
+		memstats.nfree += mheap_.nsmallfree[i]
+		memstats.by_size[i].nfree = mheap_.nsmallfree[i]
+		memstats.by_size[i].nmalloc += mheap_.nsmallfree[i]
+		smallfree += uint64(mheap_.nsmallfree[i]) * uint64(class_to_size[i])
+	}
+	memstats.nfree += memstats.tinyallocs
+	memstats.nmalloc += memstats.nfree
+
+	// Calculate derived stats.
+	memstats.total_alloc = uint64(memstats.alloc) + uint64(mheap_.largefree) + smallfree
+	memstats.heap_alloc = memstats.alloc
+	memstats.heap_objects = memstats.nmalloc - memstats.nfree
+}
+
+//go:nowritebarrier
+func cachestats() {
+	for i := 0; ; i++ {
+		p := allp[i]
+		if p == nil {
+			break
+		}
+		c := p.mcache
+		if c == nil {
+			continue
+		}
+		purgecachedstats(c)
+	}
+}
+
+//go:nowritebarrier
+func flushallmcaches() {
+	for i := 0; ; i++ {
+		p := allp[i]
+		if p == nil {
+			break
+		}
+		c := p.mcache
+		if c == nil {
+			continue
+		}
+		mCache_ReleaseAll(c)
+		stackcache_clear(c)
+	}
+}
+
+//go:nosplit
+func purgecachedstats(c *mcache) {
+	// Protected by either heap or GC lock.
+	h := &mheap_
+	memstats.heap_live += uint64(c.local_cachealloc)
+	c.local_cachealloc = 0
+	if trace.enabled {
+		traceHeapAlloc()
+	}
+	memstats.heap_scan += uint64(c.local_scan)
+	c.local_scan = 0
+	memstats.tinyallocs += uint64(c.local_tinyallocs)
+	c.local_tinyallocs = 0
+	memstats.nlookup += uint64(c.local_nlookup)
+	c.local_nlookup = 0
+	h.largefree += uint64(c.local_largefree)
+	c.local_largefree = 0
+	h.nlargefree += uint64(c.local_nlargefree)
+	c.local_nlargefree = 0
+	for i := 0; i < len(c.local_nsmallfree); i++ {
+		h.nsmallfree[i] += uint64(c.local_nsmallfree[i])
+		c.local_nsmallfree[i] = 0
+	}
+}
+
+// Atomically increases a given *system* memory stat.  We are counting on this
+// stat never overflowing a uintptr, so this function must only be used for
+// system memory stats.
+//
+// The current implementation for little endian architectures is based on
+// xadduintptr(), which is less than ideal: xadd64() should really be used.
+// Using xadduintptr() is a stop-gap solution until arm supports xadd64() that
+// doesn't use locks.  (Locks are a problem as they require a valid G, which
+// restricts their useability.)
+//
+// A side-effect of using xadduintptr() is that we need to check for
+// overflow errors.
+//go:nosplit
+func mSysStatInc(sysStat *uint64, n uintptr) {
+	if _BigEndian != 0 {
+		xadd64(sysStat, int64(n))
+		return
+	}
+	if val := xadduintptr((*uintptr)(unsafe.Pointer(sysStat)), n); val < n {
+		print("runtime: stat overflow: val ", val, ", n ", n, "\n")
+		exit(2)
+	}
+}
+
+// Atomically decreases a given *system* memory stat.  Same comments as
+// mSysStatInc apply.
+//go:nosplit
+func mSysStatDec(sysStat *uint64, n uintptr) {
+	if _BigEndian != 0 {
+		xadd64(sysStat, -int64(n))
+		return
+	}
+	if val := xadduintptr((*uintptr)(unsafe.Pointer(sysStat)), uintptr(-int64(n))); val+n < n {
+		print("runtime: stat underflow: val ", val, ", n ", n, "\n")
+		exit(2)
+	}
+}
diff --git a/src/runtime/netpoll.go b/src/runtime/netpoll.go
index 3456e02..7c6e3fa 100644
--- a/src/runtime/netpoll.go
+++ b/src/runtime/netpoll.go
@@ -46,17 +46,17 @@ type pollDesc struct {
 	// in a lock-free way by all operations.
 	// NOTE(dvyukov): the following code uses uintptr to store *g (rg/wg),
 	// that will blow up when GC starts moving objects.
-	lock    mutex // protectes the following fields
+	lock    mutex // protects the following fields
 	fd      uintptr
 	closing bool
-	seq     uintptr        // protects from stale timers and ready notifications
-	rg      uintptr        // pdReady, pdWait, G waiting for read or nil
-	rt      timer          // read deadline timer (set if rt.f != nil)
-	rd      int64          // read deadline
-	wg      uintptr        // pdReady, pdWait, G waiting for write or nil
-	wt      timer          // write deadline timer
-	wd      int64          // write deadline
-	user    unsafe.Pointer // user settable cookie
+	seq     uintptr // protects from stale timers and ready notifications
+	rg      uintptr // pdReady, pdWait, G waiting for read or nil
+	rt      timer   // read deadline timer (set if rt.f != nil)
+	rd      int64   // read deadline
+	wg      uintptr // pdReady, pdWait, G waiting for write or nil
+	wt      timer   // write deadline timer
+	wd      int64   // write deadline
+	user    uint32  // user settable cookie
 }
 
 type pollCache struct {
@@ -69,20 +69,30 @@ type pollCache struct {
 	// seq is incremented when deadlines are changed or descriptor is reused.
 }
 
-var pollcache pollCache
+var (
+	netpollInited uint32
+	pollcache     pollCache
+)
+
+//go:linkname net_runtime_pollServerInit net.runtime_pollServerInit
+func net_runtime_pollServerInit() {
+	netpollinit()
+	atomicstore(&netpollInited, 1)
+}
 
-func netpollServerInit() {
-	onM(netpollinit)
+func netpollinited() bool {
+	return atomicload(&netpollInited) != 0
 }
 
-func netpollOpen(fd uintptr) (*pollDesc, int) {
+//go:linkname net_runtime_pollOpen net.runtime_pollOpen
+func net_runtime_pollOpen(fd uintptr) (*pollDesc, int) {
 	pd := pollcache.alloc()
 	lock(&pd.lock)
 	if pd.wg != 0 && pd.wg != pdReady {
-		gothrow("netpollOpen: blocked write on free descriptor")
+		throw("netpollOpen: blocked write on free descriptor")
 	}
 	if pd.rg != 0 && pd.rg != pdReady {
-		gothrow("netpollOpen: blocked read on free descriptor")
+		throw("netpollOpen: blocked read on free descriptor")
 	}
 	pd.fd = fd
 	pd.closing = false
@@ -94,25 +104,22 @@ func netpollOpen(fd uintptr) (*pollDesc, int) {
 	unlock(&pd.lock)
 
 	var errno int32
-	onM(func() {
-		errno = netpollopen(fd, pd)
-	})
+	errno = netpollopen(fd, pd)
 	return pd, int(errno)
 }
 
-func netpollClose(pd *pollDesc) {
+//go:linkname net_runtime_pollClose net.runtime_pollClose
+func net_runtime_pollClose(pd *pollDesc) {
 	if !pd.closing {
-		gothrow("netpollClose: close w/o unblock")
+		throw("netpollClose: close w/o unblock")
 	}
 	if pd.wg != 0 && pd.wg != pdReady {
-		gothrow("netpollClose: blocked write on closing descriptor")
+		throw("netpollClose: blocked write on closing descriptor")
 	}
 	if pd.rg != 0 && pd.rg != pdReady {
-		gothrow("netpollClose: blocked read on closing descriptor")
+		throw("netpollClose: blocked read on closing descriptor")
 	}
-	onM(func() {
-		netpollclose(uintptr(pd.fd))
-	})
+	netpollclose(uintptr(pd.fd))
 	pollcache.free(pd)
 }
 
@@ -123,7 +130,8 @@ func (c *pollCache) free(pd *pollDesc) {
 	unlock(&c.lock)
 }
 
-func netpollReset(pd *pollDesc, mode int) int {
+//go:linkname net_runtime_pollReset net.runtime_pollReset
+func net_runtime_pollReset(pd *pollDesc, mode int) int {
 	err := netpollcheckerr(pd, int32(mode))
 	if err != 0 {
 		return err
@@ -136,16 +144,15 @@ func netpollReset(pd *pollDesc, mode int) int {
 	return 0
 }
 
-func netpollWait(pd *pollDesc, mode int) int {
+//go:linkname net_runtime_pollWait net.runtime_pollWait
+func net_runtime_pollWait(pd *pollDesc, mode int) int {
 	err := netpollcheckerr(pd, int32(mode))
 	if err != 0 {
 		return err
 	}
 	// As for now only Solaris uses level-triggered IO.
 	if GOOS == "solaris" {
-		onM(func() {
-			netpollarm(pd, mode)
-		})
+		netpollarm(pd, mode)
 	}
 	for !netpollblock(pd, int32(mode), false) {
 		err = netpollcheckerr(pd, int32(mode))
@@ -159,14 +166,16 @@ func netpollWait(pd *pollDesc, mode int) int {
 	return 0
 }
 
-func netpollWaitCanceled(pd *pollDesc, mode int) {
+//go:linkname net_runtime_pollWaitCanceled net.runtime_pollWaitCanceled
+func net_runtime_pollWaitCanceled(pd *pollDesc, mode int) {
 	// This function is used only on windows after a failed attempt to cancel
 	// a pending async IO operation. Wait for ioready, ignore closing or timeouts.
 	for !netpollblock(pd, int32(mode), true) {
 	}
 }
 
-func netpollSetDeadline(pd *pollDesc, d int64, mode int) {
+//go:linkname net_runtime_pollSetDeadline net.runtime_pollSetDeadline
+func net_runtime_pollSetDeadline(pd *pollDesc, d int64, mode int) {
 	lock(&pd.lock)
 	if pd.closing {
 		unlock(&pd.lock)
@@ -228,17 +237,18 @@ func netpollSetDeadline(pd *pollDesc, d int64, mode int) {
 	}
 	unlock(&pd.lock)
 	if rg != nil {
-		goready(rg)
+		goready(rg, 3)
 	}
 	if wg != nil {
-		goready(wg)
+		goready(wg, 3)
 	}
 }
 
-func netpollUnblock(pd *pollDesc) {
+//go:linkname net_runtime_pollUnblock net.runtime_pollUnblock
+func net_runtime_pollUnblock(pd *pollDesc) {
 	lock(&pd.lock)
 	if pd.closing {
-		gothrow("netpollUnblock: already closing")
+		throw("netpollUnblock: already closing")
 	}
 	pd.closing = true
 	pd.seq++
@@ -256,48 +266,30 @@ func netpollUnblock(pd *pollDesc) {
 	}
 	unlock(&pd.lock)
 	if rg != nil {
-		goready(rg)
+		goready(rg, 3)
 	}
 	if wg != nil {
-		goready(wg)
+		goready(wg, 3)
 	}
 }
 
-func netpollfd(pd *pollDesc) uintptr {
-	return pd.fd
-}
-
-func netpolluser(pd *pollDesc) *unsafe.Pointer {
-	return &pd.user
-}
-
-func netpollclosing(pd *pollDesc) bool {
-	return pd.closing
-}
-
-func netpolllock(pd *pollDesc) {
-	lock(&pd.lock)
-}
-
-func netpollunlock(pd *pollDesc) {
-	unlock(&pd.lock)
-}
-
 // make pd ready, newly runnable goroutines (if any) are returned in rg/wg
-func netpollready(gpp **g, pd *pollDesc, mode int32) {
-	var rg, wg *g
+// May run during STW, so write barriers are not allowed.
+//go:nowritebarrier
+func netpollready(gpp *guintptr, pd *pollDesc, mode int32) {
+	var rg, wg guintptr
 	if mode == 'r' || mode == 'r'+'w' {
-		rg = netpollunblock(pd, 'r', true)
+		rg.set(netpollunblock(pd, 'r', true))
 	}
 	if mode == 'w' || mode == 'r'+'w' {
-		wg = netpollunblock(pd, 'w', true)
+		wg.set(netpollunblock(pd, 'w', true))
 	}
-	if rg != nil {
-		rg.schedlink = *gpp
+	if rg != 0 {
+		rg.ptr().schedlink = *gpp
 		*gpp = rg
 	}
-	if wg != nil {
-		wg.schedlink = *gpp
+	if wg != 0 {
+		wg.ptr().schedlink = *gpp
 		*gpp = wg
 	}
 }
@@ -332,7 +324,7 @@ func netpollblock(pd *pollDesc, mode int32, waitio bool) bool {
 			return true
 		}
 		if old != 0 {
-			gothrow("netpollblock: double wait")
+			throw("netpollblock: double wait")
 		}
 		if casuintptr(gpp, 0, pdWait) {
 			break
@@ -343,13 +335,12 @@ func netpollblock(pd *pollDesc, mode int32, waitio bool) bool {
 	// 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 {
-		f := netpollblockcommit
-		gopark(**(**unsafe.Pointer)(unsafe.Pointer(&f)), unsafe.Pointer(gpp), "IO wait")
+		gopark(netpollblockcommit, unsafe.Pointer(gpp), "IO wait", traceEvGoBlockNet, 5)
 	}
 	// be careful to not lose concurrent READY notification
 	old := xchguintptr(gpp, 0)
 	if old > pdWait {
-		gothrow("netpollblock: corrupted state")
+		throw("netpollblock: corrupted state")
 	}
 	return old == pdReady
 }
@@ -395,7 +386,7 @@ func netpolldeadlineimpl(pd *pollDesc, seq uintptr, read, write bool) {
 	var rg *g
 	if read {
 		if pd.rd <= 0 || pd.rt.f == nil {
-			gothrow("netpolldeadlineimpl: inconsistent read deadline")
+			throw("netpolldeadlineimpl: inconsistent read deadline")
 		}
 		pd.rd = -1
 		atomicstorep(unsafe.Pointer(&pd.rt.f), nil) // full memory barrier between store to rd and load of rg in netpollunblock
@@ -404,7 +395,7 @@ func netpolldeadlineimpl(pd *pollDesc, seq uintptr, read, write bool) {
 	var wg *g
 	if write {
 		if pd.wd <= 0 || pd.wt.f == nil && !read {
-			gothrow("netpolldeadlineimpl: inconsistent write deadline")
+			throw("netpolldeadlineimpl: inconsistent write deadline")
 		}
 		pd.wd = -1
 		atomicstorep(unsafe.Pointer(&pd.wt.f), nil) // full memory barrier between store to wd and load of wg in netpollunblock
@@ -412,10 +403,10 @@ func netpolldeadlineimpl(pd *pollDesc, seq uintptr, read, write bool) {
 	}
 	unlock(&pd.lock)
 	if rg != nil {
-		goready(rg)
+		goready(rg, 0)
 	}
 	if wg != nil {
-		goready(wg)
+		goready(wg, 0)
 	}
 }
 
diff --git a/src/runtime/netpoll_epoll.go b/src/runtime/netpoll_epoll.go
index ecfc9cd..7b4052a 100644
--- a/src/runtime/netpoll_epoll.go
+++ b/src/runtime/netpoll_epoll.go
@@ -34,7 +34,7 @@ func netpollinit() {
 		return
 	}
 	println("netpollinit: failed to create epoll descriptor", -epfd)
-	gothrow("netpollinit: failed to create descriptor")
+	throw("netpollinit: failed to create descriptor")
 }
 
 func netpollopen(fd uintptr, pd *pollDesc) int32 {
@@ -50,14 +50,14 @@ func netpollclose(fd uintptr) int32 {
 }
 
 func netpollarm(pd *pollDesc, mode int) {
-	gothrow("unused")
+	throw("unused")
 }
 
 // polls for ready network connections
 // returns list of goroutines that become runnable
-func netpoll(block bool) (gp *g) {
+func netpoll(block bool) *g {
 	if epfd == -1 {
-		return
+		return nil
 	}
 	waitms := int32(-1)
 	if !block {
@@ -73,6 +73,7 @@ retry:
 		}
 		goto retry
 	}
+	var gp guintptr
 	for i := int32(0); i < n; i++ {
 		ev := &events[i]
 		if ev.events == 0 {
@@ -87,11 +88,12 @@ retry:
 		}
 		if mode != 0 {
 			pd := *(**pollDesc)(unsafe.Pointer(&ev.data))
-			netpollready((**g)(noescape(unsafe.Pointer(&gp))), pd, mode)
+
+			netpollready(&gp, pd, mode)
 		}
 	}
-	if block && gp == nil {
+	if block && gp == 0 {
 		goto retry
 	}
-	return gp
+	return gp.ptr()
 }
diff --git a/src/runtime/netpoll_kqueue.go b/src/runtime/netpoll_kqueue.go
index d6d55b9..01445dc 100644
--- a/src/runtime/netpoll_kqueue.go
+++ b/src/runtime/netpoll_kqueue.go
@@ -25,7 +25,7 @@ func netpollinit() {
 	kq = kqueue()
 	if kq < 0 {
 		println("netpollinit: kqueue failed with", -kq)
-		gothrow("netpollinit: kqueue failed")
+		throw("netpollinit: kqueue failed")
 	}
 	closeonexec(kq)
 }
@@ -57,14 +57,14 @@ func netpollclose(fd uintptr) int32 {
 }
 
 func netpollarm(pd *pollDesc, mode int) {
-	gothrow("unused")
+	throw("unused")
 }
 
 // Polls for ready network connections.
 // Returns list of goroutines that become runnable.
-func netpoll(block bool) (gp *g) {
+func netpoll(block bool) *g {
 	if kq == -1 {
-		return
+		return nil
 	}
 	var tp *timespec
 	var ts timespec
@@ -81,6 +81,7 @@ retry:
 		}
 		goto retry
 	}
+	var gp guintptr
 	for i := 0; i < int(n); i++ {
 		ev := &events[i]
 		var mode int32
@@ -91,11 +92,11 @@ retry:
 			mode += 'w'
 		}
 		if mode != 0 {
-			netpollready((**g)(noescape(unsafe.Pointer(&gp))), (*pollDesc)(unsafe.Pointer(ev.udata)), mode)
+			netpollready(&gp, (*pollDesc)(unsafe.Pointer(ev.udata)), mode)
 		}
 	}
-	if block && gp == nil {
+	if block && gp == 0 {
 		goto retry
 	}
-	return gp
+	return gp.ptr()
 }
diff --git a/src/runtime/netpoll_solaris.c b/src/runtime/netpoll_solaris.c
deleted file mode 100644
index d422719..0000000
--- a/src/runtime/netpoll_solaris.c
+++ /dev/null
@@ -1,264 +0,0 @@
-// 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 "runtime.h"
-#include "arch_GOARCH.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-
-// Solaris runtime-integrated network poller.
-// 
-// Solaris uses event ports for scalable network I/O. Event
-// ports are level-triggered, unlike epoll and kqueue which
-// can be configured in both level-triggered and edge-triggered
-// mode. Level triggering means we have to keep track of a few things
-// ourselves. After we receive an event for a file descriptor,
-// it's our responsibility to ask again to be notified for future
-// events for that descriptor. When doing this we must keep track of
-// what kind of events the goroutines are currently interested in,
-// for example a fd may be open both for reading and writing.
-// 
-// A description of the high level operation of this code
-// follows. Networking code will get a file descriptor by some means
-// and will register it with the netpolling mechanism by a code path
-// that eventually calls runtime·netpollopen. runtime·netpollopen
-// calls port_associate with an empty event set. That means that we
-// will not receive any events at this point. The association needs
-// to be done at this early point because we need to process the I/O
-// readiness notification at some point in the future. If I/O becomes
-// ready when nobody is listening, when we finally care about it,
-// nobody will tell us anymore.
-// 
-// Beside calling runtime·netpollopen, the networking code paths
-// will call runtime·netpollarm each time goroutines are interested
-// in doing network I/O. Because now we know what kind of I/O we
-// are interested in (reading/writting), we can call port_associate
-// passing the correct type of event set (POLLIN/POLLOUT). As we made
-// sure to have already associated the file descriptor with the port,
-// when we now call port_associate, we will unblock the main poller
-// loop (in runtime·netpoll) right away if the socket is actually
-// ready for I/O.
-// 
-// The main poller loop runs in its own thread waiting for events
-// using port_getn. When an event happens, it will tell the scheduler
-// about it using runtime·netpollready. Besides doing this, it must
-// also re-associate the events that were not part of this current
-// notification with the file descriptor. Failing to do this would
-// mean each notification will prevent concurrent code using the
-// same file descriptor in parallel.
-// 
-// The logic dealing with re-associations is encapsulated in
-// runtime·netpollupdate. This function takes care to associate the
-// descriptor only with the subset of events that were previously
-// part of the association, except the one that just happened. We
-// can't re-associate with that right away, because event ports
-// are level triggered so it would cause a busy loop. Instead, that
-// association is effected only by the runtime·netpollarm code path,
-// when Go code actually asks for I/O.
-// 
-// The open and arming mechanisms are serialized using the lock
-// inside PollDesc. This is required because the netpoll loop runs
-// asynchonously in respect to other Go code and by the time we get
-// to call port_associate to update the association in the loop, the
-// file descriptor might have been closed and reopened already. The
-// lock allows runtime·netpollupdate to be called synchronously from
-// the loop thread while preventing other threads operating to the
-// same PollDesc, so once we unblock in the main loop, until we loop
-// again we know for sure we are always talking about the same file
-// descriptor and can safely access the data we want (the event set).
-
-#pragma dynimport libc·fcntl fcntl "libc.so"
-#pragma dynimport libc·port_create port_create "libc.so"
-#pragma dynimport libc·port_associate port_associate "libc.so"
-#pragma dynimport libc·port_dissociate port_dissociate "libc.so"
-#pragma dynimport libc·port_getn port_getn "libc.so"
-extern uintptr libc·fcntl;
-extern uintptr libc·port_create;
-extern uintptr libc·port_associate;
-extern uintptr libc·port_dissociate;
-extern uintptr libc·port_getn;
-
-#define errno (*g->m->perrno)
-
-int32
-runtime·fcntl(int32 fd, int32 cmd, uintptr arg)
-{
-	return runtime·sysvicall3(libc·fcntl, (uintptr)fd, (uintptr)cmd, (uintptr)arg);
-}
-
-int32
-runtime·port_create(void)
-{
-	return runtime·sysvicall0(libc·port_create);
-}
-
-int32
-runtime·port_associate(int32 port, int32 source, uintptr object, int32 events, uintptr user)
-{
-	return runtime·sysvicall5(libc·port_associate, (uintptr)port, (uintptr)source, object, (uintptr)events, user);
-}
-
-int32
-runtime·port_dissociate(int32 port, int32 source, uintptr object)
-{
-	return runtime·sysvicall3(libc·port_dissociate, (uintptr)port, (uintptr)source, object);
-}
-
-int32
-runtime·port_getn(int32 port, PortEvent *evs, uint32 max, uint32 *nget, Timespec *timeout)
-{
-	return runtime·sysvicall5(libc·port_getn, (uintptr)port, (uintptr)evs, (uintptr)max, (uintptr)nget, (uintptr)timeout);
-}
-
-static int32 portfd = -1;
-
-void
-runtime·netpollinit(void)
-{
-	if((portfd = runtime·port_create()) >= 0) {
-		runtime·fcntl(portfd, F_SETFD, FD_CLOEXEC);
-		return;
-	}
-
-	runtime·printf("netpollinit: failed to create port (%d)\n", errno);
-	runtime·throw("netpollinit: failed to create port");
-}
-
-int32
-runtime·netpollopen(uintptr fd, PollDesc *pd)
-{
-	int32 r;
-
-	runtime·netpolllock(pd);
-	// We don't register for any specific type of events yet, that's
-	// netpollarm's job. We merely ensure we call port_associate before
-	// asynchonous connect/accept completes, so when we actually want
-	// to do any I/O, the call to port_associate (from netpollarm,
-	// with the interested event set) will unblock port_getn right away
-	// because of the I/O readiness notification.
-	*runtime·netpolluser(pd) = 0;
-	r = runtime·port_associate(portfd, PORT_SOURCE_FD, fd, 0, (uintptr)pd);
-	runtime·netpollunlock(pd);
-	return r;
-}
-
-int32
-runtime·netpollclose(uintptr fd)
-{
-	return runtime·port_dissociate(portfd, PORT_SOURCE_FD, fd);
-}
-
-// Updates the association with a new set of interested events. After
-// this call, port_getn will return one and only one event for that
-// particular descriptor, so this function needs to be called again.
-void
-runtime·netpollupdate(PollDesc* pd, uint32 set, uint32 clear)
-{
-	uint32 *ep, old, events;
-	uintptr fd = runtime·netpollfd(pd);
-	ep = (uint32*)runtime·netpolluser(pd);
-
-	if(runtime·netpollclosing(pd))
-		return;
-
-	old = *ep;
-	events = (old & ~clear) | set;
-	if(old == events)
-		return;
-
-	if(events && runtime·port_associate(portfd, PORT_SOURCE_FD, fd, events, (uintptr)pd) != 0) {
-		runtime·printf("netpollupdate: failed to associate (%d)\n", errno);
-		runtime·throw("netpollupdate: failed to associate");
-	} 
-	*ep = events;
-}
-
-// subscribe the fd to the port such that port_getn will return one event.
-void
-runtime·netpollarm(PollDesc* pd, int32 mode)
-{
-	runtime·netpolllock(pd);
-	switch(mode) {
-	case 'r':
-		runtime·netpollupdate(pd, POLLIN, 0);
-		break;
-	case 'w':
-		runtime·netpollupdate(pd, POLLOUT, 0);
-		break;
-	default:
-		runtime·throw("netpollarm: bad mode");
-	}
-	runtime·netpollunlock(pd);
-}
-
-// polls for ready network connections
-// returns list of goroutines that become runnable
-G*
-runtime·netpoll(bool block)
-{
-	static int32 lasterr;
-	PortEvent events[128], *ev;
-	PollDesc *pd;
-	int32 i, mode, clear;
-	uint32 n;
-	Timespec *wait = nil, zero;
-	G *gp;
-
-	if(portfd == -1)
-		return (nil);
-
-	if(!block) {
-		zero.tv_sec = 0;
-		zero.tv_nsec = 0;
-		wait = &zero;
-	}
-
-retry:
-	n = 1;
-	if(runtime·port_getn(portfd, events, nelem(events), &n, wait) < 0) {
-		if(errno != EINTR && errno != lasterr) {
-			lasterr = errno;
-			runtime·printf("runtime: port_getn on fd %d failed with %d\n", portfd, errno);
-		}
-		goto retry;
-	}
-
-	gp = nil;
-	for(i = 0; i < n; i++) {
-		ev = &events[i];
-
-		if(ev->portev_events == 0)
-			continue;
-		pd = (PollDesc *)ev->portev_user;
-
-		mode = 0;
-		clear = 0;
-		if(ev->portev_events & (POLLIN|POLLHUP|POLLERR)) {
-			mode += 'r';
-			clear |= POLLIN;
-		}
-		if(ev->portev_events & (POLLOUT|POLLHUP|POLLERR)) {
-			mode += 'w';
-			clear |= POLLOUT;
-		}
-		// To effect edge-triggered events, we need to be sure to
-		// update our association with whatever events were not
-		// set with the event. For example if we are registered
-		// for POLLIN|POLLOUT, and we get POLLIN, besides waking
-		// the goroutine interested in POLLIN we have to not forget
-		// about the one interested in POLLOUT.
-		if(clear != 0) {
-			runtime·netpolllock(pd);
-			runtime·netpollupdate(pd, 0, clear);
-			runtime·netpollunlock(pd);
-		}
-
-		if(mode)
-			runtime·netpollready(&gp, pd, mode);
-	}
-
-	if(block && gp == nil)
-		goto retry;
-	return gp;
-}
diff --git a/src/runtime/netpoll_solaris.go b/src/runtime/netpoll_solaris.go
new file mode 100644
index 0000000..e4652d8
--- /dev/null
+++ b/src/runtime/netpoll_solaris.go
@@ -0,0 +1,243 @@
+// 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"
+
+// Solaris runtime-integrated network poller.
+//
+// Solaris uses event ports for scalable network I/O. Event
+// ports are level-triggered, unlike epoll and kqueue which
+// can be configured in both level-triggered and edge-triggered
+// mode. Level triggering means we have to keep track of a few things
+// ourselves. After we receive an event for a file descriptor,
+// it's our responsibility to ask again to be notified for future
+// events for that descriptor. When doing this we must keep track of
+// what kind of events the goroutines are currently interested in,
+// for example a fd may be open both for reading and writing.
+//
+// A description of the high level operation of this code
+// follows. Networking code will get a file descriptor by some means
+// and will register it with the netpolling mechanism by a code path
+// that eventually calls runtime·netpollopen. runtime·netpollopen
+// calls port_associate with an empty event set. That means that we
+// will not receive any events at this point. The association needs
+// to be done at this early point because we need to process the I/O
+// readiness notification at some point in the future. If I/O becomes
+// ready when nobody is listening, when we finally care about it,
+// nobody will tell us anymore.
+//
+// Beside calling runtime·netpollopen, the networking code paths
+// will call runtime·netpollarm each time goroutines are interested
+// in doing network I/O. Because now we know what kind of I/O we
+// are interested in (reading/writing), we can call port_associate
+// passing the correct type of event set (POLLIN/POLLOUT). As we made
+// sure to have already associated the file descriptor with the port,
+// when we now call port_associate, we will unblock the main poller
+// loop (in runtime·netpoll) right away if the socket is actually
+// ready for I/O.
+//
+// The main poller loop runs in its own thread waiting for events
+// using port_getn. When an event happens, it will tell the scheduler
+// about it using runtime·netpollready. Besides doing this, it must
+// also re-associate the events that were not part of this current
+// notification with the file descriptor. Failing to do this would
+// mean each notification will prevent concurrent code using the
+// same file descriptor in parallel.
+//
+// The logic dealing with re-associations is encapsulated in
+// runtime·netpollupdate. This function takes care to associate the
+// descriptor only with the subset of events that were previously
+// part of the association, except the one that just happened. We
+// can't re-associate with that right away, because event ports
+// are level triggered so it would cause a busy loop. Instead, that
+// association is effected only by the runtime·netpollarm code path,
+// when Go code actually asks for I/O.
+//
+// The open and arming mechanisms are serialized using the lock
+// inside PollDesc. This is required because the netpoll loop runs
+// asynchonously in respect to other Go code and by the time we get
+// to call port_associate to update the association in the loop, the
+// file descriptor might have been closed and reopened already. The
+// lock allows runtime·netpollupdate to be called synchronously from
+// the loop thread while preventing other threads operating to the
+// same PollDesc, so once we unblock in the main loop, until we loop
+// again we know for sure we are always talking about the same file
+// descriptor and can safely access the data we want (the event set).
+
+//go:cgo_import_dynamic libc_port_create port_create "libc.so"
+//go:cgo_import_dynamic libc_port_associate port_associate "libc.so"
+//go:cgo_import_dynamic libc_port_dissociate port_dissociate "libc.so"
+//go:cgo_import_dynamic libc_port_getn port_getn "libc.so"
+
+//go:linkname libc_port_create libc_port_create
+//go:linkname libc_port_associate libc_port_associate
+//go:linkname libc_port_dissociate libc_port_dissociate
+//go:linkname libc_port_getn libc_port_getn
+
+var (
+	libc_port_create,
+	libc_port_associate,
+	libc_port_dissociate,
+	libc_port_getn libcFunc
+)
+
+func errno() int32 {
+	return *getg().m.perrno
+}
+
+func fcntl(fd, cmd int32, arg uintptr) int32 {
+	return int32(sysvicall3(&libc_fcntl, uintptr(fd), uintptr(cmd), arg))
+}
+
+func port_create() int32 {
+	return int32(sysvicall0(&libc_port_create))
+}
+
+func port_associate(port, source int32, object uintptr, events uint32, user uintptr) int32 {
+	return int32(sysvicall5(&libc_port_associate, uintptr(port), uintptr(source), object, uintptr(events), user))
+}
+
+func port_dissociate(port, source int32, object uintptr) int32 {
+	return int32(sysvicall3(&libc_port_dissociate, uintptr(port), uintptr(source), object))
+}
+
+func port_getn(port int32, evs *portevent, max uint32, nget *uint32, timeout *timespec) int32 {
+	return int32(sysvicall5(&libc_port_getn, uintptr(port), uintptr(unsafe.Pointer(evs)), uintptr(max), uintptr(unsafe.Pointer(nget)), uintptr(unsafe.Pointer(timeout))))
+}
+
+var portfd int32 = -1
+
+func netpollinit() {
+	portfd = port_create()
+	if portfd >= 0 {
+		fcntl(portfd, _F_SETFD, _FD_CLOEXEC)
+		return
+	}
+
+	print("netpollinit: failed to create port (", errno(), ")\n")
+	throw("netpollinit: failed to create port")
+}
+
+func netpollopen(fd uintptr, pd *pollDesc) int32 {
+	lock(&pd.lock)
+	// We don't register for any specific type of events yet, that's
+	// netpollarm's job. We merely ensure we call port_associate before
+	// asynchonous connect/accept completes, so when we actually want
+	// to do any I/O, the call to port_associate (from netpollarm,
+	// with the interested event set) will unblock port_getn right away
+	// because of the I/O readiness notification.
+	pd.user = 0
+	r := port_associate(portfd, _PORT_SOURCE_FD, fd, 0, uintptr(unsafe.Pointer(pd)))
+	unlock(&pd.lock)
+	return r
+}
+
+func netpollclose(fd uintptr) int32 {
+	return port_dissociate(portfd, _PORT_SOURCE_FD, fd)
+}
+
+// Updates the association with a new set of interested events. After
+// this call, port_getn will return one and only one event for that
+// particular descriptor, so this function needs to be called again.
+func netpollupdate(pd *pollDesc, set, clear uint32) {
+	if pd.closing {
+		return
+	}
+
+	old := pd.user
+	events := (old & ^clear) | set
+	if old == events {
+		return
+	}
+
+	if events != 0 && port_associate(portfd, _PORT_SOURCE_FD, pd.fd, events, uintptr(unsafe.Pointer(pd))) != 0 {
+		print("netpollupdate: failed to associate (", errno(), ")\n")
+		throw("netpollupdate: failed to associate")
+	}
+	pd.user = events
+}
+
+// subscribe the fd to the port such that port_getn will return one event.
+func netpollarm(pd *pollDesc, mode int) {
+	lock(&pd.lock)
+	switch mode {
+	case 'r':
+		netpollupdate(pd, _POLLIN, 0)
+	case 'w':
+		netpollupdate(pd, _POLLOUT, 0)
+	default:
+		throw("netpollarm: bad mode")
+	}
+	unlock(&pd.lock)
+}
+
+// netpolllasterr holds the last error code returned by port_getn to prevent log spamming
+var netpolllasterr int32
+
+// polls for ready network connections
+// returns list of goroutines that become runnable
+func netpoll(block bool) *g {
+	if portfd == -1 {
+		return nil
+	}
+
+	var wait *timespec
+	var zero timespec
+	if !block {
+		wait = &zero
+	}
+
+	var events [128]portevent
+retry:
+	var n uint32 = 1
+	if port_getn(portfd, &events[0], uint32(len(events)), &n, wait) < 0 {
+		if e := errno(); e != _EINTR && e != netpolllasterr {
+			netpolllasterr = e
+			print("runtime: port_getn on fd ", portfd, " failed with ", e, "\n")
+		}
+		goto retry
+	}
+
+	var gp guintptr
+	for i := 0; i < int(n); i++ {
+		ev := &events[i]
+
+		if ev.portev_events == 0 {
+			continue
+		}
+		pd := (*pollDesc)(unsafe.Pointer(ev.portev_user))
+
+		var mode, clear int32
+		if (ev.portev_events & (_POLLIN | _POLLHUP | _POLLERR)) != 0 {
+			mode += 'r'
+			clear |= _POLLIN
+		}
+		if (ev.portev_events & (_POLLOUT | _POLLHUP | _POLLERR)) != 0 {
+			mode += 'w'
+			clear |= _POLLOUT
+		}
+		// To effect edge-triggered events, we need to be sure to
+		// update our association with whatever events were not
+		// set with the event. For example if we are registered
+		// for POLLIN|POLLOUT, and we get POLLIN, besides waking
+		// the goroutine interested in POLLIN we have to not forget
+		// about the one interested in POLLOUT.
+		if clear != 0 {
+			lock(&pd.lock)
+			netpollupdate(pd, 0, uint32(clear))
+			unlock(&pd.lock)
+		}
+
+		if mode != 0 {
+			netpollready(&gp, pd, mode)
+		}
+	}
+
+	if block && gp == 0 {
+		goto retry
+	}
+	return gp.ptr()
+}
diff --git a/src/runtime/netpoll_stub.c b/src/runtime/netpoll_stub.c
deleted file mode 100644
index b7a8f29..0000000
--- a/src/runtime/netpoll_stub.c
+++ /dev/null
@@ -1,18 +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.
-
-// +build plan9
-
-#include "runtime.h"
-
-// Polls for ready network connections.
-// Returns list of goroutines that become runnable.
-G*
-runtime·netpoll(bool block)
-{
-	// Implementation for platforms that do not support
-	// integrated network poller.
-	USED(block);
-	return nil;
-}
diff --git a/src/runtime/netpoll_stub.go b/src/runtime/netpoll_stub.go
new file mode 100644
index 0000000..09f64ad
--- /dev/null
+++ b/src/runtime/netpoll_stub.go
@@ -0,0 +1,19 @@
+// 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 plan9
+
+package runtime
+
+// Polls for ready network connections.
+// Returns list of goroutines that become runnable.
+func netpoll(block bool) (gp *g) {
+	// Implementation for platforms that do not support
+	// integrated network poller.
+	return
+}
+
+func netpollinited() bool {
+	return false
+}
diff --git a/src/runtime/netpoll_windows.c b/src/runtime/netpoll_windows.c
deleted file mode 100644
index 64da41a..0000000
--- a/src/runtime/netpoll_windows.c
+++ /dev/null
@@ -1,163 +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.
-
-#include "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-
-#define DWORD_MAX 0xffffffff
-
-#pragma dynimport runtime·CreateIoCompletionPort CreateIoCompletionPort "kernel32.dll"
-#pragma dynimport runtime·GetQueuedCompletionStatus GetQueuedCompletionStatus "kernel32.dll"
-#pragma dynimport runtime·WSAGetOverlappedResult WSAGetOverlappedResult "ws2_32.dll"
-
-extern void *runtime·CreateIoCompletionPort;
-extern void *runtime·GetQueuedCompletionStatus;
-extern void *runtime·WSAGetOverlappedResult;
-
-#define INVALID_HANDLE_VALUE ((uintptr)-1)
-
-// net_op must be the same as beginning of net.operation. Keep these in sync.
-typedef struct net_op net_op;
-struct net_op
-{
-	// used by windows
-	Overlapped	o;
-	// used by netpoll
-	PollDesc*	pd;
-	int32	mode;
-	int32	errno;
-	uint32	qty;
-};
-
-typedef struct OverlappedEntry OverlappedEntry;
-struct OverlappedEntry
-{
-	uintptr	key;
-	net_op*	op;  // In reality it's Overlapped*, but we cast it to net_op* anyway.
-	uintptr	internal;
-	uint32	qty;
-};
-
-static void handlecompletion(G **gpp, net_op *o, int32 errno, uint32 qty);
-
-static uintptr iocphandle = INVALID_HANDLE_VALUE;  // completion port io handle
-
-void
-runtime·netpollinit(void)
-{
-	iocphandle = (uintptr)runtime·stdcall4(runtime·CreateIoCompletionPort, INVALID_HANDLE_VALUE, 0, 0, DWORD_MAX);
-	if(iocphandle == 0) {
-		runtime·printf("netpoll: failed to create iocp handle (errno=%d)\n", runtime·getlasterror());
-		runtime·throw("netpoll: failed to create iocp handle");
-	}
-	return;
-}
-
-int32
-runtime·netpollopen(uintptr fd, PollDesc *pd)
-{
-	USED(pd);
-	if(runtime·stdcall4(runtime·CreateIoCompletionPort, fd, iocphandle, 0, 0) == 0)
-		return -runtime·getlasterror();
-	return 0;
-}
-
-int32
-runtime·netpollclose(uintptr fd)
-{
-	// nothing to do
-	USED(fd);
-	return 0;
-}
-
-void
-runtime·netpollarm(PollDesc* pd, int32 mode)
-{
-	USED(pd, mode);
-	runtime·throw("unused");
-}
-
-// Polls for completed network IO.
-// Returns list of goroutines that become runnable.
-G*
-runtime·netpoll(bool block)
-{
-	OverlappedEntry entries[64];
-	uint32 wait, qty, key, flags, n, i;
-	int32 errno;
-	net_op *op;
-	G *gp;
-
-	if(iocphandle == INVALID_HANDLE_VALUE)
-		return nil;
-	gp = nil;
-	wait = 0;
-	if(block)
-		wait = INFINITE;
-retry:
-	if(runtime·GetQueuedCompletionStatusEx != nil) {
-		n = nelem(entries) / runtime·gomaxprocs;
-		if(n < 8)
-			n = 8;
-		if(block)
-			g->m->blocked = true;
-		if(runtime·stdcall6(runtime·GetQueuedCompletionStatusEx, iocphandle, (uintptr)entries, n, (uintptr)&n, wait, 0) == 0) {
-			g->m->blocked = false;
-			errno = runtime·getlasterror();
-			if(!block && errno == WAIT_TIMEOUT)
-				return nil;
-			runtime·printf("netpoll: GetQueuedCompletionStatusEx failed (errno=%d)\n", errno);
-			runtime·throw("netpoll: GetQueuedCompletionStatusEx failed");
-		}
-		g->m->blocked = false;
-		for(i = 0; i < n; i++) {
-			op = entries[i].op;
-			errno = 0;
-			qty = 0;
-			if(runtime·stdcall5(runtime·WSAGetOverlappedResult, runtime·netpollfd(op->pd), (uintptr)op, (uintptr)&qty, 0, (uintptr)&flags) == 0)
-				errno = runtime·getlasterror();
-			handlecompletion(&gp, op, errno, qty);
-		}
-	} else {
-		op = nil;
-		errno = 0;
-		qty = 0;
-		if(block)
-			g->m->blocked = true;
-		if(runtime·stdcall5(runtime·GetQueuedCompletionStatus, iocphandle, (uintptr)&qty, (uintptr)&key, (uintptr)&op, wait) == 0) {
-			g->m->blocked = false;
-			errno = runtime·getlasterror();
-			if(!block && errno == WAIT_TIMEOUT)
-				return nil;
-			if(op == nil) {
-				runtime·printf("netpoll: GetQueuedCompletionStatus failed (errno=%d)\n", errno);
-				runtime·throw("netpoll: GetQueuedCompletionStatus failed");
-			}
-			// dequeued failed IO packet, so report that
-		}
-		g->m->blocked = false;
-		handlecompletion(&gp, op, errno, qty);
-	}
-	if(block && gp == nil)
-		goto retry;
-	return gp;
-}
-
-static void
-handlecompletion(G **gpp, net_op *op, int32 errno, uint32 qty)
-{
-	int32 mode;
-
-	if(op == nil)
-		runtime·throw("netpoll: GetQueuedCompletionStatus returned op == nil");
-	mode = op->mode;
-	if(mode != 'r' && mode != 'w') {
-		runtime·printf("netpoll: GetQueuedCompletionStatus returned invalid mode=%d\n", mode);
-		runtime·throw("netpoll: GetQueuedCompletionStatus returned invalid mode");
-	}
-	op->errno = errno;
-	op->qty = qty;
-	runtime·netpollready(gpp, op->pd, mode);
-}
diff --git a/src/runtime/netpoll_windows.go b/src/runtime/netpoll_windows.go
new file mode 100644
index 0000000..7e15cd2
--- /dev/null
+++ b/src/runtime/netpoll_windows.go
@@ -0,0 +1,145 @@
+// 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"
+)
+
+const _DWORD_MAX = 0xffffffff
+
+const _INVALID_HANDLE_VALUE = ^uintptr(0)
+
+// net_op must be the same as beginning of net.operation. Keep these in sync.
+type net_op struct {
+	// used by windows
+	o overlapped
+	// used by netpoll
+	pd    *pollDesc
+	mode  int32
+	errno int32
+	qty   uint32
+}
+
+type overlappedEntry struct {
+	key      uintptr
+	op       *net_op // In reality it's *overlapped, but we cast it to *net_op anyway.
+	internal uintptr
+	qty      uint32
+}
+
+var iocphandle uintptr = _INVALID_HANDLE_VALUE // completion port io handle
+
+func netpollinit() {
+	iocphandle = uintptr(stdcall4(_CreateIoCompletionPort, _INVALID_HANDLE_VALUE, 0, 0, _DWORD_MAX))
+	if iocphandle == 0 {
+		println("netpoll: failed to create iocp handle (errno=", getlasterror(), ")")
+		throw("netpoll: failed to create iocp handle")
+	}
+}
+
+func netpollopen(fd uintptr, pd *pollDesc) int32 {
+	if stdcall4(_CreateIoCompletionPort, fd, iocphandle, 0, 0) == 0 {
+		return -int32(getlasterror())
+	}
+	return 0
+}
+
+func netpollclose(fd uintptr) int32 {
+	// nothing to do
+	return 0
+}
+
+func netpollarm(pd *pollDesc, mode int) {
+	throw("unused")
+}
+
+// Polls for completed network IO.
+// Returns list of goroutines that become runnable.
+func netpoll(block bool) *g {
+	var entries [64]overlappedEntry
+	var wait, qty, key, flags, n, i uint32
+	var errno int32
+	var op *net_op
+	var gp guintptr
+
+	mp := getg().m
+
+	if iocphandle == _INVALID_HANDLE_VALUE {
+		return nil
+	}
+	wait = 0
+	if block {
+		wait = _INFINITE
+	}
+retry:
+	if _GetQueuedCompletionStatusEx != nil {
+		n = uint32(len(entries) / int(gomaxprocs))
+		if n < 8 {
+			n = 8
+		}
+		if block {
+			mp.blocked = true
+		}
+		if stdcall6(_GetQueuedCompletionStatusEx, iocphandle, uintptr(unsafe.Pointer(&entries[0])), uintptr(n), uintptr(unsafe.Pointer(&n)), uintptr(wait), 0) == 0 {
+			mp.blocked = false
+			errno = int32(getlasterror())
+			if !block && errno == _WAIT_TIMEOUT {
+				return nil
+			}
+			println("netpoll: GetQueuedCompletionStatusEx failed (errno=", errno, ")")
+			throw("netpoll: GetQueuedCompletionStatusEx failed")
+		}
+		mp.blocked = false
+		for i = 0; i < n; i++ {
+			op = entries[i].op
+			errno = 0
+			qty = 0
+			if stdcall5(_WSAGetOverlappedResult, op.pd.fd, uintptr(unsafe.Pointer(op)), uintptr(unsafe.Pointer(&qty)), 0, uintptr(unsafe.Pointer(&flags))) == 0 {
+				errno = int32(getlasterror())
+			}
+			handlecompletion(&gp, op, errno, qty)
+		}
+	} else {
+		op = nil
+		errno = 0
+		qty = 0
+		if block {
+			mp.blocked = true
+		}
+		if stdcall5(_GetQueuedCompletionStatus, iocphandle, uintptr(unsafe.Pointer(&qty)), uintptr(unsafe.Pointer(&key)), uintptr(unsafe.Pointer(&op)), uintptr(wait)) == 0 {
+			mp.blocked = false
+			errno = int32(getlasterror())
+			if !block && errno == _WAIT_TIMEOUT {
+				return nil
+			}
+			if op == nil {
+				println("netpoll: GetQueuedCompletionStatus failed (errno=", errno, ")")
+				throw("netpoll: GetQueuedCompletionStatus failed")
+			}
+			// dequeued failed IO packet, so report that
+		}
+		mp.blocked = false
+		handlecompletion(&gp, op, errno, qty)
+	}
+	if block && gp == 0 {
+		goto retry
+	}
+	return gp.ptr()
+}
+
+func handlecompletion(gpp *guintptr, op *net_op, errno int32, qty uint32) {
+	if op == nil {
+		throw("netpoll: GetQueuedCompletionStatus returned op == nil")
+	}
+	mode := op.mode
+	if mode != 'r' && mode != 'w' {
+		println("netpoll: GetQueuedCompletionStatus returned invalid mode=", mode)
+		throw("netpoll: GetQueuedCompletionStatus returned invalid mode")
+	}
+	op.errno = errno
+	op.qty = qty
+	netpollready(gpp, op.pd, mode)
+}
diff --git a/src/runtime/noasm.go b/src/runtime/noasm.go
new file mode 100644
index 0000000..9a6dbee
--- /dev/null
+++ b/src/runtime/noasm.go
@@ -0,0 +1,58 @@
+// 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.
+
+// Routines that are implemented in assembly in asm_{amd64,386,arm,arm64}.s
+
+// +build ppc64 ppc64le
+
+package runtime
+
+import _ "unsafe" // for go:linkname
+
+func cmpstring(s1, s2 string) int {
+	l := len(s1)
+	if len(s2) < l {
+		l = len(s2)
+	}
+	for i := 0; i < l; i++ {
+		c1, c2 := s1[i], s2[i]
+		if c1 < c2 {
+			return -1
+		}
+		if c1 > c2 {
+			return +1
+		}
+	}
+	if len(s1) < len(s2) {
+		return -1
+	}
+	if len(s1) > len(s2) {
+		return +1
+	}
+	return 0
+}
+
+//go:linkname bytes_Compare bytes.Compare
+func bytes_Compare(s1, s2 []byte) int {
+	l := len(s1)
+	if len(s2) < l {
+		l = len(s2)
+	}
+	for i := 0; i < l; i++ {
+		c1, c2 := s1[i], s2[i]
+		if c1 < c2 {
+			return -1
+		}
+		if c1 > c2 {
+			return +1
+		}
+	}
+	if len(s1) < len(s2) {
+		return -1
+	}
+	if len(s1) > len(s2) {
+		return +1
+	}
+	return 0
+}
diff --git a/src/runtime/noasm_arm.go b/src/runtime/noasm_arm.go
deleted file mode 100644
index dd3ef82..0000000
--- a/src/runtime/noasm_arm.go
+++ /dev/null
@@ -1,54 +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.
-
-// Routines that are implemented in assembly in asm_{amd64,386}.s
-// but are implemented in Go for arm.
-
-package runtime
-
-func cmpstring(s1, s2 string) int {
-	l := len(s1)
-	if len(s2) < l {
-		l = len(s2)
-	}
-	for i := 0; i < l; i++ {
-		c1, c2 := s1[i], s2[i]
-		if c1 < c2 {
-			return -1
-		}
-		if c1 > c2 {
-			return +1
-		}
-	}
-	if len(s1) < len(s2) {
-		return -1
-	}
-	if len(s1) > len(s2) {
-		return +1
-	}
-	return 0
-}
-
-func cmpbytes(s1, s2 []byte) int {
-	l := len(s1)
-	if len(s2) < l {
-		l = len(s2)
-	}
-	for i := 0; i < l; i++ {
-		c1, c2 := s1[i], s2[i]
-		if c1 < c2 {
-			return -1
-		}
-		if c1 > c2 {
-			return +1
-		}
-	}
-	if len(s1) < len(s2) {
-		return -1
-	}
-	if len(s1) > len(s2) {
-		return +1
-	}
-	return 0
-}
diff --git a/src/runtime/norace_linux_test.go b/src/runtime/norace_linux_test.go
new file mode 100644
index 0000000..bbf9d0b
--- /dev/null
+++ b/src/runtime/norace_linux_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.
+
+// The file contains tests that can not run under race detector for some reason.
+// +build !race
+
+package runtime_test
+
+import (
+	"runtime"
+	"testing"
+	"time"
+	"unsafe"
+)
+
+var newOSProcDone bool
+
+//go:nosplit
+func newOSProcCreated() {
+	newOSProcDone = true
+}
+
+// Can't be run with -race because it inserts calls into newOSProcCreated()
+// that require a valid G/M.
+func TestNewOSProc0(t *testing.T) {
+	runtime.NewOSProc0(0x800000, unsafe.Pointer(runtime.FuncPC(newOSProcCreated)))
+	check := time.NewTicker(100 * time.Millisecond)
+	defer check.Stop()
+	end := time.After(5 * time.Second)
+	for {
+		select {
+		case <-check.C:
+			if newOSProcDone {
+				return
+			}
+		case <-end:
+			t.Fatalf("couldn't create new OS process")
+		}
+	}
+}
diff --git a/src/runtime/norace_test.go b/src/runtime/norace_test.go
index 3b17187..3681bf1 100644
--- a/src/runtime/norace_test.go
+++ b/src/runtime/norace_test.go
@@ -34,12 +34,12 @@ func benchmarkSyscall(b *testing.B, work, excess int) {
 	b.RunParallel(func(pb *testing.PB) {
 		foo := 42
 		for pb.Next() {
-			runtime.Entersyscall()
+			runtime.Entersyscall(0)
 			for i := 0; i < work; i++ {
 				foo *= 2
 				foo /= 2
 			}
-			runtime.Exitsyscall()
+			runtime.Exitsyscall(0)
 		}
 		_ = foo
 	})
diff --git a/src/runtime/os1_darwin.go b/src/runtime/os1_darwin.go
new file mode 100644
index 0000000..e070229
--- /dev/null
+++ b/src/runtime/os1_darwin.go
@@ -0,0 +1,481 @@
+// 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"
+
+//extern SigTabTT runtime·sigtab[];
+
+var sigset_all = ^uint32(0)
+
+func unimplemented(name string) {
+	println(name, "not implemented")
+	*(*int)(unsafe.Pointer(uintptr(1231))) = 1231
+}
+
+//go:nosplit
+func semawakeup(mp *m) {
+	mach_semrelease(uint32(mp.waitsema))
+}
+
+//go:nosplit
+func semacreate() uintptr {
+	var x uintptr
+	systemstack(func() {
+		x = uintptr(mach_semcreate())
+	})
+	return x
+}
+
+// BSD interface for threading.
+func osinit() {
+	// bsdthread_register delayed until end of goenvs so that we
+	// can look at the environment first.
+
+	ncpu = getncpu()
+}
+
+func getncpu() int32 {
+	// Use sysctl to fetch hw.ncpu.
+	mib := [2]uint32{6, 3}
+	out := uint32(0)
+	nout := unsafe.Sizeof(out)
+	ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
+	if ret >= 0 && int32(out) > 0 {
+		return int32(out)
+	}
+	return 1
+}
+
+var urandom_dev = []byte("/dev/urandom\x00")
+
+//go:nosplit
+func getRandomData(r []byte) {
+	fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
+	n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
+	closefd(fd)
+	extendRandom(r, int(n))
+}
+
+func goenvs() {
+	goenvs_unix()
+
+	// Register our thread-creation callback (see sys_darwin_{amd64,386}.s)
+	// but only if we're not using cgo.  If we are using cgo we need
+	// to let the C pthread library install its own thread-creation callback.
+	if !iscgo {
+		if bsdthread_register() != 0 {
+			if gogetenv("DYLD_INSERT_LIBRARIES") != "" {
+				throw("runtime: bsdthread_register error (unset DYLD_INSERT_LIBRARIES)")
+			}
+			throw("runtime: bsdthread_register error")
+		}
+	}
+}
+
+// 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 {
+		print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " id=", mp.id, "/", int(mp.tls[0]), " ostk=", &mp, "\n")
+	}
+
+	var oset uint32
+	sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
+	errno := bsdthread_create(stk, unsafe.Pointer(mp), funcPC(mstart))
+	sigprocmask(_SIG_SETMASK, &oset, nil)
+
+	if errno < 0 {
+		print("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", -errno, ")\n")
+		throw("runtime.newosproc")
+	}
+}
+
+// newosproc0 is a version of newosproc that can be called before the runtime
+// is initialized.
+//
+// As Go uses bsdthread_register when running without cgo, this function is
+// not safe to use after initialization as it does not pass an M as fnarg.
+//
+//go:nosplit
+func newosproc0(stacksize uintptr, fn unsafe.Pointer, fnarg uintptr) {
+	stack := sysAlloc(stacksize, &memstats.stacks_sys)
+	if stack == nil {
+		write(2, unsafe.Pointer(&failallocatestack[0]), int32(len(failallocatestack)))
+		exit(1)
+	}
+	stk := unsafe.Pointer(uintptr(stack) + stacksize)
+
+	var oset uint32
+	sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
+	errno := bsdthread_create(stk, fn, fnarg)
+	sigprocmask(_SIG_SETMASK, &oset, nil)
+
+	if errno < 0 {
+		write(2, unsafe.Pointer(&failthreadcreate[0]), int32(len(failthreadcreate)))
+		exit(1)
+	}
+}
+
+var failallocatestack = []byte("runtime: failed to allocate stack for the new OS thread\n")
+var failthreadcreate = []byte("runtime: failed to create new OS thread\n")
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
+func mpreinit(mp *m) {
+	mp.gsignal = malg(32 * 1024) // OS X wants >= 8K
+	mp.gsignal.m = mp
+}
+
+func msigsave(mp *m) {
+	smask := (*uint32)(unsafe.Pointer(&mp.sigmask))
+	if unsafe.Sizeof(*smask) > unsafe.Sizeof(mp.sigmask) {
+		throw("insufficient storage for signal mask")
+	}
+	sigprocmask(_SIG_SETMASK, nil, smask)
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, can not allocate memory.
+func minit() {
+	// Initialize signal handling.
+	_g_ := getg()
+	signalstack(&_g_.m.gsignal.stack)
+
+	// restore signal mask from m.sigmask and unblock essential signals
+	nmask := *(*uint32)(unsafe.Pointer(&_g_.m.sigmask))
+	for i := range sigtable {
+		if sigtable[i].flags&_SigUnblock != 0 {
+			nmask &^= 1 << (uint32(i) - 1)
+		}
+	}
+	sigprocmask(_SIG_SETMASK, &nmask, nil)
+}
+
+// Called from dropm to undo the effect of an minit.
+func unminit() {
+	_g_ := getg()
+	smask := (*uint32)(unsafe.Pointer(&_g_.m.sigmask))
+	sigprocmask(_SIG_SETMASK, smask, nil)
+	signalstack(nil)
+}
+
+// Mach IPC, to get at semaphores
+// Definitions are in /usr/include/mach on a Mac.
+
+func macherror(r int32, fn string) {
+	print("mach error ", fn, ": ", r, "\n")
+	throw("mach error")
+}
+
+const _DebugMach = false
+
+var zerondr machndr
+
+func mach_msgh_bits(a, b uint32) uint32 {
+	return a | b<<8
+}
+
+func mach_msg(h *machheader, op int32, send_size, rcv_size, rcv_name, timeout, notify uint32) int32 {
+	// TODO: Loop on interrupt.
+	return mach_msg_trap(unsafe.Pointer(h), op, send_size, rcv_size, rcv_name, timeout, notify)
+}
+
+// Mach RPC (MIG)
+const (
+	_MinMachMsg = 48
+	_MachReply  = 100
+)
+
+type codemsg struct {
+	h    machheader
+	ndr  machndr
+	code int32
+}
+
+func machcall(h *machheader, maxsize int32, rxsize int32) int32 {
+	_g_ := getg()
+	port := _g_.m.machport
+	if port == 0 {
+		port = mach_reply_port()
+		_g_.m.machport = port
+	}
+
+	h.msgh_bits |= mach_msgh_bits(_MACH_MSG_TYPE_COPY_SEND, _MACH_MSG_TYPE_MAKE_SEND_ONCE)
+	h.msgh_local_port = port
+	h.msgh_reserved = 0
+	id := h.msgh_id
+
+	if _DebugMach {
+		p := (*[10000]unsafe.Pointer)(unsafe.Pointer(h))
+		print("send:\t")
+		var i uint32
+		for i = 0; i < h.msgh_size/uint32(unsafe.Sizeof(p[0])); i++ {
+			print(" ", p[i])
+			if i%8 == 7 {
+				print("\n\t")
+			}
+		}
+		if i%8 != 0 {
+			print("\n")
+		}
+	}
+	ret := mach_msg(h, _MACH_SEND_MSG|_MACH_RCV_MSG, h.msgh_size, uint32(maxsize), port, 0, 0)
+	if ret != 0 {
+		if _DebugMach {
+			print("mach_msg error ", ret, "\n")
+		}
+		return ret
+	}
+	if _DebugMach {
+		p := (*[10000]unsafe.Pointer)(unsafe.Pointer(h))
+		var i uint32
+		for i = 0; i < h.msgh_size/uint32(unsafe.Sizeof(p[0])); i++ {
+			print(" ", p[i])
+			if i%8 == 7 {
+				print("\n\t")
+			}
+		}
+		if i%8 != 0 {
+			print("\n")
+		}
+	}
+	if h.msgh_id != id+_MachReply {
+		if _DebugMach {
+			print("mach_msg _MachReply id mismatch ", h.msgh_id, " != ", id+_MachReply, "\n")
+		}
+		return -303 // MIG_REPLY_MISMATCH
+	}
+	// Look for a response giving the return value.
+	// Any call can send this back with an error,
+	// and some calls only have return values so they
+	// send it back on success too.  I don't quite see how
+	// you know it's one of these and not the full response
+	// format, so just look if the message is right.
+	c := (*codemsg)(unsafe.Pointer(h))
+	if uintptr(h.msgh_size) == unsafe.Sizeof(*c) && h.msgh_bits&_MACH_MSGH_BITS_COMPLEX == 0 {
+		if _DebugMach {
+			print("mig result ", c.code, "\n")
+		}
+		return c.code
+	}
+	if h.msgh_size != uint32(rxsize) {
+		if _DebugMach {
+			print("mach_msg _MachReply size mismatch ", h.msgh_size, " != ", rxsize, "\n")
+		}
+		return -307 // MIG_ARRAY_TOO_LARGE
+	}
+	return 0
+}
+
+// Semaphores!
+
+const (
+	tmach_semcreate = 3418
+	rmach_semcreate = tmach_semcreate + _MachReply
+
+	tmach_semdestroy = 3419
+	rmach_semdestroy = tmach_semdestroy + _MachReply
+
+	_KERN_ABORTED             = 14
+	_KERN_OPERATION_TIMED_OUT = 49
+)
+
+type tmach_semcreatemsg struct {
+	h      machheader
+	ndr    machndr
+	policy int32
+	value  int32
+}
+
+type rmach_semcreatemsg struct {
+	h         machheader
+	body      machbody
+	semaphore machport
+}
+
+type tmach_semdestroymsg struct {
+	h         machheader
+	body      machbody
+	semaphore machport
+}
+
+func mach_semcreate() uint32 {
+	var m [256]uint8
+	tx := (*tmach_semcreatemsg)(unsafe.Pointer(&m))
+	rx := (*rmach_semcreatemsg)(unsafe.Pointer(&m))
+
+	tx.h.msgh_bits = 0
+	tx.h.msgh_size = uint32(unsafe.Sizeof(*tx))
+	tx.h.msgh_remote_port = mach_task_self()
+	tx.h.msgh_id = tmach_semcreate
+	tx.ndr = zerondr
+
+	tx.policy = 0 // 0 = SYNC_POLICY_FIFO
+	tx.value = 0
+
+	for {
+		r := machcall(&tx.h, int32(unsafe.Sizeof(m)), int32(unsafe.Sizeof(*rx)))
+		if r == 0 {
+			break
+		}
+		if r == _KERN_ABORTED { // interrupted
+			continue
+		}
+		macherror(r, "semaphore_create")
+	}
+	if rx.body.msgh_descriptor_count != 1 {
+		unimplemented("mach_semcreate desc count")
+	}
+	return rx.semaphore.name
+}
+
+func mach_semdestroy(sem uint32) {
+	var m [256]uint8
+	tx := (*tmach_semdestroymsg)(unsafe.Pointer(&m))
+
+	tx.h.msgh_bits = _MACH_MSGH_BITS_COMPLEX
+	tx.h.msgh_size = uint32(unsafe.Sizeof(*tx))
+	tx.h.msgh_remote_port = mach_task_self()
+	tx.h.msgh_id = tmach_semdestroy
+	tx.body.msgh_descriptor_count = 1
+	tx.semaphore.name = sem
+	tx.semaphore.disposition = _MACH_MSG_TYPE_MOVE_SEND
+	tx.semaphore._type = 0
+
+	for {
+		r := machcall(&tx.h, int32(unsafe.Sizeof(m)), 0)
+		if r == 0 {
+			break
+		}
+		if r == _KERN_ABORTED { // interrupted
+			continue
+		}
+		macherror(r, "semaphore_destroy")
+	}
+}
+
+// The other calls have simple system call traps in sys_darwin_{amd64,386}.s
+
+func mach_semaphore_wait(sema uint32) int32
+func mach_semaphore_timedwait(sema, sec, nsec uint32) int32
+func mach_semaphore_signal(sema uint32) int32
+func mach_semaphore_signal_all(sema uint32) int32
+
+func semasleep1(ns int64) int32 {
+	_g_ := getg()
+
+	if ns >= 0 {
+		var nsecs int32
+		secs := timediv(ns, 1000000000, &nsecs)
+		r := mach_semaphore_timedwait(uint32(_g_.m.waitsema), uint32(secs), uint32(nsecs))
+		if r == _KERN_ABORTED || r == _KERN_OPERATION_TIMED_OUT {
+			return -1
+		}
+		if r != 0 {
+			macherror(r, "semaphore_wait")
+		}
+		return 0
+	}
+
+	for {
+		r := mach_semaphore_wait(uint32(_g_.m.waitsema))
+		if r == 0 {
+			break
+		}
+		if r == _KERN_ABORTED { // interrupted
+			continue
+		}
+		macherror(r, "semaphore_wait")
+	}
+	return 0
+}
+
+//go:nosplit
+func semasleep(ns int64) int32 {
+	var r int32
+	systemstack(func() {
+		r = semasleep1(ns)
+	})
+	return r
+}
+
+//go:nosplit
+func mach_semrelease(sem uint32) {
+	for {
+		r := mach_semaphore_signal(sem)
+		if r == 0 {
+			break
+		}
+		if r == _KERN_ABORTED { // interrupted
+			continue
+		}
+
+		// mach_semrelease must be completely nosplit,
+		// because it is called from Go code.
+		// If we're going to die, start that process on the system stack
+		// to avoid a Go stack split.
+		systemstack(func() { macherror(r, "semaphore_signal") })
+	}
+}
+
+//go:nosplit
+func osyield() {
+	usleep(1)
+}
+
+func memlimit() uintptr {
+	// NOTE(rsc): Could use getrlimit here,
+	// like on FreeBSD or Linux, but Darwin doesn't enforce
+	// ulimit -v, so it's unclear why we'd try to stay within
+	// the limit.
+	return 0
+}
+
+func setsig(i int32, fn uintptr, restart bool) {
+	var sa sigactiont
+	memclr(unsafe.Pointer(&sa), unsafe.Sizeof(sa))
+	sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
+	if restart {
+		sa.sa_flags |= _SA_RESTART
+	}
+	sa.sa_mask = ^uint32(0)
+	sa.sa_tramp = unsafe.Pointer(funcPC(sigtramp)) // runtime·sigtramp's job is to call into real handler
+	*(*uintptr)(unsafe.Pointer(&sa.__sigaction_u)) = fn
+	sigaction(uint32(i), &sa, nil)
+}
+
+func setsigstack(i int32) {
+	throw("setsigstack")
+}
+
+func getsig(i int32) uintptr {
+	var sa sigactiont
+	memclr(unsafe.Pointer(&sa), unsafe.Sizeof(sa))
+	sigaction(uint32(i), nil, &sa)
+	return *(*uintptr)(unsafe.Pointer(&sa.__sigaction_u))
+}
+
+func signalstack(s *stack) {
+	var st stackt
+	if s == nil {
+		st.ss_flags = _SS_DISABLE
+	} else {
+		st.ss_sp = (*byte)(unsafe.Pointer(s.lo))
+		st.ss_size = s.hi - s.lo
+		st.ss_flags = 0
+	}
+	sigaltstack(&st, nil)
+}
+
+func updatesigmask(m sigmask) {
+	sigprocmask(_SIG_SETMASK, &m[0], nil)
+}
+
+func unblocksig(sig int32) {
+	mask := uint32(1) << (uint32(sig) - 1)
+	sigprocmask(_SIG_UNBLOCK, &mask, nil)
+}
diff --git a/src/runtime/os1_dragonfly.go b/src/runtime/os1_dragonfly.go
new file mode 100644
index 0000000..f96c78c
--- /dev/null
+++ b/src/runtime/os1_dragonfly.go
@@ -0,0 +1,247 @@
+// 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
+
+import "unsafe"
+
+// From DragonFly's <sys/sysctl.h>
+const (
+	_CTL_HW  = 6
+	_HW_NCPU = 3
+)
+
+var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}}
+
+func getncpu() int32 {
+	mib := [2]uint32{_CTL_HW, _HW_NCPU}
+	out := uint32(0)
+	nout := unsafe.Sizeof(out)
+	ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
+	if ret >= 0 {
+		return int32(out)
+	}
+	return 1
+}
+
+//go:nosplit
+func futexsleep(addr *uint32, val uint32, ns int64) {
+	systemstack(func() {
+		futexsleep1(addr, val, ns)
+	})
+}
+
+func futexsleep1(addr *uint32, val uint32, ns int64) {
+	var timeout int32
+	if ns >= 0 {
+		// The timeout is specified in microseconds - ensure that we
+		// do not end up dividing to zero, which would put us to sleep
+		// indefinitely...
+		timeout = timediv(ns, 1000, nil)
+		if timeout == 0 {
+			timeout = 1
+		}
+	}
+
+	// sys_umtx_sleep will return EWOULDBLOCK (EAGAIN) when the timeout
+	// expires or EBUSY if the mutex value does not match.
+	ret := sys_umtx_sleep(addr, int32(val), timeout)
+	if ret >= 0 || ret == -_EINTR || ret == -_EAGAIN || ret == -_EBUSY {
+		return
+	}
+
+	print("umtx_sleep addr=", addr, " val=", val, " ret=", ret, "\n")
+	*(*int32)(unsafe.Pointer(uintptr(0x1005))) = 0x1005
+}
+
+//go:nosplit
+func futexwakeup(addr *uint32, cnt uint32) {
+	ret := sys_umtx_wakeup(addr, int32(cnt))
+	if ret >= 0 {
+		return
+	}
+
+	systemstack(func() {
+		print("umtx_wake_addr=", addr, " ret=", ret, "\n")
+		*(*int32)(unsafe.Pointer(uintptr(0x1006))) = 0x1006
+	})
+}
+
+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")
+	}
+
+	var oset sigset
+	sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
+
+	params := lwpparams{
+		start_func: funcPC(lwp_start),
+		arg:        unsafe.Pointer(mp),
+		stack:      uintptr(stk),
+		tid1:       unsafe.Pointer(&mp.procid),
+		tid2:       nil,
+	}
+
+	mp.tls[0] = uintptr(mp.id) // XXX so 386 asm can find it
+
+	lwp_create(&params)
+	sigprocmask(_SIG_SETMASK, &oset, nil)
+}
+
+func osinit() {
+	ncpu = getncpu()
+}
+
+var urandom_dev = []byte("/dev/urandom\x00")
+
+//go:nosplit
+func getRandomData(r []byte) {
+	fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
+	n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
+	closefd(fd)
+	extendRandom(r, int(n))
+}
+
+func goenvs() {
+	goenvs_unix()
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
+func mpreinit(mp *m) {
+	mp.gsignal = malg(32 * 1024)
+	mp.gsignal.m = mp
+}
+
+func msigsave(mp *m) {
+	smask := (*sigset)(unsafe.Pointer(&mp.sigmask))
+	if unsafe.Sizeof(*smask) > unsafe.Sizeof(mp.sigmask) {
+		throw("insufficient storage for signal mask")
+	}
+	sigprocmask(_SIG_SETMASK, nil, smask)
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, can not allocate memory.
+func minit() {
+	_g_ := getg()
+
+	// m.procid is a uint64, but lwp_start writes an int32. Fix it up.
+	_g_.m.procid = uint64(*(*int32)(unsafe.Pointer(&_g_.m.procid)))
+
+	// Initialize signal handling
+	signalstack(&_g_.m.gsignal.stack)
+
+	// restore signal mask from m.sigmask and unblock essential signals
+	nmask := *(*sigset)(unsafe.Pointer(&_g_.m.sigmask))
+	for i := range sigtable {
+		if sigtable[i].flags&_SigUnblock != 0 {
+			nmask.__bits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
+		}
+	}
+	sigprocmask(_SIG_SETMASK, &nmask, nil)
+}
+
+// Called from dropm to undo the effect of an minit.
+func unminit() {
+	_g_ := getg()
+	smask := (*sigset)(unsafe.Pointer(&_g_.m.sigmask))
+	sigprocmask(_SIG_SETMASK, smask, nil)
+	signalstack(nil)
+}
+
+func memlimit() uintptr {
+	/*
+		                TODO: Convert to Go when something actually uses the result.
+
+				Rlimit rl;
+				extern byte runtime·text[], runtime·end[];
+				uintptr used;
+
+				if(runtime·getrlimit(RLIMIT_AS, &rl) != 0)
+					return 0;
+				if(rl.rlim_cur >= 0x7fffffff)
+					return 0;
+
+				// Estimate our VM footprint excluding the heap.
+				// Not an exact science: use size of binary plus
+				// some room for thread stacks.
+				used = runtime·end - runtime·text + (64<<20);
+				if(used >= rl.rlim_cur)
+					return 0;
+
+				// If there's not at least 16 MB left, we're probably
+				// not going to be able to do much.  Treat as no limit.
+				rl.rlim_cur -= used;
+				if(rl.rlim_cur < (16<<20))
+					return 0;
+
+				return rl.rlim_cur - used;
+	*/
+	return 0
+}
+
+func sigtramp()
+
+type sigactiont struct {
+	sa_sigaction uintptr
+	sa_flags     int32
+	sa_mask      sigset
+}
+
+func setsig(i int32, fn uintptr, restart bool) {
+	var sa sigactiont
+	sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
+	if restart {
+		sa.sa_flags |= _SA_RESTART
+	}
+	sa.sa_mask = sigset_all
+	if fn == funcPC(sighandler) {
+		fn = funcPC(sigtramp)
+	}
+	sa.sa_sigaction = fn
+	sigaction(i, &sa, nil)
+}
+
+func setsigstack(i int32) {
+	throw("setsigstack")
+}
+
+func getsig(i int32) uintptr {
+	var sa sigactiont
+	sigaction(i, nil, &sa)
+	if sa.sa_sigaction == funcPC(sigtramp) {
+		return funcPC(sighandler)
+	}
+	return sa.sa_sigaction
+}
+
+func signalstack(s *stack) {
+	var st sigaltstackt
+	if s == nil {
+		st.ss_flags = _SS_DISABLE
+	} else {
+		st.ss_sp = s.lo
+		st.ss_size = s.hi - s.lo
+		st.ss_flags = 0
+	}
+	sigaltstack(&st, nil)
+}
+
+func updatesigmask(m sigmask) {
+	var mask sigset
+	copy(mask.__bits[:], m[:])
+	sigprocmask(_SIG_SETMASK, &mask, nil)
+}
+
+func unblocksig(sig int32) {
+	var mask sigset
+	mask.__bits[(sig-1)/32] |= 1 << ((uint32(sig) - 1) & 31)
+	sigprocmask(_SIG_UNBLOCK, &mask, nil)
+}
diff --git a/src/runtime/os1_freebsd.go b/src/runtime/os1_freebsd.go
new file mode 100644
index 0000000..f3519f3
--- /dev/null
+++ b/src/runtime/os1_freebsd.go
@@ -0,0 +1,249 @@
+// 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
+
+import "unsafe"
+
+// From FreeBSD's <sys/sysctl.h>
+const (
+	_CTL_HW  = 6
+	_HW_NCPU = 3
+)
+
+var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}}
+
+func getncpu() int32 {
+	mib := [2]uint32{_CTL_HW, _HW_NCPU}
+	out := uint32(0)
+	nout := unsafe.Sizeof(out)
+	ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
+	if ret >= 0 {
+		return int32(out)
+	}
+	return 1
+}
+
+// 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.go for comments.
+
+//go:nosplit
+func futexsleep(addr *uint32, val uint32, ns int64) {
+	systemstack(func() {
+		futexsleep1(addr, val, ns)
+	})
+}
+
+func futexsleep1(addr *uint32, val uint32, ns int64) {
+	var tsp *timespec
+	if ns >= 0 {
+		var ts timespec
+		ts.tv_nsec = 0
+		ts.set_sec(int64(timediv(ns, 1000000000, (*int32)(unsafe.Pointer(&ts.tv_nsec)))))
+		tsp = &ts
+	}
+	ret := sys_umtx_op(addr, _UMTX_OP_WAIT_UINT_PRIVATE, val, nil, tsp)
+	if ret >= 0 || ret == -_EINTR {
+		return
+	}
+	print("umtx_wait addr=", addr, " val=", val, " ret=", ret, "\n")
+	*(*int32)(unsafe.Pointer(uintptr(0x1005))) = 0x1005
+}
+
+//go:nosplit
+func futexwakeup(addr *uint32, cnt uint32) {
+	ret := sys_umtx_op(addr, _UMTX_OP_WAKE_PRIVATE, cnt, nil, nil)
+	if ret >= 0 {
+		return
+	}
+
+	systemstack(func() {
+		print("umtx_wake_addr=", addr, " ret=", ret, "\n")
+	})
+}
+
+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")
+	}
+
+	// NOTE(rsc): This code is confused. stackbase is the top of the stack
+	// and is equal to stk. However, it's working, so I'm not changing it.
+	param := thrparam{
+		start_func: funcPC(thr_start),
+		arg:        unsafe.Pointer(mp),
+		stack_base: mp.g0.stack.hi,
+		stack_size: uintptr(stk) - mp.g0.stack.hi,
+		child_tid:  unsafe.Pointer(&mp.procid),
+		parent_tid: nil,
+		tls_base:   unsafe.Pointer(&mp.tls[0]),
+		tls_size:   unsafe.Sizeof(mp.tls),
+	}
+	mp.tls[0] = uintptr(mp.id) // so 386 asm can find it
+
+	var oset sigset
+	sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
+	thr_new(&param, int32(unsafe.Sizeof(param)))
+	sigprocmask(_SIG_SETMASK, &oset, nil)
+}
+
+func osinit() {
+	ncpu = getncpu()
+}
+
+var urandom_dev = []byte("/dev/urandom\x00")
+
+//go:nosplit
+func getRandomData(r []byte) {
+	fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
+	n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
+	closefd(fd)
+	extendRandom(r, int(n))
+}
+
+func goenvs() {
+	goenvs_unix()
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
+func mpreinit(mp *m) {
+	mp.gsignal = malg(32 * 1024)
+	mp.gsignal.m = mp
+}
+
+func msigsave(mp *m) {
+	smask := (*sigset)(unsafe.Pointer(&mp.sigmask))
+	if unsafe.Sizeof(*smask) > unsafe.Sizeof(mp.sigmask) {
+		throw("insufficient storage for signal mask")
+	}
+	sigprocmask(_SIG_SETMASK, nil, smask)
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, can not allocate memory.
+func minit() {
+	_g_ := getg()
+
+	// m.procid is a uint64, but thr_new writes a uint32 on 32-bit systems.
+	// Fix it up. (Only matters on big-endian, but be clean anyway.)
+	if ptrSize == 4 {
+		_g_.m.procid = uint64(*(*uint32)(unsafe.Pointer(&_g_.m.procid)))
+	}
+
+	// Initialize signal handling.
+	signalstack(&_g_.m.gsignal.stack)
+
+	// restore signal mask from m.sigmask and unblock essential signals
+	nmask := *(*sigset)(unsafe.Pointer(&_g_.m.sigmask))
+	for i := range sigtable {
+		if sigtable[i].flags&_SigUnblock != 0 {
+			nmask.__bits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
+		}
+	}
+	sigprocmask(_SIG_SETMASK, &nmask, nil)
+}
+
+// Called from dropm to undo the effect of an minit.
+func unminit() {
+	_g_ := getg()
+	smask := (*sigset)(unsafe.Pointer(&_g_.m.sigmask))
+	sigprocmask(_SIG_SETMASK, smask, nil)
+	signalstack(nil)
+}
+
+func memlimit() uintptr {
+	/*
+		TODO: Convert to Go when something actually uses the result.
+		Rlimit rl;
+		extern byte runtime·text[], runtime·end[];
+		uintptr used;
+
+		if(runtime·getrlimit(RLIMIT_AS, &rl) != 0)
+			return 0;
+		if(rl.rlim_cur >= 0x7fffffff)
+			return 0;
+
+		// Estimate our VM footprint excluding the heap.
+		// Not an exact science: use size of binary plus
+		// some room for thread stacks.
+		used = runtime·end - runtime·text + (64<<20);
+		if(used >= rl.rlim_cur)
+			return 0;
+
+		// If there's not at least 16 MB left, we're probably
+		// not going to be able to do much.  Treat as no limit.
+		rl.rlim_cur -= used;
+		if(rl.rlim_cur < (16<<20))
+			return 0;
+
+		return rl.rlim_cur - used;
+	*/
+
+	return 0
+}
+
+func sigtramp()
+
+type sigactiont struct {
+	sa_handler uintptr
+	sa_flags   int32
+	sa_mask    sigset
+}
+
+func setsig(i int32, fn uintptr, restart bool) {
+	var sa sigactiont
+	sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
+	if restart {
+		sa.sa_flags |= _SA_RESTART
+	}
+	sa.sa_mask = sigset_all
+	if fn == funcPC(sighandler) {
+		fn = funcPC(sigtramp)
+	}
+	sa.sa_handler = fn
+	sigaction(i, &sa, nil)
+}
+
+func setsigstack(i int32) {
+	throw("setsigstack")
+}
+
+func getsig(i int32) uintptr {
+	var sa sigactiont
+	sigaction(i, nil, &sa)
+	if sa.sa_handler == funcPC(sigtramp) {
+		return funcPC(sighandler)
+	}
+	return sa.sa_handler
+}
+
+func signalstack(s *stack) {
+	var st stackt
+	if s == nil {
+		st.ss_flags = _SS_DISABLE
+	} else {
+		st.ss_sp = s.lo
+		st.ss_size = s.hi - s.lo
+		st.ss_flags = 0
+	}
+	sigaltstack(&st, nil)
+}
+
+func updatesigmask(m [(_NSIG + 31) / 32]uint32) {
+	var mask sigset
+	copy(mask.__bits[:], m[:])
+	sigprocmask(_SIG_SETMASK, &mask, nil)
+}
+
+func unblocksig(sig int32) {
+	var mask sigset
+	mask.__bits[(sig-1)/32] |= 1 << ((uint32(sig) - 1) & 31)
+	sigprocmask(_SIG_UNBLOCK, &mask, nil)
+}
diff --git a/src/runtime/os1_linux.go b/src/runtime/os1_linux.go
new file mode 100644
index 0000000..c23dc30
--- /dev/null
+++ b/src/runtime/os1_linux.go
@@ -0,0 +1,350 @@
+// 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"
+
+var sigset_all sigset = sigset{^uint32(0), ^uint32(0)}
+
+// Linux futex.
+//
+//	futexsleep(uint32 *addr, uint32 val)
+//	futexwakeup(uint32 *addr)
+//
+// Futexsleep atomically checks if *addr == val and if so, sleeps on addr.
+// Futexwakeup wakes up threads sleeping on addr.
+// Futexsleep is allowed to wake up spuriously.
+
+const (
+	_FUTEX_WAIT = 0
+	_FUTEX_WAKE = 1
+)
+
+// Atomically,
+//	if(*addr == val) sleep
+// Might be woken up spuriously; that's allowed.
+// Don't sleep longer than ns; ns < 0 means forever.
+//go:nosplit
+func futexsleep(addr *uint32, val uint32, ns int64) {
+	var ts timespec
+
+	// Some Linux kernels have a bug where futex of
+	// FUTEX_WAIT returns an internal error code
+	// as an errno.  Libpthread ignores the return value
+	// here, and so can we: as it says a few lines up,
+	// spurious wakeups are allowed.
+	if ns < 0 {
+		futex(unsafe.Pointer(addr), _FUTEX_WAIT, val, nil, nil, 0)
+		return
+	}
+
+	// It's difficult to live within the no-split stack limits here.
+	// On ARM and 386, a 64-bit divide invokes a general software routine
+	// that needs more stack than we can afford. So we use timediv instead.
+	// But on real 64-bit systems, where words are larger but the stack limit
+	// is not, even timediv is too heavy, and we really need to use just an
+	// ordinary machine instruction.
+	if ptrSize == 8 {
+		ts.set_sec(ns / 1000000000)
+		ts.set_nsec(int32(ns % 1000000000))
+	} else {
+		ts.tv_nsec = 0
+		ts.set_sec(int64(timediv(ns, 1000000000, (*int32)(unsafe.Pointer(&ts.tv_nsec)))))
+	}
+	futex(unsafe.Pointer(addr), _FUTEX_WAIT, val, unsafe.Pointer(&ts), nil, 0)
+}
+
+// If any procs are sleeping on addr, wake up at most cnt.
+//go:nosplit
+func futexwakeup(addr *uint32, cnt uint32) {
+	ret := futex(unsafe.Pointer(addr), _FUTEX_WAKE, cnt, nil, nil, 0)
+	if ret >= 0 {
+		return
+	}
+
+	// I don't know that futex wakeup can return
+	// EAGAIN or EINTR, but if it does, it would be
+	// safe to loop and call futex again.
+	systemstack(func() {
+		print("futexwakeup addr=", addr, " returned ", ret, "\n")
+	})
+
+	*(*int32)(unsafe.Pointer(uintptr(0x1006))) = 0x1006
+}
+
+func getproccount() int32 {
+	// This buffer is huge (8 kB) but we are on the system stack
+	// and there should be plenty of space (64 kB) -- except on ARM where
+	// the system stack itself is only 8kb (see golang.org/issue/11873).
+	// Also this is a leaf, so we're not holding up the memory for long.
+	// See golang.org/issue/11823.
+	// The suggested behavior here is to keep trying with ever-larger
+	// buffers, but we don't have a dynamic memory allocator at the
+	// moment, so that's a bit tricky and seems like overkill.
+	const maxCPUs = 64*1024*(1-goarch_arm) + 1024*goarch_arm
+	var buf [maxCPUs / (ptrSize * 8)]uintptr
+	r := sched_getaffinity(0, unsafe.Sizeof(buf), &buf[0])
+	n := int32(0)
+	for _, v := range buf[:r/ptrSize] {
+		for v != 0 {
+			n += int32(v & 1)
+			v >>= 1
+		}
+	}
+	if n == 0 {
+		n = 1
+	}
+	return n
+}
+
+// Clone, the Linux rfork.
+const (
+	_CLONE_VM             = 0x100
+	_CLONE_FS             = 0x200
+	_CLONE_FILES          = 0x400
+	_CLONE_SIGHAND        = 0x800
+	_CLONE_PTRACE         = 0x2000
+	_CLONE_VFORK          = 0x4000
+	_CLONE_PARENT         = 0x8000
+	_CLONE_THREAD         = 0x10000
+	_CLONE_NEWNS          = 0x20000
+	_CLONE_SYSVSEM        = 0x40000
+	_CLONE_SETTLS         = 0x80000
+	_CLONE_PARENT_SETTID  = 0x100000
+	_CLONE_CHILD_CLEARTID = 0x200000
+	_CLONE_UNTRACED       = 0x800000
+	_CLONE_CHILD_SETTID   = 0x1000000
+	_CLONE_STOPPED        = 0x2000000
+	_CLONE_NEWUTS         = 0x4000000
+	_CLONE_NEWIPC         = 0x8000000
+
+	cloneFlags = _CLONE_VM | /* share memory */
+		_CLONE_FS | /* share cwd, etc */
+		_CLONE_FILES | /* share fd table */
+		_CLONE_SIGHAND | /* share sig handler table */
+		_CLONE_THREAD /* revisit - okay for now */
+)
+
+// 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.
+	 */
+	mp.tls[0] = uintptr(mp.id) // so 386 asm can find it
+	if false {
+		print("newosproc stk=", stk, " m=", mp, " g=", mp.g0, " clone=", funcPC(clone), " id=", mp.id, "/", mp.tls[0], " ostk=", &mp, "\n")
+	}
+
+	// Disable signals during clone, so that the new thread starts
+	// with signals disabled.  It will enable them in minit.
+	var oset sigset
+	rtsigprocmask(_SIG_SETMASK, &sigset_all, &oset, int32(unsafe.Sizeof(oset)))
+	ret := clone(cloneFlags, stk, unsafe.Pointer(mp), unsafe.Pointer(mp.g0), unsafe.Pointer(funcPC(mstart)))
+	rtsigprocmask(_SIG_SETMASK, &oset, nil, int32(unsafe.Sizeof(oset)))
+
+	if ret < 0 {
+		print("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", -ret, ")\n")
+		throw("newosproc")
+	}
+}
+
+// Version of newosproc that doesn't require a valid G.
+//go:nosplit
+func newosproc0(stacksize uintptr, fn unsafe.Pointer) {
+	stack := sysAlloc(stacksize, &memstats.stacks_sys)
+	if stack == nil {
+		write(2, unsafe.Pointer(&failallocatestack[0]), int32(len(failallocatestack)))
+		exit(1)
+	}
+	ret := clone(cloneFlags, unsafe.Pointer(uintptr(stack)+stacksize), nil, nil, fn)
+	if ret < 0 {
+		write(2, unsafe.Pointer(&failthreadcreate[0]), int32(len(failthreadcreate)))
+		exit(1)
+	}
+}
+
+var failallocatestack = []byte("runtime: failed to allocate stack for the new OS thread\n")
+var failthreadcreate = []byte("runtime: failed to create new OS thread\n")
+
+func osinit() {
+	ncpu = getproccount()
+}
+
+var urandom_dev = []byte("/dev/urandom\x00")
+
+func getRandomData(r []byte) {
+	if startupRandomData != nil {
+		n := copy(r, startupRandomData)
+		extendRandom(r, n)
+		return
+	}
+	fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
+	n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
+	closefd(fd)
+	extendRandom(r, int(n))
+}
+
+func goenvs() {
+	goenvs_unix()
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
+func mpreinit(mp *m) {
+	mp.gsignal = malg(32 * 1024) // Linux wants >= 2K
+	mp.gsignal.m = mp
+}
+
+func msigsave(mp *m) {
+	smask := (*sigset)(unsafe.Pointer(&mp.sigmask))
+	if unsafe.Sizeof(*smask) > unsafe.Sizeof(mp.sigmask) {
+		throw("insufficient storage for signal mask")
+	}
+	rtsigprocmask(_SIG_SETMASK, nil, smask, int32(unsafe.Sizeof(*smask)))
+}
+
+func gettid() uint32
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, can not allocate memory.
+func minit() {
+	// Initialize signal handling.
+	_g_ := getg()
+	signalstack(&_g_.m.gsignal.stack)
+
+	// for debuggers, in case cgo created the thread
+	_g_.m.procid = uint64(gettid())
+
+	// restore signal mask from m.sigmask and unblock essential signals
+	nmask := *(*sigset)(unsafe.Pointer(&_g_.m.sigmask))
+	for i := range sigtable {
+		if sigtable[i].flags&_SigUnblock != 0 {
+			nmask[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
+		}
+	}
+	rtsigprocmask(_SIG_SETMASK, &nmask, nil, int32(unsafe.Sizeof(nmask)))
+}
+
+// Called from dropm to undo the effect of an minit.
+func unminit() {
+	_g_ := getg()
+	smask := (*sigset)(unsafe.Pointer(&_g_.m.sigmask))
+	rtsigprocmask(_SIG_SETMASK, smask, nil, int32(unsafe.Sizeof(*smask)))
+	signalstack(nil)
+}
+
+func memlimit() uintptr {
+	/*
+		TODO: Convert to Go when something actually uses the result.
+
+		Rlimit rl;
+		extern byte runtime·text[], runtime·end[];
+		uintptr used;
+
+		if(runtime·getrlimit(RLIMIT_AS, &rl) != 0)
+			return 0;
+		if(rl.rlim_cur >= 0x7fffffff)
+			return 0;
+
+		// Estimate our VM footprint excluding the heap.
+		// Not an exact science: use size of binary plus
+		// some room for thread stacks.
+		used = runtime·end - runtime·text + (64<<20);
+		if(used >= rl.rlim_cur)
+			return 0;
+
+		// If there's not at least 16 MB left, we're probably
+		// not going to be able to do much.  Treat as no limit.
+		rl.rlim_cur -= used;
+		if(rl.rlim_cur < (16<<20))
+			return 0;
+
+		return rl.rlim_cur - used;
+	*/
+
+	return 0
+}
+
+//#ifdef GOARCH_386
+//#define sa_handler k_sa_handler
+//#endif
+
+func sigreturn()
+func sigtramp()
+
+func setsig(i int32, fn uintptr, restart bool) {
+	var sa sigactiont
+	memclr(unsafe.Pointer(&sa), unsafe.Sizeof(sa))
+	sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTORER
+	if restart {
+		sa.sa_flags |= _SA_RESTART
+	}
+	sa.sa_mask = ^uint64(0)
+	// Although Linux manpage says "sa_restorer element is obsolete and
+	// should not be used". x86_64 kernel requires it. Only use it on
+	// x86.
+	if GOARCH == "386" || GOARCH == "amd64" {
+		sa.sa_restorer = funcPC(sigreturn)
+	}
+	if fn == funcPC(sighandler) {
+		fn = funcPC(sigtramp)
+	}
+	sa.sa_handler = fn
+	if rt_sigaction(uintptr(i), &sa, nil, unsafe.Sizeof(sa.sa_mask)) != 0 {
+		throw("rt_sigaction failure")
+	}
+}
+
+func setsigstack(i int32) {
+	var sa sigactiont
+	if rt_sigaction(uintptr(i), nil, &sa, unsafe.Sizeof(sa.sa_mask)) != 0 {
+		throw("rt_sigaction failure")
+	}
+	if sa.sa_handler == 0 || sa.sa_handler == _SIG_DFL || sa.sa_handler == _SIG_IGN || sa.sa_flags&_SA_ONSTACK != 0 {
+		return
+	}
+	sa.sa_flags |= _SA_ONSTACK
+	if rt_sigaction(uintptr(i), &sa, nil, unsafe.Sizeof(sa.sa_mask)) != 0 {
+		throw("rt_sigaction failure")
+	}
+}
+
+func getsig(i int32) uintptr {
+	var sa sigactiont
+
+	memclr(unsafe.Pointer(&sa), unsafe.Sizeof(sa))
+	if rt_sigaction(uintptr(i), nil, &sa, unsafe.Sizeof(sa.sa_mask)) != 0 {
+		throw("rt_sigaction read failure")
+	}
+	if sa.sa_handler == funcPC(sigtramp) {
+		return funcPC(sighandler)
+	}
+	return sa.sa_handler
+}
+
+func signalstack(s *stack) {
+	var st sigaltstackt
+	if s == nil {
+		st.ss_flags = _SS_DISABLE
+	} else {
+		st.ss_sp = (*byte)(unsafe.Pointer(s.lo))
+		st.ss_size = s.hi - s.lo
+		st.ss_flags = 0
+	}
+	sigaltstack(&st, nil)
+}
+
+func updatesigmask(m sigmask) {
+	var mask sigset
+	copy(mask[:], m[:])
+	rtsigprocmask(_SIG_SETMASK, &mask, nil, int32(unsafe.Sizeof(mask)))
+}
+
+func unblocksig(sig int32) {
+	var mask sigset
+	mask[(sig-1)/32] |= 1 << ((uint32(sig) - 1) & 31)
+	rtsigprocmask(_SIG_UNBLOCK, &mask, nil, int32(unsafe.Sizeof(mask)))
+}
diff --git a/src/runtime/os1_nacl.go b/src/runtime/os1_nacl.go
new file mode 100644
index 0000000..143752a
--- /dev/null
+++ b/src/runtime/os1_nacl.go
@@ -0,0 +1,203 @@
+// Copyright 2010 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"
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
+func mpreinit(mp *m) {
+	mp.gsignal = malg(32 * 1024)
+	mp.gsignal.m = mp
+}
+
+func sigtramp()
+
+func msigsave(mp *m) {
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, can not allocate memory.
+func minit() {
+	_g_ := getg()
+
+	// Initialize signal handling
+	ret := nacl_exception_stack(_g_.m.gsignal.stack.lo, 32*1024)
+	if ret < 0 {
+		print("runtime: nacl_exception_stack: error ", -ret, "\n")
+	}
+
+	ret = nacl_exception_handler(funcPC(sigtramp), nil)
+	if ret < 0 {
+		print("runtime: nacl_exception_handler: error ", -ret, "\n")
+	}
+}
+
+// Called from dropm to undo the effect of an minit.
+func unminit() {
+}
+
+func osinit() {
+	ncpu = 1
+	getg().m.procid = 2
+	//nacl_exception_handler(funcPC(sigtramp), nil);
+}
+
+func crash() {
+	*(*int32)(nil) = 0
+}
+
+//go:noescape
+func getRandomData([]byte)
+
+func goenvs() {
+	goenvs_unix()
+}
+
+func initsig() {
+}
+
+//go:nosplit
+func usleep(us uint32) {
+	var ts timespec
+
+	ts.tv_sec = int64(us / 1e6)
+	ts.tv_nsec = int32(us%1e6) * 1e3
+	nacl_nanosleep(&ts, nil)
+}
+
+func mstart_nacl()
+
+// 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(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")
+	}
+}
+
+//go:nosplit
+func semacreate() uintptr {
+	var cond uintptr
+	systemstack(func() {
+		mu := nacl_mutex_create(0)
+		if mu < 0 {
+			print("nacl_mutex_create: error ", -mu, "\n")
+			throw("semacreate")
+		}
+		c := nacl_cond_create(0)
+		if c < 0 {
+			print("nacl_cond_create: error ", -cond, "\n")
+			throw("semacreate")
+		}
+		cond = uintptr(c)
+		_g_ := getg()
+		_g_.m.waitsemalock = uint32(mu)
+	})
+	return cond
+}
+
+//go:nosplit
+func semasleep(ns int64) int32 {
+	var ret int32
+
+	systemstack(func() {
+		_g_ := getg()
+		if nacl_mutex_lock(int32(_g_.m.waitsemalock)) < 0 {
+			throw("semasleep")
+		}
+
+		for _g_.m.waitsemacount == 0 {
+			if ns < 0 {
+				if nacl_cond_wait(int32(_g_.m.waitsema), int32(_g_.m.waitsemalock)) < 0 {
+					throw("semasleep")
+				}
+			} else {
+				var ts timespec
+				end := ns + nanotime()
+				ts.tv_sec = end / 1e9
+				ts.tv_nsec = int32(end % 1e9)
+				r := nacl_cond_timed_wait_abs(int32(_g_.m.waitsema), int32(_g_.m.waitsemalock), &ts)
+				if r == -_ETIMEDOUT {
+					nacl_mutex_unlock(int32(_g_.m.waitsemalock))
+					ret = -1
+					return
+				}
+				if r < 0 {
+					throw("semasleep")
+				}
+			}
+		}
+
+		_g_.m.waitsemacount = 0
+		nacl_mutex_unlock(int32(_g_.m.waitsemalock))
+		ret = 0
+	})
+	return ret
+}
+
+//go:nosplit
+func semawakeup(mp *m) {
+	systemstack(func() {
+		if nacl_mutex_lock(int32(mp.waitsemalock)) < 0 {
+			throw("semawakeup")
+		}
+		if mp.waitsemacount != 0 {
+			throw("semawakeup")
+		}
+		mp.waitsemacount = 1
+		nacl_cond_signal(int32(mp.waitsema))
+		nacl_mutex_unlock(int32(mp.waitsemalock))
+	})
+}
+
+func memlimit() uintptr {
+	return 0
+}
+
+// This runs on a foreign stack, without an m or a g.  No stack split.
+//go:nosplit
+func badsignal2() {
+	write(2, unsafe.Pointer(&badsignal1[0]), int32(len(badsignal1)))
+	exit(2)
+}
+
+var badsignal1 = []byte("runtime: signal received on thread not created by Go.\n")
+
+func raisebadsignal(sig int32) {
+	badsignal2()
+}
+
+func madvise(addr unsafe.Pointer, n uintptr, flags int32) {}
+func munmap(addr unsafe.Pointer, n uintptr)               {}
+func resetcpuprofiler(hz int32)                           {}
+func sigdisable(uint32)                                   {}
+func sigenable(uint32)                                    {}
+func sigignore(uint32)                                    {}
+func closeonexec(int32)                                   {}
+
+var writelock uint32 // test-and-set spin lock for write
+
+/*
+An attempt at IRT. Doesn't work. See end of sys_nacl_amd64.s.
+
+void (*nacl_irt_query)(void);
+
+int8 nacl_irt_basic_v0_1_str[] = "nacl-irt-basic-0.1";
+void *nacl_irt_basic_v0_1[6]; // exit, gettod, clock, nanosleep, sched_yield, sysconf
+int32 nacl_irt_basic_v0_1_size = sizeof(nacl_irt_basic_v0_1);
+
+int8 nacl_irt_memory_v0_3_str[] = "nacl-irt-memory-0.3";
+void *nacl_irt_memory_v0_3[3]; // mmap, munmap, mprotect
+int32 nacl_irt_memory_v0_3_size = sizeof(nacl_irt_memory_v0_3);
+
+int8 nacl_irt_thread_v0_1_str[] = "nacl-irt-thread-0.1";
+void *nacl_irt_thread_v0_1[3]; // thread_create, thread_exit, thread_nice
+int32 nacl_irt_thread_v0_1_size = sizeof(nacl_irt_thread_v0_1);
+*/
diff --git a/src/runtime/os1_netbsd.go b/src/runtime/os1_netbsd.go
new file mode 100644
index 0000000..cacd606
--- /dev/null
+++ b/src/runtime/os1_netbsd.go
@@ -0,0 +1,238 @@
+// 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
+
+import "unsafe"
+
+const (
+	_ESRCH     = 3
+	_ETIMEDOUT = 60
+
+	// From NetBSD's <sys/time.h>
+	_CLOCK_REALTIME  = 0
+	_CLOCK_VIRTUAL   = 1
+	_CLOCK_PROF      = 2
+	_CLOCK_MONOTONIC = 3
+)
+
+var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}}
+
+// From NetBSD's <sys/sysctl.h>
+const (
+	_CTL_HW  = 6
+	_HW_NCPU = 3
+)
+
+func getncpu() int32 {
+	mib := [2]uint32{_CTL_HW, _HW_NCPU}
+	out := uint32(0)
+	nout := unsafe.Sizeof(out)
+	ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
+	if ret >= 0 {
+		return int32(out)
+	}
+	return 1
+}
+
+//go:nosplit
+func semacreate() uintptr {
+	return 1
+}
+
+//go:nosplit
+func semasleep(ns int64) int32 {
+	_g_ := getg()
+
+	// Compute sleep deadline.
+	var tsp *timespec
+	if ns >= 0 {
+		var ts timespec
+		var nsec int32
+		ns += nanotime()
+		ts.set_sec(timediv(ns, 1000000000, &nsec))
+		ts.set_nsec(nsec)
+		tsp = &ts
+	}
+
+	for {
+		v := atomicload(&_g_.m.waitsemacount)
+		if v > 0 {
+			if cas(&_g_.m.waitsemacount, v, v-1) {
+				return 0 // semaphore acquired
+			}
+			continue
+		}
+
+		// Sleep until unparked by semawakeup or timeout.
+		ret := lwp_park(tsp, 0, unsafe.Pointer(&_g_.m.waitsemacount), nil)
+		if ret == _ETIMEDOUT {
+			return -1
+		}
+	}
+}
+
+//go:nosplit
+func semawakeup(mp *m) {
+	xadd(&mp.waitsemacount, 1)
+	// From NetBSD's _lwp_unpark(2) manual:
+	// "If the target LWP is not currently waiting, it will return
+	// immediately upon the next call to _lwp_park()."
+	ret := lwp_unpark(int32(mp.procid), unsafe.Pointer(&mp.waitsemacount))
+	if ret != 0 && ret != _ESRCH {
+		// semawakeup can be called on signal stack.
+		systemstack(func() {
+			print("thrwakeup addr=", &mp.waitsemacount, " sem=", mp.waitsemacount, " ret=", ret, "\n")
+		})
+	}
+}
+
+// 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")
+	}
+
+	mp.tls[0] = uintptr(mp.id) // so 386 asm can find it
+
+	var uc ucontextt
+	getcontext(unsafe.Pointer(&uc))
+
+	uc.uc_flags = _UC_SIGMASK | _UC_CPU
+	uc.uc_link = nil
+	uc.uc_sigmask = sigset_all
+
+	lwp_mcontext_init(&uc.uc_mcontext, stk, mp, mp.g0, funcPC(mstart))
+
+	ret := lwp_create(unsafe.Pointer(&uc), 0, unsafe.Pointer(&mp.procid))
+	if ret < 0 {
+		print("runtime: failed to create new OS thread (have ", mcount()-1, " already; errno=", -ret, ")\n")
+		throw("runtime.newosproc")
+	}
+}
+
+func osinit() {
+	ncpu = getncpu()
+}
+
+var urandom_dev = []byte("/dev/urandom\x00")
+
+//go:nosplit
+func getRandomData(r []byte) {
+	fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
+	n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
+	closefd(fd)
+	extendRandom(r, int(n))
+}
+
+func goenvs() {
+	goenvs_unix()
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
+func mpreinit(mp *m) {
+	mp.gsignal = malg(32 * 1024)
+	mp.gsignal.m = mp
+}
+
+func msigsave(mp *m) {
+	smask := (*sigset)(unsafe.Pointer(&mp.sigmask))
+	if unsafe.Sizeof(*smask) > unsafe.Sizeof(mp.sigmask) {
+		throw("insufficient storage for signal mask")
+	}
+	sigprocmask(_SIG_SETMASK, nil, smask)
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, can not allocate memory.
+func minit() {
+	_g_ := getg()
+	_g_.m.procid = uint64(lwp_self())
+
+	// Initialize signal handling
+	signalstack(&_g_.m.gsignal.stack)
+
+	// restore signal mask from m.sigmask and unblock essential signals
+	nmask := *(*sigset)(unsafe.Pointer(&_g_.m.sigmask))
+	for i := range sigtable {
+		if sigtable[i].flags&_SigUnblock != 0 {
+			nmask.__bits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
+		}
+	}
+	sigprocmask(_SIG_SETMASK, &nmask, nil)
+}
+
+// Called from dropm to undo the effect of an minit.
+func unminit() {
+	_g_ := getg()
+	smask := (*sigset)(unsafe.Pointer(&_g_.m.sigmask))
+	sigprocmask(_SIG_SETMASK, smask, nil)
+
+	signalstack(nil)
+}
+
+func memlimit() uintptr {
+	return 0
+}
+
+func sigtramp()
+
+type sigactiont struct {
+	sa_sigaction uintptr
+	sa_mask      sigset
+	sa_flags     int32
+}
+
+func setsig(i int32, fn uintptr, restart bool) {
+	var sa sigactiont
+	sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
+	if restart {
+		sa.sa_flags |= _SA_RESTART
+	}
+	sa.sa_mask = sigset_all
+	if fn == funcPC(sighandler) {
+		fn = funcPC(sigtramp)
+	}
+	sa.sa_sigaction = fn
+	sigaction(i, &sa, nil)
+}
+
+func setsigstack(i int32) {
+	throw("setsigstack")
+}
+
+func getsig(i int32) uintptr {
+	var sa sigactiont
+	sigaction(i, nil, &sa)
+	if sa.sa_sigaction == funcPC(sigtramp) {
+		return funcPC(sighandler)
+	}
+	return sa.sa_sigaction
+}
+
+func signalstack(s *stack) {
+	var st sigaltstackt
+	if s == nil {
+		st.ss_flags = _SS_DISABLE
+	} else {
+		st.ss_sp = s.lo
+		st.ss_size = s.hi - s.lo
+		st.ss_flags = 0
+	}
+	sigaltstack(&st, nil)
+}
+
+func updatesigmask(m sigmask) {
+	var mask sigset
+	copy(mask.__bits[:], m[:])
+	sigprocmask(_SIG_SETMASK, &mask, nil)
+}
+
+func unblocksig(sig int32) {
+	var mask sigset
+	mask.__bits[(sig-1)/32] |= 1 << ((uint32(sig) - 1) & 31)
+	sigprocmask(_SIG_UNBLOCK, &mask, nil)
+}
diff --git a/src/runtime/os1_netbsd_386.go b/src/runtime/os1_netbsd_386.go
new file mode 100644
index 0000000..037f7e3
--- /dev/null
+++ b/src/runtime/os1_netbsd_386.go
@@ -0,0 +1,16 @@
+// 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"
+
+func lwp_mcontext_init(mc *mcontextt, stk unsafe.Pointer, mp *m, gp *g, fn uintptr) {
+	// Machine dependent mcontext initialisation for LWP.
+	mc.__gregs[_REG_EIP] = uint32(funcPC(lwp_tramp))
+	mc.__gregs[_REG_UESP] = uint32(uintptr(stk))
+	mc.__gregs[_REG_EBX] = uint32(uintptr(unsafe.Pointer(mp)))
+	mc.__gregs[_REG_EDX] = uint32(uintptr(unsafe.Pointer(gp)))
+	mc.__gregs[_REG_ESI] = uint32(fn)
+}
diff --git a/src/runtime/os1_netbsd_amd64.go b/src/runtime/os1_netbsd_amd64.go
new file mode 100644
index 0000000..5118b0c
--- /dev/null
+++ b/src/runtime/os1_netbsd_amd64.go
@@ -0,0 +1,16 @@
+// 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"
+
+func lwp_mcontext_init(mc *mcontextt, stk unsafe.Pointer, mp *m, gp *g, fn uintptr) {
+	// Machine dependent mcontext initialisation for LWP.
+	mc.__gregs[_REG_RIP] = uint64(funcPC(lwp_tramp))
+	mc.__gregs[_REG_RSP] = uint64(uintptr(stk))
+	mc.__gregs[_REG_R8] = uint64(uintptr(unsafe.Pointer(mp)))
+	mc.__gregs[_REG_R9] = uint64(uintptr(unsafe.Pointer(gp)))
+	mc.__gregs[_REG_R12] = uint64(fn)
+}
diff --git a/src/runtime/os1_openbsd.go b/src/runtime/os1_openbsd.go
new file mode 100644
index 0000000..24a095b
--- /dev/null
+++ b/src/runtime/os1_openbsd.go
@@ -0,0 +1,246 @@
+// 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
+
+import "unsafe"
+
+const (
+	_ESRCH       = 3
+	_EAGAIN      = 35
+	_EWOULDBLOCK = _EAGAIN
+	_ENOTSUP     = 91
+
+	// From OpenBSD's sys/time.h
+	_CLOCK_REALTIME  = 0
+	_CLOCK_VIRTUAL   = 1
+	_CLOCK_PROF      = 2
+	_CLOCK_MONOTONIC = 3
+)
+
+const (
+	sigset_none = uint32(0)
+	sigset_all  = ^uint32(0)
+)
+
+// From OpenBSD's <sys/sysctl.h>
+const (
+	_CTL_HW  = 6
+	_HW_NCPU = 3
+)
+
+func getncpu() int32 {
+	mib := [2]uint32{_CTL_HW, _HW_NCPU}
+	out := uint32(0)
+	nout := unsafe.Sizeof(out)
+
+	// Fetch hw.ncpu via sysctl.
+	ret := sysctl(&mib[0], 2, (*byte)(unsafe.Pointer(&out)), &nout, nil, 0)
+	if ret >= 0 {
+		return int32(out)
+	}
+	return 1
+}
+
+//go:nosplit
+func semacreate() uintptr {
+	return 1
+}
+
+//go:nosplit
+func semasleep(ns int64) int32 {
+	_g_ := getg()
+
+	// Compute sleep deadline.
+	var tsp *timespec
+	if ns >= 0 {
+		var ts timespec
+		var nsec int32
+		ns += nanotime()
+		ts.set_sec(int64(timediv(ns, 1000000000, &nsec)))
+		ts.set_nsec(nsec)
+		tsp = &ts
+	}
+
+	for {
+		v := atomicload(&_g_.m.waitsemacount)
+		if v > 0 {
+			if cas(&_g_.m.waitsemacount, v, v-1) {
+				return 0 // semaphore acquired
+			}
+			continue
+		}
+
+		// Sleep until woken by semawakeup or timeout; or abort if waitsemacount != 0.
+		//
+		// From OpenBSD's __thrsleep(2) manual:
+		// "The abort argument, if not NULL, points to an int that will
+		// be examined [...] immediately before blocking.  If that int
+		// is non-zero then __thrsleep() will immediately return EINTR
+		// without blocking."
+		ret := thrsleep(uintptr(unsafe.Pointer(&_g_.m.waitsemacount)), _CLOCK_MONOTONIC, tsp, 0, &_g_.m.waitsemacount)
+		if ret == _EWOULDBLOCK {
+			return -1
+		}
+	}
+}
+
+//go:nosplit
+func semawakeup(mp *m) {
+	xadd(&mp.waitsemacount, 1)
+	ret := thrwakeup(uintptr(unsafe.Pointer(&mp.waitsemacount)), 1)
+	if ret != 0 && ret != _ESRCH {
+		// semawakeup can be called on signal stack.
+		systemstack(func() {
+			print("thrwakeup addr=", &mp.waitsemacount, " sem=", mp.waitsemacount, " ret=", ret, "\n")
+		})
+	}
+}
+
+// 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")
+	}
+
+	mp.tls[0] = uintptr(mp.id) // so 386 asm can find it
+
+	param := tforkt{
+		tf_tcb:   unsafe.Pointer(&mp.tls[0]),
+		tf_tid:   (*int32)(unsafe.Pointer(&mp.procid)),
+		tf_stack: uintptr(stk),
+	}
+
+	oset := sigprocmask(_SIG_SETMASK, sigset_all)
+	ret := tfork(&param, unsafe.Sizeof(param), mp, mp.g0, funcPC(mstart))
+	sigprocmask(_SIG_SETMASK, oset)
+
+	if ret < 0 {
+		print("runtime: failed to create new OS thread (have ", mcount()-1, " already; errno=", -ret, ")\n")
+		throw("runtime.newosproc")
+	}
+}
+
+func osinit() {
+	ncpu = getncpu()
+}
+
+var urandom_dev = []byte("/dev/urandom\x00")
+
+//go:nosplit
+func getRandomData(r []byte) {
+	fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
+	n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
+	closefd(fd)
+	extendRandom(r, int(n))
+}
+
+func goenvs() {
+	goenvs_unix()
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
+func mpreinit(mp *m) {
+	mp.gsignal = malg(32 * 1024)
+	mp.gsignal.m = mp
+}
+
+func msigsave(mp *m) {
+	smask := (*uint32)(unsafe.Pointer(&mp.sigmask))
+	if unsafe.Sizeof(*smask) > unsafe.Sizeof(mp.sigmask) {
+		throw("insufficient storage for signal mask")
+	}
+	*smask = sigprocmask(_SIG_BLOCK, 0)
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, can not allocate memory.
+func minit() {
+	_g_ := getg()
+
+	// m.procid is a uint64, but tfork writes an int32. Fix it up.
+	_g_.m.procid = uint64(*(*int32)(unsafe.Pointer(&_g_.m.procid)))
+
+	// Initialize signal handling
+	signalstack(&_g_.m.gsignal.stack)
+
+	// restore signal mask from m.sigmask and unblock essential signals
+	nmask := *(*uint32)(unsafe.Pointer(&_g_.m.sigmask))
+	for i := range sigtable {
+		if sigtable[i].flags&_SigUnblock != 0 {
+			nmask &^= 1 << (uint32(i) - 1)
+		}
+	}
+	sigprocmask(_SIG_SETMASK, nmask)
+}
+
+// Called from dropm to undo the effect of an minit.
+func unminit() {
+	_g_ := getg()
+	smask := *(*uint32)(unsafe.Pointer(&_g_.m.sigmask))
+	sigprocmask(_SIG_SETMASK, smask)
+	signalstack(nil)
+}
+
+func memlimit() uintptr {
+	return 0
+}
+
+func sigtramp()
+
+type sigactiont struct {
+	sa_sigaction uintptr
+	sa_mask      uint32
+	sa_flags     int32
+}
+
+func setsig(i int32, fn uintptr, restart bool) {
+	var sa sigactiont
+	sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
+	if restart {
+		sa.sa_flags |= _SA_RESTART
+	}
+	sa.sa_mask = sigset_all
+	if fn == funcPC(sighandler) {
+		fn = funcPC(sigtramp)
+	}
+	sa.sa_sigaction = fn
+	sigaction(i, &sa, nil)
+}
+
+func setsigstack(i int32) {
+	throw("setsigstack")
+}
+
+func getsig(i int32) uintptr {
+	var sa sigactiont
+	sigaction(i, nil, &sa)
+	if sa.sa_sigaction == funcPC(sigtramp) {
+		return funcPC(sighandler)
+	}
+	return sa.sa_sigaction
+}
+
+func signalstack(s *stack) {
+	var st stackt
+	if s == nil {
+		st.ss_flags = _SS_DISABLE
+	} else {
+		st.ss_sp = s.lo
+		st.ss_size = s.hi - s.lo
+		st.ss_flags = 0
+	}
+	sigaltstack(&st, nil)
+}
+
+func updatesigmask(m sigmask) {
+	sigprocmask(_SIG_SETMASK, m[0])
+}
+
+func unblocksig(sig int32) {
+	mask := uint32(1) << (uint32(sig) - 1)
+	sigprocmask(_SIG_UNBLOCK, mask)
+}
diff --git a/src/runtime/os1_plan9.go b/src/runtime/os1_plan9.go
new file mode 100644
index 0000000..9615b6d
--- /dev/null
+++ b/src/runtime/os1_plan9.go
@@ -0,0 +1,268 @@
+// Copyright 2010 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"
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
+func mpreinit(mp *m) {
+	// Initialize stack and goroutine for note handling.
+	mp.gsignal = malg(32 * 1024)
+	mp.gsignal.m = mp
+	mp.notesig = (*int8)(mallocgc(_ERRMAX, nil, _FlagNoScan))
+	// Initialize stack for handling strings from the
+	// errstr system call, as used in package syscall.
+	mp.errstr = (*byte)(mallocgc(_ERRMAX, nil, _FlagNoScan))
+}
+
+func msigsave(mp *m) {
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, can not allocate memory.
+func minit() {
+	// Mask all SSE floating-point exceptions
+	// when running on the 64-bit kernel.
+	setfpmasks()
+}
+
+// Called from dropm to undo the effect of an minit.
+func unminit() {
+}
+
+var sysstat = []byte("/dev/sysstat\x00")
+
+func getproccount() int32 {
+	var buf [2048]byte
+	fd := open(&sysstat[0], _OREAD, 0)
+	if fd < 0 {
+		return 1
+	}
+	ncpu := int32(0)
+	for {
+		n := read(fd, unsafe.Pointer(&buf), int32(len(buf)))
+		if n <= 0 {
+			break
+		}
+		for i := int32(0); i < n; i++ {
+			if buf[i] == '\n' {
+				ncpu++
+			}
+		}
+	}
+	closefd(fd)
+	if ncpu == 0 {
+		ncpu = 1
+	}
+	return ncpu
+}
+
+var pid = []byte("#c/pid\x00")
+
+func getpid() uint64 {
+	var b [20]byte
+	fd := open(&pid[0], 0, 0)
+	if fd >= 0 {
+		read(fd, unsafe.Pointer(&b), int32(len(b)))
+		closefd(fd)
+	}
+	c := b[:]
+	for c[0] == ' ' || c[0] == '\t' {
+		c = c[1:]
+	}
+	return uint64(_atoi(c))
+}
+
+func osinit() {
+	initBloc()
+	ncpu = getproccount()
+	getg().m.procid = getpid()
+	notify(unsafe.Pointer(funcPC(sigtramp)))
+}
+
+func crash() {
+	notify(nil)
+	*(*int)(nil) = 0
+}
+
+//go:nosplit
+func getRandomData(r []byte) {
+	extendRandom(r, 0)
+}
+
+func goenvs() {
+}
+
+func initsig() {
+}
+
+//go:nosplit
+func osyield() {
+	sleep(0)
+}
+
+//go:nosplit
+func usleep(µs uint32) {
+	ms := int32(µs / 1000)
+	if ms == 0 {
+		ms = 1
+	}
+	sleep(ms)
+}
+
+//go:nosplit
+func nanotime() int64 {
+	var scratch int64
+	ns := nsec(&scratch)
+	// TODO(aram): remove hack after I fix _nsec in the pc64 kernel.
+	if ns == 0 {
+		return scratch
+	}
+	return ns
+}
+
+//go:nosplit
+func itoa(buf []byte, val uint64) []byte {
+	i := len(buf) - 1
+	for val >= 10 {
+		buf[i] = byte(val%10 + '0')
+		i--
+		val /= 10
+	}
+	buf[i] = byte(val + '0')
+	return buf[i:]
+}
+
+var goexits = []byte("go: exit ")
+
+func goexitsall(status *byte) {
+	var buf [_ERRMAX]byte
+	n := copy(buf[:], goexits)
+	n = copy(buf[n:], gostringnocopy(status))
+	pid := getpid()
+	for mp := (*m)(atomicloadp(unsafe.Pointer(&allm))); mp != nil; mp = mp.alllink {
+		if mp.procid != pid {
+			postnote(mp.procid, buf[:])
+		}
+	}
+}
+
+var procdir = []byte("/proc/")
+var notefile = []byte("/note\x00")
+
+func postnote(pid uint64, msg []byte) int {
+	var buf [128]byte
+	var tmp [32]byte
+	n := copy(buf[:], procdir)
+	n += copy(buf[n:], itoa(tmp[:], pid))
+	copy(buf[n:], notefile)
+	fd := open(&buf[0], _OWRITE, 0)
+	if fd < 0 {
+		return -1
+	}
+	len := findnull(&msg[0])
+	if write(uintptr(fd), (unsafe.Pointer)(&msg[0]), int32(len)) != int64(len) {
+		closefd(fd)
+		return -1
+	}
+	closefd(fd)
+	return 0
+}
+
+//go:nosplit
+func exit(e int) {
+	var status []byte
+	if e == 0 {
+		status = []byte("\x00")
+	} else {
+		// build error string
+		var tmp [32]byte
+		status = append(itoa(tmp[:len(tmp)-1], uint64(e)), 0)
+	}
+	goexitsall(&status[0])
+	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")
+	}
+	pid := rfork(_RFPROC | _RFMEM | _RFNOWAIT)
+	if pid < 0 {
+		throw("newosproc: rfork failed")
+	}
+	if pid == 0 {
+		tstart_plan9(mp)
+	}
+}
+
+//go:nosplit
+func semacreate() uintptr {
+	return 1
+}
+
+//go:nosplit
+func semasleep(ns int64) int {
+	_g_ := getg()
+	if ns >= 0 {
+		ms := timediv(ns, 1000000, nil)
+		if ms == 0 {
+			ms = 1
+		}
+		ret := plan9_tsemacquire(&_g_.m.waitsemacount, ms)
+		if ret == 1 {
+			return 0 // success
+		}
+		return -1 // timeout or interrupted
+	}
+	for plan9_semacquire(&_g_.m.waitsemacount, 1) < 0 {
+		// interrupted; try again (c.f. lock_sema.go)
+	}
+	return 0 // success
+}
+
+//go:nosplit
+func semawakeup(mp *m) {
+	plan9_semrelease(&mp.waitsemacount, 1)
+}
+
+//go:nosplit
+func read(fd int32, buf unsafe.Pointer, n int32) int32 {
+	return pread(fd, buf, n, -1)
+}
+
+//go:nosplit
+func write(fd uintptr, buf unsafe.Pointer, n int32) int64 {
+	return int64(pwrite(int32(fd), buf, n, -1))
+}
+
+func memlimit() uint64 {
+	return 0
+}
+
+var _badsignal = []byte("runtime: signal received on thread not created by Go.\n")
+
+// This runs on a foreign stack, without an m or a g.  No stack split.
+//go:nosplit
+func badsignal2() {
+	pwrite(2, unsafe.Pointer(&_badsignal[0]), int32(len(_badsignal)), -1)
+	exits(&_badsignal[0])
+}
+
+func raisebadsignal(sig int32) {
+	badsignal2()
+}
+
+func _atoi(b []byte) int {
+	n := 0
+	for len(b) > 0 && '0' <= b[0] && b[0] <= '9' {
+		n = n*10 + int(b[0]) - '0'
+		b = b[1:]
+	}
+	return n
+}
diff --git a/src/runtime/os1_windows.go b/src/runtime/os1_windows.go
new file mode 100644
index 0000000..f608b4a
--- /dev/null
+++ b/src/runtime/os1_windows.go
@@ -0,0 +1,540 @@
+// 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"
+)
+
+//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._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.
+	// All these variables are set by the Windows executable
+	// loader before the Go program starts.
+	_AddVectoredExceptionHandler,
+	_CloseHandle,
+	_CreateEventA,
+	_CreateIoCompletionPort,
+	_CreateThread,
+	_CreateWaitableTimerA,
+	_CryptAcquireContextW,
+	_CryptGenRandom,
+	_CryptReleaseContext,
+	_DuplicateHandle,
+	_ExitProcess,
+	_FreeEnvironmentStringsW,
+	_GetEnvironmentStringsW,
+	_GetProcAddress,
+	_GetQueuedCompletionStatus,
+	_GetStdHandle,
+	_GetSystemInfo,
+	_GetThreadContext,
+	_LoadLibraryW,
+	_LoadLibraryA,
+	_NtWaitForSingleObject,
+	_ResumeThread,
+	_SetConsoleCtrlHandler,
+	_SetErrorMode,
+	_SetEvent,
+	_SetProcessPriorityBoost,
+	_SetThreadPriority,
+	_SetUnhandledExceptionFilter,
+	_SetWaitableTimer,
+	_SuspendThread,
+	_VirtualAlloc,
+	_VirtualFree,
+	_WSAGetOverlappedResult,
+	_WaitForSingleObject,
+	_WriteFile,
+	_timeBeginPeriod stdFunction
+
+	// Following syscalls are only available on some Windows PCs.
+	// We will load syscalls, if available, before using them.
+	_AddVectoredContinueHandler,
+	_GetQueuedCompletionStatusEx stdFunction
+)
+
+// Call a Windows function with stdcall conventions,
+// and switch to os stack during the call.
+func asmstdcall(fn unsafe.Pointer)
+
+var asmstdcallAddr unsafe.Pointer
+
+func loadOptionalSyscalls() {
+	var buf [50]byte // large enough for longest string
+	strtoptr := func(s string) uintptr {
+		buf[copy(buf[:], s)] = 0 // nil-terminated for OS
+		return uintptr(noescape(unsafe.Pointer(&buf[0])))
+	}
+	l := stdcall1(_LoadLibraryA, strtoptr("kernel32.dll"))
+	findfunc := func(name string) stdFunction {
+		f := stdcall2(_GetProcAddress, l, strtoptr(name))
+		return stdFunction(unsafe.Pointer(f))
+	}
+	if l != 0 {
+		_AddVectoredContinueHandler = findfunc("AddVectoredContinueHandler")
+		_GetQueuedCompletionStatusEx = findfunc("GetQueuedCompletionStatusEx")
+	}
+}
+
+//go:nosplit
+func getLoadLibrary() uintptr {
+	return uintptr(unsafe.Pointer(_LoadLibraryW))
+}
+
+//go:nosplit
+func getGetProcAddress() uintptr {
+	return uintptr(unsafe.Pointer(_GetProcAddress))
+}
+
+func getproccount() int32 {
+	var info systeminfo
+	stdcall1(_GetSystemInfo, uintptr(unsafe.Pointer(&info)))
+	return int32(info.dwnumberofprocessors)
+}
+
+const (
+	currentProcess = ^uintptr(0) // -1 = current process
+	currentThread  = ^uintptr(1) // -2 = current thread
+)
+
+// in sys_windows_386.s and sys_windows_amd64.s
+func externalthreadhandler()
+
+func osinit() {
+	asmstdcallAddr = unsafe.Pointer(funcPC(asmstdcall))
+
+	setBadSignalMsg()
+
+	loadOptionalSyscalls()
+
+	disableWER()
+
+	externalthreadhandlerp = funcPC(externalthreadhandler)
+
+	initExceptionHandler()
+
+	stdcall2(_SetConsoleCtrlHandler, funcPC(ctrlhandler), 1)
+
+	stdcall1(_timeBeginPeriod, 1)
+
+	ncpu = getproccount()
+
+	// Windows dynamic priority boosting assumes that a process has different types
+	// of dedicated threads -- GUI, IO, computational, etc. Go processes use
+	// equivalent threads that all do a mix of GUI, IO, computations, etc.
+	// In such context dynamic priority boosting does nothing but harm, so we turn it off.
+	stdcall2(_SetProcessPriorityBoost, currentProcess, 1)
+}
+
+//go:nosplit
+func getRandomData(r []byte) {
+	const (
+		prov_rsa_full       = 1
+		crypt_verifycontext = 0xF0000000
+	)
+	var handle uintptr
+	n := 0
+	if stdcall5(_CryptAcquireContextW, uintptr(unsafe.Pointer(&handle)), 0, 0, prov_rsa_full, crypt_verifycontext) != 0 {
+		if stdcall3(_CryptGenRandom, handle, uintptr(len(r)), uintptr(unsafe.Pointer(&r[0]))) != 0 {
+			n = len(r)
+		}
+		stdcall2(_CryptReleaseContext, handle, 0)
+	}
+	extendRandom(r, n)
+}
+
+func goenvs() {
+	// strings is a pointer to environment variable pairs in the form:
+	//     "envA=valA\x00envB=valB\x00\x00" (in UTF-16)
+	// Two consecutive zero bytes end the list.
+	strings := unsafe.Pointer(stdcall0(_GetEnvironmentStringsW))
+	p := (*[1 << 24]uint16)(strings)[:]
+
+	n := 0
+	for from, i := 0, 0; true; i++ {
+		if p[i] == 0 {
+			// empty string marks the end
+			if i == from {
+				break
+			}
+			from = i + 1
+			n++
+		}
+	}
+	envs = make([]string, n)
+
+	for i := range envs {
+		envs[i] = gostringw(&p[0])
+		for p[0] != 0 {
+			p = p[1:]
+		}
+		p = p[1:] // skip nil byte
+	}
+
+	stdcall1(_FreeEnvironmentStringsW, uintptr(strings))
+}
+
+//go:nosplit
+func exit(code int32) {
+	stdcall1(_ExitProcess, uintptr(code))
+}
+
+//go:nosplit
+func write(fd uintptr, buf unsafe.Pointer, n int32) int32 {
+	const (
+		_STD_OUTPUT_HANDLE = ^uintptr(10) // -11
+		_STD_ERROR_HANDLE  = ^uintptr(11) // -12
+	)
+	var handle uintptr
+	switch fd {
+	case 1:
+		handle = stdcall1(_GetStdHandle, _STD_OUTPUT_HANDLE)
+	case 2:
+		handle = stdcall1(_GetStdHandle, _STD_ERROR_HANDLE)
+	default:
+		// assume fd is real windows handle.
+		handle = fd
+	}
+	var written uint32
+	stdcall5(_WriteFile, handle, uintptr(buf), uintptr(n), uintptr(unsafe.Pointer(&written)), 0)
+	return int32(written)
+}
+
+//go:nosplit
+func semasleep(ns int64) int32 {
+	// store ms in ns to save stack space
+	if ns < 0 {
+		ns = _INFINITE
+	} else {
+		ns = int64(timediv(ns, 1000000, nil))
+		if ns == 0 {
+			ns = 1
+		}
+	}
+	if stdcall2(_WaitForSingleObject, getg().m.waitsema, uintptr(ns)) != 0 {
+		return -1 // timeout
+	}
+	return 0
+}
+
+//go:nosplit
+func semawakeup(mp *m) {
+	stdcall1(_SetEvent, mp.waitsema)
+}
+
+//go:nosplit
+func semacreate() uintptr {
+	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,
+		funcPC(tstart_stdcall), uintptr(unsafe.Pointer(mp)),
+		_STACK_SIZE_PARAM_IS_A_RESERVATION, 0)
+	if thandle == 0 {
+		print("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", getlasterror(), ")\n")
+		throw("runtime.newosproc")
+	}
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
+func mpreinit(mp *m) {
+}
+
+func msigsave(mp *m) {
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, can not allocate memory.
+func minit() {
+	var thandle uintptr
+	stdcall7(_DuplicateHandle, currentProcess, currentThread, currentProcess, uintptr(unsafe.Pointer(&thandle)), 0, 0, _DUPLICATE_SAME_ACCESS)
+	atomicstoreuintptr(&getg().m.thread, thandle)
+}
+
+// Called from dropm to undo the effect of an minit.
+func unminit() {
+	tp := &getg().m.thread
+	stdcall1(_CloseHandle, *tp)
+	*tp = 0
+}
+
+// Described in http://www.dcl.hpi.uni-potsdam.de/research/WRK/2007/08/getting-os-information-the-kuser_shared_data-structure/
+type _KSYSTEM_TIME struct {
+	LowPart   uint32
+	High1Time int32
+	High2Time int32
+}
+
+const (
+	_INTERRUPT_TIME = 0x7ffe0008
+	_SYSTEM_TIME    = 0x7ffe0014
+)
+
+//go:nosplit
+func systime(addr uintptr) int64 {
+	timeaddr := (*_KSYSTEM_TIME)(unsafe.Pointer(addr))
+
+	var t _KSYSTEM_TIME
+	for i := 1; i < 10000; i++ {
+		// these fields must be read in that order (see URL above)
+		t.High1Time = timeaddr.High1Time
+		t.LowPart = timeaddr.LowPart
+		t.High2Time = timeaddr.High2Time
+		if t.High1Time == t.High2Time {
+			return int64(t.High1Time)<<32 | int64(t.LowPart)
+		}
+		if (i % 100) == 0 {
+			osyield()
+		}
+	}
+	systemstack(func() {
+		throw("interrupt/system time is changing too fast")
+	})
+	return 0
+}
+
+//go:nosplit
+func unixnano() int64 {
+	return (systime(_SYSTEM_TIME) - 116444736000000000) * 100
+}
+
+//go:nosplit
+func nanotime() int64 {
+	return systime(_INTERRUPT_TIME) * 100
+}
+
+// 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()
+	mp := gp.m
+	mp.libcall.fn = uintptr(unsafe.Pointer(fn))
+
+	if mp.profilehz != 0 {
+		// leave pc/sp for cpu profiler
+		mp.libcallg.set(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
+		mp.libcallsp = getcallersp(unsafe.Pointer(&fn))
+	}
+	asmcgocall(asmstdcallAddr, unsafe.Pointer(&mp.libcall))
+	mp.libcallsp = 0
+	return mp.libcall.r1
+}
+
+//go:nosplit
+func stdcall0(fn stdFunction) uintptr {
+	mp := getg().m
+	mp.libcall.n = 0
+	mp.libcall.args = uintptr(noescape(unsafe.Pointer(&fn))) // it's unused but must be non-nil, otherwise crashes
+	return stdcall(fn)
+}
+
+//go:nosplit
+func stdcall1(fn stdFunction, a0 uintptr) uintptr {
+	mp := getg().m
+	mp.libcall.n = 1
+	mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
+	return stdcall(fn)
+}
+
+//go:nosplit
+func stdcall2(fn stdFunction, a0, a1 uintptr) uintptr {
+	mp := getg().m
+	mp.libcall.n = 2
+	mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
+	return stdcall(fn)
+}
+
+//go:nosplit
+func stdcall3(fn stdFunction, a0, a1, a2 uintptr) uintptr {
+	mp := getg().m
+	mp.libcall.n = 3
+	mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
+	return stdcall(fn)
+}
+
+//go:nosplit
+func stdcall4(fn stdFunction, a0, a1, a2, a3 uintptr) uintptr {
+	mp := getg().m
+	mp.libcall.n = 4
+	mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
+	return stdcall(fn)
+}
+
+//go:nosplit
+func stdcall5(fn stdFunction, a0, a1, a2, a3, a4 uintptr) uintptr {
+	mp := getg().m
+	mp.libcall.n = 5
+	mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
+	return stdcall(fn)
+}
+
+//go:nosplit
+func stdcall6(fn stdFunction, a0, a1, a2, a3, a4, a5 uintptr) uintptr {
+	mp := getg().m
+	mp.libcall.n = 6
+	mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
+	return stdcall(fn)
+}
+
+//go:nosplit
+func stdcall7(fn stdFunction, a0, a1, a2, a3, a4, a5, a6 uintptr) uintptr {
+	mp := getg().m
+	mp.libcall.n = 7
+	mp.libcall.args = uintptr(noescape(unsafe.Pointer(&a0)))
+	return stdcall(fn)
+}
+
+// in sys_windows_386.s and sys_windows_amd64.s
+func usleep1(usec uint32)
+
+//go:nosplit
+func osyield() {
+	usleep1(1)
+}
+
+//go:nosplit
+func usleep(us uint32) {
+	// Have 1us units; want 100ns units.
+	usleep1(10 * us)
+}
+
+func ctrlhandler1(_type uint32) uint32 {
+	var s uint32
+
+	switch _type {
+	case _CTRL_C_EVENT, _CTRL_BREAK_EVENT:
+		s = _SIGINT
+	default:
+		return 0
+	}
+
+	if sigsend(s) {
+		return 1
+	}
+	exit(2) // SIGINT, SIGTERM, etc
+	return 0
+}
+
+// in sys_windows_386.s and sys_windows_amd64.s
+func profileloop()
+
+var profiletimer uintptr
+
+func profilem(mp *m) {
+	var r *context
+	rbuf := make([]byte, unsafe.Sizeof(*r)+15)
+
+	tls := &mp.tls[0]
+	if mp == &m0 {
+		tls = &tls0[0]
+	}
+	gp := *((**g)(unsafe.Pointer(tls)))
+
+	// align Context to 16 bytes
+	r = (*context)(unsafe.Pointer((uintptr(unsafe.Pointer(&rbuf[15]))) &^ 15))
+	r.contextflags = _CONTEXT_CONTROL
+	stdcall2(_GetThreadContext, mp.thread, uintptr(unsafe.Pointer(r)))
+	sigprof(r.ip(), r.sp(), 0, gp, mp)
+}
+
+func profileloop1(param uintptr) uint32 {
+	stdcall2(_SetThreadPriority, currentThread, _THREAD_PRIORITY_HIGHEST)
+
+	for {
+		stdcall2(_WaitForSingleObject, profiletimer, _INFINITE)
+		first := (*m)(atomicloadp(unsafe.Pointer(&allm)))
+		for mp := first; mp != nil; mp = mp.alllink {
+			thread := atomicloaduintptr(&mp.thread)
+			// Do not profile threads blocked on Notes,
+			// this includes idle worker threads,
+			// idle timer thread, idle heap scavenger, etc.
+			if thread == 0 || mp.profilehz == 0 || mp.blocked {
+				continue
+			}
+			stdcall1(_SuspendThread, thread)
+			if mp.profilehz != 0 && !mp.blocked {
+				profilem(mp)
+			}
+			stdcall1(_ResumeThread, thread)
+		}
+	}
+}
+
+var cpuprofilerlock mutex
+
+func resetcpuprofiler(hz int32) {
+	lock(&cpuprofilerlock)
+	if profiletimer == 0 {
+		timer := stdcall3(_CreateWaitableTimerA, 0, 0, 0)
+		atomicstoreuintptr(&profiletimer, timer)
+		thread := stdcall6(_CreateThread, 0, 0, funcPC(profileloop), 0, 0, 0)
+		stdcall2(_SetThreadPriority, thread, _THREAD_PRIORITY_HIGHEST)
+		stdcall1(_CloseHandle, thread)
+	}
+	unlock(&cpuprofilerlock)
+
+	ms := int32(0)
+	due := ^int64(^uint64(1 << 63))
+	if hz > 0 {
+		ms = 1000 / hz
+		if ms == 0 {
+			ms = 1
+		}
+		due = int64(ms) * -10000
+	}
+	stdcall6(_SetWaitableTimer, profiletimer, uintptr(unsafe.Pointer(&due)), uintptr(ms), 0, 0, 0)
+	atomicstore((*uint32)(unsafe.Pointer(&getg().m.profilehz)), uint32(hz))
+}
+
+func memlimit() uintptr {
+	return 0
+}
diff --git a/src/runtime/os2_darwin.go b/src/runtime/os2_darwin.go
new file mode 100644
index 0000000..542bd74
--- /dev/null
+++ b/src/runtime/os2_darwin.go
@@ -0,0 +1,14 @@
+// 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
+
+const (
+	_NSIG        = 32
+	_SI_USER     = 0 /* empirically true, but not what headers say */
+	_SIG_BLOCK   = 1
+	_SIG_UNBLOCK = 2
+	_SIG_SETMASK = 3
+	_SS_DISABLE  = 4
+)
diff --git a/src/runtime/os2_dragonfly.go b/src/runtime/os2_dragonfly.go
new file mode 100644
index 0000000..ccad82f
--- /dev/null
+++ b/src/runtime/os2_dragonfly.go
@@ -0,0 +1,15 @@
+// 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 (
+	_NSIG        = 33
+	_SI_USER     = 0x10001
+	_SS_DISABLE  = 4
+	_RLIMIT_AS   = 10
+	_SIG_BLOCK   = 1
+	_SIG_UNBLOCK = 2
+	_SIG_SETMASK = 3
+)
diff --git a/src/runtime/os2_freebsd.go b/src/runtime/os2_freebsd.go
new file mode 100644
index 0000000..84ab715
--- /dev/null
+++ b/src/runtime/os2_freebsd.go
@@ -0,0 +1,15 @@
+// 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 (
+	_SS_DISABLE  = 4
+	_NSIG        = 33
+	_SI_USER     = 0x10001
+	_RLIMIT_AS   = 10
+	_SIG_BLOCK   = 1
+	_SIG_UNBLOCK = 2
+	_SIG_SETMASK = 3
+)
diff --git a/src/runtime/os2_linux.go b/src/runtime/os2_linux.go
new file mode 100644
index 0000000..71f36eb
--- /dev/null
+++ b/src/runtime/os2_linux.go
@@ -0,0 +1,25 @@
+// 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
+
+const (
+	_SS_DISABLE  = 2
+	_NSIG        = 65
+	_SI_USER     = 0
+	_SIG_BLOCK   = 0
+	_SIG_UNBLOCK = 1
+	_SIG_SETMASK = 2
+	_RLIMIT_AS   = 9
+)
+
+// It's hard to tease out exactly how big a Sigset is, but
+// rt_sigprocmask crashes if we get it wrong, so if binaries
+// are running, this is right.
+type sigset [2]uint32
+
+type rlimit struct {
+	rlim_cur uintptr
+	rlim_max uintptr
+}
diff --git a/src/runtime/os2_nacl.go b/src/runtime/os2_nacl.go
new file mode 100644
index 0000000..0c91e0f
--- /dev/null
+++ b/src/runtime/os2_nacl.go
@@ -0,0 +1,154 @@
+// 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
+
+const (
+	_NSIG    = 32
+	_SI_USER = 1
+
+	// native_client/src/trusted/service_runtime/include/sys/errno.h
+	// The errors are mainly copied from Linux.
+	_EPERM           = 1        /* Operation not permitted */
+	_ENOENT          = 2        /* No such file or directory */
+	_ESRCH           = 3        /* No such process */
+	_EINTR           = 4        /* Interrupted system call */
+	_EIO             = 5        /* I/O error */
+	_ENXIO           = 6        /* No such device or address */
+	_E2BIG           = 7        /* Argument list too long */
+	_ENOEXEC         = 8        /* Exec format error */
+	_EBADF           = 9        /* Bad file number */
+	_ECHILD          = 10       /* No child processes */
+	_EAGAIN          = 11       /* Try again */
+	_ENOMEM          = 12       /* Out of memory */
+	_EACCES          = 13       /* Permission denied */
+	_EFAULT          = 14       /* Bad address */
+	_EBUSY           = 16       /* Device or resource busy */
+	_EEXIST          = 17       /* File exists */
+	_EXDEV           = 18       /* Cross-device link */
+	_ENODEV          = 19       /* No such device */
+	_ENOTDIR         = 20       /* Not a directory */
+	_EISDIR          = 21       /* Is a directory */
+	_EINVAL          = 22       /* Invalid argument */
+	_ENFILE          = 23       /* File table overflow */
+	_EMFILE          = 24       /* Too many open files */
+	_ENOTTY          = 25       /* Not a typewriter */
+	_EFBIG           = 27       /* File too large */
+	_ENOSPC          = 28       /* No space left on device */
+	_ESPIPE          = 29       /* Illegal seek */
+	_EROFS           = 30       /* Read-only file system */
+	_EMLINK          = 31       /* Too many links */
+	_EPIPE           = 32       /* Broken pipe */
+	_ENAMETOOLONG    = 36       /* File name too long */
+	_ENOSYS          = 38       /* Function not implemented */
+	_EDQUOT          = 122      /* Quota exceeded */
+	_EDOM            = 33       /* Math arg out of domain of func */
+	_ERANGE          = 34       /* Math result not representable */
+	_EDEADLK         = 35       /* Deadlock condition */
+	_ENOLCK          = 37       /* No record locks available */
+	_ENOTEMPTY       = 39       /* Directory not empty */
+	_ELOOP           = 40       /* Too many symbolic links */
+	_ENOMSG          = 42       /* No message of desired type */
+	_EIDRM           = 43       /* Identifier removed */
+	_ECHRNG          = 44       /* Channel number out of range */
+	_EL2NSYNC        = 45       /* Level 2 not synchronized */
+	_EL3HLT          = 46       /* Level 3 halted */
+	_EL3RST          = 47       /* Level 3 reset */
+	_ELNRNG          = 48       /* Link number out of range */
+	_EUNATCH         = 49       /* Protocol driver not attached */
+	_ENOCSI          = 50       /* No CSI structure available */
+	_EL2HLT          = 51       /* Level 2 halted */
+	_EBADE           = 52       /* Invalid exchange */
+	_EBADR           = 53       /* Invalid request descriptor */
+	_EXFULL          = 54       /* Exchange full */
+	_ENOANO          = 55       /* No anode */
+	_EBADRQC         = 56       /* Invalid request code */
+	_EBADSLT         = 57       /* Invalid slot */
+	_EDEADLOCK       = _EDEADLK /* File locking deadlock error */
+	_EBFONT          = 59       /* Bad font file fmt */
+	_ENOSTR          = 60       /* Device not a stream */
+	_ENODATA         = 61       /* No data (for no delay io) */
+	_ETIME           = 62       /* Timer expired */
+	_ENOSR           = 63       /* Out of streams resources */
+	_ENONET          = 64       /* Machine is not on the network */
+	_ENOPKG          = 65       /* Package not installed */
+	_EREMOTE         = 66       /* The object is remote */
+	_ENOLINK         = 67       /* The link has been severed */
+	_EADV            = 68       /* Advertise error */
+	_ESRMNT          = 69       /* Srmount error */
+	_ECOMM           = 70       /* Communication error on send */
+	_EPROTO          = 71       /* Protocol error */
+	_EMULTIHOP       = 72       /* Multihop attempted */
+	_EDOTDOT         = 73       /* Cross mount point (not really error) */
+	_EBADMSG         = 74       /* Trying to read unreadable message */
+	_EOVERFLOW       = 75       /* Value too large for defined data type */
+	_ENOTUNIQ        = 76       /* Given log. name not unique */
+	_EBADFD          = 77       /* f.d. invalid for this operation */
+	_EREMCHG         = 78       /* Remote address changed */
+	_ELIBACC         = 79       /* Can't access a needed shared lib */
+	_ELIBBAD         = 80       /* Accessing a corrupted shared lib */
+	_ELIBSCN         = 81       /* .lib section in a.out corrupted */
+	_ELIBMAX         = 82       /* Attempting to link in too many libs */
+	_ELIBEXEC        = 83       /* Attempting to exec a shared library */
+	_EILSEQ          = 84
+	_EUSERS          = 87
+	_ENOTSOCK        = 88  /* Socket operation on non-socket */
+	_EDESTADDRREQ    = 89  /* Destination address required */
+	_EMSGSIZE        = 90  /* Message too long */
+	_EPROTOTYPE      = 91  /* Protocol wrong type for socket */
+	_ENOPROTOOPT     = 92  /* Protocol not available */
+	_EPROTONOSUPPORT = 93  /* Unknown protocol */
+	_ESOCKTNOSUPPORT = 94  /* Socket type not supported */
+	_EOPNOTSUPP      = 95  /* Operation not supported on transport endpoint */
+	_EPFNOSUPPORT    = 96  /* Protocol family not supported */
+	_EAFNOSUPPORT    = 97  /* Address family not supported by protocol family */
+	_EADDRINUSE      = 98  /* Address already in use */
+	_EADDRNOTAVAIL   = 99  /* Address not available */
+	_ENETDOWN        = 100 /* Network interface is not configured */
+	_ENETUNREACH     = 101 /* Network is unreachable */
+	_ENETRESET       = 102
+	_ECONNABORTED    = 103 /* Connection aborted */
+	_ECONNRESET      = 104 /* Connection reset by peer */
+	_ENOBUFS         = 105 /* No buffer space available */
+	_EISCONN         = 106 /* Socket is already connected */
+	_ENOTCONN        = 107 /* Socket is not connected */
+	_ESHUTDOWN       = 108 /* Can't send after socket shutdown */
+	_ETOOMANYREFS    = 109
+	_ETIMEDOUT       = 110 /* Connection timed out */
+	_ECONNREFUSED    = 111 /* Connection refused */
+	_EHOSTDOWN       = 112 /* Host is down */
+	_EHOSTUNREACH    = 113 /* Host is unreachable */
+	_EALREADY        = 114 /* Socket already connected */
+	_EINPROGRESS     = 115 /* Connection already in progress */
+	_ESTALE          = 116
+	_ENOTSUP         = _EOPNOTSUPP /* Not supported */
+	_ENOMEDIUM       = 123         /* No medium (in tape drive) */
+	_ECANCELED       = 125         /* Operation canceled. */
+	_ELBIN           = 2048        /* Inode is remote (not really error) */
+	_EFTYPE          = 2049        /* Inappropriate file type or format */
+	_ENMFILE         = 2050        /* No more files */
+	_EPROCLIM        = 2051
+	_ENOSHARE        = 2052    /* No such host or network path */
+	_ECASECLASH      = 2053    /* Filename exists with different case */
+	_EWOULDBLOCK     = _EAGAIN /* Operation would block */
+
+	// native_client/src/trusted/service_runtime/include/bits/mman.h.
+	// NOTE: DO NOT USE native_client/src/shared/imc/nacl_imc_c.h.
+	// Those MAP_*values are different from these.
+	_PROT_NONE  = 0x0
+	_PROT_READ  = 0x1
+	_PROT_WRITE = 0x2
+	_PROT_EXEC  = 0x4
+
+	_MAP_SHARED  = 0x1
+	_MAP_PRIVATE = 0x2
+	_MAP_FIXED   = 0x10
+	_MAP_ANON    = 0x20
+
+	_MADV_FREE  = 0
+	_SIGFPE     = 8
+	_FPE_INTDIV = 0
+)
+
+type siginfo struct{}
diff --git a/src/runtime/os2_netbsd.go b/src/runtime/os2_netbsd.go
new file mode 100644
index 0000000..46576b9
--- /dev/null
+++ b/src/runtime/os2_netbsd.go
@@ -0,0 +1,18 @@
+// Copyright 2010 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 (
+	_SS_DISABLE  = 4
+	_SIG_BLOCK   = 1
+	_SIG_UNBLOCK = 2
+	_SIG_SETMASK = 3
+	_NSIG        = 33
+	_SI_USER     = 0
+
+	// From NetBSD's <sys/ucontext.h>
+	_UC_SIGMASK = 0x01
+	_UC_CPU     = 0x04
+)
diff --git a/src/runtime/os2_openbsd.go b/src/runtime/os2_openbsd.go
new file mode 100644
index 0000000..1e785ad
--- /dev/null
+++ b/src/runtime/os2_openbsd.go
@@ -0,0 +1,14 @@
+// Copyright 2010 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 (
+	_SS_DISABLE  = 4
+	_SIG_BLOCK   = 1
+	_SIG_UNBLOCK = 2
+	_SIG_SETMASK = 3
+	_NSIG        = 33
+	_SI_USER     = 0
+)
diff --git a/src/runtime/os2_plan9.go b/src/runtime/os2_plan9.go
new file mode 100644
index 0000000..58fb2be
--- /dev/null
+++ b/src/runtime/os2_plan9.go
@@ -0,0 +1,74 @@
+// Copyright 2010 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.
+
+// Plan 9-specific system calls
+
+package runtime
+
+// open
+const (
+	_OREAD   = 0
+	_OWRITE  = 1
+	_ORDWR   = 2
+	_OEXEC   = 3
+	_OTRUNC  = 16
+	_OCEXEC  = 32
+	_ORCLOSE = 64
+	_OEXCL   = 0x1000
+)
+
+// rfork
+const (
+	_RFNAMEG  = 1 << 0
+	_RFENVG   = 1 << 1
+	_RFFDG    = 1 << 2
+	_RFNOTEG  = 1 << 3
+	_RFPROC   = 1 << 4
+	_RFMEM    = 1 << 5
+	_RFNOWAIT = 1 << 6
+	_RFCNAMEG = 1 << 10
+	_RFCENVG  = 1 << 11
+	_RFCFDG   = 1 << 12
+	_RFREND   = 1 << 13
+	_RFNOMNT  = 1 << 14
+)
+
+// notify
+const (
+	_NCONT = 0
+	_NDFLT = 1
+)
+
+type uinptr _Plink
+
+type tos struct {
+	prof struct { // Per process profiling
+		pp    *_Plink // known to be 0(ptr)
+		next  *_Plink // known to be 4(ptr)
+		last  *_Plink
+		first *_Plink
+		pid   uint32
+		what  uint32
+	}
+	cyclefreq uint64 // cycle clock frequency if there is one, 0 otherwise
+	kcycles   int64  // cycles spent in kernel
+	pcycles   int64  // cycles spent in process (kernel + user)
+	pid       uint32 // might as well put the pid here
+	clock     uint32
+	// top of stack is here
+}
+
+const (
+	_NSIG   = 14  // number of signals in sigtable array
+	_ERRMAX = 128 // max length of note string
+
+	// Notes in runtime·sigtab that are handled by runtime·sigpanic.
+	_SIGRFAULT = 2
+	_SIGWFAULT = 3
+	_SIGINTDIV = 4
+	_SIGFLOAT  = 5
+	_SIGTRAP   = 6
+	_SIGPROF   = 0 // dummy value defined for badsignal
+	_SIGQUIT   = 0 // dummy value defined for sighandler
+)
diff --git a/src/runtime/os2_solaris.go b/src/runtime/os2_solaris.go
new file mode 100644
index 0000000..f5c0c83
--- /dev/null
+++ b/src/runtime/os2_solaris.go
@@ -0,0 +1,14 @@
+// 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
+
+const (
+	_SS_DISABLE  = 2
+	_SIG_UNBLOCK = 2
+	_SIG_SETMASK = 3
+	_NSIG        = 73 /* number of signals in sigtable array */
+	_SI_USER     = 0
+	_RLIMIT_AS   = 10
+)
diff --git a/src/runtime/os2_windows.go b/src/runtime/os2_windows.go
new file mode 100644
index 0000000..a867dfe
--- /dev/null
+++ b/src/runtime/os2_windows.go
@@ -0,0 +1,19 @@
+// 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
+
+func getlasterror() uint32
+func setlasterror(err uint32)
+
+// Function to be called by windows CreateThread
+// to start new os thread.
+func tstart_stdcall(newm *m) uint32
+
+func ctrlhandler(_type uint32) uint32
+
+// TODO(brainman): should not need those
+const (
+	_NSIG = 65
+)
diff --git a/src/runtime/os3_plan9.go b/src/runtime/os3_plan9.go
new file mode 100644
index 0000000..03e9410
--- /dev/null
+++ b/src/runtime/os3_plan9.go
@@ -0,0 +1,128 @@
+// Copyright 2010 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"
+
+// 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
+	var docrash bool
+	var sig int
+	var flags int
+
+	c := &sigctxt{_ureg}
+	notestr := gostringnocopy(note)
+
+	// The kernel will never pass us a nil note or ureg so we probably
+	// made a mistake somewhere in sigtramp.
+	if _ureg == nil || note == nil {
+		print("sighandler: ureg ", _ureg, " note ", note, "\n")
+		goto Throw
+	}
+	// Check that the note is no more than ERRMAX bytes (including
+	// the trailing NUL). We should never receive a longer note.
+	if len(notestr) > _ERRMAX-1 {
+		print("sighandler: note is longer than ERRMAX\n")
+		goto Throw
+	}
+	// See if the note matches one of the patterns in sigtab.
+	// Notes that do not match any pattern can be handled at a higher
+	// level by the program but will otherwise be ignored.
+	flags = _SigNotify
+	for sig, t = range sigtable {
+		if hasprefix(notestr, t.name) {
+			flags = t.flags
+			break
+		}
+	}
+	if flags&_SigGoExit != 0 {
+		exits((*byte)(add(unsafe.Pointer(note), 9))) // Strip "go: exit " prefix.
+	}
+	if flags&_SigPanic != 0 {
+		// Copy the error string from sigtramp's stack into m->notesig so
+		// we can reliably access it from the panic routines.
+		memmove(unsafe.Pointer(_g_.m.notesig), unsafe.Pointer(note), uintptr(len(notestr)+1))
+		gp.sig = uint32(sig)
+		gp.sigpc = c.pc()
+
+		pc := uintptr(c.pc())
+		sp := uintptr(c.sp())
+
+		// If we don't recognize the PC as code
+		// but we do recognize the top pointer on the stack as code,
+		// then assume this was a call to non-code and treat like
+		// pc == 0, to make unwinding show the context.
+		if pc != 0 && findfunc(pc) == nil && findfunc(*(*uintptr)(unsafe.Pointer(sp))) != nil {
+			pc = 0
+		}
+
+		// Only push sigpanic if PC != 0.
+		//
+		// If PC == 0, probably panicked because of a call to a nil func.
+		// Not pushing that onto SP will make the trace look like a call
+		// to sigpanic instead. (Otherwise the trace will end at
+		// sigpanic and we won't get to see who faulted).
+		if pc != 0 {
+			if regSize > ptrSize {
+				sp -= ptrSize
+				*(*uintptr)(unsafe.Pointer(sp)) = 0
+			}
+			sp -= ptrSize
+			*(*uintptr)(unsafe.Pointer(sp)) = pc
+			c.setsp(sp)
+		}
+		c.setpc(funcPC(sigpanic))
+		return _NCONT
+	}
+	if flags&_SigNotify != 0 {
+		if sendNote(note) {
+			return _NCONT
+		}
+	}
+	if flags&_SigKill != 0 {
+		goto Exit
+	}
+	if flags&_SigThrow == 0 {
+		return _NCONT
+	}
+Throw:
+	_g_.m.throwing = 1
+	_g_.m.caughtsig.set(gp)
+	startpanic()
+	print(notestr, "\n")
+	print("PC=", hex(c.pc()), "\n")
+	print("\n")
+	if gotraceback(&docrash) > 0 {
+		goroutineheader(gp)
+		tracebacktrap(c.pc(), c.sp(), 0, gp)
+		tracebackothers(gp)
+		print("\n")
+		dumpregs(_ureg)
+	}
+	if docrash {
+		crash()
+	}
+Exit:
+	goexitsall(note)
+	exits(note)
+	return _NDFLT // not reached
+}
+
+func sigenable(sig uint32) {
+}
+
+func sigdisable(sig uint32) {
+}
+
+func sigignore(sig uint32) {
+}
+
+func resetcpuprofiler(hz int32) {
+	// TODO: Enable profiling interrupts.
+	getg().m.profilehz = hz
+}
diff --git a/src/runtime/os3_solaris.go b/src/runtime/os3_solaris.go
new file mode 100644
index 0000000..792188f
--- /dev/null
+++ b/src/runtime/os3_solaris.go
@@ -0,0 +1,529 @@
+// 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
+
+import "unsafe"
+
+//go:cgo_export_dynamic runtime.end _end
+//go:cgo_export_dynamic runtime.etext _etext
+//go:cgo_export_dynamic runtime.edata _edata
+
+//go:cgo_import_dynamic libc____errno ___errno "libc.so"
+//go:cgo_import_dynamic libc_clock_gettime clock_gettime "libc.so"
+//go:cgo_import_dynamic libc_close close "libc.so"
+//go:cgo_import_dynamic libc_exit exit "libc.so"
+//go:cgo_import_dynamic libc_fstat fstat "libc.so"
+//go:cgo_import_dynamic libc_getcontext getcontext "libc.so"
+//go:cgo_import_dynamic libc_getrlimit getrlimit "libc.so"
+//go:cgo_import_dynamic libc_kill kill "libc.so"
+//go:cgo_import_dynamic libc_madvise madvise "libc.so"
+//go:cgo_import_dynamic libc_malloc malloc "libc.so"
+//go:cgo_import_dynamic libc_mmap mmap "libc.so"
+//go:cgo_import_dynamic libc_munmap munmap "libc.so"
+//go:cgo_import_dynamic libc_open open "libc.so"
+//go:cgo_import_dynamic libc_pthread_attr_destroy pthread_attr_destroy "libc.so"
+//go:cgo_import_dynamic libc_pthread_attr_getstack pthread_attr_getstack "libc.so"
+//go:cgo_import_dynamic libc_pthread_attr_init pthread_attr_init "libc.so"
+//go:cgo_import_dynamic libc_pthread_attr_setdetachstate pthread_attr_setdetachstate "libc.so"
+//go:cgo_import_dynamic libc_pthread_attr_setstack pthread_attr_setstack "libc.so"
+//go:cgo_import_dynamic libc_pthread_create pthread_create "libc.so"
+//go:cgo_import_dynamic libc_raise raise "libc.so"
+//go:cgo_import_dynamic libc_read read "libc.so"
+//go:cgo_import_dynamic libc_select select "libc.so"
+//go:cgo_import_dynamic libc_sched_yield sched_yield "libc.so"
+//go:cgo_import_dynamic libc_sem_init sem_init "libc.so"
+//go:cgo_import_dynamic libc_sem_post sem_post "libc.so"
+//go:cgo_import_dynamic libc_sem_reltimedwait_np sem_reltimedwait_np "libc.so"
+//go:cgo_import_dynamic libc_sem_wait sem_wait "libc.so"
+//go:cgo_import_dynamic libc_setitimer setitimer "libc.so"
+//go:cgo_import_dynamic libc_sigaction sigaction "libc.so"
+//go:cgo_import_dynamic libc_sigaltstack sigaltstack "libc.so"
+//go:cgo_import_dynamic libc_sigprocmask sigprocmask "libc.so"
+//go:cgo_import_dynamic libc_sysconf sysconf "libc.so"
+//go:cgo_import_dynamic libc_usleep usleep "libc.so"
+//go:cgo_import_dynamic libc_write write "libc.so"
+
+//go:linkname libc____errno libc____errno
+//go:linkname libc_clock_gettime libc_clock_gettime
+//go:linkname libc_close libc_close
+//go:linkname libc_exit libc_exit
+//go:linkname libc_fstat libc_fstat
+//go:linkname libc_getcontext libc_getcontext
+//go:linkname libc_getrlimit libc_getrlimit
+//go:linkname libc_kill libc_kill
+//go:linkname libc_madvise libc_madvise
+//go:linkname libc_malloc libc_malloc
+//go:linkname libc_mmap libc_mmap
+//go:linkname libc_munmap libc_munmap
+//go:linkname libc_open libc_open
+//go:linkname libc_pthread_attr_destroy libc_pthread_attr_destroy
+//go:linkname libc_pthread_attr_getstack libc_pthread_attr_getstack
+//go:linkname libc_pthread_attr_init libc_pthread_attr_init
+//go:linkname libc_pthread_attr_setdetachstate libc_pthread_attr_setdetachstate
+//go:linkname libc_pthread_attr_setstack libc_pthread_attr_setstack
+//go:linkname libc_pthread_create libc_pthread_create
+//go:linkname libc_raise libc_raise
+//go:linkname libc_read libc_read
+//go:linkname libc_select libc_select
+//go:linkname libc_sched_yield libc_sched_yield
+//go:linkname libc_sem_init libc_sem_init
+//go:linkname libc_sem_post libc_sem_post
+//go:linkname libc_sem_reltimedwait_np libc_sem_reltimedwait_np
+//go:linkname libc_sem_wait libc_sem_wait
+//go:linkname libc_setitimer libc_setitimer
+//go:linkname libc_sigaction libc_sigaction
+//go:linkname libc_sigaltstack libc_sigaltstack
+//go:linkname libc_sigprocmask libc_sigprocmask
+//go:linkname libc_sysconf libc_sysconf
+//go:linkname libc_usleep libc_usleep
+//go:linkname libc_write libc_write
+
+var (
+	libc____errno,
+	libc_clock_gettime,
+	libc_close,
+	libc_exit,
+	libc_fstat,
+	libc_getcontext,
+	libc_getrlimit,
+	libc_kill,
+	libc_madvise,
+	libc_malloc,
+	libc_mmap,
+	libc_munmap,
+	libc_open,
+	libc_pthread_attr_destroy,
+	libc_pthread_attr_getstack,
+	libc_pthread_attr_init,
+	libc_pthread_attr_setdetachstate,
+	libc_pthread_attr_setstack,
+	libc_pthread_create,
+	libc_raise,
+	libc_read,
+	libc_sched_yield,
+	libc_select,
+	libc_sem_init,
+	libc_sem_post,
+	libc_sem_reltimedwait_np,
+	libc_sem_wait,
+	libc_setitimer,
+	libc_sigaction,
+	libc_sigaltstack,
+	libc_sigprocmask,
+	libc_sysconf,
+	libc_usleep,
+	libc_write libcFunc
+)
+
+var sigset_all = sigset{[4]uint32{^uint32(0), ^uint32(0), ^uint32(0), ^uint32(0)}}
+
+func getncpu() int32 {
+	n := int32(sysconf(__SC_NPROCESSORS_ONLN))
+	if n < 1 {
+		return 1
+	}
+	return n
+}
+
+func osinit() {
+	ncpu = getncpu()
+}
+
+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
+		oset sigset
+		tid  pthread
+		ret  int32
+		size uint64
+	)
+
+	if pthread_attr_init(&attr) != 0 {
+		throw("pthread_attr_init")
+	}
+	if pthread_attr_setstack(&attr, 0, 0x200000) != 0 {
+		throw("pthread_attr_setstack")
+	}
+	if pthread_attr_getstack(&attr, unsafe.Pointer(&mp.g0.stack.hi), &size) != 0 {
+		throw("pthread_attr_getstack")
+	}
+	mp.g0.stack.lo = mp.g0.stack.hi - uintptr(size)
+	if pthread_attr_setdetachstate(&attr, _PTHREAD_CREATE_DETACHED) != 0 {
+		throw("pthread_attr_setdetachstate")
+	}
+
+	// Disable signals during create, so that the new thread starts
+	// with signals disabled.  It will enable them in minit.
+	sigprocmask(_SIG_SETMASK, &sigset_all, &oset)
+	ret = pthread_create(&tid, &attr, funcPC(tstart_sysvicall), unsafe.Pointer(mp))
+	sigprocmask(_SIG_SETMASK, &oset, nil)
+	if ret != 0 {
+		print("runtime: failed to create new OS thread (have ", mcount(), " already; errno=", ret, ")\n")
+		throw("newosproc")
+	}
+}
+
+var urandom_dev = []byte("/dev/urandom\x00")
+
+//go:nosplit
+func getRandomData(r []byte) {
+	fd := open(&urandom_dev[0], 0 /* O_RDONLY */, 0)
+	n := read(fd, unsafe.Pointer(&r[0]), int32(len(r)))
+	closefd(fd)
+	extendRandom(r, int(n))
+}
+
+func goenvs() {
+	goenvs_unix()
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
+func mpreinit(mp *m) {
+	mp.gsignal = malg(32 * 1024)
+	mp.gsignal.m = mp
+}
+
+func miniterrno()
+
+func msigsave(mp *m) {
+	smask := (*sigset)(unsafe.Pointer(&mp.sigmask))
+	if unsafe.Sizeof(*smask) > unsafe.Sizeof(mp.sigmask) {
+		throw("insufficient storage for signal mask")
+	}
+	sigprocmask(_SIG_SETMASK, nil, smask)
+}
+
+// Called to initialize a new m (including the bootstrap m).
+// Called on the new thread, can not allocate memory.
+func minit() {
+	_g_ := getg()
+	asmcgocall(unsafe.Pointer(funcPC(miniterrno)), unsafe.Pointer(&libc____errno))
+	// Initialize signal handling
+	signalstack(&_g_.m.gsignal.stack)
+
+	// restore signal mask from m.sigmask and unblock essential signals
+	nmask := *(*sigset)(unsafe.Pointer(&_g_.m.sigmask))
+	for i := range sigtable {
+		if sigtable[i].flags&_SigUnblock != 0 {
+			nmask.__sigbits[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
+		}
+	}
+	sigprocmask(_SIG_SETMASK, &nmask, nil)
+}
+
+// Called from dropm to undo the effect of an minit.
+func unminit() {
+	_g_ := getg()
+	smask := (*sigset)(unsafe.Pointer(&_g_.m.sigmask))
+	sigprocmask(_SIG_SETMASK, smask, nil)
+
+	signalstack(nil)
+}
+
+func memlimit() uintptr {
+	/*
+		TODO: Convert to Go when something actually uses the result.
+		Rlimit rl;
+		extern byte runtime·text[], runtime·end[];
+		uintptr used;
+
+		if(runtime·getrlimit(RLIMIT_AS, &rl) != 0)
+			return 0;
+		if(rl.rlim_cur >= 0x7fffffff)
+			return 0;
+
+		// Estimate our VM footprint excluding the heap.
+		// Not an exact science: use size of binary plus
+		// some room for thread stacks.
+		used = runtime·end - runtime·text + (64<<20);
+		if(used >= rl.rlim_cur)
+			return 0;
+
+		// If there's not at least 16 MB left, we're probably
+		// not going to be able to do much.  Treat as no limit.
+		rl.rlim_cur -= used;
+		if(rl.rlim_cur < (16<<20))
+			return 0;
+
+		return rl.rlim_cur - used;
+	*/
+
+	return 0
+}
+
+func sigtramp()
+
+func setsig(i int32, fn uintptr, restart bool) {
+	var sa sigactiont
+
+	sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
+	sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK
+	if restart {
+		sa.sa_flags |= _SA_RESTART
+	}
+	sa.sa_mask = sigset_all
+	if fn == funcPC(sighandler) {
+		fn = funcPC(sigtramp)
+	}
+	*((*uintptr)(unsafe.Pointer(&sa._funcptr))) = fn
+	sigaction(i, &sa, nil)
+}
+
+func setsigstack(i int32) {
+	throw("setsigstack")
+}
+
+func getsig(i int32) uintptr {
+	var sa sigactiont
+	sigaction(i, nil, &sa)
+	if *((*uintptr)(unsafe.Pointer(&sa._funcptr))) == funcPC(sigtramp) {
+		return funcPC(sighandler)
+	}
+	return *((*uintptr)(unsafe.Pointer(&sa._funcptr)))
+}
+
+func signalstack(s *stack) {
+	var st sigaltstackt
+	if s == nil {
+		st.ss_flags = _SS_DISABLE
+	} else {
+		st.ss_sp = (*byte)(unsafe.Pointer(s.lo))
+		st.ss_size = uint64(s.hi - s.lo)
+		st.ss_flags = 0
+	}
+	sigaltstack(&st, nil)
+}
+
+func updatesigmask(m sigmask) {
+	var mask sigset
+	copy(mask.__sigbits[:], m[:])
+	sigprocmask(_SIG_SETMASK, &mask, nil)
+}
+
+func unblocksig(sig int32) {
+	var mask sigset
+	mask.__sigbits[(sig-1)/32] |= 1 << ((uint32(sig) - 1) & 31)
+	sigprocmask(_SIG_UNBLOCK, &mask, nil)
+}
+
+//go:nosplit
+func semacreate() uintptr {
+	var sem *semt
+	_g_ := getg()
+
+	// Call libc's malloc rather than malloc.  This will
+	// allocate space on the C heap.  We can't call malloc
+	// here because it could cause a deadlock.
+	_g_.m.libcall.fn = uintptr(unsafe.Pointer(&libc_malloc))
+	_g_.m.libcall.n = 1
+	memclr(unsafe.Pointer(&_g_.m.scratch), uintptr(len(_g_.m.scratch.v)))
+	_g_.m.scratch.v[0] = unsafe.Sizeof(*sem)
+	_g_.m.libcall.args = uintptr(unsafe.Pointer(&_g_.m.scratch))
+	asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&_g_.m.libcall))
+	sem = (*semt)(unsafe.Pointer(_g_.m.libcall.r1))
+	if sem_init(sem, 0, 0) != 0 {
+		throw("sem_init")
+	}
+	return uintptr(unsafe.Pointer(sem))
+}
+
+//go:nosplit
+func semasleep(ns int64) int32 {
+	_m_ := getg().m
+	if ns >= 0 {
+		_m_.ts.tv_sec = ns / 1000000000
+		_m_.ts.tv_nsec = ns % 1000000000
+
+		_m_.libcall.fn = uintptr(unsafe.Pointer(&libc_sem_reltimedwait_np))
+		_m_.libcall.n = 2
+		memclr(unsafe.Pointer(&_m_.scratch), uintptr(len(_m_.scratch.v)))
+		_m_.scratch.v[0] = _m_.waitsema
+		_m_.scratch.v[1] = uintptr(unsafe.Pointer(&_m_.ts))
+		_m_.libcall.args = uintptr(unsafe.Pointer(&_m_.scratch))
+		asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&_m_.libcall))
+		if *_m_.perrno != 0 {
+			if *_m_.perrno == _ETIMEDOUT || *_m_.perrno == _EAGAIN || *_m_.perrno == _EINTR {
+				return -1
+			}
+			throw("sem_reltimedwait_np")
+		}
+		return 0
+	}
+	for {
+		_m_.libcall.fn = uintptr(unsafe.Pointer(&libc_sem_wait))
+		_m_.libcall.n = 1
+		memclr(unsafe.Pointer(&_m_.scratch), uintptr(len(_m_.scratch.v)))
+		_m_.scratch.v[0] = _m_.waitsema
+		_m_.libcall.args = uintptr(unsafe.Pointer(&_m_.scratch))
+		asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&_m_.libcall))
+		if _m_.libcall.r1 == 0 {
+			break
+		}
+		if *_m_.perrno == _EINTR {
+			continue
+		}
+		throw("sem_wait")
+	}
+	return 0
+}
+
+//go:nosplit
+func semawakeup(mp *m) {
+	if sem_post((*semt)(unsafe.Pointer(mp.waitsema))) != 0 {
+		throw("sem_post")
+	}
+}
+
+//go:nosplit
+func closefd(fd int32) int32 {
+	return int32(sysvicall1(&libc_close, uintptr(fd)))
+}
+
+//go:nosplit
+func exit(r int32) {
+	sysvicall1(&libc_exit, uintptr(r))
+}
+
+//go:nosplit
+func getcontext(context *ucontext) /* int32 */ {
+	sysvicall1(&libc_getcontext, uintptr(unsafe.Pointer(context)))
+}
+
+//go:nosplit
+func madvise(addr unsafe.Pointer, n uintptr, flags int32) {
+	sysvicall3(&libc_madvise, uintptr(addr), uintptr(n), uintptr(flags))
+}
+
+//go:nosplit
+func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) unsafe.Pointer {
+	return unsafe.Pointer(sysvicall6(&libc_mmap, uintptr(addr), uintptr(n), uintptr(prot), uintptr(flags), uintptr(fd), uintptr(off)))
+}
+
+//go:nosplit
+func munmap(addr unsafe.Pointer, n uintptr) {
+	sysvicall2(&libc_munmap, uintptr(addr), uintptr(n))
+}
+
+func nanotime1()
+
+//go:nosplit
+func nanotime() int64 {
+	return int64(sysvicall0((*libcFunc)(unsafe.Pointer(funcPC(nanotime1)))))
+}
+
+//go:nosplit
+func open(path *byte, mode, perm int32) int32 {
+	return int32(sysvicall3(&libc_open, uintptr(unsafe.Pointer(path)), uintptr(mode), uintptr(perm)))
+}
+
+func pthread_attr_destroy(attr *pthreadattr) int32 {
+	return int32(sysvicall1(&libc_pthread_attr_destroy, uintptr(unsafe.Pointer(attr))))
+}
+
+func pthread_attr_getstack(attr *pthreadattr, addr unsafe.Pointer, size *uint64) int32 {
+	return int32(sysvicall3(&libc_pthread_attr_getstack, uintptr(unsafe.Pointer(attr)), uintptr(addr), uintptr(unsafe.Pointer(size))))
+}
+
+func pthread_attr_init(attr *pthreadattr) int32 {
+	return int32(sysvicall1(&libc_pthread_attr_init, uintptr(unsafe.Pointer(attr))))
+}
+
+func pthread_attr_setdetachstate(attr *pthreadattr, state int32) int32 {
+	return int32(sysvicall2(&libc_pthread_attr_setdetachstate, uintptr(unsafe.Pointer(attr)), uintptr(state)))
+}
+
+func pthread_attr_setstack(attr *pthreadattr, addr uintptr, size uint64) int32 {
+	return int32(sysvicall3(&libc_pthread_attr_setstack, uintptr(unsafe.Pointer(attr)), uintptr(addr), uintptr(size)))
+}
+
+func pthread_create(thread *pthread, attr *pthreadattr, fn uintptr, arg unsafe.Pointer) int32 {
+	return int32(sysvicall4(&libc_pthread_create, uintptr(unsafe.Pointer(thread)), uintptr(unsafe.Pointer(attr)), uintptr(fn), uintptr(arg)))
+}
+
+func raise(sig int32) /* int32 */ {
+	sysvicall1(&libc_raise, uintptr(sig))
+}
+
+func raiseproc(sig int32) /* int32 */ {
+	pid := sysvicall0(&libc_getpid)
+	sysvicall2(&libc_kill, pid, uintptr(sig))
+}
+
+//go:nosplit
+func read(fd int32, buf unsafe.Pointer, nbyte int32) int32 {
+	return int32(sysvicall3(&libc_read, uintptr(fd), uintptr(buf), uintptr(nbyte)))
+}
+
+//go:nosplit
+func sem_init(sem *semt, pshared int32, value uint32) int32 {
+	return int32(sysvicall3(&libc_sem_init, uintptr(unsafe.Pointer(sem)), uintptr(pshared), uintptr(value)))
+}
+
+//go:nosplit
+func sem_post(sem *semt) int32 {
+	return int32(sysvicall1(&libc_sem_post, uintptr(unsafe.Pointer(sem))))
+}
+
+//go:nosplit
+func sem_reltimedwait_np(sem *semt, timeout *timespec) int32 {
+	return int32(sysvicall2(&libc_sem_reltimedwait_np, uintptr(unsafe.Pointer(sem)), uintptr(unsafe.Pointer(timeout))))
+}
+
+//go:nosplit
+func sem_wait(sem *semt) int32 {
+	return int32(sysvicall1(&libc_sem_wait, uintptr(unsafe.Pointer(sem))))
+}
+
+func setitimer(which int32, value *itimerval, ovalue *itimerval) /* int32 */ {
+	sysvicall3(&libc_setitimer, uintptr(which), uintptr(unsafe.Pointer(value)), uintptr(unsafe.Pointer(ovalue)))
+}
+
+func sigaction(sig int32, act *sigactiont, oact *sigactiont) /* int32 */ {
+	sysvicall3(&libc_sigaction, uintptr(sig), uintptr(unsafe.Pointer(act)), uintptr(unsafe.Pointer(oact)))
+}
+
+func sigaltstack(ss *sigaltstackt, oss *sigaltstackt) /* int32 */ {
+	sysvicall2(&libc_sigaltstack, uintptr(unsafe.Pointer(ss)), uintptr(unsafe.Pointer(oss)))
+}
+
+func sigprocmask(how int32, set *sigset, oset *sigset) /* int32 */ {
+	sysvicall3(&libc_sigprocmask, uintptr(how), uintptr(unsafe.Pointer(set)), uintptr(unsafe.Pointer(oset)))
+}
+
+func sysconf(name int32) int64 {
+	return int64(sysvicall1(&libc_sysconf, uintptr(name)))
+}
+
+func usleep1(uint32)
+
+//go:nosplit
+func usleep(µs uint32) {
+	usleep1(µs)
+}
+
+//go:nosplit
+func write(fd uintptr, buf unsafe.Pointer, nbyte int32) int32 {
+	return int32(sysvicall3(&libc_write, uintptr(fd), uintptr(buf), uintptr(nbyte)))
+}
+
+func osyield1()
+
+//go:nosplit
+func osyield() {
+	_g_ := getg()
+
+	// Check the validity of m because we might be called in cgo callback
+	// path early enough where there isn't a m available yet.
+	if _g_ != nil && _g_.m != nil {
+		sysvicall0(&libc_sched_yield)
+		return
+	}
+	osyield1()
+}
diff --git a/src/runtime/os_android.c b/src/runtime/os_android.c
deleted file mode 100644
index 5805f68..0000000
--- a/src/runtime/os_android.c
+++ /dev/null
@@ -1,16 +0,0 @@
-// 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 "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-
-// Export the runtime entry point symbol.
-//
-// Used by the app package to start the Go runtime after loading
-// a shared library via JNI. See golang.org/x/mobile/app.
-
-void _rt0_arm_linux1();
-#pragma cgo_export_static _rt0_arm_linux1
-#pragma cgo_export_dynamic _rt0_arm_linux1
diff --git a/src/runtime/os_android.h b/src/runtime/os_android.h
deleted file mode 100644
index c7c1098..0000000
--- a/src/runtime/os_android.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "os_linux.h"
diff --git a/src/runtime/os_android_arm.go b/src/runtime/os_android_arm.go
new file mode 100644
index 0000000..52c8c86
--- /dev/null
+++ b/src/runtime/os_android_arm.go
@@ -0,0 +1,15 @@
+// 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" // for go:cgo_export_static and go:cgo_export_dynamic
+
+// Export the main function.
+//
+// Used by the app package to start all-Go Android apps that are
+// loaded via JNI. See golang.org/x/mobile/app.
+
+//go:cgo_export_static main.main
+//go:cgo_export_dynamic main.main
diff --git a/src/runtime/os_darwin.c b/src/runtime/os_darwin.c
deleted file mode 100644
index bbd2928..0000000
--- a/src/runtime/os_darwin.c
+++ /dev/null
@@ -1,567 +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 "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "signal_unix.h"
-#include "stack.h"
-#include "textflag.h"
-
-extern SigTab runtime·sigtab[];
-
-static Sigset sigset_none;
-static Sigset sigset_all = ~(Sigset)0;
-
-static void
-unimplemented(int8 *name)
-{
-	runtime·prints(name);
-	runtime·prints(" not implemented\n");
-	*(int32*)1231 = 1231;
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·semawakeup(M *mp)
-{
-	runtime·mach_semrelease(mp->waitsema);
-}
-
-static void
-semacreate(void)
-{
-	g->m->scalararg[0] = runtime·mach_semcreate();
-}
-
-#pragma textflag NOSPLIT
-uintptr
-runtime·semacreate(void)
-{
-	uintptr x;
-	void (*fn)(void);
-	
-	fn = semacreate;
-	runtime·onM(&fn);
-	x = g->m->scalararg[0];
-	g->m->scalararg[0] = 0;
-	return x;
-}
-
-// BSD interface for threading.
-void
-runtime·osinit(void)
-{
-	// bsdthread_register delayed until end of goenvs so that we
-	// can look at the environment first.
-
-	// Use sysctl to fetch hw.ncpu.
-	uint32 mib[2];
-	uint32 out;
-	int32 ret;
-	uintptr nout;
-
-	mib[0] = 6;
-	mib[1] = 3;
-	nout = sizeof out;
-	out = 0;
-	ret = runtime·sysctl(mib, 2, (byte*)&out, &nout, nil, 0);
-	if(ret >= 0)
-		runtime·ncpu = out;
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·get_random_data(byte **rnd, int32 *rnd_len)
-{
-	#pragma dataflag NOPTR
-	static byte urandom_data[HashRandomBytes];
-	int32 fd;
-	fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0);
-	if(runtime·read(fd, urandom_data, HashRandomBytes) == HashRandomBytes) {
-		*rnd = urandom_data;
-		*rnd_len = HashRandomBytes;
-	} else {
-		*rnd = nil;
-		*rnd_len = 0;
-	}
-	runtime·close(fd);
-}
-
-void
-runtime·goenvs(void)
-{
-	runtime·goenvs_unix();
-
-	// Register our thread-creation callback (see sys_darwin_{amd64,386}.s)
-	// but only if we're not using cgo.  If we are using cgo we need
-	// to let the C pthread library install its own thread-creation callback.
-	if(!runtime·iscgo) {
-		if(runtime·bsdthread_register() != 0) {
-			if(runtime·getenv("DYLD_INSERT_LIBRARIES"))
-				runtime·throw("runtime: bsdthread_register error (unset DYLD_INSERT_LIBRARIES)");
-			runtime·throw("runtime: bsdthread_register error");
-		}
-	}
-
-}
-
-void
-runtime·newosproc(M *mp, void *stk)
-{
-	int32 errno;
-	Sigset oset;
-
-	mp->tls[0] = mp->id;	// so 386 asm can find it
-	if(0){
-		runtime·printf("newosproc stk=%p m=%p g=%p id=%d/%d ostk=%p\n",
-			stk, mp, mp->g0, mp->id, (int32)mp->tls[0], &mp);
-	}
-
-	runtime·sigprocmask(SIG_SETMASK, &sigset_all, &oset);
-	errno = runtime·bsdthread_create(stk, mp, mp->g0, runtime·mstart);
-	runtime·sigprocmask(SIG_SETMASK, &oset, nil);
-
-	if(errno < 0) {
-		runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), -errno);
-		runtime·throw("runtime.newosproc");
-	}
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
-void
-runtime·mpreinit(M *mp)
-{
-	mp->gsignal = runtime·malg(32*1024);	// OS X wants >=8K, Linux >=2K
-	mp->gsignal->m = mp;
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the new thread, can not allocate memory.
-void
-runtime·minit(void)
-{
-	// Initialize signal handling.
-	runtime·signalstack((byte*)g->m->gsignal->stack.lo, 32*1024);
-
-	runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil);
-}
-
-// Called from dropm to undo the effect of an minit.
-void
-runtime·unminit(void)
-{
-	runtime·signalstack(nil, 0);
-}
-
-// Mach IPC, to get at semaphores
-// Definitions are in /usr/include/mach on a Mac.
-
-static void
-macherror(int32 r, int8 *fn)
-{
-	runtime·prints("mach error ");
-	runtime·prints(fn);
-	runtime·prints(": ");
-	runtime·printint(r);
-	runtime·prints("\n");
-	runtime·throw("mach error");
-}
-
-enum
-{
-	DebugMach = 0
-};
-
-static MachNDR zerondr;
-
-#define MACH_MSGH_BITS(a, b) ((a) | ((b)<<8))
-
-static int32
-mach_msg(MachHeader *h,
-	int32 op,
-	uint32 send_size,
-	uint32 rcv_size,
-	uint32 rcv_name,
-	uint32 timeout,
-	uint32 notify)
-{
-	// TODO: Loop on interrupt.
-	return runtime·mach_msg_trap(h, op, send_size, rcv_size, rcv_name, timeout, notify);
-}
-
-// Mach RPC (MIG)
-
-enum
-{
-	MinMachMsg = 48,
-	Reply = 100,
-};
-
-#pragma pack on
-typedef struct CodeMsg CodeMsg;
-struct CodeMsg
-{
-	MachHeader h;
-	MachNDR NDR;
-	int32 code;
-};
-#pragma pack off
-
-static int32
-machcall(MachHeader *h, int32 maxsize, int32 rxsize)
-{
-	uint32 *p;
-	int32 i, ret, id;
-	uint32 port;
-	CodeMsg *c;
-
-	if((port = g->m->machport) == 0){
-		port = runtime·mach_reply_port();
-		g->m->machport = port;
-	}
-
-	h->msgh_bits |= MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE);
-	h->msgh_local_port = port;
-	h->msgh_reserved = 0;
-	id = h->msgh_id;
-
-	if(DebugMach){
-		p = (uint32*)h;
-		runtime·prints("send:\t");
-		for(i=0; i<h->msgh_size/sizeof(p[0]); i++){
-			runtime·prints(" ");
-			runtime·printpointer((void*)p[i]);
-			if(i%8 == 7)
-				runtime·prints("\n\t");
-		}
-		if(i%8)
-			runtime·prints("\n");
-	}
-
-	ret = mach_msg(h, MACH_SEND_MSG|MACH_RCV_MSG,
-		h->msgh_size, maxsize, port, 0, 0);
-	if(ret != 0){
-		if(DebugMach){
-			runtime·prints("mach_msg error ");
-			runtime·printint(ret);
-			runtime·prints("\n");
-		}
-		return ret;
-	}
-
-	if(DebugMach){
-		p = (uint32*)h;
-		runtime·prints("recv:\t");
-		for(i=0; i<h->msgh_size/sizeof(p[0]); i++){
-			runtime·prints(" ");
-			runtime·printpointer((void*)p[i]);
-			if(i%8 == 7)
-				runtime·prints("\n\t");
-		}
-		if(i%8)
-			runtime·prints("\n");
-	}
-
-	if(h->msgh_id != id+Reply){
-		if(DebugMach){
-			runtime·prints("mach_msg reply id mismatch ");
-			runtime·printint(h->msgh_id);
-			runtime·prints(" != ");
-			runtime·printint(id+Reply);
-			runtime·prints("\n");
-		}
-		return -303;	// MIG_REPLY_MISMATCH
-	}
-
-	// Look for a response giving the return value.
-	// Any call can send this back with an error,
-	// and some calls only have return values so they
-	// send it back on success too.  I don't quite see how
-	// you know it's one of these and not the full response
-	// format, so just look if the message is right.
-	c = (CodeMsg*)h;
-	if(h->msgh_size == sizeof(CodeMsg)
-	&& !(h->msgh_bits & MACH_MSGH_BITS_COMPLEX)){
-		if(DebugMach){
-			runtime·prints("mig result ");
-			runtime·printint(c->code);
-			runtime·prints("\n");
-		}
-		return c->code;
-	}
-
-	if(h->msgh_size != rxsize){
-		if(DebugMach){
-			runtime·prints("mach_msg reply size mismatch ");
-			runtime·printint(h->msgh_size);
-			runtime·prints(" != ");
-			runtime·printint(rxsize);
-			runtime·prints("\n");
-		}
-		return -307;	// MIG_ARRAY_TOO_LARGE
-	}
-
-	return 0;
-}
-
-
-// Semaphores!
-
-enum
-{
-	Tmach_semcreate = 3418,
-	Rmach_semcreate = Tmach_semcreate + Reply,
-
-	Tmach_semdestroy = 3419,
-	Rmach_semdestroy = Tmach_semdestroy + Reply,
-
-	// Mach calls that get interrupted by Unix signals
-	// return this error code.  We retry them.
-	KERN_ABORTED = 14,
-	KERN_OPERATION_TIMED_OUT = 49,
-};
-
-typedef struct Tmach_semcreateMsg Tmach_semcreateMsg;
-typedef struct Rmach_semcreateMsg Rmach_semcreateMsg;
-typedef struct Tmach_semdestroyMsg Tmach_semdestroyMsg;
-// Rmach_semdestroyMsg = CodeMsg
-
-#pragma pack on
-struct Tmach_semcreateMsg
-{
-	MachHeader h;
-	MachNDR ndr;
-	int32 policy;
-	int32 value;
-};
-
-struct Rmach_semcreateMsg
-{
-	MachHeader h;
-	MachBody body;
-	MachPort semaphore;
-};
-
-struct Tmach_semdestroyMsg
-{
-	MachHeader h;
-	MachBody body;
-	MachPort semaphore;
-};
-#pragma pack off
-
-uint32
-runtime·mach_semcreate(void)
-{
-	union {
-		Tmach_semcreateMsg tx;
-		Rmach_semcreateMsg rx;
-		uint8 pad[MinMachMsg];
-	} m;
-	int32 r;
-
-	m.tx.h.msgh_bits = 0;
-	m.tx.h.msgh_size = sizeof(m.tx);
-	m.tx.h.msgh_remote_port = runtime·mach_task_self();
-	m.tx.h.msgh_id = Tmach_semcreate;
-	m.tx.ndr = zerondr;
-
-	m.tx.policy = 0;	// 0 = SYNC_POLICY_FIFO
-	m.tx.value = 0;
-
-	while((r = machcall(&m.tx.h, sizeof m, sizeof(m.rx))) != 0){
-		if(r == KERN_ABORTED)	// interrupted
-			continue;
-		macherror(r, "semaphore_create");
-	}
-	if(m.rx.body.msgh_descriptor_count != 1)
-		unimplemented("mach_semcreate desc count");
-	return m.rx.semaphore.name;
-}
-
-void
-runtime·mach_semdestroy(uint32 sem)
-{
-	union {
-		Tmach_semdestroyMsg tx;
-		uint8 pad[MinMachMsg];
-	} m;
-	int32 r;
-
-	m.tx.h.msgh_bits = MACH_MSGH_BITS_COMPLEX;
-	m.tx.h.msgh_size = sizeof(m.tx);
-	m.tx.h.msgh_remote_port = runtime·mach_task_self();
-	m.tx.h.msgh_id = Tmach_semdestroy;
-	m.tx.body.msgh_descriptor_count = 1;
-	m.tx.semaphore.name = sem;
-	m.tx.semaphore.disposition = MACH_MSG_TYPE_MOVE_SEND;
-	m.tx.semaphore.type = 0;
-
-	while((r = machcall(&m.tx.h, sizeof m, 0)) != 0){
-		if(r == KERN_ABORTED)	// interrupted
-			continue;
-		macherror(r, "semaphore_destroy");
-	}
-}
-
-// The other calls have simple system call traps in sys_darwin_{amd64,386}.s
-int32 runtime·mach_semaphore_wait(uint32 sema);
-int32 runtime·mach_semaphore_timedwait(uint32 sema, uint32 sec, uint32 nsec);
-int32 runtime·mach_semaphore_signal(uint32 sema);
-int32 runtime·mach_semaphore_signal_all(uint32 sema);
-
-static void
-semasleep(void)
-{
-	int32 r, secs, nsecs;
-	int64 ns;
-	
-	ns = (int64)(uint32)g->m->scalararg[0] | (int64)(uint32)g->m->scalararg[1]<<32;
-	g->m->scalararg[0] = 0;
-	g->m->scalararg[1] = 0;
-
-	if(ns >= 0) {
-		secs = runtime·timediv(ns, 1000000000, &nsecs);
-		r = runtime·mach_semaphore_timedwait(g->m->waitsema, secs, nsecs);
-		if(r == KERN_ABORTED || r == KERN_OPERATION_TIMED_OUT) {
-			g->m->scalararg[0] = -1;
-			return;
-		}
-		if(r != 0)
-			macherror(r, "semaphore_wait");
-		g->m->scalararg[0] = 0;
-		return;
-	}
-	while((r = runtime·mach_semaphore_wait(g->m->waitsema)) != 0) {
-		if(r == KERN_ABORTED)	// interrupted
-			continue;
-		macherror(r, "semaphore_wait");
-	}
-	g->m->scalararg[0] = 0;
-	return;
-}
-
-#pragma textflag NOSPLIT
-int32
-runtime·semasleep(int64 ns)
-{
-	int32 r;
-	void (*fn)(void);
-
-	g->m->scalararg[0] = (uint32)ns;
-	g->m->scalararg[1] = (uint32)(ns>>32);
-	fn = semasleep;
-	runtime·onM(&fn);
-	r = g->m->scalararg[0];
-	g->m->scalararg[0] = 0;
-	return r;
-}
-
-static int32 mach_semrelease_errno;
-
-static void
-mach_semrelease_fail(void)
-{
-	macherror(mach_semrelease_errno, "semaphore_signal");
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·mach_semrelease(uint32 sem)
-{
-	int32 r;
-	void (*fn)(void);
-
-	while((r = runtime·mach_semaphore_signal(sem)) != 0) {
-		if(r == KERN_ABORTED)	// interrupted
-			continue;
-		
-		// mach_semrelease must be completely nosplit,
-		// because it is called from Go code.
-		// If we're going to die, start that process on the m stack
-		// to avoid a Go stack split.
-		// Only do that if we're actually running on the g stack.
-		// We might be on the gsignal stack, and if so, onM will abort.
-		// We use the global variable instead of scalararg because
-		// we might be on the gsignal stack, having interrupted a
-		// normal call to onM. It doesn't quite matter, since the
-		// program is about to die, but better to be clean.
-		mach_semrelease_errno = r;
-		fn = mach_semrelease_fail;
-		if(g == g->m->curg)
-			runtime·onM(&fn);
-		else
-			fn();
-	}
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·osyield(void)
-{
-	runtime·usleep(1);
-}
-
-uintptr
-runtime·memlimit(void)
-{
-	// NOTE(rsc): Could use getrlimit here,
-	// like on FreeBSD or Linux, but Darwin doesn't enforce
-	// ulimit -v, so it's unclear why we'd try to stay within
-	// the limit.
-	return 0;
-}
-
-void
-runtime·setsig(int32 i, GoSighandler *fn, bool restart)
-{
-	SigactionT sa;
-		
-	runtime·memclr((byte*)&sa, sizeof sa);
-	sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
-	if(restart)
-		sa.sa_flags |= SA_RESTART;
-	sa.sa_mask = ~(uintptr)0;
-	sa.sa_tramp = (void*)runtime·sigtramp;	// runtime·sigtramp's job is to call into real handler
-	*(uintptr*)sa.__sigaction_u = (uintptr)fn;
-	runtime·sigaction(i, &sa, nil);
-}
-
-GoSighandler*
-runtime·getsig(int32 i)
-{
-	SigactionT sa;
-
-	runtime·memclr((byte*)&sa, sizeof sa);
-	runtime·sigaction(i, nil, &sa);
-	return *(void**)sa.__sigaction_u;
-}
-
-void
-runtime·signalstack(byte *p, int32 n)
-{
-	StackT st;
-
-	st.ss_sp = (void*)p;
-	st.ss_size = n;
-	st.ss_flags = 0;
-	if(p == nil)
-		st.ss_flags = SS_DISABLE;
-	runtime·sigaltstack(&st, nil);
-}
-
-void
-runtime·unblocksignals(void)
-{
-	runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil);
-}
-
-#pragma textflag NOSPLIT
-int8*
-runtime·signame(int32 sig)
-{
-	return runtime·sigtab[sig].name;
-}
diff --git a/src/runtime/os_darwin.go b/src/runtime/os_darwin.go
index 4327ced..3deafd5 100644
--- a/src/runtime/os_darwin.go
+++ b/src/runtime/os_darwin.go
@@ -6,19 +6,32 @@ package runtime
 
 import "unsafe"
 
-func bsdthread_create(stk, mm, gg, fn unsafe.Pointer) int32
+func bsdthread_create(stk, arg unsafe.Pointer, fn uintptr) int32
 func bsdthread_register() int32
+
+//go:noescape
 func mach_msg_trap(h unsafe.Pointer, op int32, send_size, rcv_size, rcv_name, timeout, notify uint32) int32
+
 func mach_reply_port() uint32
 func mach_task_self() uint32
 func mach_thread_self() uint32
+
+//go:noescape
 func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32
-func sigprocmask(sig int32, new, old unsafe.Pointer)
-func sigaction(mode uint32, new, old unsafe.Pointer)
-func sigaltstack(new, old unsafe.Pointer)
+
+//go:noescape
+func sigprocmask(how uint32, new, old *uint32)
+
+//go:noescape
+func sigaction(mode uint32, new, old *sigactiont)
+
+//go:noescape
+func sigaltstack(new, old *stackt)
+
 func sigtramp()
-func setitimer(mode int32, new, old unsafe.Pointer)
-func mach_semaphore_wait(sema uint32) int32
-func mach_semaphore_timedwait(sema, sec, nsec uint32) int32
-func mach_semaphore_signal(sema uint32) int32
-func mach_semaphore_signal_all(sema uint32) int32
+
+//go:noescape
+func setitimer(mode int32, new, old *itimerval)
+
+func raise(sig int32)
+func raiseproc(int32)
diff --git a/src/runtime/os_darwin.h b/src/runtime/os_darwin.h
deleted file mode 100644
index e8bb45d..0000000
--- a/src/runtime/os_darwin.h
+++ /dev/null
@@ -1,43 +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.
-
-typedef byte* kevent_udata;
-
-int32	runtime·bsdthread_create(void*, M*, G*, void(*)(void));
-int32	runtime·bsdthread_register(void);
-int32	runtime·mach_msg_trap(MachHeader*, int32, uint32, uint32, uint32, uint32, uint32);
-uint32	runtime·mach_reply_port(void);
-int32	runtime·mach_semacquire(uint32, int64);
-uint32	runtime·mach_semcreate(void);
-void	runtime·mach_semdestroy(uint32);
-void	runtime·mach_semrelease(uint32);
-void	runtime·mach_semreset(uint32);
-uint32	runtime·mach_task_self(void);
-uint32	runtime·mach_task_self(void);
-uint32	runtime·mach_thread_self(void);
-uint32	runtime·mach_thread_self(void);
-int32	runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr);
-
-typedef uint32 Sigset;
-void	runtime·sigprocmask(int32, Sigset*, Sigset*);
-void	runtime·unblocksignals(void);
-
-struct SigactionT;
-void	runtime·sigaction(uintptr, struct SigactionT*, struct SigactionT*);
-
-struct StackT;
-void	runtime·sigaltstack(struct StackT*, struct StackT*);
-void	runtime·sigtramp(void);
-void	runtime·sigpanic(void);
-void	runtime·setitimer(int32, Itimerval*, Itimerval*);
-
-
-enum {
-	NSIG = 32,
-	SI_USER = 0, /* empirically true, but not what headers say */
-	SIG_BLOCK = 1,
-	SIG_UNBLOCK = 2,
-	SIG_SETMASK = 3,
-	SS_DISABLE = 4,
-};
diff --git a/src/runtime/os_darwin_arm.go b/src/runtime/os_darwin_arm.go
new file mode 100644
index 0000000..1ccc959
--- /dev/null
+++ b/src/runtime/os_darwin_arm.go
@@ -0,0 +1,24 @@
+// 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
+
+func checkgoarm() {
+	// TODO(minux): FP checks like in os_linux_arm.go.
+
+	// osinit not called yet, so ncpu not set: must use getncpu directly.
+	if getncpu() > 1 && goarm < 7 {
+		print("runtime: this system has multiple CPUs and must use\n")
+		print("atomic synchronization instructions. Recompile using GOARM=7.\n")
+		exit(1)
+	}
+}
+
+//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_darwin_arm64.go b/src/runtime/os_darwin_arm64.go
new file mode 100644
index 0000000..4d35af9
--- /dev/null
+++ b/src/runtime/os_darwin_arm64.go
@@ -0,0 +1,13 @@
+// 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
+
+//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_dragonfly.c b/src/runtime/os_dragonfly.c
deleted file mode 100644
index e372205..0000000
--- a/src/runtime/os_dragonfly.c
+++ /dev/null
@@ -1,312 +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.
-
-#include "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "signal_unix.h"
-#include "stack.h"
-#include "textflag.h"
-
-extern SigTab runtime·sigtab[];
-extern int32 runtime·sys_umtx_sleep(uint32*, int32, int32);
-extern int32 runtime·sys_umtx_wakeup(uint32*, int32);
-
-// From DragonFly's <sys/sysctl.h>
-#define	CTL_HW	6
-#define	HW_NCPU	3
-
-static Sigset sigset_none;
-static Sigset sigset_all = { ~(uint32)0, ~(uint32)0, ~(uint32)0, ~(uint32)0, };
-
-static int32
-getncpu(void)
-{
-	uint32 mib[2];
-	uint32 out;
-	int32 ret;
-	uintptr nout;
-
-	// Fetch hw.ncpu via sysctl.
-	mib[0] = CTL_HW;
-	mib[1] = HW_NCPU;
-	nout = sizeof out;
-	out = 0;
-	ret = runtime·sysctl(mib, 2, (byte*)&out, &nout, nil, 0);
-	if(ret >= 0)
-		return out;
-	else
-		return 1;
-}
-
-static void futexsleep(void);
-
-#pragma textflag NOSPLIT
-void
-runtime·futexsleep(uint32 *addr, uint32 val, int64 ns)
-{
-	void (*fn)(void);
-
-	g->m->ptrarg[0] = addr;
-	g->m->scalararg[0] = val;
-	g->m->ptrarg[1] = &ns;
-
-	fn = futexsleep;
-	runtime·onM(&fn);
-}
-
-static void
-futexsleep(void)
-{
-	uint32 *addr;
-	uint32 val;
-	int64 ns;
-	int32 timeout = 0;
-	int32 ret;
-
-	addr = g->m->ptrarg[0];
-	val = g->m->scalararg[0];
-	ns = *(int64*)g->m->ptrarg[1];
-	g->m->ptrarg[0] = nil;
-	g->m->scalararg[0] = 0;
-	g->m->ptrarg[1] = nil;
-
-	if(ns >= 0) {
-		// The timeout is specified in microseconds - ensure that we
-		// do not end up dividing to zero, which would put us to sleep
-		// indefinitely...
-		timeout = runtime·timediv(ns, 1000, nil);
-		if(timeout == 0)
-			timeout = 1;
-	}
-
-	// sys_umtx_sleep will return EWOULDBLOCK (EAGAIN) when the timeout
-	// expires or EBUSY if the mutex value does not match. 
-	ret = runtime·sys_umtx_sleep(addr, val, timeout);
-	if(ret >= 0 || ret == -EINTR || ret == -EAGAIN || ret == -EBUSY)
-		return;
-
-	runtime·prints("umtx_wait addr=");
-	runtime·printpointer(addr);
-	runtime·prints(" val=");
-	runtime·printint(val);
-	runtime·prints(" ret=");
-	runtime·printint(ret);
-	runtime·prints("\n");
-	*(int32*)0x1005 = 0x1005;
-}
-
-static void badfutexwakeup(void);
-
-#pragma textflag NOSPLIT
-void
-runtime·futexwakeup(uint32 *addr, uint32 cnt)
-{
-	int32 ret;
-	void (*fn)(void);
-
-	ret = runtime·sys_umtx_wakeup(addr, cnt);
-	if(ret >= 0)
-		return;
-
-	g->m->ptrarg[0] = addr;
-	g->m->scalararg[0] = ret;
-	fn = badfutexwakeup;
-	if(g == g->m->gsignal)
-		fn();
-	else
-		runtime·onM(&fn);
-	*(int32*)0x1006 = 0x1006;
-}
-
-static void
-badfutexwakeup(void)
-{
-	void *addr;
-	int32 ret;
-	
-	addr = g->m->ptrarg[0];
-	ret = g->m->scalararg[0];
-	runtime·printf("umtx_wake addr=%p ret=%d\n", addr, ret);
-}
-
-void runtime·lwp_start(void*);
-
-void
-runtime·newosproc(M *mp, void *stk)
-{
-	Lwpparams params;
-	Sigset oset;
-
-	if(0){
-		runtime·printf("newosproc stk=%p m=%p g=%p id=%d/%d ostk=%p\n",
-			stk, mp, mp->g0, mp->id, (int32)mp->tls[0], &mp);
-	}
-
-	runtime·sigprocmask(&sigset_all, &oset);
-	runtime·memclr((byte*)&params, sizeof params);
-
-	params.func = runtime·lwp_start;
-	params.arg = (byte*)mp;
-	params.stack = (byte*)stk;
-	params.tid1 = (int32*)&mp->procid;
-	params.tid2 = nil;
-
-	mp->tls[0] = mp->id;	// so 386 asm can find it
-
-	runtime·lwp_create(&params);
-	runtime·sigprocmask(&oset, nil);
-}
-
-void
-runtime·osinit(void)
-{
-	runtime·ncpu = getncpu();
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·get_random_data(byte **rnd, int32 *rnd_len)
-{
-	#pragma dataflag NOPTR
-	static byte urandom_data[HashRandomBytes];
-	int32 fd;
-	fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0);
-	if(runtime·read(fd, urandom_data, HashRandomBytes) == HashRandomBytes) {
-		*rnd = urandom_data;
-		*rnd_len = HashRandomBytes;
-	} else {
-		*rnd = nil;
-		*rnd_len = 0;
-	}
-	runtime·close(fd);
-}
-
-void
-runtime·goenvs(void)
-{
-	runtime·goenvs_unix();
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
-void
-runtime·mpreinit(M *mp)
-{
-	mp->gsignal = runtime·malg(32*1024);
-	mp->gsignal->m = mp;
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the new thread, can not allocate memory.
-void
-runtime·minit(void)
-{
-	// Initialize signal handling
-	runtime·signalstack((byte*)g->m->gsignal->stack.lo, 32*1024);
-	runtime·sigprocmask(&sigset_none, nil);
-}
-
-// Called from dropm to undo the effect of an minit.
-void
-runtime·unminit(void)
-{
-	runtime·signalstack(nil, 0);
-}
-
-uintptr
-runtime·memlimit(void)
-{
-	Rlimit rl;
-	extern byte runtime·text[], runtime·end[];
-	uintptr used;
-	
-	if(runtime·getrlimit(RLIMIT_AS, &rl) != 0)
-		return 0;
-	if(rl.rlim_cur >= 0x7fffffff)
-		return 0;
-
-	// Estimate our VM footprint excluding the heap.
-	// Not an exact science: use size of binary plus
-	// some room for thread stacks.
-	used = runtime·end - runtime·text + (64<<20);
-	if(used >= rl.rlim_cur)
-		return 0;
-
-	// If there's not at least 16 MB left, we're probably
-	// not going to be able to do much.  Treat as no limit.
-	rl.rlim_cur -= used;
-	if(rl.rlim_cur < (16<<20))
-		return 0;
-
-	return rl.rlim_cur - used;
-}
-
-extern void runtime·sigtramp(void);
-
-typedef struct sigaction {
-	union {
-		void    (*__sa_handler)(int32);
-		void    (*__sa_sigaction)(int32, Siginfo*, void *);
-	} __sigaction_u;		/* signal handler */
-	int32	sa_flags;		/* see signal options below */
-	Sigset	sa_mask;		/* signal mask to apply */
-} SigactionT;
-
-void
-runtime·setsig(int32 i, GoSighandler *fn, bool restart)
-{
-	SigactionT sa;
-
-	runtime·memclr((byte*)&sa, sizeof sa);
-	sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
-	if(restart)
-		sa.sa_flags |= SA_RESTART;
-	sa.sa_mask.__bits[0] = ~(uint32)0;
-	sa.sa_mask.__bits[1] = ~(uint32)0;
-	sa.sa_mask.__bits[2] = ~(uint32)0;
-	sa.sa_mask.__bits[3] = ~(uint32)0;
-	if(fn == runtime·sighandler)
-		fn = (void*)runtime·sigtramp;
-	sa.__sigaction_u.__sa_sigaction = (void*)fn;
-	runtime·sigaction(i, &sa, nil);
-}
-
-GoSighandler*
-runtime·getsig(int32 i)
-{
-	SigactionT sa;
-
-	runtime·memclr((byte*)&sa, sizeof sa);
-	runtime·sigaction(i, nil, &sa);
-	if((void*)sa.__sigaction_u.__sa_sigaction == runtime·sigtramp)
-		return runtime·sighandler;
-	return (void*)sa.__sigaction_u.__sa_sigaction;
-}
-
-void
-runtime·signalstack(byte *p, int32 n)
-{
-	StackT st;
-
-	st.ss_sp = (void*)p;
-	st.ss_size = n;
-	st.ss_flags = 0;
-	if(p == nil)
-		st.ss_flags = SS_DISABLE;
-	runtime·sigaltstack(&st, nil);
-}
-
-void
-runtime·unblocksignals(void)
-{
-	runtime·sigprocmask(&sigset_none, nil);
-}
-
-#pragma textflag NOSPLIT
-int8*
-runtime·signame(int32 sig)
-{
-	return runtime·sigtab[sig].name;
-}
diff --git a/src/runtime/os_dragonfly.go b/src/runtime/os_dragonfly.go
index cdaa069..b19270a 100644
--- a/src/runtime/os_dragonfly.go
+++ b/src/runtime/os_dragonfly.go
@@ -6,15 +6,39 @@ package runtime
 
 import "unsafe"
 
-func lwp_create(param unsafe.Pointer) int32
-func sigaltstack(new, old unsafe.Pointer)
-func sigaction(sig int32, new, old unsafe.Pointer)
-func sigprocmask(new, old unsafe.Pointer)
-func setitimer(mode int32, new, old unsafe.Pointer)
+//go:noescape
+func lwp_create(param *lwpparams) int32
+
+//go:noescape
+func sigaltstack(new, old *sigaltstackt)
+
+//go:noescape
+func sigfwd(fn uintptr, sig uint32, info *siginfo, ctx unsafe.Pointer)
+
+//go:noescape
+func sigaction(sig int32, new, old *sigactiont)
+
+//go:noescape
+func sigprocmask(how int32, new, old *sigset)
+
+//go:noescape
+func setitimer(mode int32, new, old *itimerval)
+
+//go:noescape
 func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32
+
+//go:noescape
 func getrlimit(kind int32, limit unsafe.Pointer) int32
+
 func raise(sig int32)
-func sys_umtx_sleep(addr unsafe.Pointer, val, timeout int32) int32
-func sys_umtx_wakeup(addr unsafe.Pointer, val int32) int32
+func raiseproc(sig int32)
+
+//go:noescape
+func sys_umtx_sleep(addr *uint32, val, timeout int32) int32
+
+//go:noescape
+func sys_umtx_wakeup(addr *uint32, val int32) int32
+
+func osyield()
 
 const stackSystem = 0
diff --git a/src/runtime/os_dragonfly.h b/src/runtime/os_dragonfly.h
deleted file mode 100644
index 389736a..0000000
--- a/src/runtime/os_dragonfly.h
+++ /dev/null
@@ -1,30 +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.
-
-
-typedef byte* kevent_udata;
-
-int32	runtime·lwp_create(Lwpparams*);
-void	runtime·sigpanic(void);
-void	runtime·sigaltstack(SigaltstackT*, SigaltstackT*);
-struct	sigaction;
-void	runtime·sigaction(int32, struct sigaction*, struct sigaction*);
-void	runtime·sigprocmask(Sigset *, Sigset *);
-void	runtime·unblocksignals(void);
-void	runtime·setitimer(int32, Itimerval*, Itimerval*);
-int32	runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr);
-
-enum {
-	NSIG = 33,
-	SI_USER = 0x10001,
-	SS_DISABLE = 4,
-	RLIMIT_AS = 10,
-};
-
-typedef struct Rlimit Rlimit;
-struct Rlimit {
-	int64	rlim_cur;
-	int64	rlim_max;
-};
-int32	runtime·getrlimit(int32, Rlimit*);
diff --git a/src/runtime/os_freebsd.c b/src/runtime/os_freebsd.c
deleted file mode 100644
index a513cb6..0000000
--- a/src/runtime/os_freebsd.c
+++ /dev/null
@@ -1,320 +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.
-
-#include "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "signal_unix.h"
-#include "stack.h"
-#include "textflag.h"
-
-extern SigTab runtime·sigtab[];
-extern int32 runtime·sys_umtx_op(uint32*, int32, uint32, void*, void*);
-
-// From FreeBSD's <sys/sysctl.h>
-#define	CTL_HW	6
-#define	HW_NCPU	3
-
-static Sigset sigset_none;
-static Sigset sigset_all = { ~(uint32)0, ~(uint32)0, ~(uint32)0, ~(uint32)0, };
-
-static int32
-getncpu(void)
-{
-	uint32 mib[2];
-	uint32 out;
-	int32 ret;
-	uintptr nout;
-
-	// Fetch hw.ncpu via sysctl.
-	mib[0] = CTL_HW;
-	mib[1] = HW_NCPU;
-	nout = sizeof out;
-	out = 0;
-	ret = runtime·sysctl(mib, 2, (byte*)&out, &nout, nil, 0);
-	if(ret >= 0)
-		return out;
-	else
-		return 1;
-}
-
-// FreeBSD's umtx_op syscall is effectively the same as Linux's futex, and
-// thus the code is largely similar. See linux/thread.c and lock_futex.c for comments.
-
-static void futexsleep(void);
-
-#pragma textflag NOSPLIT
-void
-runtime·futexsleep(uint32 *addr, uint32 val, int64 ns)
-{
-	void (*fn)(void);
-
-	g->m->ptrarg[0] = addr;
-	g->m->scalararg[0] = val;
-	g->m->ptrarg[1] = &ns;
-
-	fn = futexsleep;
-	runtime·onM(&fn);
-}
-
-static void
-futexsleep(void)
-{
-	uint32 *addr;
-	uint32 val;
-	int64 ns;
-	int32 ret;
-	Timespec ts;
-	
-	addr = g->m->ptrarg[0];
-	val = g->m->scalararg[0];
-	ns = *(int64*)g->m->ptrarg[1];
-	g->m->ptrarg[0] = nil;
-	g->m->scalararg[0] = 0;
-	g->m->ptrarg[1] = nil;
-
-	if(ns < 0) {
-		ret = runtime·sys_umtx_op(addr, UMTX_OP_WAIT_UINT_PRIVATE, val, nil, nil);
-		if(ret >= 0 || ret == -EINTR)
-			return;
-		goto fail;
-	}
-	// NOTE: tv_nsec is int64 on amd64, so this assumes a little-endian system.
-	ts.tv_nsec = 0;
-	ts.tv_sec = runtime·timediv(ns, 1000000000, (int32*)&ts.tv_nsec);
-	ret = runtime·sys_umtx_op(addr, UMTX_OP_WAIT_UINT_PRIVATE, val, nil, &ts);
-	if(ret >= 0 || ret == -EINTR)
-		return;
-
-fail:
-	runtime·prints("umtx_wait addr=");
-	runtime·printpointer(addr);
-	runtime·prints(" val=");
-	runtime·printint(val);
-	runtime·prints(" ret=");
-	runtime·printint(ret);
-	runtime·prints("\n");
-	*(int32*)0x1005 = 0x1005;
-}
-
-static void badfutexwakeup(void);
-
-#pragma textflag NOSPLIT
-void
-runtime·futexwakeup(uint32 *addr, uint32 cnt)
-{
-	int32 ret;
-	void (*fn)(void);
-
-	ret = runtime·sys_umtx_op(addr, UMTX_OP_WAKE_PRIVATE, cnt, nil, nil);
-	if(ret >= 0)
-		return;
-
-	g->m->ptrarg[0] = addr;
-	g->m->scalararg[0] = ret;
-	fn = badfutexwakeup;
-	if(g == g->m->gsignal)
-		fn();
-	else
-		runtime·onM(&fn);
-	*(int32*)0x1006 = 0x1006;
-}
-
-static void
-badfutexwakeup(void)
-{
-	void *addr;
-	int32 ret;
-	
-	addr = g->m->ptrarg[0];
-	ret = g->m->scalararg[0];
-	runtime·printf("umtx_wake addr=%p ret=%d\n", addr, ret);
-}
-
-void runtime·thr_start(void*);
-
-void
-runtime·newosproc(M *mp, void *stk)
-{
-	ThrParam param;
-	Sigset oset;
-
-	if(0){
-		runtime·printf("newosproc stk=%p m=%p g=%p id=%d/%d ostk=%p\n",
-			stk, mp, mp->g0, mp->id, (int32)mp->tls[0], &mp);
-	}
-
-	runtime·sigprocmask(&sigset_all, &oset);
-	runtime·memclr((byte*)&param, sizeof param);
-
-	param.start_func = runtime·thr_start;
-	param.arg = (byte*)mp;
-	
-	// NOTE(rsc): This code is confused. stackbase is the top of the stack
-	// and is equal to stk. However, it's working, so I'm not changing it.
-	param.stack_base = (void*)mp->g0->stack.hi;
-	param.stack_size = (byte*)stk - (byte*)mp->g0->stack.hi;
-
-	param.child_tid = (void*)&mp->procid;
-	param.parent_tid = nil;
-	param.tls_base = (void*)&mp->tls[0];
-	param.tls_size = sizeof mp->tls;
-
-	mp->tls[0] = mp->id;	// so 386 asm can find it
-
-	runtime·thr_new(&param, sizeof param);
-	runtime·sigprocmask(&oset, nil);
-}
-
-void
-runtime·osinit(void)
-{
-	runtime·ncpu = getncpu();
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·get_random_data(byte **rnd, int32 *rnd_len)
-{
-	#pragma dataflag NOPTR
-	static byte urandom_data[HashRandomBytes];
-	int32 fd;
-	fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0);
-	if(runtime·read(fd, urandom_data, HashRandomBytes) == HashRandomBytes) {
-		*rnd = urandom_data;
-		*rnd_len = HashRandomBytes;
-	} else {
-		*rnd = nil;
-		*rnd_len = 0;
-	}
-	runtime·close(fd);
-}
-
-void
-runtime·goenvs(void)
-{
-	runtime·goenvs_unix();
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
-void
-runtime·mpreinit(M *mp)
-{
-	mp->gsignal = runtime·malg(32*1024);
-	mp->gsignal->m = mp;
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the new thread, can not allocate memory.
-void
-runtime·minit(void)
-{
-	// Initialize signal handling
-	runtime·signalstack((byte*)g->m->gsignal->stack.lo, 32*1024);
-	runtime·sigprocmask(&sigset_none, nil);
-}
-
-// Called from dropm to undo the effect of an minit.
-void
-runtime·unminit(void)
-{
-	runtime·signalstack(nil, 0);
-}
-
-uintptr
-runtime·memlimit(void)
-{
-	Rlimit rl;
-	extern byte runtime·text[], runtime·end[];
-	uintptr used;
-	
-	if(runtime·getrlimit(RLIMIT_AS, &rl) != 0)
-		return 0;
-	if(rl.rlim_cur >= 0x7fffffff)
-		return 0;
-
-	// Estimate our VM footprint excluding the heap.
-	// Not an exact science: use size of binary plus
-	// some room for thread stacks.
-	used = runtime·end - runtime·text + (64<<20);
-	if(used >= rl.rlim_cur)
-		return 0;
-
-	// If there's not at least 16 MB left, we're probably
-	// not going to be able to do much.  Treat as no limit.
-	rl.rlim_cur -= used;
-	if(rl.rlim_cur < (16<<20))
-		return 0;
-
-	return rl.rlim_cur - used;
-}
-
-extern void runtime·sigtramp(void);
-
-typedef struct sigaction {
-	union {
-		void    (*__sa_handler)(int32);
-		void    (*__sa_sigaction)(int32, Siginfo*, void *);
-	} __sigaction_u;		/* signal handler */
-	int32	sa_flags;		/* see signal options below */
-	Sigset	sa_mask;		/* signal mask to apply */
-} SigactionT;
-
-void
-runtime·setsig(int32 i, GoSighandler *fn, bool restart)
-{
-	SigactionT sa;
-
-	runtime·memclr((byte*)&sa, sizeof sa);
-	sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
-	if(restart)
-		sa.sa_flags |= SA_RESTART;
-	sa.sa_mask.__bits[0] = ~(uint32)0;
-	sa.sa_mask.__bits[1] = ~(uint32)0;
-	sa.sa_mask.__bits[2] = ~(uint32)0;
-	sa.sa_mask.__bits[3] = ~(uint32)0;
-	if(fn == runtime·sighandler)
-		fn = (void*)runtime·sigtramp;
-	sa.__sigaction_u.__sa_sigaction = (void*)fn;
-	runtime·sigaction(i, &sa, nil);
-}
-
-GoSighandler*
-runtime·getsig(int32 i)
-{
-	SigactionT sa;
-
-	runtime·memclr((byte*)&sa, sizeof sa);
-	runtime·sigaction(i, nil, &sa);
-	if((void*)sa.__sigaction_u.__sa_sigaction == runtime·sigtramp)
-		return runtime·sighandler;
-	return (void*)sa.__sigaction_u.__sa_sigaction;
-}
-
-void
-runtime·signalstack(byte *p, int32 n)
-{
-	StackT st;
-
-	st.ss_sp = (void*)p;
-	st.ss_size = n;
-	st.ss_flags = 0;
-	if(p == nil)
-		st.ss_flags = SS_DISABLE;
-	runtime·sigaltstack(&st, nil);
-}
-
-void
-runtime·unblocksignals(void)
-{
-	runtime·sigprocmask(&sigset_none, nil);
-}
-
-#pragma textflag NOSPLIT
-int8*
-runtime·signame(int32 sig)
-{
-	return runtime·sigtab[sig].name;
-}
diff --git a/src/runtime/os_freebsd.go b/src/runtime/os_freebsd.go
index 5970804..8c8a106 100644
--- a/src/runtime/os_freebsd.go
+++ b/src/runtime/os_freebsd.go
@@ -6,12 +6,33 @@ package runtime
 
 import "unsafe"
 
-func thr_new(param unsafe.Pointer, size int32)
-func sigaltstack(new, old unsafe.Pointer)
-func sigaction(sig int32, new, old unsafe.Pointer)
-func sigprocmask(new, old unsafe.Pointer)
-func setitimer(mode int32, new, old unsafe.Pointer)
+//go:noescape
+func thr_new(param *thrparam, size int32)
+
+//go:noescape
+func sigaltstack(new, old *stackt)
+
+//go:noescape
+func sigfwd(fn uintptr, sig uint32, info *siginfo, ctx unsafe.Pointer)
+
+//go:noescape
+func sigaction(sig int32, new, old *sigactiont)
+
+//go:noescape
+func sigprocmask(how int32, new, old *sigset)
+
+//go:noescape
+func setitimer(mode int32, new, old *itimerval)
+
+//go:noescape
 func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32
+
+//go:noescape
 func getrlimit(kind int32, limit unsafe.Pointer) int32
 func raise(sig int32)
-func sys_umtx_op(addr unsafe.Pointer, mode int32, val uint32, ptr2, ts unsafe.Pointer) int32
+func raiseproc(sig int32)
+
+//go:noescape
+func sys_umtx_op(addr *uint32, mode int32, val uint32, ptr2, ts *timespec) int32
+
+func osyield()
diff --git a/src/runtime/os_freebsd.h b/src/runtime/os_freebsd.h
deleted file mode 100644
index b86bb39..0000000
--- a/src/runtime/os_freebsd.h
+++ /dev/null
@@ -1,29 +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.
-
-typedef byte* kevent_udata;
-
-int32	runtime·thr_new(ThrParam*, int32);
-void	runtime·sigpanic(void);
-void	runtime·sigaltstack(SigaltstackT*, SigaltstackT*);
-struct	sigaction;
-void	runtime·sigaction(int32, struct sigaction*, struct sigaction*);
-void	runtime·sigprocmask(Sigset *, Sigset *);
-void	runtime·unblocksignals(void);
-void	runtime·setitimer(int32, Itimerval*, Itimerval*);
-int32	runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr);
-
-enum {
-	SS_DISABLE = 4,
-	NSIG = 33,
-	SI_USER = 0x10001,
-	RLIMIT_AS = 10,
-};
-
-typedef struct Rlimit Rlimit;
-struct Rlimit {
-	int64	rlim_cur;
-	int64	rlim_max;
-};
-int32	runtime·getrlimit(int32, Rlimit*);
diff --git a/src/runtime/os_freebsd_arm.c b/src/runtime/os_freebsd_arm.c
deleted file mode 100644
index 2f2d776..0000000
--- a/src/runtime/os_freebsd_arm.c
+++ /dev/null
@@ -1,24 +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.
-
-#include "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "textflag.h"
-
-void
-runtime·checkgoarm(void)
-{
-	// TODO(minux)
-}
-
-#pragma textflag NOSPLIT
-int64
-runtime·cputicks(void)
-{
-	// 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 runtime·nanotime();
-}
diff --git a/src/runtime/os_freebsd_arm.go b/src/runtime/os_freebsd_arm.go
new file mode 100644
index 0000000..1f2add2
--- /dev/null
+++ b/src/runtime/os_freebsd_arm.go
@@ -0,0 +1,24 @@
+// 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.
+
+package runtime
+
+func checkgoarm() {
+	// TODO(minux): FP checks like in os_linux_arm.go.
+
+	// osinit not called yet, so ncpu not set: must use getncpu directly.
+	if getncpu() > 1 && goarm < 7 {
+		print("runtime: this system has multiple CPUs and must use\n")
+		print("atomic synchronization instructions. Recompile using GOARM=7.\n")
+		exit(1)
+	}
+}
+
+//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_linux.c b/src/runtime/os_linux.c
deleted file mode 100644
index 0d8ffc9..0000000
--- a/src/runtime/os_linux.c
+++ /dev/null
@@ -1,342 +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 "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "signal_unix.h"
-#include "stack.h"
-#include "textflag.h"
-
-extern SigTab runtime·sigtab[];
-
-static Sigset sigset_none;
-static Sigset sigset_all = { ~(uint32)0, ~(uint32)0 };
-
-// Linux futex.
-//
-//	futexsleep(uint32 *addr, uint32 val)
-//	futexwakeup(uint32 *addr)
-//
-// Futexsleep atomically checks if *addr == val and if so, sleeps on addr.
-// Futexwakeup wakes up threads sleeping on addr.
-// Futexsleep is allowed to wake up spuriously.
-
-enum
-{
-	FUTEX_WAIT = 0,
-	FUTEX_WAKE = 1,
-};
-
-// Atomically,
-//	if(*addr == val) sleep
-// Might be woken up spuriously; that's allowed.
-// Don't sleep longer than ns; ns < 0 means forever.
-#pragma textflag NOSPLIT
-void
-runtime·futexsleep(uint32 *addr, uint32 val, int64 ns)
-{
-	Timespec ts;
-
-	// Some Linux kernels have a bug where futex of
-	// FUTEX_WAIT returns an internal error code
-	// as an errno.  Libpthread ignores the return value
-	// here, and so can we: as it says a few lines up,
-	// spurious wakeups are allowed.
-
-	if(ns < 0) {
-		runtime·futex(addr, FUTEX_WAIT, val, nil, nil, 0);
-		return;
-	}
-	// NOTE: tv_nsec is int64 on amd64, so this assumes a little-endian system.
-	ts.tv_nsec = 0;
-	ts.tv_sec = runtime·timediv(ns, 1000000000LL, (int32*)&ts.tv_nsec);
-	runtime·futex(addr, FUTEX_WAIT, val, &ts, nil, 0);
-}
-
-static void badfutexwakeup(void);
-
-// If any procs are sleeping on addr, wake up at most cnt.
-#pragma textflag NOSPLIT
-void
-runtime·futexwakeup(uint32 *addr, uint32 cnt)
-{
-	int64 ret;
-	void (*fn)(void);
-
-	ret = runtime·futex(addr, FUTEX_WAKE, cnt, nil, nil, 0);
-	if(ret >= 0)
-		return;
-
-	// I don't know that futex wakeup can return
-	// EAGAIN or EINTR, but if it does, it would be
-	// safe to loop and call futex again.
-	g->m->ptrarg[0] = addr;
-	g->m->scalararg[0] = (int32)ret; // truncated but fine
-	fn = badfutexwakeup;
-	if(g == g->m->gsignal)
-		fn();
-	else
-		runtime·onM(&fn);
-	*(int32*)0x1006 = 0x1006;
-}
-
-static void
-badfutexwakeup(void)
-{
-	void *addr;
-	int64 ret;
-	
-	addr = g->m->ptrarg[0];
-	ret = (int32)g->m->scalararg[0];
-	runtime·printf("futexwakeup addr=%p returned %D\n", addr, ret);
-}
-
-extern runtime·sched_getaffinity(uintptr pid, uintptr len, uintptr *buf);
-static int32
-getproccount(void)
-{
-	uintptr buf[16], t;
-	int32 r, cnt, i;
-
-	cnt = 0;
-	r = runtime·sched_getaffinity(0, sizeof(buf), buf);
-	if(r > 0)
-	for(i = 0; i < r/sizeof(buf[0]); i++) {
-		t = buf[i];
-		t = t - ((t >> 1) & 0x5555555555555555ULL);
-		t = (t & 0x3333333333333333ULL) + ((t >> 2) & 0x3333333333333333ULL);
-		cnt += (int32)((((t + (t >> 4)) & 0xF0F0F0F0F0F0F0FULL) * 0x101010101010101ULL) >> 56);
-	}
-
-	return cnt ? cnt : 1;
-}
-
-// Clone, the Linux rfork.
-enum
-{
-	CLONE_VM = 0x100,
-	CLONE_FS = 0x200,
-	CLONE_FILES = 0x400,
-	CLONE_SIGHAND = 0x800,
-	CLONE_PTRACE = 0x2000,
-	CLONE_VFORK = 0x4000,
-	CLONE_PARENT = 0x8000,
-	CLONE_THREAD = 0x10000,
-	CLONE_NEWNS = 0x20000,
-	CLONE_SYSVSEM = 0x40000,
-	CLONE_SETTLS = 0x80000,
-	CLONE_PARENT_SETTID = 0x100000,
-	CLONE_CHILD_CLEARTID = 0x200000,
-	CLONE_UNTRACED = 0x800000,
-	CLONE_CHILD_SETTID = 0x1000000,
-	CLONE_STOPPED = 0x2000000,
-	CLONE_NEWUTS = 0x4000000,
-	CLONE_NEWIPC = 0x8000000,
-};
-
-void
-runtime·newosproc(M *mp, void *stk)
-{
-	int32 ret;
-	int32 flags;
-	Sigset oset;
-
-	/*
-	 * note: strace gets confused if we use CLONE_PTRACE here.
-	 */
-	flags = CLONE_VM	/* share memory */
-		| CLONE_FS	/* share cwd, etc */
-		| CLONE_FILES	/* share fd table */
-		| CLONE_SIGHAND	/* share sig handler table */
-		| CLONE_THREAD	/* revisit - okay for now */
-		;
-
-	mp->tls[0] = mp->id;	// so 386 asm can find it
-	if(0){
-		runtime·printf("newosproc stk=%p m=%p g=%p clone=%p id=%d/%d ostk=%p\n",
-			stk, mp, mp->g0, runtime·clone, mp->id, (int32)mp->tls[0], &mp);
-	}
-
-	// Disable signals during clone, so that the new thread starts
-	// with signals disabled.  It will enable them in minit.
-	runtime·rtsigprocmask(SIG_SETMASK, &sigset_all, &oset, sizeof oset);
-	ret = runtime·clone(flags, stk, mp, mp->g0, runtime·mstart);
-	runtime·rtsigprocmask(SIG_SETMASK, &oset, nil, sizeof oset);
-
-	if(ret < 0) {
-		runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), -ret);
-		runtime·throw("runtime.newosproc");
-	}
-}
-
-void
-runtime·osinit(void)
-{
-	runtime·ncpu = getproccount();
-}
-
-// Random bytes initialized at startup.  These come
-// from the ELF AT_RANDOM auxiliary vector (vdso_linux_amd64.c).
-byte*	runtime·startup_random_data;
-uint32	runtime·startup_random_data_len;
-
-#pragma textflag NOSPLIT
-void
-runtime·get_random_data(byte **rnd, int32 *rnd_len)
-{
-	if(runtime·startup_random_data != nil) {
-		*rnd = runtime·startup_random_data;
-		*rnd_len = runtime·startup_random_data_len;
-	} else {
-		#pragma dataflag NOPTR
-		static byte urandom_data[HashRandomBytes];
-		int32 fd;
-		fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0);
-		if(runtime·read(fd, urandom_data, HashRandomBytes) == HashRandomBytes) {
-			*rnd = urandom_data;
-			*rnd_len = HashRandomBytes;
-		} else {
-			*rnd = nil;
-			*rnd_len = 0;
-		}
-		runtime·close(fd);
-	}
-}
-
-void
-runtime·goenvs(void)
-{
-	runtime·goenvs_unix();
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
-void
-runtime·mpreinit(M *mp)
-{
-	mp->gsignal = runtime·malg(32*1024);	// OS X wants >=8K, Linux >=2K
-	mp->gsignal->m = mp;
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the new thread, can not allocate memory.
-void
-runtime·minit(void)
-{
-	// Initialize signal handling.
-	runtime·signalstack((byte*)g->m->gsignal->stack.lo, 32*1024);
-	runtime·rtsigprocmask(SIG_SETMASK, &sigset_none, nil, sizeof(Sigset));
-}
-
-// Called from dropm to undo the effect of an minit.
-void
-runtime·unminit(void)
-{
-	runtime·signalstack(nil, 0);
-}
-
-uintptr
-runtime·memlimit(void)
-{
-	Rlimit rl;
-	extern byte runtime·text[], runtime·end[];
-	uintptr used;
-
-	if(runtime·getrlimit(RLIMIT_AS, &rl) != 0)
-		return 0;
-	if(rl.rlim_cur >= 0x7fffffff)
-		return 0;
-
-	// Estimate our VM footprint excluding the heap.
-	// Not an exact science: use size of binary plus
-	// some room for thread stacks.
-	used = runtime·end - runtime·text + (64<<20);
-	if(used >= rl.rlim_cur)
-		return 0;
-
-	// If there's not at least 16 MB left, we're probably
-	// not going to be able to do much.  Treat as no limit.
-	rl.rlim_cur -= used;
-	if(rl.rlim_cur < (16<<20))
-		return 0;
-
-	return rl.rlim_cur - used;
-}
-
-#ifdef GOARCH_386
-#define sa_handler k_sa_handler
-#endif
-
-/*
- * This assembler routine takes the args from registers, puts them on the stack,
- * and calls sighandler().
- */
-extern void runtime·sigtramp(void);
-extern void runtime·sigreturn(void);	// calls rt_sigreturn, only used with SA_RESTORER
-
-void
-runtime·setsig(int32 i, GoSighandler *fn, bool restart)
-{
-	SigactionT sa;
-
-	runtime·memclr((byte*)&sa, sizeof sa);
-	sa.sa_flags = SA_ONSTACK | SA_SIGINFO | SA_RESTORER;
-	if(restart)
-		sa.sa_flags |= SA_RESTART;
-	sa.sa_mask = ~0ULL;
-	// Although Linux manpage says "sa_restorer element is obsolete and
-	// should not be used". x86_64 kernel requires it. Only use it on
-	// x86.
-#ifdef GOARCH_386
-	sa.sa_restorer = (void*)runtime·sigreturn;
-#endif
-#ifdef GOARCH_amd64
-	sa.sa_restorer = (void*)runtime·sigreturn;
-#endif
-	if(fn == runtime·sighandler)
-		fn = (void*)runtime·sigtramp;
-	sa.sa_handler = fn;
-	if(runtime·rt_sigaction(i, &sa, nil, sizeof(sa.sa_mask)) != 0)
-		runtime·throw("rt_sigaction failure");
-}
-
-GoSighandler*
-runtime·getsig(int32 i)
-{
-	SigactionT sa;
-
-	runtime·memclr((byte*)&sa, sizeof sa);
-	if(runtime·rt_sigaction(i, nil, &sa, sizeof(sa.sa_mask)) != 0)
-		runtime·throw("rt_sigaction read failure");
-	if((void*)sa.sa_handler == runtime·sigtramp)
-		return runtime·sighandler;
-	return (void*)sa.sa_handler;
-}
-
-void
-runtime·signalstack(byte *p, int32 n)
-{
-	SigaltstackT st;
-
-	st.ss_sp = p;
-	st.ss_size = n;
-	st.ss_flags = 0;
-	if(p == nil)
-		st.ss_flags = SS_DISABLE;
-	runtime·sigaltstack(&st, nil);
-}
-
-void
-runtime·unblocksignals(void)
-{
-	runtime·rtsigprocmask(SIG_SETMASK, &sigset_none, nil, sizeof sigset_none);
-}
-
-#pragma textflag NOSPLIT
-int8*
-runtime·signame(int32 sig)
-{
-	return runtime·sigtab[sig].name;
-}
diff --git a/src/runtime/os_linux.go b/src/runtime/os_linux.go
index 41123ad..bd492f5 100644
--- a/src/runtime/os_linux.go
+++ b/src/runtime/os_linux.go
@@ -6,12 +6,32 @@ package runtime
 
 import "unsafe"
 
+//go:noescape
 func futex(addr unsafe.Pointer, op int32, val uint32, ts, addr2 unsafe.Pointer, val3 uint32) int32
+
+//go:noescape
 func clone(flags int32, stk, mm, gg, fn unsafe.Pointer) int32
-func rt_sigaction(sig uintptr, new, old unsafe.Pointer, size uintptr) int32
-func sigaltstack(new, old unsafe.Pointer)
-func setitimer(mode int32, new, old unsafe.Pointer)
-func rtsigprocmask(sig int32, new, old unsafe.Pointer, size int32)
+
+//go:noescape
+func rt_sigaction(sig uintptr, new, old *sigactiont, size uintptr) int32
+
+//go:noescape
+func sigaltstack(new, old *sigaltstackt)
+
+//go:noescape
+func sigfwd(fn uintptr, sig uint32, info *siginfo, ctx unsafe.Pointer)
+
+//go:noescape
+func setitimer(mode int32, new, old *itimerval)
+
+//go:noescape
+func rtsigprocmask(sig uint32, new, old *sigset, size int32)
+
+//go:noescape
 func getrlimit(kind int32, limit unsafe.Pointer) int32
 func raise(sig int32)
+func raiseproc(sig int32)
+
+//go:noescape
 func sched_getaffinity(pid, len uintptr, buf *uintptr) int32
+func osyield()
diff --git a/src/runtime/os_linux.h b/src/runtime/os_linux.h
deleted file mode 100644
index 75606d6..0000000
--- a/src/runtime/os_linux.h
+++ /dev/null
@@ -1,41 +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.
-
-
-// Linux-specific system calls
-int32	runtime·futex(uint32*, int32, uint32, Timespec*, uint32*, uint32);
-int32	runtime·clone(int32, void*, M*, G*, void(*)(void));
-
-struct SigactionT;
-int32	runtime·rt_sigaction(uintptr, struct SigactionT*, void*, uintptr);
-
-void	runtime·sigaltstack(SigaltstackT*, SigaltstackT*);
-void	runtime·sigpanic(void);
-void runtime·setitimer(int32, Itimerval*, Itimerval*);
-
-enum {
-	SS_DISABLE = 2,
-	NSIG = 65,
-	SI_USER = 0,
-	SIG_SETMASK = 2,
-	RLIMIT_AS = 9,
-};
-
-// It's hard to tease out exactly how big a Sigset is, but
-// rt_sigprocmask crashes if we get it wrong, so if binaries
-// are running, this is right.
-typedef struct Sigset Sigset;
-struct Sigset
-{
-	uint32 mask[2];
-};
-void	runtime·rtsigprocmask(int32, Sigset*, Sigset*, int32);
-void	runtime·unblocksignals(void);
-
-typedef struct Rlimit Rlimit;
-struct Rlimit {
-	uintptr	rlim_cur;
-	uintptr	rlim_max;
-};
-int32	runtime·getrlimit(int32, Rlimit*);
diff --git a/src/runtime/os_linux_386.c b/src/runtime/os_linux_386.c
deleted file mode 100644
index dc89d04..0000000
--- a/src/runtime/os_linux_386.c
+++ /dev/null
@@ -1,38 +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 "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "textflag.h"
-
-#define AT_NULL		0
-#define AT_RANDOM	25
-#define AT_SYSINFO	32
-extern uint32 runtime·_vdso;
-
-#pragma textflag NOSPLIT
-void
-runtime·linux_setup_vdso(int32 argc, byte **argv)
-{
-	byte **envp;
-	uint32 *auxv;
-
-	// skip envp to get to ELF auxiliary vector.
-	for(envp = &argv[argc+1]; *envp != nil; envp++)
-		;
-	envp++;
-	
-	for(auxv=(uint32*)envp; auxv[0] != AT_NULL; auxv += 2) {
-		if(auxv[0] == AT_SYSINFO) {
-			runtime·_vdso = auxv[1];
-			continue;
-		}
-		if(auxv[0] == AT_RANDOM) {
-			runtime·startup_random_data = (byte*)auxv[1];
-			runtime·startup_random_data_len = 16;
-			continue;
-		}
-	}
-}
diff --git a/src/runtime/os_linux_386.go b/src/runtime/os_linux_386.go
new file mode 100644
index 0000000..e2120da
--- /dev/null
+++ b/src/runtime/os_linux_386.go
@@ -0,0 +1,35 @@
+// 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"
+
+const (
+	_AT_NULL    = 0
+	_AT_RANDOM  = 25
+	_AT_SYSINFO = 32
+)
+
+var _vdso uint32
+
+func sysargs(argc int32, argv **byte) {
+	// skip over argv, envv to get to auxv
+	n := argc + 1
+	for argv_index(argv, n) != nil {
+		n++
+	}
+	n++
+	auxv := (*[1 << 28]uint32)(add(unsafe.Pointer(argv), uintptr(n)*ptrSize))
+
+	for i := 0; auxv[i] != _AT_NULL; i += 2 {
+		switch auxv[i] {
+		case _AT_SYSINFO:
+			_vdso = auxv[i+1]
+
+		case _AT_RANDOM:
+			startupRandomData = (*[16]byte)(unsafe.Pointer(uintptr(auxv[i+1])))[:]
+		}
+	}
+}
diff --git a/src/runtime/os_linux_arm.c b/src/runtime/os_linux_arm.c
deleted file mode 100644
index e3eda7c..0000000
--- a/src/runtime/os_linux_arm.c
+++ /dev/null
@@ -1,80 +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 "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "textflag.h"
-
-#define AT_NULL		0
-#define AT_PLATFORM	15 // introduced in at least 2.6.11
-#define AT_HWCAP	16 // introduced in at least 2.6.11
-#define AT_RANDOM	25 // introduced in 2.6.29
-#define HWCAP_VFP	(1 << 6) // introduced in at least 2.6.11
-#define HWCAP_VFPv3	(1 << 13) // introduced in 2.6.30
-static uint32 runtime·randomNumber;
-uint8  runtime·armArch = 6;	// we default to ARMv6
-uint32 runtime·hwcap;	// set by setup_auxv
-extern uint8  runtime·goarm;	// set by 5l
-
-void
-runtime·checkgoarm(void)
-{
-	if(runtime·goarm > 5 && !(runtime·hwcap & HWCAP_VFP)) {
-		runtime·printf("runtime: this CPU has no floating point hardware, so it cannot run\n");
-		runtime·printf("this GOARM=%d binary. Recompile using GOARM=5.\n", runtime·goarm);
-		runtime·exit(1);
-	}
-	if(runtime·goarm > 6 && !(runtime·hwcap & HWCAP_VFPv3)) {
-		runtime·printf("runtime: this CPU has no VFPv3 floating point hardware, so it cannot run\n");
-		runtime·printf("this GOARM=%d binary. Recompile using GOARM=6.\n", runtime·goarm);
-		runtime·exit(1);
-	}
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·setup_auxv(int32 argc, byte **argv)
-{
-	byte **envp;
-	byte *rnd;
-	uint32 *auxv;
-	uint32 t;
-
-	// skip envp to get to ELF auxiliary vector.
-	for(envp = &argv[argc+1]; *envp != nil; envp++)
-		;
-	envp++;
-	
-	for(auxv=(uint32*)envp; auxv[0] != AT_NULL; auxv += 2) {
-		switch(auxv[0]) {
-		case AT_RANDOM: // kernel provided 16-byte worth of random data
-			if(auxv[1]) {
-				rnd = (byte*)auxv[1];
-				runtime·randomNumber = rnd[4] | rnd[5]<<8 | rnd[6]<<16 | rnd[7]<<24;
-			}
-			break;
-		case AT_PLATFORM: // v5l, v6l, v7l
-			if(auxv[1]) {
-				t = *(uint8*)(auxv[1]+1);
-				if(t >= '5' && t <= '7')
-					runtime·armArch = t - '0';
-			}
-			break;
-		case AT_HWCAP: // CPU capability bit flags
-			runtime·hwcap = auxv[1];
-			break;
-		}
-	}
-}
-
-#pragma textflag NOSPLIT
-int64
-runtime·cputicks(void)
-{
-	// 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.
-	// runtime·randomNumber provides better seeding of fastrand1.
-	return runtime·nanotime() + runtime·randomNumber;
-}
diff --git a/src/runtime/os_linux_arm.go b/src/runtime/os_linux_arm.go
new file mode 100644
index 0000000..3749640
--- /dev/null
+++ b/src/runtime/os_linux_arm.go
@@ -0,0 +1,72 @@
+// 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"
+
+const (
+	_AT_NULL     = 0
+	_AT_PLATFORM = 15 //  introduced in at least 2.6.11
+	_AT_HWCAP    = 16 // introduced in at least 2.6.11
+	_AT_RANDOM   = 25 // introduced in 2.6.29
+
+	_HWCAP_VFP   = 1 << 6  // introduced in at least 2.6.11
+	_HWCAP_VFPv3 = 1 << 13 // introduced in 2.6.30
+)
+
+var randomNumber uint32
+var armArch uint8 = 6 // we default to ARMv6
+var hwcap uint32      // set by setup_auxv
+
+func checkgoarm() {
+	if goarm > 5 && hwcap&_HWCAP_VFP == 0 {
+		print("runtime: this CPU has no floating point hardware, so it cannot run\n")
+		print("this GOARM=", goarm, " binary. Recompile using GOARM=5.\n")
+		exit(1)
+	}
+	if goarm > 6 && hwcap&_HWCAP_VFPv3 == 0 {
+		print("runtime: this CPU has no VFPv3 floating point hardware, so it cannot run\n")
+		print("this GOARM=", goarm, " binary. Recompile using GOARM=5.\n")
+		exit(1)
+	}
+}
+
+func sysargs(argc int32, argv **byte) {
+	// skip over argv, envv to get to auxv
+	n := argc + 1
+	for argv_index(argv, n) != nil {
+		n++
+	}
+	n++
+	auxv := (*[1 << 28]uint32)(add(unsafe.Pointer(argv), uintptr(n)*ptrSize))
+
+	for i := 0; auxv[i] != _AT_NULL; i += 2 {
+		switch auxv[i] {
+		case _AT_RANDOM: // kernel provides a pointer to 16-bytes worth of random data
+			startupRandomData = (*[16]byte)(unsafe.Pointer(uintptr(auxv[i+1])))[:]
+			// the pointer provided may not be word aligned, so we must treat it
+			// as a byte array.
+			randomNumber = uint32(startupRandomData[4]) | uint32(startupRandomData[5])<<8 |
+				uint32(startupRandomData[6])<<16 | uint32(startupRandomData[7])<<24
+
+		case _AT_PLATFORM: // v5l, v6l, v7l
+			t := *(*uint8)(unsafe.Pointer(uintptr(auxv[i+1] + 1)))
+			if '5' <= t && t <= '7' {
+				armArch = t - '0'
+			}
+
+		case _AT_HWCAP: // CPU capability bit flags
+			hwcap = auxv[i+1]
+		}
+	}
+}
+
+//go:nosplit
+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_linux_arm64.go b/src/runtime/os_linux_arm64.go
new file mode 100644
index 0000000..3f994f1
--- /dev/null
+++ b/src/runtime/os_linux_arm64.go
@@ -0,0 +1,20 @@
+// 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
+
+//go:nosplit
+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.c b/src/runtime/os_nacl.c
deleted file mode 100644
index 14b5583..0000000
--- a/src/runtime/os_nacl.c
+++ /dev/null
@@ -1,312 +0,0 @@
-// Copyright 2010 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 "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "arch_GOARCH.h"
-#include "textflag.h"
-#include "stack.h"
-
-int8 *goos = "nacl";
-extern SigTab runtime·sigtab[];
-
-void runtime·sigtramp(void);
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
-void
-runtime·mpreinit(M *mp)
-{
-	mp->gsignal = runtime·malg(32*1024);	// OS X wants >=8K, Linux >=2K
-	mp->gsignal->m = mp;
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the new thread, can not allocate memory.
-void
-runtime·minit(void)
-{
-	int32 ret;
-
-	// Initialize signal handling
-	ret = runtime·nacl_exception_stack((byte*)g->m->gsignal->stack.lo, 32*1024);
-	if(ret < 0)
-		runtime·printf("runtime: nacl_exception_stack: error %d\n", -ret);
-
-	ret = runtime·nacl_exception_handler(runtime·sigtramp, nil);
-	if(ret < 0)
-		runtime·printf("runtime: nacl_exception_handler: error %d\n", -ret);
-}
-
-// Called from dropm to undo the effect of an minit.
-void
-runtime·unminit(void)
-{
-}
-
-int8 runtime·sigtrampf[] = "runtime: signal at PC=%X AX=%X CX=%X DX=%X BX=%X DI=%X R15=%X *SP=%X\n";
-int8 runtime·sigtrampp[] = "runtime: sigtramp";
-
-extern byte runtime·tls0[];
-
-void
-runtime·osinit(void)
-{
-	runtime·ncpu = 1;
-	g->m->procid = 2;
-//runtime·nacl_exception_handler(runtime·sigtramp, nil);
-}
-
-void
-runtime·crash(void)
-{
-	*(int32*)0 = 0;
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·get_random_data(byte **rnd, int32 *rnd_len)
-{
-	*rnd = nil;
-	*rnd_len = 0;
-}
-
-void
-runtime·goenvs(void)
-{
-	runtime·goenvs_unix();
-}
-
-void
-runtime·initsig(void)
-{
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·usleep(uint32 us)
-{
-	Timespec ts;
-	
-	ts.tv_sec = us/1000000;
-	ts.tv_nsec = (us%1000000)*1000;
-	runtime·nacl_nanosleep(&ts, nil);
-}
-
-void runtime·mstart_nacl(void);
-
-void
-runtime·newosproc(M *mp, void *stk)
-{
-	int32 ret;
-	void **tls;
-
-	tls = (void**)mp->tls;
-	tls[0] = mp->g0;
-	tls[1] = mp;
-	ret = runtime·nacl_thread_create(runtime·mstart_nacl, stk, tls+2, 0);
-	if(ret < 0) {
-		runtime·printf("nacl_thread_create: error %d\n", -ret);
-		runtime·throw("newosproc");
-	}
-}
-
-static void
-semacreate(void)
-{
-	int32 mu, cond;
-	
-	mu = runtime·nacl_mutex_create(0);
-	if(mu < 0) {
-		runtime·printf("nacl_mutex_create: error %d\n", -mu);
-		runtime·throw("semacreate");
-	}
-	cond = runtime·nacl_cond_create(0);
-	if(cond < 0) {
-		runtime·printf("nacl_cond_create: error %d\n", -cond);
-		runtime·throw("semacreate");
-	}
-	g->m->waitsemalock = mu;
-	g->m->scalararg[0] = cond; // assigned to m->waitsema
-}
-
-#pragma textflag NOSPLIT
-uint32
-runtime·semacreate(void)
-{
-	void (*fn)(void);
-	uint32 x;
-	
-	fn = semacreate;
-	runtime·onM(&fn);
-	x = g->m->scalararg[0];
-	g->m->scalararg[0] = 0;
-	return x;
-}
-
-static void
-semasleep(void)
-{
-	int32 ret;
-	int64 ns;
-	
-	ns = (int64)(uint32)g->m->scalararg[0] | (int64)(uint32)g->m->scalararg[1]<<32;
-	g->m->scalararg[0] = 0;
-	g->m->scalararg[1] = 0;
-	
-	ret = runtime·nacl_mutex_lock(g->m->waitsemalock);
-	if(ret < 0) {
-		//runtime·printf("nacl_mutex_lock: error %d\n", -ret);
-		runtime·throw("semasleep");
-	}
-	if(g->m->waitsemacount > 0) {
-		g->m->waitsemacount = 0;
-		runtime·nacl_mutex_unlock(g->m->waitsemalock);
-		g->m->scalararg[0] = 0;
-		return;
-	}
-
-	while(g->m->waitsemacount == 0) {
-		if(ns < 0) {
-			ret = runtime·nacl_cond_wait(g->m->waitsema, g->m->waitsemalock);
-			if(ret < 0) {
-				//runtime·printf("nacl_cond_wait: error %d\n", -ret);
-				runtime·throw("semasleep");
-			}
-		} else {
-			Timespec ts;
-			
-			ns += runtime·nanotime();
-			ts.tv_sec = runtime·timediv(ns, 1000000000, (int32*)&ts.tv_nsec);
-			ret = runtime·nacl_cond_timed_wait_abs(g->m->waitsema, g->m->waitsemalock, &ts);
-			if(ret == -ETIMEDOUT) {
-				runtime·nacl_mutex_unlock(g->m->waitsemalock);
-				g->m->scalararg[0] = -1;
-				return;
-			}
-			if(ret < 0) {
-				//runtime·printf("nacl_cond_timed_wait_abs: error %d\n", -ret);
-				runtime·throw("semasleep");
-			}
-		}
-	}
-			
-	g->m->waitsemacount = 0;
-	runtime·nacl_mutex_unlock(g->m->waitsemalock);
-	g->m->scalararg[0] = 0;
-}
-
-#pragma textflag NOSPLIT
-int32
-runtime·semasleep(int64 ns)
-{
-	int32 r;
-	void (*fn)(void);
-
-	g->m->scalararg[0] = (uint32)ns;
-	g->m->scalararg[1] = (uint32)(ns>>32);
-	fn = semasleep;
-	runtime·onM(&fn);
-	r = g->m->scalararg[0];
-	g->m->scalararg[0] = 0;
-	return r;
-}
-
-static void
-semawakeup(void)
-{
-	int32 ret;
-	M *mp;
-	
-	mp = g->m->ptrarg[0];
-	g->m->ptrarg[0] = nil;
-
-	ret = runtime·nacl_mutex_lock(mp->waitsemalock);
-	if(ret < 0) {
-		//runtime·printf("nacl_mutex_lock: error %d\n", -ret);
-		runtime·throw("semawakeup");
-	}
-	if(mp->waitsemacount != 0) {
-		//runtime·printf("semawakeup: double wakeup\n");
-		runtime·throw("semawakeup");
-	}
-	mp->waitsemacount = 1;
-	runtime·nacl_cond_signal(mp->waitsema);
-	runtime·nacl_mutex_unlock(mp->waitsemalock);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·semawakeup(M *mp)
-{
-	void (*fn)(void);
-
-	g->m->ptrarg[0] = mp;
-	fn = semawakeup;
-	runtime·onM(&fn);
-}
-
-uintptr
-runtime·memlimit(void)
-{
-	runtime·printf("memlimit\n");
-	return 0;
-}
-
-#pragma dataflag NOPTR
-static int8 badsignal[] = "runtime: signal received on thread not created by Go.\n";
-
-// This runs on a foreign stack, without an m or a g.  No stack split.
-#pragma textflag NOSPLIT
-void
-runtime·badsignal2(void)
-{
-	runtime·write(2, badsignal, sizeof badsignal - 1);
-	runtime·exit(2);
-}
-
-void	runtime·madvise(byte*, uintptr, int32) { }
-void runtime·munmap(byte*, uintptr) {}
-
-void
-runtime·resetcpuprofiler(int32 hz)
-{
-	USED(hz);
-}
-
-void
-runtime·sigdisable(uint32)
-{
-}
-
-void
-runtime·sigenable(uint32)
-{
-}
-
-void
-runtime·closeonexec(int32)
-{
-}
-
-uint32 runtime·writelock; // test-and-set spin lock for runtime.write
-
-/*
-An attempt at IRT. Doesn't work. See end of sys_nacl_amd64.s.
-
-void (*runtime·nacl_irt_query)(void);
-
-int8 runtime·nacl_irt_basic_v0_1_str[] = "nacl-irt-basic-0.1";
-void *runtime·nacl_irt_basic_v0_1[6]; // exit, gettod, clock, nanosleep, sched_yield, sysconf
-int32 runtime·nacl_irt_basic_v0_1_size = sizeof(runtime·nacl_irt_basic_v0_1);
-
-int8 runtime·nacl_irt_memory_v0_3_str[] = "nacl-irt-memory-0.3";
-void *runtime·nacl_irt_memory_v0_3[3]; // mmap, munmap, mprotect
-int32 runtime·nacl_irt_memory_v0_3_size = sizeof(runtime·nacl_irt_memory_v0_3);
-
-int8 runtime·nacl_irt_thread_v0_1_str[] = "nacl-irt-thread-0.1";
-void *runtime·nacl_irt_thread_v0_1[3]; // thread_create, thread_exit, thread_nice
-int32 runtime·nacl_irt_thread_v0_1_size = sizeof(runtime·nacl_irt_thread_v0_1);
-*/
diff --git a/src/runtime/os_nacl.go b/src/runtime/os_nacl.go
index 8dd43ff..3b4c136 100644
--- a/src/runtime/os_nacl.go
+++ b/src/runtime/os_nacl.go
@@ -6,8 +6,8 @@ package runtime
 
 import "unsafe"
 
-func nacl_exception_stack(p unsafe.Pointer, size int32) int32
-func nacl_exception_handler(fn, arg unsafe.Pointer) int32
+func nacl_exception_stack(p uintptr, size int32) int32
+func nacl_exception_handler(fn uintptr, arg unsafe.Pointer) int32
 func nacl_sem_create(flag int32) int32
 func nacl_sem_wait(sem int32) int32
 func nacl_sem_post(sem int32) int32
@@ -19,21 +19,45 @@ func nacl_cond_create(flag int32) int32
 func nacl_cond_wait(cond, n int32) int32
 func nacl_cond_signal(cond int32) int32
 func nacl_cond_broadcast(cond int32) int32
-func nacl_cond_timed_wait_abs(cond, lock int32, ts unsafe.Pointer) int32
-func nacl_thread_create(fn, stk, tls, xx unsafe.Pointer) int32
-func nacl_nanosleep(ts, extra unsafe.Pointer) int32
 
+//go:noescape
+func nacl_cond_timed_wait_abs(cond, lock int32, ts *timespec) int32
+func nacl_thread_create(fn uintptr, stk, tls, xx unsafe.Pointer) int32
+
+//go:noescape
+func nacl_nanosleep(ts, extra *timespec) int32
+func nanotime() int64
+func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) unsafe.Pointer
+func exit(code int32)
+func osyield()
+
+//go:noescape
+func write(fd uintptr, p unsafe.Pointer, n int32) int32
+
+//go:linkname os_sigpipe os.sigpipe
 func os_sigpipe() {
-	gothrow("too many writes on closed pipe")
+	throw("too many writes on closed pipe")
 }
 
 func sigpanic() {
 	g := getg()
 	if !canpanic(g) {
-		gothrow("unexpected signal during runtime execution")
+		throw("unexpected signal during runtime execution")
 	}
 
 	// Native Client only invokes the exception handler for memory faults.
 	g.sig = _SIGSEGV
 	panicmem()
 }
+
+func sigfwd(fn uintptr, sig uint32, info *siginfo, ctx unsafe.Pointer) {
+	throw("sigfwd not implemented")
+}
+
+func raiseproc(sig int32) {
+}
+
+// Stubs so tests can link correctly.  These should never be called.
+func open(name *byte, mode, perm int32) int32
+func closefd(fd int32) int32
+func read(fd int32, p unsafe.Pointer, n int32) int32
diff --git a/src/runtime/os_nacl.h b/src/runtime/os_nacl.h
deleted file mode 100644
index 7c9d9c2..0000000
--- a/src/runtime/os_nacl.h
+++ /dev/null
@@ -1,162 +0,0 @@
-enum {
-	NSIG = 32,
-	SI_USER = 1,
-
-	// native_client/src/trusted/service_runtime/include/sys/errno.h
-	// The errors are mainly copied from Linux.
-	EPERM = 1,  /* Operation not permitted */
-	ENOENT = 2,  /* No such file or directory */
-	ESRCH = 3,  /* No such process */
-	EINTR = 4,  /* Interrupted system call */
-	EIO = 5,  /* I/O error */
-	ENXIO = 6,  /* No such device or address */
-	E2BIG = 7,  /* Argument list too long */
-	ENOEXEC = 8,  /* Exec format error */
-	EBADF = 9,  /* Bad file number */
-	ECHILD = 10,  /* No child processes */
-	EAGAIN = 11,  /* Try again */
-	ENOMEM = 12,  /* Out of memory */
-	EACCES = 13,  /* Permission denied */
-	EFAULT = 14,  /* Bad address */
-	EBUSY = 16,  /* Device or resource busy */
-	EEXIST = 17,  /* File exists */
-	EXDEV = 18,  /* Cross-device link */
-	ENODEV = 19,  /* No such device */
-	ENOTDIR = 20,  /* Not a directory */
-	EISDIR = 21,  /* Is a directory */
-	EINVAL = 22,  /* Invalid argument */
-	ENFILE = 23,  /* File table overflow */
-	EMFILE = 24,  /* Too many open files */
-	ENOTTY = 25,  /* Not a typewriter */
-	EFBIG = 27,  /* File too large */
-	ENOSPC = 28,  /* No space left on device */
-	ESPIPE = 29,  /* Illegal seek */
-	EROFS = 30,  /* Read-only file system */
-	EMLINK = 31,  /* Too many links */
-	EPIPE = 32,  /* Broken pipe */
-	ENAMETOOLONG = 36,  /* File name too long */
-	ENOSYS = 38,  /* Function not implemented */
-	EDQUOT = 122, /* Quota exceeded */
-	EDOM = 33,   /* Math arg out of domain of func */
-	ERANGE = 34, /* Math result not representable */
-	EDEADLK = 35,  /* Deadlock condition */
-	ENOLCK = 37, /* No record locks available */
-	ENOTEMPTY = 39,  /* Directory not empty */
-	ELOOP = 40,  /* Too many symbolic links */
-	ENOMSG = 42, /* No message of desired type */
-	EIDRM = 43,  /* Identifier removed */
-	ECHRNG = 44, /* Channel number out of range */
-	EL2NSYNC = 45, /* Level 2 not synchronized */
-	EL3HLT = 46, /* Level 3 halted */
-	EL3RST = 47, /* Level 3 reset */
-	ELNRNG = 48, /* Link number out of range */
-	EUNATCH = 49,  /* Protocol driver not attached */
-	ENOCSI = 50, /* No CSI structure available */
-	EL2HLT = 51, /* Level 2 halted */
-	EBADE = 52,  /* Invalid exchange */
-	EBADR = 53,  /* Invalid request descriptor */
-	EXFULL = 54, /* Exchange full */
-	ENOANO = 55, /* No anode */
-	EBADRQC = 56,  /* Invalid request code */
-	EBADSLT = 57,  /* Invalid slot */
-	EDEADLOCK = EDEADLK,  /* File locking deadlock error */
-	EBFONT = 59, /* Bad font file fmt */
-	ENOSTR = 60, /* Device not a stream */
-	ENODATA = 61,  /* No data (for no delay io) */
-	ETIME = 62,  /* Timer expired */
-	ENOSR = 63,  /* Out of streams resources */
-	ENONET = 64, /* Machine is not on the network */
-	ENOPKG = 65, /* Package not installed */
-	EREMOTE = 66,  /* The object is remote */
-	ENOLINK = 67,  /* The link has been severed */
-	EADV = 68,   /* Advertise error */
-	ESRMNT = 69, /* Srmount error */
-	ECOMM = 70,  /* Communication error on send */
-	EPROTO = 71, /* Protocol error */
-	EMULTIHOP = 72,  /* Multihop attempted */
-	EDOTDOT = 73,  /* Cross mount point (not really error) */
-	EBADMSG = 74,  /* Trying to read unreadable message */
-	EOVERFLOW = 75, /* Value too large for defined data type */
-	ENOTUNIQ = 76, /* Given log. name not unique */
-	EBADFD = 77, /* f.d. invalid for this operation */
-	EREMCHG = 78,  /* Remote address changed */
-	ELIBACC = 79,  /* Can't access a needed shared lib */
-	ELIBBAD = 80,  /* Accessing a corrupted shared lib */
-	ELIBSCN = 81,  /* .lib section in a.out corrupted */
-	ELIBMAX = 82,  /* Attempting to link in too many libs */
-	ELIBEXEC = 83, /* Attempting to exec a shared library */
-	EILSEQ = 84,
-	EUSERS = 87,
-	ENOTSOCK = 88,  /* Socket operation on non-socket */
-	EDESTADDRREQ = 89,  /* Destination address required */
-	EMSGSIZE = 90,    /* Message too long */
-	EPROTOTYPE = 91,  /* Protocol wrong type for socket */
-	ENOPROTOOPT = 92, /* Protocol not available */
-	EPROTONOSUPPORT = 93, /* Unknown protocol */
-	ESOCKTNOSUPPORT = 94, /* Socket type not supported */
-	EOPNOTSUPP = 95, /* Operation not supported on transport endpoint */
-	EPFNOSUPPORT = 96, /* Protocol family not supported */
-	EAFNOSUPPORT = 97, /* Address family not supported by protocol family */
-	EADDRINUSE = 98,    /* Address already in use */
-	EADDRNOTAVAIL = 99, /* Address not available */
-	ENETDOWN = 100,    /* Network interface is not configured */
-	ENETUNREACH = 101,   /* Network is unreachable */
-	ENETRESET = 102,
-	ECONNABORTED = 103,  /* Connection aborted */
-	ECONNRESET = 104,  /* Connection reset by peer */
-	ENOBUFS = 105, /* No buffer space available */
-	EISCONN = 106,   /* Socket is already connected */
-	ENOTCONN = 107,    /* Socket is not connected */
-	ESHUTDOWN = 108, /* Can't send after socket shutdown */
-	ETOOMANYREFS = 109,
-	ETIMEDOUT = 110,   /* Connection timed out */
-	ECONNREFUSED = 111,  /* Connection refused */
-	EHOSTDOWN = 112,   /* Host is down */
-	EHOSTUNREACH = 113,  /* Host is unreachable */
-	EALREADY = 114,    /* Socket already connected */
-	EINPROGRESS = 115,   /* Connection already in progress */
-	ESTALE = 116,
-	ENOTSUP = EOPNOTSUPP,   /* Not supported */
-	ENOMEDIUM = 123,   /* No medium (in tape drive) */
-	ECANCELED = 125, /* Operation canceled. */
-	ELBIN = 2048,  /* Inode is remote (not really error) */
-	EFTYPE = 2049,  /* Inappropriate file type or format */
-	ENMFILE = 2050,  /* No more files */
-	EPROCLIM = 2051,
-	ENOSHARE = 2052,  /* No such host or network path */
-	ECASECLASH = 2053,  /* Filename exists with different case */
-	EWOULDBLOCK = EAGAIN,      /* Operation would block */
-
-	// native_client/src/trusted/service_runtime/include/bits/mman.h.
-	// NOTE: DO NOT USE native_client/src/shared/imc/nacl_imc_c.h.
-	// Those MAP_*values are different from these.
-	PROT_NONE	= 0x0,
-	PROT_READ	= 0x1,
-	PROT_WRITE	= 0x2,
-	PROT_EXEC	= 0x4,
-
-	MAP_SHARED	= 0x1,
-	MAP_PRIVATE	= 0x2,
-	MAP_FIXED	= 0x10,
-	MAP_ANON	= 0x20,
-};
-typedef byte* kevent_udata;
-
-int32	runtime·nacl_exception_stack(byte*, int32);
-int32	runtime·nacl_exception_handler(void*, void*);
-int32	runtime·nacl_sem_create(int32);
-int32	runtime·nacl_sem_wait(int32);
-int32	runtime·nacl_sem_post(int32);
-int32	runtime·nacl_mutex_create(int32);
-int32	runtime·nacl_mutex_lock(int32);
-int32	runtime·nacl_mutex_trylock(int32);
-int32	runtime·nacl_mutex_unlock(int32);
-int32	runtime·nacl_cond_create(int32);
-int32	runtime·nacl_cond_wait(int32, int32);
-int32	runtime·nacl_cond_signal(int32);
-int32	runtime·nacl_cond_broadcast(int32);
-int32	runtime·nacl_cond_timed_wait_abs(int32, int32, Timespec*);
-int32	runtime·nacl_thread_create(void*, void*, void*, void*);
-int32	runtime·nacl_nanosleep(Timespec*, Timespec*);
-
-void	runtime·sigpanic(void);
diff --git a/src/runtime/os_nacl_arm.c b/src/runtime/os_nacl_arm.c
deleted file mode 100644
index 1248ea6..0000000
--- a/src/runtime/os_nacl_arm.c
+++ /dev/null
@@ -1,24 +0,0 @@
-// 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 "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "textflag.h"
-
-void
-runtime·checkgoarm(void)
-{
-	return; // NaCl/ARM only supports ARMv7
-}
-
-#pragma textflag NOSPLIT
-int64
-runtime·cputicks(void)
-{
-	// 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 runtime·nanotime();
-}
diff --git a/src/runtime/os_nacl_arm.go b/src/runtime/os_nacl_arm.go
new file mode 100644
index 0000000..f94c183
--- /dev/null
+++ b/src/runtime/os_nacl_arm.go
@@ -0,0 +1,23 @@
+// 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
+
+func checkgoarm() {
+	// TODO(minux): FP checks like in os_linux_arm.go.
+
+	// NaCl/ARM only supports ARMv7
+	if goarm != 7 {
+		print("runtime: NaCl requires ARMv7. Recompile using GOARM=7.\n")
+		exit(1)
+	}
+}
+
+//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_netbsd.c b/src/runtime/os_netbsd.c
deleted file mode 100644
index 58e5bed..0000000
--- a/src/runtime/os_netbsd.c
+++ /dev/null
@@ -1,368 +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.
-
-#include "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "signal_unix.h"
-#include "stack.h"
-#include "textflag.h"
-
-enum
-{
-	ESRCH = 3,
-	ENOTSUP = 91,
-
-	// From NetBSD's <sys/time.h>
-	CLOCK_REALTIME = 0,
-	CLOCK_VIRTUAL = 1,
-	CLOCK_PROF = 2,
-	CLOCK_MONOTONIC = 3
-};
-
-extern SigTab runtime·sigtab[];
-
-static Sigset sigset_none;
-static Sigset sigset_all = { ~(uint32)0, ~(uint32)0, ~(uint32)0, ~(uint32)0, };
-
-extern void runtime·getcontext(UcontextT *context);
-extern int32 runtime·lwp_create(UcontextT *context, uintptr flags, void *lwpid);
-extern void runtime·lwp_mcontext_init(void *mc, void *stack, M *mp, G *gp, void (*fn)(void));
-extern int32 runtime·lwp_park(Timespec *abstime, int32 unpark, void *hint, void *unparkhint);
-extern int32 runtime·lwp_unpark(int32 lwp, void *hint);
-extern int32 runtime·lwp_self(void);
-
-// From NetBSD's <sys/sysctl.h>
-#define	CTL_HW	6
-#define	HW_NCPU	3
-
-static int32
-getncpu(void)
-{
-	uint32 mib[2];
-	uint32 out;
-	int32 ret;
-	uintptr nout;
-
-	// Fetch hw.ncpu via sysctl.
-	mib[0] = CTL_HW;
-	mib[1] = HW_NCPU;
-	nout = sizeof out;
-	out = 0;
-	ret = runtime·sysctl(mib, 2, (byte*)&out, &nout, nil, 0);
-	if(ret >= 0)
-		return out;
-	else
-		return 1;
-}
-
-#pragma textflag NOSPLIT
-uintptr
-runtime·semacreate(void)
-{
-	return 1;
-}
-
-static void
-semasleep(void)
-{
-	int64 ns;
-	Timespec ts;
-
-	ns = (int64)(uint32)g->m->scalararg[0] | (int64)(uint32)g->m->scalararg[1]<<32;
-	g->m->scalararg[0] = 0;
-	g->m->scalararg[1] = 0;
-
-	// spin-mutex lock
-	while(runtime·xchg(&g->m->waitsemalock, 1))
-		runtime·osyield();
-
-	for(;;) {
-		// lock held
-		if(g->m->waitsemacount == 0) {
-			// sleep until semaphore != 0 or timeout.
-			// thrsleep unlocks m->waitsemalock.
-			if(ns < 0) {
-				// TODO(jsing) - potential deadlock!
-				//
-				// There is a potential deadlock here since we
-				// have to release the waitsemalock mutex
-				// before we call lwp_park() to suspend the
-				// thread. This allows another thread to
-				// release the lock and call lwp_unpark()
-				// before the thread is actually suspended.
-				// If this occurs the current thread will end
-				// up sleeping indefinitely. Unfortunately
-				// the NetBSD kernel does not appear to provide
-				// a mechanism for unlocking the userspace
-				// mutex once the thread is actually parked.
-				runtime·atomicstore(&g->m->waitsemalock, 0);
-				runtime·lwp_park(nil, 0, &g->m->waitsemacount, nil);
-			} else {
-				ns = ns + runtime·nanotime();
-				// NOTE: tv_nsec is int64 on amd64, so this assumes a little-endian system.
-				ts.tv_nsec = 0;
-				ts.tv_sec = runtime·timediv(ns, 1000000000, (int32*)&ts.tv_nsec);
-				// TODO(jsing) - potential deadlock!
-				// See above for details.
-				runtime·atomicstore(&g->m->waitsemalock, 0);
-				runtime·lwp_park(&ts, 0, &g->m->waitsemacount, nil);
-			}
-			// reacquire lock
-			while(runtime·xchg(&g->m->waitsemalock, 1))
-				runtime·osyield();
-		}
-
-		// lock held (again)
-		if(g->m->waitsemacount != 0) {
-			// semaphore is available.
-			g->m->waitsemacount--;
-			// spin-mutex unlock
-			runtime·atomicstore(&g->m->waitsemalock, 0);
-			g->m->scalararg[0] = 0; // semaphore acquired
-			return;
-		}
-
-		// semaphore not available.
-		// if there is a timeout, stop now.
-		// otherwise keep trying.
-		if(ns >= 0)
-			break;
-	}
-
-	// lock held but giving up
-	// spin-mutex unlock
-	runtime·atomicstore(&g->m->waitsemalock, 0);
-	g->m->scalararg[0] = -1;
-	return;
-}
-
-#pragma textflag NOSPLIT
-int32
-runtime·semasleep(int64 ns)
-{
-	int32 r;
-	void (*fn)(void);
-
-	g->m->scalararg[0] = (uint32)ns;
-	g->m->scalararg[1] = (uint32)(ns>>32);
-	fn = semasleep;
-	runtime·onM(&fn);
-	r = g->m->scalararg[0];
-	g->m->scalararg[0] = 0;
-	return r;
-}
-
-static void badsemawakeup(void);
-
-#pragma textflag NOSPLIT
-void
-runtime·semawakeup(M *mp)
-{
-	uint32 ret;
-	void (*fn)(void);
-	void *oldptr;
-	uintptr oldscalar;
-
-	// spin-mutex lock
-	while(runtime·xchg(&mp->waitsemalock, 1))
-		runtime·osyield();
-	mp->waitsemacount++;
-	// TODO(jsing) - potential deadlock, see semasleep() for details.
-	// Confirm that LWP is parked before unparking...
-	ret = runtime·lwp_unpark(mp->procid, &mp->waitsemacount);
-	if(ret != 0 && ret != ESRCH) {
-		// semawakeup can be called on signal stack.
-		// Save old ptrarg/scalararg so we can restore them.
-		oldptr = g->m->ptrarg[0];
-		oldscalar = g->m->scalararg[0];
-		g->m->ptrarg[0] = mp;
-		g->m->scalararg[0] = ret;
-		fn = badsemawakeup;
-		if(g == g->m->gsignal)
-			fn();
-		else
-			runtime·onM(&fn);
-		g->m->ptrarg[0] = oldptr;
-		g->m->scalararg[0] = oldscalar;
-	}
-	// spin-mutex unlock
-	runtime·atomicstore(&mp->waitsemalock, 0);
-}
-
-static void
-badsemawakeup(void)
-{
-	M *mp;
-	int32 ret;
-
-	mp = g->m->ptrarg[0];
-	g->m->ptrarg[0] = nil;
-	ret = g->m->scalararg[0];
-	g->m->scalararg[0] = 0;
-
-	runtime·printf("thrwakeup addr=%p sem=%d ret=%d\n", &mp->waitsemacount, mp->waitsemacount, ret);
-}
-
-void
-runtime·newosproc(M *mp, void *stk)
-{
-	UcontextT uc;
-	int32 ret;
-
-	if(0) {
-		runtime·printf(
-			"newosproc stk=%p m=%p g=%p id=%d/%d ostk=%p\n",
-			stk, mp, mp->g0, mp->id, (int32)mp->tls[0], &mp);
-	}
-
-	mp->tls[0] = mp->id;	// so 386 asm can find it
-
-	runtime·getcontext(&uc);
-	
-	uc.uc_flags = _UC_SIGMASK | _UC_CPU;
-	uc.uc_link = nil;
-	uc.uc_sigmask = sigset_all;
-
-	runtime·lwp_mcontext_init(&uc.uc_mcontext, stk, mp, mp->g0, runtime·mstart);
-
-	ret = runtime·lwp_create(&uc, 0, &mp->procid);
-
-	if(ret < 0) {
-		runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount() - 1, -ret);
-		runtime·throw("runtime.newosproc");
-	}
-}
-
-void
-runtime·osinit(void)
-{
-	runtime·ncpu = getncpu();
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·get_random_data(byte **rnd, int32 *rnd_len)
-{
-	#pragma dataflag NOPTR
-	static byte urandom_data[HashRandomBytes];
-	int32 fd;
-	fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0);
-	if(runtime·read(fd, urandom_data, HashRandomBytes) == HashRandomBytes) {
-		*rnd = urandom_data;
-		*rnd_len = HashRandomBytes;
-	} else {
-		*rnd = nil;
-		*rnd_len = 0;
-	}
-	runtime·close(fd);
-}
-
-void
-runtime·goenvs(void)
-{
-	runtime·goenvs_unix();
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
-void
-runtime·mpreinit(M *mp)
-{
-	mp->gsignal = runtime·malg(32*1024);
-	mp->gsignal->m = mp;
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the new thread, can not allocate memory.
-void
-runtime·minit(void)
-{
-	g->m->procid = runtime·lwp_self();
-
-	// Initialize signal handling
-	runtime·signalstack((byte*)g->m->gsignal->stack.lo, 32*1024);
-	runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil);
-}
-
-// Called from dropm to undo the effect of an minit.
-void
-runtime·unminit(void)
-{
-	runtime·signalstack(nil, 0);
-}
-
-uintptr
-runtime·memlimit(void)
-{
-	return 0;
-}
-
-extern void runtime·sigtramp(void);
-
-typedef struct sigaction {
-	union {
-		void    (*_sa_handler)(int32);
-		void    (*_sa_sigaction)(int32, Siginfo*, void *);
-	} _sa_u;			/* signal handler */
-	uint32	sa_mask[4];		/* signal mask to apply */
-	int32	sa_flags;		/* see signal options below */
-} SigactionT;
-
-void
-runtime·setsig(int32 i, GoSighandler *fn, bool restart)
-{
-	SigactionT sa;
-
-	runtime·memclr((byte*)&sa, sizeof sa);
-	sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
-	if(restart)
-		sa.sa_flags |= SA_RESTART;
-	sa.sa_mask[0] = ~0U;
-	sa.sa_mask[1] = ~0U;
-	sa.sa_mask[2] = ~0U;
-	sa.sa_mask[3] = ~0U;
-	if (fn == runtime·sighandler)
-		fn = (void*)runtime·sigtramp;
-	sa._sa_u._sa_sigaction = (void*)fn;
-	runtime·sigaction(i, &sa, nil);
-}
-
-GoSighandler*
-runtime·getsig(int32 i)
-{
-	SigactionT sa;
-
-	runtime·memclr((byte*)&sa, sizeof sa);
-	runtime·sigaction(i, nil, &sa);
-	if((void*)sa._sa_u._sa_sigaction == runtime·sigtramp)
-		return runtime·sighandler;
-	return (void*)sa._sa_u._sa_sigaction;
-}
-
-void
-runtime·signalstack(byte *p, int32 n)
-{
-	StackT st;
-
-	st.ss_sp = (void*)p;
-	st.ss_size = n;
-	st.ss_flags = 0;
-	if(p == nil)
-		st.ss_flags = SS_DISABLE;
-	runtime·sigaltstack(&st, nil);
-}
-
-void
-runtime·unblocksignals(void)
-{
-	runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil);
-}
-
-#pragma textflag NOSPLIT
-int8*
-runtime·signame(int32 sig)
-{
-	return runtime·sigtab[sig].name;
-}
diff --git a/src/runtime/os_netbsd.go b/src/runtime/os_netbsd.go
index f000c5e..af52099 100644
--- a/src/runtime/os_netbsd.go
+++ b/src/runtime/os_netbsd.go
@@ -6,15 +6,42 @@ package runtime
 
 import "unsafe"
 
-func setitimer(mode int32, new, old unsafe.Pointer)
-func sigaction(sig int32, new, old unsafe.Pointer)
-func sigaltstack(new, old unsafe.Pointer)
-func sigprocmask(mode int32, new, old unsafe.Pointer)
+//go:noescape
+func setitimer(mode int32, new, old *itimerval)
+
+//go:noescape
+func sigaction(sig int32, new, old *sigactiont)
+
+//go:noescape
+func sigaltstack(new, old *sigaltstackt)
+
+func sigfwd(fn uintptr, sig uint32, info *siginfo, ctx unsafe.Pointer) {
+	throw("sigfwd not implemented")
+}
+
+//go:noescape
+func sigprocmask(mode int32, new, old *sigset)
+
+//go:noescape
 func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32
+
 func lwp_tramp()
+
 func raise(sig int32)
+func raiseproc(sig int32)
+
+//go:noescape
 func getcontext(ctxt unsafe.Pointer)
+
+//go:noescape
 func lwp_create(ctxt unsafe.Pointer, flags uintptr, lwpid unsafe.Pointer) int32
-func lwp_park(abstime unsafe.Pointer, unpark int32, hint, unparkhint unsafe.Pointer) int32
+
+//go:noescape
+func lwp_park(abstime *timespec, unpark int32, hint, unparkhint unsafe.Pointer) int32
+
+//go:noescape
 func lwp_unpark(lwp int32, hint unsafe.Pointer) int32
+
 func lwp_self() int32
+
+func osyield()
diff --git a/src/runtime/os_netbsd.h b/src/runtime/os_netbsd.h
deleted file mode 100644
index f95db32..0000000
--- a/src/runtime/os_netbsd.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2010 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.
-
-
-typedef uintptr kevent_udata;
-
-struct sigaction;
-
-void	runtime·sigpanic(void);
-
-void	runtime·setitimer(int32, Itimerval*, Itimerval*);
-void	runtime·sigaction(int32, struct sigaction*, struct sigaction*);
-void	runtime·sigaltstack(SigaltstackT*, SigaltstackT*);
-void	runtime·sigprocmask(int32, Sigset*, Sigset*);
-void	runtime·unblocksignals(void);
-int32	runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr);
-extern void runtime·lwp_tramp(void);
-
-enum {
-	SS_DISABLE = 4,
-	SIG_BLOCK = 1,
-	SIG_UNBLOCK = 2,
-	SIG_SETMASK = 3,
-	NSIG = 33,
-	SI_USER = 0,
-
-	// From NetBSD's <sys/ucontext.h>
-	_UC_SIGMASK = 0x01,
-	_UC_CPU = 0x04,
-};
diff --git a/src/runtime/os_netbsd_386.c b/src/runtime/os_netbsd_386.c
deleted file mode 100644
index 23e9db3..0000000
--- a/src/runtime/os_netbsd_386.c
+++ /dev/null
@@ -1,17 +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 "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-
-void
-runtime·lwp_mcontext_init(McontextT *mc, void *stack, M *mp, G *gp, void (*fn)(void))
-{
-	mc->__gregs[REG_EIP] = (uint32)runtime·lwp_tramp;
-	mc->__gregs[REG_UESP] = (uint32)stack;
-	mc->__gregs[REG_EBX] = (uint32)mp;
-	mc->__gregs[REG_EDX] = (uint32)gp;
-	mc->__gregs[REG_ESI] = (uint32)fn;
-}
diff --git a/src/runtime/os_netbsd_amd64.c b/src/runtime/os_netbsd_amd64.c
deleted file mode 100644
index 226846c..0000000
--- a/src/runtime/os_netbsd_amd64.c
+++ /dev/null
@@ -1,18 +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 "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-
-void
-runtime·lwp_mcontext_init(McontextT *mc, void *stack, M *mp, G *gp, void (*fn)(void))
-{
-	// Machine dependent mcontext initialisation for LWP.
-	mc->__gregs[REG_RIP] = (uint64)runtime·lwp_tramp;
-	mc->__gregs[REG_RSP] = (uint64)stack;
-	mc->__gregs[REG_R8] = (uint64)mp;
-	mc->__gregs[REG_R9] = (uint64)gp;
-	mc->__gregs[REG_R12] = (uint64)fn;
-}
diff --git a/src/runtime/os_netbsd_arm.c b/src/runtime/os_netbsd_arm.c
deleted file mode 100644
index 9dd4bcd..0000000
--- a/src/runtime/os_netbsd_arm.c
+++ /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.
-
-#include "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "signal_GOOS_GOARCH.h"
-#include "textflag.h"
-
-void
-runtime·lwp_mcontext_init(McontextT *mc, void *stack, M *mp, G *gp, void (*fn)(void))
-{
-	mc->__gregs[REG_R15] = (uint32)runtime·lwp_tramp;
-	mc->__gregs[REG_R13] = (uint32)stack;
-	mc->__gregs[REG_R0] = (uint32)mp;
-	mc->__gregs[REG_R1] = (uint32)gp;
-	mc->__gregs[REG_R2] = (uint32)fn;
-}
-
-void
-runtime·checkgoarm(void)
-{
-	// TODO(minux)
-}
-
-#pragma textflag NOSPLIT
-int64
-runtime·cputicks() {
-	// 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 runtime·nanotime();
-}
diff --git a/src/runtime/os_netbsd_arm.go b/src/runtime/os_netbsd_arm.go
new file mode 100644
index 0000000..03032e8
--- /dev/null
+++ b/src/runtime/os_netbsd_arm.go
@@ -0,0 +1,35 @@
+// 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"
+
+func lwp_mcontext_init(mc *mcontextt, stk unsafe.Pointer, mp *m, gp *g, fn uintptr) {
+	// Machine dependent mcontext initialisation for LWP.
+	mc.__gregs[_REG_R15] = uint32(funcPC(lwp_tramp))
+	mc.__gregs[_REG_R13] = uint32(uintptr(stk))
+	mc.__gregs[_REG_R0] = uint32(uintptr(unsafe.Pointer(mp)))
+	mc.__gregs[_REG_R1] = uint32(uintptr(unsafe.Pointer(gp)))
+	mc.__gregs[_REG_R2] = uint32(fn)
+}
+
+func checkgoarm() {
+	// TODO(minux): FP checks like in os_linux_arm.go.
+
+	// osinit not called yet, so ncpu not set: must use getncpu directly.
+	if getncpu() > 1 && goarm < 7 {
+		print("runtime: this system has multiple CPUs and must use\n")
+		print("atomic synchronization instructions. Recompile using GOARM=7.\n")
+		exit(1)
+	}
+}
+
+//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_openbsd.c b/src/runtime/os_openbsd.c
deleted file mode 100644
index eebaa13..0000000
--- a/src/runtime/os_openbsd.c
+++ /dev/null
@@ -1,309 +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.
-
-#include "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "signal_unix.h"
-#include "stack.h"
-#include "textflag.h"
-
-enum
-{
-	ESRCH = 3,
-	EAGAIN = 35,
-	EWOULDBLOCK = EAGAIN,
-	ENOTSUP = 91,
-
-	// From OpenBSD's sys/time.h
-	CLOCK_REALTIME = 0,
-	CLOCK_VIRTUAL = 1,
-	CLOCK_PROF = 2,
-	CLOCK_MONOTONIC = 3
-};
-
-extern SigTab runtime·sigtab[];
-
-static Sigset sigset_none;
-static Sigset sigset_all = ~(Sigset)0;
-
-extern int32 runtime·tfork(TforkT *param, uintptr psize, M *mp, G *gp, void (*fn)(void));
-extern int32 runtime·thrsleep(void *ident, int32 clock_id, void *tsp, void *lock, const int32 *abort);
-extern int32 runtime·thrwakeup(void *ident, int32 n);
-
-// From OpenBSD's <sys/sysctl.h>
-#define	CTL_HW	6
-#define	HW_NCPU	3
-
-static int32
-getncpu(void)
-{
-	uint32 mib[2];
-	uint32 out;
-	int32 ret;
-	uintptr nout;
-
-	// Fetch hw.ncpu via sysctl.
-	mib[0] = CTL_HW;
-	mib[1] = HW_NCPU;
-	nout = sizeof out;
-	out = 0;
-	ret = runtime·sysctl(mib, 2, (byte*)&out, &nout, nil, 0);
-	if(ret >= 0)
-		return out;
-	else
-		return 1;
-}
-
-#pragma textflag NOSPLIT
-uintptr
-runtime·semacreate(void)
-{
-	return 1;
-}
-
-#pragma textflag NOSPLIT
-int32
-runtime·semasleep(int64 ns)
-{
-	Timespec ts, *tsp = nil;
-
-	// Compute sleep deadline.
-	if(ns >= 0) {
-		int32 nsec;
-		ns += runtime·nanotime();
-		ts.tv_sec = runtime·timediv(ns, 1000000000, &nsec);
-		ts.tv_nsec = nsec; // tv_nsec is int64 on amd64
-		tsp = &ts;
-	}
-
-	for(;;) {
-		int32 ret;
-
-		// spin-mutex lock
-		while(runtime·xchg(&g->m->waitsemalock, 1))
-			runtime·osyield();
-
-		if(g->m->waitsemacount != 0) {
-			// semaphore is available.
-			g->m->waitsemacount--;
-			// spin-mutex unlock
-			runtime·atomicstore(&g->m->waitsemalock, 0);
-			return 0;  // semaphore acquired
-		}
-
-		// sleep until semaphore != 0 or timeout.
-		// thrsleep unlocks m->waitsemalock.
-		ret = runtime·thrsleep(&g->m->waitsemacount, CLOCK_MONOTONIC, tsp, &g->m->waitsemalock, (int32 *)&g->m->waitsemacount);
-		if(ret == EWOULDBLOCK)
-			return -1;
-	}
-}
-
-static void badsemawakeup(void);
-
-#pragma textflag NOSPLIT
-void
-runtime·semawakeup(M *mp)
-{
-	uint32 ret;
-	void *oldptr;
-	uint32 oldscalar;
-	void (*fn)(void);
-
-	// spin-mutex lock
-	while(runtime·xchg(&mp->waitsemalock, 1))
-		runtime·osyield();
-	mp->waitsemacount++;
-	ret = runtime·thrwakeup(&mp->waitsemacount, 1);
-	if(ret != 0 && ret != ESRCH) {
-		// semawakeup can be called on signal stack.
-		// Save old ptrarg/scalararg so we can restore them.
-		oldptr = g->m->ptrarg[0];
-		oldscalar = g->m->scalararg[0];
-		g->m->ptrarg[0] = mp;
-		g->m->scalararg[0] = ret;
-		fn = badsemawakeup;
-		if(g == g->m->gsignal)
-			fn();
-		else
-			runtime·onM(&fn);
-		g->m->ptrarg[0] = oldptr;
-		g->m->scalararg[0] = oldscalar;
-	}
-	// spin-mutex unlock
-	runtime·atomicstore(&mp->waitsemalock, 0);
-}
-
-static void
-badsemawakeup(void)
-{
-	M *mp;
-	int32 ret;
-
-	mp = g->m->ptrarg[0];
-	g->m->ptrarg[0] = nil;
-	ret = g->m->scalararg[0];
-	g->m->scalararg[0] = 0;
-
-	runtime·printf("thrwakeup addr=%p sem=%d ret=%d\n", &mp->waitsemacount, mp->waitsemacount, ret);
-}
-
-void
-runtime·newosproc(M *mp, void *stk)
-{
-	TforkT param;
-	Sigset oset;
-	int32 ret;
-
-	if(0) {
-		runtime·printf(
-			"newosproc stk=%p m=%p g=%p id=%d/%d ostk=%p\n",
-			stk, mp, mp->g0, mp->id, (int32)mp->tls[0], &mp);
-	}
-
-	mp->tls[0] = mp->id;	// so 386 asm can find it
-
-	param.tf_tcb = (byte*)&mp->tls[0];
-	param.tf_tid = (int32*)&mp->procid;
-	param.tf_stack = stk;
-
-	oset = runtime·sigprocmask(SIG_SETMASK, sigset_all);
-	ret = runtime·tfork(&param, sizeof(param), mp, mp->g0, runtime·mstart);
-	runtime·sigprocmask(SIG_SETMASK, oset);
-
-	if(ret < 0) {
-		runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount() - 1, -ret);
-		if (ret == -ENOTSUP)
-			runtime·printf("runtime: is kern.rthreads disabled?\n");
-		runtime·throw("runtime.newosproc");
-	}
-}
-
-void
-runtime·osinit(void)
-{
-	runtime·ncpu = getncpu();
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·get_random_data(byte **rnd, int32 *rnd_len)
-{
-	#pragma dataflag NOPTR
-	static byte urandom_data[HashRandomBytes];
-	int32 fd;
-	fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0);
-	if(runtime·read(fd, urandom_data, HashRandomBytes) == HashRandomBytes) {
-		*rnd = urandom_data;
-		*rnd_len = HashRandomBytes;
-	} else {
-		*rnd = nil;
-		*rnd_len = 0;
-	}
-	runtime·close(fd);
-}
-
-void
-runtime·goenvs(void)
-{
-	runtime·goenvs_unix();
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
-void
-runtime·mpreinit(M *mp)
-{
-	mp->gsignal = runtime·malg(32*1024);
-	mp->gsignal->m = mp;
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the new thread, can not allocate memory.
-void
-runtime·minit(void)
-{
-	// Initialize signal handling
-	runtime·signalstack((byte*)g->m->gsignal->stack.lo, 32*1024);
-	runtime·sigprocmask(SIG_SETMASK, sigset_none);
-}
-
-// Called from dropm to undo the effect of an minit.
-void
-runtime·unminit(void)
-{
-	runtime·signalstack(nil, 0);
-}
-
-uintptr
-runtime·memlimit(void)
-{
-	return 0;
-}
-
-extern void runtime·sigtramp(void);
-
-typedef struct sigaction {
-	union {
-		void    (*__sa_handler)(int32);
-		void    (*__sa_sigaction)(int32, Siginfo*, void *);
-	} __sigaction_u;		/* signal handler */
-	uint32	sa_mask;		/* signal mask to apply */
-	int32	sa_flags;		/* see signal options below */
-} SigactionT;
-
-void
-runtime·setsig(int32 i, GoSighandler *fn, bool restart)
-{
-	SigactionT sa;
-
-	runtime·memclr((byte*)&sa, sizeof sa);
-	sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
-	if(restart)
-		sa.sa_flags |= SA_RESTART;
-	sa.sa_mask = ~0U;
-	if(fn == runtime·sighandler)
-		fn = (void*)runtime·sigtramp;
-	sa.__sigaction_u.__sa_sigaction = (void*)fn;
-	runtime·sigaction(i, &sa, nil);
-}
-
-GoSighandler*
-runtime·getsig(int32 i)
-{
-	SigactionT sa;
-
-	runtime·memclr((byte*)&sa, sizeof sa);
-	runtime·sigaction(i, nil, &sa);
-	if((void*)sa.__sigaction_u.__sa_sigaction == runtime·sigtramp)
-		return runtime·sighandler;
-	return (void*)sa.__sigaction_u.__sa_sigaction;
-}
-
-void
-runtime·signalstack(byte *p, int32 n)
-{
-	StackT st;
-
-	st.ss_sp = (void*)p;
-	st.ss_size = n;
-	st.ss_flags = 0;
-	if(p == nil)
-		st.ss_flags = SS_DISABLE;
-	runtime·sigaltstack(&st, nil);
-}
-
-void
-runtime·unblocksignals(void)
-{
-	runtime·sigprocmask(SIG_SETMASK, sigset_none);
-}
-
-#pragma textflag NOSPLIT
-int8*
-runtime·signame(int32 sig)
-{
-	return runtime·sigtab[sig].name;
-}
diff --git a/src/runtime/os_openbsd.go b/src/runtime/os_openbsd.go
index a000f96..f94b490 100644
--- a/src/runtime/os_openbsd.go
+++ b/src/runtime/os_openbsd.go
@@ -6,12 +6,34 @@ package runtime
 
 import "unsafe"
 
-func setitimer(mode int32, new, old unsafe.Pointer)
-func sigaction(sig int32, new, old unsafe.Pointer)
-func sigaltstack(new, old unsafe.Pointer)
+//go:noescape
+func setitimer(mode int32, new, old *itimerval)
+
+//go:noescape
+func sigaction(sig int32, new, old *sigactiont)
+
+//go:noescape
+func sigaltstack(new, old *stackt)
+
+//go:noescape
+func sigfwd(fn uintptr, sig uint32, info *siginfo, ctx unsafe.Pointer)
+
+//go:noescape
 func sigprocmask(mode int32, new uint32) uint32
+
+//go:noescape
 func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32
+
 func raise(sig int32)
-func tfork(param unsafe.Pointer, psize uintptr, mm, gg, fn unsafe.Pointer) int32
-func thrsleep(ident unsafe.Pointer, clock_id int32, tsp, lock, abort unsafe.Pointer) int32
-func thrwakeup(ident unsafe.Pointer, n int32) int32
+func raiseproc(sig int32)
+
+//go:noescape
+func tfork(param *tforkt, psize uintptr, mm *m, gg *g, fn uintptr) int32
+
+//go:noescape
+func thrsleep(ident uintptr, clock_id int32, tsp *timespec, lock uintptr, abort *uint32) int32
+
+//go:noescape
+func thrwakeup(ident uintptr, n int32) int32
+
+func osyield()
diff --git a/src/runtime/os_openbsd.h b/src/runtime/os_openbsd.h
deleted file mode 100644
index 6ad9810..0000000
--- a/src/runtime/os_openbsd.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2010 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.
-
-
-typedef byte* kevent_udata;
-
-struct sigaction;
-
-void	runtime·sigpanic(void);
-
-void	runtime·setitimer(int32, Itimerval*, Itimerval*);
-void	runtime·sigaction(int32, struct sigaction*, struct sigaction*);
-void	runtime·sigaltstack(SigaltstackT*, SigaltstackT*);
-Sigset	runtime·sigprocmask(int32, Sigset);
-void	runtime·unblocksignals(void);
-int32	runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr);
-
-enum {
-	SS_DISABLE = 4,
-	SIG_BLOCK = 1,
-	SIG_UNBLOCK = 2,
-	SIG_SETMASK = 3,
-	NSIG = 33,
-	SI_USER = 0,
-};
diff --git a/src/runtime/os_openbsd_arm.go b/src/runtime/os_openbsd_arm.go
new file mode 100644
index 0000000..b46fef0
--- /dev/null
+++ b/src/runtime/os_openbsd_arm.go
@@ -0,0 +1,24 @@
+// 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): FP checks like in os_linux_arm.go.
+
+	// osinit not called yet, so ncpu not set: must use getncpu directly.
+	if getncpu() > 1 && goarm < 7 {
+		print("runtime: this system has multiple CPUs and must use\n")
+		print("atomic synchronization instructions. Recompile using GOARM=7.\n")
+		exit(1)
+	}
+}
+
+//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_plan9.c b/src/runtime/os_plan9.c
deleted file mode 100644
index f8c543f..0000000
--- a/src/runtime/os_plan9.c
+++ /dev/null
@@ -1,362 +0,0 @@
-// Copyright 2010 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 "runtime.h"
-#include "os_GOOS.h"
-#include "arch_GOARCH.h"
-#include "textflag.h"
-#include "malloc.h"
-
-int8 *goos = "plan9";
-extern SigTab runtime·sigtab[];
-
-int32 runtime·postnote(int32, int8*);
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
-void
-runtime·mpreinit(M *mp)
-{
-	// Initialize stack and goroutine for note handling.
-	mp->gsignal = runtime·malg(32*1024);
-	mp->gsignal->m = mp;
-	mp->notesig = (int8*)runtime·mallocgc(ERRMAX*sizeof(int8), nil, FlagNoScan);
-
-	// Initialize stack for handling strings from the
-	// errstr system call, as used in package syscall.
-	mp->errstr = (byte*)runtime·mallocgc(ERRMAX*sizeof(byte), nil, FlagNoScan);
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the new thread, can not allocate memory.
-void
-runtime·minit(void)
-{
-	// Mask all SSE floating-point exceptions
-	// when running on the 64-bit kernel.
-	runtime·setfpmasks();
-}
-
-// Called from dropm to undo the effect of an minit.
-void
-runtime·unminit(void)
-{
-}
-
-
-static int32
-getproccount(void)
-{
-	int32 fd, i, n, ncpu;
-	byte buf[2048];
-
-	fd = runtime·open("/dev/sysstat", OREAD, 0);
-	if(fd < 0)
-		return 1;
-	ncpu = 0;
-	for(;;) {
-		n = runtime·read(fd, buf, sizeof buf);
-		if(n <= 0)
-			break;
-		for(i = 0; i < n; i++) {
-			if(buf[i] == '\n')
-				ncpu++;
-		}
-	}
-	runtime·close(fd);
-	return ncpu > 0 ? ncpu : 1;
-}
-
-static int32
-getpid(void)
-{
-	byte b[20], *c;
-	int32 fd;
-
-	runtime·memclr(b, sizeof(b));
-	fd = runtime·open("#c/pid", 0, 0);
-	if(fd >= 0) {
-		runtime·read(fd, b, sizeof(b));
-		runtime·close(fd);
-	}
-	c = b;
-	while(*c == ' ' || *c == '\t')
-		c++;
-	return runtime·atoi(c);
-}
-
-void
-runtime·osinit(void)
-{
-	runtime·ncpu = getproccount();
-	g->m->procid = getpid();
-	runtime·notify(runtime·sigtramp);
-}
-
-void
-runtime·crash(void)
-{
-	runtime·notify(nil);
-	*(int32*)0 = 0;
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·get_random_data(byte **rnd, int32 *rnd_len)
-{
-	static byte random_data[HashRandomBytes];
-	int32 fd;
-
-	fd = runtime·open("/dev/random", 0 /* O_RDONLY */, 0);
-	if(runtime·read(fd, random_data, HashRandomBytes) == HashRandomBytes) {
-		*rnd = random_data;
-		*rnd_len = HashRandomBytes;
-	} else {
-		*rnd = nil;
-		*rnd_len = 0;
-	}
-	runtime·close(fd);
-}
-
-void
-runtime·goenvs(void)
-{
-}
-
-void
-runtime·initsig(void)
-{
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·osyield(void)
-{
-	runtime·sleep(0);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·usleep(uint32 µs)
-{
-	uint32 ms;
-
-	ms = µs/1000;
-	if(ms == 0)
-		ms = 1;
-	runtime·sleep(ms);
-}
-
-#pragma textflag NOSPLIT
-int64
-runtime·nanotime(void)
-{
-	int64 ns, scratch;
-
-	ns = runtime·nsec(&scratch);
-	// TODO(aram): remove hack after I fix _nsec in the pc64 kernel.
-	if(ns == 0)
-		return scratch;
-	return ns;
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·itoa(int32 n, byte *p, uint32 len)
-{
-	byte *q, c;
-	uint32 i;
-
-	if(len <= 1)
-		return;
-
-	runtime·memclr(p, len);
-	q = p;
-
-	if(n==0) {
-		*q++ = '0';
-		USED(q);
-		return;
-	}
-	if(n < 0) {
-		*q++ = '-';
-		p++;
-		n = -n;
-	}
-	for(i=0; n > 0 && i < len; i++) {
-		*q++ = '0' + (n%10);
-		n = n/10;
-	}
-	for(q--; q >= p; ) {
-		c = *p;
-		*p++ = *q;
-		*q-- = c;
-	}
-}
-
-void
-runtime·goexitsall(int8 *status)
-{
-	int8 buf[ERRMAX];
-	M *mp;
-	int32 pid;
-
-	runtime·snprintf((byte*)buf, sizeof buf, "go: exit %s", status);
-	pid = getpid();
-	for(mp=runtime·atomicloadp(&runtime·allm); mp; mp=mp->alllink)
-		if(mp->procid != pid)
-			runtime·postnote(mp->procid, buf);
-}
-
-int32
-runtime·postnote(int32 pid, int8* msg)
-{
-	int32 fd;
-	intgo len;
-	uint8 buf[128];
-	uint8 tmp[16];
-	uint8 *p, *q;
-
-	runtime·memclr(buf, sizeof buf);
-
-	/* build path string /proc/pid/note */
-	q = tmp;
-	p = buf;
-	runtime·itoa(pid, tmp, sizeof tmp);
-	runtime·memmove((void*)p, (void*)"/proc/", 6);
-	for(p += 6; *p++ = *q++; );
-	p--;
-	runtime·memmove((void*)p, (void*)"/note", 5);
-
-	fd = runtime·open((int8*)buf, OWRITE, 0);
-	if(fd < 0)
-		return -1;
-
-	len = runtime·findnull((byte*)msg);
-	if(runtime·write(fd, msg, len) != len) {
-		runtime·close(fd);
-		return -1;
-	}
-	runtime·close(fd);
-	return 0;
-}
-
-static void exit(void);
-
-#pragma textflag NOSPLIT
-void
-runtime·exit(int32 e)
-{
-	void (*fn)(void);
-
-	g->m->scalararg[0] = e;
-	fn = exit;
-	runtime·onM(&fn);
-}
-
-static void
-exit(void)
-{
-	int32 e;
-	byte tmp[16];
-	int8 *status;
- 
- 	e = g->m->scalararg[0];
- 	g->m->scalararg[0] = 0;
-
-	if(e == 0)
-		status = "";
-	else {
-		/* build error string */
-		runtime·itoa(e, tmp, sizeof tmp);
-		status = (int8*)tmp;
-	}
-
-	runtime·goexitsall(status);
-	runtime·exits(status);
-}
-
-void
-runtime·newosproc(M *mp, void *stk)
-{
-	int32 pid;
-
-	if(0)
-		runtime·printf("newosproc mp=%p ostk=%p\n", mp, &mp);
-
-	USED(stk);
-	if((pid = runtime·rfork(RFPROC|RFMEM|RFNOWAIT)) < 0)
-		runtime·throw("newosproc: rfork failed\n");
-	if(pid == 0)
-		runtime·tstart_plan9(mp);
-}
-
-#pragma textflag NOSPLIT
-uintptr
-runtime·semacreate(void)
-{
-	return 1;
-}
-
-#pragma textflag NOSPLIT
-int32
-runtime·semasleep(int64 ns)
-{
-	int32 ret;
-	int32 ms;
-
-	if(ns >= 0) {
-		ms = runtime·timediv(ns, 1000000, nil);
-		if(ms == 0)
-			ms = 1;
-		ret = runtime·plan9_tsemacquire(&g->m->waitsemacount, ms);
-		if(ret == 1)
-			return 0;  // success
-		return -1;  // timeout or interrupted
-	}
-
-	while(runtime·plan9_semacquire(&g->m->waitsemacount, 1) < 0) {
-		/* interrupted; try again (c.f. lock_sema.c) */
-	}
-	return 0;  // success
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·semawakeup(M *mp)
-{
-	runtime·plan9_semrelease(&mp->waitsemacount, 1);
-}
-
-#pragma textflag NOSPLIT
-int32
-runtime·read(int32 fd, void *buf, int32 nbytes)
-{
-	return runtime·pread(fd, buf, nbytes, -1LL);
-}
-
-#pragma textflag NOSPLIT
-int32
-runtime·write(uintptr fd, void *buf, int32 nbytes)
-{
-	return runtime·pwrite((int32)fd, buf, nbytes, -1LL);
-}
-
-uintptr
-runtime·memlimit(void)
-{
-	return 0;
-}
-
-#pragma dataflag NOPTR
-static int8 badsignal[] = "runtime: signal received on thread not created by Go.\n";
-
-// This runs on a foreign stack, without an m or a g.  No stack split.
-#pragma textflag NOSPLIT
-void
-runtime·badsignal2(void)
-{
-	runtime·pwrite(2, badsignal, sizeof badsignal - 1, -1LL);
-	runtime·exits(badsignal);
-}
diff --git a/src/runtime/os_plan9.go b/src/runtime/os_plan9.go
index 10e5531..6def35c 100644
--- a/src/runtime/os_plan9.go
+++ b/src/runtime/os_plan9.go
@@ -6,36 +6,67 @@ package runtime
 
 import "unsafe"
 
-const _SIGPROF = 0 // dummy value for badsignal
+func closefd(fd int32) int32
 
+//go:noescape
+func open(name *byte, mode, perm int32) int32
+
+//go:noescape
 func pread(fd int32, buf unsafe.Pointer, nbytes int32, offset int64) int32
+
+//go:noescape
 func pwrite(fd int32, buf unsafe.Pointer, nbytes int32, offset int64) int32
+
 func seek(fd int32, offset int64, whence int32) int64
+
+//go:noescape
 func exits(msg *byte)
-func brk_(addr unsafe.Pointer) uintptr
+
+//go:noescape
+func brk_(addr unsafe.Pointer) int32
+
 func sleep(ms int32) int32
+
 func rfork(flags int32) int32
+
+//go:noescape
 func plan9_semacquire(addr *uint32, block int32) int32
+
+//go:noescape
 func plan9_tsemacquire(addr *uint32, ms int32) int32
+
+//go:noescape
 func plan9_semrelease(addr *uint32, count int32) int32
+
+//go:noescape
 func notify(fn unsafe.Pointer) int32
+
 func noted(mode int32) int32
+
+//go:noescape
 func nsec(*int64) int64
+
+//go:noescape
 func sigtramp(ureg, msg unsafe.Pointer)
+
 func setfpmasks()
+
+//go:noescape
 func tstart_plan9(newm *m)
+
 func errstr() string
 
 type _Plink uintptr
 
+//go:linkname os_sigpipe os.sigpipe
 func os_sigpipe() {
-	gothrow("too many writes on closed pipe")
+	throw("too many writes on closed pipe")
 }
 
 func sigpanic() {
 	g := getg()
 	if !canpanic(g) {
-		gothrow("unexpected signal during runtime execution")
+		throw("unexpected signal during runtime execution")
 	}
 
 	note := gostringnocopy((*byte)(unsafe.Pointer(g.m.notesig)))
@@ -47,12 +78,12 @@ func sigpanic() {
 			panicmem()
 		}
 		print("unexpected fault address ", hex(g.sigcode1), "\n")
-		gothrow("fault")
+		throw("fault")
 	case _SIGTRAP:
 		if g.paniconfault {
 			panicmem()
 		}
-		gothrow(note)
+		throw(note)
 	case _SIGINTDIV:
 		panicdivide()
 	case _SIGFLOAT:
diff --git a/src/runtime/os_plan9.h b/src/runtime/os_plan9.h
deleted file mode 100644
index 6d18024..0000000
--- a/src/runtime/os_plan9.h
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2010 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.
-
-// Plan 9-specific system calls
-int32	runtime·pread(int32 fd, void *buf, int32 nbytes, int64 offset);
-int32	runtime·pwrite(int32 fd, void *buf, int32 nbytes, int64 offset);
-int64	runtime·seek(int32 fd, int64 offset, int32 whence);
-void	runtime·exits(int8* msg);
-intptr	runtime·brk_(void*);
-int32	runtime·sleep(int32 ms);
-int32	runtime·rfork(int32 flags);
-int32	runtime·plan9_semacquire(uint32 *addr, int32 block);
-int32	runtime·plan9_tsemacquire(uint32 *addr, int32 ms);
-int32 	runtime·plan9_semrelease(uint32 *addr, int32 count);
-int32	runtime·notify(void (*fn)(void*, int8*));
-int32	runtime·noted(int32);
-int64	runtime·nsec(int64*);
-void	runtime·sigtramp(void*, int8*);
-void	runtime·sigpanic(void);
-void	runtime·goexitsall(int8*);
-void	runtime·setfpmasks(void);
-void	runtime·tstart_plan9(M *newm);
-
-/* open */
-enum
-{
-	OREAD	= 0,
-	OWRITE	= 1,
-	ORDWR	= 2,
-	OEXEC	= 3,
-	OTRUNC	= 16,
-	OCEXEC	= 32,
-	ORCLOSE	= 64,
-	OEXCL	= 0x1000
-};
-
-/* rfork */
-enum
-{
-	RFNAMEG         = (1<<0),
-	RFENVG          = (1<<1),
-	RFFDG           = (1<<2),
-	RFNOTEG         = (1<<3),
-	RFPROC          = (1<<4),
-	RFMEM           = (1<<5),
-	RFNOWAIT        = (1<<6),
-	RFCNAMEG        = (1<<10),
-	RFCENVG         = (1<<11),
-	RFCFDG          = (1<<12),
-	RFREND          = (1<<13),
-	RFNOMNT         = (1<<14)
-};
-
-/* notify */
-enum
-{
-	NCONT	= 0,
-	NDFLT	= 1
-};
-
-typedef struct Tos Tos;
-typedef intptr _Plink;
-
-struct Tos {
-	struct TosProf			/* Per process profiling */
-	{
-		_Plink	*pp;	/* known to be 0(ptr) */
-		_Plink	*next;	/* known to be 4(ptr) */
-		_Plink	*last;
-		_Plink	*first;
-		uint32	pid;
-		uint32	what;
-	} prof;
-	uint64	cyclefreq;	/* cycle clock frequency if there is one, 0 otherwise */
-	int64	kcycles;	/* cycles spent in kernel */
-	int64	pcycles;	/* cycles spent in process (kernel + user) */
-	uint32	pid;		/* might as well put the pid here */
-	uint32	clock;
-	/* top of stack is here */
-};
-
-enum {
-	NSIG = 14, /* number of signals in runtime·SigTab array */
-	ERRMAX = 128, /* max length of note string */
-
-	/* Notes in runtime·sigtab that are handled by runtime·sigpanic. */
-	SIGRFAULT = 2,
-	SIGWFAULT = 3,
-	SIGINTDIV = 4,
-	SIGFLOAT = 5,
-	SIGTRAP = 6,
-};
diff --git a/src/runtime/os_plan9_386.c b/src/runtime/os_plan9_386.c
deleted file mode 100644
index 42c6d16..0000000
--- a/src/runtime/os_plan9_386.c
+++ /dev/null
@@ -1,150 +0,0 @@
-// Copyright 2010 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 "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "signals_GOOS.h"
-
-void
-runtime·dumpregs(Ureg *u)
-{
-	runtime·printf("ax	%x\n", u->ax);
-	runtime·printf("bx	%x\n", u->bx);
-	runtime·printf("cx	%x\n", u->cx);
-	runtime·printf("dx	%x\n", u->dx);
-	runtime·printf("di	%x\n", u->di);
-	runtime·printf("si	%x\n", u->si);
-	runtime·printf("bp	%x\n", u->bp);
-	runtime·printf("sp	%x\n", u->sp);
-	runtime·printf("pc	%x\n", u->pc);
-	runtime·printf("flags	%x\n", u->flags);
-	runtime·printf("cs	%x\n", u->cs);
-	runtime·printf("fs	%x\n", u->fs);
-	runtime·printf("gs	%x\n", u->gs);
-}
-
-int32
-runtime·sighandler(void *v, int8 *note, G *gp)
-{
-	uintptr *sp;
-	SigTab *t;
-	bool crash;
-	Ureg *ureg;
-	intgo len, n;
-	int32 sig, flags;
-
-	ureg = (Ureg*)v;
-
-	// The kernel will never pass us a nil note or ureg so we probably
-	// made a mistake somewhere in runtime·sigtramp.
-	if(ureg == nil || note == nil) {
-		runtime·printf("sighandler: ureg %p note %p\n", ureg, note);
-		goto Throw;
-	}
-
-	// Check that the note is no more than ERRMAX bytes (including
-	// the trailing NUL). We should never receive a longer note.
-	len = runtime·findnull((byte*)note);
-	if(len > ERRMAX-1) {
-		runtime·printf("sighandler: note is longer than ERRMAX\n");
-		goto Throw;
-	}
-
-	// See if the note matches one of the patterns in runtime·sigtab.
-	// Notes that do not match any pattern can be handled at a higher
-	// level by the program but will otherwise be ignored.
-	flags = SigNotify;
-	for(sig = 0; sig < nelem(runtime·sigtab); sig++) {
-		t = &runtime·sigtab[sig];
-		n = runtime·findnull((byte*)t->name);
-		if(len < n)
-			continue;
-		if(runtime·strncmp((byte*)note, (byte*)t->name, n) == 0) {
-			flags = t->flags;
-			break;
-		}
-	}
-
-	if(flags & SigGoExit)
-		runtime·exits(note+9); // Strip "go: exit " prefix.
-
-	if(flags & SigPanic) {
-		// Copy the error string from sigtramp's stack into m->notesig so
-		// we can reliably access it from the panic routines.
-		runtime·memmove(g->m->notesig, note, len+1);
-
-		gp->sig = sig;
-		gp->sigpc = ureg->pc;
-
-		// Only push runtime·sigpanic if PC != 0.
-		//
-		// If PC == 0, probably panicked because of a call to a nil func.
-		// Not pushing that onto SP will make the trace look like a call
-		// to runtime·sigpanic instead. (Otherwise the trace will end at
-		// runtime·sigpanic and we won't get to see who faulted).
-		if(ureg->pc != 0) {
-			sp = (uintptr*)ureg->sp;
-			*--sp = ureg->pc;
-			ureg->sp = (uint32)sp;
-		}
-		ureg->pc = (uintptr)runtime·sigpanic;
-		return NCONT;
-	}
-
-	if(flags & SigNotify) {
-		// TODO(ality): See if os/signal wants it.
-		//if(runtime·sigsend(...))
-		//	return NCONT;
-	}
-	if(flags & SigKill)
-		goto Exit;
-	if(!(flags & SigThrow))
-		return NCONT;
-
-Throw:
-	g->m->throwing = 1;
-	g->m->caughtsig = gp;
-	runtime·startpanic();
-
-	runtime·printf("%s\n", note);
-	runtime·printf("PC=%x\n", ureg->pc);
-	runtime·printf("\n");
-
-	if(runtime·gotraceback(&crash)) {
-		runtime·goroutineheader(gp);
-		runtime·tracebacktrap(ureg->pc, ureg->sp, 0, gp);
-		runtime·tracebackothers(gp);
-		runtime·printf("\n");
-		runtime·dumpregs(ureg);
-	}
-	
-	if(crash)
-		runtime·crash();
-
-Exit:
-	runtime·goexitsall(note);
-	runtime·exits(note);
-	return NDFLT; // not reached
-}
-
-void
-runtime·sigenable(uint32 sig)
-{
-	USED(sig);
-}
-
-void
-runtime·sigdisable(uint32 sig)
-{
-	USED(sig);
-}
-
-void
-runtime·resetcpuprofiler(int32 hz)
-{
-	// TODO: Enable profiling interrupts.
-	
-	g->m->profilehz = hz;
-}
diff --git a/src/runtime/os_plan9_amd64.c b/src/runtime/os_plan9_amd64.c
deleted file mode 100644
index a9dc0eb..0000000
--- a/src/runtime/os_plan9_amd64.c
+++ /dev/null
@@ -1,158 +0,0 @@
-// Copyright 2010 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 "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "signals_GOOS.h"
-
-void
-runtime·dumpregs(Ureg *u)
-{
-	runtime·printf("ax	%X\n", u->ax);
-	runtime·printf("bx	%X\n", u->bx);
-	runtime·printf("cx	%X\n", u->cx);
-	runtime·printf("dx	%X\n", u->dx);
-	runtime·printf("di	%X\n", u->di);
-	runtime·printf("si	%X\n", u->si);
-	runtime·printf("bp	%X\n", u->bp);
-	runtime·printf("sp	%X\n", u->sp);
-	runtime·printf("r8	%X\n", u->r8);
-	runtime·printf("r9	%X\n", u->r9);
-	runtime·printf("r10	%X\n", u->r10);
-	runtime·printf("r11	%X\n", u->r11);
-	runtime·printf("r12	%X\n", u->r12);
-	runtime·printf("r13	%X\n", u->r13);
-	runtime·printf("r14	%X\n", u->r14);
-	runtime·printf("r15	%X\n", u->r15);
-	runtime·printf("ip	%X\n", u->ip);
-	runtime·printf("flags	%X\n", u->flags);
-	runtime·printf("cs	%X\n", (uint64)u->cs);
-	runtime·printf("fs	%X\n", (uint64)u->fs);
-	runtime·printf("gs	%X\n", (uint64)u->gs);
-}
-
-int32
-runtime·sighandler(void *v, int8 *note, G *gp)
-{
-	uintptr *sp;
-	SigTab *t;
-	bool crash;
-	Ureg *ureg;
-	intgo len, n;
-	int32 sig, flags;
-
-	ureg = (Ureg*)v;
-
-	// The kernel will never pass us a nil note or ureg so we probably
-	// made a mistake somewhere in runtime·sigtramp.
-	if(ureg == nil || note == nil) {
-		runtime·printf("sighandler: ureg %p note %p\n", ureg, note);
-		goto Throw;
-	}
-
-	// Check that the note is no more than ERRMAX bytes (including
-	// the trailing NUL). We should never receive a longer note.
-	len = runtime·findnull((byte*)note);
-	if(len > ERRMAX-1) {
-		runtime·printf("sighandler: note is longer than ERRMAX\n");
-		goto Throw;
-	}
-
-	// See if the note matches one of the patterns in runtime·sigtab.
-	// Notes that do not match any pattern can be handled at a higher
-	// level by the program but will otherwise be ignored.
-	flags = SigNotify;
-	for(sig = 0; sig < nelem(runtime·sigtab); sig++) {
-		t = &runtime·sigtab[sig];
-		n = runtime·findnull((byte*)t->name);
-		if(len < n)
-			continue;
-		if(runtime·strncmp((byte*)note, (byte*)t->name, n) == 0) {
-			flags = t->flags;
-			break;
-		}
-	}
-
-	if(flags & SigGoExit)
-		runtime·exits(note+9); // Strip "go: exit " prefix.
-
-	if(flags & SigPanic) {
-		// Copy the error string from sigtramp's stack into m->notesig so
-		// we can reliably access it from the panic routines.
-		runtime·memmove(g->m->notesig, note, len+1);
-
-		gp->sig = sig;
-		gp->sigpc = ureg->ip;
-
-		// Only push runtime·sigpanic if PC != 0.
-		//
-		// If PC == 0, probably panicked because of a call to a nil func.
-		// Not pushing that onto SP will make the trace look like a call
-		// to runtime·sigpanic instead. (Otherwise the trace will end at
-		// runtime·sigpanic and we won't get to see who faulted).
-		if(ureg->ip != 0) {
-			sp = (uintptr*)ureg->sp;
-			*--sp = ureg->ip;
-			ureg->sp = (uint64)sp;
-		}
-		ureg->ip = (uintptr)runtime·sigpanic;
-		return NCONT;
-	}
-
-	if(flags & SigNotify) {
-		// TODO(ality): See if os/signal wants it.
-		//if(runtime·sigsend(...))
-		//	return NCONT;
-	}
-	if(flags & SigKill)
-		goto Exit;
-	if(!(flags & SigThrow))
-		return NCONT;
-
-Throw:
-	g->m->throwing = 1;
-	g->m->caughtsig = gp;
-	runtime·startpanic();
-
-	runtime·printf("%s\n", note);
-	runtime·printf("PC=%X\n", ureg->ip);
-	runtime·printf("\n");
-
-	if(runtime·gotraceback(&crash)) {
-		runtime·goroutineheader(gp);
-		runtime·tracebacktrap(ureg->ip, ureg->sp, 0, gp);
-		runtime·tracebackothers(gp);
-		runtime·printf("\n");
-		runtime·dumpregs(ureg);
-	}
-	
-	if(crash)
-		runtime·crash();
-
-Exit:
-	runtime·goexitsall(note);
-	runtime·exits(note);
-	return NDFLT; // not reached
-}
-
-void
-runtime·sigenable(uint32 sig)
-{
-	USED(sig);
-}
-
-void
-runtime·sigdisable(uint32 sig)
-{
-	USED(sig);
-}
-
-void
-runtime·resetcpuprofiler(int32 hz)
-{
-	// TODO: Enable profiling interrupts.
-	
-	g->m->profilehz = hz;
-}
diff --git a/src/runtime/os_solaris.c b/src/runtime/os_solaris.c
deleted file mode 100644
index e16b8e6..0000000
--- a/src/runtime/os_solaris.c
+++ /dev/null
@@ -1,557 +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.
-
-#include "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "signal_unix.h"
-#include "stack.h"
-#include "textflag.h"
-
-#pragma dynexport runtime·end _end
-#pragma dynexport runtime·etext _etext
-#pragma dynexport runtime·edata _edata
-
-#pragma dynimport libc·___errno ___errno "libc.so"
-#pragma dynimport libc·clock_gettime clock_gettime "libc.so"
-#pragma dynimport libc·close close "libc.so"
-#pragma dynimport libc·exit exit "libc.so"
-#pragma dynimport libc·fstat fstat "libc.so"
-#pragma dynimport libc·getcontext getcontext "libc.so"
-#pragma dynimport libc·getrlimit getrlimit "libc.so"
-#pragma dynimport libc·malloc malloc "libc.so"
-#pragma dynimport libc·mmap mmap "libc.so"
-#pragma dynimport libc·munmap munmap "libc.so"
-#pragma dynimport libc·open open "libc.so"
-#pragma dynimport libc·pthread_attr_destroy pthread_attr_destroy "libc.so"
-#pragma dynimport libc·pthread_attr_getstack pthread_attr_getstack "libc.so"
-#pragma dynimport libc·pthread_attr_init pthread_attr_init "libc.so"
-#pragma dynimport libc·pthread_attr_setdetachstate pthread_attr_setdetachstate "libc.so"
-#pragma dynimport libc·pthread_attr_setstack pthread_attr_setstack "libc.so"
-#pragma dynimport libc·pthread_create pthread_create "libc.so"
-#pragma dynimport libc·raise raise "libc.so"
-#pragma dynimport libc·read read "libc.so"
-#pragma dynimport libc·select select "libc.so"
-#pragma dynimport libc·sched_yield sched_yield "libc.so"
-#pragma dynimport libc·sem_init sem_init "libc.so"
-#pragma dynimport libc·sem_post sem_post "libc.so"
-#pragma dynimport libc·sem_reltimedwait_np sem_reltimedwait_np "libc.so"
-#pragma dynimport libc·sem_wait sem_wait "libc.so"
-#pragma dynimport libc·setitimer setitimer "libc.so"
-#pragma dynimport libc·sigaction sigaction "libc.so"
-#pragma dynimport libc·sigaltstack sigaltstack "libc.so"
-#pragma dynimport libc·sigprocmask sigprocmask "libc.so"
-#pragma dynimport libc·sysconf sysconf "libc.so"
-#pragma dynimport libc·usleep usleep "libc.so"
-#pragma dynimport libc·write write "libc.so"
-
-extern uintptr libc·___errno;
-extern uintptr libc·clock_gettime;
-extern uintptr libc·close;
-extern uintptr libc·exit;
-extern uintptr libc·fstat;
-extern uintptr libc·getcontext;
-extern uintptr libc·getrlimit;
-extern uintptr libc·malloc;
-extern uintptr libc·mmap;
-extern uintptr libc·munmap;
-extern uintptr libc·open;
-extern uintptr libc·pthread_attr_destroy;
-extern uintptr libc·pthread_attr_getstack;
-extern uintptr libc·pthread_attr_init;
-extern uintptr libc·pthread_attr_setdetachstate;
-extern uintptr libc·pthread_attr_setstack;
-extern uintptr libc·pthread_create;
-extern uintptr libc·raise;
-extern uintptr libc·read;
-extern uintptr libc·sched_yield;
-extern uintptr libc·select;
-extern uintptr libc·sem_init;
-extern uintptr libc·sem_post;
-extern uintptr libc·sem_reltimedwait_np;
-extern uintptr libc·sem_wait;
-extern uintptr libc·setitimer;
-extern uintptr libc·sigaction;
-extern uintptr libc·sigaltstack;
-extern uintptr libc·sigprocmask;
-extern uintptr libc·sysconf;
-extern uintptr libc·usleep;
-extern uintptr libc·write;
-
-void	runtime·getcontext(Ucontext *context);
-int32	runtime·pthread_attr_destroy(PthreadAttr* attr);
-int32	runtime·pthread_attr_init(PthreadAttr* attr);
-int32	runtime·pthread_attr_getstack(PthreadAttr* attr, void** addr, uint64* size);
-int32	runtime·pthread_attr_setdetachstate(PthreadAttr* attr, int32 state);
-int32	runtime·pthread_attr_setstack(PthreadAttr* attr, void* addr, uint64 size);
-int32	runtime·pthread_create(Pthread* thread, PthreadAttr* attr, void(*fn)(void), void *arg);
-uint32	runtime·tstart_sysvicall(M *newm);
-int32	runtime·sem_init(SemT* sem, int32 pshared, uint32 value);
-int32	runtime·sem_post(SemT* sem);
-int32	runtime·sem_reltimedwait_np(SemT* sem, Timespec* timeout);
-int32	runtime·sem_wait(SemT* sem);
-int64	runtime·sysconf(int32 name);
-
-extern SigTab runtime·sigtab[];
-static Sigset sigset_none;
-static Sigset sigset_all = { ~(uint32)0, ~(uint32)0, ~(uint32)0, ~(uint32)0, };
-
-static int32
-getncpu(void) 
-{
-	int32 n;
-	
-	n = (int32)runtime·sysconf(_SC_NPROCESSORS_ONLN);
-	if(n < 1)
-		return 1;
-	return n;
-}
-
-void
-runtime·osinit(void)
-{
-	runtime·ncpu = getncpu(); 
-}
-
-void
-runtime·newosproc(M *mp, void *stk)
-{
-	PthreadAttr attr;
-	Sigset oset;
-	Pthread tid;
-	int32 ret;
-	uint64 size;
-
-	USED(stk);
-	if(runtime·pthread_attr_init(&attr) != 0)
-		runtime·throw("pthread_attr_init");
-	if(runtime·pthread_attr_setstack(&attr, 0, 0x200000) != 0)
-		runtime·throw("pthread_attr_setstack");
-	size = 0;
-	if(runtime·pthread_attr_getstack(&attr, (void**)&mp->g0->stack.hi, &size) != 0)
-		runtime·throw("pthread_attr_getstack");	
-	mp->g0->stack.lo = mp->g0->stack.hi - size;
-	if(runtime·pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0)
-		runtime·throw("pthread_attr_setdetachstate");
-
-	// Disable signals during create, so that the new thread starts
-	// with signals disabled.  It will enable them in minit.
-	runtime·sigprocmask(SIG_SETMASK, &sigset_all, &oset);
-	ret = runtime·pthread_create(&tid, &attr, (void (*)(void))runtime·tstart_sysvicall, mp);
-	runtime·sigprocmask(SIG_SETMASK, &oset, nil);
-	if(ret != 0) {
-		runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), ret);
-		runtime·throw("runtime.newosproc");
-	}
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·get_random_data(byte **rnd, int32 *rnd_len)
-{
-	#pragma dataflag NOPTR
-	static byte urandom_data[HashRandomBytes];
-	int32 fd;
-	fd = runtime·open("/dev/urandom", 0 /* O_RDONLY */, 0);
-	if(runtime·read(fd, urandom_data, HashRandomBytes) == HashRandomBytes) {
-		*rnd = urandom_data;
-		*rnd_len = HashRandomBytes;
-	} else {
-		*rnd = nil;
-		*rnd_len = 0;
-	}
-	runtime·close(fd);
-}
-
-void
-runtime·goenvs(void)
-{
-	runtime·goenvs_unix();
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
-void
-runtime·mpreinit(M *mp)
-{
-	mp->gsignal = runtime·malg(32*1024);
-	mp->gsignal->m = mp;
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the new thread, can not allocate memory.
-void
-runtime·minit(void)
-{
-	runtime·asmcgocall(runtime·miniterrno, (void *)libc·___errno);
-	// Initialize signal handling
-	runtime·signalstack((byte*)g->m->gsignal->stack.lo, 32*1024);
-	runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil);
-}
-
-// Called from dropm to undo the effect of an minit.
-void
-runtime·unminit(void)
-{
-	runtime·signalstack(nil, 0);
-}
-
-uintptr
-runtime·memlimit(void)
-{
-	Rlimit rl;
-	extern byte runtime·text[], runtime·end[];
-	uintptr used;
-	
-	if(runtime·getrlimit(RLIMIT_AS, &rl) != 0)
-		return 0;
-	if(rl.rlim_cur >= 0x7fffffff)
-		return 0;
-
-	// Estimate our VM footprint excluding the heap.
-	// Not an exact science: use size of binary plus
-	// some room for thread stacks.
-	used = runtime·end - runtime·text + (64<<20);
-	if(used >= rl.rlim_cur)
-		return 0;
-
-	// If there's not at least 16 MB left, we're probably
-	// not going to be able to do much.  Treat as no limit.
-	rl.rlim_cur -= used;
-	if(rl.rlim_cur < (16<<20))
-		return 0;
-
-	return rl.rlim_cur - used;
-}
-
-void
-runtime·setprof(bool on)
-{
-	USED(on);
-}
-
-extern void runtime·sigtramp(void);
-
-void
-runtime·setsig(int32 i, GoSighandler *fn, bool restart)
-{
-	SigactionT sa;
-
-	runtime·memclr((byte*)&sa, sizeof sa);
-	sa.sa_flags = SA_SIGINFO|SA_ONSTACK;
-	if(restart)
-		sa.sa_flags |= SA_RESTART;
-	sa.sa_mask.__sigbits[0] = ~(uint32)0;
-	sa.sa_mask.__sigbits[1] = ~(uint32)0;
-	sa.sa_mask.__sigbits[2] = ~(uint32)0;
-	sa.sa_mask.__sigbits[3] = ~(uint32)0;
-	if(fn == runtime·sighandler)
-		fn = (void*)runtime·sigtramp;
-	*((void**)&sa._funcptr[0]) = (void*)fn;
-	runtime·sigaction(i, &sa, nil);
-}
-
-GoSighandler*
-runtime·getsig(int32 i)
-{
-	SigactionT sa;
-
-	runtime·memclr((byte*)&sa, sizeof sa);
-	runtime·sigaction(i, nil, &sa);
-	if(*((void**)&sa._funcptr[0]) == runtime·sigtramp)
-		return runtime·sighandler;
-	return *((void**)&sa._funcptr[0]);
-}
-
-void
-runtime·signalstack(byte *p, int32 n)
-{
-	StackT st;
-
-	st.ss_sp = (void*)p;
-	st.ss_size = n;
-	st.ss_flags = 0;
-	if(p == nil)
-		st.ss_flags = SS_DISABLE;
-	runtime·sigaltstack(&st, nil);
-}
-
-void
-runtime·unblocksignals(void)
-{
-	runtime·sigprocmask(SIG_SETMASK, &sigset_none, nil);
-}
-
-#pragma textflag NOSPLIT
-uintptr
-runtime·semacreate(void)
-{
-	SemT* sem;
-
-	// Call libc's malloc rather than runtime·malloc.  This will
-	// allocate space on the C heap.  We can't call runtime·malloc
-	// here because it could cause a deadlock.
-	g->m->libcall.fn = (uintptr)(void*)libc·malloc;
-	g->m->libcall.n = 1;
-	runtime·memclr((byte*)&g->m->scratch, sizeof(g->m->scratch));
-	g->m->scratch.v[0] = (uintptr)sizeof(*sem);
-	g->m->libcall.args = (uintptr)(uintptr*)&g->m->scratch;
-	runtime·asmcgocall(runtime·asmsysvicall6, &g->m->libcall);
-	sem = (void*)g->m->libcall.r1;
-	if(runtime·sem_init(sem, 0, 0) != 0)
-		runtime·throw("sem_init");
-	return (uintptr)sem;
-}
-
-#pragma textflag NOSPLIT
-int32
-runtime·semasleep(int64 ns)
-{
-	M *m;
-
-	m = g->m;
-	if(ns >= 0) {
-		m->ts.tv_sec = ns / 1000000000LL;
-		m->ts.tv_nsec = ns % 1000000000LL;
-
-		m->libcall.fn = (uintptr)(void*)libc·sem_reltimedwait_np;
-		m->libcall.n = 2;
-		runtime·memclr((byte*)&m->scratch, sizeof(m->scratch));
-		m->scratch.v[0] = m->waitsema;
-		m->scratch.v[1] = (uintptr)&m->ts;
-		m->libcall.args = (uintptr)(uintptr*)&m->scratch;
-		runtime·asmcgocall(runtime·asmsysvicall6, &m->libcall);
-		if(*m->perrno != 0) {
-			if(*m->perrno == ETIMEDOUT || *m->perrno == EAGAIN || *m->perrno == EINTR)
-				return -1;
-			runtime·throw("sem_reltimedwait_np");
-		}
-		return 0;
-	}
-	for(;;) {
-		m->libcall.fn = (uintptr)(void*)libc·sem_wait;
-		m->libcall.n = 1;
-		runtime·memclr((byte*)&m->scratch, sizeof(m->scratch));
-		m->scratch.v[0] = m->waitsema;
-		m->libcall.args = (uintptr)(uintptr*)&m->scratch;
-		runtime·asmcgocall(runtime·asmsysvicall6, &m->libcall);
-		if(m->libcall.r1 == 0)
-			break;
-		if(*m->perrno == EINTR) 
-			continue;
-		runtime·throw("sem_wait");
-	}
-	return 0;
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·semawakeup(M *mp)
-{
-	SemT* sem = (SemT*)mp->waitsema;
-	if(runtime·sem_post(sem) != 0)
-		runtime·throw("sem_post");
-}
-
-#pragma textflag NOSPLIT
-int32
-runtime·close(int32 fd)
-{
-	return runtime·sysvicall1(libc·close, (uintptr)fd);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·exit(int32 r)
-{
-	runtime·sysvicall1(libc·exit, (uintptr)r);
-}
-
-#pragma textflag NOSPLIT
-/* int32 */ void
-runtime·getcontext(Ucontext* context)
-{
-	runtime·sysvicall1(libc·getcontext, (uintptr)context);
-}
-
-#pragma textflag NOSPLIT
-int32
-runtime·getrlimit(int32 res, Rlimit* rlp)
-{
-	return runtime·sysvicall2(libc·getrlimit, (uintptr)res, (uintptr)rlp);
-}
-
-#pragma textflag NOSPLIT
-uint8*
-runtime·mmap(byte* addr, uintptr len, int32 prot, int32 flags, int32 fildes, uint32 off)
-{
-	return (uint8*)runtime·sysvicall6(libc·mmap, (uintptr)addr, (uintptr)len, (uintptr)prot, (uintptr)flags, (uintptr)fildes, (uintptr)off);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·munmap(byte* addr, uintptr len)
-{
-	runtime·sysvicall2(libc·munmap, (uintptr)addr, (uintptr)len);
-}
-
-extern int64 runtime·nanotime1(void);
-#pragma textflag NOSPLIT
-int64
-runtime·nanotime(void)
-{
-	return runtime·sysvicall0((uintptr)runtime·nanotime1);
-}
-
-#pragma textflag NOSPLIT
-int32
-runtime·open(int8* path, int32 oflag, int32 mode)
-{
-	return runtime·sysvicall3(libc·open, (uintptr)path, (uintptr)oflag, (uintptr)mode);
-}
-
-int32
-runtime·pthread_attr_destroy(PthreadAttr* attr)
-{
-	return runtime·sysvicall1(libc·pthread_attr_destroy, (uintptr)attr);
-}
-
-int32
-runtime·pthread_attr_getstack(PthreadAttr* attr, void** addr, uint64* size)
-{
-	return runtime·sysvicall3(libc·pthread_attr_getstack, (uintptr)attr, (uintptr)addr, (uintptr)size);
-}
-
-int32
-runtime·pthread_attr_init(PthreadAttr* attr)
-{
-	return runtime·sysvicall1(libc·pthread_attr_init, (uintptr)attr);
-}
-
-int32
-runtime·pthread_attr_setdetachstate(PthreadAttr* attr, int32 state)
-{
-	return runtime·sysvicall2(libc·pthread_attr_setdetachstate, (uintptr)attr, (uintptr)state);
-}
-
-int32
-runtime·pthread_attr_setstack(PthreadAttr* attr, void* addr, uint64 size)
-{
-	return runtime·sysvicall3(libc·pthread_attr_setstack, (uintptr)attr, (uintptr)addr, (uintptr)size);
-}
-
-int32
-runtime·pthread_create(Pthread* thread, PthreadAttr* attr, void(*fn)(void), void *arg)
-{
-	return runtime·sysvicall4(libc·pthread_create, (uintptr)thread, (uintptr)attr, (uintptr)fn, (uintptr)arg);
-}
-
-/* int32 */ void
-runtime·raise(int32 sig)
-{
-	runtime·sysvicall1(libc·raise, (uintptr)sig);
-}
-
-#pragma textflag NOSPLIT
-int32
-runtime·read(int32 fd, void* buf, int32 nbyte)
-{
-	return runtime·sysvicall3(libc·read, (uintptr)fd, (uintptr)buf, (uintptr)nbyte);
-}
-
-#pragma textflag NOSPLIT
-int32
-runtime·sem_init(SemT* sem, int32 pshared, uint32 value)
-{
-	return runtime·sysvicall3(libc·sem_init, (uintptr)sem, (uintptr)pshared, (uintptr)value);
-}
-
-#pragma textflag NOSPLIT
-int32
-runtime·sem_post(SemT* sem)
-{
-	return runtime·sysvicall1(libc·sem_post, (uintptr)sem);
-}
-
-#pragma textflag NOSPLIT
-int32
-runtime·sem_reltimedwait_np(SemT* sem, Timespec* timeout)
-{
-	return runtime·sysvicall2(libc·sem_reltimedwait_np, (uintptr)sem, (uintptr)timeout);
-}
-
-#pragma textflag NOSPLIT
-int32
-runtime·sem_wait(SemT* sem)
-{
-	return runtime·sysvicall1(libc·sem_wait, (uintptr)sem);
-}
-
-/* int32 */ void
-runtime·setitimer(int32 which, Itimerval* value, Itimerval* ovalue)
-{
-	runtime·sysvicall3(libc·setitimer, (uintptr)which, (uintptr)value, (uintptr)ovalue);
-}
-
-/* int32 */ void
-runtime·sigaction(int32 sig, struct SigactionT* act, struct SigactionT* oact)
-{
-	runtime·sysvicall3(libc·sigaction, (uintptr)sig, (uintptr)act, (uintptr)oact);
-}
-
-/* int32 */ void
-runtime·sigaltstack(SigaltstackT* ss, SigaltstackT* oss)
-{
-	runtime·sysvicall2(libc·sigaltstack, (uintptr)ss, (uintptr)oss);
-}
-
-/* int32 */ void
-runtime·sigprocmask(int32 how, Sigset* set, Sigset* oset)
-{
-	runtime·sysvicall3(libc·sigprocmask, (uintptr)how, (uintptr)set, (uintptr)oset);
-}
-
-int64
-runtime·sysconf(int32 name)
-{
-	return runtime·sysvicall1(libc·sysconf, (uintptr)name);
-}
-
-extern void runtime·usleep1(uint32);
-
-#pragma textflag NOSPLIT
-void
-runtime·usleep(uint32 µs)
-{
-	runtime·usleep1(µs);
-}
-
-#pragma textflag NOSPLIT
-int32
-runtime·write(uintptr fd, void* buf, int32 nbyte)
-{
-	return runtime·sysvicall3(libc·write, (uintptr)fd, (uintptr)buf, (uintptr)nbyte);
-}
-
-extern void runtime·osyield1(void);
-
-#pragma textflag NOSPLIT
-void
-runtime·osyield(void)
-{
-	// Check the validity of m because we might be called in cgo callback
-	// path early enough where there isn't a m available yet.
-	if(g && g->m != nil) {
-		runtime·sysvicall0(libc·sched_yield);
-		return;
-	}
-	runtime·osyield1();
-}
-
-#pragma textflag NOSPLIT
-int8*
-runtime·signame(int32 sig)
-{
-	return runtime·sigtab[sig].name;
-}
diff --git a/src/runtime/os_solaris.go b/src/runtime/os_solaris.go
index ca13151..fd20a5c 100644
--- a/src/runtime/os_solaris.go
+++ b/src/runtime/os_solaris.go
@@ -6,35 +6,19 @@ package runtime
 
 import "unsafe"
 
-func setitimer(mode int32, new, old unsafe.Pointer)
-func sigaction(sig int32, new, old unsafe.Pointer)
-func sigaltstack(new, old unsafe.Pointer)
-func sigprocmask(mode int32, new, old unsafe.Pointer)
-func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32
-func getrlimit(kind int32, limit unsafe.Pointer)
-func miniterrno(fn unsafe.Pointer)
-func raise(sig int32)
-func getcontext(ctxt unsafe.Pointer)
-func tstart_sysvicall(mm unsafe.Pointer) uint32
-func nanotime1() int64
-func usleep1(usec uint32)
-func osyield1()
-func netpollinit()
-func netpollopen(fd uintptr, pd *pollDesc) int32
-func netpollclose(fd uintptr) int32
-func netpollarm(pd *pollDesc, mode int)
-
-type libcFunc byte
+type libcFunc uintptr
 
 var asmsysvicall6 libcFunc
 
+//go:noescape
+func sigfwd(fn uintptr, sig uint32, info *siginfo, ctx unsafe.Pointer)
+
 //go:nosplit
 func sysvicall0(fn *libcFunc) uintptr {
 	libcall := &getg().m.libcall
 	libcall.fn = uintptr(unsafe.Pointer(fn))
 	libcall.n = 0
-	// TODO(rsc): Why is noescape necessary here and below?
-	libcall.args = uintptr(noescape(unsafe.Pointer(&fn))) // it's unused but must be non-nil, otherwise crashes
+	libcall.args = uintptr(unsafe.Pointer(fn)) // it's unused but must be non-nil, otherwise crashes
 	asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(libcall))
 	return libcall.r1
 }
@@ -44,6 +28,7 @@ func sysvicall1(fn *libcFunc, a1 uintptr) uintptr {
 	libcall := &getg().m.libcall
 	libcall.fn = uintptr(unsafe.Pointer(fn))
 	libcall.n = 1
+	// TODO(rsc): Why is noescape necessary here and below?
 	libcall.args = uintptr(noescape(unsafe.Pointer(&a1)))
 	asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(libcall))
 	return libcall.r1
diff --git a/src/runtime/os_solaris.h b/src/runtime/os_solaris.h
deleted file mode 100644
index 3d9e1a2..0000000
--- a/src/runtime/os_solaris.h
+++ /dev/null
@@ -1,55 +0,0 @@
-// 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.
-
-
-typedef uintptr kevent_udata;
-
-struct sigaction;
-
-void	runtime·sigpanic(void);
-
-void	runtime·setitimer(int32, Itimerval*, Itimerval*);
-void	runtime·sigaction(int32, struct SigactionT*, struct SigactionT*);
-void	runtime·sigaltstack(SigaltstackT*, SigaltstackT*);
-void	runtime·sigprocmask(int32, Sigset*, Sigset*);
-void	runtime·unblocksignals(void);
-int32	runtime·sysctl(uint32*, uint32, byte*, uintptr*, byte*, uintptr);
-
-
-void	runtime·raisesigpipe(void);
-void	runtime·setsig(int32, void(*)(int32, Siginfo*, void*, G*), bool);
-void	runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp);
-void	runtime·sigpanic(void);
-
-enum {
-	SS_DISABLE = 2,
-	SIG_BLOCK = 1,
-	SIG_UNBLOCK = 2,
-	SIG_SETMASK = 3,
-	NSIG = 73, /* number of signals in runtime·SigTab array */
-	SI_USER = 0,
-	_UC_SIGMASK = 0x01,
-	_UC_CPU = 0x04,
-	RLIMIT_AS = 10,
-};
-
-typedef struct Rlimit Rlimit;
-struct Rlimit {
-	int64   rlim_cur;
-	int64   rlim_max;
-};
-int32   runtime·getrlimit(int32, Rlimit*);
-
-// Call an external library function described by {fn, a0, ..., an}, with
-// SysV conventions, switching to os stack during the call, if necessary.
-uintptr	runtime·sysvicall0(uintptr fn);
-uintptr	runtime·sysvicall1(uintptr fn, uintptr a1);
-uintptr	runtime·sysvicall2(uintptr fn, uintptr a1, uintptr a2);
-uintptr	runtime·sysvicall3(uintptr fn, uintptr a1, uintptr a2, uintptr a3);
-uintptr	runtime·sysvicall4(uintptr fn, uintptr a1, uintptr a2, uintptr a3, uintptr a4);
-uintptr	runtime·sysvicall5(uintptr fn, uintptr a1, uintptr a2, uintptr a3, uintptr a4, uintptr a5);
-uintptr	runtime·sysvicall6(uintptr fn, uintptr a1, uintptr a2, uintptr a3, uintptr a4, uintptr a5, uintptr a6);
-void	runtime·asmsysvicall6(void *c);
-
-void	runtime·miniterrno(void *fn);
diff --git a/src/runtime/os_windows.c b/src/runtime/os_windows.c
deleted file mode 100644
index b8b8eda..0000000
--- a/src/runtime/os_windows.c
+++ /dev/null
@@ -1,636 +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 "runtime.h"
-#include "type.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "textflag.h"
-#include "arch_GOARCH.h"
-#include "malloc.h"
-
-#pragma dynimport runtime·AddVectoredExceptionHandler AddVectoredExceptionHandler "kernel32.dll"
-#pragma dynimport runtime·CloseHandle CloseHandle "kernel32.dll"
-#pragma dynimport runtime·CreateEvent CreateEventA "kernel32.dll"
-#pragma dynimport runtime·CreateThread CreateThread "kernel32.dll"
-#pragma dynimport runtime·CreateWaitableTimer CreateWaitableTimerA "kernel32.dll"
-#pragma dynimport runtime·CryptAcquireContextW CryptAcquireContextW "advapi32.dll"
-#pragma dynimport runtime·CryptGenRandom CryptGenRandom "advapi32.dll"
-#pragma dynimport runtime·CryptReleaseContext CryptReleaseContext "advapi32.dll"
-#pragma dynimport runtime·DuplicateHandle DuplicateHandle "kernel32.dll"
-#pragma dynimport runtime·ExitProcess ExitProcess "kernel32.dll"
-#pragma dynimport runtime·FreeEnvironmentStringsW FreeEnvironmentStringsW "kernel32.dll"
-#pragma dynimport runtime·GetEnvironmentStringsW GetEnvironmentStringsW "kernel32.dll"
-#pragma dynimport runtime·GetProcAddress GetProcAddress "kernel32.dll"
-#pragma dynimport runtime·GetStdHandle GetStdHandle "kernel32.dll"
-#pragma dynimport runtime·GetSystemInfo GetSystemInfo "kernel32.dll"
-#pragma dynimport runtime·GetThreadContext GetThreadContext "kernel32.dll"
-#pragma dynimport runtime·LoadLibrary LoadLibraryW "kernel32.dll"
-#pragma dynimport runtime·LoadLibraryA LoadLibraryA "kernel32.dll"
-#pragma dynimport runtime·NtWaitForSingleObject NtWaitForSingleObject "ntdll.dll"
-#pragma dynimport runtime·ResumeThread ResumeThread "kernel32.dll"
-#pragma dynimport runtime·SetConsoleCtrlHandler SetConsoleCtrlHandler "kernel32.dll"
-#pragma dynimport runtime·SetEvent SetEvent "kernel32.dll"
-#pragma dynimport runtime·SetProcessPriorityBoost SetProcessPriorityBoost "kernel32.dll"
-#pragma dynimport runtime·SetThreadPriority SetThreadPriority "kernel32.dll"
-#pragma dynimport runtime·SetUnhandledExceptionFilter SetUnhandledExceptionFilter "kernel32.dll"
-#pragma dynimport runtime·SetWaitableTimer SetWaitableTimer "kernel32.dll"
-#pragma dynimport runtime·Sleep Sleep "kernel32.dll"
-#pragma dynimport runtime·SuspendThread SuspendThread "kernel32.dll"
-#pragma dynimport runtime·WaitForSingleObject WaitForSingleObject "kernel32.dll"
-#pragma dynimport runtime·WriteFile WriteFile "kernel32.dll"
-#pragma dynimport runtime·timeBeginPeriod timeBeginPeriod "winmm.dll"
-
-extern void *runtime·AddVectoredExceptionHandler;
-extern void *runtime·CloseHandle;
-extern void *runtime·CreateEvent;
-extern void *runtime·CreateThread;
-extern void *runtime·CreateWaitableTimer;
-extern void *runtime·CryptAcquireContextW;
-extern void *runtime·CryptGenRandom;
-extern void *runtime·CryptReleaseContext;
-extern void *runtime·DuplicateHandle;
-extern void *runtime·ExitProcess;
-extern void *runtime·FreeEnvironmentStringsW;
-extern void *runtime·GetEnvironmentStringsW;
-extern void *runtime·GetProcAddress;
-extern void *runtime·GetStdHandle;
-extern void *runtime·GetSystemInfo;
-extern void *runtime·GetThreadContext;
-extern void *runtime·LoadLibrary;
-extern void *runtime·LoadLibraryA;
-extern void *runtime·NtWaitForSingleObject;
-extern void *runtime·ResumeThread;
-extern void *runtime·SetConsoleCtrlHandler;
-extern void *runtime·SetEvent;
-extern void *runtime·SetProcessPriorityBoost;
-extern void *runtime·SetThreadPriority;
-extern void *runtime·SetUnhandledExceptionFilter;
-extern void *runtime·SetWaitableTimer;
-extern void *runtime·Sleep;
-extern void *runtime·SuspendThread;
-extern void *runtime·WaitForSingleObject;
-extern void *runtime·WriteFile;
-extern void *runtime·timeBeginPeriod;
-
-#pragma dataflag NOPTR
-void *runtime·GetQueuedCompletionStatusEx;
-
-extern uintptr runtime·externalthreadhandlerp;
-void runtime·externalthreadhandler(void);
-void runtime·exceptiontramp(void);
-void runtime·firstcontinuetramp(void);
-void runtime·lastcontinuetramp(void);
-
-#pragma textflag NOSPLIT
-uintptr
-runtime·getLoadLibrary(void)
-{
-	return (uintptr)runtime·LoadLibrary;
-}
-
-#pragma textflag NOSPLIT
-uintptr
-runtime·getGetProcAddress(void)
-{
-	return (uintptr)runtime·GetProcAddress;
-}
-
-static int32
-getproccount(void)
-{
-	SystemInfo info;
-
-	runtime·stdcall1(runtime·GetSystemInfo, (uintptr)&info);
-	return info.dwNumberOfProcessors;
-}
-
-void
-runtime·osinit(void)
-{
-	void *kernel32;
-	void *addVectoredContinueHandler;
-
-	kernel32 = runtime·stdcall1(runtime·LoadLibraryA, (uintptr)"kernel32.dll");
-
-	runtime·externalthreadhandlerp = (uintptr)runtime·externalthreadhandler;
-
-	runtime·stdcall2(runtime·AddVectoredExceptionHandler, 1, (uintptr)runtime·exceptiontramp);
-	addVectoredContinueHandler = nil;
-	if(kernel32 != nil)
-		addVectoredContinueHandler = runtime·stdcall2(runtime·GetProcAddress, (uintptr)kernel32, (uintptr)"AddVectoredContinueHandler");
-	if(addVectoredContinueHandler == nil || sizeof(void*) == 4) {
-		// use SetUnhandledExceptionFilter for windows-386 or
-		// if VectoredContinueHandler is unavailable.
-		// note: SetUnhandledExceptionFilter handler won't be called, if debugging.
-		runtime·stdcall1(runtime·SetUnhandledExceptionFilter, (uintptr)runtime·lastcontinuetramp);
-	} else {
-		runtime·stdcall2(addVectoredContinueHandler, 1, (uintptr)runtime·firstcontinuetramp);
-		runtime·stdcall2(addVectoredContinueHandler, 0, (uintptr)runtime·lastcontinuetramp);
-	}
-
-	runtime·stdcall2(runtime·SetConsoleCtrlHandler, (uintptr)runtime·ctrlhandler, 1);
-
-	runtime·stdcall1(runtime·timeBeginPeriod, 1);
-
-	runtime·ncpu = getproccount();
-	
-	// Windows dynamic priority boosting assumes that a process has different types
-	// of dedicated threads -- GUI, IO, computational, etc. Go processes use
-	// equivalent threads that all do a mix of GUI, IO, computations, etc.
-	// In such context dynamic priority boosting does nothing but harm, so we turn it off.
-	runtime·stdcall2(runtime·SetProcessPriorityBoost, -1, 1);
-
-	if(kernel32 != nil) {
-		runtime·GetQueuedCompletionStatusEx = runtime·stdcall2(runtime·GetProcAddress, (uintptr)kernel32, (uintptr)"GetQueuedCompletionStatusEx");
-	}
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·get_random_data(byte **rnd, int32 *rnd_len)
-{
-	uintptr handle;
-	*rnd = nil;
-	*rnd_len = 0;
-	if(runtime·stdcall5(runtime·CryptAcquireContextW, (uintptr)&handle, (uintptr)nil, (uintptr)nil,
-			   1 /* PROV_RSA_FULL */,
-			   0xf0000000U /* CRYPT_VERIFYCONTEXT */) != 0) {
-		static byte random_data[HashRandomBytes];
-		if(runtime·stdcall3(runtime·CryptGenRandom, handle, HashRandomBytes, (uintptr)&random_data[0])) {
-			*rnd = random_data;
-			*rnd_len = HashRandomBytes;
-		}
-		runtime·stdcall2(runtime·CryptReleaseContext, handle, 0);
-	}
-}
-
-void
-runtime·goenvs(void)
-{
-	extern Slice runtime·envs;
-
-	uint16 *env;
-	String *s;
-	int32 i, n;
-	uint16 *p;
-
-	env = runtime·stdcall0(runtime·GetEnvironmentStringsW);
-
-	n = 0;
-	for(p=env; *p; n++)
-		p += runtime·findnullw(p)+1;
-
-	runtime·envs = runtime·makeStringSlice(n);
-	s = (String*)runtime·envs.array;
-
-	p = env;
-	for(i=0; i<n; i++) {
-		s[i] = runtime·gostringw(p);
-		p += runtime·findnullw(p)+1;
-	}
-
-	runtime·stdcall1(runtime·FreeEnvironmentStringsW, (uintptr)env);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·exit(int32 code)
-{
-	runtime·stdcall1(runtime·ExitProcess, code);
-}
-
-#pragma textflag NOSPLIT
-int32
-runtime·write(uintptr fd, void *buf, int32 n)
-{
-	void *handle;
-	uint32 written;
-
-	written = 0;
-	switch(fd) {
-	case 1:
-		handle = runtime·stdcall1(runtime·GetStdHandle, -11);
-		break;
-	case 2:
-		handle = runtime·stdcall1(runtime·GetStdHandle, -12);
-		break;
-	default:
-		// assume fd is real windows handle.
-		handle = (void*)fd;
-		break;
-	}
-	runtime·stdcall5(runtime·WriteFile, (uintptr)handle, (uintptr)buf, n, (uintptr)&written, 0);
-	return written;
-}
-
-#define INFINITE ((uintptr)0xFFFFFFFF)
-
-#pragma textflag NOSPLIT
-int32
-runtime·semasleep(int64 ns)
-{
-	// store ms in ns to save stack space
-	if(ns < 0)
-		ns = INFINITE;
-	else {
-		ns = runtime·timediv(ns, 1000000, nil);
-		if(ns == 0)
-			ns = 1;
-	}
-	if(runtime·stdcall2(runtime·WaitForSingleObject, (uintptr)g->m->waitsema, ns) != 0)
-		return -1;  // timeout
-	return 0;
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·semawakeup(M *mp)
-{
-	runtime·stdcall1(runtime·SetEvent, mp->waitsema);
-}
-
-#pragma textflag NOSPLIT
-uintptr
-runtime·semacreate(void)
-{
-	return (uintptr)runtime·stdcall4(runtime·CreateEvent, 0, 0, 0, 0);
-}
-
-#define STACK_SIZE_PARAM_IS_A_RESERVATION ((uintptr)0x00010000)
-
-void
-runtime·newosproc(M *mp, void *stk)
-{
-	void *thandle;
-
-	USED(stk);
-
-	thandle = runtime·stdcall6(runtime·CreateThread,
-		(uintptr)nil, 0x20000, (uintptr)runtime·tstart_stdcall, (uintptr)mp,
-		STACK_SIZE_PARAM_IS_A_RESERVATION, (uintptr)nil);
-	if(thandle == nil) {
-		runtime·printf("runtime: failed to create new OS thread (have %d already; errno=%d)\n", runtime·mcount(), runtime·getlasterror());
-		runtime·throw("runtime.newosproc");
-	}
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the parent thread (main thread in case of bootstrap), can allocate memory.
-void
-runtime·mpreinit(M *mp)
-{
-	USED(mp);
-}
-
-// Called to initialize a new m (including the bootstrap m).
-// Called on the new thread, can not allocate memory.
-void
-runtime·minit(void)
-{
-	uintptr thandle;
-
-	// -1 = current process, -2 = current thread
-	runtime·stdcall7(runtime·DuplicateHandle, -1, -2, -1, (uintptr)&thandle, 0, 0, DUPLICATE_SAME_ACCESS);
-	runtime·atomicstoreuintptr(&g->m->thread, thandle);
-}
-
-// Called from dropm to undo the effect of an minit.
-void
-runtime·unminit(void)
-{
-	runtime·stdcall1(runtime·CloseHandle, g->m->thread);
-	g->m->thread = 0;
-}
-
-// Described in http://www.dcl.hpi.uni-potsdam.de/research/WRK/2007/08/getting-os-information-the-kuser_shared_data-structure/
-typedef struct KSYSTEM_TIME {
-	uint32	LowPart;
-	int32	High1Time;
-	int32	High2Time;
-} KSYSTEM_TIME;
-
-#pragma dataflag NOPTR
-const KSYSTEM_TIME* INTERRUPT_TIME	= (KSYSTEM_TIME*)0x7ffe0008;
-#pragma dataflag NOPTR
-const KSYSTEM_TIME* SYSTEM_TIME		= (KSYSTEM_TIME*)0x7ffe0014;
-
-static void badsystime(void);
-
-#pragma textflag NOSPLIT
-int64
-runtime·systime(KSYSTEM_TIME *timeaddr)
-{
-	KSYSTEM_TIME t;
-	int32 i;
-	void (*fn)(void);
-
-	for(i = 1; i < 10000; i++) {
-		// these fields must be read in that order (see URL above)
-		t.High1Time = timeaddr->High1Time;
-		t.LowPart = timeaddr->LowPart;
-		t.High2Time = timeaddr->High2Time;
-		if(t.High1Time == t.High2Time)
-			return (int64)t.High1Time<<32 | t.LowPart;
-		if((i%100) == 0)
-			runtime·osyield();
-	}
-	fn = badsystime;
-	runtime·onM(&fn);
-	return 0;
-}
-
-#pragma textflag NOSPLIT
-int64
-runtime·unixnano(void)
-{
-	return (runtime·systime(SYSTEM_TIME) - 116444736000000000LL) * 100LL;
-}
-
-static void
-badsystime(void)
-{
-	runtime·throw("interrupt/system time is changing too fast");
-}
-
-#pragma textflag NOSPLIT
-int64
-runtime·nanotime(void)
-{
-	return runtime·systime(INTERRUPT_TIME) * 100LL;
-}
-
-// Calling stdcall on os stack.
-#pragma textflag NOSPLIT
-static void*
-stdcall(void *fn)
-{
-	g->m->libcall.fn = (uintptr)fn;
-	if(g->m->profilehz != 0) {
-		// leave pc/sp for cpu profiler
-		g->m->libcallg = g;
-		g->m->libcallpc = (uintptr)runtime·getcallerpc(&fn);
-		// sp must be the last, because once async cpu profiler finds
-		// all three values to be non-zero, it will use them
-		g->m->libcallsp = (uintptr)runtime·getcallersp(&fn);
-	}
-	runtime·asmcgocall(runtime·asmstdcall, &g->m->libcall);
-	g->m->libcallsp = 0;
-	return (void*)g->m->libcall.r1;
-}
-
-#pragma textflag NOSPLIT
-void*
-runtime·stdcall0(void *fn)
-{
-	g->m->libcall.n = 0;
-	g->m->libcall.args = (uintptr)&fn;  // it's unused but must be non-nil, otherwise crashes
-	return stdcall(fn);
-}
-
-#pragma textflag NOSPLIT
-void*
-runtime·stdcall1(void *fn, uintptr a0)
-{
-	USED(a0);
-	g->m->libcall.n = 1;
-	g->m->libcall.args = (uintptr)&a0;
-	return stdcall(fn);
-}
-
-#pragma textflag NOSPLIT
-void*
-runtime·stdcall2(void *fn, uintptr a0, uintptr a1)
-{
-	USED(a0, a1);
-	g->m->libcall.n = 2;
-	g->m->libcall.args = (uintptr)&a0;
-	return stdcall(fn);
-}
-
-#pragma textflag NOSPLIT
-void*
-runtime·stdcall3(void *fn, uintptr a0, uintptr a1, uintptr a2)
-{
-	USED(a0, a1, a2);
-	g->m->libcall.n = 3;
-	g->m->libcall.args = (uintptr)&a0;
-	return stdcall(fn);
-}
-
-#pragma textflag NOSPLIT
-void*
-runtime·stdcall4(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3)
-{
-	USED(a0, a1, a2, a3);
-	g->m->libcall.n = 4;
-	g->m->libcall.args = (uintptr)&a0;
-	return stdcall(fn);
-}
-
-#pragma textflag NOSPLIT
-void*
-runtime·stdcall5(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uintptr a4)
-{
-	USED(a0, a1, a2, a3, a4);
-	g->m->libcall.n = 5;
-	g->m->libcall.args = (uintptr)&a0;
-	return stdcall(fn);
-}
-
-#pragma textflag NOSPLIT
-void*
-runtime·stdcall6(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uintptr a4, uintptr a5)
-{
-	USED(a0, a1, a2, a3, a4, a5);
-	g->m->libcall.n = 6;
-	g->m->libcall.args = (uintptr)&a0;
-	return stdcall(fn);
-}
-
-#pragma textflag NOSPLIT
-void*
-runtime·stdcall7(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uintptr a4, uintptr a5, uintptr a6)
-{
-	USED(a0, a1, a2, a3, a4, a5, a6);
-	g->m->libcall.n = 7;
-	g->m->libcall.args = (uintptr)&a0;
-	return stdcall(fn);
-}
-
-extern void runtime·usleep1(uint32);
-
-#pragma textflag NOSPLIT
-void
-runtime·osyield(void)
-{
-	runtime·usleep1(1);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·usleep(uint32 us)
-{
-	// Have 1us units; want 100ns units.
-	runtime·usleep1(10*us);
-}
-
-uint32
-runtime·issigpanic(uint32 code)
-{
-	switch(code) {
-	case EXCEPTION_ACCESS_VIOLATION:
-	case EXCEPTION_INT_DIVIDE_BY_ZERO:
-	case EXCEPTION_INT_OVERFLOW:
-	case EXCEPTION_FLT_DENORMAL_OPERAND:
-	case EXCEPTION_FLT_DIVIDE_BY_ZERO:
-	case EXCEPTION_FLT_INEXACT_RESULT:
-	case EXCEPTION_FLT_OVERFLOW:
-	case EXCEPTION_FLT_UNDERFLOW:
-	case EXCEPTION_BREAKPOINT:
-		return 1;
-	}
-	return 0;
-}
-
-void
-runtime·initsig(void)
-{
-	// following line keeps these functions alive at link stage
-	// if there's a better way please write it here
-	void *e = runtime·exceptiontramp;
-	void *f = runtime·firstcontinuetramp;
-	void *l = runtime·lastcontinuetramp;
-	USED(e);
-	USED(f);
-	USED(l);
-}
-
-uint32
-runtime·ctrlhandler1(uint32 type)
-{
-	int32 s;
-
-	switch(type) {
-	case CTRL_C_EVENT:
-	case CTRL_BREAK_EVENT:
-		s = SIGINT;
-		break;
-	default:
-		return 0;
-	}
-
-	if(runtime·sigsend(s))
-		return 1;
-	runtime·exit(2);	// SIGINT, SIGTERM, etc
-	return 0;
-}
-
-extern void runtime·dosigprof(Context *r, G *gp, M *mp);
-extern void runtime·profileloop(void);
-#pragma dataflag NOPTR
-static void *profiletimer;
-
-static void
-profilem(M *mp)
-{
-	extern M runtime·m0;
-	extern uint32 runtime·tls0[];
-	byte rbuf[sizeof(Context)+15];
-	Context *r;
-	void *tls;
-	G *gp;
-
-	tls = mp->tls;
-	if(mp == &runtime·m0)
-		tls = runtime·tls0;
-	gp = *(G**)tls;
-
-	// align Context to 16 bytes
-	r = (Context*)((uintptr)(&rbuf[15]) & ~15);
-	r->ContextFlags = CONTEXT_CONTROL;
-	runtime·stdcall2(runtime·GetThreadContext, (uintptr)mp->thread, (uintptr)r);
-	runtime·dosigprof(r, gp, mp);
-}
-
-void
-runtime·profileloop1(void)
-{
-	M *mp, *allm;
-	uintptr thread;
-
-	runtime·stdcall2(runtime·SetThreadPriority, -2, THREAD_PRIORITY_HIGHEST);
-
-	for(;;) {
-		runtime·stdcall2(runtime·WaitForSingleObject, (uintptr)profiletimer, -1);
-		allm = runtime·atomicloadp(&runtime·allm);
-		for(mp = allm; mp != nil; mp = mp->alllink) {
-			thread = runtime·atomicloaduintptr(&mp->thread);
-			// Do not profile threads blocked on Notes,
-			// this includes idle worker threads,
-			// idle timer thread, idle heap scavenger, etc.
-			if(thread == 0 || mp->profilehz == 0 || mp->blocked)
-				continue;
-			runtime·stdcall1(runtime·SuspendThread, (uintptr)thread);
-			if(mp->profilehz != 0 && !mp->blocked)
-				profilem(mp);
-			runtime·stdcall1(runtime·ResumeThread, (uintptr)thread);
-		}
-	}
-}
-
-void
-runtime·resetcpuprofiler(int32 hz)
-{
-	static Mutex lock;
-	void *timer, *thread;
-	int32 ms;
-	int64 due;
-
-	runtime·lock(&lock);
-	if(profiletimer == nil) {
-		timer = runtime·stdcall3(runtime·CreateWaitableTimer, (uintptr)nil, (uintptr)nil, (uintptr)nil);
-		runtime·atomicstorep(&profiletimer, timer);
-		thread = runtime·stdcall6(runtime·CreateThread,
-			(uintptr)nil, (uintptr)nil, (uintptr)runtime·profileloop, (uintptr)nil, (uintptr)nil, (uintptr)nil);
-		runtime·stdcall2(runtime·SetThreadPriority, (uintptr)thread, THREAD_PRIORITY_HIGHEST);
-		runtime·stdcall1(runtime·CloseHandle, (uintptr)thread);
-	}
-	runtime·unlock(&lock);
-
-	ms = 0;
-	due = 1LL<<63;
-	if(hz > 0) {
-		ms = 1000 / hz;
-		if(ms == 0)
-			ms = 1;
-		due = ms * -10000;
-	}
-	runtime·stdcall6(runtime·SetWaitableTimer,
-		(uintptr)profiletimer, (uintptr)&due, ms, (uintptr)nil, (uintptr)nil, (uintptr)nil);
-	runtime·atomicstore((uint32*)&g->m->profilehz, hz);
-}
-
-uintptr
-runtime·memlimit(void)
-{
-	return 0;
-}
-
-#pragma dataflag NOPTR
-int8 runtime·badsignalmsg[] = "runtime: signal received on thread not created by Go.\n";
-int32 runtime·badsignallen = sizeof runtime·badsignalmsg - 1;
-
-void
-runtime·crash(void)
-{
-	// TODO: This routine should do whatever is needed
-	// to make the Windows program abort/crash as it
-	// would if Go was not intercepting signals.
-	// On Unix the routine would remove the custom signal
-	// handler and then raise a signal (like SIGABRT).
-	// Something like that should happen here.
-	// It's okay to leave this empty for now: if crash returns
-	// the ordinary exit-after-panic happens.
-}
diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go
index 1528d2f..545b416 100644
--- a/src/runtime/os_windows.go
+++ b/src/runtime/os_windows.go
@@ -8,51 +8,21 @@ import "unsafe"
 
 type stdFunction *byte
 
-func stdcall0(fn stdFunction) uintptr
-func stdcall1(fn stdFunction, a0 uintptr) uintptr
-func stdcall2(fn stdFunction, a0, a1 uintptr) uintptr
-func stdcall3(fn stdFunction, a0, a1, a2 uintptr) uintptr
-func stdcall4(fn stdFunction, a0, a1, a2, a3 uintptr) uintptr
-func stdcall5(fn stdFunction, a0, a1, a2, a3, a4 uintptr) uintptr
-func stdcall6(fn stdFunction, a0, a1, a2, a3, a4, a5 uintptr) uintptr
-func stdcall7(fn stdFunction, a0, a1, a2, a3, a4, a5, a6 uintptr) uintptr
-
-func asmstdcall(fn unsafe.Pointer)
-func getlasterror() uint32
-func setlasterror(err uint32)
-func usleep1(usec uint32)
-func netpollinit()
-func netpollopen(fd uintptr, pd *pollDesc) int32
-func netpollclose(fd uintptr) int32
-func netpollarm(pd *pollDesc, mode int)
-
+//go:linkname os_sigpipe os.sigpipe
 func os_sigpipe() {
-	gothrow("too many writes on closed pipe")
+	throw("too many writes on closed pipe")
 }
 
-func sigpanic() {
-	g := getg()
-	if !canpanic(g) {
-		gothrow("unexpected signal during runtime execution")
-	}
-
-	switch uint32(g.sig) {
-	case _EXCEPTION_ACCESS_VIOLATION:
-		if g.sigcode1 < 0x1000 || g.paniconfault {
-			panicmem()
-		}
-		print("unexpected fault address ", hex(g.sigcode1), "\n")
-		gothrow("fault")
-	case _EXCEPTION_INT_DIVIDE_BY_ZERO:
-		panicdivide()
-	case _EXCEPTION_INT_OVERFLOW:
-		panicoverflow()
-	case _EXCEPTION_FLT_DENORMAL_OPERAND,
-		_EXCEPTION_FLT_DIVIDE_BY_ZERO,
-		_EXCEPTION_FLT_INEXACT_RESULT,
-		_EXCEPTION_FLT_OVERFLOW,
-		_EXCEPTION_FLT_UNDERFLOW:
-		panicfloat()
-	}
-	gothrow("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 closefd(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/os_windows.h b/src/runtime/os_windows.h
deleted file mode 100644
index d5d168d..0000000
--- a/src/runtime/os_windows.h
+++ /dev/null
@@ -1,42 +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.
-
-extern void *runtime·LoadLibrary;
-extern void *runtime·GetProcAddress;
-extern void *runtime·GetQueuedCompletionStatusEx;
-
-// Call a Windows function with stdcall conventions,
-// and switch to os stack during the call.
-void runtime·asmstdcall(void *c);
-void *runtime·stdcall0(void *fn);
-void *runtime·stdcall1(void *fn, uintptr a0);
-void *runtime·stdcall2(void *fn, uintptr a0, uintptr a1);
-void *runtime·stdcall3(void *fn, uintptr a0, uintptr a1, uintptr a2);
-void *runtime·stdcall4(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3);
-void *runtime·stdcall5(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uintptr a4);
-void *runtime·stdcall6(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uintptr a4, uintptr a5);
-void *runtime·stdcall7(void *fn, uintptr a0, uintptr a1, uintptr a2, uintptr a3, uintptr a4, uintptr a5, uintptr a6);
-
-uint32 runtime·getlasterror(void);
-void runtime·setlasterror(uint32 err);
-
-// Function to be called by windows CreateThread
-// to start new os thread.
-uint32 runtime·tstart_stdcall(M *newm);
-
-uint32 runtime·issigpanic(uint32);
-void runtime·sigpanic(void);
-uint32 runtime·ctrlhandler(uint32 type);
-
-// Windows dll function to go callback entry.
-byte *runtime·compilecallback(Eface fn, bool cleanstack);
-void *runtime·callbackasm(void);
-
-void runtime·install_exception_handler(void);
-void runtime·remove_exception_handler(void);
-
-// TODO(brainman): should not need those
-enum {
-	NSIG = 65,
-};
diff --git a/src/runtime/os_windows_386.c b/src/runtime/os_windows_386.c
deleted file mode 100644
index 9962f0d..0000000
--- a/src/runtime/os_windows_386.c
+++ /dev/null
@@ -1,128 +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 "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-
-void
-runtime·dumpregs(Context *r)
-{
-	runtime·printf("eax     %x\n", r->Eax);
-	runtime·printf("ebx     %x\n", r->Ebx);
-	runtime·printf("ecx     %x\n", r->Ecx);
-	runtime·printf("edx     %x\n", r->Edx);
-	runtime·printf("edi     %x\n", r->Edi);
-	runtime·printf("esi     %x\n", r->Esi);
-	runtime·printf("ebp     %x\n", r->Ebp);
-	runtime·printf("esp     %x\n", r->Esp);
-	runtime·printf("eip     %x\n", r->Eip);
-	runtime·printf("eflags  %x\n", r->EFlags);
-	runtime·printf("cs      %x\n", r->SegCs);
-	runtime·printf("fs      %x\n", r->SegFs);
-	runtime·printf("gs      %x\n", r->SegGs);
-}
-
-bool
-runtime·isgoexception(ExceptionRecord *info, Context *r)
-{
-	extern byte runtime·text[], runtime·etext[];
-
-	// Only handle exception if executing instructions in Go binary
-	// (not Windows library code). 
-	if(r->Eip < (uint32)runtime·text || (uint32)runtime·etext < r->Eip)
-		return false;
-
-	if(!runtime·issigpanic(info->ExceptionCode))
-		return false;
-
-	return true;
-}
-
-// Called by sigtramp from Windows VEH handler.
-// Return value signals whether the exception has been handled (EXCEPTION_CONTINUE_EXECUTION)
-// or should be made available to other handlers in the chain (EXCEPTION_CONTINUE_SEARCH).
-uint32
-runtime·exceptionhandler(ExceptionRecord *info, Context *r, G *gp)
-{
-	uintptr *sp;
-
-	if(!runtime·isgoexception(info, r))
-		return EXCEPTION_CONTINUE_SEARCH;
-
-	// 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 = info->ExceptionCode;
-	gp->sigcode0 = info->ExceptionInformation[0];
-	gp->sigcode1 = info->ExceptionInformation[1];
-	gp->sigpc = r->Eip;
-
-	// Only push runtime·sigpanic if r->eip != 0.
-	// If r->eip == 0, probably panicked because of a
-	// call to a nil func.  Not pushing that onto sp will
-	// make the trace look like a call to runtime·sigpanic instead.
-	// (Otherwise the trace will end at runtime·sigpanic and we
-	// won't get to see who faulted.)
-	if(r->Eip != 0) {
-		sp = (uintptr*)r->Esp;
-		*--sp = r->Eip;
-		r->Esp = (uintptr)sp;
-	}
-	r->Eip = (uintptr)runtime·sigpanic;
-	return EXCEPTION_CONTINUE_EXECUTION;
-}
-
-// lastcontinuehandler is reached, because runtime cannot handle
-// current exception. lastcontinuehandler will print crash info and exit.
-uint32
-runtime·lastcontinuehandler(ExceptionRecord *info, Context *r, G *gp)
-{
-	bool crash;
-
-	if(runtime·panicking)	// traceback already printed
-		runtime·exit(2);
-	runtime·panicking = 1;
-
-	runtime·printf("Exception %x %p %p %p\n", info->ExceptionCode,
-		(uintptr)info->ExceptionInformation[0], (uintptr)info->ExceptionInformation[1], (uintptr)r->Eip);
-
-	runtime·printf("PC=%x\n", r->Eip);
-	if(g->m->lockedg != nil && g->m->ncgo > 0 && gp == g->m->g0) {
-		runtime·printf("signal arrived during cgo execution\n");
-		gp = g->m->lockedg;
-	}
-	runtime·printf("\n");
-
-	if(runtime·gotraceback(&crash)){
-		runtime·tracebacktrap(r->Eip, r->Esp, 0, gp);
-		runtime·tracebackothers(gp);
-		runtime·dumpregs(r);
-	}
-	
-	if(crash)
-		runtime·crash();
-
-	runtime·exit(2);
-	return 0; // not reached
-}
-
-void
-runtime·sigenable(uint32 sig)
-{
-	USED(sig);
-}
-
-void
-runtime·sigdisable(uint32 sig)
-{
-	USED(sig);
-}
-
-void
-runtime·dosigprof(Context *r, G *gp, M *mp)
-{
-	runtime·sigprof((uint8*)r->Eip, (uint8*)r->Esp, nil, gp, mp);
-}
diff --git a/src/runtime/os_windows_386.go b/src/runtime/os_windows_386.go
deleted file mode 100644
index 86a1906..0000000
--- a/src/runtime/os_windows_386.go
+++ /dev/null
@@ -1,11 +0,0 @@
-// 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
-
-// contextPC returns the EIP (program counter) register from the context.
-func contextPC(r *context) uintptr { return uintptr(r.eip) }
-
-// contextSP returns the ESP (stack pointer) register from the context.
-func contextSP(r *context) uintptr { return uintptr(r.esp) }
diff --git a/src/runtime/os_windows_amd64.c b/src/runtime/os_windows_amd64.c
deleted file mode 100644
index e4617e4..0000000
--- a/src/runtime/os_windows_amd64.c
+++ /dev/null
@@ -1,150 +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.
-
-#include "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-
-void
-runtime·dumpregs(Context *r)
-{
-	runtime·printf("rax     %X\n", r->Rax);
-	runtime·printf("rbx     %X\n", r->Rbx);
-	runtime·printf("rcx     %X\n", r->Rcx);
-	runtime·printf("rdx     %X\n", r->Rdx);
-	runtime·printf("rdi     %X\n", r->Rdi);
-	runtime·printf("rsi     %X\n", r->Rsi);
-	runtime·printf("rbp     %X\n", r->Rbp);
-	runtime·printf("rsp     %X\n", r->Rsp);
-	runtime·printf("r8      %X\n", r->R8 );
-	runtime·printf("r9      %X\n", r->R9 );
-	runtime·printf("r10     %X\n", r->R10);
-	runtime·printf("r11     %X\n", r->R11);
-	runtime·printf("r12     %X\n", r->R12);
-	runtime·printf("r13     %X\n", r->R13);
-	runtime·printf("r14     %X\n", r->R14);
-	runtime·printf("r15     %X\n", r->R15);
-	runtime·printf("rip     %X\n", r->Rip);
-	runtime·printf("rflags  %X\n", r->EFlags);
-	runtime·printf("cs      %X\n", (uint64)r->SegCs);
-	runtime·printf("fs      %X\n", (uint64)r->SegFs);
-	runtime·printf("gs      %X\n", (uint64)r->SegGs);
-}
-
-bool
-runtime·isgoexception(ExceptionRecord *info, Context *r)
-{
-	extern byte runtime·text[], runtime·etext[];
-
-	// Only handle exception if executing instructions in Go binary
-	// (not Windows library code). 
-	if(r->Rip < (uint64)runtime·text || (uint64)runtime·etext < r->Rip)
-		return false;
-
-	if(!runtime·issigpanic(info->ExceptionCode))
-		return false;
-
-	return true;
-}
-
-// Called by sigtramp from Windows VEH handler.
-// Return value signals whether the exception has been handled (EXCEPTION_CONTINUE_EXECUTION)
-// or should be made available to other handlers in the chain (EXCEPTION_CONTINUE_SEARCH).
-uint32
-runtime·exceptionhandler(ExceptionRecord *info, Context *r, G *gp)
-{
-	uintptr *sp;
-
-	if(!runtime·isgoexception(info, r))
-		return EXCEPTION_CONTINUE_SEARCH;
-
-	// 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 = info->ExceptionCode;
-	gp->sigcode0 = info->ExceptionInformation[0];
-	gp->sigcode1 = info->ExceptionInformation[1];
-	gp->sigpc = r->Rip;
-
-	// Only push runtime·sigpanic if r->rip != 0.
-	// If r->rip == 0, probably panicked because of a
-	// call to a nil func.  Not pushing that onto sp will
-	// make the trace look like a call to runtime·sigpanic instead.
-	// (Otherwise the trace will end at runtime·sigpanic and we
-	// won't get to see who faulted.)
-	if(r->Rip != 0) {
-		sp = (uintptr*)r->Rsp;
-		*--sp = r->Rip;
-		r->Rsp = (uintptr)sp;
-	}
-	r->Rip = (uintptr)runtime·sigpanic;
-	return EXCEPTION_CONTINUE_EXECUTION;
-}
-
-// It seems Windows searches ContinueHandler's list even
-// if ExceptionHandler returns EXCEPTION_CONTINUE_EXECUTION.
-// firstcontinuehandler will stop that search,
-// if exceptionhandler did the same earlier.
-uint32
-runtime·firstcontinuehandler(ExceptionRecord *info, Context *r, G *gp)
-{
-	USED(gp);
-	if(!runtime·isgoexception(info, r))
-		return EXCEPTION_CONTINUE_SEARCH;
-	return EXCEPTION_CONTINUE_EXECUTION;
-}
-
-// lastcontinuehandler is reached, because runtime cannot handle
-// current exception. lastcontinuehandler will print crash info and exit.
-uint32
-runtime·lastcontinuehandler(ExceptionRecord *info, Context *r, G *gp)
-{
-	bool crash;
-
-	if(runtime·panicking)	// traceback already printed
-		runtime·exit(2);
-	runtime·panicking = 1;
-
-	runtime·printf("Exception %x %p %p %p\n", info->ExceptionCode,
-		info->ExceptionInformation[0], info->ExceptionInformation[1], r->Rip);
-
-
-	runtime·printf("PC=%X\n", r->Rip);
-	if(g->m->lockedg != nil && g->m->ncgo > 0 && gp == g->m->g0) {
-		runtime·printf("signal arrived during cgo execution\n");
-		gp = g->m->lockedg;
-	}
-	runtime·printf("\n");
-
-	if(runtime·gotraceback(&crash)){
-		runtime·tracebacktrap(r->Rip, r->Rsp, 0, gp);
-		runtime·tracebackothers(gp);
-		runtime·dumpregs(r);
-	}
-	
-	if(crash)
-		runtime·crash();
-
-	runtime·exit(2);
-	return 0; // not reached
-}
-
-void
-runtime·sigenable(uint32 sig)
-{
-	USED(sig);
-}
-
-void
-runtime·sigdisable(uint32 sig)
-{
-	USED(sig);
-}
-
-void
-runtime·dosigprof(Context *r, G *gp, M *mp)
-{
-	runtime·sigprof((uint8*)r->Rip, (uint8*)r->Rsp, nil, gp, mp);
-}
diff --git a/src/runtime/os_windows_amd64.go b/src/runtime/os_windows_amd64.go
deleted file mode 100644
index 3f4d4d0..0000000
--- a/src/runtime/os_windows_amd64.go
+++ /dev/null
@@ -1,11 +0,0 @@
-// 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
-
-// contextPC returns the RIP (program counter) register from the context.
-func contextPC(r *context) uintptr { return uintptr(r.rip) }
-
-// contextSP returns the RSP (stack pointer) register from the context.
-func contextSP(r *context) uintptr { return uintptr(r.rsp) }
diff --git a/src/runtime/panic.c b/src/runtime/panic.c
deleted file mode 100644
index 24eb6db..0000000
--- a/src/runtime/panic.c
+++ /dev/null
@@ -1,200 +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.
-
-#include "runtime.h"
-#include "arch_GOARCH.h"
-#include "stack.h"
-#include "malloc.h"
-#include "textflag.h"
-
-// Code related to defer, panic and recover.
-
-// TODO: remove once code is moved to Go
-extern Defer* runtime·newdefer(int32 siz);
-extern runtime·freedefer(Defer *d);
-
-uint32 runtime·panicking;
-static Mutex paniclk;
-
-void
-runtime·deferproc_m(void)
-{
-	int32 siz;
-	FuncVal *fn;
-	uintptr argp;
-	uintptr callerpc;
-	Defer *d;
-
-	siz = g->m->scalararg[0];
-	fn = g->m->ptrarg[0];
-	argp = g->m->scalararg[1];
-	callerpc = g->m->scalararg[2];
-	g->m->ptrarg[0] = nil;
-	g->m->scalararg[1] = 0;
-
-	d = runtime·newdefer(siz);
-	if(d->panic != nil)
-		runtime·throw("deferproc: d->panic != nil after newdefer");
-	d->fn = fn;
-	d->pc = callerpc;
-	d->argp = argp;
-	runtime·memmove(d+1, (void*)argp, siz);
-}
-
-// Unwind the stack after a deferred function calls recover
-// after a panic.  Then arrange to continue running as though
-// the caller of the deferred function returned normally.
-void
-runtime·recovery_m(G *gp)
-{
-	void *argp;
-	uintptr pc;
-	
-	// Info about defer passed in G struct.
-	argp = (void*)gp->sigcode0;
-	pc = (uintptr)gp->sigcode1;
-
-	// d's arguments need to be in the stack.
-	if(argp != nil && ((uintptr)argp < gp->stack.lo || gp->stack.hi < (uintptr)argp)) {
-		runtime·printf("recover: %p not in [%p, %p]\n", argp, gp->stack.lo, gp->stack.hi);
-		runtime·throw("bad recovery");
-	}
-
-	// Make the deferproc for this d return again,
-	// this time returning 1.  The calling function will
-	// jump to the standard return epilogue.
-	// The -2*sizeof(uintptr) makes up for the
-	// two extra words that are on the stack at
-	// each call to deferproc.
-	// (The pc we're returning to does pop pop
-	// before it tests the return value.)
-	// On the arm there are 2 saved LRs mixed in too.
-	if(thechar == '5')
-		gp->sched.sp = (uintptr)argp - 4*sizeof(uintptr);
-	else
-		gp->sched.sp = (uintptr)argp - 2*sizeof(uintptr);
-	gp->sched.pc = pc;
-	gp->sched.lr = 0;
-	gp->sched.ret = 1;
-	runtime·gogo(&gp->sched);
-}
-
-void
-runtime·startpanic_m(void)
-{
-	if(runtime·mheap.cachealloc.size == 0) { // very early
-		runtime·printf("runtime: panic before malloc heap initialized\n");
-		g->m->mallocing = 1; // tell rest of panic not to try to malloc
-	} else if(g->m->mcache == nil) // can happen if called from signal handler or throw
-		g->m->mcache = runtime·allocmcache();
-	switch(g->m->dying) {
-	case 0:
-		g->m->dying = 1;
-		if(g != nil) {
-			g->writebuf.array = nil;
-			g->writebuf.len = 0;
-			g->writebuf.cap = 0;
-		}
-		runtime·xadd(&runtime·panicking, 1);
-		runtime·lock(&paniclk);
-		if(runtime·debug.schedtrace > 0 || runtime·debug.scheddetail > 0)
-			runtime·schedtrace(true);
-		runtime·freezetheworld();
-		return;
-	case 1:
-		// Something failed while panicing, probably the print of the
-		// argument to panic().  Just print a stack trace and exit.
-		g->m->dying = 2;
-		runtime·printf("panic during panic\n");
-		runtime·dopanic(0);
-		runtime·exit(3);
-	case 2:
-		// This is a genuine bug in the runtime, we couldn't even
-		// print the stack trace successfully.
-		g->m->dying = 3;
-		runtime·printf("stack trace unavailable\n");
-		runtime·exit(4);
-	default:
-		// Can't even print!  Just exit.
-		runtime·exit(5);
-	}
-}
-
-void
-runtime·dopanic_m(void)
-{
-	G *gp;
-	uintptr sp, pc;
-	static bool didothers;
-	bool crash;
-	int32 t;
-
-	gp = g->m->ptrarg[0];
-	g->m->ptrarg[0] = nil;
-	pc = g->m->scalararg[0];
-	sp = g->m->scalararg[1];
-	g->m->scalararg[1] = 0;
-	if(gp->sig != 0)
-		runtime·printf("[signal %x code=%p addr=%p pc=%p]\n",
-			gp->sig, gp->sigcode0, gp->sigcode1, gp->sigpc);
-
-	if((t = runtime·gotraceback(&crash)) > 0){
-		if(gp != gp->m->g0) {
-			runtime·printf("\n");
-			runtime·goroutineheader(gp);
-			runtime·traceback(pc, sp, 0, gp);
-		} else if(t >= 2 || g->m->throwing > 0) {
-			runtime·printf("\nruntime stack:\n");
-			runtime·traceback(pc, sp, 0, gp);
-		}
-		if(!didothers) {
-			didothers = true;
-			runtime·tracebackothers(gp);
-		}
-	}
-	runtime·unlock(&paniclk);
-	if(runtime·xadd(&runtime·panicking, -1) != 0) {
-		// Some other m is panicking too.
-		// Let it print what it needs to print.
-		// Wait forever without chewing up cpu.
-		// It will exit when it's done.
-		static Mutex deadlock;
-		runtime·lock(&deadlock);
-		runtime·lock(&deadlock);
-	}
-	
-	if(crash)
-		runtime·crash();
-
-	runtime·exit(2);
-}
-
-#pragma textflag NOSPLIT
-bool
-runtime·canpanic(G *gp)
-{
-	M *m;
-	uint32 status;
-
-	// Note that g is m->gsignal, different from gp.
-	// Note also that g->m can change at preemption, so m can go stale
-	// if this function ever makes a function call.
-	m = g->m;
-
-	// Is it okay for gp to panic instead of crashing the program?
-	// Yes, as long as it is running Go code, not runtime code,
-	// and not stuck in a system call.
-	if(gp == nil || gp != m->curg)
-		return false;
-	if(m->locks-m->softfloat != 0 || m->mallocing != 0 || m->throwing != 0 || m->gcing != 0 || m->dying != 0)
-		return false;
-	status = runtime·readgstatus(gp);
-	if((status&~Gscan) != Grunning || gp->syscallsp != 0)
-		return false;
-#ifdef GOOS_windows
-	if(m->libcallsp != 0)
-		return false;
-#endif
-	return true;
-}
diff --git a/src/runtime/panic.go b/src/runtime/panic.go
index 685ff5c..a166281 100644
--- a/src/runtime/panic.go
+++ b/src/runtime/panic.go
@@ -43,41 +43,41 @@ func panicmem() {
 }
 
 func throwreturn() {
-	gothrow("no return at end of a typed function - compiler is broken")
+	throw("no return at end of a typed function - compiler is broken")
 }
 
 func throwinit() {
-	gothrow("recursive call during initialization - linker skew")
+	throw("recursive call during initialization - linker skew")
 }
 
 // Create a new deferred function fn with siz bytes of arguments.
 // The compiler turns a defer statement into a call to this.
 //go:nosplit
 func deferproc(siz int32, fn *funcval) { // arguments of fn follow fn
+	if getg().m.curg != getg() {
+		// go code on the system stack can't defer
+		throw("defer on system stack")
+	}
+
 	// the arguments of fn are in a perilous state.  The stack map
 	// for deferproc does not describe them.  So we can't let garbage
 	// collection or stack copying trigger until we've copied them out
-	// to somewhere safe.  deferproc_m does that.  Until deferproc_m,
-	// we can only call nosplit routines.
-	argp := uintptr(unsafe.Pointer(&fn))
-	argp += unsafe.Sizeof(fn)
-	if GOARCH == "arm" {
-		argp += ptrSize // skip caller's saved link register
-	}
-	mp := acquirem()
-	mp.scalararg[0] = uintptr(siz)
-	mp.ptrarg[0] = unsafe.Pointer(fn)
-	mp.scalararg[1] = argp
-	mp.scalararg[2] = getcallerpc(unsafe.Pointer(&siz))
-
-	if mp.curg != getg() {
-		// go code on the m stack can't defer
-		gothrow("defer on m")
-	}
-
-	onM(deferproc_m)
-
-	releasem(mp)
+	// to somewhere safe.  The memmove below does that.
+	// Until the copy completes, we can only call nosplit routines.
+	sp := getcallersp(unsafe.Pointer(&siz))
+	argp := uintptr(unsafe.Pointer(&fn)) + unsafe.Sizeof(fn)
+	callerpc := getcallerpc(unsafe.Pointer(&siz))
+
+	systemstack(func() {
+		d := newdefer(siz)
+		if d._panic != nil {
+			throw("deferproc: d.panic != nil after newdefer")
+		}
+		d.fn = fn
+		d.pc = callerpc
+		d.sp = sp
+		memmove(add(unsafe.Pointer(d), unsafe.Sizeof(*d)), unsafe.Pointer(argp), uintptr(siz))
+	})
 
 	// deferproc returns 0 normally.
 	// a deferred func that stops a panic
@@ -130,14 +130,14 @@ func testdefersizes() {
 		if defersc >= uintptr(len(m)) {
 			break
 		}
-		siz := goroundupsize(totaldefersize(i))
+		siz := roundupsize(totaldefersize(i))
 		if m[defersc] < 0 {
 			m[defersc] = int32(siz)
 			continue
 		}
 		if m[defersc] != int32(siz) {
 			print("bad defer size class: i=", i, " siz=", siz, " defersc=", defersc, "\n")
-			gothrow("bad defer size class")
+			throw("bad defer size class")
 		}
 	}
 }
@@ -159,21 +159,32 @@ func init() {
 
 // Allocate a Defer, usually using per-P pool.
 // Each defer must be released with freedefer.
-// Note: runs on M stack
+// Note: runs on g0 stack
 func newdefer(siz int32) *_defer {
 	var d *_defer
 	sc := deferclass(uintptr(siz))
 	mp := acquirem()
 	if sc < uintptr(len(p{}.deferpool)) {
-		pp := mp.p
-		d = pp.deferpool[sc]
-		if d != nil {
-			pp.deferpool[sc] = d.link
+		pp := mp.p.ptr()
+		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 {
 		// Allocate new defer+args.
-		total := goroundupsize(totaldefersize(uintptr(siz)))
+		total := roundupsize(totaldefersize(uintptr(siz)))
 		d = (*_defer)(mallocgc(total, deferType, 0))
 	}
 	d.siz = siz
@@ -186,7 +197,6 @@ func newdefer(siz int32) *_defer {
 
 // Free the given defer.
 // The defer cannot be used after this call.
-//go:nosplit
 func freedefer(d *_defer) {
 	if d._panic != nil {
 		freedeferpanic()
@@ -197,10 +207,29 @@ func freedefer(d *_defer) {
 	sc := deferclass(uintptr(d.siz))
 	if sc < uintptr(len(p{}.deferpool)) {
 		mp := acquirem()
-		pp := mp.p
+		pp := mp.p.ptr()
+		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)
 	}
 }
@@ -209,12 +238,12 @@ func freedefer(d *_defer) {
 // Windows otherwise runs out of stack space.
 func freedeferpanic() {
 	// _panic must be cleared before d is unlinked from gp.
-	gothrow("freedefer with d._panic != nil")
+	throw("freedefer with d._panic != nil")
 }
 
 func freedeferfn() {
 	// fn must be cleared before d is unlinked from gp.
-	gothrow("freedefer with d.fn != nil")
+	throw("freedefer with d.fn != nil")
 }
 
 // Run a deferred function if there is one.
@@ -237,8 +266,8 @@ func deferreturn(arg0 uintptr) {
 	if d == nil {
 		return
 	}
-	argp := uintptr(unsafe.Pointer(&arg0))
-	if d.argp != argp {
+	sp := getcallersp(unsafe.Pointer(&arg0))
+	if d.sp != sp {
 		return
 	}
 
@@ -247,13 +276,16 @@ func deferreturn(arg0 uintptr) {
 	// won't know the form of the arguments until the jmpdefer can
 	// flip the PC over to fn.
 	mp := acquirem()
-	memmove(unsafe.Pointer(argp), deferArgs(d), uintptr(d.siz))
+	memmove(unsafe.Pointer(&arg0), deferArgs(d), uintptr(d.siz))
 	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, argp)
+	jmpdefer(fn, uintptr(unsafe.Pointer(&arg0)))
 }
 
 // Goexit terminates the goroutine that calls it.  No other goroutine is affected.
@@ -285,9 +317,9 @@ func Goexit() {
 			continue
 		}
 		d.started = true
-		reflectcall(unsafe.Pointer(d.fn), deferArgs(d), uint32(d.siz), uint32(d.siz))
+		reflectcall(nil, unsafe.Pointer(d.fn), deferArgs(d), uint32(d.siz), uint32(d.siz))
 		if gp._defer != d {
-			gothrow("bad defer entry in Goexit")
+			throw("bad defer entry in Goexit")
 		}
 		d._panic = nil
 		d.fn = nil
@@ -295,11 +327,9 @@ func Goexit() {
 		freedefer(d)
 		// Note: we ignore recovers here because Goexit isn't a panic
 	}
-	goexit()
+	goexit1()
 }
 
-func canpanic(*g) bool
-
 // Print all currently active panics.  Used when crashing.
 func printpanics(p *_panic) {
 	if p.link != nil {
@@ -318,7 +348,10 @@ func printpanics(p *_panic) {
 func gopanic(e interface{}) {
 	gp := getg()
 	if gp.m.curg != gp {
-		gothrow("panic on m stack")
+		print("panic: ")
+		printany(e)
+		print("\n")
+		throw("panic on system stack")
 	}
 
 	// m.softfloat is set during software floating point.
@@ -328,25 +361,28 @@ func gopanic(e interface{}) {
 	if gp.m.softfloat != 0 {
 		gp.m.locks--
 		gp.m.softfloat = 0
-		gothrow("panic during softfloat")
+		throw("panic during softfloat")
 	}
 	if gp.m.mallocing != 0 {
 		print("panic: ")
 		printany(e)
 		print("\n")
-		gothrow("panic during malloc")
+		throw("panic during malloc")
 	}
-	if gp.m.gcing != 0 {
+	if gp.m.preemptoff != "" {
 		print("panic: ")
 		printany(e)
 		print("\n")
-		gothrow("panic during gc")
+		print("preempt off reason: ")
+		print(gp.m.preemptoff)
+		print("\n")
+		throw("panic during preemptoff")
 	}
 	if gp.m.locks != 0 {
 		print("panic: ")
 		printany(e)
 		print("\n")
-		gothrow("panic holding locks")
+		throw("panic holding locks")
 	}
 
 	var p _panic
@@ -375,7 +411,7 @@ func gopanic(e interface{}) {
 
 		// Mark defer as started, but keep on list, so that traceback
 		// can find and update the defer's argument frame if stack growth
-		// or a garbage collection hapens before reflectcall starts executing d.fn.
+		// or a garbage collection happens before reflectcall starts executing d.fn.
 		d.started = true
 
 		// Record the panic that is running the defer.
@@ -384,12 +420,12 @@ func gopanic(e interface{}) {
 		d._panic = (*_panic)(noescape((unsafe.Pointer)(&p)))
 
 		p.argp = unsafe.Pointer(getargp(0))
-		reflectcall(unsafe.Pointer(d.fn), deferArgs(d), uint32(d.siz), uint32(d.siz))
+		reflectcall(nil, unsafe.Pointer(d.fn), deferArgs(d), uint32(d.siz), uint32(d.siz))
 		p.argp = nil
 
 		// reflectcall did not panic. Remove d.
 		if gp._defer != d {
-			gothrow("bad defer entry in panic")
+			throw("bad defer entry in panic")
 		}
 		d._panic = nil
 		d.fn = nil
@@ -399,7 +435,7 @@ func gopanic(e interface{}) {
 		//GC()
 
 		pc := d.pc
-		argp := unsafe.Pointer(d.argp) // must be pointer so it gets adjusted during stack copy
+		sp := unsafe.Pointer(d.sp) // must be pointer so it gets adjusted during stack copy
 		freedefer(d)
 		if p.recovered {
 			gp._panic = p.link
@@ -412,10 +448,10 @@ func gopanic(e interface{}) {
 				gp.sig = 0
 			}
 			// Pass information about recovering frame to recovery.
-			gp.sigcode0 = uintptr(argp)
+			gp.sigcode0 = uintptr(sp)
 			gp.sigcode1 = pc
-			mcall(recovery_m)
-			gothrow("recovery failed") // mcall should not return
+			mcall(recovery)
+			throw("recovery failed") // mcall should not return
 		}
 	}
 
@@ -466,40 +502,28 @@ func gorecover(argp uintptr) interface{} {
 
 //go:nosplit
 func startpanic() {
-	onM_signalok(startpanic_m)
+	systemstack(startpanic_m)
 }
 
 //go:nosplit
 func dopanic(unused int) {
+	pc := getcallerpc(unsafe.Pointer(&unused))
+	sp := getcallersp(unsafe.Pointer(&unused))
 	gp := getg()
-	mp := acquirem()
-	mp.ptrarg[0] = unsafe.Pointer(gp)
-	mp.scalararg[0] = getcallerpc((unsafe.Pointer)(&unused))
-	mp.scalararg[1] = getcallersp((unsafe.Pointer)(&unused))
-	onM_signalok(dopanic_m) // should never return
+	systemstack(func() {
+		dopanic_m(gp, pc, sp) // should never return
+	})
 	*(*int)(nil) = 0
 }
 
 //go:nosplit
-func throw(s *byte) {
-	gp := getg()
-	if gp.m.throwing == 0 {
-		gp.m.throwing = 1
-	}
-	startpanic()
-	print("fatal error: ", gostringnocopy(s), "\n")
-	dopanic(0)
-	*(*int)(nil) = 0 // not reached
-}
-
-//go:nosplit
-func gothrow(s string) {
+func throw(s string) {
+	print("fatal error: ", s, "\n")
 	gp := getg()
 	if gp.m.throwing == 0 {
 		gp.m.throwing = 1
 	}
 	startpanic()
-	print("fatal error: ", s, "\n")
 	dopanic(0)
 	*(*int)(nil) = 0 // not reached
 }
diff --git a/src/runtime/panic1.go b/src/runtime/panic1.go
new file mode 100644
index 0000000..1a71d09
--- /dev/null
+++ b/src/runtime/panic1.go
@@ -0,0 +1,150 @@
+// 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.
+
+package runtime
+
+// Code related to defer, panic and recover.
+// TODO: Merge into panic.go.
+
+//uint32 runtime·panicking;
+var paniclk mutex
+
+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
+// the caller of the deferred function returned normally.
+func recovery(gp *g) {
+	// Info about defer passed in G struct.
+	sp := gp.sigcode0
+	pc := gp.sigcode1
+
+	// d's arguments need to be in the stack.
+	if sp != 0 && (sp < gp.stack.lo || gp.stack.hi < sp) {
+		print("recover: ", hex(sp), " not in [", hex(gp.stack.lo), ", ", hex(gp.stack.hi), "]\n")
+		throw("bad recovery")
+	}
+
+	// Make the deferproc for this d return again,
+	// this time returning 1.  The calling function will
+	// jump to the standard return epilogue.
+	gcUnwindBarriers(gp, sp)
+	gp.sched.sp = sp
+	gp.sched.pc = pc
+	gp.sched.lr = 0
+	gp.sched.ret = 1
+	gogo(&gp.sched)
+}
+
+func startpanic_m() {
+	_g_ := getg()
+	if mheap_.cachealloc.size == 0 { // very early
+		print("runtime: panic before malloc heap initialized\n")
+		_g_.m.mallocing = 1 // tell rest of panic not to try to malloc
+	} else if _g_.m.mcache == nil { // can happen if called from signal handler or throw
+		_g_.m.mcache = allocmcache()
+	}
+
+	switch _g_.m.dying {
+	case 0:
+		_g_.m.dying = 1
+		if _g_ != nil {
+			_g_.writebuf = nil
+		}
+		xadd(&panicking, 1)
+		lock(&paniclk)
+		if debug.schedtrace > 0 || debug.scheddetail > 0 {
+			schedtrace(true)
+		}
+		freezetheworld()
+		return
+	case 1:
+		// Something failed while panicing, probably the print of the
+		// argument to panic().  Just print a stack trace and exit.
+		_g_.m.dying = 2
+		print("panic during panic\n")
+		dopanic(0)
+		exit(3)
+		fallthrough
+	case 2:
+		// This is a genuine bug in the runtime, we couldn't even
+		// print the stack trace successfully.
+		_g_.m.dying = 3
+		print("stack trace unavailable\n")
+		exit(4)
+		fallthrough
+	default:
+		// Can't even print!  Just exit.
+		exit(5)
+	}
+}
+
+var didothers bool
+var deadlock mutex
+
+func dopanic_m(gp *g, pc, sp uintptr) {
+	if gp.sig != 0 {
+		print("[signal ", hex(gp.sig), " code=", hex(gp.sigcode0), " addr=", hex(gp.sigcode1), " pc=", hex(gp.sigpc), "]\n")
+	}
+
+	var docrash bool
+	_g_ := getg()
+	if t := gotraceback(&docrash); t > 0 {
+		if gp != gp.m.g0 {
+			print("\n")
+			goroutineheader(gp)
+			traceback(pc, sp, 0, gp)
+		} else if t >= 2 || _g_.m.throwing > 0 {
+			print("\nruntime stack:\n")
+			traceback(pc, sp, 0, gp)
+		}
+		if !didothers {
+			didothers = true
+			tracebackothers(gp)
+		}
+	}
+	unlock(&paniclk)
+
+	if xadd(&panicking, -1) != 0 {
+		// Some other m is panicking too.
+		// Let it print what it needs to print.
+		// Wait forever without chewing up cpu.
+		// It will exit when it's done.
+		lock(&deadlock)
+		lock(&deadlock)
+	}
+
+	if docrash {
+		crash()
+	}
+
+	exit(2)
+}
+
+//go:nosplit
+func canpanic(gp *g) bool {
+	// Note that g is m->gsignal, different from gp.
+	// Note also that g->m can change at preemption, so m can go stale
+	// if this function ever makes a function call.
+	_g_ := getg()
+	_m_ := _g_.m
+
+	// Is it okay for gp to panic instead of crashing the program?
+	// Yes, as long as it is running Go code, not runtime code,
+	// and not stuck in a system call.
+	if gp == nil || gp != _m_.curg {
+		return false
+	}
+	if _m_.locks-_m_.softfloat != 0 || _m_.mallocing != 0 || _m_.throwing != 0 || _m_.preemptoff != "" || _m_.dying != 0 {
+		return false
+	}
+	status := readgstatus(gp)
+	if status&^_Gscan != _Grunning || gp.syscallsp != 0 {
+		return false
+	}
+	if GOOS == "windows" && _m_.libcallsp != 0 {
+		return false
+	}
+	return true
+}
diff --git a/src/runtime/parfor.c b/src/runtime/parfor.c
deleted file mode 100644
index e449568..0000000
--- a/src/runtime/parfor.c
+++ /dev/null
@@ -1,226 +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.
-
-// Parallel for algorithm.
-
-#include "runtime.h"
-#include "arch_GOARCH.h"
-#include "malloc.h"
-
-struct ParForThread
-{
-	// the thread's iteration space [32lsb, 32msb)
-	uint64 pos;
-	// stats
-	uint64 nsteal;
-	uint64 nstealcnt;
-	uint64 nprocyield;
-	uint64 nosyield;
-	uint64 nsleep;
-	byte pad[CacheLineSize];
-};
-
-void
-runtime·parforsetup(ParFor *desc, uint32 nthr, uint32 n, void *ctx, bool wait, void (*body)(ParFor*, uint32))
-{
-	uint32 i, begin, end;
-	uint64 *pos;
-
-	if(desc == nil || nthr == 0 || nthr > desc->nthrmax || body == nil) {
-		runtime·printf("desc=%p nthr=%d count=%d body=%p\n", desc, nthr, n, body);
-		runtime·throw("parfor: invalid args");
-	}
-
-	desc->body = body;
-	desc->done = 0;
-	desc->nthr = nthr;
-	desc->thrseq = 0;
-	desc->cnt = n;
-	desc->ctx = ctx;
-	desc->wait = wait;
-	desc->nsteal = 0;
-	desc->nstealcnt = 0;
-	desc->nprocyield = 0;
-	desc->nosyield = 0;
-	desc->nsleep = 0;
-	for(i=0; i<nthr; i++) {
-		begin = (uint64)n*i / nthr;
-		end = (uint64)n*(i+1) / nthr;
-		pos = &desc->thr[i].pos;
-		if(((uintptr)pos & 7) != 0)
-			runtime·throw("parforsetup: pos is not aligned");
-		*pos = (uint64)begin | (((uint64)end)<<32);
-	}
-}
-
-void
-runtime·parfordo(ParFor *desc)
-{
-	ParForThread *me;
-	uint32 tid, begin, end, begin2, try, victim, i;
-	uint64 *mypos, *victimpos, pos, newpos;
-	void (*body)(ParFor*, uint32);
-	bool idle;
-
-	// Obtain 0-based thread index.
-	tid = runtime·xadd(&desc->thrseq, 1) - 1;
-	if(tid >= desc->nthr) {
-		runtime·printf("tid=%d nthr=%d\n", tid, desc->nthr);
-		runtime·throw("parfor: invalid tid");
-	}
-
-	// If single-threaded, just execute the for serially.
-	if(desc->nthr==1) {
-		for(i=0; i<desc->cnt; i++)
-			desc->body(desc, i);
-		return;
-	}
-
-	body = desc->body;
-	me = &desc->thr[tid];
-	mypos = &me->pos;
-	for(;;) {
-		for(;;) {
-			// While there is local work,
-			// bump low index and execute the iteration.
-			pos = runtime·xadd64(mypos, 1);
-			begin = (uint32)pos-1;
-			end = (uint32)(pos>>32);
-			if(begin < end) {
-				body(desc, begin);
-				continue;
-			}
-			break;
-		}
-
-		// Out of work, need to steal something.
-		idle = false;
-		for(try=0;; try++) {
-			// If we don't see any work for long enough,
-			// increment the done counter...
-			if(try > desc->nthr*4 && !idle) {
-				idle = true;
-				runtime·xadd(&desc->done, 1);
-			}
-			// ...if all threads have incremented the counter,
-			// we are done.
-			if(desc->done + !idle == desc->nthr) {
-				if(!idle)
-					runtime·xadd(&desc->done, 1);
-				goto exit;
-			}
-			// Choose a random victim for stealing.
-			victim = runtime·fastrand1() % (desc->nthr-1);
-			if(victim >= tid)
-				victim++;
-			victimpos = &desc->thr[victim].pos;
-			for(;;) {
-				// See if it has any work.
-				pos = runtime·atomicload64(victimpos);
-				begin = (uint32)pos;
-				end = (uint32)(pos>>32);
-				if(begin+1 >= end) {
-					begin = end = 0;
-					break;
-				}
-				if(idle) {
-					runtime·xadd(&desc->done, -1);
-					idle = false;
-				}
-				begin2 = begin + (end-begin)/2;
-				newpos = (uint64)begin | (uint64)begin2<<32;
-				if(runtime·cas64(victimpos, pos, newpos)) {
-					begin = begin2;
-					break;
-				}
-			}
-			if(begin < end) {
-				// Has successfully stolen some work.
-				if(idle)
-					runtime·throw("parfor: should not be idle");
-				runtime·atomicstore64(mypos, (uint64)begin | (uint64)end<<32);
-				me->nsteal++;
-				me->nstealcnt += end-begin;
-				break;
-			}
-			// Backoff.
-			if(try < desc->nthr) {
-				// nothing
-			} else if (try < 4*desc->nthr) {
-				me->nprocyield++;
-				runtime·procyield(20);
-			// If a caller asked not to wait for the others, exit now
-			// (assume that most work is already done at this point).
-			} else if (!desc->wait) {
-				if(!idle)
-					runtime·xadd(&desc->done, 1);
-				goto exit;
-			} else if (try < 6*desc->nthr) {
-				me->nosyield++;
-				runtime·osyield();
-			} else {
-				me->nsleep++;
-				runtime·usleep(1);
-			}
-		}
-	}
-exit:
-	runtime·xadd64(&desc->nsteal, me->nsteal);
-	runtime·xadd64(&desc->nstealcnt, me->nstealcnt);
-	runtime·xadd64(&desc->nprocyield, me->nprocyield);
-	runtime·xadd64(&desc->nosyield, me->nosyield);
-	runtime·xadd64(&desc->nsleep, me->nsleep);
-	me->nsteal = 0;
-	me->nstealcnt = 0;
-	me->nprocyield = 0;
-	me->nosyield = 0;
-	me->nsleep = 0;
-}
-
-// For testing from Go.
-void
-runtime·newparfor_m(void)
-{
-	g->m->ptrarg[0] = runtime·parforalloc(g->m->scalararg[0]);
-}
-
-void
-runtime·parforsetup_m(void)
-{
-	ParFor *desc;
-	void *ctx;
-	void (*body)(ParFor*, uint32);
-
-	desc = g->m->ptrarg[0];
-	g->m->ptrarg[0] = nil;
-	ctx = g->m->ptrarg[1];
-	g->m->ptrarg[1] = nil;
-	body = g->m->ptrarg[2];
-	g->m->ptrarg[2] = nil;
-
-	runtime·parforsetup(desc, g->m->scalararg[0], g->m->scalararg[1], ctx, g->m->scalararg[2], body);
-}
-
-void
-runtime·parfordo_m(void)
-{
-	ParFor *desc;
-
-	desc = g->m->ptrarg[0];
-	g->m->ptrarg[0] = nil;
-	runtime·parfordo(desc);
-}
-
-void
-runtime·parforiters_m(void)
-{
-	ParFor *desc;
-	uintptr tid;
-
-	desc = g->m->ptrarg[0];
-	g->m->ptrarg[0] = nil;
-	tid = g->m->scalararg[0];
-	g->m->scalararg[0] = desc->thr[tid].pos;
-	g->m->scalararg[1] = desc->thr[tid].pos>>32;
-}
diff --git a/src/runtime/parfor.go b/src/runtime/parfor.go
new file mode 100644
index 0000000..c82beee
--- /dev/null
+++ b/src/runtime/parfor.go
@@ -0,0 +1,212 @@
+// 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.
+
+// Parallel for algorithm.
+
+package runtime
+
+// A parfor holds state for the parallel for operation.
+type parfor struct {
+	body   func(*parfor, uint32) // executed for each element
+	done   uint32                // number of idle threads
+	nthr   uint32                // total number of threads
+	thrseq uint32                // thread id sequencer
+	cnt    uint32                // iteration space [0, cnt)
+	wait   bool                  // if true, wait while all threads finish processing,
+	// otherwise parfor may return while other threads are still working
+
+	thr []parforthread // thread descriptors
+
+	// stats
+	nsteal     uint64
+	nstealcnt  uint64
+	nprocyield uint64
+	nosyield   uint64
+	nsleep     uint64
+}
+
+// A parforthread holds state for a single thread in the parallel for.
+type parforthread struct {
+	// the thread's iteration space [32lsb, 32msb)
+	pos uint64
+	// stats
+	nsteal     uint64
+	nstealcnt  uint64
+	nprocyield uint64
+	nosyield   uint64
+	nsleep     uint64
+	pad        [_CacheLineSize]byte
+}
+
+func parforalloc(nthrmax uint32) *parfor {
+	return &parfor{
+		thr: make([]parforthread, nthrmax),
+	}
+}
+
+// Parforsetup initializes desc for a parallel for operation with nthr
+// threads executing n jobs.
+//
+// On return the nthr threads are each expected to call parfordo(desc)
+// to run the operation. During those calls, for each i in [0, n), one
+// thread will be used invoke body(desc, i).
+// If wait is true, no parfordo will return until all work has been completed.
+// If wait is false, parfordo may return when there is a small amount
+// of work left, under the assumption that another thread has that
+// work well in hand.
+func parforsetup(desc *parfor, nthr, n uint32, wait bool, body func(*parfor, uint32)) {
+	if desc == nil || nthr == 0 || nthr > uint32(len(desc.thr)) || body == nil {
+		print("desc=", desc, " nthr=", nthr, " count=", n, " body=", body, "\n")
+		throw("parfor: invalid args")
+	}
+
+	desc.body = body
+	desc.done = 0
+	desc.nthr = nthr
+	desc.thrseq = 0
+	desc.cnt = n
+	desc.wait = wait
+	desc.nsteal = 0
+	desc.nstealcnt = 0
+	desc.nprocyield = 0
+	desc.nosyield = 0
+	desc.nsleep = 0
+
+	for i := range desc.thr {
+		begin := uint32(uint64(n) * uint64(i) / uint64(nthr))
+		end := uint32(uint64(n) * uint64(i+1) / uint64(nthr))
+		desc.thr[i].pos = uint64(begin) | uint64(end)<<32
+	}
+}
+
+func parfordo(desc *parfor) {
+	// Obtain 0-based thread index.
+	tid := xadd(&desc.thrseq, 1) - 1
+	if tid >= desc.nthr {
+		print("tid=", tid, " nthr=", desc.nthr, "\n")
+		throw("parfor: invalid tid")
+	}
+
+	// If single-threaded, just execute the for serially.
+	body := desc.body
+	if desc.nthr == 1 {
+		for i := uint32(0); i < desc.cnt; i++ {
+			body(desc, i)
+		}
+		return
+	}
+
+	me := &desc.thr[tid]
+	mypos := &me.pos
+	for {
+		for {
+			// While there is local work,
+			// bump low index and execute the iteration.
+			pos := xadd64(mypos, 1)
+			begin := uint32(pos) - 1
+			end := uint32(pos >> 32)
+			if begin < end {
+				body(desc, begin)
+				continue
+			}
+			break
+		}
+
+		// Out of work, need to steal something.
+		idle := false
+		for try := uint32(0); ; try++ {
+			// If we don't see any work for long enough,
+			// increment the done counter...
+			if try > desc.nthr*4 && !idle {
+				idle = true
+				xadd(&desc.done, 1)
+			}
+
+			// ...if all threads have incremented the counter,
+			// we are done.
+			extra := uint32(0)
+			if !idle {
+				extra = 1
+			}
+			if desc.done+extra == desc.nthr {
+				if !idle {
+					xadd(&desc.done, 1)
+				}
+				goto exit
+			}
+
+			// Choose a random victim for stealing.
+			var begin, end uint32
+			victim := fastrand1() % (desc.nthr - 1)
+			if victim >= tid {
+				victim++
+			}
+			victimpos := &desc.thr[victim].pos
+			for {
+				// See if it has any work.
+				pos := atomicload64(victimpos)
+				begin = uint32(pos)
+				end = uint32(pos >> 32)
+				if begin+1 >= end {
+					end = 0
+					begin = end
+					break
+				}
+				if idle {
+					xadd(&desc.done, -1)
+					idle = false
+				}
+				begin2 := begin + (end-begin)/2
+				newpos := uint64(begin) | uint64(begin2)<<32
+				if cas64(victimpos, pos, newpos) {
+					begin = begin2
+					break
+				}
+			}
+			if begin < end {
+				// Has successfully stolen some work.
+				if idle {
+					throw("parfor: should not be idle")
+				}
+				atomicstore64(mypos, uint64(begin)|uint64(end)<<32)
+				me.nsteal++
+				me.nstealcnt += uint64(end) - uint64(begin)
+				break
+			}
+
+			// Backoff.
+			if try < desc.nthr {
+				// nothing
+			} else if try < 4*desc.nthr {
+				me.nprocyield++
+				procyield(20)
+			} else if !desc.wait {
+				// If a caller asked not to wait for the others, exit now
+				// (assume that most work is already done at this point).
+				if !idle {
+					xadd(&desc.done, 1)
+				}
+				goto exit
+			} else if try < 6*desc.nthr {
+				me.nosyield++
+				osyield()
+			} else {
+				me.nsleep++
+				usleep(1)
+			}
+		}
+	}
+
+exit:
+	xadd64(&desc.nsteal, int64(me.nsteal))
+	xadd64(&desc.nstealcnt, int64(me.nstealcnt))
+	xadd64(&desc.nprocyield, int64(me.nprocyield))
+	xadd64(&desc.nosyield, int64(me.nosyield))
+	xadd64(&desc.nsleep, int64(me.nsleep))
+	me.nsteal = 0
+	me.nstealcnt = 0
+	me.nprocyield = 0
+	me.nosyield = 0
+	me.nsleep = 0
+}
diff --git a/src/runtime/parfor_test.go b/src/runtime/parfor_test.go
index de64285..5d22aec 100644
--- a/src/runtime/parfor_test.go
+++ b/src/runtime/parfor_test.go
@@ -10,11 +10,8 @@ package runtime_test
 import (
 	. "runtime"
 	"testing"
-	"unsafe"
 )
 
-var gdata []uint64
-
 // Simple serial sanity test for parallelfor.
 func TestParFor(t *testing.T) {
 	const P = 1
@@ -24,12 +21,7 @@ func TestParFor(t *testing.T) {
 		data[i] = i
 	}
 	desc := NewParFor(P)
-	// Avoid making func a closure: parfor cannot invoke them.
-	// Since it doesn't happen in the C code, it's not worth doing
-	// just for the test.
-	gdata = data
-	ParForSetup(desc, P, N, nil, true, func(desc *ParFor, i uint32) {
-		data := gdata
+	ParForSetup(desc, P, N, true, func(desc *ParFor, i uint32) {
 		data[i] = data[i]*data[i] + 1
 	})
 	ParForDo(desc)
@@ -49,9 +41,8 @@ func TestParFor2(t *testing.T) {
 		data[i] = i
 	}
 	desc := NewParFor(P)
-	ParForSetup(desc, P, N, (*byte)(unsafe.Pointer(&data)), false, func(desc *ParFor, i uint32) {
-		d := *(*[]uint64)(unsafe.Pointer(desc.Ctx))
-		d[i] = d[i]*d[i] + 1
+	ParForSetup(desc, P, N, false, func(desc *ParFor, i uint32) {
+		data[i] = data[i]*data[i] + 1
 	})
 	for p := 0; p < P; p++ {
 		ParForDo(desc)
@@ -70,7 +61,7 @@ func TestParForSetup(t *testing.T) {
 	desc := NewParFor(P)
 	for n := uint32(0); n < N; n++ {
 		for p := uint32(1); p <= P; p++ {
-			ParForSetup(desc, p, n, nil, true, func(desc *ParFor, i uint32) {})
+			ParForSetup(desc, p, n, true, func(desc *ParFor, i uint32) {})
 			sum := uint32(0)
 			size0 := uint32(0)
 			end0 := uint32(0)
@@ -113,9 +104,7 @@ func TestParForParallel(t *testing.T) {
 	P := GOMAXPROCS(-1)
 	c := make(chan bool, P)
 	desc := NewParFor(uint32(P))
-	gdata = data
-	ParForSetup(desc, uint32(P), uint32(N), nil, false, func(desc *ParFor, i uint32) {
-		data := gdata
+	ParForSetup(desc, uint32(P), uint32(N), false, func(desc *ParFor, i uint32) {
 		data[i] = data[i]*data[i] + 1
 	})
 	for p := 1; p < P; p++ {
diff --git a/src/runtime/pprof/pprof.go b/src/runtime/pprof/pprof.go
index 236de54..23fc850 100644
--- a/src/runtime/pprof/pprof.go
+++ b/src/runtime/pprof/pprof.go
@@ -21,7 +21,7 @@ import (
 )
 
 // BUG(rsc): Profiles are incomplete and inaccurate on NetBSD and OS X.
-// See http://golang.org/issue/6047 for details.
+// See https://golang.org/issue/6047 for details.
 
 // A Profile is a collection of stack traces showing the call sequences
 // that led to instances of a particular event, such as allocation.
@@ -41,6 +41,13 @@ import (
 // These predefined profiles maintain themselves and panic on an explicit
 // Add or Remove method call.
 //
+// The heap profile reports statistics as of the most recently completed
+// garbage collection; it elides more recent allocation to avoid skewing
+// the profile away from live data and toward garbage.
+// If there has been no garbage collection at all, the heap profile reports
+// all known allocations. This exception helps mainly in programs running
+// without garbage collection enabled, usually for debugging purposes.
+//
 // The CPU profile is not available as a Profile.  It has a special API,
 // the StartCPUProfile and StopCPUProfile functions, because it streams
 // output to a writer during profiling.
@@ -442,35 +449,33 @@ func writeHeap(w io.Writer, debug int) error {
 
 	// Print memstats information too.
 	// Pprof will ignore, but useful for people
-	if debug > 0 {
-		s := new(runtime.MemStats)
-		runtime.ReadMemStats(s)
-		fmt.Fprintf(w, "\n# runtime.MemStats\n")
-		fmt.Fprintf(w, "# Alloc = %d\n", s.Alloc)
-		fmt.Fprintf(w, "# TotalAlloc = %d\n", s.TotalAlloc)
-		fmt.Fprintf(w, "# Sys = %d\n", s.Sys)
-		fmt.Fprintf(w, "# Lookups = %d\n", s.Lookups)
-		fmt.Fprintf(w, "# Mallocs = %d\n", s.Mallocs)
-		fmt.Fprintf(w, "# Frees = %d\n", s.Frees)
-
-		fmt.Fprintf(w, "# HeapAlloc = %d\n", s.HeapAlloc)
-		fmt.Fprintf(w, "# HeapSys = %d\n", s.HeapSys)
-		fmt.Fprintf(w, "# HeapIdle = %d\n", s.HeapIdle)
-		fmt.Fprintf(w, "# HeapInuse = %d\n", s.HeapInuse)
-		fmt.Fprintf(w, "# HeapReleased = %d\n", s.HeapReleased)
-		fmt.Fprintf(w, "# HeapObjects = %d\n", s.HeapObjects)
-
-		fmt.Fprintf(w, "# Stack = %d / %d\n", s.StackInuse, s.StackSys)
-		fmt.Fprintf(w, "# MSpan = %d / %d\n", s.MSpanInuse, s.MSpanSys)
-		fmt.Fprintf(w, "# MCache = %d / %d\n", s.MCacheInuse, s.MCacheSys)
-		fmt.Fprintf(w, "# BuckHashSys = %d\n", s.BuckHashSys)
-
-		fmt.Fprintf(w, "# NextGC = %d\n", s.NextGC)
-		fmt.Fprintf(w, "# PauseNs = %d\n", s.PauseNs)
-		fmt.Fprintf(w, "# NumGC = %d\n", s.NumGC)
-		fmt.Fprintf(w, "# EnableGC = %v\n", s.EnableGC)
-		fmt.Fprintf(w, "# DebugGC = %v\n", s.DebugGC)
-	}
+	s := new(runtime.MemStats)
+	runtime.ReadMemStats(s)
+	fmt.Fprintf(w, "\n# runtime.MemStats\n")
+	fmt.Fprintf(w, "# Alloc = %d\n", s.Alloc)
+	fmt.Fprintf(w, "# TotalAlloc = %d\n", s.TotalAlloc)
+	fmt.Fprintf(w, "# Sys = %d\n", s.Sys)
+	fmt.Fprintf(w, "# Lookups = %d\n", s.Lookups)
+	fmt.Fprintf(w, "# Mallocs = %d\n", s.Mallocs)
+	fmt.Fprintf(w, "# Frees = %d\n", s.Frees)
+
+	fmt.Fprintf(w, "# HeapAlloc = %d\n", s.HeapAlloc)
+	fmt.Fprintf(w, "# HeapSys = %d\n", s.HeapSys)
+	fmt.Fprintf(w, "# HeapIdle = %d\n", s.HeapIdle)
+	fmt.Fprintf(w, "# HeapInuse = %d\n", s.HeapInuse)
+	fmt.Fprintf(w, "# HeapReleased = %d\n", s.HeapReleased)
+	fmt.Fprintf(w, "# HeapObjects = %d\n", s.HeapObjects)
+
+	fmt.Fprintf(w, "# Stack = %d / %d\n", s.StackInuse, s.StackSys)
+	fmt.Fprintf(w, "# MSpan = %d / %d\n", s.MSpanInuse, s.MSpanSys)
+	fmt.Fprintf(w, "# MCache = %d / %d\n", s.MCacheInuse, s.MCacheSys)
+	fmt.Fprintf(w, "# BuckHashSys = %d\n", s.BuckHashSys)
+
+	fmt.Fprintf(w, "# NextGC = %d\n", s.NextGC)
+	fmt.Fprintf(w, "# PauseNs = %d\n", s.PauseNs)
+	fmt.Fprintf(w, "# NumGC = %d\n", s.NumGC)
+	fmt.Fprintf(w, "# EnableGC = %v\n", s.EnableGC)
+	fmt.Fprintf(w, "# DebugGC = %v\n", s.DebugGC)
 
 	if tw != nil {
 		tw.Flush()
diff --git a/src/runtime/pprof/pprof_test.go b/src/runtime/pprof/pprof_test.go
index 8677cb3..785d75a 100644
--- a/src/runtime/pprof/pprof_test.go
+++ b/src/runtime/pprof/pprof_test.go
@@ -9,7 +9,9 @@ package pprof_test
 import (
 	"bytes"
 	"fmt"
+	"internal/testenv"
 	"math/big"
+	"os"
 	"os/exec"
 	"regexp"
 	"runtime"
@@ -121,15 +123,19 @@ func parseProfile(t *testing.T, bytes []byte, f func(uintptr, []uintptr)) {
 func testCPUProfile(t *testing.T, need []string, f func()) {
 	switch runtime.GOOS {
 	case "darwin":
-		out, err := exec.Command("uname", "-a").CombinedOutput()
-		if err != nil {
-			t.Fatal(err)
+		switch runtime.GOARCH {
+		case "arm", "arm64":
+			// nothing
+		default:
+			out, err := exec.Command("uname", "-a").CombinedOutput()
+			if err != nil {
+				t.Fatal(err)
+			}
+			vers := string(out)
+			t.Logf("uname -a: %v", vers)
 		}
-		vers := string(out)
-		t.Logf("uname -a: %v", vers)
 	case "plan9":
-		// unimplemented
-		return
+		t.Skip("skipping on plan9")
 	}
 
 	var prof bytes.Buffer
@@ -141,7 +147,9 @@ func testCPUProfile(t *testing.T, need []string, f func()) {
 
 	// 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 {
@@ -154,6 +162,14 @@ func testCPUProfile(t *testing.T, need []string, f func()) {
 			}
 		}
 	})
+	t.Logf("total %d CPU profile samples collected", samples)
+
+	if samples < 10 && runtime.GOOS == "windows" {
+		// On some windows machines we end up with
+		// not enough samples due to coarse timer
+		// resolution. Let it go.
+		t.Skip("too few samples on Windows (golang.org/issue/10842)")
+	}
 
 	if len(need) == 0 {
 		return
@@ -186,14 +202,28 @@ func testCPUProfile(t *testing.T, need []string, f func()) {
 			t.Skipf("ignoring failure on %s; see golang.org/issue/6047", runtime.GOOS)
 			return
 		}
+		// Ignore the failure if the tests are running in a QEMU-based emulator,
+		// QEMU is not perfect at emulating everything.
+		// IN_QEMU environmental variable is set by some of the Go builders.
+		// IN_QEMU=1 indicates that the tests are running in QEMU. See issue 9605.
+		if os.Getenv("IN_QEMU") == "1" {
+			t.Skip("ignore the failure in QEMU; see golang.org/issue/9605")
+			return
+		}
 		t.FailNow()
 	}
 }
 
+// Fork can hang if preempted with signals frequently enough (see issue 5517).
+// Ensure that we do not do this.
 func TestCPUProfileWithFork(t *testing.T) {
-	// Fork can hang if preempted with signals frequently enough (see issue 5517).
-	// Ensure that we do not do this.
+	testenv.MustHaveExec(t)
+
 	heap := 1 << 30
+	if runtime.GOOS == "android" {
+		// Use smaller size for Android to avoid crash.
+		heap = 100 << 20
+	}
 	if testing.Short() {
 		heap = 100 << 20
 	}
@@ -216,7 +246,7 @@ func TestCPUProfileWithFork(t *testing.T) {
 	defer StopCPUProfile()
 
 	for i := 0; i < 10; i++ {
-		exec.Command("go").CombinedOutput()
+		exec.Command(os.Args[0], "-h").CombinedOutput()
 	}
 }
 
@@ -249,7 +279,7 @@ func TestGoroutineSwitch(t *testing.T) {
 			// exists to record a PC without a traceback. Those are okay.
 			if len(stk) == 2 {
 				f := runtime.FuncForPC(stk[1])
-				if f != nil && (f.Name() == "System" || f.Name() == "ExternalCode" || f.Name() == "GC") {
+				if f != nil && (f.Name() == "runtime._System" || f.Name() == "runtime._ExternalCode" || f.Name() == "runtime._GC") {
 					return
 				}
 			}
@@ -366,7 +396,7 @@ func TestBlockProfile(t *testing.T) {
 	}
 
 	for _, test := range tests {
-		if !regexp.MustCompile(test.re).MatchString(prof) {
+		if !regexp.MustCompile(strings.Replace(test.re, "\t", "\t+", -1)).MatchString(prof) {
 			t.Fatalf("Bad %v entry, expect:\n%v\ngot:\n%v", test.name, test.re, prof)
 		}
 	}
diff --git a/src/runtime/print1.go b/src/runtime/print1.go
index 8f82688..6eff381 100644
--- a/src/runtime/print1.go
+++ b/src/runtime/print1.go
@@ -13,35 +13,39 @@ type hex uint64
 func bytes(s string) (ret []byte) {
 	rp := (*slice)(unsafe.Pointer(&ret))
 	sp := (*_string)(noescape(unsafe.Pointer(&s)))
-	rp.array = sp.str
-	rp.len = uint(sp.len)
-	rp.cap = uint(sp.len)
+	rp.array = unsafe.Pointer(sp.str)
+	rp.len = sp.len
+	rp.cap = sp.len
 	return
 }
 
-// printf is only called from C code. It has no type information for the args,
-// but C stacks are ignored by the garbage collector anyway, so having
-// type information would not add anything.
-//go:nosplit
-func printf(s *byte) {
-	vprintf(gostringnocopy(s), add(unsafe.Pointer(&s), unsafe.Sizeof(s)))
-}
+var debuglock mutex
 
-// sprintf is only called from C code. It has no type information for the args,
-// but C stacks are ignored by the garbage collector anyway, so having
-// type information would not add anything.
-//go:nosplit
-func snprintf(dst *byte, n int32, s *byte) {
-	buf := (*[1 << 30]byte)(unsafe.Pointer(dst))[0:n:n]
+// The compiler emits calls to printlock and printunlock around
+// the multiple calls that implement a single Go print or println
+// statement. Some of the print helpers (printsp, for example)
+// call print recursively. There is also the problem of a crash
+// happening during the print routines and needing to acquire
+// the print lock to print information about the crash.
+// For both these reasons, let a thread acquire the printlock 'recursively'.
 
-	gp := getg()
-	gp.writebuf = buf[0:0 : n-1] // leave room for NUL, this is called from C
-	vprintf(gostringnocopy(s), add(unsafe.Pointer(&s), unsafe.Sizeof(s)))
-	buf[len(gp.writebuf)] = '\x00'
-	gp.writebuf = nil
+func printlock() {
+	mp := getg().m
+	mp.locks++ // do not reschedule between printlock++ and lock(&debuglock).
+	mp.printlock++
+	if mp.printlock == 1 {
+		lock(&debuglock)
+	}
+	mp.locks-- // now we know debuglock is held and holding up mp.locks for us.
 }
 
-//var debuglock mutex
+func printunlock() {
+	mp := getg().m
+	mp.printlock--
+	if mp.printlock == 0 {
+		unlock(&debuglock)
+	}
+}
 
 // write to goroutine-local buffer if diverting output,
 // or else standard error.
@@ -51,7 +55,7 @@ func gwrite(b []byte) {
 	}
 	gp := getg()
 	if gp == nil || gp.writebuf == nil {
-		write(2, unsafe.Pointer(&b[0]), int32(len(b)))
+		writeErr(b)
 		return
 	}
 
@@ -59,16 +63,6 @@ func gwrite(b []byte) {
 	gp.writebuf = gp.writebuf[:len(gp.writebuf)+n]
 }
 
-func prints(s *byte) {
-	b := (*[1 << 30]byte)(unsafe.Pointer(s))
-	for i := 0; ; i++ {
-		if b[i] == 0 {
-			gwrite(b[:i])
-			return
-		}
-	}
-}
-
 func printsp() {
 	print(" ")
 }
@@ -77,92 +71,6 @@ func printnl() {
 	print("\n")
 }
 
-// Very simple printf.  Only for debugging prints.
-// Do not add to this without checking with Rob.
-func vprintf(str string, arg unsafe.Pointer) {
-	//lock(&debuglock);
-
-	s := bytes(str)
-	start := 0
-	i := 0
-	for ; i < len(s); i++ {
-		if s[i] != '%' {
-			continue
-		}
-		if i > start {
-			gwrite(s[start:i])
-		}
-		if i++; i >= len(s) {
-			break
-		}
-		var siz uintptr
-		switch s[i] {
-		case 't', 'c':
-			siz = 1
-		case 'd', 'x': // 32-bit
-			arg = roundup(arg, 4)
-			siz = 4
-		case 'D', 'U', 'X', 'f': // 64-bit
-			arg = roundup(arg, unsafe.Sizeof(uintreg(0)))
-			siz = 8
-		case 'C':
-			arg = roundup(arg, unsafe.Sizeof(uintreg(0)))
-			siz = 16
-		case 'p', 's': // pointer-sized
-			arg = roundup(arg, unsafe.Sizeof(uintptr(0)))
-			siz = unsafe.Sizeof(uintptr(0))
-		case 'S': // pointer-aligned but bigger
-			arg = roundup(arg, unsafe.Sizeof(uintptr(0)))
-			siz = unsafe.Sizeof(string(""))
-		case 'a': // pointer-aligned but bigger
-			arg = roundup(arg, unsafe.Sizeof(uintptr(0)))
-			siz = unsafe.Sizeof([]byte{})
-		case 'i', 'e': // pointer-aligned but bigger
-			arg = roundup(arg, unsafe.Sizeof(uintptr(0)))
-			siz = unsafe.Sizeof(interface{}(nil))
-		}
-		switch s[i] {
-		case 'a':
-			printslice(*(*[]byte)(arg))
-		case 'c':
-			printbyte(*(*byte)(arg))
-		case 'd':
-			printint(int64(*(*int32)(arg)))
-		case 'D':
-			printint(int64(*(*int64)(arg)))
-		case 'e':
-			printeface(*(*interface{})(arg))
-		case 'f':
-			printfloat(*(*float64)(arg))
-		case 'C':
-			printcomplex(*(*complex128)(arg))
-		case 'i':
-			printiface(*(*fInterface)(arg))
-		case 'p':
-			printpointer(*(*unsafe.Pointer)(arg))
-		case 's':
-			prints(*(**byte)(arg))
-		case 'S':
-			printstring(*(*string)(arg))
-		case 't':
-			printbool(*(*bool)(arg))
-		case 'U':
-			printuint(*(*uint64)(arg))
-		case 'x':
-			printhex(uint64(*(*uint32)(arg)))
-		case 'X':
-			printhex(*(*uint64)(arg))
-		}
-		arg = add(arg, siz)
-		start = i + 1
-	}
-	if start < i {
-		gwrite(s[start:i])
-	}
-
-	//unlock(&debuglock);
-}
-
 func printpc(p unsafe.Pointer) {
 	print("PC=", hex(uintptr(p)))
 }
diff --git a/src/runtime/print1_write.go b/src/runtime/print1_write.go
new file mode 100644
index 0000000..6b1467b
--- /dev/null
+++ b/src/runtime/print1_write.go
@@ -0,0 +1,13 @@
+// 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.
+
+// +build !android
+
+package runtime
+
+import "unsafe"
+
+func writeErr(b []byte) {
+	write(2, unsafe.Pointer(&b[0]), int32(len(b)))
+}
diff --git a/src/runtime/print1_write_android.go b/src/runtime/print1_write_android.go
new file mode 100644
index 0000000..54d4826
--- /dev/null
+++ b/src/runtime/print1_write_android.go
@@ -0,0 +1,160 @@
+// 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"
+
+var (
+	writeHeader = []byte{6 /* ANDROID_LOG_ERROR */, 'G', 'o', 0}
+	writePath   = []byte("/dev/log/main\x00")
+	writeLogd   = []byte("/dev/socket/logdw\x00")
+
+	// guarded by printlock/printunlock.
+	writeFD  uintptr
+	writeBuf [1024]byte
+	writePos int
+)
+
+// Prior to Android-L, logging was done through writes to /dev/log files implemented
+// in kernel ring buffers. In Android-L, those /dev/log files are no longer
+// accessible and logging is done through a centralized user-mode logger, logd.
+//
+// https://android.googlesource.com/platform/system/core/+/master/liblog/logd_write.c
+type loggerType int32
+
+const (
+	unknown loggerType = iota
+	legacy
+	logd
+	// TODO(hakim): logging for emulator?
+)
+
+var logger loggerType
+
+func writeErr(b []byte) {
+	if logger == unknown {
+		// Use logd if /dev/socket/logdw is available.
+		if v := uintptr(access(&writeLogd[0], 0x02 /* W_OK */)); v == 0 {
+			logger = logd
+			initLogd()
+		} else {
+			logger = legacy
+			initLegacy()
+		}
+	}
+
+	// Write to stderr for command-line programs.
+	write(2, unsafe.Pointer(&b[0]), int32(len(b)))
+
+	// Log format: "<header>\x00<message m bytes>\x00"
+	//
+	// <header>
+	//   In legacy mode: "<priority 1 byte><tag n bytes>".
+	//   In logd mode: "<android_log_header_t 11 bytes><priority 1 byte><tag n bytes>"
+	//
+	// The entire log needs to be delivered in a single syscall (the NDK
+	// does this with writev). Each log is its own line, so we need to
+	// buffer writes until we see a newline.
+	var hlen int
+	switch logger {
+	case logd:
+		hlen = writeLogdHeader()
+	case legacy:
+		hlen = len(writeHeader)
+	}
+
+	dst := writeBuf[hlen:]
+	for _, v := range b {
+		if v == 0 { // android logging won't print a zero byte
+			v = '0'
+		}
+		dst[writePos] = v
+		writePos++
+		if v == '\n' || writePos == len(dst)-1 {
+			dst[writePos] = 0
+			write(writeFD, unsafe.Pointer(&writeBuf[0]), int32(hlen+writePos))
+			memclrBytes(dst)
+			writePos = 0
+		}
+	}
+}
+
+func initLegacy() {
+	// In legacy mode, logs are written to /dev/log/main
+	writeFD = uintptr(open(&writePath[0], 0x1 /* O_WRONLY */, 0))
+	if writeFD == 0 {
+		// It is hard to do anything here. Write to stderr just
+		// in case user has root on device and has run
+		//	adb shell setprop log.redirect-stdio true
+		msg := []byte("runtime: cannot open /dev/log/main\x00")
+		write(2, unsafe.Pointer(&msg[0]), int32(len(msg)))
+		exit(2)
+	}
+
+	// Prepopulate the invariant header part.
+	copy(writeBuf[:len(writeHeader)], writeHeader)
+}
+
+// used in initLogdWrite but defined here to avoid heap allocation.
+var logdAddr sockaddr_un
+
+func initLogd() {
+	// In logd mode, logs are sent to the logd via a unix domain socket.
+	logdAddr.family = _AF_UNIX
+	copy(logdAddr.path[:], writeLogd)
+
+	// We are not using non-blocking I/O because writes taking this path
+	// are most likely triggered by panic, we cannot think of the advantage of
+	// non-blocking I/O for panic but see disadvantage (dropping panic message),
+	// and blocking I/O simplifies the code a lot.
+	fd := socket(_AF_UNIX, _SOCK_DGRAM|_O_CLOEXEC, 0)
+	if fd < 0 {
+		msg := []byte("runtime: cannot create a socket for logging\x00")
+		write(2, unsafe.Pointer(&msg[0]), int32(len(msg)))
+		exit(2)
+	}
+
+	errno := connect(uintptr(fd), unsafe.Pointer(&logdAddr), int32(unsafe.Sizeof(logdAddr)))
+	if errno < 0 {
+		msg := []byte("runtime: cannot connect to /dev/socket/logdw\x00")
+		write(2, unsafe.Pointer(&msg[0]), int32(len(msg)))
+		// TODO(hakim): or should we just close fd and hope for better luck next time?
+		exit(2)
+	}
+	writeFD = uintptr(fd)
+
+	// Prepopulate invariant part of the header.
+	// The first 11 bytes will be populated later in writeLogdHeader.
+	copy(writeBuf[11:11+len(writeHeader)], writeHeader)
+}
+
+// writeLogdHeader populates the header and returns the length of the payload.
+func writeLogdHeader() int {
+	hdr := writeBuf[:11]
+
+	// The first 11 bytes of the header corresponds to android_log_header_t
+	// as defined in system/core/include/private/android_logger.h
+	//   hdr[0] log type id (unsigned char), defined in <log/log.h>
+	//   hdr[1:2] tid (uint16_t)
+	//   hdr[3:11] log_time defined in <log/log_read.h>
+	//      hdr[3:7] sec unsigned uint32, little endian.
+	//      hdr[7:11] nsec unsigned uint32, little endian.
+	hdr[0] = 0 // LOG_ID_MAIN
+	sec, nsec := time_now()
+	packUint32(hdr[3:7], uint32(sec))
+	packUint32(hdr[7:11], uint32(nsec))
+
+	// TODO(hakim):  hdr[1:2] = gettid?
+
+	return 11 + len(writeHeader)
+}
+
+func packUint32(b []byte, v uint32) {
+	// little-endian.
+	b[0] = byte(v)
+	b[1] = byte(v >> 8)
+	b[2] = byte(v >> 16)
+	b[3] = byte(v >> 24)
+}
diff --git a/src/runtime/proc.c b/src/runtime/proc.c
deleted file mode 100644
index 8462c4b..0000000
--- a/src/runtime/proc.c
+++ /dev/null
@@ -1,3521 +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 "runtime.h"
-#include "arch_GOARCH.h"
-#include "zaexperiment.h"
-#include "malloc.h"
-#include "stack.h"
-#include "race.h"
-#include "type.h"
-#include "mgc0.h"
-#include "textflag.h"
-
-// Goroutine scheduler
-// The scheduler's job is to distribute ready-to-run goroutines over worker threads.
-//
-// The main concepts are:
-// G - goroutine.
-// M - worker thread, or machine.
-// P - processor, a resource that is required to execute Go code.
-//     M must have an associated P to execute Go code, however it can be
-//     blocked or in a syscall w/o an associated P.
-//
-// Design doc at http://golang.org/s/go11sched.
-
-enum
-{
-	// Number of goroutine ids to grab from runtime·sched.goidgen to local per-P cache at once.
-	// 16 seems to provide enough amortization, but other than that it's mostly arbitrary number.
-	GoidCacheBatch = 16,
-};
-
-SchedT	runtime·sched;
-int32	runtime·gomaxprocs;
-uint32	runtime·needextram;
-bool	runtime·iscgo;
-M	runtime·m0;
-G	runtime·g0;	// idle goroutine for m0
-G*	runtime·lastg;
-M*	runtime·allm;
-M*	runtime·extram;
-P*	runtime·allp[MaxGomaxprocs+1];
-int8*	runtime·goos;
-int32	runtime·ncpu;
-int32	runtime·newprocs;
-
-Mutex runtime·allglock;	// the following vars are protected by this lock or by stoptheworld
-G**	runtime·allg;
-Slice	runtime·allgs;
-uintptr runtime·allglen;
-ForceGCState	runtime·forcegc;
-
-void runtime·mstart(void);
-static void runqput(P*, G*);
-static G* runqget(P*);
-static bool runqputslow(P*, G*, uint32, uint32);
-static G* runqsteal(P*, P*);
-static void mput(M*);
-static M* mget(void);
-static void mcommoninit(M*);
-static void schedule(void);
-static void procresize(int32);
-static void acquirep(P*);
-static P* releasep(void);
-static void newm(void(*)(void), P*);
-static void stopm(void);
-static void startm(P*, bool);
-static void handoffp(P*);
-static void wakep(void);
-static void stoplockedm(void);
-static void startlockedm(G*);
-static void sysmon(void);
-static uint32 retake(int64);
-static void incidlelocked(int32);
-static void checkdead(void);
-static void exitsyscall0(G*);
-void runtime·park_m(G*);
-static void goexit0(G*);
-static void gfput(P*, G*);
-static G* gfget(P*);
-static void gfpurge(P*);
-static void globrunqput(G*);
-static void globrunqputbatch(G*, G*, int32);
-static G* globrunqget(P*, int32);
-static P* pidleget(void);
-static void pidleput(P*);
-static void injectglist(G*);
-static bool preemptall(void);
-static bool preemptone(P*);
-static bool exitsyscallfast(void);
-static bool haveexperiment(int8*);
-void runtime·allgadd(G*);
-static void dropg(void);
-
-extern String runtime·buildVersion;
-
-// For cgo-using programs with external linking,
-// export "main" (defined in assembly) so that libc can handle basic
-// C runtime startup and call the Go program as if it were
-// the C main function.
-#pragma cgo_export_static main
-
-// Filled in by dynamic linker when Cgo is available.
-void (*_cgo_init)(void);
-void (*_cgo_malloc)(void);
-void (*_cgo_free)(void);
-
-// Copy for Go code.
-void* runtime·cgoMalloc;
-void* runtime·cgoFree;
-
-// The bootstrap sequence is:
-//
-//	call osinit
-//	call schedinit
-//	make & queue new G
-//	call runtime·mstart
-//
-// The new G calls runtime·main.
-void
-runtime·schedinit(void)
-{
-	int32 n, procs;
-	byte *p;
-
-	// raceinit must be the first call to race detector.
-	// In particular, it must be done before mallocinit below calls racemapshadow.
-	if(raceenabled)
-		g->racectx = runtime·raceinit();
-
-	runtime·sched.maxmcount = 10000;
-
-	runtime·tracebackinit();
-	runtime·symtabinit();
-	runtime·stackinit();
-	runtime·mallocinit();
-	mcommoninit(g->m);
-	
-	runtime·goargs();
-	runtime·goenvs();
-	runtime·parsedebugvars();
-	runtime·gcinit();
-
-	runtime·sched.lastpoll = runtime·nanotime();
-	procs = 1;
-	p = runtime·getenv("GOMAXPROCS");
-	if(p != nil && (n = runtime·atoi(p)) > 0) {
-		if(n > MaxGomaxprocs)
-			n = MaxGomaxprocs;
-		procs = n;
-	}
-	procresize(procs);
-
-	if(runtime·buildVersion.str == nil) {
-		// Condition should never trigger.  This code just serves
-		// to ensure runtime·buildVersion is kept in the resulting binary.
-		runtime·buildVersion.str = (uint8*)"unknown";
-		runtime·buildVersion.len = 7;
-	}
-
-	runtime·cgoMalloc = _cgo_malloc;
-	runtime·cgoFree = _cgo_free;
-}
-
-void
-runtime·newsysmon(void)
-{
-	newm(sysmon, nil);
-}
-
-static void
-dumpgstatus(G* gp)
-{
-	runtime·printf("runtime: gp: gp=%p, goid=%D, gp->atomicstatus=%x\n", gp, gp->goid, runtime·readgstatus(gp));
-	runtime·printf("runtime:  g:  g=%p, goid=%D,  g->atomicstatus=%x\n", g, g->goid, runtime·readgstatus(g));
-}
-
-static void
-checkmcount(void)
-{
-	// sched lock is held
-	if(runtime·sched.mcount > runtime·sched.maxmcount){
-		runtime·printf("runtime: program exceeds %d-thread limit\n", runtime·sched.maxmcount);
-		runtime·throw("thread exhaustion");
-	}
-}
-
-static void
-mcommoninit(M *mp)
-{
-	// g0 stack won't make sense for user (and is not necessary unwindable).
-	if(g != g->m->g0)
-		runtime·callers(1, mp->createstack, nelem(mp->createstack));
-
-	mp->fastrand = 0x49f6428aUL + mp->id + runtime·cputicks();
-
-	runtime·lock(&runtime·sched.lock);
-	mp->id = runtime·sched.mcount++;
-	checkmcount();
-	runtime·mpreinit(mp);
-	if(mp->gsignal)
-		mp->gsignal->stackguard1 = mp->gsignal->stack.lo + StackGuard;
-
-	// Add to runtime·allm so garbage collector doesn't free g->m
-	// when it is just in a register or thread-local storage.
-	mp->alllink = runtime·allm;
-	// runtime·NumCgoCall() iterates over allm w/o schedlock,
-	// so we need to publish it safely.
-	runtime·atomicstorep(&runtime·allm, mp);
-	runtime·unlock(&runtime·sched.lock);
-}
-
-// Mark gp ready to run.
-void
-runtime·ready(G *gp)
-{
-	uint32 status;
-
-	status = runtime·readgstatus(gp);
-	// Mark runnable.
-	g->m->locks++;  // disable preemption because it can be holding p in a local var
-	if((status&~Gscan) != Gwaiting){
-		dumpgstatus(gp);
-		runtime·throw("bad g->status in ready");
-	}
-	// status is Gwaiting or Gscanwaiting, make Grunnable and put on runq
-	runtime·casgstatus(gp, Gwaiting, Grunnable);
-	runqput(g->m->p, gp);
-	if(runtime·atomicload(&runtime·sched.npidle) != 0 && runtime·atomicload(&runtime·sched.nmspinning) == 0)  // TODO: fast atomic
-		wakep();
-	g->m->locks--;
-	if(g->m->locks == 0 && g->preempt)  // restore the preemption request in case we've cleared it in newstack
-		g->stackguard0 = StackPreempt;
-}
-
-void
-runtime·ready_m(void)
-{
-	G *gp;
-
-	gp = g->m->ptrarg[0];
-	g->m->ptrarg[0] = nil;
-	runtime·ready(gp);
-}
-
-int32
-runtime·gcprocs(void)
-{
-	int32 n;
-
-	// Figure out how many CPUs to use during GC.
-	// Limited by gomaxprocs, number of actual CPUs, and MaxGcproc.
-	runtime·lock(&runtime·sched.lock);
-	n = runtime·gomaxprocs;
-	if(n > runtime·ncpu)
-		n = runtime·ncpu;
-	if(n > MaxGcproc)
-		n = MaxGcproc;
-	if(n > runtime·sched.nmidle+1) // one M is currently running
-		n = runtime·sched.nmidle+1;
-	runtime·unlock(&runtime·sched.lock);
-	return n;
-}
-
-static bool
-needaddgcproc(void)
-{
-	int32 n;
-
-	runtime·lock(&runtime·sched.lock);
-	n = runtime·gomaxprocs;
-	if(n > runtime·ncpu)
-		n = runtime·ncpu;
-	if(n > MaxGcproc)
-		n = MaxGcproc;
-	n -= runtime·sched.nmidle+1; // one M is currently running
-	runtime·unlock(&runtime·sched.lock);
-	return n > 0;
-}
-
-void
-runtime·helpgc(int32 nproc)
-{
-	M *mp;
-	int32 n, pos;
-
-	runtime·lock(&runtime·sched.lock);
-	pos = 0;
-	for(n = 1; n < nproc; n++) {  // one M is currently running
-		if(runtime·allp[pos]->mcache == g->m->mcache)
-			pos++;
-		mp = mget();
-		if(mp == nil)
-			runtime·throw("runtime·gcprocs inconsistency");
-		mp->helpgc = n;
-		mp->mcache = runtime·allp[pos]->mcache;
-		pos++;
-		runtime·notewakeup(&mp->park);
-	}
-	runtime·unlock(&runtime·sched.lock);
-}
-
-// Similar to stoptheworld but best-effort and can be called several times.
-// There is no reverse operation, used during crashing.
-// This function must not lock any mutexes.
-void
-runtime·freezetheworld(void)
-{
-	int32 i;
-
-	if(runtime·gomaxprocs == 1)
-		return;
-	// stopwait and preemption requests can be lost
-	// due to races with concurrently executing threads,
-	// so try several times
-	for(i = 0; i < 5; i++) {
-		// this should tell the scheduler to not start any new goroutines
-		runtime·sched.stopwait = 0x7fffffff;
-		runtime·atomicstore((uint32*)&runtime·sched.gcwaiting, 1);
-		// this should stop running goroutines
-		if(!preemptall())
-			break;  // no running goroutines
-		runtime·usleep(1000);
-	}
-	// to be sure
-	runtime·usleep(1000);
-	preemptall();
-	runtime·usleep(1000);
-}
-
-static bool
-isscanstatus(uint32 status)
-{
-	if(status == Gscan)
-		runtime·throw("isscanstatus: Bad status Gscan");
-	return (status&Gscan) == Gscan;
-}
-
-// All reads and writes of g's status go through readgstatus, casgstatus
-// castogscanstatus, casfromgscanstatus.
-#pragma textflag NOSPLIT
-uint32
-runtime·readgstatus(G *gp)
-{
-	return runtime·atomicload(&gp->atomicstatus);
-}
-
-// The Gscanstatuses are acting like locks and this releases them.
-// If it proves to be a performance hit we should be able to make these
-// simple atomic stores but for now we are going to throw if
-// we see an inconsistent state.
-void
-runtime·casfromgscanstatus(G *gp, uint32 oldval, uint32 newval)
-{
-	bool success = false;
-
-	// Check that transition is valid.
-	switch(oldval) {
-	case Gscanrunnable:
-	case Gscanwaiting:
-	case Gscanrunning:
-	case Gscansyscall:
-		if(newval == (oldval&~Gscan))
-			success = runtime·cas(&gp->atomicstatus, oldval, newval);
-		break;
-	case Gscanenqueue:
-		if(newval == Gwaiting)
-			success = runtime·cas(&gp->atomicstatus, oldval, newval);
-		break;
-	}	
-	if(!success){
-		runtime·printf("runtime: casfromgscanstatus failed gp=%p, oldval=%d, newval=%d\n",  
-			gp, oldval, newval);
-		dumpgstatus(gp);
-		runtime·throw("casfromgscanstatus: gp->status is not in scan state");
-	}
-}
-
-// This will return false if the gp is not in the expected status and the cas fails. 
-// This acts like a lock acquire while the casfromgstatus acts like a lock release.
-bool
-runtime·castogscanstatus(G *gp, uint32 oldval, uint32 newval)
-{
-	switch(oldval) {
-	case Grunnable:
-	case Gwaiting:
-	case Gsyscall:
-		if(newval == (oldval|Gscan))
-			return runtime·cas(&gp->atomicstatus, oldval, newval);
-		break;
-	case Grunning:
-		if(newval == Gscanrunning || newval == Gscanenqueue)
-			return runtime·cas(&gp->atomicstatus, oldval, newval);
-		break;   
-	}
-
-	runtime·printf("runtime: castogscanstatus oldval=%d newval=%d\n", oldval, newval);
-	runtime·throw("castogscanstatus");
-	return false; // not reached
-}
-
-static void badcasgstatus(void);
-static void helpcasgstatus(void);
-static void badgstatusrunnable(void);
-
-// If asked to move to or from a Gscanstatus this will throw. Use the castogscanstatus
-// and casfromgscanstatus instead.
-// casgstatus will loop if the g->atomicstatus is in a Gscan status until the routine that 
-// put it in the Gscan state is finished.
-#pragma textflag NOSPLIT
-void
-runtime·casgstatus(G *gp, uint32 oldval, uint32 newval)
-{
-	void (*fn)(void);
-
-	if((oldval&Gscan) || (newval&Gscan) || oldval == newval) {
-		g->m->scalararg[0] = oldval;
-		g->m->scalararg[1] = newval;
-		fn = badcasgstatus;
-		runtime·onM(&fn);
-	}
-
-	// loop if gp->atomicstatus is in a scan state giving
-	// GC time to finish and change the state to oldval.
-	while(!runtime·cas(&gp->atomicstatus, oldval, newval)) {
-		if(oldval == Gwaiting && gp->atomicstatus == Grunnable) {
-			fn = badgstatusrunnable;
-			runtime·onM(&fn);
-		}
-		// Help GC if needed. 
-		if(gp->preemptscan && !gp->gcworkdone && (oldval == Grunning || oldval == Gsyscall)) {
-			gp->preemptscan = false;
-			g->m->ptrarg[0] = gp;
-			fn = helpcasgstatus;
-			runtime·onM(&fn);
-		}
-	}	
-}
-
-static void
-badgstatusrunnable(void)
-{
-	runtime·throw("casgstatus: waiting for Gwaiting but is Grunnable");
-}
-
-// casgstatus(gp, oldstatus, Gcopystack), assuming oldstatus is Gwaiting or Grunnable.
-// Returns old status. Cannot call casgstatus directly, because we are racing with an
-// async wakeup that might come in from netpoll. If we see Gwaiting from the readgstatus,
-// it might have become Grunnable by the time we get to the cas. If we called casgstatus,
-// it would loop waiting for the status to go back to Gwaiting, which it never will.
-#pragma textflag NOSPLIT
-uint32
-runtime·casgcopystack(G *gp)
-{
-	uint32 oldstatus;
-
-	for(;;) {
-		oldstatus = runtime·readgstatus(gp) & ~Gscan;
-		if(oldstatus != Gwaiting && oldstatus != Grunnable)
-			runtime·throw("copystack: bad status, not Gwaiting or Grunnable");
-		if(runtime·cas(&gp->atomicstatus, oldstatus, Gcopystack))
-			break;
-	}
-	return oldstatus;
-}
-
-static void
-badcasgstatus(void)
-{
-	uint32 oldval, newval;
-	
-	oldval = g->m->scalararg[0];
-	newval = g->m->scalararg[1];
-	g->m->scalararg[0] = 0;
-	g->m->scalararg[1] = 0;
-
-	runtime·printf("casgstatus: oldval=%d, newval=%d\n", oldval, newval);
-	runtime·throw("casgstatus: bad incoming values");
-}
-
-static void
-helpcasgstatus(void)
-{
-	G *gp;
-	
-	gp = g->m->ptrarg[0];
-	g->m->ptrarg[0] = 0;
-	runtime·gcphasework(gp);
-}
-
-// stopg ensures that gp is stopped at a GC safe point where its stack can be scanned
-// or in the context of a moving collector the pointers can be flipped from pointing 
-// to old object to pointing to new objects. 
-// If stopg returns true, the caller knows gp is at a GC safe point and will remain there until
-// the caller calls restartg.
-// If stopg returns false, the caller is not responsible for calling restartg. This can happen
-// if another thread, either the gp itself or another GC thread is taking the responsibility 
-// to do the GC work related to this thread.
-bool
-runtime·stopg(G *gp)
-{
-	uint32 s;
-
-	for(;;) {
-		if(gp->gcworkdone)
-			return false;
-
-		s = runtime·readgstatus(gp);
-		switch(s) {
-		default:
-			dumpgstatus(gp);
-			runtime·throw("stopg: gp->atomicstatus is not valid");
-
-		case Gdead:
-			return false;
-
-		case Gcopystack:
-			// Loop until a new stack is in place.
-			break;
-
-		case Grunnable:
-		case Gsyscall:
-		case Gwaiting:
-			// Claim goroutine by setting scan bit.
-			if(!runtime·castogscanstatus(gp, s, s|Gscan))
-				break;
-			// In scan state, do work.
-			runtime·gcphasework(gp);
-			return true;
-
-		case Gscanrunnable:
-		case Gscanwaiting:
-		case Gscansyscall:
-			// Goroutine already claimed by another GC helper.
-			return false;
-
-		case Grunning:
-			// Claim goroutine, so we aren't racing with a status
-			// transition away from Grunning.
-			if(!runtime·castogscanstatus(gp, Grunning, Gscanrunning))
-				break;
-
-			// Mark gp for preemption.
-			if(!gp->gcworkdone) {
-				gp->preemptscan = true;
-				gp->preempt = true;
-				gp->stackguard0 = StackPreempt;
-			}
-
-			// Unclaim.
-			runtime·casfromgscanstatus(gp, Gscanrunning, Grunning);
-			return false;
-		}
-	}
-	// Should not be here....
-}
-
-// The GC requests that this routine be moved from a scanmumble state to a mumble state.
-void 
-runtime·restartg (G *gp)
-{
-	uint32 s;
-
-	s = runtime·readgstatus(gp);
-	switch(s) {
-	default:
-		dumpgstatus(gp); 
-		runtime·throw("restartg: unexpected status");
-
-	case Gdead:
-		break;
-
-	case Gscanrunnable:
-	case Gscanwaiting:
-	case Gscansyscall:
-		runtime·casfromgscanstatus(gp, s, s&~Gscan);
-		break;
-
-	case Gscanenqueue:
-		// Scan is now completed.
-		// Goroutine now needs to be made runnable.
-		// We put it on the global run queue; ready blocks on the global scheduler lock.
-		runtime·casfromgscanstatus(gp, Gscanenqueue, Gwaiting);
-		if(gp != g->m->curg)
-			runtime·throw("processing Gscanenqueue on wrong m");
-		dropg();
-		runtime·ready(gp);
-		break;
-	}
-}
-
-static void
-stopscanstart(G* gp)
-{
-	if(g == gp)
-		runtime·throw("GC not moved to G0");
-	if(runtime·stopg(gp)) {
-		if(!isscanstatus(runtime·readgstatus(gp))) {
-			dumpgstatus(gp);
-			runtime·throw("GC not in scan state");
-		}
-		runtime·restartg(gp);
-	}
-}
-
-// Runs on g0 and does the actual work after putting the g back on the run queue.
-static void
-mquiesce(G *gpmaster)
-{
-	G* gp;
-	uint32 i;
-	uint32 status;
-	uint32 activeglen;
-
-	activeglen = runtime·allglen;
-	// enqueue the calling goroutine.
-	runtime·restartg(gpmaster);
-	for(i = 0; i < activeglen; i++) {
-		gp = runtime·allg[i];
-		if(runtime·readgstatus(gp) == Gdead) 
-			gp->gcworkdone = true; // noop scan.
-		else 
-			gp->gcworkdone = false; 
-		stopscanstart(gp); 
-	}
-
-	// Check that the G's gcwork (such as scanning) has been done. If not do it now. 
-	// You can end up doing work here if the page trap on a Grunning Goroutine has
-	// not been sprung or in some race situations. For example a runnable goes dead
-	// and is started up again with a gp->gcworkdone set to false.
-	for(i = 0; i < activeglen; i++) {
-		gp = runtime·allg[i];
-		while (!gp->gcworkdone) {
-			status = runtime·readgstatus(gp);
-			if(status == Gdead) {
-				gp->gcworkdone = true; // scan is a noop
-				break;
-				//do nothing, scan not needed. 
-			}
-			if(status == Grunning && gp->stackguard0 == (uintptr)StackPreempt && runtime·notetsleep(&runtime·sched.stopnote, 100*1000)) // nanosecond arg 
-				runtime·noteclear(&runtime·sched.stopnote);
-			else 
-				stopscanstart(gp);
-		}
-	}
-
-	for(i = 0; i < activeglen; i++) {
-		gp = runtime·allg[i];
-		status = runtime·readgstatus(gp);
-		if(isscanstatus(status)) {
-			runtime·printf("mstopandscang:bottom: post scan bad status gp=%p has status %x\n", gp, status);
-			dumpgstatus(gp);
-		}
-		if(!gp->gcworkdone && status != Gdead) {
-			runtime·printf("mstopandscang:bottom: post scan gp=%p->gcworkdone still false\n", gp);
-			dumpgstatus(gp);
-		}
-	}
-
-	schedule(); // Never returns.
-}
-
-// quiesce moves all the goroutines to a GC safepoint which for now is a at preemption point.
-// If the global runtime·gcphase is GCmark quiesce will ensure that all of the goroutine's stacks
-// have been scanned before it returns.
-void
-runtime·quiesce(G* mastergp)
-{
-	void (*fn)(G*);
-
-	runtime·castogscanstatus(mastergp, Grunning, Gscanenqueue);
-	// Now move this to the g0 (aka m) stack.
-	// g0 will potentially scan this thread and put mastergp on the runqueue 
-	fn = mquiesce;
-	runtime·mcall(&fn);
-}
-
-// This is used by the GC as well as the routines that do stack dumps. In the case
-// of GC all the routines can be reliably stopped. This is not always the case
-// when the system is in panic or being exited.
-void
-runtime·stoptheworld(void)
-{
-	int32 i;
-	uint32 s;
-	P *p;
-	bool wait;
-
-	// If we hold a lock, then we won't be able to stop another M
-	// that is blocked trying to acquire the lock.
-	if(g->m->locks > 0)
-		runtime·throw("stoptheworld: holding locks");
-
-	runtime·lock(&runtime·sched.lock);
-	runtime·sched.stopwait = runtime·gomaxprocs;
-	runtime·atomicstore((uint32*)&runtime·sched.gcwaiting, 1);
-	preemptall();
-	// stop current P
-	g->m->p->status = Pgcstop; // Pgcstop is only diagnostic.
-	runtime·sched.stopwait--;
-	// try to retake all P's in Psyscall status
-	for(i = 0; i < runtime·gomaxprocs; i++) {
-		p = runtime·allp[i];
-		s = p->status;
-		if(s == Psyscall && runtime·cas(&p->status, s, Pgcstop))
-			runtime·sched.stopwait--;
-	}
-	// stop idle P's
-	while(p = pidleget()) {
-		p->status = Pgcstop;
-		runtime·sched.stopwait--;
-	}
-	wait = runtime·sched.stopwait > 0;
-	runtime·unlock(&runtime·sched.lock);
-
-	// wait for remaining P's to stop voluntarily
-	if(wait) {
-		for(;;) {
-			// wait for 100us, then try to re-preempt in case of any races
-			if(runtime·notetsleep(&runtime·sched.stopnote, 100*1000)) {
-				runtime·noteclear(&runtime·sched.stopnote);
-				break;
-			}
-			preemptall();
-		}
-	}
-	if(runtime·sched.stopwait)
-		runtime·throw("stoptheworld: not stopped");
-	for(i = 0; i < runtime·gomaxprocs; i++) {
-		p = runtime·allp[i];
-		if(p->status != Pgcstop)
-			runtime·throw("stoptheworld: not stopped");
-	}
-}
-
-static void
-mhelpgc(void)
-{
-	g->m->helpgc = -1;
-}
-
-void
-runtime·starttheworld(void)
-{
-	P *p, *p1;
-	M *mp;
-	G *gp;
-	bool add;
-
-	g->m->locks++;  // disable preemption because it can be holding p in a local var
-	gp = runtime·netpoll(false);  // non-blocking
-	injectglist(gp);
-	add = needaddgcproc();
-	runtime·lock(&runtime·sched.lock);
-	if(runtime·newprocs) {
-		procresize(runtime·newprocs);
-		runtime·newprocs = 0;
-	} else
-		procresize(runtime·gomaxprocs);
-	runtime·sched.gcwaiting = 0;
-
-	p1 = nil;
-	while(p = pidleget()) {
-		// procresize() puts p's with work at the beginning of the list.
-		// Once we reach a p without a run queue, the rest don't have one either.
-		if(p->runqhead == p->runqtail) {
-			pidleput(p);
-			break;
-		}
-		p->m = mget();
-		p->link = p1;
-		p1 = p;
-	}
-	if(runtime·sched.sysmonwait) {
-		runtime·sched.sysmonwait = false;
-		runtime·notewakeup(&runtime·sched.sysmonnote);
-	}
-	runtime·unlock(&runtime·sched.lock);
-
-	while(p1) {
-		p = p1;
-		p1 = p1->link;
-		if(p->m) {
-			mp = p->m;
-			p->m = nil;
-			if(mp->nextp)
-				runtime·throw("starttheworld: inconsistent mp->nextp");
-			mp->nextp = p;
-			runtime·notewakeup(&mp->park);
-		} else {
-			// Start M to run P.  Do not start another M below.
-			newm(nil, p);
-			add = false;
-		}
-	}
-
-	if(add) {
-		// If GC could have used another helper proc, start one now,
-		// in the hope that it will be available next time.
-		// It would have been even better to start it before the collection,
-		// but doing so requires allocating memory, so it's tricky to
-		// coordinate.  This lazy approach works out in practice:
-		// we don't mind if the first couple gc rounds don't have quite
-		// the maximum number of procs.
-		newm(mhelpgc, nil);
-	}
-	g->m->locks--;
-	if(g->m->locks == 0 && g->preempt)  // restore the preemption request in case we've cleared it in newstack
-		g->stackguard0 = StackPreempt;
-}
-
-static void mstart(void);
-
-// Called to start an M.
-#pragma textflag NOSPLIT
-void
-runtime·mstart(void)
-{
-	uintptr x, size;
-	
-	if(g->stack.lo == 0) {
-		// Initialize stack bounds from system stack.
-		// Cgo may have left stack size in stack.hi.
-		size = g->stack.hi;
-		if(size == 0)
-			size = 8192;
-		g->stack.hi = (uintptr)&x;
-		g->stack.lo = g->stack.hi - size + 1024;
-	}
-	
-	// Initialize stack guards so that we can start calling
-	// both Go and C functions with stack growth prologues.
-	g->stackguard0 = g->stack.lo + StackGuard;
-	g->stackguard1 = g->stackguard0;
-	mstart();
-}
-
-static void
-mstart(void)
-{
-	if(g != g->m->g0)
-		runtime·throw("bad runtime·mstart");
-
-	// Record top of stack for use by mcall.
-	// Once we call schedule we're never coming back,
-	// so other calls can reuse this stack space.
-	runtime·gosave(&g->m->g0->sched);
-	g->m->g0->sched.pc = (uintptr)-1;  // make sure it is never used
-	runtime·asminit();
-	runtime·minit();
-
-	// Install signal handlers; after minit so that minit can
-	// prepare the thread to be able to handle the signals.
-	if(g->m == &runtime·m0)
-		runtime·initsig();
-	
-	if(g->m->mstartfn)
-		g->m->mstartfn();
-
-	if(g->m->helpgc) {
-		g->m->helpgc = 0;
-		stopm();
-	} else if(g->m != &runtime·m0) {
-		acquirep(g->m->nextp);
-		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
-// to start threads for us so that we can play nicely with
-// foreign code.
-void (*_cgo_thread_start)(void*);
-
-typedef struct CgoThreadStart CgoThreadStart;
-struct CgoThreadStart
-{
-	G *g;
-	uintptr *tls;
-	void (*fn)(void);
-};
-
-M *runtime·newM(void); // in proc.go
-
-// Allocate a new m unassociated with any thread.
-// Can use p for allocation context if needed.
-M*
-runtime·allocm(P *p)
-{
-	M *mp;
-
-	g->m->locks++;  // disable GC because it can be called from sysmon
-	if(g->m->p == nil)
-		acquirep(p);  // temporarily borrow p for mallocs in this function
-	mp = runtime·newM();
-	mcommoninit(mp);
-
-	// In case of cgo or Solaris, pthread_create will make us a stack.
-	// Windows and Plan 9 will layout sched stack on OS stack.
-	if(runtime·iscgo || Solaris || Windows || Plan9)
-		mp->g0 = runtime·malg(-1);
-	else
-		mp->g0 = runtime·malg(8192);
-	mp->g0->m = mp;
-
-	if(p == g->m->p)
-		releasep();
-	g->m->locks--;
-	if(g->m->locks == 0 && g->preempt)  // restore the preemption request in case we've cleared it in newstack
-		g->stackguard0 = StackPreempt;
-
-	return mp;
-}
-
-G *runtime·newG(void); // in proc.go
-
-static G*
-allocg(void)
-{
-	return runtime·newG();
-}
-
-static M* lockextra(bool nilokay);
-static void unlockextra(M*);
-
-// needm is called when a cgo callback happens on a
-// thread without an m (a thread not created by Go).
-// In this case, needm is expected to find an m to use
-// and return with m, g initialized correctly.
-// Since m and g are not set now (likely nil, but see below)
-// needm is limited in what routines it can call. In particular
-// it can only call nosplit functions (textflag 7) and cannot
-// do any scheduling that requires an m.
-//
-// In order to avoid needing heavy lifting here, we adopt
-// the following strategy: there is a stack of available m's
-// that can be stolen. Using compare-and-swap
-// to pop from the stack has ABA races, so we simulate
-// a lock by doing an exchange (via casp) to steal the stack
-// head and replace the top pointer with MLOCKED (1).
-// This serves as a simple spin lock that we can use even
-// without an m. The thread that locks the stack in this way
-// unlocks the stack by storing a valid stack head pointer.
-//
-// In order to make sure that there is always an m structure
-// available to be stolen, we maintain the invariant that there
-// is always one more than needed. At the beginning of the
-// program (if cgo is in use) the list is seeded with a single m.
-// If needm finds that it has taken the last m off the list, its job
-// is - once it has installed its own m so that it can do things like
-// allocate memory - to create a spare m and put it on the list.
-//
-// Each of these extra m's also has a g0 and a curg that are
-// pressed into service as the scheduling stack and current
-// goroutine for the duration of the cgo callback.
-//
-// When the callback is done with the m, it calls dropm to
-// put the m back on the list.
-#pragma textflag NOSPLIT
-void
-runtime·needm(byte x)
-{
-	M *mp;
-
-	if(runtime·needextram) {
-		// Can happen if C/C++ code calls Go from a global ctor.
-		// Can not throw, because scheduler is not initialized yet.
-		runtime·write(2, "fatal error: cgo callback before cgo call\n",
-			sizeof("fatal error: cgo callback before cgo call\n")-1);
-		runtime·exit(1);
-	}
-
-	// Lock extra list, take head, unlock popped list.
-	// nilokay=false is safe here because of the invariant above,
-	// that the extra list always contains or will soon contain
-	// at least one m.
-	mp = lockextra(false);
-
-	// Set needextram when we've just emptied the list,
-	// so that the eventual call into cgocallbackg will
-	// allocate a new m for the extra list. We delay the
-	// allocation until then so that it can be done
-	// after exitsyscall makes sure it is okay to be
-	// running at all (that is, there's no garbage collection
-	// running right now).
-	mp->needextram = mp->schedlink == nil;
-	unlockextra(mp->schedlink);
-
-	// Install g (= m->g0) and set the stack bounds
-	// to match the current stack. We don't actually know
-	// how big the stack is, like we don't know how big any
-	// scheduling stack is, but we assume there's at least 32 kB,
-	// which is more than enough for us.
-	runtime·setg(mp->g0);
-	g->stack.hi = (uintptr)(&x + 1024);
-	g->stack.lo = (uintptr)(&x - 32*1024);
-	g->stackguard0 = g->stack.lo + StackGuard;
-
-	// Initialize this thread to use the m.
-	runtime·asminit();
-	runtime·minit();
-}
-
-// newextram allocates an m and puts it on the extra list.
-// It is called with a working local m, so that it can do things
-// like call schedlock and allocate.
-void
-runtime·newextram(void)
-{
-	M *mp, *mnext;
-	G *gp;
-
-	// Create extra goroutine locked to extra m.
-	// The goroutine is the context in which the cgo callback will run.
-	// The sched.pc will never be returned to, but setting it to
-	// runtime.goexit makes clear to the traceback routines where
-	// the goroutine stack ends.
-	mp = runtime·allocm(nil);
-	gp = runtime·malg(4096);
-	gp->sched.pc = (uintptr)runtime·goexit + PCQuantum;
-	gp->sched.sp = gp->stack.hi;
-	gp->sched.sp -= 4*sizeof(uintreg); // extra space in case of reads slightly beyond frame
-	gp->sched.lr = 0;
-	gp->sched.g = gp;
-	gp->syscallpc = gp->sched.pc;
-	gp->syscallsp = gp->sched.sp;
-	// malg returns status as Gidle, change to Gsyscall before adding to allg
-	// where GC will see it.
-	runtime·casgstatus(gp, Gidle, Gsyscall);
-	gp->m = mp;
-	mp->curg = gp;
-	mp->locked = LockInternal;
-	mp->lockedg = gp;
-	gp->lockedm = mp;
-	gp->goid = runtime·xadd64(&runtime·sched.goidgen, 1);
-	if(raceenabled)
-		gp->racectx = runtime·racegostart(runtime·newextram);
-	// put on allg for garbage collector
-	runtime·allgadd(gp);
-
-	// Add m to the extra list.
-	mnext = lockextra(true);
-	mp->schedlink = mnext;
-	unlockextra(mp);
-}
-
-// dropm is called when a cgo callback has called needm but is now
-// done with the callback and returning back into the non-Go thread.
-// It puts the current m back onto the extra list.
-//
-// The main expense here is the call to signalstack to release the
-// m's signal stack, and then the call to needm on the next callback
-// from this thread. It is tempting to try to save the m for next time,
-// which would eliminate both these costs, but there might not be
-// a next time: the current thread (which Go does not control) might exit.
-// If we saved the m for that thread, there would be an m leak each time
-// such a thread exited. Instead, we acquire and release an m on each
-// call. These should typically not be scheduling operations, just a few
-// atomics, so the cost should be small.
-//
-// TODO(rsc): An alternative would be to allocate a dummy pthread per-thread
-// variable using pthread_key_create. Unlike the pthread keys we already use
-// on OS X, this dummy key would never be read by Go code. It would exist
-// only so that we could register at thread-exit-time destructor.
-// That destructor would put the m back onto the extra list.
-// This is purely a performance optimization. The current version,
-// in which dropm happens on each cgo call, is still correct too.
-// We may have to keep the current version on systems with cgo
-// but without pthreads, like Windows.
-void
-runtime·dropm(void)
-{
-	M *mp, *mnext;
-
-	// Undo whatever initialization minit did during needm.
-	runtime·unminit();
-
-	// Clear m and g, and return m to the extra list.
-	// After the call to setmg we can only call nosplit functions.
-	mp = g->m;
-	runtime·setg(nil);
-
-	mnext = lockextra(true);
-	mp->schedlink = mnext;
-	unlockextra(mp);
-}
-
-#define MLOCKED ((M*)1)
-
-// lockextra locks the extra list and returns the list head.
-// The caller must unlock the list by storing a new list head
-// to runtime.extram. If nilokay is true, then lockextra will
-// return a nil list head if that's what it finds. If nilokay is false,
-// lockextra will keep waiting until the list head is no longer nil.
-#pragma textflag NOSPLIT
-static M*
-lockextra(bool nilokay)
-{
-	M *mp;
-	void (*yield)(void);
-
-	for(;;) {
-		mp = runtime·atomicloadp(&runtime·extram);
-		if(mp == MLOCKED) {
-			yield = runtime·osyield;
-			yield();
-			continue;
-		}
-		if(mp == nil && !nilokay) {
-			runtime·usleep(1);
-			continue;
-		}
-		if(!runtime·casp(&runtime·extram, mp, MLOCKED)) {
-			yield = runtime·osyield;
-			yield();
-			continue;
-		}
-		break;
-	}
-	return mp;
-}
-
-#pragma textflag NOSPLIT
-static void
-unlockextra(M *mp)
-{
-	runtime·atomicstorep(&runtime·extram, mp);
-}
-
-
-// Create a new m.  It will start off with a call to fn, or else the scheduler.
-static void
-newm(void(*fn)(void), P *p)
-{
-	M *mp;
-
-	mp = runtime·allocm(p);
-	mp->nextp = p;
-	mp->mstartfn = fn;
-
-	if(runtime·iscgo) {
-		CgoThreadStart ts;
-
-		if(_cgo_thread_start == nil)
-			runtime·throw("_cgo_thread_start missing");
-		ts.g = mp->g0;
-		ts.tls = mp->tls;
-		ts.fn = runtime·mstart;
-		runtime·asmcgocall(_cgo_thread_start, &ts);
-		return;
-	}
-	runtime·newosproc(mp, (byte*)mp->g0->stack.hi);
-}
-
-// Stops execution of the current m until new work is available.
-// Returns with acquired P.
-static void
-stopm(void)
-{
-	if(g->m->locks)
-		runtime·throw("stopm holding locks");
-	if(g->m->p)
-		runtime·throw("stopm holding p");
-	if(g->m->spinning) {
-		g->m->spinning = false;
-		runtime·xadd(&runtime·sched.nmspinning, -1);
-	}
-
-retry:
-	runtime·lock(&runtime·sched.lock);
-	mput(g->m);
-	runtime·unlock(&runtime·sched.lock);
-	runtime·notesleep(&g->m->park);
-	runtime·noteclear(&g->m->park);
-	if(g->m->helpgc) {
-		runtime·gchelper();
-		g->m->helpgc = 0;
-		g->m->mcache = nil;
-		goto retry;
-	}
-	acquirep(g->m->nextp);
-	g->m->nextp = nil;
-}
-
-static void
-mspinning(void)
-{
-	g->m->spinning = true;
-}
-
-// 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.
-static void
-startm(P *p, bool spinning)
-{
-	M *mp;
-	void (*fn)(void);
-
-	runtime·lock(&runtime·sched.lock);
-	if(p == nil) {
-		p = pidleget();
-		if(p == nil) {
-			runtime·unlock(&runtime·sched.lock);
-			if(spinning)
-				runtime·xadd(&runtime·sched.nmspinning, -1);
-			return;
-		}
-	}
-	mp = mget();
-	runtime·unlock(&runtime·sched.lock);
-	if(mp == nil) {
-		fn = nil;
-		if(spinning)
-			fn = mspinning;
-		newm(fn, p);
-		return;
-	}
-	if(mp->spinning)
-		runtime·throw("startm: m is spinning");
-	if(mp->nextp)
-		runtime·throw("startm: m has p");
-	mp->spinning = spinning;
-	mp->nextp = p;
-	runtime·notewakeup(&mp->park);
-}
-
-// Hands off P from syscall or locked M.
-static void
-handoffp(P *p)
-{
-	// if it has local work, start it straight away
-	if(p->runqhead != p->runqtail || runtime·sched.runqsize) {
-		startm(p, false);
-		return;
-	}
-	// no local work, check that there are no spinning/idle M's,
-	// otherwise our help is not required
-	if(runtime·atomicload(&runtime·sched.nmspinning) + runtime·atomicload(&runtime·sched.npidle) == 0 &&  // TODO: fast atomic
-		runtime·cas(&runtime·sched.nmspinning, 0, 1)){
-		startm(p, true);
-		return;
-	}
-	runtime·lock(&runtime·sched.lock);
-	if(runtime·sched.gcwaiting) {
-		p->status = Pgcstop;
-		if(--runtime·sched.stopwait == 0)
-			runtime·notewakeup(&runtime·sched.stopnote);
-		runtime·unlock(&runtime·sched.lock);
-		return;
-	}
-	if(runtime·sched.runqsize) {
-		runtime·unlock(&runtime·sched.lock);
-		startm(p, false);
-		return;
-	}
-	// If this is the last running P and nobody is polling network,
-	// need to wakeup another M to poll network.
-	if(runtime·sched.npidle == runtime·gomaxprocs-1 && runtime·atomicload64(&runtime·sched.lastpoll) != 0) {
-		runtime·unlock(&runtime·sched.lock);
-		startm(p, false);
-		return;
-	}
-	pidleput(p);
-	runtime·unlock(&runtime·sched.lock);
-}
-
-// Tries to add one more P to execute G's.
-// Called when a G is made runnable (newproc, ready).
-static void
-wakep(void)
-{
-	// be conservative about spinning threads
-	if(!runtime·cas(&runtime·sched.nmspinning, 0, 1))
-		return;
-	startm(nil, true);
-}
-
-// Stops execution of the current m that is locked to a g until the g is runnable again.
-// Returns with acquired P.
-static void
-stoplockedm(void)
-{
-	P *p;
-	uint32 status;
-
-	if(g->m->lockedg == nil || g->m->lockedg->lockedm != g->m)
-		runtime·throw("stoplockedm: inconsistent locking");
-	if(g->m->p) {
-		// Schedule another M to run this p.
-		p = releasep();
-		handoffp(p);
-	}
-	incidlelocked(1);
-	// Wait until another thread schedules lockedg again.
-	runtime·notesleep(&g->m->park);
-	runtime·noteclear(&g->m->park);
-	status = runtime·readgstatus(g->m->lockedg);
-	if((status&~Gscan) != Grunnable){
-		runtime·printf("runtime:stoplockedm: g is not Grunnable or Gscanrunnable");
-		dumpgstatus(g);
-		runtime·throw("stoplockedm: not runnable");
-	}
-	acquirep(g->m->nextp);
-	g->m->nextp = nil;
-}
-
-// Schedules the locked m to run the locked gp.
-static void
-startlockedm(G *gp)
-{
-	M *mp;
-	P *p;
-
-	mp = gp->lockedm;
-	if(mp == g->m)
-		runtime·throw("startlockedm: locked to me");
-	if(mp->nextp)
-		runtime·throw("startlockedm: m has p");
-	// directly handoff current P to the locked m
-	incidlelocked(-1);
-	p = releasep();
-	mp->nextp = p;
-	runtime·notewakeup(&mp->park);
-	stopm();
-}
-
-// Stops the current m for stoptheworld.
-// Returns when the world is restarted.
-static void
-gcstopm(void)
-{
-	P *p;
-
-	if(!runtime·sched.gcwaiting)
-		runtime·throw("gcstopm: not waiting for gc");
-	if(g->m->spinning) {
-		g->m->spinning = false;
-		runtime·xadd(&runtime·sched.nmspinning, -1);
-	}
-	p = releasep();
-	runtime·lock(&runtime·sched.lock);
-	p->status = Pgcstop;
-	if(--runtime·sched.stopwait == 0)
-		runtime·notewakeup(&runtime·sched.stopnote);
-	runtime·unlock(&runtime·sched.lock);
-	stopm();
-}
-
-// Schedules gp to run on the current M.
-// Never returns.
-static void
-execute(G *gp)
-{
-	int32 hz;
-	
-	runtime·casgstatus(gp, Grunnable, Grunning);
-	gp->waitsince = 0;
-	gp->preempt = false;
-	gp->stackguard0 = gp->stack.lo + StackGuard;
-	g->m->p->schedtick++;
-	g->m->curg = gp;
-	gp->m = g->m;
-
-	// Check whether the profiler needs to be turned on or off.
-	hz = runtime·sched.profilehz;
-	if(g->m->profilehz != hz)
-		runtime·resetcpuprofiler(hz);
-
-	runtime·gogo(&gp->sched);
-}
-
-// Finds a runnable goroutine to execute.
-// Tries to steal from other P's, get g from global queue, poll network.
-static G*
-findrunnable(void)
-{
-	G *gp;
-	P *p;
-	int32 i;
-
-top:
-	if(runtime·sched.gcwaiting) {
-		gcstopm();
-		goto top;
-	}
-	if(runtime·fingwait && runtime·fingwake && (gp = runtime·wakefing()) != nil)
-		runtime·ready(gp);
-	// local runq
-	gp = runqget(g->m->p);
-	if(gp)
-		return gp;
-	// global runq
-	if(runtime·sched.runqsize) {
-		runtime·lock(&runtime·sched.lock);
-		gp = globrunqget(g->m->p, 0);
-		runtime·unlock(&runtime·sched.lock);
-		if(gp)
-			return gp;
-	}
-	// poll network
-	gp = runtime·netpoll(false);  // non-blocking
-	if(gp) {
-		injectglist(gp->schedlink);
-		runtime·casgstatus(gp, Gwaiting, Grunnable);
-		return gp;
-	}
-	// If number of spinning M's >= number of busy P's, block.
-	// This is necessary to prevent excessive CPU consumption
-	// when GOMAXPROCS>>1 but the program parallelism is low.
-	if(!g->m->spinning && 2 * runtime·atomicload(&runtime·sched.nmspinning) >= runtime·gomaxprocs - runtime·atomicload(&runtime·sched.npidle))  // TODO: fast atomic
-		goto stop;
-	if(!g->m->spinning) {
-		g->m->spinning = true;
-		runtime·xadd(&runtime·sched.nmspinning, 1);
-	}
-	// random steal from other P's
-	for(i = 0; i < 2*runtime·gomaxprocs; i++) {
-		if(runtime·sched.gcwaiting)
-			goto top;
-		p = runtime·allp[runtime·fastrand1()%runtime·gomaxprocs];
-		if(p == g->m->p)
-			gp = runqget(p);
-		else
-			gp = runqsteal(g->m->p, p);
-		if(gp)
-			return gp;
-	}
-stop:
-	// return P and block
-	runtime·lock(&runtime·sched.lock);
-	if(runtime·sched.gcwaiting) {
-		runtime·unlock(&runtime·sched.lock);
-		goto top;
-	}
-	if(runtime·sched.runqsize) {
-		gp = globrunqget(g->m->p, 0);
-		runtime·unlock(&runtime·sched.lock);
-		return gp;
-	}
-	p = releasep();
-	pidleput(p);
-	runtime·unlock(&runtime·sched.lock);
-	if(g->m->spinning) {
-		g->m->spinning = false;
-		runtime·xadd(&runtime·sched.nmspinning, -1);
-	}
-	// check all runqueues once again
-	for(i = 0; i < runtime·gomaxprocs; i++) {
-		p = runtime·allp[i];
-		if(p && p->runqhead != p->runqtail) {
-			runtime·lock(&runtime·sched.lock);
-			p = pidleget();
-			runtime·unlock(&runtime·sched.lock);
-			if(p) {
-				acquirep(p);
-				goto top;
-			}
-			break;
-		}
-	}
-	// poll network
-	if(runtime·xchg64(&runtime·sched.lastpoll, 0) != 0) {
-		if(g->m->p)
-			runtime·throw("findrunnable: netpoll with p");
-		if(g->m->spinning)
-			runtime·throw("findrunnable: netpoll with spinning");
-		gp = runtime·netpoll(true);  // block until new work is available
-		runtime·atomicstore64(&runtime·sched.lastpoll, runtime·nanotime());
-		if(gp) {
-			runtime·lock(&runtime·sched.lock);
-			p = pidleget();
-			runtime·unlock(&runtime·sched.lock);
-			if(p) {
-				acquirep(p);
-				injectglist(gp->schedlink);
-				runtime·casgstatus(gp, Gwaiting, Grunnable);
-				return gp;
-			}
-			injectglist(gp);
-		}
-	}
-	stopm();
-	goto top;
-}
-
-static void
-resetspinning(void)
-{
-	int32 nmspinning;
-
-	if(g->m->spinning) {
-		g->m->spinning = false;
-		nmspinning = runtime·xadd(&runtime·sched.nmspinning, -1);
-		if(nmspinning < 0)
-			runtime·throw("findrunnable: negative nmspinning");
-	} else
-		nmspinning = runtime·atomicload(&runtime·sched.nmspinning);
-
-	// M wakeup policy is deliberately somewhat conservative (see nmspinning handling),
-	// so see if we need to wakeup another P here.
-	if (nmspinning == 0 && runtime·atomicload(&runtime·sched.npidle) > 0)
-		wakep();
-}
-
-// Injects the list of runnable G's into the scheduler.
-// Can run concurrently with GC.
-static void
-injectglist(G *glist)
-{
-	int32 n;
-	G *gp;
-
-	if(glist == nil)
-		return;
-	runtime·lock(&runtime·sched.lock);
-	for(n = 0; glist; n++) {
-		gp = glist;
-		glist = gp->schedlink;
-		runtime·casgstatus(gp, Gwaiting, Grunnable); 
-		globrunqput(gp);
-	}
-	runtime·unlock(&runtime·sched.lock);
-
-	for(; n && runtime·sched.npidle; n--)
-		startm(nil, false);
-}
-
-// One round of scheduler: find a runnable goroutine and execute it.
-// Never returns.
-static void
-schedule(void)
-{
-	G *gp;
-	uint32 tick;
-
-	if(g->m->locks)
-		runtime·throw("schedule: holding locks");
-
-	if(g->m->lockedg) {
-		stoplockedm();
-		execute(g->m->lockedg);  // Never returns.
-	}
-
-top:
-	if(runtime·sched.gcwaiting) {
-		gcstopm();
-		goto top;
-	}
-
-	gp = nil;
-	// Check the global runnable queue once in a while to ensure fairness.
-	// Otherwise two goroutines can completely occupy the local runqueue
-	// by constantly respawning each other.
-	tick = g->m->p->schedtick;
-	// This is a fancy way to say tick%61==0,
-	// it uses 2 MUL instructions instead of a single DIV and so is faster on modern processors.
-	if(tick - (((uint64)tick*0x4325c53fu)>>36)*61 == 0 && runtime·sched.runqsize > 0) {
-		runtime·lock(&runtime·sched.lock);
-		gp = globrunqget(g->m->p, 1);
-		runtime·unlock(&runtime·sched.lock);
-		if(gp)
-			resetspinning();
-	}
-	if(gp == nil) {
-		gp = runqget(g->m->p);
-		if(gp && g->m->spinning)
-			runtime·throw("schedule: spinning with local work");
-	}
-	if(gp == nil) {
-		gp = findrunnable();  // blocks until work is available
-		resetspinning();
-	}
-
-	if(gp->lockedm) {
-		// Hands off own p to the locked m,
-		// then blocks waiting for a new p.
-		startlockedm(gp);
-		goto top;
-	}
-
-	execute(gp);
-}
-
-// dropg removes the association between m and the current goroutine m->curg (gp for short).
-// Typically a caller sets gp's status away from Grunning and then
-// immediately calls dropg to finish the job. The caller is also responsible
-// for arranging that gp will be restarted using runtime·ready at an
-// appropriate time. After calling dropg and arranging for gp to be
-// readied later, the caller can do other work but eventually should
-// call schedule to restart the scheduling of goroutines on this m.
-static void
-dropg(void)
-{
-	if(g->m->lockedg == nil) {
-		g->m->curg->m = nil;
-		g->m->curg = nil;
-	}
-}
-
-// Puts the current goroutine into a waiting state and calls unlockf.
-// If unlockf returns false, the goroutine is resumed.
-void
-runtime·park(bool(*unlockf)(G*, void*), void *lock, String reason)
-{
-	void (*fn)(G*);
-
-	g->m->waitlock = lock;
-	g->m->waitunlockf = unlockf;
-	g->waitreason = reason;
-	fn = runtime·park_m;
-	runtime·mcall(&fn);
-}
-
-bool
-runtime·parkunlock_c(G *gp, void *lock)
-{
-	USED(gp);
-	runtime·unlock(lock);
-	return true;
-}
-
-// Puts the current goroutine into a waiting state and unlocks the lock.
-// The goroutine can be made runnable again by calling runtime·ready(gp).
-void
-runtime·parkunlock(Mutex *lock, String reason)
-{
-	runtime·park(runtime·parkunlock_c, lock, reason);
-}
-
-// runtime·park continuation on g0.
-void
-runtime·park_m(G *gp)
-{
-	bool ok;
-
-	runtime·casgstatus(gp, Grunning, Gwaiting);
-	dropg();
-
-	if(g->m->waitunlockf) {
-		ok = g->m->waitunlockf(gp, g->m->waitlock);
-		g->m->waitunlockf = nil;
-		g->m->waitlock = nil;
-		if(!ok) {
-			runtime·casgstatus(gp, Gwaiting, Grunnable); 
-			execute(gp);  // Schedule it back, never returns.
-		}
-	}
-
-	schedule();
-}
-
-// Gosched continuation on g0.
-void
-runtime·gosched_m(G *gp)
-{
-	uint32 status;
-
-	status = runtime·readgstatus(gp);
-	if((status&~Gscan) != Grunning){
-		dumpgstatus(gp);
-		runtime·throw("bad g status");
-	}
-	runtime·casgstatus(gp, Grunning, Grunnable);
-	dropg();
-	runtime·lock(&runtime·sched.lock);
-	globrunqput(gp);
-	runtime·unlock(&runtime·sched.lock);
-
-	schedule();
-}
-
-// Finishes execution of the current goroutine.
-// Must be NOSPLIT because it is called from Go.
-#pragma textflag NOSPLIT
-void
-runtime·goexit1(void)
-{
-	void (*fn)(G*);
-
-	if(raceenabled)
-		runtime·racegoend();
-	fn = goexit0;
-	runtime·mcall(&fn);
-}
-
-// runtime·goexit continuation on g0.
-static void
-goexit0(G *gp)
-{
-	runtime·casgstatus(gp, Grunning, Gdead);
-	gp->m = nil;
-	gp->lockedm = nil;
-	g->m->lockedg = nil;
-	gp->paniconfault = 0;
-	gp->defer = nil; // should be true already but just in case.
-	gp->panic = nil; // non-nil for Goexit during panic. points at stack-allocated data.
-	gp->writebuf.array = nil;
-	gp->writebuf.len = 0;
-	gp->writebuf.cap = 0;
-	gp->waitreason.str = nil;
-	gp->waitreason.len = 0;
-	gp->param = nil;
-
-	dropg();
-
-	if(g->m->locked & ~LockExternal) {
-		runtime·printf("invalid m->locked = %d\n", g->m->locked);
-		runtime·throw("internal lockOSThread error");
-	}	
-	g->m->locked = 0;
-	gfput(g->m->p, gp);
-	schedule();
-}
-
-#pragma textflag NOSPLIT
-static void
-save(uintptr pc, uintptr sp)
-{
-	g->sched.pc = pc;
-	g->sched.sp = sp;
-	g->sched.lr = 0;
-	g->sched.ret = 0;
-	g->sched.ctxt = 0;
-	g->sched.g = g;
-}
-
-static void entersyscall_bad(void);
-static void entersyscall_sysmon(void);
-static void entersyscall_gcwait(void);
-
-// The goroutine g is about to enter a system call.
-// Record that it's not using the cpu anymore.
-// This is called only from the go syscall library and cgocall,
-// not from the low-level system calls used by the runtime.
-//
-// Entersyscall cannot split the stack: the runtime·gosave must
-// make g->sched refer to the caller's stack segment, because
-// entersyscall is going to return immediately after.
-//
-// Nothing entersyscall calls can split the stack either.
-// We cannot safely move the stack during an active call to syscall,
-// because we do not know which of the uintptr arguments are
-// really pointers (back into the stack).
-// In practice, this means that we make the fast path run through
-// entersyscall doing no-split things, and the slow path has to use onM
-// to run bigger things on the m stack.
-//
-// reentersyscall is the entry point used by cgo callbacks, where explicitly
-// saved SP and PC are restored. This is needed when exitsyscall will be called
-// from a function further up in the call stack than the parent, as g->syscallsp
-// must always point to a valid stack frame. entersyscall below is the normal
-// entry point for syscalls, which obtains the SP and PC from the caller.
-#pragma textflag NOSPLIT
-void
-runtime·reentersyscall(uintptr pc, uintptr sp)
-{
-	void (*fn)(void);
-
-	// Disable preemption because during this function g is in Gsyscall status,
-	// but can have inconsistent g->sched, do not let GC observe it.
-	g->m->locks++;
-	
-	// Entersyscall must not call any function that might split/grow the stack.
-	// (See details in comment above.)
-	// Catch calls that might, by replacing the stack guard with something that
-	// will trip any stack check and leaving a flag to tell newstack to die.
-	g->stackguard0 = StackPreempt;
-	g->throwsplit = 1;
-
-	// Leave SP around for GC and traceback.
-	save(pc, sp);
-	g->syscallsp = sp;
-	g->syscallpc = pc;
-	runtime·casgstatus(g, Grunning, Gsyscall);
-	if(g->syscallsp < g->stack.lo || g->stack.hi < g->syscallsp) {
-		fn = entersyscall_bad;
-		runtime·onM(&fn);
-	}
-
-	if(runtime·atomicload(&runtime·sched.sysmonwait)) {  // TODO: fast atomic
-		fn = entersyscall_sysmon;
-		runtime·onM(&fn);
-		save(pc, sp);
-	}
-
-	g->m->mcache = nil;
-	g->m->p->m = nil;
-	runtime·atomicstore(&g->m->p->status, Psyscall);
-	if(runtime·sched.gcwaiting) {
-		fn = entersyscall_gcwait;
-		runtime·onM(&fn);
-		save(pc, sp);
-	}
-
-	// Goroutines must not split stacks in Gsyscall status (it would corrupt g->sched).
-	// We set stackguard to StackPreempt so that first split stack check calls morestack.
-	// Morestack detects this case and throws.
-	g->stackguard0 = StackPreempt;
-	g->m->locks--;
-}
-
-// Standard syscall entry used by the go syscall library and normal cgo calls.
-#pragma textflag NOSPLIT
-void
-·entersyscall(int32 dummy)
-{
-	runtime·reentersyscall((uintptr)runtime·getcallerpc(&dummy), runtime·getcallersp(&dummy));
-}
-
-static void
-entersyscall_bad(void)
-{
-	G *gp;
-	
-	gp = g->m->curg;
-	runtime·printf("entersyscall inconsistent %p [%p,%p]\n",
-		gp->syscallsp, gp->stack.lo, gp->stack.hi);
-	runtime·throw("entersyscall");
-}
-
-static void
-entersyscall_sysmon(void)
-{
-	runtime·lock(&runtime·sched.lock);
-	if(runtime·atomicload(&runtime·sched.sysmonwait)) {
-		runtime·atomicstore(&runtime·sched.sysmonwait, 0);
-		runtime·notewakeup(&runtime·sched.sysmonnote);
-	}
-	runtime·unlock(&runtime·sched.lock);
-}
-
-static void
-entersyscall_gcwait(void)
-{
-	runtime·lock(&runtime·sched.lock);
-	if (runtime·sched.stopwait > 0 && runtime·cas(&g->m->p->status, Psyscall, Pgcstop)) {
-		if(--runtime·sched.stopwait == 0)
-			runtime·notewakeup(&runtime·sched.stopnote);
-	}
-	runtime·unlock(&runtime·sched.lock);
-}
-
-static void entersyscallblock_handoff(void);
-
-// The same as runtime·entersyscall(), but with a hint that the syscall is blocking.
-#pragma textflag NOSPLIT
-void
-·entersyscallblock(int32 dummy)
-{
-	void (*fn)(void);
-
-	g->m->locks++;  // see comment in entersyscall
-	g->throwsplit = 1;
-	g->stackguard0 = StackPreempt;  // see comment in entersyscall
-
-	// Leave SP around for GC and traceback.
-	save((uintptr)runtime·getcallerpc(&dummy), runtime·getcallersp(&dummy));
-	g->syscallsp = g->sched.sp;
-	g->syscallpc = g->sched.pc;
-	runtime·casgstatus(g, Grunning, Gsyscall);
-	if(g->syscallsp < g->stack.lo || g->stack.hi < g->syscallsp) {
-		fn = entersyscall_bad;
-		runtime·onM(&fn);
-	}
-	
-	fn = entersyscallblock_handoff;
-	runtime·onM(&fn);
-
-	// Resave for traceback during blocked call.
-	save((uintptr)runtime·getcallerpc(&dummy), runtime·getcallersp(&dummy));
-
-	g->m->locks--;
-}
-
-static void
-entersyscallblock_handoff(void)
-{
-	handoffp(releasep());
-}
-
-// The goroutine g exited its system call.
-// Arrange for it to run on a cpu again.
-// This is called only from the go syscall library, not
-// from the low-level system calls used by the runtime.
-#pragma textflag NOSPLIT
-void
-·exitsyscall(int32 dummy)
-{
-	void (*fn)(G*);
-
-	g->m->locks++;  // see comment in entersyscall
-
-	if(runtime·getcallersp(&dummy) > g->syscallsp)
-		runtime·throw("exitsyscall: syscall frame is no longer valid");
-
-	g->waitsince = 0;
-	if(exitsyscallfast()) {
-		// There's a cpu for us, so we can run.
-		g->m->p->syscalltick++;
-		// We need to cas the status and scan before resuming...
-		runtime·casgstatus(g, Gsyscall, Grunning);
-
-		// Garbage collector isn't running (since we are),
-		// so okay to clear syscallsp.
-		g->syscallsp = (uintptr)nil;
-		g->m->locks--;
-		if(g->preempt) {
-			// restore the preemption request in case we've cleared it in newstack
-			g->stackguard0 = StackPreempt;
-		} else {
-			// otherwise restore the real stackguard, we've spoiled it in entersyscall/entersyscallblock
-			g->stackguard0 = g->stack.lo + StackGuard;
-		}
-		g->throwsplit = 0;
-		return;
-	}
-
-	g->m->locks--;
-
-	// Call the scheduler.
-	fn = exitsyscall0;
-	runtime·mcall(&fn);
-
-	// Scheduler returned, so we're allowed to run now.
-	// Delete the syscallsp information that we left for
-	// the garbage collector during the system call.
-	// Must wait until now because until gosched returns
-	// we don't know for sure that the garbage collector
-	// is not running.
-	g->syscallsp = (uintptr)nil;
-	g->m->p->syscalltick++;
-	g->throwsplit = 0;
-}
-
-static void exitsyscallfast_pidle(void);
-
-#pragma textflag NOSPLIT
-static bool
-exitsyscallfast(void)
-{
-	void (*fn)(void);
-
-	// Freezetheworld sets stopwait but does not retake P's.
-	if(runtime·sched.stopwait) {
-		g->m->p = nil;
-		return false;
-	}
-
-	// Try to re-acquire the last P.
-	if(g->m->p && g->m->p->status == Psyscall && runtime·cas(&g->m->p->status, Psyscall, Prunning)) {
-		// There's a cpu for us, so we can run.
-		g->m->mcache = g->m->p->mcache;
-		g->m->p->m = g->m;
-		return true;
-	}
-	// Try to get any other idle P.
-	g->m->p = nil;
-	if(runtime·sched.pidle) {
-		fn = exitsyscallfast_pidle;
-		runtime·onM(&fn);
-		if(g->m->scalararg[0]) {
-			g->m->scalararg[0] = 0;
-			return true;
-		}
-	}
-	return false;
-}
-
-static void
-exitsyscallfast_pidle(void)
-{
-	P *p;
-
-	runtime·lock(&runtime·sched.lock);
-	p = pidleget();
-	if(p && runtime·atomicload(&runtime·sched.sysmonwait)) {
-		runtime·atomicstore(&runtime·sched.sysmonwait, 0);
-		runtime·notewakeup(&runtime·sched.sysmonnote);
-	}
-	runtime·unlock(&runtime·sched.lock);
-	if(p) {
-		acquirep(p);
-		g->m->scalararg[0] = 1;
-	} else
-		g->m->scalararg[0] = 0;
-}
-
-// runtime·exitsyscall slow path on g0.
-// Failed to acquire P, enqueue gp as runnable.
-static void
-exitsyscall0(G *gp)
-{
-	P *p;
-
-	runtime·casgstatus(gp, Gsyscall, Grunnable);
-	dropg();
-	runtime·lock(&runtime·sched.lock);
-	p = pidleget();
-	if(p == nil)
-		globrunqput(gp);
-	else if(runtime·atomicload(&runtime·sched.sysmonwait)) {
-		runtime·atomicstore(&runtime·sched.sysmonwait, 0);
-		runtime·notewakeup(&runtime·sched.sysmonnote);
-	}
-	runtime·unlock(&runtime·sched.lock);
-	if(p) {
-		acquirep(p);
-		execute(gp);  // Never returns.
-	}
-	if(g->m->lockedg) {
-		// Wait until another thread schedules gp and so m again.
-		stoplockedm();
-		execute(gp);  // Never returns.
-	}
-	stopm();
-	schedule();  // Never returns.
-}
-
-static void
-beforefork(void)
-{
-	G *gp;
-	
-	gp = g->m->curg;
-	// Fork can hang if preempted with signals frequently enough (see issue 5517).
-	// Ensure that we stay on the same M where we disable profiling.
-	gp->m->locks++;
-	if(gp->m->profilehz != 0)
-		runtime·resetcpuprofiler(0);
-
-	// This function is called before fork in syscall package.
-	// Code between fork and exec must not allocate memory nor even try to grow stack.
-	// Here we spoil g->stackguard to reliably detect any attempts to grow stack.
-	// runtime_AfterFork will undo this in parent process, but not in child.
-	gp->stackguard0 = StackFork;
-}
-
-// Called from syscall package before fork.
-#pragma textflag NOSPLIT
-void
-syscall·runtime_BeforeFork(void)
-{
-	void (*fn)(void);
-	
-	fn = beforefork;
-	runtime·onM(&fn);
-}
-
-static void
-afterfork(void)
-{
-	int32 hz;
-	G *gp;
-	
-	gp = g->m->curg;
-	// See the comment in runtime_BeforeFork.
-	gp->stackguard0 = gp->stack.lo + StackGuard;
-
-	hz = runtime·sched.profilehz;
-	if(hz != 0)
-		runtime·resetcpuprofiler(hz);
-	gp->m->locks--;
-}
-
-// Called from syscall package after fork in parent.
-#pragma textflag NOSPLIT
-void
-syscall·runtime_AfterFork(void)
-{
-	void (*fn)(void);
-	
-	fn = afterfork;
-	runtime·onM(&fn);
-}
-
-// Hook used by runtime·malg to call runtime·stackalloc on the
-// scheduler stack.  This exists because runtime·stackalloc insists
-// on being called on the scheduler stack, to avoid trying to grow
-// the stack while allocating a new stack segment.
-static void
-mstackalloc(G *gp)
-{
-	G *newg;
-	uintptr size;
-
-	newg = g->m->ptrarg[0];
-	size = g->m->scalararg[0];
-
-	newg->stack = runtime·stackalloc(size);
-
-	runtime·gogo(&gp->sched);
-}
-
-// Allocate a new g, with a stack big enough for stacksize bytes.
-G*
-runtime·malg(int32 stacksize)
-{
-	G *newg;
-	void (*fn)(G*);
-
-	newg = allocg();
-	if(stacksize >= 0) {
-		stacksize = runtime·round2(StackSystem + stacksize);
-		if(g == g->m->g0) {
-			// running on scheduler stack already.
-			newg->stack = runtime·stackalloc(stacksize);
-		} else {
-			// have to call stackalloc on scheduler stack.
-			g->m->scalararg[0] = stacksize;
-			g->m->ptrarg[0] = newg;
-			fn = mstackalloc;
-			runtime·mcall(&fn);
-			g->m->ptrarg[0] = nil;
-		}
-		newg->stackguard0 = newg->stack.lo + StackGuard;
-		newg->stackguard1 = ~(uintptr)0;
-	}
-	return newg;
-}
-
-static void
-newproc_m(void)
-{
-	byte *argp;
-	void *callerpc;
-	FuncVal *fn;
-	int32 siz;
-
-	siz = g->m->scalararg[0];
-	callerpc = (void*)g->m->scalararg[1];	
-	argp = g->m->ptrarg[0];
-	fn = (FuncVal*)g->m->ptrarg[1];
-
-	runtime·newproc1(fn, argp, siz, 0, callerpc);
-	g->m->ptrarg[0] = nil;
-	g->m->ptrarg[1] = nil;
-}
-
-// Create a new g running fn with siz bytes of arguments.
-// Put it on the queue of g's waiting to run.
-// The compiler turns a go statement into a call to this.
-// Cannot split the stack because it assumes that the arguments
-// are available sequentially after &fn; they would not be
-// copied if a stack split occurred.
-#pragma textflag NOSPLIT
-void
-runtime·newproc(int32 siz, FuncVal* fn, ...)
-{
-	byte *argp;
-	void (*mfn)(void);
-
-	if(thechar == '5')
-		argp = (byte*)(&fn+2);  // skip caller's saved LR
-	else
-		argp = (byte*)(&fn+1);
-
-	g->m->locks++;
-	g->m->scalararg[0] = siz;
-	g->m->scalararg[1] = (uintptr)runtime·getcallerpc(&siz);
-	g->m->ptrarg[0] = argp;
-	g->m->ptrarg[1] = fn;
-	mfn = newproc_m;
-	runtime·onM(&mfn);
-	g->m->locks--;
-}
-
-void runtime·main(void);
-
-// Create a new g running fn with narg bytes of arguments starting
-// at argp and returning nret bytes of results.  callerpc is the
-// address of the go statement that created this.  The new g is put
-// on the queue of g's waiting to run.
-G*
-runtime·newproc1(FuncVal *fn, byte *argp, int32 narg, int32 nret, void *callerpc)
-{
-	byte *sp;
-	G *newg;
-	P *p;
-	int32 siz;
-
-	if(fn == nil) {
-		g->m->throwing = -1;  // do not dump full stacks
-		runtime·throw("go of nil func value");
-	}
-	g->m->locks++;  // disable preemption because it can be holding p in a local var
-	siz = narg + nret;
-	siz = (siz+7) & ~7;
-
-	// We could allocate a larger initial stack if necessary.
-	// Not worth it: this is almost always an error.
-	// 4*sizeof(uintreg): extra space added below
-	// sizeof(uintreg): caller's LR (arm) or return address (x86, in gostartcall).
-	if(siz >= StackMin - 4*sizeof(uintreg) - sizeof(uintreg))
-		runtime·throw("runtime.newproc: function arguments too large for new goroutine");
-
-	p = g->m->p;
-	if((newg = gfget(p)) == nil) {
-		newg = runtime·malg(StackMin);
-		runtime·casgstatus(newg, Gidle, Gdead);
-		runtime·allgadd(newg); // publishes with a g->status of Gdead so GC scanner doesn't look at uninitialized stack.
-	}
-	if(newg->stack.hi == 0)
-		runtime·throw("newproc1: newg missing stack");
-
-	if(runtime·readgstatus(newg) != Gdead) 
-		runtime·throw("newproc1: new g is not Gdead");
-
-	sp = (byte*)newg->stack.hi;
-	sp -= 4*sizeof(uintreg); // extra space in case of reads slightly beyond frame
-	sp -= siz;
-	runtime·memmove(sp, argp, narg);
-	if(thechar == '5') {
-		// caller's LR
-		sp -= sizeof(void*);
-		*(void**)sp = nil;
-	}
-
-	runtime·memclr((byte*)&newg->sched, sizeof newg->sched);
-	newg->sched.sp = (uintptr)sp;
-	newg->sched.pc = (uintptr)runtime·goexit + PCQuantum; // +PCQuantum so that previous instruction is in same function
-	newg->sched.g = newg;
-	runtime·gostartcallfn(&newg->sched, fn);
-	newg->gopc = (uintptr)callerpc;
-	runtime·casgstatus(newg, Gdead, Grunnable);
-
-	if(p->goidcache == p->goidcacheend) {
-		// Sched.goidgen is the last allocated id,
-		// this batch must be [sched.goidgen+1, sched.goidgen+GoidCacheBatch].
-		// At startup sched.goidgen=0, so main goroutine receives goid=1.
-		p->goidcache = runtime·xadd64(&runtime·sched.goidgen, GoidCacheBatch);
-		p->goidcache -= GoidCacheBatch - 1;
-		p->goidcacheend = p->goidcache + GoidCacheBatch;
-	}
-	newg->goid = p->goidcache++;
-	if(raceenabled)
-		newg->racectx = runtime·racegostart((void*)callerpc);
-	runqput(p, newg);
-
-	if(runtime·atomicload(&runtime·sched.npidle) != 0 && runtime·atomicload(&runtime·sched.nmspinning) == 0 && fn->fn != runtime·main)  // TODO: fast atomic
-		wakep();
-	g->m->locks--;
-	if(g->m->locks == 0 && g->preempt)  // restore the preemption request in case we've cleared it in newstack
-		g->stackguard0 = StackPreempt;
-	return newg;
-}
-
-// Put on gfree list.
-// If local list is too long, transfer a batch to the global list.
-static void
-gfput(P *p, G *gp)
-{
-	uintptr stksize;
-
-	if(runtime·readgstatus(gp) != Gdead) 
-		runtime·throw("gfput: bad status (not Gdead)");
-
-	stksize = gp->stack.hi - gp->stack.lo;
-	
-	if(stksize != FixedStack) {
-		// non-standard stack size - free it.
-		runtime·stackfree(gp->stack);
-		gp->stack.lo = 0;
-		gp->stack.hi = 0;
-		gp->stackguard0 = 0;
-	}
-	gp->schedlink = p->gfree;
-	p->gfree = gp;
-	p->gfreecnt++;
-	if(p->gfreecnt >= 64) {
-		runtime·lock(&runtime·sched.gflock);
-		while(p->gfreecnt >= 32) {
-			p->gfreecnt--;
-			gp = p->gfree;
-			p->gfree = gp->schedlink;
-			gp->schedlink = runtime·sched.gfree;
-			runtime·sched.gfree = gp;
-			runtime·sched.ngfree++;
-		}
-		runtime·unlock(&runtime·sched.gflock);
-	}
-}
-
-// Get from gfree list.
-// If local list is empty, grab a batch from global list.
-static G*
-gfget(P *p)
-{
-	G *gp;
-	void (*fn)(G*);
-
-retry:
-	gp = p->gfree;
-	if(gp == nil && runtime·sched.gfree) {
-		runtime·lock(&runtime·sched.gflock);
-		while(p->gfreecnt < 32 && runtime·sched.gfree != nil) {
-			p->gfreecnt++;
-			gp = runtime·sched.gfree;
-			runtime·sched.gfree = gp->schedlink;
-			runtime·sched.ngfree--;
-			gp->schedlink = p->gfree;
-			p->gfree = gp;
-		}
-		runtime·unlock(&runtime·sched.gflock);
-		goto retry;
-	}
-	if(gp) {
-		p->gfree = gp->schedlink;
-		p->gfreecnt--;
-
-		if(gp->stack.lo == 0) {
-			// Stack was deallocated in gfput.  Allocate a new one.
-			if(g == g->m->g0) {
-				gp->stack = runtime·stackalloc(FixedStack);
-			} else {
-				g->m->scalararg[0] = FixedStack;
-				g->m->ptrarg[0] = gp;
-				fn = mstackalloc;
-				runtime·mcall(&fn);
-				g->m->ptrarg[0] = nil;
-			}
-			gp->stackguard0 = gp->stack.lo + StackGuard;
-		} else {
-			if(raceenabled)
-				runtime·racemalloc((void*)gp->stack.lo, gp->stack.hi - gp->stack.lo);
-		}
-	}
-	return gp;
-}
-
-// Purge all cached G's from gfree list to the global list.
-static void
-gfpurge(P *p)
-{
-	G *gp;
-
-	runtime·lock(&runtime·sched.gflock);
-	while(p->gfreecnt != 0) {
-		p->gfreecnt--;
-		gp = p->gfree;
-		p->gfree = gp->schedlink;
-		gp->schedlink = runtime·sched.gfree;
-		runtime·sched.gfree = gp;
-		runtime·sched.ngfree++;
-	}
-	runtime·unlock(&runtime·sched.gflock);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·Breakpoint(void)
-{
-	runtime·breakpoint();
-}
-
-// lockOSThread is called by runtime.LockOSThread and runtime.lockOSThread below
-// after they modify m->locked. Do not allow preemption during this call,
-// or else the m might be different in this function than in the caller.
-#pragma textflag NOSPLIT
-static void
-lockOSThread(void)
-{
-	g->m->lockedg = g;
-	g->lockedm = g->m;
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·LockOSThread(void)
-{
-	g->m->locked |= LockExternal;
-	lockOSThread();
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·lockOSThread(void)
-{
-	g->m->locked += LockInternal;
-	lockOSThread();
-}
-
-
-// unlockOSThread is called by runtime.UnlockOSThread and runtime.unlockOSThread below
-// after they update m->locked. Do not allow preemption during this call,
-// or else the m might be in different in this function than in the caller.
-#pragma textflag NOSPLIT
-static void
-unlockOSThread(void)
-{
-	if(g->m->locked != 0)
-		return;
-	g->m->lockedg = nil;
-	g->lockedm = nil;
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·UnlockOSThread(void)
-{
-	g->m->locked &= ~LockExternal;
-	unlockOSThread();
-}
-
-static void badunlockOSThread(void);
-
-#pragma textflag NOSPLIT
-void
-runtime·unlockOSThread(void)
-{
-	void (*fn)(void);
-
-	if(g->m->locked < LockInternal) {
-		fn = badunlockOSThread;
-		runtime·onM(&fn);
-	}
-	g->m->locked -= LockInternal;
-	unlockOSThread();
-}
-
-static void
-badunlockOSThread(void)
-{
-	runtime·throw("runtime: internal error: misuse of lockOSThread/unlockOSThread");
-}
-
-#pragma textflag NOSPLIT
-int32
-runtime·gcount(void)
-{
-	P *p, **pp;
-	int32 n;
-
-	n = runtime·allglen - runtime·sched.ngfree;
-	for(pp=runtime·allp; p=*pp; pp++)
-		n -= p->gfreecnt;
-	// All these variables can be changed concurrently, so the result can be inconsistent.
-	// But at least the current goroutine is running.
-	if(n < 1)
-		n = 1;
-	return n;
-}
-
-int32
-runtime·mcount(void)
-{
-	return runtime·sched.mcount;
-}
-
-static struct ProfState {
-	uint32 lock;
-	int32 hz;
-} prof;
-
-static void System(void) { System(); }
-static void ExternalCode(void) { ExternalCode(); }
-static void GC(void) { GC(); }
-
-extern void runtime·cpuproftick(uintptr*, int32);
-extern byte runtime·etext[];
-
-// Called if we receive a SIGPROF signal.
-void
-runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp, M *mp)
-{
-	int32 n;
-	bool traceback;
-	// Do not use global m in this function, use mp instead.
-	// On windows one m is sending reports about all the g's, so m means a wrong thing.
-	byte m;
-	uintptr stk[100];
-
-	m = 0;
-	USED(m);
-
-	if(prof.hz == 0)
-		return;
-
-	// Profiling runs concurrently with GC, so it must not allocate.
-	mp->mallocing++;
-
-	// Define that a "user g" is a user-created goroutine, and a "system g"
-	// is one that is m->g0 or m->gsignal. We've only made sure that we
-	// can unwind user g's, so exclude the system g's.
-	//
-	// It is not quite as easy as testing gp == m->curg (the current user g)
-	// because we might be interrupted for profiling halfway through a
-	// goroutine switch. The switch involves updating three (or four) values:
-	// g, PC, SP, and (on arm) LR. The PC must be the last to be updated,
-	// because once it gets updated the new g is running.
-	//
-	// When switching from a user g to a system g, LR is not considered live,
-	// so the update only affects g, SP, and PC. Since PC must be last, there
-	// the possible partial transitions in ordinary execution are (1) g alone is updated,
-	// (2) both g and SP are updated, and (3) SP alone is updated.
-	// If g is updated, we'll see a system g and not look closer.
-	// If SP alone is updated, we can detect the partial transition by checking
-	// whether the SP is within g's stack bounds. (We could also require that SP
-	// be changed only after g, but the stack bounds check is needed by other
-	// cases, so there is no need to impose an additional requirement.)
-	//
-	// There is one exceptional transition to a system g, not in ordinary execution.
-	// When a signal arrives, the operating system starts the signal handler running
-	// with an updated PC and SP. The g is updated last, at the beginning of the
-	// handler. There are two reasons this is okay. First, until g is updated the
-	// g and SP do not match, so the stack bounds check detects the partial transition.
-	// Second, signal handlers currently run with signals disabled, so a profiling
-	// signal cannot arrive during the handler.
-	//
-	// When switching from a system g to a user g, there are three possibilities.
-	//
-	// First, it may be that the g switch has no PC update, because the SP
-	// either corresponds to a user g throughout (as in runtime.asmcgocall)
-	// or because it has been arranged to look like a user g frame
-	// (as in runtime.cgocallback_gofunc). In this case, since the entire
-	// transition is a g+SP update, a partial transition updating just one of 
-	// those will be detected by the stack bounds check.
-	//
-	// Second, when returning from a signal handler, the PC and SP updates
-	// are performed by the operating system in an atomic update, so the g
-	// update must be done before them. The stack bounds check detects
-	// the partial transition here, and (again) signal handlers run with signals
-	// disabled, so a profiling signal cannot arrive then anyway.
-	//
-	// Third, the common case: it may be that the switch updates g, SP, and PC
-	// separately, as in runtime.gogo.
-	//
-	// Because runtime.gogo is the only instance, we check whether the PC lies
-	// within that function, and if so, not ask for a traceback. This approach
-	// requires knowing the size of the runtime.gogo function, which we
-	// record in arch_*.h and check in runtime_test.go.
-	//
-	// There is another apparently viable approach, recorded here in case
-	// the "PC within runtime.gogo" check turns out not to be usable.
-	// It would be possible to delay the update of either g or SP until immediately
-	// before the PC update instruction. Then, because of the stack bounds check,
-	// the only problematic interrupt point is just before that PC update instruction,
-	// and the sigprof handler can detect that instruction and simulate stepping past
-	// it in order to reach a consistent state. On ARM, the update of g must be made
-	// in two places (in R10 and also in a TLS slot), so the delayed update would
-	// need to be the SP update. The sigprof handler must read the instruction at
-	// the current PC and if it was the known instruction (for example, JMP BX or 
-	// MOV R2, PC), use that other register in place of the PC value.
-	// The biggest drawback to this solution is that it requires that we can tell
-	// whether it's safe to read from the memory pointed at by PC.
-	// In a correct program, we can test PC == nil and otherwise read,
-	// but if a profiling signal happens at the instant that a program executes
-	// a bad jump (before the program manages to handle the resulting fault)
-	// the profiling handler could fault trying to read nonexistent memory.
-	//
-	// To recap, there are no constraints on the assembly being used for the
-	// transition. We simply require that g and SP match and that the PC is not
-	// in runtime.gogo.
-	traceback = true;
-	if(gp == nil || gp != mp->curg ||
-	   (uintptr)sp < gp->stack.lo || gp->stack.hi < (uintptr)sp ||
-	   ((uint8*)runtime·gogo <= pc && pc < (uint8*)runtime·gogo + RuntimeGogoBytes))
-		traceback = false;
-
-	n = 0;
-	if(traceback)
-		n = runtime·gentraceback((uintptr)pc, (uintptr)sp, (uintptr)lr, gp, 0, stk, nelem(stk), nil, nil, TraceTrap);
-	if(!traceback || n <= 0) {
-		// Normal traceback is impossible or has failed.
-		// See if it falls into several common cases.
-		n = 0;
-		if(mp->ncgo > 0 && mp->curg != nil &&
-			mp->curg->syscallpc != 0 && mp->curg->syscallsp != 0) {
-			// Cgo, we can't unwind and symbolize arbitrary C code,
-			// so instead collect Go stack that leads to the cgo call.
-			// This is especially important on windows, since all syscalls are cgo calls.
-			n = runtime·gentraceback(mp->curg->syscallpc, mp->curg->syscallsp, 0, mp->curg, 0, stk, nelem(stk), nil, nil, 0);
-		}
-#ifdef GOOS_windows
-		if(n == 0 && mp->libcallg != nil && mp->libcallpc != 0 && mp->libcallsp != 0) {
-			// Libcall, i.e. runtime syscall on windows.
-			// Collect Go stack that leads to the call.
-			n = runtime·gentraceback(mp->libcallpc, mp->libcallsp, 0, mp->libcallg, 0, stk, nelem(stk), nil, nil, 0);
-		}
-#endif
-		if(n == 0) {
-			// If all of the above has failed, account it against abstract "System" or "GC".
-			n = 2;
-			// "ExternalCode" is better than "etext".
-			if((uintptr)pc > (uintptr)runtime·etext)
-				pc = (byte*)ExternalCode + PCQuantum;
-			stk[0] = (uintptr)pc;
-			if(mp->gcing || mp->helpgc)
-				stk[1] = (uintptr)GC + PCQuantum;
-			else
-				stk[1] = (uintptr)System + PCQuantum;
-		}
-	}
-
-	if(prof.hz != 0) {
-		// Simple cas-lock to coordinate with setcpuprofilerate.
-		while(!runtime·cas(&prof.lock, 0, 1))
-			runtime·osyield();
-		if(prof.hz != 0)
-			runtime·cpuproftick(stk, n);
-		runtime·atomicstore(&prof.lock, 0);
-	}
-	mp->mallocing--;
-}
-
-// Arrange to call fn with a traceback hz times a second.
-void
-runtime·setcpuprofilerate_m(void)
-{
-	int32 hz;
-	
-	hz = g->m->scalararg[0];
-	g->m->scalararg[0] = 0;
-
-	// Force sane arguments.
-	if(hz < 0)
-		hz = 0;
-
-	// Disable preemption, otherwise we can be rescheduled to another thread
-	// that has profiling enabled.
-	g->m->locks++;
-
-	// Stop profiler on this thread so that it is safe to lock prof.
-	// if a profiling signal came in while we had prof locked,
-	// it would deadlock.
-	runtime·resetcpuprofiler(0);
-
-	while(!runtime·cas(&prof.lock, 0, 1))
-		runtime·osyield();
-	prof.hz = hz;
-	runtime·atomicstore(&prof.lock, 0);
-
-	runtime·lock(&runtime·sched.lock);
-	runtime·sched.profilehz = hz;
-	runtime·unlock(&runtime·sched.lock);
-
-	if(hz != 0)
-		runtime·resetcpuprofiler(hz);
-
-	g->m->locks--;
-}
-
-P *runtime·newP(void);
-
-// Change number of processors.  The world is stopped, sched is locked.
-static void
-procresize(int32 new)
-{
-	int32 i, old;
-	bool empty;
-	G *gp;
-	P *p;
-
-	old = runtime·gomaxprocs;
-	if(old < 0 || old > MaxGomaxprocs || new <= 0 || new >MaxGomaxprocs)
-		runtime·throw("procresize: invalid arg");
-	// initialize new P's
-	for(i = 0; i < new; i++) {
-		p = runtime·allp[i];
-		if(p == nil) {
-			p = runtime·newP();
-			p->id = i;
-			p->status = Pgcstop;
-			runtime·atomicstorep(&runtime·allp[i], p);
-		}
-		if(p->mcache == nil) {
-			if(old==0 && i==0)
-				p->mcache = g->m->mcache;  // bootstrap
-			else
-				p->mcache = runtime·allocmcache();
-		}
-	}
-
-	// redistribute runnable G's evenly
-	// collect all runnable goroutines in global queue preserving FIFO order
-	// FIFO order is required to ensure fairness even during frequent GCs
-	// see http://golang.org/issue/7126
-	empty = false;
-	while(!empty) {
-		empty = true;
-		for(i = 0; i < old; i++) {
-			p = runtime·allp[i];
-			if(p->runqhead == p->runqtail)
-				continue;
-			empty = false;
-			// pop from tail of local queue
-			p->runqtail--;
-			gp = p->runq[p->runqtail%nelem(p->runq)];
-			// push onto head of global queue
-			gp->schedlink = runtime·sched.runqhead;
-			runtime·sched.runqhead = gp;
-			if(runtime·sched.runqtail == nil)
-				runtime·sched.runqtail = gp;
-			runtime·sched.runqsize++;
-		}
-	}
-	// fill local queues with at most nelem(p->runq)/2 goroutines
-	// start at 1 because current M already executes some G and will acquire allp[0] below,
-	// so if we have a spare G we want to put it into allp[1].
-	for(i = 1; i < new * nelem(p->runq)/2 && runtime·sched.runqsize > 0; i++) {
-		gp = runtime·sched.runqhead;
-		runtime·sched.runqhead = gp->schedlink;
-		if(runtime·sched.runqhead == nil)
-			runtime·sched.runqtail = nil;
-		runtime·sched.runqsize--;
-		runqput(runtime·allp[i%new], gp);
-	}
-
-	// free unused P's
-	for(i = new; i < old; i++) {
-		p = runtime·allp[i];
-		runtime·freemcache(p->mcache);
-		p->mcache = nil;
-		gfpurge(p);
-		p->status = Pdead;
-		// can't free P itself because it can be referenced by an M in syscall
-	}
-
-	if(g->m->p)
-		g->m->p->m = nil;
-	g->m->p = nil;
-	g->m->mcache = nil;
-	p = runtime·allp[0];
-	p->m = nil;
-	p->status = Pidle;
-	acquirep(p);
-	for(i = new-1; i > 0; i--) {
-		p = runtime·allp[i];
-		p->status = Pidle;
-		pidleput(p);
-	}
-	runtime·atomicstore((uint32*)&runtime·gomaxprocs, new);
-}
-
-// Associate p and the current m.
-static void
-acquirep(P *p)
-{
-	if(g->m->p || g->m->mcache)
-		runtime·throw("acquirep: already in go");
-	if(p->m || p->status != Pidle) {
-		runtime·printf("acquirep: p->m=%p(%d) p->status=%d\n", p->m, p->m ? p->m->id : 0, p->status);
-		runtime·throw("acquirep: invalid p state");
-	}
-	g->m->mcache = p->mcache;
-	g->m->p = p;
-	p->m = g->m;
-	p->status = Prunning;
-}
-
-// Disassociate p and the current m.
-static P*
-releasep(void)
-{
-	P *p;
-
-	if(g->m->p == nil || g->m->mcache == nil)
-		runtime·throw("releasep: invalid arg");
-	p = g->m->p;
-	if(p->m != g->m || p->mcache != g->m->mcache || p->status != Prunning) {
-		runtime·printf("releasep: m=%p m->p=%p p->m=%p m->mcache=%p p->mcache=%p p->status=%d\n",
-			g->m, g->m->p, p->m, g->m->mcache, p->mcache, p->status);
-		runtime·throw("releasep: invalid p state");
-	}
-	g->m->p = nil;
-	g->m->mcache = nil;
-	p->m = nil;
-	p->status = Pidle;
-	return p;
-}
-
-static void
-incidlelocked(int32 v)
-{
-	runtime·lock(&runtime·sched.lock);
-	runtime·sched.nmidlelocked += v;
-	if(v > 0)
-		checkdead();
-	runtime·unlock(&runtime·sched.lock);
-}
-
-// Check for deadlock situation.
-// The check is based on number of running M's, if 0 -> deadlock.
-static void
-checkdead(void)
-{
-	G *gp;
-	P *p;
-	M *mp;
-	int32 run, grunning, s;
-	uintptr i;
-
-	// -1 for sysmon
-	run = runtime·sched.mcount - runtime·sched.nmidle - runtime·sched.nmidlelocked - 1;
-	if(run > 0)
-		return;
-	// If we are dying because of a signal caught on an already idle thread,
-	// freezetheworld will cause all running threads to block.
-	// And runtime will essentially enter into deadlock state,
-	// except that there is a thread that will call runtime·exit soon.
-	if(runtime·panicking > 0)
-		return;
-	if(run < 0) {
-		runtime·printf("runtime: checkdead: nmidle=%d nmidlelocked=%d mcount=%d\n",
-			runtime·sched.nmidle, runtime·sched.nmidlelocked, runtime·sched.mcount);
-		runtime·throw("checkdead: inconsistent counts");
-	}
-	grunning = 0;
-	runtime·lock(&runtime·allglock);
-	for(i = 0; i < runtime·allglen; i++) {
-		gp = runtime·allg[i];
-		if(gp->issystem)
-			continue;
-		s = runtime·readgstatus(gp);
-		switch(s&~Gscan) {
-		case Gwaiting:
-			grunning++;
-			break;
-		case Grunnable:
-		case Grunning:
-		case Gsyscall:
-			runtime·unlock(&runtime·allglock);
-			runtime·printf("runtime: checkdead: find g %D in status %d\n", gp->goid, s);
-			runtime·throw("checkdead: runnable g");
-			break;
-		}
-	}
-	runtime·unlock(&runtime·allglock);
-	if(grunning == 0)  // possible if main goroutine calls runtime·Goexit()
-		runtime·throw("no goroutines (main called runtime.Goexit) - deadlock!");
-
-	// Maybe jump time forward for playground.
-	if((gp = runtime·timejump()) != nil) {
-		runtime·casgstatus(gp, Gwaiting, Grunnable);
-		globrunqput(gp);
- 		p = pidleget();
- 		if(p == nil)
- 			runtime·throw("checkdead: no p for timer");
- 		mp = mget();
- 		if(mp == nil)
- 			newm(nil, p);
- 		else {
- 			mp->nextp = p;
- 			runtime·notewakeup(&mp->park);
- 		}
- 		return;
- 	}
-
-	g->m->throwing = -1;  // do not dump full stacks
-	runtime·throw("all goroutines are asleep - deadlock!");
-}
-
-static void
-sysmon(void)
-{
-	uint32 idle, delay, nscavenge;
-	int64 now, unixnow, lastpoll, lasttrace, lastgc;
-	int64 forcegcperiod, scavengelimit, lastscavenge, maxsleep;
-	G *gp;
-
-	// If we go two minutes without a garbage collection, force one to run.
-	forcegcperiod = 2*60*1e9;
-	// If a heap span goes unused for 5 minutes after a garbage collection,
-	// we hand it back to the operating system.
-	scavengelimit = 5*60*1e9;
-	if(runtime·debug.scavenge > 0) {
-		// Scavenge-a-lot for testing.
-		forcegcperiod = 10*1e6;
-		scavengelimit = 20*1e6;
-	}
-	lastscavenge = runtime·nanotime();
-	nscavenge = 0;
-	// Make wake-up period small enough for the sampling to be correct.
-	maxsleep = forcegcperiod/2;
-	if(scavengelimit < forcegcperiod)
-		maxsleep = scavengelimit/2;
-
-	lasttrace = 0;
-	idle = 0;  // how many cycles in succession we had not wokeup somebody
-	delay = 0;
-	for(;;) {
-		if(idle == 0)  // start with 20us sleep...
-			delay = 20;
-		else if(idle > 50)  // start doubling the sleep after 1ms...
-			delay *= 2;
-		if(delay > 10*1000)  // up to 10ms
-			delay = 10*1000;
-		runtime·usleep(delay);
-		if(runtime·debug.schedtrace <= 0 &&
-			(runtime·sched.gcwaiting || runtime·atomicload(&runtime·sched.npidle) == runtime·gomaxprocs)) {  // TODO: fast atomic
-			runtime·lock(&runtime·sched.lock);
-			if(runtime·atomicload(&runtime·sched.gcwaiting) || runtime·atomicload(&runtime·sched.npidle) == runtime·gomaxprocs) {
-				runtime·atomicstore(&runtime·sched.sysmonwait, 1);
-				runtime·unlock(&runtime·sched.lock);
-				runtime·notetsleep(&runtime·sched.sysmonnote, maxsleep);
-				runtime·lock(&runtime·sched.lock);
-				runtime·atomicstore(&runtime·sched.sysmonwait, 0);
-				runtime·noteclear(&runtime·sched.sysmonnote);
-				idle = 0;
-				delay = 20;
-			}
-			runtime·unlock(&runtime·sched.lock);
-		}
-		// poll network if not polled for more than 10ms
-		lastpoll = runtime·atomicload64(&runtime·sched.lastpoll);
-		now = runtime·nanotime();
-		unixnow = runtime·unixnanotime();
-		if(lastpoll != 0 && lastpoll + 10*1000*1000 < now) {
-			runtime·cas64(&runtime·sched.lastpoll, lastpoll, now);
-			gp = runtime·netpoll(false);  // non-blocking
-			if(gp) {
-				// Need to decrement number of idle locked M's
-				// (pretending that one more is running) before injectglist.
-				// Otherwise it can lead to the following situation:
-				// injectglist grabs all P's but before it starts M's to run the P's,
-				// another M returns from syscall, finishes running its G,
-				// observes that there is no work to do and no other running M's
-				// and reports deadlock.
-				incidlelocked(-1);
-				injectglist(gp);
-				incidlelocked(1);
-			}
-		}
-		// retake P's blocked in syscalls
-		// and preempt long running G's
-		if(retake(now))
-			idle = 0;
-		else
-			idle++;
-
-		// check if we need to force a GC
-		lastgc = runtime·atomicload64(&mstats.last_gc);
-		if(lastgc != 0 && unixnow - lastgc > forcegcperiod && runtime·atomicload(&runtime·forcegc.idle)) {
-			runtime·lock(&runtime·forcegc.lock);
-			runtime·forcegc.idle = 0;
-			runtime·forcegc.g->schedlink = nil;
-			injectglist(runtime·forcegc.g);
-			runtime·unlock(&runtime·forcegc.lock);
-		}
-
-		// scavenge heap once in a while
-		if(lastscavenge + scavengelimit/2 < now) {
-			runtime·MHeap_Scavenge(nscavenge, now, scavengelimit);
-			lastscavenge = now;
-			nscavenge++;
-		}
-
-		if(runtime·debug.schedtrace > 0 && lasttrace + runtime·debug.schedtrace*1000000ll <= now) {
-			lasttrace = now;
-			runtime·schedtrace(runtime·debug.scheddetail);
-		}
-	}
-}
-
-typedef struct Pdesc Pdesc;
-struct Pdesc
-{
-	uint32	schedtick;
-	int64	schedwhen;
-	uint32	syscalltick;
-	int64	syscallwhen;
-};
-#pragma dataflag NOPTR
-static Pdesc pdesc[MaxGomaxprocs];
-
-static uint32
-retake(int64 now)
-{
-	uint32 i, s, n;
-	int64 t;
-	P *p;
-	Pdesc *pd;
-
-	n = 0;
-	for(i = 0; i < runtime·gomaxprocs; i++) {
-		p = runtime·allp[i];
-		if(p==nil)
-			continue;
-		pd = &pdesc[i];
-		s = p->status;
-		if(s == Psyscall) {
-			// Retake P from syscall if it's there for more than 1 sysmon tick (at least 20us).
-			t = p->syscalltick;
-			if(pd->syscalltick != t) {
-				pd->syscalltick = t;
-				pd->syscallwhen = now;
-				continue;
-			}
-			// On the one hand we don't want to retake Ps if there is no other work to do,
-			// but on the other hand we want to retake them eventually
-			// because they can prevent the sysmon thread from deep sleep.
-			if(p->runqhead == p->runqtail &&
-				runtime·atomicload(&runtime·sched.nmspinning) + runtime·atomicload(&runtime·sched.npidle) > 0 &&
-				pd->syscallwhen + 10*1000*1000 > now)
-				continue;
-			// Need to decrement number of idle locked M's
-			// (pretending that one more is running) before the CAS.
-			// Otherwise the M from which we retake can exit the syscall,
-			// increment nmidle and report deadlock.
-			incidlelocked(-1);
-			if(runtime·cas(&p->status, s, Pidle)) {
-				n++;
-				handoffp(p);
-			}
-			incidlelocked(1);
-		} else if(s == Prunning) {
-			// Preempt G if it's running for more than 10ms.
-			t = p->schedtick;
-			if(pd->schedtick != t) {
-				pd->schedtick = t;
-				pd->schedwhen = now;
-				continue;
-			}
-			if(pd->schedwhen + 10*1000*1000 > now)
-				continue;
-			preemptone(p);
-		}
-	}
-	return n;
-}
-
-// Tell all goroutines that they have been preempted and they should stop.
-// This function is purely best-effort.  It can fail to inform a goroutine if a
-// processor just started running it.
-// No locks need to be held.
-// Returns true if preemption request was issued to at least one goroutine.
-static bool
-preemptall(void)
-{
-	P *p;
-	int32 i;
-	bool res;
-
-	res = false;
-	for(i = 0; i < runtime·gomaxprocs; i++) {
-		p = runtime·allp[i];
-		if(p == nil || p->status != Prunning)
-			continue;
-		res |= preemptone(p);
-	}
-	return res;
-}
-
-// Tell the goroutine running on processor P to stop.
-// This function is purely best-effort.  It can incorrectly fail to inform the
-// goroutine.  It can send inform the wrong goroutine.  Even if it informs the
-// correct goroutine, that goroutine might ignore the request if it is
-// simultaneously executing runtime·newstack.
-// No lock needs to be held.
-// Returns true if preemption request was issued.
-// The actual preemption will happen at some point in the future
-// and will be indicated by the gp->status no longer being
-// Grunning
-static bool
-preemptone(P *p)
-{
-	M *mp;
-	G *gp;
-
-	mp = p->m;
-	if(mp == nil || mp == g->m)
-		return false;
-	gp = mp->curg;
-	if(gp == nil || gp == mp->g0)
-		return false;
-	gp->preempt = true;
-	// Every call in a go routine checks for stack overflow by
-	// comparing the current stack pointer to gp->stackguard0.
-	// Setting gp->stackguard0 to StackPreempt folds
-	// preemption into the normal stack overflow check.
-	gp->stackguard0 = StackPreempt;
-	return true;
-}
-
-void
-runtime·schedtrace(bool detailed)
-{
-	static int64 starttime;
-	int64 now;
-	int64 id1, id2, id3;
-	int32 i, t, h;
-	uintptr gi;
-	int8 *fmt;
-	M *mp, *lockedm;
-	G *gp, *lockedg;
-	P *p;
-
-	now = runtime·nanotime();
-	if(starttime == 0)
-		starttime = now;
-
-	runtime·lock(&runtime·sched.lock);
-	runtime·printf("SCHED %Dms: gomaxprocs=%d idleprocs=%d threads=%d spinningthreads=%d idlethreads=%d runqueue=%d",
-		(now-starttime)/1000000, runtime·gomaxprocs, runtime·sched.npidle, runtime·sched.mcount,
-		runtime·sched.nmspinning, runtime·sched.nmidle, runtime·sched.runqsize);
-	if(detailed) {
-		runtime·printf(" gcwaiting=%d nmidlelocked=%d stopwait=%d sysmonwait=%d\n",
-			runtime·sched.gcwaiting, runtime·sched.nmidlelocked,
-			runtime·sched.stopwait, runtime·sched.sysmonwait);
-	}
-	// We must be careful while reading data from P's, M's and G's.
-	// Even if we hold schedlock, most data can be changed concurrently.
-	// E.g. (p->m ? p->m->id : -1) can crash if p->m changes from non-nil to nil.
-	for(i = 0; i < runtime·gomaxprocs; i++) {
-		p = runtime·allp[i];
-		if(p == nil)
-			continue;
-		mp = p->m;
-		h = runtime·atomicload(&p->runqhead);
-		t = runtime·atomicload(&p->runqtail);
-		if(detailed)
-			runtime·printf("  P%d: status=%d schedtick=%d syscalltick=%d m=%d runqsize=%d gfreecnt=%d\n",
-				i, p->status, p->schedtick, p->syscalltick, mp ? mp->id : -1, t-h, p->gfreecnt);
-		else {
-			// In non-detailed mode format lengths of per-P run queues as:
-			// [len1 len2 len3 len4]
-			fmt = " %d";
-			if(runtime·gomaxprocs == 1)
-				fmt = " [%d]\n";
-			else if(i == 0)
-				fmt = " [%d";
-			else if(i == runtime·gomaxprocs-1)
-				fmt = " %d]\n";
-			runtime·printf(fmt, t-h);
-		}
-	}
-	if(!detailed) {
-		runtime·unlock(&runtime·sched.lock);
-		return;
-	}
-	for(mp = runtime·allm; mp; mp = mp->alllink) {
-		p = mp->p;
-		gp = mp->curg;
-		lockedg = mp->lockedg;
-		id1 = -1;
-		if(p)
-			id1 = p->id;
-		id2 = -1;
-		if(gp)
-			id2 = gp->goid;
-		id3 = -1;
-		if(lockedg)
-			id3 = lockedg->goid;
-		runtime·printf("  M%d: p=%D curg=%D mallocing=%d throwing=%d gcing=%d"
-			" locks=%d dying=%d helpgc=%d spinning=%d blocked=%d lockedg=%D\n",
-			mp->id, id1, id2,
-			mp->mallocing, mp->throwing, mp->gcing, mp->locks, mp->dying, mp->helpgc,
-			mp->spinning, g->m->blocked, id3);
-	}
-	runtime·lock(&runtime·allglock);
-	for(gi = 0; gi < runtime·allglen; gi++) {
-		gp = runtime·allg[gi];
-		mp = gp->m;
-		lockedm = gp->lockedm;
-		runtime·printf("  G%D: status=%d(%S) m=%d lockedm=%d\n",
-			gp->goid, runtime·readgstatus(gp), gp->waitreason, mp ? mp->id : -1,
-			lockedm ? lockedm->id : -1);
-	}
-	runtime·unlock(&runtime·allglock);
-	runtime·unlock(&runtime·sched.lock);
-}
-
-// Put mp on midle list.
-// Sched must be locked.
-static void
-mput(M *mp)
-{
-	mp->schedlink = runtime·sched.midle;
-	runtime·sched.midle = mp;
-	runtime·sched.nmidle++;
-	checkdead();
-}
-
-// Try to get an m from midle list.
-// Sched must be locked.
-static M*
-mget(void)
-{
-	M *mp;
-
-	if((mp = runtime·sched.midle) != nil){
-		runtime·sched.midle = mp->schedlink;
-		runtime·sched.nmidle--;
-	}
-	return mp;
-}
-
-// Put gp on the global runnable queue.
-// Sched must be locked.
-static void
-globrunqput(G *gp)
-{
-	gp->schedlink = nil;
-	if(runtime·sched.runqtail)
-		runtime·sched.runqtail->schedlink = gp;
-	else
-		runtime·sched.runqhead = gp;
-	runtime·sched.runqtail = gp;
-	runtime·sched.runqsize++;
-}
-
-// Put a batch of runnable goroutines on the global runnable queue.
-// Sched must be locked.
-static void
-globrunqputbatch(G *ghead, G *gtail, int32 n)
-{
-	gtail->schedlink = nil;
-	if(runtime·sched.runqtail)
-		runtime·sched.runqtail->schedlink = ghead;
-	else
-		runtime·sched.runqhead = ghead;
-	runtime·sched.runqtail = gtail;
-	runtime·sched.runqsize += n;
-}
-
-// Try get a batch of G's from the global runnable queue.
-// Sched must be locked.
-static G*
-globrunqget(P *p, int32 max)
-{
-	G *gp, *gp1;
-	int32 n;
-
-	if(runtime·sched.runqsize == 0)
-		return nil;
-	n = runtime·sched.runqsize/runtime·gomaxprocs+1;
-	if(n > runtime·sched.runqsize)
-		n = runtime·sched.runqsize;
-	if(max > 0 && n > max)
-		n = max;
-	if(n > nelem(p->runq)/2)
-		n = nelem(p->runq)/2;
-	runtime·sched.runqsize -= n;
-	if(runtime·sched.runqsize == 0)
-		runtime·sched.runqtail = nil;
-	gp = runtime·sched.runqhead;
-	runtime·sched.runqhead = gp->schedlink;
-	n--;
-	while(n--) {
-		gp1 = runtime·sched.runqhead;
-		runtime·sched.runqhead = gp1->schedlink;
-		runqput(p, gp1);
-	}
-	return gp;
-}
-
-// Put p to on pidle list.
-// Sched must be locked.
-static void
-pidleput(P *p)
-{
-	p->link = runtime·sched.pidle;
-	runtime·sched.pidle = p;
-	runtime·xadd(&runtime·sched.npidle, 1);  // TODO: fast atomic
-}
-
-// Try get a p from pidle list.
-// Sched must be locked.
-static P*
-pidleget(void)
-{
-	P *p;
-
-	p = runtime·sched.pidle;
-	if(p) {
-		runtime·sched.pidle = p->link;
-		runtime·xadd(&runtime·sched.npidle, -1);  // TODO: fast atomic
-	}
-	return p;
-}
-
-// Try to put g on local runnable queue.
-// If it's full, put onto global queue.
-// Executed only by the owner P.
-static void
-runqput(P *p, G *gp)
-{
-	uint32 h, t;
-
-retry:
-	h = runtime·atomicload(&p->runqhead);  // load-acquire, synchronize with consumers
-	t = p->runqtail;
-	if(t - h < nelem(p->runq)) {
-		p->runq[t%nelem(p->runq)] = gp;
-		runtime·atomicstore(&p->runqtail, t+1);  // store-release, makes the item available for consumption
-		return;
-	}
-	if(runqputslow(p, gp, h, t))
-		return;
-	// the queue is not full, now the put above must suceed
-	goto retry;
-}
-
-// Put g and a batch of work from local runnable queue on global queue.
-// Executed only by the owner P.
-static bool
-runqputslow(P *p, G *gp, uint32 h, uint32 t)
-{
-	G *batch[nelem(p->runq)/2+1];
-	uint32 n, i;
-
-	// First, grab a batch from local queue.
-	n = t-h;
-	n = n/2;
-	if(n != nelem(p->runq)/2)
-		runtime·throw("runqputslow: queue is not full");
-	for(i=0; i<n; i++)
-		batch[i] = p->runq[(h+i)%nelem(p->runq)];
-	if(!runtime·cas(&p->runqhead, h, h+n))  // cas-release, commits consume
-		return false;
-	batch[n] = gp;
-	// Link the goroutines.
-	for(i=0; i<n; i++)
-		batch[i]->schedlink = batch[i+1];
-	// Now put the batch on global queue.
-	runtime·lock(&runtime·sched.lock);
-	globrunqputbatch(batch[0], batch[n], n+1);
-	runtime·unlock(&runtime·sched.lock);
-	return true;
-}
-
-// Get g from local runnable queue.
-// Executed only by the owner P.
-static G*
-runqget(P *p)
-{
-	G *gp;
-	uint32 t, h;
-
-	for(;;) {
-		h = runtime·atomicload(&p->runqhead);  // load-acquire, synchronize with other consumers
-		t = p->runqtail;
-		if(t == h)
-			return nil;
-		gp = p->runq[h%nelem(p->runq)];
-		if(runtime·cas(&p->runqhead, h, h+1))  // cas-release, commits consume
-			return gp;
-	}
-}
-
-// Grabs a batch of goroutines from local runnable queue.
-// batch array must be of size nelem(p->runq)/2. Returns number of grabbed goroutines.
-// Can be executed by any P.
-static uint32
-runqgrab(P *p, G **batch)
-{
-	uint32 t, h, n, i;
-
-	for(;;) {
-		h = runtime·atomicload(&p->runqhead);  // load-acquire, synchronize with other consumers
-		t = runtime·atomicload(&p->runqtail);  // load-acquire, synchronize with the producer
-		n = t-h;
-		n = n - n/2;
-		if(n == 0)
-			break;
-		if(n > nelem(p->runq)/2)  // read inconsistent h and t
-			continue;
-		for(i=0; i<n; i++)
-			batch[i] = p->runq[(h+i)%nelem(p->runq)];
-		if(runtime·cas(&p->runqhead, h, h+n))  // cas-release, commits consume
-			break;
-	}
-	return n;
-}
-
-// Steal half of elements from local runnable queue of p2
-// and put onto local runnable queue of p.
-// Returns one of the stolen elements (or nil if failed).
-static G*
-runqsteal(P *p, P *p2)
-{
-	G *gp;
-	G *batch[nelem(p->runq)/2];
-	uint32 t, h, n, i;
-
-	n = runqgrab(p2, batch);
-	if(n == 0)
-		return nil;
-	n--;
-	gp = batch[n];
-	if(n == 0)
-		return gp;
-	h = runtime·atomicload(&p->runqhead);  // load-acquire, synchronize with consumers
-	t = p->runqtail;
-	if(t - h + n >= nelem(p->runq))
-		runtime·throw("runqsteal: runq overflow");
-	for(i=0; i<n; i++, t++)
-		p->runq[t%nelem(p->runq)] = batch[i];
-	runtime·atomicstore(&p->runqtail, t);  // store-release, makes the item available for consumption
-	return gp;
-}
-
-void
-runtime·testSchedLocalQueue(void)
-{
-	P *p;
-	G *gs;
-	int32 i, j;
-
-	p = (P*)runtime·mallocgc(sizeof(*p), nil, FlagNoScan);
-	gs = (G*)runtime·mallocgc(nelem(p->runq)*sizeof(*gs), nil, FlagNoScan);
-
-	for(i = 0; i < nelem(p->runq); i++) {
-		if(runqget(p) != nil)
-			runtime·throw("runq is not empty initially");
-		for(j = 0; j < i; j++)
-			runqput(p, &gs[i]);
-		for(j = 0; j < i; j++) {
-			if(runqget(p) != &gs[i]) {
-				runtime·printf("bad element at iter %d/%d\n", i, j);
-				runtime·throw("bad element");
-			}
-		}
-		if(runqget(p) != nil)
-			runtime·throw("runq is not empty afterwards");
-	}
-}
-
-void
-runtime·testSchedLocalQueueSteal(void)
-{
-	P *p1, *p2;
-	G *gs, *gp;
-	int32 i, j, s;
-
-	p1 = (P*)runtime·mallocgc(sizeof(*p1), nil, FlagNoScan);
-	p2 = (P*)runtime·mallocgc(sizeof(*p2), nil, FlagNoScan);
-	gs = (G*)runtime·mallocgc(nelem(p1->runq)*sizeof(*gs), nil, FlagNoScan);
-
-	for(i = 0; i < nelem(p1->runq); i++) {
-		for(j = 0; j < i; j++) {
-			gs[j].sig = 0;
-			runqput(p1, &gs[j]);
-		}
-		gp = runqsteal(p2, p1);
-		s = 0;
-		if(gp) {
-			s++;
-			gp->sig++;
-		}
-		while(gp = runqget(p2)) {
-			s++;
-			gp->sig++;
-		}
-		while(gp = runqget(p1))
-			gp->sig++;
-		for(j = 0; j < i; j++) {
-			if(gs[j].sig != 1) {
-				runtime·printf("bad element %d(%d) at iter %d\n", j, gs[j].sig, i);
-				runtime·throw("bad element");
-			}
-		}
-		if(s != i/2 && s != i/2+1) {
-			runtime·printf("bad steal %d, want %d or %d, iter %d\n",
-				s, i/2, i/2+1, i);
-			runtime·throw("bad steal");
-		}
-	}
-}
-
-void
-runtime·setmaxthreads_m(void)
-{
-	int32 in;
-	int32 out;
-
-	in = g->m->scalararg[0];
-
-	runtime·lock(&runtime·sched.lock);
-	out = runtime·sched.maxmcount;
-	runtime·sched.maxmcount = in;
-	checkmcount();
-	runtime·unlock(&runtime·sched.lock);
-
-	g->m->scalararg[0] = out;
-}
-
-static int8 experiment[] = GOEXPERIMENT; // defined in zaexperiment.h
-
-static bool
-haveexperiment(int8 *name)
-{
-	int32 i, j;
-	
-	for(i=0; i<sizeof(experiment); i++) {
-		if((i == 0 || experiment[i-1] == ',') && experiment[i] == name[0]) {
-			for(j=0; name[j]; j++)
-				if(experiment[i+j] != name[j])
-					goto nomatch;
-			if(experiment[i+j] != '\0' && experiment[i+j] != ',')
-				goto nomatch;
-			return 1;
-		}
-	nomatch:;
-	}
-	return 0;
-}
-
-#pragma textflag NOSPLIT
-void
-sync·runtime_procPin(intptr p)
-{
-	M *mp;
-
-	mp = g->m;
-	// Disable preemption.
-	mp->locks++;
-	p = mp->p->id;
-	FLUSH(&p);
-}
-
-#pragma textflag NOSPLIT
-void
-sync·runtime_procUnpin()
-{
-	g->m->locks--;
-}
diff --git a/src/runtime/proc.go b/src/runtime/proc.go
index 517ca03..c5b4a8c 100644
--- a/src/runtime/proc.go
+++ b/src/runtime/proc.go
@@ -6,12 +6,24 @@ package runtime
 
 import "unsafe"
 
-func newsysmon()
-
+//go:linkname runtime_init runtime.init
 func runtime_init()
+
+//go:linkname main_init main.init
 func main_init()
+
+// main_init_done is a signal used by cgocallbackg that initialization
+// has been completed. It is made before _cgo_notify_runtime_init_done,
+// so all cgo calls can rely on it existing. When main_init is complete,
+// it is closed, meaning cgocallbackg can reliably receive from it.
+var main_init_done chan bool
+
+//go:linkname main_main main.main
 func main_main()
 
+// runtimeInitTime is the nanotime() at which the runtime started.
+var runtimeInitTime int64
+
 // The main goroutine.
 func main() {
 	g := getg()
@@ -29,7 +41,12 @@ func main() {
 		maxstacksize = 250000000
 	}
 
-	onM(newsysmon)
+	// Record when the world started.
+	runtimeInitTime = nanotime()
+
+	systemstack(func() {
+		newm(sysmon, nil)
+	})
 
 	// Lock the main goroutine onto this, the main OS thread,
 	// during initialization.  Most programs won't care, but a few
@@ -40,7 +57,7 @@ func main() {
 	lockOSThread()
 
 	if g.m != &m0 {
-		gothrow("runtime.main not on m0")
+		throw("runtime.main not on m0")
 	}
 
 	runtime_init() // must be before defer
@@ -53,13 +70,44 @@ func main() {
 		}
 	}()
 
-	memstats.enablegc = true // now that runtime is initialized, GC is okay
+	gcenable()
+
+	main_init_done = make(chan bool)
+	if iscgo {
+		if _cgo_thread_start == nil {
+			throw("_cgo_thread_start missing")
+		}
+		if _cgo_malloc == nil {
+			throw("_cgo_malloc missing")
+		}
+		if _cgo_free == nil {
+			throw("_cgo_free missing")
+		}
+		if GOOS != "windows" {
+			if _cgo_setenv == nil {
+				throw("_cgo_setenv missing")
+			}
+			if _cgo_unsetenv == nil {
+				throw("_cgo_unsetenv missing")
+			}
+		}
+		if _cgo_notify_runtime_init_done == nil {
+			throw("_cgo_notify_runtime_init_done missing")
+		}
+		cgocall(_cgo_notify_runtime_init_done, nil)
+	}
 
 	main_init()
+	close(main_init_done)
 
 	needUnlock = false
 	unlockOSThread()
 
+	if isarchive || islibrary {
+		// A program compiled with -buildmode=c-archive or c-shared
+		// has a main, but it is not executed.
+		return
+	}
 	main_main()
 	if raceenabled {
 		racefini()
@@ -70,7 +118,7 @@ func main() {
 	// 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")
+		gopark(nil, nil, "panicwait", traceEvGoStop, 1)
 	}
 
 	exit(0)
@@ -80,7 +128,13 @@ func main() {
 	}
 }
 
-var parkunlock_c byte
+// 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() {
@@ -89,19 +143,18 @@ func init() {
 
 func forcegchelper() {
 	forcegc.g = getg()
-	forcegc.g.issystem = true
 	for {
 		lock(&forcegc.lock)
 		if forcegc.idle != 0 {
-			gothrow("forcegc: phase error")
+			throw("forcegc: phase error")
 		}
 		atomicstore(&forcegc.idle, 1)
-		goparkunlock(&forcegc.lock, "force gc (idle)")
+		goparkunlock(&forcegc.lock, "force gc (idle)", traceEvGoBlock, 1)
 		// this goroutine is explicitly resumed by sysmon
 		if debug.gctrace > 0 {
 			println("GC forced")
 		}
-		gogc(1)
+		startGC(gcBackgroundMode, true)
 	}
 }
 
@@ -115,16 +168,18 @@ func Gosched() {
 
 // Puts the current goroutine into a waiting state and calls unlockf.
 // If unlockf returns false, the goroutine is resumed.
-func gopark(unlockf unsafe.Pointer, lock unsafe.Pointer, reason string) {
+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)
 	if status != _Grunning && status != _Gscanrunning {
-		gothrow("gopark: bad g status")
+		throw("gopark: bad g status")
 	}
 	mp.waitlock = lock
-	mp.waitunlockf = unlockf
+	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)
@@ -132,68 +187,99 @@ func gopark(unlockf unsafe.Pointer, lock unsafe.Pointer, reason string) {
 
 // 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) {
-	gopark(unsafe.Pointer(&parkunlock_c), unsafe.Pointer(lock), reason)
+func goparkunlock(lock *mutex, reason string, traceEv byte, traceskip int) {
+	gopark(parkunlock_c, unsafe.Pointer(lock), reason, traceEv, traceskip)
 }
 
-func goready(gp *g) {
-	mp := acquirem()
-	mp.ptrarg[0] = unsafe.Pointer(gp)
-	onM(ready_m)
-	releasem(mp)
+func goready(gp *g, traceskip int) {
+	systemstack(func() {
+		ready(gp, traceskip)
+	})
 }
 
 //go:nosplit
 func acquireSudog() *sudog {
-	c := gomcache()
-	s := c.sudogcache
-	if s != nil {
-		if s.elem != nil {
-			gothrow("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,
 	// and the garbage collector calls the semaphore implementation
-	// in stoptheworld.
+	// in stopTheWorld.
 	// Break the cycle by doing acquirem/releasem around new(sudog).
 	// The acquirem/releasem increments m.locks during new(sudog),
 	// which keeps the garbage collector from being invoked.
 	mp := acquirem()
-	p := new(sudog)
+	pp := mp.p.ptr()
+	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
 func releaseSudog(s *sudog) {
 	if s.elem != nil {
-		gothrow("runtime: sudog with non-nil elem")
+		throw("runtime: sudog with non-nil elem")
 	}
 	if s.selectdone != nil {
-		gothrow("runtime: sudog with non-nil selectdone")
+		throw("runtime: sudog with non-nil selectdone")
 	}
 	if s.next != nil {
-		gothrow("runtime: sudog with non-nil next")
+		throw("runtime: sudog with non-nil next")
 	}
 	if s.prev != nil {
-		gothrow("runtime: sudog with non-nil prev")
+		throw("runtime: sudog with non-nil prev")
 	}
 	if s.waitlink != nil {
-		gothrow("runtime: sudog with non-nil waitlink")
+		throw("runtime: sudog with non-nil waitlink")
 	}
 	gp := getg()
 	if gp.param != nil {
-		gothrow("runtime: releaseSudog with non-nil gp.param")
+		throw("runtime: releaseSudog with non-nil gp.param")
+	}
+	mp := acquirem() // avoid rescheduling to another P
+	pp := mp.p.ptr()
+	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)
 	}
-	c := gomcache()
-	s.next = c.sudogcache
-	c.sudogcache = s
+	pp.sudogcache = append(pp.sudogcache, s)
+	releasem(mp)
 }
 
 // funcPC returns the entry PC of the function f.
@@ -205,11 +291,11 @@ func funcPC(f interface{}) uintptr {
 
 // called from assembly
 func badmcall(fn func(*g)) {
-	gothrow("runtime: mcall called on m->g0 stack")
+	throw("runtime: mcall called on m->g0 stack")
 }
 
 func badmcall2(fn func(*g)) {
-	gothrow("runtime: mcall function returned")
+	throw("runtime: mcall function returned")
 }
 
 func badreflectcall() {
@@ -221,21 +307,14 @@ func lockedOSThread() bool {
 	return gp.lockedm != nil && gp.m.lockedg != nil
 }
 
-func newP() *p {
-	return new(p)
-}
-
-func newM() *m {
-	return new(m)
-}
-
-func newG() *g {
-	return new(g)
-}
+var (
+	allgs    []*g
+	allglock mutex
+)
 
 func allgadd(gp *g) {
 	if readgstatus(gp) == _Gidle {
-		gothrow("allgadd: bad status Gidle")
+		throw("allgadd: bad status Gidle")
 	}
 
 	lock(&allglock)
diff --git a/src/runtime/proc1.go b/src/runtime/proc1.go
new file mode 100644
index 0000000..09cb775
--- /dev/null
+++ b/src/runtime/proc1.go
@@ -0,0 +1,3725 @@
+// 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"
+
+var (
+	m0 m
+	g0 g
+)
+
+// Goroutine scheduler
+// The scheduler's job is to distribute ready-to-run goroutines over worker threads.
+//
+// The main concepts are:
+// G - goroutine.
+// M - worker thread, or machine.
+// P - processor, a resource that is required to execute Go code.
+//     M must have an associated P to execute Go code, however it can be
+//     blocked or in a syscall w/o an associated P.
+//
+// Design doc at https://golang.org/s/go11sched.
+
+const (
+	// Number of goroutine ids to grab from sched.goidgen to local per-P cache at once.
+	// 16 seems to provide enough amortization, but other than that it's mostly arbitrary number.
+	_GoidCacheBatch = 16
+)
+
+// The bootstrap sequence is:
+//
+//	call osinit
+//	call schedinit
+//	make & queue new G
+//	call runtime·mstart
+//
+// The new G calls runtime·main.
+func schedinit() {
+	// raceinit must be the first call to race detector.
+	// In particular, it must be done before mallocinit below calls racemapshadow.
+	_g_ := getg()
+	if raceenabled {
+		_g_.racectx = raceinit()
+	}
+
+	sched.maxmcount = 10000
+
+	// Cache the framepointer experiment.  This affects stack unwinding.
+	framepointer_enabled = haveexperiment("framepointer")
+
+	tracebackinit()
+	moduledataverify()
+	stackinit()
+	mallocinit()
+	mcommoninit(_g_.m)
+
+	goargs()
+	goenvs()
+	parsedebugvars()
+	gcinit()
+
+	sched.lastpoll = uint64(nanotime())
+	procs := int(ncpu)
+	if n := atoi(gogetenv("GOMAXPROCS")); n > 0 {
+		if n > _MaxGomaxprocs {
+			n = _MaxGomaxprocs
+		}
+		procs = n
+	}
+	if procresize(int32(procs)) != nil {
+		throw("unknown runnable goroutine during bootstrap")
+	}
+
+	if buildVersion == "" {
+		// Condition should never trigger.  This code just serves
+		// to ensure runtime·buildVersion is kept in the resulting binary.
+		buildVersion = "unknown"
+	}
+}
+
+func dumpgstatus(gp *g) {
+	_g_ := getg()
+	print("runtime: gp: gp=", gp, ", goid=", gp.goid, ", gp->atomicstatus=", readgstatus(gp), "\n")
+	print("runtime:  g:  g=", _g_, ", goid=", _g_.goid, ",  g->atomicstatus=", readgstatus(_g_), "\n")
+}
+
+func checkmcount() {
+	// sched lock is held
+	if sched.mcount > sched.maxmcount {
+		print("runtime: program exceeds ", sched.maxmcount, "-thread limit\n")
+		throw("thread exhaustion")
+	}
+}
+
+func mcommoninit(mp *m) {
+	_g_ := getg()
+
+	// g0 stack won't make sense for user (and is not necessary unwindable).
+	if _g_ != _g_.m.g0 {
+		callers(1, mp.createstack[:])
+	}
+
+	mp.fastrand = 0x49f6428a + uint32(mp.id) + uint32(cputicks())
+	if mp.fastrand == 0 {
+		mp.fastrand = 0x49f6428a
+	}
+
+	lock(&sched.lock)
+	mp.id = sched.mcount
+	sched.mcount++
+	checkmcount()
+	mpreinit(mp)
+	if mp.gsignal != nil {
+		mp.gsignal.stackguard1 = mp.gsignal.stack.lo + _StackGuard
+	}
+
+	// Add to allm so garbage collector doesn't free g->m
+	// when it is just in a register or thread-local storage.
+	mp.alllink = allm
+
+	// NumCgoCall() iterates over allm w/o schedlock,
+	// so we need to publish it safely.
+	atomicstorep(unsafe.Pointer(&allm), unsafe.Pointer(mp))
+	unlock(&sched.lock)
+}
+
+// Mark gp ready to run.
+func ready(gp *g, traceskip int) {
+	if trace.enabled {
+		traceGoUnpark(gp, traceskip)
+	}
+
+	status := readgstatus(gp)
+
+	// Mark runnable.
+	_g_ := getg()
+	_g_.m.locks++ // disable preemption because it can be holding p in a local var
+	if status&^_Gscan != _Gwaiting {
+		dumpgstatus(gp)
+		throw("bad g->status in ready")
+	}
+
+	// status is Gwaiting or Gscanwaiting, make Grunnable and put on runq
+	casgstatus(gp, _Gwaiting, _Grunnable)
+	runqput(_g_.m.p.ptr(), gp, true)
+	if atomicload(&sched.npidle) != 0 && atomicload(&sched.nmspinning) == 0 { // TODO: fast atomic
+		wakep()
+	}
+	_g_.m.locks--
+	if _g_.m.locks == 0 && _g_.preempt { // restore the preemption request in case we've cleared it in newstack
+		_g_.stackguard0 = stackPreempt
+	}
+}
+
+func gcprocs() int32 {
+	// Figure out how many CPUs to use during GC.
+	// Limited by gomaxprocs, number of actual CPUs, and MaxGcproc.
+	lock(&sched.lock)
+	n := gomaxprocs
+	if n > ncpu {
+		n = ncpu
+	}
+	if n > _MaxGcproc {
+		n = _MaxGcproc
+	}
+	if n > sched.nmidle+1 { // one M is currently running
+		n = sched.nmidle + 1
+	}
+	unlock(&sched.lock)
+	return n
+}
+
+func needaddgcproc() bool {
+	lock(&sched.lock)
+	n := gomaxprocs
+	if n > ncpu {
+		n = ncpu
+	}
+	if n > _MaxGcproc {
+		n = _MaxGcproc
+	}
+	n -= sched.nmidle + 1 // one M is currently running
+	unlock(&sched.lock)
+	return n > 0
+}
+
+func helpgc(nproc int32) {
+	_g_ := getg()
+	lock(&sched.lock)
+	pos := 0
+	for n := int32(1); n < nproc; n++ { // one M is currently running
+		if allp[pos].mcache == _g_.m.mcache {
+			pos++
+		}
+		mp := mget()
+		if mp == nil {
+			throw("gcprocs inconsistency")
+		}
+		mp.helpgc = n
+		mp.p.set(allp[pos])
+		mp.mcache = allp[pos].mcache
+		pos++
+		notewakeup(&mp.park)
+	}
+	unlock(&sched.lock)
+}
+
+// freezeStopWait is a large value that freezetheworld sets
+// sched.stopwait to in order to request that all Gs permanently stop.
+const freezeStopWait = 0x7fffffff
+
+// Similar to stopTheWorld but best-effort and can be called several times.
+// There is no reverse operation, used during crashing.
+// This function must not lock any mutexes.
+func freezetheworld() {
+	// stopwait and preemption requests can be lost
+	// due to races with concurrently executing threads,
+	// so try several times
+	for i := 0; i < 5; i++ {
+		// this should tell the scheduler to not start any new goroutines
+		sched.stopwait = freezeStopWait
+		atomicstore(&sched.gcwaiting, 1)
+		// this should stop running goroutines
+		if !preemptall() {
+			break // no running goroutines
+		}
+		usleep(1000)
+	}
+	// to be sure
+	usleep(1000)
+	preemptall()
+	usleep(1000)
+}
+
+func isscanstatus(status uint32) bool {
+	if status == _Gscan {
+		throw("isscanstatus: Bad status Gscan")
+	}
+	return status&_Gscan == _Gscan
+}
+
+// All reads and writes of g's status go through readgstatus, casgstatus
+// castogscanstatus, casfrom_Gscanstatus.
+//go:nosplit
+func readgstatus(gp *g) uint32 {
+	return atomicload(&gp.atomicstatus)
+}
+
+// Ownership of gscanvalid:
+//
+// If gp is running (meaning status == _Grunning or _Grunning|_Gscan),
+// then gp owns gp.gscanvalid, and other goroutines must not modify it.
+//
+// Otherwise, a second goroutine can lock the scan state by setting _Gscan
+// in the status bit and then modify gscanvalid, and then unlock the scan state.
+//
+// Note that the first condition implies an exception to the second:
+// if a second goroutine changes gp's status to _Grunning|_Gscan,
+// that second goroutine still does not have the right to modify gscanvalid.
+
+// The Gscanstatuses are acting like locks and this releases them.
+// If it proves to be a performance hit we should be able to make these
+// simple atomic stores but for now we are going to throw if
+// we see an inconsistent state.
+func casfrom_Gscanstatus(gp *g, oldval, newval uint32) {
+	success := false
+
+	// Check that transition is valid.
+	switch oldval {
+	default:
+		print("runtime: casfrom_Gscanstatus bad oldval gp=", gp, ", oldval=", hex(oldval), ", newval=", hex(newval), "\n")
+		dumpgstatus(gp)
+		throw("casfrom_Gscanstatus:top gp->status is not in scan state")
+	case _Gscanrunnable,
+		_Gscanwaiting,
+		_Gscanrunning,
+		_Gscansyscall:
+		if newval == oldval&^_Gscan {
+			success = cas(&gp.atomicstatus, oldval, newval)
+		}
+	case _Gscanenqueue:
+		if newval == _Gwaiting {
+			success = cas(&gp.atomicstatus, oldval, newval)
+		}
+	}
+	if !success {
+		print("runtime: casfrom_Gscanstatus failed gp=", gp, ", oldval=", hex(oldval), ", newval=", hex(newval), "\n")
+		dumpgstatus(gp)
+		throw("casfrom_Gscanstatus: gp->status is not in scan state")
+	}
+	if newval == _Grunning {
+		gp.gcscanvalid = false
+	}
+}
+
+// This will return false if the gp is not in the expected status and the cas fails.
+// This acts like a lock acquire while the casfromgstatus acts like a lock release.
+func castogscanstatus(gp *g, oldval, newval uint32) bool {
+	switch oldval {
+	case _Grunnable,
+		_Gwaiting,
+		_Gsyscall:
+		if newval == oldval|_Gscan {
+			return cas(&gp.atomicstatus, oldval, newval)
+		}
+	case _Grunning:
+		if newval == _Gscanrunning || newval == _Gscanenqueue {
+			return cas(&gp.atomicstatus, oldval, newval)
+		}
+	}
+	print("runtime: castogscanstatus oldval=", hex(oldval), " newval=", hex(newval), "\n")
+	throw("castogscanstatus")
+	panic("not reached")
+}
+
+// If asked to move to or from a Gscanstatus this will throw. Use the castogscanstatus
+// and casfrom_Gscanstatus instead.
+// casgstatus will loop if the g->atomicstatus is in a Gscan status until the routine that
+// put it in the Gscan state is finished.
+//go:nosplit
+func casgstatus(gp *g, oldval, newval uint32) {
+	if (oldval&_Gscan != 0) || (newval&_Gscan != 0) || oldval == newval {
+		systemstack(func() {
+			print("runtime: casgstatus: oldval=", hex(oldval), " newval=", hex(newval), "\n")
+			throw("casgstatus: bad incoming values")
+		})
+	}
+
+	if oldval == _Grunning && gp.gcscanvalid {
+		// If oldvall == _Grunning, then the actual status must be
+		// _Grunning or _Grunning|_Gscan; either way,
+		// we own gp.gcscanvalid, so it's safe to read.
+		// gp.gcscanvalid must not be true when we are running.
+		print("runtime: casgstatus ", hex(oldval), "->", hex(newval), " gp.status=", hex(gp.atomicstatus), " gp.gcscanvalid=true\n")
+		throw("casgstatus")
+	}
+
+	// loop if gp->atomicstatus is in a scan state giving
+	// GC time to finish and change the state to oldval.
+	for !cas(&gp.atomicstatus, oldval, newval) {
+		if oldval == _Gwaiting && gp.atomicstatus == _Grunnable {
+			systemstack(func() {
+				throw("casgstatus: waiting for Gwaiting but is Grunnable")
+			})
+		}
+		// Help GC if needed.
+		// if gp.preemptscan && !gp.gcworkdone && (oldval == _Grunning || oldval == _Gsyscall) {
+		// 	gp.preemptscan = false
+		// 	systemstack(func() {
+		// 		gcphasework(gp)
+		// 	})
+		// }
+	}
+	if newval == _Grunning {
+		gp.gcscanvalid = false
+	}
+}
+
+// casgstatus(gp, oldstatus, Gcopystack), assuming oldstatus is Gwaiting or Grunnable.
+// Returns old status. Cannot call casgstatus directly, because we are racing with an
+// async wakeup that might come in from netpoll. If we see Gwaiting from the readgstatus,
+// it might have become Grunnable by the time we get to the cas. If we called casgstatus,
+// it would loop waiting for the status to go back to Gwaiting, which it never will.
+//go:nosplit
+func casgcopystack(gp *g) uint32 {
+	for {
+		oldstatus := readgstatus(gp) &^ _Gscan
+		if oldstatus != _Gwaiting && oldstatus != _Grunnable {
+			throw("copystack: bad status, not Gwaiting or Grunnable")
+		}
+		if cas(&gp.atomicstatus, oldstatus, _Gcopystack) {
+			return oldstatus
+		}
+	}
+}
+
+// scang blocks until gp's stack has been scanned.
+// It might be scanned by scang or it might be scanned by the goroutine itself.
+// Either way, the stack scan has completed when scang returns.
+func scang(gp *g) {
+	// Invariant; we (the caller, markroot for a specific goroutine) own gp.gcscandone.
+	// Nothing is racing with us now, but gcscandone might be set to true left over
+	// from an earlier round of stack scanning (we scan twice per GC).
+	// We use gcscandone to record whether the scan has been done during this round.
+	// It is important that the scan happens exactly once: if called twice,
+	// the installation of stack barriers will detect the double scan and die.
+
+	gp.gcscandone = false
+
+	// Endeavor to get gcscandone set to true,
+	// either by doing the stack scan ourselves or by coercing gp to scan itself.
+	// gp.gcscandone can transition from false to true when we're not looking
+	// (if we asked for preemption), so any time we lock the status using
+	// castogscanstatus we have to double-check that the scan is still not done.
+	for !gp.gcscandone {
+		switch s := readgstatus(gp); s {
+		default:
+			dumpgstatus(gp)
+			throw("stopg: invalid status")
+
+		case _Gdead:
+			// No stack.
+			gp.gcscandone = true
+
+		case _Gcopystack:
+			// Stack being switched. Go around again.
+
+		case _Grunnable, _Gsyscall, _Gwaiting:
+			// Claim goroutine by setting scan bit.
+			// Racing with execution or readying of gp.
+			// The scan bit keeps them from running
+			// the goroutine until we're done.
+			if castogscanstatus(gp, s, s|_Gscan) {
+				if !gp.gcscandone {
+					// Coordinate with traceback
+					// in sigprof.
+					for !cas(&gp.stackLock, 0, 1) {
+						osyield()
+					}
+					scanstack(gp)
+					atomicstore(&gp.stackLock, 0)
+					gp.gcscandone = true
+				}
+				restartg(gp)
+			}
+
+		case _Gscanwaiting:
+			// newstack is doing a scan for us right now. Wait.
+
+		case _Grunning:
+			// Goroutine running. Try to preempt execution so it can scan itself.
+			// The preemption handler (in newstack) does the actual scan.
+
+			// Optimization: if there is already a pending preemption request
+			// (from the previous loop iteration), don't bother with the atomics.
+			if gp.preemptscan && gp.preempt && gp.stackguard0 == stackPreempt {
+				break
+			}
+
+			// Ask for preemption and self scan.
+			if castogscanstatus(gp, _Grunning, _Gscanrunning) {
+				if !gp.gcscandone {
+					gp.preemptscan = true
+					gp.preempt = true
+					gp.stackguard0 = stackPreempt
+				}
+				casfrom_Gscanstatus(gp, _Gscanrunning, _Grunning)
+			}
+		}
+	}
+
+	gp.preemptscan = false // cancel scan request if no longer needed
+}
+
+// The GC requests that this routine be moved from a scanmumble state to a mumble state.
+func restartg(gp *g) {
+	s := readgstatus(gp)
+	switch s {
+	default:
+		dumpgstatus(gp)
+		throw("restartg: unexpected status")
+
+	case _Gdead:
+		// ok
+
+	case _Gscanrunnable,
+		_Gscanwaiting,
+		_Gscansyscall:
+		casfrom_Gscanstatus(gp, s, s&^_Gscan)
+
+	// Scan is now completed.
+	// Goroutine now needs to be made runnable.
+	// We put it on the global run queue; ready blocks on the global scheduler lock.
+	case _Gscanenqueue:
+		casfrom_Gscanstatus(gp, _Gscanenqueue, _Gwaiting)
+		if gp != getg().m.curg {
+			throw("processing Gscanenqueue on wrong m")
+		}
+		dropg()
+		ready(gp, 0)
+	}
+}
+
+// stopTheWorld stops all P's from executing goroutines, interrupting
+// all goroutines at GC safe points and records reason as the reason
+// for the stop. On return, only the current goroutine's P is running.
+// stopTheWorld must not be called from a system stack and the caller
+// must not hold worldsema. The caller must call startTheWorld when
+// other P's should resume execution.
+//
+// stopTheWorld is safe for multiple goroutines to call at the
+// same time. Each will execute its own stop, and the stops will
+// be serialized.
+//
+// This is also used by routines that do stack dumps. If the system is
+// in panic or being exited, this may not reliably stop all
+// goroutines.
+func stopTheWorld(reason string) {
+	semacquire(&worldsema, false)
+	getg().m.preemptoff = reason
+	systemstack(stopTheWorldWithSema)
+}
+
+// startTheWorld undoes the effects of stopTheWorld.
+func startTheWorld() {
+	systemstack(startTheWorldWithSema)
+	// worldsema must be held over startTheWorldWithSema to ensure
+	// gomaxprocs cannot change while worldsema is held.
+	semrelease(&worldsema)
+	getg().m.preemptoff = ""
+}
+
+// Holding worldsema grants an M the right to try to stop the world
+// and prevents gomaxprocs from changing concurrently.
+var worldsema uint32 = 1
+
+// stopTheWorldWithSema is the core implementation of stopTheWorld.
+// The caller is responsible for acquiring worldsema and disabling
+// preemption first and then should stopTheWorldWithSema on the system
+// stack:
+//
+//	semacquire(&worldsema, false)
+//	m.preemptoff = "reason"
+//	systemstack(stopTheWorldWithSema)
+//
+// When finished, the caller must either call startTheWorld or undo
+// these three operations separately:
+//
+//	m.preemptoff = ""
+//	systemstack(startTheWorldWithSema)
+//	semrelease(&worldsema)
+//
+// It is allowed to acquire worldsema once and then execute multiple
+// startTheWorldWithSema/stopTheWorldWithSema pairs.
+// Other P's are able to execute between successive calls to
+// startTheWorldWithSema and stopTheWorldWithSema.
+// Holding worldsema causes any other goroutines invoking
+// stopTheWorld to block.
+func stopTheWorldWithSema() {
+	_g_ := getg()
+
+	// If we hold a lock, then we won't be able to stop another M
+	// that is blocked trying to acquire the lock.
+	if _g_.m.locks > 0 {
+		throw("stopTheWorld: holding locks")
+	}
+
+	lock(&sched.lock)
+	sched.stopwait = gomaxprocs
+	atomicstore(&sched.gcwaiting, 1)
+	preemptall()
+	// stop current P
+	_g_.m.p.ptr().status = _Pgcstop // Pgcstop is only diagnostic.
+	sched.stopwait--
+	// try to retake all P's in Psyscall status
+	for i := 0; i < int(gomaxprocs); i++ {
+		p := allp[i]
+		s := p.status
+		if s == _Psyscall && cas(&p.status, s, _Pgcstop) {
+			if trace.enabled {
+				traceGoSysBlock(p)
+				traceProcStop(p)
+			}
+			p.syscalltick++
+			sched.stopwait--
+		}
+	}
+	// stop idle P's
+	for {
+		p := pidleget()
+		if p == nil {
+			break
+		}
+		p.status = _Pgcstop
+		sched.stopwait--
+	}
+	wait := sched.stopwait > 0
+	unlock(&sched.lock)
+
+	// wait for remaining P's to stop voluntarily
+	if wait {
+		for {
+			// wait for 100us, then try to re-preempt in case of any races
+			if notetsleep(&sched.stopnote, 100*1000) {
+				noteclear(&sched.stopnote)
+				break
+			}
+			preemptall()
+		}
+	}
+	if sched.stopwait != 0 {
+		throw("stopTheWorld: not stopped")
+	}
+	for i := 0; i < int(gomaxprocs); i++ {
+		p := allp[i]
+		if p.status != _Pgcstop {
+			throw("stopTheWorld: not stopped")
+		}
+	}
+}
+
+func mhelpgc() {
+	_g_ := getg()
+	_g_.m.helpgc = -1
+}
+
+func startTheWorldWithSema() {
+	_g_ := getg()
+
+	_g_.m.locks++        // disable preemption because it can be holding p in a local var
+	gp := netpoll(false) // non-blocking
+	injectglist(gp)
+	add := needaddgcproc()
+	lock(&sched.lock)
+
+	procs := gomaxprocs
+	if newprocs != 0 {
+		procs = newprocs
+		newprocs = 0
+	}
+	p1 := procresize(procs)
+	sched.gcwaiting = 0
+	if sched.sysmonwait != 0 {
+		sched.sysmonwait = 0
+		notewakeup(&sched.sysmonnote)
+	}
+	unlock(&sched.lock)
+
+	for p1 != nil {
+		p := p1
+		p1 = p1.link.ptr()
+		if p.m != 0 {
+			mp := p.m.ptr()
+			p.m = 0
+			if mp.nextp != 0 {
+				throw("startTheWorld: inconsistent mp->nextp")
+			}
+			mp.nextp.set(p)
+			notewakeup(&mp.park)
+		} else {
+			// Start M to run P.  Do not start another M below.
+			newm(nil, p)
+			add = false
+		}
+	}
+
+	// Wakeup an additional proc in case we have excessive runnable goroutines
+	// in local queues or in the global queue. If we don't, the proc will park itself.
+	// If we have lots of excessive work, resetspinning will unpark additional procs as necessary.
+	if atomicload(&sched.npidle) != 0 && atomicload(&sched.nmspinning) == 0 {
+		wakep()
+	}
+
+	if add {
+		// If GC could have used another helper proc, start one now,
+		// in the hope that it will be available next time.
+		// It would have been even better to start it before the collection,
+		// but doing so requires allocating memory, so it's tricky to
+		// coordinate.  This lazy approach works out in practice:
+		// we don't mind if the first couple gc rounds don't have quite
+		// the maximum number of procs.
+		newm(mhelpgc, nil)
+	}
+	_g_.m.locks--
+	if _g_.m.locks == 0 && _g_.preempt { // restore the preemption request in case we've cleared it in newstack
+		_g_.stackguard0 = stackPreempt
+	}
+}
+
+// Called to start an M.
+//go:nosplit
+func mstart() {
+	_g_ := getg()
+
+	if _g_.stack.lo == 0 {
+		// Initialize stack bounds from system stack.
+		// Cgo may have left stack size in stack.hi.
+		size := _g_.stack.hi
+		if size == 0 {
+			size = 8192 * stackGuardMultiplier
+		}
+		_g_.stack.hi = uintptr(noescape(unsafe.Pointer(&size)))
+		_g_.stack.lo = _g_.stack.hi - size + 1024
+	}
+	// Initialize stack guards so that we can start calling
+	// both Go and C functions with stack growth prologues.
+	_g_.stackguard0 = _g_.stack.lo + _StackGuard
+	_g_.stackguard1 = _g_.stackguard0
+	mstart1()
+}
+
+func mstart1() {
+	_g_ := getg()
+
+	if _g_ != _g_.m.g0 {
+		throw("bad runtime·mstart")
+	}
+
+	// Record top of stack for use by mcall.
+	// Once we call schedule we're never coming back,
+	// so other calls can reuse this stack space.
+	gosave(&_g_.m.g0.sched)
+	_g_.m.g0.sched.pc = ^uintptr(0) // make sure it is never used
+	asminit()
+	minit()
+
+	// 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 fn := _g_.m.mstartfn; fn != nil {
+		fn()
+	}
+
+	if _g_.m.helpgc != 0 {
+		_g_.m.helpgc = 0
+		stopm()
+	} else if _g_.m != &m0 {
+		acquirep(_g_.m.nextp.ptr())
+		_g_.m.nextp = 0
+	}
+	schedule()
+}
+
+// forEachP calls fn(p) for every P p when p reaches a GC safe point.
+// If a P is currently executing code, this will bring the P to a GC
+// safe point and execute fn on that P. If the P is not executing code
+// (it is idle or in a syscall), this will call fn(p) directly while
+// preventing the P from exiting its state. This does not ensure that
+// fn will run on every CPU executing Go code, but it acts as a global
+// memory barrier. GC uses this as a "ragged barrier."
+//
+// The caller must hold worldsema.
+func forEachP(fn func(*p)) {
+	mp := acquirem()
+	_p_ := getg().m.p.ptr()
+
+	lock(&sched.lock)
+	if sched.safePointWait != 0 {
+		throw("forEachP: sched.safePointWait != 0")
+	}
+	sched.safePointWait = gomaxprocs - 1
+	sched.safePointFn = fn
+
+	// Ask all Ps to run the safe point function.
+	for _, p := range allp[:gomaxprocs] {
+		if p != _p_ {
+			atomicstore(&p.runSafePointFn, 1)
+		}
+	}
+	preemptall()
+
+	// Any P entering _Pidle or _Psyscall from now on will observe
+	// p.runSafePointFn == 1 and will call runSafePointFn when
+	// changing its status to _Pidle/_Psyscall.
+
+	// Run safe point function for all idle Ps. sched.pidle will
+	// not change because we hold sched.lock.
+	for p := sched.pidle.ptr(); p != nil; p = p.link.ptr() {
+		if cas(&p.runSafePointFn, 1, 0) {
+			fn(p)
+			sched.safePointWait--
+		}
+	}
+
+	wait := sched.safePointWait > 0
+	unlock(&sched.lock)
+
+	// Run fn for the current P.
+	fn(_p_)
+
+	// Force Ps currently in _Psyscall into _Pidle and hand them
+	// off to induce safe point function execution.
+	for i := 0; i < int(gomaxprocs); i++ {
+		p := allp[i]
+		s := p.status
+		if s == _Psyscall && p.runSafePointFn == 1 && cas(&p.status, s, _Pidle) {
+			if trace.enabled {
+				traceGoSysBlock(p)
+				traceProcStop(p)
+			}
+			p.syscalltick++
+			handoffp(p)
+		}
+	}
+
+	// Wait for remaining Ps to run fn.
+	if wait {
+		for {
+			// Wait for 100us, then try to re-preempt in
+			// case of any races.
+			if notetsleep(&sched.safePointNote, 100*1000) {
+				noteclear(&sched.safePointNote)
+				break
+			}
+			preemptall()
+		}
+	}
+	if sched.safePointWait != 0 {
+		throw("forEachP: not done")
+	}
+	for i := 0; i < int(gomaxprocs); i++ {
+		p := allp[i]
+		if p.runSafePointFn != 0 {
+			throw("forEachP: P did not run fn")
+		}
+	}
+
+	lock(&sched.lock)
+	sched.safePointFn = nil
+	unlock(&sched.lock)
+	releasem(mp)
+}
+
+// runSafePointFn runs the safe point function, if any, for this P.
+// This should be called like
+//
+//     if getg().m.p.runSafePointFn != 0 {
+//         runSafePointFn()
+//     }
+//
+// runSafePointFn must be checked on any transition in to _Pidle or
+// _Psyscall to avoid a race where forEachP sees that the P is running
+// just before the P goes into _Pidle/_Psyscall and neither forEachP
+// nor the P run the safe-point function.
+func runSafePointFn() {
+	p := getg().m.p.ptr()
+	// Resolve the race between forEachP running the safe-point
+	// function on this P's behalf and this P running the
+	// safe-point function directly.
+	if !cas(&p.runSafePointFn, 1, 0) {
+		return
+	}
+	sched.safePointFn(p)
+	lock(&sched.lock)
+	sched.safePointWait--
+	if sched.safePointWait == 0 {
+		notewakeup(&sched.safePointNote)
+	}
+	unlock(&sched.lock)
+}
+
+// When running with cgo, we call _cgo_thread_start
+// to start threads for us so that we can play nicely with
+// foreign code.
+var cgoThreadStart unsafe.Pointer
+
+type cgothreadstart struct {
+	g   guintptr
+	tls *uint64
+	fn  unsafe.Pointer
+}
+
+// Allocate a new m unassociated with any thread.
+// Can use p for allocation context if needed.
+// fn is recorded as the new m's m.mstartfn.
+func allocm(_p_ *p, fn func()) *m {
+	_g_ := getg()
+	_g_.m.locks++ // disable GC because it can be called from sysmon
+	if _g_.m.p == 0 {
+		acquirep(_p_) // temporarily borrow p for mallocs in this function
+	}
+	mp := new(m)
+	mp.mstartfn = fn
+	mcommoninit(mp)
+
+	// In case of cgo or Solaris, pthread_create will make us a stack.
+	// Windows and Plan 9 will layout sched stack on OS stack.
+	if iscgo || GOOS == "solaris" || GOOS == "windows" || GOOS == "plan9" {
+		mp.g0 = malg(-1)
+	} else {
+		mp.g0 = malg(8192 * stackGuardMultiplier)
+	}
+	mp.g0.m = mp
+
+	if _p_ == _g_.m.p.ptr() {
+		releasep()
+	}
+	_g_.m.locks--
+	if _g_.m.locks == 0 && _g_.preempt { // restore the preemption request in case we've cleared it in newstack
+		_g_.stackguard0 = stackPreempt
+	}
+
+	return mp
+}
+
+// needm is called when a cgo callback happens on a
+// thread without an m (a thread not created by Go).
+// In this case, needm is expected to find an m to use
+// and return with m, g initialized correctly.
+// Since m and g are not set now (likely nil, but see below)
+// needm is limited in what routines it can call. In particular
+// it can only call nosplit functions (textflag 7) and cannot
+// do any scheduling that requires an m.
+//
+// In order to avoid needing heavy lifting here, we adopt
+// the following strategy: there is a stack of available m's
+// that can be stolen. Using compare-and-swap
+// to pop from the stack has ABA races, so we simulate
+// a lock by doing an exchange (via casp) to steal the stack
+// head and replace the top pointer with MLOCKED (1).
+// This serves as a simple spin lock that we can use even
+// without an m. The thread that locks the stack in this way
+// unlocks the stack by storing a valid stack head pointer.
+//
+// In order to make sure that there is always an m structure
+// available to be stolen, we maintain the invariant that there
+// is always one more than needed. At the beginning of the
+// program (if cgo is in use) the list is seeded with a single m.
+// If needm finds that it has taken the last m off the list, its job
+// is - once it has installed its own m so that it can do things like
+// allocate memory - to create a spare m and put it on the list.
+//
+// Each of these extra m's also has a g0 and a curg that are
+// pressed into service as the scheduling stack and current
+// goroutine for the duration of the cgo callback.
+//
+// When the callback is done with the m, it calls dropm to
+// put the m back on the list.
+//go:nosplit
+func needm(x byte) {
+	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)))
+		exit(1)
+	}
+
+	// Lock extra list, take head, unlock popped list.
+	// nilokay=false is safe here because of the invariant above,
+	// that the extra list always contains or will soon contain
+	// at least one m.
+	mp := lockextra(false)
+
+	// Set needextram when we've just emptied the list,
+	// so that the eventual call into cgocallbackg will
+	// allocate a new m for the extra list. We delay the
+	// allocation until then so that it can be done
+	// after exitsyscall makes sure it is okay to be
+	// running at all (that is, there's no garbage collection
+	// running right now).
+	mp.needextram = mp.schedlink == 0
+	unlockextra(mp.schedlink.ptr())
+
+	// Install g (= m->g0) and set the stack bounds
+	// to match the current stack. We don't actually know
+	// how big the stack is, like we don't know how big any
+	// scheduling stack is, but we assume there's at least 32 kB,
+	// which is more than enough for us.
+	setg(mp.g0)
+	_g_ := getg()
+	_g_.stack.hi = uintptr(noescape(unsafe.Pointer(&x))) + 1024
+	_g_.stack.lo = uintptr(noescape(unsafe.Pointer(&x))) - 32*1024
+	_g_.stackguard0 = _g_.stack.lo + _StackGuard
+
+	msigsave(mp)
+	// Initialize this thread to use the m.
+	asminit()
+	minit()
+}
+
+var earlycgocallback = []byte("fatal error: cgo callback before cgo call\n")
+
+// newextram allocates an m and puts it on the extra list.
+// It is called with a working local m, so that it can do things
+// like call schedlock and allocate.
+func newextram() {
+	// Create extra goroutine locked to extra m.
+	// The goroutine is the context in which the cgo callback will run.
+	// The sched.pc will never be returned to, but setting it to
+	// goexit makes clear to the traceback routines where
+	// the goroutine stack ends.
+	mp := allocm(nil, nil)
+	gp := malg(4096)
+	gp.sched.pc = funcPC(goexit) + _PCQuantum
+	gp.sched.sp = gp.stack.hi
+	gp.sched.sp -= 4 * regSize // extra space in case of reads slightly beyond frame
+	gp.sched.lr = 0
+	gp.sched.g = guintptr(unsafe.Pointer(gp))
+	gp.syscallpc = gp.sched.pc
+	gp.syscallsp = gp.sched.sp
+	// malg returns status as Gidle, change to Gsyscall before adding to allg
+	// where GC will see it.
+	casgstatus(gp, _Gidle, _Gsyscall)
+	gp.m = mp
+	mp.curg = gp
+	mp.locked = _LockInternal
+	mp.lockedg = gp
+	gp.lockedm = mp
+	gp.goid = int64(xadd64(&sched.goidgen, 1))
+	if raceenabled {
+		gp.racectx = racegostart(funcPC(newextram))
+	}
+	// put on allg for garbage collector
+	allgadd(gp)
+
+	// Add m to the extra list.
+	mnext := lockextra(true)
+	mp.schedlink.set(mnext)
+	unlockextra(mp)
+}
+
+// dropm is called when a cgo callback has called needm but is now
+// done with the callback and returning back into the non-Go thread.
+// It puts the current m back onto the extra list.
+//
+// The main expense here is the call to signalstack to release the
+// m's signal stack, and then the call to needm on the next callback
+// from this thread. It is tempting to try to save the m for next time,
+// which would eliminate both these costs, but there might not be
+// a next time: the current thread (which Go does not control) might exit.
+// If we saved the m for that thread, there would be an m leak each time
+// such a thread exited. Instead, we acquire and release an m on each
+// call. These should typically not be scheduling operations, just a few
+// atomics, so the cost should be small.
+//
+// TODO(rsc): An alternative would be to allocate a dummy pthread per-thread
+// variable using pthread_key_create. Unlike the pthread keys we already use
+// on OS X, this dummy key would never be read by Go code. It would exist
+// only so that we could register at thread-exit-time destructor.
+// That destructor would put the m back onto the extra list.
+// This is purely a performance optimization. The current version,
+// in which dropm happens on each cgo call, is still correct too.
+// We may have to keep the current version on systems with cgo
+// but without pthreads, like Windows.
+func dropm() {
+	// Undo whatever initialization minit did during needm.
+	unminit()
+
+	// Clear m and g, and return m to the extra list.
+	// After the call to setg we can only call nosplit functions
+	// with no pointer manipulation.
+	mp := getg().m
+	mnext := lockextra(true)
+	mp.schedlink.set(mnext)
+
+	setg(nil)
+	unlockextra(mp)
+}
+
+var extram uintptr
+
+// lockextra locks the extra list and returns the list head.
+// The caller must unlock the list by storing a new list head
+// to extram. If nilokay is true, then lockextra will
+// return a nil list head if that's what it finds. If nilokay is false,
+// lockextra will keep waiting until the list head is no longer nil.
+//go:nosplit
+func lockextra(nilokay bool) *m {
+	const locked = 1
+
+	for {
+		old := atomicloaduintptr(&extram)
+		if old == locked {
+			yield := osyield
+			yield()
+			continue
+		}
+		if old == 0 && !nilokay {
+			usleep(1)
+			continue
+		}
+		if casuintptr(&extram, old, locked) {
+			return (*m)(unsafe.Pointer(old))
+		}
+		yield := osyield
+		yield()
+		continue
+	}
+}
+
+//go:nosplit
+func unlockextra(mp *m) {
+	atomicstoreuintptr(&extram, uintptr(unsafe.Pointer(mp)))
+}
+
+// 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_, fn)
+	mp.nextp.set(_p_)
+	msigsave(mp)
+	if iscgo {
+		var ts cgothreadstart
+		if _cgo_thread_start == nil {
+			throw("_cgo_thread_start missing")
+		}
+		ts.g.set(mp.g0)
+		ts.tls = (*uint64)(unsafe.Pointer(&mp.tls[0]))
+		ts.fn = unsafe.Pointer(funcPC(mstart))
+		asmcgocall(_cgo_thread_start, unsafe.Pointer(&ts))
+		return
+	}
+	newosproc(mp, unsafe.Pointer(mp.g0.stack.hi))
+}
+
+// Stops execution of the current m until new work is available.
+// Returns with acquired P.
+func stopm() {
+	_g_ := getg()
+
+	if _g_.m.locks != 0 {
+		throw("stopm holding locks")
+	}
+	if _g_.m.p != 0 {
+		throw("stopm holding p")
+	}
+	if _g_.m.spinning {
+		_g_.m.spinning = false
+		xadd(&sched.nmspinning, -1)
+	}
+
+retry:
+	lock(&sched.lock)
+	mput(_g_.m)
+	unlock(&sched.lock)
+	notesleep(&_g_.m.park)
+	noteclear(&_g_.m.park)
+	if _g_.m.helpgc != 0 {
+		gchelper()
+		_g_.m.helpgc = 0
+		_g_.m.mcache = nil
+		_g_.m.p = 0
+		goto retry
+	}
+	acquirep(_g_.m.nextp.ptr())
+	_g_.m.nextp = 0
+}
+
+func mspinning() {
+	gp := getg()
+	if !runqempty(gp.m.nextp.ptr()) {
+		// Something (presumably the GC) was readied while the
+		// runtime was starting up this M, so the M is no
+		// longer spinning.
+		if int32(xadd(&sched.nmspinning, -1)) < 0 {
+			throw("mspinning: nmspinning underflowed")
+		}
+	} else {
+		gp.m.spinning = true
+	}
+}
+
+// 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 {
+		_p_ = pidleget()
+		if _p_ == nil {
+			unlock(&sched.lock)
+			if spinning {
+				xadd(&sched.nmspinning, -1)
+			}
+			return
+		}
+	}
+	mp := mget()
+	unlock(&sched.lock)
+	if mp == nil {
+		var fn func()
+		if spinning {
+			fn = mspinning
+		}
+		newm(fn, _p_)
+		return
+	}
+	if mp.spinning {
+		throw("startm: m is spinning")
+	}
+	if mp.nextp != 0 {
+		throw("startm: m has p")
+	}
+	if spinning && !runqempty(_p_) {
+		throw("startm: p has runnable gs")
+	}
+	mp.spinning = spinning
+	mp.nextp.set(_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 !runqempty(_p_) || sched.runqsize != 0 {
+		startm(_p_, false)
+		return
+	}
+	// no local work, check that there are no spinning/idle M's,
+	// otherwise our help is not required
+	if atomicload(&sched.nmspinning)+atomicload(&sched.npidle) == 0 && cas(&sched.nmspinning, 0, 1) { // TODO: fast atomic
+		startm(_p_, true)
+		return
+	}
+	lock(&sched.lock)
+	if sched.gcwaiting != 0 {
+		_p_.status = _Pgcstop
+		sched.stopwait--
+		if sched.stopwait == 0 {
+			notewakeup(&sched.stopnote)
+		}
+		unlock(&sched.lock)
+		return
+	}
+	if _p_.runSafePointFn != 0 && cas(&_p_.runSafePointFn, 1, 0) {
+		sched.safePointFn(_p_)
+		sched.safePointWait--
+		if sched.safePointWait == 0 {
+			notewakeup(&sched.safePointNote)
+		}
+	}
+	if sched.runqsize != 0 {
+		unlock(&sched.lock)
+		startm(_p_, false)
+		return
+	}
+	// If this is the last running P and nobody is polling network,
+	// need to wakeup another M to poll network.
+	if sched.npidle == uint32(gomaxprocs-1) && atomicload64(&sched.lastpoll) != 0 {
+		unlock(&sched.lock)
+		startm(_p_, false)
+		return
+	}
+	pidleput(_p_)
+	unlock(&sched.lock)
+}
+
+// Tries to add one more P to execute G's.
+// Called when a G is made runnable (newproc, ready).
+func wakep() {
+	// be conservative about spinning threads
+	if !cas(&sched.nmspinning, 0, 1) {
+		return
+	}
+	startm(nil, true)
+}
+
+// Stops execution of the current m that is locked to a g until the g is runnable again.
+// Returns with acquired P.
+func stoplockedm() {
+	_g_ := getg()
+
+	if _g_.m.lockedg == nil || _g_.m.lockedg.lockedm != _g_.m {
+		throw("stoplockedm: inconsistent locking")
+	}
+	if _g_.m.p != 0 {
+		// Schedule another M to run this p.
+		_p_ := releasep()
+		handoffp(_p_)
+	}
+	incidlelocked(1)
+	// Wait until another thread schedules lockedg again.
+	notesleep(&_g_.m.park)
+	noteclear(&_g_.m.park)
+	status := readgstatus(_g_.m.lockedg)
+	if status&^_Gscan != _Grunnable {
+		print("runtime:stoplockedm: g is not Grunnable or Gscanrunnable\n")
+		dumpgstatus(_g_)
+		throw("stoplockedm: not runnable")
+	}
+	acquirep(_g_.m.nextp.ptr())
+	_g_.m.nextp = 0
+}
+
+// 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()
+
+	mp := gp.lockedm
+	if mp == _g_.m {
+		throw("startlockedm: locked to me")
+	}
+	if mp.nextp != 0 {
+		throw("startlockedm: m has p")
+	}
+	// directly handoff current P to the locked m
+	incidlelocked(-1)
+	_p_ := releasep()
+	mp.nextp.set(_p_)
+	notewakeup(&mp.park)
+	stopm()
+}
+
+// Stops the current m for stopTheWorld.
+// Returns when the world is restarted.
+func gcstopm() {
+	_g_ := getg()
+
+	if sched.gcwaiting == 0 {
+		throw("gcstopm: not waiting for gc")
+	}
+	if _g_.m.spinning {
+		_g_.m.spinning = false
+		xadd(&sched.nmspinning, -1)
+	}
+	_p_ := releasep()
+	lock(&sched.lock)
+	_p_.status = _Pgcstop
+	sched.stopwait--
+	if sched.stopwait == 0 {
+		notewakeup(&sched.stopnote)
+	}
+	unlock(&sched.lock)
+	stopm()
+}
+
+// Schedules gp to run on the current M.
+// If inheritTime is true, gp inherits the remaining time in the
+// current time slice. Otherwise, it starts a new time slice.
+// Never returns.
+func execute(gp *g, inheritTime bool) {
+	_g_ := getg()
+
+	casgstatus(gp, _Grunnable, _Grunning)
+	gp.waitsince = 0
+	gp.preempt = false
+	gp.stackguard0 = gp.stack.lo + _StackGuard
+	if !inheritTime {
+		_g_.m.p.ptr().schedtick++
+	}
+	_g_.m.curg = gp
+	gp.m = _g_.m
+
+	// Check whether the profiler needs to be turned on or off.
+	hz := sched.profilehz
+	if _g_.m.profilehz != hz {
+		resetcpuprofiler(hz)
+	}
+
+	if trace.enabled {
+		// GoSysExit has to happen when we have a P, but before GoStart.
+		// So we emit it here.
+		if gp.syscallsp != 0 && gp.sysblocktraced {
+			// Since gp.sysblocktraced is true, we must emit an event.
+			// There is a race between the code that initializes sysexitseq
+			// and sysexitticks (in exitsyscall, which runs without a P,
+			// and therefore is not stopped with the rest of the world)
+			// and the code that initializes a new trace.
+			// The recorded sysexitseq and sysexitticks must therefore
+			// be treated as "best effort". If they are valid for this trace,
+			// then great, use them for greater accuracy.
+			// But if they're not valid for this trace, assume that the
+			// trace was started after the actual syscall exit (but before
+			// we actually managed to start the goroutine, aka right now),
+			// and assign a fresh time stamp to keep the log consistent.
+			seq, ts := gp.sysexitseq, gp.sysexitticks
+			if seq == 0 || int64(seq)-int64(trace.seqStart) < 0 {
+				seq, ts = tracestamp()
+			}
+			traceGoSysExit(seq, ts)
+		}
+		traceGoStart()
+	}
+
+	gogo(&gp.sched)
+}
+
+// Finds a runnable goroutine to execute.
+// Tries to steal from other P's, get g from global queue, poll network.
+func findrunnable() (gp *g, inheritTime bool) {
+	_g_ := getg()
+
+top:
+	if sched.gcwaiting != 0 {
+		gcstopm()
+		goto top
+	}
+	if _g_.m.p.ptr().runSafePointFn != 0 {
+		runSafePointFn()
+	}
+	if fingwait && fingwake {
+		if gp := wakefing(); gp != nil {
+			ready(gp, 0)
+		}
+	}
+
+	// local runq
+	if gp, inheritTime := runqget(_g_.m.p.ptr()); gp != nil {
+		return gp, inheritTime
+	}
+
+	// global runq
+	if sched.runqsize != 0 {
+		lock(&sched.lock)
+		gp := globrunqget(_g_.m.p.ptr(), 0)
+		unlock(&sched.lock)
+		if gp != nil {
+			return gp, false
+		}
+	}
+
+	// Poll network.
+	// This netpoll is only an optimization before we resort to stealing.
+	// We can safely skip it if there a thread blocked in netpoll already.
+	// If there is any kind of logical race with that blocked thread
+	// (e.g. it has already returned from netpoll, but does not set lastpoll yet),
+	// this thread will do blocking netpoll below anyway.
+	if netpollinited() && sched.lastpoll != 0 {
+		if gp := netpoll(false); gp != nil { // non-blocking
+			// netpoll returns list of goroutines linked by schedlink.
+			injectglist(gp.schedlink.ptr())
+			casgstatus(gp, _Gwaiting, _Grunnable)
+			if trace.enabled {
+				traceGoUnpark(gp, 0)
+			}
+			return gp, false
+		}
+	}
+
+	// If number of spinning M's >= number of busy P's, block.
+	// This is necessary to prevent excessive CPU consumption
+	// when GOMAXPROCS>>1 but the program parallelism is low.
+	if !_g_.m.spinning && 2*atomicload(&sched.nmspinning) >= uint32(gomaxprocs)-atomicload(&sched.npidle) { // TODO: fast atomic
+		goto stop
+	}
+	if !_g_.m.spinning {
+		_g_.m.spinning = true
+		xadd(&sched.nmspinning, 1)
+	}
+	// random steal from other P's
+	for i := 0; i < int(4*gomaxprocs); i++ {
+		if sched.gcwaiting != 0 {
+			goto top
+		}
+		_p_ := allp[fastrand1()%uint32(gomaxprocs)]
+		var gp *g
+		if _p_ == _g_.m.p.ptr() {
+			gp, _ = runqget(_p_)
+		} else {
+			stealRunNextG := i > 2*int(gomaxprocs) // first look for ready queues with more than 1 g
+			gp = runqsteal(_g_.m.p.ptr(), _p_, stealRunNextG)
+		}
+		if gp != nil {
+			return gp, false
+		}
+	}
+
+stop:
+
+	// We have nothing to do. If we're in the GC mark phase and can
+	// safely scan and blacken objects, run idle-time marking
+	// rather than give up the P.
+	if _p_ := _g_.m.p.ptr(); gcBlackenEnabled != 0 && _p_.gcBgMarkWorker != nil && gcMarkWorkAvailable(_p_) {
+		_p_.gcMarkWorkerMode = gcMarkWorkerIdleMode
+		gp := _p_.gcBgMarkWorker
+		casgstatus(gp, _Gwaiting, _Grunnable)
+		if trace.enabled {
+			traceGoUnpark(gp, 0)
+		}
+		return gp, false
+	}
+
+	// return P and block
+	lock(&sched.lock)
+	if sched.gcwaiting != 0 || _g_.m.p.ptr().runSafePointFn != 0 {
+		unlock(&sched.lock)
+		goto top
+	}
+	if sched.runqsize != 0 {
+		gp := globrunqget(_g_.m.p.ptr(), 0)
+		unlock(&sched.lock)
+		return gp, false
+	}
+	_p_ := releasep()
+	pidleput(_p_)
+	unlock(&sched.lock)
+	if _g_.m.spinning {
+		_g_.m.spinning = false
+		xadd(&sched.nmspinning, -1)
+	}
+
+	// check all runqueues once again
+	for i := 0; i < int(gomaxprocs); i++ {
+		_p_ := allp[i]
+		if _p_ != nil && !runqempty(_p_) {
+			lock(&sched.lock)
+			_p_ = pidleget()
+			unlock(&sched.lock)
+			if _p_ != nil {
+				acquirep(_p_)
+				goto top
+			}
+			break
+		}
+	}
+
+	// poll network
+	if netpollinited() && xchg64(&sched.lastpoll, 0) != 0 {
+		if _g_.m.p != 0 {
+			throw("findrunnable: netpoll with p")
+		}
+		if _g_.m.spinning {
+			throw("findrunnable: netpoll with spinning")
+		}
+		gp := netpoll(true) // block until new work is available
+		atomicstore64(&sched.lastpoll, uint64(nanotime()))
+		if gp != nil {
+			lock(&sched.lock)
+			_p_ = pidleget()
+			unlock(&sched.lock)
+			if _p_ != nil {
+				acquirep(_p_)
+				injectglist(gp.schedlink.ptr())
+				casgstatus(gp, _Gwaiting, _Grunnable)
+				if trace.enabled {
+					traceGoUnpark(gp, 0)
+				}
+				return gp, false
+			}
+			injectglist(gp)
+		}
+	}
+	stopm()
+	goto top
+}
+
+func resetspinning() {
+	_g_ := getg()
+
+	var nmspinning uint32
+	if _g_.m.spinning {
+		_g_.m.spinning = false
+		nmspinning = xadd(&sched.nmspinning, -1)
+		if nmspinning < 0 {
+			throw("findrunnable: negative nmspinning")
+		}
+	} else {
+		nmspinning = atomicload(&sched.nmspinning)
+	}
+
+	// M wakeup policy is deliberately somewhat conservative (see nmspinning handling),
+	// so see if we need to wakeup another P here.
+	if nmspinning == 0 && atomicload(&sched.npidle) > 0 {
+		wakep()
+	}
+}
+
+// Injects the list of runnable G's into the scheduler.
+// Can run concurrently with GC.
+func injectglist(glist *g) {
+	if glist == nil {
+		return
+	}
+	if trace.enabled {
+		for gp := glist; gp != nil; gp = gp.schedlink.ptr() {
+			traceGoUnpark(gp, 0)
+		}
+	}
+	lock(&sched.lock)
+	var n int
+	for n = 0; glist != nil; n++ {
+		gp := glist
+		glist = gp.schedlink.ptr()
+		casgstatus(gp, _Gwaiting, _Grunnable)
+		globrunqput(gp)
+	}
+	unlock(&sched.lock)
+	for ; n != 0 && sched.npidle != 0; n-- {
+		startm(nil, false)
+	}
+}
+
+// One round of scheduler: find a runnable goroutine and execute it.
+// Never returns.
+func schedule() {
+	_g_ := getg()
+
+	if _g_.m.locks != 0 {
+		throw("schedule: holding locks")
+	}
+
+	if _g_.m.lockedg != nil {
+		stoplockedm()
+		execute(_g_.m.lockedg, false) // Never returns.
+	}
+
+top:
+	if sched.gcwaiting != 0 {
+		gcstopm()
+		goto top
+	}
+	if _g_.m.p.ptr().runSafePointFn != 0 {
+		runSafePointFn()
+	}
+
+	var gp *g
+	var inheritTime bool
+	if trace.enabled || trace.shutdown {
+		gp = traceReader()
+		if gp != nil {
+			casgstatus(gp, _Gwaiting, _Grunnable)
+			traceGoUnpark(gp, 0)
+			resetspinning()
+		}
+	}
+	if gp == nil && gcBlackenEnabled != 0 {
+		gp = gcController.findRunnableGCWorker(_g_.m.p.ptr())
+		if gp != nil {
+			resetspinning()
+		}
+	}
+	if gp == nil {
+		// Check the global runnable queue once in a while to ensure fairness.
+		// Otherwise two goroutines can completely occupy the local runqueue
+		// by constantly respawning each other.
+		if _g_.m.p.ptr().schedtick%61 == 0 && sched.runqsize > 0 {
+			lock(&sched.lock)
+			gp = globrunqget(_g_.m.p.ptr(), 1)
+			unlock(&sched.lock)
+			if gp != nil {
+				resetspinning()
+			}
+		}
+	}
+	if gp == nil {
+		gp, inheritTime = runqget(_g_.m.p.ptr())
+		if gp != nil && _g_.m.spinning {
+			throw("schedule: spinning with local work")
+		}
+	}
+	if gp == nil {
+		gp, inheritTime = findrunnable() // blocks until work is available
+		resetspinning()
+	}
+
+	if gp.lockedm != nil {
+		// Hands off own p to the locked m,
+		// then blocks waiting for a new p.
+		startlockedm(gp)
+		goto top
+	}
+
+	execute(gp, inheritTime)
+}
+
+// dropg removes the association between m and the current goroutine m->curg (gp for short).
+// Typically a caller sets gp's status away from Grunning and then
+// immediately calls dropg to finish the job. The caller is also responsible
+// for arranging that gp will be restarted using ready at an
+// appropriate time. After calling dropg and arranging for gp to be
+// readied later, the caller can do other work but eventually should
+// call schedule to restart the scheduling of goroutines on this m.
+func dropg() {
+	_g_ := getg()
+
+	if _g_.m.lockedg == nil {
+		_g_.m.curg.m = nil
+		_g_.m.curg = nil
+	}
+}
+
+func parkunlock_c(gp *g, lock unsafe.Pointer) bool {
+	unlock((*mutex)(lock))
+	return true
+}
+
+// park continuation on g0.
+func park_m(gp *g) {
+	_g_ := getg()
+
+	if trace.enabled {
+		traceGoPark(_g_.m.waittraceev, _g_.m.waittraceskip, gp)
+	}
+
+	casgstatus(gp, _Grunning, _Gwaiting)
+	dropg()
+
+	if _g_.m.waitunlockf != nil {
+		fn := *(*func(*g, unsafe.Pointer) bool)(unsafe.Pointer(&_g_.m.waitunlockf))
+		ok := fn(gp, _g_.m.waitlock)
+		_g_.m.waitunlockf = nil
+		_g_.m.waitlock = nil
+		if !ok {
+			if trace.enabled {
+				traceGoUnpark(gp, 2)
+			}
+			casgstatus(gp, _Gwaiting, _Grunnable)
+			execute(gp, true) // Schedule it back, never returns.
+		}
+	}
+	schedule()
+}
+
+func goschedImpl(gp *g) {
+	status := readgstatus(gp)
+	if status&^_Gscan != _Grunning {
+		dumpgstatus(gp)
+		throw("bad g status")
+	}
+	casgstatus(gp, _Grunning, _Grunnable)
+	dropg()
+	lock(&sched.lock)
+	globrunqput(gp)
+	unlock(&sched.lock)
+
+	schedule()
+}
+
+// Gosched continuation on g0.
+func gosched_m(gp *g) {
+	if trace.enabled {
+		traceGoSched()
+	}
+	goschedImpl(gp)
+}
+
+func gopreempt_m(gp *g) {
+	if trace.enabled {
+		traceGoPreempt()
+	}
+	goschedImpl(gp)
+}
+
+// Finishes execution of the current goroutine.
+func goexit1() {
+	if raceenabled {
+		racegoend()
+	}
+	if trace.enabled {
+		traceGoEnd()
+	}
+	mcall(goexit0)
+}
+
+// goexit continuation on g0.
+func goexit0(gp *g) {
+	_g_ := getg()
+
+	casgstatus(gp, _Grunning, _Gdead)
+	gp.m = nil
+	gp.lockedm = nil
+	_g_.m.lockedg = nil
+	gp.paniconfault = false
+	gp._defer = nil // should be true already but just in case.
+	gp._panic = nil // non-nil for Goexit during panic. points at stack-allocated data.
+	gp.writebuf = nil
+	gp.waitreason = ""
+	gp.param = nil
+
+	dropg()
+
+	if _g_.m.locked&^_LockExternal != 0 {
+		print("invalid m->locked = ", _g_.m.locked, "\n")
+		throw("internal lockOSThread error")
+	}
+	_g_.m.locked = 0
+	gfput(_g_.m.p.ptr(), gp)
+	schedule()
+}
+
+//go:nosplit
+//go:nowritebarrier
+func save(pc, sp uintptr) {
+	_g_ := getg()
+
+	_g_.sched.pc = pc
+	_g_.sched.sp = sp
+	_g_.sched.lr = 0
+	_g_.sched.ret = 0
+	_g_.sched.ctxt = nil
+	_g_.sched.g = guintptr(unsafe.Pointer(_g_))
+}
+
+// The goroutine g is about to enter a system call.
+// Record that it's not using the cpu anymore.
+// This is called only from the go syscall library and cgocall,
+// not from the low-level system calls used by the
+//
+// Entersyscall cannot split the stack: the gosave must
+// make g->sched refer to the caller's stack segment, because
+// entersyscall is going to return immediately after.
+//
+// Nothing entersyscall calls can split the stack either.
+// We cannot safely move the stack during an active call to syscall,
+// because we do not know which of the uintptr arguments are
+// really pointers (back into the stack).
+// In practice, this means that we make the fast path run through
+// entersyscall doing no-split things, and the slow path has to use systemstack
+// to run bigger things on the system stack.
+//
+// reentersyscall is the entry point used by cgo callbacks, where explicitly
+// saved SP and PC are restored. This is needed when exitsyscall will be called
+// from a function further up in the call stack than the parent, as g->syscallsp
+// must always point to a valid stack frame. entersyscall below is the normal
+// entry point for syscalls, which obtains the SP and PC from the caller.
+//
+// Syscall tracing:
+// At the start of a syscall we emit traceGoSysCall to capture the stack trace.
+// If the syscall does not block, that is it, we do not emit any other events.
+// If the syscall blocks (that is, P is retaken), retaker emits traceGoSysBlock;
+// when syscall returns we emit traceGoSysExit and when the goroutine starts running
+// (potentially instantly, if exitsyscallfast returns true) we emit traceGoStart.
+// To ensure that traceGoSysExit is emitted strictly after traceGoSysBlock,
+// we remember current value of syscalltick in m (_g_.m.syscalltick = _g_.m.p.ptr().syscalltick),
+// whoever emits traceGoSysBlock increments p.syscalltick afterwards;
+// and we wait for the increment before emitting traceGoSysExit.
+// Note that the increment is done even if tracing is not enabled,
+// because tracing can be enabled in the middle of syscall. We don't want the wait to hang.
+//
+//go:nosplit
+func reentersyscall(pc, sp uintptr) {
+	_g_ := getg()
+
+	// Disable preemption because during this function g is in Gsyscall status,
+	// but can have inconsistent g->sched, do not let GC observe it.
+	_g_.m.locks++
+
+	if trace.enabled {
+		systemstack(traceGoSysCall)
+	}
+
+	// Entersyscall must not call any function that might split/grow the stack.
+	// (See details in comment above.)
+	// Catch calls that might, by replacing the stack guard with something that
+	// will trip any stack check and leaving a flag to tell newstack to die.
+	_g_.stackguard0 = stackPreempt
+	_g_.throwsplit = true
+
+	// Leave SP around for GC and traceback.
+	save(pc, sp)
+	_g_.syscallsp = sp
+	_g_.syscallpc = pc
+	casgstatus(_g_, _Grunning, _Gsyscall)
+	if _g_.syscallsp < _g_.stack.lo || _g_.stack.hi < _g_.syscallsp {
+		systemstack(func() {
+			print("entersyscall inconsistent ", hex(_g_.syscallsp), " [", hex(_g_.stack.lo), ",", hex(_g_.stack.hi), "]\n")
+			throw("entersyscall")
+		})
+	}
+
+	if atomicload(&sched.sysmonwait) != 0 { // TODO: fast atomic
+		systemstack(entersyscall_sysmon)
+		save(pc, sp)
+	}
+
+	if _g_.m.p.ptr().runSafePointFn != 0 {
+		// runSafePointFn may stack split if run on this stack
+		systemstack(runSafePointFn)
+		save(pc, sp)
+	}
+
+	_g_.m.syscalltick = _g_.m.p.ptr().syscalltick
+	_g_.sysblocktraced = true
+	_g_.m.mcache = nil
+	_g_.m.p.ptr().m = 0
+	atomicstore(&_g_.m.p.ptr().status, _Psyscall)
+	if sched.gcwaiting != 0 {
+		systemstack(entersyscall_gcwait)
+		save(pc, sp)
+	}
+
+	// Goroutines must not split stacks in Gsyscall status (it would corrupt g->sched).
+	// We set _StackGuard to StackPreempt so that first split stack check calls morestack.
+	// Morestack detects this case and throws.
+	_g_.stackguard0 = stackPreempt
+	_g_.m.locks--
+}
+
+// Standard syscall entry used by the go syscall library and normal cgo calls.
+//go:nosplit
+func entersyscall(dummy int32) {
+	reentersyscall(getcallerpc(unsafe.Pointer(&dummy)), getcallersp(unsafe.Pointer(&dummy)))
+}
+
+func entersyscall_sysmon() {
+	lock(&sched.lock)
+	if atomicload(&sched.sysmonwait) != 0 {
+		atomicstore(&sched.sysmonwait, 0)
+		notewakeup(&sched.sysmonnote)
+	}
+	unlock(&sched.lock)
+}
+
+func entersyscall_gcwait() {
+	_g_ := getg()
+	_p_ := _g_.m.p.ptr()
+
+	lock(&sched.lock)
+	if sched.stopwait > 0 && cas(&_p_.status, _Psyscall, _Pgcstop) {
+		if trace.enabled {
+			traceGoSysBlock(_p_)
+			traceProcStop(_p_)
+		}
+		_p_.syscalltick++
+		if sched.stopwait--; sched.stopwait == 0 {
+			notewakeup(&sched.stopnote)
+		}
+	}
+	unlock(&sched.lock)
+}
+
+// The same as entersyscall(), but with a hint that the syscall is blocking.
+//go:nosplit
+func entersyscallblock(dummy int32) {
+	_g_ := getg()
+
+	_g_.m.locks++ // see comment in entersyscall
+	_g_.throwsplit = true
+	_g_.stackguard0 = stackPreempt // see comment in entersyscall
+	_g_.m.syscalltick = _g_.m.p.ptr().syscalltick
+	_g_.sysblocktraced = true
+	_g_.m.p.ptr().syscalltick++
+
+	// Leave SP around for GC and traceback.
+	pc := getcallerpc(unsafe.Pointer(&dummy))
+	sp := getcallersp(unsafe.Pointer(&dummy))
+	save(pc, sp)
+	_g_.syscallsp = _g_.sched.sp
+	_g_.syscallpc = _g_.sched.pc
+	if _g_.syscallsp < _g_.stack.lo || _g_.stack.hi < _g_.syscallsp {
+		sp1 := sp
+		sp2 := _g_.sched.sp
+		sp3 := _g_.syscallsp
+		systemstack(func() {
+			print("entersyscallblock inconsistent ", hex(sp1), " ", hex(sp2), " ", hex(sp3), " [", hex(_g_.stack.lo), ",", hex(_g_.stack.hi), "]\n")
+			throw("entersyscallblock")
+		})
+	}
+	casgstatus(_g_, _Grunning, _Gsyscall)
+	if _g_.syscallsp < _g_.stack.lo || _g_.stack.hi < _g_.syscallsp {
+		systemstack(func() {
+			print("entersyscallblock inconsistent ", hex(sp), " ", hex(_g_.sched.sp), " ", hex(_g_.syscallsp), " [", hex(_g_.stack.lo), ",", hex(_g_.stack.hi), "]\n")
+			throw("entersyscallblock")
+		})
+	}
+
+	systemstack(entersyscallblock_handoff)
+
+	// Resave for traceback during blocked call.
+	save(getcallerpc(unsafe.Pointer(&dummy)), getcallersp(unsafe.Pointer(&dummy)))
+
+	_g_.m.locks--
+}
+
+func entersyscallblock_handoff() {
+	if trace.enabled {
+		traceGoSysCall()
+		traceGoSysBlock(getg().m.p.ptr())
+	}
+	handoffp(releasep())
+}
+
+// The goroutine g exited its system call.
+// Arrange for it to run on a cpu again.
+// This is called only from the go syscall library, not
+// from the low-level system calls used by the
+//go:nosplit
+func exitsyscall(dummy int32) {
+	_g_ := getg()
+
+	_g_.m.locks++ // see comment in entersyscall
+	if getcallersp(unsafe.Pointer(&dummy)) > _g_.syscallsp {
+		throw("exitsyscall: syscall frame is no longer valid")
+	}
+
+	_g_.waitsince = 0
+	oldp := _g_.m.p.ptr()
+	if exitsyscallfast() {
+		if _g_.m.mcache == nil {
+			throw("lost mcache")
+		}
+		if trace.enabled {
+			if oldp != _g_.m.p.ptr() || _g_.m.syscalltick != _g_.m.p.ptr().syscalltick {
+				systemstack(traceGoStart)
+			}
+		}
+		// There's a cpu for us, so we can run.
+		_g_.m.p.ptr().syscalltick++
+		// We need to cas the status and scan before resuming...
+		casgstatus(_g_, _Gsyscall, _Grunning)
+
+		// Garbage collector isn't running (since we are),
+		// so okay to clear syscallsp.
+		_g_.syscallsp = 0
+		_g_.m.locks--
+		if _g_.preempt {
+			// restore the preemption request in case we've cleared it in newstack
+			_g_.stackguard0 = stackPreempt
+		} else {
+			// otherwise restore the real _StackGuard, we've spoiled it in entersyscall/entersyscallblock
+			_g_.stackguard0 = _g_.stack.lo + _StackGuard
+		}
+		_g_.throwsplit = false
+		return
+	}
+
+	_g_.sysexitticks = 0
+	_g_.sysexitseq = 0
+	if trace.enabled {
+		// Wait till traceGoSysBlock event is emitted.
+		// This ensures consistency of the trace (the goroutine is started after it is blocked).
+		for oldp != nil && oldp.syscalltick == _g_.m.syscalltick {
+			osyield()
+		}
+		// We can't trace syscall exit right now because we don't have a P.
+		// Tracing code can invoke write barriers that cannot run without a P.
+		// So instead we remember the syscall exit time and emit the event
+		// in execute when we have a P.
+		_g_.sysexitseq, _g_.sysexitticks = tracestamp()
+	}
+
+	_g_.m.locks--
+
+	// Call the scheduler.
+	mcall(exitsyscall0)
+
+	if _g_.m.mcache == nil {
+		throw("lost mcache")
+	}
+
+	// Scheduler returned, so we're allowed to run now.
+	// Delete the syscallsp information that we left for
+	// the garbage collector during the system call.
+	// Must wait until now because until gosched returns
+	// we don't know for sure that the garbage collector
+	// is not running.
+	_g_.syscallsp = 0
+	_g_.m.p.ptr().syscalltick++
+	_g_.throwsplit = false
+}
+
+//go:nosplit
+func exitsyscallfast() bool {
+	_g_ := getg()
+
+	// Freezetheworld sets stopwait but does not retake P's.
+	if sched.stopwait == freezeStopWait {
+		_g_.m.mcache = nil
+		_g_.m.p = 0
+		return false
+	}
+
+	// Try to re-acquire the last P.
+	if _g_.m.p != 0 && _g_.m.p.ptr().status == _Psyscall && cas(&_g_.m.p.ptr().status, _Psyscall, _Prunning) {
+		// There's a cpu for us, so we can run.
+		_g_.m.mcache = _g_.m.p.ptr().mcache
+		_g_.m.p.ptr().m.set(_g_.m)
+		if _g_.m.syscalltick != _g_.m.p.ptr().syscalltick {
+			if trace.enabled {
+				// The p was retaken and then enter into syscall again (since _g_.m.syscalltick has changed).
+				// traceGoSysBlock for this syscall was already emitted,
+				// but here we effectively retake the p from the new syscall running on the same p.
+				systemstack(func() {
+					// Denote blocking of the new syscall.
+					traceGoSysBlock(_g_.m.p.ptr())
+					// Denote completion of the current syscall.
+					traceGoSysExit(tracestamp())
+				})
+			}
+			_g_.m.p.ptr().syscalltick++
+		}
+		return true
+	}
+
+	// Try to get any other idle P.
+	oldp := _g_.m.p.ptr()
+	_g_.m.mcache = nil
+	_g_.m.p = 0
+	if sched.pidle != 0 {
+		var ok bool
+		systemstack(func() {
+			ok = exitsyscallfast_pidle()
+			if ok && trace.enabled {
+				if oldp != nil {
+					// Wait till traceGoSysBlock event is emitted.
+					// This ensures consistency of the trace (the goroutine is started after it is blocked).
+					for oldp.syscalltick == _g_.m.syscalltick {
+						osyield()
+					}
+				}
+				traceGoSysExit(tracestamp())
+			}
+		})
+		if ok {
+			return true
+		}
+	}
+	return false
+}
+
+func exitsyscallfast_pidle() bool {
+	lock(&sched.lock)
+	_p_ := pidleget()
+	if _p_ != nil && atomicload(&sched.sysmonwait) != 0 {
+		atomicstore(&sched.sysmonwait, 0)
+		notewakeup(&sched.sysmonnote)
+	}
+	unlock(&sched.lock)
+	if _p_ != nil {
+		acquirep(_p_)
+		return true
+	}
+	return false
+}
+
+// exitsyscall slow path on g0.
+// Failed to acquire P, enqueue gp as runnable.
+func exitsyscall0(gp *g) {
+	_g_ := getg()
+
+	casgstatus(gp, _Gsyscall, _Grunnable)
+	dropg()
+	lock(&sched.lock)
+	_p_ := pidleget()
+	if _p_ == nil {
+		globrunqput(gp)
+	} else if atomicload(&sched.sysmonwait) != 0 {
+		atomicstore(&sched.sysmonwait, 0)
+		notewakeup(&sched.sysmonnote)
+	}
+	unlock(&sched.lock)
+	if _p_ != nil {
+		acquirep(_p_)
+		execute(gp, false) // Never returns.
+	}
+	if _g_.m.lockedg != nil {
+		// Wait until another thread schedules gp and so m again.
+		stoplockedm()
+		execute(gp, false) // Never returns.
+	}
+	stopm()
+	schedule() // Never returns.
+}
+
+func beforefork() {
+	gp := getg().m.curg
+
+	// Fork can hang if preempted with signals frequently enough (see issue 5517).
+	// Ensure that we stay on the same M where we disable profiling.
+	gp.m.locks++
+	if gp.m.profilehz != 0 {
+		resetcpuprofiler(0)
+	}
+
+	// This function is called before fork in syscall package.
+	// Code between fork and exec must not allocate memory nor even try to grow stack.
+	// Here we spoil g->_StackGuard to reliably detect any attempts to grow stack.
+	// runtime_AfterFork will undo this in parent process, but not in child.
+	gp.stackguard0 = stackFork
+}
+
+// Called from syscall package before fork.
+//go:linkname syscall_runtime_BeforeFork syscall.runtime_BeforeFork
+//go:nosplit
+func syscall_runtime_BeforeFork() {
+	systemstack(beforefork)
+}
+
+func afterfork() {
+	gp := getg().m.curg
+
+	// See the comment in beforefork.
+	gp.stackguard0 = gp.stack.lo + _StackGuard
+
+	hz := sched.profilehz
+	if hz != 0 {
+		resetcpuprofiler(hz)
+	}
+	gp.m.locks--
+}
+
+// Called from syscall package after fork in parent.
+//go:linkname syscall_runtime_AfterFork syscall.runtime_AfterFork
+//go:nosplit
+func syscall_runtime_AfterFork() {
+	systemstack(afterfork)
+}
+
+// Allocate a new g, with a stack big enough for stacksize bytes.
+func malg(stacksize int32) *g {
+	newg := new(g)
+	if stacksize >= 0 {
+		stacksize = round2(_StackSystem + stacksize)
+		systemstack(func() {
+			newg.stack, newg.stkbar = stackalloc(uint32(stacksize))
+		})
+		newg.stackguard0 = newg.stack.lo + _StackGuard
+		newg.stackguard1 = ^uintptr(0)
+		newg.stackAlloc = uintptr(stacksize)
+	}
+	return newg
+}
+
+// Create a new g running fn with siz bytes of arguments.
+// Put it on the queue of g's waiting to run.
+// The compiler turns a go statement into a call to this.
+// Cannot split the stack because it assumes that the arguments
+// are available sequentially after &fn; they would not be
+// copied if a stack split occurred.
+//go:nosplit
+func newproc(siz int32, fn *funcval) {
+	argp := add(unsafe.Pointer(&fn), ptrSize)
+	pc := getcallerpc(unsafe.Pointer(&siz))
+	systemstack(func() {
+		newproc1(fn, (*uint8)(argp), siz, 0, pc)
+	})
+}
+
+// Create a new g running fn with narg bytes of arguments starting
+// at argp and returning nret bytes of results.  callerpc is the
+// address of the go statement that created this.  The new g is put
+// on the queue of g's waiting to run.
+func newproc1(fn *funcval, argp *uint8, narg int32, nret int32, callerpc uintptr) *g {
+	_g_ := getg()
+
+	if fn == nil {
+		_g_.m.throwing = -1 // do not dump full stacks
+		throw("go of nil func value")
+	}
+	_g_.m.locks++ // disable preemption because it can be holding p in a local var
+	siz := narg + nret
+	siz = (siz + 7) &^ 7
+
+	// We could allocate a larger initial stack if necessary.
+	// Not worth it: this is almost always an error.
+	// 4*sizeof(uintreg): extra space added below
+	// sizeof(uintreg): caller's LR (arm) or return address (x86, in gostartcall).
+	if siz >= _StackMin-4*regSize-regSize {
+		throw("newproc: function arguments too large for new goroutine")
+	}
+
+	_p_ := _g_.m.p.ptr()
+	newg := gfget(_p_)
+	if newg == nil {
+		newg = malg(_StackMin)
+		casgstatus(newg, _Gidle, _Gdead)
+		allgadd(newg) // publishes with a g->status of Gdead so GC scanner doesn't look at uninitialized stack.
+	}
+	if newg.stack.hi == 0 {
+		throw("newproc1: newg missing stack")
+	}
+
+	if readgstatus(newg) != _Gdead {
+		throw("newproc1: new g is not Gdead")
+	}
+
+	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
+		*(*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
+	newg.sched.pc = funcPC(goexit) + _PCQuantum // +PCQuantum so that previous instruction is in same function
+	newg.sched.g = guintptr(unsafe.Pointer(newg))
+	gostartcallfn(&newg.sched, fn)
+	newg.gopc = callerpc
+	newg.startpc = fn.fn
+	casgstatus(newg, _Gdead, _Grunnable)
+
+	if _p_.goidcache == _p_.goidcacheend {
+		// Sched.goidgen is the last allocated id,
+		// this batch must be [sched.goidgen+1, sched.goidgen+GoidCacheBatch].
+		// At startup sched.goidgen=0, so main goroutine receives goid=1.
+		_p_.goidcache = xadd64(&sched.goidgen, _GoidCacheBatch)
+		_p_.goidcache -= _GoidCacheBatch - 1
+		_p_.goidcacheend = _p_.goidcache + _GoidCacheBatch
+	}
+	newg.goid = int64(_p_.goidcache)
+	_p_.goidcache++
+	if raceenabled {
+		newg.racectx = racegostart(callerpc)
+	}
+	if trace.enabled {
+		traceGoCreate(newg, newg.startpc)
+	}
+	runqput(_p_, newg, true)
+
+	if atomicload(&sched.npidle) != 0 && atomicload(&sched.nmspinning) == 0 && unsafe.Pointer(fn.fn) != unsafe.Pointer(funcPC(main)) { // TODO: fast atomic
+		wakep()
+	}
+	_g_.m.locks--
+	if _g_.m.locks == 0 && _g_.preempt { // restore the preemption request in case we've cleared it in newstack
+		_g_.stackguard0 = stackPreempt
+	}
+	return newg
+}
+
+// Put on gfree list.
+// If local list is too long, transfer a batch to the global list.
+func gfput(_p_ *p, gp *g) {
+	if readgstatus(gp) != _Gdead {
+		throw("gfput: bad status (not Gdead)")
+	}
+
+	stksize := gp.stackAlloc
+
+	if stksize != _FixedStack {
+		// non-standard stack size - free it.
+		stackfree(gp.stack, gp.stackAlloc)
+		gp.stack.lo = 0
+		gp.stack.hi = 0
+		gp.stackguard0 = 0
+		gp.stkbar = nil
+		gp.stkbarPos = 0
+	} else {
+		// Reset stack barriers.
+		gp.stkbar = gp.stkbar[:0]
+		gp.stkbarPos = 0
+	}
+
+	gp.schedlink.set(_p_.gfree)
+	_p_.gfree = gp
+	_p_.gfreecnt++
+	if _p_.gfreecnt >= 64 {
+		lock(&sched.gflock)
+		for _p_.gfreecnt >= 32 {
+			_p_.gfreecnt--
+			gp = _p_.gfree
+			_p_.gfree = gp.schedlink.ptr()
+			gp.schedlink.set(sched.gfree)
+			sched.gfree = gp
+			sched.ngfree++
+		}
+		unlock(&sched.gflock)
+	}
+}
+
+// Get from gfree list.
+// If local list is empty, grab a batch from global list.
+func gfget(_p_ *p) *g {
+retry:
+	gp := _p_.gfree
+	if gp == nil && sched.gfree != nil {
+		lock(&sched.gflock)
+		for _p_.gfreecnt < 32 && sched.gfree != nil {
+			_p_.gfreecnt++
+			gp = sched.gfree
+			sched.gfree = gp.schedlink.ptr()
+			sched.ngfree--
+			gp.schedlink.set(_p_.gfree)
+			_p_.gfree = gp
+		}
+		unlock(&sched.gflock)
+		goto retry
+	}
+	if gp != nil {
+		_p_.gfree = gp.schedlink.ptr()
+		_p_.gfreecnt--
+		if gp.stack.lo == 0 {
+			// Stack was deallocated in gfput.  Allocate a new one.
+			systemstack(func() {
+				gp.stack, gp.stkbar = stackalloc(_FixedStack)
+			})
+			gp.stackguard0 = gp.stack.lo + _StackGuard
+			gp.stackAlloc = _FixedStack
+		} else {
+			if raceenabled {
+				racemalloc(unsafe.Pointer(gp.stack.lo), gp.stackAlloc)
+			}
+		}
+	}
+	return gp
+}
+
+// Purge all cached G's from gfree list to the global list.
+func gfpurge(_p_ *p) {
+	lock(&sched.gflock)
+	for _p_.gfreecnt != 0 {
+		_p_.gfreecnt--
+		gp := _p_.gfree
+		_p_.gfree = gp.schedlink.ptr()
+		gp.schedlink.set(sched.gfree)
+		sched.gfree = gp
+		sched.ngfree++
+	}
+	unlock(&sched.gflock)
+}
+
+// Breakpoint executes a breakpoint trap.
+func Breakpoint() {
+	breakpoint()
+}
+
+// dolockOSThread is called by LockOSThread and lockOSThread below
+// after they modify m.locked. Do not allow preemption during this call,
+// or else the m might be different in this function than in the caller.
+//go:nosplit
+func dolockOSThread() {
+	_g_ := getg()
+	_g_.m.lockedg = _g_
+	_g_.lockedm = _g_.m
+}
+
+//go:nosplit
+
+// LockOSThread wires the calling goroutine to its current operating system thread.
+// Until the calling goroutine exits or calls UnlockOSThread, it will always
+// execute in that thread, and no other goroutine can.
+func LockOSThread() {
+	getg().m.locked |= _LockExternal
+	dolockOSThread()
+}
+
+//go:nosplit
+func lockOSThread() {
+	getg().m.locked += _LockInternal
+	dolockOSThread()
+}
+
+// dounlockOSThread is called by UnlockOSThread and unlockOSThread below
+// after they update m->locked. Do not allow preemption during this call,
+// or else the m might be in different in this function than in the caller.
+//go:nosplit
+func dounlockOSThread() {
+	_g_ := getg()
+	if _g_.m.locked != 0 {
+		return
+	}
+	_g_.m.lockedg = nil
+	_g_.lockedm = nil
+}
+
+//go:nosplit
+
+// UnlockOSThread unwires the calling goroutine from its fixed operating system thread.
+// If the calling goroutine has not called LockOSThread, UnlockOSThread is a no-op.
+func UnlockOSThread() {
+	getg().m.locked &^= _LockExternal
+	dounlockOSThread()
+}
+
+//go:nosplit
+func unlockOSThread() {
+	_g_ := getg()
+	if _g_.m.locked < _LockInternal {
+		systemstack(badunlockosthread)
+	}
+	_g_.m.locked -= _LockInternal
+	dounlockOSThread()
+}
+
+func badunlockosthread() {
+	throw("runtime: internal error: misuse of lockOSThread/unlockOSThread")
+}
+
+func gcount() int32 {
+	n := int32(allglen) - sched.ngfree
+	for i := 0; ; i++ {
+		_p_ := allp[i]
+		if _p_ == nil {
+			break
+		}
+		n -= _p_.gfreecnt
+	}
+
+	// All these variables can be changed concurrently, so the result can be inconsistent.
+	// But at least the current goroutine is running.
+	if n < 1 {
+		n = 1
+	}
+	return n
+}
+
+func mcount() int32 {
+	return sched.mcount
+}
+
+var prof struct {
+	lock uint32
+	hz   int32
+}
+
+func _System()       { _System() }
+func _ExternalCode() { _ExternalCode() }
+func _GC()           { _GC() }
+
+// Called if we receive a SIGPROF signal.
+func sigprof(pc, sp, lr uintptr, gp *g, mp *m) {
+	if prof.hz == 0 {
+		return
+	}
+
+	// Profiling runs concurrently with GC, so it must not allocate.
+	mp.mallocing++
+
+	// Coordinate with stack barrier insertion in scanstack.
+	for !cas(&gp.stackLock, 0, 1) {
+		osyield()
+	}
+
+	// Define that a "user g" is a user-created goroutine, and a "system g"
+	// is one that is m->g0 or m->gsignal.
+	//
+	// We might be interrupted for profiling halfway through a
+	// goroutine switch. The switch involves updating three (or four) values:
+	// g, PC, SP, and (on arm) LR. The PC must be the last to be updated,
+	// because once it gets updated the new g is running.
+	//
+	// When switching from a user g to a system g, LR is not considered live,
+	// so the update only affects g, SP, and PC. Since PC must be last, there
+	// the possible partial transitions in ordinary execution are (1) g alone is updated,
+	// (2) both g and SP are updated, and (3) SP alone is updated.
+	// If SP or g alone is updated, we can detect the partial transition by checking
+	// whether the SP is within g's stack bounds. (We could also require that SP
+	// be changed only after g, but the stack bounds check is needed by other
+	// cases, so there is no need to impose an additional requirement.)
+	//
+	// There is one exceptional transition to a system g, not in ordinary execution.
+	// When a signal arrives, the operating system starts the signal handler running
+	// with an updated PC and SP. The g is updated last, at the beginning of the
+	// handler. There are two reasons this is okay. First, until g is updated the
+	// g and SP do not match, so the stack bounds check detects the partial transition.
+	// Second, signal handlers currently run with signals disabled, so a profiling
+	// signal cannot arrive during the handler.
+	//
+	// When switching from a system g to a user g, there are three possibilities.
+	//
+	// First, it may be that the g switch has no PC update, because the SP
+	// either corresponds to a user g throughout (as in asmcgocall)
+	// or because it has been arranged to look like a user g frame
+	// (as in cgocallback_gofunc). In this case, since the entire
+	// transition is a g+SP update, a partial transition updating just one of
+	// those will be detected by the stack bounds check.
+	//
+	// Second, when returning from a signal handler, the PC and SP updates
+	// are performed by the operating system in an atomic update, so the g
+	// update must be done before them. The stack bounds check detects
+	// the partial transition here, and (again) signal handlers run with signals
+	// disabled, so a profiling signal cannot arrive then anyway.
+	//
+	// Third, the common case: it may be that the switch updates g, SP, and PC
+	// separately. If the PC is within any of the functions that does this,
+	// we don't ask for a traceback. C.F. the function setsSP for more about this.
+	//
+	// There is another apparently viable approach, recorded here in case
+	// the "PC within setsSP function" check turns out not to be usable.
+	// It would be possible to delay the update of either g or SP until immediately
+	// before the PC update instruction. Then, because of the stack bounds check,
+	// the only problematic interrupt point is just before that PC update instruction,
+	// and the sigprof handler can detect that instruction and simulate stepping past
+	// it in order to reach a consistent state. On ARM, the update of g must be made
+	// in two places (in R10 and also in a TLS slot), so the delayed update would
+	// need to be the SP update. The sigprof handler must read the instruction at
+	// the current PC and if it was the known instruction (for example, JMP BX or
+	// MOV R2, PC), use that other register in place of the PC value.
+	// The biggest drawback to this solution is that it requires that we can tell
+	// whether it's safe to read from the memory pointed at by PC.
+	// In a correct program, we can test PC == nil and otherwise read,
+	// but if a profiling signal happens at the instant that a program executes
+	// a bad jump (before the program manages to handle the resulting fault)
+	// the profiling handler could fault trying to read nonexistent memory.
+	//
+	// To recap, there are no constraints on the assembly being used for the
+	// transition. We simply require that g and SP match and that the PC is not
+	// in gogo.
+	traceback := true
+	if gp == nil || sp < gp.stack.lo || gp.stack.hi < sp || setsSP(pc) {
+		traceback = false
+	}
+	var stk [maxCPUProfStack]uintptr
+	n := 0
+	if mp.ncgo > 0 && mp.curg != nil && mp.curg.syscallpc != 0 && mp.curg.syscallsp != 0 {
+		// Cgo, we can't unwind and symbolize arbitrary C code,
+		// so instead collect Go stack that leads to the cgo call.
+		// This is especially important on windows, since all syscalls are cgo calls.
+		n = gentraceback(mp.curg.syscallpc, mp.curg.syscallsp, 0, mp.curg, 0, &stk[0], len(stk), nil, nil, 0)
+	} else if traceback {
+		n = gentraceback(pc, sp, lr, gp, 0, &stk[0], len(stk), nil, nil, _TraceTrap|_TraceJumpStack)
+	}
+	if !traceback || n <= 0 {
+		// Normal traceback is impossible or has failed.
+		// See if it falls into several common cases.
+		n = 0
+		if GOOS == "windows" && n == 0 && mp.libcallg != 0 && mp.libcallpc != 0 && mp.libcallsp != 0 {
+			// Libcall, i.e. runtime syscall on windows.
+			// Collect Go stack that leads to the call.
+			n = gentraceback(mp.libcallpc, mp.libcallsp, 0, mp.libcallg.ptr(), 0, &stk[0], len(stk), nil, nil, 0)
+		}
+		if n == 0 {
+			// If all of the above has failed, account it against abstract "System" or "GC".
+			n = 2
+			// "ExternalCode" is better than "etext".
+			if pc > firstmoduledata.etext {
+				pc = funcPC(_ExternalCode) + _PCQuantum
+			}
+			stk[0] = pc
+			if mp.preemptoff != "" || mp.helpgc != 0 {
+				stk[1] = funcPC(_GC) + _PCQuantum
+			} else {
+				stk[1] = funcPC(_System) + _PCQuantum
+			}
+		}
+	}
+	atomicstore(&gp.stackLock, 0)
+
+	if prof.hz != 0 {
+		// Simple cas-lock to coordinate with setcpuprofilerate.
+		for !cas(&prof.lock, 0, 1) {
+			osyield()
+		}
+		if prof.hz != 0 {
+			cpuprof.add(stk[:n])
+		}
+		atomicstore(&prof.lock, 0)
+	}
+	mp.mallocing--
+}
+
+// Reports whether a function will set the SP
+// to an absolute value. Important that
+// we don't traceback when these are at the bottom
+// of the stack since we can't be sure that we will
+// find the caller.
+//
+// If the function is not on the bottom of the stack
+// we assume that it will have set it up so that traceback will be consistent,
+// either by being a traceback terminating function
+// or putting one on the stack at the right offset.
+func setsSP(pc uintptr) bool {
+	f := findfunc(pc)
+	if f == nil {
+		// couldn't find the function for this PC,
+		// so assume the worst and stop traceback
+		return true
+	}
+	switch f.entry {
+	case gogoPC, systemstackPC, mcallPC, morestackPC:
+		return true
+	}
+	return false
+}
+
+// Arrange to call fn with a traceback hz times a second.
+func setcpuprofilerate_m(hz int32) {
+	// Force sane arguments.
+	if hz < 0 {
+		hz = 0
+	}
+
+	// Disable preemption, otherwise we can be rescheduled to another thread
+	// that has profiling enabled.
+	_g_ := getg()
+	_g_.m.locks++
+
+	// Stop profiler on this thread so that it is safe to lock prof.
+	// if a profiling signal came in while we had prof locked,
+	// it would deadlock.
+	resetcpuprofiler(0)
+
+	for !cas(&prof.lock, 0, 1) {
+		osyield()
+	}
+	prof.hz = hz
+	atomicstore(&prof.lock, 0)
+
+	lock(&sched.lock)
+	sched.profilehz = hz
+	unlock(&sched.lock)
+
+	if hz != 0 {
+		resetcpuprofiler(hz)
+	}
+
+	_g_.m.locks--
+}
+
+// Change number of processors.  The world is stopped, sched is locked.
+// gcworkbufs are not being modified by either the GC or
+// the write barrier code.
+// Returns list of Ps with local work, they need to be scheduled by the caller.
+func procresize(nprocs int32) *p {
+	old := gomaxprocs
+	if old < 0 || old > _MaxGomaxprocs || nprocs <= 0 || nprocs > _MaxGomaxprocs {
+		throw("procresize: invalid arg")
+	}
+	if trace.enabled {
+		traceGomaxprocs(nprocs)
+	}
+
+	// update statistics
+	now := nanotime()
+	if sched.procresizetime != 0 {
+		sched.totaltime += int64(old) * (now - sched.procresizetime)
+	}
+	sched.procresizetime = now
+
+	// initialize new P's
+	for i := int32(0); i < nprocs; i++ {
+		pp := allp[i]
+		if pp == nil {
+			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 {
+			if old == 0 && i == 0 {
+				if getg().m.mcache == nil {
+					throw("missing mcache?")
+				}
+				pp.mcache = getg().m.mcache // bootstrap
+			} else {
+				pp.mcache = allocmcache()
+			}
+		}
+	}
+
+	// free unused P's
+	for i := nprocs; i < old; i++ {
+		p := allp[i]
+		if trace.enabled {
+			if p == getg().m.p.ptr() {
+				// moving to p[0], pretend that we were descheduled
+				// and then scheduled again to keep the trace sane.
+				traceGoSched()
+				traceProcStop(p)
+			}
+		}
+		// move all runnable goroutines to the global queue
+		for p.runqhead != p.runqtail {
+			// pop from tail of local queue
+			p.runqtail--
+			gp := p.runq[p.runqtail%uint32(len(p.runq))]
+			// push onto head of global queue
+			globrunqputhead(gp)
+		}
+		if p.runnext != 0 {
+			globrunqputhead(p.runnext.ptr())
+			p.runnext = 0
+		}
+		// if there's a background worker, make it runnable and put
+		// it on the global queue so it can clean itself up
+		if p.gcBgMarkWorker != nil {
+			casgstatus(p.gcBgMarkWorker, _Gwaiting, _Grunnable)
+			if trace.enabled {
+				traceGoUnpark(p.gcBgMarkWorker, 0)
+			}
+			globrunqput(p.gcBgMarkWorker)
+			p.gcBgMarkWorker = nil
+		}
+		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)
+		traceProcFree(p)
+		p.status = _Pdead
+		// can't free P itself because it can be referenced by an M in syscall
+	}
+
+	_g_ := getg()
+	if _g_.m.p != 0 && _g_.m.p.ptr().id < nprocs {
+		// continue to use the current P
+		_g_.m.p.ptr().status = _Prunning
+	} else {
+		// release the current P and acquire allp[0]
+		if _g_.m.p != 0 {
+			_g_.m.p.ptr().m = 0
+		}
+		_g_.m.p = 0
+		_g_.m.mcache = nil
+		p := allp[0]
+		p.m = 0
+		p.status = _Pidle
+		acquirep(p)
+		if trace.enabled {
+			traceGoStart()
+		}
+	}
+	var runnablePs *p
+	for i := nprocs - 1; i >= 0; i-- {
+		p := allp[i]
+		if _g_.m.p.ptr() == p {
+			continue
+		}
+		p.status = _Pidle
+		if runqempty(p) {
+			pidleput(p)
+		} else {
+			p.m.set(mget())
+			p.link.set(runnablePs)
+			runnablePs = p
+		}
+	}
+	var int32p *int32 = &gomaxprocs // make compiler check that gomaxprocs is an int32
+	atomicstore((*uint32)(unsafe.Pointer(int32p)), uint32(nprocs))
+	return runnablePs
+}
+
+// Associate p and the current m.
+func acquirep(_p_ *p) {
+	acquirep1(_p_)
+
+	// have p; write barriers now allowed
+	_g_ := getg()
+	_g_.m.mcache = _p_.mcache
+
+	if trace.enabled {
+		traceProcStart()
+	}
+}
+
+// May run during STW, so write barriers are not allowed.
+//go:nowritebarrier
+func acquirep1(_p_ *p) {
+	_g_ := getg()
+
+	if _g_.m.p != 0 || _g_.m.mcache != nil {
+		throw("acquirep: already in go")
+	}
+	if _p_.m != 0 || _p_.status != _Pidle {
+		id := int32(0)
+		if _p_.m != 0 {
+			id = _p_.m.ptr().id
+		}
+		print("acquirep: p->m=", _p_.m, "(", id, ") p->status=", _p_.status, "\n")
+		throw("acquirep: invalid p state")
+	}
+	_g_.m.p.set(_p_)
+	_p_.m.set(_g_.m)
+	_p_.status = _Prunning
+}
+
+// Disassociate p and the current m.
+func releasep() *p {
+	_g_ := getg()
+
+	if _g_.m.p == 0 || _g_.m.mcache == nil {
+		throw("releasep: invalid arg")
+	}
+	_p_ := _g_.m.p.ptr()
+	if _p_.m.ptr() != _g_.m || _p_.mcache != _g_.m.mcache || _p_.status != _Prunning {
+		print("releasep: m=", _g_.m, " m->p=", _g_.m.p.ptr(), " p->m=", _p_.m, " m->mcache=", _g_.m.mcache, " p->mcache=", _p_.mcache, " p->status=", _p_.status, "\n")
+		throw("releasep: invalid p state")
+	}
+	if trace.enabled {
+		traceProcStop(_g_.m.p.ptr())
+	}
+	_g_.m.p = 0
+	_g_.m.mcache = nil
+	_p_.m = 0
+	_p_.status = _Pidle
+	return _p_
+}
+
+func incidlelocked(v int32) {
+	lock(&sched.lock)
+	sched.nmidlelocked += v
+	if v > 0 {
+		checkdead()
+	}
+	unlock(&sched.lock)
+}
+
+// Check for deadlock situation.
+// The check is based on number of running M's, if 0 -> deadlock.
+func checkdead() {
+	// For -buildmode=c-shared or -buildmode=c-archive it's OK if
+	// there are no running goroutines.  The calling program is
+	// assumed to be running.
+	if islibrary || isarchive {
+		return
+	}
+
+	// If we are dying because of a signal caught on an already idle thread,
+	// freezetheworld will cause all running threads to block.
+	// And runtime will essentially enter into deadlock state,
+	// except that there is a thread that will call exit soon.
+	if panicking > 0 {
+		return
+	}
+
+	// -1 for sysmon
+	run := sched.mcount - sched.nmidle - sched.nmidlelocked - 1
+	if run > 0 {
+		return
+	}
+	if run < 0 {
+		print("runtime: checkdead: nmidle=", sched.nmidle, " nmidlelocked=", sched.nmidlelocked, " mcount=", sched.mcount, "\n")
+		throw("checkdead: inconsistent counts")
+	}
+
+	grunning := 0
+	lock(&allglock)
+	for i := 0; i < len(allgs); i++ {
+		gp := allgs[i]
+		if isSystemGoroutine(gp) {
+			continue
+		}
+		s := readgstatus(gp)
+		switch s &^ _Gscan {
+		case _Gwaiting:
+			grunning++
+		case _Grunnable,
+			_Grunning,
+			_Gsyscall:
+			unlock(&allglock)
+			print("runtime: checkdead: find g ", gp.goid, " in status ", s, "\n")
+			throw("checkdead: runnable g")
+		}
+	}
+	unlock(&allglock)
+	if grunning == 0 { // possible if main goroutine calls runtime·Goexit()
+		throw("no goroutines (main called runtime.Goexit) - deadlock!")
+	}
+
+	// Maybe jump time forward for playground.
+	gp := timejump()
+	if gp != nil {
+		casgstatus(gp, _Gwaiting, _Grunnable)
+		globrunqput(gp)
+		_p_ := pidleget()
+		if _p_ == nil {
+			throw("checkdead: no p for timer")
+		}
+		mp := mget()
+		if mp == nil {
+			newm(nil, _p_)
+		} else {
+			mp.nextp.set(_p_)
+			notewakeup(&mp.park)
+		}
+		return
+	}
+
+	getg().m.throwing = -1 // do not dump full stacks
+	throw("all goroutines are asleep - deadlock!")
+}
+
+func sysmon() {
+	// If we go two minutes without a garbage collection, force one to run.
+	forcegcperiod := int64(2 * 60 * 1e9)
+
+	// If a heap span goes unused for 5 minutes after a garbage collection,
+	// we hand it back to the operating system.
+	scavengelimit := int64(5 * 60 * 1e9)
+
+	if debug.scavenge > 0 {
+		// Scavenge-a-lot for testing.
+		forcegcperiod = 10 * 1e6
+		scavengelimit = 20 * 1e6
+	}
+
+	lastscavenge := nanotime()
+	nscavenge := 0
+
+	// Make wake-up period small enough for the sampling to be correct.
+	maxsleep := forcegcperiod / 2
+	if scavengelimit < forcegcperiod {
+		maxsleep = scavengelimit / 2
+	}
+
+	lasttrace := int64(0)
+	idle := 0 // how many cycles in succession we had not wokeup somebody
+	delay := uint32(0)
+	for {
+		if idle == 0 { // start with 20us sleep...
+			delay = 20
+		} else if idle > 50 { // start doubling the sleep after 1ms...
+			delay *= 2
+		}
+		if delay > 10*1000 { // up to 10ms
+			delay = 10 * 1000
+		}
+		usleep(delay)
+		if debug.schedtrace <= 0 && (sched.gcwaiting != 0 || atomicload(&sched.npidle) == uint32(gomaxprocs)) { // TODO: fast atomic
+			lock(&sched.lock)
+			if atomicload(&sched.gcwaiting) != 0 || atomicload(&sched.npidle) == uint32(gomaxprocs) {
+				atomicstore(&sched.sysmonwait, 1)
+				unlock(&sched.lock)
+				notetsleep(&sched.sysmonnote, maxsleep)
+				lock(&sched.lock)
+				atomicstore(&sched.sysmonwait, 0)
+				noteclear(&sched.sysmonnote)
+				idle = 0
+				delay = 20
+			}
+			unlock(&sched.lock)
+		}
+		// poll network if not polled for more than 10ms
+		lastpoll := int64(atomicload64(&sched.lastpoll))
+		now := nanotime()
+		unixnow := unixnanotime()
+		if lastpoll != 0 && lastpoll+10*1000*1000 < now {
+			cas64(&sched.lastpoll, uint64(lastpoll), uint64(now))
+			gp := netpoll(false) // non-blocking - returns list of goroutines
+			if gp != nil {
+				// Need to decrement number of idle locked M's
+				// (pretending that one more is running) before injectglist.
+				// Otherwise it can lead to the following situation:
+				// injectglist grabs all P's but before it starts M's to run the P's,
+				// another M returns from syscall, finishes running its G,
+				// observes that there is no work to do and no other running M's
+				// and reports deadlock.
+				incidlelocked(-1)
+				injectglist(gp)
+				incidlelocked(1)
+			}
+		}
+		// retake P's blocked in syscalls
+		// and preempt long running G's
+		if retake(now) != 0 {
+			idle = 0
+		} else {
+			idle++
+		}
+		// check if we need to force a GC
+		lastgc := int64(atomicload64(&memstats.last_gc))
+		if lastgc != 0 && unixnow-lastgc > forcegcperiod && atomicload(&forcegc.idle) != 0 && atomicloaduint(&bggc.working) == 0 {
+			lock(&forcegc.lock)
+			forcegc.idle = 0
+			forcegc.g.schedlink = 0
+			injectglist(forcegc.g)
+			unlock(&forcegc.lock)
+		}
+		// scavenge heap once in a while
+		if lastscavenge+scavengelimit/2 < now {
+			mHeap_Scavenge(int32(nscavenge), uint64(now), uint64(scavengelimit))
+			lastscavenge = now
+			nscavenge++
+		}
+		if debug.schedtrace > 0 && lasttrace+int64(debug.schedtrace*1000000) <= now {
+			lasttrace = now
+			schedtrace(debug.scheddetail > 0)
+		}
+	}
+}
+
+var pdesc [_MaxGomaxprocs]struct {
+	schedtick   uint32
+	schedwhen   int64
+	syscalltick uint32
+	syscallwhen int64
+}
+
+// forcePreemptNS is the time slice given to a G before it is
+// preempted.
+const forcePreemptNS = 10 * 1000 * 1000 // 10ms
+
+func retake(now int64) uint32 {
+	n := 0
+	for i := int32(0); i < gomaxprocs; i++ {
+		_p_ := allp[i]
+		if _p_ == nil {
+			continue
+		}
+		pd := &pdesc[i]
+		s := _p_.status
+		if s == _Psyscall {
+			// Retake P from syscall if it's there for more than 1 sysmon tick (at least 20us).
+			t := int64(_p_.syscalltick)
+			if int64(pd.syscalltick) != t {
+				pd.syscalltick = uint32(t)
+				pd.syscallwhen = now
+				continue
+			}
+			// On the one hand we don't want to retake Ps if there is no other work to do,
+			// but on the other hand we want to retake them eventually
+			// because they can prevent the sysmon thread from deep sleep.
+			if runqempty(_p_) && atomicload(&sched.nmspinning)+atomicload(&sched.npidle) > 0 && pd.syscallwhen+10*1000*1000 > now {
+				continue
+			}
+			// Need to decrement number of idle locked M's
+			// (pretending that one more is running) before the CAS.
+			// Otherwise the M from which we retake can exit the syscall,
+			// increment nmidle and report deadlock.
+			incidlelocked(-1)
+			if cas(&_p_.status, s, _Pidle) {
+				if trace.enabled {
+					traceGoSysBlock(_p_)
+					traceProcStop(_p_)
+				}
+				n++
+				_p_.syscalltick++
+				handoffp(_p_)
+			}
+			incidlelocked(1)
+		} else if s == _Prunning {
+			// Preempt G if it's running for too long.
+			t := int64(_p_.schedtick)
+			if int64(pd.schedtick) != t {
+				pd.schedtick = uint32(t)
+				pd.schedwhen = now
+				continue
+			}
+			if pd.schedwhen+forcePreemptNS > now {
+				continue
+			}
+			preemptone(_p_)
+		}
+	}
+	return uint32(n)
+}
+
+// Tell all goroutines that they have been preempted and they should stop.
+// This function is purely best-effort.  It can fail to inform a goroutine if a
+// processor just started running it.
+// No locks need to be held.
+// Returns true if preemption request was issued to at least one goroutine.
+func preemptall() bool {
+	res := false
+	for i := int32(0); i < gomaxprocs; i++ {
+		_p_ := allp[i]
+		if _p_ == nil || _p_.status != _Prunning {
+			continue
+		}
+		if preemptone(_p_) {
+			res = true
+		}
+	}
+	return res
+}
+
+// Tell the goroutine running on processor P to stop.
+// This function is purely best-effort.  It can incorrectly fail to inform the
+// goroutine.  It can send inform the wrong goroutine.  Even if it informs the
+// correct goroutine, that goroutine might ignore the request if it is
+// simultaneously executing newstack.
+// No lock needs to be held.
+// Returns true if preemption request was issued.
+// The actual preemption will happen at some point in the future
+// and will be indicated by the gp->status no longer being
+// Grunning
+func preemptone(_p_ *p) bool {
+	mp := _p_.m.ptr()
+	if mp == nil || mp == getg().m {
+		return false
+	}
+	gp := mp.curg
+	if gp == nil || gp == mp.g0 {
+		return false
+	}
+
+	gp.preempt = true
+
+	// Every call in a go routine checks for stack overflow by
+	// comparing the current stack pointer to gp->stackguard0.
+	// Setting gp->stackguard0 to StackPreempt folds
+	// preemption into the normal stack overflow check.
+	gp.stackguard0 = stackPreempt
+	return true
+}
+
+var starttime int64
+
+func schedtrace(detailed bool) {
+	now := nanotime()
+	if starttime == 0 {
+		starttime = now
+	}
+
+	lock(&sched.lock)
+	print("SCHED ", (now-starttime)/1e6, "ms: gomaxprocs=", gomaxprocs, " idleprocs=", sched.npidle, " threads=", sched.mcount, " spinningthreads=", sched.nmspinning, " idlethreads=", sched.nmidle, " runqueue=", sched.runqsize)
+	if detailed {
+		print(" gcwaiting=", sched.gcwaiting, " nmidlelocked=", sched.nmidlelocked, " stopwait=", sched.stopwait, " sysmonwait=", sched.sysmonwait, "\n")
+	}
+	// We must be careful while reading data from P's, M's and G's.
+	// Even if we hold schedlock, most data can be changed concurrently.
+	// E.g. (p->m ? p->m->id : -1) can crash if p->m changes from non-nil to nil.
+	for i := int32(0); i < gomaxprocs; i++ {
+		_p_ := allp[i]
+		if _p_ == nil {
+			continue
+		}
+		mp := _p_.m.ptr()
+		h := atomicload(&_p_.runqhead)
+		t := atomicload(&_p_.runqtail)
+		if detailed {
+			id := int32(-1)
+			if mp != nil {
+				id = mp.id
+			}
+			print("  P", i, ": status=", _p_.status, " schedtick=", _p_.schedtick, " syscalltick=", _p_.syscalltick, " m=", id, " runqsize=", t-h, " gfreecnt=", _p_.gfreecnt, "\n")
+		} else {
+			// In non-detailed mode format lengths of per-P run queues as:
+			// [len1 len2 len3 len4]
+			print(" ")
+			if i == 0 {
+				print("[")
+			}
+			print(t - h)
+			if i == gomaxprocs-1 {
+				print("]\n")
+			}
+		}
+	}
+
+	if !detailed {
+		unlock(&sched.lock)
+		return
+	}
+
+	for mp := allm; mp != nil; mp = mp.alllink {
+		_p_ := mp.p.ptr()
+		gp := mp.curg
+		lockedg := mp.lockedg
+		id1 := int32(-1)
+		if _p_ != nil {
+			id1 = _p_.id
+		}
+		id2 := int64(-1)
+		if gp != nil {
+			id2 = gp.goid
+		}
+		id3 := int64(-1)
+		if lockedg != nil {
+			id3 = lockedg.goid
+		}
+		print("  M", mp.id, ": p=", id1, " curg=", id2, " mallocing=", mp.mallocing, " throwing=", mp.throwing, " preemptoff=", mp.preemptoff, ""+" locks=", mp.locks, " dying=", mp.dying, " helpgc=", mp.helpgc, " spinning=", mp.spinning, " blocked=", getg().m.blocked, " lockedg=", id3, "\n")
+	}
+
+	lock(&allglock)
+	for gi := 0; gi < len(allgs); gi++ {
+		gp := allgs[gi]
+		mp := gp.m
+		lockedm := gp.lockedm
+		id1 := int32(-1)
+		if mp != nil {
+			id1 = mp.id
+		}
+		id2 := int32(-1)
+		if lockedm != nil {
+			id2 = lockedm.id
+		}
+		print("  G", gp.goid, ": status=", readgstatus(gp), "(", gp.waitreason, ") m=", id1, " lockedm=", id2, "\n")
+	}
+	unlock(&allglock)
+	unlock(&sched.lock)
+}
+
+// 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.set(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.ptr()
+	if mp != nil {
+		sched.midle = mp.schedlink
+		sched.nmidle--
+	}
+	return mp
+}
+
+// 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 = 0
+	if sched.runqtail != 0 {
+		sched.runqtail.ptr().schedlink.set(gp)
+	} else {
+		sched.runqhead.set(gp)
+	}
+	sched.runqtail.set(gp)
+	sched.runqsize++
+}
+
+// Put gp at the head of the global runnable queue.
+// Sched must be locked.
+// May run during STW, so write barriers are not allowed.
+//go:nowritebarrier
+func globrunqputhead(gp *g) {
+	gp.schedlink = sched.runqhead
+	sched.runqhead.set(gp)
+	if sched.runqtail == 0 {
+		sched.runqtail.set(gp)
+	}
+	sched.runqsize++
+}
+
+// Put a batch of runnable goroutines on the global runnable queue.
+// Sched must be locked.
+func globrunqputbatch(ghead *g, gtail *g, n int32) {
+	gtail.schedlink = 0
+	if sched.runqtail != 0 {
+		sched.runqtail.ptr().schedlink.set(ghead)
+	} else {
+		sched.runqhead.set(ghead)
+	}
+	sched.runqtail.set(gtail)
+	sched.runqsize += n
+}
+
+// Try get a batch of G's from the global runnable queue.
+// Sched must be locked.
+func globrunqget(_p_ *p, max int32) *g {
+	if sched.runqsize == 0 {
+		return nil
+	}
+
+	n := sched.runqsize/gomaxprocs + 1
+	if n > sched.runqsize {
+		n = sched.runqsize
+	}
+	if max > 0 && n > max {
+		n = max
+	}
+	if n > int32(len(_p_.runq))/2 {
+		n = int32(len(_p_.runq)) / 2
+	}
+
+	sched.runqsize -= n
+	if sched.runqsize == 0 {
+		sched.runqtail = 0
+	}
+
+	gp := sched.runqhead.ptr()
+	sched.runqhead = gp.schedlink
+	n--
+	for ; n > 0; n-- {
+		gp1 := sched.runqhead.ptr()
+		sched.runqhead = gp1.schedlink
+		runqput(_p_, gp1, false)
+	}
+	return gp
+}
+
+// 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) {
+	if !runqempty(_p_) {
+		throw("pidleput: P has non-empty run queue")
+	}
+	_p_.link = sched.pidle
+	sched.pidle.set(_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.ptr()
+	if _p_ != nil {
+		sched.pidle = _p_.link
+		xadd(&sched.npidle, -1) // TODO: fast atomic
+	}
+	return _p_
+}
+
+// runqempty returns true if _p_ has no Gs on its local run queue.
+// Note that this test is generally racy.
+func runqempty(_p_ *p) bool {
+	return _p_.runqhead == _p_.runqtail && _p_.runnext == 0
+}
+
+// To shake out latent assumptions about scheduling order,
+// we introduce some randomness into scheduling decisions
+// when running with the race detector.
+// The need for this was made obvious by changing the
+// (deterministic) scheduling order in Go 1.5 and breaking
+// many poorly-written tests.
+// With the randomness here, as long as the tests pass
+// consistently with -race, they shouldn't have latent scheduling
+// assumptions.
+const randomizeScheduler = raceenabled
+
+// runqput tries to put g on the local runnable queue.
+// If next if false, runqput adds g to the tail of the runnable queue.
+// If next is true, runqput puts g in the _p_.runnext slot.
+// If the run queue is full, runnext puts g on the global queue.
+// Executed only by the owner P.
+func runqput(_p_ *p, gp *g, next bool) {
+	if randomizeScheduler && next && fastrand1()%2 == 0 {
+		next = false
+	}
+
+	if next {
+	retryNext:
+		oldnext := _p_.runnext
+		if !_p_.runnext.cas(oldnext, guintptr(unsafe.Pointer(gp))) {
+			goto retryNext
+		}
+		if oldnext == 0 {
+			return
+		}
+		// Kick the old runnext out to the regular run queue.
+		gp = oldnext.ptr()
+	}
+
+retry:
+	h := atomicload(&_p_.runqhead) // load-acquire, synchronize with consumers
+	t := _p_.runqtail
+	if t-h < uint32(len(_p_.runq)) {
+		_p_.runq[t%uint32(len(_p_.runq))] = gp
+		atomicstore(&_p_.runqtail, t+1) // store-release, makes the item available for consumption
+		return
+	}
+	if runqputslow(_p_, gp, h, t) {
+		return
+	}
+	// the queue is not full, now the put above must suceed
+	goto retry
+}
+
+// Put g and a batch of work from local runnable queue on global queue.
+// Executed only by the owner P.
+func runqputslow(_p_ *p, gp *g, h, t uint32) bool {
+	var batch [len(_p_.runq)/2 + 1]*g
+
+	// First, grab a batch from local queue.
+	n := t - h
+	n = n / 2
+	if n != uint32(len(_p_.runq)/2) {
+		throw("runqputslow: queue is not full")
+	}
+	for i := uint32(0); i < n; i++ {
+		batch[i] = _p_.runq[(h+i)%uint32(len(_p_.runq))]
+	}
+	if !cas(&_p_.runqhead, h, h+n) { // cas-release, commits consume
+		return false
+	}
+	batch[n] = gp
+
+	if randomizeScheduler {
+		for i := uint32(1); i <= n; i++ {
+			j := fastrand1() % (i + 1)
+			batch[i], batch[j] = batch[j], batch[i]
+		}
+	}
+
+	// Link the goroutines.
+	for i := uint32(0); i < n; i++ {
+		batch[i].schedlink.set(batch[i+1])
+	}
+
+	// Now put the batch on global queue.
+	lock(&sched.lock)
+	globrunqputbatch(batch[0], batch[n], int32(n+1))
+	unlock(&sched.lock)
+	return true
+}
+
+// Get g from local runnable queue.
+// If inheritTime is true, gp should inherit the remaining time in the
+// current time slice. Otherwise, it should start a new time slice.
+// Executed only by the owner P.
+func runqget(_p_ *p) (gp *g, inheritTime bool) {
+	// If there's a runnext, it's the next G to run.
+	for {
+		next := _p_.runnext
+		if next == 0 {
+			break
+		}
+		if _p_.runnext.cas(next, 0) {
+			return next.ptr(), true
+		}
+	}
+
+	for {
+		h := atomicload(&_p_.runqhead) // load-acquire, synchronize with other consumers
+		t := _p_.runqtail
+		if t == h {
+			return nil, false
+		}
+		gp := _p_.runq[h%uint32(len(_p_.runq))]
+		if cas(&_p_.runqhead, h, h+1) { // cas-release, commits consume
+			return gp, false
+		}
+	}
+}
+
+// Grabs a batch of goroutines from _p_'s runnable queue into batch.
+// Batch is a ring buffer starting at batchHead.
+// Returns number of grabbed goroutines.
+// Can be executed by any P.
+func runqgrab(_p_ *p, batch *[256]*g, batchHead uint32, stealRunNextG bool) uint32 {
+	for {
+		h := atomicload(&_p_.runqhead) // load-acquire, synchronize with other consumers
+		t := atomicload(&_p_.runqtail) // load-acquire, synchronize with the producer
+		n := t - h
+		n = n - n/2
+		if n == 0 {
+			if stealRunNextG {
+				// Try to steal from _p_.runnext.
+				if next := _p_.runnext; next != 0 {
+					// Sleep to ensure that _p_ isn't about to run the g we
+					// are about to steal.
+					// The important use case here is when the g running on _p_
+					// ready()s another g and then almost immediately blocks.
+					// Instead of stealing runnext in this window, back off
+					// to give _p_ a chance to schedule runnext. This will avoid
+					// thrashing gs between different Ps.
+					usleep(100)
+					if !_p_.runnext.cas(next, 0) {
+						continue
+					}
+					batch[batchHead%uint32(len(batch))] = next.ptr()
+					return 1
+				}
+			}
+			return 0
+		}
+		if n > uint32(len(_p_.runq)/2) { // read inconsistent h and t
+			continue
+		}
+		for i := uint32(0); i < n; i++ {
+			g := _p_.runq[(h+i)%uint32(len(_p_.runq))]
+			batch[(batchHead+i)%uint32(len(batch))] = g
+		}
+		if cas(&_p_.runqhead, h, h+n) { // cas-release, commits consume
+			return n
+		}
+	}
+}
+
+// Steal half of elements from local runnable queue of p2
+// and put onto local runnable queue of p.
+// Returns one of the stolen elements (or nil if failed).
+func runqsteal(_p_, p2 *p, stealRunNextG bool) *g {
+	t := _p_.runqtail
+	n := runqgrab(p2, &_p_.runq, t, stealRunNextG)
+	if n == 0 {
+		return nil
+	}
+	n--
+	gp := _p_.runq[(t+n)%uint32(len(_p_.runq))]
+	if n == 0 {
+		return gp
+	}
+	h := atomicload(&_p_.runqhead) // load-acquire, synchronize with consumers
+	if t-h+n >= uint32(len(_p_.runq)) {
+		throw("runqsteal: runq overflow")
+	}
+	atomicstore(&_p_.runqtail, t+n) // store-release, makes the item available for consumption
+	return gp
+}
+
+func testSchedLocalQueue() {
+	_p_ := new(p)
+	gs := make([]g, len(_p_.runq))
+	for i := 0; i < len(_p_.runq); i++ {
+		if g, _ := runqget(_p_); g != nil {
+			throw("runq is not empty initially")
+		}
+		for j := 0; j < i; j++ {
+			runqput(_p_, &gs[i], false)
+		}
+		for j := 0; j < i; j++ {
+			if g, _ := runqget(_p_); g != &gs[i] {
+				print("bad element at iter ", i, "/", j, "\n")
+				throw("bad element")
+			}
+		}
+		if g, _ := runqget(_p_); g != nil {
+			throw("runq is not empty afterwards")
+		}
+	}
+}
+
+func testSchedLocalQueueSteal() {
+	p1 := new(p)
+	p2 := new(p)
+	gs := make([]g, len(p1.runq))
+	for i := 0; i < len(p1.runq); i++ {
+		for j := 0; j < i; j++ {
+			gs[j].sig = 0
+			runqput(p1, &gs[j], false)
+		}
+		gp := runqsteal(p2, p1, true)
+		s := 0
+		if gp != nil {
+			s++
+			gp.sig++
+		}
+		for {
+			gp, _ = runqget(p2)
+			if gp == nil {
+				break
+			}
+			s++
+			gp.sig++
+		}
+		for {
+			gp, _ = runqget(p1)
+			if gp == nil {
+				break
+			}
+			gp.sig++
+		}
+		for j := 0; j < i; j++ {
+			if gs[j].sig != 1 {
+				print("bad element ", j, "(", gs[j].sig, ") at iter ", i, "\n")
+				throw("bad element")
+			}
+		}
+		if s != i/2 && s != i/2+1 {
+			print("bad steal ", s, ", want ", i/2, " or ", i/2+1, ", iter ", i, "\n")
+			throw("bad steal")
+		}
+	}
+}
+
+func setMaxThreads(in int) (out int) {
+	lock(&sched.lock)
+	out = int(sched.maxmcount)
+	sched.maxmcount = int32(in)
+	checkmcount()
+	unlock(&sched.lock)
+	return
+}
+
+func haveexperiment(name string) bool {
+	x := goexperiment
+	for x != "" {
+		xname := ""
+		i := index(x, ",")
+		if i < 0 {
+			xname, x = x, ""
+		} else {
+			xname, x = x[:i], x[i+1:]
+		}
+		if xname == name {
+			return true
+		}
+	}
+	return false
+}
+
+//go:nosplit
+func procPin() int {
+	_g_ := getg()
+	mp := _g_.m
+
+	mp.locks++
+	return int(mp.p.ptr().id)
+}
+
+//go:nosplit
+func procUnpin() {
+	_g_ := getg()
+	_g_.m.locks--
+}
+
+//go:linkname sync_runtime_procPin sync.runtime_procPin
+//go:nosplit
+func sync_runtime_procPin() int {
+	return procPin()
+}
+
+//go:linkname sync_runtime_procUnpin sync.runtime_procUnpin
+//go:nosplit
+func sync_runtime_procUnpin() {
+	procUnpin()
+}
+
+//go:linkname sync_atomic_runtime_procPin sync/atomic.runtime_procPin
+//go:nosplit
+func sync_atomic_runtime_procPin() int {
+	return procPin()
+}
+
+//go:linkname sync_atomic_runtime_procUnpin sync/atomic.runtime_procUnpin
+//go:nosplit
+func sync_atomic_runtime_procUnpin() {
+	procUnpin()
+}
+
+// Active spinning for sync.Mutex.
+//go:linkname sync_runtime_canSpin sync.runtime_canSpin
+//go:nosplit
+func sync_runtime_canSpin(i int) bool {
+	// sync.Mutex is cooperative, so we are conservative with spinning.
+	// Spin only few times and only if running on a multicore machine and
+	// GOMAXPROCS>1 and there is at least one other running P and local runq is empty.
+	// As opposed to runtime mutex we don't do passive spinning here,
+	// because there can be work on global runq on on other Ps.
+	if i >= active_spin || ncpu <= 1 || gomaxprocs <= int32(sched.npidle+sched.nmspinning)+1 {
+		return false
+	}
+	if p := getg().m.p.ptr(); !runqempty(p) {
+		return false
+	}
+	return true
+}
+
+//go:linkname sync_runtime_doSpin sync.runtime_doSpin
+//go:nosplit
+func sync_runtime_doSpin() {
+	procyield(active_spin_cnt)
+}
diff --git a/src/runtime/proc_test.go b/src/runtime/proc_test.go
index aa9bc81..2be103e 100644
--- a/src/runtime/proc_test.go
+++ b/src/runtime/proc_test.go
@@ -7,6 +7,8 @@ package runtime_test
 import (
 	"math"
 	"runtime"
+	"runtime/debug"
+	"sync"
 	"sync/atomic"
 	"syscall"
 	"testing"
@@ -94,6 +96,10 @@ func TestYieldLocked(t *testing.T) {
 }
 
 func TestGoroutineParallelism(t *testing.T) {
+	if runtime.NumCPU() == 1 {
+		// Takes too long, too easy to deadlock, etc.
+		t.Skip("skipping on uniprocessor")
+	}
 	P := 4
 	N := 10
 	if testing.Short() {
@@ -103,8 +109,8 @@ func TestGoroutineParallelism(t *testing.T) {
 	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(P))
 	// If runtime triggers a forced GC during this test then it will deadlock,
 	// since the goroutines can't be stopped/preempted.
-	// So give this test as much time as possible.
-	runtime.GC()
+	// Disable GC for this test (see issue #10958).
+	defer debug.SetGCPercent(debug.SetGCPercent(-1))
 	for try := 0; try < N; try++ {
 		done := make(chan bool)
 		x := uint32(0)
@@ -291,6 +297,98 @@ func main() {
 }
 `
 
+func TestPingPongHog(t *testing.T) {
+	if testing.Short() {
+		t.Skip("skipping in -short mode")
+	}
+
+	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
+	done := make(chan bool)
+	hogChan, lightChan := make(chan bool), make(chan bool)
+	hogCount, lightCount := 0, 0
+
+	run := func(limit int, counter *int, wake chan bool) {
+		for {
+			select {
+			case <-done:
+				return
+
+			case <-wake:
+				for i := 0; i < limit; i++ {
+					*counter++
+				}
+				wake <- true
+			}
+		}
+	}
+
+	// Start two co-scheduled hog goroutines.
+	for i := 0; i < 2; i++ {
+		go run(1e6, &hogCount, hogChan)
+	}
+
+	// Start two co-scheduled light goroutines.
+	for i := 0; i < 2; i++ {
+		go run(1e3, &lightCount, lightChan)
+	}
+
+	// Start goroutine pairs and wait for a few preemption rounds.
+	hogChan <- true
+	lightChan <- true
+	time.Sleep(100 * time.Millisecond)
+	close(done)
+	<-hogChan
+	<-lightChan
+
+	// Check that hogCount and lightCount are within a factor of
+	// 2, which indicates that both pairs of goroutines handed off
+	// the P within a time-slice to their buddy.
+	if hogCount > lightCount*2 || lightCount > hogCount*2 {
+		t.Fatalf("want hogCount/lightCount in [0.5, 2]; got %d/%d = %g", hogCount, lightCount, float64(hogCount)/float64(lightCount))
+	}
+}
+
+func BenchmarkPingPongHog(b *testing.B) {
+	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
+
+	// Create a CPU hog
+	stop, done := make(chan bool), make(chan bool)
+	go func() {
+		for {
+			select {
+			case <-stop:
+				done <- true
+				return
+			default:
+			}
+		}
+	}()
+
+	// Ping-pong b.N times
+	ping, pong := make(chan bool), make(chan bool)
+	go func() {
+		for j := 0; j < b.N; j++ {
+			pong <- <-ping
+		}
+		close(stop)
+		done <- true
+	}()
+	go func() {
+		for i := 0; i < b.N; i++ {
+			ping <- <-pong
+		}
+		done <- true
+	}()
+	b.ResetTimer()
+	ping <- true // Start ping-pong
+	<-stop
+	b.StopTimer()
+	<-ping // Let last ponger exit
+	<-done // Make sure goroutines exit
+	<-done
+	<-done
+}
+
 func stackGrowthRecursive(i int) {
 	var pad [128]uint64
 	if i != 0 && pad[0] == 0 {
@@ -415,6 +513,37 @@ func benchmarkCreateGoroutines(b *testing.B, procs int) {
 	}
 }
 
+func BenchmarkCreateGoroutinesCapture(b *testing.B) {
+	b.ReportAllocs()
+	for i := 0; i < b.N; i++ {
+		const N = 4
+		var wg sync.WaitGroup
+		wg.Add(N)
+		for i := 0; i < N; i++ {
+			i := i
+			go func() {
+				if i >= N {
+					b.Logf("bad") // just to capture b
+				}
+				wg.Done()
+			}()
+		}
+		wg.Wait()
+	}
+}
+
+func BenchmarkClosureCall(b *testing.B) {
+	sum := 0
+	off1 := 1
+	for i := 0; i < b.N; i++ {
+		off2 := 2
+		func() {
+			sum += i + off1 + off2
+		}()
+	}
+	_ = sum
+}
+
 type Matrix [][]float64
 
 func BenchmarkMatmult(b *testing.B) {
diff --git a/src/runtime/race.c b/src/runtime/race.c
deleted file mode 100644
index 5b0d116..0000000
--- a/src/runtime/race.c
+++ /dev/null
@@ -1,347 +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.
-
-// Implementation of the race detector API.
-// +build race
-
-#include "runtime.h"
-#include "arch_GOARCH.h"
-#include "malloc.h"
-#include "race.h"
-#include "type.h"
-#include "typekind.h"
-#include "textflag.h"
-
-// Race runtime functions called via runtime·racecall.
-void __tsan_init(void);
-void __tsan_fini(void);
-void __tsan_map_shadow(void);
-void __tsan_finalizer_goroutine(void);
-void __tsan_go_start(void);
-void __tsan_go_end(void);
-void __tsan_malloc(void);
-void __tsan_acquire(void);
-void __tsan_release(void);
-void __tsan_release_merge(void);
-void __tsan_go_ignore_sync_begin(void);
-void __tsan_go_ignore_sync_end(void);
-
-// Mimic what cmd/cgo would do.
-#pragma cgo_import_static __tsan_init
-#pragma cgo_import_static __tsan_fini
-#pragma cgo_import_static __tsan_map_shadow
-#pragma cgo_import_static __tsan_finalizer_goroutine
-#pragma cgo_import_static __tsan_go_start
-#pragma cgo_import_static __tsan_go_end
-#pragma cgo_import_static __tsan_malloc
-#pragma cgo_import_static __tsan_acquire
-#pragma cgo_import_static __tsan_release
-#pragma cgo_import_static __tsan_release_merge
-#pragma cgo_import_static __tsan_go_ignore_sync_begin
-#pragma cgo_import_static __tsan_go_ignore_sync_end
-
-// These are called from race_amd64.s.
-#pragma cgo_import_static __tsan_read
-#pragma cgo_import_static __tsan_read_pc
-#pragma cgo_import_static __tsan_read_range
-#pragma cgo_import_static __tsan_write
-#pragma cgo_import_static __tsan_write_pc
-#pragma cgo_import_static __tsan_write_range
-#pragma cgo_import_static __tsan_func_enter
-#pragma cgo_import_static __tsan_func_exit
-
-#pragma cgo_import_static __tsan_go_atomic32_load
-#pragma cgo_import_static __tsan_go_atomic64_load
-#pragma cgo_import_static __tsan_go_atomic32_store
-#pragma cgo_import_static __tsan_go_atomic64_store
-#pragma cgo_import_static __tsan_go_atomic32_exchange
-#pragma cgo_import_static __tsan_go_atomic64_exchange
-#pragma cgo_import_static __tsan_go_atomic32_fetch_add
-#pragma cgo_import_static __tsan_go_atomic64_fetch_add
-#pragma cgo_import_static __tsan_go_atomic32_compare_exchange
-#pragma cgo_import_static __tsan_go_atomic64_compare_exchange
-
-extern byte runtime·noptrdata[];
-extern byte runtime·enoptrdata[];
-extern byte runtime·data[];
-extern byte runtime·edata[];
-extern byte runtime·bss[];
-extern byte runtime·ebss[];
-extern byte runtime·noptrbss[];
-extern byte runtime·enoptrbss[];
-
-// start/end of global data (data+bss).
-uintptr runtime·racedatastart;
-uintptr runtime·racedataend;
-// start/end of heap for race_amd64.s
-uintptr runtime·racearenastart;
-uintptr runtime·racearenaend;
-
-void runtime·racefuncenter(void *callpc);
-void runtime·racefuncexit(void);
-void runtime·racereadrangepc1(void *addr, uintptr sz, void *pc);
-void runtime·racewriterangepc1(void *addr, uintptr sz, void *pc);
-void runtime·racesymbolizethunk(void*);
-
-// racecall allows calling an arbitrary function f from C race runtime
-// with up to 4 uintptr arguments.
-void runtime·racecall(void(*f)(void), ...);
-
-// checks if the address has shadow (i.e. heap or data/bss)
-#pragma textflag NOSPLIT
-static bool
-isvalidaddr(uintptr addr)
-{
-	if(addr >= runtime·racearenastart && addr < runtime·racearenaend)
-		return true;
-	if(addr >= runtime·racedatastart && addr < runtime·racedataend)
-		return true;
-	return false;
-}
-
-#pragma textflag NOSPLIT
-uintptr
-runtime·raceinit(void)
-{
-	uintptr racectx, start, end, size;
-
-	// cgo is required to initialize libc, which is used by race runtime
-	if(!runtime·iscgo)
-		runtime·throw("raceinit: race build must use cgo");
-	runtime·racecall(__tsan_init, &racectx, runtime·racesymbolizethunk);
-	// Round data segment to page boundaries, because it's used in mmap().
-	// The relevant sections are noptrdata, data, bss, noptrbss.
-	// In external linking mode, there may be other non-Go data mixed in,
-	// and the sections may even occur out of order.
-	// Work out a conservative range of addresses.
-	start = ~(uintptr)0;
-	end = 0;
-	if(start > (uintptr)runtime·noptrdata)
-		start = (uintptr)runtime·noptrdata;
-	if(start > (uintptr)runtime·data)
-		start = (uintptr)runtime·data;
-	if(start > (uintptr)runtime·noptrbss)
-		start = (uintptr)runtime·noptrbss;
-	if(start > (uintptr)runtime·bss)
-		start = (uintptr)runtime·bss;
-	if(end < (uintptr)runtime·enoptrdata)
-		end = (uintptr)runtime·enoptrdata;
-	if(end < (uintptr)runtime·edata)
-		end = (uintptr)runtime·edata;
-	if(end < (uintptr)runtime·enoptrbss)
-		end = (uintptr)runtime·enoptrbss;
-	if(end < (uintptr)runtime·ebss)
-		end = (uintptr)runtime·ebss;
-	start = start & ~(PageSize-1);
-	size = ROUND(end - start, PageSize);
-	runtime·racecall(__tsan_map_shadow, start, size);
-	runtime·racedatastart = start;
-	runtime·racedataend = start + size;
-	return racectx;
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·racefini(void)
-{
-	runtime·racecall(__tsan_fini);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·racemapshadow(void *addr, uintptr size)
-{
-	if(runtime·racearenastart == 0)
-		runtime·racearenastart = (uintptr)addr;
-	if(runtime·racearenaend < (uintptr)addr+size)
-		runtime·racearenaend = (uintptr)addr+size;
-	runtime·racecall(__tsan_map_shadow, addr, size);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·racemalloc(void *p, uintptr sz)
-{
-	runtime·racecall(__tsan_malloc, p, sz);
-}
-
-#pragma textflag NOSPLIT
-uintptr
-runtime·racegostart(void *pc)
-{
-	uintptr racectx;
-	G *spawng;
-
-	if(g->m->curg != nil)
-		spawng = g->m->curg;
-	else
-		spawng = g;
-
-	runtime·racecall(__tsan_go_start, spawng->racectx, &racectx, pc);
-	return racectx;
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·racegoend(void)
-{
-	runtime·racecall(__tsan_go_end, g->racectx);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·racewriterangepc(void *addr, uintptr sz, void *callpc, void *pc)
-{
-	if(g != g->m->curg) {
-		// The call is coming from manual instrumentation of Go code running on g0/gsignal.
-		// Not interesting.
-		return;
-	}
-	if(callpc != nil)
-		runtime·racefuncenter(callpc);
-	runtime·racewriterangepc1(addr, sz, pc);
-	if(callpc != nil)
-		runtime·racefuncexit();
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·racereadrangepc(void *addr, uintptr sz, void *callpc, void *pc)
-{
-	if(g != g->m->curg) {
-		// The call is coming from manual instrumentation of Go code running on g0/gsignal.
-		// Not interesting.
-		return;
-	}
-	if(callpc != nil)
-		runtime·racefuncenter(callpc);
-	runtime·racereadrangepc1(addr, sz, pc);
-	if(callpc != nil)
-		runtime·racefuncexit();
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·racewriteobjectpc(void *addr, Type *t, void *callpc, void *pc)
-{
-	uint8 kind;
-
-	kind = t->kind & KindMask;
-	if(kind == KindArray || kind == KindStruct)
-		runtime·racewriterangepc(addr, t->size, callpc, pc);
-	else
-		runtime·racewritepc(addr, callpc, pc);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·racereadobjectpc(void *addr, Type *t, void *callpc, void *pc)
-{
-	uint8 kind;
-
-	kind = t->kind & KindMask;
-	if(kind == KindArray || kind == KindStruct)
-		runtime·racereadrangepc(addr, t->size, callpc, pc);
-	else
-		runtime·racereadpc(addr, callpc, pc);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·raceacquire(void *addr)
-{
-	runtime·raceacquireg(g, addr);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·raceacquireg(G *gp, void *addr)
-{
-	if(g->raceignore || !isvalidaddr((uintptr)addr))
-		return;
-	runtime·racecall(__tsan_acquire, gp->racectx, addr);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·racerelease(void *addr)
-{
-	if(g->raceignore || !isvalidaddr((uintptr)addr))
-		return;
-	runtime·racereleaseg(g, addr);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·racereleaseg(G *gp, void *addr)
-{
-	if(g->raceignore || !isvalidaddr((uintptr)addr))
-		return;
-	runtime·racecall(__tsan_release, gp->racectx, addr);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·racereleasemerge(void *addr)
-{
-	runtime·racereleasemergeg(g, addr);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·racereleasemergeg(G *gp, void *addr)
-{
-	if(g->raceignore || !isvalidaddr((uintptr)addr))
-		return;
-	runtime·racecall(__tsan_release_merge, gp->racectx, addr);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·racefingo(void)
-{
-	runtime·racecall(__tsan_finalizer_goroutine, g->racectx);
-}
-
-// func RaceAcquire(addr unsafe.Pointer)
-#pragma textflag NOSPLIT
-void
-runtime·RaceAcquire(void *addr)
-{
-	runtime·raceacquire(addr);
-}
-
-// func RaceRelease(addr unsafe.Pointer)
-#pragma textflag NOSPLIT
-void
-runtime·RaceRelease(void *addr)
-{
-	runtime·racerelease(addr);
-}
-
-// func RaceReleaseMerge(addr unsafe.Pointer)
-#pragma textflag NOSPLIT
-void
-runtime·RaceReleaseMerge(void *addr)
-{
-	runtime·racereleasemerge(addr);
-}
-
-// func RaceDisable()
-#pragma textflag NOSPLIT
-void
-runtime·RaceDisable(void)
-{
-	if(g->raceignore++ == 0)
-		runtime·racecall(__tsan_go_ignore_sync_begin, g->racectx);
-}
-
-// func RaceEnable()
-#pragma textflag NOSPLIT
-void
-runtime·RaceEnable(void)
-{
-	if(--g->raceignore == 0)
-		runtime·racecall(__tsan_go_ignore_sync_end, g->racectx);
-}
diff --git a/src/runtime/race.go b/src/runtime/race.go
index bb0ee6d..923d611 100644
--- a/src/runtime/race.go
+++ b/src/runtime/race.go
@@ -12,18 +12,6 @@ import (
 	"unsafe"
 )
 
-func racefini()
-
-// RaceDisable disables handling of race events in the current goroutine.
-func RaceDisable()
-
-// RaceEnable re-enables handling of race events in the current goroutine.
-func RaceEnable()
-
-func RaceAcquire(addr unsafe.Pointer)
-func RaceRelease(addr unsafe.Pointer)
-func RaceReleaseMerge(addr unsafe.Pointer)
-
 func RaceRead(addr unsafe.Pointer)
 func RaceWrite(addr unsafe.Pointer)
 func RaceReadRange(addr unsafe.Pointer, len int)
@@ -35,6 +23,9 @@ func RaceSemrelease(s *uint32)
 // private interface for the runtime
 const raceenabled = true
 
+// For all functions accepting callerpc and pc,
+// callerpc is a return PC of the function that calls this function,
+// pc is start PC of the function that calls this function.
 func raceReadObjectPC(t *_type, addr unsafe.Pointer, callerpc, pc uintptr) {
 	kind := t.kind & kindMask
 	if kind == kindArray || kind == kindStruct {
@@ -67,32 +58,6 @@ func racereadpc(addr unsafe.Pointer, callpc, pc uintptr)
 //go:noescape
 func racewritepc(addr unsafe.Pointer, callpc, pc uintptr)
 
-//go:noescape
-func racereadrangepc(addr unsafe.Pointer, len uintptr, callpc, pc uintptr)
-
-//go:noescape
-func racewriterangepc(addr unsafe.Pointer, len uintptr, callpc, pc uintptr)
-
-//go:noescape
-func raceacquire(addr unsafe.Pointer)
-
-//go:noescape
-func racerelease(addr unsafe.Pointer)
-
-//go:noescape
-func raceacquireg(gp *g, addr unsafe.Pointer)
-
-//go:noescape
-func racereleaseg(gp *g, addr unsafe.Pointer)
-
-func racefingo()
-
-//go:noescape
-func racemalloc(p unsafe.Pointer, size uintptr)
-
-//go:noescape
-func racereleasemerge(addr unsafe.Pointer)
-
 type symbolizeContext struct {
 	pc   uintptr
 	fn   *byte
@@ -117,9 +82,9 @@ func racesymbolize(ctx *symbolizeContext) {
 		return
 	}
 
-	ctx.fn = funcname(f)
-	var file string
-	ctx.line = uintptr(funcline(f, ctx.pc, &file))
+	ctx.fn = cfuncname(f)
+	file, line := funcline(f, ctx.pc)
+	ctx.line = uintptr(line)
 	ctx.file = &bytes(file)[0] // assume NUL-terminated
 	ctx.off = ctx.pc - f.entry
 	ctx.res = 1
diff --git a/src/runtime/race.h b/src/runtime/race.h
deleted file mode 100644
index fee31e0..0000000
--- a/src/runtime/race.h
+++ /dev/null
@@ -1,34 +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.
-
-// Definitions related to data race detection.
-
-#ifdef RACE
-enum { raceenabled = 1 };
-#else
-enum { raceenabled = 0 };
-#endif
-
-// Initialize race detection subsystem.
-uintptr	runtime·raceinit(void);
-// Finalize race detection subsystem, does not return.
-void	runtime·racefini(void);
-
-void	runtime·racemapshadow(void *addr, uintptr size);
-void	runtime·racemalloc(void *p, uintptr sz);
-uintptr	runtime·racegostart(void *pc);
-void	runtime·racegoend(void);
-void	runtime·racewritepc(void *addr, void *callpc, void *pc);
-void	runtime·racereadpc(void *addr, void *callpc, void *pc);
-void	runtime·racewriterangepc(void *addr, uintptr sz, void *callpc, void *pc);
-void	runtime·racereadrangepc(void *addr, uintptr sz, void *callpc, void *pc);
-void	runtime·racereadobjectpc(void *addr, Type *t, void *callpc, void *pc);
-void	runtime·racewriteobjectpc(void *addr, Type *t, void *callpc, void *pc);
-void	runtime·racefingo(void);
-void	runtime·raceacquire(void *addr);
-void	runtime·raceacquireg(G *gp, void *addr);
-void	runtime·racerelease(void *addr);
-void	runtime·racereleaseg(G *gp, void *addr);
-void	runtime·racereleasemerge(void *addr);
-void	runtime·racereleasemergeg(G *gp, void *addr);
diff --git a/src/runtime/race/README b/src/runtime/race/README
index 7f18535..52dd38e 100644
--- a/src/runtime/race/README
+++ b/src/runtime/race/README
@@ -9,4 +9,4 @@ $ ./buildgo.sh
 
 Tested with gcc 4.6.1 and 4.7.0.  On Windows it's built with 64-bit MinGW.
 
-Current runtime is built on rev 215000.
+Current runtime is built on rev 229396.
diff --git a/src/runtime/race/doc.go b/src/runtime/race/doc.go
index aef805d..9e93f66 100644
--- a/src/runtime/race/doc.go
+++ b/src/runtime/race/doc.go
@@ -5,5 +5,5 @@
 // Package race implements data race detection logic.
 // No public interface is provided.
 // For details about the race detector see
-// http://golang.org/doc/articles/race_detector.html
+// https://golang.org/doc/articles/race_detector.html
 package race
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 @@ func TestOutput(t *testing.T) {
 			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 @@ func TestOutput(t *testing.T) {
 			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 @@ func TestOutput(t *testing.T) {
 
 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 @@ Found 1 data race\(s\)
 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 @@ func main() {
 }
 `, `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 @@ func main() {
       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 @@ func main() {
 ==================
 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/race/race_darwin_amd64.syso b/src/runtime/race/race_darwin_amd64.syso
index 81b48c6..9cf1ecc 100644
Binary files a/src/runtime/race/race_darwin_amd64.syso and b/src/runtime/race/race_darwin_amd64.syso differ
diff --git a/src/runtime/race/race_freebsd_amd64.syso b/src/runtime/race/race_freebsd_amd64.syso
index 5bbe322..50ae2d3 100644
Binary files a/src/runtime/race/race_freebsd_amd64.syso and b/src/runtime/race/race_freebsd_amd64.syso differ
diff --git a/src/runtime/race/race_linux_amd64.syso b/src/runtime/race/race_linux_amd64.syso
index 49bf08e..a141051 100644
Binary files a/src/runtime/race/race_linux_amd64.syso and b/src/runtime/race/race_linux_amd64.syso differ
diff --git a/src/runtime/race/race_test.go b/src/runtime/race/race_test.go
index 7e0ee86..6898e74 100644
--- a/src/runtime/race/race_test.go
+++ b/src/runtime/race/race_test.go
@@ -36,7 +36,7 @@ var (
 
 const (
 	visibleLen = 40
-	testPrefix = "=== RUN Test"
+	testPrefix = "=== RUN   Test"
 )
 
 func TestRace(t *testing.T) {
@@ -63,6 +63,9 @@ func TestRace(t *testing.T) {
 		}
 	}
 
+	if totalTests == 0 {
+		t.Fatalf("failed to parse test output")
+	}
 	fmt.Printf("\nPassed %d of %d tests (%.02f%%, %d+, %d-)\n",
 		passedTests, totalTests, 100*float64(passedTests)/float64(totalTests), falsePos, falseNeg)
 	fmt.Printf("%d expected failures (%d has not fail)\n", failingPos+failingNeg, failingNeg)
@@ -152,7 +155,7 @@ func runTests() ([]byte, error) {
 		}
 		cmd.Env = append(cmd.Env, env)
 	}
-	cmd.Env = append(cmd.Env, `GORACE="suppress_equal_stacks=0 suppress_equal_addresses=0 exitcode=0"`)
+	cmd.Env = append(cmd.Env, `GORACE=suppress_equal_stacks=0 suppress_equal_addresses=0 exitcode=0`)
 	return cmd.CombinedOutput()
 }
 
@@ -170,3 +173,12 @@ func TestIssue8102(t *testing.T) {
 		}
 	}
 }
+
+func TestIssue9137(t *testing.T) {
+	a := []string{"a"}
+	i := 0
+	a[i], a[len(a)-1], a = a[len(a)-1], "", a[:len(a)-1]
+	if len(a) != 0 || a[:1][0] != "" {
+		t.Errorf("mangled a: %q %q", a, a[:1])
+	}
+}
diff --git a/src/runtime/race/race_windows_amd64.syso b/src/runtime/race/race_windows_amd64.syso
index a4eae9b..125115e 100644
Binary files a/src/runtime/race/race_windows_amd64.syso and b/src/runtime/race/race_windows_amd64.syso differ
diff --git a/src/runtime/race/sched_test.go b/src/runtime/race/sched_test.go
new file mode 100644
index 0000000..aac8fed
--- /dev/null
+++ b/src/runtime/race/sched_test.go
@@ -0,0 +1,48 @@
+// 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 race
+
+package race_test
+
+import (
+	"bytes"
+	"fmt"
+	"reflect"
+	"runtime"
+	"testing"
+)
+
+func TestRandomScheduling(t *testing.T) {
+	// Scheduler is most consistent with GOMAXPROCS=1.
+	// Use that to make the test most likely to fail.
+	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
+	const N = 10
+	out := make([][]int, N)
+	for i := 0; i < N; i++ {
+		c := make(chan int, N)
+		for j := 0; j < N; j++ {
+			go func(j int) {
+				c <- j
+			}(j)
+		}
+		row := make([]int, N)
+		for j := 0; j < N; j++ {
+			row[j] = <-c
+		}
+		out[i] = row
+	}
+
+	for i := 0; i < N; i++ {
+		if !reflect.DeepEqual(out[0], out[i]) {
+			return // found a different order
+		}
+	}
+
+	var buf bytes.Buffer
+	for i := 0; i < N; i++ {
+		fmt.Fprintf(&buf, "%v\n", out[i])
+	}
+	t.Fatalf("consistent goroutine execution order:\n%v", buf.String())
+}
diff --git a/src/runtime/race/testdata/io_test.go b/src/runtime/race/testdata/io_test.go
index 9eb3552..1b3ee38 100644
--- a/src/runtime/race/testdata/io_test.go
+++ b/src/runtime/race/testdata/io_test.go
@@ -49,7 +49,7 @@ func TestNoRaceIOHttp(t *testing.T) {
 			fmt.Fprintf(w, "test")
 			x = 42
 		})
-		err := http.ListenAndServe(":23651", nil)
+		err := http.ListenAndServe("127.0.0.1:23651", nil)
 		if err != nil {
 			t.Fatalf("http.ListenAndServe: %v", err)
 		}
diff --git a/src/runtime/race/testdata/mop_test.go b/src/runtime/race/testdata/mop_test.go
index cb17a27..d7cbc98 100644
--- a/src/runtime/race/testdata/mop_test.go
+++ b/src/runtime/race/testdata/mop_test.go
@@ -335,6 +335,8 @@ func TestRaceRange(t *testing.T) {
 			}
 			done <- true
 		}(i)
+		// Ensure the goroutine runs before we continue the loop.
+		runtime.Gosched()
 	}
 	for i := 0; i < N; i++ {
 		<-done
@@ -1063,6 +1065,7 @@ func TestRaceCrawl(t *testing.T) {
 		}()
 		seen[u] = true
 		if d <= 0 {
+			wg.Done()
 			return
 		}
 		urls := [...]string{"a", "b", "c"}
@@ -1584,6 +1587,110 @@ func TestRaceBlockAs(t *testing.T) {
 	<-c
 }
 
+func TestRaceBlockCall1(t *testing.T) {
+	done := make(chan bool)
+	x, y := 0, 0
+	go func() {
+		f := func() (int, int) {
+			return 42, 43
+		}
+		x, y = f()
+		done <- true
+	}()
+	_ = x
+	<-done
+	if x != 42 || y != 43 {
+		panic("corrupted data")
+	}
+}
+func TestRaceBlockCall2(t *testing.T) {
+	done := make(chan bool)
+	x, y := 0, 0
+	go func() {
+		f := func() (int, int) {
+			return 42, 43
+		}
+		x, y = f()
+		done <- true
+	}()
+	_ = y
+	<-done
+	if x != 42 || y != 43 {
+		panic("corrupted data")
+	}
+}
+func TestRaceBlockCall3(t *testing.T) {
+	done := make(chan bool)
+	var x *int
+	y := 0
+	go func() {
+		f := func() (*int, int) {
+			i := 42
+			return &i, 43
+		}
+		x, y = f()
+		done <- true
+	}()
+	_ = x
+	<-done
+	if *x != 42 || y != 43 {
+		panic("corrupted data")
+	}
+}
+func TestRaceBlockCall4(t *testing.T) {
+	done := make(chan bool)
+	x := 0
+	var y *int
+	go func() {
+		f := func() (int, *int) {
+			i := 43
+			return 42, &i
+		}
+		x, y = f()
+		done <- true
+	}()
+	_ = y
+	<-done
+	if x != 42 || *y != 43 {
+		panic("corrupted data")
+	}
+}
+func TestRaceBlockCall5(t *testing.T) {
+	done := make(chan bool)
+	var x *int
+	y := 0
+	go func() {
+		f := func() (*int, int) {
+			i := 42
+			return &i, 43
+		}
+		x, y = f()
+		done <- true
+	}()
+	_ = y
+	<-done
+	if *x != 42 || y != 43 {
+		panic("corrupted data")
+	}
+}
+func TestRaceBlockCall6(t *testing.T) {
+	done := make(chan bool)
+	x := 0
+	var y *int
+	go func() {
+		f := func() (int, *int) {
+			i := 43
+			return 42, &i
+		}
+		x, y = f()
+		done <- true
+	}()
+	_ = x
+	<-done
+	if x != 42 || *y != 43 {
+		panic("corrupted data")
+	}
+}
 func TestRaceSliceSlice(t *testing.T) {
 	c := make(chan bool, 1)
 	x := make([]int, 10)
@@ -1726,13 +1833,16 @@ func TestNoRaceAsFunc4(t *testing.T) {
 }
 
 func TestRaceHeapParam(t *testing.T) {
+	done := make(chan bool)
 	x := func() (x int) {
 		go func() {
 			x = 42
+			done <- true
 		}()
 		return
 	}()
 	_ = x
+	<-done
 }
 
 func TestNoRaceEmptyStruct(t *testing.T) {
diff --git a/src/runtime/race/testdata/rwmutex_test.go b/src/runtime/race/testdata/rwmutex_test.go
index 85cb5df..7ac829d 100644
--- a/src/runtime/race/testdata/rwmutex_test.go
+++ b/src/runtime/race/testdata/rwmutex_test.go
@@ -54,13 +54,16 @@ func TestNoRaceRWMutex(t *testing.T) {
 func TestRaceRWMutexMultipleReaders(t *testing.T) {
 	var mu sync.RWMutex
 	var x, y int64 = 0, 1
-	ch := make(chan bool, 3)
+	ch := make(chan bool, 4)
 	go func() {
 		mu.Lock()
 		defer mu.Unlock()
 		x = 2
 		ch <- true
 	}()
+	// Use three readers so that no matter what order they're
+	// scheduled in, two will be on the same side of the write
+	// lock above.
 	go func() {
 		mu.RLock()
 		y = x + 1
@@ -73,6 +76,13 @@ func TestRaceRWMutexMultipleReaders(t *testing.T) {
 		mu.RUnlock()
 		ch <- true
 	}()
+	go func() {
+		mu.RLock()
+		y = x + 3
+		mu.RUnlock()
+		ch <- true
+	}()
+	<-ch
 	<-ch
 	<-ch
 	<-ch
@@ -82,7 +92,7 @@ func TestRaceRWMutexMultipleReaders(t *testing.T) {
 func TestNoRaceRWMutexMultipleReaders(t *testing.T) {
 	var mu sync.RWMutex
 	x := int64(0)
-	ch := make(chan bool, 3)
+	ch := make(chan bool, 4)
 	go func() {
 		mu.Lock()
 		defer mu.Unlock()
@@ -103,6 +113,14 @@ func TestNoRaceRWMutexMultipleReaders(t *testing.T) {
 		mu.RUnlock()
 		ch <- true
 	}()
+	go func() {
+		mu.RLock()
+		y := x + 3
+		_ = y
+		mu.RUnlock()
+		ch <- true
+	}()
+	<-ch
 	<-ch
 	<-ch
 	<-ch
diff --git a/src/runtime/race/testdata/select_test.go b/src/runtime/race/testdata/select_test.go
index 4a3a236..b4b1991 100644
--- a/src/runtime/race/testdata/select_test.go
+++ b/src/runtime/race/testdata/select_test.go
@@ -236,7 +236,7 @@ func TestRaceSelect4(t *testing.T) {
 // there are two variables, access to one
 // of them is synchronized, access to the other
 // is not.
-// Select must (unconditionaly) choose the non-synchronized variable
+// Select must (unconditionally) choose the non-synchronized variable
 // thus causing exactly one race.
 // Currently this test doesn't look like it accomplishes
 // this goal.
diff --git a/src/runtime/race/testdata/slice_test.go b/src/runtime/race/testdata/slice_test.go
index 5702d1a..1ec5243 100644
--- a/src/runtime/race/testdata/slice_test.go
+++ b/src/runtime/race/testdata/slice_test.go
@@ -144,6 +144,54 @@ func TestNoRaceSliceCopyRead(t *testing.T) {
 	<-ch
 }
 
+func TestRacePointerSliceCopyRead(t *testing.T) {
+	ch := make(chan bool, 1)
+	a := make([]*int, 10)
+	b := make([]*int, 10)
+	go func() {
+		_ = a[5]
+		ch <- true
+	}()
+	copy(a, b)
+	<-ch
+}
+
+func TestNoRacePointerSliceWriteCopy(t *testing.T) {
+	ch := make(chan bool, 1)
+	a := make([]*int, 10)
+	b := make([]*int, 10)
+	go func() {
+		a[5] = new(int)
+		ch <- true
+	}()
+	copy(a[:5], b[:5])
+	<-ch
+}
+
+func TestRacePointerSliceCopyWrite2(t *testing.T) {
+	ch := make(chan bool, 1)
+	a := make([]*int, 10)
+	b := make([]*int, 10)
+	go func() {
+		b[5] = new(int)
+		ch <- true
+	}()
+	copy(a, b)
+	<-ch
+}
+
+func TestNoRacePointerSliceCopyRead(t *testing.T) {
+	ch := make(chan bool, 1)
+	a := make([]*int, 10)
+	b := make([]*int, 10)
+	go func() {
+		_ = b[5]
+		ch <- true
+	}()
+	copy(a, b)
+	<-ch
+}
+
 func TestNoRaceSliceWriteSlice2(t *testing.T) {
 	ch := make(chan bool, 1)
 	a := make([]float64, 10)
@@ -395,6 +443,53 @@ func TestRaceSliceAppendString(t *testing.T) {
 	<-c
 }
 
+func TestRacePointerSliceAppend(t *testing.T) {
+	c := make(chan bool, 1)
+	s := make([]*int, 10, 20)
+	go func() {
+		_ = append(s, new(int))
+		c <- true
+	}()
+	_ = append(s, new(int))
+	<-c
+}
+
+func TestRacePointerSliceAppendWrite(t *testing.T) {
+	c := make(chan bool, 1)
+	s := make([]*int, 10)
+	go func() {
+		_ = append(s, new(int))
+		c <- true
+	}()
+	s[0] = new(int)
+	<-c
+}
+
+func TestRacePointerSliceAppendSlice(t *testing.T) {
+	c := make(chan bool, 1)
+	s := make([]*int, 10)
+	go func() {
+		s2 := make([]*int, 10)
+		_ = append(s, s2...)
+		c <- true
+	}()
+	s[0] = new(int)
+	<-c
+}
+
+func TestRacePointerSliceAppendSlice2(t *testing.T) {
+	c := make(chan bool, 1)
+	s := make([]*int, 10)
+	s2foobar := make([]*int, 10)
+	go func() {
+		_ = append(s, s2foobar...)
+		c <- true
+	}()
+	println("WRITE:", &s2foobar[5])
+	s2foobar[5] = nil
+	<-c
+}
+
 func TestNoRaceSliceIndexAccess(t *testing.T) {
 	c := make(chan bool, 1)
 	s := make([]int, 10)
@@ -483,3 +578,15 @@ func TestRaceCompareString(t *testing.T) {
 	s1 = s2
 	<-c
 }
+
+func TestRaceSlice3(t *testing.T) {
+	done := make(chan bool)
+	x := make([]int, 10)
+	i := 2
+	go func() {
+		i = 3
+		done <- true
+	}()
+	_ = x[:1:i]
+	<-done
+}
diff --git a/src/runtime/race/testdata/sync_test.go b/src/runtime/race/testdata/sync_test.go
index 93af0b1..d48680d 100644
--- a/src/runtime/race/testdata/sync_test.go
+++ b/src/runtime/race/testdata/sync_test.go
@@ -10,72 +10,52 @@ import (
 	"time"
 )
 
-func TestNoRaceCond(t *testing.T) { // tsan's test02
-	ch := make(chan bool, 1)
-	var x int = 0
+func TestNoRaceCond(t *testing.T) {
+	x := 0
+	condition := 0
 	var mu sync.Mutex
-	var cond *sync.Cond = sync.NewCond(&mu)
-	var condition int = 0
-	var waker func()
-	waker = func() {
+	cond := sync.NewCond(&mu)
+	go func() {
 		x = 1
 		mu.Lock()
 		condition = 1
 		cond.Signal()
 		mu.Unlock()
+	}()
+	mu.Lock()
+	for condition != 1 {
+		cond.Wait()
 	}
-
-	var waiter func()
-	waiter = func() {
-		go waker()
-		cond.L.Lock()
-		for condition != 1 {
-			cond.Wait()
-		}
-		cond.L.Unlock()
-		x = 2
-		ch <- true
-	}
-	go waiter()
-	<-ch
+	mu.Unlock()
+	x = 2
 }
 
-func TestRaceCond(t *testing.T) { // tsan's test50
-	ch := make(chan bool, 2)
-
-	var x int = 0
+func TestRaceCond(t *testing.T) {
+	done := make(chan bool)
 	var mu sync.Mutex
-	var condition int = 0
-	var cond *sync.Cond = sync.NewCond(&mu)
-
-	var waker func() = func() {
-		<-time.After(1e5)
+	cond := sync.NewCond(&mu)
+	x := 0
+	condition := 0
+	go func() {
+		time.Sleep(10 * time.Millisecond) // Enter cond.Wait loop
 		x = 1
 		mu.Lock()
 		condition = 1
 		cond.Signal()
 		mu.Unlock()
-		<-time.After(1e5)
+		time.Sleep(10 * time.Millisecond) // Exit cond.Wait loop
 		mu.Lock()
 		x = 3
 		mu.Unlock()
-		ch <- true
-	}
-
-	var waiter func() = func() {
-		mu.Lock()
-		for condition != 1 {
-			cond.Wait()
-		}
-		mu.Unlock()
-		x = 2
-		ch <- true
+		done <- true
+	}()
+	mu.Lock()
+	for condition != 1 {
+		cond.Wait()
 	}
-	x = 0
-	go waker()
-	go waiter()
-	<-ch
-	<-ch
+	mu.Unlock()
+	x = 2
+	<-done
 }
 
 // We do not currently automatically
diff --git a/src/runtime/race0.go b/src/runtime/race0.go
index 5d90cc8..591d5d9 100644
--- a/src/runtime/race0.go
+++ b/src/runtime/race0.go
@@ -16,22 +16,22 @@ const raceenabled = false
 
 // Because raceenabled is false, none of these functions should be called.
 
-func raceReadObjectPC(t *_type, addr unsafe.Pointer, callerpc, pc uintptr)  { gothrow("race") }
-func raceWriteObjectPC(t *_type, addr unsafe.Pointer, callerpc, pc uintptr) { gothrow("race") }
-func raceinit()                                                             { gothrow("race") }
-func racefini()                                                             { gothrow("race") }
-func racemapshadow(addr unsafe.Pointer, size uintptr)                       { gothrow("race") }
-func racewritepc(addr unsafe.Pointer, callerpc, pc uintptr)                 { gothrow("race") }
-func racereadpc(addr unsafe.Pointer, callerpc, pc uintptr)                  { gothrow("race") }
-func racereadrangepc(addr unsafe.Pointer, sz, callerpc, pc uintptr)         { gothrow("race") }
-func racewriterangepc(addr unsafe.Pointer, sz, callerpc, pc uintptr)        { gothrow("race") }
-func raceacquire(addr unsafe.Pointer)                                       { gothrow("race") }
-func raceacquireg(gp *g, addr unsafe.Pointer)                               { gothrow("race") }
-func racerelease(addr unsafe.Pointer)                                       { gothrow("race") }
-func racereleaseg(gp *g, addr unsafe.Pointer)                               { gothrow("race") }
-func racereleasemerge(addr unsafe.Pointer)                                  { gothrow("race") }
-func racereleasemergeg(gp *g, addr unsafe.Pointer)                          { gothrow("race") }
-func racefingo()                                                            { gothrow("race") }
-func racemalloc(p unsafe.Pointer, sz uintptr)                               { gothrow("race") }
-func racegostart(pc uintptr) uintptr                                        { gothrow("race"); return 0 }
-func racegoend()                                                            { gothrow("race") }
+func raceReadObjectPC(t *_type, addr unsafe.Pointer, callerpc, pc uintptr)  { throw("race") }
+func raceWriteObjectPC(t *_type, addr unsafe.Pointer, callerpc, pc uintptr) { throw("race") }
+func raceinit() uintptr                                                     { throw("race"); return 0 }
+func racefini()                                                             { throw("race") }
+func racemapshadow(addr unsafe.Pointer, size uintptr)                       { throw("race") }
+func racewritepc(addr unsafe.Pointer, callerpc, pc uintptr)                 { throw("race") }
+func racereadpc(addr unsafe.Pointer, callerpc, pc uintptr)                  { throw("race") }
+func racereadrangepc(addr unsafe.Pointer, sz, callerpc, pc uintptr)         { throw("race") }
+func racewriterangepc(addr unsafe.Pointer, sz, callerpc, pc uintptr)        { throw("race") }
+func raceacquire(addr unsafe.Pointer)                                       { throw("race") }
+func raceacquireg(gp *g, addr unsafe.Pointer)                               { throw("race") }
+func racerelease(addr unsafe.Pointer)                                       { throw("race") }
+func racereleaseg(gp *g, addr unsafe.Pointer)                               { throw("race") }
+func racereleasemerge(addr unsafe.Pointer)                                  { throw("race") }
+func racereleasemergeg(gp *g, addr unsafe.Pointer)                          { throw("race") }
+func racefingo()                                                            { throw("race") }
+func racemalloc(p unsafe.Pointer, sz uintptr)                               { throw("race") }
+func racegostart(pc uintptr) uintptr                                        { throw("race"); return 0 }
+func racegoend()                                                            { throw("race") }
diff --git a/src/runtime/race1.go b/src/runtime/race1.go
new file mode 100644
index 0000000..38afca7
--- /dev/null
+++ b/src/runtime/race1.go
@@ -0,0 +1,315 @@
+// 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.
+
+// Implementation of the race detector API.
+// +build race
+
+package runtime
+
+import "unsafe"
+
+// Race runtime functions called via runtime·racecall.
+//go:linkname __tsan_init __tsan_init
+var __tsan_init byte
+
+//go:linkname __tsan_fini __tsan_fini
+var __tsan_fini byte
+
+//go:linkname __tsan_map_shadow __tsan_map_shadow
+var __tsan_map_shadow byte
+
+//go:linkname __tsan_finalizer_goroutine __tsan_finalizer_goroutine
+var __tsan_finalizer_goroutine byte
+
+//go:linkname __tsan_go_start __tsan_go_start
+var __tsan_go_start byte
+
+//go:linkname __tsan_go_end __tsan_go_end
+var __tsan_go_end byte
+
+//go:linkname __tsan_malloc __tsan_malloc
+var __tsan_malloc byte
+
+//go:linkname __tsan_acquire __tsan_acquire
+var __tsan_acquire byte
+
+//go:linkname __tsan_release __tsan_release
+var __tsan_release byte
+
+//go:linkname __tsan_release_merge __tsan_release_merge
+var __tsan_release_merge byte
+
+//go:linkname __tsan_go_ignore_sync_begin __tsan_go_ignore_sync_begin
+var __tsan_go_ignore_sync_begin byte
+
+//go:linkname __tsan_go_ignore_sync_end __tsan_go_ignore_sync_end
+var __tsan_go_ignore_sync_end byte
+
+// Mimic what cmd/cgo would do.
+//go:cgo_import_static __tsan_init
+//go:cgo_import_static __tsan_fini
+//go:cgo_import_static __tsan_map_shadow
+//go:cgo_import_static __tsan_finalizer_goroutine
+//go:cgo_import_static __tsan_go_start
+//go:cgo_import_static __tsan_go_end
+//go:cgo_import_static __tsan_malloc
+//go:cgo_import_static __tsan_acquire
+//go:cgo_import_static __tsan_release
+//go:cgo_import_static __tsan_release_merge
+//go:cgo_import_static __tsan_go_ignore_sync_begin
+//go:cgo_import_static __tsan_go_ignore_sync_end
+
+// These are called from race_amd64.s.
+//go:cgo_import_static __tsan_read
+//go:cgo_import_static __tsan_read_pc
+//go:cgo_import_static __tsan_read_range
+//go:cgo_import_static __tsan_write
+//go:cgo_import_static __tsan_write_pc
+//go:cgo_import_static __tsan_write_range
+//go:cgo_import_static __tsan_func_enter
+//go:cgo_import_static __tsan_func_exit
+
+//go:cgo_import_static __tsan_go_atomic32_load
+//go:cgo_import_static __tsan_go_atomic64_load
+//go:cgo_import_static __tsan_go_atomic32_store
+//go:cgo_import_static __tsan_go_atomic64_store
+//go:cgo_import_static __tsan_go_atomic32_exchange
+//go:cgo_import_static __tsan_go_atomic64_exchange
+//go:cgo_import_static __tsan_go_atomic32_fetch_add
+//go:cgo_import_static __tsan_go_atomic64_fetch_add
+//go:cgo_import_static __tsan_go_atomic32_compare_exchange
+//go:cgo_import_static __tsan_go_atomic64_compare_exchange
+
+// start/end of global data (data+bss).
+var racedatastart uintptr
+var racedataend uintptr
+
+// start/end of heap for race_amd64.s
+var racearenastart uintptr
+var racearenaend uintptr
+
+func racefuncenter(uintptr)
+func racefuncexit()
+func racereadrangepc1(uintptr, uintptr, uintptr)
+func racewriterangepc1(uintptr, uintptr, uintptr)
+func racesymbolizethunk(uintptr)
+
+// racecall allows calling an arbitrary function f from C race runtime
+// with up to 4 uintptr arguments.
+func racecall(*byte, uintptr, uintptr, uintptr, uintptr)
+
+// checks if the address has shadow (i.e. heap or data/bss)
+//go:nosplit
+func isvalidaddr(addr unsafe.Pointer) bool {
+	return racearenastart <= uintptr(addr) && uintptr(addr) < racearenaend ||
+		racedatastart <= uintptr(addr) && uintptr(addr) < racedataend
+}
+
+//go:nosplit
+func raceinit() uintptr {
+	// cgo is required to initialize libc, which is used by race runtime
+	if !iscgo {
+		throw("raceinit: race build must use cgo")
+	}
+
+	var racectx uintptr
+	racecall(&__tsan_init, uintptr(unsafe.Pointer(&racectx)), funcPC(racesymbolizethunk), 0, 0)
+
+	// Round data segment to page boundaries, because it's used in mmap().
+	start := ^uintptr(0)
+	end := uintptr(0)
+	if start > firstmoduledata.noptrdata {
+		start = firstmoduledata.noptrdata
+	}
+	if start > firstmoduledata.data {
+		start = firstmoduledata.data
+	}
+	if start > firstmoduledata.noptrbss {
+		start = firstmoduledata.noptrbss
+	}
+	if start > firstmoduledata.bss {
+		start = firstmoduledata.bss
+	}
+	if end < firstmoduledata.enoptrdata {
+		end = firstmoduledata.enoptrdata
+	}
+	if end < firstmoduledata.edata {
+		end = firstmoduledata.edata
+	}
+	if end < firstmoduledata.enoptrbss {
+		end = firstmoduledata.enoptrbss
+	}
+	if end < firstmoduledata.ebss {
+		end = firstmoduledata.ebss
+	}
+	size := round(end-start, _PageSize)
+	racecall(&__tsan_map_shadow, start, size, 0, 0)
+	racedatastart = start
+	racedataend = start + size
+
+	return racectx
+}
+
+//go:nosplit
+func racefini() {
+	racecall(&__tsan_fini, 0, 0, 0, 0)
+}
+
+//go:nosplit
+func racemapshadow(addr unsafe.Pointer, size uintptr) {
+	if racearenastart == 0 {
+		racearenastart = uintptr(addr)
+	}
+	if racearenaend < uintptr(addr)+size {
+		racearenaend = uintptr(addr) + size
+	}
+	racecall(&__tsan_map_shadow, uintptr(addr), size, 0, 0)
+}
+
+//go:nosplit
+func racemalloc(p unsafe.Pointer, sz uintptr) {
+	racecall(&__tsan_malloc, uintptr(p), sz, 0, 0)
+}
+
+//go:nosplit
+func racegostart(pc uintptr) uintptr {
+	_g_ := getg()
+	var spawng *g
+	if _g_.m.curg != nil {
+		spawng = _g_.m.curg
+	} else {
+		spawng = _g_
+	}
+
+	var racectx uintptr
+	racecall(&__tsan_go_start, spawng.racectx, uintptr(unsafe.Pointer(&racectx)), pc, 0)
+	return racectx
+}
+
+//go:nosplit
+func racegoend() {
+	racecall(&__tsan_go_end, getg().racectx, 0, 0, 0)
+}
+
+//go:nosplit
+func racewriterangepc(addr unsafe.Pointer, sz, callpc, pc uintptr) {
+	_g_ := getg()
+	if _g_ != _g_.m.curg {
+		// The call is coming from manual instrumentation of Go code running on g0/gsignal.
+		// Not interesting.
+		return
+	}
+	if callpc != 0 {
+		racefuncenter(callpc)
+	}
+	racewriterangepc1(uintptr(addr), sz, pc)
+	if callpc != 0 {
+		racefuncexit()
+	}
+}
+
+//go:nosplit
+func racereadrangepc(addr unsafe.Pointer, sz, callpc, pc uintptr) {
+	_g_ := getg()
+	if _g_ != _g_.m.curg {
+		// The call is coming from manual instrumentation of Go code running on g0/gsignal.
+		// Not interesting.
+		return
+	}
+	if callpc != 0 {
+		racefuncenter(callpc)
+	}
+	racereadrangepc1(uintptr(addr), sz, pc)
+	if callpc != 0 {
+		racefuncexit()
+	}
+}
+
+//go:nosplit
+func raceacquire(addr unsafe.Pointer) {
+	raceacquireg(getg(), addr)
+}
+
+//go:nosplit
+func raceacquireg(gp *g, addr unsafe.Pointer) {
+	if getg().raceignore != 0 || !isvalidaddr(addr) {
+		return
+	}
+	racecall(&__tsan_acquire, gp.racectx, uintptr(addr), 0, 0)
+}
+
+//go:nosplit
+func racerelease(addr unsafe.Pointer) {
+	_g_ := getg()
+	if _g_.raceignore != 0 || !isvalidaddr(addr) {
+		return
+	}
+	racereleaseg(_g_, addr)
+}
+
+//go:nosplit
+func racereleaseg(gp *g, addr unsafe.Pointer) {
+	if getg().raceignore != 0 || !isvalidaddr(addr) {
+		return
+	}
+	racecall(&__tsan_release, gp.racectx, uintptr(addr), 0, 0)
+}
+
+//go:nosplit
+func racereleasemerge(addr unsafe.Pointer) {
+	racereleasemergeg(getg(), addr)
+}
+
+//go:nosplit
+func racereleasemergeg(gp *g, addr unsafe.Pointer) {
+	if getg().raceignore != 0 || !isvalidaddr(addr) {
+		return
+	}
+	racecall(&__tsan_release_merge, gp.racectx, uintptr(addr), 0, 0)
+}
+
+//go:nosplit
+func racefingo() {
+	racecall(&__tsan_finalizer_goroutine, getg().racectx, 0, 0, 0)
+}
+
+//go:nosplit
+
+func RaceAcquire(addr unsafe.Pointer) {
+	raceacquire(addr)
+}
+
+//go:nosplit
+
+func RaceRelease(addr unsafe.Pointer) {
+	racerelease(addr)
+}
+
+//go:nosplit
+
+func RaceReleaseMerge(addr unsafe.Pointer) {
+	racereleasemerge(addr)
+}
+
+//go:nosplit
+
+// RaceDisable disables handling of race events in the current goroutine.
+func RaceDisable() {
+	_g_ := getg()
+	if _g_.raceignore == 0 {
+		racecall(&__tsan_go_ignore_sync_begin, _g_.racectx, 0, 0, 0)
+	}
+	_g_.raceignore++
+}
+
+//go:nosplit
+
+// RaceEnable re-enables handling of race events in the current goroutine.
+func RaceEnable() {
+	_g_ := getg()
+	_g_.raceignore--
+	if _g_.raceignore == 0 {
+		racecall(&__tsan_go_ignore_sync_end, _g_.racectx, 0, 0, 0)
+	}
+}
diff --git a/src/runtime/race_amd64.s b/src/runtime/race_amd64.s
index a96d9de..d9e674b 100644
--- a/src/runtime/race_amd64.s
+++ b/src/runtime/race_amd64.s
@@ -4,7 +4,8 @@
 
 // +build race
 
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
 #include "funcdata.h"
 #include "textflag.h"
 
@@ -57,6 +58,7 @@ TEXT	runtime·racereadpc(SB), NOSPLIT, $0-24
 	MOVQ	addr+0(FP), RARG1
 	MOVQ	callpc+8(FP), RARG2
 	MOVQ	pc+16(FP), RARG3
+	ADDQ	$1, RARG3 // pc is function start, tsan wants return address
 	// void __tsan_read_pc(ThreadState *thr, void *addr, void *callpc, void *pc);
 	MOVQ	$__tsan_read_pc(SB), AX
 	JMP	racecalladdr<>(SB)
@@ -80,6 +82,7 @@ TEXT	runtime·racewritepc(SB), NOSPLIT, $0-24
 	MOVQ	addr+0(FP), RARG1
 	MOVQ	callpc+8(FP), RARG2
 	MOVQ	pc+16(FP), RARG3
+	ADDQ	$1, RARG3 // pc is function start, tsan wants return address
 	// void __tsan_write_pc(ThreadState *thr, void *addr, void *callpc, void *pc);
 	MOVQ	$__tsan_write_pc(SB), AX
 	JMP	racecalladdr<>(SB)
@@ -104,6 +107,7 @@ TEXT	runtime·racereadrangepc1(SB), NOSPLIT, $0-24
 	MOVQ	addr+0(FP), RARG1
 	MOVQ	size+8(FP), RARG2
 	MOVQ	pc+16(FP), RARG3
+	ADDQ	$1, RARG3 // pc is function start, tsan wants return address
 	// void __tsan_read_range(ThreadState *thr, void *addr, uintptr size, void *pc);
 	MOVQ	$__tsan_read_range(SB), AX
 	JMP	racecalladdr<>(SB)
@@ -128,6 +132,7 @@ TEXT	runtime·racewriterangepc1(SB), NOSPLIT, $0-24
 	MOVQ	addr+0(FP), RARG1
 	MOVQ	size+8(FP), RARG2
 	MOVQ	pc+16(FP), RARG3
+	ADDQ	$1, RARG3 // pc is function start, tsan wants return address
 	// void __tsan_write_range(ThreadState *thr, void *addr, uintptr size, void *pc);
 	MOVQ	$__tsan_write_range(SB), AX
 	JMP	racecalladdr<>(SB)
@@ -140,18 +145,18 @@ TEXT	racecalladdr<>(SB), NOSPLIT, $0-0
 	MOVQ	g_racectx(R14), RARG0	// goroutine context
 	// Check that addr is within [arenastart, arenaend) or within [racedatastart, racedataend).
 	CMPQ	RARG1, runtime·racearenastart(SB)
-	JB	racecalladdr_data
+	JB	data
 	CMPQ	RARG1, runtime·racearenaend(SB)
-	JB	racecalladdr_call
-racecalladdr_data:
+	JB	call
+data:
 	CMPQ	RARG1, runtime·racedatastart(SB)
-	JB	racecalladdr_ret
+	JB	ret
 	CMPQ	RARG1, runtime·racedataend(SB)
-	JAE	racecalladdr_ret
-racecalladdr_call:
+	JAE	ret
+call:
 	MOVQ	AX, AX		// w/o this 6a miscompiles this function
 	JMP	racecall<>(SB)
-racecalladdr_ret:
+ret:
 	RET
 
 // func runtime·racefuncenter(pc uintptr)
@@ -224,9 +229,6 @@ TEXT	sync∕atomic·StoreUint64(SB), NOSPLIT, $0-0
 TEXT	sync∕atomic·StoreUintptr(SB), NOSPLIT, $0-0
 	JMP	sync∕atomic·StoreInt64(SB)
 
-TEXT	sync∕atomic·StorePointer(SB), NOSPLIT, $0-0
-	JMP	sync∕atomic·StoreInt64(SB)
-
 // Swap
 TEXT	sync∕atomic·SwapInt32(SB), NOSPLIT, $0-0
 	MOVQ	$__tsan_go_atomic32_exchange(SB), AX
@@ -247,9 +249,6 @@ TEXT	sync∕atomic·SwapUint64(SB), NOSPLIT, $0-0
 TEXT	sync∕atomic·SwapUintptr(SB), NOSPLIT, $0-0
 	JMP	sync∕atomic·SwapInt64(SB)
 
-TEXT	sync∕atomic·SwapPointer(SB), NOSPLIT, $0-0
-	JMP	sync∕atomic·SwapInt64(SB)
-
 // Add
 TEXT	sync∕atomic·AddInt32(SB), NOSPLIT, $0-0
 	MOVQ	$__tsan_go_atomic32_fetch_add(SB), AX
@@ -274,9 +273,6 @@ TEXT	sync∕atomic·AddUint64(SB), NOSPLIT, $0-0
 TEXT	sync∕atomic·AddUintptr(SB), NOSPLIT, $0-0
 	JMP	sync∕atomic·AddInt64(SB)
 
-TEXT	sync∕atomic·AddPointer(SB), NOSPLIT, $0-0
-	JMP	sync∕atomic·AddInt64(SB)
-
 // CompareAndSwap
 TEXT	sync∕atomic·CompareAndSwapInt32(SB), NOSPLIT, $0-0
 	MOVQ	$__tsan_go_atomic32_compare_exchange(SB), AX
@@ -297,9 +293,6 @@ TEXT	sync∕atomic·CompareAndSwapUint64(SB), NOSPLIT, $0-0
 TEXT	sync∕atomic·CompareAndSwapUintptr(SB), NOSPLIT, $0-0
 	JMP	sync∕atomic·CompareAndSwapInt64(SB)
 
-TEXT	sync∕atomic·CompareAndSwapPointer(SB), NOSPLIT, $0-0
-	JMP	sync∕atomic·CompareAndSwapInt64(SB)
-
 // Generic atomic operation implementation.
 // AX already contains target function.
 TEXT	racecallatomic<>(SB), NOSPLIT, $0-0
@@ -366,9 +359,9 @@ TEXT	racecall<>(SB), NOSPLIT, $0-0
 	MOVQ	SP, R12		// callee-saved, preserved across the CALL
 	MOVQ	m_g0(R13), R10
 	CMPQ	R10, R14
-	JE	racecall_cont	// already on g0
+	JE	call	// already on g0
 	MOVQ	(g_sched+gobuf_sp)(R10), SP
-racecall_cont:
+call:
 	ANDQ	$~15, SP	// alignment for gcc ABI
 	CALL	AX
 	MOVQ	R12, SP
@@ -394,8 +387,9 @@ TEXT	runtime·racesymbolizethunk(SB), NOSPLIT, $56-8
 	MOVQ	g_m(R13), R13
 	MOVQ	m_g0(R13), R14
 	MOVQ	R14, g(R12)	// g = m->g0
-	MOVQ	RARG0, 0(SP)	// func arg
+	PUSHQ	RARG0	// func arg
 	CALL	runtime·racesymbolize(SB)
+	POPQ	R12
 	// All registers are smashed after Go code, reload.
 	get_tls(R12)
 	MOVQ	g(R12), R13
diff --git a/src/runtime/rdebug.go b/src/runtime/rdebug.go
index e5e6911..f2766d7 100644
--- a/src/runtime/rdebug.go
+++ b/src/runtime/rdebug.go
@@ -10,15 +10,6 @@ func setMaxStack(in int) (out int) {
 	return out
 }
 
-func setGCPercent(in int32) (out int32) {
-	mp := acquirem()
-	mp.scalararg[0] = uintptr(int(in))
-	onM(setgcpercent_m)
-	out = int32(int(mp.scalararg[0]))
-	releasem(mp)
-	return out
-}
-
 func setPanicOnFault(new bool) (old bool) {
 	mp := acquirem()
 	old = mp.curg.paniconfault
@@ -26,12 +17,3 @@ func setPanicOnFault(new bool) (old bool) {
 	releasem(mp)
 	return old
 }
-
-func setMaxThreads(in int) (out int) {
-	mp := acquirem()
-	mp.scalararg[0] = uintptr(in)
-	onM(setmaxthreads_m)
-	out = int(mp.scalararg[0])
-	releasem(mp)
-	return out
-}
diff --git a/src/runtime/rt0_android_arm.s b/src/runtime/rt0_android_arm.s
index 6b65fb4..8571253 100644
--- a/src/runtime/rt0_android_arm.s
+++ b/src/runtime/rt0_android_arm.s
@@ -9,3 +9,27 @@ TEXT _rt0_arm_android(SB),NOSPLIT,$-4
 	MOVW		$4(R13), R1    // argv
 	MOVW		$_rt0_arm_linux1(SB), R4
 	B		(R4)
+
+// When building with -buildmode=c-shared, this symbol is called when the shared
+// library is loaded.
+TEXT _rt0_arm_android_lib(SB),NOSPLIT,$0
+	MOVW	$1, R0                          // argc
+	MOVW	$_rt0_arm_android_argv(SB), R1  // **argv
+	BL _rt0_arm_linux_lib(SB)
+	RET
+
+DATA _rt0_arm_android_argv+0x00(SB)/4,$_rt0_arm_android_argv0(SB)
+DATA _rt0_arm_android_argv+0x04(SB)/4,$0
+DATA _rt0_arm_android_argv+0x08(SB)/4,$0
+DATA _rt0_arm_android_argv+0x0C(SB)/4,$15      // AT_PLATFORM
+DATA _rt0_arm_android_argv+0x10(SB)/4,$_rt0_arm_android_auxv0(SB)
+DATA _rt0_arm_android_argv+0x14(SB)/4,$16      // AT_HWCAP
+DATA _rt0_arm_android_argv+0x18(SB)/4,$0x2040  // HWCAP_VFP | HWCAP_VFPv3
+DATA _rt0_arm_android_argv+0x1C(SB)/4,$0
+GLOBL _rt0_arm_android_argv(SB),NOPTR,$0x20
+
+DATA _rt0_arm_android_argv0(SB)/8, $"gojni"
+GLOBL _rt0_arm_android_argv0(SB),RODATA,$8
+
+DATA _rt0_arm_android_auxv0(SB)/4, $"v7l"
+GLOBL _rt0_arm_android_auxv0(SB),RODATA,$4
diff --git a/src/runtime/rt0_darwin_amd64.s b/src/runtime/rt0_darwin_amd64.s
index 452d854..8d50e96 100644
--- a/src/runtime/rt0_darwin_amd64.s
+++ b/src/runtime/rt0_darwin_amd64.s
@@ -10,6 +10,40 @@ TEXT _rt0_amd64_darwin(SB),NOSPLIT,$-8
 	MOVQ	$main(SB), AX
 	JMP	AX
 
+// When linking with -shared, this symbol is called when the shared library
+// is loaded.
+TEXT _rt0_amd64_darwin_lib(SB),NOSPLIT,$40
+	MOVQ	DI, _rt0_amd64_darwin_lib_argc<>(SB)
+	MOVQ	SI, _rt0_amd64_darwin_lib_argv<>(SB)
+
+	// Create a new thread to do the runtime initialization and return.
+	MOVQ	_cgo_sys_thread_create(SB), AX
+	TESTQ	AX, AX
+	JZ	nocgo
+	MOVQ	$_rt0_amd64_darwin_lib_go(SB), DI
+	MOVQ	$0, SI
+	CALL	AX
+	RET
+nocgo:
+	MOVQ	$8388608, 0(SP)                    // stacksize
+	MOVQ	$_rt0_amd64_darwin_lib_go(SB), AX
+	MOVQ	AX, 8(SP)                          // fn
+	MOVQ	$0, 16(SP)                         // fnarg
+	MOVQ	$runtime·newosproc0(SB), AX
+	CALL	AX
+	RET
+
+TEXT _rt0_amd64_darwin_lib_go(SB),NOSPLIT,$0
+	MOVQ	_rt0_amd64_darwin_lib_argc<>(SB), DI
+	MOVQ	_rt0_amd64_darwin_lib_argv<>(SB), SI
+	MOVQ	$runtime·rt0_go(SB), AX
+	JMP	AX
+
+DATA _rt0_amd64_darwin_lib_argc<>(SB)/8, $0
+GLOBL _rt0_amd64_darwin_lib_argc<>(SB),NOPTR, $8
+DATA _rt0_amd64_darwin_lib_argv<>(SB)/8, $0
+GLOBL _rt0_amd64_darwin_lib_argv<>(SB),NOPTR, $8
+
 TEXT main(SB),NOSPLIT,$-8
 	MOVQ	$runtime·rt0_go(SB), AX
 	JMP	AX
diff --git a/src/runtime/rt0_darwin_arm.s b/src/runtime/rt0_darwin_arm.s
new file mode 100644
index 0000000..95a2b17
--- /dev/null
+++ b/src/runtime/rt0_darwin_arm.s
@@ -0,0 +1,59 @@
+// 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 _rt0_arm_darwin(SB),7,$-4
+	// prepare arguments for main (_rt0_go)
+	MOVW	(R13), R0	// argc
+	MOVW	$4(R13), R1		// argv
+	MOVW	$main(SB), R4
+	B		(R4)
+
+// When linking with -buildmode=c-archive or -buildmode=c-shared,
+// this symbol is called from a global initialization function.
+//
+// Note that all currently shipping darwin/arm platforms require
+// cgo and do not support c-shared.
+TEXT _rt0_arm_darwin_lib(SB),NOSPLIT,$12
+	MOVW  R0, _rt0_arm_darwin_lib_argc<>(SB)
+	MOVW  R1, _rt0_arm_darwin_lib_argv<>(SB)
+
+	// Create a new thread to do the runtime initialization and return.
+	MOVW  _cgo_sys_thread_create(SB), R4
+	CMP   $0, R4
+	B.EQ  nocgo
+	MOVW  $_rt0_arm_darwin_lib_go(SB), R0
+	MOVW  $0, R1
+	BL    (R4)
+	RET
+nocgo:
+	MOVW  $0x400000, R0
+	MOVW  $_rt0_arm_darwin_lib_go(SB), R1
+	MOVW  $0, R2
+	MOVW  R0,  (R13) // stacksize
+	MOVW  R1, 4(R13) // fn
+	MOVW  R2, 8(R13) // fnarg
+	MOVW  $runtime·newosproc0(SB), R4
+	BL    (R4)
+	RET
+
+TEXT _rt0_arm_darwin_lib_go(SB),NOSPLIT,$0
+	MOVW  _rt0_arm_darwin_lib_argc<>(SB), R0
+	MOVW  _rt0_arm_darwin_lib_argv<>(SB), R1
+	MOVW  R0,  (R13)
+	MOVW  R1, 4(R13)
+	MOVW  $runtime·rt0_go(SB), R4
+	B     (R4)
+
+DATA  _rt0_arm_darwin_lib_argc<>(SB)/4, $0
+GLOBL _rt0_arm_darwin_lib_argc<>(SB),NOPTR, $4
+DATA  _rt0_arm_darwin_lib_argv<>(SB)/4, $0
+GLOBL _rt0_arm_darwin_lib_argv<>(SB),NOPTR, $4
+
+TEXT main(SB),NOSPLIT,$-8
+	// save argc and argv onto stack
+	MOVM.DB.W [R0-R1], (R13)
+	MOVW	$runtime·rt0_go(SB), R4
+	B		(R4)
diff --git a/src/runtime/rt0_darwin_arm64.s b/src/runtime/rt0_darwin_arm64.s
new file mode 100644
index 0000000..e4e4a30
--- /dev/null
+++ b/src/runtime/rt0_darwin_arm64.s
@@ -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.
+
+#include "textflag.h"
+
+// No need for _rt0_arm64_darwin as darwin/arm64 only
+// supports external linking.
+TEXT _rt0_arm64_darwin(SB),NOSPLIT,$-8
+	MOVD	$42, R0
+	MOVD	$1, R16	// SYS_exit
+	SVC	$0x80
+
+// When linking with -buildmode=c-archive or -buildmode=c-shared,
+// this symbol is called from a global initialization function.
+//
+// Note that all currently shipping darwin/arm64 platforms require
+// cgo and do not support c-shared.
+TEXT _rt0_arm64_darwin_lib(SB),NOSPLIT,$0
+	// R27 is REGTMP, reserved for liblink. It is used below to
+	// move R0/R1 into globals. However in the standard ARM64 calling
+	// convention, it is a callee-saved register. So we save it to a
+	// temporary register.
+	MOVD  R27, R7
+
+	MOVD  R0, _rt0_arm64_darwin_lib_argc<>(SB)
+	MOVD  R1, _rt0_arm64_darwin_lib_argv<>(SB)
+	// Create a new thread to do the runtime initialization and return.
+	MOVD  _cgo_sys_thread_create(SB), R4
+	MOVD  $_rt0_arm64_darwin_lib_go(SB), R0
+	MOVD  $0, R1
+	BL    (R4)
+
+	MOVD  R7, R27
+	RET
+
+TEXT _rt0_arm64_darwin_lib_go(SB),NOSPLIT,$0
+	MOVD  _rt0_arm64_darwin_lib_argc<>(SB), R0
+	MOVD  _rt0_arm64_darwin_lib_argv<>(SB), R1
+	MOVD  $runtime·rt0_go(SB), R4
+	B     (R4)
+
+DATA  _rt0_arm64_darwin_lib_argc<>(SB)/8, $0
+GLOBL _rt0_arm64_darwin_lib_argc<>(SB),NOPTR, $8
+DATA  _rt0_arm64_darwin_lib_argv<>(SB)/8, $0
+GLOBL _rt0_arm64_darwin_lib_argv<>(SB),NOPTR, $8
+
+TEXT main(SB),NOSPLIT,$-8
+	MOVD	$runtime·rt0_go(SB), R2
+	BL	(R2)
+exit:
+	MOVD	$0, R0
+	MOVD	$1, R16	// sys_exit
+	SVC	$0x80
+	B	exit
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 _rt0_arm_freebsd(SB),NOSPLIT,$-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_386.s b/src/runtime/rt0_linux_386.s
index 352e594..633e806 100644
--- a/src/runtime/rt0_linux_386.s
+++ b/src/runtime/rt0_linux_386.s
@@ -9,10 +9,64 @@ TEXT _rt0_386_linux(SB),NOSPLIT,$8
 	LEAL	12(SP), BX
 	MOVL	AX, 0(SP)
 	MOVL	BX, 4(SP)
-	CALL	runtime·linux_setup_vdso(SB)
 	CALL	main(SB)
 	INT	$3
 
+// When building with -buildmode=c-shared, this symbol is called when the shared
+// library is loaded.
+TEXT _rt0_386_linux_lib(SB),NOSPLIT,$0
+	PUSHL	BP
+	MOVL	SP, BP
+	PUSHL	BX
+	PUSHL	SI
+	PUSHL	DI
+
+	MOVL	8(BP), AX
+	MOVL	AX, _rt0_386_linux_lib_argc<>(SB)
+	MOVL	12(BP), AX
+	MOVL	AX, _rt0_386_linux_lib_argv<>(SB)
+
+	SUBL	$8, SP
+
+	// Create a new thread to do the runtime initialization.
+	MOVL	_cgo_sys_thread_create(SB), AX
+	TESTL	AX, AX
+	JZ	nocgo
+	MOVL	$_rt0_386_linux_lib_go(SB), BX
+	MOVL	BX, 0(SP)
+	MOVL	$0, 4(SP)
+	CALL	AX
+	JMP	restore
+
+nocgo:
+	MOVL	$0x800000, 0(SP)                    // stacksize = 8192KB
+	MOVL	$_rt0_386_linux_lib_go(SB), AX
+	MOVL	AX, 4(SP)                           // fn
+	MOVL	$runtime·newosproc0(SB), AX
+	CALL	AX
+
+restore:
+	ADDL	$8, SP
+	POPL	DI
+	POPL	SI
+	POPL	BX
+	POPL	BP
+	RET
+
+TEXT _rt0_386_linux_lib_go(SB),NOSPLIT,$12
+	MOVL	_rt0_386_linux_lib_argc<>(SB), AX
+	MOVL	AX, 0(SP)
+	MOVL	_rt0_386_linux_lib_argv<>(SB), AX
+	MOVL	AX, 4(SP)
+	MOVL	$runtime·rt0_go(SB), AX
+	CALL	AX
+	RET
+
+DATA _rt0_386_linux_lib_argc<>(SB)/4, $0
+GLOBL _rt0_386_linux_lib_argc<>(SB),NOPTR, $4
+DATA _rt0_386_linux_lib_argv<>(SB)/4, $0
+GLOBL _rt0_386_linux_lib_argv<>(SB),NOPTR, $4
+
 TEXT main(SB),NOSPLIT,$0
 	JMP	runtime·rt0_go(SB)
 
diff --git a/src/runtime/rt0_linux_amd64.s b/src/runtime/rt0_linux_amd64.s
index 985426a..726b550 100644
--- a/src/runtime/rt0_linux_amd64.s
+++ b/src/runtime/rt0_linux_amd64.s
@@ -10,6 +10,55 @@ TEXT _rt0_amd64_linux(SB),NOSPLIT,$-8
 	MOVQ	$main(SB), AX
 	JMP	AX
 
+// When building with -buildmode=c-shared, this symbol is called when the shared
+// library is loaded.
+TEXT _rt0_amd64_linux_lib(SB),NOSPLIT,$0x48
+	MOVQ	BX, 0x10(SP)
+	MOVQ	BP, 0x18(SP)
+	MOVQ	R12, 0x20(SP)
+	MOVQ	R13, 0x28(SP)
+	MOVQ	R14, 0x30(SP)
+	MOVQ	R15, 0x38(SP)
+
+	MOVQ	DI, _rt0_amd64_linux_lib_argc<>(SB)
+	MOVQ	SI, _rt0_amd64_linux_lib_argv<>(SB)
+
+	// Create a new thread to do the runtime initialization and return.
+	MOVQ	_cgo_sys_thread_create(SB), AX
+	TESTQ	AX, AX
+	JZ	nocgo
+	MOVQ	$_rt0_amd64_linux_lib_go(SB), DI
+	MOVQ	$0, SI
+	CALL	AX
+	JMP	restore
+
+nocgo:
+	MOVQ	$8388608, 0(SP)                    // stacksize
+	MOVQ	$_rt0_amd64_linux_lib_go(SB), AX
+	MOVQ	AX, 8(SP)                          // fn
+	MOVQ	$runtime·newosproc0(SB), AX
+	CALL	AX
+
+restore:
+	MOVQ	0x10(SP), BX
+	MOVQ	0x18(SP), BP
+	MOVQ	0x20(SP), R12
+	MOVQ	0x28(SP), R13
+	MOVQ	0x30(SP), R14
+	MOVQ	0x38(SP), R15
+	RET
+
+TEXT _rt0_amd64_linux_lib_go(SB),NOSPLIT,$0
+	MOVQ	_rt0_amd64_linux_lib_argc<>(SB), DI
+	MOVQ	_rt0_amd64_linux_lib_argv<>(SB), SI
+	MOVQ	$runtime·rt0_go(SB), AX
+	JMP	AX
+
+DATA _rt0_amd64_linux_lib_argc<>(SB)/8, $0
+GLOBL _rt0_amd64_linux_lib_argc<>(SB),NOPTR, $8
+DATA _rt0_amd64_linux_lib_argv<>(SB)/8, $0
+GLOBL _rt0_amd64_linux_lib_argv<>(SB),NOPTR, $8
+
 TEXT main(SB),NOSPLIT,$-8
 	MOVQ	$runtime·rt0_go(SB), AX
 	JMP	AX
diff --git a/src/runtime/rt0_linux_arm.s b/src/runtime/rt0_linux_arm.s
index 5f521d2..b71a3f9 100644
--- a/src/runtime/rt0_linux_arm.s
+++ b/src/runtime/rt0_linux_arm.s
@@ -10,6 +10,58 @@ TEXT _rt0_arm_linux(SB),NOSPLIT,$-4
 	MOVW	$_rt0_arm_linux1(SB), R4
 	B		(R4)
 
+// When building with -buildmode=c-shared, this symbol is called when the shared
+// library is loaded.
+TEXT _rt0_arm_linux_lib(SB),NOSPLIT,$32
+	// Preserve callee-save registers.  Raspberry Pi's dlopen(), for example,
+	// actually cares that R11 is preserved.
+	MOVW	R4, 12(R13)
+	MOVW	R5, 16(R13)
+	MOVW	R6, 20(R13)
+	MOVW	R7, 24(R13)
+	MOVW	R8, 28(R13)
+	MOVW	R11, 32(R13)
+
+	// Save argc/argv.
+	MOVW	R0, _rt0_arm_linux_lib_argc<>(SB)
+	MOVW	R1, _rt0_arm_linux_lib_argv<>(SB)
+
+	// Create a new thread to do the runtime initialization.
+	MOVW	_cgo_sys_thread_create(SB), R2
+	CMP	$0, R2
+	BEQ	nocgo
+	MOVW	$_rt0_arm_linux_lib_go<>(SB), R0
+	MOVW	$0, R1
+	BL	(R2)
+	B	rr
+nocgo:
+	MOVW	$0x800000, R0                     // stacksize = 8192KB
+	MOVW	$_rt0_arm_linux_lib_go<>(SB), R1  // fn
+	MOVW	R0, 4(R13)
+	MOVW	R1, 8(R13)
+	BL	runtime·newosproc0(SB)
+rr:
+	// Restore callee-save registers and return.
+	MOVW	12(R13), R4
+	MOVW	16(R13), R5
+	MOVW	20(R13), R6
+	MOVW	24(R13), R7
+	MOVW	28(R13), R8
+	MOVW	32(R13), R11
+	RET
+
+TEXT _rt0_arm_linux_lib_go<>(SB),NOSPLIT,$8
+	MOVW	_rt0_arm_linux_lib_argc<>(SB), R0
+	MOVW	_rt0_arm_linux_lib_argv<>(SB), R1
+	MOVW	R0, 0(R13)
+	MOVW	R1, 4(R13)
+	B	runtime·rt0_go(SB)
+
+DATA _rt0_arm_linux_lib_argc<>(SB)/4,$0
+GLOBL _rt0_arm_linux_lib_argc<>(SB),NOPTR,$4
+DATA _rt0_arm_linux_lib_argv<>(SB)/4,$0
+GLOBL _rt0_arm_linux_lib_argv<>(SB),NOPTR,$4
+
 TEXT _rt0_arm_linux1(SB),NOSPLIT,$-4
 	// We first need to detect the kernel ABI, and warn the user
 	// if the system only supports OABI
@@ -53,9 +105,6 @@ TEXT _rt0_arm_linux1(SB),NOSPLIT,$-4
 	// SWI	$0 // restore signal handler
 	// ADD	$32, R13
 
-	SUB	$4, R13 // fake a stack frame for runtime·setup_auxv
-	BL	runtime·setup_auxv(SB)
-	ADD	$4, R13
 	B	runtime·rt0_go(SB)
 
 TEXT bad_abi<>(SB),NOSPLIT,$-4
@@ -80,7 +129,7 @@ DATA bad_abi_msg+0x2c(SB)/1, $0xa
 GLOBL bad_abi_msg(SB), RODATA, $45
 
 TEXT oabi_syscall<>(SB),NOSPLIT,$-4
-	ADD $1, PC, R4
+	ADD $1, R15, R4 // R15 is hardware PC
 	WORD $0xe12fff14 //BX	(R4) // enter thumb mode
 	// TODO(minux): only supports little-endian CPUs
 	WORD $0x4770df01 // swi $1; bx lr
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_linux_ppc64.s b/src/runtime/rt0_linux_ppc64.s
new file mode 100644
index 0000000..33e973d
--- /dev/null
+++ b/src/runtime/rt0_linux_ppc64.s
@@ -0,0 +1,23 @@
+#include "textflag.h"
+
+// actually a function descriptor for _main<>(SB)
+TEXT _rt0_ppc64_linux(SB),NOSPLIT,$0
+	DWORD $_main<>(SB)
+	DWORD $0
+	DWORD $0
+
+TEXT _main<>(SB),NOSPLIT,$-8
+	// In a statically linked binary, the stack contains argc,
+	// argv as argc string pointers followed by a NULL, envv as a
+	// sequence of string pointers followed by a NULL, and auxv.
+	// There is no TLS base pointer.
+	//
+	// TODO(austin): Support ABI v1 dynamic linking entry point
+	MOVD 0(R1), R3 // argc
+	ADD $8, R1, R4 // argv
+	BR main(SB)
+
+TEXT main(SB),NOSPLIT,$-8
+	MOVD	$runtime·rt0_go(SB), R31
+	MOVD	R31, CTR
+	BR	(CTR)
diff --git a/src/runtime/rt0_linux_ppc64le.s b/src/runtime/rt0_linux_ppc64le.s
new file mode 100644
index 0000000..f5c0af5
--- /dev/null
+++ b/src/runtime/rt0_linux_ppc64le.s
@@ -0,0 +1,34 @@
+#include "textflag.h"
+
+TEXT _rt0_ppc64le_linux(SB),NOSPLIT,$0
+	BR _main<>(SB)
+
+TEXT _main<>(SB),NOSPLIT,$-8
+	// In a statically linked binary, the stack contains argc,
+	// argv as argc string pointers followed by a NULL, envv as a
+	// sequence of string pointers followed by a NULL, and auxv.
+	// There is no TLS base pointer.
+	//
+	// In a dynamically linked binary, r3 contains argc, r4
+	// contains argv, r5 contains envp, r6 contains auxv, and r13
+	// contains the TLS pointer.
+	//
+	// Figure out which case this is by looking at r4: if it's 0,
+	// we're statically linked; otherwise we're dynamically
+	// linked.
+	CMP	R0, R4
+	BNE	dlink
+
+	// Statically linked
+	MOVD	0(R1), R3 // argc
+	ADD	$8, R1, R4 // argv
+	MOVD	$runtime·tls0(SB), R13 // TLS
+	ADD	$0x7000, R13
+
+dlink:
+	BR	main(SB)
+
+TEXT main(SB),NOSPLIT,$-8
+	MOVD	$runtime·rt0_go(SB), R31
+	MOVD	R31, CTR
+	BR	(CTR)
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 @@ TEXT _rt0_386_windows(SB),NOSPLIT,$12
 	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/rt0_windows_amd64.s b/src/runtime/rt0_windows_amd64.s
index 197f52e..df956ba 100644
--- a/src/runtime/rt0_windows_amd64.s
+++ b/src/runtime/rt0_windows_amd64.s
@@ -2,7 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
 #include "textflag.h"
 
 TEXT _rt0_amd64_windows(SB),NOSPLIT,$-8
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 eedac7c..e57fa00 100644
--- a/src/runtime/runtime-gdb.py
+++ b/src/runtime/runtime-gdb.py
@@ -28,6 +28,31 @@ goobjfile = gdb.current_objfile() or gdb.objfiles()[0]
 goobjfile.pretty_printers = []
 
 #
+#  Value wrappers
+#
+
+class SliceValue:
+	"Wrapper for slice values."
+
+	def __init__(self, val):
+		self.val = val
+
+	@property
+	def len(self):
+		return int(self.val['len'])
+
+	@property
+	def cap(self):
+		return int(self.val['cap'])
+
+	def __getitem__(self, i):
+		if i < 0 or i >= self.len:
+			raise IndexError(i)
+		ptr = self.val["array"]
+		return (ptr + i).dereference()
+
+
+#
 #  Pretty Printers
 #
 
@@ -35,7 +60,7 @@ goobjfile.pretty_printers = []
 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
@@ -63,11 +88,11 @@ class SliceTypePrinter:
 		return str(self.val.type)[6:]  # skip 'struct '
 
 	def children(self):
-		if self.val["len"] > self.val["cap"]:
+		sval = SliceValue(self.val)
+		if sval.len > sval.cap:
 			return
-		ptr = self.val["array"]
-		for idx in range(int(self.val["len"])):
-			yield ('[{0}]'.format(idx), (ptr + idx).dereference())
+		for idx, item in enumerate(sval):
+			yield ('[{0}]'.format(idx), item)
 
 
 class MapTypePrinter:
@@ -89,7 +114,7 @@ class MapTypePrinter:
 		return str(self.val.type)
 
 	def children(self):
-		B = self.val['b']
+		B = self.val['B']
 		buckets = self.val['buckets']
 		oldbuckets = self.val['oldbuckets']
 		flags = self.val['flags']
@@ -202,8 +227,6 @@ def lookup_type(name):
 	except gdb.error:
 		pass
 
-_rctp_type = gdb.lookup_type("struct runtime.rtype").pointer()
-
 
 def iface_commontype(obj):
 	if is_iface(obj):
@@ -213,7 +236,7 @@ def iface_commontype(obj):
 	else:
 		return
 
-	return go_type_ptr.cast(_rctp_type).dereference()
+	return go_type_ptr.cast(gdb.lookup_type("struct reflect.rtype").pointer()).dereference()
 
 
 def iface_dtype(obj):
@@ -355,8 +378,8 @@ class GoroutinesCmd(gdb.Command):
 	def invoke(self, _arg, _from_tty):
 		# args = gdb.string_to_argv(arg)
 		vp = gdb.lookup_type('void').pointer()
-		for ptr in linked_list(gdb.parse_and_eval("'runtime.allg'"), 'alllink'):
-			if ptr['status'] == 6:  # 'gdead'
+		for ptr in SliceValue(gdb.parse_and_eval("'runtime.allgs'")):
+			if ptr['atomicstatus'] == 6:  # 'gdead'
 				continue
 			s = ' '
 			if ptr['m']:
@@ -370,9 +393,12 @@ class GoroutinesCmd(gdb.Command):
 				#python3 / newer versions of gdb
 				pc = int(pc)
 			except gdb.error:
-				pc = int(str(pc), 16)
+				# str(pc) can return things like
+				# "0x429d6c <runtime.gopark+284>", so
+				# chop at first space.
+				pc = int(str(pc).split(None, 1)[0], 16)
 			blk = gdb.block_for_pc(pc)
-			print(s, ptr['goid'], "{0:8s}".format(sts[int(ptr['status'])]), blk.function)
+			print(s, ptr['goid'], "{0:8s}".format(sts[int(ptr['atomicstatus'])]), blk.function)
 
 
 def find_goroutine(goid):
@@ -386,8 +412,8 @@ def find_goroutine(goid):
 	@return tuple (gdb.Value, gdb.Value)
 	"""
 	vp = gdb.lookup_type('void').pointer()
-	for ptr in linked_list(gdb.parse_and_eval("'runtime.allg'"), 'alllink'):
-		if ptr['status'] == 6:  # 'gdead'
+	for ptr in SliceValue(gdb.parse_and_eval("'runtime.allgs'")):
+		if ptr['atomicstatus'] == 6:  # 'gdead'
 			continue
 		if ptr['goid'] == goid:
 			return (ptr['sched'][x].cast(vp) for x in ('pc', 'sp'))
@@ -420,7 +446,7 @@ class GoroutineCmd(gdb.Command):
 			#python3 / newer versions of gdb
 			pc = int(pc)
 		except gdb.error:
-			pc = int(str(pc), 16)
+			pc = int(str(pc).split(None, 1)[0], 16)
 		save_frame = gdb.selected_frame()
 		gdb.parse_and_eval('$save_pc = $pc')
 		gdb.parse_and_eval('$save_sp = $sp')
diff --git a/src/runtime/runtime-gdb_test.go b/src/runtime/runtime-gdb_test.go
new file mode 100644
index 0000000..2843633
--- /dev/null
+++ b/src/runtime/runtime-gdb_test.go
@@ -0,0 +1,164 @@
+package runtime_test
+
+import (
+	"bytes"
+	"fmt"
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"regexp"
+	"runtime"
+	"strconv"
+	"testing"
+)
+
+func checkGdbPython(t *testing.T) {
+	cmd := exec.Command("gdb", "-nx", "-q", "--batch", "-iex", "python import sys; print('go gdb python support')")
+	out, err := cmd.CombinedOutput()
+
+	if err != nil {
+		t.Skipf("skipping due to issue running gdb: %v", err)
+	}
+	if string(out) != "go gdb python support\n" {
+		t.Skipf("skipping due to lack of python gdb support: %s", out)
+	}
+
+	// Issue 11214 reports various failures with older versions of gdb.
+	out, err = exec.Command("gdb", "--version").CombinedOutput()
+	re := regexp.MustCompile(`([0-9]+)\.([0-9]+)`)
+	matches := re.FindSubmatch(out)
+	if len(matches) < 3 {
+		t.Skipf("skipping: can't determine gdb version from\n%s\n", out)
+	}
+	major, err1 := strconv.Atoi(string(matches[1]))
+	minor, err2 := strconv.Atoi(string(matches[2]))
+	if err1 != nil || err2 != nil {
+		t.Skipf("skipping: can't determine gdb version: %v, %v", err1, err2)
+	}
+	if major < 7 || (major == 7 && minor < 7) {
+		t.Skipf("skipping: gdb version %d.%d too old", major, minor)
+	}
+	t.Logf("gdb version %d.%d", major, minor)
+}
+
+const helloSource = `
+package main
+import "fmt"
+func main() {
+	mapvar := make(map[string]string,5)
+	mapvar["abc"] = "def"
+	mapvar["ghi"] = "jkl"
+	strvar := "abc"
+	ptrvar := &strvar
+	fmt.Println("hi") // line 10
+	_ = ptrvar
+}
+`
+
+func TestGdbPython(t *testing.T) {
+	if runtime.GOOS == "darwin" {
+		t.Skip("gdb does not work on darwin")
+	}
+
+	checkGdbPython(t)
+
+	dir, err := ioutil.TempDir("", "go-build")
+	if err != nil {
+		t.Fatalf("failed to create temp directory: %v", err)
+	}
+	defer os.RemoveAll(dir)
+
+	src := filepath.Join(dir, "main.go")
+	err = ioutil.WriteFile(src, []byte(helloSource), 0644)
+	if err != nil {
+		t.Fatalf("failed to create file: %v", err)
+	}
+
+	cmd := exec.Command("go", "build", "-o", "a.exe")
+	cmd.Dir = dir
+	out, err := testEnv(cmd).CombinedOutput()
+	if err != nil {
+		t.Fatalf("building source %v\n%s", err, out)
+	}
+
+	args := []string{"-nx", "-q", "--batch", "-iex",
+		fmt.Sprintf("add-auto-load-safe-path %s/src/runtime", runtime.GOROOT()),
+		"-ex", "br main.go:10",
+		"-ex", "run",
+		"-ex", "echo BEGIN info goroutines\n",
+		"-ex", "info goroutines",
+		"-ex", "echo END\n",
+		"-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"}
+
+	// without framepointer, gdb cannot backtrace our non-standard
+	// stack frames on RISC architectures.
+	canBackTrace := false
+	switch runtime.GOARCH {
+	case "amd64", "386", "ppc64", "ppc64le", "arm", "arm64":
+		canBackTrace = true
+		args = append(args,
+			"-ex", "echo BEGIN goroutine 2 bt\n",
+			"-ex", "goroutine 2 bt",
+			"-ex", "echo END\n")
+	}
+
+	args = append(args, filepath.Join(dir, "a.exe"))
+	got, _ := exec.Command("gdb", args...).CombinedOutput()
+
+	firstLine := bytes.SplitN(got, []byte("\n"), 2)[0]
+	if string(firstLine) != "Loading Go Runtime support." {
+		// This can happen when using all.bash with
+		// GOROOT_FINAL set, because the tests are run before
+		// the final installation of the files.
+		cmd := exec.Command("go", "env", "GOROOT")
+		cmd.Env = []string{}
+		out, err := cmd.CombinedOutput()
+		if err != nil && bytes.Contains(out, []byte("cannot find GOROOT")) {
+			t.Skipf("skipping because GOROOT=%s does not exist", runtime.GOROOT())
+		}
+
+		t.Fatalf("failed to load Go runtime support: %s", firstLine)
+	}
+
+	// Extract named BEGIN...END blocks from output
+	partRe := regexp.MustCompile(`(?ms)^BEGIN ([^\n]*)\n(.*?)\nEND`)
+	blocks := map[string]string{}
+	for _, subs := range partRe.FindAllSubmatch(got, -1) {
+		blocks[string(subs[1])] = string(subs[2])
+	}
+
+	infoGoroutinesRe := regexp.MustCompile(`\*\s+\d+\s+running\s+`)
+	if bl := blocks["info goroutines"]; !infoGoroutinesRe.MatchString(bl) {
+		t.Fatalf("info goroutines failed: %s", bl)
+	}
+
+	printMapvarRe := regexp.MustCompile(`\Q = map[string]string = {["abc"] = "def", ["ghi"] = "jkl"}\E$`)
+	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)
+	}
+
+	btGoroutineRe := regexp.MustCompile(`^#0\s+runtime.+at`)
+	if bl := blocks["goroutine 2 bt"]; canBackTrace && !btGoroutineRe.MatchString(bl) {
+		t.Fatalf("goroutine 2 bt failed: %s", bl)
+	} else if !canBackTrace {
+		t.Logf("gdb cannot backtrace for GOARCH=%s, skipped goroutine backtrace test", runtime.GOARCH)
+	}
+}
diff --git a/src/runtime/runtime.c b/src/runtime/runtime.c
deleted file mode 100644
index c823691..0000000
--- a/src/runtime/runtime.c
+++ /dev/null
@@ -1,399 +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 "runtime.h"
-#include "stack.h"
-#include "arch_GOARCH.h"
-#include "textflag.h"
-#include "malloc.h"
-
-// Keep a cached value to make gotraceback fast,
-// since we call it on every call to gentraceback.
-// The cached value is a uint32 in which the low bit
-// is the "crash" setting and the top 31 bits are the
-// gotraceback value.
-static uint32 traceback_cache = 2<<1;
-
-// The GOTRACEBACK environment variable controls the
-// behavior of a Go program that is crashing and exiting.
-//	GOTRACEBACK=0   suppress all tracebacks
-//	GOTRACEBACK=1   default behavior - show tracebacks but exclude runtime frames
-//	GOTRACEBACK=2   show tracebacks including runtime frames
-//	GOTRACEBACK=crash   show tracebacks including runtime frames, then crash (core dump etc)
-#pragma textflag NOSPLIT
-int32
-runtime·gotraceback(bool *crash)
-{
-	if(crash != nil)
-		*crash = false;
-	if(g->m->traceback != 0)
-		return g->m->traceback;
-	if(crash != nil)
-		*crash = traceback_cache&1;
-	return traceback_cache>>1;
-}
-
-int32
-runtime·mcmp(byte *s1, byte *s2, uintptr n)
-{
-	uintptr i;
-	byte c1, c2;
-
-	for(i=0; i<n; i++) {
-		c1 = s1[i];
-		c2 = s2[i];
-		if(c1 < c2)
-			return -1;
-		if(c1 > c2)
-			return +1;
-	}
-	return 0;
-}
-
-
-byte*
-runtime·mchr(byte *p, byte c, byte *ep)
-{
-	for(; p < ep; p++)
-		if(*p == c)
-			return p;
-	return nil;
-}
-
-static int32	argc;
-
-#pragma dataflag NOPTR /* argv not a heap pointer */
-static uint8**	argv;
-
-extern Slice runtime·argslice;
-extern Slice runtime·envs;
-
-void (*runtime·sysargs)(int32, uint8**);
-
-void
-runtime·args(int32 c, uint8 **v)
-{
-	argc = c;
-	argv = v;
-	if(runtime·sysargs != nil)
-		runtime·sysargs(c, v);
-}
-
-int32 runtime·isplan9;
-int32 runtime·issolaris;
-int32 runtime·iswindows;
-
-// Information about what cpu features are available.
-// Set on startup in asm_{x86/amd64}.s.
-uint32 runtime·cpuid_ecx;
-uint32 runtime·cpuid_edx;
-
-void
-runtime·goargs(void)
-{
-	String *s;
-	int32 i;
-
-	// for windows implementation see "os" package
-	if(Windows)
-		return;
-
-	runtime·argslice = runtime·makeStringSlice(argc);
-	s = (String*)runtime·argslice.array;
-	for(i=0; i<argc; i++)
-		s[i] = runtime·gostringnocopy(argv[i]);
-}
-
-void
-runtime·goenvs_unix(void)
-{
-	String *s;
-	int32 i, n;
-
-	for(n=0; argv[argc+1+n] != 0; n++)
-		;
-
-	runtime·envs = runtime·makeStringSlice(n);
-	s = (String*)runtime·envs.array;
-	for(i=0; i<n; i++)
-		s[i] = runtime·gostringnocopy(argv[argc+1+i]);
-}
-
-#pragma textflag NOSPLIT
-Slice
-runtime·environ()
-{
-	return runtime·envs;
-}
-
-int32
-runtime·atoi(byte *p)
-{
-	int32 n;
-
-	n = 0;
-	while('0' <= *p && *p <= '9')
-		n = n*10 + *p++ - '0';
-	return n;
-}
-
-static void
-TestAtomic64(void)
-{
-	uint64 z64, x64;
-
-	z64 = 42;
-	x64 = 0;
-	PREFETCH(&z64);
-	if(runtime·cas64(&z64, x64, 1))
-		runtime·throw("cas64 failed");
-	if(x64 != 0)
-		runtime·throw("cas64 failed");
-	x64 = 42;
-	if(!runtime·cas64(&z64, x64, 1))
-		runtime·throw("cas64 failed");
-	if(x64 != 42 || z64 != 1)
-		runtime·throw("cas64 failed");
-	if(runtime·atomicload64(&z64) != 1)
-		runtime·throw("load64 failed");
-	runtime·atomicstore64(&z64, (1ull<<40)+1);
-	if(runtime·atomicload64(&z64) != (1ull<<40)+1)
-		runtime·throw("store64 failed");
-	if(runtime·xadd64(&z64, (1ull<<40)+1) != (2ull<<40)+2)
-		runtime·throw("xadd64 failed");
-	if(runtime·atomicload64(&z64) != (2ull<<40)+2)
-		runtime·throw("xadd64 failed");
-	if(runtime·xchg64(&z64, (3ull<<40)+3) != (2ull<<40)+2)
-		runtime·throw("xchg64 failed");
-	if(runtime·atomicload64(&z64) != (3ull<<40)+3)
-		runtime·throw("xchg64 failed");
-}
-
-void
-runtime·check(void)
-{
-	int8 a;
-	uint8 b;
-	int16 c;
-	uint16 d;
-	int32 e;
-	uint32 f;
-	int64 g;
-	uint64 h;
-	float32 i, i1;
-	float64 j, j1;
-	byte *k, *k1;
-	uint16* l;
-	struct x1 {
-		byte x;
-	};
-	struct y1 {
-		struct x1 x1;
-		byte y;
-	};
-
-	if(sizeof(a) != 1) runtime·throw("bad a");
-	if(sizeof(b) != 1) runtime·throw("bad b");
-	if(sizeof(c) != 2) runtime·throw("bad c");
-	if(sizeof(d) != 2) runtime·throw("bad d");
-	if(sizeof(e) != 4) runtime·throw("bad e");
-	if(sizeof(f) != 4) runtime·throw("bad f");
-	if(sizeof(g) != 8) runtime·throw("bad g");
-	if(sizeof(h) != 8) runtime·throw("bad h");
-	if(sizeof(i) != 4) runtime·throw("bad i");
-	if(sizeof(j) != 8) runtime·throw("bad j");
-	if(sizeof(k) != sizeof(uintptr)) runtime·throw("bad k");
-	if(sizeof(l) != sizeof(uintptr)) runtime·throw("bad l");
-	if(sizeof(struct x1) != 1) runtime·throw("bad sizeof x1");
-	if(offsetof(struct y1, y) != 1) runtime·throw("bad offsetof y1.y");
-	if(sizeof(struct y1) != 2) runtime·throw("bad sizeof y1");
-
-	if(runtime·timediv(12345LL*1000000000+54321, 1000000000, &e) != 12345 || e != 54321)
-		runtime·throw("bad timediv");
-
-	uint32 z;
-	z = 1;
-	if(!runtime·cas(&z, 1, 2))
-		runtime·throw("cas1");
-	if(z != 2)
-		runtime·throw("cas2");
-
-	z = 4;
-	if(runtime·cas(&z, 5, 6))
-		runtime·throw("cas3");
-	if(z != 4)
-		runtime·throw("cas4");
-
-	k = (byte*)0xfedcb123;
-	if(sizeof(void*) == 8)
-		k = (byte*)((uintptr)k<<10);
-	if(runtime·casp((void**)&k, nil, nil))
-		runtime·throw("casp1");
-	k1 = k+1;
-	if(!runtime·casp((void**)&k, k, k1))
-		runtime·throw("casp2");
-	if(k != k1)
-		runtime·throw("casp3");
-
-	*(uint64*)&j = ~0ULL;
-	if(j == j)
-		runtime·throw("float64nan");
-	if(!(j != j))
-		runtime·throw("float64nan1");
-
-	*(uint64*)&j1 = ~1ULL;
-	if(j == j1)
-		runtime·throw("float64nan2");
-	if(!(j != j1))
-		runtime·throw("float64nan3");
-
-	*(uint32*)&i = ~0UL;
-	if(i == i)
-		runtime·throw("float32nan");
-	if(!(i != i))
-		runtime·throw("float32nan1");
-
-	*(uint32*)&i1 = ~1UL;
-	if(i == i1)
-		runtime·throw("float32nan2");
-	if(!(i != i1))
-		runtime·throw("float32nan3");
-
-	TestAtomic64();
-
-	if(FixedStack != runtime·round2(FixedStack))
-		runtime·throw("FixedStack is not power-of-2");
-}
-
-#pragma dataflag NOPTR
-DebugVars	runtime·debug;
-
-typedef struct DbgVar DbgVar;
-struct DbgVar
-{
-	int8*	name;
-	int32*	value;
-};
-
-// Do we report invalid pointers found during stack or heap scans?
-int32 runtime·invalidptr = 1;
-
-#pragma dataflag NOPTR /* dbgvar has no heap pointers */
-static DbgVar dbgvar[] = {
-	{"allocfreetrace", &runtime·debug.allocfreetrace},
-	{"invalidptr", &runtime·invalidptr},
-	{"efence", &runtime·debug.efence},
-	{"gctrace", &runtime·debug.gctrace},
-	{"gcdead", &runtime·debug.gcdead},
-	{"scheddetail", &runtime·debug.scheddetail},
-	{"schedtrace", &runtime·debug.schedtrace},
-	{"scavenge", &runtime·debug.scavenge},
-};
-
-void
-runtime·parsedebugvars(void)
-{
-	byte *p;
-	intgo i, n;
-
-	p = runtime·getenv("GODEBUG");
-	if(p != nil){
-		for(;;) {
-			for(i=0; i<nelem(dbgvar); i++) {
-				n = runtime·findnull((byte*)dbgvar[i].name);
-				if(runtime·mcmp(p, (byte*)dbgvar[i].name, n) == 0 && p[n] == '=')
-					*dbgvar[i].value = runtime·atoi(p+n+1);
-			}
-			p = runtime·strstr(p, (byte*)",");
-			if(p == nil)
-				break;
-			p++;
-		}
-	}
-
-	p = runtime·getenv("GOTRACEBACK");
-	if(p == nil)
-		p = (byte*)"";
-	if(p[0] == '\0')
-		traceback_cache = 1<<1;
-	else if(runtime·strcmp(p, (byte*)"crash") == 0)
-		traceback_cache = (2<<1) | 1;
-	else
-		traceback_cache = runtime·atoi(p)<<1;	
-}
-
-// Poor mans 64-bit division.
-// This is a very special function, do not use it if you are not sure what you are doing.
-// int64 division is lowered into _divv() call on 386, which does not fit into nosplit functions.
-// Handles overflow in a time-specific manner.
-#pragma textflag NOSPLIT
-int32
-runtime·timediv(int64 v, int32 div, int32 *rem)
-{
-	int32 res, bit;
-
-	res = 0;
-	for(bit = 30; bit >= 0; bit--) {
-		if(v >= ((int64)div<<bit)) {
-			v = v - ((int64)div<<bit);
-			res += 1<<bit;
-		}
-	}
-	if(v >= (int64)div) {
-		if(rem != nil)
-			*rem = 0;
-		return 0x7fffffff;
-	}
-	if(rem != nil)
-		*rem = v;
-	return res;
-}
-
-// Helpers for Go. Must be NOSPLIT, must only call NOSPLIT functions, and must not block.
-
-#pragma textflag NOSPLIT
-G*
-runtime·getg(void)
-{
-	return g;
-}
-
-#pragma textflag NOSPLIT
-M*
-runtime·acquirem(void)
-{
-	g->m->locks++;
-	return g->m;
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·releasem(M *mp)
-{
-	mp->locks--;
-	if(mp->locks == 0 && g->preempt) {
-		// restore the preemption request in case we've cleared it in newstack
-		g->stackguard0 = StackPreempt;
-	}
-}
-
-#pragma textflag NOSPLIT
-MCache*
-runtime·gomcache(void)
-{
-	return g->m->mcache;
-}
-
-#pragma textflag NOSPLIT
-Slice
-reflect·typelinks(void)
-{
-	extern Type *runtime·typelink[], *runtime·etypelink[];
-	Slice ret;
-
-	ret.array = (byte*)runtime·typelink;
-	ret.len = runtime·etypelink - runtime·typelink;
-	ret.cap = ret.len;
-	return ret;
-}
diff --git a/src/runtime/runtime.go b/src/runtime/runtime.go
index 4e4e1d1..2387d9a 100644
--- a/src/runtime/runtime.go
+++ b/src/runtime/runtime.go
@@ -4,8 +4,14 @@
 
 package runtime
 
+import _ "unsafe" // for go:linkname
+
+//go:generate go run wincallback.go
+//go:generate go run mkduff.go
+
 var ticks struct {
 	lock mutex
+	pad  uint32 // ensure 8-byte alignment of val on 386
 	val  uint64
 }
 
@@ -38,23 +44,11 @@ func tickspersecond() int64 {
 	return r
 }
 
-func makeStringSlice(n int) []string {
-	return make([]string, n)
-}
-
-// TODO: Move to parfor.go when parfor.c becomes parfor.go.
-func parforalloc(nthrmax uint32) *parfor {
-	return &parfor{
-		thr:     &make([]parforthread, nthrmax)[0],
-		nthrmax: nthrmax,
-	}
-}
-
 var envs []string
 var argslice []string
 
-// called from syscall
-func runtime_envs() []string { return envs }
+//go:linkname syscall_runtime_envs syscall.runtime_envs
+func syscall_runtime_envs() []string { return append([]string{}, envs...) }
 
-// called from os
-func runtime_args() []string { return argslice }
+//go:linkname os_runtime_args os.runtime_args
+func os_runtime_args() []string { return append([]string{}, argslice...) }
diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h
deleted file mode 100644
index 177a128..0000000
--- a/src/runtime/runtime.h
+++ /dev/null
@@ -1,1132 +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.
-
-/*
- * basic types
- */
-typedef	signed char		int8;
-typedef	unsigned char		uint8;
-typedef	signed short		int16;
-typedef	unsigned short		uint16;
-typedef	signed int		int32;
-typedef	unsigned int		uint32;
-typedef	signed long long int	int64;
-typedef	unsigned long long int	uint64;
-typedef	float			float32;
-typedef	double			float64;
-
-#ifdef _64BIT
-typedef	uint64		uintptr;
-typedef	int64		intptr;
-typedef	int64		intgo; // Go's int
-typedef	uint64		uintgo; // Go's uint
-#else
-typedef	uint32		uintptr;
-typedef	int32		intptr;
-typedef	int32		intgo; // Go's int
-typedef	uint32		uintgo; // Go's uint
-#endif
-
-#ifdef _64BITREG
-typedef	uint64		uintreg;
-#else
-typedef	uint32		uintreg;
-#endif
-
-/*
- * get rid of C types
- * the / / / forces a syntax error immediately,
- * which will show "last name: XXunsigned".
- */
-#define	unsigned		XXunsigned / / /
-#define	signed			XXsigned / / /
-#define	char			XXchar / / /
-#define	short			XXshort / / /
-#define	int			XXint / / /
-#define	long			XXlong / / /
-#define	float			XXfloat / / /
-#define	double			XXdouble / / /
-
-/*
- * defined types
- */
-typedef	uint8			bool;
-typedef	uint8			byte;
-typedef	struct	Func		Func;
-typedef	struct	G		G;
-typedef	struct	Gobuf		Gobuf;
-typedef	struct	SudoG		SudoG;
-typedef	struct	Mutex		Mutex;
-typedef	struct	M		M;
-typedef	struct	P		P;
-typedef	struct	SchedT	SchedT;
-typedef	struct	Note		Note;
-typedef	struct	Slice		Slice;
-typedef	struct	String		String;
-typedef	struct	FuncVal		FuncVal;
-typedef	struct	SigTab		SigTab;
-typedef	struct	MCache		MCache;
-typedef	struct	FixAlloc	FixAlloc;
-typedef	struct	Iface		Iface;
-typedef	struct	Itab		Itab;
-typedef	struct	InterfaceType	InterfaceType;
-typedef	struct	Eface		Eface;
-typedef	struct	Type		Type;
-typedef	struct	PtrType		PtrType;
-typedef	struct	ChanType	ChanType;
-typedef	struct	MapType		MapType;
-typedef	struct	Defer		Defer;
-typedef	struct	Panic		Panic;
-typedef	struct	Hmap		Hmap;
-typedef	struct	Hiter		Hiter;
-typedef	struct	Hchan		Hchan;
-typedef	struct	Complex64	Complex64;
-typedef	struct	Complex128	Complex128;
-typedef	struct	LibCall		LibCall;
-typedef	struct	WinCallbackContext	WinCallbackContext;
-typedef	struct	GCStats		GCStats;
-typedef	struct	LFNode		LFNode;
-typedef	struct	ParFor		ParFor;
-typedef	struct	ParForThread	ParForThread;
-typedef	struct	CgoMal		CgoMal;
-typedef	struct	PollDesc	PollDesc;
-typedef	struct	DebugVars	DebugVars;
-typedef	struct	ForceGCState	ForceGCState;
-typedef	struct	Stack		Stack;
-
-/*
- * Per-CPU declaration.
- *
- * "extern register" is a special storage class implemented by 6c, 8c, etc.
- * On the ARM, it is an actual register; elsewhere it is a slot in thread-
- * local storage indexed by a pseudo-register TLS. See zasmhdr in
- * src/cmd/dist/buildruntime.c for details, and be aware that the linker may
- * make further OS-specific changes to the compiler's output. For example,
- * 6l/linux rewrites 0(TLS) as -8(FS).
- *
- * Every C file linked into a Go program must include runtime.h so that the
- * C compiler (6c, 8c, etc.) knows to avoid other uses of these dedicated
- * registers. The Go compiler (6g, 8g, etc.) knows to avoid them.
- */
-extern	register	G*	g;
-
-/*
- * defined constants
- */
-enum
-{
-	// G status
-	//
-	// If you add to this list, add to the list
-	// of "okay during garbage collection" status
-	// in mgc0.c too.
-	Gidle,                                 // 0
-	Grunnable,                             // 1 runnable and on a run queue
-	Grunning,                              // 2
-	Gsyscall,                              // 3
-	Gwaiting,                              // 4
-	Gmoribund_unused,                      // 5 currently unused, but hardcoded in gdb scripts
-	Gdead,                                 // 6
-	Genqueue,                              // 7 Only the Gscanenqueue is used.
-	Gcopystack,                            // 8 in this state when newstack is moving the stack
-	// the following encode that the GC is scanning the stack and what to do when it is done 
-	Gscan = 0x1000,                        // atomicstatus&~Gscan = the non-scan state,
-	// Gscanidle =     Gscan + Gidle,      // Not used. Gidle only used with newly malloced gs
-	Gscanrunnable = Gscan + Grunnable,     //  0x1001 When scanning complets make Grunnable (it is already on run queue)
-	Gscanrunning =  Gscan + Grunning,      //  0x1002 Used to tell preemption newstack routine to scan preempted stack.
-	Gscansyscall =  Gscan + Gsyscall,      //  0x1003 When scanning completes make is Gsyscall
-	Gscanwaiting =  Gscan + Gwaiting,      //  0x1004 When scanning completes make it Gwaiting
-	// Gscanmoribund_unused,               //  not possible
-	// Gscandead,                          //  not possible
-	Gscanenqueue = Gscan + Genqueue,       //  When scanning completes make it Grunnable and put on runqueue
-};
-enum
-{
-	// P status
-	Pidle,
-	Prunning,
-	Psyscall,
-	Pgcstop,
-	Pdead,
-};
-enum
-{
-	true	= 1,
-	false	= 0,
-};
-enum
-{
-	PtrSize = sizeof(void*),
-};
-/*
- * structures
- */
-struct	Mutex
-{
-	// Futex-based impl treats it as uint32 key,
-	// while sema-based impl as M* waitm.
-	// Used to be a union, but unions break precise GC.
-	uintptr	key;
-};
-struct	Note
-{
-	// Futex-based impl treats it as uint32 key,
-	// while sema-based impl as M* waitm.
-	// Used to be a union, but unions break precise GC.
-	uintptr	key;
-};
-struct String
-{
-	byte*	str;
-	intgo	len;
-};
-struct FuncVal
-{
-	void	(*fn)(void);
-	// variable-size, fn-specific data here
-};
-struct Iface
-{
-	Itab*	tab;
-	void*	data;
-};
-struct Eface
-{
-	Type*	type;
-	void*	data;
-};
-struct Complex64
-{
-	float32	real;
-	float32	imag;
-};
-struct Complex128
-{
-	float64	real;
-	float64	imag;
-};
-
-struct	Slice
-{				// must not move anything
-	byte*	array;		// actual data
-	uintgo	len;		// number of elements
-	uintgo	cap;		// allocated number of elements
-};
-struct	Gobuf
-{
-	// The offsets of sp, pc, and g are known to (hard-coded in) libmach.
-	uintptr	sp;
-	uintptr	pc;
-	G*	g;
-	void*	ctxt; // this has to be a pointer so that GC scans it
-	uintreg	ret;
-	uintptr	lr;
-};
-// Known to compiler.
-// Changes here must also be made in src/cmd/gc/select.c's selecttype.
-struct	SudoG
-{
-	G*	g;
-	uint32*	selectdone;
-	SudoG*	next;
-	SudoG*	prev;
-	void*	elem;		// data element
-	int64	releasetime;
-	int32	nrelease;	// -1 for acquire
-	SudoG*	waitlink;	// G.waiting list
-};
-struct	GCStats
-{
-	// the struct must consist of only uint64's,
-	// because it is casted to uint64[].
-	uint64	nhandoff;
-	uint64	nhandoffcnt;
-	uint64	nprocyield;
-	uint64	nosyield;
-	uint64	nsleep;
-};
-
-struct	LibCall
-{
-	uintptr	fn;
-	uintptr	n;	// number of parameters
-	uintptr	args;	// parameters
-	uintptr	r1;	// return values
-	uintptr	r2;
-	uintptr	err;	// error number
-};
-
-// describes how to handle callback
-struct	WinCallbackContext
-{
-	void*	gobody;		// Go function to call
-	uintptr	argsize;	// callback arguments size (in bytes)
-	uintptr	restorestack;	// adjust stack on return by (in bytes) (386 only)
-	bool	cleanstack;
-};
-
-// Stack describes a Go execution stack.
-// The bounds of the stack are exactly [lo, hi),
-// with no implicit data structures on either side.
-struct	Stack
-{
-	uintptr	lo;
-	uintptr	hi;
-};
-
-struct	G
-{
-	// Stack parameters.
-	// stack describes the actual stack memory: [stack.lo, stack.hi).
-	// stackguard0 is the stack pointer compared in the Go stack growth prologue.
-	// It is stack.lo+StackGuard normally, but can be StackPreempt to trigger a preemption.
-	// stackguard1 is the stack pointer compared in the C stack growth prologue.
-	// It is stack.lo+StackGuard on g0 and gsignal stacks.
-	// It is ~0 on other goroutine stacks, to trigger a call to morestackc (and crash).
-	Stack	stack;	// offset known to runtime/cgo
-	uintptr	stackguard0;	// offset known to liblink
-	uintptr	stackguard1;	// offset known to liblink
-
-	Panic*	panic;	// innermost panic - offset known to liblink
-	Defer*	defer;	// innermost defer
-	Gobuf	sched;
-	uintptr	syscallsp;	// if status==Gsyscall, syscallsp = sched.sp to use during gc
-	uintptr	syscallpc;	// if status==Gsyscall, syscallpc = sched.pc to use during gc
-	void*	param;		// passed parameter on wakeup
-	uint32	atomicstatus;
-	int64	goid;
-	int64	waitsince;	// approx time when the G become blocked
-	String	waitreason;	// if status==Gwaiting
-	G*	schedlink;
-	bool	issystem;	// do not output in stack dump, ignore in deadlock detector
-	bool	preempt;	// preemption signal, duplicates stackguard0 = StackPreempt
-	bool	paniconfault;	// panic (instead of crash) on unexpected fault address
-	bool	preemptscan;    // preempted g does scan for GC
-	bool	gcworkdone;     // debug: cleared at begining of gc work phase cycle, set by gcphasework, tested at end of cycle
-	bool	throwsplit; // must not split stack
-	int8	raceignore;	// ignore race detection events
-	M*	m;		// for debuggers, but offset not hard-coded
-	M*	lockedm;
-	int32	sig;
-	Slice	writebuf;
-	uintptr	sigcode0;
-	uintptr	sigcode1;
-	uintptr	sigpc;
-	uintptr	gopc;		// pc of go statement that created this goroutine
-	uintptr	racectx;
-	SudoG*	waiting;	// sudog structures this G is waiting on (that have a valid elem ptr)
-	uintptr	end[];
-};
-
-struct	M
-{
-	G*	g0;		// goroutine with scheduling stack
-	Gobuf	morebuf;	// gobuf arg to morestack
-
-	// Fields not known to debuggers.
-	uint64	procid;		// for debuggers, but offset not hard-coded
-	G*	gsignal;	// signal-handling G
-	uintptr	tls[4];		// thread-local storage (for x86 extern register)
-	void	(*mstartfn)(void);
-	G*	curg;		// current running goroutine
-	G*	caughtsig;	// goroutine running during fatal signal
-	P*	p;		// attached P for executing Go code (nil if not executing Go code)
-	P*	nextp;
-	int32	id;
-	int32	mallocing;
-	int32	throwing;
-	int32	gcing;
-	int32	locks;
-	int32	softfloat;
-	int32	dying;
-	int32	profilehz;
-	int32	helpgc;
-	bool	spinning;	// M is out of work and is actively looking for work
-	bool	blocked;	// M is blocked on a Note
-	uint32	fastrand;
-	uint64	ncgocall;	// number of cgo calls in total
-	int32	ncgo;		// number of cgo calls currently in progress
-	CgoMal*	cgomal;
-	Note	park;
-	M*	alllink;	// on allm
-	M*	schedlink;
-	uint32	machport;	// Return address for Mach IPC (OS X)
-	MCache*	mcache;
-	G*	lockedg;
-	uintptr	createstack[32];// Stack that created this thread.
-	uint32	freglo[16];	// D[i] lsb and F[i]
-	uint32	freghi[16];	// D[i] msb and F[i+16]
-	uint32	fflag;		// floating point compare flags
-	uint32	locked;		// tracking for LockOSThread
-	M*	nextwaitm;	// next M waiting for lock
-	uintptr	waitsema;	// semaphore for parking on locks
-	uint32	waitsemacount;
-	uint32	waitsemalock;
-	GCStats	gcstats;
-	bool	needextram;
-	uint8	traceback;
-	bool	(*waitunlockf)(G*, void*);
-	void*	waitlock;
-	uintptr scalararg[4];	// scalar argument/return for mcall
-	void*   ptrarg[4];	// pointer argument/return for mcall
-#ifdef GOOS_windows
-	uintptr	thread;		// thread handle
-	// these are here because they are too large to be on the stack
-	// of low-level NOSPLIT functions.
-	LibCall	libcall;
-	uintptr	libcallpc;	// for cpu profiler
-	uintptr	libcallsp;
-	G*	libcallg;
-#endif
-#ifdef GOOS_solaris
-	int32*	perrno; 	// pointer to TLS errno
-	// these are here because they are too large to be on the stack
-	// of low-level NOSPLIT functions.
-	LibCall	libcall;
-	struct MTs {
-		int64	tv_sec;
-		int64	tv_nsec;
-	} ts;
-	struct MScratch {
-		uintptr v[6];
-	} scratch;
-#endif
-#ifdef GOOS_plan9
-	int8*	notesig;
-	byte*	errstr;
-#endif
-	uintptr	end[];
-};
-
-struct P
-{
-	Mutex	lock;
-
-	int32	id;
-	uint32	status;		// one of Pidle/Prunning/...
-	P*	link;
-	uint32	schedtick;	// incremented on every scheduler call
-	uint32	syscalltick;	// incremented on every system call
-	M*	m;		// back-link to associated M (nil if idle)
-	MCache*	mcache;
-	Defer*	deferpool[5];	// pool of available Defer structs of different sizes (see panic.c)
-
-	// Cache of goroutine ids, amortizes accesses to runtime·sched.goidgen.
-	uint64	goidcache;
-	uint64	goidcacheend;
-
-	// Queue of runnable goroutines.
-	uint32	runqhead;
-	uint32	runqtail;
-	G*	runq[256];
-
-	// Available G's (status == Gdead)
-	G*	gfree;
-	int32	gfreecnt;
-
-	byte	pad[64];
-};
-
-enum {
-	// The max value of GOMAXPROCS.
-	// There are no fundamental restrictions on the value.
-	MaxGomaxprocs = 1<<8,
-};
-
-struct	SchedT
-{
-	Mutex	lock;
-
-	uint64	goidgen;
-
-	M*	midle;	 // idle m's waiting for work
-	int32	nmidle;	 // number of idle m's waiting for work
-	int32	nmidlelocked; // number of locked m's waiting for work
-	int32	mcount;	 // number of m's that have been created
-	int32	maxmcount;	// maximum number of m's allowed (or die)
-
-	P*	pidle;  // idle P's
-	uint32	npidle;
-	uint32	nmspinning;
-
-	// Global runnable queue.
-	G*	runqhead;
-	G*	runqtail;
-	int32	runqsize;
-
-	// Global cache of dead G's.
-	Mutex	gflock;
-	G*	gfree;
-	int32	ngfree;
-
-	uint32	gcwaiting;	// gc is waiting to run
-	int32	stopwait;
-	Note	stopnote;
-	uint32	sysmonwait;
-	Note	sysmonnote;
-	uint64	lastpoll;
-
-	int32	profilehz;	// cpu profiling rate
-};
-
-// The m->locked word holds two pieces of state counting active calls to LockOSThread/lockOSThread.
-// The low bit (LockExternal) is a boolean reporting whether any LockOSThread call is active.
-// External locks are not recursive; a second lock is silently ignored.
-// The upper bits of m->lockedcount record the nesting depth of calls to lockOSThread
-// (counting up by LockInternal), popped by unlockOSThread (counting down by LockInternal).
-// Internal locks can be recursive. For instance, a lock for cgo can occur while the main
-// goroutine is holding the lock during the initialization phase.
-enum
-{
-	LockExternal = 1,
-	LockInternal = 2,
-};
-
-struct	SigTab
-{
-	int32	flags;
-	int8	*name;
-};
-enum
-{
-	SigNotify = 1<<0,	// let signal.Notify have signal, even if from kernel
-	SigKill = 1<<1,		// if signal.Notify doesn't take it, exit quietly
-	SigThrow = 1<<2,	// if signal.Notify doesn't take it, exit loudly
-	SigPanic = 1<<3,	// if the signal is from the kernel, panic
-	SigDefault = 1<<4,	// if the signal isn't explicitly requested, don't monitor it
-	SigHandling = 1<<5,	// our signal handler is registered
-	SigIgnored = 1<<6,	// the signal was ignored before we registered for it
-	SigGoExit = 1<<7,	// cause all runtime procs to exit (only used on Plan 9).
-};
-
-// 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
-// and with package debug/gosym and with symtab.go in package runtime.
-struct	Func
-{
-	uintptr	entry;	// start pc
-	int32	nameoff;// function name
-	
-	int32	args;	// in/out args size
-	int32	frame;	// legacy frame size; use pcsp if possible
-
-	int32	pcsp;
-	int32	pcfile;
-	int32	pcln;
-	int32	npcdata;
-	int32	nfuncdata;
-};
-
-// layout of Itab known to compilers
-// allocated in non-garbage-collected memory
-struct	Itab
-{
-	InterfaceType*	inter;
-	Type*	type;
-	Itab*	link;
-	int32	bad;
-	int32	unused;
-	void	(*fun[])(void);
-};
-
-#ifdef GOOS_nacl
-enum {
-   NaCl = 1,
-};
-#else
-enum {
-   NaCl = 0,
-};
-#endif
-
-#ifdef GOOS_windows
-enum {
-   Windows = 1
-};
-#else
-enum {
-   Windows = 0
-};
-#endif
-#ifdef GOOS_solaris
-enum {
-   Solaris = 1
-};
-#else
-enum {
-   Solaris = 0
-};
-#endif
-#ifdef GOOS_plan9
-enum {
-   Plan9 = 1
-};
-#else
-enum {
-   Plan9 = 0
-};
-#endif
-
-// Lock-free stack node.
-struct LFNode
-{
-	LFNode	*next;
-	uintptr	pushcnt;
-};
-
-// Parallel for descriptor.
-struct ParFor
-{
-	void (*body)(ParFor*, uint32);	// executed for each element
-	uint32 done;			// number of idle threads
-	uint32 nthr;			// total number of threads
-	uint32 nthrmax;			// maximum number of threads
-	uint32 thrseq;			// thread id sequencer
-	uint32 cnt;			// iteration space [0, cnt)
-	void *ctx;			// arbitrary user context
-	bool wait;			// if true, wait while all threads finish processing,
-					// otherwise parfor may return while other threads are still working
-	ParForThread *thr;		// array of thread descriptors
-	uint32 pad;			// to align ParForThread.pos for 64-bit atomic operations
-	// stats
-	uint64 nsteal;
-	uint64 nstealcnt;
-	uint64 nprocyield;
-	uint64 nosyield;
-	uint64 nsleep;
-};
-
-// Track memory allocated by code not written in Go during a cgo call,
-// so that the garbage collector can see them.
-struct CgoMal
-{
-	CgoMal	*next;
-	void	*alloc;
-};
-
-// Holds variables parsed from GODEBUG env var.
-struct DebugVars
-{
-	int32	allocfreetrace;
-	int32	efence;
-	int32	gctrace;
-	int32	gcdead;
-	int32	scheddetail;
-	int32	schedtrace;
-	int32	scavenge;
-};
-
-// Indicates to write barrier and sychronization task to preform.
-enum
-{                   // Synchronization            Write barrier
-	GCoff,      // stop and start             nop
-	GCquiesce,  // stop and start             nop
-	GCstw,      // stop the ps                nop
-	GCmark,     // scan the stacks and start  no white to black
-	GCsweep,    // stop and start             nop
-};
-
-struct ForceGCState
-{
-	Mutex	lock;
-	G*	g;
-	uint32	idle;
-};
-
-extern uint32 runtime·gcphase;
-
-/*
- * defined macros
- *    you need super-gopher-guru privilege
- *    to add this list.
- */
-#define	nelem(x)	(sizeof(x)/sizeof((x)[0]))
-#define	nil		((void*)0)
-#define	offsetof(s,m)	(uint32)(&(((s*)0)->m))
-#define	ROUND(x, n)	(((x)+(n)-1)&~(uintptr)((n)-1)) /* all-caps to mark as macro: it evaluates n twice */
-
-/*
- * known to compiler
- */
-enum {
-	Structrnd = sizeof(uintreg),
-};
-
-byte*	runtime·startup_random_data;
-uint32	runtime·startup_random_data_len;
-
-int32	runtime·invalidptr;
-
-enum {
-	// hashinit wants this many random bytes
-	HashRandomBytes = 32
-};
-
-uint32  runtime·readgstatus(G*);
-void    runtime·casgstatus(G*, uint32, uint32);
-void    runtime·casgstatus(G*, uint32, uint32);
-uint32	runtime·casgcopystack(G*);
-void    runtime·quiesce(G*);
-bool    runtime·stopg(G*);
-void    runtime·restartg(G*);
-void    runtime·gcphasework(G*);
-
-/*
- * deferred subroutine calls
- */
-struct Defer
-{
-	int32	siz;
-	bool	started;
-	uintptr	argp;		// where args were copied from
-	uintptr	pc;
-	FuncVal*	fn;
-	Panic*	panic;	// panic that is running defer
-	Defer*	link;
-};
-
-// argp used in Defer structs when there is no argp.
-#define NoArgs ((uintptr)-1)
-
-/*
- * panics
- */
-struct Panic
-{
-	void*	argp;	// pointer to arguments of deferred call run during panic; cannot move - known to liblink
-	Eface	arg;		// argument to panic
-	Panic*	link;		// link to earlier panic
-	bool	recovered;	// whether this panic is over
-	bool	aborted;	// the panic was aborted
-};
-
-/*
- * stack traces
- */
-typedef struct Stkframe Stkframe;
-typedef struct BitVector BitVector;
-struct Stkframe
-{
-	Func*	fn;	// function being run
-	uintptr	pc;	// program counter within fn
-	uintptr	continpc;	// program counter where execution can continue, or 0 if not
-	uintptr	lr;	// program counter at caller aka link register
-	uintptr	sp;	// stack pointer at pc
-	uintptr	fp;	// stack pointer at caller aka frame pointer
-	uintptr	varp;	// top of local variables
-	uintptr	argp;	// pointer to function arguments
-	uintptr	arglen;	// number of bytes at argp
-	BitVector*	argmap;	// force use of this argmap
-};
-
-enum
-{
-	TraceRuntimeFrames = 1<<0, // include frames for internal runtime functions.
-	TraceTrap = 1<<1, // the initial PC, SP are from a trap, not a return PC from a call
-};
-intgo	runtime·gentraceback(uintptr, uintptr, uintptr, G*, intgo, uintptr*, intgo, bool(**)(Stkframe*, void*), void*, uintgo);
-void	runtime·tracebackdefers(G*, bool(**)(Stkframe*, void*), void*);
-void	runtime·traceback(uintptr pc, uintptr sp, uintptr lr, G* gp);
-void	runtime·tracebacktrap(uintptr pc, uintptr sp, uintptr lr, G* gp);
-void	runtime·tracebackothers(G*);
-bool	runtime·haszeroargs(uintptr pc);
-bool	runtime·topofstack(Func*);
-enum
-{
-	// The maximum number of frames we print for a traceback
-	TracebackMaxFrames = 100,
-};
-
-/*
- * external data
- */
-extern	String	runtime·emptystring;
-extern	G**	runtime·allg;
-extern	Slice	runtime·allgs; // []*G
-extern	uintptr runtime·allglen;
-extern	G*	runtime·lastg;
-extern	M*	runtime·allm;
-extern	P*	runtime·allp[MaxGomaxprocs+1];
-extern	int32	runtime·gomaxprocs;
-extern	uint32	runtime·needextram;
-extern	uint32	runtime·panicking;
-extern	int8*	runtime·goos;
-extern	int32	runtime·ncpu;
-extern	bool	runtime·iscgo;
-extern 	void	(*runtime·sysargs)(int32, uint8**);
-extern	uintptr	runtime·maxstring;
-extern	uint32	runtime·cpuid_ecx;
-extern	uint32	runtime·cpuid_edx;
-extern	DebugVars	runtime·debug;
-extern	uintptr	runtime·maxstacksize;
-extern	Note	runtime·signote;
-extern	ForceGCState	runtime·forcegc;
-extern	SchedT	runtime·sched;
-extern	int32		runtime·newprocs;
-
-/*
- * common functions and data
- */
-int32	runtime·strcmp(byte*, byte*);
-int32	runtime·strncmp(byte*, byte*, uintptr);
-byte*	runtime·strstr(byte*, byte*);
-intgo	runtime·findnull(byte*);
-intgo	runtime·findnullw(uint16*);
-void	runtime·dump(byte*, int32);
-int32	runtime·runetochar(byte*, int32);
-int32	runtime·charntorune(int32*, uint8*, int32);
-
-
-/*
- * This macro is used when writing C functions
- * called as if they were Go functions.
- * Passed the address of a result before a return statement,
- * it makes sure the result has been flushed to memory
- * before the return.
- *
- * It is difficult to write such functions portably, because
- * of the varying requirements on the alignment of the
- * first output value. Almost all code should write such
- * functions in .goc files, where goc2c (part of cmd/dist)
- * can arrange the correct alignment for the target system.
- * Goc2c also takes care of conveying to the garbage collector
- * which parts of the argument list are inputs vs outputs.
- *
- * Therefore, do NOT use this macro if at all possible.
- */ 
-#define FLUSH(x)	USED(x)
-
-/*
- * GoOutput is a type with the same alignment requirements as the
- * initial output argument from a Go function. Only for use in cases
- * where using goc2c is not possible. See comment on FLUSH above.
- */
-typedef uint64 GoOutput;
-
-void	runtime·gogo(Gobuf*);
-void	runtime·gostartcall(Gobuf*, void(*)(void), void*);
-void	runtime·gostartcallfn(Gobuf*, FuncVal*);
-void	runtime·gosave(Gobuf*);
-void	runtime·goargs(void);
-void	runtime·goenvs(void);
-void	runtime·goenvs_unix(void);
-void*	runtime·getu(void);
-void	runtime·throw(int8*);
-bool	runtime·canpanic(G*);
-void	runtime·prints(int8*);
-void	runtime·printf(int8*, ...);
-void	runtime·snprintf(byte*, int32, int8*, ...);
-byte*	runtime·mchr(byte*, byte, byte*);
-int32	runtime·mcmp(byte*, byte*, uintptr);
-void	runtime·memmove(void*, void*, uintptr);
-String	runtime·catstring(String, String);
-String	runtime·gostring(byte*);
-Slice	runtime·makeStringSlice(intgo);
-String  runtime·gostringn(byte*, intgo);
-Slice	runtime·gobytes(byte*, intgo);
-String	runtime·gostringnocopy(byte*);
-String	runtime·gostringw(uint16*);
-void	runtime·initsig(void);
-void	runtime·sigenable(uint32 sig);
-void	runtime·sigdisable(uint32 sig);
-int32	runtime·gotraceback(bool *crash);
-void	runtime·goroutineheader(G*);
-int32	runtime·open(int8*, int32, int32);
-int32	runtime·read(int32, void*, int32);
-int32	runtime·write(uintptr, void*, int32); // use uintptr to accommodate windows.
-int32	runtime·close(int32);
-int32	runtime·mincore(void*, uintptr, byte*);
-void	runtime·jmpdefer(FuncVal*, uintptr);
-void	runtime·exit1(int32);
-void	runtime·ready(G*);
-byte*	runtime·getenv(int8*);
-int32	runtime·atoi(byte*);
-void	runtime·newosproc(M *mp, void *stk);
-void	runtime·mstart(void);
-G*	runtime·malg(int32);
-void	runtime·asminit(void);
-void	runtime·mpreinit(M*);
-void	runtime·minit(void);
-void	runtime·unminit(void);
-void	runtime·signalstack(byte*, int32);
-void	runtime·tracebackinit(void);
-void	runtime·symtabinit(void);
-Func*	runtime·findfunc(uintptr);
-int32	runtime·funcline(Func*, uintptr, String*);
-int32	runtime·funcspdelta(Func*, uintptr);
-int8*	runtime·funcname(Func*);
-int32	runtime·pcdatavalue(Func*, int32, uintptr);
-void	runtime·stackinit(void);
-Stack	runtime·stackalloc(uint32);
-void	runtime·stackfree(Stack);
-void	runtime·shrinkstack(G*);
-void	runtime·shrinkfinish(void);
-MCache*	runtime·allocmcache(void);
-void	runtime·freemcache(MCache*);
-void	runtime·mallocinit(void);
-void	runtime·gcinit(void);
-void*	runtime·mallocgc(uintptr size, Type* typ, uint32 flag);
-void	runtime·runpanic(Panic*);
-uintptr	runtime·getcallersp(void*);
-int32	runtime·mcount(void);
-int32	runtime·gcount(void);
-void	runtime·mcall(void(**)(G*));
-void	runtime·onM(void(**)(void));
-void	runtime·onMsignal(void(**)(void));
-uint32	runtime·fastrand1(void);
-void	runtime·rewindmorestack(Gobuf*);
-int32	runtime·timediv(int64, int32, int32*);
-int32	runtime·round2(int32 x); // round x up to a power of 2.
-
-// atomic operations
-bool	runtime·cas(uint32*, uint32, uint32);
-bool	runtime·cas64(uint64*, uint64, uint64);
-bool	runtime·casp(void**, void*, void*);
-// Don't confuse with XADD x86 instruction,
-// this one is actually 'addx', that is, add-and-fetch.
-uint32	runtime·xadd(uint32 volatile*, int32);
-uint64	runtime·xadd64(uint64 volatile*, int64);
-uint32	runtime·xchg(uint32 volatile*, uint32);
-uint64	runtime·xchg64(uint64 volatile*, uint64);
-void*	runtime·xchgp(void* volatile*, void*);
-uint32	runtime·atomicload(uint32 volatile*);
-void	runtime·atomicstore(uint32 volatile*, uint32);
-void	runtime·atomicstore64(uint64 volatile*, uint64);
-uint64	runtime·atomicload64(uint64 volatile*);
-void*	runtime·atomicloadp(void* volatile*);
-uintptr	runtime·atomicloaduintptr(uintptr volatile*);
-void	runtime·atomicstorep(void* volatile*, void*);
-void	runtime·atomicstoreuintptr(uintptr volatile*, uintptr);
-void	runtime·atomicor8(byte volatile*, byte);
-
-void	runtime·setg(G*);
-void	runtime·newextram(void);
-void	runtime·exit(int32);
-void	runtime·breakpoint(void);
-void	runtime·gosched_m(G*);
-void	runtime·schedtrace(bool);
-void	runtime·park(bool(*)(G*, void*), void*, String);
-void	runtime·parkunlock(Mutex*, String);
-void	runtime·tsleep(int64, String);
-M*	runtime·newm(void);
-void	runtime·goexit(void);
-void	runtime·asmcgocall(void (*fn)(void*), void*);
-int32	runtime·asmcgocall_errno(void (*fn)(void*), void*);
-void	runtime·entersyscall(void);
-void	runtime·reentersyscall(uintptr, uintptr);
-void	runtime·entersyscallblock(void);
-void	runtime·exitsyscall(void);
-G*	runtime·newproc1(FuncVal*, byte*, int32, int32, void*);
-bool	runtime·sigsend(int32 sig);
-intgo	runtime·callers(intgo, uintptr*, intgo);
-intgo	runtime·gcallers(G*, intgo, uintptr*, intgo);
-int64	runtime·nanotime(void);	// monotonic time
-int64	runtime·unixnanotime(void); // real time, can skip
-void	runtime·dopanic(int32);
-void	runtime·startpanic(void);
-void	runtime·freezetheworld(void);
-void	runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp, M *mp);
-void	runtime·resetcpuprofiler(int32);
-void	runtime·setcpuprofilerate(int32);
-void	runtime·usleep(uint32);
-int64	runtime·cputicks(void);
-int64	runtime·tickspersecond(void);
-void	runtime·blockevent(int64, intgo);
-G*	runtime·netpoll(bool);
-void	runtime·netpollready(G**, PollDesc*, int32);
-uintptr	runtime·netpollfd(PollDesc*);
-void**	runtime·netpolluser(PollDesc*);
-bool	runtime·netpollclosing(PollDesc*);
-void	runtime·netpolllock(PollDesc*);
-void	runtime·netpollunlock(PollDesc*);
-void	runtime·crash(void);
-void	runtime·parsedebugvars(void);
-void*	runtime·funcdata(Func*, int32);
-void	runtime·setmaxthreads_m(void);
-G*	runtime·timejump(void);
-void	runtime·iterate_itabs(void (**callback)(Itab*));
-void	runtime·iterate_finq(void (*callback)(FuncVal*, byte*, uintptr, Type*, PtrType*));
-
-#pragma	varargck	argpos	runtime·printf	1
-#pragma	varargck	type	"c"	int32
-#pragma	varargck	type	"d"	int32
-#pragma	varargck	type	"d"	uint32
-#pragma	varargck	type	"D"	int64
-#pragma	varargck	type	"D"	uint64
-#pragma	varargck	type	"x"	int32
-#pragma	varargck	type	"x"	uint32
-#pragma	varargck	type	"X"	int64
-#pragma	varargck	type	"X"	uint64
-#pragma	varargck	type	"p"	void*
-#pragma	varargck	type	"p"	uintptr
-#pragma	varargck	type	"s"	int8*
-#pragma	varargck	type	"s"	uint8*
-#pragma	varargck	type	"S"	String
-
-void	runtime·stoptheworld(void);
-void	runtime·starttheworld(void);
-extern uint32 runtime·worldsema;
-
-/*
- * mutual exclusion locks.  in the uncontended case,
- * as fast as spin locks (just a few user-level instructions),
- * but on the contention path they sleep in the kernel.
- * a zeroed Mutex is unlocked (no need to initialize each lock).
- */
-void	runtime·lock(Mutex*);
-void	runtime·unlock(Mutex*);
-
-/*
- * sleep and wakeup on one-time events.
- * before any calls to notesleep or notewakeup,
- * must call noteclear to initialize the Note.
- * then, exactly one thread can call notesleep
- * and exactly one thread can call notewakeup (once).
- * once notewakeup has been called, the notesleep
- * will return.  future notesleep will return immediately.
- * subsequent noteclear must be called only after
- * previous notesleep has returned, e.g. it's disallowed
- * to call noteclear straight after notewakeup.
- *
- * notetsleep is like notesleep but wakes up after
- * a given number of nanoseconds even if the event
- * has not yet happened.  if a goroutine uses notetsleep to
- * wake up early, it must wait to call noteclear until it
- * can be sure that no other goroutine is calling
- * notewakeup.
- *
- * notesleep/notetsleep are generally called on g0,
- * notetsleepg is similar to notetsleep but is called on user g.
- */
-void	runtime·noteclear(Note*);
-void	runtime·notesleep(Note*);
-void	runtime·notewakeup(Note*);
-bool	runtime·notetsleep(Note*, int64);  // false - timeout
-bool	runtime·notetsleepg(Note*, int64);  // false - timeout
-
-/*
- * low-level synchronization for implementing the above
- */
-uintptr	runtime·semacreate(void);
-int32	runtime·semasleep(int64);
-void	runtime·semawakeup(M*);
-// or
-void	runtime·futexsleep(uint32*, uint32, int64);
-void	runtime·futexwakeup(uint32*, uint32);
-
-/*
- * Mutex-free stack.
- * Initialize uint64 head to 0, compare with 0 to test for emptiness.
- * The stack does not keep pointers to nodes,
- * so they can be garbage collected if there are no other pointers to nodes.
- */
-void	runtime·lfstackpush(uint64 *head, LFNode *node);
-LFNode*	runtime·lfstackpop(uint64 *head);
-
-/*
- * Parallel for over [0, n).
- * body() is executed for each iteration.
- * nthr - total number of worker threads.
- * ctx - arbitrary user context.
- * if wait=true, threads return from parfor() when all work is done;
- * otherwise, threads can return while other threads are still finishing processing.
- */
-ParFor*	runtime·parforalloc(uint32 nthrmax);
-void	runtime·parforsetup(ParFor *desc, uint32 nthr, uint32 n, void *ctx, bool wait, void (*body)(ParFor*, uint32));
-void	runtime·parfordo(ParFor *desc);
-void	runtime·parforiters(ParFor*, uintptr, uintptr*, uintptr*);
-
-/*
- * low level C-called
- */
-// for mmap, we only pass the lower 32 bits of file offset to the 
-// assembly routine; the higher bits (if required), should be provided
-// by the assembly routine as 0.
-uint8*	runtime·mmap(byte*, uintptr, int32, int32, int32, uint32);
-void	runtime·munmap(byte*, uintptr);
-void	runtime·madvise(byte*, uintptr, int32);
-void	runtime·memclr(byte*, uintptr);
-void	runtime·setcallerpc(void*, void*);
-void*	runtime·getcallerpc(void*);
-void	runtime·printbool(bool);
-void	runtime·printbyte(int8);
-void	runtime·printfloat(float64);
-void	runtime·printint(int64);
-void	runtime·printiface(Iface);
-void	runtime·printeface(Eface);
-void	runtime·printstring(String);
-void	runtime·printpc(void*);
-void	runtime·printpointer(void*);
-void	runtime·printuint(uint64);
-void	runtime·printhex(uint64);
-void	runtime·printslice(Slice);
-void	runtime·printcomplex(Complex128);
-
-/*
- * runtime go-called
- */
-void	runtime·gopanic(Eface);
-void	runtime·panicindex(void);
-void	runtime·panicslice(void);
-void	runtime·panicdivide(void);
-
-/*
- * runtime c-called (but written in Go)
- */
-void	runtime·printany(Eface);
-void	runtime·newTypeAssertionError(String*, String*, String*, String*, Eface*);
-void	runtime·fadd64c(uint64, uint64, uint64*);
-void	runtime·fsub64c(uint64, uint64, uint64*);
-void	runtime·fmul64c(uint64, uint64, uint64*);
-void	runtime·fdiv64c(uint64, uint64, uint64*);
-void	runtime·fneg64c(uint64, uint64*);
-void	runtime·f32to64c(uint32, uint64*);
-void	runtime·f64to32c(uint64, uint32*);
-void	runtime·fcmp64c(uint64, uint64, int32*, bool*);
-void	runtime·fintto64c(int64, uint64*);
-void	runtime·f64tointc(uint64, int64*, bool*);
-
-/*
- * wrapped for go users
- */
-float64	runtime·Inf(int32 sign);
-float64	runtime·NaN(void);
-float32	runtime·float32frombits(uint32 i);
-uint32	runtime·float32tobits(float32 f);
-float64	runtime·float64frombits(uint64 i);
-uint64	runtime·float64tobits(float64 f);
-float64	runtime·frexp(float64 d, int32 *ep);
-bool	runtime·isInf(float64 f, int32 sign);
-bool	runtime·isNaN(float64 f);
-float64	runtime·ldexp(float64 d, int32 e);
-float64	runtime·modf(float64 d, float64 *ip);
-void	runtime·semacquire(uint32*, bool);
-void	runtime·semrelease(uint32*);
-int32	runtime·gomaxprocsfunc(int32 n);
-void	runtime·procyield(uint32);
-void	runtime·osyield(void);
-void	runtime·lockOSThread(void);
-void	runtime·unlockOSThread(void);
-
-bool	runtime·showframe(Func*, G*);
-void	runtime·printcreatedby(G*);
-
-void	runtime·ifaceE2I(InterfaceType*, Eface, Iface*);
-bool	runtime·ifaceE2I2(InterfaceType*, Eface, Iface*);
-uintptr	runtime·memlimit(void);
-
-// float.c
-extern float64 runtime·nan;
-extern float64 runtime·posinf;
-extern float64 runtime·neginf;
-extern uint64 ·nan;
-extern uint64 ·posinf;
-extern uint64 ·neginf;
-#define ISNAN(f) ((f) != (f))
-
-enum
-{
-	UseSpanType = 1,
-};
diff --git a/src/runtime/runtime1.go b/src/runtime/runtime1.go
new file mode 100644
index 0000000..134c999
--- /dev/null
+++ b/src/runtime/runtime1.go
@@ -0,0 +1,450 @@
+// 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"
+
+// Keep a cached value to make gotraceback fast,
+// since we call it on every call to gentraceback.
+// The cached value is a uint32 in which the low bit
+// is the "crash" setting and the top 31 bits are the
+// gotraceback value.
+var traceback_cache uint32 = 2 << 1
+
+// The GOTRACEBACK environment variable controls the
+// behavior of a Go program that is crashing and exiting.
+//	GOTRACEBACK=0   suppress all tracebacks
+//	GOTRACEBACK=1   default behavior - show tracebacks but exclude runtime frames
+//	GOTRACEBACK=2   show tracebacks including runtime frames
+//	GOTRACEBACK=crash   show tracebacks including runtime frames, then crash (core dump etc)
+//go:nosplit
+func gotraceback(crash *bool) int32 {
+	_g_ := getg()
+	if crash != nil {
+		*crash = false
+	}
+	if _g_.m.traceback != 0 {
+		return int32(_g_.m.traceback)
+	}
+	if crash != nil {
+		*crash = traceback_cache&1 != 0
+	}
+	return int32(traceback_cache >> 1)
+}
+
+var (
+	argc int32
+	argv **byte
+)
+
+// nosplit for use in linux/386 startup linux_setup_vdso
+//go:nosplit
+func argv_index(argv **byte, i int32) *byte {
+	return *(**byte)(add(unsafe.Pointer(argv), uintptr(i)*ptrSize))
+}
+
+func args(c int32, v **byte) {
+	argc = c
+	argv = v
+	sysargs(c, v)
+}
+
+var (
+	// TODO: Retire in favor of GOOS== checks.
+	isplan9   int32
+	issolaris int32
+	iswindows int32
+)
+
+func goargs() {
+	if GOOS == "windows" {
+		return
+	}
+
+	argslice = make([]string, argc)
+	for i := int32(0); i < argc; i++ {
+		argslice[i] = gostringnocopy(argv_index(argv, i))
+	}
+}
+
+func goenvs_unix() {
+	// TODO(austin): ppc64 in dynamic linking mode doesn't
+	// guarantee env[] will immediately follow argv.  Might cause
+	// problems.
+	n := int32(0)
+	for argv_index(argv, argc+1+n) != nil {
+		n++
+	}
+
+	envs = make([]string, n)
+	for i := int32(0); i < n; i++ {
+		envs[i] = gostring(argv_index(argv, argc+1+i))
+	}
+}
+
+func environ() []string {
+	return envs
+}
+
+// TODO: These should be locals in testAtomic64, but we don't 8-byte
+// align stack variables on 386.
+var test_z64, test_x64 uint64
+
+func testAtomic64() {
+	test_z64 = 42
+	test_x64 = 0
+	prefetcht0(uintptr(unsafe.Pointer(&test_z64)))
+	prefetcht1(uintptr(unsafe.Pointer(&test_z64)))
+	prefetcht2(uintptr(unsafe.Pointer(&test_z64)))
+	prefetchnta(uintptr(unsafe.Pointer(&test_z64)))
+	if cas64(&test_z64, test_x64, 1) {
+		throw("cas64 failed")
+	}
+	if test_x64 != 0 {
+		throw("cas64 failed")
+	}
+	test_x64 = 42
+	if !cas64(&test_z64, test_x64, 1) {
+		throw("cas64 failed")
+	}
+	if test_x64 != 42 || test_z64 != 1 {
+		throw("cas64 failed")
+	}
+	if atomicload64(&test_z64) != 1 {
+		throw("load64 failed")
+	}
+	atomicstore64(&test_z64, (1<<40)+1)
+	if atomicload64(&test_z64) != (1<<40)+1 {
+		throw("store64 failed")
+	}
+	if xadd64(&test_z64, (1<<40)+1) != (2<<40)+2 {
+		throw("xadd64 failed")
+	}
+	if atomicload64(&test_z64) != (2<<40)+2 {
+		throw("xadd64 failed")
+	}
+	if xchg64(&test_z64, (3<<40)+3) != (2<<40)+2 {
+		throw("xchg64 failed")
+	}
+	if atomicload64(&test_z64) != (3<<40)+3 {
+		throw("xchg64 failed")
+	}
+}
+
+func check() {
+	var (
+		a     int8
+		b     uint8
+		c     int16
+		d     uint16
+		e     int32
+		f     uint32
+		g     int64
+		h     uint64
+		i, i1 float32
+		j, j1 float64
+		k, k1 unsafe.Pointer
+		l     *uint16
+		m     [4]byte
+	)
+	type x1t struct {
+		x uint8
+	}
+	type y1t struct {
+		x1 x1t
+		y  uint8
+	}
+	var x1 x1t
+	var y1 y1t
+
+	if unsafe.Sizeof(a) != 1 {
+		throw("bad a")
+	}
+	if unsafe.Sizeof(b) != 1 {
+		throw("bad b")
+	}
+	if unsafe.Sizeof(c) != 2 {
+		throw("bad c")
+	}
+	if unsafe.Sizeof(d) != 2 {
+		throw("bad d")
+	}
+	if unsafe.Sizeof(e) != 4 {
+		throw("bad e")
+	}
+	if unsafe.Sizeof(f) != 4 {
+		throw("bad f")
+	}
+	if unsafe.Sizeof(g) != 8 {
+		throw("bad g")
+	}
+	if unsafe.Sizeof(h) != 8 {
+		throw("bad h")
+	}
+	if unsafe.Sizeof(i) != 4 {
+		throw("bad i")
+	}
+	if unsafe.Sizeof(j) != 8 {
+		throw("bad j")
+	}
+	if unsafe.Sizeof(k) != ptrSize {
+		throw("bad k")
+	}
+	if unsafe.Sizeof(l) != ptrSize {
+		throw("bad l")
+	}
+	if unsafe.Sizeof(x1) != 1 {
+		throw("bad unsafe.Sizeof x1")
+	}
+	if unsafe.Offsetof(y1.y) != 1 {
+		throw("bad offsetof y1.y")
+	}
+	if unsafe.Sizeof(y1) != 2 {
+		throw("bad unsafe.Sizeof y1")
+	}
+
+	if timediv(12345*1000000000+54321, 1000000000, &e) != 12345 || e != 54321 {
+		throw("bad timediv")
+	}
+
+	var z uint32
+	z = 1
+	if !cas(&z, 1, 2) {
+		throw("cas1")
+	}
+	if z != 2 {
+		throw("cas2")
+	}
+
+	z = 4
+	if cas(&z, 5, 6) {
+		throw("cas3")
+	}
+	if z != 4 {
+		throw("cas4")
+	}
+
+	z = 0xffffffff
+	if !cas(&z, 0xffffffff, 0xfffffffe) {
+		throw("cas5")
+	}
+	if z != 0xfffffffe {
+		throw("cas6")
+	}
+
+	k = unsafe.Pointer(uintptr(0xfedcb123))
+	if ptrSize == 8 {
+		k = unsafe.Pointer(uintptr(unsafe.Pointer(k)) << 10)
+	}
+	if casp(&k, nil, nil) {
+		throw("casp1")
+	}
+	k1 = add(k, 1)
+	if !casp(&k, k, k1) {
+		throw("casp2")
+	}
+	if k != k1 {
+		throw("casp3")
+	}
+
+	m = [4]byte{1, 1, 1, 1}
+	atomicor8(&m[1], 0xf0)
+	if m[0] != 1 || m[1] != 0xf1 || m[2] != 1 || m[3] != 1 {
+		throw("atomicor8")
+	}
+
+	*(*uint64)(unsafe.Pointer(&j)) = ^uint64(0)
+	if j == j {
+		throw("float64nan")
+	}
+	if !(j != j) {
+		throw("float64nan1")
+	}
+
+	*(*uint64)(unsafe.Pointer(&j1)) = ^uint64(1)
+	if j == j1 {
+		throw("float64nan2")
+	}
+	if !(j != j1) {
+		throw("float64nan3")
+	}
+
+	*(*uint32)(unsafe.Pointer(&i)) = ^uint32(0)
+	if i == i {
+		throw("float32nan")
+	}
+	if i == i {
+		throw("float32nan1")
+	}
+
+	*(*uint32)(unsafe.Pointer(&i1)) = ^uint32(1)
+	if i == i1 {
+		throw("float32nan2")
+	}
+	if i == i1 {
+		throw("float32nan3")
+	}
+
+	testAtomic64()
+
+	if _FixedStack != round2(_FixedStack) {
+		throw("FixedStack is not power-of-2")
+	}
+}
+
+type dbgVar struct {
+	name  string
+	value *int32
+}
+
+// Holds variables parsed from GODEBUG env var,
+// except for "memprofilerate" since there is an
+// existing int var for that value, which may
+// already have an initial value.
+var debug struct {
+	allocfreetrace    int32
+	efence            int32
+	gccheckmark       int32
+	gcpacertrace      int32
+	gcshrinkstackoff  int32
+	gcstackbarrieroff int32
+	gcstackbarrierall int32
+	gcstoptheworld    int32
+	gctrace           int32
+	invalidptr        int32
+	sbrk              int32
+	scavenge          int32
+	scheddetail       int32
+	schedtrace        int32
+	wbshadow          int32
+}
+
+var dbgvars = []dbgVar{
+	{"allocfreetrace", &debug.allocfreetrace},
+	{"efence", &debug.efence},
+	{"gccheckmark", &debug.gccheckmark},
+	{"gcpacertrace", &debug.gcpacertrace},
+	{"gcshrinkstackoff", &debug.gcshrinkstackoff},
+	{"gcstackbarrieroff", &debug.gcstackbarrieroff},
+	{"gcstackbarrierall", &debug.gcstackbarrierall},
+	{"gcstoptheworld", &debug.gcstoptheworld},
+	{"gctrace", &debug.gctrace},
+	{"invalidptr", &debug.invalidptr},
+	{"sbrk", &debug.sbrk},
+	{"scavenge", &debug.scavenge},
+	{"scheddetail", &debug.scheddetail},
+	{"schedtrace", &debug.schedtrace},
+	{"wbshadow", &debug.wbshadow},
+}
+
+func parsedebugvars() {
+	// defaults
+	debug.invalidptr = 1
+
+	for p := gogetenv("GODEBUG"); p != ""; {
+		field := ""
+		i := index(p, ",")
+		if i < 0 {
+			field, p = p, ""
+		} else {
+			field, p = p[:i], p[i+1:]
+		}
+		i = index(field, "=")
+		if i < 0 {
+			continue
+		}
+		key, value := field[:i], field[i+1:]
+
+		// Update MemProfileRate directly here since it
+		// is int, not int32, and should only be updated
+		// if specified in GODEBUG.
+		if key == "memprofilerate" {
+			MemProfileRate = atoi(value)
+		} else {
+			for _, v := range dbgvars {
+				if v.name == key {
+					*v.value = int32(atoi(value))
+				}
+			}
+		}
+	}
+
+	switch p := gogetenv("GOTRACEBACK"); p {
+	case "":
+		traceback_cache = 1 << 1
+	case "crash":
+		traceback_cache = 2<<1 | 1
+	default:
+		traceback_cache = uint32(atoi(p)) << 1
+	}
+	// when C owns the process, simply exit'ing the process on fatal errors
+	// and panics is surprising. Be louder and abort instead.
+	if islibrary || isarchive {
+		traceback_cache |= 1
+	}
+
+	if debug.gcstackbarrierall > 0 {
+		firstStackBarrierOffset = 0
+	}
+}
+
+// Poor mans 64-bit division.
+// This is a very special function, do not use it if you are not sure what you are doing.
+// int64 division is lowered into _divv() call on 386, which does not fit into nosplit functions.
+// Handles overflow in a time-specific manner.
+//go:nosplit
+func timediv(v int64, div int32, rem *int32) int32 {
+	res := int32(0)
+	for bit := 30; bit >= 0; bit-- {
+		if v >= int64(div)<<uint(bit) {
+			v = v - (int64(div) << uint(bit))
+			res += 1 << uint(bit)
+		}
+	}
+	if v >= int64(div) {
+		if rem != nil {
+			*rem = 0
+		}
+		return 0x7fffffff
+	}
+	if rem != nil {
+		*rem = int32(v)
+	}
+	return res
+}
+
+// Helpers for Go. Must be NOSPLIT, must only call NOSPLIT functions, and must not block.
+
+//go:nosplit
+func acquirem() *m {
+	_g_ := getg()
+	_g_.m.locks++
+	return _g_.m
+}
+
+//go:nosplit
+func releasem(mp *m) {
+	_g_ := getg()
+	mp.locks--
+	if mp.locks == 0 && _g_.preempt {
+		// restore the preemption request in case we've cleared it in newstack
+		_g_.stackguard0 = stackPreempt
+	}
+}
+
+//go:nosplit
+func gomcache() *mcache {
+	return getg().m.mcache
+}
+
+//go:linkname reflect_typelinks reflect.typelinks
+//go:nosplit
+func reflect_typelinks() [][]*_type {
+	ret := [][]*_type{firstmoduledata.typelinks}
+	for datap := firstmoduledata.next; datap != nil; datap = datap.next {
+		ret = append(ret, datap.typelinks)
+	}
+	return ret
+}
diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go
new file mode 100644
index 0000000..57cd869
--- /dev/null
+++ b/src/runtime/runtime2.go
@@ -0,0 +1,699 @@
+// 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"
+
+/*
+ * defined constants
+ */
+const (
+	// G status
+	//
+	// If you add to this list, add to the list
+	// of "okay during garbage collection" status
+	// in mgcmark.go too.
+	_Gidle            = iota // 0
+	_Grunnable               // 1 runnable and on a run queue
+	_Grunning                // 2
+	_Gsyscall                // 3
+	_Gwaiting                // 4
+	_Gmoribund_unused        // 5 currently unused, but hardcoded in gdb scripts
+	_Gdead                   // 6
+	_Genqueue                // 7 Only the Gscanenqueue is used.
+	_Gcopystack              // 8 in this state when newstack is moving the stack
+	// the following encode that the GC is scanning the stack and what to do when it is done
+	_Gscan = 0x1000 // atomicstatus&~Gscan = the non-scan state,
+	// _Gscanidle =     _Gscan + _Gidle,      // Not used. Gidle only used with newly malloced gs
+	_Gscanrunnable = _Gscan + _Grunnable //  0x1001 When scanning completes make Grunnable (it is already on run queue)
+	_Gscanrunning  = _Gscan + _Grunning  //  0x1002 Used to tell preemption newstack routine to scan preempted stack.
+	_Gscansyscall  = _Gscan + _Gsyscall  //  0x1003 When scanning completes make it Gsyscall
+	_Gscanwaiting  = _Gscan + _Gwaiting  //  0x1004 When scanning completes make it Gwaiting
+	// _Gscanmoribund_unused,               //  not possible
+	// _Gscandead,                          //  not possible
+	_Gscanenqueue = _Gscan + _Genqueue //  When scanning completes make it Grunnable and put on runqueue
+)
+
+const (
+	// P status
+	_Pidle    = iota
+	_Prunning // Only this P is allowed to change from _Prunning.
+	_Psyscall
+	_Pgcstop
+	_Pdead
+)
+
+// The next line makes 'go generate' write the zgen_*.go files with
+// per-OS and per-arch information, including constants
+// named goos_$GOOS and goarch_$GOARCH for every
+// known GOOS and GOARCH. The constant is 1 on the
+// current system, 0 otherwise; multiplying by them is
+// useful for defining GOOS- or GOARCH-specific constants.
+//go:generate go run gengoos.go
+
+type mutex struct {
+	// Futex-based impl treats it as uint32 key,
+	// while sema-based impl as M* waitm.
+	// Used to be a union, but unions break precise GC.
+	key uintptr
+}
+
+type note struct {
+	// Futex-based impl treats it as uint32 key,
+	// while sema-based impl as M* waitm.
+	// Used to be a union, but unions break precise GC.
+	key uintptr
+}
+
+type _string struct {
+	str *byte
+	len int
+}
+
+type funcval struct {
+	fn uintptr
+	// variable-size, fn-specific data here
+}
+
+type iface struct {
+	tab  *itab
+	data unsafe.Pointer
+}
+
+type eface struct {
+	_type *_type
+	data  unsafe.Pointer
+}
+
+// The guintptr, muintptr, and puintptr are all used to bypass write barriers.
+// It is particularly important to avoid write barriers when the current P has
+// been released, because the GC thinks the world is stopped, and an
+// unexpected write barrier would not be synchronized with the GC,
+// which can lead to a half-executed write barrier that has marked the object
+// but not queued it. If the GC skips the object and completes before the
+// queuing can occur, it will incorrectly free the object.
+//
+// We tried using special assignment functions invoked only when not
+// holding a running P, but then some updates to a particular memory
+// word went through write barriers and some did not. This breaks the
+// write barrier shadow checking mode, and it is also scary: better to have
+// a word that is completely ignored by the GC than to have one for which
+// only a few updates are ignored.
+//
+// Gs, Ms, and Ps are always reachable via true pointers in the
+// allgs, allm, and allp lists or (during allocation before they reach those lists)
+// from stack variables.
+
+// A guintptr holds a goroutine pointer, but typed as a uintptr
+// to bypass write barriers. It is used in the Gobuf goroutine state
+// and in scheduling lists that are manipulated without a P.
+//
+// The Gobuf.g goroutine pointer is almost always updated by assembly code.
+// In one of the few places it is updated by Go code - func save - it must be
+// treated as a uintptr to avoid a write barrier being emitted at a bad time.
+// Instead of figuring out how to emit the write barriers missing in the
+// assembly manipulation, we change the type of the field to uintptr,
+// so that it does not require write barriers at all.
+//
+// Goroutine structs are published in the allg list and never freed.
+// That will keep the goroutine structs from being collected.
+// There is never a time that Gobuf.g's contain the only references
+// to a goroutine: the publishing of the goroutine in allg comes first.
+// Goroutine pointers are also kept in non-GC-visible places like TLS,
+// so I can't see them ever moving. If we did want to start moving data
+// in the GC, we'd need to allocate the goroutine structs from an
+// alternate arena. Using guintptr doesn't make that problem any worse.
+type guintptr uintptr
+
+func (gp guintptr) ptr() *g   { return (*g)(unsafe.Pointer(gp)) }
+func (gp *guintptr) set(g *g) { *gp = guintptr(unsafe.Pointer(g)) }
+func (gp *guintptr) cas(old, new guintptr) bool {
+	return casuintptr((*uintptr)(unsafe.Pointer(gp)), uintptr(old), uintptr(new))
+}
+
+type puintptr uintptr
+
+func (pp puintptr) ptr() *p   { return (*p)(unsafe.Pointer(pp)) }
+func (pp *puintptr) set(p *p) { *pp = puintptr(unsafe.Pointer(p)) }
+
+type muintptr uintptr
+
+func (mp muintptr) ptr() *m   { return (*m)(unsafe.Pointer(mp)) }
+func (mp *muintptr) set(m *m) { *mp = muintptr(unsafe.Pointer(m)) }
+
+type gobuf struct {
+	// The offsets of sp, pc, and g are known to (hard-coded in) libmach.
+	sp   uintptr
+	pc   uintptr
+	g    guintptr
+	ctxt unsafe.Pointer // this has to be a pointer so that gc scans it
+	ret  uintreg
+	lr   uintptr
+	bp   uintptr // for GOEXPERIMENT=framepointer
+}
+
+// Known to compiler.
+// Changes here must also be made in src/cmd/internal/gc/select.go's selecttype.
+type sudog struct {
+	g           *g
+	selectdone  *uint32
+	next        *sudog
+	prev        *sudog
+	elem        unsafe.Pointer // data element
+	releasetime int64
+	nrelease    int32  // -1 for acquire
+	waitlink    *sudog // g.waiting list
+}
+
+type gcstats struct {
+	// the struct must consist of only uint64's,
+	// because it is casted to uint64[].
+	nhandoff    uint64
+	nhandoffcnt uint64
+	nprocyield  uint64
+	nosyield    uint64
+	nsleep      uint64
+}
+
+type libcall struct {
+	fn   uintptr
+	n    uintptr // number of parameters
+	args uintptr // parameters
+	r1   uintptr // return values
+	r2   uintptr
+	err  uintptr // error number
+}
+
+// describes how to handle callback
+type wincallbackcontext struct {
+	gobody       unsafe.Pointer // go function to call
+	argsize      uintptr        // callback arguments size (in bytes)
+	restorestack uintptr        // adjust stack on return by (in bytes) (386 only)
+	cleanstack   bool
+}
+
+// Stack describes a Go execution stack.
+// The bounds of the stack are exactly [lo, hi),
+// with no implicit data structures on either side.
+type stack struct {
+	lo uintptr
+	hi uintptr
+}
+
+// stkbar records the state of a G's stack barrier.
+type stkbar struct {
+	savedLRPtr uintptr // location overwritten by stack barrier PC
+	savedLRVal uintptr // value overwritten at savedLRPtr
+}
+
+type g struct {
+	// Stack parameters.
+	// stack describes the actual stack memory: [stack.lo, stack.hi).
+	// stackguard0 is the stack pointer compared in the Go stack growth prologue.
+	// It is stack.lo+StackGuard normally, but can be StackPreempt to trigger a preemption.
+	// stackguard1 is the stack pointer compared in the C stack growth prologue.
+	// It is stack.lo+StackGuard on g0 and gsignal stacks.
+	// It is ~0 on other goroutine stacks, to trigger a call to morestackc (and crash).
+	stack       stack   // offset known to runtime/cgo
+	stackguard0 uintptr // offset known to liblink
+	stackguard1 uintptr // offset known to liblink
+
+	_panic         *_panic // innermost panic - offset known to liblink
+	_defer         *_defer // innermost defer
+	m              *m      // current m; offset known to arm liblink
+	stackAlloc     uintptr // stack allocation is [stack.lo,stack.lo+stackAlloc)
+	sched          gobuf
+	syscallsp      uintptr        // if status==Gsyscall, syscallsp = sched.sp to use during gc
+	syscallpc      uintptr        // if status==Gsyscall, syscallpc = sched.pc to use during gc
+	stkbar         []stkbar       // stack barriers, from low to high
+	stkbarPos      uintptr        // index of lowest stack barrier not hit
+	param          unsafe.Pointer // passed parameter on wakeup
+	atomicstatus   uint32
+	stackLock      uint32 // sigprof/scang lock; TODO: fold in to atomicstatus
+	goid           int64
+	waitsince      int64  // approx time when the g become blocked
+	waitreason     string // if status==Gwaiting
+	schedlink      guintptr
+	preempt        bool   // preemption signal, duplicates stackguard0 = stackpreempt
+	paniconfault   bool   // panic (instead of crash) on unexpected fault address
+	preemptscan    bool   // preempted g does scan for gc
+	gcscandone     bool   // g has scanned stack; protected by _Gscan bit in status
+	gcscanvalid    bool   // false at start of gc cycle, true if G has not run since last scan
+	throwsplit     bool   // must not split stack
+	raceignore     int8   // ignore race detection events
+	sysblocktraced bool   // StartTrace has emitted EvGoInSyscall about this goroutine
+	sysexitticks   int64  // cputicks when syscall has returned (for tracing)
+	sysexitseq     uint64 // trace seq when syscall has returned (for tracing)
+	lockedm        *m
+	sig            uint32
+	writebuf       []byte
+	sigcode0       uintptr
+	sigcode1       uintptr
+	sigpc          uintptr
+	gopc           uintptr // pc of go statement that created this goroutine
+	startpc        uintptr // pc of goroutine function
+	racectx        uintptr
+	waiting        *sudog // sudog structures this g is waiting on (that have a valid elem ptr)
+	readyg         *g     // scratch for readyExecute
+
+	// Per-G gcController state
+	gcalloc    uintptr // bytes allocated during this GC cycle
+	gcscanwork int64   // scan work done (or stolen) this GC cycle
+}
+
+type mts struct {
+	tv_sec  int64
+	tv_nsec int64
+}
+
+type mscratch struct {
+	v [6]uintptr
+}
+
+type m struct {
+	g0      *g     // goroutine with scheduling stack
+	morebuf gobuf  // gobuf arg to morestack
+	divmod  uint32 // div/mod denominator for arm - known to liblink
+
+	// Fields not known to debuggers.
+	procid        uint64     // for debuggers, but offset not hard-coded
+	gsignal       *g         // signal-handling g
+	sigmask       [4]uintptr // storage for saved signal mask
+	tls           [4]uintptr // thread-local storage (for x86 extern register)
+	mstartfn      func()
+	curg          *g       // current running goroutine
+	caughtsig     guintptr // goroutine running during fatal signal
+	p             puintptr // attached p for executing go code (nil if not executing go code)
+	nextp         puintptr
+	id            int32
+	mallocing     int32
+	throwing      int32
+	preemptoff    string // if != "", keep curg running on this m
+	locks         int32
+	softfloat     int32
+	dying         int32
+	profilehz     int32
+	helpgc        int32
+	spinning      bool // m is out of work and is actively looking for work
+	blocked       bool // m is blocked on a note
+	inwb          bool // m is executing a write barrier
+	printlock     int8
+	fastrand      uint32
+	ncgocall      uint64 // number of cgo calls in total
+	ncgo          int32  // number of cgo calls currently in progress
+	park          note
+	alllink       *m // on allm
+	schedlink     muintptr
+	machport      uint32 // return address for mach ipc (os x)
+	mcache        *mcache
+	lockedg       *g
+	createstack   [32]uintptr // stack that created this thread.
+	freglo        [16]uint32  // d[i] lsb and f[i]
+	freghi        [16]uint32  // d[i] msb and f[i+16]
+	fflag         uint32      // floating point compare flags
+	locked        uint32      // tracking for lockosthread
+	nextwaitm     uintptr     // next m waiting for lock
+	waitsema      uintptr     // semaphore for parking on locks
+	waitsemacount uint32
+	waitsemalock  uint32
+	gcstats       gcstats
+	needextram    bool
+	traceback     uint8
+	waitunlockf   unsafe.Pointer // todo go func(*g, unsafe.pointer) bool
+	waitlock      unsafe.Pointer
+	waittraceev   byte
+	waittraceskip int
+	startingtrace bool
+	syscalltick   uint32
+	//#ifdef GOOS_windows
+	thread uintptr // thread handle
+	// these are here because they are too large to be on the stack
+	// of low-level NOSPLIT functions.
+	libcall   libcall
+	libcallpc uintptr // for cpu profiler
+	libcallsp uintptr
+	libcallg  guintptr
+	syscall   libcall // stores syscall parameters on windows
+	//#endif
+	//#ifdef GOOS_solaris
+	perrno *int32 // pointer to tls errno
+	// these are here because they are too large to be on the stack
+	// of low-level NOSPLIT functions.
+	//LibCall	libcall;
+	ts      mts
+	scratch mscratch
+	//#endif
+	//#ifdef GOOS_plan9
+	notesig *int8
+	errstr  *byte
+	//#endif
+}
+
+type p struct {
+	lock mutex
+
+	id          int32
+	status      uint32 // one of pidle/prunning/...
+	link        puintptr
+	schedtick   uint32   // incremented on every scheduler call
+	syscalltick uint32   // incremented on every system call
+	m           muintptr // back-link to associated m (nil if idle)
+	mcache      *mcache
+
+	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
+	goidcacheend uint64
+
+	// Queue of runnable goroutines. Accessed without lock.
+	runqhead uint32
+	runqtail uint32
+	runq     [256]*g
+	// runnext, if non-nil, is a runnable G that was ready'd by
+	// the current G and should be run next instead of what's in
+	// runq if there's time remaining in the running G's time
+	// slice. It will inherit the time left in the current time
+	// slice. If a set of goroutines is locked in a
+	// communicate-and-wait pattern, this schedules that set as a
+	// unit and eliminates the (potentially large) scheduling
+	// latency that otherwise arises from adding the ready'd
+	// goroutines to the end of the run queue.
+	runnext guintptr
+
+	// Available G's (status == Gdead)
+	gfree    *g
+	gfreecnt int32
+
+	sudogcache []*sudog
+	sudogbuf   [128]*sudog
+
+	tracebuf *traceBuf
+
+	palloc persistentAlloc // per-P to avoid mutex
+
+	// Per-P GC state
+	gcAssistTime     int64 // Nanoseconds in assistAlloc
+	gcBgMarkWorker   *g
+	gcMarkWorkerMode gcMarkWorkerMode
+
+	// gcw is this P's GC work buffer cache. The work buffer is
+	// filled by write barriers, drained by mutator assists, and
+	// disposed on certain GC state transitions.
+	gcw gcWork
+
+	runSafePointFn uint32 // if 1, run sched.safePointFn at next safe point
+
+	pad [64]byte
+}
+
+const (
+	// The max value of GOMAXPROCS.
+	// There are no fundamental restrictions on the value.
+	_MaxGomaxprocs = 1 << 8
+)
+
+type schedt struct {
+	lock mutex
+
+	goidgen uint64
+
+	midle        muintptr // idle m's waiting for work
+	nmidle       int32    // number of idle m's waiting for work
+	nmidlelocked int32    // number of locked m's waiting for work
+	mcount       int32    // number of m's that have been created
+	maxmcount    int32    // maximum number of m's allowed (or die)
+
+	pidle      puintptr // idle p's
+	npidle     uint32
+	nmspinning uint32
+
+	// Global runnable queue.
+	runqhead guintptr
+	runqtail guintptr
+	runqsize int32
+
+	// Global cache of dead G's.
+	gflock mutex
+	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
+	sysmonwait uint32
+	sysmonnote note
+	lastpoll   uint64
+
+	// safepointFn should be called on each P at the next GC
+	// safepoint if p.runSafePointFn is set.
+	safePointFn   func(*p)
+	safePointWait int32
+	safePointNote note
+
+	profilehz int32 // cpu profiling rate
+
+	procresizetime int64 // nanotime() of last change to gomaxprocs
+	totaltime      int64 // ∫gomaxprocs dt up to procresizetime
+}
+
+// The m->locked word holds two pieces of state counting active calls to LockOSThread/lockOSThread.
+// The low bit (LockExternal) is a boolean reporting whether any LockOSThread call is active.
+// External locks are not recursive; a second lock is silently ignored.
+// The upper bits of m->locked record the nesting depth of calls to lockOSThread
+// (counting up by LockInternal), popped by unlockOSThread (counting down by LockInternal).
+// Internal locks can be recursive. For instance, a lock for cgo can occur while the main
+// goroutine is holding the lock during the initialization phase.
+const (
+	_LockExternal = 1
+	_LockInternal = 2
+)
+
+type sigtabtt struct {
+	flags int32
+	name  *int8
+}
+
+const (
+	_SigNotify   = 1 << iota // let signal.Notify have signal, even if from kernel
+	_SigKill                 // if signal.Notify doesn't take it, exit quietly
+	_SigThrow                // if signal.Notify doesn't take it, exit loudly
+	_SigPanic                // if the signal is from the kernel, panic
+	_SigDefault              // if the signal isn't explicitly requested, don't monitor it
+	_SigHandling             // our signal handler is registered
+	_SigIgnored              // the signal was ignored before we registered for it
+	_SigGoExit               // cause all runtime procs to exit (only used on Plan 9).
+	_SigSetStack             // add SA_ONSTACK to libc handler
+	_SigUnblock              // unblocked in minit
+)
+
+// Layout of in-memory per-function information prepared by linker
+// See https://golang.org/s/go12symtab.
+// Keep in sync with linker
+// and with package debug/gosym and with symtab.go in package runtime.
+type _func struct {
+	entry   uintptr // start pc
+	nameoff int32   // function name
+
+	args  int32 // in/out args size
+	frame int32 // legacy frame size; use pcsp if possible
+
+	pcsp      int32
+	pcfile    int32
+	pcln      int32
+	npcdata   int32
+	nfuncdata int32
+}
+
+// layout of Itab known to compilers
+// allocated in non-garbage-collected memory
+type itab struct {
+	inter  *interfacetype
+	_type  *_type
+	link   *itab
+	bad    int32
+	unused int32
+	fun    [1]uintptr // variable sized
+}
+
+// Lock-free stack node.
+// // Also known to export_test.go.
+type lfnode struct {
+	next    uint64
+	pushcnt uintptr
+}
+
+type forcegcstate struct {
+	lock mutex
+	g    *g
+	idle uint32
+}
+
+/*
+ * known to compiler
+ */
+const (
+	_Structrnd = regSize
+)
+
+// startup_random_data holds random bytes initialized at startup.  These come from
+// the ELF AT_RANDOM auxiliary vector (vdso_linux_amd64.go or os_linux_386.go).
+var startupRandomData []byte
+
+// extendRandom extends the random numbers in r[:n] to the whole slice r.
+// Treats n<0 as n==0.
+func extendRandom(r []byte, n int) {
+	if n < 0 {
+		n = 0
+	}
+	for n < len(r) {
+		// Extend random bits using hash function & time seed
+		w := n
+		if w > 16 {
+			w = 16
+		}
+		h := memhash(unsafe.Pointer(&r[n-w]), uintptr(nanotime()), uintptr(w))
+		for i := 0; i < ptrSize && n < len(r); i++ {
+			r[n] = byte(h)
+			n++
+			h >>= 8
+		}
+	}
+}
+
+/*
+ * deferred subroutine calls
+ */
+type _defer struct {
+	siz     int32
+	started bool
+	sp      uintptr // sp at time of defer
+	pc      uintptr
+	fn      *funcval
+	_panic  *_panic // panic that is running defer
+	link    *_defer
+}
+
+/*
+ * panics
+ */
+type _panic struct {
+	argp      unsafe.Pointer // pointer to arguments of deferred call run during panic; cannot move - known to liblink
+	arg       interface{}    // argument to panic
+	link      *_panic        // link to earlier panic
+	recovered bool           // whether this panic is over
+	aborted   bool           // the panic was aborted
+}
+
+/*
+ * stack traces
+ */
+
+type stkframe struct {
+	fn       *_func     // function being run
+	pc       uintptr    // program counter within fn
+	continpc uintptr    // program counter where execution can continue, or 0 if not
+	lr       uintptr    // program counter at caller aka link register
+	sp       uintptr    // stack pointer at pc
+	fp       uintptr    // stack pointer at caller aka frame pointer
+	varp     uintptr    // top of local variables
+	argp     uintptr    // pointer to function arguments
+	arglen   uintptr    // number of bytes at argp
+	argmap   *bitvector // force use of this argmap
+}
+
+const (
+	_TraceRuntimeFrames = 1 << iota // include frames for internal runtime functions.
+	_TraceTrap                      // the initial PC, SP are from a trap, not a return PC from a call
+	_TraceJumpStack                 // if traceback is on a systemstack, resume trace at g that called into it
+)
+
+const (
+	// The maximum number of frames we print for a traceback
+	_TracebackMaxFrames = 100
+)
+
+var (
+	emptystring string
+	allg        **g
+	allglen     uintptr
+	lastg       *g
+	allm        *m
+	allp        [_MaxGomaxprocs + 1]*p
+	gomaxprocs  int32
+	panicking   uint32
+	goos        *int8
+	ncpu        int32
+	signote     note
+	forcegc     forcegcstate
+	sched       schedt
+	newprocs    int32
+
+	// Information about what cpu features are available.
+	// Set on startup in asm_{x86,amd64}.s.
+	cpuid_ecx         uint32
+	cpuid_edx         uint32
+	lfenceBeforeRdtsc bool
+
+	goarm uint8 // set by cmd/link on arm systems
+)
+
+// Set by the linker so the runtime can determine the buildmode.
+var (
+	islibrary bool // -buildmode=c-shared
+	isarchive bool // -buildmode=c-archive
+)
+
+/*
+ * mutual exclusion locks.  in the uncontended case,
+ * as fast as spin locks (just a few user-level instructions),
+ * but on the contention path they sleep in the kernel.
+ * a zeroed Mutex is unlocked (no need to initialize each lock).
+ */
+
+/*
+ * sleep and wakeup on one-time events.
+ * before any calls to notesleep or notewakeup,
+ * must call noteclear to initialize the Note.
+ * then, exactly one thread can call notesleep
+ * and exactly one thread can call notewakeup (once).
+ * once notewakeup has been called, the notesleep
+ * will return.  future notesleep will return immediately.
+ * subsequent noteclear must be called only after
+ * previous notesleep has returned, e.g. it's disallowed
+ * to call noteclear straight after notewakeup.
+ *
+ * notetsleep is like notesleep but wakes up after
+ * a given number of nanoseconds even if the event
+ * has not yet happened.  if a goroutine uses notetsleep to
+ * wake up early, it must wait to call noteclear until it
+ * can be sure that no other goroutine is calling
+ * notewakeup.
+ *
+ * notesleep/notetsleep are generally called on g0,
+ * notetsleepg is similar to notetsleep but is called on user g.
+ */
+// bool	runtime·notetsleep(Note*, int64);  // false - timeout
+// bool	runtime·notetsleepg(Note*, int64);  // false - timeout
+
+/*
+ * Lock-free stack.
+ * Initialize uint64 head to 0, compare with 0 to test for emptiness.
+ * The stack does not keep pointers to nodes,
+ * so they can be garbage collected if there are no other pointers to nodes.
+ */
+
+// for mmap, we only pass the lower 32 bits of file offset to the
+// assembly routine; the higher bits (if required), should be provided
+// by the assembly routine as 0.
diff --git a/src/runtime/runtime_test.go b/src/runtime/runtime_test.go
index 1688364..75fc9bc 100644
--- a/src/runtime/runtime_test.go
+++ b/src/runtime/runtime_test.go
@@ -6,13 +6,8 @@ package runtime_test
 
 import (
 	"io"
-	"io/ioutil"
-	"os"
-	"os/exec"
 	. "runtime"
 	"runtime/debug"
-	"strconv"
-	"strings"
 	"testing"
 	"unsafe"
 )
@@ -88,48 +83,6 @@ func BenchmarkDeferMany(b *testing.B) {
 	}
 }
 
-// The profiling signal handler needs to know whether it is executing runtime.gogo.
-// The constant RuntimeGogoBytes in arch_*.h gives the size of the function;
-// we don't have a way to obtain it from the linker (perhaps someday).
-// Test that the constant matches the size determined by 'go tool nm -S'.
-// The value reported will include the padding between runtime.gogo and the
-// next function in memory. That's fine.
-func TestRuntimeGogoBytes(t *testing.T) {
-	switch GOOS {
-	case "android", "nacl":
-		t.Skipf("skipping on %s", GOOS)
-	}
-
-	dir, err := ioutil.TempDir("", "go-build")
-	if err != nil {
-		t.Fatalf("failed to create temp directory: %v", err)
-	}
-	defer os.RemoveAll(dir)
-
-	out, err := exec.Command("go", "build", "-o", dir+"/hello", "../../test/helloworld.go").CombinedOutput()
-	if err != nil {
-		t.Fatalf("building hello world: %v\n%s", err, out)
-	}
-
-	out, err = exec.Command("go", "tool", "nm", "-size", dir+"/hello").CombinedOutput()
-	if err != nil {
-		t.Fatalf("go tool nm: %v\n%s", err, out)
-	}
-
-	for _, line := range strings.Split(string(out), "\n") {
-		f := strings.Fields(line)
-		if len(f) == 4 && f[3] == "runtime.gogo" {
-			size, _ := strconv.Atoi(f[1])
-			if GogoBytes() != int32(size) {
-				t.Fatalf("RuntimeGogoBytes = %d, should be %d", GogoBytes(), size)
-			}
-			return
-		}
-	}
-
-	t.Fatalf("go tool nm did not report size for runtime.gogo")
-}
-
 // golang.org/issue/7063
 func TestStopCPUProfilingWithProfilerOff(t *testing.T) {
 	SetCPUProfileRate(0)
@@ -173,12 +126,6 @@ var faultAddrs = []uint64{
 }
 
 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)
 
@@ -247,3 +194,110 @@ func TestEqString(t *testing.T) {
 		}
 	}
 }
+
+func TestTrailingZero(t *testing.T) {
+	// make sure we add padding for structs with trailing zero-sized fields
+	type T1 struct {
+		n int32
+		z [0]byte
+	}
+	if unsafe.Sizeof(T1{}) != 8 {
+		t.Errorf("sizeof(%#v)==%d, want 8", T1{}, unsafe.Sizeof(T1{}))
+	}
+	type T2 struct {
+		n int64
+		z struct{}
+	}
+	if unsafe.Sizeof(T2{}) != 8+unsafe.Sizeof(Uintreg(0)) {
+		t.Errorf("sizeof(%#v)==%d, want %d", T2{}, unsafe.Sizeof(T2{}), 8+unsafe.Sizeof(Uintreg(0)))
+	}
+	type T3 struct {
+		n byte
+		z [4]struct{}
+	}
+	if unsafe.Sizeof(T3{}) != 2 {
+		t.Errorf("sizeof(%#v)==%d, want 2", T3{}, unsafe.Sizeof(T3{}))
+	}
+	// make sure padding can double for both zerosize and alignment
+	type T4 struct {
+		a int32
+		b int16
+		c int8
+		z struct{}
+	}
+	if unsafe.Sizeof(T4{}) != 8 {
+		t.Errorf("sizeof(%#v)==%d, want 8", T4{}, unsafe.Sizeof(T4{}))
+	}
+	// make sure we don't pad a zero-sized thing
+	type T5 struct {
+	}
+	if unsafe.Sizeof(T5{}) != 0 {
+		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)
+	}
+}
+
+func TestAppendGrowth(t *testing.T) {
+	var x []int64
+	check := func(want int) {
+		if cap(x) != want {
+			t.Errorf("len=%d, cap=%d, want cap=%d", len(x), cap(x), want)
+		}
+	}
+
+	check(0)
+	want := 1
+	for i := 1; i <= 100; i++ {
+		x = append(x, 1)
+		check(want)
+		if i&(i-1) == 0 {
+			want = 2 * i
+		}
+	}
+}
+
+var One = []int64{1}
+
+func TestAppendSliceGrowth(t *testing.T) {
+	var x []int64
+	check := func(want int) {
+		if cap(x) != want {
+			t.Errorf("len=%d, cap=%d, want cap=%d", len(x), cap(x), want)
+		}
+	}
+
+	check(0)
+	want := 1
+	for i := 1; i <= 100; i++ {
+		x = append(x, One...)
+		check(want)
+		if i&(i-1) == 0 {
+			want = 2 * i
+		}
+	}
+}
diff --git a/src/runtime/runtime_unix_test.go b/src/runtime/runtime_unix_test.go
index 963de8c..cfec332 100644
--- a/src/runtime/runtime_unix_test.go
+++ b/src/runtime/runtime_unix_test.go
@@ -42,7 +42,7 @@ func TestGoroutineProfile(t *testing.T) {
 	if testing.Short() {
 		max = 100
 	}
-	stk := make([]runtime.StackRecord, 100)
+	stk := make([]runtime.StackRecord, 128)
 	for n := 0; n < max; n++ {
 		_, ok := runtime.GoroutineProfile(stk)
 		if !ok {
diff --git a/src/runtime/select.go b/src/runtime/select.go
index f735a71..b18b44c 100644
--- a/src/runtime/select.go
+++ b/src/runtime/select.go
@@ -10,30 +10,59 @@ import "unsafe"
 
 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")
-		gothrow("bad select size")
+		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 @@ func newselect(sel *_select, selsize int64, size int32) {
 }
 
 //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,27 +79,27 @@ func selectsend(sel *_select, c *hchan, elem unsafe.Pointer) (selected bool) {
 }
 
 // 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 {
-		gothrow("selectsend: too many cases")
+		throw("selectsend: too many cases")
 	}
 	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 = _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 @@ func selectrecv(sel *_select, c *hchan, elem unsafe.Pointer) (selected bool) {
 }
 
 //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,50 +116,50 @@ func selectrecv2(sel *_select, c *hchan, elem unsafe.Pointer, received *bool) (s
 	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 {
-		gothrow("selectrecv: too many cases")
+		throw("selectrecv: too many cases")
 	}
 	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 {
-		gothrow("selectdefault: too many cases")
+		throw("selectdefault: too many cases")
 	}
 	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) {
-	lockslice := sliceStruct{unsafe.Pointer(sel.lockorder), int(sel.ncase), int(sel.ncase)}
+func sellock(sel *hselect) {
+	lockslice := slice{unsafe.Pointer(sel.lockorder), int(sel.ncase), int(sel.ncase)}
 	lockorder := *(*[]*hchan)(unsafe.Pointer(&lockslice))
 	var c *hchan
 	for _, c0 := range lockorder {
@@ -141,7 +170,7 @@ func sellock(sel *_select) {
 	}
 }
 
-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.
@@ -152,7 +181,7 @@ func selunlock(sel *_select) {
 	// Now if the first M touches sel, it will access freed memory.
 	n := int(sel.ncase)
 	r := 0
-	lockslice := sliceStruct{unsafe.Pointer(sel.lockorder), n, n}
+	lockslice := slice{unsafe.Pointer(sel.lockorder), n, n}
 	lockorder := *(*[]*hchan)(unsafe.Pointer(&lockslice))
 	// skip the default case
 	if n > 0 && lockorder[0] == nil {
@@ -167,19 +196,19 @@ func selunlock(sel *_select) {
 	}
 }
 
-func selparkcommit(gp *g, sel *_select) bool {
-	selunlock(sel)
+func selparkcommit(gp *g, sel unsafe.Pointer) bool {
+	selunlock((*hselect)(sel))
 	return true
 }
 
 func block() {
-	gopark(nil, nil, "select (no cases)") // 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,12 +216,12 @@ func selectgo(sel *_select) {
 
 // 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")
 	}
 
-	scaseslice := sliceStruct{unsafe.Pointer(&sel.scase), int(sel.ncase), int(sel.ncase)}
+	scaseslice := slice{unsafe.Pointer(&sel.scase), int(sel.ncase), int(sel.ncase)}
 	scases := *(*[]scase)(unsafe.Pointer(&scaseslice))
 
 	var t0 int64
@@ -212,25 +241,21 @@ func selectgoImpl(sel *_select) (uintptr, uint16) {
 	// optimizing (and needing to test).
 
 	// generate permuted order
-	pollslice := sliceStruct{unsafe.Pointer(sel.pollorder), int(sel.ncase), int(sel.ncase)}
+	pollslice := slice{unsafe.Pointer(sel.pollorder), int(sel.ncase), int(sel.ncase)}
 	pollorder := *(*[]uint16)(unsafe.Pointer(&pollslice))
-	for i := 0; i < int(sel.ncase); i++ {
-		pollorder[i] = uint16(i)
-	}
 	for i := 1; i < int(sel.ncase); i++ {
-		o := pollorder[i]
 		j := int(fastrand1()) % (i + 1)
 		pollorder[i] = pollorder[j]
-		pollorder[j] = o
+		pollorder[j] = uint16(i)
 	}
 
 	// sort the cases by Hchan address to get the locking order.
 	// simple heap sort, to guarantee n log n time and constant stack footprint.
-	lockslice := sliceStruct{unsafe.Pointer(sel.lockorder), int(sel.ncase), int(sel.ncase)}
+	lockslice := slice{unsafe.Pointer(sel.lockorder), int(sel.ncase), int(sel.ncase)}
 	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]
@@ -263,7 +288,7 @@ func selectgoImpl(sel *_select) (uintptr, uint16) {
 		for i := 0; i+1 < int(sel.ncase); i++ {
 			if lockorder[i].sortkey() > lockorder[i+1].sortkey() {
 				print("i=", i, " x=", lockorder[i], " y=", lockorder[i+1], "\n")
-				gothrow("select: broken sort")
+				throw("select: broken sort")
 			}
 		}
 	*/
@@ -279,6 +304,7 @@ func selectgoImpl(sel *_select) (uintptr, uint16) {
 		k      *scase
 		sglist *sudog
 		sgnext *sudog
+		futile byte
 	)
 
 loop:
@@ -287,10 +313,10 @@ loop:
 	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 +331,7 @@ loop:
 				goto rclose
 			}
 
-		case _CaseSend:
+		case caseSend:
 			if raceenabled {
 				racereadpc(unsafe.Pointer(c), cas.pc, chansendpc)
 			}
@@ -323,7 +349,7 @@ loop:
 				}
 			}
 
-		case _CaseDefault:
+		case caseDefault:
 			dfl = cas
 		}
 	}
@@ -339,10 +365,10 @@ loop:
 	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 +379,17 @@ loop:
 		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(unsafe.Pointer(funcPC(selparkcommit)), unsafe.Pointer(sel), "select")
+	gopark(selparkcommit, unsafe.Pointer(sel), "select", traceEvGoBlockSelect|futile, 2)
 
 	// someone woke us up
 	sellock(sel)
@@ -377,12 +403,7 @@ loop:
 	// iterating through the linked list they are in reverse order.
 	cas = nil
 	sglist = gp.waiting
-	// Clear all selectdone and elem before unlinking from gp.waiting.
-	// They must be cleared before being put back into the sudog cache.
-	// Clear before unlinking, because if a stack copy happens after the unlink,
-	// they will not be updated, they will be left pointing to the old stack,
-	// which creates dangling pointers, which may be detected by the
-	// garbage collector.
+	// Clear all elem before unlinking from gp.waiting.
 	for sg1 := gp.waiting; sg1 != nil; sg1 = sg1.waitlink {
 		sg1.selectdone = nil
 		sg1.elem = nil
@@ -394,10 +415,11 @@ loop:
 			k.releasetime = sglist.releasetime
 		}
 		if sg == sglist {
+			// 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)
@@ -410,29 +432,30 @@ loop:
 	}
 
 	if cas == nil {
+		futile = traceFutileWakeup
 		goto loop
 	}
 
-	c = cas._chan
+	c = cas.c
 
 	if c.dataqsiz > 0 {
-		gothrow("selectgo: shouldn't happen")
+		throw("selectgo: shouldn't happen")
 	}
 
 	if debugSelect {
 		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)
 		}
 	}
@@ -453,7 +476,7 @@ asyncrecv:
 		*cas.receivedp = true
 	}
 	if cas.elem != nil {
-		memmove(cas.elem, chanbuf(c, c.recvx), uintptr(c.elemsize))
+		typedmemmove(c.elemtype, cas.elem, chanbuf(c, c.recvx))
 	}
 	memclr(chanbuf(c, c.recvx), uintptr(c.elemsize))
 	c.recvx++
@@ -468,7 +491,7 @@ asyncrecv:
 		if sg.releasetime != 0 {
 			sg.releasetime = cputicks()
 		}
-		goready(gp)
+		goready(gp, 3)
 	} else {
 		selunlock(sel)
 	}
@@ -481,7 +504,7 @@ asyncsend:
 		racerelease(chanbuf(c, c.sendx))
 		raceReadObjectPC(c.elemtype, cas.elem, cas.pc, chansendpc)
 	}
-	memmove(chanbuf(c, c.sendx), cas.elem, uintptr(c.elemsize))
+	typedmemmove(c.elemtype, chanbuf(c, c.sendx), cas.elem)
 	c.sendx++
 	if c.sendx == c.dataqsiz {
 		c.sendx = 0
@@ -494,7 +517,7 @@ asyncsend:
 		if sg.releasetime != 0 {
 			sg.releasetime = cputicks()
 		}
-		goready(gp)
+		goready(gp, 3)
 	} else {
 		selunlock(sel)
 	}
@@ -516,7 +539,7 @@ syncrecv:
 		*cas.receivedp = true
 	}
 	if cas.elem != nil {
-		memmove(cas.elem, sg.elem, uintptr(c.elemsize))
+		typedmemmove(c.elemtype, cas.elem, sg.elem)
 	}
 	sg.elem = nil
 	gp = sg.g
@@ -524,7 +547,7 @@ syncrecv:
 	if sg.releasetime != 0 {
 		sg.releasetime = cputicks()
 	}
-	goready(gp)
+	goready(gp, 3)
 	goto retc
 
 rclose:
@@ -552,7 +575,7 @@ syncsend:
 		print("syncsend: sel=", sel, " c=", c, "\n")
 	}
 	if sg.elem != nil {
-		memmove(sg.elem, cas.elem, uintptr(c.elemsize))
+		syncsend(c, sg, cas.elem)
 	}
 	sg.elem = nil
 	gp = sg.g
@@ -560,7 +583,7 @@ syncsend:
 	if sg.releasetime != 0 {
 		sg.releasetime = cputicks()
 	}
-	goready(gp)
+	goready(gp, 3)
 
 retc:
 	if cas.releasetime > 0 {
@@ -599,10 +622,11 @@ const (
 	selectDefault           // default
 )
 
+//go:linkname reflect_rselect reflect.rselect
 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 {
@@ -629,23 +653,36 @@ func reflect_rselect(cases []runtimeSelect) (chosen int, recvOK bool) {
 	return
 }
 
-func (q *waitq) dequeueSudoG(s *sudog) {
-	var prevsgp *sudog
-	l := &q.first
-	for {
-		sgp := *l
-		if sgp == nil {
-			return
-		}
-		if sgp == s {
-			*l = sgp.next
-			if q.last == sgp {
-				q.last = prevsgp
-			}
-			s.next = nil
+func (q *waitq) dequeueSudoG(sgp *sudog) {
+	x := sgp.prev
+	y := sgp.next
+	if x != nil {
+		if y != nil {
+			// middle of queue
+			x.next = y
+			y.prev = x
+			sgp.next = nil
+			sgp.prev = nil
 			return
 		}
-		l = &sgp.next
-		prevsgp = sgp
+		// end of queue
+		x.next = nil
+		q.last = x
+		sgp.prev = nil
+		return
+	}
+	if y != nil {
+		// start of queue
+		y.prev = nil
+		q.first = y
+		sgp.next = nil
+		return
+	}
+
+	// x==y==nil.  Either sgp is the only element in the queue,
+	// or it has already been removed.  Use q.first to disambiguate.
+	if q.first == sgp {
+		q.first = nil
+		q.last = nil
 	}
 }
diff --git a/src/runtime/sema.go b/src/runtime/sema.go
index 26dbd30..8ae51b4 100644
--- a/src/runtime/sema.go
+++ b/src/runtime/sema.go
@@ -38,12 +38,23 @@ var semtable [semTabSize]struct {
 	pad  [_CacheLineSize - unsafe.Sizeof(semaRoot{})]byte
 }
 
-// Called from sync/net packages.
-func asyncsemacquire(addr *uint32) {
+//go:linkname sync_runtime_Semacquire sync.runtime_Semacquire
+func sync_runtime_Semacquire(addr *uint32) {
 	semacquire(addr, true)
 }
 
-func asyncsemrelease(addr *uint32) {
+//go:linkname net_runtime_Semacquire net.runtime_Semacquire
+func net_runtime_Semacquire(addr *uint32) {
+	semacquire(addr, true)
+}
+
+//go:linkname sync_runtime_Semrelease sync.runtime_Semrelease
+func sync_runtime_Semrelease(addr *uint32) {
+	semrelease(addr)
+}
+
+//go:linkname net_runtime_Semrelease net.runtime_Semrelease
+func net_runtime_Semrelease(addr *uint32) {
 	semrelease(addr)
 }
 
@@ -51,7 +62,7 @@ func asyncsemrelease(addr *uint32) {
 func semacquire(addr *uint32, profile bool) {
 	gp := getg()
 	if gp != gp.m.curg {
-		gothrow("semacquire not on the G stack")
+		throw("semacquire not on the G stack")
 	}
 
 	// Easy case.
@@ -86,7 +97,7 @@ func semacquire(addr *uint32, profile bool) {
 		// 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")
+		goparkunlock(&root.lock, "semacquire", traceEvGoBlockSync, 4)
 		if cansemacquire(addr) {
 			break
 		}
@@ -129,7 +140,7 @@ func semrelease(addr *uint32) {
 		if s.releasetime != 0 {
 			s.releasetime = cputicks()
 		}
-		goready(s.g)
+		goready(s.g, 4)
 	}
 }
 
@@ -185,7 +196,8 @@ type syncSema struct {
 	tail *sudog
 }
 
-// Syncsemacquire waits for a pairing syncsemrelease on the same semaphore s.
+// syncsemacquire waits for a pairing syncsemrelease on the same semaphore s.
+//go:linkname syncsemacquire sync.runtime_Syncsemacquire
 func syncsemacquire(s *syncSema) {
 	lock(&s.lock)
 	if s.head != nil && s.head.nrelease > 0 {
@@ -202,7 +214,7 @@ func syncsemacquire(s *syncSema) {
 		unlock(&s.lock)
 		if wake != nil {
 			wake.next = nil
-			goready(wake.g)
+			goready(wake.g, 4)
 		}
 	} else {
 		// Enqueue itself.
@@ -222,7 +234,7 @@ func syncsemacquire(s *syncSema) {
 			s.tail.next = w
 		}
 		s.tail = w
-		goparkunlock(&s.lock, "semacquire")
+		goparkunlock(&s.lock, "semacquire", traceEvGoBlockCond, 3)
 		if t0 != 0 {
 			blockevent(int64(w.releasetime)-t0, 2)
 		}
@@ -230,7 +242,8 @@ func syncsemacquire(s *syncSema) {
 	}
 }
 
-// Syncsemrelease waits for n pairing syncsemacquire on the same semaphore s.
+// syncsemrelease waits for n pairing syncsemacquire on the same semaphore s.
+//go:linkname syncsemrelease sync.runtime_Syncsemrelease
 func syncsemrelease(s *syncSema, n uint32) {
 	lock(&s.lock)
 	for n > 0 && s.head != nil && s.head.nrelease < 0 {
@@ -244,7 +257,7 @@ func syncsemrelease(s *syncSema, n uint32) {
 			wake.releasetime = cputicks()
 		}
 		wake.next = nil
-		goready(wake.g)
+		goready(wake.g, 4)
 		n--
 	}
 	if n > 0 {
@@ -260,16 +273,17 @@ func syncsemrelease(s *syncSema, n uint32) {
 			s.tail.next = w
 		}
 		s.tail = w
-		goparkunlock(&s.lock, "semarelease")
+		goparkunlock(&s.lock, "semarelease", traceEvGoBlockCond, 3)
 		releaseSudog(w)
 	} else {
 		unlock(&s.lock)
 	}
 }
 
+//go:linkname syncsemcheck sync.runtime_Syncsemcheck
 func syncsemcheck(sz uintptr) {
 	if sz != unsafe.Sizeof(syncSema{}) {
 		print("runtime: bad syncSema size - sync=", sz, " runtime=", unsafe.Sizeof(syncSema{}), "\n")
-		gothrow("bad syncSema size")
+		throw("bad syncSema size")
 	}
 }
diff --git a/src/runtime/signal.c b/src/runtime/signal.c
deleted file mode 100644
index 0674bfb..0000000
--- a/src/runtime/signal.c
+++ /dev/null
@@ -1,25 +0,0 @@
-// 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 "runtime.h"
-
-void
-runtime·sigenable_m(void)
-{
-	uint32 s;
-	
-	s = g->m->scalararg[0];
-	g->m->scalararg[0] = 0;
-	runtime·sigenable(s);
-}
-
-void
-runtime·sigdisable_m(void)
-{
-	uint32 s;
-	
-	s = g->m->scalararg[0];
-	g->m->scalararg[0] = 0;
-	runtime·sigdisable(s);
-}
diff --git a/src/runtime/signal1_unix.go b/src/runtime/signal1_unix.go
new file mode 100644
index 0000000..56d9755
--- /dev/null
+++ b/src/runtime/signal1_unix.go
@@ -0,0 +1,241 @@
+// 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.
+
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+
+package runtime
+
+const (
+	_SIG_DFL uintptr = 0
+	_SIG_IGN uintptr = 1
+)
+
+// Stores the signal handlers registered before Go installed its own.
+// These signal handlers will be invoked in cases where Go doesn't want to
+// handle a particular signal (e.g., signal occurred on a non-Go thread).
+// See sigfwdgo() for more information on when the signals are forwarded.
+//
+// Signal forwarding is currently available only on Linux.
+var fwdSig [_NSIG]uintptr
+
+// sigmask represents a general signal mask compatible with the GOOS
+// specific sigset types: the signal numbered x is represented by bit x-1
+// to match the representation expected by sigprocmask.
+type sigmask [(_NSIG + 31) / 32]uint32
+
+// channels for synchronizing signal mask updates with the signal mask
+// thread
+var (
+	disableSigChan  chan uint32
+	enableSigChan   chan uint32
+	maskUpdatedChan chan struct{}
+)
+
+func initsig() {
+	// _NSIG is the number of signals on this operating system.
+	// sigtable should describe what to do for all the possible signals.
+	if len(sigtable) != _NSIG {
+		print("runtime: len(sigtable)=", len(sigtable), " _NSIG=", _NSIG, "\n")
+		throw("initsig")
+	}
+
+	// First call: basic setup.
+	for i := int32(0); i < _NSIG; i++ {
+		t := &sigtable[i]
+		if t.flags == 0 || t.flags&_SigDefault != 0 {
+			continue
+		}
+		fwdSig[i] = getsig(i)
+		// For some signals, we respect an inherited SIG_IGN handler
+		// rather than insist on installing our own default handler.
+		// Even these signals can be fetched using the os/signal package.
+		switch i {
+		case _SIGHUP, _SIGINT:
+			if getsig(i) == _SIG_IGN {
+				t.flags = _SigNotify | _SigIgnored
+				continue
+			}
+		}
+
+		if t.flags&_SigSetStack != 0 {
+			setsigstack(i)
+			continue
+		}
+
+		t.flags |= _SigHandling
+		setsig(i, funcPC(sighandler), true)
+	}
+}
+
+func sigenable(sig uint32) {
+	if sig >= uint32(len(sigtable)) {
+		return
+	}
+
+	t := &sigtable[sig]
+	if t.flags&_SigNotify != 0 {
+		ensureSigM()
+		enableSigChan <- sig
+		<-maskUpdatedChan
+		if t.flags&_SigHandling == 0 {
+			t.flags |= _SigHandling
+			if getsig(int32(sig)) == _SIG_IGN {
+				t.flags |= _SigIgnored
+			}
+			setsig(int32(sig), funcPC(sighandler), true)
+		}
+	}
+}
+
+func sigdisable(sig uint32) {
+	if sig >= uint32(len(sigtable)) {
+		return
+	}
+
+	t := &sigtable[sig]
+	if t.flags&_SigNotify != 0 {
+		ensureSigM()
+		disableSigChan <- sig
+		<-maskUpdatedChan
+		if t.flags&_SigHandling != 0 {
+			t.flags &^= _SigHandling
+			if t.flags&_SigIgnored != 0 {
+				setsig(int32(sig), _SIG_IGN, true)
+			} else {
+				setsig(int32(sig), _SIG_DFL, true)
+			}
+		}
+	}
+}
+
+func sigignore(sig uint32) {
+	if sig >= uint32(len(sigtable)) {
+		return
+	}
+
+	t := &sigtable[sig]
+	if t.flags&_SigNotify != 0 {
+		t.flags &^= _SigHandling
+		setsig(int32(sig), _SIG_IGN, true)
+	}
+}
+
+func resetcpuprofiler(hz int32) {
+	var it itimerval
+	if hz == 0 {
+		setitimer(_ITIMER_PROF, &it, nil)
+	} else {
+		it.it_interval.tv_sec = 0
+		it.it_interval.set_usec(1000000 / hz)
+		it.it_value = it.it_interval
+		setitimer(_ITIMER_PROF, &it, nil)
+	}
+	_g_ := getg()
+	_g_.m.profilehz = hz
+}
+
+func sigpipe() {
+	setsig(_SIGPIPE, _SIG_DFL, false)
+	raise(_SIGPIPE)
+}
+
+// raisebadsignal is called when a signal is received on a non-Go
+// thread, and the Go program does not want to handle it (that is, the
+// program has not called os/signal.Notify for the signal).
+func raisebadsignal(sig int32) {
+	if sig == _SIGPROF {
+		// Ignore profiling signals that arrive on non-Go threads.
+		return
+	}
+
+	var handler uintptr
+	if sig >= _NSIG {
+		handler = _SIG_DFL
+	} else {
+		handler = fwdSig[sig]
+	}
+
+	// Reset the signal handler and raise the signal.
+	// We are currently running inside a signal handler, so the
+	// signal is blocked.  We need to unblock it before raising the
+	// signal, or the signal we raise will be ignored until we return
+	// from the signal handler.  We know that the signal was unblocked
+	// before entering the handler, or else we would not have received
+	// it.  That means that we don't have to worry about blocking it
+	// again.
+	unblocksig(sig)
+	setsig(sig, handler, false)
+	raise(sig)
+
+	// If the signal didn't cause the program to exit, restore the
+	// Go signal handler and carry on.
+	//
+	// We may receive another instance of the signal before we
+	// restore the Go handler, but that is not so bad: we know
+	// that the Go program has been ignoring the signal.
+	setsig(sig, funcPC(sighandler), true)
+}
+
+func crash() {
+	if GOOS == "darwin" {
+		// OS X core dumps are linear dumps of the mapped memory,
+		// from the first virtual byte to the last, with zeros in the gaps.
+		// Because of the way we arrange the address space on 64-bit systems,
+		// this means the OS X core file will be >128 GB and even on a zippy
+		// workstation can take OS X well over an hour to write (uninterruptible).
+		// Save users from making that mistake.
+		if ptrSize == 8 {
+			return
+		}
+	}
+
+	updatesigmask(sigmask{})
+	setsig(_SIGABRT, _SIG_DFL, false)
+	raise(_SIGABRT)
+}
+
+// createSigM starts one global, sleeping thread to make sure at least one thread
+// is available to catch signals enabled for os/signal.
+func ensureSigM() {
+	if maskUpdatedChan != nil {
+		return
+	}
+	maskUpdatedChan = make(chan struct{})
+	disableSigChan = make(chan uint32)
+	enableSigChan = make(chan uint32)
+	go func() {
+		// Signal masks are per-thread, so make sure this goroutine stays on one
+		// thread.
+		LockOSThread()
+		defer UnlockOSThread()
+		// The sigBlocked mask contains the signals not active for os/signal,
+		// initially all signals except the essential. When signal.Notify()/Stop is called,
+		// sigenable/sigdisable in turn notify this thread to update its signal
+		// mask accordingly.
+		var sigBlocked sigmask
+		for i := range sigBlocked {
+			sigBlocked[i] = ^uint32(0)
+		}
+		for i := range sigtable {
+			if sigtable[i].flags&_SigUnblock != 0 {
+				sigBlocked[(i-1)/32] &^= 1 << ((uint32(i) - 1) & 31)
+			}
+		}
+		updatesigmask(sigBlocked)
+		for {
+			select {
+			case sig := <-enableSigChan:
+				if b := sig - 1; b >= 0 {
+					sigBlocked[b/32] &^= (1 << (b & 31))
+				}
+			case sig := <-disableSigChan:
+				if b := sig - 1; b >= 0 {
+					sigBlocked[b/32] |= (1 << (b & 31))
+				}
+			}
+			updatesigmask(sigBlocked)
+			maskUpdatedChan <- struct{}{}
+		}
+	}()
+}
diff --git a/src/runtime/signal_386.c b/src/runtime/signal_386.c
deleted file mode 100644
index 30a7488..0000000
--- a/src/runtime/signal_386.c
+++ /dev/null
@@ -1,122 +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.
-
-// +build darwin dragonfly freebsd linux nacl netbsd openbsd
-
-#include "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "signal_GOOS_GOARCH.h"
-#include "signals_GOOS.h"
-
-void
-runtime·dumpregs(Siginfo *info, void *ctxt)
-{
-	USED(info);
-	USED(ctxt);
-	
-	runtime·printf("eax     %x\n", SIG_EAX(info, ctxt));
-	runtime·printf("ebx     %x\n", SIG_EBX(info, ctxt));
-	runtime·printf("ecx     %x\n", SIG_ECX(info, ctxt));
-	runtime·printf("edx     %x\n", SIG_EDX(info, ctxt));
-	runtime·printf("edi     %x\n", SIG_EDI(info, ctxt));
-	runtime·printf("esi     %x\n", SIG_ESI(info, ctxt));
-	runtime·printf("ebp     %x\n", SIG_EBP(info, ctxt));
-	runtime·printf("esp     %x\n", SIG_ESP(info, ctxt));
-	runtime·printf("eip     %x\n", SIG_EIP(info, ctxt));
-	runtime·printf("eflags  %x\n", SIG_EFLAGS(info, ctxt));
-	runtime·printf("cs      %x\n", SIG_CS(info, ctxt));
-	runtime·printf("fs      %x\n", SIG_FS(info, ctxt));
-	runtime·printf("gs      %x\n", SIG_GS(info, ctxt));
-}
-
-void
-runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp)
-{
-	uintptr *sp;
-	SigTab *t;
-	bool crash;
-
-	if(sig == SIGPROF) {
-		runtime·sigprof((byte*)SIG_EIP(info, ctxt), (byte*)SIG_ESP(info, ctxt), nil, gp, g->m);
-		return;
-	}
-
-	t = &runtime·sigtab[sig];
-	if(SIG_CODE0(info, ctxt) != SI_USER && (t->flags & SigPanic)) {
-		// 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 = SIG_CODE0(info, ctxt);
-		gp->sigcode1 = SIG_CODE1(info, ctxt);
-		gp->sigpc = SIG_EIP(info, ctxt);
-
-#ifdef GOOS_darwin
-		// Work around Leopard bug that doesn't set FPE_INTDIV.
-		// Look at instruction to see if it is a divide.
-		// Not necessary in Snow Leopard (si_code will be != 0).
-		if(sig == SIGFPE && gp->sigcode0 == 0) {
-			byte *pc;
-			pc = (byte*)gp->sigpc;
-			if(pc[0] == 0x66)	// 16-bit instruction prefix
-				pc++;
-			if(pc[0] == 0xF6 || pc[0] == 0xF7)
-				gp->sigcode0 = FPE_INTDIV;
-		}
-#endif
-
-		// Only push runtime·sigpanic if eip != 0.
-		// If eip == 0, probably panicked because of a
-		// call to a nil func.  Not pushing that onto sp will
-		// make the trace look like a call to runtime·sigpanic instead.
-		// (Otherwise the trace will end at runtime·sigpanic and we
-		// won't get to see who faulted.)
-		if(SIG_EIP(info, ctxt) != 0) {
-			sp = (uintptr*)SIG_ESP(info, ctxt);
-			*--sp = SIG_EIP(info, ctxt);
-			SIG_ESP(info, ctxt) = (uintptr)sp;
-		}
-		SIG_EIP(info, ctxt) = (uintptr)runtime·sigpanic;
-		return;
-	}
-
-	if(SIG_CODE0(info, ctxt) == SI_USER || (t->flags & SigNotify))
-		if(runtime·sigsend(sig))
-			return;
-	if(t->flags & SigKill)
-		runtime·exit(2);
-	if(!(t->flags & SigThrow))
-		return;
-
-	g->m->throwing = 1;
-	g->m->caughtsig = gp;
-	runtime·startpanic();
-
-	if(sig < 0 || sig >= NSIG)
-		runtime·printf("Signal %d\n", sig);
-	else
-		runtime·printf("%s\n", runtime·sigtab[sig].name);
-
-	runtime·printf("PC=%x\n", SIG_EIP(info, ctxt));
-	if(g->m->lockedg != nil && g->m->ncgo > 0 && gp == g->m->g0) {
-		runtime·printf("signal arrived during cgo execution\n");
-		gp = g->m->lockedg;
-	}
-	runtime·printf("\n");
-
-	if(runtime·gotraceback(&crash)){
-		runtime·goroutineheader(gp);
-		runtime·tracebacktrap(SIG_EIP(info, ctxt), SIG_ESP(info, ctxt), 0, gp);
-		runtime·tracebackothers(gp);
-		runtime·printf("\n");
-		runtime·dumpregs(info, ctxt);
-	}
-	
-	if(crash)
-		runtime·crash();
-
-	runtime·exit(2);
-}
diff --git a/src/runtime/signal_386.go b/src/runtime/signal_386.go
new file mode 100644
index 0000000..ca18942
--- /dev/null
+++ b/src/runtime/signal_386.go
@@ -0,0 +1,193 @@
+// 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 darwin dragonfly freebsd linux nacl netbsd openbsd
+
+package runtime
+
+import "unsafe"
+
+func dumpregs(c *sigctxt) {
+	print("eax    ", hex(c.eax()), "\n")
+	print("ebx    ", hex(c.ebx()), "\n")
+	print("ecx    ", hex(c.ecx()), "\n")
+	print("edx    ", hex(c.edx()), "\n")
+	print("edi    ", hex(c.edi()), "\n")
+	print("esi    ", hex(c.esi()), "\n")
+	print("ebp    ", hex(c.ebp()), "\n")
+	print("esp    ", hex(c.esp()), "\n")
+	print("eip    ", hex(c.eip()), "\n")
+	print("eflags ", hex(c.eflags()), "\n")
+	print("cs     ", hex(c.cs()), "\n")
+	print("fs     ", hex(c.fs()), "\n")
+	print("gs     ", hex(c.gs()), "\n")
+}
+
+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}
+
+	if sig == _SIGPROF {
+		sigprof(uintptr(c.eip()), uintptr(c.esp()), 0, 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.sigaddr())
+		gp.sigpc = uintptr(c.eip())
+
+		if GOOS == "darwin" {
+			// Work around Leopard bug that doesn't set FPE_INTDIV.
+			// Look at instruction to see if it is a divide.
+			// Not necessary in Snow Leopard (si_code will be != 0).
+			if sig == _SIGFPE && gp.sigcode0 == 0 {
+				pc := (*[4]byte)(unsafe.Pointer(gp.sigpc))
+				i := 0
+				if pc[i] == 0x66 { // 16-bit instruction prefix
+					i++
+				}
+				if pc[i] == 0xF6 || pc[i] == 0xF7 {
+					gp.sigcode0 = _FPE_INTDIV
+				}
+			}
+		}
+
+		pc := uintptr(c.eip())
+		sp := uintptr(c.esp())
+
+		// If we don't recognize the PC as code
+		// but we do recognize the top pointer on the stack as code,
+		// then assume this was a call to non-code and treat like
+		// pc == 0, to make unwinding show the context.
+		if pc != 0 && findfunc(pc) == nil && findfunc(*(*uintptr)(unsafe.Pointer(sp))) != nil {
+			pc = 0
+		}
+
+		// Only push runtime.sigpanic if pc != 0.
+		// If pc == 0, probably panicked because of a
+		// call to a nil func.  Not pushing that onto sp will
+		// make the trace look like a call to runtime.sigpanic instead.
+		// (Otherwise the trace will end at runtime.sigpanic and we
+		// won't get to see who faulted.)
+		if pc != 0 {
+			if regSize > ptrSize {
+				sp -= ptrSize
+				*(*uintptr)(unsafe.Pointer(sp)) = 0
+			}
+			sp -= ptrSize
+			*(*uintptr)(unsafe.Pointer(sp)) = pc
+			c.set_esp(uint32(sp))
+		}
+		c.set_eip(uint32(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
+	_g_.m.caughtsig.set(gp)
+
+	if crashing == 0 {
+		startpanic()
+	}
+
+	if sig < uint32(len(sigtable)) {
+		print(sigtable[sig].name, "\n")
+	} else {
+		print("Signal ", sig, "\n")
+	}
+
+	print("PC=", hex(c.eip()), " m=", _g_.m.id, "\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)
+
+		// On Linux/386, all system calls go through the vdso kernel_vsyscall routine.
+		// Normally we don't see those PCs, but during signals we can.
+		// If we see a PC in the vsyscall area (it moves around, but near the top of memory),
+		// assume we're blocked in the vsyscall routine, which has saved
+		// three words on the stack after the initial call saved the caller PC.
+		// Pop all four words off SP and use the saved PC.
+		// The check of the stack bounds here should suffice to avoid a fault
+		// during the actual PC pop.
+		// If we do load a bogus PC, not much harm done: we weren't going
+		// to get a decent traceback anyway.
+		// TODO(rsc): Make this more precise: we should do more checks on the PC,
+		// and we should find out whether different versions of the vdso page
+		// use different prologues that store different amounts on the stack.
+		pc := uintptr(c.eip())
+		sp := uintptr(c.esp())
+		if GOOS == "linux" && pc >= 0xf4000000 && gp.stack.lo <= sp && sp+16 <= gp.stack.hi {
+			// Assume in vsyscall page.
+			sp += 16
+			pc = *(*uintptr)(unsafe.Pointer(sp - 4))
+			print("runtime: unwind vdso kernel_vsyscall: pc=", hex(pc), " sp=", hex(sp), "\n")
+		}
+
+		tracebacktrap(pc, sp, 0, gp)
+		if crashing > 0 && gp != _g_.m.curg && _g_.m.curg != nil && readgstatus(_g_.m.curg)&^_Gscan == _Grunning {
+			// tracebackothers on original m skipped this one; trace it now.
+			goroutineheader(_g_.m.curg)
+			traceback(^uintptr(0), ^uintptr(0), 0, gp)
+		} else if crashing == 0 {
+			tracebackothers(gp)
+			print("\n")
+		}
+		dumpregs(c)
+	}
+
+	if docrash {
+		crashing++
+		if crashing < sched.mcount {
+			// There are other m's that need to dump their stacks.
+			// Relay SIGQUIT to the next m by sending it to the current process.
+			// All m's that have already received SIGQUIT have signal masks blocking
+			// receipt of any signals, so the SIGQUIT will go to an m that hasn't seen it yet.
+			// When the last m receives the SIGQUIT, it will fall through to the call to
+			// crash below. Just in case the relaying gets botched, each m involved in
+			// the relay sleeps for 5 seconds and then does the crash/exit itself.
+			// In expected operation, the last m has received the SIGQUIT and run
+			// crash/exit and the process is gone, all long before any of the
+			// 5-second sleeps have finished.
+			print("\n-----\n\n")
+			raiseproc(_SIGQUIT)
+			usleep(5 * 1000 * 1000)
+		}
+		crash()
+	}
+
+	exit(2)
+}
diff --git a/src/runtime/signal_amd64x.c b/src/runtime/signal_amd64x.c
deleted file mode 100644
index feb4afc..0000000
--- a/src/runtime/signal_amd64x.c
+++ /dev/null
@@ -1,156 +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.
-
-// +build amd64 amd64p32
-// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
-
-#include "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "signal_GOOS_GOARCH.h"
-#include "signals_GOOS.h"
-
-void
-runtime·dumpregs(Siginfo *info, void *ctxt)
-{
-	USED(info);
-	USED(ctxt);
-	
-	runtime·printf("rax     %X\n", SIG_RAX(info, ctxt));
-	runtime·printf("rbx     %X\n", SIG_RBX(info, ctxt));
-	runtime·printf("rcx     %X\n", SIG_RCX(info, ctxt));
-	runtime·printf("rdx     %X\n", SIG_RDX(info, ctxt));
-	runtime·printf("rdi     %X\n", SIG_RDI(info, ctxt));
-	runtime·printf("rsi     %X\n", SIG_RSI(info, ctxt));
-	runtime·printf("rbp     %X\n", SIG_RBP(info, ctxt));
-	runtime·printf("rsp     %X\n", SIG_RSP(info, ctxt));
-	runtime·printf("r8      %X\n", SIG_R8(info, ctxt) );
-	runtime·printf("r9      %X\n", SIG_R9(info, ctxt) );
-	runtime·printf("r10     %X\n", SIG_R10(info, ctxt));
-	runtime·printf("r11     %X\n", SIG_R11(info, ctxt));
-	runtime·printf("r12     %X\n", SIG_R12(info, ctxt));
-	runtime·printf("r13     %X\n", SIG_R13(info, ctxt));
-	runtime·printf("r14     %X\n", SIG_R14(info, ctxt));
-	runtime·printf("r15     %X\n", SIG_R15(info, ctxt));
-	runtime·printf("rip     %X\n", SIG_RIP(info, ctxt));
-	runtime·printf("rflags  %X\n", SIG_RFLAGS(info, ctxt));
-	runtime·printf("cs      %X\n", SIG_CS(info, ctxt));
-	runtime·printf("fs      %X\n", SIG_FS(info, ctxt));
-	runtime·printf("gs      %X\n", SIG_GS(info, ctxt));
-}
-
-void
-runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp)
-{
-	uintptr *sp;
-	SigTab *t;
-	bool crash;
-
-	if(sig == SIGPROF) {
-		runtime·sigprof((byte*)SIG_RIP(info, ctxt), (byte*)SIG_RSP(info, ctxt), nil, gp, g->m);
-		return;
-	}
-
-#ifdef GOOS_darwin
-	// x86-64 has 48-bit virtual addresses. The top 16 bits must echo bit 47.
-	// The hardware delivers a different kind of fault for a malformed address
-	// than it does for an attempt to access a valid but unmapped address.
-	// OS X 10.9.2 mishandles the malformed address case, making it look like
-	// a user-generated signal (like someone ran kill -SEGV ourpid).
-	// We pass user-generated signals to os/signal, or else ignore them.
-	// Doing that here - and returning to the faulting code - results in an
-	// infinite loop. It appears the best we can do is rewrite what the kernel
-	// delivers into something more like the truth. The address used below
-	// has very little chance of being the one that caused the fault, but it is
-	// malformed, it is clearly not a real pointer, and if it does get printed
-	// in real life, people will probably search for it and find this code.
-	// There are no Google hits for b01dfacedebac1e or 0xb01dfacedebac1e
-	// as I type this comment.
-	if(sig == SIGSEGV && SIG_CODE0(info, ctxt) == SI_USER) {
-		SIG_CODE0(info, ctxt) = SI_USER+1;
-		info->si_addr = (void*)(uintptr)0xb01dfacedebac1eULL;
-	}
-#endif
-
-	t = &runtime·sigtab[sig];
-	if(SIG_CODE0(info, ctxt) != SI_USER && (t->flags & SigPanic)) {
-		// 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 = SIG_CODE0(info, ctxt);
-		gp->sigcode1 = SIG_CODE1(info, ctxt);
-		gp->sigpc = SIG_RIP(info, ctxt);
-
-#ifdef GOOS_darwin
-		// Work around Leopard bug that doesn't set FPE_INTDIV.
-		// Look at instruction to see if it is a divide.
-		// Not necessary in Snow Leopard (si_code will be != 0).
-		if(sig == SIGFPE && gp->sigcode0 == 0) {
-			byte *pc;
-			pc = (byte*)gp->sigpc;
-			if((pc[0]&0xF0) == 0x40)	// 64-bit REX prefix
-				pc++;
-			else if(pc[0] == 0x66)	// 16-bit instruction prefix
-				pc++;
-			if(pc[0] == 0xF6 || pc[0] == 0xF7)
-				gp->sigcode0 = FPE_INTDIV;
-		}
-#endif
-
-		// Only push runtime·sigpanic if rip != 0.
-		// If rip == 0, probably panicked because of a
-		// call to a nil func.  Not pushing that onto sp will
-		// make the trace look like a call to runtime·sigpanic instead.
-		// (Otherwise the trace will end at runtime·sigpanic and we
-		// won't get to see who faulted.)
-		if(SIG_RIP(info, ctxt) != 0) {
-			sp = (uintptr*)SIG_RSP(info, ctxt);
-			if(sizeof(uintreg) > sizeof(uintptr))
-				*--sp = 0;
-			*--sp = SIG_RIP(info, ctxt);
-			SIG_RSP(info, ctxt) = (uintptr)sp;
-		}
-		SIG_RIP(info, ctxt) = (uintptr)runtime·sigpanic;
-		return;
-	}
-
-	if(SIG_CODE0(info, ctxt) == SI_USER || (t->flags & SigNotify))
-		if(runtime·sigsend(sig))
-			return;
-	if(t->flags & SigKill)
-		runtime·exit(2);
-	if(!(t->flags & SigThrow))
-		return;
-
-	g->m->throwing = 1;
-	g->m->caughtsig = gp;
-	runtime·startpanic();
-
-	if(sig < 0 || sig >= NSIG)
-		runtime·printf("Signal %d\n", sig);
-	else
-		runtime·printf("%s\n", runtime·sigtab[sig].name);
-
-	runtime·printf("PC=%X\n", SIG_RIP(info, ctxt));
-	if(g->m->lockedg != nil && g->m->ncgo > 0 && gp == g->m->g0) {
-		runtime·printf("signal arrived during cgo execution\n");
-		gp = g->m->lockedg;
-	}
-	runtime·printf("\n");
-
-	if(runtime·gotraceback(&crash)){
-		runtime·goroutineheader(gp);
-		runtime·tracebacktrap(SIG_RIP(info, ctxt), SIG_RSP(info, ctxt), 0, gp);
-		runtime·tracebackothers(gp);
-		runtime·printf("\n");
-		runtime·dumpregs(info, ctxt);
-	}
-	
-	if(crash)
-		runtime·crash();
-
-	runtime·exit(2);
-}
diff --git a/src/runtime/signal_amd64x.go b/src/runtime/signal_amd64x.go
new file mode 100644
index 0000000..3e14480
--- /dev/null
+++ b/src/runtime/signal_amd64x.go
@@ -0,0 +1,204 @@
+// 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 amd64 amd64p32
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
+
+package runtime
+
+import (
+	"unsafe"
+)
+
+func dumpregs(c *sigctxt) {
+	print("rax    ", hex(c.rax()), "\n")
+	print("rbx    ", hex(c.rbx()), "\n")
+	print("rcx    ", hex(c.rcx()), "\n")
+	print("rdx    ", hex(c.rdx()), "\n")
+	print("rdi    ", hex(c.rdi()), "\n")
+	print("rsi    ", hex(c.rsi()), "\n")
+	print("rbp    ", hex(c.rbp()), "\n")
+	print("rsp    ", hex(c.rsp()), "\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("rip    ", hex(c.rip()), "\n")
+	print("rflags ", hex(c.rflags()), "\n")
+	print("cs     ", hex(c.cs()), "\n")
+	print("fs     ", hex(c.fs()), "\n")
+	print("gs     ", hex(c.gs()), "\n")
+}
+
+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}
+
+	if sig == _SIGPROF {
+		sigprof(uintptr(c.rip()), uintptr(c.rsp()), 0, gp, _g_.m)
+		return
+	}
+
+	if GOOS == "darwin" {
+		// x86-64 has 48-bit virtual addresses. The top 16 bits must echo bit 47.
+		// The hardware delivers a different kind of fault for a malformed address
+		// than it does for an attempt to access a valid but unmapped address.
+		// OS X 10.9.2 mishandles the malformed address case, making it look like
+		// a user-generated signal (like someone ran kill -SEGV ourpid).
+		// We pass user-generated signals to os/signal, or else ignore them.
+		// Doing that here - and returning to the faulting code - results in an
+		// infinite loop. It appears the best we can do is rewrite what the kernel
+		// delivers into something more like the truth. The address used below
+		// has very little chance of being the one that caused the fault, but it is
+		// malformed, it is clearly not a real pointer, and if it does get printed
+		// in real life, people will probably search for it and find this code.
+		// There are no Google hits for b01dfacedebac1e or 0xb01dfacedebac1e
+		// as I type this comment.
+		if sig == _SIGSEGV && c.sigcode() == _SI_USER {
+			c.set_sigcode(_SI_USER + 1)
+			c.set_sigaddr(0xb01dfacedebac1e)
+		}
+	}
+
+	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.sigaddr())
+		gp.sigpc = uintptr(c.rip())
+
+		if GOOS == "darwin" {
+			// Work around Leopard bug that doesn't set FPE_INTDIV.
+			// Look at instruction to see if it is a divide.
+			// Not necessary in Snow Leopard (si_code will be != 0).
+			if sig == _SIGFPE && gp.sigcode0 == 0 {
+				pc := (*[4]byte)(unsafe.Pointer(gp.sigpc))
+				i := 0
+				if pc[i]&0xF0 == 0x40 { // 64-bit REX prefix
+					i++
+				} else if pc[i] == 0x66 { // 16-bit instruction prefix
+					i++
+				}
+				if pc[i] == 0xF6 || pc[i] == 0xF7 {
+					gp.sigcode0 = _FPE_INTDIV
+				}
+			}
+		}
+
+		pc := uintptr(c.rip())
+		sp := uintptr(c.rsp())
+
+		// If we don't recognize the PC as code
+		// but we do recognize the top pointer on the stack as code,
+		// then assume this was a call to non-code and treat like
+		// pc == 0, to make unwinding show the context.
+		if pc != 0 && findfunc(pc) == nil && findfunc(*(*uintptr)(unsafe.Pointer(sp))) != nil {
+			pc = 0
+		}
+
+		// Only push runtime.sigpanic if pc != 0.
+		// If pc == 0, probably panicked because of a
+		// call to a nil func.  Not pushing that onto sp will
+		// make the trace look like a call to runtime.sigpanic instead.
+		// (Otherwise the trace will end at runtime.sigpanic and we
+		// won't get to see who faulted.)
+		if pc != 0 {
+			if regSize > ptrSize {
+				sp -= ptrSize
+				*(*uintptr)(unsafe.Pointer(sp)) = 0
+			}
+			sp -= ptrSize
+			*(*uintptr)(unsafe.Pointer(sp)) = pc
+			c.set_rsp(uint64(sp))
+		}
+		c.set_rip(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
+	_g_.m.caughtsig.set(gp)
+
+	if crashing == 0 {
+		startpanic()
+	}
+
+	if sig < uint32(len(sigtable)) {
+		print(sigtable[sig].name, "\n")
+	} else {
+		print("Signal ", sig, "\n")
+	}
+
+	print("PC=", hex(c.rip()), " m=", _g_.m.id, "\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.rip()), uintptr(c.rsp()), 0, gp)
+		if crashing > 0 && gp != _g_.m.curg && _g_.m.curg != nil && readgstatus(_g_.m.curg)&^_Gscan == _Grunning {
+			// tracebackothers on original m skipped this one; trace it now.
+			goroutineheader(_g_.m.curg)
+			traceback(^uintptr(0), ^uintptr(0), 0, gp)
+		} else if crashing == 0 {
+			tracebackothers(gp)
+			print("\n")
+		}
+		dumpregs(c)
+	}
+
+	if docrash {
+		crashing++
+		if crashing < sched.mcount {
+			// There are other m's that need to dump their stacks.
+			// Relay SIGQUIT to the next m by sending it to the current process.
+			// All m's that have already received SIGQUIT have signal masks blocking
+			// receipt of any signals, so the SIGQUIT will go to an m that hasn't seen it yet.
+			// When the last m receives the SIGQUIT, it will fall through to the call to
+			// crash below. Just in case the relaying gets botched, each m involved in
+			// the relay sleeps for 5 seconds and then does the crash/exit itself.
+			// In expected operation, the last m has received the SIGQUIT and run
+			// crash/exit and the process is gone, all long before any of the
+			// 5-second sleeps have finished.
+			print("\n-----\n\n")
+			raiseproc(_SIGQUIT)
+			usleep(5 * 1000 * 1000)
+		}
+		crash()
+	}
+
+	exit(2)
+}
diff --git a/src/runtime/signal_android_386.h b/src/runtime/signal_android_386.h
deleted file mode 100644
index 2a1bb4b..0000000
--- a/src/runtime/signal_android_386.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "signal_linux_386.h"
diff --git a/src/runtime/signal_android_arm.h b/src/runtime/signal_android_arm.h
deleted file mode 100644
index 8a05e21..0000000
--- a/src/runtime/signal_android_arm.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "signal_linux_arm.h"
diff --git a/src/runtime/signal_arm.c b/src/runtime/signal_arm.c
deleted file mode 100644
index afad5e7..0000000
--- a/src/runtime/signal_arm.c
+++ /dev/null
@@ -1,121 +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.
-
-// +build darwin dragonfly freebsd linux nacl netbsd openbsd
-
-#include "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "signal_GOOS_GOARCH.h"
-#include "signals_GOOS.h"
-
-void
-runtime·dumpregs(Siginfo *info, void *ctxt)
-{
-	USED(info);
-	USED(ctxt);
-
-	runtime·printf("trap    %x\n", SIG_TRAP(info, ctxt));
-	runtime·printf("error   %x\n", SIG_ERROR(info, ctxt));
-	runtime·printf("oldmask %x\n", SIG_OLDMASK(info, ctxt));
-	runtime·printf("r0      %x\n", SIG_R0(info, ctxt));
-	runtime·printf("r1      %x\n", SIG_R1(info, ctxt));
-	runtime·printf("r2      %x\n", SIG_R2(info, ctxt));
-	runtime·printf("r3      %x\n", SIG_R3(info, ctxt));
-	runtime·printf("r4      %x\n", SIG_R4(info, ctxt));
-	runtime·printf("r5      %x\n", SIG_R5(info, ctxt));
-	runtime·printf("r6      %x\n", SIG_R6(info, ctxt));
-	runtime·printf("r7      %x\n", SIG_R7(info, ctxt));
-	runtime·printf("r8      %x\n", SIG_R8(info, ctxt));
-	runtime·printf("r9      %x\n", SIG_R9(info, ctxt));
-	runtime·printf("r10     %x\n", SIG_R10(info, ctxt));
-	runtime·printf("fp      %x\n", SIG_FP(info, ctxt));
-	runtime·printf("ip      %x\n", SIG_IP(info, ctxt));
-	runtime·printf("sp      %x\n", SIG_SP(info, ctxt));
-	runtime·printf("lr      %x\n", SIG_LR(info, ctxt));
-	runtime·printf("pc      %x\n", SIG_PC(info, ctxt));
-	runtime·printf("cpsr    %x\n", SIG_CPSR(info, ctxt));
-	runtime·printf("fault   %x\n", SIG_FAULT(info, ctxt));
-}
-
-void
-runtime·sighandler(int32 sig, Siginfo *info, void *ctxt, G *gp)
-{
-	SigTab *t;
-	bool crash;
-
-	if(sig == SIGPROF) {
-		runtime·sigprof((uint8*)SIG_PC(info, ctxt), (uint8*)SIG_SP(info, ctxt), (uint8*)SIG_LR(info, ctxt), gp, g->m);
-		return;
-	}
-
-	t = &runtime·sigtab[sig];
-	if(SIG_CODE0(info, ctxt) != SI_USER && (t->flags & SigPanic)) {
-		// 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 = SIG_CODE0(info, ctxt);
-		gp->sigcode1 = SIG_FAULT(info, ctxt);
-		gp->sigpc = SIG_PC(info, ctxt);
-
-		// 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.
-		SIG_SP(info, ctxt) -= 4;
-		*(uint32*)SIG_SP(info, ctxt) = SIG_LR(info, ctxt);
-		// 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)
-			SIG_LR(info, ctxt) = gp->sigpc;
-		// In case we are panicking from external C code
-		SIG_R10(info, ctxt) = (uintptr)gp;
-		SIG_PC(info, ctxt) = (uintptr)runtime·sigpanic;
-		return;
-	}
-
-	if(SIG_CODE0(info, ctxt) == SI_USER || (t->flags & SigNotify))
-		if(runtime·sigsend(sig))
-			return;
-	if(t->flags & SigKill)
-		runtime·exit(2);
-	if(!(t->flags & SigThrow))
-		return;
-
-	g->m->throwing = 1;
-	g->m->caughtsig = gp;
-	if(runtime·panicking)	// traceback already printed
-		runtime·exit(2);
-	runtime·panicking = 1;
-
-	if(sig < 0 || sig >= NSIG)
-		runtime·printf("Signal %d\n", sig);
-	else
-		runtime·printf("%s\n", runtime·sigtab[sig].name);
-
-	runtime·printf("PC=%x\n", SIG_PC(info, ctxt));
-	if(g->m->lockedg != nil && g->m->ncgo > 0 && gp == g->m->g0) {
-		runtime·printf("signal arrived during cgo execution\n");
-		gp = g->m->lockedg;
-	}
-	runtime·printf("\n");
-
-	if(runtime·gotraceback(&crash)){
-		runtime·goroutineheader(gp);
-		runtime·tracebacktrap(SIG_PC(info, ctxt), SIG_SP(info, ctxt), SIG_LR(info, ctxt), gp);
-		runtime·tracebackothers(gp);
-		runtime·printf("\n");
-		runtime·dumpregs(info, ctxt);
-	}
-	
-	if(crash)
-		runtime·crash();
-
-	runtime·exit(2);
-}
diff --git a/src/runtime/signal_arm.go b/src/runtime/signal_arm.go
new file mode 100644
index 0000000..1b8a2f5
--- /dev/null
+++ b/src/runtime/signal_arm.go
@@ -0,0 +1,165 @@
+// 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.
+
+// +build darwin dragonfly freebsd linux nacl netbsd openbsd
+
+package runtime
+
+import "unsafe"
+
+func dumpregs(c *sigctxt) {
+	print("trap    ", hex(c.trap()), "\n")
+	print("error   ", hex(c.error()), "\n")
+	print("oldmask ", hex(c.oldmask()), "\n")
+	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("fp      ", hex(c.fp()), "\n")
+	print("ip      ", hex(c.ip()), "\n")
+	print("sp      ", hex(c.sp()), "\n")
+	print("lr      ", hex(c.lr()), "\n")
+	print("pc      ", hex(c.pc()), "\n")
+	print("cpsr    ", hex(c.cpsr()), "\n")
+	print("fault   ", hex(c.fault()), "\n")
+}
+
+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}
+
+	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() - 4
+		c.set_sp(sp)
+		*(*uint32)(unsafe.Pointer(uintptr(sp))) = c.lr()
+
+		pc := uintptr(gp.sigpc)
+
+		// If we don't recognize the PC as code
+		// but we do recognize the link register as code,
+		// then assume this was a call to non-code and treat like
+		// pc == 0, to make unwinding show the context.
+		if pc != 0 && findfunc(pc) == nil && findfunc(uintptr(c.lr())) != nil {
+			pc = 0
+		}
+
+		// 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 pc != 0 {
+			c.set_lr(uint32(pc))
+		}
+
+		// In case we are panicking from external C code
+		c.set_r10(uint32(uintptr(unsafe.Pointer(gp))))
+		c.set_pc(uint32(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
+	_g_.m.caughtsig.set(gp)
+
+	if crashing == 0 {
+		startpanic()
+	}
+
+	if sig < uint32(len(sigtable)) {
+		print(sigtable[sig].name, "\n")
+	} else {
+		print("Signal ", sig, "\n")
+	}
+
+	print("PC=", hex(c.pc()), " m=", _g_.m.id, "\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)
+		if crashing > 0 && gp != _g_.m.curg && _g_.m.curg != nil && readgstatus(_g_.m.curg)&^_Gscan == _Grunning {
+			// tracebackothers on original m skipped this one; trace it now.
+			goroutineheader(_g_.m.curg)
+			traceback(^uintptr(0), ^uintptr(0), 0, gp)
+		} else if crashing == 0 {
+			tracebackothers(gp)
+			print("\n")
+		}
+		dumpregs(c)
+	}
+
+	if docrash {
+		crashing++
+		if crashing < sched.mcount {
+			// There are other m's that need to dump their stacks.
+			// Relay SIGQUIT to the next m by sending it to the current process.
+			// All m's that have already received SIGQUIT have signal masks blocking
+			// receipt of any signals, so the SIGQUIT will go to an m that hasn't seen it yet.
+			// When the last m receives the SIGQUIT, it will fall through to the call to
+			// crash below. Just in case the relaying gets botched, each m involved in
+			// the relay sleeps for 5 seconds and then does the crash/exit itself.
+			// In expected operation, the last m has received the SIGQUIT and run
+			// crash/exit and the process is gone, all long before any of the
+			// 5-second sleeps have finished.
+			print("\n-----\n\n")
+			raiseproc(_SIGQUIT)
+			usleep(5 * 1000 * 1000)
+		}
+		crash()
+	}
+
+	exit(2)
+}
diff --git a/src/runtime/signal_arm64.go b/src/runtime/signal_arm64.go
new file mode 100644
index 0000000..4a7c8b9
--- /dev/null
+++ b/src/runtime/signal_arm64.go
@@ -0,0 +1,178 @@
+// 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 darwin
+
+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")
+}
+
+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}
+
+	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()
+
+		pc := uintptr(gp.sigpc)
+
+		// If we don't recognize the PC as code
+		// but we do recognize the link register as code,
+		// then assume this was a call to non-code and treat like
+		// pc == 0, to make unwinding show the context.
+		if pc != 0 && findfunc(pc) == nil && findfunc(uintptr(c.lr())) != nil {
+			pc = 0
+		}
+
+		// 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 pc != 0 {
+			c.set_lr(uint64(pc))
+		}
+
+		// 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
+	_g_.m.caughtsig.set(gp)
+
+	if crashing == 0 {
+		startpanic()
+	}
+
+	if sig < uint32(len(sigtable)) {
+		print(sigtable[sig].name, "\n")
+	} else {
+		print("Signal ", sig, "\n")
+	}
+
+	print("PC=", hex(c.pc()), " m=", _g_.m.id, "\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)
+		if crashing > 0 && gp != _g_.m.curg && _g_.m.curg != nil && readgstatus(_g_.m.curg)&^_Gscan == _Grunning {
+			// tracebackothers on original m skipped this one; trace it now.
+			goroutineheader(_g_.m.curg)
+			traceback(^uintptr(0), ^uintptr(0), 0, gp)
+		} else if crashing == 0 {
+			tracebackothers(gp)
+			print("\n")
+		}
+		dumpregs(c)
+	}
+
+	if docrash {
+		crashing++
+		if crashing < sched.mcount {
+			// There are other m's that need to dump their stacks.
+			// Relay SIGQUIT to the next m by sending it to the current process.
+			// All m's that have already received SIGQUIT have signal masks blocking
+			// receipt of any signals, so the SIGQUIT will go to an m that hasn't seen it yet.
+			// When the last m receives the SIGQUIT, it will fall through to the call to
+			// crash below. Just in case the relaying gets botched, each m involved in
+			// the relay sleeps for 5 seconds and then does the crash/exit itself.
+			// In expected operation, the last m has received the SIGQUIT and run
+			// crash/exit and the process is gone, all long before any of the
+			// 5-second sleeps have finished.
+			print("\n-----\n\n")
+			raiseproc(_SIGQUIT)
+			usleep(5 * 1000 * 1000)
+		}
+		crash()
+	}
+
+	exit(2)
+}
diff --git a/src/runtime/signal_darwin.go b/src/runtime/signal_darwin.go
new file mode 100644
index 0000000..6cd1865
--- /dev/null
+++ b/src/runtime/signal_darwin.go
@@ -0,0 +1,71 @@
+// 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"
+
+type sigTabT struct {
+	flags int32
+	name  string
+}
+
+var sigtable = [...]sigTabT{
+	/* 0 */ {0, "SIGNONE: no trap"},
+	/* 1 */ {_SigNotify + _SigKill, "SIGHUP: terminal line hangup"},
+	/* 2 */ {_SigNotify + _SigKill, "SIGINT: interrupt"},
+	/* 3 */ {_SigNotify + _SigThrow, "SIGQUIT: quit"},
+	/* 4 */ {_SigThrow + _SigUnblock, "SIGILL: illegal instruction"},
+	/* 5 */ {_SigThrow + _SigUnblock, "SIGTRAP: trace trap"},
+	/* 6 */ {_SigNotify + _SigThrow, "SIGABRT: abort"},
+	/* 7 */ {_SigThrow, "SIGEMT: emulate instruction executed"},
+	/* 8 */ {_SigPanic + _SigUnblock, "SIGFPE: floating-point exception"},
+	/* 9 */ {0, "SIGKILL: kill"},
+	/* 10 */ {_SigPanic + _SigUnblock, "SIGBUS: bus error"},
+	/* 11 */ {_SigPanic + _SigUnblock, "SIGSEGV: segmentation violation"},
+	/* 12 */ {_SigThrow, "SIGSYS: bad system call"},
+	/* 13 */ {_SigNotify, "SIGPIPE: write to broken pipe"},
+	/* 14 */ {_SigNotify, "SIGALRM: alarm clock"},
+	/* 15 */ {_SigNotify + _SigKill, "SIGTERM: termination"},
+	/* 16 */ {_SigNotify, "SIGURG: urgent condition on socket"},
+	/* 17 */ {0, "SIGSTOP: stop"},
+	/* 18 */ {_SigNotify + _SigDefault, "SIGTSTP: keyboard stop"},
+	/* 19 */ {0, "SIGCONT: continue after stop"},
+	/* 20 */ {_SigNotify + _SigUnblock, "SIGCHLD: child status has changed"},
+	/* 21 */ {_SigNotify + _SigDefault, "SIGTTIN: background read from tty"},
+	/* 22 */ {_SigNotify + _SigDefault, "SIGTTOU: background write to tty"},
+	/* 23 */ {_SigNotify, "SIGIO: i/o now possible"},
+	/* 24 */ {_SigNotify, "SIGXCPU: cpu limit exceeded"},
+	/* 25 */ {_SigNotify, "SIGXFSZ: file size limit exceeded"},
+	/* 26 */ {_SigNotify, "SIGVTALRM: virtual alarm clock"},
+	/* 27 */ {_SigNotify + _SigUnblock, "SIGPROF: profiling alarm clock"},
+	/* 28 */ {_SigNotify, "SIGWINCH: window size change"},
+	/* 29 */ {_SigNotify, "SIGINFO: status request from keyboard"},
+	/* 30 */ {_SigNotify, "SIGUSR1: user-defined signal 1"},
+	/* 31 */ {_SigNotify, "SIGUSR2: user-defined signal 2"},
+}
+
+//go:noescape
+func sigfwd(fn uintptr, sig uint32, info *siginfo, ctx unsafe.Pointer)
+
+//go:noescape
+func sigreturn(ctx unsafe.Pointer, infostyle uint32)
+
+//go:nosplit
+func sigtrampgo(fn uintptr, infostyle, sig uint32, info *siginfo, ctx unsafe.Pointer) {
+	if sigfwdgo(sig, info, ctx) {
+		sigreturn(ctx, infostyle)
+		return
+	}
+	g := getg()
+	if g == nil {
+		badsignal(uintptr(sig))
+		sigreturn(ctx, infostyle)
+		return
+	}
+	setg(g.m.gsignal)
+	sighandler(sig, info, ctx, g)
+	setg(g)
+	sigreturn(ctx, infostyle)
+}
diff --git a/src/runtime/signal_darwin_386.go b/src/runtime/signal_darwin_386.go
new file mode 100644
index 0000000..302b3aa
--- /dev/null
+++ b/src/runtime/signal_darwin_386.go
@@ -0,0 +1,34 @@
+// 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() *regs32   { return &(*ucontext)(c.ctxt).uc_mcontext.ss }
+func (c *sigctxt) eax() uint32     { return c.regs().eax }
+func (c *sigctxt) ebx() uint32     { return c.regs().ebx }
+func (c *sigctxt) ecx() uint32     { return c.regs().ecx }
+func (c *sigctxt) edx() uint32     { return c.regs().edx }
+func (c *sigctxt) edi() uint32     { return c.regs().edi }
+func (c *sigctxt) esi() uint32     { return c.regs().esi }
+func (c *sigctxt) ebp() uint32     { return c.regs().ebp }
+func (c *sigctxt) esp() uint32     { return c.regs().esp }
+func (c *sigctxt) eip() uint32     { return c.regs().eip }
+func (c *sigctxt) eflags() uint32  { return c.regs().eflags }
+func (c *sigctxt) cs() uint32      { return c.regs().cs }
+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 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 = x }
diff --git a/src/runtime/signal_darwin_386.h b/src/runtime/signal_darwin_386.h
deleted file mode 100644
index 5459e10..0000000
--- a/src/runtime/signal_darwin_386.h
+++ /dev/null
@@ -1,23 +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.
-
-#define SIG_REGS(ctxt) (((Ucontext*)(ctxt))->uc_mcontext->ss)
-
-#define SIG_EAX(info, ctxt) (SIG_REGS(ctxt).eax)
-#define SIG_EBX(info, ctxt) (SIG_REGS(ctxt).ebx)
-#define SIG_ECX(info, ctxt) (SIG_REGS(ctxt).ecx)
-#define SIG_EDX(info, ctxt) (SIG_REGS(ctxt).edx)
-#define SIG_EDI(info, ctxt) (SIG_REGS(ctxt).edi)
-#define SIG_ESI(info, ctxt) (SIG_REGS(ctxt).esi)
-#define SIG_EBP(info, ctxt) (SIG_REGS(ctxt).ebp)
-#define SIG_ESP(info, ctxt) (SIG_REGS(ctxt).esp)
-#define SIG_EIP(info, ctxt) (SIG_REGS(ctxt).eip)
-#define SIG_EFLAGS(info, ctxt) (SIG_REGS(ctxt).eflags)
-
-#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).cs)
-#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).fs)
-#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).gs)
-
-#define SIG_CODE0(info, ctxt) ((info)->si_code)
-#define SIG_CODE1(info, ctxt) ((uintptr)(info)->si_addr)
diff --git a/src/runtime/signal_darwin_amd64.go b/src/runtime/signal_darwin_amd64.go
new file mode 100644
index 0000000..dbf0448
--- /dev/null
+++ b/src/runtime/signal_darwin_amd64.go
@@ -0,0 +1,42 @@
+// 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() *regs64   { return &(*ucontext)(c.ctxt).uc_mcontext.ss }
+func (c *sigctxt) rax() uint64     { return c.regs().rax }
+func (c *sigctxt) rbx() uint64     { return c.regs().rbx }
+func (c *sigctxt) rcx() uint64     { return c.regs().rcx }
+func (c *sigctxt) rdx() uint64     { return c.regs().rdx }
+func (c *sigctxt) rdi() uint64     { return c.regs().rdi }
+func (c *sigctxt) rsi() uint64     { return c.regs().rsi }
+func (c *sigctxt) rbp() uint64     { return c.regs().rbp }
+func (c *sigctxt) rsp() uint64     { return c.regs().rsp }
+func (c *sigctxt) r8() uint64      { return c.regs().r8 }
+func (c *sigctxt) r9() uint64      { return c.regs().r9 }
+func (c *sigctxt) r10() uint64     { return c.regs().r10 }
+func (c *sigctxt) r11() uint64     { return c.regs().r11 }
+func (c *sigctxt) r12() uint64     { return c.regs().r12 }
+func (c *sigctxt) r13() uint64     { return c.regs().r13 }
+func (c *sigctxt) r14() uint64     { return c.regs().r14 }
+func (c *sigctxt) r15() uint64     { return c.regs().r15 }
+func (c *sigctxt) rip() uint64     { return c.regs().rip }
+func (c *sigctxt) rflags() uint64  { return c.regs().rflags }
+func (c *sigctxt) cs() uint64      { return c.regs().cs }
+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 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 = x }
diff --git a/src/runtime/signal_darwin_amd64.h b/src/runtime/signal_darwin_amd64.h
deleted file mode 100644
index e3da6de..0000000
--- a/src/runtime/signal_darwin_amd64.h
+++ /dev/null
@@ -1,31 +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.
-
-#define SIG_REGS(ctxt) (((Ucontext*)(ctxt))->uc_mcontext->ss)
-
-#define SIG_RAX(info, ctxt) (SIG_REGS(ctxt).rax)
-#define SIG_RBX(info, ctxt) (SIG_REGS(ctxt).rbx)
-#define SIG_RCX(info, ctxt) (SIG_REGS(ctxt).rcx)
-#define SIG_RDX(info, ctxt) (SIG_REGS(ctxt).rdx)
-#define SIG_RDI(info, ctxt) (SIG_REGS(ctxt).rdi)
-#define SIG_RSI(info, ctxt) (SIG_REGS(ctxt).rsi)
-#define SIG_RBP(info, ctxt) (SIG_REGS(ctxt).rbp)
-#define SIG_RSP(info, ctxt) (SIG_REGS(ctxt).rsp)
-#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).r8)
-#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).r9)
-#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).r10)
-#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).r11)
-#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).r12)
-#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).r13)
-#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).r14)
-#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).r15)
-#define SIG_RIP(info, ctxt) (SIG_REGS(ctxt).rip)
-#define SIG_RFLAGS(info, ctxt) (SIG_REGS(ctxt).rflags)
-
-#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).cs)
-#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).fs)
-#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).gs)
-
-#define SIG_CODE0(info, ctxt) ((info)->si_code)
-#define SIG_CODE1(info, ctxt) ((uintptr)(info)->si_addr)
diff --git a/src/runtime/signal_darwin_arm.go b/src/runtime/signal_darwin_arm.go
new file mode 100644
index 0000000..0f10971
--- /dev/null
+++ b/src/runtime/signal_darwin_arm.go
@@ -0,0 +1,44 @@
+// 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"
+
+type sigctxt struct {
+	info *siginfo
+	ctxt unsafe.Pointer
+}
+
+func (c *sigctxt) regs() *regs32   { return &(*ucontext)(c.ctxt).uc_mcontext.ss }
+func (c *sigctxt) r0() uint32      { return c.regs().r[0] }
+func (c *sigctxt) r1() uint32      { return c.regs().r[1] }
+func (c *sigctxt) r2() uint32      { return c.regs().r[2] }
+func (c *sigctxt) r3() uint32      { return c.regs().r[3] }
+func (c *sigctxt) r4() uint32      { return c.regs().r[4] }
+func (c *sigctxt) r5() uint32      { return c.regs().r[5] }
+func (c *sigctxt) r6() uint32      { return c.regs().r[6] }
+func (c *sigctxt) r7() uint32      { return c.regs().r[7] }
+func (c *sigctxt) r8() uint32      { return c.regs().r[8] }
+func (c *sigctxt) r9() uint32      { return c.regs().r[9] }
+func (c *sigctxt) r10() uint32     { return c.regs().r[10] }
+func (c *sigctxt) fp() uint32      { return c.regs().r[11] }
+func (c *sigctxt) ip() uint32      { return c.regs().r[12] }
+func (c *sigctxt) sp() uint32      { return c.regs().sp }
+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 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 }
+func (c *sigctxt) oldmask() uint32 { return 0 }
+
+func (c *sigctxt) set_pc(x uint32)  { c.regs().pc = x }
+func (c *sigctxt) set_sp(x uint32)  { c.regs().sp = x }
+func (c *sigctxt) set_lr(x uint32)  { c.regs().lr = x }
+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 = x }
diff --git a/src/runtime/signal_darwin_arm64.go b/src/runtime/signal_darwin_arm64.go
new file mode 100644
index 0000000..2df4229
--- /dev/null
+++ b/src/runtime/signal_darwin_arm64.go
@@ -0,0 +1,60 @@
+// 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() *regs64 { return &(*ucontext)(c.ctxt).uc_mcontext.ss }
+func (c *sigctxt) r0() uint64    { return c.regs().x[0] }
+func (c *sigctxt) r1() uint64    { return c.regs().x[1] }
+func (c *sigctxt) r2() uint64    { return c.regs().x[2] }
+func (c *sigctxt) r3() uint64    { return c.regs().x[3] }
+func (c *sigctxt) r4() uint64    { return c.regs().x[4] }
+func (c *sigctxt) r5() uint64    { return c.regs().x[5] }
+func (c *sigctxt) r6() uint64    { return c.regs().x[6] }
+func (c *sigctxt) r7() uint64    { return c.regs().x[7] }
+func (c *sigctxt) r8() uint64    { return c.regs().x[8] }
+func (c *sigctxt) r9() uint64    { return c.regs().x[9] }
+func (c *sigctxt) r10() uint64   { return c.regs().x[10] }
+func (c *sigctxt) r11() uint64   { return c.regs().x[11] }
+func (c *sigctxt) r12() uint64   { return c.regs().x[12] }
+func (c *sigctxt) r13() uint64   { return c.regs().x[13] }
+func (c *sigctxt) r14() uint64   { return c.regs().x[14] }
+func (c *sigctxt) r15() uint64   { return c.regs().x[15] }
+func (c *sigctxt) r16() uint64   { return c.regs().x[16] }
+func (c *sigctxt) r17() uint64   { return c.regs().x[17] }
+func (c *sigctxt) r18() uint64   { return c.regs().x[18] }
+func (c *sigctxt) r19() uint64   { return c.regs().x[19] }
+func (c *sigctxt) r20() uint64   { return c.regs().x[20] }
+func (c *sigctxt) r21() uint64   { return c.regs().x[21] }
+func (c *sigctxt) r22() uint64   { return c.regs().x[22] }
+func (c *sigctxt) r23() uint64   { return c.regs().x[23] }
+func (c *sigctxt) r24() uint64   { return c.regs().x[24] }
+func (c *sigctxt) r25() uint64   { return c.regs().x[25] }
+func (c *sigctxt) r26() uint64   { return c.regs().x[26] }
+func (c *sigctxt) r27() uint64   { return c.regs().x[27] }
+func (c *sigctxt) r28() uint64   { return c.regs().x[28] }
+func (c *sigctxt) r29() uint64   { return c.regs().fp }
+func (c *sigctxt) lr() uint64    { return c.regs().lr }
+func (c *sigctxt) sp() uint64    { return c.regs().sp }
+func (c *sigctxt) pc() uint64    { return c.regs().pc }
+func (c *sigctxt) fault() uint64 { return uint64(uintptr(unsafe.Pointer(c.info.si_addr))) }
+
+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) 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().lr = x }
+func (c *sigctxt) set_r28(x uint64) { c.regs().x[28] = x }
+
+func (c *sigctxt) set_sigaddr(x uint64) {
+	c.info.si_addr = (*byte)(unsafe.Pointer(uintptr(x)))
+}
diff --git a/src/runtime/signal_dragonfly.go b/src/runtime/signal_dragonfly.go
new file mode 100644
index 0000000..d37e11a
--- /dev/null
+++ b/src/runtime/signal_dragonfly.go
@@ -0,0 +1,46 @@
+// 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
+
+type sigTabT struct {
+	flags int32
+	name  string
+}
+
+var sigtable = [...]sigTabT{
+	/* 0 */ {0, "SIGNONE: no trap"},
+	/* 1 */ {_SigNotify + _SigKill, "SIGHUP: terminal line hangup"},
+	/* 2 */ {_SigNotify + _SigKill, "SIGINT: interrupt"},
+	/* 3 */ {_SigNotify + _SigThrow, "SIGQUIT: quit"},
+	/* 4 */ {_SigThrow, "SIGILL: illegal instruction"},
+	/* 5 */ {_SigThrow, "SIGTRAP: trace trap"},
+	/* 6 */ {_SigNotify + _SigThrow, "SIGABRT: abort"},
+	/* 7 */ {_SigThrow, "SIGEMT: emulate instruction executed"},
+	/* 8 */ {_SigPanic, "SIGFPE: floating-point exception"},
+	/* 9 */ {0, "SIGKILL: kill"},
+	/* 10 */ {_SigPanic, "SIGBUS: bus error"},
+	/* 11 */ {_SigPanic, "SIGSEGV: segmentation violation"},
+	/* 12 */ {_SigThrow, "SIGSYS: bad system call"},
+	/* 13 */ {_SigNotify, "SIGPIPE: write to broken pipe"},
+	/* 14 */ {_SigNotify, "SIGALRM: alarm clock"},
+	/* 15 */ {_SigNotify + _SigKill, "SIGTERM: termination"},
+	/* 16 */ {_SigNotify, "SIGURG: urgent condition on socket"},
+	/* 17 */ {0, "SIGSTOP: stop"},
+	/* 18 */ {_SigNotify + _SigDefault, "SIGTSTP: keyboard stop"},
+	/* 19 */ {0, "SIGCONT: continue after stop"},
+	/* 20 */ {_SigNotify, "SIGCHLD: child status has changed"},
+	/* 21 */ {_SigNotify + _SigDefault, "SIGTTIN: background read from tty"},
+	/* 22 */ {_SigNotify + _SigDefault, "SIGTTOU: background write to tty"},
+	/* 23 */ {_SigNotify, "SIGIO: i/o now possible"},
+	/* 24 */ {_SigNotify, "SIGXCPU: cpu limit exceeded"},
+	/* 25 */ {_SigNotify, "SIGXFSZ: file size limit exceeded"},
+	/* 26 */ {_SigNotify, "SIGVTALRM: virtual alarm clock"},
+	/* 27 */ {_SigNotify, "SIGPROF: profiling alarm clock"},
+	/* 28 */ {_SigNotify, "SIGWINCH: window size change"},
+	/* 29 */ {_SigNotify, "SIGINFO: status request from keyboard"},
+	/* 30 */ {_SigNotify, "SIGUSR1: user-defined signal 1"},
+	/* 31 */ {_SigNotify, "SIGUSR2: user-defined signal 2"},
+	/* 32 */ {_SigNotify, "SIGTHR: reserved"},
+}
diff --git a/src/runtime/signal_dragonfly_386.h b/src/runtime/signal_dragonfly_386.h
deleted file mode 100644
index a24f1ee..0000000
--- a/src/runtime/signal_dragonfly_386.h
+++ /dev/null
@@ -1,23 +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.
-
-#define SIG_REGS(ctxt) (((Ucontext*)(ctxt))->uc_mcontext)
-
-#define SIG_EAX(info, ctxt) (SIG_REGS(ctxt).mc_eax)
-#define SIG_EBX(info, ctxt) (SIG_REGS(ctxt).mc_ebx)
-#define SIG_ECX(info, ctxt) (SIG_REGS(ctxt).mc_ecx)
-#define SIG_EDX(info, ctxt) (SIG_REGS(ctxt).mc_edx)
-#define SIG_EDI(info, ctxt) (SIG_REGS(ctxt).mc_edi)
-#define SIG_ESI(info, ctxt) (SIG_REGS(ctxt).mc_esi)
-#define SIG_EBP(info, ctxt) (SIG_REGS(ctxt).mc_ebp)
-#define SIG_ESP(info, ctxt) (SIG_REGS(ctxt).mc_esp)
-#define SIG_EIP(info, ctxt) (SIG_REGS(ctxt).mc_eip)
-#define SIG_EFLAGS(info, ctxt) (SIG_REGS(ctxt).mc_eflags)
-
-#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).mc_cs)
-#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).mc_fs)
-#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).mc_gs)
-
-#define SIG_CODE0(info, ctxt) ((info)->si_code)
-#define SIG_CODE1(info, ctxt) ((uintptr)(info)->si_addr)
diff --git a/src/runtime/signal_dragonfly_amd64.go b/src/runtime/signal_dragonfly_amd64.go
new file mode 100644
index 0000000..740959c
--- /dev/null
+++ b/src/runtime/signal_dragonfly_amd64.go
@@ -0,0 +1,44 @@
+// 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 (*mcontext)(unsafe.Pointer(&(*ucontext)(c.ctxt).uc_mcontext))
+}
+func (c *sigctxt) rax() uint64     { return c.regs().mc_rax }
+func (c *sigctxt) rbx() uint64     { return c.regs().mc_rbx }
+func (c *sigctxt) rcx() uint64     { return c.regs().mc_rcx }
+func (c *sigctxt) rdx() uint64     { return c.regs().mc_rdx }
+func (c *sigctxt) rdi() uint64     { return c.regs().mc_rdi }
+func (c *sigctxt) rsi() uint64     { return c.regs().mc_rsi }
+func (c *sigctxt) rbp() uint64     { return c.regs().mc_rbp }
+func (c *sigctxt) rsp() uint64     { return c.regs().mc_rsp }
+func (c *sigctxt) r8() uint64      { return c.regs().mc_r8 }
+func (c *sigctxt) r9() uint64      { return c.regs().mc_r9 }
+func (c *sigctxt) r10() uint64     { return c.regs().mc_r10 }
+func (c *sigctxt) r11() uint64     { return c.regs().mc_r11 }
+func (c *sigctxt) r12() uint64     { return c.regs().mc_r12 }
+func (c *sigctxt) r13() uint64     { return c.regs().mc_r13 }
+func (c *sigctxt) r14() uint64     { return c.regs().mc_r14 }
+func (c *sigctxt) r15() uint64     { return c.regs().mc_r15 }
+func (c *sigctxt) rip() uint64     { return c.regs().mc_rip }
+func (c *sigctxt) rflags() uint64  { return c.regs().mc_rflags }
+func (c *sigctxt) cs() uint64      { return uint64(c.regs().mc_cs) }
+func (c *sigctxt) fs() uint64      { return uint64(c.regs().mc_ss) }
+func (c *sigctxt) gs() uint64      { return uint64(c.regs().mc_ss) }
+func (c *sigctxt) sigcode() uint64 { return uint64(c.info.si_code) }
+func (c *sigctxt) sigaddr() uint64 { return uint64(c.info.si_addr) }
+
+func (c *sigctxt) set_rip(x uint64)     { c.regs().mc_rip = x }
+func (c *sigctxt) set_rsp(x uint64)     { c.regs().mc_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 = x }
diff --git a/src/runtime/signal_dragonfly_amd64.h b/src/runtime/signal_dragonfly_amd64.h
deleted file mode 100644
index 5b4f977..0000000
--- a/src/runtime/signal_dragonfly_amd64.h
+++ /dev/null
@@ -1,31 +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.
-
-#define SIG_REGS(ctxt) (((Ucontext*)(ctxt))->uc_mcontext)
-
-#define SIG_RAX(info, ctxt) (SIG_REGS(ctxt).mc_rax)
-#define SIG_RBX(info, ctxt) (SIG_REGS(ctxt).mc_rbx)
-#define SIG_RCX(info, ctxt) (SIG_REGS(ctxt).mc_rcx)
-#define SIG_RDX(info, ctxt) (SIG_REGS(ctxt).mc_rdx)
-#define SIG_RDI(info, ctxt) (SIG_REGS(ctxt).mc_rdi)
-#define SIG_RSI(info, ctxt) (SIG_REGS(ctxt).mc_rsi)
-#define SIG_RBP(info, ctxt) (SIG_REGS(ctxt).mc_rbp)
-#define SIG_RSP(info, ctxt) (SIG_REGS(ctxt).mc_rsp)
-#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).mc_r8)
-#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).mc_r9)
-#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).mc_r10)
-#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).mc_r11)
-#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).mc_r12)
-#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).mc_r13)
-#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).mc_r14)
-#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).mc_r15)
-#define SIG_RIP(info, ctxt) (SIG_REGS(ctxt).mc_rip)
-#define SIG_RFLAGS(info, ctxt) (SIG_REGS(ctxt).mc_rflags)
-
-#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).mc_cs)
-#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).mc_ss)
-#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).mc_ss)
-
-#define SIG_CODE0(info, ctxt) ((info)->si_code)
-#define SIG_CODE1(info, ctxt) ((uintptr)(info)->si_addr)
diff --git a/src/runtime/signal_freebsd.go b/src/runtime/signal_freebsd.go
new file mode 100644
index 0000000..1dbdb1b
--- /dev/null
+++ b/src/runtime/signal_freebsd.go
@@ -0,0 +1,46 @@
+// 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
+
+type sigTabT struct {
+	flags int32
+	name  string
+}
+
+var sigtable = [...]sigTabT{
+	/* 0 */ {0, "SIGNONE: no trap"},
+	/* 1 */ {_SigNotify + _SigKill, "SIGHUP: terminal line hangup"},
+	/* 2 */ {_SigNotify + _SigKill, "SIGINT: interrupt"},
+	/* 3 */ {_SigNotify + _SigThrow, "SIGQUIT: quit"},
+	/* 4 */ {_SigThrow, "SIGILL: illegal instruction"},
+	/* 5 */ {_SigThrow, "SIGTRAP: trace trap"},
+	/* 6 */ {_SigNotify + _SigThrow, "SIGABRT: abort"},
+	/* 7 */ {_SigThrow, "SIGEMT: emulate instruction executed"},
+	/* 8 */ {_SigPanic, "SIGFPE: floating-point exception"},
+	/* 9 */ {0, "SIGKILL: kill"},
+	/* 10 */ {_SigPanic, "SIGBUS: bus error"},
+	/* 11 */ {_SigPanic, "SIGSEGV: segmentation violation"},
+	/* 12 */ {_SigNotify, "SIGSYS: bad system call"},
+	/* 13 */ {_SigNotify, "SIGPIPE: write to broken pipe"},
+	/* 14 */ {_SigNotify, "SIGALRM: alarm clock"},
+	/* 15 */ {_SigNotify + _SigKill, "SIGTERM: termination"},
+	/* 16 */ {_SigNotify, "SIGURG: urgent condition on socket"},
+	/* 17 */ {0, "SIGSTOP: stop"},
+	/* 18 */ {_SigNotify + _SigDefault, "SIGTSTP: keyboard stop"},
+	/* 19 */ {0, "SIGCONT: continue after stop"},
+	/* 20 */ {_SigNotify, "SIGCHLD: child status has changed"},
+	/* 21 */ {_SigNotify + _SigDefault, "SIGTTIN: background read from tty"},
+	/* 22 */ {_SigNotify + _SigDefault, "SIGTTOU: background write to tty"},
+	/* 23 */ {_SigNotify, "SIGIO: i/o now possible"},
+	/* 24 */ {_SigNotify, "SIGXCPU: cpu limit exceeded"},
+	/* 25 */ {_SigNotify, "SIGXFSZ: file size limit exceeded"},
+	/* 26 */ {_SigNotify, "SIGVTALRM: virtual alarm clock"},
+	/* 27 */ {_SigNotify, "SIGPROF: profiling alarm clock"},
+	/* 28 */ {_SigNotify, "SIGWINCH: window size change"},
+	/* 29 */ {_SigNotify, "SIGINFO: status request from keyboard"},
+	/* 30 */ {_SigNotify, "SIGUSR1: user-defined signal 1"},
+	/* 31 */ {_SigNotify, "SIGUSR2: user-defined signal 2"},
+	/* 32 */ {_SigNotify, "SIGTHR: reserved"},
+}
diff --git a/src/runtime/signal_freebsd_386.go b/src/runtime/signal_freebsd_386.go
new file mode 100644
index 0000000..a0fec13
--- /dev/null
+++ b/src/runtime/signal_freebsd_386.go
@@ -0,0 +1,34 @@
+// 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_freebsd_386.h b/src/runtime/signal_freebsd_386.h
deleted file mode 100644
index a24f1ee..0000000
--- a/src/runtime/signal_freebsd_386.h
+++ /dev/null
@@ -1,23 +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.
-
-#define SIG_REGS(ctxt) (((Ucontext*)(ctxt))->uc_mcontext)
-
-#define SIG_EAX(info, ctxt) (SIG_REGS(ctxt).mc_eax)
-#define SIG_EBX(info, ctxt) (SIG_REGS(ctxt).mc_ebx)
-#define SIG_ECX(info, ctxt) (SIG_REGS(ctxt).mc_ecx)
-#define SIG_EDX(info, ctxt) (SIG_REGS(ctxt).mc_edx)
-#define SIG_EDI(info, ctxt) (SIG_REGS(ctxt).mc_edi)
-#define SIG_ESI(info, ctxt) (SIG_REGS(ctxt).mc_esi)
-#define SIG_EBP(info, ctxt) (SIG_REGS(ctxt).mc_ebp)
-#define SIG_ESP(info, ctxt) (SIG_REGS(ctxt).mc_esp)
-#define SIG_EIP(info, ctxt) (SIG_REGS(ctxt).mc_eip)
-#define SIG_EFLAGS(info, ctxt) (SIG_REGS(ctxt).mc_eflags)
-
-#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).mc_cs)
-#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).mc_fs)
-#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).mc_gs)
-
-#define SIG_CODE0(info, ctxt) ((info)->si_code)
-#define SIG_CODE1(info, ctxt) ((uintptr)(info)->si_addr)
diff --git a/src/runtime/signal_freebsd_amd64.go b/src/runtime/signal_freebsd_amd64.go
new file mode 100644
index 0000000..d10c883
--- /dev/null
+++ b/src/runtime/signal_freebsd_amd64.go
@@ -0,0 +1,44 @@
+// 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 (*mcontext)(unsafe.Pointer(&(*ucontext)(c.ctxt).uc_mcontext))
+}
+func (c *sigctxt) rax() uint64     { return c.regs().mc_rax }
+func (c *sigctxt) rbx() uint64     { return c.regs().mc_rbx }
+func (c *sigctxt) rcx() uint64     { return c.regs().mc_rcx }
+func (c *sigctxt) rdx() uint64     { return c.regs().mc_rdx }
+func (c *sigctxt) rdi() uint64     { return c.regs().mc_rdi }
+func (c *sigctxt) rsi() uint64     { return c.regs().mc_rsi }
+func (c *sigctxt) rbp() uint64     { return c.regs().mc_rbp }
+func (c *sigctxt) rsp() uint64     { return c.regs().mc_rsp }
+func (c *sigctxt) r8() uint64      { return c.regs().mc_r8 }
+func (c *sigctxt) r9() uint64      { return c.regs().mc_r9 }
+func (c *sigctxt) r10() uint64     { return c.regs().mc_r10 }
+func (c *sigctxt) r11() uint64     { return c.regs().mc_r11 }
+func (c *sigctxt) r12() uint64     { return c.regs().mc_r12 }
+func (c *sigctxt) r13() uint64     { return c.regs().mc_r13 }
+func (c *sigctxt) r14() uint64     { return c.regs().mc_r14 }
+func (c *sigctxt) r15() uint64     { return c.regs().mc_r15 }
+func (c *sigctxt) rip() uint64     { return c.regs().mc_rip }
+func (c *sigctxt) rflags() uint64  { return c.regs().mc_rflags }
+func (c *sigctxt) cs() uint64      { return uint64(c.regs().mc_cs) }
+func (c *sigctxt) fs() uint64      { return uint64(c.regs().mc_fs) }
+func (c *sigctxt) gs() uint64      { return uint64(c.regs().mc_gs) }
+func (c *sigctxt) sigcode() uint64 { return uint64(c.info.si_code) }
+func (c *sigctxt) sigaddr() uint64 { return uint64(c.info.si_addr) }
+
+func (c *sigctxt) set_rip(x uint64)     { c.regs().mc_rip = x }
+func (c *sigctxt) set_rsp(x uint64)     { c.regs().mc_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 = x }
diff --git a/src/runtime/signal_freebsd_amd64.h b/src/runtime/signal_freebsd_amd64.h
deleted file mode 100644
index 7d35b7f..0000000
--- a/src/runtime/signal_freebsd_amd64.h
+++ /dev/null
@@ -1,31 +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.
-
-#define SIG_REGS(ctxt) (((Ucontext*)(ctxt))->uc_mcontext)
-
-#define SIG_RAX(info, ctxt) (SIG_REGS(ctxt).mc_rax)
-#define SIG_RBX(info, ctxt) (SIG_REGS(ctxt).mc_rbx)
-#define SIG_RCX(info, ctxt) (SIG_REGS(ctxt).mc_rcx)
-#define SIG_RDX(info, ctxt) (SIG_REGS(ctxt).mc_rdx)
-#define SIG_RDI(info, ctxt) (SIG_REGS(ctxt).mc_rdi)
-#define SIG_RSI(info, ctxt) (SIG_REGS(ctxt).mc_rsi)
-#define SIG_RBP(info, ctxt) (SIG_REGS(ctxt).mc_rbp)
-#define SIG_RSP(info, ctxt) (SIG_REGS(ctxt).mc_rsp)
-#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).mc_r8)
-#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).mc_r9)
-#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).mc_r10)
-#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).mc_r11)
-#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).mc_r12)
-#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).mc_r13)
-#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).mc_r14)
-#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).mc_r15)
-#define SIG_RIP(info, ctxt) (SIG_REGS(ctxt).mc_rip)
-#define SIG_RFLAGS(info, ctxt) (SIG_REGS(ctxt).mc_rflags)
-
-#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).mc_cs)
-#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).mc_fs)
-#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).mc_gs)
-
-#define SIG_CODE0(info, ctxt) ((info)->si_code)
-#define SIG_CODE1(info, ctxt) ((uintptr)(info)->si_addr)
diff --git a/src/runtime/signal_freebsd_arm.go b/src/runtime/signal_freebsd_arm.go
new file mode 100644
index 0000000..12de23d
--- /dev/null
+++ b/src/runtime/signal_freebsd_arm.go
@@ -0,0 +1,48 @@
+// 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) r0() uint32      { return c.regs().__gregs[0] }
+func (c *sigctxt) r1() uint32      { return c.regs().__gregs[1] }
+func (c *sigctxt) r2() uint32      { return c.regs().__gregs[2] }
+func (c *sigctxt) r3() uint32      { return c.regs().__gregs[3] }
+func (c *sigctxt) r4() uint32      { return c.regs().__gregs[4] }
+func (c *sigctxt) r5() uint32      { return c.regs().__gregs[5] }
+func (c *sigctxt) r6() uint32      { return c.regs().__gregs[6] }
+func (c *sigctxt) r7() uint32      { return c.regs().__gregs[7] }
+func (c *sigctxt) r8() uint32      { return c.regs().__gregs[8] }
+func (c *sigctxt) r9() uint32      { return c.regs().__gregs[9] }
+func (c *sigctxt) r10() uint32     { return c.regs().__gregs[10] }
+func (c *sigctxt) fp() uint32      { return c.regs().__gregs[11] }
+func (c *sigctxt) ip() uint32      { return c.regs().__gregs[12] }
+func (c *sigctxt) sp() uint32      { return c.regs().__gregs[13] }
+func (c *sigctxt) lr() uint32      { return c.regs().__gregs[14] }
+func (c *sigctxt) pc() uint32      { return c.regs().__gregs[15] }
+func (c *sigctxt) cpsr() uint32    { return c.regs().__gregs[16] }
+func (c *sigctxt) fault() uint32   { return uint32(c.info.si_addr) }
+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(c.info.si_addr) }
+
+func (c *sigctxt) set_pc(x uint32)  { c.regs().__gregs[15] = x }
+func (c *sigctxt) set_sp(x uint32)  { c.regs().__gregs[13] = x }
+func (c *sigctxt) set_lr(x uint32)  { c.regs().__gregs[14] = x }
+func (c *sigctxt) set_r10(x uint32) { c.regs().__gregs[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 = uintptr(x)
+}
diff --git a/src/runtime/signal_freebsd_arm.h b/src/runtime/signal_freebsd_arm.h
deleted file mode 100644
index 87a45aa..0000000
--- a/src/runtime/signal_freebsd_arm.h
+++ /dev/null
@@ -1,28 +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.
-
-#define SIG_REGS(ctxt) (((Ucontext*)(ctxt))->uc_mcontext)
-
-#define SIG_R0(info, ctxt) (SIG_REGS(ctxt).__gregs[0])
-#define SIG_R1(info, ctxt) (SIG_REGS(ctxt).__gregs[1])
-#define SIG_R2(info, ctxt) (SIG_REGS(ctxt).__gregs[2])
-#define SIG_R3(info, ctxt) (SIG_REGS(ctxt).__gregs[3])
-#define SIG_R4(info, ctxt) (SIG_REGS(ctxt).__gregs[4])
-#define SIG_R5(info, ctxt) (SIG_REGS(ctxt).__gregs[5])
-#define SIG_R6(info, ctxt) (SIG_REGS(ctxt).__gregs[6])
-#define SIG_R7(info, ctxt) (SIG_REGS(ctxt).__gregs[7])
-#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).__gregs[8])
-#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).__gregs[9])
-#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).__gregs[10])
-#define SIG_FP(info, ctxt) (SIG_REGS(ctxt).__gregs[11])
-#define SIG_IP(info, ctxt) (SIG_REGS(ctxt).__gregs[12])
-#define SIG_SP(info, ctxt) (SIG_REGS(ctxt).__gregs[13])
-#define SIG_LR(info, ctxt) (SIG_REGS(ctxt).__gregs[14])
-#define SIG_PC(info, ctxt) (SIG_REGS(ctxt).__gregs[15])
-#define SIG_CPSR(info, ctxt) (SIG_REGS(ctxt).__gregs[16])
-#define SIG_FAULT(info, ctxt) ((uintptr)(info)->si_addr)
-#define SIG_TRAP(info, ctxt) (0)
-#define SIG_ERROR(info, ctxt) (0)
-#define SIG_OLDMASK(info, ctxt) (0)
-#define SIG_CODE0(info, ctxt) ((uintptr)(info)->si_code)
diff --git a/src/runtime/signal_linux.go b/src/runtime/signal_linux.go
new file mode 100644
index 0000000..2f25b59
--- /dev/null
+++ b/src/runtime/signal_linux.go
@@ -0,0 +1,96 @@
+// 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"
+
+type sigTabT struct {
+	flags int32
+	name  string
+}
+
+var sigtable = [...]sigTabT{
+	/* 0 */ {0, "SIGNONE: no trap"},
+	/* 1 */ {_SigNotify + _SigKill, "SIGHUP: terminal line hangup"},
+	/* 2 */ {_SigNotify + _SigKill, "SIGINT: interrupt"},
+	/* 3 */ {_SigNotify + _SigThrow, "SIGQUIT: quit"},
+	/* 4 */ {_SigThrow + _SigUnblock, "SIGILL: illegal instruction"},
+	/* 5 */ {_SigThrow + _SigUnblock, "SIGTRAP: trace trap"},
+	/* 6 */ {_SigNotify + _SigThrow, "SIGABRT: abort"},
+	/* 7 */ {_SigPanic + _SigUnblock, "SIGBUS: bus error"},
+	/* 8 */ {_SigPanic + _SigUnblock, "SIGFPE: floating-point exception"},
+	/* 9 */ {0, "SIGKILL: kill"},
+	/* 10 */ {_SigNotify, "SIGUSR1: user-defined signal 1"},
+	/* 11 */ {_SigPanic + _SigUnblock, "SIGSEGV: segmentation violation"},
+	/* 12 */ {_SigNotify, "SIGUSR2: user-defined signal 2"},
+	/* 13 */ {_SigNotify, "SIGPIPE: write to broken pipe"},
+	/* 14 */ {_SigNotify, "SIGALRM: alarm clock"},
+	/* 15 */ {_SigNotify + _SigKill, "SIGTERM: termination"},
+	/* 16 */ {_SigThrow + _SigUnblock, "SIGSTKFLT: stack fault"},
+	/* 17 */ {_SigNotify + _SigUnblock, "SIGCHLD: child status has changed"},
+	/* 18 */ {0, "SIGCONT: continue"},
+	/* 19 */ {0, "SIGSTOP: stop, unblockable"},
+	/* 20 */ {_SigNotify + _SigDefault, "SIGTSTP: keyboard stop"},
+	/* 21 */ {_SigNotify + _SigDefault, "SIGTTIN: background read from tty"},
+	/* 22 */ {_SigNotify + _SigDefault, "SIGTTOU: background write to tty"},
+	/* 23 */ {_SigNotify, "SIGURG: urgent condition on socket"},
+	/* 24 */ {_SigNotify, "SIGXCPU: cpu limit exceeded"},
+	/* 25 */ {_SigNotify, "SIGXFSZ: file size limit exceeded"},
+	/* 26 */ {_SigNotify, "SIGVTALRM: virtual alarm clock"},
+	/* 27 */ {_SigNotify + _SigUnblock, "SIGPROF: profiling alarm clock"},
+	/* 28 */ {_SigNotify, "SIGWINCH: window size change"},
+	/* 29 */ {_SigNotify, "SIGIO: i/o now possible"},
+	/* 30 */ {_SigNotify, "SIGPWR: power failure restart"},
+	/* 31 */ {_SigNotify, "SIGSYS: bad system call"},
+	/* 32 */ {_SigSetStack, "signal 32"}, /* SIGCANCEL; see issue 6997 */
+	/* 33 */ {_SigSetStack, "signal 33"}, /* SIGSETXID; see issue 3871, 9400 */
+	/* 34 */ {_SigNotify, "signal 34"},
+	/* 35 */ {_SigNotify, "signal 35"},
+	/* 36 */ {_SigNotify, "signal 36"},
+	/* 37 */ {_SigNotify, "signal 37"},
+	/* 38 */ {_SigNotify, "signal 38"},
+	/* 39 */ {_SigNotify, "signal 39"},
+	/* 40 */ {_SigNotify, "signal 40"},
+	/* 41 */ {_SigNotify, "signal 41"},
+	/* 42 */ {_SigNotify, "signal 42"},
+	/* 43 */ {_SigNotify, "signal 43"},
+	/* 44 */ {_SigNotify, "signal 44"},
+	/* 45 */ {_SigNotify, "signal 45"},
+	/* 46 */ {_SigNotify, "signal 46"},
+	/* 47 */ {_SigNotify, "signal 47"},
+	/* 48 */ {_SigNotify, "signal 48"},
+	/* 49 */ {_SigNotify, "signal 49"},
+	/* 50 */ {_SigNotify, "signal 50"},
+	/* 51 */ {_SigNotify, "signal 51"},
+	/* 52 */ {_SigNotify, "signal 52"},
+	/* 53 */ {_SigNotify, "signal 53"},
+	/* 54 */ {_SigNotify, "signal 54"},
+	/* 55 */ {_SigNotify, "signal 55"},
+	/* 56 */ {_SigNotify, "signal 56"},
+	/* 57 */ {_SigNotify, "signal 57"},
+	/* 58 */ {_SigNotify, "signal 58"},
+	/* 59 */ {_SigNotify, "signal 59"},
+	/* 60 */ {_SigNotify, "signal 60"},
+	/* 61 */ {_SigNotify, "signal 61"},
+	/* 62 */ {_SigNotify, "signal 62"},
+	/* 63 */ {_SigNotify, "signal 63"},
+	/* 64 */ {_SigNotify, "signal 64"},
+}
+
+// Continuation of the (assembly) sigtramp() logic.
+//go:nosplit
+func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) {
+	if sigfwdgo(sig, info, ctx) {
+		return
+	}
+	g := getg()
+	if g == nil {
+		badsignal(uintptr(sig))
+		return
+	}
+	setg(g.m.gsignal)
+	sighandler(sig, info, ctx, g)
+	setg(g)
+}
diff --git a/src/runtime/signal_linux_386.go b/src/runtime/signal_linux_386.go
new file mode 100644
index 0000000..085f66e
--- /dev/null
+++ b/src/runtime/signal_linux_386.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"
+
+type sigctxt struct {
+	info *siginfo
+	ctxt unsafe.Pointer
+}
+
+func (c *sigctxt) regs() *sigcontext { return &(*ucontext)(c.ctxt).uc_mcontext }
+func (c *sigctxt) eax() uint32       { return c.regs().eax }
+func (c *sigctxt) ebx() uint32       { return c.regs().ebx }
+func (c *sigctxt) ecx() uint32       { return c.regs().ecx }
+func (c *sigctxt) edx() uint32       { return c.regs().edx }
+func (c *sigctxt) edi() uint32       { return c.regs().edi }
+func (c *sigctxt) esi() uint32       { return c.regs().esi }
+func (c *sigctxt) ebp() uint32       { return c.regs().ebp }
+func (c *sigctxt) esp() uint32       { return c.regs().esp }
+func (c *sigctxt) eip() uint32       { return c.regs().eip }
+func (c *sigctxt) eflags() uint32    { return c.regs().eflags }
+func (c *sigctxt) cs() uint32        { return uint32(c.regs().cs) }
+func (c *sigctxt) fs() uint32        { return uint32(c.regs().fs) }
+func (c *sigctxt) gs() uint32        { return uint32(c.regs().gs) }
+func (c *sigctxt) sigcode() uint32   { return uint32(c.info.si_code) }
+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) {
+	*(*uintptr)(add(unsafe.Pointer(c.info), 2*ptrSize)) = uintptr(x)
+}
diff --git a/src/runtime/signal_linux_386.h b/src/runtime/signal_linux_386.h
deleted file mode 100644
index f77f1c9..0000000
--- a/src/runtime/signal_linux_386.h
+++ /dev/null
@@ -1,24 +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.
-
-#define SIG_REGS(ctxt) (*((Sigcontext*)&((Ucontext*)(ctxt))->uc_mcontext))
-
-#define SIG_EAX(info, ctxt) (SIG_REGS(ctxt).eax)
-#define SIG_EBX(info, ctxt) (SIG_REGS(ctxt).ebx)
-#define SIG_ECX(info, ctxt) (SIG_REGS(ctxt).ecx)
-#define SIG_EDX(info, ctxt) (SIG_REGS(ctxt).edx)
-#define SIG_EDI(info, ctxt) (SIG_REGS(ctxt).edi)
-#define SIG_ESI(info, ctxt) (SIG_REGS(ctxt).esi)
-#define SIG_EBP(info, ctxt) (SIG_REGS(ctxt).ebp)
-#define SIG_ESP(info, ctxt) (SIG_REGS(ctxt).esp)
-#define SIG_EIP(info, ctxt) (SIG_REGS(ctxt).eip)
-#define SIG_EFLAGS(info, ctxt) (SIG_REGS(ctxt).eflags)
-
-#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).cs)
-#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).fs)
-#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).gs)
-
-#define SIG_CODE0(info, ctxt) ((info)->si_code)
-#define SIG_CODE1(info, ctxt) (((uintptr*)(info))[2])
-
diff --git a/src/runtime/signal_linux_amd64.go b/src/runtime/signal_linux_amd64.go
new file mode 100644
index 0000000..5e339b8
--- /dev/null
+++ b/src/runtime/signal_linux_amd64.go
@@ -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.
+
+package runtime
+
+import "unsafe"
+
+type sigctxt struct {
+	info *siginfo
+	ctxt unsafe.Pointer
+}
+
+func (c *sigctxt) regs() *sigcontext {
+	return (*sigcontext)(unsafe.Pointer(&(*ucontext)(c.ctxt).uc_mcontext))
+}
+func (c *sigctxt) rax() uint64     { return c.regs().rax }
+func (c *sigctxt) rbx() uint64     { return c.regs().rbx }
+func (c *sigctxt) rcx() uint64     { return c.regs().rcx }
+func (c *sigctxt) rdx() uint64     { return c.regs().rdx }
+func (c *sigctxt) rdi() uint64     { return c.regs().rdi }
+func (c *sigctxt) rsi() uint64     { return c.regs().rsi }
+func (c *sigctxt) rbp() uint64     { return c.regs().rbp }
+func (c *sigctxt) rsp() uint64     { return c.regs().rsp }
+func (c *sigctxt) r8() uint64      { return c.regs().r8 }
+func (c *sigctxt) r9() uint64      { return c.regs().r9 }
+func (c *sigctxt) r10() uint64     { return c.regs().r10 }
+func (c *sigctxt) r11() uint64     { return c.regs().r11 }
+func (c *sigctxt) r12() uint64     { return c.regs().r12 }
+func (c *sigctxt) r13() uint64     { return c.regs().r13 }
+func (c *sigctxt) r14() uint64     { return c.regs().r14 }
+func (c *sigctxt) r15() uint64     { return c.regs().r15 }
+func (c *sigctxt) rip() uint64     { return c.regs().rip }
+func (c *sigctxt) rflags() uint64  { return c.regs().eflags }
+func (c *sigctxt) cs() uint64      { return uint64(c.regs().cs) }
+func (c *sigctxt) fs() uint64      { return uint64(c.regs().fs) }
+func (c *sigctxt) gs() uint64      { return uint64(c.regs().gs) }
+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_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) {
+	*(*uintptr)(add(unsafe.Pointer(c.info), 2*ptrSize)) = uintptr(x)
+}
diff --git a/src/runtime/signal_linux_amd64.h b/src/runtime/signal_linux_amd64.h
deleted file mode 100644
index 5a9a3e5..0000000
--- a/src/runtime/signal_linux_amd64.h
+++ /dev/null
@@ -1,32 +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.
-
-#define SIG_REGS(ctxt) (*((Sigcontext*)&((Ucontext*)(ctxt))->uc_mcontext))
-
-#define SIG_RAX(info, ctxt) (SIG_REGS(ctxt).rax)
-#define SIG_RBX(info, ctxt) (SIG_REGS(ctxt).rbx)
-#define SIG_RCX(info, ctxt) (SIG_REGS(ctxt).rcx)
-#define SIG_RDX(info, ctxt) (SIG_REGS(ctxt).rdx)
-#define SIG_RDI(info, ctxt) (SIG_REGS(ctxt).rdi)
-#define SIG_RSI(info, ctxt) (SIG_REGS(ctxt).rsi)
-#define SIG_RBP(info, ctxt) (SIG_REGS(ctxt).rbp)
-#define SIG_RSP(info, ctxt) (SIG_REGS(ctxt).rsp)
-#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).r8)
-#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).r9)
-#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).r10)
-#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).r11)
-#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).r12)
-#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).r13)
-#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).r14)
-#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).r15)
-#define SIG_RIP(info, ctxt) (SIG_REGS(ctxt).rip)
-#define SIG_RFLAGS(info, ctxt) ((uint64)SIG_REGS(ctxt).eflags)
-
-#define SIG_CS(info, ctxt) ((uint64)SIG_REGS(ctxt).cs)
-#define SIG_FS(info, ctxt) ((uint64)SIG_REGS(ctxt).fs)
-#define SIG_GS(info, ctxt) ((uint64)SIG_REGS(ctxt).gs)
-
-#define SIG_CODE0(info, ctxt) ((info)->si_code)
-#define SIG_CODE1(info, ctxt) (((uintptr*)(info))[2])
-
diff --git a/src/runtime/signal_linux_arm.go b/src/runtime/signal_linux_arm.go
new file mode 100644
index 0000000..bdb4314
--- /dev/null
+++ b/src/runtime/signal_linux_arm.go
@@ -0,0 +1,48 @@
+// 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 &(*ucontext)(c.ctxt).uc_mcontext }
+func (c *sigctxt) r0() uint32        { return c.regs().r0 }
+func (c *sigctxt) r1() uint32        { return c.regs().r1 }
+func (c *sigctxt) r2() uint32        { return c.regs().r2 }
+func (c *sigctxt) r3() uint32        { return c.regs().r3 }
+func (c *sigctxt) r4() uint32        { return c.regs().r4 }
+func (c *sigctxt) r5() uint32        { return c.regs().r5 }
+func (c *sigctxt) r6() uint32        { return c.regs().r6 }
+func (c *sigctxt) r7() uint32        { return c.regs().r7 }
+func (c *sigctxt) r8() uint32        { return c.regs().r8 }
+func (c *sigctxt) r9() uint32        { return c.regs().r9 }
+func (c *sigctxt) r10() uint32       { return c.regs().r10 }
+func (c *sigctxt) fp() uint32        { return c.regs().fp }
+func (c *sigctxt) ip() uint32        { return c.regs().ip }
+func (c *sigctxt) sp() uint32        { return c.regs().sp }
+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 c.regs().fault_address }
+func (c *sigctxt) trap() uint32      { return c.regs().trap_no }
+func (c *sigctxt) error() uint32     { return c.regs().error_code }
+func (c *sigctxt) oldmask() uint32   { return c.regs().oldmask }
+
+func (c *sigctxt) sigcode() uint32 { return uint32(c.info.si_code) }
+func (c *sigctxt) sigaddr() uint32 { return c.info.si_addr }
+
+func (c *sigctxt) set_pc(x uint32)  { c.regs().pc = x }
+func (c *sigctxt) set_sp(x uint32)  { c.regs().sp = x }
+func (c *sigctxt) set_lr(x uint32)  { c.regs().lr = x }
+func (c *sigctxt) set_r10(x uint32) { c.regs().r10 = x }
+
+func (c *sigctxt) set_sigcode(x uint32) { c.info.si_code = int32(x) }
+func (c *sigctxt) set_sigaddr(x uint32) {
+	*(*uintptr)(add(unsafe.Pointer(c.info), 2*ptrSize)) = uintptr(x)
+}
diff --git a/src/runtime/signal_linux_arm.h b/src/runtime/signal_linux_arm.h
deleted file mode 100644
index a674c0d..0000000
--- a/src/runtime/signal_linux_arm.h
+++ /dev/null
@@ -1,28 +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.
-
-#define SIG_REGS(ctxt) (*((Sigcontext*)&((Ucontext*)(ctxt))->uc_mcontext))
-
-#define SIG_R0(info, ctxt) (SIG_REGS(ctxt).arm_r0)
-#define SIG_R1(info, ctxt) (SIG_REGS(ctxt).arm_r1)
-#define SIG_R2(info, ctxt) (SIG_REGS(ctxt).arm_r2)
-#define SIG_R3(info, ctxt) (SIG_REGS(ctxt).arm_r3)
-#define SIG_R4(info, ctxt) (SIG_REGS(ctxt).arm_r4)
-#define SIG_R5(info, ctxt) (SIG_REGS(ctxt).arm_r5)
-#define SIG_R6(info, ctxt) (SIG_REGS(ctxt).arm_r6)
-#define SIG_R7(info, ctxt) (SIG_REGS(ctxt).arm_r7)
-#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).arm_r8)
-#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).arm_r9)
-#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).arm_r10)
-#define SIG_FP(info, ctxt) (SIG_REGS(ctxt).arm_fp)
-#define SIG_IP(info, ctxt) (SIG_REGS(ctxt).arm_ip)
-#define SIG_SP(info, ctxt) (SIG_REGS(ctxt).arm_sp)
-#define SIG_LR(info, ctxt) (SIG_REGS(ctxt).arm_lr)
-#define SIG_PC(info, ctxt) (SIG_REGS(ctxt).arm_pc)
-#define SIG_CPSR(info, ctxt) (SIG_REGS(ctxt).arm_cpsr)
-#define SIG_FAULT(info, ctxt) (SIG_REGS(ctxt).fault_address)
-#define SIG_TRAP(info, ctxt) (SIG_REGS(ctxt).trap_no)
-#define SIG_ERROR(info, ctxt) (SIG_REGS(ctxt).error_code)
-#define SIG_OLDMASK(info, ctxt) (SIG_REGS(ctxt).oldmask)
-#define SIG_CODE0(info, ctxt) ((uintptr)(info)->si_code)
diff --git a/src/runtime/signal_linux_arm64.go b/src/runtime/signal_linux_arm64.go
new file mode 100644
index 0000000..7d8b010
--- /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_linux_ppc64x.go b/src/runtime/signal_linux_ppc64x.go
new file mode 100644
index 0000000..da3afc9
--- /dev/null
+++ b/src/runtime/signal_linux_ppc64x.go
@@ -0,0 +1,71 @@
+// 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
+// +build ppc64 ppc64le
+
+package runtime
+
+import "unsafe"
+
+type sigctxt struct {
+	info *siginfo
+	ctxt unsafe.Pointer
+}
+
+func (c *sigctxt) regs() *ptregs { return (*ucontext)(c.ctxt).uc_mcontext.regs }
+func (c *sigctxt) r0() uint64    { return c.regs().gpr[0] }
+func (c *sigctxt) r1() uint64    { return c.regs().gpr[1] }
+func (c *sigctxt) r2() uint64    { return c.regs().gpr[2] }
+func (c *sigctxt) r3() uint64    { return c.regs().gpr[3] }
+func (c *sigctxt) r4() uint64    { return c.regs().gpr[4] }
+func (c *sigctxt) r5() uint64    { return c.regs().gpr[5] }
+func (c *sigctxt) r6() uint64    { return c.regs().gpr[6] }
+func (c *sigctxt) r7() uint64    { return c.regs().gpr[7] }
+func (c *sigctxt) r8() uint64    { return c.regs().gpr[8] }
+func (c *sigctxt) r9() uint64    { return c.regs().gpr[9] }
+func (c *sigctxt) r10() uint64   { return c.regs().gpr[10] }
+func (c *sigctxt) r11() uint64   { return c.regs().gpr[11] }
+func (c *sigctxt) r12() uint64   { return c.regs().gpr[12] }
+func (c *sigctxt) r13() uint64   { return c.regs().gpr[13] }
+func (c *sigctxt) r14() uint64   { return c.regs().gpr[14] }
+func (c *sigctxt) r15() uint64   { return c.regs().gpr[15] }
+func (c *sigctxt) r16() uint64   { return c.regs().gpr[16] }
+func (c *sigctxt) r17() uint64   { return c.regs().gpr[17] }
+func (c *sigctxt) r18() uint64   { return c.regs().gpr[18] }
+func (c *sigctxt) r19() uint64   { return c.regs().gpr[19] }
+func (c *sigctxt) r20() uint64   { return c.regs().gpr[20] }
+func (c *sigctxt) r21() uint64   { return c.regs().gpr[21] }
+func (c *sigctxt) r22() uint64   { return c.regs().gpr[22] }
+func (c *sigctxt) r23() uint64   { return c.regs().gpr[23] }
+func (c *sigctxt) r24() uint64   { return c.regs().gpr[24] }
+func (c *sigctxt) r25() uint64   { return c.regs().gpr[25] }
+func (c *sigctxt) r26() uint64   { return c.regs().gpr[26] }
+func (c *sigctxt) r27() uint64   { return c.regs().gpr[27] }
+func (c *sigctxt) r28() uint64   { return c.regs().gpr[28] }
+func (c *sigctxt) r29() uint64   { return c.regs().gpr[29] }
+func (c *sigctxt) r30() uint64   { return c.regs().gpr[30] }
+func (c *sigctxt) r31() uint64   { return c.regs().gpr[31] }
+func (c *sigctxt) sp() uint64    { return c.regs().gpr[1] }
+func (c *sigctxt) pc() uint64    { return c.regs().nip }
+func (c *sigctxt) trap() uint64  { return c.regs().trap }
+func (c *sigctxt) ctr() uint64   { return c.regs().ctr }
+func (c *sigctxt) link() uint64  { return c.regs().link }
+func (c *sigctxt) xer() uint64   { return c.regs().xer }
+func (c *sigctxt) ccr() uint64   { return c.regs().ccr }
+
+func (c *sigctxt) sigcode() uint32 { return uint32(c.info.si_code) }
+func (c *sigctxt) sigaddr() uint64 { return c.info.si_addr }
+func (c *sigctxt) fault() uint64   { return c.regs().dar }
+
+func (c *sigctxt) set_r0(x uint64)   { c.regs().gpr[0] = x }
+func (c *sigctxt) set_r30(x uint64)  { c.regs().gpr[30] = x }
+func (c *sigctxt) set_pc(x uint64)   { c.regs().nip = x }
+func (c *sigctxt) set_sp(x uint64)   { c.regs().gpr[1] = x }
+func (c *sigctxt) set_link(x uint64) { c.regs().link = x }
+
+func (c *sigctxt) set_sigcode(x uint32) { c.info.si_code = int32(x) }
+func (c *sigctxt) set_sigaddr(x uint64) {
+	*(*uintptr)(add(unsafe.Pointer(c.info), 2*ptrSize)) = uintptr(x)
+}
diff --git a/src/runtime/signal_nacl.go b/src/runtime/signal_nacl.go
new file mode 100644
index 0000000..122648b
--- /dev/null
+++ b/src/runtime/signal_nacl.go
@@ -0,0 +1,45 @@
+// 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
+
+type sigTabT struct {
+	flags int32
+	name  string
+}
+
+var sigtable = [...]sigTabT{
+	/* 0 */ {0, "SIGNONE: no trap"},
+	/* 1 */ {_SigNotify + _SigKill, "SIGHUP: terminal line hangup"},
+	/* 2 */ {_SigNotify + _SigKill, "SIGINT: interrupt"},
+	/* 3 */ {_SigNotify + _SigThrow, "SIGQUIT: quit"},
+	/* 4 */ {_SigThrow, "SIGILL: illegal instruction"},
+	/* 5 */ {_SigThrow, "SIGTRAP: trace trap"},
+	/* 6 */ {_SigNotify + _SigThrow, "SIGABRT: abort"},
+	/* 7 */ {_SigThrow, "SIGEMT: emulate instruction executed"},
+	/* 8 */ {_SigPanic, "SIGFPE: floating-point exception"},
+	/* 9 */ {0, "SIGKILL: kill"},
+	/* 10 */ {_SigPanic, "SIGBUS: bus error"},
+	/* 11 */ {_SigPanic, "SIGSEGV: segmentation violation"},
+	/* 12 */ {_SigThrow, "SIGSYS: bad system call"},
+	/* 13 */ {_SigNotify, "SIGPIPE: write to broken pipe"},
+	/* 14 */ {_SigNotify, "SIGALRM: alarm clock"},
+	/* 15 */ {_SigNotify + _SigKill, "SIGTERM: termination"},
+	/* 16 */ {_SigNotify, "SIGURG: urgent condition on socket"},
+	/* 17 */ {0, "SIGSTOP: stop"},
+	/* 18 */ {_SigNotify + _SigDefault, "SIGTSTP: keyboard stop"},
+	/* 19 */ {0, "SIGCONT: continue after stop"},
+	/* 20 */ {_SigNotify, "SIGCHLD: child status has changed"},
+	/* 21 */ {_SigNotify + _SigDefault, "SIGTTIN: background read from tty"},
+	/* 22 */ {_SigNotify + _SigDefault, "SIGTTOU: background write to tty"},
+	/* 23 */ {_SigNotify, "SIGIO: i/o now possible"},
+	/* 24 */ {_SigNotify, "SIGXCPU: cpu limit exceeded"},
+	/* 25 */ {_SigNotify, "SIGXFSZ: file size limit exceeded"},
+	/* 26 */ {_SigNotify, "SIGVTALRM: virtual alarm clock"},
+	/* 27 */ {_SigNotify, "SIGPROF: profiling alarm clock"},
+	/* 28 */ {_SigNotify, "SIGWINCH: window size change"},
+	/* 29 */ {_SigNotify, "SIGINFO: status request from keyboard"},
+	/* 30 */ {_SigNotify, "SIGUSR1: user-defined signal 1"},
+	/* 31 */ {_SigNotify, "SIGUSR2: user-defined signal 2"},
+}
diff --git a/src/runtime/signal_nacl_386.go b/src/runtime/signal_nacl_386.go
new file mode 100644
index 0000000..0a1e7c6
--- /dev/null
+++ b/src/runtime/signal_nacl_386.go
@@ -0,0 +1,34 @@
+// 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() *excregs386 { return &(*exccontext)(c.ctxt).regs }
+func (c *sigctxt) eax() uint32       { return c.regs().eax }
+func (c *sigctxt) ebx() uint32       { return c.regs().ebx }
+func (c *sigctxt) ecx() uint32       { return c.regs().ecx }
+func (c *sigctxt) edx() uint32       { return c.regs().edx }
+func (c *sigctxt) edi() uint32       { return c.regs().edi }
+func (c *sigctxt) esi() uint32       { return c.regs().esi }
+func (c *sigctxt) ebp() uint32       { return c.regs().ebp }
+func (c *sigctxt) esp() uint32       { return c.regs().esp }
+func (c *sigctxt) eip() uint32       { return c.regs().eip }
+func (c *sigctxt) eflags() uint32    { return c.regs().eflags }
+func (c *sigctxt) cs() uint32        { return ^uint32(0) }
+func (c *sigctxt) fs() uint32        { return ^uint32(0) }
+func (c *sigctxt) gs() uint32        { return ^uint32(0) }
+func (c *sigctxt) sigcode() uint32   { return ^uint32(0) }
+func (c *sigctxt) sigaddr() uint32   { return 0 }
+
+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) {}
+func (c *sigctxt) set_sigaddr(x uint32) {}
diff --git a/src/runtime/signal_nacl_386.h b/src/runtime/signal_nacl_386.h
deleted file mode 100644
index c9481b5..0000000
--- a/src/runtime/signal_nacl_386.h
+++ /dev/null
@@ -1,23 +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.
-
-#define SIG_REGS(ctxt) (((ExcContext*)(ctxt))->regs)
-
-#define SIG_EAX(info, ctxt) (SIG_REGS(ctxt).eax)
-#define SIG_EBX(info, ctxt) (SIG_REGS(ctxt).ebx)
-#define SIG_ECX(info, ctxt) (SIG_REGS(ctxt).ecx)
-#define SIG_EDX(info, ctxt) (SIG_REGS(ctxt).edx)
-#define SIG_EDI(info, ctxt) (SIG_REGS(ctxt).edi)
-#define SIG_ESI(info, ctxt) (SIG_REGS(ctxt).esi)
-#define SIG_EBP(info, ctxt) (SIG_REGS(ctxt).ebp)
-#define SIG_ESP(info, ctxt) (SIG_REGS(ctxt).esp)
-#define SIG_EIP(info, ctxt) (SIG_REGS(ctxt).eip)
-#define SIG_EFLAGS(info, ctxt) (SIG_REGS(ctxt).eflags)
-
-#define SIG_CS(info, ctxt) (~0)
-#define SIG_FS(info, ctxt) (~0)
-#define SIG_GS(info, ctxt) (~0)
-
-#define SIG_CODE0(info, ctxt) (~0)
-#define SIG_CODE1(info, ctxt) (0)
diff --git a/src/runtime/signal_nacl_amd64p32.go b/src/runtime/signal_nacl_amd64p32.go
new file mode 100644
index 0000000..024ceba
--- /dev/null
+++ b/src/runtime/signal_nacl_amd64p32.go
@@ -0,0 +1,44 @@
+// 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"
+
+type sigctxt struct {
+	info *siginfo
+	ctxt unsafe.Pointer
+}
+
+func (c *sigctxt) regs() *excregsamd64 {
+	return &(*exccontext)(c.ctxt).regs
+}
+func (c *sigctxt) rax() uint64     { return c.regs().rax }
+func (c *sigctxt) rbx() uint64     { return c.regs().rbx }
+func (c *sigctxt) rcx() uint64     { return c.regs().rcx }
+func (c *sigctxt) rdx() uint64     { return c.regs().rdx }
+func (c *sigctxt) rdi() uint64     { return c.regs().rdi }
+func (c *sigctxt) rsi() uint64     { return c.regs().rsi }
+func (c *sigctxt) rbp() uint64     { return c.regs().rbp }
+func (c *sigctxt) rsp() uint64     { return c.regs().rsp }
+func (c *sigctxt) r8() uint64      { return c.regs().r8 }
+func (c *sigctxt) r9() uint64      { return c.regs().r9 }
+func (c *sigctxt) r10() uint64     { return c.regs().r10 }
+func (c *sigctxt) r11() uint64     { return c.regs().r11 }
+func (c *sigctxt) r12() uint64     { return c.regs().r12 }
+func (c *sigctxt) r13() uint64     { return c.regs().r13 }
+func (c *sigctxt) r14() uint64     { return c.regs().r14 }
+func (c *sigctxt) r15() uint64     { return c.regs().r15 }
+func (c *sigctxt) rip() uint64     { return c.regs().rip }
+func (c *sigctxt) rflags() uint64  { return uint64(c.regs().rflags) }
+func (c *sigctxt) cs() uint64      { return ^uint64(0) }
+func (c *sigctxt) fs() uint64      { return ^uint64(0) }
+func (c *sigctxt) gs() uint64      { return ^uint64(0) }
+func (c *sigctxt) sigcode() uint64 { return ^uint64(0) }
+func (c *sigctxt) sigaddr() uint64 { return 0 }
+
+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) {}
+func (c *sigctxt) set_sigaddr(x uint64) {}
diff --git a/src/runtime/signal_nacl_amd64p32.h b/src/runtime/signal_nacl_amd64p32.h
deleted file mode 100644
index f62305c..0000000
--- a/src/runtime/signal_nacl_amd64p32.h
+++ /dev/null
@@ -1,31 +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.
-
-#define SIG_REGS(ctxt) (((ExcContext*)(ctxt))->regs.regs64)
-
-#define SIG_RAX(info, ctxt) (SIG_REGS(ctxt).rax)
-#define SIG_RBX(info, ctxt) (SIG_REGS(ctxt).rbx)
-#define SIG_RCX(info, ctxt) (SIG_REGS(ctxt).rcx)
-#define SIG_RDX(info, ctxt) (SIG_REGS(ctxt).rdx)
-#define SIG_RDI(info, ctxt) (SIG_REGS(ctxt).rdi)
-#define SIG_RSI(info, ctxt) (SIG_REGS(ctxt).rsi)
-#define SIG_RBP(info, ctxt) (SIG_REGS(ctxt).rbp)
-#define SIG_RSP(info, ctxt) (SIG_REGS(ctxt).rsp)
-#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).r8)
-#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).r9)
-#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).r10)
-#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).r11)
-#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).r12)
-#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).r13)
-#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).r14)
-#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).r15)
-#define SIG_RIP(info, ctxt) (SIG_REGS(ctxt).rip)
-#define SIG_RFLAGS(info, ctxt) (SIG_REGS(ctxt).rflags)
-
-#define SIG_CS(info, ctxt) (~0)
-#define SIG_FS(info, ctxt) (~0)
-#define SIG_GS(info, ctxt) (~0)
-
-#define SIG_CODE0(info, ctxt) (~0)
-#define SIG_CODE1(info, ctxt) (0)
diff --git a/src/runtime/signal_nacl_arm.go b/src/runtime/signal_nacl_arm.go
new file mode 100644
index 0000000..1aeaa4e
--- /dev/null
+++ b/src/runtime/signal_nacl_arm.go
@@ -0,0 +1,47 @@
+// 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"
+
+type sigctxt struct {
+	info *siginfo
+	ctxt unsafe.Pointer
+}
+
+func (c *sigctxt) regs() *excregsarm { return &(*exccontext)(c.ctxt).regs }
+
+func (c *sigctxt) r0() uint32      { return c.regs().r0 }
+func (c *sigctxt) r1() uint32      { return c.regs().r1 }
+func (c *sigctxt) r2() uint32      { return c.regs().r2 }
+func (c *sigctxt) r3() uint32      { return c.regs().r3 }
+func (c *sigctxt) r4() uint32      { return c.regs().r4 }
+func (c *sigctxt) r5() uint32      { return c.regs().r5 }
+func (c *sigctxt) r6() uint32      { return c.regs().r6 }
+func (c *sigctxt) r7() uint32      { return c.regs().r7 }
+func (c *sigctxt) r8() uint32      { return c.regs().r8 }
+func (c *sigctxt) r9() uint32      { return c.regs().r9 }
+func (c *sigctxt) r10() uint32     { return c.regs().r10 }
+func (c *sigctxt) fp() uint32      { return c.regs().r11 }
+func (c *sigctxt) ip() uint32      { return c.regs().r12 }
+func (c *sigctxt) sp() uint32      { return c.regs().sp }
+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(0) }
+func (c *sigctxt) trap() uint32    { return ^uint32(0) }
+func (c *sigctxt) error() uint32   { return ^uint32(0) }
+func (c *sigctxt) oldmask() uint32 { return ^uint32(0) }
+
+func (c *sigctxt) sigcode() uint32 { return 0 }
+func (c *sigctxt) sigaddr() uint32 { return 0 }
+
+func (c *sigctxt) set_pc(x uint32)  { c.regs().pc = x }
+func (c *sigctxt) set_sp(x uint32)  { c.regs().sp = x }
+func (c *sigctxt) set_lr(x uint32)  { c.regs().lr = x }
+func (c *sigctxt) set_r10(x uint32) { c.regs().r10 = x }
+
+func (c *sigctxt) set_sigcode(x uint32) {}
+func (c *sigctxt) set_sigaddr(x uint32) {}
diff --git a/src/runtime/signal_nacl_arm.h b/src/runtime/signal_nacl_arm.h
deleted file mode 100644
index e5bbb21..0000000
--- a/src/runtime/signal_nacl_arm.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// 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.
-
-#define SIG_REGS(ctxt) (((ExcContext*)(ctxt))->regs)
-
-#define SIG_R0(info, ctxt) (SIG_REGS(ctxt).r0)
-#define SIG_R1(info, ctxt) (SIG_REGS(ctxt).r1)
-#define SIG_R2(info, ctxt) (SIG_REGS(ctxt).r2)
-#define SIG_R3(info, ctxt) (SIG_REGS(ctxt).r3)
-#define SIG_R4(info, ctxt) (SIG_REGS(ctxt).r4)
-#define SIG_R5(info, ctxt) (SIG_REGS(ctxt).r5)
-#define SIG_R6(info, ctxt) (SIG_REGS(ctxt).r6)
-#define SIG_R7(info, ctxt) (SIG_REGS(ctxt).r7)
-#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).r8)
-#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).r9)
-#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).r10)
-#define SIG_FP(info, ctxt) (SIG_REGS(ctxt).r11)
-#define SIG_IP(info, ctxt) (SIG_REGS(ctxt).r12)
-#define SIG_SP(info, ctxt) (SIG_REGS(ctxt).sp)
-#define SIG_LR(info, ctxt) (SIG_REGS(ctxt).lr)
-#define SIG_PC(info, ctxt) (SIG_REGS(ctxt).pc)
-#define SIG_CPSR(info, ctxt) (SIG_REGS(ctxt).cpsr)
-#define SIG_FAULT(info, ctxt) (~0)
-#define SIG_TRAP(info, ctxt) (~0)
-#define SIG_ERROR(info, ctxt) (~0)
-#define SIG_OLDMASK(info, ctxt) (~0)
-#define SIG_CODE0(info, ctxt) (~0)
diff --git a/src/runtime/signal_netbsd.go b/src/runtime/signal_netbsd.go
new file mode 100644
index 0000000..d93a450
--- /dev/null
+++ b/src/runtime/signal_netbsd.go
@@ -0,0 +1,46 @@
+// 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
+
+type sigTabT struct {
+	flags int32
+	name  string
+}
+
+var sigtable = [...]sigTabT{
+	/*  0 */ {0, "SIGNONE: no trap"},
+	/*  1 */ {_SigNotify + _SigKill, "SIGHUP: terminal line hangup"},
+	/*  2 */ {_SigNotify + _SigKill, "SIGINT: interrupt"},
+	/*  3 */ {_SigNotify + _SigThrow, "SIGQUIT: quit"},
+	/*  4 */ {_SigThrow + _SigUnblock, "SIGILL: illegal instruction"},
+	/*  5 */ {_SigThrow + _SigUnblock, "SIGTRAP: trace trap"},
+	/*  6 */ {_SigNotify + _SigThrow, "SIGABRT: abort"},
+	/*  7 */ {_SigThrow, "SIGEMT: emulate instruction executed"},
+	/*  8 */ {_SigPanic + _SigUnblock, "SIGFPE: floating-point exception"},
+	/*  9 */ {0, "SIGKILL: kill"},
+	/* 10 */ {_SigPanic + _SigUnblock, "SIGBUS: bus error"},
+	/* 11 */ {_SigPanic + _SigUnblock, "SIGSEGV: segmentation violation"},
+	/* 12 */ {_SigThrow, "SIGSYS: bad system call"},
+	/* 13 */ {_SigNotify, "SIGPIPE: write to broken pipe"},
+	/* 14 */ {_SigNotify, "SIGALRM: alarm clock"},
+	/* 15 */ {_SigNotify + _SigKill, "SIGTERM: termination"},
+	/* 16 */ {_SigNotify, "SIGURG: urgent condition on socket"},
+	/* 17 */ {0, "SIGSTOP: stop"},
+	/* 18 */ {_SigNotify + _SigDefault, "SIGTSTP: keyboard stop"},
+	/* 19 */ {0, "SIGCONT: continue after stop"},
+	/* 20 */ {_SigNotify + _SigUnblock, "SIGCHLD: child status has changed"},
+	/* 21 */ {_SigNotify + _SigDefault, "SIGTTIN: background read from tty"},
+	/* 22 */ {_SigNotify + _SigDefault, "SIGTTOU: background write to tty"},
+	/* 23 */ {_SigNotify, "SIGIO: i/o now possible"},
+	/* 24 */ {_SigNotify, "SIGXCPU: cpu limit exceeded"},
+	/* 25 */ {_SigNotify, "SIGXFSZ: file size limit exceeded"},
+	/* 26 */ {_SigNotify, "SIGVTALRM: virtual alarm clock"},
+	/* 27 */ {_SigNotify + _SigUnblock, "SIGPROF: profiling alarm clock"},
+	/* 28 */ {_SigNotify, "SIGWINCH: window size change"},
+	/* 29 */ {_SigNotify, "SIGINFO: status request from keyboard"},
+	/* 30 */ {_SigNotify, "SIGUSR1: user-defined signal 1"},
+	/* 31 */ {_SigNotify, "SIGUSR2: user-defined signal 2"},
+	/* 32 */ {_SigNotify, "SIGTHR: reserved"},
+}
diff --git a/src/runtime/signal_netbsd_386.go b/src/runtime/signal_netbsd_386.go
new file mode 100644
index 0000000..6702336
--- /dev/null
+++ b/src/runtime/signal_netbsd_386.go
@@ -0,0 +1,38 @@
+// 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() *mcontextt { return &(*ucontextt)(c.ctxt).uc_mcontext }
+func (c *sigctxt) eax() uint32      { return c.regs().__gregs[_REG_EAX] }
+func (c *sigctxt) ebx() uint32      { return c.regs().__gregs[_REG_EBX] }
+func (c *sigctxt) ecx() uint32      { return c.regs().__gregs[_REG_ECX] }
+func (c *sigctxt) edx() uint32      { return c.regs().__gregs[_REG_EDX] }
+func (c *sigctxt) edi() uint32      { return c.regs().__gregs[_REG_EDI] }
+func (c *sigctxt) esi() uint32      { return c.regs().__gregs[_REG_ESI] }
+func (c *sigctxt) ebp() uint32      { return c.regs().__gregs[_REG_EBP] }
+func (c *sigctxt) esp() uint32      { return c.regs().__gregs[_REG_UESP] }
+func (c *sigctxt) eip() uint32      { return c.regs().__gregs[_REG_EIP] }
+func (c *sigctxt) eflags() uint32   { return c.regs().__gregs[_REG_EFL] }
+func (c *sigctxt) cs() uint32       { return uint32(c.regs().__gregs[_REG_CS]) }
+func (c *sigctxt) fs() uint32       { return uint32(c.regs().__gregs[_REG_FS]) }
+func (c *sigctxt) gs() uint32       { return uint32(c.regs().__gregs[_REG_GS]) }
+func (c *sigctxt) sigcode() uint32  { return uint32(c.info._code) }
+func (c *sigctxt) sigaddr() uint32 {
+	return uint32(*(*uint32)(unsafe.Pointer(&c.info._reason[0])))
+}
+
+func (c *sigctxt) set_eip(x uint32)     { c.regs().__gregs[_REG_EIP] = x }
+func (c *sigctxt) set_esp(x uint32)     { c.regs().__gregs[_REG_UESP] = x }
+func (c *sigctxt) set_sigcode(x uint32) { c.info._code = int32(x) }
+func (c *sigctxt) set_sigaddr(x uint32) {
+	*(*uint32)(unsafe.Pointer(&c.info._reason[0])) = x
+}
diff --git a/src/runtime/signal_netbsd_386.h b/src/runtime/signal_netbsd_386.h
deleted file mode 100644
index d5a8a0c..0000000
--- a/src/runtime/signal_netbsd_386.h
+++ /dev/null
@@ -1,23 +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.
-
-#define SIG_REGS(ctxt) (((UcontextT*)(ctxt))->uc_mcontext)
-
-#define SIG_EAX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EAX])
-#define SIG_EBX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EBX])
-#define SIG_ECX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_ECX])
-#define SIG_EDX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EDX])
-#define SIG_EDI(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EDI])
-#define SIG_ESI(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_ESI])
-#define SIG_EBP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EBP])
-#define SIG_ESP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_UESP])
-#define SIG_EIP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EIP])
-#define SIG_EFLAGS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_EFL])
-
-#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_CS])
-#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_FS])
-#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_GS])
-
-#define SIG_CODE0(info, ctxt) ((info)->_code)
-#define SIG_CODE1(info, ctxt) (*(uintptr*)&(info)->_reason[0])
diff --git a/src/runtime/signal_netbsd_amd64.go b/src/runtime/signal_netbsd_amd64.go
new file mode 100644
index 0000000..e22f4a7
--- /dev/null
+++ b/src/runtime/signal_netbsd_amd64.go
@@ -0,0 +1,48 @@
+// 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() *mcontextt {
+	return (*mcontextt)(unsafe.Pointer(&(*ucontextt)(c.ctxt).uc_mcontext))
+}
+func (c *sigctxt) rax() uint64     { return c.regs().__gregs[_REG_RAX] }
+func (c *sigctxt) rbx() uint64     { return c.regs().__gregs[_REG_RBX] }
+func (c *sigctxt) rcx() uint64     { return c.regs().__gregs[_REG_RCX] }
+func (c *sigctxt) rdx() uint64     { return c.regs().__gregs[_REG_RDX] }
+func (c *sigctxt) rdi() uint64     { return c.regs().__gregs[_REG_RDI] }
+func (c *sigctxt) rsi() uint64     { return c.regs().__gregs[_REG_RSI] }
+func (c *sigctxt) rbp() uint64     { return c.regs().__gregs[_REG_RBP] }
+func (c *sigctxt) rsp() uint64     { return c.regs().__gregs[_REG_RSP] }
+func (c *sigctxt) r8() uint64      { return c.regs().__gregs[_REG_R8] }
+func (c *sigctxt) r9() uint64      { return c.regs().__gregs[_REG_R8] }
+func (c *sigctxt) r10() uint64     { return c.regs().__gregs[_REG_R10] }
+func (c *sigctxt) r11() uint64     { return c.regs().__gregs[_REG_R11] }
+func (c *sigctxt) r12() uint64     { return c.regs().__gregs[_REG_R12] }
+func (c *sigctxt) r13() uint64     { return c.regs().__gregs[_REG_R13] }
+func (c *sigctxt) r14() uint64     { return c.regs().__gregs[_REG_R14] }
+func (c *sigctxt) r15() uint64     { return c.regs().__gregs[_REG_R15] }
+func (c *sigctxt) rip() uint64     { return c.regs().__gregs[_REG_RIP] }
+func (c *sigctxt) rflags() uint64  { return c.regs().__gregs[_REG_RFLAGS] }
+func (c *sigctxt) cs() uint64      { return c.regs().__gregs[_REG_CS] }
+func (c *sigctxt) fs() uint64      { return c.regs().__gregs[_REG_FS] }
+func (c *sigctxt) gs() uint64      { return c.regs().__gregs[_REG_GS] }
+func (c *sigctxt) sigcode() uint64 { return uint64(c.info._code) }
+func (c *sigctxt) sigaddr() uint64 {
+	return uint64(*(*uint64)(unsafe.Pointer(&c.info._reason[0])))
+}
+
+func (c *sigctxt) set_rip(x uint64)     { c.regs().__gregs[_REG_RIP] = x }
+func (c *sigctxt) set_rsp(x uint64)     { c.regs().__gregs[_REG_RSP] = x }
+func (c *sigctxt) set_sigcode(x uint64) { c.info._code = int32(x) }
+func (c *sigctxt) set_sigaddr(x uint64) {
+	*(*uint64)(unsafe.Pointer(&c.info._reason[0])) = x
+}
diff --git a/src/runtime/signal_netbsd_amd64.h b/src/runtime/signal_netbsd_amd64.h
deleted file mode 100644
index 7ec4cd9..0000000
--- a/src/runtime/signal_netbsd_amd64.h
+++ /dev/null
@@ -1,31 +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.
-
-#define SIG_REGS(ctxt) (((UcontextT*)(ctxt))->uc_mcontext)
-
-#define SIG_RAX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RAX])
-#define SIG_RBX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RBX])
-#define SIG_RCX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RCX])
-#define SIG_RDX(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RDX])
-#define SIG_RDI(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RDI])
-#define SIG_RSI(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RSI])
-#define SIG_RBP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RBP])
-#define SIG_RSP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RSP])
-#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R8])
-#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R9])
-#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R10])
-#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R11])
-#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R12])
-#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R13])
-#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R14])
-#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R15])
-#define SIG_RIP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RIP])
-#define SIG_RFLAGS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_RFLAGS])
-
-#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_CS])
-#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_FS])
-#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_GS])
-
-#define SIG_CODE0(info, ctxt) ((info)->_code)
-#define SIG_CODE1(info, ctxt) (*(uintptr*)&(info)->_reason[0])
diff --git a/src/runtime/signal_netbsd_arm.go b/src/runtime/signal_netbsd_arm.go
new file mode 100644
index 0000000..9b114c8
--- /dev/null
+++ b/src/runtime/signal_netbsd_arm.go
@@ -0,0 +1,48 @@
+// 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() *mcontextt { return &(*ucontextt)(c.ctxt).uc_mcontext }
+func (c *sigctxt) r0() uint32       { return c.regs().__gregs[_REG_R0] }
+func (c *sigctxt) r1() uint32       { return c.regs().__gregs[_REG_R1] }
+func (c *sigctxt) r2() uint32       { return c.regs().__gregs[_REG_R2] }
+func (c *sigctxt) r3() uint32       { return c.regs().__gregs[_REG_R3] }
+func (c *sigctxt) r4() uint32       { return c.regs().__gregs[_REG_R4] }
+func (c *sigctxt) r5() uint32       { return c.regs().__gregs[_REG_R5] }
+func (c *sigctxt) r6() uint32       { return c.regs().__gregs[_REG_R6] }
+func (c *sigctxt) r7() uint32       { return c.regs().__gregs[_REG_R7] }
+func (c *sigctxt) r8() uint32       { return c.regs().__gregs[_REG_R8] }
+func (c *sigctxt) r9() uint32       { return c.regs().__gregs[_REG_R9] }
+func (c *sigctxt) r10() uint32      { return c.regs().__gregs[_REG_R10] }
+func (c *sigctxt) fp() uint32       { return c.regs().__gregs[_REG_R11] }
+func (c *sigctxt) ip() uint32       { return c.regs().__gregs[_REG_R12] }
+func (c *sigctxt) sp() uint32       { return c.regs().__gregs[_REG_R13] }
+func (c *sigctxt) lr() uint32       { return c.regs().__gregs[_REG_R14] }
+func (c *sigctxt) pc() uint32       { return c.regs().__gregs[_REG_R15] }
+func (c *sigctxt) cpsr() uint32     { return c.regs().__gregs[_REG_CPSR] }
+func (c *sigctxt) fault() uint32    { return uint32(c.info._reason) }
+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._code) }
+func (c *sigctxt) sigaddr() uint32 { return uint32(c.info._reason) }
+
+func (c *sigctxt) set_pc(x uint32)  { c.regs().__gregs[_REG_R15] = x }
+func (c *sigctxt) set_sp(x uint32)  { c.regs().__gregs[_REG_R13] = x }
+func (c *sigctxt) set_lr(x uint32)  { c.regs().__gregs[_REG_R14] = x }
+func (c *sigctxt) set_r10(x uint32) { c.regs().__gregs[_REG_R10] = x }
+
+func (c *sigctxt) set_sigcode(x uint32) { c.info._code = int32(x) }
+func (c *sigctxt) set_sigaddr(x uint32) {
+	c.info._reason = uintptr(x)
+}
diff --git a/src/runtime/signal_netbsd_arm.h b/src/runtime/signal_netbsd_arm.h
deleted file mode 100644
index 12f5827..0000000
--- a/src/runtime/signal_netbsd_arm.h
+++ /dev/null
@@ -1,30 +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.
-
-#define SIG_REGS(ctxt) (((UcontextT*)(ctxt))->uc_mcontext)
-
-#define SIG_R0(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R0])
-#define SIG_R1(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R1])
-#define SIG_R2(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R2])
-#define SIG_R3(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R3])
-#define SIG_R4(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R4])
-#define SIG_R5(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R5])
-#define SIG_R6(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R6])
-#define SIG_R7(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R7])
-#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R8])
-#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R9])
-#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R10])
-#define SIG_FP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R11])
-#define SIG_IP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R12])
-#define SIG_SP(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R13])
-#define SIG_LR(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R14])
-#define SIG_PC(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_R15])
-#define SIG_CPSR(info, ctxt) (SIG_REGS(ctxt).__gregs[REG_CPSR])
-#define SIG_FAULT(info, ctxt) (*(uintptr*)&(info)->_reason[0])
-#define SIG_TRAP(info, ctxt) (0)
-#define SIG_ERROR(info, ctxt) (0)
-#define SIG_OLDMASK(info, ctxt) (0)
-
-#define SIG_CODE0(info, ctxt) ((info)->_code)
-#define SIG_CODE1(info, ctxt) (*(uintptr*)&(info)->_reason[0])
diff --git a/src/runtime/signal_openbsd.go b/src/runtime/signal_openbsd.go
new file mode 100644
index 0000000..78afc59
--- /dev/null
+++ b/src/runtime/signal_openbsd.go
@@ -0,0 +1,46 @@
+// 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
+
+type sigTabT struct {
+	flags int32
+	name  string
+}
+
+var sigtable = [...]sigTabT{
+	/*  0 */ {0, "SIGNONE: no trap"},
+	/*  1 */ {_SigNotify + _SigKill, "SIGHUP: terminal line hangup"},
+	/*  2 */ {_SigNotify + _SigKill, "SIGINT: interrupt"},
+	/*  3 */ {_SigNotify + _SigThrow, "SIGQUIT: quit"},
+	/*  4 */ {_SigThrow, "SIGILL: illegal instruction"},
+	/*  5 */ {_SigThrow, "SIGTRAP: trace trap"},
+	/*  6 */ {_SigNotify + _SigThrow, "SIGABRT: abort"},
+	/*  7 */ {_SigThrow, "SIGEMT: emulate instruction executed"},
+	/*  8 */ {_SigPanic, "SIGFPE: floating-point exception"},
+	/*  9 */ {0, "SIGKILL: kill"},
+	/* 10 */ {_SigPanic, "SIGBUS: bus error"},
+	/* 11 */ {_SigPanic, "SIGSEGV: segmentation violation"},
+	/* 12 */ {_SigThrow, "SIGSYS: bad system call"},
+	/* 13 */ {_SigNotify, "SIGPIPE: write to broken pipe"},
+	/* 14 */ {_SigNotify, "SIGALRM: alarm clock"},
+	/* 15 */ {_SigNotify + _SigKill, "SIGTERM: termination"},
+	/* 16 */ {_SigNotify, "SIGURG: urgent condition on socket"},
+	/* 17 */ {0, "SIGSTOP: stop"},
+	/* 18 */ {_SigNotify + _SigDefault, "SIGTSTP: keyboard stop"},
+	/* 19 */ {0, "SIGCONT: continue after stop"},
+	/* 20 */ {_SigNotify, "SIGCHLD: child status has changed"},
+	/* 21 */ {_SigNotify + _SigDefault, "SIGTTIN: background read from tty"},
+	/* 22 */ {_SigNotify + _SigDefault, "SIGTTOU: background write to tty"},
+	/* 23 */ {_SigNotify, "SIGIO: i/o now possible"},
+	/* 24 */ {_SigNotify, "SIGXCPU: cpu limit exceeded"},
+	/* 25 */ {_SigNotify, "SIGXFSZ: file size limit exceeded"},
+	/* 26 */ {_SigNotify, "SIGVTALRM: virtual alarm clock"},
+	/* 27 */ {_SigNotify, "SIGPROF: profiling alarm clock"},
+	/* 28 */ {_SigNotify, "SIGWINCH: window size change"},
+	/* 29 */ {_SigNotify, "SIGINFO: status request from keyboard"},
+	/* 30 */ {_SigNotify, "SIGUSR1: user-defined signal 1"},
+	/* 31 */ {_SigNotify, "SIGUSR2: user-defined signal 2"},
+	/* 32 */ {_SigNotify, "SIGTHR: reserved"},
+}
diff --git a/src/runtime/signal_openbsd_386.go b/src/runtime/signal_openbsd_386.go
new file mode 100644
index 0000000..c582a449
--- /dev/null
+++ b/src/runtime/signal_openbsd_386.go
@@ -0,0 +1,41 @@
+// 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) eax() uint32     { return c.regs().sc_eax }
+func (c *sigctxt) ebx() uint32     { return c.regs().sc_ebx }
+func (c *sigctxt) ecx() uint32     { return c.regs().sc_ecx }
+func (c *sigctxt) edx() uint32     { return c.regs().sc_edx }
+func (c *sigctxt) edi() uint32     { return c.regs().sc_edi }
+func (c *sigctxt) esi() uint32     { return c.regs().sc_esi }
+func (c *sigctxt) ebp() uint32     { return c.regs().sc_ebp }
+func (c *sigctxt) esp() uint32     { return c.regs().sc_esp }
+func (c *sigctxt) eip() uint32     { return c.regs().sc_eip }
+func (c *sigctxt) eflags() uint32  { return c.regs().sc_eflags }
+func (c *sigctxt) cs() uint32      { return c.regs().sc_cs }
+func (c *sigctxt) fs() uint32      { return c.regs().sc_fs }
+func (c *sigctxt) gs() uint32      { return c.regs().sc_gs }
+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_eip(x uint32)     { c.regs().sc_eip = x }
+func (c *sigctxt) set_esp(x uint32)     { c.regs().sc_esp = 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_openbsd_386.h b/src/runtime/signal_openbsd_386.h
deleted file mode 100644
index 6742db8..0000000
--- a/src/runtime/signal_openbsd_386.h
+++ /dev/null
@@ -1,23 +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.
-
-#define SIG_REGS(ctxt) (*(Sigcontext*)(ctxt))
-
-#define SIG_EAX(info, ctxt) (SIG_REGS(ctxt).sc_eax)
-#define SIG_EBX(info, ctxt) (SIG_REGS(ctxt).sc_ebx)
-#define SIG_ECX(info, ctxt) (SIG_REGS(ctxt).sc_ecx)
-#define SIG_EDX(info, ctxt) (SIG_REGS(ctxt).sc_edx)
-#define SIG_EDI(info, ctxt) (SIG_REGS(ctxt).sc_edi)
-#define SIG_ESI(info, ctxt) (SIG_REGS(ctxt).sc_esi)
-#define SIG_EBP(info, ctxt) (SIG_REGS(ctxt).sc_ebp)
-#define SIG_ESP(info, ctxt) (SIG_REGS(ctxt).sc_esp)
-#define SIG_EIP(info, ctxt) (SIG_REGS(ctxt).sc_eip)
-#define SIG_EFLAGS(info, ctxt) (SIG_REGS(ctxt).sc_eflags)
-
-#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).sc_cs)
-#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).sc_fs)
-#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).sc_gs)
-
-#define SIG_CODE0(info, ctxt) ((info)->si_code)
-#define SIG_CODE1(info, ctxt) (*(uintptr*)((byte*)info + 12))
diff --git a/src/runtime/signal_openbsd_amd64.go b/src/runtime/signal_openbsd_amd64.go
new file mode 100644
index 0000000..4f0d19d
--- /dev/null
+++ b/src/runtime/signal_openbsd_amd64.go
@@ -0,0 +1,49 @@
+// 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) rax() uint64     { return c.regs().sc_rax }
+func (c *sigctxt) rbx() uint64     { return c.regs().sc_rbx }
+func (c *sigctxt) rcx() uint64     { return c.regs().sc_rcx }
+func (c *sigctxt) rdx() uint64     { return c.regs().sc_rdx }
+func (c *sigctxt) rdi() uint64     { return c.regs().sc_rdi }
+func (c *sigctxt) rsi() uint64     { return c.regs().sc_rsi }
+func (c *sigctxt) rbp() uint64     { return c.regs().sc_rbp }
+func (c *sigctxt) rsp() uint64     { return c.regs().sc_rsp }
+func (c *sigctxt) r8() uint64      { return c.regs().sc_r8 }
+func (c *sigctxt) r9() uint64      { return c.regs().sc_r9 }
+func (c *sigctxt) r10() uint64     { return c.regs().sc_r10 }
+func (c *sigctxt) r11() uint64     { return c.regs().sc_r11 }
+func (c *sigctxt) r12() uint64     { return c.regs().sc_r12 }
+func (c *sigctxt) r13() uint64     { return c.regs().sc_r13 }
+func (c *sigctxt) r14() uint64     { return c.regs().sc_r14 }
+func (c *sigctxt) r15() uint64     { return c.regs().sc_r15 }
+func (c *sigctxt) rip() uint64     { return c.regs().sc_rip }
+func (c *sigctxt) rflags() uint64  { return c.regs().sc_rflags }
+func (c *sigctxt) cs() uint64      { return c.regs().sc_cs }
+func (c *sigctxt) fs() uint64      { return c.regs().sc_fs }
+func (c *sigctxt) gs() uint64      { return c.regs().sc_gs }
+func (c *sigctxt) sigcode() uint64 { return uint64(c.info.si_code) }
+func (c *sigctxt) sigaddr() uint64 {
+	return *(*uint64)(add(unsafe.Pointer(c.info), 16))
+}
+
+func (c *sigctxt) set_rip(x uint64)     { c.regs().sc_rip = x }
+func (c *sigctxt) set_rsp(x uint64)     { c.regs().sc_rsp = x }
+func (c *sigctxt) set_sigcode(x uint64) { c.info.si_code = int32(x) }
+func (c *sigctxt) set_sigaddr(x uint64) {
+	*(*uint64)(add(unsafe.Pointer(c.info), 16)) = x
+}
diff --git a/src/runtime/signal_openbsd_amd64.h b/src/runtime/signal_openbsd_amd64.h
deleted file mode 100644
index b46a5df..0000000
--- a/src/runtime/signal_openbsd_amd64.h
+++ /dev/null
@@ -1,31 +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.
-
-#define SIG_REGS(ctxt) (*(Sigcontext*)(ctxt))
-
-#define SIG_RAX(info, ctxt) (SIG_REGS(ctxt).sc_rax)
-#define SIG_RBX(info, ctxt) (SIG_REGS(ctxt).sc_rbx)
-#define SIG_RCX(info, ctxt) (SIG_REGS(ctxt).sc_rcx)
-#define SIG_RDX(info, ctxt) (SIG_REGS(ctxt).sc_rdx)
-#define SIG_RDI(info, ctxt) (SIG_REGS(ctxt).sc_rdi)
-#define SIG_RSI(info, ctxt) (SIG_REGS(ctxt).sc_rsi)
-#define SIG_RBP(info, ctxt) (SIG_REGS(ctxt).sc_rbp)
-#define SIG_RSP(info, ctxt) (SIG_REGS(ctxt).sc_rsp)
-#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).sc_r8)
-#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).sc_r9)
-#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).sc_r10)
-#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).sc_r11)
-#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).sc_r12)
-#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).sc_r13)
-#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).sc_r14)
-#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).sc_r15)
-#define SIG_RIP(info, ctxt) (SIG_REGS(ctxt).sc_rip)
-#define SIG_RFLAGS(info, ctxt) (SIG_REGS(ctxt).sc_rflags)
-
-#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).sc_cs)
-#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).sc_fs)
-#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).sc_gs)
-
-#define SIG_CODE0(info, ctxt) ((info)->si_code)
-#define SIG_CODE1(info, ctxt) (*(uintptr*)((byte*)(info) + 16))
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_plan9.go b/src/runtime/signal_plan9.go
new file mode 100644
index 0000000..302f156
--- /dev/null
+++ b/src/runtime/signal_plan9.go
@@ -0,0 +1,54 @@
+// 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
+
+type sigTabT struct {
+	flags int
+	name  string
+}
+
+// Incoming notes are compared against this table using strncmp, so the
+// order matters: longer patterns must appear before their prefixes.
+// There are _SIG constants in os2_plan9.go for the table index of some
+// of these.
+//
+// If you add entries to this table, you must respect the prefix ordering
+// and also update the constant values is os2_plan9.go.
+var sigtable = [...]sigTabT{
+	// Traps that we cannot be recovered.
+	{_SigThrow, "sys: trap: debug exception"},
+	{_SigThrow, "sys: trap: invalid opcode"},
+
+	// We can recover from some memory errors in runtime·sigpanic.
+	{_SigPanic, "sys: trap: fault read addr"},  // SIGRFAULT
+	{_SigPanic, "sys: trap: fault write addr"}, // SIGWFAULT
+
+	// We can also recover from math errors.
+	{_SigPanic, "sys: trap: divide error"}, // SIGINTDIV
+	{_SigPanic, "sys: fp:"},                // SIGFLOAT
+
+	// All other traps are normally handled as if they were marked SigThrow.
+	// We mark them SigPanic here so that debug.SetPanicOnFault will work.
+	{_SigPanic, "sys: trap:"}, // SIGTRAP
+
+	// Writes to a closed pipe can be handled if desired, otherwise they're ignored.
+	{_SigNotify, "sys: write on closed pipe"},
+
+	// Other system notes are more serious and cannot be recovered.
+	{_SigThrow, "sys:"},
+
+	// Issued to all other procs when calling runtime·exit.
+	{_SigGoExit, "go: exit "},
+
+	// Kill is sent by external programs to cause an exit.
+	{_SigKill, "kill"},
+
+	// Interrupts can be handled if desired, otherwise they cause an exit.
+	{_SigNotify + _SigKill, "interrupt"},
+	{_SigNotify + _SigKill, "hangup"},
+
+	// Alarms can be handled if desired, otherwise they're ignored.
+	{_SigNotify, "alarm"},
+}
diff --git a/src/runtime/signal_ppc64x.go b/src/runtime/signal_ppc64x.go
new file mode 100644
index 0000000..bad9fe6
--- /dev/null
+++ b/src/runtime/signal_ppc64x.go
@@ -0,0 +1,183 @@
+// 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
+// +build ppc64 ppc64le
+
+package runtime
+
+import "unsafe"
+
+func dumpregs(c *sigctxt) {
+	print("r0   ", hex(c.r0()), "\t")
+	print("r1   ", hex(c.r1()), "\n")
+	print("r2   ", hex(c.r2()), "\t")
+	print("r3   ", hex(c.r3()), "\n")
+	print("r4   ", hex(c.r4()), "\t")
+	print("r5   ", hex(c.r5()), "\n")
+	print("r6   ", hex(c.r6()), "\t")
+	print("r7   ", hex(c.r7()), "\n")
+	print("r8   ", hex(c.r8()), "\t")
+	print("r9   ", hex(c.r9()), "\n")
+	print("r10  ", hex(c.r10()), "\t")
+	print("r11  ", hex(c.r11()), "\n")
+	print("r12  ", hex(c.r12()), "\t")
+	print("r13  ", hex(c.r13()), "\n")
+	print("r14  ", hex(c.r14()), "\t")
+	print("r15  ", hex(c.r15()), "\n")
+	print("r16  ", hex(c.r16()), "\t")
+	print("r17  ", hex(c.r17()), "\n")
+	print("r18  ", hex(c.r18()), "\t")
+	print("r19  ", hex(c.r19()), "\n")
+	print("r20  ", hex(c.r20()), "\t")
+	print("r21  ", hex(c.r21()), "\n")
+	print("r22  ", hex(c.r22()), "\t")
+	print("r23  ", hex(c.r23()), "\n")
+	print("r24  ", hex(c.r24()), "\t")
+	print("r25  ", hex(c.r25()), "\n")
+	print("r26  ", hex(c.r26()), "\t")
+	print("r27  ", hex(c.r27()), "\n")
+	print("r28  ", hex(c.r28()), "\t")
+	print("r29  ", hex(c.r29()), "\n")
+	print("r30  ", hex(c.r30()), "\t")
+	print("r31  ", hex(c.r31()), "\n")
+	print("pc   ", hex(c.pc()), "\t")
+	print("ctr  ", hex(c.ctr()), "\n")
+	print("link ", hex(c.link()), "\t")
+	print("xer  ", hex(c.xer()), "\n")
+	print("ccr  ", hex(c.ccr()), "\t")
+	print("trap ", hex(c.trap()), "\n")
+}
+
+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}
+
+	if sig == _SIGPROF {
+		sigprof(uintptr(c.pc()), uintptr(c.sp()), uintptr(c.link()), 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 link, and pc to pretend the panicking
+		// function calls sigpanic directly.
+		// Always save LINK 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() - ptrSize
+		c.set_sp(sp)
+		*(*uint64)(unsafe.Pointer(uintptr(sp))) = c.link()
+
+		pc := uintptr(gp.sigpc)
+
+		// If we don't recognize the PC as code
+		// but we do recognize the link register as code,
+		// then assume this was a call to non-code and treat like
+		// pc == 0, to make unwinding show the context.
+		if pc != 0 && findfunc(pc) == nil && findfunc(uintptr(c.link())) != nil {
+			pc = 0
+		}
+
+		// 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 pc != 0 {
+			c.set_link(uint64(pc))
+		}
+
+		// In case we are panicking from external C code
+		c.set_r0(0)
+		c.set_r30(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
+	_g_.m.caughtsig.set(gp)
+
+	if crashing == 0 {
+		startpanic()
+	}
+
+	if sig < uint32(len(sigtable)) {
+		print(sigtable[sig].name, "\n")
+	} else {
+		print("Signal ", sig, "\n")
+	}
+
+	print("PC=", hex(c.pc()), " m=", _g_.m.id, "\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.link()), gp)
+		if crashing > 0 && gp != _g_.m.curg && _g_.m.curg != nil && readgstatus(_g_.m.curg)&^_Gscan == _Grunning {
+			// tracebackothers on original m skipped this one; trace it now.
+			goroutineheader(_g_.m.curg)
+			traceback(^uintptr(0), ^uintptr(0), 0, gp)
+		} else if crashing == 0 {
+			tracebackothers(gp)
+			print("\n")
+		}
+		dumpregs(c)
+	}
+
+	if docrash {
+		crashing++
+		if crashing < sched.mcount {
+			// There are other m's that need to dump their stacks.
+			// Relay SIGQUIT to the next m by sending it to the current process.
+			// All m's that have already received SIGQUIT have signal masks blocking
+			// receipt of any signals, so the SIGQUIT will go to an m that hasn't seen it yet.
+			// When the last m receives the SIGQUIT, it will fall through to the call to
+			// crash below. Just in case the relaying gets botched, each m involved in
+			// the relay sleeps for 5 seconds and then does the crash/exit itself.
+			// In expected operation, the last m has received the SIGQUIT and run
+			// crash/exit and the process is gone, all long before any of the
+			// 5-second sleeps have finished.
+			print("\n-----\n\n")
+			raiseproc(_SIGQUIT)
+			usleep(5 * 1000 * 1000)
+		}
+		crash()
+	}
+
+	exit(2)
+}
diff --git a/src/runtime/signal_solaris.go b/src/runtime/signal_solaris.go
new file mode 100644
index 0000000..d8ac676
--- /dev/null
+++ b/src/runtime/signal_solaris.go
@@ -0,0 +1,88 @@
+// 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 sigTabT struct {
+	flags int32
+	name  string
+}
+
+var sigtable = [...]sigTabT{
+	/* 0 */ {0, "SIGNONE: no trap"},
+	/* 1 */ {_SigNotify + _SigKill, "SIGHUP: hangup"},
+	/* 2 */ {_SigNotify + _SigKill, "SIGINT: interrupt (rubout)"},
+	/* 3 */ {_SigNotify + _SigThrow, "SIGQUIT: quit (ASCII FS)"},
+	/* 4 */ {_SigThrow + _SigUnblock, "SIGILL: illegal instruction (not reset when caught)"},
+	/* 5 */ {_SigThrow + _SigUnblock, "SIGTRAP: trace trap (not reset when caught)"},
+	/* 6 */ {_SigNotify + _SigThrow, "SIGABRT: used by abort, replace SIGIOT in the future"},
+	/* 7 */ {_SigThrow, "SIGEMT: EMT instruction"},
+	/* 8 */ {_SigPanic + _SigUnblock, "SIGFPE: floating point exception"},
+	/* 9 */ {0, "SIGKILL: kill (cannot be caught or ignored)"},
+	/* 10 */ {_SigPanic + _SigUnblock, "SIGBUS: bus error"},
+	/* 11 */ {_SigPanic + _SigUnblock, "SIGSEGV: segmentation violation"},
+	/* 12 */ {_SigThrow, "SIGSYS: bad argument to system call"},
+	/* 13 */ {_SigNotify, "SIGPIPE: write on a pipe with no one to read it"},
+	/* 14 */ {_SigNotify, "SIGALRM: alarm clock"},
+	/* 15 */ {_SigNotify + _SigKill, "SIGTERM: software termination signal from kill"},
+	/* 16 */ {_SigNotify, "SIGUSR1: user defined signal 1"},
+	/* 17 */ {_SigNotify, "SIGUSR2: user defined signal 2"},
+	/* 18 */ {_SigNotify + _SigUnblock, "SIGCHLD: child status change alias (POSIX)"},
+	/* 19 */ {_SigNotify, "SIGPWR: power-fail restart"},
+	/* 20 */ {_SigNotify, "SIGWINCH: window size change"},
+	/* 21 */ {_SigNotify, "SIGURG: urgent socket condition"},
+	/* 22 */ {_SigNotify, "SIGPOLL: pollable event occured"},
+	/* 23 */ {_SigNotify + _SigDefault, "SIGSTOP: stop (cannot be caught or ignored)"},
+	/* 24 */ {0, "SIGTSTP: user stop requested from tty"},
+	/* 25 */ {0, "SIGCONT: stopped process has been continued"},
+	/* 26 */ {_SigNotify + _SigDefault, "SIGTTIN: background tty read attempted"},
+	/* 27 */ {_SigNotify + _SigDefault, "SIGTTOU: background tty write attempted"},
+	/* 28 */ {_SigNotify, "SIGVTALRM: virtual timer expired"},
+	/* 29 */ {_SigNotify + _SigUnblock, "SIGPROF: profiling timer expired"},
+	/* 30 */ {_SigNotify, "SIGXCPU: exceeded cpu limit"},
+	/* 31 */ {_SigNotify, "SIGXFSZ: exceeded file size limit"},
+	/* 32 */ {_SigNotify, "SIGWAITING: reserved signal no longer used by"},
+	/* 33 */ {_SigNotify, "SIGLWP: reserved signal no longer used by"},
+	/* 34 */ {_SigNotify, "SIGFREEZE: special signal used by CPR"},
+	/* 35 */ {_SigNotify, "SIGTHAW: special signal used by CPR"},
+	/* 36 */ {0, "SIGCANCEL: reserved signal for thread cancellation"},
+	/* 37 */ {_SigNotify, "SIGLOST: resource lost (eg, record-lock lost)"},
+	/* 38 */ {_SigNotify, "SIGXRES: resource control exceeded"},
+	/* 39 */ {_SigNotify, "SIGJVM1: reserved signal for Java Virtual Machine"},
+	/* 40 */ {_SigNotify, "SIGJVM2: reserved signal for Java Virtual Machine"},
+
+	/* TODO(aram): what should be do about these signals? _SigDefault or _SigNotify? is this set static? */
+	/* 41 */ {_SigNotify, "real time signal"},
+	/* 42 */ {_SigNotify, "real time signal"},
+	/* 43 */ {_SigNotify, "real time signal"},
+	/* 44 */ {_SigNotify, "real time signal"},
+	/* 45 */ {_SigNotify, "real time signal"},
+	/* 46 */ {_SigNotify, "real time signal"},
+	/* 47 */ {_SigNotify, "real time signal"},
+	/* 48 */ {_SigNotify, "real time signal"},
+	/* 49 */ {_SigNotify, "real time signal"},
+	/* 50 */ {_SigNotify, "real time signal"},
+	/* 51 */ {_SigNotify, "real time signal"},
+	/* 52 */ {_SigNotify, "real time signal"},
+	/* 53 */ {_SigNotify, "real time signal"},
+	/* 54 */ {_SigNotify, "real time signal"},
+	/* 55 */ {_SigNotify, "real time signal"},
+	/* 56 */ {_SigNotify, "real time signal"},
+	/* 57 */ {_SigNotify, "real time signal"},
+	/* 58 */ {_SigNotify, "real time signal"},
+	/* 59 */ {_SigNotify, "real time signal"},
+	/* 60 */ {_SigNotify, "real time signal"},
+	/* 61 */ {_SigNotify, "real time signal"},
+	/* 62 */ {_SigNotify, "real time signal"},
+	/* 63 */ {_SigNotify, "real time signal"},
+	/* 64 */ {_SigNotify, "real time signal"},
+	/* 65 */ {_SigNotify, "real time signal"},
+	/* 66 */ {_SigNotify, "real time signal"},
+	/* 67 */ {_SigNotify, "real time signal"},
+	/* 68 */ {_SigNotify, "real time signal"},
+	/* 69 */ {_SigNotify, "real time signal"},
+	/* 70 */ {_SigNotify, "real time signal"},
+	/* 71 */ {_SigNotify, "real time signal"},
+	/* 72 */ {_SigNotify, "real time signal"},
+}
diff --git a/src/runtime/signal_solaris_amd64.go b/src/runtime/signal_solaris_amd64.go
new file mode 100644
index 0000000..a577c8c
--- /dev/null
+++ b/src/runtime/signal_solaris_amd64.go
@@ -0,0 +1,46 @@
+// 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"
+
+type sigctxt struct {
+	info *siginfo
+	ctxt unsafe.Pointer
+}
+
+func (c *sigctxt) regs() *mcontext {
+	return (*mcontext)(unsafe.Pointer(&(*ucontext)(c.ctxt).uc_mcontext))
+}
+func (c *sigctxt) rax() uint64     { return uint64(c.regs().gregs[_REG_RAX]) }
+func (c *sigctxt) rbx() uint64     { return uint64(c.regs().gregs[_REG_RBX]) }
+func (c *sigctxt) rcx() uint64     { return uint64(c.regs().gregs[_REG_RCX]) }
+func (c *sigctxt) rdx() uint64     { return uint64(c.regs().gregs[_REG_RDX]) }
+func (c *sigctxt) rdi() uint64     { return uint64(c.regs().gregs[_REG_RDI]) }
+func (c *sigctxt) rsi() uint64     { return uint64(c.regs().gregs[_REG_RSI]) }
+func (c *sigctxt) rbp() uint64     { return uint64(c.regs().gregs[_REG_RBP]) }
+func (c *sigctxt) rsp() uint64     { return uint64(c.regs().gregs[_REG_RSP]) }
+func (c *sigctxt) r8() uint64      { return uint64(c.regs().gregs[_REG_R8]) }
+func (c *sigctxt) r9() uint64      { return uint64(c.regs().gregs[_REG_R9]) }
+func (c *sigctxt) r10() uint64     { return uint64(c.regs().gregs[_REG_R10]) }
+func (c *sigctxt) r11() uint64     { return uint64(c.regs().gregs[_REG_R11]) }
+func (c *sigctxt) r12() uint64     { return uint64(c.regs().gregs[_REG_R12]) }
+func (c *sigctxt) r13() uint64     { return uint64(c.regs().gregs[_REG_R13]) }
+func (c *sigctxt) r14() uint64     { return uint64(c.regs().gregs[_REG_R14]) }
+func (c *sigctxt) r15() uint64     { return uint64(c.regs().gregs[_REG_R15]) }
+func (c *sigctxt) rip() uint64     { return uint64(c.regs().gregs[_REG_RIP]) }
+func (c *sigctxt) rflags() uint64  { return uint64(c.regs().gregs[_REG_RFLAGS]) }
+func (c *sigctxt) cs() uint64      { return uint64(c.regs().gregs[_REG_CS]) }
+func (c *sigctxt) fs() uint64      { return uint64(c.regs().gregs[_REG_FS]) }
+func (c *sigctxt) gs() uint64      { return uint64(c.regs().gregs[_REG_GS]) }
+func (c *sigctxt) sigcode() uint64 { return uint64(c.info.si_code) }
+func (c *sigctxt) sigaddr() uint64 { return *(*uint64)(unsafe.Pointer(&c.info.__data[0])) }
+
+func (c *sigctxt) set_rip(x uint64)     { c.regs().gregs[_REG_RIP] = int64(x) }
+func (c *sigctxt) set_rsp(x uint64)     { c.regs().gregs[_REG_RSP] = int64(x) }
+func (c *sigctxt) set_sigcode(x uint64) { c.info.si_code = int32(x) }
+func (c *sigctxt) set_sigaddr(x uint64) {
+	*(*uintptr)(unsafe.Pointer(&c.info.__data[0])) = uintptr(x)
+}
diff --git a/src/runtime/signal_solaris_amd64.h b/src/runtime/signal_solaris_amd64.h
deleted file mode 100644
index c2e0a15..0000000
--- a/src/runtime/signal_solaris_amd64.h
+++ /dev/null
@@ -1,31 +0,0 @@
-// 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.
-
-#define SIG_REGS(ctxt) (((Ucontext*)(ctxt))->uc_mcontext)
-
-#define SIG_RAX(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RAX])
-#define SIG_RBX(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RBX])
-#define SIG_RCX(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RCX])
-#define SIG_RDX(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RDX])
-#define SIG_RDI(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RDI])
-#define SIG_RSI(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RSI])
-#define SIG_RBP(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RBP])
-#define SIG_RSP(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RSP])
-#define SIG_R8(info, ctxt) (SIG_REGS(ctxt).gregs[REG_R8])
-#define SIG_R9(info, ctxt) (SIG_REGS(ctxt).gregs[REG_R9])
-#define SIG_R10(info, ctxt) (SIG_REGS(ctxt).gregs[REG_R10])
-#define SIG_R11(info, ctxt) (SIG_REGS(ctxt).gregs[REG_R11])
-#define SIG_R12(info, ctxt) (SIG_REGS(ctxt).gregs[REG_R12])
-#define SIG_R13(info, ctxt) (SIG_REGS(ctxt).gregs[REG_R13])
-#define SIG_R14(info, ctxt) (SIG_REGS(ctxt).gregs[REG_R14])
-#define SIG_R15(info, ctxt) (SIG_REGS(ctxt).gregs[REG_R15])
-#define SIG_RIP(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RIP])
-#define SIG_RFLAGS(info, ctxt) (SIG_REGS(ctxt).gregs[REG_RFLAGS])
-
-#define SIG_CS(info, ctxt) (SIG_REGS(ctxt).gregs[REG_CS])
-#define SIG_FS(info, ctxt) (SIG_REGS(ctxt).gregs[REG_FS])
-#define SIG_GS(info, ctxt) (SIG_REGS(ctxt).gregs[REG_GS])
-
-#define SIG_CODE0(info, ctxt) ((info)->si_code)
-#define SIG_CODE1(info, ctxt) (*(uintptr*)&(info)->__data[0])
diff --git a/src/runtime/signal_unix.c b/src/runtime/signal_unix.c
deleted file mode 100644
index 0e33ece..0000000
--- a/src/runtime/signal_unix.c
+++ /dev/null
@@ -1,119 +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.
-
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
-
-#include "runtime.h"
-#include "defs_GOOS_GOARCH.h"
-#include "os_GOOS.h"
-#include "signal_unix.h"
-
-extern SigTab runtime·sigtab[];
-
-void
-runtime·initsig(void)
-{
-	int32 i;
-	SigTab *t;
-
-	// First call: basic setup.
-	for(i = 0; i<NSIG; i++) {
-		t = &runtime·sigtab[i];
-		if((t->flags == 0) || (t->flags & SigDefault))
-			continue;
-
-		// For some signals, we respect an inherited SIG_IGN handler
-		// rather than insist on installing our own default handler.
-		// Even these signals can be fetched using the os/signal package.
-		switch(i) {
-		case SIGHUP:
-		case SIGINT:
-			if(runtime·getsig(i) == SIG_IGN) {
-				t->flags = SigNotify | SigIgnored;
-				continue;
-			}
-		}
-
-		t->flags |= SigHandling;
-		runtime·setsig(i, runtime·sighandler, true);
-	}
-}
-
-void
-runtime·sigenable(uint32 sig)
-{
-	SigTab *t;
-
-	if(sig >= NSIG)
-		return;
-
-	t = &runtime·sigtab[sig];
-	if((t->flags & SigNotify) && !(t->flags & SigHandling)) {
-		t->flags |= SigHandling;
-		if(runtime·getsig(sig) == SIG_IGN)
-			t->flags |= SigIgnored;
-		runtime·setsig(sig, runtime·sighandler, true);
-	}
-}
-
-void
-runtime·sigdisable(uint32 sig)
-{
-	SigTab *t;
-
-	if(sig >= NSIG)
-		return;
-
-	t = &runtime·sigtab[sig];
-	if((t->flags & SigNotify) && (t->flags & SigHandling)) {
-		t->flags &= ~SigHandling;
-		if(t->flags & SigIgnored)
-			runtime·setsig(sig, SIG_IGN, true);
-		else
-			runtime·setsig(sig, SIG_DFL, true);
-	}
-}
-
-void
-runtime·resetcpuprofiler(int32 hz)
-{
-	Itimerval it;
-
-	runtime·memclr((byte*)&it, sizeof it);
-	if(hz == 0) {
-		runtime·setitimer(ITIMER_PROF, &it, nil);
-	} else {
-		it.it_interval.tv_sec = 0;
-		it.it_interval.tv_usec = 1000000 / hz;
-		it.it_value = it.it_interval;
-		runtime·setitimer(ITIMER_PROF, &it, nil);
-	}
-	g->m->profilehz = hz;
-}
-
-void
-runtime·sigpipe(void)
-{
-	runtime·setsig(SIGPIPE, SIG_DFL, false);
-	runtime·raise(SIGPIPE);
-}
-
-void
-runtime·crash(void)
-{
-#ifdef GOOS_darwin
-	// OS X core dumps are linear dumps of the mapped memory,
-	// from the first virtual byte to the last, with zeros in the gaps.
-	// Because of the way we arrange the address space on 64-bit systems,
-	// this means the OS X core file will be >128 GB and even on a zippy
-	// workstation can take OS X well over an hour to write (uninterruptible).
-	// Save users from making that mistake.
-	if(sizeof(void*) == 8)
-		return;
-#endif
-
-	runtime·unblocksignals();
-	runtime·setsig(SIGABRT, SIG_DFL, false);
-	runtime·raise(SIGABRT);
-}
diff --git a/src/runtime/signal_unix.go b/src/runtime/signal_unix.go
index ba77b6e..ad3ab31 100644
--- a/src/runtime/signal_unix.go
+++ b/src/runtime/signal_unix.go
@@ -6,8 +6,43 @@
 
 package runtime
 
-func sigpipe()
+import "unsafe"
 
+//go:linkname os_sigpipe os.sigpipe
 func os_sigpipe() {
-	onM(sigpipe)
+	systemstack(sigpipe)
+}
+
+// Determines if the signal should be handled by Go and if not, forwards the
+// signal to the handler that was installed before Go's.  Returns whether the
+// signal was forwarded.
+//go:nosplit
+func sigfwdgo(sig uint32, info *siginfo, ctx unsafe.Pointer) bool {
+	g := getg()
+	c := &sigctxt{info, ctx}
+	if sig >= uint32(len(sigtable)) {
+		return false
+	}
+	fwdFn := fwdSig[sig]
+	flags := sigtable[sig].flags
+
+	// If there is no handler to forward to, no need to forward.
+	if fwdFn == _SIG_DFL {
+		return false
+	}
+	// Only forward synchronous signals.
+	if c.sigcode() == _SI_USER || flags&_SigPanic == 0 {
+		return false
+	}
+	// Determine if the signal occurred inside Go code.  We test that:
+	//   (1) we were in a goroutine (i.e., m.curg != nil), and
+	//   (2) we weren't in CGO (i.e., m.curg.syscallsp == 0).
+	if g != nil && g.m != nil && g.m.curg != nil && g.m.curg.syscallsp == 0 {
+		return false
+	}
+	// Signal not handled by Go, forward it.
+	if fwdFn != _SIG_IGN {
+		sigfwd(fwdFn, sig, info, ctx)
+	}
+	return true
 }
diff --git a/src/runtime/signal_unix.h b/src/runtime/signal_unix.h
deleted file mode 100644
index 2d84a01..0000000
--- a/src/runtime/signal_unix.h
+++ /dev/null
@@ -1,14 +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.
-
-#define SIG_DFL ((void*)0)
-#define SIG_IGN ((void*)1)
-
-typedef void GoSighandler(int32, Siginfo*, void*, G*);
-void	runtime·setsig(int32, GoSighandler*, bool);
-GoSighandler* runtime·getsig(int32);
-
-void	runtime·sighandler(int32 sig, Siginfo *info, void *context, G *gp);
-void	runtime·raise(int32);
-
diff --git a/src/runtime/signal_windows.go b/src/runtime/signal_windows.go
new file mode 100644
index 0000000..d80cc97
--- /dev/null
+++ b/src/runtime/signal_windows.go
@@ -0,0 +1,221 @@
+// 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
+
+import (
+	"unsafe"
+)
+
+func disableWER() {
+	// do not display Windows Error Reporting dialogue
+	const (
+		SEM_FAILCRITICALERRORS     = 0x0001
+		SEM_NOGPFAULTERRORBOX      = 0x0002
+		SEM_NOALIGNMENTFAULTEXCEPT = 0x0004
+		SEM_NOOPENFILEERRORBOX     = 0x8000
+	)
+	errormode := uint32(stdcall1(_SetErrorMode, SEM_NOGPFAULTERRORBOX))
+	stdcall1(_SetErrorMode, uintptr(errormode)|SEM_FAILCRITICALERRORS|SEM_NOGPFAULTERRORBOX|SEM_NOOPENFILEERRORBOX)
+}
+
+// in sys_windows_386.s and sys_windows_amd64.s
+func exceptiontramp()
+func firstcontinuetramp()
+func lastcontinuetramp()
+
+func initExceptionHandler() {
+	stdcall2(_AddVectoredExceptionHandler, 1, funcPC(exceptiontramp))
+	if _AddVectoredContinueHandler == nil || unsafe.Sizeof(&_AddVectoredContinueHandler) == 4 {
+		// use SetUnhandledExceptionFilter for windows-386 or
+		// if VectoredContinueHandler is unavailable.
+		// note: SetUnhandledExceptionFilter handler won't be called, if debugging.
+		stdcall1(_SetUnhandledExceptionFilter, funcPC(lastcontinuetramp))
+	} else {
+		stdcall2(_AddVectoredContinueHandler, 1, funcPC(firstcontinuetramp))
+		stdcall2(_AddVectoredContinueHandler, 0, funcPC(lastcontinuetramp))
+	}
+}
+
+func isgoexception(info *exceptionrecord, r *context) bool {
+	// Only handle exception if executing instructions in Go binary
+	// (not Windows library code).
+	// TODO(mwhudson): needs to loop to support shared libs
+	if r.ip() < firstmoduledata.text || firstmoduledata.etext < r.ip() {
+		return false
+	}
+
+	// Go will only handle some exceptions.
+	switch info.exceptioncode {
+	default:
+		return false
+	case _EXCEPTION_ACCESS_VIOLATION:
+	case _EXCEPTION_INT_DIVIDE_BY_ZERO:
+	case _EXCEPTION_INT_OVERFLOW:
+	case _EXCEPTION_FLT_DENORMAL_OPERAND:
+	case _EXCEPTION_FLT_DIVIDE_BY_ZERO:
+	case _EXCEPTION_FLT_INEXACT_RESULT:
+	case _EXCEPTION_FLT_OVERFLOW:
+	case _EXCEPTION_FLT_UNDERFLOW:
+	case _EXCEPTION_BREAKPOINT:
+	}
+	return true
+}
+
+// Called by sigtramp from Windows VEH handler.
+// Return value signals whether the exception has been handled (EXCEPTION_CONTINUE_EXECUTION)
+// or should be made available to other handlers in the chain (EXCEPTION_CONTINUE_SEARCH).
+func exceptionhandler(info *exceptionrecord, r *context, gp *g) int32 {
+	if !isgoexception(info, r) {
+		return _EXCEPTION_CONTINUE_SEARCH
+	}
+
+	// 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 = info.exceptioncode
+	gp.sigcode0 = uintptr(info.exceptioninformation[0])
+	gp.sigcode1 = uintptr(info.exceptioninformation[1])
+	gp.sigpc = r.ip()
+
+	// Only push runtime·sigpanic if r.ip() != 0.
+	// If r.ip() == 0, probably panicked because of a
+	// call to a nil func.  Not pushing that onto sp will
+	// make the trace look like a call to runtime·sigpanic instead.
+	// (Otherwise the trace will end at runtime·sigpanic and we
+	// won't get to see who faulted.)
+	if r.ip() != 0 {
+		sp := unsafe.Pointer(r.sp())
+		sp = add(sp, ^uintptr(unsafe.Sizeof(uintptr(0))-1)) // sp--
+		*((*uintptr)(sp)) = r.ip()
+		r.setsp(uintptr(sp))
+	}
+	r.setip(funcPC(sigpanic))
+	return _EXCEPTION_CONTINUE_EXECUTION
+}
+
+// It seems Windows searches ContinueHandler's list even
+// if ExceptionHandler returns EXCEPTION_CONTINUE_EXECUTION.
+// firstcontinuehandler will stop that search,
+// if exceptionhandler did the same earlier.
+func firstcontinuehandler(info *exceptionrecord, r *context, gp *g) int32 {
+	if !isgoexception(info, r) {
+		return _EXCEPTION_CONTINUE_SEARCH
+	}
+	return _EXCEPTION_CONTINUE_EXECUTION
+}
+
+var testingWER bool
+
+// lastcontinuehandler is reached, because runtime cannot handle
+// current exception. lastcontinuehandler will print crash info and exit.
+func lastcontinuehandler(info *exceptionrecord, r *context, gp *g) int32 {
+	if testingWER {
+		return _EXCEPTION_CONTINUE_SEARCH
+	}
+
+	_g_ := getg()
+
+	if panicking != 0 { // traceback already printed
+		exit(2)
+	}
+	panicking = 1
+
+	print("Exception ", hex(info.exceptioncode), " ", hex(info.exceptioninformation[0]), " ", hex(info.exceptioninformation[1]), " ", hex(r.ip()), "\n")
+
+	print("PC=", hex(r.ip()), "\n")
+	if _g_.m.lockedg != nil && _g_.m.ncgo > 0 && gp == _g_.m.g0 {
+		if iscgo {
+			print("signal arrived during external code execution\n")
+		}
+		gp = _g_.m.lockedg
+	}
+	print("\n")
+
+	var docrash bool
+	if gotraceback(&docrash) > 0 {
+		tracebacktrap(r.ip(), r.sp(), 0, gp)
+		tracebackothers(gp)
+		dumpregs(r)
+	}
+
+	if docrash {
+		crash()
+	}
+
+	exit(2)
+	return 0 // not reached
+}
+
+func sigpanic() {
+	g := getg()
+	if !canpanic(g) {
+		throw("unexpected signal during runtime execution")
+	}
+
+	switch uint32(g.sig) {
+	case _EXCEPTION_ACCESS_VIOLATION:
+		if g.sigcode1 < 0x1000 || g.paniconfault {
+			panicmem()
+		}
+		print("unexpected fault address ", hex(g.sigcode1), "\n")
+		throw("fault")
+	case _EXCEPTION_INT_DIVIDE_BY_ZERO:
+		panicdivide()
+	case _EXCEPTION_INT_OVERFLOW:
+		panicoverflow()
+	case _EXCEPTION_FLT_DENORMAL_OPERAND,
+		_EXCEPTION_FLT_DIVIDE_BY_ZERO,
+		_EXCEPTION_FLT_INEXACT_RESULT,
+		_EXCEPTION_FLT_OVERFLOW,
+		_EXCEPTION_FLT_UNDERFLOW:
+		panicfloat()
+	}
+	throw("fault")
+}
+
+var (
+	badsignalmsg [100]byte
+	badsignallen int32
+)
+
+func setBadSignalMsg() {
+	const msg = "runtime: signal received on thread not created by Go.\n"
+	for i, c := range msg {
+		badsignalmsg[i] = byte(c)
+		badsignallen++
+	}
+}
+
+// Following are not implemented.
+
+func initsig() {
+}
+
+func sigenable(sig uint32) {
+}
+
+func sigdisable(sig uint32) {
+}
+
+func sigignore(sig uint32) {
+}
+
+func badsignal2()
+
+func raisebadsignal(sig int32) {
+	badsignal2()
+}
+
+func crash() {
+	// TODO: This routine should do whatever is needed
+	// to make the Windows program abort/crash as it
+	// would if Go was not intercepting signals.
+	// On Unix the routine would remove the custom signal
+	// handler and then raise a signal (like SIGABRT).
+	// Something like that should happen here.
+	// It's okay to leave this empty for now: if crash returns
+	// the ordinary exit-after-panic happens.
+}
diff --git a/src/runtime/signals_android.h b/src/runtime/signals_android.h
deleted file mode 100644
index 5140d8a..0000000
--- a/src/runtime/signals_android.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "signals_linux.h"
diff --git a/src/runtime/signals_darwin.h b/src/runtime/signals_darwin.h
deleted file mode 100644
index 8761e1b..0000000
--- a/src/runtime/signals_darwin.h
+++ /dev/null
@@ -1,53 +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"
-
-#define N SigNotify
-#define K SigKill
-#define T SigThrow
-#define P SigPanic
-#define D SigDefault
-
-#pragma dataflag NOPTR
-SigTab runtime·sigtab[] = {
-	/* 0 */	0, "SIGNONE: no trap",
-	/* 1 */	N+K, "SIGHUP: terminal line hangup",
-	/* 2 */	N+K, "SIGINT: interrupt",
-	/* 3 */	N+T, "SIGQUIT: quit",
-	/* 4 */	T, "SIGILL: illegal instruction",
-	/* 5 */	T, "SIGTRAP: trace trap",
-	/* 6 */	N+T, "SIGABRT: abort",
-	/* 7 */	T, "SIGEMT: emulate instruction executed",
-	/* 8 */	P, "SIGFPE: floating-point exception",
-	/* 9 */	0, "SIGKILL: kill",
-	/* 10 */	P, "SIGBUS: bus error",
-	/* 11 */	P, "SIGSEGV: segmentation violation",
-	/* 12 */	T, "SIGSYS: bad system call",
-	/* 13 */	N, "SIGPIPE: write to broken pipe",
-	/* 14 */	N, "SIGALRM: alarm clock",
-	/* 15 */	N+K, "SIGTERM: termination",
-	/* 16 */	N, "SIGURG: urgent condition on socket",
-	/* 17 */	0, "SIGSTOP: stop",
-	/* 18 */	N+D, "SIGTSTP: keyboard stop",
-	/* 19 */	0, "SIGCONT: continue after stop",
-	/* 20 */	N, "SIGCHLD: child status has changed",
-	/* 21 */	N+D, "SIGTTIN: background read from tty",
-	/* 22 */	N+D, "SIGTTOU: background write to tty",
-	/* 23 */	N, "SIGIO: i/o now possible",
-	/* 24 */	N, "SIGXCPU: cpu limit exceeded",
-	/* 25 */	N, "SIGXFSZ: file size limit exceeded",
-	/* 26 */	N, "SIGVTALRM: virtual alarm clock",
-	/* 27 */	N, "SIGPROF: profiling alarm clock",
-	/* 28 */	N, "SIGWINCH: window size change",
-	/* 29 */	N, "SIGINFO: status request from keyboard",
-	/* 30 */	N, "SIGUSR1: user-defined signal 1",
-	/* 31 */	N, "SIGUSR2: user-defined signal 2",
-};
-
-#undef N
-#undef K
-#undef T
-#undef P
-#undef D
diff --git a/src/runtime/signals_dragonfly.h b/src/runtime/signals_dragonfly.h
deleted file mode 100644
index 07343a7..0000000
--- a/src/runtime/signals_dragonfly.h
+++ /dev/null
@@ -1,54 +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"
-
-#define N SigNotify
-#define K SigKill
-#define T SigThrow
-#define P SigPanic
-#define D SigDefault
-
-#pragma dataflag NOPTR
-SigTab runtime·sigtab[] = {
-	/* 0 */	0, "SIGNONE: no trap",
-	/* 1 */	N+K, "SIGHUP: terminal line hangup",
-	/* 2 */	N+K, "SIGINT: interrupt",
-	/* 3 */	N+T, "SIGQUIT: quit",
-	/* 4 */	T, "SIGILL: illegal instruction",
-	/* 5 */	T, "SIGTRAP: trace trap",
-	/* 6 */	N+T, "SIGABRT: abort",
-	/* 7 */	T, "SIGEMT: emulate instruction executed",
-	/* 8 */	P, "SIGFPE: floating-point exception",
-	/* 9 */	0, "SIGKILL: kill",
-	/* 10 */	P, "SIGBUS: bus error",
-	/* 11 */	P, "SIGSEGV: segmentation violation",
-	/* 12 */	T, "SIGSYS: bad system call",
-	/* 13 */	N, "SIGPIPE: write to broken pipe",
-	/* 14 */	N, "SIGALRM: alarm clock",
-	/* 15 */	N+K, "SIGTERM: termination",
-	/* 16 */	N, "SIGURG: urgent condition on socket",
-	/* 17 */	0, "SIGSTOP: stop",
-	/* 18 */	N+D, "SIGTSTP: keyboard stop",
-	/* 19 */	0, "SIGCONT: continue after stop",
-	/* 20 */	N, "SIGCHLD: child status has changed",
-	/* 21 */	N+D, "SIGTTIN: background read from tty",
-	/* 22 */	N+D, "SIGTTOU: background write to tty",
-	/* 23 */	N, "SIGIO: i/o now possible",
-	/* 24 */	N, "SIGXCPU: cpu limit exceeded",
-	/* 25 */	N, "SIGXFSZ: file size limit exceeded",
-	/* 26 */	N, "SIGVTALRM: virtual alarm clock",
-	/* 27 */	N, "SIGPROF: profiling alarm clock",
-	/* 28 */	N, "SIGWINCH: window size change",
-	/* 29 */	N, "SIGINFO: status request from keyboard",
-	/* 30 */	N, "SIGUSR1: user-defined signal 1",
-	/* 31 */	N, "SIGUSR2: user-defined signal 2",
-	/* 32 */	N, "SIGTHR: reserved",
-};
-
-#undef N
-#undef K
-#undef T
-#undef P
-#undef D
diff --git a/src/runtime/signals_freebsd.h b/src/runtime/signals_freebsd.h
deleted file mode 100644
index 39e0a94..0000000
--- a/src/runtime/signals_freebsd.h
+++ /dev/null
@@ -1,54 +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"
-
-#define N SigNotify
-#define K SigKill
-#define T SigThrow
-#define P SigPanic
-#define D SigDefault
-
-#pragma dataflag NOPTR
-SigTab runtime·sigtab[] = {
-	/* 0 */	0, "SIGNONE: no trap",
-	/* 1 */	N+K, "SIGHUP: terminal line hangup",
-	/* 2 */	N+K, "SIGINT: interrupt",
-	/* 3 */	N+T, "SIGQUIT: quit",
-	/* 4 */	T, "SIGILL: illegal instruction",
-	/* 5 */	T, "SIGTRAP: trace trap",
-	/* 6 */	N+T, "SIGABRT: abort",
-	/* 7 */	T, "SIGEMT: emulate instruction executed",
-	/* 8 */	P, "SIGFPE: floating-point exception",
-	/* 9 */	0, "SIGKILL: kill",
-	/* 10 */	P, "SIGBUS: bus error",
-	/* 11 */	P, "SIGSEGV: segmentation violation",
-	/* 12 */	N, "SIGSYS: bad system call",
-	/* 13 */	N, "SIGPIPE: write to broken pipe",
-	/* 14 */	N, "SIGALRM: alarm clock",
-	/* 15 */	N+K, "SIGTERM: termination",
-	/* 16 */	N, "SIGURG: urgent condition on socket",
-	/* 17 */	0, "SIGSTOP: stop",
-	/* 18 */	N+D, "SIGTSTP: keyboard stop",
-	/* 19 */	0, "SIGCONT: continue after stop",
-	/* 20 */	N, "SIGCHLD: child status has changed",
-	/* 21 */	N+D, "SIGTTIN: background read from tty",
-	/* 22 */	N+D, "SIGTTOU: background write to tty",
-	/* 23 */	N, "SIGIO: i/o now possible",
-	/* 24 */	N, "SIGXCPU: cpu limit exceeded",
-	/* 25 */	N, "SIGXFSZ: file size limit exceeded",
-	/* 26 */	N, "SIGVTALRM: virtual alarm clock",
-	/* 27 */	N, "SIGPROF: profiling alarm clock",
-	/* 28 */	N, "SIGWINCH: window size change",
-	/* 29 */	N, "SIGINFO: status request from keyboard",
-	/* 30 */	N, "SIGUSR1: user-defined signal 1",
-	/* 31 */	N, "SIGUSR2: user-defined signal 2",
-	/* 32 */	N, "SIGTHR: reserved",
-};
-
-#undef N
-#undef K
-#undef T
-#undef P
-#undef D
diff --git a/src/runtime/signals_linux.h b/src/runtime/signals_linux.h
deleted file mode 100644
index 3741076..0000000
--- a/src/runtime/signals_linux.h
+++ /dev/null
@@ -1,86 +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"
-
-#define N SigNotify
-#define K SigKill
-#define T SigThrow
-#define P SigPanic
-#define D SigDefault
-
-#pragma dataflag NOPTR
-SigTab runtime·sigtab[] = {
-	/* 0 */	0, "SIGNONE: no trap",
-	/* 1 */	N+K, "SIGHUP: terminal line hangup",
-	/* 2 */	N+K, "SIGINT: interrupt",
-	/* 3 */	N+T, "SIGQUIT: quit",
-	/* 4 */	T, "SIGILL: illegal instruction",
-	/* 5 */	T, "SIGTRAP: trace trap",
-	/* 6 */	N+T, "SIGABRT: abort",
-	/* 7 */	P, "SIGBUS: bus error",
-	/* 8 */	P, "SIGFPE: floating-point exception",
-	/* 9 */	0, "SIGKILL: kill",
-	/* 10 */	N, "SIGUSR1: user-defined signal 1",
-	/* 11 */	P, "SIGSEGV: segmentation violation",
-	/* 12 */	N, "SIGUSR2: user-defined signal 2",
-	/* 13 */	N, "SIGPIPE: write to broken pipe",
-	/* 14 */	N, "SIGALRM: alarm clock",
-	/* 15 */	N+K, "SIGTERM: termination",
-	/* 16 */	T, "SIGSTKFLT: stack fault",
-	/* 17 */	N, "SIGCHLD: child status has changed",
-	/* 18 */	0, "SIGCONT: continue",
-	/* 19 */	0, "SIGSTOP: stop, unblockable",
-	/* 20 */	N+D, "SIGTSTP: keyboard stop",
-	/* 21 */	N+D, "SIGTTIN: background read from tty",
-	/* 22 */	N+D, "SIGTTOU: background write to tty",
-	/* 23 */	N, "SIGURG: urgent condition on socket",
-	/* 24 */	N, "SIGXCPU: cpu limit exceeded",
-	/* 25 */	N, "SIGXFSZ: file size limit exceeded",
-	/* 26 */	N, "SIGVTALRM: virtual alarm clock",
-	/* 27 */	N, "SIGPROF: profiling alarm clock",
-	/* 28 */	N, "SIGWINCH: window size change",
-	/* 29 */	N, "SIGIO: i/o now possible",
-	/* 30 */	N, "SIGPWR: power failure restart",
-	/* 31 */	N, "SIGSYS: bad system call",
-	/* 32 */	0, "signal 32", /* SIGCANCEL; see issue 6997 */
-	/* 33 */	0, "signal 33", /* SIGSETXID; see issue 3871 */
-	/* 34 */	N, "signal 34",
-	/* 35 */	N, "signal 35",
-	/* 36 */	N, "signal 36",
-	/* 37 */	N, "signal 37",
-	/* 38 */	N, "signal 38",
-	/* 39 */	N, "signal 39",
-	/* 40 */	N, "signal 40",
-	/* 41 */	N, "signal 41",
-	/* 42 */	N, "signal 42",
-	/* 43 */	N, "signal 43",
-	/* 44 */	N, "signal 44",
-	/* 45 */	N, "signal 45",
-	/* 46 */	N, "signal 46",
-	/* 47 */	N, "signal 47",
-	/* 48 */	N, "signal 48",
-	/* 49 */	N, "signal 49",
-	/* 50 */	N, "signal 50",
-	/* 51 */	N, "signal 51",
-	/* 52 */	N, "signal 52",
-	/* 53 */	N, "signal 53",
-	/* 54 */	N, "signal 54",
-	/* 55 */	N, "signal 55",
-	/* 56 */	N, "signal 56",
-	/* 57 */	N, "signal 57",
-	/* 58 */	N, "signal 58",
-	/* 59 */	N, "signal 59",
-	/* 60 */	N, "signal 60",
-	/* 61 */	N, "signal 61",
-	/* 62 */	N, "signal 62",
-	/* 63 */	N, "signal 63",
-	/* 64 */	N, "signal 64",
-};
-
-#undef N
-#undef K
-#undef T
-#undef P
-#undef D
diff --git a/src/runtime/signals_nacl.h b/src/runtime/signals_nacl.h
deleted file mode 100644
index 8761e1b..0000000
--- a/src/runtime/signals_nacl.h
+++ /dev/null
@@ -1,53 +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"
-
-#define N SigNotify
-#define K SigKill
-#define T SigThrow
-#define P SigPanic
-#define D SigDefault
-
-#pragma dataflag NOPTR
-SigTab runtime·sigtab[] = {
-	/* 0 */	0, "SIGNONE: no trap",
-	/* 1 */	N+K, "SIGHUP: terminal line hangup",
-	/* 2 */	N+K, "SIGINT: interrupt",
-	/* 3 */	N+T, "SIGQUIT: quit",
-	/* 4 */	T, "SIGILL: illegal instruction",
-	/* 5 */	T, "SIGTRAP: trace trap",
-	/* 6 */	N+T, "SIGABRT: abort",
-	/* 7 */	T, "SIGEMT: emulate instruction executed",
-	/* 8 */	P, "SIGFPE: floating-point exception",
-	/* 9 */	0, "SIGKILL: kill",
-	/* 10 */	P, "SIGBUS: bus error",
-	/* 11 */	P, "SIGSEGV: segmentation violation",
-	/* 12 */	T, "SIGSYS: bad system call",
-	/* 13 */	N, "SIGPIPE: write to broken pipe",
-	/* 14 */	N, "SIGALRM: alarm clock",
-	/* 15 */	N+K, "SIGTERM: termination",
-	/* 16 */	N, "SIGURG: urgent condition on socket",
-	/* 17 */	0, "SIGSTOP: stop",
-	/* 18 */	N+D, "SIGTSTP: keyboard stop",
-	/* 19 */	0, "SIGCONT: continue after stop",
-	/* 20 */	N, "SIGCHLD: child status has changed",
-	/* 21 */	N+D, "SIGTTIN: background read from tty",
-	/* 22 */	N+D, "SIGTTOU: background write to tty",
-	/* 23 */	N, "SIGIO: i/o now possible",
-	/* 24 */	N, "SIGXCPU: cpu limit exceeded",
-	/* 25 */	N, "SIGXFSZ: file size limit exceeded",
-	/* 26 */	N, "SIGVTALRM: virtual alarm clock",
-	/* 27 */	N, "SIGPROF: profiling alarm clock",
-	/* 28 */	N, "SIGWINCH: window size change",
-	/* 29 */	N, "SIGINFO: status request from keyboard",
-	/* 30 */	N, "SIGUSR1: user-defined signal 1",
-	/* 31 */	N, "SIGUSR2: user-defined signal 2",
-};
-
-#undef N
-#undef K
-#undef T
-#undef P
-#undef D
diff --git a/src/runtime/signals_netbsd.h b/src/runtime/signals_netbsd.h
deleted file mode 100644
index 950a2fe..0000000
--- a/src/runtime/signals_netbsd.h
+++ /dev/null
@@ -1,54 +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"
-
-#define N SigNotify
-#define K SigKill
-#define T SigThrow
-#define P SigPanic
-#define D SigDefault
-
-#pragma dataflag NOPTR
-SigTab runtime·sigtab[] = {
-	/*  0 */	0, "SIGNONE: no trap",
-	/*  1 */	N+K, "SIGHUP: terminal line hangup",
-	/*  2 */	N+K, "SIGINT: interrupt",
-	/*  3 */	N+T, "SIGQUIT: quit",
-	/*  4 */	T, "SIGILL: illegal instruction",
-	/*  5 */	T, "SIGTRAP: trace trap",
-	/*  6 */	N+T, "SIGABRT: abort",
-	/*  7 */	T, "SIGEMT: emulate instruction executed",
-	/*  8 */	P, "SIGFPE: floating-point exception",
-	/*  9 */	0, "SIGKILL: kill",
-	/* 10 */	P, "SIGBUS: bus error",
-	/* 11 */	P, "SIGSEGV: segmentation violation",
-	/* 12 */	T, "SIGSYS: bad system call",
-	/* 13 */	N, "SIGPIPE: write to broken pipe",
-	/* 14 */	N, "SIGALRM: alarm clock",
-	/* 15 */	N+K, "SIGTERM: termination",
-	/* 16 */	N, "SIGURG: urgent condition on socket",
-	/* 17 */	0, "SIGSTOP: stop",
-	/* 18 */	N+D, "SIGTSTP: keyboard stop",
-	/* 19 */	0, "SIGCONT: continue after stop",
-	/* 20 */	N, "SIGCHLD: child status has changed",
-	/* 21 */	N+D, "SIGTTIN: background read from tty",
-	/* 22 */	N+D, "SIGTTOU: background write to tty",
-	/* 23 */	N, "SIGIO: i/o now possible",
-	/* 24 */	N, "SIGXCPU: cpu limit exceeded",
-	/* 25 */	N, "SIGXFSZ: file size limit exceeded",
-	/* 26 */	N, "SIGVTALRM: virtual alarm clock",
-	/* 27 */	N, "SIGPROF: profiling alarm clock",
-	/* 28 */	N, "SIGWINCH: window size change",
-	/* 29 */	N, "SIGINFO: status request from keyboard",
-	/* 30 */	N, "SIGUSR1: user-defined signal 1",
-	/* 31 */	N, "SIGUSR2: user-defined signal 2",
-	/* 32 */	N, "SIGTHR: reserved",
-};
-
-#undef N
-#undef K
-#undef T
-#undef P
-#undef D
diff --git a/src/runtime/signals_openbsd.h b/src/runtime/signals_openbsd.h
deleted file mode 100644
index 950a2fe..0000000
--- a/src/runtime/signals_openbsd.h
+++ /dev/null
@@ -1,54 +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"
-
-#define N SigNotify
-#define K SigKill
-#define T SigThrow
-#define P SigPanic
-#define D SigDefault
-
-#pragma dataflag NOPTR
-SigTab runtime·sigtab[] = {
-	/*  0 */	0, "SIGNONE: no trap",
-	/*  1 */	N+K, "SIGHUP: terminal line hangup",
-	/*  2 */	N+K, "SIGINT: interrupt",
-	/*  3 */	N+T, "SIGQUIT: quit",
-	/*  4 */	T, "SIGILL: illegal instruction",
-	/*  5 */	T, "SIGTRAP: trace trap",
-	/*  6 */	N+T, "SIGABRT: abort",
-	/*  7 */	T, "SIGEMT: emulate instruction executed",
-	/*  8 */	P, "SIGFPE: floating-point exception",
-	/*  9 */	0, "SIGKILL: kill",
-	/* 10 */	P, "SIGBUS: bus error",
-	/* 11 */	P, "SIGSEGV: segmentation violation",
-	/* 12 */	T, "SIGSYS: bad system call",
-	/* 13 */	N, "SIGPIPE: write to broken pipe",
-	/* 14 */	N, "SIGALRM: alarm clock",
-	/* 15 */	N+K, "SIGTERM: termination",
-	/* 16 */	N, "SIGURG: urgent condition on socket",
-	/* 17 */	0, "SIGSTOP: stop",
-	/* 18 */	N+D, "SIGTSTP: keyboard stop",
-	/* 19 */	0, "SIGCONT: continue after stop",
-	/* 20 */	N, "SIGCHLD: child status has changed",
-	/* 21 */	N+D, "SIGTTIN: background read from tty",
-	/* 22 */	N+D, "SIGTTOU: background write to tty",
-	/* 23 */	N, "SIGIO: i/o now possible",
-	/* 24 */	N, "SIGXCPU: cpu limit exceeded",
-	/* 25 */	N, "SIGXFSZ: file size limit exceeded",
-	/* 26 */	N, "SIGVTALRM: virtual alarm clock",
-	/* 27 */	N, "SIGPROF: profiling alarm clock",
-	/* 28 */	N, "SIGWINCH: window size change",
-	/* 29 */	N, "SIGINFO: status request from keyboard",
-	/* 30 */	N, "SIGUSR1: user-defined signal 1",
-	/* 31 */	N, "SIGUSR2: user-defined signal 2",
-	/* 32 */	N, "SIGTHR: reserved",
-};
-
-#undef N
-#undef K
-#undef T
-#undef P
-#undef D
diff --git a/src/runtime/signals_plan9.h b/src/runtime/signals_plan9.h
deleted file mode 100644
index 4ee8e54..0000000
--- a/src/runtime/signals_plan9.h
+++ /dev/null
@@ -1,63 +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.
-
-#include "textflag.h"
-
-#define N SigNotify
-#define K SigKill
-#define T SigThrow
-#define P SigPanic
-#define E SigGoExit
-
-// Incoming notes are compared against this table using strncmp, so the
-// order matters: longer patterns must appear before their prefixes.
-// There are #defined SIG constants in os_plan9.h for the table index of
-// some of these.
-//
-// If you add entries to this table, you must respect the prefix ordering
-// and also update the constant values is os_plan9.h.
-
-#pragma dataflag NOPTR
-SigTab runtime·sigtab[] = {
-	// Traps that we cannot be recovered.
-	T,	"sys: trap: debug exception",
-	T,	"sys: trap: invalid opcode",
-
-	// We can recover from some memory errors in runtime·sigpanic.
-	P,	"sys: trap: fault read addr",	// SIGRFAULT
-	P,	"sys: trap: fault write addr",	// SIGWFAULT
-
-	// We can also recover from math errors.
-	P,	"sys: trap: divide error",	// SIGINTDIV
-	P,	"sys: fp:",	// SIGFLOAT
-
-	// All other traps are normally handled as if they were marked SigThrow.
-	// We mark them SigPanic here so that debug.SetPanicOnFault will work.
-	P,	"sys: trap:",	// SIGTRAP
-
-	// Writes to a closed pipe can be handled if desired, otherwise they're ignored.
-	N,	"sys: write on closed pipe",
-
-	// Other system notes are more serious and cannot be recovered.
-	T,	"sys:",
-
-	// Issued to all other procs when calling runtime·exit.
-	E,	"go: exit ",
-
-	// Kill is sent by external programs to cause an exit.
-	K,	"kill",
-
-	// Interrupts can be handled if desired, otherwise they cause an exit.
-	N+K,	"interrupt",
-	N+K,	"hangup",
-
-	// Alarms can be handled if desired, otherwise they're ignored.
-	N,	"alarm",
-};
-
-#undef N
-#undef K
-#undef T
-#undef P
-#undef E
diff --git a/src/runtime/signals_solaris.h b/src/runtime/signals_solaris.h
deleted file mode 100644
index 1f0a65e..0000000
--- a/src/runtime/signals_solaris.h
+++ /dev/null
@@ -1,97 +0,0 @@
-// 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"
-
-#define N SigNotify
-#define K SigKill
-#define T SigThrow
-#define P SigPanic
-#define D SigDefault
-
-#pragma dataflag NOPTR
-SigTab runtime·sigtab[] = {
-	/* 0 */		0, "SIGNONE: no trap",
-	/* 1 */		N+K, "SIGHUP: hangup",
-	/* 2 */		N+K, "SIGINT: interrupt (rubout)",
-	/* 3 */		N+T, "SIGQUIT: quit (ASCII FS)",
-	/* 4 */		T, "SIGILL: illegal instruction (not reset when caught)",
-	/* 5 */		T, "SIGTRAP: trace trap (not reset when caught)",
-	/* 6 */		N+T, "SIGABRT: used by abort, replace SIGIOT in the future",
-	/* 7 */		T, "SIGEMT: EMT instruction",
-	/* 8 */		P, "SIGFPE: floating point exception",
-	/* 9 */		0, "SIGKILL: kill (cannot be caught or ignored)",
-	/* 10 */	P, "SIGBUS: bus error",
-	/* 11 */	P, "SIGSEGV: segmentation violation",
-	/* 12 */	T, "SIGSYS: bad argument to system call",
-	/* 13 */	N, "SIGPIPE: write on a pipe with no one to read it",
-	/* 14 */	N, "SIGALRM: alarm clock",
-	/* 15 */	N+K, "SIGTERM: software termination signal from kill",
-	/* 16 */	N, "SIGUSR1: user defined signal 1",
-	/* 17 */	N, "SIGUSR2: user defined signal 2",
-	/* 18 */	N, "SIGCLD: child status change",
-	/* 18 */	N, "SIGCHLD: child status change alias (POSIX)",
-	/* 19 */	N, "SIGPWR: power-fail restart",
-	/* 20 */	N, "SIGWINCH: window size change",
-	/* 21 */	N, "SIGURG: urgent socket condition",
-	/* 22 */	N, "SIGPOLL: pollable event occured",
-	/* 23 */	N+D, "SIGSTOP: stop (cannot be caught or ignored)",
-	/* 24 */	0, "SIGTSTP: user stop requested from tty",
-	/* 25 */	0, "SIGCONT: stopped process has been continued",
-	/* 26 */	N+D, "SIGTTIN: background tty read attempted",
-	/* 27 */	N+D, "SIGTTOU: background tty write attempted",
-	/* 28 */	N, "SIGVTALRM: virtual timer expired",
-	/* 29 */	N, "SIGPROF: profiling timer expired",
-	/* 30 */	N, "SIGXCPU: exceeded cpu limit",
-	/* 31 */	N, "SIGXFSZ: exceeded file size limit",
-	/* 32 */	N, "SIGWAITING: reserved signal no longer used by",
-	/* 33 */	N, "SIGLWP: reserved signal no longer used by",
-	/* 34 */	N, "SIGFREEZE: special signal used by CPR",
-	/* 35 */	N, "SIGTHAW: special signal used by CPR",
-	/* 36 */	0, "SIGCANCEL: reserved signal for thread cancellation",
-	/* 37 */	N, "SIGLOST: resource lost (eg, record-lock lost)",
-	/* 38 */	N, "SIGXRES: resource control exceeded",
-	/* 39 */	N, "SIGJVM1: reserved signal for Java Virtual Machine",
-	/* 40 */	N, "SIGJVM2: reserved signal for Java Virtual Machine",
-
-	/* TODO(aram): what should be do about these signals? D or N? is this set static? */
-	/* 41 */	N, "real time signal",
-	/* 42 */	N, "real time signal",
-	/* 43 */	N, "real time signal",
-	/* 44 */	N, "real time signal",
-	/* 45 */	N, "real time signal",
-	/* 46 */	N, "real time signal",
-	/* 47 */	N, "real time signal",
-	/* 48 */	N, "real time signal",
-	/* 49 */	N, "real time signal",
-	/* 50 */	N, "real time signal",
-	/* 51 */	N, "real time signal",
-	/* 52 */	N, "real time signal",
-	/* 53 */	N, "real time signal",
-	/* 54 */	N, "real time signal",
-	/* 55 */	N, "real time signal",
-	/* 56 */	N, "real time signal",
-	/* 57 */	N, "real time signal",
-	/* 58 */	N, "real time signal",
-	/* 59 */	N, "real time signal",
-	/* 60 */	N, "real time signal",
-	/* 61 */	N, "real time signal",
-	/* 62 */	N, "real time signal",
-	/* 63 */	N, "real time signal",
-	/* 64 */	N, "real time signal",
-	/* 65 */	N, "real time signal",
-	/* 66 */	N, "real time signal",
-	/* 67 */	N, "real time signal",
-	/* 68 */	N, "real time signal",
-	/* 69 */	N, "real time signal",
-	/* 70 */	N, "real time signal",
-	/* 71 */	N, "real time signal",
-	/* 72 */	N, "real time signal",
-};
-
-#undef N
-#undef K
-#undef T
-#undef P
-#undef D
diff --git a/src/runtime/signals_windows.h b/src/runtime/signals_windows.h
deleted file mode 100644
index 6943714..0000000
--- a/src/runtime/signals_windows.h
+++ /dev/null
@@ -1,3 +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.
diff --git a/src/runtime/sigpanic_unix.go b/src/runtime/sigpanic_unix.go
index 6807985..1ce6223 100644
--- a/src/runtime/sigpanic_unix.go
+++ b/src/runtime/sigpanic_unix.go
@@ -6,12 +6,10 @@
 
 package runtime
 
-func signame(int32) *byte
-
 func sigpanic() {
 	g := getg()
 	if !canpanic(g) {
-		gothrow("unexpected signal during runtime execution")
+		throw("unexpected signal during runtime execution")
 	}
 
 	switch g.sig {
@@ -20,13 +18,13 @@ func sigpanic() {
 			panicmem()
 		}
 		print("unexpected fault address ", hex(g.sigcode1), "\n")
-		gothrow("fault")
+		throw("fault")
 	case _SIGSEGV:
 		if (g.sigcode0 == 0 || g.sigcode0 == _SEGV_MAPERR || g.sigcode0 == _SEGV_ACCERR) && g.sigcode1 < 0x1000 || g.paniconfault {
 			panicmem()
 		}
 		print("unexpected fault address ", hex(g.sigcode1), "\n")
-		gothrow("fault")
+		throw("fault")
 	case _SIGFPE:
 		switch g.sigcode0 {
 		case _FPE_INTDIV:
@@ -36,5 +34,20 @@ func sigpanic() {
 		}
 		panicfloat()
 	}
-	panic(errorString(gostringnocopy(signame(g.sig))))
+
+	if g.sig >= uint32(len(sigtable)) {
+		// can't happen: we looked up g.sig in sigtable to decide to call sigpanic
+		throw("unexpected signal value")
+	}
+	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 fed4560..3f50a59 100644
--- a/src/runtime/sigqueue.go
+++ b/src/runtime/sigqueue.go
@@ -24,6 +24,8 @@
 // unnecessary rechecks of sig.mask, but it cannot lead to missed signals
 // nor deadlocks.
 
+// +build !plan9
+
 package runtime
 
 import "unsafe"
@@ -45,7 +47,7 @@ const (
 
 // Called from sighandler to send a signal back out of the signal handling thread.
 // Reports whether the signal was sent. If not, the caller typically crashes the program.
-func sigsend(s int32) bool {
+func sigsend(s uint32) bool {
 	bit := uint32(1) << uint(s&31)
 	if !sig.inuse || s < 0 || int(s) >= 32*len(sig.wanted) || sig.wanted[s/32]&bit == 0 {
 		return false
@@ -67,7 +69,7 @@ Send:
 	for {
 		switch atomicload(&sig.state) {
 		default:
-			gothrow("sigsend: inconsistent state")
+			throw("sigsend: inconsistent state")
 		case sigIdle:
 			if cas(&sig.state, sigIdle, sigSending) {
 				break Send
@@ -103,7 +105,7 @@ func signal_recv() uint32 {
 		for {
 			switch atomicload(&sig.state) {
 			default:
-				gothrow("signal_recv: inconsistent state")
+				throw("signal_recv: inconsistent state")
 			case sigIdle:
 				if cas(&sig.state, sigIdle, sigReceiving) {
 					notetsleepg(&sig.note, -1)
@@ -139,7 +141,7 @@ func signal_enable(s uint32) {
 		return
 	}
 	sig.wanted[s/32] |= 1 << (s & 31)
-	sigenable_go(s)
+	sigenable(s)
 }
 
 // Must only be called from a single goroutine at a time.
@@ -148,35 +150,29 @@ func signal_disable(s uint32) {
 		return
 	}
 	sig.wanted[s/32] &^= 1 << (s & 31)
-	sigdisable_go(s)
+	sigdisable(s)
 }
 
-// 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 {
+// Must only be called from a single goroutine at a time.
+func signal_ignore(s uint32) {
+	if int(s) >= len(sig.wanted)*32 {
 		return
 	}
-	cgocallback(unsafe.Pointer(funcPC(sigsend)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig))
+	sig.wanted[s/32] &^= 1 << (s & 31)
+	sigignore(s)
 }
 
-func sigenable_m()
-func sigdisable_m()
-
-func sigenable_go(s uint32) {
-	g := getg()
-	g.m.scalararg[0] = uintptr(s)
-	onM(sigenable_m)
+// This runs on a foreign stack, without an m or a g.  No stack split.
+//go:nosplit
+//go:norace
+func badsignal(sig uintptr) {
+	cgocallback(unsafe.Pointer(funcPC(badsignalgo)), noescape(unsafe.Pointer(&sig)), unsafe.Sizeof(sig))
 }
 
-func sigdisable_go(s uint32) {
-	g := getg()
-	g.m.scalararg[0] = uintptr(s)
-	onM(sigdisable_m)
+func badsignalgo(sig uintptr) {
+	if !sigsend(uint32(sig)) {
+		// A foreign thread received the signal sig, and the
+		// Go code does not want to handle it.
+		raisebadsignal(int32(sig))
+	}
 }
diff --git a/src/runtime/sigqueue_plan9.go b/src/runtime/sigqueue_plan9.go
new file mode 100644
index 0000000..f000fab
--- /dev/null
+++ b/src/runtime/sigqueue_plan9.go
@@ -0,0 +1,128 @@
+// 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.
+
+// This file implements runtime support for signal handling.
+
+package runtime
+
+const qsize = 64
+
+var sig struct {
+	q     noteQueue
+	inuse bool
+
+	lock     mutex
+	note     note
+	sleeping bool
+}
+
+type noteData struct {
+	s [_ERRMAX]byte
+	n int // n bytes of s are valid
+}
+
+type noteQueue struct {
+	lock mutex
+	data [qsize]noteData
+	ri   int
+	wi   int
+	full bool
+}
+
+// It is not allowed to allocate memory in the signal handler.
+func (q *noteQueue) push(item *byte) bool {
+	lock(&q.lock)
+	if q.full {
+		unlock(&q.lock)
+		return false
+	}
+	s := gostringnocopy(item)
+	copy(q.data[q.wi].s[:], s)
+	q.data[q.wi].n = len(s)
+	q.wi++
+	if q.wi == qsize {
+		q.wi = 0
+	}
+	if q.wi == q.ri {
+		q.full = true
+	}
+	unlock(&q.lock)
+	return true
+}
+
+func (q *noteQueue) pop() string {
+	lock(&q.lock)
+	q.full = false
+	if q.ri == q.wi {
+		unlock(&q.lock)
+		return ""
+	}
+	note := &q.data[q.ri]
+	item := string(note.s[:note.n])
+	q.ri++
+	if q.ri == qsize {
+		q.ri = 0
+	}
+	unlock(&q.lock)
+	return item
+}
+
+// Called from sighandler to send a signal back out of the signal handling thread.
+// Reports whether the signal was sent. If not, the caller typically crashes the program.
+func sendNote(s *byte) bool {
+	if !sig.inuse {
+		return false
+	}
+
+	// Add signal to outgoing queue.
+	if !sig.q.push(s) {
+		return false
+	}
+
+	lock(&sig.lock)
+	if sig.sleeping {
+		sig.sleeping = false
+		notewakeup(&sig.note)
+	}
+	unlock(&sig.lock)
+
+	return true
+}
+
+// Called to receive the next queued signal.
+// Must only be called from a single goroutine at a time.
+func signal_recv() string {
+	for {
+		note := sig.q.pop()
+		if note != "" {
+			return note
+		}
+
+		lock(&sig.lock)
+		sig.sleeping = true
+		noteclear(&sig.note)
+		unlock(&sig.lock)
+		notetsleepg(&sig.note, -1)
+	}
+}
+
+// Must only be called from a single goroutine at a time.
+func signal_enable(s uint32) {
+	if !sig.inuse {
+		// The first call to signal_enable is for us
+		// to use for initialization.  It does not pass
+		// signal information in m.
+		sig.inuse = true // enable reception of signals; cannot disable
+		noteclear(&sig.note)
+		return
+	}
+}
+
+// Must only be called from a single goroutine at a time.
+func signal_disable(s uint32) {
+}
+
+// Must only be called from a single goroutine at a time.
+func signal_ignore(s uint32) {
+}
diff --git a/src/runtime/slice.go b/src/runtime/slice.go
index f457f41..5cda11d 100644
--- a/src/runtime/slice.go
+++ b/src/runtime/slice.go
@@ -8,41 +8,48 @@ import (
 	"unsafe"
 )
 
-type sliceStruct struct {
+type slice struct {
 	array unsafe.Pointer
 	len   int
 	cap   int
 }
 
 // TODO: take uintptrs instead of int64s?
-func makeslice(t *slicetype, len64 int64, cap64 int64) sliceStruct {
+func makeslice(t *slicetype, len64, cap64 int64) slice {
 	// NOTE: The len > MaxMem/elemsize check here is not strictly necessary,
 	// but it produces a 'len out of range' error instead of a 'cap out of range' error
 	// when someone does make([]T, bignumber). 'cap out of range' is true too,
 	// but since the cap is only being supplied implicitly, saying len is clearer.
 	// See issue 4085.
 	len := int(len64)
-	if len64 < 0 || int64(len) != len64 || t.elem.size > 0 && uintptr(len) > maxmem/uintptr(t.elem.size) {
+	if len64 < 0 || int64(len) != len64 || t.elem.size > 0 && uintptr(len) > _MaxMem/uintptr(t.elem.size) {
 		panic(errorString("makeslice: len out of range"))
 	}
 	cap := int(cap64)
-	if cap < len || int64(cap) != cap64 || t.elem.size > 0 && uintptr(cap) > maxmem/uintptr(t.elem.size) {
+	if cap < len || int64(cap) != cap64 || t.elem.size > 0 && uintptr(cap) > _MaxMem/uintptr(t.elem.size) {
 		panic(errorString("makeslice: cap out of range"))
 	}
 	p := newarray(t.elem, uintptr(cap))
-	return sliceStruct{p, len, cap}
+	return slice{p, len, cap}
 }
 
-// TODO: take uintptr instead of int64?
-func growslice(t *slicetype, old sliceStruct, n int64) sliceStruct {
+// growslice_n is a variant of growslice that takes the number of new elements
+// instead of the new minimum capacity.
+// TODO(rsc): This is used by append(slice, slice...).
+// The compiler should change that code to use growslice directly (issue #11419).
+func growslice_n(t *slicetype, old slice, n int) slice {
 	if n < 1 {
 		panic(errorString("growslice: invalid n"))
 	}
+	return growslice(t, old, old.cap+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) {
+// growslice handles slice growth during append.
+// It is passed the slice type, the old slice, and the desired new minimum capacity,
+// and it returns a new slice with at least that capacity, with the old data
+// copied into it.
+func growslice(t *slicetype, old slice, cap int) slice {
+	if cap < old.cap || t.elem.size > 0 && uintptr(cap) > _MaxMem/uintptr(t.elem.size) {
 		panic(errorString("growslice: cap out of range"))
 	}
 
@@ -55,7 +62,7 @@ func growslice(t *slicetype, old sliceStruct, n int64) sliceStruct {
 	if et.size == 0 {
 		// 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}
+		return slice{unsafe.Pointer(&zerobase), old.len, cap}
 	}
 
 	newcap := old.cap
@@ -74,27 +81,34 @@ func growslice(t *slicetype, old sliceStruct, n int64) sliceStruct {
 		}
 	}
 
-	if uintptr(newcap) >= maxmem/uintptr(et.size) {
+	if uintptr(newcap) >= _MaxMem/uintptr(et.size) {
 		panic(errorString("growslice: cap out of range"))
 	}
 	lenmem := uintptr(old.len) * uintptr(et.size)
-	capmem := goroundupsize(uintptr(newcap) * uintptr(et.size))
+	capmem := roundupsize(uintptr(newcap) * uintptr(et.size))
 	newcap = int(capmem / uintptr(et.size))
 	var p unsafe.Pointer
 	if et.kind&kindNoPointers != 0 {
 		p = rawmem(capmem)
+		memmove(p, old.array, lenmem)
 		memclr(add(p, lenmem), capmem-lenmem)
 	} else {
-		// Note: can't use rawmem (which avoids zeroing of memory), because then GC can scan unitialized memory
+		// Note: can't use rawmem (which avoids zeroing of memory), because then GC can scan uninitialized memory.
 		p = newarray(et, uintptr(newcap))
+		if !writeBarrierEnabled {
+			memmove(p, old.array, lenmem)
+		} else {
+			for i := uintptr(0); i < lenmem; i += et.size {
+				typedmemmove(et, add(p, i), add(old.array, i))
+			}
+		}
 	}
-	memmove(p, old.array, lenmem)
 
-	return sliceStruct{p, old.len, newcap}
+	return slice{p, old.len, newcap}
 }
 
-func slicecopy(to sliceStruct, fm sliceStruct, width uintptr) int {
-	if fm.len == 0 || to.len == 0 || width == 0 {
+func slicecopy(to, fm slice, width uintptr) int {
+	if fm.len == 0 || to.len == 0 {
 		return 0
 	}
 
@@ -103,6 +117,10 @@ func slicecopy(to sliceStruct, fm sliceStruct, width uintptr) int {
 		n = to.len
 	}
 
+	if width == 0 {
+		return n
+	}
+
 	if raceenabled {
 		callerpc := getcallerpc(unsafe.Pointer(&to))
 		pc := funcPC(slicecopy)
diff --git a/src/runtime/softfloat64.go b/src/runtime/softfloat64.go
index 4fcf8f2..790dbda 100644
--- a/src/runtime/softfloat64.go
+++ b/src/runtime/softfloat64.go
@@ -340,7 +340,7 @@ func f32to64(f uint32) uint64 {
 	return fpack64(fs64, uint64(fm)<<d, fe, 0)
 }
 
-func fcmp64(f, g uint64) (cmp int, isnan bool) {
+func fcmp64(f, g uint64) (cmp int32, isnan bool) {
 	fs, fm, _, fi, fn := funpack64(f)
 	gs, gm, _, gi, gn := funpack64(g)
 
@@ -483,16 +483,3 @@ again2:
 
 	return q1*b + q0, (un21*b + un0 - q0*v) >> s
 }
-
-// callable from C
-
-func fadd64c(f, g uint64, ret *uint64)            { *ret = fadd64(f, g) }
-func fsub64c(f, g uint64, ret *uint64)            { *ret = fsub64(f, g) }
-func fmul64c(f, g uint64, ret *uint64)            { *ret = fmul64(f, g) }
-func fdiv64c(f, g uint64, ret *uint64)            { *ret = fdiv64(f, g) }
-func fneg64c(f uint64, ret *uint64)               { *ret = fneg64(f) }
-func f32to64c(f uint32, ret *uint64)              { *ret = f32to64(f) }
-func f64to32c(f uint64, ret *uint32)              { *ret = f64to32(f) }
-func fcmp64c(f, g uint64, ret *int, retnan *bool) { *ret, *retnan = fcmp64(f, g) }
-func fintto64c(val int64, ret *uint64)            { *ret = fintto64(val) }
-func f64tointc(f uint64, ret *int64, retok *bool) { *ret, *retok = f64toint(f) }
diff --git a/src/runtime/softfloat64_test.go b/src/runtime/softfloat64_test.go
index df63010..e108872 100644
--- a/src/runtime/softfloat64_test.go
+++ b/src/runtime/softfloat64_test.go
@@ -182,7 +182,7 @@ func hwcmp(f, g float64) (cmp int, isnan bool) {
 func testcmp(t *testing.T, f, g float64) {
 	hcmp, hisnan := hwcmp(f, g)
 	scmp, sisnan := Fcmp64(math.Float64bits(f), math.Float64bits(g))
-	if hcmp != scmp || hisnan != sisnan {
+	if int32(hcmp) != scmp || hisnan != sisnan {
 		err(t, "cmp(%g, %g) = sw %v, %v, hw %v, %v\n", f, g, scmp, sisnan, hcmp, hisnan)
 	}
 }
diff --git a/src/runtime/softfloat_arm.c b/src/runtime/softfloat_arm.c
deleted file mode 100644
index 3f3f33a..0000000
--- a/src/runtime/softfloat_arm.c
+++ /dev/null
@@ -1,687 +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.
-
-// Software floating point interpretaton of ARM 7500 FP instructions.
-// The interpretation is not bit compatible with the 7500.
-// It uses true little-endian doubles, while the 7500 used mixed-endian.
-
-#include "runtime.h"
-#include "textflag.h"
-
-#define CPSR 14
-#define FLAGS_N (1U << 31)
-#define FLAGS_Z (1U << 30)
-#define FLAGS_C (1U << 29)
-#define FLAGS_V (1U << 28)
-
-void	runtime·abort(void);
-void	runtime·sqrtC(uint64, uint64*);
-
-static	uint32	trace = 0;
-
-static void
-fabort(void)
-{
-	if (1) {
-		runtime·printf("Unsupported floating point instruction\n");
-		runtime·abort();
-	}
-}
-
-static void
-putf(uint32 reg, uint32 val)
-{
-	g->m->freglo[reg] = val;
-}
-
-static void
-putd(uint32 reg, uint64 val)
-{
-	g->m->freglo[reg] = (uint32)val;
-	g->m->freghi[reg] = (uint32)(val>>32);
-}
-
-static uint64
-getd(uint32 reg)
-{
-	return (uint64)g->m->freglo[reg] | ((uint64)g->m->freghi[reg]<<32);
-}
-
-static void
-fprint(void)
-{
-	uint32 i;
-	for (i = 0; i < 16; i++) {
-		runtime·printf("\tf%d:\t%X %X\n", i, g->m->freghi[i], g->m->freglo[i]);
-	}
-}
-
-static uint32
-d2f(uint64 d)
-{
-	uint32 x;
-
-	runtime·f64to32c(d, &x);
-	return x;
-}
-
-static uint64
-f2d(uint32 f)
-{
-	uint64 x;
-
-	runtime·f32to64c(f, &x);
-	return x;
-}
-
-static uint32
-fstatus(bool nan, int32 cmp)
-{
-	if(nan)
-		return FLAGS_C | FLAGS_V;
-	if(cmp == 0)
-		return FLAGS_Z | FLAGS_C;
-	if(cmp < 0)
-		return FLAGS_N;
-	return FLAGS_C;
-}
-
-// conditions array record the required CPSR cond field for the
-// first 5 pairs of conditional execution opcodes
-// higher 4 bits are must set, lower 4 bits are must clear
-#pragma dataflag NOPTR
-static const uint8 conditions[10/2] = {
-	[0/2] = (FLAGS_Z >> 24) | 0, // 0: EQ (Z set), 1: NE (Z clear)
-	[2/2] = (FLAGS_C >> 24) | 0, // 2: CS/HS (C set), 3: CC/LO (C clear)
-	[4/2] = (FLAGS_N >> 24) | 0, // 4: MI (N set), 5: PL (N clear)
-	[6/2] = (FLAGS_V >> 24) | 0, // 6: VS (V set), 7: VC (V clear)
-	[8/2] = (FLAGS_C >> 24) | 
-	        (FLAGS_Z >> 28),     // 8: HI (C set and Z clear), 9: LS (C clear and Z set)
-};
-
-#define FAULT (0x80000000U) // impossible PC offset
-
-// returns number of words that the fp instruction
-// is occupying, 0 if next instruction isn't float.
-static uint32
-stepflt(uint32 *pc, uint32 *regs)
-{
-	uint32 i, opc, regd, regm, regn, cpsr;
-	int32 delta;
-	uint32 *addr;
-	uint64 uval;
-	int64 sval;
-	bool nan, ok;
-	int32 cmp;
-	M *m;
-
-	// m is locked in vlop_arm.s, so g->m cannot change during this function call,
-	// so caching it in a local variable is safe.
-	m = g->m;
-	i = *pc;
-
-	if(trace)
-		runtime·printf("stepflt %p %x (cpsr %x)\n", pc, i, regs[CPSR] >> 28);
-
-	opc = i >> 28;
-	if(opc == 14) // common case first
-		goto execute;
-	cpsr = regs[CPSR] >> 28;
-	switch(opc) {
-	case 0: case 1: case 2: case 3: case 4: 
-	case 5: case 6: case 7: case 8: case 9:
-		if(((cpsr & (conditions[opc/2] >> 4)) == (conditions[opc/2] >> 4)) &&
-		   ((cpsr & (conditions[opc/2] & 0xf)) == 0)) {
-			if(opc & 1) return 1;
-		} else {
-			if(!(opc & 1)) return 1;
-		}
-		break;
-	case 10: // GE (N == V)
-	case 11: // LT (N != V)
-		if((cpsr & (FLAGS_N >> 28)) == (cpsr & (FLAGS_V >> 28))) {
-			if(opc & 1) return 1;
-		} else {
-			if(!(opc & 1)) return 1;
-		}
-		break;
-	case 12: // GT (N == V and Z == 0)
-	case 13: // LE (N != V or Z == 1)
-		if((cpsr & (FLAGS_N >> 28)) == (cpsr & (FLAGS_V >> 28)) &&
-		   (cpsr & (FLAGS_Z >> 28)) == 0) {
-			if(opc & 1) return 1;
-		} else {
-			if(!(opc & 1)) return 1;
-		}
-		break;
-	case 14: // AL
-		break;
-	case 15: // shouldn't happen
-		return 0;
-	}
-	if(trace)
-		runtime·printf("conditional %x (cpsr %x) pass\n", opc, cpsr);
-	i = (0xeU << 28) | (i & 0xfffffff);
-
-execute:
-	// special cases
-	if((i&0xfffff000) == 0xe59fb000) {
-		// load r11 from pc-relative address.
-		// might be part of a floating point move
-		// (or might not, but no harm in simulating
-		// one instruction too many).
-		addr = (uint32*)((uint8*)pc + (i&0xfff) + 8);
-		regs[11] = addr[0];
-
-		if(trace)
-			runtime·printf("*** cpu R[%d] = *(%p) %x\n",
-				11, addr, regs[11]);
-		return 1;
-	}
-	if(i == 0xe08bb00d) {
-		// add sp to r11.
-		// might be part of a large stack offset address
-		// (or might not, but again no harm done).
-		regs[11] += regs[13];
-
-		if(trace)
-			runtime·printf("*** cpu R[%d] += R[%d] %x\n",
-				11, 13, regs[11]);
-		return 1;
-	}
-	if(i == 0xeef1fa10) {
-		regs[CPSR] = (regs[CPSR]&0x0fffffff) | m->fflag;
-
-		if(trace)
-			runtime·printf("*** fpsr R[CPSR] = F[CPSR] %x\n", regs[CPSR]);
-		return 1;
-	}
-	if((i&0xff000000) == 0xea000000) {
-		// unconditional branch
-		// can happen in the middle of floating point
-		// if the linker decides it is time to lay down
-		// a sequence of instruction stream constants.
-		delta = i&0xffffff;
-		delta = (delta<<8) >> 8;	// sign extend
-
-		if(trace)
-			runtime·printf("*** cpu PC += %x\n", (delta+2)*4);
-		return delta+2;
-	}
-
-	goto stage1;
-
-stage1:	// load/store regn is cpureg, regm is 8bit offset
-	regd = i>>12 & 0xf;
-	regn = i>>16 & 0xf;
-	regm = (i & 0xff) << 2;	// PLUS or MINUS ??
-
-	switch(i & 0xfff00f00) {
-	default:
-		goto stage2;
-
-	case 0xed900a00:	// single load
-		addr = (uint32*)(regs[regn] + regm);
-		if((uintptr)addr < 4096) {
-			if(trace)
-				runtime·printf("*** load @%p => fault\n", addr);
-			return FAULT;
-		}
-		m->freglo[regd] = addr[0];
-
-		if(trace)
-			runtime·printf("*** load F[%d] = %x\n",
-				regd, m->freglo[regd]);
-		break;
-
-	case 0xed900b00:	// double load
-		addr = (uint32*)(regs[regn] + regm);
-		if((uintptr)addr < 4096) {
-			if(trace)
-				runtime·printf("*** double load @%p => fault\n", addr);
-			return FAULT;
-		}
-		m->freglo[regd] = addr[0];
-		m->freghi[regd] = addr[1];
-
-		if(trace)
-			runtime·printf("*** load D[%d] = %x-%x\n",
-				regd, m->freghi[regd], m->freglo[regd]);
-		break;
-
-	case 0xed800a00:	// single store
-		addr = (uint32*)(regs[regn] + regm);
-		if((uintptr)addr < 4096) {
-			if(trace)
-				runtime·printf("*** store @%p => fault\n", addr);
-			return FAULT;
-		}
-		addr[0] = m->freglo[regd];
-
-		if(trace)
-			runtime·printf("*** *(%p) = %x\n",
-				addr, addr[0]);
-		break;
-
-	case 0xed800b00:	// double store
-		addr = (uint32*)(regs[regn] + regm);
-		if((uintptr)addr < 4096) {
-			if(trace)
-				runtime·printf("*** double store @%p => fault\n", addr);
-			return FAULT;
-		}
-		addr[0] = m->freglo[regd];
-		addr[1] = m->freghi[regd];
-
-		if(trace)
-			runtime·printf("*** *(%p) = %x-%x\n",
-				addr, addr[1], addr[0]);
-		break;
-	}
-	return 1;
-
-stage2:	// regd, regm, regn are 4bit variables
-	regm = i>>0 & 0xf;
-	switch(i & 0xfff00ff0) {
-	default:
-		goto stage3;
-
-	case 0xf3000110:	// veor
-		m->freglo[regd] = m->freglo[regm]^m->freglo[regn];
-		m->freghi[regd] = m->freghi[regm]^m->freghi[regn];
-
-		if(trace)
-			runtime·printf("*** veor D[%d] = %x-%x\n",
-				regd, m->freghi[regd], m->freglo[regd]);
-		break;
-
-	case 0xeeb00b00:	// D[regd] = const(regn,regm)
-		regn = (regn<<4) | regm;
-		regm = 0x40000000UL;
-		if(regn & 0x80)
-			regm |= 0x80000000UL;
-		if(regn & 0x40)
-			regm ^= 0x7fc00000UL;
-		regm |= (regn & 0x3f) << 16;
-		m->freglo[regd] = 0;
-		m->freghi[regd] = regm;
-
-		if(trace)
-			runtime·printf("*** immed D[%d] = %x-%x\n",
-				regd, m->freghi[regd], m->freglo[regd]);
-		break;
-
-	case 0xeeb00a00:	// F[regd] = const(regn,regm)
-		regn = (regn<<4) | regm;
-		regm = 0x40000000UL;
-		if(regn & 0x80)
-			regm |= 0x80000000UL;
-		if(regn & 0x40)
-			regm ^= 0x7e000000UL;
-		regm |= (regn & 0x3f) << 19;
-		m->freglo[regd] = regm;
-
-		if(trace)
-			runtime·printf("*** immed D[%d] = %x\n",
-				regd, m->freglo[regd]);
-		break;
-
-	case 0xee300b00:	// D[regd] = D[regn]+D[regm]
-		runtime·fadd64c(getd(regn), getd(regm), &uval);
-		putd(regd, uval);
-
-		if(trace)
-			runtime·printf("*** add D[%d] = D[%d]+D[%d] %x-%x\n",
-				regd, regn, regm, m->freghi[regd], m->freglo[regd]);
-		break;
-
-	case 0xee300a00:	// F[regd] = F[regn]+F[regm]
-		runtime·fadd64c(f2d(m->freglo[regn]), f2d(m->freglo[regm]), &uval);
-		m->freglo[regd] = d2f(uval);
-
-		if(trace)
-			runtime·printf("*** add F[%d] = F[%d]+F[%d] %x\n",
-				regd, regn, regm, m->freglo[regd]);
-		break;
-
-	case 0xee300b40:	// D[regd] = D[regn]-D[regm]
-		runtime·fsub64c(getd(regn), getd(regm), &uval);
-		putd(regd, uval);
-
-		if(trace)
-			runtime·printf("*** sub D[%d] = D[%d]-D[%d] %x-%x\n",
-				regd, regn, regm, m->freghi[regd], m->freglo[regd]);
-		break;
-
-	case 0xee300a40:	// F[regd] = F[regn]-F[regm]
-		runtime·fsub64c(f2d(m->freglo[regn]), f2d(m->freglo[regm]), &uval);
-		m->freglo[regd] = d2f(uval);
-
-		if(trace)
-			runtime·printf("*** sub F[%d] = F[%d]-F[%d] %x\n",
-				regd, regn, regm, m->freglo[regd]);
-		break;
-
-	case 0xee200b00:	// D[regd] = D[regn]*D[regm]
-		runtime·fmul64c(getd(regn), getd(regm), &uval);
-		putd(regd, uval);
-
-		if(trace)
-			runtime·printf("*** mul D[%d] = D[%d]*D[%d] %x-%x\n",
-				regd, regn, regm, m->freghi[regd], m->freglo[regd]);
-		break;
-
-	case 0xee200a00:	// F[regd] = F[regn]*F[regm]
-		runtime·fmul64c(f2d(m->freglo[regn]), f2d(m->freglo[regm]), &uval);
-		m->freglo[regd] = d2f(uval);
-
-		if(trace)
-			runtime·printf("*** mul F[%d] = F[%d]*F[%d] %x\n",
-				regd, regn, regm, m->freglo[regd]);
-		break;
-
-	case 0xee800b00:	// D[regd] = D[regn]/D[regm]
-		runtime·fdiv64c(getd(regn), getd(regm), &uval);
-		putd(regd, uval);
-
-		if(trace)
-			runtime·printf("*** div D[%d] = D[%d]/D[%d] %x-%x\n",
-				regd, regn, regm, m->freghi[regd], m->freglo[regd]);
-		break;
-
-	case 0xee800a00:	// F[regd] = F[regn]/F[regm]
-		runtime·fdiv64c(f2d(m->freglo[regn]), f2d(m->freglo[regm]), &uval);
-		m->freglo[regd] = d2f(uval);
-
-		if(trace)
-			runtime·printf("*** div F[%d] = F[%d]/F[%d] %x\n",
-				regd, regn, regm, m->freglo[regd]);
-		break;
-
-	case 0xee000b10:	// S[regn] = R[regd] (MOVW) (regm ignored)
-		m->freglo[regn] = regs[regd];
-
-		if(trace)
-			runtime·printf("*** cpy S[%d] = R[%d] %x\n",
-				regn, regd, m->freglo[regn]);
-		break;
-
-	case 0xee100b10:	// R[regd] = S[regn] (MOVW) (regm ignored)
-		regs[regd] = m->freglo[regn];
-
-		if(trace)
-			runtime·printf("*** cpy R[%d] = S[%d] %x\n",
-				regd, regn, regs[regd]);
-		break;
-	}
-	return 1;
-
-stage3:	// regd, regm are 4bit variables
-	switch(i & 0xffff0ff0) {
-	default:
-		goto done;
-
-	case 0xeeb00a40:	// F[regd] = F[regm] (MOVF)
-		m->freglo[regd] = m->freglo[regm];
-
-		if(trace)
-			runtime·printf("*** F[%d] = F[%d] %x\n",
-				regd, regm, m->freglo[regd]);
-		break;
-
-	case 0xeeb00b40:	// D[regd] = D[regm] (MOVD)
-		m->freglo[regd] = m->freglo[regm];
-		m->freghi[regd] = m->freghi[regm];
-
-		if(trace)
-			runtime·printf("*** D[%d] = D[%d] %x-%x\n",
-				regd, regm, m->freghi[regd], m->freglo[regd]);
-		break;
-
-	case 0xeeb10bc0:	// D[regd] = sqrt D[regm]
-		runtime·sqrtC(getd(regm), &uval);
-		putd(regd, uval);
-
-		if(trace)
-			runtime·printf("*** D[%d] = sqrt D[%d] %x-%x\n",
-				regd, regm, m->freghi[regd], m->freglo[regd]);
-		break;
-
-	case 0xeeb00bc0:	// D[regd] = abs D[regm]
-		m->freglo[regd] = m->freglo[regm];
-		m->freghi[regd] = m->freghi[regm] & ((1<<31)-1);
-
-		if(trace)
-			runtime·printf("*** D[%d] = abs D[%d] %x-%x\n",
-					regd, regm, m->freghi[regd], m->freglo[regd]);
-		break;
-
-	case 0xeeb00ac0:	// F[regd] = abs F[regm]
-		m->freglo[regd] = m->freglo[regm] & ((1<<31)-1);
-
-		if(trace)
-			runtime·printf("*** F[%d] = abs F[%d] %x\n",
-					regd, regm, m->freglo[regd]);
-		break;
-
-	case 0xeeb40bc0:	// D[regd] :: D[regm] (CMPD)
-		runtime·fcmp64c(getd(regd), getd(regm), &cmp, &nan);
-		m->fflag = fstatus(nan, cmp);
-
-		if(trace)
-			runtime·printf("*** cmp D[%d]::D[%d] %x\n",
-				regd, regm, m->fflag);
-		break;
-
-	case 0xeeb40ac0:	// F[regd] :: F[regm] (CMPF)
-		runtime·fcmp64c(f2d(m->freglo[regd]), f2d(m->freglo[regm]), &cmp, &nan);
-		m->fflag = fstatus(nan, cmp);
-
-		if(trace)
-			runtime·printf("*** cmp F[%d]::F[%d] %x\n",
-				regd, regm, m->fflag);
-		break;
-
-	case 0xeeb70ac0:	// D[regd] = F[regm] (MOVFD)
-		putd(regd, f2d(m->freglo[regm]));
-
-		if(trace)
-			runtime·printf("*** f2d D[%d]=F[%d] %x-%x\n",
-				regd, regm, m->freghi[regd], m->freglo[regd]);
-		break;
-
-	case 0xeeb70bc0:	// F[regd] = D[regm] (MOVDF)
-		m->freglo[regd] = d2f(getd(regm));
-
-		if(trace)
-			runtime·printf("*** d2f F[%d]=D[%d] %x-%x\n",
-				regd, regm, m->freghi[regd], m->freglo[regd]);
-		break;
-
-	case 0xeebd0ac0:	// S[regd] = F[regm] (MOVFW)
-		runtime·f64tointc(f2d(m->freglo[regm]), &sval, &ok);
-		if(!ok || (int32)sval != sval)
-			sval = 0;
-		m->freglo[regd] = sval;
-
-		if(trace)
-			runtime·printf("*** fix S[%d]=F[%d] %x\n",
-				regd, regm, m->freglo[regd]);
-		break;
-
-	case 0xeebc0ac0:	// S[regd] = F[regm] (MOVFW.U)
-		runtime·f64tointc(f2d(m->freglo[regm]), &sval, &ok);
-		if(!ok || (uint32)sval != sval)
-			sval = 0;
-		m->freglo[regd] = sval;
-
-		if(trace)
-			runtime·printf("*** fix unsigned S[%d]=F[%d] %x\n",
-				regd, regm, m->freglo[regd]);
-		break;
-
-	case 0xeebd0bc0:	// S[regd] = D[regm] (MOVDW)
-		runtime·f64tointc(getd(regm), &sval, &ok);
-		if(!ok || (int32)sval != sval)
-			sval = 0;
-		m->freglo[regd] = sval;
-
-		if(trace)
-			runtime·printf("*** fix S[%d]=D[%d] %x\n",
-				regd, regm, m->freglo[regd]);
-		break;
-
-	case 0xeebc0bc0:	// S[regd] = D[regm] (MOVDW.U)
-		runtime·f64tointc(getd(regm), &sval, &ok);
-		if(!ok || (uint32)sval != sval)
-			sval = 0;
-		m->freglo[regd] = sval;
-
-		if(trace)
-			runtime·printf("*** fix unsigned S[%d]=D[%d] %x\n",
-				regd, regm, m->freglo[regd]);
-		break;
-
-	case 0xeeb80ac0:	// D[regd] = S[regm] (MOVWF)
-		cmp = m->freglo[regm];
-		if(cmp < 0) {
-			runtime·fintto64c(-cmp, &uval);
-			putf(regd, d2f(uval));
-			m->freglo[regd] ^= 0x80000000;
-		} else {
-			runtime·fintto64c(cmp, &uval);
-			putf(regd, d2f(uval));
-		}
-
-		if(trace)
-			runtime·printf("*** float D[%d]=S[%d] %x-%x\n",
-				regd, regm, m->freghi[regd], m->freglo[regd]);
-		break;
-
-	case 0xeeb80a40:	// D[regd] = S[regm] (MOVWF.U)
-		runtime·fintto64c(m->freglo[regm], &uval);
-		putf(regd, d2f(uval));
-
-		if(trace)
-			runtime·printf("*** float unsigned D[%d]=S[%d] %x-%x\n",
-				regd, regm, m->freghi[regd], m->freglo[regd]);
-		break;
-
-	case 0xeeb80bc0:	// D[regd] = S[regm] (MOVWD)
-		cmp = m->freglo[regm];
-		if(cmp < 0) {
-			runtime·fintto64c(-cmp, &uval);
-			putd(regd, uval);
-			m->freghi[regd] ^= 0x80000000;
-		} else {
-			runtime·fintto64c(cmp, &uval);
-			putd(regd, uval);
-		}
-
-		if(trace)
-			runtime·printf("*** float D[%d]=S[%d] %x-%x\n",
-				regd, regm, m->freghi[regd], m->freglo[regd]);
-		break;
-
-	case 0xeeb80b40:	// D[regd] = S[regm] (MOVWD.U)
-		runtime·fintto64c(m->freglo[regm], &uval);
-		putd(regd, uval);
-
-		if(trace)
-			runtime·printf("*** float unsigned D[%d]=S[%d] %x-%x\n",
-				regd, regm, m->freghi[regd], m->freglo[regd]);
-		break;
-	}
-	return 1;
-
-done:
-	if((i&0xff000000) == 0xee000000 ||
-	   (i&0xff000000) == 0xed000000) {
-		runtime·printf("stepflt %p %x\n", pc, i);
-		fabort();
-	}
-	return 0;
-}
-
-typedef struct Sfregs Sfregs;
-
-// NOTE: These are all recorded as pointers because they are possibly live registers,
-// and we don't know what they contain. Recording them as pointers should be
-// safer than not.
-struct Sfregs
-{
-	uint32 *r0;
-	uint32 *r1;
-	uint32 *r2;
-	uint32 *r3;
-	uint32 *r4;
-	uint32 *r5;
-	uint32 *r6;
-	uint32 *r7;
-	uint32 *r8;
-	uint32 *r9;
-	uint32 *r10;
-	uint32 *r11;
-	uint32 *r12;
-	uint32 *r13;
-	uint32 cspr;
-};
-
-static void sfloat2(void);
-void _sfloatpanic(void);
-
-#pragma textflag NOSPLIT
-uint32*
-runtime·_sfloat2(uint32 *pc, Sfregs regs)
-{
-	void (*fn)(void);
-	
-	g->m->ptrarg[0] = pc;
-	g->m->ptrarg[1] = ®s;
-	fn = sfloat2;
-	runtime·onM(&fn);
-	pc = g->m->ptrarg[0];
-	g->m->ptrarg[0] = nil;
-	return pc;
-}
-
-static void
-sfloat2(void)
-{
-	uint32 *pc;
-	G *curg;
-	Sfregs *regs;
-	int32 skip;
-	bool first;
-	
-	pc = g->m->ptrarg[0];
-	regs = g->m->ptrarg[1];
-	g->m->ptrarg[0] = nil;
-	g->m->ptrarg[1] = nil;
-
-	first = true;
-	while(skip = stepflt(pc, (uint32*)&regs->r0)) {
-		first = false;
-		if(skip == FAULT) {
-			// Encountered bad address in store/load.
-			// Record signal information and return to assembly
-			// trampoline that fakes the call.
-			enum { SIGSEGV = 11 };
-			curg = g->m->curg;
-			curg->sig = SIGSEGV;
-			curg->sigcode0 = 0;
-			curg->sigcode1 = 0;
-			curg->sigpc = (uint32)pc;
-			pc = (uint32*)_sfloatpanic;
-			break;
-		}
-		pc += skip;
-	}
-	if(first) {
-		runtime·printf("sfloat2 %p %x\n", pc, *pc);
-		fabort(); // not ok to fail first instruction
-	}
-		
-	g->m->ptrarg[0] = pc;
-}
diff --git a/src/runtime/softfloat_arm.go b/src/runtime/softfloat_arm.go
new file mode 100644
index 0000000..c6eba58
--- /dev/null
+++ b/src/runtime/softfloat_arm.go
@@ -0,0 +1,608 @@
+// 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.
+
+// Software floating point interpretaton of ARM 7500 FP instructions.
+// The interpretation is not bit compatible with the 7500.
+// It uses true little-endian doubles, while the 7500 used mixed-endian.
+
+package runtime
+
+import "unsafe"
+
+const (
+	_CPSR    = 14
+	_FLAGS_N = 1 << 31
+	_FLAGS_Z = 1 << 30
+	_FLAGS_C = 1 << 29
+	_FLAGS_V = 1 << 28
+)
+
+var fptrace = 0
+
+func fabort() {
+	throw("unsupported floating point instruction")
+}
+
+func fputf(reg uint32, val uint32) {
+	_g_ := getg()
+	_g_.m.freglo[reg] = val
+}
+
+func fputd(reg uint32, val uint64) {
+	_g_ := getg()
+	_g_.m.freglo[reg] = uint32(val)
+	_g_.m.freghi[reg] = uint32(val >> 32)
+}
+
+func fgetd(reg uint32) uint64 {
+	_g_ := getg()
+	return uint64(_g_.m.freglo[reg]) | uint64(_g_.m.freghi[reg])<<32
+}
+
+func fprintregs() {
+	_g_ := getg()
+	for i := range _g_.m.freglo {
+		print("\tf", i, ":\t", hex(_g_.m.freghi[i]), " ", hex(_g_.m.freglo[i]), "\n")
+	}
+}
+
+func fstatus(nan bool, cmp int32) uint32 {
+	if nan {
+		return _FLAGS_C | _FLAGS_V
+	}
+	if cmp == 0 {
+		return _FLAGS_Z | _FLAGS_C
+	}
+	if cmp < 0 {
+		return _FLAGS_N
+	}
+	return _FLAGS_C
+}
+
+// conditions array record the required CPSR cond field for the
+// first 5 pairs of conditional execution opcodes
+// higher 4 bits are must set, lower 4 bits are must clear
+var conditions = [10 / 2]uint32{
+	0 / 2: _FLAGS_Z>>24 | 0, // 0: EQ (Z set), 1: NE (Z clear)
+	2 / 2: _FLAGS_C>>24 | 0, // 2: CS/HS (C set), 3: CC/LO (C clear)
+	4 / 2: _FLAGS_N>>24 | 0, // 4: MI (N set), 5: PL (N clear)
+	6 / 2: _FLAGS_V>>24 | 0, // 6: VS (V set), 7: VC (V clear)
+	8 / 2: _FLAGS_C>>24 |
+		_FLAGS_Z>>28,
+}
+
+const _FAULT = 0x80000000 // impossible PC offset
+
+// returns number of words that the fp instruction
+// is occupying, 0 if next instruction isn't float.
+func stepflt(pc *uint32, regs *[15]uint32) uint32 {
+	var i, opc, regd, regm, regn, cpsr uint32
+
+	// m is locked in vlop_arm.s, so g.m cannot change during this function call,
+	// so caching it in a local variable is safe.
+	m := getg().m
+	i = *pc
+
+	if fptrace > 0 {
+		print("stepflt ", pc, " ", hex(i), " (cpsr ", hex(regs[_CPSR]>>28), ")\n")
+	}
+
+	opc = i >> 28
+	if opc == 14 { // common case first
+		goto execute
+	}
+
+	cpsr = regs[_CPSR] >> 28
+	switch opc {
+	case 0, 1, 2, 3, 4, 5, 6, 7, 8, 9:
+		if cpsr&(conditions[opc/2]>>4) == conditions[opc/2]>>4 &&
+			cpsr&(conditions[opc/2]&0xf) == 0 {
+			if opc&1 != 0 {
+				return 1
+			}
+		} else {
+			if opc&1 == 0 {
+				return 1
+			}
+		}
+
+	case 10, 11: // GE (N == V), LT (N != V)
+		if cpsr&(_FLAGS_N>>28) == cpsr&(_FLAGS_V>>28) {
+			if opc&1 != 0 {
+				return 1
+			}
+		} else {
+			if opc&1 == 0 {
+				return 1
+			}
+		}
+
+	case 12, 13: // GT (N == V and Z == 0), LE (N != V or Z == 1)
+		if cpsr&(_FLAGS_N>>28) == cpsr&(_FLAGS_V>>28) &&
+			cpsr&(_FLAGS_Z>>28) == 0 {
+			if opc&1 != 0 {
+				return 1
+			}
+		} else {
+			if opc&1 == 0 {
+				return 1
+			}
+		}
+
+	case 14: // AL
+		// ok
+
+	case 15: // shouldn't happen
+		return 0
+	}
+
+	if fptrace > 0 {
+		print("conditional ", hex(opc), " (cpsr ", hex(cpsr), ") pass\n")
+	}
+	i = 0xe<<28 | i&(1<<28-1)
+
+execute:
+	// special cases
+	if i&0xfffff000 == 0xe59fb000 {
+		// load r11 from pc-relative address.
+		// might be part of a floating point move
+		// (or might not, but no harm in simulating
+		// one instruction too many).
+		addr := (*[1]uint32)(add(unsafe.Pointer(pc), uintptr(i&0xfff+8)))
+		regs[11] = addr[0]
+
+		if fptrace > 0 {
+			print("*** cpu R[11] = *(", addr, ") ", hex(regs[11]), "\n")
+		}
+		return 1
+	}
+	if i == 0xe08bb00d {
+		// add sp to r11.
+		// might be part of a large stack offset address
+		// (or might not, but again no harm done).
+		regs[11] += regs[13]
+
+		if fptrace > 0 {
+			print("*** cpu R[11] += R[13] ", hex(regs[11]), "\n")
+		}
+		return 1
+	}
+	if i == 0xeef1fa10 {
+		regs[_CPSR] = regs[_CPSR]&0x0fffffff | m.fflag
+
+		if fptrace > 0 {
+			print("*** fpsr R[CPSR] = F[CPSR] ", hex(regs[_CPSR]), "\n")
+		}
+		return 1
+	}
+	if i&0xff000000 == 0xea000000 {
+		// unconditional branch
+		// can happen in the middle of floating point
+		// if the linker decides it is time to lay down
+		// a sequence of instruction stream constants.
+		delta := int32(i&0xffffff) << 8 >> 8 // sign extend
+
+		if fptrace > 0 {
+			print("*** cpu PC += ", hex((delta+2)*4), "\n")
+		}
+		return uint32(delta + 2)
+	}
+
+	// load/store regn is cpureg, regm is 8bit offset
+	regd = i >> 12 & 0xf
+	regn = i >> 16 & 0xf
+	regm = i & 0xff << 2 // PLUS or MINUS ??
+
+	switch i & 0xfff00f00 {
+	case 0xed900a00: // single load
+		uaddr := uintptr(regs[regn] + regm)
+		if uaddr < 4096 {
+			if fptrace > 0 {
+				print("*** load @", hex(uaddr), " => fault\n")
+			}
+			return _FAULT
+		}
+		addr := (*[1]uint32)(unsafe.Pointer(uaddr))
+		m.freglo[regd] = addr[0]
+
+		if fptrace > 0 {
+			print("*** load F[", regd, "] = ", hex(m.freglo[regd]), "\n")
+		}
+		return 1
+
+	case 0xed900b00: // double load
+		uaddr := uintptr(regs[regn] + regm)
+		if uaddr < 4096 {
+			if fptrace > 0 {
+				print("*** double load @", hex(uaddr), " => fault\n")
+			}
+			return _FAULT
+		}
+		addr := (*[2]uint32)(unsafe.Pointer(uaddr))
+		m.freglo[regd] = addr[0]
+		m.freghi[regd] = addr[1]
+
+		if fptrace > 0 {
+			print("*** load D[", regd, "] = ", hex(m.freghi[regd]), "-", hex(m.freglo[regd]), "\n")
+		}
+		return 1
+
+	case 0xed800a00: // single store
+		uaddr := uintptr(regs[regn] + regm)
+		if uaddr < 4096 {
+			if fptrace > 0 {
+				print("*** store @", hex(uaddr), " => fault\n")
+			}
+			return _FAULT
+		}
+		addr := (*[1]uint32)(unsafe.Pointer(uaddr))
+		addr[0] = m.freglo[regd]
+
+		if fptrace > 0 {
+			print("*** *(", addr, ") = ", hex(addr[0]), "\n")
+		}
+		return 1
+
+	case 0xed800b00: // double store
+		uaddr := uintptr(regs[regn] + regm)
+		if uaddr < 4096 {
+			if fptrace > 0 {
+				print("*** double store @", hex(uaddr), " => fault\n")
+			}
+			return _FAULT
+		}
+		addr := (*[2]uint32)(unsafe.Pointer(uaddr))
+		addr[0] = m.freglo[regd]
+		addr[1] = m.freghi[regd]
+
+		if fptrace > 0 {
+			print("*** *(", addr, ") = ", hex(addr[1]), "-", hex(addr[0]), "\n")
+		}
+		return 1
+	}
+
+	// regd, regm, regn are 4bit variables
+	regm = i >> 0 & 0xf
+	switch i & 0xfff00ff0 {
+	case 0xf3000110: // veor
+		m.freglo[regd] = m.freglo[regm] ^ m.freglo[regn]
+		m.freghi[regd] = m.freghi[regm] ^ m.freghi[regn]
+
+		if fptrace > 0 {
+			print("*** veor D[", regd, "] = ", hex(m.freghi[regd]), "-", hex(m.freglo[regd]), "\n")
+		}
+		return 1
+
+	case 0xeeb00b00: // D[regd] = const(regn,regm)
+		regn = regn<<4 | regm
+		regm = 0x40000000
+		if regn&0x80 != 0 {
+			regm |= 0x80000000
+		}
+		if regn&0x40 != 0 {
+			regm ^= 0x7fc00000
+		}
+		regm |= regn & 0x3f << 16
+		m.freglo[regd] = 0
+		m.freghi[regd] = regm
+
+		if fptrace > 0 {
+			print("*** immed D[", regd, "] = ", hex(m.freghi[regd]), "-", hex(m.freglo[regd]), "\n")
+		}
+		return 1
+
+	case 0xeeb00a00: // F[regd] = const(regn,regm)
+		regn = regn<<4 | regm
+		regm = 0x40000000
+		if regn&0x80 != 0 {
+			regm |= 0x80000000
+		}
+		if regn&0x40 != 0 {
+			regm ^= 0x7e000000
+		}
+		regm |= regn & 0x3f << 19
+		m.freglo[regd] = regm
+
+		if fptrace > 0 {
+			print("*** immed D[", regd, "] = ", hex(m.freglo[regd]), "\n")
+		}
+		return 1
+
+	case 0xee300b00: // D[regd] = D[regn]+D[regm]
+		fputd(regd, fadd64(fgetd(regn), fgetd(regm)))
+
+		if fptrace > 0 {
+			print("*** add D[", regd, "] = D[", regn, "]+D[", regm, "] ", hex(m.freghi[regd]), "-", hex(m.freglo[regd]), "\n")
+		}
+		return 1
+
+	case 0xee300a00: // F[regd] = F[regn]+F[regm]
+		m.freglo[regd] = f64to32(fadd64(f32to64(m.freglo[regn]), f32to64(m.freglo[regm])))
+
+		if fptrace > 0 {
+			print("*** add F[", regd, "] = F[", regn, "]+F[", regm, "] ", hex(m.freglo[regd]), "\n")
+		}
+		return 1
+
+	case 0xee300b40: // D[regd] = D[regn]-D[regm]
+		fputd(regd, fsub64(fgetd(regn), fgetd(regm)))
+
+		if fptrace > 0 {
+			print("*** sub D[", regd, "] = D[", regn, "]-D[", regm, "] ", hex(m.freghi[regd]), "-", hex(m.freglo[regd]), "\n")
+		}
+		return 1
+
+	case 0xee300a40: // F[regd] = F[regn]-F[regm]
+		m.freglo[regd] = f64to32(fsub64(f32to64(m.freglo[regn]), f32to64(m.freglo[regm])))
+
+		if fptrace > 0 {
+			print("*** sub F[", regd, "] = F[", regn, "]-F[", regm, "] ", hex(m.freglo[regd]), "\n")
+		}
+		return 1
+
+	case 0xee200b00: // D[regd] = D[regn]*D[regm]
+		fputd(regd, fmul64(fgetd(regn), fgetd(regm)))
+
+		if fptrace > 0 {
+			print("*** mul D[", regd, "] = D[", regn, "]*D[", regm, "] ", hex(m.freghi[regd]), "-", hex(m.freglo[regd]), "\n")
+		}
+		return 1
+
+	case 0xee200a00: // F[regd] = F[regn]*F[regm]
+		m.freglo[regd] = f64to32(fmul64(f32to64(m.freglo[regn]), f32to64(m.freglo[regm])))
+
+		if fptrace > 0 {
+			print("*** mul F[", regd, "] = F[", regn, "]*F[", regm, "] ", hex(m.freglo[regd]), "\n")
+		}
+		return 1
+
+	case 0xee800b00: // D[regd] = D[regn]/D[regm]
+		fputd(regd, fdiv64(fgetd(regn), fgetd(regm)))
+
+		if fptrace > 0 {
+			print("*** div D[", regd, "] = D[", regn, "]/D[", regm, "] ", hex(m.freghi[regd]), "-", hex(m.freglo[regd]), "\n")
+		}
+		return 1
+
+	case 0xee800a00: // F[regd] = F[regn]/F[regm]
+		m.freglo[regd] = f64to32(fdiv64(f32to64(m.freglo[regn]), f32to64(m.freglo[regm])))
+
+		if fptrace > 0 {
+			print("*** div F[", regd, "] = F[", regn, "]/F[", regm, "] ", hex(m.freglo[regd]), "\n")
+		}
+		return 1
+
+	case 0xee000b10: // S[regn] = R[regd] (MOVW) (regm ignored)
+		m.freglo[regn] = regs[regd]
+
+		if fptrace > 0 {
+			print("*** cpy S[", regn, "] = R[", regd, "] ", hex(m.freglo[regn]), "\n")
+		}
+		return 1
+
+	case 0xee100b10: // R[regd] = S[regn] (MOVW) (regm ignored)
+		regs[regd] = m.freglo[regn]
+
+		if fptrace > 0 {
+			print("*** cpy R[", regd, "] = S[", regn, "] ", hex(regs[regd]), "\n")
+		}
+		return 1
+	}
+
+	// regd, regm are 4bit variables
+	switch i & 0xffff0ff0 {
+	case 0xeeb00a40: // F[regd] = F[regm] (MOVF)
+		m.freglo[regd] = m.freglo[regm]
+
+		if fptrace > 0 {
+			print("*** F[", regd, "] = F[", regm, "] ", hex(m.freglo[regd]), "\n")
+		}
+		return 1
+
+	case 0xeeb00b40: // D[regd] = D[regm] (MOVD)
+		m.freglo[regd] = m.freglo[regm]
+		m.freghi[regd] = m.freghi[regm]
+
+		if fptrace > 0 {
+			print("*** D[", regd, "] = D[", regm, "] ", hex(m.freghi[regd]), "-", hex(m.freglo[regd]), "\n")
+		}
+		return 1
+
+	case 0xeeb10bc0: // D[regd] = sqrt D[regm]
+		fputd(regd, sqrt(fgetd(regm)))
+
+		if fptrace > 0 {
+			print("*** D[", regd, "] = sqrt D[", regm, "] ", hex(m.freghi[regd]), "-", hex(m.freglo[regd]), "\n")
+		}
+		return 1
+
+	case 0xeeb00bc0: // D[regd] = abs D[regm]
+		m.freglo[regd] = m.freglo[regm]
+		m.freghi[regd] = m.freghi[regm] & (1<<31 - 1)
+
+		if fptrace > 0 {
+			print("*** D[", regd, "] = abs D[", regm, "] ", hex(m.freghi[regd]), "-", hex(m.freglo[regd]), "\n")
+		}
+		return 1
+
+	case 0xeeb00ac0: // F[regd] = abs F[regm]
+		m.freglo[regd] = m.freglo[regm] & (1<<31 - 1)
+
+		if fptrace > 0 {
+			print("*** F[", regd, "] = abs F[", regm, "] ", hex(m.freglo[regd]), "\n")
+		}
+		return 1
+
+	case 0xeeb40bc0: // D[regd] :: D[regm] (CMPD)
+		cmp, nan := fcmp64(fgetd(regd), fgetd(regm))
+		m.fflag = fstatus(nan, cmp)
+
+		if fptrace > 0 {
+			print("*** cmp D[", regd, "]::D[", regm, "] ", hex(m.fflag), "\n")
+		}
+		return 1
+
+	case 0xeeb40ac0: // F[regd] :: F[regm] (CMPF)
+		cmp, nan := fcmp64(f32to64(m.freglo[regd]), f32to64(m.freglo[regm]))
+		m.fflag = fstatus(nan, cmp)
+
+		if fptrace > 0 {
+			print("*** cmp F[", regd, "]::F[", regm, "] ", hex(m.fflag), "\n")
+		}
+		return 1
+
+	case 0xeeb70ac0: // D[regd] = F[regm] (MOVFD)
+		fputd(regd, f32to64(m.freglo[regm]))
+
+		if fptrace > 0 {
+			print("*** f2d D[", regd, "]=F[", regm, "] ", hex(m.freghi[regd]), "-", hex(m.freglo[regd]), "\n")
+		}
+		return 1
+
+	case 0xeeb70bc0: // F[regd] = D[regm] (MOVDF)
+		m.freglo[regd] = f64to32(fgetd(regm))
+
+		if fptrace > 0 {
+			print("*** d2f F[", regd, "]=D[", regm, "] ", hex(m.freghi[regd]), "-", hex(m.freglo[regd]), "\n")
+		}
+		return 1
+
+	case 0xeebd0ac0: // S[regd] = F[regm] (MOVFW)
+		sval, ok := f64toint(f32to64(m.freglo[regm]))
+		if !ok || int64(int32(sval)) != sval {
+			sval = 0
+		}
+		m.freglo[regd] = uint32(sval)
+		if fptrace > 0 {
+			print("*** fix S[", regd, "]=F[", regm, "] ", hex(m.freglo[regd]), "\n")
+		}
+		return 1
+
+	case 0xeebc0ac0: // S[regd] = F[regm] (MOVFW.U)
+		sval, ok := f64toint(f32to64(m.freglo[regm]))
+		if !ok || int64(uint32(sval)) != sval {
+			sval = 0
+		}
+		m.freglo[regd] = uint32(sval)
+
+		if fptrace > 0 {
+			print("*** fix unsigned S[", regd, "]=F[", regm, "] ", hex(m.freglo[regd]), "\n")
+		}
+		return 1
+
+	case 0xeebd0bc0: // S[regd] = D[regm] (MOVDW)
+		sval, ok := f64toint(fgetd(regm))
+		if !ok || int64(int32(sval)) != sval {
+			sval = 0
+		}
+		m.freglo[regd] = uint32(sval)
+
+		if fptrace > 0 {
+			print("*** fix S[", regd, "]=D[", regm, "] ", hex(m.freglo[regd]), "\n")
+		}
+		return 1
+
+	case 0xeebc0bc0: // S[regd] = D[regm] (MOVDW.U)
+		sval, ok := f64toint(fgetd(regm))
+		if !ok || int64(uint32(sval)) != sval {
+			sval = 0
+		}
+		m.freglo[regd] = uint32(sval)
+
+		if fptrace > 0 {
+			print("*** fix unsigned S[", regd, "]=D[", regm, "] ", hex(m.freglo[regd]), "\n")
+		}
+		return 1
+
+	case 0xeeb80ac0: // D[regd] = S[regm] (MOVWF)
+		cmp := int32(m.freglo[regm])
+		if cmp < 0 {
+			fputf(regd, f64to32(fintto64(int64(-cmp))))
+			m.freglo[regd] ^= 0x80000000
+		} else {
+			fputf(regd, f64to32(fintto64(int64(cmp))))
+		}
+
+		if fptrace > 0 {
+			print("*** float D[", regd, "]=S[", regm, "] ", hex(m.freghi[regd]), "-", hex(m.freglo[regd]), "\n")
+		}
+		return 1
+
+	case 0xeeb80a40: // D[regd] = S[regm] (MOVWF.U)
+		fputf(regd, f64to32(fintto64(int64(m.freglo[regm]))))
+
+		if fptrace > 0 {
+			print("*** float unsigned D[", regd, "]=S[", regm, "] ", hex(m.freghi[regd]), "-", hex(m.freglo[regd]), "\n")
+		}
+		return 1
+
+	case 0xeeb80bc0: // D[regd] = S[regm] (MOVWD)
+		cmp := int32(m.freglo[regm])
+		if cmp < 0 {
+			fputd(regd, fintto64(int64(-cmp)))
+			m.freghi[regd] ^= 0x80000000
+		} else {
+			fputd(regd, fintto64(int64(cmp)))
+		}
+
+		if fptrace > 0 {
+			print("*** float D[", regd, "]=S[", regm, "] ", hex(m.freghi[regd]), "-", hex(m.freglo[regd]), "\n")
+		}
+		return 1
+
+	case 0xeeb80b40: // D[regd] = S[regm] (MOVWD.U)
+		fputd(regd, fintto64(int64(m.freglo[regm])))
+
+		if fptrace > 0 {
+			print("*** float unsigned D[", regd, "]=S[", regm, "] ", hex(m.freghi[regd]), "-", hex(m.freglo[regd]), "\n")
+		}
+		return 1
+	}
+
+	if i&0xff000000 == 0xee000000 || i&0xff000000 == 0xed000000 {
+		print("stepflt ", pc, " ", hex(i), "\n")
+		fabort()
+	}
+	return 0
+}
+
+//go:nosplit
+func _sfloat2(pc uint32, regs [15]uint32) (newpc uint32) {
+	systemstack(func() {
+		newpc = sfloat2(pc, &regs)
+	})
+	return
+}
+
+func _sfloatpanic()
+
+func sfloat2(pc uint32, regs *[15]uint32) uint32 {
+	first := true
+	for {
+		skip := stepflt((*uint32)(unsafe.Pointer(uintptr(pc))), regs)
+		if skip == 0 {
+			break
+		}
+		first = false
+		if skip == _FAULT {
+			// Encountered bad address in store/load.
+			// Record signal information and return to assembly
+			// trampoline that fakes the call.
+			const SIGSEGV = 11
+			curg := getg().m.curg
+			curg.sig = SIGSEGV
+			curg.sigcode0 = 0
+			curg.sigcode1 = 0
+			curg.sigpc = uintptr(pc)
+			pc = uint32(funcPC(_sfloatpanic))
+			break
+		}
+		pc += 4 * uint32(skip)
+	}
+	if first {
+		print("sfloat2 ", pc, " ", hex(*(*uint32)(unsafe.Pointer(uintptr(pc)))), "\n")
+		fabort() // not ok to fail first instruction
+	}
+	return pc
+}
diff --git a/src/runtime/sqrt.go b/src/runtime/sqrt.go
index 34a8c38..7452a61 100644
--- a/src/runtime/sqrt.go
+++ b/src/runtime/sqrt.go
@@ -3,11 +3,12 @@
 // license that can be found in the LICENSE file.
 
 // Copy of math/sqrt.go, here for use by ARM softfloat.
+// Modified to not use any floating point arithmetic so
+// that we don't clobber any floating-point registers
+// while emulating the sqrt instruction.
 
 package runtime
 
-import "unsafe"
-
 // The original C code and the long comment below are
 // from FreeBSD's /usr/src/lib/msun/src/e_sqrt.c and
 // came with this notice.  The go code is a simplified
@@ -86,47 +87,53 @@ import "unsafe"
 // Notes:  Rounding mode detection omitted.
 
 const (
-	uvnan      = 0x7FF8000000000001
-	uvinf      = 0x7FF0000000000000
-	uvneginf   = 0xFFF0000000000000
-	mask       = 0x7FF
-	shift      = 64 - 11 - 1
-	bias       = 1023
-	maxFloat64 = 1.797693134862315708145274237317043567981e+308 // 2**1023 * (2**53 - 1) / 2**52
+	float64Mask  = 0x7FF
+	float64Shift = 64 - 11 - 1
+	float64Bias  = 1023
+	float64NaN   = 0x7FF8000000000001
+	float64Inf   = 0x7FF0000000000000
+	maxFloat64   = 1.797693134862315708145274237317043567981e+308 // 2**1023 * (2**53 - 1) / 2**52
 )
 
-func float64bits(f float64) uint64     { return *(*uint64)(unsafe.Pointer(&f)) }
-func float64frombits(b uint64) float64 { return *(*float64)(unsafe.Pointer(&b)) }
+// isnanu returns whether ix represents a NaN floating point number.
+func isnanu(ix uint64) bool {
+	exp := (ix >> float64Shift) & float64Mask
+	sig := ix << (64 - float64Shift) >> (64 - float64Shift)
+	return exp == float64Mask && sig != 0
+}
 
-func sqrt(x float64) float64 {
+func sqrt(ix uint64) uint64 {
 	// special cases
 	switch {
-	case x == 0 || x != x || x > maxFloat64:
-		return x
-	case x < 0:
-		return nan
+	case ix == 0 || ix == 1<<63: // x == 0
+		return ix
+	case isnanu(ix): // x != x
+		return ix
+	case ix&(1<<63) != 0: // x < 0
+		return float64NaN
+	case ix == float64Inf: // x > MaxFloat
+		return ix
 	}
-	ix := float64bits(x)
 	// normalize x
-	exp := int((ix >> shift) & mask)
+	exp := int((ix >> float64Shift) & float64Mask)
 	if exp == 0 { // subnormal x
-		for ix&1<<shift == 0 {
+		for ix&1<<float64Shift == 0 {
 			ix <<= 1
 			exp--
 		}
 		exp++
 	}
-	exp -= bias // unbias exponent
-	ix &^= mask << shift
-	ix |= 1 << shift
+	exp -= float64Bias // unbias exponent
+	ix &^= float64Mask << float64Shift
+	ix |= 1 << float64Shift
 	if exp&1 == 1 { // odd exp, double x to make it even
 		ix <<= 1
 	}
 	exp >>= 1 // exp = exp/2, exponent of square root
 	// generate sqrt(x) bit by bit
 	ix <<= 1
-	var q, s uint64               // q = sqrt(x)
-	r := uint64(1 << (shift + 1)) // r = moving bit from MSB to LSB
+	var q, s uint64                      // q = sqrt(x)
+	r := uint64(1 << (float64Shift + 1)) // r = moving bit from MSB to LSB
 	for r != 0 {
 		t := s + r
 		if t <= ix {
@@ -141,10 +148,6 @@ func sqrt(x float64) float64 {
 	if ix != 0 { // remainder, result not exact
 		q += q & 1 // round according to extra bit
 	}
-	ix = q>>1 + uint64(exp-1+bias)<<shift // significand + biased exponent
-	return float64frombits(ix)
-}
-
-func sqrtC(f float64, r *float64) {
-	*r = sqrt(f)
+	ix = q>>1 + uint64(exp-1+float64Bias)<<float64Shift // significand + biased exponent
+	return ix
 }
diff --git a/src/runtime/sqrt_test.go b/src/runtime/sqrt_test.go
new file mode 100644
index 0000000..d5ccc7f
--- /dev/null
+++ b/src/runtime/sqrt_test.go
@@ -0,0 +1,85 @@
+// 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.
+
+// A copy of Sqrt tests from the math package to test the
+// purely integer arithmetic implementation in sqrt.go.
+
+package runtime_test
+
+import (
+	"math"
+	"runtime"
+	"testing"
+)
+
+func SqrtRT(x float64) float64 {
+	return math.Float64frombits(runtime.Sqrt(math.Float64bits(x)))
+}
+
+func TestSqrt(t *testing.T) {
+	for i := 0; i < len(vf); i++ {
+		a := math.Abs(vf[i])
+		if f := SqrtRT(a); sqrt[i] != f {
+			t.Errorf("Sqrt(%g) = %g, want %g", a, f, sqrt[i])
+		}
+	}
+	for i := 0; i < len(vfsqrtSC); i++ {
+		if f := SqrtRT(vfsqrtSC[i]); !alike(sqrtSC[i], f) {
+			t.Errorf("Sqrt(%g) = %g, want %g", vfsqrtSC[i], f, sqrtSC[i])
+		}
+	}
+}
+
+func alike(a, b float64) bool {
+	switch {
+	case math.IsNaN(a) && math.IsNaN(b):
+		return true
+	case a == b:
+		return math.Signbit(a) == math.Signbit(b)
+	}
+	return false
+}
+
+var vf = []float64{
+	4.9790119248836735e+00,
+	7.7388724745781045e+00,
+	-2.7688005719200159e-01,
+	-5.0106036182710749e+00,
+	9.6362937071984173e+00,
+	2.9263772392439646e+00,
+	5.2290834314593066e+00,
+	2.7279399104360102e+00,
+	1.8253080916808550e+00,
+	-8.6859247685756013e+00,
+}
+
+var sqrt = []float64{
+	2.2313699659365484748756904e+00,
+	2.7818829009464263511285458e+00,
+	5.2619393496314796848143251e-01,
+	2.2384377628763938724244104e+00,
+	3.1042380236055381099288487e+00,
+	1.7106657298385224403917771e+00,
+	2.286718922705479046148059e+00,
+	1.6516476350711159636222979e+00,
+	1.3510396336454586262419247e+00,
+	2.9471892997524949215723329e+00,
+}
+
+var vfsqrtSC = []float64{
+	math.Inf(-1),
+	-math.Pi,
+	math.Copysign(0, -1),
+	0,
+	math.Inf(1),
+	math.NaN(),
+}
+var sqrtSC = []float64{
+	math.NaN(),
+	math.NaN(),
+	math.Copysign(0, -1),
+	0,
+	math.Inf(1),
+	math.NaN(),
+}
diff --git a/src/runtime/stack.c b/src/runtime/stack.c
deleted file mode 100644
index cb95572..0000000
--- a/src/runtime/stack.c
+++ /dev/null
@@ -1,892 +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.
-
-#include "runtime.h"
-#include "arch_GOARCH.h"
-#include "malloc.h"
-#include "stack.h"
-#include "funcdata.h"
-#include "typekind.h"
-#include "type.h"
-#include "race.h"
-#include "mgc0.h"
-#include "textflag.h"
-
-enum
-{
-	// StackDebug == 0: no logging
-	//            == 1: logging of per-stack operations
-	//            == 2: logging of per-frame operations
-	//            == 3: logging of per-word updates
-	//            == 4: logging of per-word reads
-	StackDebug = 0,
-	StackFromSystem = 0,	// allocate stacks from system memory instead of the heap
-	StackFaultOnFree = 0,	// old stacks are mapped noaccess to detect use after free
-	StackPoisonCopy = 0,	// fill stack that should not be accessed with garbage, to detect bad dereferences during copy
-
-	StackCache = 1,
-};
-
-// Global pool of spans that have free stacks.
-// Stacks are assigned an order according to size.
-//     order = log_2(size/FixedStack)
-// There is a free list for each order.
-MSpan runtime·stackpool[NumStackOrders];
-Mutex runtime·stackpoolmu;
-// TODO: one lock per order?
-
-static Stack stackfreequeue;
-
-void
-runtime·stackinit(void)
-{
-	int32 i;
-
-	if((StackCacheSize & PageMask) != 0)
-		runtime·throw("cache size must be a multiple of page size");
-
-	for(i = 0; i < NumStackOrders; i++)
-		runtime·MSpanList_Init(&runtime·stackpool[i]);
-}
-
-// Allocates a stack from the free pool.  Must be called with
-// stackpoolmu held.
-static MLink*
-poolalloc(uint8 order)
-{
-	MSpan *list;
-	MSpan *s;
-	MLink *x;
-	uintptr i;
-
-	list = &runtime·stackpool[order];
-	s = list->next;
-	if(s == list) {
-		// no free stacks.  Allocate another span worth.
-		s = runtime·MHeap_AllocStack(&runtime·mheap, StackCacheSize >> PageShift);
-		if(s == nil)
-			runtime·throw("out of memory");
-		if(s->ref != 0)
-			runtime·throw("bad ref");
-		if(s->freelist != nil)
-			runtime·throw("bad freelist");
-		for(i = 0; i < StackCacheSize; i += FixedStack << order) {
-			x = (MLink*)((s->start << PageShift) + i);
-			x->next = s->freelist;
-			s->freelist = x;
-		}
-		runtime·MSpanList_Insert(list, s);
-	}
-	x = s->freelist;
-	if(x == nil)
-		runtime·throw("span has no free stacks");
-	s->freelist = x->next;
-	s->ref++;
-	if(s->freelist == nil) {
-		// all stacks in s are allocated.
-		runtime·MSpanList_Remove(s);
-	}
-	return x;
-}
-
-// Adds stack x to the free pool.  Must be called with stackpoolmu held.
-static void
-poolfree(MLink *x, uint8 order)
-{
-	MSpan *s;
-
-	s = runtime·MHeap_Lookup(&runtime·mheap, x);
-	if(s->state != MSpanStack)
-		runtime·throw("freeing stack not in a stack span");
-	if(s->freelist == nil) {
-		// s will now have a free stack
-		runtime·MSpanList_Insert(&runtime·stackpool[order], s);
-	}
-	x->next = s->freelist;
-	s->freelist = x;
-	s->ref--;
-	if(s->ref == 0) {
-		// span is completely free - return to heap
-		runtime·MSpanList_Remove(s);
-		s->freelist = nil;
-		runtime·MHeap_FreeStack(&runtime·mheap, s);
-	}
-}
-
-// stackcacherefill/stackcacherelease implement a global pool of stack segments.
-// The pool is required to prevent unlimited growth of per-thread caches.
-static void
-stackcacherefill(MCache *c, uint8 order)
-{
-	MLink *x, *list;
-	uintptr size;
-
-	if(StackDebug >= 1)
-		runtime·printf("stackcacherefill order=%d\n", order);
-
-	// Grab some stacks from the global cache.
-	// Grab half of the allowed capacity (to prevent thrashing).
-	list = nil;
-	size = 0;
-	runtime·lock(&runtime·stackpoolmu);
-	while(size < StackCacheSize/2) {
-		x = poolalloc(order);
-		x->next = list;
-		list = x;
-		size += FixedStack << order;
-	}
-	runtime·unlock(&runtime·stackpoolmu);
-
-	c->stackcache[order].list = list;
-	c->stackcache[order].size = size;
-}
-
-static void
-stackcacherelease(MCache *c, uint8 order)
-{
-	MLink *x, *y;
-	uintptr size;
-
-	if(StackDebug >= 1)
-		runtime·printf("stackcacherelease order=%d\n", order);
-	x = c->stackcache[order].list;
-	size = c->stackcache[order].size;
-	runtime·lock(&runtime·stackpoolmu);
-	while(size > StackCacheSize/2) {
-		y = x->next;
-		poolfree(x, order);
-		x = y;
-		size -= FixedStack << order;
-	}
-	runtime·unlock(&runtime·stackpoolmu);
-	c->stackcache[order].list = x;
-	c->stackcache[order].size = size;
-}
-
-void
-runtime·stackcache_clear(MCache *c)
-{
-	uint8 order;
-	MLink *x, *y;
-
-	if(StackDebug >= 1)
-		runtime·printf("stackcache clear\n");
-	runtime·lock(&runtime·stackpoolmu);
-	for(order = 0; order < NumStackOrders; order++) {
-		x = c->stackcache[order].list;
-		while(x != nil) {
-			y = x->next;
-			poolfree(x, order);
-			x = y;
-		}
-		c->stackcache[order].list = nil;
-		c->stackcache[order].size = 0;
-	}
-	runtime·unlock(&runtime·stackpoolmu);
-}
-
-Stack
-runtime·stackalloc(uint32 n)
-{
-	uint8 order;
-	uint32 n2;
-	void *v;
-	MLink *x;
-	MSpan *s;
-	MCache *c;
-
-	// Stackalloc must be called on scheduler stack, so that we
-	// never try to grow the stack during the code that stackalloc runs.
-	// Doing so would cause a deadlock (issue 1547).
-	if(g != g->m->g0)
-		runtime·throw("stackalloc not on scheduler stack");
-	if((n & (n-1)) != 0)
-		runtime·throw("stack size not a power of 2");
-	if(StackDebug >= 1)
-		runtime·printf("stackalloc %d\n", n);
-
-	if(runtime·debug.efence || StackFromSystem) {
-		v = runtime·sysAlloc(ROUND(n, PageSize), &mstats.stacks_sys);
-		if(v == nil)
-			runtime·throw("out of memory (stackalloc)");
-		return (Stack){(uintptr)v, (uintptr)v+n};
-	}
-
-	// Small stacks are allocated with a fixed-size free-list allocator.
-	// If we need a stack of a bigger size, we fall back on allocating
-	// a dedicated span.
-	if(StackCache && n < FixedStack << NumStackOrders && n < StackCacheSize) {
-		order = 0;
-		n2 = n;
-		while(n2 > FixedStack) {
-			order++;
-			n2 >>= 1;
-		}
-		c = g->m->mcache;
-		if(c == nil || g->m->gcing || g->m->helpgc) {
-			// c == nil can happen in the guts of exitsyscall or
-			// procresize. Just get a stack from the global pool.
-			// Also don't touch stackcache during gc
-			// as it's flushed concurrently.
-			runtime·lock(&runtime·stackpoolmu);
-			x = poolalloc(order);
-			runtime·unlock(&runtime·stackpoolmu);
-		} else {
-			x = c->stackcache[order].list;
-			if(x == nil) {
-				stackcacherefill(c, order);
-				x = c->stackcache[order].list;
-			}
-			c->stackcache[order].list = x->next;
-			c->stackcache[order].size -= n;
-		}
-		v = (byte*)x;
-	} else {
-		s = runtime·MHeap_AllocStack(&runtime·mheap, ROUND(n, PageSize) >> PageShift);
-		if(s == nil)
-			runtime·throw("out of memory");
-		v = (byte*)(s->start<<PageShift);
-	}
-	
-	if(raceenabled)
-		runtime·racemalloc(v, n);
-	if(StackDebug >= 1)
-		runtime·printf("  allocated %p\n", v);
-	return (Stack){(uintptr)v, (uintptr)v+n};
-}
-
-void
-runtime·stackfree(Stack stk)
-{
-	uint8 order;
-	uintptr n, n2;
-	MSpan *s;
-	MLink *x;
-	MCache *c;
-	void *v;
-	
-	n = stk.hi - stk.lo;
-	v = (void*)stk.lo;
-	if(n & (n-1))
-		runtime·throw("stack not a power of 2");
-	if(StackDebug >= 1) {
-		runtime·printf("stackfree %p %d\n", v, (int32)n);
-		runtime·memclr(v, n); // for testing, clobber stack data
-	}
-	if(runtime·debug.efence || StackFromSystem) {
-		if(runtime·debug.efence || StackFaultOnFree)
-			runtime·SysFault(v, n);
-		else
-			runtime·SysFree(v, n, &mstats.stacks_sys);
-		return;
-	}
-	if(StackCache && n < FixedStack << NumStackOrders && n < StackCacheSize) {
-		order = 0;
-		n2 = n;
-		while(n2 > FixedStack) {
-			order++;
-			n2 >>= 1;
-		}
-		x = (MLink*)v;
-		c = g->m->mcache;
-		if(c == nil || g->m->gcing || g->m->helpgc) {
-			runtime·lock(&runtime·stackpoolmu);
-			poolfree(x, order);
-			runtime·unlock(&runtime·stackpoolmu);
-		} else {
-			if(c->stackcache[order].size >= StackCacheSize)
-				stackcacherelease(c, order);
-			x->next = c->stackcache[order].list;
-			c->stackcache[order].list = x;
-			c->stackcache[order].size += n;
-		}
-	} else {
-		s = runtime·MHeap_Lookup(&runtime·mheap, v);
-		if(s->state != MSpanStack) {
-			runtime·printf("%p %p\n", s->start<<PageShift, v);
-			runtime·throw("bad span state");
-		}
-		runtime·MHeap_FreeStack(&runtime·mheap, s);
-	}
-}
-
-uintptr runtime·maxstacksize = 1<<20; // enough until runtime.main sets it for real
-
-static uint8*
-mapnames[] = {
-	(uint8*)"---",
-	(uint8*)"scalar",
-	(uint8*)"ptr",
-	(uint8*)"multi",
-};
-
-// Stack frame layout
-//
-// (x86)
-// +------------------+
-// | args from caller |
-// +------------------+ <- frame->argp
-// |  return address  |
-// +------------------+ <- frame->varp
-// |     locals       |
-// +------------------+
-// |  args to callee  |
-// +------------------+ <- frame->sp
-//
-// (arm)
-// +------------------+
-// | args from caller |
-// +------------------+ <- frame->argp
-// | caller's retaddr |
-// +------------------+ <- frame->varp
-// |     locals       |
-// +------------------+
-// |  args to callee  |
-// +------------------+
-// |  return address  |
-// +------------------+ <- frame->sp
-
-void runtime·main(void);
-void runtime·switchtoM(void(*)(void));
-
-typedef struct AdjustInfo AdjustInfo;
-struct AdjustInfo {
-	Stack old;
-	uintptr delta;  // ptr distance from old to new stack (newbase - oldbase)
-};
-
-// Adjustpointer checks whether *vpp is in the old stack described by adjinfo.
-// If so, it rewrites *vpp to point into the new stack.
-static void
-adjustpointer(AdjustInfo *adjinfo, void *vpp)
-{
-	byte **pp, *p;
-	
-	pp = vpp;
-	p = *pp;
-	if(StackDebug >= 4)
-		runtime·printf("        %p:%p\n", pp, p);
-	if(adjinfo->old.lo <= (uintptr)p && (uintptr)p < adjinfo->old.hi) {
-		*pp = p + adjinfo->delta;
-		if(StackDebug >= 3)
-			runtime·printf("        adjust ptr %p: %p -> %p\n", pp, p, *pp);
-	}
-}
-
-// bv describes the memory starting at address scanp.
-// Adjust any pointers contained therein.
-static void
-adjustpointers(byte **scanp, BitVector *bv, AdjustInfo *adjinfo, Func *f)
-{
-	uintptr delta;
-	int32 num, i;
-	byte *p, *minp, *maxp;
-	Type *t;
-	Itab *tab;
-	
-	minp = (byte*)adjinfo->old.lo;
-	maxp = (byte*)adjinfo->old.hi;
-	delta = adjinfo->delta;
-	num = bv->n / BitsPerPointer;
-	for(i = 0; i < num; i++) {
-		if(StackDebug >= 4)
-			runtime·printf("        %p:%s:%p\n", &scanp[i], mapnames[bv->bytedata[i / (8 / BitsPerPointer)] >> (i * BitsPerPointer & 7) & 3], scanp[i]);
-		switch(bv->bytedata[i / (8 / BitsPerPointer)] >> (i * BitsPerPointer & 7) & 3) {
-		case BitsDead:
-			if(runtime·debug.gcdead)
-				scanp[i] = (byte*)PoisonStack;
-			break;
-		case BitsScalar:
-			break;
-		case BitsPointer:
-			p = scanp[i];
-			if(f != nil && (byte*)0 < p && (p < (byte*)PageSize && runtime·invalidptr || (uintptr)p == PoisonGC || (uintptr)p == PoisonStack)) {
-				// Looks like a junk value in a pointer slot.
-				// Live analysis wrong?
-				g->m->traceback = 2;
-				runtime·printf("runtime: bad pointer in frame %s at %p: %p\n", runtime·funcname(f), &scanp[i], p);
-				runtime·throw("invalid stack pointer");
-			}
-			if(minp <= p && p < maxp) {
-				if(StackDebug >= 3)
-					runtime·printf("adjust ptr %p %s\n", p, runtime·funcname(f));
-				scanp[i] = p + delta;
-			}
-			break;
-		case BitsMultiWord:
-			switch(bv->bytedata[(i+1) / (8 / BitsPerPointer)] >> ((i+1) * BitsPerPointer & 7) & 3) {
-			default:
-				runtime·throw("unexpected garbage collection bits");
-			case BitsEface:
-				t = (Type*)scanp[i];
-				if(t != nil && ((t->kind & KindDirectIface) == 0 || (t->kind & KindNoPointers) == 0)) {
-					p = scanp[i+1];
-					if(minp <= p && p < maxp) {
-						if(StackDebug >= 3)
-							runtime·printf("adjust eface %p\n", p);
-						if(t->size > PtrSize) // currently we always allocate such objects on the heap
-							runtime·throw("large interface value found on stack");
-						scanp[i+1] = p + delta;
-					}
-				}
-				i++;
-				break;
-			case BitsIface:
-				tab = (Itab*)scanp[i];
-				if(tab != nil) {
-					t = tab->type;
-					//runtime·printf("          type=%p\n", t);
-					if((t->kind & KindDirectIface) == 0 || (t->kind & KindNoPointers) == 0) {
-						p = scanp[i+1];
-						if(minp <= p && p < maxp) {
-							if(StackDebug >= 3)
-								runtime·printf("adjust iface %p\n", p);
-							if(t->size > PtrSize) // currently we always allocate such objects on the heap
-								runtime·throw("large interface value found on stack");
-							scanp[i+1] = p + delta;
-						}
-					}
-				}
-				i++;
-				break;
-			}
-			break;
-		}
-	}
-}
-
-// Note: the argument/return area is adjusted by the callee.
-static bool
-adjustframe(Stkframe *frame, void *arg)
-{
-	AdjustInfo *adjinfo;
-	Func *f;
-	StackMap *stackmap;
-	int32 pcdata;
-	BitVector bv;
-	uintptr targetpc, size, minsize;
-
-	adjinfo = arg;
-	targetpc = frame->continpc;
-	if(targetpc == 0) {
-		// Frame is dead.
-		return true;
-	}
-	f = frame->fn;
-	if(StackDebug >= 2)
-		runtime·printf("    adjusting %s frame=[%p,%p] pc=%p continpc=%p\n", runtime·funcname(f), frame->sp, frame->fp, frame->pc, frame->continpc);
-	if(f->entry == (uintptr)runtime·switchtoM) {
-		// A special routine at the bottom of stack of a goroutine that does an onM call.
-		// We will allow it to be copied even though we don't
-		// have full GC info for it (because it is written in asm).
-		return true;
-	}
-	if(targetpc != f->entry)
-		targetpc--;
-	pcdata = runtime·pcdatavalue(f, PCDATA_StackMapIndex, targetpc);
-	if(pcdata == -1)
-		pcdata = 0; // in prologue
-
-	// Adjust local variables if stack frame has been allocated.
-	size = frame->varp - frame->sp;
-	if(thechar != '6' && thechar != '8')
-		minsize = sizeof(uintptr);
-	else
-		minsize = 0;
-	if(size > minsize) {
-		stackmap = runtime·funcdata(f, FUNCDATA_LocalsPointerMaps);
-		if(stackmap == nil || stackmap->n <= 0) {
-			runtime·printf("runtime: frame %s untyped locals %p+%p\n", runtime·funcname(f), (byte*)(frame->varp-size), size);
-			runtime·throw("missing stackmap");
-		}
-		// Locals bitmap information, scan just the pointers in locals.
-		if(pcdata < 0 || pcdata >= stackmap->n) {
-			// don't know where we are
-			runtime·printf("runtime: pcdata is %d and %d locals stack map entries for %s (targetpc=%p)\n",
-				pcdata, stackmap->n, runtime·funcname(f), targetpc);
-			runtime·throw("bad symbol table");
-		}
-		bv = runtime·stackmapdata(stackmap, pcdata);
-		size = (bv.n * PtrSize) / BitsPerPointer;
-		if(StackDebug >= 3)
-			runtime·printf("      locals\n");
-		adjustpointers((byte**)(frame->varp - size), &bv, adjinfo, f);
-	}
-	
-	// Adjust arguments.
-	if(frame->arglen > 0) {
-		if(frame->argmap != nil) {
-			bv = *frame->argmap;
-		} else {
-			stackmap = runtime·funcdata(f, FUNCDATA_ArgsPointerMaps);
-			if(stackmap == nil || stackmap->n <= 0) {
-				runtime·printf("runtime: frame %s untyped args %p+%p\n", runtime·funcname(f), frame->argp, (uintptr)frame->arglen);
-				runtime·throw("missing stackmap");
-			}
-			if(pcdata < 0 || pcdata >= stackmap->n) {
-				// don't know where we are
-				runtime·printf("runtime: pcdata is %d and %d args stack map entries for %s (targetpc=%p)\n",
-					pcdata, stackmap->n, runtime·funcname(f), targetpc);
-				runtime·throw("bad symbol table");
-			}
-			bv = runtime·stackmapdata(stackmap, pcdata);
-		}
-		if(StackDebug >= 3)
-			runtime·printf("      args\n");
-		adjustpointers((byte**)frame->argp, &bv, adjinfo, nil);
-	}
-	
-	return true;
-}
-
-static void
-adjustctxt(G *gp, AdjustInfo *adjinfo)
-{
-	adjustpointer(adjinfo, &gp->sched.ctxt);
-}
-
-static void
-adjustdefers(G *gp, AdjustInfo *adjinfo)
-{
-	Defer *d;
-	bool (*cb)(Stkframe*, void*);
-
-	// Adjust defer argument blocks the same way we adjust active stack frames.
-	cb = adjustframe;
-	runtime·tracebackdefers(gp, &cb, adjinfo);
-
-	// Adjust pointers in the Defer structs.
-	// Defer structs themselves are never on the stack.
-	for(d = gp->defer; d != nil; d = d->link) {
-		adjustpointer(adjinfo, &d->fn);
-		adjustpointer(adjinfo, &d->argp);
-		adjustpointer(adjinfo, &d->panic);
-	}
-}
-
-static void
-adjustpanics(G *gp, AdjustInfo *adjinfo)
-{
-	// Panics are on stack and already adjusted.
-	// Update pointer to head of list in G.
-	adjustpointer(adjinfo, &gp->panic);
-}
-
-static void
-adjustsudogs(G *gp, AdjustInfo *adjinfo)
-{
-	SudoG *s;
-
-	// the data elements pointed to by a SudoG structure
-	// might be in the stack.
-	for(s = gp->waiting; s != nil; s = s->waitlink) {
-		adjustpointer(adjinfo, &s->elem);
-		adjustpointer(adjinfo, &s->selectdone);
-	}
-}
-
-// Copies gp's stack to a new stack of a different size.
-static void
-copystack(G *gp, uintptr newsize)
-{
-	Stack old, new;
-	uintptr used;
-	AdjustInfo adjinfo;
-	uint32 oldstatus;
-	bool (*cb)(Stkframe*, void*);
-	byte *p, *ep;
-
-	if(gp->syscallsp != 0)
-		runtime·throw("stack growth not allowed in system call");
-	old = gp->stack;
-	if(old.lo == 0)
-		runtime·throw("nil stackbase");
-	used = old.hi - gp->sched.sp;
-
-	// allocate new stack
-	new = runtime·stackalloc(newsize);
-	if(StackPoisonCopy) {
-		p = (byte*)new.lo;
-		ep = (byte*)new.hi;
-		while(p < ep)
-			*p++ = 0xfd;
-	}
-
-	if(StackDebug >= 1)
-		runtime·printf("copystack gp=%p [%p %p %p]/%d -> [%p %p %p]/%d\n", gp, old.lo, old.hi-used, old.hi, (int32)(old.hi-old.lo), new.lo, new.hi-used, new.hi, (int32)newsize);
-	
-	// adjust pointers in the to-be-copied frames
-	adjinfo.old = old;
-	adjinfo.delta = new.hi - old.hi;
-	cb = adjustframe;
-	runtime·gentraceback(~(uintptr)0, ~(uintptr)0, 0, gp, 0, nil, 0x7fffffff, &cb, &adjinfo, 0);
-	
-	// adjust other miscellaneous things that have pointers into stacks.
-	adjustctxt(gp, &adjinfo);
-	adjustdefers(gp, &adjinfo);
-	adjustpanics(gp, &adjinfo);
-	adjustsudogs(gp, &adjinfo);
-	
-	// copy the stack to the new location
-	if(StackPoisonCopy) {
-		p = (byte*)new.lo;
-		ep = (byte*)new.hi;
-		while(p < ep)
-			*p++ = 0xfb;
-	}
-	runtime·memmove((byte*)new.hi - used, (byte*)old.hi - used, used);
-
-	oldstatus = runtime·casgcopystack(gp); // cas from Gwaiting or Grunnable to Gcopystack, return old status
-
-	// Swap out old stack for new one
-	gp->stack = new;
-	gp->stackguard0 = new.lo + StackGuard; // NOTE: might clobber a preempt request
-	gp->sched.sp = new.hi - used;
-
-	runtime·casgstatus(gp, Gcopystack, oldstatus); // oldstatus is Gwaiting or Grunnable
-
-	// free old stack
-	if(StackPoisonCopy) {
-		p = (byte*)old.lo;
-		ep = (byte*)old.hi;
-		while(p < ep)
-			*p++ = 0xfc;
-	}
-	if(newsize > old.hi-old.lo) {
-		// growing, free stack immediately
-		runtime·stackfree(old);
-	} else {
-		// shrinking, queue up free operation.  We can't actually free the stack
-		// just yet because we might run into the following situation:
-		// 1) GC starts, scans a SudoG but does not yet mark the SudoG.elem pointer
-		// 2) The stack that pointer points to is shrunk
-		// 3) The old stack is freed
-		// 4) The containing span is marked free
-		// 5) GC attempts to mark the SudoG.elem pointer.  The marking fails because
-		//    the pointer looks like a pointer into a free span.
-		// By not freeing, we prevent step #4 until GC is done.
-		runtime·lock(&runtime·stackpoolmu);
-		*(Stack*)old.lo = stackfreequeue;
-		stackfreequeue = old;
-		runtime·unlock(&runtime·stackpoolmu);
-	}
-}
-
-// round x up to a power of 2.
-int32
-runtime·round2(int32 x)
-{
-	int32 s;
-
-	s = 0;
-	while((1 << s) < x)
-		s++;
-	return 1 << s;
-}
-
-// Called from runtime·morestack when more stack is needed.
-// Allocate larger stack and relocate to new stack.
-// Stack growth is multiplicative, for constant amortized cost.
-//
-// g->atomicstatus will be Grunning or Gscanrunning upon entry. 
-// If the GC is trying to stop this g then it will set preemptscan to true.
-void
-runtime·newstack(void)
-{
-	int32 oldsize, newsize;
-	uintptr sp;
-	G *gp;
-	Gobuf morebuf;
-
-	if(g->m->morebuf.g->stackguard0 == (uintptr)StackFork)
-		runtime·throw("stack growth after fork");
-	if(g->m->morebuf.g != g->m->curg) {
-		runtime·printf("runtime: newstack called from g=%p\n"
-			"\tm=%p m->curg=%p m->g0=%p m->gsignal=%p\n",
-			g->m->morebuf.g, g->m, g->m->curg, g->m->g0, g->m->gsignal);
-		morebuf = g->m->morebuf;
-		runtime·traceback(morebuf.pc, morebuf.sp, morebuf.lr, morebuf.g);
-		runtime·throw("runtime: wrong goroutine in newstack");
-	}
-	if(g->m->curg->throwsplit)
-		runtime·throw("runtime: stack split at bad time");
-
-	// The goroutine must be executing in order to call newstack,
-	// so it must be Grunning or Gscanrunning.
-
-	gp = g->m->curg;
-	morebuf = g->m->morebuf;
-	g->m->morebuf.pc = (uintptr)nil;
-	g->m->morebuf.lr = (uintptr)nil;
-	g->m->morebuf.sp = (uintptr)nil;
-	g->m->morebuf.g = (G*)nil;
-
-	runtime·casgstatus(gp, Grunning, Gwaiting);
-	gp->waitreason = runtime·gostringnocopy((byte*)"stack growth");
-
-	runtime·rewindmorestack(&gp->sched);
-
-	if(gp->stack.lo == 0)
-		runtime·throw("missing stack in newstack");
-	sp = gp->sched.sp;
-	if(thechar == '6' || thechar == '8') {
-		// The call to morestack cost a word.
-		sp -= sizeof(uintreg);
-	}
-	if(StackDebug >= 1 || sp < gp->stack.lo) {
-		runtime·printf("runtime: newstack sp=%p stack=[%p, %p]\n"
-			"\tmorebuf={pc:%p sp:%p lr:%p}\n"
-			"\tsched={pc:%p sp:%p lr:%p ctxt:%p}\n",
-			sp, gp->stack.lo, gp->stack.hi,
-			g->m->morebuf.pc, g->m->morebuf.sp, g->m->morebuf.lr,
-			gp->sched.pc, gp->sched.sp, gp->sched.lr, gp->sched.ctxt);
-	}
-	if(sp < gp->stack.lo) {
-		runtime·printf("runtime: gp=%p, gp->status=%d\n ", (void*)gp, runtime·readgstatus(gp));
-		runtime·printf("runtime: split stack overflow: %p < %p\n", sp, gp->stack.lo);
-		runtime·throw("runtime: split stack overflow");
-	}
-
-	if(gp->stackguard0 == (uintptr)StackPreempt) {
-		if(gp == g->m->g0)
-			runtime·throw("runtime: preempt g0");
-		if(g->m->p == nil && g->m->locks == 0)
-			runtime·throw("runtime: g is running but p is not");
-		if(gp->preemptscan) {
-			runtime·gcphasework(gp);
-			runtime·casgstatus(gp, Gwaiting, Grunning);
-			gp->stackguard0 = gp->stack.lo + StackGuard;
-			gp->preempt = false; 
-			gp->preemptscan = false;        // Tells the GC premption was successful.
-			runtime·gogo(&gp->sched);	// never return 
-		}
-
-		// Be conservative about where we preempt.
-		// We are interested in preempting user Go code, not runtime code.
-		if(g->m->locks || g->m->mallocing || g->m->gcing || g->m->p->status != Prunning) {
-			// Let the goroutine keep running for now.
-			// gp->preempt is set, so it will be preempted next time.
-			gp->stackguard0 = gp->stack.lo + StackGuard;
-			runtime·casgstatus(gp, Gwaiting, Grunning);
-			runtime·gogo(&gp->sched);	// never return
-		}
-		// Act like goroutine called runtime.Gosched.
-		runtime·casgstatus(gp, Gwaiting, Grunning);
-		runtime·gosched_m(gp);	// never return
-	}
-
-	// Allocate a bigger segment and move the stack.
-	oldsize = gp->stack.hi - gp->stack.lo;
-	newsize = oldsize * 2;
-	if(newsize > runtime·maxstacksize) {
-		runtime·printf("runtime: goroutine stack exceeds %D-byte limit\n", (uint64)runtime·maxstacksize);
-		runtime·throw("stack overflow");
-	}
-
-	// Note that the concurrent GC might be scanning the stack as we try to replace it.
-	// copystack takes care of the appropriate coordination with the stack scanner.
-	copystack(gp, newsize);
-	if(StackDebug >= 1)
-		runtime·printf("stack grow done\n");
-	runtime·casgstatus(gp, Gwaiting, Grunning);
-	runtime·gogo(&gp->sched);
-}
-
-#pragma textflag NOSPLIT
-void
-runtime·nilfunc(void)
-{
-	*(byte*)0 = 0;
-}
-
-// adjust Gobuf as if it executed a call to fn
-// and then did an immediate gosave.
-void
-runtime·gostartcallfn(Gobuf *gobuf, FuncVal *fv)
-{
-	void *fn;
-
-	if(fv != nil)
-		fn = fv->fn;
-	else
-		fn = runtime·nilfunc;
-	runtime·gostartcall(gobuf, fn, fv);
-}
-
-// Maybe shrink the stack being used by gp.
-// Called at garbage collection time.
-void
-runtime·shrinkstack(G *gp)
-{
-	uintptr used, oldsize, newsize;
-
-	if(runtime·readgstatus(gp) == Gdead) {
-		if(gp->stack.lo != 0) {
-			// Free whole stack - it will get reallocated
-			// if G is used again.
-			runtime·stackfree(gp->stack);
-			gp->stack.lo = 0;
-			gp->stack.hi = 0;
-		}
-		return;
-	}
-	if(gp->stack.lo == 0)
-		runtime·throw("missing stack in shrinkstack");
-
-	oldsize = gp->stack.hi - gp->stack.lo;
-	newsize = oldsize / 2;
-	if(newsize < FixedStack)
-		return; // don't shrink below the minimum-sized stack
-	used = gp->stack.hi - gp->sched.sp;
-	if(used >= oldsize / 4)
-		return; // still using at least 1/4 of the segment.
-
-	// We can't copy the stack if we're in a syscall.
-	// The syscall might have pointers into the stack.
-	if(gp->syscallsp != 0)
-		return;
-
-#ifdef GOOS_windows
-	if(gp->m != nil && gp->m->libcallsp != 0)
-		return;
-#endif
-	if(StackDebug > 0)
-		runtime·printf("shrinking stack %D->%D\n", (uint64)oldsize, (uint64)newsize);
-	copystack(gp, newsize);
-}
-
-// Do any delayed stack freeing that was queued up during GC.
-void
-runtime·shrinkfinish(void)
-{
-	Stack s, t;
-
-	runtime·lock(&runtime·stackpoolmu);
-	s = stackfreequeue;
-	stackfreequeue = (Stack){0,0};
-	runtime·unlock(&runtime·stackpoolmu);
-	while(s.lo != 0) {
-		t = *(Stack*)s.lo;
-		runtime·stackfree(s);
-		s = t;
-	}
-}
-
-static void badc(void);
-
-#pragma textflag NOSPLIT
-void
-runtime·morestackc(void)
-{
-	void (*fn)(void);
-	
-	fn = badc;
-	runtime·onM(&fn);
-}
-
-static void
-badc(void)
-{
-	runtime·throw("attempt to execute C code on Go stack");
-}
diff --git a/src/runtime/stack.go b/src/runtime/stack.go
deleted file mode 100644
index f1b7d32..0000000
--- a/src/runtime/stack.go
+++ /dev/null
@@ -1,13 +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.
-
-package runtime
-
-const (
-	// Goroutine preemption request.
-	// Stored into g->stackguard0 to cause split stack check failure.
-	// Must be greater than any real sp.
-	// 0xfffffade in hex.
-	stackPreempt = ^uintptr(1313)
-)
diff --git a/src/runtime/stack.h b/src/runtime/stack.h
deleted file mode 100644
index f97dc4e..0000000
--- a/src/runtime/stack.h
+++ /dev/null
@@ -1,118 +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.
-
-/*
-Stack layout parameters.
-Included both by runtime (compiled via 6c) and linkers (compiled via gcc).
-
-The per-goroutine g->stackguard is set to point StackGuard bytes
-above the bottom of the stack.  Each function compares its stack
-pointer against g->stackguard to check for overflow.  To cut one
-instruction from the check sequence for functions with tiny frames,
-the stack is allowed to protrude StackSmall bytes below the stack
-guard.  Functions with large frames don't bother with the check and
-always call morestack.  The sequences are (for amd64, others are
-similar):
- 
-	guard = g->stackguard
-	frame = function's stack frame size
-	argsize = size of function arguments (call + return)
-
-	stack frame size <= StackSmall:
-		CMPQ guard, SP
-		JHI 3(PC)
-		MOVQ m->morearg, $(argsize << 32)
-		CALL morestack(SB)
-
-	stack frame size > StackSmall but < StackBig
-		LEAQ (frame-StackSmall)(SP), R0
-		CMPQ guard, R0
-		JHI 3(PC)
-		MOVQ m->morearg, $(argsize << 32)
-		CALL morestack(SB)
-
-	stack frame size >= StackBig:
-		MOVQ m->morearg, $((argsize << 32) | frame)
-		CALL morestack(SB)
-
-The bottom StackGuard - StackSmall bytes are important: there has
-to be enough room to execute functions that refuse to check for
-stack overflow, either because they need to be adjacent to the
-actual caller's frame (deferproc) or because they handle the imminent
-stack overflow (morestack).
-
-For example, deferproc might call malloc, which does one of the
-above checks (without allocating a full frame), which might trigger
-a call to morestack.  This sequence needs to fit in the bottom
-section of the stack.  On amd64, morestack's frame is 40 bytes, and
-deferproc's frame is 56 bytes.  That fits well within the
-StackGuard - StackSmall bytes at the bottom.  
-The linkers explore all possible call traces involving non-splitting
-functions to make sure that this limit cannot be violated.
- */
-
-enum {
-	// StackSystem is a number of additional bytes to add
-	// to each stack below the usual guard area for OS-specific
-	// purposes like signal handling. Used on Windows and on
-	// Plan 9 because they do not use a separate stack.
-#ifdef GOOS_windows
-	StackSystem = 512 * sizeof(uintptr),
-#else
-#ifdef GOOS_plan9
-	// The size of the note handler frame varies among architectures,
-	// but 512 bytes should be enough for every implementation.
-	StackSystem = 512,
-#else
-	StackSystem = 0,
-#endif	// Plan 9
-#endif	// Windows
-
-	// The minimum size of stack used by Go code
-	StackMin = 2048,
-
-	// The minimum stack size to allocate.
-	// The hackery here rounds FixedStack0 up to a power of 2.
-	FixedStack0 = StackMin + StackSystem,
-	FixedStack1 = FixedStack0 - 1,
-	FixedStack2 = FixedStack1 | (FixedStack1 >> 1),
-	FixedStack3 = FixedStack2 | (FixedStack2 >> 2),
-	FixedStack4 = FixedStack3 | (FixedStack3 >> 4),
-	FixedStack5 = FixedStack4 | (FixedStack4 >> 8),
-	FixedStack6 = FixedStack5 | (FixedStack5 >> 16),
-	FixedStack = FixedStack6 + 1,
-
-	// Functions that need frames bigger than this use an extra
-	// instruction to do the stack split check, to avoid overflow
-	// in case SP - framesize wraps below zero.
-	// This value can be no bigger than the size of the unmapped
-	// space at zero.
-	StackBig = 4096,
-
-	// The stack guard is a pointer this many bytes above the
-	// bottom of the stack.
-	StackGuard = 512 + StackSystem,
-
-	// After a stack split check the SP is allowed to be this
-	// many bytes below the stack guard.  This saves an instruction
-	// in the checking sequence for tiny frames.
-	StackSmall = 128,
-
-	// The maximum number of bytes that a chain of NOSPLIT
-	// functions can use.
-	StackLimit = StackGuard - StackSystem - StackSmall,
-};
-
-// Goroutine preemption request.
-// Stored into g->stackguard0 to cause split stack check failure.
-// Must be greater than any real sp.
-// 0xfffffade in hex.
-#define StackPreempt ((uint64)-1314)
-/*c2go
-enum
-{
-	StackPreempt = -1314,
-};
-*/
-#define StackFork ((uint64)-1234)
diff --git a/src/runtime/stack1.go b/src/runtime/stack1.go
new file mode 100644
index 0000000..efcb5f2
--- /dev/null
+++ b/src/runtime/stack1.go
@@ -0,0 +1,917 @@
+// 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"
+
+const (
+	// stackDebug == 0: no logging
+	//            == 1: logging of per-stack operations
+	//            == 2: logging of per-frame operations
+	//            == 3: logging of per-word updates
+	//            == 4: logging of per-word reads
+	stackDebug       = 0
+	stackFromSystem  = 0 // allocate stacks from system memory instead of the heap
+	stackFaultOnFree = 0 // old stacks are mapped noaccess to detect use after free
+	stackPoisonCopy  = 0 // fill stack that should not be accessed with garbage, to detect bad dereferences during copy
+
+	stackCache = 1
+)
+
+const (
+	uintptrMask = 1<<(8*ptrSize) - 1
+	poisonStack = uintptrMask & 0x6868686868686868
+
+	// Goroutine preemption request.
+	// Stored into g->stackguard0 to cause split stack check failure.
+	// Must be greater than any real sp.
+	// 0xfffffade in hex.
+	stackPreempt = uintptrMask & -1314
+
+	// Thread is forking.
+	// Stored into g->stackguard0 to cause split stack check failure.
+	// Must be greater than any real sp.
+	stackFork = uintptrMask & -1234
+)
+
+// Global pool of spans that have free stacks.
+// Stacks are assigned an order according to size.
+//     order = log_2(size/FixedStack)
+// There is a free list for each order.
+// TODO: one lock per order?
+var stackpool [_NumStackOrders]mspan
+var stackpoolmu mutex
+
+// List of stack spans to be freed at the end of GC. Protected by
+// stackpoolmu.
+var stackFreeQueue mspan
+
+// Cached value of haveexperiment("framepointer")
+var framepointer_enabled bool
+
+func stackinit() {
+	if _StackCacheSize&_PageMask != 0 {
+		throw("cache size must be a multiple of page size")
+	}
+	for i := range stackpool {
+		mSpanList_Init(&stackpool[i])
+	}
+	mSpanList_Init(&stackFreeQueue)
+}
+
+// Allocates a stack from the free pool.  Must be called with
+// stackpoolmu held.
+func stackpoolalloc(order uint8) gclinkptr {
+	list := &stackpool[order]
+	s := list.next
+	if s == list {
+		// no free stacks.  Allocate another span worth.
+		s = mHeap_AllocStack(&mheap_, _StackCacheSize>>_PageShift)
+		if s == nil {
+			throw("out of memory")
+		}
+		if s.ref != 0 {
+			throw("bad ref")
+		}
+		if s.freelist.ptr() != nil {
+			throw("bad freelist")
+		}
+		for i := uintptr(0); i < _StackCacheSize; i += _FixedStack << order {
+			x := gclinkptr(uintptr(s.start)<<_PageShift + i)
+			x.ptr().next = s.freelist
+			s.freelist = x
+		}
+		mSpanList_Insert(list, s)
+	}
+	x := s.freelist
+	if x.ptr() == nil {
+		throw("span has no free stacks")
+	}
+	s.freelist = x.ptr().next
+	s.ref++
+	if s.freelist.ptr() == nil {
+		// all stacks in s are allocated.
+		mSpanList_Remove(s)
+	}
+	return x
+}
+
+// Adds stack x to the free pool.  Must be called with stackpoolmu held.
+func stackpoolfree(x gclinkptr, order uint8) {
+	s := mHeap_Lookup(&mheap_, (unsafe.Pointer)(x))
+	if s.state != _MSpanStack {
+		throw("freeing stack not in a stack span")
+	}
+	if s.freelist.ptr() == nil {
+		// s will now have a free stack
+		mSpanList_Insert(&stackpool[order], s)
+	}
+	x.ptr().next = s.freelist
+	s.freelist = x
+	s.ref--
+	if gcphase == _GCoff && s.ref == 0 {
+		// Span is completely free. Return it to the heap
+		// immediately if we're sweeping.
+		//
+		// If GC is active, we delay the free until the end of
+		// GC to avoid the following type of situation:
+		//
+		// 1) GC starts, scans a SudoG but does not yet mark the SudoG.elem pointer
+		// 2) The stack that pointer points to is copied
+		// 3) The old stack is freed
+		// 4) The containing span is marked free
+		// 5) GC attempts to mark the SudoG.elem pointer. The
+		//    marking fails because the pointer looks like a
+		//    pointer into a free span.
+		//
+		// By not freeing, we prevent step #4 until GC is done.
+		mSpanList_Remove(s)
+		s.freelist = 0
+		mHeap_FreeStack(&mheap_, s)
+	}
+}
+
+// stackcacherefill/stackcacherelease implement a global pool of stack segments.
+// The pool is required to prevent unlimited growth of per-thread caches.
+func stackcacherefill(c *mcache, order uint8) {
+	if stackDebug >= 1 {
+		print("stackcacherefill order=", order, "\n")
+	}
+
+	// Grab some stacks from the global cache.
+	// Grab half of the allowed capacity (to prevent thrashing).
+	var list gclinkptr
+	var size uintptr
+	lock(&stackpoolmu)
+	for size < _StackCacheSize/2 {
+		x := stackpoolalloc(order)
+		x.ptr().next = list
+		list = x
+		size += _FixedStack << order
+	}
+	unlock(&stackpoolmu)
+	c.stackcache[order].list = list
+	c.stackcache[order].size = size
+}
+
+func stackcacherelease(c *mcache, order uint8) {
+	if stackDebug >= 1 {
+		print("stackcacherelease order=", order, "\n")
+	}
+	x := c.stackcache[order].list
+	size := c.stackcache[order].size
+	lock(&stackpoolmu)
+	for size > _StackCacheSize/2 {
+		y := x.ptr().next
+		stackpoolfree(x, order)
+		x = y
+		size -= _FixedStack << order
+	}
+	unlock(&stackpoolmu)
+	c.stackcache[order].list = x
+	c.stackcache[order].size = size
+}
+
+func stackcache_clear(c *mcache) {
+	if stackDebug >= 1 {
+		print("stackcache clear\n")
+	}
+	lock(&stackpoolmu)
+	for order := uint8(0); order < _NumStackOrders; order++ {
+		x := c.stackcache[order].list
+		for x.ptr() != nil {
+			y := x.ptr().next
+			stackpoolfree(x, order)
+			x = y
+		}
+		c.stackcache[order].list = 0
+		c.stackcache[order].size = 0
+	}
+	unlock(&stackpoolmu)
+}
+
+func stackalloc(n uint32) (stack, []stkbar) {
+	// Stackalloc must be called on scheduler stack, so that we
+	// never try to grow the stack during the code that stackalloc runs.
+	// Doing so would cause a deadlock (issue 1547).
+	thisg := getg()
+	if thisg != thisg.m.g0 {
+		throw("stackalloc not on scheduler stack")
+	}
+	if n&(n-1) != 0 {
+		throw("stack size not a power of 2")
+	}
+	if stackDebug >= 1 {
+		print("stackalloc ", n, "\n")
+	}
+
+	// Compute the size of stack barrier array.
+	maxstkbar := gcMaxStackBarriers(int(n))
+	nstkbar := unsafe.Sizeof(stkbar{}) * uintptr(maxstkbar)
+
+	if debug.efence != 0 || stackFromSystem != 0 {
+		v := sysAlloc(round(uintptr(n), _PageSize), &memstats.stacks_sys)
+		if v == nil {
+			throw("out of memory (stackalloc)")
+		}
+		top := uintptr(n) - nstkbar
+		stkbarSlice := slice{add(v, top), 0, maxstkbar}
+		return stack{uintptr(v), uintptr(v) + top}, *(*[]stkbar)(unsafe.Pointer(&stkbarSlice))
+	}
+
+	// Small stacks are allocated with a fixed-size free-list allocator.
+	// If we need a stack of a bigger size, we fall back on allocating
+	// a dedicated span.
+	var v unsafe.Pointer
+	if stackCache != 0 && n < _FixedStack<<_NumStackOrders && n < _StackCacheSize {
+		order := uint8(0)
+		n2 := n
+		for n2 > _FixedStack {
+			order++
+			n2 >>= 1
+		}
+		var x gclinkptr
+		c := thisg.m.mcache
+		if c == nil || thisg.m.preemptoff != "" || thisg.m.helpgc != 0 {
+			// c == nil can happen in the guts of exitsyscall or
+			// procresize. Just get a stack from the global pool.
+			// Also don't touch stackcache during gc
+			// as it's flushed concurrently.
+			lock(&stackpoolmu)
+			x = stackpoolalloc(order)
+			unlock(&stackpoolmu)
+		} else {
+			x = c.stackcache[order].list
+			if x.ptr() == nil {
+				stackcacherefill(c, order)
+				x = c.stackcache[order].list
+			}
+			c.stackcache[order].list = x.ptr().next
+			c.stackcache[order].size -= uintptr(n)
+		}
+		v = (unsafe.Pointer)(x)
+	} else {
+		s := mHeap_AllocStack(&mheap_, round(uintptr(n), _PageSize)>>_PageShift)
+		if s == nil {
+			throw("out of memory")
+		}
+		v = (unsafe.Pointer)(s.start << _PageShift)
+	}
+
+	if raceenabled {
+		racemalloc(v, uintptr(n))
+	}
+	if stackDebug >= 1 {
+		print("  allocated ", v, "\n")
+	}
+	top := uintptr(n) - nstkbar
+	stkbarSlice := slice{add(v, top), 0, maxstkbar}
+	return stack{uintptr(v), uintptr(v) + top}, *(*[]stkbar)(unsafe.Pointer(&stkbarSlice))
+}
+
+func stackfree(stk stack, n uintptr) {
+	gp := getg()
+	v := (unsafe.Pointer)(stk.lo)
+	if n&(n-1) != 0 {
+		throw("stack not a power of 2")
+	}
+	if stk.lo+n < stk.hi {
+		throw("bad stack size")
+	}
+	if stackDebug >= 1 {
+		println("stackfree", v, n)
+		memclr(v, n) // for testing, clobber stack data
+	}
+	if debug.efence != 0 || stackFromSystem != 0 {
+		if debug.efence != 0 || stackFaultOnFree != 0 {
+			sysFault(v, n)
+		} else {
+			sysFree(v, n, &memstats.stacks_sys)
+		}
+		return
+	}
+	if stackCache != 0 && n < _FixedStack<<_NumStackOrders && n < _StackCacheSize {
+		order := uint8(0)
+		n2 := n
+		for n2 > _FixedStack {
+			order++
+			n2 >>= 1
+		}
+		x := gclinkptr(v)
+		c := gp.m.mcache
+		if c == nil || gp.m.preemptoff != "" || gp.m.helpgc != 0 {
+			lock(&stackpoolmu)
+			stackpoolfree(x, order)
+			unlock(&stackpoolmu)
+		} else {
+			if c.stackcache[order].size >= _StackCacheSize {
+				stackcacherelease(c, order)
+			}
+			x.ptr().next = c.stackcache[order].list
+			c.stackcache[order].list = x
+			c.stackcache[order].size += n
+		}
+	} else {
+		s := mHeap_Lookup(&mheap_, v)
+		if s.state != _MSpanStack {
+			println(hex(s.start<<_PageShift), v)
+			throw("bad span state")
+		}
+		if gcphase == _GCoff {
+			// Free the stack immediately if we're
+			// sweeping.
+			mHeap_FreeStack(&mheap_, s)
+		} else {
+			// Otherwise, add it to a list of stack spans
+			// to be freed at the end of GC.
+			//
+			// TODO(austin): Make it possible to re-use
+			// these spans as stacks, like we do for small
+			// stack spans. (See issue #11466.)
+			lock(&stackpoolmu)
+			mSpanList_Insert(&stackFreeQueue, s)
+			unlock(&stackpoolmu)
+		}
+	}
+}
+
+var maxstacksize uintptr = 1 << 20 // enough until runtime.main sets it for real
+
+var ptrnames = []string{
+	0: "scalar",
+	1: "ptr",
+}
+
+// Stack frame layout
+//
+// (x86)
+// +------------------+
+// | args from caller |
+// +------------------+ <- frame->argp
+// |  return address  |
+// +------------------+
+// |  caller's BP (*) | (*) if framepointer_enabled && varp < sp
+// +------------------+ <- frame->varp
+// |     locals       |
+// +------------------+
+// |  args to callee  |
+// +------------------+ <- frame->sp
+//
+// (arm)
+// +------------------+
+// | args from caller |
+// +------------------+ <- frame->argp
+// | caller's retaddr |
+// +------------------+ <- frame->varp
+// |     locals       |
+// +------------------+
+// |  args to callee  |
+// +------------------+
+// |  return address  |
+// +------------------+ <- frame->sp
+
+type adjustinfo struct {
+	old   stack
+	delta uintptr // ptr distance from old to new stack (newbase - oldbase)
+}
+
+// Adjustpointer checks whether *vpp is in the old stack described by adjinfo.
+// If so, it rewrites *vpp to point into the new stack.
+func adjustpointer(adjinfo *adjustinfo, vpp unsafe.Pointer) {
+	pp := (*unsafe.Pointer)(vpp)
+	p := *pp
+	if stackDebug >= 4 {
+		print("        ", pp, ":", p, "\n")
+	}
+	if adjinfo.old.lo <= uintptr(p) && uintptr(p) < adjinfo.old.hi {
+		*pp = add(p, adjinfo.delta)
+		if stackDebug >= 3 {
+			print("        adjust ptr ", pp, ":", p, " -> ", *pp, "\n")
+		}
+	}
+}
+
+// Information from the compiler about the layout of stack frames.
+type bitvector struct {
+	n        int32 // # of bits
+	bytedata *uint8
+}
+
+type gobitvector struct {
+	n        uintptr
+	bytedata []uint8
+}
+
+func gobv(bv bitvector) gobitvector {
+	return gobitvector{
+		uintptr(bv.n),
+		(*[1 << 30]byte)(unsafe.Pointer(bv.bytedata))[:(bv.n+7)/8],
+	}
+}
+
+func ptrbit(bv *gobitvector, i uintptr) uint8 {
+	return (bv.bytedata[i/8] >> (i % 8)) & 1
+}
+
+// bv describes the memory starting at address scanp.
+// Adjust any pointers contained therein.
+func adjustpointers(scanp unsafe.Pointer, cbv *bitvector, adjinfo *adjustinfo, f *_func) {
+	bv := gobv(*cbv)
+	minp := adjinfo.old.lo
+	maxp := adjinfo.old.hi
+	delta := adjinfo.delta
+	num := uintptr(bv.n)
+	for i := uintptr(0); i < num; i++ {
+		if stackDebug >= 4 {
+			print("        ", add(scanp, i*ptrSize), ":", ptrnames[ptrbit(&bv, i)], ":", hex(*(*uintptr)(add(scanp, i*ptrSize))), " # ", i, " ", bv.bytedata[i/8], "\n")
+		}
+		if ptrbit(&bv, i) == 1 {
+			pp := (*uintptr)(add(scanp, i*ptrSize))
+			p := *pp
+			if f != nil && 0 < p && p < _PageSize && debug.invalidptr != 0 || p == poisonStack {
+				// Looks like a junk value in a pointer slot.
+				// Live analysis wrong?
+				getg().m.traceback = 2
+				print("runtime: bad pointer in frame ", funcname(f), " at ", pp, ": ", hex(p), "\n")
+				throw("invalid stack pointer")
+			}
+			if minp <= p && p < maxp {
+				if stackDebug >= 3 {
+					print("adjust ptr ", p, " ", funcname(f), "\n")
+				}
+				*pp = p + delta
+			}
+		}
+	}
+}
+
+// Note: the argument/return area is adjusted by the callee.
+func adjustframe(frame *stkframe, arg unsafe.Pointer) bool {
+	adjinfo := (*adjustinfo)(arg)
+	targetpc := frame.continpc
+	if targetpc == 0 {
+		// Frame is dead.
+		return true
+	}
+	f := frame.fn
+	if stackDebug >= 2 {
+		print("    adjusting ", funcname(f), " frame=[", hex(frame.sp), ",", hex(frame.fp), "] pc=", hex(frame.pc), " continpc=", hex(frame.continpc), "\n")
+	}
+	if f.entry == systemstack_switchPC {
+		// A special routine at the bottom of stack of a goroutine that does an systemstack call.
+		// We will allow it to be copied even though we don't
+		// have full GC info for it (because it is written in asm).
+		return true
+	}
+	if targetpc != f.entry {
+		targetpc--
+	}
+	pcdata := pcdatavalue(f, _PCDATA_StackMapIndex, targetpc)
+	if pcdata == -1 {
+		pcdata = 0 // in prologue
+	}
+
+	// Adjust local variables if stack frame has been allocated.
+	size := frame.varp - frame.sp
+	var minsize uintptr
+	switch thechar {
+	case '6', '8':
+		minsize = 0
+	case '7':
+		minsize = spAlign
+	default:
+		minsize = ptrSize
+	}
+	if size > minsize {
+		var bv bitvector
+		stackmap := (*stackmap)(funcdata(f, _FUNCDATA_LocalsPointerMaps))
+		if stackmap == nil || stackmap.n <= 0 {
+			print("runtime: frame ", funcname(f), " untyped locals ", hex(frame.varp-size), "+", hex(size), "\n")
+			throw("missing stackmap")
+		}
+		// Locals bitmap information, scan just the pointers in locals.
+		if pcdata < 0 || pcdata >= stackmap.n {
+			// don't know where we are
+			print("runtime: pcdata is ", pcdata, " and ", stackmap.n, " locals stack map entries for ", funcname(f), " (targetpc=", targetpc, ")\n")
+			throw("bad symbol table")
+		}
+		bv = stackmapdata(stackmap, pcdata)
+		size = uintptr(bv.n) * ptrSize
+		if stackDebug >= 3 {
+			print("      locals ", pcdata, "/", stackmap.n, " ", size/ptrSize, " words ", bv.bytedata, "\n")
+		}
+		adjustpointers(unsafe.Pointer(frame.varp-size), &bv, adjinfo, f)
+	}
+
+	// Adjust saved base pointer if there is one.
+	if thechar == '6' && frame.argp-frame.varp == 2*regSize {
+		if !framepointer_enabled {
+			print("runtime: found space for saved base pointer, but no framepointer experiment\n")
+			print("argp=", hex(frame.argp), " varp=", hex(frame.varp), "\n")
+			throw("bad frame layout")
+		}
+		if stackDebug >= 3 {
+			print("      saved bp\n")
+		}
+		adjustpointer(adjinfo, unsafe.Pointer(frame.varp))
+	}
+
+	// Adjust arguments.
+	if frame.arglen > 0 {
+		var bv bitvector
+		if frame.argmap != nil {
+			bv = *frame.argmap
+		} else {
+			stackmap := (*stackmap)(funcdata(f, _FUNCDATA_ArgsPointerMaps))
+			if stackmap == nil || stackmap.n <= 0 {
+				print("runtime: frame ", funcname(f), " untyped args ", frame.argp, "+", uintptr(frame.arglen), "\n")
+				throw("missing stackmap")
+			}
+			if pcdata < 0 || pcdata >= stackmap.n {
+				// don't know where we are
+				print("runtime: pcdata is ", pcdata, " and ", stackmap.n, " args stack map entries for ", funcname(f), " (targetpc=", targetpc, ")\n")
+				throw("bad symbol table")
+			}
+			bv = stackmapdata(stackmap, pcdata)
+		}
+		if stackDebug >= 3 {
+			print("      args\n")
+		}
+		adjustpointers(unsafe.Pointer(frame.argp), &bv, adjinfo, nil)
+	}
+	return true
+}
+
+func adjustctxt(gp *g, adjinfo *adjustinfo) {
+	adjustpointer(adjinfo, (unsafe.Pointer)(&gp.sched.ctxt))
+}
+
+func adjustdefers(gp *g, adjinfo *adjustinfo) {
+	// Adjust defer argument blocks the same way we adjust active stack frames.
+	tracebackdefers(gp, adjustframe, noescape(unsafe.Pointer(adjinfo)))
+
+	// Adjust pointers in the Defer structs.
+	// Defer structs themselves are never on the stack.
+	for d := gp._defer; d != nil; d = d.link {
+		adjustpointer(adjinfo, (unsafe.Pointer)(&d.fn))
+		adjustpointer(adjinfo, (unsafe.Pointer)(&d.sp))
+		adjustpointer(adjinfo, (unsafe.Pointer)(&d._panic))
+	}
+}
+
+func adjustpanics(gp *g, adjinfo *adjustinfo) {
+	// Panics are on stack and already adjusted.
+	// Update pointer to head of list in G.
+	adjustpointer(adjinfo, (unsafe.Pointer)(&gp._panic))
+}
+
+func adjustsudogs(gp *g, adjinfo *adjustinfo) {
+	// the data elements pointed to by a SudoG structure
+	// might be in the stack.
+	for s := gp.waiting; s != nil; s = s.waitlink {
+		adjustpointer(adjinfo, (unsafe.Pointer)(&s.elem))
+		adjustpointer(adjinfo, (unsafe.Pointer)(&s.selectdone))
+	}
+}
+
+func adjuststkbar(gp *g, adjinfo *adjustinfo) {
+	for i := int(gp.stkbarPos); i < len(gp.stkbar); i++ {
+		adjustpointer(adjinfo, (unsafe.Pointer)(&gp.stkbar[i].savedLRPtr))
+	}
+}
+
+func fillstack(stk stack, b byte) {
+	for p := stk.lo; p < stk.hi; p++ {
+		*(*byte)(unsafe.Pointer(p)) = b
+	}
+}
+
+// Copies gp's stack to a new stack of a different size.
+// Caller must have changed gp status to Gcopystack.
+func copystack(gp *g, newsize uintptr) {
+	if gp.syscallsp != 0 {
+		throw("stack growth not allowed in system call")
+	}
+	old := gp.stack
+	if old.lo == 0 {
+		throw("nil stackbase")
+	}
+	used := old.hi - gp.sched.sp
+
+	// allocate new stack
+	new, newstkbar := stackalloc(uint32(newsize))
+	if stackPoisonCopy != 0 {
+		fillstack(new, 0xfd)
+	}
+	if stackDebug >= 1 {
+		print("copystack gp=", gp, " [", hex(old.lo), " ", hex(old.hi-used), " ", hex(old.hi), "]/", gp.stackAlloc, " -> [", hex(new.lo), " ", hex(new.hi-used), " ", hex(new.hi), "]/", newsize, "\n")
+	}
+
+	// adjust pointers in the to-be-copied frames
+	var adjinfo adjustinfo
+	adjinfo.old = old
+	adjinfo.delta = new.hi - old.hi
+	gentraceback(^uintptr(0), ^uintptr(0), 0, gp, 0, nil, 0x7fffffff, adjustframe, noescape(unsafe.Pointer(&adjinfo)), 0)
+
+	// adjust other miscellaneous things that have pointers into stacks.
+	adjustctxt(gp, &adjinfo)
+	adjustdefers(gp, &adjinfo)
+	adjustpanics(gp, &adjinfo)
+	adjustsudogs(gp, &adjinfo)
+	adjuststkbar(gp, &adjinfo)
+
+	// copy the stack to the new location
+	if stackPoisonCopy != 0 {
+		fillstack(new, 0xfb)
+	}
+	memmove(unsafe.Pointer(new.hi-used), unsafe.Pointer(old.hi-used), used)
+
+	// copy old stack barriers to new stack barrier array
+	newstkbar = newstkbar[:len(gp.stkbar)]
+	copy(newstkbar, gp.stkbar)
+
+	// Swap out old stack for new one
+	gp.stack = new
+	gp.stackguard0 = new.lo + _StackGuard // NOTE: might clobber a preempt request
+	gp.sched.sp = new.hi - used
+	oldsize := gp.stackAlloc
+	gp.stackAlloc = newsize
+	gp.stkbar = newstkbar
+
+	// free old stack
+	if stackPoisonCopy != 0 {
+		fillstack(old, 0xfc)
+	}
+	stackfree(old, oldsize)
+}
+
+// round x up to a power of 2.
+func round2(x int32) int32 {
+	s := uint(0)
+	for 1<<s < x {
+		s++
+	}
+	return 1 << s
+}
+
+// Called from runtime·morestack when more stack is needed.
+// Allocate larger stack and relocate to new stack.
+// Stack growth is multiplicative, for constant amortized cost.
+//
+// g->atomicstatus will be Grunning or Gscanrunning upon entry.
+// If the GC is trying to stop this g then it will set preemptscan to true.
+func newstack() {
+	thisg := getg()
+	// TODO: double check all gp. shouldn't be getg().
+	if thisg.m.morebuf.g.ptr().stackguard0 == stackFork {
+		throw("stack growth after fork")
+	}
+	if thisg.m.morebuf.g.ptr() != thisg.m.curg {
+		print("runtime: newstack called from g=", thisg.m.morebuf.g, "\n"+"\tm=", thisg.m, " m->curg=", thisg.m.curg, " m->g0=", thisg.m.g0, " m->gsignal=", thisg.m.gsignal, "\n")
+		morebuf := thisg.m.morebuf
+		traceback(morebuf.pc, morebuf.sp, morebuf.lr, morebuf.g.ptr())
+		throw("runtime: wrong goroutine in newstack")
+	}
+	if thisg.m.curg.throwsplit {
+		gp := thisg.m.curg
+		// Update syscallsp, syscallpc in case traceback uses them.
+		morebuf := thisg.m.morebuf
+		gp.syscallsp = morebuf.sp
+		gp.syscallpc = morebuf.pc
+		print("runtime: newstack sp=", hex(gp.sched.sp), " stack=[", hex(gp.stack.lo), ", ", hex(gp.stack.hi), "]\n",
+			"\tmorebuf={pc:", hex(morebuf.pc), " sp:", hex(morebuf.sp), " lr:", hex(morebuf.lr), "}\n",
+			"\tsched={pc:", hex(gp.sched.pc), " sp:", hex(gp.sched.sp), " lr:", hex(gp.sched.lr), " ctxt:", gp.sched.ctxt, "}\n")
+
+		traceback(morebuf.pc, morebuf.sp, morebuf.lr, gp)
+		throw("runtime: stack split at bad time")
+	}
+
+	gp := thisg.m.curg
+	morebuf := thisg.m.morebuf
+	thisg.m.morebuf.pc = 0
+	thisg.m.morebuf.lr = 0
+	thisg.m.morebuf.sp = 0
+	thisg.m.morebuf.g = 0
+	rewindmorestack(&gp.sched)
+
+	// NOTE: stackguard0 may change underfoot, if another thread
+	// is about to try to preempt gp. Read it just once and use that same
+	// value now and below.
+	preempt := atomicloaduintptr(&gp.stackguard0) == stackPreempt
+
+	// Be conservative about where we preempt.
+	// We are interested in preempting user Go code, not runtime code.
+	// If we're holding locks, mallocing, or preemption is disabled, don't
+	// preempt.
+	// This check is very early in newstack so that even the status change
+	// from Grunning to Gwaiting and back doesn't happen in this case.
+	// That status change by itself can be viewed as a small preemption,
+	// because the GC might change Gwaiting to Gscanwaiting, and then
+	// this goroutine has to wait for the GC to finish before continuing.
+	// If the GC is in some way dependent on this goroutine (for example,
+	// it needs a lock held by the goroutine), that small preemption turns
+	// into a real deadlock.
+	if preempt {
+		if thisg.m.locks != 0 || thisg.m.mallocing != 0 || thisg.m.preemptoff != "" || thisg.m.p.ptr().status != _Prunning {
+			// Let the goroutine keep running for now.
+			// gp->preempt is set, so it will be preempted next time.
+			gp.stackguard0 = gp.stack.lo + _StackGuard
+			gogo(&gp.sched) // never return
+		}
+	}
+
+	// The goroutine must be executing in order to call newstack,
+	// so it must be Grunning (or Gscanrunning).
+	casgstatus(gp, _Grunning, _Gwaiting)
+	gp.waitreason = "stack growth"
+
+	if gp.stack.lo == 0 {
+		throw("missing stack in newstack")
+	}
+	sp := gp.sched.sp
+	if thechar == '6' || thechar == '8' {
+		// The call to morestack cost a word.
+		sp -= ptrSize
+	}
+	if stackDebug >= 1 || sp < gp.stack.lo {
+		print("runtime: newstack sp=", hex(sp), " stack=[", hex(gp.stack.lo), ", ", hex(gp.stack.hi), "]\n",
+			"\tmorebuf={pc:", hex(morebuf.pc), " sp:", hex(morebuf.sp), " lr:", hex(morebuf.lr), "}\n",
+			"\tsched={pc:", hex(gp.sched.pc), " sp:", hex(gp.sched.sp), " lr:", hex(gp.sched.lr), " ctxt:", gp.sched.ctxt, "}\n")
+	}
+	if sp < gp.stack.lo {
+		print("runtime: gp=", gp, ", gp->status=", hex(readgstatus(gp)), "\n ")
+		print("runtime: split stack overflow: ", hex(sp), " < ", hex(gp.stack.lo), "\n")
+		throw("runtime: split stack overflow")
+	}
+
+	if gp.sched.ctxt != nil {
+		// morestack wrote sched.ctxt on its way in here,
+		// without a write barrier. Run the write barrier now.
+		// It is not possible to be preempted between then
+		// and now, so it's okay.
+		writebarrierptr_nostore((*uintptr)(unsafe.Pointer(&gp.sched.ctxt)), uintptr(gp.sched.ctxt))
+	}
+
+	if preempt {
+		if gp == thisg.m.g0 {
+			throw("runtime: preempt g0")
+		}
+		if thisg.m.p == 0 && thisg.m.locks == 0 {
+			throw("runtime: g is running but p is not")
+		}
+		if gp.preemptscan {
+			for !castogscanstatus(gp, _Gwaiting, _Gscanwaiting) {
+				// Likely to be racing with the GC as
+				// it sees a _Gwaiting and does the
+				// stack scan. If so, gcworkdone will
+				// be set and gcphasework will simply
+				// return.
+			}
+			if !gp.gcscandone {
+				scanstack(gp)
+				gp.gcscandone = true
+			}
+			gp.preemptscan = false
+			gp.preempt = false
+			casfrom_Gscanstatus(gp, _Gscanwaiting, _Gwaiting)
+			casgstatus(gp, _Gwaiting, _Grunning)
+			gp.stackguard0 = gp.stack.lo + _StackGuard
+			gogo(&gp.sched) // never return
+		}
+
+		// Act like goroutine called runtime.Gosched.
+		casgstatus(gp, _Gwaiting, _Grunning)
+		gopreempt_m(gp) // never return
+	}
+
+	// Allocate a bigger segment and move the stack.
+	oldsize := int(gp.stackAlloc)
+	newsize := oldsize * 2
+	if uintptr(newsize) > maxstacksize {
+		print("runtime: goroutine stack exceeds ", maxstacksize, "-byte limit\n")
+		throw("stack overflow")
+	}
+
+	casgstatus(gp, _Gwaiting, _Gcopystack)
+
+	// The concurrent GC will not scan the stack while we are doing the copy since
+	// the gp is in a Gcopystack status.
+	copystack(gp, uintptr(newsize))
+	if stackDebug >= 1 {
+		print("stack grow done\n")
+	}
+	casgstatus(gp, _Gcopystack, _Grunning)
+	gogo(&gp.sched)
+}
+
+//go:nosplit
+func nilfunc() {
+	*(*uint8)(nil) = 0
+}
+
+// adjust Gobuf as if it executed a call to fn
+// and then did an immediate gosave.
+func gostartcallfn(gobuf *gobuf, fv *funcval) {
+	var fn unsafe.Pointer
+	if fv != nil {
+		fn = (unsafe.Pointer)(fv.fn)
+	} else {
+		fn = unsafe.Pointer(funcPC(nilfunc))
+	}
+	gostartcall(gobuf, fn, (unsafe.Pointer)(fv))
+}
+
+// Maybe shrink the stack being used by gp.
+// Called at garbage collection time.
+func shrinkstack(gp *g) {
+	if readgstatus(gp) == _Gdead {
+		if gp.stack.lo != 0 {
+			// Free whole stack - it will get reallocated
+			// if G is used again.
+			stackfree(gp.stack, gp.stackAlloc)
+			gp.stack.lo = 0
+			gp.stack.hi = 0
+			gp.stkbar = nil
+			gp.stkbarPos = 0
+		}
+		return
+	}
+	if gp.stack.lo == 0 {
+		throw("missing stack in shrinkstack")
+	}
+
+	if debug.gcshrinkstackoff > 0 {
+		return
+	}
+
+	oldsize := gp.stackAlloc
+	newsize := oldsize / 2
+	// Don't shrink the allocation below the minimum-sized stack
+	// allocation.
+	if newsize < _FixedStack {
+		return
+	}
+	// Compute how much of the stack is currently in use and only
+	// shrink the stack if gp is using less than a quarter of its
+	// current stack. The currently used stack includes everything
+	// down to the SP plus the stack guard space that ensures
+	// there's room for nosplit functions.
+	avail := gp.stack.hi - gp.stack.lo
+	if used := gp.stack.hi - gp.sched.sp + _StackLimit; used >= avail/4 {
+		return
+	}
+
+	// We can't copy the stack if we're in a syscall.
+	// The syscall might have pointers into the stack.
+	if gp.syscallsp != 0 {
+		return
+	}
+	if goos_windows != 0 && gp.m != nil && gp.m.libcallsp != 0 {
+		return
+	}
+
+	if stackDebug > 0 {
+		print("shrinking stack ", oldsize, "->", newsize, "\n")
+	}
+
+	oldstatus := casgcopystack(gp)
+	copystack(gp, newsize)
+	casgstatus(gp, _Gcopystack, oldstatus)
+}
+
+// freeStackSpans frees unused stack spans at the end of GC.
+func freeStackSpans() {
+	lock(&stackpoolmu)
+
+	// Scan stack pools for empty stack spans.
+	for order := range stackpool {
+		list := &stackpool[order]
+		for s := list.next; s != list; {
+			next := s.next
+			if s.ref == 0 {
+				mSpanList_Remove(s)
+				s.freelist = 0
+				mHeap_FreeStack(&mheap_, s)
+			}
+			s = next
+		}
+	}
+
+	// Free queued stack spans.
+	for stackFreeQueue.next != &stackFreeQueue {
+		s := stackFreeQueue.next
+		mSpanList_Remove(s)
+		mHeap_FreeStack(&mheap_, s)
+	}
+
+	unlock(&stackpoolmu)
+}
+
+//go:nosplit
+func morestackc() {
+	systemstack(func() {
+		throw("attempt to execute C code on Go stack")
+	})
+}
diff --git a/src/runtime/stack2.go b/src/runtime/stack2.go
new file mode 100644
index 0000000..5ec8d8d
--- /dev/null
+++ b/src/runtime/stack2.go
@@ -0,0 +1,106 @@
+// 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
+
+/*
+Stack layout parameters.
+Included both by runtime (compiled via 6c) and linkers (compiled via gcc).
+
+The per-goroutine g->stackguard is set to point StackGuard bytes
+above the bottom of the stack.  Each function compares its stack
+pointer against g->stackguard to check for overflow.  To cut one
+instruction from the check sequence for functions with tiny frames,
+the stack is allowed to protrude StackSmall bytes below the stack
+guard.  Functions with large frames don't bother with the check and
+always call morestack.  The sequences are (for amd64, others are
+similar):
+
+	guard = g->stackguard
+	frame = function's stack frame size
+	argsize = size of function arguments (call + return)
+
+	stack frame size <= StackSmall:
+		CMPQ guard, SP
+		JHI 3(PC)
+		MOVQ m->morearg, $(argsize << 32)
+		CALL morestack(SB)
+
+	stack frame size > StackSmall but < StackBig
+		LEAQ (frame-StackSmall)(SP), R0
+		CMPQ guard, R0
+		JHI 3(PC)
+		MOVQ m->morearg, $(argsize << 32)
+		CALL morestack(SB)
+
+	stack frame size >= StackBig:
+		MOVQ m->morearg, $((argsize << 32) | frame)
+		CALL morestack(SB)
+
+The bottom StackGuard - StackSmall bytes are important: there has
+to be enough room to execute functions that refuse to check for
+stack overflow, either because they need to be adjacent to the
+actual caller's frame (deferproc) or because they handle the imminent
+stack overflow (morestack).
+
+For example, deferproc might call malloc, which does one of the
+above checks (without allocating a full frame), which might trigger
+a call to morestack.  This sequence needs to fit in the bottom
+section of the stack.  On amd64, morestack's frame is 40 bytes, and
+deferproc's frame is 56 bytes.  That fits well within the
+StackGuard - StackSmall bytes at the bottom.
+The linkers explore all possible call traces involving non-splitting
+functions to make sure that this limit cannot be violated.
+*/
+
+const (
+	// StackSystem is a number of additional bytes to add
+	// to each stack below the usual guard area for OS-specific
+	// purposes like signal handling. Used on Windows, Plan 9,
+	// and Darwin/ARM because they do not use a separate stack.
+	_StackSystem = goos_windows*512*ptrSize + goos_plan9*512 + goos_darwin*goarch_arm*1024
+
+	// The minimum size of stack used by Go code
+	_StackMin = 2048
+
+	// The minimum stack size to allocate.
+	// The hackery here rounds FixedStack0 up to a power of 2.
+	_FixedStack0 = _StackMin + _StackSystem
+	_FixedStack1 = _FixedStack0 - 1
+	_FixedStack2 = _FixedStack1 | (_FixedStack1 >> 1)
+	_FixedStack3 = _FixedStack2 | (_FixedStack2 >> 2)
+	_FixedStack4 = _FixedStack3 | (_FixedStack3 >> 4)
+	_FixedStack5 = _FixedStack4 | (_FixedStack4 >> 8)
+	_FixedStack6 = _FixedStack5 | (_FixedStack5 >> 16)
+	_FixedStack  = _FixedStack6 + 1
+
+	// Functions that need frames bigger than this use an extra
+	// instruction to do the stack split check, to avoid overflow
+	// in case SP - framesize wraps below zero.
+	// This value can be no bigger than the size of the unmapped
+	// space at zero.
+	_StackBig = 4096
+
+	// The stack guard is a pointer this many bytes above the
+	// bottom of the stack.
+	_StackGuard = 640*stackGuardMultiplier + _StackSystem
+
+	// After a stack split check the SP is allowed to be this
+	// many bytes below the stack guard.  This saves an instruction
+	// in the checking sequence for tiny frames.
+	_StackSmall = 128
+
+	// The maximum number of bytes that a chain of NOSPLIT
+	// functions can use.
+	_StackLimit = _StackGuard - _StackSystem - _StackSmall
+)
+
+// Goroutine preemption request.
+// Stored into g->stackguard0 to cause split stack check failure.
+// Must be greater than any real sp.
+// 0xfffffade in hex.
+const (
+	_StackPreempt = uintptrMask & -1314
+	_StackFork    = uintptrMask & -1234
+)
diff --git a/src/runtime/stack_test.go b/src/runtime/stack_test.go
index 652c72e..fa073f1 100644
--- a/src/runtime/stack_test.go
+++ b/src/runtime/stack_test.go
@@ -60,7 +60,7 @@ func TestStackMem(t *testing.T) {
 	if consumed > estimate {
 		t.Fatalf("Stack mem: want %v, got %v", estimate, consumed)
 	}
-	// Due to broken stack memory accounting (http://golang.org/issue/7468),
+	// Due to broken stack memory accounting (https://golang.org/issue/7468),
 	// StackInuse can decrease during function execution, so we cast the values to int64.
 	inuse := int64(s1.StackInuse) - int64(s0.StackInuse)
 	t.Logf("Inuse %vMB for stack mem", inuse>>20)
@@ -309,6 +309,40 @@ func TestPanicUseStack(t *testing.T) {
 	panic(1)
 }
 
+func TestPanicFar(t *testing.T) {
+	var xtree *xtreeNode
+	pc := make([]uintptr, 10000)
+	defer func() {
+		// At this point we created a large stack and unwound
+		// it via recovery. Force a stack walk, which will
+		// check the consistency of stack barriers.
+		Callers(0, pc)
+	}()
+	defer func() {
+		recover()
+	}()
+	useStackAndCall(100, func() {
+		// Kick off the GC and make it do something nontrivial
+		// to keep stack barriers installed for a while.
+		xtree = makeTree(18)
+		// Give the GC time to install stack barriers.
+		time.Sleep(time.Millisecond)
+		panic(1)
+	})
+	_ = xtree
+}
+
+type xtreeNode struct {
+	l, r *xtreeNode
+}
+
+func makeTree(d int) *xtreeNode {
+	if d == 0 {
+		return new(xtreeNode)
+	}
+	return &xtreeNode{makeTree(d - 1), makeTree(d - 1)}
+}
+
 // use about n KB of stack and call f
 func useStackAndCall(n int, f func()) {
 	if n == 0 {
@@ -395,3 +429,21 @@ func TestStackPanic(t *testing.T) {
 	useStack(32)
 	panic("test panic")
 }
+
+func BenchmarkStackCopy(b *testing.B) {
+	c := make(chan bool)
+	for i := 0; i < b.N; i++ {
+		go func() {
+			count(1000000)
+			c <- true
+		}()
+		<-c
+	}
+}
+
+func count(n int) int {
+	if n == 0 {
+		return 0
+	}
+	return 1 + count(n-1)
+}
diff --git a/src/runtime/string.c b/src/runtime/string.c
deleted file mode 100644
index ed5debc..0000000
--- a/src/runtime/string.c
+++ /dev/null
@@ -1,226 +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 "runtime.h"
-#include "arch_GOARCH.h"
-#include "malloc.h"
-#include "race.h"
-#include "textflag.h"
-
-String	runtime·emptystring;
-
-#pragma textflag NOSPLIT
-intgo
-runtime·findnull(byte *s)
-{
-	intgo l;
-
-	if(s == nil)
-		return 0;
-	for(l=0; s[l]!=0; l++)
-		;
-	return l;
-}
-
-intgo
-runtime·findnullw(uint16 *s)
-{
-	intgo l;
-
-	if(s == nil)
-		return 0;
-	for(l=0; s[l]!=0; l++)
-		;
-	return l;
-}
-
-uintptr runtime·maxstring = 256; // a hint for print
-
-#pragma textflag NOSPLIT
-String
-runtime·gostringnocopy(byte *str)
-{
-	String s;
-	uintptr ms;
-	
-	s.str = str;
-	s.len = runtime·findnull(str);
-	while(true) {
-		ms = runtime·maxstring;
-		if(s.len <= ms || runtime·casp((void**)&runtime·maxstring, (void*)ms, (void*)s.len))
-			return s;
-	}
-}
-
-// TODO: move this elsewhere
-enum
-{
-	Bit1	= 7,
-	Bitx	= 6,
-	Bit2	= 5,
-	Bit3	= 4,
-	Bit4	= 3,
-	Bit5	= 2,
-
-	Tx	= ((1<<(Bitx+1))-1) ^ 0xFF,	/* 1000 0000 */
-	T2	= ((1<<(Bit2+1))-1) ^ 0xFF,	/* 1100 0000 */
-	T3	= ((1<<(Bit3+1))-1) ^ 0xFF,	/* 1110 0000 */
-	T4	= ((1<<(Bit4+1))-1) ^ 0xFF,	/* 1111 0000 */
-
-	Rune1	= (1<<(Bit1+0*Bitx))-1,		/* 0000 0000 0111 1111 */
-	Rune2	= (1<<(Bit2+1*Bitx))-1,		/* 0000 0111 1111 1111 */
-	Rune3	= (1<<(Bit3+2*Bitx))-1,		/* 1111 1111 1111 1111 */
-
-	Maskx	= (1<<Bitx)-1,			/* 0011 1111 */
-
-	Runeerror	= 0xFFFD,
-
-	SurrogateMin = 0xD800,
-	SurrogateMax = 0xDFFF,
-
-	Runemax	= 0x10FFFF,	/* maximum rune value */
-};
-
-static int32
-runetochar(byte *str, int32 rune)  /* note: in original, arg2 was pointer */
-{
-	/* Runes are signed, so convert to unsigned for range check. */
-	uint32 c;
-
-	/*
-	 * one character sequence
-	 *	00000-0007F => 00-7F
-	 */
-	c = rune;
-	if(c <= Rune1) {
-		str[0] = c;
-		return 1;
-	}
-
-	/*
-	 * two character sequence
-	 *	0080-07FF => T2 Tx
-	 */
-	if(c <= Rune2) {
-		str[0] = T2 | (c >> 1*Bitx);
-		str[1] = Tx | (c & Maskx);
-		return 2;
-	}
-
-	/*
-	 * If the Rune is out of range or a surrogate half, convert it to the error rune.
-	 * Do this test here because the error rune encodes to three bytes.
-	 * Doing it earlier would duplicate work, since an out of range
-	 * Rune wouldn't have fit in one or two bytes.
-	 */
-	if (c > Runemax)
-		c = Runeerror;
-	if (SurrogateMin <= c && c <= SurrogateMax)
-		c = Runeerror;
-
-	/*
-	 * three character sequence
-	 *	0800-FFFF => T3 Tx Tx
-	 */
-	if (c <= Rune3) {
-		str[0] = T3 |  (c >> 2*Bitx);
-		str[1] = Tx | ((c >> 1*Bitx) & Maskx);
-		str[2] = Tx |  (c & Maskx);
-		return 3;
-	}
-
-	/*
-	 * four character sequence (21-bit value)
-	 *     10000-1FFFFF => T4 Tx Tx Tx
-	 */
-	str[0] = T4 | (c >> 3*Bitx);
-	str[1] = Tx | ((c >> 2*Bitx) & Maskx);
-	str[2] = Tx | ((c >> 1*Bitx) & Maskx);
-	str[3] = Tx | (c & Maskx);
-	return 4;
-}
-
-String runtime·gostringsize(intgo);
-
-String
-runtime·gostringw(uint16 *str)
-{
-	intgo n1, n2, i;
-	byte buf[8];
-	String s;
-
-	n1 = 0;
-	for(i=0; str[i]; i++)
-		n1 += runetochar(buf, str[i]);
-	s = runtime·gostringsize(n1+4);
-	n2 = 0;
-	for(i=0; str[i]; i++) {
-		// check for race
-		if(n2 >= n1)
-			break;
-		n2 += runetochar(s.str+n2, str[i]);
-	}
-	s.len = n2;
-	s.str[s.len] = 0;
-	return s;
-}
-
-int32
-runtime·strcmp(byte *s1, byte *s2)
-{
-	uintptr i;
-	byte c1, c2;
-
-	for(i=0;; i++) {
-		c1 = s1[i];
-		c2 = s2[i];
-		if(c1 < c2)
-			return -1;
-		if(c1 > c2)
-			return +1;
-		if(c1 == 0)
-			return 0;
-	}
-}
-
-int32
-runtime·strncmp(byte *s1, byte *s2, uintptr n)
-{
-	uintptr i;
-	byte c1, c2;
-
-	for(i=0; i<n; i++) {
-		c1 = s1[i];
-		c2 = s2[i];
-		if(c1 < c2)
-			return -1;
-		if(c1 > c2)
-			return +1;
-		if(c1 == 0)
-			break;
-	}
-	return 0;
-}
-
-byte*
-runtime·strstr(byte *s1, byte *s2)
-{
-	byte *sp1, *sp2;
-
-	if(*s2 == 0)
-		return s1;
-	for(; *s1; s1++) {
-		if(*s1 != *s2)
-			continue;
-		sp1 = s1;
-		sp2 = s2;
-		for(;;) {
-			if(*sp2 == 0)
-				return s1;
-			if(*sp1++ != *sp2++)
-				break;
-		}
-	}
-	return nil;
-}
diff --git a/src/runtime/string.go b/src/runtime/string.go
index 0809f89..a5851b7 100644
--- a/src/runtime/string.go
+++ b/src/runtime/string.go
@@ -8,7 +8,18 @@ import (
 	"unsafe"
 )
 
-func concatstrings(a []string) string {
+// The constant is known to the compiler.
+// There is no fundamental theory behind this number.
+const tmpStringBufSize = 32
+
+type tmpBuf [tmpStringBufSize]byte
+
+// concatstrings implements a Go string concatenation x+y+z+...
+// The operands are passed in the slice a.
+// If buf != nil, the compiler has determined that the result does not
+// escape the calling function, so the string data can be stored in buf
+// if small enough.
+func concatstrings(buf *tmpBuf, a []string) string {
 	idx := 0
 	l := 0
 	count := 0
@@ -18,7 +29,7 @@ func concatstrings(a []string) string {
 			continue
 		}
 		if l+n < l {
-			gothrow("string concatenation too long")
+			throw("string concatenation too long")
 		}
 		l += n
 		count++
@@ -27,10 +38,14 @@ func concatstrings(a []string) string {
 	if count == 0 {
 		return ""
 	}
-	if count == 1 {
+
+	// If there is just one string and either it is not on the stack
+	// or our result does not escape the calling frame (buf != nil),
+	// then we can return that string directly.
+	if count == 1 && (buf != nil || !stringDataOnStack(a[idx])) {
 		return a[idx]
 	}
-	s, b := rawstring(l)
+	s, b := rawstringtmp(buf, l)
 	l = 0
 	for _, x := range a {
 		copy(b[l:], x)
@@ -39,46 +54,71 @@ func concatstrings(a []string) string {
 	return s
 }
 
-//go:nosplit
-func concatstring2(a [2]string) string {
-	return concatstrings(a[:])
+func concatstring2(buf *tmpBuf, a [2]string) string {
+	return concatstrings(buf, a[:])
 }
 
-//go:nosplit
-func concatstring3(a [3]string) string {
-	return concatstrings(a[:])
+func concatstring3(buf *tmpBuf, a [3]string) string {
+	return concatstrings(buf, a[:])
 }
 
-//go:nosplit
-func concatstring4(a [4]string) string {
-	return concatstrings(a[:])
+func concatstring4(buf *tmpBuf, a [4]string) string {
+	return concatstrings(buf, a[:])
 }
 
-//go:nosplit
-func concatstring5(a [5]string) string {
-	return concatstrings(a[:])
+func concatstring5(buf *tmpBuf, a [5]string) string {
+	return concatstrings(buf, a[:])
 }
 
-func slicebytetostring(b []byte) string {
-	if raceenabled && len(b) > 0 {
+// Buf is a fixed-size buffer for the result,
+// it is not nil if the result does not escape.
+func slicebytetostring(buf *tmpBuf, b []byte) string {
+	l := len(b)
+	if l == 0 {
+		// Turns out to be a relatively common case.
+		// Consider that you want to parse out data between parens in "foo()bar",
+		// you find the indices and convert the subslice to string.
+		return ""
+	}
+	if raceenabled && l > 0 {
 		racereadrangepc(unsafe.Pointer(&b[0]),
-			uintptr(len(b)),
+			uintptr(l),
 			getcallerpc(unsafe.Pointer(&b)),
 			funcPC(slicebytetostring))
 	}
-	s, c := rawstring(len(b))
+	s, c := rawstringtmp(buf, l)
 	copy(c, b)
 	return s
 }
 
+// stringDataOnStack reports whether the string's data is
+// stored on the current goroutine's stack.
+func stringDataOnStack(s string) bool {
+	ptr := uintptr((*stringStruct)(unsafe.Pointer(&s)).str)
+	stk := getg().stack
+	return stk.lo <= ptr && ptr < stk.hi
+}
+
+func rawstringtmp(buf *tmpBuf, l int) (s string, b []byte) {
+	if buf != nil && l <= len(buf) {
+		b = buf[:l]
+		s = slicebytetostringtmp(b)
+	} else {
+		s, b = rawstring(l)
+	}
+	return
+}
+
 func slicebytetostringtmp(b []byte) string {
 	// Return a "string" referring to the actual []byte bytes.
 	// This is only for use by internal compiler optimizations
 	// that know that the string form will be discarded before
 	// the calling goroutine could possibly modify the original
 	// slice or synchronize with another goroutine.
-	// Today, the only such case is a m[string(k)] lookup where
+	// First such case is a m[string(k)] lookup where
 	// m is a string-keyed map and k is a []byte.
+	// Second such case is "<"+string(b)+">" concatenation where b is []byte.
+	// Third such case is string(b)=="foo" comparison where b is []byte.
 
 	if raceenabled && len(b) > 0 {
 		racereadrangepc(unsafe.Pointer(&b[0]),
@@ -89,13 +129,30 @@ func slicebytetostringtmp(b []byte) string {
 	return *(*string)(unsafe.Pointer(&b))
 }
 
-func stringtoslicebyte(s string) []byte {
-	b := rawbyteslice(len(s))
+func stringtoslicebyte(buf *tmpBuf, s string) []byte {
+	var b []byte
+	if buf != nil && len(s) <= len(buf) {
+		b = buf[:len(s)]
+	} else {
+		b = rawbyteslice(len(s))
+	}
 	copy(b, s)
 	return b
 }
 
-func stringtoslicerune(s string) []rune {
+func stringtoslicebytetmp(s string) []byte {
+	// Return a slice referring to the actual string bytes.
+	// This is only for use by internal compiler optimizations
+	// that know that the slice won't be mutated.
+	// The only such case today is:
+	// for i, c := range []byte(str)
+
+	str := (*stringStruct)(unsafe.Pointer(&s))
+	ret := slice{array: unsafe.Pointer(str.str), len: str.len, cap: str.len}
+	return *(*[]byte)(unsafe.Pointer(&ret))
+}
+
+func stringtoslicerune(buf *[tmpStringBufSize]rune, s string) []rune {
 	// two passes.
 	// unlike slicerunetostring, no race because strings are immutable.
 	n := 0
@@ -105,7 +162,12 @@ func stringtoslicerune(s string) []rune {
 		s = s[k:]
 		n++
 	}
-	a := rawruneslice(n)
+	var a []rune
+	if buf != nil && n <= len(buf) {
+		a = buf[:n]
+	} else {
+		a = rawruneslice(n)
+	}
 	n = 0
 	for len(t) > 0 {
 		r, k := charntorune(t)
@@ -116,7 +178,7 @@ func stringtoslicerune(s string) []rune {
 	return a
 }
 
-func slicerunetostring(a []rune) string {
+func slicerunetostring(buf *tmpBuf, a []rune) string {
 	if raceenabled && len(a) > 0 {
 		racereadrangepc(unsafe.Pointer(&a[0]),
 			uintptr(len(a))*unsafe.Sizeof(a[0]),
@@ -128,7 +190,7 @@ func slicerunetostring(a []rune) string {
 	for _, r := range a {
 		size1 += runetochar(dum[:], r)
 	}
-	s, b := rawstring(size1 + 3)
+	s, b := rawstringtmp(buf, size1+3)
 	size2 := 0
 	for _, r := range a {
 		// check for race
@@ -145,8 +207,15 @@ type stringStruct struct {
 	len int
 }
 
-func intstring(v int64) string {
-	s, b := rawstring(4)
+func intstring(buf *[4]byte, v int64) string {
+	var s string
+	var b []byte
+	if buf != nil {
+		b = buf[:]
+		s = slicebytetostringtmp(b)
+	} else {
+		s, b = rawstring(4)
+	}
 	n := runetochar(b, rune(v))
 	return s[:n]
 }
@@ -197,9 +266,7 @@ func rawstring(size int) (s string, b []byte) {
 	(*stringStruct)(unsafe.Pointer(&s)).str = p
 	(*stringStruct)(unsafe.Pointer(&s)).len = size
 
-	(*slice)(unsafe.Pointer(&b)).array = (*uint8)(p)
-	(*slice)(unsafe.Pointer(&b)).len = uint(size)
-	(*slice)(unsafe.Pointer(&b)).cap = uint(size)
+	*(*slice)(unsafe.Pointer(&b)) = slice{p, size, size}
 
 	for {
 		ms := maxstring
@@ -211,32 +278,28 @@ func rawstring(size int) (s string, b []byte) {
 
 // rawbyteslice allocates a new byte slice. The byte slice is not zeroed.
 func rawbyteslice(size int) (b []byte) {
-	cap := goroundupsize(uintptr(size))
+	cap := roundupsize(uintptr(size))
 	p := mallocgc(cap, nil, flagNoScan|flagNoZero)
 	if cap != uintptr(size) {
 		memclr(add(p, uintptr(size)), cap-uintptr(size))
 	}
 
-	(*slice)(unsafe.Pointer(&b)).array = (*uint8)(p)
-	(*slice)(unsafe.Pointer(&b)).len = uint(size)
-	(*slice)(unsafe.Pointer(&b)).cap = uint(cap)
+	*(*slice)(unsafe.Pointer(&b)) = slice{p, size, int(cap)}
 	return
 }
 
 // rawruneslice allocates a new rune slice. The rune slice is not zeroed.
 func rawruneslice(size int) (b []rune) {
-	if uintptr(size) > maxmem/4 {
-		gothrow("out of memory")
+	if uintptr(size) > _MaxMem/4 {
+		throw("out of memory")
 	}
-	mem := goroundupsize(uintptr(size) * 4)
+	mem := roundupsize(uintptr(size) * 4)
 	p := mallocgc(mem, nil, flagNoScan|flagNoZero)
 	if mem != uintptr(size)*4 {
 		memclr(add(p, uintptr(size)*4), mem-uintptr(size)*4)
 	}
 
-	(*slice)(unsafe.Pointer(&b)).array = (*uint8)(p)
-	(*slice)(unsafe.Pointer(&b)).len = uint(size)
-	(*slice)(unsafe.Pointer(&b)).cap = uint(mem / 4)
+	*(*slice)(unsafe.Pointer(&b)) = slice{p, size, int(mem / 4)}
 	return
 }
 
@@ -250,14 +313,6 @@ func gobytes(p *byte, n int) []byte {
 	return x
 }
 
-func gostringsize(n int) string {
-	s, _ := rawstring(n)
-	return s
-}
-
-//go:noescape
-func findnull(*byte) int
-
 func gostring(p *byte) string {
 	l := findnull(p)
 	if l == 0 {
@@ -296,3 +351,12 @@ func contains(s, t string) bool {
 func hasprefix(s, t string) bool {
 	return len(s) >= len(t) && s[:len(t)] == t
 }
+
+func atoi(s string) int {
+	n := 0
+	for len(s) > 0 && '0' <= s[0] && s[0] <= '9' {
+		n = n*10 + int(s[0]) - '0'
+		s = s[1:]
+	}
+	return n
+}
diff --git a/src/runtime/string1.go b/src/runtime/string1.go
new file mode 100644
index 0000000..4bfa3d9
--- /dev/null
+++ b/src/runtime/string1.go
@@ -0,0 +1,67 @@
+// 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"
+
+//go:nosplit
+func findnull(s *byte) int {
+	if s == nil {
+		return 0
+	}
+	p := (*[_MaxMem/2 - 1]byte)(unsafe.Pointer(s))
+	l := 0
+	for p[l] != 0 {
+		l++
+	}
+	return l
+}
+
+func findnullw(s *uint16) int {
+	if s == nil {
+		return 0
+	}
+	p := (*[_MaxMem/2/2 - 1]uint16)(unsafe.Pointer(s))
+	l := 0
+	for p[l] != 0 {
+		l++
+	}
+	return l
+}
+
+var maxstring uintptr = 256 // a hint for print
+
+//go:nosplit
+func gostringnocopy(str *byte) string {
+	ss := stringStruct{str: unsafe.Pointer(str), len: findnull(str)}
+	s := *(*string)(unsafe.Pointer(&ss))
+	for {
+		ms := maxstring
+		if uintptr(len(s)) <= ms || casuintptr(&maxstring, ms, uintptr(len(s))) {
+			break
+		}
+	}
+	return s
+}
+
+func gostringw(strw *uint16) string {
+	var buf [8]byte
+	str := (*[_MaxMem/2/2 - 1]uint16)(unsafe.Pointer(strw))
+	n1 := 0
+	for i := 0; str[i] != 0; i++ {
+		n1 += runetochar(buf[:], rune(str[i]))
+	}
+	s, b := rawstring(n1 + 4)
+	n2 := 0
+	for i := 0; str[i] != 0; i++ {
+		// check for race
+		if n2 >= n1 {
+			break
+		}
+		n2 += runetochar(b[n2:], rune(str[i]))
+	}
+	b[n2] = 0 // for luck
+	return s[:n2]
+}
diff --git a/src/runtime/string_test.go b/src/runtime/string_test.go
index 1551ecc..dfda950 100644
--- a/src/runtime/string_test.go
+++ b/src/runtime/string_test.go
@@ -158,3 +158,80 @@ func TestGostringnocopy(t *testing.T) {
 		t.Errorf("want %d, got %d", max+9, newmax)
 	}
 }
+
+func TestCompareTempString(t *testing.T) {
+	s := "foo"
+	b := []byte(s)
+	n := testing.AllocsPerRun(1000, func() {
+		if string(b) != s {
+			t.Fatalf("strings are not equal: '%v' and '%v'", string(b), s)
+		}
+		if string(b) == s {
+		} else {
+			t.Fatalf("strings are not equal: '%v' and '%v'", string(b), s)
+		}
+	})
+	if n != 0 {
+		t.Fatalf("want 0 allocs, got %v", n)
+	}
+}
+
+func TestStringOnStack(t *testing.T) {
+	s := ""
+	for i := 0; i < 3; i++ {
+		s = "a" + s + "b" + s + "c"
+	}
+
+	if want := "aaabcbabccbaabcbabccc"; s != want {
+		t.Fatalf("want: '%v', got '%v'", want, s)
+	}
+}
+
+func TestIntString(t *testing.T) {
+	// Non-escaping result of intstring.
+	s := ""
+	for i := 0; i < 4; i++ {
+		s += string(i+'0') + string(i+'0'+1)
+	}
+	if want := "01122334"; s != want {
+		t.Fatalf("want '%v', got '%v'", want, s)
+	}
+
+	// Escaping result of intstring.
+	var a [4]string
+	for i := 0; i < 4; i++ {
+		a[i] = string(i + '0')
+	}
+	s = a[0] + a[1] + a[2] + a[3]
+	if want := "0123"; s != want {
+		t.Fatalf("want '%v', got '%v'", want, s)
+	}
+}
+
+func TestIntStringAllocs(t *testing.T) {
+	unknown := '0'
+	n := testing.AllocsPerRun(1000, func() {
+		s1 := string(unknown)
+		s2 := string(unknown + 1)
+		if s1 == s2 {
+			t.Fatalf("bad")
+		}
+	})
+	if n != 0 {
+		t.Fatalf("want 0 allocs, got %v", n)
+	}
+}
+
+func TestRangeStringCast(t *testing.T) {
+	s := "abc"
+	n := testing.AllocsPerRun(1000, func() {
+		for i, c := range []byte(s) {
+			if c != s[i] {
+				t.Fatalf("want '%c' at pos %v, got '%c'", s[i], i, c)
+			}
+		}
+	})
+	if n != 0 {
+		t.Fatalf("want 0 allocs, got %v", n)
+	}
+}
diff --git a/src/runtime/stubs.go b/src/runtime/stubs.go
index fe8f9c9..d725bb1 100644
--- a/src/runtime/stubs.go
+++ b/src/runtime/stubs.go
@@ -8,8 +8,9 @@ import "unsafe"
 
 // 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
@@ -17,18 +18,10 @@ func add(p unsafe.Pointer, x uintptr) unsafe.Pointer {
 	return unsafe.Pointer(uintptr(p) + x)
 }
 
-// n must be a power of 2
-func roundup(p unsafe.Pointer, n uintptr) unsafe.Pointer {
-	delta := -uintptr(p) & (n - 1)
-	return unsafe.Pointer(uintptr(p) + delta)
-}
-
-// in runtime.c
+// getg returns the pointer to the current g.
+// The compiler rewrites calls to this function into instructions
+// that fetch the g directly (from TLS or from the dedicated register).
 func getg() *g
-func acquirem() *m
-func releasem(mp *m)
-func gomcache() *mcache
-func readgstatus(*g) uint32 // proc.c
 
 // mcall switches from the g to the g0 stack and invokes fn(g),
 // where g is the goroutine that made the call.
@@ -40,103 +33,55 @@ func readgstatus(*g) uint32 // proc.c
 // run other goroutines.
 //
 // mcall can only be called from g stacks (not g0, not gsignal).
-//go:noescape
+//
+// This must NOT be go:noescape: if fn is a stack-allocated closure,
+// fn puts g on a run queue, and g executes before fn returns, the
+// closure will be invalidated while it is still executing.
 func mcall(fn func(*g))
 
-// onM switches from the g to the g0 stack and invokes fn().
-// When fn returns, onM switches back to the g and returns,
-// continuing execution on the g stack.
-// If arguments must be passed to fn, they can be written to
-// g->m->ptrarg (pointers) and g->m->scalararg (non-pointers)
-// before the call and then consulted during fn.
-// Similarly, fn can pass return values back in those locations.
-// If fn is written in Go, it can be a closure, which avoids the need for
-// ptrarg and scalararg entirely.
-// After reading values out of ptrarg and scalararg it is conventional
-// to zero them to avoid (memory or information) leaks.
-//
-// If onM is called from a g0 stack, it invokes fn and returns,
-// without any stack switches.
-//
-// If onM is called from a gsignal stack, it crashes the program.
-// The implication is that functions used in signal handlers must
-// not use onM.
+// systemstack runs fn on a system stack.
+// If systemstack is called from the per-OS-thread (g0) stack, or
+// if systemstack is called from the signal handling (gsignal) stack,
+// systemstack calls fn directly and returns.
+// Otherwise, systemstack is being called from the limited stack
+// of an ordinary goroutine. In this case, systemstack switches
+// to the per-OS-thread stack, calls fn, and switches back.
+// It is common to use a func literal as the argument, in order
+// to share inputs and outputs with the code around the call
+// to system stack:
 //
-// NOTE(rsc): We could introduce a separate onMsignal that is
-// like onM but if called from a gsignal stack would just run fn on
-// that stack. The caller of onMsignal would be required to save the
-// old values of ptrarg/scalararg and restore them when the call
-// was finished, in case the signal interrupted an onM sequence
-// in progress on the g or g0 stacks. Until there is a clear need for this,
-// we just reject onM in signal handling contexts entirely.
+//	... set up y ...
+//	systemstack(func() {
+//		x = bigcall(y)
+//	})
+//	... use x ...
 //
 //go:noescape
-func onM(fn func())
-
-// onMsignal is like onM but is allowed to be used in code that
-// might run on the gsignal stack. Code running on a signal stack
-// may be interrupting an onM sequence on the main stack, so
-// if the onMsignal calling sequence writes to ptrarg/scalararg,
-// it must first save the old values and then restore them when
-// finished. As an exception to the rule, it is fine not to save and
-// restore the values if the program is trying to crash rather than
-// return from the signal handler.
-// Once all the runtime is written in Go, there will be no ptrarg/scalararg
-// and the distinction between onM and onMsignal (and perhaps mcall)
-// can go away.
-//
-// If onMsignal is called from a gsignal stack, it invokes fn directly,
-// without a stack switch. Otherwise onMsignal behaves like onM.
-//
-//go:noescape
-func onM_signalok(fn func())
+func systemstack(fn func())
 
-func badonm() {
-	gothrow("onM called from signal goroutine")
+func badsystemstack() {
+	throw("systemstack called from unexpected goroutine")
 }
 
-// C functions that run on the M stack.
-// Call using mcall.
-func gosched_m(*g)
-func park_m(*g)
-func recovery_m(*g)
-
-// More C functions that run on the M stack.
-// Call using onM.
-func mcacheRefill_m()
-func largeAlloc_m()
-func gc_m()
-func scavenge_m()
-func setFinalizer_m()
-func removeFinalizer_m()
-func markallocated_m()
-func unrollgcprog_m()
-func unrollgcproginplace_m()
-func setgcpercent_m()
-func setmaxthreads_m()
-func ready_m()
-func deferproc_m()
-func goexit_m()
-func startpanic_m()
-func dopanic_m()
-func readmemstats_m()
-func writeheapdump_m()
-
 // memclr clears n bytes starting at ptr.
 // in memclr_*.s
 //go:noescape
 func memclr(ptr unsafe.Pointer, n uintptr)
 
+//go:linkname reflect_memclr reflect.memclr
+func reflect_memclr(ptr unsafe.Pointer, n uintptr) {
+	memclr(ptr, n)
+}
+
 // memmove copies n bytes from "from" to "to".
 // in memmove_*.s
 //go:noescape
-func memmove(to unsafe.Pointer, from unsafe.Pointer, n uintptr)
+func memmove(to, from unsafe.Pointer, n uintptr)
 
-func starttheworld()
-func stoptheworld()
-func newextram()
-func lockOSThread()
-func unlockOSThread()
+//go:linkname reflect_memmove reflect.memmove
+func reflect_memmove(to, from unsafe.Pointer, n uintptr) {
+	memmove(to, from, n)
+}
 
 // exported value for testing
 var hashLoad = loadFactor
@@ -159,16 +104,9 @@ func noescape(p unsafe.Pointer) unsafe.Pointer {
 	return unsafe.Pointer(x ^ 0)
 }
 
-func entersyscall()
-func reentersyscall(pc uintptr, sp unsafe.Pointer)
-func entersyscallblock()
-func exitsyscall()
-
 func cgocallback(fn, frame unsafe.Pointer, framesize uintptr)
 func gogo(buf *gobuf)
 func gosave(buf *gobuf)
-func read(fd int32, p unsafe.Pointer, n int32) int32
-func close(fd int32) int32
 func mincore(addr unsafe.Pointer, n uintptr, dst *byte) int32
 
 //go:noescape
@@ -176,35 +114,50 @@ func jmpdefer(fv *funcval, argp uintptr)
 func exit1(code int32)
 func asminit()
 func setg(gg *g)
-func exit(code int32)
 func breakpoint()
-func nanotime() int64
-func usleep(usec uint32)
-
-// careful: cputicks is not guaranteed to be monotonic!  In particular, we have
-// noticed drift between cpus on certain os/arch combinations.  See issue 8976.
-func cputicks() int64
-
-func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) unsafe.Pointer
-func munmap(addr unsafe.Pointer, n uintptr)
-func madvise(addr unsafe.Pointer, n uintptr, flags int32)
-func reflectcall(fn, arg unsafe.Pointer, n uint32, retoffset uint32)
-func osyield()
+
+// reflectcall calls fn with a copy of the n argument bytes pointed at by arg.
+// After fn returns, reflectcall copies n-retoffset result bytes
+// back into arg+retoffset before returning. If copying result bytes back,
+// the caller should pass the argument frame type as argtype, so that
+// call can execute appropriate write barriers during the copy.
+// Package reflect passes a frame type. In package runtime, there is only
+// one call that copies results back, in cgocallbackg1, and it does NOT pass a
+// frame type, meaning there are no write barriers invoked. See that call
+// site for justification.
+func reflectcall(argtype *_type, fn, arg unsafe.Pointer, argsize uint32, retoffset uint32)
+
 func procyield(cycles uint32)
-func cgocallback_gofunc(fv *funcval, frame unsafe.Pointer, framesize uintptr)
-func readgogc() int32
-func purgecachedstats(c *mcache)
-func gostringnocopy(b *byte) string
-func goexit()
 
-//go:noescape
-func write(fd uintptr, p unsafe.Pointer, n int32) int32
+type neverCallThisFunction struct{}
+
+// goexit is the return stub at the top of every goroutine call stack.
+// Each goroutine stack is constructed as if goexit called the
+// goroutine's entry point function, so that when the entry point
+// function returns, it will return to goexit, which will call goexit1
+// to perform the actual exit.
+//
+// This function must never be called directly. Call goexit1 instead.
+// gentraceback assumes that goexit terminates the stack. A direct
+// call on the stack will cause gentraceback to stop walking the stack
+// prematurely and if there are leftover stack barriers it may panic.
+func goexit(neverCallThisFunction)
+
+// Not all cgocallback_gofunc frames are actually cgocallback_gofunc,
+// so not all have these arguments. Mark them uintptr so that the GC
+// does not misinterpret memory when the arguments are not present.
+// cgocallback_gofunc is not called from go, only from cgocallback,
+// so the arguments will be found via cgocallback's pointer-declared arguments.
+// See the assembly implementations for more details.
+func cgocallback_gofunc(fv uintptr, frame uintptr, framesize uintptr)
 
 //go:noescape
 func cas(ptr *uint32, old, new uint32) bool
 
-//go:noescape
-func casp(ptr *unsafe.Pointer, old, new unsafe.Pointer) bool
+// NO go:noescape annotation; see atomic_pointer.go.
+func casp1(ptr *unsafe.Pointer, old, new unsafe.Pointer) bool
+
+func nop() // call to prevent inlining of function body
 
 //go:noescape
 func casuintptr(ptr *uintptr, old, new uintptr) bool
@@ -218,6 +171,39 @@ func atomicloaduintptr(ptr *uintptr) uintptr
 //go:noescape
 func atomicloaduint(ptr *uint) uint
 
+// TODO: Write native implementations of int64 atomic ops (or improve
+// inliner). These portable ones can't be inlined right now, so we're
+// taking an extra function call hit.
+
+func atomicstoreint64(ptr *int64, new int64) {
+	atomicstore64((*uint64)(unsafe.Pointer(ptr)), uint64(new))
+}
+
+func atomicloadint64(ptr *int64) int64 {
+	return int64(atomicload64((*uint64)(unsafe.Pointer(ptr))))
+}
+
+func xaddint64(ptr *int64, delta int64) int64 {
+	return int64(xadd64((*uint64)(unsafe.Pointer(ptr)), delta))
+}
+
+// publicationBarrier performs a store/store barrier (a "publication"
+// or "export" barrier). Some form of synchronization is required
+// between initializing an object and making that object accessible to
+// another processor. Without synchronization, the initialization
+// writes and the "publication" write may be reordered, allowing the
+// other processor to follow the pointer and observe an uninitialized
+// object. In general, higher-level synchronization should be used,
+// such as locking or an atomic pointer write. publicationBarrier is
+// for when those aren't an option, such as in the implementation of
+// the memory manager.
+//
+// There's no corresponding barrier for the read side because the read
+// side naturally has a data dependency order. All architectures that
+// Go supports or seems likely to ever support automatically enforce
+// data dependency ordering.
+func publicationBarrier()
+
 //go:noescape
 func setcallerpc(argp unsafe.Pointer, pc uintptr)
 
@@ -231,7 +217,7 @@ func setcallerpc(argp unsafe.Pointer, pc uintptr)
 //
 //	func f(arg1, arg2, arg3 int) {
 //		pc := getcallerpc(unsafe.Pointer(&arg1))
-//		sp := getcallerpc(unsafe.Pointer(&arg2))
+//		sp := getcallersp(unsafe.Pointer(&arg1))
 //	}
 //
 // These two lines find the PC and SP immediately following
@@ -256,25 +242,21 @@ func getcallerpc(argp unsafe.Pointer) uintptr
 func getcallersp(argp unsafe.Pointer) uintptr
 
 //go:noescape
-func asmcgocall(fn, arg unsafe.Pointer)
-
-//go:noescape
-func asmcgocall_errno(fn, arg unsafe.Pointer) int32
-
-//go:noescape
-func open(name *byte, mode, perm int32) int32
-
-//go:noescape
-func gotraceback(*bool) int32
+func asmcgocall(fn, arg unsafe.Pointer) int32
 
+// argp used in Defer structs when there is no argp.
 const _NoArgs = ^uintptr(0)
 
-func newstack()
-func newproc()
 func morestack()
-func mstart()
 func rt0_go()
 
+// stackBarrier records that the stack has been unwound past a certain
+// point. It is installed over a return PC on the stack. It must
+// retrieve the original return PC from g.stkbuf, increment
+// g.stkbufPos to record that the barrier was hit, and jump to the
+// original return PC.
+func stackBarrier()
+
 // return0 is a stub used to return 0 from deferproc.
 // It is called at the very end of deferproc to signal
 // the calling Go function that it should not jump
@@ -282,12 +264,11 @@ func rt0_go()
 // in asm_*.s
 func return0()
 
-// thunk to call time.now.
-func timenow() (sec int64, nsec int32)
+//go:linkname time_now time.now
+func time_now() (sec int64, nsec int32)
 
 // in asm_*.s
 // not called directly; definitions here supply type information for traceback.
-func call16(fn, arg unsafe.Pointer, n, retoffset uint32)
 func call32(fn, arg unsafe.Pointer, n, retoffset uint32)
 func call64(fn, arg unsafe.Pointer, n, retoffset uint32)
 func call128(fn, arg unsafe.Pointer, n, retoffset uint32)
@@ -314,3 +295,20 @@ func call134217728(fn, arg unsafe.Pointer, n, retoffset uint32)
 func call268435456(fn, arg unsafe.Pointer, n, retoffset uint32)
 func call536870912(fn, arg unsafe.Pointer, n, retoffset uint32)
 func call1073741824(fn, arg unsafe.Pointer, n, retoffset uint32)
+
+func systemstack_switch()
+
+func prefetcht0(addr uintptr)
+func prefetcht1(addr uintptr)
+func prefetcht2(addr uintptr)
+func prefetchnta(addr uintptr)
+
+func unixnanotime() int64 {
+	sec, nsec := time_now()
+	return sec*1e9 + int64(nsec)
+}
+
+// round n up to a multiple of a.  a must be a power of 2.
+func round(n, a uintptr) uintptr {
+	return (n + a - 1) &^ (a - 1)
+}
diff --git a/src/runtime/stubs2.go b/src/runtime/stubs2.go
new file mode 100644
index 0000000..1cb6f91
--- /dev/null
+++ b/src/runtime/stubs2.go
@@ -0,0 +1,30 @@
+// 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 !plan9
+// +build !solaris
+// +build !windows
+// +build !nacl
+
+package runtime
+
+import "unsafe"
+
+func read(fd int32, p unsafe.Pointer, n int32) int32
+func closefd(fd int32) int32
+
+func exit(code int32)
+func nanotime() int64
+func usleep(usec uint32)
+
+func mmap(addr unsafe.Pointer, n uintptr, prot, flags, fd int32, off uint32) unsafe.Pointer
+func munmap(addr unsafe.Pointer, n uintptr)
+
+//go:noescape
+func write(fd uintptr, p unsafe.Pointer, n int32) int32
+
+//go:noescape
+func open(name *byte, mode, perm int32) int32
+
+func madvise(addr unsafe.Pointer, n uintptr, flags int32)
diff --git a/src/runtime/stubs32.go b/src/runtime/stubs32.go
new file mode 100644
index 0000000..cd442e9
--- /dev/null
+++ b/src/runtime/stubs32.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 386 arm amd64p32
+
+package runtime
+
+import "unsafe"
+
+// Declarations for runtime services implemented in C or assembly that
+// are only present on 32 bit systems.
+
+func call16(fn, arg unsafe.Pointer, n, retoffset uint32)
diff --git a/src/runtime/stubs_android.go b/src/runtime/stubs_android.go
new file mode 100644
index 0000000..e372377
--- /dev/null
+++ b/src/runtime/stubs_android.go
@@ -0,0 +1,10 @@
+package runtime
+
+import "unsafe"
+
+//go:noescape
+func access(name *byte, mode int32) int32
+
+func connect(fd uintptr, addr unsafe.Pointer, len int32) int32
+
+func socket(domain int32, typ int32, prot int32) int32
diff --git a/src/runtime/symtab.go b/src/runtime/symtab.go
index 45d107b..400ab6d 100644
--- a/src/runtime/symtab.go
+++ b/src/runtime/symtab.go
@@ -22,81 +22,149 @@ func (f *Func) raw() *_func {
 
 // funcdata.h
 const (
-	_PCDATA_ArgSize             = 0
-	_PCDATA_StackMapIndex       = 1
+	_PCDATA_StackMapIndex       = 0
 	_FUNCDATA_ArgsPointerMaps   = 0
 	_FUNCDATA_LocalsPointerMaps = 1
 	_FUNCDATA_DeadValueMaps     = 2
 	_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.
+// moduledata is stored in read-only memory; none of the pointers here
+// are visible to the garbage collector.
+type moduledata struct {
+	pclntable    []byte
+	ftab         []functab
+	filetab      []uint32
+	findfunctab  uintptr
+	minpc, maxpc uintptr
+
+	text, etext           uintptr
+	noptrdata, enoptrdata uintptr
+	data, edata           uintptr
+	bss, ebss             uintptr
+	noptrbss, enoptrbss   uintptr
+	end, gcdata, gcbss    uintptr
+
+	typelinks []*_type
+
+	modulename   string
+	modulehashes []modulehash
+
+	gcdatamask, gcbssmask bitvector
+
+	next *moduledata
+}
 
-	pclntab, epclntab struct{} // linker symbols
-)
+// For each shared library a module links against, the linker creates an entry in the
+// moduledata.modulehashes slice containing the name of the module, the abi hash seen
+// at link time and a pointer to the runtime abi hash. These are checked in
+// moduledataverify1 below.
+type modulehash struct {
+	modulename   string
+	linktimehash string
+	runtimehash  *string
+}
+
+var firstmoduledata moduledata  // linker symbol
+var lastmoduledatap *moduledata // linker symbol
 
 type functab struct {
 	entry   uintptr
 	funcoff uintptr
 }
 
-func symtabinit() {
+const minfunc = 16                 // minimum function size
+const pcbucketsize = 256 * minfunc // size of bucket in the pc->func lookup table
+
+// findfunctab is an array of these structures.
+// Each bucket represents 4096 bytes of the text segment.
+// Each subbucket represents 256 bytes of the text segment.
+// To find a function given a pc, locate the bucket and subbucket for
+// that pc.  Add together the idx and subbucket value to obtain a
+// function index.  Then scan the functab array starting at that
+// index to find the target function.
+// This table uses 20 bytes for every 4096 bytes of code, or ~0.5% overhead.
+type findfuncbucket struct {
+	idx        uint32
+	subbuckets [16]byte
+}
+
+func moduledataverify() {
+	for datap := &firstmoduledata; datap != nil; datap = datap.next {
+		moduledataverify1(datap)
+	}
+}
+
+const debugPcln = false
+
+func moduledataverify1(datap *moduledata) {
 	// 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(&datap.pclntable))
+	pcln32 := *(**[2]uint32)(unsafe.Pointer(&datap.pclntable))
 	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]))
-		gothrow("invalid function symbol table\n")
+		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.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.array = p
-	sp.len = nftab + 1
-	sp.cap = sp.len
+	nftab := len(datap.ftab) - 1
 	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 datap.ftab[i].entry > datap.ftab[i+1].entry {
+			f1 := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i].funcoff]))
+			f2 := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i+1].funcoff]))
 			f2name := "end"
 			if i+1 < nftab {
-				f2name = gofuncname(f2)
+				f2name = funcname(f2)
 			}
-			println("function symbol table not sorted by program counter:", hex(ftab[i].entry), gofuncname(f1), ">", hex(ftab[i+1].entry), f2name)
+			println("function symbol table not sorted by program counter:", hex(datap.ftab[i].entry), funcname(f1), ">", hex(datap.ftab[i+1].entry), f2name)
 			for j := 0; j <= i; j++ {
-				print("\t", hex(ftab[j].entry), " ", gofuncname((*_func)(unsafe.Pointer(&pclntable[ftab[j].funcoff]))))
+				print("\t", hex(datap.ftab[j].entry), " ", funcname((*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[j].funcoff]))), "\n")
+			}
+			throw("invalid runtime symbol table")
+		}
+
+		if debugPcln || nftab-i < 5 {
+			// Check a PC near but not at the very end.
+			// The very end might be just padding that is not covered by the tables.
+			// No architecture rounds function entries to more than 16 bytes,
+			// but if one came along we'd need to subtract more here.
+			// But don't use the next PC if it corresponds to a foreign object chunk
+			// (no pcln table, f2.pcln == 0). That chunk might have an alignment
+			// more than 16 bytes.
+			f := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i].funcoff]))
+			end := f.entry
+			if i+1 < nftab {
+				f2 := (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[i+1].funcoff]))
+				if f2.pcln != 0 {
+					end = f2.entry - 16
+					if end < f.entry {
+						end = f.entry
+					}
+				}
 			}
-			gothrow("invalid runtime symbol table")
+			pcvalue(f, f.pcfile, end, true)
+			pcvalue(f, f.pcln, end, true)
+			pcvalue(f, f.pcsp, end, true)
 		}
 	}
 
-	// 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
-	fileoffset := *(*uint32)(end)
-	sp.array = unsafe.Pointer(&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.cap = sp.len
+	if datap.minpc != datap.ftab[0].entry ||
+		datap.maxpc != datap.ftab[nftab].entry {
+		throw("minpc or maxpc invalid")
+	}
+
+	for _, modulehash := range datap.modulehashes {
+		if modulehash.linktimehash != *modulehash.runtimehash {
+			println("abi mismatch detected between", datap.modulename, "and", modulehash.modulename)
+			throw("abi mismatch")
+		}
+	}
 }
 
 // FuncForPC returns a *Func describing the function that contains the
@@ -107,7 +175,7 @@ func FuncForPC(pc uintptr) *Func {
 
 // Name returns the name of the function.
 func (f *Func) Name() string {
-	return gofuncname(f.raw())
+	return funcname(f.raw())
 }
 
 // Entry returns the entry address of the function.
@@ -122,44 +190,56 @@ func (f *Func) Entry() uintptr {
 func (f *Func) FileLine(pc uintptr) (file string, line int) {
 	// Pass strict=false here, because anyone can call this function,
 	// and they might just be wrong about targetpc belonging to f.
-	line = int(funcline1(f.raw(), pc, &file, false))
-	return file, line
+	file, line32 := funcline1(f.raw(), pc, false)
+	return file, int(line32)
 }
 
-func findfunc(pc uintptr) *_func {
-	if len(ftab) == 0 {
-		return nil
+func findmoduledatap(pc uintptr) *moduledata {
+	for datap := &firstmoduledata; datap != nil; datap = datap.next {
+		if datap.minpc <= pc && pc <= datap.maxpc {
+			return datap
+		}
 	}
+	return nil
+}
 
-	if pc < ftab[0].entry || pc >= ftab[len(ftab)-1].entry {
+func findfunc(pc uintptr) *_func {
+	datap := findmoduledatap(pc)
+	if datap == nil {
 		return nil
 	}
+	const nsub = uintptr(len(findfuncbucket{}.subbuckets))
 
-	// binary search to find func with entry <= pc.
-	lo := 0
-	nf := len(ftab) - 1 // last entry is sentinel
-	for nf > 0 {
-		n := nf / 2
-		f := &ftab[lo+n]
-		if f.entry <= pc && pc < ftab[lo+n+1].entry {
-			return (*_func)(unsafe.Pointer(&pclntable[f.funcoff]))
-		} else if pc < f.entry {
-			nf = n
-		} else {
-			lo += n + 1
-			nf -= n + 1
-		}
+	x := pc - datap.minpc
+	b := x / pcbucketsize
+	i := x % pcbucketsize / (pcbucketsize / nsub)
+
+	ffb := (*findfuncbucket)(add(unsafe.Pointer(datap.findfunctab), b*unsafe.Sizeof(findfuncbucket{})))
+	idx := ffb.idx + uint32(ffb.subbuckets[i])
+	if pc < datap.ftab[idx].entry {
+		throw("findfunc: bad findfunctab entry")
 	}
 
-	gothrow("findfunc: binary search failed")
-	return nil
+	// linear search to find func with pc >= entry.
+	for datap.ftab[idx+1].entry <= pc {
+		idx++
+	}
+	return (*_func)(unsafe.Pointer(&datap.pclntable[datap.ftab[idx].funcoff]))
 }
 
 func pcvalue(f *_func, off int32, targetpc uintptr, strict bool) int32 {
 	if off == 0 {
 		return -1
 	}
-	p := pclntable[off:]
+	datap := findmoduledatap(f.entry) // inefficient
+	if datap == nil {
+		if strict && panicking == 0 {
+			print("runtime: no module data for ", hex(f.entry), "\n")
+			throw("no module data")
+		}
+		return -1
+	}
+	p := datap.pclntable[off:]
 	pc := f.entry
 	val := int32(-1)
 	for {
@@ -179,9 +259,9 @@ func pcvalue(f *_func, off int32, targetpc uintptr, strict bool) int32 {
 		return -1
 	}
 
-	print("runtime: invalid pc-encoded table f=", gofuncname(f), " pc=", hex(pc), " targetpc=", hex(targetpc), " tab=", p, "\n")
+	print("runtime: invalid pc-encoded table f=", funcname(f), " pc=", hex(pc), " targetpc=", hex(targetpc), " tab=", p, "\n")
 
-	p = pclntable[off:]
+	p = datap.pclntable[off:]
 	pc = f.entry
 	val = -1
 	for {
@@ -193,41 +273,48 @@ func pcvalue(f *_func, off int32, targetpc uintptr, strict bool) int32 {
 		print("\tvalue=", val, " until pc=", hex(pc), "\n")
 	}
 
-	gothrow("invalid runtime symbol table")
+	throw("invalid runtime symbol table")
 	return -1
 }
 
-func funcname(f *_func) *byte {
+func cfuncname(f *_func) *byte {
 	if f == nil || f.nameoff == 0 {
 		return nil
 	}
-	return (*byte)(unsafe.Pointer(&pclntable[f.nameoff]))
+	datap := findmoduledatap(f.entry) // inefficient
+	if datap == nil {
+		return nil
+	}
+	return (*byte)(unsafe.Pointer(&datap.pclntable[f.nameoff]))
 }
 
-func gofuncname(f *_func) string {
-	return gostringnocopy(funcname(f))
+func funcname(f *_func) string {
+	return gostringnocopy(cfuncname(f))
 }
 
-func funcline1(f *_func, targetpc uintptr, file *string, strict bool) int32 {
-	*file = "?"
+func funcline1(f *_func, targetpc uintptr, strict bool) (file string, line int32) {
+	datap := findmoduledatap(f.entry) // inefficient
+	if datap == nil {
+		return "?", 0
+	}
 	fileno := int(pcvalue(f, f.pcfile, targetpc, strict))
-	line := pcvalue(f, f.pcln, targetpc, strict)
-	if fileno == -1 || line == -1 || fileno >= len(filetab) {
-		// print("looking for ", hex(targetpc), " in ", gofuncname(f), " got file=", fileno, " line=", lineno, "\n")
-		return 0
+	line = pcvalue(f, f.pcln, targetpc, strict)
+	if fileno == -1 || line == -1 || fileno >= len(datap.filetab) {
+		// print("looking for ", hex(targetpc), " in ", funcname(f), " got file=", fileno, " line=", lineno, "\n")
+		return "?", 0
 	}
-	*file = gostringnocopy(&pclntable[filetab[fileno]])
-	return line
+	file = gostringnocopy(&datap.pclntable[datap.filetab[fileno]])
+	return
 }
 
-func funcline(f *_func, targetpc uintptr, file *string) int32 {
-	return funcline1(f, targetpc, file, true)
+func funcline(f *_func, targetpc uintptr) (file string, line int32) {
+	return funcline1(f, targetpc, true)
 }
 
 func funcspdelta(f *_func, targetpc uintptr) int32 {
 	x := pcvalue(f, f.pcsp, targetpc, true)
 	if x&(ptrSize-1) != 0 {
-		print("invalid spdelta ", hex(f.entry), " ", hex(targetpc), " ", hex(f.pcsp), " ", x, "\n")
+		print("invalid spdelta ", funcname(f), " ", hex(f.entry), " ", hex(targetpc), " ", hex(f.pcsp), " ", x, "\n")
 	}
 	return x
 }
@@ -286,3 +373,17 @@ func readvarint(p []byte) (newp []byte, val uint32) {
 	}
 	return p, v
 }
+
+type stackmap struct {
+	n        int32   // number of bitmaps
+	nbit     int32   // number of bits in each bitmap
+	bytedata [1]byte // bitmaps, each starting on a 32-bit boundary
+}
+
+//go:nowritebarrier
+func stackmapdata(stkmap *stackmap, n int32) bitvector {
+	if n < 0 || n >= stkmap.n {
+		throw("stackmapdata: index out of range")
+	}
+	return bitvector{stkmap.nbit, (*byte)(add(unsafe.Pointer(&stkmap.bytedata), uintptr(n*((stkmap.nbit+31)/32*4))))}
+}
diff --git a/src/runtime/symtab_test.go b/src/runtime/symtab_test.go
index bd9fe18..b15a2e9 100644
--- a/src/runtime/symtab_test.go
+++ b/src/runtime/symtab_test.go
@@ -45,3 +45,108 @@ func testCallerBar(t *testing.T) {
 		}
 	}
 }
+
+func lineNumber() int {
+	_, _, line, _ := runtime.Caller(1)
+	return line // return 0 for error
+}
+
+// Do not add/remove lines in this block without updating the line numbers.
+var firstLine = lineNumber() // 0
+var (                        // 1
+	lineVar1             = lineNumber()               // 2
+	lineVar2a, lineVar2b = lineNumber(), lineNumber() // 3
+)                        // 4
+var compLit = []struct { // 5
+	lineA, lineB int // 6
+}{ // 7
+	{ // 8
+		lineNumber(), lineNumber(), // 9
+	}, // 10
+	{ // 11
+		lineNumber(), // 12
+		lineNumber(), // 13
+	}, // 14
+	{ // 15
+		lineB: lineNumber(), // 16
+		lineA: lineNumber(), // 17
+	}, // 18
+}                                     // 19
+var arrayLit = [...]int{lineNumber(), // 20
+	lineNumber(), lineNumber(), // 21
+	lineNumber(), // 22
+}                                  // 23
+var sliceLit = []int{lineNumber(), // 24
+	lineNumber(), lineNumber(), // 25
+	lineNumber(), // 26
+}                         // 27
+var mapLit = map[int]int{ // 28
+	29:           lineNumber(), // 29
+	30:           lineNumber(), // 30
+	lineNumber(): 31,           // 31
+	lineNumber(): 32,           // 32
+}                           // 33
+var intLit = lineNumber() + // 34
+	lineNumber() + // 35
+			lineNumber() // 36
+func trythis() { // 37
+	recordLines(lineNumber(), // 38
+		lineNumber(), // 39
+		lineNumber()) // 40
+}
+
+// Modifications below this line are okay.
+
+var l38, l39, l40 int
+
+func recordLines(a, b, c int) {
+	l38 = a
+	l39 = b
+	l40 = c
+}
+
+func TestLineNumber(t *testing.T) {
+	trythis()
+	for _, test := range []struct {
+		name string
+		val  int
+		want int
+	}{
+		{"firstLine", firstLine, 0},
+		{"lineVar1", lineVar1, 2},
+		{"lineVar2a", lineVar2a, 3},
+		{"lineVar2b", lineVar2b, 3},
+		{"compLit[0].lineA", compLit[0].lineA, 9},
+		{"compLit[0].lineB", compLit[0].lineB, 9},
+		{"compLit[1].lineA", compLit[1].lineA, 12},
+		{"compLit[1].lineB", compLit[1].lineB, 13},
+		{"compLit[2].lineA", compLit[2].lineA, 17},
+		{"compLit[2].lineB", compLit[2].lineB, 16},
+
+		{"arrayLit[0]", arrayLit[0], 20},
+		{"arrayLit[1]", arrayLit[1], 21},
+		{"arrayLit[2]", arrayLit[2], 21},
+		{"arrayLit[3]", arrayLit[3], 22},
+
+		{"sliceLit[0]", sliceLit[0], 24},
+		{"sliceLit[1]", sliceLit[1], 25},
+		{"sliceLit[2]", sliceLit[2], 25},
+		{"sliceLit[3]", sliceLit[3], 26},
+
+		{"mapLit[29]", mapLit[29], 29},
+		{"mapLit[30]", mapLit[30], 30},
+		{"mapLit[31]", mapLit[31+firstLine] + firstLine, 31}, // nb it's the key not the value
+		{"mapLit[32]", mapLit[32+firstLine] + firstLine, 32}, // nb it's the key not the value
+
+		{"intLit", intLit - 2*firstLine, 34 + 35 + 36},
+
+		{"l38", l38, 38},
+		{"l39", l39, 39},
+		{"l40", l40, 40},
+	} {
+		if got := test.val - firstLine; got != test.want {
+			t.Errorf("%s on firstLine+%d want firstLine+%d (firstLine=%d, val=%d)",
+				test.name, got, test.want, firstLine, test.val)
+		}
+	}
+}
diff --git a/src/runtime/sys_arm.c b/src/runtime/sys_arm.c
deleted file mode 100644
index a65560e..0000000
--- a/src/runtime/sys_arm.c
+++ /dev/null
@@ -1,35 +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.
-
-#include "runtime.h"
-
-// adjust Gobuf as if it executed a call to fn with context ctxt
-// and then did an immediate Gosave.
-void
-runtime·gostartcall(Gobuf *gobuf, void (*fn)(void), void *ctxt)
-{
-	if(gobuf->lr != 0)
-		runtime·throw("invalid use of gostartcall");
-	gobuf->lr = gobuf->pc;
-	gobuf->pc = (uintptr)fn;
-	gobuf->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.
-void
-runtime·rewindmorestack(Gobuf *gobuf)
-{
-	uint32 inst;
-
-	inst = *(uint32*)gobuf->pc;
-	if((gobuf->pc&3) == 0 && (inst>>24) == 0x9a) {
-		//runtime·printf("runtime: rewind pc=%p to pc=%p\n", gobuf->pc, gobuf->pc + ((int32)(inst<<8)>>6) + 8);
-		gobuf->pc += ((int32)(inst<<8)>>6) + 8;
-		return;
-	}
-	runtime·printf("runtime: pc=%p %x\n", gobuf->pc, inst);
-	runtime·throw("runtime: misuse of rewindmorestack");
-}
diff --git a/src/runtime/sys_arm.go b/src/runtime/sys_arm.go
new file mode 100644
index 0000000..d2e6914
--- /dev/null
+++ b/src/runtime/sys_arm.go
@@ -0,0 +1,38 @@
+// 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))
+		if inst>>24 == 0x9a || inst>>24 == 0xea {
+			buf.pc += uintptr(int32(inst<<8)>>6) + 8
+			return
+		}
+	}
+
+	print("runtime: pc=", hex(buf.pc), " ", hex(inst), "\n")
+	throw("runtime: misuse of rewindmorestack")
+}
+
+// for testing
+func usplit(x uint32) (q, r uint32)
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 a961c71..abc5d32 100644
--- a/src/runtime/sys_darwin_386.s
+++ b/src/runtime/sys_darwin_386.s
@@ -6,7 +6,8 @@
 // See http://fxr.watson.org/fxr/source/bsd/kern/syscalls.c?v=xnu-1228
 // or /usr/include/sys/syscall.h (on a Mac) for system call numbers.
 
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
 #include "textflag.h"
 
 // Exit the entire program (like C exit)
@@ -28,28 +29,41 @@ TEXT runtime·exit1(SB),NOSPLIT,$0
 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
+TEXT runtime·closefd(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
 
-TEXT runtime·raise(SB),NOSPLIT,$16
+TEXT runtime·raise(SB),NOSPLIT,$0
+	// Ideally we'd send the signal to the current thread,
+	// not the whole process, but that's too hard on OS X.
+	JMP	runtime·raiseproc(SB)
+
+TEXT runtime·raiseproc(SB),NOSPLIT,$16
 	MOVL	$20, AX // getpid
 	INT	$0x80
 	MOVL	AX, 4(SP)	// pid
@@ -207,8 +221,7 @@ TEXT time·now(SB),NOSPLIT,$0
 	MOVL	DX, nsec+8(FP)
 	RET
 
-// int64 nanotime(void) so really
-// void nanotime(int64 *nsec)
+// func nanotime() int64
 TEXT runtime·nanotime(SB),NOSPLIT,$0
 	CALL	runtime·now(SB)
 	MOVL	AX, ret_lo+0(FP)
@@ -248,7 +261,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$40
 	MOVL	BX, 0(SP)
 	MOVL	$runtime·badsignal(SB), AX
 	CALL	AX
-	JMP 	sigtramp_ret
+	JMP 	ret
 
 	// save g
 	MOVL	DI, 20(SP)
@@ -275,7 +288,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$40
 	MOVL	20(SP), DI
 	MOVL	DI, g(CX)
 
-sigtramp_ret:
+ret:
 	// call sigreturn
 	MOVL	context+16(FP), CX
 	MOVL	style+4(FP), BX
@@ -314,33 +327,32 @@ TEXT runtime·usleep(SB),NOSPLIT,$32
 	INT	$0x80
 	RET
 
-// void bsdthread_create(void *stk, M *mp, G *gp, void (*fn)(void))
+// func bsdthread_create(stk, arg unsafe.Pointer, fn uintptr) int32
 // System call args are: func arg stack pthread flags.
 TEXT runtime·bsdthread_create(SB),NOSPLIT,$32
 	MOVL	$360, AX
 	// 0(SP) is where the caller PC would be; kernel skips it
-	MOVL	fn+12(FP), BX
+	MOVL	fn+8(FP), BX
 	MOVL	BX, 4(SP)	// func
-	MOVL	mm+4(FP), BX
+	MOVL	arg+4(FP), BX
 	MOVL	BX, 8(SP)	// arg
 	MOVL	stk+0(FP), BX
 	MOVL	BX, 12(SP)	// stack
-	MOVL	gg+8(FP), BX
-	MOVL	BX, 16(SP)	// pthread
+	MOVL    $0, 16(SP)      // pthread
 	MOVL	$0x1000000, 20(SP)	// flags = PTHREAD_START_CUSTOM
 	INT	$0x80
 	JAE	4(PC)
 	NEGL	AX
-	MOVL	AX, ret+16(FP)
+	MOVL	AX, ret+12(FP)
 	RET
 	MOVL	$0, AX
-	MOVL	AX, ret+16(FP)
+	MOVL	AX, ret+12(FP)
 	RET
 
 // The thread that bsdthread_create creates starts executing here,
 // because we registered this function using bsdthread_register
 // at startup.
-//	AX = "pthread" (= g)
+//	AX = "pthread" (= 0x0)
 //	BX = mach thread port
 //	CX = "func" (= fn)
 //	DX = "arg" (= m)
@@ -367,6 +379,7 @@ TEXT runtime·bsdthread_start(SB),NOSPLIT,$0
 
 	// Now segment is established.  Initialize m, g.
 	get_tls(BP)
+	MOVL    m_g0(DX), AX
 	MOVL	AX, g(BP)
 	MOVL	DX, g_m(AX)
 	MOVL	BX, m_procid(DX)	// m->procid = thread port (for debuggers)
@@ -375,7 +388,7 @@ TEXT runtime·bsdthread_start(SB),NOSPLIT,$0
 	CALL	runtime·exit1(SB)
 	RET
 
-// void bsdthread_register(void)
+// func bsdthread_register() int32
 // registers callbacks for threadstart (see bsdthread_create above
 // and wqthread and pthsize (not used).  returns 0 on success.
 TEXT runtime·bsdthread_register(SB),NOSPLIT,$40
@@ -434,35 +447,35 @@ TEXT runtime·mach_task_self(SB),NOSPLIT,$0
 // Mach provides trap versions of the semaphore ops,
 // instead of requiring the use of RPC.
 
-// uint32 mach_semaphore_wait(uint32)
+// func mach_semaphore_wait(sema uint32) int32
 TEXT runtime·mach_semaphore_wait(SB),NOSPLIT,$0
 	MOVL	$-36, AX
 	CALL	runtime·sysenter(SB)
 	MOVL	AX, ret+4(FP)
 	RET
 
-// uint32 mach_semaphore_timedwait(uint32, uint32, uint32)
+// func mach_semaphore_timedwait(sema, sec, nsec uint32) int32
 TEXT runtime·mach_semaphore_timedwait(SB),NOSPLIT,$0
 	MOVL	$-38, AX
 	CALL	runtime·sysenter(SB)
 	MOVL	AX, ret+12(FP)
 	RET
 
-// uint32 mach_semaphore_signal(uint32)
+// func mach_semaphore_signal(sema uint32) int32
 TEXT runtime·mach_semaphore_signal(SB),NOSPLIT,$0
 	MOVL	$-33, AX
 	CALL	runtime·sysenter(SB)
 	MOVL	AX, ret+4(FP)
 	RET
 
-// uint32 mach_semaphore_signal_all(uint32)
+// func mach_semaphore_signal_all(sema uint32) int32
 TEXT runtime·mach_semaphore_signal_all(SB),NOSPLIT,$0
 	MOVL	$-34, AX
 	CALL	runtime·sysenter(SB)
 	MOVL	AX, ret+4(FP)
 	RET
 
-// setldt(int entry, int address, int limit)
+// func setldt(entry int, address int, limit int)
 // entry and limit are ignored.
 TEXT runtime·setldt(SB),NOSPLIT,$32
 	MOVL	address+4(FP), BX	// aka base
@@ -509,7 +522,7 @@ TEXT runtime·sysctl(SB),NOSPLIT,$0
 	MOVL	AX, ret+24(FP)
 	RET
 
-// int32 runtime·kqueue(void);
+// func kqueue() int32
 TEXT runtime·kqueue(SB),NOSPLIT,$0
 	MOVL	$362, AX
 	INT	$0x80
@@ -518,7 +531,7 @@ TEXT runtime·kqueue(SB),NOSPLIT,$0
 	MOVL	AX, ret+0(FP)
 	RET
 
-// int32 runtime·kevent(int kq, Kevent *changelist, int nchanges, Kevent *eventlist, int nevents, Timespec *timeout);
+// func kevent(kq int32, ch *keventt, nch int32, ev *keventt, nev int32, ts *timespec) int32
 TEXT runtime·kevent(SB),NOSPLIT,$0
 	MOVL	$363, AX
 	INT	$0x80
@@ -527,7 +540,7 @@ TEXT runtime·kevent(SB),NOSPLIT,$0
 	MOVL	AX, ret+24(FP)
 	RET
 
-// int32 runtime·closeonexec(int32 fd);
+// func closeonexec(fd int32)
 TEXT runtime·closeonexec(SB),NOSPLIT,$32
 	MOVL	$92, AX  // fcntl
 	// 0(SP) is where the caller PC would be; kernel skips it
diff --git a/src/runtime/sys_darwin_amd64.s b/src/runtime/sys_darwin_amd64.s
index bd397d7..692dbca 100644
--- a/src/runtime/sys_darwin_amd64.s
+++ b/src/runtime/sys_darwin_amd64.s
@@ -11,7 +11,8 @@
 // The high 8 bits specify the kind of system call: 1=Mach, 2=BSD, 3=Machine-Dependent.
 //
 
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
 #include "textflag.h"
 
 // Exit the entire program (like C exit)
@@ -37,13 +38,17 @@ TEXT runtime·open(SB),NOSPLIT,$0
 	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
 
-TEXT runtime·close(SB),NOSPLIT,$0
+TEXT runtime·closefd(SB),NOSPLIT,$0
 	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
 
@@ -53,6 +58,8 @@ TEXT runtime·read(SB),NOSPLIT,$0
 	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
 
@@ -62,10 +69,17 @@ TEXT runtime·write(SB),NOSPLIT,$0
 	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
 
-TEXT runtime·raise(SB),NOSPLIT,$24
+TEXT runtime·raise(SB),NOSPLIT,$0
+	// Ideally we'd send the signal to the current thread,
+	// not the whole process, but that's too hard on OS X.
+	JMP	runtime·raiseproc(SB)
+
+TEXT runtime·raiseproc(SB),NOSPLIT,$24
 	MOVL	$(0x2000000+20), AX // getpid
 	SYSCALL
 	MOVQ	AX, DI	// arg 1 - pid
@@ -186,7 +200,7 @@ TEXT runtime·sigprocmask(SB),NOSPLIT,$0
 	MOVL	$0xf1, 0xf1  // crash
 	RET
 
-TEXT runtime·sigaction(SB),NOSPLIT,$0
+TEXT runtime·sigaction(SB),NOSPLIT,$0-24
 	MOVL	mode+0(FP), DI		// arg 1 sig
 	MOVQ	new+8(FP), SI		// arg 2 act
 	MOVQ	old+16(FP), DX		// arg 3 oact
@@ -198,48 +212,29 @@ TEXT runtime·sigaction(SB),NOSPLIT,$0
 	MOVL	$0xf1, 0xf1  // crash
 	RET
 
-TEXT runtime·sigtramp(SB),NOSPLIT,$64
-	get_tls(BX)
-
-	MOVQ	R8, 32(SP)	// save ucontext
-	MOVQ	SI, 40(SP)	// save infostyle
-
-	// check that g exists
-	MOVQ	g(BX), R10
-	CMPQ	R10, $0
-	JNE	5(PC)
-	MOVL	DX, 0(SP)
-	MOVQ	$runtime·badsignal(SB), AX
-	CALL	AX
-	JMP 	sigtramp_ret
-
-	// save g
-	MOVQ	R10, 48(SP)
-
-	// g = m->gsignal
-	MOVQ	g_m(R10), BP
-	MOVQ	m_gsignal(BP), BP
-	MOVQ	BP, g(BX)
-
-	MOVL	DX, 0(SP)
-	MOVQ	CX, 8(SP)
-	MOVQ	R8, 16(SP)
-	MOVQ	R10, 24(SP)
-
-	CALL	DI
-
-	// restore g
-	get_tls(BX)
-	MOVQ	48(SP), R10
-	MOVQ	R10, g(BX)
+TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
+	MOVQ fn+0(FP),    AX
+	MOVQ sig+8(FP),   DI
+	MOVQ info+16(FP), SI
+	MOVQ ctx+24(FP),  DX
+	CALL AX
+	RET
 
-sigtramp_ret:
-	// call sigreturn
-	MOVL	$(0x2000000+184), AX	// sigreturn(ucontext, infostyle)
-	MOVQ	32(SP), DI	// saved ucontext
-	MOVQ	40(SP), SI	// saved infostyle
+TEXT runtime·sigreturn(SB),NOSPLIT,$0-12
+	MOVQ ctx+0(FP),        DI
+	MOVL infostyle+8(FP),  SI
+	MOVL $(0x2000000+184), AX
 	SYSCALL
-	INT $3	// not reached
+	INT $3 // not reached
+
+TEXT runtime·sigtramp(SB),NOSPLIT,$32
+	MOVQ DI,  0(SP) // fn
+	MOVL SI,  8(SP) // infostyle
+	MOVL DX, 12(SP) // sig
+	MOVQ CX, 16(SP) // info
+	MOVQ R8, 24(SP) // ctx
+	MOVQ $runtime·sigtrampgo(SB), AX
+	CALL AX
 
 TEXT runtime·mmap(SB),NOSPLIT,$0
 	MOVQ	addr+0(FP), DI		// arg 1 addr
@@ -263,8 +258,8 @@ TEXT runtime·munmap(SB),NOSPLIT,$0
 	RET
 
 TEXT runtime·sigaltstack(SB),NOSPLIT,$0
-	MOVQ	new+8(SP), DI
-	MOVQ	old+16(SP), SI
+	MOVQ	new+0(FP), DI
+	MOVQ	old+8(FP), SI
 	MOVQ	$(0x2000000+53), AX
 	SYSCALL
 	JCC	2(PC)
@@ -289,25 +284,25 @@ TEXT runtime·usleep(SB),NOSPLIT,$16
 	SYSCALL
 	RET
 
-// void bsdthread_create(void *stk, M *mp, G *gp, void (*fn)(void))
+// func bsdthread_create(stk, arg unsafe.Pointer, fn uintptr) int32
 TEXT runtime·bsdthread_create(SB),NOSPLIT,$0
 	// Set up arguments to bsdthread_create system call.
 	// The ones in quotes pass through to the thread callback
 	// uninterpreted, so we can put whatever we want there.
-	MOVQ	fn+32(SP), DI	// "func"
-	MOVQ	mm+16(SP), SI	// "arg"
-	MOVQ	stk+8(SP), DX	// stack
-	MOVQ	gg+24(SP), R10	// "pthread"
-	MOVQ	$0x01000000, R8	// flags = PTHREAD_START_CUSTOM
-	MOVQ	$0, R9	// paranoia
+	MOVQ	fn+16(FP),   DI
+	MOVQ	arg+8(FP),  SI
+	MOVQ	stk+0(FP),   DX
+	MOVQ	$0x01000000, R8  // flags = PTHREAD_START_CUSTOM
+	MOVQ	$0,          R9  // paranoia
+	MOVQ	$0,          R10 // paranoia, "pthread"
 	MOVQ	$(0x2000000+360), AX	// bsdthread_create
 	SYSCALL
 	JCC 4(PC)
 	NEGQ	AX
-	MOVL	AX, ret+32(FP)
+	MOVL	AX, ret+24(FP)
 	RET
 	MOVL	$0, AX
-	MOVL	AX, ret+32(FP)
+	MOVL	AX, ret+24(FP)
 	RET
 
 // The thread that bsdthread_create creates starts executing here,
@@ -345,7 +340,7 @@ TEXT runtime·bsdthread_start(SB),NOSPLIT,$0
 	CALL	runtime·exit1(SB)
 	RET
 
-// void bsdthread_register(void)
+// func bsdthread_register() int32
 // registers callbacks for threadstart (see bsdthread_create above
 // and wqthread and pthsize (not used).  returns 0 on success.
 TEXT runtime·bsdthread_register(SB),NOSPLIT,$0
@@ -367,7 +362,7 @@ TEXT runtime·bsdthread_register(SB),NOSPLIT,$0
 
 // Mach system calls use 0x1000000 instead of the BSD's 0x2000000.
 
-// uint32 mach_msg_trap(void*, uint32, uint32, uint32, uint32, uint32, uint32)
+// func mach_msg_trap(h unsafe.Pointer, op int32, send_size, rcv_size, rcv_name, timeout, notify uint32) int32
 TEXT runtime·mach_msg_trap(SB),NOSPLIT,$0
 	MOVQ	h+0(FP), DI
 	MOVL	op+8(FP), SI
@@ -404,7 +399,7 @@ TEXT runtime·mach_reply_port(SB),NOSPLIT,$0
 // Mach provides trap versions of the semaphore ops,
 // instead of requiring the use of RPC.
 
-// uint32 mach_semaphore_wait(uint32)
+// func mach_semaphore_wait(sema uint32) int32
 TEXT runtime·mach_semaphore_wait(SB),NOSPLIT,$0
 	MOVL	sema+0(FP), DI
 	MOVL	$(0x1000000+36), AX	// semaphore_wait_trap
@@ -412,7 +407,7 @@ TEXT runtime·mach_semaphore_wait(SB),NOSPLIT,$0
 	MOVL	AX, ret+8(FP)
 	RET
 
-// uint32 mach_semaphore_timedwait(uint32, uint32, uint32)
+// func mach_semaphore_timedwait(sema, sec, nsec uint32) int32
 TEXT runtime·mach_semaphore_timedwait(SB),NOSPLIT,$0
 	MOVL	sema+0(FP), DI
 	MOVL	sec+4(FP), SI
@@ -422,7 +417,7 @@ TEXT runtime·mach_semaphore_timedwait(SB),NOSPLIT,$0
 	MOVL	AX, ret+16(FP)
 	RET
 
-// uint32 mach_semaphore_signal(uint32)
+// func mach_semaphore_signal(sema uint32) int32
 TEXT runtime·mach_semaphore_signal(SB),NOSPLIT,$0
 	MOVL	sema+0(FP), DI
 	MOVL	$(0x1000000+33), AX	// semaphore_signal_trap
@@ -430,7 +425,7 @@ TEXT runtime·mach_semaphore_signal(SB),NOSPLIT,$0
 	MOVL	AX, ret+8(FP)
 	RET
 
-// uint32 mach_semaphore_signal_all(uint32)
+// func mach_semaphore_signal_all(sema uint32) int32
 TEXT runtime·mach_semaphore_signal_all(SB),NOSPLIT,$0
 	MOVL	sema+0(FP), DI
 	MOVL	$(0x1000000+34), AX	// semaphore_signal_all_trap
@@ -468,7 +463,7 @@ TEXT runtime·sysctl(SB),NOSPLIT,$0
 	MOVL	AX, ret+48(FP)
 	RET
 
-// int32 runtime·kqueue(void);
+// func kqueue() int32
 TEXT runtime·kqueue(SB),NOSPLIT,$0
 	MOVQ    $0, DI
 	MOVQ    $0, SI
@@ -480,13 +475,13 @@ TEXT runtime·kqueue(SB),NOSPLIT,$0
 	MOVL	AX, ret+0(FP)
 	RET
 
-// int32 runtime·kevent(int kq, Kevent *changelist, int nchanges, Kevent *eventlist, int nevents, Timespec *timeout);
+// func kevent(kq int32, ch *keventt, nch int32, ev *keventt, nev int32, ts *timespec) int32
 TEXT runtime·kevent(SB),NOSPLIT,$0
-	MOVL    fd+0(FP), DI
-	MOVQ    ev1+8(FP), SI
-	MOVL    nev1+16(FP), DX
-	MOVQ    ev2+24(FP), R10
-	MOVL    nev2+32(FP), R8
+	MOVL    kq+0(FP), DI
+	MOVQ    ch+8(FP), SI
+	MOVL    nch+16(FP), DX
+	MOVQ    ev+24(FP), R10
+	MOVL    nev+32(FP), R8
 	MOVQ    ts+40(FP), R9
 	MOVL	$(0x2000000+363), AX
 	SYSCALL
@@ -495,7 +490,7 @@ TEXT runtime·kevent(SB),NOSPLIT,$0
 	MOVL	AX, ret+48(FP)
 	RET
 
-// void runtime·closeonexec(int32 fd);
+// func closeonexec(fd int32)
 TEXT runtime·closeonexec(SB),NOSPLIT,$0
 	MOVL    fd+0(FP), DI  // fd
 	MOVQ    $2, SI  // F_SETFD
diff --git a/src/runtime/sys_darwin_arm.s b/src/runtime/sys_darwin_arm.s
new file mode 100644
index 0000000..087dec5
--- /dev/null
+++ b/src/runtime/sys_darwin_arm.s
@@ -0,0 +1,490 @@
+// 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 ARM, Darwin
+// See http://fxr.watson.org/fxr/source/bsd/kern/syscalls.c?v=xnu-1228
+// or /usr/include/sys/syscall.h (on a Mac) for system call numbers.
+
+#include "go_asm.h"
+#include "go_tls.h"
+#include "textflag.h"
+
+// Copied from /usr/include/sys/syscall.h
+#define	SYS_exit           1
+#define	SYS_read           3
+#define	SYS_write          4
+#define	SYS_open           5
+#define	SYS_close          6
+#define	SYS_mmap           197
+#define	SYS_munmap         73
+#define	SYS_madvise        75
+#define	SYS_mincore        78
+#define	SYS_gettimeofday   116
+#define	SYS_kill           37
+#define	SYS_getpid         20
+#define	SYS___pthread_kill 328
+#define	SYS_setitimer      83
+#define	SYS___sysctl       202
+#define	SYS_sigprocmask    48
+#define	SYS_sigaction      46
+#define	SYS_sigreturn      184
+#define	SYS_select         93
+#define	SYS_bsdthread_register 366
+#define	SYS_bsdthread_create 360
+#define	SYS_bsdthread_terminate 361
+#define	SYS_kqueue         362
+#define	SYS_kevent         363
+#define	SYS_fcntl          92
+
+TEXT notok<>(SB),NOSPLIT,$0
+	MOVW	$0, R8
+	MOVW	R8, (R8)
+	B		0(PC)
+
+TEXT runtime·open(SB),NOSPLIT,$0
+	MOVW	name+0(FP), R0
+	MOVW	mode+4(FP), R1
+	MOVW	perm+8(FP), R2
+	MOVW	$SYS_open, R12
+	SWI	$0x80
+	MOVW.CS	$-1, R0
+	MOVW	R0, ret+12(FP)
+	RET
+
+TEXT runtime·closefd(SB),NOSPLIT,$0
+	MOVW	fd+0(FP), R0
+	MOVW	$SYS_close, R12
+	SWI	$0x80
+	MOVW.CS	$-1, R0
+	MOVW	R0, ret+4(FP)
+	RET
+
+TEXT runtime·write(SB),NOSPLIT,$0
+	MOVW	fd+0(FP), R0
+	MOVW	p+4(FP), R1
+	MOVW	n+8(FP), R2
+	MOVW	$SYS_write, R12
+	SWI	$0x80
+	MOVW.CS	$-1, R0
+	MOVW	R0, ret+12(FP)
+	RET
+
+TEXT runtime·read(SB),NOSPLIT,$0
+	MOVW	fd+0(FP), R0
+	MOVW	p+4(FP), R1
+	MOVW	n+8(FP), R2
+	MOVW	$SYS_read, R12
+	SWI	$0x80
+	MOVW.CS	$-1, R0
+	MOVW	R0, ret+12(FP)
+	RET
+
+TEXT runtime·exit(SB),NOSPLIT,$-4
+	MOVW	code+0(FP), R0
+	MOVW	$SYS_exit, R12
+	SWI	$0x80
+	MOVW	$1234, R0
+	MOVW	$1002, R1
+	MOVW	R0, (R1)	// fail hard
+
+// Exit this OS thread (like pthread_exit, which eventually
+// calls __bsdthread_terminate).
+TEXT runtime·exit1(SB),NOSPLIT,$0
+	MOVW	$SYS_bsdthread_terminate, R12
+	SWI	$0x80
+	MOVW	$1234, R0
+	MOVW	$1003, R1
+	MOVW	R0, (R1)	// fail hard
+
+TEXT runtime·raise(SB),NOSPLIT,$0
+	// Ideally we'd send the signal to the current thread,
+	// not the whole process, but that's too hard on OS X.
+	JMP	runtime·raiseproc(SB)
+
+TEXT runtime·raiseproc(SB),NOSPLIT,$24
+	MOVW	$SYS_getpid, R12
+	SWI	$0x80
+	// arg 1 pid already in R0 from getpid
+	MOVW	unnamed+0(FP), R1	// arg 2 - signal
+	MOVW	$1, R2	// arg 3 - posix
+	MOVW	$SYS_kill, R12
+	SWI $0x80
+	RET
+
+TEXT runtime·mmap(SB),NOSPLIT,$0
+	MOVW	addr+0(FP), R0
+	MOVW	n+4(FP), R1
+	MOVW	prot+8(FP), R2
+	MOVW	flags+12(FP), R3
+	MOVW	fd+16(FP), R4
+	MOVW	off+20(FP), R5
+	MOVW	$0, R6 // off_t is uint64_t
+	MOVW	$SYS_mmap, R12
+	SWI	$0x80
+	MOVW	R0, ret+24(FP)
+	RET
+
+TEXT runtime·munmap(SB),NOSPLIT,$0
+	MOVW	addr+0(FP), R0
+	MOVW	n+4(FP), R1
+	MOVW	$SYS_munmap, R12
+	SWI	$0x80
+	BL.CS	notok<>(SB)
+	RET
+
+TEXT runtime·madvise(SB),NOSPLIT,$0
+	MOVW	addr+0(FP), R0
+	MOVW	n+4(FP), R1
+	MOVW	flags+8(FP), R2
+	MOVW	$SYS_madvise, R12
+	SWI	$0x80
+	BL.CS	notok<>(SB)
+	RET
+
+TEXT runtime·setitimer(SB),NOSPLIT,$0
+	MOVW	mode+0(FP), R0
+	MOVW	new+4(FP), R1
+	MOVW	old+8(FP), R2
+	MOVW	$SYS_setitimer, R12
+	SWI	$0x80
+	RET
+
+TEXT runtime·mincore(SB),NOSPLIT,$0
+	MOVW	addr+0(FP), R0
+	MOVW	n+4(FP), R1
+	MOVW	dst+8(FP), R2
+	MOVW	$SYS_mincore, R12
+	SWI	$0x80
+	MOVW	R0, ret+12(FP)
+	RET
+
+TEXT time·now(SB), 7, $32
+	MOVW	$8(R13), R0  // timeval
+	MOVW	$0, R1  // zone
+	MOVW	$SYS_gettimeofday, R12
+	SWI	$0x80 // Note: R0 is tv_sec, R1 is tv_usec
+
+	MOVW    R1, R2  // usec
+
+	MOVW	R0, sec+0(FP)
+	MOVW	$0, R1
+	MOVW	R1, loc+4(FP)
+	MOVW	$1000, R3
+	MUL	R3, R2
+	MOVW	R2, nsec+8(FP)
+	RET
+
+TEXT runtime·nanotime(SB),NOSPLIT,$32
+	MOVW	$8(R13), R0  // timeval
+	MOVW	$0, R1  // zone
+	MOVW	$SYS_gettimeofday, R12
+	SWI	$0x80 // Note: R0 is tv_sec, R1 is tv_usec
+
+	MOVW    R1, R2
+	MOVW	$1000000000, R3
+	MULLU	R0, R3, (R1, R0)
+	MOVW	$1000, R3
+	MOVW	$0, R4
+	MUL	R3, R2
+	ADD.S	R2, R0
+	ADC	R4, R1
+
+	MOVW	R0, ret_lo+0(FP)
+	MOVW	R1, ret_hi+4(FP)
+	RET
+
+// Sigtramp's job is to call the actual signal handler.
+// It is called with the following arguments on the stack:
+//	 LR  	"return address" - ignored
+//	 R0  	actual handler
+//	 R1  	siginfo style - ignored
+//	 R2   	signal number
+//	 R3   	siginfo
+//	 -4(FP)	context, beware that 0(FP) is the saved LR
+TEXT runtime·sigtramp(SB),NOSPLIT,$0
+	// this might be called in external code context,
+	// where g is not set.
+	// first save R0, because runtime·load_g will clobber it
+	MOVM.DB.W [R0], (R13)
+	MOVB	runtime·iscgo(SB), R0
+	CMP 	$0, R0
+	BL.NE	runtime·load_g(SB)
+
+	CMP 	$0, g
+	BNE 	cont
+	// fake function call stack frame for badsignal
+	// we only need to pass R2 (signal number), but
+	// badsignal will expect R2 at 4(R13), so we also
+	// push R1 onto stack. turns out we do need R1
+	// to do sigreturn.
+	MOVM.DB.W [R1,R2], (R13)
+	MOVW  	$runtime·badsignal(SB), R11
+	BL	(R11)
+	MOVM.IA.W [R1], (R13) // saved infostype
+	ADD		$(4+4), R13 // +4: also need to remove the pushed R0.
+	MOVW    ucontext-4(FP), R0 // load ucontext
+	B	ret
+
+cont:
+	// Restore R0
+	MOVM.IA.W (R13), [R0]
+
+	// NOTE: some Darwin/ARM kernels always use the main stack to run the
+	// signal handler. We need to switch to gsignal ourselves.
+	MOVW	g_m(g), R11
+	MOVW	m_gsignal(R11), R5
+	MOVW	(g_stack+stack_hi)(R5), R6
+	SUB		$28, R6
+
+	// copy arguments for call to sighandler
+	MOVW	R2, 4(R6) // signal num
+	MOVW	R3, 8(R6) // signal info
+	MOVW	g, 16(R6) // old_g
+	MOVW	context-4(FP), R4
+	MOVW	R4, 12(R6) // context
+
+	// Backup ucontext and infostyle
+	MOVW    R4, 20(R6)
+	MOVW    R1, 24(R6)
+
+	// switch stack and g
+	MOVW	R6, R13 // sigtramp can not re-entrant, so no need to back up R13.
+	MOVW	R5, g
+
+	BL	(R0)
+
+	// call sigreturn
+	MOVW	20(R13), R0	// saved ucontext
+	MOVW	24(R13), R1	// saved infostyle
+ret:
+	MOVW	$SYS_sigreturn, R12 // sigreturn(ucontext, infostyle)
+	SWI	$0x80
+
+	// if sigreturn fails, we can do nothing but exit
+	B	runtime·exit(SB)
+
+TEXT runtime·sigprocmask(SB),NOSPLIT,$0
+	MOVW	sig+0(FP), R0
+	MOVW	new+4(FP), R1
+	MOVW	old+8(FP), R2
+	MOVW	$SYS_sigprocmask, R12
+	SWI	$0x80
+	BL.CS	notok<>(SB)
+	RET
+
+TEXT runtime·sigaction(SB),NOSPLIT,$0
+	MOVW	mode+0(FP), R0
+	MOVW	new+4(FP), R1
+	MOVW	old+8(FP), R2
+	MOVW	$SYS_sigaction, R12
+	SWI	$0x80
+	RET
+
+TEXT runtime·usleep(SB),NOSPLIT,$12
+	MOVW	usec+0(FP), R0
+	CALL	runtime·usplitR0(SB)
+	MOVW	R0, a-12(SP)
+	MOVW	R1, b-8(SP)
+
+	// select(0, 0, 0, 0, &tv)
+	MOVW	$0, R0
+	MOVW	$0, R1
+	MOVW	$0, R2
+	MOVW	$0, R3
+	MOVW	$a-12(SP), R4
+	MOVW	$SYS_select, R12
+	SWI	$0x80
+	RET
+
+TEXT runtime·cas(SB),NOSPLIT,$0
+	B	runtime·armcas(SB)
+
+TEXT runtime·casp1(SB),NOSPLIT,$0
+	B	runtime·cas(SB)
+
+TEXT ·publicationBarrier(SB),NOSPLIT,$-4-0
+	B	runtime·armPublicationBarrier(SB)
+
+TEXT runtime·sysctl(SB),NOSPLIT,$0
+	MOVW	mib+0(FP), R0
+	MOVW	miblen+4(FP), R1
+	MOVW	out+8(FP), R2
+	MOVW	size+12(FP), R3
+	MOVW	dst+16(FP), R4
+	MOVW	ndst+20(FP), R5
+	MOVW	$SYS___sysctl, R12 // syscall entry
+	SWI	$0x80
+	BCC     sysctl_ret
+	RSB     $0, R0, R0
+	MOVW	R0, ret+24(FP)
+	RET
+sysctl_ret:
+	MOVW	$0, R0
+	MOVW	R0, ret+24(FP)
+	RET
+
+// Thread related functions
+// func bsdthread_create(stk, arg unsafe.Pointer, fn uintptr) int32
+TEXT runtime·bsdthread_create(SB),NOSPLIT,$0
+	// Set up arguments to bsdthread_create system call.
+	// The ones in quotes pass through to the thread callback
+	// uninterpreted, so we can put whatever we want there.
+	MOVW    fn+8(FP),    R0 // "func"
+	MOVW    arg+4(FP),   R1 // "arg"
+	MOVW    stk+0(FP),   R2 // stack
+	MOVW	$0x01000000, R4	// flags = PTHREAD_START_CUSTOM
+	MOVW	$0,          R5 // paranoia
+	MOVW	$SYS_bsdthread_create, R12
+	SWI	$0x80
+	BCC		create_ret
+	RSB 	$0, R0, R0
+	MOVW	R0, ret+12(FP)
+	RET
+create_ret:
+	MOVW	$0, R0
+	MOVW	R0, ret+12(FP)
+	RET
+
+// The thread that bsdthread_create creates starts executing here,
+// because we registered this function using bsdthread_register
+// at startup.
+//	R0 = "pthread"
+//	R1 = mach thread port
+//	R2 = "func" (= fn)
+//	R3 = "arg" (= m)
+//	R4 = stack
+//	R5 = flags (= 0)
+// XXX: how to deal with R4/SP? ref: Libc-594.9.1/arm/pthreads/thread_start.s
+TEXT runtime·bsdthread_start(SB),NOSPLIT,$0
+	MOVW    R1, m_procid(R3) // thread port is m->procid
+	MOVW	m_g0(R3), g
+	MOVW	R3, g_m(g)
+	// ARM don't have runtime·stackcheck(SB)
+	// disable runfast mode of vfp
+	EOR     R12, R12
+	WORD    $0xeee1ca10 // fmxr	fpscr, ip
+	BL      (R2) // fn
+	BL      runtime·exit1(SB)
+	RET
+
+// int32 bsdthread_register(void)
+// registers callbacks for threadstart (see bsdthread_create above
+// and wqthread and pthsize (not used).  returns 0 on success.
+TEXT runtime·bsdthread_register(SB),NOSPLIT,$0
+	MOVW	$runtime·bsdthread_start(SB), R0	// threadstart
+	MOVW	$0, R1	// wqthread, not used by us
+	MOVW	$0, R2	// pthsize, not used by us
+	MOVW	$0, R3 	// dummy_value [sic]
+	MOVW	$0, R4	// targetconc_ptr
+	MOVW	$0, R5	// dispatchqueue_offset
+	MOVW	$SYS_bsdthread_register, R12	// bsdthread_register
+	SWI	$0x80
+	MOVW	R0, ret+0(FP)
+	RET
+
+// uint32 mach_msg_trap(void*, uint32, uint32, uint32, uint32, uint32, uint32)
+TEXT runtime·mach_msg_trap(SB),NOSPLIT,$0
+	MOVW    h+0(FP), R0
+	MOVW    op+4(FP), R1
+	MOVW    send_size+8(FP), R2
+	MOVW    rcv_size+12(FP), R3
+	MOVW    rcv_name+16(FP), R4
+	MOVW    timeout+20(FP), R5
+	MOVW    notify+24(FP), R6
+	MVN     $30, R12
+	SWI	$0x80
+	MOVW	R0, ret+28(FP)
+	RET
+
+TEXT runtime·mach_task_self(SB),NOSPLIT,$0
+	MVN     $27, R12 // task_self_trap
+	SWI	$0x80
+	MOVW	R0, ret+0(FP)
+	RET
+
+TEXT runtime·mach_thread_self(SB),NOSPLIT,$0
+	MVN 	$26, R12 // thread_self_trap
+	SWI	$0x80
+	MOVW	R0, ret+0(FP)
+	RET
+
+TEXT runtime·mach_reply_port(SB),NOSPLIT,$0
+	MVN 	$25, R12	// mach_reply_port
+	SWI	$0x80
+	MOVW	R0, ret+0(FP)
+	RET
+
+// Mach provides trap versions of the semaphore ops,
+// instead of requiring the use of RPC.
+
+// uint32 mach_semaphore_wait(uint32)
+TEXT runtime·mach_semaphore_wait(SB),NOSPLIT,$0
+	MOVW	sema+0(FP), R0
+	MVN 	$35, R12	// semaphore_wait_trap
+	SWI	$0x80
+	MOVW	R0, ret+4(FP)
+	RET
+
+// uint32 mach_semaphore_timedwait(uint32, uint32, uint32)
+TEXT runtime·mach_semaphore_timedwait(SB),NOSPLIT,$0
+	MOVW	sema+0(FP), R0
+	MOVW	sec+4(FP), R1
+	MOVW	nsec+8(FP), R2
+	MVN 	$37, R12	// semaphore_timedwait_trap
+	SWI	$0x80
+	MOVW	R0, ret+12(FP)
+	RET
+
+// uint32 mach_semaphore_signal(uint32)
+TEXT runtime·mach_semaphore_signal(SB),NOSPLIT,$0
+	MOVW    sema+0(FP), R0
+	MVN 	$32, R12	// semaphore_signal_trap
+	SWI	$0x80
+	MOVW	R0, ret+4(FP)
+	RET
+
+// uint32 mach_semaphore_signal_all(uint32)
+TEXT runtime·mach_semaphore_signal_all(SB),NOSPLIT,$0
+	MOVW	sema+0(FP), R0
+	MVN 	$33, R12	// semaphore_signal_all_trap
+	SWI	$0x80
+	MOVW	R0, ret+4(FP)
+	RET
+
+// int32 runtime·kqueue(void)
+TEXT runtime·kqueue(SB),NOSPLIT,$0
+	MOVW	$SYS_kqueue, R12
+	SWI	$0x80
+	RSB.CS	$0, R0, R0
+	MOVW	R0, ret+0(FP)
+	RET
+
+// int32 runtime·kevent(int kq, Kevent *changelist, int nchanges, Kevent *eventlist, int events, Timespec *timeout)
+TEXT runtime·kevent(SB),NOSPLIT,$0
+	MOVW	$SYS_kevent, R12
+	MOVW	kq+0(FP), R0
+	MOVW	ch+4(FP), R1
+	MOVW	nch+8(FP), R2
+	MOVW	ev+12(FP), R3
+	MOVW	nev+16(FP), R4
+	MOVW	ts+20(FP), R5
+	SWI	$0x80
+	RSB.CS	$0, R0, R0
+	MOVW	R0, ret+24(FP)
+	RET
+
+// int32 runtime·closeonexec(int32 fd)
+TEXT runtime·closeonexec(SB),NOSPLIT,$0
+	MOVW	$SYS_fcntl, R12
+	MOVW	fd+0(FP), R0
+	MOVW	$2, R1	// F_SETFD
+	MOVW	$1, R2	// FD_CLOEXEC
+	SWI	$0x80
+	RET
+
+// sigaltstack on some darwin/arm version is buggy and will always
+// run the signal handler on the main stack, so our sigtramp has
+// to do the stack switch ourselves.
+TEXT runtime·sigaltstack(SB),NOSPLIT,$0
+	RET
diff --git a/src/runtime/sys_darwin_arm64.s b/src/runtime/sys_darwin_arm64.s
new file mode 100644
index 0000000..0f9da85
--- /dev/null
+++ b/src/runtime/sys_darwin_arm64.s
@@ -0,0 +1,455 @@
+// 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.
+
+// System calls and other sys.stuff for ARM64, Darwin
+// See http://fxr.watson.org/fxr/source/bsd/kern/syscalls.c?v=xnu-1228
+// or /usr/include/sys/syscall.h (on a Mac) for system call numbers.
+
+#include "go_asm.h"
+#include "go_tls.h"
+#include "textflag.h"
+
+// Copied from /usr/include/sys/syscall.h
+#define	SYS_exit           1
+#define	SYS_read           3
+#define	SYS_write          4
+#define	SYS_open           5
+#define	SYS_close          6
+#define	SYS_mmap           197
+#define	SYS_munmap         73
+#define	SYS_madvise        75
+#define	SYS_mincore        78
+#define	SYS_gettimeofday   116
+#define	SYS_kill           37
+#define	SYS_getpid         20
+#define	SYS___pthread_kill 328
+#define	SYS_setitimer      83
+#define	SYS___sysctl       202
+#define	SYS_sigprocmask    48
+#define	SYS_sigaction      46
+#define	SYS_sigreturn      184
+#define	SYS_select         93
+#define	SYS_bsdthread_register 366
+#define	SYS_bsdthread_create 360
+#define	SYS_bsdthread_terminate 361
+#define	SYS_kqueue         362
+#define	SYS_kevent         363
+#define	SYS_fcntl          92
+
+TEXT notok<>(SB),NOSPLIT,$0
+	MOVD	$0, R8
+	MOVD	R8, (R8)
+	B	0(PC)
+
+TEXT runtime·open(SB),NOSPLIT,$0
+	MOVD	name+0(FP), R0
+	MOVW	mode+8(FP), R1
+	MOVW	perm+12(FP), R2
+	MOVD	$SYS_open, R16
+	SVC	$0x80
+	CSINV	LO, R0, ZR, R0
+	MOVW	R0, ret+16(FP)
+	RET
+
+TEXT runtime·closefd(SB),NOSPLIT,$0
+	MOVW	fd+0(FP), R0
+	MOVW	$SYS_close, R16
+	SVC	$0x80
+	CSINV	LO, R0, ZR, R0
+	MOVW	R0, ret+8(FP)
+	RET
+
+TEXT runtime·write(SB),NOSPLIT,$0
+	MOVW	fd+0(FP), R0
+	MOVD	p+8(FP), R1
+	MOVW	n+16(FP), R2
+	MOVW	$SYS_write, R16
+	SVC	$0x80
+	CSINV	LO, R0, ZR, R0
+	MOVW	R0, ret+24(FP)
+	RET
+
+TEXT runtime·read(SB),NOSPLIT,$0
+	MOVW	fd+0(FP), R0
+	MOVD	p+8(FP), R1
+	MOVW	n+16(FP), R2
+	MOVW	$SYS_read, R16
+	SVC	$0x80
+	CSINV	LO, R0, ZR, R0
+	MOVW	R0, ret+24(FP)
+	RET
+
+TEXT runtime·exit(SB),NOSPLIT,$-8
+	MOVW	code+0(FP), R0
+	MOVW	$SYS_exit, R16
+	SVC	$0x80
+	MOVD	$1234, R0
+	MOVD	$1002, R1
+	MOVD	R0, (R1)	// fail hard
+
+// Exit this OS thread (like pthread_exit, which eventually
+// calls __bsdthread_terminate).
+TEXT runtime·exit1(SB),NOSPLIT,$0
+	MOVW	$SYS_bsdthread_terminate, R16
+	SVC	$0x80
+	MOVD	$1234, R0
+	MOVD	$1003, R1
+	MOVD	R0, (R1)	// fail hard
+
+TEXT runtime·raise(SB),NOSPLIT,$0
+	// Ideally we'd send the signal to the current thread,
+	// not the whole process, but that's too hard on OS X.
+	JMP	runtime·raiseproc(SB)
+
+TEXT runtime·raiseproc(SB),NOSPLIT,$0
+	MOVW	$SYS_getpid, R16
+	SVC	$0x80
+	// arg 1 pid already in R0 from getpid
+	MOVW	sig+0(FP), R1	// arg 2 - signal
+	MOVW	$1, R2	// arg 3 - posix
+	MOVW	$SYS_kill, R16
+	SVC	$0x80
+	RET
+
+TEXT runtime·mmap(SB),NOSPLIT,$0
+	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
+	MOVW	$SYS_mmap, R16
+	SVC	$0x80
+	MOVD	R0, ret+32(FP)
+	RET
+
+TEXT runtime·munmap(SB),NOSPLIT,$0
+	MOVD	addr+0(FP), R0
+	MOVD	n+8(FP), R1
+	MOVW	$SYS_munmap, R16
+	SVC	$0x80
+	BCC	2(PC)
+	BL	notok<>(SB)
+	RET
+
+TEXT runtime·madvise(SB),NOSPLIT,$0
+	MOVD	addr+0(FP), R0
+	MOVD	n+8(FP), R1
+	MOVW	flags+16(FP), R2
+	MOVW	$SYS_madvise, R16
+	SVC	$0x80
+	BCC	2(PC)
+	BL	notok<>(SB)
+	RET
+
+TEXT runtime·setitimer(SB),NOSPLIT,$0
+	MOVW	mode+0(FP), R0
+	MOVD	new+8(FP), R1
+	MOVD	old+16(FP), R2
+	MOVW	$SYS_setitimer, R16
+	SVC	$0x80
+	RET
+
+TEXT time·now(SB),NOSPLIT,$40-12
+	MOVD	RSP, R0	// timeval
+	MOVD	R0, R9	// this is how dyld calls gettimeofday
+	MOVW	$0, R1	// zone
+	MOVW	$SYS_gettimeofday, R16
+	SVC	$0x80	// Note: x0 is tv_sec, w1 is tv_usec
+
+	MOVD	R0, sec+0(FP)
+	MOVW	$1000, R3
+	MUL	R3, R1
+	MOVW	R1, nsec+8(FP)
+	RET
+
+TEXT runtime·nanotime(SB),NOSPLIT,$40
+	MOVD	RSP, R0	// timeval
+	MOVD	R0, R9	// this is how dyld calls gettimeofday
+	MOVW	$0, R1	// zone
+	MOVW	$SYS_gettimeofday, R16
+	SVC	$0x80	// Note: x0 is tv_sec, w1 is tv_usec
+
+	MOVW	$1000000000, R3
+	MUL	R3, R0
+	MOVW	$1000, R3
+	MUL	R3, R1
+	ADD	R1, R0
+
+	MOVD	R0, ret+0(FP)
+	RET
+
+// Sigtramp's job is to call the actual signal handler.
+// It is called with the following arguments on the stack:
+//	LR	"return address" - ignored
+//	R0	actual handler
+//	R1	siginfo style - ignored
+//	R2	signal number
+//	R3	siginfo
+//	R4	context
+TEXT runtime·sigtramp(SB),NOSPLIT,$0
+	// this might be called in external code context,
+	// where g is not set.
+	// first save R0, because runtime·load_g will clobber it
+	MOVD.W	R0, -16(RSP)	// note: stack must be 16-byte aligned
+	MOVB	runtime·iscgo(SB), R0
+	CMP	$0, R0
+	BEQ	2(PC)
+	BL	runtime·load_g(SB)
+
+	CMP	$0, g
+	BNE	cont
+	// fake function call stack frame for badsignal
+	// we only need to pass R2 (signal number), but
+	// badsignal will expect R2 at 8(RSP), so we also
+	// push R1 onto stack. turns out we do need R1
+	// to do sigreturn.
+	MOVD.W	R1, -16(RSP)
+	MOVD	R2, 8(RSP)
+	MOVD	R4, 24(RSP)	// save ucontext, badsignal might clobber R4
+	MOVD	$runtime·badsignal(SB), R26
+	BL	(R26)
+	MOVD	0(RSP), R1	// saved infostype
+	MOVD	24(RSP), R0	// the ucontext
+	ADD	$(16+16), RSP
+	B	ret
+
+cont:
+	// Restore R0
+	MOVD.P	16(RSP), R0
+
+	// NOTE: some Darwin/ARM kernels always use the main stack to run the
+	// signal handler. We need to switch to gsignal ourselves.
+	MOVD	g_m(g), R11
+	MOVD	m_gsignal(R11), R5
+	MOVD	(g_stack+stack_hi)(R5), R6
+	SUB	$64, R6
+
+	// copy arguments for call to sighandler
+	MOVD	R2, 8(R6)	// signal num
+	MOVD	R3, 16(R6)	// signal info
+	MOVD	R4, 24(R6)	// context
+	MOVD	g, 32(R6)	// old_g
+
+	// Backup ucontext and infostyle
+	MOVD	R4, 40(R6)
+	MOVD	R1, 48(R6)
+
+	// switch stack and g
+	MOVD	R6, RSP	// sigtramp can not re-entrant, so no need to back up RSP.
+	MOVD	R5, g
+
+	BL	(R0)
+
+	// call sigreturn
+	MOVD	40(RSP), R0	// saved ucontext
+	MOVD	48(RSP), R1	// saved infostyle
+ret:
+	MOVW	$SYS_sigreturn, R16 // sigreturn(ucontext, infostyle)
+	SVC	$0x80
+
+	// if sigreturn fails, we can do nothing but exit
+	B	runtime·exit(SB)
+
+TEXT runtime·sigprocmask(SB),NOSPLIT,$0
+	MOVW	sig+0(FP), R0
+	MOVD	new+8(FP), R1
+	MOVD	old+16(FP), R2
+	MOVW	$SYS_sigprocmask, R16
+	SVC	$0x80
+	BCC	2(PC)
+	BL	notok<>(SB)
+	RET
+
+TEXT runtime·sigaction(SB),NOSPLIT,$0
+	MOVW	mode+0(FP), R0
+	MOVD	new+8(FP), R1
+	MOVD	old+16(FP), R2
+	MOVW	$SYS_sigaction, R16
+	SVC	$0x80
+	BCC	2(PC)
+	BL	notok<>(SB)
+	RET
+
+TEXT runtime·usleep(SB),NOSPLIT,$24
+	MOVW	usec+0(FP), R0
+	MOVW	R0, R1
+	MOVW	$1000000, R2
+	UDIV	R2, R0
+	MUL	R0, R2
+	SUB	R2, R1
+	MOVD	R0, 0(RSP)
+	MOVW	R1, 8(RSP)
+
+	// select(0, 0, 0, 0, &tv)
+	MOVW	$0, R0
+	MOVW	$0, R1
+	MOVW	$0, R2
+	MOVW	$0, R3
+	MOVD	RSP, R4
+	MOVW	$SYS_select, R16
+	SVC	$0x80
+	RET
+
+TEXT runtime·sysctl(SB),NOSPLIT,$0
+	MOVD	mib+0(FP), R0
+	MOVW	miblen+8(FP), R1
+	MOVD	out+16(FP), R2
+	MOVD	size+24(FP), R3
+	MOVD	dst+32(FP), R4
+	MOVD	ndst+40(FP), R5
+	MOVW	$SYS___sysctl, R16
+	SVC	$0x80
+	BCC	ok
+	NEG	R0, R0
+	MOVW	R0, ret+48(FP)
+	RET
+ok:
+	MOVW	$0, R0
+	MOVW	R0, ret+48(FP)
+	RET
+
+// Thread related functions
+// Note: On darwin/arm64, it is no longer possible to use bsdthread_register
+// as the libc is always linked in. The runtime must use runtime/cgo to
+// create threads, so all thread related functions will just exit with a
+// unique status.
+// void bsdthread_create(void *stk, M *m, G *g, void (*fn)(void))
+TEXT runtime·bsdthread_create(SB),NOSPLIT,$0
+	MOVD	$44, R0
+	MOVW	$SYS_exit, R16
+	SVC	$0x80
+	RET
+
+// The thread that bsdthread_create creates starts executing here,
+// because we registered this function using bsdthread_register
+// at startup.
+//	R0 = "pthread"
+//	R1 = mach thread port
+//	R2 = "func" (= fn)
+//	R3 = "arg" (= m)
+//	R4 = stack
+//	R5 = flags (= 0)
+TEXT runtime·bsdthread_start(SB),NOSPLIT,$0
+	MOVD	$45, R0
+	MOVW	$SYS_exit, R16
+	SVC	$0x80
+	RET
+
+// int32 bsdthread_register(void)
+// registers callbacks for threadstart (see bsdthread_create above
+// and wqthread and pthsize (not used).  returns 0 on success.
+TEXT runtime·bsdthread_register(SB),NOSPLIT,$0
+	MOVD	$46, R0
+	MOVW	$SYS_exit, R16
+	SVC	$0x80
+	RET
+
+// uint32 mach_msg_trap(void*, uint32, uint32, uint32, uint32, uint32, uint32)
+TEXT runtime·mach_msg_trap(SB),NOSPLIT,$0
+	MOVD	h+0(FP), R0
+	MOVW	op+8(FP), R1
+	MOVW	send_size+12(FP), R2
+	MOVW	rcv_size+16(FP), R3
+	MOVW	rcv_name+20(FP), R4
+	MOVW	timeout+24(FP), R5
+	MOVW	notify+28(FP), R6
+	MOVN	$30, R16
+	SVC	$0x80
+	MOVW	R0, ret+32(FP)
+	RET
+
+TEXT runtime·mach_task_self(SB),NOSPLIT,$0
+	MOVN	$27, R16 // task_self_trap
+	SVC	$0x80
+	MOVW	R0, ret+0(FP)
+	RET
+
+TEXT runtime·mach_thread_self(SB),NOSPLIT,$0
+	MOVN	$26, R16 // thread_self_trap
+	SVC	$0x80
+	MOVW	R0, ret+0(FP)
+	RET
+
+TEXT runtime·mach_reply_port(SB),NOSPLIT,$0
+	MOVN	$25, R16	// mach_reply_port
+	SVC	$0x80
+	MOVW	R0, ret+0(FP)
+	RET
+
+// Mach provides trap versions of the semaphore ops,
+// instead of requiring the use of RPC.
+
+// uint32 mach_semaphore_wait(uint32)
+TEXT runtime·mach_semaphore_wait(SB),NOSPLIT,$0
+	MOVW	sema+0(FP), R0
+	MOVN	$35, R16	// semaphore_wait_trap
+	SVC	$0x80
+	MOVW	R0, ret+8(FP)
+	RET
+
+// uint32 mach_semaphore_timedwait(uint32, uint32, uint32)
+TEXT runtime·mach_semaphore_timedwait(SB),NOSPLIT,$0
+	MOVW	sema+0(FP), R0
+	MOVW	sec+4(FP), R1
+	MOVW	nsec+8(FP), R2
+	MOVN	$37, R16	// semaphore_timedwait_trap
+	SVC	$0x80
+	MOVW	R0, ret+16(FP)
+	RET
+
+// uint32 mach_semaphore_signal(uint32)
+TEXT runtime·mach_semaphore_signal(SB),NOSPLIT,$0
+	MOVW	sema+0(FP), R0
+	MOVN	$32, R16	// semaphore_signal_trap
+	SVC	$0x80
+	MOVW	R0, ret+8(FP)
+	RET
+
+// uint32 mach_semaphore_signal_all(uint32)
+TEXT runtime·mach_semaphore_signal_all(SB),NOSPLIT,$0
+	MOVW	sema+0(FP), R0
+	MOVN	$33, R16	// semaphore_signal_all_trap
+	SVC	$0x80
+	MOVW	R0, ret+8(FP)
+	RET
+
+// int32 runtime·kqueue(void)
+TEXT runtime·kqueue(SB),NOSPLIT,$0
+	MOVW	$SYS_kqueue, R16
+	SVC	$0x80
+	BCC	2(PC)
+	NEG	R0, R0
+	MOVW	R0, ret+0(FP)
+	RET
+
+// int32 runtime·kevent(int kq, Kevent *ch, int nch, Kevent *ev, int nev, Timespec *ts)
+TEXT runtime·kevent(SB),NOSPLIT,$0
+	MOVW	kq+0(FP), R0
+	MOVD	ch+8(FP), R1
+	MOVW	nch+16(FP), R2
+	MOVD	ev+24(FP), R3
+	MOVW	nev+32(FP), R4
+	MOVD	ts+40(FP), R5
+	MOVW	$SYS_kevent, R16
+	SVC	$0x80
+	BCC	2(PC)
+	NEG	R0, R0
+	MOVW	R0, ret+48(FP)
+	RET
+
+// int32 runtime·closeonexec(int32 fd)
+TEXT runtime·closeonexec(SB),NOSPLIT,$0
+	MOVW	fd+0(FP), R0
+	MOVW	$2, R1	// F_SETFD
+	MOVW	$1, R2	// FD_CLOEXEC
+	MOVW	$SYS_fcntl, R16
+	SVC	$0x80
+	RET
+
+// sigaltstack on some darwin/arm version is buggy and will always
+// run the signal handler on the main stack, so our sigtramp has
+// to do the stack switch ourselves.
+TEXT runtime·sigaltstack(SB),NOSPLIT,$0
+	RET
diff --git a/src/runtime/sys_dragonfly_386.s b/src/runtime/sys_dragonfly_386.s
deleted file mode 100644
index 161eaec..0000000
--- a/src/runtime/sys_dragonfly_386.s
+++ /dev/null
@@ -1,381 +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 "zasm_GOOS_GOARCH.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 	sigtramp_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)
-
-sigtramp_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 2c75601..26c9784 100644
--- a/src/runtime/sys_dragonfly_amd64.s
+++ b/src/runtime/sys_dragonfly_amd64.s
@@ -6,7 +6,8 @@
 // /usr/src/sys/kern/syscalls.master for syscall numbers.
 //
 
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
 #include "textflag.h"
 	
 TEXT runtime·sys_umtx_sleep(SB),NOSPLIT,$0
@@ -76,13 +77,17 @@ TEXT runtime·open(SB),NOSPLIT,$-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
 
-TEXT runtime·close(SB),NOSPLIT,$-8
+TEXT runtime·closefd(SB),NOSPLIT,$-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
 
@@ -92,6 +97,8 @@ TEXT runtime·read(SB),NOSPLIT,$-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
 
@@ -101,6 +108,8 @@ TEXT runtime·write(SB),NOSPLIT,$-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
 
@@ -116,12 +125,21 @@ TEXT runtime·raise(SB),NOSPLIT,$16
 	MOVL	$496, AX	// lwp_gettid
 	SYSCALL
 	MOVQ	$-1, DI		// arg 1 - pid
-	MOVQ	8(SP), DI	// arg 2 - tid
-	MOVL	sig+0(FP), SI	// arg 3 - signum
+	MOVQ	AX, SI		// arg 2 - tid
+	MOVL	sig+0(FP), DX	// arg 3 - signum
 	MOVL	$497, AX	// lwp_kill
 	SYSCALL
 	RET
 
+TEXT runtime·raiseproc(SB),NOSPLIT,$0
+	MOVL	$20, AX		// getpid
+	SYSCALL
+	MOVQ	AX, DI		// arg 1 - pid
+	MOVL	sig+0(FP), SI	// arg 2 - signum
+	MOVL	$37, AX		// kill
+	SYSCALL
+	RET
+
 TEXT runtime·setitimer(SB), NOSPLIT, $-8
 	MOVL	mode+0(FP), DI
 	MOVQ	new+8(FP), SI
@@ -185,9 +203,9 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$64
 	MOVQ	R10, 40(SP)
 	
 	// g = m->signal
-	MOVQ	g_m(R10), BP
-	MOVQ	m_gsignal(BP), BP
-	MOVQ	BP, g(BX)
+	MOVQ	g_m(R10), AX
+	MOVQ	m_gsignal(AX), AX
+	MOVQ	AX, g(BX)
 	
 	MOVQ	DI, 0(SP)
 	MOVQ	SI, 8(SP)
@@ -263,7 +281,7 @@ TEXT runtime·usleep(SB),NOSPLIT,$16
 
 // 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
@@ -298,9 +316,9 @@ TEXT runtime·osyield(SB),NOSPLIT,$-4
 	RET
 
 TEXT runtime·sigprocmask(SB),NOSPLIT,$0
-	MOVL	$3, DI			// arg 1 - how (SIG_SETMASK)
-	MOVQ	new+0(FP), SI		// arg 2 - set
-	MOVQ	old+8(FP), DX		// arg 3 - oset
+	MOVL	how+0(FP), DI		// arg 1 - how
+	MOVQ	new+8(FP), SI		// arg 2 - set
+	MOVQ	old+16(FP), DX		// arg 3 - oset
 	MOVL	$340, AX		// sys_sigprocmask
 	SYSCALL
 	JAE	2(PC)
diff --git a/src/runtime/sys_freebsd_386.s b/src/runtime/sys_freebsd_386.s
index 2c40fc4..b2dd780 100644
--- a/src/runtime/sys_freebsd_386.s
+++ b/src/runtime/sys_freebsd_386.s
@@ -6,7 +6,8 @@
 // /usr/src/sys/kern/syscalls.master for syscall numbers.
 //
 
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
 #include "textflag.h"
 	
 TEXT runtime·sys_umtx_op(SB),NOSPLIT,$-4
@@ -61,24 +62,32 @@ TEXT runtime·exit1(SB),NOSPLIT,$-4
 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
+TEXT runtime·closefd(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
 
@@ -103,6 +112,18 @@ TEXT runtime·raise(SB),NOSPLIT,$16
 	INT	$0x80
 	RET
 
+TEXT runtime·raiseproc(SB),NOSPLIT,$16
+	// getpid
+	MOVL	$20, AX
+	INT	$0x80
+	// kill(self, sig)
+	MOVL	AX, 4(SP)
+	MOVL	sig+0(FP), AX
+	MOVL	AX, 8(SP)
+	MOVL	$37, AX
+	INT	$0x80
+	RET
+
 TEXT runtime·mmap(SB),NOSPLIT,$32
 	LEAL addr+0(FP), SI
 	LEAL	4(SP), DI
@@ -197,7 +218,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$44
 	MOVL	BX, 0(SP)
 	MOVL	$runtime·badsignal(SB), AX
 	CALL	AX
-	JMP 	sigtramp_ret
+	JMP 	ret
 
 	// save g
 	MOVL	DI, 20(SP)
@@ -223,7 +244,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$44
 	MOVL	20(SP), BX
 	MOVL	BX, g(CX)
 
-sigtramp_ret:
+ret:
 	// call sigreturn
 	MOVL	context+8(FP), AX
 	MOVL	$0, 0(SP)	// syscall gap
@@ -278,7 +299,7 @@ int i386_set_ldt(int, const union ldt_entry *, int);
 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
@@ -346,10 +367,11 @@ TEXT runtime·osyield(SB),NOSPLIT,$-4
 
 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	how+0(FP), AX		// arg 1 - how
+	MOVL	AX, 4(SP)
+	MOVL	new+4(FP), AX
 	MOVL	AX, 8(SP)		// arg 2 - set
-	MOVL	old+4(FP), AX
+	MOVL	old+8(FP), AX
 	MOVL	AX, 12(SP)		// arg 3 - oset
 	MOVL	$340, AX		// sys_sigprocmask
 	INT	$0x80
diff --git a/src/runtime/sys_freebsd_amd64.s b/src/runtime/sys_freebsd_amd64.s
index 65f8c1a..b1c67c7 100644
--- a/src/runtime/sys_freebsd_amd64.s
+++ b/src/runtime/sys_freebsd_amd64.s
@@ -6,34 +6,10 @@
 // /usr/src/sys/kern/syscalls.master for syscall numbers.
 //
 
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
 #include "textflag.h"
 
-// FreeBSD 8, FreeBSD 9, and older versions that I have checked
-// do not restore R10 on exit from a "restarted" system call
-// if you use the SYSCALL instruction. This means that, for example,
-// if a signal arrives while the wait4 system call is executing,
-// the wait4 internally returns ERESTART, which makes the kernel
-// back up the PC to execute the SYSCALL instruction a second time.
-// However, since the kernel does not restore R10, the fourth
-// argument to the system call has been lost. (FreeBSD 9 also fails
-// to restore the fifth and sixth arguments, R8 and R9, although
-// some earlier versions did restore those correctly.)
-// The broken code is in fast_syscall in FreeBSD's amd64/amd64/exception.S.
-// It restores only DI, SI, DX, AX, and RFLAGS on system call return.
-// http://fxr.watson.org/fxr/source/amd64/amd64/exception.S?v=FREEBSD91#L399
-//
-// The INT $0x80 system call path (int0x80_syscall in FreeBSD's 
-// amd64/ia32/ia32_exception.S) does not have this problem,
-// but it expects the third argument in R10. Instead of rewriting
-// all the assembly in this file, #define SYSCALL to a safe simulation
-// using INT $0x80.
-//
-// INT $0x80 is a little slower than SYSCALL, but correctness wins.
-//
-// See golang.org/issue/6372.
-#define SYSCALL MOVQ R10, CX; INT $0x80
-	
 TEXT runtime·sys_umtx_op(SB),NOSPLIT,$0
 	MOVQ addr+0(FP), DI
 	MOVL mode+8(FP), SI
@@ -91,13 +67,17 @@ TEXT runtime·open(SB),NOSPLIT,$-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
 
-TEXT runtime·close(SB),NOSPLIT,$-8
+TEXT runtime·closefd(SB),NOSPLIT,$-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 +87,8 @@ TEXT runtime·read(SB),NOSPLIT,$-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 +98,8 @@ TEXT runtime·write(SB),NOSPLIT,$-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
 
@@ -139,6 +123,17 @@ TEXT runtime·raise(SB),NOSPLIT,$16
 	SYSCALL
 	RET
 
+TEXT runtime·raiseproc(SB),NOSPLIT,$0
+	// getpid
+	MOVL	$20, AX
+	SYSCALL
+	// kill(self, sig)
+	MOVQ	AX, DI		// arg 1 pid
+	MOVL	sig+0(FP), SI	// arg 2 sig
+	MOVL	$37, AX
+	SYSCALL
+	RET
+
 TEXT runtime·setitimer(SB), NOSPLIT, $-8
 	MOVL	mode+0(FP), DI
 	MOVQ	new+8(FP), SI
@@ -204,9 +199,9 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$64
 	MOVQ	R10, 40(SP)
 	
 	// g = m->signal
-	MOVQ	g_m(R10), BP
-	MOVQ	m_gsignal(BP), BP
-	MOVQ	BP, g(BX)
+	MOVQ	g_m(R10), AX
+	MOVQ	m_gsignal(AX), AX
+	MOVQ	AX, g(BX)
 	
 	MOVQ	DI, 0(SP)
 	MOVQ	SI, 8(SP)
@@ -278,7 +273,7 @@ TEXT runtime·usleep(SB),NOSPLIT,$16
 
 // 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
@@ -311,9 +306,9 @@ TEXT runtime·osyield(SB),NOSPLIT,$-4
 	RET
 
 TEXT runtime·sigprocmask(SB),NOSPLIT,$0
-	MOVL	$3, DI			// arg 1 - how (SIG_SETMASK)
-	MOVQ	new+0(FP), SI		// arg 2 - set
-	MOVQ	old+8(FP), DX		// arg 3 - oset
+	MOVL	how+0(FP), DI		// arg 1 - how
+	MOVQ	new+8(FP), SI		// arg 2 - set
+	MOVQ	old+16(FP), DX		// arg 3 - oset
 	MOVL	$340, AX		// sys_sigprocmask
 	SYSCALL
 	JAE	2(PC)
diff --git a/src/runtime/sys_freebsd_arm.s b/src/runtime/sys_freebsd_arm.s
index d875138..bd6ff96 100644
--- a/src/runtime/sys_freebsd_arm.s
+++ b/src/runtime/sys_freebsd_arm.s
@@ -6,7 +6,8 @@
 // /usr/src/sys/kern/syscalls.master for syscall numbers.
 //
 
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
 #include "textflag.h"
 
 // for EABI, as we don't support OABI
@@ -17,6 +18,8 @@
 #define SYS_write (SYS_BASE + 4)
 #define SYS_open (SYS_BASE + 5)
 #define SYS_close (SYS_BASE + 6)
+#define SYS_getpid (SYS_BASE + 20)
+#define SYS_kill (SYS_BASE + 37)
 #define SYS_sigaltstack (SYS_BASE + 53)
 #define SYS_munmap (SYS_BASE + 73)
 #define SYS_madvise (SYS_BASE + 75)
@@ -39,10 +42,10 @@
 #define SYS_mmap (SYS_BASE + 477) 
 	
 TEXT runtime·sys_umtx_op(SB),NOSPLIT,$0
-	MOVW 0(FP), R0
-	MOVW 4(FP), R1
-	MOVW 8(FP), R2
-	MOVW 12(FP), R3
+	MOVW addr+0(FP), R0
+	MOVW mode+4(FP), R1
+	MOVW val+8(FP), R2
+	MOVW ptr2+12(FP), R3
 	ADD $20, R13 // arg 5 is passed on stack
 	MOVW $SYS__umtx_op, R7
 	SWI $0
@@ -52,8 +55,8 @@ TEXT runtime·sys_umtx_op(SB),NOSPLIT,$0
 	RET
 
 TEXT runtime·thr_new(SB),NOSPLIT,$0
-	MOVW 0(FP), R0
-	MOVW 4(FP), R1
+	MOVW param+0(FP), R0
+	MOVW size+4(FP), R1
 	MOVW $SYS_thr_new, R7
 	SWI $0
 	RET
@@ -71,7 +74,7 @@ TEXT runtime·thr_start(SB),NOSPLIT,$0
 
 // Exit the entire program (like C exit)
 TEXT runtime·exit(SB),NOSPLIT,$-8
-	MOVW 0(FP), R0	// arg 1 exit status
+	MOVW code+0(FP), R0	// arg 1 exit status
 	MOVW $SYS_exit, R7
 	SWI $0
 	MOVW.CS $0, R8 // crash on syscall failure
@@ -79,7 +82,7 @@ TEXT runtime·exit(SB),NOSPLIT,$-8
 	RET
 
 TEXT runtime·exit1(SB),NOSPLIT,$-8
-	MOVW 0(FP), R0	// arg 1 exit status
+	MOVW code+0(FP), R0	// arg 1 exit status
 	MOVW $SYS_thr_exit, R7	
 	SWI $0
 	MOVW.CS $0, R8 // crash on syscall failure
@@ -87,42 +90,46 @@ TEXT runtime·exit1(SB),NOSPLIT,$-8
 	RET
 
 TEXT runtime·open(SB),NOSPLIT,$-8
-	MOVW 0(FP), R0	// arg 1 name
-	MOVW 4(FP), R1	// arg 2 mode
-	MOVW 8(FP), R2	// arg 3 perm
+	MOVW name+0(FP), R0	// arg 1 name
+	MOVW mode+4(FP), R1	// arg 2 mode
+	MOVW perm+8(FP), R2	// arg 3 perm
 	MOVW $SYS_open, R7
 	SWI $0
+	MOVW.CS	$-1, R0
 	MOVW	R0, ret+12(FP)
 	RET
 
 TEXT runtime·read(SB),NOSPLIT,$-8
-	MOVW 0(FP), R0	// arg 1 fd
-	MOVW 4(FP), R1	// arg 2 buf
-	MOVW 8(FP), R2	// arg 3 count
+	MOVW fd+0(FP), R0	// arg 1 fd
+	MOVW p+4(FP), R1	// arg 2 buf
+	MOVW n+8(FP), R2	// arg 3 count
 	MOVW $SYS_read, R7
 	SWI $0
+	MOVW.CS	$-1, R0
 	MOVW	R0, ret+12(FP)
 	RET
 
 TEXT runtime·write(SB),NOSPLIT,$-8
-	MOVW 0(FP), R0	// arg 1 fd
-	MOVW 4(FP), R1	// arg 2 buf
-	MOVW 8(FP), R2	// arg 3 count
+	MOVW fd+0(FP), R0	// arg 1 fd
+	MOVW p+4(FP), R1	// arg 2 buf
+	MOVW n+8(FP), R2	// arg 3 count
 	MOVW $SYS_write, R7
 	SWI $0
+	MOVW.CS	$-1, R0
 	MOVW	R0, ret+12(FP)
 	RET
 
-TEXT runtime·close(SB),NOSPLIT,$-8
-	MOVW 0(FP), R0	// arg 1 fd
+TEXT runtime·closefd(SB),NOSPLIT,$-8
+	MOVW fd+0(FP), R0	// arg 1 fd
 	MOVW $SYS_close, R7
 	SWI $0
+	MOVW.CS	$-1, R0
 	MOVW	R0, ret+4(FP)
 	RET
 
 TEXT runtime·getrlimit(SB),NOSPLIT,$-8
-	MOVW 0(FP), R0
-	MOVW 4(FP), R1
+	MOVW kind+0(FP), R0
+	MOVW limit+4(FP), R1
 	MOVW $SYS_getrlimit, R7
 	SWI $0
 	MOVW	R0, ret+8(FP)
@@ -140,10 +147,21 @@ TEXT runtime·raise(SB),NOSPLIT,$8
 	SWI $0
 	RET
 
+TEXT runtime·raiseproc(SB),NOSPLIT,$0
+	// getpid
+	MOVW $SYS_getpid, R7
+	SWI $0
+	// kill(self, sig)
+				// arg 1 - pid, now in R0
+	MOVW sig+0(FP), R1	// arg 2 - signal
+	MOVW $SYS_kill, R7
+	SWI $0
+	RET
+
 TEXT runtime·setitimer(SB), NOSPLIT, $-8
-	MOVW 0(FP), R0
-	MOVW 4(FP), R1
-	MOVW 8(FP), R2
+	MOVW mode+0(FP), R0
+	MOVW new+4(FP), R1
+	MOVW old+8(FP), R2
 	MOVW $SYS_setitimer, R7
 	SWI $0
 	RET
@@ -159,9 +177,9 @@ TEXT time·now(SB), NOSPLIT, $32
 	MOVW 12(R13), R1 // sec.high
 	MOVW 16(R13), R2 // nsec
 
-	MOVW R0, 0(FP)
-	MOVW R1, 4(FP)
-	MOVW R2, 8(FP)
+	MOVW R0, sec_lo+0(FP)
+	MOVW R1, sec_hi+4(FP)
+	MOVW R2, nsec+8(FP)
 	RET
 
 // int64 nanotime(void) so really
@@ -189,9 +207,9 @@ TEXT runtime·nanotime(SB), NOSPLIT, $32
 	RET
 
 TEXT runtime·sigaction(SB),NOSPLIT,$-8
-	MOVW 0(FP), R0		// arg 1 sig
-	MOVW 4(FP), R1		// arg 2 act
-	MOVW 8(FP), R2		// arg 3 oact
+	MOVW sig+0(FP), R0		// arg 1 sig
+	MOVW new+4(FP), R1		// arg 2 act
+	MOVW old+8(FP), R2		// arg 3 oact
 	MOVW $SYS_sigaction, R7
 	SWI $0
 	MOVW.CS $0, R8 // crash on syscall failure
@@ -234,15 +252,15 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$24
 	RET
 
 TEXT runtime·mmap(SB),NOSPLIT,$16
-	MOVW 0(FP), R0		// arg 1 addr
-	MOVW 4(FP), R1		// arg 2 len
-	MOVW 8(FP), R2		// arg 3 prot
-	MOVW 12(FP), R3		// arg 4 flags
+	MOVW addr+0(FP), R0		// arg 1 addr
+	MOVW n+4(FP), R1		// arg 2 len
+	MOVW prot+8(FP), R2		// arg 3 prot
+	MOVW flags+12(FP), R3		// arg 4 flags
 	// arg 5 (fid) and arg6 (offset_lo, offset_hi) are passed on stack
 	// note the C runtime only passes the 32-bit offset_lo to us
-	MOVW 16(FP), R4		// arg 5
+	MOVW fd+16(FP), R4		// arg 5
 	MOVW R4, 4(R13)
-	MOVW 20(FP), R5		// arg 6 lower 32-bit
+	MOVW off+20(FP), R5		// arg 6 lower 32-bit
 	// the word at 8(R13) is skipped due to 64-bit argument alignment.
 	MOVW R5, 12(R13)
 	MOVW $0, R6 		// higher 32-bit for arg 6
@@ -256,8 +274,8 @@ TEXT runtime·mmap(SB),NOSPLIT,$16
 	RET
 
 TEXT runtime·munmap(SB),NOSPLIT,$0
-	MOVW 0(FP), R0		// arg 1 addr
-	MOVW 4(FP), R1		// arg 2 len
+	MOVW addr+0(FP), R0		// arg 1 addr
+	MOVW n+4(FP), R1		// arg 2 len
 	MOVW $SYS_munmap, R7
 	SWI $0
 	MOVW.CS $0, R8 // crash on syscall failure
@@ -265,9 +283,9 @@ TEXT runtime·munmap(SB),NOSPLIT,$0
 	RET
 
 TEXT runtime·madvise(SB),NOSPLIT,$0
-	MOVW 0(FP), R0		// arg 1 addr
-	MOVW 4(FP), R1		// arg 2 len
-	MOVW 8(FP), R2		// arg 3 flags
+	MOVW addr+0(FP), R0		// arg 1 addr
+	MOVW n+4(FP), R1		// arg 2 len
+	MOVW flags+8(FP), R2		// arg 3 flags
 	MOVW $SYS_madvise, R7
 	SWI $0
 	// ignore failure - maybe pages are locked
@@ -284,15 +302,12 @@ TEXT runtime·sigaltstack(SB),NOSPLIT,$-8
 
 TEXT runtime·usleep(SB),NOSPLIT,$16
 	MOVW usec+0(FP), R0
-	MOVW R0, R2
-	MOVW $1000000, R1
-	DIV R1, R0
+	CALL runtime·usplitR0(SB)
 	// 0(R13) is the saved LR, don't use it
 	MOVW R0, 4(R13) // tv_sec.low
 	MOVW $0, R0
 	MOVW R0, 8(R13) // tv_sec.high
-	MOD R1, R2
-	MOVW $1000, R1
+	MOVW $1000, R2
 	MUL R1, R2
 	MOVW R2, 12(R13) // tv_nsec
 
@@ -303,10 +318,10 @@ TEXT runtime·usleep(SB),NOSPLIT,$16
 	RET
 
 TEXT runtime·sysctl(SB),NOSPLIT,$0
-	MOVW 0(FP), R0	// arg 1 - name
-	MOVW 4(FP), R1	// arg 2 - namelen
-	MOVW 8(FP), R2	// arg 3 - old
-	MOVW 12(FP), R3	// arg 4 - oldlenp
+	MOVW mib+0(FP), R0	// arg 1 - name
+	MOVW miblen+4(FP), R1	// arg 2 - namelen
+	MOVW out+8(FP), R2	// arg 3 - old
+	MOVW size+12(FP), R3	// arg 4 - oldlenp
 	// arg 5 (newp) and arg 6 (newlen) are passed on stack
 	ADD $20, R13
 	MOVW $SYS___sysctl, R7
@@ -322,9 +337,9 @@ TEXT runtime·osyield(SB),NOSPLIT,$-4
 	RET
 
 TEXT runtime·sigprocmask(SB),NOSPLIT,$0
-	MOVW $3, R0	// arg 1 - how (SIG_SETMASK)
-	MOVW 0(FP), R1	// arg 2 - set
-	MOVW 4(FP), R2	// arg 3 - oset
+	MOVW how+0(FP), R0	// arg 1 - how
+	MOVW new+4(FP), R1	// arg 2 - set
+	MOVW old+8(FP), R2	// arg 3 - oset
 	MOVW $SYS_sigprocmask, R7
 	SWI $0
 	MOVW.CS $0, R8 // crash on syscall failure
@@ -341,10 +356,10 @@ TEXT runtime·kqueue(SB),NOSPLIT,$0
 
 // int32 runtime·kevent(int kq, Kevent *changelist, int nchanges, Kevent *eventlist, int nevents, Timespec *timeout)
 TEXT runtime·kevent(SB),NOSPLIT,$0
-	MOVW 0(FP), R0	// kq
-	MOVW 4(FP), R1	// changelist
-	MOVW 8(FP), R2	// nchanges
-	MOVW 12(FP), R3	// eventlist
+	MOVW kq+0(FP), R0	// kq
+	MOVW ch+4(FP), R1	// changelist
+	MOVW nch+8(FP), R2	// nchanges
+	MOVW ev+12(FP), R3	// eventlist
 	ADD $20, R13	// pass arg 5 and 6 on stack
 	MOVW $SYS_kevent, R7
 	SWI $0
@@ -355,14 +370,14 @@ TEXT runtime·kevent(SB),NOSPLIT,$0
 
 // void runtime·closeonexec(int32 fd)
 TEXT runtime·closeonexec(SB),NOSPLIT,$0
-	MOVW 0(FP), R0	// fd
+	MOVW fd+0(FP), R0	// fd
 	MOVW $2, R1	// F_SETFD
 	MOVW $1, R2	// FD_CLOEXEC
 	MOVW $SYS_fcntl, R7
 	SWI $0
 	RET
 
-TEXT runtime·casp(SB),NOSPLIT,$0
+TEXT runtime·casp1(SB),NOSPLIT,$0
 	B	runtime·cas(SB)
 
 // TODO(minux): this is only valid for ARMv6+
@@ -376,6 +391,10 @@ TEXT runtime·casp(SB),NOSPLIT,$0
 TEXT runtime·cas(SB),NOSPLIT,$0
 	B runtime·armcas(SB)
 
+// TODO: this is only valid for ARMv7+
+TEXT ·publicationBarrier(SB),NOSPLIT,$-4-0
+	B	runtime·armPublicationBarrier(SB)
+
 // TODO(minux): this only supports ARMv6K+.
 TEXT runtime·read_tls_fallback(SB),NOSPLIT,$-4
 	WORD $0xee1d0f70 // mrc p15, 0, r0, c13, c0, 3
diff --git a/src/runtime/sys_linux_386.s b/src/runtime/sys_linux_386.s
index 0f6d4bb..98a1a0e 100644
--- a/src/runtime/sys_linux_386.s
+++ b/src/runtime/sys_linux_386.s
@@ -6,7 +6,8 @@
 // System calls and other sys.stuff for 386, Linux
 //
 
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
 #include "textflag.h"
 
 TEXT runtime·exit(SB),NOSPLIT,$0
@@ -29,13 +30,19 @@ TEXT runtime·open(SB),NOSPLIT,$0
 	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
 
-TEXT runtime·close(SB),NOSPLIT,$0
+TEXT runtime·closefd(SB),NOSPLIT,$0
 	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
 
@@ -45,6 +52,9 @@ TEXT runtime·write(SB),NOSPLIT,$0
 	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
 
@@ -54,6 +64,9 @@ TEXT runtime·read(SB),NOSPLIT,$0
 	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
 
@@ -83,6 +96,12 @@ TEXT runtime·usleep(SB),NOSPLIT,$8
 	CALL	*runtime·_vdso(SB)
 	RET
 
+TEXT runtime·gettid(SB),NOSPLIT,$0-4
+	MOVL	$224, AX	// syscall - gettid
+	CALL	*runtime·_vdso(SB)
+	MOVL	AX, ret+0(FP)
+	RET
+
 TEXT runtime·raise(SB),NOSPLIT,$12
 	MOVL	$224, AX	// syscall - gettid
 	CALL	*runtime·_vdso(SB)
@@ -92,6 +111,15 @@ TEXT runtime·raise(SB),NOSPLIT,$12
 	CALL	*runtime·_vdso(SB)
 	RET
 
+TEXT runtime·raiseproc(SB),NOSPLIT,$12
+	MOVL	$20, AX	// syscall - getpid
+	CALL	*runtime·_vdso(SB)
+	MOVL	AX, BX	// arg 1 pid
+	MOVL	sig+0(FP), CX	// arg 2 signal
+	MOVL	$37, AX	// syscall - kill
+	CALL	*runtime·_vdso(SB)
+	RET
+
 TEXT runtime·setitimer(SB),NOSPLIT,$0-12
 	MOVL	$104, AX			// syscall - setitimer
 	MOVL	mode+0(FP), BX
@@ -169,43 +197,25 @@ TEXT runtime·rt_sigaction(SB),NOSPLIT,$0
 	MOVL	AX, ret+16(FP)
 	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	sig+0(FP), BX
-	MOVL	BX, 0(SP)
-	MOVL	$runtime·badsignal(SB), AX
+TEXT runtime·sigfwd(SB),NOSPLIT,$12-16
+	MOVL	sig+4(FP), AX
+	MOVL	AX, 0(SP)
+	MOVL	info+8(FP), AX
+	MOVL	AX, 4(SP)
+	MOVL	ctx+12(FP), AX
+	MOVL	AX, 8(SP)
+	MOVL	fn+0(FP), AX
 	CALL	AX
 	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
+TEXT runtime·sigtramp(SB),NOSPLIT,$12
 	MOVL	sig+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)
-
+	CALL	runtime·sigtrampgo(SB)
 	RET
 
 TEXT runtime·sigreturn(SB),NOSPLIT,$0
@@ -269,18 +279,18 @@ TEXT runtime·futex(SB),NOSPLIT,$0
 // int32 clone(int32 flags, void *stack, M *mp, G *gp, void (*fn)(void));
 TEXT runtime·clone(SB),NOSPLIT,$0
 	MOVL	$120, AX	// clone
-	MOVL	flags+4(SP), BX
-	MOVL	stack+8(SP), CX
+	MOVL	flags+0(FP), BX
+	MOVL	stack+4(FP), CX
 	MOVL	$0, DX	// parent tid ptr
 	MOVL	$0, DI	// child tid ptr
 
 	// Copy mp, gp, fn off parent stack for use by child.
 	SUBL	$16, CX
-	MOVL	mm+12(SP), SI
+	MOVL	mm+8(FP), SI
 	MOVL	SI, 0(CX)
-	MOVL	gg+16(SP), SI
+	MOVL	gg+12(FP), SI
 	MOVL	SI, 4(CX)
-	MOVL	fn+20(SP), SI
+	MOVL	fn+16(FP), SI
 	MOVL	SI, 8(CX)
 	MOVL	$1234, 12(CX)
 
@@ -297,7 +307,7 @@ TEXT runtime·clone(SB),NOSPLIT,$0
 	RET
 
 	// Paranoia: check that SP is as we expect.
-	MOVL	mm+8(FP), BP
+	MOVL	12(SP), BP
 	CMPL	BP, $1234
 	JEQ	2(PC)
 	INT	$3
@@ -306,10 +316,14 @@ TEXT runtime·clone(SB),NOSPLIT,$0
 	MOVL	$224, AX
 	CALL	*runtime·_vdso(SB)
 
-	// In child on new stack.  Reload registers (paranoia).
-	MOVL	0(SP), BX	// m
-	MOVL	flags+0(FP), DX	// g
-	MOVL	stk+4(FP), SI	// fn
+	MOVL	0(SP), BX	    // m
+	MOVL	4(SP), DX	    // g
+	MOVL	8(SP), SI	    // fn
+
+	CMPL	BX, $0
+	JEQ	nog
+	CMPL	DX, $0
+	JEQ	nog
 
 	MOVL	AX, m_procid(BX)	// save tid as m->procid
 
@@ -343,6 +357,7 @@ TEXT runtime·clone(SB),NOSPLIT,$0
 	CALL	runtime·emptyfunc(SB)
 	POPAL
 
+nog:
 	CALL	SI	// fn()
 	CALL	runtime·exit1(SB)
 	MOVL	$0x1234, 0x1005
@@ -388,16 +403,16 @@ TEXT runtime·setldt(SB),NOSPLIT,$32
 	 * 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 33b91e8..59c21c5 100644
--- a/src/runtime/sys_linux_amd64.s
+++ b/src/runtime/sys_linux_amd64.s
@@ -6,7 +6,8 @@
 // System calls and other sys.stuff for AMD64, Linux
 //
 
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
 #include "textflag.h"
 
 TEXT runtime·exit(SB),NOSPLIT,$0-4
@@ -27,13 +28,19 @@ TEXT runtime·open(SB),NOSPLIT,$0-20
 	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
 
-TEXT runtime·close(SB),NOSPLIT,$0-12
+TEXT runtime·closefd(SB),NOSPLIT,$0-12
 	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
 
@@ -43,6 +50,9 @@ TEXT runtime·write(SB),NOSPLIT,$0-28
 	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
 
@@ -52,6 +62,9 @@ TEXT runtime·read(SB),NOSPLIT,$0-28
 	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
 
@@ -81,6 +94,12 @@ TEXT runtime·usleep(SB),NOSPLIT,$16
 	SYSCALL
 	RET
 
+TEXT runtime·gettid(SB),NOSPLIT,$0-4
+	MOVL	$186, AX	// syscall - gettid
+	SYSCALL
+	MOVL	AX, ret+0(FP)
+	RET
+
 TEXT runtime·raise(SB),NOSPLIT,$0
 	MOVL	$186, AX	// syscall - gettid
 	SYSCALL
@@ -90,6 +109,15 @@ TEXT runtime·raise(SB),NOSPLIT,$0
 	SYSCALL
 	RET
 
+TEXT runtime·raiseproc(SB),NOSPLIT,$0
+	MOVL	$39, AX	// syscall - getpid
+	SYSCALL
+	MOVL	AX, DI	// arg 1 pid
+	MOVL	sig+0(FP), SI	// arg 2
+	MOVL	$62, AX	// syscall - kill
+	SYSCALL
+	RET
+
 TEXT runtime·setitimer(SB),NOSPLIT,$0-24
 	MOVL	mode+0(FP), DI
 	MOVQ	new+8(FP), SI
@@ -115,7 +143,7 @@ TEXT time·now(SB),NOSPLIT,$16
 	// That leaves 104 for the gettime code to use. Hope that's enough!
 	MOVQ	runtime·__vdso_clock_gettime_sym(SB), AX
 	CMPQ	AX, $0
-	JEQ	fallback_gtod
+	JEQ	fallback
 	MOVL	$0, DI // CLOCK_REALTIME
 	LEAQ	0(SP), SI
 	CALL	AX
@@ -124,7 +152,7 @@ TEXT time·now(SB),NOSPLIT,$16
 	MOVQ	AX, sec+0(FP)
 	MOVL	DX, nsec+8(FP)
 	RET
-fallback_gtod:
+fallback:
 	LEAQ	0(SP), DI
 	MOVQ	$0, SI
 	MOVQ	runtime·__vdso_gettimeofday_sym(SB), AX
@@ -141,7 +169,7 @@ TEXT runtime·nanotime(SB),NOSPLIT,$16
 	// See comment above in time.now.
 	MOVQ	runtime·__vdso_clock_gettime_sym(SB), AX
 	CMPQ	AX, $0
-	JEQ	fallback_gtod_nt
+	JEQ	fallback
 	MOVL	$1, DI // CLOCK_MONOTONIC
 	LEAQ	0(SP), SI
 	CALL	AX
@@ -153,7 +181,7 @@ TEXT runtime·nanotime(SB),NOSPLIT,$16
 	ADDQ	DX, AX
 	MOVQ	AX, ret+0(FP)
 	RET
-fallback_gtod_nt:
+fallback:
 	LEAQ	0(SP), DI
 	MOVQ	$0, SI
 	MOVQ	runtime·__vdso_gettimeofday_sym(SB), AX
@@ -190,37 +218,20 @@ TEXT runtime·rt_sigaction(SB),NOSPLIT,$0-36
 	MOVL	AX, ret+32(FP)
 	RET
 
-TEXT runtime·sigtramp(SB),NOSPLIT,$64
-	get_tls(BX)
-
-	// check that g exists
-	MOVQ	g(BX), R10
-	CMPQ	R10, $0
-	JNE	5(PC)
-	MOVQ	DI, 0(SP)
-	MOVQ	$runtime·badsignal(SB), AX
+TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
+	MOVL	sig+8(FP), DI
+	MOVQ	info+16(FP), SI
+	MOVQ	ctx+24(FP), DX
+	MOVQ	fn+0(FP), AX
 	CALL	AX
 	RET
 
-	// save g
-	MOVQ	R10, 40(SP)
-
-	// g = m->gsignal
-	MOVQ	g_m(R10), BP
-	MOVQ	m_gsignal(BP), BP
-	MOVQ	BP, g(BX)
-
-	MOVQ	DI, 0(SP)
-	MOVQ	SI, 8(SP)
-	MOVQ	DX, 16(SP)
-	MOVQ	R10, 24(SP)
-
-	CALL	runtime·sighandler(SB)
-
-	// restore g
-	get_tls(BX)
-	MOVQ	40(SP), R10
-	MOVQ	R10, g(BX)
+TEXT runtime·sigtramp(SB),NOSPLIT,$24
+	MOVQ	DI, 0(SP)   // signum
+	MOVQ	SI, 8(SP)   // info
+	MOVQ	DX, 16(SP)  // ctx
+	MOVQ	$runtime·sigtrampgo(SB), AX
+	CALL AX
 	RET
 
 TEXT runtime·sigreturn(SB),NOSPLIT,$0
@@ -280,14 +291,16 @@ TEXT runtime·futex(SB),NOSPLIT,$0
 
 // int32 clone(int32 flags, void *stack, M *mp, G *gp, void (*fn)(void));
 TEXT runtime·clone(SB),NOSPLIT,$0
-	MOVL	flags+8(SP), DI
-	MOVQ	stack+16(SP), SI
+	MOVL	flags+0(FP), DI
+	MOVQ	stack+8(FP), SI
+	MOVQ	$0, DX
+	MOVQ	$0, R10
 
 	// Copy mp, gp, fn off parent stack for use by child.
 	// Careful: Linux system call clobbers CX and R11.
-	MOVQ	mm+24(SP), R8
-	MOVQ	gg+32(SP), R9
-	MOVQ	fn+40(SP), R12
+	MOVQ	mp+16(FP), R8
+	MOVQ	gp+24(FP), R9
+	MOVQ	fn+32(FP), R12
 
 	MOVL	$56, AX
 	SYSCALL
@@ -301,6 +314,12 @@ TEXT runtime·clone(SB),NOSPLIT,$0
 	// In child, on new stack.
 	MOVQ	SI, SP
 
+	// If g or m are nil, skip Go-related setup.
+	CMPQ	R8, $0    // m
+	JEQ	nog
+	CMPQ	R9, $0    // g
+	JEQ	nog
+
 	// Initialize m->procid to Linux tid
 	MOVL	$186, AX	// gettid
 	SYSCALL
@@ -316,10 +335,11 @@ TEXT runtime·clone(SB),NOSPLIT,$0
 	MOVQ	R9, g(CX)
 	CALL	runtime·stackcheck(SB)
 
+nog:
 	// Call fn
 	CALL	R12
 
-	// It shouldn't return.  If it does, exit
+	// It shouldn't return.  If it does, exit that thread.
 	MOVL	$111, DI
 	MOVL	$60, AX
 	SYSCALL
@@ -337,7 +357,7 @@ TEXT runtime·sigaltstack(SB),NOSPLIT,$-8
 
 // 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 bd285f3..29eb8eb 100644
--- a/src/runtime/sys_linux_arm.s
+++ b/src/runtime/sys_linux_arm.s
@@ -6,7 +6,8 @@
 // System calls and other sys.stuff for arm, Linux
 //
 
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
 #include "textflag.h"
 
 // for EABI, as we don't support OABI
@@ -17,6 +18,8 @@
 #define SYS_write (SYS_BASE + 4)
 #define SYS_open (SYS_BASE + 5)
 #define SYS_close (SYS_BASE + 6)
+#define SYS_getpid (SYS_BASE + 20)
+#define SYS_kill (SYS_BASE + 37)
 #define SYS_gettimeofday (SYS_BASE + 78)
 #define SYS_clone (SYS_BASE + 120)
 #define SYS_rt_sigreturn (SYS_BASE + 173)
@@ -42,53 +45,68 @@
 #define SYS_epoll_wait (SYS_BASE + 252)
 #define SYS_epoll_create1 (SYS_BASE + 357)
 #define SYS_fcntl (SYS_BASE + 55)
+#define SYS_access (SYS_BASE + 33)
+#define SYS_connect (SYS_BASE + 283)
+#define SYS_socket (SYS_BASE + 281)
 
 #define ARM_BASE (SYS_BASE + 0x0f0000)
 
 TEXT runtime·open(SB),NOSPLIT,$0
-	MOVW	0(FP), R0
-	MOVW	4(FP), R1
-	MOVW	8(FP), R2
+	MOVW	name+0(FP), R0
+	MOVW	mode+4(FP), R1
+	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
 
-TEXT runtime·close(SB),NOSPLIT,$0
-	MOVW	0(FP), R0
+TEXT runtime·closefd(SB),NOSPLIT,$0
+	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
 
 TEXT runtime·write(SB),NOSPLIT,$0
-	MOVW	0(FP), R0
-	MOVW	4(FP), R1
-	MOVW	8(FP), R2
+	MOVW	fd+0(FP), R0
+	MOVW	p+4(FP), R1
+	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
 
 TEXT runtime·read(SB),NOSPLIT,$0
-	MOVW	0(FP), R0
-	MOVW	4(FP), R1
-	MOVW	8(FP), R2
+	MOVW	fd+0(FP), R0
+	MOVW	p+4(FP), R1
+	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
 
 TEXT runtime·getrlimit(SB),NOSPLIT,$0
-	MOVW	0(FP), R0
-	MOVW	4(FP), R1
+	MOVW	kind+0(FP), R0
+	MOVW	limit+4(FP), R1
 	MOVW	$SYS_ugetrlimit, R7
 	SWI	$0
 	MOVW	R0, ret+8(FP)
 	RET
 
 TEXT runtime·exit(SB),NOSPLIT,$-4
-	MOVW	0(FP), R0
+	MOVW	code+0(FP), R0
 	MOVW	$SYS_exit_group, R7
 	SWI	$0
 	MOVW	$1234, R0
@@ -96,13 +114,19 @@ TEXT runtime·exit(SB),NOSPLIT,$-4
 	MOVW	R0, (R1)	// fail hard
 
 TEXT runtime·exit1(SB),NOSPLIT,$-4
-	MOVW	0(FP), R0
+	MOVW	code+0(FP), R0
 	MOVW	$SYS_exit, R7
 	SWI	$0
 	MOVW	$1234, R0
 	MOVW	$1003, R1
 	MOVW	R0, (R1)	// fail hard
 
+TEXT runtime·gettid(SB),NOSPLIT,$0-4
+	MOVW	$SYS_gettid, R7
+	SWI	$0
+	MOVW	R0, ret+0(FP)
+	RET
+
 TEXT	runtime·raise(SB),NOSPLIT,$-4
 	MOVW	$SYS_gettid, R7
 	SWI	$0
@@ -112,13 +136,22 @@ TEXT	runtime·raise(SB),NOSPLIT,$-4
 	SWI	$0
 	RET
 
+TEXT	runtime·raiseproc(SB),NOSPLIT,$-4
+	MOVW	$SYS_getpid, R7
+	SWI	$0
+	// arg 1 tid already in R0 from getpid
+	MOVW	sig+0(FP), R1	// arg 2 - signal
+	MOVW	$SYS_kill, R7
+	SWI	$0
+	RET
+
 TEXT runtime·mmap(SB),NOSPLIT,$0
-	MOVW	0(FP), R0
-	MOVW	4(FP), R1
-	MOVW	8(FP), R2
-	MOVW	12(FP), R3
-	MOVW	16(FP), R4
-	MOVW	20(FP), R5
+	MOVW	addr+0(FP), R0
+	MOVW	n+4(FP), R1
+	MOVW	prot+8(FP), R2
+	MOVW	flags+12(FP), R3
+	MOVW	fd+16(FP), R4
+	MOVW	off+20(FP), R5
 	MOVW	$SYS_mmap2, R7
 	SWI	$0
 	MOVW	$0xfffff001, R6
@@ -128,8 +161,8 @@ TEXT runtime·mmap(SB),NOSPLIT,$0
 	RET
 
 TEXT runtime·munmap(SB),NOSPLIT,$0
-	MOVW	0(FP), R0
-	MOVW	4(FP), R1
+	MOVW	addr+0(FP), R0
+	MOVW	n+4(FP), R1
 	MOVW	$SYS_munmap, R7
 	SWI	$0
 	MOVW	$0xfffff001, R6
@@ -139,26 +172,26 @@ TEXT runtime·munmap(SB),NOSPLIT,$0
 	RET
 
 TEXT runtime·madvise(SB),NOSPLIT,$0
-	MOVW	0(FP), R0
-	MOVW	4(FP), R1
-	MOVW	8(FP), R2
+	MOVW	addr+0(FP), R0
+	MOVW	n+4(FP), R1
+	MOVW	flags+8(FP), R2
 	MOVW	$SYS_madvise, R7
 	SWI	$0
 	// ignore failure - maybe pages are locked
 	RET
 
 TEXT runtime·setitimer(SB),NOSPLIT,$0
-	MOVW	0(FP), R0
-	MOVW	4(FP), R1
-	MOVW	8(FP), R2
+	MOVW	mode+0(FP), R0
+	MOVW	new+4(FP), R1
+	MOVW	old+8(FP), R2
 	MOVW	$SYS_setitimer, R7
 	SWI	$0
 	RET
 
 TEXT runtime·mincore(SB),NOSPLIT,$0
-	MOVW	0(FP), R0
-	MOVW	4(FP), R1
-	MOVW	8(FP), R2
+	MOVW	addr+0(FP), R0
+	MOVW	n+4(FP), R1
+	MOVW	dst+8(FP), R2
 	MOVW	$SYS_mincore, R7
 	SWI	$0
 	MOVW	R0, ret+12(FP)
@@ -173,10 +206,10 @@ TEXT time·now(SB), NOSPLIT, $32
 	MOVW	8(R13), R0  // sec
 	MOVW	12(R13), R2  // nsec
 	
-	MOVW	R0, 0(FP)
+	MOVW	R0, sec+0(FP)
 	MOVW	$0, R1
-	MOVW	R1, 4(FP)
-	MOVW	R2, 8(FP)
+	MOVW	R1, loc+4(FP)
+	MOVW	R2, nsec+8(FP)
 	RET	
 
 // int64 nanotime(void)
@@ -202,18 +235,18 @@ TEXT runtime·nanotime(SB),NOSPLIT,$32
 // int32 futex(int32 *uaddr, int32 op, int32 val,
 //	struct timespec *timeout, int32 *uaddr2, int32 val2);
 TEXT runtime·futex(SB),NOSPLIT,$0
-	MOVW	4(SP), R0
-	MOVW	8(SP), R1
-	MOVW	12(SP), R2
-	MOVW	16(SP), R3
-	MOVW	20(SP), R4
-	MOVW	24(SP), R5
+	// TODO: Rewrite to use FP references. Vet complains.
+	MOVW	4(R13), R0
+	MOVW	8(R13), R1
+	MOVW	12(R13), R2
+	MOVW	16(R13), R3
+	MOVW	20(R13), R4
+	MOVW	24(R13), R5
 	MOVW	$SYS_futex, R7
 	SWI	$0
 	MOVW	R0, ret+24(FP)
 	RET
 
-
 // int32 clone(int32 flags, void *stack, M *mp, G *gp, void (*fn)(void));
 TEXT runtime·clone(SB),NOSPLIT,$0
 	MOVW	flags+0(FP), R0
@@ -251,8 +284,15 @@ TEXT runtime·clone(SB),NOSPLIT,$0
 	BEQ	2(PC)
 	BL	runtime·abort(SB)
 
-	MOVW	4(R13), g
-	MOVW	0(R13), R8
+	MOVW	0(R13), R8    // m
+	MOVW	4(R13), R0    // g
+
+	CMP	$0, R8
+	BEQ	nog
+	CMP	$0, R0
+	BEQ	nog
+
+	MOVW	R0, g
 	MOVW	R8, g_m(g)
 
 	// paranoia; check they are not nil
@@ -267,23 +307,25 @@ TEXT runtime·clone(SB),NOSPLIT,$0
 	MOVW	g_m(g), R8
 	MOVW	R0, m_procid(R8)
 
+nog:
 	// Call fn
 	MOVW	8(R13), R0
 	MOVW	$16(R13), R13
 	BL	(R0)
 
+	// It shouldn't return.  If it does, exit that thread.
+	SUB	$16, R13 // restore the stack pointer to avoid memory corruption
 	MOVW	$0, R0
 	MOVW	R0, 4(R13)
 	BL	runtime·exit1(SB)
 
-	// It shouldn't return
 	MOVW	$1234, R0
 	MOVW	$1005, R1
 	MOVW	R0, (R1)
 
 TEXT runtime·sigaltstack(SB),NOSPLIT,$0
-	MOVW	0(FP), R0
-	MOVW	4(FP), R1
+	MOVW	new+0(FP), R0
+	MOVW	old+4(FP), R1
 	MOVW	$SYS_sigaltstack, R7
 	SWI	$0
 	MOVW	$0xfffff001, R6
@@ -292,7 +334,15 @@ TEXT runtime·sigaltstack(SB),NOSPLIT,$0
 	MOVW.HI	R8, (R8)
 	RET
 
-TEXT runtime·sigtramp(SB),NOSPLIT,$24
+TEXT runtime·sigfwd(SB),NOSPLIT,$0-16
+	MOVW	sig+4(FP), R0
+	MOVW	info+8(FP), R1
+	MOVW	ctx+12(FP), R2
+	MOVW	fn+0(FP), R11
+	BL	(R11)
+	RET
+
+TEXT runtime·sigtramp(SB),NOSPLIT,$12
 	// this might be called in external code context,
 	// where g is not set.
 	// first save R0, because runtime·load_g will clobber it
@@ -301,48 +351,26 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$24
 	CMP 	$0, R0
 	BL.NE	runtime·load_g(SB)
 
-	CMP 	$0, g
-	BNE 	4(PC)
-	// signal number is already prepared in 4(R13)
-	MOVW  	$runtime·badsignal(SB), R11
-	BL	(R11)
-	RET
-
-	// save g
-	MOVW	g, R3
-	MOVW	g, 20(R13)
-
-	// g = m->gsignal
-	MOVW	g_m(g), R8
-	MOVW	m_gsignal(R8), g
-
-	// copy arguments for call to sighandler
-	// R0 is already saved above
 	MOVW	R1, 8(R13)
 	MOVW	R2, 12(R13)
-	MOVW	R3, 16(R13)
-
-	BL	runtime·sighandler(SB)
-
-	// restore g
-	MOVW	20(R13), g
-
+	MOVW  	$runtime·sigtrampgo(SB), R11
+	BL	(R11)
 	RET
 
 TEXT runtime·rtsigprocmask(SB),NOSPLIT,$0
-	MOVW	0(FP), R0
-	MOVW	4(FP), R1
-	MOVW	8(FP), R2
-	MOVW	12(FP), R3
+	MOVW	sig+0(FP), R0
+	MOVW	new+4(FP), R1
+	MOVW	old+8(FP), R2
+	MOVW	size+12(FP), R3
 	MOVW	$SYS_rt_sigprocmask, R7
 	SWI	$0
 	RET
 
 TEXT runtime·rt_sigaction(SB),NOSPLIT,$0
-	MOVW	0(FP), R0
-	MOVW	4(FP), R1
-	MOVW	8(FP), R2
-	MOVW	12(FP), R3
+	MOVW	sig+0(FP), R0
+	MOVW	new+4(FP), R1
+	MOVW	old+8(FP), R2
+	MOVW	size+12(FP), R3
 	MOVW	$SYS_rt_sigaction, R7
 	SWI	$0
 	MOVW	R0, ret+16(FP)
@@ -350,17 +378,14 @@ TEXT runtime·rt_sigaction(SB),NOSPLIT,$0
 
 TEXT runtime·usleep(SB),NOSPLIT,$12
 	MOVW	usec+0(FP), R0
-	MOVW	R0, R1
-	MOVW	$1000000, R2
-	DIV	R2, R0
-	MOD	R2, R1
-	MOVW	R0, 4(SP)
-	MOVW	R1, 8(SP)
+	CALL	runtime·usplitR0(SB)
+	MOVW	R0, 4(R13)
+	MOVW	R1, 8(R13)
 	MOVW	$0, R0
 	MOVW	$0, R1
 	MOVW	$0, R2
 	MOVW	$0, R3
-	MOVW	$4(SP), R4
+	MOVW	$4(R13), R4
 	MOVW	$SYS_select, R7
 	SWI	$0
 	RET
@@ -368,41 +393,57 @@ TEXT runtime·usleep(SB),NOSPLIT,$12
 // Use kernel version instead of native armcas in asm_arm.s.
 // See ../sync/atomic/asm_linux_arm.s for details.
 TEXT cas<>(SB),NOSPLIT,$0
-	MOVW	$0xffff0fc0, PC
+	MOVW	$0xffff0fc0, R15 // R15 is hardware PC.
 
 TEXT runtime·cas(SB),NOSPLIT,$0
 	MOVW	ptr+0(FP), R2
 	MOVW	old+4(FP), R0
-casagain:
+loop:
 	MOVW	new+8(FP), R1
 	BL	cas<>(SB)
-	BCC	cascheck
+	BCC	check
 	MOVW	$1, R0
 	MOVB	R0, ret+12(FP)
 	RET
-cascheck:
+check:
 	// Kernel lies; double-check.
 	MOVW	ptr+0(FP), R2
 	MOVW	old+4(FP), R0
 	MOVW	0(R2), R3
 	CMP	R0, R3
-	BEQ	casagain
+	BEQ	loop
 	MOVW	$0, R0
 	MOVB	R0, ret+12(FP)
 	RET
 
-TEXT runtime·casp(SB),NOSPLIT,$0
+TEXT runtime·casp1(SB),NOSPLIT,$0
 	B	runtime·cas(SB)
 
+// As for cas, memory barriers are complicated on ARM, but the kernel
+// provides a user helper. ARMv5 does not support SMP and has no
+// memory barrier instruction at all. ARMv6 added SMP support and has
+// a memory barrier, but it requires writing to a coprocessor
+// register. ARMv7 introduced the DMB instruction, but it's expensive
+// even on single-core devices. The kernel helper takes care of all of
+// this for us.
+
+TEXT publicationBarrier<>(SB),NOSPLIT,$0
+	// void __kuser_memory_barrier(void);
+	MOVW	$0xffff0fa0, R15 // R15 is hardware PC.
+
+TEXT ·publicationBarrier(SB),NOSPLIT,$0
+	BL	publicationBarrier<>(SB)
+	RET
+
 TEXT runtime·osyield(SB),NOSPLIT,$0
 	MOVW	$SYS_sched_yield, R7
 	SWI	$0
 	RET
 
 TEXT runtime·sched_getaffinity(SB),NOSPLIT,$0
-	MOVW	0(FP), R0
-	MOVW	4(FP), R1
-	MOVW	8(FP), R2
+	MOVW	pid+0(FP), R0
+	MOVW	len+4(FP), R1
+	MOVW	buf+8(FP), R2
 	MOVW	$SYS_sched_getaffinity, R7
 	SWI	$0
 	MOVW	R0, ret+12(FP)
@@ -410,7 +451,7 @@ TEXT runtime·sched_getaffinity(SB),NOSPLIT,$0
 
 // int32 runtime·epollcreate(int32 size)
 TEXT runtime·epollcreate(SB),NOSPLIT,$0
-	MOVW	0(FP), R0
+	MOVW	size+0(FP), R0
 	MOVW	$SYS_epoll_create, R7
 	SWI	$0
 	MOVW	R0, ret+4(FP)
@@ -418,7 +459,7 @@ TEXT runtime·epollcreate(SB),NOSPLIT,$0
 
 // int32 runtime·epollcreate1(int32 flags)
 TEXT runtime·epollcreate1(SB),NOSPLIT,$0
-	MOVW	0(FP), R0
+	MOVW	flags+0(FP), R0
 	MOVW	$SYS_epoll_create1, R7
 	SWI	$0
 	MOVW	R0, ret+4(FP)
@@ -437,10 +478,10 @@ TEXT runtime·epollctl(SB),NOSPLIT,$0
 
 // int32 runtime·epollwait(int32 epfd, EpollEvent *ev, int32 nev, int32 timeout)
 TEXT runtime·epollwait(SB),NOSPLIT,$0
-	MOVW	0(FP), R0
-	MOVW	4(FP), R1
-	MOVW	8(FP), R2
-	MOVW	12(FP), R3
+	MOVW	epfd+0(FP), R0
+	MOVW	ev+4(FP), R1
+	MOVW	nev+8(FP), R2
+	MOVW	timeout+12(FP), R3
 	MOVW	$SYS_epoll_wait, R7
 	SWI	$0
 	MOVW	R0, ret+16(FP)
@@ -448,7 +489,7 @@ TEXT runtime·epollwait(SB),NOSPLIT,$0
 
 // void runtime·closeonexec(int32 fd)
 TEXT runtime·closeonexec(SB),NOSPLIT,$0
-	MOVW	0(FP), R0	// fd
+	MOVW	fd+0(FP), R0	// fd
 	MOVW	$2, R1	// F_SETFD
 	MOVW	$1, R2	// FD_CLOEXEC
 	MOVW	$SYS_fcntl, R7
@@ -459,3 +500,29 @@ TEXT runtime·closeonexec(SB),NOSPLIT,$0
 TEXT runtime·read_tls_fallback(SB),NOSPLIT,$-4
 	MOVW	$0xffff0fe0, R0
 	B	(R0)
+
+TEXT runtime·access(SB),NOSPLIT,$0
+	MOVW	name+0(FP), R0
+	MOVW	mode+4(FP), R1
+	MOVW	$SYS_access, R7
+	SWI	$0
+	MOVW	R0, ret+8(FP)
+	RET
+
+TEXT runtime·connect(SB),NOSPLIT,$0
+	MOVW	fd+0(FP), R0
+	MOVW	addr+4(FP), R1
+	MOVW	addrlen+8(FP), R2
+	MOVW	$SYS_connect, R7
+	SWI	$0
+	MOVW	R0, ret+12(FP)
+	RET
+
+TEXT runtime·socket(SB),NOSPLIT,$0
+	MOVW	domain+0(FP), R0
+	MOVW	type+4(FP), R1
+	MOVW	protocol+8(FP), R2
+	MOVW	$SYS_socket, R7
+	SWI	$0
+	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..7b58d67
--- /dev/null
+++ b/src/runtime/sys_linux_arm64.s
@@ -0,0 +1,447 @@
+// 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_getpid		172
+#define SYS_gettid		178
+#define SYS_kill		129
+#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·closefd(SB),NOSPLIT,$-8-12
+	MOVW	fd+0(FP), R0
+	MOVD	$SYS_close, R8
+	SVC
+	CMN	$4095, R0
+	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
+	CMN	$4095, R0
+	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
+	CMN	$4095, R0
+	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,$24-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·gettid(SB),NOSPLIT,$0-4
+	MOVD	$SYS_gettid, R8
+	SVC
+	MOVW	R0, ret+0(FP)
+	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·raiseproc(SB),NOSPLIT,$-8
+	MOVD	$SYS_getpid, R8
+	SVC
+	MOVW	R0, R0		// arg 1 pid
+	MOVW	sig+0(FP), R1	// arg 2
+	MOVD	$SYS_kill, 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,$24-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,$24-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·sigfwd(SB),NOSPLIT,$0-32
+	MOVW	sig+8(FP), R0
+	MOVD	info+16(FP), R1
+	MOVD	ctx+24(FP), R2
+	MOVD	fn+0(FP), R11
+	BL	(R11)
+	RET
+
+TEXT runtime·sigtramp(SB),NOSPLIT,$24
+	// 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)
+	MOVBU	runtime·iscgo(SB), R0
+	CMP	$0, R0
+	BEQ	2(PC)
+	BL	runtime·load_g(SB)
+
+	MOVD	R1, 16(RSP)
+	MOVD	R2, 24(RSP)
+	MOVD	$runtime·sigtrampgo(SB), R0
+	BL	(R0)
+	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
+
+good:
+	// Initialize m->procid to Linux tid
+	MOVD	$SYS_gettid, R8
+	SVC
+
+	MOVD	-24(RSP), R12     // fn
+	MOVD	-16(RSP), R11     // g
+	MOVD	-8(RSP), R10      // m
+
+	CMP	$0, R10
+	BEQ	nog
+	CMP	$0, R11
+	BEQ	nog
+
+	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)
+
+nog:
+	// Call fn
+	MOVD	R12, R0
+	BL	(R0)
+
+	// It shouldn't return.	 If it does, exit that thread.
+	MOVW	$111, R0
+again:
+	MOVD	$SYS_exit, 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
new file mode 100644
index 0000000..01575f8
--- /dev/null
+++ b/src/runtime/sys_linux_ppc64x.s
@@ -0,0 +1,407 @@
+// 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
+// +build ppc64 ppc64le
+
+//
+// System calls and other sys.stuff for ppc64, Linux
+//
+
+#include "go_asm.h"
+#include "go_tls.h"
+#include "textflag.h"
+
+#define SYS_exit		  1
+#define SYS_read		  3
+#define SYS_write		  4
+#define SYS_open		  5
+#define SYS_close		  6
+#define SYS_getpid		 20
+#define SYS_kill		 37
+#define SYS_fcntl		 55
+#define SYS_gettimeofday	 78
+#define SYS_select		 82	// always return -ENOSYS
+#define SYS_mmap		 90
+#define SYS_munmap		 91
+#define SYS_setitimer		104
+#define SYS_clone		120
+#define SYS_newselect		142
+#define SYS_sched_yield		158
+#define SYS_rt_sigreturn	172
+#define SYS_rt_sigaction	173
+#define SYS_rt_sigprocmask	174
+#define SYS_sigaltstack		185
+#define SYS_ugetrlimit		190
+#define SYS_madvise		205
+#define SYS_mincore		206
+#define SYS_gettid		207
+#define SYS_tkill		208
+#define SYS_futex		221
+#define SYS_sched_getaffinity	223
+#define SYS_exit_group		234
+#define SYS_epoll_create	236
+#define SYS_epoll_ctl		237
+#define SYS_epoll_wait		238
+#define SYS_clock_gettime	246
+#define SYS_epoll_create1	315
+
+TEXT runtime·exit(SB),NOSPLIT,$-8-4
+	MOVW	code+0(FP), R3
+	SYSCALL	$SYS_exit_group
+	RET
+
+TEXT runtime·exit1(SB),NOSPLIT,$-8-4
+	MOVW	code+0(FP), R3
+	SYSCALL	$SYS_exit
+	RET
+
+TEXT runtime·open(SB),NOSPLIT,$-8-20
+	MOVD	name+0(FP), R3
+	MOVW	mode+8(FP), R4
+	MOVW	perm+12(FP), R5
+	SYSCALL	$SYS_open
+	BVC	2(PC)
+	MOVW	$-1, R3
+	MOVW	R3, ret+16(FP)
+	RET
+
+TEXT runtime·closefd(SB),NOSPLIT,$-8-12
+	MOVW	fd+0(FP), R3
+	SYSCALL	$SYS_close
+	BVC	2(PC)
+	MOVW	$-1, R3
+	MOVW	R3, ret+8(FP)
+	RET
+
+TEXT runtime·write(SB),NOSPLIT,$-8-28
+	MOVD	fd+0(FP), R3
+	MOVD	p+8(FP), R4
+	MOVW	n+16(FP), R5
+	SYSCALL	$SYS_write
+	BVC	2(PC)
+	MOVW	$-1, R3
+	MOVW	R3, ret+24(FP)
+	RET
+
+TEXT runtime·read(SB),NOSPLIT,$-8-28
+	MOVW	fd+0(FP), R3
+	MOVD	p+8(FP), R4
+	MOVW	n+16(FP), R5
+	SYSCALL	$SYS_read
+	BVC	2(PC)
+	MOVW	$-1, R3
+	MOVW	R3, ret+24(FP)
+	RET
+
+TEXT runtime·getrlimit(SB),NOSPLIT,$-8-20
+	MOVW	kind+0(FP), R3
+	MOVD	limit+8(FP), R4
+	SYSCALL	$SYS_ugetrlimit
+	MOVW	R3, ret+16(FP)
+	RET
+
+TEXT runtime·usleep(SB),NOSPLIT,$16-4
+	MOVW	usec+0(FP), R3
+	MOVD	R3, R5
+	MOVW	$1000000, R4
+	DIVD	R4, R3
+	MOVD	R3, 8(R1)
+	MULLD	R3, R4
+	SUB	R4, R5
+	MOVD	R5, 16(R1)
+
+	// select(0, 0, 0, 0, &tv)
+	MOVW	$0, R3
+	MOVW	$0, R4
+	MOVW	$0, R5
+	MOVW	$0, R6
+	ADD	$8, R1, R7
+	SYSCALL	$SYS_newselect
+	RET
+
+TEXT runtime·gettid(SB),NOSPLIT,$0-4
+	SYSCALL	$SYS_gettid
+	MOVW	R3, ret+0(FP)
+	RET
+
+TEXT runtime·raise(SB),NOSPLIT,$-8
+	SYSCALL	$SYS_gettid
+	MOVW	R3, R3	// arg 1 tid
+	MOVW	sig+0(FP), R4	// arg 2
+	SYSCALL	$SYS_tkill
+	RET
+
+TEXT runtime·raiseproc(SB),NOSPLIT,$-8
+	SYSCALL	$SYS_getpid
+	MOVW	R3, R3	// arg 1 pid
+	MOVW	sig+0(FP), R4	// arg 2
+	SYSCALL	$SYS_kill
+	RET
+
+TEXT runtime·setitimer(SB),NOSPLIT,$-8-24
+	MOVW	mode+0(FP), R3
+	MOVD	new+8(FP), R4
+	MOVD	old+16(FP), R5
+	SYSCALL	$SYS_setitimer
+	RET
+
+TEXT runtime·mincore(SB),NOSPLIT,$-8-28
+	MOVD	addr+0(FP), R3
+	MOVD	n+8(FP), R4
+	MOVD	dst+16(FP), R5
+	SYSCALL	$SYS_mincore
+	MOVW	R3, ret+24(FP)
+	RET
+
+// func now() (sec int64, nsec int32)
+TEXT time·now(SB),NOSPLIT,$16
+	MOVD	$0(R1), R3
+	MOVD	$0, R4
+	SYSCALL	$SYS_gettimeofday
+	MOVD	0(R1), R3	// sec
+	MOVD	8(R1), R5	// usec
+	MOVD	$1000, R4
+	MULLD	R4, R5
+	MOVD	R3, sec+0(FP)
+	MOVW	R5, nsec+8(FP)
+	RET
+
+TEXT runtime·nanotime(SB),NOSPLIT,$16
+	MOVW	$1, R3 // CLOCK_MONOTONIC
+	MOVD	$0(R1), R4
+	SYSCALL	$SYS_clock_gettime
+	MOVD	0(R1), R3	// sec
+	MOVD	8(R1), R5	// nsec
+	// sec is in R3, nsec in R5
+	// return nsec in R3
+	MOVD	$1000000000, R4
+	MULLD	R4, R3
+	ADD	R5, R3
+	MOVD	R3, ret+0(FP)
+	RET
+
+TEXT runtime·rtsigprocmask(SB),NOSPLIT,$-8-28
+	MOVW	sig+0(FP), R3
+	MOVD	new+8(FP), R4
+	MOVD	old+16(FP), R5
+	MOVW	size+24(FP), R6
+	SYSCALL	$SYS_rt_sigprocmask
+	BVC	2(PC)
+	MOVD	R0, 0xf1(R0)	// crash
+	RET
+
+TEXT runtime·rt_sigaction(SB),NOSPLIT,$-8-36
+	MOVD	sig+0(FP), R3
+	MOVD	new+8(FP), R4
+	MOVD	old+16(FP), R5
+	MOVD	size+24(FP), R6
+	SYSCALL	$SYS_rt_sigaction
+	MOVW	R3, ret+32(FP)
+	RET
+
+TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
+	MOVW	sig+8(FP), R3
+	MOVD	info+16(FP), R4
+	MOVD	ctx+24(FP), R5
+	MOVD	fn+0(FP), R31
+	MOVD	R31, CTR
+	BL	(CTR)
+	RET
+
+#ifdef GOARCH_ppc64le
+// ppc64le doesn't need function descriptors
+TEXT runtime·sigtramp(SB),NOSPLIT,$64
+#else
+// function descriptor for the real sigtramp
+TEXT runtime·sigtramp(SB),NOSPLIT,$-8
+	DWORD	$runtime·_sigtramp(SB)
+	DWORD	$0
+	DWORD	$0
+TEXT runtime·_sigtramp(SB),NOSPLIT,$64
+#endif
+	// initialize essential registers (just in case)
+	BL	runtime·reginit(SB)
+
+	// this might be called in external code context,
+	// where g is not set.
+	MOVB	runtime·iscgo(SB), R6
+	CMP 	R6, $0
+	BEQ	2(PC)
+	BL	runtime·load_g(SB)
+
+	MOVW	R3, 8(R1)
+	MOVD	R4, 16(R1)
+	MOVD	R5, 24(R1)
+	MOVD	$runtime·sigtrampgo(SB), R31
+	MOVD	R31, CTR
+	BL	(CTR)
+	RET
+
+TEXT runtime·mmap(SB),NOSPLIT,$-8
+	MOVD	addr+0(FP), R3
+	MOVD	n+8(FP), R4
+	MOVW	prot+16(FP), R5
+	MOVW	flags+20(FP), R6
+	MOVW	fd+24(FP), R7
+	MOVW	off+28(FP), R8
+
+	SYSCALL	$SYS_mmap
+	MOVD	R3, ret+32(FP)
+	RET
+
+TEXT runtime·munmap(SB),NOSPLIT,$-8
+	MOVD	addr+0(FP), R3
+	MOVD	n+8(FP), R4
+	SYSCALL	$SYS_munmap
+	BVC	2(PC)
+	MOVD	R0, 0xf3(R0)
+	RET
+
+TEXT runtime·madvise(SB),NOSPLIT,$-8
+	MOVD	addr+0(FP), R3
+	MOVD	n+8(FP), R4
+	MOVW	flags+16(FP), R5
+	SYSCALL	$SYS_madvise
+	// 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), R3
+	MOVW	op+8(FP), R4
+	MOVW	val+12(FP), R5
+	MOVD	ts+16(FP), R6
+	MOVD	addr2+24(FP), R7
+	MOVW	val3+32(FP), R8
+	SYSCALL	$SYS_futex
+	MOVW	R3, 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), R3
+	MOVD	stk+8(FP), R4
+
+	// Copy mp, gp, fn off parent stack for use by child.
+	// Careful: Linux system call clobbers ???.
+	MOVD	mm+16(FP), R7
+	MOVD	gg+24(FP), R8
+	MOVD	fn+32(FP), R12
+
+	MOVD	R7, -8(R4)
+	MOVD	R8, -16(R4)
+	MOVD	R12, -24(R4)
+	MOVD	$1234, R7
+	MOVD	R7, -32(R4)
+
+	SYSCALL $SYS_clone
+
+	// In parent, return.
+	CMP	R3, $0
+	BEQ	3(PC)
+	MOVW	R3, ret+40(FP)
+	RET
+
+	// In child, on new stack.
+	// initialize essential registers
+	BL	runtime·reginit(SB)
+	MOVD	-32(R1), R7
+	CMP	R7, $1234
+	BEQ	2(PC)
+	MOVD	R0, 0(R0)
+
+	// Initialize m->procid to Linux tid
+	SYSCALL $SYS_gettid
+
+	MOVD	-24(R1), R12       // fn
+	MOVD	-16(R1), R8        // g
+	MOVD	-8(R1), R7         // m
+
+	CMP	R7, $0
+	BEQ	nog
+	CMP	R8, $0
+	BEQ	nog
+
+	MOVD	R3, m_procid(R7)
+
+	// TODO: setup TLS.
+
+	// In child, set up new stack
+	MOVD	R7, g_m(R8)
+	MOVD	R8, g
+	//CALL	runtime·stackcheck(SB)
+
+nog:
+	// Call fn
+	MOVD	R12, CTR
+	BL	(CTR)
+
+	// It shouldn't return.	 If it does, exit that thread.
+	MOVW	$111, R3
+	SYSCALL	$SYS_exit
+	BR	-2(PC)	// keep exiting
+
+TEXT runtime·sigaltstack(SB),NOSPLIT,$-8
+	MOVD	new+0(FP), R3
+	MOVD	old+8(FP), R4
+	SYSCALL	$SYS_sigaltstack
+	BVC	2(PC)
+	MOVD	R0, 0xf1(R0)  // crash
+	RET
+
+TEXT runtime·osyield(SB),NOSPLIT,$-8
+	SYSCALL	$SYS_sched_yield
+	RET
+
+TEXT runtime·sched_getaffinity(SB),NOSPLIT,$-8
+	MOVD	pid+0(FP), R3
+	MOVD	len+8(FP), R4
+	MOVD	buf+16(FP), R5
+	SYSCALL	$SYS_sched_getaffinity
+	MOVW	R3, ret+24(FP)
+	RET
+
+// int32 runtime·epollcreate(int32 size);
+TEXT runtime·epollcreate(SB),NOSPLIT,$-8
+	MOVW    size+0(FP), R3
+	SYSCALL	$SYS_epoll_create
+	MOVW	R3, ret+8(FP)
+	RET
+
+// int32 runtime·epollcreate1(int32 flags);
+TEXT runtime·epollcreate1(SB),NOSPLIT,$-8
+	MOVW	flags+0(FP), R3
+	SYSCALL	$SYS_epoll_create1
+	MOVW	R3, ret+8(FP)
+	RET
+
+// func epollctl(epfd, op, fd int32, ev *epollEvent) int
+TEXT runtime·epollctl(SB),NOSPLIT,$-8
+	MOVW	epfd+0(FP), R3
+	MOVW	op+4(FP), R4
+	MOVW	fd+8(FP), R5
+	MOVD	ev+16(FP), R6
+	SYSCALL	$SYS_epoll_ctl
+	MOVW	R3, 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), R3
+	MOVD	ev+8(FP), R4
+	MOVW	nev+16(FP), R5
+	MOVW	timeout+20(FP), R6
+	SYSCALL	$SYS_epoll_wait
+	MOVW	R3, ret+24(FP)
+	RET
+
+// void runtime·closeonexec(int32 fd);
+TEXT runtime·closeonexec(SB),NOSPLIT,$-8
+	MOVW    fd+0(FP), R3  // fd
+	MOVD    $2, R4  // F_SETFD
+	MOVD    $1, R5  // FD_CLOEXEC
+	SYSCALL	$SYS_fcntl
+	RET
diff --git a/src/runtime/sys_nacl_386.s b/src/runtime/sys_nacl_386.s
index 47985f3..bf2d36e 100644
--- a/src/runtime/sys_nacl_386.s
+++ b/src/runtime/sys_nacl_386.s
@@ -2,7 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
 #include "textflag.h"
 #include "syscall_nacl.h"
 
@@ -32,7 +33,7 @@ TEXT runtime·open(SB),NOSPLIT,$12
 	MOVL AX, ret+12(FP)
 	RET
 
-TEXT runtime·close(SB),NOSPLIT,$4
+TEXT runtime·closefd(SB),NOSPLIT,$4
 	MOVL fd+0(FP), AX
 	MOVL AX, 0(SP)
 	NACL_SYSCALL(SYS_close)
@@ -293,7 +294,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0
 	MOVL	$0, 0(SP)
 	MOVL	$runtime·badsignal(SB), AX
 	CALL	AX
-	JMP 	sigtramp_ret
+	JMP 	ret
 
 	// save g
 	MOVL	DI, 20(SP)
@@ -317,11 +318,11 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0
 	MOVL	20(SP), BX
 	MOVL	BX, g(CX)
 
-sigtramp_ret:
+ret:
 	// Enable exceptions again.
 	NACL_SYSCALL(SYS_exception_clear_flag)
 
-	// NaCl has abidcated its traditional operating system responsibility
+	// NaCl has abdicated its traditional operating system responsibility
 	// and declined to implement 'sigreturn'. Instead the only way to return
 	// to the execution of our program is to restore the registers ourselves.
 	// Unfortunately, that is impossible to do with strict fidelity, because
@@ -361,3 +362,12 @@ sigtramp_ret:
 	// 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 4eb4aac..0b29c9f 100644
--- a/src/runtime/sys_nacl_amd64p32.s
+++ b/src/runtime/sys_nacl_amd64p32.s
@@ -2,7 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
 #include "textflag.h"
 #include "syscall_nacl.h"
 
@@ -31,7 +32,7 @@ TEXT runtime·open(SB),NOSPLIT,$0
 	MOVL AX, ret+16(FP)
 	RET
 
-TEXT runtime·close(SB),NOSPLIT,$0
+TEXT runtime·closefd(SB),NOSPLIT,$0
 	MOVL fd+0(FP), DI
 	NACL_SYSCALL(SYS_close)
 	MOVL AX, ret+8(FP)
@@ -93,13 +94,13 @@ playback:
 	MOVL n+8(FP), DX
 	BSWAPL DX
 	MOVL DX, 12(SP)
-	MOVL $1, DI // standard output
+	MOVL fd+0(FP), DI
 	MOVL SP, SI
 	MOVL $16, DX
 	NACL_SYSCALL(SYS_write)
 
 	// Write actual data.
-	MOVL $1, DI // standard output
+	MOVL fd+0(FP), DI
 	MOVL p+4(FP), SI
 	MOVL n+8(FP), DX
 	NACL_SYSCALL(SYS_write)
@@ -338,7 +339,6 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$80
 	MOVL	20(SP), BX
 	MOVL	BX, g(CX)
 
-sigtramp_ret:
 	// Enable exceptions again.
 	NACL_SYSCALL(SYS_exception_clear_flag)
 
@@ -412,6 +412,13 @@ nog:
 // 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 d354ab4..cf4804f 100644
--- a/src/runtime/sys_nacl_arm.s
+++ b/src/runtime/sys_nacl_arm.s
@@ -2,7 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
 #include "textflag.h"
 #include "syscall_nacl.h"
 
@@ -27,7 +28,7 @@ TEXT runtime·open(SB),NOSPLIT,$0
 	MOVW	R0, ret+12(FP)
 	RET
 
-TEXT runtime·close(SB),NOSPLIT,$0
+TEXT runtime·closefd(SB),NOSPLIT,$0
 	MOVW	fd+0(FP), R0
 	NACL_SYSCALL(SYS_close)
 	MOVW	R0, ret+4(FP)
@@ -269,7 +270,6 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$80
 	// restore g
 	MOVW	20(R13), g
 
-sigtramp_ret:
 	// Enable exceptions again.
 	NACL_SYSCALL(SYS_exception_clear_flag)
 
@@ -301,7 +301,14 @@ nog:
 TEXT runtime·nacl_sysinfo(SB),NOSPLIT,$16
 	RET
 
-TEXT runtime·casp(SB),NOSPLIT,$0
+// 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)
 
 // This is only valid for ARMv6+, however, NaCl/ARM is only defined
@@ -316,5 +323,9 @@ TEXT runtime·casp(SB),NOSPLIT,$0
 TEXT runtime·cas(SB),NOSPLIT,$0
 	B runtime·armcas(SB)
 
+// Likewise, this is only valid for ARMv7+, but that's okay.
+TEXT ·publicationBarrier(SB),NOSPLIT,$-4-0
+	B	runtime·armPublicationBarrier(SB)
+
 TEXT runtime·read_tls_fallback(SB),NOSPLIT,$-4
 	WORD $0xe7fedef0 // NACL_INSTR_ARM_ABORT_NOW (UDF #0xEDE0)
diff --git a/src/runtime/sys_netbsd_386.s b/src/runtime/sys_netbsd_386.s
index 23f2f6b..13b8428 100644
--- a/src/runtime/sys_netbsd_386.s
+++ b/src/runtime/sys_netbsd_386.s
@@ -6,7 +6,8 @@
 // /usr/src/sys/kern/syscalls.master for syscall numbers.
 //
 
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
 #include "textflag.h"
 
 // Exit the entire program (like C exit)
@@ -26,24 +27,32 @@ TEXT runtime·exit1(SB),NOSPLIT,$-4
 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
+TEXT runtime·closefd(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
 
@@ -77,6 +86,17 @@ TEXT runtime·raise(SB),NOSPLIT,$12
 	INT	$0x80
 	RET
 
+TEXT runtime·raiseproc(SB),NOSPLIT,$12
+	MOVL	$20, AX			// sys_getpid
+	INT	$0x80
+	MOVL	$0, 0(SP)
+	MOVL	AX, 4(SP)		// arg 1 - pid
+	MOVL	sig+0(FP), AX
+	MOVL	AX, 8(SP)		// arg 2 - signo
+	MOVL	$37, AX			// sys_kill
+	INT	$0x80
+	RET
+
 TEXT runtime·mmap(SB),NOSPLIT,$36
 	LEAL	addr+0(FP), SI
 	LEAL	4(SP), DI
@@ -298,9 +318,9 @@ TEXT runtime·setldt(SB),NOSPLIT,$8
 	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 eb9766d..d0640db 100644
--- a/src/runtime/sys_netbsd_amd64.s
+++ b/src/runtime/sys_netbsd_amd64.s
@@ -6,7 +6,8 @@
 // /usr/src/sys/kern/syscalls.master for syscall numbers.
 //
 
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
 #include "textflag.h"
 
 // int32 lwp_create(void *context, uintptr flags, void *lwpid)
@@ -90,13 +91,17 @@ TEXT runtime·open(SB),NOSPLIT,$-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
 
-TEXT runtime·close(SB),NOSPLIT,$-8
+TEXT runtime·closefd(SB),NOSPLIT,$-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
 
@@ -106,6 +111,8 @@ TEXT runtime·read(SB),NOSPLIT,$-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
 
@@ -115,6 +122,8 @@ TEXT runtime·write(SB),NOSPLIT,$-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
 
@@ -143,6 +152,15 @@ TEXT runtime·raise(SB),NOSPLIT,$16
 	SYSCALL
 	RET
 
+TEXT runtime·raiseproc(SB),NOSPLIT,$16
+	MOVL	$20, AX			// sys_getpid
+	SYSCALL
+	MOVQ	AX, DI			// arg 1 - pid
+	MOVL	sig+0(FP), SI		// arg 2 - signo
+	MOVL	$37, AX			// sys_kill
+	SYSCALL
+	RET
+
 TEXT runtime·setitimer(SB),NOSPLIT,$-8
 	MOVL	mode+0(FP), DI		// arg 1 - which
 	MOVQ	new+8(FP), SI		// arg 2 - itv
@@ -235,9 +253,9 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$64
 	MOVQ	R10, 40(SP)
 
 	// g = m->signal
-	MOVQ	g_m(R10), BP
-	MOVQ	m_gsignal(BP), BP
-	MOVQ	BP, g(BX)
+	MOVQ	g_m(R10), AX
+	MOVQ	m_gsignal(AX), AX
+	MOVQ	AX, g(BX)
 
 	MOVQ	DI, 0(SP)
 	MOVQ	SI, 8(SP)
@@ -298,8 +316,8 @@ TEXT runtime·sigaltstack(SB),NOSPLIT,$-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 039a083..ae669ce 100644
--- a/src/runtime/sys_netbsd_arm.s
+++ b/src/runtime/sys_netbsd_arm.s
@@ -6,12 +6,13 @@
 // /usr/src/sys/kern/syscalls.master for syscall numbers.
 //
 
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
 #include "textflag.h"
 
 // Exit the entire program (like C exit)
 TEXT runtime·exit(SB),NOSPLIT,$-4
-	MOVW 0(FP), R0	// arg 1 exit status
+	MOVW code+0(FP), R0	// arg 1 exit status
 	SWI $0xa00001
 	MOVW.CS $0, R8	// crash on syscall failure
 	MOVW.CS R8, (R8)
@@ -24,32 +25,36 @@ TEXT runtime·exit1(SB),NOSPLIT,$-4
 	RET
 	
 TEXT runtime·open(SB),NOSPLIT,$-8
-	MOVW 0(FP), R0
-	MOVW 4(FP), R1
-	MOVW 8(FP), R2
+	MOVW name+0(FP), R0
+	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 0(FP), R0
+TEXT runtime·closefd(SB),NOSPLIT,$-8
+	MOVW fd+0(FP), R0
 	SWI $0xa00006
+	MOVW.CS	$-1, R0
 	MOVW	R0, ret+4(FP)
 	RET
 
 TEXT runtime·read(SB),NOSPLIT,$-8
-	MOVW 0(FP), R0
-	MOVW 4(FP), R1
-	MOVW 8(FP), R2
+	MOVW fd+0(FP), R0
+	MOVW p+4(FP), R1
+	MOVW n+8(FP), R2
 	SWI $0xa00003
+	MOVW.CS	$-1, R0
 	MOVW	R0, ret+12(FP)
 	RET
 
 TEXT runtime·write(SB),NOSPLIT,$-4
-	MOVW	0(FP), R0	// arg 1 - fd
-	MOVW	4(FP), R1	// arg 2 - buf
-	MOVW	8(FP), R2	// arg 3 - nbyte
+	MOVW	fd+0(FP), R0	// arg 1 - fd
+	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
 
@@ -67,17 +72,17 @@ TEXT runtime·osyield(SB),NOSPLIT,$0
 	RET
 
 TEXT runtime·lwp_park(SB),NOSPLIT,$0
-	MOVW 0(FP), R0	// arg 1 - abstime
-	MOVW 4(FP), R1	// arg 2 - unpark
-	MOVW 8(FP), R2	// arg 3 - hint
-	MOVW 12(FP), R3	// arg 4 - unparkhint
+	MOVW abstime+0(FP), R0	// arg 1 - abstime
+	MOVW unpark+4(FP), R1	// arg 2 - unpark
+	MOVW hint+8(FP), R2	// arg 3 - hint
+	MOVW unparkhint+12(FP), R3	// arg 4 - unparkhint
 	SWI $0xa001b2	// sys__lwp_park
 	MOVW	R0, ret+16(FP)
 	RET
 
 TEXT runtime·lwp_unpark(SB),NOSPLIT,$0
-	MOVW	0(FP), R0	// arg 1 - lwp
-	MOVW	4(FP), R1	// arg 2 - hint
+	MOVW	lwp+0(FP), R0	// arg 1 - lwp
+	MOVW	hint+4(FP), R1	// arg 2 - hint
 	SWI $0xa00141 // sys__lwp_unpark
 	MOVW	R0, ret+8(FP)
 	RET
@@ -99,15 +104,12 @@ TEXT runtime·lwp_tramp(SB),NOSPLIT,$0
 
 TEXT runtime·usleep(SB),NOSPLIT,$16
 	MOVW usec+0(FP), R0
-	MOVW R0, R2
-	MOVW $1000000, R1
-	DIV R1, R0
+	CALL runtime·usplitR0(SB)
 	// 0(R13) is the saved LR, don't use it
 	MOVW R0, 4(R13) // tv_sec.low
 	MOVW $0, R0
 	MOVW R0, 8(R13) // tv_sec.high
-	MOD R1, R2
-	MOVW $1000, R1
+	MOVW $1000, R2
 	MUL R1, R2
 	MOVW R2, 12(R13) // tv_nsec
 
@@ -122,10 +124,16 @@ TEXT runtime·raise(SB),NOSPLIT,$16
 	SWI $0xa0013e	// sys__lwp_kill
 	RET
 
+TEXT runtime·raiseproc(SB),NOSPLIT,$16
+	SWI $0xa00014	// sys_getpid, the returned R0 is arg 1
+	MOVW	sig+0(FP), R1	// arg 2 - signal
+	SWI $0xa00025	// sys_kill
+	RET
+
 TEXT runtime·setitimer(SB),NOSPLIT,$-4
-	MOVW 0(FP), R0	// arg 1 - which
-	MOVW 4(FP), R1	// arg 2 - itv
-	MOVW 8(FP), R2	// arg 3 - oitv
+	MOVW mode+0(FP), R0	// arg 1 - which
+	MOVW new+4(FP), R1	// arg 2 - itv
+	MOVW old+8(FP), R2	// arg 3 - oitv
 	SWI $0xa001a9	// sys_setitimer
 	RET
 
@@ -139,9 +147,9 @@ TEXT time·now(SB), NOSPLIT, $32
 	MOVW 12(R13), R1 // sec.high
 	MOVW 16(R13), R2 // nsec
 
-	MOVW R0, 0(FP)
-	MOVW R1, 4(FP)
-	MOVW R2, 8(FP)
+	MOVW R0, sec_lo+0(FP)
+	MOVW R1, sec_hi+4(FP)
+	MOVW R2, nsec+8(FP)
 	RET
 
 // int64 nanotime(void) so really
@@ -166,16 +174,16 @@ TEXT runtime·nanotime(SB), NOSPLIT, $32
 	RET
 
 TEXT runtime·getcontext(SB),NOSPLIT,$-4
-	MOVW 0(FP), R0	// arg 1 - context
+	MOVW ctxt+0(FP), R0	// arg 1 - context
 	SWI $0xa00133	// sys_getcontext
 	MOVW.CS $0, R8	// crash on syscall failure
 	MOVW.CS R8, (R8)
 	RET
 
 TEXT runtime·sigprocmask(SB),NOSPLIT,$0
-	MOVW 0(FP), R0	// arg 1 - how
-	MOVW 4(FP), R1	// arg 2 - set
-	MOVW 8(FP), R2	// arg 3 - oset
+	MOVW mode+0(FP), R0	// arg 1 - how
+	MOVW new+4(FP), R1	// arg 2 - set
+	MOVW old+8(FP), R2	// arg 3 - oset
 	SWI $0xa00125	// sys_sigprocmask
 	MOVW.CS $0, R8	// crash on syscall failure
 	MOVW.CS R8, (R8)
@@ -192,9 +200,9 @@ TEXT runtime·sigreturn_tramp(SB),NOSPLIT,$-4
 	B -2(PC)	// continue exit
 
 TEXT runtime·sigaction(SB),NOSPLIT,$4
-	MOVW 0(FP), R0	// arg 1 - signum
-	MOVW 4(FP), R1	// arg 2 - nsa
-	MOVW 8(FP), R2	// arg 3 - osa
+	MOVW sig+0(FP), R0	// arg 1 - signum
+	MOVW new+4(FP), R1	// arg 2 - nsa
+	MOVW old+8(FP), R2	// arg 3 - osa
 	MOVW $runtime·sigreturn_tramp(SB), R3	// arg 4 - tramp
 	MOVW $2, R4	// arg 5 - vers
 	MOVW R4, 4(R13)
@@ -241,15 +249,15 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$24
 	RET
 
 TEXT runtime·mmap(SB),NOSPLIT,$12
-	MOVW 0(FP), R0	// arg 1 - addr
-	MOVW 4(FP), R1	// arg 2 - len
-	MOVW 8(FP), R2	// arg 3 - prot
-	MOVW 12(FP), R3	// arg 4 - flags
+	MOVW addr+0(FP), R0	// arg 1 - addr
+	MOVW n+4(FP), R1	// arg 2 - len
+	MOVW prot+8(FP), R2	// arg 3 - prot
+	MOVW flags+12(FP), R3	// arg 4 - flags
 	// arg 5 (fid) and arg6 (offset_lo, offset_hi) are passed on stack
 	// note the C runtime only passes the 32-bit offset_lo to us
-	MOVW 16(FP), R4		// arg 5
+	MOVW fd+16(FP), R4		// arg 5
 	MOVW R4, 4(R13)
-	MOVW 20(FP), R5		// arg 6 lower 32-bit
+	MOVW off+20(FP), R5		// arg 6 lower 32-bit
 	MOVW R5, 8(R13)
 	MOVW $0, R6 // higher 32-bit for arg 6
 	MOVW R6, 12(R13)
@@ -260,37 +268,37 @@ TEXT runtime·mmap(SB),NOSPLIT,$12
 	RET
 
 TEXT runtime·munmap(SB),NOSPLIT,$0
-	MOVW 0(FP), R0	// arg 1 - addr
-	MOVW 4(FP), R1	// arg 2 - len
+	MOVW addr+0(FP), R0	// arg 1 - addr
+	MOVW n+4(FP), R1	// arg 2 - len
 	SWI $0xa00049	// sys_munmap
 	MOVW.CS $0, R8	// crash on syscall failure
 	MOVW.CS R8, (R8)
 	RET
 
 TEXT runtime·madvise(SB),NOSPLIT,$0
-	MOVW 0(FP), R0	// arg 1 - addr
-	MOVW 4(FP), R1	// arg 2 - len
-	MOVW 8(FP), R2	// arg 3 - behav
+	MOVW addr+0(FP), R0	// arg 1 - addr
+	MOVW n+4(FP), R1	// arg 2 - len
+	MOVW flags+8(FP), R2	// arg 3 - behav
 	SWI $0xa0004b	// sys_madvise
 	// ignore failure - maybe pages are locked
 	RET
 
 TEXT runtime·sigaltstack(SB),NOSPLIT,$-4
-	MOVW 0(FP), R0	// arg 1 - nss
-	MOVW 4(FP), R1	// arg 2 - oss
+	MOVW new+0(FP), R0	// arg 1 - nss
+	MOVW old+4(FP), R1	// arg 2 - oss
 	SWI $0xa00119	// sys___sigaltstack14
 	MOVW.CS $0, R8	// crash on syscall failure
 	MOVW.CS R8, (R8)
 	RET
 
 TEXT runtime·sysctl(SB),NOSPLIT,$8
-	MOVW 0(FP), R0	// arg 1 - name
-	MOVW 4(FP), R1	// arg 2 - namelen
-	MOVW 8(FP), R2	// arg 3 - oldp
-	MOVW 12(FP), R3	// arg 4 - oldlenp
-	MOVW 16(FP), R4	// arg 5 - newp
+	MOVW mib+0(FP), R0	// arg 1 - name
+	MOVW miblen+4(FP), R1	// arg 2 - namelen
+	MOVW out+8(FP), R2	// arg 3 - oldp
+	MOVW size+12(FP), R3	// arg 4 - oldlenp
+	MOVW dst+16(FP), R4	// arg 5 - newp
 	MOVW R4, 4(R13)
-	MOVW 20(FP), R4	// arg 6 - newlen
+	MOVW ndst+20(FP), R4	// arg 6 - newlen
 	MOVW R4, 8(R13)
 	ADD $4, R13	// pass arg 5 and 6 on stack
 	SWI $0xa000ca	// sys___sysctl
@@ -307,13 +315,13 @@ TEXT runtime·kqueue(SB),NOSPLIT,$0
 
 // int32 runtime·kevent(int kq, Kevent *changelist, int nchanges, Kevent *eventlist, int nevents, Timespec *timeout)
 TEXT runtime·kevent(SB),NOSPLIT,$8
-	MOVW 0(FP), R0	// kq
-	MOVW 4(FP), R1	// changelist
-	MOVW 8(FP), R2	// nchanges
-	MOVW 12(FP), R3	// eventlist
-	MOVW 16(FP), R4	// nevents
+	MOVW kq+0(FP), R0	// kq
+	MOVW ch+4(FP), R1	// changelist
+	MOVW nch+8(FP), R2	// nchanges
+	MOVW ev+12(FP), R3	// eventlist
+	MOVW nev+16(FP), R4	// nevents
 	MOVW R4, 4(R13)
-	MOVW 20(FP), R4	// timeout
+	MOVW ts+20(FP), R4	// timeout
 	MOVW R4, 8(R13)
 	ADD $4, R13	// pass arg 5 and 6 on stack
 	SWI $0xa001b3	// sys___kevent50
@@ -324,13 +332,13 @@ TEXT runtime·kevent(SB),NOSPLIT,$8
 
 // void runtime·closeonexec(int32 fd)
 TEXT runtime·closeonexec(SB),NOSPLIT,$0
-	MOVW 0(FP), R0	// fd
+	MOVW fd+0(FP), R0	// fd
 	MOVW $2, R1	// F_SETFD
 	MOVW $1, R2	// FD_CLOEXEC
 	SWI $0xa0005c	// sys_fcntl
 	RET
 
-TEXT runtime·casp(SB),NOSPLIT,$0
+TEXT runtime·casp1(SB),NOSPLIT,$0
 	B	runtime·cas(SB)
 
 // TODO(minux): this is only valid for ARMv6+
@@ -344,6 +352,10 @@ TEXT runtime·casp(SB),NOSPLIT,$0
 TEXT runtime·cas(SB),NOSPLIT,$0
 	B runtime·armcas(SB)
 
+// TODO: this is only valid for ARMv7+
+TEXT ·publicationBarrier(SB),NOSPLIT,$-4-0
+	B	runtime·armPublicationBarrier(SB)
+
 TEXT runtime·read_tls_fallback(SB),NOSPLIT,$-4
 	MOVM.WP [R1, R2, R3, R12], (R13)
 	SWI $0x00a0013c // _lwp_getprivate
diff --git a/src/runtime/sys_openbsd_386.s b/src/runtime/sys_openbsd_386.s
index 5cda776..bdf18d8 100644
--- a/src/runtime/sys_openbsd_386.s
+++ b/src/runtime/sys_openbsd_386.s
@@ -6,7 +6,8 @@
 // /usr/src/sys/kern/syscalls.master for syscall numbers.
 //
 
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
 #include "textflag.h"
 
 #define	CLOCK_MONOTONIC	$3
@@ -30,24 +31,32 @@ TEXT runtime·exit1(SB),NOSPLIT,$8
 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
+TEXT runtime·closefd(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
 
@@ -81,6 +90,17 @@ TEXT runtime·raise(SB),NOSPLIT,$12
 	INT	$0x80
 	RET
 
+TEXT runtime·raiseproc(SB),NOSPLIT,$12
+	MOVL	$20, AX			// sys_getpid
+	INT	$0x80
+	MOVL	$0, 0(SP)
+	MOVL	AX, 4(SP)		// arg 1 - pid
+	MOVL	sig+0(FP), AX
+	MOVL	AX, 8(SP)		// arg 2 - signum
+	MOVL	$37, AX			// sys_kill
+	INT	$0x80
+	RET
+
 TEXT runtime·mmap(SB),NOSPLIT,$36
 	LEAL	addr+0(FP), SI
 	LEAL	4(SP), DI
@@ -186,7 +206,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$44
 	MOVL	BX, 0(SP)
 	MOVL	$runtime·badsignal(SB), AX
 	CALL	AX
-	JMP 	sigtramp_ret
+	JMP 	ret
 
 	// save g
 	MOVL	DI, 20(SP)
@@ -212,7 +232,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$44
 	MOVL	20(SP), BX
 	MOVL	BX, g(CX)
 
-sigtramp_ret:
+ret:
 	// call sigreturn
 	MOVL	context+8(FP), AX
 	MOVL	$0, 0(SP)		// syscall gap
@@ -316,9 +336,9 @@ TEXT runtime·setldt(SB),NOSPLIT,$4
 	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 4e9db23..213ffc1 100644
--- a/src/runtime/sys_openbsd_amd64.s
+++ b/src/runtime/sys_openbsd_amd64.s
@@ -6,7 +6,8 @@
 // /usr/src/sys/kern/syscalls.master for syscall numbers.
 //
 
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
 #include "textflag.h"
 
 #define CLOCK_MONOTONIC	$3
@@ -100,13 +101,17 @@ TEXT runtime·open(SB),NOSPLIT,$-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
 
-TEXT runtime·close(SB),NOSPLIT,$-8
+TEXT runtime·closefd(SB),NOSPLIT,$-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
 
@@ -116,6 +121,8 @@ TEXT runtime·read(SB),NOSPLIT,$-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
 
@@ -125,6 +132,8 @@ TEXT runtime·write(SB),NOSPLIT,$-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
 
@@ -153,6 +162,15 @@ TEXT runtime·raise(SB),NOSPLIT,$16
 	SYSCALL
 	RET
 
+TEXT runtime·raiseproc(SB),NOSPLIT,$16
+	MOVL	$20, AX			// sys_getpid
+	SYSCALL
+	MOVQ	AX, DI			// arg 1 - pid
+	MOVL	sig+0(FP), SI		// arg 2 - signum
+	MOVL	$37, AX			// sys_kill
+	SYSCALL
+	RET
+
 TEXT runtime·setitimer(SB),NOSPLIT,$-8
 	MOVL	mode+0(FP), DI		// arg 1 - which
 	MOVQ	new+8(FP), SI		// arg 2 - itv
@@ -226,9 +244,9 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$64
 	MOVQ	R10, 40(SP)
 	
 	// g = m->signal
-	MOVQ	g_m(R10), BP
-	MOVQ	m_gsignal(BP), BP
-	MOVQ	BP, g(BX)
+	MOVQ	g_m(R10), AX
+	MOVQ	m_gsignal(AX), AX
+	MOVQ	AX, g(BX)
 	
 	MOVQ	DI, 0(SP)
 	MOVQ	SI, 8(SP)
@@ -289,7 +307,7 @@ TEXT runtime·sigaltstack(SB),NOSPLIT,$-8
 // 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..60deb8f
--- /dev/null
+++ b/src/runtime/sys_openbsd_arm.s
@@ -0,0 +1,390 @@
+// 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·closefd(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
+	CALL	runtime·usplitR0(SB)
+	MOVW	R0, 4(R13)		// tv_sec - l32
+	MOVW	$0, R0
+	MOVW	R0, 8(R13)		// tv_sec - h32
+	MOVW	$1000, R2
+	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·raiseproc(SB),NOSPLIT,$12
+	MOVW	$20, R12
+	SWI	$0			// sys_getpid
+					// 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)
+
+TEXT ·publicationBarrier(SB),NOSPLIT,$-4-0
+	B	runtime·armPublicationBarrier(SB)
+
+// TODO(jsing): Implement.
+TEXT runtime·read_tls_fallback(SB),NOSPLIT,$-4
+	MOVW	$5, R0
+	MOVW	R0, (R0)
+	RET
diff --git a/src/runtime/sys_plan9_386.s b/src/runtime/sys_plan9_386.s
index a41b562..cae326a 100644
--- a/src/runtime/sys_plan9_386.s
+++ b/src/runtime/sys_plan9_386.s
@@ -2,7 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
 #include "textflag.h"
 
 // setldt(int entry, int address, int limit)
@@ -51,7 +52,7 @@ TEXT runtime·seek(SB),NOSPLIT,$24
 	MOVL	$-1, ret_hi+20(FP)
 	RET
 
-TEXT runtime·close(SB),NOSPLIT,$0
+TEXT runtime·closefd(SB),NOSPLIT,$0
 	MOVL	$4, AX
 	INT	$64
 	MOVL	AX, ret+4(FP)
diff --git a/src/runtime/sys_plan9_amd64.s b/src/runtime/sys_plan9_amd64.s
index 3a96c2b..6aefe5f 100644
--- a/src/runtime/sys_plan9_amd64.s
+++ b/src/runtime/sys_plan9_amd64.s
@@ -2,7 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
 #include "textflag.h"
 
 // setldt(int entry, int address, int limit)
@@ -50,7 +51,7 @@ TEXT runtime·seek(SB),NOSPLIT,$32
 	MOVQ	$-1, ret+24(FP)
 	RET
 
-TEXT runtime·close(SB),NOSPLIT,$0
+TEXT runtime·closefd(SB),NOSPLIT,$0
 	MOVQ	$4, BP
 	SYSCALL
 	MOVL	AX, ret+8(FP)
diff --git a/src/runtime/sys_ppc64x.go b/src/runtime/sys_ppc64x.go
new file mode 100644
index 0000000..bd182e3
--- /dev/null
+++ b/src/runtime/sys_ppc64x.go
@@ -0,0 +1,37 @@
+// 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 ppc64 ppc64le
+
+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))
+		if inst>>26 == 18 && inst&3 == 0 {
+			//print("runtime: rewind pc=", hex(buf.pc), " to pc=", hex(uintptr(buf.pc + int32(inst<<6)>>6)), "\n");
+			buf.pc += uintptr(int32(inst<<6) >> 6)
+			return
+		}
+	}
+	print("runtime: pc=", hex(buf.pc), " ", hex(inst), "\n")
+	throw("runtime: misuse of rewindmorestack")
+}
diff --git a/src/runtime/sys_solaris_amd64.s b/src/runtime/sys_solaris_amd64.s
index 0ebdab6..e431564 100644
--- a/src/runtime/sys_solaris_amd64.s
+++ b/src/runtime/sys_solaris_amd64.s
@@ -6,14 +6,15 @@
 // /usr/include/sys/syscall.h for syscall numbers.
 //
 
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
 #include "textflag.h"
 
 // This is needed by asm_amd64.s
 TEXT runtime·settls(SB),NOSPLIT,$8
 	RET
 
-// void libc·miniterrno(void *(*___errno)(void));
+// void libc_miniterrno(void *(*___errno)(void));
 //
 // Set the TLS errno pointer in M.
 //
@@ -40,7 +41,7 @@ TEXT runtime·nanotime1(SB),NOSPLIT,$0
 	SUBQ	$64, SP	// 16 bytes will do, but who knows in the future?
 	MOVQ	$3, DI	// CLOCK_REALTIME from <sys/time_impl.h>
 	MOVQ	SP, SI
-	MOVQ	libc·clock_gettime(SB), AX
+	LEAQ	libc_clock_gettime(SB), AX
 	CALL	AX
 	MOVQ	(SP), AX	// tv_sec from struct timespec
 	IMULQ	$1000000000, AX	// multiply into nanoseconds
@@ -53,7 +54,7 @@ TEXT runtime·nanotime1(SB),NOSPLIT,$0
 TEXT runtime·pipe1(SB),NOSPLIT,$0
 	SUBQ	$16, SP // 8 bytes will do, but stack has to be 16-byte alligned
 	MOVQ	SP, DI
-	MOVQ	libc·pipe(SB), AX
+	LEAQ	libc_pipe(SB), AX
 	CALL	AX
 	MOVL	0(SP), AX
 	MOVL	4(SP), DX
@@ -132,7 +133,7 @@ TEXT runtime·tstart_sysvicall(SB),NOSPLIT,$0
 	MOVQ	AX, (g_stack+stack_hi)(DX)
 	SUBQ	$(0x100000), AX		// stack size
 	MOVQ	AX, (g_stack+stack_lo)(DX)
-	ADDQ	$const_StackGuard, AX
+	ADDQ	$const__StackGuard, AX
 	MOVQ	AX, g_stackguard0(DX)
 	MOVQ	AX, g_stackguard1(DX)
 
@@ -287,24 +288,24 @@ TEXT runtime·usleep1(SB),NOSPLIT,$0
 	// Execute call on m->g0.
 	get_tls(R15)
 	CMPQ	R15, $0
-	JE	usleep1_noswitch
+	JE	noswitch
 
 	MOVQ	g(R15), R13
 	CMPQ	R13, $0
-	JE	usleep1_noswitch
+	JE	noswitch
 	MOVQ	g_m(R13), R13
 	CMPQ	R13, $0
-	JE	usleep1_noswitch
+	JE	noswitch
 	// TODO(aram): do something about the cpu profiler here.
 
 	MOVQ	m_g0(R13), R14
 	CMPQ	g(R15), R14
-	JNE	usleep1_switch
+	JNE	switch
 	// executing on m->g0 already
 	CALL	AX
 	RET
 
-usleep1_switch:
+switch:
 	// Switch to m->g0 stack and back.
 	MOVQ	(g_sched+gobuf_sp)(R14), R14
 	MOVQ	SP, -8(R14)
@@ -313,20 +314,20 @@ usleep1_switch:
 	MOVQ	0(SP), SP
 	RET
 
-usleep1_noswitch:
+noswitch:
 	// Not a Go-managed thread. Do not switch stack.
 	CALL	AX
 	RET
 
 // Runs on OS stack. duration (in µs units) is in DI.
 TEXT runtime·usleep2(SB),NOSPLIT,$0
-	MOVQ	libc·usleep(SB), AX
+	LEAQ	libc_usleep(SB), AX
 	CALL	AX
 	RET
 
 // Runs on OS stack, called from runtime·osyield.
 TEXT runtime·osyield1(SB),NOSPLIT,$0
-	MOVQ	libc·sched_yield(SB), AX
+	LEAQ	libc_sched_yield(SB), AX
 	CALL	AX
 	RET
 
diff --git a/src/runtime/sys_windows_386.s b/src/runtime/sys_windows_386.s
index 932fe9d..e5fe88a 100644
--- a/src/runtime/sys_windows_386.s
+++ b/src/runtime/sys_windows_386.s
@@ -2,7 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
 #include "textflag.h"
 
 // void runtime·asmstdcall(void *c);
@@ -43,7 +44,7 @@ TEXT	runtime·badsignal2(SB),NOSPLIT,$24
 	// stderr
 	MOVL	$-12, 0(SP)
 	MOVL	SP, BP
-	CALL	*runtime·GetStdHandle(SB)
+	CALL	*runtime·_GetStdHandle(SB)
 	MOVL	BP, SP
 
 	MOVL	AX, 0(SP)	// handle
@@ -55,7 +56,7 @@ TEXT	runtime·badsignal2(SB),NOSPLIT,$24
 	MOVL	$0, 0(DX)
 	MOVL	DX, 12(SP)
 	MOVL	$0, 16(SP) // overlapped
-	CALL	*runtime·WriteFile(SB)
+	CALL	*runtime·_WriteFile(SB)
 	MOVL	BP, SI
 	RET
 
@@ -106,7 +107,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0-0
 	MOVL	g_m(DX), BX
 	MOVL	m_g0(BX), BX
 	CMPL	DX, BX
-	JEQ	sigtramp_g0
+	JEQ	g0
 
 	// switch to the g0 stack
 	get_tls(BP)
@@ -123,7 +124,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0-0
 	MOVL	SP, 36(DI)
 	MOVL	DI, SP
 
-sigtramp_g0:
+g0:
 	MOVL	0(CX), BX // ExceptionRecord*
 	MOVL	4(CX), CX // Context*
 	MOVL	BX, 0(SP)
@@ -188,33 +189,35 @@ TEXT runtime·externalthreadhandler(SB),NOSPLIT,$0
 	MOVL	SP, DX
 
 	// setup dummy m, g
-	SUBL	$m_end, SP		// space for M
+	SUBL	$m__size, SP		// space for M
 	MOVL	SP, 0(SP)
-	MOVL	$m_end, 4(SP)
+	MOVL	$m__size, 4(SP)
 	CALL	runtime·memclr(SB)	// smashes AX,BX,CX
 
 	LEAL	m_tls(SP), CX
 	MOVL	CX, 0x14(FS)
 	MOVL	SP, BX
-	SUBL	$g_end, SP		// space for G
+	SUBL	$g__size, SP		// space for G
 	MOVL	SP, g(CX)
 	MOVL	SP, m_g0(BX)
 
 	MOVL	SP, 0(SP)
-	MOVL	$g_end, 4(SP)
+	MOVL	$g__size, 4(SP)
 	CALL	runtime·memclr(SB)	// smashes AX,BX,CX
-	LEAL	g_end(SP), BX
+	LEAL	g__size(SP), BX
 	MOVL	BX, g_m(SP)
 	LEAL	-8192(SP), CX
 	MOVL	CX, (g_stack+stack_lo)(SP)
-	ADDL	$const_StackGuard, CX
+	ADDL	$const__StackGuard, CX
 	MOVL	CX, g_stackguard0(SP)
 	MOVL	CX, g_stackguard1(SP)
 	MOVL	DX, (g_stack+stack_hi)(SP)
 
+	PUSHL	AX			// room for return value
 	PUSHL	16(BP)			// arg for handler
 	CALL	8(BP)
 	POPL	CX
+	POPL	AX			// pass return value to Windows in AX
 
 	get_tls(CX)
 	MOVL	g(CX), CX
@@ -247,15 +250,15 @@ TEXT runtime·callbackasm1+0(SB),NOSPLIT,$0
 	SUBL	$runtime·callbackasm(SB), AX
 	MOVL	$0, DX
 	MOVL	$5, BX	// divide by 5 because each call instruction in runtime·callbacks is 5 bytes long
-	DIVL	BX,
+	DIVL	BX
 
 	// find correspondent runtime·cbctxts table entry
 	MOVL	runtime·cbctxts(SB), BX
 	MOVL	-4(BX)(AX*4), BX
 
 	// extract callback context
-	MOVL	cbctxt_gobody(BX), AX
-	MOVL	cbctxt_argsize(BX), DX
+	MOVL	wincallbackcontext_gobody(BX), AX
+	MOVL	wincallbackcontext_argsize(BX), DX
 
 	// preserve whatever's at the memory location that
 	// the callback will use to store the return value
@@ -265,7 +268,7 @@ TEXT runtime·callbackasm1+0(SB),NOSPLIT,$0
 	ADDL	$4, DX
 
 	// remember how to restore stack on return
-	MOVL	cbctxt_restorestack(BX), BX
+	MOVL	wincallbackcontext_restorestack(BX), BX
 	PUSHL	BX
 
 	// call target Go function
@@ -313,7 +316,7 @@ TEXT runtime·tstart(SB),NOSPLIT,$0
 	MOVL	AX, (g_stack+stack_hi)(DX)
 	SUBL	$(64*1024), AX		// stack size
 	MOVL	AX, (g_stack+stack_lo)(DX)
-	ADDL	$const_StackGuard, AX
+	ADDL	$const__StackGuard, AX
 	MOVL	AX, g_stackguard0(DX)
 	MOVL	AX, g_stackguard1(DX)
 
@@ -383,12 +386,12 @@ TEXT runtime·usleep1(SB),NOSPLIT,$0
 
 	MOVL	m_g0(BP), SI
 	CMPL	g(CX), SI
-	JNE	usleep1_switch
+	JNE	switch
 	// executing on m->g0 already
 	CALL	AX
-	JMP	usleep1_ret
+	JMP	ret
 
-usleep1_switch:
+switch:
 	// Switch to m->g0 stack and back.
 	MOVL	(g_sched+gobuf_sp)(SI), SI
 	MOVL	SP, -4(SI)
@@ -396,7 +399,7 @@ usleep1_switch:
 	CALL	AX
 	MOVL	0(SP), SP
 
-usleep1_ret:
+ret:
 	get_tls(CX)
 	MOVL	g(CX), BP
 	MOVL	g_m(BP), BP
@@ -414,7 +417,7 @@ TEXT runtime·usleep2(SB),NOSPLIT,$20
 	MOVL	$0, alertable-16(SP)
 	MOVL	$-1, handle-20(SP)
 	MOVL	SP, BP
-	MOVL	runtime·NtWaitForSingleObject(SB), AX
+	MOVL	runtime·_NtWaitForSingleObject(SB), AX
 	CALL	AX
 	MOVL	BP, SP
 	RET
diff --git a/src/runtime/sys_windows_amd64.s b/src/runtime/sys_windows_amd64.s
index e6190ce..ea4f3e0 100644
--- a/src/runtime/sys_windows_amd64.s
+++ b/src/runtime/sys_windows_amd64.s
@@ -2,7 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
 #include "textflag.h"
 
 // maxargs should be divisible by 2, as Windows stack
@@ -65,7 +66,7 @@ TEXT runtime·badsignal2(SB),NOSPLIT,$48
 	// stderr
 	MOVQ	$-12, CX // stderr
 	MOVQ	CX, 0(SP)
-	MOVQ	runtime·GetStdHandle(SB), AX
+	MOVQ	runtime·_GetStdHandle(SB), AX
 	CALL	AX
 
 	MOVQ	AX, CX	// handle
@@ -78,7 +79,7 @@ TEXT runtime·badsignal2(SB),NOSPLIT,$48
 	MOVQ	$0, 0(R9)
 	MOVQ	R9, 24(SP)
 	MOVQ	$0, 32(SP)	// overlapped
-	MOVQ	runtime·WriteFile(SB), AX
+	MOVQ	runtime·_WriteFile(SB), AX
 	CALL	AX
 	
 	RET
@@ -138,7 +139,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0-0
 	MOVQ	g_m(DX), BX
 	MOVQ	m_g0(BX), BX
 	CMPQ	DX, BX
-	JEQ	sigtramp_g0
+	JEQ	g0
 
 	// switch to g0 stack
 	get_tls(BP)
@@ -157,7 +158,7 @@ TEXT runtime·sigtramp(SB),NOSPLIT,$0-0
 	MOVQ	SP, 104(DI)
 	MOVQ	DI, SP
 
-sigtramp_g0:
+g0:
 	MOVQ	0(CX), BX // ExceptionRecord*
 	MOVQ	8(CX), CX // Context*
 	MOVQ	BX, 0(SP)
@@ -224,34 +225,36 @@ TEXT runtime·externalthreadhandler(SB),NOSPLIT,$0
 	MOVQ	SP, DX
 
 	// setup dummy m, g
-	SUBQ	$m_end, SP		// space for M
+	SUBQ	$m__size, SP		// space for M
 	MOVQ	SP, 0(SP)
-	MOVQ	$m_end, 8(SP)
+	MOVQ	$m__size, 8(SP)
 	CALL	runtime·memclr(SB)	// smashes AX,BX,CX
 
 	LEAQ	m_tls(SP), CX
 	MOVQ	CX, 0x28(GS)
 	MOVQ	SP, BX
-	SUBQ	$g_end, SP		// space for G
+	SUBQ	$g__size, SP		// space for G
 	MOVQ	SP, g(CX)
 	MOVQ	SP, m_g0(BX)
 
 	MOVQ	SP, 0(SP)
-	MOVQ	$g_end, 8(SP)
+	MOVQ	$g__size, 8(SP)
 	CALL	runtime·memclr(SB)	// smashes AX,BX,CX
-	LEAQ	g_end(SP), BX
+	LEAQ	g__size(SP), BX
 	MOVQ	BX, g_m(SP)
 
 	LEAQ	-8192(SP), CX
 	MOVQ	CX, (g_stack+stack_lo)(SP)
-	ADDQ	$const_StackGuard, CX
+	ADDQ	$const__StackGuard, CX
 	MOVQ	CX, g_stackguard0(SP)
 	MOVQ	CX, g_stackguard1(SP)
 	MOVQ	DX, (g_stack+stack_hi)(SP)
 
+	PUSHQ	AX			// room for return value
 	PUSHQ	32(BP)			// arg for handler
 	CALL	16(BP)
 	POPQ	CX
+	POPQ	AX			// pass return value to Windows in AX
 
 	get_tls(CX)
 	MOVQ	g(CX), CX
@@ -286,15 +289,15 @@ TEXT runtime·callbackasm1(SB),NOSPLIT,$0
 	SUBQ	DX, AX
 	MOVQ	$0, DX
 	MOVQ	$5, CX	// divide by 5 because each call instruction in runtime·callbacks is 5 bytes long
-	DIVL	CX,
+	DIVL	CX
 
 	// find correspondent runtime·cbctxts table entry
 	MOVQ	runtime·cbctxts(SB), CX
 	MOVQ	-8(CX)(AX*8), AX
 
 	// extract callback context
-	MOVQ	cbctxt_argsize(AX), DX
-	MOVQ	cbctxt_gobody(AX), AX
+	MOVQ	wincallbackcontext_argsize(AX), DX
+	MOVQ	wincallbackcontext_gobody(AX), AX
 
 	// preserve whatever's at the memory location that
 	// the callback will use to store the return value
@@ -354,7 +357,7 @@ TEXT runtime·tstart_stdcall(SB),NOSPLIT,$0
 	MOVQ	AX, (g_stack+stack_hi)(DX)
 	SUBQ	$(64*1024), AX		// stack size
 	MOVQ	AX, (g_stack+stack_lo)(DX)
-	ADDQ	$const_StackGuard, AX
+	ADDQ	$const__StackGuard, AX
 	MOVQ	AX, g_stackguard0(DX)
 	MOVQ	AX, g_stackguard1(DX)
 
@@ -407,12 +410,12 @@ TEXT runtime·usleep1(SB),NOSPLIT,$0
 
 	MOVQ	m_g0(R13), R14
 	CMPQ	g(R15), R14
-	JNE	usleep1_switch
+	JNE	switch
 	// executing on m->g0 already
 	CALL	AX
-	JMP	usleep1_ret
+	JMP	ret
 
-usleep1_switch:
+switch:
 	// Switch to m->g0 stack and back.
 	MOVQ	(g_sched+gobuf_sp)(R14), R14
 	MOVQ	SP, -8(R14)
@@ -420,7 +423,7 @@ usleep1_switch:
 	CALL	AX
 	MOVQ	0(SP), SP
 
-usleep1_ret:
+ret:
 	MOVQ	$0, m_libcallsp(R13)
 	RET
 
@@ -435,7 +438,7 @@ TEXT runtime·usleep2(SB),NOSPLIT,$16
 	MOVQ	BX, (R8)
 	MOVQ	$-1, CX // handle
 	MOVQ	$0, DX // alertable
-	MOVQ	runtime·NtWaitForSingleObject(SB), AX
+	MOVQ	runtime·_NtWaitForSingleObject(SB), AX
 	CALL	AX
 	MOVQ	8(SP), SP
 	RET
diff --git a/src/runtime/sys_x86.c b/src/runtime/sys_x86.c
deleted file mode 100644
index a450b3e..0000000
--- a/src/runtime/sys_x86.c
+++ /dev/null
@@ -1,57 +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.
-
-// +build amd64 amd64p32 386
-
-#include "runtime.h"
-
-// adjust Gobuf as it if executed a call to fn with context ctxt
-// and then did an immediate gosave.
-void
-runtime·gostartcall(Gobuf *gobuf, void (*fn)(void), void *ctxt)
-{
-	uintptr *sp;
-	
-	sp = (uintptr*)gobuf->sp;
-	if(sizeof(uintreg) > sizeof(uintptr))
-		*--sp = 0;
-	*--sp = (uintptr)gobuf->pc;
-	gobuf->sp = (uintptr)sp;
-	gobuf->pc = (uintptr)fn;
-	gobuf->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.
-void
-runtime·rewindmorestack(Gobuf *gobuf)
-{
-	byte *pc;
-
-	pc = (byte*)gobuf->pc;
-	if(pc[0] == 0xe9) { // jmp 4-byte offset
-		gobuf->pc = gobuf->pc + 5 + *(int32*)(pc+1);
-		return;
-	}
-	if(pc[0] == 0xeb) { // jmp 1-byte offset
-		gobuf->pc = gobuf->pc + 2 + *(int8*)(pc+1);
-		return;
-	}
-	if(pc[0] == 0xcc) {
-		// This is a breakpoint inserted by gdb.  We could use
-		// runtime·findfunc to find the function.  But if we
-		// do that, then we will continue execution at the
-		// function entry point, and we will not hit the gdb
-		// breakpoint.  So for this case we don't change
-		// gobuf->pc, so that when we return we will execute
-		// the jump instruction and carry on.  This means that
-		// stack unwinding may not work entirely correctly
-		// (http://golang.org/issue/5723) but the user is
-		// running under gdb anyhow.
-		return;
-	}
-	runtime·printf("runtime: pc=%p %x %x %x %x %x\n", pc, pc[0], pc[1], pc[2], pc[3], pc[4]);
-	runtime·throw("runtime: misuse of rewindmorestack");
-}
diff --git a/src/runtime/sys_x86.go b/src/runtime/sys_x86.go
new file mode 100644
index 0000000..3f0771f
--- /dev/null
+++ b/src/runtime/sys_x86.go
@@ -0,0 +1,54 @@
+// 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 amd64 amd64p32 386
+
+package runtime
+
+import "unsafe"
+
+// adjust Gobuf as it if executed a call to fn with context ctxt
+// and then did an immediate gosave.
+func gostartcall(buf *gobuf, fn, ctxt unsafe.Pointer) {
+	sp := buf.sp
+	if regSize > ptrSize {
+		sp -= ptrSize
+		*(*uintptr)(unsafe.Pointer(sp)) = 0
+	}
+	sp -= ptrSize
+	*(*uintptr)(unsafe.Pointer(sp)) = buf.pc
+	buf.sp = sp
+	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) {
+	pc := (*[8]byte)(unsafe.Pointer(buf.pc))
+	if pc[0] == 0xe9 { // jmp 4-byte offset
+		buf.pc = buf.pc + 5 + uintptr(int64(*(*int32)(unsafe.Pointer(&pc[1]))))
+		return
+	}
+	if pc[0] == 0xeb { // jmp 1-byte offset
+		buf.pc = buf.pc + 2 + uintptr(int64(*(*int8)(unsafe.Pointer(&pc[1]))))
+		return
+	}
+	if pc[0] == 0xcc {
+		// This is a breakpoint inserted by gdb.  We could use
+		// runtime·findfunc to find the function.  But if we
+		// do that, then we will continue execution at the
+		// function entry point, and we will not hit the gdb
+		// breakpoint.  So for this case we don't change
+		// buf.pc, so that when we return we will execute
+		// the jump instruction and carry on.  This means that
+		// stack unwinding may not work entirely correctly
+		// (https://golang.org/issue/5723) but the user is
+		// running under gdb anyhow.
+		return
+	}
+	print("runtime: pc=", pc, " ", hex(pc[0]), " ", hex(pc[1]), " ", hex(pc[2]), " ", hex(pc[3]), " ", hex(pc[4]), "\n")
+	throw("runtime: misuse of rewindmorestack")
+}
diff --git a/src/runtime/syscall2_solaris.go b/src/runtime/syscall2_solaris.go
new file mode 100644
index 0000000..df72996
--- /dev/null
+++ b/src/runtime/syscall2_solaris.go
@@ -0,0 +1,49 @@
+// 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" // for go:linkname
+
+//go:cgo_import_dynamic libc_chdir chdir "libc.so"
+//go:cgo_import_dynamic libc_chroot chroot "libc.so"
+//go:cgo_import_dynamic libc_close close "libc.so"
+//go:cgo_import_dynamic libc_dlclose dlclose "libc.so"
+//go:cgo_import_dynamic libc_dlopen dlopen "libc.so"
+//go:cgo_import_dynamic libc_dlsym dlsym "libc.so"
+//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 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"
+
+//go:linkname libc_chdir libc_chdir
+//go:linkname libc_chroot libc_chroot
+//go:linkname libc_close libc_close
+//go:linkname libc_dlclose libc_dlclose
+//go:linkname libc_dlopen libc_dlopen
+//go:linkname libc_dlsym libc_dlsym
+//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
+//go:linkname libc_setgroups libc_setgroups
+//go:linkname libc_setsid libc_setsid
+//go:linkname libc_setuid libc_setuid
+//go:linkname libc_setpgid libc_setpgid
+//go:linkname libc_syscall libc_syscall
+//go:linkname libc_forkx libc_forkx
+//go:linkname libc_wait4 libc_wait4
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.c b/src/runtime/syscall_solaris.c
deleted file mode 100644
index 13ac31b..0000000
--- a/src/runtime/syscall_solaris.c
+++ /dev/null
@@ -1,23 +0,0 @@
-// 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.
-
-#pragma dynimport libc·chdir chdir "libc.so"
-#pragma dynimport libc·chroot chroot "libc.so"
-#pragma dynimport libc·close close "libc.so"
-#pragma dynimport libc·dlclose dlclose "libc.so"
-#pragma dynimport libc·dlopen dlopen "libc.so"
-#pragma dynimport libc·dlsym dlsym "libc.so"
-#pragma dynimport libc·execve execve "libc.so"
-#pragma dynimport libc·fcntl fcntl "libc.so"
-#pragma dynimport libc·gethostname gethostname "libc.so"
-#pragma dynimport libc·ioctl ioctl "libc.so"
-#pragma dynimport libc·pipe pipe "libc.so"
-#pragma dynimport libc·setgid setgid "libc.so"
-#pragma dynimport libc·setgroups setgroups "libc.so"
-#pragma dynimport libc·setsid setsid "libc.so"
-#pragma dynimport libc·setuid setuid "libc.so"
-#pragma dynimport libc·setpgid setsid "libc.so"
-#pragma dynimport libc·syscall syscall "libc.so"
-#pragma dynimport libc·forkx forkx "libc.so"
-#pragma dynimport libc·wait4 wait4 "libc.so"
diff --git a/src/runtime/syscall_solaris.go b/src/runtime/syscall_solaris.go
index 50d3a1d..ae1f334 100644
--- a/src/runtime/syscall_solaris.go
+++ b/src/runtime/syscall_solaris.go
@@ -9,15 +9,11 @@ import "unsafe"
 var (
 	libc_chdir,
 	libc_chroot,
-	libc_close,
-	libc_dlopen,
-	libc_dlclose,
-	libc_dlsym,
 	libc_execve,
-	libc_exit,
 	libc_fcntl,
 	libc_forkx,
 	libc_gethostname,
+	libc_getpid,
 	libc_ioctl,
 	libc_pipe,
 	libc_setgid,
@@ -27,7 +23,6 @@ var (
 	libc_setpgid,
 	libc_syscall,
 	libc_wait4,
-	libc_write,
 	pipe1 libcFunc
 )
 
@@ -38,9 +33,9 @@ func syscall_sysvicall6(fn, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err
 		n:    nargs,
 		args: uintptr(unsafe.Pointer(&a1)),
 	}
-	entersyscallblock()
+	entersyscallblock(0)
 	asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call))
-	exitsyscall()
+	exitsyscall(0)
 	return call.r1, call.r2, call.err
 }
 
@@ -87,48 +82,6 @@ func syscall_close(fd int32) int32 {
 	return int32(sysvicall1(&libc_close, uintptr(fd)))
 }
 
-func syscall_dlopen(name *byte, mode uintptr) (handle uintptr, err uintptr) {
-	call := libcall{
-		fn:   uintptr(unsafe.Pointer(&libc_dlopen)),
-		n:    2,
-		args: uintptr(unsafe.Pointer(&name)),
-	}
-	entersyscallblock()
-	asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call))
-	exitsyscall()
-	if call.r1 == 0 {
-		return call.r1, call.err
-	}
-	return call.r1, 0
-}
-
-func syscall_dlclose(handle uintptr) (err uintptr) {
-	call := libcall{
-		fn:   uintptr(unsafe.Pointer(&libc_dlclose)),
-		n:    1,
-		args: uintptr(unsafe.Pointer(&handle)),
-	}
-	entersyscallblock()
-	asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call))
-	exitsyscall()
-	return call.r1
-}
-
-func syscall_dlsym(handle uintptr, name *byte) (proc uintptr, err uintptr) {
-	call := libcall{
-		fn:   uintptr(unsafe.Pointer(&libc_dlsym)),
-		n:    2,
-		args: uintptr(unsafe.Pointer(&handle)),
-	}
-	entersyscallblock()
-	asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call))
-	exitsyscall()
-	if call.r1 == 0 {
-		return call.r1, call.err
-	}
-	return call.r1, 0
-}
-
 //go:nosplit
 func syscall_execve(path, argv, envp uintptr) (err uintptr) {
 	call := libcall{
@@ -176,9 +129,9 @@ func syscall_gethostname() (name string, err uintptr) {
 		n:    2,
 		args: uintptr(unsafe.Pointer(&args[0])),
 	}
-	entersyscallblock()
+	entersyscallblock(0)
 	asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call))
-	exitsyscall()
+	exitsyscall(0)
 	if call.r1 != 0 {
 		return "", call.err
 	}
@@ -187,6 +140,17 @@ func syscall_gethostname() (name string, err uintptr) {
 }
 
 //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)),
@@ -203,9 +167,9 @@ func syscall_pipe() (r, w, err uintptr) {
 		n:    0,
 		args: uintptr(unsafe.Pointer(&pipe1)), // it's unused but must be non-nil, otherwise crashes
 	}
-	entersyscallblock()
+	entersyscallblock(0)
 	asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call))
-	exitsyscall()
+	exitsyscall(0)
 	return call.r1, call.r2, call.err
 }
 
@@ -292,9 +256,9 @@ func syscall_syscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr) {
 		n:    4,
 		args: uintptr(unsafe.Pointer(&trap)),
 	}
-	entersyscallblock()
+	entersyscallblock(0)
 	asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call))
-	exitsyscall()
+	exitsyscall(0)
 	return call.r1, call.r2, call.err
 }
 
@@ -304,9 +268,9 @@ func syscall_wait4(pid uintptr, wstatus *uint32, options uintptr, rusage unsafe.
 		n:    4,
 		args: uintptr(unsafe.Pointer(&pid)),
 	}
-	entersyscallblock()
+	entersyscallblock(0)
 	asmcgocall(unsafe.Pointer(&asmsysvicall6), unsafe.Pointer(&call))
-	exitsyscall()
+	exitsyscall(0)
 	return int(call.r1), call.err
 }
 
diff --git a/src/runtime/syscall_windows.go b/src/runtime/syscall_windows.go
index 51004b7..8e069cd 100644
--- a/src/runtime/syscall_windows.go
+++ b/src/runtime/syscall_windows.go
@@ -8,8 +8,6 @@ import (
 	"unsafe"
 )
 
-const _SIGPROF = 0 // dummy value for badsignal
-
 type callbacks struct {
 	lock mutex
 	ctxt [cb_max]*wincallbackcontext
@@ -41,26 +39,25 @@ func callbackasmAddr(i int) uintptr {
 	return uintptr(add(unsafe.Pointer(&callbackasm), uintptr(i*5)))
 }
 
+//go:linkname compileCallback syscall.compileCallback
 func compileCallback(fn eface, cleanstack bool) (code uintptr) {
 	if fn._type == nil || (fn._type.kind&kindMask) != kindFunc {
-		panic("compilecallback: not a function")
+		panic("compileCallback: not a function")
 	}
 	ft := (*functype)(unsafe.Pointer(fn._type))
-	if len(ft.out) != 1 {
-		panic("compilecallback: function must have one output parameter")
+	if ft.out.len != 1 {
+		panic("compileCallback: function must have one output parameter")
 	}
 	uintptrSize := unsafe.Sizeof(uintptr(0))
-	if t := (**_type)(unsafe.Pointer(&ft.out[0])); (*t).size != uintptrSize {
-		panic("compilecallback: output parameter size is wrong")
+	if t := (**_type)(unsafe.Pointer(ft.out.array)); (*t).size != uintptrSize {
+		panic("compileCallback: output parameter size is wrong")
 	}
 	argsize := uintptr(0)
-	if len(ft.in) > 0 {
-		for _, t := range (*[1024](*_type))(unsafe.Pointer(&ft.in[0]))[:len(ft.in)] {
-			if (*t).size > uintptrSize {
-				panic("compilecallback: input parameter size is wrong")
-			}
-			argsize += uintptrSize
+	for _, t := range (*[1024](*_type))(unsafe.Pointer(ft.in.array))[:ft.in.len] {
+		if (*t).size > uintptrSize {
+			panic("compileCallback: input parameter size is wrong")
 		}
+		argsize += uintptrSize
 	}
 
 	lock(&cbs.lock)
@@ -73,7 +70,7 @@ func compileCallback(fn eface, cleanstack bool) (code uintptr) {
 		}
 	}
 	if n >= cb_max {
-		gothrow("too many callback functions")
+		throw("too many callback functions")
 	}
 
 	c := new(wincallbackcontext)
@@ -91,15 +88,14 @@ func compileCallback(fn eface, cleanstack bool) (code uintptr) {
 	return callbackasmAddr(n)
 }
 
-func getLoadLibrary() uintptr
-
+//go:linkname syscall_loadlibrary syscall.loadlibrary
 //go:nosplit
 func syscall_loadlibrary(filename *uint16) (handle, err uintptr) {
-	var c libcall
+	c := &getg().m.syscall
 	c.fn = getLoadLibrary()
 	c.n = 1
-	c.args = uintptr(unsafe.Pointer(&filename))
-	cgocall_errno(unsafe.Pointer(funcPC(asmstdcall)), unsafe.Pointer(&c))
+	c.args = uintptr(noescape(unsafe.Pointer(&filename)))
+	cgocall(asmstdcallAddr, unsafe.Pointer(c))
 	handle = c.r1
 	if handle == 0 {
 		err = c.err
@@ -107,15 +103,14 @@ func syscall_loadlibrary(filename *uint16) (handle, err uintptr) {
 	return
 }
 
-func getGetProcAddress() uintptr
-
+//go:linkname syscall_getprocaddress syscall.getprocaddress
 //go:nosplit
 func syscall_getprocaddress(handle uintptr, procname *byte) (outhandle, err uintptr) {
-	var c libcall
+	c := &getg().m.syscall
 	c.fn = getGetProcAddress()
 	c.n = 2
-	c.args = uintptr(unsafe.Pointer(&handle))
-	cgocall_errno(unsafe.Pointer(funcPC(asmstdcall)), unsafe.Pointer(&c))
+	c.args = uintptr(noescape(unsafe.Pointer(&handle)))
+	cgocall(asmstdcallAddr, unsafe.Pointer(c))
 	outhandle = c.r1
 	if outhandle == 0 {
 		err = c.err
@@ -123,52 +118,57 @@ func syscall_getprocaddress(handle uintptr, procname *byte) (outhandle, err uint
 	return
 }
 
+//go:linkname syscall_Syscall syscall.Syscall
 //go:nosplit
 func syscall_Syscall(fn, nargs, a1, a2, a3 uintptr) (r1, r2, err uintptr) {
-	var c libcall
+	c := &getg().m.syscall
 	c.fn = fn
 	c.n = nargs
-	c.args = uintptr(unsafe.Pointer(&a1))
-	cgocall_errno(unsafe.Pointer(funcPC(asmstdcall)), unsafe.Pointer(&c))
+	c.args = uintptr(noescape(unsafe.Pointer(&a1)))
+	cgocall(asmstdcallAddr, unsafe.Pointer(c))
 	return c.r1, c.r2, c.err
 }
 
+//go:linkname syscall_Syscall6 syscall.Syscall6
 //go:nosplit
 func syscall_Syscall6(fn, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr) {
-	var c libcall
+	c := &getg().m.syscall
 	c.fn = fn
 	c.n = nargs
-	c.args = uintptr(unsafe.Pointer(&a1))
-	cgocall_errno(unsafe.Pointer(funcPC(asmstdcall)), unsafe.Pointer(&c))
+	c.args = uintptr(noescape(unsafe.Pointer(&a1)))
+	cgocall(asmstdcallAddr, unsafe.Pointer(c))
 	return c.r1, c.r2, c.err
 }
 
+//go:linkname syscall_Syscall9 syscall.Syscall9
 //go:nosplit
 func syscall_Syscall9(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2, err uintptr) {
-	var c libcall
+	c := &getg().m.syscall
 	c.fn = fn
 	c.n = nargs
-	c.args = uintptr(unsafe.Pointer(&a1))
-	cgocall_errno(unsafe.Pointer(funcPC(asmstdcall)), unsafe.Pointer(&c))
+	c.args = uintptr(noescape(unsafe.Pointer(&a1)))
+	cgocall(asmstdcallAddr, unsafe.Pointer(c))
 	return c.r1, c.r2, c.err
 }
 
+//go:linkname syscall_Syscall12 syscall.Syscall12
 //go:nosplit
 func syscall_Syscall12(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12 uintptr) (r1, r2, err uintptr) {
-	var c libcall
+	c := &getg().m.syscall
 	c.fn = fn
 	c.n = nargs
-	c.args = uintptr(unsafe.Pointer(&a1))
-	cgocall_errno(unsafe.Pointer(funcPC(asmstdcall)), unsafe.Pointer(&c))
+	c.args = uintptr(noescape(unsafe.Pointer(&a1)))
+	cgocall(asmstdcallAddr, unsafe.Pointer(c))
 	return c.r1, c.r2, c.err
 }
 
+//go:linkname syscall_Syscall15 syscall.Syscall15
 //go:nosplit
 func syscall_Syscall15(fn, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15 uintptr) (r1, r2, err uintptr) {
-	var c libcall
+	c := &getg().m.syscall
 	c.fn = fn
 	c.n = nargs
-	c.args = uintptr(unsafe.Pointer(&a1))
-	cgocall_errno(unsafe.Pointer(funcPC(asmstdcall)), unsafe.Pointer(&c))
+	c.args = uintptr(noescape(unsafe.Pointer(&a1)))
+	cgocall(asmstdcallAddr, unsafe.Pointer(c))
 	return c.r1, c.r2, c.err
 }
diff --git a/src/runtime/syscall_windows_test.go b/src/runtime/syscall_windows_test.go
index 126bef6..677eb5f 100644
--- a/src/runtime/syscall_windows_test.go
+++ b/src/runtime/syscall_windows_test.go
@@ -271,7 +271,7 @@ func (f cbDLLFunc) buildOne(stdcall bool) string {
 	typename := "t" + funcname
 	p := make([]string, f)
 	for i := range p {
-		p[i] = "void*"
+		p[i] = "uintptr_t"
 	}
 	params := strings.Join(p, ",")
 	for i := range p {
@@ -280,9 +280,9 @@ func (f cbDLLFunc) buildOne(stdcall bool) string {
 	args := strings.Join(p, ",")
 	return fmt.Sprintf(`
 typedef void %s (*%s)(%s);
-void %s(%s f, void *n) {
-	int i;
-	for(i=0;i<(int)n;i++){
+void %s(%s f, uintptr_t n) {
+	uintptr_t i;
+	for(i=0;i<n;i++){
 		f(%s);
 	}
 }
@@ -290,7 +290,7 @@ void %s(%s f, void *n) {
 }
 
 func (f cbDLLFunc) build() string {
-	return f.buildOne(false) + f.buildOne(true)
+	return "#include <stdint.h>\n\n" + f.buildOne(false) + f.buildOne(true)
 }
 
 var cbFuncs = [...]interface{}{
@@ -379,13 +379,13 @@ var cbDLLs = []cbDLL{
 	{
 		"test",
 		func(out, src string) []string {
-			return []string{"gcc", "-shared", "-s", "-o", out, src}
+			return []string{"gcc", "-shared", "-s", "-Werror", "-o", out, src}
 		},
 	},
 	{
 		"testO2",
 		func(out, src string) []string {
-			return []string{"gcc", "-shared", "-s", "-o", out, "-O2", src}
+			return []string{"gcc", "-shared", "-s", "-Werror", "-o", out, "-O2", src}
 		},
 	},
 }
@@ -436,6 +436,9 @@ var cbTests = []cbTest{
 }
 
 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)
@@ -534,10 +537,106 @@ func main() {
 }
 `
 
-func TestCallbackWithNoInputParameters(t *testing.T) {
-	// Test that NewCallback and NewCallbackCDecl can accept functions without
-	// input parameters, see issue 9871.
-	cb := func() uintptr { return 0 }
-	_ = syscall.NewCallback(cb)
-	_ = syscall.NewCallbackCDecl(cb)
+func TestWERDialogue(t *testing.T) {
+	if os.Getenv("TESTING_WER_DIALOGUE") == "1" {
+		defer os.Exit(0)
+
+		*runtime.TestingWER = true
+		const EXCEPTION_NONCONTINUABLE = 1
+		mod := syscall.MustLoadDLL("kernel32.dll")
+		proc := mod.MustFindProc("RaiseException")
+		proc.Call(0xbad, EXCEPTION_NONCONTINUABLE, 0, 0)
+		println("RaiseException should not return")
+		return
+	}
+	cmd := exec.Command(os.Args[0], "-test.run=TestWERDialogue")
+	cmd.Env = []string{"TESTING_WER_DIALOGUE=1"}
+	// Child process should not open WER dialogue, but return immediately instead.
+	cmd.CombinedOutput()
+}
+
+var used byte
+
+func use(buf []byte) {
+	for _, c := range buf {
+		used += c
+	}
+}
+
+func forceStackCopy() (r int) {
+	var f func(int) int
+	f = func(i int) int {
+		var buf [256]byte
+		use(buf[:])
+		if i == 0 {
+			return 0
+		}
+		return i + f(i-1)
+	}
+	r = f(128)
+	return
+}
+
+func TestReturnAfterStackGrowInCallback(t *testing.T) {
+	if _, err := exec.LookPath("gcc"); err != nil {
+		t.Skip("skipping test: gcc is missing")
+	}
+
+	const src = `
+#include <stdint.h>
+#include <windows.h>
+
+typedef uintptr_t __stdcall (*callback)(uintptr_t);
+
+uintptr_t cfunc(callback f, uintptr_t n) {
+   uintptr_t r;
+   r = f(n);
+   SetLastError(333);
+   return r;
+}
+`
+	tmpdir, err := ioutil.TempDir("", "TestReturnAfterStackGrowInCallback")
+	if err != nil {
+		t.Fatal("TempDir failed: ", err)
+	}
+	defer os.RemoveAll(tmpdir)
+
+	srcname := "mydll.c"
+	err = ioutil.WriteFile(filepath.Join(tmpdir, srcname), []byte(src), 0)
+	if err != nil {
+		t.Fatal(err)
+	}
+	outname := "mydll.dll"
+	cmd := exec.Command("gcc", "-shared", "-s", "-Werror", "-o", outname, srcname)
+	cmd.Dir = tmpdir
+	out, err := cmd.CombinedOutput()
+	if err != nil {
+		t.Fatalf("failed to build dll: %v - %v", err, string(out))
+	}
+	dllpath := filepath.Join(tmpdir, outname)
+
+	dll := syscall.MustLoadDLL(dllpath)
+	defer dll.Release()
+
+	proc := dll.MustFindProc("cfunc")
+
+	cb := syscall.NewCallback(func(n uintptr) uintptr {
+		forceStackCopy()
+		return n
+	})
+
+	// Use a new goroutine so that we get a small stack.
+	type result struct {
+		r   uintptr
+		err syscall.Errno
+	}
+	c := make(chan result)
+	go func() {
+		r, _, err := proc.Call(cb, 100)
+		c <- result{r, err.(syscall.Errno)}
+	}()
+	want := result{r: 100, err: 333}
+	if got := <-c; got != want {
+		t.Errorf("got %d want %d", got, want)
+	}
 }
diff --git a/src/runtime/textflag.h b/src/runtime/textflag.h
new file mode 100644
index 0000000..2a76e76
--- /dev/null
+++ b/src/runtime/textflag.h
@@ -0,0 +1,23 @@
+// 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.
+
+// This file defines flags attached to various functions
+// and data objects.  The compilers, assemblers, and linker must
+// all agree on these values.
+
+// Don't profile the marked routine.  This flag is deprecated.
+#define NOPROF	1
+// It is ok for the linker to get multiple of these symbols.  It will
+// pick one of the duplicates to use.
+#define DUPOK	2
+// Don't insert stack check preamble.
+#define NOSPLIT	4
+// Put this data in a read-only section.
+#define RODATA	8
+// This data contains no pointers.
+#define NOPTR	16
+// This is a wrapper function and should not count as disabling 'recover'.
+#define WRAPPER 32
+// This function uses its incoming context register.
+#define NEEDCTXT 64
diff --git a/src/runtime/thunk.s b/src/runtime/thunk.s
deleted file mode 100644
index 0a0f147..0000000
--- a/src/runtime/thunk.s
+++ /dev/null
@@ -1,183 +0,0 @@
-// 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.
-
-// This file exposes various internal runtime functions to other packages in std lib.
-
-#include "zasm_GOOS_GOARCH.h"
-#include "textflag.h"
-
-#ifdef GOARCH_arm
-#define JMP B
-#endif
-
-TEXT net·runtimeNano(SB),NOSPLIT,$0-0
-	JMP	runtime·nanotime(SB)
-
-TEXT time·runtimeNano(SB),NOSPLIT,$0-0
-	JMP     runtime·nanotime(SB)
-
-TEXT time·Sleep(SB),NOSPLIT,$0-0
-	JMP     runtime·timeSleep(SB)
-
-TEXT time·startTimer(SB),NOSPLIT,$0-0
-	JMP     runtime·startTimer(SB)
-
-TEXT time·stopTimer(SB),NOSPLIT,$0-0
-	JMP     runtime·stopTimer(SB)
-
-TEXT sync·runtime_Syncsemacquire(SB),NOSPLIT,$0-0
-	JMP	runtime·syncsemacquire(SB)
-
-TEXT sync·runtime_Syncsemrelease(SB),NOSPLIT,$0-0
-	JMP	runtime·syncsemrelease(SB)
-
-TEXT sync·runtime_Syncsemcheck(SB),NOSPLIT,$0-0
-	JMP	runtime·syncsemcheck(SB)
-
-TEXT sync·runtime_Semacquire(SB),NOSPLIT,$0-0
-	JMP	runtime·asyncsemacquire(SB)
-
-TEXT sync·runtime_Semrelease(SB),NOSPLIT,$0-0
-	JMP	runtime·asyncsemrelease(SB)
-
-TEXT sync·runtime_registerPoolCleanup(SB),NOSPLIT,$0-0
-	JMP	runtime·registerPoolCleanup(SB)
-
-TEXT net·runtime_Semacquire(SB),NOSPLIT,$0-0
-	JMP	runtime·asyncsemacquire(SB)
-
-TEXT net·runtime_Semrelease(SB),NOSPLIT,$0-0
-	JMP	runtime·asyncsemrelease(SB)
-
-TEXT runtime∕pprof·runtime_cyclesPerSecond(SB),NOSPLIT,$0-0
-	JMP	runtime·tickspersecond(SB)
-
-TEXT bytes·Compare(SB),NOSPLIT,$0-0
-	JMP	runtime·cmpbytes(SB)
-
-TEXT reflect·call(SB), NOSPLIT, $0-0
-	JMP	runtime·reflectcall(SB)
-
-TEXT reflect·chanclose(SB), NOSPLIT, $0-0
-	JMP	runtime·closechan(SB)
-
-TEXT reflect·chanlen(SB), NOSPLIT, $0-0
-	JMP	runtime·reflect_chanlen(SB)
-
-TEXT reflect·chancap(SB), NOSPLIT, $0-0
-	JMP	runtime·reflect_chancap(SB)
-
-TEXT reflect·chansend(SB), NOSPLIT, $0-0
-	JMP	runtime·reflect_chansend(SB)
-
-TEXT reflect·chanrecv(SB), NOSPLIT, $0-0
-	JMP	runtime·reflect_chanrecv(SB)
-
-TEXT reflect·memmove(SB), NOSPLIT, $0-0
-	JMP	runtime·memmove(SB)
-
-TEXT runtime∕debug·freeOSMemory(SB), NOSPLIT, $0-0
-	JMP	runtime·freeOSMemory(SB)
-
-TEXT runtime∕debug·WriteHeapDump(SB), NOSPLIT, $0-0
-	JMP	runtime·writeHeapDump(SB)
-
-TEXT net·runtime_pollServerInit(SB),NOSPLIT,$0-0
-	JMP	runtime·netpollServerInit(SB)
-
-TEXT net·runtime_pollOpen(SB),NOSPLIT,$0-0
-	JMP	runtime·netpollOpen(SB)
-
-TEXT net·runtime_pollClose(SB),NOSPLIT,$0-0
-	JMP	runtime·netpollClose(SB)
-
-TEXT net·runtime_pollReset(SB),NOSPLIT,$0-0
-	JMP	runtime·netpollReset(SB)
-
-TEXT net·runtime_pollWait(SB),NOSPLIT,$0-0
-	JMP	runtime·netpollWait(SB)
-
-TEXT net·runtime_pollWaitCanceled(SB),NOSPLIT,$0-0
-	JMP	runtime·netpollWaitCanceled(SB)
-
-TEXT net·runtime_pollSetDeadline(SB),NOSPLIT,$0-0
-	JMP	runtime·netpollSetDeadline(SB)
-
-TEXT net·runtime_pollUnblock(SB),NOSPLIT,$0-0
-	JMP	runtime·netpollUnblock(SB)
-
-TEXT syscall·setenv_c(SB), NOSPLIT, $0-0
-	JMP	runtime·syscall_setenv_c(SB)
-
-TEXT syscall·unsetenv_c(SB), NOSPLIT, $0-0
-	JMP	runtime·syscall_unsetenv_c(SB)
-
-TEXT reflect·makemap(SB),NOSPLIT,$0-0
-	JMP	runtime·reflect_makemap(SB)
-
-TEXT reflect·mapaccess(SB),NOSPLIT,$0-0
-	JMP	runtime·reflect_mapaccess(SB)
-
-TEXT reflect·mapassign(SB),NOSPLIT,$0-0
-	JMP	runtime·reflect_mapassign(SB)
-
-TEXT reflect·mapdelete(SB),NOSPLIT,$0-0
-	JMP	runtime·reflect_mapdelete(SB)
-
-TEXT reflect·mapiterinit(SB),NOSPLIT,$0-0
-	JMP	runtime·reflect_mapiterinit(SB)
-
-TEXT reflect·mapiterkey(SB),NOSPLIT,$0-0
-	JMP	runtime·reflect_mapiterkey(SB)
-
-TEXT reflect·mapiternext(SB),NOSPLIT,$0-0
-	JMP	runtime·reflect_mapiternext(SB)
-
-TEXT reflect·maplen(SB),NOSPLIT,$0-0
-	JMP	runtime·reflect_maplen(SB)
-
-TEXT reflect·ismapkey(SB),NOSPLIT,$0-0
-	JMP	runtime·reflect_ismapkey(SB)
-
-TEXT reflect·ifaceE2I(SB),NOSPLIT,$0-0
-	JMP	runtime·reflect_ifaceE2I(SB)
-
-TEXT reflect·unsafe_New(SB),NOSPLIT,$0-0
-	JMP	runtime·newobject(SB)
-
-TEXT reflect·unsafe_NewArray(SB),NOSPLIT,$0-0
-	JMP	runtime·newarray(SB)
-
-TEXT reflect·makechan(SB),NOSPLIT,$0-0
-	JMP	runtime·makechan(SB)
-
-TEXT reflect·rselect(SB),NOSPLIT,$0-0
-	JMP	runtime·reflect_rselect(SB)
-
-TEXT os·sigpipe(SB),NOSPLIT,$0-0
-	JMP	runtime·os_sigpipe(SB)
-
-TEXT runtime·runtime_init(SB),NOSPLIT,$0-0
-	JMP	runtime·init(SB)
-
-TEXT runtime·main_init(SB),NOSPLIT,$0-0
-	JMP	main·init(SB)
-
-TEXT runtime·main_main(SB),NOSPLIT,$0-0
-	JMP	main·main(SB)
-
-TEXT runtime·timenow(SB),NOSPLIT,$0-0
-	JMP	time·now(SB)
-
-TEXT sync∕atomic·runtime_procPin(SB),NOSPLIT,$0-0
-	JMP     sync·runtime_procPin(SB)
-
-TEXT sync∕atomic·runtime_procUnpin(SB),NOSPLIT,$0-0
-	JMP     sync·runtime_procUnpin(SB)
-
-TEXT syscall·runtime_envs(SB),NOSPLIT,$0-0
-	JMP	runtime·runtime_envs(SB)
-
-TEXT os·runtime_args(SB),NOSPLIT,$0-0
-	JMP	runtime·runtime_args(SB)
diff --git a/src/runtime/thunk_solaris_amd64.s b/src/runtime/thunk_solaris_amd64.s
deleted file mode 100644
index f61188c..0000000
--- a/src/runtime/thunk_solaris_amd64.s
+++ /dev/null
@@ -1,88 +0,0 @@
-// 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.
-
-// This file exposes various external library functions to Go code in the runtime.
-
-#include "zasm_GOOS_GOARCH.h"
-#include "textflag.h"
-
-TEXT runtime·libc_chdir(SB),NOSPLIT,$0
-	MOVQ	libc·chdir(SB), AX
-	JMP	AX
-
-TEXT runtime·libc_chroot(SB),NOSPLIT,$0
-	MOVQ	libc·chroot(SB), AX
-	JMP	AX
-
-TEXT runtime·libc_close(SB),NOSPLIT,$0
-	MOVQ	libc·close(SB), AX
-	JMP	AX
-
-TEXT runtime·libc_dlopen(SB),NOSPLIT,$0
-	MOVQ	libc·dlopen(SB), AX
-	JMP	AX
-
-TEXT runtime·libc_dlclose(SB),NOSPLIT,$0
-	MOVQ	libc·dlclose(SB), AX
-	JMP	AX
-
-TEXT runtime·libc_dlsym(SB),NOSPLIT,$0
-	MOVQ	libc·dlsym(SB), AX
-	JMP	AX
-
-TEXT runtime·libc_execve(SB),NOSPLIT,$0
-	MOVQ	libc·execve(SB), AX
-	JMP	AX
-
-TEXT runtime·libc_exit(SB),NOSPLIT,$0
-	MOVQ	libc·exit(SB), AX
-	JMP	AX
-
-TEXT runtime·libc_fcntl(SB),NOSPLIT,$0
-	MOVQ	libc·fcntl(SB), AX
-	JMP	AX
-
-TEXT runtime·libc_forkx(SB),NOSPLIT,$0
-	MOVQ	libc·forkx(SB), AX
-	JMP	AX
-
-TEXT runtime·libc_gethostname(SB),NOSPLIT,$0
-	MOVQ	libc·gethostname(SB), AX
-	JMP	AX
-
-TEXT runtime·libc_ioctl(SB),NOSPLIT,$0
-	MOVQ	libc·ioctl(SB), AX
-	JMP	AX
-
-TEXT runtime·libc_setgid(SB),NOSPLIT,$0
-	MOVQ	libc·setgid(SB), AX
-	JMP	AX
-
-TEXT runtime·libc_setgroups(SB),NOSPLIT,$0
-	MOVQ	libc·setgroups(SB), AX
-	JMP	AX
-
-TEXT runtime·libc_setsid(SB),NOSPLIT,$0
-	MOVQ	libc·setsid(SB), AX
-	JMP	AX
-
-TEXT runtime·libc_setuid(SB),NOSPLIT,$0
-	MOVQ	libc·setuid(SB), AX
-	JMP	AX
-
-TEXT runtime·libc_setpgid(SB),NOSPLIT,$0
-	MOVQ	libc·setpgid(SB), AX
-	JMP	AX
-
-TEXT runtime·libc_syscall(SB),NOSPLIT,$0
-	MOVQ	libc·syscall(SB), AX
-	JMP	AX
-
-TEXT runtime·libc_wait4(SB),NOSPLIT,$0
-	MOVQ	libc·wait4(SB), AX
-	JMP	AX
-
-TEXT runtime·libc_write(SB),NOSPLIT,$0
-	MOVQ	libc·write(SB), AX
-	JMP	AX
diff --git a/src/runtime/thunk_windows.s b/src/runtime/thunk_windows.s
deleted file mode 100644
index 7ccb98f..0000000
--- a/src/runtime/thunk_windows.s
+++ /dev/null
@@ -1,30 +0,0 @@
-// 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 "zasm_GOOS_GOARCH.h"
-#include "textflag.h"
-
-TEXT syscall·Syscall(SB),NOSPLIT,$0-0
-	JMP	runtime·syscall_Syscall(SB)
-
-TEXT syscall·Syscall6(SB),NOSPLIT,$0-0
-	JMP	runtime·syscall_Syscall6(SB)
-
-TEXT syscall·Syscall9(SB),NOSPLIT,$0-0
-	JMP	runtime·syscall_Syscall9(SB)
-
-TEXT syscall·Syscall12(SB),NOSPLIT,$0-0
-	JMP	runtime·syscall_Syscall12(SB)
-
-TEXT syscall·Syscall15(SB),NOSPLIT,$0-0
-	JMP	runtime·syscall_Syscall15(SB)
-
-TEXT syscall·loadlibrary(SB),NOSPLIT,$0-0
-	JMP	runtime·syscall_loadlibrary(SB)
-
-TEXT syscall·getprocaddress(SB),NOSPLIT,$0-0
-	JMP	runtime·syscall_getprocaddress(SB)
-
-TEXT syscall·compileCallback(SB),NOSPLIT,$0
-	JMP	runtime·compileCallback(SB)
diff --git a/src/runtime/time.go b/src/runtime/time.go
index 11862c7..ffe7590 100644
--- a/src/runtime/time.go
+++ b/src/runtime/time.go
@@ -43,7 +43,8 @@ var faketime int64
 
 // time.now is implemented in assembly.
 
-// Sleep puts the current goroutine to sleep for at least ns nanoseconds.
+// timeSleep puts the current goroutine to sleep for at least ns nanoseconds.
+//go:linkname timeSleep time.Sleep
 func timeSleep(ns int64) {
 	if ns <= 0 {
 		return
@@ -55,10 +56,11 @@ func timeSleep(ns int64) {
 	t.arg = getg()
 	lock(&timers.lock)
 	addtimerLocked(t)
-	goparkunlock(&timers.lock, "sleep")
+	goparkunlock(&timers.lock, "sleep", traceEvGoSleep, 2)
 }
 
 // startTimer adds t to the timer heap.
+//go:linkname startTimer time.startTimer
 func startTimer(t *timer) {
 	if raceenabled {
 		racerelease(unsafe.Pointer(t))
@@ -68,6 +70,7 @@ func startTimer(t *timer) {
 
 // stopTimer removes t from the timer heap if it is there.
 // It returns true if t was removed, false if t wasn't even there.
+//go:linkname stopTimer time.stopTimer
 func stopTimer(t *timer) bool {
 	return deltimer(t)
 }
@@ -76,7 +79,7 @@ func stopTimer(t *timer) bool {
 
 // Ready the goroutine arg.
 func goroutineReady(arg interface{}, seq uintptr) {
-	goready(arg.(*g))
+	goready(arg.(*g), 0)
 }
 
 func addtimer(t *timer) {
@@ -105,7 +108,7 @@ func addtimerLocked(t *timer) {
 		}
 		if timers.rescheduling {
 			timers.rescheduling = false
-			goready(timers.gp)
+			goready(timers.gp, 0)
 		}
 	}
 	if !timers.created {
@@ -150,7 +153,6 @@ func deltimer(t *timer) bool {
 // If addtimer inserts a new earlier event, addtimer1 wakes timerproc early.
 func timerproc() {
 	timers.gp = getg()
-	timers.gp.issystem = true
 	for {
 		lock(&timers.lock)
 		timers.sleeping = false
@@ -197,7 +199,7 @@ func timerproc() {
 		if delta < 0 || faketime > 0 {
 			// No timers left - put goroutine to sleep.
 			timers.rescheduling = true
-			goparkunlock(&timers.lock, "timer goroutine (idle)")
+			goparkunlock(&timers.lock, "timer goroutine (idle)", traceEvGoBlock, 1)
 			continue
 		}
 		// At least one timer pending.  Sleep until then.
@@ -287,3 +289,15 @@ func siftdownTimer(i int) {
 		i = c
 	}
 }
+
+// Entry points for net, time to call nanotime.
+
+//go:linkname net_runtimeNano net.runtimeNano
+func net_runtimeNano() int64 {
+	return nanotime()
+}
+
+//go:linkname time_runtimeNano time.runtimeNano
+func time_runtimeNano() int64 {
+	return nanotime()
+}
diff --git a/src/runtime/tls_arm.s b/src/runtime/tls_arm.s
index 85c3940..d37970e 100644
--- a/src/runtime/tls_arm.s
+++ b/src/runtime/tls_arm.s
@@ -2,7 +2,8 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
 #include "funcdata.h"
 #include "textflag.h"
 
@@ -14,8 +15,14 @@
 // Note: both functions will clobber R0 and R11 and
 // can be called from 5c ABI code.
 
-// On android, runtime.tlsg is a normal variable.
+// On android and darwin, runtime.tlsg is a normal variable.
 // TLS offset is computed in x_cgo_inittls.
+#ifdef GOOS_android
+#define TLSG_IS_VARIABLE
+#endif
+#ifdef GOOS_darwin
+#define TLSG_IS_VARIABLE
+#endif
 
 // save_g saves the g register into pthread-provided
 // thread-local memory, so that we can call externally compiled
@@ -33,10 +40,11 @@ TEXT runtime·save_g(SB),NOSPLIT,$-4
 	// a call to runtime.read_tls_fallback which jumps to __kuser_get_tls.
 	// The replacement function saves LR in R11 over the call to read_tls_fallback.
 	MRC	15, 0, R0, C13, C0, 3 // fetch TLS base pointer
+	BIC $3, R0 // Darwin/ARM might return unaligned pointer
 	// $runtime.tlsg(SB) is a special linker symbol.
 	// It is the offset from the TLS base pointer to our
 	// thread-local storage for g.
-#ifdef GOOS_android
+#ifdef TLSG_IS_VARIABLE
 	MOVW	runtime·tlsg(SB), R11
 #else
 	MOVW	$runtime·tlsg(SB), R11
@@ -56,10 +64,11 @@ TEXT runtime·load_g(SB),NOSPLIT,$0
 #endif
 	// See save_g
 	MRC	15, 0, R0, C13, C0, 3 // fetch TLS base pointer
+	BIC $3, R0 // Darwin/ARM might return unaligned pointer
 	// $runtime.tlsg(SB) is a special linker symbol.
 	// It is the offset from the TLS base pointer to our
 	// thread-local storage for g.
-#ifdef GOOS_android
+#ifdef TLSG_IS_VARIABLE
 	MOVW	runtime·tlsg(SB), R11
 #else
 	MOVW	$runtime·tlsg(SB), R11
@@ -67,3 +76,38 @@ TEXT runtime·load_g(SB),NOSPLIT,$0
 	ADD	R11, R0
 	MOVW	0(R0), g
 	RET
+
+// This is called from rt0_go, which runs on the system stack
+// using the initial stack allocated by the OS.
+// It calls back into standard C using the BL (R4) below.
+// To do that, the stack pointer must be 8-byte-aligned
+// on some systems, notably FreeBSD.
+// The ARM ABI says the stack pointer must be 8-byte-aligned
+// on entry to any function, but only FreeBSD's C library seems to care.
+// The caller was 8-byte aligned, but we push an LR.
+// Declare a dummy word ($4, not $0) to make sure the
+// frame is 8 bytes and stays 8-byte-aligned.
+TEXT runtime·_initcgo(SB),NOSPLIT,$4
+#ifndef GOOS_nacl
+	// if there is an _cgo_init, call it.
+	MOVW	_cgo_init(SB), R4
+	CMP	$0, R4
+	B.EQ	nocgo
+	MRC     15, 0, R0, C13, C0, 3 	// load TLS base pointer
+	MOVW 	R0, R3 			// arg 3: TLS base pointer
+	MOVW 	$runtime·tlsg(SB), R2 	// arg 2: tlsg
+	MOVW	$setg_gcc<>(SB), R1 	// arg 1: setg
+	MOVW	g, R0 			// arg 0: G
+	BL	(R4) // will clobber R0-R3
+#endif
+nocgo:
+	RET
+
+// void setg_gcc(G*); set g called from gcc.
+TEXT setg_gcc<>(SB),NOSPLIT,$0
+	MOVW	R0, g
+	B		runtime·save_g(SB)
+
+#ifdef TLSG_IS_VARIABLE
+GLOBL runtime·tlsg+0(SB), NOPTR, $4
+#endif
diff --git a/src/runtime/tls_arm64.h b/src/runtime/tls_arm64.h
new file mode 100644
index 0000000..d5676ab
--- /dev/null
+++ b/src/runtime/tls_arm64.h
@@ -0,0 +1,20 @@
+// 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.
+
+#ifdef GOOS_linux
+#define TPIDR TPIDR_EL0
+#define MRS_TPIDR_R0 WORD $0xd53bd040 // MRS TPIDR_EL0, R0
+#endif
+
+#ifdef GOOS_darwin
+#define TPIDR TPIDRRO_EL0
+#define TLSG_IS_VARIABLE
+#define MRS_TPIDR_R0 WORD $0xd53bd060 // MRS TPIDRRO_EL0, R0
+#endif
+
+// Define something that will break the build if
+// the GOOS is unknown.
+#ifndef TPIDR
+#define MRS_TPIDR_R0 TPIDR_UNKNOWN
+#endif
diff --git a/src/runtime/tls_arm64.s b/src/runtime/tls_arm64.s
new file mode 100644
index 0000000..a5f86c4
--- /dev/null
+++ b/src/runtime/tls_arm64.s
@@ -0,0 +1,60 @@
+// 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"
+#include "tls_arm64.h"
+
+TEXT runtime·load_g(SB),NOSPLIT,$0
+	MOVB	runtime·iscgo(SB), R0
+	CMP	$0, R0
+	BEQ	nocgo
+
+	MRS_TPIDR_R0
+#ifdef GOOS_darwin
+	// Darwin sometimes returns unaligned pointers
+	AND	$0xfffffffffffffff8, R0
+#endif
+#ifdef TLSG_IS_VARIABLE
+	MOVD	runtime·tls_g(SB), R27
+	ADD	R27, R0
+#else
+	// TODO(minux): use real TLS relocation, instead of hard-code for Linux
+	ADD	$0x10, R0
+#endif
+	MOVD	0(R0), g
+
+nocgo:
+	RET
+
+TEXT runtime·save_g(SB),NOSPLIT,$0
+	MOVB	runtime·iscgo(SB), R0
+	CMP	$0, R0
+	BEQ	nocgo
+
+	MRS_TPIDR_R0
+#ifdef GOOS_darwin
+	// Darwin sometimes returns unaligned pointers
+	AND	$0xfffffffffffffff8, R0
+#endif
+#ifdef TLSG_IS_VARIABLE
+	MOVD	runtime·tls_g(SB), R27
+	ADD	R27, R0
+#else
+	// TODO(minux): use real TLS relocation, instead of hard-code for Linux
+	ADD	$0x10, R0
+#endif
+	MOVD	g, 0(R0)
+
+nocgo:
+	RET
+
+#ifdef TLSG_IS_VARIABLE
+// The runtime.tlsg name is being handled specially in the
+// linker. As we just need a regular variable here, don't
+// use that name.
+GLOBL runtime·tls_g+0(SB), NOPTR, $8
+#endif
diff --git a/src/runtime/tls_ppc64x.s b/src/runtime/tls_ppc64x.s
new file mode 100644
index 0000000..fc1718f
--- /dev/null
+++ b/src/runtime/tls_ppc64x.s
@@ -0,0 +1,60 @@
+// 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 ppc64 ppc64le
+
+#include "go_asm.h"
+#include "go_tls.h"
+#include "funcdata.h"
+#include "textflag.h"
+
+// We have to resort to TLS variable to save g (R30).
+// One reason is that external code might trigger
+// SIGSEGV, and our runtime.sigtramp don't even know we
+// are in external code, and will continue to use R30,
+// this might well result in another SIGSEGV.
+
+// 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.
+//
+// NOTE: setg_gcc<> assume this clobbers only R31.
+TEXT runtime·save_g(SB),NOSPLIT,$-8-0
+	MOVB	runtime·iscgo(SB), R31
+	CMP	R31, $0
+	BEQ	nocgo
+
+	// $runtime.tlsg(SB) is a special linker symbol.
+	// It is the offset from the start of TLS to our
+	// thread-local storage for g.
+	MOVD	$runtime·tlsg(SB), R31
+	ADD	R13, R31
+	// The actual TLS base is 0x7000 below R13
+	SUB	$0x7000, R31
+
+	// Store g in TLS
+	MOVD	g, 0(R31)
+
+nocgo:
+	RET
+
+// load_g loads the g register from pthread-provided
+// thread-local memory, for use after calling externally compiled
+// ppc64 code that overwrote those registers.
+//
+// This is never called directly from C code (it doesn't have to
+// follow the C ABI), but it may be called from a C context, where the
+// usual Go registers aren't set up.
+//
+// NOTE: _cgo_topofstack assumes this only clobbers g (R30), and R31.
+TEXT runtime·load_g(SB),NOSPLIT,$-8-0
+	MOVD	$runtime·tlsg(SB), R31
+	// R13 is the C ABI TLS base pointer + 0x7000
+	ADD	R13, R31
+	SUB	$0x7000, R31
+
+	MOVD	0(R31), g
+	RET
diff --git a/src/runtime/trace.go b/src/runtime/trace.go
new file mode 100644
index 0000000..c818462
--- /dev/null
+++ b/src/runtime/trace.go
@@ -0,0 +1,859 @@
+// 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.
+
+// Go execution tracer.
+// The tracer captures a wide range of execution events like goroutine
+// creation/blocking/unblocking, syscall enter/exit/block, GC-related events,
+// changes of heap size, processor start/stop, etc and writes them to a buffer
+// in a compact form. A precise nanosecond-precision timestamp and a stack
+// trace is captured for most events.
+// See https://golang.org/s/go15trace for more info.
+
+package runtime
+
+import "unsafe"
+
+// Event types in the trace, args are given in square brackets.
+const (
+	traceEvNone           = 0  // unused
+	traceEvBatch          = 1  // start of per-P batch of events [pid, timestamp]
+	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, thread id]
+	traceEvProcStop       = 6  // stop of P [timestamp]
+	traceEvGCStart        = 7  // GC start [timestamp, stack id]
+	traceEvGCDone         = 8  // GC done [timestamp]
+	traceEvGCScanStart    = 9  // GC scan start [timestamp]
+	traceEvGCScanDone     = 10 // GC scan done [timestamp]
+	traceEvGCSweepStart   = 11 // GC sweep start [timestamp, stack id]
+	traceEvGCSweepDone    = 12 // GC sweep done [timestamp]
+	traceEvGoCreate       = 13 // goroutine creation [timestamp, new goroutine id, start PC, stack id]
+	traceEvGoStart        = 14 // goroutine starts running [timestamp, goroutine id]
+	traceEvGoEnd          = 15 // goroutine ends [timestamp]
+	traceEvGoStop         = 16 // goroutine stops (like in select{}) [timestamp, stack]
+	traceEvGoSched        = 17 // goroutine calls Gosched [timestamp, stack]
+	traceEvGoPreempt      = 18 // goroutine is preempted [timestamp, stack]
+	traceEvGoSleep        = 19 // goroutine calls Sleep [timestamp, stack]
+	traceEvGoBlock        = 20 // goroutine blocks [timestamp, stack]
+	traceEvGoUnblock      = 21 // goroutine is unblocked [timestamp, goroutine id, stack]
+	traceEvGoBlockSend    = 22 // goroutine blocks on chan send [timestamp, stack]
+	traceEvGoBlockRecv    = 23 // goroutine blocks on chan recv [timestamp, stack]
+	traceEvGoBlockSelect  = 24 // goroutine blocks on select [timestamp, stack]
+	traceEvGoBlockSync    = 25 // goroutine blocks on Mutex/RWMutex [timestamp, stack]
+	traceEvGoBlockCond    = 26 // goroutine blocks on Cond [timestamp, stack]
+	traceEvGoBlockNet     = 27 // goroutine blocks on network [timestamp, stack]
+	traceEvGoSysCall      = 28 // syscall enter [timestamp, stack]
+	traceEvGoSysExit      = 29 // syscall exit [timestamp, goroutine id, real timestamp]
+	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_live change [timestamp, heap_alloc]
+	traceEvNextGC         = 34 // memstats.next_gc change [timestamp, next_gc]
+	traceEvTimerGoroutine = 35 // denotes timer goroutine [timer goroutine id]
+	traceEvFutileWakeup   = 36 // denotes that the previous wakeup of this goroutine was futile [timestamp]
+	traceEvCount          = 37
+)
+
+const (
+	// Timestamps in trace are cputicks/traceTickDiv.
+	// This makes absolute values of timestamp diffs smaller,
+	// and so they are encoded in less number of bytes.
+	// 64 on x86 is somewhat arbitrary (one tick is ~20ns on a 3GHz machine).
+	// The suggested increment frequency for PowerPC's time base register is
+	// 512 MHz according to Power ISA v2.07 section 6.2, so we use 16 on ppc64
+	// and ppc64le.
+	// Tracing won't work reliably for architectures where cputicks is emulated
+	// by nanotime, so the value doesn't matter for those architectures.
+	traceTickDiv = 16 + 48*(goarch_386|goarch_amd64|goarch_amd64p32)
+	// Maximum number of PCs in a single stack trace.
+	// Since events contain only stack id rather than whole stack trace,
+	// we can allow quite large values here.
+	traceStackSize = 128
+	// Identifier of a fake P that is used when we trace without a real P.
+	traceGlobProc = -1
+	// Maximum number of bytes to encode uint64 in base-128.
+	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.
+var trace struct {
+	lock          mutex     // protects the following members
+	lockOwner     *g        // to avoid deadlocks during recursive lock locks
+	enabled       bool      // when set runtime traces events
+	shutdown      bool      // set when we are waiting for trace reader to finish after setting enabled to false
+	headerWritten bool      // whether ReadTrace has emitted trace header
+	footerWritten bool      // whether ReadTrace has emitted trace footer
+	shutdownSema  uint32    // used to wait for ReadTrace completion
+	seqStart      uint64    // sequence number when tracing was started
+	ticksStart    int64     // cputicks when tracing was started
+	ticksEnd      int64     // cputicks when tracing was stopped
+	timeStart     int64     // nanotime when tracing was started
+	timeEnd       int64     // nanotime when tracing was stopped
+	reading       *traceBuf // buffer currently handed off to user
+	empty         *traceBuf // stack of empty buffers
+	fullHead      *traceBuf // queue of full buffers
+	fullTail      *traceBuf
+	reader        *g              // goroutine that called ReadTrace, or nil
+	stackTab      traceStackTable // maps stack traces to unique ids
+
+	bufLock mutex     // protects buf
+	buf     *traceBuf // global trace buffer, used when running without a p
+}
+
+var traceseq uint64 // global trace sequence number
+
+// tracestamp returns a consistent sequence number, time stamp pair
+// for use in a trace. We need to make sure that time stamp ordering
+// (assuming synchronized CPUs) and sequence ordering match.
+// To do that, we increment traceseq, grab ticks, and increment traceseq again.
+// We treat odd traceseq as a sign that another thread is in the middle
+// of the sequence and spin until it is done.
+// Not splitting stack to avoid preemption, just in case the call sites
+// that used to call xadd64 and cputicks are sensitive to that.
+//go:nosplit
+func tracestamp() (seq uint64, ts int64) {
+	seq = atomicload64(&traceseq)
+	for seq&1 != 0 || !cas64(&traceseq, seq, seq+1) {
+		seq = atomicload64(&traceseq)
+	}
+	ts = cputicks()
+	atomicstore64(&traceseq, seq+2)
+	return seq >> 1, ts
+}
+
+// traceBufHeader is per-P tracing buffer.
+type traceBufHeader struct {
+	link      *traceBuf               // in trace.empty/full
+	lastSeq   uint64                  // sequence number of last event
+	lastTicks uint64                  // when we wrote the last event
+	buf       []byte                  // trace data, always points to traceBuf.arr
+	stk       [traceStackSize]uintptr // scratch buffer for traceback
+}
+
+// traceBuf is per-P tracing buffer.
+type traceBuf struct {
+	traceBufHeader
+	arr [64<<10 - unsafe.Sizeof(traceBufHeader{})]byte // underlying buffer for traceBufHeader.buf
+}
+
+// StartTrace enables tracing for the current process.
+// While tracing, the data will be buffered and available via ReadTrace.
+// StartTrace returns an error if tracing is already enabled.
+// Most clients should use the runtime/trace package or the testing package's
+// -test.trace flag instead of calling StartTrace directly.
+func StartTrace() error {
+	// Stop the world, so that we can take a consistent snapshot
+	// of all goroutines at the beginning of the trace.
+	stopTheWorld("start tracing")
+
+	// We are in stop-the-world, but syscalls can finish and write to trace concurrently.
+	// Exitsyscall could check trace.enabled long before and then suddenly wake up
+	// and decide to write to trace at a random point in time.
+	// However, such syscall will use the global trace.buf buffer, because we've
+	// acquired all p's by doing stop-the-world. So this protects us from such races.
+	lock(&trace.bufLock)
+
+	if trace.enabled || trace.shutdown {
+		unlock(&trace.bufLock)
+		startTheWorld()
+		return errorString("tracing is already enabled")
+	}
+
+	trace.seqStart, trace.ticksStart = tracestamp()
+	trace.timeStart = nanotime()
+	trace.headerWritten = false
+	trace.footerWritten = false
+
+	// Can't set trace.enabled yet. While the world is stopped, exitsyscall could
+	// already emit a delayed event (see exitTicks in exitsyscall) if we set trace.enabled here.
+	// That would lead to an inconsistent trace:
+	// - either GoSysExit appears before EvGoInSyscall,
+	// - or GoSysExit appears for a goroutine for which we don't emit EvGoInSyscall below.
+	// To instruct traceEvent that it must not ignore events below, we set startingtrace.
+	// trace.enabled is set afterwards once we have emitted all preliminary events.
+	_g_ := getg()
+	_g_.m.startingtrace = true
+	for _, gp := range allgs {
+		status := readgstatus(gp)
+		if status != _Gdead {
+			traceGoCreate(gp, gp.startpc)
+		}
+		if status == _Gwaiting {
+			traceEvent(traceEvGoWaiting, -1, uint64(gp.goid))
+		}
+		if status == _Gsyscall {
+			traceEvent(traceEvGoInSyscall, -1, uint64(gp.goid))
+		} else {
+			gp.sysblocktraced = false
+		}
+	}
+	traceProcStart()
+	traceGoStart()
+	_g_.m.startingtrace = false
+	trace.enabled = true
+
+	unlock(&trace.bufLock)
+
+	startTheWorld()
+	return nil
+}
+
+// StopTrace stops tracing, if it was previously enabled.
+// StopTrace only returns after all the reads for the trace have completed.
+func StopTrace() {
+	// Stop the world so that we can collect the trace buffers from all p's below,
+	// and also to avoid races with traceEvent.
+	stopTheWorld("stop tracing")
+
+	// See the comment in StartTrace.
+	lock(&trace.bufLock)
+
+	if !trace.enabled {
+		unlock(&trace.bufLock)
+		startTheWorld()
+		return
+	}
+
+	traceGoSched()
+
+	for _, p := range &allp {
+		if p == nil {
+			break
+		}
+		buf := p.tracebuf
+		if buf != nil {
+			traceFullQueue(buf)
+			p.tracebuf = nil
+		}
+	}
+	if trace.buf != nil && len(trace.buf.buf) != 0 {
+		buf := trace.buf
+		trace.buf = nil
+		traceFullQueue(buf)
+	}
+
+	for {
+		trace.ticksEnd = cputicks()
+		trace.timeEnd = nanotime()
+		// Windows time can tick only every 15ms, wait for at least one tick.
+		if trace.timeEnd != trace.timeStart {
+			break
+		}
+		osyield()
+	}
+
+	trace.enabled = false
+	trace.shutdown = true
+	trace.stackTab.dump()
+
+	unlock(&trace.bufLock)
+
+	startTheWorld()
+
+	// The world is started but we've set trace.shutdown, so new tracing can't start.
+	// Wait for the trace reader to flush pending buffers and stop.
+	semacquire(&trace.shutdownSema, false)
+	if raceenabled {
+		raceacquire(unsafe.Pointer(&trace.shutdownSema))
+	}
+
+	// The lock protects us from races with StartTrace/StopTrace because they do stop-the-world.
+	lock(&trace.lock)
+	for _, p := range &allp {
+		if p == nil {
+			break
+		}
+		if p.tracebuf != nil {
+			throw("trace: non-empty trace buffer in proc")
+		}
+	}
+	if trace.buf != nil {
+		throw("trace: non-empty global trace buffer")
+	}
+	if trace.fullHead != nil || trace.fullTail != nil {
+		throw("trace: non-empty full trace buffer")
+	}
+	if trace.reading != nil || trace.reader != nil {
+		throw("trace: reading after shutdown")
+	}
+	for trace.empty != nil {
+		buf := trace.empty
+		trace.empty = buf.link
+		sysFree(unsafe.Pointer(buf), unsafe.Sizeof(*buf), &memstats.other_sys)
+	}
+	trace.shutdown = false
+	unlock(&trace.lock)
+}
+
+// ReadTrace returns the next chunk of binary tracing data, blocking until data
+// is available. If tracing is turned off and all the data accumulated while it
+// was on has been returned, ReadTrace returns nil. The caller must copy the
+// returned data before calling ReadTrace again.
+// ReadTrace must be called from one goroutine at a time.
+func ReadTrace() []byte {
+	// This function may need to lock trace.lock recursively
+	// (goparkunlock -> traceGoPark -> traceEvent -> traceFlush).
+	// To allow this we use trace.lockOwner.
+	// Also this function must not allocate while holding trace.lock:
+	// allocation can call heap allocate, which will try to emit a trace
+	// event while holding heap lock.
+	lock(&trace.lock)
+	trace.lockOwner = getg()
+
+	if trace.reader != nil {
+		// More than one goroutine reads trace. This is bad.
+		// But we rather do not crash the program because of tracing,
+		// because tracing can be enabled at runtime on prod servers.
+		trace.lockOwner = nil
+		unlock(&trace.lock)
+		println("runtime: ReadTrace called from multiple goroutines simultaneously")
+		return nil
+	}
+	// Recycle the old buffer.
+	if buf := trace.reading; buf != nil {
+		buf.link = trace.empty
+		trace.empty = buf
+		trace.reading = nil
+	}
+	// Write trace header.
+	if !trace.headerWritten {
+		trace.headerWritten = true
+		trace.lockOwner = nil
+		unlock(&trace.lock)
+		return []byte("go 1.5 trace\x00\x00\x00\x00")
+	}
+	// Wait for new data.
+	if trace.fullHead == nil && !trace.shutdown {
+		trace.reader = getg()
+		goparkunlock(&trace.lock, "trace reader (blocked)", traceEvGoBlock, 2)
+		lock(&trace.lock)
+	}
+	// Write a buffer.
+	if trace.fullHead != nil {
+		buf := traceFullDequeue()
+		trace.reading = buf
+		trace.lockOwner = nil
+		unlock(&trace.lock)
+		return buf.buf
+	}
+	// Write footer with timer frequency.
+	if !trace.footerWritten {
+		trace.footerWritten = true
+		// Use float64 because (trace.ticksEnd - trace.ticksStart) * 1e9 can overflow int64.
+		freq := float64(trace.ticksEnd-trace.ticksStart) * 1e9 / float64(trace.timeEnd-trace.timeStart) / traceTickDiv
+		trace.lockOwner = nil
+		unlock(&trace.lock)
+		var data []byte
+		data = append(data, traceEvFrequency|0<<traceArgCountShift)
+		data = traceAppend(data, uint64(freq))
+		data = traceAppend(data, 0)
+		if timers.gp != nil {
+			data = append(data, traceEvTimerGoroutine|0<<traceArgCountShift)
+			data = traceAppend(data, uint64(timers.gp.goid))
+			data = traceAppend(data, 0)
+		}
+		return data
+	}
+	// Done.
+	if trace.shutdown {
+		trace.lockOwner = nil
+		unlock(&trace.lock)
+		if raceenabled {
+			// Model synchronization on trace.shutdownSema, which race
+			// detector does not see. This is required to avoid false
+			// race reports on writer passed to trace.Start.
+			racerelease(unsafe.Pointer(&trace.shutdownSema))
+		}
+		// trace.enabled is already reset, so can call traceable functions.
+		semrelease(&trace.shutdownSema)
+		return nil
+	}
+	// Also bad, but see the comment above.
+	trace.lockOwner = nil
+	unlock(&trace.lock)
+	println("runtime: spurious wakeup of trace reader")
+	return nil
+}
+
+// traceReader returns the trace reader that should be woken up, if any.
+func traceReader() *g {
+	if trace.reader == nil || (trace.fullHead == nil && !trace.shutdown) {
+		return nil
+	}
+	lock(&trace.lock)
+	if trace.reader == nil || (trace.fullHead == nil && !trace.shutdown) {
+		unlock(&trace.lock)
+		return nil
+	}
+	gp := trace.reader
+	trace.reader = nil
+	unlock(&trace.lock)
+	return gp
+}
+
+// traceProcFree frees trace buffer associated with pp.
+func traceProcFree(pp *p) {
+	buf := pp.tracebuf
+	pp.tracebuf = nil
+	if buf == nil {
+		return
+	}
+	lock(&trace.lock)
+	traceFullQueue(buf)
+	unlock(&trace.lock)
+}
+
+// traceFullQueue queues buf into queue of full buffers.
+func traceFullQueue(buf *traceBuf) {
+	buf.link = nil
+	if trace.fullHead == nil {
+		trace.fullHead = buf
+	} else {
+		trace.fullTail.link = buf
+	}
+	trace.fullTail = buf
+}
+
+// traceFullDequeue dequeues from queue of full buffers.
+func traceFullDequeue() *traceBuf {
+	buf := trace.fullHead
+	if buf == nil {
+		return nil
+	}
+	trace.fullHead = buf.link
+	if trace.fullHead == nil {
+		trace.fullTail = nil
+	}
+	buf.link = nil
+	return buf
+}
+
+// traceEvent writes a single event to trace buffer, flushing the buffer if necessary.
+// ev is event type.
+// 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.
+
+	// The caller checked that trace.enabled == true, but trace.enabled might have been
+	// turned off between the check and now. Check again. traceLockBuffer did mp.locks++,
+	// StopTrace does stopTheWorld, and stopTheWorld waits for mp.locks to go back to zero,
+	// so if we see trace.enabled == true now, we know it's true for the rest of the function.
+	// Exitsyscall can run even during stopTheWorld. The race with StartTrace/StopTrace
+	// during tracing in exitsyscall is resolved by locking trace.bufLock in traceLockBuffer.
+	if !trace.enabled && !mp.startingtrace {
+		traceReleaseBuffer(pid)
+		return
+	}
+	buf := *bufp
+	const maxSize = 2 + 5*traceBytesPerNumber // event type, length, sequence, timestamp, stack id and two add params
+	if buf == nil || cap(buf.buf)-len(buf.buf) < maxSize {
+		buf = traceFlush(buf)
+		*bufp = buf
+	}
+
+	seq, ticksraw := tracestamp()
+	seqDiff := seq - buf.lastSeq
+	ticks := uint64(ticksraw) / traceTickDiv
+	tickDiff := ticks - buf.lastTicks
+	if len(buf.buf) == 0 {
+		data := buf.buf
+		data = append(data, traceEvBatch|1<<traceArgCountShift)
+		data = traceAppend(data, uint64(pid))
+		data = traceAppend(data, seq)
+		data = traceAppend(data, ticks)
+		buf.buf = data
+		seqDiff = 0
+		tickDiff = 0
+	}
+	buf.lastSeq = seq
+	buf.lastTicks = ticks
+	narg := byte(len(args))
+	if skip >= 0 {
+		narg++
+	}
+	// We have only 2 bits for number of arguments.
+	// If number is >= 3, then the event type is followed by event length in bytes.
+	if narg > 3 {
+		narg = 3
+	}
+	data := buf.buf
+	data = append(data, ev|narg<<traceArgCountShift)
+	var lenp *byte
+	if narg == 3 {
+		// Reserve the byte for length assuming that length < 128.
+		data = append(data, 0)
+		lenp = &data[len(data)-1]
+	}
+	data = traceAppend(data, seqDiff)
+	data = traceAppend(data, tickDiff)
+	for _, a := range args {
+		data = traceAppend(data, a)
+	}
+	if skip == 0 {
+		data = append(data, 0)
+	} else if skip > 0 {
+		_g_ := getg()
+		gp := mp.curg
+		var nstk int
+		if gp == _g_ {
+			nstk = callers(skip, buf.stk[:])
+		} else if gp != nil {
+			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))
+	}
+	evSize := len(data) - len(buf.buf)
+	if evSize > maxSize {
+		throw("invalid length of trace event")
+	}
+	if lenp != nil {
+		// Fill in actual length.
+		*lenp = byte(evSize - 2)
+	}
+	buf.buf = data
+	traceReleaseBuffer(pid)
+}
+
+// traceAcquireBuffer returns trace buffer to use and, if necessary, locks it.
+func traceAcquireBuffer() (mp *m, pid int32, bufp **traceBuf) {
+	mp = acquirem()
+	if p := mp.p.ptr(); p != nil {
+		return mp, p.id, &p.tracebuf
+	}
+	lock(&trace.bufLock)
+	return mp, traceGlobProc, &trace.buf
+}
+
+// traceReleaseBuffer releases a buffer previously acquired with traceAcquireBuffer.
+func traceReleaseBuffer(pid int32) {
+	if pid == traceGlobProc {
+		unlock(&trace.bufLock)
+	}
+	releasem(getg().m)
+}
+
+// traceFlush puts buf onto stack of full buffers and returns an empty buffer.
+func traceFlush(buf *traceBuf) *traceBuf {
+	owner := trace.lockOwner
+	dolock := owner == nil || owner != getg().m.curg
+	if dolock {
+		lock(&trace.lock)
+	}
+	if buf != nil {
+		if &buf.buf[0] != &buf.arr[0] {
+			throw("trace buffer overflow")
+		}
+		traceFullQueue(buf)
+	}
+	if trace.empty != nil {
+		buf = trace.empty
+		trace.empty = buf.link
+	} else {
+		buf = (*traceBuf)(sysAlloc(unsafe.Sizeof(traceBuf{}), &memstats.other_sys))
+		if buf == nil {
+			throw("trace: out of memory")
+		}
+	}
+	buf.link = nil
+	buf.buf = buf.arr[:0]
+	buf.lastTicks = 0
+	if dolock {
+		unlock(&trace.lock)
+	}
+	return buf
+}
+
+// traceAppend appends v to buf in little-endian-base-128 encoding.
+func traceAppend(buf []byte, v uint64) []byte {
+	for ; v >= 0x80; v >>= 7 {
+		buf = append(buf, 0x80|byte(v))
+	}
+	buf = append(buf, byte(v))
+	return buf
+}
+
+// traceStackTable maps stack traces (arrays of PC's) to unique uint32 ids.
+// It is lock-free for reading.
+type traceStackTable struct {
+	lock mutex
+	seq  uint32
+	mem  traceAlloc
+	tab  [1 << 13]*traceStack
+}
+
+// traceStack is a single stack in traceStackTable.
+type traceStack struct {
+	link *traceStack
+	hash uintptr
+	id   uint32
+	n    int
+	stk  [0]uintptr // real type [n]uintptr
+}
+
+// stack returns slice of PCs.
+func (ts *traceStack) stack() []uintptr {
+	return (*[traceStackSize]uintptr)(unsafe.Pointer(&ts.stk))[:ts.n]
+}
+
+// put returns a unique id for the stack trace pcs and caches it in the table,
+// if it sees the trace for the first time.
+func (tab *traceStackTable) put(pcs []uintptr) uint32 {
+	if len(pcs) == 0 {
+		return 0
+	}
+	hash := memhash(unsafe.Pointer(&pcs[0]), uintptr(len(pcs))*unsafe.Sizeof(pcs[0]), 0)
+	// First, search the hashtable w/o the mutex.
+	if id := tab.find(pcs, hash); id != 0 {
+		return id
+	}
+	// Now, double check under the mutex.
+	lock(&tab.lock)
+	if id := tab.find(pcs, hash); id != 0 {
+		unlock(&tab.lock)
+		return id
+	}
+	// Create new record.
+	tab.seq++
+	stk := tab.newStack(len(pcs))
+	stk.hash = hash
+	stk.id = tab.seq
+	stk.n = len(pcs)
+	stkpc := stk.stack()
+	for i, pc := range pcs {
+		stkpc[i] = pc
+	}
+	part := int(hash % uintptr(len(tab.tab)))
+	stk.link = tab.tab[part]
+	atomicstorep(unsafe.Pointer(&tab.tab[part]), unsafe.Pointer(stk))
+	unlock(&tab.lock)
+	return stk.id
+}
+
+// find checks if the stack trace pcs is already present in the table.
+func (tab *traceStackTable) find(pcs []uintptr, hash uintptr) uint32 {
+	part := int(hash % uintptr(len(tab.tab)))
+Search:
+	for stk := tab.tab[part]; stk != nil; stk = stk.link {
+		if stk.hash == hash && stk.n == len(pcs) {
+			for i, stkpc := range stk.stack() {
+				if stkpc != pcs[i] {
+					continue Search
+				}
+			}
+			return stk.id
+		}
+	}
+	return 0
+}
+
+// newStack allocates a new stack of size n.
+func (tab *traceStackTable) newStack(n int) *traceStack {
+	return (*traceStack)(tab.mem.alloc(unsafe.Sizeof(traceStack{}) + uintptr(n)*ptrSize))
+}
+
+// dump writes all previously cached stacks to trace buffers,
+// releases all memory and resets state.
+func (tab *traceStackTable) dump() {
+	var tmp [(2 + traceStackSize) * traceBytesPerNumber]byte
+	buf := traceFlush(nil)
+	for _, stk := range tab.tab {
+		for ; stk != nil; stk = stk.link {
+			maxSize := 1 + (3+stk.n)*traceBytesPerNumber
+			if cap(buf.buf)-len(buf.buf) < maxSize {
+				buf = traceFlush(buf)
+			}
+			// Form the event in the temp buffer, we need to know the actual length.
+			tmpbuf := tmp[:0]
+			tmpbuf = traceAppend(tmpbuf, uint64(stk.id))
+			tmpbuf = traceAppend(tmpbuf, uint64(stk.n))
+			for _, pc := range stk.stack() {
+				tmpbuf = traceAppend(tmpbuf, uint64(pc))
+			}
+			// Now copy to the buffer.
+			data := buf.buf
+			data = append(data, traceEvStack|3<<traceArgCountShift)
+			data = traceAppend(data, uint64(len(tmpbuf)))
+			data = append(data, tmpbuf...)
+			buf.buf = data
+		}
+	}
+
+	lock(&trace.lock)
+	traceFullQueue(buf)
+	unlock(&trace.lock)
+
+	tab.mem.drop()
+	*tab = traceStackTable{}
+}
+
+// traceAlloc is a non-thread-safe region allocator.
+// It holds a linked list of traceAllocBlock.
+type traceAlloc struct {
+	head *traceAllocBlock
+	off  uintptr
+}
+
+// traceAllocBlock is a block in traceAlloc.
+type traceAllocBlock struct {
+	next *traceAllocBlock
+	data [64<<10 - ptrSize]byte
+}
+
+// alloc allocates n-byte block.
+func (a *traceAlloc) alloc(n uintptr) unsafe.Pointer {
+	n = round(n, ptrSize)
+	if a.head == nil || a.off+n > uintptr(len(a.head.data)) {
+		if n > uintptr(len(a.head.data)) {
+			throw("trace: alloc too large")
+		}
+		block := (*traceAllocBlock)(sysAlloc(unsafe.Sizeof(traceAllocBlock{}), &memstats.other_sys))
+		if block == nil {
+			throw("trace: out of memory")
+		}
+		block.next = a.head
+		a.head = block
+		a.off = 0
+	}
+	p := &a.head.data[a.off]
+	a.off += n
+	return unsafe.Pointer(p)
+}
+
+// drop frees all previously allocated memory and resets the allocator.
+func (a *traceAlloc) drop() {
+	for a.head != nil {
+		block := a.head
+		a.head = block.next
+		sysFree(unsafe.Pointer(block), unsafe.Sizeof(traceAllocBlock{}), &memstats.other_sys)
+	}
+}
+
+// The following functions write specific events to trace.
+
+func traceGomaxprocs(procs int32) {
+	traceEvent(traceEvGomaxprocs, 1, uint64(procs))
+}
+
+func traceProcStart() {
+	traceEvent(traceEvProcStart, -1, uint64(getg().m.id))
+}
+
+func traceProcStop(pp *p) {
+	// Sysmon and stopTheWorld can stop Ps blocked in syscalls,
+	// to handle this we temporary employ the P.
+	mp := acquirem()
+	oldp := mp.p
+	mp.p.set(pp)
+	traceEvent(traceEvProcStop, -1)
+	mp.p = oldp
+	releasem(mp)
+}
+
+func traceGCStart() {
+	traceEvent(traceEvGCStart, 4)
+}
+
+func traceGCDone() {
+	traceEvent(traceEvGCDone, -1)
+}
+
+func traceGCScanStart() {
+	traceEvent(traceEvGCScanStart, -1)
+}
+
+func traceGCScanDone() {
+	traceEvent(traceEvGCScanDone, -1)
+}
+
+func traceGCSweepStart() {
+	traceEvent(traceEvGCSweepStart, 1)
+}
+
+func traceGCSweepDone() {
+	traceEvent(traceEvGCSweepDone, -1)
+}
+
+func traceGoCreate(newg *g, pc uintptr) {
+	traceEvent(traceEvGoCreate, 2, uint64(newg.goid), uint64(pc))
+}
+
+func traceGoStart() {
+	traceEvent(traceEvGoStart, -1, uint64(getg().m.curg.goid))
+}
+
+func traceGoEnd() {
+	traceEvent(traceEvGoEnd, -1)
+}
+
+func traceGoSched() {
+	traceEvent(traceEvGoSched, 1)
+}
+
+func traceGoPreempt() {
+	traceEvent(traceEvGoPreempt, 1)
+}
+
+func traceGoPark(traceEv byte, skip int, gp *g) {
+	if traceEv&traceFutileWakeup != 0 {
+		traceEvent(traceEvFutileWakeup, -1)
+	}
+	traceEvent(traceEv & ^traceFutileWakeup, skip)
+}
+
+func traceGoUnpark(gp *g, skip int) {
+	traceEvent(traceEvGoUnblock, skip, uint64(gp.goid))
+}
+
+func traceGoSysCall() {
+	traceEvent(traceEvGoSysCall, 4)
+}
+
+func traceGoSysExit(seq uint64, ts int64) {
+	if int64(seq)-int64(trace.seqStart) < 0 {
+		// The timestamp was obtained during a previous tracing session, ignore.
+		return
+	}
+	traceEvent(traceEvGoSysExit, -1, uint64(getg().m.curg.goid), seq, uint64(ts)/traceTickDiv)
+}
+
+func traceGoSysBlock(pp *p) {
+	// Sysmon and stopTheWorld can declare syscalls running on remote Ps as blocked,
+	// to handle this we temporary employ the P.
+	mp := acquirem()
+	oldp := mp.p
+	mp.p.set(pp)
+	traceEvent(traceEvGoSysBlock, -1)
+	mp.p = oldp
+	releasem(mp)
+}
+
+func traceHeapAlloc() {
+	traceEvent(traceEvHeapAlloc, -1, memstats.heap_live)
+}
+
+func traceNextGC() {
+	traceEvent(traceEvNextGC, -1, memstats.next_gc)
+}
diff --git a/src/runtime/trace/trace.go b/src/runtime/trace/trace.go
new file mode 100644
index 0000000..7cbb8a6
--- /dev/null
+++ b/src/runtime/trace/trace.go
@@ -0,0 +1,42 @@
+// 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 execution tracer.
+// The tracer captures a wide range of execution events like goroutine
+// creation/blocking/unblocking, syscall enter/exit/block, GC-related events,
+// changes of heap size, processor start/stop, etc and writes them to an io.Writer
+// in a compact form. A precise nanosecond-precision timestamp and a stack
+// trace is captured for most events. A trace can be analyzed later with
+// 'go tool trace' command.
+package trace
+
+import (
+	"io"
+	"runtime"
+)
+
+// Start enables tracing for the current program.
+// While tracing, the trace will be buffered and written to w.
+// Start returns an error if tracing is already enabled.
+func Start(w io.Writer) error {
+	if err := runtime.StartTrace(); err != nil {
+		return err
+	}
+	go func() {
+		for {
+			data := runtime.ReadTrace()
+			if data == nil {
+				break
+			}
+			w.Write(data)
+		}
+	}()
+	return nil
+}
+
+// Stop stops the current tracing, if any.
+// Stop only returns after all the writes for the trace have completed.
+func Stop() {
+	runtime.StopTrace()
+}
diff --git a/src/runtime/trace/trace_stack_test.go b/src/runtime/trace/trace_stack_test.go
new file mode 100644
index 0000000..3fe1747
--- /dev/null
+++ b/src/runtime/trace/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 trace_test
+
+import (
+	"bytes"
+	"internal/testenv"
+	"internal/trace"
+	"net"
+	"os"
+	"runtime"
+	. "runtime/trace"
+	"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) {
+	testenv.MustHaveGoBuild(t)
+
+	buf := new(bytes.Buffer)
+	if err := Start(buf); err != nil {
+		t.Fatalf("failed to start tracing: %v", err)
+	}
+	defer Stop() // in case of early return
+
+	// 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", "127.0.0.1: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
+
+	Stop()
+	events, _, err := parseTrace(t, 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/trace_test.TestTraceSymbolize", 106},
+			frame{"testing.tRunner", 0},
+		}},
+		eventDesc{trace.EvGoSched, []frame{
+			frame{"runtime/trace_test.TestTraceSymbolize", 107},
+			frame{"testing.tRunner", 0},
+		}},
+		eventDesc{trace.EvGoCreate, []frame{
+			frame{"runtime/trace_test.TestTraceSymbolize", 39},
+			frame{"testing.tRunner", 0},
+		}},
+		eventDesc{trace.EvGoStop, []frame{
+			frame{"runtime.block", 0},
+			frame{"runtime/trace_test.TestTraceSymbolize.func1", 38},
+		}},
+		eventDesc{trace.EvGoStop, []frame{
+			frame{"runtime.chansend1", 0},
+			frame{"runtime/trace_test.TestTraceSymbolize.func2", 42},
+		}},
+		eventDesc{trace.EvGoStop, []frame{
+			frame{"runtime.chanrecv1", 0},
+			frame{"runtime/trace_test.TestTraceSymbolize.func3", 46},
+		}},
+		eventDesc{trace.EvGoBlockRecv, []frame{
+			frame{"runtime.chanrecv1", 0},
+			frame{"runtime/trace_test.TestTraceSymbolize.func4", 50},
+		}},
+		eventDesc{trace.EvGoUnblock, []frame{
+			frame{"runtime.chansend1", 0},
+			frame{"runtime/trace_test.TestTraceSymbolize", 109},
+			frame{"testing.tRunner", 0},
+		}},
+		eventDesc{trace.EvGoBlockSend, []frame{
+			frame{"runtime.chansend1", 0},
+			frame{"runtime/trace_test.TestTraceSymbolize.func5", 54},
+		}},
+		eventDesc{trace.EvGoUnblock, []frame{
+			frame{"runtime.chanrecv1", 0},
+			frame{"runtime/trace_test.TestTraceSymbolize", 110},
+			frame{"testing.tRunner", 0},
+		}},
+		eventDesc{trace.EvGoBlockSelect, []frame{
+			frame{"runtime.selectgo", 0},
+			frame{"runtime/trace_test.TestTraceSymbolize.func6", 59},
+		}},
+		eventDesc{trace.EvGoUnblock, []frame{
+			frame{"runtime.selectgo", 0},
+			frame{"runtime/trace_test.TestTraceSymbolize", 111},
+			frame{"testing.tRunner", 0},
+		}},
+		eventDesc{trace.EvGoBlockSync, []frame{
+			frame{"sync.(*Mutex).Lock", 0},
+			frame{"runtime/trace_test.TestTraceSymbolize.func7", 67},
+		}},
+		eventDesc{trace.EvGoUnblock, []frame{
+			frame{"sync.(*Mutex).Unlock", 0},
+			frame{"runtime/trace_test.TestTraceSymbolize", 115},
+			frame{"testing.tRunner", 0},
+		}},
+		eventDesc{trace.EvGoBlockSync, []frame{
+			frame{"sync.(*WaitGroup).Wait", 0},
+			frame{"runtime/trace_test.TestTraceSymbolize.func8", 73},
+		}},
+		eventDesc{trace.EvGoUnblock, []frame{
+			frame{"sync.(*WaitGroup).Add", 0},
+			frame{"sync.(*WaitGroup).Done", 0},
+			frame{"runtime/trace_test.TestTraceSymbolize", 116},
+			frame{"testing.tRunner", 0},
+		}},
+		eventDesc{trace.EvGoBlockCond, []frame{
+			frame{"sync.(*Cond).Wait", 0},
+			frame{"runtime/trace_test.TestTraceSymbolize.func9", 78},
+		}},
+		eventDesc{trace.EvGoUnblock, []frame{
+			frame{"sync.(*Cond).Signal", 0},
+			frame{"runtime/trace_test.TestTraceSymbolize", 117},
+			frame{"testing.tRunner", 0},
+		}},
+		eventDesc{trace.EvGoSleep, []frame{
+			frame{"time.Sleep", 0},
+			frame{"runtime/trace_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/trace_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/trace_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/trace/trace_test.go b/src/runtime/trace/trace_test.go
new file mode 100644
index 0000000..0a8957f
--- /dev/null
+++ b/src/runtime/trace/trace_test.go
@@ -0,0 +1,434 @@
+// 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_test
+
+import (
+	"bytes"
+	"internal/trace"
+	"io"
+	"net"
+	"os"
+	"runtime"
+	. "runtime/trace"
+	"sync"
+	"testing"
+	"time"
+)
+
+func TestTraceStartStop(t *testing.T) {
+	buf := new(bytes.Buffer)
+	if err := Start(buf); err != nil {
+		t.Fatalf("failed to start tracing: %v", err)
+	}
+	Stop()
+	size := buf.Len()
+	if size == 0 {
+		t.Fatalf("trace is empty")
+	}
+	time.Sleep(100 * time.Millisecond)
+	if size != buf.Len() {
+		t.Fatalf("trace writes after stop: %v -> %v", size, buf.Len())
+	}
+}
+
+func TestTraceDoubleStart(t *testing.T) {
+	Stop()
+	buf := new(bytes.Buffer)
+	if err := Start(buf); err != nil {
+		t.Fatalf("failed to start tracing: %v", err)
+	}
+	if err := Start(buf); err == nil {
+		t.Fatalf("succeed to start tracing second time")
+	}
+	Stop()
+	Stop()
+}
+
+func TestTrace(t *testing.T) {
+	buf := new(bytes.Buffer)
+	if err := Start(buf); err != nil {
+		t.Fatalf("failed to start tracing: %v", err)
+	}
+	Stop()
+	_, err := trace.Parse(buf)
+	if err == trace.ErrTimeOrder {
+		t.Skipf("skipping trace: %v", err)
+	}
+	if err != nil {
+		t.Fatalf("failed to parse trace: %v", err)
+	}
+}
+
+func parseTrace(t *testing.T, r io.Reader) ([]*trace.Event, map[uint64]*trace.GDesc, error) {
+	events, err := trace.Parse(r)
+	if err == trace.ErrTimeOrder {
+		t.Skipf("skipping trace: %v", err)
+	}
+	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) {
+	var wg sync.WaitGroup
+	done := make(chan bool)
+
+	// Create a goroutine blocked before tracing.
+	wg.Add(1)
+	go func() {
+		<-done
+		wg.Done()
+	}()
+
+	// Create a goroutine blocked in syscall before tracing.
+	rp, wp, err := os.Pipe()
+	if err != nil {
+		t.Fatalf("failed to create pipe: %v", err)
+	}
+	defer func() {
+		rp.Close()
+		wp.Close()
+	}()
+	wg.Add(1)
+	go func() {
+		var tmp [1]byte
+		rp.Read(tmp[:])
+		<-done
+		wg.Done()
+	}()
+	time.Sleep(time.Millisecond) // give the goroutine above time to block
+
+	buf := new(bytes.Buffer)
+	if err := Start(buf); err != nil {
+		t.Fatalf("failed to start tracing: %v", err)
+	}
+
+	procs := runtime.GOMAXPROCS(10)
+	time.Sleep(50 * time.Millisecond) // test proc stop/start events
+
+	go func() {
+		runtime.LockOSThread()
+		for {
+			select {
+			case <-done:
+				return
+			default:
+				runtime.Gosched()
+			}
+		}
+	}()
+
+	runtime.GC()
+	// Trigger GC from malloc.
+	for i := 0; i < 1e3; i++ {
+		_ = make([]byte, 1<<20)
+	}
+
+	// Create a bunch of busy goroutines to load all Ps.
+	for p := 0; p < 10; p++ {
+		wg.Add(1)
+		go func() {
+			// Do something useful.
+			tmp := make([]byte, 1<<16)
+			for i := range tmp {
+				tmp[i]++
+			}
+			_ = tmp
+			<-done
+			wg.Done()
+		}()
+	}
+
+	// Block in syscall.
+	wg.Add(1)
+	go func() {
+		var tmp [1]byte
+		rp.Read(tmp[:])
+		<-done
+		wg.Done()
+	}()
+
+	// Test timers.
+	timerDone := make(chan bool)
+	go func() {
+		time.Sleep(time.Millisecond)
+		timerDone <- true
+	}()
+	<-timerDone
+
+	// A bit of network.
+	ln, err := net.Listen("tcp", "127.0.0.1:0")
+	if err != nil {
+		t.Fatalf("listen failed: %v", err)
+	}
+	defer ln.Close()
+	go func() {
+		c, err := ln.Accept()
+		if err != nil {
+			return
+		}
+		time.Sleep(time.Millisecond)
+		var buf [1]byte
+		c.Write(buf[:])
+		c.Close()
+	}()
+	c, err := net.Dial("tcp", ln.Addr().String())
+	if err != nil {
+		t.Fatalf("dial failed: %v", err)
+	}
+	var tmp [1]byte
+	c.Read(tmp[:])
+	c.Close()
+
+	go func() {
+		runtime.Gosched()
+		select {}
+	}()
+
+	// Unblock helper goroutines and wait them to finish.
+	wp.Write(tmp[:])
+	wp.Write(tmp[:])
+	close(done)
+	wg.Wait()
+
+	runtime.GOMAXPROCS(procs)
+
+	Stop()
+	_, _, err = parseTrace(t, buf)
+	if err != nil {
+		t.Fatalf("failed to parse trace: %v", err)
+	}
+}
+
+// Do a bunch of various stuff (timers, GC, network, etc) in a separate goroutine.
+// And concurrently with all that start/stop trace 3 times.
+func TestTraceStressStartStop(t *testing.T) {
+	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(8))
+	outerDone := make(chan bool)
+
+	go func() {
+		defer func() {
+			outerDone <- true
+		}()
+
+		var wg sync.WaitGroup
+		done := make(chan bool)
+
+		wg.Add(1)
+		go func() {
+			<-done
+			wg.Done()
+		}()
+
+		rp, wp, err := os.Pipe()
+		if err != nil {
+			t.Fatalf("failed to create pipe: %v", err)
+		}
+		defer func() {
+			rp.Close()
+			wp.Close()
+		}()
+		wg.Add(1)
+		go func() {
+			var tmp [1]byte
+			rp.Read(tmp[:])
+			<-done
+			wg.Done()
+		}()
+		time.Sleep(time.Millisecond)
+
+		go func() {
+			runtime.LockOSThread()
+			for {
+				select {
+				case <-done:
+					return
+				default:
+					runtime.Gosched()
+				}
+			}
+		}()
+
+		runtime.GC()
+		// Trigger GC from malloc.
+		for i := 0; i < 1e3; i++ {
+			_ = make([]byte, 1<<20)
+		}
+
+		// Create a bunch of busy goroutines to load all Ps.
+		for p := 0; p < 10; p++ {
+			wg.Add(1)
+			go func() {
+				// Do something useful.
+				tmp := make([]byte, 1<<16)
+				for i := range tmp {
+					tmp[i]++
+				}
+				_ = tmp
+				<-done
+				wg.Done()
+			}()
+		}
+
+		// Block in syscall.
+		wg.Add(1)
+		go func() {
+			var tmp [1]byte
+			rp.Read(tmp[:])
+			<-done
+			wg.Done()
+		}()
+
+		runtime.GOMAXPROCS(runtime.GOMAXPROCS(1))
+
+		// Test timers.
+		timerDone := make(chan bool)
+		go func() {
+			time.Sleep(time.Millisecond)
+			timerDone <- true
+		}()
+		<-timerDone
+
+		// A bit of network.
+		ln, err := net.Listen("tcp", "127.0.0.1:0")
+		if err != nil {
+			t.Fatalf("listen failed: %v", err)
+		}
+		defer ln.Close()
+		go func() {
+			c, err := ln.Accept()
+			if err != nil {
+				return
+			}
+			time.Sleep(time.Millisecond)
+			var buf [1]byte
+			c.Write(buf[:])
+			c.Close()
+		}()
+		c, err := net.Dial("tcp", ln.Addr().String())
+		if err != nil {
+			t.Fatalf("dial failed: %v", err)
+		}
+		var tmp [1]byte
+		c.Read(tmp[:])
+		c.Close()
+
+		go func() {
+			runtime.Gosched()
+			select {}
+		}()
+
+		// Unblock helper goroutines and wait them to finish.
+		wp.Write(tmp[:])
+		wp.Write(tmp[:])
+		close(done)
+		wg.Wait()
+	}()
+
+	for i := 0; i < 3; i++ {
+		buf := new(bytes.Buffer)
+		if err := Start(buf); err != nil {
+			t.Fatalf("failed to start tracing: %v", err)
+		}
+		time.Sleep(time.Millisecond)
+		Stop()
+		if _, _, err := parseTrace(t, buf); err != nil {
+			t.Fatalf("failed to parse trace: %v", err)
+		}
+	}
+	<-outerDone
+}
+
+func TestTraceFutileWakeup(t *testing.T) {
+	buf := new(bytes.Buffer)
+	if err := Start(buf); err != nil {
+		t.Fatalf("failed to start tracing: %v", err)
+	}
+
+	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()
+
+	Stop()
+	events, _, err := parseTrace(t, buf)
+	if err != nil {
+		t.Fatalf("failed to parse trace: %v", err)
+	}
+	// 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 {
+		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)
+		}
+	}
+}
diff --git a/src/runtime/traceback.go b/src/runtime/traceback.go
index 1c6ce6e..2def359 100644
--- a/src/runtime/traceback.go
+++ b/src/runtime/traceback.go
@@ -32,15 +32,25 @@ const usesLR = GOARCH != "amd64" && GOARCH != "amd64p32" && GOARCH != "386"
 
 var (
 	// initialized in tracebackinit
-	deferprocPC uintptr
-	goexitPC    uintptr
-	jmpdeferPC  uintptr
-	mcallPC     uintptr
-	morestackPC uintptr
-	mstartPC    uintptr
-	newprocPC   uintptr
-	rt0_goPC    uintptr
-	sigpanicPC  uintptr
+	goexitPC             uintptr
+	jmpdeferPC           uintptr
+	mcallPC              uintptr
+	morestackPC          uintptr
+	mstartPC             uintptr
+	rt0_goPC             uintptr
+	sigpanicPC           uintptr
+	runfinqPC            uintptr
+	backgroundgcPC       uintptr
+	bgsweepPC            uintptr
+	forcegchelperPC      uintptr
+	timerprocPC          uintptr
+	gcBgMarkWorkerPC     uintptr
+	systemstack_switchPC uintptr
+	systemstackPC        uintptr
+	stackBarrierPC       uintptr
+	cgocallback_gofuncPC uintptr
+
+	gogoPC uintptr
 
 	externalthreadhandlerp uintptr // initialized elsewhere
 )
@@ -50,15 +60,26 @@ func tracebackinit() {
 	// Instead of initializing the variables above in the declarations,
 	// schedinit calls this function so that the variables are
 	// initialized and available earlier in the startup sequence.
-	deferprocPC = funcPC(deferproc)
 	goexitPC = funcPC(goexit)
 	jmpdeferPC = funcPC(jmpdefer)
 	mcallPC = funcPC(mcall)
 	morestackPC = funcPC(morestack)
 	mstartPC = funcPC(mstart)
-	newprocPC = funcPC(newproc)
 	rt0_goPC = funcPC(rt0_go)
 	sigpanicPC = funcPC(sigpanic)
+	runfinqPC = funcPC(runfinq)
+	backgroundgcPC = funcPC(backgroundgc)
+	bgsweepPC = funcPC(bgsweep)
+	forcegchelperPC = funcPC(forcegchelper)
+	timerprocPC = funcPC(timerproc)
+	gcBgMarkWorkerPC = funcPC(gcBgMarkWorker)
+	systemstack_switchPC = funcPC(systemstack_switch)
+	systemstackPC = funcPC(systemstack)
+	stackBarrierPC = funcPC(stackBarrier)
+	cgocallback_gofuncPC = funcPC(cgocallback_gofunc)
+
+	// used by sigprof handler
+	gogoPC = funcPC(gogo)
 }
 
 // Traceback over the deferred function calls.
@@ -79,7 +100,7 @@ func tracebackdefers(gp *g, callback func(*stkframe, unsafe.Pointer) bool, v uns
 			f := findfunc(frame.pc)
 			if f == nil {
 				print("runtime: unknown pc in defer ", hex(frame.pc), "\n")
-				gothrow("unknown pc")
+				throw("unknown pc")
 			}
 			frame.fn = f
 			frame.argp = uintptr(deferArgs(d))
@@ -96,9 +117,9 @@ func tracebackdefers(gp *g, callback func(*stkframe, unsafe.Pointer) bool, v uns
 // the runtime.Callers function (pcbuf != nil), as well as the garbage
 // collector (callback != nil).  A little clunky to merge these, but avoids
 // duplicating the code and all its subtlety.
-func gentraceback(pc0 uintptr, sp0 uintptr, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max int, callback func(*stkframe, unsafe.Pointer) bool, v unsafe.Pointer, flags uint) int {
+func gentraceback(pc0, sp0, lr0 uintptr, gp *g, skip int, pcbuf *uintptr, max int, callback func(*stkframe, unsafe.Pointer) bool, v unsafe.Pointer, flags uint) int {
 	if goexitPC == 0 {
-		gothrow("gentraceback before goexitPC initialization")
+		throw("gentraceback before goexitPC initialization")
 	}
 	g := getg()
 	if g == gp && g == g.m.curg {
@@ -115,9 +136,14 @@ func gentraceback(pc0 uintptr, sp0 uintptr, lr0 uintptr, gp *g, skip int, pcbuf
 		// accepts an sp for the current goroutine (typically obtained by
 		// calling getcallersp) must not run on that goroutine's stack but
 		// instead on the g0 stack.
-		gothrow("gentraceback cannot trace user goroutine on its own stack")
+		throw("gentraceback cannot trace user goroutine on its own stack")
 	}
 	gotraceback := gotraceback(nil)
+
+	// Fix up returns to the stack barrier by fetching the
+	// original return PC from gp.stkbar.
+	stkbar := gp.stkbar[gp.stkbarPos:]
+
 	if pc0 == ^uintptr(0) && sp0 == ^uintptr(0) { // Signal to fetch saved values from gp.
 		if gp.syscallsp != 0 {
 			pc0 = gp.syscallpc
@@ -142,11 +168,10 @@ func gentraceback(pc0 uintptr, sp0 uintptr, lr0 uintptr, gp *g, skip int, pcbuf
 		frame.lr = lr0
 	}
 	waspanic := false
-	wasnewproc := false
 	printing := pcbuf == nil && callback == nil
 	_defer := gp._defer
 
-	for _defer != nil && uintptr(_defer.argp) == _NoArgs {
+	for _defer != nil && uintptr(_defer.sp) == _NoArgs {
 		_defer = _defer.link
 	}
 
@@ -166,7 +191,7 @@ func gentraceback(pc0 uintptr, sp0 uintptr, lr0 uintptr, gp *g, skip int, pcbuf
 	if f == nil {
 		if callback != nil {
 			print("runtime: unknown pc ", hex(frame.pc), "\n")
-			gothrow("unknown pc")
+			throw("unknown pc")
 		}
 		return 0
 	}
@@ -185,7 +210,15 @@ func gentraceback(pc0 uintptr, sp0 uintptr, lr0 uintptr, gp *g, skip int, pcbuf
 		// Found an actual function.
 		// Derive frame pointer and link register.
 		if frame.fp == 0 {
-			frame.fp = frame.sp + uintptr(funcspdelta(f, frame.pc))
+			// We want to jump over the systemstack switch. If we're running on the
+			// g0, this systemstack is at the top of the stack.
+			// if we're not on g0 or there's a no curg, then this is a regular call.
+			sp := frame.sp
+			if flags&_TraceJumpStack != 0 && f.entry == systemstackPC && gp == g.m.g0 && gp.m.curg != nil {
+				sp = gp.m.curg.sched.sp
+				stkbar = gp.m.curg.stkbar[gp.m.curg.stkbarPos:]
+			}
+			frame.fp = sp + uintptr(funcspdelta(f, frame.pc))
 			if !usesLR {
 				// On x86, call instruction pushes return PC before entering new function.
 				frame.fp += regSize
@@ -203,19 +236,33 @@ func gentraceback(pc0 uintptr, sp0 uintptr, lr0 uintptr, gp *g, skip int, pcbuf
 			// to avoid that confusion.
 			// See golang.org/issue/8153.
 			if callback != nil {
-				gothrow("traceback_arm: found jmpdefer when tracing with callback")
+				throw("traceback_arm: found jmpdefer when tracing with callback")
 			}
 			frame.lr = 0
 		} else {
+			var lrPtr uintptr
 			if usesLR {
 				if n == 0 && frame.sp < frame.fp || frame.lr == 0 {
-					frame.lr = *(*uintptr)(unsafe.Pointer(frame.sp))
+					lrPtr = frame.sp
+					frame.lr = *(*uintptr)(unsafe.Pointer(lrPtr))
 				}
 			} else {
 				if frame.lr == 0 {
-					frame.lr = uintptr(*(*uintreg)(unsafe.Pointer(frame.fp - regSize)))
+					lrPtr = frame.fp - regSize
+					frame.lr = uintptr(*(*uintreg)(unsafe.Pointer(lrPtr)))
 				}
 			}
+			if frame.lr == stackBarrierPC {
+				// Recover original PC.
+				if stkbar[0].savedLRPtr != lrPtr {
+					print("found next stack barrier at ", hex(lrPtr), "; expected ")
+					gcPrintStkbars(stkbar)
+					print("\n")
+					throw("missed stack barrier")
+				}
+				frame.lr = stkbar[0].savedLRVal
+				stkbar = stkbar[1:]
+			}
 			flr = findfunc(frame.lr)
 			if flr == nil {
 				// This happens if you get a profiling interrupt at just the wrong time.
@@ -223,8 +270,8 @@ func gentraceback(pc0 uintptr, sp0 uintptr, lr0 uintptr, gp *g, skip int, pcbuf
 				// But if callback is set, we're doing a garbage collection and must
 				// get everything, so crash loudly.
 				if callback != nil {
-					print("runtime: unexpected return pc for ", gofuncname(f), " called from ", hex(frame.lr), "\n")
-					gothrow("unknown caller pc")
+					print("runtime: unexpected return pc for ", funcname(f), " called from ", hex(frame.lr), "\n")
+					throw("unknown caller pc")
 				}
 			}
 		}
@@ -235,6 +282,12 @@ func gentraceback(pc0 uintptr, sp0 uintptr, lr0 uintptr, gp *g, skip int, pcbuf
 			frame.varp -= regSize
 		}
 
+		// If framepointer_enabled and there's a frame, then
+		// there's a saved bp here.
+		if framepointer_enabled && GOARCH == "amd64" && frame.varp > frame.sp {
+			frame.varp -= regSize
+		}
+
 		// Derive size of arguments.
 		// Most functions have a fixed-size argument block,
 		// so we can use metadata about the function f.
@@ -249,32 +302,6 @@ func gentraceback(pc0 uintptr, sp0 uintptr, lr0 uintptr, gp *g, skip int, pcbuf
 			setArgInfo(&frame, f, callback != nil)
 		}
 
-		// Determine function SP where deferproc would find its arguments.
-		var sparg uintptr
-		if usesLR {
-			// On link register architectures, that's the standard bottom-of-stack plus 1 word
-			// for the saved LR. If the previous frame was a direct call to newproc/deferproc,
-			// however, the SP is three words lower than normal.
-			// If the function has no frame at all - perhaps it just started, or perhaps
-			// it is a leaf with no local variables - then we cannot possibly find its
-			// SP in a defer, and we might confuse its SP for its caller's SP, so
-			// leave sparg=0 in that case.
-			if frame.fp != frame.sp {
-				sparg = frame.sp + regSize
-				if wasnewproc {
-					sparg += 3 * regSize
-				}
-			}
-		} else {
-			// On x86 that's the standard bottom-of-stack, so SP exactly.
-			// If the previous frame was a direct call to newproc/deferproc, however,
-			// the SP is two words lower than normal.
-			sparg = frame.sp
-			if wasnewproc {
-				sparg += 2 * ptrSize
-			}
-		}
-
 		// Determine frame's 'continuation PC', where it can continue.
 		// Normally this is the return address on the stack, but if sigpanic
 		// is immediately below this function on the stack, then the frame
@@ -287,7 +314,7 @@ func gentraceback(pc0 uintptr, sp0 uintptr, lr0 uintptr, gp *g, skip int, pcbuf
 		// returns; everything live at earlier deferprocs is still live at that one.
 		frame.continpc = frame.pc
 		if waspanic {
-			if _defer != nil && _defer.argp == sparg {
+			if _defer != nil && _defer.sp == frame.sp {
 				frame.continpc = _defer.pc
 			} else {
 				frame.continpc = 0
@@ -295,7 +322,7 @@ func gentraceback(pc0 uintptr, sp0 uintptr, lr0 uintptr, gp *g, skip int, pcbuf
 		}
 
 		// Unwind our local defer stack past this frame.
-		for _defer != nil && (_defer.argp == sparg || _defer.argp == _NoArgs) {
+		for _defer != nil && (_defer.sp == frame.sp || _defer.sp == _NoArgs) {
 			_defer = _defer.link
 		}
 
@@ -322,7 +349,7 @@ func gentraceback(pc0 uintptr, sp0 uintptr, lr0 uintptr, gp *g, skip int, pcbuf
 				if (n > 0 || flags&_TraceTrap == 0) && frame.pc > f.entry && !waspanic {
 					tracepc--
 				}
-				print(gofuncname(f), "(")
+				print(funcname(f), "(")
 				argp := (*[100]uintptr)(unsafe.Pointer(frame.argp))
 				for i := uintptr(0); i < frame.arglen/ptrSize; i++ {
 					if i >= 10 {
@@ -335,8 +362,7 @@ func gentraceback(pc0 uintptr, sp0 uintptr, lr0 uintptr, gp *g, skip int, pcbuf
 					print(hex(argp[i]))
 				}
 				print(")\n")
-				var file string
-				line := funcline(f, tracepc, &file)
+				file, line := funcline(f, tracepc)
 				print("\t", file, ":", line)
 				if frame.pc > f.entry {
 					print(" +", hex(frame.pc-f.entry))
@@ -352,7 +378,6 @@ func gentraceback(pc0 uintptr, sp0 uintptr, lr0 uintptr, gp *g, skip int, pcbuf
 
 	skipped:
 		waspanic = f.entry == sigpanicPC
-		wasnewproc = f.entry == newprocPC || f.entry == deferprocPC
 
 		// Do not unwind past the bottom of the stack.
 		if flr == nil {
@@ -372,17 +397,21 @@ func gentraceback(pc0 uintptr, sp0 uintptr, lr0 uintptr, gp *g, skip int, pcbuf
 		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
 			}
 		}
 	}
 
-	if pcbuf == nil && callback == nil {
+	if printing {
 		n = nprint
 	}
 
@@ -437,12 +466,19 @@ func gentraceback(pc0 uintptr, sp0 uintptr, lr0 uintptr, gp *g, skip int, pcbuf
 	// incomplete information then is still better than nothing.
 	if callback != nil && n < max && _defer != nil {
 		if _defer != nil {
-			print("runtime: g", gp.goid, ": leftover defer argp=", hex(_defer.argp), " pc=", hex(_defer.pc), "\n")
+			print("runtime: g", gp.goid, ": leftover defer sp=", hex(_defer.sp), " pc=", hex(_defer.pc), "\n")
 		}
 		for _defer = gp._defer; _defer != nil; _defer = _defer.link {
-			print("\tdefer ", _defer, " argp=", hex(_defer.argp), " pc=", hex(_defer.pc), "\n")
+			print("\tdefer ", _defer, " sp=", hex(_defer.sp), " pc=", hex(_defer.pc), "\n")
 		}
-		gothrow("traceback has leftover defers")
+		throw("traceback has leftover defers")
+	}
+
+	if callback != nil && n < max && len(stkbar) > 0 {
+		print("runtime: g", gp.goid, ": leftover stack barriers ")
+		gcPrintStkbars(stkbar)
+		print("\n")
+		throw("traceback has leftover stack barriers")
 	}
 
 	return n
@@ -452,7 +488,7 @@ func setArgInfo(frame *stkframe, f *_func, needArgMap bool) {
 	frame.arglen = uintptr(f.args)
 	if needArgMap && f.args == _ArgsSizeUnknown {
 		// Extract argument bitmaps for reflect stubs from the calls they made to reflect.
-		switch gofuncname(f) {
+		switch funcname(f) {
 		case "reflect.makeFuncStub", "reflect.methodValueCall":
 			arg0 := frame.sp
 			if usesLR {
@@ -460,11 +496,11 @@ func setArgInfo(frame *stkframe, f *_func, needArgMap bool) {
 			}
 			fn := *(**[2]uintptr)(unsafe.Pointer(arg0))
 			if fn[0] != f.entry {
-				print("runtime: confused by ", gofuncname(f), "\n")
-				gothrow("reflect mismatch")
+				print("runtime: confused by ", funcname(f), "\n")
+				throw("reflect mismatch")
 			}
 			bv := (*bitvector)(unsafe.Pointer(fn[1]))
-			frame.arglen = uintptr(bv.n / 2 * ptrSize)
+			frame.arglen = uintptr(bv.n * ptrSize)
 			frame.argmap = bv
 		}
 	}
@@ -475,13 +511,12 @@ func printcreatedby(gp *g) {
 	pc := gp.gopc
 	f := findfunc(pc)
 	if f != nil && showframe(f, gp) && gp.goid != 1 {
-		print("created by ", gofuncname(f), "\n")
+		print("created by ", funcname(f), "\n")
 		tracepc := pc // back up to CALL instruction for funcline.
 		if pc > f.entry {
 			tracepc -= _PCQuantum
 		}
-		var file string
-		line := funcline(f, tracepc, &file)
+		file, line := funcline(f, tracepc)
 		print("\t", file, ":", line)
 		if pc > f.entry {
 			print(" +", hex(pc-f.entry))
@@ -490,7 +525,7 @@ func printcreatedby(gp *g) {
 	}
 }
 
-func traceback(pc uintptr, sp uintptr, lr uintptr, gp *g) {
+func traceback(pc, sp, lr uintptr, gp *g) {
 	traceback1(pc, sp, lr, gp, 0)
 }
 
@@ -500,11 +535,11 @@ func traceback(pc uintptr, sp uintptr, lr uintptr, gp *g) {
 // the initial PC must not be rewound to the previous instruction.
 // (All the saved pairs record a PC that is a return address, so we
 // rewind it into the CALL instruction.)
-func tracebacktrap(pc uintptr, sp uintptr, lr uintptr, gp *g) {
+func tracebacktrap(pc, sp, lr uintptr, gp *g) {
 	traceback1(pc, sp, lr, gp, _TraceTrap)
 }
 
-func traceback1(pc uintptr, sp uintptr, lr uintptr, gp *g, flags uint) {
+func traceback1(pc, sp, lr uintptr, gp *g, flags uint) {
 	var n int
 	if readgstatus(gp)&^_Gscan == _Gsyscall {
 		// Override registers if blocked in system call.
@@ -524,27 +559,28 @@ func traceback1(pc uintptr, sp uintptr, lr uintptr, gp *g, flags uint) {
 	printcreatedby(gp)
 }
 
-func callers(skip int, pcbuf *uintptr, m int) int {
+func callers(skip int, pcbuf []uintptr) int {
 	sp := getcallersp(unsafe.Pointer(&skip))
 	pc := uintptr(getcallerpc(unsafe.Pointer(&skip)))
+	gp := getg()
 	var n int
-	onM(func() {
-		n = gentraceback(pc, sp, 0, getg(), skip, pcbuf, m, nil, nil, 0)
+	systemstack(func() {
+		n = gentraceback(pc, sp, 0, gp, skip, &pcbuf[0], len(pcbuf), nil, nil, 0)
 	})
 	return n
 }
 
-func gcallers(gp *g, skip int, pcbuf *uintptr, m int) int {
-	return gentraceback(^uintptr(0), ^uintptr(0), 0, gp, skip, pcbuf, m, nil, nil, 0)
+func gcallers(gp *g, skip int, pcbuf []uintptr) int {
+	return gentraceback(^uintptr(0), ^uintptr(0), 0, gp, skip, &pcbuf[0], len(pcbuf), nil, nil, 0)
 }
 
 func showframe(f *_func, gp *g) bool {
 	g := getg()
-	if g.m.throwing > 0 && gp != nil && (gp == g.m.curg || gp == g.m.caughtsig) {
+	if g.m.throwing > 0 && gp != nil && (gp == g.m.curg || gp == g.m.caughtsig.ptr()) {
 		return true
 	}
 	traceback := gotraceback(nil)
-	name := gostringnocopy(funcname(f))
+	name := funcname(f)
 
 	// Special case: always show runtime.panic frame, so that we can
 	// see where a panic started in the middle of a stack trace.
@@ -632,12 +668,16 @@ func tracebackothers(me *g) {
 
 	lock(&allglock)
 	for _, gp := range allgs {
-		if gp == me || gp == g.m.curg || readgstatus(gp) == _Gdead || gp.issystem && level < 2 {
+		if gp == me || gp == g.m.curg || readgstatus(gp) == _Gdead || isSystemGoroutine(gp) && level < 2 {
 			continue
 		}
 		print("\n")
 		goroutineheader(gp)
-		if readgstatus(gp)&^_Gscan == _Grunning {
+		// Note: gp.m == g.m occurs when tracebackothers is
+		// called from a signal handler initiated during a
+		// systemstack call.  The original G is still in the
+		// running state, and we want to print its stack.
+		if gp.m != g.m && readgstatus(gp)&^_Gscan == _Grunning {
 			print("\tgoroutine running on other thread; stack unavailable\n")
 			printcreatedby(gp)
 		} else {
@@ -657,3 +697,15 @@ func topofstack(f *_func) bool {
 		pc == rt0_goPC ||
 		externalthreadhandlerp != 0 && pc == externalthreadhandlerp
 }
+
+// isSystemGoroutine reports whether the goroutine g must be omitted in
+// stack dumps and deadlock detector.
+func isSystemGoroutine(gp *g) bool {
+	pc := gp.startpc
+	return pc == runfinqPC && !fingRunning ||
+		pc == backgroundgcPC ||
+		pc == bgsweepPC ||
+		pc == forcegchelperPC ||
+		pc == timerprocPC ||
+		pc == gcBgMarkWorkerPC
+}
diff --git a/src/runtime/type.go b/src/runtime/type.go
new file mode 100644
index 0000000..45bdac8
--- /dev/null
+++ b/src/runtime/type.go
@@ -0,0 +1,94 @@
+// 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.
+
+// Runtime type representation.
+
+package runtime
+
+import "unsafe"
+
+// Needs to be in sync with ../cmd/internal/ld/decodesym.go:/^func.commonsize,
+// ../cmd/internal/gc/reflect.go:/^func.dcommontype and
+// ../reflect/type.go:/^type.rtype.
+type _type struct {
+	size       uintptr
+	ptrdata    uintptr // size of memory prefix holding all pointers
+	hash       uint32
+	_unused    uint8
+	align      uint8
+	fieldalign uint8
+	kind       uint8
+	alg        *typeAlg
+	// gcdata stores the GC type data for the garbage collector.
+	// If the KindGCProg bit is set in kind, gcdata is a GC program.
+	// Otherwise it is a ptrmask bitmap. See mbitmap.go for details.
+	gcdata  *byte
+	_string *string
+	x       *uncommontype
+	ptrto   *_type
+	zero    *byte // ptr to the zero value for this type
+}
+
+type method struct {
+	name    *string
+	pkgpath *string
+	mtyp    *_type
+	typ     *_type
+	ifn     unsafe.Pointer
+	tfn     unsafe.Pointer
+}
+
+type uncommontype struct {
+	name    *string
+	pkgpath *string
+	mhdr    []method
+}
+
+type imethod struct {
+	name    *string
+	pkgpath *string
+	_type   *_type
+}
+
+type interfacetype struct {
+	typ  _type
+	mhdr []imethod
+}
+
+type maptype struct {
+	typ           _type
+	key           *_type
+	elem          *_type
+	bucket        *_type // internal type representing a hash bucket
+	hmap          *_type // internal type representing a hmap
+	keysize       uint8  // size of key slot
+	indirectkey   bool   // store ptr to key instead of key itself
+	valuesize     uint8  // size of value slot
+	indirectvalue bool   // store ptr to value instead of value itself
+	bucketsize    uint16 // size of bucket
+	reflexivekey  bool   // true if k==k for all keys
+}
+
+type chantype struct {
+	typ  _type
+	elem *_type
+	dir  uintptr
+}
+
+type slicetype struct {
+	typ  _type
+	elem *_type
+}
+
+type functype struct {
+	typ       _type
+	dotdotdot bool
+	in        slice
+	out       slice
+}
+
+type ptrtype struct {
+	typ  _type
+	elem *_type
+}
diff --git a/src/runtime/type.h b/src/runtime/type.h
deleted file mode 100644
index f5b4f9d..0000000
--- a/src/runtime/type.h
+++ /dev/null
@@ -1,113 +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.
-
-// Runtime type representation.
-
-typedef struct Type Type;
-typedef struct UncommonType UncommonType;
-typedef struct InterfaceType InterfaceType;
-typedef struct Method Method;
-typedef struct IMethod IMethod;
-typedef struct SliceType SliceType;
-typedef struct FuncType FuncType;
-
-// Needs to be in sync with ../../cmd/ld/decodesym.c:/^commonsize and pkg/reflect/type.go:/type.
-struct Type
-{
-	uintptr size;
-	uint32 hash;
-	uint8 _unused;
-	uint8 align;
-	uint8 fieldAlign;
-	uint8 kind;
-	void* alg;
-	// gc stores type info required for garbage collector.
-	// If (kind&KindGCProg)==0, then gc[0] points at sparse GC bitmap
-	// (no indirection), 4 bits per word.
-	// If (kind&KindGCProg)!=0, then gc[1] points to a compiler-generated
-	// read-only GC program; and gc[0] points to BSS space for sparse GC bitmap.
-	// For huge types (>MaxGCMask), runtime unrolls the program directly into
-	// GC bitmap and gc[0] is not used. For moderately-sized types, runtime
-	// unrolls the program into gc[0] space on first use. The first byte of gc[0]
-	// (gc[0][0]) contains 'unroll' flag saying whether the program is already
-	// unrolled into gc[0] or not.
-	uintptr gc[2];
-	String *string;
-	UncommonType *x;
-	Type *ptrto;
-	byte *zero;  // ptr to the zero value for this type
-};
-
-struct Method
-{
-	String *name;
-	String *pkgPath;
-	Type	*mtyp;
-	Type *typ;
-	void (*ifn)(void);
-	void (*tfn)(void);
-};
-
-struct UncommonType
-{
-	String *name;
-	String *pkgPath;
-	Slice mhdr;
-	Method m[];
-};
-
-struct IMethod
-{
-	String *name;
-	String *pkgPath;
-	Type *type;
-};
-
-struct InterfaceType
-{
-	Type  typ;
-	Slice mhdr;
-	IMethod m[];
-};
-
-struct MapType
-{
-	Type typ;
-	Type *key;
-	Type *elem;
-	Type *bucket;		// internal type representing a hash bucket
-	Type *hmap;		// internal type representing a Hmap
-	uint8 keysize;		// size of key slot
-	bool indirectkey;	// store ptr to key instead of key itself
-	uint8 valuesize;	// size of value slot
-	bool indirectvalue;	// store ptr to value instead of value itself
-	uint16 bucketsize;	// size of bucket
-};
-
-struct ChanType
-{
-	Type typ;
-	Type *elem;
-	uintptr dir;
-};
-
-struct SliceType
-{
-	Type typ;
-	Type *elem;
-};
-
-struct FuncType
-{
-	Type typ;
-	bool dotdotdot;
-	Slice in;
-	Slice out;
-};
-
-struct PtrType
-{
-	Type typ;
-	Type *elem;
-};
diff --git a/src/runtime/typekind.h b/src/runtime/typekind.h
deleted file mode 100644
index e0fe177..0000000
--- a/src/runtime/typekind.h
+++ /dev/null
@@ -1,38 +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.
-
-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/typekind1.go b/src/runtime/typekind1.go
new file mode 100644
index 0000000..73028d6
--- /dev/null
+++ b/src/runtime/typekind1.go
@@ -0,0 +1,39 @@
+// 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.
+
+package runtime
+
+const (
+	_KindBool = 1 + iota
+	_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
new file mode 100644
index 0000000..d3d6c70
--- /dev/null
+++ b/src/runtime/unaligned1.go
@@ -0,0 +1,17 @@
+// 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 386 amd64 amd64p32 arm64
+
+package runtime
+
+import "unsafe"
+
+func readUnaligned32(p unsafe.Pointer) uint32 {
+	return *(*uint32)(p)
+}
+
+func readUnaligned64(p unsafe.Pointer) uint64 {
+	return *(*uint64)(p)
+}
diff --git a/src/runtime/unaligned2.go b/src/runtime/unaligned2.go
new file mode 100644
index 0000000..4fc7917
--- /dev/null
+++ b/src/runtime/unaligned2.go
@@ -0,0 +1,20 @@
+// 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 arm ppc64 ppc64le
+
+package runtime
+
+import "unsafe"
+
+// Note: These routines perform the read with an unspecified endianness.
+func readUnaligned32(p unsafe.Pointer) uint32 {
+	q := (*[4]byte)(p)
+	return uint32(q[0]) + uint32(q[1])<<8 + uint32(q[2])<<16 + uint32(q[3])<<24
+}
+
+func readUnaligned64(p unsafe.Pointer) uint64 {
+	q := (*[8]byte)(p)
+	return uint64(q[0]) + uint64(q[1])<<8 + uint64(q[2])<<16 + uint64(q[3])<<24 + uint64(q[4])<<32 + uint64(q[5])<<40 + uint64(q[6])<<48 + uint64(q[7])<<56
+}
diff --git a/src/runtime/vdso_linux_amd64.c b/src/runtime/vdso_linux_amd64.c
deleted file mode 100644
index 681340c..0000000
--- a/src/runtime/vdso_linux_amd64.c
+++ /dev/null
@@ -1,371 +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.
-
-#include "runtime.h"
-#include "textflag.h"
-
-// Look up symbols in the Linux vDSO.
-
-// This code was originally based on the sample Linux vDSO parser at
-// https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/vDSO/parse_vdso.c
-
-// This implements the ELF dynamic linking spec at
-// http://sco.com/developers/gabi/latest/ch5.dynamic.html
-
-// The version section is documented at
-// http://refspecs.linuxfoundation.org/LSB_3.2.0/LSB-Core-generic/LSB-Core-generic/symversion.html
-
-#define AT_RANDOM 25
-#define AT_SYSINFO_EHDR 33
-#define AT_NULL	0    /* End of vector */
-#define PT_LOAD	1    /* Loadable program segment */
-#define PT_DYNAMIC 2 /* Dynamic linking information */
-#define DT_NULL 0    /* Marks end of dynamic section */
-#define DT_HASH 4    /* Dynamic symbol hash table */
-#define DT_STRTAB 5  /* Address of string table */
-#define DT_SYMTAB 6  /* Address of symbol table */
-#define DT_VERSYM 0x6ffffff0
-#define	DT_VERDEF 0x6ffffffc
-
-#define VER_FLG_BASE 0x1 /* Version definition of file itself */
-#define SHN_UNDEF 0      /* Undefined section */
-#define SHT_DYNSYM 11    /* Dynamic linker symbol table */
-#define STT_FUNC 2       /* Symbol is a code object */
-#define STB_GLOBAL 1     /* Global symbol */
-#define STB_WEAK 2       /* Weak symbol */
-
-/* How to extract and insert information held in the st_info field.  */
-#define ELF64_ST_BIND(val) (((byte) (val)) >> 4)
-#define ELF64_ST_TYPE(val) ((val) & 0xf)
-
-#define EI_NIDENT (16)
-
-typedef uint16 Elf64_Half;
-typedef uint32 Elf64_Word;
-typedef	int32  Elf64_Sword;
-typedef uint64 Elf64_Xword;
-typedef	int64  Elf64_Sxword;
-typedef uint64 Elf64_Addr;
-typedef uint64 Elf64_Off;
-typedef uint16 Elf64_Section;
-typedef Elf64_Half Elf64_Versym;
-
-
-typedef struct Elf64_Sym
-{
-	Elf64_Word st_name;
-	byte st_info;
-	byte st_other;
-	Elf64_Section st_shndx;
-	Elf64_Addr st_value;
-	Elf64_Xword st_size;
-} Elf64_Sym;
-
-typedef struct Elf64_Verdef
-{
-	Elf64_Half vd_version; /* Version revision */
-	Elf64_Half vd_flags;   /* Version information */
-	Elf64_Half vd_ndx;     /* Version Index */
-	Elf64_Half vd_cnt;     /* Number of associated aux entries */
-	Elf64_Word vd_hash;    /* Version name hash value */
-	Elf64_Word vd_aux;     /* Offset in bytes to verdaux array */
-	Elf64_Word vd_next;    /* Offset in bytes to next verdef entry */
-} Elf64_Verdef;
-
-typedef struct Elf64_Ehdr
-{
-	byte e_ident[EI_NIDENT]; /* Magic number and other info */
-	Elf64_Half e_type;       /* Object file type */
-	Elf64_Half e_machine;    /* Architecture */
-	Elf64_Word e_version;    /* Object file version */
-	Elf64_Addr e_entry;      /* Entry point virtual address */
-	Elf64_Off e_phoff;       /* Program header table file offset */
-	Elf64_Off e_shoff;       /* Section header table file offset */
-	Elf64_Word e_flags;      /* Processor-specific flags */
-	Elf64_Half e_ehsize;     /* ELF header size in bytes */
-	Elf64_Half e_phentsize;  /* Program header table entry size */
-	Elf64_Half e_phnum;      /* Program header table entry count */
-	Elf64_Half e_shentsize;  /* Section header table entry size */
-	Elf64_Half e_shnum;      /* Section header table entry count */
-	Elf64_Half e_shstrndx;   /* Section header string table index */
-} Elf64_Ehdr;
-
-typedef struct Elf64_Phdr
-{
-	Elf64_Word p_type;    /* Segment type */
-	Elf64_Word p_flags;   /* Segment flags */
-	Elf64_Off p_offset;   /* Segment file offset */
-	Elf64_Addr p_vaddr;   /* Segment virtual address */
-	Elf64_Addr p_paddr;   /* Segment physical address */
-	Elf64_Xword p_filesz; /* Segment size in file */
-	Elf64_Xword p_memsz;  /* Segment size in memory */
-	Elf64_Xword p_align;  /* Segment alignment */
-} Elf64_Phdr;
-
-typedef struct Elf64_Shdr
-{
-	Elf64_Word sh_name;       /* Section name (string tbl index) */
-	Elf64_Word sh_type;       /* Section type */
-	Elf64_Xword sh_flags;     /* Section flags */
-	Elf64_Addr sh_addr;       /* Section virtual addr at execution */
-	Elf64_Off sh_offset;      /* Section file offset */
-	Elf64_Xword sh_size;      /* Section size in bytes */
-	Elf64_Word sh_link;       /* Link to another section */
-	Elf64_Word sh_info;       /* Additional section information */
-	Elf64_Xword sh_addralign; /* Section alignment */
-	Elf64_Xword sh_entsize;   /* Entry size if section holds table */
-} Elf64_Shdr;
-
-typedef struct Elf64_Dyn
-{
-	Elf64_Sxword d_tag; /* Dynamic entry type */
-	union
-	{
-		Elf64_Xword d_val;  /* Integer value */
-		Elf64_Addr d_ptr;   /* Address value */
-	} d_un;
-} Elf64_Dyn;
-
-typedef struct Elf64_Verdaux
-{
-	Elf64_Word vda_name; /* Version or dependency names */
-	Elf64_Word vda_next; /* Offset in bytes to next verdaux entry */
-} Elf64_Verdaux;
-
-typedef struct Elf64_auxv_t
-{
-	uint64 a_type;        /* Entry type */
-	union
-	{
-		uint64 a_val; /* Integer value */
-	} a_un;
-} Elf64_auxv_t;
-
-
-typedef struct symbol_key {
-	byte* name;
-	int32 sym_hash;
-	void** var_ptr;
-} symbol_key;
-
-typedef struct version_key {
-	byte* version;
-	int32 ver_hash;
-} version_key;
-
-struct vdso_info {
-	bool valid;
-
-	/* Load information */
-	uintptr load_addr;
-	uintptr load_offset;  /* load_addr - recorded vaddr */
-
-	/* Symbol table */
-	Elf64_Sym *symtab;
-	const byte *symstrings;
-	Elf64_Word *bucket, *chain;
-	Elf64_Word nbucket, nchain;
-
-	/* Version table */
-	Elf64_Versym *versym;
-	Elf64_Verdef *verdef;
-};
-
-#pragma dataflag NOPTR
-static version_key linux26 = { (byte*)"LINUX_2.6", 0x3ae75f6 };
-
-// initialize with vsyscall fallbacks
-#pragma dataflag NOPTR
-void* runtime·__vdso_time_sym = (void*)0xffffffffff600400ULL;
-#pragma dataflag NOPTR
-void* runtime·__vdso_gettimeofday_sym = (void*)0xffffffffff600000ULL;
-#pragma dataflag NOPTR
-void* runtime·__vdso_clock_gettime_sym = (void*)0;
-
-#pragma dataflag NOPTR
-static symbol_key sym_keys[] = {
-	{ (byte*)"__vdso_time", 0xa33c485, &runtime·__vdso_time_sym },
-	{ (byte*)"__vdso_gettimeofday", 0x315ca59, &runtime·__vdso_gettimeofday_sym },
-	{ (byte*)"__vdso_clock_gettime", 0xd35ec75, &runtime·__vdso_clock_gettime_sym },
-};
-
-static void
-vdso_init_from_sysinfo_ehdr(struct vdso_info *vdso_info, Elf64_Ehdr* hdr)
-{
-	uint64 i;
-	bool found_vaddr = false;
-	Elf64_Phdr *pt;
-	Elf64_Dyn *dyn;
-	Elf64_Word *hash;
-
-	vdso_info->valid = false;
-	vdso_info->load_addr = (uintptr) hdr;
-
-	pt = (Elf64_Phdr*)(vdso_info->load_addr + hdr->e_phoff);
-	dyn = nil;
-
-	// We need two things from the segment table: the load offset
-	// and the dynamic table.
-	for(i=0; i<hdr->e_phnum; i++) {
-		if(pt[i].p_type == PT_LOAD && found_vaddr == false) {
-			found_vaddr = true;
-			vdso_info->load_offset =	(uintptr)hdr
-				+ (uintptr)pt[i].p_offset
-				- (uintptr)pt[i].p_vaddr;
-		} else if(pt[i].p_type == PT_DYNAMIC) {
-			dyn = (Elf64_Dyn*)((uintptr)hdr + pt[i].p_offset);
-		}
-	}
-
-	if(found_vaddr == false || dyn == nil)
-		return;  // Failed
-
-	// Fish out the useful bits of the dynamic table.
-	hash = nil;
-	vdso_info->symstrings = nil;
-	vdso_info->symtab = nil;
-	vdso_info->versym = nil;
-	vdso_info->verdef = nil;
-	for(i=0; dyn[i].d_tag!=DT_NULL; i++) {
-		switch(dyn[i].d_tag) {
-		case DT_STRTAB:
-			vdso_info->symstrings = (const byte *)
-				((uintptr)dyn[i].d_un.d_ptr
-				 + vdso_info->load_offset);
-			break;
-		case DT_SYMTAB:
-			vdso_info->symtab = (Elf64_Sym *)
-				((uintptr)dyn[i].d_un.d_ptr
-				 + vdso_info->load_offset);
-			break;
-		case DT_HASH:
-			hash = (Elf64_Word *)
-			  ((uintptr)dyn[i].d_un.d_ptr
-			   + vdso_info->load_offset);
-			break;
-		case DT_VERSYM:
-			vdso_info->versym = (Elf64_Versym *)
-				((uintptr)dyn[i].d_un.d_ptr
-				 + vdso_info->load_offset);
-			break;
-		case DT_VERDEF:
-			vdso_info->verdef = (Elf64_Verdef *)
-				((uintptr)dyn[i].d_un.d_ptr
-				 + vdso_info->load_offset);
-			break;
-		}
-	}
-	if(vdso_info->symstrings == nil || vdso_info->symtab == nil || hash == nil)
-		return;  // Failed
-
-	if(vdso_info->verdef == nil)
-		vdso_info->versym = 0;
-
-	// Parse the hash table header.
-	vdso_info->nbucket = hash[0];
-	vdso_info->nchain = hash[1];
-	vdso_info->bucket = &hash[2];
-	vdso_info->chain = &hash[vdso_info->nbucket + 2];
-
-	// That's all we need.
-	vdso_info->valid = true;
-}
-
-static int32
-vdso_find_version(struct vdso_info *vdso_info, version_key* ver)
-{
-	if(vdso_info->valid == false) {
-		return 0;
-	}
-	Elf64_Verdef *def = vdso_info->verdef;
-	while(true) {
-		if((def->vd_flags & VER_FLG_BASE) == 0) {
-			Elf64_Verdaux *aux = (Elf64_Verdaux*)((byte *)def + def->vd_aux);
-			if(def->vd_hash == ver->ver_hash &&
-				runtime·strcmp(ver->version, vdso_info->symstrings + aux->vda_name) == 0) {
-				return def->vd_ndx & 0x7fff;
-			}
-		}
-
-		if(def->vd_next == 0) {
-			break;
-		}
-		def = (Elf64_Verdef *)((byte *)def + def->vd_next);
-	}
-	return -1; // can not match any version
-}
-
-static void
-vdso_parse_symbols(struct vdso_info *vdso_info, int32 version)
-{
-	int32 i;
-	Elf64_Word chain;
-	Elf64_Sym *sym;
-
-	if(vdso_info->valid == false)
-		return;
-
-	for(i=0; i<nelem(sym_keys); i++) {
-		for(chain = vdso_info->bucket[sym_keys[i].sym_hash % vdso_info->nbucket];
-			chain != 0; chain = vdso_info->chain[chain]) {
-
-			sym = &vdso_info->symtab[chain];
-			if(ELF64_ST_TYPE(sym->st_info) != STT_FUNC)
-				continue;
-			if(ELF64_ST_BIND(sym->st_info) != STB_GLOBAL &&
-				 ELF64_ST_BIND(sym->st_info) != STB_WEAK)
-				continue;
-			if(sym->st_shndx == SHN_UNDEF)
-				continue;
-			if(runtime·strcmp(sym_keys[i].name, vdso_info->symstrings + sym->st_name) != 0)
-				continue;
-
-			// Check symbol version.
-			if(vdso_info->versym != nil && version != 0
-				&& vdso_info->versym[chain] & 0x7fff != version)
-				continue;
-
-			*sym_keys[i].var_ptr = (void *)(vdso_info->load_offset + sym->st_value);
-			break;
-		}
-	}
-}
-
-static void
-runtime·linux_setup_vdso(int32 argc, uint8** argv)
-{
-	struct vdso_info vdso_info;
-
-	// skip argvc
-	byte **p = argv;
-	p = &p[argc+1];
-
-	// skip envp to get to ELF auxiliary vector.
-	for(; *p!=0; p++) {}
-
-	// skip NULL separator
-	p++;
-
-	// now, p points to auxv
-	Elf64_auxv_t *elf_auxv = (Elf64_auxv_t*) p;
-
-	for(int32 i=0; elf_auxv[i].a_type!=AT_NULL; i++) {
-		if(elf_auxv[i].a_type == AT_SYSINFO_EHDR) {
-			if(elf_auxv[i].a_un.a_val == 0) {
-				// Something went wrong
-				continue;
-			}
-			vdso_init_from_sysinfo_ehdr(&vdso_info, (Elf64_Ehdr*)elf_auxv[i].a_un.a_val);
-			vdso_parse_symbols(&vdso_info, vdso_find_version(&vdso_info, &linux26));
-			continue;
-		}
-		if(elf_auxv[i].a_type == AT_RANDOM) {
-		        runtime·startup_random_data = (byte*)elf_auxv[i].a_un.a_val;
-		        runtime·startup_random_data_len = 16;
-			continue;
-		}
-	}
-}
-
-void (*runtime·sysargs)(int32, uint8**) = runtime·linux_setup_vdso;
diff --git a/src/runtime/vdso_linux_amd64.go b/src/runtime/vdso_linux_amd64.go
new file mode 100644
index 0000000..2440015
--- /dev/null
+++ b/src/runtime/vdso_linux_amd64.go
@@ -0,0 +1,327 @@
+// 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.
+
+package runtime
+
+import "unsafe"
+
+// Look up symbols in the Linux vDSO.
+
+// This code was originally based on the sample Linux vDSO parser at
+// https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/vDSO/parse_vdso.c
+
+// This implements the ELF dynamic linking spec at
+// http://sco.com/developers/gabi/latest/ch5.dynamic.html
+
+// The version section is documented at
+// http://refspecs.linuxfoundation.org/LSB_3.2.0/LSB-Core-generic/LSB-Core-generic/symversion.html
+
+const (
+	_AT_RANDOM       = 25
+	_AT_SYSINFO_EHDR = 33
+	_AT_NULL         = 0 /* End of vector */
+
+	_PT_LOAD    = 1 /* Loadable program segment */
+	_PT_DYNAMIC = 2 /* Dynamic linking information */
+
+	_DT_NULL   = 0 /* Marks end of dynamic section */
+	_DT_HASH   = 4 /* Dynamic symbol hash table */
+	_DT_STRTAB = 5 /* Address of string table */
+	_DT_SYMTAB = 6 /* Address of symbol table */
+	_DT_VERSYM = 0x6ffffff0
+	_DT_VERDEF = 0x6ffffffc
+
+	_VER_FLG_BASE = 0x1 /* Version definition of file itself */
+
+	_SHN_UNDEF = 0 /* Undefined section */
+
+	_SHT_DYNSYM = 11 /* Dynamic linker symbol table */
+
+	_STT_FUNC = 2 /* Symbol is a code object */
+
+	_STB_GLOBAL = 1 /* Global symbol */
+	_STB_WEAK   = 2 /* Weak symbol */
+
+	_EI_NIDENT = 16
+)
+
+/* How to extract and insert information held in the st_info field.  */
+func _ELF64_ST_BIND(val byte) byte { return val >> 4 }
+func _ELF64_ST_TYPE(val byte) byte { return val & 0xf }
+
+type elf64Sym struct {
+	st_name  uint32
+	st_info  byte
+	st_other byte
+	st_shndx uint16
+	st_value uint64
+	st_size  uint64
+}
+
+type elf64Verdef struct {
+	vd_version uint16 /* Version revision */
+	vd_flags   uint16 /* Version information */
+	vd_ndx     uint16 /* Version Index */
+	vd_cnt     uint16 /* Number of associated aux entries */
+	vd_hash    uint32 /* Version name hash value */
+	vd_aux     uint32 /* Offset in bytes to verdaux array */
+	vd_next    uint32 /* Offset in bytes to next verdef entry */
+}
+
+type elf64Ehdr struct {
+	e_ident     [_EI_NIDENT]byte /* Magic number and other info */
+	e_type      uint16           /* Object file type */
+	e_machine   uint16           /* Architecture */
+	e_version   uint32           /* Object file version */
+	e_entry     uint64           /* Entry point virtual address */
+	e_phoff     uint64           /* Program header table file offset */
+	e_shoff     uint64           /* Section header table file offset */
+	e_flags     uint32           /* Processor-specific flags */
+	e_ehsize    uint16           /* ELF header size in bytes */
+	e_phentsize uint16           /* Program header table entry size */
+	e_phnum     uint16           /* Program header table entry count */
+	e_shentsize uint16           /* Section header table entry size */
+	e_shnum     uint16           /* Section header table entry count */
+	e_shstrndx  uint16           /* Section header string table index */
+}
+
+type elf64Phdr struct {
+	p_type   uint32 /* Segment type */
+	p_flags  uint32 /* Segment flags */
+	p_offset uint64 /* Segment file offset */
+	p_vaddr  uint64 /* Segment virtual address */
+	p_paddr  uint64 /* Segment physical address */
+	p_filesz uint64 /* Segment size in file */
+	p_memsz  uint64 /* Segment size in memory */
+	p_align  uint64 /* Segment alignment */
+}
+
+type elf64Shdr struct {
+	sh_name      uint32 /* Section name (string tbl index) */
+	sh_type      uint32 /* Section type */
+	sh_flags     uint64 /* Section flags */
+	sh_addr      uint64 /* Section virtual addr at execution */
+	sh_offset    uint64 /* Section file offset */
+	sh_size      uint64 /* Section size in bytes */
+	sh_link      uint32 /* Link to another section */
+	sh_info      uint32 /* Additional section information */
+	sh_addralign uint64 /* Section alignment */
+	sh_entsize   uint64 /* Entry size if section holds table */
+}
+
+type elf64Dyn struct {
+	d_tag int64  /* Dynamic entry type */
+	d_val uint64 /* Integer value */
+}
+
+type elf64Verdaux struct {
+	vda_name uint32 /* Version or dependency names */
+	vda_next uint32 /* Offset in bytes to next verdaux entry */
+}
+
+type elf64Auxv struct {
+	a_type uint64 /* Entry type */
+	a_val  uint64 /* Integer value */
+}
+
+type symbol_key struct {
+	name     string
+	sym_hash uint32
+	ptr      *uintptr
+}
+
+type version_key struct {
+	version  string
+	ver_hash uint32
+}
+
+type vdso_info struct {
+	valid bool
+
+	/* Load information */
+	load_addr   uintptr
+	load_offset uintptr /* load_addr - recorded vaddr */
+
+	/* Symbol table */
+	symtab     *[1 << 32]elf64Sym
+	symstrings *[1 << 32]byte
+	chain      []uint32
+	bucket     []uint32
+
+	/* Version table */
+	versym *[1 << 32]uint16
+	verdef *elf64Verdef
+}
+
+var linux26 = version_key{"LINUX_2.6", 0x3ae75f6}
+
+var sym_keys = []symbol_key{
+	{"__vdso_time", 0xa33c485, &__vdso_time_sym},
+	{"__vdso_gettimeofday", 0x315ca59, &__vdso_gettimeofday_sym},
+	{"__vdso_clock_gettime", 0xd35ec75, &__vdso_clock_gettime_sym},
+}
+
+// initialize with vsyscall fallbacks
+var (
+	__vdso_time_sym          uintptr = 0xffffffffff600400
+	__vdso_gettimeofday_sym  uintptr = 0xffffffffff600000
+	__vdso_clock_gettime_sym uintptr = 0
+)
+
+func vdso_init_from_sysinfo_ehdr(info *vdso_info, hdr *elf64Ehdr) {
+	info.valid = false
+	info.load_addr = uintptr(unsafe.Pointer(hdr))
+
+	pt := unsafe.Pointer(info.load_addr + uintptr(hdr.e_phoff))
+
+	// We need two things from the segment table: the load offset
+	// and the dynamic table.
+	var found_vaddr bool
+	var dyn *[1 << 20]elf64Dyn
+	for i := uint16(0); i < hdr.e_phnum; i++ {
+		pt := (*elf64Phdr)(add(pt, uintptr(i)*unsafe.Sizeof(elf64Phdr{})))
+		switch pt.p_type {
+		case _PT_LOAD:
+			if !found_vaddr {
+				found_vaddr = true
+				info.load_offset = info.load_addr + uintptr(pt.p_offset-pt.p_vaddr)
+			}
+
+		case _PT_DYNAMIC:
+			dyn = (*[1 << 20]elf64Dyn)(unsafe.Pointer(info.load_addr + uintptr(pt.p_offset)))
+		}
+	}
+
+	if !found_vaddr || dyn == nil {
+		return // Failed
+	}
+
+	// Fish out the useful bits of the dynamic table.
+
+	var hash *[1 << 30]uint32
+	hash = nil
+	info.symstrings = nil
+	info.symtab = nil
+	info.versym = nil
+	info.verdef = nil
+	for i := 0; dyn[i].d_tag != _DT_NULL; i++ {
+		dt := &dyn[i]
+		p := info.load_offset + uintptr(dt.d_val)
+		switch dt.d_tag {
+		case _DT_STRTAB:
+			info.symstrings = (*[1 << 32]byte)(unsafe.Pointer(p))
+		case _DT_SYMTAB:
+			info.symtab = (*[1 << 32]elf64Sym)(unsafe.Pointer(p))
+		case _DT_HASH:
+			hash = (*[1 << 30]uint32)(unsafe.Pointer(p))
+		case _DT_VERSYM:
+			info.versym = (*[1 << 32]uint16)(unsafe.Pointer(p))
+		case _DT_VERDEF:
+			info.verdef = (*elf64Verdef)(unsafe.Pointer(p))
+		}
+	}
+
+	if info.symstrings == nil || info.symtab == nil || hash == nil {
+		return // Failed
+	}
+
+	if info.verdef == nil {
+		info.versym = nil
+	}
+
+	// Parse the hash table header.
+	nbucket := hash[0]
+	nchain := hash[1]
+	info.bucket = hash[2 : 2+nbucket]
+	info.chain = hash[2+nbucket : 2+nbucket+nchain]
+
+	// That's all we need.
+	info.valid = true
+}
+
+func vdso_find_version(info *vdso_info, ver *version_key) int32 {
+	if !info.valid {
+		return 0
+	}
+
+	def := info.verdef
+	for {
+		if def.vd_flags&_VER_FLG_BASE == 0 {
+			aux := (*elf64Verdaux)(add(unsafe.Pointer(def), uintptr(def.vd_aux)))
+			if def.vd_hash == ver.ver_hash && ver.version == gostringnocopy(&info.symstrings[aux.vda_name]) {
+				return int32(def.vd_ndx & 0x7fff)
+			}
+		}
+
+		if def.vd_next == 0 {
+			break
+		}
+		def = (*elf64Verdef)(add(unsafe.Pointer(def), uintptr(def.vd_next)))
+	}
+
+	return -1 // can not match any version
+}
+
+func vdso_parse_symbols(info *vdso_info, version int32) {
+	if !info.valid {
+		return
+	}
+
+	for _, k := range sym_keys {
+		for chain := info.bucket[k.sym_hash%uint32(len(info.bucket))]; chain != 0; chain = info.chain[chain] {
+			sym := &info.symtab[chain]
+			typ := _ELF64_ST_TYPE(sym.st_info)
+			bind := _ELF64_ST_BIND(sym.st_info)
+			if typ != _STT_FUNC || bind != _STB_GLOBAL && bind != _STB_WEAK || sym.st_shndx == _SHN_UNDEF {
+				continue
+			}
+			if k.name != gostringnocopy(&info.symstrings[sym.st_name]) {
+				continue
+			}
+
+			// Check symbol version.
+			if info.versym != nil && version != 0 && int32(info.versym[chain]&0x7fff) != version {
+				continue
+			}
+
+			*k.ptr = info.load_offset + uintptr(sym.st_value)
+			break
+		}
+	}
+}
+
+func sysargs(argc int32, argv **byte) {
+	n := argc + 1
+
+	// skip envp to get to ELF auxiliary vector.
+	for argv_index(argv, n) != nil {
+		n++
+	}
+
+	// skip NULL separator
+	n++
+
+	// now argv+n is auxv
+	auxv := (*[1 << 32]elf64Auxv)(add(unsafe.Pointer(argv), uintptr(n)*ptrSize))
+
+	for i := 0; auxv[i].a_type != _AT_NULL; i++ {
+		av := &auxv[i]
+		switch av.a_type {
+		case _AT_SYSINFO_EHDR:
+			if av.a_val == 0 {
+				// Something went wrong
+				continue
+			}
+			var info vdso_info
+			// TODO(rsc): I don't understand why the compiler thinks info escapes
+			// when passed to the three functions below.
+			info1 := (*vdso_info)(noescape(unsafe.Pointer(&info)))
+			vdso_init_from_sysinfo_ehdr(info1, (*elf64Ehdr)(unsafe.Pointer(uintptr(av.a_val))))
+			vdso_parse_symbols(info1, vdso_find_version(info1, &linux26))
+
+		case _AT_RANDOM:
+			startupRandomData = (*[16]byte)(unsafe.Pointer(uintptr(av.a_val)))[:]
+		}
+	}
+}
diff --git a/src/runtime/vdso_none.go b/src/runtime/vdso_none.go
new file mode 100644
index 0000000..93bd91c
--- /dev/null
+++ b/src/runtime/vdso_none.go
@@ -0,0 +1,12 @@
+// 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 !amd64
+// +build !linux !386
+// +build !linux !arm
+
+package runtime
+
+func sysargs(argc int32, argv **byte) {
+}
diff --git a/src/runtime/vlop_arm.s b/src/runtime/vlop_arm.s
index b4b905b..ae1f582 100644
--- a/src/runtime/vlop_arm.s
+++ b/src/runtime/vlop_arm.s
@@ -23,11 +23,11 @@
 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 // THE SOFTWARE.
 
-#include "zasm_GOOS_GOARCH.h"
+#include "go_asm.h"
+#include "go_tls.h"
+#include "funcdata.h"
 #include "textflag.h"
 
-arg=0
-
 /* replaced use of R10 by R11 because the former can be the data segment base register */
 
 TEXT _mulv(SB), NOSPLIT, $0
@@ -100,7 +100,7 @@ TEXT _sfloat(SB), NOSPLIT, $68-0 // 4 arg + 14*4 saved regs + cpsr + return valu
 // load the signal fault address into LR, and jump
 // to the real sigpanic.
 // This simulates what sighandler does for a memory fault.
-TEXT _sfloatpanic(SB),NOSPLIT,$-4
+TEXT runtime·_sfloatpanic(SB),NOSPLIT,$-4
 	MOVW	$0, R0
 	MOVW.W	R0, -4(R13)
 	MOVW	g_sigpc(g), LR
@@ -110,89 +110,76 @@ TEXT _sfloatpanic(SB),NOSPLIT,$-4
 // Reference: 
 // Sloss, Andrew et. al; ARM System Developer's Guide: Designing and Optimizing System Software
 // Morgan Kaufmann; 1 edition (April 8, 2004), ISBN 978-1558608740
-q = 0 // input d, output q
-r = 1 // input n, output r
-s = 2 // three temporary variables
-M = 3
-a = 11
-// Be careful: R(a) == R11 will be used by the linker for synthesized instructions.
+#define Rq	R0 // input d, output q
+#define Rr	R1 // input n, output r
+#define Rs	R2 // three temporary variables
+#define RM	R3
+#define Ra	R11
+
+// Be careful: Ra == R11 will be used by the linker for synthesized instructions.
 TEXT udiv<>(SB),NOSPLIT,$-4
-	CLZ 	R(q), R(s) // find normalizing shift
-	MOVW.S	R(q)<<R(s), R(a)
-	MOVW	$fast_udiv_tab<>-64(SB), R(M)
-	ADD.NE	R(a)>>25, R(M), R(a) // index by most significant 7 bits of divisor
-	MOVBU.NE	(R(a)), R(a)
+	CLZ 	Rq, Rs // find normalizing shift
+	MOVW.S	Rq<<Rs, Ra
+	MOVW	$fast_udiv_tab<>-64(SB), RM
+	ADD.NE	Ra>>25, RM, Ra // index by most significant 7 bits of divisor
+	MOVBU.NE	(Ra), Ra
 
-	SUB.S	$7, R(s)
-	RSB 	$0, R(q), R(M) // M = -q
-	MOVW.PL	R(a)<<R(s), R(q)
+	SUB.S	$7, Rs
+	RSB 	$0, Rq, RM // M = -q
+	MOVW.PL	Ra<<Rs, Rq
 
 	// 1st Newton iteration
-	MUL.PL	R(M), R(q), R(a) // a = -q*d
+	MUL.PL	RM, Rq, Ra // a = -q*d
 	BMI 	udiv_by_large_d
-	MULAWT	R(a), R(q), R(q), R(q) // q approx q-(q*q*d>>32)
-	TEQ 	R(M)->1, R(M) // check for d=0 or d=1
+	MULAWT	Ra, Rq, Rq, Rq // q approx q-(q*q*d>>32)
+	TEQ 	RM->1, RM // check for d=0 or d=1
 
 	// 2nd Newton iteration
-	MUL.NE	R(M), R(q), R(a)
-	MOVW.NE	$0, R(s)
-	MULAL.NE R(q), R(a), (R(q),R(s))
+	MUL.NE	RM, Rq, Ra
+	MOVW.NE	$0, Rs
+	MULAL.NE Rq, Ra, (Rq,Rs)
 	BEQ 	udiv_by_0_or_1
 
 	// q now accurate enough for a remainder r, 0<=r<3*d
-	MULLU	R(q), R(r), (R(q),R(s)) // q = (r * q) >> 32	
-	ADD 	R(M), R(r), R(r) // r = n - d
-	MULA	R(M), R(q), R(r), R(r) // r = n - (q+1)*d
+	MULLU	Rq, Rr, (Rq,Rs) // q = (r * q) >> 32
+	ADD 	RM, Rr, Rr // r = n - d
+	MULA	RM, Rq, Rr, Rr // r = n - (q+1)*d
 
 	// since 0 <= n-q*d < 3*d; thus -d <= r < 2*d
-	CMN 	R(M), R(r) // t = r-d
-	SUB.CS	R(M), R(r), R(r) // if (t<-d || t>=0) r=r+d
-	ADD.CC	$1, R(q)
-	ADD.PL	R(M)<<1, R(r)
-	ADD.PL	$2, R(q)
+	CMN 	RM, Rr // t = r-d
+	SUB.CS	RM, Rr, Rr // if (t<-d || t>=0) r=r+d
+	ADD.CC	$1, Rq
+	ADD.PL	RM<<1, Rr
+	ADD.PL	$2, Rq
 	RET
 
 udiv_by_large_d:
 	// at this point we know d>=2^(31-6)=2^25
-	SUB 	$4, R(a), R(a)
-	RSB 	$0, R(s), R(s)
-	MOVW	R(a)>>R(s), R(q)
-	MULLU	R(q), R(r), (R(q),R(s))
-	MULA	R(M), R(q), R(r), R(r)
+	SUB 	$4, Ra, Ra
+	RSB 	$0, Rs, Rs
+	MOVW	Ra>>Rs, Rq
+	MULLU	Rq, Rr, (Rq,Rs)
+	MULA	RM, Rq, Rr, Rr
 
 	// q now accurate enough for a remainder r, 0<=r<4*d
-	CMN 	R(r)>>1, R(M) // if(r/2 >= d)
-	ADD.CS	R(M)<<1, R(r)
-	ADD.CS	$2, R(q)
-	CMN 	R(r), R(M)
-	ADD.CS	R(M), R(r)
-	ADD.CS	$1, R(q)
+	CMN 	Rr>>1, RM // if(r/2 >= d)
+	ADD.CS	RM<<1, Rr
+	ADD.CS	$2, Rq
+	CMN 	Rr, RM
+	ADD.CS	RM, Rr
+	ADD.CS	$1, Rq
 	RET
 
 udiv_by_0_or_1:
 	// carry set if d==1, carry clear if d==0
 	BCC udiv_by_0
-	MOVW	R(r), R(q)
-	MOVW	$0, R(r)
+	MOVW	Rr, Rq
+	MOVW	$0, Rr
 	RET
 
 udiv_by_0:
-	// The ARM toolchain expects it can emit references to DIV and MOD
-	// instructions. The linker rewrites each pseudo-instruction into
-	// a sequence that pushes two values onto the stack and then calls
-	// _divu, _modu, _div, or _mod (below), all of which have a 16-byte
-	// frame plus the saved LR. The traceback routine knows the expanded
-	// stack frame size at the pseudo-instruction call site, but it
-	// doesn't know that the frame has a non-standard layout. In particular,
-	// it expects to find a saved LR in the bottom word of the frame.
-	// Unwind the stack back to the pseudo-instruction call site, copy the
-	// saved LR where the traceback routine will look for it, and make it
-	// appear that panicdivide was called from that PC.
-	MOVW	0(R13), LR
-	ADD	$20, R13
-	MOVW	8(R13), R1 // actual saved LR
-	MOVW	R1, 0(R13) // expected here for traceback
-	B 	runtime·panicdivide(SB)
+	MOVW	$runtime·panicdivide(SB), R11
+	B	(R11)
 
 // var tab [64]byte
 // tab[0] = 255; for i := 1; i <= 63; i++ { tab[i] = (1<<14)/(64+i) }
@@ -215,96 +202,115 @@ DATA fast_udiv_tab<>+0x38(SB)/4, $0x85868788
 DATA fast_udiv_tab<>+0x3c(SB)/4, $0x81828384
 GLOBL fast_udiv_tab<>(SB), RODATA, $64
 
-// The linker will pass numerator in R(TMP), and it also
-// expects the result in R(TMP)
-TMP = 11
+// The linker will pass numerator in RTMP, and it also
+// expects the result in RTMP
+#define RTMP R11
 
-TEXT _divu(SB), NOSPLIT, $16
-	MOVW	R(q), 4(R13)
-	MOVW	R(r), 8(R13)
-	MOVW	R(s), 12(R13)
-	MOVW	R(M), 16(R13)
+TEXT _divu(SB), NOSPLIT, $16-0
+	// It's not strictly true that there are no local pointers.
+	// It could be that the saved registers Rq, Rr, Rs, and Rm
+	// contain pointers. However, the only way this can matter
+	// is if the stack grows (which it can't, udiv is nosplit)
+	// or if a fault happens and more frames are added to
+	// the stack due to deferred functions.
+	// In the latter case, the stack can grow arbitrarily,
+	// and garbage collection can happen, and those
+	// operations care about pointers, but in that case
+	// the calling frame is dead, and so are the saved
+	// registers. So we can claim there are no pointers here.
+	NO_LOCAL_POINTERS
+	MOVW	Rq, 4(R13)
+	MOVW	Rr, 8(R13)
+	MOVW	Rs, 12(R13)
+	MOVW	RM, 16(R13)
 
-	MOVW	R(TMP), R(r)		/* numerator */
-	MOVW	0(FP), R(q) 		/* denominator */
+	MOVW	RTMP, Rr		/* numerator */
+	MOVW	g_m(g), Rq
+	MOVW	m_divmod(Rq), Rq	/* denominator */
 	BL  	udiv<>(SB)
-	MOVW	R(q), R(TMP)
-	MOVW	4(R13), R(q)
-	MOVW	8(R13), R(r)
-	MOVW	12(R13), R(s)
-	MOVW	16(R13), R(M)
+	MOVW	Rq, RTMP
+	MOVW	4(R13), Rq
+	MOVW	8(R13), Rr
+	MOVW	12(R13), Rs
+	MOVW	16(R13), RM
 	RET
 
-TEXT _modu(SB), NOSPLIT, $16
-	MOVW	R(q), 4(R13)
-	MOVW	R(r), 8(R13)
-	MOVW	R(s), 12(R13)
-	MOVW	R(M), 16(R13)
+TEXT _modu(SB), NOSPLIT, $16-0
+	NO_LOCAL_POINTERS
+	MOVW	Rq, 4(R13)
+	MOVW	Rr, 8(R13)
+	MOVW	Rs, 12(R13)
+	MOVW	RM, 16(R13)
 
-	MOVW	R(TMP), R(r)		/* numerator */
-	MOVW	0(FP), R(q) 		/* denominator */
+	MOVW	RTMP, Rr		/* numerator */
+	MOVW	g_m(g), Rq
+	MOVW	m_divmod(Rq), Rq	/* denominator */
 	BL  	udiv<>(SB)
-	MOVW	R(r), R(TMP)
-	MOVW	4(R13), R(q)
-	MOVW	8(R13), R(r)
-	MOVW	12(R13), R(s)
-	MOVW	16(R13), R(M)
+	MOVW	Rr, RTMP
+	MOVW	4(R13), Rq
+	MOVW	8(R13), Rr
+	MOVW	12(R13), Rs
+	MOVW	16(R13), RM
 	RET
 
-TEXT _div(SB),NOSPLIT,$16
-	MOVW	R(q), 4(R13)
-	MOVW	R(r), 8(R13)
-	MOVW	R(s), 12(R13)
-	MOVW	R(M), 16(R13)
-	MOVW	R(TMP), R(r)		/* numerator */
-	MOVW	0(FP), R(q) 		/* denominator */
-	CMP 	$0, R(r)
+TEXT _div(SB),NOSPLIT,$16-0
+	NO_LOCAL_POINTERS
+	MOVW	Rq, 4(R13)
+	MOVW	Rr, 8(R13)
+	MOVW	Rs, 12(R13)
+	MOVW	RM, 16(R13)
+	MOVW	RTMP, Rr		/* numerator */
+	MOVW	g_m(g), Rq
+	MOVW	m_divmod(Rq), Rq	/* denominator */
+	CMP 	$0, Rr
 	BGE 	d1
-	RSB 	$0, R(r), R(r)
-	CMP 	$0, R(q)
+	RSB 	$0, Rr, Rr
+	CMP 	$0, Rq
 	BGE 	d2
-	RSB 	$0, R(q), R(q)
+	RSB 	$0, Rq, Rq
 d0:
 	BL  	udiv<>(SB)  		/* none/both neg */
-	MOVW	R(q), R(TMP)
+	MOVW	Rq, RTMP
 	B		out1
 d1:
-	CMP 	$0, R(q)
+	CMP 	$0, Rq
 	BGE 	d0
-	RSB 	$0, R(q), R(q)
+	RSB 	$0, Rq, Rq
 d2:
 	BL  	udiv<>(SB)  		/* one neg */
-	RSB		$0, R(q), R(TMP)
+	RSB		$0, Rq, RTMP
 out1:
-	MOVW	4(R13), R(q)
-	MOVW	8(R13), R(r)
-	MOVW	12(R13), R(s)
-	MOVW	16(R13), R(M)
+	MOVW	4(R13), Rq
+	MOVW	8(R13), Rr
+	MOVW	12(R13), Rs
+	MOVW	16(R13), RM
 	RET
 
-TEXT _mod(SB),NOSPLIT,$16
-	MOVW	R(q), 4(R13)
-	MOVW	R(r), 8(R13)
-	MOVW	R(s), 12(R13)
-	MOVW	R(M), 16(R13)
-	MOVW	R(TMP), R(r)		/* numerator */
-	MOVW	0(FP), R(q) 		/* denominator */
-	CMP 	$0, R(q)
-	RSB.LT	$0, R(q), R(q)
-	CMP 	$0, R(r)
+TEXT _mod(SB),NOSPLIT,$16-0
+	NO_LOCAL_POINTERS
+	MOVW	Rq, 4(R13)
+	MOVW	Rr, 8(R13)
+	MOVW	Rs, 12(R13)
+	MOVW	RM, 16(R13)
+	MOVW	RTMP, Rr		/* numerator */
+	MOVW	g_m(g), Rq
+	MOVW	m_divmod(Rq), Rq	/* denominator */
+	CMP 	$0, Rq
+	RSB.LT	$0, Rq, Rq
+	CMP 	$0, Rr
 	BGE 	m1
-	RSB 	$0, R(r), R(r)
+	RSB 	$0, Rr, Rr
 	BL  	udiv<>(SB)  		/* neg numerator */
-	RSB 	$0, R(r), R(TMP)
+	RSB 	$0, Rr, RTMP
 	B   	out
 m1:
 	BL  	udiv<>(SB)  		/* pos numerator */
-	MOVW	R(r), R(TMP)
+	MOVW	Rr, RTMP
 out:
-	MOVW	4(R13), R(q)
-	MOVW	8(R13), R(r)
-	MOVW	12(R13), R(s)
-	MOVW	16(R13), R(M)
+	MOVW	4(R13), Rq
+	MOVW	8(R13), Rr
+	MOVW	12(R13), Rs
+	MOVW	16(R13), RM
 	RET
 
 // _mul64by32 and _div64by32 not implemented on arm
diff --git a/src/runtime/vlop_arm_test.go b/src/runtime/vlop_arm_test.go
index cd28419..1a21119 100644
--- a/src/runtime/vlop_arm_test.go
+++ b/src/runtime/vlop_arm_test.go
@@ -4,7 +4,10 @@
 
 package runtime_test
 
-import "testing"
+import (
+	"runtime"
+	"testing"
+)
 
 // arm soft division benchmarks adapted from
 // http://ridiculousfish.com/files/division_benchmarks.tar.gz
@@ -68,3 +71,14 @@ func BenchmarkUint32Mod13307(b *testing.B)     { bmUint32Mod(13307, b) }
 func BenchmarkUint32Mod52513(b *testing.B)     { bmUint32Mod(52513, b) }
 func BenchmarkUint32Mod60978747(b *testing.B)  { bmUint32Mod(60978747, b) }
 func BenchmarkUint32Mod106956295(b *testing.B) { bmUint32Mod(106956295, b) }
+
+func TestUsplit(t *testing.T) {
+	var den uint32 = 1000000
+	for _, x := range []uint32{0, 1, 999999, 1000000, 1010101, 0xFFFFFFFF} {
+		q1, r1 := runtime.Usplit(x)
+		q2, r2 := x/den, x%den
+		if q1 != q2 || r1 != r2 {
+			t.Errorf("%d/1e6, %d%%1e6 = %d, %d, want %d, %d", x, x, q1, r1, q2, r2)
+		}
+	}
+}
diff --git a/src/runtime/vlrt.c b/src/runtime/vlrt.c
deleted file mode 100644
index cb0d147..0000000
--- a/src/runtime/vlrt.c
+++ /dev/null
@@ -1,914 +0,0 @@
-// Inferno's libkern/vlrt-386.c
-// http://code.google.com/p/inferno-os/source/browse/libkern/vlrt-386.c
-//
-//         Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
-//         Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com).  All rights reserved.
-//         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.
-
-// +build arm 386
-
-#include "textflag.h"
-
-/*
- * C runtime for 64-bit divide, others.
- *
- * TODO(rsc): The simple functions are dregs--8c knows how
- * to generate the code directly now.  Find and remove.
- */
-
-void	runtime·panicdivide(void);
-
-typedef	unsigned long	ulong;
-typedef	unsigned int	uint;
-typedef	unsigned short	ushort;
-typedef	unsigned char	uchar;
-typedef	signed char	schar;
-
-#define	SIGN(n)	(1UL<<(n-1))
-
-typedef	struct	Vlong	Vlong;
-struct	Vlong
-{
-	ulong	lo;
-	ulong	hi;
-};
-
-typedef	union	Vlong64	Vlong64;
-union	Vlong64
-{
-	long long	v;
-	Vlong	v2;
-};
-
-void	runtime·abort(void);
-
-#pragma textflag NOSPLIT
-Vlong
-_addv(Vlong a, Vlong b)
-{
-	Vlong r;
-
-	r.lo = a.lo + b.lo;
-	r.hi = a.hi + b.hi;
-	if(r.lo < a.lo)
-		r.hi++;
-	return r;
-}
-
-#pragma textflag NOSPLIT
-Vlong
-_subv(Vlong a, Vlong b)
-{
-	Vlong r;
-
-	r.lo = a.lo - b.lo;
-	r.hi = a.hi - b.hi;
-	if(r.lo > a.lo)
-		r.hi--;
-	return r;
-}
-
-Vlong
-_d2v(double d)
-{
-	union { double d; Vlong vl; } x;
-	ulong xhi, xlo, ylo, yhi;
-	int sh;
-	Vlong y;
-
-	x.d = d;
-
-	xhi = (x.vl.hi & 0xfffff) | 0x100000;
-	xlo = x.vl.lo;
-	sh = 1075 - ((x.vl.hi >> 20) & 0x7ff);
-
-	ylo = 0;
-	yhi = 0;
-	if(sh >= 0) {
-		/* v = (hi||lo) >> sh */
-		if(sh < 32) {
-			if(sh == 0) {
-				ylo = xlo;
-				yhi = xhi;
-			} else {
-				ylo = (xlo >> sh) | (xhi << (32-sh));
-				yhi = xhi >> sh;
-			}
-		} else {
-			if(sh == 32) {
-				ylo = xhi;
-			} else
-			if(sh < 64) {
-				ylo = xhi >> (sh-32);
-			}
-		}
-	} else {
-		/* v = (hi||lo) << -sh */
-		sh = -sh;
-		if(sh <= 10) { /* NOTE: sh <= 11 on ARM??? */
-			ylo = xlo << sh;
-			yhi = (xhi << sh) | (xlo >> (32-sh));
-		} else {
-			/* overflow */
-			yhi = d;	/* causes something awful */
-		}
-	}
-	if(x.vl.hi & SIGN(32)) {
-		if(ylo != 0) {
-			ylo = -ylo;
-			yhi = ~yhi;
-		} else
-			yhi = -yhi;
-	}
-
-	y.hi = yhi;
-	y.lo = ylo;
-	return y;
-}
-
-Vlong
-_f2v(float f)
-{
-	return _d2v(f);
-}
-
-double
-_ul2d(ulong u)
-{
-	// compensate for bug in c
-	if(u & SIGN(32)) {
-		u ^= SIGN(32);
-		return 2147483648. + u;
-	}
-	return u;
-}
-
-double
-_v2d(Vlong x)
-{
-	if(x.hi & SIGN(32)) {
-		if(x.lo) {
-			x.lo = -x.lo;
-			x.hi = ~x.hi;
-		} else
-			x.hi = -x.hi;
-		return -(_ul2d(x.hi)*4294967296. + _ul2d(x.lo));
-	}
-	return (long)x.hi*4294967296. + x.lo;
-}
-
-float
-_v2f(Vlong x)
-{
-	return _v2d(x);
-}
-
-ulong	runtime·_div64by32(Vlong, ulong, ulong*);
-int	runtime·_mul64by32(Vlong*, Vlong, ulong);
-
-static void
-slowdodiv(Vlong num, Vlong den, Vlong *q, Vlong *r)
-{
-	ulong numlo, numhi, denhi, denlo, quohi, quolo, t;
-	int i;
-
-	numhi = num.hi;
-	numlo = num.lo;
-	denhi = den.hi;
-	denlo = den.lo;
-
-	/*
-	 * get a divide by zero
-	 */
-	if(denlo==0 && denhi==0) {
-		runtime·panicdivide();
-	}
-
-	/*
-	 * set up the divisor and find the number of iterations needed
-	 */
-	if(numhi >= SIGN(32)) {
-		quohi = SIGN(32);
-		quolo = 0;
-	} else {
-		quohi = numhi;
-		quolo = numlo;
-	}
-	i = 0;
-	while(denhi < quohi || (denhi == quohi && denlo < quolo)) {
-		denhi = (denhi<<1) | (denlo>>31);
-		denlo <<= 1;
-		i++;
-	}
-
-	quohi = 0;
-	quolo = 0;
-	for(; i >= 0; i--) {
-		quohi = (quohi<<1) | (quolo>>31);
-		quolo <<= 1;
-		if(numhi > denhi || (numhi == denhi && numlo >= denlo)) {
-			t = numlo;
-			numlo -= denlo;
-			if(numlo > t)
-				numhi--;
-			numhi -= denhi;
-			quolo |= 1;
-		}
-		denlo = (denlo>>1) | (denhi<<31);
-		denhi >>= 1;
-	}
-
-	if(q) {
-		q->lo = quolo;
-		q->hi = quohi;
-	}
-	if(r) {
-		r->lo = numlo;
-		r->hi = numhi;
-	}
-}
-
-#ifdef GOARCH_arm
-static void
-dodiv(Vlong num, Vlong den, Vlong *qp, Vlong *rp)
-{
-	slowdodiv(num, den, qp, rp);
-}
-#endif
-
-#ifdef GOARCH_386
-static void
-dodiv(Vlong num, Vlong den, Vlong *qp, Vlong *rp)
-{
-	ulong n;
-	Vlong x, q, r;
-	
-	if(den.hi > num.hi || (den.hi == num.hi && den.lo > num.lo)){
-		if(qp) {
-			qp->hi = 0;
-			qp->lo = 0;
-		}
-		if(rp) {
-			rp->hi = num.hi;
-			rp->lo = num.lo;
-		}
-		return;
-	}
-
-	if(den.hi != 0){
-		q.hi = 0;
-		n = num.hi/den.hi;
-		if(runtime·_mul64by32(&x, den, n) || x.hi > num.hi || (x.hi == num.hi && x.lo > num.lo))
-			slowdodiv(num, den, &q, &r);
-		else {
-			q.lo = n;
-			*(long long*)&r = *(long long*)&num - *(long long*)&x;
-		}
-	} else {
-		if(num.hi >= den.lo){
-			if(den.lo == 0)
-				runtime·panicdivide();
-			q.hi = n = num.hi/den.lo;
-			num.hi -= den.lo*n;
-		} else {
-			q.hi = 0;
-		}
-		q.lo = runtime·_div64by32(num, den.lo, &r.lo);
-		r.hi = 0;
-	}
-	if(qp) {
-		qp->lo = q.lo;
-		qp->hi = q.hi;
-	}
-	if(rp) {
-		rp->lo = r.lo;
-		rp->hi = r.hi;
-	}
-}
-#endif
-
-Vlong
-_divvu(Vlong n, Vlong d)
-{
-	Vlong q;
-
-	if(n.hi == 0 && d.hi == 0) {
-		if(d.lo == 0)
-			runtime·panicdivide();
-		q.hi = 0;
-		q.lo = n.lo / d.lo;
-		return q;
-	}
-	dodiv(n, d, &q, 0);
-	return q;
-}
-
-Vlong
-_modvu(Vlong n, Vlong d)
-{
-	Vlong r;
-
-	if(n.hi == 0 && d.hi == 0) {
-		if(d.lo == 0)
-			runtime·panicdivide();
-		r.hi = 0;
-		r.lo = n.lo % d.lo;
-		return r;
-	}
-	dodiv(n, d, 0, &r);
-	return r;
-}
-
-static void
-vneg(Vlong *v)
-{
-
-	if(v->lo == 0) {
-		v->hi = -v->hi;
-		return;
-	}
-	v->lo = -v->lo;
-	v->hi = ~v->hi;
-}
-
-Vlong
-_divv(Vlong n, Vlong d)
-{
-	long nneg, dneg;
-	Vlong q;
-
-	if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
-		if((long)n.lo == -0x80000000 && (long)d.lo == -1) {
-			// special case: 32-bit -0x80000000 / -1 causes divide error,
-			// but it's okay in this 64-bit context.
-			q.lo = 0x80000000;
-			q.hi = 0;
-			return q;
-		}
-		if(d.lo == 0)
-			runtime·panicdivide();
-		q.lo = (long)n.lo / (long)d.lo;
-		q.hi = ((long)q.lo) >> 31;
-		return q;
-	}
-	nneg = n.hi >> 31;
-	if(nneg)
-		vneg(&n);
-	dneg = d.hi >> 31;
-	if(dneg)
-		vneg(&d);
-	dodiv(n, d, &q, 0);
-	if(nneg != dneg)
-		vneg(&q);
-	return q;
-}
-
-Vlong
-_modv(Vlong n, Vlong d)
-{
-	long nneg, dneg;
-	Vlong r;
-
-	if(n.hi == (((long)n.lo)>>31) && d.hi == (((long)d.lo)>>31)) {
-		if((long)n.lo == -0x80000000 && (long)d.lo == -1) {
-			// special case: 32-bit -0x80000000 % -1 causes divide error,
-			// but it's okay in this 64-bit context.
-			r.lo = 0;
-			r.hi = 0;
-			return r;
-		}
-		if(d.lo == 0)
-			runtime·panicdivide();
-		r.lo = (long)n.lo % (long)d.lo;
-		r.hi = ((long)r.lo) >> 31;
-		return r;
-	}
-	nneg = n.hi >> 31;
-	if(nneg)
-		vneg(&n);
-	dneg = d.hi >> 31;
-	if(dneg)
-		vneg(&d);
-	dodiv(n, d, 0, &r);
-	if(nneg)
-		vneg(&r);
-	return r;
-}
-
-#pragma textflag NOSPLIT
-Vlong
-_rshav(Vlong a, int b)
-{
-	long t;
-	Vlong r;
-
-	t = a.hi;
-	if(b >= 32) {
-		r.hi = t>>31;
-		if(b >= 64) {
-			/* this is illegal re C standard */
-			r.lo = t>>31;
-			return r;
-		}
-		r.lo = t >> (b-32);
-		return r;
-	}
-	if(b <= 0) {
-		r.hi = t;
-		r.lo = a.lo;
-		return r;
-	}
-	r.hi = t >> b;
-	r.lo = (t << (32-b)) | (a.lo >> b);
-	return r;
-}
-
-#pragma textflag NOSPLIT
-Vlong
-_rshlv(Vlong a, int b)
-{
-	ulong t;
-	Vlong r;
-
-	t = a.hi;
-	if(b >= 32) {
-		r.hi = 0;
-		if(b >= 64) {
-			/* this is illegal re C standard */
-			r.lo = 0;
-			return r;
-		}
-		r.lo = t >> (b-32);
-		return r;
-	}
-	if(b <= 0) {
-		r.hi = t;
-		r.lo = a.lo;
-		return r;
-	}
-	r.hi = t >> b;
-	r.lo = (t << (32-b)) | (a.lo >> b);
-	return r;
-}
-
-#pragma textflag NOSPLIT
-Vlong
-_lshv(Vlong a, int b)
-{
-	ulong t;
-
-	t = a.lo;
-	if(b >= 32) {
-		if(b >= 64) {
-			/* this is illegal re C standard */
-			return (Vlong){0, 0};
-		}
-		return (Vlong){0, t<<(b-32)};
-	}
-	if(b <= 0) {
-		return (Vlong){t, a.hi};
-	}
-	return (Vlong){t<<b, (t >> (32-b)) | (a.hi << b)};
-}
-
-#pragma textflag NOSPLIT
-Vlong
-_andv(Vlong a, Vlong b)
-{
-	Vlong r;
-
-	r.hi = a.hi & b.hi;
-	r.lo = a.lo & b.lo;
-	return r;
-}
-
-#pragma textflag NOSPLIT
-Vlong
-_orv(Vlong a, Vlong b)
-{
-	Vlong r;
-
-	r.hi = a.hi | b.hi;
-	r.lo = a.lo | b.lo;
-	return r;
-}
-
-#pragma textflag NOSPLIT
-Vlong
-_xorv(Vlong a, Vlong b)
-{
-	Vlong r;
-
-	r.hi = a.hi ^ b.hi;
-	r.lo = a.lo ^ b.lo;
-	return r;
-}
-
-Vlong
-_vpp(Vlong *r)
-{
-	Vlong l;
-
-	l = *r;
-	r->lo++;
-	if(r->lo == 0)
-		r->hi++;
-	return l;
-}
-
-#pragma textflag NOSPLIT
-Vlong
-_vmm(Vlong *r)
-{
-	Vlong l;
-
-	l = *r;
-	if(r->lo == 0)
-		r->hi--;
-	r->lo--;
-	return l;
-}
-
-#pragma textflag NOSPLIT
-Vlong
-_ppv(Vlong *r)
-{
-
-	r->lo++;
-	if(r->lo == 0)
-		r->hi++;
-	return *r;
-}
-
-#pragma textflag NOSPLIT
-Vlong
-_mmv(Vlong *r)
-{
-
-	if(r->lo == 0)
-		r->hi--;
-	r->lo--;
-	return *r;
-}
-
-#pragma textflag NOSPLIT
-Vlong
-_vasop(void *lv, Vlong fn(Vlong, Vlong), int type, Vlong rv)
-{
-	Vlong t, u;
-
-	u.lo = 0;
-	u.hi = 0;
-	switch(type) {
-	default:
-		runtime·abort();
-		break;
-
-	case 1:	/* schar */
-		t.lo = *(schar*)lv;
-		t.hi = t.lo >> 31;
-		u = fn(t, rv);
-		*(schar*)lv = u.lo;
-		break;
-
-	case 2:	/* uchar */
-		t.lo = *(uchar*)lv;
-		t.hi = 0;
-		u = fn(t, rv);
-		*(uchar*)lv = u.lo;
-		break;
-
-	case 3:	/* short */
-		t.lo = *(short*)lv;
-		t.hi = t.lo >> 31;
-		u = fn(t, rv);
-		*(short*)lv = u.lo;
-		break;
-
-	case 4:	/* ushort */
-		t.lo = *(ushort*)lv;
-		t.hi = 0;
-		u = fn(t, rv);
-		*(ushort*)lv = u.lo;
-		break;
-
-	case 9:	/* int */
-		t.lo = *(int*)lv;
-		t.hi = t.lo >> 31;
-		u = fn(t, rv);
-		*(int*)lv = u.lo;
-		break;
-
-	case 10:	/* uint */
-		t.lo = *(uint*)lv;
-		t.hi = 0;
-		u = fn(t, rv);
-		*(uint*)lv = u.lo;
-		break;
-
-	case 5:	/* long */
-		t.lo = *(long*)lv;
-		t.hi = t.lo >> 31;
-		u = fn(t, rv);
-		*(long*)lv = u.lo;
-		break;
-
-	case 6:	/* ulong */
-		t.lo = *(ulong*)lv;
-		t.hi = 0;
-		u = fn(t, rv);
-		*(ulong*)lv = u.lo;
-		break;
-
-	case 7:	/* vlong */
-	case 8:	/* uvlong */
-		if((void*)fn == _lshv || (void*)fn == _rshav || (void*)fn == _rshlv)
-			u = ((Vlong(*)(Vlong,int))fn)(*(Vlong*)lv, *(int*)&rv);
-		else
-			u = fn(*(Vlong*)lv, rv);
-		*(Vlong*)lv = u;
-		break;
-	}
-	return u;
-}
-
-#pragma textflag NOSPLIT
-Vlong
-_p2v(void *p)
-{
-	long t;
-	Vlong ret;
-
-	t = (ulong)p;
-	ret.lo = t;
-	ret.hi = 0;
-	return ret;
-}
-
-#pragma textflag NOSPLIT
-Vlong
-_sl2v(long sl)
-{
-	long t;
-	Vlong ret;
-
-	t = sl;
-	ret.lo = t;
-	ret.hi = t >> 31;
-	return ret;
-}
-
-#pragma textflag NOSPLIT
-Vlong
-_ul2v(ulong ul)
-{
-	long t;
-	Vlong ret;
-
-	t = ul;
-	ret.lo = t;
-	ret.hi = 0;
-	return ret;
-}
-
-#pragma textflag NOSPLIT
-Vlong
-_si2v(int si)
-{
-	return (Vlong){si, si>>31};
-}
-
-#pragma textflag NOSPLIT
-Vlong
-_ui2v(uint ui)
-{
-	long t;
-	Vlong ret;
-
-	t = ui;
-	ret.lo = t;
-	ret.hi = 0;
-	return ret;
-}
-
-#pragma textflag NOSPLIT
-Vlong
-_sh2v(long sh)
-{
-	long t;
-	Vlong ret;
-
-	t = (sh << 16) >> 16;
-	ret.lo = t;
-	ret.hi = t >> 31;
-	return ret;
-}
-
-#pragma textflag NOSPLIT
-Vlong
-_uh2v(ulong ul)
-{
-	long t;
-	Vlong ret;
-
-	t = ul & 0xffff;
-	ret.lo = t;
-	ret.hi = 0;
-	return ret;
-}
-
-#pragma textflag NOSPLIT
-Vlong
-_sc2v(long uc)
-{
-	long t;
-	Vlong ret;
-
-	t = (uc << 24) >> 24;
-	ret.lo = t;
-	ret.hi = t >> 31;
-	return ret;
-}
-
-#pragma textflag NOSPLIT
-Vlong
-_uc2v(ulong ul)
-{
-	long t;
-	Vlong ret;
-
-	t = ul & 0xff;
-	ret.lo = t;
-	ret.hi = 0;
-	return ret;
-}
-
-#pragma textflag NOSPLIT
-long
-_v2sc(Vlong rv)
-{
-	long t;
-
-	t = rv.lo & 0xff;
-	return (t << 24) >> 24;
-}
-
-#pragma textflag NOSPLIT
-long
-_v2uc(Vlong rv)
-{
-
-	return rv.lo & 0xff;
-}
-
-#pragma textflag NOSPLIT
-long
-_v2sh(Vlong rv)
-{
-	long t;
-
-	t = rv.lo & 0xffff;
-	return (t << 16) >> 16;
-}
-
-#pragma textflag NOSPLIT
-long
-_v2uh(Vlong rv)
-{
-
-	return rv.lo & 0xffff;
-}
-
-#pragma textflag NOSPLIT
-long
-_v2sl(Vlong rv)
-{
-
-	return rv.lo;
-}
-
-#pragma textflag NOSPLIT
-long
-_v2ul(Vlong rv)
-{
-
-	return rv.lo;
-}
-
-#pragma textflag NOSPLIT
-long
-_v2si(Vlong rv)
-{
-	return rv.lo;
-}
-
-#pragma textflag NOSPLIT
-long
-_v2ui(Vlong rv)
-{
-
-	return rv.lo;
-}
-
-#pragma textflag NOSPLIT
-int
-_testv(Vlong rv)
-{
-	return rv.lo || rv.hi;
-}
-
-#pragma textflag NOSPLIT
-int
-_eqv(Vlong lv, Vlong rv)
-{
-	return lv.lo == rv.lo && lv.hi == rv.hi;
-}
-
-#pragma textflag NOSPLIT
-int
-_nev(Vlong lv, Vlong rv)
-{
-	return lv.lo != rv.lo || lv.hi != rv.hi;
-}
-
-#pragma textflag NOSPLIT
-int
-_ltv(Vlong lv, Vlong rv)
-{
-	return (long)lv.hi < (long)rv.hi ||
-		(lv.hi == rv.hi && lv.lo < rv.lo);
-}
-
-#pragma textflag NOSPLIT
-int
-_lev(Vlong lv, Vlong rv)
-{
-	return (long)lv.hi < (long)rv.hi ||
-		(lv.hi == rv.hi && lv.lo <= rv.lo);
-}
-
-#pragma textflag NOSPLIT
-int
-_gtv(Vlong lv, Vlong rv)
-{
-	return (long)lv.hi > (long)rv.hi ||
-		(lv.hi == rv.hi && lv.lo > rv.lo);
-}
-
-#pragma textflag NOSPLIT
-int
-_gev(Vlong lv, Vlong rv)
-{
-	return (long)lv.hi > (long)rv.hi ||
-		(lv.hi == rv.hi && lv.lo >= rv.lo);
-}
-
-#pragma textflag NOSPLIT
-int
-_lov(Vlong lv, Vlong rv)
-{
-	return lv.hi < rv.hi ||
-		(lv.hi == rv.hi && lv.lo < rv.lo);
-}
-
-#pragma textflag NOSPLIT
-int
-_lsv(Vlong lv, Vlong rv)
-{
-	return lv.hi < rv.hi ||
-		(lv.hi == rv.hi && lv.lo <= rv.lo);
-}
-
-#pragma textflag NOSPLIT
-int
-_hiv(Vlong lv, Vlong rv)
-{
-	return lv.hi > rv.hi ||
-		(lv.hi == rv.hi && lv.lo > rv.lo);
-}
-
-#pragma textflag NOSPLIT
-int
-_hsv(Vlong lv, Vlong rv)
-{
-	return lv.hi > rv.hi ||
-		(lv.hi == rv.hi && lv.lo >= rv.lo);
-}
diff --git a/src/runtime/wbfat.go b/src/runtime/wbfat.go
new file mode 100644
index 0000000..8fe2cef
--- /dev/null
+++ b/src/runtime/wbfat.go
@@ -0,0 +1,190 @@
+// generated by wbfat_gen.go; use go generate
+
+package runtime
+
+//go:nosplit
+func writebarrierfat01(dst *[2]uintptr, _ uintptr, src [2]uintptr) {
+	dst[0] = src[0]
+	writebarrierptr(&dst[1], src[1])
+}
+
+//go:nosplit
+func writebarrierfat10(dst *[2]uintptr, _ uintptr, src [2]uintptr) {
+	writebarrierptr(&dst[0], src[0])
+	dst[1] = src[1]
+}
+
+//go:nosplit
+func writebarrierfat11(dst *[2]uintptr, _ uintptr, src [2]uintptr) {
+	writebarrierptr(&dst[0], src[0])
+	writebarrierptr(&dst[1], src[1])
+}
+
+//go:nosplit
+func writebarrierfat001(dst *[3]uintptr, _ uintptr, src [3]uintptr) {
+	dst[0] = src[0]
+	dst[1] = src[1]
+	writebarrierptr(&dst[2], src[2])
+}
+
+//go:nosplit
+func writebarrierfat010(dst *[3]uintptr, _ uintptr, src [3]uintptr) {
+	dst[0] = src[0]
+	writebarrierptr(&dst[1], src[1])
+	dst[2] = src[2]
+}
+
+//go:nosplit
+func writebarrierfat011(dst *[3]uintptr, _ uintptr, src [3]uintptr) {
+	dst[0] = src[0]
+	writebarrierptr(&dst[1], src[1])
+	writebarrierptr(&dst[2], src[2])
+}
+
+//go:nosplit
+func writebarrierfat100(dst *[3]uintptr, _ uintptr, src [3]uintptr) {
+	writebarrierptr(&dst[0], src[0])
+	dst[1] = src[1]
+	dst[2] = src[2]
+}
+
+//go:nosplit
+func writebarrierfat101(dst *[3]uintptr, _ uintptr, src [3]uintptr) {
+	writebarrierptr(&dst[0], src[0])
+	dst[1] = src[1]
+	writebarrierptr(&dst[2], src[2])
+}
+
+//go:nosplit
+func writebarrierfat110(dst *[3]uintptr, _ uintptr, src [3]uintptr) {
+	writebarrierptr(&dst[0], src[0])
+	writebarrierptr(&dst[1], src[1])
+	dst[2] = src[2]
+}
+
+//go:nosplit
+func writebarrierfat111(dst *[3]uintptr, _ uintptr, src [3]uintptr) {
+	writebarrierptr(&dst[0], src[0])
+	writebarrierptr(&dst[1], src[1])
+	writebarrierptr(&dst[2], src[2])
+}
+
+//go:nosplit
+func writebarrierfat0001(dst *[4]uintptr, _ uintptr, src [4]uintptr) {
+	dst[0] = src[0]
+	dst[1] = src[1]
+	dst[2] = src[2]
+	writebarrierptr(&dst[3], src[3])
+}
+
+//go:nosplit
+func writebarrierfat0010(dst *[4]uintptr, _ uintptr, src [4]uintptr) {
+	dst[0] = src[0]
+	dst[1] = src[1]
+	writebarrierptr(&dst[2], src[2])
+	dst[3] = src[3]
+}
+
+//go:nosplit
+func writebarrierfat0011(dst *[4]uintptr, _ uintptr, src [4]uintptr) {
+	dst[0] = src[0]
+	dst[1] = src[1]
+	writebarrierptr(&dst[2], src[2])
+	writebarrierptr(&dst[3], src[3])
+}
+
+//go:nosplit
+func writebarrierfat0100(dst *[4]uintptr, _ uintptr, src [4]uintptr) {
+	dst[0] = src[0]
+	writebarrierptr(&dst[1], src[1])
+	dst[2] = src[2]
+	dst[3] = src[3]
+}
+
+//go:nosplit
+func writebarrierfat0101(dst *[4]uintptr, _ uintptr, src [4]uintptr) {
+	dst[0] = src[0]
+	writebarrierptr(&dst[1], src[1])
+	dst[2] = src[2]
+	writebarrierptr(&dst[3], src[3])
+}
+
+//go:nosplit
+func writebarrierfat0110(dst *[4]uintptr, _ uintptr, src [4]uintptr) {
+	dst[0] = src[0]
+	writebarrierptr(&dst[1], src[1])
+	writebarrierptr(&dst[2], src[2])
+	dst[3] = src[3]
+}
+
+//go:nosplit
+func writebarrierfat0111(dst *[4]uintptr, _ uintptr, src [4]uintptr) {
+	dst[0] = src[0]
+	writebarrierptr(&dst[1], src[1])
+	writebarrierptr(&dst[2], src[2])
+	writebarrierptr(&dst[3], src[3])
+}
+
+//go:nosplit
+func writebarrierfat1000(dst *[4]uintptr, _ uintptr, src [4]uintptr) {
+	writebarrierptr(&dst[0], src[0])
+	dst[1] = src[1]
+	dst[2] = src[2]
+	dst[3] = src[3]
+}
+
+//go:nosplit
+func writebarrierfat1001(dst *[4]uintptr, _ uintptr, src [4]uintptr) {
+	writebarrierptr(&dst[0], src[0])
+	dst[1] = src[1]
+	dst[2] = src[2]
+	writebarrierptr(&dst[3], src[3])
+}
+
+//go:nosplit
+func writebarrierfat1010(dst *[4]uintptr, _ uintptr, src [4]uintptr) {
+	writebarrierptr(&dst[0], src[0])
+	dst[1] = src[1]
+	writebarrierptr(&dst[2], src[2])
+	dst[3] = src[3]
+}
+
+//go:nosplit
+func writebarrierfat1011(dst *[4]uintptr, _ uintptr, src [4]uintptr) {
+	writebarrierptr(&dst[0], src[0])
+	dst[1] = src[1]
+	writebarrierptr(&dst[2], src[2])
+	writebarrierptr(&dst[3], src[3])
+}
+
+//go:nosplit
+func writebarrierfat1100(dst *[4]uintptr, _ uintptr, src [4]uintptr) {
+	writebarrierptr(&dst[0], src[0])
+	writebarrierptr(&dst[1], src[1])
+	dst[2] = src[2]
+	dst[3] = src[3]
+}
+
+//go:nosplit
+func writebarrierfat1101(dst *[4]uintptr, _ uintptr, src [4]uintptr) {
+	writebarrierptr(&dst[0], src[0])
+	writebarrierptr(&dst[1], src[1])
+	dst[2] = src[2]
+	writebarrierptr(&dst[3], src[3])
+}
+
+//go:nosplit
+func writebarrierfat1110(dst *[4]uintptr, _ uintptr, src [4]uintptr) {
+	writebarrierptr(&dst[0], src[0])
+	writebarrierptr(&dst[1], src[1])
+	writebarrierptr(&dst[2], src[2])
+	dst[3] = src[3]
+}
+
+//go:nosplit
+func writebarrierfat1111(dst *[4]uintptr, _ uintptr, src [4]uintptr) {
+	writebarrierptr(&dst[0], src[0])
+	writebarrierptr(&dst[1], src[1])
+	writebarrierptr(&dst[2], src[2])
+	writebarrierptr(&dst[3], src[3])
+}
diff --git a/src/runtime/wbfat_gen.go b/src/runtime/wbfat_gen.go
new file mode 100644
index 0000000..9482cfe
--- /dev/null
+++ b/src/runtime/wbfat_gen.go
@@ -0,0 +1,41 @@
+// 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 ignore
+
+package main
+
+import (
+	"flag"
+	"fmt"
+	"log"
+	"os"
+)
+
+func main() {
+	flag.Parse()
+	if flag.NArg() > 0 {
+		f, err := os.Create(flag.Arg(0))
+		if err != nil {
+			log.Fatal(err)
+		}
+		os.Stdout = f
+	}
+	fmt.Printf("// generated by wbfat_gen.go; use go generate\n\n")
+	fmt.Printf("package runtime\n")
+	for i := uint(2); i <= 4; i++ {
+		for j := 1; j < 1<<i; j++ {
+			fmt.Printf("\n//go:nosplit\n")
+			fmt.Printf("func writebarrierfat%0*b(dst *[%d]uintptr, _ uintptr, src [%d]uintptr) {\n", int(i), j, i, i)
+			for k := uint(0); k < i; k++ {
+				if j&(1<<(i-1-k)) != 0 {
+					fmt.Printf("\twritebarrierptr(&dst[%d], src[%d])\n", k, k)
+				} else {
+					fmt.Printf("\tdst[%d] = src[%d]\n", k, k)
+				}
+			}
+			fmt.Printf("}\n")
+		}
+	}
+}
diff --git a/src/runtime/wincallback.go b/src/runtime/wincallback.go
new file mode 100644
index 0000000..a16ad21
--- /dev/null
+++ b/src/runtime/wincallback.go
@@ -0,0 +1,64 @@
+// 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 ignore
+
+// Generate Windows callback assembly file.
+
+package main
+
+import (
+	"bytes"
+	"fmt"
+	"io/ioutil"
+	"os"
+)
+
+const maxCallback = 2000
+
+func genasm() {
+	var buf bytes.Buffer
+
+	buf.WriteString(`// generated by wincallback.go; run go generate
+
+// runtime·callbackasm is called by external code to
+// execute Go implemented callback function. It is not
+// called from the start, instead runtime·compilecallback
+// always returns address into runtime·callbackasm offset
+// appropriately so different callbacks start with different
+// CALL instruction in runtime·callbackasm. This determines
+// which Go callback function is executed later on.
+TEXT runtime·callbackasm(SB),7,$0
+`)
+	for i := 0; i < maxCallback; i++ {
+		buf.WriteString("\tCALL\truntime·callbackasm1(SB)\n")
+	}
+
+	err := ioutil.WriteFile("zcallback_windows.s", buf.Bytes(), 0666)
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "wincallback: %s\n", err)
+		os.Exit(2)
+	}
+}
+
+func gengo() {
+	var buf bytes.Buffer
+
+	buf.WriteString(fmt.Sprintf(`// generated by wincallback.go; run go generate
+
+package runtime
+
+const cb_max = %d // maximum number of windows callbacks allowed
+`, maxCallback))
+	err := ioutil.WriteFile("zcallback_windows.go", buf.Bytes(), 0666)
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "wincallback: %s\n", err)
+		os.Exit(2)
+	}
+}
+
+func main() {
+	genasm()
+	gengo()
+}
diff --git a/src/runtime/zcallback_windows.go b/src/runtime/zcallback_windows.go
new file mode 100644
index 0000000..9908d4e
--- /dev/null
+++ b/src/runtime/zcallback_windows.go
@@ -0,0 +1,5 @@
+// generated by wincallback.go; run go generate
+
+package runtime
+
+const cb_max = 2000 // maximum number of windows callbacks allowed
diff --git a/src/runtime/zcallback_windows.s b/src/runtime/zcallback_windows.s
new file mode 100644
index 0000000..b9a3a30
--- /dev/null
+++ b/src/runtime/zcallback_windows.s
@@ -0,0 +1,2010 @@
+// generated by wincallback.go; run go generate
+
+// runtime·callbackasm is called by external code to
+// execute Go implemented callback function. It is not
+// called from the start, instead runtime·compilecallback
+// always returns address into runtime·callbackasm offset
+// appropriately so different callbacks start with different
+// CALL instruction in runtime·callbackasm. This determines
+// which Go callback function is executed later on.
+TEXT runtime·callbackasm(SB),7,$0
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
+	CALL	runtime·callbackasm1(SB)
diff --git a/src/runtime/zgoarch_386.go b/src/runtime/zgoarch_386.go
new file mode 100644
index 0000000..79053f1
--- /dev/null
+++ b/src/runtime/zgoarch_386.go
@@ -0,0 +1,13 @@
+// generated by gengoos.go using 'go generate'
+
+package runtime
+
+const theGoarch = `386`
+
+const goarch_386 = 1
+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
new file mode 100644
index 0000000..70095f5
--- /dev/null
+++ b/src/runtime/zgoarch_amd64.go
@@ -0,0 +1,13 @@
+// generated by gengoos.go using 'go generate'
+
+package runtime
+
+const theGoarch = `amd64`
+
+const goarch_386 = 0
+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
new file mode 100644
index 0000000..9ac3f0b
--- /dev/null
+++ b/src/runtime/zgoarch_amd64p32.go
@@ -0,0 +1,13 @@
+// generated by gengoos.go using 'go generate'
+
+package runtime
+
+const theGoarch = `amd64p32`
+
+const goarch_386 = 0
+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
new file mode 100644
index 0000000..c865dc0
--- /dev/null
+++ b/src/runtime/zgoarch_arm.go
@@ -0,0 +1,13 @@
+// generated by gengoos.go using 'go generate'
+
+package runtime
+
+const theGoarch = `arm`
+
+const goarch_386 = 0
+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
new file mode 100644
index 0000000..13d87d9
--- /dev/null
+++ b/src/runtime/zgoarch_ppc64.go
@@ -0,0 +1,13 @@
+// generated by gengoos.go using 'go generate'
+
+package runtime
+
+const theGoarch = `ppc64`
+
+const goarch_386 = 0
+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
new file mode 100644
index 0000000..5d088aa
--- /dev/null
+++ b/src/runtime/zgoarch_ppc64le.go
@@ -0,0 +1,13 @@
+// generated by gengoos.go using 'go generate'
+
+package runtime
+
+const theGoarch = `ppc64le`
+
+const goarch_386 = 0
+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/runtime/zgoos_android.go b/src/runtime/zgoos_android.go
new file mode 100644
index 0000000..0590bd9
--- /dev/null
+++ b/src/runtime/zgoos_android.go
@@ -0,0 +1,17 @@
+// generated by gengoos.go using 'go generate'
+
+package runtime
+
+const theGoos = `android`
+
+const goos_android = 1
+const goos_darwin = 0
+const goos_dragonfly = 0
+const goos_freebsd = 0
+const goos_linux = 0
+const goos_nacl = 0
+const goos_netbsd = 0
+const goos_openbsd = 0
+const goos_plan9 = 0
+const goos_solaris = 0
+const goos_windows = 0
diff --git a/src/runtime/zgoos_darwin.go b/src/runtime/zgoos_darwin.go
new file mode 100644
index 0000000..c0a7cd6
--- /dev/null
+++ b/src/runtime/zgoos_darwin.go
@@ -0,0 +1,17 @@
+// generated by gengoos.go using 'go generate'
+
+package runtime
+
+const theGoos = `darwin`
+
+const goos_android = 0
+const goos_darwin = 1
+const goos_dragonfly = 0
+const goos_freebsd = 0
+const goos_linux = 0
+const goos_nacl = 0
+const goos_netbsd = 0
+const goos_openbsd = 0
+const goos_plan9 = 0
+const goos_solaris = 0
+const goos_windows = 0
diff --git a/src/runtime/zgoos_dragonfly.go b/src/runtime/zgoos_dragonfly.go
new file mode 100644
index 0000000..008d6de
--- /dev/null
+++ b/src/runtime/zgoos_dragonfly.go
@@ -0,0 +1,17 @@
+// generated by gengoos.go using 'go generate'
+
+package runtime
+
+const theGoos = `dragonfly`
+
+const goos_android = 0
+const goos_darwin = 0
+const goos_dragonfly = 1
+const goos_freebsd = 0
+const goos_linux = 0
+const goos_nacl = 0
+const goos_netbsd = 0
+const goos_openbsd = 0
+const goos_plan9 = 0
+const goos_solaris = 0
+const goos_windows = 0
diff --git a/src/runtime/zgoos_freebsd.go b/src/runtime/zgoos_freebsd.go
new file mode 100644
index 0000000..2478940
--- /dev/null
+++ b/src/runtime/zgoos_freebsd.go
@@ -0,0 +1,17 @@
+// generated by gengoos.go using 'go generate'
+
+package runtime
+
+const theGoos = `freebsd`
+
+const goos_android = 0
+const goos_darwin = 0
+const goos_dragonfly = 0
+const goos_freebsd = 1
+const goos_linux = 0
+const goos_nacl = 0
+const goos_netbsd = 0
+const goos_openbsd = 0
+const goos_plan9 = 0
+const goos_solaris = 0
+const goos_windows = 0
diff --git a/src/runtime/zgoos_linux.go b/src/runtime/zgoos_linux.go
new file mode 100644
index 0000000..c775ab5
--- /dev/null
+++ b/src/runtime/zgoos_linux.go
@@ -0,0 +1,19 @@
+// generated by gengoos.go using 'go generate'
+
+// +build !android
+
+package runtime
+
+const theGoos = `linux`
+
+const goos_android = 0
+const goos_darwin = 0
+const goos_dragonfly = 0
+const goos_freebsd = 0
+const goos_linux = 1
+const goos_nacl = 0
+const goos_netbsd = 0
+const goos_openbsd = 0
+const goos_plan9 = 0
+const goos_solaris = 0
+const goos_windows = 0
diff --git a/src/runtime/zgoos_nacl.go b/src/runtime/zgoos_nacl.go
new file mode 100644
index 0000000..d9d88f4
--- /dev/null
+++ b/src/runtime/zgoos_nacl.go
@@ -0,0 +1,17 @@
+// generated by gengoos.go using 'go generate'
+
+package runtime
+
+const theGoos = `nacl`
+
+const goos_android = 0
+const goos_darwin = 0
+const goos_dragonfly = 0
+const goos_freebsd = 0
+const goos_linux = 0
+const goos_nacl = 1
+const goos_netbsd = 0
+const goos_openbsd = 0
+const goos_plan9 = 0
+const goos_solaris = 0
+const goos_windows = 0
diff --git a/src/runtime/zgoos_netbsd.go b/src/runtime/zgoos_netbsd.go
new file mode 100644
index 0000000..ff2c5cb
--- /dev/null
+++ b/src/runtime/zgoos_netbsd.go
@@ -0,0 +1,17 @@
+// generated by gengoos.go using 'go generate'
+
+package runtime
+
+const theGoos = `netbsd`
+
+const goos_android = 0
+const goos_darwin = 0
+const goos_dragonfly = 0
+const goos_freebsd = 0
+const goos_linux = 0
+const goos_nacl = 0
+const goos_netbsd = 1
+const goos_openbsd = 0
+const goos_plan9 = 0
+const goos_solaris = 0
+const goos_windows = 0
diff --git a/src/runtime/zgoos_openbsd.go b/src/runtime/zgoos_openbsd.go
new file mode 100644
index 0000000..b071dc6
--- /dev/null
+++ b/src/runtime/zgoos_openbsd.go
@@ -0,0 +1,17 @@
+// generated by gengoos.go using 'go generate'
+
+package runtime
+
+const theGoos = `openbsd`
+
+const goos_android = 0
+const goos_darwin = 0
+const goos_dragonfly = 0
+const goos_freebsd = 0
+const goos_linux = 0
+const goos_nacl = 0
+const goos_netbsd = 0
+const goos_openbsd = 1
+const goos_plan9 = 0
+const goos_solaris = 0
+const goos_windows = 0
diff --git a/src/runtime/zgoos_plan9.go b/src/runtime/zgoos_plan9.go
new file mode 100644
index 0000000..4306b0f
--- /dev/null
+++ b/src/runtime/zgoos_plan9.go
@@ -0,0 +1,17 @@
+// generated by gengoos.go using 'go generate'
+
+package runtime
+
+const theGoos = `plan9`
+
+const goos_android = 0
+const goos_darwin = 0
+const goos_dragonfly = 0
+const goos_freebsd = 0
+const goos_linux = 0
+const goos_nacl = 0
+const goos_netbsd = 0
+const goos_openbsd = 0
+const goos_plan9 = 1
+const goos_solaris = 0
+const goos_windows = 0
diff --git a/src/runtime/zgoos_solaris.go b/src/runtime/zgoos_solaris.go
new file mode 100644
index 0000000..10f9537
--- /dev/null
+++ b/src/runtime/zgoos_solaris.go
@@ -0,0 +1,17 @@
+// generated by gengoos.go using 'go generate'
+
+package runtime
+
+const theGoos = `solaris`
+
+const goos_android = 0
+const goos_darwin = 0
+const goos_dragonfly = 0
+const goos_freebsd = 0
+const goos_linux = 0
+const goos_nacl = 0
+const goos_netbsd = 0
+const goos_openbsd = 0
+const goos_plan9 = 0
+const goos_solaris = 1
+const goos_windows = 0
diff --git a/src/runtime/zgoos_windows.go b/src/runtime/zgoos_windows.go
new file mode 100644
index 0000000..56f5c58
--- /dev/null
+++ b/src/runtime/zgoos_windows.go
@@ -0,0 +1,17 @@
+// generated by gengoos.go using 'go generate'
+
+package runtime
+
+const theGoos = `windows`
+
+const goos_android = 0
+const goos_darwin = 0
+const goos_dragonfly = 0
+const goos_freebsd = 0
+const goos_linux = 0
+const goos_nacl = 0
+const goos_netbsd = 0
+const goos_openbsd = 0
+const goos_plan9 = 0
+const goos_solaris = 0
+const goos_windows = 1
diff --git a/src/sort/sort.go b/src/sort/sort.go
index e980c29..c7c3042 100644
--- a/src/sort/sort.go
+++ b/src/sort/sort.go
@@ -75,20 +75,19 @@ func heapSort(data Interface, a, b int) {
 // Quicksort, following Bentley and McIlroy,
 // ``Engineering a Sort Function,'' SP&E November 1993.
 
-// medianOfThree moves the median of the three values data[a], data[b], data[c] into data[a].
-func medianOfThree(data Interface, a, b, c int) {
-	m0 := b
-	m1 := a
-	m2 := c
-	// bubble sort on 3 elements
+// medianOfThree moves the median of the three values data[m0], data[m1], data[m2] into data[m1].
+func medianOfThree(data Interface, m1, m0, m2 int) {
+	// sort 3 elements
 	if data.Less(m1, m0) {
 		data.Swap(m1, m0)
 	}
+	// data[m0] <= data[m1]
 	if data.Less(m2, m1) {
 		data.Swap(m2, m1)
-	}
-	if data.Less(m1, m0) {
-		data.Swap(m1, m0)
+		// data[m0] <= data[m2] && data[m1] < data[m2]
+		if data.Less(m1, m0) {
+			data.Swap(m1, m0)
+		}
 	}
 	// now data[m0] <= data[m1] <= data[m2]
 }
@@ -297,11 +296,11 @@ func StringsAreSorted(a []string) bool { return IsSorted(StringSlice(a)) }
 //    and Jukka Teuhola; Nordic Journal of Computing 3,1 (1996), 27-40:
 //    The given algorithms are in-place, number of Swap and Assignments
 //    grow as n log n but the algorithm is not stable.
-//  - "Fast Stable In-Plcae Sorting with O(n) Data Moves" J.I. Munro and
+//  - "Fast Stable In-Place Sorting with O(n) Data Moves" J.I. Munro and
 //    V. Raman in Algorithmica (1996) 16, 115-160:
 //    This algorithm either needs additional 2n bits or works only if there
 //    are enough different elements available to encode some permutations
-//    which have to be undone later (so not stable an any input).
+//    which have to be undone later (so not stable on any input).
 //  - All the optimal in-place sorting/merging algorithms I found are either
 //    unstable or rely on enough different elements in each step to encode the
 //    performed block rearrangements. See also "In-Place Merging Algorithms",
@@ -316,7 +315,7 @@ func StringsAreSorted(a []string) bool { return IsSorted(StringSlice(a)) }
 // data.Less and O(n*log(n)*log(n)) calls to data.Swap.
 func Stable(data Interface) {
 	n := data.Len()
-	blockSize := 20
+	blockSize := 20 // must be > 0
 	a, b := 0, blockSize
 	for b <= n {
 		insertionSort(data, a, b)
@@ -332,7 +331,9 @@ func Stable(data Interface) {
 			a = b
 			b += 2 * blockSize
 		}
-		symMerge(data, a, a+blockSize, n)
+		if m := a + blockSize; m < n {
+			symMerge(data, a, m, n)
+		}
 		blockSize *= 2
 	}
 }
@@ -352,72 +353,111 @@ func Stable(data Interface) {
 // rotation algorithm which uses O(M+N+gcd(M+N)) assignments. The argumentation
 // in the paper carries through for Swap operations, especially as the block
 // swapping rotate uses only O(M+N) Swaps.
+//
+// symMerge assumes non-degenerate arguments: a < m && m < b.
+// Having the caller check this condition eliminates many leaf recursion calls,
+// which improves performance.
 func symMerge(data Interface, a, m, b int) {
-	if a >= m || m >= b {
+	// Avoid unnecessary recursions of symMerge
+	// by direct insertion of data[a] into data[m:b]
+	// if data[a:m] only contains one element.
+	if m-a == 1 {
+		// Use binary search to find the lowest index i
+		// such that data[i] >= data[a] for m <= i < b.
+		// Exit the search loop with i == b in case no such index exists.
+		i := m
+		j := b
+		for i < j {
+			h := i + (j-i)/2
+			if data.Less(h, a) {
+				i = h + 1
+			} else {
+				j = h
+			}
+		}
+		// Swap values until data[a] reaches the position before i.
+		for k := a; k < i-1; k++ {
+			data.Swap(k, k+1)
+		}
+		return
+	}
+
+	// Avoid unnecessary recursions of symMerge
+	// by direct insertion of data[m] into data[a:m]
+	// if data[m:b] only contains one element.
+	if b-m == 1 {
+		// Use binary search to find the lowest index i
+		// such that data[i] > data[m] for a <= i < m.
+		// Exit the search loop with i == m in case no such index exists.
+		i := a
+		j := m
+		for i < j {
+			h := i + (j-i)/2
+			if !data.Less(m, h) {
+				i = h + 1
+			} else {
+				j = h
+			}
+		}
+		// Swap values until data[m] reaches the position i.
+		for k := m; k > i; k-- {
+			data.Swap(k, k-1)
+		}
 		return
 	}
 
 	mid := a + (b-a)/2
 	n := mid + m
-	start := 0
+	var start, r int
 	if m > mid {
 		start = n - b
-		r, p := mid, n-1
-		for start < r {
-			c := start + (r-start)/2
-			if !data.Less(p-c, c) {
-				start = c + 1
-			} else {
-				r = c
-			}
-		}
+		r = mid
 	} else {
 		start = a
-		r, p := m, n-1
-		for start < r {
-			c := start + (r-start)/2
-			if !data.Less(p-c, c) {
-				start = c + 1
-			} else {
-				r = c
-			}
+		r = m
+	}
+	p := n - 1
+
+	for start < r {
+		c := start + (r-start)/2
+		if !data.Less(p-c, c) {
+			start = c + 1
+		} else {
+			r = c
 		}
 	}
+
 	end := n - start
-	rotate(data, start, m, end)
-	symMerge(data, a, start, mid)
-	symMerge(data, mid, end, b)
+	if start < m && m < end {
+		rotate(data, start, m, end)
+	}
+	if a < start && start < mid {
+		symMerge(data, a, start, mid)
+	}
+	if mid < end && end < b {
+		symMerge(data, mid, end, b)
+	}
 }
 
 // Rotate two consecutives blocks u = data[a:m] and v = data[m:b] in data:
 // Data of the form 'x u v y' is changed to 'x v u y'.
 // Rotate performs at most b-a many calls to data.Swap.
+// Rotate assumes non-degenerate arguments: a < m && m < b.
 func rotate(data Interface, a, m, b int) {
 	i := m - a
-	if i == 0 {
-		return
-	}
 	j := b - m
-	if j == 0 {
-		return
-	}
-
-	if i == j {
-		swapRange(data, a, m, i)
-		return
-	}
 
-	p := a + i
 	for i != j {
 		if i > j {
-			swapRange(data, p-i, p, j)
+			swapRange(data, m-i, m, j)
 			i -= j
 		} else {
-			swapRange(data, p-i, p+j-i, i)
+			swapRange(data, m-i, m+j-i, i)
 			j -= i
 		}
 	}
-	swapRange(data, p-i, p, i)
+	// i == j
+	swapRange(data, m-i, m, i)
 }
 
 /*
diff --git a/src/strconv/atof.go b/src/strconv/atof.go
index 2862064..85b959f 100644
--- a/src/strconv/atof.go
+++ b/src/strconv/atof.go
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Package strconv implements conversions to and from string representations
-// of basic data types.
 package strconv
 
 // decimal to binary floating point conversion.
diff --git a/src/strconv/atoi.go b/src/strconv/atoi.go
index 9ecec5a..965e3a2 100644
--- a/src/strconv/atoi.go
+++ b/src/strconv/atoi.go
@@ -36,13 +36,7 @@ const intSize = 32 << (^uint(0) >> 63)
 // IntSize is the size in bits of an int or uint value.
 const IntSize = intSize
 
-// Return the first number n such that n*base >= 1<<64.
-func cutoff64(base int) uint64 {
-	if base < 2 {
-		return 0
-	}
-	return (1<<64-1)/uint64(base) + 1
-}
+const maxUint64 = (1<<64 - 1)
 
 // ParseUint is like ParseInt but for unsigned numbers.
 func ParseUint(s string, base int, bitSize int) (n uint64, err error) {
@@ -52,7 +46,7 @@ func ParseUint(s string, base int, bitSize int) (n uint64, err error) {
 		bitSize = int(IntSize)
 	}
 
-	s0 := s
+	i := 0
 	switch {
 	case len(s) < 1:
 		err = ErrSyntax
@@ -65,14 +59,15 @@ func ParseUint(s string, base int, bitSize int) (n uint64, err error) {
 		// Look for octal, hex prefix.
 		switch {
 		case s[0] == '0' && len(s) > 1 && (s[1] == 'x' || s[1] == 'X'):
-			base = 16
-			s = s[2:]
-			if len(s) < 1 {
+			if len(s) < 3 {
 				err = ErrSyntax
 				goto Error
 			}
+			base = 16
+			i = 2
 		case s[0] == '0':
 			base = 8
+			i = 1
 		default:
 			base = 10
 		}
@@ -82,11 +77,20 @@ func ParseUint(s string, base int, bitSize int) (n uint64, err error) {
 		goto Error
 	}
 
-	n = 0
-	cutoff = cutoff64(base)
+	// Cutoff is the smallest number such that cutoff*base > maxUint64.
+	// Use compile-time constants for common cases.
+	switch base {
+	case 10:
+		cutoff = maxUint64/10 + 1
+	case 16:
+		cutoff = maxUint64/16 + 1
+	default:
+		cutoff = maxUint64/uint64(base) + 1
+	}
+
 	maxVal = 1<<uint(bitSize) - 1
 
-	for i := 0; i < len(s); i++ {
+	for ; i < len(s); i++ {
 		var v byte
 		d := s[i]
 		switch {
@@ -101,7 +105,7 @@ func ParseUint(s string, base int, bitSize int) (n uint64, err error) {
 			err = ErrSyntax
 			goto Error
 		}
-		if int(v) >= base {
+		if v >= byte(base) {
 			n = 0
 			err = ErrSyntax
 			goto Error
@@ -109,7 +113,7 @@ func ParseUint(s string, base int, bitSize int) (n uint64, err error) {
 
 		if n >= cutoff {
 			// n*base overflows
-			n = 1<<64 - 1
+			n = maxUint64
 			err = ErrRange
 			goto Error
 		}
@@ -118,7 +122,7 @@ func ParseUint(s string, base int, bitSize int) (n uint64, err error) {
 		n1 := n + uint64(v)
 		if n1 < n || n1 > maxVal {
 			// n+v overflows
-			n = 1<<64 - 1
+			n = maxUint64
 			err = ErrRange
 			goto Error
 		}
@@ -128,7 +132,7 @@ func ParseUint(s string, base int, bitSize int) (n uint64, err error) {
 	return n, nil
 
 Error:
-	return n, &NumError{"ParseUint", s0, err}
+	return n, &NumError{"ParseUint", s, err}
 }
 
 // ParseInt interprets a string s in the given base (2 to 36) and
diff --git a/src/strconv/atoi_test.go b/src/strconv/atoi_test.go
index 9407573..bd6a6a0 100644
--- a/src/strconv/atoi_test.go
+++ b/src/strconv/atoi_test.go
@@ -33,12 +33,16 @@ var atoui64tests = []atoui64Test{
 var btoui64tests = []atoui64Test{
 	{"", 0, ErrSyntax},
 	{"0", 0, nil},
+	{"0x", 0, ErrSyntax},
+	{"0X", 0, ErrSyntax},
 	{"1", 1, nil},
 	{"12345", 12345, nil},
 	{"012345", 012345, nil},
 	{"0x12345", 0x12345, nil},
 	{"0X12345", 0x12345, nil},
 	{"12345x", 0, ErrSyntax},
+	{"0xabcdefg123", 0, ErrSyntax},
+	{"123456789abc", 0, ErrSyntax},
 	{"98765432100", 98765432100, nil},
 	{"18446744073709551615", 1<<64 - 1, nil},
 	{"18446744073709551616", 1<<64 - 1, ErrRange},
@@ -77,28 +81,61 @@ var atoi64tests = []atoi64Test{
 	{"-9223372036854775809", -1 << 63, ErrRange},
 }
 
-var btoi64tests = []atoi64Test{
-	{"", 0, ErrSyntax},
-	{"0", 0, nil},
-	{"-0", 0, nil},
-	{"1", 1, nil},
-	{"-1", -1, nil},
-	{"12345", 12345, nil},
-	{"-12345", -12345, nil},
-	{"012345", 012345, nil},
-	{"-012345", -012345, nil},
-	{"0x12345", 0x12345, nil},
-	{"-0X12345", -0x12345, nil},
-	{"12345x", 0, ErrSyntax},
-	{"-12345x", 0, ErrSyntax},
-	{"98765432100", 98765432100, nil},
-	{"-98765432100", -98765432100, nil},
-	{"9223372036854775807", 1<<63 - 1, nil},
-	{"-9223372036854775807", -(1<<63 - 1), nil},
-	{"9223372036854775808", 1<<63 - 1, ErrRange},
-	{"-9223372036854775808", -1 << 63, nil},
-	{"9223372036854775809", 1<<63 - 1, ErrRange},
-	{"-9223372036854775809", -1 << 63, ErrRange},
+type btoi64Test struct {
+	in   string
+	base int
+	out  int64
+	err  error
+}
+
+var btoi64tests = []btoi64Test{
+	{"", 0, 0, ErrSyntax},
+	{"0", 0, 0, nil},
+	{"-0", 0, 0, nil},
+	{"1", 0, 1, nil},
+	{"-1", 0, -1, nil},
+	{"12345", 0, 12345, nil},
+	{"-12345", 0, -12345, nil},
+	{"012345", 0, 012345, nil},
+	{"-012345", 0, -012345, nil},
+	{"0x12345", 0, 0x12345, nil},
+	{"-0X12345", 0, -0x12345, nil},
+	{"12345x", 0, 0, ErrSyntax},
+	{"-12345x", 0, 0, ErrSyntax},
+	{"98765432100", 0, 98765432100, nil},
+	{"-98765432100", 0, -98765432100, nil},
+	{"9223372036854775807", 0, 1<<63 - 1, nil},
+	{"-9223372036854775807", 0, -(1<<63 - 1), nil},
+	{"9223372036854775808", 0, 1<<63 - 1, ErrRange},
+	{"-9223372036854775808", 0, -1 << 63, nil},
+	{"9223372036854775809", 0, 1<<63 - 1, ErrRange},
+	{"-9223372036854775809", 0, -1 << 63, ErrRange},
+
+	// other bases
+	{"g", 17, 16, nil},
+	{"10", 25, 25, nil},
+	{"holycow", 35, (((((17*35+24)*35+21)*35+34)*35+12)*35+24)*35 + 32, nil},
+	{"holycow", 36, (((((17*36+24)*36+21)*36+34)*36+12)*36+24)*36 + 32, nil},
+
+	// base 2
+	{"0", 2, 0, nil},
+	{"-1", 2, -1, nil},
+	{"1010", 2, 10, nil},
+	{"1000000000000000", 2, 1 << 15, nil},
+	{"111111111111111111111111111111111111111111111111111111111111111", 2, 1<<63 - 1, nil},
+	{"1000000000000000000000000000000000000000000000000000000000000000", 2, 1<<63 - 1, ErrRange},
+	{"-1000000000000000000000000000000000000000000000000000000000000000", 2, -1 << 63, nil},
+	{"-1000000000000000000000000000000000000000000000000000000000000001", 2, -1 << 63, ErrRange},
+
+	// base 8
+	{"-10", 8, -8, nil},
+	{"57635436545", 8, 057635436545, nil},
+	{"100000000", 8, 1 << 24, nil},
+
+	// base 16
+	{"10", 16, 16, nil},
+	{"-123456789abcdef", 16, -0x123456789abcdef, nil},
+	{"7fffffffffffffff", 16, 1<<63 - 1, nil},
 }
 
 type atoui32Test struct {
@@ -234,7 +271,7 @@ func TestParseInt64(t *testing.T) {
 func TestParseInt64Base(t *testing.T) {
 	for i := range btoi64tests {
 		test := &btoi64tests[i]
-		out, err := ParseInt(test.in, 0, 64)
+		out, err := ParseInt(test.in, test.base, 64)
 		if test.out != out || !reflect.DeepEqual(test.err, err) {
 			t.Errorf("ParseInt(%q) = %v, %v want %v, %v",
 				test.in, out, err, test.out, test.err)
diff --git a/src/strconv/decimal.go b/src/strconv/decimal.go
index 4260128..5252d6e 100644
--- a/src/strconv/decimal.go
+++ b/src/strconv/decimal.go
@@ -12,7 +12,7 @@
 package strconv
 
 type decimal struct {
-	d     [800]byte // digits
+	d     [800]byte // digits, big-endian representation
 	nd    int       // number of digits used
 	dp    int       // decimal point
 	neg   bool
@@ -102,16 +102,17 @@ func (a *decimal) Assign(v uint64) {
 }
 
 // Maximum shift that we can do in one pass without overflow.
-// Signed int has 31 bits, and we have to be able to accommodate 9<<k.
-const maxShift = 27
+// A uint has 32 or 64 bits, and we have to be able to accommodate 9<<k.
+const uintSize = 32 << (^uint(0) >> 63)
+const maxShift = uintSize - 4
 
-// Binary shift right (* 2) by k bits.  k <= maxShift to avoid overflow.
+// Binary shift right (/ 2) by k bits.  k <= maxShift to avoid overflow.
 func rightShift(a *decimal, k uint) {
 	r := 0 // read pointer
 	w := 0 // write pointer
 
 	// Pick up enough leading digits to cover first shift.
-	n := 0
+	var n uint
 	for ; n>>k == 0; r++ {
 		if r >= a.nd {
 			if n == 0 {
@@ -125,14 +126,14 @@ func rightShift(a *decimal, k uint) {
 			}
 			break
 		}
-		c := int(a.d[r])
+		c := uint(a.d[r])
 		n = n*10 + c - '0'
 	}
 	a.dp -= r - 1
 
 	// Pick up a digit, put down a digit.
 	for ; r < a.nd; r++ {
-		c := int(a.d[r])
+		c := uint(a.d[r])
 		dig := n >> k
 		n -= dig << k
 		a.d[w] = byte(dig + '0')
@@ -169,50 +170,84 @@ func rightShift(a *decimal, k uint) {
 
 type leftCheat struct {
 	delta  int    // number of new digits
-	cutoff string //   minus one digit if original < a.
+	cutoff string // minus one digit if original < a.
 }
 
 var leftcheats = []leftCheat{
 	// Leading digits of 1/2^i = 5^i.
 	// 5^23 is not an exact 64-bit floating point number,
 	// so have to use bc for the math.
+	// Go up to 60 to be large enough for 32bit and 64bit platforms.
 	/*
-		seq 27 | sed 's/^/5^/' | bc |
-		awk 'BEGIN{ print "\tleftCheat{ 0, \"\" }," }
+		seq 60 | sed 's/^/5^/' | bc |
+		awk 'BEGIN{ print "\t{ 0, \"\" }," }
 		{
 			log2 = log(2)/log(10)
-			printf("\tleftCheat{ %d, \"%s\" },\t// * %d\n",
+			printf("\t{ %d, \"%s\" },\t// * %d\n",
 				int(log2*NR+1), $0, 2**NR)
 		}'
 	*/
 	{0, ""},
-	{1, "5"},                   // * 2
-	{1, "25"},                  // * 4
-	{1, "125"},                 // * 8
-	{2, "625"},                 // * 16
-	{2, "3125"},                // * 32
-	{2, "15625"},               // * 64
-	{3, "78125"},               // * 128
-	{3, "390625"},              // * 256
-	{3, "1953125"},             // * 512
-	{4, "9765625"},             // * 1024
-	{4, "48828125"},            // * 2048
-	{4, "244140625"},           // * 4096
-	{4, "1220703125"},          // * 8192
-	{5, "6103515625"},          // * 16384
-	{5, "30517578125"},         // * 32768
-	{5, "152587890625"},        // * 65536
-	{6, "762939453125"},        // * 131072
-	{6, "3814697265625"},       // * 262144
-	{6, "19073486328125"},      // * 524288
-	{7, "95367431640625"},      // * 1048576
-	{7, "476837158203125"},     // * 2097152
-	{7, "2384185791015625"},    // * 4194304
-	{7, "11920928955078125"},   // * 8388608
-	{8, "59604644775390625"},   // * 16777216
-	{8, "298023223876953125"},  // * 33554432
-	{8, "1490116119384765625"}, // * 67108864
-	{9, "7450580596923828125"}, // * 134217728
+	{1, "5"},                                           // * 2
+	{1, "25"},                                          // * 4
+	{1, "125"},                                         // * 8
+	{2, "625"},                                         // * 16
+	{2, "3125"},                                        // * 32
+	{2, "15625"},                                       // * 64
+	{3, "78125"},                                       // * 128
+	{3, "390625"},                                      // * 256
+	{3, "1953125"},                                     // * 512
+	{4, "9765625"},                                     // * 1024
+	{4, "48828125"},                                    // * 2048
+	{4, "244140625"},                                   // * 4096
+	{4, "1220703125"},                                  // * 8192
+	{5, "6103515625"},                                  // * 16384
+	{5, "30517578125"},                                 // * 32768
+	{5, "152587890625"},                                // * 65536
+	{6, "762939453125"},                                // * 131072
+	{6, "3814697265625"},                               // * 262144
+	{6, "19073486328125"},                              // * 524288
+	{7, "95367431640625"},                              // * 1048576
+	{7, "476837158203125"},                             // * 2097152
+	{7, "2384185791015625"},                            // * 4194304
+	{7, "11920928955078125"},                           // * 8388608
+	{8, "59604644775390625"},                           // * 16777216
+	{8, "298023223876953125"},                          // * 33554432
+	{8, "1490116119384765625"},                         // * 67108864
+	{9, "7450580596923828125"},                         // * 134217728
+	{9, "37252902984619140625"},                        // * 268435456
+	{9, "186264514923095703125"},                       // * 536870912
+	{10, "931322574615478515625"},                      // * 1073741824
+	{10, "4656612873077392578125"},                     // * 2147483648
+	{10, "23283064365386962890625"},                    // * 4294967296
+	{10, "116415321826934814453125"},                   // * 8589934592
+	{11, "582076609134674072265625"},                   // * 17179869184
+	{11, "2910383045673370361328125"},                  // * 34359738368
+	{11, "14551915228366851806640625"},                 // * 68719476736
+	{12, "72759576141834259033203125"},                 // * 137438953472
+	{12, "363797880709171295166015625"},                // * 274877906944
+	{12, "1818989403545856475830078125"},               // * 549755813888
+	{13, "9094947017729282379150390625"},               // * 1099511627776
+	{13, "45474735088646411895751953125"},              // * 2199023255552
+	{13, "227373675443232059478759765625"},             // * 4398046511104
+	{13, "1136868377216160297393798828125"},            // * 8796093022208
+	{14, "5684341886080801486968994140625"},            // * 17592186044416
+	{14, "28421709430404007434844970703125"},           // * 35184372088832
+	{14, "142108547152020037174224853515625"},          // * 70368744177664
+	{15, "710542735760100185871124267578125"},          // * 140737488355328
+	{15, "3552713678800500929355621337890625"},         // * 281474976710656
+	{15, "17763568394002504646778106689453125"},        // * 562949953421312
+	{16, "88817841970012523233890533447265625"},        // * 1125899906842624
+	{16, "444089209850062616169452667236328125"},       // * 2251799813685248
+	{16, "2220446049250313080847263336181640625"},      // * 4503599627370496
+	{16, "11102230246251565404236316680908203125"},     // * 9007199254740992
+	{17, "55511151231257827021181583404541015625"},     // * 18014398509481984
+	{17, "277555756156289135105907917022705078125"},    // * 36028797018963968
+	{17, "1387778780781445675529539585113525390625"},   // * 72057594037927936
+	{18, "6938893903907228377647697925567626953125"},   // * 144115188075855872
+	{18, "34694469519536141888238489627838134765625"},  // * 288230376151711744
+	{18, "173472347597680709441192448139190673828125"}, // * 576460752303423488
+	{19, "867361737988403547205962240695953369140625"}, // * 1152921504606846976
 }
 
 // Is the leading prefix of b lexicographically less than s?
@@ -228,7 +263,7 @@ func prefixIsLessThan(b []byte, s string) bool {
 	return false
 }
 
-// Binary shift left (/ 2) by k bits.  k <= maxShift to avoid overflow.
+// Binary shift left (* 2) by k bits.  k <= maxShift to avoid overflow.
 func leftShift(a *decimal, k uint) {
 	delta := leftcheats[k].delta
 	if prefixIsLessThan(a.d[0:a.nd], leftcheats[k].cutoff) {
@@ -237,11 +272,11 @@ func leftShift(a *decimal, k uint) {
 
 	r := a.nd         // read index
 	w := a.nd + delta // write index
-	n := 0
 
 	// Pick up a digit, put down a digit.
+	var n uint
 	for r--; r >= 0; r-- {
-		n += (int(a.d[r]) - '0') << k
+		n += (uint(a.d[r]) - '0') << k
 		quo := n / 10
 		rem := n - 10*quo
 		w--
diff --git a/src/strconv/doc.go b/src/strconv/doc.go
new file mode 100644
index 0000000..7bc1e27
--- /dev/null
+++ b/src/strconv/doc.go
@@ -0,0 +1,57 @@
+// 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 strconv implements conversions to and from string representations
+// of basic data types.
+//
+// Numeric Conversions
+//
+// The most common numeric conversions are Atoi (string to int) and Itoa (int to string).
+//
+//	i, err := strconv.Atoi("-42")
+//	s := strconv.Itoa(-42)
+//
+// These assume decimal and the Go int type.
+//
+// ParseBool, ParseFloat, ParseInt, and ParseUint convert strings to values:
+//
+//	b, err := strconv.ParseBool("true")
+//	f, err := strconv.ParseFloat("3.1415", 64)
+//	i, err := strconv.ParseInt("-42", 10, 64)
+//	u, err := strconv.ParseUint("42", 10, 64)
+//
+// The parse functions return the widest type (float64, int64, and uint64),
+// but if the size argument specifies a narrower width the result can be
+// converted to that narrower type without data loss:
+//
+//	s := "2147483647" // biggest int32
+//	i64, err := strconv.ParseInt(s, 10, 32)
+//	...
+//	i := int32(i64)
+//
+// FormatBool, FormatFloat, FormatInt, and FormatUint convert values to strings:
+//
+// 	s := strconv.FormatBool(true)
+// 	s := strconv.FormatFloat(3.1415, 'E', -1, 64)
+// 	s := strconv.FormatInt(-42, 16)
+// 	s := strconv.FormatUint(42, 16)
+//
+// AppendBool, AppendFloat, AppendInt, and AppendUint are similar but
+// append the formatted value to a destination slice.
+//
+// String Conversions
+//
+// Quote and QuoteToASCII convert strings to quoted Go string literals.
+// The latter guarantees that the result is an ASCII string, by escaping
+// any non-ASCII Unicode with \u:
+//
+//	q := Quote("Hello, 世界")
+//	q := QuoteToASCII("Hello, 世界")
+//
+// QuoteRune and QuoteRuneToASCII are similar but accept runes and
+// return quoted Go rune literals.
+//
+// Unquote and UnquoteChar unquote Go string and rune literals.
+//
+package strconv
diff --git a/src/strconv/example_test.go b/src/strconv/example_test.go
new file mode 100644
index 0000000..01fbbc0
--- /dev/null
+++ b/src/strconv/example_test.go
@@ -0,0 +1,338 @@
+// 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 strconv_test
+
+import (
+	"fmt"
+	"log"
+	"strconv"
+)
+
+func ExampleAppendBool() {
+	b := []byte("bool:")
+	b = strconv.AppendBool(b, true)
+	fmt.Println(string(b))
+
+	// Output:
+	// bool:true
+}
+
+func ExampleAppendFloat() {
+	b32 := []byte("float32:")
+	b32 = strconv.AppendFloat(b32, 3.1415926535, 'E', -1, 32)
+	fmt.Println(string(b32))
+
+	b64 := []byte("float64:")
+	b64 = strconv.AppendFloat(b64, 3.1415926535, 'E', -1, 64)
+	fmt.Println(string(b64))
+
+	// Output:
+	// float32:3.1415927E+00
+	// float64:3.1415926535E+00
+}
+
+func ExampleAppendInt() {
+	b10 := []byte("int (base 10):")
+	b10 = strconv.AppendInt(b10, -42, 10)
+	fmt.Println(string(b10))
+
+	b16 := []byte("int (base 16):")
+	b16 = strconv.AppendInt(b16, -42, 16)
+	fmt.Println(string(b16))
+
+	// Output:
+	// int (base 10):-42
+	// int (base 16):-2a
+}
+
+func ExampleAppendQuote() {
+	b := []byte("quote:")
+	b = strconv.AppendQuote(b, `"Fran & Freddie's Diner"`)
+	fmt.Println(string(b))
+
+	// Output:
+	// quote:"\"Fran & Freddie's Diner\""
+}
+
+func ExampleAppendQuoteRune() {
+	b := []byte("rune:")
+	b = strconv.AppendQuoteRune(b, '☺')
+	fmt.Println(string(b))
+
+	// Output:
+	// rune:'☺'
+}
+
+func ExampleAppendQuoteRuneToASCII() {
+	b := []byte("rune (ascii):")
+	b = strconv.AppendQuoteRuneToASCII(b, '☺')
+	fmt.Println(string(b))
+
+	// Output:
+	// rune (ascii):'\u263a'
+}
+
+func ExampleAppendQuoteToASCII() {
+	b := []byte("quote (ascii):")
+	b = strconv.AppendQuoteToASCII(b, `"Fran & Freddie's Diner"`)
+	fmt.Println(string(b))
+
+	// Output:
+	// quote (ascii):"\"Fran & Freddie's Diner\""
+}
+
+func ExampleAppendUint() {
+	b10 := []byte("uint (base 10):")
+	b10 = strconv.AppendUint(b10, 42, 10)
+	fmt.Println(string(b10))
+
+	b16 := []byte("uint (base 16):")
+	b16 = strconv.AppendUint(b16, 42, 16)
+	fmt.Println(string(b16))
+
+	// Output:
+	// uint (base 10):42
+	// uint (base 16):2a
+}
+
+func ExampleAtoi() {
+	v := "10"
+	if s, err := strconv.Atoi(v); err == nil {
+		fmt.Printf("%T, %v", s, s)
+	}
+
+	// Output:
+	// int, 10
+}
+
+func ExampleCanBackquote() {
+	fmt.Println(strconv.CanBackquote("Fran & Freddie's Diner ☺"))
+	fmt.Println(strconv.CanBackquote("`can't backquote this`"))
+
+	// Output:
+	// true
+	// false
+}
+
+func ExampleFormatBool() {
+	v := true
+	s := strconv.FormatBool(v)
+	fmt.Printf("%T, %v\n", s, s)
+
+	// Output:
+	// string, true
+}
+
+func ExampleFormatFloat() {
+	v := 3.1415926535
+
+	s32 := strconv.FormatFloat(v, 'E', -1, 32)
+	fmt.Printf("%T, %v\n", s32, s32)
+
+	s64 := strconv.FormatFloat(v, 'E', -1, 64)
+	fmt.Printf("%T, %v\n", s64, s64)
+
+	// Output:
+	// string, 3.1415927E+00
+	// string, 3.1415926535E+00
+}
+
+func ExampleFormatInt() {
+	v := int64(-42)
+
+	s10 := strconv.FormatInt(v, 10)
+	fmt.Printf("%T, %v\n", s10, s10)
+
+	s16 := strconv.FormatInt(v, 16)
+	fmt.Printf("%T, %v\n", s16, s16)
+
+	// Output:
+	// string, -42
+	// string, -2a
+}
+
+func ExampleFormatUint() {
+	v := uint64(42)
+
+	s10 := strconv.FormatUint(v, 10)
+	fmt.Printf("%T, %v\n", s10, s10)
+
+	s16 := strconv.FormatUint(v, 16)
+	fmt.Printf("%T, %v\n", s16, s16)
+
+	// Output:
+	// string, 42
+	// string, 2a
+}
+
+func ExampleIsPrint() {
+	c := strconv.IsPrint('\u263a')
+	fmt.Println(c)
+
+	bel := strconv.IsPrint('\007')
+	fmt.Println(bel)
+
+	// Output:
+	// true
+	// false
+}
+
+func ExampleItoa() {
+	i := 10
+	s := strconv.Itoa(i)
+	fmt.Printf("%T, %v\n", s, s)
+
+	// Output:
+	// string, 10
+}
+
+func ExampleParseBool() {
+	v := "true"
+	if s, err := strconv.ParseBool(v); err == nil {
+		fmt.Printf("%T, %v\n", s, s)
+	}
+
+	// Output:
+	// bool, true
+}
+
+func ExampleParseFloat() {
+	v := "3.1415926535"
+	if s, err := strconv.ParseFloat(v, 32); err == nil {
+		fmt.Printf("%T, %v\n", s, s)
+	}
+	if s, err := strconv.ParseFloat(v, 64); err == nil {
+		fmt.Printf("%T, %v\n", s, s)
+	}
+
+	// Output:
+	// float64, 3.1415927410125732
+	// float64, 3.1415926535
+}
+
+func ExampleParseInt() {
+	v32 := "-354634382"
+	if s, err := strconv.ParseInt(v32, 10, 32); err == nil {
+		fmt.Printf("%T, %v\n", s, s)
+	}
+	if s, err := strconv.ParseInt(v32, 16, 32); err == nil {
+		fmt.Printf("%T, %v\n", s, s)
+	}
+
+	v64 := "-3546343826724305832"
+	if s, err := strconv.ParseInt(v64, 10, 64); err == nil {
+		fmt.Printf("%T, %v\n", s, s)
+	}
+	if s, err := strconv.ParseInt(v64, 16, 64); err == nil {
+		fmt.Printf("%T, %v\n", s, s)
+	}
+
+	// Output:
+	// int64, -354634382
+	// int64, -3546343826724305832
+}
+
+func ExampleParseUint() {
+	v := "42"
+	if s, err := strconv.ParseUint(v, 10, 32); err == nil {
+		fmt.Printf("%T, %v\n", s, s)
+	}
+	if s, err := strconv.ParseUint(v, 10, 64); err == nil {
+		fmt.Printf("%T, %v\n", s, s)
+	}
+
+	// Output:
+	// uint64, 42
+	// uint64, 42
+}
+
+func ExampleQuote() {
+	s := strconv.Quote(`"Fran & Freddie's Diner	☺"`)
+	fmt.Println(s)
+
+	// Output:
+	// "\"Fran & Freddie's Diner\t☺\""
+}
+
+func ExampleQuoteRune() {
+	s := strconv.QuoteRune('☺')
+	fmt.Println(s)
+
+	// Output:
+	// '☺'
+}
+
+func ExampleQuoteRuneToASCII() {
+	s := strconv.QuoteRuneToASCII('☺')
+	fmt.Println(s)
+
+	// Output:
+	// '\u263a'
+}
+
+func ExampleQuoteToASCII() {
+	s := strconv.QuoteToASCII(`"Fran & Freddie's Diner	☺"`)
+	fmt.Println(s)
+
+	// Output:
+	// "\"Fran & Freddie's Diner\t\u263a\""
+}
+
+func ExampleUnquote() {
+	test := func(s string) {
+		t, err := strconv.Unquote(s)
+		if err != nil {
+			fmt.Printf("Unquote(%#v): %v\n", s, err)
+		} else {
+			fmt.Printf("Unquote(%#v) = %v\n", s, t)
+		}
+	}
+
+	s := `\"Fran & Freddie's Diner\t\u263a\"\"`
+	// If the string doesn't have quotes, it can't be unquoted.
+	test(s) // invalid syntax
+	test("`" + s + "`")
+	test(`"` + s + `"`)
+	test(`'\u263a'`)
+
+	// Output:
+	// Unquote("\\\"Fran & Freddie's Diner\\t\\u263a\\\"\\\""): invalid syntax
+	// Unquote("`\\\"Fran & Freddie's Diner\\t\\u263a\\\"\\\"`") = \"Fran & Freddie's Diner\t\u263a\"\"
+	// Unquote("\"\\\"Fran & Freddie's Diner\\t\\u263a\\\"\\\"\"") = "Fran & Freddie's Diner	☺""
+	// Unquote("'\\u263a'") = ☺
+}
+
+func ExampleUnquoteChar() {
+	v, mb, t, err := strconv.UnquoteChar(`\"Fran & Freddie's Diner\"`, '"')
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	fmt.Println("value:", string(v))
+	fmt.Println("multibyte:", mb)
+	fmt.Println("tail:", t)
+
+	// Output:
+	// value: "
+	// multibyte: false
+	// tail: Fran & Freddie's Diner\"
+}
+
+func ExampleNumError() {
+	str := "Not a number"
+	if _, err := strconv.ParseFloat(str, 64); err != nil {
+		e := err.(*strconv.NumError)
+		fmt.Println("Func:", e.Func)
+		fmt.Println("Num:", e.Num)
+		fmt.Println("Err:", e.Err)
+		fmt.Println(err)
+	}
+
+	// Output:
+	// Func: ParseFloat
+	// Num: Not a number
+	// Err: invalid syntax
+	// strconv.ParseFloat: parsing "Not a number": invalid syntax
+}
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 @@ var uint64pow10 = [...]uint64{
 }
 
 // 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 1a9c41b..468c37f 100644
--- a/src/strconv/ftoa.go
+++ b/src/strconv/ftoa.go
@@ -47,7 +47,7 @@ func FormatFloat(f float64, fmt byte, prec, bitSize int) string {
 
 // 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)
 }
 
@@ -119,7 +119,7 @@ func genericFtoa(dst []byte, val float64, fmt byte, prec, bitSize int) []byte {
 		// Precision for shortest representation mode.
 		switch fmt {
 		case 'e', 'E':
-			prec = digs.nd - 1
+			prec = max(digs.nd-1, 0)
 		case 'f':
 			prec = max(digs.nd-digs.dp, 0)
 		case 'g', 'G':
@@ -223,9 +223,8 @@ func formatDigits(dst []byte, shortest bool, neg bool, digs decimalSlice, prec i
 	return append(dst, '%', fmt)
 }
 
-// Round d (= mant * 2^exp) to the shortest number of digits
-// that will let the original floating point value be precisely
-// reconstructed.  Size is original floating point size (64 or 32).
+// roundShortest rounds d (= mant * 2^exp) to the shortest number of digits
+// that will let the original floating point value be precisely reconstructed.
 func roundShortest(d *decimal, mant uint64, exp int, flt *floatInfo) {
 	// If mantissa is zero, the number is zero; stop now.
 	if mant == 0 {
@@ -348,14 +347,13 @@ func fmtE(dst []byte, neg bool, d decimalSlice, prec int, fmt byte) []byte {
 	if prec > 0 {
 		dst = append(dst, '.')
 		i := 1
-		m := d.nd + prec + 1 - max(d.nd, prec+1)
-		for i < m {
-			dst = append(dst, d.d[i])
-			i++
+		m := min(d.nd, prec+1)
+		if i < m {
+			dst = append(dst, d.d[i:m]...)
+			i = m
 		}
-		for i <= prec {
+		for ; i <= prec; i++ {
 			dst = append(dst, '0')
-			i++
 		}
 	}
 
@@ -373,27 +371,16 @@ func fmtE(dst []byte, neg bool, d decimalSlice, prec int, fmt byte) []byte {
 	}
 	dst = append(dst, ch)
 
-	// dddd
-	var buf [3]byte
-	i := len(buf)
-	for exp >= 10 {
-		i--
-		buf[i] = byte(exp%10 + '0')
-		exp /= 10
+	// dd or ddd
+	switch {
+	case exp < 10:
+		dst = append(dst, '0', byte(exp)+'0')
+	case exp < 100:
+		dst = append(dst, byte(exp/10)+'0', byte(exp%10)+'0')
+	default:
+		dst = append(dst, byte(exp/100)+'0', byte(exp/10)%10+'0', byte(exp%10)+'0')
 	}
-	// exp < 10
-	i--
-	buf[i] = byte(exp + '0')
 
-	switch i {
-	case 0:
-		dst = append(dst, buf[0], buf[1], buf[2])
-	case 1:
-		dst = append(dst, buf[1], buf[2])
-	case 2:
-		// leading zeroes
-		dst = append(dst, '0', buf[2])
-	}
 	return dst
 }
 
@@ -406,11 +393,9 @@ func fmtF(dst []byte, neg bool, d decimalSlice, prec int) []byte {
 
 	// integer, padded with zeros as needed.
 	if d.dp > 0 {
-		var i int
-		for i = 0; i < d.dp && i < d.nd; i++ {
-			dst = append(dst, d.d[i])
-		}
-		for ; i < d.dp; i++ {
+		m := min(d.nd, d.dp)
+		dst = append(dst, d.d[:m]...)
+		for ; m < d.dp; m++ {
 			dst = append(dst, '0')
 		}
 	} else {
@@ -432,39 +417,34 @@ func fmtF(dst []byte, neg bool, d decimalSlice, prec int) []byte {
 	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
+	// sign
+	if neg {
+		dst = append(dst, '-')
 	}
-	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
+
+	// mantissa
+	dst, _ = formatBits(dst, mant, 10, false, true)
+
+	// p
+	dst = append(dst, 'p')
+
+	// ±exponent
+	exp -= int(flt.mantbits)
+	if exp >= 0 {
+		dst = append(dst, '+')
 	}
-	if neg {
-		w--
-		buf[w] = '-'
+	dst, _ = formatBits(dst, uint64(exp), 10, exp < 0, true)
+
+	return dst
+}
+
+func min(a, b int) int {
+	if a < b {
+		return a
 	}
-	return append(dst, buf[w:]...)
+	return b
 }
 
 func max(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 BenchmarkAppendFloatNegExp(b *testing.B)  { benchmarkAppendFloat(b, -5.11e-
 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/strconv/isprint.go b/src/strconv/isprint.go
index 80738ed..0cf363c 100644
--- a/src/strconv/isprint.go
+++ b/src/strconv/isprint.go
@@ -7,7 +7,7 @@
 
 package strconv
 
-// (468+138+67)*2 + (326)*4 = 2650 bytes
+// (470+136+73)*2 + (342)*4 = 2726 bytes
 
 var isPrint16 = []uint16{
 	0x0020, 0x007e,
@@ -26,8 +26,8 @@ var isPrint16 = []uint16{
 	0x0800, 0x082d,
 	0x0830, 0x085b,
 	0x085e, 0x085e,
-	0x08a0, 0x08b2,
-	0x08e4, 0x098c,
+	0x08a0, 0x08b4,
+	0x08e3, 0x098c,
 	0x098f, 0x0990,
 	0x0993, 0x09b2,
 	0x09b6, 0x09b9,
@@ -51,6 +51,7 @@ var isPrint16 = []uint16{
 	0x0ad0, 0x0ad0,
 	0x0ae0, 0x0ae3,
 	0x0ae6, 0x0af1,
+	0x0af9, 0x0af9,
 	0x0b01, 0x0b0c,
 	0x0b0f, 0x0b10,
 	0x0b13, 0x0b39,
@@ -73,7 +74,7 @@ var isPrint16 = []uint16{
 	0x0be6, 0x0bfa,
 	0x0c00, 0x0c39,
 	0x0c3d, 0x0c4d,
-	0x0c55, 0x0c59,
+	0x0c55, 0x0c5a,
 	0x0c60, 0x0c63,
 	0x0c66, 0x0c6f,
 	0x0c78, 0x0cb9,
@@ -84,7 +85,7 @@ var isPrint16 = []uint16{
 	0x0d01, 0x0d3a,
 	0x0d3d, 0x0d4e,
 	0x0d57, 0x0d57,
-	0x0d60, 0x0d63,
+	0x0d5f, 0x0d63,
 	0x0d66, 0x0d75,
 	0x0d79, 0x0d7f,
 	0x0d82, 0x0d96,
@@ -117,7 +118,8 @@ var isPrint16 = []uint16{
 	0x1318, 0x135a,
 	0x135d, 0x137c,
 	0x1380, 0x1399,
-	0x13a0, 0x13f4,
+	0x13a0, 0x13f5,
+	0x13f8, 0x13fd,
 	0x1400, 0x169c,
 	0x16a0, 0x16f8,
 	0x1700, 0x1714,
@@ -167,9 +169,9 @@ var isPrint16 = []uint16{
 	0x2030, 0x205e,
 	0x2070, 0x2071,
 	0x2074, 0x209c,
-	0x20a0, 0x20bd,
+	0x20a0, 0x20be,
 	0x20d0, 0x20f0,
-	0x2100, 0x2189,
+	0x2100, 0x218b,
 	0x2190, 0x23fa,
 	0x2400, 0x2426,
 	0x2440, 0x244a,
@@ -177,6 +179,7 @@ var isPrint16 = []uint16{
 	0x2b76, 0x2b95,
 	0x2b98, 0x2bb9,
 	0x2bbd, 0x2bd1,
+	0x2bec, 0x2bef,
 	0x2c00, 0x2cf3,
 	0x2cf9, 0x2d27,
 	0x2d2d, 0x2d2d,
@@ -193,19 +196,19 @@ var isPrint16 = []uint16{
 	0x3131, 0x31ba,
 	0x31c0, 0x31e3,
 	0x31f0, 0x4db5,
-	0x4dc0, 0x9fcc,
+	0x4dc0, 0x9fd5,
 	0xa000, 0xa48c,
 	0xa490, 0xa4c6,
 	0xa4d0, 0xa62b,
 	0xa640, 0xa6f7,
 	0xa700, 0xa7ad,
-	0xa7b0, 0xa7b1,
+	0xa7b0, 0xa7b7,
 	0xa7f7, 0xa82b,
 	0xa830, 0xa839,
 	0xa840, 0xa877,
 	0xa880, 0xa8c4,
 	0xa8ce, 0xa8d9,
-	0xa8e0, 0xa8fb,
+	0xa8e0, 0xa8fd,
 	0xa900, 0xa953,
 	0xa95f, 0xa97c,
 	0xa980, 0xa9d9,
@@ -217,9 +220,8 @@ var isPrint16 = []uint16{
 	0xab01, 0xab06,
 	0xab09, 0xab0e,
 	0xab11, 0xab16,
-	0xab20, 0xab5f,
-	0xab64, 0xab65,
-	0xabc0, 0xabed,
+	0xab20, 0xab65,
+	0xab70, 0xabed,
 	0xabf0, 0xabf9,
 	0xac00, 0xd7a3,
 	0xd7b0, 0xd7c6,
@@ -234,8 +236,7 @@ var isPrint16 = []uint16{
 	0xfd92, 0xfdc7,
 	0xfdf0, 0xfdfd,
 	0xfe00, 0xfe19,
-	0xfe20, 0xfe2d,
-	0xfe30, 0xfe6b,
+	0xfe20, 0xfe6b,
 	0xfe70, 0xfefc,
 	0xff01, 0xffbe,
 	0xffc2, 0xffc7,
@@ -370,8 +371,6 @@ var isNotPrint16 = []uint16{
 	0x318f,
 	0x321f,
 	0x32ff,
-	0xa69e,
-	0xa78f,
 	0xa9ce,
 	0xa9ff,
 	0xab27,
@@ -418,12 +417,13 @@ var isPrint32 = []uint32{
 	0x01083c, 0x01083c,
 	0x01083f, 0x01089e,
 	0x0108a7, 0x0108af,
-	0x010900, 0x01091b,
+	0x0108e0, 0x0108f5,
+	0x0108fb, 0x01091b,
 	0x01091f, 0x010939,
 	0x01093f, 0x01093f,
 	0x010980, 0x0109b7,
-	0x0109be, 0x0109bf,
-	0x010a00, 0x010a06,
+	0x0109bc, 0x0109cf,
+	0x0109d2, 0x010a06,
 	0x010a0c, 0x010a33,
 	0x010a38, 0x010a3a,
 	0x010a3f, 0x010a47,
@@ -438,6 +438,9 @@ var isPrint32 = []uint32{
 	0x010b99, 0x010b9c,
 	0x010ba9, 0x010baf,
 	0x010c00, 0x010c48,
+	0x010c80, 0x010cb2,
+	0x010cc0, 0x010cf2,
+	0x010cfa, 0x010cff,
 	0x010e60, 0x010e7e,
 	0x011000, 0x01104d,
 	0x011052, 0x01106f,
@@ -446,19 +449,19 @@ var isPrint32 = []uint32{
 	0x0110f0, 0x0110f9,
 	0x011100, 0x011143,
 	0x011150, 0x011176,
-	0x011180, 0x0111c8,
-	0x0111cd, 0x0111cd,
-	0x0111d0, 0x0111da,
-	0x0111e1, 0x0111f4,
+	0x011180, 0x0111cd,
+	0x0111d0, 0x0111f4,
 	0x011200, 0x01123d,
+	0x011280, 0x0112a9,
 	0x0112b0, 0x0112ea,
 	0x0112f0, 0x0112f9,
-	0x011301, 0x01130c,
+	0x011300, 0x01130c,
 	0x01130f, 0x011310,
 	0x011313, 0x011339,
 	0x01133c, 0x011344,
 	0x011347, 0x011348,
 	0x01134b, 0x01134d,
+	0x011350, 0x011350,
 	0x011357, 0x011357,
 	0x01135d, 0x011363,
 	0x011366, 0x01136c,
@@ -466,17 +469,22 @@ var isPrint32 = []uint32{
 	0x011480, 0x0114c7,
 	0x0114d0, 0x0114d9,
 	0x011580, 0x0115b5,
-	0x0115b8, 0x0115c9,
+	0x0115b8, 0x0115dd,
 	0x011600, 0x011644,
 	0x011650, 0x011659,
 	0x011680, 0x0116b7,
 	0x0116c0, 0x0116c9,
+	0x011700, 0x011719,
+	0x01171d, 0x01172b,
+	0x011730, 0x01173f,
 	0x0118a0, 0x0118f2,
 	0x0118ff, 0x0118ff,
 	0x011ac0, 0x011af8,
-	0x012000, 0x012398,
+	0x012000, 0x012399,
 	0x012400, 0x012474,
+	0x012480, 0x012543,
 	0x013000, 0x01342e,
+	0x014400, 0x014646,
 	0x016800, 0x016a38,
 	0x016a40, 0x016a69,
 	0x016a6e, 0x016a6f,
@@ -497,7 +505,7 @@ var isPrint32 = []uint32{
 	0x01d000, 0x01d0f5,
 	0x01d100, 0x01d126,
 	0x01d129, 0x01d172,
-	0x01d17b, 0x01d1dd,
+	0x01d17b, 0x01d1e8,
 	0x01d200, 0x01d245,
 	0x01d300, 0x01d356,
 	0x01d360, 0x01d371,
@@ -508,7 +516,8 @@ var isPrint32 = []uint32{
 	0x01d50d, 0x01d546,
 	0x01d54a, 0x01d6a5,
 	0x01d6a8, 0x01d7cb,
-	0x01d7ce, 0x01d7ff,
+	0x01d7ce, 0x01da8b,
+	0x01da9b, 0x01daaf,
 	0x01e800, 0x01e8c4,
 	0x01e8c7, 0x01e8d6,
 	0x01ee00, 0x01ee24,
@@ -530,13 +539,7 @@ var isPrint32 = []uint32{
 	0x01f210, 0x01f23a,
 	0x01f240, 0x01f248,
 	0x01f250, 0x01f251,
-	0x01f300, 0x01f32c,
-	0x01f330, 0x01f37d,
-	0x01f380, 0x01f3ce,
-	0x01f3d4, 0x01f3f7,
-	0x01f400, 0x01f54a,
-	0x01f550, 0x01f642,
-	0x01f645, 0x01f6cf,
+	0x01f300, 0x01f6d0,
 	0x01f6e0, 0x01f6ec,
 	0x01f6f0, 0x01f6f3,
 	0x01f700, 0x01f773,
@@ -546,9 +549,13 @@ var isPrint32 = []uint32{
 	0x01f850, 0x01f859,
 	0x01f860, 0x01f887,
 	0x01f890, 0x01f8ad,
+	0x01f910, 0x01f918,
+	0x01f980, 0x01f984,
+	0x01f9c0, 0x01f9c0,
 	0x020000, 0x02a6d6,
 	0x02a700, 0x02b734,
 	0x02b740, 0x02b81d,
+	0x02b820, 0x02cea1,
 	0x02f800, 0x02fa1d,
 	0x0e0100, 0x0e01ef,
 }
@@ -562,12 +569,18 @@ var isNotPrint32 = []uint16{ // add 0x10000 to each entry
 	0x0809,
 	0x0836,
 	0x0856,
+	0x08f3,
 	0x0a04,
 	0x0a14,
 	0x0a18,
 	0x10bd,
 	0x1135,
+	0x11e0,
 	0x1212,
+	0x1287,
+	0x1289,
+	0x128e,
+	0x129e,
 	0x1304,
 	0x1329,
 	0x1331,
@@ -589,6 +602,7 @@ var isNotPrint32 = []uint16{ // add 0x10000 to each entry
 	0xd53f,
 	0xd545,
 	0xd551,
+	0xdaa0,
 	0xee04,
 	0xee20,
 	0xee23,
@@ -618,7 +632,6 @@ var isNotPrint32 = []uint16{ // add 0x10000 to each entry
 	0xf0c0,
 	0xf0d0,
 	0xf12f,
-	0xf4ff,
 	0xf57a,
 	0xf5a4,
 }
diff --git a/src/strconv/itoa.go b/src/strconv/itoa.go
index 67f17d8..e6f6303 100644
--- a/src/strconv/itoa.go
+++ b/src/strconv/itoa.go
@@ -40,9 +40,7 @@ func AppendUint(dst []byte, i uint64, base int) []byte {
 }
 
 const (
-	digits   = "0123456789abcdefghijklmnopqrstuvwxyz"
-	digits01 = "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"
-	digits10 = "0000000000111111111122222222223333333333444444444455555555556666666666777777777788888888889999999999"
+	digits = "0123456789abcdefghijklmnopqrstuvwxyz"
 )
 
 var shifts = [len(digits) + 1]uint{
@@ -74,23 +72,34 @@ func formatBits(dst []byte, u uint64, base int, neg, append_ bool) (d []byte, s
 
 	// convert bits
 	if base == 10 {
-		// common case: use constants for / and % because
-		// the compiler can optimize it into a multiply+shift,
-		// and unroll loop
-		for u >= 100 {
-			i -= 2
-			q := u / 100
-			j := uintptr(u - q*100)
-			a[i+1] = digits01[j]
-			a[i+0] = digits10[j]
-			u = q
+		// common case: use constants for / because
+		// the compiler can optimize it into a multiply+shift
+
+		if ^uintptr(0)>>32 == 0 {
+			for u > uint64(^uintptr(0)) {
+				q := u / 1e9
+				us := uintptr(u - q*1e9) // us % 1e9 fits into a uintptr
+				for j := 9; j > 0; j-- {
+					i--
+					qs := us / 10
+					a[i] = byte(us - qs*10 + '0')
+					us = qs
+				}
+				u = q
+			}
 		}
-		if u >= 10 {
+
+		// u guaranteed to fit into a uintptr
+		us := uintptr(u)
+		for us >= 10 {
 			i--
-			q := u / 10
-			a[i] = digits[uintptr(u-q*10)]
-			u = q
+			q := us / 10
+			a[i] = byte(us - q*10 + '0')
+			us = q
 		}
+		// u < 10
+		i--
+		a[i] = byte(us + '0')
 
 	} else if s := shifts[base]; s > 0 {
 		// base is power of 2: use shifts and masks instead of / and %
@@ -101,21 +110,24 @@ func formatBits(dst []byte, u uint64, base int, neg, append_ bool) (d []byte, s
 			a[i] = digits[uintptr(u)&m]
 			u >>= s
 		}
+		// u < base
+		i--
+		a[i] = digits[uintptr(u)]
 
 	} else {
 		// general case
 		b := uint64(base)
 		for u >= b {
 			i--
-			a[i] = digits[uintptr(u%b)]
-			u /= b
+			q := u / b
+			a[i] = digits[uintptr(u-q*b)]
+			u = q
 		}
+		// u < base
+		i--
+		a[i] = digits[uintptr(u)]
 	}
 
-	// u < base
-	i--
-	a[i] = digits[uintptr(u)]
-
 	// add sign, if any
 	if neg {
 		i--
diff --git a/src/strconv/itoa_test.go b/src/strconv/itoa_test.go
index e0213ae..48dc03e 100644
--- a/src/strconv/itoa_test.go
+++ b/src/strconv/itoa_test.go
@@ -51,6 +51,7 @@ var itob64tests = []itob64Test{
 	{-0x123456789abcdef, 16, "-123456789abcdef"},
 	{1<<63 - 1, 16, "7fffffffffffffff"},
 	{1<<63 - 1, 2, "111111111111111111111111111111111111111111111111111111111111111"},
+	{-1 << 63, 2, "-1000000000000000000000000000000000000000000000000000000000000000"},
 
 	{16, 17, "g"},
 	{25, 25, "10"},
diff --git a/src/strconv/quote_example_test.go b/src/strconv/quote_example_test.go
deleted file mode 100644
index 405a57e..0000000
--- a/src/strconv/quote_example_test.go
+++ /dev/null
@@ -1,35 +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 strconv_test
-
-import (
-	"fmt"
-	"strconv"
-)
-
-func ExampleUnquote() {
-	test := func(s string) {
-		t, err := strconv.Unquote(s)
-		if err != nil {
-			fmt.Printf("Unquote(%#v): %v\n", s, err)
-		} else {
-			fmt.Printf("Unquote(%#v) = %v\n", s, t)
-		}
-	}
-
-	s := `cafe\u0301`
-	// If the string doesn't have quotes, it can't be unquoted.
-	test(s) // invalid syntax
-	test("`" + s + "`")
-	test(`"` + s + `"`)
-
-	test(`'\u00e9'`)
-
-	// Output:
-	// Unquote("cafe\\u0301"): invalid syntax
-	// Unquote("`cafe\\u0301`") = cafe\u0301
-	// Unquote("\"cafe\\u0301\"") = café
-	// Unquote("'\\u00e9'") = é
-}
diff --git a/src/strings/compare.go b/src/strings/compare.go
new file mode 100644
index 0000000..b84ddde
--- /dev/null
+++ b/src/strings/compare.go
@@ -0,0 +1,28 @@
+// 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 strings
+
+// Compare returns an integer comparing two strings lexicographically.
+// The result will be 0 if a==b, -1 if a < b, and +1 if a > b.
+//
+// Compare is included only for symmetry with package bytes.
+// It is usually clearer and always faster to use the built-in
+// string comparison operators ==, <, >, and so on.
+func Compare(a, b string) int {
+	// NOTE(rsc): This function does NOT call the runtime cmpstring function,
+	// because we do not want to provide any performance justification for
+	// using strings.Compare. Basically no one should use strings.Compare.
+	// As the comment above says, it is here only for symmetry with package bytes.
+	// If performance is important, the compiler should be changed to recognize
+	// the pattern so that all code doing three-way comparisons, not just code
+	// using strings.Compare, can benefit.
+	if a == b {
+		return 0
+	}
+	if a < b {
+		return -1
+	}
+	return +1
+}
diff --git a/src/strings/compare_test.go b/src/strings/compare_test.go
new file mode 100644
index 0000000..68fc88e
--- /dev/null
+++ b/src/strings/compare_test.go
@@ -0,0 +1,98 @@
+// 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 strings_test
+
+// Derived from bytes/compare_test.go.
+// Benchmarks omitted since the underlying implementation is identical.
+
+import (
+	. "strings"
+	"testing"
+)
+
+var compareTests = []struct {
+	a, b string
+	i    int
+}{
+	{"", "", 0},
+	{"a", "", 1},
+	{"", "a", -1},
+	{"abc", "abc", 0},
+	{"ab", "abc", -1},
+	{"abc", "ab", 1},
+	{"x", "ab", 1},
+	{"ab", "x", -1},
+	{"x", "a", 1},
+	{"b", "x", -1},
+	// test runtime·memeq's chunked implementation
+	{"abcdefgh", "abcdefgh", 0},
+	{"abcdefghi", "abcdefghi", 0},
+	{"abcdefghi", "abcdefghj", -1},
+}
+
+func TestCompare(t *testing.T) {
+	for _, tt := range compareTests {
+		cmp := Compare(tt.a, tt.b)
+		if cmp != tt.i {
+			t.Errorf(`Compare(%q, %q) = %v`, tt.a, tt.b, cmp)
+		}
+	}
+}
+
+func TestCompareIdenticalString(t *testing.T) {
+	var s = "Hello Gophers!"
+	if Compare(s, s) != 0 {
+		t.Error("s != s")
+	}
+	if Compare(s, s[:1]) != 1 {
+		t.Error("s > s[:1] failed")
+	}
+}
+
+func TestCompareStrings(t *testing.T) {
+	n := 128
+	a := make([]byte, n+1)
+	b := make([]byte, n+1)
+	for len := 0; len < 128; len++ {
+		// randomish but deterministic data.  No 0 or 255.
+		for i := 0; i < len; i++ {
+			a[i] = byte(1 + 31*i%254)
+			b[i] = byte(1 + 31*i%254)
+		}
+		// data past the end is different
+		for i := len; i <= n; i++ {
+			a[i] = 8
+			b[i] = 9
+		}
+
+		cmp := Compare(string(a[:len]), string(b[:len]))
+		if cmp != 0 {
+			t.Errorf(`CompareIdentical(%d) = %d`, len, cmp)
+		}
+		if len > 0 {
+			cmp = Compare(string(a[:len-1]), string(b[:len]))
+			if cmp != -1 {
+				t.Errorf(`CompareAshorter(%d) = %d`, len, cmp)
+			}
+			cmp = Compare(string(a[:len]), string(b[:len-1]))
+			if cmp != 1 {
+				t.Errorf(`CompareBshorter(%d) = %d`, len, cmp)
+			}
+		}
+		for k := 0; k < len; k++ {
+			b[k] = a[k] - 1
+			cmp = Compare(string(a[:len]), string(b[:len]))
+			if cmp != 1 {
+				t.Errorf(`CompareAbigger(%d,%d) = %d`, len, k, cmp)
+			}
+			b[k] = a[k] + 1
+			cmp = Compare(string(a[:len]), string(b[:len]))
+			if cmp != -1 {
+				t.Errorf(`CompareBbigger(%d,%d) = %d`, len, k, cmp)
+			}
+			b[k] = a[k]
+		}
+	}
+}
diff --git a/src/strings/reader.go b/src/strings/reader.go
index 82df974..7a872fb 100644
--- a/src/strings/reader.go
+++ b/src/strings/reader.go
@@ -28,6 +28,12 @@ func (r *Reader) Len() int {
 	return int(int64(len(r.s)) - r.i)
 }
 
+// Size returns the original length of the underlying string.
+// Size is the number of bytes available for reading via ReadAt.
+// The returned value is always the same and is not affected by calls
+// to any other method.
+func (r *Reader) Size() int64 { return int64(len(r.s)) }
+
 func (r *Reader) Read(b []byte) (n int, err error) {
 	if len(b) == 0 {
 		return 0, nil
diff --git a/src/strings/reader_test.go b/src/strings/reader_test.go
index bee90eb..5003a37 100644
--- a/src/strings/reader_test.go
+++ b/src/strings/reader_test.go
@@ -8,6 +8,7 @@ import (
 	"bytes"
 	"fmt"
 	"io"
+	"io/ioutil"
 	"os"
 	"strings"
 	"sync"
@@ -157,3 +158,15 @@ func TestWriteTo(t *testing.T) {
 		}
 	}
 }
+
+// tests that Len is affected by reads, but Size is not.
+func TestReaderLenSize(t *testing.T) {
+	r := strings.NewReader("abc")
+	io.CopyN(ioutil.Discard, r, 1)
+	if r.Len() != 2 {
+		t.Errorf("Len = %d; want 2", r.Len())
+	}
+	if r.Size() != 3 {
+		t.Errorf("Size = %d; want 3", r.Size())
+	}
+}
diff --git a/src/strings/strings.go b/src/strings/strings.go
index 27d3849..dd51dab 100644
--- a/src/strings/strings.go
+++ b/src/strings/strings.go
@@ -2,7 +2,9 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Package strings implements simple functions to manipulate strings.
+// Package strings implements simple functions to manipulate UTF-8 encoded strings.
+//
+// For information about UTF-8 strings in Go, see https://blog.golang.org/strings.
 package strings
 
 import (
@@ -78,6 +80,7 @@ func hashStrRev(sep string) (uint32, uint32) {
 }
 
 // Count counts the number of non-overlapping instances of sep in s.
+// If sep is an empty string, Count returns 1 + the number of Unicode code points in s.
 func Count(s, sep string) int {
 	n := 0
 	// special cases
@@ -125,17 +128,17 @@ func Count(s, sep string) int {
 	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
 }
@@ -184,14 +187,7 @@ func LastIndex(s, sep string) int {
 	case n == 0:
 		return len(s)
 	case n == 1:
-		// special case worth making fast
-		c := sep[0]
-		for i := len(s) - 1; i >= 0; i-- {
-			if s[i] == c {
-				return i
-			}
-		}
-		return -1
+		return LastIndexByte(s, sep[0])
 	case n == len(s):
 		if sep == s {
 			return 0
@@ -270,6 +266,16 @@ func LastIndexAny(s, chars string) int {
 	return -1
 }
 
+// LastIndexByte returns the index of the last instance of c in s, or -1 if c is not present in s.
+func LastIndexByte(s string, c byte) int {
+	for i := len(s) - 1; i >= 0; i-- {
+		if s[i] == c {
+			return i
+		}
+	}
+	return -1
+}
+
 // Generic split: splits after each instance of sep,
 // including sepSave bytes of sep in the subarrays.
 func genSplit(s, sep string, sepSave, n int) []string {
@@ -519,7 +525,7 @@ func isSeparator(r rune) bool {
 // 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..4e21dea 100644
--- a/src/strings/strings_test.go
+++ b/src/strings/strings_test.go
@@ -120,6 +120,23 @@ func TestLastIndex(t *testing.T)    { runIndexTests(t, LastIndex, "LastIndex", l
 func TestIndexAny(t *testing.T)     { runIndexTests(t, IndexAny, "IndexAny", indexAnyTests) }
 func TestLastIndexAny(t *testing.T) { runIndexTests(t, LastIndexAny, "LastIndexAny", lastIndexAnyTests) }
 
+func TestLastIndexByte(t *testing.T) {
+	testCases := []IndexTest{
+		{"", "q", -1},
+		{"abcdef", "q", -1},
+		{"abcdefabcdef", "a", len("abcdef")},      // something in the middle
+		{"abcdefabcdef", "f", len("abcdefabcde")}, // last byte
+		{"zabcdefabcdef", "z", 0},                 // first byte
+		{"a☺b☻c☹d", "b", len("a☺")},               // non-ascii
+	}
+	for _, test := range testCases {
+		actual := LastIndexByte(test.s, test.sep[0])
+		if actual != test.out {
+			t.Errorf("LastIndexByte(%q,%c) = %v; want %v", test.s, test.sep[0], actual, test.out)
+		}
+	}
+}
+
 var indexRuneTests = []struct {
 	s    string
 	rune rune
@@ -569,6 +586,35 @@ func TestTrim(t *testing.T) {
 	}
 }
 
+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/sudo.bash b/src/sudo.bash
deleted file mode 100755
index 33254c2..0000000
--- a/src/sudo.bash
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/usr/bin/env bash
-# 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.
-
-set -e
-
-case "`uname`" in
-Darwin)
-	;;
-*)
-	exit 0
-esac
-
-# Check that the go command exists
-if ! go help >/dev/null 2>&1; then
-	echo "The go command is not in your PATH." >&2
-	exit 2
-fi
-
-eval $(go env)
-if ! [ -x $GOTOOLDIR/prof ]; then
-	echo "You don't need to run sudo.bash." >&2
-	exit 2
-fi
-
-if [[ ! -d /usr/local/bin ]]; then
-	echo 1>&2 'sudo.bash: problem with /usr/local/bin; cannot install tools.'
-	exit 2
-fi
-
-cd $(dirname $0)
-for i in prof
-do
-	# Remove old binaries if present
-	sudo rm -f /usr/local/bin/6$i
-	# Install new binaries
-	sudo cp $GOTOOLDIR/$i /usr/local/bin/go$i
-	sudo chgrp procmod /usr/local/bin/go$i
-	sudo chmod g+s /usr/local/bin/go$i
-done
diff --git a/src/sync/atomic/asm_386.s b/src/sync/atomic/asm_386.s
index 740dfe7..383d759 100644
--- a/src/sync/atomic/asm_386.s
+++ b/src/sync/atomic/asm_386.s
@@ -50,9 +50,6 @@ swaploop:
 TEXT ·SwapUintptr(SB),NOSPLIT,$0-12
 	JMP	·SwapUint32(SB)
 
-TEXT ·SwapPointer(SB),NOSPLIT,$0-12
-	JMP	·SwapUint32(SB)
-
 TEXT ·CompareAndSwapInt32(SB),NOSPLIT,$0-13
 	JMP	·CompareAndSwapUint32(SB)
 
@@ -69,9 +66,6 @@ TEXT ·CompareAndSwapUint32(SB),NOSPLIT,$0-13
 TEXT ·CompareAndSwapUintptr(SB),NOSPLIT,$0-13
 	JMP	·CompareAndSwapUint32(SB)
 
-TEXT ·CompareAndSwapPointer(SB),NOSPLIT,$0-13
-	JMP	·CompareAndSwapUint32(SB)
-
 TEXT ·CompareAndSwapInt64(SB),NOSPLIT,$0-21
 	JMP	·CompareAndSwapUint64(SB)
 
@@ -209,6 +203,3 @@ TEXT ·StoreUint64(SB),NOSPLIT,$0-12
 
 TEXT ·StoreUintptr(SB),NOSPLIT,$0-8
 	JMP	·StoreUint32(SB)
-
-TEXT ·StorePointer(SB),NOSPLIT,$0-8
-	JMP	·StoreUint32(SB)
diff --git a/src/sync/atomic/asm_amd64.s b/src/sync/atomic/asm_amd64.s
index 6e53ebe..551c002 100644
--- a/src/sync/atomic/asm_amd64.s
+++ b/src/sync/atomic/asm_amd64.s
@@ -29,9 +29,6 @@ TEXT ·SwapUint64(SB),NOSPLIT,$0-24
 TEXT ·SwapUintptr(SB),NOSPLIT,$0-24
 	JMP	·SwapUint64(SB)
 
-TEXT ·SwapPointer(SB),NOSPLIT,$0-24
-	JMP	·SwapUint64(SB)
-
 TEXT ·CompareAndSwapInt32(SB),NOSPLIT,$0-17
 	JMP	·CompareAndSwapUint32(SB)
 
@@ -47,9 +44,6 @@ TEXT ·CompareAndSwapUint32(SB),NOSPLIT,$0-17
 TEXT ·CompareAndSwapUintptr(SB),NOSPLIT,$0-25
 	JMP	·CompareAndSwapUint64(SB)
 
-TEXT ·CompareAndSwapPointer(SB),NOSPLIT,$0-25
-	JMP	·CompareAndSwapUint64(SB)
-
 TEXT ·CompareAndSwapInt64(SB),NOSPLIT,$0-25
 	JMP	·CompareAndSwapUint64(SB)
 
@@ -137,10 +131,4 @@ TEXT ·StoreUint64(SB),NOSPLIT,$0-16
 	RET
 
 TEXT ·StoreUintptr(SB),NOSPLIT,$0-16
-	JMP	·StorePointer(SB)
-
-TEXT ·StorePointer(SB),NOSPLIT,$0-16
-	MOVQ	addr+0(FP), BP
-	MOVQ	val+8(FP), AX
-	XCHGQ	AX, 0(BP)
-	RET
+	JMP	·StoreUint64(SB)
diff --git a/src/sync/atomic/asm_amd64p32.s b/src/sync/atomic/asm_amd64p32.s
index d77cc2c..b4e19ee 100644
--- a/src/sync/atomic/asm_amd64p32.s
+++ b/src/sync/atomic/asm_amd64p32.s
@@ -30,9 +30,6 @@ TEXT ·SwapUint64(SB),NOSPLIT,$0-24
 TEXT ·SwapUintptr(SB),NOSPLIT,$0-12
 	JMP	·SwapUint32(SB)
 
-TEXT ·SwapPointer(SB),NOSPLIT,$0-12
-	JMP	·SwapUint32(SB)
-
 TEXT ·CompareAndSwapInt32(SB),NOSPLIT,$0-17
 	JMP	·CompareAndSwapUint32(SB)
 
@@ -48,9 +45,6 @@ TEXT ·CompareAndSwapUint32(SB),NOSPLIT,$0-17
 TEXT ·CompareAndSwapUintptr(SB),NOSPLIT,$0-17
 	JMP	·CompareAndSwapUint32(SB)
 
-TEXT ·CompareAndSwapPointer(SB),NOSPLIT,$0-17
-	JMP	·CompareAndSwapUint32(SB)
-
 TEXT ·CompareAndSwapInt64(SB),NOSPLIT,$0-25
 	JMP	·CompareAndSwapUint64(SB)
 
@@ -150,10 +144,4 @@ TEXT ·StoreUint64(SB),NOSPLIT,$0-16
 	RET
 
 TEXT ·StoreUintptr(SB),NOSPLIT,$0-8
-	JMP	·StorePointer(SB)
-
-TEXT ·StorePointer(SB),NOSPLIT,$0-8
-	MOVL	addr+0(FP), BX
-	MOVL	val+4(FP), AX
-	XCHGL	AX, 0(BX)
-	RET
+	JMP	·StoreUint32(SB)
diff --git a/src/sync/atomic/asm_arm.s b/src/sync/atomic/asm_arm.s
index 8a85273..3b50657 100644
--- a/src/sync/atomic/asm_arm.s
+++ b/src/sync/atomic/asm_arm.s
@@ -8,6 +8,18 @@
 
 // ARM atomic operations, for use by asm_$(GOOS)_arm.s.
 
+#define DMB_ISHST_7 \
+	MOVB	runtime·goarm(SB), R11; \
+	CMP	$7, R11; \
+	BLT	2(PC); \
+	WORD	$0xf57ff05a	// dmb ishst
+
+#define DMB_ISH_7 \
+	MOVB	runtime·goarm(SB), R11; \
+	CMP	$7, R11; \
+	BLT	2(PC); \
+	WORD	$0xf57ff05b	// dmb ish
+
 TEXT ·armCompareAndSwapUint32(SB),NOSPLIT,$0-13
 	MOVW	addr+0(FP), R1
 	MOVW	old+4(FP), R2
@@ -17,10 +29,12 @@ casloop:
 	LDREX	(R1), R0
 	CMP	R0, R2
 	BNE	casfail
+	DMB_ISHST_7
 	STREX	R3, (R1), R0
 	CMP	$0, R0
 	BNE	casloop
 	MOVW	$1, R0
+	DMB_ISH_7
 	MOVBU	R0, ret+12(FP)
 	RET
 casfail:
@@ -46,10 +60,12 @@ cas64loop:
 	BNE	cas64fail
 	CMP	R3, R7
 	BNE	cas64fail
+	DMB_ISHST_7
 	STREXD	R4, (R1), R0	// stores R4 and R5
 	CMP	$0, R0
 	BNE	cas64loop
 	MOVW	$1, R0
+	DMB_ISH_7
 	MOVBU	R0, ret+20(FP)
 	RET
 cas64fail:
@@ -64,9 +80,11 @@ addloop:
 	// LDREX and STREX were introduced in ARMv6.
 	LDREX	(R1), R3
 	ADD	R2, R3
+	DMB_ISHST_7
 	STREX	R3, (R1), R0
 	CMP	$0, R0
 	BNE	addloop
+	DMB_ISH_7
 	MOVW	R3, ret+8(FP)
 	RET
 
@@ -84,9 +102,11 @@ add64loop:
 	LDREXD	(R1), R4	// loads R4 and R5
 	ADD.S	R2, R4
 	ADC	R3, R5
+	DMB_ISHST_7
 	STREXD	R4, (R1), R0	// stores R4 and R5
 	CMP	$0, R0
 	BNE	add64loop
+	DMB_ISH_7
 	MOVW	R4, retlo+12(FP)
 	MOVW	R5, rethi+16(FP)
 	RET
@@ -97,9 +117,11 @@ TEXT ·armSwapUint32(SB),NOSPLIT,$0-12
 swaploop:
 	// LDREX and STREX were introduced in ARMv6.
 	LDREX	(R1), R3
+	DMB_ISHST_7
 	STREX	R2, (R1), R0
 	CMP	$0, R0
 	BNE	swaploop
+	DMB_ISH_7
 	MOVW	R3, old+8(FP)
 	RET
 
@@ -115,9 +137,11 @@ TEXT ·armSwapUint64(SB),NOSPLIT,$0-20
 swap64loop:
 	// LDREXD and STREXD were introduced in ARMv6k.
 	LDREXD	(R1), R4	// loads R4 and R5
+	DMB_ISHST_7
 	STREXD	R2, (R1), R0	// stores R2 and R3
 	CMP	$0, R0
 	BNE	swap64loop
+	DMB_ISH_7
 	MOVW	R4, oldlo+12(FP)
 	MOVW	R5, oldhi+16(FP)
 	RET
@@ -131,9 +155,11 @@ TEXT ·armLoadUint64(SB),NOSPLIT,$0-12
 	MOVW	R2, (R2)
 load64loop:
 	LDREXD	(R1), R2	// loads R2 and R3
+	DMB_ISHST_7
 	STREXD	R2, (R1), R0	// stores R2 and R3
 	CMP	$0, R0
 	BNE	load64loop
+	DMB_ISH_7
 	MOVW	R2, vallo+4(FP)
 	MOVW	R3, valhi+8(FP)
 	RET
@@ -149,9 +175,11 @@ TEXT ·armStoreUint64(SB),NOSPLIT,$0-12
 	MOVW	valhi+8(FP), R3
 store64loop:
 	LDREXD	(R1), R4	// loads R4 and R5
+	DMB_ISHST_7
 	STREXD	R2, (R1), R0	// stores R2 and R3
 	CMP	$0, R0
 	BNE	store64loop
+	DMB_ISH_7
 	RET
 
 // Check for broken 64-bit LDREXD as found in QEMU.
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_darwin_arm.s b/src/sync/atomic/asm_darwin_arm.s
new file mode 100644
index 0000000..36dd483
--- /dev/null
+++ b/src/sync/atomic/asm_darwin_arm.s
@@ -0,0 +1,99 @@
+// 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"
+
+// Darwin/ARM atomic operations.
+
+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/asm_freebsd_arm.s b/src/sync/atomic/asm_freebsd_arm.s
index 06b975e..46710ea 100644
--- a/src/sync/atomic/asm_freebsd_arm.s
+++ b/src/sync/atomic/asm_freebsd_arm.s
@@ -16,9 +16,6 @@ TEXT ·CompareAndSwapUint32(SB),NOSPLIT,$0
 TEXT ·CompareAndSwapUintptr(SB),NOSPLIT,$0
 	B ·CompareAndSwapUint32(SB)
 
-TEXT ·CompareAndSwapPointer(SB),NOSPLIT,$0
-	B ·CompareAndSwapUint32(SB)
-
 TEXT ·AddInt32(SB),NOSPLIT,$0
 	B ·AddUint32(SB)
 
@@ -37,9 +34,6 @@ TEXT ·SwapUint32(SB),NOSPLIT,$0
 TEXT ·SwapUintptr(SB),NOSPLIT,$0
 	B ·SwapUint32(SB)
 
-TEXT ·SwapPointer(SB),NOSPLIT,$0
-	B ·SwapUint32(SB)
-
 TEXT ·CompareAndSwapInt64(SB),NOSPLIT,$0
 	B ·CompareAndSwapUint64(SB)
 
@@ -104,6 +98,3 @@ TEXT ·StoreUint64(SB),NOSPLIT,$0
 
 TEXT ·StoreUintptr(SB),NOSPLIT,$0
 	B ·StoreUint32(SB)
-
-TEXT ·StorePointer(SB),NOSPLIT,$0
-	B ·StoreUint32(SB)
diff --git a/src/sync/atomic/asm_linux_arm.s b/src/sync/atomic/asm_linux_arm.s
index 9447584..631c105 100644
--- a/src/sync/atomic/asm_linux_arm.s
+++ b/src/sync/atomic/asm_linux_arm.s
@@ -24,7 +24,7 @@
 // http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=b49c0f24cf6744a3f4fd09289fe7cade349dead5
 //
 TEXT cas<>(SB),NOSPLIT,$0
-	MOVW	$0xffff0fc0, PC
+	MOVW	$0xffff0fc0, R15
 
 TEXT ·CompareAndSwapInt32(SB),NOSPLIT,$0
 	B	·CompareAndSwapUint32(SB)
@@ -57,9 +57,6 @@ cascheck:
 TEXT ·CompareAndSwapUintptr(SB),NOSPLIT,$0
 	B	·CompareAndSwapUint32(SB)
 
-TEXT ·CompareAndSwapPointer(SB),NOSPLIT,$0
-	B	·CompareAndSwapUint32(SB)
-
 TEXT ·AddInt32(SB),NOSPLIT,$0
 	B	·AddUint32(SB)
 
@@ -97,11 +94,8 @@ swaploop1:
 TEXT ·SwapUintptr(SB),NOSPLIT,$0
 	B	·SwapUint32(SB)
 
-TEXT ·SwapPointer(SB),NOSPLIT,$0
-	B	·SwapUint32(SB)
-
 TEXT cas64<>(SB),NOSPLIT,$0
-	MOVW	$0xffff0f60, PC // __kuser_cmpxchg64: Linux-3.1 and above
+	MOVW	$0xffff0f60, R15 // R15 = hardware PC. __kuser_cmpxchg64: Linux-3.1 and above
 
 TEXT kernelCAS64<>(SB),NOSPLIT,$0-21
 	// int (*__kuser_cmpxchg64_t)(const int64_t *oldval, const int64_t *newval, volatile int64_t *ptr);
@@ -113,12 +107,12 @@ TEXT kernelCAS64<>(SB),NOSPLIT,$0-21
 	AND.S	$7, R2, R1
 	BEQ 	2(PC)
 	MOVW	R1, (R1)
-	MOVW	$4(FP), R0 // oldval
-	MOVW	$12(FP), R1 // newval
+	MOVW	$oldval+4(FP), R0
+	MOVW	$newval+12(FP), R1
 	BL	cas64<>(SB)
 	MOVW.CS	$1, R0 // C is set if the kernel has changed *ptr
 	MOVW.CC	$0, R0
-	MOVW	R0, 20(FP)
+	MOVW	R0, ret+20(FP)
 	RET
 
 TEXT ·generalCAS64(SB),NOSPLIT,$0-21
@@ -133,17 +127,17 @@ TEXT setupAndCallCAS64<>(SB),NOSPLIT,$-4-21
 	CMP 	$5, R0
 	MOVW.CS	$kernelCAS64<>(SB), R1
 	MOVW.CS	R1, armCAS64(SB)
-	MOVW.CS	R1, PC
+	MOVW.CS	R1, R15 // R15 = hardware PC
 	MOVB	runtime·armArch(SB), R0
 	// LDREXD, STREXD only present on ARMv6K or higher
 	CMP	$6, R0 // TODO(minux): how to differentiate ARMv6 with ARMv6K?
 	MOVW.CS	$·armCompareAndSwapUint64(SB), R1
 	MOVW.CS	R1, armCAS64(SB)
-	MOVW.CS	R1, PC
+	MOVW.CS	R1, R15
 	// we are out of luck, can only use runtime's emulated 64-bit cas
 	MOVW	$·generalCAS64(SB), R1
 	MOVW	R1, armCAS64(SB)
-	MOVW	R1, PC
+	MOVW	R1, R15
 
 TEXT ·CompareAndSwapInt64(SB),NOSPLIT,$0
 	B   	·CompareAndSwapUint64(SB)
@@ -151,7 +145,7 @@ TEXT ·CompareAndSwapInt64(SB),NOSPLIT,$0
 TEXT ·CompareAndSwapUint64(SB),NOSPLIT,$-4-21
 	MOVW	armCAS64(SB), R0
 	CMP 	$0, R0
-	MOVW.NE	R0, PC
+	MOVW.NE	R0, R15 // R15 = hardware PC
 	B	setupAndCallCAS64<>(SB)
 
 TEXT ·AddInt64(SB),NOSPLIT,$0
@@ -211,6 +205,3 @@ TEXT ·StoreUint64(SB),NOSPLIT,$0
 
 TEXT ·StoreUintptr(SB),NOSPLIT,$0
 	B	·StoreUint32(SB)
-
-TEXT ·StorePointer(SB),NOSPLIT,$0
-	B	·StoreUint32(SB)
diff --git a/src/sync/atomic/asm_nacl_arm.s b/src/sync/atomic/asm_nacl_arm.s
index 76f6233..8b4b687 100644
--- a/src/sync/atomic/asm_nacl_arm.s
+++ b/src/sync/atomic/asm_nacl_arm.s
@@ -16,9 +16,6 @@ TEXT ·CompareAndSwapUint32(SB),NOSPLIT,$0
 TEXT ·CompareAndSwapUintptr(SB),NOSPLIT,$0
 	B ·CompareAndSwapUint32(SB)
 
-TEXT ·CompareAndSwapPointer(SB),NOSPLIT,$0
-	B ·CompareAndSwapUint32(SB)
-
 TEXT ·AddInt32(SB),NOSPLIT,$0
 	B ·AddUint32(SB)
 
@@ -37,9 +34,6 @@ TEXT ·SwapUint32(SB),NOSPLIT,$0
 TEXT ·SwapUintptr(SB),NOSPLIT,$0
 	B ·SwapUint32(SB)
 
-TEXT ·SwapPointer(SB),NOSPLIT,$0
-	B ·SwapUint32(SB)
-
 TEXT ·CompareAndSwapInt64(SB),NOSPLIT,$0
 	B ·CompareAndSwapUint64(SB)
 
@@ -104,6 +98,3 @@ TEXT ·StoreUint64(SB),NOSPLIT,$0
 
 TEXT ·StoreUintptr(SB),NOSPLIT,$0
 	B ·StoreUint32(SB)
-
-TEXT ·StorePointer(SB),NOSPLIT,$0
-	B ·StoreUint32(SB)
diff --git a/src/sync/atomic/asm_netbsd_arm.s b/src/sync/atomic/asm_netbsd_arm.s
index dbe8089..5c98de3 100644
--- a/src/sync/atomic/asm_netbsd_arm.s
+++ b/src/sync/atomic/asm_netbsd_arm.s
@@ -16,9 +16,6 @@ TEXT ·CompareAndSwapUint32(SB),NOSPLIT,$0
 TEXT ·CompareAndSwapUintptr(SB),NOSPLIT,$0
 	B ·CompareAndSwapUint32(SB)
 
-TEXT ·CompareAndSwapPointer(SB),NOSPLIT,$0
-	B ·CompareAndSwapUint32(SB)
-
 TEXT ·AddInt32(SB),NOSPLIT,$0
 	B ·AddUint32(SB)
 
@@ -37,9 +34,6 @@ TEXT ·SwapUint32(SB),NOSPLIT,$0
 TEXT ·SwapUintptr(SB),NOSPLIT,$0
 	B ·SwapUint32(SB)
 
-TEXT ·SwapPointer(SB),NOSPLIT,$0
-	B ·SwapUint32(SB)
-
 TEXT ·CompareAndSwapInt64(SB),NOSPLIT,$0
 	B ·CompareAndSwapUint64(SB)
 
@@ -104,6 +98,3 @@ TEXT ·StoreUint64(SB),NOSPLIT,$0
 
 TEXT ·StoreUintptr(SB),NOSPLIT,$0
 	B ·StoreUint32(SB)
-
-TEXT ·StorePointer(SB),NOSPLIT,$0
-	B ·StoreUint32(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/asm_ppc64x.s b/src/sync/atomic/asm_ppc64x.s
new file mode 100644
index 0000000..d3e49ae
--- /dev/null
+++ b/src/sync/atomic/asm_ppc64x.s
@@ -0,0 +1,175 @@
+// 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 ppc64 ppc64le
+
+#include "textflag.h"
+
+TEXT ·SwapInt32(SB),NOSPLIT,$0-20
+	BR	·SwapUint32(SB)
+
+TEXT ·SwapUint32(SB),NOSPLIT,$0-20
+	MOVD	addr+0(FP), R3
+	MOVW	new+8(FP), R4
+	SYNC
+	LWAR	(R3), R5
+	STWCCC	R4, (R3)
+	BNE	-3(PC)
+	SYNC
+	ISYNC
+	MOVW	R5, old+16(FP)
+	RET
+
+TEXT ·SwapInt64(SB),NOSPLIT,$0-24
+	BR	·SwapUint64(SB)
+
+TEXT ·SwapUint64(SB),NOSPLIT,$0-24
+	MOVD	addr+0(FP), R3
+	MOVD	new+8(FP), R4
+	SYNC
+	LDAR	(R3), R5
+	STDCCC	R4, (R3)
+	BNE	-3(PC)
+	SYNC
+	ISYNC
+	MOVD	R5, old+16(FP)
+	RET
+
+TEXT ·SwapUintptr(SB),NOSPLIT,$0-24
+	BR	·SwapUint64(SB)
+
+TEXT ·CompareAndSwapInt32(SB),NOSPLIT,$0-17
+	BR	·CompareAndSwapUint32(SB)
+
+TEXT ·CompareAndSwapUint32(SB),NOSPLIT,$0-17
+	MOVD	addr+0(FP), R3
+	MOVW	old+8(FP), R4
+	MOVW	new+12(FP), R5
+	SYNC
+	LWAR	(R3), R6
+	CMPW	R6, R4
+	BNE	8(PC)
+	STWCCC	R5, (R3)
+	BNE	-5(PC)
+	SYNC
+	ISYNC
+	MOVD	$1, R3
+	MOVB	R3, swapped+16(FP)
+	RET
+	MOVB	R0, swapped+16(FP)
+	RET
+
+TEXT ·CompareAndSwapUintptr(SB),NOSPLIT,$0-25
+	BR	·CompareAndSwapUint64(SB)
+
+TEXT ·CompareAndSwapInt64(SB),NOSPLIT,$0-25
+	BR	·CompareAndSwapUint64(SB)
+
+TEXT ·CompareAndSwapUint64(SB),NOSPLIT,$0-25
+	MOVD	addr+0(FP), R3
+	MOVD	old+8(FP), R4
+	MOVD	new+16(FP), R5
+	SYNC
+	LDAR	(R3), R6
+	CMP	R6, R4
+	BNE	8(PC)
+	STDCCC	R5, (R3)
+	BNE	-5(PC)
+	SYNC
+	ISYNC
+	MOVD	$1, R3
+	MOVB	R3, swapped+24(FP)
+	RET
+	MOVB	R0, swapped+24(FP)
+	RET
+
+TEXT ·AddInt32(SB),NOSPLIT,$0-20
+	BR	·AddUint32(SB)
+
+TEXT ·AddUint32(SB),NOSPLIT,$0-20
+	MOVD	addr+0(FP), R3
+	MOVW	delta+8(FP), R4
+	SYNC
+	LWAR	(R3), R5
+	ADD	R4, R5
+	STWCCC	R5, (R3)
+	BNE	-4(PC)
+	SYNC
+	ISYNC
+	MOVW	R5, ret+16(FP)
+	RET
+
+TEXT ·AddUintptr(SB),NOSPLIT,$0-24
+	BR	·AddUint64(SB)
+
+TEXT ·AddInt64(SB),NOSPLIT,$0-24
+	BR	·AddUint64(SB)
+
+TEXT ·AddUint64(SB),NOSPLIT,$0-24
+	MOVD	addr+0(FP), R3
+	MOVD	delta+8(FP), R4
+	SYNC
+	LDAR	(R3), R5
+	ADD	R4, R5
+	STDCCC	R5, (R3)
+	BNE	-4(PC)
+	SYNC
+	ISYNC
+	MOVD	R5, ret+16(FP)
+	RET
+
+TEXT ·LoadInt32(SB),NOSPLIT,$0-12
+	BR	·LoadUint32(SB)
+
+TEXT ·LoadUint32(SB),NOSPLIT,$0-12
+	MOVD	addr+0(FP), R3
+	SYNC
+	MOVW	0(R3), R3
+	CMPW	R3, R3, CR7
+	BC	4, 30, 1(PC)	// bne- cr7,0x4
+	ISYNC
+	MOVW	R3, val+8(FP)
+	RET
+
+TEXT ·LoadInt64(SB),NOSPLIT,$0-16
+	BR	·LoadUint64(SB)
+
+TEXT ·LoadUint64(SB),NOSPLIT,$0-16
+	MOVD	addr+0(FP), R3
+	SYNC
+	MOVD	0(R3), R3
+	CMP	R3, R3, CR7
+	BC	4, 30, 1(PC)	// bne- cr7,0x4
+	ISYNC
+	MOVD	R3, val+8(FP)
+	RET
+
+TEXT ·LoadUintptr(SB),NOSPLIT,$0-16
+	BR	·LoadPointer(SB)
+
+TEXT ·LoadPointer(SB),NOSPLIT,$0-16
+	BR	·LoadUint64(SB)
+
+TEXT ·StoreInt32(SB),NOSPLIT,$0-12
+	BR	·StoreUint32(SB)
+
+TEXT ·StoreUint32(SB),NOSPLIT,$0-12
+	MOVD	addr+0(FP), R3
+	MOVW	val+8(FP), R4
+	SYNC
+	MOVW	R4, 0(R3)
+	RET
+
+TEXT ·StoreInt64(SB),NOSPLIT,$0-16
+	BR	·StoreUint64(SB)
+
+TEXT ·StoreUint64(SB),NOSPLIT,$0-16
+	MOVD	addr+0(FP), R3
+	MOVD	val+8(FP), R4
+	SYNC
+	MOVD	R4, 0(R3)
+	RET
+
+TEXT ·StoreUintptr(SB),NOSPLIT,$0-16
+	BR	·StoreUint64(SB)
diff --git a/src/sync/atomic/atomic_test.go b/src/sync/atomic/atomic_test.go
index 9f13af4..e2c63b9 100644
--- a/src/sync/atomic/atomic_test.go
+++ b/src/sync/atomic/atomic_test.go
@@ -164,7 +164,7 @@ func TestSwapPointer(t *testing.T) {
 	x.before = magicptr
 	x.after = magicptr
 	var j uintptr
-	for delta := uintptr(1); delta+delta > delta; delta += delta {
+	for delta := uintptr(1 << 16); delta+delta > delta; delta += delta {
 		k := SwapPointer(&x.i, unsafe.Pointer(delta))
 		if uintptr(x.i) != delta || uintptr(k) != j {
 			t.Fatalf("delta=%d i=%d j=%d k=%d", delta, x.i, j, k)
@@ -456,7 +456,7 @@ func TestCompareAndSwapPointer(t *testing.T) {
 	magicptr := uintptr(m)
 	x.before = magicptr
 	x.after = magicptr
-	for val := uintptr(1); val+val > val; val += val {
+	for val := uintptr(1 << 16); val+val > val; val += val {
 		x.i = unsafe.Pointer(val)
 		if !CompareAndSwapPointer(&x.i, unsafe.Pointer(val), unsafe.Pointer(val+1)) {
 			t.Fatalf("should have swapped %#x %#x", val, val+1)
@@ -595,7 +595,7 @@ func TestLoadPointer(t *testing.T) {
 	magicptr := uintptr(m)
 	x.before = magicptr
 	x.after = magicptr
-	for delta := uintptr(1); delta+delta > delta; delta += delta {
+	for delta := uintptr(1 << 16); delta+delta > delta; delta += delta {
 		k := LoadPointer(&x.i)
 		if k != x.i {
 			t.Fatalf("delta=%d i=%d k=%d", delta, x.i, k)
@@ -731,7 +731,7 @@ func TestStorePointer(t *testing.T) {
 	x.before = magicptr
 	x.after = magicptr
 	v := unsafe.Pointer(uintptr(0))
-	for delta := uintptr(1); delta+delta > delta; delta += delta {
+	for delta := uintptr(1 << 16); delta+delta > delta; delta += delta {
 		StorePointer(&x.i, unsafe.Pointer(v))
 		if x.i != v {
 			t.Fatalf("delta=%d i=%d v=%d", delta, x.i, v)
@@ -759,14 +759,12 @@ var hammer32 = map[string]func(*uint32, int){
 	"SwapInt32":             hammerSwapInt32,
 	"SwapUint32":            hammerSwapUint32,
 	"SwapUintptr":           hammerSwapUintptr32,
-	"SwapPointer":           hammerSwapPointer32,
 	"AddInt32":              hammerAddInt32,
 	"AddUint32":             hammerAddUint32,
 	"AddUintptr":            hammerAddUintptr32,
 	"CompareAndSwapInt32":   hammerCompareAndSwapInt32,
 	"CompareAndSwapUint32":  hammerCompareAndSwapUint32,
 	"CompareAndSwapUintptr": hammerCompareAndSwapUintptr32,
-	"CompareAndSwapPointer": hammerCompareAndSwapPointer32,
 }
 
 func init() {
@@ -818,20 +816,6 @@ func hammerSwapUintptr32(uaddr *uint32, count int) {
 	}
 }
 
-func hammerSwapPointer32(uaddr *uint32, count int) {
-	// only safe when uintptr is 32-bit.
-	// not called on 64-bit systems.
-	addr := (*unsafe.Pointer)(unsafe.Pointer(uaddr))
-	seed := int(uintptr(unsafe.Pointer(&count)))
-	for i := 0; i < count; i++ {
-		new := uintptr(seed+i)<<16 | uintptr(seed+i)<<16>>16
-		old := uintptr(SwapPointer(addr, unsafe.Pointer(new)))
-		if old>>16 != old<<16>>16 {
-			panic(fmt.Sprintf("SwapPointer is not atomic: %#08x", old))
-		}
-	}
-}
-
 func hammerAddInt32(uaddr *uint32, count int) {
 	addr := (*int32)(unsafe.Pointer(uaddr))
 	for i := 0; i < count; i++ {
@@ -891,20 +875,6 @@ func hammerCompareAndSwapUintptr32(uaddr *uint32, count int) {
 	}
 }
 
-func hammerCompareAndSwapPointer32(uaddr *uint32, count int) {
-	// only safe when uintptr is 32-bit.
-	// not called on 64-bit systems.
-	addr := (*unsafe.Pointer)(unsafe.Pointer(uaddr))
-	for i := 0; i < count; i++ {
-		for {
-			v := LoadPointer(addr)
-			if CompareAndSwapPointer(addr, v, unsafe.Pointer(uintptr(v)+1)) {
-				break
-			}
-		}
-	}
-}
-
 func TestHammer32(t *testing.T) {
 	const p = 4
 	n := 100000
@@ -940,14 +910,12 @@ var hammer64 = map[string]func(*uint64, int){
 	"SwapInt64":             hammerSwapInt64,
 	"SwapUint64":            hammerSwapUint64,
 	"SwapUintptr":           hammerSwapUintptr64,
-	"SwapPointer":           hammerSwapPointer64,
 	"AddInt64":              hammerAddInt64,
 	"AddUint64":             hammerAddUint64,
 	"AddUintptr":            hammerAddUintptr64,
 	"CompareAndSwapInt64":   hammerCompareAndSwapInt64,
 	"CompareAndSwapUint64":  hammerCompareAndSwapUint64,
 	"CompareAndSwapUintptr": hammerCompareAndSwapUintptr64,
-	"CompareAndSwapPointer": hammerCompareAndSwapPointer64,
 }
 
 func init() {
@@ -999,20 +967,6 @@ func hammerSwapUintptr64(uaddr *uint64, count int) {
 	}
 }
 
-func hammerSwapPointer64(uaddr *uint64, count int) {
-	// only safe when uintptr is 64-bit.
-	// not called on 32-bit systems.
-	addr := (*unsafe.Pointer)(unsafe.Pointer(uaddr))
-	seed := int(uintptr(unsafe.Pointer(&count)))
-	for i := 0; i < count; i++ {
-		new := uintptr(seed+i)<<32 | uintptr(seed+i)<<32>>32
-		old := uintptr(SwapPointer(addr, unsafe.Pointer(new)))
-		if old>>32 != old<<32>>32 {
-			panic(fmt.Sprintf("SwapPointer is not atomic: %v", old))
-		}
-	}
-}
-
 func hammerAddInt64(uaddr *uint64, count int) {
 	addr := (*int64)(unsafe.Pointer(uaddr))
 	for i := 0; i < count; i++ {
@@ -1072,20 +1026,6 @@ func hammerCompareAndSwapUintptr64(uaddr *uint64, count int) {
 	}
 }
 
-func hammerCompareAndSwapPointer64(uaddr *uint64, count int) {
-	// only safe when uintptr is 64-bit.
-	// not called on 32-bit systems.
-	addr := (*unsafe.Pointer)(unsafe.Pointer(uaddr))
-	for i := 0; i < count; i++ {
-		for {
-			v := LoadPointer(addr)
-			if CompareAndSwapPointer(addr, v, unsafe.Pointer(uintptr(v)+1)) {
-				break
-			}
-		}
-	}
-}
-
 func TestHammer64(t *testing.T) {
 	if test64err != nil {
 		t.Skipf("Skipping 64-bit tests: %v", test64err)
@@ -1463,9 +1403,6 @@ func TestUnaligned64(t *testing.T) {
 }
 
 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)
-	}
 	funcs := [...]func(){
 		func() { CompareAndSwapInt32(nil, 0, 0) },
 		func() { CompareAndSwapInt64(nil, 0, 0) },
diff --git a/src/sync/export_test.go b/src/sync/export_test.go
index fa5983a..6f49b3b 100644
--- a/src/sync/export_test.go
+++ b/src/sync/export_test.go
@@ -7,3 +7,5 @@ package sync
 // Export for testing.
 var Runtime_Semacquire = runtime_Semacquire
 var Runtime_Semrelease = runtime_Semrelease
+
+const RaceEnabled = raceenabled
diff --git a/src/sync/mutex.go b/src/sync/mutex.go
index 73b3377..3f280ad 100644
--- a/src/sync/mutex.go
+++ b/src/sync/mutex.go
@@ -48,15 +48,31 @@ func (m *Mutex) Lock() {
 	}
 
 	awoke := false
+	iter := 0
 	for {
 		old := m.state
 		new := old | mutexLocked
 		if old&mutexLocked != 0 {
+			if runtime_canSpin(iter) {
+				// Active spinning makes sense.
+				// Try to set mutexWoken flag to inform Unlock
+				// to not wake other blocked goroutines.
+				if !awoke && old&mutexWoken == 0 && old>>mutexWaiterShift != 0 &&
+					atomic.CompareAndSwapInt32(&m.state, old, old|mutexWoken) {
+					awoke = true
+				}
+				runtime_doSpin()
+				iter++
+				continue
+			}
 			new = old + 1<<mutexWaiterShift
 		}
 		if awoke {
 			// The goroutine has been woken from sleep,
 			// so we need to reset the flag in either case.
+			if new&mutexWoken == 0 {
+				panic("sync: inconsistent mutex state")
+			}
 			new &^= mutexWoken
 		}
 		if atomic.CompareAndSwapInt32(&m.state, old, new) {
@@ -65,6 +81,7 @@ func (m *Mutex) Lock() {
 			}
 			runtime_Semacquire(&m.sema)
 			awoke = true
+			iter = 0
 		}
 	}
 
diff --git a/src/sync/mutex_test.go b/src/sync/mutex_test.go
index 151b25c..91a4855 100644
--- a/src/sync/mutex_test.go
+++ b/src/sync/mutex_test.go
@@ -134,3 +134,58 @@ func BenchmarkMutexWork(b *testing.B) {
 func BenchmarkMutexWorkSlack(b *testing.B) {
 	benchmarkMutex(b, true, true)
 }
+
+func BenchmarkMutexNoSpin(b *testing.B) {
+	// This benchmark models a situation where spinning in the mutex should be
+	// non-profitable and allows to confirm that spinning does not do harm.
+	// To achieve this we create excess of goroutines most of which do local work.
+	// These goroutines yield during local work, so that switching from
+	// a blocked goroutine to other goroutines is profitable.
+	// As a matter of fact, this benchmark still triggers some spinning in the mutex.
+	var m Mutex
+	var acc0, acc1 uint64
+	b.SetParallelism(4)
+	b.RunParallel(func(pb *testing.PB) {
+		c := make(chan bool)
+		var data [4 << 10]uint64
+		for i := 0; pb.Next(); i++ {
+			if i%4 == 0 {
+				m.Lock()
+				acc0 -= 100
+				acc1 += 100
+				m.Unlock()
+			} else {
+				for i := 0; i < len(data); i += 4 {
+					data[i]++
+				}
+				// Elaborate way to say runtime.Gosched
+				// that does not put the goroutine onto global runq.
+				go func() {
+					c <- true
+				}()
+				<-c
+			}
+		}
+	})
+}
+
+func BenchmarkMutexSpin(b *testing.B) {
+	// This benchmark models a situation where spinning in the mutex should be
+	// profitable. To achieve this we create a goroutine per-proc.
+	// These goroutines access considerable amount of local data so that
+	// unnecessary rescheduling is penalized by cache misses.
+	var m Mutex
+	var acc0, acc1 uint64
+	b.RunParallel(func(pb *testing.PB) {
+		var data [16 << 10]uint64
+		for i := 0; pb.Next(); i++ {
+			m.Lock()
+			acc0 -= 100
+			acc1 += 100
+			m.Unlock()
+			for i := 0; i < len(data); i += 4 {
+				data[i]++
+			}
+		}
+	})
+}
diff --git a/src/sync/runtime.go b/src/sync/runtime.go
index 3b86630..c66d2de 100644
--- a/src/sync/runtime.go
+++ b/src/sync/runtime.go
@@ -38,3 +38,10 @@ func init() {
 	var s syncSema
 	runtime_Syncsemcheck(unsafe.Sizeof(s))
 }
+
+// Active spinning runtime support.
+// runtime_canSpin returns true is spinning makes sense at the moment.
+func runtime_canSpin(i int) bool
+
+// runtime_doSpin does active spinning.
+func runtime_doSpin()
diff --git a/src/sync/waitgroup.go b/src/sync/waitgroup.go
index 92cc57d..de399e6 100644
--- a/src/sync/waitgroup.go
+++ b/src/sync/waitgroup.go
@@ -15,23 +15,21 @@ import (
 // runs and calls Done when finished.  At the same time,
 // Wait can be used to block until all goroutines have finished.
 type WaitGroup struct {
-	m       Mutex
-	counter int32
-	waiters int32
-	sema    *uint32
+	// 64-bit value: high 32 bits are counter, low 32 bits are waiter count.
+	// 64-bit atomic operations require 64-bit alignment, but 32-bit
+	// compilers do not ensure it. So we allocate 12 bytes and then use
+	// the aligned 8 bytes in them as state.
+	state1 [12]byte
+	sema   uint32
 }
 
-// WaitGroup creates a new semaphore each time the old semaphore
-// is released. This is to avoid the following race:
-//
-// G1: Add(1)
-// G1: go G2()
-// G1: Wait() // Context switch after Unlock() and before Semacquire().
-// G2: Done() // Release semaphore: sema == 1, waiters == 0. G1 doesn't run yet.
-// G3: Wait() // Finds counter == 0, waiters == 0, doesn't block.
-// G3: Add(1) // Makes counter == 1, waiters == 0.
-// G3: go G4()
-// G3: Wait() // G1 still hasn't run, G3 finds sema == 1, unblocked! Bug.
+func (wg *WaitGroup) state() *uint64 {
+	if uintptr(unsafe.Pointer(&wg.state1))%8 == 0 {
+		return (*uint64)(unsafe.Pointer(&wg.state1))
+	} else {
+		return (*uint64)(unsafe.Pointer(&wg.state1[4]))
+	}
+}
 
 // Add adds delta, which may be negative, to the WaitGroup counter.
 // If the counter becomes zero, all goroutines blocked on Wait are released.
@@ -43,10 +41,13 @@ type WaitGroup struct {
 // at any time.
 // Typically this means the calls to Add should execute before the statement
 // creating the goroutine or other event to be waited for.
+// If a WaitGroup is reused to wait for several independent sets of events,
+// new Add calls must happen after all previous Wait calls have returned.
 // See the WaitGroup example.
 func (wg *WaitGroup) Add(delta int) {
+	statep := wg.state()
 	if raceenabled {
-		_ = wg.m.state // trigger nil deref early
+		_ = *statep // trigger nil deref early
 		if delta < 0 {
 			// Synchronize decrements with Wait.
 			raceReleaseMerge(unsafe.Pointer(wg))
@@ -54,7 +55,9 @@ func (wg *WaitGroup) Add(delta int) {
 		raceDisable()
 		defer raceEnable()
 	}
-	v := atomic.AddInt32(&wg.counter, int32(delta))
+	state := atomic.AddUint64(statep, uint64(delta)<<32)
+	v := int32(state >> 32)
+	w := uint32(state)
 	if raceenabled {
 		if delta > 0 && v == int32(delta) {
 			// The first increment must be synchronized with Wait.
@@ -66,18 +69,25 @@ func (wg *WaitGroup) Add(delta int) {
 	if v < 0 {
 		panic("sync: negative WaitGroup counter")
 	}
-	if v > 0 || atomic.LoadInt32(&wg.waiters) == 0 {
+	if w != 0 && delta > 0 && v == int32(delta) {
+		panic("sync: WaitGroup misuse: Add called concurrently with Wait")
+	}
+	if v > 0 || w == 0 {
 		return
 	}
-	wg.m.Lock()
-	if atomic.LoadInt32(&wg.counter) == 0 {
-		for i := int32(0); i < wg.waiters; i++ {
-			runtime_Semrelease(wg.sema)
-		}
-		wg.waiters = 0
-		wg.sema = nil
+	// This goroutine has set counter to 0 when waiters > 0.
+	// Now there can't be concurrent mutations of state:
+	// - Adds must not happen concurrently with Wait,
+	// - Wait does not increment waiters if it sees counter == 0.
+	// Still do a cheap sanity check to detect WaitGroup misuse.
+	if *statep != state {
+		panic("sync: WaitGroup misuse: Add called concurrently with Wait")
+	}
+	// Reset waiters count to 0.
+	*statep = 0
+	for ; w != 0; w-- {
+		runtime_Semrelease(&wg.sema)
 	}
-	wg.m.Unlock()
 }
 
 // Done decrements the WaitGroup counter.
@@ -87,51 +97,41 @@ func (wg *WaitGroup) Done() {
 
 // Wait blocks until the WaitGroup counter is zero.
 func (wg *WaitGroup) Wait() {
+	statep := wg.state()
 	if raceenabled {
-		_ = wg.m.state // trigger nil deref early
+		_ = *statep // trigger nil deref early
 		raceDisable()
 	}
-	if atomic.LoadInt32(&wg.counter) == 0 {
-		if raceenabled {
-			raceEnable()
-			raceAcquire(unsafe.Pointer(wg))
-		}
-		return
-	}
-	wg.m.Lock()
-	w := atomic.AddInt32(&wg.waiters, 1)
-	// This code is racing with the unlocked path in Add above.
-	// The code above modifies counter and then reads waiters.
-	// We must modify waiters and then read counter (the opposite order)
-	// to avoid missing an Add.
-	if atomic.LoadInt32(&wg.counter) == 0 {
-		atomic.AddInt32(&wg.waiters, -1)
-		if raceenabled {
-			raceEnable()
-			raceAcquire(unsafe.Pointer(wg))
-			raceDisable()
+	for {
+		state := atomic.LoadUint64(statep)
+		v := int32(state >> 32)
+		w := uint32(state)
+		if v == 0 {
+			// Counter is 0, no need to wait.
+			if raceenabled {
+				raceEnable()
+				raceAcquire(unsafe.Pointer(wg))
+			}
+			return
 		}
-		wg.m.Unlock()
-		if raceenabled {
-			raceEnable()
+		// Increment waiters count.
+		if atomic.CompareAndSwapUint64(statep, state, state+1) {
+			if raceenabled && w == 0 {
+				// Wait must be synchronized with the first Add.
+				// Need to model this is as a write to race with the read in Add.
+				// As a consequence, can do the write only for the first waiter,
+				// otherwise concurrent Waits will race with each other.
+				raceWrite(unsafe.Pointer(&wg.sema))
+			}
+			runtime_Semacquire(&wg.sema)
+			if *statep != 0 {
+				panic("sync: WaitGroup is reused before previous Wait has returned")
+			}
+			if raceenabled {
+				raceEnable()
+				raceAcquire(unsafe.Pointer(wg))
+			}
+			return
 		}
-		return
-	}
-	if raceenabled && w == 1 {
-		// Wait must be synchronized with the first Add.
-		// Need to model this is as a write to race with the read in Add.
-		// As a consequence, can do the write only for the first waiter,
-		// otherwise concurrent Waits will race with each other.
-		raceWrite(unsafe.Pointer(&wg.sema))
-	}
-	if wg.sema == nil {
-		wg.sema = new(uint32)
-	}
-	s := wg.sema
-	wg.m.Unlock()
-	runtime_Semacquire(s)
-	if raceenabled {
-		raceEnable()
-		raceAcquire(unsafe.Pointer(wg))
 	}
 }
diff --git a/src/sync/waitgroup_test.go b/src/sync/waitgroup_test.go
index 4c0a043..3e3e3bf 100644
--- a/src/sync/waitgroup_test.go
+++ b/src/sync/waitgroup_test.go
@@ -5,6 +5,7 @@
 package sync_test
 
 import (
+	"runtime"
 	. "sync"
 	"sync/atomic"
 	"testing"
@@ -46,6 +47,12 @@ func TestWaitGroup(t *testing.T) {
 	}
 }
 
+func knownRacy(t *testing.T) {
+	if RaceEnabled {
+		t.Skip("skipping known-racy test under the race detector")
+	}
+}
+
 func TestWaitGroupMisuse(t *testing.T) {
 	defer func() {
 		err := recover()
@@ -60,6 +67,95 @@ func TestWaitGroupMisuse(t *testing.T) {
 	t.Fatal("Should panic")
 }
 
+func TestWaitGroupMisuse2(t *testing.T) {
+	knownRacy(t)
+	if testing.Short() {
+		t.Skip("skipping flaky test in short mode; see issue 11443")
+	}
+	if runtime.NumCPU() <= 2 {
+		t.Skip("NumCPU<=2, skipping: this test requires parallelism")
+	}
+	defer func() {
+		err := recover()
+		if err != "sync: negative WaitGroup counter" &&
+			err != "sync: WaitGroup misuse: Add called concurrently with Wait" &&
+			err != "sync: WaitGroup is reused before previous Wait has returned" {
+			t.Fatalf("Unexpected panic: %#v", err)
+		}
+	}()
+	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
+	done := make(chan interface{}, 2)
+	// The detection is opportunistically, so we want it to panic
+	// at least in one run out of a million.
+	for i := 0; i < 1e6; i++ {
+		var wg WaitGroup
+		wg.Add(1)
+		go func() {
+			defer func() {
+				done <- recover()
+			}()
+			wg.Wait()
+		}()
+		go func() {
+			defer func() {
+				done <- recover()
+			}()
+			wg.Add(1) // This is the bad guy.
+			wg.Done()
+		}()
+		wg.Done()
+		for j := 0; j < 2; j++ {
+			if err := <-done; err != nil {
+				panic(err)
+			}
+		}
+	}
+	t.Fatal("Should panic")
+}
+
+func TestWaitGroupMisuse3(t *testing.T) {
+	knownRacy(t)
+	if runtime.NumCPU() <= 1 {
+		t.Skip("NumCPU==1, skipping: this test requires parallelism")
+	}
+	defer func() {
+		err := recover()
+		if err != "sync: negative WaitGroup counter" &&
+			err != "sync: WaitGroup misuse: Add called concurrently with Wait" &&
+			err != "sync: WaitGroup is reused before previous Wait has returned" {
+			t.Fatalf("Unexpected panic: %#v", err)
+		}
+	}()
+	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
+	done := make(chan interface{}, 1)
+	// The detection is opportunistically, so we want it to panic
+	// at least in one run out of a million.
+	for i := 0; i < 1e6; i++ {
+		var wg WaitGroup
+		wg.Add(1)
+		go func() {
+			wg.Done()
+		}()
+		go func() {
+			defer func() {
+				done <- recover()
+			}()
+			wg.Wait()
+			// Start reusing the wg before waiting for the Wait below to return.
+			wg.Add(1)
+			go func() {
+				wg.Done()
+			}()
+			wg.Wait()
+		}()
+		wg.Wait()
+		if err := <-done; err != nil {
+			panic(err)
+		}
+	}
+	t.Fatal("Should panic")
+}
+
 func TestWaitGroupRace(t *testing.T) {
 	// Run this test for about 1ms.
 	for i := 0; i < 1000; i++ {
@@ -85,6 +181,19 @@ func TestWaitGroupRace(t *testing.T) {
 	}
 }
 
+func TestWaitGroupAlign(t *testing.T) {
+	type X struct {
+		x  byte
+		wg WaitGroup
+	}
+	var x X
+	x.wg.Add(1)
+	go func(x *X) {
+		x.wg.Done()
+	}(&x)
+	x.wg.Wait()
+}
+
 func BenchmarkWaitGroupUncontended(b *testing.B) {
 	type PaddedWaitGroup struct {
 		WaitGroup
@@ -146,3 +255,17 @@ func BenchmarkWaitGroupWait(b *testing.B) {
 func BenchmarkWaitGroupWaitWork(b *testing.B) {
 	benchmarkWaitGroupWait(b, 100)
 }
+
+func BenchmarkWaitGroupActuallyWait(b *testing.B) {
+	b.ReportAllocs()
+	b.RunParallel(func(pb *testing.PB) {
+		for pb.Next() {
+			var wg WaitGroup
+			wg.Add(1)
+			go func() {
+				wg.Done()
+			}()
+			wg.Wait()
+		}
+	})
+}
diff --git a/src/syscall/asm_darwin_386.s b/src/syscall/asm_darwin_386.s
index 7205deb..dee7116 100644
--- a/src/syscall/asm_darwin_386.s
+++ b/src/syscall/asm_darwin_386.s
@@ -2,9 +2,6 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
-// so that go vet can check that they are correct.
-
 #include "textflag.h"
 #include "funcdata.h"
 
@@ -18,34 +15,34 @@
 
 TEXT	·Syscall(SB),NOSPLIT,$0-28
 	CALL	runtime·entersyscall(SB)
-	MOVL	4(SP), AX	// syscall entry
+	MOVL	trap+0(FP), AX	// syscall entry
 	// slide args down on top of system call number
-	LEAL		8(SP), SI
-	LEAL		4(SP), DI
+	LEAL		a1+4(FP), SI
+	LEAL		trap+0(FP), DI
 	CLD
 	MOVSL
 	MOVSL
 	MOVSL
 	INT	$0x80
 	JAE	ok
-	MOVL	$-1, 20(SP)	// r1
-	MOVL	$-1, 24(SP)	// r2
-	MOVL	AX, 28(SP)		// errno
+	MOVL	$-1, r1+16(FP)
+	MOVL	$-1, r2+20(FP)
+	MOVL	AX, err+24(FP)
 	CALL	runtime·exitsyscall(SB)
 	RET
 ok:
-	MOVL	AX, 20(SP)	// r1
-	MOVL	DX, 24(SP)	// r2
-	MOVL	$0, 28(SP)	// errno
+	MOVL	AX, r1+16(FP)
+	MOVL	DX, r2+20(FP)
+	MOVL	$0, err+24(FP)
 	CALL	runtime·exitsyscall(SB)
 	RET
 
 TEXT	·Syscall6(SB),NOSPLIT,$0-40
 	CALL	runtime·entersyscall(SB)
-	MOVL	4(SP), AX	// syscall entry
+	MOVL	trap+0(FP), AX	// syscall entry
 	// slide args down on top of system call number
-	LEAL		8(SP), SI
-	LEAL		4(SP), DI
+	LEAL		a1+4(FP), SI
+	LEAL		trap+0(FP), DI
 	CLD
 	MOVSL
 	MOVSL
@@ -55,24 +52,24 @@ TEXT	·Syscall6(SB),NOSPLIT,$0-40
 	MOVSL
 	INT	$0x80
 	JAE	ok6
-	MOVL	$-1, 32(SP)	// r1
-	MOVL	$-1, 36(SP)	// r2
-	MOVL	AX, 40(SP)		// errno
+	MOVL	$-1, r1+28(FP)
+	MOVL	$-1, r2+32(FP)
+	MOVL	AX, err+36(FP)
 	CALL	runtime·exitsyscall(SB)
 	RET
 ok6:
-	MOVL	AX, 32(SP)	// r1
-	MOVL	DX, 36(SP)	// r2
-	MOVL	$0, 40(SP)	// errno
+	MOVL	AX, r1+28(FP)
+	MOVL	DX, r2+32(FP)
+	MOVL	$0, err+36(FP)
 	CALL	runtime·exitsyscall(SB)
 	RET
 
 TEXT	·Syscall9(SB),NOSPLIT,$0-52
 	CALL	runtime·entersyscall(SB)
-	MOVL	4(SP), AX	// syscall entry
+	MOVL	num+0(FP), AX	// syscall entry
 	// slide args down on top of system call number
-	LEAL		8(SP), SI
-	LEAL		4(SP), DI
+	LEAL		a1+4(FP), SI
+	LEAL		num+0(FP), DI
 	CLD
 	MOVSL
 	MOVSL
@@ -85,44 +82,44 @@ TEXT	·Syscall9(SB),NOSPLIT,$0-52
 	MOVSL
 	INT	$0x80
 	JAE	ok9
-	MOVL	$-1, 44(SP)	// r1
-	MOVL	$-1, 48(SP)	// r2
-	MOVL	AX, 52(SP)		// errno
+	MOVL	$-1, r1+40(FP)
+	MOVL	$-1, r2+44(FP)
+	MOVL	AX, err+48(FP)
 	CALL	runtime·exitsyscall(SB)
 	RET
 ok9:
-	MOVL	AX, 44(SP)	// r1
-	MOVL	DX, 48(SP)	// r2
-	MOVL	$0, 52(SP)	// errno
+	MOVL	AX, r1+40(FP)
+	MOVL	DX, r2+44(FP)
+	MOVL	$0, err+48(FP)
 	CALL	runtime·exitsyscall(SB)
 	RET
 
 TEXT ·RawSyscall(SB),NOSPLIT,$0-28
-	MOVL	4(SP), AX	// syscall entry
+	MOVL	trap+0(FP), AX	// syscall entry
 	// slide args down on top of system call number
-	LEAL		8(SP), SI
-	LEAL		4(SP), DI
+	LEAL		a1+4(FP), SI
+	LEAL		trap+0(FP), DI
 	CLD
 	MOVSL
 	MOVSL
 	MOVSL
 	INT	$0x80
 	JAE	ok1
-	MOVL	$-1, 20(SP)	// r1
-	MOVL	$-1, 24(SP)	// r2
-	MOVL	AX, 28(SP)		// errno
+	MOVL	$-1, r1+16(FP)
+	MOVL	$-1, r2+20(FP)
+	MOVL	AX, err+24(FP)
 	RET
 ok1:
-	MOVL	AX, 20(SP)	// r1
-	MOVL	DX, 24(SP)	// r2
-	MOVL	$0, 28(SP)	// errno
+	MOVL	AX, r1+16(FP)
+	MOVL	DX, r2+20(FP)
+	MOVL	$0, err+24(FP)
 	RET
 
 TEXT	·RawSyscall6(SB),NOSPLIT,$0-40
-	MOVL	4(SP), AX	// syscall entry
+	MOVL	trap+0(FP), AX	// syscall entry
 	// slide args down on top of system call number
-	LEAL		8(SP), SI
-	LEAL		4(SP), DI
+	LEAL		a1+4(FP), SI
+	LEAL		trap+0(FP), DI
 	CLD
 	MOVSL
 	MOVSL
@@ -132,12 +129,12 @@ TEXT	·RawSyscall6(SB),NOSPLIT,$0-40
 	MOVSL
 	INT	$0x80
 	JAE	ok2
-	MOVL	$-1, 32(SP)	// r1
-	MOVL	$-1, 36(SP)	// r2
-	MOVL	AX, 40(SP)		// errno
+	MOVL	$-1, r1+28(FP)
+	MOVL	$-1, r2+32(FP)
+	MOVL	AX, err+36(FP)
 	RET
 ok2:
-	MOVL	AX, 32(SP)	// r1
-	MOVL	DX, 36(SP)	// r2
-	MOVL	$0, 40(SP)	// errno
+	MOVL	AX, r1+28(FP)
+	MOVL	DX, r2+32(FP)
+	MOVL	$0, err+36(FP)
 	RET
diff --git a/src/syscall/asm_darwin_amd64.s b/src/syscall/asm_darwin_amd64.s
index e57199d..01f461b 100644
--- a/src/syscall/asm_darwin_amd64.s
+++ b/src/syscall/asm_darwin_amd64.s
@@ -2,9 +2,6 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
-// so that go vet can check that they are correct.
-
 #include "textflag.h"
 #include "funcdata.h"
 
@@ -12,96 +9,132 @@
 // 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	16(SP), DI
-	MOVQ	24(SP), SI
-	MOVQ	32(SP), DX
+	MOVQ	a1+8(FP), DI
+	MOVQ	a2+16(FP), SI
+	MOVQ	a3+24(FP), DX
 	MOVQ	$0, R10
 	MOVQ	$0, R8
 	MOVQ	$0, R9
-	MOVQ	8(SP), AX	// syscall entry
+	MOVQ	trap+0(FP), AX	// syscall entry
 	ADDQ	$0x2000000, AX
 	SYSCALL
 	JCC	ok
-	MOVQ	$-1, 40(SP)	// r1
-	MOVQ	$0, 48(SP)	// r2
-	MOVQ	AX, 56(SP)  // errno
+	MOVQ	$-1, r1+32(FP)
+	MOVQ	$0, r2+40(FP)
+	MOVQ	AX, err+48(FP)
 	CALL	runtime·exitsyscall(SB)
 	RET
 ok:
-	MOVQ	AX, 40(SP)	// r1
-	MOVQ	DX, 48(SP)	// r2
-	MOVQ	$0, 56(SP)	// errno
+	MOVQ	AX, r1+32(FP)
+	MOVQ	DX, r2+40(FP)
+	MOVQ	$0, err+48(FP)
 	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	16(SP), DI
-	MOVQ	24(SP), SI
-	MOVQ	32(SP), DX
-	MOVQ	40(SP), R10
-	MOVQ	48(SP), R8
-	MOVQ	56(SP), R9
-	MOVQ	8(SP), 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	trap+0(FP), AX	// syscall entry
 	ADDQ	$0x2000000, AX
 	SYSCALL
 	JCC	ok6
-	MOVQ	$-1, 64(SP)	// r1
-	MOVQ	$0, 72(SP)	// r2
-	MOVQ	AX, 80(SP)  // errno
+	MOVQ	$-1, r1+56(FP)
+	MOVQ	$0, r2+64(FP)
+	MOVQ	AX, err+72(FP)
 	CALL	runtime·exitsyscall(SB)
 	RET
 ok6:
-	MOVQ	AX, 64(SP)	// r1
-	MOVQ	DX, 72(SP)	// r2
-	MOVQ	$0, 80(SP)	// errno
+	MOVQ	AX, r1+56(FP)
+	MOVQ	DX, r2+64(FP)
+	MOVQ	$0, err+72(FP)
+	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	16(SP), DI
-	MOVQ	24(SP), SI
-	MOVQ	32(SP), DX
+	MOVQ	a1+8(FP), DI
+	MOVQ	a2+16(FP), SI
+	MOVQ	a3+24(FP), DX
 	MOVQ	$0, R10
 	MOVQ	$0, R8
 	MOVQ	$0, R9
-	MOVQ	8(SP), AX	// syscall entry
+	MOVQ	trap+0(FP), AX	// syscall entry
 	ADDQ	$0x2000000, AX
 	SYSCALL
 	JCC	ok1
-	MOVQ	$-1, 40(SP)	// r1
-	MOVQ	$0, 48(SP)	// r2
-	MOVQ	AX, 56(SP)  // errno
+	MOVQ	$-1, r1+32(FP)
+	MOVQ	$0, r2+40(FP)
+	MOVQ	AX, err+48(FP)
 	RET
 ok1:
-	MOVQ	AX, 40(SP)	// r1
-	MOVQ	DX, 48(SP)	// r2
-	MOVQ	$0, 56(SP)	// errno
+	MOVQ	AX, r1+32(FP)
+	MOVQ	DX, r2+40(FP)
+	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	16(SP), DI
-	MOVQ	24(SP), SI
-	MOVQ	32(SP), DX
-	MOVQ	40(SP), R10
-	MOVQ	48(SP), R8
-	MOVQ	56(SP), R9
-	MOVQ	8(SP), 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	trap+0(FP), AX	// syscall entry
 	ADDQ	$0x2000000, AX
 	SYSCALL
 	JCC	ok2
-	MOVQ	$-1, 64(SP)	// r1
-	MOVQ	$0, 72(SP)	// r2
-	MOVQ	AX, 80(SP)  // errno
+	MOVQ	$-1, r1+56(FP)
+	MOVQ	$0, r2+64(FP)
+	MOVQ	AX, err+72(FP)
 	RET
 ok2:
-	MOVQ	AX, 64(SP)	// r1
-	MOVQ	DX, 72(SP)	// r2
-	MOVQ	$0, 80(SP)	// errno
+	MOVQ	AX, r1+56(FP)
+	MOVQ	DX, r2+64(FP)
+	MOVQ	$0, err+72(FP)
 	RET
diff --git a/src/syscall/asm_darwin_arm.s b/src/syscall/asm_darwin_arm.s
new file mode 100644
index 0000000..1a2aad0
--- /dev/null
+++ b/src/syscall/asm_darwin_arm.s
@@ -0,0 +1,134 @@
+// 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"
+
+//
+// System call support for ARM, Darwin
+//
+
+// func Syscall(syscall uintptr, a1, a2, a3 uintptr) (r1, r2, err uintptr)
+TEXT	·Syscall(SB),NOSPLIT,$0-28
+	BL		runtime·entersyscall(SB)
+	MOVW	syscall+4(SP), R12
+	MOVW	a1+8(SP), R0
+	MOVW	a2+12(SP), R1
+	MOVW	a3+16(SP), R2
+	SWI		$0x80
+	BCC		ok
+	MOVW	$-1, R1
+	MOVW	R1, r1+20(SP)	// r1
+	MOVW	$0, R2
+	MOVW	R2, r2+24(SP)	// r2
+	MOVW	R0, errno+28(SP)	// errno
+	BL		runtime·exitsyscall(SB)
+	RET
+ok:
+	MOVW	R0, r1+20(SP) // r1
+	MOVW	R1, r2+24(SP)	// r2
+	MOVW	$0, R0
+	MOVW	R0, errno+28(SP)	// errno
+	BL		runtime·exitsyscall(SB)
+	RET
+
+// func RawSyscall(trap uintptr, a1, a2, a3 uintptr) (r1, r2, err uintptr)
+TEXT ·RawSyscall(SB),NOSPLIT,$0-28
+	MOVW	syscall+4(SP), R12	// syscall entry
+	MOVW	a1+8(SP), R0
+	MOVW	a2+12(SP), R1
+	MOVW	a3+16(SP), R2
+	SWI		$0x80
+	BCC		ok1
+	MOVW	$-1, R1
+	MOVW	R1, r1+20(SP)	// r1
+	MOVW	$0, R2
+	MOVW	R2, r2+24(SP)	// r2
+	MOVW	R0, errno+28(SP)	// errno
+	RET
+ok1:
+	MOVW	R0, r1+20(SP) // r1
+	MOVW	R1, r2+24(SP)	// r2
+	MOVW	$0, R0
+	MOVW	R0, errno+28(SP)	// errno
+	RET
+
+// func Syscall6(trap uintptr, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
+TEXT	·Syscall6(SB),NOSPLIT,$0-40
+	BL		runtime·entersyscall(SB)
+	MOVW	syscall+4(SP), R12	// syscall entry
+	MOVW	a1+8(SP), R0
+	MOVW	a2+12(SP), R1
+	MOVW	a3+16(SP), R2
+	MOVW	a4+20(SP), R3
+	MOVW	a5+24(SP), R4
+	MOVW	a6+28(SP), R5
+	SWI		$0x80
+	BCC		ok6
+	MOVW	$-1, R1
+	MOVW	R1, r1+32(SP)	// r1
+	MOVW	$0, R2
+	MOVW	R2, r2+36(SP)	// r2
+	MOVW	R0, errno+40(SP)	// errno
+	BL		runtime·exitsyscall(SB)
+	RET
+ok6:
+	MOVW	R0, r1+32(SP) // r1
+	MOVW	R1, r2+36(SP)	// r2
+	MOVW	$0, R0
+	MOVW	R0, errno+40(SP)	// errno
+	BL		runtime·exitsyscall(SB)
+	RET
+
+// func RawSyscall6(trap uintptr, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
+TEXT	·RawSyscall6(SB),NOSPLIT,$0-40
+	MOVW	trap+4(SP), R12	// syscall entry
+	MOVW	a1+8(SP), R0
+	MOVW	a2+12(SP), R1
+	MOVW	a3+16(SP), R2
+	MOVW	a4+20(SP), R3
+	MOVW	a5+24(SP), R4
+	MOVW	a6+28(SP), R5
+	SWI		$0x80
+	BCC		ok2
+	MOVW	$-1, R1
+	MOVW	R1, r1+32(SP)	// r1
+	MOVW	$0, R2
+	MOVW	R2, r2+36(SP)	// r2
+	MOVW	R0, errno+40(SP)	// errno
+	RET
+ok2:
+	MOVW	R0, r1+32(SP) // r1
+	MOVW	R1, r2+36(SP)	// r2
+	MOVW	$0, R0
+	MOVW	R0, errno+40(SP)	// errno
+	RET
+
+// Actually Syscall7.
+TEXT	·Syscall9(SB),NOSPLIT,$0-52
+	BL runtime·entersyscall(SB)
+	MOVW	syscall+4(SP), R12	// syscall entry
+	MOVW	a1+8(SP), R0
+	MOVW	a2+12(SP), R1
+	MOVW	a3+16(SP), R2
+	MOVW	a4+20(SP), R3
+	MOVW	a5+24(SP), R4
+	MOVW	a6+28(SP), R5
+	MOVW	a7+32(SP), R6
+	SWI		$0x80
+	BCC		ok9
+	MOVW	$-1, R1
+	MOVW	R1, r1+44(SP)	// r1
+	MOVW	$0, R2
+	MOVW	R2, r2+48(SP)	// r2
+	MOVW	R0, errno+52(SP)	// errno
+	BL		runtime·exitsyscall(SB)
+	RET
+ok9:
+	MOVW	R0, r1+44(SP) // r1
+	MOVW	R1, r2+48(SP)	// r2
+	MOVW	$0, R0
+	MOVW	R0, errno+52(SP)	// errno
+	BL	runtime·exitsyscall(SB)
+	RET
+
diff --git a/src/syscall/asm_darwin_arm64.s b/src/syscall/asm_darwin_arm64.s
new file mode 100644
index 0000000..e18ff6a
--- /dev/null
+++ b/src/syscall/asm_darwin_arm64.s
@@ -0,0 +1,127 @@
+// 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"
+
+//
+// System call support for ARM64, Darwin
+//
+
+// func Syscall(syscall uintptr, a1, a2, a3 uintptr) (r1, r2, err uintptr)
+TEXT	·Syscall(SB),NOSPLIT,$0-56
+	BL	runtime·entersyscall(SB)
+	MOVD	syscall+0(FP), R16
+	MOVD	a1+8(FP), R0
+	MOVD	a2+16(FP), R1
+	MOVD	a3+24(FP), R2
+	SVC	$0x80
+	BCC	ok
+	MOVD	$-1, R1
+	MOVD	R1, r1+32(FP)	// r1
+	MOVD	ZR, r2+40(FP)	// r2
+	MOVD	R0, errno+48(FP)	// errno
+	BL	runtime·exitsyscall(SB)
+	RET
+ok:
+	MOVD	R0, r1+32(FP) // r1
+	MOVD	R1, r2+40(FP)	// r2
+	MOVD	ZR, errno+48(FP)	// errno
+	BL	runtime·exitsyscall(SB)
+	RET
+
+// func RawSyscall(trap uintptr, a1, a2, a3 uintptr) (r1, r2, err uintptr)
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
+	MOVD	syscall+0(FP), R16	// syscall entry
+	MOVD	a1+8(FP), R0
+	MOVD	a2+16(FP), R1
+	MOVD	a3+24(FP), R2
+	SVC	$0x80
+	BCC	ok
+	MOVD	$-1, R1
+	MOVD	R1, r1+32(FP)	// r1
+	MOVD	ZR, r2+40(FP)	// r2
+	MOVD	R0, errno+48(FP)	// errno
+	RET
+ok:
+	MOVD	R0, r1+32(FP) // r1
+	MOVD	R1, r2+40(FP)	// r2
+	MOVD	ZR, errno+48(FP)	// errno
+	RET
+
+// func Syscall6(trap uintptr, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
+TEXT	·Syscall6(SB),NOSPLIT,$0-80
+	BL	runtime·entersyscall(SB)
+	MOVD	syscall+0(FP), R16	// syscall entry
+	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
+	SVC	$0x80
+	BCC	ok
+	MOVD	$-1, R1
+	MOVD	R1, r1+56(FP)	// r1
+	MOVD	ZR, r2+64(FP)	// r2
+	MOVD	R0, errno+72(FP)	// errno
+	BL	runtime·exitsyscall(SB)
+	RET
+ok:
+	MOVD	R0, r1+56(FP) // r1
+	MOVD	R1, r2+64(FP)	// r2
+	MOVD	ZR, errno+72(FP)	// errno
+	BL	runtime·exitsyscall(SB)
+	RET
+
+// func RawSyscall6(trap uintptr, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
+TEXT	·RawSyscall6(SB),NOSPLIT,$0-80
+	MOVD	trap+0(FP), R16	// syscall entry
+	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
+	SVC	$0x80
+	BCC	ok
+	MOVD	$-1, R1
+	MOVD	R1, r1+56(FP)	// r1
+	MOVD	ZR, r2+64(FP)	// r2
+	MOVD	R0, errno+72(FP)	// errno
+	RET
+ok:
+	MOVD	R0, r1+56(FP) // r1
+	MOVD	R1, r2+64(FP)	// r2
+	MOVD	ZR, R0
+	MOVD	R0, errno+72(FP)	// errno
+	RET
+
+// Actually Syscall7
+TEXT	·Syscall9(SB),NOSPLIT,$0-104
+	BL	runtime·entersyscall(SB)
+	MOVD	syscall+0(FP), R16	// syscall entry
+	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	a7+56(FP), R6
+	//MOVD	a8+64(FP), R7
+	//MOVD	a9+72(FP), R8
+	SVC	$0x80
+	BCC	ok
+	MOVD	$-1, R1
+	MOVD	R1, r1+80(FP)	// r1
+	MOVD	ZR, r2+88(FP)	// r2
+	MOVD	R0, errno+96(FP)	// errno
+	BL	runtime·exitsyscall(SB)
+	RET
+ok:
+	MOVD	R0, r1+80(FP) // r1
+	MOVD	R1, r2+88(FP)	// r2
+	MOVD	ZR, errno+96(FP)	// errno
+	BL	runtime·exitsyscall(SB)
+	RET
+
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_freebsd_amd64.s b/src/syscall/asm_freebsd_amd64.s
index c525190..c6988c9 100644
--- a/src/syscall/asm_freebsd_amd64.s
+++ b/src/syscall/asm_freebsd_amd64.s
@@ -12,11 +12,6 @@
 // System call support for AMD64, FreeBSD
 //
 
-// The SYSCALL variant for invoking system calls is broken in FreeBSD.
-// See comment at top of ../runtime/sys_freebsd_amd64.c and
-// golang.org/issue/6372.
-#define SYSCALL MOVQ R10, CX; INT $0x80
-
 // 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);
 // func Syscall9(trap int64, a1, a2, a3, a4, a5, a6, a7, a8, a9 int64) (r1, r2, err int64)
diff --git a/src/syscall/asm_freebsd_arm.s b/src/syscall/asm_freebsd_arm.s
index 6b0c182..64d9dee 100644
--- a/src/syscall/asm_freebsd_arm.s
+++ b/src/syscall/asm_freebsd_arm.s
@@ -15,116 +15,116 @@
 
 TEXT	·Syscall(SB),NOSPLIT,$0-28
 	BL runtime·entersyscall(SB)
-	MOVW 0(FP), R7 // syscall number
-	MOVW 4(FP), R0 // a1
-	MOVW 8(FP), R1 // a2
-	MOVW 12(FP), R2 // a3
+	MOVW trap+0(FP), R7 // syscall number
+	MOVW a1+4(FP), R0 // a1
+	MOVW a2+8(FP), R1 // a2
+	MOVW a3+12(FP), R2 // a3
 	SWI $0 // syscall
 	MOVW $0, R2
 	BCS error
-	MOVW R0, 16(FP) // r1
-	MOVW R1, 20(FP) // r2
-	MOVW R2, 24(FP) // errno
+	MOVW R0, r1+16(FP) // r1
+	MOVW R1, r2+20(FP) // r2
+	MOVW R2, err+24(FP) // errno
 	BL runtime·exitsyscall(SB)
 	RET
 error:
 	MOVW $-1, R3
-	MOVW R3, 16(FP) // r1
-	MOVW R2, 20(FP) // r2
-	MOVW R0, 24(FP) // errno
+	MOVW R3, r1+16(FP) // r1
+	MOVW R2, r2+20(FP) // r2
+	MOVW R0, err+24(FP) // errno
 	BL runtime·exitsyscall(SB)
 	RET
 
 TEXT	·Syscall6(SB),NOSPLIT,$0-40
 	BL runtime·entersyscall(SB)
-	MOVW 0(FP), R7 // syscall number
-	MOVW 4(FP), R0 // a1
-	MOVW 8(FP), R1 // a2
-	MOVW 12(FP), R2 // a3
-	MOVW 16(FP), R3 // a4
+	MOVW trap+0(FP), R7 // syscall number
+	MOVW a1+4(FP), R0 // a1
+	MOVW a2+8(FP), R1 // a2
+	MOVW a3+12(FP), R2 // a3
+	MOVW a4+16(FP), R3 // a4
 	MOVW R13, R4
-	MOVW $20(FP), R13 // a5 to a6 are passed on stack
+	MOVW $a5+20(FP), R13 // a5 to a6 are passed on stack
 	SWI $0 // syscall
 	MOVW R4, R13
 	MOVW $0, R2
 	BCS error6
-	MOVW R0, 28(FP) // r1
-	MOVW R1, 32(FP) // r2
-	MOVW R2, 36(FP) // errno
+	MOVW R0, r1+28(FP) // r1
+	MOVW R1, r2+32(FP) // r2
+	MOVW R2, err+36(FP) // errno
 	BL runtime·exitsyscall(SB)
 	RET
 error6:
 	MOVW $-1, R3
-	MOVW R3, 28(FP) // r1
-	MOVW R2, 32(FP) // r2
-	MOVW R0, 36(FP) // errno
+	MOVW R3, r1+28(FP) // r1
+	MOVW R2, r2+32(FP) // r2
+	MOVW R0, err+36(FP) // errno
 	BL runtime·exitsyscall(SB)
 	RET
 
 TEXT	·Syscall9(SB),NOSPLIT,$0-52
 	BL runtime·entersyscall(SB)
-	MOVW 0(FP), R7 // syscall number
-	MOVW 4(FP), R0 // a1
-	MOVW 8(FP), R1 // a2
-	MOVW 12(FP), R2 // a3
-	MOVW 16(FP), R3 // a4
+	MOVW num+0(FP), R7 // syscall number
+	MOVW a1+4(FP), R0 // a1
+	MOVW a2+8(FP), R1 // a2
+	MOVW a3+12(FP), R2 // a3
+	MOVW a4+16(FP), R3 // a4
 	MOVW R13, R4
-	MOVW $20(FP), R13 // a5 to a9 are passed on stack
+	MOVW $a5+20(FP), R13 // a5 to a9 are passed on stack
 	SWI $0 // syscall
 	MOVW R4, R13
 	MOVW $0, R2
 	BCS error9
-	MOVW R0, 40(FP) // r1
-	MOVW R1, 44(FP) // r2
-	MOVW R2, 48(FP) // errno
+	MOVW R0, r1+40(FP) // r1
+	MOVW R1, r2+44(FP) // r2
+	MOVW R2, err+48(FP) // errno
 	BL runtime·exitsyscall(SB)
 	RET
 error9:
 	MOVW $-1, R3
-	MOVW R3, 40(FP) // r1
-	MOVW R2, 44(FP) // r2
-	MOVW R0, 48(FP) // errno
+	MOVW R3, r1+40(FP) // r1
+	MOVW R2, r2+44(FP) // r2
+	MOVW R0, err+48(FP) // errno
 	BL runtime·exitsyscall(SB)
 	RET
 
 TEXT	·RawSyscall(SB),NOSPLIT,$0-28
-	MOVW 0(FP), R7 // syscall number
-	MOVW 4(FP), R0 // a1
-	MOVW 8(FP), R1 // a2
-	MOVW 12(FP), R2 // a3
+	MOVW trap+0(FP), R7 // syscall number
+	MOVW a1+4(FP), R0 // a1
+	MOVW a2+8(FP), R1 // a2
+	MOVW a3+12(FP), R2 // a3
 	SWI $0 // syscall
 	MOVW $0, R2
 	BCS errorr
-	MOVW R0, 16(FP) // r1
-	MOVW R1, 20(FP) // r2
-	MOVW R2, 24(FP) // errno
+	MOVW R0, r1+16(FP) // r1
+	MOVW R1, r2+20(FP) // r2
+	MOVW R2, err+24(FP) // errno
 	RET
 errorr:
 	MOVW $-1, R3
-	MOVW R3, 16(FP) // r1
-	MOVW R2, 20(FP) // r2
-	MOVW R0, 24(FP) // errno
+	MOVW R3, r1+16(FP) // r1
+	MOVW R2, r2+20(FP) // r2
+	MOVW R0, err+24(FP) // errno
 	RET
 
 TEXT	·RawSyscall6(SB),NOSPLIT,$0-40
-	MOVW 0(FP), R7 // syscall number
-	MOVW 4(FP), R0 // a1
-	MOVW 8(FP), R1 // a2
-	MOVW 12(FP), R2 // a3
-	MOVW 16(FP), R3 // a4
+	MOVW trap+0(FP), R7 // syscall number
+	MOVW a1+4(FP), R0 // a1
+	MOVW a2+8(FP), R1 // a2
+	MOVW a3+12(FP), R2 // a3
+	MOVW a4+16(FP), R3 // a4
 	MOVW R13, R4
-	MOVW $20(FP), R13 // a5 to a6 are passed on stack
+	MOVW $a5+20(FP), R13 // a5 to a6 are passed on stack
 	SWI $0 // syscall
 	MOVW R4, R13
 	MOVW $0, R2
 	BCS errorr6
-	MOVW R0, 28(FP) // r1
-	MOVW R1, 32(FP) // r2
-	MOVW R2, 36(FP) // errno
+	MOVW R0, r1+28(FP) // r1
+	MOVW R1, r2+32(FP) // r2
+	MOVW R2, err+36(FP) // errno
 	RET
 errorr6:
 	MOVW $-1, R3
-	MOVW R3, 28(FP) // r1
-	MOVW R2, 32(FP) // r2
-	MOVW R0, 36(FP) // errno
+	MOVW R3, r1+28(FP) // r1
+	MOVW R2, r2+32(FP) // r2
+	MOVW R0, err+36(FP) // errno
 	RET
diff --git a/src/syscall/asm_linux_386.s b/src/syscall/asm_linux_386.s
index fa1b371..ec7487b 100644
--- a/src/syscall/asm_linux_386.s
+++ b/src/syscall/asm_linux_386.s
@@ -2,9 +2,6 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
-// so that go vet can check that they are correct.
-
 #include "textflag.h"
 #include "funcdata.h"
 
@@ -17,148 +14,148 @@
 
 TEXT	·Syscall(SB),NOSPLIT,$0-28
 	CALL	runtime·entersyscall(SB)
-	MOVL	4(SP), AX	// syscall entry
-	MOVL	8(SP), BX
-	MOVL	12(SP), CX
-	MOVL	16(SP), DX
+	MOVL	trap+0(FP), AX	// syscall entry
+	MOVL	a1+4(FP), BX
+	MOVL	a2+8(FP), CX
+	MOVL	a3+12(FP), DX
 	MOVL	$0, SI
 	MOVL	$0,  DI
 	CALL	*runtime·_vdso(SB)
 	CMPL	AX, $0xfffff001
 	JLS	ok
-	MOVL	$-1, 20(SP)	// r1
-	MOVL	$0, 24(SP)	// r2
+	MOVL	$-1, r1+16(FP)
+	MOVL	$0, r2+20(FP)
 	NEGL	AX
-	MOVL	AX, 28(SP)  // errno
+	MOVL	AX, err+24(FP)
 	CALL	runtime·exitsyscall(SB)
 	RET
 ok:
-	MOVL	AX, 20(SP)	// r1
-	MOVL	DX, 24(SP)	// r2
-	MOVL	$0, 28(SP)	// errno
+	MOVL	AX, r1+16(FP)
+	MOVL	DX, r2+20(FP)
+	MOVL	$0, err+24(FP)
 	CALL	runtime·exitsyscall(SB)
 	RET
 
 // func Syscall6(trap uintptr, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr);
 TEXT	·Syscall6(SB),NOSPLIT,$0-40
 	CALL	runtime·entersyscall(SB)
-	MOVL	4(SP), AX	// syscall entry
-	MOVL	8(SP), BX
-	MOVL	12(SP), CX
-	MOVL	16(SP), DX
-	MOVL	20(SP), SI
-	MOVL	24(SP), DI
-	MOVL	28(SP), BP
+	MOVL	trap+0(FP), AX	// syscall entry
+	MOVL	a1+4(FP), BX
+	MOVL	a2+8(FP), CX
+	MOVL	a3+12(FP), DX
+	MOVL	a4+16(FP), SI
+	MOVL	a5+20(FP), DI
+	MOVL	a6+24(FP), BP
 	CALL	*runtime·_vdso(SB)
 	CMPL	AX, $0xfffff001
 	JLS	ok6
-	MOVL	$-1, 32(SP)	// r1
-	MOVL	$0, 36(SP)	// r2
+	MOVL	$-1, r1+28(FP)
+	MOVL	$0, r2+32(FP)
 	NEGL	AX
-	MOVL	AX, 40(SP)  // errno
+	MOVL	AX, err+36(FP)
 	CALL	runtime·exitsyscall(SB)
 	RET
 ok6:
-	MOVL	AX, 32(SP)	// r1
-	MOVL	DX, 36(SP)	// r2
-	MOVL	$0, 40(SP)	// errno
+	MOVL	AX, r1+28(FP)
+	MOVL	DX, r2+32(FP)
+	MOVL	$0, err+36(FP)
 	CALL	runtime·exitsyscall(SB)
 	RET
 
 // func RawSyscall(trap uintptr, a1, a2, a3 uintptr) (r1, r2, err uintptr);
 TEXT ·RawSyscall(SB),NOSPLIT,$0-28
-	MOVL	4(SP), AX	// syscall entry
-	MOVL	8(SP), BX
-	MOVL	12(SP), CX
-	MOVL	16(SP), DX
+	MOVL	trap+0(FP), AX	// syscall entry
+	MOVL	a1+4(FP), BX
+	MOVL	a2+8(FP), CX
+	MOVL	a3+12(FP), DX
 	MOVL	$0, SI
 	MOVL	$0,  DI
 	CALL	*runtime·_vdso(SB)
 	CMPL	AX, $0xfffff001
 	JLS	ok1
-	MOVL	$-1, 20(SP)	// r1
-	MOVL	$0, 24(SP)	// r2
+	MOVL	$-1, r1+16(FP)
+	MOVL	$0, r2+20(FP)
 	NEGL	AX
-	MOVL	AX, 28(SP)  // errno
+	MOVL	AX, err+24(FP)
 	RET
 ok1:
-	MOVL	AX, 20(SP)	// r1
-	MOVL	DX, 24(SP)	// r2
-	MOVL	$0, 28(SP)	// errno
+	MOVL	AX, r1+16(FP)
+	MOVL	DX, r2+20(FP)
+	MOVL	$0, err+24(FP)
 	RET
 
 // func RawSyscall6(trap uintptr, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr);
 TEXT	·RawSyscall6(SB),NOSPLIT,$0-40
-	MOVL	4(SP), AX	// syscall entry
-	MOVL	8(SP), BX
-	MOVL	12(SP), CX
-	MOVL	16(SP), DX
-	MOVL	20(SP), SI
-	MOVL	24(SP), DI
-	MOVL	28(SP), BP
+	MOVL	trap+0(FP), AX	// syscall entry
+	MOVL	a1+4(FP), BX
+	MOVL	a2+8(FP), CX
+	MOVL	a3+12(FP), DX
+	MOVL	a4+16(FP), SI
+	MOVL	a5+20(FP), DI
+	MOVL	a6+24(FP), BP
 	CALL	*runtime·_vdso(SB)
 	CMPL	AX, $0xfffff001
 	JLS	ok2
-	MOVL	$-1, 32(SP)	// r1
-	MOVL	$0, 36(SP)	// r2
+	MOVL	$-1, r1+28(FP)
+	MOVL	$0, r2+32(FP)
 	NEGL	AX
-	MOVL	AX, 40(SP)  // errno
+	MOVL	AX, err+36(FP)
 	RET
 ok2:
-	MOVL	AX, 32(SP)	// r1
-	MOVL	DX, 36(SP)	// r2
-	MOVL	$0, 40(SP)	// errno
+	MOVL	AX, r1+28(FP)
+	MOVL	DX, r2+32(FP)
+	MOVL	$0, err+36(FP)
 	RET
 
 #define SYS_SOCKETCALL 102	/* from zsysnum_linux_386.go */
 
-// func socketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, errno int)
+// func socketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, err int)
 // Kernel interface gets call sub-number and pointer to a0.
 TEXT ·socketcall(SB),NOSPLIT,$0-36
 	CALL	runtime·entersyscall(SB)
 	MOVL	$SYS_SOCKETCALL, AX	// syscall entry
-	MOVL	4(SP), BX	// socket call number
-	LEAL		8(SP), CX	// pointer to call arguments
+	MOVL	call+0(FP), BX	// socket call number
+	LEAL		a0+4(FP), CX	// pointer to call arguments
 	MOVL	$0, DX
 	MOVL	$0, SI
 	MOVL	$0,  DI
 	CALL	*runtime·_vdso(SB)
 	CMPL	AX, $0xfffff001
 	JLS	oksock
-	MOVL	$-1, 32(SP)	// n
+	MOVL	$-1, n+28(FP)
 	NEGL	AX
-	MOVL	AX, 36(SP)  // errno
+	MOVL	AX, err+32(FP)
 	CALL	runtime·exitsyscall(SB)
 	RET
 oksock:
-	MOVL	AX, 32(SP)	// n
-	MOVL	$0, 36(SP)	// errno
+	MOVL	AX, n+28(FP)
+	MOVL	$0, err+32(FP)
 	CALL	runtime·exitsyscall(SB)
 	RET
 
-// func rawsocketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, errno int)
+// func rawsocketcall(call int, a0, a1, a2, a3, a4, a5 uintptr) (n int, err int)
 // Kernel interface gets call sub-number and pointer to a0.
 TEXT ·rawsocketcall(SB),NOSPLIT,$0-36
 	MOVL	$SYS_SOCKETCALL, AX	// syscall entry
-	MOVL	4(SP), BX	// socket call number
-	LEAL		8(SP), CX	// pointer to call arguments
+	MOVL	call+0(FP), BX	// socket call number
+	LEAL		a0+4(FP), CX	// pointer to call arguments
 	MOVL	$0, DX
 	MOVL	$0, SI
 	MOVL	$0,  DI
 	CALL	*runtime·_vdso(SB)
 	CMPL	AX, $0xfffff001
 	JLS	oksock1
-	MOVL	$-1, 32(SP)	// n
+	MOVL	$-1, n+28(FP)
 	NEGL	AX
-	MOVL	AX, 36(SP)  // errno
+	MOVL	AX, err+32(FP)
 	RET
 oksock1:
-	MOVL	AX, 32(SP)	// n
-	MOVL	$0, 36(SP)	// errno
+	MOVL	AX, n+28(FP)
+	MOVL	$0, err+32(FP)
 	RET
 
 #define SYS__LLSEEK 140	/* from zsysnum_linux_386.go */
-// func Seek(fd int, offset int64, whence int) (newoffset int64, errno int)
+// func Seek(fd int, offset int64, whence int) (newoffset int64, err int)
 // Implemented in assembly to avoid allocation when
 // taking the address of the return value newoffset.
 // Underlying system call is
@@ -166,22 +163,22 @@ oksock1:
 TEXT ·seek(SB),NOSPLIT,$0-28
 	CALL	runtime·entersyscall(SB)
 	MOVL	$SYS__LLSEEK, AX	// syscall entry
-	MOVL	4(SP), BX	// fd
-	MOVL	12(SP), CX	// offset-high
-	MOVL	8(SP), DX	// offset-low
-	LEAL	20(SP), SI	// result pointer
-	MOVL	16(SP),  DI	// whence
+	MOVL	fd+0(FP), BX
+	MOVL	offset_hi+8(FP), CX
+	MOVL	offset_lo+4(FP), DX
+	LEAL	newoffset_lo+16(FP), SI	// result pointer
+	MOVL	whence+12(FP),  DI
 	CALL	*runtime·_vdso(SB)
 	CMPL	AX, $0xfffff001
 	JLS	okseek
-	MOVL	$-1, 20(SP)	// newoffset low
-	MOVL	$-1, 24(SP)	// newoffset high
+	MOVL	$-1, newoffset_lo+16(FP)
+	MOVL	$-1, newoffset_hi+20(FP)
 	NEGL	AX
-	MOVL	AX, 28(SP)  // errno
+	MOVL	AX, err+24(FP)
 	CALL	runtime·exitsyscall(SB)
 	RET
 okseek:
 	// system call filled in newoffset already
-	MOVL	$0, 28(SP)	// errno
+	MOVL	$0, err+24(FP)
 	CALL	runtime·exitsyscall(SB)
 	RET
diff --git a/src/syscall/asm_linux_amd64.s b/src/syscall/asm_linux_amd64.s
index b3ce216..6634875 100644
--- a/src/syscall/asm_linux_amd64.s
+++ b/src/syscall/asm_linux_amd64.s
@@ -2,9 +2,6 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// TODO(rsc): Rewrite all nn(SP) references into name+(nn-8)(FP)
-// so that go vet can check that they are correct.
-
 #include "textflag.h"
 #include "funcdata.h"
 
@@ -19,100 +16,104 @@
 
 TEXT	·Syscall(SB),NOSPLIT,$0-56
 	CALL	runtime·entersyscall(SB)
-	MOVQ	16(SP), DI
-	MOVQ	24(SP), SI
-	MOVQ	32(SP), DX
+	MOVQ	a1+8(FP), DI
+	MOVQ	a2+16(FP), SI
+	MOVQ	a3+24(FP), DX
 	MOVQ	$0, R10
 	MOVQ	$0, R8
 	MOVQ	$0, R9
-	MOVQ	8(SP), AX	// syscall entry
+	MOVQ	trap+0(FP), AX	// syscall entry
 	SYSCALL
 	CMPQ	AX, $0xfffffffffffff001
 	JLS	ok
-	MOVQ	$-1, 40(SP)	// r1
-	MOVQ	$0, 48(SP)	// r2
+	MOVQ	$-1, r1+32(FP)
+	MOVQ	$0, r2+40(FP)
 	NEGQ	AX
-	MOVQ	AX, 56(SP)  // errno
+	MOVQ	AX, err+48(FP)
 	CALL	runtime·exitsyscall(SB)
 	RET
 ok:
-	MOVQ	AX, 40(SP)	// r1
-	MOVQ	DX, 48(SP)	// r2
-	MOVQ	$0, 56(SP)	// errno
+	MOVQ	AX, r1+32(FP)
+	MOVQ	DX, r2+40(FP)
+	MOVQ	$0, err+48(FP)
 	CALL	runtime·exitsyscall(SB)
 	RET
 
+// func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
 TEXT ·Syscall6(SB),NOSPLIT,$0-80
 	CALL	runtime·entersyscall(SB)
-	MOVQ	16(SP), DI
-	MOVQ	24(SP), SI
-	MOVQ	32(SP), DX
-	MOVQ	40(SP), R10
-	MOVQ	48(SP), R8
-	MOVQ	56(SP), R9
-	MOVQ	8(SP), 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	trap+0(FP), AX	// syscall entry
 	SYSCALL
 	CMPQ	AX, $0xfffffffffffff001
 	JLS	ok6
-	MOVQ	$-1, 64(SP)	// r1
-	MOVQ	$0, 72(SP)	// r2
+	MOVQ	$-1, r1+56(FP)
+	MOVQ	$0, r2+64(FP)
 	NEGQ	AX
-	MOVQ	AX, 80(SP)  // errno
+	MOVQ	AX, err+72(FP)
 	CALL	runtime·exitsyscall(SB)
 	RET
 ok6:
-	MOVQ	AX, 64(SP)	// r1
-	MOVQ	DX, 72(SP)	// r2
-	MOVQ	$0, 80(SP)	// errno
+	MOVQ	AX, r1+56(FP)
+	MOVQ	DX, r2+64(FP)
+	MOVQ	$0, err+72(FP)
 	CALL	runtime·exitsyscall(SB)
 	RET
 
+// func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
 TEXT ·RawSyscall(SB),NOSPLIT,$0-56
-	MOVQ	16(SP), DI
-	MOVQ	24(SP), SI
-	MOVQ	32(SP), DX
+	MOVQ	a1+8(FP), DI
+	MOVQ	a2+16(FP), SI
+	MOVQ	a3+24(FP), DX
 	MOVQ	$0, R10
 	MOVQ	$0, R8
 	MOVQ	$0, R9
-	MOVQ	8(SP), AX	// syscall entry
+	MOVQ	trap+0(FP), AX	// syscall entry
 	SYSCALL
 	CMPQ	AX, $0xfffffffffffff001
 	JLS	ok1
-	MOVQ	$-1, 40(SP)	// r1
-	MOVQ	$0, 48(SP)	// r2
+	MOVQ	$-1, r1+32(FP)
+	MOVQ	$0, r2+40(FP)
 	NEGQ	AX
-	MOVQ	AX, 56(SP)  // errno
+	MOVQ	AX, err+48(FP)
 	RET
 ok1:
-	MOVQ	AX, 40(SP)	// r1
-	MOVQ	DX, 48(SP)	// r2
-	MOVQ	$0, 56(SP)	// errno
+	MOVQ	AX, r1+32(FP)
+	MOVQ	DX, r2+40(FP)
+	MOVQ	$0, err+48(FP)
 	RET
 
+// func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
 TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
-	MOVQ	16(SP), DI
-	MOVQ	24(SP), SI
-	MOVQ	32(SP), DX
-	MOVQ	40(SP), R10
-	MOVQ	48(SP), R8
-	MOVQ	56(SP), R9
-	MOVQ	8(SP), 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	trap+0(FP), AX	// syscall entry
 	SYSCALL
 	CMPQ	AX, $0xfffffffffffff001
 	JLS	ok2
-	MOVQ	$-1, 64(SP)	// r1
-	MOVQ	$0, 72(SP)	// r2
+	MOVQ	$-1, r1+56(FP)
+	MOVQ	$0, r2+64(FP)
 	NEGQ	AX
-	MOVQ	AX, 80(SP)  // errno
+	MOVQ	AX, err+72(FP)
 	RET
 ok2:
-	MOVQ	AX, 64(SP)	// r1
-	MOVQ	DX, 72(SP)	// r2
-	MOVQ	$0, 80(SP)	// errno
+	MOVQ	AX, r1+56(FP)
+	MOVQ	DX, r2+64(FP)
+	MOVQ	$0, err+72(FP)
 	RET
 
+// func gettimeofday(tv *Timeval) (err uintptr)
 TEXT ·gettimeofday(SB),NOSPLIT,$0-16
-	MOVQ	8(SP), DI
+	MOVQ	tv+0(FP), DI
 	MOVQ	$0, SI
 	MOVQ	runtime·__vdso_gettimeofday_sym(SB), AX
 	CALL	AX
@@ -120,8 +121,8 @@ TEXT ·gettimeofday(SB),NOSPLIT,$0-16
 	CMPQ	AX, $0xfffffffffffff001
 	JLS	ok7
 	NEGQ	AX
-	MOVQ	AX, 16(SP)  // errno
+	MOVQ	AX, err+8(FP)
 	RET
 ok7:
-	MOVQ	$0, 16(SP)  // errno
+	MOVQ	$0, err+8(FP)
 	RET
diff --git a/src/syscall/asm_linux_arm.s b/src/syscall/asm_linux_arm.s
index 3526533..997ba6f 100644
--- a/src/syscall/asm_linux_arm.s
+++ b/src/syscall/asm_linux_arm.s
@@ -15,10 +15,10 @@
 
 TEXT	·Syscall(SB),NOSPLIT,$0-28
 	BL		runtime·entersyscall(SB)
-	MOVW	4(SP), R7
-	MOVW	8(SP), R0
-	MOVW	12(SP), R1
-	MOVW	16(SP), R2
+	MOVW	trap+0(FP), R7
+	MOVW	a1+4(FP), R0
+	MOVW	a2+8(FP), R1
+	MOVW	a3+12(FP), R2
 	MOVW	$0, R3
 	MOVW	$0, R4
 	MOVW	$0, R5
@@ -27,18 +27,18 @@ TEXT	·Syscall(SB),NOSPLIT,$0-28
 	CMP		R1, R0
 	BLS		ok
 	MOVW	$-1, R1
-	MOVW	R1, 20(SP)	// r1
+	MOVW	R1, r1+16(FP)
 	MOVW	$0, R2
-	MOVW	R2, 24(SP)	// r2
+	MOVW	R2, r2+20(FP)
 	RSB		$0, R0, R0
-	MOVW	R0, 28(SP)	// errno
+	MOVW	R0, err+24(FP)
 	BL		runtime·exitsyscall(SB)
 	RET
 ok:
-	MOVW	R0, 20(SP) // r1
+	MOVW	R0, r1+16(FP)
 	MOVW	$0, R0
-	MOVW	R0, 24(SP)	// r2
-	MOVW	R0, 28(SP)	// errno
+	MOVW	R0, r2+20(FP)
+	MOVW	R0, err+24(FP)
 	BL		runtime·exitsyscall(SB)
 	RET
 
@@ -46,59 +46,59 @@ ok:
 // Actually Syscall5 but the rest of the code expects it to be named Syscall6.
 TEXT	·Syscall6(SB),NOSPLIT,$0-40
 	BL		runtime·entersyscall(SB)
-	MOVW	4(SP), R7	// syscall entry
-	MOVW	8(SP), R0
-	MOVW	12(SP), R1
-	MOVW	16(SP), R2
-	MOVW	20(SP), R3
-	MOVW	24(SP), R4
-	MOVW	28(SP), R5
+	MOVW	trap+0(FP), R7	// syscall entry
+	MOVW	a1+4(FP), R0
+	MOVW	a2+8(FP), R1
+	MOVW	a3+12(FP), R2
+	MOVW	a4+16(FP), R3
+	MOVW	a5+20(FP), R4
+	MOVW	a6+24(FP), R5
 	SWI		$0
 	MOVW	$0xfffff001, R6
 	CMP		R6, R0
 	BLS		ok6
 	MOVW	$-1, R1
-	MOVW	R1, 32(SP)	// r1
+	MOVW	R1, r1+28(FP)
 	MOVW	$0, R2
-	MOVW	R2, 36(SP)	// r2
+	MOVW	R2, r2+32(FP)
 	RSB		$0, R0, R0
-	MOVW	R0, 40(SP)	// errno
+	MOVW	R0, err+36(FP)
 	BL		runtime·exitsyscall(SB)
 	RET
 ok6:
-	MOVW	R0, 32(SP) // r1
-	MOVW	R1, 36(SP)	// r2
+	MOVW	R0, r1+28(FP)
+	MOVW	R1, r2+32(FP)
 	MOVW	$0, R0
-	MOVW	R0, 40(SP)	// errno
+	MOVW	R0, err+36(FP)
 	BL		runtime·exitsyscall(SB)
 	RET
 
 // func RawSyscall6(trap uintptr, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr);
 // Actually RawSyscall5 but the rest of the code expects it to be named RawSyscall6.
 TEXT	·RawSyscall6(SB),NOSPLIT,$0-40
-	MOVW	4(SP), R7	// syscall entry
-	MOVW	8(SP), R0
-	MOVW	12(SP), R1
-	MOVW	16(SP), R2
-	MOVW	20(SP), R3
-	MOVW	24(SP), R4
-	MOVW	28(SP), R5
+	MOVW	trap+0(FP), R7	// syscall entry
+	MOVW	a1+4(FP), R0
+	MOVW	a2+8(FP), R1
+	MOVW	a3+12(FP), R2
+	MOVW	a4+16(FP), R3
+	MOVW	a5+20(FP), R4
+	MOVW	a6+24(FP), R5
 	SWI		$0
 	MOVW	$0xfffff001, R6
 	CMP		R6, R0
 	BLS		ok2
 	MOVW	$-1, R1
-	MOVW	R1, 32(SP)	// r1
+	MOVW	R1, r1+28(FP)
 	MOVW	$0, R2
-	MOVW	R2, 36(SP)	// r2
+	MOVW	R2, r2+32(FP)
 	RSB		$0, R0, R0
-	MOVW	R0, 40(SP)	// errno
+	MOVW	R0, err+36(FP)
 	RET
 ok2:
-	MOVW	R0, 32(SP) // r1
-	MOVW	R1, 36(SP)	// r2
+	MOVW	R0, r1+28(FP)
+	MOVW	R1, r2+32(FP)
 	MOVW	$0, R0
-	MOVW	R0, 40(SP)	// errno
+	MOVW	R0, err+36(FP)
 	RET
 
 #define SYS__LLSEEK 140  /* from zsysnum_linux_arm.go */
@@ -107,53 +107,53 @@ ok2:
 // taking the address of the return value newoffset.
 // Underlying system call is
 //	llseek(int fd, int offhi, int offlo, int64 *result, int whence)
-TEXT ·seek(SB),NOSPLIT,$0-32
+TEXT ·seek(SB),NOSPLIT,$0-28
 	BL	runtime·entersyscall(SB)
 	MOVW	$SYS__LLSEEK, R7	// syscall entry
-	MOVW	4(SP), R0	// fd
-	MOVW	12(SP), R1	// offset-high
-	MOVW	8(SP), R2	// offset-low
-	MOVW	$20(SP), R3
-	MOVW	16(SP), R4	// whence
+	MOVW	fd+0(FP), R0
+	MOVW	offset_hi+8(FP), R1
+	MOVW	offset_lo+4(FP), R2
+	MOVW	$newoffset_lo+16(FP), R3
+	MOVW	whence+12(FP), R4
 	SWI	$0
 	MOVW	$0xfffff001, R6
 	CMP	R6, R0
 	BLS	okseek
 	MOVW	$0, R1
-	MOVW	R1, 20(SP)
-	MOVW	R1, 24(SP)
+	MOVW	R1, newoffset_lo+16(FP)
+	MOVW	R1, newoffset_hi+20(FP)
 	RSB	$0, R0, R0
-	MOVW	R0, 28(SP)	// errno
+	MOVW	R0, err+24(FP)
 	BL	runtime·exitsyscall(SB)
 	RET
 okseek:
 	// system call filled in newoffset already
 	MOVW	$0, R0
-	MOVW	R0, 28(SP)	// errno
+	MOVW	R0, err+24(FP)
 	BL	runtime·exitsyscall(SB)
 	RET	
 
 // func RawSyscall(trap uintptr, a1, a2, a3 uintptr) (r1, r2, err uintptr);
 TEXT ·RawSyscall(SB),NOSPLIT,$0-28
-	MOVW	4(SP), R7	// syscall entry
-	MOVW	8(SP), R0
-	MOVW	12(SP), R1
-	MOVW	16(SP), R2
+	MOVW	trap+0(FP), R7	// syscall entry
+	MOVW	a1+4(FP), R0
+	MOVW	a2+8(FP), R1
+	MOVW	a3+12(FP), R2
 	SWI		$0
 	MOVW	$0xfffff001, R1
 	CMP		R1, R0
 	BLS		ok1
 	MOVW	$-1, R1
-	MOVW	R1, 20(SP)	// r1
+	MOVW	R1, r1+16(FP)
 	MOVW	$0, R2
-	MOVW	R2, 24(SP)	// r2
+	MOVW	R2, r2+20(FP)
 	RSB		$0, R0, R0
-	MOVW	R0, 28(SP)	// errno
+	MOVW	R0, err+24(FP)
 	RET
 ok1:
-	MOVW	R0, 20(SP) // r1
+	MOVW	R0, r1+16(FP)
 	MOVW	$0, R0
-	MOVW	R0, 24(SP)	// r2
-	MOVW	R0, 28(SP)	// errno
+	MOVW	R0, r2+20(FP)
+	MOVW	R0, err+24(FP)
 	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_linux_ppc64x.s b/src/syscall/asm_linux_ppc64x.s
new file mode 100644
index 0000000..be6727c
--- /dev/null
+++ b/src/syscall/asm_linux_ppc64x.s
@@ -0,0 +1,104 @@
+// 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
+// +build ppc64 ppc64le
+
+#include "textflag.h"
+
+//
+// System calls for ppc64, Linux
+//
+
+// 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), R3
+	MOVD	a2+16(FP), R4
+	MOVD	a3+24(FP), R5
+	MOVD	R0, R6
+	MOVD	R0, R7
+	MOVD	R0, R8
+	MOVD	trap+0(FP), R9	// syscall entry
+	SYSCALL R9
+	BVC	ok
+	MOVD	$-1, R4
+	MOVD	R4, r1+32(FP)	// r1
+	MOVD	R0, r2+40(FP)	// r2
+	MOVD	R3, err+48(FP)	// errno
+	BL	runtime·exitsyscall(SB)
+	RET
+ok:
+	MOVD	R3, r1+32(FP)	// r1
+	MOVD	R4, r2+40(FP)	// r2
+	MOVD	R0, err+48(FP)	// errno
+	BL	runtime·exitsyscall(SB)
+	RET
+
+TEXT ·Syscall6(SB),NOSPLIT,$0-80
+	BL	runtime·entersyscall(SB)
+	MOVD	a1+8(FP), R3
+	MOVD	a2+16(FP), R4
+	MOVD	a3+24(FP), R5
+	MOVD	a4+32(FP), R6
+	MOVD	a5+40(FP), R7
+	MOVD	a6+48(FP), R8
+	MOVD	trap+0(FP), R9	// syscall entry
+	SYSCALL R9
+	BVC	ok6
+	MOVD	$-1, R4
+	MOVD	R4, r1+56(FP)	// r1
+	MOVD	R0, r2+64(FP)	// r2
+	MOVD	R3, err+72(FP)	// errno
+	BL	runtime·exitsyscall(SB)
+	RET
+ok6:
+	MOVD	R3, r1+56(FP)	// r1
+	MOVD	R4, r2+64(FP)	// r2
+	MOVD	R0, err+72(FP)	// errno
+	BL	runtime·exitsyscall(SB)
+	RET
+
+TEXT ·RawSyscall(SB),NOSPLIT,$0-56
+	MOVD	a1+8(FP), R3
+	MOVD	a2+16(FP), R4
+	MOVD	a3+24(FP), R5
+	MOVD	R0, R6
+	MOVD	R0, R7
+	MOVD	R0, R8
+	MOVD	trap+0(FP), R9	// syscall entry
+	SYSCALL R9
+	BVC	ok1
+	MOVD	$-1, R4
+	MOVD	R4, r1+32(FP)	// r1
+	MOVD	R0, r2+40(FP)	// r2
+	MOVD	R3, err+48(FP)	// errno
+	RET
+ok1:
+	MOVD	R3, r1+32(FP)	// r1
+	MOVD	R4, r2+40(FP)	// r2
+	MOVD	R0, err+48(FP)	// errno
+	RET
+
+TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
+	MOVD	a1+8(FP), R3
+	MOVD	a2+16(FP), R4
+	MOVD	a3+24(FP), R5
+	MOVD	a4+32(FP), R6
+	MOVD	a5+40(FP), R7
+	MOVD	a6+48(FP), R8
+	MOVD	trap+0(FP), R9	// syscall entry
+	SYSCALL R9
+	BVC	ok2
+	MOVD	$-1, R4
+	MOVD	R4, r1+56(FP)	// r1
+	MOVD	R0, r2+64(FP)	// r2
+	MOVD	R3, err+72(FP)	// errno
+	RET
+ok2:
+	MOVD	R3, r1+56(FP)	// r1
+	MOVD	R4, r2+64(FP)	// r2
+	MOVD	R0, err+72(FP)	// errno
+	RET
diff --git a/src/syscall/asm_nacl_386.s b/src/syscall/asm_nacl_386.s
index cb6fb44..9d1e541 100644
--- a/src/syscall/asm_nacl_386.s
+++ b/src/syscall/asm_nacl_386.s
@@ -16,7 +16,8 @@
 #define NACL_SYSJMP(code) \
 	MOVL $(0x10000 + ((code)<<5)), AX; JMP AX
 
-TEXT syscall·Syscall(SB),NOSPLIT,$12-28
+TEXT ·Syscall(SB),NOSPLIT,$12-28
+	NO_LOCAL_POINTERS
 	CALL	runtime·entersyscall(SB)
 	MOVL	trap+0(FP), AX
 	MOVL	a1+4(FP), BX
diff --git a/src/syscall/asm_nacl_amd64p32.s b/src/syscall/asm_nacl_amd64p32.s
index 72391c4..b8c097b 100644
--- a/src/syscall/asm_nacl_amd64p32.s
+++ b/src/syscall/asm_nacl_amd64p32.s
@@ -16,7 +16,7 @@
 #define NACL_SYSJMP(code) \
 	MOVL $(0x10000 + ((code)<<5)), AX; JMP AX
 
-TEXT syscall·Syscall(SB),NOSPLIT,$0-28
+TEXT ·Syscall(SB),NOSPLIT,$0-28
 	CALL	runtime·entersyscall(SB)
 	MOVL	trap+0(FP), AX
 	MOVL	a1+4(FP), DI
diff --git a/src/syscall/asm_nacl_arm.s b/src/syscall/asm_nacl_arm.s
index 78e10bf..3e7df1a 100644
--- a/src/syscall/asm_nacl_arm.s
+++ b/src/syscall/asm_nacl_arm.s
@@ -16,7 +16,7 @@
 #define NACL_SYSJMP(code) \
 	MOVW $(0x10000 + ((code)<<5)), R8; B (R8)
 
-TEXT syscall·Syscall(SB),NOSPLIT,$0-28
+TEXT ·Syscall(SB),NOSPLIT,$0-28
 	BL	runtime·entersyscall(SB)
 	MOVW	trap+0(FP), R8
 	MOVW	a1+4(FP), R0
diff --git a/src/syscall/asm_netbsd_arm.s b/src/syscall/asm_netbsd_arm.s
index 290bb58..18bca56 100644
--- a/src/syscall/asm_netbsd_arm.s
+++ b/src/syscall/asm_netbsd_arm.s
@@ -15,113 +15,113 @@
 
 TEXT	·Syscall(SB),NOSPLIT,$0-28
 	BL runtime·entersyscall(SB)
-	MOVW 0(FP), R0 // sigcall num
-	MOVW 4(FP), R1 // a1
-	MOVW 8(FP), R2 // a2
-	MOVW 12(FP), R3 // a3
+	MOVW trap+0(FP), R0 // sigcall num
+	MOVW a1+4(FP), R1 // a1
+	MOVW a2+8(FP), R2 // a2
+	MOVW a3+12(FP), R3 // a3
 	SWI $0 // syscall
 	MOVW $0, R2
 	BCS error
-	MOVW R0, 16(FP) // r1
-	MOVW R1, 20(FP) // r2
-	MOVW R2, 24(FP) // err
+	MOVW R0, r1+16(FP) // r1
+	MOVW R1, r2+20(FP) // r2
+	MOVW R2, err+24(FP) // err
 	BL runtime·exitsyscall(SB)
 	RET
 error:
 	MOVW $-1, R3
-	MOVW R3, 16(FP) // r1
-	MOVW R2, 20(FP) // r2
-	MOVW R0, 24(FP) // err
+	MOVW R3, r1+16(FP) // r1
+	MOVW R2, r2+20(FP) // r2
+	MOVW R0, err+24(FP) // err
 	BL runtime·exitsyscall(SB)
 	RET
 
 TEXT	·Syscall6(SB),NOSPLIT,$0-40
 	BL runtime·entersyscall(SB)
-	MOVW 0(FP), R0 // sigcall num
-	MOVW 4(FP), R1 // a1
-	MOVW 8(FP), R2 // a2
-	MOVW 12(FP), R3 // a3
+	MOVW trap+0(FP), R0 // sigcall num
+	MOVW a1+4(FP), R1 // a1
+	MOVW a2+8(FP), R2 // a2
+	MOVW a3+12(FP), R3 // a3
 	MOVW R13, R4
-	MOVW $16(FP), R13 // a4 to a6 are passed on stack
+	MOVW $a4+16(FP), R13 // a4 to a6 are passed on stack
 	SWI $0 // syscall
 	MOVW R4, R13
 	MOVW $0, R2
 	BCS error6
-	MOVW R0, 28(FP) // r1
-	MOVW R1, 32(FP) // r2
-	MOVW R2, 36(FP) // err
+	MOVW R0, r1+28(FP) // r1
+	MOVW R1, r2+32(FP) // r2
+	MOVW R2, err+36(FP) // err
 	BL runtime·exitsyscall(SB)
 	RET
 error6:
 	MOVW $-1, R3
-	MOVW R3, 28(FP) // r1
-	MOVW R2, 32(FP) // r2
-	MOVW R0, 36(FP) // err
+	MOVW R3, r1+28(FP) // r1
+	MOVW R2, r2+32(FP) // r2
+	MOVW R0, err+36(FP) // err
 	BL runtime·exitsyscall(SB)
 	RET
 
 TEXT	·Syscall9(SB),NOSPLIT,$0-52
 	BL runtime·entersyscall(SB)
-	MOVW 0(FP), R0 // sigcall num
-	MOVW 4(FP), R1 // a1
-	MOVW 8(FP), R2 // a2
-	MOVW 12(FP), R3 // a3
+	MOVW trap+0(FP), R0 // sigcall num
+	MOVW a1+4(FP), R1 // a1
+	MOVW a2+8(FP), R2 // a2
+	MOVW a3+12(FP), R3 // a3
 	MOVW R13, R4
-	MOVW $16(FP), R13 // a4 to a9 are passed on stack
+	MOVW $a4+16(FP), R13 // a4 to a9 are passed on stack
 	SWI $0 // syscall
 	MOVW R4, R13
 	MOVW $0, R2
 	BCS error9
-	MOVW R0, 40(FP) // r1
-	MOVW R1, 44(FP) // r2
-	MOVW R2, 48(FP) // err
+	MOVW R0, r1+40(FP) // r1
+	MOVW R1, r2+44(FP) // r2
+	MOVW R2, err+48(FP) // err
 	BL runtime·exitsyscall(SB)
 	RET
 error9:
 	MOVW $-1, R3
-	MOVW R3, 40(FP) // r1
-	MOVW R2, 44(FP) // r2
-	MOVW R0, 48(FP) // err
+	MOVW R3, r1+40(FP) // r1
+	MOVW R2, r2+44(FP) // r2
+	MOVW R0, err+48(FP) // err
 	BL runtime·exitsyscall(SB)
 	RET
 
 TEXT	·RawSyscall(SB),NOSPLIT,$0-28
-	MOVW 0(FP), R0 // sigcall num
-	MOVW 4(FP), R1 // a1
-	MOVW 8(FP), R2 // a2
-	MOVW 12(FP), R3 // a3
+	MOVW trap+0(FP), R0 // sigcall num
+	MOVW a1+4(FP), R1 // a1
+	MOVW a2+8(FP), R2 // a2
+	MOVW a3+12(FP), R3 // a3
 	SWI $0 // syscall
 	MOVW $0, R2
 	BCS errorr
-	MOVW R0, 16(FP) // r1
-	MOVW R1, 20(FP) // r2
-	MOVW R2, 24(FP) // err
+	MOVW R0, r1+16(FP) // r1
+	MOVW R1, r2+20(FP) // r2
+	MOVW R2, err+24(FP) // err
 	RET
 errorr:
 	MOVW $-1, R3
-	MOVW R3, 16(FP) // r1
-	MOVW R2, 20(FP) // r2
-	MOVW R0, 24(FP) // err
+	MOVW R3, r1+16(FP) // r1
+	MOVW R2, r2+20(FP) // r2
+	MOVW R0, err+24(FP) // err
 	RET
 
 TEXT	·RawSyscall6(SB),NOSPLIT,$0-40
-	MOVW 0(FP), R0 // sigcall num
-	MOVW 4(FP), R1 // a1
-	MOVW 8(FP), R2 // a2
-	MOVW 12(FP), R3 // a3
+	MOVW trap+0(FP), R0 // sigcall num
+	MOVW a1+4(FP), R1 // a1
+	MOVW a2+8(FP), R2 // a2
+	MOVW a3+12(FP), R3 // a3
 	MOVW R13, R4
-	MOVW $16(FP), R13 // a4 to a9 are passed on stack
+	MOVW $a4+16(FP), R13 // a4 to a9 are passed on stack
 	SWI $0 // syscall
 	MOVW R4, R13
 	MOVW $0, R2
 	BCS errorr6
-	MOVW R0, 28(FP) // r1
-	MOVW R1, 32(FP) // r2
-	MOVW R2, 36(FP) // err
+	MOVW R0, r1+28(FP) // r1
+	MOVW R1, r2+32(FP) // r2
+	MOVW R2, err+36(FP) // err
 	RET
 errorr6:
 	MOVW $-1, R3
-	MOVW R3, 28(FP) // r1
-	MOVW R2, 32(FP) // r2
-	MOVW R0, 36(FP) // err
+	MOVW R3, r1+28(FP) // r1
+	MOVW R2, r2+32(FP) // r2
+	MOVW R0, err+36(FP) // err
 	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 ·forkx(SB),NOSPLIT,$0
 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/const_plan9.go b/src/syscall/const_plan9.go
new file mode 100644
index 0000000..ba26f12
--- /dev/null
+++ b/src/syscall/const_plan9.go
@@ -0,0 +1,59 @@
+package syscall
+
+// Plan 9 Constants
+
+// Open modes
+const (
+	O_RDONLY  = 0
+	O_WRONLY  = 1
+	O_RDWR    = 2
+	O_TRUNC   = 16
+	O_CLOEXEC = 32
+	O_EXCL    = 0x1000
+)
+
+// Rfork flags
+const (
+	RFNAMEG  = 1 << 0
+	RFENVG   = 1 << 1
+	RFFDG    = 1 << 2
+	RFNOTEG  = 1 << 3
+	RFPROC   = 1 << 4
+	RFMEM    = 1 << 5
+	RFNOWAIT = 1 << 6
+	RFCNAMEG = 1 << 10
+	RFCENVG  = 1 << 11
+	RFCFDG   = 1 << 12
+	RFREND   = 1 << 13
+	RFNOMNT  = 1 << 14
+)
+
+// Qid.Type bits
+const (
+	QTDIR    = 0x80
+	QTAPPEND = 0x40
+	QTEXCL   = 0x20
+	QTMOUNT  = 0x10
+	QTAUTH   = 0x08
+	QTTMP    = 0x04
+	QTFILE   = 0x00
+)
+
+// Dir.Mode bits
+const (
+	DMDIR    = 0x80000000
+	DMAPPEND = 0x40000000
+	DMEXCL   = 0x20000000
+	DMMOUNT  = 0x10000000
+	DMAUTH   = 0x08000000
+	DMTMP    = 0x04000000
+	DMREAD   = 0x4
+	DMWRITE  = 0x2
+	DMEXEC   = 0x1
+)
+
+const (
+	STATMAX    = 65535
+	ERRMAX     = 128
+	STATFIXLEN = 49
+)
diff --git a/src/syscall/creds_test.go b/src/syscall/creds_test.go
index b1894c6..b4a14ff 100644
--- a/src/syscall/creds_test.go
+++ b/src/syscall/creds_test.go
@@ -56,7 +56,13 @@ func TestSCMCredentials(t *testing.T) {
 		ucred.Gid = 0
 		oob := syscall.UnixCredentials(&ucred)
 		_, _, err := cli.(*net.UnixConn).WriteMsgUnix(nil, oob, nil)
-		if err.(*net.OpError).Err != syscall.EPERM {
+		if op, ok := err.(*net.OpError); ok {
+			err = op.Err
+		}
+		if sys, ok := err.(*os.SyscallError); ok {
+			err = sys.Err
+		}
+		if err != syscall.EPERM {
 			t.Fatalf("WriteMsgUnix failed with %v, want EPERM", err)
 		}
 	}
diff --git a/src/syscall/dll_windows.go b/src/syscall/dll_windows.go
index 18663b4..c157e6d 100644
--- a/src/syscall/dll_windows.go
+++ b/src/syscall/dll_windows.go
@@ -55,7 +55,7 @@ func LoadDLL(name string) (dll *DLL, err error) {
 	return d, nil
 }
 
-// MustLoadDLL is like LoadDLL but panics if load operation failes.
+// MustLoadDLL is like LoadDLL but panics if load operation fails.
 func MustLoadDLL(name string) *DLL {
 	d, e := LoadDLL(name)
 	if e != nil {
diff --git a/src/syscall/env_plan9.go b/src/syscall/env_plan9.go
index 9ea36c8..cbf7f41 100644
--- a/src/syscall/env_plan9.go
+++ b/src/syscall/env_plan9.go
@@ -16,7 +16,7 @@ var (
 )
 
 func readenv(key string) (string, error) {
-	fd, err := Open("/env/"+key, O_RDONLY)
+	fd, err := open("/env/"+key, O_RDONLY)
 	if err != nil {
 		return "", err
 	}
@@ -35,7 +35,7 @@ func readenv(key string) (string, error) {
 }
 
 func writeenv(key, value string) error {
-	fd, err := Create("/env/"+key, O_RDWR, 0666)
+	fd, err := create("/env/"+key, O_RDWR, 0666)
 	if err != nil {
 		return err
 	}
@@ -86,7 +86,7 @@ func Unsetenv(key string) error {
 }
 
 func Environ() []string {
-	fd, err := Open("/env", O_RDONLY)
+	fd, err := open("/env", O_RDONLY)
 	if err != nil {
 		return nil
 	}
diff --git a/src/syscall/env_windows.go b/src/syscall/env_windows.go
index bc21690..1cb4754 100644
--- a/src/syscall/env_windows.go
+++ b/src/syscall/env_windows.go
@@ -16,19 +16,17 @@ func Getenv(key string) (value string, found bool) {
 	if err != nil {
 		return "", false
 	}
-	b := make([]uint16, 100)
-	n, e := GetEnvironmentVariable(keyp, &b[0], uint32(len(b)))
-	if n == 0 && e == ERROR_ENVVAR_NOT_FOUND {
-		return "", false
-	}
-	if n > uint32(len(b)) {
-		b = make([]uint16, n)
-		n, e = GetEnvironmentVariable(keyp, &b[0], uint32(len(b)))
-		if n > uint32(len(b)) {
-			n = 0
+	n := uint32(100)
+	for {
+		b := make([]uint16, n)
+		n, err = GetEnvironmentVariable(keyp, &b[0], uint32(len(b)))
+		if n == 0 && err == ERROR_ENVVAR_NOT_FOUND {
+			return "", false
+		}
+		if n <= uint32(len(b)) {
+			return string(utf16.Decode(b[:n])), true
 		}
 	}
-	return string(utf16.Decode(b[0:n])), true
 }
 
 func Setenv(key, value string) error {
diff --git a/src/syscall/zerrors_plan9_386.go b/src/syscall/errors_plan9.go
similarity index 100%
rename from src/syscall/zerrors_plan9_386.go
rename to src/syscall/errors_plan9.go
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 @@ type SysProcAttr struct {
 	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 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
 	}
 
 	// 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 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
 		}
 	}
 
-	// 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 042c20a..9bac042 100644
--- a/src/syscall/exec_linux.go
+++ b/src/syscall/exec_linux.go
@@ -23,14 +23,21 @@ type SysProcAttr struct {
 	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.
 	GidMappings []SysProcIDMap // Group ID mappings for user namespaces.
+	// GidMappingsEnableSetgroups enabling setgroups syscall.
+	// If false, then setgroups syscall will be disabled for the child process.
+	// This parameter is no-op if GidMappings == nil. Otherwise for unprivileged
+	// users this should be set to false for mappings work.
+	GidMappingsEnableSetgroups bool
 }
 
 // Implemented in runtime package.
@@ -58,6 +65,9 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
 		p      [2]int
 	)
 
+	// Record parent PID so child can test if it has died.
+	ppid, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0)
+
 	// Guard against side effects of shuffling fds below.
 	// Make sure that nextfd is beyond any currently open files so
 	// that we can't run the risk of overwriting any of them.
@@ -127,26 +137,6 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
 		}
 	}
 
-	// Parent death signal
-	if sys.Pdeathsig != 0 {
-		_, _, err1 = RawSyscall6(SYS_PRCTL, PR_SET_PDEATHSIG, uintptr(sys.Pdeathsig), 0, 0, 0, 0)
-		if err1 != 0 {
-			goto childerror
-		}
-
-		// Signal self if parent is already dead. This might cause a
-		// duplicate signal in rare cases, but it won't matter when
-		// using SIGKILL.
-		r1, _, _ = RawSyscall(SYS_GETPPID, 0, 0, 0)
-		if r1 == 1 {
-			pid, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0)
-			_, _, err1 := RawSyscall(SYS_KILL, pid, uintptr(sys.Pdeathsig), 0)
-			if err1 != 0 {
-				goto childerror
-			}
-		}
-	}
-
 	// Enable tracing if requested.
 	if sys.Ptrace {
 		_, _, err1 = RawSyscall(SYS_PTRACE, uintptr(PTRACE_TRACEME), 0, 0)
@@ -164,8 +154,27 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
 	}
 
 	// 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 := int32(sys.Pgid)
+		if pgrp == 0 {
+			r1, _, err1 = RawSyscall(SYS_GETPID, 0, 0, 0)
+			if err1 != 0 {
+				goto childerror
+			}
+
+			pgrp = int32(r1)
+		}
+
+		// Place process group in foreground.
+		_, _, err1 = RawSyscall(SYS_IOCTL, uintptr(sys.Ctty), uintptr(TIOCSPGRP), uintptr(unsafe.Pointer(&pgrp)))
 		if err1 != 0 {
 			goto childerror
 		}
@@ -208,10 +217,30 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
 		}
 	}
 
+	// Parent death signal
+	if sys.Pdeathsig != 0 {
+		_, _, err1 = RawSyscall6(SYS_PRCTL, PR_SET_PDEATHSIG, uintptr(sys.Pdeathsig), 0, 0, 0, 0)
+		if err1 != 0 {
+			goto childerror
+		}
+
+		// Signal self if parent is already dead. This might cause a
+		// duplicate signal in rare cases, but it won't matter when
+		// using SIGKILL.
+		r1, _, _ = RawSyscall(SYS_GETPPID, 0, 0, 0)
+		if r1 != ppid {
+			pid, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0)
+			_, _, err1 := RawSyscall(SYS_KILL, pid, uintptr(sys.Pdeathsig), 0)
+			if err1 != 0 {
+				goto childerror
+			}
+		}
+	}
+
 	// 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
 		}
@@ -221,7 +250,7 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
 	}
 	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
 			}
@@ -251,7 +280,7 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
 		}
 		// 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
 		}
@@ -274,7 +303,7 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
 	}
 
 	// 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
@@ -342,6 +371,32 @@ func writeIDMappings(path string, idMap []SysProcIDMap) error {
 	return nil
 }
 
+// writeSetgroups writes to /proc/PID/setgroups "deny" if enable is false
+// and "allow" if enable is true.
+// This is needed since kernel 3.19, because you can't write gid_map without
+// disabling setgroups() system call.
+func writeSetgroups(pid int, enable bool) error {
+	sgf := "/proc/" + itoa(pid) + "/setgroups"
+	fd, err := Open(sgf, O_RDWR, 0)
+	if err != nil {
+		return err
+	}
+
+	var data []byte
+	if enable {
+		data = []byte("allow")
+	} else {
+		data = []byte("deny")
+	}
+
+	if _, err := Write(fd, data); err != nil {
+		Close(fd)
+		return err
+	}
+
+	return Close(fd)
+}
+
 // writeUidGidMappings writes User ID and Group ID mappings for user namespaces
 // for a process and it is called from the parent process.
 func writeUidGidMappings(pid int, sys *SysProcAttr) error {
@@ -353,6 +408,10 @@ func writeUidGidMappings(pid int, sys *SysProcAttr) error {
 	}
 
 	if sys.GidMappings != nil {
+		// If the kernel is too old to support /proc/PID/setgroups, writeSetGroups will return ENOENT; this is OK.
+		if err := writeSetgroups(pid, sys.GidMappingsEnableSetgroups); err != nil && err != ENOENT {
+			return err
+		}
 		gidf := "/proc/" + itoa(pid) + "/gid_map"
 		if err := writeIDMappings(gidf, sys.GidMappings); err != nil {
 			return err
diff --git a/src/syscall/exec_linux_test.go b/src/syscall/exec_linux_test.go
new file mode 100644
index 0000000..60d2734
--- /dev/null
+++ b/src/syscall/exec_linux_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.
+
+// +build linux
+
+package syscall_test
+
+import (
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"regexp"
+	"strconv"
+	"strings"
+	"syscall"
+	"testing"
+)
+
+func whoamiCmd(t *testing.T, uid, gid int, setgroups bool) *exec.Cmd {
+	if _, err := os.Stat("/proc/self/ns/user"); err != nil {
+		if os.IsNotExist(err) {
+			t.Skip("kernel doesn't support user namespaces")
+		}
+		t.Fatalf("Failed to stat /proc/self/ns/user: %v", err)
+	}
+	cmd := exec.Command("whoami")
+	cmd.SysProcAttr = &syscall.SysProcAttr{
+		Cloneflags: syscall.CLONE_NEWUSER,
+		UidMappings: []syscall.SysProcIDMap{
+			{ContainerID: 0, HostID: uid, Size: 1},
+		},
+		GidMappings: []syscall.SysProcIDMap{
+			{ContainerID: 0, HostID: gid, Size: 1},
+		},
+		GidMappingsEnableSetgroups: setgroups,
+	}
+	return cmd
+}
+
+func testNEWUSERRemap(t *testing.T, uid, gid int, setgroups bool) {
+	cmd := whoamiCmd(t, uid, gid, setgroups)
+	out, err := cmd.CombinedOutput()
+	if err != nil {
+		// On some systems, there is a sysctl setting.
+		if os.IsPermission(err) && os.Getuid() != 0 {
+			data, errRead := ioutil.ReadFile("/proc/sys/kernel/unprivileged_userns_clone")
+			if errRead == nil && data[0] == '0' {
+				t.Skip("kernel prohibits user namespace in unprivileged process")
+			}
+		}
+
+		t.Fatalf("Cmd failed with err %v, output: %s", err, out)
+	}
+	sout := strings.TrimSpace(string(out))
+	want := "root"
+	if sout != want {
+		t.Fatalf("whoami = %q; want %q", out, want)
+	}
+}
+
+func TestCloneNEWUSERAndRemapRootDisableSetgroups(t *testing.T) {
+	if os.Getuid() != 0 {
+		t.Skip("skipping root only test")
+	}
+	testNEWUSERRemap(t, 0, 0, false)
+}
+
+func TestCloneNEWUSERAndRemapRootEnableSetgroups(t *testing.T) {
+	if os.Getuid() != 0 {
+		t.Skip("skipping root only test")
+	}
+	testNEWUSERRemap(t, 0, 0, false)
+}
+
+// kernelVersion returns the major and minor versions of the Linux
+// kernel version.  It calls t.Skip if it can't figure it out.
+func kernelVersion(t *testing.T) (int, int) {
+	bytes, err := ioutil.ReadFile("/proc/version")
+	if err != nil {
+		t.Skipf("can't get kernel version: %v", err)
+	}
+	matches := regexp.MustCompile("([0-9]+).([0-9]+)").FindSubmatch(bytes)
+	if len(matches) < 3 {
+		t.Skipf("can't get kernel version from %s", bytes)
+	}
+	major, _ := strconv.Atoi(string(matches[1]))
+	minor, _ := strconv.Atoi(string(matches[2]))
+	return major, minor
+}
+
+func TestCloneNEWUSERAndRemapNoRootDisableSetgroups(t *testing.T) {
+	if os.Getuid() == 0 {
+		t.Skip("skipping unprivileged user only test")
+	}
+	testNEWUSERRemap(t, os.Getuid(), os.Getgid(), false)
+}
+
+func TestCloneNEWUSERAndRemapNoRootSetgroupsEnableSetgroups(t *testing.T) {
+	if os.Getuid() == 0 {
+		t.Skip("skipping unprivileged user only test")
+	}
+	cmd := whoamiCmd(t, os.Getuid(), os.Getgid(), true)
+	err := cmd.Run()
+	if err == nil {
+		t.Skip("probably old kernel without security fix")
+	}
+	if !os.IsPermission(err) {
+		t.Fatalf("Unprivileged gid_map rewriting with GidMappingsEnableSetgroups must fail")
+	}
+}
diff --git a/src/syscall/exec_plan9.go b/src/syscall/exec_plan9.go
index 45ee542..7a415fd 100644
--- a/src/syscall/exec_plan9.go
+++ b/src/syscall/exec_plan9.go
@@ -61,9 +61,11 @@ import (
 
 var ForkLock sync.RWMutex
 
-// StringSlicePtr is deprecated. Use SlicePtrFromStrings instead.
-// If any string contains a NUL byte this function panics instead
-// of returning an error.
+// StringSlicePtr converts a slice of strings to a slice of pointers
+// to NUL-terminated byte arrays. If any string contains a NUL byte
+// this function panics instead of returning an error.
+//
+// Deprecated: Use SlicePtrFromStrings instead.
 func StringSlicePtr(ss []string) []*byte {
 	bb := make([]*byte, len(ss)+1)
 	for i := 0; i < len(ss); i++ {
@@ -74,7 +76,7 @@ func StringSlicePtr(ss []string) []*byte {
 }
 
 // SlicePtrFromStrings converts a slice of strings to a slice of
-// pointers to NUL-terminated byte slices. If any string contains
+// pointers to NUL-terminated byte arrays. If any string contains
 // a NUL byte, it returns (nil, EINVAL).
 func SlicePtrFromStrings(ss []string) ([]*byte, error) {
 	var err error
@@ -396,9 +398,15 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error)
 		return 0, err
 	}
 
+	destDir := attr.Dir
+	if destDir == "" {
+		wdmu.Lock()
+		destDir = wdStr
+		wdmu.Unlock()
+	}
 	var dir *byte
-	if attr.Dir != "" {
-		dir, err = BytePtrFromString(attr.Dir)
+	if destDir != "" {
+		dir, err = BytePtrFromString(destDir)
 		if err != nil {
 			return 0, err
 		}
diff --git a/src/syscall/exec_solaris.go b/src/syscall/exec_solaris.go
index 97de6ca..3e949f1 100644
--- a/src/syscall/exec_solaris.go
+++ b/src/syscall/exec_solaris.go
@@ -12,9 +12,12 @@ type SysProcAttr struct {
 	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 execve(path uintptr, argv uintptr, envp uintptr) (err Errno)
 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)
@@ -44,7 +48,7 @@ func write1(fd uintptr, buf uintptr, nbyte uintptr) (n uintptr, err Errno)
 // no rescheduling, no malloc calls, and no new stack segments.
 //
 // We call hand-crafted syscalls, implemented in
-// ../runtime/syscall_solaris.goc, rather than generated libc wrappers
+// ../runtime/syscall_solaris.go, rather than generated libc wrappers
 // because we need to avoid lazy-loading the functions (might malloc,
 // split the stack, or acquire mutexes). We can't call RawSyscall
 // because it's not safe even for BSD-subsystem calls.
@@ -97,8 +101,27 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
 	}
 
 	// 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 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
 		}
 	}
 
-	// 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..6b8f1ad
--- /dev/null
+++ b/src/syscall/exec_solaris_test.go
@@ -0,0 +1,37 @@
+// 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
+
+import "unsafe"
+
+//go:cgo_import_dynamic libc_Getpgid getpgid "libc.so"
+//go:cgo_import_dynamic libc_Getpgrp getpgrp "libc.so"
+
+//go:linkname libc_Getpgid libc_Getpgid
+//go:linkname libc_Getpgrp libc_Getpgrp
+
+var (
+	libc_Getpgid,
+	libc_Getpgrp libcFunc
+)
+
+func Getpgid(pid int) (pgid int, err error) {
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Getpgid)), 1, uintptr(pid), 0, 0, 0, 0, 0)
+	pgid = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+func Getpgrp() (pgrp int) {
+	r0, _, _ := sysvicall6(uintptr(unsafe.Pointer(&libc_Getpgrp)), 0, 0, 0, 0, 0, 0, 0)
+	pgrp = int(r0)
+	return
+}
+
+var Ioctl = ioctl
diff --git a/src/syscall/exec_unix.go b/src/syscall/exec_unix.go
index 890bfdc..565252c 100644
--- a/src/syscall/exec_unix.go
+++ b/src/syscall/exec_unix.go
@@ -63,9 +63,11 @@ import (
 
 var ForkLock sync.RWMutex
 
-// StringSlicePtr is deprecated. Use SlicePtrFromStrings instead.
-// If any string contains a NUL byte this function panics instead
-// of returning an error.
+// StringSlicePtr converts a slice of strings to a slice of pointers
+// to NUL-terminated byte arrays. If any string contains a NUL byte
+// this function panics instead of returning an error.
+//
+// Deprecated: Use SlicePtrFromStrings instead.
 func StringSlicePtr(ss []string) []*byte {
 	bb := make([]*byte, len(ss)+1)
 	for i := 0; i < len(ss); i++ {
@@ -76,7 +78,7 @@ func StringSlicePtr(ss []string) []*byte {
 }
 
 // SlicePtrFromStrings converts a slice of strings to a slice of
-// pointers to NUL-terminated byte slices. If any string contains
+// pointers to NUL-terminated byte arrays. If any string contains
 // a NUL byte, it returns (nil, EINVAL).
 func SlicePtrFromStrings(ss []string) ([]*byte, error) {
 	var err error
diff --git a/src/syscall/exec_unix_test.go b/src/syscall/exec_unix_test.go
new file mode 100644
index 0000000..9bb95c0
--- /dev/null
+++ b/src/syscall/exec_unix_test.go
@@ -0,0 +1,215 @@
+// 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 (
+	"internal/testenv"
+	"io"
+	"os"
+	"os/exec"
+	"os/signal"
+	"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 {
+	testenv.MustHaveExec(t)
+
+	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/exec_windows.go b/src/syscall/exec_windows.go
index 936aeb5..5a01843 100644
--- a/src/syscall/exec_windows.go
+++ b/src/syscall/exec_windows.go
@@ -135,23 +135,17 @@ func FullPath(name string) (path string, err error) {
 	if err != nil {
 		return "", err
 	}
-	buf := make([]uint16, 100)
-	n, err := GetFullPathName(p, uint32(len(buf)), &buf[0], nil)
-	if err != nil {
-		return "", err
-	}
-	if n > uint32(len(buf)) {
-		// Windows is asking for bigger buffer.
-		buf = make([]uint16, n)
+	n := uint32(100)
+	for {
+		buf := make([]uint16, n)
 		n, err = GetFullPathName(p, uint32(len(buf)), &buf[0], nil)
 		if err != nil {
 			return "", err
 		}
-		if n > uint32(len(buf)) {
-			return "", EINVAL
+		if n <= uint32(len(buf)) {
+			return UTF16ToString(buf[:n]), nil
 		}
 	}
-	return UTF16ToString(buf[:n]), nil
 }
 
 func isSlash(c uint8) bool {
@@ -250,6 +244,9 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle
 	if len(attr.Files) > 3 {
 		return 0, 0, EWINDOWS
 	}
+	if len(attr.Files) < 3 {
+		return 0, 0, EINVAL
+	}
 
 	if len(attr.Dir) != 0 {
 		// StartProcess assumes that argv0 is relative to attr.Dir,
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 6e6ce2a..711809f 100644
--- a/src/syscall/fs_nacl.go
+++ b/src/syscall/fs_nacl.go
@@ -772,29 +772,24 @@ func (f *zeroFile) pread(b []byte, offset int64) (int, error) {
 	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
 }
 
@@ -815,7 +810,7 @@ func fdToFsysFile(fd int) (*fsysFile, error) {
 // It is meant to be called when initializing the file system image.
 func create(name string, mode uint32, sec int64, data []byte) error {
 	fs.mu.Lock()
-	fs.mu.Unlock()
+	defer fs.mu.Unlock()
 	f, err := fs.open(name, O_CREATE|O_EXCL, mode)
 	if err != nil {
 		if mode&S_IFMT == S_IFDIR {
diff --git a/src/syscall/mkall.sh b/src/syscall/mkall.sh
index 9cb82a6..85fab4f 100755
--- a/src/syscall/mkall.sh
+++ b/src/syscall/mkall.sh
@@ -107,6 +107,7 @@ case "$#" in
 	exit 2
 esac
 
+GOOSARCH_in=syscall_$GOOSARCH.go
 case "$GOOSARCH" in
 _* | *_ | _)
 	echo 'undefined $GOOS_$GOARCH:' "$GOOSARCH" 1>&2
@@ -123,6 +124,11 @@ darwin_amd64)
 	mksysnum="./mksysnum_darwin.pl /usr/include/sys/syscall.h"
 	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
 	;;
+darwin_arm64)
+	mkerrors="$mkerrors -m64"
+	mksysnum="./mksysnum_darwin.pl /usr/include/sys/syscall.h"
+	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+	;;
 dragonfly_386)
 	mkerrors="$mkerrors -m32"
 	mksyscall="./mksyscall.pl -l32 -dragonfly"
@@ -173,7 +179,32 @@ linux_amd64)
 linux_arm)
 	mkerrors="$mkerrors"
 	mksyscall="./mksyscall.pl -l32 -arm"
-	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"
+	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
+	mkerrors="$mkerrors -m64"
+	mksysnum="./mksysnum_linux.pl $unistd_h"
+	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+	;;
+linux_ppc64le)
+	GOOSARCH_in=syscall_linux_ppc64x.go
+	unistd_h=/usr/include/powerpc64le-linux-gnu/asm/unistd.h
+	mkerrors="$mkerrors -m64"
+	mksysnum="./mksysnum_linux.pl $unistd_h"
 	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
 	;;
 nacl_386)
@@ -205,7 +236,7 @@ openbsd_386)
 	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)
@@ -213,7 +244,15 @@ openbsd_amd64)
 	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)
@@ -229,9 +268,8 @@ solaris_amd64)
 	mktypes="GOARCH=$GOARCH go tool cgo -godefs"
 	;;
 windows_*)
-	mksyscall=
-	mkerrors=
-	zerrors=
+	echo 'run "go generate syscall_windows.go" instead' 1>&2
+	exit 1
 	;;
 *)
 	echo 'unrecognized $GOOS_$GOARCH: ' "$GOOSARCH" 1>&2
@@ -241,22 +279,13 @@ esac
 
 (
 	if [ -n "$mkerrors" ]; then echo "$mkerrors |gofmt >$zerrors"; fi
-	case "$GOOS" in
-	windows)
-		echo "GOOS= GOARCH= go build mksyscall_windows.go"
-		echo "./mksyscall_windows syscall_windows.go security_windows.go |gofmt >zsyscall_windows.go"
-		echo "rm -f ./mksyscall_windows"
-		;;
-	*)
-		syscall_goos="syscall_$GOOS.go"
-		case "$GOOS" in
-		darwin | dragonfly | freebsd | netbsd | openbsd)
-			syscall_goos="syscall_bsd.go $syscall_goos"
-			;;
-		esac
-		if [ -n "$mksyscall" ]; then echo "$mksyscall $syscall_goos syscall_$GOOSARCH.go |gofmt >zsyscall_$GOOSARCH.go"; fi
-		;;
-	esac
+	syscall_goos="syscall_$GOOS.go"
+ 	case "$GOOS" in
+	darwin | dragonfly | freebsd | netbsd | openbsd)
+		syscall_goos="syscall_bsd.go $syscall_goos"
+ 		;;
+ 	esac
+	if [ -n "$mksyscall" ]; then echo "$mksyscall $syscall_goos $GOOSARCH_in |gofmt >zsyscall_$GOOSARCH.go"; fi
 	if [ -n "$mksysctl" ]; then echo "$mksysctl |gofmt >$zsysctl"; fi
 	if [ -n "$mksysnum" ]; then echo "$mksysnum |gofmt >zsysnum_$GOOSARCH.go"; fi
 	if [ -n "$mktypes" ]; then echo "$mktypes types_$GOOS.go |gofmt >ztypes_$GOOSARCH.go"; fi
diff --git a/src/syscall/mkall_windows.bat b/src/syscall/mkall_windows.bat
deleted file mode 100644
index 0f3a98b..0000000
--- a/src/syscall/mkall_windows.bat
+++ /dev/null
@@ -1,15 +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.
- at echo off
-
-if exist mkall.sh goto dirok
-echo mkall_windows.bat must be run from src\syscall directory
-goto :end
-:dirok
-
-go build mksyscall_windows.go
-.\mksyscall_windows syscall_windows.go security_windows.go |gofmt >zsyscall_windows.go
-del mksyscall_windows.exe
-
-:end
diff --git a/src/syscall/mkerrors.sh b/src/syscall/mkerrors.sh
index cf0afe0..438de6e 100755
--- a/src/syscall/mkerrors.sh
+++ b/src/syscall/mkerrors.sh
@@ -87,7 +87,9 @@ includes_FreeBSD='
 includes_Linux='
 #define _LARGEFILE_SOURCE
 #define _LARGEFILE64_SOURCE
+#ifndef __LP64__
 #define _FILE_OFFSET_BITS 64
+#endif
 #define _GNU_SOURCE
 
 #include <bits/sockaddr.h>
@@ -121,6 +123,14 @@ includes_Linux='
 #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='
@@ -242,6 +252,7 @@ ccflags="$@"
 		$2 ~ /^(SIGEV_|SIGSTKSZ|SIGRT(MIN|MAX))/ {next}
 		$2 ~ /^(SCM_SRCRT)$/ {next}
 		$2 ~ /^(MAP_FAILED)$/ {next}
+		$2 ~ /^ELF_.*$/ {next}	# <asm/elf.h> contains ELF_ARCH, etc.
 
 		$2 !~ /^ETH_/ &&
 		$2 !~ /^EPROC_/ &&
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 @@ while(<>) {
 		$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..f5eb4b3 100755
--- a/src/syscall/mksyscall_solaris.pl
+++ b/src/syscall/mksyscall_solaris.pl
@@ -61,8 +61,8 @@ sub parseparam($) {
 my $package = "";
 my $text = "";
 my $vars = "";
-my $mods = "";
-my $modnames = "";
+my $dynimports = "";
+my $linknames = "";
 while(<>) {
 	chomp;
 	s/\s+/ /g;
@@ -93,11 +93,6 @@ while(<>) {
 	if($modname eq "") {
 		$modname = "libc";
 	}
-	my $modvname = "mod$modname";
-	if($modnames !~ /$modname/) {
-		$modnames .= ".$modname";
-		$mods .= "\t$modvname = ${syscalldot}newLazySO(\"$modname.so\")\n";
-	}
 
 	# System call name.
 	if($sysname eq "") {
@@ -105,14 +100,20 @@ while(<>) {
 	}
 
 	# System call pointer variable name.
-	my $sysvarname = "proc$sysname";
+	my $sysvarname = "libc_$sysname";
 
 	my $strconvfunc = "BytePtrFromString";
 	my $strconvtype = "*byte";
 
 	# Library proc address variable.
 	$sysname =~ y/A-Z/a-z/; # All libc functions are lowercase.
-	$vars .= "\t$sysvarname = $modvname.NewProc(\"$sysname\")\n";
+	if($vars eq "") {
+		$vars .= "\t$sysvarname";
+	} else {
+		$vars .= ",\n\t$sysvarname";
+	}
+	$dynimports .= "//go:cgo_import_dynamic $sysvarname $sysname \"$modname.so\"\n";
+	$linknames .= "//go:linkname $sysvarname $sysvarname\n";
 
 	# Go function header.
 	$out = join(', ', @out);
@@ -196,7 +197,7 @@ while(<>) {
 
 	# Actual call.
 	my $args = join(', ', @args);
-	my $call = "$asm($sysvarname.Addr(), $nargs, $args)";
+	my $call = "$asm(uintptr(unsafe.Pointer(&$sysvarname)), $nargs, $args)";
 
 	# Assign return values.
 	my $body = "";
@@ -248,7 +249,7 @@ while(<>) {
 
 	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";
@@ -272,9 +273,12 @@ print "import \"syscall\"\n" if $package ne "syscall";
 
 print <<EOF;
 
+$dynimports
+$linknames
+type libcFunc uintptr
+
 var (
-$mods
-$vars
+$vars libcFunc
 )
 
 $text
diff --git a/src/syscall/mksyscall_windows.go b/src/syscall/mksyscall_windows.go
index 316e88d..622272a 100644
--- a/src/syscall/mksyscall_windows.go
+++ b/src/syscall/mksyscall_windows.go
@@ -37,6 +37,8 @@ Usage:
 	mksyscall_windows [flags] [path ...]
 
 The flags are:
+	-output
+		Specify output file name (outputs to console if blank).
 	-trace
 		Generate print statement after every syscall.
 */
@@ -44,12 +46,15 @@ package main
 
 import (
 	"bufio"
+	"bytes"
 	"errors"
 	"flag"
 	"fmt"
+	"go/format"
 	"go/parser"
 	"go/token"
 	"io"
+	"io/ioutil"
 	"log"
 	"os"
 	"strconv"
@@ -57,7 +62,10 @@ import (
 	"text/template"
 )
 
-var PrintTraceFlag = flag.Bool("trace", false, "generate print statement after every syscall")
+var (
+	filename       = flag.String("output", "", "output file name (standard output if omitted)")
+	printTraceFlag = flag.Bool("trace", false, "generate print statement after every syscall")
+)
 
 func trim(s string) string {
 	return strings.Trim(s, " \t")
@@ -379,7 +387,7 @@ func newFn(s string) (*Fn, error) {
 	f := &Fn{
 		Rets:       &Rets{},
 		src:        s,
-		PrintTrace: *PrintTraceFlag,
+		PrintTrace: *printTraceFlag,
 	}
 	// function name and args
 	prefix, body, s, found := extractSection(s, '(', ')')
@@ -619,7 +627,7 @@ func (src *Source) DLLs() []string {
 	return r
 }
 
-// ParseFile adds adition file path to a source set src.
+// ParseFile adds additional file path to a source set src.
 func (src *Source) ParseFile(path string) error {
 	file, err := os.Open(path)
 	if err != nil {
@@ -669,8 +677,8 @@ func (src *Source) ParseFile(path string) error {
 // Generate output source file from a source set src.
 func (src *Source) Generate(w io.Writer) error {
 	funcMap := template.FuncMap{
-		"syscalldot":  syscalldot,
 		"packagename": packagename,
+		"syscalldot":  syscalldot,
 	}
 	t := template.Must(template.New("main").Funcs(funcMap).Parse(srcTemplate))
 	err := t.Execute(w, src)
@@ -689,15 +697,31 @@ func usage() {
 func main() {
 	flag.Usage = usage
 	flag.Parse()
-	if len(os.Args) <= 1 {
+	if len(flag.Args()) <= 0 {
 		fmt.Fprintf(os.Stderr, "no files to parse provided\n")
 		usage()
 	}
-	src, err := ParseFiles(os.Args[1:])
+
+	src, err := ParseFiles(flag.Args())
+	if err != nil {
+		log.Fatal(err)
+	}
+
+	var buf bytes.Buffer
+	if err := src.Generate(&buf); err != nil {
+		log.Fatal(err)
+	}
+
+	data, err := format.Source(buf.Bytes())
 	if err != nil {
 		log.Fatal(err)
 	}
-	if err := src.Generate(os.Stdout); err != nil {
+	if *filename == "" {
+		_, err = os.Stdout.Write(data)
+	} else {
+		err = ioutil.WriteFile(*filename, data, 0644)
+	}
+	if err != nil {
 		log.Fatal(err)
 	}
 }
@@ -705,14 +729,15 @@ func main() {
 // TODO: use println instead to print in the following template
 const srcTemplate = `
 
-{{define "main"}}// go build mksyscall_windows.go && ./mksyscall_windows{{range .Files}} {{.}}{{end}}
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+{{define "main"}}// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
 
 package {{packagename}}
 
 import "unsafe"{{if syscalldot}}
 import "syscall"{{end}}
 
+var _ unsafe.Pointer
+
 var (
 {{template "dlls" .}}
 {{template "funcnames" .}})
diff --git a/src/syscall/mksysnum_linux.pl b/src/syscall/mksysnum_linux.pl
index c7e5cf7..b6fbcb5 100755
--- a/src/syscall/mksysnum_linux.pl
+++ b/src/syscall/mksysnum_linux.pl
@@ -18,13 +18,26 @@ EOF
 
 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]+)/){
+open(GCC, "gcc -E -dD $ARGV[0] |") || die "can't run gcc";
+while(<GCC>){
+	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/pwd_plan9.go b/src/syscall/pwd_plan9.go
new file mode 100644
index 0000000..1248613
--- /dev/null
+++ b/src/syscall/pwd_plan9.go
@@ -0,0 +1,83 @@
+// 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.
+
+// The working directory in Plan 9 is effectively per P, so different
+// goroutines and even the same goroutine as it's rescheduled on
+// different Ps can see different working directories.
+//
+// Instead, track a Go process-wide intent of the current working directory,
+// and switch to it at important points.
+
+package syscall
+
+import "sync"
+
+var (
+	wdmu  sync.Mutex // guards following
+	wdSet bool
+	wdStr string
+)
+
+func Fixwd() {
+	wdmu.Lock()
+	defer wdmu.Unlock()
+	fixwdLocked()
+}
+
+func fixwdLocked() {
+	if !wdSet {
+		return
+	}
+	// always call chdir when getwd returns an error
+	wd, _ := getwd()
+	if wd == wdStr {
+		return
+	}
+	if err := chdir(wdStr); err != nil {
+		return
+	}
+}
+
+// goroutine-specific getwd
+func getwd() (wd string, err error) {
+	fd, err := open(".", O_RDONLY)
+	if err != nil {
+		return "", err
+	}
+	defer Close(fd)
+	return Fd2path(fd)
+}
+
+func Getwd() (wd string, err error) {
+	wdmu.Lock()
+	defer wdmu.Unlock()
+
+	if wdSet {
+		return wdStr, nil
+	}
+	wd, err = getwd()
+	if err != nil {
+		return
+	}
+	wdSet = true
+	wdStr = wd
+	return wd, nil
+}
+
+func Chdir(path string) error {
+	wdmu.Lock()
+	defer wdmu.Unlock()
+
+	if err := chdir(path); err != nil {
+		return err
+	}
+
+	wd, err := getwd()
+	if err != nil {
+		return err
+	}
+	wdSet = true
+	wdStr = wd
+	return nil
+}
diff --git a/src/syscall/route_bsd.go b/src/syscall/route_bsd.go
index 1dabe42..c62fdc3 100644
--- a/src/syscall/route_bsd.go
+++ b/src/syscall/route_bsd.go
@@ -4,23 +4,37 @@
 
 // +build darwin dragonfly freebsd netbsd openbsd
 
-// Routing sockets and messages
-
 package syscall
 
-import "unsafe"
+import (
+	"runtime"
+	"unsafe"
+)
+
+var (
+	freebsdConfArch       string // "machine $arch" line in kern.conftxt on freebsd
+	minRoutingSockaddrLen = rsaAlignOf(0)
+)
 
 // Round the length of a raw sockaddr up to align it properly.
 func rsaAlignOf(salen int) int {
 	salign := sizeofPtr
-	// NOTE: It seems like 64-bit Darwin kernel still requires
-	// 32-bit aligned access to BSD subsystem. Also NetBSD 6
-	// kernel and beyond require 64-bit aligned access to routing
-	// facilities.
 	if darwin64Bit {
+		// Darwin kernels require 32-bit aligned access to
+		// routing facilities.
 		salign = 4
 	} else if netbsd32Bit {
+		// NetBSD 6 and beyond kernels require 64-bit aligned
+		// access to routing facilities.
 		salign = 8
+	} else if runtime.GOOS == "freebsd" {
+		// In the case of kern.supported_archs="amd64 i386",
+		// we need to know the underlying kernel's
+		// architecture because the alignment for routing
+		// facilities are set at the build time of the kernel.
+		if freebsdConfArch == "amd64" {
+			salign = 8
+		}
 	}
 	if salen == 0 {
 		return salign
@@ -28,6 +42,134 @@ func rsaAlignOf(salen int) int {
 	return (salen + salign - 1) & ^(salign - 1)
 }
 
+// parseSockaddrLink parses b as a datalink socket address.
+func parseSockaddrLink(b []byte) (*SockaddrDatalink, error) {
+	sa, _, err := parseLinkLayerAddr(b[4:])
+	if err != nil {
+		return nil, err
+	}
+	rsa := (*RawSockaddrDatalink)(unsafe.Pointer(&b[0]))
+	sa.Len = rsa.Len
+	sa.Family = rsa.Family
+	sa.Index = rsa.Index
+	return sa, nil
+}
+
+// parseLinkLayerAddr parses b as a datalink socket address in
+// conventional BSD kernel form.
+func parseLinkLayerAddr(b []byte) (*SockaddrDatalink, int, error) {
+	// The encoding looks like the following:
+	// +----------------------------+
+	// | Type             (1 octet) |
+	// +----------------------------+
+	// | Name length      (1 octet) |
+	// +----------------------------+
+	// | Address length   (1 octet) |
+	// +----------------------------+
+	// | Selector length  (1 octet) |
+	// +----------------------------+
+	// | Data            (variable) |
+	// +----------------------------+
+	type linkLayerAddr struct {
+		Type byte
+		Nlen byte
+		Alen byte
+		Slen byte
+	}
+	lla := (*linkLayerAddr)(unsafe.Pointer(&b[0]))
+	l := rsaAlignOf(int(4 + lla.Nlen + lla.Alen + lla.Slen))
+	if len(b) < l {
+		return nil, 0, EINVAL
+	}
+	b = b[4:]
+	sa := &SockaddrDatalink{Type: lla.Type, Nlen: lla.Nlen, Alen: lla.Alen, Slen: lla.Slen}
+	for i := 0; len(sa.Data) > i && i < int(lla.Nlen+lla.Alen+lla.Slen); i++ {
+		sa.Data[i] = int8(b[i])
+	}
+	return sa, l, nil
+}
+
+// parseSockaddrInet parses b as an internet socket address.
+func parseSockaddrInet(b []byte, family byte) (Sockaddr, error) {
+	switch family {
+	case AF_INET:
+		if len(b) < SizeofSockaddrInet4 {
+			return nil, EINVAL
+		}
+		rsa := (*RawSockaddrAny)(unsafe.Pointer(&b[0]))
+		return anyToSockaddr(rsa)
+	case AF_INET6:
+		if len(b) < SizeofSockaddrInet6 {
+			return nil, EINVAL
+		}
+		rsa := (*RawSockaddrAny)(unsafe.Pointer(&b[0]))
+		return anyToSockaddr(rsa)
+	default:
+		return nil, EINVAL
+	}
+}
+
+const (
+	offsetofInet4 = int(unsafe.Offsetof(RawSockaddrInet4{}.Addr))
+	offsetofInet6 = int(unsafe.Offsetof(RawSockaddrInet6{}.Addr))
+)
+
+// parseNetworkLayerAddr parses b as an internet socket address in
+// conventional BSD kernel form.
+func parseNetworkLayerAddr(b []byte, family byte) (Sockaddr, error) {
+	// The encoding looks similar to the NLRI encoding.
+	// +----------------------------+
+	// | Length           (1 octet) |
+	// +----------------------------+
+	// | Address prefix  (variable) |
+	// +----------------------------+
+	//
+	// The differences between the kernel form and the NLRI
+	// encoding are:
+	//
+	// - The length field of the kernel form indicates the prefix
+	//   length in bytes, not in bits
+	//
+	// - In the kernel form, zero value of the length field
+	//   doesn't mean 0.0.0.0/0 or ::/0
+	//
+	// - The kernel form appends leading bytes to the prefix field
+	//   to make the <length, prefix> tuple to be conformed with
+	//   the routing messeage boundary
+	l := int(rsaAlignOf(int(b[0])))
+	if len(b) < l {
+		return nil, EINVAL
+	}
+	// 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])
+		} else {
+			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 {
+			copy(sa.Addr[:], b[1:l])
+		} else {
+			copy(sa.Addr[:], b[l-offsetofInet4:l])
+		}
+		return sa, nil
+	}
+}
+
 // RouteRIB returns routing information base, as known as RIB,
 // which consists of network facility information, states and
 // parameters.
@@ -50,7 +192,7 @@ func RouteRIB(facility, param int) ([]byte, error) {
 
 // RoutingMessage represents a routing message.
 type RoutingMessage interface {
-	sockaddr() []Sockaddr
+	sockaddr() ([]Sockaddr, error)
 }
 
 const anyMessageLen = int(unsafe.Sizeof(anyMessage{}))
@@ -68,50 +210,41 @@ type RouteMessage struct {
 	Data   []byte
 }
 
-const rtaRtMask = RTA_DST | RTA_GATEWAY | RTA_NETMASK | RTA_GENMASK
-
-func (m *RouteMessage) sockaddr() []Sockaddr {
-	var (
-		af  int
-		sas [4]Sockaddr
-	)
+func (m *RouteMessage) sockaddr() ([]Sockaddr, error) {
+	var sas [RTAX_MAX]Sockaddr
 	b := m.Data[:]
-	for i := uint(0); i < RTAX_MAX; i++ {
-		if m.Header.Addrs&rtaRtMask&(1<<i) == 0 {
+	family := uint8(AF_UNSPEC)
+	for i := uint(0); i < RTAX_MAX && len(b) >= minRoutingSockaddrLen; i++ {
+		if m.Header.Addrs&(1<<i) == 0 {
 			continue
 		}
 		rsa := (*RawSockaddr)(unsafe.Pointer(&b[0]))
-		switch i {
-		case RTAX_DST, RTAX_GATEWAY:
-			sa, err := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
+		switch rsa.Family {
+		case AF_LINK:
+			sa, err := parseSockaddrLink(b)
 			if err != nil {
-				return nil
+				return nil, err
 			}
-			if i == RTAX_DST {
-				af = int(rsa.Family)
+			sas[i] = sa
+			b = b[rsaAlignOf(int(rsa.Len)):]
+		case AF_INET, AF_INET6:
+			sa, err := parseSockaddrInet(b, rsa.Family)
+			if err != nil {
+				return nil, err
 			}
 			sas[i] = sa
-		case RTAX_NETMASK, RTAX_GENMASK:
-			switch af {
-			case AF_INET:
-				rsa4 := (*RawSockaddrInet4)(unsafe.Pointer(&b[0]))
-				sa := new(SockaddrInet4)
-				for j := 0; rsa4.Len > 0 && j < int(rsa4.Len)-int(unsafe.Offsetof(rsa4.Addr)); j++ {
-					sa.Addr[j] = rsa4.Addr[j]
-				}
-				sas[i] = sa
-			case AF_INET6:
-				rsa6 := (*RawSockaddrInet6)(unsafe.Pointer(&b[0]))
-				sa := new(SockaddrInet6)
-				for j := 0; rsa6.Len > 0 && j < int(rsa6.Len)-int(unsafe.Offsetof(rsa6.Addr)); j++ {
-					sa.Addr[j] = rsa6.Addr[j]
-				}
-				sas[i] = sa
+			b = b[rsaAlignOf(int(rsa.Len)):]
+			family = rsa.Family
+		default:
+			sa, err := parseNetworkLayerAddr(b, family)
+			if err != nil {
+				return nil, err
 			}
+			sas[i] = sa
+			b = b[rsaAlignOf(int(b[0])):]
 		}
-		b = b[rsaAlignOf(int(rsa.Len)):]
 	}
-	return sas[:]
+	return sas[:], nil
 }
 
 // InterfaceMessage represents a routing message containing
@@ -121,15 +254,17 @@ type InterfaceMessage struct {
 	Data   []byte
 }
 
-func (m *InterfaceMessage) sockaddr() (sas []Sockaddr) {
+func (m *InterfaceMessage) sockaddr() ([]Sockaddr, error) {
+	var sas [RTAX_MAX]Sockaddr
 	if m.Header.Addrs&RTA_IFP == 0 {
-		return nil
+		return nil, nil
 	}
-	sa, err := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(&m.Data[0])))
+	sa, err := parseSockaddrLink(m.Data[:])
 	if err != nil {
-		return nil
+		return nil, err
 	}
-	return append(sas, sa)
+	sas[RTAX_IFP] = sa
+	return sas[:], nil
 }
 
 // InterfaceAddrMessage represents a routing message containing
@@ -139,79 +274,63 @@ type InterfaceAddrMessage struct {
 	Data   []byte
 }
 
-const rtaIfaMask = RTA_IFA | RTA_NETMASK | RTA_BRD
-
-func (m *InterfaceAddrMessage) sockaddr() (sas []Sockaddr) {
-	if m.Header.Addrs&rtaIfaMask == 0 {
-		return nil
-	}
+func (m *InterfaceAddrMessage) sockaddr() ([]Sockaddr, error) {
+	var sas [RTAX_MAX]Sockaddr
 	b := m.Data[:]
-	// We still see AF_UNSPEC in socket addresses on some
-	// platforms. To identify each address family correctly, we
-	// will use the address family of RTAX_NETMASK as a preferred
-	// one on the 32-bit NetBSD kernel, also use the length of
-	// RTAX_NETMASK socket address on the FreeBSD kernel.
-	preferredFamily := uint8(AF_UNSPEC)
-	for i := uint(0); i < RTAX_MAX; i++ {
+	family := uint8(AF_UNSPEC)
+	for i := uint(0); i < RTAX_MAX && len(b) >= minRoutingSockaddrLen; i++ {
 		if m.Header.Addrs&(1<<i) == 0 {
 			continue
 		}
 		rsa := (*RawSockaddr)(unsafe.Pointer(&b[0]))
-		switch i {
-		case RTAX_IFA:
-			if rsa.Family == AF_UNSPEC {
-				rsa.Family = preferredFamily
-			}
-			sa, err := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
+		switch rsa.Family {
+		case AF_LINK:
+			sa, err := parseSockaddrLink(b)
 			if err != nil {
-				return nil
+				return nil, err
 			}
-			sas = append(sas, sa)
-		case RTAX_NETMASK:
-			switch rsa.Family {
-			case AF_UNSPEC:
-				switch rsa.Len {
-				case SizeofSockaddrInet4:
-					rsa.Family = AF_INET
-				case SizeofSockaddrInet6:
-					rsa.Family = AF_INET6
-				default:
-					rsa.Family = AF_INET // an old fashion, AF_UNSPEC means AF_INET
-				}
-			case AF_INET, AF_INET6:
-				preferredFamily = rsa.Family
-			default:
-				return nil
+			sas[i] = sa
+			b = b[rsaAlignOf(int(rsa.Len)):]
+		case AF_INET, AF_INET6:
+			sa, err := parseSockaddrInet(b, rsa.Family)
+			if err != nil {
+				return nil, err
 			}
-			sa, err := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
+			sas[i] = sa
+			b = b[rsaAlignOf(int(rsa.Len)):]
+			family = rsa.Family
+		default:
+			sa, err := parseNetworkLayerAddr(b, family)
 			if err != nil {
-				return nil
+				return nil, err
 			}
-			sas = append(sas, sa)
-		case RTAX_BRD:
-			// nothing to do
+			sas[i] = sa
+			b = b[rsaAlignOf(int(b[0])):]
 		}
-		b = b[rsaAlignOf(int(rsa.Len)):]
 	}
-	return sas
+	return sas[:], nil
 }
 
 // ParseRoutingMessage parses b as routing messages and returns the
 // slice containing the RoutingMessage interfaces.
 func ParseRoutingMessage(b []byte) (msgs []RoutingMessage, err error) {
-	msgCount := 0
+	nmsgs, nskips := 0, 0
 	for len(b) >= anyMessageLen {
-		msgCount++
+		nmsgs++
 		any := (*anyMessage)(unsafe.Pointer(&b[0]))
 		if any.Version != RTM_VERSION {
 			b = b[any.Msglen:]
 			continue
 		}
-		msgs = append(msgs, any.toRoutingMessage(b))
+		if m := any.toRoutingMessage(b); m == nil {
+			nskips++
+		} else {
+			msgs = append(msgs, m)
+		}
 		b = b[any.Msglen:]
 	}
 	// We failed to parse any of the messages - version mismatch?
-	if msgCount > 0 && len(msgs) == 0 {
+	if nmsgs != len(msgs)+nskips {
 		return nil, EINVAL
 	}
 	return msgs, nil
@@ -219,6 +338,10 @@ func ParseRoutingMessage(b []byte) (msgs []RoutingMessage, err error) {
 
 // ParseRoutingMessage parses msg's payload as raw sockaddrs and
 // returns the slice containing the Sockaddr interfaces.
-func ParseRoutingSockaddr(msg RoutingMessage) (sas []Sockaddr, err error) {
-	return append(sas, msg.sockaddr()...), nil
+func ParseRoutingSockaddr(msg RoutingMessage) ([]Sockaddr, error) {
+	sas, err := msg.sockaddr()
+	if err != nil {
+		return nil, err
+	}
+	return sas, nil
 }
diff --git a/src/syscall/route_bsd_test.go b/src/syscall/route_bsd_test.go
new file mode 100644
index 0000000..8617663
--- /dev/null
+++ b/src/syscall/route_bsd_test.go
@@ -0,0 +1,225 @@
+// 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 netbsd openbsd
+
+package syscall_test
+
+import (
+	"fmt"
+	"net"
+	"os"
+	"syscall"
+	"testing"
+	"time"
+)
+
+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} {
+			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
+			}
+			msgs, err := syscall.ParseRoutingMessage(b)
+			if err != nil {
+				t.Error(facility, param, err)
+				continue
+			}
+			var ipv4loopback, ipv6loopback bool
+			for _, m := range msgs {
+				flags, err := parseRoutingMessageHeader(m)
+				if err != nil {
+					t.Error(err)
+					continue
+				}
+				sas, err := parseRoutingSockaddrs(m)
+				if err != nil {
+					t.Error(err)
+					continue
+				}
+				if flags&(syscall.RTA_DST|syscall.RTA_IFA) != 0 {
+					sa := sas[syscall.RTAX_DST]
+					if sa == nil {
+						sa = sas[syscall.RTAX_IFA]
+					}
+					switch sa := sa.(type) {
+					case *syscall.SockaddrInet4:
+						if net.IP(sa.Addr[:]).IsLoopback() {
+							ipv4loopback = true
+						}
+					case *syscall.SockaddrInet6:
+						if net.IP(sa.Addr[:]).IsLoopback() {
+							ipv6loopback = true
+						}
+					}
+				}
+				t.Log(facility, param, flags, sockaddrs(sas))
+			}
+			if param == syscall.AF_UNSPEC && len(msgs) > 0 && !ipv4loopback && !ipv6loopback {
+				t.Errorf("no loopback facility found: ipv4/ipv6=%v/%v, %v", ipv4loopback, ipv6loopback, len(msgs))
+				continue
+			}
+		}
+	}
+}
+
+func TestRouteMonitor(t *testing.T) {
+	if testing.Short() || os.Getuid() != 0 {
+		t.Skip("must be root")
+	}
+
+	s, err := syscall.Socket(syscall.AF_ROUTE, syscall.SOCK_RAW, syscall.AF_UNSPEC)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer syscall.Close(s)
+
+	tmo := time.After(30 * time.Second)
+	go func() {
+		b := make([]byte, os.Getpagesize())
+		for {
+			n, err := syscall.Read(s, b)
+			if err != nil {
+				return
+			}
+			msgs, err := syscall.ParseRoutingMessage(b[:n])
+			if err != nil {
+				t.Error(err)
+				return
+			}
+			for _, m := range msgs {
+				flags, err := parseRoutingMessageHeader(m)
+				if err != nil {
+					t.Error(err)
+					continue
+				}
+				sas, err := parseRoutingSockaddrs(m)
+				if err != nil {
+					t.Error(err)
+					continue
+				}
+				t.Log(flags, sockaddrs(sas))
+			}
+		}
+	}()
+	<-tmo
+}
+
+type addrFamily byte
+
+func (f addrFamily) String() string {
+	switch f {
+	case syscall.AF_UNSPEC:
+		return "unspec"
+	case syscall.AF_LINK:
+		return "link"
+	case syscall.AF_INET:
+		return "inet4"
+	case syscall.AF_INET6:
+		return "inet6"
+	default:
+		return fmt.Sprintf("unknown %d", f)
+	}
+}
+
+type addrFlags uint32
+
+var addrFlagNames = [...]string{
+	"dst",
+	"gateway",
+	"netmask",
+	"genmask",
+	"ifp",
+	"ifa",
+	"author",
+	"brd",
+	"mpls1,tag,src", // sockaddr_mpls=dragonfly,netbsd, sockaddr_in/in6=openbsd
+	"mpls2,srcmask", // sockaddr_mpls=dragonfly, sockaddr_in/in6=openbsd
+	"mpls3,label",   // sockaddr_mpls=dragonfly, sockaddr_rtlabel=openbsd
+}
+
+func (f addrFlags) String() string {
+	var s string
+	for i, name := range addrFlagNames {
+		if f&(1<<uint(i)) != 0 {
+			if s != "" {
+				s += "|"
+			}
+			s += name
+		}
+	}
+	if s == "" {
+		return "<nil>"
+	}
+	return s
+}
+
+type sockaddrs []syscall.Sockaddr
+
+func (sas sockaddrs) String() string {
+	var s string
+	for _, sa := range sas {
+		if sa == nil {
+			continue
+		}
+		if len(s) > 0 {
+			s += " "
+		}
+		switch sa := sa.(type) {
+		case *syscall.SockaddrDatalink:
+			s += fmt.Sprintf("[%v/%v/%v t/n/a/s=%v/%v/%v/%v]", sa.Len, addrFamily(sa.Family), sa.Index, sa.Type, sa.Nlen, sa.Alen, sa.Slen)
+		case *syscall.SockaddrInet4:
+			s += fmt.Sprintf("%v", net.IP(sa.Addr[:]).To4())
+		case *syscall.SockaddrInet6:
+			s += fmt.Sprintf("%v", net.IP(sa.Addr[:]).To16())
+		}
+	}
+	if s == "" {
+		return "<nil>"
+	}
+	return s
+}
+
+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)
+	}
+	return nil
+}
diff --git a/src/syscall/route_darwin.go b/src/syscall/route_darwin.go
index ad27907..89bca12 100644
--- a/src/syscall/route_darwin.go
+++ b/src/syscall/route_darwin.go
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Routing sockets and messages for Darwin
-
 package syscall
 
 import "unsafe"
@@ -33,29 +31,37 @@ type InterfaceMulticastAddrMessage struct {
 	Data   []byte
 }
 
-const rtaIfmaMask = RTA_GATEWAY | RTA_IFP | RTA_IFA
-
-func (m *InterfaceMulticastAddrMessage) sockaddr() (sas []Sockaddr) {
-	if m.Header.Addrs&rtaIfmaMask == 0 {
-		return nil
-	}
+func (m *InterfaceMulticastAddrMessage) sockaddr() ([]Sockaddr, error) {
+	var sas [RTAX_MAX]Sockaddr
 	b := m.Data[:]
-	for i := uint(0); i < RTAX_MAX; i++ {
-		if m.Header.Addrs&rtaIfmaMask&(1<<i) == 0 {
+	for i := uint(0); i < RTAX_MAX && len(b) >= minRoutingSockaddrLen; i++ {
+		if m.Header.Addrs&(1<<i) == 0 {
 			continue
 		}
 		rsa := (*RawSockaddr)(unsafe.Pointer(&b[0]))
-		switch i {
-		case RTAX_IFA:
-			sa, e := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
-			if e != nil {
-				return nil
+		switch rsa.Family {
+		case AF_LINK:
+			sa, err := parseSockaddrLink(b)
+			if err != nil {
+				return nil, err
+			}
+			sas[i] = sa
+			b = b[rsaAlignOf(int(rsa.Len)):]
+		case AF_INET, AF_INET6:
+			sa, err := parseSockaddrInet(b, rsa.Family)
+			if err != nil {
+				return nil, err
+			}
+			sas[i] = sa
+			b = b[rsaAlignOf(int(rsa.Len)):]
+		default:
+			sa, l, err := parseLinkLayerAddr(b)
+			if err != nil {
+				return nil, err
 			}
-			sas = append(sas, sa)
-		case RTAX_GATEWAY, RTAX_IFP:
-			// nothing to do
+			sas[i] = sa
+			b = b[l:]
 		}
-		b = b[rsaAlignOf(int(rsa.Len)):]
 	}
-	return sas
+	return sas[:], nil
 }
diff --git a/src/syscall/route_dragonfly.go b/src/syscall/route_dragonfly.go
index 79190d2..5226f7f 100644
--- a/src/syscall/route_dragonfly.go
+++ b/src/syscall/route_dragonfly.go
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Routing sockets and messages for Dragonfly
-
 package syscall
 
 import "unsafe"
@@ -12,6 +10,8 @@ func (any *anyMessage) toRoutingMessage(b []byte) RoutingMessage {
 	switch any.Type {
 	case RTM_ADD, RTM_DELETE, RTM_CHANGE, RTM_GET, RTM_LOSING, RTM_REDIRECT, RTM_MISS, RTM_LOCK, RTM_RESOLVE:
 		p := (*RouteMessage)(unsafe.Pointer(any))
+		// We don't support sockaddr_mpls for now.
+		p.Header.Addrs &= RTA_DST | RTA_GATEWAY | RTA_NETMASK | RTA_GENMASK | RTA_IFA | RTA_IFP | RTA_BRD | RTA_AUTHOR
 		return &RouteMessage{Header: p.Header, Data: b[SizeofRtMsghdr:any.Msglen]}
 	case RTM_IFINFO:
 		p := (*InterfaceMessage)(unsafe.Pointer(any))
@@ -35,7 +35,7 @@ type InterfaceAnnounceMessage struct {
 	Header IfAnnounceMsghdr
 }
 
-func (m *InterfaceAnnounceMessage) sockaddr() (sas []Sockaddr) { return nil }
+func (m *InterfaceAnnounceMessage) sockaddr() ([]Sockaddr, error) { return nil, nil }
 
 // InterfaceMulticastAddrMessage represents a routing message
 // containing network interface address entries.
@@ -44,29 +44,37 @@ type InterfaceMulticastAddrMessage struct {
 	Data   []byte
 }
 
-const rtaIfmaMask = RTA_GATEWAY | RTA_IFP | RTA_IFA
-
-func (m *InterfaceMulticastAddrMessage) sockaddr() (sas []Sockaddr) {
-	if m.Header.Addrs&rtaIfmaMask == 0 {
-		return nil
-	}
+func (m *InterfaceMulticastAddrMessage) sockaddr() ([]Sockaddr, error) {
+	var sas [RTAX_MAX]Sockaddr
 	b := m.Data[:]
-	for i := uint(0); i < RTAX_MAX; i++ {
-		if m.Header.Addrs&rtaIfmaMask&(1<<i) == 0 {
+	for i := uint(0); i < RTAX_MAX && len(b) >= minRoutingSockaddrLen; i++ {
+		if m.Header.Addrs&(1<<i) == 0 {
 			continue
 		}
 		rsa := (*RawSockaddr)(unsafe.Pointer(&b[0]))
-		switch i {
-		case RTAX_IFA:
-			sa, e := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
-			if e != nil {
-				return nil
+		switch rsa.Family {
+		case AF_LINK:
+			sa, err := parseSockaddrLink(b)
+			if err != nil {
+				return nil, err
+			}
+			sas[i] = sa
+			b = b[rsaAlignOf(int(rsa.Len)):]
+		case AF_INET, AF_INET6:
+			sa, err := parseSockaddrInet(b, rsa.Family)
+			if err != nil {
+				return nil, err
+			}
+			sas[i] = sa
+			b = b[rsaAlignOf(int(rsa.Len)):]
+		default:
+			sa, l, err := parseLinkLayerAddr(b)
+			if err != nil {
+				return nil, err
 			}
-			sas = append(sas, sa)
-		case RTAX_GATEWAY, RTAX_IFP:
-			// nothing to do
+			sas[i] = sa
+			b = b[l:]
 		}
-		b = b[rsaAlignOf(int(rsa.Len)):]
 	}
-	return sas
+	return sas[:], nil
 }
diff --git a/src/syscall/route_freebsd.go b/src/syscall/route_freebsd.go
index 15897b1..0e18103 100644
--- a/src/syscall/route_freebsd.go
+++ b/src/syscall/route_freebsd.go
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Routing sockets and messages for FreeBSD
-
 package syscall
 
 import "unsafe"
@@ -13,13 +11,31 @@ var freebsdVersion uint32
 
 func init() {
 	freebsdVersion, _ = SysctlUint32("kern.osreldate")
+	conf, _ := Sysctl("kern.conftxt")
+	for i, j := 0, 0; j < len(conf); j++ {
+		if conf[j] != '\n' {
+			continue
+		}
+		s := conf[i:j]
+		i = j + 1
+		if len(s) > len("machine") && s[:len("machine")] == "machine" {
+			s = s[len("machine"):]
+			for k := 0; k < len(s); k++ {
+				if s[k] == ' ' || s[k] == '\t' {
+					s = s[1:]
+				}
+				break
+			}
+			freebsdConfArch = s
+			break
+		}
+	}
 }
 
 func (any *anyMessage) toRoutingMessage(b []byte) RoutingMessage {
 	switch any.Type {
 	case RTM_ADD, RTM_DELETE, RTM_CHANGE, RTM_GET, RTM_LOSING, RTM_REDIRECT, RTM_MISS, RTM_LOCK, RTM_RESOLVE:
-		p := (*RouteMessage)(unsafe.Pointer(any))
-		return &RouteMessage{Header: p.Header, Data: b[SizeofRtMsghdr:any.Msglen]}
+		return any.parseRouteMessage(b)
 	case RTM_IFINFO:
 		return any.parseInterfaceMessage(b)
 	case RTM_IFANNOUNCE:
@@ -41,7 +57,7 @@ type InterfaceAnnounceMessage struct {
 	Header IfAnnounceMsghdr
 }
 
-func (m *InterfaceAnnounceMessage) sockaddr() (sas []Sockaddr) { return nil }
+func (m *InterfaceAnnounceMessage) sockaddr() ([]Sockaddr, error) { return nil, nil }
 
 // InterfaceMulticastAddrMessage represents a routing message
 // containing network interface address entries.
@@ -50,29 +66,37 @@ type InterfaceMulticastAddrMessage struct {
 	Data   []byte
 }
 
-const rtaIfmaMask = RTA_GATEWAY | RTA_IFP | RTA_IFA
-
-func (m *InterfaceMulticastAddrMessage) sockaddr() (sas []Sockaddr) {
-	if m.Header.Addrs&rtaIfmaMask == 0 {
-		return nil
-	}
+func (m *InterfaceMulticastAddrMessage) sockaddr() ([]Sockaddr, error) {
+	var sas [RTAX_MAX]Sockaddr
 	b := m.Data[:]
-	for i := uint(0); i < RTAX_MAX; i++ {
-		if m.Header.Addrs&rtaIfmaMask&(1<<i) == 0 {
+	for i := uint(0); i < RTAX_MAX && len(b) >= minRoutingSockaddrLen; i++ {
+		if m.Header.Addrs&(1<<i) == 0 {
 			continue
 		}
 		rsa := (*RawSockaddr)(unsafe.Pointer(&b[0]))
-		switch i {
-		case RTAX_IFA:
-			sa, e := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
-			if e != nil {
-				return nil
+		switch rsa.Family {
+		case AF_LINK:
+			sa, err := parseSockaddrLink(b)
+			if err != nil {
+				return nil, err
+			}
+			sas[i] = sa
+			b = b[rsaAlignOf(int(rsa.Len)):]
+		case AF_INET, AF_INET6:
+			sa, err := parseSockaddrInet(b, rsa.Family)
+			if err != nil {
+				return nil, err
+			}
+			sas[i] = sa
+			b = b[rsaAlignOf(int(rsa.Len)):]
+		default:
+			sa, l, err := parseLinkLayerAddr(b)
+			if err != nil {
+				return nil, err
 			}
-			sas = append(sas, sa)
-		case RTAX_GATEWAY, RTAX_IFP:
-			// nothing to do
+			sas[i] = sa
+			b = b[l:]
 		}
-		b = b[rsaAlignOf(int(rsa.Len)):]
 	}
-	return sas
+	return sas[:], nil
 }
diff --git a/src/syscall/route_freebsd_32bit.go b/src/syscall/route_freebsd_32bit.go
index 93efddd..5c10b05 100644
--- a/src/syscall/route_freebsd_32bit.go
+++ b/src/syscall/route_freebsd_32bit.go
@@ -8,6 +8,15 @@ package syscall
 
 import "unsafe"
 
+func (any *anyMessage) parseRouteMessage(b []byte) *RouteMessage {
+	p := (*RouteMessage)(unsafe.Pointer(any))
+	off := int(unsafe.Offsetof(p.Header.Rmx)) + SizeofRtMetrics
+	if freebsdConfArch == "amd64" {
+		off += SizeofRtMetrics // rt_metrics on amd64 is simply doubled
+	}
+	return &RouteMessage{Header: p.Header, Data: b[rsaAlignOf(off):any.Msglen]}
+}
+
 func (any *anyMessage) parseInterfaceMessage(b []byte) *InterfaceMessage {
 	p := (*InterfaceMessage)(unsafe.Pointer(any))
 	// FreeBSD 10 and beyond have a restructured mbuf
@@ -18,7 +27,7 @@ func (any *anyMessage) parseInterfaceMessage(b []byte) *InterfaceMessage {
 		p.Header.Data.Hwassist = uint32(m.Data.Hwassist)
 		p.Header.Data.Epoch = m.Data.Epoch
 		p.Header.Data.Lastchange = m.Data.Lastchange
-		return &InterfaceMessage{Header: p.Header, Data: b[sizeofIfMsghdr:any.Msglen]}
+		return &InterfaceMessage{Header: p.Header, Data: b[int(unsafe.Offsetof(p.Header.Data))+int(p.Header.Data.Datalen) : any.Msglen]}
 	}
-	return &InterfaceMessage{Header: p.Header, Data: b[SizeofIfMsghdr:any.Msglen]}
+	return &InterfaceMessage{Header: p.Header, Data: b[int(unsafe.Offsetof(p.Header.Data))+int(p.Header.Data.Datalen) : any.Msglen]}
 }
diff --git a/src/syscall/route_freebsd_64bit.go b/src/syscall/route_freebsd_64bit.go
index 9377f2f..728837e 100644
--- a/src/syscall/route_freebsd_64bit.go
+++ b/src/syscall/route_freebsd_64bit.go
@@ -8,7 +8,12 @@ package syscall
 
 import "unsafe"
 
+func (any *anyMessage) parseRouteMessage(b []byte) *RouteMessage {
+	p := (*RouteMessage)(unsafe.Pointer(any))
+	return &RouteMessage{Header: p.Header, Data: b[rsaAlignOf(int(unsafe.Offsetof(p.Header.Rmx))+SizeofRtMetrics):any.Msglen]}
+}
+
 func (any *anyMessage) parseInterfaceMessage(b []byte) *InterfaceMessage {
 	p := (*InterfaceMessage)(unsafe.Pointer(any))
-	return &InterfaceMessage{Header: p.Header, Data: b[SizeofIfMsghdr:any.Msglen]}
+	return &InterfaceMessage{Header: p.Header, Data: b[int(unsafe.Offsetof(p.Header.Data))+int(p.Header.Data.Datalen) : any.Msglen]}
 }
diff --git a/src/syscall/route_ifma_test.go b/src/syscall/route_ifma_test.go
new file mode 100644
index 0000000..af2b67d
--- /dev/null
+++ b/src/syscall/route_ifma_test.go
@@ -0,0 +1,74 @@
+// 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
+
+package syscall_test
+
+import (
+	"fmt"
+	"syscall"
+)
+
+func parseRoutingMessageHeader(m syscall.RoutingMessage) (addrFlags, error) {
+	switch m := m.(type) {
+	case *syscall.RouteMessage:
+		errno := syscall.Errno(uintptr(m.Header.Errno))
+		if errno != 0 {
+			return 0, fmt.Errorf("%T: %v, %#v", m, errno, m.Header)
+		}
+		return addrFlags(m.Header.Addrs), nil
+	case *syscall.InterfaceMessage:
+		return addrFlags(m.Header.Addrs), nil
+	case *syscall.InterfaceAddrMessage:
+		return addrFlags(m.Header.Addrs), nil
+	case *syscall.InterfaceMulticastAddrMessage:
+		return addrFlags(m.Header.Addrs), nil
+	default:
+		panic(fmt.Sprintf("unknown routing message type: %T", m))
+	}
+}
+
+func parseRoutingSockaddrs(m syscall.RoutingMessage) ([]syscall.Sockaddr, error) {
+	switch m := m.(type) {
+	case *syscall.RouteMessage:
+		sas, err := syscall.ParseRoutingSockaddr(m)
+		if err != nil {
+			return nil, fmt.Errorf("%T: %v, %#v", m, err, m.Data)
+		}
+		if err = sockaddrs(sas).match(addrFlags(m.Header.Addrs)); err != nil {
+			return nil, err
+		}
+		return sas, nil
+	case *syscall.InterfaceMessage:
+		sas, err := syscall.ParseRoutingSockaddr(m)
+		if err != nil {
+			return nil, fmt.Errorf("%T: %v, %#v", m, err, m.Data)
+		}
+		if err = sockaddrs(sas).match(addrFlags(m.Header.Addrs)); err != nil {
+			return nil, err
+		}
+		return sas, nil
+	case *syscall.InterfaceAddrMessage:
+		sas, err := syscall.ParseRoutingSockaddr(m)
+		if err != nil {
+			return nil, fmt.Errorf("%T: %v, %#v", m, err, m.Data)
+		}
+		if err = sockaddrs(sas).match(addrFlags(m.Header.Addrs)); err != nil {
+			return nil, err
+		}
+		return sas, nil
+	case *syscall.InterfaceMulticastAddrMessage:
+		sas, err := syscall.ParseRoutingSockaddr(m)
+		if err != nil {
+			return nil, fmt.Errorf("%T: %v, %#v", m, err, m.Data)
+		}
+		if err = sockaddrs(sas).match(addrFlags(m.Header.Addrs)); err != nil {
+			return nil, err
+		}
+		return sas, nil
+	default:
+		panic(fmt.Sprintf("unknown routing message type: %T", m))
+	}
+}
diff --git a/src/syscall/route_netbsd.go b/src/syscall/route_netbsd.go
index 9883aeb..d605ffa 100644
--- a/src/syscall/route_netbsd.go
+++ b/src/syscall/route_netbsd.go
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Routing sockets and messages for NetBSD
-
 package syscall
 
 import "unsafe"
@@ -12,6 +10,8 @@ func (any *anyMessage) toRoutingMessage(b []byte) RoutingMessage {
 	switch any.Type {
 	case RTM_ADD, RTM_DELETE, RTM_CHANGE, RTM_GET, RTM_LOSING, RTM_REDIRECT, RTM_MISS, RTM_LOCK, RTM_RESOLVE:
 		p := (*RouteMessage)(unsafe.Pointer(any))
+		// We don't support sockaddr_mpls for now.
+		p.Header.Addrs &= RTA_DST | RTA_GATEWAY | RTA_NETMASK | RTA_GENMASK | RTA_IFA | RTA_IFP | RTA_BRD | RTA_AUTHOR
 		return &RouteMessage{Header: p.Header, Data: b[SizeofRtMsghdr:any.Msglen]}
 	case RTM_IFINFO:
 		p := (*InterfaceMessage)(unsafe.Pointer(any))
@@ -32,4 +32,4 @@ type InterfaceAnnounceMessage struct {
 	Header IfAnnounceMsghdr
 }
 
-func (m *InterfaceAnnounceMessage) sockaddr() (sas []Sockaddr) { return nil }
+func (m *InterfaceAnnounceMessage) sockaddr() ([]Sockaddr, error) { return nil, nil }
diff --git a/src/syscall/route_noifma_test.go b/src/syscall/route_noifma_test.go
new file mode 100644
index 0000000..19d5d8e
--- /dev/null
+++ b/src/syscall/route_noifma_test.go
@@ -0,0 +1,63 @@
+// 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 netbsd openbsd
+
+package syscall_test
+
+import (
+	"fmt"
+	"syscall"
+)
+
+func parseRoutingMessageHeader(m syscall.RoutingMessage) (addrFlags, error) {
+	switch m := m.(type) {
+	case *syscall.RouteMessage:
+		errno := syscall.Errno(uintptr(m.Header.Errno))
+		if errno != 0 {
+			return 0, fmt.Errorf("%T: %v, %#v", m, errno, m.Header)
+		}
+		return addrFlags(m.Header.Addrs), nil
+	case *syscall.InterfaceMessage:
+		return addrFlags(m.Header.Addrs), nil
+	case *syscall.InterfaceAddrMessage:
+		return addrFlags(m.Header.Addrs), nil
+	default:
+		panic(fmt.Sprintf("unknown routing message type: %T", m))
+	}
+}
+
+func parseRoutingSockaddrs(m syscall.RoutingMessage) ([]syscall.Sockaddr, error) {
+	switch m := m.(type) {
+	case *syscall.RouteMessage:
+		sas, err := syscall.ParseRoutingSockaddr(m)
+		if err != nil {
+			return nil, fmt.Errorf("%T: %v, %#v", m, err, m.Data)
+		}
+		if err = sockaddrs(sas).match(addrFlags(m.Header.Addrs)); err != nil {
+			return nil, err
+		}
+		return sas, nil
+	case *syscall.InterfaceMessage:
+		sas, err := syscall.ParseRoutingSockaddr(m)
+		if err != nil {
+			return nil, fmt.Errorf("%T: %v, %#v", m, err, m.Data)
+		}
+		if err = sockaddrs(sas).match(addrFlags(m.Header.Addrs)); err != nil {
+			return nil, err
+		}
+		return sas, nil
+	case *syscall.InterfaceAddrMessage:
+		sas, err := syscall.ParseRoutingSockaddr(m)
+		if err != nil {
+			return nil, fmt.Errorf("%T: %v, %#v", m, err, m.Data)
+		}
+		if err = sockaddrs(sas).match(addrFlags(m.Header.Addrs)); err != nil {
+			return nil, err
+		}
+		return sas, nil
+	default:
+		panic(fmt.Sprintf("unknown routing message type: %T", m))
+	}
+}
diff --git a/src/syscall/route_openbsd.go b/src/syscall/route_openbsd.go
index e508640..7804a08 100644
--- a/src/syscall/route_openbsd.go
+++ b/src/syscall/route_openbsd.go
@@ -2,8 +2,6 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Routing sockets and messages for OpenBSD
-
 package syscall
 
 import "unsafe"
@@ -12,6 +10,8 @@ func (any *anyMessage) toRoutingMessage(b []byte) RoutingMessage {
 	switch any.Type {
 	case RTM_ADD, RTM_DELETE, RTM_CHANGE, RTM_GET, RTM_LOSING, RTM_REDIRECT, RTM_MISS, RTM_LOCK, RTM_RESOLVE:
 		p := (*RouteMessage)(unsafe.Pointer(any))
+		// We don't support sockaddr_rtlabel for now.
+		p.Header.Addrs &= RTA_DST | RTA_GATEWAY | RTA_NETMASK | RTA_GENMASK | RTA_IFA | RTA_IFP | RTA_BRD | RTA_AUTHOR | RTA_SRC | RTA_SRCMASK
 		return &RouteMessage{Header: p.Header, Data: b[p.Header.Hdrlen:any.Msglen]}
 	case RTM_IFINFO:
 		p := (*InterfaceMessage)(unsafe.Pointer(any))
@@ -32,4 +32,4 @@ type InterfaceAnnounceMessage struct {
 	Header IfAnnounceMsghdr
 }
 
-func (m *InterfaceAnnounceMessage) sockaddr() (sas []Sockaddr) { return nil }
+func (m *InterfaceAnnounceMessage) sockaddr() ([]Sockaddr, error) { return nil, nil }
diff --git a/src/syscall/security_windows.go b/src/syscall/security_windows.go
index b22ecf5..1625b07 100644
--- a/src/syscall/security_windows.go
+++ b/src/syscall/security_windows.go
@@ -41,21 +41,20 @@ func TranslateAccountName(username string, from, to uint32, initSize int) (strin
 	if e != nil {
 		return "", e
 	}
-	b := make([]uint16, 50)
-	n := uint32(len(b))
-	e = TranslateName(u, from, to, &b[0], &n)
-	if e != nil {
+	n := uint32(50)
+	for {
+		b := make([]uint16, n)
+		e = TranslateName(u, from, to, &b[0], &n)
+		if e == nil {
+			return UTF16ToString(b[:n]), nil
+		}
 		if e != ERROR_INSUFFICIENT_BUFFER {
 			return "", e
 		}
-		// make receive buffers of requested size and try again
-		b = make([]uint16, n)
-		e = TranslateName(u, from, to, &b[0], &n)
-		if e != nil {
+		if n <= uint32(len(b)) {
 			return "", e
 		}
 	}
-	return UTF16ToString(b), nil
 }
 
 const (
@@ -136,26 +135,23 @@ func LookupSID(system, account string) (sid *SID, domain string, accType uint32,
 			return nil, "", 0, e
 		}
 	}
-	db := make([]uint16, 50)
-	dn := uint32(len(db))
-	b := make([]byte, 50)
-	n := uint32(len(b))
-	sid = (*SID)(unsafe.Pointer(&b[0]))
-	e = LookupAccountName(sys, acc, sid, &n, &db[0], &dn, &accType)
-	if e != nil {
+	n := uint32(50)
+	dn := uint32(50)
+	for {
+		b := make([]byte, n)
+		db := make([]uint16, dn)
+		sid = (*SID)(unsafe.Pointer(&b[0]))
+		e = LookupAccountName(sys, acc, sid, &n, &db[0], &dn, &accType)
+		if e == nil {
+			return sid, UTF16ToString(db), accType, nil
+		}
 		if e != ERROR_INSUFFICIENT_BUFFER {
 			return nil, "", 0, e
 		}
-		// make receive buffers of requested size and try again
-		b = make([]byte, n)
-		sid = (*SID)(unsafe.Pointer(&b[0]))
-		db = make([]uint16, dn)
-		e = LookupAccountName(sys, acc, sid, &n, &db[0], &dn, &accType)
-		if e != nil {
+		if n <= uint32(len(b)) {
 			return nil, "", 0, e
 		}
 	}
-	return sid, UTF16ToString(db), accType, nil
 }
 
 // String converts sid to a string format
@@ -197,24 +193,22 @@ func (sid *SID) LookupAccount(system string) (account, domain string, accType ui
 			return "", "", 0, err
 		}
 	}
-	b := make([]uint16, 50)
-	n := uint32(len(b))
-	db := make([]uint16, 50)
-	dn := uint32(len(db))
-	e := LookupAccountSid(sys, sid, &b[0], &n, &db[0], &dn, &accType)
-	if e != nil {
+	n := uint32(50)
+	dn := uint32(50)
+	for {
+		b := make([]uint16, n)
+		db := make([]uint16, dn)
+		e := LookupAccountSid(sys, sid, &b[0], &n, &db[0], &dn, &accType)
+		if e == nil {
+			return UTF16ToString(b), UTF16ToString(db), accType, nil
+		}
 		if e != ERROR_INSUFFICIENT_BUFFER {
 			return "", "", 0, e
 		}
-		// make receive buffers of requested size and try again
-		b = make([]uint16, n)
-		db = make([]uint16, dn)
-		e = LookupAccountSid(nil, sid, &b[0], &n, &db[0], &dn, &accType)
-		if e != nil {
+		if n <= uint32(len(b)) {
 			return "", "", 0, e
 		}
 	}
-	return UTF16ToString(b), UTF16ToString(db), accType, nil
 }
 
 const (
@@ -326,21 +320,20 @@ func (t Token) Close() error {
 
 // getInfo retrieves a specified type of information about an access token.
 func (t Token) getInfo(class uint32, initSize int) (unsafe.Pointer, error) {
-	b := make([]byte, initSize)
-	var n uint32
-	e := GetTokenInformation(t, class, &b[0], uint32(len(b)), &n)
-	if e != nil {
+	n := uint32(initSize)
+	for {
+		b := make([]byte, n)
+		e := GetTokenInformation(t, class, &b[0], uint32(len(b)), &n)
+		if e == nil {
+			return unsafe.Pointer(&b[0]), nil
+		}
 		if e != ERROR_INSUFFICIENT_BUFFER {
 			return nil, e
 		}
-		// make receive buffers of requested size and try again
-		b = make([]byte, n)
-		e = GetTokenInformation(t, class, &b[0], uint32(len(b)), &n)
-		if e != nil {
+		if n <= uint32(len(b)) {
 			return nil, e
 		}
 	}
-	return unsafe.Pointer(&b[0]), nil
 }
 
 // GetTokenUser retrieves access token t user account information.
@@ -366,19 +359,18 @@ func (t Token) GetTokenPrimaryGroup() (*Tokenprimarygroup, error) {
 // GetUserProfileDirectory retrieves path to the
 // root directory of the access token t user's profile.
 func (t Token) GetUserProfileDirectory() (string, error) {
-	b := make([]uint16, 100)
-	n := uint32(len(b))
-	e := GetUserProfileDirectory(t, &b[0], &n)
-	if e != nil {
+	n := uint32(100)
+	for {
+		b := make([]uint16, n)
+		e := GetUserProfileDirectory(t, &b[0], &n)
+		if e == nil {
+			return UTF16ToString(b), nil
+		}
 		if e != ERROR_INSUFFICIENT_BUFFER {
 			return "", e
 		}
-		// make receive buffers of requested size and try again
-		b = make([]uint16, n)
-		e = GetUserProfileDirectory(t, &b[0], &n)
-		if e != nil {
+		if n <= uint32(len(b)) {
 			return "", e
 		}
 	}
-	return UTF16ToString(b), nil
 }
diff --git a/src/syscall/so_solaris.go b/src/syscall/so_solaris.go
deleted file mode 100644
index 8b1980f..0000000
--- a/src/syscall/so_solaris.go
+++ /dev/null
@@ -1,262 +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.
-
-package syscall
-
-import (
-	"sync"
-	"sync/atomic"
-	"unsafe"
-)
-
-// soError describes reasons for shared library load failures.
-type soError struct {
-	Err     error
-	ObjName string
-	Msg     string
-}
-
-func (e *soError) Error() string { return e.Msg }
-
-// Implemented in asm_solaris_amd64.s.
-func rawSysvicall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
-func sysvicall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
-func dlclose(handle uintptr) (err Errno)
-func dlopen(name *uint8, mode uintptr) (handle uintptr, err Errno)
-func dlsym(handle uintptr, name *uint8) (proc uintptr, err Errno)
-
-// A so implements access to a single shared library object.
-type so struct {
-	Name   string
-	Handle uintptr
-}
-
-// loadSO loads shared library file into memory.
-func loadSO(name string) (*so, error) {
-	namep, err := BytePtrFromString(name)
-	if err != nil {
-		return nil, err
-	}
-	h, e := dlopen(namep, 1) // RTLD_LAZY
-	use(unsafe.Pointer(namep))
-	if e != 0 {
-		return nil, &soError{
-			Err:     e,
-			ObjName: name,
-			Msg:     "Failed to load " + name + ": " + e.Error(),
-		}
-	}
-	d := &so{
-		Name:   name,
-		Handle: uintptr(h),
-	}
-	return d, nil
-}
-
-// mustLoadSO is like loadSO but panics if load operation fails.
-func mustLoadSO(name string) *so {
-	d, e := loadSO(name)
-	if e != nil {
-		panic(e)
-	}
-	return d
-}
-
-// FindProc searches shared library d for procedure named name and returns
-// *proc if found. It returns an error if the search fails.
-func (d *so) FindProc(name string) (*proc, error) {
-	namep, err := BytePtrFromString(name)
-	if err != nil {
-		return nil, err
-	}
-	a, _ := dlsym(uintptr(d.Handle), namep)
-	use(unsafe.Pointer(namep))
-	if a == 0 {
-		return nil, &soError{
-			Err:     ENOSYS,
-			ObjName: name,
-			Msg:     "Failed to find " + name + " procedure in " + d.Name,
-		}
-	}
-	p := &proc{
-		SO:   d,
-		Name: name,
-		addr: a,
-	}
-	return p, nil
-}
-
-// MustFindProc is like FindProc but panics if search fails.
-func (d *so) MustFindProc(name string) *proc {
-	p, e := d.FindProc(name)
-	if e != nil {
-		panic(e)
-	}
-	return p
-}
-
-// Release unloads shared library d from memory.
-func (d *so) Release() (err error) {
-	return dlclose(d.Handle)
-}
-
-// A proc implements access to a procedure inside a shared library.
-type proc struct {
-	SO   *so
-	Name string
-	addr uintptr
-}
-
-// Addr returns the address of the procedure represented by p.
-// The return value can be passed to Syscall to run the procedure.
-func (p *proc) Addr() uintptr {
-	return p.addr
-}
-
-// Call executes procedure p with arguments a. It will panic, if more then
-// 6 arguments are supplied.
-//
-// The returned error is always non-nil, constructed from the result of
-// GetLastError.  Callers must inspect the primary return value to decide
-// whether an error occurred (according to the semantics of the specific
-// function being called) before consulting the error. The error will be
-// guaranteed to contain syscall.Errno.
-func (p *proc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
-	switch len(a) {
-	case 0:
-		return sysvicall6(p.Addr(), uintptr(len(a)), 0, 0, 0, 0, 0, 0)
-	case 1:
-		return sysvicall6(p.Addr(), uintptr(len(a)), a[0], 0, 0, 0, 0, 0)
-	case 2:
-		return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], 0, 0, 0, 0)
-	case 3:
-		return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], 0, 0, 0)
-	case 4:
-		return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], 0, 0)
-	case 5:
-		return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], 0)
-	case 6:
-		return sysvicall6(p.Addr(), uintptr(len(a)), a[0], a[1], a[2], a[3], a[4], a[5])
-	default:
-		panic("Call " + p.Name + " with too many arguments " + itoa(len(a)) + ".")
-	}
-	return
-}
-
-// A lazySO implements access to a single shared library.  It will delay
-// the load of the shared library until the first call to its Handle method
-// or to one of its lazyProc's Addr method.
-type lazySO struct {
-	mu   sync.Mutex
-	so   *so // non nil once SO is loaded
-	Name string
-}
-
-// Load loads single shared file d.Name into memory. It returns an error if
-// fails.  Load will not try to load SO, if it is already loaded into memory.
-func (d *lazySO) Load() error {
-	// Non-racy version of:
-	// if d.so == nil {
-	if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&d.so))) == nil {
-		d.mu.Lock()
-		defer d.mu.Unlock()
-		if d.so == nil {
-			so, e := loadSO(d.Name)
-			if e != nil {
-				return e
-			}
-			// Non-racy version of:
-			// d.so = so
-			atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&d.so)), unsafe.Pointer(so))
-		}
-	}
-	return nil
-}
-
-// mustLoad is like Load but panics if search fails.
-func (d *lazySO) mustLoad() {
-	e := d.Load()
-	if e != nil {
-		panic(e)
-	}
-}
-
-// Handle returns d's module handle.
-func (d *lazySO) Handle() uintptr {
-	d.mustLoad()
-	return uintptr(d.so.Handle)
-}
-
-// NewProc returns a lazyProc for accessing the named procedure in the SO d.
-func (d *lazySO) NewProc(name string) *lazyProc {
-	return &lazyProc{l: d, Name: name}
-}
-
-// newLazySO creates new lazySO associated with SO file.
-func newLazySO(name string) *lazySO {
-	return &lazySO{Name: name}
-}
-
-// A lazyProc implements access to a procedure inside a lazySO.
-// It delays the lookup until the Addr method is called.
-type lazyProc struct {
-	mu   sync.Mutex
-	Name string
-	l    *lazySO
-	proc *proc
-}
-
-// Find searches the shared library for procedure named p.Name. It returns an
-// error if search fails. Find will not search procedure, if it is already
-// found and loaded into memory.
-func (p *lazyProc) Find() error {
-	// Non-racy version of:
-	// if p.proc == nil {
-	if atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc))) == nil {
-		p.mu.Lock()
-		defer p.mu.Unlock()
-		if p.proc == nil {
-			e := p.l.Load()
-			if e != nil {
-				return e
-			}
-			proc, e := p.l.so.FindProc(p.Name)
-			if e != nil {
-				return e
-			}
-			// Non-racy version of:
-			// p.proc = proc
-			atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&p.proc)), unsafe.Pointer(proc))
-		}
-	}
-	return nil
-}
-
-// mustFind is like Find but panics if search fails.
-func (p *lazyProc) mustFind() {
-	e := p.Find()
-	if e != nil {
-		panic(e)
-	}
-}
-
-// Addr returns the address of the procedure represented by p.
-// The return value can be passed to Syscall to run the procedure.
-func (p *lazyProc) Addr() uintptr {
-	p.mustFind()
-	return p.proc.Addr()
-}
-
-// Call executes procedure p with arguments a. It will panic, if more then
-// 6 arguments are supplied.
-//
-// The returned error is always non-nil, constructed from the result of
-// GetLastError.  Callers must inspect the primary return value to decide
-// whether an error occurred (according to the semantics of the specific
-// function being called) before consulting the error. The error will be
-// guaranteed to contain syscall.Errno.
-func (p *lazyProc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
-	p.mustFind()
-	return p.proc.Call(a...)
-}
diff --git a/src/syscall/syscall.go b/src/syscall/syscall.go
index 1f209ec..791bcbb 100644
--- a/src/syscall/syscall.go
+++ b/src/syscall/syscall.go
@@ -20,7 +20,7 @@
 //
 // NOTE: This package is locked down. Code outside the standard
 // Go repository should be migrated to use the corresponding
-// package in the go.sys subrepository. That is also where updates
+// package in the golang.org/x/sys repository. That is also where updates
 // required by new systems or versions should be applied.
 // See https://golang.org/s/go1.4-syscall for more information.
 //
@@ -28,9 +28,11 @@ package syscall
 
 import "unsafe"
 
-// StringByteSlice is deprecated. Use ByteSliceFromString instead.
+// StringByteSlice converts a string to a NUL-terminated []byte,
 // If s contains a NUL byte this function panics instead of
 // returning an error.
+//
+// Deprecated: Use ByteSliceFromString instead.
 func StringByteSlice(s string) []byte {
 	a, err := ByteSliceFromString(s)
 	if err != nil {
@@ -53,9 +55,11 @@ func ByteSliceFromString(s string) ([]byte, error) {
 	return a, nil
 }
 
-// StringBytePtr is deprecated. Use BytePtrFromString instead.
-// If s contains a NUL byte this function panics instead of
-// returning an error.
+// StringBytePtr returns a pointer to a NUL-terminated array of bytes.
+// If s contains a NUL byte this function panics instead of returning
+// an error.
+//
+// Deprecated: Use BytePtrFromString instead.
 func StringBytePtr(s string) *byte { return &StringByteSlice(s)[0] }
 
 // BytePtrFromString returns a pointer to a NUL-terminated array of
diff --git a/src/syscall/syscall_bsd.go b/src/syscall/syscall_bsd.go
index 2556fa8..af56391 100644
--- a/src/syscall/syscall_bsd.go
+++ b/src/syscall/syscall_bsd.go
@@ -68,40 +68,7 @@ func ReadDirent(fd int, buf []byte) (n int, err error) {
 	// actual system call is getdirentries64, 64 is a good guess.
 	// TODO(rsc): Can we use a single global basep for all calls?
 	var base = (*uintptr)(unsafe.Pointer(new(uint64)))
-	n, err = Getdirentries(fd, buf, base)
-
-	// On OS X 10.10 Yosemite, if you have a directory that can be returned
-	// in a single getdirentries64 call (for example, a directory with one file),
-	// and you read from the directory at EOF twice, you get EOF both times:
-	//	fd = open("dir")
-	//	getdirentries64(fd) // returns data
-	//	getdirentries64(fd) // returns 0 (EOF)
-	//	getdirentries64(fd) // returns 0 (EOF)
-	//
-	// But if you remove the file in the middle between the two calls, the
-	// second call returns an error instead.
-	//	fd = open("dir")
-	//	getdirentries64(fd) // returns data
-	//	getdirentries64(fd) // returns 0 (EOF)
-	//	remove("dir/file")
-	//	getdirentries64(fd) // returns ENOENT/EINVAL
-	//
-	// Whether you get ENOENT or EINVAL depends on exactly what was
-	// in the directory. It is deterministic, just data-dependent.
-	//
-	// This only happens in small directories. A directory containing more data
-	// than fits in a 4k getdirentries64 call will return EOF correctly.
-	// (It's not clear if the criteria is that the directory be split across multiple
-	// getdirentries64 calls or that it be split across multiple file system blocks.)
-	//
-	// We could change package os to avoid the second read at EOF,
-	// and maybe we should, but that's a bit involved.
-	// For now, treat the EINVAL/ENOENT as EOF.
-	if runtime.GOOS == "darwin" && (err == EINVAL || err == ENOENT) {
-		err = nil
-	}
-
-	return
+	return Getdirentries(fd, buf, base)
 }
 
 // Wait status is 7 bits at bottom, either 0 (exited),
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 @@ func Kill(pid int, signum Signal) (err error) { return kill(pid, int(signum), 1)
 //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 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
 	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_darwin_arm.go b/src/syscall/syscall_darwin_arm.go
new file mode 100644
index 0000000..2a7d4f2
--- /dev/null
+++ b/src/syscall/syscall_darwin_arm.go
@@ -0,0 +1,70 @@
+// 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 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.Nsec = int32(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.Usec = int32(nsec % 1e9 / 1e3)
+	tv.Sec = int32(nsec / 1e9)
+	return
+}
+
+//sysnb	gettimeofday(tp *Timeval) (sec int32, usec int32, err error)
+func Gettimeofday(tv *Timeval) (err error) {
+	// The tv passed to gettimeofday must be non-nil
+	// but is otherwise unused.  The answers come back
+	// in the two registers.
+	sec, usec, err := gettimeofday(tv)
+	tv.Sec = int32(sec)
+	tv.Usec = int32(usec)
+	return err
+}
+
+func SetKevent(k *Kevent_t, fd, mode, flags int) {
+	k.Ident = uint32(fd)
+	k.Filter = int16(mode)
+	k.Flags = uint16(flags)
+}
+
+func (iov *Iovec) SetLen(length int) {
+	iov.Len = uint32(length)
+}
+
+func (msghdr *Msghdr) SetControllen(length int) {
+	msghdr.Controllen = uint32(length)
+}
+
+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 length = uint64(count)
+
+	_, _, e1 := Syscall9(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr(*offset>>32), uintptr(unsafe.Pointer(&length)), 0, 0, 0, 0)
+
+	written = int(length)
+
+	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_darwin_arm64.go b/src/syscall/syscall_darwin_arm64.go
new file mode 100644
index 0000000..de7a08b
--- /dev/null
+++ b/src/syscall/syscall_darwin_arm64.go
@@ -0,0 +1,70 @@
+// 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
+
+import "unsafe"
+
+func Getpagesize() int { return 16384 }
+
+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.Usec = int32(nsec % 1e9 / 1e3)
+	tv.Sec = int64(nsec / 1e9)
+	return
+}
+
+//sysnb	gettimeofday(tp *Timeval) (sec int64, usec int32, err error)
+func Gettimeofday(tv *Timeval) (err error) {
+	// The tv passed to gettimeofday must be non-nil
+	// but is otherwise unused.  The answers come back
+	// in the two registers.
+	sec, usec, err := gettimeofday(tv)
+	tv.Sec = sec
+	tv.Usec = usec
+	return err
+}
+
+func SetKevent(k *Kevent_t, fd, mode, flags int) {
+	k.Ident = uint64(fd)
+	k.Filter = int16(mode)
+	k.Flags = uint16(flags)
+}
+
+func (iov *Iovec) SetLen(length int) {
+	iov.Len = uint64(length)
+}
+
+func (msghdr *Msghdr) SetControllen(length int) {
+	msghdr.Controllen = uint32(length)
+}
+
+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 length = uint64(count)
+
+	_, _, e1 := Syscall6(SYS_SENDFILE, uintptr(infd), uintptr(outfd), uintptr(*offset), uintptr(unsafe.Pointer(&length)), 0, 0)
+
+	written = int(length)
+
+	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_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 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
 //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_dragonfly_386.go
deleted file mode 100644
index ebd3d4c..0000000
--- a/src/syscall/syscall_dragonfly_386.go
+++ /dev/null
@@ -1,58 +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 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.Nsec = int32(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.Usec = int32(nsec % 1e9 / 1e3)
-	tv.Sec = int32(nsec / 1e9)
-	return
-}
-
-func SetKevent(k *Kevent_t, fd, mode, flags int) {
-	k.Ident = uint32(fd)
-	k.Filter = int16(mode)
-	k.Flags = uint16(flags)
-}
-
-func (iov *Iovec) SetLen(length int) {
-	iov.Len = uint32(length)
-}
-
-func (msghdr *Msghdr) SetControllen(length int) {
-	msghdr.Controllen = uint32(length)
-}
-
-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_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 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
 //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 c40c718..4f88d51 100644
--- a/src/syscall/syscall_linux.go
+++ b/src/syscall/syscall_linux.go
@@ -17,10 +17,38 @@ import "unsafe"
  * Wrapped
  */
 
-//sys	open(path string, mode int, perm uint32) (fd int, err error)
+func Access(path string, mode uint32) (err error) {
+	return Faccessat(_AT_FDCWD, path, mode, 0)
+}
+
+func Chmod(path string, mode uint32) (err error) {
+	return Fchmodat(_AT_FDCWD, path, mode, 0)
+}
+
+func Chown(path string, uid int, gid int) (err error) {
+	return Fchownat(_AT_FDCWD, path, uid, gid, 0)
+}
+
+func Creat(path string, mode uint32) (fd int, err error) {
+	return Open(path, O_CREAT|O_WRONLY|O_TRUNC, mode)
+}
+
+//sys	linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error)
+
+func Link(oldpath string, newpath string) (err error) {
+	return linkat(_AT_FDCWD, oldpath, _AT_FDCWD, newpath, 0)
+}
+
+func Mkdir(path string, mode uint32) (err error) {
+	return Mkdirat(_AT_FDCWD, path, mode)
+}
+
+func Mknod(path string, mode uint32, dev int) (err error) {
+	return Mknodat(_AT_FDCWD, path, mode, dev)
+}
 
 func Open(path string, mode int, perm uint32) (fd int, err error) {
-	return open(path, mode|O_LARGEFILE, perm)
+	return openat(_AT_FDCWD, path, mode|O_LARGEFILE, perm)
 }
 
 //sys	openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)
@@ -29,30 +57,34 @@ func Openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)
 	return openat(dirfd, path, flags|O_LARGEFILE, mode)
 }
 
-//sysnb	pipe(p *[2]_C_int) (err error)
+//sys	readlinkat(dirfd int, path string, buf []byte) (n int, err error)
 
-func Pipe(p []int) (err error) {
-	if len(p) != 2 {
-		return EINVAL
-	}
-	var pp [2]_C_int
-	err = pipe(&pp)
-	p[0] = int(pp[0])
-	p[1] = int(pp[1])
-	return
+func Readlink(path string, buf []byte) (n int, err error) {
+	return readlinkat(_AT_FDCWD, path, buf)
 }
 
-//sysnb pipe2(p *[2]_C_int, flags int) (err error)
+func Rename(oldpath string, newpath string) (err error) {
+	return Renameat(_AT_FDCWD, oldpath, _AT_FDCWD, newpath)
+}
 
-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 Rmdir(path string) error {
+	return unlinkat(_AT_FDCWD, path, _AT_REMOVEDIR)
+}
+
+//sys	symlinkat(oldpath string, newdirfd int, newpath string) (err error)
+
+func Symlink(oldpath string, newpath string) (err error) {
+	return symlinkat(oldpath, _AT_FDCWD, newpath)
+}
+
+func Unlink(path string) error {
+	return unlinkat(_AT_FDCWD, path, 0)
+}
+
+//sys	unlinkat(dirfd int, path string, flags int) (err error)
+
+func Unlinkat(dirfd int, path string) error {
+	return unlinkat(dirfd, path, 0)
 }
 
 //sys	utimes(path string, times *[2]Timeval) (err error)
@@ -783,17 +815,13 @@ func Mount(source string, target string, fstype string, flags uintptr, data stri
 /*
  * Direct access
  */
-//sys	Access(path string, mode uint32) (err error)
 //sys	Acct(path string) (err error)
 //sys	Adjtimex(buf *Timex) (state int, err error)
 //sys	Chdir(path string) (err error)
-//sys	Chmod(path string, mode uint32) (err error)
 //sys	Chroot(path string) (err error)
 //sys	Close(fd int) (err error)
-//sys	Creat(path string, mode uint32) (fd int, err error)
-//sysnb	Dup(oldfd int) (fd int, err error)
-//sysnb	Dup2(oldfd int, newfd 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)
@@ -811,7 +839,12 @@ func Mount(source string, target string, fstype string, flags uintptr, data stri
 //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)
@@ -819,27 +852,20 @@ func Mount(source string, target string, fstype string, flags uintptr, data stri
 //sysnb	Gettid() (tid int)
 //sys	Getxattr(path string, attr string, dest []byte) (sz int, err error)
 //sys	InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err error)
-//sysnb	InotifyInit() (fd int, err error)
 //sysnb	InotifyInit1(flags int) (fd int, err error)
 //sysnb	InotifyRmWatch(fd int, watchdesc uint32) (success int, err error)
 //sysnb	Kill(pid int, sig Signal) (err error)
 //sys	Klogctl(typ int, buf []byte) (n int, err error) = SYS_SYSLOG
-//sys	Link(oldpath string, newpath string) (err error)
 //sys	Listxattr(path string, dest []byte) (sz int, err error)
-//sys	Mkdir(path string, mode uint32) (err error)
 //sys	Mkdirat(dirfd int, path string, mode uint32) (err error)
-//sys	Mknod(path string, mode uint32, dev int) (err error)
 //sys	Mknodat(dirfd int, path string, mode uint32, dev int) (err error)
 //sys	Nanosleep(time *Timespec, leftover *Timespec) (err error)
 //sys	Pause() (err error)
 //sys	PivotRoot(newroot string, putold string) (err error) = SYS_PIVOT_ROOT
 //sysnb prlimit(pid int, resource int, old *Rlimit, newlimit *Rlimit) (err error) = SYS_PRLIMIT64
 //sys	read(fd int, p []byte) (n int, err error)
-//sys	Readlink(path string, buf []byte) (n int, err error)
 //sys	Removexattr(path string, attr string) (err error)
-//sys	Rename(oldpath string, newpath string) (err error)
 //sys	Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error)
-//sys	Rmdir(path string) (err error)
 //sys	Setdomainname(p []byte) (err error)
 //sys	Sethostname(p []byte) (err error)
 //sysnb	Setpgid(pid int, pgid int) (err error)
@@ -861,7 +887,6 @@ func Setgid(uid int) (err error) {
 
 //sys	Setpriority(which int, who int, prio int) (err error)
 //sys	Setxattr(path string, attr string, data []byte, flags int) (err error)
-//sys	Symlink(oldpath string, newpath string) (err error)
 //sys	Sync()
 //sysnb	Sysinfo(info *Sysinfo_t) (err error)
 //sys	Tee(rfd int, wfd int, len int, flags int) (n int64, err error)
@@ -869,8 +894,6 @@ func Setgid(uid int) (err error) {
 //sysnb	Times(tms *Tms) (ticks uintptr, err error)
 //sysnb	Umask(mask int) (oldmask int)
 //sysnb	Uname(buf *Utsname) (err error)
-//sys	Unlink(path string) (err error)
-//sys	Unlinkat(dirfd int, path string) (err error)
 //sys	Unmount(target string, flags int) (err error) = SYS_UMOUNT2
 //sys	Unshare(flags int) (err error)
 //sys	Ustat(dev int, ubuf *Ustat_t) (err error)
diff --git a/src/syscall/syscall_linux_386.go b/src/syscall/syscall_linux_386.go
index 8278750..9ee1c1c 100644
--- a/src/syscall/syscall_linux_386.go
+++ b/src/syscall/syscall_linux_386.go
@@ -9,6 +9,8 @@ package syscall
 
 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) }
@@ -28,9 +30,35 @@ func NsecToTimeval(nsec int64) (tv Timeval) {
 	return
 }
 
+//sysnb	pipe(p *[2]_C_int) (err error)
+
+func Pipe(p []int) (err error) {
+	if len(p) != 2 {
+		return EINVAL
+	}
+	var pp [2]_C_int
+	err = pipe(&pp)
+	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
+}
+
 // 64-bit file system and 32-bit uid calls
 // (386 default is 32-bit file system and 16-bit uid).
-//sys	Chown(path string, uid int, gid int) (err error) = SYS_CHOWN32
+//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
@@ -38,6 +66,7 @@ func NsecToTimeval(nsec int64) (tv Timeval) {
 //sysnb	Geteuid() (euid int) = SYS_GETEUID32
 //sysnb	Getgid() (gid int) = SYS_GETGID32
 //sysnb	Getuid() (uid int) = SYS_GETUID32
+//sysnb	InotifyInit() (fd int, err error)
 //sys	Ioperm(from int, num int, on int) (err error)
 //sys	Iopl(level int) (err error)
 //sys	Lchown(path string, uid int, gid int) (err error) = SYS_LCHOWN32
diff --git a/src/syscall/syscall_linux_amd64.go b/src/syscall/syscall_linux_amd64.go
index 74a89fb..6fbef21 100644
--- a/src/syscall/syscall_linux_amd64.go
+++ b/src/syscall/syscall_linux_amd64.go
@@ -4,7 +4,9 @@
 
 package syscall
 
-//sys	Chown(path string, uid int, gid 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)
@@ -14,6 +16,7 @@ package syscall
 //sysnb	Getgid() (gid int)
 //sysnb	Getrlimit(resource int, rlim *Rlimit) (err error)
 //sysnb	Getuid() (uid int)
+//sysnb	InotifyInit() (fd int, err error)
 //sys	Ioperm(from int, num int, on int) (err error)
 //sys	Iopl(level int) (err error)
 //sys	Lchown(path string, uid int, gid int) (err error)
@@ -55,8 +58,6 @@ package syscall
 //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 4096 }
-
 //go:noescape
 func gettimeofday(tv *Timeval) (err Errno)
 
@@ -68,6 +69,8 @@ func Gettimeofday(tv *Timeval) (err error) {
 	return nil
 }
 
+func Getpagesize() int { return 4096 }
+
 func Time(t *Time_t) (tt Time_t, err error) {
 	var tv Timeval
 	errno := gettimeofday(&tv)
@@ -97,6 +100,32 @@ func NsecToTimeval(nsec int64) (tv Timeval) {
 	return
 }
 
+//sysnb	pipe(p *[2]_C_int) (err error)
+
+func Pipe(p []int) (err error) {
+	if len(p) != 2 {
+		return EINVAL
+	}
+	var pp [2]_C_int
+	err = pipe(&pp)
+	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.Rip }
 
 func (r *PtraceRegs) SetPC(pc uint64) { r.Rip = pc }
diff --git a/src/syscall/syscall_linux_arm.go b/src/syscall/syscall_linux_arm.go
index b127345..218d6b8 100644
--- a/src/syscall/syscall_linux_arm.go
+++ b/src/syscall/syscall_linux_arm.go
@@ -6,6 +6,8 @@ package syscall
 
 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) }
@@ -23,6 +25,30 @@ func NsecToTimeval(nsec int64) (tv Timeval) {
 	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
+}
+
 // Underlying system call writes to newoffset via pointer.
 // Implemented in assembly to avoid allocation.
 func seek(fd int, offset int64, whence int) (newoffset int64, err Errno)
@@ -54,13 +80,14 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 
 // 64-bit file system and 32-bit uid calls
 // (16-bit uid calls are not always supported in newer kernels)
-//sys	Chown(path string, uid int, gid int) (err error) = SYS_CHOWN32
+//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
 //sysnb	Geteuid() (euid int) = SYS_GETEUID32
 //sysnb	Getgid() (gid int) = SYS_GETGID32
 //sysnb	Getuid() (uid int) = SYS_GETUID32
+//sysnb	InotifyInit() (fd int, err error)
 //sys	Lchown(path string, uid int, gid int) (err error) = SYS_LCHOWN32
 //sys	Listen(s int, n int) (err error)
 //sys	Lstat(path string, stat *Stat_t) (err error) = SYS_LSTAT64
diff --git a/src/syscall/syscall_linux_arm64.go b/src/syscall/syscall_linux_arm64.go
new file mode 100644
index 0000000..3d55181
--- /dev/null
+++ b/src/syscall/syscall_linux_arm64.go
@@ -0,0 +1,148 @@
+// 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	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 Lchown(path string, uid int, gid int) (err error) {
+	return Fchownat(_AT_FDCWD, path, uid, gid, _AT_SYMLINK_NOFOLLOW)
+}
+
+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)
+}
+
+func InotifyInit() (fd int, err error) {
+	return InotifyInit1(0)
+}
+
+// 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_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
new file mode 100644
index 0000000..10489d9
--- /dev/null
+++ b/src/syscall/syscall_linux_ppc64x.go
@@ -0,0 +1,124 @@
+// 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.
+
+// +build linux
+// +build ppc64 ppc64le
+
+package syscall
+
+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)
+//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) = SYS_UGETRLIMIT
+//sysnb	Getuid() (uid int)
+//sysnb	InotifyInit() (fd int, err error)
+//sys	Ioperm(from int, num int, on int) (err error)
+//sys	Iopl(level int) (err error)
+//sys	Lchown(path string, uid int, gid int) (err error)
+//sys	Listen(s int, n int) (err error)
+//sys	Lstat(path string, stat *Stat_t) (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	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)
+//sys	Stat(path string, stat *Stat_t) (err error)
+//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.Nip }
+
+func (r *PtraceRegs) SetPC(pc uint64) { r.Nip = 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)
+}
diff --git a/src/syscall/syscall_linux_test.go b/src/syscall/syscall_linux_test.go
new file mode 100644
index 0000000..40fce6d
--- /dev/null
+++ b/src/syscall/syscall_linux_test.go
@@ -0,0 +1,140 @@
+// 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_test
+
+import (
+	"bufio"
+	"fmt"
+	"io"
+	"io/ioutil"
+	"os"
+	"os/exec"
+	"os/signal"
+	"path/filepath"
+	"syscall"
+	"testing"
+	"time"
+)
+
+func TestMain(m *testing.M) {
+	if os.Getenv("GO_DEATHSIG_PARENT") == "1" {
+		deathSignalParent()
+	} else if os.Getenv("GO_DEATHSIG_CHILD") == "1" {
+		deathSignalChild()
+	}
+
+	os.Exit(m.Run())
+}
+
+func TestLinuxDeathSignal(t *testing.T) {
+	if os.Getuid() != 0 {
+		t.Skip("skipping root only test")
+	}
+
+	// Copy the test binary to a location that a non-root user can read/execute
+	// after we drop privileges
+	tempDir, err := ioutil.TempDir("", "TestDeathSignal")
+	if err != nil {
+		t.Fatalf("cannot create temporary directory: %v", err)
+	}
+	defer os.RemoveAll(tempDir)
+	os.Chmod(tempDir, 0755)
+
+	tmpBinary := filepath.Join(tempDir, filepath.Base(os.Args[0]))
+
+	src, err := os.Open(os.Args[0])
+	if err != nil {
+		t.Fatalf("cannot open binary %q, %v", os.Args[0], err)
+	}
+	defer src.Close()
+
+	dst, err := os.OpenFile(tmpBinary, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755)
+	if err != nil {
+		t.Fatalf("cannot create temporary binary %q, %v", tmpBinary, err)
+	}
+	if _, err := io.Copy(dst, src); err != nil {
+		t.Fatalf("failed to copy test binary to %q, %v", tmpBinary, err)
+	}
+	err = dst.Close()
+	if err != nil {
+		t.Fatalf("failed to close test binary %q, %v", tmpBinary, err)
+	}
+
+	cmd := exec.Command(tmpBinary)
+	cmd.Env = []string{"GO_DEATHSIG_PARENT=1"}
+	chldStdin, err := cmd.StdinPipe()
+	if err != nil {
+		t.Fatal("failed to create new stdin pipe: %v", err)
+	}
+	chldStdout, err := cmd.StdoutPipe()
+	if err != nil {
+		t.Fatal("failed to create new stdout pipe: %v", err)
+	}
+	cmd.Stderr = os.Stderr
+
+	err = cmd.Start()
+	defer cmd.Wait()
+	if err != nil {
+		t.Fatalf("failed to start first child process: %v", err)
+	}
+
+	chldPipe := bufio.NewReader(chldStdout)
+
+	if got, err := chldPipe.ReadString('\n'); got == "start\n" {
+		syscall.Kill(cmd.Process.Pid, syscall.SIGTERM)
+
+		go func() {
+			time.Sleep(5 * time.Second)
+			chldStdin.Close()
+		}()
+
+		want := "ok\n"
+		if got, err = chldPipe.ReadString('\n'); got != want {
+			t.Fatalf("expected %q, received %q, %v", want, got, err)
+		}
+	} else {
+		t.Fatalf("did not receive start from child, received %q, %v", got, err)
+	}
+}
+
+func deathSignalParent() {
+	cmd := exec.Command(os.Args[0])
+	cmd.Env = []string{"GO_DEATHSIG_CHILD=1"}
+	cmd.Stdin = os.Stdin
+	cmd.Stdout = os.Stdout
+	attrs := syscall.SysProcAttr{
+		Pdeathsig: syscall.SIGUSR1,
+		// UID/GID 99 is the user/group "nobody" on RHEL/Fedora and is
+		// unused on Ubuntu
+		Credential: &syscall.Credential{Uid: 99, Gid: 99},
+	}
+	cmd.SysProcAttr = &attrs
+
+	err := cmd.Start()
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "death signal parent error: %v\n")
+		os.Exit(1)
+	}
+	cmd.Wait()
+	os.Exit(0)
+}
+
+func deathSignalChild() {
+	c := make(chan os.Signal, 1)
+	signal.Notify(c, syscall.SIGUSR1)
+	go func() {
+		<-c
+		fmt.Println("ok")
+		os.Exit(0)
+	}()
+	fmt.Println("start")
+
+	buf := make([]byte, 32)
+	os.Stdin.Read(buf)
+
+	// We expected to be signaled before stdin closed
+	fmt.Println("not ok")
+	os.Exit(1)
+}
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 @@ import (
 //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 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
 //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 @@ func Getfsstat(buf []Statfs_t, flags int) (n int, err error) {
 //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_arm.go b/src/syscall/syscall_openbsd_arm.go
new file mode 100644
index 0000000..ad5ae14
--- /dev/null
+++ b/src/syscall/syscall_openbsd_arm.go
@@ -0,0 +1,42 @@
+// 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 syscall
+
+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 = int64(nsec / 1e9)
+	ts.Nsec = int32(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.Usec = int32(nsec % 1e9 / 1e3)
+	tv.Sec = int64(nsec / 1e9)
+	return
+}
+
+func SetKevent(k *Kevent_t, fd, mode, flags int) {
+	k.Ident = uint32(fd)
+	k.Filter = int16(mode)
+	k.Flags = uint16(flags)
+}
+
+func (iov *Iovec) SetLen(length int) {
+	iov.Len = uint32(length)
+}
+
+func (msghdr *Msghdr) SetControllen(length int) {
+	msghdr.Controllen = uint32(length)
+}
+
+func (cmsg *Cmsghdr) SetLen(length int) {
+	cmsg.Len = uint32(length)
+}
diff --git a/src/syscall/syscall_plan9.go b/src/syscall/syscall_plan9.go
index 618e02c..7968708 100644
--- a/src/syscall/syscall_plan9.go
+++ b/src/syscall/syscall_plan9.go
@@ -129,17 +129,6 @@ func Write(fd int, p []byte) (n int, err error) {
 
 var ioSync int64
 
-func Getwd() (wd string, err error) {
-	fd, e := Open(".", O_RDONLY)
-
-	if e != nil {
-		return "", e
-	}
-	defer Close(fd)
-
-	return Fd2path(fd)
-}
-
 //sys	fd2path(fd int, buf []byte) (err error)
 func Fd2path(fd int) (path string, err error) {
 	var buf [512]byte
@@ -151,12 +140,12 @@ func Fd2path(fd int) (path string, err error) {
 	return cstring(buf[:]), nil
 }
 
-//sys	pipe(p *[2]_C_int) (err error)
+//sys	pipe(p *[2]int32) (err error)
 func Pipe(p []int) (err error) {
 	if len(p) != 2 {
 		return NewError("bad arg in system call")
 	}
-	var pp [2]_C_int
+	var pp [2]int32
 	err = pipe(&pp)
 	p[0] = int(pp[0])
 	p[1] = int(pp[1])
@@ -242,6 +231,7 @@ func Await(w *Waitmsg) (err error) {
 }
 
 func Unmount(name, old string) (err error) {
+	Fixwd()
 	oldp, err := BytePtrFromString(old)
 	if err != nil {
 		return err
@@ -325,17 +315,52 @@ func Getgroups() (gids []int, err error) {
 	return make([]int, 0), nil
 }
 
+//sys	open(path string, mode int) (fd int, err error)
+func Open(path string, mode int) (fd int, err error) {
+	Fixwd()
+	return open(path, mode)
+}
+
+//sys	create(path string, mode int, perm uint32) (fd int, err error)
+func Create(path string, mode int, perm uint32) (fd int, err error) {
+	Fixwd()
+	return create(path, mode, perm)
+}
+
+//sys	remove(path string) (err error)
+func Remove(path string) error {
+	Fixwd()
+	return remove(path)
+}
+
+//sys	stat(path string, edir []byte) (n int, err error)
+func Stat(path string, edir []byte) (n int, err error) {
+	Fixwd()
+	return stat(path, edir)
+}
+
+//sys	bind(name string, old string, flag int) (err error)
+func Bind(name string, old string, flag int) (err error) {
+	Fixwd()
+	return bind(name, old, flag)
+}
+
+//sys	mount(fd int, afd int, old string, flag int, aname string) (err error)
+func Mount(fd int, afd int, old string, flag int, aname string) (err error) {
+	Fixwd()
+	return mount(fd, afd, old, flag, aname)
+}
+
+//sys	wstat(path string, edir []byte) (err error)
+func Wstat(path string, edir []byte) (err error) {
+	Fixwd()
+	return wstat(path, edir)
+}
+
+//sys	chdir(path string) (err error)
 //sys	Dup(oldfd int, newfd int) (fd int, err error)
-//sys	Open(path string, mode int) (fd int, err error)
-//sys	Create(path string, mode int, perm uint32) (fd int, err error)
-//sys	Remove(path string) (err error)
 //sys	Pread(fd int, p []byte, offset int64) (n int, err error)
 //sys	Pwrite(fd int, p []byte, offset int64) (n int, err error)
 //sys	Close(fd int) (err error)
-//sys	Chdir(path string) (err error)
-//sys	Bind(name string, old string, flag int) (err error)
-//sys	Mount(fd int, afd int, old string, flag int, aname string) (err error)
-//sys	Stat(path string, edir []byte) (n int, err error)
 //sys	Fstat(fd int, edir []byte) (n int, err error)
-//sys	Wstat(path string, edir []byte) (err error)
 //sys	Fwstat(fd int, edir []byte) (err error)
diff --git a/src/syscall/syscall_solaris.go b/src/syscall/syscall_solaris.go
index adc52b1..0f60e21 100644
--- a/src/syscall/syscall_solaris.go
+++ b/src/syscall/syscall_solaris.go
@@ -14,6 +14,10 @@ package syscall
 
 import "unsafe"
 
+// Implemented in asm_solaris_amd64.s.
+func rawSysvicall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
+func sysvicall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
+
 type SockaddrDatalink struct {
 	Family uint16
 	Index  uint16
@@ -283,7 +287,7 @@ func UtimesNano(path string, ts []Timespec) (err error) {
 
 // FcntlFlock performs a fcntl syscall for the F_GETLK, F_SETLK or F_SETLKW command.
 func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) error {
-	_, _, e1 := sysvicall6(procfcntl.Addr(), 3, uintptr(fd), uintptr(cmd), uintptr(unsafe.Pointer(lk)), 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_fcntl)), 3, uintptr(fd), uintptr(cmd), uintptr(unsafe.Pointer(lk)), 0, 0, 0)
 	if e1 != 0 {
 		return e1
 	}
@@ -469,6 +473,7 @@ func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error)
 //sys	Rename(from string, to string) (err error)
 //sys	Rmdir(path string) (err error)
 //sys	Seek(fd int, offset int64, whence int) (newoffset int64, err error) = lseek
+//sys	sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) = libsendfile.sendfile
 //sysnb	Setegid(egid int) (err error)
 //sysnb	Seteuid(euid int) (err error)
 //sysnb	Setgid(gid int) (err error)
@@ -505,7 +510,7 @@ func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error)
 //sys	recvmsg(s int, msg *Msghdr, flags int) (n int, err error) = libsocket.recvmsg
 
 func readlen(fd int, buf *byte, nbuf int) (n int, err error) {
-	r0, _, e1 := sysvicall6(procread.Addr(), 3, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf), 0, 0, 0)
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_read)), 3, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf), 0, 0, 0)
 	n = int(r0)
 	if e1 != 0 {
 		err = e1
@@ -514,7 +519,7 @@ func readlen(fd int, buf *byte, nbuf int) (n int, err error) {
 }
 
 func writelen(fd int, buf *byte, nbuf int) (n int, err error) {
-	r0, _, e1 := sysvicall6(procwrite.Addr(), 3, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf), 0, 0, 0)
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_write)), 3, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf), 0, 0, 0)
 	n = int(r0)
 	if e1 != 0 {
 		err = e1
diff --git a/src/syscall/syscall_solaris_amd64.go b/src/syscall/syscall_solaris_amd64.go
index 37cf06d..67b8af1 100644
--- a/src/syscall/syscall_solaris_amd64.go
+++ b/src/syscall/syscall_solaris_amd64.go
@@ -30,8 +30,3 @@ func (iov *Iovec) SetLen(length int) {
 func (cmsg *Cmsghdr) SetLen(length int) {
 	cmsg.Len = uint32(length)
 }
-
-func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
-	// TODO(aram): implement this, see issue 5847.
-	panic("unimplemented")
-}
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 @@ func (e Errno) Timeout() bool {
 	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/syscall_unix_test.go b/src/syscall/syscall_unix_test.go
index a0afb91..c7b4560 100644
--- a/src/syscall/syscall_unix_test.go
+++ b/src/syscall/syscall_unix_test.go
@@ -9,6 +9,7 @@ package syscall_test
 import (
 	"flag"
 	"fmt"
+	"internal/testenv"
 	"io/ioutil"
 	"net"
 	"os"
@@ -60,20 +61,58 @@ func _() {
 
 // TestFcntlFlock tests whether the file locking structure matches
 // the calling convention of each kernel.
+// On some Linux systems, glibc uses another set of values for the
+// commands and translates them to the correct value that the kernel
+// expects just before the actual fcntl syscall. As Go uses raw
+// syscalls directly, it must use the real value, not the glibc value.
+// Thus this test also verifies that the Flock_t structure can be
+// roundtripped with F_SETLK and F_GETLK.
 func TestFcntlFlock(t *testing.T) {
-	name := filepath.Join(os.TempDir(), "TestFcntlFlock")
-	fd, err := syscall.Open(name, syscall.O_CREAT|syscall.O_RDWR|syscall.O_CLOEXEC, 0)
-	if err != nil {
-		t.Fatalf("Open failed: %v", err)
+	if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") {
+		t.Skip("skipping; no child processes allowed on iOS")
 	}
-	defer syscall.Unlink(name)
-	defer syscall.Close(fd)
 	flock := syscall.Flock_t{
-		Type:  syscall.F_RDLCK,
-		Start: 0, Len: 0, Whence: 1,
+		Type:  syscall.F_WRLCK,
+		Start: 31415, Len: 271828, Whence: 1,
 	}
-	if err := syscall.FcntlFlock(uintptr(fd), syscall.F_GETLK, &flock); err != nil {
-		t.Fatalf("FcntlFlock failed: %v", err)
+	if os.Getenv("GO_WANT_HELPER_PROCESS") == "" {
+		// parent
+		name := filepath.Join(os.TempDir(), "TestFcntlFlock")
+		fd, err := syscall.Open(name, syscall.O_CREAT|syscall.O_RDWR|syscall.O_CLOEXEC, 0)
+		if err != nil {
+			t.Fatalf("Open failed: %v", err)
+		}
+		defer syscall.Unlink(name)
+		defer syscall.Close(fd)
+		if err := syscall.Ftruncate(fd, 1<<20); err != nil {
+			t.Fatalf("Ftruncate(1<<20) failed: %v", err)
+		}
+		if err := syscall.FcntlFlock(uintptr(fd), syscall.F_SETLK, &flock); err != nil {
+			t.Fatalf("FcntlFlock(F_SETLK) failed: %v", err)
+		}
+		cmd := exec.Command(os.Args[0], "-test.run=^TestFcntlFlock$")
+		cmd.Env = append(os.Environ(), "GO_WANT_HELPER_PROCESS=1")
+		cmd.ExtraFiles = []*os.File{os.NewFile(uintptr(fd), name)}
+		out, err := cmd.CombinedOutput()
+		if len(out) > 0 || err != nil {
+			t.Fatalf("child process: %q, %v", out, err)
+		}
+	} else {
+		// child
+		got := flock
+		// make sure the child lock is conflicting with the parent lock
+		got.Start--
+		got.Len++
+		if err := syscall.FcntlFlock(3, syscall.F_GETLK, &got); err != nil {
+			t.Fatalf("FcntlFlock(F_GETLK) failed: %v", err)
+		}
+		flock.Pid = int32(syscall.Getppid())
+		// Linux kernel always set Whence to 0
+		flock.Whence = 0
+		if got.Type == flock.Type && got.Start == flock.Start && got.Len == flock.Len && got.Pid == flock.Pid && got.Whence == flock.Whence {
+			os.Exit(0)
+		}
+		t.Fatalf("FcntlFlock got %v, want %v", got, flock)
 	}
 }
 
@@ -93,6 +132,9 @@ func TestPassFD(t *testing.T) {
 		// TODO(aram): Figure out why ReadMsgUnix is returning empty message.
 		t.Skip("skipping test on solaris, see issue 7402")
 	}
+
+	testenv.MustHaveExec(t)
+
 	if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
 		passFDChild()
 		return
@@ -116,7 +158,7 @@ func TestPassFD(t *testing.T) {
 	defer readFile.Close()
 
 	cmd := exec.Command(os.Args[0], "-test.run=^TestPassFD$", "--", tempDir)
-	cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
+	cmd.Env = append(os.Environ(), "GO_WANT_HELPER_PROCESS=1")
 	cmd.ExtraFiles = []*os.File{writeFile}
 
 	out, err := cmd.CombinedOutput()
@@ -175,7 +217,7 @@ func passFDChild() {
 	defer os.Exit(0)
 
 	// Look for our fd. It should be fd 3, but we work around an fd leak
-	// bug here (http://golang.org/issue/2603) to let it be elsewhere.
+	// bug here (https://golang.org/issue/2603) to let it be elsewhere.
 	var uc *net.UnixConn
 	for fd := uintptr(3); fd <= 10; fd++ {
 		f := os.NewFile(fd, "unix-conn")
diff --git a/src/syscall/syscall_windows.go b/src/syscall/syscall_windows.go
index e89fd09..1006a9b 100644
--- a/src/syscall/syscall_windows.go
+++ b/src/syscall/syscall_windows.go
@@ -13,13 +13,17 @@ import (
 	"unsafe"
 )
 
+//go:generate go run mksyscall_windows.go -output zsyscall_windows.go syscall_windows.go security_windows.go
+
 type Handle uintptr
 
 const InvalidHandle = ^Handle(0)
 
-// StringToUTF16 is deprecated. Use UTF16FromString instead.
-// If s contains a NUL byte this function panics instead of
-// returning an error.
+// StringToUTF16 returns the UTF-16 encoding of the UTF-8 string s,
+// with a terminating NUL added. If s contains a NUL byte this
+// function panics instead of returning an error.
+//
+// Deprecated: Use UTF16FromString instead.
 func StringToUTF16(s string) []uint16 {
 	a, err := UTF16FromString(s)
 	if err != nil {
@@ -52,9 +56,12 @@ func UTF16ToString(s []uint16) string {
 	return string(utf16.Decode(s))
 }
 
-// StringToUTF16Ptr is deprecated. Use UTF16PtrFromString instead.
+// StringToUTF16Ptr returns pointer to the UTF-16 encoding of
+// the UTF-8 string s, with a terminating NUL added. If s
 // If s contains a NUL byte this function panics instead of
 // returning an error.
+//
+// Deprecated: Use UTF16PtrFromString instead.
 func StringToUTF16Ptr(s string) *uint16 { return &StringToUTF16(s)[0] }
 
 // UTF16PtrFromString returns pointer to the UTF-16 encoding of
@@ -75,6 +82,14 @@ type Errno uintptr
 
 func langid(pri, sub uint16) uint32 { return uint32(sub)<<10 | uint32(pri) }
 
+// FormatMessage is deprecated (msgsrc should be uintptr, not uint32, but can
+// not be changed due to the Go 1 compatibility guarantee).
+//
+// Deprecated: Use FormatMessage from golang.org/x/sys/windows instead.
+func FormatMessage(flags uint32, msgsrc uint32, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, err error) {
+	return formatMessage(flags, uintptr(msgsrc), msgid, langid, buf, args)
+}
+
 func (e Errno) Error() string {
 	// deal with special go errors
 	idx := int(e - APPLICATION_ERROR)
@@ -84,9 +99,9 @@ func (e Errno) Error() string {
 	// ask windows for the remaining errors
 	var flags uint32 = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ARGUMENT_ARRAY | FORMAT_MESSAGE_IGNORE_INSERTS
 	b := make([]uint16, 300)
-	n, err := FormatMessage(flags, 0, uint32(e), langid(LANG_ENGLISH, SUBLANG_ENGLISH_US), b, nil)
+	n, err := formatMessage(flags, 0, uint32(e), langid(LANG_ENGLISH, SUBLANG_ENGLISH_US), b, nil)
 	if err != nil {
-		n, err = FormatMessage(flags, 0, uint32(e), 0, b, nil)
+		n, err = formatMessage(flags, 0, uint32(e), 0, b, nil)
 		if err != nil {
 			return "winapi error #" + itoa(int(e))
 		}
@@ -105,7 +120,7 @@ func (e Errno) Timeout() bool {
 	return e == EAGAIN || e == EWOULDBLOCK || e == ETIMEDOUT
 }
 
-// Implemented in asm_windows.s
+// Implemented in runtime/syscall_windows.go.
 func compileCallback(fn interface{}, cleanstack bool) uintptr
 
 // Converts a Go function to a function pointer conforming
@@ -129,7 +144,7 @@ func NewCallbackCDecl(fn interface{}) uintptr {
 //sys	FreeLibrary(handle Handle) (err error)
 //sys	GetProcAddress(module Handle, procname string) (proc uintptr, err error)
 //sys	GetVersion() (ver uint32, err error)
-//sys	FormatMessage(flags uint32, msgsrc uint32, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, err error) = FormatMessageW
+//sys	formatMessage(flags uint32, msgsrc uintptr, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, err error) = FormatMessageW
 //sys	ExitProcess(exitcode uint32)
 //sys	CreateFile(name *uint16, access uint32, mode uint32, sa *SecurityAttributes, createmode uint32, attrs uint32, templatefile int32) (handle Handle, err error) [failretval==InvalidHandle] = CreateFileW
 //sys	ReadFile(handle Handle, buf []byte, done *uint32, overlapped *Overlapped) (err error)
@@ -1001,13 +1016,22 @@ func Readlink(path string, buf []byte) (n int, err error) {
 	}
 
 	rdb := (*reparseDataBuffer)(unsafe.Pointer(&rdbbuf[0]))
-	if uintptr(bytesReturned) < unsafe.Sizeof(*rdb) ||
-		rdb.ReparseTag != IO_REPARSE_TAG_SYMLINK {
-		// the path is not a symlink but another type of reparse point
+	var s string
+	switch rdb.ReparseTag {
+	case IO_REPARSE_TAG_SYMLINK:
+		data := (*symbolicLinkReparseBuffer)(unsafe.Pointer(&rdb.reparseBuffer))
+		p := (*[0xffff]uint16)(unsafe.Pointer(&data.PathBuffer[0]))
+		s = UTF16ToString(p[data.PrintNameOffset/2 : (data.PrintNameLength-data.PrintNameOffset)/2])
+	case _IO_REPARSE_TAG_MOUNT_POINT:
+		data := (*mountPointReparseBuffer)(unsafe.Pointer(&rdb.reparseBuffer))
+		p := (*[0xffff]uint16)(unsafe.Pointer(&data.PathBuffer[0]))
+		s = UTF16ToString(p[data.PrintNameOffset/2 : (data.PrintNameLength-data.PrintNameOffset)/2])
+	default:
+		// the path is not a symlink or junction but another type of reparse
+		// point
 		return -1, ENOENT
 	}
-
-	s := UTF16ToString((*[0xffff]uint16)(unsafe.Pointer(&rdb.PathBuffer[0]))[:rdb.PrintNameLength/2])
 	n = copy(buf, []byte(s))
+
 	return n, nil
 }
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 @@ const (
 	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 @@ const (
 	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 @@ var errorstr = [...]string{
 	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 e8396a4..0ebdc7c 100644
--- a/src/syscall/types_linux.go
+++ b/src/syscall/types_linux.go
@@ -77,8 +77,8 @@ struct sockaddr_any {
 // copied from /usr/include/linux/un.h
 struct my_sockaddr_un {
 	sa_family_t sun_family;
-#ifdef __ARM_EABI__
-	// on ARM char is by default unsigned
+#if defined(__ARM_EABI__) || defined(__powerpc64__)
+	// on ARM and PPC char is by default unsigned
 	signed char sun_path[108];
 #else
 	char sun_path[108];
@@ -87,6 +87,10 @@ struct my_sockaddr_un {
 
 #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
 typedef struct user_regs_struct PtraceRegs;
 #endif
@@ -374,7 +378,9 @@ type Ustat_t C.struct_ustat
 type EpollEvent C.struct_my_epoll_event
 
 const (
-	_AT_FDCWD = C.AT_FDCWD
+	_AT_FDCWD            = C.AT_FDCWD
+	_AT_REMOVEDIR        = C.AT_REMOVEDIR
+	_AT_SYMLINK_NOFOLLOW = C.AT_SYMLINK_NOFOLLOW
 )
 
 // Terminal handling
@@ -382,103 +388,9 @@ const (
 type Termios C.struct_termios
 
 const (
-	VINTR    = C.VINTR
-	VQUIT    = C.VQUIT
-	VERASE   = C.VERASE
-	VKILL    = C.VKILL
-	VEOF     = C.VEOF
-	VTIME    = C.VTIME
-	VMIN     = C.VMIN
-	VSWTC    = C.VSWTC
-	VSTART   = C.VSTART
-	VSTOP    = C.VSTOP
-	VSUSP    = C.VSUSP
-	VEOL     = C.VEOL
-	VREPRINT = C.VREPRINT
-	VDISCARD = C.VDISCARD
-	VWERASE  = C.VWERASE
-	VLNEXT   = C.VLNEXT
-	VEOL2    = C.VEOL2
-	IGNBRK   = C.IGNBRK
-	BRKINT   = C.BRKINT
-	IGNPAR   = C.IGNPAR
-	PARMRK   = C.PARMRK
-	INPCK    = C.INPCK
-	ISTRIP   = C.ISTRIP
-	INLCR    = C.INLCR
-	IGNCR    = C.IGNCR
-	ICRNL    = C.ICRNL
-	IUCLC    = C.IUCLC
-	IXON     = C.IXON
-	IXANY    = C.IXANY
-	IXOFF    = C.IXOFF
-	IMAXBEL  = C.IMAXBEL
-	IUTF8    = C.IUTF8
-	OPOST    = C.OPOST
-	OLCUC    = C.OLCUC
-	ONLCR    = C.ONLCR
-	OCRNL    = C.OCRNL
-	ONOCR    = C.ONOCR
-	ONLRET   = C.ONLRET
-	OFILL    = C.OFILL
-	OFDEL    = C.OFDEL
-	B0       = C.B0
-	B50      = C.B50
-	B75      = C.B75
-	B110     = C.B110
-	B134     = C.B134
-	B150     = C.B150
-	B200     = C.B200
-	B300     = C.B300
-	B600     = C.B600
-	B1200    = C.B1200
-	B1800    = C.B1800
-	B2400    = C.B2400
-	B4800    = C.B4800
-	B9600    = C.B9600
-	B19200   = C.B19200
-	B38400   = C.B38400
-	CSIZE    = C.CSIZE
-	CS5      = C.CS5
-	CS6      = C.CS6
-	CS7      = C.CS7
-	CS8      = C.CS8
-	CSTOPB   = C.CSTOPB
-	CREAD    = C.CREAD
-	PARENB   = C.PARENB
-	PARODD   = C.PARODD
-	HUPCL    = C.HUPCL
-	CLOCAL   = C.CLOCAL
-	B57600   = C.B57600
-	B115200  = C.B115200
-	B230400  = C.B230400
-	B460800  = C.B460800
-	B500000  = C.B500000
-	B576000  = C.B576000
-	B921600  = C.B921600
-	B1000000 = C.B1000000
-	B1152000 = C.B1152000
-	B1500000 = C.B1500000
-	B2000000 = C.B2000000
-	B2500000 = C.B2500000
-	B3000000 = C.B3000000
-	B3500000 = C.B3500000
-	B4000000 = C.B4000000
-	ISIG     = C.ISIG
-	ICANON   = C.ICANON
-	XCASE    = C.XCASE
-	ECHO     = C.ECHO
-	ECHOE    = C.ECHOE
-	ECHOK    = C.ECHOK
-	ECHONL   = C.ECHONL
-	NOFLSH   = C.NOFLSH
-	TOSTOP   = C.TOSTOP
-	ECHOCTL  = C.ECHOCTL
-	ECHOPRT  = C.ECHOPRT
-	ECHOKE   = C.ECHOKE
-	FLUSHO   = C.FLUSHO
-	PENDIN   = C.PENDIN
-	IEXTEN   = C.IEXTEN
-	TCGETS   = C.TCGETS
-	TCSETS   = C.TCSETS
+	IUCLC  = C.IUCLC
+	OLCUC  = C.OLCUC
+	TCGETS = C.TCGETS
+	TCSETS = C.TCSETS
+	XCASE  = C.XCASE
 )
diff --git a/src/syscall/types_plan9.c b/src/syscall/types_plan9.c
deleted file mode 100644
index cd9e15f..0000000
--- a/src/syscall/types_plan9.c
+++ /dev/null
@@ -1,115 +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.
-
-// +build ignore
-
-/*
-Input to godefs.  See also mkerrors.sh and mkall.sh
-*/
-
-typedef unsigned short ushort;
-typedef unsigned char uchar;
-typedef unsigned long ulong;
-typedef unsigned int uint;
-typedef long long vlong;
-typedef unsigned long long uvlong;
-
-typedef int $_C_int;
-
-enum {
-	OREAD	= 0,	// open for read
-	OWRITE	= 1,	// write
-	ORDWR	= 2,	// read and write
-	OEXEC	= 3,	// execute, == read but check execute permission
-	OTRUNC	= 16,	// or'ed in (except for exec), truncate file first
-	OCEXEC	= 32,	// or'ed in, close on exec
-	ORCLOSE	= 64,		// or'ed in, remove on close
-	OEXCL	= 0x1000,	// or'ed in, exclusive use (create only)
-
-	$O_RDONLY	= OREAD,
-	$O_WRONLY	= OWRITE,
-	$O_RDWR		= ORDWR,
-	$O_TRUNC	= OTRUNC,
-	$O_CLOEXEC	= OCEXEC,
-	$O_EXCL		= OEXCL,
-
-	$STATMAX	= 65535U,
-	$ERRMAX		= 128,
-
-	$MORDER		= 0x0003,	// mask for bits defining order of mounting
-	$MREPL		= 0x0000,	// mount replaces object
-	$MBEFORE	= 0x0001,	// mount goes before others in union directory
-	$MAFTER		= 0x0002,	// mount goes after others in union directory
-	$MCREATE	= 0x0004,	// permit creation in mounted directory
-	$MCACHE		= 0x0010,	// cache some data
-	$MMASK		= 0x0017,	// all bits on
-
-	$RFNAMEG	= (1<<0),
-	$RFENVG		= (1<<1),
-	$RFFDG		= (1<<2),
-	$RFNOTEG	= (1<<3),
-	$RFPROC		= (1<<4),
-	$RFMEM		= (1<<5),
-	$RFNOWAIT	= (1<<6),
-	$RFCNAMEG	= (1<<10),
-	$RFCENVG	= (1<<11),
-	$RFCFDG		= (1<<12),
-	$RFREND		= (1<<13),
-	$RFNOMNT	= (1<<14),
-
-	// bits in Qid.type
-	$QTDIR		= 0x80,		// type bit for directories
-	$QTAPPEND	= 0x40,		// type bit for append only files
-	$QTEXCL		= 0x20,		// type bit for exclusive use files
-	$QTMOUNT	= 0x10,		// type bit for mounted channel
-	$QTAUTH		= 0x08,		// type bit for authentication file
-	$QTTMP		= 0x04,		// type bit for not-backed-up file
-	$QTFILE		= 0x00,		// plain file
-
-
-	// bits in Dir.mode
-	$DMDIR		= 0x80000000,	// mode bit for directories
-	$DMAPPEND	= 0x40000000,	// mode bit for append only files
-	$DMEXCL		= 0x20000000,	// mode bit for exclusive use files
-	$DMMOUNT	= 0x10000000,	// mode bit for mounted channel
-	$DMAUTH		= 0x08000000,	// mode bit for authentication file
-	$DMTMP		= 0x04000000,	// mode bit for non-backed-up files
-	$DMREAD		= 0x4,		// mode bit for read permission
-	$DMWRITE	= 0x2,		// mode bit for write permission
-	$DMEXEC		= 0x1,		// mode bit for execute permission
-
-	BIT8SZ	= 1,
-	BIT16SZ	= 2,
-	BIT32SZ	= 4,
-	BIT64SZ	= 8,
-	QIDSZ = BIT8SZ+BIT32SZ+BIT64SZ,
-
-	// STATFIXLEN includes leading 16-bit count
-	// The count, however, excludes itself; total size is BIT16SZ+count
-	$STATFIXLEN = BIT16SZ+QIDSZ+5*BIT16SZ+4*BIT32SZ+1*BIT64SZ,	// amount of fixed length data in a stat buffer
-};
-
-
-struct Prof			// Per process profiling
-{
-	struct Plink	*pp;	// known to be 0(ptr)
-	struct Plink	*next;	// known to be 4(ptr)
-	struct Plink	*last;
-	struct Plink	*first;
-	ulong		pid;
-	ulong		what;
-};
-
-struct Tos {
-	struct Prof	prof;
-	uvlong		cyclefreq;	// cycle clock frequency if there is one, 0 otherwise
-	vlong		kcycles;	// cycles spent in kernel
-	vlong		pcycles;	// cycles spent in process (kernel + user)
-	ulong		pid;		// might as well put the pid here
-	ulong		clock;
-	// top of stack is here
-};
-
-typedef struct Prof $Prof;
-typedef struct Tos $Tos;
diff --git a/src/syscall/zerrors_darwin_386.go b/src/syscall/zerrors_darwin_386.go
index bb3a161..debadaa 100644
--- a/src/syscall/zerrors_darwin_386.go
+++ b/src/syscall/zerrors_darwin_386.go
@@ -4,6 +4,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- -m32 _const.go
 
+// +build 386,darwin
+
 package syscall
 
 const (
diff --git a/src/syscall/zerrors_darwin_amd64.go b/src/syscall/zerrors_darwin_amd64.go
index 05ab48e..d4262ba 100644
--- a/src/syscall/zerrors_darwin_amd64.go
+++ b/src/syscall/zerrors_darwin_amd64.go
@@ -4,6 +4,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- -m64 _const.go
 
+// +build amd64,darwin
+
 package syscall
 
 const (
diff --git a/src/syscall/zerrors_darwin_arm.go b/src/syscall/zerrors_darwin_arm.go
new file mode 100644
index 0000000..a64f373
--- /dev/null
+++ b/src/syscall/zerrors_darwin_arm.go
@@ -0,0 +1,1351 @@
+// mkerrors.sh
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs -- _const.go
+
+// +build arm,darwin
+
+package syscall
+
+const (
+	AF_APPLETALK                = 0x10
+	AF_CCITT                    = 0xa
+	AF_CHAOS                    = 0x5
+	AF_CNT                      = 0x15
+	AF_COIP                     = 0x14
+	AF_DATAKIT                  = 0x9
+	AF_DECnet                   = 0xc
+	AF_DLI                      = 0xd
+	AF_E164                     = 0x1c
+	AF_ECMA                     = 0x8
+	AF_HYLINK                   = 0xf
+	AF_IMPLINK                  = 0x3
+	AF_INET                     = 0x2
+	AF_INET6                    = 0x1e
+	AF_IPX                      = 0x17
+	AF_ISDN                     = 0x1c
+	AF_ISO                      = 0x7
+	AF_LAT                      = 0xe
+	AF_LINK                     = 0x12
+	AF_LOCAL                    = 0x1
+	AF_MAX                      = 0x25
+	AF_NATM                     = 0x1f
+	AF_NDRV                     = 0x1b
+	AF_NETBIOS                  = 0x21
+	AF_NS                       = 0x6
+	AF_OSI                      = 0x7
+	AF_PPP                      = 0x22
+	AF_PUP                      = 0x4
+	AF_RESERVED_36              = 0x24
+	AF_ROUTE                    = 0x11
+	AF_SIP                      = 0x18
+	AF_SNA                      = 0xb
+	AF_SYSTEM                   = 0x20
+	AF_UNIX                     = 0x1
+	AF_UNSPEC                   = 0x0
+	B0                          = 0x0
+	B110                        = 0x6e
+	B115200                     = 0x1c200
+	B1200                       = 0x4b0
+	B134                        = 0x86
+	B14400                      = 0x3840
+	B150                        = 0x96
+	B1800                       = 0x708
+	B19200                      = 0x4b00
+	B200                        = 0xc8
+	B230400                     = 0x38400
+	B2400                       = 0x960
+	B28800                      = 0x7080
+	B300                        = 0x12c
+	B38400                      = 0x9600
+	B4800                       = 0x12c0
+	B50                         = 0x32
+	B57600                      = 0xe100
+	B600                        = 0x258
+	B7200                       = 0x1c20
+	B75                         = 0x4b
+	B76800                      = 0x12c00
+	B9600                       = 0x2580
+	BIOCFLUSH                   = 0x20004268
+	BIOCGBLEN                   = 0x40044266
+	BIOCGDLT                    = 0x4004426a
+	BIOCGDLTLIST                = 0xc00c4279
+	BIOCGETIF                   = 0x4020426b
+	BIOCGHDRCMPLT               = 0x40044274
+	BIOCGRSIG                   = 0x40044272
+	BIOCGRTIMEOUT               = 0x4008426e
+	BIOCGSEESENT                = 0x40044276
+	BIOCGSTATS                  = 0x4008426f
+	BIOCIMMEDIATE               = 0x80044270
+	BIOCPROMISC                 = 0x20004269
+	BIOCSBLEN                   = 0xc0044266
+	BIOCSDLT                    = 0x80044278
+	BIOCSETF                    = 0x80084267
+	BIOCSETIF                   = 0x8020426c
+	BIOCSHDRCMPLT               = 0x80044275
+	BIOCSRSIG                   = 0x80044273
+	BIOCSRTIMEOUT               = 0x8008426d
+	BIOCSSEESENT                = 0x80044277
+	BIOCVERSION                 = 0x40044271
+	BPF_A                       = 0x10
+	BPF_ABS                     = 0x20
+	BPF_ADD                     = 0x0
+	BPF_ALIGNMENT               = 0x4
+	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_MAXBUFSIZE              = 0x80000
+	BPF_MAXINSNS                = 0x200
+	BPF_MEM                     = 0x60
+	BPF_MEMWORDS                = 0x10
+	BPF_MINBUFSIZE              = 0x20
+	BPF_MINOR_VERSION           = 0x1
+	BPF_MISC                    = 0x7
+	BPF_MSH                     = 0xa0
+	BPF_MUL                     = 0x20
+	BPF_NEG                     = 0x80
+	BPF_OR                      = 0x40
+	BPF_RELEASE                 = 0x30bb6
+	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
+	BRKINT                      = 0x2
+	CFLUSH                      = 0xf
+	CLOCAL                      = 0x8000
+	CREAD                       = 0x800
+	CS5                         = 0x0
+	CS6                         = 0x100
+	CS7                         = 0x200
+	CS8                         = 0x300
+	CSIZE                       = 0x300
+	CSTART                      = 0x11
+	CSTATUS                     = 0x14
+	CSTOP                       = 0x13
+	CSTOPB                      = 0x400
+	CSUSP                       = 0x1a
+	CTL_MAXNAME                 = 0xc
+	CTL_NET                     = 0x4
+	DLT_APPLE_IP_OVER_IEEE1394  = 0x8a
+	DLT_ARCNET                  = 0x7
+	DLT_ATM_CLIP                = 0x13
+	DLT_ATM_RFC1483             = 0xb
+	DLT_AX25                    = 0x3
+	DLT_CHAOS                   = 0x5
+	DLT_CHDLC                   = 0x68
+	DLT_C_HDLC                  = 0x68
+	DLT_EN10MB                  = 0x1
+	DLT_EN3MB                   = 0x2
+	DLT_FDDI                    = 0xa
+	DLT_IEEE802                 = 0x6
+	DLT_IEEE802_11              = 0x69
+	DLT_IEEE802_11_RADIO        = 0x7f
+	DLT_IEEE802_11_RADIO_AVS    = 0xa3
+	DLT_LINUX_SLL               = 0x71
+	DLT_LOOP                    = 0x6c
+	DLT_NULL                    = 0x0
+	DLT_PFLOG                   = 0x75
+	DLT_PFSYNC                  = 0x12
+	DLT_PPP                     = 0x9
+	DLT_PPP_BSDOS               = 0x10
+	DLT_PPP_SERIAL              = 0x32
+	DLT_PRONET                  = 0x4
+	DLT_RAW                     = 0xc
+	DLT_SLIP                    = 0x8
+	DLT_SLIP_BSDOS              = 0xf
+	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                     = 0x40
+	ECHOE                       = 0x2
+	ECHOK                       = 0x4
+	ECHOKE                      = 0x1
+	ECHONL                      = 0x10
+	ECHOPRT                     = 0x20
+	EVFILT_AIO                  = -0x3
+	EVFILT_FS                   = -0x9
+	EVFILT_MACHPORT             = -0x8
+	EVFILT_PROC                 = -0x5
+	EVFILT_READ                 = -0x1
+	EVFILT_SIGNAL               = -0x6
+	EVFILT_SYSCOUNT             = 0x9
+	EVFILT_THREADMARKER         = 0x9
+	EVFILT_TIMER                = -0x7
+	EVFILT_VNODE                = -0x4
+	EVFILT_WRITE                = -0x2
+	EV_ADD                      = 0x1
+	EV_CLEAR                    = 0x20
+	EV_DELETE                   = 0x2
+	EV_DISABLE                  = 0x8
+	EV_ENABLE                   = 0x4
+	EV_EOF                      = 0x8000
+	EV_ERROR                    = 0x4000
+	EV_FLAG0                    = 0x1000
+	EV_FLAG1                    = 0x2000
+	EV_ONESHOT                  = 0x10
+	EV_OOBAND                   = 0x2000
+	EV_POLL                     = 0x1000
+	EV_RECEIPT                  = 0x40
+	EV_SYSFLAGS                 = 0xf000
+	EXTA                        = 0x4b00
+	EXTB                        = 0x9600
+	EXTPROC                     = 0x800
+	FD_CLOEXEC                  = 0x1
+	FD_SETSIZE                  = 0x400
+	FLUSHO                      = 0x800000
+	F_ADDSIGS                   = 0x3b
+	F_ALLOCATEALL               = 0x4
+	F_ALLOCATECONTIG            = 0x2
+	F_CHKCLEAN                  = 0x29
+	F_DUPFD                     = 0x0
+	F_DUPFD_CLOEXEC             = 0x43
+	F_FREEZE_FS                 = 0x35
+	F_FULLFSYNC                 = 0x33
+	F_GETFD                     = 0x1
+	F_GETFL                     = 0x3
+	F_GETLK                     = 0x7
+	F_GETOWN                    = 0x5
+	F_GETPATH                   = 0x32
+	F_GLOBAL_NOCACHE            = 0x37
+	F_LOG2PHYS                  = 0x31
+	F_MARKDEPENDENCY            = 0x3c
+	F_NOCACHE                   = 0x30
+	F_OK                        = 0x0
+	F_PATHPKG_CHECK             = 0x34
+	F_PEOFPOSMODE               = 0x3
+	F_PREALLOCATE               = 0x2a
+	F_RDADVISE                  = 0x2c
+	F_RDAHEAD                   = 0x2d
+	F_RDLCK                     = 0x1
+	F_READBOOTSTRAP             = 0x2e
+	F_SETFD                     = 0x2
+	F_SETFL                     = 0x4
+	F_SETLK                     = 0x8
+	F_SETLKW                    = 0x9
+	F_SETOWN                    = 0x6
+	F_SETSIZE                   = 0x2b
+	F_THAW_FS                   = 0x36
+	F_UNLCK                     = 0x2
+	F_VOLPOSMODE                = 0x4
+	F_WRITEBOOTSTRAP            = 0x2f
+	F_WRLCK                     = 0x3
+	HUPCL                       = 0x4000
+	ICANON                      = 0x100
+	ICRNL                       = 0x100
+	IEXTEN                      = 0x400
+	IFF_ALLMULTI                = 0x200
+	IFF_ALTPHYS                 = 0x4000
+	IFF_BROADCAST               = 0x2
+	IFF_DEBUG                   = 0x4
+	IFF_LINK0                   = 0x1000
+	IFF_LINK1                   = 0x2000
+	IFF_LINK2                   = 0x4000
+	IFF_LOOPBACK                = 0x8
+	IFF_MULTICAST               = 0x8000
+	IFF_NOARP                   = 0x80
+	IFF_NOTRAILERS              = 0x20
+	IFF_OACTIVE                 = 0x400
+	IFF_POINTOPOINT             = 0x10
+	IFF_PROMISC                 = 0x100
+	IFF_RUNNING                 = 0x40
+	IFF_SIMPLEX                 = 0x800
+	IFF_UP                      = 0x1
+	IFNAMSIZ                    = 0x10
+	IFT_1822                    = 0x2
+	IFT_AAL5                    = 0x31
+	IFT_ARCNET                  = 0x23
+	IFT_ARCNETPLUS              = 0x24
+	IFT_ATM                     = 0x25
+	IFT_BRIDGE                  = 0xd1
+	IFT_CARP                    = 0xf8
+	IFT_CEPT                    = 0x13
+	IFT_DS3                     = 0x1e
+	IFT_ENC                     = 0xf4
+	IFT_EON                     = 0x19
+	IFT_ETHER                   = 0x6
+	IFT_FAITH                   = 0x38
+	IFT_FDDI                    = 0xf
+	IFT_FRELAY                  = 0x20
+	IFT_FRELAYDCE               = 0x2c
+	IFT_GIF                     = 0x37
+	IFT_HDH1822                 = 0x3
+	IFT_HIPPI                   = 0x2f
+	IFT_HSSI                    = 0x2e
+	IFT_HY                      = 0xe
+	IFT_IEEE1394                = 0x90
+	IFT_IEEE8023ADLAG           = 0x88
+	IFT_ISDNBASIC               = 0x14
+	IFT_ISDNPRIMARY             = 0x15
+	IFT_ISO88022LLC             = 0x29
+	IFT_ISO88023                = 0x7
+	IFT_ISO88024                = 0x8
+	IFT_ISO88025                = 0x9
+	IFT_ISO88026                = 0xa
+	IFT_L2VLAN                  = 0x87
+	IFT_LAPB                    = 0x10
+	IFT_LOCALTALK               = 0x2a
+	IFT_LOOP                    = 0x18
+	IFT_MIOX25                  = 0x26
+	IFT_MODEM                   = 0x30
+	IFT_NSIP                    = 0x1b
+	IFT_OTHER                   = 0x1
+	IFT_P10                     = 0xc
+	IFT_P80                     = 0xd
+	IFT_PARA                    = 0x22
+	IFT_PDP                     = 0xff
+	IFT_PFLOG                   = 0xf5
+	IFT_PFSYNC                  = 0xf6
+	IFT_PPP                     = 0x17
+	IFT_PROPMUX                 = 0x36
+	IFT_PROPVIRTUAL             = 0x35
+	IFT_PTPSERIAL               = 0x16
+	IFT_RS232                   = 0x21
+	IFT_SDLC                    = 0x11
+	IFT_SIP                     = 0x1f
+	IFT_SLIP                    = 0x1c
+	IFT_SMDSDXI                 = 0x2b
+	IFT_SMDSICIP                = 0x34
+	IFT_SONET                   = 0x27
+	IFT_SONETPATH               = 0x32
+	IFT_SONETVT                 = 0x33
+	IFT_STARLAN                 = 0xb
+	IFT_STF                     = 0x39
+	IFT_T1                      = 0x12
+	IFT_ULTRA                   = 0x1d
+	IFT_V35                     = 0x2d
+	IFT_X25                     = 0x5
+	IFT_X25DDN                  = 0x4
+	IFT_X25PLE                  = 0x28
+	IFT_XETHER                  = 0x1a
+	IGNBRK                      = 0x1
+	IGNCR                       = 0x80
+	IGNPAR                      = 0x4
+	IMAXBEL                     = 0x2000
+	INLCR                       = 0x40
+	INPCK                       = 0x10
+	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_CLASSD_HOST              = 0xfffffff
+	IN_CLASSD_NET               = 0xf0000000
+	IN_CLASSD_NSHIFT            = 0x1c
+	IN_LINKLOCALNETNUM          = 0xa9fe0000
+	IN_LOOPBACKNET              = 0x7f
+	IPPROTO_3PC                 = 0x22
+	IPPROTO_ADFS                = 0x44
+	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_CFTP                = 0x3e
+	IPPROTO_CHAOS               = 0x10
+	IPPROTO_CMTP                = 0x26
+	IPPROTO_CPHB                = 0x49
+	IPPROTO_CPNX                = 0x48
+	IPPROTO_DDP                 = 0x25
+	IPPROTO_DGP                 = 0x56
+	IPPROTO_DIVERT              = 0xfe
+	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_MTP                 = 0x5c
+	IPPROTO_MUX                 = 0x12
+	IPPROTO_ND                  = 0x4d
+	IPPROTO_NHRP                = 0x36
+	IPPROTO_NONE                = 0x3b
+	IPPROTO_NSP                 = 0x1f
+	IPPROTO_NVPII               = 0xb
+	IPPROTO_OSPFIGP             = 0x59
+	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_SDRP                = 0x2a
+	IPPROTO_SEP                 = 0x21
+	IPPROTO_SRPC                = 0x5a
+	IPPROTO_ST                  = 0x7
+	IPPROTO_SVMTP               = 0x52
+	IPPROTO_SWIPE               = 0x35
+	IPPROTO_TCF                 = 0x57
+	IPPROTO_TCP                 = 0x6
+	IPPROTO_TP                  = 0x1d
+	IPPROTO_TPXX                = 0x27
+	IPPROTO_TRUNK1              = 0x17
+	IPPROTO_TRUNK2              = 0x18
+	IPPROTO_TTP                 = 0x54
+	IPPROTO_UDP                 = 0x11
+	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_BINDV6ONLY             = 0x1b
+	IPV6_CHECKSUM               = 0x1a
+	IPV6_DEFAULT_MULTICAST_HOPS = 0x1
+	IPV6_DEFAULT_MULTICAST_LOOP = 0x1
+	IPV6_DEFHLIM                = 0x40
+	IPV6_DSTOPTS                = 0x17
+	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               = 0x14
+	IPV6_HOPOPTS                = 0x16
+	IPV6_IPSEC_POLICY           = 0x1c
+	IPV6_JOIN_GROUP             = 0xc
+	IPV6_LEAVE_GROUP            = 0xd
+	IPV6_MAXHLIM                = 0xff
+	IPV6_MAXPACKET              = 0xffff
+	IPV6_MMTU                   = 0x500
+	IPV6_MULTICAST_HOPS         = 0xa
+	IPV6_MULTICAST_IF           = 0x9
+	IPV6_MULTICAST_LOOP         = 0xb
+	IPV6_NEXTHOP                = 0x15
+	IPV6_PKTINFO                = 0x13
+	IPV6_PKTOPTIONS             = 0x19
+	IPV6_PORTRANGE              = 0xe
+	IPV6_PORTRANGE_DEFAULT      = 0x0
+	IPV6_PORTRANGE_HIGH         = 0x1
+	IPV6_PORTRANGE_LOW          = 0x2
+	IPV6_RTHDR                  = 0x18
+	IPV6_RTHDR_LOOSE            = 0x0
+	IPV6_RTHDR_STRICT           = 0x1
+	IPV6_RTHDR_TYPE_0           = 0x0
+	IPV6_SOCKOPT_RESERVED1      = 0x3
+	IPV6_UNICAST_HOPS           = 0x4
+	IPV6_V6ONLY                 = 0x1b
+	IPV6_VERSION                = 0x60
+	IPV6_VERSION_MASK           = 0xf0
+	IP_ADD_MEMBERSHIP           = 0xc
+	IP_DEFAULT_MULTICAST_LOOP   = 0x1
+	IP_DEFAULT_MULTICAST_TTL    = 0x1
+	IP_DF                       = 0x4000
+	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                   = 0x28
+	IP_FW_DEL                   = 0x29
+	IP_FW_FLUSH                 = 0x2a
+	IP_FW_GET                   = 0x2c
+	IP_FW_RESETLOG              = 0x2d
+	IP_FW_ZERO                  = 0x2b
+	IP_HDRINCL                  = 0x2
+	IP_IPSEC_POLICY             = 0x15
+	IP_MAXPACKET                = 0xffff
+	IP_MAX_MEMBERSHIPS          = 0x14
+	IP_MF                       = 0x2000
+	IP_MSS                      = 0x240
+	IP_MULTICAST_IF             = 0x9
+	IP_MULTICAST_LOOP           = 0xb
+	IP_MULTICAST_TTL            = 0xa
+	IP_MULTICAST_VIF            = 0xe
+	IP_NAT__XXX                 = 0x37
+	IP_OFFMASK                  = 0x1fff
+	IP_OLD_FW_ADD               = 0x32
+	IP_OLD_FW_DEL               = 0x33
+	IP_OLD_FW_FLUSH             = 0x34
+	IP_OLD_FW_GET               = 0x36
+	IP_OLD_FW_RESETLOG          = 0x38
+	IP_OLD_FW_ZERO              = 0x35
+	IP_OPTIONS                  = 0x1
+	IP_PKTINFO                  = 0x1a
+	IP_PORTRANGE                = 0x13
+	IP_PORTRANGE_DEFAULT        = 0x0
+	IP_PORTRANGE_HIGH           = 0x1
+	IP_PORTRANGE_LOW            = 0x2
+	IP_RECVDSTADDR              = 0x7
+	IP_RECVIF                   = 0x14
+	IP_RECVOPTS                 = 0x5
+	IP_RECVPKTINFO              = 0x1a
+	IP_RECVRETOPTS              = 0x6
+	IP_RECVTTL                  = 0x18
+	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_STRIPHDR                 = 0x17
+	IP_TOS                      = 0x3
+	IP_TRAFFIC_MGT_BACKGROUND   = 0x41
+	IP_TTL                      = 0x4
+	ISIG                        = 0x80
+	ISTRIP                      = 0x20
+	IUTF8                       = 0x4000
+	IXANY                       = 0x800
+	IXOFF                       = 0x400
+	IXON                        = 0x200
+	LOCK_EX                     = 0x2
+	LOCK_NB                     = 0x4
+	LOCK_SH                     = 0x1
+	LOCK_UN                     = 0x8
+	MADV_DONTNEED               = 0x4
+	MADV_FREE                   = 0x5
+	MADV_NORMAL                 = 0x0
+	MADV_RANDOM                 = 0x1
+	MADV_SEQUENTIAL             = 0x2
+	MADV_WILLNEED               = 0x3
+	MAP_ANON                    = 0x1000
+	MAP_COPY                    = 0x2
+	MAP_FILE                    = 0x0
+	MAP_FIXED                   = 0x10
+	MAP_HASSEMAPHORE            = 0x200
+	MAP_NOCACHE                 = 0x400
+	MAP_NOEXTEND                = 0x100
+	MAP_NORESERVE               = 0x40
+	MAP_PRIVATE                 = 0x2
+	MAP_RENAME                  = 0x20
+	MAP_RESERVED0080            = 0x80
+	MAP_SHARED                  = 0x1
+	MCL_CURRENT                 = 0x1
+	MCL_FUTURE                  = 0x2
+	MSG_CTRUNC                  = 0x20
+	MSG_DONTROUTE               = 0x4
+	MSG_DONTWAIT                = 0x80
+	MSG_EOF                     = 0x100
+	MSG_EOR                     = 0x8
+	MSG_FLUSH                   = 0x400
+	MSG_HAVEMORE                = 0x2000
+	MSG_HOLD                    = 0x800
+	MSG_NEEDSA                  = 0x10000
+	MSG_OOB                     = 0x1
+	MSG_PEEK                    = 0x2
+	MSG_RCVMORE                 = 0x4000
+	MSG_SEND                    = 0x1000
+	MSG_TRUNC                   = 0x10
+	MSG_WAITALL                 = 0x40
+	MSG_WAITSTREAM              = 0x200
+	MS_ASYNC                    = 0x1
+	MS_DEACTIVATE               = 0x8
+	MS_INVALIDATE               = 0x2
+	MS_KILLPAGES                = 0x4
+	MS_SYNC                     = 0x10
+	NAME_MAX                    = 0xff
+	NET_RT_DUMP                 = 0x1
+	NET_RT_DUMP2                = 0x7
+	NET_RT_FLAGS                = 0x2
+	NET_RT_IFLIST               = 0x3
+	NET_RT_IFLIST2              = 0x6
+	NET_RT_MAXID                = 0x8
+	NET_RT_STAT                 = 0x4
+	NET_RT_TRASH                = 0x5
+	NOFLSH                      = 0x80000000
+	NOTE_ABSOLUTE               = 0x8
+	NOTE_ATTRIB                 = 0x8
+	NOTE_CHILD                  = 0x4
+	NOTE_DELETE                 = 0x1
+	NOTE_EXEC                   = 0x20000000
+	NOTE_EXIT                   = 0x80000000
+	NOTE_EXTEND                 = 0x4
+	NOTE_FORK                   = 0x40000000
+	NOTE_LINK                   = 0x10
+	NOTE_LOWAT                  = 0x1
+	NOTE_NSECONDS               = 0x4
+	NOTE_PCTRLMASK              = -0x100000
+	NOTE_PDATAMASK              = 0xfffff
+	NOTE_REAP                   = 0x10000000
+	NOTE_RENAME                 = 0x20
+	NOTE_REVOKE                 = 0x40
+	NOTE_SECONDS                = 0x1
+	NOTE_SIGNAL                 = 0x8000000
+	NOTE_TRACK                  = 0x1
+	NOTE_TRACKERR               = 0x2
+	NOTE_USECONDS               = 0x2
+	NOTE_WRITE                  = 0x2
+	OCRNL                       = 0x10
+	OFDEL                       = 0x20000
+	OFILL                       = 0x80
+	ONLCR                       = 0x2
+	ONLRET                      = 0x40
+	ONOCR                       = 0x20
+	ONOEOT                      = 0x8
+	OPOST                       = 0x1
+	O_ACCMODE                   = 0x3
+	O_ALERT                     = 0x20000000
+	O_APPEND                    = 0x8
+	O_ASYNC                     = 0x40
+	O_CLOEXEC                   = 0x1000000
+	O_CREAT                     = 0x200
+	O_DIRECTORY                 = 0x100000
+	O_EVTONLY                   = 0x8000
+	O_EXCL                      = 0x800
+	O_EXLOCK                    = 0x20
+	O_FSYNC                     = 0x80
+	O_NDELAY                    = 0x4
+	O_NOCTTY                    = 0x20000
+	O_NOFOLLOW                  = 0x100
+	O_NONBLOCK                  = 0x4
+	O_POPUP                     = 0x80000000
+	O_RDONLY                    = 0x0
+	O_RDWR                      = 0x2
+	O_SHLOCK                    = 0x10
+	O_SYMLINK                   = 0x200000
+	O_SYNC                      = 0x80
+	O_TRUNC                     = 0x400
+	O_WRONLY                    = 0x1
+	PARENB                      = 0x1000
+	PARMRK                      = 0x8
+	PARODD                      = 0x2000
+	PENDIN                      = 0x20000000
+	PRIO_PGRP                   = 0x1
+	PRIO_PROCESS                = 0x0
+	PRIO_USER                   = 0x2
+	PROT_EXEC                   = 0x4
+	PROT_NONE                   = 0x0
+	PROT_READ                   = 0x1
+	PROT_WRITE                  = 0x2
+	PT_ATTACH                   = 0xa
+	PT_ATTACHEXC                = 0xe
+	PT_CONTINUE                 = 0x7
+	PT_DENY_ATTACH              = 0x1f
+	PT_DETACH                   = 0xb
+	PT_FIRSTMACH                = 0x20
+	PT_FORCEQUOTA               = 0x1e
+	PT_KILL                     = 0x8
+	PT_READ_D                   = 0x2
+	PT_READ_I                   = 0x1
+	PT_READ_U                   = 0x3
+	PT_SIGEXC                   = 0xc
+	PT_STEP                     = 0x9
+	PT_THUPDATE                 = 0xd
+	PT_TRACE_ME                 = 0x0
+	PT_WRITE_D                  = 0x5
+	PT_WRITE_I                  = 0x4
+	PT_WRITE_U                  = 0x6
+	RLIMIT_AS                   = 0x5
+	RLIMIT_CORE                 = 0x4
+	RLIMIT_CPU                  = 0x0
+	RLIMIT_DATA                 = 0x2
+	RLIMIT_FSIZE                = 0x1
+	RLIMIT_NOFILE               = 0x8
+	RLIMIT_STACK                = 0x3
+	RLIM_INFINITY               = 0x7fffffffffffffff
+	RTAX_AUTHOR                 = 0x6
+	RTAX_BRD                    = 0x7
+	RTAX_DST                    = 0x0
+	RTAX_GATEWAY                = 0x1
+	RTAX_GENMASK                = 0x3
+	RTAX_IFA                    = 0x5
+	RTAX_IFP                    = 0x4
+	RTAX_MAX                    = 0x8
+	RTAX_NETMASK                = 0x2
+	RTA_AUTHOR                  = 0x40
+	RTA_BRD                     = 0x80
+	RTA_DST                     = 0x1
+	RTA_GATEWAY                 = 0x2
+	RTA_GENMASK                 = 0x8
+	RTA_IFA                     = 0x20
+	RTA_IFP                     = 0x10
+	RTA_NETMASK                 = 0x4
+	RTF_BLACKHOLE               = 0x1000
+	RTF_BROADCAST               = 0x400000
+	RTF_CLONING                 = 0x100
+	RTF_CONDEMNED               = 0x2000000
+	RTF_DELCLONE                = 0x80
+	RTF_DONE                    = 0x40
+	RTF_DYNAMIC                 = 0x10
+	RTF_GATEWAY                 = 0x2
+	RTF_HOST                    = 0x4
+	RTF_IFREF                   = 0x4000000
+	RTF_IFSCOPE                 = 0x1000000
+	RTF_LLINFO                  = 0x400
+	RTF_LOCAL                   = 0x200000
+	RTF_MODIFIED                = 0x20
+	RTF_MULTICAST               = 0x800000
+	RTF_PINNED                  = 0x100000
+	RTF_PRCLONING               = 0x10000
+	RTF_PROTO1                  = 0x8000
+	RTF_PROTO2                  = 0x4000
+	RTF_PROTO3                  = 0x40000
+	RTF_REJECT                  = 0x8
+	RTF_STATIC                  = 0x800
+	RTF_UP                      = 0x1
+	RTF_WASCLONED               = 0x20000
+	RTF_XRESOLVE                = 0x200
+	RTM_ADD                     = 0x1
+	RTM_CHANGE                  = 0x3
+	RTM_DELADDR                 = 0xd
+	RTM_DELETE                  = 0x2
+	RTM_DELMADDR                = 0x10
+	RTM_GET                     = 0x4
+	RTM_GET2                    = 0x14
+	RTM_IFINFO                  = 0xe
+	RTM_IFINFO2                 = 0x12
+	RTM_LOCK                    = 0x8
+	RTM_LOSING                  = 0x5
+	RTM_MISS                    = 0x7
+	RTM_NEWADDR                 = 0xc
+	RTM_NEWMADDR                = 0xf
+	RTM_NEWMADDR2               = 0x13
+	RTM_OLDADD                  = 0x9
+	RTM_OLDDEL                  = 0xa
+	RTM_REDIRECT                = 0x6
+	RTM_RESOLVE                 = 0xb
+	RTM_RTTUNIT                 = 0xf4240
+	RTM_VERSION                 = 0x5
+	RTV_EXPIRE                  = 0x4
+	RTV_HOPCOUNT                = 0x2
+	RTV_MTU                     = 0x1
+	RTV_RPIPE                   = 0x8
+	RTV_RTT                     = 0x40
+	RTV_RTTVAR                  = 0x80
+	RTV_SPIPE                   = 0x10
+	RTV_SSTHRESH                = 0x20
+	RUSAGE_CHILDREN             = -0x1
+	RUSAGE_SELF                 = 0x0
+	SCM_CREDS                   = 0x3
+	SCM_RIGHTS                  = 0x1
+	SCM_TIMESTAMP               = 0x2
+	SHUT_RD                     = 0x0
+	SHUT_RDWR                   = 0x2
+	SHUT_WR                     = 0x1
+	SIOCADDMULTI                = 0x80206931
+	SIOCAIFADDR                 = 0x8040691a
+	SIOCALIFADDR                = 0x8118691d
+	SIOCARPIPLL                 = 0xc0206928
+	SIOCATMARK                  = 0x40047307
+	SIOCAUTOADDR                = 0xc0206926
+	SIOCAUTONETMASK             = 0x80206927
+	SIOCDELMULTI                = 0x80206932
+	SIOCDIFADDR                 = 0x80206919
+	SIOCDIFPHYADDR              = 0x80206941
+	SIOCDLIFADDR                = 0x8118691f
+	SIOCGETSGCNT                = 0xc014721c
+	SIOCGETVIFCNT               = 0xc014721b
+	SIOCGETVLAN                 = 0xc020697f
+	SIOCGHIWAT                  = 0x40047301
+	SIOCGIFADDR                 = 0xc0206921
+	SIOCGIFALTMTU               = 0xc0206948
+	SIOCGIFASYNCMAP             = 0xc020697c
+	SIOCGIFBOND                 = 0xc0206947
+	SIOCGIFBRDADDR              = 0xc0206923
+	SIOCGIFCONF                 = 0xc0086924
+	SIOCGIFDEVMTU               = 0xc0206944
+	SIOCGIFDSTADDR              = 0xc0206922
+	SIOCGIFFLAGS                = 0xc0206911
+	SIOCGIFGENERIC              = 0xc020693a
+	SIOCGIFKPI                  = 0xc0206987
+	SIOCGIFMAC                  = 0xc0206982
+	SIOCGIFMEDIA                = 0xc0286938
+	SIOCGIFMETRIC               = 0xc0206917
+	SIOCGIFMTU                  = 0xc0206933
+	SIOCGIFNETMASK              = 0xc0206925
+	SIOCGIFPDSTADDR             = 0xc0206940
+	SIOCGIFPHYS                 = 0xc0206935
+	SIOCGIFPSRCADDR             = 0xc020693f
+	SIOCGIFSTATUS               = 0xc331693d
+	SIOCGIFVLAN                 = 0xc020697f
+	SIOCGLIFADDR                = 0xc118691e
+	SIOCGLIFPHYADDR             = 0xc1186943
+	SIOCGLOWAT                  = 0x40047303
+	SIOCGPGRP                   = 0x40047309
+	SIOCIFCREATE                = 0xc0206978
+	SIOCIFDESTROY               = 0x80206979
+	SIOCRSLVMULTI               = 0xc008693b
+	SIOCSETVLAN                 = 0x8020697e
+	SIOCSHIWAT                  = 0x80047300
+	SIOCSIFADDR                 = 0x8020690c
+	SIOCSIFALTMTU               = 0x80206945
+	SIOCSIFASYNCMAP             = 0x8020697d
+	SIOCSIFBOND                 = 0x80206946
+	SIOCSIFBRDADDR              = 0x80206913
+	SIOCSIFDSTADDR              = 0x8020690e
+	SIOCSIFFLAGS                = 0x80206910
+	SIOCSIFGENERIC              = 0x80206939
+	SIOCSIFKPI                  = 0x80206986
+	SIOCSIFLLADDR               = 0x8020693c
+	SIOCSIFMAC                  = 0x80206983
+	SIOCSIFMEDIA                = 0xc0206937
+	SIOCSIFMETRIC               = 0x80206918
+	SIOCSIFMTU                  = 0x80206934
+	SIOCSIFNETMASK              = 0x80206916
+	SIOCSIFPHYADDR              = 0x8040693e
+	SIOCSIFPHYS                 = 0x80206936
+	SIOCSIFVLAN                 = 0x8020697e
+	SIOCSLIFPHYADDR             = 0x81186942
+	SIOCSLOWAT                  = 0x80047302
+	SIOCSPGRP                   = 0x80047308
+	SOCK_DGRAM                  = 0x2
+	SOCK_MAXADDRLEN             = 0xff
+	SOCK_RAW                    = 0x3
+	SOCK_RDM                    = 0x4
+	SOCK_SEQPACKET              = 0x5
+	SOCK_STREAM                 = 0x1
+	SOL_SOCKET                  = 0xffff
+	SOMAXCONN                   = 0x80
+	SO_ACCEPTCONN               = 0x2
+	SO_BROADCAST                = 0x20
+	SO_DEBUG                    = 0x1
+	SO_DONTROUTE                = 0x10
+	SO_DONTTRUNC                = 0x2000
+	SO_ERROR                    = 0x1007
+	SO_KEEPALIVE                = 0x8
+	SO_LABEL                    = 0x1010
+	SO_LINGER                   = 0x80
+	SO_LINGER_SEC               = 0x1080
+	SO_NKE                      = 0x1021
+	SO_NOADDRERR                = 0x1023
+	SO_NOSIGPIPE                = 0x1022
+	SO_NOTIFYCONFLICT           = 0x1026
+	SO_NREAD                    = 0x1020
+	SO_NWRITE                   = 0x1024
+	SO_OOBINLINE                = 0x100
+	SO_PEERLABEL                = 0x1011
+	SO_RCVBUF                   = 0x1002
+	SO_RCVLOWAT                 = 0x1004
+	SO_RCVTIMEO                 = 0x1006
+	SO_RESTRICTIONS             = 0x1081
+	SO_RESTRICT_DENYIN          = 0x1
+	SO_RESTRICT_DENYOUT         = 0x2
+	SO_RESTRICT_DENYSET         = 0x80000000
+	SO_REUSEADDR                = 0x4
+	SO_REUSEPORT                = 0x200
+	SO_REUSESHAREUID            = 0x1025
+	SO_SNDBUF                   = 0x1001
+	SO_SNDLOWAT                 = 0x1003
+	SO_SNDTIMEO                 = 0x1005
+	SO_TIMESTAMP                = 0x400
+	SO_TYPE                     = 0x1008
+	SO_UPCALLCLOSEWAIT          = 0x1027
+	SO_USELOOPBACK              = 0x40
+	SO_WANTMORE                 = 0x4000
+	SO_WANTOOBFLAG              = 0x8000
+	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_IFWHT                     = 0xe000
+	S_IFXATTR                   = 0x10000
+	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_ISTXT                     = 0x200
+	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
+	TCIFLUSH                    = 0x1
+	TCIOFLUSH                   = 0x3
+	TCOFLUSH                    = 0x2
+	TCP_KEEPALIVE               = 0x10
+	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                  = 0xd8
+	TCP_MINMSSOVERLOAD          = 0x3e8
+	TCP_MSS                     = 0x200
+	TCP_NODELAY                 = 0x1
+	TCP_NOOPT                   = 0x8
+	TCP_NOPUSH                  = 0x4
+	TCSAFLUSH                   = 0x2
+	TIOCCBRK                    = 0x2000747a
+	TIOCCDTR                    = 0x20007478
+	TIOCCONS                    = 0x80047462
+	TIOCDCDTIMESTAMP            = 0x40087458
+	TIOCDRAIN                   = 0x2000745e
+	TIOCDSIMICROCODE            = 0x20007455
+	TIOCEXCL                    = 0x2000740d
+	TIOCEXT                     = 0x80047460
+	TIOCFLUSH                   = 0x80047410
+	TIOCGDRAINWAIT              = 0x40047456
+	TIOCGETA                    = 0x402c7413
+	TIOCGETD                    = 0x4004741a
+	TIOCGPGRP                   = 0x40047477
+	TIOCGWINSZ                  = 0x40087468
+	TIOCIXOFF                   = 0x20007480
+	TIOCIXON                    = 0x20007481
+	TIOCMBIC                    = 0x8004746b
+	TIOCMBIS                    = 0x8004746c
+	TIOCMGDTRWAIT               = 0x4004745a
+	TIOCMGET                    = 0x4004746a
+	TIOCMODG                    = 0x40047403
+	TIOCMODS                    = 0x80047404
+	TIOCMSDTRWAIT               = 0x8004745b
+	TIOCMSET                    = 0x8004746d
+	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                   = 0x20007471
+	TIOCNXCL                    = 0x2000740e
+	TIOCOUTQ                    = 0x40047473
+	TIOCPKT                     = 0x80047470
+	TIOCPKT_DATA                = 0x0
+	TIOCPKT_DOSTOP              = 0x20
+	TIOCPKT_FLUSHREAD           = 0x1
+	TIOCPKT_FLUSHWRITE          = 0x2
+	TIOCPKT_IOCTL               = 0x40
+	TIOCPKT_NOSTOP              = 0x10
+	TIOCPKT_START               = 0x8
+	TIOCPKT_STOP                = 0x4
+	TIOCPTYGNAME                = 0x40807453
+	TIOCPTYGRANT                = 0x20007454
+	TIOCPTYUNLK                 = 0x20007452
+	TIOCREMOTE                  = 0x80047469
+	TIOCSBRK                    = 0x2000747b
+	TIOCSCONS                   = 0x20007463
+	TIOCSCTTY                   = 0x20007461
+	TIOCSDRAINWAIT              = 0x80047457
+	TIOCSDTR                    = 0x20007479
+	TIOCSETA                    = 0x802c7414
+	TIOCSETAF                   = 0x802c7416
+	TIOCSETAW                   = 0x802c7415
+	TIOCSETD                    = 0x8004741b
+	TIOCSIG                     = 0x2000745f
+	TIOCSPGRP                   = 0x80047476
+	TIOCSTART                   = 0x2000746e
+	TIOCSTAT                    = 0x20007465
+	TIOCSTI                     = 0x80017472
+	TIOCSTOP                    = 0x2000746f
+	TIOCSWINSZ                  = 0x80087467
+	TIOCTIMESTAMP               = 0x40087459
+	TIOCUCNTL                   = 0x80047466
+	TOSTOP                      = 0x400000
+	VDISCARD                    = 0xf
+	VDSUSP                      = 0xb
+	VEOF                        = 0x0
+	VEOL                        = 0x1
+	VEOL2                       = 0x2
+	VERASE                      = 0x3
+	VINTR                       = 0x8
+	VKILL                       = 0x5
+	VLNEXT                      = 0xe
+	VMIN                        = 0x10
+	VQUIT                       = 0x9
+	VREPRINT                    = 0x6
+	VSTART                      = 0xc
+	VSTATUS                     = 0x12
+	VSTOP                       = 0xd
+	VSUSP                       = 0xa
+	VT0                         = 0x0
+	VT1                         = 0x10000
+	VTDLY                       = 0x10000
+	VTIME                       = 0x11
+	VWERASE                     = 0x4
+	WCONTINUED                  = 0x10
+	WCOREFLAG                   = 0x80
+	WEXITED                     = 0x4
+	WNOHANG                     = 0x1
+	WNOWAIT                     = 0x20
+	WORDSIZE                    = 0x20
+	WSTOPPED                    = 0x8
+	WUNTRACED                   = 0x2
+)
+
+// Errors
+const (
+	E2BIG           = Errno(0x7)
+	EACCES          = Errno(0xd)
+	EADDRINUSE      = Errno(0x30)
+	EADDRNOTAVAIL   = Errno(0x31)
+	EAFNOSUPPORT    = Errno(0x2f)
+	EAGAIN          = Errno(0x23)
+	EALREADY        = Errno(0x25)
+	EAUTH           = Errno(0x50)
+	EBADARCH        = Errno(0x56)
+	EBADEXEC        = Errno(0x55)
+	EBADF           = Errno(0x9)
+	EBADMACHO       = Errno(0x58)
+	EBADMSG         = Errno(0x5e)
+	EBADRPC         = Errno(0x48)
+	EBUSY           = Errno(0x10)
+	ECANCELED       = Errno(0x59)
+	ECHILD          = Errno(0xa)
+	ECONNABORTED    = Errno(0x35)
+	ECONNREFUSED    = Errno(0x3d)
+	ECONNRESET      = Errno(0x36)
+	EDEADLK         = Errno(0xb)
+	EDESTADDRREQ    = Errno(0x27)
+	EDEVERR         = Errno(0x53)
+	EDOM            = Errno(0x21)
+	EDQUOT          = Errno(0x45)
+	EEXIST          = Errno(0x11)
+	EFAULT          = Errno(0xe)
+	EFBIG           = Errno(0x1b)
+	EFTYPE          = Errno(0x4f)
+	EHOSTDOWN       = Errno(0x40)
+	EHOSTUNREACH    = Errno(0x41)
+	EIDRM           = Errno(0x5a)
+	EILSEQ          = Errno(0x5c)
+	EINPROGRESS     = Errno(0x24)
+	EINTR           = Errno(0x4)
+	EINVAL          = Errno(0x16)
+	EIO             = Errno(0x5)
+	EISCONN         = Errno(0x38)
+	EISDIR          = Errno(0x15)
+	ELAST           = Errno(0x67)
+	ELOOP           = Errno(0x3e)
+	EMFILE          = Errno(0x18)
+	EMLINK          = Errno(0x1f)
+	EMSGSIZE        = Errno(0x28)
+	EMULTIHOP       = Errno(0x5f)
+	ENAMETOOLONG    = Errno(0x3f)
+	ENEEDAUTH       = Errno(0x51)
+	ENETDOWN        = Errno(0x32)
+	ENETRESET       = Errno(0x34)
+	ENETUNREACH     = Errno(0x33)
+	ENFILE          = Errno(0x17)
+	ENOATTR         = Errno(0x5d)
+	ENOBUFS         = Errno(0x37)
+	ENODATA         = Errno(0x60)
+	ENODEV          = Errno(0x13)
+	ENOENT          = Errno(0x2)
+	ENOEXEC         = Errno(0x8)
+	ENOLCK          = Errno(0x4d)
+	ENOLINK         = Errno(0x61)
+	ENOMEM          = Errno(0xc)
+	ENOMSG          = Errno(0x5b)
+	ENOPOLICY       = Errno(0x67)
+	ENOPROTOOPT     = Errno(0x2a)
+	ENOSPC          = Errno(0x1c)
+	ENOSR           = Errno(0x62)
+	ENOSTR          = Errno(0x63)
+	ENOSYS          = Errno(0x4e)
+	ENOTBLK         = Errno(0xf)
+	ENOTCONN        = Errno(0x39)
+	ENOTDIR         = Errno(0x14)
+	ENOTEMPTY       = Errno(0x42)
+	ENOTSOCK        = Errno(0x26)
+	ENOTSUP         = Errno(0x2d)
+	ENOTTY          = Errno(0x19)
+	ENXIO           = Errno(0x6)
+	EOPNOTSUPP      = Errno(0x66)
+	EOVERFLOW       = Errno(0x54)
+	EPERM           = Errno(0x1)
+	EPFNOSUPPORT    = Errno(0x2e)
+	EPIPE           = Errno(0x20)
+	EPROCLIM        = Errno(0x43)
+	EPROCUNAVAIL    = Errno(0x4c)
+	EPROGMISMATCH   = Errno(0x4b)
+	EPROGUNAVAIL    = Errno(0x4a)
+	EPROTO          = Errno(0x64)
+	EPROTONOSUPPORT = Errno(0x2b)
+	EPROTOTYPE      = Errno(0x29)
+	EPWROFF         = Errno(0x52)
+	ERANGE          = Errno(0x22)
+	EREMOTE         = Errno(0x47)
+	EROFS           = Errno(0x1e)
+	ERPCMISMATCH    = Errno(0x49)
+	ESHLIBVERS      = Errno(0x57)
+	ESHUTDOWN       = Errno(0x3a)
+	ESOCKTNOSUPPORT = Errno(0x2c)
+	ESPIPE          = Errno(0x1d)
+	ESRCH           = Errno(0x3)
+	ESTALE          = Errno(0x46)
+	ETIME           = Errno(0x65)
+	ETIMEDOUT       = Errno(0x3c)
+	ETOOMANYREFS    = Errno(0x3b)
+	ETXTBSY         = Errno(0x1a)
+	EUSERS          = Errno(0x44)
+	EWOULDBLOCK     = Errno(0x23)
+	EXDEV           = Errno(0x12)
+)
+
+// Signals
+const (
+	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)
+	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
+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:   "device not configured",
+	7:   "argument list too long",
+	8:   "exec format error",
+	9:   "bad file descriptor",
+	10:  "no child processes",
+	11:  "resource deadlock avoided",
+	12:  "cannot allocate memory",
+	13:  "permission denied",
+	14:  "bad address",
+	15:  "block device required",
+	16:  "resource busy",
+	17:  "file exists",
+	18:  "cross-device link",
+	19:  "operation not supported by 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:  "result too large",
+	35:  "resource temporarily unavailable",
+	36:  "operation now in progress",
+	37:  "operation already in progress",
+	38:  "socket operation on non-socket",
+	39:  "destination address required",
+	40:  "message too long",
+	41:  "protocol wrong type for socket",
+	42:  "protocol not available",
+	43:  "protocol not supported",
+	44:  "socket type not supported",
+	45:  "operation not supported",
+	46:  "protocol family not supported",
+	47:  "address family not supported by protocol family",
+	48:  "address already in use",
+	49:  "can't assign requested address",
+	50:  "network is down",
+	51:  "network is unreachable",
+	52:  "network dropped connection on reset",
+	53:  "software caused connection abort",
+	54:  "connection reset by peer",
+	55:  "no buffer space available",
+	56:  "socket is already connected",
+	57:  "socket is not connected",
+	58:  "can't send after socket shutdown",
+	59:  "too many references: can't splice",
+	60:  "operation timed out",
+	61:  "connection refused",
+	62:  "too many levels of symbolic links",
+	63:  "file name too long",
+	64:  "host is down",
+	65:  "no route to host",
+	66:  "directory not empty",
+	67:  "too many processes",
+	68:  "too many users",
+	69:  "disc quota exceeded",
+	70:  "stale NFS file handle",
+	71:  "too many levels of remote in path",
+	72:  "RPC struct is bad",
+	73:  "RPC version wrong",
+	74:  "RPC prog. not avail",
+	75:  "program version wrong",
+	76:  "bad procedure for program",
+	77:  "no locks available",
+	78:  "function not implemented",
+	79:  "inappropriate file type or format",
+	80:  "authentication error",
+	81:  "need authenticator",
+	82:  "device power is off",
+	83:  "device error",
+	84:  "value too large to be stored in data type",
+	85:  "bad executable (or shared library)",
+	86:  "bad CPU type in executable",
+	87:  "shared library version mismatch",
+	88:  "malformed Mach-o file",
+	89:  "operation canceled",
+	90:  "identifier removed",
+	91:  "no message of desired type",
+	92:  "illegal byte sequence",
+	93:  "attribute not found",
+	94:  "bad message",
+	95:  "EMULTIHOP (Reserved)",
+	96:  "no message available on STREAM",
+	97:  "ENOLINK (Reserved)",
+	98:  "no STREAM resources",
+	99:  "not a STREAM",
+	100: "protocol error",
+	101: "STREAM ioctl timeout",
+	102: "operation not supported on socket",
+	103: "policy not found",
+}
+
+// Signal table
+var signals = [...]string{
+	1:  "hangup",
+	2:  "interrupt",
+	3:  "quit",
+	4:  "illegal instruction",
+	5:  "trace/BPT trap",
+	6:  "abort trap",
+	7:  "EMT trap",
+	8:  "floating point exception",
+	9:  "killed",
+	10: "bus error",
+	11: "segmentation fault",
+	12: "bad system call",
+	13: "broken pipe",
+	14: "alarm clock",
+	15: "terminated",
+	16: "urgent I/O condition",
+	17: "suspended (signal)",
+	18: "suspended",
+	19: "continued",
+	20: "child exited",
+	21: "stopped (tty input)",
+	22: "stopped (tty output)",
+	23: "I/O possible",
+	24: "cputime limit exceeded",
+	25: "filesize limit exceeded",
+	26: "virtual timer expired",
+	27: "profiling timer expired",
+	28: "window size changes",
+	29: "information request",
+	30: "user defined signal 1",
+	31: "user defined signal 2",
+}
diff --git a/src/syscall/zerrors_darwin_arm64.go b/src/syscall/zerrors_darwin_arm64.go
new file mode 100644
index 0000000..98f431c
--- /dev/null
+++ b/src/syscall/zerrors_darwin_arm64.go
@@ -0,0 +1,1436 @@
+// mkerrors.sh -m64
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs -- -m64 _const.go
+
+// +build arm64,darwin
+
+package syscall
+
+const (
+	AF_APPLETALK                      = 0x10
+	AF_CCITT                          = 0xa
+	AF_CHAOS                          = 0x5
+	AF_CNT                            = 0x15
+	AF_COIP                           = 0x14
+	AF_DATAKIT                        = 0x9
+	AF_DECnet                         = 0xc
+	AF_DLI                            = 0xd
+	AF_E164                           = 0x1c
+	AF_ECMA                           = 0x8
+	AF_HYLINK                         = 0xf
+	AF_IEEE80211                      = 0x25
+	AF_IMPLINK                        = 0x3
+	AF_INET                           = 0x2
+	AF_INET6                          = 0x1e
+	AF_IPX                            = 0x17
+	AF_ISDN                           = 0x1c
+	AF_ISO                            = 0x7
+	AF_LAT                            = 0xe
+	AF_LINK                           = 0x12
+	AF_LOCAL                          = 0x1
+	AF_MAX                            = 0x28
+	AF_NATM                           = 0x1f
+	AF_NDRV                           = 0x1b
+	AF_NETBIOS                        = 0x21
+	AF_NS                             = 0x6
+	AF_OSI                            = 0x7
+	AF_PPP                            = 0x22
+	AF_PUP                            = 0x4
+	AF_RESERVED_36                    = 0x24
+	AF_ROUTE                          = 0x11
+	AF_SIP                            = 0x18
+	AF_SNA                            = 0xb
+	AF_SYSTEM                         = 0x20
+	AF_UNIX                           = 0x1
+	AF_UNSPEC                         = 0x0
+	AF_UTUN                           = 0x26
+	B0                                = 0x0
+	B110                              = 0x6e
+	B115200                           = 0x1c200
+	B1200                             = 0x4b0
+	B134                              = 0x86
+	B14400                            = 0x3840
+	B150                              = 0x96
+	B1800                             = 0x708
+	B19200                            = 0x4b00
+	B200                              = 0xc8
+	B230400                           = 0x38400
+	B2400                             = 0x960
+	B28800                            = 0x7080
+	B300                              = 0x12c
+	B38400                            = 0x9600
+	B4800                             = 0x12c0
+	B50                               = 0x32
+	B57600                            = 0xe100
+	B600                              = 0x258
+	B7200                             = 0x1c20
+	B75                               = 0x4b
+	B76800                            = 0x12c00
+	B9600                             = 0x2580
+	BIOCFLUSH                         = 0x20004268
+	BIOCGBLEN                         = 0x40044266
+	BIOCGDLT                          = 0x4004426a
+	BIOCGDLTLIST                      = 0xc00c4279
+	BIOCGETIF                         = 0x4020426b
+	BIOCGHDRCMPLT                     = 0x40044274
+	BIOCGRSIG                         = 0x40044272
+	BIOCGRTIMEOUT                     = 0x4010426e
+	BIOCGSEESENT                      = 0x40044276
+	BIOCGSTATS                        = 0x4008426f
+	BIOCIMMEDIATE                     = 0x80044270
+	BIOCPROMISC                       = 0x20004269
+	BIOCSBLEN                         = 0xc0044266
+	BIOCSDLT                          = 0x80044278
+	BIOCSETF                          = 0x80104267
+	BIOCSETIF                         = 0x8020426c
+	BIOCSHDRCMPLT                     = 0x80044275
+	BIOCSRSIG                         = 0x80044273
+	BIOCSRTIMEOUT                     = 0x8010426d
+	BIOCSSEESENT                      = 0x80044277
+	BIOCVERSION                       = 0x40044271
+	BPF_A                             = 0x10
+	BPF_ABS                           = 0x20
+	BPF_ADD                           = 0x0
+	BPF_ALIGNMENT                     = 0x4
+	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_MAXBUFSIZE                    = 0x80000
+	BPF_MAXINSNS                      = 0x200
+	BPF_MEM                           = 0x60
+	BPF_MEMWORDS                      = 0x10
+	BPF_MINBUFSIZE                    = 0x20
+	BPF_MINOR_VERSION                 = 0x1
+	BPF_MISC                          = 0x7
+	BPF_MSH                           = 0xa0
+	BPF_MUL                           = 0x20
+	BPF_NEG                           = 0x80
+	BPF_OR                            = 0x40
+	BPF_RELEASE                       = 0x30bb6
+	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
+	BRKINT                            = 0x2
+	CFLUSH                            = 0xf
+	CLOCAL                            = 0x8000
+	CREAD                             = 0x800
+	CS5                               = 0x0
+	CS6                               = 0x100
+	CS7                               = 0x200
+	CS8                               = 0x300
+	CSIZE                             = 0x300
+	CSTART                            = 0x11
+	CSTATUS                           = 0x14
+	CSTOP                             = 0x13
+	CSTOPB                            = 0x400
+	CSUSP                             = 0x1a
+	CTL_MAXNAME                       = 0xc
+	CTL_NET                           = 0x4
+	DLT_APPLE_IP_OVER_IEEE1394        = 0x8a
+	DLT_ARCNET                        = 0x7
+	DLT_ATM_CLIP                      = 0x13
+	DLT_ATM_RFC1483                   = 0xb
+	DLT_AX25                          = 0x3
+	DLT_CHAOS                         = 0x5
+	DLT_CHDLC                         = 0x68
+	DLT_C_HDLC                        = 0x68
+	DLT_EN10MB                        = 0x1
+	DLT_EN3MB                         = 0x2
+	DLT_FDDI                          = 0xa
+	DLT_IEEE802                       = 0x6
+	DLT_IEEE802_11                    = 0x69
+	DLT_IEEE802_11_RADIO              = 0x7f
+	DLT_IEEE802_11_RADIO_AVS          = 0xa3
+	DLT_LINUX_SLL                     = 0x71
+	DLT_LOOP                          = 0x6c
+	DLT_NULL                          = 0x0
+	DLT_PFLOG                         = 0x75
+	DLT_PFSYNC                        = 0x12
+	DLT_PPP                           = 0x9
+	DLT_PPP_BSDOS                     = 0x10
+	DLT_PPP_SERIAL                    = 0x32
+	DLT_PRONET                        = 0x4
+	DLT_RAW                           = 0xc
+	DLT_SLIP                          = 0x8
+	DLT_SLIP_BSDOS                    = 0xf
+	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                           = 0x40
+	ECHOE                             = 0x2
+	ECHOK                             = 0x4
+	ECHOKE                            = 0x1
+	ECHONL                            = 0x10
+	ECHOPRT                           = 0x20
+	EVFILT_AIO                        = -0x3
+	EVFILT_FS                         = -0x9
+	EVFILT_MACHPORT                   = -0x8
+	EVFILT_PROC                       = -0x5
+	EVFILT_READ                       = -0x1
+	EVFILT_SIGNAL                     = -0x6
+	EVFILT_SYSCOUNT                   = 0xe
+	EVFILT_THREADMARKER               = 0xe
+	EVFILT_TIMER                      = -0x7
+	EVFILT_USER                       = -0xa
+	EVFILT_VM                         = -0xc
+	EVFILT_VNODE                      = -0x4
+	EVFILT_WRITE                      = -0x2
+	EV_ADD                            = 0x1
+	EV_CLEAR                          = 0x20
+	EV_DELETE                         = 0x2
+	EV_DISABLE                        = 0x8
+	EV_DISPATCH                       = 0x80
+	EV_ENABLE                         = 0x4
+	EV_EOF                            = 0x8000
+	EV_ERROR                          = 0x4000
+	EV_FLAG0                          = 0x1000
+	EV_FLAG1                          = 0x2000
+	EV_ONESHOT                        = 0x10
+	EV_OOBAND                         = 0x2000
+	EV_POLL                           = 0x1000
+	EV_RECEIPT                        = 0x40
+	EV_SYSFLAGS                       = 0xf000
+	EXTA                              = 0x4b00
+	EXTB                              = 0x9600
+	EXTPROC                           = 0x800
+	FD_CLOEXEC                        = 0x1
+	FD_SETSIZE                        = 0x400
+	FLUSHO                            = 0x800000
+	F_ADDFILESIGS                     = 0x3d
+	F_ADDSIGS                         = 0x3b
+	F_ALLOCATEALL                     = 0x4
+	F_ALLOCATECONTIG                  = 0x2
+	F_CHKCLEAN                        = 0x29
+	F_DUPFD                           = 0x0
+	F_DUPFD_CLOEXEC                   = 0x43
+	F_FINDSIGS                        = 0x4e
+	F_FLUSH_DATA                      = 0x28
+	F_FREEZE_FS                       = 0x35
+	F_FULLFSYNC                       = 0x33
+	F_GETCODEDIR                      = 0x48
+	F_GETFD                           = 0x1
+	F_GETFL                           = 0x3
+	F_GETLK                           = 0x7
+	F_GETLKPID                        = 0x42
+	F_GETNOSIGPIPE                    = 0x4a
+	F_GETOWN                          = 0x5
+	F_GETPATH                         = 0x32
+	F_GETPATH_MTMINFO                 = 0x47
+	F_GETPROTECTIONCLASS              = 0x3f
+	F_GETPROTECTIONLEVEL              = 0x4d
+	F_GLOBAL_NOCACHE                  = 0x37
+	F_LOG2PHYS                        = 0x31
+	F_LOG2PHYS_EXT                    = 0x41
+	F_NOCACHE                         = 0x30
+	F_NODIRECT                        = 0x3e
+	F_OK                              = 0x0
+	F_PATHPKG_CHECK                   = 0x34
+	F_PEOFPOSMODE                     = 0x3
+	F_PREALLOCATE                     = 0x2a
+	F_RDADVISE                        = 0x2c
+	F_RDAHEAD                         = 0x2d
+	F_RDLCK                           = 0x1
+	F_SETBACKINGSTORE                 = 0x46
+	F_SETFD                           = 0x2
+	F_SETFL                           = 0x4
+	F_SETLK                           = 0x8
+	F_SETLKW                          = 0x9
+	F_SETLKWTIMEOUT                   = 0xa
+	F_SETNOSIGPIPE                    = 0x49
+	F_SETOWN                          = 0x6
+	F_SETPROTECTIONCLASS              = 0x40
+	F_SETSIZE                         = 0x2b
+	F_SINGLE_WRITER                   = 0x4c
+	F_THAW_FS                         = 0x36
+	F_TRANSCODEKEY                    = 0x4b
+	F_UNLCK                           = 0x2
+	F_VOLPOSMODE                      = 0x4
+	F_WRLCK                           = 0x3
+	HUPCL                             = 0x4000
+	ICANON                            = 0x100
+	ICMP6_FILTER                      = 0x12
+	ICRNL                             = 0x100
+	IEXTEN                            = 0x400
+	IFF_ALLMULTI                      = 0x200
+	IFF_ALTPHYS                       = 0x4000
+	IFF_BROADCAST                     = 0x2
+	IFF_DEBUG                         = 0x4
+	IFF_LINK0                         = 0x1000
+	IFF_LINK1                         = 0x2000
+	IFF_LINK2                         = 0x4000
+	IFF_LOOPBACK                      = 0x8
+	IFF_MULTICAST                     = 0x8000
+	IFF_NOARP                         = 0x80
+	IFF_NOTRAILERS                    = 0x20
+	IFF_OACTIVE                       = 0x400
+	IFF_POINTOPOINT                   = 0x10
+	IFF_PROMISC                       = 0x100
+	IFF_RUNNING                       = 0x40
+	IFF_SIMPLEX                       = 0x800
+	IFF_UP                            = 0x1
+	IFNAMSIZ                          = 0x10
+	IFT_1822                          = 0x2
+	IFT_AAL5                          = 0x31
+	IFT_ARCNET                        = 0x23
+	IFT_ARCNETPLUS                    = 0x24
+	IFT_ATM                           = 0x25
+	IFT_BRIDGE                        = 0xd1
+	IFT_CARP                          = 0xf8
+	IFT_CELLULAR                      = 0xff
+	IFT_CEPT                          = 0x13
+	IFT_DS3                           = 0x1e
+	IFT_ENC                           = 0xf4
+	IFT_EON                           = 0x19
+	IFT_ETHER                         = 0x6
+	IFT_FAITH                         = 0x38
+	IFT_FDDI                          = 0xf
+	IFT_FRELAY                        = 0x20
+	IFT_FRELAYDCE                     = 0x2c
+	IFT_GIF                           = 0x37
+	IFT_HDH1822                       = 0x3
+	IFT_HIPPI                         = 0x2f
+	IFT_HSSI                          = 0x2e
+	IFT_HY                            = 0xe
+	IFT_IEEE1394                      = 0x90
+	IFT_IEEE8023ADLAG                 = 0x88
+	IFT_ISDNBASIC                     = 0x14
+	IFT_ISDNPRIMARY                   = 0x15
+	IFT_ISO88022LLC                   = 0x29
+	IFT_ISO88023                      = 0x7
+	IFT_ISO88024                      = 0x8
+	IFT_ISO88025                      = 0x9
+	IFT_ISO88026                      = 0xa
+	IFT_L2VLAN                        = 0x87
+	IFT_LAPB                          = 0x10
+	IFT_LOCALTALK                     = 0x2a
+	IFT_LOOP                          = 0x18
+	IFT_MIOX25                        = 0x26
+	IFT_MODEM                         = 0x30
+	IFT_NSIP                          = 0x1b
+	IFT_OTHER                         = 0x1
+	IFT_P10                           = 0xc
+	IFT_P80                           = 0xd
+	IFT_PARA                          = 0x22
+	IFT_PDP                           = 0xff
+	IFT_PFLOG                         = 0xf5
+	IFT_PFSYNC                        = 0xf6
+	IFT_PPP                           = 0x17
+	IFT_PROPMUX                       = 0x36
+	IFT_PROPVIRTUAL                   = 0x35
+	IFT_PTPSERIAL                     = 0x16
+	IFT_RS232                         = 0x21
+	IFT_SDLC                          = 0x11
+	IFT_SIP                           = 0x1f
+	IFT_SLIP                          = 0x1c
+	IFT_SMDSDXI                       = 0x2b
+	IFT_SMDSICIP                      = 0x34
+	IFT_SONET                         = 0x27
+	IFT_SONETPATH                     = 0x32
+	IFT_SONETVT                       = 0x33
+	IFT_STARLAN                       = 0xb
+	IFT_STF                           = 0x39
+	IFT_T1                            = 0x12
+	IFT_ULTRA                         = 0x1d
+	IFT_V35                           = 0x2d
+	IFT_X25                           = 0x5
+	IFT_X25DDN                        = 0x4
+	IFT_X25PLE                        = 0x28
+	IFT_XETHER                        = 0x1a
+	IGNBRK                            = 0x1
+	IGNCR                             = 0x80
+	IGNPAR                            = 0x4
+	IMAXBEL                           = 0x2000
+	INLCR                             = 0x40
+	INPCK                             = 0x10
+	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_CLASSD_HOST                    = 0xfffffff
+	IN_CLASSD_NET                     = 0xf0000000
+	IN_CLASSD_NSHIFT                  = 0x1c
+	IN_LINKLOCALNETNUM                = 0xa9fe0000
+	IN_LOOPBACKNET                    = 0x7f
+	IPPROTO_3PC                       = 0x22
+	IPPROTO_ADFS                      = 0x44
+	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_CFTP                      = 0x3e
+	IPPROTO_CHAOS                     = 0x10
+	IPPROTO_CMTP                      = 0x26
+	IPPROTO_CPHB                      = 0x49
+	IPPROTO_CPNX                      = 0x48
+	IPPROTO_DDP                       = 0x25
+	IPPROTO_DGP                       = 0x56
+	IPPROTO_DIVERT                    = 0xfe
+	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_MTP                       = 0x5c
+	IPPROTO_MUX                       = 0x12
+	IPPROTO_ND                        = 0x4d
+	IPPROTO_NHRP                      = 0x36
+	IPPROTO_NONE                      = 0x3b
+	IPPROTO_NSP                       = 0x1f
+	IPPROTO_NVPII                     = 0xb
+	IPPROTO_OSPFIGP                   = 0x59
+	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_SRPC                      = 0x5a
+	IPPROTO_ST                        = 0x7
+	IPPROTO_SVMTP                     = 0x52
+	IPPROTO_SWIPE                     = 0x35
+	IPPROTO_TCF                       = 0x57
+	IPPROTO_TCP                       = 0x6
+	IPPROTO_TP                        = 0x1d
+	IPPROTO_TPXX                      = 0x27
+	IPPROTO_TRUNK1                    = 0x17
+	IPPROTO_TRUNK2                    = 0x18
+	IPPROTO_TTP                       = 0x54
+	IPPROTO_UDP                       = 0x11
+	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_2292DSTOPTS                  = 0x17
+	IPV6_2292HOPLIMIT                 = 0x14
+	IPV6_2292HOPOPTS                  = 0x16
+	IPV6_2292NEXTHOP                  = 0x15
+	IPV6_2292PKTINFO                  = 0x13
+	IPV6_2292PKTOPTIONS               = 0x19
+	IPV6_2292RTHDR                    = 0x18
+	IPV6_BINDV6ONLY                   = 0x1b
+	IPV6_BOUND_IF                     = 0x7d
+	IPV6_CHECKSUM                     = 0x1a
+	IPV6_DEFAULT_MULTICAST_HOPS       = 0x1
+	IPV6_DEFAULT_MULTICAST_LOOP       = 0x1
+	IPV6_DEFHLIM                      = 0x40
+	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_IPSEC_POLICY                 = 0x1c
+	IPV6_JOIN_GROUP                   = 0xc
+	IPV6_LEAVE_GROUP                  = 0xd
+	IPV6_MAXHLIM                      = 0xff
+	IPV6_MAXOPTHDR                    = 0x800
+	IPV6_MAXPACKET                    = 0xffff
+	IPV6_MAX_GROUP_SRC_FILTER         = 0x200
+	IPV6_MAX_MEMBERSHIPS              = 0xfff
+	IPV6_MAX_SOCK_SRC_FILTER          = 0x80
+	IPV6_MIN_MEMBERSHIPS              = 0x1f
+	IPV6_MMTU                         = 0x500
+	IPV6_MULTICAST_HOPS               = 0xa
+	IPV6_MULTICAST_IF                 = 0x9
+	IPV6_MULTICAST_LOOP               = 0xb
+	IPV6_PORTRANGE                    = 0xe
+	IPV6_PORTRANGE_DEFAULT            = 0x0
+	IPV6_PORTRANGE_HIGH               = 0x1
+	IPV6_PORTRANGE_LOW                = 0x2
+	IPV6_RECVTCLASS                   = 0x23
+	IPV6_RTHDR_LOOSE                  = 0x0
+	IPV6_RTHDR_STRICT                 = 0x1
+	IPV6_RTHDR_TYPE_0                 = 0x0
+	IPV6_SOCKOPT_RESERVED1            = 0x3
+	IPV6_TCLASS                       = 0x24
+	IPV6_UNICAST_HOPS                 = 0x4
+	IPV6_V6ONLY                       = 0x1b
+	IPV6_VERSION                      = 0x60
+	IPV6_VERSION_MASK                 = 0xf0
+	IP_ADD_MEMBERSHIP                 = 0xc
+	IP_ADD_SOURCE_MEMBERSHIP          = 0x46
+	IP_BLOCK_SOURCE                   = 0x48
+	IP_BOUND_IF                       = 0x19
+	IP_DEFAULT_MULTICAST_LOOP         = 0x1
+	IP_DEFAULT_MULTICAST_TTL          = 0x1
+	IP_DF                             = 0x4000
+	IP_DROP_MEMBERSHIP                = 0xd
+	IP_DROP_SOURCE_MEMBERSHIP         = 0x47
+	IP_DUMMYNET_CONFIGURE             = 0x3c
+	IP_DUMMYNET_DEL                   = 0x3d
+	IP_DUMMYNET_FLUSH                 = 0x3e
+	IP_DUMMYNET_GET                   = 0x40
+	IP_FAITH                          = 0x16
+	IP_FW_ADD                         = 0x28
+	IP_FW_DEL                         = 0x29
+	IP_FW_FLUSH                       = 0x2a
+	IP_FW_GET                         = 0x2c
+	IP_FW_RESETLOG                    = 0x2d
+	IP_FW_ZERO                        = 0x2b
+	IP_HDRINCL                        = 0x2
+	IP_IPSEC_POLICY                   = 0x15
+	IP_MAXPACKET                      = 0xffff
+	IP_MAX_GROUP_SRC_FILTER           = 0x200
+	IP_MAX_MEMBERSHIPS                = 0xfff
+	IP_MAX_SOCK_MUTE_FILTER           = 0x80
+	IP_MAX_SOCK_SRC_FILTER            = 0x80
+	IP_MF                             = 0x2000
+	IP_MIN_MEMBERSHIPS                = 0x1f
+	IP_MSFILTER                       = 0x4a
+	IP_MSS                            = 0x240
+	IP_MULTICAST_IF                   = 0x9
+	IP_MULTICAST_IFINDEX              = 0x42
+	IP_MULTICAST_LOOP                 = 0xb
+	IP_MULTICAST_TTL                  = 0xa
+	IP_MULTICAST_VIF                  = 0xe
+	IP_NAT__XXX                       = 0x37
+	IP_OFFMASK                        = 0x1fff
+	IP_OLD_FW_ADD                     = 0x32
+	IP_OLD_FW_DEL                     = 0x33
+	IP_OLD_FW_FLUSH                   = 0x34
+	IP_OLD_FW_GET                     = 0x36
+	IP_OLD_FW_RESETLOG                = 0x38
+	IP_OLD_FW_ZERO                    = 0x35
+	IP_OPTIONS                        = 0x1
+	IP_PKTINFO                        = 0x1a
+	IP_PORTRANGE                      = 0x13
+	IP_PORTRANGE_DEFAULT              = 0x0
+	IP_PORTRANGE_HIGH                 = 0x1
+	IP_PORTRANGE_LOW                  = 0x2
+	IP_RECVDSTADDR                    = 0x7
+	IP_RECVIF                         = 0x14
+	IP_RECVOPTS                       = 0x5
+	IP_RECVPKTINFO                    = 0x1a
+	IP_RECVRETOPTS                    = 0x6
+	IP_RECVTTL                        = 0x18
+	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_STRIPHDR                       = 0x17
+	IP_TOS                            = 0x3
+	IP_TRAFFIC_MGT_BACKGROUND         = 0x41
+	IP_TTL                            = 0x4
+	IP_UNBLOCK_SOURCE                 = 0x49
+	ISIG                              = 0x80
+	ISTRIP                            = 0x20
+	IUTF8                             = 0x4000
+	IXANY                             = 0x800
+	IXOFF                             = 0x400
+	IXON                              = 0x200
+	LOCK_EX                           = 0x2
+	LOCK_NB                           = 0x4
+	LOCK_SH                           = 0x1
+	LOCK_UN                           = 0x8
+	MADV_CAN_REUSE                    = 0x9
+	MADV_DONTNEED                     = 0x4
+	MADV_FREE                         = 0x5
+	MADV_FREE_REUSABLE                = 0x7
+	MADV_FREE_REUSE                   = 0x8
+	MADV_NORMAL                       = 0x0
+	MADV_RANDOM                       = 0x1
+	MADV_SEQUENTIAL                   = 0x2
+	MADV_WILLNEED                     = 0x3
+	MADV_ZERO_WIRED_PAGES             = 0x6
+	MAP_ANON                          = 0x1000
+	MAP_COPY                          = 0x2
+	MAP_FILE                          = 0x0
+	MAP_FIXED                         = 0x10
+	MAP_HASSEMAPHORE                  = 0x200
+	MAP_JIT                           = 0x800
+	MAP_NOCACHE                       = 0x400
+	MAP_NOEXTEND                      = 0x100
+	MAP_NORESERVE                     = 0x40
+	MAP_PRIVATE                       = 0x2
+	MAP_RENAME                        = 0x20
+	MAP_RESERVED0080                  = 0x80
+	MAP_SHARED                        = 0x1
+	MCL_CURRENT                       = 0x1
+	MCL_FUTURE                        = 0x2
+	MSG_CTRUNC                        = 0x20
+	MSG_DONTROUTE                     = 0x4
+	MSG_DONTWAIT                      = 0x80
+	MSG_EOF                           = 0x100
+	MSG_EOR                           = 0x8
+	MSG_FLUSH                         = 0x400
+	MSG_HAVEMORE                      = 0x2000
+	MSG_HOLD                          = 0x800
+	MSG_NEEDSA                        = 0x10000
+	MSG_OOB                           = 0x1
+	MSG_PEEK                          = 0x2
+	MSG_RCVMORE                       = 0x4000
+	MSG_SEND                          = 0x1000
+	MSG_TRUNC                         = 0x10
+	MSG_WAITALL                       = 0x40
+	MSG_WAITSTREAM                    = 0x200
+	MS_ASYNC                          = 0x1
+	MS_DEACTIVATE                     = 0x8
+	MS_INVALIDATE                     = 0x2
+	MS_KILLPAGES                      = 0x4
+	MS_SYNC                           = 0x10
+	NAME_MAX                          = 0xff
+	NET_RT_DUMP                       = 0x1
+	NET_RT_DUMP2                      = 0x7
+	NET_RT_FLAGS                      = 0x2
+	NET_RT_IFLIST                     = 0x3
+	NET_RT_IFLIST2                    = 0x6
+	NET_RT_MAXID                      = 0xa
+	NET_RT_STAT                       = 0x4
+	NET_RT_TRASH                      = 0x5
+	NOFLSH                            = 0x80000000
+	NOTE_ABSOLUTE                     = 0x8
+	NOTE_ATTRIB                       = 0x8
+	NOTE_BACKGROUND                   = 0x40
+	NOTE_CHILD                        = 0x4
+	NOTE_CRITICAL                     = 0x20
+	NOTE_DELETE                       = 0x1
+	NOTE_EXEC                         = 0x20000000
+	NOTE_EXIT                         = 0x80000000
+	NOTE_EXITSTATUS                   = 0x4000000
+	NOTE_EXIT_CSERROR                 = 0x40000
+	NOTE_EXIT_DECRYPTFAIL             = 0x10000
+	NOTE_EXIT_DETAIL                  = 0x2000000
+	NOTE_EXIT_DETAIL_MASK             = 0x70000
+	NOTE_EXIT_MEMORY                  = 0x20000
+	NOTE_EXIT_REPARENTED              = 0x80000
+	NOTE_EXTEND                       = 0x4
+	NOTE_FFAND                        = 0x40000000
+	NOTE_FFCOPY                       = 0xc0000000
+	NOTE_FFCTRLMASK                   = 0xc0000000
+	NOTE_FFLAGSMASK                   = 0xffffff
+	NOTE_FFNOP                        = 0x0
+	NOTE_FFOR                         = 0x80000000
+	NOTE_FORK                         = 0x40000000
+	NOTE_LEEWAY                       = 0x10
+	NOTE_LINK                         = 0x10
+	NOTE_LOWAT                        = 0x1
+	NOTE_NONE                         = 0x80
+	NOTE_NSECONDS                     = 0x4
+	NOTE_PCTRLMASK                    = -0x100000
+	NOTE_PDATAMASK                    = 0xfffff
+	NOTE_REAP                         = 0x10000000
+	NOTE_RENAME                       = 0x20
+	NOTE_REVOKE                       = 0x40
+	NOTE_SECONDS                      = 0x1
+	NOTE_SIGNAL                       = 0x8000000
+	NOTE_TRACK                        = 0x1
+	NOTE_TRACKERR                     = 0x2
+	NOTE_TRIGGER                      = 0x1000000
+	NOTE_USECONDS                     = 0x2
+	NOTE_VM_ERROR                     = 0x10000000
+	NOTE_VM_PRESSURE                  = 0x80000000
+	NOTE_VM_PRESSURE_SUDDEN_TERMINATE = 0x20000000
+	NOTE_VM_PRESSURE_TERMINATE        = 0x40000000
+	NOTE_WRITE                        = 0x2
+	OCRNL                             = 0x10
+	OFDEL                             = 0x20000
+	OFILL                             = 0x80
+	ONLCR                             = 0x2
+	ONLRET                            = 0x40
+	ONOCR                             = 0x20
+	ONOEOT                            = 0x8
+	OPOST                             = 0x1
+	O_ACCMODE                         = 0x3
+	O_ALERT                           = 0x20000000
+	O_APPEND                          = 0x8
+	O_ASYNC                           = 0x40
+	O_CLOEXEC                         = 0x1000000
+	O_CREAT                           = 0x200
+	O_DIRECTORY                       = 0x100000
+	O_DP_GETRAWENCRYPTED              = 0x1
+	O_DSYNC                           = 0x400000
+	O_EVTONLY                         = 0x8000
+	O_EXCL                            = 0x800
+	O_EXLOCK                          = 0x20
+	O_FSYNC                           = 0x80
+	O_NDELAY                          = 0x4
+	O_NOCTTY                          = 0x20000
+	O_NOFOLLOW                        = 0x100
+	O_NONBLOCK                        = 0x4
+	O_POPUP                           = 0x80000000
+	O_RDONLY                          = 0x0
+	O_RDWR                            = 0x2
+	O_SHLOCK                          = 0x10
+	O_SYMLINK                         = 0x200000
+	O_SYNC                            = 0x80
+	O_TRUNC                           = 0x400
+	O_WRONLY                          = 0x1
+	PARENB                            = 0x1000
+	PARMRK                            = 0x8
+	PARODD                            = 0x2000
+	PENDIN                            = 0x20000000
+	PRIO_PGRP                         = 0x1
+	PRIO_PROCESS                      = 0x0
+	PRIO_USER                         = 0x2
+	PROT_EXEC                         = 0x4
+	PROT_NONE                         = 0x0
+	PROT_READ                         = 0x1
+	PROT_WRITE                        = 0x2
+	PT_ATTACH                         = 0xa
+	PT_ATTACHEXC                      = 0xe
+	PT_CONTINUE                       = 0x7
+	PT_DENY_ATTACH                    = 0x1f
+	PT_DETACH                         = 0xb
+	PT_FIRSTMACH                      = 0x20
+	PT_FORCEQUOTA                     = 0x1e
+	PT_KILL                           = 0x8
+	PT_READ_D                         = 0x2
+	PT_READ_I                         = 0x1
+	PT_READ_U                         = 0x3
+	PT_SIGEXC                         = 0xc
+	PT_STEP                           = 0x9
+	PT_THUPDATE                       = 0xd
+	PT_TRACE_ME                       = 0x0
+	PT_WRITE_D                        = 0x5
+	PT_WRITE_I                        = 0x4
+	PT_WRITE_U                        = 0x6
+	RLIMIT_AS                         = 0x5
+	RLIMIT_CORE                       = 0x4
+	RLIMIT_CPU                        = 0x0
+	RLIMIT_CPU_USAGE_MONITOR          = 0x2
+	RLIMIT_DATA                       = 0x2
+	RLIMIT_FSIZE                      = 0x1
+	RLIMIT_NOFILE                     = 0x8
+	RLIMIT_STACK                      = 0x3
+	RLIM_INFINITY                     = 0x7fffffffffffffff
+	RTAX_AUTHOR                       = 0x6
+	RTAX_BRD                          = 0x7
+	RTAX_DST                          = 0x0
+	RTAX_GATEWAY                      = 0x1
+	RTAX_GENMASK                      = 0x3
+	RTAX_IFA                          = 0x5
+	RTAX_IFP                          = 0x4
+	RTAX_MAX                          = 0x8
+	RTAX_NETMASK                      = 0x2
+	RTA_AUTHOR                        = 0x40
+	RTA_BRD                           = 0x80
+	RTA_DST                           = 0x1
+	RTA_GATEWAY                       = 0x2
+	RTA_GENMASK                       = 0x8
+	RTA_IFA                           = 0x20
+	RTA_IFP                           = 0x10
+	RTA_NETMASK                       = 0x4
+	RTF_BLACKHOLE                     = 0x1000
+	RTF_BROADCAST                     = 0x400000
+	RTF_CLONING                       = 0x100
+	RTF_CONDEMNED                     = 0x2000000
+	RTF_DELCLONE                      = 0x80
+	RTF_DONE                          = 0x40
+	RTF_DYNAMIC                       = 0x10
+	RTF_GATEWAY                       = 0x2
+	RTF_HOST                          = 0x4
+	RTF_IFREF                         = 0x4000000
+	RTF_IFSCOPE                       = 0x1000000
+	RTF_LLINFO                        = 0x400
+	RTF_LOCAL                         = 0x200000
+	RTF_MODIFIED                      = 0x20
+	RTF_MULTICAST                     = 0x800000
+	RTF_PINNED                        = 0x100000
+	RTF_PRCLONING                     = 0x10000
+	RTF_PROTO1                        = 0x8000
+	RTF_PROTO2                        = 0x4000
+	RTF_PROTO3                        = 0x40000
+	RTF_PROXY                         = 0x8000000
+	RTF_REJECT                        = 0x8
+	RTF_ROUTER                        = 0x10000000
+	RTF_STATIC                        = 0x800
+	RTF_UP                            = 0x1
+	RTF_WASCLONED                     = 0x20000
+	RTF_XRESOLVE                      = 0x200
+	RTM_ADD                           = 0x1
+	RTM_CHANGE                        = 0x3
+	RTM_DELADDR                       = 0xd
+	RTM_DELETE                        = 0x2
+	RTM_DELMADDR                      = 0x10
+	RTM_GET                           = 0x4
+	RTM_GET2                          = 0x14
+	RTM_IFINFO                        = 0xe
+	RTM_IFINFO2                       = 0x12
+	RTM_LOCK                          = 0x8
+	RTM_LOSING                        = 0x5
+	RTM_MISS                          = 0x7
+	RTM_NEWADDR                       = 0xc
+	RTM_NEWMADDR                      = 0xf
+	RTM_NEWMADDR2                     = 0x13
+	RTM_OLDADD                        = 0x9
+	RTM_OLDDEL                        = 0xa
+	RTM_REDIRECT                      = 0x6
+	RTM_RESOLVE                       = 0xb
+	RTM_RTTUNIT                       = 0xf4240
+	RTM_VERSION                       = 0x5
+	RTV_EXPIRE                        = 0x4
+	RTV_HOPCOUNT                      = 0x2
+	RTV_MTU                           = 0x1
+	RTV_RPIPE                         = 0x8
+	RTV_RTT                           = 0x40
+	RTV_RTTVAR                        = 0x80
+	RTV_SPIPE                         = 0x10
+	RTV_SSTHRESH                      = 0x20
+	RUSAGE_CHILDREN                   = -0x1
+	RUSAGE_SELF                       = 0x0
+	SCM_CREDS                         = 0x3
+	SCM_RIGHTS                        = 0x1
+	SCM_TIMESTAMP                     = 0x2
+	SCM_TIMESTAMP_MONOTONIC           = 0x4
+	SHUT_RD                           = 0x0
+	SHUT_RDWR                         = 0x2
+	SHUT_WR                           = 0x1
+	SIOCADDMULTI                      = 0x80206931
+	SIOCAIFADDR                       = 0x8040691a
+	SIOCARPIPLL                       = 0xc0206928
+	SIOCATMARK                        = 0x40047307
+	SIOCAUTOADDR                      = 0xc0206926
+	SIOCAUTONETMASK                   = 0x80206927
+	SIOCDELMULTI                      = 0x80206932
+	SIOCDIFADDR                       = 0x80206919
+	SIOCDIFPHYADDR                    = 0x80206941
+	SIOCGDRVSPEC                      = 0xc028697b
+	SIOCGETVLAN                       = 0xc020697f
+	SIOCGHIWAT                        = 0x40047301
+	SIOCGIFADDR                       = 0xc0206921
+	SIOCGIFALTMTU                     = 0xc0206948
+	SIOCGIFASYNCMAP                   = 0xc020697c
+	SIOCGIFBOND                       = 0xc0206947
+	SIOCGIFBRDADDR                    = 0xc0206923
+	SIOCGIFCAP                        = 0xc020695b
+	SIOCGIFCONF                       = 0xc00c6924
+	SIOCGIFDEVMTU                     = 0xc0206944
+	SIOCGIFDSTADDR                    = 0xc0206922
+	SIOCGIFFLAGS                      = 0xc0206911
+	SIOCGIFGENERIC                    = 0xc020693a
+	SIOCGIFKPI                        = 0xc0206987
+	SIOCGIFMAC                        = 0xc0206982
+	SIOCGIFMEDIA                      = 0xc02c6938
+	SIOCGIFMETRIC                     = 0xc0206917
+	SIOCGIFMTU                        = 0xc0206933
+	SIOCGIFNETMASK                    = 0xc0206925
+	SIOCGIFPDSTADDR                   = 0xc0206940
+	SIOCGIFPHYS                       = 0xc0206935
+	SIOCGIFPSRCADDR                   = 0xc020693f
+	SIOCGIFSTATUS                     = 0xc331693d
+	SIOCGIFVLAN                       = 0xc020697f
+	SIOCGIFWAKEFLAGS                  = 0xc0206988
+	SIOCGLOWAT                        = 0x40047303
+	SIOCGPGRP                         = 0x40047309
+	SIOCIFCREATE                      = 0xc0206978
+	SIOCIFCREATE2                     = 0xc020697a
+	SIOCIFDESTROY                     = 0x80206979
+	SIOCIFGCLONERS                    = 0xc0106981
+	SIOCRSLVMULTI                     = 0xc010693b
+	SIOCSDRVSPEC                      = 0x8028697b
+	SIOCSETVLAN                       = 0x8020697e
+	SIOCSHIWAT                        = 0x80047300
+	SIOCSIFADDR                       = 0x8020690c
+	SIOCSIFALTMTU                     = 0x80206945
+	SIOCSIFASYNCMAP                   = 0x8020697d
+	SIOCSIFBOND                       = 0x80206946
+	SIOCSIFBRDADDR                    = 0x80206913
+	SIOCSIFCAP                        = 0x8020695a
+	SIOCSIFDSTADDR                    = 0x8020690e
+	SIOCSIFFLAGS                      = 0x80206910
+	SIOCSIFGENERIC                    = 0x80206939
+	SIOCSIFKPI                        = 0x80206986
+	SIOCSIFLLADDR                     = 0x8020693c
+	SIOCSIFMAC                        = 0x80206983
+	SIOCSIFMEDIA                      = 0xc0206937
+	SIOCSIFMETRIC                     = 0x80206918
+	SIOCSIFMTU                        = 0x80206934
+	SIOCSIFNETMASK                    = 0x80206916
+	SIOCSIFPHYADDR                    = 0x8040693e
+	SIOCSIFPHYS                       = 0x80206936
+	SIOCSIFVLAN                       = 0x8020697e
+	SIOCSLOWAT                        = 0x80047302
+	SIOCSPGRP                         = 0x80047308
+	SOCK_DGRAM                        = 0x2
+	SOCK_MAXADDRLEN                   = 0xff
+	SOCK_RAW                          = 0x3
+	SOCK_RDM                          = 0x4
+	SOCK_SEQPACKET                    = 0x5
+	SOCK_STREAM                       = 0x1
+	SOL_SOCKET                        = 0xffff
+	SOMAXCONN                         = 0x80
+	SO_ACCEPTCONN                     = 0x2
+	SO_BROADCAST                      = 0x20
+	SO_DEBUG                          = 0x1
+	SO_DONTROUTE                      = 0x10
+	SO_DONTTRUNC                      = 0x2000
+	SO_ERROR                          = 0x1007
+	SO_KEEPALIVE                      = 0x8
+	SO_LABEL                          = 0x1010
+	SO_LINGER                         = 0x80
+	SO_LINGER_SEC                     = 0x1080
+	SO_NKE                            = 0x1021
+	SO_NOADDRERR                      = 0x1023
+	SO_NOSIGPIPE                      = 0x1022
+	SO_NOTIFYCONFLICT                 = 0x1026
+	SO_NP_EXTENSIONS                  = 0x1083
+	SO_NREAD                          = 0x1020
+	SO_NUMRCVPKT                      = 0x1112
+	SO_NWRITE                         = 0x1024
+	SO_OOBINLINE                      = 0x100
+	SO_PEERLABEL                      = 0x1011
+	SO_RANDOMPORT                     = 0x1082
+	SO_RCVBUF                         = 0x1002
+	SO_RCVLOWAT                       = 0x1004
+	SO_RCVTIMEO                       = 0x1006
+	SO_REUSEADDR                      = 0x4
+	SO_REUSEPORT                      = 0x200
+	SO_REUSESHAREUID                  = 0x1025
+	SO_SNDBUF                         = 0x1001
+	SO_SNDLOWAT                       = 0x1003
+	SO_SNDTIMEO                       = 0x1005
+	SO_TIMESTAMP                      = 0x400
+	SO_TIMESTAMP_MONOTONIC            = 0x800
+	SO_TYPE                           = 0x1008
+	SO_UPCALLCLOSEWAIT                = 0x1027
+	SO_USELOOPBACK                    = 0x40
+	SO_WANTMORE                       = 0x4000
+	SO_WANTOOBFLAG                    = 0x8000
+	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_IFWHT                           = 0xe000
+	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_ISTXT                           = 0x200
+	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
+	TCIFLUSH                          = 0x1
+	TCIOFLUSH                         = 0x3
+	TCOFLUSH                          = 0x2
+	TCP_CONNECTIONTIMEOUT             = 0x20
+	TCP_ENABLE_ECN                    = 0x104
+	TCP_KEEPALIVE                     = 0x10
+	TCP_KEEPCNT                       = 0x102
+	TCP_KEEPINTVL                     = 0x101
+	TCP_MAXHLEN                       = 0x3c
+	TCP_MAXOLEN                       = 0x28
+	TCP_MAXSEG                        = 0x2
+	TCP_MAXWIN                        = 0xffff
+	TCP_MAX_SACK                      = 0x4
+	TCP_MAX_WINSHIFT                  = 0xe
+	TCP_MINMSS                        = 0xd8
+	TCP_MSS                           = 0x200
+	TCP_NODELAY                       = 0x1
+	TCP_NOOPT                         = 0x8
+	TCP_NOPUSH                        = 0x4
+	TCP_NOTSENT_LOWAT                 = 0x201
+	TCP_RXT_CONNDROPTIME              = 0x80
+	TCP_RXT_FINDROP                   = 0x100
+	TCP_SENDMOREACKS                  = 0x103
+	TCSAFLUSH                         = 0x2
+	TIOCCBRK                          = 0x2000747a
+	TIOCCDTR                          = 0x20007478
+	TIOCCONS                          = 0x80047462
+	TIOCDCDTIMESTAMP                  = 0x40107458
+	TIOCDRAIN                         = 0x2000745e
+	TIOCDSIMICROCODE                  = 0x20007455
+	TIOCEXCL                          = 0x2000740d
+	TIOCEXT                           = 0x80047460
+	TIOCFLUSH                         = 0x80047410
+	TIOCGDRAINWAIT                    = 0x40047456
+	TIOCGETA                          = 0x40487413
+	TIOCGETD                          = 0x4004741a
+	TIOCGPGRP                         = 0x40047477
+	TIOCGWINSZ                        = 0x40087468
+	TIOCIXOFF                         = 0x20007480
+	TIOCIXON                          = 0x20007481
+	TIOCMBIC                          = 0x8004746b
+	TIOCMBIS                          = 0x8004746c
+	TIOCMGDTRWAIT                     = 0x4004745a
+	TIOCMGET                          = 0x4004746a
+	TIOCMODG                          = 0x40047403
+	TIOCMODS                          = 0x80047404
+	TIOCMSDTRWAIT                     = 0x8004745b
+	TIOCMSET                          = 0x8004746d
+	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                         = 0x20007471
+	TIOCNXCL                          = 0x2000740e
+	TIOCOUTQ                          = 0x40047473
+	TIOCPKT                           = 0x80047470
+	TIOCPKT_DATA                      = 0x0
+	TIOCPKT_DOSTOP                    = 0x20
+	TIOCPKT_FLUSHREAD                 = 0x1
+	TIOCPKT_FLUSHWRITE                = 0x2
+	TIOCPKT_IOCTL                     = 0x40
+	TIOCPKT_NOSTOP                    = 0x10
+	TIOCPKT_START                     = 0x8
+	TIOCPKT_STOP                      = 0x4
+	TIOCPTYGNAME                      = 0x40807453
+	TIOCPTYGRANT                      = 0x20007454
+	TIOCPTYUNLK                       = 0x20007452
+	TIOCREMOTE                        = 0x80047469
+	TIOCSBRK                          = 0x2000747b
+	TIOCSCONS                         = 0x20007463
+	TIOCSCTTY                         = 0x20007461
+	TIOCSDRAINWAIT                    = 0x80047457
+	TIOCSDTR                          = 0x20007479
+	TIOCSETA                          = 0x80487414
+	TIOCSETAF                         = 0x80487416
+	TIOCSETAW                         = 0x80487415
+	TIOCSETD                          = 0x8004741b
+	TIOCSIG                           = 0x2000745f
+	TIOCSPGRP                         = 0x80047476
+	TIOCSTART                         = 0x2000746e
+	TIOCSTAT                          = 0x20007465
+	TIOCSTI                           = 0x80017472
+	TIOCSTOP                          = 0x2000746f
+	TIOCSWINSZ                        = 0x80087467
+	TIOCTIMESTAMP                     = 0x40107459
+	TIOCUCNTL                         = 0x80047466
+	TOSTOP                            = 0x400000
+	VDISCARD                          = 0xf
+	VDSUSP                            = 0xb
+	VEOF                              = 0x0
+	VEOL                              = 0x1
+	VEOL2                             = 0x2
+	VERASE                            = 0x3
+	VINTR                             = 0x8
+	VKILL                             = 0x5
+	VLNEXT                            = 0xe
+	VMIN                              = 0x10
+	VQUIT                             = 0x9
+	VREPRINT                          = 0x6
+	VSTART                            = 0xc
+	VSTATUS                           = 0x12
+	VSTOP                             = 0xd
+	VSUSP                             = 0xa
+	VT0                               = 0x0
+	VT1                               = 0x10000
+	VTDLY                             = 0x10000
+	VTIME                             = 0x11
+	VWERASE                           = 0x4
+	WCONTINUED                        = 0x10
+	WCOREFLAG                         = 0x80
+	WEXITED                           = 0x4
+	WNOHANG                           = 0x1
+	WNOWAIT                           = 0x20
+	WORDSIZE                          = 0x40
+	WSTOPPED                          = 0x8
+	WUNTRACED                         = 0x2
+)
+
+// Errors
+const (
+	E2BIG           = Errno(0x7)
+	EACCES          = Errno(0xd)
+	EADDRINUSE      = Errno(0x30)
+	EADDRNOTAVAIL   = Errno(0x31)
+	EAFNOSUPPORT    = Errno(0x2f)
+	EAGAIN          = Errno(0x23)
+	EALREADY        = Errno(0x25)
+	EAUTH           = Errno(0x50)
+	EBADARCH        = Errno(0x56)
+	EBADEXEC        = Errno(0x55)
+	EBADF           = Errno(0x9)
+	EBADMACHO       = Errno(0x58)
+	EBADMSG         = Errno(0x5e)
+	EBADRPC         = Errno(0x48)
+	EBUSY           = Errno(0x10)
+	ECANCELED       = Errno(0x59)
+	ECHILD          = Errno(0xa)
+	ECONNABORTED    = Errno(0x35)
+	ECONNREFUSED    = Errno(0x3d)
+	ECONNRESET      = Errno(0x36)
+	EDEADLK         = Errno(0xb)
+	EDESTADDRREQ    = Errno(0x27)
+	EDEVERR         = Errno(0x53)
+	EDOM            = Errno(0x21)
+	EDQUOT          = Errno(0x45)
+	EEXIST          = Errno(0x11)
+	EFAULT          = Errno(0xe)
+	EFBIG           = Errno(0x1b)
+	EFTYPE          = Errno(0x4f)
+	EHOSTDOWN       = Errno(0x40)
+	EHOSTUNREACH    = Errno(0x41)
+	EIDRM           = Errno(0x5a)
+	EILSEQ          = Errno(0x5c)
+	EINPROGRESS     = Errno(0x24)
+	EINTR           = Errno(0x4)
+	EINVAL          = Errno(0x16)
+	EIO             = Errno(0x5)
+	EISCONN         = Errno(0x38)
+	EISDIR          = Errno(0x15)
+	ELAST           = Errno(0x6a)
+	ELOOP           = Errno(0x3e)
+	EMFILE          = Errno(0x18)
+	EMLINK          = Errno(0x1f)
+	EMSGSIZE        = Errno(0x28)
+	EMULTIHOP       = Errno(0x5f)
+	ENAMETOOLONG    = Errno(0x3f)
+	ENEEDAUTH       = Errno(0x51)
+	ENETDOWN        = Errno(0x32)
+	ENETRESET       = Errno(0x34)
+	ENETUNREACH     = Errno(0x33)
+	ENFILE          = Errno(0x17)
+	ENOATTR         = Errno(0x5d)
+	ENOBUFS         = Errno(0x37)
+	ENODATA         = Errno(0x60)
+	ENODEV          = Errno(0x13)
+	ENOENT          = Errno(0x2)
+	ENOEXEC         = Errno(0x8)
+	ENOLCK          = Errno(0x4d)
+	ENOLINK         = Errno(0x61)
+	ENOMEM          = Errno(0xc)
+	ENOMSG          = Errno(0x5b)
+	ENOPOLICY       = Errno(0x67)
+	ENOPROTOOPT     = Errno(0x2a)
+	ENOSPC          = Errno(0x1c)
+	ENOSR           = Errno(0x62)
+	ENOSTR          = Errno(0x63)
+	ENOSYS          = Errno(0x4e)
+	ENOTBLK         = Errno(0xf)
+	ENOTCONN        = Errno(0x39)
+	ENOTDIR         = Errno(0x14)
+	ENOTEMPTY       = Errno(0x42)
+	ENOTRECOVERABLE = Errno(0x68)
+	ENOTSOCK        = Errno(0x26)
+	ENOTSUP         = Errno(0x2d)
+	ENOTTY          = Errno(0x19)
+	ENXIO           = Errno(0x6)
+	EOPNOTSUPP      = Errno(0x66)
+	EOVERFLOW       = Errno(0x54)
+	EOWNERDEAD      = Errno(0x69)
+	EPERM           = Errno(0x1)
+	EPFNOSUPPORT    = Errno(0x2e)
+	EPIPE           = Errno(0x20)
+	EPROCLIM        = Errno(0x43)
+	EPROCUNAVAIL    = Errno(0x4c)
+	EPROGMISMATCH   = Errno(0x4b)
+	EPROGUNAVAIL    = Errno(0x4a)
+	EPROTO          = Errno(0x64)
+	EPROTONOSUPPORT = Errno(0x2b)
+	EPROTOTYPE      = Errno(0x29)
+	EPWROFF         = Errno(0x52)
+	EQFULL          = Errno(0x6a)
+	ERANGE          = Errno(0x22)
+	EREMOTE         = Errno(0x47)
+	EROFS           = Errno(0x1e)
+	ERPCMISMATCH    = Errno(0x49)
+	ESHLIBVERS      = Errno(0x57)
+	ESHUTDOWN       = Errno(0x3a)
+	ESOCKTNOSUPPORT = Errno(0x2c)
+	ESPIPE          = Errno(0x1d)
+	ESRCH           = Errno(0x3)
+	ESTALE          = Errno(0x46)
+	ETIME           = Errno(0x65)
+	ETIMEDOUT       = Errno(0x3c)
+	ETOOMANYREFS    = Errno(0x3b)
+	ETXTBSY         = Errno(0x1a)
+	EUSERS          = Errno(0x44)
+	EWOULDBLOCK     = Errno(0x23)
+	EXDEV           = Errno(0x12)
+)
+
+// Signals
+const (
+	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)
+	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
+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:   "device not configured",
+	7:   "argument list too long",
+	8:   "exec format error",
+	9:   "bad file descriptor",
+	10:  "no child processes",
+	11:  "resource deadlock avoided",
+	12:  "cannot allocate memory",
+	13:  "permission denied",
+	14:  "bad address",
+	15:  "block device required",
+	16:  "resource busy",
+	17:  "file exists",
+	18:  "cross-device link",
+	19:  "operation not supported by 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:  "result too large",
+	35:  "resource temporarily unavailable",
+	36:  "operation now in progress",
+	37:  "operation already in progress",
+	38:  "socket operation on non-socket",
+	39:  "destination address required",
+	40:  "message too long",
+	41:  "protocol wrong type for socket",
+	42:  "protocol not available",
+	43:  "protocol not supported",
+	44:  "socket type not supported",
+	45:  "operation not supported",
+	46:  "protocol family not supported",
+	47:  "address family not supported by protocol family",
+	48:  "address already in use",
+	49:  "can't assign requested address",
+	50:  "network is down",
+	51:  "network is unreachable",
+	52:  "network dropped connection on reset",
+	53:  "software caused connection abort",
+	54:  "connection reset by peer",
+	55:  "no buffer space available",
+	56:  "socket is already connected",
+	57:  "socket is not connected",
+	58:  "can't send after socket shutdown",
+	59:  "too many references: can't splice",
+	60:  "operation timed out",
+	61:  "connection refused",
+	62:  "too many levels of symbolic links",
+	63:  "file name too long",
+	64:  "host is down",
+	65:  "no route to host",
+	66:  "directory not empty",
+	67:  "too many processes",
+	68:  "too many users",
+	69:  "disc quota exceeded",
+	70:  "stale NFS file handle",
+	71:  "too many levels of remote in path",
+	72:  "RPC struct is bad",
+	73:  "RPC version wrong",
+	74:  "RPC prog. not avail",
+	75:  "program version wrong",
+	76:  "bad procedure for program",
+	77:  "no locks available",
+	78:  "function not implemented",
+	79:  "inappropriate file type or format",
+	80:  "authentication error",
+	81:  "need authenticator",
+	82:  "device power is off",
+	83:  "device error",
+	84:  "value too large to be stored in data type",
+	85:  "bad executable (or shared library)",
+	86:  "bad CPU type in executable",
+	87:  "shared library version mismatch",
+	88:  "malformed Mach-o file",
+	89:  "operation canceled",
+	90:  "identifier removed",
+	91:  "no message of desired type",
+	92:  "illegal byte sequence",
+	93:  "attribute not found",
+	94:  "bad message",
+	95:  "EMULTIHOP (Reserved)",
+	96:  "no message available on STREAM",
+	97:  "ENOLINK (Reserved)",
+	98:  "no STREAM resources",
+	99:  "not a STREAM",
+	100: "protocol error",
+	101: "STREAM ioctl timeout",
+	102: "operation not supported on socket",
+	103: "policy not found",
+	104: "state not recoverable",
+	105: "previous owner died",
+	106: "interface output queue is full",
+}
+
+// Signal table
+var signals = [...]string{
+	1:  "hangup",
+	2:  "interrupt",
+	3:  "quit",
+	4:  "illegal instruction",
+	5:  "trace/BPT trap",
+	6:  "abort trap",
+	7:  "EMT trap",
+	8:  "floating point exception",
+	9:  "killed",
+	10: "bus error",
+	11: "segmentation fault",
+	12: "bad system call",
+	13: "broken pipe",
+	14: "alarm clock",
+	15: "terminated",
+	16: "urgent I/O condition",
+	17: "suspended (signal)",
+	18: "suspended",
+	19: "continued",
+	20: "child exited",
+	21: "stopped (tty input)",
+	22: "stopped (tty output)",
+	23: "I/O possible",
+	24: "cputime limit exceeded",
+	25: "filesize limit exceeded",
+	26: "virtual timer expired",
+	27: "profiling timer expired",
+	28: "window size changes",
+	29: "information request",
+	30: "user defined signal 1",
+	31: "user defined signal 2",
+}
diff --git a/src/syscall/zerrors_dragonfly_386.go b/src/syscall/zerrors_dragonfly_386.go
deleted file mode 100644
index 701a1c3..0000000
--- a/src/syscall/zerrors_dragonfly_386.go
+++ /dev/null
@@ -1,1526 +0,0 @@
-// mkerrors.sh -m32
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
-
-// Created by cgo -godefs - DO NOT EDIT
-// cgo -godefs -- -m32 _const.go
-
-package syscall
-
-const (
-	AF_APPLETALK                      = 0x10
-	AF_ATM                            = 0x1e
-	AF_BLUETOOTH                      = 0x21
-	AF_CCITT                          = 0xa
-	AF_CHAOS                          = 0x5
-	AF_CNT                            = 0x15
-	AF_COIP                           = 0x14
-	AF_DATAKIT                        = 0x9
-	AF_DECnet                         = 0xc
-	AF_DLI                            = 0xd
-	AF_E164                           = 0x1a
-	AF_ECMA                           = 0x8
-	AF_HYLINK                         = 0xf
-	AF_IEEE80211                      = 0x23
-	AF_IMPLINK                        = 0x3
-	AF_INET                           = 0x2
-	AF_INET6                          = 0x1c
-	AF_IPX                            = 0x17
-	AF_ISDN                           = 0x1a
-	AF_ISO                            = 0x7
-	AF_LAT                            = 0xe
-	AF_LINK                           = 0x12
-	AF_LOCAL                          = 0x1
-	AF_MAX                            = 0x24
-	AF_MPLS                           = 0x22
-	AF_NATM                           = 0x1d
-	AF_NETGRAPH                       = 0x20
-	AF_NS                             = 0x6
-	AF_OSI                            = 0x7
-	AF_PUP                            = 0x4
-	AF_ROUTE                          = 0x11
-	AF_SIP                            = 0x18
-	AF_SNA                            = 0xb
-	AF_UNIX                           = 0x1
-	AF_UNSPEC                         = 0x0
-	B0                                = 0x0
-	B110                              = 0x6e
-	B115200                           = 0x1c200
-	B1200                             = 0x4b0
-	B134                              = 0x86
-	B14400                            = 0x3840
-	B150                              = 0x96
-	B1800                             = 0x708
-	B19200                            = 0x4b00
-	B200                              = 0xc8
-	B230400                           = 0x38400
-	B2400                             = 0x960
-	B28800                            = 0x7080
-	B300                              = 0x12c
-	B38400                            = 0x9600
-	B4800                             = 0x12c0
-	B50                               = 0x32
-	B57600                            = 0xe100
-	B600                              = 0x258
-	B7200                             = 0x1c20
-	B75                               = 0x4b
-	B76800                            = 0x12c00
-	B9600                             = 0x2580
-	BIOCFLUSH                         = 0x20004268
-	BIOCGBLEN                         = 0x40044266
-	BIOCGDLT                          = 0x4004426a
-	BIOCGDLTLIST                      = 0xc0084279
-	BIOCGETIF                         = 0x4020426b
-	BIOCGHDRCMPLT                     = 0x40044274
-	BIOCGRSIG                         = 0x40044272
-	BIOCGRTIMEOUT                     = 0x4008426e
-	BIOCGSEESENT                      = 0x40044276
-	BIOCGSTATS                        = 0x4008426f
-	BIOCIMMEDIATE                     = 0x80044270
-	BIOCLOCK                          = 0x2000427a
-	BIOCPROMISC                       = 0x20004269
-	BIOCSBLEN                         = 0xc0044266
-	BIOCSDLT                          = 0x80044278
-	BIOCSETF                          = 0x80084267
-	BIOCSETIF                         = 0x8020426c
-	BIOCSETWF                         = 0x8008427b
-	BIOCSHDRCMPLT                     = 0x80044275
-	BIOCSRSIG                         = 0x80044273
-	BIOCSRTIMEOUT                     = 0x8008426d
-	BIOCSSEESENT                      = 0x80044277
-	BIOCVERSION                       = 0x40044271
-	BPF_A                             = 0x10
-	BPF_ABS                           = 0x20
-	BPF_ADD                           = 0x0
-	BPF_ALIGNMENT                     = 0x4
-	BPF_ALU                           = 0x4
-	BPF_AND                           = 0x50
-	BPF_B                             = 0x10
-	BPF_DEFAULTBUFSIZE                = 0x1000
-	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_MAXBUFSIZE                    = 0x80000
-	BPF_MAXINSNS                      = 0x200
-	BPF_MAX_CLONES                    = 0x80
-	BPF_MEM                           = 0x60
-	BPF_MEMWORDS                      = 0x10
-	BPF_MINBUFSIZE                    = 0x20
-	BPF_MINOR_VERSION                 = 0x1
-	BPF_MISC                          = 0x7
-	BPF_MSH                           = 0xa0
-	BPF_MUL                           = 0x20
-	BPF_NEG                           = 0x80
-	BPF_OR                            = 0x40
-	BPF_RELEASE                       = 0x30bb6
-	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
-	BRKINT                            = 0x2
-	CFLUSH                            = 0xf
-	CLOCAL                            = 0x8000
-	CREAD                             = 0x800
-	CS5                               = 0x0
-	CS6                               = 0x100
-	CS7                               = 0x200
-	CS8                               = 0x300
-	CSIZE                             = 0x300
-	CSTART                            = 0x11
-	CSTATUS                           = 0x14
-	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
-	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_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_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_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
-	ECHOK                             = 0x4
-	ECHOKE                            = 0x1
-	ECHONL                            = 0x10
-	ECHOPRT                           = 0x20
-	EVFILT_AIO                        = -0x3
-	EVFILT_EXCEPT                     = -0x8
-	EVFILT_MARKER                     = 0xf
-	EVFILT_PROC                       = -0x5
-	EVFILT_READ                       = -0x1
-	EVFILT_SIGNAL                     = -0x6
-	EVFILT_SYSCOUNT                   = 0x8
-	EVFILT_TIMER                      = -0x7
-	EVFILT_VNODE                      = -0x4
-	EVFILT_WRITE                      = -0x2
-	EV_ADD                            = 0x1
-	EV_CLEAR                          = 0x20
-	EV_DELETE                         = 0x2
-	EV_DISABLE                        = 0x8
-	EV_ENABLE                         = 0x4
-	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_GETFD                           = 0x1
-	F_GETFL                           = 0x3
-	F_GETLK                           = 0x7
-	F_GETOWN                          = 0x5
-	F_OK                              = 0x0
-	F_RDLCK                           = 0x1
-	F_SETFD                           = 0x2
-	F_SETFL                           = 0x4
-	F_SETLK                           = 0x8
-	F_SETLKW                          = 0x9
-	F_SETOWN                          = 0x6
-	F_UNLCK                           = 0x2
-	F_WRLCK                           = 0x3
-	HUPCL                             = 0x4000
-	ICANON                            = 0x100
-	ICMP6_FILTER                      = 0x12
-	ICRNL                             = 0x100
-	IEXTEN                            = 0x400
-	IFAN_ARRIVAL                      = 0x0
-	IFAN_DEPARTURE                    = 0x1
-	IFF_ALLMULTI                      = 0x200
-	IFF_ALTPHYS                       = 0x4000
-	IFF_BROADCAST                     = 0x2
-	IFF_CANTCHANGE                    = 0x118e72
-	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_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
-	IFT_A12MPPSWITCH                  = 0x82
-	IFT_AAL2                          = 0xbb
-	IFT_AAL5                          = 0x31
-	IFT_ADSL                          = 0x5e
-	IFT_AFLANE8023                    = 0x3b
-	IFT_AFLANE8025                    = 0x3c
-	IFT_ARAP                          = 0x58
-	IFT_ARCNET                        = 0x23
-	IFT_ARCNETPLUS                    = 0x24
-	IFT_ASYNC                         = 0x54
-	IFT_ATM                           = 0x25
-	IFT_ATMDXI                        = 0x69
-	IFT_ATMFUNI                       = 0x6a
-	IFT_ATMIMA                        = 0x6b
-	IFT_ATMLOGICAL                    = 0x50
-	IFT_ATMRADIO                      = 0xbd
-	IFT_ATMSUBINTERFACE               = 0x86
-	IFT_ATMVCIENDPT                   = 0xc2
-	IFT_ATMVIRTUAL                    = 0x95
-	IFT_BGPPOLICYACCOUNTING           = 0xa2
-	IFT_BRIDGE                        = 0xd1
-	IFT_BSC                           = 0x53
-	IFT_CARP                          = 0xf8
-	IFT_CCTEMUL                       = 0x3d
-	IFT_CEPT                          = 0x13
-	IFT_CES                           = 0x85
-	IFT_CHANNEL                       = 0x46
-	IFT_CNR                           = 0x55
-	IFT_COFFEE                        = 0x84
-	IFT_COMPOSITELINK                 = 0x9b
-	IFT_DCN                           = 0x8d
-	IFT_DIGITALPOWERLINE              = 0x8a
-	IFT_DIGITALWRAPPEROVERHEADCHANNEL = 0xba
-	IFT_DLSW                          = 0x4a
-	IFT_DOCSCABLEDOWNSTREAM           = 0x80
-	IFT_DOCSCABLEMACLAYER             = 0x7f
-	IFT_DOCSCABLEUPSTREAM             = 0x81
-	IFT_DS0                           = 0x51
-	IFT_DS0BUNDLE                     = 0x52
-	IFT_DS1FDL                        = 0xaa
-	IFT_DS3                           = 0x1e
-	IFT_DTM                           = 0x8c
-	IFT_DVBASILN                      = 0xac
-	IFT_DVBASIOUT                     = 0xad
-	IFT_DVBRCCDOWNSTREAM              = 0x93
-	IFT_DVBRCCMACLAYER                = 0x92
-	IFT_DVBRCCUPSTREAM                = 0x94
-	IFT_ENC                           = 0xf4
-	IFT_EON                           = 0x19
-	IFT_EPLRS                         = 0x57
-	IFT_ESCON                         = 0x49
-	IFT_ETHER                         = 0x6
-	IFT_FAITH                         = 0xf2
-	IFT_FAST                          = 0x7d
-	IFT_FASTETHER                     = 0x3e
-	IFT_FASTETHERFX                   = 0x45
-	IFT_FDDI                          = 0xf
-	IFT_FIBRECHANNEL                  = 0x38
-	IFT_FRAMERELAYINTERCONNECT        = 0x3a
-	IFT_FRAMERELAYMPI                 = 0x5c
-	IFT_FRDLCIENDPT                   = 0xc1
-	IFT_FRELAY                        = 0x20
-	IFT_FRELAYDCE                     = 0x2c
-	IFT_FRF16MFRBUNDLE                = 0xa3
-	IFT_FRFORWARD                     = 0x9e
-	IFT_G703AT2MB                     = 0x43
-	IFT_G703AT64K                     = 0x42
-	IFT_GIF                           = 0xf0
-	IFT_GIGABITETHERNET               = 0x75
-	IFT_GR303IDT                      = 0xb2
-	IFT_GR303RDT                      = 0xb1
-	IFT_H323GATEKEEPER                = 0xa4
-	IFT_H323PROXY                     = 0xa5
-	IFT_HDH1822                       = 0x3
-	IFT_HDLC                          = 0x76
-	IFT_HDSL2                         = 0xa8
-	IFT_HIPERLAN2                     = 0xb7
-	IFT_HIPPI                         = 0x2f
-	IFT_HIPPIINTERFACE                = 0x39
-	IFT_HOSTPAD                       = 0x5a
-	IFT_HSSI                          = 0x2e
-	IFT_HY                            = 0xe
-	IFT_IBM370PARCHAN                 = 0x48
-	IFT_IDSL                          = 0x9a
-	IFT_IEEE1394                      = 0x90
-	IFT_IEEE80211                     = 0x47
-	IFT_IEEE80212                     = 0x37
-	IFT_IEEE8023ADLAG                 = 0xa1
-	IFT_IFGSN                         = 0x91
-	IFT_IMT                           = 0xbe
-	IFT_INTERLEAVE                    = 0x7c
-	IFT_IP                            = 0x7e
-	IFT_IPFORWARD                     = 0x8e
-	IFT_IPOVERATM                     = 0x72
-	IFT_IPOVERCDLC                    = 0x6d
-	IFT_IPOVERCLAW                    = 0x6e
-	IFT_IPSWITCH                      = 0x4e
-	IFT_ISDN                          = 0x3f
-	IFT_ISDNBASIC                     = 0x14
-	IFT_ISDNPRIMARY                   = 0x15
-	IFT_ISDNS                         = 0x4b
-	IFT_ISDNU                         = 0x4c
-	IFT_ISO88022LLC                   = 0x29
-	IFT_ISO88023                      = 0x7
-	IFT_ISO88024                      = 0x8
-	IFT_ISO88025                      = 0x9
-	IFT_ISO88025CRFPINT               = 0x62
-	IFT_ISO88025DTR                   = 0x56
-	IFT_ISO88025FIBER                 = 0x73
-	IFT_ISO88026                      = 0xa
-	IFT_ISUP                          = 0xb3
-	IFT_L2VLAN                        = 0x87
-	IFT_L3IPVLAN                      = 0x88
-	IFT_L3IPXVLAN                     = 0x89
-	IFT_LAPB                          = 0x10
-	IFT_LAPD                          = 0x4d
-	IFT_LAPF                          = 0x77
-	IFT_LOCALTALK                     = 0x2a
-	IFT_LOOP                          = 0x18
-	IFT_MEDIAMAILOVERIP               = 0x8b
-	IFT_MFSIGLINK                     = 0xa7
-	IFT_MIOX25                        = 0x26
-	IFT_MODEM                         = 0x30
-	IFT_MPC                           = 0x71
-	IFT_MPLS                          = 0xa6
-	IFT_MPLSTUNNEL                    = 0x96
-	IFT_MSDSL                         = 0x8f
-	IFT_MVL                           = 0xbf
-	IFT_MYRINET                       = 0x63
-	IFT_NFAS                          = 0xaf
-	IFT_NSIP                          = 0x1b
-	IFT_OPTICALCHANNEL                = 0xc3
-	IFT_OPTICALTRANSPORT              = 0xc4
-	IFT_OTHER                         = 0x1
-	IFT_P10                           = 0xc
-	IFT_P80                           = 0xd
-	IFT_PARA                          = 0x22
-	IFT_PFLOG                         = 0xf5
-	IFT_PFSYNC                        = 0xf6
-	IFT_PLC                           = 0xae
-	IFT_POS                           = 0xab
-	IFT_PPP                           = 0x17
-	IFT_PPPMULTILINKBUNDLE            = 0x6c
-	IFT_PROPBWAP2MP                   = 0xb8
-	IFT_PROPCNLS                      = 0x59
-	IFT_PROPDOCSWIRELESSDOWNSTREAM    = 0xb5
-	IFT_PROPDOCSWIRELESSMACLAYER      = 0xb4
-	IFT_PROPDOCSWIRELESSUPSTREAM      = 0xb6
-	IFT_PROPMUX                       = 0x36
-	IFT_PROPVIRTUAL                   = 0x35
-	IFT_PROPWIRELESSP2P               = 0x9d
-	IFT_PTPSERIAL                     = 0x16
-	IFT_PVC                           = 0xf1
-	IFT_QLLC                          = 0x44
-	IFT_RADIOMAC                      = 0xbc
-	IFT_RADSL                         = 0x5f
-	IFT_REACHDSL                      = 0xc0
-	IFT_RFC1483                       = 0x9f
-	IFT_RS232                         = 0x21
-	IFT_RSRB                          = 0x4f
-	IFT_SDLC                          = 0x11
-	IFT_SDSL                          = 0x60
-	IFT_SHDSL                         = 0xa9
-	IFT_SIP                           = 0x1f
-	IFT_SLIP                          = 0x1c
-	IFT_SMDSDXI                       = 0x2b
-	IFT_SMDSICIP                      = 0x34
-	IFT_SONET                         = 0x27
-	IFT_SONETOVERHEADCHANNEL          = 0xb9
-	IFT_SONETPATH                     = 0x32
-	IFT_SONETVT                       = 0x33
-	IFT_SRP                           = 0x97
-	IFT_SS7SIGLINK                    = 0x9c
-	IFT_STACKTOSTACK                  = 0x6f
-	IFT_STARLAN                       = 0xb
-	IFT_STF                           = 0xf3
-	IFT_T1                            = 0x12
-	IFT_TDLC                          = 0x74
-	IFT_TERMPAD                       = 0x5b
-	IFT_TR008                         = 0xb0
-	IFT_TRANSPHDLC                    = 0x7b
-	IFT_TUNNEL                        = 0x83
-	IFT_ULTRA                         = 0x1d
-	IFT_USB                           = 0xa0
-	IFT_V11                           = 0x40
-	IFT_V35                           = 0x2d
-	IFT_V36                           = 0x41
-	IFT_V37                           = 0x78
-	IFT_VDSL                          = 0x61
-	IFT_VIRTUALIPADDRESS              = 0x70
-	IFT_VOICEEM                       = 0x64
-	IFT_VOICEENCAP                    = 0x67
-	IFT_VOICEFXO                      = 0x65
-	IFT_VOICEFXS                      = 0x66
-	IFT_VOICEOVERATM                  = 0x98
-	IFT_VOICEOVERFRAMERELAY           = 0x99
-	IFT_VOICEOVERIP                   = 0x68
-	IFT_X213                          = 0x5d
-	IFT_X25                           = 0x5
-	IFT_X25DDN                        = 0x4
-	IFT_X25HUNTGROUP                  = 0x7a
-	IFT_X25MLP                        = 0x79
-	IFT_X25PLE                        = 0x28
-	IFT_XETHER                        = 0x1a
-	IGNBRK                            = 0x1
-	IGNCR                             = 0x80
-	IGNPAR                            = 0x4
-	IMAXBEL                           = 0x2000
-	INLCR                             = 0x40
-	INPCK                             = 0x10
-	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_CLASSD_HOST                    = 0xfffffff
-	IN_CLASSD_NET                     = 0xf0000000
-	IN_CLASSD_NSHIFT                  = 0x1c
-	IN_LOOPBACKNET                    = 0x7f
-	IPPROTO_3PC                       = 0x22
-	IPPROTO_ADFS                      = 0x44
-	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_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_MOBILE                    = 0x37
-	IPPROTO_MTP                       = 0x5c
-	IPPROTO_MUX                       = 0x12
-	IPPROTO_ND                        = 0x4d
-	IPPROTO_NHRP                      = 0x36
-	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_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_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_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_PATHMTU                      = 0x2c
-	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_RECVHOPLIMIT                 = 0x25
-	IPV6_RECVHOPOPTS                  = 0x27
-	IPV6_RECVPATHMTU                  = 0x2b
-	IPV6_RECVPKTINFO                  = 0x24
-	IPV6_RECVRTHDR                    = 0x26
-	IPV6_RECVTCLASS                   = 0x39
-	IPV6_RTHDR                        = 0x33
-	IPV6_RTHDRDSTOPTS                 = 0x23
-	IPV6_RTHDR_LOOSE                  = 0x0
-	IPV6_RTHDR_STRICT                 = 0x1
-	IPV6_RTHDR_TYPE_0                 = 0x0
-	IPV6_SOCKOPT_RESERVED1            = 0x3
-	IPV6_TCLASS                       = 0x3d
-	IPV6_UNICAST_HOPS                 = 0x4
-	IPV6_USE_MIN_MTU                  = 0x2a
-	IPV6_V6ONLY                       = 0x1b
-	IPV6_VERSION                      = 0x60
-	IPV6_VERSION_MASK                 = 0xf0
-	IP_ADD_MEMBERSHIP                 = 0xc
-	IP_DEFAULT_MULTICAST_LOOP         = 0x1
-	IP_DEFAULT_MULTICAST_TTL          = 0x1
-	IP_DF                             = 0x4000
-	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_HDRINCL                        = 0x2
-	IP_IPSEC_POLICY                   = 0x15
-	IP_MAXPACKET                      = 0xffff
-	IP_MAX_MEMBERSHIPS                = 0x14
-	IP_MF                             = 0x2000
-	IP_MINTTL                         = 0x42
-	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_PORTRANGE                      = 0x13
-	IP_PORTRANGE_DEFAULT              = 0x0
-	IP_PORTRANGE_HIGH                 = 0x1
-	IP_PORTRANGE_LOW                  = 0x2
-	IP_RECVDSTADDR                    = 0x7
-	IP_RECVIF                         = 0x14
-	IP_RECVOPTS                       = 0x5
-	IP_RECVRETOPTS                    = 0x6
-	IP_RECVTTL                        = 0x41
-	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_TOS                            = 0x3
-	IP_TTL                            = 0x4
-	ISIG                              = 0x80
-	ISTRIP                            = 0x20
-	IXANY                             = 0x800
-	IXOFF                             = 0x400
-	IXON                              = 0x200
-	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_NORMAL                       = 0x0
-	MADV_NOSYNC                       = 0x6
-	MADV_RANDOM                       = 0x1
-	MADV_SEQUENTIAL                   = 0x2
-	MADV_SETMAP                       = 0xb
-	MADV_WILLNEED                     = 0x3
-	MAP_ANON                          = 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_PRIVATE                       = 0x2
-	MAP_RENAME                        = 0x20
-	MAP_SHARED                        = 0x1
-	MAP_SIZEALIGN                     = 0x40000
-	MAP_STACK                         = 0x400
-	MAP_TRYFIXED                      = 0x10000
-	MAP_VPAGETABLE                    = 0x2000
-	MCL_CURRENT                       = 0x1
-	MCL_FUTURE                        = 0x2
-	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_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
-	NAME_MAX                          = 0xff
-	NET_RT_DUMP                       = 0x1
-	NET_RT_FLAGS                      = 0x2
-	NET_RT_IFLIST                     = 0x3
-	NET_RT_MAXID                      = 0x4
-	NOFLSH                            = 0x80000000
-	NOTE_ATTRIB                       = 0x8
-	NOTE_CHILD                        = 0x4
-	NOTE_DELETE                       = 0x1
-	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_WRITE                        = 0x2
-	OCRNL                             = 0x10
-	ONLCR                             = 0x2
-	ONLRET                            = 0x40
-	ONOCR                             = 0x20
-	ONOEOT                            = 0x8
-	OPOST                             = 0x1
-	O_ACCMODE                         = 0x3
-	O_APPEND                          = 0x8
-	O_ASYNC                           = 0x40
-	O_CLOEXEC                         = 0x20000
-	O_CREAT                           = 0x200
-	O_DIRECT                          = 0x10000
-	O_DIRECTORY                       = 0x8000000
-	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_SHLOCK                          = 0x10
-	O_SYNC                            = 0x80
-	O_TRUNC                           = 0x400
-	O_WRONLY                          = 0x1
-	PARENB                            = 0x1000
-	PARMRK                            = 0x8
-	PARODD                            = 0x2000
-	PENDIN                            = 0x20000000
-	PRIO_PGRP                         = 0x1
-	PRIO_PROCESS                      = 0x0
-	PRIO_USER                         = 0x2
-	PROT_EXEC                         = 0x4
-	PROT_NONE                         = 0x0
-	PROT_READ                         = 0x1
-	PROT_WRITE                        = 0x2
-	RLIMIT_AS                         = 0xa
-	RLIMIT_CORE                       = 0x4
-	RLIMIT_CPU                        = 0x0
-	RLIMIT_DATA                       = 0x2
-	RLIMIT_FSIZE                      = 0x1
-	RLIMIT_NOFILE                     = 0x8
-	RLIMIT_STACK                      = 0x3
-	RLIM_INFINITY                     = 0x7fffffffffffffff
-	RTAX_AUTHOR                       = 0x6
-	RTAX_BRD                          = 0x7
-	RTAX_DST                          = 0x0
-	RTAX_GATEWAY                      = 0x1
-	RTAX_GENMASK                      = 0x3
-	RTAX_IFA                          = 0x5
-	RTAX_IFP                          = 0x4
-	RTAX_MAX                          = 0xb
-	RTAX_MPLS1                        = 0x8
-	RTAX_MPLS2                        = 0x9
-	RTAX_MPLS3                        = 0xa
-	RTAX_NETMASK                      = 0x2
-	RTA_AUTHOR                        = 0x40
-	RTA_BRD                           = 0x80
-	RTA_DST                           = 0x1
-	RTA_GATEWAY                       = 0x2
-	RTA_GENMASK                       = 0x8
-	RTA_IFA                           = 0x20
-	RTA_IFP                           = 0x10
-	RTA_MPLS1                         = 0x100
-	RTA_MPLS2                         = 0x200
-	RTA_MPLS3                         = 0x400
-	RTA_NETMASK                       = 0x4
-	RTF_BLACKHOLE                     = 0x1000
-	RTF_BROADCAST                     = 0x400000
-	RTF_CLONING                       = 0x100
-	RTF_DONE                          = 0x40
-	RTF_DYNAMIC                       = 0x10
-	RTF_GATEWAY                       = 0x2
-	RTF_HOST                          = 0x4
-	RTF_LLINFO                        = 0x400
-	RTF_LOCAL                         = 0x200000
-	RTF_MODIFIED                      = 0x20
-	RTF_MPLSOPS                       = 0x1000000
-	RTF_MULTICAST                     = 0x800000
-	RTF_PINNED                        = 0x100000
-	RTF_PRCLONING                     = 0x10000
-	RTF_PROTO1                        = 0x8000
-	RTF_PROTO2                        = 0x4000
-	RTF_PROTO3                        = 0x40000
-	RTF_REJECT                        = 0x8
-	RTF_STATIC                        = 0x800
-	RTF_UP                            = 0x1
-	RTF_WASCLONED                     = 0x20000
-	RTF_XRESOLVE                      = 0x200
-	RTM_ADD                           = 0x1
-	RTM_CHANGE                        = 0x3
-	RTM_DELADDR                       = 0xd
-	RTM_DELETE                        = 0x2
-	RTM_DELMADDR                      = 0x10
-	RTM_GET                           = 0x4
-	RTM_IEEE80211                     = 0x12
-	RTM_IFANNOUNCE                    = 0x11
-	RTM_IFINFO                        = 0xe
-	RTM_LOCK                          = 0x8
-	RTM_LOSING                        = 0x5
-	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
-	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
-	RUSAGE_CHILDREN                   = -0x1
-	RUSAGE_SELF                       = 0x0
-	SCM_CREDS                         = 0x3
-	SCM_RIGHTS                        = 0x1
-	SCM_TIMESTAMP                     = 0x2
-	SHUT_RD                           = 0x0
-	SHUT_RDWR                         = 0x2
-	SHUT_WR                           = 0x1
-	SIOCADDMULTI                      = 0x80206931
-	SIOCADDRT                         = 0x8030720a
-	SIOCAIFADDR                       = 0x8040691a
-	SIOCALIFADDR                      = 0x8118691b
-	SIOCATMARK                        = 0x40047307
-	SIOCDELMULTI                      = 0x80206932
-	SIOCDELRT                         = 0x8030720b
-	SIOCDIFADDR                       = 0x80206919
-	SIOCDIFPHYADDR                    = 0x80206949
-	SIOCDLIFADDR                      = 0x8118691d
-	SIOCGDRVSPEC                      = 0xc01c697b
-	SIOCGETSGCNT                      = 0xc0147210
-	SIOCGETVIFCNT                     = 0xc014720f
-	SIOCGHIWAT                        = 0x40047301
-	SIOCGIFADDR                       = 0xc0206921
-	SIOCGIFBRDADDR                    = 0xc0206923
-	SIOCGIFCAP                        = 0xc020691f
-	SIOCGIFCONF                       = 0xc0086924
-	SIOCGIFDATA                       = 0xc0206926
-	SIOCGIFDSTADDR                    = 0xc0206922
-	SIOCGIFFLAGS                      = 0xc0206911
-	SIOCGIFGENERIC                    = 0xc020693a
-	SIOCGIFGMEMB                      = 0xc024698a
-	SIOCGIFINDEX                      = 0xc0206920
-	SIOCGIFMEDIA                      = 0xc0286938
-	SIOCGIFMETRIC                     = 0xc0206917
-	SIOCGIFMTU                        = 0xc0206933
-	SIOCGIFNETMASK                    = 0xc0206925
-	SIOCGIFPDSTADDR                   = 0xc0206948
-	SIOCGIFPHYS                       = 0xc0206935
-	SIOCGIFPOLLCPU                    = 0xc020697e
-	SIOCGIFPSRCADDR                   = 0xc0206947
-	SIOCGIFSTATUS                     = 0xc331693b
-	SIOCGIFTSOLEN                     = 0xc0206980
-	SIOCGLIFADDR                      = 0xc118691c
-	SIOCGLIFPHYADDR                   = 0xc118694b
-	SIOCGLOWAT                        = 0x40047303
-	SIOCGPGRP                         = 0x40047309
-	SIOCGPRIVATE_0                    = 0xc0206950
-	SIOCGPRIVATE_1                    = 0xc0206951
-	SIOCIFCREATE                      = 0xc020697a
-	SIOCIFCREATE2                     = 0xc020697c
-	SIOCIFDESTROY                     = 0x80206979
-	SIOCIFGCLONERS                    = 0xc00c6978
-	SIOCSDRVSPEC                      = 0x801c697b
-	SIOCSHIWAT                        = 0x80047300
-	SIOCSIFADDR                       = 0x8020690c
-	SIOCSIFBRDADDR                    = 0x80206913
-	SIOCSIFCAP                        = 0x8020691e
-	SIOCSIFDSTADDR                    = 0x8020690e
-	SIOCSIFFLAGS                      = 0x80206910
-	SIOCSIFGENERIC                    = 0x80206939
-	SIOCSIFLLADDR                     = 0x8020693c
-	SIOCSIFMEDIA                      = 0xc0206937
-	SIOCSIFMETRIC                     = 0x80206918
-	SIOCSIFMTU                        = 0x80206934
-	SIOCSIFNAME                       = 0x80206928
-	SIOCSIFNETMASK                    = 0x80206916
-	SIOCSIFPHYADDR                    = 0x80406946
-	SIOCSIFPHYS                       = 0x80206936
-	SIOCSIFPOLLCPU                    = 0x8020697d
-	SIOCSIFTSOLEN                     = 0x8020697f
-	SIOCSLIFPHYADDR                   = 0x8118694a
-	SIOCSLOWAT                        = 0x80047302
-	SIOCSPGRP                         = 0x80047308
-	SOCK_DGRAM                        = 0x2
-	SOCK_MAXADDRLEN                   = 0xff
-	SOCK_RAW                          = 0x3
-	SOCK_RDM                          = 0x4
-	SOCK_SEQPACKET                    = 0x5
-	SOCK_STREAM                       = 0x1
-	SOL_SOCKET                        = 0xffff
-	SOMAXCONN                         = 0x80
-	SO_ACCEPTCONN                     = 0x2
-	SO_ACCEPTFILTER                   = 0x1000
-	SO_BROADCAST                      = 0x20
-	SO_DEBUG                          = 0x1
-	SO_DONTROUTE                      = 0x10
-	SO_ERROR                          = 0x1007
-	SO_KEEPALIVE                      = 0x8
-	SO_LINGER                         = 0x80
-	SO_NOSIGPIPE                      = 0x800
-	SO_OOBINLINE                      = 0x100
-	SO_RCVBUF                         = 0x1002
-	SO_RCVLOWAT                       = 0x1004
-	SO_RCVTIMEO                       = 0x1006
-	SO_REUSEADDR                      = 0x4
-	SO_REUSEPORT                      = 0x200
-	SO_SNDBUF                         = 0x1001
-	SO_SNDLOWAT                       = 0x1003
-	SO_SNDSPACE                       = 0x100a
-	SO_SNDTIMEO                       = 0x1005
-	SO_TIMESTAMP                      = 0x400
-	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_WINSHIFT                  = 0xe
-	TCP_MINMSS                        = 0x100
-	TCP_MIN_WINSHIFT                  = 0x5
-	TCP_MSS                           = 0x200
-	TCP_NODELAY                       = 0x1
-	TCP_NOOPT                         = 0x8
-	TCP_NOPUSH                        = 0x4
-	TCP_SIGNATURE_ENABLE              = 0x10
-	TCSAFLUSH                         = 0x2
-	TIOCCBRK                          = 0x2000747a
-	TIOCCDTR                          = 0x20007478
-	TIOCCONS                          = 0x80047462
-	TIOCDCDTIMESTAMP                  = 0x40087458
-	TIOCDRAIN                         = 0x2000745e
-	TIOCEXCL                          = 0x2000740d
-	TIOCEXT                           = 0x80047460
-	TIOCFLUSH                         = 0x80047410
-	TIOCGDRAINWAIT                    = 0x40047456
-	TIOCGETA                          = 0x402c7413
-	TIOCGETD                          = 0x4004741a
-	TIOCGPGRP                         = 0x40047477
-	TIOCGSID                          = 0x40047463
-	TIOCGSIZE                         = 0x40087468
-	TIOCGWINSZ                        = 0x40087468
-	TIOCISPTMASTER                    = 0x20007455
-	TIOCMBIC                          = 0x8004746b
-	TIOCMBIS                          = 0x8004746c
-	TIOCMGDTRWAIT                     = 0x4004745a
-	TIOCMGET                          = 0x4004746a
-	TIOCMODG                          = 0x40047403
-	TIOCMODS                          = 0x80047404
-	TIOCMSDTRWAIT                     = 0x8004745b
-	TIOCMSET                          = 0x8004746d
-	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                         = 0x20007471
-	TIOCNXCL                          = 0x2000740e
-	TIOCOUTQ                          = 0x40047473
-	TIOCPKT                           = 0x80047470
-	TIOCPKT_DATA                      = 0x0
-	TIOCPKT_DOSTOP                    = 0x20
-	TIOCPKT_FLUSHREAD                 = 0x1
-	TIOCPKT_FLUSHWRITE                = 0x2
-	TIOCPKT_IOCTL                     = 0x40
-	TIOCPKT_NOSTOP                    = 0x10
-	TIOCPKT_START                     = 0x8
-	TIOCPKT_STOP                      = 0x4
-	TIOCREMOTE                        = 0x80047469
-	TIOCSBRK                          = 0x2000747b
-	TIOCSCTTY                         = 0x20007461
-	TIOCSDRAINWAIT                    = 0x80047457
-	TIOCSDTR                          = 0x20007479
-	TIOCSETA                          = 0x802c7414
-	TIOCSETAF                         = 0x802c7416
-	TIOCSETAW                         = 0x802c7415
-	TIOCSETD                          = 0x8004741b
-	TIOCSIG                           = 0x2000745f
-	TIOCSPGRP                         = 0x80047476
-	TIOCSSIZE                         = 0x80087467
-	TIOCSTART                         = 0x2000746e
-	TIOCSTAT                          = 0x20007465
-	TIOCSTI                           = 0x80017472
-	TIOCSTOP                          = 0x2000746f
-	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
-	VMIN                              = 0x10
-	VQUIT                             = 0x9
-	VREPRINT                          = 0x6
-	VSTART                            = 0xc
-	VSTATUS                           = 0x12
-	VSTOP                             = 0xd
-	VSUSP                             = 0xa
-	VTIME                             = 0x11
-	VWERASE                           = 0x4
-	WCONTINUED                        = 0x4
-	WCOREFLAG                         = 0x80
-	WLINUXCLONE                       = 0x80000000
-	WNOHANG                           = 0x1
-	WSTOPPED                          = 0x7f
-	WUNTRACED                         = 0x2
-)
-
-// Errors
-const (
-	E2BIG           = Errno(0x7)
-	EACCES          = Errno(0xd)
-	EADDRINUSE      = Errno(0x30)
-	EADDRNOTAVAIL   = Errno(0x31)
-	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)
-	ECHILD          = Errno(0xa)
-	ECONNABORTED    = Errno(0x35)
-	ECONNREFUSED    = Errno(0x3d)
-	ECONNRESET      = Errno(0x36)
-	EDEADLK         = Errno(0xb)
-	EDESTADDRREQ    = Errno(0x27)
-	EDOM            = Errno(0x21)
-	EDOOFUS         = Errno(0x58)
-	EDQUOT          = Errno(0x45)
-	EEXIST          = Errno(0x11)
-	EFAULT          = Errno(0xe)
-	EFBIG           = Errno(0x1b)
-	EFTYPE          = Errno(0x4f)
-	EHOSTDOWN       = Errno(0x40)
-	EHOSTUNREACH    = Errno(0x41)
-	EIDRM           = Errno(0x52)
-	EILSEQ          = Errno(0x56)
-	EINPROGRESS     = Errno(0x24)
-	EINTR           = Errno(0x4)
-	EINVAL          = Errno(0x16)
-	EIO             = Errno(0x5)
-	EISCONN         = Errno(0x38)
-	EISDIR          = Errno(0x15)
-	ELAST           = Errno(0x63)
-	ELOOP           = Errno(0x3e)
-	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)
-	ENOBUFS         = Errno(0x37)
-	ENODEV          = Errno(0x13)
-	ENOENT          = Errno(0x2)
-	ENOEXEC         = Errno(0x8)
-	ENOLCK          = Errno(0x4d)
-	ENOLINK         = Errno(0x5b)
-	ENOMEDIUM       = Errno(0x5d)
-	ENOMEM          = Errno(0xc)
-	ENOMSG          = Errno(0x53)
-	ENOPROTOOPT     = Errno(0x2a)
-	ENOSPC          = Errno(0x1c)
-	ENOSYS          = Errno(0x4e)
-	ENOTBLK         = Errno(0xf)
-	ENOTCONN        = Errno(0x39)
-	ENOTDIR         = Errno(0x14)
-	ENOTEMPTY       = Errno(0x42)
-	ENOTSOCK        = Errno(0x26)
-	ENOTSUP         = Errno(0x2d)
-	ENOTTY          = Errno(0x19)
-	ENXIO           = Errno(0x6)
-	EOPNOTSUPP      = Errno(0x2d)
-	EOVERFLOW       = Errno(0x54)
-	EPERM           = Errno(0x1)
-	EPFNOSUPPORT    = Errno(0x2e)
-	EPIPE           = Errno(0x20)
-	EPROCLIM        = Errno(0x43)
-	EPROCUNAVAIL    = Errno(0x4c)
-	EPROGMISMATCH   = Errno(0x4b)
-	EPROGUNAVAIL    = Errno(0x4a)
-	EPROTO          = Errno(0x5c)
-	EPROTONOSUPPORT = Errno(0x2b)
-	EPROTOTYPE      = Errno(0x29)
-	ERANGE          = Errno(0x22)
-	EREMOTE         = Errno(0x47)
-	EROFS           = Errno(0x1e)
-	ERPCMISMATCH    = Errno(0x49)
-	ESHUTDOWN       = Errno(0x3a)
-	ESOCKTNOSUPPORT = Errno(0x2c)
-	ESPIPE          = Errno(0x1d)
-	ESRCH           = Errno(0x3)
-	ESTALE          = Errno(0x46)
-	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)
-)
-
-// 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)
-)
-
-// 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:  "device not configured",
-	7:  "argument list too long",
-	8:  "exec format error",
-	9:  "bad file descriptor",
-	10: "no child processes",
-	11: "resource deadlock avoided",
-	12: "cannot allocate memory",
-	13: "permission denied",
-	14: "bad address",
-	15: "block device required",
-	16: "device busy",
-	17: "file exists",
-	18: "cross-device link",
-	19: "operation not supported by 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: "result too large",
-	35: "resource temporarily unavailable",
-	36: "operation now in progress",
-	37: "operation already in progress",
-	38: "socket operation on non-socket",
-	39: "destination address required",
-	40: "message too long",
-	41: "protocol wrong type for socket",
-	42: "protocol not available",
-	43: "protocol not supported",
-	44: "socket type not supported",
-	45: "operation not supported",
-	46: "protocol family not supported",
-	47: "address family not supported by protocol family",
-	48: "address already in use",
-	49: "can't assign requested address",
-	50: "network is down",
-	51: "network is unreachable",
-	52: "network dropped connection on reset",
-	53: "software caused connection abort",
-	54: "connection reset by peer",
-	55: "no buffer space available",
-	56: "socket is already connected",
-	57: "socket is not connected",
-	58: "can't send after socket shutdown",
-	59: "too many references: can't splice",
-	60: "operation timed out",
-	61: "connection refused",
-	62: "too many levels of symbolic links",
-	63: "file name too long",
-	64: "host is down",
-	65: "no route to host",
-	66: "directory not empty",
-	67: "too many processes",
-	68: "too many users",
-	69: "disc quota exceeded",
-	70: "stale NFS file handle",
-	71: "too many levels of remote in path",
-	72: "RPC struct is bad",
-	73: "RPC version wrong",
-	74: "RPC prog. not avail",
-	75: "program version wrong",
-	76: "bad procedure for program",
-	77: "no locks available",
-	78: "function not implemented",
-	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",
-}
-
-// Signal table
-var signals = [...]string{
-	1:  "hangup",
-	2:  "interrupt",
-	3:  "quit",
-	4:  "illegal instruction",
-	5:  "trace/BPT trap",
-	6:  "abort trap",
-	7:  "EMT trap",
-	8:  "floating point exception",
-	9:  "killed",
-	10: "bus error",
-	11: "segmentation fault",
-	12: "bad system call",
-	13: "broken pipe",
-	14: "alarm clock",
-	15: "terminated",
-	16: "urgent I/O condition",
-	17: "suspended (signal)",
-	18: "suspended",
-	19: "continued",
-	20: "child exited",
-	21: "stopped (tty input)",
-	22: "stopped (tty output)",
-	23: "I/O possible",
-	24: "cputime limit exceeded",
-	25: "filesize limit exceeded",
-	26: "virtual timer expired",
-	27: "profiling timer expired",
-	28: "window size changes",
-	29: "information request",
-	30: "user defined signal 1",
-	31: "user defined signal 2",
-	32: "thread Scheduler",
-	33: "checkPoint",
-	34: "checkPointExit",
-}
diff --git a/src/syscall/zerrors_dragonfly_amd64.go b/src/syscall/zerrors_dragonfly_amd64.go
index 59bff75..15d300f 100644
--- a/src/syscall/zerrors_dragonfly_amd64.go
+++ b/src/syscall/zerrors_dragonfly_amd64.go
@@ -4,6 +4,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- -m64 _const.go
 
+// +build amd64,dragonfly
+
 package syscall
 
 const (
diff --git a/src/syscall/zerrors_freebsd_386.go b/src/syscall/zerrors_freebsd_386.go
index cd3aa80..bbad05f 100644
--- a/src/syscall/zerrors_freebsd_386.go
+++ b/src/syscall/zerrors_freebsd_386.go
@@ -4,6 +4,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- -m32 _const.go
 
+// +build 386,freebsd
+
 package syscall
 
 const (
diff --git a/src/syscall/zerrors_freebsd_amd64.go b/src/syscall/zerrors_freebsd_amd64.go
index 9edce6e..b36125b 100644
--- a/src/syscall/zerrors_freebsd_amd64.go
+++ b/src/syscall/zerrors_freebsd_amd64.go
@@ -4,6 +4,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- -m64 _const.go
 
+// +build amd64,freebsd
+
 package syscall
 
 const (
diff --git a/src/syscall/zerrors_freebsd_arm.go b/src/syscall/zerrors_freebsd_arm.go
index f29dd05..0c844f1 100644
--- a/src/syscall/zerrors_freebsd_arm.go
+++ b/src/syscall/zerrors_freebsd_arm.go
@@ -4,6 +4,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- _const.go
 
+// +build arm,freebsd
+
 package syscall
 
 const (
diff --git a/src/syscall/zerrors_linux_386.go b/src/syscall/zerrors_linux_386.go
index 7aa8ff0..d433a4f 100644
--- a/src/syscall/zerrors_linux_386.go
+++ b/src/syscall/zerrors_linux_386.go
@@ -4,6 +4,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- -m32 _const.go
 
+// +build 386,linux
+
 package syscall
 
 const (
diff --git a/src/syscall/zerrors_linux_amd64.go b/src/syscall/zerrors_linux_amd64.go
index 94d051d..dd86a3b 100644
--- a/src/syscall/zerrors_linux_amd64.go
+++ b/src/syscall/zerrors_linux_amd64.go
@@ -4,6 +4,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- -m64 _const.go
 
+// +build amd64,linux
+
 package syscall
 
 const (
diff --git a/src/syscall/zerrors_linux_arm.go b/src/syscall/zerrors_linux_arm.go
index dcaaef7..2a9c0f9 100644
--- a/src/syscall/zerrors_linux_arm.go
+++ b/src/syscall/zerrors_linux_arm.go
@@ -4,6 +4,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- _const.go
 
+// +build arm,linux
+
 package syscall
 
 const (
diff --git a/src/syscall/zerrors_linux_arm64.go b/src/syscall/zerrors_linux_arm64.go
new file mode 100644
index 0000000..35d9ace
--- /dev/null
+++ b/src/syscall/zerrors_linux_arm64.go
@@ -0,0 +1,1824 @@
+// mkerrors.sh
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs -- _const.go
+
+// +build arm64,linux
+
+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_linux_ppc64.go b/src/syscall/zerrors_linux_ppc64.go
new file mode 100644
index 0000000..1c769cd
--- /dev/null
+++ b/src/syscall/zerrors_linux_ppc64.go
@@ -0,0 +1,1880 @@
+// mkerrors.sh -m64
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs -- -m64 _const.go
+
+// +build ppc64,linux
+
+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                           = 0x28
+	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_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                         = 0x17
+	B110                             = 0x3
+	B115200                          = 0x11
+	B1152000                         = 0x18
+	B1200                            = 0x9
+	B134                             = 0x4
+	B150                             = 0x5
+	B1500000                         = 0x19
+	B1800                            = 0xa
+	B19200                           = 0xe
+	B200                             = 0x6
+	B2000000                         = 0x1a
+	B230400                          = 0x12
+	B2400                            = 0xb
+	B2500000                         = 0x1b
+	B300                             = 0x7
+	B3000000                         = 0x1c
+	B3500000                         = 0x1d
+	B38400                           = 0xf
+	B4000000                         = 0x1e
+	B460800                          = 0x13
+	B4800                            = 0xc
+	B50                              = 0x1
+	B500000                          = 0x14
+	B57600                           = 0x10
+	B576000                          = 0x15
+	B600                             = 0x8
+	B75                              = 0x2
+	B921600                          = 0x16
+	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                           = 0x8000
+	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                            = 0x800
+	CS5                              = 0x0
+	CS6                              = 0x100
+	CS7                              = 0x200
+	CS8                              = 0x300
+	CSIGNAL                          = 0xff
+	CSIZE                            = 0x300
+	CSTART                           = 0x11
+	CSTATUS                          = 0x0
+	CSTOP                            = 0x13
+	CSTOPB                           = 0x400
+	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                          = 0x40
+	ECHOE                            = 0x2
+	ECHOK                            = 0x4
+	ECHOKE                           = 0x1
+	ECHONL                           = 0x10
+	ECHOPRT                          = 0x20
+	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
+	EPOLL_NONBLOCK                   = 0x800
+	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                          = 0x10000000
+	FD_CLOEXEC                       = 0x1
+	FD_SETSIZE                       = 0x400
+	FLUSHO                           = 0x800000
+	F_DUPFD                          = 0x0
+	F_DUPFD_CLOEXEC                  = 0x406
+	F_EXLCK                          = 0x4
+	F_GETFD                          = 0x1
+	F_GETFL                          = 0x3
+	F_GETLEASE                       = 0x401
+	F_GETLK                          = 0x5
+	F_GETLK64                        = 0xc
+	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                        = 0xd
+	F_SETLKW                         = 0x7
+	F_SETLKW64                       = 0xe
+	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                            = 0x4000
+	ICANON                           = 0x100
+	ICMPV6_FILTER                    = 0x1
+	ICRNL                            = 0x100
+	IEXTEN                           = 0x400
+	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_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_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                             = 0x80
+	ISTRIP                           = 0x20
+	IUTF8                            = 0x4000
+	IXANY                            = 0x800
+	IXOFF                            = 0x400
+	IXON                             = 0x200
+	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_LOCKED                       = 0x80
+	MAP_NONBLOCK                     = 0x10000
+	MAP_NORESERVE                    = 0x40
+	MAP_POPULATE                     = 0x8000
+	MAP_PRIVATE                      = 0x2
+	MAP_SHARED                       = 0x1
+	MAP_STACK                        = 0x20000
+	MAP_TYPE                         = 0xf
+	MCL_CURRENT                      = 0x2000
+	MCL_FUTURE                       = 0x4000
+	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                           = 0x80000000
+	OCRNL                            = 0x8
+	OFDEL                            = 0x80
+	OFILL                            = 0x40
+	ONLCR                            = 0x2
+	ONLRET                           = 0x20
+	ONOCR                            = 0x10
+	OPOST                            = 0x1
+	O_ACCMODE                        = 0x3
+	O_APPEND                         = 0x400
+	O_ASYNC                          = 0x2000
+	O_CLOEXEC                        = 0x80000
+	O_CREAT                          = 0x40
+	O_DIRECT                         = 0x20000
+	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_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                           = 0x1000
+	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                           = 0x2000
+	PENDIN                           = 0x20000000
+	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_SAO                         = 0x10
+	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_GETEVRREGS                = 0x14
+	PTRACE_GETFPREGS                 = 0xe
+	PTRACE_GETREGS                   = 0xc
+	PTRACE_GETREGS64                 = 0x16
+	PTRACE_GETREGSET                 = 0x4204
+	PTRACE_GETSIGINFO                = 0x4202
+	PTRACE_GETSIGMASK                = 0x420a
+	PTRACE_GETVRREGS                 = 0x12
+	PTRACE_GETVSRREGS                = 0x1b
+	PTRACE_GET_DEBUGREG              = 0x19
+	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_SETEVRREGS                = 0x15
+	PTRACE_SETFPREGS                 = 0xf
+	PTRACE_SETOPTIONS                = 0x4200
+	PTRACE_SETREGS                   = 0xd
+	PTRACE_SETREGS64                 = 0x17
+	PTRACE_SETREGSET                 = 0x4205
+	PTRACE_SETSIGINFO                = 0x4203
+	PTRACE_SETSIGMASK                = 0x420b
+	PTRACE_SETVRREGS                 = 0x13
+	PTRACE_SETVSRREGS                = 0x1c
+	PTRACE_SET_DEBUGREG              = 0x1a
+	PTRACE_SINGLEBLOCK               = 0x100
+	PTRACE_SINGLESTEP                = 0x9
+	PTRACE_SYSCALL                   = 0x18
+	PTRACE_TRACEME                   = 0x0
+	PT_CCR                           = 0x26
+	PT_CTR                           = 0x23
+	PT_DAR                           = 0x29
+	PT_DSCR                          = 0x2c
+	PT_DSISR                         = 0x2a
+	PT_FPR0                          = 0x30
+	PT_FPSCR                         = 0x50
+	PT_LNK                           = 0x24
+	PT_MSR                           = 0x21
+	PT_NIP                           = 0x20
+	PT_ORIG_R3                       = 0x22
+	PT_R0                            = 0x0
+	PT_R1                            = 0x1
+	PT_R10                           = 0xa
+	PT_R11                           = 0xb
+	PT_R12                           = 0xc
+	PT_R13                           = 0xd
+	PT_R14                           = 0xe
+	PT_R15                           = 0xf
+	PT_R16                           = 0x10
+	PT_R17                           = 0x11
+	PT_R18                           = 0x12
+	PT_R19                           = 0x13
+	PT_R2                            = 0x2
+	PT_R20                           = 0x14
+	PT_R21                           = 0x15
+	PT_R22                           = 0x16
+	PT_R23                           = 0x17
+	PT_R24                           = 0x18
+	PT_R25                           = 0x19
+	PT_R26                           = 0x1a
+	PT_R27                           = 0x1b
+	PT_R28                           = 0x1c
+	PT_R29                           = 0x1d
+	PT_R3                            = 0x3
+	PT_R30                           = 0x1e
+	PT_R31                           = 0x1f
+	PT_R4                            = 0x4
+	PT_R5                            = 0x5
+	PT_R6                            = 0x6
+	PT_R7                            = 0x7
+	PT_R8                            = 0x8
+	PT_R9                            = 0x9
+	PT_REGS_COUNT                    = 0x2c
+	PT_RESULT                        = 0x2b
+	PT_SOFTE                         = 0x27
+	PT_TRAP                          = 0x28
+	PT_VR0                           = 0x52
+	PT_VRSAVE                        = 0x94
+	PT_VSCR                          = 0x93
+	PT_VSR0                          = 0x96
+	PT_VSR31                         = 0xd4
+	PT_XER                           = 0x25
+	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                      = 0x14
+	SO_PASSSEC                       = 0x22
+	SO_PEEK_OFF                      = 0x2a
+	SO_PEERCRED                      = 0x15
+	SO_PEERNAME                      = 0x1c
+	SO_PEERSEC                       = 0x1f
+	SO_PRIORITY                      = 0xc
+	SO_PROTOCOL                      = 0x26
+	SO_RCVBUF                        = 0x8
+	SO_RCVBUFFORCE                   = 0x21
+	SO_RCVLOWAT                      = 0x10
+	SO_RCVTIMEO                      = 0x12
+	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                      = 0x11
+	SO_SNDTIMEO                      = 0x13
+	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                           = 0x2000741f
+	TCIFLUSH                         = 0x0
+	TCIOFLUSH                        = 0x2
+	TCOFLUSH                         = 0x1
+	TCP_CONGESTION                   = 0xd
+	TCP_CORK                         = 0x3
+	TCP_DEFER_ACCEPT                 = 0x9
+	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_NODELAY                      = 0x1
+	TCP_QUICKACK                     = 0xc
+	TCP_SYNCNT                       = 0x7
+	TCP_WINDOW_CLAMP                 = 0xa
+	TCSAFLUSH                        = 0x2
+	TIOCCBRK                         = 0x5428
+	TIOCCONS                         = 0x541d
+	TIOCEXCL                         = 0x540c
+	TIOCGDEV                         = 0x40045432
+	TIOCGETC                         = 0x40067412
+	TIOCGETD                         = 0x5424
+	TIOCGETP                         = 0x40067408
+	TIOCGEXCL                        = 0x40045440
+	TIOCGICOUNT                      = 0x545d
+	TIOCGLCKTRMIOS                   = 0x5456
+	TIOCGLTC                         = 0x40067474
+	TIOCGPGRP                        = 0x40047477
+	TIOCGPKT                         = 0x40045438
+	TIOCGPTLCK                       = 0x40045439
+	TIOCGPTN                         = 0x40045430
+	TIOCGRS485                       = 0x542e
+	TIOCGSERIAL                      = 0x541e
+	TIOCGSID                         = 0x5429
+	TIOCGSOFTCAR                     = 0x5419
+	TIOCGWINSZ                       = 0x40087468
+	TIOCINQ                          = 0x4004667f
+	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_LOOP                       = 0x8000
+	TIOCM_OUT1                       = 0x2000
+	TIOCM_OUT2                       = 0x4000
+	TIOCM_RI                         = 0x80
+	TIOCM_RNG                        = 0x80
+	TIOCM_RTS                        = 0x4
+	TIOCM_SR                         = 0x10
+	TIOCM_ST                         = 0x8
+	TIOCNOTTY                        = 0x5422
+	TIOCNXCL                         = 0x540d
+	TIOCOUTQ                         = 0x40047473
+	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
+	TIOCSETC                         = 0x80067411
+	TIOCSETD                         = 0x5423
+	TIOCSETN                         = 0x8006740a
+	TIOCSETP                         = 0x80067409
+	TIOCSIG                          = 0x80045436
+	TIOCSLCKTRMIOS                   = 0x5457
+	TIOCSLTC                         = 0x80067475
+	TIOCSPGRP                        = 0x80047476
+	TIOCSPTLCK                       = 0x80045431
+	TIOCSRS485                       = 0x542f
+	TIOCSSERIAL                      = 0x541f
+	TIOCSSOFTCAR                     = 0x541a
+	TIOCSTART                        = 0x2000746e
+	TIOCSTI                          = 0x5412
+	TIOCSTOP                         = 0x2000746f
+	TIOCSWINSZ                       = 0x80087467
+	TIOCVHANGUP                      = 0x5437
+	TOSTOP                           = 0x400000
+	TUNATTACHFILTER                  = 0x801054d5
+	TUNDETACHFILTER                  = 0x801054d6
+	TUNGETFEATURES                   = 0x400454cf
+	TUNGETFILTER                     = 0x401054db
+	TUNGETIFF                        = 0x400454d2
+	TUNGETSNDBUF                     = 0x400454d3
+	TUNGETVNETHDRSZ                  = 0x400454d7
+	TUNSETDEBUG                      = 0x800454c9
+	TUNSETGROUP                      = 0x800454ce
+	TUNSETIFF                        = 0x800454ca
+	TUNSETIFINDEX                    = 0x800454da
+	TUNSETLINK                       = 0x800454cd
+	TUNSETNOCSUM                     = 0x800454c8
+	TUNSETOFFLOAD                    = 0x800454d0
+	TUNSETOWNER                      = 0x800454cc
+	TUNSETPERSIST                    = 0x800454cb
+	TUNSETQUEUE                      = 0x800454d9
+	TUNSETSNDBUF                     = 0x800454d4
+	TUNSETTXFILTER                   = 0x800454d1
+	TUNSETVNETHDRSZ                  = 0x800454d8
+	VDISCARD                         = 0x10
+	VEOF                             = 0x4
+	VEOL                             = 0x6
+	VEOL2                            = 0x8
+	VERASE                           = 0x2
+	VINTR                            = 0x0
+	VKILL                            = 0x3
+	VLNEXT                           = 0xf
+	VMIN                             = 0x5
+	VQUIT                            = 0x1
+	VREPRINT                         = 0xb
+	VSTART                           = 0xd
+	VSTOP                            = 0xe
+	VSUSP                            = 0xc
+	VSWTC                            = 0x9
+	VT0                              = 0x0
+	VT1                              = 0x10000
+	VTDLY                            = 0x10000
+	VTIME                            = 0x7
+	VWERASE                          = 0xa
+	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(0x3a)
+	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",
+	58:  "file locking deadlock error",
+	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 NFS 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_linux_ppc64le.go b/src/syscall/zerrors_linux_ppc64le.go
new file mode 100644
index 0000000..73727a4
--- /dev/null
+++ b/src/syscall/zerrors_linux_ppc64le.go
@@ -0,0 +1,1904 @@
+// mkerrors.sh -m64
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs -- -m64 _const.go
+
+// +build ppc64le,linux
+
+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                         = 0x17
+	B110                             = 0x3
+	B115200                          = 0x11
+	B1152000                         = 0x18
+	B1200                            = 0x9
+	B134                             = 0x4
+	B150                             = 0x5
+	B1500000                         = 0x19
+	B1800                            = 0xa
+	B19200                           = 0xe
+	B200                             = 0x6
+	B2000000                         = 0x1a
+	B230400                          = 0x12
+	B2400                            = 0xb
+	B2500000                         = 0x1b
+	B300                             = 0x7
+	B3000000                         = 0x1c
+	B3500000                         = 0x1d
+	B38400                           = 0xf
+	B4000000                         = 0x1e
+	B460800                          = 0x13
+	B4800                            = 0xc
+	B50                              = 0x1
+	B500000                          = 0x14
+	B57600                           = 0x10
+	B576000                          = 0x15
+	B600                             = 0x8
+	B75                              = 0x2
+	B921600                          = 0x16
+	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                           = 0x8000
+	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                            = 0x800
+	CS5                              = 0x0
+	CS6                              = 0x100
+	CS7                              = 0x200
+	CS8                              = 0x300
+	CSIGNAL                          = 0xff
+	CSIZE                            = 0x300
+	CSTART                           = 0x11
+	CSTATUS                          = 0x0
+	CSTOP                            = 0x13
+	CSTOPB                           = 0x400
+	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                          = 0x40
+	ECHOE                            = 0x2
+	ECHOK                            = 0x4
+	ECHOKE                           = 0x1
+	ECHONL                           = 0x10
+	ECHOPRT                          = 0x20
+	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                          = 0x10000000
+	FD_CLOEXEC                       = 0x1
+	FD_SETSIZE                       = 0x400
+	FLUSHO                           = 0x800000
+	F_DUPFD                          = 0x0
+	F_DUPFD_CLOEXEC                  = 0x406
+	F_EXLCK                          = 0x4
+	F_GETFD                          = 0x1
+	F_GETFL                          = 0x3
+	F_GETLEASE                       = 0x401
+	F_GETLK                          = 0x5
+	F_GETLK64                        = 0xc
+	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                        = 0xd
+	F_SETLKW                         = 0x7
+	F_SETLKW64                       = 0xe
+	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                            = 0x4000
+	ICANON                           = 0x100
+	ICMPV6_FILTER                    = 0x1
+	ICRNL                            = 0x100
+	IEXTEN                           = 0x400
+	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                             = 0x80
+	ISTRIP                           = 0x20
+	IUTF8                            = 0x4000
+	IXANY                            = 0x800
+	IXOFF                            = 0x400
+	IXON                             = 0x200
+	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                       = 0x80
+	MAP_NONBLOCK                     = 0x10000
+	MAP_NORESERVE                    = 0x40
+	MAP_POPULATE                     = 0x8000
+	MAP_PRIVATE                      = 0x2
+	MAP_SHARED                       = 0x1
+	MAP_STACK                        = 0x20000
+	MAP_TYPE                         = 0xf
+	MCL_CURRENT                      = 0x2000
+	MCL_FUTURE                       = 0x4000
+	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                           = 0x80000000
+	OCRNL                            = 0x8
+	OFDEL                            = 0x80
+	OFILL                            = 0x40
+	ONLCR                            = 0x2
+	ONLRET                           = 0x20
+	ONOCR                            = 0x10
+	OPOST                            = 0x1
+	O_ACCMODE                        = 0x3
+	O_APPEND                         = 0x400
+	O_ASYNC                          = 0x2000
+	O_CLOEXEC                        = 0x80000
+	O_CREAT                          = 0x40
+	O_DIRECT                         = 0x20000
+	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                           = 0x1000
+	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                           = 0x2000
+	PENDIN                           = 0x20000000
+	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_SAO                         = 0x10
+	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_GETEVRREGS                = 0x14
+	PTRACE_GETFPREGS                 = 0xe
+	PTRACE_GETREGS                   = 0xc
+	PTRACE_GETREGS64                 = 0x16
+	PTRACE_GETREGSET                 = 0x4204
+	PTRACE_GETSIGINFO                = 0x4202
+	PTRACE_GETSIGMASK                = 0x420a
+	PTRACE_GETVRREGS                 = 0x12
+	PTRACE_GETVSRREGS                = 0x1b
+	PTRACE_GET_DEBUGREG              = 0x19
+	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_SETEVRREGS                = 0x15
+	PTRACE_SETFPREGS                 = 0xf
+	PTRACE_SETOPTIONS                = 0x4200
+	PTRACE_SETREGS                   = 0xd
+	PTRACE_SETREGS64                 = 0x17
+	PTRACE_SETREGSET                 = 0x4205
+	PTRACE_SETSIGINFO                = 0x4203
+	PTRACE_SETSIGMASK                = 0x420b
+	PTRACE_SETVRREGS                 = 0x13
+	PTRACE_SETVSRREGS                = 0x1c
+	PTRACE_SET_DEBUGREG              = 0x1a
+	PTRACE_SINGLEBLOCK               = 0x100
+	PTRACE_SINGLESTEP                = 0x9
+	PTRACE_SYSCALL                   = 0x18
+	PTRACE_TRACEME                   = 0x0
+	PT_CCR                           = 0x26
+	PT_CTR                           = 0x23
+	PT_DAR                           = 0x29
+	PT_DSCR                          = 0x2c
+	PT_DSISR                         = 0x2a
+	PT_FPR0                          = 0x30
+	PT_FPSCR                         = 0x50
+	PT_LNK                           = 0x24
+	PT_MSR                           = 0x21
+	PT_NIP                           = 0x20
+	PT_ORIG_R3                       = 0x22
+	PT_R0                            = 0x0
+	PT_R1                            = 0x1
+	PT_R10                           = 0xa
+	PT_R11                           = 0xb
+	PT_R12                           = 0xc
+	PT_R13                           = 0xd
+	PT_R14                           = 0xe
+	PT_R15                           = 0xf
+	PT_R16                           = 0x10
+	PT_R17                           = 0x11
+	PT_R18                           = 0x12
+	PT_R19                           = 0x13
+	PT_R2                            = 0x2
+	PT_R20                           = 0x14
+	PT_R21                           = 0x15
+	PT_R22                           = 0x16
+	PT_R23                           = 0x17
+	PT_R24                           = 0x18
+	PT_R25                           = 0x19
+	PT_R26                           = 0x1a
+	PT_R27                           = 0x1b
+	PT_R28                           = 0x1c
+	PT_R29                           = 0x1d
+	PT_R3                            = 0x3
+	PT_R30                           = 0x1e
+	PT_R31                           = 0x1f
+	PT_R4                            = 0x4
+	PT_R5                            = 0x5
+	PT_R6                            = 0x6
+	PT_R7                            = 0x7
+	PT_R8                            = 0x8
+	PT_R9                            = 0x9
+	PT_REGS_COUNT                    = 0x2c
+	PT_RESULT                        = 0x2b
+	PT_SOFTE                         = 0x27
+	PT_TRAP                          = 0x28
+	PT_VR0                           = 0x52
+	PT_VRSAVE                        = 0x94
+	PT_VSCR                          = 0x93
+	PT_VSR0                          = 0x96
+	PT_VSR31                         = 0xd4
+	PT_XER                           = 0x25
+	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                      = 0x14
+	SO_PASSSEC                       = 0x22
+	SO_PEEK_OFF                      = 0x2a
+	SO_PEERCRED                      = 0x15
+	SO_PEERNAME                      = 0x1c
+	SO_PEERSEC                       = 0x1f
+	SO_PRIORITY                      = 0xc
+	SO_PROTOCOL                      = 0x26
+	SO_RCVBUF                        = 0x8
+	SO_RCVBUFFORCE                   = 0x21
+	SO_RCVLOWAT                      = 0x10
+	SO_RCVTIMEO                      = 0x12
+	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                      = 0x11
+	SO_SNDTIMEO                      = 0x13
+	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                           = 0x2000741f
+	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                         = 0x40045432
+	TIOCGETC                         = 0x40067412
+	TIOCGETD                         = 0x5424
+	TIOCGETP                         = 0x40067408
+	TIOCGEXCL                        = 0x40045440
+	TIOCGICOUNT                      = 0x545d
+	TIOCGLCKTRMIOS                   = 0x5456
+	TIOCGLTC                         = 0x40067474
+	TIOCGPGRP                        = 0x40047477
+	TIOCGPKT                         = 0x40045438
+	TIOCGPTLCK                       = 0x40045439
+	TIOCGPTN                         = 0x40045430
+	TIOCGRS485                       = 0x542e
+	TIOCGSERIAL                      = 0x541e
+	TIOCGSID                         = 0x5429
+	TIOCGSOFTCAR                     = 0x5419
+	TIOCGWINSZ                       = 0x40087468
+	TIOCINQ                          = 0x4004667f
+	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_LOOP                       = 0x8000
+	TIOCM_OUT1                       = 0x2000
+	TIOCM_OUT2                       = 0x4000
+	TIOCM_RI                         = 0x80
+	TIOCM_RNG                        = 0x80
+	TIOCM_RTS                        = 0x4
+	TIOCM_SR                         = 0x10
+	TIOCM_ST                         = 0x8
+	TIOCNOTTY                        = 0x5422
+	TIOCNXCL                         = 0x540d
+	TIOCOUTQ                         = 0x40047473
+	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
+	TIOCSETC                         = 0x80067411
+	TIOCSETD                         = 0x5423
+	TIOCSETN                         = 0x8006740a
+	TIOCSETP                         = 0x80067409
+	TIOCSIG                          = 0x80045436
+	TIOCSLCKTRMIOS                   = 0x5457
+	TIOCSLTC                         = 0x80067475
+	TIOCSPGRP                        = 0x80047476
+	TIOCSPTLCK                       = 0x80045431
+	TIOCSRS485                       = 0x542f
+	TIOCSSERIAL                      = 0x541f
+	TIOCSSOFTCAR                     = 0x541a
+	TIOCSTART                        = 0x2000746e
+	TIOCSTI                          = 0x5412
+	TIOCSTOP                         = 0x2000746f
+	TIOCSWINSZ                       = 0x80087467
+	TIOCVHANGUP                      = 0x5437
+	TOSTOP                           = 0x400000
+	TUNATTACHFILTER                  = 0x801054d5
+	TUNDETACHFILTER                  = 0x801054d6
+	TUNGETFEATURES                   = 0x400454cf
+	TUNGETFILTER                     = 0x401054db
+	TUNGETIFF                        = 0x400454d2
+	TUNGETSNDBUF                     = 0x400454d3
+	TUNGETVNETHDRSZ                  = 0x400454d7
+	TUNSETDEBUG                      = 0x800454c9
+	TUNSETGROUP                      = 0x800454ce
+	TUNSETIFF                        = 0x800454ca
+	TUNSETIFINDEX                    = 0x800454da
+	TUNSETLINK                       = 0x800454cd
+	TUNSETNOCSUM                     = 0x800454c8
+	TUNSETOFFLOAD                    = 0x800454d0
+	TUNSETOWNER                      = 0x800454cc
+	TUNSETPERSIST                    = 0x800454cb
+	TUNSETQUEUE                      = 0x800454d9
+	TUNSETSNDBUF                     = 0x800454d4
+	TUNSETTXFILTER                   = 0x800454d1
+	TUNSETVNETHDRSZ                  = 0x800454d8
+	VDISCARD                         = 0x10
+	VEOF                             = 0x4
+	VEOL                             = 0x6
+	VEOL2                            = 0x8
+	VERASE                           = 0x2
+	VINTR                            = 0x0
+	VKILL                            = 0x3
+	VLNEXT                           = 0xf
+	VMIN                             = 0x5
+	VQUIT                            = 0x1
+	VREPRINT                         = 0xb
+	VSTART                           = 0xd
+	VSTOP                            = 0xe
+	VSUSP                            = 0xc
+	VSWTC                            = 0x9
+	VT0                              = 0x0
+	VT1                              = 0x10000
+	VTDLY                            = 0x10000
+	VTIME                            = 0x7
+	VWERASE                          = 0xa
+	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(0x3a)
+	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",
+	58:  "file locking deadlock error",
+	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_netbsd_386.go b/src/syscall/zerrors_netbsd_386.go
index 1e3dff7..6f32def 100644
--- a/src/syscall/zerrors_netbsd_386.go
+++ b/src/syscall/zerrors_netbsd_386.go
@@ -4,6 +4,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- -m32 _const.go
 
+// +build 386,netbsd
+
 package syscall
 
 const (
diff --git a/src/syscall/zerrors_netbsd_amd64.go b/src/syscall/zerrors_netbsd_amd64.go
index 1469d00..a6d1701 100644
--- a/src/syscall/zerrors_netbsd_amd64.go
+++ b/src/syscall/zerrors_netbsd_amd64.go
@@ -4,6 +4,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- -m64 _const.go
 
+// +build amd64,netbsd
+
 package syscall
 
 const (
diff --git a/src/syscall/zerrors_netbsd_arm.go b/src/syscall/zerrors_netbsd_arm.go
index 1a88c0d..7f99279 100644
--- a/src/syscall/zerrors_netbsd_arm.go
+++ b/src/syscall/zerrors_netbsd_arm.go
@@ -4,6 +4,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- -marm _const.go
 
+// +build arm,netbsd
+
 package syscall
 
 const (
diff --git a/src/syscall/zerrors_openbsd_386.go b/src/syscall/zerrors_openbsd_386.go
index 0829834..540d310 100644
--- a/src/syscall/zerrors_openbsd_386.go
+++ b/src/syscall/zerrors_openbsd_386.go
@@ -4,6 +4,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- -m32 _const.go
 
+// +build 386,openbsd
+
 package syscall
 
 const (
diff --git a/src/syscall/zerrors_openbsd_amd64.go b/src/syscall/zerrors_openbsd_amd64.go
index e9fa37c..ae5b8c9 100644
--- a/src/syscall/zerrors_openbsd_amd64.go
+++ b/src/syscall/zerrors_openbsd_amd64.go
@@ -4,6 +4,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- -m64 _const.go
 
+// +build amd64,openbsd
+
 package syscall
 
 const (
diff --git a/src/syscall/zerrors_openbsd_arm.go b/src/syscall/zerrors_openbsd_arm.go
new file mode 100644
index 0000000..c49ebcf
--- /dev/null
+++ b/src/syscall/zerrors_openbsd_arm.go
@@ -0,0 +1,1584 @@
+// mkerrors.sh
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs -- _const.go
+
+// +build arm,openbsd
+
+package syscall
+
+const (
+	AF_APPLETALK                      = 0x10
+	AF_BLUETOOTH                      = 0x20
+	AF_CCITT                          = 0xa
+	AF_CHAOS                          = 0x5
+	AF_CNT                            = 0x15
+	AF_COIP                           = 0x14
+	AF_DATAKIT                        = 0x9
+	AF_DECnet                         = 0xc
+	AF_DLI                            = 0xd
+	AF_E164                           = 0x1a
+	AF_ECMA                           = 0x8
+	AF_ENCAP                          = 0x1c
+	AF_HYLINK                         = 0xf
+	AF_IMPLINK                        = 0x3
+	AF_INET                           = 0x2
+	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                           = 0x21
+	AF_NATM                           = 0x1b
+	AF_NS                             = 0x6
+	AF_OSI                            = 0x7
+	AF_PUP                            = 0x4
+	AF_ROUTE                          = 0x11
+	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
+	B1200                             = 0x4b0
+	B134                              = 0x86
+	B14400                            = 0x3840
+	B150                              = 0x96
+	B1800                             = 0x708
+	B19200                            = 0x4b00
+	B200                              = 0xc8
+	B230400                           = 0x38400
+	B2400                             = 0x960
+	B28800                            = 0x7080
+	B300                              = 0x12c
+	B38400                            = 0x9600
+	B4800                             = 0x12c0
+	B50                               = 0x32
+	B57600                            = 0xe100
+	B600                              = 0x258
+	B7200                             = 0x1c20
+	B75                               = 0x4b
+	B76800                            = 0x12c00
+	B9600                             = 0x2580
+	BIOCFLUSH                         = 0x20004268
+	BIOCGBLEN                         = 0x40044266
+	BIOCGDIRFILT                      = 0x4004427c
+	BIOCGDLT                          = 0x4004426a
+	BIOCGDLTLIST                      = 0xc008427b
+	BIOCGETIF                         = 0x4020426b
+	BIOCGFILDROP                      = 0x40044278
+	BIOCGHDRCMPLT                     = 0x40044274
+	BIOCGRSIG                         = 0x40044273
+	BIOCGRTIMEOUT                     = 0x400c426e
+	BIOCGSTATS                        = 0x4008426f
+	BIOCIMMEDIATE                     = 0x80044270
+	BIOCLOCK                          = 0x20004276
+	BIOCPROMISC                       = 0x20004269
+	BIOCSBLEN                         = 0xc0044266
+	BIOCSDIRFILT                      = 0x8004427d
+	BIOCSDLT                          = 0x8004427a
+	BIOCSETF                          = 0x80084267
+	BIOCSETIF                         = 0x8020426c
+	BIOCSETWF                         = 0x80084277
+	BIOCSFILDROP                      = 0x80044279
+	BIOCSHDRCMPLT                     = 0x80044275
+	BIOCSRSIG                         = 0x80044272
+	BIOCSRTIMEOUT                     = 0x800c426d
+	BIOCVERSION                       = 0x40044271
+	BPF_A                             = 0x10
+	BPF_ABS                           = 0x20
+	BPF_ADD                           = 0x0
+	BPF_ALIGNMENT                     = 0x4
+	BPF_ALU                           = 0x4
+	BPF_AND                           = 0x50
+	BPF_B                             = 0x10
+	BPF_DIRECTION_IN                  = 0x1
+	BPF_DIRECTION_OUT                 = 0x2
+	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_MAXBUFSIZE                    = 0x200000
+	BPF_MAXINSNS                      = 0x200
+	BPF_MEM                           = 0x60
+	BPF_MEMWORDS                      = 0x10
+	BPF_MINBUFSIZE                    = 0x20
+	BPF_MINOR_VERSION                 = 0x1
+	BPF_MISC                          = 0x7
+	BPF_MSH                           = 0xa0
+	BPF_MUL                           = 0x20
+	BPF_NEG                           = 0x80
+	BPF_OR                            = 0x40
+	BPF_RELEASE                       = 0x30bb6
+	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
+	BRKINT                            = 0x2
+	CFLUSH                            = 0xf
+	CLOCAL                            = 0x8000
+	CREAD                             = 0x800
+	CS5                               = 0x0
+	CS6                               = 0x100
+	CS7                               = 0x200
+	CS8                               = 0x300
+	CSIZE                             = 0x300
+	CSTART                            = 0x11
+	CSTATUS                           = 0xff
+	CSTOP                             = 0x13
+	CSTOPB                            = 0x400
+	CSUSP                             = 0x1a
+	CTL_MAXNAME                       = 0xc
+	CTL_NET                           = 0x4
+	DIOCOSFPFLUSH                     = 0x2000444e
+	DLT_ARCNET                        = 0x7
+	DLT_ATM_RFC1483                   = 0xb
+	DLT_AX25                          = 0x3
+	DLT_CHAOS                         = 0x5
+	DLT_C_HDLC                        = 0x68
+	DLT_EN10MB                        = 0x1
+	DLT_EN3MB                         = 0x2
+	DLT_ENC                           = 0xd
+	DLT_FDDI                          = 0xa
+	DLT_IEEE802                       = 0x6
+	DLT_IEEE802_11                    = 0x69
+	DLT_IEEE802_11_RADIO              = 0x7f
+	DLT_LOOP                          = 0xc
+	DLT_MPLS                          = 0xdb
+	DLT_NULL                          = 0x0
+	DLT_PFLOG                         = 0x75
+	DLT_PFSYNC                        = 0x12
+	DLT_PPP                           = 0x9
+	DLT_PPP_BSDOS                     = 0x10
+	DLT_PPP_ETHER                     = 0x33
+	DLT_PPP_SERIAL                    = 0x32
+	DLT_PRONET                        = 0x4
+	DLT_RAW                           = 0xe
+	DLT_SLIP                          = 0x8
+	DLT_SLIP_BSDOS                    = 0xf
+	DT_BLK                            = 0x6
+	DT_CHR                            = 0x2
+	DT_DIR                            = 0x4
+	DT_FIFO                           = 0x1
+	DT_LNK                            = 0xa
+	DT_REG                            = 0x8
+	DT_SOCK                           = 0xc
+	DT_UNKNOWN                        = 0x0
+	ECHO                              = 0x8
+	ECHOCTL                           = 0x40
+	ECHOE                             = 0x2
+	ECHOK                             = 0x4
+	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_PROC                       = -0x5
+	EVFILT_READ                       = -0x1
+	EVFILT_SIGNAL                     = -0x6
+	EVFILT_SYSCOUNT                   = 0x7
+	EVFILT_TIMER                      = -0x7
+	EVFILT_VNODE                      = -0x4
+	EVFILT_WRITE                      = -0x2
+	EV_ADD                            = 0x1
+	EV_CLEAR                          = 0x20
+	EV_DELETE                         = 0x2
+	EV_DISABLE                        = 0x8
+	EV_ENABLE                         = 0x4
+	EV_EOF                            = 0x8000
+	EV_ERROR                          = 0x4000
+	EV_FLAG1                          = 0x2000
+	EV_ONESHOT                        = 0x10
+	EV_SYSFLAGS                       = 0xf000
+	EXTA                              = 0x4b00
+	EXTB                              = 0x9600
+	EXTPROC                           = 0x800
+	FD_CLOEXEC                        = 0x1
+	FD_SETSIZE                        = 0x400
+	FLUSHO                            = 0x800000
+	F_DUPFD                           = 0x0
+	F_DUPFD_CLOEXEC                   = 0xa
+	F_GETFD                           = 0x1
+	F_GETFL                           = 0x3
+	F_GETLK                           = 0x7
+	F_GETOWN                          = 0x5
+	F_RDLCK                           = 0x1
+	F_SETFD                           = 0x2
+	F_SETFL                           = 0x4
+	F_SETLK                           = 0x8
+	F_SETLKW                          = 0x9
+	F_SETOWN                          = 0x6
+	F_UNLCK                           = 0x2
+	F_WRLCK                           = 0x3
+	HUPCL                             = 0x4000
+	ICANON                            = 0x100
+	ICMP6_FILTER                      = 0x12
+	ICRNL                             = 0x100
+	IEXTEN                            = 0x400
+	IFAN_ARRIVAL                      = 0x0
+	IFAN_DEPARTURE                    = 0x1
+	IFA_ROUTE                         = 0x1
+	IFF_ALLMULTI                      = 0x200
+	IFF_BROADCAST                     = 0x2
+	IFF_CANTCHANGE                    = 0x8e52
+	IFF_DEBUG                         = 0x4
+	IFF_LINK0                         = 0x1000
+	IFF_LINK1                         = 0x2000
+	IFF_LINK2                         = 0x4000
+	IFF_LOOPBACK                      = 0x8
+	IFF_MULTICAST                     = 0x8000
+	IFF_NOARP                         = 0x80
+	IFF_NOTRAILERS                    = 0x20
+	IFF_OACTIVE                       = 0x400
+	IFF_POINTOPOINT                   = 0x10
+	IFF_PROMISC                       = 0x100
+	IFF_RUNNING                       = 0x40
+	IFF_SIMPLEX                       = 0x800
+	IFF_UP                            = 0x1
+	IFNAMSIZ                          = 0x10
+	IFT_1822                          = 0x2
+	IFT_A12MPPSWITCH                  = 0x82
+	IFT_AAL2                          = 0xbb
+	IFT_AAL5                          = 0x31
+	IFT_ADSL                          = 0x5e
+	IFT_AFLANE8023                    = 0x3b
+	IFT_AFLANE8025                    = 0x3c
+	IFT_ARAP                          = 0x58
+	IFT_ARCNET                        = 0x23
+	IFT_ARCNETPLUS                    = 0x24
+	IFT_ASYNC                         = 0x54
+	IFT_ATM                           = 0x25
+	IFT_ATMDXI                        = 0x69
+	IFT_ATMFUNI                       = 0x6a
+	IFT_ATMIMA                        = 0x6b
+	IFT_ATMLOGICAL                    = 0x50
+	IFT_ATMRADIO                      = 0xbd
+	IFT_ATMSUBINTERFACE               = 0x86
+	IFT_ATMVCIENDPT                   = 0xc2
+	IFT_ATMVIRTUAL                    = 0x95
+	IFT_BGPPOLICYACCOUNTING           = 0xa2
+	IFT_BLUETOOTH                     = 0xf8
+	IFT_BRIDGE                        = 0xd1
+	IFT_BSC                           = 0x53
+	IFT_CARP                          = 0xf7
+	IFT_CCTEMUL                       = 0x3d
+	IFT_CEPT                          = 0x13
+	IFT_CES                           = 0x85
+	IFT_CHANNEL                       = 0x46
+	IFT_CNR                           = 0x55
+	IFT_COFFEE                        = 0x84
+	IFT_COMPOSITELINK                 = 0x9b
+	IFT_DCN                           = 0x8d
+	IFT_DIGITALPOWERLINE              = 0x8a
+	IFT_DIGITALWRAPPEROVERHEADCHANNEL = 0xba
+	IFT_DLSW                          = 0x4a
+	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                         = 0xf3
+	IFT_FAST                          = 0x7d
+	IFT_FASTETHER                     = 0x3e
+	IFT_FASTETHERFX                   = 0x45
+	IFT_FDDI                          = 0xf
+	IFT_FIBRECHANNEL                  = 0x38
+	IFT_FRAMERELAYINTERCONNECT        = 0x3a
+	IFT_FRAMERELAYMPI                 = 0x5c
+	IFT_FRDLCIENDPT                   = 0xc1
+	IFT_FRELAY                        = 0x20
+	IFT_FRELAYDCE                     = 0x2c
+	IFT_FRF16MFRBUNDLE                = 0xa3
+	IFT_FRFORWARD                     = 0x9e
+	IFT_G703AT2MB                     = 0x43
+	IFT_G703AT64K                     = 0x42
+	IFT_GIF                           = 0xf0
+	IFT_GIGABITETHERNET               = 0x75
+	IFT_GR303IDT                      = 0xb2
+	IFT_GR303RDT                      = 0xb1
+	IFT_H323GATEKEEPER                = 0xa4
+	IFT_H323PROXY                     = 0xa5
+	IFT_HDH1822                       = 0x3
+	IFT_HDLC                          = 0x76
+	IFT_HDSL2                         = 0xa8
+	IFT_HIPERLAN2                     = 0xb7
+	IFT_HIPPI                         = 0x2f
+	IFT_HIPPIINTERFACE                = 0x39
+	IFT_HOSTPAD                       = 0x5a
+	IFT_HSSI                          = 0x2e
+	IFT_HY                            = 0xe
+	IFT_IBM370PARCHAN                 = 0x48
+	IFT_IDSL                          = 0x9a
+	IFT_IEEE1394                      = 0x90
+	IFT_IEEE80211                     = 0x47
+	IFT_IEEE80212                     = 0x37
+	IFT_IEEE8023ADLAG                 = 0xa1
+	IFT_IFGSN                         = 0x91
+	IFT_IMT                           = 0xbe
+	IFT_INFINIBAND                    = 0xc7
+	IFT_INTERLEAVE                    = 0x7c
+	IFT_IP                            = 0x7e
+	IFT_IPFORWARD                     = 0x8e
+	IFT_IPOVERATM                     = 0x72
+	IFT_IPOVERCDLC                    = 0x6d
+	IFT_IPOVERCLAW                    = 0x6e
+	IFT_IPSWITCH                      = 0x4e
+	IFT_ISDN                          = 0x3f
+	IFT_ISDNBASIC                     = 0x14
+	IFT_ISDNPRIMARY                   = 0x15
+	IFT_ISDNS                         = 0x4b
+	IFT_ISDNU                         = 0x4c
+	IFT_ISO88022LLC                   = 0x29
+	IFT_ISO88023                      = 0x7
+	IFT_ISO88024                      = 0x8
+	IFT_ISO88025                      = 0x9
+	IFT_ISO88025CRFPINT               = 0x62
+	IFT_ISO88025DTR                   = 0x56
+	IFT_ISO88025FIBER                 = 0x73
+	IFT_ISO88026                      = 0xa
+	IFT_ISUP                          = 0xb3
+	IFT_L2VLAN                        = 0x87
+	IFT_L3IPVLAN                      = 0x88
+	IFT_L3IPXVLAN                     = 0x89
+	IFT_LAPB                          = 0x10
+	IFT_LAPD                          = 0x4d
+	IFT_LAPF                          = 0x77
+	IFT_LINEGROUP                     = 0xd2
+	IFT_LOCALTALK                     = 0x2a
+	IFT_LOOP                          = 0x18
+	IFT_MEDIAMAILOVERIP               = 0x8b
+	IFT_MFSIGLINK                     = 0xa7
+	IFT_MIOX25                        = 0x26
+	IFT_MODEM                         = 0x30
+	IFT_MPC                           = 0x71
+	IFT_MPLS                          = 0xa6
+	IFT_MPLSTUNNEL                    = 0x96
+	IFT_MSDSL                         = 0x8f
+	IFT_MVL                           = 0xbf
+	IFT_MYRINET                       = 0x63
+	IFT_NFAS                          = 0xaf
+	IFT_NSIP                          = 0x1b
+	IFT_OPTICALCHANNEL                = 0xc3
+	IFT_OPTICALTRANSPORT              = 0xc4
+	IFT_OTHER                         = 0x1
+	IFT_P10                           = 0xc
+	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
+	IFT_PROPDOCSWIRELESSMACLAYER      = 0xb4
+	IFT_PROPDOCSWIRELESSUPSTREAM      = 0xb6
+	IFT_PROPMUX                       = 0x36
+	IFT_PROPVIRTUAL                   = 0x35
+	IFT_PROPWIRELESSP2P               = 0x9d
+	IFT_PTPSERIAL                     = 0x16
+	IFT_PVC                           = 0xf2
+	IFT_Q2931                         = 0xc9
+	IFT_QLLC                          = 0x44
+	IFT_RADIOMAC                      = 0xbc
+	IFT_RADSL                         = 0x5f
+	IFT_REACHDSL                      = 0xc0
+	IFT_RFC1483                       = 0x9f
+	IFT_RS232                         = 0x21
+	IFT_RSRB                          = 0x4f
+	IFT_SDLC                          = 0x11
+	IFT_SDSL                          = 0x60
+	IFT_SHDSL                         = 0xa9
+	IFT_SIP                           = 0x1f
+	IFT_SIPSIG                        = 0xcc
+	IFT_SIPTG                         = 0xcb
+	IFT_SLIP                          = 0x1c
+	IFT_SMDSDXI                       = 0x2b
+	IFT_SMDSICIP                      = 0x34
+	IFT_SONET                         = 0x27
+	IFT_SONETOVERHEADCHANNEL          = 0xb9
+	IFT_SONETPATH                     = 0x32
+	IFT_SONETVT                       = 0x33
+	IFT_SRP                           = 0x97
+	IFT_SS7SIGLINK                    = 0x9c
+	IFT_STACKTOSTACK                  = 0x6f
+	IFT_STARLAN                       = 0xb
+	IFT_T1                            = 0x12
+	IFT_TDLC                          = 0x74
+	IFT_TELINK                        = 0xc8
+	IFT_TERMPAD                       = 0x5b
+	IFT_TR008                         = 0xb0
+	IFT_TRANSPHDLC                    = 0x7b
+	IFT_TUNNEL                        = 0x83
+	IFT_ULTRA                         = 0x1d
+	IFT_USB                           = 0xa0
+	IFT_V11                           = 0x40
+	IFT_V35                           = 0x2d
+	IFT_V36                           = 0x41
+	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
+	IFT_X25                           = 0x5
+	IFT_X25DDN                        = 0x4
+	IFT_X25HUNTGROUP                  = 0x7a
+	IFT_X25MLP                        = 0x79
+	IFT_X25PLE                        = 0x28
+	IFT_XETHER                        = 0x1a
+	IGNBRK                            = 0x1
+	IGNCR                             = 0x80
+	IGNPAR                            = 0x4
+	IMAXBEL                           = 0x2000
+	INLCR                             = 0x40
+	INPCK                             = 0x10
+	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_CLASSD_HOST                    = 0xfffffff
+	IN_CLASSD_NET                     = 0xf0000000
+	IN_CLASSD_NSHIFT                  = 0x1c
+	IN_LOOPBACKNET                    = 0x7f
+	IN_RFC3021_HOST                   = 0x1
+	IN_RFC3021_NET                    = 0xfffffffe
+	IN_RFC3021_NSHIFT                 = 0x1f
+	IPPROTO_AH                        = 0x33
+	IPPROTO_CARP                      = 0x70
+	IPPROTO_DIVERT                    = 0x102
+	IPPROTO_DIVERT_INIT               = 0x2
+	IPPROTO_DIVERT_RESP               = 0x1
+	IPPROTO_DONE                      = 0x101
+	IPPROTO_DSTOPTS                   = 0x3c
+	IPPROTO_EGP                       = 0x8
+	IPPROTO_ENCAP                     = 0x62
+	IPPROTO_EON                       = 0x50
+	IPPROTO_ESP                       = 0x32
+	IPPROTO_ETHERIP                   = 0x61
+	IPPROTO_FRAGMENT                  = 0x2c
+	IPPROTO_GGP                       = 0x3
+	IPPROTO_GRE                       = 0x2f
+	IPPROTO_HOPOPTS                   = 0x0
+	IPPROTO_ICMP                      = 0x1
+	IPPROTO_ICMPV6                    = 0x3a
+	IPPROTO_IDP                       = 0x16
+	IPPROTO_IGMP                      = 0x2
+	IPPROTO_IP                        = 0x0
+	IPPROTO_IPCOMP                    = 0x6c
+	IPPROTO_IPIP                      = 0x4
+	IPPROTO_IPV4                      = 0x4
+	IPPROTO_IPV6                      = 0x29
+	IPPROTO_MAX                       = 0x100
+	IPPROTO_MAXID                     = 0x103
+	IPPROTO_MOBILE                    = 0x37
+	IPPROTO_MPLS                      = 0x89
+	IPPROTO_NONE                      = 0x3b
+	IPPROTO_PFSYNC                    = 0xf0
+	IPPROTO_PIM                       = 0x67
+	IPPROTO_PUP                       = 0xc
+	IPPROTO_RAW                       = 0xff
+	IPPROTO_ROUTING                   = 0x2b
+	IPPROTO_RSVP                      = 0x2e
+	IPPROTO_TCP                       = 0x6
+	IPPROTO_TP                        = 0x1d
+	IPPROTO_UDP                       = 0x11
+	IPV6_AUTH_LEVEL                   = 0x35
+	IPV6_AUTOFLOWLABEL                = 0x3b
+	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_HLIMDEC                      = 0x1
+	IPV6_HOPLIMIT                     = 0x2f
+	IPV6_HOPOPTS                      = 0x31
+	IPV6_IPCOMP_LEVEL                 = 0x3c
+	IPV6_JOIN_GROUP                   = 0xc
+	IPV6_LEAVE_GROUP                  = 0xd
+	IPV6_MAXHLIM                      = 0xff
+	IPV6_MAXPACKET                    = 0xffff
+	IPV6_MMTU                         = 0x500
+	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_PORTRANGE                    = 0xe
+	IPV6_PORTRANGE_DEFAULT            = 0x0
+	IPV6_PORTRANGE_HIGH               = 0x1
+	IPV6_PORTRANGE_LOW                = 0x2
+	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
+	IPV6_RTHDR_STRICT                 = 0x1
+	IPV6_RTHDR_TYPE_0                 = 0x0
+	IPV6_SOCKOPT_RESERVED1            = 0x3
+	IPV6_TCLASS                       = 0x3d
+	IPV6_UNICAST_HOPS                 = 0x4
+	IPV6_USE_MIN_MTU                  = 0x2a
+	IPV6_V6ONLY                       = 0x1b
+	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_ESP_NETWORK_LEVEL              = 0x16
+	IP_ESP_TRANS_LEVEL                = 0x15
+	IP_HDRINCL                        = 0x2
+	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                = 0xfff
+	IP_MF                             = 0x2000
+	IP_MINTTL                         = 0x20
+	IP_MIN_MEMBERSHIPS                = 0xf
+	IP_MSS                            = 0x240
+	IP_MULTICAST_IF                   = 0x9
+	IP_MULTICAST_LOOP                 = 0xb
+	IP_MULTICAST_TTL                  = 0xa
+	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_RECVDSTPORT                    = 0x21
+	IP_RECVIF                         = 0x1e
+	IP_RECVOPTS                       = 0x5
+	IP_RECVRETOPTS                    = 0x6
+	IP_RECVRTABLE                     = 0x23
+	IP_RECVTTL                        = 0x1f
+	IP_RETOPTS                        = 0x8
+	IP_RF                             = 0x8000
+	IP_RTABLE                         = 0x1021
+	IP_TOS                            = 0x3
+	IP_TTL                            = 0x4
+	ISIG                              = 0x80
+	ISTRIP                            = 0x20
+	IXANY                             = 0x800
+	IXOFF                             = 0x400
+	IXON                              = 0x200
+	LCNT_OVERLOAD_FLUSH               = 0x6
+	LOCK_EX                           = 0x2
+	LOCK_NB                           = 0x4
+	LOCK_SH                           = 0x1
+	LOCK_UN                           = 0x8
+	MADV_DONTNEED                     = 0x4
+	MADV_FREE                         = 0x6
+	MADV_NORMAL                       = 0x0
+	MADV_RANDOM                       = 0x1
+	MADV_SEQUENTIAL                   = 0x2
+	MADV_SPACEAVAIL                   = 0x5
+	MADV_WILLNEED                     = 0x3
+	MAP_ANON                          = 0x1000
+	MAP_ANONYMOUS                     = 0x1000
+	MAP_COPY                          = 0x2
+	MAP_FILE                          = 0x0
+	MAP_FIXED                         = 0x10
+	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                        = 0x0
+	MAP_SHARED                        = 0x1
+	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_EOR                           = 0x8
+	MSG_MCAST                         = 0x200
+	MSG_NOSIGNAL                      = 0x400
+	MSG_OOB                           = 0x1
+	MSG_PEEK                          = 0x2
+	MSG_TRUNC                         = 0x10
+	MSG_WAITALL                       = 0x40
+	MS_ASYNC                          = 0x1
+	MS_INVALIDATE                     = 0x4
+	MS_SYNC                           = 0x2
+	NAME_MAX                          = 0xff
+	NET_RT_DUMP                       = 0x1
+	NET_RT_FLAGS                      = 0x2
+	NET_RT_IFLIST                     = 0x3
+	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_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                            = 0x80
+	ONOCR                             = 0x40
+	ONOEOT                            = 0x8
+	OPOST                             = 0x1
+	O_ACCMODE                         = 0x3
+	O_APPEND                          = 0x8
+	O_ASYNC                           = 0x40
+	O_CLOEXEC                         = 0x10000
+	O_CREAT                           = 0x200
+	O_DIRECTORY                       = 0x20000
+	O_DSYNC                           = 0x80
+	O_EXCL                            = 0x800
+	O_EXLOCK                          = 0x20
+	O_FSYNC                           = 0x80
+	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
+	O_WRONLY                          = 0x1
+	PARENB                            = 0x1000
+	PARMRK                            = 0x8
+	PARODD                            = 0x2000
+	PENDIN                            = 0x20000000
+	PF_FLUSH                          = 0x1
+	PRIO_PGRP                         = 0x1
+	PRIO_PROCESS                      = 0x0
+	PRIO_USER                         = 0x2
+	PROT_EXEC                         = 0x4
+	PROT_NONE                         = 0x0
+	PROT_READ                         = 0x1
+	PROT_WRITE                        = 0x2
+	RLIMIT_CORE                       = 0x4
+	RLIMIT_CPU                        = 0x0
+	RLIMIT_DATA                       = 0x2
+	RLIMIT_FSIZE                      = 0x1
+	RLIMIT_NOFILE                     = 0x8
+	RLIMIT_STACK                      = 0x3
+	RLIM_INFINITY                     = 0x7fffffffffffffff
+	RTAX_AUTHOR                       = 0x6
+	RTAX_BRD                          = 0x7
+	RTAX_DST                          = 0x0
+	RTAX_GATEWAY                      = 0x1
+	RTAX_GENMASK                      = 0x3
+	RTAX_IFA                          = 0x5
+	RTAX_IFP                          = 0x4
+	RTAX_LABEL                        = 0xa
+	RTAX_MAX                          = 0xb
+	RTAX_NETMASK                      = 0x2
+	RTAX_SRC                          = 0x8
+	RTAX_SRCMASK                      = 0x9
+	RTA_AUTHOR                        = 0x40
+	RTA_BRD                           = 0x80
+	RTA_DST                           = 0x1
+	RTA_GATEWAY                       = 0x2
+	RTA_GENMASK                       = 0x8
+	RTA_IFA                           = 0x20
+	RTA_IFP                           = 0x10
+	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_MPATH                         = 0x40000
+	RTF_MPLS                          = 0x100000
+	RTF_PERMANENT_ARP                 = 0x2000
+	RTF_PROTO1                        = 0x8000
+	RTF_PROTO2                        = 0x4000
+	RTF_PROTO3                        = 0x2000
+	RTF_REJECT                        = 0x8
+	RTF_STATIC                        = 0x800
+	RTF_UP                            = 0x1
+	RTF_USETRAILERS                   = 0x8000
+	RTF_XRESOLVE                      = 0x200
+	RTM_ADD                           = 0x1
+	RTM_CHANGE                        = 0x3
+	RTM_DELADDR                       = 0xd
+	RTM_DELETE                        = 0x2
+	RTM_DESYNC                        = 0x10
+	RTM_GET                           = 0x4
+	RTM_IFANNOUNCE                    = 0xf
+	RTM_IFINFO                        = 0xe
+	RTM_LOCK                          = 0x8
+	RTM_LOSING                        = 0x5
+	RTM_MAXSIZE                       = 0x800
+	RTM_MISS                          = 0x7
+	RTM_NEWADDR                       = 0xc
+	RTM_REDIRECT                      = 0x6
+	RTM_RESOLVE                       = 0xb
+	RTM_RTTUNIT                       = 0xf4240
+	RTM_VERSION                       = 0x5
+	RTV_EXPIRE                        = 0x4
+	RTV_HOPCOUNT                      = 0x2
+	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
+	RUSAGE_THREAD                     = 0x1
+	SCM_RIGHTS                        = 0x1
+	SCM_TIMESTAMP                     = 0x4
+	SHUT_RD                           = 0x0
+	SHUT_RDWR                         = 0x2
+	SHUT_WR                           = 0x1
+	SIOCADDMULTI                      = 0x80206931
+	SIOCAIFADDR                       = 0x8040691a
+	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
+	SIOCDIFADDR                       = 0x80206919
+	SIOCDIFGROUP                      = 0x80246989
+	SIOCDIFPHYADDR                    = 0x80206949
+	SIOCDLIFADDR                      = 0x8218691e
+	SIOCGETKALIVE                     = 0xc01869a4
+	SIOCGETLABEL                      = 0x8020699a
+	SIOCGETPFLOW                      = 0xc02069fe
+	SIOCGETPFSYNC                     = 0xc02069f8
+	SIOCGETSGCNT                      = 0xc0147534
+	SIOCGETVIFCNT                     = 0xc0147533
+	SIOCGETVLAN                       = 0xc0206990
+	SIOCGHIWAT                        = 0x40047301
+	SIOCGIFADDR                       = 0xc0206921
+	SIOCGIFASYNCMAP                   = 0xc020697c
+	SIOCGIFBRDADDR                    = 0xc0206923
+	SIOCGIFCONF                       = 0xc0086924
+	SIOCGIFDATA                       = 0xc020691b
+	SIOCGIFDESCR                      = 0xc0206981
+	SIOCGIFDSTADDR                    = 0xc0206922
+	SIOCGIFFLAGS                      = 0xc0206911
+	SIOCGIFGATTR                      = 0xc024698b
+	SIOCGIFGENERIC                    = 0xc020693a
+	SIOCGIFGMEMB                      = 0xc024698a
+	SIOCGIFGROUP                      = 0xc0246988
+	SIOCGIFHARDMTU                    = 0xc02069a5
+	SIOCGIFMEDIA                      = 0xc0286936
+	SIOCGIFMETRIC                     = 0xc0206917
+	SIOCGIFMTU                        = 0xc020697e
+	SIOCGIFNETMASK                    = 0xc0206925
+	SIOCGIFPDSTADDR                   = 0xc0206948
+	SIOCGIFPRIORITY                   = 0xc020699c
+	SIOCGIFPSRCADDR                   = 0xc0206947
+	SIOCGIFRDOMAIN                    = 0xc02069a0
+	SIOCGIFRTLABEL                    = 0xc0206983
+	SIOCGIFRXR                        = 0x802069aa
+	SIOCGIFTIMESLOT                   = 0xc0206986
+	SIOCGIFXFLAGS                     = 0xc020699e
+	SIOCGLIFADDR                      = 0xc218691d
+	SIOCGLIFPHYADDR                   = 0xc218694b
+	SIOCGLIFPHYRTABLE                 = 0xc02069a2
+	SIOCGLIFPHYTTL                    = 0xc02069a9
+	SIOCGLOWAT                        = 0x40047303
+	SIOCGPGRP                         = 0x40047309
+	SIOCGSPPPPARAMS                   = 0xc0206994
+	SIOCGVH                           = 0xc02069f6
+	SIOCGVNETID                       = 0xc02069a7
+	SIOCIFCREATE                      = 0x8020697a
+	SIOCIFDESTROY                     = 0x80206979
+	SIOCIFGCLONERS                    = 0xc00c6978
+	SIOCSETKALIVE                     = 0x801869a3
+	SIOCSETLABEL                      = 0x80206999
+	SIOCSETPFLOW                      = 0x802069fd
+	SIOCSETPFSYNC                     = 0x802069f7
+	SIOCSETVLAN                       = 0x8020698f
+	SIOCSHIWAT                        = 0x80047300
+	SIOCSIFADDR                       = 0x8020690c
+	SIOCSIFASYNCMAP                   = 0x8020697d
+	SIOCSIFBRDADDR                    = 0x80206913
+	SIOCSIFDESCR                      = 0x80206980
+	SIOCSIFDSTADDR                    = 0x8020690e
+	SIOCSIFFLAGS                      = 0x80206910
+	SIOCSIFGATTR                      = 0x8024698c
+	SIOCSIFGENERIC                    = 0x80206939
+	SIOCSIFLLADDR                     = 0x8020691f
+	SIOCSIFMEDIA                      = 0xc0206935
+	SIOCSIFMETRIC                     = 0x80206918
+	SIOCSIFMTU                        = 0x8020697f
+	SIOCSIFNETMASK                    = 0x80206916
+	SIOCSIFPHYADDR                    = 0x80406946
+	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_NONBLOCK                     = 0x4000
+	SOCK_RAW                          = 0x3
+	SOCK_RDM                          = 0x4
+	SOCK_SEQPACKET                    = 0x5
+	SOCK_STREAM                       = 0x1
+	SOL_SOCKET                        = 0xffff
+	SOMAXCONN                         = 0x80
+	SO_ACCEPTCONN                     = 0x2
+	SO_BINDANY                        = 0x1000
+	SO_BROADCAST                      = 0x20
+	SO_DEBUG                          = 0x1
+	SO_DONTROUTE                      = 0x10
+	SO_ERROR                          = 0x1007
+	SO_KEEPALIVE                      = 0x8
+	SO_LINGER                         = 0x80
+	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_SNDTIMEO                       = 0x1005
+	SO_SPLICE                         = 0x1023
+	SO_TIMESTAMP                      = 0x800
+	SO_TYPE                           = 0x1008
+	SO_USELOOPBACK                    = 0x40
+	TCIFLUSH                          = 0x1
+	TCIOFLUSH                         = 0x3
+	TCOFLUSH                          = 0x2
+	TCP_MAXBURST                      = 0x4
+	TCP_MAXSEG                        = 0x2
+	TCP_MAXWIN                        = 0xffff
+	TCP_MAX_SACK                      = 0x3
+	TCP_MAX_WINSHIFT                  = 0xe
+	TCP_MD5SIG                        = 0x4
+	TCP_MSS                           = 0x200
+	TCP_NODELAY                       = 0x1
+	TCP_NOPUSH                        = 0x10
+	TCP_NSTATES                       = 0xb
+	TCP_SACK_ENABLE                   = 0x8
+	TCSAFLUSH                         = 0x2
+	TIOCCBRK                          = 0x2000747a
+	TIOCCDTR                          = 0x20007478
+	TIOCCONS                          = 0x80047462
+	TIOCDRAIN                         = 0x2000745e
+	TIOCEXCL                          = 0x2000740d
+	TIOCEXT                           = 0x80047460
+	TIOCFLAG_CLOCAL                   = 0x2
+	TIOCFLAG_CRTSCTS                  = 0x4
+	TIOCFLAG_MDMBUF                   = 0x8
+	TIOCFLAG_PPS                      = 0x10
+	TIOCFLAG_SOFTCAR                  = 0x1
+	TIOCFLUSH                         = 0x80047410
+	TIOCGETA                          = 0x402c7413
+	TIOCGETD                          = 0x4004741a
+	TIOCGFLAGS                        = 0x4004745d
+	TIOCGPGRP                         = 0x40047477
+	TIOCGSID                          = 0x40047463
+	TIOCGTSTAMP                       = 0x400c745b
+	TIOCGWINSZ                        = 0x40087468
+	TIOCMBIC                          = 0x8004746b
+	TIOCMBIS                          = 0x8004746c
+	TIOCMGET                          = 0x4004746a
+	TIOCMODG                          = 0x4004746a
+	TIOCMODS                          = 0x8004746d
+	TIOCMSET                          = 0x8004746d
+	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                         = 0x20007471
+	TIOCNXCL                          = 0x2000740e
+	TIOCOUTQ                          = 0x40047473
+	TIOCPKT                           = 0x80047470
+	TIOCPKT_DATA                      = 0x0
+	TIOCPKT_DOSTOP                    = 0x20
+	TIOCPKT_FLUSHREAD                 = 0x1
+	TIOCPKT_FLUSHWRITE                = 0x2
+	TIOCPKT_IOCTL                     = 0x40
+	TIOCPKT_NOSTOP                    = 0x10
+	TIOCPKT_START                     = 0x8
+	TIOCPKT_STOP                      = 0x4
+	TIOCREMOTE                        = 0x80047469
+	TIOCSBRK                          = 0x2000747b
+	TIOCSCTTY                         = 0x20007461
+	TIOCSDTR                          = 0x20007479
+	TIOCSETA                          = 0x802c7414
+	TIOCSETAF                         = 0x802c7416
+	TIOCSETAW                         = 0x802c7415
+	TIOCSETD                          = 0x8004741b
+	TIOCSFLAGS                        = 0x8004745c
+	TIOCSIG                           = 0x8004745f
+	TIOCSPGRP                         = 0x80047476
+	TIOCSTART                         = 0x2000746e
+	TIOCSTAT                          = 0x80047465
+	TIOCSTI                           = 0x80017472
+	TIOCSTOP                          = 0x2000746f
+	TIOCSTSTAMP                       = 0x8008745a
+	TIOCSWINSZ                        = 0x80087467
+	TIOCUCNTL                         = 0x80047466
+	TOSTOP                            = 0x400000
+	VDISCARD                          = 0xf
+	VDSUSP                            = 0xb
+	VEOF                              = 0x0
+	VEOL                              = 0x1
+	VEOL2                             = 0x2
+	VERASE                            = 0x3
+	VINTR                             = 0x8
+	VKILL                             = 0x5
+	VLNEXT                            = 0xe
+	VMIN                              = 0x10
+	VQUIT                             = 0x9
+	VREPRINT                          = 0x6
+	VSTART                            = 0xc
+	VSTATUS                           = 0x12
+	VSTOP                             = 0xd
+	VSUSP                             = 0xa
+	VTIME                             = 0x11
+	VWERASE                           = 0x4
+	WALTSIG                           = 0x4
+	WCONTINUED                        = 0x8
+	WCOREFLAG                         = 0x80
+	WNOHANG                           = 0x1
+	WUNTRACED                         = 0x2
+)
+
+// Errors
+const (
+	E2BIG           = Errno(0x7)
+	EACCES          = Errno(0xd)
+	EADDRINUSE      = Errno(0x30)
+	EADDRNOTAVAIL   = Errno(0x31)
+	EAFNOSUPPORT    = Errno(0x2f)
+	EAGAIN          = Errno(0x23)
+	EALREADY        = Errno(0x25)
+	EAUTH           = Errno(0x50)
+	EBADF           = Errno(0x9)
+	EBADRPC         = Errno(0x48)
+	EBUSY           = Errno(0x10)
+	ECANCELED       = Errno(0x58)
+	ECHILD          = Errno(0xa)
+	ECONNABORTED    = Errno(0x35)
+	ECONNREFUSED    = Errno(0x3d)
+	ECONNRESET      = Errno(0x36)
+	EDEADLK         = Errno(0xb)
+	EDESTADDRREQ    = Errno(0x27)
+	EDOM            = Errno(0x21)
+	EDQUOT          = Errno(0x45)
+	EEXIST          = Errno(0x11)
+	EFAULT          = Errno(0xe)
+	EFBIG           = Errno(0x1b)
+	EFTYPE          = Errno(0x4f)
+	EHOSTDOWN       = Errno(0x40)
+	EHOSTUNREACH    = Errno(0x41)
+	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(0x5b)
+	ELOOP           = Errno(0x3e)
+	EMEDIUMTYPE     = Errno(0x56)
+	EMFILE          = Errno(0x18)
+	EMLINK          = Errno(0x1f)
+	EMSGSIZE        = Errno(0x28)
+	ENAMETOOLONG    = Errno(0x3f)
+	ENEEDAUTH       = Errno(0x51)
+	ENETDOWN        = Errno(0x32)
+	ENETRESET       = Errno(0x34)
+	ENETUNREACH     = Errno(0x33)
+	ENFILE          = Errno(0x17)
+	ENOATTR         = Errno(0x53)
+	ENOBUFS         = Errno(0x37)
+	ENODEV          = Errno(0x13)
+	ENOENT          = Errno(0x2)
+	ENOEXEC         = Errno(0x8)
+	ENOLCK          = Errno(0x4d)
+	ENOMEDIUM       = Errno(0x55)
+	ENOMEM          = Errno(0xc)
+	ENOMSG          = Errno(0x5a)
+	ENOPROTOOPT     = Errno(0x2a)
+	ENOSPC          = Errno(0x1c)
+	ENOSYS          = Errno(0x4e)
+	ENOTBLK         = Errno(0xf)
+	ENOTCONN        = Errno(0x39)
+	ENOTDIR         = Errno(0x14)
+	ENOTEMPTY       = Errno(0x42)
+	ENOTSOCK        = Errno(0x26)
+	ENOTSUP         = Errno(0x5b)
+	ENOTTY          = Errno(0x19)
+	ENXIO           = Errno(0x6)
+	EOPNOTSUPP      = Errno(0x2d)
+	EOVERFLOW       = Errno(0x57)
+	EPERM           = Errno(0x1)
+	EPFNOSUPPORT    = Errno(0x2e)
+	EPIPE           = Errno(0x20)
+	EPROCLIM        = Errno(0x43)
+	EPROCUNAVAIL    = Errno(0x4c)
+	EPROGMISMATCH   = Errno(0x4b)
+	EPROGUNAVAIL    = Errno(0x4a)
+	EPROTONOSUPPORT = Errno(0x2b)
+	EPROTOTYPE      = Errno(0x29)
+	ERANGE          = Errno(0x22)
+	EREMOTE         = Errno(0x47)
+	EROFS           = Errno(0x1e)
+	ERPCMISMATCH    = Errno(0x49)
+	ESHUTDOWN       = Errno(0x3a)
+	ESOCKTNOSUPPORT = Errno(0x2c)
+	ESPIPE          = Errno(0x1d)
+	ESRCH           = Errno(0x3)
+	ESTALE          = Errno(0x46)
+	ETIMEDOUT       = Errno(0x3c)
+	ETOOMANYREFS    = Errno(0x3b)
+	ETXTBSY         = Errno(0x1a)
+	EUSERS          = Errno(0x44)
+	EWOULDBLOCK     = Errno(0x23)
+	EXDEV           = Errno(0x12)
+)
+
+// Signals
+const (
+	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
+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:  "device not configured",
+	7:  "argument list too long",
+	8:  "exec format error",
+	9:  "bad file descriptor",
+	10: "no child processes",
+	11: "resource deadlock avoided",
+	12: "cannot allocate memory",
+	13: "permission denied",
+	14: "bad address",
+	15: "block device required",
+	16: "device busy",
+	17: "file exists",
+	18: "cross-device link",
+	19: "operation not supported by 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: "result too large",
+	35: "resource temporarily unavailable",
+	36: "operation now in progress",
+	37: "operation already in progress",
+	38: "socket operation on non-socket",
+	39: "destination address required",
+	40: "message too long",
+	41: "protocol wrong type for socket",
+	42: "protocol not available",
+	43: "protocol not supported",
+	44: "socket type not supported",
+	45: "operation not supported",
+	46: "protocol family not supported",
+	47: "address family not supported by protocol family",
+	48: "address already in use",
+	49: "can't assign requested address",
+	50: "network is down",
+	51: "network is unreachable",
+	52: "network dropped connection on reset",
+	53: "software caused connection abort",
+	54: "connection reset by peer",
+	55: "no buffer space available",
+	56: "socket is already connected",
+	57: "socket is not connected",
+	58: "can't send after socket shutdown",
+	59: "too many references: can't splice",
+	60: "connection timed out",
+	61: "connection refused",
+	62: "too many levels of symbolic links",
+	63: "file name too long",
+	64: "host is down",
+	65: "no route to host",
+	66: "directory not empty",
+	67: "too many processes",
+	68: "too many users",
+	69: "disc quota exceeded",
+	70: "stale NFS file handle",
+	71: "too many levels of remote in path",
+	72: "RPC struct is bad",
+	73: "RPC version wrong",
+	74: "RPC prog. not avail",
+	75: "program version wrong",
+	76: "bad procedure for program",
+	77: "no locks available",
+	78: "function not implemented",
+	79: "inappropriate file type or format",
+	80: "authentication error",
+	81: "need authenticator",
+	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
+var signals = [...]string{
+	1:  "hangup",
+	2:  "interrupt",
+	3:  "quit",
+	4:  "illegal instruction",
+	5:  "trace/BPT trap",
+	6:  "abort trap",
+	7:  "EMT trap",
+	8:  "floating point exception",
+	9:  "killed",
+	10: "bus error",
+	11: "segmentation fault",
+	12: "bad system call",
+	13: "broken pipe",
+	14: "alarm clock",
+	15: "terminated",
+	16: "urgent I/O condition",
+	17: "stopped (signal)",
+	18: "stopped",
+	19: "continued",
+	20: "child exited",
+	21: "stopped (tty input)",
+	22: "stopped (tty output)",
+	23: "I/O possible",
+	24: "cputime limit exceeded",
+	25: "filesize limit exceeded",
+	26: "virtual timer expired",
+	27: "profiling timer expired",
+	28: "window size changes",
+	29: "information request",
+	30: "user defined signal 1",
+	31: "user defined signal 2",
+	32: "thread AST",
+}
diff --git a/src/syscall/zerrors_plan9_amd64.go b/src/syscall/zerrors_plan9_amd64.go
deleted file mode 100644
index ede3d6a..0000000
--- a/src/syscall/zerrors_plan9_amd64.go
+++ /dev/null
@@ -1,48 +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.
-
-package syscall
-
-// Constants
-const (
-	// Invented values to support what package os expects.
-	O_CREAT    = 0x02000
-	O_APPEND   = 0x00400
-	O_NOCTTY   = 0x00000
-	O_NONBLOCK = 0x00000
-	O_SYNC     = 0x00000
-	O_ASYNC    = 0x00000
-
-	S_IFMT   = 0x1f000
-	S_IFIFO  = 0x1000
-	S_IFCHR  = 0x2000
-	S_IFDIR  = 0x4000
-	S_IFBLK  = 0x6000
-	S_IFREG  = 0x8000
-	S_IFLNK  = 0xa000
-	S_IFSOCK = 0xc000
-)
-
-// Errors
-var (
-	EINVAL       = NewError("bad arg in system call")
-	ENOTDIR      = NewError("not a directory")
-	EISDIR       = NewError("file is a directory")
-	ENOENT       = NewError("file does not exist")
-	EEXIST       = NewError("file already exists")
-	EMFILE       = NewError("no free file descriptors")
-	EIO          = NewError("i/o error")
-	ENAMETOOLONG = NewError("file name too long")
-	EINTR        = NewError("interrupted")
-	EPERM        = NewError("permission denied")
-	EBUSY        = NewError("no free devices")
-	ETIMEDOUT    = NewError("connection timed out")
-	EPLAN9       = NewError("not supported by plan 9")
-
-	// The following errors do not correspond to any
-	// Plan 9 system messages. Invented to support
-	// what package os and others expect.
-	EACCES       = NewError("access permission denied")
-	EAFNOSUPPORT = NewError("address family not supported by protocol")
-)
diff --git a/src/syscall/zerrors_solaris_amd64.go b/src/syscall/zerrors_solaris_amd64.go
index 3f4cbfd..62ec81b 100644
--- a/src/syscall/zerrors_solaris_amd64.go
+++ b/src/syscall/zerrors_solaris_amd64.go
@@ -4,6 +4,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- -m64 _const.go
 
+// +build amd64,solaris
+
 package syscall
 
 const (
diff --git a/src/syscall/zsyscall_darwin_386.go b/src/syscall/zsyscall_darwin_386.go
index 934565f..23e7b5e 100644
--- a/src/syscall/zsyscall_darwin_386.go
+++ b/src/syscall/zsyscall_darwin_386.go
@@ -1,6 +1,8 @@
 // mksyscall.pl -l32 syscall_bsd.go syscall_darwin.go syscall_darwin_386.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build 386,darwin
+
 package syscall
 
 import "unsafe"
@@ -11,7 +13,7 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
 	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 +23,7 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
 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 +34,7 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err
 	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 +45,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -53,7 +55,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
 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 +65,7 @@ func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 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 +76,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -84,7 +86,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
 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 +96,7 @@ func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen
 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 +106,7 @@ func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr)
 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 +116,7 @@ func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 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 +126,7 @@ func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 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 +136,7 @@ func Shutdown(s int, how int) (err error) {
 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 +153,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 	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 +169,7 @@ func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (
 	}
 	_, _, 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 +180,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -189,7 +191,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -200,7 +202,7 @@ func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, ne
 	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 +218,7 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr)
 	}
 	_, _, 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 +234,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 	_, _, 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 +244,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 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 +255,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -263,7 +265,7 @@ func fcntl(fd int, cmd int, arg int) (val int, err error) {
 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 +277,7 @@ func pipe() (r int, w int, err error) {
 	r = int(r0)
 	w = int(r1)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -285,7 +287,7 @@ func pipe() (r int, w int, err error) {
 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 +303,7 @@ func Access(path string, mode uint32) (err error) {
 	_, _, 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 +313,7 @@ func Access(path string, mode uint32) (err error) {
 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 +329,7 @@ func Chdir(path string) (err error) {
 	_, _, 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 +345,7 @@ func Chflags(path string, flags int) (err error) {
 	_, _, 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 +361,7 @@ func Chmod(path string, mode uint32) (err error) {
 	_, _, 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 +377,7 @@ func Chown(path string, uid int, gid int) (err error) {
 	_, _, 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 +393,7 @@ func Chroot(path string) (err error) {
 	_, _, 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 +403,7 @@ func Chroot(path string) (err error) {
 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 +411,10 @@ func Close(fd int) (err error) {
 // 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 +422,9 @@ func Dup(fd int) (nfd int, err error) {
 // 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 +446,7 @@ func Exchangedata(path1 string, path2 string, options int) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -461,7 +463,7 @@ func Exit(code int) {
 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 +473,7 @@ func Fchdir(fd int) (err error) {
 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 +483,7 @@ func Fchflags(fd int, flags int) (err error) {
 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 +493,7 @@ func Fchmod(fd int, mode uint32) (err error) {
 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 +503,7 @@ func Fchown(fd int, uid int, gid int) (err error) {
 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 +514,7 @@ func Fpathconf(fd int, name int) (val int, err error) {
 	r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -522,7 +524,7 @@ func Fpathconf(fd int, name int) (val int, err error) {
 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 +534,7 @@ func Fstat(fd int, stat *Stat_t) (err error) {
 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 +544,7 @@ func Fstatfs(fd int, stat *Statfs_t) (err error) {
 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 +554,7 @@ func Fsync(fd int) (err error) {
 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 +571,7 @@ func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
 	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 +614,7 @@ func Getpgid(pid int) (pgid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
 	pgid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -647,7 +649,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -657,7 +659,7 @@ func Getpriority(which int, who int) (prio int, err error) {
 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 +669,7 @@ func Getrlimit(which int, lim *Rlimit) (err error) {
 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 +680,7 @@ func Getsid(pid int) (sid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
 	sid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -705,7 +707,7 @@ func Kqueue() (fd int, err error) {
 	r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -721,7 +723,7 @@ func Lchown(path string, uid int, gid int) (err error) {
 	_, _, 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 +745,7 @@ func Link(path string, link string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -753,7 +755,7 @@ func Link(path string, link string) (err error) {
 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 +771,7 @@ func Lstat(path string, stat *Stat_t) (err error) {
 	_, _, 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 +787,7 @@ func Mkdir(path string, mode uint32) (err error) {
 	_, _, 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 +803,7 @@ func Mkfifo(path string, mode uint32) (err error) {
 	_, _, 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 +819,7 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 	_, _, 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 +835,7 @@ func Mlock(b []byte) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -843,7 +845,7 @@ func Mlock(b []byte) (err error) {
 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 +861,7 @@ func Mprotect(b []byte, prot int) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -875,7 +877,7 @@ func Munlock(b []byte) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -885,7 +887,7 @@ func Munlock(b []byte) (err error) {
 func Munlockall() (err error) {
 	_, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -902,7 +904,7 @@ func Open(path string, mode int, perm uint32) (fd int, err error) {
 	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -919,7 +921,7 @@ func Pathconf(path string, name int) (val int, err error) {
 	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -936,7 +938,7 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) {
 	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 +955,7 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
 	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 +972,7 @@ func read(fd int, p []byte) (n int, err error) {
 	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 +995,7 @@ func Readlink(path string, buf []byte) (n int, err error) {
 	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1015,7 +1017,7 @@ func Rename(from string, to string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1031,7 +1033,7 @@ func Revoke(path string) (err error) {
 	_, _, 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 +1049,7 @@ func Rmdir(path string) (err error) {
 	_, _, 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 +1060,7 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 	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 +1070,7 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 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 +1080,7 @@ func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
 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 +1090,7 @@ func Setegid(egid int) (err error) {
 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 +1100,7 @@ func Seteuid(euid int) (err error) {
 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 +1116,7 @@ func Setlogin(name string) (err error) {
 	_, _, 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 +1126,7 @@ func Setlogin(name string) (err error) {
 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 +1136,7 @@ func Setpgid(pid int, pgid int) (err error) {
 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 +1146,7 @@ func Setpriority(which int, who int, prio int) (err error) {
 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 +1156,7 @@ func Setprivexec(flag int) (err error) {
 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 +1166,7 @@ func Setregid(rgid int, egid int) (err error) {
 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 +1176,7 @@ func Setreuid(ruid int, euid int) (err error) {
 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 +1187,7 @@ func Setsid() (pid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1195,7 +1197,7 @@ func Setsid() (pid int, err error) {
 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 +1207,7 @@ func Settimeofday(tp *Timeval) (err error) {
 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 +1223,7 @@ func Stat(path string, stat *Stat_t) (err error) {
 	_, _, 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 +1239,7 @@ func Statfs(path string, stat *Statfs_t) (err error) {
 	_, _, 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 +1261,7 @@ func Symlink(path string, link string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1269,7 +1271,7 @@ func Symlink(path string, link string) (err error) {
 func Sync() (err error) {
 	_, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1285,7 +1287,7 @@ func Truncate(path string, length int64) (err error) {
 	_, _, 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 +1311,7 @@ func Undelete(path string) (err error) {
 	_, _, 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 +1327,7 @@ func Unlink(path string) (err error) {
 	_, _, 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 +1343,7 @@ func Unmount(path string, flags int) (err error) {
 	_, _, 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 +1360,7 @@ func write(fd int, p []byte) (n int, err error) {
 	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 +1371,7 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
 	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 +1381,7 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
 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 +1392,7 @@ func readlen(fd int, buf *byte, nbuf int) (n int, err error) {
 	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 +1403,7 @@ func writelen(fd int, buf *byte, nbuf int) (n int, err error) {
 	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 +1415,7 @@ func gettimeofday(tp *Timeval) (sec int32, usec int32, err error) {
 	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..6e63d9a 100644
--- a/src/syscall/zsyscall_darwin_amd64.go
+++ b/src/syscall/zsyscall_darwin_amd64.go
@@ -1,6 +1,8 @@
 // mksyscall.pl syscall_bsd.go syscall_darwin.go syscall_darwin_amd64.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build amd64,darwin
+
 package syscall
 
 import "unsafe"
@@ -11,7 +13,7 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
 	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 +23,7 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
 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 +34,7 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err
 	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 +45,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -53,7 +55,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
 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 +65,7 @@ func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 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 +76,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -84,7 +86,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
 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 +96,7 @@ func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen
 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 +106,7 @@ func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr)
 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 +116,7 @@ func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 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 +126,7 @@ func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 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 +136,7 @@ func Shutdown(s int, how int) (err error) {
 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 +153,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 	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 +169,7 @@ func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (
 	}
 	_, _, 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 +180,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -189,7 +191,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -200,7 +202,7 @@ func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, ne
 	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 +218,7 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr)
 	}
 	_, _, 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 +234,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 	_, _, 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 +244,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 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 +255,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -263,7 +265,7 @@ func fcntl(fd int, cmd int, arg int) (val int, err error) {
 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 +277,7 @@ func pipe() (r int, w int, err error) {
 	r = int(r0)
 	w = int(r1)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -285,7 +287,7 @@ func pipe() (r int, w int, err error) {
 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 +303,7 @@ func Access(path string, mode uint32) (err error) {
 	_, _, 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 +313,7 @@ func Access(path string, mode uint32) (err error) {
 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 +329,7 @@ func Chdir(path string) (err error) {
 	_, _, 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 +345,7 @@ func Chflags(path string, flags int) (err error) {
 	_, _, 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 +361,7 @@ func Chmod(path string, mode uint32) (err error) {
 	_, _, 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 +377,7 @@ func Chown(path string, uid int, gid int) (err error) {
 	_, _, 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 +393,7 @@ func Chroot(path string) (err error) {
 	_, _, 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 +403,7 @@ func Chroot(path string) (err error) {
 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 +411,10 @@ func Close(fd int) (err error) {
 // 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 +422,9 @@ func Dup(fd int) (nfd int, err error) {
 // 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 +446,7 @@ func Exchangedata(path1 string, path2 string, options int) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -461,7 +463,7 @@ func Exit(code int) {
 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 +473,7 @@ func Fchdir(fd int) (err error) {
 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 +483,7 @@ func Fchflags(fd int, flags int) (err error) {
 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 +493,7 @@ func Fchmod(fd int, mode uint32) (err error) {
 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 +503,7 @@ func Fchown(fd int, uid int, gid int) (err error) {
 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 +514,7 @@ func Fpathconf(fd int, name int) (val int, err error) {
 	r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -522,7 +524,7 @@ func Fpathconf(fd int, name int) (val int, err error) {
 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 +534,7 @@ func Fstat(fd int, stat *Stat_t) (err error) {
 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 +544,7 @@ func Fstatfs(fd int, stat *Statfs_t) (err error) {
 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 +554,7 @@ func Fsync(fd int) (err error) {
 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 +571,7 @@ func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
 	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 +614,7 @@ func Getpgid(pid int) (pgid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
 	pgid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -647,7 +649,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -657,7 +659,7 @@ func Getpriority(which int, who int) (prio int, err error) {
 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 +669,7 @@ func Getrlimit(which int, lim *Rlimit) (err error) {
 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 +680,7 @@ func Getsid(pid int) (sid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
 	sid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -705,7 +707,7 @@ func Kqueue() (fd int, err error) {
 	r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -721,7 +723,7 @@ func Lchown(path string, uid int, gid int) (err error) {
 	_, _, 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 +745,7 @@ func Link(path string, link string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -753,7 +755,7 @@ func Link(path string, link string) (err error) {
 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 +771,7 @@ func Lstat(path string, stat *Stat_t) (err error) {
 	_, _, 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 +787,7 @@ func Mkdir(path string, mode uint32) (err error) {
 	_, _, 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 +803,7 @@ func Mkfifo(path string, mode uint32) (err error) {
 	_, _, 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 +819,7 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 	_, _, 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 +835,7 @@ func Mlock(b []byte) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -843,7 +845,7 @@ func Mlock(b []byte) (err error) {
 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 +861,7 @@ func Mprotect(b []byte, prot int) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -875,7 +877,7 @@ func Munlock(b []byte) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -885,7 +887,7 @@ func Munlock(b []byte) (err error) {
 func Munlockall() (err error) {
 	_, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -902,7 +904,7 @@ func Open(path string, mode int, perm uint32) (fd int, err error) {
 	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -919,7 +921,7 @@ func Pathconf(path string, name int) (val int, err error) {
 	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -936,7 +938,7 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) {
 	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 +955,7 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
 	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 +972,7 @@ func read(fd int, p []byte) (n int, err error) {
 	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 +995,7 @@ func Readlink(path string, buf []byte) (n int, err error) {
 	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1015,7 +1017,7 @@ func Rename(from string, to string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1031,7 +1033,7 @@ func Revoke(path string) (err error) {
 	_, _, 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 +1049,7 @@ func Rmdir(path string) (err error) {
 	_, _, 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 +1060,7 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 	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 +1070,7 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 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 +1080,7 @@ func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
 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 +1090,7 @@ func Setegid(egid int) (err error) {
 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 +1100,7 @@ func Seteuid(euid int) (err error) {
 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 +1116,7 @@ func Setlogin(name string) (err error) {
 	_, _, 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 +1126,7 @@ func Setlogin(name string) (err error) {
 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 +1136,7 @@ func Setpgid(pid int, pgid int) (err error) {
 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 +1146,7 @@ func Setpriority(which int, who int, prio int) (err error) {
 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 +1156,7 @@ func Setprivexec(flag int) (err error) {
 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 +1166,7 @@ func Setregid(rgid int, egid int) (err error) {
 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 +1176,7 @@ func Setreuid(ruid int, euid int) (err error) {
 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 +1187,7 @@ func Setsid() (pid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1195,7 +1197,7 @@ func Setsid() (pid int, err error) {
 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 +1207,7 @@ func Settimeofday(tp *Timeval) (err error) {
 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 +1223,7 @@ func Stat(path string, stat *Stat_t) (err error) {
 	_, _, 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 +1239,7 @@ func Statfs(path string, stat *Statfs_t) (err error) {
 	_, _, 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 +1261,7 @@ func Symlink(path string, link string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1269,7 +1271,7 @@ func Symlink(path string, link string) (err error) {
 func Sync() (err error) {
 	_, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1285,7 +1287,7 @@ func Truncate(path string, length int64) (err error) {
 	_, _, 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 +1311,7 @@ func Undelete(path string) (err error) {
 	_, _, 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 +1327,7 @@ func Unlink(path string) (err error) {
 	_, _, 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 +1343,7 @@ func Unmount(path string, flags int) (err error) {
 	_, _, 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 +1360,7 @@ func write(fd int, p []byte) (n int, err error) {
 	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 +1371,7 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
 	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 +1381,7 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
 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 +1392,7 @@ func readlen(fd int, buf *byte, nbuf int) (n int, err error) {
 	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 +1403,7 @@ func writelen(fd int, buf *byte, nbuf int) (n int, err error) {
 	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 +1415,7 @@ func gettimeofday(tp *Timeval) (sec int64, usec int32, err error) {
 	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
new file mode 100644
index 0000000..f996a50
--- /dev/null
+++ b/src/syscall/zsyscall_darwin_arm.go
@@ -0,0 +1,1421 @@
+// mksyscall.pl -l32 syscall_bsd.go syscall_darwin.go syscall_darwin_arm.go
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+// +build arm,darwin
+
+package syscall
+
+import "unsafe"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
+	r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 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 setgroups(ngid int, gid *_Gid_t) (err error) {
+	_, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
+	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 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 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 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 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 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 Shutdown(s int, how int) (err error) {
+	_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0)
+	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 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 kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) {
+	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 = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) {
+	var _p0 unsafe.Pointer
+	if len(mib) > 0 {
+		_p0 = unsafe.Pointer(&mib[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	_, _, 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 = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func utimes(path string, timeval *[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(timeval)), 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 futimes(fd int, timeval *[2]Timeval) (err error) {
+	_, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0)
+	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 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 pipe() (r int, w int, err error) {
+	r0, r1, e1 := RawSyscall(SYS_PIPE, 0, 0, 0)
+	r = int(r0)
+	w = int(r1)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func kill(pid int, signum int, posix int) (err error) {
+	_, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), uintptr(posix))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Access(path string, mode uint32) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 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 Adjtime(delta *Timeval, olddelta *Timeval) (err error) {
+	_, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0)
+	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 Chflags(path string, flags int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_CHFLAGS, 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 Chmod(path string, mode uint32) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 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 Chown(path string, uid int, gid int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_CHOWN, 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 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(fd int) (nfd int, err error) {
+	r0, _, e1 := Syscall(SYS_DUP, uintptr(fd), 0, 0)
+	nfd = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Dup2(from int, to int) (err error) {
+	_, _, e1 := Syscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Exchangedata(path1 string, path2 string, options int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path1)
+	if err != nil {
+		return
+	}
+	var _p1 *byte
+	_p1, err = BytePtrFromString(path2)
+	if err != nil {
+		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 = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Exit(code int) {
+	Syscall(SYS_EXIT, uintptr(code), 0, 0)
+	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 Fchflags(fd int, flags int) (err error) {
+	_, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 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 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 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 Fpathconf(fd int, name int) (val int, err error) {
+	r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
+	val = int(r0)
+	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_FSTAT64, 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 Fstatfs(fd int, stat *Statfs_t) (err error) {
+	_, _, e1 := Syscall(SYS_FSTATFS64, 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 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 Ftruncate(fd int, length int64) (err error) {
+	_, _, e1 := Syscall(SYS_FTRUNCATE, uintptr(fd), uintptr(length), uintptr(length>>32))
+	if e1 != 0 {
+		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_GETDIRENTRIES64, uintptr(fd), uintptr(_p0), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 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 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)
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Geteuid() (uid int) {
+	r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0)
+	uid = 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 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 Getpgrp() (pgrp int) {
+	r0, _, _ := RawSyscall(SYS_GETPGRP, 0, 0, 0)
+	pgrp = 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)
+	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 Getrlimit(which int, lim *Rlimit) (err error) {
+	_, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
+	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 Getsid(pid int) (sid int, err error) {
+	r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
+	sid = int(r0)
+	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 Issetugid() (tainted bool) {
+	r0, _, _ := RawSyscall(SYS_ISSETUGID, 0, 0, 0)
+	tainted = bool(r0 != 0)
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Kqueue() (fd int, err error) {
+	r0, _, e1 := Syscall(SYS_KQUEUE, 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 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 Link(path string, link string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	var _p1 *byte
+	_p1, err = BytePtrFromString(link)
+	if err != nil {
+		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 = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Listen(s int, backlog int) (err error) {
+	_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Lstat(path string, stat *Stat_t) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_LSTAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 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 Mkdir(path string, mode uint32) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 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 Mkfifo(path string, mode uint32) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 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 Mknod(path string, mode uint32, dev int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
+	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 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
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Open(path string, mode int, perm uint32) (fd int, err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		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 = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pathconf(path string, name int) (val int, err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0)
+	use(unsafe.Pointer(_p0))
+	val = int(r0)
+	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_PREAD, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 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_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 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 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 Readlink(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 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)))
+	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 Rename(from string, to string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(from)
+	if err != nil {
+		return
+	}
+	var _p1 *byte
+	_p1, err = BytePtrFromString(to)
+	if err != nil {
+		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 = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Revoke(path string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_REVOKE, 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 Rmdir(path string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_RMDIR, 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 Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
+	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 = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+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 = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setegid(egid int) (err error) {
+	_, _, e1 := Syscall(SYS_SETEGID, uintptr(egid), 0, 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Seteuid(euid int) (err error) {
+	_, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setgid(gid int) (err error) {
+	_, _, e1 := RawSyscall(SYS_SETGID, 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 Setlogin(name string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(name)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_SETLOGIN, 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 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 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 Setprivexec(flag int) (err error) {
+	_, _, e1 := Syscall(SYS_SETPRIVEXEC, uintptr(flag), 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 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 Setrlimit(which int, lim *Rlimit) (err error) {
+	_, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 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(tp *Timeval) (err error) {
+	_, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setuid(uid int) (err error) {
+	_, _, e1 := RawSyscall(SYS_SETUID, 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 Stat(path string, stat *Stat_t) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_STAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 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 Statfs(path string, stat *Statfs_t) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 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 Symlink(path string, link string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	var _p1 *byte
+	_p1, err = BytePtrFromString(link)
+	if err != nil {
+		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 = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Sync() (err error) {
+	_, _, e1 := Syscall(SYS_SYNC, 0, 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), uintptr(length>>32))
+	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 Umask(newmask int) (oldmask int) {
+	r0, _, _ := Syscall(SYS_UMASK, uintptr(newmask), 0, 0)
+	oldmask = int(r0)
+	return
+}
+
+// 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 = errnoErr(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)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_UNLINK, 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 Unmount(path string, flags int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_UNMOUNT, 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 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 mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) {
+	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 = 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 readlen(fd int, buf *byte, nbuf int) (n int, err error) {
+	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
+	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, buf *byte, nbuf int) (n int, err error) {
+	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
+	n = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func gettimeofday(tp *Timeval) (sec int32, usec int32, err error) {
+	r0, r1, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
+	sec = int32(r0)
+	usec = int32(r1)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
diff --git a/src/syscall/zsyscall_darwin_arm64.go b/src/syscall/zsyscall_darwin_arm64.go
new file mode 100644
index 0000000..c260cc7
--- /dev/null
+++ b/src/syscall/zsyscall_darwin_arm64.go
@@ -0,0 +1,1421 @@
+// mksyscall.pl syscall_bsd.go syscall_darwin.go syscall_darwin_arm64.go
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+// +build arm64,darwin
+
+package syscall
+
+import "unsafe"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
+	r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+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
+	}
+	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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Shutdown(s int, how int) (err error) {
+	_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0)
+	if e1 != 0 {
+		err = 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 = 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 = 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 = 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 = 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 = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) {
+	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
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) {
+	var _p0 unsafe.Pointer
+	if len(mib) > 0 {
+		_p0 = unsafe.Pointer(&mib[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	_, _, 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
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func utimes(path string, timeval *[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(timeval)), 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 futimes(fd int, timeval *[2]Timeval) (err error) {
+	_, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0)
+	if e1 != 0 {
+		err = 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 = 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 = 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)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+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
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Access(path string, mode uint32) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 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 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
+	}
+	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 = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Chflags(path string, flags int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 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 Chmod(path string, mode uint32) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 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 Chown(path string, uid int, gid int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = 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 = 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 = e1
+	}
+	return
+}
+
+// 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)
+	nfd = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// 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)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Exchangedata(path1 string, path2 string, options int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path1)
+	if err != nil {
+		return
+	}
+	var _p1 *byte
+	_p1, err = BytePtrFromString(path2)
+	if err != nil {
+		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
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Exit(code int) {
+	Syscall(SYS_EXIT, uintptr(code), 0, 0)
+	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 = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fchflags(fd int, flags int) (err error) {
+	_, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0)
+	if e1 != 0 {
+		err = 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 = 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 = 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 = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fpathconf(fd int, name int) (val int, err error) {
+	r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
+	val = int(r0)
+	if e1 != 0 {
+		err = 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_FSTAT64, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+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
+	}
+	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 = 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 = 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_GETDIRENTRIES64, 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)
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Geteuid() (uid int) {
+	r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0)
+	uid = 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 Getpgid(pid int) (pgid int, err error) {
+	r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
+	pgid = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getpgrp() (pgrp int) {
+	r0, _, _ := RawSyscall(SYS_GETPGRP, 0, 0, 0)
+	pgrp = 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)
+	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 = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getrlimit(which int, lim *Rlimit) (err error) {
+	_, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
+	if e1 != 0 {
+		err = 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 = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Getsid(pid int) (sid int, err error) {
+	r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
+	sid = int(r0)
+	if e1 != 0 {
+		err = 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 Issetugid() (tainted bool) {
+	r0, _, _ := RawSyscall(SYS_ISSETUGID, 0, 0, 0)
+	tainted = bool(r0 != 0)
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Kqueue() (fd int, err error) {
+	r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
+	fd = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	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 = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Link(path string, link string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	var _p1 *byte
+	_p1, err = BytePtrFromString(link)
+	if err != nil {
+		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
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Listen(s int, backlog int) (err error) {
+	_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Lstat(path string, stat *Stat_t) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_LSTAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 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 Mkdir(path string, mode uint32) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 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 Mkfifo(path string, mode uint32) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 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 Mknod(path string, mode uint32, dev int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
+	use(unsafe.Pointer(_p0))
+	if e1 != 0 {
+		err = 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 = 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 = 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 = 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 = 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 = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Open(path string, mode int, perm uint32) (fd int, err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		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
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pathconf(path string, name int) (val int, err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		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
+	}
+	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)), uintptr(offset), 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 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)), uintptr(offset), 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 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 = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Readlink(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 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)))
+	use(unsafe.Pointer(_p0))
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Rename(from string, to string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(from)
+	if err != nil {
+		return
+	}
+	var _p1 *byte
+	_p1, err = BytePtrFromString(to)
+	if err != nil {
+		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
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Revoke(path string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_REVOKE, 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 Rmdir(path string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_RMDIR, 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 Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
+	r0, _, e1 := Syscall(SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(whence))
+	newoffset = int64(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+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
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setegid(egid int) (err error) {
+	_, _, e1 := Syscall(SYS_SETEGID, uintptr(egid), 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Seteuid(euid int) (err error) {
+	_, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setgid(gid int) (err error) {
+	_, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setlogin(name string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(name)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_SETLOGIN, 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 Setpgid(pid int, pgid int) (err error) {
+	_, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
+	if e1 != 0 {
+		err = 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 = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setprivexec(flag int) (err error) {
+	_, _, e1 := Syscall(SYS_SETPRIVEXEC, uintptr(flag), 0, 0)
+	if e1 != 0 {
+		err = 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 = 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 = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setrlimit(which int, lim *Rlimit) (err error) {
+	_, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
+	if e1 != 0 {
+		err = 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 = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Settimeofday(tp *Timeval) (err error) {
+	_, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setuid(uid int) (err error) {
+	_, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Stat(path string, stat *Stat_t) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_STAT64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 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 Statfs(path string, stat *Statfs_t) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 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 Symlink(path string, link string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	var _p1 *byte
+	_p1, err = BytePtrFromString(link)
+	if err != nil {
+		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
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Sync() (err error) {
+	_, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
+	if e1 != 0 {
+		err = 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 = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Umask(newmask int) (oldmask int) {
+	r0, _, _ := Syscall(SYS_UMASK, uintptr(newmask), 0, 0)
+	oldmask = int(r0)
+	return
+}
+
+// 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)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_UNLINK, 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 Unmount(path string, flags int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 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 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 = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) {
+	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
+	}
+	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 = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func readlen(fd int, buf *byte, nbuf int) (n int, err error) {
+	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func writelen(fd int, buf *byte, nbuf int) (n int, err error) {
+	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
+	n = int(r0)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func gettimeofday(tp *Timeval) (sec int64, usec int32, err error) {
+	r0, r1, e1 := RawSyscall(SYS_GETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
+	sec = int64(r0)
+	usec = int32(r1)
+	if e1 != 0 {
+		err = e1
+	}
+	return
+}
diff --git a/src/syscall/zsyscall_dragonfly_386.go b/src/syscall/zsyscall_dragonfly_386.go
deleted file mode 100644
index 01b0819..0000000
--- a/src/syscall/zsyscall_dragonfly_386.go
+++ /dev/null
@@ -1,1317 +0,0 @@
-// mksyscall.pl -l32 -dragonfly syscall_bsd.go syscall_dragonfly.go syscall_dragonfly_386.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 getgroups(ngid int, gid *_Gid_t) (n int, err error) {
-	r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
-	n = int(r0)
-	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-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
-	}
-	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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Shutdown(s int, how int) (err error) {
-	_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0)
-	if e1 != 0 {
-		err = 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 = 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 = 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 = 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 = 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 = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) {
-	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
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) {
-	var _p0 unsafe.Pointer
-	if len(mib) > 0 {
-		_p0 = unsafe.Pointer(&mib[0])
-	} else {
-		_p0 = unsafe.Pointer(&_zero)
-	}
-	_, _, 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
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func utimes(path string, timeval *[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(timeval)), 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 futimes(fd int, timeval *[2]Timeval) (err error) {
-	_, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0)
-	if e1 != 0 {
-		err = 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 = 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)
-	if e1 != 0 {
-		err = 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) {
-	var _p0 unsafe.Pointer
-	if len(p) > 0 {
-		_p0 = unsafe.Pointer(&p[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))
-	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
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Access(path string, mode uint32) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		return
-	}
-	_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 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 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
-	}
-	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 = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Chflags(path string, flags int) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		return
-	}
-	_, _, e1 := Syscall(SYS_CHFLAGS, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 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 Chmod(path string, mode uint32) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		return
-	}
-	_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 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 Chown(path string, uid int, gid int) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		return
-	}
-	_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
-	use(unsafe.Pointer(_p0))
-	if e1 != 0 {
-		err = 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 = 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 = e1
-	}
-	return
-}
-
-// 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)
-	nfd = int(r0)
-	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// 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)
-	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Exit(code int) {
-	Syscall(SYS_EXIT, uintptr(code), 0, 0)
-	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 = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Fchflags(fd int, flags int) (err error) {
-	_, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 0)
-	if e1 != 0 {
-		err = 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 = 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 = 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 = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Fpathconf(fd int, name int) (val int, err error) {
-	r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
-	val = int(r0)
-	if e1 != 0 {
-		err = 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 = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-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
-	}
-	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 = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-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
-	}
-	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)
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Geteuid() (uid int) {
-	r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0)
-	uid = 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 Getpgid(pid int) (pgid int, err error) {
-	r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
-	pgid = int(r0)
-	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Getpgrp() (pgrp int) {
-	r0, _, _ := RawSyscall(SYS_GETPGRP, 0, 0, 0)
-	pgrp = 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)
-	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 = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Getrlimit(which int, lim *Rlimit) (err error) {
-	_, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
-	if e1 != 0 {
-		err = 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 = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Getsid(pid int) (sid int, err error) {
-	r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
-	sid = int(r0)
-	if e1 != 0 {
-		err = 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 = 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 Issetugid() (tainted bool) {
-	r0, _, _ := Syscall(SYS_ISSETUGID, 0, 0, 0)
-	tainted = bool(r0 != 0)
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Kill(pid int, signum Signal) (err error) {
-	_, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), 0)
-	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Kqueue() (fd int, err error) {
-	r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
-	fd = int(r0)
-	if e1 != 0 {
-		err = e1
-	}
-	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 = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Link(path string, link string) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		return
-	}
-	var _p1 *byte
-	_p1, err = BytePtrFromString(link)
-	if err != nil {
-		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
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Listen(s int, backlog int) (err error) {
-	_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0)
-	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Lstat(path string, stat *Stat_t) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		return
-	}
-	_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 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 Mkdir(path string, mode uint32) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		return
-	}
-	_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 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 Mkfifo(path string, mode uint32) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		return
-	}
-	_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 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 Mknod(path string, mode uint32, dev int) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		return
-	}
-	_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
-	use(unsafe.Pointer(_p0))
-	if e1 != 0 {
-		err = 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 = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Open(path string, mode int, perm uint32) (fd int, err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		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
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Pathconf(path string, name int) (val int, err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		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
-	}
-	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 = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Readlink(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 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)))
-	use(unsafe.Pointer(_p0))
-	n = int(r0)
-	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Rename(from string, to string) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(from)
-	if err != nil {
-		return
-	}
-	var _p1 *byte
-	_p1, err = BytePtrFromString(to)
-	if err != nil {
-		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
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Revoke(path string) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		return
-	}
-	_, _, e1 := Syscall(SYS_REVOKE, 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 Rmdir(path string) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		return
-	}
-	_, _, e1 := Syscall(SYS_RMDIR, 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 Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
-	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
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-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
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Setegid(egid int) (err error) {
-	_, _, e1 := RawSyscall(SYS_SETEGID, uintptr(egid), 0, 0)
-	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Seteuid(euid int) (err error) {
-	_, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0)
-	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Setgid(gid int) (err error) {
-	_, _, e1 := RawSyscall(SYS_SETGID, uintptr(gid), 0, 0)
-	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Setlogin(name string) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(name)
-	if err != nil {
-		return
-	}
-	_, _, e1 := Syscall(SYS_SETLOGIN, 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 Setpgid(pid int, pgid int) (err error) {
-	_, _, e1 := RawSyscall(SYS_SETPGID, uintptr(pid), uintptr(pgid), 0)
-	if e1 != 0 {
-		err = 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 = 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 = 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 = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Setrlimit(which int, lim *Rlimit) (err error) {
-	_, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
-	if e1 != 0 {
-		err = 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 = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Settimeofday(tp *Timeval) (err error) {
-	_, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
-	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Setuid(uid int) (err error) {
-	_, _, e1 := RawSyscall(SYS_SETUID, uintptr(uid), 0, 0)
-	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Stat(path string, stat *Stat_t) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		return
-	}
-	_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 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 Statfs(path string, stat *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(stat)), 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 Symlink(path string, link string) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		return
-	}
-	var _p1 *byte
-	_p1, err = BytePtrFromString(link)
-	if err != nil {
-		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
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Sync() (err error) {
-	_, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
-	if e1 != 0 {
-		err = 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 := Syscall6(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length), uintptr(length>>32), 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 Umask(newmask int) (oldmask int) {
-	r0, _, _ := Syscall(SYS_UMASK, uintptr(newmask), 0, 0)
-	oldmask = int(r0)
-	return
-}
-
-// 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)
-	if err != nil {
-		return
-	}
-	_, _, e1 := Syscall(SYS_UNLINK, 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 Unmount(path string, flags int) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		return
-	}
-	_, _, e1 := Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 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 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 = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) {
-	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
-	}
-	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 = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func readlen(fd int, buf *byte, nbuf int) (n int, err error) {
-	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
-	n = int(r0)
-	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func writelen(fd int, buf *byte, nbuf int) (n int, err error) {
-	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
-	n = int(r0)
-	if e1 != 0 {
-		err = e1
-	}
-	return
-}
diff --git a/src/syscall/zsyscall_dragonfly_amd64.go b/src/syscall/zsyscall_dragonfly_amd64.go
index 0121374..88e09d3 100644
--- a/src/syscall/zsyscall_dragonfly_amd64.go
+++ b/src/syscall/zsyscall_dragonfly_amd64.go
@@ -1,6 +1,8 @@
 // mksyscall.pl -dragonfly syscall_bsd.go syscall_dragonfly.go syscall_dragonfly_amd64.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build amd64,dragonfly
+
 package syscall
 
 import "unsafe"
@@ -11,7 +13,7 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
 	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 +23,7 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
 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 +34,7 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err
 	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 +45,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -53,7 +55,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
 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 +65,7 @@ func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 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 +76,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -84,7 +86,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
 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 +96,7 @@ func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen
 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 +106,7 @@ func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr)
 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 +116,7 @@ func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 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 +126,7 @@ func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 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 +136,7 @@ func Shutdown(s int, how int) (err error) {
 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 +153,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 	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 +169,7 @@ func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (
 	}
 	_, _, 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 +180,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -189,7 +191,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -200,7 +202,7 @@ func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, ne
 	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 +218,7 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr)
 	}
 	_, _, 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 +234,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 	_, _, 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 +244,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 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 +255,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -265,7 +267,7 @@ func pipe() (r int, w int, err error) {
 	r = int(r0)
 	w = int(r1)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -282,7 +284,7 @@ func extpread(fd int, p []byte, flags int, offset int64) (n int, err error) {
 	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 +301,7 @@ func extpwrite(fd int, p []byte, flags int, offset int64) (n int, err error) {
 	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 +317,7 @@ func Access(path string, mode uint32) (err error) {
 	_, _, 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 +327,7 @@ func Access(path string, mode uint32) (err error) {
 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 +343,7 @@ func Chdir(path string) (err error) {
 	_, _, 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 +359,7 @@ func Chflags(path string, flags int) (err error) {
 	_, _, 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 +375,7 @@ func Chmod(path string, mode uint32) (err error) {
 	_, _, 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 +391,7 @@ func Chown(path string, uid int, gid int) (err error) {
 	_, _, 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 +407,7 @@ func Chroot(path string) (err error) {
 	_, _, 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 +417,7 @@ func Chroot(path string) (err error) {
 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 +425,10 @@ func Close(fd int) (err error) {
 // 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 +436,9 @@ func Dup(fd int) (nfd int, err error) {
 // 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 +455,7 @@ func Exit(code int) {
 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 +465,7 @@ func Fchdir(fd int) (err error) {
 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 +475,7 @@ func Fchflags(fd int, flags int) (err error) {
 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 +485,7 @@ func Fchmod(fd int, mode uint32) (err error) {
 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 +495,7 @@ func Fchown(fd int, uid int, gid int) (err error) {
 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 +506,7 @@ func Fpathconf(fd int, name int) (val int, err error) {
 	r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -514,7 +516,7 @@ func Fpathconf(fd int, name int) (val int, err error) {
 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 +526,7 @@ func Fstat(fd int, stat *Stat_t) (err error) {
 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 +536,7 @@ func Fstatfs(fd int, stat *Statfs_t) (err error) {
 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 +546,7 @@ func Fsync(fd int) (err error) {
 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 +563,7 @@ func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
 	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 +606,7 @@ func Getpgid(pid int) (pgid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
 	pgid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -639,7 +641,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -649,7 +651,7 @@ func Getpriority(which int, who int) (prio int, err error) {
 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 +661,7 @@ func Getrlimit(which int, lim *Rlimit) (err error) {
 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 +672,7 @@ func Getsid(pid int) (sid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
 	sid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -680,7 +682,7 @@ func Getsid(pid int) (sid int, err error) {
 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 +708,7 @@ func Issetugid() (tainted bool) {
 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 +719,7 @@ func Kqueue() (fd int, err error) {
 	r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -733,7 +735,7 @@ func Lchown(path string, uid int, gid int) (err error) {
 	_, _, 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 +757,7 @@ func Link(path string, link string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -765,7 +767,7 @@ func Link(path string, link string) (err error) {
 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 +783,7 @@ func Lstat(path string, stat *Stat_t) (err error) {
 	_, _, 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 +799,7 @@ func Mkdir(path string, mode uint32) (err error) {
 	_, _, 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 +815,7 @@ func Mkfifo(path string, mode uint32) (err error) {
 	_, _, 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 +831,7 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 	_, _, 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 +841,7 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 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 +858,7 @@ func Open(path string, mode int, perm uint32) (fd int, err error) {
 	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -873,7 +875,7 @@ func Pathconf(path string, name int) (val int, err error) {
 	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -890,7 +892,7 @@ func read(fd int, p []byte) (n int, err error) {
 	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 +915,7 @@ func Readlink(path string, buf []byte) (n int, err error) {
 	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -935,7 +937,7 @@ func Rename(from string, to string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -951,7 +953,7 @@ func Revoke(path string) (err error) {
 	_, _, 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 +969,7 @@ func Rmdir(path string) (err error) {
 	_, _, 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 +980,7 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 	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 +990,7 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 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 +1000,7 @@ func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
 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 +1010,7 @@ func Setegid(egid int) (err error) {
 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 +1020,7 @@ func Seteuid(euid int) (err error) {
 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 +1036,7 @@ func Setlogin(name string) (err error) {
 	_, _, 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 +1046,7 @@ func Setlogin(name string) (err error) {
 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 +1056,7 @@ func Setpgid(pid int, pgid int) (err error) {
 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 +1066,7 @@ func Setpriority(which int, who int, prio int) (err error) {
 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 +1076,7 @@ func Setregid(rgid int, egid int) (err error) {
 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 +1086,7 @@ func Setreuid(ruid int, euid int) (err error) {
 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 +1097,7 @@ func Setsid() (pid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1105,7 +1107,7 @@ func Setsid() (pid int, err error) {
 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 +1117,7 @@ func Settimeofday(tp *Timeval) (err error) {
 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 +1133,7 @@ func Stat(path string, stat *Stat_t) (err error) {
 	_, _, 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 +1149,7 @@ func Statfs(path string, stat *Statfs_t) (err error) {
 	_, _, 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 +1171,7 @@ func Symlink(path string, link string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1179,7 +1181,7 @@ func Symlink(path string, link string) (err error) {
 func Sync() (err error) {
 	_, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1195,7 +1197,7 @@ func Truncate(path string, length int64) (err error) {
 	_, _, 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 +1221,7 @@ func Undelete(path string) (err error) {
 	_, _, 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 +1237,7 @@ func Unlink(path string) (err error) {
 	_, _, 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 +1253,7 @@ func Unmount(path string, flags int) (err error) {
 	_, _, 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 +1270,7 @@ func write(fd int, p []byte) (n int, err error) {
 	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 +1281,7 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
 	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 +1291,7 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
 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 +1302,7 @@ func readlen(fd int, buf *byte, nbuf int) (n int, err error) {
 	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 +1313,7 @@ func writelen(fd int, buf *byte, nbuf int) (n int, err error) {
 	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..30f29e5 100644
--- a/src/syscall/zsyscall_freebsd_386.go
+++ b/src/syscall/zsyscall_freebsd_386.go
@@ -1,6 +1,8 @@
 // mksyscall.pl -l32 syscall_bsd.go syscall_freebsd.go syscall_freebsd_386.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build 386,freebsd
+
 package syscall
 
 import "unsafe"
@@ -11,7 +13,7 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
 	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 +23,7 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
 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 +34,7 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err
 	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 +45,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -53,7 +55,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
 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 +65,7 @@ func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 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 +76,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -84,7 +86,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
 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 +96,7 @@ func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen
 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 +106,7 @@ func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr)
 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 +116,7 @@ func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 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 +126,7 @@ func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 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 +136,7 @@ func Shutdown(s int, how int) (err error) {
 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 +153,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 	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 +169,7 @@ func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (
 	}
 	_, _, 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 +180,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -189,7 +191,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -200,7 +202,7 @@ func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, ne
 	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 +218,7 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr)
 	}
 	_, _, 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 +234,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 	_, _, 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 +244,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 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 +255,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -265,7 +267,7 @@ func pipe() (r int, w int, err error) {
 	r = int(r0)
 	w = int(r1)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -281,7 +283,7 @@ func Access(path string, mode uint32) (err error) {
 	_, _, 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 +293,7 @@ func Access(path string, mode uint32) (err error) {
 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 +309,7 @@ func Chdir(path string) (err error) {
 	_, _, 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 +325,7 @@ func Chflags(path string, flags int) (err error) {
 	_, _, 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 +341,7 @@ func Chmod(path string, mode uint32) (err error) {
 	_, _, 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 +357,7 @@ func Chown(path string, uid int, gid int) (err error) {
 	_, _, 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 +373,7 @@ func Chroot(path string) (err error) {
 	_, _, 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 +383,7 @@ func Chroot(path string) (err error) {
 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 +391,10 @@ func Close(fd int) (err error) {
 // 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 +402,9 @@ func Dup(fd int) (nfd int, err error) {
 // 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 +421,7 @@ func Exit(code int) {
 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 +431,7 @@ func Fchdir(fd int) (err error) {
 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 +441,7 @@ func Fchflags(fd int, flags int) (err error) {
 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 +451,7 @@ func Fchmod(fd int, mode uint32) (err error) {
 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 +461,7 @@ func Fchown(fd int, uid int, gid int) (err error) {
 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 +472,7 @@ func Fpathconf(fd int, name int) (val int, err error) {
 	r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -480,7 +482,7 @@ func Fpathconf(fd int, name int) (val int, err error) {
 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 +492,7 @@ func Fstat(fd int, stat *Stat_t) (err error) {
 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 +502,7 @@ func Fstatfs(fd int, stat *Statfs_t) (err error) {
 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 +512,7 @@ func Fsync(fd int) (err error) {
 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 +529,7 @@ func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
 	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 +572,7 @@ func Getpgid(pid int) (pgid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
 	pgid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -605,7 +607,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -615,7 +617,7 @@ func Getpriority(which int, who int) (prio int, err error) {
 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 +627,7 @@ func Getrlimit(which int, lim *Rlimit) (err error) {
 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 +638,7 @@ func Getsid(pid int) (sid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
 	sid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -646,7 +648,7 @@ func Getsid(pid int) (sid int, err error) {
 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 +674,7 @@ func Issetugid() (tainted bool) {
 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 +685,7 @@ func Kqueue() (fd int, err error) {
 	r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -699,7 +701,7 @@ func Lchown(path string, uid int, gid int) (err error) {
 	_, _, 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 +723,7 @@ func Link(path string, link string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -731,7 +733,7 @@ func Link(path string, link string) (err error) {
 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 +749,7 @@ func Lstat(path string, stat *Stat_t) (err error) {
 	_, _, 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 +765,7 @@ func Mkdir(path string, mode uint32) (err error) {
 	_, _, 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 +781,7 @@ func Mkfifo(path string, mode uint32) (err error) {
 	_, _, 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 +797,7 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 	_, _, 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 +807,7 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 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 +824,7 @@ func Open(path string, mode int, perm uint32) (fd int, err error) {
 	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -839,7 +841,7 @@ func Pathconf(path string, name int) (val int, err error) {
 	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -856,7 +858,7 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) {
 	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 +875,7 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
 	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 +892,7 @@ func read(fd int, p []byte) (n int, err error) {
 	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 +915,7 @@ func Readlink(path string, buf []byte) (n int, err error) {
 	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -935,7 +937,7 @@ func Rename(from string, to string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -951,7 +953,7 @@ func Revoke(path string) (err error) {
 	_, _, 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 +969,7 @@ func Rmdir(path string) (err error) {
 	_, _, 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 +980,7 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 	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 +990,7 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 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 +1000,7 @@ func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
 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 +1010,7 @@ func Setegid(egid int) (err error) {
 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 +1020,7 @@ func Seteuid(euid int) (err error) {
 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 +1036,7 @@ func Setlogin(name string) (err error) {
 	_, _, 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 +1046,7 @@ func Setlogin(name string) (err error) {
 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 +1056,7 @@ func Setpgid(pid int, pgid int) (err error) {
 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 +1066,7 @@ func Setpriority(which int, who int, prio int) (err error) {
 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 +1076,7 @@ func Setregid(rgid int, egid int) (err error) {
 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 +1086,7 @@ func Setreuid(ruid int, euid int) (err error) {
 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 +1097,7 @@ func Setsid() (pid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1105,7 +1107,7 @@ func Setsid() (pid int, err error) {
 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 +1117,7 @@ func Settimeofday(tp *Timeval) (err error) {
 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 +1133,7 @@ func Stat(path string, stat *Stat_t) (err error) {
 	_, _, 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 +1149,7 @@ func Statfs(path string, stat *Statfs_t) (err error) {
 	_, _, 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 +1171,7 @@ func Symlink(path string, link string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1179,7 +1181,7 @@ func Symlink(path string, link string) (err error) {
 func Sync() (err error) {
 	_, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1195,7 +1197,7 @@ func Truncate(path string, length int64) (err error) {
 	_, _, 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 +1221,7 @@ func Undelete(path string) (err error) {
 	_, _, 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 +1237,7 @@ func Unlink(path string) (err error) {
 	_, _, 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 +1253,7 @@ func Unmount(path string, flags int) (err error) {
 	_, _, 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 +1270,7 @@ func write(fd int, p []byte) (n int, err error) {
 	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 +1281,7 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
 	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 +1291,7 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
 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 +1302,7 @@ func readlen(fd int, buf *byte, nbuf int) (n int, err error) {
 	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 +1313,7 @@ func writelen(fd int, buf *byte, nbuf int) (n int, err error) {
 	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 +1324,7 @@ func accept4(fd int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (nfd int
 	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..93059d1 100644
--- a/src/syscall/zsyscall_freebsd_amd64.go
+++ b/src/syscall/zsyscall_freebsd_amd64.go
@@ -1,6 +1,8 @@
 // mksyscall.pl syscall_bsd.go syscall_freebsd.go syscall_freebsd_amd64.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build amd64,freebsd
+
 package syscall
 
 import "unsafe"
@@ -11,7 +13,7 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
 	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 +23,7 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
 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 +34,7 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err
 	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 +45,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -53,7 +55,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
 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 +65,7 @@ func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 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 +76,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -84,7 +86,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
 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 +96,7 @@ func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen
 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 +106,7 @@ func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr)
 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 +116,7 @@ func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 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 +126,7 @@ func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 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 +136,7 @@ func Shutdown(s int, how int) (err error) {
 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 +153,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 	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 +169,7 @@ func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (
 	}
 	_, _, 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 +180,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -189,7 +191,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -200,7 +202,7 @@ func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, ne
 	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 +218,7 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr)
 	}
 	_, _, 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 +234,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 	_, _, 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 +244,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 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 +255,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -265,7 +267,7 @@ func pipe() (r int, w int, err error) {
 	r = int(r0)
 	w = int(r1)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -281,7 +283,7 @@ func Access(path string, mode uint32) (err error) {
 	_, _, 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 +293,7 @@ func Access(path string, mode uint32) (err error) {
 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 +309,7 @@ func Chdir(path string) (err error) {
 	_, _, 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 +325,7 @@ func Chflags(path string, flags int) (err error) {
 	_, _, 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 +341,7 @@ func Chmod(path string, mode uint32) (err error) {
 	_, _, 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 +357,7 @@ func Chown(path string, uid int, gid int) (err error) {
 	_, _, 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 +373,7 @@ func Chroot(path string) (err error) {
 	_, _, 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 +383,7 @@ func Chroot(path string) (err error) {
 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 +391,10 @@ func Close(fd int) (err error) {
 // 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 +402,9 @@ func Dup(fd int) (nfd int, err error) {
 // 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 +421,7 @@ func Exit(code int) {
 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 +431,7 @@ func Fchdir(fd int) (err error) {
 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 +441,7 @@ func Fchflags(fd int, flags int) (err error) {
 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 +451,7 @@ func Fchmod(fd int, mode uint32) (err error) {
 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 +461,7 @@ func Fchown(fd int, uid int, gid int) (err error) {
 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 +472,7 @@ func Fpathconf(fd int, name int) (val int, err error) {
 	r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -480,7 +482,7 @@ func Fpathconf(fd int, name int) (val int, err error) {
 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 +492,7 @@ func Fstat(fd int, stat *Stat_t) (err error) {
 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 +502,7 @@ func Fstatfs(fd int, stat *Statfs_t) (err error) {
 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 +512,7 @@ func Fsync(fd int) (err error) {
 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 +529,7 @@ func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
 	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 +572,7 @@ func Getpgid(pid int) (pgid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
 	pgid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -605,7 +607,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -615,7 +617,7 @@ func Getpriority(which int, who int) (prio int, err error) {
 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 +627,7 @@ func Getrlimit(which int, lim *Rlimit) (err error) {
 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 +638,7 @@ func Getsid(pid int) (sid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
 	sid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -646,7 +648,7 @@ func Getsid(pid int) (sid int, err error) {
 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 +674,7 @@ func Issetugid() (tainted bool) {
 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 +685,7 @@ func Kqueue() (fd int, err error) {
 	r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -699,7 +701,7 @@ func Lchown(path string, uid int, gid int) (err error) {
 	_, _, 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 +723,7 @@ func Link(path string, link string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -731,7 +733,7 @@ func Link(path string, link string) (err error) {
 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 +749,7 @@ func Lstat(path string, stat *Stat_t) (err error) {
 	_, _, 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 +765,7 @@ func Mkdir(path string, mode uint32) (err error) {
 	_, _, 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 +781,7 @@ func Mkfifo(path string, mode uint32) (err error) {
 	_, _, 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 +797,7 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 	_, _, 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 +807,7 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 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 +824,7 @@ func Open(path string, mode int, perm uint32) (fd int, err error) {
 	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -839,7 +841,7 @@ func Pathconf(path string, name int) (val int, err error) {
 	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -856,7 +858,7 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) {
 	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 +875,7 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
 	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 +892,7 @@ func read(fd int, p []byte) (n int, err error) {
 	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 +915,7 @@ func Readlink(path string, buf []byte) (n int, err error) {
 	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -935,7 +937,7 @@ func Rename(from string, to string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -951,7 +953,7 @@ func Revoke(path string) (err error) {
 	_, _, 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 +969,7 @@ func Rmdir(path string) (err error) {
 	_, _, 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 +980,7 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 	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 +990,7 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 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 +1000,7 @@ func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
 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 +1010,7 @@ func Setegid(egid int) (err error) {
 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 +1020,7 @@ func Seteuid(euid int) (err error) {
 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 +1036,7 @@ func Setlogin(name string) (err error) {
 	_, _, 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 +1046,7 @@ func Setlogin(name string) (err error) {
 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 +1056,7 @@ func Setpgid(pid int, pgid int) (err error) {
 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 +1066,7 @@ func Setpriority(which int, who int, prio int) (err error) {
 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 +1076,7 @@ func Setregid(rgid int, egid int) (err error) {
 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 +1086,7 @@ func Setreuid(ruid int, euid int) (err error) {
 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 +1097,7 @@ func Setsid() (pid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1105,7 +1107,7 @@ func Setsid() (pid int, err error) {
 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 +1117,7 @@ func Settimeofday(tp *Timeval) (err error) {
 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 +1133,7 @@ func Stat(path string, stat *Stat_t) (err error) {
 	_, _, 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 +1149,7 @@ func Statfs(path string, stat *Statfs_t) (err error) {
 	_, _, 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 +1171,7 @@ func Symlink(path string, link string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1179,7 +1181,7 @@ func Symlink(path string, link string) (err error) {
 func Sync() (err error) {
 	_, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1195,7 +1197,7 @@ func Truncate(path string, length int64) (err error) {
 	_, _, 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 +1221,7 @@ func Undelete(path string) (err error) {
 	_, _, 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 +1237,7 @@ func Unlink(path string) (err error) {
 	_, _, 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 +1253,7 @@ func Unmount(path string, flags int) (err error) {
 	_, _, 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 +1270,7 @@ func write(fd int, p []byte) (n int, err error) {
 	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 +1281,7 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
 	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 +1291,7 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
 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 +1302,7 @@ func readlen(fd int, buf *byte, nbuf int) (n int, err error) {
 	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 +1313,7 @@ func writelen(fd int, buf *byte, nbuf int) (n int, err error) {
 	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 +1324,7 @@ func accept4(fd int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (nfd int
 	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..84096b0 100644
--- a/src/syscall/zsyscall_freebsd_arm.go
+++ b/src/syscall/zsyscall_freebsd_arm.go
@@ -1,6 +1,8 @@
 // mksyscall.pl -l32 -arm syscall_bsd.go syscall_freebsd.go syscall_freebsd_arm.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build arm,freebsd
+
 package syscall
 
 import "unsafe"
@@ -11,7 +13,7 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
 	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 +23,7 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
 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 +34,7 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err
 	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 +45,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -53,7 +55,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
 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 +65,7 @@ func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 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 +76,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -84,7 +86,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
 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 +96,7 @@ func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen
 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 +106,7 @@ func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr)
 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 +116,7 @@ func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 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 +126,7 @@ func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 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 +136,7 @@ func Shutdown(s int, how int) (err error) {
 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 +153,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 	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 +169,7 @@ func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (
 	}
 	_, _, 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 +180,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -189,7 +191,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -200,7 +202,7 @@ func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, ne
 	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 +218,7 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr)
 	}
 	_, _, 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 +234,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 	_, _, 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 +244,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 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 +255,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -265,7 +267,7 @@ func pipe() (r int, w int, err error) {
 	r = int(r0)
 	w = int(r1)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -281,7 +283,7 @@ func Access(path string, mode uint32) (err error) {
 	_, _, 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 +293,7 @@ func Access(path string, mode uint32) (err error) {
 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 +309,7 @@ func Chdir(path string) (err error) {
 	_, _, 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 +325,7 @@ func Chflags(path string, flags int) (err error) {
 	_, _, 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 +341,7 @@ func Chmod(path string, mode uint32) (err error) {
 	_, _, 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 +357,7 @@ func Chown(path string, uid int, gid int) (err error) {
 	_, _, 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 +373,7 @@ func Chroot(path string) (err error) {
 	_, _, 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 +383,7 @@ func Chroot(path string) (err error) {
 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 +391,10 @@ func Close(fd int) (err error) {
 // 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 +402,9 @@ func Dup(fd int) (nfd int, err error) {
 // 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 +421,7 @@ func Exit(code int) {
 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 +431,7 @@ func Fchdir(fd int) (err error) {
 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 +441,7 @@ func Fchflags(fd int, flags int) (err error) {
 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 +451,7 @@ func Fchmod(fd int, mode uint32) (err error) {
 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 +461,7 @@ func Fchown(fd int, uid int, gid int) (err error) {
 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 +472,7 @@ func Fpathconf(fd int, name int) (val int, err error) {
 	r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -480,7 +482,7 @@ func Fpathconf(fd int, name int) (val int, err error) {
 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 +492,7 @@ func Fstat(fd int, stat *Stat_t) (err error) {
 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 +502,7 @@ func Fstatfs(fd int, stat *Statfs_t) (err error) {
 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 +512,7 @@ func Fsync(fd int) (err error) {
 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 +529,7 @@ func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
 	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 +572,7 @@ func Getpgid(pid int) (pgid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
 	pgid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -605,7 +607,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -615,7 +617,7 @@ func Getpriority(which int, who int) (prio int, err error) {
 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 +627,7 @@ func Getrlimit(which int, lim *Rlimit) (err error) {
 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 +638,7 @@ func Getsid(pid int) (sid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
 	sid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -646,7 +648,7 @@ func Getsid(pid int) (sid int, err error) {
 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 +674,7 @@ func Issetugid() (tainted bool) {
 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 +685,7 @@ func Kqueue() (fd int, err error) {
 	r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -699,7 +701,7 @@ func Lchown(path string, uid int, gid int) (err error) {
 	_, _, 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 +723,7 @@ func Link(path string, link string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -731,7 +733,7 @@ func Link(path string, link string) (err error) {
 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 +749,7 @@ func Lstat(path string, stat *Stat_t) (err error) {
 	_, _, 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 +765,7 @@ func Mkdir(path string, mode uint32) (err error) {
 	_, _, 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 +781,7 @@ func Mkfifo(path string, mode uint32) (err error) {
 	_, _, 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 +797,7 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 	_, _, 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 +807,7 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 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 +824,7 @@ func Open(path string, mode int, perm uint32) (fd int, err error) {
 	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -839,7 +841,7 @@ func Pathconf(path string, name int) (val int, err error) {
 	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -856,7 +858,7 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) {
 	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 +875,7 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
 	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 +892,7 @@ func read(fd int, p []byte) (n int, err error) {
 	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 +915,7 @@ func Readlink(path string, buf []byte) (n int, err error) {
 	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -935,7 +937,7 @@ func Rename(from string, to string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -951,7 +953,7 @@ func Revoke(path string) (err error) {
 	_, _, 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 +969,7 @@ func Rmdir(path string) (err error) {
 	_, _, 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 +980,7 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 	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 +990,7 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 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 +1000,7 @@ func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
 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 +1010,7 @@ func Setegid(egid int) (err error) {
 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 +1020,7 @@ func Seteuid(euid int) (err error) {
 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 +1036,7 @@ func Setlogin(name string) (err error) {
 	_, _, 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 +1046,7 @@ func Setlogin(name string) (err error) {
 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 +1056,7 @@ func Setpgid(pid int, pgid int) (err error) {
 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 +1066,7 @@ func Setpriority(which int, who int, prio int) (err error) {
 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 +1076,7 @@ func Setregid(rgid int, egid int) (err error) {
 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 +1086,7 @@ func Setreuid(ruid int, euid int) (err error) {
 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 +1097,7 @@ func Setsid() (pid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1105,7 +1107,7 @@ func Setsid() (pid int, err error) {
 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 +1117,7 @@ func Settimeofday(tp *Timeval) (err error) {
 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 +1133,7 @@ func Stat(path string, stat *Stat_t) (err error) {
 	_, _, 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 +1149,7 @@ func Statfs(path string, stat *Statfs_t) (err error) {
 	_, _, 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 +1171,7 @@ func Symlink(path string, link string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1179,7 +1181,7 @@ func Symlink(path string, link string) (err error) {
 func Sync() (err error) {
 	_, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1195,7 +1197,7 @@ func Truncate(path string, length int64) (err error) {
 	_, _, 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 +1221,7 @@ func Undelete(path string) (err error) {
 	_, _, 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 +1237,7 @@ func Unlink(path string) (err error) {
 	_, _, 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 +1253,7 @@ func Unmount(path string, flags int) (err error) {
 	_, _, 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 +1270,7 @@ func write(fd int, p []byte) (n int, err error) {
 	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 +1281,7 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
 	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 +1291,7 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
 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 +1302,7 @@ func readlen(fd int, buf *byte, nbuf int) (n int, err error) {
 	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 +1313,7 @@ func writelen(fd int, buf *byte, nbuf int) (n int, err error) {
 	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 +1324,7 @@ func accept4(fd int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (nfd int
 	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 dee8343..620fba2 100644
--- a/src/syscall/zsyscall_linux_386.go
+++ b/src/syscall/zsyscall_linux_386.go
@@ -1,23 +1,30 @@
 // mksyscall.pl -l32 syscall_linux.go syscall_linux_386.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build 386,linux
+
 package syscall
 
 import "unsafe"
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func open(path string, mode int, perm uint32) (fd int, err error) {
+func linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) {
 	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
+	_p0, err = BytePtrFromString(oldpath)
+	if err != nil {
+		return
+	}
+	var _p1 *byte
+	_p1, err = BytePtrFromString(newpath)
 	if err != nil {
 		return
 	}
-	r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm))
+	_, _, e1 := Syscall6(SYS_LINKAT, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
-	fd = int(r0)
+	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -34,27 +41,68 @@ func openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)
 	use(unsafe.Pointer(_p0))
 	fd = 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(p *[2]_C_int) (err error) {
-	_, _, e1 := RawSyscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
+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 = e1
+		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)
+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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -70,7 +118,7 @@ func utimes(path string, times *[2]Timeval) (err error) {
 	_, _, 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
 }
@@ -86,7 +134,7 @@ func utimensat(dirfd int, path string, times *[2]Timespec) (err error) {
 	_, _, 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
 }
@@ -96,7 +144,7 @@ func utimensat(dirfd int, path string, times *[2]Timespec) (err error) {
 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
 }
@@ -113,7 +161,7 @@ func Getcwd(buf []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_GETCWD, uintptr(_p0), uintptr(len(buf)), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -124,7 +172,7 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err
 	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
 }
@@ -134,7 +182,7 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err
 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
 }
@@ -150,7 +198,7 @@ func reboot(magic1 uint, magic2 uint, cmd int, arg string) (err error) {
 	_, _, 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
 }
@@ -178,23 +226,7 @@ func mount(source string, target string, fstype string, flags uintptr, data *byt
 	use(unsafe.Pointer(_p1))
 	use(unsafe.Pointer(_p2))
 	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Access(path string, mode uint32) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		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
 }
@@ -210,7 +242,7 @@ func Acct(path string) (err error) {
 	_, _, e1 := Syscall(SYS_ACCT, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -221,7 +253,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -237,23 +269,7 @@ func Chdir(path string) (err error) {
 	_, _, e1 := Syscall(SYS_CHDIR, 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 Chmod(path string, mode uint32) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		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
 }
@@ -269,7 +285,7 @@ func Chroot(path string) (err error) {
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -279,24 +295,7 @@ func Chroot(path string) (err error) {
 func Close(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Creat(path string, mode uint32) (fd int, err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		return
-	}
-	r0, _, e1 := Syscall(SYS_CREAT, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
-	fd = int(r0)
-	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -304,20 +303,10 @@ func Creat(path string, mode uint32) (fd int, err error) {
 // 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
-	}
-	return
-}
-
-// 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)
-	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -325,9 +314,9 @@ func Dup2(oldfd int, newfd int) (err error) {
 // 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
 }
@@ -338,7 +327,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -349,7 +338,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -359,7 +348,7 @@ func EpollCreate1(flag int) (fd int, err error) {
 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
 }
@@ -376,7 +365,7 @@ func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
 	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
 }
@@ -399,7 +388,7 @@ func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
 	_, _, 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
 }
@@ -409,7 +398,7 @@ func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
 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
 }
@@ -419,7 +408,7 @@ func Fallocate(fd int, mode uint32, off int64, len int64) (err error) {
 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 +418,7 @@ func Fchdir(fd int) (err error) {
 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
 }
@@ -445,7 +434,7 @@ func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
 	_, _, 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
 }
@@ -461,7 +450,7 @@ func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) {
 	_, _, 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
 }
@@ -472,7 +461,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -482,7 +471,7 @@ func fcntl(fd int, cmd int, arg int) (val int, err error) {
 func Fdatasync(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FDATASYNC, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -492,7 +481,7 @@ func Fdatasync(fd int) (err error) {
 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
 }
@@ -502,7 +491,7 @@ func Flock(fd int, how int) (err error) {
 func Fsync(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -519,7 +508,7 @@ func Getdents(fd int, buf []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_GETDENTS64, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -530,21 +519,13 @@ func Getpgid(pid int) (pgid int, err error) {
 	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)
@@ -565,7 +546,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -575,7 +556,7 @@ func Getpriority(which int, who int) (prio int, err error) {
 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
 }
@@ -612,7 +593,7 @@ func Getxattr(path string, attr string, dest []byte) (sz int, err error) {
 	use(unsafe.Pointer(_p1))
 	sz = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -629,18 +610,7 @@ func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err e
 	use(unsafe.Pointer(_p0))
 	watchdesc = int(r0)
 	if e1 != 0 {
-		err = 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -651,7 +621,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -662,7 +632,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -672,7 +642,7 @@ func InotifyRmWatch(fd int, watchdesc uint32) (success int, err error) {
 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
 }
@@ -689,29 +659,7 @@ func Klogctl(typ int, buf []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_SYSLOG, uintptr(typ), 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 Link(oldpath string, 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_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
 }
@@ -734,23 +682,7 @@ func Listxattr(path string, dest []byte) (sz int, err error) {
 	use(unsafe.Pointer(_p0))
 	sz = int(r0)
 	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Mkdir(path string, mode uint32) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		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
 }
@@ -766,23 +698,7 @@ func Mkdirat(dirfd int, path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Mknod(path string, mode uint32, dev int) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		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
 }
@@ -798,7 +714,7 @@ func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) {
 	_, _, 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
 }
@@ -808,7 +724,7 @@ func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) {
 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
 }
@@ -818,7 +734,7 @@ func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
 func Pause() (err error) {
 	_, _, e1 := Syscall(SYS_PAUSE, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -840,7 +756,7 @@ func PivotRoot(newroot string, putold string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -850,7 +766,7 @@ func PivotRoot(newroot string, putold string) (err error) {
 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
 }
@@ -867,30 +783,7 @@ func read(fd int, p []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Readlink(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 := 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
 }
@@ -912,29 +805,7 @@ func Removexattr(path string, attr string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Rename(oldpath string, 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_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
 }
@@ -956,23 +827,7 @@ func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err e
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Rmdir(path string) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		return
-	}
-	_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
-	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -988,7 +843,7 @@ func Setdomainname(p []byte) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_SETDOMAINNAME, uintptr(_p0), uintptr(len(p)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1004,7 +859,7 @@ func Sethostname(p []byte) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_SETHOSTNAME, uintptr(_p0), uintptr(len(p)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1014,7 +869,7 @@ func Sethostname(p []byte) (err error) {
 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
 }
@@ -1025,7 +880,7 @@ func Setsid() (pid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1035,7 +890,7 @@ func Setsid() (pid int, err error) {
 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
 }
@@ -1045,7 +900,7 @@ func Settimeofday(tv *Timeval) (err error) {
 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
 }
@@ -1073,29 +928,7 @@ func Setxattr(path string, attr string, data []byte, flags int) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Symlink(oldpath string, 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_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
 }
@@ -1112,7 +945,7 @@ func Sync() {
 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
 }
@@ -1123,7 +956,7 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
 	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
 }
@@ -1133,7 +966,7 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
 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
 }
@@ -1144,7 +977,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1162,39 +995,7 @@ func Umask(mask int) (oldmask int) {
 func Uname(buf *Utsname) (err error) {
 	_, _, e1 := RawSyscall(SYS_UNAME, uintptr(unsafe.Pointer(buf)), 0, 0)
 	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)
-	if err != nil {
-		return
-	}
-	_, _, e1 := Syscall(SYS_UNLINK, 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 Unlinkat(dirfd int, path string) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		return
-	}
-	_, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), 0)
-	use(unsafe.Pointer(_p0))
-	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1210,7 +1011,7 @@ func Unmount(target string, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_UMOUNT2, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1220,7 +1021,7 @@ func Unmount(target string, flags int) (err error) {
 func Unshare(flags int) (err error) {
 	_, _, e1 := Syscall(SYS_UNSHARE, uintptr(flags), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1230,7 +1031,7 @@ func Unshare(flags int) (err error) {
 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
 }
@@ -1246,7 +1047,7 @@ func Utime(path string, buf *Utimbuf) (err error) {
 	_, _, 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
 }
@@ -1263,7 +1064,7 @@ func write(fd int, p []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1273,7 +1074,7 @@ func write(fd int, p []byte) (n int, err error) {
 func exitThread(code int) (err error) {
 	_, _, e1 := Syscall(SYS_EXIT, uintptr(code), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1284,7 +1085,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1295,7 +1096,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1305,7 +1106,7 @@ func writelen(fd int, p *byte, np int) (n int, err error) {
 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
 }
@@ -1321,7 +1122,7 @@ func Madvise(b []byte, advice int) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_MADVISE, uintptr(_p0), uintptr(len(b)), uintptr(advice))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1337,7 +1138,7 @@ func Mprotect(b []byte, prot int) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1353,7 +1154,7 @@ func Mlock(b []byte) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1369,7 +1170,7 @@ func Munlock(b []byte) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1379,7 +1180,7 @@ func Munlock(b []byte) (err error) {
 func Mlockall(flags int) (err error) {
 	_, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1389,23 +1190,37 @@ func Mlockall(flags int) (err error) {
 func Munlockall() (err error) {
 	_, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 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 Chown(path string, uid int, gid int) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		return
+func pipe(p *[2]_C_int) (err error) {
+	_, _, e1 := RawSyscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
 	}
-	_, _, e1 := Syscall(SYS_CHOWN32, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
-	use(unsafe.Pointer(_p0))
+	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 = e1
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Dup2(oldfd int, newfd int) (err error) {
+	_, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1415,7 +1230,7 @@ func Chown(path string, uid int, gid int) (err error) {
 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
 }
@@ -1425,7 +1240,7 @@ func Fchown(fd int, uid int, gid int) (err error) {
 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
 }
@@ -1435,7 +1250,7 @@ func Fstat(fd int, stat *Stat_t) (err error) {
 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
 }
@@ -1474,10 +1289,21 @@ func Getuid() (uid int) {
 
 // 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 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
 }
@@ -1487,7 +1313,7 @@ func Ioperm(from int, num int, on int) (err error) {
 func Iopl(level int) (err error) {
 	_, _, e1 := Syscall(SYS_IOPL, uintptr(level), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1503,7 +1329,7 @@ func Lchown(path string, uid int, gid int) (err error) {
 	_, _, 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
 }
@@ -1519,7 +1345,7 @@ func Lstat(path string, stat *Stat_t) (err error) {
 	_, _, 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
 }
@@ -1536,7 +1362,7 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) {
 	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
 }
@@ -1553,7 +1379,7 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
 	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
 }
@@ -1564,7 +1390,7 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
 	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
 }
@@ -1574,7 +1400,7 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
 func Setfsgid(gid int) (err error) {
 	_, _, e1 := Syscall(SYS_SETFSGID32, uintptr(gid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1584,7 +1410,7 @@ func Setfsgid(gid int) (err error) {
 func Setfsuid(uid int) (err error) {
 	_, _, e1 := Syscall(SYS_SETFSUID32, uintptr(uid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1594,7 +1420,7 @@ func Setfsuid(uid int) (err error) {
 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
 }
@@ -1604,7 +1430,7 @@ func Setregid(rgid int, egid int) (err error) {
 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
 }
@@ -1614,7 +1440,7 @@ func Setresgid(rgid int, egid int, sgid int) (err error) {
 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
 }
@@ -1624,7 +1450,7 @@ func Setresuid(ruid int, euid int, suid int) (err error) {
 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
 }
@@ -1635,7 +1461,7 @@ func Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n i
 	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
 }
@@ -1651,7 +1477,7 @@ func Stat(path string, stat *Stat_t) (err error) {
 	_, _, 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
 }
@@ -1661,7 +1487,7 @@ func Stat(path string, stat *Stat_t) (err error) {
 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
 }
@@ -1677,7 +1503,7 @@ func Truncate(path string, length int64) (err error) {
 	_, _, 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
 }
@@ -1688,7 +1514,7 @@ func getgroups(n int, list *_Gid_t) (nn int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETGROUPS32, uintptr(n), uintptr(unsafe.Pointer(list)), 0)
 	nn = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1698,7 +1524,7 @@ func getgroups(n int, list *_Gid_t) (nn int, err error) {
 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
 }
@@ -1709,7 +1535,7 @@ func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err
 	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
 }
@@ -1720,7 +1546,7 @@ func mmap2(addr uintptr, length uintptr, prot int, flags int, fd int, pageOffset
 	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
 }
@@ -1730,7 +1556,7 @@ func mmap2(addr uintptr, length uintptr, prot int, flags int, fd int, pageOffset
 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
 }
@@ -1740,7 +1566,7 @@ func getrlimit(resource int, rlim *rlimit32) (err error) {
 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
 }
@@ -1750,7 +1576,7 @@ func setrlimit(resource int, rlim *rlimit32) (err error) {
 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
 }
@@ -1761,7 +1587,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
diff --git a/src/syscall/zsyscall_linux_amd64.go b/src/syscall/zsyscall_linux_amd64.go
index ed3afd4..16cafbf 100644
--- a/src/syscall/zsyscall_linux_amd64.go
+++ b/src/syscall/zsyscall_linux_amd64.go
@@ -1,23 +1,30 @@
 // mksyscall.pl syscall_linux.go syscall_linux_amd64.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build amd64,linux
+
 package syscall
 
 import "unsafe"
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func open(path string, mode int, perm uint32) (fd int, err error) {
+func linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) {
 	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
+	_p0, err = BytePtrFromString(oldpath)
+	if err != nil {
+		return
+	}
+	var _p1 *byte
+	_p1, err = BytePtrFromString(newpath)
 	if err != nil {
 		return
 	}
-	r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm))
+	_, _, e1 := Syscall6(SYS_LINKAT, uintptr(olddirfd), uintptr(unsafe.Pointer(_p0)), uintptr(newdirfd), uintptr(unsafe.Pointer(_p1)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
-	fd = int(r0)
+	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -34,27 +41,68 @@ func openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)
 	use(unsafe.Pointer(_p0))
 	fd = 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(p *[2]_C_int) (err error) {
-	_, _, e1 := RawSyscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
+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 = e1
+		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)
+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 = e1
+		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
 }
@@ -70,7 +118,7 @@ func utimes(path string, times *[2]Timeval) (err error) {
 	_, _, 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
 }
@@ -86,7 +134,7 @@ func utimensat(dirfd int, path string, times *[2]Timespec) (err error) {
 	_, _, 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
 }
@@ -96,7 +144,7 @@ func utimensat(dirfd int, path string, times *[2]Timespec) (err error) {
 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
 }
@@ -113,7 +161,7 @@ func Getcwd(buf []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_GETCWD, uintptr(_p0), uintptr(len(buf)), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -124,7 +172,7 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err
 	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
 }
@@ -134,7 +182,7 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err
 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
 }
@@ -150,7 +198,7 @@ func reboot(magic1 uint, magic2 uint, cmd int, arg string) (err error) {
 	_, _, 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
 }
@@ -178,23 +226,7 @@ func mount(source string, target string, fstype string, flags uintptr, data *byt
 	use(unsafe.Pointer(_p1))
 	use(unsafe.Pointer(_p2))
 	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Access(path string, mode uint32) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		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
 }
@@ -210,7 +242,7 @@ func Acct(path string) (err error) {
 	_, _, e1 := Syscall(SYS_ACCT, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -221,7 +253,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -237,23 +269,7 @@ func Chdir(path string) (err error) {
 	_, _, e1 := Syscall(SYS_CHDIR, 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 Chmod(path string, mode uint32) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		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
 }
@@ -269,7 +285,7 @@ func Chroot(path string) (err error) {
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -279,24 +295,7 @@ func Chroot(path string) (err error) {
 func Close(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Creat(path string, mode uint32) (fd int, err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		return
-	}
-	r0, _, e1 := Syscall(SYS_CREAT, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
-	fd = int(r0)
-	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -304,20 +303,10 @@ func Creat(path string, mode uint32) (fd int, err error) {
 // 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
-	}
-	return
-}
-
-// 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)
-	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -325,9 +314,9 @@ func Dup2(oldfd int, newfd int) (err error) {
 // 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
 }
@@ -338,7 +327,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -349,7 +338,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -359,7 +348,7 @@ func EpollCreate1(flag int) (fd int, err error) {
 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
 }
@@ -376,7 +365,7 @@ func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
 	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
 }
@@ -399,7 +388,7 @@ func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
 	_, _, 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
 }
@@ -409,7 +398,7 @@ func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
 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
 }
@@ -419,7 +408,7 @@ func Fallocate(fd int, mode uint32, off int64, len int64) (err error) {
 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 +418,7 @@ func Fchdir(fd int) (err error) {
 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
 }
@@ -445,7 +434,7 @@ func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
 	_, _, 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
 }
@@ -461,7 +450,7 @@ func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) {
 	_, _, 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
 }
@@ -472,7 +461,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -482,7 +471,7 @@ func fcntl(fd int, cmd int, arg int) (val int, err error) {
 func Fdatasync(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FDATASYNC, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -492,7 +481,7 @@ func Fdatasync(fd int) (err error) {
 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
 }
@@ -502,7 +491,7 @@ func Flock(fd int, how int) (err error) {
 func Fsync(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -519,7 +508,7 @@ func Getdents(fd int, buf []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_GETDENTS64, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -530,21 +519,13 @@ func Getpgid(pid int) (pgid int, err error) {
 	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)
@@ -565,7 +546,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -575,7 +556,7 @@ func Getpriority(which int, who int) (prio int, err error) {
 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
 }
@@ -612,7 +593,7 @@ func Getxattr(path string, attr string, dest []byte) (sz int, err error) {
 	use(unsafe.Pointer(_p1))
 	sz = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -629,18 +610,7 @@ func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err e
 	use(unsafe.Pointer(_p0))
 	watchdesc = int(r0)
 	if e1 != 0 {
-		err = 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -651,7 +621,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -662,7 +632,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -672,7 +642,7 @@ func InotifyRmWatch(fd int, watchdesc uint32) (success int, err error) {
 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
 }
@@ -689,29 +659,7 @@ func Klogctl(typ int, buf []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_SYSLOG, uintptr(typ), 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 Link(oldpath string, 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_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
 }
@@ -734,23 +682,7 @@ func Listxattr(path string, dest []byte) (sz int, err error) {
 	use(unsafe.Pointer(_p0))
 	sz = int(r0)
 	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Mkdir(path string, mode uint32) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		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
 }
@@ -766,23 +698,7 @@ func Mkdirat(dirfd int, path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Mknod(path string, mode uint32, dev int) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		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
 }
@@ -798,7 +714,7 @@ func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) {
 	_, _, 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
 }
@@ -808,7 +724,7 @@ func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) {
 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
 }
@@ -818,7 +734,7 @@ func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
 func Pause() (err error) {
 	_, _, e1 := Syscall(SYS_PAUSE, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -840,7 +756,7 @@ func PivotRoot(newroot string, putold string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -850,7 +766,7 @@ func PivotRoot(newroot string, putold string) (err error) {
 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
 }
@@ -867,30 +783,7 @@ func read(fd int, p []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Readlink(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 := 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
 }
@@ -912,29 +805,7 @@ func Removexattr(path string, attr string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Rename(oldpath string, 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_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
 }
@@ -956,23 +827,7 @@ func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err e
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Rmdir(path string) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		return
-	}
-	_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
-	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -988,7 +843,7 @@ func Setdomainname(p []byte) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_SETDOMAINNAME, uintptr(_p0), uintptr(len(p)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1004,7 +859,7 @@ func Sethostname(p []byte) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_SETHOSTNAME, uintptr(_p0), uintptr(len(p)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1014,7 +869,7 @@ func Sethostname(p []byte) (err error) {
 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
 }
@@ -1025,7 +880,7 @@ func Setsid() (pid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1035,7 +890,7 @@ func Setsid() (pid int, err error) {
 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
 }
@@ -1045,7 +900,7 @@ func Settimeofday(tv *Timeval) (err error) {
 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
 }
@@ -1073,29 +928,7 @@ func Setxattr(path string, attr string, data []byte, flags int) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Symlink(oldpath string, 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_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
 }
@@ -1112,7 +945,7 @@ func Sync() {
 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
 }
@@ -1123,7 +956,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1133,7 +966,7 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
 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
 }
@@ -1144,7 +977,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1162,39 +995,7 @@ func Umask(mask int) (oldmask int) {
 func Uname(buf *Utsname) (err error) {
 	_, _, e1 := RawSyscall(SYS_UNAME, uintptr(unsafe.Pointer(buf)), 0, 0)
 	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)
-	if err != nil {
-		return
-	}
-	_, _, e1 := Syscall(SYS_UNLINK, 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 Unlinkat(dirfd int, path string) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		return
-	}
-	_, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), 0)
-	use(unsafe.Pointer(_p0))
-	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1210,7 +1011,7 @@ func Unmount(target string, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_UMOUNT2, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1220,7 +1021,7 @@ func Unmount(target string, flags int) (err error) {
 func Unshare(flags int) (err error) {
 	_, _, e1 := Syscall(SYS_UNSHARE, uintptr(flags), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1230,7 +1031,7 @@ func Unshare(flags int) (err error) {
 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
 }
@@ -1246,7 +1047,7 @@ func Utime(path string, buf *Utimbuf) (err error) {
 	_, _, 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
 }
@@ -1263,7 +1064,7 @@ func write(fd int, p []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1273,7 +1074,7 @@ func write(fd int, p []byte) (n int, err error) {
 func exitThread(code int) (err error) {
 	_, _, e1 := Syscall(SYS_EXIT, uintptr(code), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1284,7 +1085,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1295,7 +1096,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1305,7 +1106,7 @@ func writelen(fd int, p *byte, np int) (n int, err error) {
 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
 }
@@ -1321,7 +1122,7 @@ func Madvise(b []byte, advice int) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_MADVISE, uintptr(_p0), uintptr(len(b)), uintptr(advice))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1337,7 +1138,7 @@ func Mprotect(b []byte, prot int) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1353,7 +1154,7 @@ func Mlock(b []byte) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1369,7 +1170,7 @@ func Munlock(b []byte) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1379,7 +1180,7 @@ func Munlock(b []byte) (err error) {
 func Mlockall(flags int) (err error) {
 	_, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1389,23 +1190,17 @@ func Mlockall(flags int) (err error) {
 func Munlockall() (err error) {
 	_, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 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 Chown(path string, uid int, gid int) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		return
-	}
-	_, _, e1 := Syscall(SYS_CHOWN, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
-	use(unsafe.Pointer(_p0))
+func Dup2(oldfd int, newfd int) (err error) {
+	_, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1415,7 +1210,7 @@ func Chown(path string, uid int, gid int) (err error) {
 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
 }
@@ -1425,7 +1220,7 @@ func Fchown(fd int, uid int, gid int) (err error) {
 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
 }
@@ -1435,7 +1230,7 @@ func Fstat(fd int, stat *Stat_t) (err error) {
 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
 }
@@ -1445,7 +1240,7 @@ func Fstatfs(fd int, buf *Statfs_t) (err error) {
 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
 }
@@ -1479,7 +1274,7 @@ func Getgid() (gid int) {
 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
 }
@@ -1494,10 +1289,21 @@ func Getuid() (uid int) {
 
 // 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 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
 }
@@ -1507,7 +1313,7 @@ func Ioperm(from int, num int, on int) (err error) {
 func Iopl(level int) (err error) {
 	_, _, e1 := Syscall(SYS_IOPL, uintptr(level), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1523,7 +1329,7 @@ func Lchown(path string, uid int, gid int) (err error) {
 	_, _, 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
 }
@@ -1533,7 +1339,7 @@ func Lchown(path string, uid int, gid int) (err error) {
 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
 }
@@ -1549,7 +1355,7 @@ func Lstat(path string, stat *Stat_t) (err error) {
 	_, _, 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
 }
@@ -1566,7 +1372,7 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) {
 	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
 }
@@ -1583,7 +1389,7 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
 	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
 }
@@ -1594,7 +1400,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1605,7 +1411,7 @@ func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err
 	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
 }
@@ -1616,7 +1422,7 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
 	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
 }
@@ -1626,7 +1432,7 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
 func Setfsgid(gid int) (err error) {
 	_, _, e1 := Syscall(SYS_SETFSGID, uintptr(gid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1636,7 +1442,7 @@ func Setfsgid(gid int) (err error) {
 func Setfsuid(uid int) (err error) {
 	_, _, e1 := Syscall(SYS_SETFSUID, uintptr(uid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1646,7 +1452,7 @@ func Setfsuid(uid int) (err error) {
 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
 }
@@ -1656,7 +1462,7 @@ func Setregid(rgid int, egid int) (err error) {
 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
 }
@@ -1666,7 +1472,7 @@ func Setresgid(rgid int, egid int, sgid int) (err error) {
 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
 }
@@ -1676,7 +1482,7 @@ func Setresuid(ruid int, euid int, suid int) (err error) {
 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
 }
@@ -1686,7 +1492,7 @@ func Setrlimit(resource int, rlim *Rlimit) (err error) {
 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
 }
@@ -1696,7 +1502,7 @@ func Setreuid(ruid int, euid int) (err error) {
 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
 }
@@ -1707,7 +1513,7 @@ func Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n i
 	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
 }
@@ -1723,7 +1529,7 @@ func Stat(path string, stat *Stat_t) (err error) {
 	_, _, 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
 }
@@ -1739,7 +1545,7 @@ func Statfs(path string, buf *Statfs_t) (err error) {
 	_, _, 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
 }
@@ -1749,7 +1555,7 @@ func Statfs(path string, buf *Statfs_t) (err error) {
 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
 }
@@ -1765,7 +1571,7 @@ func Truncate(path string, length int64) (err error) {
 	_, _, e1 := Syscall(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1776,7 +1582,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1787,7 +1593,7 @@ func accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int,
 	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
 }
@@ -1797,7 +1603,7 @@ func accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int,
 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
 }
@@ -1807,7 +1613,7 @@ func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 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
 }
@@ -1818,7 +1624,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1828,7 +1634,7 @@ func getgroups(n int, list *_Gid_t) (nn int, err error) {
 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
 }
@@ -1838,7 +1644,7 @@ func setgroups(n int, list *_Gid_t) (err error) {
 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
 }
@@ -1848,7 +1654,7 @@ func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen
 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
 }
@@ -1859,7 +1665,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1869,7 +1675,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
 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
 }
@@ -1879,7 +1685,7 @@ func socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) {
 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
 }
@@ -1889,7 +1695,7 @@ func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 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
 }
@@ -1906,7 +1712,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 	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
 }
@@ -1922,7 +1728,7 @@ func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (
 	}
 	_, _, 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
 }
@@ -1933,7 +1739,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1944,7 +1750,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1955,7 +1761,27 @@ func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int6
 	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
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func pipe(p *[2]_C_int) (err error) {
+	_, _, e1 := RawSyscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
+	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_arm.go b/src/syscall/zsyscall_linux_arm.go
index fbf6935..9bc3a54 100644
--- a/src/syscall/zsyscall_linux_arm.go
+++ b/src/syscall/zsyscall_linux_arm.go
@@ -1,23 +1,30 @@
 // mksyscall.pl -l32 -arm syscall_linux.go syscall_linux_arm.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build arm,linux
+
 package syscall
 
 import "unsafe"
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func open(path string, mode int, perm uint32) (fd int, err error) {
+func linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) {
 	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
+	_p0, err = BytePtrFromString(oldpath)
 	if err != nil {
 		return
 	}
-	r0, _, e1 := Syscall(SYS_OPEN, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm))
+	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))
-	fd = int(r0)
+	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -34,27 +41,68 @@ func openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)
 	use(unsafe.Pointer(_p0))
 	fd = 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(p *[2]_C_int) (err error) {
-	_, _, e1 := RawSyscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
+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 = e1
+		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)
+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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -70,7 +118,7 @@ func utimes(path string, times *[2]Timeval) (err error) {
 	_, _, 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
 }
@@ -86,7 +134,7 @@ func utimensat(dirfd int, path string, times *[2]Timespec) (err error) {
 	_, _, 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
 }
@@ -96,7 +144,7 @@ func utimensat(dirfd int, path string, times *[2]Timespec) (err error) {
 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
 }
@@ -113,7 +161,7 @@ func Getcwd(buf []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_GETCWD, uintptr(_p0), uintptr(len(buf)), 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -124,7 +172,7 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err
 	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
 }
@@ -134,7 +182,7 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err
 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
 }
@@ -150,7 +198,7 @@ func reboot(magic1 uint, magic2 uint, cmd int, arg string) (err error) {
 	_, _, 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
 }
@@ -178,23 +226,7 @@ func mount(source string, target string, fstype string, flags uintptr, data *byt
 	use(unsafe.Pointer(_p1))
 	use(unsafe.Pointer(_p2))
 	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Access(path string, mode uint32) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		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
 }
@@ -210,7 +242,7 @@ func Acct(path string) (err error) {
 	_, _, e1 := Syscall(SYS_ACCT, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -221,7 +253,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -237,23 +269,7 @@ func Chdir(path string) (err error) {
 	_, _, e1 := Syscall(SYS_CHDIR, 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 Chmod(path string, mode uint32) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		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
 }
@@ -269,7 +285,7 @@ func Chroot(path string) (err error) {
 	_, _, e1 := Syscall(SYS_CHROOT, uintptr(unsafe.Pointer(_p0)), 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -279,24 +295,7 @@ func Chroot(path string) (err error) {
 func Close(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Creat(path string, mode uint32) (fd int, err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		return
-	}
-	r0, _, e1 := Syscall(SYS_CREAT, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0)
-	use(unsafe.Pointer(_p0))
-	fd = int(r0)
-	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -304,20 +303,10 @@ func Creat(path string, mode uint32) (fd int, err error) {
 // 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
-	}
-	return
-}
-
-// 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)
-	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -325,9 +314,9 @@ func Dup2(oldfd int, newfd int) (err error) {
 // 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
 }
@@ -338,7 +327,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -349,7 +338,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -359,7 +348,7 @@ func EpollCreate1(flag int) (fd int, err error) {
 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
 }
@@ -376,7 +365,7 @@ func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
 	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
 }
@@ -399,7 +388,7 @@ func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
 	_, _, 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
 }
@@ -409,7 +398,7 @@ func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
 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
 }
@@ -419,7 +408,7 @@ func Fallocate(fd int, mode uint32, off int64, len int64) (err error) {
 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 +418,7 @@ func Fchdir(fd int) (err error) {
 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
 }
@@ -445,7 +434,7 @@ func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
 	_, _, 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
 }
@@ -461,7 +450,7 @@ func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) {
 	_, _, 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
 }
@@ -472,7 +461,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -482,7 +471,7 @@ func fcntl(fd int, cmd int, arg int) (val int, err error) {
 func Fdatasync(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FDATASYNC, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -492,7 +481,7 @@ func Fdatasync(fd int) (err error) {
 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
 }
@@ -502,7 +491,7 @@ func Flock(fd int, how int) (err error) {
 func Fsync(fd int) (err error) {
 	_, _, e1 := Syscall(SYS_FSYNC, uintptr(fd), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -519,7 +508,7 @@ func Getdents(fd int, buf []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_GETDENTS64, uintptr(fd), uintptr(_p0), uintptr(len(buf)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -530,21 +519,13 @@ func Getpgid(pid int) (pgid int, err error) {
 	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)
@@ -565,7 +546,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -575,7 +556,7 @@ func Getpriority(which int, who int) (prio int, err error) {
 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
 }
@@ -612,7 +593,7 @@ func Getxattr(path string, attr string, dest []byte) (sz int, err error) {
 	use(unsafe.Pointer(_p1))
 	sz = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -629,18 +610,7 @@ func InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err e
 	use(unsafe.Pointer(_p0))
 	watchdesc = int(r0)
 	if e1 != 0 {
-		err = 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -651,7 +621,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -662,7 +632,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -672,7 +642,7 @@ func InotifyRmWatch(fd int, watchdesc uint32) (success int, err error) {
 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
 }
@@ -689,29 +659,7 @@ func Klogctl(typ int, buf []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_SYSLOG, uintptr(typ), 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 Link(oldpath string, 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_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
 }
@@ -734,23 +682,7 @@ func Listxattr(path string, dest []byte) (sz int, err error) {
 	use(unsafe.Pointer(_p0))
 	sz = int(r0)
 	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Mkdir(path string, mode uint32) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		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
 }
@@ -766,23 +698,7 @@ func Mkdirat(dirfd int, path string, mode uint32) (err error) {
 	_, _, e1 := Syscall(SYS_MKDIRAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Mknod(path string, mode uint32, dev int) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		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
 }
@@ -798,7 +714,7 @@ func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) {
 	_, _, 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
 }
@@ -808,7 +724,7 @@ func Mknodat(dirfd int, path string, mode uint32, dev int) (err error) {
 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
 }
@@ -818,7 +734,7 @@ func Nanosleep(time *Timespec, leftover *Timespec) (err error) {
 func Pause() (err error) {
 	_, _, e1 := Syscall(SYS_PAUSE, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -840,7 +756,7 @@ func PivotRoot(newroot string, putold string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -850,7 +766,7 @@ func PivotRoot(newroot string, putold string) (err error) {
 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
 }
@@ -867,30 +783,7 @@ func read(fd int, p []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Readlink(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 := 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
 }
@@ -912,29 +805,7 @@ func Removexattr(path string, attr string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Rename(oldpath string, 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_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
 }
@@ -956,23 +827,7 @@ func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err e
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Rmdir(path string) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		return
-	}
-	_, _, e1 := Syscall(SYS_RMDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
-	use(unsafe.Pointer(_p0))
-	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -988,7 +843,7 @@ func Setdomainname(p []byte) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_SETDOMAINNAME, uintptr(_p0), uintptr(len(p)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1004,7 +859,7 @@ func Sethostname(p []byte) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_SETHOSTNAME, uintptr(_p0), uintptr(len(p)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1014,7 +869,7 @@ func Sethostname(p []byte) (err error) {
 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
 }
@@ -1025,7 +880,7 @@ func Setsid() (pid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1035,7 +890,7 @@ func Setsid() (pid int, err error) {
 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
 }
@@ -1045,7 +900,7 @@ func Settimeofday(tv *Timeval) (err error) {
 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
 }
@@ -1073,29 +928,7 @@ func Setxattr(path string, attr string, data []byte, flags int) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Symlink(oldpath string, 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_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
 }
@@ -1112,7 +945,7 @@ func Sync() {
 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
 }
@@ -1123,7 +956,7 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
 	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
 }
@@ -1133,7 +966,7 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
 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
 }
@@ -1144,7 +977,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1162,39 +995,7 @@ func Umask(mask int) (oldmask int) {
 func Uname(buf *Utsname) (err error) {
 	_, _, e1 := RawSyscall(SYS_UNAME, uintptr(unsafe.Pointer(buf)), 0, 0)
 	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)
-	if err != nil {
-		return
-	}
-	_, _, e1 := Syscall(SYS_UNLINK, 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 Unlinkat(dirfd int, path string) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		return
-	}
-	_, _, e1 := Syscall(SYS_UNLINKAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), 0)
-	use(unsafe.Pointer(_p0))
-	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1210,7 +1011,7 @@ func Unmount(target string, flags int) (err error) {
 	_, _, e1 := Syscall(SYS_UMOUNT2, uintptr(unsafe.Pointer(_p0)), uintptr(flags), 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1220,7 +1021,7 @@ func Unmount(target string, flags int) (err error) {
 func Unshare(flags int) (err error) {
 	_, _, e1 := Syscall(SYS_UNSHARE, uintptr(flags), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1230,7 +1031,7 @@ func Unshare(flags int) (err error) {
 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
 }
@@ -1246,7 +1047,7 @@ func Utime(path string, buf *Utimbuf) (err error) {
 	_, _, 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
 }
@@ -1263,7 +1064,7 @@ func write(fd int, p []byte) (n int, err error) {
 	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1273,7 +1074,7 @@ func write(fd int, p []byte) (n int, err error) {
 func exitThread(code int) (err error) {
 	_, _, e1 := Syscall(SYS_EXIT, uintptr(code), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1284,7 +1085,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1295,7 +1096,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1305,7 +1106,7 @@ func writelen(fd int, p *byte, np int) (n int, err error) {
 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
 }
@@ -1321,7 +1122,7 @@ func Madvise(b []byte, advice int) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_MADVISE, uintptr(_p0), uintptr(len(b)), uintptr(advice))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1337,7 +1138,7 @@ func Mprotect(b []byte, prot int) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_MPROTECT, uintptr(_p0), uintptr(len(b)), uintptr(prot))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1353,7 +1154,7 @@ func Mlock(b []byte) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_MLOCK, uintptr(_p0), uintptr(len(b)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1369,7 +1170,7 @@ func Munlock(b []byte) (err error) {
 	}
 	_, _, e1 := Syscall(SYS_MUNLOCK, uintptr(_p0), uintptr(len(b)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1379,7 +1180,7 @@ func Munlock(b []byte) (err error) {
 func Mlockall(flags int) (err error) {
 	_, _, e1 := Syscall(SYS_MLOCKALL, uintptr(flags), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1389,7 +1190,17 @@ func Mlockall(flags int) (err error) {
 func Munlockall() (err error) {
 	_, _, e1 := Syscall(SYS_MUNLOCKALL, 0, 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 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
 }
@@ -1400,7 +1211,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1411,7 +1222,7 @@ func accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int,
 	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
 }
@@ -1421,7 +1232,7 @@ func accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int,
 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
 }
@@ -1431,7 +1242,7 @@ func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 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
 }
@@ -1442,7 +1253,7 @@ func getgroups(n int, list *_Gid_t) (nn int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETGROUPS32, uintptr(n), uintptr(unsafe.Pointer(list)), 0)
 	nn = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1452,7 +1263,7 @@ func getgroups(n int, list *_Gid_t) (nn int, err error) {
 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
 }
@@ -1462,7 +1273,7 @@ func setgroups(n int, list *_Gid_t) (err error) {
 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
 }
@@ -1472,7 +1283,7 @@ func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen
 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
 }
@@ -1483,7 +1294,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1493,7 +1304,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
 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
 }
@@ -1503,7 +1314,7 @@ func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 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
 }
@@ -1520,7 +1331,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 	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
 }
@@ -1536,7 +1347,7 @@ func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (
 	}
 	_, _, 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
 }
@@ -1546,7 +1357,7 @@ func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (
 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
 }
@@ -1557,7 +1368,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1568,23 +1379,17 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func Chown(path string, uid int, gid int) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		return
-	}
-	_, _, e1 := Syscall(SYS_CHOWN32, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid))
-	use(unsafe.Pointer(_p0))
+func Dup2(oldfd int, newfd int) (err error) {
+	_, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1594,7 +1399,7 @@ func Chown(path string, uid int, gid int) (err error) {
 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
 }
@@ -1604,7 +1409,7 @@ func Fchown(fd int, uid int, gid int) (err error) {
 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
 }
@@ -1643,6 +1448,17 @@ func Getuid() (uid int) {
 
 // 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 Lchown(path string, uid int, gid int) (err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(path)
@@ -1652,7 +1468,7 @@ func Lchown(path string, uid int, gid int) (err error) {
 	_, _, 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
 }
@@ -1662,7 +1478,7 @@ func Lchown(path string, uid int, gid int) (err error) {
 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
 }
@@ -1678,7 +1494,7 @@ func Lstat(path string, stat *Stat_t) (err error) {
 	_, _, 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
 }
@@ -1689,7 +1505,7 @@ func sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
 	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
 }
@@ -1700,7 +1516,7 @@ func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err
 	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
 }
@@ -1710,7 +1526,7 @@ func Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err
 func Setfsgid(gid int) (err error) {
 	_, _, e1 := Syscall(SYS_SETFSGID32, uintptr(gid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1720,7 +1536,7 @@ func Setfsgid(gid int) (err error) {
 func Setfsuid(uid int) (err error) {
 	_, _, e1 := Syscall(SYS_SETFSUID32, uintptr(uid), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1730,7 +1546,7 @@ func Setfsuid(uid int) (err error) {
 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
 }
@@ -1740,7 +1556,7 @@ func Setregid(rgid int, egid int) (err error) {
 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
 }
@@ -1750,7 +1566,7 @@ func Setresgid(rgid int, egid int, sgid int) (err error) {
 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
 }
@@ -1760,7 +1576,7 @@ func Setresuid(ruid int, euid int, suid int) (err error) {
 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
 }
@@ -1770,7 +1586,7 @@ func Setreuid(ruid int, euid int) (err error) {
 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
 }
@@ -1781,7 +1597,7 @@ func Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n i
 	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
 }
@@ -1797,7 +1613,7 @@ func Stat(path string, stat *Stat_t) (err error) {
 	_, _, 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
 }
@@ -1807,7 +1623,7 @@ func Stat(path string, stat *Stat_t) (err error) {
 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
 }
@@ -1818,7 +1634,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1835,7 +1651,7 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) {
 	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
 }
@@ -1852,7 +1668,7 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
 	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
 }
@@ -1868,7 +1684,7 @@ func Truncate(path string, length int64) (err error) {
 	_, _, 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
 }
@@ -1878,7 +1694,7 @@ func Truncate(path string, length int64) (err error) {
 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
 }
@@ -1889,7 +1705,7 @@ func mmap2(addr uintptr, length uintptr, prot int, flags int, fd int, pageOffset
 	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
 }
@@ -1899,7 +1715,7 @@ func mmap2(addr uintptr, length uintptr, prot int, flags int, fd int, pageOffset
 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
 }
@@ -1909,7 +1725,7 @@ func getrlimit(resource int, rlim *rlimit32) (err error) {
 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..041e770
--- /dev/null
+++ b/src/syscall/zsyscall_linux_arm64.go
@@ -0,0 +1,1725 @@
+// mksyscall.pl syscall_linux.go syscall_linux_arm64.go
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+// +build arm64,linux
+
+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 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 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
new file mode 100644
index 0000000..4f61114
--- /dev/null
+++ b/src/syscall/zsyscall_linux_ppc64.go
@@ -0,0 +1,1798 @@
+// mksyscall.pl syscall_linux.go syscall_linux_ppc64x.go
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+// +build ppc64,linux
+
+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 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 Dup2(oldfd int, newfd int) (err error) {
+	_, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 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 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_UGETRLIMIT, 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 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 Ioperm(from int, num int, on int) (err error) {
+	_, _, e1 := Syscall(SYS_IOPERM, uintptr(from), uintptr(num), uintptr(on))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Iopl(level int) (err error) {
+	_, _, e1 := Syscall(SYS_IOPL, uintptr(level), 0, 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	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 Lstat(path string, stat *Stat_t) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 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 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_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 = 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 Stat(path string, stat *Stat_t) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 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 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_ppc64le.go b/src/syscall/zsyscall_linux_ppc64le.go
new file mode 100644
index 0000000..4073a0f
--- /dev/null
+++ b/src/syscall/zsyscall_linux_ppc64le.go
@@ -0,0 +1,1798 @@
+// mksyscall.pl syscall_linux.go syscall_linux_ppc64x.go
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+// +build ppc64le,linux
+
+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 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 Dup2(oldfd int, newfd int) (err error) {
+	_, _, e1 := Syscall(SYS_DUP2, uintptr(oldfd), uintptr(newfd), 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 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_UGETRLIMIT, 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 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 Ioperm(from int, num int, on int) (err error) {
+	_, _, e1 := Syscall(SYS_IOPERM, uintptr(from), uintptr(num), uintptr(on))
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Iopl(level int) (err error) {
+	_, _, e1 := Syscall(SYS_IOPL, uintptr(level), 0, 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	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 Lstat(path string, stat *Stat_t) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 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 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_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 = 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 Stat(path string, stat *Stat_t) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 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 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_nacl_386.go b/src/syscall/zsyscall_nacl_386.go
index 32eed33..bf3f9e3 100644
--- a/src/syscall/zsyscall_nacl_386.go
+++ b/src/syscall/zsyscall_nacl_386.go
@@ -1,6 +1,8 @@
 // mksyscall.pl -l32 -nacl syscall_nacl.go syscall_nacl_386.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build 386,nacl
+
 package syscall
 
 import "unsafe"
@@ -10,7 +12,7 @@ import "unsafe"
 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 +22,7 @@ func naclClose(fd int) (err error) {
 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 +32,7 @@ func Exit(code int) (err error) {
 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 +49,7 @@ func naclRead(fd int, b []byte) (n int, err error) {
 	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 +59,23 @@ func naclRead(fd int, b []byte) (n int, err error) {
 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..3f08da6 100644
--- a/src/syscall/zsyscall_nacl_amd64p32.go
+++ b/src/syscall/zsyscall_nacl_amd64p32.go
@@ -1,6 +1,8 @@
 // mksyscall.pl -nacl syscall_nacl.go syscall_nacl_amd64p32.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build amd64p32,nacl
+
 package syscall
 
 import "unsafe"
@@ -10,7 +12,7 @@ import "unsafe"
 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 +22,7 @@ func naclClose(fd int) (err error) {
 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 +32,7 @@ func Exit(code int) (err error) {
 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 +49,7 @@ func naclRead(fd int, b []byte) (n int, err error) {
 	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 +59,23 @@ func naclRead(fd int, b []byte) (n int, err error) {
 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..77d46c3 100644
--- a/src/syscall/zsyscall_nacl_arm.go
+++ b/src/syscall/zsyscall_nacl_arm.go
@@ -1,6 +1,8 @@
 // mksyscall.pl -l32 -nacl -arm syscall_nacl.go syscall_nacl_arm.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build arm,nacl
+
 package syscall
 
 import "unsafe"
@@ -10,7 +12,7 @@ import "unsafe"
 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 +22,7 @@ func naclClose(fd int) (err error) {
 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 +32,7 @@ func Exit(code int) (err error) {
 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 +49,7 @@ func naclRead(fd int, b []byte) (n int, err error) {
 	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 +59,23 @@ func naclRead(fd int, b []byte) (n int, err error) {
 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..e24c3b7 100644
--- a/src/syscall/zsyscall_netbsd_386.go
+++ b/src/syscall/zsyscall_netbsd_386.go
@@ -1,6 +1,8 @@
 // mksyscall.pl -l32 -netbsd syscall_bsd.go syscall_netbsd.go syscall_netbsd_386.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build 386,netbsd
+
 package syscall
 
 import "unsafe"
@@ -11,7 +13,7 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
 	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 +23,7 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
 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 +34,7 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err
 	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 +45,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -53,7 +55,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
 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 +65,7 @@ func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 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 +76,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -84,7 +86,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
 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 +96,7 @@ func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen
 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 +106,7 @@ func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr)
 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 +116,7 @@ func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 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 +126,7 @@ func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 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 +136,7 @@ func Shutdown(s int, how int) (err error) {
 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 +153,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 	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 +169,7 @@ func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (
 	}
 	_, _, 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 +180,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -189,7 +191,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -200,7 +202,7 @@ func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, ne
 	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 +218,7 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr)
 	}
 	_, _, 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 +234,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 	_, _, 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 +244,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 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 +255,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -265,7 +267,7 @@ func pipe() (fd1 int, fd2 int, err error) {
 	fd1 = int(r0)
 	fd2 = int(r1)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -282,7 +284,7 @@ func getdents(fd int, buf []byte) (n int, err error) {
 	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 +300,7 @@ func Access(path string, mode uint32) (err error) {
 	_, _, 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 +310,7 @@ func Access(path string, mode uint32) (err error) {
 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 +326,7 @@ func Chdir(path string) (err error) {
 	_, _, 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 +342,7 @@ func Chflags(path string, flags int) (err error) {
 	_, _, 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 +358,7 @@ func Chmod(path string, mode uint32) (err error) {
 	_, _, 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 +374,7 @@ func Chown(path string, uid int, gid int) (err error) {
 	_, _, 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 +390,7 @@ func Chroot(path string) (err error) {
 	_, _, 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 +400,7 @@ func Chroot(path string) (err error) {
 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 +408,10 @@ func Close(fd int) (err error) {
 // 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 +419,9 @@ func Dup(fd int) (nfd int, err error) {
 // 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 +438,7 @@ func Exit(code int) {
 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 +448,7 @@ func Fchdir(fd int) (err error) {
 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 +458,7 @@ func Fchflags(fd int, flags int) (err error) {
 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 +468,7 @@ func Fchmod(fd int, mode uint32) (err error) {
 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 +478,7 @@ func Fchown(fd int, uid int, gid int) (err error) {
 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 +489,7 @@ func Fpathconf(fd int, name int) (val int, err error) {
 	r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -497,7 +499,7 @@ func Fpathconf(fd int, name int) (val int, err error) {
 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 +509,7 @@ func Fstat(fd int, stat *Stat_t) (err error) {
 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 +519,7 @@ func Fsync(fd int) (err error) {
 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 +554,7 @@ func Getpgid(pid int) (pgid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
 	pgid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -587,7 +589,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -597,7 +599,7 @@ func Getpriority(which int, who int) (prio int, err error) {
 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 +609,7 @@ func Getrlimit(which int, lim *Rlimit) (err error) {
 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 +620,7 @@ func Getsid(pid int) (sid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
 	sid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -628,7 +630,7 @@ func Getsid(pid int) (sid int, err error) {
 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 +656,7 @@ func Issetugid() (tainted bool) {
 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 +667,7 @@ func Kqueue() (fd int, err error) {
 	r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -681,7 +683,7 @@ func Lchown(path string, uid int, gid int) (err error) {
 	_, _, 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 +705,7 @@ func Link(path string, link string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -713,7 +715,7 @@ func Link(path string, link string) (err error) {
 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 +731,7 @@ func Lstat(path string, stat *Stat_t) (err error) {
 	_, _, 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 +747,7 @@ func Mkdir(path string, mode uint32) (err error) {
 	_, _, 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 +763,7 @@ func Mkfifo(path string, mode uint32) (err error) {
 	_, _, 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 +779,7 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 	_, _, 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 +789,7 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 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 +806,7 @@ func Open(path string, mode int, perm uint32) (fd int, err error) {
 	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -821,7 +823,7 @@ func Pathconf(path string, name int) (val int, err error) {
 	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -838,7 +840,7 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) {
 	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 +857,7 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
 	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 +874,7 @@ func read(fd int, p []byte) (n int, err error) {
 	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 +897,7 @@ func Readlink(path string, buf []byte) (n int, err error) {
 	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -917,7 +919,7 @@ func Rename(from string, to string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -933,7 +935,7 @@ func Revoke(path string) (err error) {
 	_, _, 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 +951,7 @@ func Rmdir(path string) (err error) {
 	_, _, 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 +962,7 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 	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 +972,7 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 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 +982,7 @@ func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
 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 +992,7 @@ func Setegid(egid int) (err error) {
 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 +1002,7 @@ func Seteuid(euid int) (err error) {
 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 +1012,7 @@ func Setgid(gid int) (err error) {
 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 +1022,7 @@ func Setpgid(pid int, pgid int) (err error) {
 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 +1032,7 @@ func Setpriority(which int, who int, prio int) (err error) {
 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 +1042,7 @@ func Setregid(rgid int, egid int) (err error) {
 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 +1052,7 @@ func Setreuid(ruid int, euid int) (err error) {
 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 +1063,7 @@ func Setsid() (pid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1071,7 +1073,7 @@ func Setsid() (pid int, err error) {
 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 +1083,7 @@ func Settimeofday(tp *Timeval) (err error) {
 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 +1099,7 @@ func Stat(path string, stat *Stat_t) (err error) {
 	_, _, 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 +1121,7 @@ func Symlink(path string, link string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1129,7 +1131,7 @@ func Symlink(path string, link string) (err error) {
 func Sync() (err error) {
 	_, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1145,7 +1147,7 @@ func Truncate(path string, length int64) (err error) {
 	_, _, 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 +1171,7 @@ func Unlink(path string) (err error) {
 	_, _, 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 +1187,7 @@ func Unmount(path string, flags int) (err error) {
 	_, _, 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 +1204,7 @@ func write(fd int, p []byte) (n int, err error) {
 	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 +1215,7 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
 	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 +1225,7 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
 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 +1236,7 @@ func readlen(fd int, buf *byte, nbuf int) (n int, err error) {
 	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 +1247,7 @@ func writelen(fd int, buf *byte, nbuf int) (n int, err error) {
 	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..7aa75ab 100644
--- a/src/syscall/zsyscall_netbsd_amd64.go
+++ b/src/syscall/zsyscall_netbsd_amd64.go
@@ -1,6 +1,8 @@
 // mksyscall.pl -netbsd syscall_bsd.go syscall_netbsd.go syscall_netbsd_amd64.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build amd64,netbsd
+
 package syscall
 
 import "unsafe"
@@ -11,7 +13,7 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
 	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 +23,7 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
 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 +34,7 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err
 	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 +45,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -53,7 +55,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
 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 +65,7 @@ func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 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 +76,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -84,7 +86,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
 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 +96,7 @@ func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen
 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 +106,7 @@ func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr)
 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 +116,7 @@ func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 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 +126,7 @@ func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 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 +136,7 @@ func Shutdown(s int, how int) (err error) {
 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 +153,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 	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 +169,7 @@ func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (
 	}
 	_, _, 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 +180,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -189,7 +191,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -200,7 +202,7 @@ func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, ne
 	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 +218,7 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr)
 	}
 	_, _, 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 +234,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 	_, _, 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 +244,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 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 +255,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -265,7 +267,7 @@ func pipe() (fd1 int, fd2 int, err error) {
 	fd1 = int(r0)
 	fd2 = int(r1)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -282,7 +284,7 @@ func getdents(fd int, buf []byte) (n int, err error) {
 	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 +300,7 @@ func Access(path string, mode uint32) (err error) {
 	_, _, 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 +310,7 @@ func Access(path string, mode uint32) (err error) {
 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 +326,7 @@ func Chdir(path string) (err error) {
 	_, _, 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 +342,7 @@ func Chflags(path string, flags int) (err error) {
 	_, _, 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 +358,7 @@ func Chmod(path string, mode uint32) (err error) {
 	_, _, 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 +374,7 @@ func Chown(path string, uid int, gid int) (err error) {
 	_, _, 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 +390,7 @@ func Chroot(path string) (err error) {
 	_, _, 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 +400,7 @@ func Chroot(path string) (err error) {
 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 +408,10 @@ func Close(fd int) (err error) {
 // 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 +419,9 @@ func Dup(fd int) (nfd int, err error) {
 // 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 +438,7 @@ func Exit(code int) {
 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 +448,7 @@ func Fchdir(fd int) (err error) {
 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 +458,7 @@ func Fchflags(fd int, flags int) (err error) {
 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 +468,7 @@ func Fchmod(fd int, mode uint32) (err error) {
 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 +478,7 @@ func Fchown(fd int, uid int, gid int) (err error) {
 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 +489,7 @@ func Fpathconf(fd int, name int) (val int, err error) {
 	r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -497,7 +499,7 @@ func Fpathconf(fd int, name int) (val int, err error) {
 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 +509,7 @@ func Fstat(fd int, stat *Stat_t) (err error) {
 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 +519,7 @@ func Fsync(fd int) (err error) {
 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 +554,7 @@ func Getpgid(pid int) (pgid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
 	pgid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -587,7 +589,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -597,7 +599,7 @@ func Getpriority(which int, who int) (prio int, err error) {
 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 +609,7 @@ func Getrlimit(which int, lim *Rlimit) (err error) {
 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 +620,7 @@ func Getsid(pid int) (sid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
 	sid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -628,7 +630,7 @@ func Getsid(pid int) (sid int, err error) {
 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 +656,7 @@ func Issetugid() (tainted bool) {
 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 +667,7 @@ func Kqueue() (fd int, err error) {
 	r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -681,7 +683,7 @@ func Lchown(path string, uid int, gid int) (err error) {
 	_, _, 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 +705,7 @@ func Link(path string, link string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -713,7 +715,7 @@ func Link(path string, link string) (err error) {
 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 +731,7 @@ func Lstat(path string, stat *Stat_t) (err error) {
 	_, _, 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 +747,7 @@ func Mkdir(path string, mode uint32) (err error) {
 	_, _, 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 +763,7 @@ func Mkfifo(path string, mode uint32) (err error) {
 	_, _, 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 +779,7 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 	_, _, 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 +789,7 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 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 +806,7 @@ func Open(path string, mode int, perm uint32) (fd int, err error) {
 	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -821,7 +823,7 @@ func Pathconf(path string, name int) (val int, err error) {
 	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -838,7 +840,7 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) {
 	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 +857,7 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
 	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 +874,7 @@ func read(fd int, p []byte) (n int, err error) {
 	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 +897,7 @@ func Readlink(path string, buf []byte) (n int, err error) {
 	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -917,7 +919,7 @@ func Rename(from string, to string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -933,7 +935,7 @@ func Revoke(path string) (err error) {
 	_, _, 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 +951,7 @@ func Rmdir(path string) (err error) {
 	_, _, 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 +962,7 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 	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 +972,7 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 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 +982,7 @@ func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
 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 +992,7 @@ func Setegid(egid int) (err error) {
 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 +1002,7 @@ func Seteuid(euid int) (err error) {
 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 +1012,7 @@ func Setgid(gid int) (err error) {
 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 +1022,7 @@ func Setpgid(pid int, pgid int) (err error) {
 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 +1032,7 @@ func Setpriority(which int, who int, prio int) (err error) {
 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 +1042,7 @@ func Setregid(rgid int, egid int) (err error) {
 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 +1052,7 @@ func Setreuid(ruid int, euid int) (err error) {
 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 +1063,7 @@ func Setsid() (pid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1071,7 +1073,7 @@ func Setsid() (pid int, err error) {
 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 +1083,7 @@ func Settimeofday(tp *Timeval) (err error) {
 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 +1099,7 @@ func Stat(path string, stat *Stat_t) (err error) {
 	_, _, 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 +1121,7 @@ func Symlink(path string, link string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1129,7 +1131,7 @@ func Symlink(path string, link string) (err error) {
 func Sync() (err error) {
 	_, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1145,7 +1147,7 @@ func Truncate(path string, length int64) (err error) {
 	_, _, 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 +1171,7 @@ func Unlink(path string) (err error) {
 	_, _, 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 +1187,7 @@ func Unmount(path string, flags int) (err error) {
 	_, _, 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 +1204,7 @@ func write(fd int, p []byte) (n int, err error) {
 	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 +1215,7 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
 	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 +1225,7 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
 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 +1236,7 @@ func readlen(fd int, buf *byte, nbuf int) (n int, err error) {
 	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 +1247,7 @@ func writelen(fd int, buf *byte, nbuf int) (n int, err error) {
 	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..21f482b 100644
--- a/src/syscall/zsyscall_netbsd_arm.go
+++ b/src/syscall/zsyscall_netbsd_arm.go
@@ -1,6 +1,8 @@
 // mksyscall.pl -l32 -arm syscall_bsd.go syscall_netbsd.go syscall_netbsd_arm.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build arm,netbsd
+
 package syscall
 
 import "unsafe"
@@ -11,7 +13,7 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
 	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 +23,7 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
 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 +34,7 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err
 	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 +45,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -53,7 +55,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
 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 +65,7 @@ func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 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 +76,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -84,7 +86,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
 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 +96,7 @@ func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen
 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 +106,7 @@ func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr)
 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 +116,7 @@ func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 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 +126,7 @@ func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 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 +136,7 @@ func Shutdown(s int, how int) (err error) {
 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 +153,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 	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 +169,7 @@ func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (
 	}
 	_, _, 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 +180,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -189,7 +191,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -200,7 +202,7 @@ func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, ne
 	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 +218,7 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr)
 	}
 	_, _, 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 +234,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 	_, _, 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 +244,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 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 +255,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -265,7 +267,7 @@ func pipe() (fd1 int, fd2 int, err error) {
 	fd1 = int(r0)
 	fd2 = int(r1)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -282,7 +284,7 @@ func getdents(fd int, buf []byte) (n int, err error) {
 	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 +300,7 @@ func Access(path string, mode uint32) (err error) {
 	_, _, 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 +310,7 @@ func Access(path string, mode uint32) (err error) {
 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 +326,7 @@ func Chdir(path string) (err error) {
 	_, _, 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 +342,7 @@ func Chflags(path string, flags int) (err error) {
 	_, _, 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 +358,7 @@ func Chmod(path string, mode uint32) (err error) {
 	_, _, 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 +374,7 @@ func Chown(path string, uid int, gid int) (err error) {
 	_, _, 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 +390,7 @@ func Chroot(path string) (err error) {
 	_, _, 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 +400,7 @@ func Chroot(path string) (err error) {
 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 +408,10 @@ func Close(fd int) (err error) {
 // 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 +419,9 @@ func Dup(fd int) (nfd int, err error) {
 // 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 +438,7 @@ func Exit(code int) {
 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 +448,7 @@ func Fchdir(fd int) (err error) {
 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 +458,7 @@ func Fchflags(fd int, flags int) (err error) {
 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 +468,7 @@ func Fchmod(fd int, mode uint32) (err error) {
 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 +478,7 @@ func Fchown(fd int, uid int, gid int) (err error) {
 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 +489,7 @@ func Fpathconf(fd int, name int) (val int, err error) {
 	r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -497,7 +499,7 @@ func Fpathconf(fd int, name int) (val int, err error) {
 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 +509,7 @@ func Fstat(fd int, stat *Stat_t) (err error) {
 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 +519,7 @@ func Fsync(fd int) (err error) {
 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 +554,7 @@ func Getpgid(pid int) (pgid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
 	pgid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -587,7 +589,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -597,7 +599,7 @@ func Getpriority(which int, who int) (prio int, err error) {
 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 +609,7 @@ func Getrlimit(which int, lim *Rlimit) (err error) {
 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 +620,7 @@ func Getsid(pid int) (sid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
 	sid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -628,7 +630,7 @@ func Getsid(pid int) (sid int, err error) {
 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 +656,7 @@ func Issetugid() (tainted bool) {
 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 +667,7 @@ func Kqueue() (fd int, err error) {
 	r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -681,7 +683,7 @@ func Lchown(path string, uid int, gid int) (err error) {
 	_, _, 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 +705,7 @@ func Link(path string, link string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -713,7 +715,7 @@ func Link(path string, link string) (err error) {
 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 +731,7 @@ func Lstat(path string, stat *Stat_t) (err error) {
 	_, _, 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 +747,7 @@ func Mkdir(path string, mode uint32) (err error) {
 	_, _, 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 +763,7 @@ func Mkfifo(path string, mode uint32) (err error) {
 	_, _, 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 +779,7 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 	_, _, 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 +789,7 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 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 +806,7 @@ func Open(path string, mode int, perm uint32) (fd int, err error) {
 	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -821,7 +823,7 @@ func Pathconf(path string, name int) (val int, err error) {
 	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -838,7 +840,7 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) {
 	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 +857,7 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
 	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 +874,7 @@ func read(fd int, p []byte) (n int, err error) {
 	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 +897,7 @@ func Readlink(path string, buf []byte) (n int, err error) {
 	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -917,7 +919,7 @@ func Rename(from string, to string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -933,7 +935,7 @@ func Revoke(path string) (err error) {
 	_, _, 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 +951,7 @@ func Rmdir(path string) (err error) {
 	_, _, 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 +962,7 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 	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 +972,7 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 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 +982,7 @@ func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
 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 +992,7 @@ func Setegid(egid int) (err error) {
 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 +1002,7 @@ func Seteuid(euid int) (err error) {
 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 +1012,7 @@ func Setgid(gid int) (err error) {
 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 +1022,7 @@ func Setpgid(pid int, pgid int) (err error) {
 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 +1032,7 @@ func Setpriority(which int, who int, prio int) (err error) {
 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 +1042,7 @@ func Setregid(rgid int, egid int) (err error) {
 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 +1052,7 @@ func Setreuid(ruid int, euid int) (err error) {
 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 +1063,7 @@ func Setsid() (pid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1071,7 +1073,7 @@ func Setsid() (pid int, err error) {
 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 +1083,7 @@ func Settimeofday(tp *Timeval) (err error) {
 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 +1099,7 @@ func Stat(path string, stat *Stat_t) (err error) {
 	_, _, 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 +1121,7 @@ func Symlink(path string, link string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1129,7 +1131,7 @@ func Symlink(path string, link string) (err error) {
 func Sync() (err error) {
 	_, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1145,7 +1147,7 @@ func Truncate(path string, length int64) (err error) {
 	_, _, 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 +1171,7 @@ func Unlink(path string) (err error) {
 	_, _, 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 +1187,7 @@ func Unmount(path string, flags int) (err error) {
 	_, _, 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 +1204,7 @@ func write(fd int, p []byte) (n int, err error) {
 	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 +1215,7 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
 	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 +1225,7 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
 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 +1236,7 @@ func readlen(fd int, buf *byte, nbuf int) (n int, err error) {
 	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 +1247,7 @@ func writelen(fd int, buf *byte, nbuf int) (n int, err error) {
 	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..df7df1e 100644
--- a/src/syscall/zsyscall_openbsd_386.go
+++ b/src/syscall/zsyscall_openbsd_386.go
@@ -1,6 +1,8 @@
 // mksyscall.pl -l32 -openbsd syscall_bsd.go syscall_openbsd.go syscall_openbsd_386.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build 386,openbsd
+
 package syscall
 
 import "unsafe"
@@ -11,7 +13,7 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
 	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 +23,7 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
 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 +34,7 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err
 	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 +45,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -53,7 +55,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
 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 +65,7 @@ func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 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 +76,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -84,7 +86,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
 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 +96,7 @@ func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen
 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 +106,7 @@ func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr)
 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 +116,7 @@ func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 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 +126,7 @@ func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 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 +136,7 @@ func Shutdown(s int, how int) (err error) {
 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 +153,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 	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 +169,7 @@ func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (
 	}
 	_, _, 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 +180,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -189,7 +191,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -200,7 +202,7 @@ func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, ne
 	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 +218,7 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr)
 	}
 	_, _, 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 +234,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 	_, _, 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 +244,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 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 +255,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -263,7 +265,7 @@ func fcntl(fd int, cmd int, arg int) (val int, err error) {
 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 +282,7 @@ func getdents(fd int, buf []byte) (n int, err error) {
 	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 +298,7 @@ func Access(path string, mode uint32) (err error) {
 	_, _, 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 +308,7 @@ func Access(path string, mode uint32) (err error) {
 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 +324,7 @@ func Chdir(path string) (err error) {
 	_, _, 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 +340,7 @@ func Chflags(path string, flags int) (err error) {
 	_, _, 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 +356,7 @@ func Chmod(path string, mode uint32) (err error) {
 	_, _, 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 +372,7 @@ func Chown(path string, uid int, gid int) (err error) {
 	_, _, 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 +388,7 @@ func Chroot(path string) (err error) {
 	_, _, 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 +398,7 @@ func Chroot(path string) (err error) {
 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 +406,10 @@ func Close(fd int) (err error) {
 // 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 +417,9 @@ func Dup(fd int) (nfd int, err error) {
 // 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 +436,7 @@ func Exit(code int) {
 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 +446,7 @@ func Fchdir(fd int) (err error) {
 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 +456,7 @@ func Fchflags(fd int, flags int) (err error) {
 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 +466,7 @@ func Fchmod(fd int, mode uint32) (err error) {
 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 +476,7 @@ func Fchown(fd int, uid int, gid int) (err error) {
 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 +487,7 @@ func Fpathconf(fd int, name int) (val int, err error) {
 	r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -495,7 +497,7 @@ func Fpathconf(fd int, name int) (val int, err error) {
 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 +507,7 @@ func Fstat(fd int, stat *Stat_t) (err error) {
 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 +517,7 @@ func Fstatfs(fd int, stat *Statfs_t) (err error) {
 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 +527,7 @@ func Fsync(fd int) (err error) {
 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 +562,7 @@ func Getpgid(pid int) (pgid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
 	pgid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -595,7 +597,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -605,7 +607,7 @@ func Getpriority(which int, who int) (prio int, err error) {
 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 +617,7 @@ func Getrlimit(which int, lim *Rlimit) (err error) {
 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 +628,7 @@ func Getsid(pid int) (sid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
 	sid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -636,7 +638,7 @@ func Getsid(pid int) (sid int, err error) {
 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 +664,7 @@ func Issetugid() (tainted bool) {
 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 +675,7 @@ func Kqueue() (fd int, err error) {
 	r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -689,7 +691,7 @@ func Lchown(path string, uid int, gid int) (err error) {
 	_, _, 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 +713,7 @@ func Link(path string, link string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -721,7 +723,7 @@ func Link(path string, link string) (err error) {
 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 +739,7 @@ func Lstat(path string, stat *Stat_t) (err error) {
 	_, _, 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 +755,7 @@ func Mkdir(path string, mode uint32) (err error) {
 	_, _, 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 +771,7 @@ func Mkfifo(path string, mode uint32) (err error) {
 	_, _, 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 +787,7 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 	_, _, 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 +797,7 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 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 +814,7 @@ func Open(path string, mode int, perm uint32) (fd int, err error) {
 	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -829,7 +831,7 @@ func Pathconf(path string, name int) (val int, err error) {
 	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -846,7 +848,7 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) {
 	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 +865,7 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
 	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 +882,7 @@ func read(fd int, p []byte) (n int, err error) {
 	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 +905,7 @@ func Readlink(path string, buf []byte) (n int, err error) {
 	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -925,7 +927,7 @@ func Rename(from string, to string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -941,7 +943,7 @@ func Revoke(path string) (err error) {
 	_, _, 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 +959,7 @@ func Rmdir(path string) (err error) {
 	_, _, 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 +970,7 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 	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 +980,7 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 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 +990,7 @@ func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
 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 +1000,7 @@ func Setegid(egid int) (err error) {
 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 +1010,7 @@ func Seteuid(euid int) (err error) {
 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 +1026,7 @@ func Setlogin(name string) (err error) {
 	_, _, 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 +1036,7 @@ func Setlogin(name string) (err error) {
 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 +1046,7 @@ func Setpgid(pid int, pgid int) (err error) {
 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 +1056,7 @@ func Setpriority(which int, who int, prio int) (err error) {
 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 +1066,7 @@ func Setregid(rgid int, egid int) (err error) {
 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 +1076,7 @@ func Setreuid(ruid int, euid int) (err error) {
 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 +1087,7 @@ func Setsid() (pid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1095,7 +1097,7 @@ func Setsid() (pid int, err error) {
 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 +1107,7 @@ func Settimeofday(tp *Timeval) (err error) {
 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 +1123,7 @@ func Stat(path string, stat *Stat_t) (err error) {
 	_, _, 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 +1139,7 @@ func Statfs(path string, stat *Statfs_t) (err error) {
 	_, _, 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 +1161,7 @@ func Symlink(path string, link string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1169,7 +1171,7 @@ func Symlink(path string, link string) (err error) {
 func Sync() (err error) {
 	_, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1185,7 +1187,7 @@ func Truncate(path string, length int64) (err error) {
 	_, _, 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 +1211,7 @@ func Unlink(path string) (err error) {
 	_, _, 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 +1227,7 @@ func Unmount(path string, flags int) (err error) {
 	_, _, 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 +1244,7 @@ func write(fd int, p []byte) (n int, err error) {
 	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 +1255,7 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
 	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 +1265,7 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
 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 +1276,7 @@ func readlen(fd int, buf *byte, nbuf int) (n int, err error) {
 	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 +1287,7 @@ func writelen(fd int, buf *byte, nbuf int) (n int, err error) {
 	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..1d64070 100644
--- a/src/syscall/zsyscall_openbsd_amd64.go
+++ b/src/syscall/zsyscall_openbsd_amd64.go
@@ -1,6 +1,8 @@
 // mksyscall.pl -openbsd syscall_bsd.go syscall_openbsd.go syscall_openbsd_amd64.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build amd64,openbsd
+
 package syscall
 
 import "unsafe"
@@ -11,7 +13,7 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
 	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 +23,7 @@ func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
 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 +34,7 @@ func wait4(pid int, wstatus *_C_int, options int, rusage *Rusage) (wpid int, err
 	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 +45,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -53,7 +55,7 @@ func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
 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 +65,7 @@ func bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) {
 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 +76,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -84,7 +86,7 @@ func socket(domain int, typ int, proto int) (fd int, err error) {
 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 +96,7 @@ func getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen
 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 +106,7 @@ func setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr)
 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 +116,7 @@ func getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 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 +126,7 @@ func getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) {
 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 +136,7 @@ func Shutdown(s int, how int) (err error) {
 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 +153,7 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 	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 +169,7 @@ func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (
 	}
 	_, _, 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 +180,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -189,7 +191,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -200,7 +202,7 @@ func kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, ne
 	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 +218,7 @@ func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr)
 	}
 	_, _, 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 +234,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 	_, _, 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 +244,7 @@ func utimes(path string, timeval *[2]Timeval) (err error) {
 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 +255,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -263,7 +265,7 @@ func fcntl(fd int, cmd int, arg int) (val int, err error) {
 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 +282,7 @@ func getdents(fd int, buf []byte) (n int, err error) {
 	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 +298,7 @@ func Access(path string, mode uint32) (err error) {
 	_, _, 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 +308,7 @@ func Access(path string, mode uint32) (err error) {
 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 +324,7 @@ func Chdir(path string) (err error) {
 	_, _, 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 +340,7 @@ func Chflags(path string, flags int) (err error) {
 	_, _, 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 +356,7 @@ func Chmod(path string, mode uint32) (err error) {
 	_, _, 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 +372,7 @@ func Chown(path string, uid int, gid int) (err error) {
 	_, _, 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 +388,7 @@ func Chroot(path string) (err error) {
 	_, _, 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 +398,7 @@ func Chroot(path string) (err error) {
 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 +406,10 @@ func Close(fd int) (err error) {
 // 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 +417,9 @@ func Dup(fd int) (nfd int, err error) {
 // 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 +436,7 @@ func Exit(code int) {
 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 +446,7 @@ func Fchdir(fd int) (err error) {
 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 +456,7 @@ func Fchflags(fd int, flags int) (err error) {
 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 +466,7 @@ func Fchmod(fd int, mode uint32) (err error) {
 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 +476,7 @@ func Fchown(fd int, uid int, gid int) (err error) {
 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 +487,7 @@ func Fpathconf(fd int, name int) (val int, err error) {
 	r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -495,7 +497,7 @@ func Fpathconf(fd int, name int) (val int, err error) {
 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 +507,7 @@ func Fstat(fd int, stat *Stat_t) (err error) {
 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 +517,7 @@ func Fstatfs(fd int, stat *Statfs_t) (err error) {
 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 +527,7 @@ func Fsync(fd int) (err error) {
 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 +562,7 @@ func Getpgid(pid int) (pgid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETPGID, uintptr(pid), 0, 0)
 	pgid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -595,7 +597,7 @@ 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 = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -605,7 +607,7 @@ func Getpriority(which int, who int) (prio int, err error) {
 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 +617,7 @@ func Getrlimit(which int, lim *Rlimit) (err error) {
 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 +628,7 @@ func Getsid(pid int) (sid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
 	sid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -636,7 +638,7 @@ func Getsid(pid int) (sid int, err error) {
 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 +664,7 @@ func Issetugid() (tainted bool) {
 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 +675,7 @@ func Kqueue() (fd int, err error) {
 	r0, _, e1 := Syscall(SYS_KQUEUE, 0, 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -689,7 +691,7 @@ func Lchown(path string, uid int, gid int) (err error) {
 	_, _, 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 +713,7 @@ func Link(path string, link string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -721,7 +723,7 @@ func Link(path string, link string) (err error) {
 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 +739,7 @@ func Lstat(path string, stat *Stat_t) (err error) {
 	_, _, 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 +755,7 @@ func Mkdir(path string, mode uint32) (err error) {
 	_, _, 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 +771,7 @@ func Mkfifo(path string, mode uint32) (err error) {
 	_, _, 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 +787,7 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 	_, _, 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 +797,7 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 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 +814,7 @@ func Open(path string, mode int, perm uint32) (fd int, err error) {
 	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -829,7 +831,7 @@ func Pathconf(path string, name int) (val int, err error) {
 	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -846,7 +848,7 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) {
 	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 +865,7 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
 	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 +882,7 @@ func read(fd int, p []byte) (n int, err error) {
 	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 +905,7 @@ func Readlink(path string, buf []byte) (n int, err error) {
 	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -925,7 +927,7 @@ func Rename(from string, to string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -941,7 +943,7 @@ func Revoke(path string) (err error) {
 	_, _, 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 +959,7 @@ func Rmdir(path string) (err error) {
 	_, _, 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 +970,7 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 	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 +980,7 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
 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 +990,7 @@ func Select(n int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (err error) {
 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 +1000,7 @@ func Setegid(egid int) (err error) {
 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 +1010,7 @@ func Seteuid(euid int) (err error) {
 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 +1026,7 @@ func Setlogin(name string) (err error) {
 	_, _, 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 +1036,7 @@ func Setlogin(name string) (err error) {
 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 +1046,7 @@ func Setpgid(pid int, pgid int) (err error) {
 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 +1056,7 @@ func Setpriority(which int, who int, prio int) (err error) {
 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 +1066,7 @@ func Setregid(rgid int, egid int) (err error) {
 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 +1076,7 @@ func Setreuid(ruid int, euid int) (err error) {
 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 +1087,7 @@ func Setsid() (pid int, err error) {
 	r0, _, e1 := RawSyscall(SYS_SETSID, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1095,7 +1097,7 @@ func Setsid() (pid int, err error) {
 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 +1107,7 @@ func Settimeofday(tp *Timeval) (err error) {
 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 +1123,7 @@ func Stat(path string, stat *Stat_t) (err error) {
 	_, _, 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 +1139,7 @@ func Statfs(path string, stat *Statfs_t) (err error) {
 	_, _, 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 +1161,7 @@ func Symlink(path string, link string) (err error) {
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1169,7 +1171,7 @@ func Symlink(path string, link string) (err error) {
 func Sync() (err error) {
 	_, _, e1 := Syscall(SYS_SYNC, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -1185,7 +1187,7 @@ func Truncate(path string, length int64) (err error) {
 	_, _, 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 +1211,7 @@ func Unlink(path string) (err error) {
 	_, _, 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 +1227,7 @@ func Unmount(path string, flags int) (err error) {
 	_, _, 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 +1244,7 @@ func write(fd int, p []byte) (n int, err error) {
 	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 +1255,7 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
 	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 +1265,7 @@ func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (
 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 +1276,7 @@ func readlen(fd int, buf *byte, nbuf int) (n int, err error) {
 	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 +1287,7 @@ func writelen(fd int, buf *byte, nbuf int) (n int, err error) {
 	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_arm.go b/src/syscall/zsyscall_openbsd_arm.go
new file mode 100644
index 0000000..f40fb31
--- /dev/null
+++ b/src/syscall/zsyscall_openbsd_arm.go
@@ -0,0 +1,1293 @@
+// mksyscall.pl -l32 -openbsd -arm syscall_bsd.go syscall_openbsd.go syscall_openbsd_arm.go
+// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+
+// +build arm,openbsd
+
+package syscall
+
+import "unsafe"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
+	r0, _, e1 := RawSyscall(SYS_GETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 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 setgroups(ngid int, gid *_Gid_t) (err error) {
+	_, _, e1 := RawSyscall(SYS_SETGROUPS, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0)
+	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 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 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 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 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 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 Shutdown(s int, how int) (err error) {
+	_, _, e1 := Syscall(SYS_SHUTDOWN, uintptr(s), uintptr(how), 0)
+	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 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 kevent(kq int, change unsafe.Pointer, nchange int, event unsafe.Pointer, nevent int, timeout *Timespec) (n int, err error) {
+	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 = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func sysctl(mib []_C_int, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) {
+	var _p0 unsafe.Pointer
+	if len(mib) > 0 {
+		_p0 = unsafe.Pointer(&mib[0])
+	} else {
+		_p0 = unsafe.Pointer(&_zero)
+	}
+	_, _, 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 = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func utimes(path string, timeval *[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(timeval)), 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 futimes(fd int, timeval *[2]Timeval) (err error) {
+	_, _, e1 := Syscall(SYS_FUTIMES, uintptr(fd), uintptr(unsafe.Pointer(timeval)), 0)
+	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 pipe(p *[2]_C_int) (err error) {
+	_, _, e1 := RawSyscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 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_GETDENTS, 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 Access(path string, mode uint32) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_ACCESS, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 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 Adjtime(delta *Timeval, olddelta *Timeval) (err error) {
+	_, _, e1 := Syscall(SYS_ADJTIME, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0)
+	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 Chflags(path string, flags int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_CHFLAGS, 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 Chmod(path string, mode uint32) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_CHMOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 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 Chown(path string, uid int, gid int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_CHOWN, 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 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(fd int) (nfd int, err error) {
+	r0, _, e1 := Syscall(SYS_DUP, uintptr(fd), 0, 0)
+	nfd = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Dup2(from int, to int) (err error) {
+	_, _, e1 := Syscall(SYS_DUP2, uintptr(from), uintptr(to), 0)
+	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, uintptr(code), 0, 0)
+	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 Fchflags(fd int, flags int) (err error) {
+	_, _, e1 := Syscall(SYS_FCHFLAGS, uintptr(fd), uintptr(flags), 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 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 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 Fpathconf(fd int, name int) (val int, err error) {
+	r0, _, e1 := Syscall(SYS_FPATHCONF, uintptr(fd), uintptr(name), 0)
+	val = int(r0)
+	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 Fstatfs(fd int, stat *Statfs_t) (err error) {
+	_, _, e1 := Syscall(SYS_FSTATFS, 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 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 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 = 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() (uid int) {
+	r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0)
+	uid = 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 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 Getpgrp() (pgrp int) {
+	r0, _, _ := RawSyscall(SYS_GETPGRP, 0, 0, 0)
+	pgrp = 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)
+	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 Getrlimit(which int, lim *Rlimit) (err error) {
+	_, _, e1 := RawSyscall(SYS_GETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 0)
+	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 Getsid(pid int) (sid int, err error) {
+	r0, _, e1 := RawSyscall(SYS_GETSID, uintptr(pid), 0, 0)
+	sid = int(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 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 Issetugid() (tainted bool) {
+	r0, _, _ := Syscall(SYS_ISSETUGID, 0, 0, 0)
+	tainted = bool(r0 != 0)
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Kill(pid int, signum Signal) (err error) {
+	_, _, e1 := Syscall(SYS_KILL, uintptr(pid), uintptr(signum), 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Kqueue() (fd int, err error) {
+	r0, _, e1 := Syscall(SYS_KQUEUE, 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 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 Link(path string, link string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	var _p1 *byte
+	_p1, err = BytePtrFromString(link)
+	if err != nil {
+		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 = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Listen(s int, backlog int) (err error) {
+	_, _, e1 := Syscall(SYS_LISTEN, uintptr(s), uintptr(backlog), 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Lstat(path string, stat *Stat_t) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_LSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 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 Mkdir(path string, mode uint32) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_MKDIR, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 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 Mkfifo(path string, mode uint32) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_MKFIFO, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 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 Mknod(path string, mode uint32, dev int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_MKNOD, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev))
+	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 Open(path string, mode int, perm uint32) (fd int, err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		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 = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Pathconf(path string, name int) (val int, err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	r0, _, e1 := Syscall(SYS_PATHCONF, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0)
+	use(unsafe.Pointer(_p0))
+	val = int(r0)
+	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_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
+}
+
+// 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 Readlink(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 := Syscall(SYS_READLINK, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)))
+	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 Rename(from string, to string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(from)
+	if err != nil {
+		return
+	}
+	var _p1 *byte
+	_p1, err = BytePtrFromString(to)
+	if err != nil {
+		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 = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Revoke(path string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_REVOKE, 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 Rmdir(path string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_RMDIR, 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 Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
+	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 = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+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 = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setegid(egid int) (err error) {
+	_, _, e1 := RawSyscall(SYS_SETEGID, uintptr(egid), 0, 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Seteuid(euid int) (err error) {
+	_, _, e1 := RawSyscall(SYS_SETEUID, uintptr(euid), 0, 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setgid(gid int) (err error) {
+	_, _, e1 := RawSyscall(SYS_SETGID, 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 Setlogin(name string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(name)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_SETLOGIN, 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 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 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 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 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 Setrlimit(which int, lim *Rlimit) (err error) {
+	_, _, e1 := RawSyscall(SYS_SETRLIMIT, uintptr(which), uintptr(unsafe.Pointer(lim)), 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(tp *Timeval) (err error) {
+	_, _, e1 := RawSyscall(SYS_SETTIMEOFDAY, uintptr(unsafe.Pointer(tp)), 0, 0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Setuid(uid int) (err error) {
+	_, _, e1 := RawSyscall(SYS_SETUID, 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 Stat(path string, stat *Stat_t) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 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 Statfs(path string, stat *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(stat)), 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 Symlink(path string, link string) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	var _p1 *byte
+	_p1, err = BytePtrFromString(link)
+	if err != nil {
+		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 = errnoErr(e1)
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Sync() (err error) {
+	_, _, e1 := Syscall(SYS_SYNC, 0, 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 := Syscall6(SYS_TRUNCATE, uintptr(unsafe.Pointer(_p0)), 0, uintptr(length), uintptr(length>>32), 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 Umask(newmask int) (oldmask int) {
+	r0, _, _ := Syscall(SYS_UMASK, uintptr(newmask), 0, 0)
+	oldmask = int(r0)
+	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)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_UNLINK, 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 Unmount(path string, flags int) (err error) {
+	var _p0 *byte
+	_p0, err = BytePtrFromString(path)
+	if err != nil {
+		return
+	}
+	_, _, e1 := Syscall(SYS_UNMOUNT, 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 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 mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) {
+	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 = 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 readlen(fd int, buf *byte, nbuf int) (n int, err error) {
+	r0, _, e1 := Syscall(SYS_READ, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
+	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, buf *byte, nbuf int) (n int, err error) {
+	r0, _, e1 := Syscall(SYS_WRITE, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf))
+	n = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
+	}
+	return
+}
diff --git a/src/syscall/zsyscall_plan9_386.go b/src/syscall/zsyscall_plan9_386.go
index 44b74d7..a424e78 100644
--- a/src/syscall/zsyscall_plan9_386.go
+++ b/src/syscall/zsyscall_plan9_386.go
@@ -1,6 +1,8 @@
 // mksyscall.pl -l32 -plan9 syscall_plan9.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build 386,plan9
+
 package syscall
 
 import "unsafe"
@@ -23,7 +25,7 @@ func fd2path(fd int, buf []byte) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func pipe(p *[2]_C_int) (err error) {
+func pipe(p *[2]int32) (err error) {
 	r0, _, e1 := Syscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
 	if int32(r0) == -1 {
 		err = e1
@@ -50,18 +52,7 @@ func await(s []byte) (n int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func Dup(oldfd int, newfd int) (fd int, err error) {
-	r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), uintptr(newfd), 0)
-	fd = int(r0)
-	if int32(r0) == -1 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Open(path string, mode int) (fd int, err error) {
+func open(path string, mode int) (fd int, err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(path)
 	if err != nil {
@@ -78,7 +69,7 @@ func Open(path string, mode int) (fd int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func Create(path string, mode int, perm uint32) (fd int, err error) {
+func create(path string, mode int, perm uint32) (fd int, err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(path)
 	if err != nil {
@@ -95,7 +86,7 @@ func Create(path string, mode int, perm uint32) (fd int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func Remove(path string) (err error) {
+func remove(path string) (err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(path)
 	if err != nil {
@@ -111,58 +102,21 @@ func Remove(path string) (err error) {
 
 // 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)), uintptr(offset), uintptr(offset>>32), 0)
-	n = int(r0)
-	if int32(r0) == -1 {
-		err = 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)), uintptr(offset), uintptr(offset>>32), 0)
-	n = int(r0)
-	if int32(r0) == -1 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Close(fd int) (err error) {
-	r0, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
-	if int32(r0) == -1 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Chdir(path string) (err error) {
+func stat(path string, edir []byte) (n int, err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(path)
 	if err != nil {
 		return
 	}
-	r0, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
+	var _p1 unsafe.Pointer
+	if len(edir) > 0 {
+		_p1 = unsafe.Pointer(&edir[0])
+	} else {
+		_p1 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir)))
 	use(unsafe.Pointer(_p0))
+	n = int(r0)
 	if int32(r0) == -1 {
 		err = e1
 	}
@@ -171,7 +125,7 @@ func Chdir(path string) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func Bind(name string, old string, flag int) (err error) {
+func bind(name string, old string, flag int) (err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(name)
 	if err != nil {
@@ -193,7 +147,7 @@ func Bind(name string, old string, flag int) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func Mount(fd int, afd int, old string, flag int, aname string) (err error) {
+func mount(fd int, afd int, old string, flag int, aname string) (err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(old)
 	if err != nil {
@@ -215,7 +169,7 @@ func Mount(fd int, afd int, old string, flag int, aname string) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func Stat(path string, edir []byte) (n int, err error) {
+func wstat(path string, edir []byte) (err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(path)
 	if err != nil {
@@ -227,8 +181,51 @@ func Stat(path string, edir []byte) (n int, err error) {
 	} else {
 		_p1 = unsafe.Pointer(&_zero)
 	}
-	r0, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir)))
+	r0, _, e1 := Syscall(SYS_WSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir)))
 	use(unsafe.Pointer(_p0))
+	if int32(r0) == -1 {
+		err = 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
+	}
+	r0, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
+	use(unsafe.Pointer(_p0))
+	if int32(r0) == -1 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Dup(oldfd int, newfd int) (fd int, err error) {
+	r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), uintptr(newfd), 0)
+	fd = int(r0)
+	if int32(r0) == -1 {
+		err = 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)), uintptr(offset), uintptr(offset>>32), 0)
 	n = int(r0)
 	if int32(r0) == -1 {
 		err = e1
@@ -238,14 +235,14 @@ func Stat(path string, edir []byte) (n int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func Fstat(fd int, edir []byte) (n int, err error) {
+func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
 	var _p0 unsafe.Pointer
-	if len(edir) > 0 {
-		_p0 = unsafe.Pointer(&edir[0])
+	if len(p) > 0 {
+		_p0 = unsafe.Pointer(&p[0])
 	} else {
 		_p0 = unsafe.Pointer(&_zero)
 	}
-	r0, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir)))
+	r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
 	n = int(r0)
 	if int32(r0) == -1 {
 		err = e1
@@ -255,20 +252,25 @@ func Fstat(fd int, edir []byte) (n int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func Wstat(path string, edir []byte) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		return
+func Close(fd int) (err error) {
+	r0, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
+	if int32(r0) == -1 {
+		err = e1
 	}
-	var _p1 unsafe.Pointer
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fstat(fd int, edir []byte) (n int, err error) {
+	var _p0 unsafe.Pointer
 	if len(edir) > 0 {
-		_p1 = unsafe.Pointer(&edir[0])
+		_p0 = unsafe.Pointer(&edir[0])
 	} else {
-		_p1 = unsafe.Pointer(&_zero)
+		_p0 = unsafe.Pointer(&_zero)
 	}
-	r0, _, e1 := Syscall(SYS_WSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir)))
-	use(unsafe.Pointer(_p0))
+	r0, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir)))
+	n = int(r0)
 	if int32(r0) == -1 {
 		err = e1
 	}
diff --git a/src/syscall/zsyscall_plan9_amd64.go b/src/syscall/zsyscall_plan9_amd64.go
index 44b74d7..d58556b 100644
--- a/src/syscall/zsyscall_plan9_amd64.go
+++ b/src/syscall/zsyscall_plan9_amd64.go
@@ -1,6 +1,8 @@
 // mksyscall.pl -l32 -plan9 syscall_plan9.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build amd64,plan9
+
 package syscall
 
 import "unsafe"
@@ -23,7 +25,7 @@ func fd2path(fd int, buf []byte) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func pipe(p *[2]_C_int) (err error) {
+func pipe(p *[2]int32) (err error) {
 	r0, _, e1 := Syscall(SYS_PIPE, uintptr(unsafe.Pointer(p)), 0, 0)
 	if int32(r0) == -1 {
 		err = e1
@@ -50,18 +52,7 @@ func await(s []byte) (n int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func Dup(oldfd int, newfd int) (fd int, err error) {
-	r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), uintptr(newfd), 0)
-	fd = int(r0)
-	if int32(r0) == -1 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Open(path string, mode int) (fd int, err error) {
+func open(path string, mode int) (fd int, err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(path)
 	if err != nil {
@@ -78,7 +69,7 @@ func Open(path string, mode int) (fd int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func Create(path string, mode int, perm uint32) (fd int, err error) {
+func create(path string, mode int, perm uint32) (fd int, err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(path)
 	if err != nil {
@@ -95,7 +86,7 @@ func Create(path string, mode int, perm uint32) (fd int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func Remove(path string) (err error) {
+func remove(path string) (err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(path)
 	if err != nil {
@@ -111,58 +102,21 @@ func Remove(path string) (err error) {
 
 // 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)), uintptr(offset), uintptr(offset>>32), 0)
-	n = int(r0)
-	if int32(r0) == -1 {
-		err = 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)), uintptr(offset), uintptr(offset>>32), 0)
-	n = int(r0)
-	if int32(r0) == -1 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Close(fd int) (err error) {
-	r0, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
-	if int32(r0) == -1 {
-		err = e1
-	}
-	return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
-func Chdir(path string) (err error) {
+func stat(path string, edir []byte) (n int, err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(path)
 	if err != nil {
 		return
 	}
-	r0, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
+	var _p1 unsafe.Pointer
+	if len(edir) > 0 {
+		_p1 = unsafe.Pointer(&edir[0])
+	} else {
+		_p1 = unsafe.Pointer(&_zero)
+	}
+	r0, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir)))
 	use(unsafe.Pointer(_p0))
+	n = int(r0)
 	if int32(r0) == -1 {
 		err = e1
 	}
@@ -171,7 +125,7 @@ func Chdir(path string) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func Bind(name string, old string, flag int) (err error) {
+func bind(name string, old string, flag int) (err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(name)
 	if err != nil {
@@ -193,7 +147,7 @@ func Bind(name string, old string, flag int) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func Mount(fd int, afd int, old string, flag int, aname string) (err error) {
+func mount(fd int, afd int, old string, flag int, aname string) (err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(old)
 	if err != nil {
@@ -215,7 +169,7 @@ func Mount(fd int, afd int, old string, flag int, aname string) (err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func Stat(path string, edir []byte) (n int, err error) {
+func wstat(path string, edir []byte) (err error) {
 	var _p0 *byte
 	_p0, err = BytePtrFromString(path)
 	if err != nil {
@@ -227,8 +181,51 @@ func Stat(path string, edir []byte) (n int, err error) {
 	} else {
 		_p1 = unsafe.Pointer(&_zero)
 	}
-	r0, _, e1 := Syscall(SYS_STAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir)))
+	r0, _, e1 := Syscall(SYS_WSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir)))
 	use(unsafe.Pointer(_p0))
+	if int32(r0) == -1 {
+		err = 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
+	}
+	r0, _, e1 := Syscall(SYS_CHDIR, uintptr(unsafe.Pointer(_p0)), 0, 0)
+	use(unsafe.Pointer(_p0))
+	if int32(r0) == -1 {
+		err = e1
+	}
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Dup(oldfd int, newfd int) (fd int, err error) {
+	r0, _, e1 := Syscall(SYS_DUP, uintptr(oldfd), uintptr(newfd), 0)
+	fd = int(r0)
+	if int32(r0) == -1 {
+		err = 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)), uintptr(offset), uintptr(offset>>32), 0)
 	n = int(r0)
 	if int32(r0) == -1 {
 		err = e1
@@ -238,14 +235,14 @@ func Stat(path string, edir []byte) (n int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func Fstat(fd int, edir []byte) (n int, err error) {
+func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
 	var _p0 unsafe.Pointer
-	if len(edir) > 0 {
-		_p0 = unsafe.Pointer(&edir[0])
+	if len(p) > 0 {
+		_p0 = unsafe.Pointer(&p[0])
 	} else {
 		_p0 = unsafe.Pointer(&_zero)
 	}
-	r0, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir)))
+	r0, _, e1 := Syscall6(SYS_PWRITE, uintptr(fd), uintptr(_p0), uintptr(len(p)), uintptr(offset), uintptr(offset>>32), 0)
 	n = int(r0)
 	if int32(r0) == -1 {
 		err = e1
@@ -255,20 +252,25 @@ func Fstat(fd int, edir []byte) (n int, err error) {
 
 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
 
-func Wstat(path string, edir []byte) (err error) {
-	var _p0 *byte
-	_p0, err = BytePtrFromString(path)
-	if err != nil {
-		return
+func Close(fd int) (err error) {
+	r0, _, e1 := Syscall(SYS_CLOSE, uintptr(fd), 0, 0)
+	if int32(r0) == -1 {
+		err = e1
 	}
-	var _p1 unsafe.Pointer
+	return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func Fstat(fd int, edir []byte) (n int, err error) {
+	var _p0 unsafe.Pointer
 	if len(edir) > 0 {
-		_p1 = unsafe.Pointer(&edir[0])
+		_p0 = unsafe.Pointer(&edir[0])
 	} else {
-		_p1 = unsafe.Pointer(&_zero)
+		_p0 = unsafe.Pointer(&_zero)
 	}
-	r0, _, e1 := Syscall(SYS_WSTAT, uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(edir)))
-	use(unsafe.Pointer(_p0))
+	r0, _, e1 := Syscall(SYS_FSTAT, uintptr(fd), uintptr(_p0), uintptr(len(edir)))
+	n = int(r0)
 	if int32(r0) == -1 {
 		err = e1
 	}
diff --git a/src/syscall/zsyscall_solaris_amd64.go b/src/syscall/zsyscall_solaris_amd64.go
index 43b224a..cabab7e 100644
--- a/src/syscall/zsyscall_solaris_amd64.go
+++ b/src/syscall/zsyscall_solaris_amd64.go
@@ -1,136 +1,302 @@
 // mksyscall_solaris.pl syscall_solaris.go syscall_solaris_amd64.go
 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
 
+// +build amd64,solaris
+
 package syscall
 
 import "unsafe"
 
+//go:cgo_import_dynamic libc_getgroups getgroups "libc.so"
+//go:cgo_import_dynamic libc_setgroups setgroups "libc.so"
+//go:cgo_import_dynamic libc_fcntl fcntl "libc.so"
+//go:cgo_import_dynamic libc_accept accept "libsocket.so"
+//go:cgo_import_dynamic libc_sendmsg sendmsg "libsocket.so"
+//go:cgo_import_dynamic libc_Access access "libc.so"
+//go:cgo_import_dynamic libc_Adjtime adjtime "libc.so"
+//go:cgo_import_dynamic libc_Chdir chdir "libc.so"
+//go:cgo_import_dynamic libc_Chmod chmod "libc.so"
+//go:cgo_import_dynamic libc_Chown chown "libc.so"
+//go:cgo_import_dynamic libc_Chroot chroot "libc.so"
+//go:cgo_import_dynamic libc_Close close "libc.so"
+//go:cgo_import_dynamic libc_Dup dup "libc.so"
+//go:cgo_import_dynamic libc_Exit exit "libc.so"
+//go:cgo_import_dynamic libc_Fchdir fchdir "libc.so"
+//go:cgo_import_dynamic libc_Fchmod fchmod "libc.so"
+//go:cgo_import_dynamic libc_Fchown fchown "libc.so"
+//go:cgo_import_dynamic libc_Fpathconf fpathconf "libc.so"
+//go:cgo_import_dynamic libc_Fstat fstat "libc.so"
+//go:cgo_import_dynamic libc_Getdents getdents "libc.so"
+//go:cgo_import_dynamic libc_Getgid getgid "libc.so"
+//go:cgo_import_dynamic libc_Getpid getpid "libc.so"
+//go:cgo_import_dynamic libc_Geteuid geteuid "libc.so"
+//go:cgo_import_dynamic libc_Getegid getegid "libc.so"
+//go:cgo_import_dynamic libc_Getppid getppid "libc.so"
+//go:cgo_import_dynamic libc_Getpriority getpriority "libc.so"
+//go:cgo_import_dynamic libc_Getrlimit getrlimit "libc.so"
+//go:cgo_import_dynamic libc_Gettimeofday gettimeofday "libc.so"
+//go:cgo_import_dynamic libc_Getuid getuid "libc.so"
+//go:cgo_import_dynamic libc_Kill kill "libc.so"
+//go:cgo_import_dynamic libc_Lchown lchown "libc.so"
+//go:cgo_import_dynamic libc_Link link "libc.so"
+//go:cgo_import_dynamic libc_listen listen "libsocket.so"
+//go:cgo_import_dynamic libc_Lstat lstat "libc.so"
+//go:cgo_import_dynamic libc_Mkdir mkdir "libc.so"
+//go:cgo_import_dynamic libc_Mknod mknod "libc.so"
+//go:cgo_import_dynamic libc_Nanosleep nanosleep "libc.so"
+//go:cgo_import_dynamic libc_Open open "libc.so"
+//go:cgo_import_dynamic libc_Pathconf pathconf "libc.so"
+//go:cgo_import_dynamic libc_Pread pread "libc.so"
+//go:cgo_import_dynamic libc_Pwrite pwrite "libc.so"
+//go:cgo_import_dynamic libc_read read "libc.so"
+//go:cgo_import_dynamic libc_Readlink readlink "libc.so"
+//go:cgo_import_dynamic libc_Rename rename "libc.so"
+//go:cgo_import_dynamic libc_Rmdir rmdir "libc.so"
+//go:cgo_import_dynamic libc_lseek lseek "libc.so"
+//go:cgo_import_dynamic libc_sendfile sendfile "libsendfile.so"
+//go:cgo_import_dynamic libc_Setegid setegid "libc.so"
+//go:cgo_import_dynamic libc_Seteuid seteuid "libc.so"
+//go:cgo_import_dynamic libc_Setgid setgid "libc.so"
+//go:cgo_import_dynamic libc_Setpgid setpgid "libc.so"
+//go:cgo_import_dynamic libc_Setpriority setpriority "libc.so"
+//go:cgo_import_dynamic libc_Setregid setregid "libc.so"
+//go:cgo_import_dynamic libc_Setreuid setreuid "libc.so"
+//go:cgo_import_dynamic libc_Setrlimit setrlimit "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_shutdown shutdown "libsocket.so"
+//go:cgo_import_dynamic libc_Stat stat "libc.so"
+//go:cgo_import_dynamic libc_Symlink symlink "libc.so"
+//go:cgo_import_dynamic libc_Sync sync "libc.so"
+//go:cgo_import_dynamic libc_Truncate truncate "libc.so"
+//go:cgo_import_dynamic libc_Fsync fsync "libc.so"
+//go:cgo_import_dynamic libc_Ftruncate ftruncate "libc.so"
+//go:cgo_import_dynamic libc_Umask umask "libc.so"
+//go:cgo_import_dynamic libc_Unlink unlink "libc.so"
+//go:cgo_import_dynamic libc_Utimes utimes "libc.so"
+//go:cgo_import_dynamic libc_bind bind "libsocket.so"
+//go:cgo_import_dynamic libc_connect connect "libsocket.so"
+//go:cgo_import_dynamic libc_mmap mmap "libc.so"
+//go:cgo_import_dynamic libc_munmap munmap "libc.so"
+//go:cgo_import_dynamic libc_sendto sendto "libsocket.so"
+//go:cgo_import_dynamic libc_socket socket "libsocket.so"
+//go:cgo_import_dynamic libc_socketpair socketpair "libsocket.so"
+//go:cgo_import_dynamic libc_write write "libc.so"
+//go:cgo_import_dynamic libc_getsockopt getsockopt "libsocket.so"
+//go:cgo_import_dynamic libc_getpeername getpeername "libsocket.so"
+//go:cgo_import_dynamic libc_getsockname getsockname "libsocket.so"
+//go:cgo_import_dynamic libc_setsockopt setsockopt "libsocket.so"
+//go:cgo_import_dynamic libc_recvfrom recvfrom "libsocket.so"
+//go:cgo_import_dynamic libc_recvmsg recvmsg "libsocket.so"
+
+//go:linkname libc_getgroups libc_getgroups
+//go:linkname libc_setgroups libc_setgroups
+//go:linkname libc_fcntl libc_fcntl
+//go:linkname libc_accept libc_accept
+//go:linkname libc_sendmsg libc_sendmsg
+//go:linkname libc_Access libc_Access
+//go:linkname libc_Adjtime libc_Adjtime
+//go:linkname libc_Chdir libc_Chdir
+//go:linkname libc_Chmod libc_Chmod
+//go:linkname libc_Chown libc_Chown
+//go:linkname libc_Chroot libc_Chroot
+//go:linkname libc_Close libc_Close
+//go:linkname libc_Dup libc_Dup
+//go:linkname libc_Exit libc_Exit
+//go:linkname libc_Fchdir libc_Fchdir
+//go:linkname libc_Fchmod libc_Fchmod
+//go:linkname libc_Fchown libc_Fchown
+//go:linkname libc_Fpathconf libc_Fpathconf
+//go:linkname libc_Fstat libc_Fstat
+//go:linkname libc_Getdents libc_Getdents
+//go:linkname libc_Getgid libc_Getgid
+//go:linkname libc_Getpid libc_Getpid
+//go:linkname libc_Geteuid libc_Geteuid
+//go:linkname libc_Getegid libc_Getegid
+//go:linkname libc_Getppid libc_Getppid
+//go:linkname libc_Getpriority libc_Getpriority
+//go:linkname libc_Getrlimit libc_Getrlimit
+//go:linkname libc_Gettimeofday libc_Gettimeofday
+//go:linkname libc_Getuid libc_Getuid
+//go:linkname libc_Kill libc_Kill
+//go:linkname libc_Lchown libc_Lchown
+//go:linkname libc_Link libc_Link
+//go:linkname libc_listen libc_listen
+//go:linkname libc_Lstat libc_Lstat
+//go:linkname libc_Mkdir libc_Mkdir
+//go:linkname libc_Mknod libc_Mknod
+//go:linkname libc_Nanosleep libc_Nanosleep
+//go:linkname libc_Open libc_Open
+//go:linkname libc_Pathconf libc_Pathconf
+//go:linkname libc_Pread libc_Pread
+//go:linkname libc_Pwrite libc_Pwrite
+//go:linkname libc_read libc_read
+//go:linkname libc_Readlink libc_Readlink
+//go:linkname libc_Rename libc_Rename
+//go:linkname libc_Rmdir libc_Rmdir
+//go:linkname libc_lseek libc_lseek
+//go:linkname libc_sendfile libc_sendfile
+//go:linkname libc_Setegid libc_Setegid
+//go:linkname libc_Seteuid libc_Seteuid
+//go:linkname libc_Setgid libc_Setgid
+//go:linkname libc_Setpgid libc_Setpgid
+//go:linkname libc_Setpriority libc_Setpriority
+//go:linkname libc_Setregid libc_Setregid
+//go:linkname libc_Setreuid libc_Setreuid
+//go:linkname libc_Setrlimit libc_Setrlimit
+//go:linkname libc_Setsid libc_Setsid
+//go:linkname libc_Setuid libc_Setuid
+//go:linkname libc_shutdown libc_shutdown
+//go:linkname libc_Stat libc_Stat
+//go:linkname libc_Symlink libc_Symlink
+//go:linkname libc_Sync libc_Sync
+//go:linkname libc_Truncate libc_Truncate
+//go:linkname libc_Fsync libc_Fsync
+//go:linkname libc_Ftruncate libc_Ftruncate
+//go:linkname libc_Umask libc_Umask
+//go:linkname libc_Unlink libc_Unlink
+//go:linkname libc_Utimes libc_Utimes
+//go:linkname libc_bind libc_bind
+//go:linkname libc_connect libc_connect
+//go:linkname libc_mmap libc_mmap
+//go:linkname libc_munmap libc_munmap
+//go:linkname libc_sendto libc_sendto
+//go:linkname libc_socket libc_socket
+//go:linkname libc_socketpair libc_socketpair
+//go:linkname libc_write libc_write
+//go:linkname libc_getsockopt libc_getsockopt
+//go:linkname libc_getpeername libc_getpeername
+//go:linkname libc_getsockname libc_getsockname
+//go:linkname libc_setsockopt libc_setsockopt
+//go:linkname libc_recvfrom libc_recvfrom
+//go:linkname libc_recvmsg libc_recvmsg
+
+type libcFunc uintptr
+
 var (
-	modlibc      = newLazySO("libc.so")
-	modlibsocket = newLazySO("libsocket.so")
-
-	procgetgroups    = modlibc.NewProc("getgroups")
-	procsetgroups    = modlibc.NewProc("setgroups")
-	procfcntl        = modlibc.NewProc("fcntl")
-	procaccept       = modlibsocket.NewProc("accept")
-	procsendmsg      = modlibsocket.NewProc("sendmsg")
-	procAccess       = modlibc.NewProc("access")
-	procAdjtime      = modlibc.NewProc("adjtime")
-	procChdir        = modlibc.NewProc("chdir")
-	procChmod        = modlibc.NewProc("chmod")
-	procChown        = modlibc.NewProc("chown")
-	procChroot       = modlibc.NewProc("chroot")
-	procClose        = modlibc.NewProc("close")
-	procDup          = modlibc.NewProc("dup")
-	procExit         = modlibc.NewProc("exit")
-	procFchdir       = modlibc.NewProc("fchdir")
-	procFchmod       = modlibc.NewProc("fchmod")
-	procFchown       = modlibc.NewProc("fchown")
-	procFpathconf    = modlibc.NewProc("fpathconf")
-	procFstat        = modlibc.NewProc("fstat")
-	procGetdents     = modlibc.NewProc("getdents")
-	procGetgid       = modlibc.NewProc("getgid")
-	procGetpid       = modlibc.NewProc("getpid")
-	procGeteuid      = modlibc.NewProc("geteuid")
-	procGetegid      = modlibc.NewProc("getegid")
-	procGetppid      = modlibc.NewProc("getppid")
-	procGetpriority  = modlibc.NewProc("getpriority")
-	procGetrlimit    = modlibc.NewProc("getrlimit")
-	procGettimeofday = modlibc.NewProc("gettimeofday")
-	procGetuid       = modlibc.NewProc("getuid")
-	procKill         = modlibc.NewProc("kill")
-	procLchown       = modlibc.NewProc("lchown")
-	procLink         = modlibc.NewProc("link")
-	proclisten       = modlibsocket.NewProc("listen")
-	procLstat        = modlibc.NewProc("lstat")
-	procMkdir        = modlibc.NewProc("mkdir")
-	procMknod        = modlibc.NewProc("mknod")
-	procNanosleep    = modlibc.NewProc("nanosleep")
-	procOpen         = modlibc.NewProc("open")
-	procPathconf     = modlibc.NewProc("pathconf")
-	procPread        = modlibc.NewProc("pread")
-	procPwrite       = modlibc.NewProc("pwrite")
-	procread         = modlibc.NewProc("read")
-	procReadlink     = modlibc.NewProc("readlink")
-	procRename       = modlibc.NewProc("rename")
-	procRmdir        = modlibc.NewProc("rmdir")
-	proclseek        = modlibc.NewProc("lseek")
-	procSetegid      = modlibc.NewProc("setegid")
-	procSeteuid      = modlibc.NewProc("seteuid")
-	procSetgid       = modlibc.NewProc("setgid")
-	procSetpgid      = modlibc.NewProc("setpgid")
-	procSetpriority  = modlibc.NewProc("setpriority")
-	procSetregid     = modlibc.NewProc("setregid")
-	procSetreuid     = modlibc.NewProc("setreuid")
-	procSetrlimit    = modlibc.NewProc("setrlimit")
-	procSetsid       = modlibc.NewProc("setsid")
-	procSetuid       = modlibc.NewProc("setuid")
-	procshutdown     = modlibsocket.NewProc("shutdown")
-	procStat         = modlibc.NewProc("stat")
-	procSymlink      = modlibc.NewProc("symlink")
-	procSync         = modlibc.NewProc("sync")
-	procTruncate     = modlibc.NewProc("truncate")
-	procFsync        = modlibc.NewProc("fsync")
-	procFtruncate    = modlibc.NewProc("ftruncate")
-	procUmask        = modlibc.NewProc("umask")
-	procUnlink       = modlibc.NewProc("unlink")
-	procUtimes       = modlibc.NewProc("utimes")
-	procbind         = modlibsocket.NewProc("bind")
-	procconnect      = modlibsocket.NewProc("connect")
-	procmmap         = modlibc.NewProc("mmap")
-	procmunmap       = modlibc.NewProc("munmap")
-	procsendto       = modlibsocket.NewProc("sendto")
-	procsocket       = modlibsocket.NewProc("socket")
-	procsocketpair   = modlibsocket.NewProc("socketpair")
-	procwrite        = modlibc.NewProc("write")
-	procgetsockopt   = modlibsocket.NewProc("getsockopt")
-	procgetpeername  = modlibsocket.NewProc("getpeername")
-	procgetsockname  = modlibsocket.NewProc("getsockname")
-	procsetsockopt   = modlibsocket.NewProc("setsockopt")
-	procrecvfrom     = modlibsocket.NewProc("recvfrom")
-	procrecvmsg      = modlibsocket.NewProc("recvmsg")
+	libc_getgroups,
+	libc_setgroups,
+	libc_fcntl,
+	libc_accept,
+	libc_sendmsg,
+	libc_Access,
+	libc_Adjtime,
+	libc_Chdir,
+	libc_Chmod,
+	libc_Chown,
+	libc_Chroot,
+	libc_Close,
+	libc_Dup,
+	libc_Exit,
+	libc_Fchdir,
+	libc_Fchmod,
+	libc_Fchown,
+	libc_Fpathconf,
+	libc_Fstat,
+	libc_Getdents,
+	libc_Getgid,
+	libc_Getpid,
+	libc_Geteuid,
+	libc_Getegid,
+	libc_Getppid,
+	libc_Getpriority,
+	libc_Getrlimit,
+	libc_Gettimeofday,
+	libc_Getuid,
+	libc_Kill,
+	libc_Lchown,
+	libc_Link,
+	libc_listen,
+	libc_Lstat,
+	libc_Mkdir,
+	libc_Mknod,
+	libc_Nanosleep,
+	libc_Open,
+	libc_Pathconf,
+	libc_Pread,
+	libc_Pwrite,
+	libc_read,
+	libc_Readlink,
+	libc_Rename,
+	libc_Rmdir,
+	libc_lseek,
+	libc_sendfile,
+	libc_Setegid,
+	libc_Seteuid,
+	libc_Setgid,
+	libc_Setpgid,
+	libc_Setpriority,
+	libc_Setregid,
+	libc_Setreuid,
+	libc_Setrlimit,
+	libc_Setsid,
+	libc_Setuid,
+	libc_shutdown,
+	libc_Stat,
+	libc_Symlink,
+	libc_Sync,
+	libc_Truncate,
+	libc_Fsync,
+	libc_Ftruncate,
+	libc_Umask,
+	libc_Unlink,
+	libc_Utimes,
+	libc_bind,
+	libc_connect,
+	libc_mmap,
+	libc_munmap,
+	libc_sendto,
+	libc_socket,
+	libc_socketpair,
+	libc_write,
+	libc_getsockopt,
+	libc_getpeername,
+	libc_getsockname,
+	libc_setsockopt,
+	libc_recvfrom,
+	libc_recvmsg libcFunc
 )
 
 func getgroups(ngid int, gid *_Gid_t) (n int, err error) {
-	r0, _, e1 := rawSysvicall6(procgetgroups.Addr(), 2, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0, 0, 0, 0)
+	r0, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_getgroups)), 2, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0, 0, 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
 
 func setgroups(ngid int, gid *_Gid_t) (err error) {
-	_, _, e1 := rawSysvicall6(procsetgroups.Addr(), 2, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0, 0, 0, 0)
+	_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_setgroups)), 2, uintptr(ngid), uintptr(unsafe.Pointer(gid)), 0, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
 
 func fcntl(fd int, cmd int, arg int) (val int, err error) {
-	r0, _, e1 := sysvicall6(procfcntl.Addr(), 3, uintptr(fd), uintptr(cmd), uintptr(arg), 0, 0, 0)
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_fcntl)), 3, uintptr(fd), uintptr(cmd), uintptr(arg), 0, 0, 0)
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
 
 func accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) {
-	r0, _, e1 := sysvicall6(procaccept.Addr(), 3, uintptr(s), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_accept)), 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
 }
 
 func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
-	r0, _, e1 := sysvicall6(procsendmsg.Addr(), 3, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), 0, 0, 0)
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_sendmsg)), 3, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), 0, 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -141,18 +307,18 @@ func Access(path string, mode uint32) (err error) {
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(procAccess.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Access)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
 
 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)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Adjtime)), 2, uintptr(unsafe.Pointer(delta)), uintptr(unsafe.Pointer(olddelta)), 0, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -163,10 +329,10 @@ func Chdir(path string) (err error) {
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(procChdir.Addr(), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Chdir)), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -177,10 +343,10 @@ func Chmod(path string, mode uint32) (err error) {
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(procChmod.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Chmod)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -191,10 +357,10 @@ func Chown(path string, uid int, gid int) (err error) {
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(procChown.Addr(), 3, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Chown)), 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
 }
@@ -205,73 +371,73 @@ func Chroot(path string) (err error) {
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(procChroot.Addr(), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Chroot)), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
 
 func Close(fd int) (err error) {
-	_, _, e1 := sysvicall6(procClose.Addr(), 1, uintptr(fd), 0, 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Close)), 1, uintptr(fd), 0, 0, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
 
 func Dup(fd int) (nfd int, err error) {
-	r0, _, e1 := sysvicall6(procDup.Addr(), 1, uintptr(fd), 0, 0, 0, 0, 0)
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Dup)), 1, uintptr(fd), 0, 0, 0, 0, 0)
 	nfd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
 
 func Exit(code int) {
-	sysvicall6(procExit.Addr(), 1, uintptr(code), 0, 0, 0, 0, 0)
+	sysvicall6(uintptr(unsafe.Pointer(&libc_Exit)), 1, uintptr(code), 0, 0, 0, 0, 0)
 	return
 }
 
 func Fchdir(fd int) (err error) {
-	_, _, e1 := sysvicall6(procFchdir.Addr(), 1, uintptr(fd), 0, 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Fchdir)), 1, uintptr(fd), 0, 0, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
 
 func Fchmod(fd int, mode uint32) (err error) {
-	_, _, e1 := sysvicall6(procFchmod.Addr(), 2, uintptr(fd), uintptr(mode), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Fchmod)), 2, uintptr(fd), uintptr(mode), 0, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
 
 func Fchown(fd int, uid int, gid int) (err error) {
-	_, _, e1 := sysvicall6(procFchown.Addr(), 3, uintptr(fd), uintptr(uid), uintptr(gid), 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Fchown)), 3, uintptr(fd), uintptr(uid), uintptr(gid), 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
 
 func Fpathconf(fd int, name int) (val int, err error) {
-	r0, _, e1 := sysvicall6(procFpathconf.Addr(), 2, uintptr(fd), uintptr(name), 0, 0, 0, 0)
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Fpathconf)), 2, uintptr(fd), uintptr(name), 0, 0, 0, 0)
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
 
 func Fstat(fd int, stat *Stat_t) (err error) {
-	_, _, e1 := sysvicall6(procFstat.Addr(), 2, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Fstat)), 2, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -281,79 +447,79 @@ func Getdents(fd int, buf []byte, basep *uintptr) (n int, err error) {
 	if len(buf) > 0 {
 		_p0 = &buf[0]
 	}
-	r0, _, e1 := sysvicall6(procGetdents.Addr(), 4, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(unsafe.Pointer(basep)), 0, 0)
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Getdents)), 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
 }
 
 func Getgid() (gid int) {
-	r0, _, _ := rawSysvicall6(procGetgid.Addr(), 0, 0, 0, 0, 0, 0, 0)
+	r0, _, _ := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Getgid)), 0, 0, 0, 0, 0, 0, 0)
 	gid = int(r0)
 	return
 }
 
 func Getpid() (pid int) {
-	r0, _, _ := rawSysvicall6(procGetpid.Addr(), 0, 0, 0, 0, 0, 0, 0)
+	r0, _, _ := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Getpid)), 0, 0, 0, 0, 0, 0, 0)
 	pid = int(r0)
 	return
 }
 
 func Geteuid() (euid int) {
-	r0, _, _ := sysvicall6(procGeteuid.Addr(), 0, 0, 0, 0, 0, 0, 0)
+	r0, _, _ := sysvicall6(uintptr(unsafe.Pointer(&libc_Geteuid)), 0, 0, 0, 0, 0, 0, 0)
 	euid = int(r0)
 	return
 }
 
 func Getegid() (egid int) {
-	r0, _, _ := sysvicall6(procGetegid.Addr(), 0, 0, 0, 0, 0, 0, 0)
+	r0, _, _ := sysvicall6(uintptr(unsafe.Pointer(&libc_Getegid)), 0, 0, 0, 0, 0, 0, 0)
 	egid = int(r0)
 	return
 }
 
 func Getppid() (ppid int) {
-	r0, _, _ := sysvicall6(procGetppid.Addr(), 0, 0, 0, 0, 0, 0, 0)
+	r0, _, _ := sysvicall6(uintptr(unsafe.Pointer(&libc_Getppid)), 0, 0, 0, 0, 0, 0, 0)
 	ppid = int(r0)
 	return
 }
 
 func Getpriority(which int, who int) (n int, err error) {
-	r0, _, e1 := sysvicall6(procGetpriority.Addr(), 2, uintptr(which), uintptr(who), 0, 0, 0, 0)
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Getpriority)), 2, uintptr(which), uintptr(who), 0, 0, 0, 0)
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
 
 func Getrlimit(which int, lim *Rlimit) (err error) {
-	_, _, e1 := rawSysvicall6(procGetrlimit.Addr(), 2, uintptr(which), uintptr(unsafe.Pointer(lim)), 0, 0, 0, 0)
+	_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Getrlimit)), 2, uintptr(which), uintptr(unsafe.Pointer(lim)), 0, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
 
 func Gettimeofday(tv *Timeval) (err error) {
-	_, _, e1 := rawSysvicall6(procGettimeofday.Addr(), 1, uintptr(unsafe.Pointer(tv)), 0, 0, 0, 0, 0)
+	_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Gettimeofday)), 1, uintptr(unsafe.Pointer(tv)), 0, 0, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
 
 func Getuid() (uid int) {
-	r0, _, _ := rawSysvicall6(procGetuid.Addr(), 0, 0, 0, 0, 0, 0, 0)
+	r0, _, _ := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Getuid)), 0, 0, 0, 0, 0, 0, 0)
 	uid = int(r0)
 	return
 }
 
 func Kill(pid int, signum Signal) (err error) {
-	_, _, e1 := sysvicall6(procKill.Addr(), 2, uintptr(pid), uintptr(signum), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Kill)), 2, uintptr(pid), uintptr(signum), 0, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -364,10 +530,10 @@ func Lchown(path string, uid int, gid int) (err error) {
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(procLchown.Addr(), 3, uintptr(unsafe.Pointer(_p0)), uintptr(uid), uintptr(gid), 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Lchown)), 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
 }
@@ -383,19 +549,19 @@ func Link(path string, link string) (err error) {
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(procLink.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Link)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
 
 func Listen(s int, backlog int) (err error) {
-	_, _, e1 := sysvicall6(proclisten.Addr(), 2, uintptr(s), uintptr(backlog), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_listen)), 2, uintptr(s), uintptr(backlog), 0, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -406,10 +572,10 @@ func Lstat(path string, stat *Stat_t) (err error) {
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(procLstat.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Lstat)), 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
 }
@@ -420,10 +586,10 @@ func Mkdir(path string, mode uint32) (err error) {
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(procMkdir.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Mkdir)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(mode), 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -434,18 +600,18 @@ func Mknod(path string, mode uint32, dev int) (err error) {
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(procMknod.Addr(), 3, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(dev), 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Mknod)), 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
 }
 
 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)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Nanosleep)), 2, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)), 0, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -456,11 +622,11 @@ func Open(path string, mode int, perm uint32) (fd int, err error) {
 	if err != nil {
 		return
 	}
-	r0, _, e1 := sysvicall6(procOpen.Addr(), 3, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm), 0, 0, 0)
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Open)), 3, uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(perm), 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -471,11 +637,11 @@ func Pathconf(path string, name int) (val int, err error) {
 	if err != nil {
 		return
 	}
-	r0, _, e1 := sysvicall6(procPathconf.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0, 0, 0, 0)
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Pathconf)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(name), 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	val = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -485,10 +651,10 @@ func Pread(fd int, p []byte, offset int64) (n int, err error) {
 	if len(p) > 0 {
 		_p0 = &p[0]
 	}
-	r0, _, e1 := sysvicall6(procPread.Addr(), 4, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(offset), 0, 0)
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Pread)), 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
 }
@@ -498,10 +664,10 @@ func Pwrite(fd int, p []byte, offset int64) (n int, err error) {
 	if len(p) > 0 {
 		_p0 = &p[0]
 	}
-	r0, _, e1 := sysvicall6(procPwrite.Addr(), 4, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), uintptr(offset), 0, 0)
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Pwrite)), 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
 }
@@ -511,10 +677,10 @@ func read(fd int, p []byte) (n int, err error) {
 	if len(p) > 0 {
 		_p0 = &p[0]
 	}
-	r0, _, e1 := sysvicall6(procread.Addr(), 3, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), 0, 0, 0)
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_read)), 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
 }
@@ -529,11 +695,11 @@ func Readlink(path string, buf []byte) (n int, err error) {
 	if len(buf) > 0 {
 		_p1 = &buf[0]
 	}
-	r0, _, e1 := sysvicall6(procReadlink.Addr(), 3, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(len(buf)), 0, 0, 0)
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Readlink)), 3, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(len(buf)), 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	n = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -549,11 +715,11 @@ func Rename(from string, to string) (err error) {
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(procRename.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Rename)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -564,108 +730,117 @@ func Rmdir(path string) (err error) {
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(procRmdir.Addr(), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Rmdir)), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
 
 func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
-	r0, _, e1 := sysvicall6(proclseek.Addr(), 3, uintptr(fd), uintptr(offset), uintptr(whence), 0, 0, 0)
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_lseek)), 3, uintptr(fd), uintptr(offset), uintptr(whence), 0, 0, 0)
 	newoffset = int64(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
+	}
+	return
+}
+
+func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_sendfile)), 4, uintptr(outfd), uintptr(infd), uintptr(unsafe.Pointer(offset)), uintptr(count), 0, 0)
+	written = int(r0)
+	if e1 != 0 {
+		err = errnoErr(e1)
 	}
 	return
 }
 
 func Setegid(egid int) (err error) {
-	_, _, e1 := rawSysvicall6(procSetegid.Addr(), 1, uintptr(egid), 0, 0, 0, 0, 0)
+	_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Setegid)), 1, uintptr(egid), 0, 0, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
 
 func Seteuid(euid int) (err error) {
-	_, _, e1 := rawSysvicall6(procSeteuid.Addr(), 1, uintptr(euid), 0, 0, 0, 0, 0)
+	_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Seteuid)), 1, uintptr(euid), 0, 0, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
 
 func Setgid(gid int) (err error) {
-	_, _, e1 := rawSysvicall6(procSetgid.Addr(), 1, uintptr(gid), 0, 0, 0, 0, 0)
+	_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Setgid)), 1, uintptr(gid), 0, 0, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
 
 func Setpgid(pid int, pgid int) (err error) {
-	_, _, e1 := rawSysvicall6(procSetpgid.Addr(), 2, uintptr(pid), uintptr(pgid), 0, 0, 0, 0)
+	_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Setpgid)), 2, uintptr(pid), uintptr(pgid), 0, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
 
 func Setpriority(which int, who int, prio int) (err error) {
-	_, _, e1 := sysvicall6(procSetpriority.Addr(), 3, uintptr(which), uintptr(who), uintptr(prio), 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Setpriority)), 3, uintptr(which), uintptr(who), uintptr(prio), 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
 
 func Setregid(rgid int, egid int) (err error) {
-	_, _, e1 := rawSysvicall6(procSetregid.Addr(), 2, uintptr(rgid), uintptr(egid), 0, 0, 0, 0)
+	_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Setregid)), 2, uintptr(rgid), uintptr(egid), 0, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
 
 func Setreuid(ruid int, euid int) (err error) {
-	_, _, e1 := rawSysvicall6(procSetreuid.Addr(), 2, uintptr(ruid), uintptr(euid), 0, 0, 0, 0)
+	_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Setreuid)), 2, uintptr(ruid), uintptr(euid), 0, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
 
 func Setrlimit(which int, lim *Rlimit) (err error) {
-	_, _, e1 := rawSysvicall6(procSetrlimit.Addr(), 2, uintptr(which), uintptr(unsafe.Pointer(lim)), 0, 0, 0, 0)
+	_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Setrlimit)), 2, uintptr(which), uintptr(unsafe.Pointer(lim)), 0, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
 
 func Setsid() (pid int, err error) {
-	r0, _, e1 := rawSysvicall6(procSetsid.Addr(), 0, 0, 0, 0, 0, 0, 0)
+	r0, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Setsid)), 0, 0, 0, 0, 0, 0, 0)
 	pid = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
 
 func Setuid(uid int) (err error) {
-	_, _, e1 := rawSysvicall6(procSetuid.Addr(), 1, uintptr(uid), 0, 0, 0, 0, 0)
+	_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_Setuid)), 1, uintptr(uid), 0, 0, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
 
 func Shutdown(s int, how int) (err error) {
-	_, _, e1 := sysvicall6(procshutdown.Addr(), 2, uintptr(s), uintptr(how), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_shutdown)), 2, uintptr(s), uintptr(how), 0, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -676,10 +851,10 @@ func Stat(path string, stat *Stat_t) (err error) {
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(procStat.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(stat)), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Stat)), 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
 }
@@ -695,19 +870,19 @@ func Symlink(path string, link string) (err error) {
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(procSymlink.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Symlink)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	use(unsafe.Pointer(_p1))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
 
 func Sync() (err error) {
-	_, _, e1 := sysvicall6(procSync.Addr(), 0, 0, 0, 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Sync)), 0, 0, 0, 0, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -718,32 +893,32 @@ func Truncate(path string, length int64) (err error) {
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(procTruncate.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Truncate)), 2, uintptr(unsafe.Pointer(_p0)), uintptr(length), 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
 
 func Fsync(fd int) (err error) {
-	_, _, e1 := sysvicall6(procFsync.Addr(), 1, uintptr(fd), 0, 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Fsync)), 1, uintptr(fd), 0, 0, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
 
 func Ftruncate(fd int, length int64) (err error) {
-	_, _, e1 := sysvicall6(procFtruncate.Addr(), 2, uintptr(fd), uintptr(length), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Ftruncate)), 2, uintptr(fd), uintptr(length), 0, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
 
 func Umask(newmask int) (oldmask int) {
-	r0, _, _ := sysvicall6(procUmask.Addr(), 1, uintptr(newmask), 0, 0, 0, 0, 0)
+	r0, _, _ := sysvicall6(uintptr(unsafe.Pointer(&libc_Umask)), 1, uintptr(newmask), 0, 0, 0, 0, 0)
 	oldmask = int(r0)
 	return
 }
@@ -754,10 +929,10 @@ func Unlink(path string) (err error) {
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(procUnlink.Addr(), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Unlink)), 1, uintptr(unsafe.Pointer(_p0)), 0, 0, 0, 0, 0)
 	use(unsafe.Pointer(_p0))
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -768,43 +943,43 @@ func Utimes(path string, times *[2]Timeval) (err error) {
 	if err != nil {
 		return
 	}
-	_, _, e1 := sysvicall6(procUtimes.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(times)), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Utimes)), 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
 }
 
 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)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_bind)), 3, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
 
 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)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_connect)), 3, uintptr(s), uintptr(addr), uintptr(addrlen), 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
 
 func mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) {
-	r0, _, e1 := sysvicall6(procmmap.Addr(), 6, uintptr(addr), uintptr(length), uintptr(prot), uintptr(flag), uintptr(fd), uintptr(pos))
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_mmap)), 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
 }
 
 func munmap(addr uintptr, length uintptr) (err error) {
-	_, _, e1 := sysvicall6(procmunmap.Addr(), 2, uintptr(addr), uintptr(length), 0, 0, 0, 0)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_munmap)), 2, uintptr(addr), uintptr(length), 0, 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -814,26 +989,26 @@ func sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (
 	if len(buf) > 0 {
 		_p0 = &buf[0]
 	}
-	_, _, e1 := sysvicall6(procsendto.Addr(), 6, uintptr(s), uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), uintptr(flags), uintptr(to), uintptr(addrlen))
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_sendto)), 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
 }
 
 func socket(domain int, typ int, proto int) (fd int, err error) {
-	r0, _, e1 := sysvicall6(procsocket.Addr(), 3, uintptr(domain), uintptr(typ), uintptr(proto), 0, 0, 0)
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_socket)), 3, uintptr(domain), uintptr(typ), uintptr(proto), 0, 0, 0)
 	fd = int(r0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
 
 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)
+	_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_socketpair)), 4, uintptr(domain), uintptr(typ), uintptr(proto), uintptr(unsafe.Pointer(fd)), 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -843,42 +1018,42 @@ func write(fd int, p []byte) (n int, err error) {
 	if len(p) > 0 {
 		_p0 = &p[0]
 	}
-	r0, _, e1 := sysvicall6(procwrite.Addr(), 3, uintptr(fd), uintptr(unsafe.Pointer(_p0)), uintptr(len(p)), 0, 0, 0)
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_write)), 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
 }
 
 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)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_getsockopt)), 5, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(unsafe.Pointer(vallen)), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
 
 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)
+	_, _, e1 := rawSysvicall6(uintptr(unsafe.Pointer(&libc_getpeername)), 3, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
 
 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)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_getsockname)), 3, uintptr(fd), uintptr(unsafe.Pointer(rsa)), uintptr(unsafe.Pointer(addrlen)), 0, 0, 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
 
 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)
+	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_setsockopt)), 5, uintptr(s), uintptr(level), uintptr(name), uintptr(val), uintptr(vallen), 0)
 	if e1 != 0 {
-		err = e1
+		err = errnoErr(e1)
 	}
 	return
 }
@@ -888,19 +1063,19 @@ func recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Sockl
 	if len(p) > 0 {
 		_p0 = &p[0]
 	}
-	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)))
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_recvfrom)), 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
 }
 
 func recvmsg(s int, msg *Msghdr, flags int) (n int, err error) {
-	r0, _, e1 := sysvicall6(procrecvmsg.Addr(), 3, uintptr(s), uintptr(unsafe.Pointer(msg)), uintptr(flags), 0, 0, 0)
+	r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_recvmsg)), 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/zsyscall_windows.go b/src/syscall/zsyscall_windows.go
index afc28f9..7879ba1 100644
--- a/src/syscall/zsyscall_windows.go
+++ b/src/syscall/zsyscall_windows.go
@@ -1,10 +1,11 @@
-// go build mksyscall_windows.go && ./mksyscall_windows syscall_windows.go security_windows.go
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
 
 package syscall
 
 import "unsafe"
 
+var _ unsafe.Pointer
+
 var (
 	modkernel32 = NewLazyDLL("kernel32.dll")
 	modadvapi32 = NewLazyDLL("advapi32.dll")
@@ -239,7 +240,7 @@ func GetVersion() (ver uint32, err error) {
 	return
 }
 
-func FormatMessage(flags uint32, msgsrc uint32, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, err error) {
+func formatMessage(flags uint32, msgsrc uintptr, msgid uint32, langid uint32, buf []uint16, args *byte) (n uint32, err error) {
 	var _p0 *uint16
 	if len(buf) > 0 {
 		_p0 = &buf[0]
diff --git a/src/syscall/zsysnum_darwin_386.go b/src/syscall/zsysnum_darwin_386.go
index abdef77..c6f8342 100644
--- a/src/syscall/zsysnum_darwin_386.go
+++ b/src/syscall/zsysnum_darwin_386.go
@@ -1,6 +1,8 @@
 // mksysnum_darwin.pl /usr/include/sys/syscall.h
 // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
 
+// +build 386,darwin
+
 package syscall
 
 const (
diff --git a/src/syscall/zsysnum_darwin_amd64.go b/src/syscall/zsysnum_darwin_amd64.go
index abdef77..7189abe 100644
--- a/src/syscall/zsysnum_darwin_amd64.go
+++ b/src/syscall/zsysnum_darwin_amd64.go
@@ -1,6 +1,8 @@
 // mksysnum_darwin.pl /usr/include/sys/syscall.h
 // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
 
+// +build amd64,darwin
+
 package syscall
 
 const (
diff --git a/src/syscall/zsysnum_darwin_arm.go b/src/syscall/zsysnum_darwin_arm.go
new file mode 100644
index 0000000..1d76861
--- /dev/null
+++ b/src/syscall/zsysnum_darwin_arm.go
@@ -0,0 +1,347 @@
+// mksysnum_darwin.pl /usr/include/sys/syscall.h
+// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+
+// +build arm,darwin
+
+package syscall
+
+const (
+	SYS_SYSCALL                   = 0
+	SYS_EXIT                      = 1
+	SYS_FORK                      = 2
+	SYS_READ                      = 3
+	SYS_WRITE                     = 4
+	SYS_OPEN                      = 5
+	SYS_CLOSE                     = 6
+	SYS_WAIT4                     = 7
+	SYS_LINK                      = 9
+	SYS_UNLINK                    = 10
+	SYS_CHDIR                     = 12
+	SYS_FCHDIR                    = 13
+	SYS_MKNOD                     = 14
+	SYS_CHMOD                     = 15
+	SYS_CHOWN                     = 16
+	SYS_OBREAK                    = 17
+	SYS_OGETFSSTAT                = 18
+	SYS_GETFSSTAT                 = 18
+	SYS_GETPID                    = 20
+	SYS_SETUID                    = 23
+	SYS_GETUID                    = 24
+	SYS_GETEUID                   = 25
+	SYS_PTRACE                    = 26
+	SYS_RECVMSG                   = 27
+	SYS_SENDMSG                   = 28
+	SYS_RECVFROM                  = 29
+	SYS_ACCEPT                    = 30
+	SYS_GETPEERNAME               = 31
+	SYS_GETSOCKNAME               = 32
+	SYS_ACCESS                    = 33
+	SYS_CHFLAGS                   = 34
+	SYS_FCHFLAGS                  = 35
+	SYS_SYNC                      = 36
+	SYS_KILL                      = 37
+	SYS_GETPPID                   = 39
+	SYS_DUP                       = 41
+	SYS_PIPE                      = 42
+	SYS_GETEGID                   = 43
+	SYS_PROFIL                    = 44
+	SYS_SIGACTION                 = 46
+	SYS_GETGID                    = 47
+	SYS_SIGPROCMASK               = 48
+	SYS_GETLOGIN                  = 49
+	SYS_SETLOGIN                  = 50
+	SYS_ACCT                      = 51
+	SYS_SIGPENDING                = 52
+	SYS_SIGALTSTACK               = 53
+	SYS_IOCTL                     = 54
+	SYS_REBOOT                    = 55
+	SYS_REVOKE                    = 56
+	SYS_SYMLINK                   = 57
+	SYS_READLINK                  = 58
+	SYS_EXECVE                    = 59
+	SYS_UMASK                     = 60
+	SYS_CHROOT                    = 61
+	SYS_MSYNC                     = 65
+	SYS_VFORK                     = 66
+	SYS_SBRK                      = 69
+	SYS_SSTK                      = 70
+	SYS_OVADVISE                  = 72
+	SYS_MUNMAP                    = 73
+	SYS_MPROTECT                  = 74
+	SYS_MADVISE                   = 75
+	SYS_MINCORE                   = 78
+	SYS_GETGROUPS                 = 79
+	SYS_SETGROUPS                 = 80
+	SYS_GETPGRP                   = 81
+	SYS_SETPGID                   = 82
+	SYS_SETITIMER                 = 83
+	SYS_SWAPON                    = 85
+	SYS_GETITIMER                 = 86
+	SYS_GETDTABLESIZE             = 89
+	SYS_DUP2                      = 90
+	SYS_FCNTL                     = 92
+	SYS_SELECT                    = 93
+	SYS_FSYNC                     = 95
+	SYS_SETPRIORITY               = 96
+	SYS_SOCKET                    = 97
+	SYS_CONNECT                   = 98
+	SYS_GETPRIORITY               = 100
+	SYS_BIND                      = 104
+	SYS_SETSOCKOPT                = 105
+	SYS_LISTEN                    = 106
+	SYS_SIGSUSPEND                = 111
+	SYS_GETTIMEOFDAY              = 116
+	SYS_GETRUSAGE                 = 117
+	SYS_GETSOCKOPT                = 118
+	SYS_READV                     = 120
+	SYS_WRITEV                    = 121
+	SYS_SETTIMEOFDAY              = 122
+	SYS_FCHOWN                    = 123
+	SYS_FCHMOD                    = 124
+	SYS_SETREUID                  = 126
+	SYS_SETREGID                  = 127
+	SYS_RENAME                    = 128
+	SYS_FLOCK                     = 131
+	SYS_MKFIFO                    = 132
+	SYS_SENDTO                    = 133
+	SYS_SHUTDOWN                  = 134
+	SYS_SOCKETPAIR                = 135
+	SYS_MKDIR                     = 136
+	SYS_RMDIR                     = 137
+	SYS_UTIMES                    = 138
+	SYS_FUTIMES                   = 139
+	SYS_ADJTIME                   = 140
+	SYS_GETHOSTUUID               = 142
+	SYS_SETSID                    = 147
+	SYS_GETPGID                   = 151
+	SYS_SETPRIVEXEC               = 152
+	SYS_PREAD                     = 153
+	SYS_PWRITE                    = 154
+	SYS_NFSSVC                    = 155
+	SYS_STATFS                    = 157
+	SYS_FSTATFS                   = 158
+	SYS_UNMOUNT                   = 159
+	SYS_GETFH                     = 161
+	SYS_QUOTACTL                  = 165
+	SYS_MOUNT                     = 167
+	SYS_CSOPS                     = 169
+	SYS_TABLE                     = 170
+	SYS_WAITID                    = 173
+	SYS_ADD_PROFIL                = 176
+	SYS_KDEBUG_TRACE              = 180
+	SYS_SETGID                    = 181
+	SYS_SETEGID                   = 182
+	SYS_SETEUID                   = 183
+	SYS_SIGRETURN                 = 184
+	SYS_CHUD                      = 185
+	SYS_STAT                      = 188
+	SYS_FSTAT                     = 189
+	SYS_LSTAT                     = 190
+	SYS_PATHCONF                  = 191
+	SYS_FPATHCONF                 = 192
+	SYS_GETRLIMIT                 = 194
+	SYS_SETRLIMIT                 = 195
+	SYS_GETDIRENTRIES             = 196
+	SYS_MMAP                      = 197
+	SYS_LSEEK                     = 199
+	SYS_TRUNCATE                  = 200
+	SYS_FTRUNCATE                 = 201
+	SYS___SYSCTL                  = 202
+	SYS_MLOCK                     = 203
+	SYS_MUNLOCK                   = 204
+	SYS_UNDELETE                  = 205
+	SYS_ATSOCKET                  = 206
+	SYS_ATGETMSG                  = 207
+	SYS_ATPUTMSG                  = 208
+	SYS_ATPSNDREQ                 = 209
+	SYS_ATPSNDRSP                 = 210
+	SYS_ATPGETREQ                 = 211
+	SYS_ATPGETRSP                 = 212
+	SYS_KQUEUE_FROM_PORTSET_NP    = 214
+	SYS_KQUEUE_PORTSET_NP         = 215
+	SYS_MKCOMPLEX                 = 216
+	SYS_STATV                     = 217
+	SYS_LSTATV                    = 218
+	SYS_FSTATV                    = 219
+	SYS_GETATTRLIST               = 220
+	SYS_SETATTRLIST               = 221
+	SYS_GETDIRENTRIESATTR         = 222
+	SYS_EXCHANGEDATA              = 223
+	SYS_SEARCHFS                  = 225
+	SYS_DELETE                    = 226
+	SYS_COPYFILE                  = 227
+	SYS_POLL                      = 230
+	SYS_WATCHEVENT                = 231
+	SYS_WAITEVENT                 = 232
+	SYS_MODWATCH                  = 233
+	SYS_GETXATTR                  = 234
+	SYS_FGETXATTR                 = 235
+	SYS_SETXATTR                  = 236
+	SYS_FSETXATTR                 = 237
+	SYS_REMOVEXATTR               = 238
+	SYS_FREMOVEXATTR              = 239
+	SYS_LISTXATTR                 = 240
+	SYS_FLISTXATTR                = 241
+	SYS_FSCTL                     = 242
+	SYS_INITGROUPS                = 243
+	SYS_POSIX_SPAWN               = 244
+	SYS_NFSCLNT                   = 247
+	SYS_FHOPEN                    = 248
+	SYS_MINHERIT                  = 250
+	SYS_SEMSYS                    = 251
+	SYS_MSGSYS                    = 252
+	SYS_SHMSYS                    = 253
+	SYS_SEMCTL                    = 254
+	SYS_SEMGET                    = 255
+	SYS_SEMOP                     = 256
+	SYS_MSGCTL                    = 258
+	SYS_MSGGET                    = 259
+	SYS_MSGSND                    = 260
+	SYS_MSGRCV                    = 261
+	SYS_SHMAT                     = 262
+	SYS_SHMCTL                    = 263
+	SYS_SHMDT                     = 264
+	SYS_SHMGET                    = 265
+	SYS_SHM_OPEN                  = 266
+	SYS_SHM_UNLINK                = 267
+	SYS_SEM_OPEN                  = 268
+	SYS_SEM_CLOSE                 = 269
+	SYS_SEM_UNLINK                = 270
+	SYS_SEM_WAIT                  = 271
+	SYS_SEM_TRYWAIT               = 272
+	SYS_SEM_POST                  = 273
+	SYS_SEM_GETVALUE              = 274
+	SYS_SEM_INIT                  = 275
+	SYS_SEM_DESTROY               = 276
+	SYS_OPEN_EXTENDED             = 277
+	SYS_UMASK_EXTENDED            = 278
+	SYS_STAT_EXTENDED             = 279
+	SYS_LSTAT_EXTENDED            = 280
+	SYS_FSTAT_EXTENDED            = 281
+	SYS_CHMOD_EXTENDED            = 282
+	SYS_FCHMOD_EXTENDED           = 283
+	SYS_ACCESS_EXTENDED           = 284
+	SYS_SETTID                    = 285
+	SYS_GETTID                    = 286
+	SYS_SETSGROUPS                = 287
+	SYS_GETSGROUPS                = 288
+	SYS_SETWGROUPS                = 289
+	SYS_GETWGROUPS                = 290
+	SYS_MKFIFO_EXTENDED           = 291
+	SYS_MKDIR_EXTENDED            = 292
+	SYS_IDENTITYSVC               = 293
+	SYS_SHARED_REGION_CHECK_NP    = 294
+	SYS_SHARED_REGION_MAP_NP      = 295
+	SYS___PTHREAD_MUTEX_DESTROY   = 301
+	SYS___PTHREAD_MUTEX_INIT      = 302
+	SYS___PTHREAD_MUTEX_LOCK      = 303
+	SYS___PTHREAD_MUTEX_TRYLOCK   = 304
+	SYS___PTHREAD_MUTEX_UNLOCK    = 305
+	SYS___PTHREAD_COND_INIT       = 306
+	SYS___PTHREAD_COND_DESTROY    = 307
+	SYS___PTHREAD_COND_BROADCAST  = 308
+	SYS___PTHREAD_COND_SIGNAL     = 309
+	SYS_GETSID                    = 310
+	SYS_SETTID_WITH_PID           = 311
+	SYS___PTHREAD_COND_TIMEDWAIT  = 312
+	SYS_AIO_FSYNC                 = 313
+	SYS_AIO_RETURN                = 314
+	SYS_AIO_SUSPEND               = 315
+	SYS_AIO_CANCEL                = 316
+	SYS_AIO_ERROR                 = 317
+	SYS_AIO_READ                  = 318
+	SYS_AIO_WRITE                 = 319
+	SYS_LIO_LISTIO                = 320
+	SYS___PTHREAD_COND_WAIT       = 321
+	SYS_IOPOLICYSYS               = 322
+	SYS_MLOCKALL                  = 324
+	SYS_MUNLOCKALL                = 325
+	SYS_ISSETUGID                 = 327
+	SYS___PTHREAD_KILL            = 328
+	SYS___PTHREAD_SIGMASK         = 329
+	SYS___SIGWAIT                 = 330
+	SYS___DISABLE_THREADSIGNAL    = 331
+	SYS___PTHREAD_MARKCANCEL      = 332
+	SYS___PTHREAD_CANCELED        = 333
+	SYS___SEMWAIT_SIGNAL          = 334
+	SYS_PROC_INFO                 = 336
+	SYS_SENDFILE                  = 337
+	SYS_STAT64                    = 338
+	SYS_FSTAT64                   = 339
+	SYS_LSTAT64                   = 340
+	SYS_STAT64_EXTENDED           = 341
+	SYS_LSTAT64_EXTENDED          = 342
+	SYS_FSTAT64_EXTENDED          = 343
+	SYS_GETDIRENTRIES64           = 344
+	SYS_STATFS64                  = 345
+	SYS_FSTATFS64                 = 346
+	SYS_GETFSSTAT64               = 347
+	SYS___PTHREAD_CHDIR           = 348
+	SYS___PTHREAD_FCHDIR          = 349
+	SYS_AUDIT                     = 350
+	SYS_AUDITON                   = 351
+	SYS_GETAUID                   = 353
+	SYS_SETAUID                   = 354
+	SYS_GETAUDIT                  = 355
+	SYS_SETAUDIT                  = 356
+	SYS_GETAUDIT_ADDR             = 357
+	SYS_SETAUDIT_ADDR             = 358
+	SYS_AUDITCTL                  = 359
+	SYS_BSDTHREAD_CREATE          = 360
+	SYS_BSDTHREAD_TERMINATE       = 361
+	SYS_KQUEUE                    = 362
+	SYS_KEVENT                    = 363
+	SYS_LCHOWN                    = 364
+	SYS_STACK_SNAPSHOT            = 365
+	SYS_BSDTHREAD_REGISTER        = 366
+	SYS_WORKQ_OPEN                = 367
+	SYS_WORKQ_OPS                 = 368
+	SYS___MAC_EXECVE              = 380
+	SYS___MAC_SYSCALL             = 381
+	SYS___MAC_GET_FILE            = 382
+	SYS___MAC_SET_FILE            = 383
+	SYS___MAC_GET_LINK            = 384
+	SYS___MAC_SET_LINK            = 385
+	SYS___MAC_GET_PROC            = 386
+	SYS___MAC_SET_PROC            = 387
+	SYS___MAC_GET_FD              = 388
+	SYS___MAC_SET_FD              = 389
+	SYS___MAC_GET_PID             = 390
+	SYS___MAC_GET_LCID            = 391
+	SYS___MAC_GET_LCTX            = 392
+	SYS___MAC_SET_LCTX            = 393
+	SYS_SETLCID                   = 394
+	SYS_GETLCID                   = 395
+	SYS_READ_NOCANCEL             = 396
+	SYS_WRITE_NOCANCEL            = 397
+	SYS_OPEN_NOCANCEL             = 398
+	SYS_CLOSE_NOCANCEL            = 399
+	SYS_WAIT4_NOCANCEL            = 400
+	SYS_RECVMSG_NOCANCEL          = 401
+	SYS_SENDMSG_NOCANCEL          = 402
+	SYS_RECVFROM_NOCANCEL         = 403
+	SYS_ACCEPT_NOCANCEL           = 404
+	SYS_MSYNC_NOCANCEL            = 405
+	SYS_FCNTL_NOCANCEL            = 406
+	SYS_SELECT_NOCANCEL           = 407
+	SYS_FSYNC_NOCANCEL            = 408
+	SYS_CONNECT_NOCANCEL          = 409
+	SYS_SIGSUSPEND_NOCANCEL       = 410
+	SYS_READV_NOCANCEL            = 411
+	SYS_WRITEV_NOCANCEL           = 412
+	SYS_SENDTO_NOCANCEL           = 413
+	SYS_PREAD_NOCANCEL            = 414
+	SYS_PWRITE_NOCANCEL           = 415
+	SYS_WAITID_NOCANCEL           = 416
+	SYS_POLL_NOCANCEL             = 417
+	SYS_MSGSND_NOCANCEL           = 418
+	SYS_MSGRCV_NOCANCEL           = 419
+	SYS_SEM_WAIT_NOCANCEL         = 420
+	SYS_AIO_SUSPEND_NOCANCEL      = 421
+	SYS___SIGWAIT_NOCANCEL        = 422
+	SYS___SEMWAIT_SIGNAL_NOCANCEL = 423
+	SYS___MAC_MOUNT               = 424
+	SYS___MAC_GET_MOUNT           = 425
+	SYS___MAC_GETFSSTAT           = 426
+	SYS_MAXSYSCALL                = 427
+)
diff --git a/src/syscall/zsysnum_darwin_arm64.go b/src/syscall/zsysnum_darwin_arm64.go
new file mode 100644
index 0000000..ddf8e83
--- /dev/null
+++ b/src/syscall/zsysnum_darwin_arm64.go
@@ -0,0 +1,358 @@
+// mksysnum_darwin.pl /usr/include/sys/syscall.h
+// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+
+// +build arm64,darwin
+
+package syscall
+
+const (
+	SYS_SYSCALL                        = 0
+	SYS_EXIT                           = 1
+	SYS_FORK                           = 2
+	SYS_READ                           = 3
+	SYS_WRITE                          = 4
+	SYS_OPEN                           = 5
+	SYS_CLOSE                          = 6
+	SYS_WAIT4                          = 7
+	SYS_LINK                           = 9
+	SYS_UNLINK                         = 10
+	SYS_CHDIR                          = 12
+	SYS_FCHDIR                         = 13
+	SYS_MKNOD                          = 14
+	SYS_CHMOD                          = 15
+	SYS_CHOWN                          = 16
+	SYS_GETFSSTAT                      = 18
+	SYS_GETPID                         = 20
+	SYS_SETUID                         = 23
+	SYS_GETUID                         = 24
+	SYS_GETEUID                        = 25
+	SYS_PTRACE                         = 26
+	SYS_RECVMSG                        = 27
+	SYS_SENDMSG                        = 28
+	SYS_RECVFROM                       = 29
+	SYS_ACCEPT                         = 30
+	SYS_GETPEERNAME                    = 31
+	SYS_GETSOCKNAME                    = 32
+	SYS_ACCESS                         = 33
+	SYS_CHFLAGS                        = 34
+	SYS_FCHFLAGS                       = 35
+	SYS_SYNC                           = 36
+	SYS_KILL                           = 37
+	SYS_GETPPID                        = 39
+	SYS_DUP                            = 41
+	SYS_PIPE                           = 42
+	SYS_GETEGID                        = 43
+	SYS_SIGACTION                      = 46
+	SYS_GETGID                         = 47
+	SYS_SIGPROCMASK                    = 48
+	SYS_GETLOGIN                       = 49
+	SYS_SETLOGIN                       = 50
+	SYS_ACCT                           = 51
+	SYS_SIGPENDING                     = 52
+	SYS_SIGALTSTACK                    = 53
+	SYS_IOCTL                          = 54
+	SYS_REBOOT                         = 55
+	SYS_REVOKE                         = 56
+	SYS_SYMLINK                        = 57
+	SYS_READLINK                       = 58
+	SYS_EXECVE                         = 59
+	SYS_UMASK                          = 60
+	SYS_CHROOT                         = 61
+	SYS_MSYNC                          = 65
+	SYS_VFORK                          = 66
+	SYS_MUNMAP                         = 73
+	SYS_MPROTECT                       = 74
+	SYS_MADVISE                        = 75
+	SYS_MINCORE                        = 78
+	SYS_GETGROUPS                      = 79
+	SYS_SETGROUPS                      = 80
+	SYS_GETPGRP                        = 81
+	SYS_SETPGID                        = 82
+	SYS_SETITIMER                      = 83
+	SYS_SWAPON                         = 85
+	SYS_GETITIMER                      = 86
+	SYS_GETDTABLESIZE                  = 89
+	SYS_DUP2                           = 90
+	SYS_FCNTL                          = 92
+	SYS_SELECT                         = 93
+	SYS_FSYNC                          = 95
+	SYS_SETPRIORITY                    = 96
+	SYS_SOCKET                         = 97
+	SYS_CONNECT                        = 98
+	SYS_GETPRIORITY                    = 100
+	SYS_BIND                           = 104
+	SYS_SETSOCKOPT                     = 105
+	SYS_LISTEN                         = 106
+	SYS_SIGSUSPEND                     = 111
+	SYS_GETTIMEOFDAY                   = 116
+	SYS_GETRUSAGE                      = 117
+	SYS_GETSOCKOPT                     = 118
+	SYS_READV                          = 120
+	SYS_WRITEV                         = 121
+	SYS_SETTIMEOFDAY                   = 122
+	SYS_FCHOWN                         = 123
+	SYS_FCHMOD                         = 124
+	SYS_SETREUID                       = 126
+	SYS_SETREGID                       = 127
+	SYS_RENAME                         = 128
+	SYS_FLOCK                          = 131
+	SYS_MKFIFO                         = 132
+	SYS_SENDTO                         = 133
+	SYS_SHUTDOWN                       = 134
+	SYS_SOCKETPAIR                     = 135
+	SYS_MKDIR                          = 136
+	SYS_RMDIR                          = 137
+	SYS_UTIMES                         = 138
+	SYS_FUTIMES                        = 139
+	SYS_ADJTIME                        = 140
+	SYS_GETHOSTUUID                    = 142
+	SYS_SETSID                         = 147
+	SYS_GETPGID                        = 151
+	SYS_SETPRIVEXEC                    = 152
+	SYS_PREAD                          = 153
+	SYS_PWRITE                         = 154
+	SYS_NFSSVC                         = 155
+	SYS_STATFS                         = 157
+	SYS_FSTATFS                        = 158
+	SYS_UNMOUNT                        = 159
+	SYS_GETFH                          = 161
+	SYS_QUOTACTL                       = 165
+	SYS_MOUNT                          = 167
+	SYS_CSOPS                          = 169
+	SYS_CSOPS_AUDITTOKEN               = 170
+	SYS_WAITID                         = 173
+	SYS_KDEBUG_TRACE                   = 180
+	SYS_SETGID                         = 181
+	SYS_SETEGID                        = 182
+	SYS_SETEUID                        = 183
+	SYS_SIGRETURN                      = 184
+	SYS_CHUD                           = 185
+	SYS_FDATASYNC                      = 187
+	SYS_STAT                           = 188
+	SYS_FSTAT                          = 189
+	SYS_LSTAT                          = 190
+	SYS_PATHCONF                       = 191
+	SYS_FPATHCONF                      = 192
+	SYS_GETRLIMIT                      = 194
+	SYS_SETRLIMIT                      = 195
+	SYS_GETDIRENTRIES                  = 196
+	SYS_MMAP                           = 197
+	SYS_LSEEK                          = 199
+	SYS_TRUNCATE                       = 200
+	SYS_FTRUNCATE                      = 201
+	SYS___SYSCTL                       = 202
+	SYS_MLOCK                          = 203
+	SYS_MUNLOCK                        = 204
+	SYS_UNDELETE                       = 205
+	SYS_ATSOCKET                       = 206
+	SYS_ATGETMSG                       = 207
+	SYS_ATPUTMSG                       = 208
+	SYS_ATPSNDREQ                      = 209
+	SYS_ATPSNDRSP                      = 210
+	SYS_ATPGETREQ                      = 211
+	SYS_ATPGETRSP                      = 212
+	SYS_OPEN_DPROTECTED_NP             = 216
+	SYS_GETATTRLIST                    = 220
+	SYS_SETATTRLIST                    = 221
+	SYS_GETDIRENTRIESATTR              = 222
+	SYS_EXCHANGEDATA                   = 223
+	SYS_SEARCHFS                       = 225
+	SYS_DELETE                         = 226
+	SYS_COPYFILE                       = 227
+	SYS_FGETATTRLIST                   = 228
+	SYS_FSETATTRLIST                   = 229
+	SYS_POLL                           = 230
+	SYS_WATCHEVENT                     = 231
+	SYS_WAITEVENT                      = 232
+	SYS_MODWATCH                       = 233
+	SYS_GETXATTR                       = 234
+	SYS_FGETXATTR                      = 235
+	SYS_SETXATTR                       = 236
+	SYS_FSETXATTR                      = 237
+	SYS_REMOVEXATTR                    = 238
+	SYS_FREMOVEXATTR                   = 239
+	SYS_LISTXATTR                      = 240
+	SYS_FLISTXATTR                     = 241
+	SYS_FSCTL                          = 242
+	SYS_INITGROUPS                     = 243
+	SYS_POSIX_SPAWN                    = 244
+	SYS_FFSCTL                         = 245
+	SYS_NFSCLNT                        = 247
+	SYS_FHOPEN                         = 248
+	SYS_MINHERIT                       = 250
+	SYS_SEMSYS                         = 251
+	SYS_MSGSYS                         = 252
+	SYS_SHMSYS                         = 253
+	SYS_SEMCTL                         = 254
+	SYS_SEMGET                         = 255
+	SYS_SEMOP                          = 256
+	SYS_MSGCTL                         = 258
+	SYS_MSGGET                         = 259
+	SYS_MSGSND                         = 260
+	SYS_MSGRCV                         = 261
+	SYS_SHMAT                          = 262
+	SYS_SHMCTL                         = 263
+	SYS_SHMDT                          = 264
+	SYS_SHMGET                         = 265
+	SYS_SHM_OPEN                       = 266
+	SYS_SHM_UNLINK                     = 267
+	SYS_SEM_OPEN                       = 268
+	SYS_SEM_CLOSE                      = 269
+	SYS_SEM_UNLINK                     = 270
+	SYS_SEM_WAIT                       = 271
+	SYS_SEM_TRYWAIT                    = 272
+	SYS_SEM_POST                       = 273
+	SYS_SEM_GETVALUE                   = 274
+	SYS_SEM_INIT                       = 275
+	SYS_SEM_DESTROY                    = 276
+	SYS_OPEN_EXTENDED                  = 277
+	SYS_UMASK_EXTENDED                 = 278
+	SYS_STAT_EXTENDED                  = 279
+	SYS_LSTAT_EXTENDED                 = 280
+	SYS_FSTAT_EXTENDED                 = 281
+	SYS_CHMOD_EXTENDED                 = 282
+	SYS_FCHMOD_EXTENDED                = 283
+	SYS_ACCESS_EXTENDED                = 284
+	SYS_SETTID                         = 285
+	SYS_GETTID                         = 286
+	SYS_SETSGROUPS                     = 287
+	SYS_GETSGROUPS                     = 288
+	SYS_SETWGROUPS                     = 289
+	SYS_GETWGROUPS                     = 290
+	SYS_MKFIFO_EXTENDED                = 291
+	SYS_MKDIR_EXTENDED                 = 292
+	SYS_IDENTITYSVC                    = 293
+	SYS_SHARED_REGION_CHECK_NP         = 294
+	SYS_VM_PRESSURE_MONITOR            = 296
+	SYS_PSYNCH_RW_LONGRDLOCK           = 297
+	SYS_PSYNCH_RW_YIELDWRLOCK          = 298
+	SYS_PSYNCH_RW_DOWNGRADE            = 299
+	SYS_PSYNCH_RW_UPGRADE              = 300
+	SYS_PSYNCH_MUTEXWAIT               = 301
+	SYS_PSYNCH_MUTEXDROP               = 302
+	SYS_PSYNCH_CVBROAD                 = 303
+	SYS_PSYNCH_CVSIGNAL                = 304
+	SYS_PSYNCH_CVWAIT                  = 305
+	SYS_PSYNCH_RW_RDLOCK               = 306
+	SYS_PSYNCH_RW_WRLOCK               = 307
+	SYS_PSYNCH_RW_UNLOCK               = 308
+	SYS_PSYNCH_RW_UNLOCK2              = 309
+	SYS_GETSID                         = 310
+	SYS_SETTID_WITH_PID                = 311
+	SYS_PSYNCH_CVCLRPREPOST            = 312
+	SYS_AIO_FSYNC                      = 313
+	SYS_AIO_RETURN                     = 314
+	SYS_AIO_SUSPEND                    = 315
+	SYS_AIO_CANCEL                     = 316
+	SYS_AIO_ERROR                      = 317
+	SYS_AIO_READ                       = 318
+	SYS_AIO_WRITE                      = 319
+	SYS_LIO_LISTIO                     = 320
+	SYS_IOPOLICYSYS                    = 322
+	SYS_PROCESS_POLICY                 = 323
+	SYS_MLOCKALL                       = 324
+	SYS_MUNLOCKALL                     = 325
+	SYS_ISSETUGID                      = 327
+	SYS___PTHREAD_KILL                 = 328
+	SYS___PTHREAD_SIGMASK              = 329
+	SYS___SIGWAIT                      = 330
+	SYS___DISABLE_THREADSIGNAL         = 331
+	SYS___PTHREAD_MARKCANCEL           = 332
+	SYS___PTHREAD_CANCELED             = 333
+	SYS___SEMWAIT_SIGNAL               = 334
+	SYS_PROC_INFO                      = 336
+	SYS_SENDFILE                       = 337
+	SYS_STAT64                         = 338
+	SYS_FSTAT64                        = 339
+	SYS_LSTAT64                        = 340
+	SYS_STAT64_EXTENDED                = 341
+	SYS_LSTAT64_EXTENDED               = 342
+	SYS_FSTAT64_EXTENDED               = 343
+	SYS_GETDIRENTRIES64                = 344
+	SYS_STATFS64                       = 345
+	SYS_FSTATFS64                      = 346
+	SYS_GETFSSTAT64                    = 347
+	SYS___PTHREAD_CHDIR                = 348
+	SYS___PTHREAD_FCHDIR               = 349
+	SYS_AUDIT                          = 350
+	SYS_AUDITON                        = 351
+	SYS_GETAUID                        = 353
+	SYS_SETAUID                        = 354
+	SYS_GETAUDIT_ADDR                  = 357
+	SYS_SETAUDIT_ADDR                  = 358
+	SYS_AUDITCTL                       = 359
+	SYS_BSDTHREAD_CREATE               = 360
+	SYS_BSDTHREAD_TERMINATE            = 361
+	SYS_KQUEUE                         = 362
+	SYS_KEVENT                         = 363
+	SYS_LCHOWN                         = 364
+	SYS_STACK_SNAPSHOT                 = 365
+	SYS_BSDTHREAD_REGISTER             = 366
+	SYS_WORKQ_OPEN                     = 367
+	SYS_WORKQ_KERNRETURN               = 368
+	SYS_KEVENT64                       = 369
+	SYS___OLD_SEMWAIT_SIGNAL           = 370
+	SYS___OLD_SEMWAIT_SIGNAL_NOCANCEL  = 371
+	SYS_THREAD_SELFID                  = 372
+	SYS_LEDGER                         = 373
+	SYS___MAC_EXECVE                   = 380
+	SYS___MAC_SYSCALL                  = 381
+	SYS___MAC_GET_FILE                 = 382
+	SYS___MAC_SET_FILE                 = 383
+	SYS___MAC_GET_LINK                 = 384
+	SYS___MAC_SET_LINK                 = 385
+	SYS___MAC_GET_PROC                 = 386
+	SYS___MAC_SET_PROC                 = 387
+	SYS___MAC_GET_FD                   = 388
+	SYS___MAC_SET_FD                   = 389
+	SYS___MAC_GET_PID                  = 390
+	SYS___MAC_GET_LCID                 = 391
+	SYS___MAC_GET_LCTX                 = 392
+	SYS___MAC_SET_LCTX                 = 393
+	SYS_SETLCID                        = 394
+	SYS_GETLCID                        = 395
+	SYS_READ_NOCANCEL                  = 396
+	SYS_WRITE_NOCANCEL                 = 397
+	SYS_OPEN_NOCANCEL                  = 398
+	SYS_CLOSE_NOCANCEL                 = 399
+	SYS_WAIT4_NOCANCEL                 = 400
+	SYS_RECVMSG_NOCANCEL               = 401
+	SYS_SENDMSG_NOCANCEL               = 402
+	SYS_RECVFROM_NOCANCEL              = 403
+	SYS_ACCEPT_NOCANCEL                = 404
+	SYS_MSYNC_NOCANCEL                 = 405
+	SYS_FCNTL_NOCANCEL                 = 406
+	SYS_SELECT_NOCANCEL                = 407
+	SYS_FSYNC_NOCANCEL                 = 408
+	SYS_CONNECT_NOCANCEL               = 409
+	SYS_SIGSUSPEND_NOCANCEL            = 410
+	SYS_READV_NOCANCEL                 = 411
+	SYS_WRITEV_NOCANCEL                = 412
+	SYS_SENDTO_NOCANCEL                = 413
+	SYS_PREAD_NOCANCEL                 = 414
+	SYS_PWRITE_NOCANCEL                = 415
+	SYS_WAITID_NOCANCEL                = 416
+	SYS_POLL_NOCANCEL                  = 417
+	SYS_MSGSND_NOCANCEL                = 418
+	SYS_MSGRCV_NOCANCEL                = 419
+	SYS_SEM_WAIT_NOCANCEL              = 420
+	SYS_AIO_SUSPEND_NOCANCEL           = 421
+	SYS___SIGWAIT_NOCANCEL             = 422
+	SYS___SEMWAIT_SIGNAL_NOCANCEL      = 423
+	SYS___MAC_MOUNT                    = 424
+	SYS___MAC_GET_MOUNT                = 425
+	SYS___MAC_GETFSSTAT                = 426
+	SYS_FSGETPATH                      = 427
+	SYS_AUDIT_SESSION_SELF             = 428
+	SYS_AUDIT_SESSION_JOIN             = 429
+	SYS_FILEPORT_MAKEPORT              = 430
+	SYS_FILEPORT_MAKEFD                = 431
+	SYS_AUDIT_SESSION_PORT             = 432
+	SYS_PID_SUSPEND                    = 433
+	SYS_PID_RESUME                     = 434
+	SYS_PID_HIBERNATE                  = 435
+	SYS_PID_SHUTDOWN_SOCKETS           = 436
+	SYS_SHARED_REGION_MAP_AND_SLIDE_NP = 438
+	SYS_KAS_INFO                       = 439
+	SYS_MAXSYSCALL                     = 440
+)
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_dragonfly_amd64.go b/src/syscall/zsysnum_dragonfly_amd64.go
index 4b086b9..277478d 100644
--- a/src/syscall/zsysnum_dragonfly_amd64.go
+++ b/src/syscall/zsysnum_dragonfly_amd64.go
@@ -1,6 +1,8 @@
 // mksysnum_dragonfly.pl
 // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
 
+// +build amd64,dragonfly
+
 package syscall
 
 const (
diff --git a/src/syscall/zsysnum_freebsd_386.go b/src/syscall/zsysnum_freebsd_386.go
index dfca558..5e47217 100644
--- a/src/syscall/zsysnum_freebsd_386.go
+++ b/src/syscall/zsysnum_freebsd_386.go
@@ -1,6 +1,8 @@
 // mksysnum_freebsd.pl
 // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
 
+// +build 386,freebsd
+
 package syscall
 
 const (
diff --git a/src/syscall/zsysnum_freebsd_amd64.go b/src/syscall/zsysnum_freebsd_amd64.go
index dfca558..df8928c 100644
--- a/src/syscall/zsysnum_freebsd_amd64.go
+++ b/src/syscall/zsysnum_freebsd_amd64.go
@@ -1,6 +1,8 @@
 // mksysnum_freebsd.pl
 // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
 
+// +build amd64,freebsd
+
 package syscall
 
 const (
diff --git a/src/syscall/zsysnum_freebsd_arm.go b/src/syscall/zsysnum_freebsd_arm.go
index dfca558..f670a59 100644
--- a/src/syscall/zsysnum_freebsd_arm.go
+++ b/src/syscall/zsysnum_freebsd_arm.go
@@ -1,6 +1,8 @@
 // mksysnum_freebsd.pl
 // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
 
+// +build arm,freebsd
+
 package syscall
 
 const (
diff --git a/src/syscall/zsysnum_linux_386.go b/src/syscall/zsysnum_linux_386.go
index c40b5f1..c277ed9 100644
--- a/src/syscall/zsysnum_linux_386.go
+++ b/src/syscall/zsysnum_linux_386.go
@@ -1,6 +1,8 @@
 // mksysnum_linux.pl /usr/include/asm/unistd_32.h
 // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
 
+// +build 386,linux
+
 package syscall
 
 const (
diff --git a/src/syscall/zsysnum_linux_amd64.go b/src/syscall/zsysnum_linux_amd64.go
index 7cf70a4..978a4d3 100644
--- a/src/syscall/zsysnum_linux_amd64.go
+++ b/src/syscall/zsysnum_linux_amd64.go
@@ -1,6 +1,8 @@
 // mksysnum_linux.pl /usr/include/asm/unistd_64.h
 // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
 
+// +build amd64,linux
+
 package syscall
 
 const (
diff --git a/src/syscall/zsysnum_linux_arm.go b/src/syscall/zsysnum_linux_arm.go
index 7068e4e..5061cba 100644
--- a/src/syscall/zsysnum_linux_arm.go
+++ b/src/syscall/zsysnum_linux_arm.go
@@ -1,6 +1,8 @@
 // mksysnum_linux.pl
 // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
 
+// +build arm,linux
+
 package syscall
 
 const (
diff --git a/src/syscall/zsysnum_linux_arm64.go b/src/syscall/zsysnum_linux_arm64.go
new file mode 100644
index 0000000..d53712c
--- /dev/null
+++ b/src/syscall/zsysnum_linux_arm64.go
@@ -0,0 +1,277 @@
+// mksysnum_linux.pl /usr/include/asm-generic/unistd.h
+// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+
+// +build arm64,linux
+
+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_linux_ppc64.go b/src/syscall/zsysnum_linux_ppc64.go
new file mode 100644
index 0000000..82d253a
--- /dev/null
+++ b/src/syscall/zsysnum_linux_ppc64.go
@@ -0,0 +1,353 @@
+// mksysnum_linux.pl /usr/include/asm/unistd.h
+// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+
+// +build ppc64,linux
+
+package syscall
+
+const (
+	SYS_RESTART_SYSCALL        = 0
+	SYS_EXIT                   = 1
+	SYS_FORK                   = 2
+	SYS_READ                   = 3
+	SYS_WRITE                  = 4
+	SYS_OPEN                   = 5
+	SYS_CLOSE                  = 6
+	SYS_WAITPID                = 7
+	SYS_CREAT                  = 8
+	SYS_LINK                   = 9
+	SYS_UNLINK                 = 10
+	SYS_EXECVE                 = 11
+	SYS_CHDIR                  = 12
+	SYS_TIME                   = 13
+	SYS_MKNOD                  = 14
+	SYS_CHMOD                  = 15
+	SYS_LCHOWN                 = 16
+	SYS_BREAK                  = 17
+	SYS_OLDSTAT                = 18
+	SYS_LSEEK                  = 19
+	SYS_GETPID                 = 20
+	SYS_MOUNT                  = 21
+	SYS_UMOUNT                 = 22
+	SYS_SETUID                 = 23
+	SYS_GETUID                 = 24
+	SYS_STIME                  = 25
+	SYS_PTRACE                 = 26
+	SYS_ALARM                  = 27
+	SYS_OLDFSTAT               = 28
+	SYS_PAUSE                  = 29
+	SYS_UTIME                  = 30
+	SYS_STTY                   = 31
+	SYS_GTTY                   = 32
+	SYS_ACCESS                 = 33
+	SYS_NICE                   = 34
+	SYS_FTIME                  = 35
+	SYS_SYNC                   = 36
+	SYS_KILL                   = 37
+	SYS_RENAME                 = 38
+	SYS_MKDIR                  = 39
+	SYS_RMDIR                  = 40
+	SYS_DUP                    = 41
+	SYS_PIPE                   = 42
+	SYS_TIMES                  = 43
+	SYS_PROF                   = 44
+	SYS_BRK                    = 45
+	SYS_SETGID                 = 46
+	SYS_GETGID                 = 47
+	SYS_SIGNAL                 = 48
+	SYS_GETEUID                = 49
+	SYS_GETEGID                = 50
+	SYS_ACCT                   = 51
+	SYS_UMOUNT2                = 52
+	SYS_LOCK                   = 53
+	SYS_IOCTL                  = 54
+	SYS_FCNTL                  = 55
+	SYS_MPX                    = 56
+	SYS_SETPGID                = 57
+	SYS_ULIMIT                 = 58
+	SYS_OLDOLDUNAME            = 59
+	SYS_UMASK                  = 60
+	SYS_CHROOT                 = 61
+	SYS_USTAT                  = 62
+	SYS_DUP2                   = 63
+	SYS_GETPPID                = 64
+	SYS_GETPGRP                = 65
+	SYS_SETSID                 = 66
+	SYS_SIGACTION              = 67
+	SYS_SGETMASK               = 68
+	SYS_SSETMASK               = 69
+	SYS_SETREUID               = 70
+	SYS_SETREGID               = 71
+	SYS_SIGSUSPEND             = 72
+	SYS_SIGPENDING             = 73
+	SYS_SETHOSTNAME            = 74
+	SYS_SETRLIMIT              = 75
+	SYS_GETRLIMIT              = 76
+	SYS_GETRUSAGE              = 77
+	SYS_GETTIMEOFDAY           = 78
+	SYS_SETTIMEOFDAY           = 79
+	SYS_GETGROUPS              = 80
+	SYS_SETGROUPS              = 81
+	SYS_SELECT                 = 82
+	SYS_SYMLINK                = 83
+	SYS_OLDLSTAT               = 84
+	SYS_READLINK               = 85
+	SYS_USELIB                 = 86
+	SYS_SWAPON                 = 87
+	SYS_REBOOT                 = 88
+	SYS_READDIR                = 89
+	SYS_MMAP                   = 90
+	SYS_MUNMAP                 = 91
+	SYS_TRUNCATE               = 92
+	SYS_FTRUNCATE              = 93
+	SYS_FCHMOD                 = 94
+	SYS_FCHOWN                 = 95
+	SYS_GETPRIORITY            = 96
+	SYS_SETPRIORITY            = 97
+	SYS_PROFIL                 = 98
+	SYS_STATFS                 = 99
+	SYS_FSTATFS                = 100
+	SYS_IOPERM                 = 101
+	SYS_SOCKETCALL             = 102
+	SYS_SYSLOG                 = 103
+	SYS_SETITIMER              = 104
+	SYS_GETITIMER              = 105
+	SYS_STAT                   = 106
+	SYS_LSTAT                  = 107
+	SYS_FSTAT                  = 108
+	SYS_OLDUNAME               = 109
+	SYS_IOPL                   = 110
+	SYS_VHANGUP                = 111
+	SYS_IDLE                   = 112
+	SYS_VM86                   = 113
+	SYS_WAIT4                  = 114
+	SYS_SWAPOFF                = 115
+	SYS_SYSINFO                = 116
+	SYS_IPC                    = 117
+	SYS_FSYNC                  = 118
+	SYS_SIGRETURN              = 119
+	SYS_CLONE                  = 120
+	SYS_SETDOMAINNAME          = 121
+	SYS_UNAME                  = 122
+	SYS_MODIFY_LDT             = 123
+	SYS_ADJTIMEX               = 124
+	SYS_MPROTECT               = 125
+	SYS_SIGPROCMASK            = 126
+	SYS_CREATE_MODULE          = 127
+	SYS_INIT_MODULE            = 128
+	SYS_DELETE_MODULE          = 129
+	SYS_GET_KERNEL_SYMS        = 130
+	SYS_QUOTACTL               = 131
+	SYS_GETPGID                = 132
+	SYS_FCHDIR                 = 133
+	SYS_BDFLUSH                = 134
+	SYS_SYSFS                  = 135
+	SYS_PERSONALITY            = 136
+	SYS_AFS_SYSCALL            = 137
+	SYS_SETFSUID               = 138
+	SYS_SETFSGID               = 139
+	SYS__LLSEEK                = 140
+	SYS_GETDENTS               = 141
+	SYS__NEWSELECT             = 142
+	SYS_FLOCK                  = 143
+	SYS_MSYNC                  = 144
+	SYS_READV                  = 145
+	SYS_WRITEV                 = 146
+	SYS_GETSID                 = 147
+	SYS_FDATASYNC              = 148
+	SYS__SYSCTL                = 149
+	SYS_MLOCK                  = 150
+	SYS_MUNLOCK                = 151
+	SYS_MLOCKALL               = 152
+	SYS_MUNLOCKALL             = 153
+	SYS_SCHED_SETPARAM         = 154
+	SYS_SCHED_GETPARAM         = 155
+	SYS_SCHED_SETSCHEDULER     = 156
+	SYS_SCHED_GETSCHEDULER     = 157
+	SYS_SCHED_YIELD            = 158
+	SYS_SCHED_GET_PRIORITY_MAX = 159
+	SYS_SCHED_GET_PRIORITY_MIN = 160
+	SYS_SCHED_RR_GET_INTERVAL  = 161
+	SYS_NANOSLEEP              = 162
+	SYS_MREMAP                 = 163
+	SYS_SETRESUID              = 164
+	SYS_GETRESUID              = 165
+	SYS_QUERY_MODULE           = 166
+	SYS_POLL                   = 167
+	SYS_NFSSERVCTL             = 168
+	SYS_SETRESGID              = 169
+	SYS_GETRESGID              = 170
+	SYS_PRCTL                  = 171
+	SYS_RT_SIGRETURN           = 172
+	SYS_RT_SIGACTION           = 173
+	SYS_RT_SIGPROCMASK         = 174
+	SYS_RT_SIGPENDING          = 175
+	SYS_RT_SIGTIMEDWAIT        = 176
+	SYS_RT_SIGQUEUEINFO        = 177
+	SYS_RT_SIGSUSPEND          = 178
+	SYS_PREAD64                = 179
+	SYS_PWRITE64               = 180
+	SYS_CHOWN                  = 181
+	SYS_GETCWD                 = 182
+	SYS_CAPGET                 = 183
+	SYS_CAPSET                 = 184
+	SYS_SIGALTSTACK            = 185
+	SYS_SENDFILE               = 186
+	SYS_GETPMSG                = 187
+	SYS_PUTPMSG                = 188
+	SYS_VFORK                  = 189
+	SYS_UGETRLIMIT             = 190
+	SYS_READAHEAD              = 191
+	SYS_PCICONFIG_READ         = 198
+	SYS_PCICONFIG_WRITE        = 199
+	SYS_PCICONFIG_IOBASE       = 200
+	SYS_MULTIPLEXER            = 201
+	SYS_GETDENTS64             = 202
+	SYS_PIVOT_ROOT             = 203
+	SYS_MADVISE                = 205
+	SYS_MINCORE                = 206
+	SYS_GETTID                 = 207
+	SYS_TKILL                  = 208
+	SYS_SETXATTR               = 209
+	SYS_LSETXATTR              = 210
+	SYS_FSETXATTR              = 211
+	SYS_GETXATTR               = 212
+	SYS_LGETXATTR              = 213
+	SYS_FGETXATTR              = 214
+	SYS_LISTXATTR              = 215
+	SYS_LLISTXATTR             = 216
+	SYS_FLISTXATTR             = 217
+	SYS_REMOVEXATTR            = 218
+	SYS_LREMOVEXATTR           = 219
+	SYS_FREMOVEXATTR           = 220
+	SYS_FUTEX                  = 221
+	SYS_SCHED_SETAFFINITY      = 222
+	SYS_SCHED_GETAFFINITY      = 223
+	SYS_TUXCALL                = 225
+	SYS_IO_SETUP               = 227
+	SYS_IO_DESTROY             = 228
+	SYS_IO_GETEVENTS           = 229
+	SYS_IO_SUBMIT              = 230
+	SYS_IO_CANCEL              = 231
+	SYS_SET_TID_ADDRESS        = 232
+	SYS_FADVISE64              = 233
+	SYS_EXIT_GROUP             = 234
+	SYS_LOOKUP_DCOOKIE         = 235
+	SYS_EPOLL_CREATE           = 236
+	SYS_EPOLL_CTL              = 237
+	SYS_EPOLL_WAIT             = 238
+	SYS_REMAP_FILE_PAGES       = 239
+	SYS_TIMER_CREATE           = 240
+	SYS_TIMER_SETTIME          = 241
+	SYS_TIMER_GETTIME          = 242
+	SYS_TIMER_GETOVERRUN       = 243
+	SYS_TIMER_DELETE           = 244
+	SYS_CLOCK_SETTIME          = 245
+	SYS_CLOCK_GETTIME          = 246
+	SYS_CLOCK_GETRES           = 247
+	SYS_CLOCK_NANOSLEEP        = 248
+	SYS_SWAPCONTEXT            = 249
+	SYS_TGKILL                 = 250
+	SYS_UTIMES                 = 251
+	SYS_STATFS64               = 252
+	SYS_FSTATFS64              = 253
+	SYS_RTAS                   = 255
+	SYS_SYS_DEBUG_SETCONTEXT   = 256
+	SYS_MIGRATE_PAGES          = 258
+	SYS_MBIND                  = 259
+	SYS_GET_MEMPOLICY          = 260
+	SYS_SET_MEMPOLICY          = 261
+	SYS_MQ_OPEN                = 262
+	SYS_MQ_UNLINK              = 263
+	SYS_MQ_TIMEDSEND           = 264
+	SYS_MQ_TIMEDRECEIVE        = 265
+	SYS_MQ_NOTIFY              = 266
+	SYS_MQ_GETSETATTR          = 267
+	SYS_KEXEC_LOAD             = 268
+	SYS_ADD_KEY                = 269
+	SYS_REQUEST_KEY            = 270
+	SYS_KEYCTL                 = 271
+	SYS_WAITID                 = 272
+	SYS_IOPRIO_SET             = 273
+	SYS_IOPRIO_GET             = 274
+	SYS_INOTIFY_INIT           = 275
+	SYS_INOTIFY_ADD_WATCH      = 276
+	SYS_INOTIFY_RM_WATCH       = 277
+	SYS_SPU_RUN                = 278
+	SYS_SPU_CREATE             = 279
+	SYS_PSELECT6               = 280
+	SYS_PPOLL                  = 281
+	SYS_UNSHARE                = 282
+	SYS_SPLICE                 = 283
+	SYS_TEE                    = 284
+	SYS_VMSPLICE               = 285
+	SYS_OPENAT                 = 286
+	SYS_MKDIRAT                = 287
+	SYS_MKNODAT                = 288
+	SYS_FCHOWNAT               = 289
+	SYS_FUTIMESAT              = 290
+	SYS_NEWFSTATAT             = 291
+	SYS_UNLINKAT               = 292
+	SYS_RENAMEAT               = 293
+	SYS_LINKAT                 = 294
+	SYS_SYMLINKAT              = 295
+	SYS_READLINKAT             = 296
+	SYS_FCHMODAT               = 297
+	SYS_FACCESSAT              = 298
+	SYS_GET_ROBUST_LIST        = 299
+	SYS_SET_ROBUST_LIST        = 300
+	SYS_MOVE_PAGES             = 301
+	SYS_GETCPU                 = 302
+	SYS_EPOLL_PWAIT            = 303
+	SYS_UTIMENSAT              = 304
+	SYS_SIGNALFD               = 305
+	SYS_TIMERFD_CREATE         = 306
+	SYS_EVENTFD                = 307
+	SYS_SYNC_FILE_RANGE2       = 308
+	SYS_FALLOCATE              = 309
+	SYS_SUBPAGE_PROT           = 310
+	SYS_TIMERFD_SETTIME        = 311
+	SYS_TIMERFD_GETTIME        = 312
+	SYS_SIGNALFD4              = 313
+	SYS_EVENTFD2               = 314
+	SYS_EPOLL_CREATE1          = 315
+	SYS_DUP3                   = 316
+	SYS_PIPE2                  = 317
+	SYS_INOTIFY_INIT1          = 318
+	SYS_PERF_EVENT_OPEN        = 319
+	SYS_PREADV                 = 320
+	SYS_PWRITEV                = 321
+	SYS_RT_TGSIGQUEUEINFO      = 322
+	SYS_FANOTIFY_INIT          = 323
+	SYS_FANOTIFY_MARK          = 324
+	SYS_PRLIMIT64              = 325
+	SYS_SOCKET                 = 326
+	SYS_BIND                   = 327
+	SYS_CONNECT                = 328
+	SYS_LISTEN                 = 329
+	SYS_ACCEPT                 = 330
+	SYS_GETSOCKNAME            = 331
+	SYS_GETPEERNAME            = 332
+	SYS_SOCKETPAIR             = 333
+	SYS_SEND                   = 334
+	SYS_SENDTO                 = 335
+	SYS_RECV                   = 336
+	SYS_RECVFROM               = 337
+	SYS_SHUTDOWN               = 338
+	SYS_SETSOCKOPT             = 339
+	SYS_GETSOCKOPT             = 340
+	SYS_SENDMSG                = 341
+	SYS_RECVMSG                = 342
+	SYS_RECVMMSG               = 343
+	SYS_ACCEPT4                = 344
+	SYS_NAME_TO_HANDLE_AT      = 345
+	SYS_OPEN_BY_HANDLE_AT      = 346
+	SYS_CLOCK_ADJTIME          = 347
+	SYS_SYNCFS                 = 348
+	SYS_SENDMMSG               = 349
+	SYS_SETNS                  = 350
+	SYS_PROCESS_VM_READV       = 351
+	SYS_PROCESS_VM_WRITEV      = 352
+	SYS_FINIT_MODULE           = 353
+	SYS_KCMP                   = 354
+)
diff --git a/src/syscall/zsysnum_linux_ppc64le.go b/src/syscall/zsysnum_linux_ppc64le.go
new file mode 100644
index 0000000..3af4e83
--- /dev/null
+++ b/src/syscall/zsysnum_linux_ppc64le.go
@@ -0,0 +1,353 @@
+// mksysnum_linux.pl /usr/include/powerpc64le-linux-gnu/asm/unistd.h
+// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+
+// +build ppc64le,linux
+
+package syscall
+
+const (
+	SYS_RESTART_SYSCALL        = 0
+	SYS_EXIT                   = 1
+	SYS_FORK                   = 2
+	SYS_READ                   = 3
+	SYS_WRITE                  = 4
+	SYS_OPEN                   = 5
+	SYS_CLOSE                  = 6
+	SYS_WAITPID                = 7
+	SYS_CREAT                  = 8
+	SYS_LINK                   = 9
+	SYS_UNLINK                 = 10
+	SYS_EXECVE                 = 11
+	SYS_CHDIR                  = 12
+	SYS_TIME                   = 13
+	SYS_MKNOD                  = 14
+	SYS_CHMOD                  = 15
+	SYS_LCHOWN                 = 16
+	SYS_BREAK                  = 17
+	SYS_OLDSTAT                = 18
+	SYS_LSEEK                  = 19
+	SYS_GETPID                 = 20
+	SYS_MOUNT                  = 21
+	SYS_UMOUNT                 = 22
+	SYS_SETUID                 = 23
+	SYS_GETUID                 = 24
+	SYS_STIME                  = 25
+	SYS_PTRACE                 = 26
+	SYS_ALARM                  = 27
+	SYS_OLDFSTAT               = 28
+	SYS_PAUSE                  = 29
+	SYS_UTIME                  = 30
+	SYS_STTY                   = 31
+	SYS_GTTY                   = 32
+	SYS_ACCESS                 = 33
+	SYS_NICE                   = 34
+	SYS_FTIME                  = 35
+	SYS_SYNC                   = 36
+	SYS_KILL                   = 37
+	SYS_RENAME                 = 38
+	SYS_MKDIR                  = 39
+	SYS_RMDIR                  = 40
+	SYS_DUP                    = 41
+	SYS_PIPE                   = 42
+	SYS_TIMES                  = 43
+	SYS_PROF                   = 44
+	SYS_BRK                    = 45
+	SYS_SETGID                 = 46
+	SYS_GETGID                 = 47
+	SYS_SIGNAL                 = 48
+	SYS_GETEUID                = 49
+	SYS_GETEGID                = 50
+	SYS_ACCT                   = 51
+	SYS_UMOUNT2                = 52
+	SYS_LOCK                   = 53
+	SYS_IOCTL                  = 54
+	SYS_FCNTL                  = 55
+	SYS_MPX                    = 56
+	SYS_SETPGID                = 57
+	SYS_ULIMIT                 = 58
+	SYS_OLDOLDUNAME            = 59
+	SYS_UMASK                  = 60
+	SYS_CHROOT                 = 61
+	SYS_USTAT                  = 62
+	SYS_DUP2                   = 63
+	SYS_GETPPID                = 64
+	SYS_GETPGRP                = 65
+	SYS_SETSID                 = 66
+	SYS_SIGACTION              = 67
+	SYS_SGETMASK               = 68
+	SYS_SSETMASK               = 69
+	SYS_SETREUID               = 70
+	SYS_SETREGID               = 71
+	SYS_SIGSUSPEND             = 72
+	SYS_SIGPENDING             = 73
+	SYS_SETHOSTNAME            = 74
+	SYS_SETRLIMIT              = 75
+	SYS_GETRLIMIT              = 76
+	SYS_GETRUSAGE              = 77
+	SYS_GETTIMEOFDAY           = 78
+	SYS_SETTIMEOFDAY           = 79
+	SYS_GETGROUPS              = 80
+	SYS_SETGROUPS              = 81
+	SYS_SELECT                 = 82
+	SYS_SYMLINK                = 83
+	SYS_OLDLSTAT               = 84
+	SYS_READLINK               = 85
+	SYS_USELIB                 = 86
+	SYS_SWAPON                 = 87
+	SYS_REBOOT                 = 88
+	SYS_READDIR                = 89
+	SYS_MMAP                   = 90
+	SYS_MUNMAP                 = 91
+	SYS_TRUNCATE               = 92
+	SYS_FTRUNCATE              = 93
+	SYS_FCHMOD                 = 94
+	SYS_FCHOWN                 = 95
+	SYS_GETPRIORITY            = 96
+	SYS_SETPRIORITY            = 97
+	SYS_PROFIL                 = 98
+	SYS_STATFS                 = 99
+	SYS_FSTATFS                = 100
+	SYS_IOPERM                 = 101
+	SYS_SOCKETCALL             = 102
+	SYS_SYSLOG                 = 103
+	SYS_SETITIMER              = 104
+	SYS_GETITIMER              = 105
+	SYS_STAT                   = 106
+	SYS_LSTAT                  = 107
+	SYS_FSTAT                  = 108
+	SYS_OLDUNAME               = 109
+	SYS_IOPL                   = 110
+	SYS_VHANGUP                = 111
+	SYS_IDLE                   = 112
+	SYS_VM86                   = 113
+	SYS_WAIT4                  = 114
+	SYS_SWAPOFF                = 115
+	SYS_SYSINFO                = 116
+	SYS_IPC                    = 117
+	SYS_FSYNC                  = 118
+	SYS_SIGRETURN              = 119
+	SYS_CLONE                  = 120
+	SYS_SETDOMAINNAME          = 121
+	SYS_UNAME                  = 122
+	SYS_MODIFY_LDT             = 123
+	SYS_ADJTIMEX               = 124
+	SYS_MPROTECT               = 125
+	SYS_SIGPROCMASK            = 126
+	SYS_CREATE_MODULE          = 127
+	SYS_INIT_MODULE            = 128
+	SYS_DELETE_MODULE          = 129
+	SYS_GET_KERNEL_SYMS        = 130
+	SYS_QUOTACTL               = 131
+	SYS_GETPGID                = 132
+	SYS_FCHDIR                 = 133
+	SYS_BDFLUSH                = 134
+	SYS_SYSFS                  = 135
+	SYS_PERSONALITY            = 136
+	SYS_AFS_SYSCALL            = 137
+	SYS_SETFSUID               = 138
+	SYS_SETFSGID               = 139
+	SYS__LLSEEK                = 140
+	SYS_GETDENTS               = 141
+	SYS__NEWSELECT             = 142
+	SYS_FLOCK                  = 143
+	SYS_MSYNC                  = 144
+	SYS_READV                  = 145
+	SYS_WRITEV                 = 146
+	SYS_GETSID                 = 147
+	SYS_FDATASYNC              = 148
+	SYS__SYSCTL                = 149
+	SYS_MLOCK                  = 150
+	SYS_MUNLOCK                = 151
+	SYS_MLOCKALL               = 152
+	SYS_MUNLOCKALL             = 153
+	SYS_SCHED_SETPARAM         = 154
+	SYS_SCHED_GETPARAM         = 155
+	SYS_SCHED_SETSCHEDULER     = 156
+	SYS_SCHED_GETSCHEDULER     = 157
+	SYS_SCHED_YIELD            = 158
+	SYS_SCHED_GET_PRIORITY_MAX = 159
+	SYS_SCHED_GET_PRIORITY_MIN = 160
+	SYS_SCHED_RR_GET_INTERVAL  = 161
+	SYS_NANOSLEEP              = 162
+	SYS_MREMAP                 = 163
+	SYS_SETRESUID              = 164
+	SYS_GETRESUID              = 165
+	SYS_QUERY_MODULE           = 166
+	SYS_POLL                   = 167
+	SYS_NFSSERVCTL             = 168
+	SYS_SETRESGID              = 169
+	SYS_GETRESGID              = 170
+	SYS_PRCTL                  = 171
+	SYS_RT_SIGRETURN           = 172
+	SYS_RT_SIGACTION           = 173
+	SYS_RT_SIGPROCMASK         = 174
+	SYS_RT_SIGPENDING          = 175
+	SYS_RT_SIGTIMEDWAIT        = 176
+	SYS_RT_SIGQUEUEINFO        = 177
+	SYS_RT_SIGSUSPEND          = 178
+	SYS_PREAD64                = 179
+	SYS_PWRITE64               = 180
+	SYS_CHOWN                  = 181
+	SYS_GETCWD                 = 182
+	SYS_CAPGET                 = 183
+	SYS_CAPSET                 = 184
+	SYS_SIGALTSTACK            = 185
+	SYS_SENDFILE               = 186
+	SYS_GETPMSG                = 187
+	SYS_PUTPMSG                = 188
+	SYS_VFORK                  = 189
+	SYS_UGETRLIMIT             = 190
+	SYS_READAHEAD              = 191
+	SYS_PCICONFIG_READ         = 198
+	SYS_PCICONFIG_WRITE        = 199
+	SYS_PCICONFIG_IOBASE       = 200
+	SYS_MULTIPLEXER            = 201
+	SYS_GETDENTS64             = 202
+	SYS_PIVOT_ROOT             = 203
+	SYS_MADVISE                = 205
+	SYS_MINCORE                = 206
+	SYS_GETTID                 = 207
+	SYS_TKILL                  = 208
+	SYS_SETXATTR               = 209
+	SYS_LSETXATTR              = 210
+	SYS_FSETXATTR              = 211
+	SYS_GETXATTR               = 212
+	SYS_LGETXATTR              = 213
+	SYS_FGETXATTR              = 214
+	SYS_LISTXATTR              = 215
+	SYS_LLISTXATTR             = 216
+	SYS_FLISTXATTR             = 217
+	SYS_REMOVEXATTR            = 218
+	SYS_LREMOVEXATTR           = 219
+	SYS_FREMOVEXATTR           = 220
+	SYS_FUTEX                  = 221
+	SYS_SCHED_SETAFFINITY      = 222
+	SYS_SCHED_GETAFFINITY      = 223
+	SYS_TUXCALL                = 225
+	SYS_IO_SETUP               = 227
+	SYS_IO_DESTROY             = 228
+	SYS_IO_GETEVENTS           = 229
+	SYS_IO_SUBMIT              = 230
+	SYS_IO_CANCEL              = 231
+	SYS_SET_TID_ADDRESS        = 232
+	SYS_FADVISE64              = 233
+	SYS_EXIT_GROUP             = 234
+	SYS_LOOKUP_DCOOKIE         = 235
+	SYS_EPOLL_CREATE           = 236
+	SYS_EPOLL_CTL              = 237
+	SYS_EPOLL_WAIT             = 238
+	SYS_REMAP_FILE_PAGES       = 239
+	SYS_TIMER_CREATE           = 240
+	SYS_TIMER_SETTIME          = 241
+	SYS_TIMER_GETTIME          = 242
+	SYS_TIMER_GETOVERRUN       = 243
+	SYS_TIMER_DELETE           = 244
+	SYS_CLOCK_SETTIME          = 245
+	SYS_CLOCK_GETTIME          = 246
+	SYS_CLOCK_GETRES           = 247
+	SYS_CLOCK_NANOSLEEP        = 248
+	SYS_SWAPCONTEXT            = 249
+	SYS_TGKILL                 = 250
+	SYS_UTIMES                 = 251
+	SYS_STATFS64               = 252
+	SYS_FSTATFS64              = 253
+	SYS_RTAS                   = 255
+	SYS_SYS_DEBUG_SETCONTEXT   = 256
+	SYS_MIGRATE_PAGES          = 258
+	SYS_MBIND                  = 259
+	SYS_GET_MEMPOLICY          = 260
+	SYS_SET_MEMPOLICY          = 261
+	SYS_MQ_OPEN                = 262
+	SYS_MQ_UNLINK              = 263
+	SYS_MQ_TIMEDSEND           = 264
+	SYS_MQ_TIMEDRECEIVE        = 265
+	SYS_MQ_NOTIFY              = 266
+	SYS_MQ_GETSETATTR          = 267
+	SYS_KEXEC_LOAD             = 268
+	SYS_ADD_KEY                = 269
+	SYS_REQUEST_KEY            = 270
+	SYS_KEYCTL                 = 271
+	SYS_WAITID                 = 272
+	SYS_IOPRIO_SET             = 273
+	SYS_IOPRIO_GET             = 274
+	SYS_INOTIFY_INIT           = 275
+	SYS_INOTIFY_ADD_WATCH      = 276
+	SYS_INOTIFY_RM_WATCH       = 277
+	SYS_SPU_RUN                = 278
+	SYS_SPU_CREATE             = 279
+	SYS_PSELECT6               = 280
+	SYS_PPOLL                  = 281
+	SYS_UNSHARE                = 282
+	SYS_SPLICE                 = 283
+	SYS_TEE                    = 284
+	SYS_VMSPLICE               = 285
+	SYS_OPENAT                 = 286
+	SYS_MKDIRAT                = 287
+	SYS_MKNODAT                = 288
+	SYS_FCHOWNAT               = 289
+	SYS_FUTIMESAT              = 290
+	SYS_NEWFSTATAT             = 291
+	SYS_UNLINKAT               = 292
+	SYS_RENAMEAT               = 293
+	SYS_LINKAT                 = 294
+	SYS_SYMLINKAT              = 295
+	SYS_READLINKAT             = 296
+	SYS_FCHMODAT               = 297
+	SYS_FACCESSAT              = 298
+	SYS_GET_ROBUST_LIST        = 299
+	SYS_SET_ROBUST_LIST        = 300
+	SYS_MOVE_PAGES             = 301
+	SYS_GETCPU                 = 302
+	SYS_EPOLL_PWAIT            = 303
+	SYS_UTIMENSAT              = 304
+	SYS_SIGNALFD               = 305
+	SYS_TIMERFD_CREATE         = 306
+	SYS_EVENTFD                = 307
+	SYS_SYNC_FILE_RANGE2       = 308
+	SYS_FALLOCATE              = 309
+	SYS_SUBPAGE_PROT           = 310
+	SYS_TIMERFD_SETTIME        = 311
+	SYS_TIMERFD_GETTIME        = 312
+	SYS_SIGNALFD4              = 313
+	SYS_EVENTFD2               = 314
+	SYS_EPOLL_CREATE1          = 315
+	SYS_DUP3                   = 316
+	SYS_PIPE2                  = 317
+	SYS_INOTIFY_INIT1          = 318
+	SYS_PERF_EVENT_OPEN        = 319
+	SYS_PREADV                 = 320
+	SYS_PWRITEV                = 321
+	SYS_RT_TGSIGQUEUEINFO      = 322
+	SYS_FANOTIFY_INIT          = 323
+	SYS_FANOTIFY_MARK          = 324
+	SYS_PRLIMIT64              = 325
+	SYS_SOCKET                 = 326
+	SYS_BIND                   = 327
+	SYS_CONNECT                = 328
+	SYS_LISTEN                 = 329
+	SYS_ACCEPT                 = 330
+	SYS_GETSOCKNAME            = 331
+	SYS_GETPEERNAME            = 332
+	SYS_SOCKETPAIR             = 333
+	SYS_SEND                   = 334
+	SYS_SENDTO                 = 335
+	SYS_RECV                   = 336
+	SYS_RECVFROM               = 337
+	SYS_SHUTDOWN               = 338
+	SYS_SETSOCKOPT             = 339
+	SYS_GETSOCKOPT             = 340
+	SYS_SENDMSG                = 341
+	SYS_RECVMSG                = 342
+	SYS_RECVMMSG               = 343
+	SYS_ACCEPT4                = 344
+	SYS_NAME_TO_HANDLE_AT      = 345
+	SYS_OPEN_BY_HANDLE_AT      = 346
+	SYS_CLOCK_ADJTIME          = 347
+	SYS_SYNCFS                 = 348
+	SYS_SENDMMSG               = 349
+	SYS_SETNS                  = 350
+	SYS_PROCESS_VM_READV       = 351
+	SYS_PROCESS_VM_WRITEV      = 352
+	SYS_FINIT_MODULE           = 353
+	SYS_KCMP                   = 354
+)
diff --git a/src/syscall/zsysnum_netbsd_386.go b/src/syscall/zsysnum_netbsd_386.go
index c570965..c8af210 100644
--- a/src/syscall/zsysnum_netbsd_386.go
+++ b/src/syscall/zsysnum_netbsd_386.go
@@ -1,6 +1,8 @@
 // mksysnum_netbsd.pl
 // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
 
+// +build 386,netbsd
+
 package syscall
 
 const (
diff --git a/src/syscall/zsysnum_netbsd_amd64.go b/src/syscall/zsysnum_netbsd_amd64.go
index c570965..e342a3c 100644
--- a/src/syscall/zsysnum_netbsd_amd64.go
+++ b/src/syscall/zsysnum_netbsd_amd64.go
@@ -1,6 +1,8 @@
 // mksysnum_netbsd.pl
 // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
 
+// +build amd64,netbsd
+
 package syscall
 
 const (
diff --git a/src/syscall/zsysnum_netbsd_arm.go b/src/syscall/zsysnum_netbsd_arm.go
index c570965..1f5b569 100644
--- a/src/syscall/zsysnum_netbsd_arm.go
+++ b/src/syscall/zsysnum_netbsd_arm.go
@@ -1,6 +1,8 @@
 // mksysnum_netbsd.pl
 // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
 
+// +build arm,netbsd
+
 package syscall
 
 const (
diff --git a/src/syscall/zsysnum_openbsd_386.go b/src/syscall/zsysnum_openbsd_386.go
index 3b9ac4c..c19f6de 100644
--- a/src/syscall/zsysnum_openbsd_386.go
+++ b/src/syscall/zsysnum_openbsd_386.go
@@ -1,6 +1,8 @@
 // mksysnum_openbsd.pl
 // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
 
+// +build 386,openbsd
+
 package syscall
 
 const (
diff --git a/src/syscall/zsysnum_openbsd_amd64.go b/src/syscall/zsysnum_openbsd_amd64.go
index 3b9ac4c..86e04cd 100644
--- a/src/syscall/zsysnum_openbsd_amd64.go
+++ b/src/syscall/zsysnum_openbsd_amd64.go
@@ -1,6 +1,8 @@
 // mksysnum_openbsd.pl
 // MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
 
+// +build amd64,openbsd
+
 package syscall
 
 const (
diff --git a/src/syscall/zsysnum_openbsd_arm.go b/src/syscall/zsysnum_openbsd_arm.go
new file mode 100644
index 0000000..38b43ca
--- /dev/null
+++ b/src/syscall/zsysnum_openbsd_arm.go
@@ -0,0 +1,213 @@
+// mksysnum_openbsd.pl
+// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+
+// +build arm,openbsd
+
+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/zsysnum_plan9_386.go b/src/syscall/zsysnum_plan9.go
similarity index 100%
rename from src/syscall/zsysnum_plan9_386.go
rename to src/syscall/zsysnum_plan9.go
diff --git a/src/syscall/zsysnum_plan9_amd64.go b/src/syscall/zsysnum_plan9_amd64.go
deleted file mode 100644
index 07498c4..0000000
--- a/src/syscall/zsysnum_plan9_amd64.go
+++ /dev/null
@@ -1,49 +0,0 @@
-// mksysnum_plan9.sh /media/sys/src/libc/9syscall/sys.h
-// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
-
-package syscall
-
-const (
-	SYS_SYSR1       = 0
-	SYS_BIND        = 2
-	SYS_CHDIR       = 3
-	SYS_CLOSE       = 4
-	SYS_DUP         = 5
-	SYS_ALARM       = 6
-	SYS_EXEC        = 7
-	SYS_EXITS       = 8
-	SYS_FAUTH       = 10
-	SYS_SEGBRK      = 12
-	SYS_OPEN        = 14
-	SYS_OSEEK       = 16
-	SYS_SLEEP       = 17
-	SYS_RFORK       = 19
-	SYS_PIPE        = 21
-	SYS_CREATE      = 22
-	SYS_FD2PATH     = 23
-	SYS_BRK_        = 24
-	SYS_REMOVE      = 25
-	SYS_NOTIFY      = 28
-	SYS_NOTED       = 29
-	SYS_SEGATTACH   = 30
-	SYS_SEGDETACH   = 31
-	SYS_SEGFREE     = 32
-	SYS_SEGFLUSH    = 33
-	SYS_RENDEZVOUS  = 34
-	SYS_UNMOUNT     = 35
-	SYS_SEMACQUIRE  = 37
-	SYS_SEMRELEASE  = 38
-	SYS_SEEK        = 39
-	SYS_FVERSION    = 40
-	SYS_ERRSTR      = 41
-	SYS_STAT        = 42
-	SYS_FSTAT       = 43
-	SYS_WSTAT       = 44
-	SYS_FWSTAT      = 45
-	SYS_MOUNT       = 46
-	SYS_AWAIT       = 47
-	SYS_PREAD       = 50
-	SYS_PWRITE      = 51
-	SYS_TSEMACQUIRE = 52
-	SYS_NSEC        = 53
-)
diff --git a/src/syscall/zsysnum_solaris_amd64.go b/src/syscall/zsysnum_solaris_amd64.go
index 43b3d8b..be198f8 100644
--- a/src/syscall/zsysnum_solaris_amd64.go
+++ b/src/syscall/zsysnum_solaris_amd64.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 amd64,solaris
+
 package syscall
 
 // TODO(aram): remove these before Go 1.3.
diff --git a/src/syscall/ztypes_darwin_386.go b/src/syscall/ztypes_darwin_386.go
index 13724c3..7298d02 100644
--- a/src/syscall/ztypes_darwin_386.go
+++ b/src/syscall/ztypes_darwin_386.go
@@ -1,6 +1,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs types_darwin.go
 
+// +build 386,darwin
+
 package syscall
 
 const (
diff --git a/src/syscall/ztypes_darwin_amd64.go b/src/syscall/ztypes_darwin_amd64.go
index 65b02ae..ec95d51 100644
--- a/src/syscall/ztypes_darwin_amd64.go
+++ b/src/syscall/ztypes_darwin_amd64.go
@@ -1,6 +1,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs types_darwin.go
 
+// +build amd64,darwin
+
 package syscall
 
 const (
diff --git a/src/syscall/ztypes_darwin_arm.go b/src/syscall/ztypes_darwin_arm.go
new file mode 100644
index 0000000..91c4470
--- /dev/null
+++ b/src/syscall/ztypes_darwin_arm.go
@@ -0,0 +1,449 @@
+// NOTE: cgo can't generate struct Stat_t and struct Statfs_t yet
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_darwin.go
+
+// +build arm,darwin
+
+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 Timeval32 [0]byte
+
+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
+
+type Stat_t struct {
+	Dev           int32
+	Mode          uint16
+	Nlink         uint16
+	Ino           uint64
+	Uid           uint32
+	Gid           uint32
+	Rdev          int32
+	Atimespec     Timespec
+	Mtimespec     Timespec
+	Ctimespec     Timespec
+	Birthtimespec Timespec
+	Size          int64
+	Blocks        int64
+	Blksize       int32
+	Flags         uint32
+	Gen           uint32
+	Lspare        int32
+	Qspare        [2]int64
+}
+
+type Statfs_t struct {
+	Bsize       uint32
+	Iosize      int32
+	Blocks      uint64
+	Bfree       uint64
+	Bavail      uint64
+	Files       uint64
+	Ffree       uint64
+	Fsid        Fsid
+	Owner       uint32
+	Type        uint32
+	Flags       uint32
+	Fssubtype   uint32
+	Fstypename  [16]int8
+	Mntonname   [1024]int8
+	Mntfromname [1024]int8
+	Reserved    [8]uint32
+}
+
+type Flock_t struct {
+	Start  int64
+	Len    int64
+	Pid    int32
+	Type   int16
+	Whence int16
+}
+
+type Fstore_t struct {
+	Flags      uint32
+	Posmode    int32
+	Offset     int64
+	Length     int64
+	Bytesalloc int64
+}
+
+type Radvisory_t struct {
+	Offset int64
+	Count  int32
+}
+
+type Fbootstraptransfer_t struct {
+	Offset int64
+	Length uint32
+	Buffer *byte
+}
+
+type Log2phys_t struct {
+	Flags       uint32
+	Contigbytes int64
+	Devoffset   int64
+}
+
+type Fsid struct {
+	Val [2]int32
+}
+
+type Dirent struct {
+	Ino       uint64
+	Seekoff   uint64
+	Reclen    uint16
+	Namlen    uint16
+	Type      uint8
+	Name      [1024]int8
+	Pad_cgo_0 [3]byte
+}
+
+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
+}
+
+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 Inet4Pktinfo struct {
+	Ifindex  uint32
+	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 {
+	Filt [8]uint32
+}
+
+const (
+	SizeofSockaddrInet4    = 0x10
+	SizeofSockaddrInet6    = 0x1c
+	SizeofSockaddrAny      = 0x6c
+	SizeofSockaddrUnix     = 0x6a
+	SizeofSockaddrDatalink = 0x14
+	SizeofLinger           = 0x8
+	SizeofIPMreq           = 0x8
+	SizeofIPv6Mreq         = 0x14
+	SizeofMsghdr           = 0x1c
+	SizeofCmsghdr          = 0xc
+	SizeofInet4Pktinfo     = 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]int32
+}
+
+const (
+	SizeofIfMsghdr    = 0x70
+	SizeofIfData      = 0x60
+	SizeofIfaMsghdr   = 0x14
+	SizeofIfmaMsghdr  = 0x10
+	SizeofIfmaMsghdr2 = 0x14
+	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
+	Typelen    uint8
+	Physical   uint8
+	Addrlen    uint8
+	Hdrlen     uint8
+	Recvquota  uint8
+	Xmitquota  uint8
+	Unused1    uint8
+	Mtu        uint32
+	Metric     uint32
+	Baudrate   uint32
+	Ipackets   uint32
+	Ierrors    uint32
+	Opackets   uint32
+	Oerrors    uint32
+	Collisions uint32
+	Ibytes     uint32
+	Obytes     uint32
+	Imcasts    uint32
+	Omcasts    uint32
+	Iqdrops    uint32
+	Noproto    uint32
+	Recvtiming uint32
+	Xmittiming uint32
+	Lastchange Timeval
+	Unused2    uint32
+	Hwassist   uint32
+	Reserved1  uint32
+	Reserved2  uint32
+}
+
+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 IfmaMsghdr2 struct {
+	Msglen    uint16
+	Version   uint8
+	Type      uint8
+	Addrs     int32
+	Flags     int32
+	Index     uint16
+	Pad_cgo_0 [2]byte
+	Refcount  int32
+}
+
+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
+	Hopcount uint32
+	Expire   int32
+	Recvpipe uint32
+	Sendpipe uint32
+	Ssthresh uint32
+	Rtt      uint32
+	Rttvar   uint32
+	Pksent   uint32
+	Filler   [4]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_darwin_arm64.go b/src/syscall/ztypes_darwin_arm64.go
new file mode 100644
index 0000000..1d65cfd
--- /dev/null
+++ b/src/syscall/ztypes_darwin_arm64.go
@@ -0,0 +1,458 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_darwin.go
+
+// +build arm64,darwin
+
+package syscall
+
+const (
+	sizeofPtr      = 0x8
+	sizeofShort    = 0x2
+	sizeofInt      = 0x4
+	sizeofLong     = 0x8
+	sizeofLongLong = 0x8
+)
+
+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      int32
+	Pad_cgo_0 [4]byte
+}
+
+type Timeval32 struct {
+	Sec  int32
+	Usec int32
+}
+
+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           int32
+	Mode          uint16
+	Nlink         uint16
+	Ino           uint64
+	Uid           uint32
+	Gid           uint32
+	Rdev          int32
+	Pad_cgo_0     [4]byte
+	Atimespec     Timespec
+	Mtimespec     Timespec
+	Ctimespec     Timespec
+	Birthtimespec Timespec
+	Size          int64
+	Blocks        int64
+	Blksize       int32
+	Flags         uint32
+	Gen           uint32
+	Lspare        int32
+	Qspare        [2]int64
+}
+
+type Statfs_t struct {
+	Bsize       uint32
+	Iosize      int32
+	Blocks      uint64
+	Bfree       uint64
+	Bavail      uint64
+	Files       uint64
+	Ffree       uint64
+	Fsid        Fsid
+	Owner       uint32
+	Type        uint32
+	Flags       uint32
+	Fssubtype   uint32
+	Fstypename  [16]int8
+	Mntonname   [1024]int8
+	Mntfromname [1024]int8
+	Reserved    [8]uint32
+}
+
+type Flock_t struct {
+	Start  int64
+	Len    int64
+	Pid    int32
+	Type   int16
+	Whence int16
+}
+
+type Fstore_t struct {
+	Flags      uint32
+	Posmode    int32
+	Offset     int64
+	Length     int64
+	Bytesalloc int64
+}
+
+type Radvisory_t struct {
+	Offset    int64
+	Count     int32
+	Pad_cgo_0 [4]byte
+}
+
+type Fbootstraptransfer_t struct {
+	Offset int64
+	Length uint64
+	Buffer *byte
+}
+
+type Log2phys_t struct {
+	Flags       uint32
+	Contigbytes int64
+	Devoffset   int64
+}
+
+type Fsid struct {
+	Val [2]int32
+}
+
+type Dirent struct {
+	Ino       uint64
+	Seekoff   uint64
+	Reclen    uint16
+	Namlen    uint16
+	Type      uint8
+	Name      [1024]int8
+	Pad_cgo_0 [3]byte
+}
+
+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
+}
+
+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  uint64
+}
+
+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
+	Pad_cgo_0  [4]byte
+	Iov        *Iovec
+	Iovlen     int32
+	Pad_cgo_1  [4]byte
+	Control    *byte
+	Controllen uint32
+	Flags      int32
+}
+
+type Cmsghdr struct {
+	Len   uint32
+	Level int32
+	Type  int32
+}
+
+type Inet4Pktinfo struct {
+	Ifindex  uint32
+	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 {
+	Filt [8]uint32
+}
+
+const (
+	SizeofSockaddrInet4    = 0x10
+	SizeofSockaddrInet6    = 0x1c
+	SizeofSockaddrAny      = 0x6c
+	SizeofSockaddrUnix     = 0x6a
+	SizeofSockaddrDatalink = 0x14
+	SizeofLinger           = 0x8
+	SizeofIPMreq           = 0x8
+	SizeofIPv6Mreq         = 0x14
+	SizeofMsghdr           = 0x30
+	SizeofCmsghdr          = 0xc
+	SizeofInet4Pktinfo     = 0xc
+	SizeofInet6Pktinfo     = 0x14
+	SizeofIPv6MTUInfo      = 0x20
+	SizeofICMPv6Filter     = 0x20
+)
+
+const (
+	PTRACE_TRACEME = 0x0
+	PTRACE_CONT    = 0x7
+	PTRACE_KILL    = 0x8
+)
+
+type Kevent_t struct {
+	Ident  uint64
+	Filter int16
+	Flags  uint16
+	Fflags uint32
+	Data   int64
+	Udata  *byte
+}
+
+type FdSet struct {
+	Bits [32]int32
+}
+
+const (
+	SizeofIfMsghdr    = 0x70
+	SizeofIfData      = 0x60
+	SizeofIfaMsghdr   = 0x14
+	SizeofIfmaMsghdr  = 0x10
+	SizeofIfmaMsghdr2 = 0x14
+	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
+	Typelen    uint8
+	Physical   uint8
+	Addrlen    uint8
+	Hdrlen     uint8
+	Recvquota  uint8
+	Xmitquota  uint8
+	Unused1    uint8
+	Mtu        uint32
+	Metric     uint32
+	Baudrate   uint32
+	Ipackets   uint32
+	Ierrors    uint32
+	Opackets   uint32
+	Oerrors    uint32
+	Collisions uint32
+	Ibytes     uint32
+	Obytes     uint32
+	Imcasts    uint32
+	Omcasts    uint32
+	Iqdrops    uint32
+	Noproto    uint32
+	Recvtiming uint32
+	Xmittiming uint32
+	Lastchange Timeval32
+	Unused2    uint32
+	Hwassist   uint32
+	Reserved1  uint32
+	Reserved2  uint32
+}
+
+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 IfmaMsghdr2 struct {
+	Msglen    uint16
+	Version   uint8
+	Type      uint8
+	Addrs     int32
+	Flags     int32
+	Index     uint16
+	Pad_cgo_0 [2]byte
+	Refcount  int32
+}
+
+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
+	Hopcount uint32
+	Expire   int32
+	Recvpipe uint32
+	Sendpipe uint32
+	Ssthresh uint32
+	Rtt      uint32
+	Rttvar   uint32
+	Pksent   uint32
+	Filler   [4]uint32
+}
+
+const (
+	SizeofBpfVersion = 0x4
+	SizeofBpfStat    = 0x8
+	SizeofBpfProgram = 0x10
+	SizeofBpfInsn    = 0x8
+	SizeofBpfHdr     = 0x14
+)
+
+type BpfVersion struct {
+	Major uint16
+	Minor uint16
+}
+
+type BpfStat struct {
+	Recv uint32
+	Drop uint32
+}
+
+type BpfProgram struct {
+	Len       uint32
+	Pad_cgo_0 [4]byte
+	Insns     *BpfInsn
+}
+
+type BpfInsn struct {
+	Code uint16
+	Jt   uint8
+	Jf   uint8
+	K    uint32
+}
+
+type BpfHdr struct {
+	Tstamp    Timeval32
+	Caplen    uint32
+	Datalen   uint32
+	Hdrlen    uint16
+	Pad_cgo_0 [2]byte
+}
+
+type Termios struct {
+	Iflag     uint64
+	Oflag     uint64
+	Cflag     uint64
+	Lflag     uint64
+	Cc        [20]uint8
+	Pad_cgo_0 [4]byte
+	Ispeed    uint64
+	Ospeed    uint64
+}
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_dragonfly_amd64.go b/src/syscall/ztypes_dragonfly_amd64.go
index 954ffd7..00120d0 100644
--- a/src/syscall/ztypes_dragonfly_amd64.go
+++ b/src/syscall/ztypes_dragonfly_amd64.go
@@ -1,6 +1,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs types_dragonfly.go
 
+// +build amd64,dragonfly
+
 package syscall
 
 const (
diff --git a/src/syscall/ztypes_freebsd_386.go b/src/syscall/ztypes_freebsd_386.go
index b809eea..d972fb6 100644
--- a/src/syscall/ztypes_freebsd_386.go
+++ b/src/syscall/ztypes_freebsd_386.go
@@ -1,6 +1,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs types_freebsd.go
 
+// +build 386,freebsd
+
 package syscall
 
 const (
diff --git a/src/syscall/ztypes_freebsd_amd64.go b/src/syscall/ztypes_freebsd_amd64.go
index a05908a..0a5a10b 100644
--- a/src/syscall/ztypes_freebsd_amd64.go
+++ b/src/syscall/ztypes_freebsd_amd64.go
@@ -1,6 +1,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs types_freebsd.go
 
+// +build amd64,freebsd
+
 package syscall
 
 const (
diff --git a/src/syscall/ztypes_freebsd_arm.go b/src/syscall/ztypes_freebsd_arm.go
index 9303816..5d7acd5 100644
--- a/src/syscall/ztypes_freebsd_arm.go
+++ b/src/syscall/ztypes_freebsd_arm.go
@@ -1,6 +1,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs -- -fsigned-char types_freebsd.go
 
+// +build arm,freebsd
+
 package syscall
 
 const (
diff --git a/src/syscall/ztypes_linux_386.go b/src/syscall/ztypes_linux_386.go
index daecb1d..dd198cb 100644
--- a/src/syscall/ztypes_linux_386.go
+++ b/src/syscall/ztypes_linux_386.go
@@ -1,6 +1,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs types_linux.go
 
+// +build 386,linux
+
 package syscall
 
 const (
@@ -572,7 +574,9 @@ type EpollEvent struct {
 }
 
 const (
-	_AT_FDCWD = -0x64
+	_AT_FDCWD            = -0x64
+	_AT_REMOVEDIR        = 0x200
+	_AT_SYMLINK_NOFOLLOW = 0x100
 )
 
 type Termios struct {
diff --git a/src/syscall/ztypes_linux_amd64.go b/src/syscall/ztypes_linux_amd64.go
index 694fe1e..a39489e 100644
--- a/src/syscall/ztypes_linux_amd64.go
+++ b/src/syscall/ztypes_linux_amd64.go
@@ -1,6 +1,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs types_linux.go
 
+// +build amd64,linux
+
 package syscall
 
 const (
@@ -590,7 +592,9 @@ type EpollEvent struct {
 }
 
 const (
-	_AT_FDCWD = -0x64
+	_AT_FDCWD            = -0x64
+	_AT_REMOVEDIR        = 0x200
+	_AT_SYMLINK_NOFOLLOW = 0x100
 )
 
 type Termios struct {
diff --git a/src/syscall/ztypes_linux_arm.go b/src/syscall/ztypes_linux_arm.go
index 5f21a94..f446e41 100644
--- a/src/syscall/ztypes_linux_arm.go
+++ b/src/syscall/ztypes_linux_arm.go
@@ -1,6 +1,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs types_linux.go
 
+// +build arm,linux
+
 package syscall
 
 const (
@@ -561,7 +563,9 @@ type EpollEvent struct {
 }
 
 const (
-	_AT_FDCWD = -0x64
+	_AT_FDCWD            = -0x64
+	_AT_REMOVEDIR        = 0x200
+	_AT_SYMLINK_NOFOLLOW = 0x100
 )
 
 type Termios struct {
diff --git a/src/syscall/ztypes_linux_arm64.go b/src/syscall/ztypes_linux_arm64.go
new file mode 100644
index 0000000..dcb1178
--- /dev/null
+++ b/src/syscall/ztypes_linux_arm64.go
@@ -0,0 +1,596 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs -- -fsigned-char types_linux.go
+
+// +build arm64,linux
+
+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_linux_ppc64.go b/src/syscall/ztypes_linux_ppc64.go
new file mode 100644
index 0000000..33d1b7f
--- /dev/null
+++ b/src/syscall/ztypes_linux_ppc64.go
@@ -0,0 +1,606 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_linux.go
+
+// +build ppc64,linux
+
+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
+	Nlink      uint64
+	Mode       uint32
+	Uid        uint32
+	Gid        uint32
+	X__pad2    int32
+	Rdev       uint64
+	Size       int64
+	Blksize    int64
+	Blocks     int64
+	Atim       Timespec
+	Mtim       Timespec
+	Ctim       Timespec
+	X__unused4 uint64
+	X__unused5 uint64
+	X__unused6 uint64
+}
+
+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]uint8
+	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]uint8
+}
+
+type RawSockaddrAny struct {
+	Addr RawSockaddr
+	Pad  [96]uint8
+}
+
+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            = 0x22
+	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]uint8
+}
+
+const SizeofInotifyEvent = 0x10
+
+type PtraceRegs struct {
+	Gpr       [32]uint64
+	Nip       uint64
+	Msr       uint64
+	Orig_gpr3 uint64
+	Ctr       uint64
+	Link      uint64
+	Xer       uint64
+	Ccr       uint64
+	Softe     uint64
+	Trap      uint64
+	Dar       uint64
+	Dsisr     uint64
+	Result    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]uint8
+	Pad_cgo_1 [4]byte
+}
+
+type Utsname struct {
+	Sysname    [65]uint8
+	Nodename   [65]uint8
+	Release    [65]uint8
+	Version    [65]uint8
+	Machine    [65]uint8
+	Domainname [65]uint8
+}
+
+type Ustat_t struct {
+	Tfree     int32
+	Pad_cgo_0 [4]byte
+	Tinode    uint64
+	Fname     [6]uint8
+	Fpack     [6]uint8
+	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  = 0x1000
+	OLCUC  = 0x4
+	TCGETS = 0x403c7413
+	TCSETS = 0x803c7414
+	XCASE  = 0x4000
+)
diff --git a/src/syscall/ztypes_linux_ppc64le.go b/src/syscall/ztypes_linux_ppc64le.go
new file mode 100644
index 0000000..27ca004
--- /dev/null
+++ b/src/syscall/ztypes_linux_ppc64le.go
@@ -0,0 +1,606 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_linux.go
+
+// +build ppc64le,linux
+
+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
+	Nlink              uint64
+	Mode               uint32
+	Uid                uint32
+	Gid                uint32
+	X__pad2            int32
+	Rdev               uint64
+	Size               int64
+	Blksize            int64
+	Blocks             int64
+	Atim               Timespec
+	Mtim               Timespec
+	Ctim               Timespec
+	X__glibc_reserved4 uint64
+	X__glibc_reserved5 uint64
+	X__glibc_reserved6 uint64
+}
+
+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]uint8
+	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]uint8
+}
+
+type RawSockaddrAny struct {
+	Addr RawSockaddr
+	Pad  [96]uint8
+}
+
+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            = 0x22
+	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]uint8
+}
+
+const SizeofInotifyEvent = 0x10
+
+type PtraceRegs struct {
+	Gpr       [32]uint64
+	Nip       uint64
+	Msr       uint64
+	Orig_gpr3 uint64
+	Ctr       uint64
+	Link      uint64
+	Xer       uint64
+	Ccr       uint64
+	Softe     uint64
+	Trap      uint64
+	Dar       uint64
+	Dsisr     uint64
+	Result    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]uint8
+	Pad_cgo_1 [4]byte
+}
+
+type Utsname struct {
+	Sysname    [65]uint8
+	Nodename   [65]uint8
+	Release    [65]uint8
+	Version    [65]uint8
+	Machine    [65]uint8
+	Domainname [65]uint8
+}
+
+type Ustat_t struct {
+	Tfree     int32
+	Pad_cgo_0 [4]byte
+	Tinode    uint64
+	Fname     [6]uint8
+	Fpack     [6]uint8
+	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  = 0x1000
+	OLCUC  = 0x4
+	TCGETS = 0x403c7413
+	TCSETS = 0x803c7414
+	XCASE  = 0x4000
+)
diff --git a/src/syscall/ztypes_netbsd_386.go b/src/syscall/ztypes_netbsd_386.go
index 6add325..1752c6c 100644
--- a/src/syscall/ztypes_netbsd_386.go
+++ b/src/syscall/ztypes_netbsd_386.go
@@ -1,6 +1,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs types_netbsd.go
 
+// +build 386,netbsd
+
 package syscall
 
 const (
diff --git a/src/syscall/ztypes_netbsd_amd64.go b/src/syscall/ztypes_netbsd_amd64.go
index 4451fc1..b8d4b0b 100644
--- a/src/syscall/ztypes_netbsd_amd64.go
+++ b/src/syscall/ztypes_netbsd_amd64.go
@@ -1,6 +1,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs types_netbsd.go
 
+// +build amd64,netbsd
+
 package syscall
 
 const (
diff --git a/src/syscall/ztypes_netbsd_arm.go b/src/syscall/ztypes_netbsd_arm.go
index 4e853ea..c21d875 100644
--- a/src/syscall/ztypes_netbsd_arm.go
+++ b/src/syscall/ztypes_netbsd_arm.go
@@ -1,6 +1,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs types_netbsd.go
 
+// +build arm,netbsd
+
 package syscall
 
 const (
diff --git a/src/syscall/ztypes_openbsd_386.go b/src/syscall/ztypes_openbsd_386.go
index 2e4d9dd..0376d3a 100644
--- a/src/syscall/ztypes_openbsd_386.go
+++ b/src/syscall/ztypes_openbsd_386.go
@@ -1,6 +1,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs types_openbsd.go
 
+// +build 386,openbsd
+
 package syscall
 
 const (
diff --git a/src/syscall/ztypes_openbsd_amd64.go b/src/syscall/ztypes_openbsd_amd64.go
index f07bc71..bf23626 100644
--- a/src/syscall/ztypes_openbsd_amd64.go
+++ b/src/syscall/ztypes_openbsd_amd64.go
@@ -1,6 +1,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs types_openbsd.go
 
+// +build amd64,openbsd
+
 package syscall
 
 const (
diff --git a/src/syscall/ztypes_openbsd_arm.go b/src/syscall/ztypes_openbsd_arm.go
new file mode 100644
index 0000000..e1d8938
--- /dev/null
+++ b/src/syscall/ztypes_openbsd_arm.go
@@ -0,0 +1,434 @@
+// Created by cgo -godefs - DO NOT EDIT
+// cgo -godefs types_openbsd.go
+
+// +build arm,openbsd
+
+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/syscall/ztypes_plan9_386.go b/src/syscall/ztypes_plan9_386.go
deleted file mode 100644
index 3e3a8d1..0000000
--- a/src/syscall/ztypes_plan9_386.go
+++ /dev/null
@@ -1,75 +0,0 @@
-// godefs -gsyscall -f -m32 types_plan9.c
-
-// MACHINE GENERATED - DO NOT EDIT.
-
-package syscall
-
-// Constants
-const (
-	O_RDONLY   = 0
-	O_WRONLY   = 0x1
-	O_RDWR     = 0x2
-	O_TRUNC    = 0x10
-	O_CLOEXEC  = 0x20
-	O_EXCL     = 0x1000
-	STATMAX    = 0xffff
-	ERRMAX     = 0x80
-	MORDER     = 0x3
-	MREPL      = 0
-	MBEFORE    = 0x1
-	MAFTER     = 0x2
-	MCREATE    = 0x4
-	MCACHE     = 0x10
-	MMASK      = 0x17
-	RFNAMEG    = 0x1
-	RFENVG     = 0x2
-	RFFDG      = 0x4
-	RFNOTEG    = 0x8
-	RFPROC     = 0x10
-	RFMEM      = 0x20
-	RFNOWAIT   = 0x40
-	RFCNAMEG   = 0x400
-	RFCENVG    = 0x800
-	RFCFDG     = 0x1000
-	RFREND     = 0x2000
-	RFNOMNT    = 0x4000
-	QTDIR      = 0x80
-	QTAPPEND   = 0x40
-	QTEXCL     = 0x20
-	QTMOUNT    = 0x10
-	QTAUTH     = 0x8
-	QTTMP      = 0x4
-	QTFILE     = 0
-	DMDIR      = 0x80000000
-	DMAPPEND   = 0x40000000
-	DMEXCL     = 0x20000000
-	DMMOUNT    = 0x10000000
-	DMAUTH     = 0x8000000
-	DMTMP      = 0x4000000
-	DMREAD     = 0x4
-	DMWRITE    = 0x2
-	DMEXEC     = 0x1
-	STATFIXLEN = 0x31
-)
-
-// Types
-
-type _C_int int32
-
-type Prof struct {
-	Pp    *[0]byte /* sPlink */
-	Next  *[0]byte /* sPlink */
-	Last  *[0]byte /* sPlink */
-	First *[0]byte /* sPlink */
-	Pid   uint32
-	What  uint32
-}
-
-type Tos struct {
-	Prof      Prof
-	Cyclefreq uint64
-	Kcycles   int64
-	Pcycles   int64
-	Pid       uint32
-	Clock     uint32
-}
diff --git a/src/syscall/ztypes_plan9_amd64.go b/src/syscall/ztypes_plan9_amd64.go
deleted file mode 100644
index 3e3a8d1..0000000
--- a/src/syscall/ztypes_plan9_amd64.go
+++ /dev/null
@@ -1,75 +0,0 @@
-// godefs -gsyscall -f -m32 types_plan9.c
-
-// MACHINE GENERATED - DO NOT EDIT.
-
-package syscall
-
-// Constants
-const (
-	O_RDONLY   = 0
-	O_WRONLY   = 0x1
-	O_RDWR     = 0x2
-	O_TRUNC    = 0x10
-	O_CLOEXEC  = 0x20
-	O_EXCL     = 0x1000
-	STATMAX    = 0xffff
-	ERRMAX     = 0x80
-	MORDER     = 0x3
-	MREPL      = 0
-	MBEFORE    = 0x1
-	MAFTER     = 0x2
-	MCREATE    = 0x4
-	MCACHE     = 0x10
-	MMASK      = 0x17
-	RFNAMEG    = 0x1
-	RFENVG     = 0x2
-	RFFDG      = 0x4
-	RFNOTEG    = 0x8
-	RFPROC     = 0x10
-	RFMEM      = 0x20
-	RFNOWAIT   = 0x40
-	RFCNAMEG   = 0x400
-	RFCENVG    = 0x800
-	RFCFDG     = 0x1000
-	RFREND     = 0x2000
-	RFNOMNT    = 0x4000
-	QTDIR      = 0x80
-	QTAPPEND   = 0x40
-	QTEXCL     = 0x20
-	QTMOUNT    = 0x10
-	QTAUTH     = 0x8
-	QTTMP      = 0x4
-	QTFILE     = 0
-	DMDIR      = 0x80000000
-	DMAPPEND   = 0x40000000
-	DMEXCL     = 0x20000000
-	DMMOUNT    = 0x10000000
-	DMAUTH     = 0x8000000
-	DMTMP      = 0x4000000
-	DMREAD     = 0x4
-	DMWRITE    = 0x2
-	DMEXEC     = 0x1
-	STATFIXLEN = 0x31
-)
-
-// Types
-
-type _C_int int32
-
-type Prof struct {
-	Pp    *[0]byte /* sPlink */
-	Next  *[0]byte /* sPlink */
-	Last  *[0]byte /* sPlink */
-	First *[0]byte /* sPlink */
-	Pid   uint32
-	What  uint32
-}
-
-type Tos struct {
-	Prof      Prof
-	Cyclefreq uint64
-	Kcycles   int64
-	Pcycles   int64
-	Pid       uint32
-	Clock     uint32
-}
diff --git a/src/syscall/ztypes_solaris_amd64.go b/src/syscall/ztypes_solaris_amd64.go
index 77275a5..2471519 100644
--- a/src/syscall/ztypes_solaris_amd64.go
+++ b/src/syscall/ztypes_solaris_amd64.go
@@ -1,6 +1,8 @@
 // Created by cgo -godefs - DO NOT EDIT
 // cgo -godefs types_solaris.go
 
+// +build amd64,solaris
+
 package syscall
 
 const (
diff --git a/src/syscall/ztypes_windows.go b/src/syscall/ztypes_windows.go
index 4c8a99a..e5c7325 100644
--- a/src/syscall/ztypes_windows.go
+++ b/src/syscall/ztypes_windows.go
@@ -1083,12 +1083,7 @@ type TCPKeepalive struct {
 	Interval uint32
 }
 
-type reparseDataBuffer struct {
-	ReparseTag        uint32
-	ReparseDataLength uint16
-	Reserved          uint16
-
-	// SymbolicLinkReparseBuffer
+type symbolicLinkReparseBuffer struct {
 	SubstituteNameOffset uint16
 	SubstituteNameLength uint16
 	PrintNameOffset      uint16
@@ -1097,9 +1092,27 @@ type reparseDataBuffer struct {
 	PathBuffer           [1]uint16
 }
 
+type mountPointReparseBuffer struct {
+	SubstituteNameOffset uint16
+	SubstituteNameLength uint16
+	PrintNameOffset      uint16
+	PrintNameLength      uint16
+	PathBuffer           [1]uint16
+}
+
+type reparseDataBuffer struct {
+	ReparseTag        uint32
+	ReparseDataLength uint16
+	Reserved          uint16
+
+	// GenericReparseBuffer
+	reparseBuffer byte
+}
+
 const (
 	FSCTL_GET_REPARSE_POINT          = 0x900A8
 	MAXIMUM_REPARSE_DATA_BUFFER_SIZE = 16 * 1024
+	_IO_REPARSE_TAG_MOUNT_POINT      = 0xA0000003
 	IO_REPARSE_TAG_SYMLINK           = 0xA000000C
 	SYMBOLIC_LINK_FLAG_DIRECTORY     = 0x1
 )
diff --git a/src/testing/benchmark.go b/src/testing/benchmark.go
index ffd5376..62e696d 100644
--- a/src/testing/benchmark.go
+++ b/src/testing/benchmark.go
@@ -280,6 +280,14 @@ func (r BenchmarkResult) MemString() string {
 		r.AllocedBytesPerOp(), r.AllocsPerOp())
 }
 
+// benchmarkName returns full name of benchmark including procs suffix.
+func benchmarkName(name string, n int) string {
+	if n != 1 {
+		return fmt.Sprintf("%s-%d", name, n)
+	}
+	return name
+}
+
 // An internal function but exported because it is cross-package; part of the implementation
 // of the "go test" command.
 func RunBenchmarks(matchString func(pat, str string) (bool, error), benchmarks []InternalBenchmark) {
@@ -287,15 +295,30 @@ func RunBenchmarks(matchString func(pat, str string) (bool, error), benchmarks [
 	if len(*matchBenchmarks) == 0 {
 		return
 	}
+	// Collect matching benchmarks and determine longest name.
+	maxprocs := 1
+	for _, procs := range cpuList {
+		if procs > maxprocs {
+			maxprocs = procs
+		}
+	}
+	maxlen := 0
+	var bs []InternalBenchmark
 	for _, Benchmark := range benchmarks {
 		matched, err := matchString(*matchBenchmarks, Benchmark.Name)
 		if err != nil {
 			fmt.Fprintf(os.Stderr, "testing: invalid regexp for -test.bench: %s\n", err)
 			os.Exit(1)
 		}
-		if !matched {
-			continue
+		if matched {
+			bs = append(bs, Benchmark)
+			benchName := benchmarkName(Benchmark.Name, maxprocs)
+			if l := len(benchName); l > maxlen {
+				maxlen = l
+			}
 		}
+	}
+	for _, Benchmark := range bs {
 		for _, procs := range cpuList {
 			runtime.GOMAXPROCS(procs)
 			b := &B{
@@ -304,11 +327,8 @@ func RunBenchmarks(matchString func(pat, str string) (bool, error), benchmarks [
 				},
 				benchmark: Benchmark,
 			}
-			benchName := Benchmark.Name
-			if procs != 1 {
-				benchName = fmt.Sprintf("%s-%d", Benchmark.Name, procs)
-			}
-			fmt.Printf("%s\t", benchName)
+			benchName := benchmarkName(Benchmark.Name, procs)
+			fmt.Printf("%-*s\t", maxlen, benchName)
 			r := b.run()
 			if b.failed {
 				// The output could be very long here, but probably isn't.
diff --git a/src/testing/example.go b/src/testing/example.go
index f5762e4..30baf27 100644
--- a/src/testing/example.go
+++ b/src/testing/example.go
@@ -43,7 +43,7 @@ func RunExamples(matchString func(pat, str string) (bool, error), examples []Int
 
 func runExample(eg InternalExample) (ok bool) {
 	if *chatty {
-		fmt.Printf("=== RUN: %s\n", eg.Name)
+		fmt.Printf("=== RUN   %s\n", eg.Name)
 	}
 
 	// Capture stdout.
@@ -56,8 +56,8 @@ func runExample(eg InternalExample) (ok bool) {
 	os.Stdout = w
 	outC := make(chan string)
 	go func() {
-		buf := new(bytes.Buffer)
-		_, err := io.Copy(buf, r)
+		var buf bytes.Buffer
+		_, err := io.Copy(&buf, r)
 		r.Close()
 		if err != nil {
 			fmt.Fprintf(os.Stderr, "testing: copying pipe: %v\n", err)
diff --git a/src/testing/iotest/logger.go b/src/testing/iotest/logger.go
index 1475d9b..0aec15c 100644
--- a/src/testing/iotest/logger.go
+++ b/src/testing/iotest/logger.go
@@ -48,7 +48,7 @@ func (l *readLogger) Read(p []byte) (n int, err error) {
 
 // NewReadLogger returns a reader that behaves like r except
 // that it logs (using log.Print) each read to standard error,
-// printing the prefix and the hexadecimal data written.
+// printing the prefix and the hexadecimal data read.
 func NewReadLogger(prefix string, r io.Reader) io.Reader {
 	return &readLogger{prefix, r}
 }
diff --git a/src/testing/quick/quick.go b/src/testing/quick/quick.go
index 909c65f..13c56cd 100644
--- a/src/testing/quick/quick.go
+++ b/src/testing/quick/quick.go
@@ -102,12 +102,16 @@ func Value(t reflect.Type, rand *rand.Rand) (value reflect.Value, ok bool) {
 			v.SetMapIndex(key, value)
 		}
 	case reflect.Ptr:
-		elem, ok := Value(concrete.Elem(), rand)
-		if !ok {
-			return reflect.Value{}, false
+		if rand.Intn(complexSize) == 0 {
+			v.Set(reflect.Zero(concrete)) // Generate nil pointer.
+		} else {
+			elem, ok := Value(concrete.Elem(), rand)
+			if !ok {
+				return reflect.Value{}, false
+			}
+			v.Set(reflect.New(concrete.Elem()))
+			v.Elem().Set(elem)
 		}
-		v.Set(reflect.New(concrete.Elem()))
-		v.Elem().Set(elem)
 	case reflect.Slice:
 		numElems := rand.Intn(complexSize)
 		v.Set(reflect.MakeSlice(concrete, numElems, numElems))
@@ -118,6 +122,14 @@ func Value(t reflect.Type, rand *rand.Rand) (value reflect.Value, ok bool) {
 			}
 			v.Index(i).Set(elem)
 		}
+	case reflect.Array:
+		for i := 0; i < v.Len(); i++ {
+			elem, ok := Value(concrete.Elem(), rand)
+			if !ok {
+				return reflect.Value{}, false
+			}
+			v.Index(i).Set(elem)
+		}
 	case reflect.String:
 		numChars := rand.Intn(complexSize)
 		codePoints := make([]rune, numChars)
@@ -153,7 +165,7 @@ type Config struct {
 	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)
 }
@@ -237,7 +249,7 @@ func Check(f interface{}, config *Config) (err error) {
 	}
 
 	if fType.NumOut() != 1 {
-		err = SetupError("function returns more than one value.")
+		err = SetupError("function does not return one value")
 		return
 	}
 	if fType.Out(0).Kind() != reflect.Bool {
diff --git a/src/testing/quick/quick_test.go b/src/testing/quick/quick_test.go
index e925ba6..c79f30e 100644
--- a/src/testing/quick/quick_test.go
+++ b/src/testing/quick/quick_test.go
@@ -10,6 +10,12 @@ import (
 	"testing"
 )
 
+func fArray(a [4]byte) [4]byte { return a }
+
+type TestArrayAlias [4]byte
+
+func fArrayAlias(a TestArrayAlias) TestArrayAlias { return a }
+
 func fBool(a bool) bool { return a }
 
 type TestBoolAlias bool
@@ -76,6 +82,18 @@ type TestMapAlias map[int]int
 
 func fMapAlias(a TestMapAlias) TestMapAlias { return a }
 
+func fPtr(a *int) *int {
+	if a == nil {
+		return nil
+	}
+	b := *a
+	return &b
+}
+
+type TestPtrAlias *int
+
+func fPtrAlias(a TestPtrAlias) TestPtrAlias { return a }
+
 func fSlice(a []byte) []byte { return a }
 
 type TestSliceAlias []byte
@@ -135,15 +153,6 @@ type TestUintptrAlias uintptr
 
 func fUintptrAlias(a TestUintptrAlias) TestUintptrAlias { return a }
 
-func fIntptr(a *int) *int {
-	b := *a
-	return &b
-}
-
-type TestIntptrAlias *int
-
-func fIntptrAlias(a TestIntptrAlias) TestIntptrAlias { return a }
-
 func reportError(property string, err error, t *testing.T) {
 	if err != nil {
 		t.Errorf("%s: %s", property, err)
@@ -151,6 +160,8 @@ func reportError(property string, err error, t *testing.T) {
 }
 
 func TestCheckEqual(t *testing.T) {
+	reportError("fArray", CheckEqual(fArray, fArray, nil), t)
+	reportError("fArrayAlias", CheckEqual(fArrayAlias, fArrayAlias, nil), t)
 	reportError("fBool", CheckEqual(fBool, fBool, nil), t)
 	reportError("fBoolAlias", CheckEqual(fBoolAlias, fBoolAlias, nil), t)
 	reportError("fFloat32", CheckEqual(fFloat32, fFloat32, nil), t)
@@ -175,6 +186,8 @@ func TestCheckEqual(t *testing.T) {
 	reportError("fInt32Alias", CheckEqual(fInt32Alias, fInt32Alias, nil), t)
 	reportError("fMap", CheckEqual(fMap, fMap, nil), t)
 	reportError("fMapAlias", CheckEqual(fMapAlias, fMapAlias, nil), t)
+	reportError("fPtr", CheckEqual(fPtr, fPtr, nil), t)
+	reportError("fPtrAlias", CheckEqual(fPtrAlias, fPtrAlias, nil), t)
 	reportError("fSlice", CheckEqual(fSlice, fSlice, nil), t)
 	reportError("fSliceAlias", CheckEqual(fSliceAlias, fSliceAlias, nil), t)
 	reportError("fString", CheckEqual(fString, fString, nil), t)
@@ -193,8 +206,6 @@ func TestCheckEqual(t *testing.T) {
 	reportError("fUintAlias", CheckEqual(fUintAlias, fUintAlias, nil), t)
 	reportError("fUintptr", CheckEqual(fUintptr, fUintptr, nil), t)
 	reportError("fUintptrAlias", CheckEqual(fUintptrAlias, fUintptrAlias, nil), t)
-	reportError("fIntptr", CheckEqual(fIntptr, fIntptr, nil), t)
-	reportError("fIntptrAlias", CheckEqual(fIntptrAlias, fIntptrAlias, nil), t)
 }
 
 // This tests that ArbitraryValue is working by checking that all the arbitrary
@@ -247,3 +258,17 @@ func TestFailure(t *testing.T) {
 		t.Errorf("#3 Error was not a SetupError: %s", err)
 	}
 }
+
+// The following test didn't terminate because nil pointers were not
+// generated.
+// Issue 8818.
+func TestNilPointers(t *testing.T) {
+	type Recursive struct {
+		Next *Recursive
+	}
+
+	f := func(rec Recursive) bool {
+		return true
+	}
+	Check(f, nil)
+}
diff --git a/src/testing/testing.go b/src/testing/testing.go
index e54a3b8..1dcc35e 100644
--- a/src/testing/testing.go
+++ b/src/testing/testing.go
@@ -34,7 +34,7 @@
 // its -bench flag is provided. Benchmarks are run sequentially.
 //
 // For a description of the testing flags, see
-// http://golang.org/cmd/go/#hdr-Description_of_testing_flags.
+// https://golang.org/cmd/go/#hdr-Description_of_testing_flags.
 //
 // A sample benchmark function looks like this:
 //     func BenchmarkHello(b *testing.B) {
@@ -44,7 +44,7 @@
 //     }
 //
 // The benchmark function must run the target code b.N times.
-// During benchark execution, b.N is adjusted until the benchmark function lasts
+// During benchmark execution, b.N is adjusted until the benchmark function lasts
 // long enough to be timed reliably.  The output
 //     BenchmarkHello    10000000    282 ns/op
 // means that the loop ran 10000000 times at a speed of 282 ns per loop.
@@ -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 (
@@ -146,6 +150,7 @@ import (
 	"os"
 	"runtime"
 	"runtime/pprof"
+	"runtime/trace"
 	"strconv"
 	"strings"
 	"sync"
@@ -168,6 +173,7 @@ var (
 
 	// Report as tests are run; default is silent for success.
 	chatty           = flag.Bool("test.v", false, "verbose: print additional output")
+	count            = flag.Uint("test.count", 1, "run tests and benchmarks `n` times")
 	coverProfile     = flag.String("test.coverprofile", "", "write a coverage profile to the named file after execution")
 	match            = flag.String("test.run", "", "regular expression to select tests and examples to run")
 	memProfile       = flag.String("test.memprofile", "", "write a memory profile to the named file after execution")
@@ -175,6 +181,7 @@ var (
 	cpuProfile       = flag.String("test.cpuprofile", "", "write a cpu profile to the named file during execution")
 	blockProfile     = flag.String("test.blockprofile", "", "write a goroutine blocking profile to the named file after execution")
 	blockProfileRate = flag.Int("test.blockprofilerate", 1, "if >= 0, calls runtime.SetBlockProfileRate()")
+	traceFile        = flag.String("test.trace", "", "write an execution trace to the named file after execution")
 	timeout          = flag.Duration("test.timeout", 0, "if positive, sets an aggregate time limit for all tests")
 	cpuListStr       = flag.String("test.cpu", "", "comma-separated list of number of CPUs to use for each test")
 	parallel         = flag.Int("test.parallel", runtime.GOMAXPROCS(0), "maximum test parallelism")
@@ -337,13 +344,15 @@ func (c *common) log(s string) {
 }
 
 // Log formats its arguments using default formatting, analogous to Println,
-// and records the text in the error log. The text will be printed only if
-// the test fails or the -test.v flag is set.
+// and records the text in the error log. For tests, the text will be printed only if
+// the test fails or the -test.v flag is set. For benchmarks, the text is always
+// printed to avoid having performance depend on the value of the -test.v flag.
 func (c *common) Log(args ...interface{}) { c.log(fmt.Sprintln(args...)) }
 
 // Logf formats its arguments according to the format, analogous to Printf,
-// and records the text in the error log. The text will be printed only if
-// the test fails or the -test.v flag is set.
+// and records the text in the error log. For tests, the text will be printed only if
+// the test fails or the -test.v flag is set. For benchmarks, the text is always
+// printed to avoid having performance depend on the value of the -test.v flag.
 func (c *common) Logf(format string, args ...interface{}) { c.log(fmt.Sprintf(format, args...)) }
 
 // Error is equivalent to Log followed by Fail.
@@ -538,9 +547,6 @@ func RunTests(matchString func(pat, str string) (bool, error), tests []InternalT
 				continue
 			}
 			testName := tests[i].Name
-			if procs != 1 {
-				testName = fmt.Sprintf("%s-%d", tests[i].Name, procs)
-			}
 			t := &T{
 				common: common{
 					signal: make(chan interface{}),
@@ -550,7 +556,7 @@ func RunTests(matchString func(pat, str string) (bool, error), tests []InternalT
 			}
 			t.self = t
 			if *chatty {
-				fmt.Printf("=== RUN %s\n", t.name)
+				fmt.Printf("=== RUN   %s\n", t.name)
 			}
 			go tRunner(t, &tests[i])
 			out := (<-t.signal).(*T)
@@ -600,6 +606,19 @@ func before() {
 		}
 		// Could save f so after can call f.Close; not worth the effort.
 	}
+	if *traceFile != "" {
+		f, err := os.Create(toOutputDir(*traceFile))
+		if err != nil {
+			fmt.Fprintf(os.Stderr, "testing: %s", err)
+			return
+		}
+		if err := trace.Start(f); err != nil {
+			fmt.Fprintf(os.Stderr, "testing: can't start tracing: %s", err)
+			f.Close()
+			return
+		}
+		// Could save f so after can call f.Close; not worth the effort.
+	}
 	if *blockProfile != "" && *blockProfileRate >= 0 {
 		runtime.SetBlockProfileRate(*blockProfileRate)
 	}
@@ -614,6 +633,9 @@ func after() {
 	if *cpuProfile != "" {
 		pprof.StopCPUProfile() // flushes profile to disk
 	}
+	if *traceFile != "" {
+		trace.Stop() // flushes trace to disk
+	}
 	if *memProfile != "" {
 		f, err := os.Create(toOutputDir(*memProfile))
 		if err != nil {
@@ -701,9 +723,13 @@ func parseCpuList() {
 			fmt.Fprintf(os.Stderr, "testing: invalid value %q for -test.cpu\n", val)
 			os.Exit(1)
 		}
-		cpuList = append(cpuList, cpu)
+		for i := uint(0); i < *count; i++ {
+			cpuList = append(cpuList, cpu)
+		}
 	}
 	if cpuList == nil {
-		cpuList = append(cpuList, runtime.GOMAXPROCS(-1))
+		for i := uint(0); i < *count; i++ {
+			cpuList = append(cpuList, runtime.GOMAXPROCS(-1))
+		}
 	}
 }
diff --git a/src/text/scanner/example_test.go b/src/text/scanner/example_test.go
new file mode 100644
index 0000000..1011459
--- /dev/null
+++ b/src/text/scanner/example_test.go
@@ -0,0 +1,38 @@
+// 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 scanner_test
+
+import (
+	"fmt"
+	"strings"
+	"text/scanner"
+)
+
+func Example() {
+	const src = `
+	// This is scanned code.
+	if a > 10 {
+		someParsable = text
+	}`
+	var s scanner.Scanner
+	s.Init(strings.NewReader(src))
+	var tok rune
+	for tok != scanner.EOF {
+		tok = s.Scan()
+		fmt.Println("At position", s.Pos(), ":", s.TokenText())
+	}
+
+	// Output:
+	// At position 3:4 : if
+	// At position 3:6 : a
+	// At position 3:8 : >
+	// At position 3:11 : 10
+	// At position 3:13 : {
+	// At position 4:15 : someParsable
+	// At position 4:17 : =
+	// At position 4:22 : text
+	// At position 5:3 : }
+	// At position 5:3 :
+}
diff --git a/src/text/scanner/scanner.go b/src/text/scanner/scanner.go
index 5199ee4..3ab01ed 100644
--- a/src/text/scanner/scanner.go
+++ b/src/text/scanner/scanner.go
@@ -12,17 +12,6 @@
 // literals as defined by the Go language specification.  It may be
 // customized to recognize only a subset of those literals and to recognize
 // different identifier and white space characters.
-//
-// Basic usage pattern:
-//
-//	var s scanner.Scanner
-//	s.Init(src)
-//	tok := s.Scan()
-//	for tok != scanner.EOF {
-//		// do something with tok
-//		tok = s.Scan()
-//	}
-//
 package scanner
 
 import (
@@ -43,7 +32,7 @@ type Position struct {
 	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 +197,7 @@ func (s *Scanner) Init(src io.Reader) *Scanner {
 	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
@@ -314,7 +303,9 @@ func (s *Scanner) Next() rune {
 	s.tokPos = -1 // don't collect token text
 	s.Line = 0    // invalidate token position
 	ch := s.Peek()
-	s.ch = s.next()
+	if ch != EOF {
+		s.ch = s.next()
+	}
 	return ch
 }
 
@@ -322,7 +313,7 @@ func (s *Scanner) Next() rune {
 // 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' {
@@ -597,6 +588,8 @@ redo:
 		}
 	default:
 		switch ch {
+		case EOF:
+			break
 		case '"':
 			if s.Mode&ScanStrings != 0 {
 				s.scanString('"')
diff --git a/src/text/scanner/scanner_test.go b/src/text/scanner/scanner_test.go
index 702fac2..798bed7 100644
--- a/src/text/scanner/scanner_test.go
+++ b/src/text/scanner/scanner_test.go
@@ -616,3 +616,52 @@ func TestPos(t *testing.T) {
 		t.Errorf("%d errors", s.ErrorCount)
 	}
 }
+
+type countReader int
+
+func (r *countReader) Read([]byte) (int, error) {
+	*r++
+	return 0, io.EOF
+}
+
+func TestNextEOFHandling(t *testing.T) {
+	var r countReader
+
+	// corner case: empty source
+	s := new(Scanner).Init(&r)
+
+	tok := s.Next()
+	if tok != EOF {
+		t.Error("1) EOF not reported")
+	}
+
+	tok = s.Peek()
+	if tok != EOF {
+		t.Error("2) EOF not reported")
+	}
+
+	if r != 1 {
+		t.Errorf("scanner called Read %d times, not once", r)
+	}
+}
+
+func TestScanEOFHandling(t *testing.T) {
+	var r countReader
+
+	// corner case: empty source
+	s := new(Scanner).Init(&r)
+
+	tok := s.Scan()
+	if tok != EOF {
+		t.Error("1) EOF not reported")
+	}
+
+	tok = s.Peek()
+	if tok != EOF {
+		t.Error("2) EOF not reported")
+	}
+
+	if r != 1 {
+		t.Errorf("scanner called Read %d times, not once", r)
+	}
+}
diff --git a/src/text/template/doc.go b/src/text/template/doc.go
index 223c595..0ce63f6 100644
--- a/src/text/template/doc.go
+++ b/src/text/template/doc.go
@@ -18,7 +18,7 @@ structure as execution proceeds.
 The input text for a template is UTF-8-encoded text in any format.
 "Actions"--data evaluations or control structures--are delimited by
 "{{" and "}}"; all text outside actions is copied to the output unchanged.
-Actions may not span newlines, although comments can.
+Except for raw strings, actions may not span newlines, although comments can.
 
 Once parsed, a template may be executed safely in parallel.
 
@@ -106,7 +106,7 @@ An argument is a simple value, denoted by one of the following.
 
 	- A boolean, string, character, integer, floating-point, imaginary
 	  or complex constant in Go syntax. These behave like Go's untyped
-	  constants, although raw strings may not span newlines.
+	  constants.
 	- The keyword nil, representing an untyped Go nil.
 	- The character '.' (period):
 		.
diff --git a/src/text/template/exec.go b/src/text/template/exec.go
index b00e10c..daba788 100644
--- a/src/text/template/exec.go
+++ b/src/text/template/exec.go
@@ -113,7 +113,10 @@ func errRecover(errp *error) {
 // the output writer.
 // A template may be executed safely in parallel.
 func (t *Template) ExecuteTemplate(wr io.Writer, name string, data interface{}) error {
-	tmpl := t.tmpl[name]
+	var tmpl *Template
+	if t.common != nil {
+		tmpl = t.tmpl[name]
+	}
 	if tmpl == nil {
 		return fmt.Errorf("template: no template %q associated with template %q", name, t.name)
 	}
@@ -134,26 +137,36 @@ func (t *Template) Execute(wr io.Writer, data interface{}) (err error) {
 		wr:   wr,
 		vars: []variable{{"$", value}},
 	}
-	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)
+		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
 		}
-		var s string
 		if b.Len() > 0 {
-			s = "; defined templates are: " + b.String()
+			b.WriteString(", ")
 		}
-		state.errorf("%q is an incomplete or empty template%s", t.Name(), s)
+		fmt.Fprintf(&b, "%q", name)
 	}
-	state.walk(value, t.Root)
-	return
+	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,
@@ -418,11 +431,14 @@ func (s *state) evalFieldNode(dot reflect.Value, field *parse.FieldNode, args []
 
 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)
 }
 
@@ -505,7 +521,18 @@ func (s *state) evalField(dot reflect.Value, fieldName string, node parse.Node,
 			if hasArgs {
 				s.errorf("%s is not a method but has arguments", fieldName)
 			}
-			return receiver.MapIndex(nameVal)
+			result := receiver.MapIndex(nameVal)
+			if !result.IsValid() {
+				switch s.tmpl.option.missingKey {
+				case mapInvalid:
+					// Just use the invalid value.
+				case mapZeroValue:
+					result = reflect.Zero(receiver.Type().Elem())
+				case mapError:
+					s.errorf("map has no entry for key %q", fieldName)
+				}
+			}
+			return result
 		}
 	}
 	s.errorf("can't evaluate field %s in type %s", fieldName, typ)
@@ -560,7 +587,15 @@ func (s *state) evalCall(dot, fun reflect.Value, node parse.Node, name string, a
 	if final.IsValid() {
 		t := typ.In(typ.NumIn() - 1)
 		if typ.IsVariadic() {
-			t = t.Elem()
+			if numIn-1 < numFixed {
+				// The added final argument corresponds to a fixed parameter of the function.
+				// Validate against the type of the actual parameter.
+				t = typ.In(numIn - 1)
+			} else {
+				// The added final argument corresponds to the variadic part.
+				// Validate against the type of the elements of the variadic slice.
+				t = t.Elem()
+			}
 		}
 		argv[i] = s.validateType(final, t)
 	}
@@ -635,7 +670,7 @@ func (s *state) evalArg(dot reflect.Value, typ reflect.Type, n parse.Node) refle
 	case *parse.PipeNode:
 		return s.validateType(s.evalPipeline(dot, arg), typ)
 	case *parse.IdentifierNode:
-		return s.evalFunction(dot, arg, arg, nil, zero)
+		return s.validateType(s.evalFunction(dot, arg, arg, nil, zero), typ)
 	case *parse.ChainNode:
 		return s.validateType(s.evalChainNode(dot, arg, nil, zero), typ)
 	}
diff --git a/src/text/template/exec_test.go b/src/text/template/exec_test.go
index 69c213e..ba0e434 100644
--- a/src/text/template/exec_test.go
+++ b/src/text/template/exec_test.go
@@ -527,6 +527,24 @@ var execTests = []execTest{
 	{"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 nil or literal values in field chains.
+	{"bug14a", "{{(nil).True}}", "", tVal, false},
+	{"bug14b", "{{$x := nil}}{{$x.anything}}", "", tVal, false},
+	{"bug14c", `{{$x := (1.0)}}{{$y := ("hello")}}{{$x.anything}}{{$y.true}}`, "", tVal, false},
+	// Didn't call validateType on function results. Issue 10800.
+	{"bug15", "{{valueString returnInt}}", "", tVal, false},
+	// Variadic function corner cases. Issue 10946.
+	{"bug16a", "{{true|printf}}", "", tVal, false},
+	{"bug16b", "{{1|printf}}", "", tVal, false},
+	{"bug16c", "{{1.1|printf}}", "", tVal, false},
+	{"bug16d", "{{'x'|printf}}", "", tVal, false},
+	{"bug16e", "{{0i|printf}}", "", tVal, false},
+	{"bug16f", "{{true|twoArgs \"xxx\"}}", "", tVal, false},
+	{"bug16g", "{{\"aaa\" |twoArgs \"bbb\"}}", "twoArgs=bbbaaa", tVal, true},
+	{"bug16h", "{{1|oneArg}}", "", tVal, false},
+	{"bug16i", "{{\"aaa\"|oneArg}}", "oneArg=aaa", tVal, true},
+	{"bug16j", "{{1+2i|printf \"%v\"}}", "(1+2i)", tVal, true},
+	{"bug16k", "{{\"aaa\"|printf }}", "aaa", tVal, true},
 }
 
 func zeroArgs() string {
@@ -537,6 +555,10 @@ func oneArg(a string) string {
 	return "oneArg=" + a
 }
 
+func twoArgs(a, b string) string {
+	return "twoArgs=" + a + b
+}
+
 func dddArg(a int, b ...string) string {
 	return fmt.Sprintln(a, b)
 }
@@ -566,6 +588,11 @@ func valueString(v string) string {
 	return "value is ignored"
 }
 
+// returnInt returns an int
+func returnInt() int {
+	return 7
+}
+
 func add(args ...int) int {
 	sum := 0
 	for _, x := range args {
@@ -607,7 +634,9 @@ func testExecute(execTests []execTest, template *Template, t *testing.T) {
 		"makemap":     makemap,
 		"mapOfThree":  mapOfThree,
 		"oneArg":      oneArg,
+		"returnInt":   returnInt,
 		"stringer":    stringer,
+		"twoArgs":     twoArgs,
 		"typeOf":      typeOf,
 		"valueString": valueString,
 		"vfunc":       vfunc,
@@ -853,7 +882,13 @@ func TestTree(t *testing.T) {
 
 func TestExecuteOnNewTemplate(t *testing.T) {
 	// This is issue 3872.
-	_ = New("Name").Templates()
+	New("Name").Templates()
+	// This is issue 11379.
+	new(Template).Templates()
+	new(Template).Parse("")
+	new(Template).New("abc").Parse("")
+	new(Template).Execute(nil, nil)                // returns an error (but does not crash)
+	new(Template).ExecuteTemplate(nil, "XXX", nil) // returns an error (but does not crash)
 }
 
 const testTemplates = `{{define "one"}}one{{end}}{{define "two"}}two{{end}}`
@@ -1042,3 +1077,67 @@ func TestComparison(t *testing.T) {
 		}
 	}
 }
+
+func TestMissingMapKey(t *testing.T) {
+	data := map[string]int{
+		"x": 99,
+	}
+	tmpl, err := New("t1").Parse("{{.x}} {{.y}}")
+	if err != nil {
+		t.Fatal(err)
+	}
+	var b bytes.Buffer
+	// By default, just get "<no value>"
+	err = tmpl.Execute(&b, data)
+	if err != nil {
+		t.Fatal(err)
+	}
+	want := "99 <no value>"
+	got := b.String()
+	if got != want {
+		t.Errorf("got %q; expected %q", got, want)
+	}
+	// Same if we set the option explicitly to the default.
+	tmpl.Option("missingkey=default")
+	b.Reset()
+	err = tmpl.Execute(&b, data)
+	if err != nil {
+		t.Fatal("default:", err)
+	}
+	want = "99 <no value>"
+	got = b.String()
+	if got != want {
+		t.Errorf("got %q; expected %q", got, want)
+	}
+	// Next we ask for a zero value
+	tmpl.Option("missingkey=zero")
+	b.Reset()
+	err = tmpl.Execute(&b, data)
+	if err != nil {
+		t.Fatal("zero:", err)
+	}
+	want = "99 0"
+	got = b.String()
+	if got != want {
+		t.Errorf("got %q; expected %q", got, want)
+	}
+	// Now we ask for an error.
+	tmpl.Option("missingkey=error")
+	err = tmpl.Execute(&b, data)
+	if err == nil {
+		t.Errorf("expected error; got none")
+	}
+}
+
+// Test that the error message for multiline unterminated string
+// refers to the line number of the opening quote.
+func TestUnterminatedStringError(t *testing.T) {
+	_, err := New("X").Parse("hello\n\n{{`unterminated\n\n\n\n}}\n some more\n\n")
+	if err == nil {
+		t.Fatal("expected error")
+	}
+	str := err.Error()
+	if !strings.Contains(str, "X:3: unexpected unterminated raw quoted strin") {
+		t.Fatalf("unexpected error: %s", str)
+	}
+}
diff --git a/src/text/template/funcs.go b/src/text/template/funcs.go
index 39ee5ed..ccd0dfc 100644
--- a/src/text/template/funcs.go
+++ b/src/text/template/funcs.go
@@ -92,6 +92,8 @@ func goodFunc(typ reflect.Type) bool {
 // findFunction looks for a function in the template, and global map.
 func findFunction(name string, tmpl *Template) (reflect.Value, bool) {
 	if tmpl != nil && tmpl.common != nil {
+		tmpl.muFuncs.RLock()
+		defer tmpl.muFuncs.RUnlock()
 		if fn := tmpl.execFuncs[name]; fn.IsValid() {
 			return fn, true
 		}
@@ -590,7 +592,7 @@ func evalArgs(args []interface{}) string {
 			a, ok := printableValue(reflect.ValueOf(arg))
 			if ok {
 				args[i] = a
-			} // else left fmt do its thing
+			} // else let fmt do its thing
 		}
 		s = fmt.Sprint(args...)
 	}
diff --git a/src/text/template/helper.go b/src/text/template/helper.go
index 3636fb5..787ca62 100644
--- a/src/text/template/helper.go
+++ b/src/text/template/helper.go
@@ -26,8 +26,8 @@ func Must(t *Template, err error) *Template {
 }
 
 // ParseFiles creates a new Template and parses the template definitions from
-// the named files. The returned template's name will have the (base) name and
-// (parsed) contents of the first file. There must be at least one file.
+// the named files. The returned template's name will have the base name and
+// parsed contents of the first file. There must be at least one file.
 // If an error occurs, parsing stops and the returned *Template is nil.
 func ParseFiles(filenames ...string) (*Template, error) {
 	return parseFiles(nil, filenames...)
@@ -36,7 +36,13 @@ func ParseFiles(filenames ...string) (*Template, error) {
 // ParseFiles parses the named files and associates the resulting templates with
 // t. If an error occurs, parsing stops and the returned template is nil;
 // otherwise it is t. There must be at least one file.
+// Since the templates created by ParseFiles are named by the base
+// names of the argument files, t should usually have the name of one
+// of the (base) names of the files. If it does not, depending on t's
+// contents before calling ParseFiles, t.Execute may fail. In that
+// case use t.ExecuteTemplate to execute a valid template.
 func (t *Template) ParseFiles(filenames ...string) (*Template, error) {
+	t.init()
 	return parseFiles(t, filenames...)
 }
 
@@ -92,6 +98,7 @@ func ParseGlob(pattern string) (*Template, error) {
 // equivalent to calling t.ParseFiles with the list of files matched by the
 // pattern.
 func (t *Template) ParseGlob(pattern string) (*Template, error) {
+	t.init()
 	return parseGlob(t, pattern)
 }
 
diff --git a/src/text/template/multi_test.go b/src/text/template/multi_test.go
index e4e8048..ea01875 100644
--- a/src/text/template/multi_test.go
+++ b/src/text/template/multi_test.go
@@ -290,3 +290,76 @@ func TestRedefinition(t *testing.T) {
 		t.Fatalf("expected redefinition error; got %v", err)
 	}
 }
+
+// Issue 10879
+func TestEmptyTemplateCloneCrash(t *testing.T) {
+	t1 := New("base")
+	t1.Clone() // used to panic
+}
+
+// Issue 10910, 10926
+func TestTemplateLookUp(t *testing.T) {
+	t1 := New("foo")
+	if t1.Lookup("foo") != nil {
+		t.Error("Lookup returned non-nil value for undefined template foo")
+	}
+	t1.New("bar")
+	if t1.Lookup("bar") != nil {
+		t.Error("Lookup returned non-nil value for undefined template bar")
+	}
+	t1.Parse(`{{define "foo"}}test{{end}}`)
+	if t1.Lookup("foo") == nil {
+		t.Error("Lookup returned nil value for defined template")
+	}
+}
+
+func TestNew(t *testing.T) {
+	// template with same name already exists
+	t1, _ := New("test").Parse(`{{define "test"}}foo{{end}}`)
+	t2 := t1.New("test")
+
+	if t1.common != t2.common {
+		t.Errorf("t1 & t2 didn't share common struct; got %v != %v", t1.common, t2.common)
+	}
+	if t1.Tree == nil {
+		t.Error("defined template got nil Tree")
+	}
+	if t2.Tree != nil {
+		t.Error("undefined template got non-nil Tree")
+	}
+
+	containsT1 := false
+	for _, tmpl := range t1.Templates() {
+		if tmpl == t2 {
+			t.Error("Templates included undefined template")
+		}
+		if tmpl == t1 {
+			containsT1 = true
+		}
+	}
+	if !containsT1 {
+		t.Error("Templates didn't include defined template")
+	}
+}
+
+func TestParse(t *testing.T) {
+	// In multiple calls to Parse with the same receiver template, only one call
+	// can contain text other than space, comments, and template definitions
+	var err error
+	t1 := New("test")
+	if _, err := t1.Parse(`{{define "test"}}{{end}}`); err != nil {
+		t.Fatalf("parsing test: %s", err)
+	}
+	if _, err := t1.Parse(`{{define "test"}}{{/* this is a comment */}}{{end}}`); err != nil {
+		t.Fatalf("parsing test: %s", err)
+	}
+	if _, err := t1.Parse(`{{define "test"}}foo{{end}}`); err != nil {
+		t.Fatalf("parsing test: %s", err)
+	}
+	if _, err = t1.Parse(`{{define "test"}}foo{{end}}`); err == nil {
+		t.Fatal("no error from redefining a template")
+	}
+	if !strings.Contains(err.Error(), "redefinition") {
+		t.Fatalf("expected redefinition error; got %v", err)
+	}
+}
diff --git a/src/text/template/option.go b/src/text/template/option.go
new file mode 100644
index 0000000..addce2d
--- /dev/null
+++ b/src/text/template/option.go
@@ -0,0 +1,74 @@
+// 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 contains the code to handle template options.
+
+package template
+
+import "strings"
+
+// missingKeyAction defines how to respond to indexing a map with a key that is not present.
+type missingKeyAction int
+
+const (
+	mapInvalid   missingKeyAction = iota // Return an invalid reflect.Value.
+	mapZeroValue                         // Return the zero value for the map element.
+	mapError                             // Error out
+)
+
+type option struct {
+	missingKey missingKeyAction
+}
+
+// Option sets options for the template. Options are described by
+// strings, either a simple string or "key=value". There can be at
+// most one equals sign in an option string. If the option string
+// is unrecognized or otherwise invalid, Option panics.
+//
+// Known options:
+//
+// missingkey: Control the behavior during execution if a map is
+// indexed with a key that is not present in the map.
+//	"missingkey=default" or "missingkey=invalid"
+//		The default behavior: Do nothing and continue execution.
+//		If printed, the result of the index operation is the string
+//		"<no value>".
+//	"missingkey=zero"
+//		The operation returns the zero value for the map type's element.
+//	"missingkey=error"
+//		Execution stops immediately with an error.
+//
+func (t *Template) Option(opt ...string) *Template {
+	t.init()
+	for _, s := range opt {
+		t.setOption(s)
+	}
+	return t
+}
+
+func (t *Template) setOption(opt string) {
+	if opt == "" {
+		panic("empty option string")
+	}
+	elems := strings.Split(opt, "=")
+	switch len(elems) {
+	case 2:
+		// key=value
+		switch elems[0] {
+		case "missingkey":
+			switch elems[1] {
+			case "invalid", "default":
+				t.option.missingKey = mapInvalid
+				return
+			case "zero":
+				t.option.missingKey = mapZeroValue
+				return
+			case "error":
+				t.option.missingKey = mapError
+				return
+			}
+		}
+	}
+	panic("unrecognized option: " + opt)
+}
diff --git a/src/text/template/parse/lex.go b/src/text/template/parse/lex.go
index 1674aaf..8f9fe1d 100644
--- a/src/text/template/parse/lex.go
+++ b/src/text/template/parse/lex.go
@@ -167,12 +167,20 @@ func (l *lexer) errorf(format string, args ...interface{}) stateFn {
 }
 
 // nextItem returns the next item from the input.
+// Called by the parser, not in the lexing goroutine.
 func (l *lexer) nextItem() item {
 	item := <-l.items
 	l.lastPos = item.pos
 	return item
 }
 
+// drain drains the output so the lexing goroutine will exit.
+// Called by the parser, not in the lexing goroutine.
+func (l *lexer) drain() {
+	for range l.items {
+	}
+}
+
 // lex creates a new scanner for the input string.
 func lex(name, input, left, right string) *lexer {
 	if left == "" {
@@ -197,6 +205,7 @@ func (l *lexer) run() {
 	for l.state = lexText; l.state != nil; {
 		l.state = l.state(l)
 	}
+	close(l.items)
 }
 
 // state functions
@@ -313,14 +322,12 @@ func lexInsideAction(l *lexer) stateFn {
 	case r == '(':
 		l.emit(itemLeftParen)
 		l.parenDepth++
-		return lexInsideAction
 	case r == ')':
 		l.emit(itemRightParen)
 		l.parenDepth--
 		if l.parenDepth < 0 {
 			return l.errorf("unexpected right paren %#U", r)
 		}
-		return lexInsideAction
 	case r <= unicode.MaxASCII && unicode.IsPrint(r):
 		l.emit(itemChar)
 		return lexInsideAction
@@ -525,7 +532,7 @@ func lexRawQuote(l *lexer) stateFn {
 Loop:
 	for {
 		switch l.next() {
-		case eof, '\n':
+		case eof:
 			return l.errorf("unterminated raw quoted string")
 		case '`':
 			break Loop
diff --git a/src/text/template/parse/lex_test.go b/src/text/template/parse/lex_test.go
index d251ccf..be551d8 100644
--- a/src/text/template/parse/lex_test.go
+++ b/src/text/template/parse/lex_test.go
@@ -58,18 +58,20 @@ type lexTest struct {
 }
 
 var (
-	tEOF      = item{itemEOF, 0, ""}
-	tFor      = item{itemIdentifier, 0, "for"}
-	tLeft     = item{itemLeftDelim, 0, "{{"}
-	tLpar     = item{itemLeftParen, 0, "("}
-	tPipe     = item{itemPipe, 0, "|"}
-	tQuote    = item{itemString, 0, `"abc \n\t\" "`}
-	tRange    = item{itemRange, 0, "range"}
-	tRight    = item{itemRightDelim, 0, "}}"}
-	tRpar     = item{itemRightParen, 0, ")"}
-	tSpace    = item{itemSpace, 0, " "}
-	raw       = "`" + `abc\n\t\" ` + "`"
-	tRawQuote = item{itemRawString, 0, raw}
+	tEOF        = item{itemEOF, 0, ""}
+	tFor        = item{itemIdentifier, 0, "for"}
+	tLeft       = item{itemLeftDelim, 0, "{{"}
+	tLpar       = item{itemLeftParen, 0, "("}
+	tPipe       = item{itemPipe, 0, "|"}
+	tQuote      = item{itemString, 0, `"abc \n\t\" "`}
+	tRange      = item{itemRange, 0, "range"}
+	tRight      = item{itemRightDelim, 0, "}}"}
+	tRpar       = item{itemRightParen, 0, ")"}
+	tSpace      = item{itemSpace, 0, " "}
+	raw         = "`" + `abc\n\t\" ` + "`"
+	rawNL       = "`now is{{\n}}the time`" // Contains newline inside raw quote.
+	tRawQuote   = item{itemRawString, 0, raw}
+	tRawQuoteNL = item{itemRawString, 0, rawNL}
 )
 
 var lexTests = []lexTest{
@@ -104,6 +106,7 @@ var lexTests = []lexTest{
 	{"for", `{{for}}`, []item{tLeft, tFor, tRight, tEOF}},
 	{"quote", `{{"abc \n\t\" "}}`, []item{tLeft, tQuote, tRight, tEOF}},
 	{"raw quote", "{{" + raw + "}}", []item{tLeft, tRawQuote, tRight, tEOF}},
+	{"raw quote with newline", "{{" + rawNL + "}}", []item{tLeft, tRawQuoteNL, tRight, tEOF}},
 	{"numbers", "{{1 02 0x14 -7.2i 1e3 +1.2e-4 4.2i 1+2i}}", []item{
 		tLeft,
 		{itemNumber, 0, "1"},
@@ -294,7 +297,7 @@ var lexTests = []lexTest{
 		tLeft,
 		{itemError, 0, "unterminated quoted string"},
 	}},
-	{"unclosed raw quote", "{{`xx\n`}}", []item{
+	{"unclosed raw quote", "{{`xx}}", []item{
 		tLeft,
 		{itemError, 0, "unterminated raw quoted string"},
 	}},
@@ -463,3 +466,31 @@ func TestPos(t *testing.T) {
 		}
 	}
 }
+
+// Test that an error shuts down the lexing goroutine.
+func TestShutdown(t *testing.T) {
+	// We need to duplicate template.Parse here to hold on to the lexer.
+	const text = "erroneous{{define}}{{else}}1234"
+	lexer := lex("foo", text, "{{", "}}")
+	_, err := New("root").parseLexer(lexer, text)
+	if err == nil {
+		t.Fatalf("expected error")
+	}
+	// The error should have drained the input. Therefore, the lexer should be shut down.
+	token, ok := <-lexer.items
+	if ok {
+		t.Fatalf("input was not drained; got %v", token)
+	}
+}
+
+// parseLexer is a local version of parse that lets us pass in the lexer instead of building it.
+// We expect an error, so the tree set and funcs list are explicitly nil.
+func (t *Tree) parseLexer(lex *lexer, text string) (tree *Tree, err error) {
+	defer t.recover(&err)
+	t.ParseName = t.Name
+	t.startParse(nil, lex)
+	t.parse(nil)
+	t.add(nil)
+	t.stopParse()
+	return t, nil
+}
diff --git a/src/text/template/parse/node.go b/src/text/template/parse/node.go
index 55c37f6..55ff46c 100644
--- a/src/text/template/parse/node.go
+++ b/src/text/template/parse/node.go
@@ -145,7 +145,7 @@ type PipeNode struct {
 	NodeType
 	Pos
 	tr   *Tree
-	Line int             // The line number in the input (deprecated; kept for compatibility)
+	Line int             // The line number in the input. Deprecated: Kept for compatibility.
 	Decl []*VariableNode // Variable declarations in lexical order.
 	Cmds []*CommandNode  // The commands in lexical order.
 }
@@ -208,7 +208,7 @@ type ActionNode struct {
 	NodeType
 	Pos
 	tr   *Tree
-	Line int       // The line number in the input (deprecated; kept for compatibility)
+	Line int       // The line number in the input. Deprecated: Kept for compatibility.
 	Pipe *PipeNode // The pipeline in the action.
 }
 
@@ -592,6 +592,11 @@ func (t *Tree) newNumber(pos Pos, text string, typ itemType) (*NumberNode, error
 	} else {
 		f, err := strconv.ParseFloat(text, 64)
 		if err == nil {
+			// If we parsed it as a float but it looks like an integer,
+			// it's a huge number too large to fit in an int. Reject it.
+			if !strings.ContainsAny(text, ".eE") {
+				return nil, fmt.Errorf("integer overflow: %q", text)
+			}
 			n.IsFloat = true
 			n.Float64 = f
 			// If a floating-point extraction succeeded, extract the int if needed.
@@ -696,7 +701,7 @@ type elseNode struct {
 	NodeType
 	Pos
 	tr   *Tree
-	Line int // The line number in the input (deprecated; kept for compatibility)
+	Line int // The line number in the input. Deprecated: Kept for compatibility.
 }
 
 func (t *Tree) newElse(pos Pos, line int) *elseNode {
@@ -724,7 +729,7 @@ type BranchNode struct {
 	NodeType
 	Pos
 	tr       *Tree
-	Line     int       // The line number in the input (deprecated; kept for compatibility)
+	Line     int       // The line number in the input. Deprecated: Kept for compatibility.
 	Pipe     *PipeNode // The pipeline to be evaluated.
 	List     *ListNode // What to execute if the value is non-empty.
 	ElseList *ListNode // What to execute if the value is empty (nil if absent).
@@ -809,7 +814,7 @@ type TemplateNode struct {
 	NodeType
 	Pos
 	tr   *Tree
-	Line int       // The line number in the input (deprecated; kept for compatibility)
+	Line int       // The line number in the input. Deprecated: Kept for compatibility.
 	Name string    // The name of the template (unquoted).
 	Pipe *PipeNode // The command to evaluate as dot for the template.
 }
diff --git a/src/text/template/parse/parse.go b/src/text/template/parse/parse.go
index af33880..88aacd1 100644
--- a/src/text/template/parse/parse.go
+++ b/src/text/template/parse/parse.go
@@ -196,6 +196,7 @@ func (t *Tree) recover(errp *error) {
 			panic(e)
 		}
 		if t != nil {
+			t.lex.drain()
 			t.stopParse()
 		}
 		*errp = e.(error)
@@ -288,11 +289,12 @@ func (t *Tree) parse(treeSet map[string]*Tree) (next Node) {
 			}
 			t.backup2(delim)
 		}
-		n := t.textOrAction()
-		if n.Type() == nodeEnd {
+		switch n := t.textOrAction(); n.Type() {
+		case nodeEnd, nodeElse:
 			t.errorf("unexpected %s", n)
+		default:
+			t.Root.append(n)
 		}
-		t.Root.append(n)
 	}
 	return nil
 }
@@ -411,9 +413,8 @@ func (t *Tree) pipeline(context string) (pipe *PipeNode) {
 	for {
 		switch token := t.nextNonSpace(); token.typ {
 		case itemRightDelim, itemRightParen:
-			if len(pipe.Cmds) == 0 {
-				t.errorf("missing value for %s", context)
-			}
+			// At this point, the pipeline is complete
+			t.checkPipeline(pipe, context)
 			if token.typ == itemRightParen {
 				t.backup()
 			}
@@ -428,6 +429,21 @@ func (t *Tree) pipeline(context string) (pipe *PipeNode) {
 	}
 }
 
+func (t *Tree) checkPipeline(pipe *PipeNode, context string) {
+	// Reject empty pipelines
+	if len(pipe.Cmds) == 0 {
+		t.errorf("missing value for %s", context)
+	}
+	// Only the first command of a pipeline can start with a non executable operand
+	for i, c := range pipe.Cmds[1:] {
+		switch c.Args[0].Type() {
+		case NodeBool, NodeDot, NodeNil, NodeNumber, NodeString:
+			// With A|B|C, pipeline stage 2 is B
+			t.errorf("non executable command in pipeline stage %d", i+2)
+		}
+	}
+}
+
 func (t *Tree) parseControl(allowElseIf bool, context string) (pos Pos, line int, pipe *PipeNode, list, elseList *ListNode) {
 	defer t.popVars(len(t.vars))
 	line = t.lex.lineNumber()
@@ -553,7 +569,7 @@ func (t *Tree) command() *CommandNode {
 			t.backup()
 		case itemPipe:
 		default:
-			t.errorf("unexpected %s in operand; missing space?", token)
+			t.errorf("unexpected %s in operand", token)
 		}
 		break
 	}
@@ -581,12 +597,15 @@ func (t *Tree) operand() Node {
 		// Compatibility with original API: If the term is of type NodeField
 		// or NodeVariable, just put more fields on the original.
 		// Otherwise, keep the Chain node.
-		// TODO: Switch to Chains always when we can.
+		// Obvious parsing errors involving literal values are detected here.
+		// More complex error cases will have to be handled at execution time.
 		switch node.Type() {
 		case NodeField:
 			node = t.newField(chain.Position(), chain.String())
 		case NodeVariable:
 			node = t.newVariable(chain.Position(), chain.String())
+		case NodeBool, NodeString, NodeNumber, NodeNil, NodeDot:
+			t.errorf("unexpected . after term %q", node.String())
 		default:
 			node = chain
 		}
diff --git a/src/text/template/parse/parse_test.go b/src/text/template/parse/parse_test.go
index 4a504fa..200d50c 100644
--- a/src/text/template/parse/parse_test.go
+++ b/src/text/template/parse/parse_test.go
@@ -69,6 +69,7 @@ var numberTests = []numberTest{
 	{text: "1+2."},
 	{text: "'x"},
 	{text: "'xx'"},
+	{text: "'433937734937734969526500969526500'"}, // Integer too large - issue 10634.
 	// Issue 8622 - 0xe parsed as floating point. Very embarrassing.
 	{"0xef", true, true, true, false, 0xef, 0xef, 0xef, 0},
 }
@@ -230,6 +231,9 @@ var parseTests = []parseTest{
 	// Errors.
 	{"unclosed action", "hello{{range", hasError, ""},
 	{"unmatched end", "{{end}}", hasError, ""},
+	{"unmatched else", "{{else}}", hasError, ""},
+	{"unmatched else after if", "{{if .X}}hello{{end}}{{else}}", hasError, ""},
+	{"multiple else", "{{if .X}}1{{else}}2{{else}}3{{end}}", hasError, ""},
 	{"missing end", "hello{{range .x}}", hasError, ""},
 	{"missing end after else", "hello{{range .x}}{{else}}", hasError, ""},
 	{"undefined function", "hello{{undefined}}", hasError, ""},
@@ -257,6 +261,22 @@ var parseTests = []parseTest{
 	{"bug1a", "{{$x:=.}}{{$x!2}}", hasError, ""},                     // ! is just illegal here.
 	{"bug1b", "{{$x:=.}}{{$x+2}}", hasError, ""},                     // $x+2 should not parse as ($x) (+2).
 	{"bug1c", "{{$x:=.}}{{$x +2}}", noError, "{{$x := .}}{{$x +2}}"}, // It's OK with a space.
+	// dot following a literal value
+	{"dot after integer", "{{1.E}}", hasError, ""},
+	{"dot after float", "{{0.1.E}}", hasError, ""},
+	{"dot after boolean", "{{true.E}}", hasError, ""},
+	{"dot after char", "{{'a'.any}}", hasError, ""},
+	{"dot after string", `{{"hello".guys}}`, hasError, ""},
+	{"dot after dot", "{{..E}}", hasError, ""},
+	{"dot after nil", "{{nil.E}}", hasError, ""},
+	// Wrong pipeline
+	{"wrong pipeline dot", "{{12|.}}", hasError, ""},
+	{"wrong pipeline number", "{{.|12|printf}}", hasError, ""},
+	{"wrong pipeline string", "{{.|printf|\"error\"}}", hasError, ""},
+	{"wrong pipeline char", "{{12|printf|'e'}}", hasError, ""},
+	{"wrong pipeline boolean", "{{.|true}}", hasError, ""},
+	{"wrong pipeline nil", "{{'c'|nil}}", hasError, ""},
+	{"empty pipeline", `{{printf "%d" ( ) }}`, hasError, ""},
 }
 
 var builtins = map[string]interface{}{
@@ -375,7 +395,7 @@ var errorTests = []parseTest{
 		hasError, `unexpected ")"`},
 	{"space",
 		"{{`x`3}}",
-		hasError, `missing space?`},
+		hasError, `in operand`},
 	{"idchar",
 		"{{a#}}",
 		hasError, `'#'`},
@@ -407,6 +427,15 @@ var errorTests = []parseTest{
 	{"undefvar",
 		"{{$a}}",
 		hasError, `undefined variable`},
+	{"wrongdot",
+		"{{true.any}}",
+		hasError, `unexpected . after term`},
+	{"wrongpipeline",
+		"{{12|false}}",
+		hasError, `non executable command in pipeline`},
+	{"emptypipeline",
+		`{{ ( ) }}`,
+		hasError, `missing value for parenthesized pipeline`},
 }
 
 func TestErrors(t *testing.T) {
diff --git a/src/text/template/template.go b/src/text/template/template.go
index 249d0cb..3e80982 100644
--- a/src/text/template/template.go
+++ b/src/text/template/template.go
@@ -7,15 +7,18 @@ package template
 import (
 	"fmt"
 	"reflect"
+	"sync"
 	"text/template/parse"
 )
 
 // common holds the information shared by related templates.
 type common struct {
-	tmpl map[string]*Template
+	tmpl   map[string]*Template // Map from name to defined templates.
+	option option
 	// We use two maps, one for parsing and one for execution.
 	// This separation makes the API cleaner since it doesn't
 	// expose reflection to the client.
+	muFuncs    sync.RWMutex // protects parseFuncs and execFuncs
 	parseFuncs FuncMap
 	execFuncs  map[string]reflect.Value
 }
@@ -31,11 +34,13 @@ type Template struct {
 	rightDelim string
 }
 
-// New allocates a new template with the given name.
+// New allocates a new, undefined template with the given name.
 func New(name string) *Template {
-	return &Template{
+	t := &Template{
 		name: name,
 	}
+	t.init()
+	return t
 }
 
 // Name returns the name of the template.
@@ -43,25 +48,28 @@ func (t *Template) Name() string {
 	return t.name
 }
 
-// New allocates a new template associated with the given one and with the same
+// New allocates a new, undefined template associated with the given one and with the same
 // delimiters. The association, which is transitive, allows one template to
 // invoke another with a {{template}} action.
 func (t *Template) New(name string) *Template {
 	t.init()
-	return &Template{
+	nt := &Template{
 		name:       name,
 		common:     t.common,
 		leftDelim:  t.leftDelim,
 		rightDelim: t.rightDelim,
 	}
+	return nt
 }
 
+// init guarantees that t has a valid common structure.
 func (t *Template) init() {
 	if t.common == nil {
-		t.common = new(common)
-		t.tmpl = make(map[string]*Template)
-		t.parseFuncs = make(FuncMap)
-		t.execFuncs = make(map[string]reflect.Value)
+		c := new(common)
+		c.tmpl = make(map[string]*Template)
+		c.parseFuncs = make(FuncMap)
+		c.execFuncs = make(map[string]reflect.Value)
+		t.common = c
 	}
 }
 
@@ -74,15 +82,20 @@ func (t *Template) init() {
 func (t *Template) Clone() (*Template, error) {
 	nt := t.copy(nil)
 	nt.init()
-	nt.tmpl[t.name] = nt
+	if t.common == nil {
+		return nt, nil
+	}
 	for k, v := range t.tmpl {
-		if k == t.name { // Already installed.
+		if k == t.name {
+			nt.tmpl[t.name] = nt
 			continue
 		}
 		// The associated templates share nt's common structure.
 		tmpl := v.copy(nt.common)
 		nt.tmpl[k] = tmpl
 	}
+	t.muFuncs.RLock()
+	defer t.muFuncs.RUnlock()
 	for k, v := range t.parseFuncs {
 		nt.parseFuncs[k] = v
 	}
@@ -102,20 +115,27 @@ func (t *Template) copy(c *common) *Template {
 	return nt
 }
 
-// AddParseTree creates a new template with the name and parse tree
-// and associates it with t.
+// AddParseTree adds parse tree for template with given name and associates it with t.
+// If the template does not already exist, it will create a new one.
+// It is an error to reuse a name except to overwrite an empty template.
 func (t *Template) AddParseTree(name string, tree *parse.Tree) (*Template, error) {
-	if t.common != nil && t.tmpl[name] != nil {
-		return nil, fmt.Errorf("template: redefinition of template %q", name)
+	t.init()
+	// If the name is the name of this template, overwrite this template.
+	// The associate method checks it's not a redefinition.
+	nt := t
+	if name != t.name {
+		nt = t.New(name)
+	}
+	// Even if nt == t, we need to install it in the common.tmpl map.
+	if replace, err := t.associate(nt, tree); err != nil {
+		return nil, err
+	} else if replace {
+		nt.Tree = tree
 	}
-	nt := t.New(name)
-	nt.Tree = tree
-	t.tmpl[name] = nt
 	return nt, nil
 }
 
-// Templates returns a slice of the templates associated with t, including t
-// itself.
+// Templates returns a slice of defined templates associated with t.
 func (t *Template) Templates() []*Template {
 	if t.common == nil {
 		return nil
@@ -134,6 +154,7 @@ func (t *Template) Templates() []*Template {
 // corresponding default: {{ or }}.
 // The return value is the template, so calls can be chained.
 func (t *Template) Delims(left, right string) *Template {
+	t.init()
 	t.leftDelim = left
 	t.rightDelim = right
 	return t
@@ -145,13 +166,15 @@ func (t *Template) Delims(left, right string) *Template {
 // value is the template, so calls can be chained.
 func (t *Template) Funcs(funcMap FuncMap) *Template {
 	t.init()
+	t.muFuncs.Lock()
+	defer t.muFuncs.Unlock()
 	addValueFuncs(t.execFuncs, funcMap)
 	addFuncs(t.parseFuncs, funcMap)
 	return t
 }
 
-// Lookup returns the template with the given name that is associated with t,
-// or nil if there is no such template.
+// Lookup returns the template with the given name that is associated with t.
+// It returns nil if there is no such template or the template has no definition.
 func (t *Template) Lookup(name string) *Template {
 	if t.common == nil {
 		return nil
@@ -159,7 +182,7 @@ func (t *Template) Lookup(name string) *Template {
 	return t.tmpl[name]
 }
 
-// Parse parses a string into a template. Nested template definitions will be
+// Parse defines the template by parsing the text. Nested template definitions will be
 // associated with the top-level template t. Parse may be called multiple times
 // to parse definitions of templates to associate with t. It is an error if a
 // resulting template is non-empty (contains content other than template
@@ -168,26 +191,17 @@ func (t *Template) Lookup(name string) *Template {
 // can contain text other than space, comments, and template definitions.)
 func (t *Template) Parse(text string) (*Template, error) {
 	t.init()
+	t.muFuncs.RLock()
 	trees, err := parse.Parse(t.name, text, t.leftDelim, t.rightDelim, t.parseFuncs, builtins)
+	t.muFuncs.RUnlock()
 	if err != nil {
 		return nil, err
 	}
 	// Add the newly parsed trees, including the one for t, into our common structure.
 	for name, tree := range trees {
-		// If the name we parsed is the name of this template, overwrite this template.
-		// The associate method checks it's not a redefinition.
-		tmpl := t
-		if name != t.name {
-			tmpl = t.New(name)
-		}
-		// Even if t == tmpl, we need to install it in the common.tmpl map.
-		if replace, err := t.associate(tmpl, tree); err != nil {
+		if _, err := t.AddParseTree(name, tree); err != nil {
 			return nil, err
-		} else if replace {
-			tmpl.Tree = tree
 		}
-		tmpl.leftDelim = t.leftDelim
-		tmpl.rightDelim = t.rightDelim
 	}
 	return t, nil
 }
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 ExampleDate() {
 }
 
 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/export_windows_test.go b/src/time/export_windows_test.go
index 7e689b8..6fd4509 100644
--- a/src/time/export_windows_test.go
+++ b/src/time/export_windows_test.go
@@ -8,3 +8,7 @@ func ForceAusForTesting() {
 	ResetLocalOnceForTest()
 	localOnce.Do(initAusTestingZone)
 }
+
+func ToEnglishName(stdname, dstname string) (string, error) {
+	return toEnglishName(stdname, dstname)
+}
diff --git a/src/time/format.go b/src/time/format.go
index 04e79f3..873d3ff 100644
--- a/src/time/format.go
+++ b/src/time/format.go
@@ -39,6 +39,9 @@ import "errors"
 // offset for the UTC zone.  Thus:
 //	Z0700  Z or ±hhmm
 //	Z07:00 Z or ±hh:mm
+//
+// The executable example for time.Format demonstrates the working
+// of the layout string in detail and is a good reference.
 const (
 	ANSIC       = "Mon Jan _2 15:04:05 2006"
 	UnixDate    = "Mon Jan _2 15:04:05 MST 2006"
@@ -288,7 +291,7 @@ var longMonthNames = []string{
 	"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++ {
@@ -315,36 +318,34 @@ func lookup(tab []string, val string) (int, string, error) {
 	return -1, val, errBad
 }
 
-// appendUint appends the decimal form of x to b and returns the result.
-// If x is a single-digit number and pad != 0, appendUint inserts the pad byte
-// before the digit.
+// appendInt appends the decimal form of x to b and returns the result.
+// If the decimal form (excluding sign) is shorter than width, the result is padded with leading 0's.
 // Duplicates functionality in strconv, but avoids dependency.
-func appendUint(b []byte, x uint, pad byte) []byte {
-	if x < 10 {
-		if pad != 0 {
-			b = append(b, pad)
-		}
-		return append(b, byte('0'+x))
-	}
-	if x < 100 {
-		b = append(b, byte('0'+x/10))
-		b = append(b, byte('0'+x%10))
-		return b
+func appendInt(b []byte, x int, width int) []byte {
+	u := uint(x)
+	if x < 0 {
+		b = append(b, '-')
+		u = uint(-x)
 	}
 
-	var buf [32]byte
-	n := len(buf)
-	if x == 0 {
-		return append(b, '0')
+	// Assemble decimal in reverse order.
+	var buf [20]byte
+	i := len(buf)
+	for u >= 10 {
+		i--
+		q := u / 10
+		buf[i] = byte('0' + u - q*10)
+		u = q
 	}
-	for x >= 10 {
-		n--
-		buf[n] = byte(x%10 + '0')
-		x /= 10
+	i--
+	buf[i] = byte('0' + u)
+
+	// Add 0-padding.
+	for w := len(buf) - i; w < width; w++ {
+		b = append(b, '0')
 	}
-	n--
-	buf[n] = byte(x + '0')
-	return append(b, buf[n:]...)
+
+	return append(b, buf[i:]...)
 }
 
 // Never printed, just needs to be non-nil for return by atoi.
@@ -407,11 +408,32 @@ func (t Time) String() string {
 // would be displayed if it were the value; it serves as an example of the
 // desired output. The same display rules will then be applied to the time
 // value.
+//
+// A fractional second is represented by adding a period and zeros
+// to the end of the seconds section of layout string, as in "15:04:05.000"
+// to format a time stamp with millisecond precision.
+//
 // 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.
 func (t Time) Format(layout string) string {
+	const bufSize = 64
+	var b []byte
+	max := len(layout) + 10
+	if max < bufSize {
+		var buf [bufSize]byte
+		b = buf[:0]
+	} else {
+		b = make([]byte, 0, max)
+	}
+	b = t.AppendFormat(b, layout)
+	return string(b)
+}
+
+// AppendFormat is like Format but appends the textual
+// representation to b and returns the extended buffer.
+func (t Time) AppendFormat(b []byte, layout string) []byte {
 	var (
 		name, offset, abs = t.locabs()
 
@@ -421,16 +443,7 @@ func (t Time) Format(layout string) string {
 		hour  int = -1
 		min   int
 		sec   int
-
-		b   []byte
-		buf [64]byte
 	)
-	max := len(layout) + 10
-	if max <= len(buf) {
-		b = buf[:0]
-	} else {
-		b = make([]byte, 0, max)
-	}
 	// Each iteration generates one std value.
 	for layout != "" {
 		prefix, std, suffix := nextStdChunk(layout)
@@ -458,75 +471,56 @@ func (t Time) Format(layout string) string {
 			if y < 0 {
 				y = -y
 			}
-			b = appendUint(b, uint(y%100), '0')
+			b = appendInt(b, y%100, 2)
 		case stdLongYear:
-			// Pad year to at least 4 digits.
-			y := year
-			switch {
-			case year <= -1000:
-				b = append(b, '-')
-				y = -y
-			case year <= -100:
-				b = append(b, "-0"...)
-				y = -y
-			case year <= -10:
-				b = append(b, "-00"...)
-				y = -y
-			case year < 0:
-				b = append(b, "-000"...)
-				y = -y
-			case year < 10:
-				b = append(b, "000"...)
-			case year < 100:
-				b = append(b, "00"...)
-			case year < 1000:
-				b = append(b, '0')
-			}
-			b = appendUint(b, uint(y), 0)
+			b = appendInt(b, year, 4)
 		case stdMonth:
 			b = append(b, month.String()[:3]...)
 		case stdLongMonth:
 			m := month.String()
 			b = append(b, m...)
 		case stdNumMonth:
-			b = appendUint(b, uint(month), 0)
+			b = appendInt(b, int(month), 0)
 		case stdZeroMonth:
-			b = appendUint(b, uint(month), '0')
+			b = appendInt(b, int(month), 2)
 		case stdWeekDay:
 			b = append(b, absWeekday(abs).String()[:3]...)
 		case stdLongWeekDay:
 			s := absWeekday(abs).String()
 			b = append(b, s...)
 		case stdDay:
-			b = appendUint(b, uint(day), 0)
+			b = appendInt(b, day, 0)
 		case stdUnderDay:
-			b = appendUint(b, uint(day), ' ')
+			if day < 10 {
+				b = append(b, ' ')
+			}
+			b = appendInt(b, day, 0)
 		case stdZeroDay:
-			b = appendUint(b, uint(day), '0')
+			b = appendInt(b, day, 2)
 		case stdHour:
-			b = appendUint(b, uint(hour), '0')
+			b = appendInt(b, hour, 2)
 		case stdHour12:
 			// Noon is 12PM, midnight is 12AM.
 			hr := hour % 12
 			if hr == 0 {
 				hr = 12
 			}
-			b = appendUint(b, uint(hr), 0)
+			b = appendInt(b, hr, 0)
 		case stdZeroHour12:
 			// Noon is 12PM, midnight is 12AM.
 			hr := hour % 12
 			if hr == 0 {
 				hr = 12
 			}
-			b = appendUint(b, uint(hr), '0')
+			b = appendInt(b, hr, 2)
 		case stdMinute:
-			b = appendUint(b, uint(min), 0)
+			b = appendInt(b, min, 0)
 		case stdZeroMinute:
-			b = appendUint(b, uint(min), '0')
+			b = appendInt(b, min, 2)
 		case stdSecond:
-			b = appendUint(b, uint(sec), 0)
+			b = appendInt(b, sec, 2)
 		case stdZeroSecond:
-			b = appendUint(b, uint(sec), '0')
+			b = appendInt(b, sec, 2)
 		case stdPM:
 			if hour >= 12 {
 				b = append(b, "PM"...)
@@ -555,18 +549,18 @@ func (t Time) Format(layout string) string {
 			} else {
 				b = append(b, '+')
 			}
-			b = appendUint(b, uint(zone/60), '0')
+			b = appendInt(b, zone/60, 2)
 			if std == stdISO8601ColonTZ || std == stdNumColonTZ || std == stdISO8601ColonSecondsTZ || std == stdNumColonSecondsTZ {
 				b = append(b, ':')
 			}
-			b = appendUint(b, uint(zone%60), '0')
+			b = appendInt(b, zone%60, 2)
 
 			// append seconds if appropriate
 			if std == stdISO8601SecondsTZ || std == stdNumSecondsTz || std == stdNumColonSecondsTZ || std == stdISO8601ColonSecondsTZ {
 				if std == stdNumColonSecondsTZ || std == stdISO8601ColonSecondsTZ {
 					b = append(b, ':')
 				}
-				b = appendUint(b, uint(absoffset%60), '0')
+				b = appendInt(b, absoffset%60, 2)
 			}
 
 		case stdTZ:
@@ -583,13 +577,13 @@ func (t Time) Format(layout string) string {
 			} else {
 				b = append(b, '+')
 			}
-			b = appendUint(b, uint(zone/60), '0')
-			b = appendUint(b, uint(zone%60), '0')
+			b = appendInt(b, zone/60, 2)
+			b = appendInt(b, zone%60, 2)
 		case stdFracSecond0, stdFracSecond9:
 			b = formatNano(b, uint(t.Nanosecond()), std>>stdArgShift, std&stdMask == stdFracSecond9)
 		}
 	}
-	return string(b)
+	return b
 }
 
 var errBad = errors.New("bad value for field") // placeholder not passed to user
@@ -620,8 +614,7 @@ func (e *ParseError) Error() string {
 		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 +674,13 @@ func skip(value, prefix string) (string, error) {
 // 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
@@ -1131,24 +1127,28 @@ func leadingInt(s string) (x int64, rem string, err error) {
 		if c < '0' || c > '9' {
 			break
 		}
-		if x >= (1<<63-10)/10 {
+		if x > (1<<63-1)/10 {
 			// overflow
 			return 0, "", errLeadingInt
 		}
 		x = x*10 + int64(c) - '0'
+		if x < 0 {
+			// overflow
+			return 0, "", errLeadingInt
+		}
 	}
 	return x, s[i:], nil
 }
 
-var unitMap = map[string]float64{
-	"ns": float64(Nanosecond),
-	"us": float64(Microsecond),
-	"µs": float64(Microsecond), // U+00B5 = micro symbol
-	"μs": float64(Microsecond), // U+03BC = Greek letter mu
-	"ms": float64(Millisecond),
-	"s":  float64(Second),
-	"m":  float64(Minute),
-	"h":  float64(Hour),
+var unitMap = map[string]int64{
+	"ns": int64(Nanosecond),
+	"us": int64(Microsecond),
+	"µs": int64(Microsecond), // U+00B5 = micro symbol
+	"μs": int64(Microsecond), // U+03BC = Greek letter mu
+	"ms": int64(Millisecond),
+	"s":  int64(Second),
+	"m":  int64(Minute),
+	"h":  int64(Hour),
 }
 
 // ParseDuration parses a duration string.
@@ -1159,7 +1159,7 @@ var unitMap = map[string]float64{
 func ParseDuration(s string) (Duration, error) {
 	// [-+]?([0-9]*(\.[0-9]*)?[a-z]+)+
 	orig := s
-	f := float64(0)
+	var d int64
 	neg := false
 
 	// Consume [-+]?
@@ -1178,22 +1178,23 @@ func ParseDuration(s string) (Duration, error) {
 		return 0, errors.New("time: invalid duration " + orig)
 	}
 	for s != "" {
-		g := float64(0) // this element of the sequence
+		var (
+			v, f  int64       // integers before, after decimal point
+			scale float64 = 1 // value = v + f/scale
+		)
 
-		var x int64
 		var err error
 
 		// The next character must be [0-9.]
-		if !(s[0] == '.' || ('0' <= s[0] && s[0] <= '9')) {
+		if !(s[0] == '.' || '0' <= s[0] && s[0] <= '9') {
 			return 0, errors.New("time: invalid duration " + orig)
 		}
 		// Consume [0-9]*
 		pl := len(s)
-		x, s, err = leadingInt(s)
+		v, s, err = leadingInt(s)
 		if err != nil {
 			return 0, errors.New("time: invalid duration " + orig)
 		}
-		g = float64(x)
 		pre := pl != len(s) // whether we consumed anything before a period
 
 		// Consume (\.[0-9]*)?
@@ -1201,15 +1202,13 @@ func ParseDuration(s string) (Duration, error) {
 		if s != "" && s[0] == '.' {
 			s = s[1:]
 			pl := len(s)
-			x, s, err = leadingInt(s)
+			f, s, err = leadingInt(s)
 			if err != nil {
 				return 0, errors.New("time: invalid duration " + orig)
 			}
-			scale := 1.0
 			for n := pl - len(s); n > 0; n-- {
 				scale *= 10
 			}
-			g += float64(x) / scale
 			post = pl != len(s)
 		}
 		if !pre && !post {
@@ -1221,7 +1220,7 @@ func ParseDuration(s string) (Duration, error) {
 		i := 0
 		for ; i < len(s); i++ {
 			c := s[i]
-			if c == '.' || ('0' <= c && c <= '9') {
+			if c == '.' || '0' <= c && c <= '9' {
 				break
 			}
 		}
@@ -1234,15 +1233,29 @@ func ParseDuration(s string) (Duration, error) {
 		if !ok {
 			return 0, errors.New("time: unknown unit " + u + " in duration " + orig)
 		}
-
-		f += g * unit
+		if v > (1<<63-1)/unit {
+			// overflow
+			return 0, errors.New("time: invalid duration " + orig)
+		}
+		v *= unit
+		if f > 0 {
+			// float64 is needed to be nanosecond accurate for fractions of hours.
+			// v >= 0 && (f*unit/scale) <= 3.6e+12 (ns/h, h is the largest unit)
+			v += int64(float64(f) * (float64(unit) / scale))
+			if v < 0 {
+				// overflow
+				return 0, errors.New("time: invalid duration " + orig)
+			}
+		}
+		d += v
+		if d < 0 {
+			// overflow
+			return 0, errors.New("time: invalid duration " + orig)
+		}
 	}
 
 	if neg {
-		f = -f
-	}
-	if f < float64(-1<<63) || f > float64(1<<63-1) {
-		return 0, errors.New("time: overflow parsing duration")
+		d = -d
 	}
-	return Duration(f), nil
+	return Duration(d), nil
 }
diff --git a/src/time/sleep_test.go b/src/time/sleep_test.go
index c9b2956..dd0a820 100644
--- a/src/time/sleep_test.go
+++ b/src/time/sleep_test.go
@@ -8,7 +8,6 @@ import (
 	"errors"
 	"fmt"
 	"runtime"
-	"sort"
 	"strings"
 	"sync"
 	"sync/atomic"
@@ -224,10 +223,11 @@ func TestAfterStop(t *testing.T) {
 func TestAfterQueuing(t *testing.T) {
 	// This test flakes out on some systems,
 	// so we'll try it a few times before declaring it a failure.
-	const attempts = 3
+	const attempts = 5
 	err := errors.New("!=nil")
 	for i := 0; i < attempts && err != nil; i++ {
-		if err = testAfterQueuing(t); err != nil {
+		delta := Duration(20+i*50) * Millisecond
+		if err = testAfterQueuing(t, delta); err != nil {
 			t.Logf("attempt %v failed: %v", i, err)
 		}
 	}
@@ -247,11 +247,7 @@ func await(slot int, result chan<- afterResult, ac <-chan Time) {
 	result <- afterResult{slot, <-ac}
 }
 
-func testAfterQueuing(t *testing.T) error {
-	Delta := 100 * Millisecond
-	if testing.Short() {
-		Delta = 20 * Millisecond
-	}
+func testAfterQueuing(t *testing.T, delta Duration) error {
 	// make the result channel buffered because we don't want
 	// to depend on channel queueing semantics that might
 	// possibly change in the future.
@@ -259,18 +255,25 @@ func testAfterQueuing(t *testing.T) error {
 
 	t0 := Now()
 	for _, slot := range slots {
-		go await(slot, result, After(Duration(slot)*Delta))
+		go await(slot, result, After(Duration(slot)*delta))
 	}
-	sort.Ints(slots)
-	for _, slot := range slots {
+	var order []int
+	var times []Time
+	for range slots {
 		r := <-result
-		if r.slot != slot {
-			return fmt.Errorf("after slot %d, expected %d", r.slot, slot)
+		order = append(order, r.slot)
+		times = append(times, r.t)
+	}
+	for i := range order {
+		if i > 0 && order[i] < order[i-1] {
+			return fmt.Errorf("After calls returned out of order: %v", order)
 		}
-		dt := r.t.Sub(t0)
-		target := Duration(slot) * Delta
-		if dt < target-Delta/2 || dt > target+Delta*10 {
-			return fmt.Errorf("After(%s) arrived at %s, expected [%s,%s]", target, dt, target-Delta/2, target+Delta*10)
+	}
+	for i, t := range times {
+		dt := t.Sub(t0)
+		target := Duration(order[i]) * delta
+		if dt < target-delta/2 || dt > target+delta*10 {
+			return fmt.Errorf("After(%s) arrived at %s, expected [%s,%s]", target, dt, target-delta/2, target+delta*10)
 		}
 	}
 	return nil
@@ -383,6 +386,10 @@ func TestOverflowSleep(t *testing.T) {
 // 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/sys_unix.go b/src/time/sys_unix.go
index 379e13d..e592415 100644
--- a/src/time/sys_unix.go
+++ b/src/time/sys_unix.go
@@ -74,3 +74,5 @@ func preadn(fd uintptr, buf []byte, off int) error {
 	}
 	return nil
 }
+
+func isNotExist(err error) bool { return err == syscall.ENOENT }
diff --git a/src/time/tick.go b/src/time/tick.go
index 1900784..196e8ac 100644
--- a/src/time/tick.go
+++ b/src/time/tick.go
@@ -47,7 +47,9 @@ func (t *Ticker) Stop() {
 }
 
 // Tick is a convenience wrapper for NewTicker providing access to the ticking
-// channel only.  Useful for clients that have no need to shut down the ticker.
+// channel only. While Tick is useful for clients that have no need to shut down
+// the Ticker, be aware that without a way to shut it down the underlying
+// Ticker cannot be recovered by the garbage collector; it "leaks".
 func Tick(d Duration) <-chan Time {
 	if d <= 0 {
 		return nil
diff --git a/src/time/time.go b/src/time/time.go
index 0300e84..294cc77 100644
--- a/src/time/time.go
+++ b/src/time/time.go
@@ -966,6 +966,8 @@ func (t *Time) UnmarshalText(data []byte) (err error) {
 // Unix returns the local Time corresponding to the given Unix time,
 // sec seconds and nsec nanoseconds since January 1, 1970 UTC.
 // It is valid to pass nsec outside the range [0, 999999999].
+// Not all sec values have a corresponding time value. One such
+// value is 1<<63-1 (the largest int64 value).
 func Unix(sec int64, nsec int64) Time {
 	if nsec < 0 || nsec >= 1e9 {
 		n := nsec / 1e9
diff --git a/src/time/time_test.go b/src/time/time_test.go
index 7e31dd7..2d16ea5 100644
--- a/src/time/time_test.go
+++ b/src/time/time_test.go
@@ -830,8 +830,16 @@ var parseDurationTests = []struct {
 	{"39h9m14.425s", true, 39*Hour + 9*Minute + 14*Second + 425*Millisecond},
 	// large value
 	{"52763797000ns", true, 52763797000 * Nanosecond},
-	// more than 9 digits after decimal point, see http://golang.org/issue/6617
+	// more than 9 digits after decimal point, see https://golang.org/issue/6617
 	{"0.3333333333333333333h", true, 20 * Minute},
+	// 9007199254740993 = 1<<53+1 cannot be stored precisely in a float64
+	{"9007199254740993ns", true, (1<<53 + 1) * Nanosecond},
+	// largest duration that can be represented by int64 in nanoseconds
+	{"9223372036854775807ns", true, (1<<63 - 1) * Nanosecond},
+	{"9223372036854775.807us", true, (1<<63 - 1) * Nanosecond},
+	{"9223372036s854ms775us807ns", true, (1<<63 - 1) * Nanosecond},
+	// large negative value
+	{"-9223372036854775807ns", true, -1<<63 + 1*Nanosecond},
 
 	// errors
 	{"", false, 0},
@@ -842,7 +850,13 @@ var parseDurationTests = []struct {
 	{"-.", false, 0},
 	{".s", false, 0},
 	{"+.s", false, 0},
-	{"3000000h", false, 0}, // overflow
+	{"3000000h", false, 0},                  // overflow
+	{"9223372036854775808ns", false, 0},     // overflow
+	{"9223372036854775.808us", false, 0},    // overflow
+	{"9223372036854ms775us808ns", false, 0}, // overflow
+	// largest negative value of type int64 in nanoseconds should fail
+	// see https://go-review.googlesource.com/#/c/2461/
+	{"-9223372036854775808ns", false, 0},
 }
 
 func TestParseDuration(t *testing.T) {
@@ -1052,6 +1066,13 @@ func BenchmarkParse(b *testing.B) {
 	}
 }
 
+func BenchmarkParseDuration(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		ParseDuration("9007199254.740993ms")
+		ParseDuration("9007199254740993ns")
+	}
+}
+
 func BenchmarkHour(b *testing.B) {
 	t := Now()
 	for i := 0; i < b.N; i++ {
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_plan9.go b/src/time/zoneinfo_plan9.go
index 4bb0cb3..0694f0a 100644
--- a/src/time/zoneinfo_plan9.go
+++ b/src/time/zoneinfo_plan9.go
@@ -7,7 +7,6 @@
 package time
 
 import (
-	"errors"
 	"runtime"
 	"syscall"
 )
@@ -148,11 +147,12 @@ func initLocal() {
 }
 
 func loadLocation(name string) (*Location, error) {
-	if z, err := loadZoneFile(runtime.GOROOT()+"/lib/time/zoneinfo.zip", name); err == nil {
-		z.name = name
-		return z, nil
+	z, err := loadZoneFile(runtime.GOROOT()+"/lib/time/zoneinfo.zip", name)
+	if err != nil {
+		return nil, err
 	}
-	return nil, errors.New("unknown time zone " + name)
+	z.name = name
+	return z, nil
 }
 
 func forceZipFileForTesting(zipOnly bool) {
diff --git a/src/time/zoneinfo_unix.go b/src/time/zoneinfo_unix.go
index ab7e461..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.
@@ -74,11 +74,17 @@ func initLocal() {
 }
 
 func loadLocation(name string) (*Location, error) {
+	var firstErr error
 	for _, zoneDir := range zoneDirs {
 		if z, err := loadZoneFile(zoneDir, name); err == nil {
 			z.name = name
 			return z, nil
+		} else if firstErr == nil && !isNotExist(err) {
+			firstErr = err
 		}
 	}
+	if firstErr != nil {
+		return nil, firstErr
+	}
 	return nil, errors.New("unknown time zone " + name)
 }
diff --git a/src/time/zoneinfo_windows.go b/src/time/zoneinfo_windows.go
index 02d8e0e..d04ebec 100644
--- a/src/time/zoneinfo_windows.go
+++ b/src/time/zoneinfo_windows.go
@@ -6,9 +6,9 @@ package time
 
 import (
 	"errors"
+	"internal/syscall/windows/registry"
 	"runtime"
 	"syscall"
-	"unsafe"
 )
 
 //go:generate go run genzabbrs.go -output zoneinfo_abbrs_windows.go
@@ -20,39 +20,23 @@ import (
 // The implementation assumes that this year's rules for daylight savings
 // time apply to all previous and future years as well.
 
-// getKeyValue retrieves the string value kname associated with the open registry key kh.
-func getKeyValue(kh syscall.Handle, kname string) (string, error) {
-	var buf [50]uint16 // buf needs to be large enough to fit zone descriptions
-	var typ uint32
-	n := uint32(len(buf) * 2) // RegQueryValueEx's signature expects array of bytes, not uint16
-	p, _ := syscall.UTF16PtrFromString(kname)
-	if err := syscall.RegQueryValueEx(kh, p, nil, &typ, (*byte)(unsafe.Pointer(&buf[0])), &n); err != nil {
-		return "", err
-	}
-	if typ != syscall.REG_SZ { // null terminated strings only
-		return "", errors.New("Key is not string")
-	}
-	return syscall.UTF16ToString(buf[:]), nil
-}
-
 // matchZoneKey checks if stdname and dstname match the corresponding "Std"
 // and "Dlt" key values in the kname key stored under the open registry key zones.
-func matchZoneKey(zones syscall.Handle, kname string, stdname, dstname string) (matched bool, err2 error) {
-	var h syscall.Handle
-	p, _ := syscall.UTF16PtrFromString(kname)
-	if err := syscall.RegOpenKeyEx(zones, p, 0, syscall.KEY_READ, &h); err != nil {
+func matchZoneKey(zones registry.Key, kname string, stdname, dstname string) (matched bool, err2 error) {
+	k, err := registry.OpenKey(zones, kname, registry.READ)
+	if err != nil {
 		return false, err
 	}
-	defer syscall.RegCloseKey(h)
+	defer k.Close()
 
-	s, err := getKeyValue(h, "Std")
+	s, _, err := k.GetStringValue("Std")
 	if err != nil {
 		return false, err
 	}
 	if s != stdname {
 		return false, nil
 	}
-	s, err = getKeyValue(h, "Dlt")
+	s, _, err = k.GetStringValue("Dlt")
 	if err != nil {
 		return false, err
 	}
@@ -65,28 +49,20 @@ func matchZoneKey(zones syscall.Handle, kname string, stdname, dstname string) (
 // toEnglishName searches the registry for an English name of a time zone
 // whose zone names are stdname and dstname and returns the English name.
 func toEnglishName(stdname, dstname string) (string, error) {
-	var zones syscall.Handle
-	p, _ := syscall.UTF16PtrFromString(`SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones`)
-	if err := syscall.RegOpenKeyEx(syscall.HKEY_LOCAL_MACHINE, p, 0, syscall.KEY_READ, &zones); err != nil {
+	k, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones`, registry.ENUMERATE_SUB_KEYS|registry.QUERY_VALUE)
+	if err != nil {
 		return "", err
 	}
-	defer syscall.RegCloseKey(zones)
+	defer k.Close()
 
-	var count uint32
-	if err := syscall.RegQueryInfoKey(zones, nil, nil, nil, &count, nil, nil, nil, nil, nil, nil, nil); err != nil {
+	names, err := k.ReadSubKeyNames(-1)
+	if err != nil {
 		return "", err
 	}
-
-	var buf [50]uint16 // buf needs to be large enough to fit zone descriptions
-	for i := uint32(0); i < count; i++ {
-		n := uint32(len(buf))
-		if syscall.RegEnumKeyEx(zones, i, &buf[0], &n, nil, nil, nil, nil) != nil {
-			continue
-		}
-		kname := syscall.UTF16ToString(buf[:])
-		matched, err := matchZoneKey(zones, kname, stdname, dstname)
+	for _, name := range names {
+		matched, err := matchZoneKey(k, name, stdname, dstname)
 		if err == nil && matched {
-			return kname, nil
+			return name, nil
 		}
 	}
 	return "", errors.New(`English name for time zone "` + stdname + `" not found in registry`)
@@ -260,11 +236,12 @@ func initLocal() {
 }
 
 func loadLocation(name string) (*Location, error) {
-	if z, err := loadZoneFile(runtime.GOROOT()+`\lib\time\zoneinfo.zip`, name); err == nil {
-		z.name = name
-		return z, nil
+	z, err := loadZoneFile(runtime.GOROOT()+`\lib\time\zoneinfo.zip`, name)
+	if err != nil {
+		return nil, err
 	}
-	return nil, errors.New("unknown time zone " + name)
+	z.name = name
+	return z, nil
 }
 
 func forceZipFileForTesting(zipOnly bool) {
diff --git a/src/time/zoneinfo_windows_test.go b/src/time/zoneinfo_windows_test.go
index 9db81b7..5f1141d 100644
--- a/src/time/zoneinfo_windows_test.go
+++ b/src/time/zoneinfo_windows_test.go
@@ -5,6 +5,7 @@
 package time_test
 
 import (
+	"internal/syscall/windows/registry"
 	"testing"
 	. "time"
 )
@@ -33,3 +34,27 @@ func TestAusZoneAbbr(t *testing.T) {
 	defer ForceUSPacificForTesting()
 	testZoneAbbr(t)
 }
+
+func TestToEnglishName(t *testing.T) {
+	const want = "Central Europe Standard Time"
+	k, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones\`+want, registry.READ)
+	if err != nil {
+		t.Fatalf("cannot open CEST time zone information from registry: %s", err)
+	}
+	defer k.Close()
+	std, _, err := k.GetStringValue("Std")
+	if err != nil {
+		t.Fatalf("cannot read CEST Std registry key: %s", err)
+	}
+	dlt, _, err := k.GetStringValue("Dlt")
+	if err != nil {
+		t.Fatalf("cannot read CEST Dlt registry key: %s", err)
+	}
+	name, err := ToEnglishName(std, dlt)
+	if err != nil {
+		t.Fatalf("toEnglishName failed: %s", err)
+	}
+	if name != want {
+		t.Fatalf("english name: %q, want: %q", name, want)
+	}
+}
diff --git a/src/unicode/graphic.go b/src/unicode/graphic.go
index ba90b4e..81eae3e 100644
--- a/src/unicode/graphic.go
+++ b/src/unicode/graphic.go
@@ -82,7 +82,7 @@ func IsControl(r rune) bool {
 	if uint32(r) <= MaxLatin1 {
 		return properties[uint8(r)]&pC != 0
 	}
-	// All control characters are < Latin1Max.
+	// All control characters are < MaxLatin1.
 	return false
 }
 
diff --git a/src/unicode/letter_test.go b/src/unicode/letter_test.go
index 4ee11fb..a40b412 100644
--- a/src/unicode/letter_test.go
+++ b/src/unicode/letter_test.go
@@ -24,6 +24,7 @@ var upperTest = []rune{
 	0x181,
 	0x376,
 	0x3cf,
+	0x13bd,
 	0x1f2a,
 	0x2102,
 	0x2c00,
@@ -46,6 +47,7 @@ var notupperTest = []rune{
 	0x377,
 	0x387,
 	0x2150,
+	0xab7d,
 	0xffff,
 	0x10000,
 }
@@ -194,6 +196,15 @@ var caseTest = []caseT{
 	{LowerCase, 0x0148, 0x0148},
 	{TitleCase, 0x0148, 0x0147},
 
+	// Lowercase lower than uppercase.
+	// AB78;CHEROKEE SMALL LETTER GE;Ll;0;L;;;;;N;;;13A8;;13A8
+	{UpperCase, 0xab78, 0x13a8},
+	{LowerCase, 0xab78, 0xab78},
+	{TitleCase, 0xab78, 0x13a8},
+	{UpperCase, 0x13a8, 0x13a8},
+	{LowerCase, 0x13a8, 0xab78},
+	{TitleCase, 0x13a8, 0x13a8},
+
 	// Last block in the 5.1.0 table
 	// 10400;DESERET CAPITAL LETTER LONG I;Lu;0;L;;;;;N;;;;10428;
 	{UpperCase, 0x10400, 0x10400},
@@ -405,6 +416,9 @@ var simpleFoldTests = []string{
 	// Extra special cases: has lower/upper but no case fold.
 	"İ",
 	"ı",
+
+	// Upper comes before lower (Cherokee).
+	"\u13b0\uab80",
 }
 
 func TestSimpleFold(t *testing.T) {
diff --git a/src/unicode/maketables.go b/src/unicode/maketables.go
index d1c9aa0..9fccdec 100644
--- a/src/unicode/maketables.go
+++ b/src/unicode/maketables.go
@@ -44,7 +44,7 @@ func main() {
 var dataURL = flag.String("data", "", "full URL for UnicodeData.txt; defaults to --url/UnicodeData.txt")
 var casefoldingURL = flag.String("casefolding", "", "full URL for CaseFolding.txt; defaults to --url/CaseFolding.txt")
 var url = flag.String("url",
-	"http://www.unicode.org/Public/7.0.0/ucd/",
+	"http://www.unicode.org/Public/8.0.0/ucd/",
 	"URL of Unicode database directory")
 var tablelist = flag.String("tables",
 	"all",
@@ -1152,11 +1152,14 @@ func printCasefold() {
 		}
 	}
 
-	// Delete the groups for which assuming [lower, upper] is right.
+	// Delete the groups for which assuming [lower, upper] or [upper, lower] is right.
 	for i, orb := range caseOrbit {
 		if len(orb) == 2 && chars[orb[0]].upperCase == orb[1] && chars[orb[1]].lowerCase == orb[0] {
 			caseOrbit[i] = nil
 		}
+		if len(orb) == 2 && chars[orb[1]].upperCase == orb[0] && chars[orb[0]].lowerCase == orb[1] {
+			caseOrbit[i] = nil
+		}
 	}
 
 	// Record orbit information in chars.
diff --git a/src/unicode/script_test.go b/src/unicode/script_test.go
index 795cb4e..935c225 100644
--- a/src/unicode/script_test.go
+++ b/src/unicode/script_test.go
@@ -14,9 +14,11 @@ type T struct {
 	script string
 }
 
-// Hand-chosen tests from Unicode 5.1.0, 6.0.0, 6.2.0, 6.3.0 and 7.0.0 mostly to
-// discover when new scripts and categories arise.
+// Hand-chosen tests from Unicode 5.1.0, 6.0.0, 6.2.0, 6.3.0, 7.0.0 and 8.0.0
+// mostly to discover when new scripts and categories arise.
 var inTest = []T{
+	{0x11711, "Ahom"},
+	{0x14646, "Anatolian_Hieroglyphs"},
 	{0x06e2, "Arabic"},
 	{0x0567, "Armenian"},
 	{0x10b20, "Avestan"},
@@ -58,6 +60,7 @@ var inTest = []T{
 	{0x3028, "Han"},
 	{0x11b8, "Hangul"},
 	{0x1727, "Hanunoo"},
+	{0x108FF, "Hatran"},
 	{0x05a0, "Hebrew"},
 	{0x3058, "Hiragana"},
 	{0x10841, "Imperial_Aramaic"},
@@ -94,12 +97,14 @@ var inTest = []T{
 	{0x11611, "Modi"},
 	{0x1822, "Mongolian"},
 	{0x16a60, "Mro"},
+	{0x11293, "Multani"},
 	{0x104c, "Myanmar"},
 	{0x10880, "Nabataean"},
 	{0x19c3, "New_Tai_Lue"},
 	{0x07f8, "Nko"},
 	{0x169b, "Ogham"},
 	{0x1c6a, "Ol_Chiki"},
+	{0x10C80, "Old_Hungarian"},
 	{0x10310, "Old_Italic"},
 	{0x10a80, "Old_North_Arabian"},
 	{0x10350, "Old_Permic"},
@@ -121,6 +126,7 @@ var inTest = []T{
 	{0x111a0, "Sharada"},
 	{0x10463, "Shavian"},
 	{0x115c1, "Siddham"},
+	{0x1D920, "SignWriting"},
 	{0x0dbd, "Sinhala"},
 	{0x110d0, "Sora_Sompeng"},
 	{0x1ba3, "Sundanese"},
diff --git a/src/unicode/tables.go b/src/unicode/tables.go
index 8b77dd6..370a9d1 100644
--- a/src/unicode/tables.go
+++ b/src/unicode/tables.go
@@ -3,13 +3,13 @@
 // license that can be found in the LICENSE file.
 
 // Generated by running
-//	maketables --tables=all --data=http://www.unicode.org/Public/7.0.0/ucd/UnicodeData.txt --casefolding=http://www.unicode.org/Public/7.0.0/ucd/CaseFolding.txt
+//	maketables --tables=all --data=http://www.unicode.org/Public/8.0.0/ucd/UnicodeData.txt --casefolding=http://www.unicode.org/Public/8.0.0/ucd/CaseFolding.txt
 // DO NOT EDIT
 
 package unicode
 
 // Version is the Unicode edition from which the tables are derived.
-const Version = "7.0.0"
+const Version = "8.0.0"
 
 // Categories is the set of Unicode category tables.
 var Categories = map[string]*RangeTable{
@@ -170,7 +170,7 @@ var _L = &RangeTable{
 		{0x081a, 0x0824, 10},
 		{0x0828, 0x0840, 24},
 		{0x0841, 0x0858, 1},
-		{0x08a0, 0x08b2, 1},
+		{0x08a0, 0x08b4, 1},
 		{0x0904, 0x0939, 1},
 		{0x093d, 0x0950, 19},
 		{0x0958, 0x0961, 1},
@@ -203,7 +203,8 @@ var _L = &RangeTable{
 		{0x0ab5, 0x0ab9, 1},
 		{0x0abd, 0x0ad0, 19},
 		{0x0ae0, 0x0ae1, 1},
-		{0x0b05, 0x0b0c, 1},
+		{0x0af9, 0x0b05, 12},
+		{0x0b06, 0x0b0c, 1},
 		{0x0b0f, 0x0b10, 1},
 		{0x0b13, 0x0b28, 1},
 		{0x0b2a, 0x0b30, 1},
@@ -228,9 +229,9 @@ var _L = &RangeTable{
 		{0x0c12, 0x0c28, 1},
 		{0x0c2a, 0x0c39, 1},
 		{0x0c3d, 0x0c58, 27},
-		{0x0c59, 0x0c60, 7},
-		{0x0c61, 0x0c85, 36},
-		{0x0c86, 0x0c8c, 1},
+		{0x0c59, 0x0c5a, 1},
+		{0x0c60, 0x0c61, 1},
+		{0x0c85, 0x0c8c, 1},
 		{0x0c8e, 0x0c90, 1},
 		{0x0c92, 0x0ca8, 1},
 		{0x0caa, 0x0cb3, 1},
@@ -241,7 +242,7 @@ var _L = &RangeTable{
 		{0x0d05, 0x0d0c, 1},
 		{0x0d0e, 0x0d10, 1},
 		{0x0d12, 0x0d3a, 1},
-		{0x0d3d, 0x0d4e, 17},
+		{0x0d3d, 0x0d5f, 17},
 		{0x0d60, 0x0d61, 1},
 		{0x0d7a, 0x0d7f, 1},
 		{0x0d85, 0x0d96, 1},
@@ -300,7 +301,8 @@ var _L = &RangeTable{
 		{0x1312, 0x1315, 1},
 		{0x1318, 0x135a, 1},
 		{0x1380, 0x138f, 1},
-		{0x13a0, 0x13f4, 1},
+		{0x13a0, 0x13f5, 1},
+		{0x13f8, 0x13fd, 1},
 		{0x1401, 0x166c, 1},
 		{0x166f, 0x167f, 1},
 		{0x1681, 0x169a, 1},
@@ -322,7 +324,7 @@ var _L = &RangeTable{
 		{0x1950, 0x196d, 1},
 		{0x1970, 0x1974, 1},
 		{0x1980, 0x19ab, 1},
-		{0x19c1, 0x19c7, 1},
+		{0x19b0, 0x19c9, 1},
 		{0x1a00, 0x1a16, 1},
 		{0x1a20, 0x1a54, 1},
 		{0x1aa7, 0x1b05, 94},
@@ -399,7 +401,7 @@ var _L = &RangeTable{
 		{0x31a0, 0x31ba, 1},
 		{0x31f0, 0x31ff, 1},
 		{0x3400, 0x4db5, 1},
-		{0x4e00, 0x9fcc, 1},
+		{0x4e00, 0x9fd5, 1},
 		{0xa000, 0xa48c, 1},
 		{0xa4d0, 0xa4fd, 1},
 		{0xa500, 0xa60c, 1},
@@ -410,9 +412,8 @@ var _L = &RangeTable{
 		{0xa6a0, 0xa6e5, 1},
 		{0xa717, 0xa71f, 1},
 		{0xa722, 0xa788, 1},
-		{0xa78b, 0xa78e, 1},
-		{0xa790, 0xa7ad, 1},
-		{0xa7b0, 0xa7b1, 1},
+		{0xa78b, 0xa7ad, 1},
+		{0xa7b0, 0xa7b7, 1},
 		{0xa7f7, 0xa801, 1},
 		{0xa803, 0xa805, 1},
 		{0xa807, 0xa80a, 1},
@@ -420,8 +421,8 @@ var _L = &RangeTable{
 		{0xa840, 0xa873, 1},
 		{0xa882, 0xa8b3, 1},
 		{0xa8f2, 0xa8f7, 1},
-		{0xa8fb, 0xa90a, 15},
-		{0xa90b, 0xa925, 1},
+		{0xa8fb, 0xa8fd, 2},
+		{0xa90a, 0xa925, 1},
 		{0xa930, 0xa946, 1},
 		{0xa960, 0xa97c, 1},
 		{0xa984, 0xa9b2, 1},
@@ -448,9 +449,8 @@ var _L = &RangeTable{
 		{0xab20, 0xab26, 1},
 		{0xab28, 0xab2e, 1},
 		{0xab30, 0xab5a, 1},
-		{0xab5c, 0xab5f, 1},
-		{0xab64, 0xab65, 1},
-		{0xabc0, 0xabe2, 1},
+		{0xab5c, 0xab65, 1},
+		{0xab70, 0xabe2, 1},
 		{0xac00, 0xd7a3, 1},
 		{0xd7b0, 0xd7c6, 1},
 		{0xd7cb, 0xd7fb, 1},
@@ -511,6 +511,8 @@ var _L = &RangeTable{
 		{0x10840, 0x10855, 1},
 		{0x10860, 0x10876, 1},
 		{0x10880, 0x1089e, 1},
+		{0x108e0, 0x108f2, 1},
+		{0x108f4, 0x108f5, 1},
 		{0x10900, 0x10915, 1},
 		{0x10920, 0x10939, 1},
 		{0x10980, 0x109b7, 1},
@@ -528,6 +530,8 @@ var _L = &RangeTable{
 		{0x10b60, 0x10b72, 1},
 		{0x10b80, 0x10b91, 1},
 		{0x10c00, 0x10c48, 1},
+		{0x10c80, 0x10cb2, 1},
+		{0x10cc0, 0x10cf2, 1},
 		{0x11003, 0x11037, 1},
 		{0x11083, 0x110af, 1},
 		{0x110d0, 0x110e8, 1},
@@ -536,9 +540,14 @@ var _L = &RangeTable{
 		{0x11176, 0x11183, 13},
 		{0x11184, 0x111b2, 1},
 		{0x111c1, 0x111c4, 1},
-		{0x111da, 0x11200, 38},
-		{0x11201, 0x11211, 1},
+		{0x111da, 0x111dc, 2},
+		{0x11200, 0x11211, 1},
 		{0x11213, 0x1122b, 1},
+		{0x11280, 0x11286, 1},
+		{0x11288, 0x1128a, 2},
+		{0x1128b, 0x1128d, 1},
+		{0x1128f, 0x1129d, 1},
+		{0x1129f, 0x112a8, 1},
 		{0x112b0, 0x112de, 1},
 		{0x11305, 0x1130c, 1},
 		{0x1130f, 0x11310, 1},
@@ -546,20 +555,24 @@ var _L = &RangeTable{
 		{0x1132a, 0x11330, 1},
 		{0x11332, 0x11333, 1},
 		{0x11335, 0x11339, 1},
-		{0x1133d, 0x1135d, 32},
-		{0x1135e, 0x11361, 1},
+		{0x1133d, 0x11350, 19},
+		{0x1135d, 0x11361, 1},
 		{0x11480, 0x114af, 1},
 		{0x114c4, 0x114c5, 1},
 		{0x114c7, 0x11580, 185},
 		{0x11581, 0x115ae, 1},
+		{0x115d8, 0x115db, 1},
 		{0x11600, 0x1162f, 1},
 		{0x11644, 0x11680, 60},
 		{0x11681, 0x116aa, 1},
+		{0x11700, 0x11719, 1},
 		{0x118a0, 0x118df, 1},
 		{0x118ff, 0x11ac0, 449},
 		{0x11ac1, 0x11af8, 1},
-		{0x12000, 0x12398, 1},
+		{0x12000, 0x12399, 1},
+		{0x12480, 0x12543, 1},
 		{0x13000, 0x1342e, 1},
+		{0x14400, 0x14646, 1},
 		{0x16800, 0x16a38, 1},
 		{0x16a40, 0x16a5e, 1},
 		{0x16ad0, 0x16aed, 1},
@@ -633,6 +646,7 @@ var _L = &RangeTable{
 		{0x20000, 0x2a6d6, 1},
 		{0x2a700, 0x2b734, 1},
 		{0x2b740, 0x2b81d, 1},
+		{0x2b820, 0x2cea1, 1},
 		{0x2f800, 0x2fa1d, 1},
 	},
 	LatinOffset: 6,
@@ -691,6 +705,7 @@ var _Ll = &RangeTable{
 		{0x04c2, 0x04ce, 2},
 		{0x04cf, 0x052f, 2},
 		{0x0561, 0x0587, 1},
+		{0x13f8, 0x13fd, 1},
 		{0x1d00, 0x1d2b, 1},
 		{0x1d6b, 0x1d77, 1},
 		{0x1d79, 0x1d9a, 1},
@@ -747,15 +762,18 @@ var _Ll = &RangeTable{
 		{0xa791, 0xa793, 2},
 		{0xa794, 0xa795, 1},
 		{0xa797, 0xa7a9, 2},
+		{0xa7b5, 0xa7b7, 2},
 		{0xa7fa, 0xab30, 822},
 		{0xab31, 0xab5a, 1},
-		{0xab64, 0xab65, 1},
+		{0xab60, 0xab65, 1},
+		{0xab70, 0xabbf, 1},
 		{0xfb00, 0xfb06, 1},
 		{0xfb13, 0xfb17, 1},
 		{0xff41, 0xff5a, 1},
 	},
 	R32: []Range32{
 		{0x10428, 0x1044f, 1},
+		{0x10cc0, 0x10cf2, 1},
 		{0x118c0, 0x118df, 1},
 		{0x1d41a, 0x1d433, 1},
 		{0x1d44e, 0x1d454, 1},
@@ -861,7 +879,7 @@ var _Lo = &RangeTable{
 		{0x07cb, 0x07ea, 1},
 		{0x0800, 0x0815, 1},
 		{0x0840, 0x0858, 1},
-		{0x08a0, 0x08b2, 1},
+		{0x08a0, 0x08b4, 1},
 		{0x0904, 0x0939, 1},
 		{0x093d, 0x0950, 19},
 		{0x0958, 0x0961, 1},
@@ -894,7 +912,8 @@ var _Lo = &RangeTable{
 		{0x0ab5, 0x0ab9, 1},
 		{0x0abd, 0x0ad0, 19},
 		{0x0ae0, 0x0ae1, 1},
-		{0x0b05, 0x0b0c, 1},
+		{0x0af9, 0x0b05, 12},
+		{0x0b06, 0x0b0c, 1},
 		{0x0b0f, 0x0b10, 1},
 		{0x0b13, 0x0b28, 1},
 		{0x0b2a, 0x0b30, 1},
@@ -919,9 +938,9 @@ var _Lo = &RangeTable{
 		{0x0c12, 0x0c28, 1},
 		{0x0c2a, 0x0c39, 1},
 		{0x0c3d, 0x0c58, 27},
-		{0x0c59, 0x0c60, 7},
-		{0x0c61, 0x0c85, 36},
-		{0x0c86, 0x0c8c, 1},
+		{0x0c59, 0x0c5a, 1},
+		{0x0c60, 0x0c61, 1},
+		{0x0c85, 0x0c8c, 1},
 		{0x0c8e, 0x0c90, 1},
 		{0x0c92, 0x0ca8, 1},
 		{0x0caa, 0x0cb3, 1},
@@ -932,7 +951,7 @@ var _Lo = &RangeTable{
 		{0x0d05, 0x0d0c, 1},
 		{0x0d0e, 0x0d10, 1},
 		{0x0d12, 0x0d3a, 1},
-		{0x0d3d, 0x0d4e, 17},
+		{0x0d3d, 0x0d5f, 17},
 		{0x0d60, 0x0d61, 1},
 		{0x0d7a, 0x0d7f, 1},
 		{0x0d85, 0x0d96, 1},
@@ -988,7 +1007,6 @@ var _Lo = &RangeTable{
 		{0x1312, 0x1315, 1},
 		{0x1318, 0x135a, 1},
 		{0x1380, 0x138f, 1},
-		{0x13a0, 0x13f4, 1},
 		{0x1401, 0x166c, 1},
 		{0x166f, 0x167f, 1},
 		{0x1681, 0x169a, 1},
@@ -1011,7 +1029,7 @@ var _Lo = &RangeTable{
 		{0x1950, 0x196d, 1},
 		{0x1970, 0x1974, 1},
 		{0x1980, 0x19ab, 1},
-		{0x19c1, 0x19c7, 1},
+		{0x19b0, 0x19c9, 1},
 		{0x1a00, 0x1a16, 1},
 		{0x1a20, 0x1a54, 1},
 		{0x1b05, 0x1b33, 1},
@@ -1046,7 +1064,7 @@ var _Lo = &RangeTable{
 		{0x31a0, 0x31ba, 1},
 		{0x31f0, 0x31ff, 1},
 		{0x3400, 0x4db5, 1},
-		{0x4e00, 0x9fcc, 1},
+		{0x4e00, 0x9fd5, 1},
 		{0xa000, 0xa014, 1},
 		{0xa016, 0xa48c, 1},
 		{0xa4d0, 0xa4f7, 1},
@@ -1055,16 +1073,16 @@ var _Lo = &RangeTable{
 		{0xa62a, 0xa62b, 1},
 		{0xa66e, 0xa6a0, 50},
 		{0xa6a1, 0xa6e5, 1},
-		{0xa7f7, 0xa7fb, 4},
-		{0xa7fc, 0xa801, 1},
+		{0xa78f, 0xa7f7, 104},
+		{0xa7fb, 0xa801, 1},
 		{0xa803, 0xa805, 1},
 		{0xa807, 0xa80a, 1},
 		{0xa80c, 0xa822, 1},
 		{0xa840, 0xa873, 1},
 		{0xa882, 0xa8b3, 1},
 		{0xa8f2, 0xa8f7, 1},
-		{0xa8fb, 0xa90a, 15},
-		{0xa90b, 0xa925, 1},
+		{0xa8fb, 0xa8fd, 2},
+		{0xa90a, 0xa925, 1},
 		{0xa930, 0xa946, 1},
 		{0xa960, 0xa97c, 1},
 		{0xa984, 0xa9b2, 1},
@@ -1149,6 +1167,8 @@ var _Lo = &RangeTable{
 		{0x10840, 0x10855, 1},
 		{0x10860, 0x10876, 1},
 		{0x10880, 0x1089e, 1},
+		{0x108e0, 0x108f2, 1},
+		{0x108f4, 0x108f5, 1},
 		{0x10900, 0x10915, 1},
 		{0x10920, 0x10939, 1},
 		{0x10980, 0x109b7, 1},
@@ -1174,9 +1194,14 @@ var _Lo = &RangeTable{
 		{0x11176, 0x11183, 13},
 		{0x11184, 0x111b2, 1},
 		{0x111c1, 0x111c4, 1},
-		{0x111da, 0x11200, 38},
-		{0x11201, 0x11211, 1},
+		{0x111da, 0x111dc, 2},
+		{0x11200, 0x11211, 1},
 		{0x11213, 0x1122b, 1},
+		{0x11280, 0x11286, 1},
+		{0x11288, 0x1128a, 2},
+		{0x1128b, 0x1128d, 1},
+		{0x1128f, 0x1129d, 1},
+		{0x1129f, 0x112a8, 1},
 		{0x112b0, 0x112de, 1},
 		{0x11305, 0x1130c, 1},
 		{0x1130f, 0x11310, 1},
@@ -1184,19 +1209,23 @@ var _Lo = &RangeTable{
 		{0x1132a, 0x11330, 1},
 		{0x11332, 0x11333, 1},
 		{0x11335, 0x11339, 1},
-		{0x1133d, 0x1135d, 32},
-		{0x1135e, 0x11361, 1},
+		{0x1133d, 0x11350, 19},
+		{0x1135d, 0x11361, 1},
 		{0x11480, 0x114af, 1},
 		{0x114c4, 0x114c5, 1},
 		{0x114c7, 0x11580, 185},
 		{0x11581, 0x115ae, 1},
+		{0x115d8, 0x115db, 1},
 		{0x11600, 0x1162f, 1},
 		{0x11644, 0x11680, 60},
 		{0x11681, 0x116aa, 1},
+		{0x11700, 0x11719, 1},
 		{0x118ff, 0x11ac0, 449},
 		{0x11ac1, 0x11af8, 1},
-		{0x12000, 0x12398, 1},
+		{0x12000, 0x12399, 1},
+		{0x12480, 0x12543, 1},
 		{0x13000, 0x1342e, 1},
+		{0x14400, 0x14646, 1},
 		{0x16800, 0x16a38, 1},
 		{0x16a40, 0x16a5e, 1},
 		{0x16ad0, 0x16aed, 1},
@@ -1238,6 +1267,7 @@ var _Lo = &RangeTable{
 		{0x20000, 0x2a6d6, 1},
 		{0x2a700, 0x2b734, 1},
 		{0x2b740, 0x2b81d, 1},
+		{0x2b820, 0x2cea1, 1},
 		{0x2f800, 0x2fa1d, 1},
 	},
 	LatinOffset: 1,
@@ -1312,6 +1342,7 @@ var _Lu = &RangeTable{
 		{0x0531, 0x0556, 1},
 		{0x10a0, 0x10c5, 1},
 		{0x10c7, 0x10cd, 6},
+		{0x13a0, 0x13f5, 1},
 		{0x1e00, 0x1e94, 2},
 		{0x1e9e, 0x1efe, 2},
 		{0x1f08, 0x1f0f, 1},
@@ -1356,11 +1387,13 @@ var _Lu = &RangeTable{
 		{0xa790, 0xa792, 2},
 		{0xa796, 0xa7aa, 2},
 		{0xa7ab, 0xa7ad, 1},
-		{0xa7b0, 0xa7b1, 1},
-		{0xff21, 0xff3a, 1},
+		{0xa7b0, 0xa7b4, 1},
+		{0xa7b6, 0xff21, 22379},
+		{0xff22, 0xff3a, 1},
 	},
 	R32: []Range32{
 		{0x10400, 0x10427, 1},
+		{0x10c80, 0x10cb2, 1},
 		{0x118a0, 0x118bf, 1},
 		{0x1d400, 0x1d419, 1},
 		{0x1d434, 0x1d44d, 1},
@@ -1420,7 +1453,7 @@ var _M = &RangeTable{
 		{0x0825, 0x0827, 1},
 		{0x0829, 0x082d, 1},
 		{0x0859, 0x085b, 1},
-		{0x08e4, 0x0903, 1},
+		{0x08e3, 0x0903, 1},
 		{0x093a, 0x093c, 1},
 		{0x093e, 0x094f, 1},
 		{0x0951, 0x0957, 1},
@@ -1516,8 +1549,6 @@ var _M = &RangeTable{
 		{0x18a9, 0x1920, 119},
 		{0x1921, 0x192b, 1},
 		{0x1930, 0x193b, 1},
-		{0x19b0, 0x19c0, 1},
-		{0x19c8, 0x19c9, 1},
 		{0x1a17, 0x1a1b, 1},
 		{0x1a55, 0x1a5e, 1},
 		{0x1a60, 0x1a7c, 1},
@@ -1545,10 +1576,11 @@ var _M = &RangeTable{
 		{0x3099, 0x309a, 1},
 		{0xa66f, 0xa672, 1},
 		{0xa674, 0xa67d, 1},
-		{0xa69f, 0xa6f0, 81},
-		{0xa6f1, 0xa802, 273},
-		{0xa806, 0xa80b, 5},
-		{0xa823, 0xa827, 1},
+		{0xa69e, 0xa69f, 1},
+		{0xa6f0, 0xa6f1, 1},
+		{0xa802, 0xa806, 4},
+		{0xa80b, 0xa823, 24},
+		{0xa824, 0xa827, 1},
 		{0xa880, 0xa881, 1},
 		{0xa8b4, 0xa8c4, 1},
 		{0xa8e0, 0xa8f1, 1},
@@ -1572,7 +1604,7 @@ var _M = &RangeTable{
 		{0xabec, 0xabed, 1},
 		{0xfb1e, 0xfe00, 738},
 		{0xfe01, 0xfe0f, 1},
-		{0xfe20, 0xfe2d, 1},
+		{0xfe20, 0xfe2f, 1},
 	},
 	R32: []Range32{
 		{0x101fd, 0x102e0, 227},
@@ -1592,9 +1624,10 @@ var _M = &RangeTable{
 		{0x11173, 0x11180, 13},
 		{0x11181, 0x11182, 1},
 		{0x111b3, 0x111c0, 1},
+		{0x111ca, 0x111cc, 1},
 		{0x1122c, 0x11237, 1},
 		{0x112df, 0x112ea, 1},
-		{0x11301, 0x11303, 1},
+		{0x11300, 0x11303, 1},
 		{0x1133c, 0x1133e, 2},
 		{0x1133f, 0x11344, 1},
 		{0x11347, 0x11348, 1},
@@ -1606,8 +1639,10 @@ var _M = &RangeTable{
 		{0x114b0, 0x114c3, 1},
 		{0x115af, 0x115b5, 1},
 		{0x115b8, 0x115c0, 1},
+		{0x115dc, 0x115dd, 1},
 		{0x11630, 0x11640, 1},
 		{0x116ab, 0x116b7, 1},
+		{0x1171d, 0x1172b, 1},
 		{0x16af0, 0x16af4, 1},
 		{0x16b30, 0x16b36, 1},
 		{0x16f51, 0x16f7e, 1},
@@ -1619,6 +1654,11 @@ var _M = &RangeTable{
 		{0x1d185, 0x1d18b, 1},
 		{0x1d1aa, 0x1d1ad, 1},
 		{0x1d242, 0x1d244, 1},
+		{0x1da00, 0x1da36, 1},
+		{0x1da3b, 0x1da6c, 1},
+		{0x1da75, 0x1da84, 15},
+		{0x1da9b, 0x1da9f, 1},
+		{0x1daa1, 0x1daaf, 1},
 		{0x1e8d0, 0x1e8d6, 1},
 		{0xe0100, 0xe01ef, 1},
 	},
@@ -1685,8 +1725,6 @@ var _Mc = &RangeTable{
 		{0x1929, 0x192b, 1},
 		{0x1930, 0x1931, 1},
 		{0x1933, 0x1938, 1},
-		{0x19b0, 0x19c0, 1},
-		{0x19c8, 0x19c9, 1},
 		{0x1a19, 0x1a1a, 1},
 		{0x1a55, 0x1a57, 2},
 		{0x1a61, 0x1a63, 2},
@@ -1755,8 +1793,9 @@ var _Mc = &RangeTable{
 		{0x1163b, 0x1163c, 1},
 		{0x1163e, 0x116ac, 110},
 		{0x116ae, 0x116af, 1},
-		{0x116b6, 0x16f51, 22683},
-		{0x16f52, 0x16f7e, 1},
+		{0x116b6, 0x11720, 106},
+		{0x11721, 0x11726, 5},
+		{0x16f51, 0x16f7e, 1},
 		{0x1d165, 0x1d166, 1},
 		{0x1d16d, 0x1d172, 1},
 	},
@@ -1796,7 +1835,7 @@ var _Mn = &RangeTable{
 		{0x0825, 0x0827, 1},
 		{0x0829, 0x082d, 1},
 		{0x0859, 0x085b, 1},
-		{0x08e4, 0x0902, 1},
+		{0x08e3, 0x0902, 1},
 		{0x093a, 0x093c, 2},
 		{0x0941, 0x0948, 1},
 		{0x094d, 0x0951, 4},
@@ -1918,12 +1957,12 @@ var _Mn = &RangeTable{
 		{0x3099, 0x309a, 1},
 		{0xa66f, 0xa674, 5},
 		{0xa675, 0xa67d, 1},
-		{0xa69f, 0xa6f0, 81},
-		{0xa6f1, 0xa802, 273},
-		{0xa806, 0xa80b, 5},
-		{0xa825, 0xa826, 1},
-		{0xa8c4, 0xa8e0, 28},
-		{0xa8e1, 0xa8f1, 1},
+		{0xa69e, 0xa69f, 1},
+		{0xa6f0, 0xa6f1, 1},
+		{0xa802, 0xa806, 4},
+		{0xa80b, 0xa825, 26},
+		{0xa826, 0xa8c4, 158},
+		{0xa8e0, 0xa8f1, 1},
 		{0xa926, 0xa92d, 1},
 		{0xa947, 0xa951, 1},
 		{0xa980, 0xa982, 1},
@@ -1943,7 +1982,7 @@ var _Mn = &RangeTable{
 		{0xabe5, 0xabe8, 3},
 		{0xabed, 0xfb1e, 20273},
 		{0xfe00, 0xfe0f, 1},
-		{0xfe20, 0xfe2d, 1},
+		{0xfe20, 0xfe2f, 1},
 	},
 	R32: []Range32{
 		{0x101fd, 0x102e0, 227},
@@ -1964,13 +2003,14 @@ var _Mn = &RangeTable{
 		{0x11173, 0x11180, 13},
 		{0x11181, 0x111b6, 53},
 		{0x111b7, 0x111be, 1},
+		{0x111ca, 0x111cc, 1},
 		{0x1122f, 0x11231, 1},
 		{0x11234, 0x11236, 2},
 		{0x11237, 0x112df, 168},
 		{0x112e3, 0x112ea, 1},
-		{0x11301, 0x1133c, 59},
-		{0x11340, 0x11366, 38},
-		{0x11367, 0x1136c, 1},
+		{0x11300, 0x11301, 1},
+		{0x1133c, 0x11340, 4},
+		{0x11366, 0x1136c, 1},
 		{0x11370, 0x11374, 1},
 		{0x114b3, 0x114b8, 1},
 		{0x114ba, 0x114bf, 5},
@@ -1979,13 +2019,17 @@ var _Mn = &RangeTable{
 		{0x115b3, 0x115b5, 1},
 		{0x115bc, 0x115bd, 1},
 		{0x115bf, 0x115c0, 1},
+		{0x115dc, 0x115dd, 1},
 		{0x11633, 0x1163a, 1},
 		{0x1163d, 0x1163f, 2},
 		{0x11640, 0x116ab, 107},
 		{0x116ad, 0x116b0, 3},
 		{0x116b1, 0x116b5, 1},
-		{0x116b7, 0x16af0, 21561},
-		{0x16af1, 0x16af4, 1},
+		{0x116b7, 0x1171d, 102},
+		{0x1171e, 0x1171f, 1},
+		{0x11722, 0x11725, 1},
+		{0x11727, 0x1172b, 1},
+		{0x16af0, 0x16af4, 1},
 		{0x16b30, 0x16b36, 1},
 		{0x16f8f, 0x16f92, 1},
 		{0x1bc9d, 0x1bc9e, 1},
@@ -1994,6 +2038,11 @@ var _Mn = &RangeTable{
 		{0x1d185, 0x1d18b, 1},
 		{0x1d1aa, 0x1d1ad, 1},
 		{0x1d242, 0x1d244, 1},
+		{0x1da00, 0x1da36, 1},
+		{0x1da3b, 0x1da6c, 1},
+		{0x1da75, 0x1da84, 15},
+		{0x1da9b, 0x1da9f, 1},
+		{0x1daa1, 0x1daaf, 1},
 		{0x1e8d0, 0x1e8d6, 1},
 		{0xe0100, 0xe01ef, 1},
 	},
@@ -2079,7 +2128,11 @@ var _N = &RangeTable{
 		{0x10858, 0x1085f, 1},
 		{0x10879, 0x1087f, 1},
 		{0x108a7, 0x108af, 1},
+		{0x108fb, 0x108ff, 1},
 		{0x10916, 0x1091b, 1},
+		{0x109bc, 0x109bd, 1},
+		{0x109c0, 0x109cf, 1},
+		{0x109d2, 0x109ff, 1},
 		{0x10a40, 0x10a47, 1},
 		{0x10a7d, 0x10a7e, 1},
 		{0x10a9d, 0x10a9f, 1},
@@ -2087,6 +2140,7 @@ var _N = &RangeTable{
 		{0x10b58, 0x10b5f, 1},
 		{0x10b78, 0x10b7f, 1},
 		{0x10ba9, 0x10baf, 1},
+		{0x10cfa, 0x10cff, 1},
 		{0x10e60, 0x10e7e, 1},
 		{0x11052, 0x1106f, 1},
 		{0x110f0, 0x110f9, 1},
@@ -2097,6 +2151,7 @@ var _N = &RangeTable{
 		{0x114d0, 0x114d9, 1},
 		{0x11650, 0x11659, 1},
 		{0x116c0, 0x116c9, 1},
+		{0x11730, 0x1173b, 1},
 		{0x118e0, 0x118f2, 1},
 		{0x12400, 0x1246e, 1},
 		{0x16a60, 0x16a69, 1},
@@ -2160,6 +2215,7 @@ var _Nd = &RangeTable{
 		{0x114d0, 0x114d9, 1},
 		{0x11650, 0x11659, 1},
 		{0x116c0, 0x116c9, 1},
+		{0x11730, 0x11739, 1},
 		{0x118e0, 0x118e9, 1},
 		{0x16a60, 0x16a69, 1},
 		{0x16b50, 0x16b59, 1},
@@ -2225,7 +2281,11 @@ var _No = &RangeTable{
 		{0x10858, 0x1085f, 1},
 		{0x10879, 0x1087f, 1},
 		{0x108a7, 0x108af, 1},
+		{0x108fb, 0x108ff, 1},
 		{0x10916, 0x1091b, 1},
+		{0x109bc, 0x109bd, 1},
+		{0x109c0, 0x109cf, 1},
+		{0x109d2, 0x109ff, 1},
 		{0x10a40, 0x10a47, 1},
 		{0x10a7d, 0x10a7e, 1},
 		{0x10a9d, 0x10a9f, 1},
@@ -2233,9 +2293,11 @@ var _No = &RangeTable{
 		{0x10b58, 0x10b5f, 1},
 		{0x10b78, 0x10b7f, 1},
 		{0x10ba9, 0x10baf, 1},
+		{0x10cfa, 0x10cff, 1},
 		{0x10e60, 0x10e7e, 1},
 		{0x11052, 0x11065, 1},
 		{0x111e1, 0x111f4, 1},
+		{0x1173a, 0x1173b, 1},
 		{0x118ea, 0x118f2, 1},
 		{0x16b5b, 0x16b61, 1},
 		{0x1d360, 0x1d371, 1},
@@ -2336,9 +2398,9 @@ var _P = &RangeTable{
 		{0xa874, 0xa877, 1},
 		{0xa8ce, 0xa8cf, 1},
 		{0xa8f8, 0xa8fa, 1},
-		{0xa92e, 0xa92f, 1},
-		{0xa95f, 0xa9c1, 98},
-		{0xa9c2, 0xa9cd, 1},
+		{0xa8fc, 0xa92e, 50},
+		{0xa92f, 0xa95f, 48},
+		{0xa9c1, 0xa9cd, 1},
 		{0xa9de, 0xa9df, 1},
 		{0xaa5c, 0xaa5f, 1},
 		{0xaade, 0xaadf, 1},
@@ -2375,17 +2437,20 @@ var _P = &RangeTable{
 		{0x110be, 0x110c1, 1},
 		{0x11140, 0x11143, 1},
 		{0x11174, 0x11175, 1},
-		{0x111c5, 0x111c8, 1},
-		{0x111cd, 0x11238, 107},
-		{0x11239, 0x1123d, 1},
-		{0x114c6, 0x115c1, 251},
-		{0x115c2, 0x115c9, 1},
+		{0x111c5, 0x111c9, 1},
+		{0x111cd, 0x111db, 14},
+		{0x111dd, 0x111df, 1},
+		{0x11238, 0x1123d, 1},
+		{0x112a9, 0x114c6, 541},
+		{0x115c1, 0x115d7, 1},
 		{0x11641, 0x11643, 1},
+		{0x1173c, 0x1173e, 1},
 		{0x12470, 0x12474, 1},
 		{0x16a6e, 0x16a6f, 1},
 		{0x16af5, 0x16b37, 66},
 		{0x16b38, 0x16b3b, 1},
 		{0x16b44, 0x1bc9f, 20827},
+		{0x1da87, 0x1da8b, 1},
 	},
 	LatinOffset: 11,
 }
@@ -2550,9 +2615,9 @@ var _Po = &RangeTable{
 		{0xa874, 0xa877, 1},
 		{0xa8ce, 0xa8cf, 1},
 		{0xa8f8, 0xa8fa, 1},
-		{0xa92e, 0xa92f, 1},
-		{0xa95f, 0xa9c1, 98},
-		{0xa9c2, 0xa9cd, 1},
+		{0xa8fc, 0xa92e, 50},
+		{0xa92f, 0xa95f, 48},
+		{0xa9c1, 0xa9cd, 1},
 		{0xa9de, 0xa9df, 1},
 		{0xaa5c, 0xaa5f, 1},
 		{0xaade, 0xaadf, 1},
@@ -2592,17 +2657,20 @@ var _Po = &RangeTable{
 		{0x110be, 0x110c1, 1},
 		{0x11140, 0x11143, 1},
 		{0x11174, 0x11175, 1},
-		{0x111c5, 0x111c8, 1},
-		{0x111cd, 0x11238, 107},
-		{0x11239, 0x1123d, 1},
-		{0x114c6, 0x115c1, 251},
-		{0x115c2, 0x115c9, 1},
+		{0x111c5, 0x111c9, 1},
+		{0x111cd, 0x111db, 14},
+		{0x111dd, 0x111df, 1},
+		{0x11238, 0x1123d, 1},
+		{0x112a9, 0x114c6, 541},
+		{0x115c1, 0x115d7, 1},
 		{0x11641, 0x11643, 1},
+		{0x1173c, 0x1173e, 1},
 		{0x12470, 0x12474, 1},
 		{0x16a6e, 0x16a6f, 1},
 		{0x16af5, 0x16b37, 66},
 		{0x16b38, 0x16b3b, 1},
 		{0x16b44, 0x1bc9f, 20827},
+		{0x1da87, 0x1da8b, 1},
 	},
 	LatinOffset: 8,
 }
@@ -2694,7 +2762,7 @@ var _S = &RangeTable{
 		{0x2044, 0x2052, 14},
 		{0x207a, 0x207c, 1},
 		{0x208a, 0x208c, 1},
-		{0x20a0, 0x20bd, 1},
+		{0x20a0, 0x20be, 1},
 		{0x2100, 0x2101, 1},
 		{0x2103, 0x2106, 1},
 		{0x2108, 0x2109, 1},
@@ -2706,7 +2774,8 @@ var _S = &RangeTable{
 		{0x213b, 0x2140, 5},
 		{0x2141, 0x2144, 1},
 		{0x214a, 0x214d, 1},
-		{0x214f, 0x2190, 65},
+		{0x214f, 0x218a, 59},
+		{0x218b, 0x2190, 5},
 		{0x2191, 0x2307, 1},
 		{0x230c, 0x2328, 1},
 		{0x232b, 0x23fa, 1},
@@ -2724,6 +2793,7 @@ var _S = &RangeTable{
 		{0x2b98, 0x2bb9, 1},
 		{0x2bbd, 0x2bc8, 1},
 		{0x2bca, 0x2bd1, 1},
+		{0x2bec, 0x2bef, 1},
 		{0x2ce5, 0x2cea, 1},
 		{0x2e80, 0x2e99, 1},
 		{0x2e9b, 0x2ef3, 1},
@@ -2774,8 +2844,8 @@ var _S = &RangeTable{
 		{0x101a0, 0x101d0, 48},
 		{0x101d1, 0x101fc, 1},
 		{0x10877, 0x10878, 1},
-		{0x10ac8, 0x16b3c, 24692},
-		{0x16b3d, 0x16b3f, 1},
+		{0x10ac8, 0x1173f, 3191},
+		{0x16b3c, 0x16b3f, 1},
 		{0x16b45, 0x1bc9c, 20823},
 		{0x1d000, 0x1d0f5, 1},
 		{0x1d100, 0x1d126, 1},
@@ -2783,7 +2853,7 @@ var _S = &RangeTable{
 		{0x1d16a, 0x1d16c, 1},
 		{0x1d183, 0x1d184, 1},
 		{0x1d18c, 0x1d1a9, 1},
-		{0x1d1ae, 0x1d1dd, 1},
+		{0x1d1ae, 0x1d1e8, 1},
 		{0x1d200, 0x1d241, 1},
 		{0x1d245, 0x1d300, 187},
 		{0x1d301, 0x1d356, 1},
@@ -2792,6 +2862,11 @@ var _S = &RangeTable{
 		{0x1d735, 0x1d74f, 26},
 		{0x1d76f, 0x1d789, 26},
 		{0x1d7a9, 0x1d7c3, 26},
+		{0x1d800, 0x1d9ff, 1},
+		{0x1da37, 0x1da3a, 1},
+		{0x1da6d, 0x1da74, 1},
+		{0x1da76, 0x1da83, 1},
+		{0x1da85, 0x1da86, 1},
 		{0x1eef0, 0x1eef1, 1},
 		{0x1f000, 0x1f02b, 1},
 		{0x1f030, 0x1f093, 1},
@@ -2806,16 +2881,9 @@ var _S = &RangeTable{
 		{0x1f210, 0x1f23a, 1},
 		{0x1f240, 0x1f248, 1},
 		{0x1f250, 0x1f251, 1},
-		{0x1f300, 0x1f32c, 1},
-		{0x1f330, 0x1f37d, 1},
-		{0x1f380, 0x1f3ce, 1},
-		{0x1f3d4, 0x1f3f7, 1},
-		{0x1f400, 0x1f4fe, 1},
-		{0x1f500, 0x1f54a, 1},
-		{0x1f550, 0x1f579, 1},
+		{0x1f300, 0x1f579, 1},
 		{0x1f57b, 0x1f5a3, 1},
-		{0x1f5a5, 0x1f642, 1},
-		{0x1f645, 0x1f6cf, 1},
+		{0x1f5a5, 0x1f6d0, 1},
 		{0x1f6e0, 0x1f6ec, 1},
 		{0x1f6f0, 0x1f6f3, 1},
 		{0x1f700, 0x1f773, 1},
@@ -2825,6 +2893,9 @@ var _S = &RangeTable{
 		{0x1f850, 0x1f859, 1},
 		{0x1f860, 0x1f887, 1},
 		{0x1f890, 0x1f8ad, 1},
+		{0x1f910, 0x1f918, 1},
+		{0x1f980, 0x1f984, 1},
+		{0x1f9c0, 0x1f9c0, 1},
 	},
 	LatinOffset: 10,
 }
@@ -2838,7 +2909,7 @@ var _Sc = &RangeTable{
 		{0x09fb, 0x0af1, 246},
 		{0x0bf9, 0x0e3f, 582},
 		{0x17db, 0x20a0, 2245},
-		{0x20a1, 0x20bd, 1},
+		{0x20a1, 0x20be, 1},
 		{0xa838, 0xfdfc, 21956},
 		{0xfe69, 0xff04, 155},
 		{0xffe0, 0xffe1, 1},
@@ -2873,6 +2944,10 @@ var _Sk = &RangeTable{
 		{0xff3e, 0xff40, 2},
 		{0xffe3, 0xffe3, 1},
 	},
+	R32: []Range32{
+		{0x1f3fb, 0x1f3fb, 1},
+		{0x1f3fc, 0x1f3ff, 1},
+	},
 	LatinOffset: 3,
 }
 
@@ -2971,7 +3046,8 @@ var _So = &RangeTable{
 		{0x212e, 0x213a, 12},
 		{0x213b, 0x214a, 15},
 		{0x214c, 0x214d, 1},
-		{0x214f, 0x2195, 70},
+		{0x214f, 0x218a, 59},
+		{0x218b, 0x2195, 10},
 		{0x2196, 0x2199, 1},
 		{0x219c, 0x219f, 1},
 		{0x21a1, 0x21a2, 1},
@@ -3005,6 +3081,7 @@ var _So = &RangeTable{
 		{0x2b98, 0x2bb9, 1},
 		{0x2bbd, 0x2bc8, 1},
 		{0x2bca, 0x2bd1, 1},
+		{0x2bec, 0x2bef, 1},
 		{0x2ce5, 0x2cea, 1},
 		{0x2e80, 0x2e99, 1},
 		{0x2e9b, 0x2ef3, 1},
@@ -3044,8 +3121,8 @@ var _So = &RangeTable{
 		{0x101a0, 0x101d0, 48},
 		{0x101d1, 0x101fc, 1},
 		{0x10877, 0x10878, 1},
-		{0x10ac8, 0x16b3c, 24692},
-		{0x16b3d, 0x16b3f, 1},
+		{0x10ac8, 0x1173f, 3191},
+		{0x16b3c, 0x16b3f, 1},
 		{0x16b45, 0x1bc9c, 20823},
 		{0x1d000, 0x1d0f5, 1},
 		{0x1d100, 0x1d126, 1},
@@ -3053,10 +3130,15 @@ var _So = &RangeTable{
 		{0x1d16a, 0x1d16c, 1},
 		{0x1d183, 0x1d184, 1},
 		{0x1d18c, 0x1d1a9, 1},
-		{0x1d1ae, 0x1d1dd, 1},
+		{0x1d1ae, 0x1d1e8, 1},
 		{0x1d200, 0x1d241, 1},
 		{0x1d245, 0x1d300, 187},
 		{0x1d301, 0x1d356, 1},
+		{0x1d800, 0x1d9ff, 1},
+		{0x1da37, 0x1da3a, 1},
+		{0x1da6d, 0x1da74, 1},
+		{0x1da76, 0x1da83, 1},
+		{0x1da85, 0x1da86, 1},
 		{0x1f000, 0x1f02b, 1},
 		{0x1f030, 0x1f093, 1},
 		{0x1f0a0, 0x1f0ae, 1},
@@ -3070,16 +3152,10 @@ var _So = &RangeTable{
 		{0x1f210, 0x1f23a, 1},
 		{0x1f240, 0x1f248, 1},
 		{0x1f250, 0x1f251, 1},
-		{0x1f300, 0x1f32c, 1},
-		{0x1f330, 0x1f37d, 1},
-		{0x1f380, 0x1f3ce, 1},
-		{0x1f3d4, 0x1f3f7, 1},
-		{0x1f400, 0x1f4fe, 1},
-		{0x1f500, 0x1f54a, 1},
-		{0x1f550, 0x1f579, 1},
+		{0x1f300, 0x1f3fa, 1},
+		{0x1f400, 0x1f579, 1},
 		{0x1f57b, 0x1f5a3, 1},
-		{0x1f5a5, 0x1f642, 1},
-		{0x1f645, 0x1f6cf, 1},
+		{0x1f5a5, 0x1f6d0, 1},
 		{0x1f6e0, 0x1f6ec, 1},
 		{0x1f6f0, 0x1f6f3, 1},
 		{0x1f700, 0x1f773, 1},
@@ -3089,6 +3165,9 @@ var _So = &RangeTable{
 		{0x1f850, 0x1f859, 1},
 		{0x1f860, 0x1f887, 1},
 		{0x1f890, 0x1f8ad, 1},
+		{0x1f910, 0x1f918, 1},
+		{0x1f980, 0x1f984, 1},
+		{0x1f9c0, 0x1f9c0, 1},
 	},
 	LatinOffset: 2,
 }
@@ -3180,11 +3259,13 @@ var (
 )
 
 // Generated by running
-//	maketables --scripts=all --url=http://www.unicode.org/Public/7.0.0/ucd/
+//	maketables --scripts=all --url=http://www.unicode.org/Public/8.0.0/ucd/
 // DO NOT EDIT
 
 // Scripts is the set of Unicode script tables.
 var Scripts = map[string]*RangeTable{
+	"Ahom":                   Ahom,
+	"Anatolian_Hieroglyphs":  Anatolian_Hieroglyphs,
 	"Arabic":                 Arabic,
 	"Armenian":               Armenian,
 	"Avestan":                Avestan,
@@ -3225,6 +3306,7 @@ var Scripts = map[string]*RangeTable{
 	"Han":                    Han,
 	"Hangul":                 Hangul,
 	"Hanunoo":                Hanunoo,
+	"Hatran":                 Hatran,
 	"Hebrew":                 Hebrew,
 	"Hiragana":               Hiragana,
 	"Imperial_Aramaic":       Imperial_Aramaic,
@@ -3261,12 +3343,14 @@ var Scripts = map[string]*RangeTable{
 	"Modi":                   Modi,
 	"Mongolian":              Mongolian,
 	"Mro":                    Mro,
+	"Multani":                Multani,
 	"Myanmar":                Myanmar,
 	"Nabataean":              Nabataean,
 	"New_Tai_Lue":            New_Tai_Lue,
 	"Nko":                    Nko,
 	"Ogham":                  Ogham,
 	"Ol_Chiki":               Ol_Chiki,
+	"Old_Hungarian":          Old_Hungarian,
 	"Old_Italic":             Old_Italic,
 	"Old_North_Arabian":      Old_North_Arabian,
 	"Old_Permic":             Old_Permic,
@@ -3288,6 +3372,7 @@ var Scripts = map[string]*RangeTable{
 	"Sharada":                Sharada,
 	"Shavian":                Shavian,
 	"Siddham":                Siddham,
+	"SignWriting":            SignWriting,
 	"Sinhala":                Sinhala,
 	"Sora_Sompeng":           Sora_Sompeng,
 	"Sundanese":              Sundanese,
@@ -3312,6 +3397,22 @@ var Scripts = map[string]*RangeTable{
 	"Yi":                     Yi,
 }
 
+var _Ahom = &RangeTable{
+	R16: []Range16{},
+	R32: []Range32{
+		{0x11700, 0x11719, 1},
+		{0x1171d, 0x1172b, 1},
+		{0x11730, 0x1173f, 1},
+	},
+}
+
+var _Anatolian_Hieroglyphs = &RangeTable{
+	R16: []Range16{},
+	R32: []Range32{
+		{0x14400, 0x14646, 1},
+	},
+}
+
 var _Arabic = &RangeTable{
 	R16: []Range16{
 		{0x0600, 0x0604, 1},
@@ -3320,13 +3421,12 @@ var _Arabic = &RangeTable{
 		{0x061e, 0x061e, 1},
 		{0x0620, 0x063f, 1},
 		{0x0641, 0x064a, 1},
-		{0x0656, 0x065f, 1},
-		{0x066a, 0x066f, 1},
+		{0x0656, 0x066f, 1},
 		{0x0671, 0x06dc, 1},
 		{0x06de, 0x06ff, 1},
 		{0x0750, 0x077f, 1},
-		{0x08a0, 0x08b2, 1},
-		{0x08e4, 0x08ff, 1},
+		{0x08a0, 0x08b4, 1},
+		{0x08e3, 0x08ff, 1},
 		{0xfb50, 0xfbc1, 1},
 		{0xfbd3, 0xfd3d, 1},
 		{0xfd50, 0xfd8f, 1},
@@ -3520,7 +3620,9 @@ var _Cham = &RangeTable{
 
 var _Cherokee = &RangeTable{
 	R16: []Range16{
-		{0x13a0, 0x13f4, 1},
+		{0x13a0, 0x13f5, 1},
+		{0x13f8, 0x13fd, 1},
+		{0xab70, 0xabbf, 1},
 	},
 }
 
@@ -3546,7 +3648,6 @@ var _Common = &RangeTable{
 		{0x061b, 0x061c, 1},
 		{0x061f, 0x061f, 1},
 		{0x0640, 0x0640, 1},
-		{0x0660, 0x0669, 1},
 		{0x06dd, 0x06dd, 1},
 		{0x0964, 0x0965, 1},
 		{0x0e3f, 0x0e3f, 1},
@@ -3566,13 +3667,13 @@ var _Common = &RangeTable{
 		{0x2066, 0x2070, 1},
 		{0x2074, 0x207e, 1},
 		{0x2080, 0x208e, 1},
-		{0x20a0, 0x20bd, 1},
+		{0x20a0, 0x20be, 1},
 		{0x2100, 0x2125, 1},
 		{0x2127, 0x2129, 1},
 		{0x212c, 0x2131, 1},
 		{0x2133, 0x214d, 1},
 		{0x214f, 0x215f, 1},
-		{0x2189, 0x2189, 1},
+		{0x2189, 0x218b, 1},
 		{0x2190, 0x23fa, 1},
 		{0x2400, 0x2426, 1},
 		{0x2440, 0x244a, 1},
@@ -3582,6 +3683,7 @@ var _Common = &RangeTable{
 		{0x2b98, 0x2bb9, 1},
 		{0x2bbd, 0x2bc8, 1},
 		{0x2bca, 0x2bd1, 1},
+		{0x2bec, 0x2bef, 1},
 		{0x2e00, 0x2e42, 1},
 		{0x2ff0, 0x2ffb, 1},
 		{0x3000, 0x3004, 1},
@@ -3633,7 +3735,7 @@ var _Common = &RangeTable{
 		{0x1d16a, 0x1d17a, 1},
 		{0x1d183, 0x1d184, 1},
 		{0x1d18c, 0x1d1a9, 1},
-		{0x1d1ae, 0x1d1dd, 1},
+		{0x1d1ae, 0x1d1e8, 1},
 		{0x1d300, 0x1d356, 1},
 		{0x1d360, 0x1d371, 1},
 		{0x1d400, 0x1d454, 1},
@@ -3672,16 +3774,9 @@ var _Common = &RangeTable{
 		{0x1f210, 0x1f23a, 1},
 		{0x1f240, 0x1f248, 1},
 		{0x1f250, 0x1f251, 1},
-		{0x1f300, 0x1f32c, 1},
-		{0x1f330, 0x1f37d, 1},
-		{0x1f380, 0x1f3ce, 1},
-		{0x1f3d4, 0x1f3f7, 1},
-		{0x1f400, 0x1f4fe, 1},
-		{0x1f500, 0x1f54a, 1},
-		{0x1f550, 0x1f579, 1},
+		{0x1f300, 0x1f579, 1},
 		{0x1f57b, 0x1f5a3, 1},
-		{0x1f5a5, 0x1f642, 1},
-		{0x1f645, 0x1f6cf, 1},
+		{0x1f5a5, 0x1f6d0, 1},
 		{0x1f6e0, 0x1f6ec, 1},
 		{0x1f6f0, 0x1f6f3, 1},
 		{0x1f700, 0x1f773, 1},
@@ -3691,6 +3786,9 @@ var _Common = &RangeTable{
 		{0x1f850, 0x1f859, 1},
 		{0x1f860, 0x1f887, 1},
 		{0x1f890, 0x1f8ad, 1},
+		{0x1f910, 0x1f918, 1},
+		{0x1f980, 0x1f984, 1},
+		{0x1f9c0, 0x1f9c0, 1},
 		{0xe0001, 0xe0001, 1},
 		{0xe0020, 0xe007f, 1},
 	},
@@ -3708,9 +3806,10 @@ var _Coptic = &RangeTable{
 var _Cuneiform = &RangeTable{
 	R16: []Range16{},
 	R32: []Range32{
-		{0x12000, 0x12398, 1},
+		{0x12000, 0x12399, 1},
 		{0x12400, 0x1246e, 1},
 		{0x12470, 0x12474, 1},
+		{0x12480, 0x12543, 1},
 	},
 }
 
@@ -3733,8 +3832,8 @@ var _Cyrillic = &RangeTable{
 		{0x1d2b, 0x1d2b, 1},
 		{0x1d78, 0x1d78, 1},
 		{0x2de0, 0x2dff, 1},
-		{0xa640, 0xa69d, 1},
-		{0xa69f, 0xa69f, 1},
+		{0xa640, 0xa69f, 1},
+		{0xfe2e, 0xfe2f, 1},
 	},
 }
 
@@ -3750,7 +3849,7 @@ var _Devanagari = &RangeTable{
 		{0x0900, 0x0950, 1},
 		{0x0953, 0x0963, 1},
 		{0x0966, 0x097f, 1},
-		{0xa8e0, 0xa8fb, 1},
+		{0xa8e0, 0xa8fd, 1},
 	},
 }
 
@@ -3846,7 +3945,7 @@ var _Gothic = &RangeTable{
 var _Grantha = &RangeTable{
 	R16: []Range16{},
 	R32: []Range32{
-		{0x11301, 0x11303, 1},
+		{0x11300, 0x11303, 1},
 		{0x11305, 0x1130c, 1},
 		{0x1130f, 0x11310, 1},
 		{0x11313, 0x11328, 1},
@@ -3856,6 +3955,7 @@ var _Grantha = &RangeTable{
 		{0x1133c, 0x11344, 1},
 		{0x11347, 0x11348, 1},
 		{0x1134b, 0x1134d, 1},
+		{0x11350, 0x11350, 1},
 		{0x11357, 0x11357, 1},
 		{0x1135d, 0x11363, 1},
 		{0x11366, 0x1136c, 1},
@@ -3921,6 +4021,7 @@ var _Gujarati = &RangeTable{
 		{0x0ad0, 0x0ad0, 1},
 		{0x0ae0, 0x0ae3, 1},
 		{0x0ae6, 0x0af1, 1},
+		{0x0af9, 0x0af9, 1},
 	},
 }
 
@@ -3955,7 +4056,7 @@ var _Han = &RangeTable{
 		{0x3021, 0x3029, 1},
 		{0x3038, 0x303b, 1},
 		{0x3400, 0x4db5, 1},
-		{0x4e00, 0x9fcc, 1},
+		{0x4e00, 0x9fd5, 1},
 		{0xf900, 0xfa6d, 1},
 		{0xfa70, 0xfad9, 1},
 	},
@@ -3963,6 +4064,7 @@ var _Han = &RangeTable{
 		{0x20000, 0x2a6d6, 1},
 		{0x2a700, 0x2b734, 1},
 		{0x2b740, 0x2b81d, 1},
+		{0x2b820, 0x2cea1, 1},
 		{0x2f800, 0x2fa1d, 1},
 	},
 }
@@ -3992,6 +4094,15 @@ var _Hanunoo = &RangeTable{
 	},
 }
 
+var _Hatran = &RangeTable{
+	R16: []Range16{},
+	R32: []Range32{
+		{0x108e0, 0x108f2, 1},
+		{0x108f4, 0x108f5, 1},
+		{0x108fb, 0x108ff, 1},
+	},
+}
+
 var _Hebrew = &RangeTable{
 	R16: []Range16{
 		{0x0591, 0x05c7, 1},
@@ -4218,13 +4329,11 @@ var _Latin = &RangeTable{
 		{0x2160, 0x2188, 1},
 		{0x2c60, 0x2c7f, 1},
 		{0xa722, 0xa787, 1},
-		{0xa78b, 0xa78e, 1},
-		{0xa790, 0xa7ad, 1},
-		{0xa7b0, 0xa7b1, 1},
+		{0xa78b, 0xa7ad, 1},
+		{0xa7b0, 0xa7b7, 1},
 		{0xa7f7, 0xa7ff, 1},
 		{0xab30, 0xab5a, 1},
-		{0xab5c, 0xab5f, 1},
-		{0xab64, 0xab64, 1},
+		{0xab5c, 0xab64, 1},
 		{0xfb00, 0xfb06, 1},
 		{0xff21, 0xff3a, 1},
 		{0xff41, 0xff5a, 1},
@@ -4310,7 +4419,7 @@ var _Malayalam = &RangeTable{
 		{0x0d46, 0x0d48, 1},
 		{0x0d4a, 0x0d4e, 1},
 		{0x0d57, 0x0d57, 1},
-		{0x0d60, 0x0d63, 1},
+		{0x0d5f, 0x0d63, 1},
 		{0x0d66, 0x0d75, 1},
 		{0x0d79, 0x0d7f, 1},
 	},
@@ -4351,7 +4460,8 @@ var _Meroitic_Cursive = &RangeTable{
 	R16: []Range16{},
 	R32: []Range32{
 		{0x109a0, 0x109b7, 1},
-		{0x109be, 0x109bf, 1},
+		{0x109bc, 0x109cf, 1},
+		{0x109d2, 0x109ff, 1},
 	},
 }
 
@@ -4399,6 +4509,17 @@ var _Mro = &RangeTable{
 	},
 }
 
+var _Multani = &RangeTable{
+	R16: []Range16{},
+	R32: []Range32{
+		{0x11280, 0x11286, 1},
+		{0x11288, 0x11288, 1},
+		{0x1128a, 0x1128d, 1},
+		{0x1128f, 0x1129d, 1},
+		{0x1129f, 0x112a9, 1},
+	},
+}
+
 var _Myanmar = &RangeTable{
 	R16: []Range16{
 		{0x1000, 0x109f, 1},
@@ -4442,6 +4563,15 @@ var _Ol_Chiki = &RangeTable{
 	},
 }
 
+var _Old_Hungarian = &RangeTable{
+	R16: []Range16{},
+	R32: []Range32{
+		{0x10c80, 0x10cb2, 1},
+		{0x10cc0, 0x10cf2, 1},
+		{0x10cfa, 0x10cff, 1},
+	},
+}
+
 var _Old_Italic = &RangeTable{
 	R16: []Range16{},
 	R32: []Range32{
@@ -4591,9 +4721,8 @@ var _Saurashtra = &RangeTable{
 var _Sharada = &RangeTable{
 	R16: []Range16{},
 	R32: []Range32{
-		{0x11180, 0x111c8, 1},
-		{0x111cd, 0x111cd, 1},
-		{0x111d0, 0x111da, 1},
+		{0x11180, 0x111cd, 1},
+		{0x111d0, 0x111df, 1},
 	},
 }
 
@@ -4608,7 +4737,16 @@ var _Siddham = &RangeTable{
 	R16: []Range16{},
 	R32: []Range32{
 		{0x11580, 0x115b5, 1},
-		{0x115b8, 0x115c9, 1},
+		{0x115b8, 0x115dd, 1},
+	},
+}
+
+var _SignWriting = &RangeTable{
+	R16: []Range16{},
+	R32: []Range32{
+		{0x1d800, 0x1da8b, 1},
+		{0x1da9b, 0x1da9f, 1},
+		{0x1daa1, 0x1daaf, 1},
 	},
 }
 
@@ -4740,7 +4878,7 @@ var _Telugu = &RangeTable{
 		{0x0c46, 0x0c48, 1},
 		{0x0c4a, 0x0c4d, 1},
 		{0x0c55, 0x0c56, 1},
-		{0x0c58, 0x0c59, 1},
+		{0x0c58, 0x0c5a, 1},
 		{0x0c60, 0x0c63, 1},
 		{0x0c66, 0x0c6f, 1},
 		{0x0c78, 0x0c7f, 1},
@@ -4819,6 +4957,8 @@ var _Yi = &RangeTable{
 
 // These variables have type *RangeTable.
 var (
+	Ahom                   = _Ahom                   // Ahom is the set of Unicode characters in script Ahom.
+	Anatolian_Hieroglyphs  = _Anatolian_Hieroglyphs  // Anatolian_Hieroglyphs is the set of Unicode characters in script Anatolian_Hieroglyphs.
 	Arabic                 = _Arabic                 // Arabic is the set of Unicode characters in script Arabic.
 	Armenian               = _Armenian               // Armenian is the set of Unicode characters in script Armenian.
 	Avestan                = _Avestan                // Avestan is the set of Unicode characters in script Avestan.
@@ -4859,6 +4999,7 @@ var (
 	Han                    = _Han                    // Han is the set of Unicode characters in script Han.
 	Hangul                 = _Hangul                 // Hangul is the set of Unicode characters in script Hangul.
 	Hanunoo                = _Hanunoo                // Hanunoo is the set of Unicode characters in script Hanunoo.
+	Hatran                 = _Hatran                 // Hatran is the set of Unicode characters in script Hatran.
 	Hebrew                 = _Hebrew                 // Hebrew is the set of Unicode characters in script Hebrew.
 	Hiragana               = _Hiragana               // Hiragana is the set of Unicode characters in script Hiragana.
 	Imperial_Aramaic       = _Imperial_Aramaic       // Imperial_Aramaic is the set of Unicode characters in script Imperial_Aramaic.
@@ -4895,12 +5036,14 @@ var (
 	Modi                   = _Modi                   // Modi is the set of Unicode characters in script Modi.
 	Mongolian              = _Mongolian              // Mongolian is the set of Unicode characters in script Mongolian.
 	Mro                    = _Mro                    // Mro is the set of Unicode characters in script Mro.
+	Multani                = _Multani                // Multani is the set of Unicode characters in script Multani.
 	Myanmar                = _Myanmar                // Myanmar is the set of Unicode characters in script Myanmar.
 	Nabataean              = _Nabataean              // Nabataean is the set of Unicode characters in script Nabataean.
 	New_Tai_Lue            = _New_Tai_Lue            // New_Tai_Lue is the set of Unicode characters in script New_Tai_Lue.
 	Nko                    = _Nko                    // Nko is the set of Unicode characters in script Nko.
 	Ogham                  = _Ogham                  // Ogham is the set of Unicode characters in script Ogham.
 	Ol_Chiki               = _Ol_Chiki               // Ol_Chiki is the set of Unicode characters in script Ol_Chiki.
+	Old_Hungarian          = _Old_Hungarian          // Old_Hungarian is the set of Unicode characters in script Old_Hungarian.
 	Old_Italic             = _Old_Italic             // Old_Italic is the set of Unicode characters in script Old_Italic.
 	Old_North_Arabian      = _Old_North_Arabian      // Old_North_Arabian is the set of Unicode characters in script Old_North_Arabian.
 	Old_Permic             = _Old_Permic             // Old_Permic is the set of Unicode characters in script Old_Permic.
@@ -4922,6 +5065,7 @@ var (
 	Sharada                = _Sharada                // Sharada is the set of Unicode characters in script Sharada.
 	Shavian                = _Shavian                // Shavian is the set of Unicode characters in script Shavian.
 	Siddham                = _Siddham                // Siddham is the set of Unicode characters in script Siddham.
+	SignWriting            = _SignWriting            // SignWriting is the set of Unicode characters in script SignWriting.
 	Sinhala                = _Sinhala                // Sinhala is the set of Unicode characters in script Sinhala.
 	Sora_Sompeng           = _Sora_Sompeng           // Sora_Sompeng is the set of Unicode characters in script Sora_Sompeng.
 	Sundanese              = _Sundanese              // Sundanese is the set of Unicode characters in script Sundanese.
@@ -4947,7 +5091,7 @@ var (
 )
 
 // Generated by running
-//	maketables --props=all --url=http://www.unicode.org/Public/7.0.0/ucd/
+//	maketables --props=all --url=http://www.unicode.org/Public/8.0.0/ucd/
 // DO NOT EDIT
 
 // Properties is the set of Unicode property tables.
@@ -5043,7 +5187,7 @@ var _Deprecated = &RangeTable{
 	},
 	R32: []Range32{
 		{0xe0001, 0xe0001, 1},
-		{0xe0020, 0xe007f, 1},
+		{0xe007f, 0xe007f, 1},
 	},
 }
 
@@ -5077,7 +5221,7 @@ var _Diacritic = &RangeTable{
 		{0x07a6, 0x07b0, 1},
 		{0x07eb, 0x07f5, 1},
 		{0x0818, 0x0819, 1},
-		{0x08e4, 0x08fe, 1},
+		{0x08e3, 0x08fe, 1},
 		{0x093c, 0x093c, 1},
 		{0x094d, 0x094d, 1},
 		{0x0951, 0x0954, 1},
@@ -5164,7 +5308,7 @@ var _Diacritic = &RangeTable{
 		{0xab5b, 0xab5f, 1},
 		{0xabec, 0xabed, 1},
 		{0xfb1e, 0xfb1e, 1},
-		{0xfe20, 0xfe2d, 1},
+		{0xfe20, 0xfe2f, 1},
 		{0xff3e, 0xff3e, 1},
 		{0xff40, 0xff40, 1},
 		{0xff70, 0xff70, 1},
@@ -5178,6 +5322,7 @@ var _Diacritic = &RangeTable{
 		{0x11133, 0x11134, 1},
 		{0x11173, 0x11173, 1},
 		{0x111c0, 0x111c0, 1},
+		{0x111ca, 0x111cc, 1},
 		{0x11235, 0x11236, 1},
 		{0x112e9, 0x112ea, 1},
 		{0x1133c, 0x1133c, 1},
@@ -5188,6 +5333,7 @@ var _Diacritic = &RangeTable{
 		{0x115bf, 0x115c0, 1},
 		{0x1163f, 0x1163f, 1},
 		{0x116b6, 0x116b7, 1},
+		{0x1172b, 0x1172b, 1},
 		{0x16af0, 0x16af4, 1},
 		{0x16f8f, 0x16f9f, 1},
 		{0x1d167, 0x1d169, 1},
@@ -5281,7 +5427,7 @@ var _Ideographic = &RangeTable{
 		{0x3021, 0x3029, 1},
 		{0x3038, 0x303a, 1},
 		{0x3400, 0x4db5, 1},
-		{0x4e00, 0x9fcc, 1},
+		{0x4e00, 0x9fd5, 1},
 		{0xf900, 0xfa6d, 1},
 		{0xfa70, 0xfad9, 1},
 	},
@@ -5289,6 +5435,7 @@ var _Ideographic = &RangeTable{
 		{0x20000, 0x2a6d6, 1},
 		{0x2a700, 0x2b734, 1},
 		{0x2b740, 0x2b81d, 1},
+		{0x2b820, 0x2cea1, 1},
 		{0x2f800, 0x2fa1d, 1},
 	},
 }
@@ -5303,6 +5450,8 @@ var _Logical_Order_Exception = &RangeTable{
 	R16: []Range16{
 		{0x0e40, 0x0e44, 1},
 		{0x0ec0, 0x0ec4, 1},
+		{0x19b5, 0x19b7, 1},
+		{0x19ba, 0x19ba, 1},
 		{0xaab5, 0xaab6, 1},
 		{0xaab9, 0xaab9, 1},
 		{0xaabb, 0xaabc, 1},
@@ -5357,7 +5506,7 @@ var _Other_Alphabetic = &RangeTable{
 		{0x081b, 0x0823, 1},
 		{0x0825, 0x0827, 1},
 		{0x0829, 0x082c, 1},
-		{0x08e4, 0x08e9, 1},
+		{0x08e3, 0x08e9, 1},
 		{0x08f0, 0x0903, 1},
 		{0x093a, 0x093b, 1},
 		{0x093e, 0x094c, 1},
@@ -5445,8 +5594,6 @@ var _Other_Alphabetic = &RangeTable{
 		{0x18a9, 0x18a9, 1},
 		{0x1920, 0x192b, 1},
 		{0x1930, 0x1938, 1},
-		{0x19b0, 0x19c0, 1},
-		{0x19c8, 0x19c9, 1},
 		{0x1a17, 0x1a1b, 1},
 		{0x1a55, 0x1a5e, 1},
 		{0x1a61, 0x1a74, 1},
@@ -5462,7 +5609,7 @@ var _Other_Alphabetic = &RangeTable{
 		{0x24b6, 0x24e9, 1},
 		{0x2de0, 0x2dff, 1},
 		{0xa674, 0xa67b, 1},
-		{0xa69f, 0xa69f, 1},
+		{0xa69e, 0xa69f, 1},
 		{0xa823, 0xa827, 1},
 		{0xa880, 0xa881, 1},
 		{0xa8b4, 0xa8c3, 1},
@@ -5498,7 +5645,7 @@ var _Other_Alphabetic = &RangeTable{
 		{0x1122c, 0x11234, 1},
 		{0x11237, 0x11237, 1},
 		{0x112df, 0x112e8, 1},
-		{0x11301, 0x11303, 1},
+		{0x11300, 0x11303, 1},
 		{0x1133e, 0x11344, 1},
 		{0x11347, 0x11348, 1},
 		{0x1134b, 0x1134c, 1},
@@ -5507,9 +5654,11 @@ var _Other_Alphabetic = &RangeTable{
 		{0x114b0, 0x114c1, 1},
 		{0x115af, 0x115b5, 1},
 		{0x115b8, 0x115be, 1},
+		{0x115dc, 0x115dd, 1},
 		{0x11630, 0x1163e, 1},
 		{0x11640, 0x11640, 1},
 		{0x116ab, 0x116b5, 1},
+		{0x1171d, 0x1172a, 1},
 		{0x16b30, 0x16b36, 1},
 		{0x16f51, 0x16f7e, 1},
 		{0x1bc9e, 0x1bc9e, 1},
@@ -5890,16 +6039,20 @@ var _STerm = &RangeTable{
 		{0x11141, 0x11143, 1},
 		{0x111c5, 0x111c6, 1},
 		{0x111cd, 0x111cd, 1},
+		{0x111de, 0x111df, 1},
 		{0x11238, 0x11239, 1},
 		{0x1123b, 0x1123c, 1},
+		{0x112a9, 0x112a9, 1},
 		{0x115c2, 0x115c3, 1},
-		{0x115c9, 0x115c9, 1},
+		{0x115c9, 0x115d7, 1},
 		{0x11641, 0x11642, 1},
+		{0x1173c, 0x1173e, 1},
 		{0x16a6e, 0x16a6f, 1},
 		{0x16af5, 0x16af5, 1},
 		{0x16b37, 0x16b38, 1},
 		{0x16b44, 0x16b44, 1},
 		{0x1bc9f, 0x1bc9f, 1},
+		{0x1da88, 0x1da88, 1},
 	},
 	LatinOffset: 3,
 }
@@ -6023,16 +6176,20 @@ var _Terminal_Punctuation = &RangeTable{
 		{0x11141, 0x11143, 1},
 		{0x111c5, 0x111c6, 1},
 		{0x111cd, 0x111cd, 1},
+		{0x111de, 0x111df, 1},
 		{0x11238, 0x1123c, 1},
+		{0x112a9, 0x112a9, 1},
 		{0x115c2, 0x115c5, 1},
-		{0x115c9, 0x115c9, 1},
+		{0x115c9, 0x115d7, 1},
 		{0x11641, 0x11642, 1},
+		{0x1173c, 0x1173e, 1},
 		{0x12470, 0x12474, 1},
 		{0x16a6e, 0x16a6f, 1},
 		{0x16af5, 0x16af5, 1},
 		{0x16b37, 0x16b39, 1},
 		{0x16b44, 0x16b44, 1},
 		{0x1bc9f, 0x1bc9f, 1},
+		{0x1da87, 0x1da8a, 1},
 	},
 	LatinOffset: 5,
 }
@@ -6040,7 +6197,7 @@ var _Terminal_Punctuation = &RangeTable{
 var _Unified_Ideograph = &RangeTable{
 	R16: []Range16{
 		{0x3400, 0x4db5, 1},
-		{0x4e00, 0x9fcc, 1},
+		{0x4e00, 0x9fd5, 1},
 		{0xfa0e, 0xfa0f, 1},
 		{0xfa11, 0xfa11, 1},
 		{0xfa13, 0xfa14, 1},
@@ -6053,6 +6210,7 @@ var _Unified_Ideograph = &RangeTable{
 		{0x20000, 0x2a6d6, 1},
 		{0x2a700, 0x2b734, 1},
 		{0x2b740, 0x2b81d, 1},
+		{0x2b820, 0x2cea1, 1},
 	},
 }
 
@@ -6119,7 +6277,7 @@ var (
 )
 
 // Generated by running
-//	maketables --data=http://www.unicode.org/Public/7.0.0/ucd/UnicodeData.txt --casefolding=http://www.unicode.org/Public/7.0.0/ucd/CaseFolding.txt
+//	maketables --data=http://www.unicode.org/Public/8.0.0/ucd/UnicodeData.txt --casefolding=http://www.unicode.org/Public/8.0.0/ucd/CaseFolding.txt
 // DO NOT EDIT
 
 // CaseRanges is the table describing case mappings for all letters with
@@ -6240,6 +6398,7 @@ var _CaseRanges = []CaseRange{
 	{0x028A, 0x028B, d{-217, 0, -217}},
 	{0x028C, 0x028C, d{-71, 0, -71}},
 	{0x0292, 0x0292, d{-219, 0, -219}},
+	{0x029D, 0x029D, d{42261, 0, 42261}},
 	{0x029E, 0x029E, d{42258, 0, 42258}},
 	{0x0345, 0x0345, d{84, 0, 84}},
 	{0x0370, 0x0373, d{UpperLower, UpperLower, UpperLower}},
@@ -6291,6 +6450,9 @@ var _CaseRanges = []CaseRange{
 	{0x10A0, 0x10C5, d{0, 7264, 0}},
 	{0x10C7, 0x10C7, d{0, 7264, 0}},
 	{0x10CD, 0x10CD, d{0, 7264, 0}},
+	{0x13A0, 0x13EF, d{0, 38864, 0}},
+	{0x13F0, 0x13F5, d{0, 8, 0}},
+	{0x13F8, 0x13FD, d{-8, 0, -8}},
 	{0x1D79, 0x1D79, d{35332, 0, 35332}},
 	{0x1D7D, 0x1D7D, d{3814, 0, 3814}},
 	{0x1E00, 0x1E95, d{UpperLower, UpperLower, UpperLower}},
@@ -6399,10 +6561,17 @@ var _CaseRanges = []CaseRange{
 	{0xA7AD, 0xA7AD, d{0, -42305, 0}},
 	{0xA7B0, 0xA7B0, d{0, -42258, 0}},
 	{0xA7B1, 0xA7B1, d{0, -42282, 0}},
+	{0xA7B2, 0xA7B2, d{0, -42261, 0}},
+	{0xA7B3, 0xA7B3, d{0, 928, 0}},
+	{0xA7B4, 0xA7B7, d{UpperLower, UpperLower, UpperLower}},
+	{0xAB53, 0xAB53, d{-928, 0, -928}},
+	{0xAB70, 0xABBF, d{-38864, 0, -38864}},
 	{0xFF21, 0xFF3A, d{0, 32, 0}},
 	{0xFF41, 0xFF5A, d{-32, 0, -32}},
 	{0x10400, 0x10427, d{0, 40, 0}},
 	{0x10428, 0x1044F, d{-40, 0, -40}},
+	{0x10C80, 0x10CB2, d{0, 64, 0}},
+	{0x10CC0, 0x10CF2, d{-64, 0, -64}},
 	{0x118A0, 0x118BF, d{0, 32, 0}},
 	{0x118C0, 0x118DF, d{-32, 0, -32}},
 }
@@ -6832,6 +7001,7 @@ var foldLl = &RangeTable{
 		{0x0531, 0x0556, 1},
 		{0x10a0, 0x10c5, 1},
 		{0x10c7, 0x10cd, 6},
+		{0x13a0, 0x13f5, 1},
 		{0x1e00, 0x1e94, 2},
 		{0x1e9e, 0x1efe, 2},
 		{0x1f08, 0x1f0f, 1},
@@ -6872,11 +7042,13 @@ var foldLl = &RangeTable{
 		{0xa790, 0xa792, 2},
 		{0xa796, 0xa7aa, 2},
 		{0xa7ab, 0xa7ad, 1},
-		{0xa7b0, 0xa7b1, 1},
-		{0xff21, 0xff3a, 1},
+		{0xa7b0, 0xa7b4, 1},
+		{0xa7b6, 0xff21, 22379},
+		{0xff22, 0xff3a, 1},
 	},
 	R32: []Range32{
 		{0x10400, 0x10427, 1},
+		{0x10c80, 0x10cb2, 1},
 		{0x118a0, 0x118bf, 1},
 	},
 	LatinOffset: 3,
@@ -6942,9 +7114,10 @@ var foldLu = &RangeTable{
 		{0x0275, 0x027d, 8},
 		{0x0280, 0x0283, 3},
 		{0x0287, 0x028c, 1},
-		{0x0292, 0x029e, 12},
-		{0x0345, 0x0371, 44},
-		{0x0373, 0x037b, 4},
+		{0x0292, 0x029d, 11},
+		{0x029e, 0x0345, 167},
+		{0x0371, 0x0373, 2},
+		{0x0377, 0x037b, 4},
 		{0x037c, 0x037d, 1},
 		{0x03ac, 0x03af, 1},
 		{0x03b1, 0x03ce, 1},
@@ -6959,6 +7132,7 @@ var foldLu = &RangeTable{
 		{0x04c2, 0x04ce, 2},
 		{0x04cf, 0x052f, 2},
 		{0x0561, 0x0586, 1},
+		{0x13f8, 0x13fd, 1},
 		{0x1d79, 0x1d7d, 4},
 		{0x1e01, 0x1e95, 2},
 		{0x1e9b, 0x1ea1, 6},
@@ -6994,10 +7168,14 @@ var foldLu = &RangeTable{
 		{0xa78c, 0xa791, 5},
 		{0xa793, 0xa797, 4},
 		{0xa799, 0xa7a9, 2},
+		{0xa7b5, 0xa7b7, 2},
+		{0xab53, 0xab70, 29},
+		{0xab71, 0xabbf, 1},
 		{0xff41, 0xff5a, 1},
 	},
 	R32: []Range32{
 		{0x10428, 0x1044f, 1},
+		{0x10cc0, 0x10cf2, 1},
 		{0x118c0, 0x118df, 1},
 	},
 	LatinOffset: 4,
@@ -7023,7 +7201,7 @@ var foldMn = &RangeTable{
 // If there is no entry for a script name, there are no such points.
 var FoldScript = map[string]*RangeTable{}
 
-// Range entries: 3532 16-bit, 1204 32-bit, 4736 total.
-// Range bytes: 21192 16-bit, 14448 32-bit, 35640 total.
+// Range entries: 3546 16-bit, 1306 32-bit, 4852 total.
+// Range bytes: 21276 16-bit, 15672 32-bit, 36948 total.
 
 // Fold orbit bytes: 63 pairs, 252 bytes
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 @@ const (
 	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/src/unsafe/unsafe.go b/src/unsafe/unsafe.go
index 79499b2..752792f 100644
--- a/src/unsafe/unsafe.go
+++ b/src/unsafe/unsafe.go
@@ -24,17 +24,19 @@ type ArbitraryType int
 // arbitrary memory. It should be used with extreme care.
 type Pointer *ArbitraryType
 
-// Sizeof returns the size in bytes occupied by the value v.  The size is that of the
-// "top level" of the value only.  For instance, if v is a slice, it returns the size of
-// the slice descriptor, not the size of the memory referenced by the slice.
-func Sizeof(v ArbitraryType) uintptr
+// Sizeof takes an expression x of any type and returns the size in bytes
+// of a hypothetical variable v as if v was declared via var v = x.
+// The size does not include any memory possibly referenced by x.
+// For instance, if x is a slice,  Sizeof returns the size of the slice
+// descriptor, not the size of the memory referenced by the slice.
+func Sizeof(x ArbitraryType) uintptr
 
-// Offsetof returns the offset within the struct of the field represented by v,
+// Offsetof returns the offset within the struct of the field represented by x,
 // which must be of the form structValue.field.  In other words, it returns the
 // number of bytes between the start of the struct and the start of the field.
-func Offsetof(v ArbitraryType) uintptr
+func Offsetof(x ArbitraryType) uintptr
 
-// Alignof returns the alignment of the value v.  It is the maximum value m such
-// that the address of a variable with the type of v will always be zero mod m.
-// If v is of the form structValue.field, it returns the alignment of field f within struct object obj.
-func Alignof(v ArbitraryType) uintptr
+// Alignof takes an expression x of any type and returns the alignment
+// of a hypothetical variable v as if v was declared via var v = x.
+// It is the largest value m such that the address of v is zero mod m.
+func Alignof(x ArbitraryType) uintptr
diff --git a/test/bench/shootout/fasta-1000.out b/test/bench/shootout/fasta-1000.txt
similarity index 100%
rename from test/bench/shootout/fasta-1000.out
rename to test/bench/shootout/fasta-1000.txt
diff --git a/test/bench/shootout/timing.sh b/test/bench/shootout/timing.sh
index a06c326..9abcf78 100755
--- a/test/bench/shootout/timing.sh
+++ b/test/bench/shootout/timing.sh
@@ -6,9 +6,8 @@
 set -e
 
 eval $(go tool dist env)
-O=$GOCHAR
-GC="go tool ${O}g"
-LD="go tool ${O}l"
+GC="go tool compile"
+LD="go tool link"
 
 gccm=""
 case "$O" in
@@ -61,11 +60,11 @@ X-test)
 esac
 
 gc() {
-	$GC $1.go; $LD -o $O.$EXE $1.$O
+	$GC $1.go; $LD -o a.$EXE $1.o
 }
 
 gc_B() {
-	$GC -B $1.go; $LD -o $O.$EXE $1.$O
+	$GC -B $1.go; $LD -o a.$EXE $1.o
 }
 
 runonly() {
@@ -84,7 +83,7 @@ run() {
 			program=$(echo $1 | sed 's/gc //')
 			shift
 			echo $program
-			$1 <fasta-1000.out > /tmp/$$
+			$1 <fasta-1000.txt > /tmp/$$
 			case $program in
 			chameneosredux)
 				# exact numbers may vary but non-numbers should match
@@ -115,8 +114,8 @@ fasta() {
 	runonly echo 'fasta -n 25000000'
 	run "gcc $gccm -O2 fasta.c" a.$EXE 25000000
 	run 'gccgo -O2 fasta.go' a.$EXE -n 25000000	#commented out until WriteString is in bufio
-	run 'gc fasta' $O.$EXE -n 25000000
-	run 'gc_B fasta' $O.$EXE -n 25000000
+	run 'gc fasta' a.$EXE -n 25000000
+	run 'gc_B fasta' a.$EXE -n 25000000
 }
 
 revcomp() {
@@ -125,8 +124,8 @@ revcomp() {
 	runonly echo 'reverse-complement < output-of-fasta-25000000'
 	run "gcc $gccm -O2 reverse-complement.c" a.$EXE < x
 	run 'gccgo -O2 reverse-complement.go' a.$EXE < x
-	run 'gc reverse-complement' $O.$EXE < x
-	run 'gc_B reverse-complement' $O.$EXE < x
+	run 'gc reverse-complement' a.$EXE < x
+	run 'gc_B reverse-complement' a.$EXE < x
 	rm x
 }
 
@@ -134,8 +133,8 @@ nbody() {
 	runonly echo 'nbody -n 50000000'
 	run "gcc $gccm -O2 nbody.c -lm" a.$EXE 50000000
 	run 'gccgo -O2 nbody.go' a.$EXE -n 50000000
-	run 'gc nbody' $O.$EXE -n 50000000
-	run 'gc_B nbody' $O.$EXE -n 50000000
+	run 'gc nbody' a.$EXE -n 50000000
+	run 'gc_B nbody' a.$EXE -n 50000000
 }
 
 binarytree() {
@@ -143,8 +142,8 @@ binarytree() {
 	run "gcc $gccm -O2 binary-tree.c -lm" a.$EXE 15
 	run 'gccgo -O2 binary-tree.go' a.$EXE -n 15
 	run 'gccgo -O2 binary-tree-freelist.go' a.$EXE -n 15
-	run 'gc binary-tree' $O.$EXE -n 15
-	run 'gc binary-tree-freelist' $O.$EXE -n 15
+	run 'gc binary-tree' a.$EXE -n 15
+	run 'gc binary-tree-freelist' a.$EXE -n 15
 }
 
 fannkuch() {
@@ -152,9 +151,9 @@ fannkuch() {
 	run "gcc $gccm -O2 fannkuch.c" a.$EXE 12
 	run 'gccgo -O2 fannkuch.go' a.$EXE -n 12
 	run 'gccgo -O2 fannkuch-parallel.go' a.$EXE -n 12
-	run 'gc fannkuch' $O.$EXE -n 12
-	run 'gc fannkuch-parallel' $O.$EXE -n 12
-	run 'gc_B fannkuch' $O.$EXE -n 12
+	run 'gc fannkuch' a.$EXE -n 12
+	run 'gc fannkuch-parallel' a.$EXE -n 12
+	run 'gc_B fannkuch' a.$EXE -n 12
 }
 
 regexdna() {
@@ -166,9 +165,9 @@ regexdna() {
 	fi
 	run 'gccgo -O2 regex-dna.go' a.$EXE <x
 	run 'gccgo -O2 regex-dna-parallel.go' a.$EXE <x
-	run 'gc regex-dna' $O.$EXE <x
-	run 'gc regex-dna-parallel' $O.$EXE <x
-	run 'gc_B regex-dna' $O.$EXE <x
+	run 'gc regex-dna' a.$EXE <x
+	run 'gc regex-dna-parallel' a.$EXE <x
+	run 'gc_B regex-dna' a.$EXE <x
 	rm x
 }
 
@@ -176,8 +175,8 @@ spectralnorm() {
 	runonly echo 'spectral-norm 5500'
 	run "gcc $gccm -O2 spectral-norm.c -lm" a.$EXE 5500
 	run 'gccgo -O2 spectral-norm.go' a.$EXE -n 5500
-	run 'gc spectral-norm' $O.$EXE -n 5500
-	run 'gc_B spectral-norm' $O.$EXE -n 5500
+	run 'gc spectral-norm' a.$EXE -n 5500
+	run 'gc_B spectral-norm' a.$EXE -n 5500
 }
 
 knucleotide() {
@@ -189,9 +188,9 @@ knucleotide() {
 	fi
 	run 'gccgo -O2 k-nucleotide.go' a.$EXE <x
 	run 'gccgo -O2 k-nucleotide-parallel.go' a.$EXE <x
-	run 'gc k-nucleotide' $O.$EXE <x
-	run 'gc k-nucleotide-parallel' $O.$EXE <x
-	run 'gc_B k-nucleotide' $O.$EXE <x
+	run 'gc k-nucleotide' a.$EXE <x
+	run 'gc k-nucleotide-parallel' a.$EXE <x
+	run 'gc_B k-nucleotide' a.$EXE <x
 	rm x
 }
 
@@ -199,16 +198,16 @@ mandelbrot() {
 	runonly echo 'mandelbrot 16000'
 	run "gcc $gccm -O2 mandelbrot.c" a.$EXE 16000
 	run 'gccgo -O2 mandelbrot.go' a.$EXE -n 16000
-	run 'gc mandelbrot' $O.$EXE -n 16000
-	run 'gc_B mandelbrot' $O.$EXE -n 16000
+	run 'gc mandelbrot' a.$EXE -n 16000
+	run 'gc_B mandelbrot' a.$EXE -n 16000
 }
 
 meteor() {
 	runonly echo 'meteor 2098'
 	run "gcc $gccm -O2 meteor-contest.c" a.$EXE 2098
 	run 'gccgo -O2 meteor-contest.go' a.$EXE -n 2098
-	run 'gc meteor-contest' $O.$EXE -n 2098
-	run 'gc_B  meteor-contest' $O.$EXE -n 2098
+	run 'gc meteor-contest' a.$EXE -n 2098
+	run 'gc_B  meteor-contest' a.$EXE -n 2098
 }
 
 pidigits() {
@@ -217,22 +216,22 @@ pidigits() {
 		run "gcc $gccm -O2 pidigits.c -lgmp" a.$EXE 10000
 	fi
 	run 'gccgo -O2 pidigits.go' a.$EXE -n 10000
-	run 'gc pidigits' $O.$EXE -n 10000
-	run 'gc_B  pidigits' $O.$EXE -n 10000
+	run 'gc pidigits' a.$EXE -n 10000
+	run 'gc_B  pidigits' a.$EXE -n 10000
 }
 
 threadring() {
 	runonly echo 'threadring 50000000'
 	run "gcc $gccm -O2 threadring.c -lpthread" a.$EXE 50000000
 	run 'gccgo -O2 threadring.go' a.$EXE -n 50000000
-	run 'gc threadring' $O.$EXE -n 50000000
+	run 'gc threadring' a.$EXE -n 50000000
 }
 
 chameneos() {
 	runonly echo 'chameneos 6000000'
 	run "gcc $gccm -O2 chameneosredux.c -lpthread" a.$EXE 6000000
 	run 'gccgo -O2 chameneosredux.go' a.$EXE 6000000
-	run 'gc chameneosredux' $O.$EXE 6000000
+	run 'gc chameneosredux' a.$EXE 6000000
 }
 
 case $# in
@@ -248,3 +247,6 @@ do
 	$i
 	runonly echo
 done
+
+rm *.o *.$EXE # Clean up
+
diff --git a/test/bugs/bug395.go b/test/bugs/bug395.go
index 4632dcd..5490a3d 100644
--- a/test/bugs/bug395.go
+++ b/test/bugs/bug395.go
@@ -1,8 +1,6 @@
-// echo bug395 is broken  # takes 90+ seconds to break
-// # $G $D/$F.go || echo bug395
+// skip
 
-// NOTE: This test is not run by 'run.go' and so not run by all.bash.
-// To run this test you must use the ./run shell script.
+// When issue 1909 is fixed, change from skip to compile.
 
 // Copyright 2011 The Go Authors.  All rights reserved.
 // Use of this source code is governed by a BSD-style
@@ -10,6 +8,7 @@
 
 // Issue 1909
 // Would OOM due to exponential recursion on Foo's expanded methodset in nodefmt
+
 package test
 
 type Foo interface {
diff --git a/test/chan/select5.go b/test/chan/select5.go
index 1081cb2..cfdc085 100644
--- a/test/chan/select5.go
+++ b/test/chan/select5.go
@@ -28,7 +28,7 @@ func main() {
 	a := new(arg)
 
 	// Generate each test as a separate function to avoid
-	// hitting the 6g optimizer with one enormous function.
+	// hitting the gc optimizer with one enormous function.
 	// If we name all the functions init we don't have to
 	// maintain a list of which ones to run.
 	do := func(t *template.Template) {
diff --git a/test/chanlinear.go b/test/chanlinear.go
new file mode 100644
index 0000000..55fee4a
--- /dev/null
+++ b/test/chanlinear.go
@@ -0,0 +1,94 @@
+// +build darwin linux
+// run
+
+// 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.
+
+// Test that dequeueing from a pending channel doesn't
+// take linear time.
+
+package main
+
+import (
+	"fmt"
+	"runtime"
+	"time"
+)
+
+// checkLinear asserts that the running time of f(n) is in O(n).
+// tries is the initial number of iterations.
+func checkLinear(typ string, tries int, f func(n int)) {
+	// Depending on the machine and OS, this test might be too fast
+	// to measure with accurate enough granularity. On failure,
+	// make it run longer, hoping that the timing granularity
+	// is eventually sufficient.
+
+	timeF := func(n int) time.Duration {
+		t1 := time.Now()
+		f(n)
+		return time.Since(t1)
+	}
+
+	t0 := time.Now()
+
+	n := tries
+	fails := 0
+	for {
+		runtime.GC()
+		t1 := timeF(n)
+		runtime.GC()
+		t2 := timeF(2 * n)
+
+		// should be 2x (linear); allow up to 3x
+		if t2 < 3*t1 {
+			if false {
+				fmt.Println(typ, "\t", time.Since(t0))
+			}
+			return
+		}
+		// If n ops run in under a second and the ratio
+		// doesn't work out, make n bigger, trying to reduce
+		// the effect that a constant amount of overhead has
+		// on the computed ratio.
+		if t1 < 1*time.Second {
+			n *= 2
+			continue
+		}
+		// Once the test runs long enough for n ops,
+		// try to get the right ratio at least once.
+		// If five in a row all fail, give up.
+		if fails++; fails >= 5 {
+			panic(fmt.Sprintf("%s: too slow: %d channels: %v; %d channels: %v\n",
+				typ, n, t1, 2*n, t2))
+		}
+	}
+}
+
+func main() {
+	checkLinear("chanSelect", 1000, func(n int) {
+		const messages = 10
+		c := make(chan bool) // global channel
+		var a []chan bool    // local channels for each goroutine
+		for i := 0; i < n; i++ {
+			d := make(chan bool)
+			a = append(a, d)
+			go func() {
+				for j := 0; j < messages; j++ {
+					// queue ourselves on the global channel
+					select {
+					case <-c:
+					case <-d:
+					}
+				}
+			}()
+		}
+		for i := 0; i < messages; i++ {
+			// wake each goroutine up, forcing it to dequeue and then enqueue
+			// on the global channel.
+			for _, d := range a {
+				d <- true
+			}
+		}
+	})
+}
diff --git a/test/clearfat.go b/test/clearfat.go
new file mode 100644
index 0000000..45d5393
--- /dev/null
+++ b/test/clearfat.go
@@ -0,0 +1,68 @@
+// runoutput
+
+// 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.
+
+// Check that {5,6,8,9}g/ggen.c:clearfat is zeroing the entire object.
+
+package main
+
+import (
+	"bytes"
+	"fmt"
+	"strconv"
+	"strings"
+)
+
+const ntest = 1100
+
+func main() {
+	var decls, calls bytes.Buffer
+
+	for i := 1; i <= ntest; i++ {
+		s := strconv.Itoa(i)
+		decls.WriteString(strings.Replace(decl, "$", s, -1))
+		calls.WriteString(strings.Replace("poison$()\n\tclearfat$()\n\t", "$", s, -1))
+	}
+
+	program = strings.Replace(program, "$DECLS", decls.String(), 1)
+	program = strings.Replace(program, "$CALLS", calls.String(), 1)
+	fmt.Print(program)
+}
+
+var program = `package main
+
+var count int
+
+$DECLS
+
+func main() {
+	$CALLS
+	if count != 0 {
+		println("failed", count, "case(s)")
+	}
+}
+`
+
+const decl = `
+func poison$() {
+	// Grow and poison the stack space that will be used by clearfat$
+	var t [2*$]byte
+	for i := range t {
+		t[i] = 0xff
+	}
+}
+
+func clearfat$() {
+	var t [$]byte
+
+	for _, x := range t {
+		if x != 0 {
+//			println("clearfat$: index", i, "expected 0, got", x)
+			count++
+			break
+		}
+	}
+}
+`
diff --git a/test/closure1.go b/test/closure1.go
new file mode 100644
index 0000000..5869982
--- /dev/null
+++ b/test/closure1.go
@@ -0,0 +1,19 @@
+// 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.
+
+package main
+
+func main() {
+	x := 0
+	func() {
+		x = 1
+	}()
+	func() {
+		if x != 1 {
+			panic("x != 1")
+		}
+	}()
+}
\ No newline at end of file
diff --git a/test/closure2.go b/test/closure2.go
new file mode 100644
index 0000000..4d61b45
--- /dev/null
+++ b/test/closure2.go
@@ -0,0 +1,118 @@
+// 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.
+
+// Check that these do not use "by value" capturing,
+// because changes are made to the value during the closure.
+
+package main
+
+func main() {
+	{
+		type X struct {
+			v int
+		}
+		var x X
+		func() {
+			x.v++
+		}()
+		if x.v != 1 {
+			panic("x.v != 1")
+		}
+
+		type Y struct {
+			X
+		}
+		var y Y
+		func() {
+			y.v = 1
+		}()
+		if y.v != 1 {
+			panic("y.v != 1")
+		}
+	}
+
+	{
+		type Z struct {
+			a [3]byte
+		}
+		var z Z
+		func() {
+			i := 0
+			for z.a[1] = 1; i < 10; i++ {
+			}
+		}()
+		if z.a[1] != 1 {
+			panic("z.a[1] != 1")
+		}
+	}
+
+	{
+		w := 0
+		tmp := 0
+		f := func() {
+			if w != 1 {
+				panic("w != 1")
+			}
+		}
+		func() {
+			tmp = w // force capture of w, but do not write to it yet
+			_ = tmp
+			func() {
+				func() {
+					w++ // write in a nested closure
+				}()
+			}()
+		}()
+		f()
+	}
+
+	{
+		var g func() int
+		for i := range [2]int{} {
+			if i == 0 {
+				g = func() int {
+					return i // test that we capture by ref here, i is mutated on every interation
+				}
+			}
+		}
+		if g() != 1 {
+			panic("g() != 1")
+		}
+	}
+
+	{
+		var g func() int
+		q := 0
+		for range [2]int{} {
+			q++
+			g = func() int {
+				return q // test that we capture by ref here
+					 // q++ must on a different decldepth than q declaration
+			}
+		}
+		if g() != 2 {
+			panic("g() != 2")
+		}
+	}
+
+	{
+		var g func() int
+		var a [2]int
+		q := 0
+		for a[func() int {
+			q++
+			return 0
+		}()] = range [2]int{} {
+			g = func() int {
+				return q // test that we capture by ref here
+					 // q++ must on a different decldepth than q declaration
+			}
+		}
+		if g() != 2 {
+			panic("g() != 2")
+		}
+	}
+}
diff --git a/test/cmp.go b/test/cmp.go
index 80d1bf6..6db9ce5 100644
--- a/test/cmp.go
+++ b/test/cmp.go
@@ -115,7 +115,7 @@ func main() {
 	isfalse(ic != d)
 	isfalse(ie != e)
 
-	// 6g used to let this go through as true.
+	// gc used to let this go through as true.
 	var g uint64 = 123
 	var h int64 = 123
 	var ig interface{} = g
diff --git a/test/cmplxdivide.c b/test/cmplxdivide.c
index 12dc4f1..d654362 100644
--- a/test/cmplxdivide.c
+++ b/test/cmplxdivide.c
@@ -2,7 +2,18 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// gcc '-std=c99' cmplxdivide.c && a.out >cmplxdivide1.go
+// This C program generates the file cmplxdivide1.go. It uses the
+// output of the operations by C99 as the reference to check
+// the implementation of complex numbers in Go.
+// The generated file, cmplxdivide1.go, is compiled along
+// with the driver cmplxdivide.go (the names are confusing
+// and unimaginative) to run the actual test. This is done by
+// the usual test runner.
+//
+// The file cmplxdivide1.go is checked in to the repository, but
+// if it needs to be regenerated, compile and run this C program
+// like this:
+//	gcc '-std=c99' cmplxdivide.c && a.out >cmplxdivide1.go
 
 #include <complex.h>
 #include <math.h>
diff --git a/test/cmplxdivide.go b/test/cmplxdivide.go
index 40c8448..8e29672 100644
--- a/test/cmplxdivide.go
+++ b/test/cmplxdivide.go
@@ -5,6 +5,7 @@
 // license that can be found in the LICENSE file.
 
 // Driver for complex division table defined in cmplxdivide1.go
+// For details, see the comment at the top of in cmplxdivide.c.
 
 package main
 
diff --git a/test/complit1.go b/test/complit1.go
index 521401d..c7a2ac9 100644
--- a/test/complit1.go
+++ b/test/complit1.go
@@ -40,3 +40,17 @@ var (
 	_ = &T{i: 0, f: 0, s: "", next: {}} // ERROR "missing type in composite literal|omit types within composite literal"
 	_ = &T{0, 0, "", {}}                // ERROR "missing type in composite literal|omit types within composite literal"
 )
+
+type M map[T]T
+
+var (
+	_ = M{{i:1}: {i:2}}
+	_ = M{T{i:1}: {i:2}}
+	_ = M{{i:1}: T{i:2}}
+	_ = M{T{i:1}: T{i:2}}
+)
+
+type S struct { s [1]*M1 }
+type M1 map[S]int
+var _ = M1{{s:[1]*M1{&M1{{}:1}}}:2}
+
diff --git a/test/const4.go b/test/const4.go
index 2fb2d06..785e1ec 100644
--- a/test/const4.go
+++ b/test/const4.go
@@ -4,7 +4,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Test len constants and non-constants, http://golang.org/issue/3244.
+// Test len constants and non-constants, https://golang.org/issue/3244.
 
 package main
 
diff --git a/test/const5.go b/test/const5.go
index 60b4d0d..51e46cb 100644
--- a/test/const5.go
+++ b/test/const5.go
@@ -4,7 +4,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Test that len non-constants are not constants, http://golang.org/issue/3244.
+// Test that len non-constants are not constants, https://golang.org/issue/3244.
 
 package p
 
diff --git a/test/convlit.go b/test/convlit.go
index 8a6145d..904e1e6 100644
--- a/test/convlit.go
+++ b/test/convlit.go
@@ -9,6 +9,8 @@
 
 package main
 
+import "unsafe"
+
 // explicit conversion of constants
 var x1 = string(1)
 var x2 string = string(1)
@@ -18,6 +20,11 @@ var x5 = "a" + string(1)
 var x6 = int(1e100)      // ERROR "overflow"
 var x7 = float32(1e1000) // ERROR "overflow"
 
+// unsafe.Pointer can only convert to/from uintptr
+var _ = string(unsafe.Pointer(uintptr(65)))  // ERROR "convert"
+var _ = float64(unsafe.Pointer(uintptr(65))) // ERROR "convert"
+var _ = int(unsafe.Pointer(uintptr(65)))     // ERROR "convert"
+
 // implicit conversions merit scrutiny
 var s string
 var bad1 string = 1  // ERROR "conver|incompatible|invalid|cannot"
diff --git a/test/errchk b/test/errchk
index de0c4fd..b07bbc7 100755
--- a/test/errchk
+++ b/test/errchk
@@ -47,7 +47,7 @@ foreach $file (@file) {
 $cmd = join(' ', @ARGV);
 open(CMD, "exec $cmd </dev/null 2>&1 |") || die "BUG: errchk: run $cmd: $!";
 
-# 6g error messages continue onto additional lines with leading tabs.
+# gc error messages continue onto additional lines with leading tabs.
 # Split the output at the beginning of each line that doesn't begin with a tab.
 $out = join('', <CMD>);
 @out = split(/^(?!\t)/m, $out);
diff --git a/test/escape2.go b/test/escape2.go
index 6a46ce8..46cfde4 100644
--- a/test/escape2.go
+++ b/test/escape2.go
@@ -18,94 +18,94 @@ import (
 
 var gxx *int
 
-func foo1(x int) { // ERROR "moved to heap: x"
-	gxx = &x // ERROR "&x escapes to heap"
+func foo1(x int) { // ERROR "moved to heap: x$"
+	gxx = &x // ERROR "&x escapes to heap$"
 }
 
-func foo2(yy *int) { // ERROR "leaking param: yy"
+func foo2(yy *int) { // ERROR "leaking param: yy$"
 	gxx = yy
 }
 
-func foo3(x int) *int { // ERROR "moved to heap: x"
-	return &x // ERROR "&x escapes to heap"
+func foo3(x int) *int { // ERROR "moved to heap: x$"
+	return &x // ERROR "&x escapes to heap$"
 }
 
 type T *T
 
-func foo3b(t T) { // ERROR "leaking param: t"
+func foo3b(t T) { // ERROR "leaking param: t$"
 	*t = t
 }
 
 // xx isn't going anywhere, so use of yy is ok
-func foo4(xx, yy *int) { // ERROR "xx does not escape" "yy does not escape"
+func foo4(xx, yy *int) { // ERROR "foo4 xx does not escape$" "foo4 yy does not escape$"
 	xx = yy
 }
 
 // xx isn't going anywhere, so taking address of yy is ok
-func foo5(xx **int, yy *int) { // ERROR "xx does not escape" "yy does not escape"
-	xx = &yy // ERROR "&yy does not escape"
+func foo5(xx **int, yy *int) { // ERROR "foo5 xx does not escape$" "foo5 yy does not escape$"
+	xx = &yy // ERROR "foo5 &yy does not escape$"
 }
 
-func foo6(xx **int, yy *int) { // ERROR "xx does not escape" "leaking param: yy"
+func foo6(xx **int, yy *int) { // ERROR "foo6 xx does not escape$" "leaking param: yy$"
 	*xx = yy
 }
 
-func foo7(xx **int, yy *int) { // ERROR "xx does not escape" "yy does not escape"
+func foo7(xx **int, yy *int) { // ERROR "foo7 xx does not escape$" "foo7 yy does not escape$"
 	**xx = *yy
 }
 
-func foo8(xx, yy *int) int { // ERROR "xx does not escape" "yy does not escape"
+func foo8(xx, yy *int) int { // ERROR "foo8 xx does not escape$" "foo8 yy does not escape$"
 	xx = yy
 	return *xx
 }
 
-func foo9(xx, yy *int) *int { // ERROR "leaking param: xx" "leaking param: yy"
+func foo9(xx, yy *int) *int { // ERROR "leaking param: xx to result ~r2 level=0$" "leaking param: yy to result ~r2 level=0$"
 	xx = yy
 	return xx
 }
 
-func foo10(xx, yy *int) { // ERROR "xx does not escape" "yy does not escape"
+func foo10(xx, yy *int) { // ERROR "foo10 xx does not escape$" "foo10 yy does not escape$"
 	*xx = *yy
 }
 
 func foo11() int {
 	x, y := 0, 42
-	xx := &x // ERROR "&x does not escape"
-	yy := &y // ERROR "&y does not escape"
+	xx := &x // ERROR "foo11 &x does not escape$"
+	yy := &y // ERROR "foo11 &y does not escape$"
 	*xx = *yy
 	return x
 }
 
 var xxx **int
 
-func foo12(yyy **int) { // ERROR "leaking param: yyy"
+func foo12(yyy **int) { // ERROR "leaking param: yyy$"
 	xxx = yyy
 }
 
 // Must treat yyy as leaking because *yyy leaks, and the escape analysis
 // summaries in exported metadata do not distinguish these two cases.
-func foo13(yyy **int) { // ERROR "leaking param: yyy"
+func foo13(yyy **int) { // ERROR "leaking param content: yyy$"
 	*xxx = *yyy
 }
 
-func foo14(yyy **int) { // ERROR "yyy does not escape"
+func foo14(yyy **int) { // ERROR "foo14 yyy does not escape$"
 	**xxx = **yyy
 }
 
-func foo15(yy *int) { // ERROR "moved to heap: yy"
-	xxx = &yy // ERROR "&yy escapes to heap"
+func foo15(yy *int) { // ERROR "moved to heap: yy$"
+	xxx = &yy // ERROR "&yy escapes to heap$"
 }
 
-func foo16(yy *int) { // ERROR "leaking param: yy"
+func foo16(yy *int) { // ERROR "leaking param: yy$"
 	*xxx = yy
 }
 
-func foo17(yy *int) { // ERROR "yy does not escape"
+func foo17(yy *int) { // ERROR "foo17 yy does not escape$"
 	**xxx = *yy
 }
 
-func foo18(y int) { // ERROR "moved to heap: "y"
-	*xxx = &y // ERROR "&y escapes to heap"
+func foo18(y int) { // ERROR "moved to heap: y$"
+	*xxx = &y // ERROR "&y escapes to heap$"
 }
 
 func foo19(y int) {
@@ -118,52 +118,52 @@ type Bar struct {
 }
 
 func NewBar() *Bar {
-	return &Bar{42, nil} // ERROR "&Bar literal escapes to heap"
+	return &Bar{42, nil} // ERROR "&Bar literal escapes to heap$"
 }
 
-func NewBarp(x *int) *Bar { // ERROR "leaking param: x"
-	return &Bar{42, x} // ERROR "&Bar literal escapes to heap"
+func NewBarp(x *int) *Bar { // ERROR "leaking param: x to result ~r1 level=-1$"
+	return &Bar{42, x} // ERROR "&Bar literal escapes to heap$"
 }
 
-func NewBarp2(x *int) *Bar { // ERROR "x does not escape"
-	return &Bar{*x, nil} // ERROR "&Bar literal escapes to heap"
+func NewBarp2(x *int) *Bar { // ERROR "NewBarp2 x does not escape$"
+	return &Bar{*x, nil} // ERROR "&Bar literal escapes to heap$"
 }
 
-func (b *Bar) NoLeak() int { // ERROR "b does not escape"
+func (b *Bar) NoLeak() int { // ERROR "\(\*Bar\).NoLeak b does not escape$"
 	return *(b.ii)
 }
 
-func (b *Bar) Leak() *int { // ERROR "leaking param: b"
-	return &b.i // ERROR "&b.i escapes to heap"
+func (b *Bar) Leak() *int { // ERROR "leaking param: b to result ~r0 level=0$"
+	return &b.i // ERROR "&b.i escapes to heap$"
 }
 
-func (b *Bar) AlsoNoLeak() *int { // ERROR "leaking param b content to result ~r0"
+func (b *Bar) AlsoNoLeak() *int { // ERROR "leaking param: b to result ~r0 level=1$"
 	return b.ii
 }
 
-func (b Bar) AlsoLeak() *int { // ERROR "leaking param: b"
+func (b Bar) AlsoLeak() *int { // ERROR "leaking param: b to result ~r0 level=0$"
 	return b.ii
 }
 
-func (b Bar) LeaksToo() *int { // ERROR "leaking param: b"
-	v := 0    // ERROR "moved to heap: v"
-	b.ii = &v // ERROR "&v escapes"
+func (b Bar) LeaksToo() *int { // ERROR "leaking param: b to result ~r0 level=0$"
+	v := 0    // ERROR "moved to heap: v$"
+	b.ii = &v // ERROR "&v escapes to heap$"
 	return b.ii
 }
 
-func (b *Bar) LeaksABit() *int { // ERROR "leaking param b content to result ~r0"
-	v := 0    // ERROR "moved to heap: v"
-	b.ii = &v // ERROR "&v escapes"
+func (b *Bar) LeaksABit() *int { // ERROR "leaking param: b to result ~r0 level=1$"
+	v := 0    // ERROR "moved to heap: v$"
+	b.ii = &v // ERROR "&v escapes to heap$"
 	return b.ii
 }
 
-func (b Bar) StillNoLeak() int { // ERROR "b does not escape"
+func (b Bar) StillNoLeak() int { // ERROR "Bar.StillNoLeak b does not escape$"
 	v := 0
-	b.ii = &v // ERROR "&v does not escape"
+	b.ii = &v // ERROR "Bar.StillNoLeak &v does not escape$"
 	return b.i
 }
 
-func goLeak(b *Bar) { // ERROR "leaking param: b"
+func goLeak(b *Bar) { // ERROR "leaking param: b$"
 	go b.NoLeak()
 }
 
@@ -173,90 +173,105 @@ type Bar2 struct {
 }
 
 func NewBar2() *Bar2 {
-	return &Bar2{[12]int{42}, nil} // ERROR "&Bar2 literal escapes to heap"
+	return &Bar2{[12]int{42}, nil} // ERROR "&Bar2 literal escapes to heap$"
 }
 
-func (b *Bar2) NoLeak() int { // ERROR "b does not escape"
+func (b *Bar2) NoLeak() int { // ERROR "\(\*Bar2\).NoLeak b does not escape$"
 	return b.i[0]
 }
 
-func (b *Bar2) Leak() []int { // ERROR "leaking param: b"
-	return b.i[:] // ERROR "b.i escapes to heap"
+func (b *Bar2) Leak() []int { // ERROR "leaking param: b to result ~r0 level=0$"
+	return b.i[:] // ERROR "b.i escapes to heap$"
 }
 
-func (b *Bar2) AlsoNoLeak() []int { // ERROR "leaking param b content to result ~r0"
+func (b *Bar2) AlsoNoLeak() []int { // ERROR "leaking param: b to result ~r0 level=1$"
 	return b.ii[0:1]
 }
 
-func (b Bar2) AgainNoLeak() [12]int { // ERROR "b does not escape"
+func (b Bar2) AgainNoLeak() [12]int { // ERROR "Bar2.AgainNoLeak b does not escape$"
 	return b.i
 }
 
-func (b *Bar2) LeakSelf() { // ERROR "leaking param: b"
-	b.ii = b.i[0:4] // ERROR "b.i escapes to heap"
+func (b *Bar2) LeakSelf() { // ERROR "leaking param: b$"
+	b.ii = b.i[0:4] // ERROR "b.i escapes to heap$"
 }
 
-func (b *Bar2) LeakSelf2() { // ERROR "leaking param: b"
+func (b *Bar2) LeakSelf2() { // ERROR "leaking param: b$"
 	var buf []int
-	buf = b.i[0:] // ERROR "b.i escapes to heap"
+	buf = b.i[0:] // ERROR "b.i escapes to heap$"
 	b.ii = buf
 }
 
 func foo21() func() int {
-	x := 42             // ERROR "moved to heap: x"
-	return func() int { // ERROR "func literal escapes to heap"
-		return x // ERROR "&x escapes to heap"
+	x := 42
+	return func() int { // ERROR "func literal escapes to heap$"
+		return x
+	}
+}
+
+func foo21a() func() int {
+	x := 42             // ERROR "moved to heap: x$"
+	return func() int { // ERROR "func literal escapes to heap$"
+		x++ // ERROR "&x escapes to heap$"
+		return x
 	}
 }
 
 func foo22() int {
 	x := 42
-	return func() int { // ERROR "func literal does not escape"
+	return func() int { // ERROR "foo22 func literal does not escape$"
 		return x
 	}()
 }
 
-func foo23(x int) func() int { // ERROR "moved to heap: x"
-	return func() int { // ERROR "func literal escapes to heap"
-		return x // ERROR "&x escapes to heap"
+func foo23(x int) func() int {
+	return func() int { // ERROR "func literal escapes to heap$"
+		return x
 	}
 }
 
-func foo23a(x int) func() int { // ERROR "moved to heap: x"
-	f := func() int { // ERROR "func literal escapes to heap"
-		return x // ERROR "&x escapes to heap"
+func foo23a(x int) func() int {
+	f := func() int { // ERROR "func literal escapes to heap$"
+		return x
 	}
 	return f
 }
 
-func foo23b(x int) *(func() int) { // ERROR "moved to heap: x"
-	f := func() int { return x } // ERROR "moved to heap: f" "func literal escapes to heap" "&x escapes to heap"
-	return &f                    // ERROR "&f escapes to heap"
+func foo23b(x int) *(func() int) {
+	f := func() int { return x } // ERROR "func literal escapes to heap$" "moved to heap: f$"
+	return &f                    // ERROR "&f escapes to heap$"
+}
+
+func foo23c(x int) func() int { // ERROR "moved to heap: x$"
+	return func() int { // ERROR "func literal escapes to heap$"
+		x++ // ERROR "&x escapes to heap$"
+		return x
+	}
 }
 
 func foo24(x int) int {
-	return func() int { // ERROR "func literal does not escape"
+	return func() int { // ERROR "foo24 func literal does not escape$"
 		return x
 	}()
 }
 
 var x *int
 
-func fooleak(xx *int) int { // ERROR "leaking param: xx"
+func fooleak(xx *int) int { // ERROR "leaking param: xx$"
 	x = xx
 	return *x
 }
 
-func foonoleak(xx *int) int { // ERROR "xx does not escape"
+func foonoleak(xx *int) int { // ERROR "foonoleak xx does not escape$"
 	return *x + *xx
 }
 
-func foo31(x int) int { // ERROR "moved to heap: x"
-	return fooleak(&x) // ERROR "&x escapes to heap"
+func foo31(x int) int { // ERROR "moved to heap: x$"
+	return fooleak(&x) // ERROR "&x escapes to heap$"
 }
 
 func foo32(x int) int {
-	return foonoleak(&x) // ERROR "&x does not escape"
+	return foonoleak(&x) // ERROR "foo32 &x does not escape$"
 }
 
 type Foo struct {
@@ -267,114 +282,114 @@ type Foo struct {
 var F Foo
 var pf *Foo
 
-func (f *Foo) fooleak() { // ERROR "leaking param: f"
+func (f *Foo) fooleak() { // ERROR "leaking param: f$"
 	pf = f
 }
 
-func (f *Foo) foonoleak() { // ERROR "f does not escape"
+func (f *Foo) foonoleak() { // ERROR "\(\*Foo\).foonoleak f does not escape$"
 	F.x = f.x
 }
 
-func (f *Foo) Leak() { // ERROR "leaking param: f"
+func (f *Foo) Leak() { // ERROR "leaking param: f$"
 	f.fooleak()
 }
 
-func (f *Foo) NoLeak() { // ERROR "f does not escape"
+func (f *Foo) NoLeak() { // ERROR "\(\*Foo\).NoLeak f does not escape$"
 	f.foonoleak()
 }
 
-func foo41(x int) { // ERROR "moved to heap: x"
-	F.xx = &x // ERROR "&x escapes to heap"
+func foo41(x int) { // ERROR "moved to heap: x$"
+	F.xx = &x // ERROR "&x escapes to heap$"
 }
 
-func (f *Foo) foo42(x int) { // ERROR "f does not escape" "moved to heap: x"
-	f.xx = &x // ERROR "&x escapes to heap"
+func (f *Foo) foo42(x int) { // ERROR "\(\*Foo\).foo42 f does not escape$" "moved to heap: x$"
+	f.xx = &x // ERROR "&x escapes to heap$"
 }
 
-func foo43(f *Foo, x int) { // ERROR "f does not escape" "moved to heap: x"
-	f.xx = &x // ERROR "&x escapes to heap"
+func foo43(f *Foo, x int) { // ERROR "foo43 f does not escape$" "moved to heap: x$"
+	f.xx = &x // ERROR "&x escapes to heap$"
 }
 
-func foo44(yy *int) { // ERROR "leaking param: yy"
+func foo44(yy *int) { // ERROR "leaking param: yy$"
 	F.xx = yy
 }
 
-func (f *Foo) foo45() { // ERROR "f does not escape"
+func (f *Foo) foo45() { // ERROR "\(\*Foo\).foo45 f does not escape$"
 	F.x = f.x
 }
 
 // See foo13 above for explanation of why f leaks.
-func (f *Foo) foo46() { // ERROR "leaking param: f"
+func (f *Foo) foo46() { // ERROR "leaking param content: f$"
 	F.xx = f.xx
 }
 
-func (f *Foo) foo47() { // ERROR "leaking param: f"
-	f.xx = &f.x // ERROR "&f.x escapes to heap"
+func (f *Foo) foo47() { // ERROR "leaking param: f$"
+	f.xx = &f.x // ERROR "&f.x escapes to heap$"
 }
 
 var ptrSlice []*int
 
-func foo50(i *int) { // ERROR "leaking param: i"
+func foo50(i *int) { // ERROR "leaking param: i$"
 	ptrSlice[0] = i
 }
 
 var ptrMap map[*int]*int
 
-func foo51(i *int) { // ERROR "leaking param: i"
+func foo51(i *int) { // ERROR "leaking param: i$"
 	ptrMap[i] = i
 }
 
-func indaddr1(x int) *int { // ERROR "moved to heap: x"
-	return &x // ERROR "&x escapes to heap"
+func indaddr1(x int) *int { // ERROR "moved to heap: x$"
+	return &x // ERROR "&x escapes to heap$"
 }
 
-func indaddr2(x *int) *int { // ERROR "leaking param: x"
-	return *&x // ERROR "&x does not escape"
+func indaddr2(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$"
+	return *&x // ERROR "indaddr2 &x does not escape$"
 }
 
-func indaddr3(x *int32) *int { // ERROR "leaking param: x"
-	return *(**int)(unsafe.Pointer(&x)) // ERROR "&x does not escape"
+func indaddr3(x *int32) *int { // ERROR "leaking param: x to result ~r1 level=0$"
+	return *(**int)(unsafe.Pointer(&x)) // ERROR "indaddr3 &x does not escape$"
 }
 
 // From package math:
 
 func Float32bits(f float32) uint32 {
-	return *(*uint32)(unsafe.Pointer(&f)) // ERROR "&f does not escape"
+	return *(*uint32)(unsafe.Pointer(&f)) // ERROR "Float32bits &f does not escape$"
 }
 
 func Float32frombits(b uint32) float32 {
-	return *(*float32)(unsafe.Pointer(&b)) // ERROR "&b does not escape"
+	return *(*float32)(unsafe.Pointer(&b)) // ERROR "Float32frombits &b does not escape$"
 }
 
 func Float64bits(f float64) uint64 {
-	return *(*uint64)(unsafe.Pointer(&f)) // ERROR "&f does not escape"
+	return *(*uint64)(unsafe.Pointer(&f)) // ERROR "Float64bits &f does not escape$"
 }
 
 func Float64frombits(b uint64) float64 {
-	return *(*float64)(unsafe.Pointer(&b)) // ERROR "&b does not escape"
+	return *(*float64)(unsafe.Pointer(&b)) // ERROR "Float64frombits &b does not escape$"
 }
 
 // contrast with
-func float64bitsptr(f float64) *uint64 { // ERROR "moved to heap: f"
-	return (*uint64)(unsafe.Pointer(&f)) // ERROR "&f escapes to heap"
+func float64bitsptr(f float64) *uint64 { // ERROR "moved to heap: f$"
+	return (*uint64)(unsafe.Pointer(&f)) // ERROR "&f escapes to heap$"
 }
 
-func float64ptrbitsptr(f *float64) *uint64 { // ERROR "leaking param: f"
+func float64ptrbitsptr(f *float64) *uint64 { // ERROR "leaking param: f to result ~r1 level=0$"
 	return (*uint64)(unsafe.Pointer(f))
 }
 
-func typesw(i interface{}) *int { // ERROR "leaking param: i"
+func typesw(i interface{}) *int { // ERROR "leaking param: i to result ~r1 level=0$"
 	switch val := i.(type) {
 	case *int:
 		return val
 	case *int8:
-		v := int(*val) // ERROR "moved to heap: v"
-		return &v      // ERROR "&v escapes to heap"
+		v := int(*val) // ERROR "moved to heap: v$"
+		return &v      // ERROR "&v escapes to heap$"
 	}
 	return nil
 }
 
-func exprsw(i *int) *int { // ERROR "leaking param: i"
+func exprsw(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$"
 	switch j := i; *j + 110 {
 	case 12:
 		return j
@@ -386,20 +401,20 @@ func exprsw(i *int) *int { // ERROR "leaking param: i"
 }
 
 // assigning to an array element is like assigning to the array
-func foo60(i *int) *int { // ERROR "leaking param: i"
+func foo60(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$"
 	var a [12]*int
 	a[0] = i
 	return a[1]
 }
 
-func foo60a(i *int) *int { // ERROR "i does not escape"
+func foo60a(i *int) *int { // ERROR "foo60a i does not escape$"
 	var a [12]*int
 	a[0] = i
 	return nil
 }
 
 // assigning to a struct field  is like assigning to the struct
-func foo61(i *int) *int { // ERROR "leaking param: i"
+func foo61(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$"
 	type S struct {
 		a, b *int
 	}
@@ -408,7 +423,7 @@ func foo61(i *int) *int { // ERROR "leaking param: i"
 	return s.b
 }
 
-func foo61a(i *int) *int { // ERROR "i does not escape"
+func foo61a(i *int) *int { // ERROR "foo61a i does not escape$"
 	type S struct {
 		a, b *int
 	}
@@ -420,11 +435,11 @@ func foo61a(i *int) *int { // ERROR "i does not escape"
 // assigning to a struct field is like assigning to the struct but
 // here this subtlety is lost, since s.a counts as an assignment to a
 // track-losing dereference.
-func foo62(i *int) *int { // ERROR "leaking param: i"
+func foo62(i *int) *int { // ERROR "leaking param: i$"
 	type S struct {
 		a, b *int
 	}
-	s := new(S) // ERROR "new[(]S[)] does not escape"
+	s := new(S) // ERROR "foo62 new\(S\) does not escape$"
 	s.a = i
 	return nil // s.b
 }
@@ -433,14 +448,14 @@ type M interface {
 	M()
 }
 
-func foo63(m M) { // ERROR "m does not escape"
+func foo63(m M) { // ERROR "foo63 m does not escape$"
 }
 
-func foo64(m M) { // ERROR "leaking param: m"
+func foo64(m M) { // ERROR "leaking param: m$"
 	m.M()
 }
 
-func foo64b(m M) { // ERROR "leaking param: m"
+func foo64b(m M) { // ERROR "leaking param: m$"
 	defer m.M()
 }
 
@@ -450,55 +465,56 @@ func (MV) M() {}
 
 func foo65() {
 	var mv MV
-	foo63(&mv) // ERROR "&mv does not escape"
+	foo63(&mv) // ERROR "foo65 &mv does not escape$"
 }
 
 func foo66() {
-	var mv MV  // ERROR "moved to heap: mv"
-	foo64(&mv) // ERROR "&mv escapes to heap"
+	var mv MV  // ERROR "moved to heap: mv$"
+	foo64(&mv) // ERROR "&mv escapes to heap$"
 }
 
 func foo67() {
 	var mv MV
-	foo63(mv)
+	foo63(mv) // ERROR "foo67 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"
+func foo69(m M) { // ERROR "leaking param: m$"
 	foo64(m)
 }
 
-func foo70(mv1 *MV, m M) { // ERROR "leaking param: mv1" "leaking param: m"
-	m = mv1
+func foo70(mv1 *MV, m M) { // ERROR "leaking param: m$" "leaking param: mv1$"
+	m = mv1 // ERROR "mv1 escapes to heap$"
 	foo64(m)
 }
 
-func foo71(x *int) []*int { // ERROR "leaking param: x"
+func foo71(x *int) []*int { // ERROR "leaking param: x$"
 	var y []*int
 	y = append(y, x)
 	return y
 }
 
-func foo71a(x int) []*int { // ERROR "moved to heap: x"
+func foo71a(x int) []*int { // ERROR "moved to heap: x$"
 	var y []*int
-	y = append(y, &x) // ERROR "&x escapes to heap"
+	y = append(y, &x) // ERROR "&x escapes to heap$"
 	return y
 }
 
 func foo72() {
 	var x int
 	var y [1]*int
-	y[0] = &x // ERROR "&x does not escape"
+	y[0] = &x // ERROR "foo72 &x does not escape$"
 }
 
 func foo72aa() [10]*int {
-	var x int // ERROR "moved to heap: x"
+	var x int // ERROR "moved to heap: x$"
 	var y [10]*int
-	y[0] = &x // ERROR "&x escapes to heap"
+	y[0] = &x // ERROR "&x escapes to heap$"
 	return y
 }
 
@@ -506,8 +522,8 @@ func foo72a() {
 	var y [10]*int
 	for i := 0; i < 10; i++ {
 		// escapes its scope
-		x := i    // ERROR "moved to heap: x"
-		y[i] = &x // ERROR "&x escapes to heap"
+		x := i    // ERROR "moved to heap: x$"
+		y[i] = &x // ERROR "&x escapes to heap$"
 	}
 	return
 }
@@ -515,31 +531,56 @@ func foo72a() {
 func foo72b() [10]*int {
 	var y [10]*int
 	for i := 0; i < 10; i++ {
-		x := i    // ERROR "moved to heap: x"
-		y[i] = &x // ERROR "&x escapes to heap"
+		x := i    // ERROR "moved to heap: x$"
+		y[i] = &x // ERROR "&x escapes to heap$"
 	}
 	return y
 }
 
 // issue 2145
 func foo73() {
-	s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape"
+	s := []int{3, 2, 1} // ERROR "foo73 \[\]int literal does not escape$"
+	for _, v := range s {
+		vv := v
+		// actually just escapes its scope
+		defer func() { // ERROR "func literal escapes to heap$"
+			println(vv)
+		}()
+	}
+}
+
+func foo731() {
+	s := []int{3, 2, 1} // ERROR "foo731 \[\]int literal does not escape$"
 	for _, v := range s {
-		vv := v // ERROR "moved to heap: vv"
+		vv := v // ERROR "moved to heap: vv$"
 		// actually just escapes its scope
-		defer func() { // ERROR "func literal escapes to heap"
-			println(vv) // ERROR "&vv escapes to heap"
+		defer func() { // ERROR "func literal escapes to heap$"
+			vv = 42 // ERROR "&vv escapes to heap$"
+			println(vv)
 		}()
 	}
 }
 
 func foo74() {
-	s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape"
+	s := []int{3, 2, 1} // ERROR "foo74 \[\]int literal does not escape$"
 	for _, v := range s {
-		vv := v // ERROR "moved to heap: vv"
+		vv := v
 		// actually just escapes its scope
-		fn := func() { // ERROR "func literal escapes to heap"
-			println(vv) // ERROR "&vv escapes to heap"
+		fn := func() { // ERROR "func literal escapes to heap$"
+			println(vv)
+		}
+		defer fn()
+	}
+}
+
+func foo74a() {
+	s := []int{3, 2, 1} // ERROR "foo74a \[\]int literal does not escape$"
+	for _, v := range s {
+		vv := v // ERROR "moved to heap: vv$"
+		// actually just escapes its scope
+		fn := func() { // ERROR "func literal escapes to heap$"
+			vv += 1 // ERROR "&vv escapes to heap$"
+			println(vv)
 		}
 		defer fn()
 	}
@@ -548,110 +589,142 @@ func foo74() {
 // issue 3975
 func foo74b() {
 	var array [3]func()
-	s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape"
+	s := []int{3, 2, 1} // ERROR "foo74b \[\]int literal does not escape$"
 	for i, v := range s {
-		vv := v // ERROR "moved to heap: vv"
+		vv := v
 		// actually just escapes its scope
-		array[i] = func() { // ERROR "func literal escapes to heap"
-			println(vv) // ERROR "&vv escapes to heap"
+		array[i] = func() { // ERROR "func literal escapes to heap$"
+			println(vv)
 		}
 	}
 }
 
-func myprint(y *int, x ...interface{}) *int { // ERROR "x does not escape" "leaking param: y"
+func foo74c() {
+	var array [3]func()
+	s := []int{3, 2, 1} // ERROR "foo74c \[\]int literal does not escape$"
+	for i, v := range s {
+		vv := v // ERROR "moved to heap: vv$"
+		// actually just escapes its scope
+		array[i] = func() { // ERROR "func literal escapes to heap$"
+			println(&vv) // ERROR "&vv escapes to heap$" "foo74c.func1 &vv does not escape$"
+		}
+	}
+}
+
+func myprint(y *int, x ...interface{}) *int { // ERROR "leaking param: y to result ~r2 level=0$" "myprint x does not escape$"
 	return y
 }
 
-func myprint1(y *int, x ...interface{}) *interface{} { // ERROR "y does not escape" "leaking param: x"
-	return &x[0] // ERROR "&x.0. escapes to heap"
+func myprint1(y *int, x ...interface{}) *interface{} { // ERROR "leaking param: x to result ~r2 level=0$" "myprint1 y does not escape$"
+	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"
+func foo75(z *int) { // ERROR "foo75 z does not escape$"
+	myprint(z, 1, 2, 3) // ERROR "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "foo75 ... argument does not escape$"
 }
 
-func foo75a(z *int) { // ERROR "z does not escape"
-	myprint1(z, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
+func foo75a(z *int) { // ERROR "foo75a z does not escape$"
+	myprint1(z, 1, 2, 3) // ERROR "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "foo75a ... argument does not escape$"
 }
 
-func foo75esc(z *int) { // ERROR "leaking param: z"
-	gxx = myprint(z, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
+func foo75esc(z *int) { // ERROR "leaking param: z$"
+	gxx = myprint(z, 1, 2, 3) // ERROR "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "foo75esc ... argument does not escape$"
 }
 
-func foo75aesc(z *int) { // ERROR "z does not escape"
+func foo75aesc(z *int) { // ERROR "foo75aesc 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 "foo75aesc1 z does not escape$"
+	sink = myprint1(z, 1, 2, 3) // ERROR "... argument escapes to heap$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "myprint1\(z, 1, 2, 3\) escapes to heap$"
 }
 
-func foo76(z *int) { // ERROR "leaking param: z"
-	myprint(nil, z) // ERROR "[.][.][.] argument does not escape"
+// BAD: z does not escape here
+func foo76(z *int) { // ERROR "leaking param: z$"
+	myprint(nil, z) // ERROR "foo76 ... argument does not escape$" "z escapes to heap$"
 }
 
-func foo76a(z *int) { // ERROR "leaking param: z"
-	myprint1(nil, z) // ERROR "[.][.][.] argument does not escape"
+// BAD: z does not escape here
+func foo76a(z *int) { // ERROR "leaking param: z$"
+	myprint1(nil, z) // ERROR "foo76a ... 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 "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "foo76b ... argument does not escape$"
 }
 
 func foo76c() {
-	myprint1(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
+	myprint1(nil, 1, 2, 3) // ERROR "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "foo76c ... argument does not escape$"
 }
 
 func foo76d() {
-	defer myprint(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
+	defer myprint(nil, 1, 2, 3) // ERROR "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "foo76d ... argument does not escape$"
 }
 
 func foo76e() {
-	defer myprint1(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
+	defer myprint1(nil, 1, 2, 3) // ERROR "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "foo76e ... argument does not escape$"
 }
 
 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$"
 	}
 }
 
-func foo77(z []interface{}) { // ERROR "z does not escape"
+func foo77(z []interface{}) { // ERROR "foo77 z does not escape$"
 	myprint(nil, z...) // z does not escape
 }
 
-func foo77a(z []interface{}) { // ERROR "z does not escape"
+func foo77a(z []interface{}) { // ERROR "foo77a z does not escape$"
 	myprint1(nil, z...)
 }
 
-func foo77b(z []interface{}) { // ERROR "leaking param: z"
+func foo77b(z []interface{}) { // ERROR "leaking param: z$"
 	var ppi **interface{}
 	*ppi = myprint1(nil, z...)
 }
 
-func foo78(z int) *int { // ERROR "moved to heap: z"
-	return &z // ERROR "&z escapes to heap"
+func foo77c(z []interface{}) { // ERROR "leaking param: z$"
+	sink = myprint1(nil, z...) // ERROR "myprint1\(nil, z...\) escapes to heap$"
 }
 
-func foo78a(z int) *int { // ERROR "moved to heap: z"
-	y := &z   // ERROR "&z escapes to heap"
-	x := &y   // ERROR "&y does not escape"
+func dotdotdot() {
+	// BAD: i should not escape here
+	i := 0           // ERROR "moved to heap: i$"
+	myprint(nil, &i) // ERROR "&i escapes to heap$" "dotdotdot ... 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$" "dotdotdot ... argument does not escape$"
+}
+
+func foo78(z int) *int { // ERROR "moved to heap: z$"
+	return &z // ERROR "&z escapes to heap$"
+}
+
+func foo78a(z int) *int { // ERROR "moved to heap: z$"
+	y := &z   // ERROR "&z escapes to heap$"
+	x := &y   // ERROR "foo78a &y does not escape$"
 	return *x // really return y
 }
 
 func foo79() *int {
-	return new(int) // ERROR "new[(]int[)] escapes to heap"
+	return new(int) // ERROR "new\(int\) escapes to heap$"
 }
 
 func foo80() *int {
 	var z *int
 	for {
 		// Really just escapes its scope but we don't distinguish
-		z = new(int) // ERROR "new[(]int[)] escapes to heap"
+		z = new(int) // ERROR "new\(int\) escapes to heap$"
 	}
 	_ = z
 	return nil
@@ -659,24 +732,24 @@ func foo80() *int {
 
 func foo81() *int {
 	for {
-		z := new(int) // ERROR "new[(]int[)] does not escape"
+		z := new(int) // ERROR "foo81 new\(int\) does not escape$"
 		_ = z
 	}
 	return nil
 }
 
-func tee(p *int) (x, y *int) { return p, p } // ERROR "leaking param"
+func tee(p *int) (x, y *int) { return p, p } // ERROR "leaking param: p to result x level=0$" "leaking param: p to result y level=0$"
 
-func noop(x, y *int) {} // ERROR "does not escape"
+func noop(x, y *int) {} // ERROR "noop x does not escape$" "noop y does not escape$"
 
 func foo82() {
-	var x, y, z int  // ERROR "moved to heap"
-	go noop(tee(&z)) // ERROR "&z escapes to heap"
-	go noop(&x, &y)  // ERROR "escapes to heap"
+	var x, y, z int  // ERROR "moved to heap: x$" "moved to heap: y$" "moved to heap: z$"
+	go noop(tee(&z)) // ERROR "&z escapes to heap$"
+	go noop(&x, &y)  // ERROR "&x escapes to heap$" "&y escapes to heap$"
 	for {
-		var u, v, w int     // ERROR "moved to heap"
-		defer noop(tee(&u)) // ERROR "&u escapes to heap"
-		defer noop(&v, &w)  // ERROR "escapes to heap"
+		var u, v, w int     // ERROR "moved to heap: u$" "moved to heap: v$" "moved to heap: w$"
+		defer noop(tee(&u)) // ERROR "&u escapes to heap$"
+		defer noop(&v, &w)  // ERROR "&v escapes to heap$" "&w escapes to heap$"
 	}
 }
 
@@ -689,24 +762,24 @@ type LimitedFooer struct {
 	N int64
 }
 
-func LimitFooer(r Fooer, n int64) Fooer { // ERROR "leaking param: r"
-	return &LimitedFooer{r, n} // ERROR "&LimitedFooer literal escapes to heap"
+func LimitFooer(r Fooer, n int64) Fooer { // ERROR "leaking param: r to result ~r2 level=-1$"
+	return &LimitedFooer{r, n} // ERROR "&LimitedFooer literal escapes to heap$"
 }
 
-func foo90(x *int) map[*int]*int { // ERROR "leaking param: x"
-	return map[*int]*int{nil: x} // ERROR "map\[\*int\]\*int literal escapes to heap"
+func foo90(x *int) map[*int]*int { // ERROR "leaking param: x$"
+	return map[*int]*int{nil: x} // ERROR "map\[\*int\]\*int literal escapes to heap$"
 }
 
-func foo91(x *int) map[*int]*int { // ERROR "leaking param: x"
-	return map[*int]*int{x: nil} // ERROR "map\[\*int\]\*int literal escapes to heap"
+func foo91(x *int) map[*int]*int { // ERROR "leaking param: x$"
+	return map[*int]*int{x: nil} // ERROR "map\[\*int\]\*int literal escapes to heap$"
 }
 
-func foo92(x *int) [2]*int { // ERROR "leaking param: x"
+func foo92(x *int) [2]*int { // ERROR "leaking param: x to result ~r1 level=0$"
 	return [2]*int{x, nil}
 }
 
 // does not leak c
-func foo93(c chan *int) *int { // ERROR "c does not escape"
+func foo93(c chan *int) *int { // ERROR "foo93 c does not escape$"
 	for v := range c {
 		return v
 	}
@@ -714,7 +787,7 @@ func foo93(c chan *int) *int { // ERROR "c does not escape"
 }
 
 // does not leak m
-func foo94(m map[*int]*int, b bool) *int { // ERROR "m does not escape"
+func foo94(m map[*int]*int, b bool) *int { // ERROR "leaking param: m to result ~r2 level=1"
 	for k, v := range m {
 		if b {
 			return k
@@ -725,32 +798,32 @@ func foo94(m map[*int]*int, b bool) *int { // ERROR "m does not escape"
 }
 
 // does leak x
-func foo95(m map[*int]*int, x *int) { // ERROR "m does not escape" "leaking param: x"
+func foo95(m map[*int]*int, x *int) { // ERROR "foo95 m does not escape$" "leaking param: x$"
 	m[x] = x
 }
 
-// does not leak m
-func foo96(m []*int) *int { // ERROR "m does not escape"
+// does not leak m but does leak content
+func foo96(m []*int) *int { // ERROR "leaking param: m to result ~r1 level=1"
 	return m[0]
 }
 
 // does leak m
-func foo97(m [1]*int) *int { // ERROR "leaking param: m"
+func foo97(m [1]*int) *int { // ERROR "leaking param: m to result ~r1 level=0$"
 	return m[0]
 }
 
 // does not leak m
-func foo98(m map[int]*int) *int { // ERROR "m does not escape"
+func foo98(m map[int]*int) *int { // ERROR "foo98 m does not escape$"
 	return m[0]
 }
 
 // does leak m
-func foo99(m *[1]*int) []*int { // ERROR "leaking param: m"
+func foo99(m *[1]*int) []*int { // ERROR "leaking param: m to result ~r1 level=0$"
 	return m[:]
 }
 
 // does not leak m
-func foo100(m []*int) *int { // ERROR "m does not escape"
+func foo100(m []*int) *int { // ERROR "leaking param: m to result ~r1 level=1"
 	for _, v := range m {
 		return v
 	}
@@ -758,7 +831,7 @@ func foo100(m []*int) *int { // ERROR "m does not escape"
 }
 
 // does leak m
-func foo101(m [1]*int) *int { // ERROR "leaking param: m"
+func foo101(m [1]*int) *int { // ERROR "leaking param: m to result ~r1 level=0$"
 	for _, v := range m {
 		return v
 	}
@@ -766,109 +839,109 @@ func foo101(m [1]*int) *int { // ERROR "leaking param: m"
 }
 
 // does not leak m
-func foo101a(m [1]*int) *int { // ERROR "m does not escape"
-	for i := range m { // ERROR "moved to heap: i"
-		return &i // ERROR "&i escapes to heap"
+func foo101a(m [1]*int) *int { // ERROR "foo101a m does not escape$"
+	for i := range m { // ERROR "moved to heap: i$"
+		return &i // ERROR "&i escapes to heap$"
 	}
 	return nil
 }
 
 // does leak x
-func foo102(m []*int, x *int) { // ERROR "m does not escape" "leaking param: x"
+func foo102(m []*int, x *int) { // ERROR "foo102 m does not escape$" "leaking param: x$"
 	m[0] = x
 }
 
 // does not leak x
-func foo103(m [1]*int, x *int) { // ERROR "m does not escape" "x does not escape"
+func foo103(m [1]*int, x *int) { // ERROR "foo103 m does not escape$" "foo103 x does not escape$"
 	m[0] = x
 }
 
 var y []*int
 
-// does not leak x
-func foo104(x []*int) { // ERROR "x does not escape"
+// does not leak x but does leak content
+func foo104(x []*int) { // ERROR "leaking param content: x"
 	copy(y, x)
 }
 
-// does not leak x
-func foo105(x []*int) { // ERROR "x does not escape"
+// does not leak x but does leak content
+func foo105(x []*int) { // ERROR "leaking param content: x"
 	_ = append(y, x...)
 }
 
 // does leak x
-func foo106(x *int) { // ERROR "leaking param: x"
+func foo106(x *int) { // ERROR "leaking param: x$"
 	_ = append(y, x)
 }
 
-func foo107(x *int) map[*int]*int { // ERROR "leaking param: x"
-	return map[*int]*int{x: nil} // ERROR "map.* literal escapes to heap"
+func foo107(x *int) map[*int]*int { // ERROR "leaking param: x$"
+	return map[*int]*int{x: nil} // ERROR "map\[\*int\]\*int literal escapes to heap$"
 }
 
-func foo108(x *int) map[*int]*int { // ERROR "leaking param: x"
-	return map[*int]*int{nil: x} // ERROR "map.* literal escapes to heap"
+func foo108(x *int) map[*int]*int { // ERROR "leaking param: x$"
+	return map[*int]*int{nil: x} // ERROR "map\[\*int\]\*int literal escapes to heap$"
 }
 
-func foo109(x *int) *int { // ERROR "leaking param: x"
-	m := map[*int]*int{x: nil} // ERROR "map.* literal does not escape"
+func foo109(x *int) *int { // ERROR "leaking param: x$"
+	m := map[*int]*int{x: nil} // ERROR "foo109 map\[\*int\]\*int literal does not escape$"
 	for k, _ := range m {
 		return k
 	}
 	return nil
 }
 
-func foo110(x *int) *int { // ERROR "leaking param: x"
-	m := map[*int]*int{nil: x} // ERROR "map.* literal does not escape"
+func foo110(x *int) *int { // ERROR "leaking param: x$"
+	m := map[*int]*int{nil: x} // ERROR "foo110 map\[\*int\]\*int literal does not escape$"
 	return m[nil]
 }
 
-func foo111(x *int) *int { // ERROR "leaking param: x"
-	m := []*int{x} // ERROR "\[\]\*int literal does not escape"
+func foo111(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0"
+	m := []*int{x} // ERROR "foo111 \[\]\*int literal does not escape$"
 	return m[0]
 }
 
-func foo112(x *int) *int { // ERROR "leaking param: x"
+func foo112(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$"
 	m := [1]*int{x}
 	return m[0]
 }
 
-func foo113(x *int) *int { // ERROR "leaking param: x"
+func foo113(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$"
 	m := Bar{ii: x}
 	return m.ii
 }
 
-func foo114(x *int) *int { // ERROR "leaking param: x"
-	m := &Bar{ii: x} // ERROR "&Bar literal does not escape"
+func foo114(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$"
+	m := &Bar{ii: x} // ERROR "foo114 &Bar literal does not escape$"
 	return m.ii
 }
 
-func foo115(x *int) *int { // ERROR "leaking param: x"
+func foo115(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$"
 	return (*int)(unsafe.Pointer(uintptr(unsafe.Pointer(x)) + 1))
 }
 
 func foo116(b bool) *int {
 	if b {
-		x := 1    // ERROR "moved to heap: x"
-		return &x // ERROR "&x escapes to heap"
+		x := 1    // ERROR "moved to heap: x$"
+		return &x // ERROR "&x escapes to heap$"
 	} else {
-		y := 1    // ERROR "moved to heap: y"
-		return &y // ERROR "&y escapes to heap"
+		y := 1    // ERROR "moved to heap: y$"
+		return &y // ERROR "&y escapes to heap$"
 	}
 	return nil
 }
 
-func foo117(unknown func(interface{})) { // ERROR "unknown does not escape"
-	x := 1      // ERROR "moved to heap: x"
-	unknown(&x) // ERROR "&x escapes to heap"
+func foo117(unknown func(interface{})) { // ERROR "foo117 unknown does not escape$"
+	x := 1      // ERROR "moved to heap: x$"
+	unknown(&x) // ERROR "&x escapes to heap$"
 }
 
-func foo118(unknown func(*int)) { // ERROR "unknown does not escape"
-	x := 1      // ERROR "moved to heap: x"
-	unknown(&x) // ERROR "&x escapes to heap"
+func foo118(unknown func(*int)) { // ERROR "foo118 unknown does not escape$"
+	x := 1      // ERROR "moved to heap: x$"
+	unknown(&x) // ERROR "&x escapes to heap$"
 }
 
 func external(*int)
 
-func foo119(x *int) { // ERROR "leaking param: x"
+func foo119(x *int) { // ERROR "leaking param: x$"
 	external(x)
 }
 
@@ -1079,16 +1152,16 @@ L100:
 
 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$"
 	}
 }
 
@@ -1098,7 +1171,7 @@ func foo122() {
 
 	goto L1
 L1:
-	i = new(int) // ERROR "new.int. does not escape"
+	i = new(int) // ERROR "foo122 new\(int\) does not escape$"
 	_ = i
 }
 
@@ -1107,25 +1180,25 @@ func foo123() {
 	var i *int
 
 L1:
-	i = new(int) // ERROR "new.int. escapes to heap"
+	i = new(int) // ERROR "new\(int\) escapes to heap$"
 
 	goto L1
 	_ = i
 }
 
-func foo124(x **int) { // ERROR "x does not escape"
-	var i int // ERROR "moved to heap: i"
-	p := &i   // ERROR "&i escapes"
-	func() {  // ERROR "func literal does not escape"
-		*x = p // ERROR "leaking closure reference p"
+func foo124(x **int) { // ERROR "foo124 x does not escape$"
+	var i int // ERROR "moved to heap: i$"
+	p := &i   // ERROR "&i escapes to heap$"
+	func() {  // ERROR "foo124 func literal does not escape$"
+		*x = p // ERROR "leaking closure reference p$"
 	}()
 }
 
-func foo125(ch chan *int) { // ERROR "does not escape"
-	var i int // ERROR "moved to heap"
-	p := &i   // ERROR "&i escapes to heap"
-	func() {  // ERROR "func literal does not escape"
-		ch <- p // ERROR "leaking closure reference p"
+func foo125(ch chan *int) { // ERROR "foo125 ch does not escape$"
+	var i int // ERROR "moved to heap: i$"
+	p := &i   // ERROR "&i escapes to heap$"
+	func() {  // ERROR "foo125 func literal does not escape$"
+		ch <- p // ERROR "leaking closure reference p$"
 	}()
 }
 
@@ -1133,9 +1206,9 @@ func foo126() {
 	var px *int // loopdepth 0
 	for {
 		// loopdepth 1
-		var i int // ERROR "moved to heap"
-		func() {  // ERROR "func literal does not escape"
-			px = &i // ERROR "&i escapes"
+		var i int // ERROR "moved to heap: i$"
+		func() {  // ERROR "foo126 func literal does not escape$"
+			px = &i // ERROR "&i escapes to heap$"
 		}()
 	}
 	_ = px
@@ -1144,26 +1217,26 @@ func foo126() {
 var px *int
 
 func foo127() {
-	var i int // ERROR "moved to heap: i"
-	p := &i   // ERROR "&i escapes to heap"
+	var i int // ERROR "moved to heap: i$"
+	p := &i   // ERROR "&i escapes to heap$"
 	q := p
 	px = q
 }
 
 func foo128() {
 	var i int
-	p := &i // ERROR "&i does not escape"
+	p := &i // ERROR "foo128 &i does not escape$"
 	q := p
 	_ = q
 }
 
 func foo129() {
-	var i int // ERROR "moved to heap: i"
-	p := &i   // ERROR "&i escapes to heap"
-	func() {  // ERROR "func literal does not escape"
-		q := p   // ERROR "leaking closure reference p"
-		func() { // ERROR "func literal does not escape"
-			r := q // ERROR "leaking closure reference q"
+	var i int // ERROR "moved to heap: i$"
+	p := &i   // ERROR "&i escapes to heap$"
+	func() {  // ERROR "foo129 func literal does not escape$"
+		q := p   // ERROR "leaking closure reference p$"
+		func() { // ERROR "foo129.func1 func literal does not escape$"
+			r := q // ERROR "leaking closure reference q$"
 			px = r
 		}()
 	}()
@@ -1171,40 +1244,40 @@ func foo129() {
 
 func foo130() {
 	for {
-		var i int // ERROR "moved to heap"
-		func() {  // ERROR "func literal does not escape"
-			px = &i // ERROR "&i escapes" "leaking closure reference i"
+		var i int // ERROR "moved to heap: i$"
+		func() {  // ERROR "foo130 func literal does not escape$"
+			px = &i // ERROR "&i escapes to heap$" "leaking closure reference i$"
 		}()
 	}
 }
 
 func foo131() {
-	var i int // ERROR "moved to heap"
-	func() {  // ERROR "func literal does not escape"
-		px = &i // ERROR "&i escapes" "leaking closure reference i"
+	var i int // ERROR "moved to heap: i$"
+	func() {  // ERROR "foo131 func literal does not escape$"
+		px = &i // ERROR "&i escapes to heap$" "leaking closure reference i$"
 	}()
 }
 
 func foo132() {
-	var i int   // ERROR "moved to heap"
-	go func() { // ERROR "func literal escapes to heap"
-		px = &i // ERROR "&i escapes" "leaking closure reference i"
+	var i int   // ERROR "moved to heap: i$"
+	go func() { // ERROR "func literal escapes to heap$"
+		px = &i // ERROR "&i escapes to heap$" "leaking closure reference i$"
 	}()
 }
 
 func foo133() {
-	var i int      // ERROR "moved to heap"
-	defer func() { // ERROR "func literal does not escape"
-		px = &i // ERROR "&i escapes" "leaking closure reference i"
+	var i int      // ERROR "moved to heap: i$"
+	defer func() { // ERROR "foo133 func literal does not escape$"
+		px = &i // ERROR "&i escapes to heap$" "leaking closure reference i$"
 	}()
 }
 
 func foo134() {
 	var i int
-	p := &i  // ERROR "&i does not escape"
-	func() { // ERROR "func literal does not escape"
+	p := &i  // ERROR "foo134 &i does not escape$"
+	func() { // ERROR "foo134 func literal does not escape$"
 		q := p
-		func() { // ERROR "func literal does not escape"
+		func() { // ERROR "foo134.func1 func literal does not escape$"
 			r := q
 			_ = r
 		}()
@@ -1212,11 +1285,11 @@ func foo134() {
 }
 
 func foo135() {
-	var i int   // ERROR "moved to heap: i"
-	p := &i     // ERROR "&i escapes to heap" "moved to heap: p"
-	go func() { // ERROR "func literal escapes to heap"
-		q := p   // ERROR "&p escapes to heap"
-		func() { // ERROR "func literal does not escape"
+	var i int   // ERROR "moved to heap: i$"
+	p := &i     // ERROR "&i escapes to heap$"
+	go func() { // ERROR "func literal escapes to heap$"
+		q := p
+		func() { // ERROR "foo135.func1 func literal does not escape$"
 			r := q
 			_ = r
 		}()
@@ -1224,24 +1297,24 @@ func foo135() {
 }
 
 func foo136() {
-	var i int   // ERROR "moved to heap: i"
-	p := &i     // ERROR "&i escapes to heap" "moved to heap: p"
-	go func() { // ERROR "func literal escapes to heap"
-		q := p   // ERROR "&p escapes to heap" "leaking closure reference p"
-		func() { // ERROR "func literal does not escape"
-			r := q // ERROR "leaking closure reference q"
+	var i int   // ERROR "moved to heap: i$"
+	p := &i     // ERROR "&i escapes to heap$"
+	go func() { // ERROR "func literal escapes to heap$"
+		q := p   // ERROR "leaking closure reference p$"
+		func() { // ERROR "foo136.func1 func literal does not escape$"
+			r := q // ERROR "leaking closure reference q$"
 			px = r
 		}()
 	}()
 }
 
 func foo137() {
-	var i int // ERROR "moved to heap: i"
-	p := &i   // ERROR "&i escapes to heap"
-	func() {  // ERROR "func literal does not escape"
-		q := p      // ERROR "leaking closure reference p" "moved to heap: q"
-		go func() { // ERROR "func literal escapes to heap"
-			r := q // ERROR "&q escapes to heap"
+	var i int // ERROR "moved to heap: i$"
+	p := &i   // ERROR "&i escapes to heap$"
+	func() {  // ERROR "foo137 func literal does not escape$"
+		q := p      // ERROR "leaking closure reference p$"
+		go func() { // ERROR "func literal escapes to heap$"
+			r := q
 			_ = r
 		}()
 	}()
@@ -1251,8 +1324,8 @@ func foo138() *byte {
 	type T struct {
 		x [1]byte
 	}
-	t := new(T)    // ERROR "new.T. escapes to heap"
-	return &t.x[0] // ERROR "&t.x.0. escapes to heap"
+	t := new(T)    // ERROR "new\(T\) escapes to heap$"
+	return &t.x[0] // ERROR "&t.x\[0\] escapes to heap$"
 }
 
 func foo139() *byte {
@@ -1261,8 +1334,8 @@ func foo139() *byte {
 			y byte
 		}
 	}
-	t := new(T)   // ERROR "new.T. escapes to heap"
-	return &t.x.y // ERROR "&t.x.y escapes to heap"
+	t := new(T)   // ERROR "new\(T\) escapes to heap$"
+	return &t.x.y // ERROR "&t.x.y escapes to heap$"
 }
 
 // issue 4751
@@ -1274,8 +1347,8 @@ func foo140() interface{} {
 		X string
 		T *T
 	}
-	t := &T{} // ERROR "&T literal escapes to heap"
-	return U{
+	t := &T{} // ERROR "&T literal escapes to heap$"
+	return U{ // ERROR "U literal escapes to heap$"
 		X: t.X,
 		T: t,
 	}
@@ -1289,53 +1362,53 @@ func F2([]byte)
 
 //go:noescape
 
-func F3(x []byte) // ERROR "F3 x does not escape"
+func F3(x []byte) // ERROR "F3 x does not escape$"
 
 func F4(x []byte)
 
 func G() {
 	var buf1 [10]byte
-	F1(buf1[:]) // ERROR "buf1 does not escape"
+	F1(buf1[:]) // ERROR "G buf1 does not escape$"
 
-	var buf2 [10]byte // ERROR "moved to heap: buf2"
-	F2(buf2[:])       // ERROR "buf2 escapes to heap"
+	var buf2 [10]byte // ERROR "moved to heap: buf2$"
+	F2(buf2[:])       // ERROR "buf2 escapes to heap$"
 
 	var buf3 [10]byte
-	F3(buf3[:]) // ERROR "buf3 does not escape"
+	F3(buf3[:]) // ERROR "G buf3 does not escape$"
 
-	var buf4 [10]byte // ERROR "moved to heap: buf4"
-	F4(buf4[:])       // ERROR "buf4 escapes to heap"
+	var buf4 [10]byte // ERROR "moved to heap: buf4$"
+	F4(buf4[:])       // ERROR "buf4 escapes to heap$"
 }
 
 type Tm struct {
 	x int
 }
 
-func (t *Tm) M() { // ERROR "t does not escape"
+func (t *Tm) M() { // ERROR "\(\*Tm\).M t does not escape$"
 }
 
 func foo141() {
 	var f func()
 
-	t := new(Tm) // ERROR "escapes to heap"
-	f = t.M      // ERROR "t.M does not escape"
+	t := new(Tm) // ERROR "new\(Tm\) escapes to heap$"
+	f = t.M      // ERROR "foo141 t.M does not escape$"
 	_ = f
 }
 
 var gf func()
 
 func foo142() {
-	t := new(Tm) // ERROR "escapes to heap"
-	gf = t.M     // ERROR "t.M escapes to heap"
+	t := new(Tm) // ERROR "new\(Tm\) escapes to heap$"
+	gf = t.M     // ERROR "t.M escapes to heap$"
 }
 
 // issue 3888.
 func foo143() {
 	for i := 0; i < 1000; i++ {
-		func() { // ERROR "func literal does not escape"
+		func() { // ERROR "foo143 func literal does not escape$"
 			for i := 0; i < 1; i++ {
 				var t Tm
-				t.M() // ERROR "t does not escape"
+				t.M() // ERROR "foo143.func1 t does not escape$"
 			}
 		}()
 	}
@@ -1351,9 +1424,9 @@ func foo144a(*int)
 
 func foo144() {
 	var x int
-	foo144a(&x) // ERROR "&x does not escape"
+	foo144a(&x) // ERROR "foo144 &x does not escape$"
 	var y int
-	foo144b(&y) // ERROR "&y does not escape"
+	foo144b(&y) // ERROR "foo144 &y does not escape$"
 }
 
 //go:noescape
@@ -1366,38 +1439,38 @@ type List struct {
 	Next *List
 }
 
-func foo145(l List) { // ERROR "l does not escape"
+func foo145(l List) { // ERROR "foo145 l does not escape$"
 	var p *List
-	for p = &l; p.Next != nil; p = p.Next { // ERROR "&l does not escape"
+	for p = &l; p.Next != nil; p = p.Next { // ERROR "foo145 &l does not escape$"
 	}
 }
 
-func foo146(l List) { // ERROR "l does not escape"
+func foo146(l List) { // ERROR "foo146 l does not escape$"
 	var p *List
-	p = &l // ERROR "&l does not escape"
+	p = &l // ERROR "foo146 &l does not escape$"
 	for ; p.Next != nil; p = p.Next {
 	}
 }
 
-func foo147(l List) { // ERROR "l does not escape"
+func foo147(l List) { // ERROR "foo147 l does not escape$"
 	var p *List
-	p = &l // ERROR "&l does not escape"
+	p = &l // ERROR "foo147 &l does not escape$"
 	for p.Next != nil {
 		p = p.Next
 	}
 }
 
-func foo148(l List) { // ERROR " l does not escape"
-	for p := &l; p.Next != nil; p = p.Next { // ERROR "&l does not escape"
+func foo148(l List) { // ERROR "foo148 l does not escape$"
+	for p := &l; p.Next != nil; p = p.Next { // ERROR "foo148 &l does not escape$"
 	}
 }
 
 // related: address of variable should have depth of variable, not of loop
 
-func foo149(l List) { // ERROR " l does not escape"
+func foo149(l List) { // ERROR "foo149 l does not escape$"
 	var p *List
 	for {
-		for p = &l; p.Next != nil; p = p.Next { // ERROR "&l does not escape"
+		for p = &l; p.Next != nil; p = p.Next { // ERROR "foo149 &l does not escape$"
 		}
 	}
 }
@@ -1406,44 +1479,44 @@ func foo149(l List) { // ERROR " l does not escape"
 
 var save150 []byte
 
-func foo150(x ...byte) { // ERROR "leaking param: x"
+func foo150(x ...byte) { // ERROR "leaking param: x$"
 	save150 = x
 }
 
 func bar150() {
-	foo150(1, 2, 3) // ERROR "[.][.][.] argument escapes to heap"
+	foo150(1, 2, 3) // ERROR "... argument escapes to heap$"
 }
 
 // issue 7931: bad handling of slice of array
 
 var save151 *int
 
-func foo151(x *int) { // ERROR "leaking param: x"
+func foo151(x *int) { // ERROR "leaking param: x$"
 	save151 = x
 }
 
 func bar151() {
-	var a [64]int // ERROR "moved to heap: a"
+	var a [64]int // ERROR "moved to heap: a$"
 	a[4] = 101
-	foo151(&(&a)[4:8][0]) // ERROR "&\(&a\)\[4:8\]\[0\] escapes to heap" "&a escapes to heap"
+	foo151(&(&a)[4:8][0]) // ERROR "&\(&a\)\[4:8\]\[0\] escapes to heap$" "&a escapes to heap$"
 }
 
 func bar151b() {
-	var a [10]int      // ERROR "moved to heap: a"
-	b := a[:]          // ERROR "a escapes to heap"
-	foo151(&b[4:8][0]) // ERROR "&b\[4:8\]\[0\] escapes to heap"
+	var a [10]int      // ERROR "moved to heap: a$"
+	b := a[:]          // ERROR "a escapes to heap$"
+	foo151(&b[4:8][0]) // ERROR "&b\[4:8\]\[0\] escapes to heap$"
 }
 
 func bar151c() {
-	var a [64]int // ERROR "moved to heap: a"
+	var a [64]int // ERROR "moved to heap: a$"
 	a[4] = 101
-	foo151(&(&a)[4:8:8][0]) // ERROR "&\(&a\)\[4:8:8\]\[0\] escapes to heap" "&a escapes to heap"
+	foo151(&(&a)[4:8:8][0]) // ERROR "&\(&a\)\[4:8:8\]\[0\] escapes to heap$" "&a escapes to heap$"
 }
 
 func bar151d() {
-	var a [10]int        // ERROR "moved to heap: a"
-	b := a[:]            // ERROR "a escapes to heap"
-	foo151(&b[4:8:8][0]) // ERROR "&b\[4:8:8\]\[0\] escapes to heap"
+	var a [10]int        // ERROR "moved to heap: a$"
+	b := a[:]            // ERROR "a escapes to heap$"
+	foo151(&b[4:8:8][0]) // ERROR "&b\[4:8:8\]\[0\] escapes to heap$"
 }
 
 // issue 8120
@@ -1452,7 +1525,7 @@ type U struct {
 	s *string
 }
 
-func (u *U) String() *string { // ERROR "leaking param u content to result ~r0"
+func (u *U) String() *string { // ERROR "leaking param: u to result ~r0 level=1$"
 	return u.s
 }
 
@@ -1460,35 +1533,298 @@ type V struct {
 	s *string
 }
 
-func NewV(u U) *V { // ERROR "leaking param: u"
-	return &V{u.String()} // ERROR "&V literal escapes to heap" "u does not escape"
+// BAD -- level of leak ought to be 0
+func NewV(u U) *V { // ERROR "leaking param: u to result ~r1 level=-1"
+	return &V{u.String()} // ERROR "&V literal escapes to heap$" "NewV u does not escape"
 }
 
 func foo152() {
-	a := "a"   // ERROR "moved to heap: a"
-	u := U{&a} // ERROR "&a escapes to heap"
+	a := "a"   // ERROR "moved to heap: a$"
+	u := U{&a} // ERROR "&a escapes to heap$"
 	v := NewV(u)
 	println(v)
 }
 
 // issue 8176 - &x in type switch body not marked as escaping
 
-func foo153(v interface{}) *int { // ERROR "leaking param: v"
+func foo153(v interface{}) *int { // ERROR "leaking param: v to result ~r1 level=-1$"
 	switch x := v.(type) {
-	case int: // ERROR "moved to heap: x"
-		return &x // ERROR "&x escapes to heap"
+	case int: // ERROR "moved to heap: x$"
+		return &x // ERROR "&x escapes to heap$"
 	}
 	panic(0)
 }
 
 // issue 8185 - &result escaping into result
 
-func f() (x int, y *int) { // ERROR "moved to heap: x"
-	y = &x // ERROR "&x escapes to heap"
+func f() (x int, y *int) { // ERROR "moved to heap: x$"
+	y = &x // ERROR "&x escapes to heap$"
 	return
 }
 
-func g() (x interface{}) { // ERROR "moved to heap: x"
-	x = &x // ERROR "&x escapes to heap"
+func g() (x interface{}) { // ERROR "moved to heap: x$"
+	x = &x // ERROR "&x escapes to heap$"
 	return
 }
+
+var sink interface{}
+
+type Lit struct {
+	p *int
+}
+
+func ptrlitNoescape() {
+	// Both literal and element do not escape.
+	i := 0
+	x := &Lit{&i} // ERROR "ptrlitNoescape &Lit literal does not escape$" "ptrlitNoescape &i does not escape$"
+	_ = x
+}
+
+func ptrlitNoEscape2() {
+	// Literal does not escape, but element does.
+	i := 0        // ERROR "moved to heap: i$"
+	x := &Lit{&i} // ERROR "&i escapes to heap$" "ptrlitNoEscape2 &Lit literal does not escape$"
+	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      // ERROR "x escapes to heap$"
+}
+
+// self-assignments
+
+type Buffer struct {
+	arr  [64]byte
+	buf1 []byte
+	buf2 []byte
+	str1 string
+	str2 string
+}
+
+func (b *Buffer) foo() { // ERROR "\(\*Buffer\).foo b does not escape$"
+	b.buf1 = b.buf1[1:2]   // ERROR "\(\*Buffer\).foo ignoring self-assignment to b.buf1$"
+	b.buf1 = b.buf1[1:2:3] // ERROR "\(\*Buffer\).foo ignoring self-assignment to b.buf1$"
+	b.buf1 = b.buf2[1:2]   // ERROR "\(\*Buffer\).foo ignoring self-assignment to b.buf1$"
+	b.buf1 = b.buf2[1:2:3] // ERROR "\(\*Buffer\).foo ignoring self-assignment to b.buf1$"
+}
+
+func (b *Buffer) bar() { // ERROR "leaking param: b$"
+	b.buf1 = b.arr[1:2] // ERROR "b.arr escapes to heap$"
+}
+
+func (b *Buffer) baz() { // ERROR "\(\*Buffer\).baz b does not escape$"
+	b.str1 = b.str1[1:2] // ERROR "\(\*Buffer\).baz ignoring self-assignment to b.str1$"
+	b.str1 = b.str2[1:2] // ERROR "\(\*Buffer\).baz ignoring self-assignment to b.str1$"
+}
+
+func (b *Buffer) bat() { // ERROR "leaking param content: b$"
+	o := new(Buffer) // ERROR "new\(Buffer\) escapes to heap$"
+	o.buf1 = b.buf1[1:2]
+	sink = o // ERROR "o escapes to heap$"
+}
+
+func quux(sp *string, bp *[]byte) { // ERROR "quux bp does not escape$" "quux sp does not escape$"
+	*sp = (*sp)[1:2] // ERROR "quux ignoring self-assignment to \*sp$"
+	*bp = (*bp)[1:2] // ERROR "quux ignoring self-assignment to \*bp$"
+}
+
+type StructWithString struct {
+	p *int
+	s string
+}
+
+// This is escape analysis false negative.
+// We assign the pointer to x.p but leak x.s. Escape analysis coarsens flows
+// 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 // ERROR "x.s escapes to heap$"
+}
+
+// String operations.
+
+func slicebytetostring0() {
+	b := make([]byte, 20) // ERROR "slicebytetostring0 make\(\[\]byte, 20\) does not escape$"
+	s := string(b)        // ERROR "slicebytetostring0 string\(b\) does not escape$"
+	_ = s
+}
+
+func slicebytetostring1() {
+	b := make([]byte, 20) // ERROR "slicebytetostring1 make\(\[\]byte, 20\) does not escape$"
+	s := string(b)        // ERROR "slicebytetostring1 string\(b\) does not escape$"
+	s1 := s[0:1]
+	_ = s1
+}
+
+func slicebytetostring2() {
+	b := make([]byte, 20) // ERROR "slicebytetostring2 make\(\[\]byte, 20\) does not escape$"
+	s := string(b)        // ERROR "string\(b\) escapes to heap$"
+	s1 := s[0:1]          // ERROR "moved to heap: s1$"
+	sink = &s1            // ERROR "&s1 escapes to heap$"
+}
+
+func slicebytetostring3() {
+	b := make([]byte, 20) // ERROR "slicebytetostring3 make\(\[\]byte, 20\) does not escape$"
+	s := string(b)        // ERROR "string\(b\) escapes to heap$"
+	s1 := s[0:1]
+	sink = s1 // ERROR "s1 escapes to heap$"
+}
+
+func addstr0() {
+	s0 := "a"
+	s1 := "b"
+	s := s0 + s1 // ERROR "addstr0 s0 \+ s1 does not escape$"
+	_ = s
+}
+
+func addstr1() {
+	s0 := "a"
+	s1 := "b"
+	s := "c"
+	s += s0 + s1 // ERROR "addstr1 s0 \+ s1 does not escape$"
+	_ = s
+}
+
+func addstr2() {
+	b := make([]byte, 20) // ERROR "addstr2 make\(\[\]byte, 20\) does not escape$"
+	s0 := "a"
+	s := string(b) + s0 // ERROR "addstr2 string\(b\) \+ s0 does not escape$" "addstr2 string\(b\) does not escape$"
+	_ = s
+}
+
+func addstr3() {
+	s0 := "a"
+	s1 := "b"
+	s := s0 + s1 // ERROR "s0 \+ s1 escapes to heap$"
+	s2 := s[0:1]
+	sink = s2 // ERROR "s2 escapes to heap$"
+}
+
+func intstring0() bool {
+	// string does not escape
+	x := '0'
+	s := string(x) // ERROR "intstring0 string\(x\) does not escape$"
+	return s == "0"
+}
+
+func intstring1() string {
+	// string does not escape, but the buffer does
+	x := '0'
+	s := string(x) // ERROR "string\(x\) escapes to heap$"
+	return s
+}
+
+func intstring2() {
+	// string escapes to heap
+	x := '0'
+	s := string(x) // ERROR "moved to heap: s$" "string\(x\) escapes to heap$"
+	sink = &s      // ERROR "&s escapes to heap$"
+}
+
+func stringtoslicebyte0() {
+	s := "foo"
+	x := []byte(s) // ERROR "stringtoslicebyte0 \(\[\]byte\)\(s\) does not escape$"
+	_ = x
+}
+
+func stringtoslicebyte1() []byte {
+	s := "foo"
+	return []byte(s) // ERROR "\(\[\]byte\)\(s\) escapes to heap$"
+}
+
+func stringtoslicebyte2() {
+	s := "foo"
+	sink = []byte(s) // ERROR "\(\[\]byte\)\(s\) escapes to heap$"
+}
+
+func stringtoslicerune0() {
+	s := "foo"
+	x := []rune(s) // ERROR "stringtoslicerune0 \(\[\]rune\)\(s\) does not escape$"
+	_ = x
+}
+
+func stringtoslicerune1() []rune {
+	s := "foo"
+	return []rune(s) // ERROR "\(\[\]rune\)\(s\) escapes to heap$"
+}
+
+func stringtoslicerune2() {
+	s := "foo"
+	sink = []rune(s) // ERROR "\(\[\]rune\)\(s\) escapes to heap$"
+}
+
+func slicerunetostring0() {
+	r := []rune{1, 2, 3} // ERROR "slicerunetostring0 \[\]rune literal does not escape$"
+	s := string(r)       // ERROR "slicerunetostring0 string\(r\) does not escape$"
+	_ = s
+}
+
+func slicerunetostring1() string {
+	r := []rune{1, 2, 3} // ERROR "slicerunetostring1 \[\]rune literal does not escape$"
+	return string(r)     // ERROR "string\(r\) escapes to heap$"
+}
+
+func slicerunetostring2() {
+	r := []rune{1, 2, 3} // ERROR "slicerunetostring2 \[\]rune literal does not escape$"
+	sink = string(r)     // ERROR "string\(r\) escapes to heap$"
+}
+
+func makemap0() {
+	m := make(map[int]int) // ERROR "makemap0 make\(map\[int\]int\) does not escape$"
+	m[0] = 0
+	m[1]++
+	delete(m, 1)
+	sink = m[0] // ERROR "m\[0\] escapes to heap$"
+}
+
+func makemap1() map[int]int {
+	return make(map[int]int) // ERROR "make\(map\[int\]int\) escapes to heap$"
+}
+
+func makemap2() {
+	m := make(map[int]int) // ERROR "make\(map\[int\]int\) escapes to heap$"
+	sink = m               // ERROR "m escapes to heap$"
+}
+
+func nonescapingEface(m map[interface{}]bool) bool { // ERROR "nonescapingEface m does not escape$"
+	return m["foo"] // ERROR "nonescapingEface .foo. does not escape$"
+}
+
+func nonescapingIface(m map[M]bool) bool { // ERROR "nonescapingIface m does not escape$"
+	return m[MV(0)] // ERROR "nonescapingIface MV\(0\) does not escape$"
+}
+
+func issue10353() {
+	x := new(int) // ERROR "new\(int\) escapes to heap$"
+	issue10353a(x)()
+}
+
+func issue10353a(x *int) func() { // ERROR "leaking param: x to result ~r1 level=-1$"
+	return func() { // ERROR "func literal escapes to heap$"
+		println(*x)
+	}
+}
+
+func issue10353b() {
+	var f func()
+	for {
+		x := new(int) // ERROR "new\(int\) escapes to heap$"
+		f = func() {  // ERROR "func literal escapes to heap$"
+			println(*x)
+		}
+	}
+	_ = f
+}
+
+func issue11387(x int) func() int {
+	f := func() int { return x }    // ERROR "func literal escapes to heap"
+	slice1 := []func() int{f}       // ERROR "\[\].* does not escape"
+	slice2 := make([]func() int, 1) // ERROR "make\(.*\) does not escape"
+	copy(slice2, slice1)
+	return slice2[0]
+}
diff --git a/test/escape2n.go b/test/escape2n.go
index 002a78e..c328773 100644
--- a/test/escape2n.go
+++ b/test/escape2n.go
@@ -18,94 +18,94 @@ import (
 
 var gxx *int
 
-func foo1(x int) { // ERROR "moved to heap: x"
-	gxx = &x // ERROR "&x escapes to heap"
+func foo1(x int) { // ERROR "moved to heap: x$"
+	gxx = &x // ERROR "&x escapes to heap$"
 }
 
-func foo2(yy *int) { // ERROR "leaking param: yy"
+func foo2(yy *int) { // ERROR "leaking param: yy$"
 	gxx = yy
 }
 
-func foo3(x int) *int { // ERROR "moved to heap: x"
-	return &x // ERROR "&x escapes to heap"
+func foo3(x int) *int { // ERROR "moved to heap: x$"
+	return &x // ERROR "&x escapes to heap$"
 }
 
 type T *T
 
-func foo3b(t T) { // ERROR "leaking param: t"
+func foo3b(t T) { // ERROR "leaking param: t$"
 	*t = t
 }
 
 // xx isn't going anywhere, so use of yy is ok
-func foo4(xx, yy *int) { // ERROR "xx does not escape" "yy does not escape"
+func foo4(xx, yy *int) { // ERROR "foo4 xx does not escape$" "foo4 yy does not escape$"
 	xx = yy
 }
 
 // xx isn't going anywhere, so taking address of yy is ok
-func foo5(xx **int, yy *int) { // ERROR "xx does not escape" "yy does not escape"
-	xx = &yy // ERROR "&yy does not escape"
+func foo5(xx **int, yy *int) { // ERROR "foo5 xx does not escape$" "foo5 yy does not escape$"
+	xx = &yy // ERROR "foo5 &yy does not escape$"
 }
 
-func foo6(xx **int, yy *int) { // ERROR "xx does not escape" "leaking param: yy"
+func foo6(xx **int, yy *int) { // ERROR "foo6 xx does not escape$" "leaking param: yy$"
 	*xx = yy
 }
 
-func foo7(xx **int, yy *int) { // ERROR "xx does not escape" "yy does not escape"
+func foo7(xx **int, yy *int) { // ERROR "foo7 xx does not escape$" "foo7 yy does not escape$"
 	**xx = *yy
 }
 
-func foo8(xx, yy *int) int { // ERROR "xx does not escape" "yy does not escape"
+func foo8(xx, yy *int) int { // ERROR "foo8 xx does not escape$" "foo8 yy does not escape$"
 	xx = yy
 	return *xx
 }
 
-func foo9(xx, yy *int) *int { // ERROR "leaking param: xx" "leaking param: yy"
+func foo9(xx, yy *int) *int { // ERROR "leaking param: xx to result ~r2 level=0$" "leaking param: yy to result ~r2 level=0$"
 	xx = yy
 	return xx
 }
 
-func foo10(xx, yy *int) { // ERROR "xx does not escape" "yy does not escape"
+func foo10(xx, yy *int) { // ERROR "foo10 xx does not escape$" "foo10 yy does not escape$"
 	*xx = *yy
 }
 
 func foo11() int {
 	x, y := 0, 42
-	xx := &x // ERROR "&x does not escape"
-	yy := &y // ERROR "&y does not escape"
+	xx := &x // ERROR "foo11 &x does not escape$"
+	yy := &y // ERROR "foo11 &y does not escape$"
 	*xx = *yy
 	return x
 }
 
 var xxx **int
 
-func foo12(yyy **int) { // ERROR "leaking param: yyy"
+func foo12(yyy **int) { // ERROR "leaking param: yyy$"
 	xxx = yyy
 }
 
 // Must treat yyy as leaking because *yyy leaks, and the escape analysis
 // summaries in exported metadata do not distinguish these two cases.
-func foo13(yyy **int) { // ERROR "leaking param: yyy"
+func foo13(yyy **int) { // ERROR "leaking param content: yyy$"
 	*xxx = *yyy
 }
 
-func foo14(yyy **int) { // ERROR "yyy does not escape"
+func foo14(yyy **int) { // ERROR "foo14 yyy does not escape$"
 	**xxx = **yyy
 }
 
-func foo15(yy *int) { // ERROR "moved to heap: yy"
-	xxx = &yy // ERROR "&yy escapes to heap"
+func foo15(yy *int) { // ERROR "moved to heap: yy$"
+	xxx = &yy // ERROR "&yy escapes to heap$"
 }
 
-func foo16(yy *int) { // ERROR "leaking param: yy"
+func foo16(yy *int) { // ERROR "leaking param: yy$"
 	*xxx = yy
 }
 
-func foo17(yy *int) { // ERROR "yy does not escape"
+func foo17(yy *int) { // ERROR "foo17 yy does not escape$"
 	**xxx = *yy
 }
 
-func foo18(y int) { // ERROR "moved to heap: "y"
-	*xxx = &y // ERROR "&y escapes to heap"
+func foo18(y int) { // ERROR "moved to heap: y$"
+	*xxx = &y // ERROR "&y escapes to heap$"
 }
 
 func foo19(y int) {
@@ -118,52 +118,52 @@ type Bar struct {
 }
 
 func NewBar() *Bar {
-	return &Bar{42, nil} // ERROR "&Bar literal escapes to heap"
+	return &Bar{42, nil} // ERROR "&Bar literal escapes to heap$"
 }
 
-func NewBarp(x *int) *Bar { // ERROR "leaking param: x"
-	return &Bar{42, x} // ERROR "&Bar literal escapes to heap"
+func NewBarp(x *int) *Bar { // ERROR "leaking param: x to result ~r1 level=-1$"
+	return &Bar{42, x} // ERROR "&Bar literal escapes to heap$"
 }
 
-func NewBarp2(x *int) *Bar { // ERROR "x does not escape"
-	return &Bar{*x, nil} // ERROR "&Bar literal escapes to heap"
+func NewBarp2(x *int) *Bar { // ERROR "NewBarp2 x does not escape$"
+	return &Bar{*x, nil} // ERROR "&Bar literal escapes to heap$"
 }
 
-func (b *Bar) NoLeak() int { // ERROR "b does not escape"
+func (b *Bar) NoLeak() int { // ERROR "\(\*Bar\).NoLeak b does not escape$"
 	return *(b.ii)
 }
 
-func (b *Bar) Leak() *int { // ERROR "leaking param: b"
-	return &b.i // ERROR "&b.i escapes to heap"
+func (b *Bar) Leak() *int { // ERROR "leaking param: b to result ~r0 level=0$"
+	return &b.i // ERROR "&b.i escapes to heap$"
 }
 
-func (b *Bar) AlsoNoLeak() *int { // ERROR "leaking param b content to result ~r0"
+func (b *Bar) AlsoNoLeak() *int { // ERROR "leaking param: b to result ~r0 level=1$"
 	return b.ii
 }
 
-func (b Bar) AlsoLeak() *int { // ERROR "leaking param: b"
+func (b Bar) AlsoLeak() *int { // ERROR "leaking param: b to result ~r0 level=0$"
 	return b.ii
 }
 
-func (b Bar) LeaksToo() *int { // ERROR "leaking param: b"
-	v := 0    // ERROR "moved to heap: v"
-	b.ii = &v // ERROR "&v escapes"
+func (b Bar) LeaksToo() *int { // ERROR "leaking param: b to result ~r0 level=0$"
+	v := 0    // ERROR "moved to heap: v$"
+	b.ii = &v // ERROR "&v escapes to heap$"
 	return b.ii
 }
 
-func (b *Bar) LeaksABit() *int { // ERROR "leaking param b content to result ~r0"
-	v := 0    // ERROR "moved to heap: v"
-	b.ii = &v // ERROR "&v escapes"
+func (b *Bar) LeaksABit() *int { // ERROR "leaking param: b to result ~r0 level=1$"
+	v := 0    // ERROR "moved to heap: v$"
+	b.ii = &v // ERROR "&v escapes to heap$"
 	return b.ii
 }
 
-func (b Bar) StillNoLeak() int { // ERROR "b does not escape"
+func (b Bar) StillNoLeak() int { // ERROR "Bar.StillNoLeak b does not escape$"
 	v := 0
-	b.ii = &v // ERROR "&v does not escape"
+	b.ii = &v // ERROR "Bar.StillNoLeak &v does not escape$"
 	return b.i
 }
 
-func goLeak(b *Bar) { // ERROR "leaking param: b"
+func goLeak(b *Bar) { // ERROR "leaking param: b$"
 	go b.NoLeak()
 }
 
@@ -173,90 +173,105 @@ type Bar2 struct {
 }
 
 func NewBar2() *Bar2 {
-	return &Bar2{[12]int{42}, nil} // ERROR "&Bar2 literal escapes to heap"
+	return &Bar2{[12]int{42}, nil} // ERROR "&Bar2 literal escapes to heap$"
 }
 
-func (b *Bar2) NoLeak() int { // ERROR "b does not escape"
+func (b *Bar2) NoLeak() int { // ERROR "\(\*Bar2\).NoLeak b does not escape$"
 	return b.i[0]
 }
 
-func (b *Bar2) Leak() []int { // ERROR "leaking param: b"
-	return b.i[:] // ERROR "b.i escapes to heap"
+func (b *Bar2) Leak() []int { // ERROR "leaking param: b to result ~r0 level=0$"
+	return b.i[:] // ERROR "b.i escapes to heap$"
 }
 
-func (b *Bar2) AlsoNoLeak() []int { // ERROR "leaking param b content to result ~r0"
+func (b *Bar2) AlsoNoLeak() []int { // ERROR "leaking param: b to result ~r0 level=1$"
 	return b.ii[0:1]
 }
 
-func (b Bar2) AgainNoLeak() [12]int { // ERROR "b does not escape"
+func (b Bar2) AgainNoLeak() [12]int { // ERROR "Bar2.AgainNoLeak b does not escape$"
 	return b.i
 }
 
-func (b *Bar2) LeakSelf() { // ERROR "leaking param: b"
-	b.ii = b.i[0:4] // ERROR "b.i escapes to heap"
+func (b *Bar2) LeakSelf() { // ERROR "leaking param: b$"
+	b.ii = b.i[0:4] // ERROR "b.i escapes to heap$"
 }
 
-func (b *Bar2) LeakSelf2() { // ERROR "leaking param: b"
+func (b *Bar2) LeakSelf2() { // ERROR "leaking param: b$"
 	var buf []int
-	buf = b.i[0:] // ERROR "b.i escapes to heap"
+	buf = b.i[0:] // ERROR "b.i escapes to heap$"
 	b.ii = buf
 }
 
 func foo21() func() int {
-	x := 42             // ERROR "moved to heap: x"
-	return func() int { // ERROR "func literal escapes to heap"
-		return x // ERROR "&x escapes to heap"
+	x := 42
+	return func() int { // ERROR "func literal escapes to heap$"
+		return x
+	}
+}
+
+func foo21a() func() int {
+	x := 42             // ERROR "moved to heap: x$"
+	return func() int { // ERROR "func literal escapes to heap$"
+		x++ // ERROR "&x escapes to heap$"
+		return x
 	}
 }
 
 func foo22() int {
 	x := 42
-	return func() int { // ERROR "func literal does not escape"
+	return func() int { // ERROR "foo22 func literal does not escape$"
 		return x
 	}()
 }
 
-func foo23(x int) func() int { // ERROR "moved to heap: x"
-	return func() int { // ERROR "func literal escapes to heap"
-		return x // ERROR "&x escapes to heap"
+func foo23(x int) func() int {
+	return func() int { // ERROR "func literal escapes to heap$"
+		return x
 	}
 }
 
-func foo23a(x int) func() int { // ERROR "moved to heap: x"
-	f := func() int { // ERROR "func literal escapes to heap"
-		return x // ERROR "&x escapes to heap"
+func foo23a(x int) func() int {
+	f := func() int { // ERROR "func literal escapes to heap$"
+		return x
 	}
 	return f
 }
 
-func foo23b(x int) *(func() int) { // ERROR "moved to heap: x"
-	f := func() int { return x } // ERROR "moved to heap: f" "func literal escapes to heap" "&x escapes to heap"
-	return &f                    // ERROR "&f escapes to heap"
+func foo23b(x int) *(func() int) {
+	f := func() int { return x } // ERROR "func literal escapes to heap$" "moved to heap: f$"
+	return &f                    // ERROR "&f escapes to heap$"
+}
+
+func foo23c(x int) func() int { // ERROR "moved to heap: x$"
+	return func() int { // ERROR "func literal escapes to heap$"
+		x++ // ERROR "&x escapes to heap$"
+		return x
+	}
 }
 
 func foo24(x int) int {
-	return func() int { // ERROR "func literal does not escape"
+	return func() int { // ERROR "foo24 func literal does not escape$"
 		return x
 	}()
 }
 
 var x *int
 
-func fooleak(xx *int) int { // ERROR "leaking param: xx"
+func fooleak(xx *int) int { // ERROR "leaking param: xx$"
 	x = xx
 	return *x
 }
 
-func foonoleak(xx *int) int { // ERROR "xx does not escape"
+func foonoleak(xx *int) int { // ERROR "foonoleak xx does not escape$"
 	return *x + *xx
 }
 
-func foo31(x int) int { // ERROR "moved to heap: x"
-	return fooleak(&x) // ERROR "&x escapes to heap"
+func foo31(x int) int { // ERROR "moved to heap: x$"
+	return fooleak(&x) // ERROR "&x escapes to heap$"
 }
 
 func foo32(x int) int {
-	return foonoleak(&x) // ERROR "&x does not escape"
+	return foonoleak(&x) // ERROR "foo32 &x does not escape$"
 }
 
 type Foo struct {
@@ -267,114 +282,114 @@ type Foo struct {
 var F Foo
 var pf *Foo
 
-func (f *Foo) fooleak() { // ERROR "leaking param: f"
+func (f *Foo) fooleak() { // ERROR "leaking param: f$"
 	pf = f
 }
 
-func (f *Foo) foonoleak() { // ERROR "f does not escape"
+func (f *Foo) foonoleak() { // ERROR "\(\*Foo\).foonoleak f does not escape$"
 	F.x = f.x
 }
 
-func (f *Foo) Leak() { // ERROR "leaking param: f"
+func (f *Foo) Leak() { // ERROR "leaking param: f$"
 	f.fooleak()
 }
 
-func (f *Foo) NoLeak() { // ERROR "f does not escape"
+func (f *Foo) NoLeak() { // ERROR "\(\*Foo\).NoLeak f does not escape$"
 	f.foonoleak()
 }
 
-func foo41(x int) { // ERROR "moved to heap: x"
-	F.xx = &x // ERROR "&x escapes to heap"
+func foo41(x int) { // ERROR "moved to heap: x$"
+	F.xx = &x // ERROR "&x escapes to heap$"
 }
 
-func (f *Foo) foo42(x int) { // ERROR "f does not escape" "moved to heap: x"
-	f.xx = &x // ERROR "&x escapes to heap"
+func (f *Foo) foo42(x int) { // ERROR "\(\*Foo\).foo42 f does not escape$" "moved to heap: x$"
+	f.xx = &x // ERROR "&x escapes to heap$"
 }
 
-func foo43(f *Foo, x int) { // ERROR "f does not escape" "moved to heap: x"
-	f.xx = &x // ERROR "&x escapes to heap"
+func foo43(f *Foo, x int) { // ERROR "foo43 f does not escape$" "moved to heap: x$"
+	f.xx = &x // ERROR "&x escapes to heap$"
 }
 
-func foo44(yy *int) { // ERROR "leaking param: yy"
+func foo44(yy *int) { // ERROR "leaking param: yy$"
 	F.xx = yy
 }
 
-func (f *Foo) foo45() { // ERROR "f does not escape"
+func (f *Foo) foo45() { // ERROR "\(\*Foo\).foo45 f does not escape$"
 	F.x = f.x
 }
 
 // See foo13 above for explanation of why f leaks.
-func (f *Foo) foo46() { // ERROR "leaking param: f"
+func (f *Foo) foo46() { // ERROR "leaking param content: f$"
 	F.xx = f.xx
 }
 
-func (f *Foo) foo47() { // ERROR "leaking param: f"
-	f.xx = &f.x // ERROR "&f.x escapes to heap"
+func (f *Foo) foo47() { // ERROR "leaking param: f$"
+	f.xx = &f.x // ERROR "&f.x escapes to heap$"
 }
 
 var ptrSlice []*int
 
-func foo50(i *int) { // ERROR "leaking param: i"
+func foo50(i *int) { // ERROR "leaking param: i$"
 	ptrSlice[0] = i
 }
 
 var ptrMap map[*int]*int
 
-func foo51(i *int) { // ERROR "leaking param: i"
+func foo51(i *int) { // ERROR "leaking param: i$"
 	ptrMap[i] = i
 }
 
-func indaddr1(x int) *int { // ERROR "moved to heap: x"
-	return &x // ERROR "&x escapes to heap"
+func indaddr1(x int) *int { // ERROR "moved to heap: x$"
+	return &x // ERROR "&x escapes to heap$"
 }
 
-func indaddr2(x *int) *int { // ERROR "leaking param: x"
-	return *&x // ERROR "&x does not escape"
+func indaddr2(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$"
+	return *&x // ERROR "indaddr2 &x does not escape$"
 }
 
-func indaddr3(x *int32) *int { // ERROR "leaking param: x"
-	return *(**int)(unsafe.Pointer(&x)) // ERROR "&x does not escape"
+func indaddr3(x *int32) *int { // ERROR "leaking param: x to result ~r1 level=0$"
+	return *(**int)(unsafe.Pointer(&x)) // ERROR "indaddr3 &x does not escape$"
 }
 
 // From package math:
 
 func Float32bits(f float32) uint32 {
-	return *(*uint32)(unsafe.Pointer(&f)) // ERROR "&f does not escape"
+	return *(*uint32)(unsafe.Pointer(&f)) // ERROR "Float32bits &f does not escape$"
 }
 
 func Float32frombits(b uint32) float32 {
-	return *(*float32)(unsafe.Pointer(&b)) // ERROR "&b does not escape"
+	return *(*float32)(unsafe.Pointer(&b)) // ERROR "Float32frombits &b does not escape$"
 }
 
 func Float64bits(f float64) uint64 {
-	return *(*uint64)(unsafe.Pointer(&f)) // ERROR "&f does not escape"
+	return *(*uint64)(unsafe.Pointer(&f)) // ERROR "Float64bits &f does not escape$"
 }
 
 func Float64frombits(b uint64) float64 {
-	return *(*float64)(unsafe.Pointer(&b)) // ERROR "&b does not escape"
+	return *(*float64)(unsafe.Pointer(&b)) // ERROR "Float64frombits &b does not escape$"
 }
 
 // contrast with
-func float64bitsptr(f float64) *uint64 { // ERROR "moved to heap: f"
-	return (*uint64)(unsafe.Pointer(&f)) // ERROR "&f escapes to heap"
+func float64bitsptr(f float64) *uint64 { // ERROR "moved to heap: f$"
+	return (*uint64)(unsafe.Pointer(&f)) // ERROR "&f escapes to heap$"
 }
 
-func float64ptrbitsptr(f *float64) *uint64 { // ERROR "leaking param: f"
+func float64ptrbitsptr(f *float64) *uint64 { // ERROR "leaking param: f to result ~r1 level=0$"
 	return (*uint64)(unsafe.Pointer(f))
 }
 
-func typesw(i interface{}) *int { // ERROR "leaking param: i"
+func typesw(i interface{}) *int { // ERROR "leaking param: i to result ~r1 level=0$"
 	switch val := i.(type) {
 	case *int:
 		return val
 	case *int8:
-		v := int(*val) // ERROR "moved to heap: v"
-		return &v      // ERROR "&v escapes to heap"
+		v := int(*val) // ERROR "moved to heap: v$"
+		return &v      // ERROR "&v escapes to heap$"
 	}
 	return nil
 }
 
-func exprsw(i *int) *int { // ERROR "leaking param: i"
+func exprsw(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$"
 	switch j := i; *j + 110 {
 	case 12:
 		return j
@@ -386,20 +401,20 @@ func exprsw(i *int) *int { // ERROR "leaking param: i"
 }
 
 // assigning to an array element is like assigning to the array
-func foo60(i *int) *int { // ERROR "leaking param: i"
+func foo60(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$"
 	var a [12]*int
 	a[0] = i
 	return a[1]
 }
 
-func foo60a(i *int) *int { // ERROR "i does not escape"
+func foo60a(i *int) *int { // ERROR "foo60a i does not escape$"
 	var a [12]*int
 	a[0] = i
 	return nil
 }
 
 // assigning to a struct field  is like assigning to the struct
-func foo61(i *int) *int { // ERROR "leaking param: i"
+func foo61(i *int) *int { // ERROR "leaking param: i to result ~r1 level=0$"
 	type S struct {
 		a, b *int
 	}
@@ -408,7 +423,7 @@ func foo61(i *int) *int { // ERROR "leaking param: i"
 	return s.b
 }
 
-func foo61a(i *int) *int { // ERROR "i does not escape"
+func foo61a(i *int) *int { // ERROR "foo61a i does not escape$"
 	type S struct {
 		a, b *int
 	}
@@ -420,11 +435,11 @@ func foo61a(i *int) *int { // ERROR "i does not escape"
 // assigning to a struct field is like assigning to the struct but
 // here this subtlety is lost, since s.a counts as an assignment to a
 // track-losing dereference.
-func foo62(i *int) *int { // ERROR "leaking param: i"
+func foo62(i *int) *int { // ERROR "leaking param: i$"
 	type S struct {
 		a, b *int
 	}
-	s := new(S) // ERROR "new[(]S[)] does not escape"
+	s := new(S) // ERROR "foo62 new\(S\) does not escape$"
 	s.a = i
 	return nil // s.b
 }
@@ -433,14 +448,14 @@ type M interface {
 	M()
 }
 
-func foo63(m M) { // ERROR "m does not escape"
+func foo63(m M) { // ERROR "foo63 m does not escape$"
 }
 
-func foo64(m M) { // ERROR "leaking param: m"
+func foo64(m M) { // ERROR "leaking param: m$"
 	m.M()
 }
 
-func foo64b(m M) { // ERROR "leaking param: m"
+func foo64b(m M) { // ERROR "leaking param: m$"
 	defer m.M()
 }
 
@@ -450,55 +465,56 @@ func (MV) M() {}
 
 func foo65() {
 	var mv MV
-	foo63(&mv) // ERROR "&mv does not escape"
+	foo63(&mv) // ERROR "foo65 &mv does not escape$"
 }
 
 func foo66() {
-	var mv MV  // ERROR "moved to heap: mv"
-	foo64(&mv) // ERROR "&mv escapes to heap"
+	var mv MV  // ERROR "moved to heap: mv$"
+	foo64(&mv) // ERROR "&mv escapes to heap$"
 }
 
 func foo67() {
 	var mv MV
-	foo63(mv)
+	foo63(mv) // ERROR "foo67 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"
+func foo69(m M) { // ERROR "leaking param: m$"
 	foo64(m)
 }
 
-func foo70(mv1 *MV, m M) { // ERROR "leaking param: mv1" "leaking param: m"
-	m = mv1
+func foo70(mv1 *MV, m M) { // ERROR "leaking param: m$" "leaking param: mv1$"
+	m = mv1 // ERROR "mv1 escapes to heap$"
 	foo64(m)
 }
 
-func foo71(x *int) []*int { // ERROR "leaking param: x"
+func foo71(x *int) []*int { // ERROR "leaking param: x$"
 	var y []*int
 	y = append(y, x)
 	return y
 }
 
-func foo71a(x int) []*int { // ERROR "moved to heap: x"
+func foo71a(x int) []*int { // ERROR "moved to heap: x$"
 	var y []*int
-	y = append(y, &x) // ERROR "&x escapes to heap"
+	y = append(y, &x) // ERROR "&x escapes to heap$"
 	return y
 }
 
 func foo72() {
 	var x int
 	var y [1]*int
-	y[0] = &x // ERROR "&x does not escape"
+	y[0] = &x // ERROR "foo72 &x does not escape$"
 }
 
 func foo72aa() [10]*int {
-	var x int // ERROR "moved to heap: x"
+	var x int // ERROR "moved to heap: x$"
 	var y [10]*int
-	y[0] = &x // ERROR "&x escapes to heap"
+	y[0] = &x // ERROR "&x escapes to heap$"
 	return y
 }
 
@@ -506,8 +522,8 @@ func foo72a() {
 	var y [10]*int
 	for i := 0; i < 10; i++ {
 		// escapes its scope
-		x := i    // ERROR "moved to heap: x"
-		y[i] = &x // ERROR "&x escapes to heap"
+		x := i    // ERROR "moved to heap: x$"
+		y[i] = &x // ERROR "&x escapes to heap$"
 	}
 	return
 }
@@ -515,31 +531,56 @@ func foo72a() {
 func foo72b() [10]*int {
 	var y [10]*int
 	for i := 0; i < 10; i++ {
-		x := i    // ERROR "moved to heap: x"
-		y[i] = &x // ERROR "&x escapes to heap"
+		x := i    // ERROR "moved to heap: x$"
+		y[i] = &x // ERROR "&x escapes to heap$"
 	}
 	return y
 }
 
 // issue 2145
 func foo73() {
-	s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape"
+	s := []int{3, 2, 1} // ERROR "foo73 \[\]int literal does not escape$"
+	for _, v := range s {
+		vv := v
+		// actually just escapes its scope
+		defer func() { // ERROR "func literal escapes to heap$"
+			println(vv)
+		}()
+	}
+}
+
+func foo731() {
+	s := []int{3, 2, 1} // ERROR "foo731 \[\]int literal does not escape$"
 	for _, v := range s {
-		vv := v // ERROR "moved to heap: vv"
+		vv := v // ERROR "moved to heap: vv$"
 		// actually just escapes its scope
-		defer func() { // ERROR "func literal escapes to heap"
-			println(vv) // ERROR "&vv escapes to heap"
+		defer func() { // ERROR "func literal escapes to heap$"
+			vv = 42 // ERROR "&vv escapes to heap$"
+			println(vv)
 		}()
 	}
 }
 
 func foo74() {
-	s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape"
+	s := []int{3, 2, 1} // ERROR "foo74 \[\]int literal does not escape$"
 	for _, v := range s {
-		vv := v // ERROR "moved to heap: vv"
+		vv := v
 		// actually just escapes its scope
-		fn := func() { // ERROR "func literal escapes to heap"
-			println(vv) // ERROR "&vv escapes to heap"
+		fn := func() { // ERROR "func literal escapes to heap$"
+			println(vv)
+		}
+		defer fn()
+	}
+}
+
+func foo74a() {
+	s := []int{3, 2, 1} // ERROR "foo74a \[\]int literal does not escape$"
+	for _, v := range s {
+		vv := v // ERROR "moved to heap: vv$"
+		// actually just escapes its scope
+		fn := func() { // ERROR "func literal escapes to heap$"
+			vv += 1 // ERROR "&vv escapes to heap$"
+			println(vv)
 		}
 		defer fn()
 	}
@@ -548,110 +589,142 @@ func foo74() {
 // issue 3975
 func foo74b() {
 	var array [3]func()
-	s := []int{3, 2, 1} // ERROR "\[\]int literal does not escape"
+	s := []int{3, 2, 1} // ERROR "foo74b \[\]int literal does not escape$"
 	for i, v := range s {
-		vv := v // ERROR "moved to heap: vv"
+		vv := v
 		// actually just escapes its scope
-		array[i] = func() { // ERROR "func literal escapes to heap"
-			println(vv) // ERROR "&vv escapes to heap"
+		array[i] = func() { // ERROR "func literal escapes to heap$"
+			println(vv)
 		}
 	}
 }
 
-func myprint(y *int, x ...interface{}) *int { // ERROR "x does not escape" "leaking param: y"
+func foo74c() {
+	var array [3]func()
+	s := []int{3, 2, 1} // ERROR "foo74c \[\]int literal does not escape$"
+	for i, v := range s {
+		vv := v // ERROR "moved to heap: vv$"
+		// actually just escapes its scope
+		array[i] = func() { // ERROR "func literal escapes to heap$"
+			println(&vv) // ERROR "&vv escapes to heap$" "foo74c.func1 &vv does not escape$"
+		}
+	}
+}
+
+func myprint(y *int, x ...interface{}) *int { // ERROR "leaking param: y to result ~r2 level=0$" "myprint x does not escape$"
 	return y
 }
 
-func myprint1(y *int, x ...interface{}) *interface{} { // ERROR "y does not escape" "leaking param: x"
-	return &x[0] // ERROR "&x.0. escapes to heap"
+func myprint1(y *int, x ...interface{}) *interface{} { // ERROR "leaking param: x to result ~r2 level=0$" "myprint1 y does not escape$"
+	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"
+func foo75(z *int) { // ERROR "foo75 z does not escape$"
+	myprint(z, 1, 2, 3) // ERROR "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "foo75 ... argument does not escape$"
 }
 
-func foo75a(z *int) { // ERROR "z does not escape"
-	myprint1(z, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
+func foo75a(z *int) { // ERROR "foo75a z does not escape$"
+	myprint1(z, 1, 2, 3) // ERROR "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "foo75a ... argument does not escape$"
 }
 
-func foo75esc(z *int) { // ERROR "leaking param: z"
-	gxx = myprint(z, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
+func foo75esc(z *int) { // ERROR "leaking param: z$"
+	gxx = myprint(z, 1, 2, 3) // ERROR "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "foo75esc ... argument does not escape$"
 }
 
-func foo75aesc(z *int) { // ERROR "z does not escape"
+func foo75aesc(z *int) { // ERROR "foo75aesc 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 "foo75aesc1 z does not escape$"
+	sink = myprint1(z, 1, 2, 3) // ERROR "... argument escapes to heap$" "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "myprint1\(z, 1, 2, 3\) escapes to heap$"
 }
 
-func foo76(z *int) { // ERROR "leaking param: z"
-	myprint(nil, z) // ERROR "[.][.][.] argument does not escape"
+// BAD: z does not escape here
+func foo76(z *int) { // ERROR "leaking param: z$"
+	myprint(nil, z) // ERROR "foo76 ... argument does not escape$" "z escapes to heap$"
 }
 
-func foo76a(z *int) { // ERROR "leaking param: z"
-	myprint1(nil, z) // ERROR "[.][.][.] argument does not escape"
+// BAD: z does not escape here
+func foo76a(z *int) { // ERROR "leaking param: z$"
+	myprint1(nil, z) // ERROR "foo76a ... 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 "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "foo76b ... argument does not escape$"
 }
 
 func foo76c() {
-	myprint1(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
+	myprint1(nil, 1, 2, 3) // ERROR "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "foo76c ... argument does not escape$"
 }
 
 func foo76d() {
-	defer myprint(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
+	defer myprint(nil, 1, 2, 3) // ERROR "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "foo76d ... argument does not escape$"
 }
 
 func foo76e() {
-	defer myprint1(nil, 1, 2, 3) // ERROR "[.][.][.] argument does not escape"
+	defer myprint1(nil, 1, 2, 3) // ERROR "1 escapes to heap$" "2 escapes to heap$" "3 escapes to heap$" "foo76e ... argument does not escape$"
 }
 
 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$"
 	}
 }
 
-func foo77(z []interface{}) { // ERROR "z does not escape"
+func foo77(z []interface{}) { // ERROR "foo77 z does not escape$"
 	myprint(nil, z...) // z does not escape
 }
 
-func foo77a(z []interface{}) { // ERROR "z does not escape"
+func foo77a(z []interface{}) { // ERROR "foo77a z does not escape$"
 	myprint1(nil, z...)
 }
 
-func foo77b(z []interface{}) { // ERROR "leaking param: z"
+func foo77b(z []interface{}) { // ERROR "leaking param: z$"
 	var ppi **interface{}
 	*ppi = myprint1(nil, z...)
 }
 
-func foo78(z int) *int { // ERROR "moved to heap: z"
-	return &z // ERROR "&z escapes to heap"
+func foo77c(z []interface{}) { // ERROR "leaking param: z$"
+	sink = myprint1(nil, z...) // ERROR "myprint1\(nil, z...\) escapes to heap$"
 }
 
-func foo78a(z int) *int { // ERROR "moved to heap: z"
-	y := &z   // ERROR "&z escapes to heap"
-	x := &y   // ERROR "&y does not escape"
+func dotdotdot() {
+	// BAD: i should not escape here
+	i := 0           // ERROR "moved to heap: i$"
+	myprint(nil, &i) // ERROR "&i escapes to heap$" "dotdotdot ... 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$" "dotdotdot ... argument does not escape$"
+}
+
+func foo78(z int) *int { // ERROR "moved to heap: z$"
+	return &z // ERROR "&z escapes to heap$"
+}
+
+func foo78a(z int) *int { // ERROR "moved to heap: z$"
+	y := &z   // ERROR "&z escapes to heap$"
+	x := &y   // ERROR "foo78a &y does not escape$"
 	return *x // really return y
 }
 
 func foo79() *int {
-	return new(int) // ERROR "new[(]int[)] escapes to heap"
+	return new(int) // ERROR "new\(int\) escapes to heap$"
 }
 
 func foo80() *int {
 	var z *int
 	for {
 		// Really just escapes its scope but we don't distinguish
-		z = new(int) // ERROR "new[(]int[)] escapes to heap"
+		z = new(int) // ERROR "new\(int\) escapes to heap$"
 	}
 	_ = z
 	return nil
@@ -659,24 +732,24 @@ func foo80() *int {
 
 func foo81() *int {
 	for {
-		z := new(int) // ERROR "new[(]int[)] does not escape"
+		z := new(int) // ERROR "foo81 new\(int\) does not escape$"
 		_ = z
 	}
 	return nil
 }
 
-func tee(p *int) (x, y *int) { return p, p } // ERROR "leaking param"
+func tee(p *int) (x, y *int) { return p, p } // ERROR "leaking param: p to result x level=0$" "leaking param: p to result y level=0$"
 
-func noop(x, y *int) {} // ERROR "does not escape"
+func noop(x, y *int) {} // ERROR "noop x does not escape$" "noop y does not escape$"
 
 func foo82() {
-	var x, y, z int  // ERROR "moved to heap"
-	go noop(tee(&z)) // ERROR "&z escapes to heap"
-	go noop(&x, &y)  // ERROR "escapes to heap"
+	var x, y, z int  // ERROR "moved to heap: x$" "moved to heap: y$" "moved to heap: z$"
+	go noop(tee(&z)) // ERROR "&z escapes to heap$"
+	go noop(&x, &y)  // ERROR "&x escapes to heap$" "&y escapes to heap$"
 	for {
-		var u, v, w int     // ERROR "moved to heap"
-		defer noop(tee(&u)) // ERROR "&u escapes to heap"
-		defer noop(&v, &w)  // ERROR "escapes to heap"
+		var u, v, w int     // ERROR "moved to heap: u$" "moved to heap: v$" "moved to heap: w$"
+		defer noop(tee(&u)) // ERROR "&u escapes to heap$"
+		defer noop(&v, &w)  // ERROR "&v escapes to heap$" "&w escapes to heap$"
 	}
 }
 
@@ -689,24 +762,24 @@ type LimitedFooer struct {
 	N int64
 }
 
-func LimitFooer(r Fooer, n int64) Fooer { // ERROR "leaking param: r"
-	return &LimitedFooer{r, n} // ERROR "&LimitedFooer literal escapes to heap"
+func LimitFooer(r Fooer, n int64) Fooer { // ERROR "leaking param: r to result ~r2 level=-1$"
+	return &LimitedFooer{r, n} // ERROR "&LimitedFooer literal escapes to heap$"
 }
 
-func foo90(x *int) map[*int]*int { // ERROR "leaking param: x"
-	return map[*int]*int{nil: x} // ERROR "map\[\*int\]\*int literal escapes to heap"
+func foo90(x *int) map[*int]*int { // ERROR "leaking param: x$"
+	return map[*int]*int{nil: x} // ERROR "map\[\*int\]\*int literal escapes to heap$"
 }
 
-func foo91(x *int) map[*int]*int { // ERROR "leaking param: x"
-	return map[*int]*int{x: nil} // ERROR "map\[\*int\]\*int literal escapes to heap"
+func foo91(x *int) map[*int]*int { // ERROR "leaking param: x$"
+	return map[*int]*int{x: nil} // ERROR "map\[\*int\]\*int literal escapes to heap$"
 }
 
-func foo92(x *int) [2]*int { // ERROR "leaking param: x"
+func foo92(x *int) [2]*int { // ERROR "leaking param: x to result ~r1 level=0$"
 	return [2]*int{x, nil}
 }
 
 // does not leak c
-func foo93(c chan *int) *int { // ERROR "c does not escape"
+func foo93(c chan *int) *int { // ERROR "foo93 c does not escape$"
 	for v := range c {
 		return v
 	}
@@ -714,7 +787,7 @@ func foo93(c chan *int) *int { // ERROR "c does not escape"
 }
 
 // does not leak m
-func foo94(m map[*int]*int, b bool) *int { // ERROR "m does not escape"
+func foo94(m map[*int]*int, b bool) *int { // ERROR "leaking param: m to result ~r2 level=1"
 	for k, v := range m {
 		if b {
 			return k
@@ -725,32 +798,32 @@ func foo94(m map[*int]*int, b bool) *int { // ERROR "m does not escape"
 }
 
 // does leak x
-func foo95(m map[*int]*int, x *int) { // ERROR "m does not escape" "leaking param: x"
+func foo95(m map[*int]*int, x *int) { // ERROR "foo95 m does not escape$" "leaking param: x$"
 	m[x] = x
 }
 
-// does not leak m
-func foo96(m []*int) *int { // ERROR "m does not escape"
+// does not leak m but does leak content
+func foo96(m []*int) *int { // ERROR "leaking param: m to result ~r1 level=1"
 	return m[0]
 }
 
 // does leak m
-func foo97(m [1]*int) *int { // ERROR "leaking param: m"
+func foo97(m [1]*int) *int { // ERROR "leaking param: m to result ~r1 level=0$"
 	return m[0]
 }
 
 // does not leak m
-func foo98(m map[int]*int) *int { // ERROR "m does not escape"
+func foo98(m map[int]*int) *int { // ERROR "foo98 m does not escape$"
 	return m[0]
 }
 
 // does leak m
-func foo99(m *[1]*int) []*int { // ERROR "leaking param: m"
+func foo99(m *[1]*int) []*int { // ERROR "leaking param: m to result ~r1 level=0$"
 	return m[:]
 }
 
 // does not leak m
-func foo100(m []*int) *int { // ERROR "m does not escape"
+func foo100(m []*int) *int { // ERROR "leaking param: m to result ~r1 level=1"
 	for _, v := range m {
 		return v
 	}
@@ -758,7 +831,7 @@ func foo100(m []*int) *int { // ERROR "m does not escape"
 }
 
 // does leak m
-func foo101(m [1]*int) *int { // ERROR "leaking param: m"
+func foo101(m [1]*int) *int { // ERROR "leaking param: m to result ~r1 level=0$"
 	for _, v := range m {
 		return v
 	}
@@ -766,109 +839,109 @@ func foo101(m [1]*int) *int { // ERROR "leaking param: m"
 }
 
 // does not leak m
-func foo101a(m [1]*int) *int { // ERROR "m does not escape"
-	for i := range m { // ERROR "moved to heap: i"
-		return &i // ERROR "&i escapes to heap"
+func foo101a(m [1]*int) *int { // ERROR "foo101a m does not escape$"
+	for i := range m { // ERROR "moved to heap: i$"
+		return &i // ERROR "&i escapes to heap$"
 	}
 	return nil
 }
 
 // does leak x
-func foo102(m []*int, x *int) { // ERROR "m does not escape" "leaking param: x"
+func foo102(m []*int, x *int) { // ERROR "foo102 m does not escape$" "leaking param: x$"
 	m[0] = x
 }
 
 // does not leak x
-func foo103(m [1]*int, x *int) { // ERROR "m does not escape" "x does not escape"
+func foo103(m [1]*int, x *int) { // ERROR "foo103 m does not escape$" "foo103 x does not escape$"
 	m[0] = x
 }
 
 var y []*int
 
-// does not leak x
-func foo104(x []*int) { // ERROR "x does not escape"
+// does not leak x but does leak content
+func foo104(x []*int) { // ERROR "leaking param content: x"
 	copy(y, x)
 }
 
-// does not leak x
-func foo105(x []*int) { // ERROR "x does not escape"
+// does not leak x but does leak content
+func foo105(x []*int) { // ERROR "leaking param content: x"
 	_ = append(y, x...)
 }
 
 // does leak x
-func foo106(x *int) { // ERROR "leaking param: x"
+func foo106(x *int) { // ERROR "leaking param: x$"
 	_ = append(y, x)
 }
 
-func foo107(x *int) map[*int]*int { // ERROR "leaking param: x"
-	return map[*int]*int{x: nil} // ERROR "map.* literal escapes to heap"
+func foo107(x *int) map[*int]*int { // ERROR "leaking param: x$"
+	return map[*int]*int{x: nil} // ERROR "map\[\*int\]\*int literal escapes to heap$"
 }
 
-func foo108(x *int) map[*int]*int { // ERROR "leaking param: x"
-	return map[*int]*int{nil: x} // ERROR "map.* literal escapes to heap"
+func foo108(x *int) map[*int]*int { // ERROR "leaking param: x$"
+	return map[*int]*int{nil: x} // ERROR "map\[\*int\]\*int literal escapes to heap$"
 }
 
-func foo109(x *int) *int { // ERROR "leaking param: x"
-	m := map[*int]*int{x: nil} // ERROR "map.* literal does not escape"
+func foo109(x *int) *int { // ERROR "leaking param: x$"
+	m := map[*int]*int{x: nil} // ERROR "foo109 map\[\*int\]\*int literal does not escape$"
 	for k, _ := range m {
 		return k
 	}
 	return nil
 }
 
-func foo110(x *int) *int { // ERROR "leaking param: x"
-	m := map[*int]*int{nil: x} // ERROR "map.* literal does not escape"
+func foo110(x *int) *int { // ERROR "leaking param: x$"
+	m := map[*int]*int{nil: x} // ERROR "foo110 map\[\*int\]\*int literal does not escape$"
 	return m[nil]
 }
 
-func foo111(x *int) *int { // ERROR "leaking param: x"
-	m := []*int{x} // ERROR "\[\]\*int literal does not escape"
+func foo111(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0"
+	m := []*int{x} // ERROR "foo111 \[\]\*int literal does not escape$"
 	return m[0]
 }
 
-func foo112(x *int) *int { // ERROR "leaking param: x"
+func foo112(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$"
 	m := [1]*int{x}
 	return m[0]
 }
 
-func foo113(x *int) *int { // ERROR "leaking param: x"
+func foo113(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$"
 	m := Bar{ii: x}
 	return m.ii
 }
 
-func foo114(x *int) *int { // ERROR "leaking param: x"
-	m := &Bar{ii: x} // ERROR "&Bar literal does not escape"
+func foo114(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$"
+	m := &Bar{ii: x} // ERROR "foo114 &Bar literal does not escape$"
 	return m.ii
 }
 
-func foo115(x *int) *int { // ERROR "leaking param: x"
+func foo115(x *int) *int { // ERROR "leaking param: x to result ~r1 level=0$"
 	return (*int)(unsafe.Pointer(uintptr(unsafe.Pointer(x)) + 1))
 }
 
 func foo116(b bool) *int {
 	if b {
-		x := 1    // ERROR "moved to heap: x"
-		return &x // ERROR "&x escapes to heap"
+		x := 1    // ERROR "moved to heap: x$"
+		return &x // ERROR "&x escapes to heap$"
 	} else {
-		y := 1    // ERROR "moved to heap: y"
-		return &y // ERROR "&y escapes to heap"
+		y := 1    // ERROR "moved to heap: y$"
+		return &y // ERROR "&y escapes to heap$"
 	}
 	return nil
 }
 
-func foo117(unknown func(interface{})) { // ERROR "unknown does not escape"
-	x := 1      // ERROR "moved to heap: x"
-	unknown(&x) // ERROR "&x escapes to heap"
+func foo117(unknown func(interface{})) { // ERROR "foo117 unknown does not escape$"
+	x := 1      // ERROR "moved to heap: x$"
+	unknown(&x) // ERROR "&x escapes to heap$"
 }
 
-func foo118(unknown func(*int)) { // ERROR "unknown does not escape"
-	x := 1      // ERROR "moved to heap: x"
-	unknown(&x) // ERROR "&x escapes to heap"
+func foo118(unknown func(*int)) { // ERROR "foo118 unknown does not escape$"
+	x := 1      // ERROR "moved to heap: x$"
+	unknown(&x) // ERROR "&x escapes to heap$"
 }
 
 func external(*int)
 
-func foo119(x *int) { // ERROR "leaking param: x"
+func foo119(x *int) { // ERROR "leaking param: x$"
 	external(x)
 }
 
@@ -1079,16 +1152,16 @@ L100:
 
 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$"
 	}
 }
 
@@ -1098,7 +1171,7 @@ func foo122() {
 
 	goto L1
 L1:
-	i = new(int) // ERROR "new.int. does not escape"
+	i = new(int) // ERROR "foo122 new\(int\) does not escape$"
 	_ = i
 }
 
@@ -1107,25 +1180,25 @@ func foo123() {
 	var i *int
 
 L1:
-	i = new(int) // ERROR "new.int. escapes to heap"
+	i = new(int) // ERROR "new\(int\) escapes to heap$"
 
 	goto L1
 	_ = i
 }
 
-func foo124(x **int) { // ERROR "x does not escape"
-	var i int // ERROR "moved to heap: i"
-	p := &i   // ERROR "&i escapes"
-	func() {  // ERROR "func literal does not escape"
-		*x = p // ERROR "leaking closure reference p"
+func foo124(x **int) { // ERROR "foo124 x does not escape$"
+	var i int // ERROR "moved to heap: i$"
+	p := &i   // ERROR "&i escapes to heap$"
+	func() {  // ERROR "foo124 func literal does not escape$"
+		*x = p // ERROR "leaking closure reference p$"
 	}()
 }
 
-func foo125(ch chan *int) { // ERROR "does not escape"
-	var i int // ERROR "moved to heap"
-	p := &i   // ERROR "&i escapes to heap"
-	func() {  // ERROR "func literal does not escape"
-		ch <- p // ERROR "leaking closure reference p"
+func foo125(ch chan *int) { // ERROR "foo125 ch does not escape$"
+	var i int // ERROR "moved to heap: i$"
+	p := &i   // ERROR "&i escapes to heap$"
+	func() {  // ERROR "foo125 func literal does not escape$"
+		ch <- p // ERROR "leaking closure reference p$"
 	}()
 }
 
@@ -1133,9 +1206,9 @@ func foo126() {
 	var px *int // loopdepth 0
 	for {
 		// loopdepth 1
-		var i int // ERROR "moved to heap"
-		func() {  // ERROR "func literal does not escape"
-			px = &i // ERROR "&i escapes"
+		var i int // ERROR "moved to heap: i$"
+		func() {  // ERROR "foo126 func literal does not escape$"
+			px = &i // ERROR "&i escapes to heap$"
 		}()
 	}
 	_ = px
@@ -1144,26 +1217,26 @@ func foo126() {
 var px *int
 
 func foo127() {
-	var i int // ERROR "moved to heap: i"
-	p := &i   // ERROR "&i escapes to heap"
+	var i int // ERROR "moved to heap: i$"
+	p := &i   // ERROR "&i escapes to heap$"
 	q := p
 	px = q
 }
 
 func foo128() {
 	var i int
-	p := &i // ERROR "&i does not escape"
+	p := &i // ERROR "foo128 &i does not escape$"
 	q := p
 	_ = q
 }
 
 func foo129() {
-	var i int // ERROR "moved to heap: i"
-	p := &i   // ERROR "&i escapes to heap"
-	func() {  // ERROR "func literal does not escape"
-		q := p   // ERROR "leaking closure reference p"
-		func() { // ERROR "func literal does not escape"
-			r := q // ERROR "leaking closure reference q"
+	var i int // ERROR "moved to heap: i$"
+	p := &i   // ERROR "&i escapes to heap$"
+	func() {  // ERROR "foo129 func literal does not escape$"
+		q := p   // ERROR "leaking closure reference p$"
+		func() { // ERROR "foo129.func1 func literal does not escape$"
+			r := q // ERROR "leaking closure reference q$"
 			px = r
 		}()
 	}()
@@ -1171,40 +1244,40 @@ func foo129() {
 
 func foo130() {
 	for {
-		var i int // ERROR "moved to heap"
-		func() {  // ERROR "func literal does not escape"
-			px = &i // ERROR "&i escapes" "leaking closure reference i"
+		var i int // ERROR "moved to heap: i$"
+		func() {  // ERROR "foo130 func literal does not escape$"
+			px = &i // ERROR "&i escapes to heap$" "leaking closure reference i$"
 		}()
 	}
 }
 
 func foo131() {
-	var i int // ERROR "moved to heap"
-	func() {  // ERROR "func literal does not escape"
-		px = &i // ERROR "&i escapes" "leaking closure reference i"
+	var i int // ERROR "moved to heap: i$"
+	func() {  // ERROR "foo131 func literal does not escape$"
+		px = &i // ERROR "&i escapes to heap$" "leaking closure reference i$"
 	}()
 }
 
 func foo132() {
-	var i int   // ERROR "moved to heap"
-	go func() { // ERROR "func literal escapes to heap"
-		px = &i // ERROR "&i escapes" "leaking closure reference i"
+	var i int   // ERROR "moved to heap: i$"
+	go func() { // ERROR "func literal escapes to heap$"
+		px = &i // ERROR "&i escapes to heap$" "leaking closure reference i$"
 	}()
 }
 
 func foo133() {
-	var i int      // ERROR "moved to heap"
-	defer func() { // ERROR "func literal does not escape"
-		px = &i // ERROR "&i escapes" "leaking closure reference i"
+	var i int      // ERROR "moved to heap: i$"
+	defer func() { // ERROR "foo133 func literal does not escape$"
+		px = &i // ERROR "&i escapes to heap$" "leaking closure reference i$"
 	}()
 }
 
 func foo134() {
 	var i int
-	p := &i  // ERROR "&i does not escape"
-	func() { // ERROR "func literal does not escape"
+	p := &i  // ERROR "foo134 &i does not escape$"
+	func() { // ERROR "foo134 func literal does not escape$"
 		q := p
-		func() { // ERROR "func literal does not escape"
+		func() { // ERROR "foo134.func1 func literal does not escape$"
 			r := q
 			_ = r
 		}()
@@ -1212,11 +1285,11 @@ func foo134() {
 }
 
 func foo135() {
-	var i int   // ERROR "moved to heap: i"
-	p := &i     // ERROR "&i escapes to heap" "moved to heap: p"
-	go func() { // ERROR "func literal escapes to heap"
-		q := p   // ERROR "&p escapes to heap"
-		func() { // ERROR "func literal does not escape"
+	var i int   // ERROR "moved to heap: i$"
+	p := &i     // ERROR "&i escapes to heap$"
+	go func() { // ERROR "func literal escapes to heap$"
+		q := p
+		func() { // ERROR "foo135.func1 func literal does not escape$"
 			r := q
 			_ = r
 		}()
@@ -1224,24 +1297,24 @@ func foo135() {
 }
 
 func foo136() {
-	var i int   // ERROR "moved to heap: i"
-	p := &i     // ERROR "&i escapes to heap" "moved to heap: p"
-	go func() { // ERROR "func literal escapes to heap"
-		q := p   // ERROR "&p escapes to heap" "leaking closure reference p"
-		func() { // ERROR "func literal does not escape"
-			r := q // ERROR "leaking closure reference q"
+	var i int   // ERROR "moved to heap: i$"
+	p := &i     // ERROR "&i escapes to heap$"
+	go func() { // ERROR "func literal escapes to heap$"
+		q := p   // ERROR "leaking closure reference p$"
+		func() { // ERROR "foo136.func1 func literal does not escape$"
+			r := q // ERROR "leaking closure reference q$"
 			px = r
 		}()
 	}()
 }
 
 func foo137() {
-	var i int // ERROR "moved to heap: i"
-	p := &i   // ERROR "&i escapes to heap"
-	func() {  // ERROR "func literal does not escape"
-		q := p      // ERROR "leaking closure reference p" "moved to heap: q"
-		go func() { // ERROR "func literal escapes to heap"
-			r := q // ERROR "&q escapes to heap"
+	var i int // ERROR "moved to heap: i$"
+	p := &i   // ERROR "&i escapes to heap$"
+	func() {  // ERROR "foo137 func literal does not escape$"
+		q := p      // ERROR "leaking closure reference p$"
+		go func() { // ERROR "func literal escapes to heap$"
+			r := q
 			_ = r
 		}()
 	}()
@@ -1251,8 +1324,8 @@ func foo138() *byte {
 	type T struct {
 		x [1]byte
 	}
-	t := new(T)    // ERROR "new.T. escapes to heap"
-	return &t.x[0] // ERROR "&t.x.0. escapes to heap"
+	t := new(T)    // ERROR "new\(T\) escapes to heap$"
+	return &t.x[0] // ERROR "&t.x\[0\] escapes to heap$"
 }
 
 func foo139() *byte {
@@ -1261,8 +1334,8 @@ func foo139() *byte {
 			y byte
 		}
 	}
-	t := new(T)   // ERROR "new.T. escapes to heap"
-	return &t.x.y // ERROR "&t.x.y escapes to heap"
+	t := new(T)   // ERROR "new\(T\) escapes to heap$"
+	return &t.x.y // ERROR "&t.x.y escapes to heap$"
 }
 
 // issue 4751
@@ -1274,8 +1347,8 @@ func foo140() interface{} {
 		X string
 		T *T
 	}
-	t := &T{} // ERROR "&T literal escapes to heap"
-	return U{
+	t := &T{} // ERROR "&T literal escapes to heap$"
+	return U{ // ERROR "U literal escapes to heap$"
 		X: t.X,
 		T: t,
 	}
@@ -1289,53 +1362,53 @@ func F2([]byte)
 
 //go:noescape
 
-func F3(x []byte) // ERROR "F3 x does not escape"
+func F3(x []byte) // ERROR "F3 x does not escape$"
 
 func F4(x []byte)
 
 func G() {
 	var buf1 [10]byte
-	F1(buf1[:]) // ERROR "buf1 does not escape"
+	F1(buf1[:]) // ERROR "G buf1 does not escape$"
 
-	var buf2 [10]byte // ERROR "moved to heap: buf2"
-	F2(buf2[:])       // ERROR "buf2 escapes to heap"
+	var buf2 [10]byte // ERROR "moved to heap: buf2$"
+	F2(buf2[:])       // ERROR "buf2 escapes to heap$"
 
 	var buf3 [10]byte
-	F3(buf3[:]) // ERROR "buf3 does not escape"
+	F3(buf3[:]) // ERROR "G buf3 does not escape$"
 
-	var buf4 [10]byte // ERROR "moved to heap: buf4"
-	F4(buf4[:])       // ERROR "buf4 escapes to heap"
+	var buf4 [10]byte // ERROR "moved to heap: buf4$"
+	F4(buf4[:])       // ERROR "buf4 escapes to heap$"
 }
 
 type Tm struct {
 	x int
 }
 
-func (t *Tm) M() { // ERROR "t does not escape"
+func (t *Tm) M() { // ERROR "\(\*Tm\).M t does not escape$"
 }
 
 func foo141() {
 	var f func()
 
-	t := new(Tm) // ERROR "escapes to heap"
-	f = t.M      // ERROR "t.M does not escape"
+	t := new(Tm) // ERROR "new\(Tm\) escapes to heap$"
+	f = t.M      // ERROR "foo141 t.M does not escape$"
 	_ = f
 }
 
 var gf func()
 
 func foo142() {
-	t := new(Tm) // ERROR "escapes to heap"
-	gf = t.M     // ERROR "t.M escapes to heap"
+	t := new(Tm) // ERROR "new\(Tm\) escapes to heap$"
+	gf = t.M     // ERROR "t.M escapes to heap$"
 }
 
 // issue 3888.
 func foo143() {
 	for i := 0; i < 1000; i++ {
-		func() { // ERROR "func literal does not escape"
+		func() { // ERROR "foo143 func literal does not escape$"
 			for i := 0; i < 1; i++ {
 				var t Tm
-				t.M() // ERROR "t does not escape"
+				t.M() // ERROR "foo143.func1 t does not escape$"
 			}
 		}()
 	}
@@ -1351,9 +1424,9 @@ func foo144a(*int)
 
 func foo144() {
 	var x int
-	foo144a(&x) // ERROR "&x does not escape"
+	foo144a(&x) // ERROR "foo144 &x does not escape$"
 	var y int
-	foo144b(&y) // ERROR "&y does not escape"
+	foo144b(&y) // ERROR "foo144 &y does not escape$"
 }
 
 //go:noescape
@@ -1366,38 +1439,38 @@ type List struct {
 	Next *List
 }
 
-func foo145(l List) { // ERROR "l does not escape"
+func foo145(l List) { // ERROR "foo145 l does not escape$"
 	var p *List
-	for p = &l; p.Next != nil; p = p.Next { // ERROR "&l does not escape"
+	for p = &l; p.Next != nil; p = p.Next { // ERROR "foo145 &l does not escape$"
 	}
 }
 
-func foo146(l List) { // ERROR "l does not escape"
+func foo146(l List) { // ERROR "foo146 l does not escape$"
 	var p *List
-	p = &l // ERROR "&l does not escape"
+	p = &l // ERROR "foo146 &l does not escape$"
 	for ; p.Next != nil; p = p.Next {
 	}
 }
 
-func foo147(l List) { // ERROR "l does not escape"
+func foo147(l List) { // ERROR "foo147 l does not escape$"
 	var p *List
-	p = &l // ERROR "&l does not escape"
+	p = &l // ERROR "foo147 &l does not escape$"
 	for p.Next != nil {
 		p = p.Next
 	}
 }
 
-func foo148(l List) { // ERROR " l does not escape"
-	for p := &l; p.Next != nil; p = p.Next { // ERROR "&l does not escape"
+func foo148(l List) { // ERROR "foo148 l does not escape$"
+	for p := &l; p.Next != nil; p = p.Next { // ERROR "foo148 &l does not escape$"
 	}
 }
 
 // related: address of variable should have depth of variable, not of loop
 
-func foo149(l List) { // ERROR " l does not escape"
+func foo149(l List) { // ERROR "foo149 l does not escape$"
 	var p *List
 	for {
-		for p = &l; p.Next != nil; p = p.Next { // ERROR "&l does not escape"
+		for p = &l; p.Next != nil; p = p.Next { // ERROR "foo149 &l does not escape$"
 		}
 	}
 }
@@ -1406,44 +1479,44 @@ func foo149(l List) { // ERROR " l does not escape"
 
 var save150 []byte
 
-func foo150(x ...byte) { // ERROR "leaking param: x"
+func foo150(x ...byte) { // ERROR "leaking param: x$"
 	save150 = x
 }
 
 func bar150() {
-	foo150(1, 2, 3) // ERROR "[.][.][.] argument escapes to heap"
+	foo150(1, 2, 3) // ERROR "... argument escapes to heap$"
 }
 
 // issue 7931: bad handling of slice of array
 
 var save151 *int
 
-func foo151(x *int) { // ERROR "leaking param: x"
+func foo151(x *int) { // ERROR "leaking param: x$"
 	save151 = x
 }
 
 func bar151() {
-	var a [64]int // ERROR "moved to heap: a"
+	var a [64]int // ERROR "moved to heap: a$"
 	a[4] = 101
-	foo151(&(&a)[4:8][0]) // ERROR "&\(&a\)\[4:8\]\[0\] escapes to heap" "&a escapes to heap"
+	foo151(&(&a)[4:8][0]) // ERROR "&\(&a\)\[4:8\]\[0\] escapes to heap$" "&a escapes to heap$"
 }
 
 func bar151b() {
-	var a [10]int      // ERROR "moved to heap: a"
-	b := a[:]          // ERROR "a escapes to heap"
-	foo151(&b[4:8][0]) // ERROR "&b\[4:8\]\[0\] escapes to heap"
+	var a [10]int      // ERROR "moved to heap: a$"
+	b := a[:]          // ERROR "a escapes to heap$"
+	foo151(&b[4:8][0]) // ERROR "&b\[4:8\]\[0\] escapes to heap$"
 }
 
 func bar151c() {
-	var a [64]int // ERROR "moved to heap: a"
+	var a [64]int // ERROR "moved to heap: a$"
 	a[4] = 101
-	foo151(&(&a)[4:8:8][0]) // ERROR "&\(&a\)\[4:8:8\]\[0\] escapes to heap" "&a escapes to heap"
+	foo151(&(&a)[4:8:8][0]) // ERROR "&\(&a\)\[4:8:8\]\[0\] escapes to heap$" "&a escapes to heap$"
 }
 
 func bar151d() {
-	var a [10]int        // ERROR "moved to heap: a"
-	b := a[:]            // ERROR "a escapes to heap"
-	foo151(&b[4:8:8][0]) // ERROR "&b\[4:8:8\]\[0\] escapes to heap"
+	var a [10]int        // ERROR "moved to heap: a$"
+	b := a[:]            // ERROR "a escapes to heap$"
+	foo151(&b[4:8:8][0]) // ERROR "&b\[4:8:8\]\[0\] escapes to heap$"
 }
 
 // issue 8120
@@ -1452,7 +1525,7 @@ type U struct {
 	s *string
 }
 
-func (u *U) String() *string { // ERROR "leaking param u content to result ~r0"
+func (u *U) String() *string { // ERROR "leaking param: u to result ~r0 level=1$"
 	return u.s
 }
 
@@ -1460,35 +1533,298 @@ type V struct {
 	s *string
 }
 
-func NewV(u U) *V { // ERROR "leaking param: u"
-	return &V{u.String()} // ERROR "&V literal escapes to heap" "u does not escape"
+// BAD -- level of leak ought to be 0
+func NewV(u U) *V { // ERROR "leaking param: u to result ~r1 level=-1"
+	return &V{u.String()} // ERROR "&V literal escapes to heap$" "NewV u does not escape"
 }
 
 func foo152() {
-	a := "a"   // ERROR "moved to heap: a"
-	u := U{&a} // ERROR "&a escapes to heap"
+	a := "a"   // ERROR "moved to heap: a$"
+	u := U{&a} // ERROR "&a escapes to heap$"
 	v := NewV(u)
 	println(v)
 }
 
 // issue 8176 - &x in type switch body not marked as escaping
 
-func foo153(v interface{}) *int { // ERROR "leaking param: v"
+func foo153(v interface{}) *int { // ERROR "leaking param: v to result ~r1 level=-1$"
 	switch x := v.(type) {
-	case int: // ERROR "moved to heap: x"
-		return &x // ERROR "&x escapes to heap"
+	case int: // ERROR "moved to heap: x$"
+		return &x // ERROR "&x escapes to heap$"
 	}
 	panic(0)
 }
 
 // issue 8185 - &result escaping into result
 
-func f() (x int, y *int) { // ERROR "moved to heap: x"
-	y = &x // ERROR "&x escapes to heap"
+func f() (x int, y *int) { // ERROR "moved to heap: x$"
+	y = &x // ERROR "&x escapes to heap$"
 	return
 }
 
-func g() (x interface{}) { // ERROR "moved to heap: x"
-	x = &x // ERROR "&x escapes to heap"
+func g() (x interface{}) { // ERROR "moved to heap: x$"
+	x = &x // ERROR "&x escapes to heap$"
 	return
 }
+
+var sink interface{}
+
+type Lit struct {
+	p *int
+}
+
+func ptrlitNoescape() {
+	// Both literal and element do not escape.
+	i := 0
+	x := &Lit{&i} // ERROR "ptrlitNoescape &Lit literal does not escape$" "ptrlitNoescape &i does not escape$"
+	_ = x
+}
+
+func ptrlitNoEscape2() {
+	// Literal does not escape, but element does.
+	i := 0        // ERROR "moved to heap: i$"
+	x := &Lit{&i} // ERROR "&i escapes to heap$" "ptrlitNoEscape2 &Lit literal does not escape$"
+	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      // ERROR "x escapes to heap$"
+}
+
+// self-assignments
+
+type Buffer struct {
+	arr  [64]byte
+	buf1 []byte
+	buf2 []byte
+	str1 string
+	str2 string
+}
+
+func (b *Buffer) foo() { // ERROR "\(\*Buffer\).foo b does not escape$"
+	b.buf1 = b.buf1[1:2]   // ERROR "\(\*Buffer\).foo ignoring self-assignment to b.buf1$"
+	b.buf1 = b.buf1[1:2:3] // ERROR "\(\*Buffer\).foo ignoring self-assignment to b.buf1$"
+	b.buf1 = b.buf2[1:2]   // ERROR "\(\*Buffer\).foo ignoring self-assignment to b.buf1$"
+	b.buf1 = b.buf2[1:2:3] // ERROR "\(\*Buffer\).foo ignoring self-assignment to b.buf1$"
+}
+
+func (b *Buffer) bar() { // ERROR "leaking param: b$"
+	b.buf1 = b.arr[1:2] // ERROR "b.arr escapes to heap$"
+}
+
+func (b *Buffer) baz() { // ERROR "\(\*Buffer\).baz b does not escape$"
+	b.str1 = b.str1[1:2] // ERROR "\(\*Buffer\).baz ignoring self-assignment to b.str1$"
+	b.str1 = b.str2[1:2] // ERROR "\(\*Buffer\).baz ignoring self-assignment to b.str1$"
+}
+
+func (b *Buffer) bat() { // ERROR "leaking param content: b$"
+	o := new(Buffer) // ERROR "new\(Buffer\) escapes to heap$"
+	o.buf1 = b.buf1[1:2]
+	sink = o // ERROR "o escapes to heap$"
+}
+
+func quux(sp *string, bp *[]byte) { // ERROR "quux bp does not escape$" "quux sp does not escape$"
+	*sp = (*sp)[1:2] // ERROR "quux ignoring self-assignment to \*sp$"
+	*bp = (*bp)[1:2] // ERROR "quux ignoring self-assignment to \*bp$"
+}
+
+type StructWithString struct {
+	p *int
+	s string
+}
+
+// This is escape analysis false negative.
+// We assign the pointer to x.p but leak x.s. Escape analysis coarsens flows
+// 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 // ERROR "x.s escapes to heap$"
+}
+
+// String operations.
+
+func slicebytetostring0() {
+	b := make([]byte, 20) // ERROR "slicebytetostring0 make\(\[\]byte, 20\) does not escape$"
+	s := string(b)        // ERROR "slicebytetostring0 string\(b\) does not escape$"
+	_ = s
+}
+
+func slicebytetostring1() {
+	b := make([]byte, 20) // ERROR "slicebytetostring1 make\(\[\]byte, 20\) does not escape$"
+	s := string(b)        // ERROR "slicebytetostring1 string\(b\) does not escape$"
+	s1 := s[0:1]
+	_ = s1
+}
+
+func slicebytetostring2() {
+	b := make([]byte, 20) // ERROR "slicebytetostring2 make\(\[\]byte, 20\) does not escape$"
+	s := string(b)        // ERROR "string\(b\) escapes to heap$"
+	s1 := s[0:1]          // ERROR "moved to heap: s1$"
+	sink = &s1            // ERROR "&s1 escapes to heap$"
+}
+
+func slicebytetostring3() {
+	b := make([]byte, 20) // ERROR "slicebytetostring3 make\(\[\]byte, 20\) does not escape$"
+	s := string(b)        // ERROR "string\(b\) escapes to heap$"
+	s1 := s[0:1]
+	sink = s1 // ERROR "s1 escapes to heap$"
+}
+
+func addstr0() {
+	s0 := "a"
+	s1 := "b"
+	s := s0 + s1 // ERROR "addstr0 s0 \+ s1 does not escape$"
+	_ = s
+}
+
+func addstr1() {
+	s0 := "a"
+	s1 := "b"
+	s := "c"
+	s += s0 + s1 // ERROR "addstr1 s0 \+ s1 does not escape$"
+	_ = s
+}
+
+func addstr2() {
+	b := make([]byte, 20) // ERROR "addstr2 make\(\[\]byte, 20\) does not escape$"
+	s0 := "a"
+	s := string(b) + s0 // ERROR "addstr2 string\(b\) \+ s0 does not escape$" "addstr2 string\(b\) does not escape$"
+	_ = s
+}
+
+func addstr3() {
+	s0 := "a"
+	s1 := "b"
+	s := s0 + s1 // ERROR "s0 \+ s1 escapes to heap$"
+	s2 := s[0:1]
+	sink = s2 // ERROR "s2 escapes to heap$"
+}
+
+func intstring0() bool {
+	// string does not escape
+	x := '0'
+	s := string(x) // ERROR "intstring0 string\(x\) does not escape$"
+	return s == "0"
+}
+
+func intstring1() string {
+	// string does not escape, but the buffer does
+	x := '0'
+	s := string(x) // ERROR "string\(x\) escapes to heap$"
+	return s
+}
+
+func intstring2() {
+	// string escapes to heap
+	x := '0'
+	s := string(x) // ERROR "moved to heap: s$" "string\(x\) escapes to heap$"
+	sink = &s      // ERROR "&s escapes to heap$"
+}
+
+func stringtoslicebyte0() {
+	s := "foo"
+	x := []byte(s) // ERROR "stringtoslicebyte0 \(\[\]byte\)\(s\) does not escape$"
+	_ = x
+}
+
+func stringtoslicebyte1() []byte {
+	s := "foo"
+	return []byte(s) // ERROR "\(\[\]byte\)\(s\) escapes to heap$"
+}
+
+func stringtoslicebyte2() {
+	s := "foo"
+	sink = []byte(s) // ERROR "\(\[\]byte\)\(s\) escapes to heap$"
+}
+
+func stringtoslicerune0() {
+	s := "foo"
+	x := []rune(s) // ERROR "stringtoslicerune0 \(\[\]rune\)\(s\) does not escape$"
+	_ = x
+}
+
+func stringtoslicerune1() []rune {
+	s := "foo"
+	return []rune(s) // ERROR "\(\[\]rune\)\(s\) escapes to heap$"
+}
+
+func stringtoslicerune2() {
+	s := "foo"
+	sink = []rune(s) // ERROR "\(\[\]rune\)\(s\) escapes to heap$"
+}
+
+func slicerunetostring0() {
+	r := []rune{1, 2, 3} // ERROR "slicerunetostring0 \[\]rune literal does not escape$"
+	s := string(r)       // ERROR "slicerunetostring0 string\(r\) does not escape$"
+	_ = s
+}
+
+func slicerunetostring1() string {
+	r := []rune{1, 2, 3} // ERROR "slicerunetostring1 \[\]rune literal does not escape$"
+	return string(r)     // ERROR "string\(r\) escapes to heap$"
+}
+
+func slicerunetostring2() {
+	r := []rune{1, 2, 3} // ERROR "slicerunetostring2 \[\]rune literal does not escape$"
+	sink = string(r)     // ERROR "string\(r\) escapes to heap$"
+}
+
+func makemap0() {
+	m := make(map[int]int) // ERROR "makemap0 make\(map\[int\]int\) does not escape$"
+	m[0] = 0
+	m[1]++
+	delete(m, 1)
+	sink = m[0] // ERROR "m\[0\] escapes to heap$"
+}
+
+func makemap1() map[int]int {
+	return make(map[int]int) // ERROR "make\(map\[int\]int\) escapes to heap$"
+}
+
+func makemap2() {
+	m := make(map[int]int) // ERROR "make\(map\[int\]int\) escapes to heap$"
+	sink = m               // ERROR "m escapes to heap$"
+}
+
+func nonescapingEface(m map[interface{}]bool) bool { // ERROR "nonescapingEface m does not escape$"
+	return m["foo"] // ERROR "nonescapingEface .foo. does not escape$"
+}
+
+func nonescapingIface(m map[M]bool) bool { // ERROR "nonescapingIface m does not escape$"
+	return m[MV(0)] // ERROR "nonescapingIface MV\(0\) does not escape$"
+}
+
+func issue10353() {
+	x := new(int) // ERROR "new\(int\) escapes to heap$"
+	issue10353a(x)()
+}
+
+func issue10353a(x *int) func() { // ERROR "leaking param: x to result ~r1 level=-1$"
+	return func() { // ERROR "func literal escapes to heap$"
+		println(*x)
+	}
+}
+
+func issue10353b() {
+	var f func()
+	for {
+		x := new(int) // ERROR "new\(int\) escapes to heap$"
+		f = func() {  // ERROR "func literal escapes to heap$"
+			println(*x)
+		}
+	}
+	_ = f
+}
+
+func issue11387(x int) func() int {
+	f := func() int { return x }    // ERROR "func literal escapes to heap"
+	slice1 := []func() int{f}       // ERROR "\[\].* does not escape"
+	slice2 := make([]func() int, 1) // ERROR "make\(.*\) does not escape"
+	copy(slice2, slice1)
+	return slice2[0]
+}
diff --git a/test/escape4.go b/test/escape4.go
index 83bc8eb..248f8a9 100644
--- a/test/escape4.go
+++ b/test/escape4.go
@@ -22,11 +22,11 @@ func f1() {
 
 	// Escape analysis used to miss inlined code in closures.
 
-	func() { // ERROR "func literal does not escape"
+	func() { // ERROR "func literal does not escape" "can inline f1.func1"
 		p = alloc(3) // ERROR "inlining call to alloc" "&x escapes to heap" "moved to heap: x"
 	}()
 
-	f = func() { // ERROR "func literal escapes to heap"
+	f = func() { // ERROR "func literal escapes to heap" "can inline f1.func2"
 		p = alloc(3) // ERROR "inlining call to alloc" "&x escapes to heap" "moved to heap: x"
 	}
 	f()
@@ -42,7 +42,7 @@ func f5() *byte {
 	type T struct {
 		x [1]byte
 	}
-	t := new(T) // ERROR "new.T. escapes to heap"
+	t := new(T)    // ERROR "new.T. escapes to heap"
 	return &t.x[0] // ERROR "&t.x.0. escapes to heap"
 }
 
@@ -52,6 +52,6 @@ func f6() *byte {
 			y byte
 		}
 	}
-	t := new(T) // ERROR "new.T. escapes to heap"
+	t := new(T)   // ERROR "new.T. escapes to heap"
 	return &t.x.y // ERROR "&t.x.y escapes to heap"
 }
diff --git a/test/escape5.go b/test/escape5.go
index a33daee..6a138ea 100644
--- a/test/escape5.go
+++ b/test/escape5.go
@@ -117,7 +117,6 @@ func leakrecursive2(p, q *int) (*int, *int) { // ERROR "leaking param: p" "leaki
 	return p, q
 }
 
-
 var global interface{}
 
 type T1 struct {
@@ -134,18 +133,19 @@ func f8(p *T1) (k T2) { // ERROR "leaking param: p to result k" "leaking param:
 		return
 	}
 
-	global = p // should make p leak always
+	// should make p leak always
+	global = p // ERROR "p escapes to heap"
 	return T2{p}
 }
 
 func f9() {
 	var j T1 // ERROR "moved to heap: j"
-	f8(&j) // ERROR "&j escapes to heap"
+	f8(&j)   // ERROR "&j escapes to heap"
 }
 
 func f10() {
 	// These don't escape but are too big for the stack
-	var x [1<<30]byte // ERROR "moved to heap: x"
-	var y = make([]byte, 1<<30) // ERROR "does not escape"
+	var x [1 << 30]byte         // ERROR "moved to heap: x"
+	var y = make([]byte, 1<<30) // ERROR "make\(\[\]byte, 1 << 30\) escapes to heap"
 	_ = x[0] + y[0]
 }
diff --git a/test/escape_array.go b/test/escape_array.go
new file mode 100644
index 0000000..5da7771
--- /dev/null
+++ b/test/escape_array.go
@@ -0,0 +1,122 @@
+// 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 arrays and some large things
+
+package foo
+
+var Ssink *string
+
+type U [2]*string
+
+func bar(a, b *string) U { // ERROR "leaking param: a to result ~r2 level=0$" "leaking param: b to result ~r2 level=0$"
+	return U{a, b}
+}
+
+func foo(x U) U { // ERROR "leaking param: x to result ~r1 level=0$"
+	return U{x[1], x[0]}
+}
+
+func bff(a, b *string) U { // ERROR "leaking param: a to result ~r2 level=0$" "leaking param: b to result ~r2 level=0$"
+	return foo(foo(bar(a, b)))
+}
+
+func tbff1() *string {
+	a := "cat"
+	b := "dog"       // ERROR "moved to heap: b$"
+	u := bff(&a, &b) // ERROR "tbff1 &a does not escape$" "tbff1 &b does not escape$"
+	_ = u[0]
+	return &b // ERROR "&b escapes to heap$"
+}
+
+// BAD: need fine-grained analysis to track u[0] and u[1] differently.
+func tbff2() *string {
+	a := "cat"       // ERROR "moved to heap: a$"
+	b := "dog"       // ERROR "moved to heap: b$"
+	u := bff(&a, &b) // ERROR "&a escapes to heap$" "&b escapes to heap$"
+	_ = u[0]
+	return u[1]
+}
+
+func car(x U) *string { // ERROR "leaking param: x to result ~r1 level=0$"
+	return x[0]
+}
+
+// BAD: need fine-grained analysis to track x[0] and x[1] differently.
+func fun(x U, y *string) *string { // ERROR "leaking param: x to result ~r2 level=0$" "leaking param: y to result ~r2 level=0$"
+	x[0] = y
+	return x[1]
+}
+
+func fup(x *U, y *string) *string { // ERROR "leaking param: x to result ~r2 level=1$" "leaking param: y$"
+	x[0] = y // leaking y to heap is intended
+	return x[1]
+}
+
+func fum(x *U, y **string) *string { // ERROR "leaking param: x to result ~r2 level=1$" "leaking param content: y$"
+	x[0] = *y
+	return x[1]
+}
+
+func fuo(x *U, y *U) *string { // ERROR "leaking param: x to result ~r2 level=1$" "leaking param content: y$"
+	x[0] = y[0]
+	return x[1]
+}
+
+// These two tests verify that:
+// small array literals are stack allocated;
+// pointers stored in small array literals do not escape;
+// large array literals are heap allocated;
+// pointers stored in large array literals escape.
+func hugeLeaks1(x **string, y **string) { // ERROR "leaking param content: x" "hugeLeaks1 y does not escape" "mark escaped content: x"
+	a := [10]*string{*y}
+	_ = a
+	// 4 x 4,000,000 exceeds MaxStackVarSize, therefore it must be heap allocated if pointers are 4 bytes or larger.
+	b := [4000000]*string{*x} // ERROR "moved to heap: b"
+	_ = b
+}
+
+func hugeLeaks2(x *string, y *string) { // ERROR "leaking param: x" "hugeLeaks2 y does not escape"
+	a := [10]*string{y}
+	_ = a
+	// 4 x 4,000,000 exceeds MaxStackVarSize, therefore it must be heap allocated if pointers are 4 bytes or larger.
+	b := [4000000]*string{x} // ERROR "moved to heap: b"
+	_ = b
+}
+
+// BAD: x need not leak.
+func doesNew1(x *string, y *string) { // ERROR "leaking param: x" "leaking param: y"
+	a := new([10]*string) // ERROR "new\(\[10\]\*string\) does not escape"
+	a[0] = x
+	b := new([65537]*string) // ERROR "new\(\[65537\]\*string\) escapes to heap"
+	b[0] = y
+}
+
+type a10 struct {
+	s *string
+	i [10]int32
+}
+
+type a65537 struct {
+	s *string
+	i [65537]int32
+}
+
+// BAD: x need not leak.
+func doesNew2(x *string, y *string) { // ERROR "leaking param: x" "leaking param: y"
+	a := new(a10) // ERROR "new\(a10\) does not escape"
+	a.s = x
+	b := new(a65537) // ERROR "new\(a65537\) escapes to heap"
+	b.s = y
+}
+
+// BAD: x need not leak.
+func doesMakeSlice(x *string, y *string) { // ERROR "leaking param: x" "leaking param: y"
+	a := make([]*string, 10) // ERROR "make\(\[\]\*string, 10\) does not escape"
+	a[0] = x
+	b := make([]*string, 65537) // ERROR "make\(\[\]\*string, 65537\) escapes to heap"
+	b[0] = y
+}
diff --git a/test/escape_calls.go b/test/escape_calls.go
new file mode 100644
index 0000000..8c9a6da
--- /dev/null
+++ b/test/escape_calls.go
@@ -0,0 +1,54 @@
+// 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 foo
+
+func f(buf []byte) []byte { // ERROR "leaking param: buf to result ~r1 level=0$"
+	return buf
+}
+
+func g(*byte) string
+
+func h(e int) {
+	var x [32]byte // ERROR "moved to heap: x$"
+	g(&f(x[:])[0]) // ERROR "&f\(x\[:\]\)\[0\] escapes to heap$" "x escapes to heap$"
+}
+
+type Node struct {
+	s           string
+	left, right *Node
+}
+
+func walk(np **Node) int { // ERROR "leaking param content: np"
+	n := *np
+	w := len(n.s)
+	if n == nil {
+		return 0
+	}
+	wl := walk(&n.left)  // ERROR "walk &n.left does not escape"
+	wr := walk(&n.right) // ERROR "walk &n.right does not escape"
+	if wl < wr {
+		n.left, n.right = n.right, n.left
+		wl, wr = wr, wl
+	}
+	*np = n
+	return w + wl + wr
+}
+
+// Test for bug where func var f used prototype's escape analysis results.
+func prototype(xyz []string) {} // ERROR "prototype xyz does not escape"
+func bar() {
+	var got [][]string
+	f := prototype
+	f = func(ss []string) { got = append(got, ss) } // ERROR "leaking param: ss" "func literal does not escape"
+	s := "string"
+	f([]string{s}) // ERROR "\[\]string literal escapes to heap"
+}
diff --git a/test/escape_closure.go b/test/escape_closure.go
new file mode 100644
index 0000000..4cdb06e
--- /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 to result ~r1 level=1" "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 to result ~r1 level=1" "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..16d1e74
--- /dev/null
+++ b/test/escape_field.go
@@ -0,0 +1,174 @@
+// 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 content: x$"
+	sink = x.p2 // ERROR "x\.p2 escapes to heap"
+}
+
+func field6a() {
+	i := 0 // ERROR "moved to heap: i$"
+	var x X
+	// BAD: &i should not escape
+	x.p1 = &i  // ERROR "&i escapes to heap$"
+	field6(&x) // ERROR "field6a &x does not escape"
+}
+
+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..2b1144a
--- /dev/null
+++ b/test/escape_iface.go
@@ -0,0 +1,227 @@
+// 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)
+	}
+}
+
+type T1 struct {
+	p *int
+}
+
+type T2 struct {
+	T1 T1
+}
+
+func dotTypeEscape() *T2 { // #11931
+	var x interface{}
+	x = &T1{p: new(int)} // ERROR "new\(int\) escapes to heap" "&T1 literal does not escape"
+	return &T2{
+		T1: *(x.(*T1)), // ERROR "&T2 literal escapes to heap"
+	}
+}
diff --git a/test/escape_indir.go b/test/escape_indir.go
new file mode 100644
index 0000000..fe03c3f
--- /dev/null
+++ b/test/escape_indir.go
@@ -0,0 +1,160 @@
+// 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 content: 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"
+}
+
+var global *byte
+
+func f() {
+	var x byte    // ERROR "moved to heap: x"
+	global = &*&x // ERROR "&\(\*\(&x\)\) escapes to heap" "&x escapes to heap"
+}
diff --git a/test/escape_level.go b/test/escape_level.go
new file mode 100644
index 0000000..867c81a
--- /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 "&i escapes to heap"
+	p1 := &p0 // ERROR "&p0 does not escape"
+	// note *p1 == &i
+	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..cfbcd51
--- /dev/null
+++ b/test/escape_param.go
@@ -0,0 +1,353 @@
+// 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 content: 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$"
+	param3(&p)        // ERROR "caller3a &p does not escape"
+	_ = 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$"
+	param3(&p)        // ERROR "caller3b &p does not escape"
+	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 content: 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$"
+	param6(&p2) // ERROR "caller6a &p2 does not escape"
+}
+
+// **in -> heap
+func param7(i ***int) { // ERROR "leaking param content: 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$"
+	param7(&p2) // ERROR "caller7 &p2 does not escape"
+}
+
+// **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 "leaking param: p to result ~r1 level=1"
+	return *p
+}
+
+func caller9a() {
+	i := 0
+	p := &i         // ERROR "caller9a &i does not escape"
+	p2 := &p        // ERROR "caller9a &p does not escape"
+	_ = 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 "leaking param: p to result ~r1 level=2"
+	return **p
+}
+
+func caller10a() {
+	i := 0
+	p := &i          // ERROR "caller10a &i does not escape"
+	p2 := &p         // ERROR "caller10a &p does not escape"
+	_ = param10(&p2) // ERROR "caller10a &p2 does not escape$"
+}
+
+func caller10b() {
+	i := 0              // ERROR "moved to heap: i$"
+	p := &i             // ERROR "&i escapes to heap$"
+	p2 := &p            // ERROR "caller10b &p does not escape$"
+	sink = param10(&p2) // ERROR "caller10b &p2 does not escape$" "param10\(&p2\) escapes to heap"
+}
+
+// in escapes to heap (address of param taken and returned)
+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 "moved to heap: p" "&i escapes to heap"
+	_ = 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() { // GOOD
+	i := 0              // ERROR "moved to heap: i$"
+	p := &i             // ERROR "moved to heap: p" "&i escapes to heap"
+	sink = *param11(&p) // ERROR "&p escapes to heap" "\*param11\(&p\) escapes to heap"
+}
+
+func caller11d() {
+	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 = param11(p2) // ERROR "param11\(p2\) 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"
+}
+
+type Node struct {
+	p *Node
+}
+
+var Sink *Node
+
+func f(x *Node) { // ERROR "leaking param content: x"
+	Sink = &Node{x.p} // ERROR "&Node literal escapes to heap"
+}
+
+func g(x *Node) *Node { // ERROR "leaking param: x to result ~r1 level=0"
+	return &Node{x.p} // ERROR "&Node literal escapes to heap"
+}
+
+func h(x *Node) { // ERROR "leaking param: x"
+	y := &Node{x} // ERROR "h &Node literal does not escape"
+	Sink = g(y)
+	f(y)
+}
diff --git a/test/escape_slice.go b/test/escape_slice.go
new file mode 100644
index 0000000..0b65997
--- /dev/null
+++ b/test/escape_slice.go
@@ -0,0 +1,165 @@
+// 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
+
+import (
+	"os"
+	"strings"
+)
+
+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() {
+	i := 0
+	s := []*int{&i} // ERROR "&i does not escape" "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
+}
+
+func envForDir(dir string) []string { // ERROR "dir does not escape"
+	env := os.Environ()
+	return mergeEnvLists([]string{"PWD=" + dir}, env) // ERROR ".PWD=. \+ dir escapes to heap" "\[\]string literal does not escape"
+}
+
+func mergeEnvLists(in, out []string) []string { // ERROR "leaking param content: in" "leaking param content: out" "leaking param: out to result ~r2 level=0"
+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
+}
+
+const (
+	IPv4len = 4
+	IPv6len = 16
+)
+
+var v4InV6Prefix = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}
+
+func IPv4(a, b, c, d byte) IP {
+	p := make(IP, IPv6len) // ERROR "make\(IP, IPv6len\) escapes to heap"
+	copy(p, v4InV6Prefix)
+	p[12] = a
+	p[13] = b
+	p[14] = c
+	p[15] = d
+	return p
+}
+
+type IP []byte
+
+type IPAddr struct {
+	IP   IP
+	Zone string // IPv6 scoped addressing zone
+}
+
+type resolveIPAddrTest struct {
+	network       string
+	litAddrOrName string
+	addr          *IPAddr
+	err           error
+}
+
+var resolveIPAddrTests = []resolveIPAddrTest{
+	{"ip", "127.0.0.1", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil},
+	{"ip4", "127.0.0.1", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil},
+	{"ip4:icmp", "127.0.0.1", &IPAddr{IP: IPv4(127, 0, 0, 1)}, nil},
+}
+
+func setupTestData() {
+	resolveIPAddrTests = append(resolveIPAddrTests,
+		[]resolveIPAddrTest{ // ERROR "\[\]resolveIPAddrTest literal does not escape"
+			{"ip",
+				"localhost",
+				&IPAddr{IP: IPv4(127, 0, 0, 1)}, // ERROR "&IPAddr literal escapes to heap"
+				nil},
+			{"ip4",
+				"localhost",
+				&IPAddr{IP: IPv4(127, 0, 0, 1)}, // ERROR "&IPAddr literal escapes to heap"
+				nil},
+		}...)
+}
diff --git a/test/escape_struct_param1.go b/test/escape_struct_param1.go
new file mode 100644
index 0000000..e30e327
--- /dev/null
+++ b/test/escape_struct_param1.go
@@ -0,0 +1,298 @@
+// 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 *struct function parameters.
+// Note companion strict_param2 checks struct function parameters with similar tests.
+
+package notmain
+
+var Ssink *string
+
+type U struct {
+	_sp  *string
+	_spp **string
+}
+
+type V struct {
+	_u   U
+	_up  *U
+	_upp **U
+}
+
+func (u *U) SP() *string { // ERROR "leaking param: u to result ~r0 level=1$"
+	return u._sp
+}
+
+func (u *U) SPP() **string { // ERROR "leaking param: u to result ~r0 level=1$"
+	return u._spp
+}
+
+func (u *U) SPPi() *string { // ERROR "leaking param: u to result ~r0 level=2$"
+	return *u._spp
+}
+
+func tSPPi() {
+	s := "cat"        // ERROR "moved to heap: s$"
+	ps := &s          // ERROR "&s escapes to heap$"
+	pps := &ps        // ERROR "tSPPi &ps does not escape$"
+	pu := &U{ps, pps} // ERROR "tSPPi &U literal does not escape$"
+	Ssink = pu.SPPi()
+}
+
+func tiSPP() {
+	s := "cat"        // ERROR "moved to heap: s$"
+	ps := &s          // ERROR "&s escapes to heap$"
+	pps := &ps        // ERROR "tiSPP &ps does not escape$"
+	pu := &U{ps, pps} // ERROR "tiSPP &U literal does not escape$"
+	Ssink = *pu.SPP()
+}
+
+// BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of ps
+func tSP() {
+	s := "cat"        // ERROR "moved to heap: s$"
+	ps := &s          // ERROR "&s escapes to heap$" "moved to heap: ps$"
+	pps := &ps        // ERROR "&ps escapes to heap$"
+	pu := &U{ps, pps} // ERROR "tSP &U literal does not escape$"
+	Ssink = pu.SP()
+}
+
+func (v *V) u() U { // ERROR "leaking param: v to result ~r0 level=1$"
+	return v._u
+}
+
+func (v *V) UP() *U { // ERROR "leaking param: v to result ~r0 level=1$"
+	return v._up
+}
+
+func (v *V) UPP() **U { // ERROR "leaking param: v to result ~r0 level=1$"
+	return v._upp
+}
+
+func (v *V) UPPia() *U { // ERROR "leaking param: v to result ~r0 level=2$"
+	return *v._upp
+}
+
+func (v *V) UPPib() *U { // ERROR "leaking param: v to result ~r0 level=2$"
+	return *v.UPP()
+}
+
+func (v *V) USPa() *string { // ERROR "leaking param: v to result ~r0 level=1$"
+	return v._u._sp
+}
+
+func (v *V) USPb() *string { // ERROR "leaking param: v to result ~r0 level=1$"
+	return v.u()._sp
+}
+
+func (v *V) USPPia() *string { // ERROR "leaking param: v to result ~r0 level=2$"
+	return *v._u._spp
+}
+
+func (v *V) USPPib() *string { // ERROR "leaking param: v to result ~r0 level=2$"
+	return v._u.SPPi() // ERROR "\(\*V\).USPPib v._u does not escape$"
+}
+
+func (v *V) UPiSPa() *string { // ERROR "leaking param: v to result ~r0 level=2$"
+	return v._up._sp
+}
+
+func (v *V) UPiSPb() *string { // ERROR "leaking param: v to result ~r0 level=2$"
+	return v._up.SP()
+}
+
+func (v *V) UPiSPc() *string { // ERROR "leaking param: v to result ~r0 level=2$"
+	return v.UP()._sp
+}
+
+func (v *V) UPiSPd() *string { // ERROR "leaking param: v to result ~r0 level=2$"
+	return v.UP().SP()
+}
+
+// BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s3
+func tUPiSPa() {
+	s1 := "ant"
+	s2 := "bat"          // ERROR "moved to heap: s2$"
+	s3 := "cat"          // ERROR "moved to heap: s3$"
+	s4 := "dog"          // ERROR "moved to heap: s4$"
+	s5 := "emu"          // ERROR "moved to heap: s5$"
+	s6 := "fox"          // ERROR "moved to heap: s6$"
+	ps2 := &s2           // ERROR "&s2 escapes to heap$"
+	ps4 := &s4           // ERROR "&s4 escapes to heap$" "moved to heap: ps4$"
+	ps6 := &s6           // ERROR "&s6 escapes to heap$" "moved to heap: ps6$"
+	u1 := U{&s1, &ps2}   // ERROR "tUPiSPa &ps2 does not escape$" "tUPiSPa &s1 does not escape$"
+	u2 := &U{&s3, &ps4}  // ERROR "&ps4 escapes to heap$" "&s3 escapes to heap$" "tUPiSPa &U literal does not escape$"
+	u3 := &U{&s5, &ps6}  // ERROR "&U literal escapes to heap$" "&ps6 escapes to heap$" "&s5 escapes to heap$"
+	v := &V{u1, u2, &u3} // ERROR "tUPiSPa &V literal does not escape$" "tUPiSPa &u3 does not escape$"
+	Ssink = v.UPiSPa()   // Ssink = &s3 (only &s3 really escapes)
+}
+
+// BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s3
+func tUPiSPb() {
+	s1 := "ant"
+	s2 := "bat"          // ERROR "moved to heap: s2$"
+	s3 := "cat"          // ERROR "moved to heap: s3$"
+	s4 := "dog"          // ERROR "moved to heap: s4$"
+	s5 := "emu"          // ERROR "moved to heap: s5$"
+	s6 := "fox"          // ERROR "moved to heap: s6$"
+	ps2 := &s2           // ERROR "&s2 escapes to heap$"
+	ps4 := &s4           // ERROR "&s4 escapes to heap$" "moved to heap: ps4$"
+	ps6 := &s6           // ERROR "&s6 escapes to heap$" "moved to heap: ps6$"
+	u1 := U{&s1, &ps2}   // ERROR "tUPiSPb &ps2 does not escape$" "tUPiSPb &s1 does not escape$"
+	u2 := &U{&s3, &ps4}  // ERROR "&ps4 escapes to heap$" "&s3 escapes to heap$" "tUPiSPb &U literal does not escape$"
+	u3 := &U{&s5, &ps6}  // ERROR "&U literal escapes to heap$" "&ps6 escapes to heap$" "&s5 escapes to heap$"
+	v := &V{u1, u2, &u3} // ERROR "tUPiSPb &V literal does not escape$" "tUPiSPb &u3 does not escape$"
+	Ssink = v.UPiSPb()   // Ssink = &s3 (only &s3 really escapes)
+}
+
+// BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s3
+func tUPiSPc() {
+	s1 := "ant"
+	s2 := "bat"          // ERROR "moved to heap: s2$"
+	s3 := "cat"          // ERROR "moved to heap: s3$"
+	s4 := "dog"          // ERROR "moved to heap: s4$"
+	s5 := "emu"          // ERROR "moved to heap: s5$"
+	s6 := "fox"          // ERROR "moved to heap: s6$"
+	ps2 := &s2           // ERROR "&s2 escapes to heap$"
+	ps4 := &s4           // ERROR "&s4 escapes to heap$" "moved to heap: ps4$"
+	ps6 := &s6           // ERROR "&s6 escapes to heap$" "moved to heap: ps6$"
+	u1 := U{&s1, &ps2}   // ERROR "tUPiSPc &ps2 does not escape$" "tUPiSPc &s1 does not escape$"
+	u2 := &U{&s3, &ps4}  // ERROR "&ps4 escapes to heap$" "&s3 escapes to heap$" "tUPiSPc &U literal does not escape$"
+	u3 := &U{&s5, &ps6}  // ERROR "&U literal escapes to heap$" "&ps6 escapes to heap$" "&s5 escapes to heap$"
+	v := &V{u1, u2, &u3} // ERROR "tUPiSPc &V literal does not escape$" "tUPiSPc &u3 does not escape$"
+	Ssink = v.UPiSPc()   // Ssink = &s3 (only &s3 really escapes)
+}
+
+// BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s3
+func tUPiSPd() {
+	s1 := "ant"
+	s2 := "bat"          // ERROR "moved to heap: s2$"
+	s3 := "cat"          // ERROR "moved to heap: s3$"
+	s4 := "dog"          // ERROR "moved to heap: s4$"
+	s5 := "emu"          // ERROR "moved to heap: s5$"
+	s6 := "fox"          // ERROR "moved to heap: s6$"
+	ps2 := &s2           // ERROR "&s2 escapes to heap$"
+	ps4 := &s4           // ERROR "&s4 escapes to heap$" "moved to heap: ps4$"
+	ps6 := &s6           // ERROR "&s6 escapes to heap$" "moved to heap: ps6$"
+	u1 := U{&s1, &ps2}   // ERROR "tUPiSPd &ps2 does not escape$" "tUPiSPd &s1 does not escape$"
+	u2 := &U{&s3, &ps4}  // ERROR "&ps4 escapes to heap$" "&s3 escapes to heap$" "tUPiSPd &U literal does not escape$"
+	u3 := &U{&s5, &ps6}  // ERROR "&U literal escapes to heap$" "&ps6 escapes to heap$" "&s5 escapes to heap$"
+	v := &V{u1, u2, &u3} // ERROR "tUPiSPd &V literal does not escape$" "tUPiSPd &u3 does not escape$"
+	Ssink = v.UPiSPd()   // Ssink = &s3 (only &s3 really escapes)
+}
+
+func (v V) UPiSPPia() *string { // ERROR "leaking param: v to result ~r0 level=2$"
+	return *v._up._spp
+}
+
+func (v V) UPiSPPib() *string { // ERROR "leaking param: v to result ~r0 level=2$"
+	return v._up.SPPi()
+}
+
+func (v V) UPiSPPic() *string { // ERROR "leaking param: v to result ~r0 level=2$"
+	return *v.UP()._spp // ERROR "V.UPiSPPic v does not escape$"
+}
+
+func (v V) UPiSPPid() *string { // ERROR "leaking param: v to result ~r0 level=2$"
+	return v.UP().SPPi() // ERROR "V.UPiSPPid v does not escape$"
+}
+
+// BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s4
+func tUPiSPPia() {
+	s1 := "ant"
+	s2 := "bat"
+	s3 := "cat"
+	s4 := "dog"          // ERROR "moved to heap: s4$"
+	s5 := "emu"          // ERROR "moved to heap: s5$"
+	s6 := "fox"          // ERROR "moved to heap: s6$"
+	ps2 := &s2           // ERROR "tUPiSPPia &s2 does not escape$"
+	ps4 := &s4           // ERROR "&s4 escapes to heap$"
+	ps6 := &s6           // ERROR "&s6 escapes to heap$" "moved to heap: ps6$"
+	u1 := U{&s1, &ps2}   // ERROR "tUPiSPPia &ps2 does not escape$" "tUPiSPPia &s1 does not escape$"
+	u2 := &U{&s3, &ps4}  // ERROR "tUPiSPPia &U literal does not escape$" "tUPiSPPia &ps4 does not escape$" "tUPiSPPia &s3 does not escape$"
+	u3 := &U{&s5, &ps6}  // ERROR "&ps6 escapes to heap$" "&s5 escapes to heap$" "tUPiSPPia &U literal does not escape$"
+	v := &V{u1, u2, &u3} // ERROR "tUPiSPPia &V literal does not escape$" "tUPiSPPia &u3 does not escape$"
+	Ssink = v.UPiSPPia() // Ssink = *&ps4 = &s4 (only &s4 really escapes)
+}
+
+// BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s4
+func tUPiSPPib() {
+	s1 := "ant"
+	s2 := "bat"
+	s3 := "cat"
+	s4 := "dog"          // ERROR "moved to heap: s4$"
+	s5 := "emu"          // ERROR "moved to heap: s5$"
+	s6 := "fox"          // ERROR "moved to heap: s6$"
+	ps2 := &s2           // ERROR "tUPiSPPib &s2 does not escape$"
+	ps4 := &s4           // ERROR "&s4 escapes to heap$"
+	ps6 := &s6           // ERROR "&s6 escapes to heap$" "moved to heap: ps6$"
+	u1 := U{&s1, &ps2}   // ERROR "tUPiSPPib &ps2 does not escape$" "tUPiSPPib &s1 does not escape$"
+	u2 := &U{&s3, &ps4}  // ERROR "tUPiSPPib &U literal does not escape$" "tUPiSPPib &ps4 does not escape$" "tUPiSPPib &s3 does not escape$"
+	u3 := &U{&s5, &ps6}  // ERROR "&ps6 escapes to heap$" "&s5 escapes to heap$" "tUPiSPPib &U literal does not escape$"
+	v := &V{u1, u2, &u3} // ERROR "tUPiSPPib &V literal does not escape$" "tUPiSPPib &u3 does not escape$"
+	Ssink = v.UPiSPPib() // Ssink = *&ps4 = &s4 (only &s4 really escapes)
+}
+
+// BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s4
+func tUPiSPPic() {
+	s1 := "ant"
+	s2 := "bat"
+	s3 := "cat"
+	s4 := "dog"          // ERROR "moved to heap: s4$"
+	s5 := "emu"          // ERROR "moved to heap: s5$"
+	s6 := "fox"          // ERROR "moved to heap: s6$"
+	ps2 := &s2           // ERROR "tUPiSPPic &s2 does not escape$"
+	ps4 := &s4           // ERROR "&s4 escapes to heap$"
+	ps6 := &s6           // ERROR "&s6 escapes to heap$" "moved to heap: ps6$"
+	u1 := U{&s1, &ps2}   // ERROR "tUPiSPPic &ps2 does not escape$" "tUPiSPPic &s1 does not escape$"
+	u2 := &U{&s3, &ps4}  // ERROR "tUPiSPPic &U literal does not escape$" "tUPiSPPic &ps4 does not escape$" "tUPiSPPic &s3 does not escape$"
+	u3 := &U{&s5, &ps6}  // ERROR "&ps6 escapes to heap$" "&s5 escapes to heap$" "tUPiSPPic &U literal does not escape$"
+	v := &V{u1, u2, &u3} // ERROR "tUPiSPPic &V literal does not escape$" "tUPiSPPic &u3 does not escape$"
+	Ssink = v.UPiSPPic() // Ssink = *&ps4 = &s4 (only &s4 really escapes)
+}
+
+// BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s4
+func tUPiSPPid() {
+	s1 := "ant"
+	s2 := "bat"
+	s3 := "cat"
+	s4 := "dog"          // ERROR "moved to heap: s4$"
+	s5 := "emu"          // ERROR "moved to heap: s5$"
+	s6 := "fox"          // ERROR "moved to heap: s6$"
+	ps2 := &s2           // ERROR "tUPiSPPid &s2 does not escape$"
+	ps4 := &s4           // ERROR "&s4 escapes to heap$"
+	ps6 := &s6           // ERROR "&s6 escapes to heap$" "moved to heap: ps6$"
+	u1 := U{&s1, &ps2}   // ERROR "tUPiSPPid &ps2 does not escape$" "tUPiSPPid &s1 does not escape$"
+	u2 := &U{&s3, &ps4}  // ERROR "tUPiSPPid &U literal does not escape$" "tUPiSPPid &ps4 does not escape$" "tUPiSPPid &s3 does not escape$"
+	u3 := &U{&s5, &ps6}  // ERROR "&ps6 escapes to heap$" "&s5 escapes to heap$" "tUPiSPPid &U literal does not escape$"
+	v := &V{u1, u2, &u3} // ERROR "tUPiSPPid &V literal does not escape$" "tUPiSPPid &u3 does not escape$"
+	Ssink = v.UPiSPPid() // Ssink = *&ps4 = &s4 (only &s4 really escapes)
+}
+
+func (v *V) UPPiSPPia() *string { // ERROR "leaking param: v to result ~r0 level=4$"
+	return *(*v._upp)._spp
+}
+
+// This test isolates the one value that needs to escape, not because
+// it distinguishes fields but because it knows that &s6 is the only
+// value reachable by two indirects from v.
+// The test depends on the level cap in the escape analysis tags
+// being able to encode that fact.
+func tUPPiSPPia() {
+	s1 := "ant"
+	s2 := "bat"
+	s3 := "cat"
+	s4 := "dog"
+	s5 := "emu"
+	s6 := "fox"           // ERROR "moved to heap: s6$"
+	ps2 := &s2            // ERROR "tUPPiSPPia &s2 does not escape$"
+	ps4 := &s4            // ERROR "tUPPiSPPia &s4 does not escape$"
+	ps6 := &s6            // ERROR "&s6 escapes to heap$"
+	u1 := U{&s1, &ps2}    // ERROR "tUPPiSPPia &ps2 does not escape$" "tUPPiSPPia &s1 does not escape$"
+	u2 := &U{&s3, &ps4}   // ERROR "tUPPiSPPia &U literal does not escape$" "tUPPiSPPia &ps4 does not escape$" "tUPPiSPPia &s3 does not escape$"
+	u3 := &U{&s5, &ps6}   // ERROR "tUPPiSPPia &U literal does not escape$" "tUPPiSPPia &ps6 does not escape$" "tUPPiSPPia &s5 does not escape$"
+	v := &V{u1, u2, &u3}  // ERROR "tUPPiSPPia &V literal does not escape$" "tUPPiSPPia &u3 does not escape$"
+	Ssink = v.UPPiSPPia() // Ssink = *&ps6 = &s6 (only &s6 really escapes)
+}
diff --git a/test/escape_struct_param2.go b/test/escape_struct_param2.go
new file mode 100644
index 0000000..c10c336
--- /dev/null
+++ b/test/escape_struct_param2.go
@@ -0,0 +1,298 @@
+// 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 struct function parameters.
+// Note companion strict_param1 checks *struct function parameters with similar tests.
+
+package notmain
+
+var Ssink *string
+
+type U struct {
+	_sp  *string
+	_spp **string
+}
+
+type V struct {
+	_u   U
+	_up  *U
+	_upp **U
+}
+
+func (u U) SP() *string { // ERROR "leaking param: u to result ~r0 level=0$"
+	return u._sp
+}
+
+func (u U) SPP() **string { // ERROR "leaking param: u to result ~r0 level=0$"
+	return u._spp
+}
+
+func (u U) SPPi() *string { // ERROR "leaking param: u to result ~r0 level=1$"
+	return *u._spp
+}
+
+func tSPPi() {
+	s := "cat"        // ERROR "moved to heap: s$"
+	ps := &s          // ERROR "&s escapes to heap$"
+	pps := &ps        // ERROR "tSPPi &ps does not escape$"
+	pu := &U{ps, pps} // ERROR "tSPPi &U literal does not escape$"
+	Ssink = pu.SPPi()
+}
+
+func tiSPP() {
+	s := "cat"        // ERROR "moved to heap: s$"
+	ps := &s          // ERROR "&s escapes to heap$"
+	pps := &ps        // ERROR "tiSPP &ps does not escape$"
+	pu := &U{ps, pps} // ERROR "tiSPP &U literal does not escape$"
+	Ssink = *pu.SPP()
+}
+
+// BAD: need fine-grained analysis to avoid spurious escape of ps
+func tSP() {
+	s := "cat"        // ERROR "moved to heap: s$"
+	ps := &s          // ERROR "&s escapes to heap$" "moved to heap: ps$"
+	pps := &ps        // ERROR "&ps escapes to heap$"
+	pu := &U{ps, pps} // ERROR "tSP &U literal does not escape$"
+	Ssink = pu.SP()
+}
+
+func (v V) u() U { // ERROR "leaking param: v to result ~r0 level=0$"
+	return v._u
+}
+
+func (v V) UP() *U { // ERROR "leaking param: v to result ~r0 level=0$"
+	return v._up
+}
+
+func (v V) UPP() **U { // ERROR "leaking param: v to result ~r0 level=0$"
+	return v._upp
+}
+
+func (v V) UPPia() *U { // ERROR "leaking param: v to result ~r0 level=1$"
+	return *v._upp
+}
+
+func (v V) UPPib() *U { // ERROR "leaking param: v to result ~r0 level=1$"
+	return *v.UPP()
+}
+
+func (v V) USPa() *string { // ERROR "leaking param: v to result ~r0 level=0$"
+	return v._u._sp
+}
+
+func (v V) USPb() *string { // ERROR "leaking param: v to result ~r0 level=0$"
+	return v.u()._sp
+}
+
+func (v V) USPPia() *string { // ERROR "leaking param: v to result ~r0 level=1$"
+	return *v._u._spp
+}
+
+func (v V) USPPib() *string { // ERROR "leaking param: v to result ~r0 level=1$"
+	return v._u.SPPi()
+}
+
+func (v V) UPiSPa() *string { // ERROR "leaking param: v to result ~r0 level=1$"
+	return v._up._sp
+}
+
+func (v V) UPiSPb() *string { // ERROR "leaking param: v to result ~r0 level=1$"
+	return v._up.SP()
+}
+
+func (v V) UPiSPc() *string { // ERROR "leaking param: v to result ~r0 level=1$"
+	return v.UP()._sp
+}
+
+func (v V) UPiSPd() *string { // ERROR "leaking param: v to result ~r0 level=1$"
+	return v.UP().SP()
+}
+
+// BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s3
+func tUPiSPa() {
+	s1 := "ant"
+	s2 := "bat"          // ERROR "moved to heap: s2$"
+	s3 := "cat"          // ERROR "moved to heap: s3$"
+	s4 := "dog"          // ERROR "moved to heap: s4$"
+	s5 := "emu"          // ERROR "moved to heap: s5$"
+	s6 := "fox"          // ERROR "moved to heap: s6$"
+	ps2 := &s2           // ERROR "&s2 escapes to heap$"
+	ps4 := &s4           // ERROR "&s4 escapes to heap$" "moved to heap: ps4$"
+	ps6 := &s6           // ERROR "&s6 escapes to heap$" "moved to heap: ps6$"
+	u1 := U{&s1, &ps2}   // ERROR "tUPiSPa &ps2 does not escape$" "tUPiSPa &s1 does not escape$"
+	u2 := &U{&s3, &ps4}  // ERROR "&ps4 escapes to heap$" "&s3 escapes to heap$" "tUPiSPa &U literal does not escape$"
+	u3 := &U{&s5, &ps6}  // ERROR "&U literal escapes to heap$" "&ps6 escapes to heap$" "&s5 escapes to heap$"
+	v := &V{u1, u2, &u3} // ERROR "tUPiSPa &V literal does not escape$" "tUPiSPa &u3 does not escape$"
+	Ssink = v.UPiSPa()   // Ssink = &s3 (only &s3 really escapes)
+}
+
+// BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s3
+func tUPiSPb() {
+	s1 := "ant"
+	s2 := "bat"          // ERROR "moved to heap: s2$"
+	s3 := "cat"          // ERROR "moved to heap: s3$"
+	s4 := "dog"          // ERROR "moved to heap: s4$"
+	s5 := "emu"          // ERROR "moved to heap: s5$"
+	s6 := "fox"          // ERROR "moved to heap: s6$"
+	ps2 := &s2           // ERROR "&s2 escapes to heap$"
+	ps4 := &s4           // ERROR "&s4 escapes to heap$" "moved to heap: ps4$"
+	ps6 := &s6           // ERROR "&s6 escapes to heap$" "moved to heap: ps6$"
+	u1 := U{&s1, &ps2}   // ERROR "tUPiSPb &ps2 does not escape$" "tUPiSPb &s1 does not escape$"
+	u2 := &U{&s3, &ps4}  // ERROR "&ps4 escapes to heap$" "&s3 escapes to heap$" "tUPiSPb &U literal does not escape$"
+	u3 := &U{&s5, &ps6}  // ERROR "&U literal escapes to heap$" "&ps6 escapes to heap$" "&s5 escapes to heap$"
+	v := &V{u1, u2, &u3} // ERROR "tUPiSPb &V literal does not escape$" "tUPiSPb &u3 does not escape$"
+	Ssink = v.UPiSPb()   // Ssink = &s3 (only &s3 really escapes)
+}
+
+// BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s3
+func tUPiSPc() {
+	s1 := "ant"
+	s2 := "bat"          // ERROR "moved to heap: s2$"
+	s3 := "cat"          // ERROR "moved to heap: s3$"
+	s4 := "dog"          // ERROR "moved to heap: s4$"
+	s5 := "emu"          // ERROR "moved to heap: s5$"
+	s6 := "fox"          // ERROR "moved to heap: s6$"
+	ps2 := &s2           // ERROR "&s2 escapes to heap$"
+	ps4 := &s4           // ERROR "&s4 escapes to heap$" "moved to heap: ps4$"
+	ps6 := &s6           // ERROR "&s6 escapes to heap$" "moved to heap: ps6$"
+	u1 := U{&s1, &ps2}   // ERROR "tUPiSPc &ps2 does not escape$" "tUPiSPc &s1 does not escape$"
+	u2 := &U{&s3, &ps4}  // ERROR "&ps4 escapes to heap$" "&s3 escapes to heap$" "tUPiSPc &U literal does not escape$"
+	u3 := &U{&s5, &ps6}  // ERROR "&U literal escapes to heap$" "&ps6 escapes to heap$" "&s5 escapes to heap$"
+	v := &V{u1, u2, &u3} // ERROR "tUPiSPc &V literal does not escape$" "tUPiSPc &u3 does not escape$"
+	Ssink = v.UPiSPc()   // Ssink = &s3 (only &s3 really escapes)
+}
+
+// BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s3
+func tUPiSPd() {
+	s1 := "ant"
+	s2 := "bat"          // ERROR "moved to heap: s2$"
+	s3 := "cat"          // ERROR "moved to heap: s3$"
+	s4 := "dog"          // ERROR "moved to heap: s4$"
+	s5 := "emu"          // ERROR "moved to heap: s5$"
+	s6 := "fox"          // ERROR "moved to heap: s6$"
+	ps2 := &s2           // ERROR "&s2 escapes to heap$"
+	ps4 := &s4           // ERROR "&s4 escapes to heap$" "moved to heap: ps4$"
+	ps6 := &s6           // ERROR "&s6 escapes to heap$" "moved to heap: ps6$"
+	u1 := U{&s1, &ps2}   // ERROR "tUPiSPd &ps2 does not escape$" "tUPiSPd &s1 does not escape$"
+	u2 := &U{&s3, &ps4}  // ERROR "&ps4 escapes to heap$" "&s3 escapes to heap$" "tUPiSPd &U literal does not escape$"
+	u3 := &U{&s5, &ps6}  // ERROR "&U literal escapes to heap$" "&ps6 escapes to heap$" "&s5 escapes to heap$"
+	v := &V{u1, u2, &u3} // ERROR "tUPiSPd &V literal does not escape$" "tUPiSPd &u3 does not escape$"
+	Ssink = v.UPiSPd()   // Ssink = &s3 (only &s3 really escapes)
+}
+
+func (v V) UPiSPPia() *string { // ERROR "leaking param: v to result ~r0 level=2$"
+	return *v._up._spp
+}
+
+func (v V) UPiSPPib() *string { // ERROR "leaking param: v to result ~r0 level=2$"
+	return v._up.SPPi()
+}
+
+func (v V) UPiSPPic() *string { // ERROR "leaking param: v to result ~r0 level=2$"
+	return *v.UP()._spp
+}
+
+func (v V) UPiSPPid() *string { // ERROR "leaking param: v to result ~r0 level=2$"
+	return v.UP().SPPi()
+}
+
+// BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s4
+func tUPiSPPia() {
+	s1 := "ant"
+	s2 := "bat"
+	s3 := "cat"
+	s4 := "dog"          // ERROR "moved to heap: s4$"
+	s5 := "emu"          // ERROR "moved to heap: s5$"
+	s6 := "fox"          // ERROR "moved to heap: s6$"
+	ps2 := &s2           // ERROR "tUPiSPPia &s2 does not escape$"
+	ps4 := &s4           // ERROR "&s4 escapes to heap$"
+	ps6 := &s6           // ERROR "&s6 escapes to heap$" "moved to heap: ps6$"
+	u1 := U{&s1, &ps2}   // ERROR "tUPiSPPia &ps2 does not escape$" "tUPiSPPia &s1 does not escape$"
+	u2 := &U{&s3, &ps4}  // ERROR "tUPiSPPia &U literal does not escape$" "tUPiSPPia &ps4 does not escape$" "tUPiSPPia &s3 does not escape$"
+	u3 := &U{&s5, &ps6}  // ERROR "&ps6 escapes to heap$" "&s5 escapes to heap$" "tUPiSPPia &U literal does not escape$"
+	v := &V{u1, u2, &u3} // ERROR "tUPiSPPia &V literal does not escape$" "tUPiSPPia &u3 does not escape$"
+	Ssink = v.UPiSPPia() // Ssink = *&ps4 = &s4 (only &s4 really escapes)
+}
+
+// BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s4
+func tUPiSPPib() {
+	s1 := "ant"
+	s2 := "bat"
+	s3 := "cat"
+	s4 := "dog"          // ERROR "moved to heap: s4$"
+	s5 := "emu"          // ERROR "moved to heap: s5$"
+	s6 := "fox"          // ERROR "moved to heap: s6$"
+	ps2 := &s2           // ERROR "tUPiSPPib &s2 does not escape$"
+	ps4 := &s4           // ERROR "&s4 escapes to heap$"
+	ps6 := &s6           // ERROR "&s6 escapes to heap$" "moved to heap: ps6$"
+	u1 := U{&s1, &ps2}   // ERROR "tUPiSPPib &ps2 does not escape$" "tUPiSPPib &s1 does not escape$"
+	u2 := &U{&s3, &ps4}  // ERROR "tUPiSPPib &U literal does not escape$" "tUPiSPPib &ps4 does not escape$" "tUPiSPPib &s3 does not escape$"
+	u3 := &U{&s5, &ps6}  // ERROR "&ps6 escapes to heap$" "&s5 escapes to heap$" "tUPiSPPib &U literal does not escape$"
+	v := &V{u1, u2, &u3} // ERROR "tUPiSPPib &V literal does not escape$" "tUPiSPPib &u3 does not escape$"
+	Ssink = v.UPiSPPib() // Ssink = *&ps4 = &s4 (only &s4 really escapes)
+}
+
+// BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s4
+func tUPiSPPic() {
+	s1 := "ant"
+	s2 := "bat"
+	s3 := "cat"
+	s4 := "dog"          // ERROR "moved to heap: s4$"
+	s5 := "emu"          // ERROR "moved to heap: s5$"
+	s6 := "fox"          // ERROR "moved to heap: s6$"
+	ps2 := &s2           // ERROR "tUPiSPPic &s2 does not escape$"
+	ps4 := &s4           // ERROR "&s4 escapes to heap$"
+	ps6 := &s6           // ERROR "&s6 escapes to heap$" "moved to heap: ps6$"
+	u1 := U{&s1, &ps2}   // ERROR "tUPiSPPic &ps2 does not escape$" "tUPiSPPic &s1 does not escape$"
+	u2 := &U{&s3, &ps4}  // ERROR "tUPiSPPic &U literal does not escape$" "tUPiSPPic &ps4 does not escape$" "tUPiSPPic &s3 does not escape$"
+	u3 := &U{&s5, &ps6}  // ERROR "&ps6 escapes to heap$" "&s5 escapes to heap$" "tUPiSPPic &U literal does not escape$"
+	v := &V{u1, u2, &u3} // ERROR "tUPiSPPic &V literal does not escape$" "tUPiSPPic &u3 does not escape$"
+	Ssink = v.UPiSPPic() // Ssink = *&ps4 = &s4 (only &s4 really escapes)
+}
+
+// BAD: need fine-grained (field-sensitive) analysis to avoid spurious escape of all but &s4
+func tUPiSPPid() {
+	s1 := "ant"
+	s2 := "bat"
+	s3 := "cat"
+	s4 := "dog"          // ERROR "moved to heap: s4$"
+	s5 := "emu"          // ERROR "moved to heap: s5$"
+	s6 := "fox"          // ERROR "moved to heap: s6$"
+	ps2 := &s2           // ERROR "tUPiSPPid &s2 does not escape$"
+	ps4 := &s4           // ERROR "&s4 escapes to heap$"
+	ps6 := &s6           // ERROR "&s6 escapes to heap$" "moved to heap: ps6$"
+	u1 := U{&s1, &ps2}   // ERROR "tUPiSPPid &ps2 does not escape$" "tUPiSPPid &s1 does not escape$"
+	u2 := &U{&s3, &ps4}  // ERROR "tUPiSPPid &U literal does not escape$" "tUPiSPPid &ps4 does not escape$" "tUPiSPPid &s3 does not escape$"
+	u3 := &U{&s5, &ps6}  // ERROR "&ps6 escapes to heap$" "&s5 escapes to heap$" "tUPiSPPid &U literal does not escape$"
+	v := &V{u1, u2, &u3} // ERROR "tUPiSPPid &V literal does not escape$" "tUPiSPPid &u3 does not escape$"
+	Ssink = v.UPiSPPid() // Ssink = *&ps4 = &s4 (only &s4 really escapes)
+}
+
+func (v V) UPPiSPPia() *string { // ERROR "leaking param: v to result ~r0 level=3$"
+	return *(*v._upp)._spp
+}
+
+// This test isolates the one value that needs to escape, not because
+// it distinguishes fields but because it knows that &s6 is the only
+// value reachable by two indirects from v.
+// The test depends on the level cap in the escape analysis tags
+// being able to encode that fact.
+func tUPPiSPPia() { // This test is sensitive to the level cap in function summary results.
+	s1 := "ant"
+	s2 := "bat"
+	s3 := "cat"
+	s4 := "dog"
+	s5 := "emu"
+	s6 := "fox"           // ERROR "moved to heap: s6$"
+	ps2 := &s2            // ERROR "tUPPiSPPia &s2 does not escape$"
+	ps4 := &s4            // ERROR "tUPPiSPPia &s4 does not escape$"
+	ps6 := &s6            // ERROR "&s6 escapes to heap$"
+	u1 := U{&s1, &ps2}    // ERROR "tUPPiSPPia &ps2 does not escape$" "tUPPiSPPia &s1 does not escape$"
+	u2 := &U{&s3, &ps4}   // ERROR "tUPPiSPPia &U literal does not escape$" "tUPPiSPPia &ps4 does not escape$" "tUPPiSPPia &s3 does not escape$"
+	u3 := &U{&s5, &ps6}   // ERROR "tUPPiSPPia &U literal does not escape$" "tUPPiSPPia &ps6 does not escape$" "tUPPiSPPia &s5 does not escape$"
+	v := &V{u1, u2, &u3}  // ERROR "tUPPiSPPia &V literal does not escape$" "tUPPiSPPia &u3 does not escape$"
+	Ssink = v.UPPiSPPia() // Ssink = *&ps6 = &s6 (only &s6 really escapes)
+}
diff --git a/test/escape_struct_return.go b/test/escape_struct_return.go
new file mode 100644
index 0000000..b423ebd
--- /dev/null
+++ b/test/escape_struct_return.go
@@ -0,0 +1,74 @@
+// 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.
+
+package foo
+
+var Ssink *string
+
+type U struct {
+	_sp  *string
+	_spp **string
+}
+
+func A(sp *string, spp **string) U { // ERROR "leaking param: sp to result ~r2 level=0$" "leaking param: spp to result ~r2 level=0$"
+	return U{sp, spp}
+}
+
+func B(spp **string) U { // ERROR "leaking param: spp to result ~r1 level=0$" "leaking param: spp to result ~r1 level=1$"
+	return U{*spp, spp}
+}
+
+func tA1() {
+	s := "cat"
+	sp := &s   // ERROR "tA1 &s does not escape$"
+	spp := &sp // ERROR "tA1 &sp does not escape$"
+	u := A(sp, spp)
+	_ = u
+	println(s)
+}
+
+func tA2() {
+	s := "cat"
+	sp := &s   // ERROR "tA2 &s does not escape$"
+	spp := &sp // ERROR "tA2 &sp does not escape$"
+	u := A(sp, spp)
+	println(*u._sp)
+}
+
+func tA3() {
+	s := "cat"
+	sp := &s   // ERROR "tA3 &s does not escape$"
+	spp := &sp // ERROR "tA3 &sp does not escape$"
+	u := A(sp, spp)
+	println(**u._spp)
+}
+
+func tB1() {
+	s := "cat"
+	sp := &s   // ERROR "tB1 &s does not escape$"
+	spp := &sp // ERROR "tB1 &sp does not escape$"
+	u := B(spp)
+	_ = u
+	println(s)
+}
+
+func tB2() {
+	s := "cat"
+	sp := &s   // ERROR "tB2 &s does not escape$"
+	spp := &sp // ERROR "tB2 &sp does not escape$"
+	u := B(spp)
+	println(*u._sp)
+}
+
+func tB3() {
+	s := "cat"
+	sp := &s   // ERROR "tB3 &s does not escape$"
+	spp := &sp // ERROR "tB3 &sp does not escape$"
+	u := B(spp)
+	println(**u._spp)
+}
diff --git a/test/fibo.go b/test/fibo.go
new file mode 100644
index 0000000..3b816d9
--- /dev/null
+++ b/test/fibo.go
@@ -0,0 +1,310 @@
+// skip
+
+// 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.
+
+// Usage:
+// fibo <n>     compute fibonacci(n), n must be >= 0
+// fibo -bench  benchmark fibonacci computation (takes about 1 min)
+//
+// Additional flags:
+// -half        add values using two half-digit additions
+// -opt         optimize memory allocation through reuse
+// -short       only print the first 10 digits of very large fibonacci numbers
+
+// Command fibo is a stand-alone test and benchmark to
+// evaluate the performance of bignum arithmetic written
+// entirely in Go.
+package main
+
+import (
+	"flag"
+	"fmt"
+	"math/big" // only used for printing
+	"os"
+	"strconv"
+	"testing"
+	"text/tabwriter"
+	"time"
+)
+
+var (
+	bench = flag.Bool("bench", false, "run benchmarks")
+	half  = flag.Bool("half", false, "use half-digit addition")
+	opt   = flag.Bool("opt", false, "optimize memory usage")
+	short = flag.Bool("short", false, "only print first 10 digits of result")
+)
+
+// A large natural number is represented by a nat, each "digit" is
+// a big.Word; the value zero corresponds to the empty nat slice.
+type nat []big.Word
+
+const W = 1 << (5 + ^big.Word(0)>>63) // big.Word size in bits
+
+// The following methods are extracted from math/big to make this a
+// stand-alone program that can easily be run without dependencies
+// and compiled with different compilers.
+
+func (z nat) make(n int) nat {
+	if n <= cap(z) {
+		return z[:n] // reuse z
+	}
+	// Choosing a good value for e has significant performance impact
+	// because it increases the chance that a value can be reused.
+	const e = 4 // extra capacity
+	return make(nat, n, n+e)
+}
+
+// z = x
+func (z nat) set(x nat) nat {
+	z = z.make(len(x))
+	copy(z, x)
+	return z
+}
+
+// z = x + y
+// (like add, but operating on half-digits at a time)
+func (z nat) halfAdd(x, y nat) nat {
+	m := len(x)
+	n := len(y)
+
+	switch {
+	case m < n:
+		return z.add(y, x)
+	case m == 0:
+		// n == 0 because m >= n; result is 0
+		return z.make(0)
+	case n == 0:
+		// result is x
+		return z.set(x)
+	}
+	// m >= n > 0
+
+	const W2 = W / 2         // half-digit size in bits
+	const M2 = (1 << W2) - 1 // lower half-digit mask
+
+	z = z.make(m + 1)
+	var c big.Word
+	for i := 0; i < n; i++ {
+		// lower half-digit
+		c += x[i]&M2 + y[i]&M2
+		d := c & M2
+		c >>= W2
+		// upper half-digit
+		c += x[i]>>W2 + y[i]>>W2
+		z[i] = c<<W2 | d
+		c >>= W2
+	}
+	for i := n; i < m; i++ {
+		// lower half-digit
+		c += x[i] & M2
+		d := c & M2
+		c >>= W2
+		// upper half-digit
+		c += x[i] >> W2
+		z[i] = c<<W2 | d
+		c >>= W2
+	}
+	if c != 0 {
+		z[m] = c
+		m++
+	}
+	return z[:m]
+}
+
+// z = x + y
+func (z nat) add(x, y nat) nat {
+	m := len(x)
+	n := len(y)
+
+	switch {
+	case m < n:
+		return z.add(y, x)
+	case m == 0:
+		// n == 0 because m >= n; result is 0
+		return z.make(0)
+	case n == 0:
+		// result is x
+		return z.set(x)
+	}
+	// m >= n > 0
+
+	z = z.make(m + 1)
+	var c big.Word
+
+	for i, xi := range x[:n] {
+		yi := y[i]
+		zi := xi + yi + c
+		z[i] = zi
+		// see "Hacker's Delight", section 2-12 (overflow detection)
+		c = ((xi & yi) | ((xi | yi) &^ zi)) >> (W - 1)
+	}
+	for i, xi := range x[n:] {
+		zi := xi + c
+		z[n+i] = zi
+		c = (xi &^ zi) >> (W - 1)
+		if c == 0 {
+			copy(z[n+i+1:], x[i+1:])
+			break
+		}
+	}
+	if c != 0 {
+		z[m] = c
+		m++
+	}
+	return z[:m]
+}
+
+func bitlen(x big.Word) int {
+	n := 0
+	for x > 0 {
+		x >>= 1
+		n++
+	}
+	return n
+}
+
+func (x nat) bitlen() int {
+	if i := len(x); i > 0 {
+		return (i-1)*W + bitlen(x[i-1])
+	}
+	return 0
+}
+
+func (x nat) String() string {
+	const shortLen = 10
+	s := new(big.Int).SetBits(x).String()
+	if *short && len(s) > shortLen {
+		s = s[:shortLen] + "..."
+	}
+	return s
+}
+
+func fibo(n int, half, opt bool) nat {
+	switch n {
+	case 0:
+		return nil
+	case 1:
+		return nat{1}
+	}
+	f0 := nat(nil)
+	f1 := nat{1}
+	if half {
+		if opt {
+			var f2 nat // reuse f2
+			for i := 1; i < n; i++ {
+				f2 = f2.halfAdd(f1, f0)
+				f0, f1, f2 = f1, f2, f0
+			}
+		} else {
+			for i := 1; i < n; i++ {
+				f2 := nat(nil).halfAdd(f1, f0) // allocate a new f2 each time
+				f0, f1 = f1, f2
+			}
+		}
+	} else {
+		if opt {
+			var f2 nat // reuse f2
+			for i := 1; i < n; i++ {
+				f2 = f2.add(f1, f0)
+				f0, f1, f2 = f1, f2, f0
+			}
+		} else {
+			for i := 1; i < n; i++ {
+				f2 := nat(nil).add(f1, f0) // allocate a new f2 each time
+				f0, f1 = f1, f2
+			}
+		}
+	}
+	return f1 // was f2 before shuffle
+}
+
+var tests = []struct {
+	n    int
+	want string
+}{
+	{0, "0"},
+	{1, "1"},
+	{2, "1"},
+	{3, "2"},
+	{4, "3"},
+	{5, "5"},
+	{6, "8"},
+	{7, "13"},
+	{8, "21"},
+	{9, "34"},
+	{10, "55"},
+	{100, "354224848179261915075"},
+	{1000, "43466557686937456435688527675040625802564660517371780402481729089536555417949051890403879840079255169295922593080322634775209689623239873322471161642996440906533187938298969649928516003704476137795166849228875"},
+}
+
+func test(half, opt bool) {
+	for _, test := range tests {
+		got := fibo(test.n, half, opt).String()
+		if got != test.want {
+			fmt.Printf("error: got std fibo(%d) = %s; want %s\n", test.n, got, test.want)
+			os.Exit(1)
+		}
+	}
+}
+
+func selfTest() {
+	if W != 32 && W != 64 {
+		fmt.Printf("error: unexpected wordsize %d", W)
+		os.Exit(1)
+	}
+	for i := 0; i < 4; i++ {
+		test(i&2 == 0, i&1 != 0)
+	}
+}
+
+func doFibo(n int) {
+	start := time.Now()
+	f := fibo(n, *half, *opt)
+	t := time.Since(start)
+	fmt.Printf("fibo(%d) = %s (%d bits, %s)\n", n, f, f.bitlen(), t)
+}
+
+func benchFibo(b *testing.B, n int, half, opt bool) {
+	for i := 0; i < b.N; i++ {
+		fibo(n, half, opt)
+	}
+}
+
+func doBench(half, opt bool) {
+	w := tabwriter.NewWriter(os.Stdout, 0, 8, 2, ' ', tabwriter.AlignRight)
+	fmt.Fprintf(w, "wordsize = %d, half = %v, opt = %v\n", W, half, opt)
+	fmt.Fprintf(w, "n\talloc count\talloc bytes\tns/op\ttime/op\t\n")
+	for n := 1; n <= 1e6; n *= 10 {
+		res := testing.Benchmark(func(b *testing.B) { benchFibo(b, n, half, opt) })
+		fmt.Fprintf(w, "%d\t%d\t%d\t%d\t%s\t\n", n, res.AllocsPerOp(), res.AllocedBytesPerOp(), res.NsPerOp(), time.Duration(res.NsPerOp()))
+	}
+	fmt.Fprintln(w)
+	w.Flush()
+}
+
+func main() {
+	selfTest()
+	flag.Parse()
+
+	if args := flag.Args(); len(args) > 0 {
+		// command-line use
+		fmt.Printf("half = %v, opt = %v, wordsize = %d bits\n", *half, *opt, W)
+		for _, arg := range args {
+			n, err := strconv.Atoi(arg)
+			if err != nil || n < 0 {
+				fmt.Println("invalid argument", arg)
+				continue
+			}
+			doFibo(n)
+		}
+		return
+	}
+
+	if *bench {
+		for i := 0; i < 4; i++ {
+			doBench(i&2 == 0, i&1 != 0)
+		}
+	}
+}
diff --git a/test/fixedbugs/bug121.go b/test/fixedbugs/bug121.go
index 5adf982..22c7181 100644
--- a/test/fixedbugs/bug121.go
+++ b/test/fixedbugs/bug121.go
@@ -15,4 +15,3 @@ type I interface {
 type J interface {
 	h T;  // ERROR "syntax|signature"
 }
-
diff --git a/test/fixedbugs/bug214.go b/test/fixedbugs/bug214.go
index 5420058..f3c25e7 100644
--- a/test/fixedbugs/bug214.go
+++ b/test/fixedbugs/bug214.go
@@ -5,7 +5,7 @@
 // license that can be found in the LICENSE file.
 
 // Used to crash the compiler.
-// http://code.google.com/p/go/issues/detail?id=88
+// https://golang.org/issue/88
 
 package main
 
diff --git a/test/fixedbugs/bug215.go b/test/fixedbugs/bug215.go
index 08ed662..b27cc7d 100644
--- a/test/fixedbugs/bug215.go
+++ b/test/fixedbugs/bug215.go
@@ -5,7 +5,7 @@
 // license that can be found in the LICENSE file.
 
 // Used to crash the compiler.
-// http://code.google.com/p/go/issues/detail?id=158
+// https://golang.org/issue/158
 
 package main
 
diff --git a/test/fixedbugs/bug216.go b/test/fixedbugs/bug216.go
index c83a522..470369a 100644
--- a/test/fixedbugs/bug216.go
+++ b/test/fixedbugs/bug216.go
@@ -5,7 +5,7 @@
 // license that can be found in the LICENSE file.
 
 // Used to be rejected
-// http://code.google.com/p/go/issues/detail?id=188
+// https://golang.org/issue/188
 
 package main
 
diff --git a/test/fixedbugs/bug217.go b/test/fixedbugs/bug217.go
index ec93c25..aafc260 100644
--- a/test/fixedbugs/bug217.go
+++ b/test/fixedbugs/bug217.go
@@ -5,7 +5,7 @@
 // license that can be found in the LICENSE file.
 
 // Used to crash
-// http://code.google.com/p/go/issues/detail?id=204
+// https://golang.org/issue/204
 
 package main
 
diff --git a/test/fixedbugs/bug218.go b/test/fixedbugs/bug218.go
index 0e008db..f159f05 100644
--- a/test/fixedbugs/bug218.go
+++ b/test/fixedbugs/bug218.go
@@ -5,7 +5,7 @@
 // license that can be found in the LICENSE file.
 
 // Crashes 6g, 8g
-// http://code.google.com/p/go/issues/detail?id=238
+// https://golang.org/issue/238
 
 package main
 
diff --git a/test/fixedbugs/bug221.go b/test/fixedbugs/bug221.go
index 86fda20..4275474 100644
--- a/test/fixedbugs/bug221.go
+++ b/test/fixedbugs/bug221.go
@@ -7,7 +7,7 @@
 // function call arg reordering was picking out 1 call that
 // didn't need to be in a temporary, but it was picking
 // out the first call instead of the last call.
-// http://code.google.com/p/go/issues/detail?id=370
+// https://golang.org/issue/370
 
 package main
 
diff --git a/test/fixedbugs/bug248.go b/test/fixedbugs/bug248.go
index 98cda35..173b46f 100644
--- a/test/fixedbugs/bug248.go
+++ b/test/fixedbugs/bug248.go
@@ -1,15 +1,53 @@
-// $G $D/$F.dir/bug0.go &&
-// $G $D/$F.dir/bug1.go &&
-// $G $D/$F.dir/bug2.go &&
-// errchk $G -e $D/$F.dir/bug3.go &&
-// $L bug2.$A &&
-// ./$A.out || echo BUG: failed to compile
-
-// NOTE: This test is not run by 'run.go' and so not run by all.bash.
-// To run this test you must use the ./run shell script.
+// +build !nacl,!plan9,!windows
+// run
 
 // 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.
 
-ignored
+package main
+
+import (
+	"fmt"
+	"os"
+	"os/exec"
+	"path/filepath"
+)
+
+func main() {
+	// TODO: If we get rid of errchk, re-enable this test on Windows.
+	errchk, err := filepath.Abs("errchk")
+	check(err)
+
+	err = os.Chdir(filepath.Join("fixedbugs", "bug248.dir"))
+	check(err)
+
+	run("go", "tool", "compile", "bug0.go")
+	run("go", "tool", "compile", "bug1.go")
+	run("go", "tool", "compile", "bug2.go")
+	run(errchk, "go", "tool", "compile", "-e", "bug3.go")
+	run("go", "tool", "link", "bug2.o")
+	run(fmt.Sprintf(".%ca.out", filepath.Separator))
+
+	os.Remove("bug0.o")
+	os.Remove("bug1.o")
+	os.Remove("bug2.o")
+	os.Remove("a.out")
+}
+
+func run(name string, args ...string) {
+	cmd := exec.Command(name, args...)
+	out, err := cmd.CombinedOutput()
+	if err != nil {
+		fmt.Println(string(out))
+		fmt.Println(err)
+		os.Exit(1)
+	}
+}
+
+func check(err error) {
+	if err != nil {
+		fmt.Println(err)
+		os.Exit(1)
+	}
+}
diff --git a/test/fixedbugs/bug264.go b/test/fixedbugs/bug264.go
index fcf373c..2f320de 100644
--- a/test/fixedbugs/bug264.go
+++ b/test/fixedbugs/bug264.go
@@ -4,7 +4,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Test case for http://code.google.com/p/go/issues/detail?id=692
+// Test case for https://golang.org/issue/692
 
 package main
 
diff --git a/test/fixedbugs/bug265.go b/test/fixedbugs/bug265.go
index 7f06fce..5e05166 100644
--- a/test/fixedbugs/bug265.go
+++ b/test/fixedbugs/bug265.go
@@ -4,7 +4,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// Test case for http://code.google.com/p/go/issues/detail?id=700
+// Test case for https://golang.org/issue/700
 
 package main
 
diff --git a/test/fixedbugs/bug269.go b/test/fixedbugs/bug269.go
index c13eb26..60ee7ee 100644
--- a/test/fixedbugs/bug269.go
+++ b/test/fixedbugs/bug269.go
@@ -4,7 +4,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// http://code.google.com/p/go/issues/detail?id=749
+// https://golang.org/issue/749
 
 package main
 
diff --git a/test/fixedbugs/bug271.go b/test/fixedbugs/bug271.go
index 88add70..30d9bb1 100644
--- a/test/fixedbugs/bug271.go
+++ b/test/fixedbugs/bug271.go
@@ -4,7 +4,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// http://code.google.com/p/go/issues/detail?id=662
+// https://golang.org/issue/662
 
 package main
 
diff --git a/test/fixedbugs/bug272.go b/test/fixedbugs/bug272.go
index c27f7ee..f943d68 100644
--- a/test/fixedbugs/bug272.go
+++ b/test/fixedbugs/bug272.go
@@ -4,7 +4,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// http://code.google.com/p/go/issues/detail?id=589
+// https://golang.org/issue/589
 
 package main
 
diff --git a/test/fixedbugs/bug273.go b/test/fixedbugs/bug273.go
index aabb912..b4e3f65 100644
--- a/test/fixedbugs/bug273.go
+++ b/test/fixedbugs/bug273.go
@@ -4,7 +4,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// http://code.google.com/p/go/issues/detail?id=589
+// https://golang.org/issue/589
 
 package main
 
diff --git a/test/fixedbugs/bug274.go b/test/fixedbugs/bug274.go
index beb2d61..e57d147 100644
--- a/test/fixedbugs/bug274.go
+++ b/test/fixedbugs/bug274.go
@@ -13,7 +13,7 @@
 // Both gccgo and gofmt correctly refuse this program as is and accept it
 // when the semicolons are present.
 
-// This is a test case for issue 777 ( http://code.google.com/p/go/issues/detail?id=777 ).
+// This is a test case for issue 777 ( https://golang.org/issue/777 ).
 
 package main
 
diff --git a/test/fixedbugs/bug279.go b/test/fixedbugs/bug279.go
index e5ec594..726ba60 100644
--- a/test/fixedbugs/bug279.go
+++ b/test/fixedbugs/bug279.go
@@ -4,7 +4,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// http://code.google.com/p/go/issues/detail?id=799
+// https://golang.org/issue/799
 
 package main
 
diff --git a/test/fixedbugs/bug280.go b/test/fixedbugs/bug280.go
index ba594a2..3925b9a 100644
--- a/test/fixedbugs/bug280.go
+++ b/test/fixedbugs/bug280.go
@@ -4,7 +4,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// http://code.google.com/p/go/issues/detail?id=808
+// https://golang.org/issue/808
 
 package main
 
diff --git a/test/fixedbugs/bug281.go b/test/fixedbugs/bug281.go
index 24d6fdc..92c8d86 100644
--- a/test/fixedbugs/bug281.go
+++ b/test/fixedbugs/bug281.go
@@ -4,7 +4,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// http://code.google.com/p/go/issues/detail?id=807
+// https://golang.org/issue/807
 
 package main
 
diff --git a/test/fixedbugs/bug283.go b/test/fixedbugs/bug283.go
index eefed03..1f7f6e0 100644
--- a/test/fixedbugs/bug283.go
+++ b/test/fixedbugs/bug283.go
@@ -4,7 +4,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// http://code.google.com/p/go/issues/detail?id=806
+// https://golang.org/issue/806
 // triggered out of registers on 8g
 
 package bug283
diff --git a/test/fixedbugs/bug285.go b/test/fixedbugs/bug285.go
index 0a8a0f0..e0b3766 100644
--- a/test/fixedbugs/bug285.go
+++ b/test/fixedbugs/bug285.go
@@ -6,7 +6,7 @@
 
 // Test for issue 778: Map key values that are assignment
 // compatible with the map key type must be accepted according
-// to the spec: http://golang.org/doc/go_spec.html#Indexes .
+// to the spec: https://golang.org/doc/go_spec.html#Indexes .
 
 package main
 
diff --git a/test/fixedbugs/bug290.go b/test/fixedbugs/bug290.go
index c8ff0bc..46ebc1f 100644
--- a/test/fixedbugs/bug290.go
+++ b/test/fixedbugs/bug290.go
@@ -4,7 +4,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// http://code.google.com/p/go/issues/detail?id=920
+// https://golang.org/issue/920
 
 package main
 
diff --git a/test/fixedbugs/bug291.go b/test/fixedbugs/bug291.go
index 17a5483..d627a9d 100644
--- a/test/fixedbugs/bug291.go
+++ b/test/fixedbugs/bug291.go
@@ -4,7 +4,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// http://code.google.com/p/go/issues/detail?id=915
+// https://golang.org/issue/915
 
 package main
 
diff --git a/test/fixedbugs/bug292.go b/test/fixedbugs/bug292.go
index 07051dd..0c24912 100644
--- a/test/fixedbugs/bug292.go
+++ b/test/fixedbugs/bug292.go
@@ -4,7 +4,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// http://code.google.com/p/go/issues/detail?id=843
+// https://golang.org/issue/843
 
 package main
 
diff --git a/test/fixedbugs/bug293.go b/test/fixedbugs/bug293.go
index bf926f5..c985305 100644
--- a/test/fixedbugs/bug293.go
+++ b/test/fixedbugs/bug293.go
@@ -4,7 +4,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// http://code.google.com/p/go/issues/detail?id=846
+// https://golang.org/issue/846
 
 package main
 
diff --git a/test/fixedbugs/bug294.go b/test/fixedbugs/bug294.go
index 0f3e380..ec41fe8 100644
--- a/test/fixedbugs/bug294.go
+++ b/test/fixedbugs/bug294.go
@@ -4,7 +4,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// http://code.google.com/p/go/issues/detail?id=800
+// https://golang.org/issue/800
 
 package main
 
diff --git a/test/fixedbugs/bug301.go b/test/fixedbugs/bug301.go
index 572668f..fc52503 100644
--- a/test/fixedbugs/bug301.go
+++ b/test/fixedbugs/bug301.go
@@ -4,7 +4,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// http://code.google.com/p/go/issues/detail?id=990
+// https://golang.org/issue/990
 
 package main
 
diff --git a/test/fixedbugs/bug302.dir/main.go b/test/fixedbugs/bug302.dir/main.go
index 9f874d0..281f908 100644
--- a/test/fixedbugs/bug302.dir/main.go
+++ b/test/fixedbugs/bug302.dir/main.go
@@ -5,8 +5,8 @@
 package main
 
 // Check that the export information is correct in p.6.
-import _ "./p"
+import _ "p"
 
 // Check that it's still correct in pp.a (which contains p.6).
-import _ "./pp"
+import _ "pp"
 
diff --git a/test/fixedbugs/bug302.go b/test/fixedbugs/bug302.go
index dc7637f..42345a9 100644
--- a/test/fixedbugs/bug302.go
+++ b/test/fixedbugs/bug302.go
@@ -1,9 +1,33 @@
-// $G $D/bug302.dir/p.go && pack grc pp.a p.$A && $G $D/bug302.dir/main.go
-
-// NOTE: This test is not run by 'run.go' and so not run by all.bash.
-// To run this test you must use the ./run shell script.
+// +build !nacl
+// run
 
 // Copyright 2010 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 (
+	"fmt"
+	"os"
+	"os/exec"
+	"path/filepath"
+)
+
+func main() {
+	run("go", "tool", "compile", filepath.Join("fixedbugs", "bug302.dir", "p.go"))
+	run("go", "tool", "pack", "grc", "pp.a", "p.o")
+	run("go", "tool", "compile", "-I", ".", filepath.Join("fixedbugs", "bug302.dir", "main.go"))
+	os.Remove("p.o")
+	os.Remove("pp.a")
+	os.Remove("main.o")
+}
+
+func run(cmd string, args ...string) {
+	out, err := exec.Command(cmd, args...).CombinedOutput()
+	if err != nil {
+		fmt.Println(string(out))
+		fmt.Println(err)
+		os.Exit(1)
+	}
+}
diff --git a/test/fixedbugs/bug345.go b/test/fixedbugs/bug345.go
index e3705f6..e291a55 100644
--- a/test/fixedbugs/bug345.go
+++ b/test/fixedbugs/bug345.go
@@ -1,10 +1,45 @@
-// $G $D/$F.dir/io.go && errchk $G -e $D/$F.dir/main.go
-
-// NOTE: This test is not run by 'run.go' and so not run by all.bash.
-// To run this test you must use the ./run shell script.
+// +build !nacl,!plan9,!windows
+// run
 
 // 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 ignored
+package main
+
+import (
+	"fmt"
+	"os"
+	"os/exec"
+	"path/filepath"
+)
+
+func main() {
+	// TODO: If we get rid of errchk, re-enable this test on Plan 9 and Windows.
+	errchk, err := filepath.Abs("errchk")
+	check(err)
+
+	err = os.Chdir(filepath.Join(".", "fixedbugs", "bug345.dir"))
+	check(err)
+
+	run("go", "tool", "compile", "io.go")
+	run(errchk, "go", "tool", "compile", "-e", "main.go")
+	os.Remove("io.o")
+}
+
+func run(name string, args ...string) {
+	cmd := exec.Command(name, args...)
+	out, err := cmd.CombinedOutput()
+	if err != nil {
+		fmt.Println(string(out))
+		fmt.Println(err)
+		os.Exit(1)
+	}
+}
+
+func check(err error) {
+	if err != nil {
+		fmt.Println(err)
+		os.Exit(1)
+	}
+}
diff --git a/test/fixedbugs/bug346.go b/test/fixedbugs/bug346.go
index d9203aa..f69b58d 100644
--- a/test/fixedbugs/bug346.go
+++ b/test/fixedbugs/bug346.go
@@ -9,11 +9,28 @@ package main
 import "os"
 
 func main() {
-	x := 4
-	a, b, c, d := func(i int) (p int, q int, r int, s int) { return 1, i, 3, x }(2)
+	// Test unclosed closure.
+	{
+		x := 4
+		a, b, c, d := func(i int) (p int, q int, r int, s int) { return 1, i, 3, x }(2)
 
-	if a != 1 || b != 2 || c != 3 || d != 4 {
-		println("abcd: expected 1 2 3 4 got", a, b, c, d)
-		os.Exit(1)
+		if a != 1 || b != 2 || c != 3 || d != 4 {
+			println("1# abcd: expected 1 2 3 4 got", a, b, c, d)
+			os.Exit(1)
+		}
+	}
+	// Test real closure.
+	{
+		x := 4
+		gf = func(i int) (p int, q int, r int, s int) { return 1, i, 3, x }
+
+		a, b, c, d := gf(2)
+
+		if a != 1 || b != 2 || c != 3 || d != 4 {
+			println("2# abcd: expected 1 2 3 4 got", a, b, c, d)
+			os.Exit(1)
+		}
 	}
 }
+
+var gf func(int) (int, int, int, int)
diff --git a/test/fixedbugs/bug369.dir/main.go b/test/fixedbugs/bug369.dir/main.go
new file mode 100644
index 0000000..1c9e36b
--- /dev/null
+++ b/test/fixedbugs/bug369.dir/main.go
@@ -0,0 +1,54 @@
+// 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 main
+
+import (
+	"flag"
+	"os"
+	"runtime"
+	"testing"
+
+	fast "./fast"
+	slow "./slow"
+)
+
+var buf = make([]byte, 1048576)
+
+func BenchmarkFastNonASCII(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		fast.NonASCII(buf, 0)
+	}
+}
+
+func BenchmarkSlowNonASCII(b *testing.B) {
+	for i := 0; i < b.N; i++ {
+		slow.NonASCII(buf, 0)
+	}
+}
+
+func main() {
+	os.Args = []string{os.Args[0], "-test.benchtime=100ms"}
+	flag.Parse()
+
+	rslow := testing.Benchmark(BenchmarkSlowNonASCII)
+	rfast := testing.Benchmark(BenchmarkFastNonASCII)
+	tslow := rslow.NsPerOp()
+	tfast := rfast.NsPerOp()
+
+	// Optimization should be good for at least 2x, but be forgiving.
+	// On the ARM simulator we see closer to 1.5x.
+	speedup := float64(tslow) / float64(tfast)
+	want := 1.8
+	if runtime.GOARCH == "arm" {
+		want = 1.3
+	}
+	if speedup < want {
+		// TODO(rsc): doesn't work on linux-amd64 or darwin-amd64 builders, nor on
+		// a Lenovo x200 (linux-amd64) laptop.
+		// println("fast:", tfast, "slow:", tslow, "speedup:", speedup, "want:", want)
+		// println("not fast enough")
+		// os.Exit(1)
+	}
+}
diff --git a/test/fixedbugs/bug369.go b/test/fixedbugs/bug369.go
index 6d52622..dd48da8 100644
--- a/test/fixedbugs/bug369.go
+++ b/test/fixedbugs/bug369.go
@@ -1,10 +1,6 @@
-// $G -N -o slow.$A $D/bug369.dir/pkg.go &&
-// $G -o fast.$A $D/bug369.dir/pkg.go &&
+// +build !nacl,!windows
 // run
 
-// NOTE: This test is not run by 'run.go' and so not run by all.bash.
-// To run this test you must use the ./run shell script.
-
 // 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.
@@ -14,49 +10,41 @@
 package main
 
 import (
-	"flag"
+	"fmt"
 	"os"
-	"runtime"
-	"testing"
-
-	fast "./fast"
-	slow "./slow"
+	"os/exec"
+	"path/filepath"
 )
 
-var buf = make([]byte, 1048576)
-
-func BenchmarkFastNonASCII(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		fast.NonASCII(buf, 0)
-	}
+func main() {
+	err := os.Chdir(filepath.Join(".", "fixedbugs", "bug369.dir"))
+	check(err)
+
+	run("go", "tool", "compile", "-N", "-o", "slow.o", "pkg.go")
+	run("go", "tool", "compile", "-o", "fast.o", "pkg.go")
+	run("go", "tool", "compile", "-o", "main.o", "main.go")
+	run("go", "tool", "link", "-o", "a.exe", "main.o")
+	run("." + string(filepath.Separator) + "a.exe")
+
+	os.Remove("slow.o")
+	os.Remove("fast.o")
+	os.Remove("main.o")
+	os.Remove("a.exe")
 }
 
-func BenchmarkSlowNonASCII(b *testing.B) {
-	for i := 0; i < b.N; i++ {
-		slow.NonASCII(buf, 0)
+func run(name string, args ...string) {
+	cmd := exec.Command(name, args...)
+	out, err := cmd.CombinedOutput()
+	if err != nil {
+		fmt.Println(string(out))
+		fmt.Println(err)
+		os.Exit(1)
 	}
 }
 
-func main() {
-	os.Args = []string{os.Args[0], "-test.benchtime=100ms"}
-	flag.Parse()
-
-	rslow := testing.Benchmark(BenchmarkSlowNonASCII)
-	rfast := testing.Benchmark(BenchmarkFastNonASCII)
-	tslow := rslow.NsPerOp()
-	tfast := rfast.NsPerOp()
-
-	// Optimization should be good for at least 2x, but be forgiving.
-	// On the ARM simulator we see closer to 1.5x.
-	speedup := float64(tslow)/float64(tfast)
-	want := 1.8
-	if runtime.GOARCH == "arm" {
-		want = 1.3
-	}
-	if speedup < want {
-		// TODO(rsc): doesn't work on linux-amd64 or darwin-amd64 builders, nor on
-		// a Lenovo x200 (linux-amd64) laptop.
-		//println("fast:", tfast, "slow:", tslow, "speedup:", speedup, "want:", want)
-		//println("not fast enough")
+func check(err error) {
+	if err != nil {
+		fmt.Println(err)
+		os.Exit(1)
 	}
 }
diff --git a/test/fixedbugs/bug425.go b/test/fixedbugs/bug425.go
index 5546bd9..c3035f6 100644
--- a/test/fixedbugs/bug425.go
+++ b/test/fixedbugs/bug425.go
@@ -4,7 +4,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// http://code.google.com/p/go/issues/detail?id=3119
+// https://golang.org/issue/3119
 
 package main
 
diff --git a/test/fixedbugs/bug427.go b/test/fixedbugs/bug427.go
index 1239e7a..c13bb81 100644
--- a/test/fixedbugs/bug427.go
+++ b/test/fixedbugs/bug427.go
@@ -4,7 +4,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// http://code.google.com/p/go/issues/detail?id=3351
+// https://golang.org/issue/3351
 
 package main
 
diff --git a/test/fixedbugs/bug429.go b/test/fixedbugs/bug429.go
index 794d293..31d5a3a 100644
--- a/test/fixedbugs/bug429.go
+++ b/test/fixedbugs/bug429.go
@@ -1,13 +1,11 @@
-// $G $D/$F.go && $L $F.$A && ! ./$A.out || echo BUG: bug429
-
-// NOTE: This test is not run by 'run.go' and so not run by all.bash.
-// To run this test you must use the ./run shell script.
+// skip
 
 // 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.
 
 // Should print deadlock message, not hang.
+// This test is run by bug429_run.go.
 
 package main
 
diff --git a/test/fixedbugs/bug429_run.go b/test/fixedbugs/bug429_run.go
new file mode 100644
index 0000000..284033d
--- /dev/null
+++ b/test/fixedbugs/bug429_run.go
@@ -0,0 +1,34 @@
+// +build !nacl
+// run
+
+// 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.
+
+// Run the bug429.go test.
+
+package main
+
+import (
+	"fmt"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"strings"
+)
+
+func main() {
+	cmd := exec.Command("go", "run", filepath.Join("fixedbugs", "bug429.go"))
+	out, err := cmd.CombinedOutput()
+	if err == nil {
+		fmt.Println("expected deadlock")
+		os.Exit(1)
+	}
+
+	want := "fatal error: all goroutines are asleep - deadlock!"
+	got := string(out)
+	if !strings.Contains(got, want) {
+		fmt.Printf("got:\n%q\nshould contain:\n%q\n", got, want)
+		os.Exit(1)
+	}
+}
diff --git a/test/fixedbugs/bug435.go b/test/fixedbugs/bug435.go
index 45323d8..0c2ac7b 100644
--- a/test/fixedbugs/bug435.go
+++ b/test/fixedbugs/bug435.go
@@ -7,7 +7,7 @@
 // Test that a syntax error caused by an unexpected EOF
 // gives an error message with the correct line number.
 //
-// https://code.google.com/p/go/issues/detail?id=3392
+// https://golang.org/issue/3392
 
 package main
 
diff --git a/test/fixedbugs/bug492.dir/a.go b/test/fixedbugs/bug492.dir/a.go
new file mode 100644
index 0000000..90917e5
--- /dev/null
+++ b/test/fixedbugs/bug492.dir/a.go
@@ -0,0 +1,16 @@
+// 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 a
+
+type s struct {
+	s string
+}
+
+func F1(s s) {
+}
+
+func F2() s {
+	return s{""}
+}
diff --git a/test/fixedbugs/bug492.dir/b.go b/test/fixedbugs/bug492.dir/b.go
new file mode 100644
index 0000000..5b8c4f2
--- /dev/null
+++ b/test/fixedbugs/bug492.dir/b.go
@@ -0,0 +1,11 @@
+// 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 "./a"
+
+func main() {
+	defer a.F1(a.F2())
+}
diff --git a/test/fixedbugs/bug492.go b/test/fixedbugs/bug492.go
new file mode 100644
index 0000000..050a9e5
--- /dev/null
+++ b/test/fixedbugs/bug492.go
@@ -0,0 +1,9 @@
+// rundir
+
+// 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.
+
+// Test case that gccgo failed to link.
+
+package ignored
diff --git a/test/fixedbugs/bug493.go b/test/fixedbugs/bug493.go
new file mode 100644
index 0000000..643e9af
--- /dev/null
+++ b/test/fixedbugs/bug493.go
@@ -0,0 +1,15 @@
+// compile
+
+// 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.
+
+// Test case that gccgo failed to compile.
+
+package p
+
+func F() []string {
+	return []string{""}
+}
+
+var V = append(F())
diff --git a/test/fixedbugs/bug494.go b/test/fixedbugs/bug494.go
new file mode 100644
index 0000000..42f1879
--- /dev/null
+++ b/test/fixedbugs/bug494.go
@@ -0,0 +1,51 @@
+// run
+
+// 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.
+
+// Gccgo incorrectly executed functions multiple times when they
+// appeared in a composite literal that required a conversion between
+// different interface types.
+
+package main
+
+type MyInt int
+
+var c MyInt
+
+func (c *MyInt) S(i int) {
+	*c = MyInt(i)
+}
+
+func (c *MyInt) V() int {
+	return int(*c)
+}
+
+type i1 interface {
+	S(int)
+	V() int
+}
+
+type i2 interface {
+	V() int
+}
+
+type s struct {
+	i i2
+}
+
+func f() i1 {
+	c++
+	return &c
+}
+
+func main() {
+	p := &s{f()}
+	if v := p.i.V(); v != 1 {
+		panic(v)
+	}
+	if c != 1 {
+		panic(c)
+	}
+}
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/gcc61204.go b/test/fixedbugs/gcc61204.go
new file mode 100644
index 0000000..5a5bb16
--- /dev/null
+++ b/test/fixedbugs/gcc61204.go
@@ -0,0 +1,17 @@
+// compile
+
+// 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.
+
+// PR61204: Making temporaries for zero-sized types caused an ICE in gccgo.
+// This is a reduction of a program reported by GoSmith.
+
+package main
+
+func main() {
+	type t [0]int
+	var v t
+	v, _ = [0]int{}, 0
+	_ = v
+}
diff --git a/test/fixedbugs/gcc61244.go b/test/fixedbugs/gcc61244.go
new file mode 100644
index 0000000..7fbc872
--- /dev/null
+++ b/test/fixedbugs/gcc61244.go
@@ -0,0 +1,19 @@
+// compile
+
+// 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.
+
+// PR61244: Type descriptors expressions were not traversed, causing an ICE
+// in gccgo when producing the backend representation.
+// This is a reduction of a program reported by GoSmith.
+
+package main
+
+const a = 0
+
+func main() {
+	switch i := (interface{})(a); i.(type) {
+	case [0]string:
+	}
+}
diff --git a/test/fixedbugs/gcc61246.go b/test/fixedbugs/gcc61246.go
new file mode 100644
index 0000000..4866570
--- /dev/null
+++ b/test/fixedbugs/gcc61246.go
@@ -0,0 +1,17 @@
+// compile
+
+// 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.
+
+// PR61246: Switch conditions could be untyped, causing an ICE when the
+// conditions were lowered into temporaries.
+// This is a reduction of a program reported by GoSmith.
+
+package main
+
+func main() {
+	switch 1 != 1 {
+	default:
+	}
+}
diff --git a/test/fixedbugs/gcc61248.go b/test/fixedbugs/gcc61248.go
new file mode 100644
index 0000000..593c634
--- /dev/null
+++ b/test/fixedbugs/gcc61248.go
@@ -0,0 +1,14 @@
+// compile
+
+// 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.
+
+// PR61248: Transformations to recover calls made them fail typechecking in gccgo.
+
+package main
+
+func main() {
+	var f func(int, interface{})
+	go f(0, recover())
+}
diff --git a/test/fixedbugs/gcc61253.go b/test/fixedbugs/gcc61253.go
new file mode 100644
index 0000000..dc125ac
--- /dev/null
+++ b/test/fixedbugs/gcc61253.go
@@ -0,0 +1,20 @@
+// compile
+
+// 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.
+
+// PR61253: gccgo incorrectly parsed the
+// `RecvStmt = ExpressionList "=" RecvExpr` production.
+
+package main
+
+func main() {
+	c := make(chan int)
+	v := new(int)
+	b := new(bool)
+	select {
+	case (*v), (*b) = <-c:
+	}
+
+}
diff --git a/test/fixedbugs/gcc61254.go b/test/fixedbugs/gcc61254.go
new file mode 100644
index 0000000..36ac7d4
--- /dev/null
+++ b/test/fixedbugs/gcc61254.go
@@ -0,0 +1,13 @@
+// compile
+
+// 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.
+
+// PR61254: gccgo failed to compile a slice expression with missing indices.
+
+package main
+
+func main() {
+	[][]int{}[:][0][0]++
+}
diff --git a/test/fixedbugs/gcc61255.go b/test/fixedbugs/gcc61255.go
new file mode 100644
index 0000000..a0e6d18
--- /dev/null
+++ b/test/fixedbugs/gcc61255.go
@@ -0,0 +1,13 @@
+// compile
+
+// 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.
+
+// PR61255: gccgo failed to compile IncDec statements on variadic functions.
+
+package main
+
+func main() {
+	append([]byte{}, 0)[0]++
+}
diff --git a/test/fixedbugs/gcc61258.go b/test/fixedbugs/gcc61258.go
new file mode 100644
index 0000000..8474665
--- /dev/null
+++ b/test/fixedbugs/gcc61258.go
@@ -0,0 +1,13 @@
+// run
+
+// 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.
+
+// PR61258: gccgo crashed when deleting a zero-sized key from a map.
+
+package main
+
+func main() {
+	delete(make(map[[0]bool]int), [0]bool{})
+}
diff --git a/test/fixedbugs/gcc61264.go b/test/fixedbugs/gcc61264.go
new file mode 100644
index 0000000..d4e05f4
--- /dev/null
+++ b/test/fixedbugs/gcc61264.go
@@ -0,0 +1,13 @@
+// compile
+
+// 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.
+
+// PR61264: IncDec statements involving composite literals caused in ICE in gccgo.
+
+package main
+
+func main() {
+        map[int]int{}[0]++
+}
diff --git a/test/fixedbugs/gcc61265.go b/test/fixedbugs/gcc61265.go
new file mode 100644
index 0000000..42fae36
--- /dev/null
+++ b/test/fixedbugs/gcc61265.go
@@ -0,0 +1,16 @@
+// compile
+
+// 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.
+
+// PR61265: The gccgo middle-end failed to represent array composite literals
+// where the elements are zero-sized values.
+// This is a reduction of a program reported by GoSmith.
+
+package p
+
+var a = [1][0]int{B}[0]
+var B = [0]int{}
+var c = [1]struct{}{D}[0]
+var D = struct{}{}
diff --git a/test/fixedbugs/gcc61273.go b/test/fixedbugs/gcc61273.go
new file mode 100644
index 0000000..2983222
--- /dev/null
+++ b/test/fixedbugs/gcc61273.go
@@ -0,0 +1,16 @@
+// compile
+
+// 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.
+
+// PR61273: gccgo failed to compile a SendStmt in the PostStmt of a ForClause
+// that involved predefined constants.
+
+package main
+
+func main() {
+	c := make(chan bool, 1)
+	for ; false; c <- false {
+	}
+}
diff --git a/test/fixedbugs/gcc65755.go b/test/fixedbugs/gcc65755.go
new file mode 100644
index 0000000..e76f4d1
--- /dev/null
+++ b/test/fixedbugs/gcc65755.go
@@ -0,0 +1,37 @@
+// 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.
+
+// PR65755: Incorrect type descriptor for type defined within method.
+
+package main
+
+import "reflect"
+
+type S1 struct{}
+
+func (S1) Fix() string {
+	type s struct {
+		f int
+	}
+	return reflect.TypeOf(s{}).Field(0).Name
+}
+
+type S2 struct{}
+
+func (S2) Fix() string {
+	type s struct {
+		g bool
+	}
+	return reflect.TypeOf(s{}).Field(0).Name
+}
+
+func main() {
+	f1 := S1{}.Fix()
+	f2 := S2{}.Fix()
+	if f1 != "f" || f2 != "g" {
+		panic(f1 + f2)
+	}
+}
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/issue10219.dir/a.go b/test/fixedbugs/issue10219.dir/a.go
new file mode 100644
index 0000000..c61d02b
--- /dev/null
+++ b/test/fixedbugs/issue10219.dir/a.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.
+
+package a
+
+type m struct {
+	S string
+}
+
+var g = struct {
+	m
+	P string
+}{
+	m{"a"},
+	"",
+}
+
+type S struct{}
+
+func (s *S) M(p string) {
+	r := g
+	r.P = p
+}
diff --git a/test/fixedbugs/issue10219.dir/b.go b/test/fixedbugs/issue10219.dir/b.go
new file mode 100644
index 0000000..09d8911
--- /dev/null
+++ b/test/fixedbugs/issue10219.dir/b.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 b
+
+import "./a"
+
+func F() *a.S {
+	return &a.S{}
+}
diff --git a/test/fixedbugs/issue10219.dir/c.go b/test/fixedbugs/issue10219.dir/c.go
new file mode 100644
index 0000000..d331495
--- /dev/null
+++ b/test/fixedbugs/issue10219.dir/c.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.
+
+package c
+
+import "./b"
+
+func F() {
+	s := b.F()
+	s.M("c")
+}
diff --git a/test/fixedbugs/issue10219.go b/test/fixedbugs/issue10219.go
new file mode 100644
index 0000000..325818c
--- /dev/null
+++ b/test/fixedbugs/issue10219.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 10219: failure of inlinable function that uses embedded types
+// in an anonymous struct via :=.
+
+package ignored
diff --git a/test/fixedbugs/issue10253.go b/test/fixedbugs/issue10253.go
new file mode 100644
index 0000000..fafca6c
--- /dev/null
+++ b/test/fixedbugs/issue10253.go
@@ -0,0 +1,26 @@
+// 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 10253: cmd/7g: bad codegen, probably regopt related
+
+package main
+
+func main() {
+	if !eq() {
+		panic("wrong value")
+	}
+}
+
+var text = "abc"
+var s = &str{text}
+
+func eq() bool {
+	return text[0] == s.text[0]
+}
+
+type str struct {
+	text string
+}
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/fixedbugs/issue10320.go b/test/fixedbugs/issue10320.go
new file mode 100644
index 0000000..697aad1
--- /dev/null
+++ b/test/fixedbugs/issue10320.go
@@ -0,0 +1,55 @@
+// 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 10320: 7g failed to compile a program because it attempted
+// to use ZR as register. Other programs compiled but failed to
+// execute correctly because they clobbered the g register.
+
+package main
+
+func main() {
+	var x00, x01, x02, x03, x04, x05, x06, x07, x08, x09 int
+	var x10, x11, x12, x13, x14, x15, x16, x17, x18, x19 int
+	var x20, x21, x22, x23, x24, x25, x26, x27, x28, x29 int
+	var x30, x31, x32 int
+
+	_ = x00
+	_ = x01
+	_ = x02
+	_ = x03
+	_ = x04
+	_ = x05
+	_ = x06
+	_ = x07
+	_ = x08
+	_ = x09
+
+	_ = x10
+	_ = x11
+	_ = x12
+	_ = x13
+	_ = x14
+	_ = x15
+	_ = x16
+	_ = x17
+	_ = x18
+	_ = x19
+
+	_ = x20
+	_ = x21
+	_ = x22
+	_ = x23
+	_ = x24
+	_ = x25
+	_ = x26
+	_ = x27
+	_ = x28
+	_ = x29
+
+	_ = x30
+	_ = x31
+	_ = x32
+}
diff --git a/test/fixedbugs/issue10332.go b/test/fixedbugs/issue10332.go
new file mode 100644
index 0000000..e00a8b4
--- /dev/null
+++ b/test/fixedbugs/issue10332.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.
+
+// The PkgPath of unexported fields of types defined in package main was incorrectly ""
+
+package main
+
+import (
+	"fmt"
+	"reflect"
+)
+
+type foo struct {
+	bar int
+}
+
+func main() {
+	pkgpath := reflect.ValueOf(foo{}).Type().Field(0).PkgPath
+	if pkgpath != "main" {
+		fmt.Printf("BUG: incorrect PkgPath: %v", pkgpath)
+	}
+}
diff --git a/test/fixedbugs/issue10353.go b/test/fixedbugs/issue10353.go
new file mode 100644
index 0000000..87771d4
--- /dev/null
+++ b/test/fixedbugs/issue10353.go
@@ -0,0 +1,49 @@
+// 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 10253: cmd/gc: incorrect escape analysis of closures
+// Partial call x.foo was not promoted to heap.
+
+package main
+
+func main() {
+	c := make(chan bool)
+	// Create a new goroutine to get a default-size stack segment.
+	go func() {
+		x := new(X)
+		clos(x.foo)()
+		c <- true
+	}()
+	<-c
+}
+
+type X int
+
+func (x *X) foo() {
+}
+
+func clos(x func()) func() {
+	f := func() {
+		print("")
+		x() // This statement crashed, because the partial call was allocated on the old stack.
+	}
+	// Grow stack so that partial call x becomes invalid if allocated on stack.
+	growstack(10000)
+	c := make(chan bool)
+	// Spoil the previous stack segment.
+	go func() {
+		c <- true
+	}()
+	<-c
+	return f
+}
+
+func growstack(x int) {
+	if x == 0 {
+		return
+	}
+	growstack(x - 1)
+}
diff --git a/test/fixedbugs/issue10407.go b/test/fixedbugs/issue10407.go
new file mode 100644
index 0000000..fe033ef
--- /dev/null
+++ b/test/fixedbugs/issue10407.go
@@ -0,0 +1,16 @@
+// runoutput
+
+// 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 10407: gccgo failed to remove carriage returns
+// from raw string literals.
+
+package main
+
+import "fmt"
+
+func main() {
+	fmt.Println("package main\nfunc main() { if `a\rb\r\nc` != \"ab\\nc\" { panic(42) }}")
+}
diff --git a/test/fixedbugs/issue10441.go b/test/fixedbugs/issue10441.go
new file mode 100644
index 0000000..25832fa
--- /dev/null
+++ b/test/fixedbugs/issue10441.go
@@ -0,0 +1,17 @@
+// build
+
+// 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 bar() {
+	f := func() {}
+	foo(&f)
+}
+
+func foo(f *func()) func() {
+	defer func() {}() // prevent inlining of foo
+	return *f
+}
diff --git a/test/fixedbugs/issue10486.go b/test/fixedbugs/issue10486.go
new file mode 100644
index 0000000..f346828
--- /dev/null
+++ b/test/fixedbugs/issue10486.go
@@ -0,0 +1,31 @@
+// 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 10486.
+// Check stack walk during div by zero fault,
+// especially on software divide systems.
+
+package main
+
+import "runtime"
+
+var A, B int
+
+func divZero() int {
+	defer func() {
+		if p := recover(); p != nil {
+			var pcs [512]uintptr
+			runtime.Callers(2, pcs[:])
+			runtime.GC()
+		}
+	}()
+	return A / B
+}
+
+func main() {
+	A = 1
+	divZero()
+}
diff --git a/test/fixedbugs/issue10607.go b/test/fixedbugs/issue10607.go
new file mode 100644
index 0000000..bf527d0
--- /dev/null
+++ b/test/fixedbugs/issue10607.go
@@ -0,0 +1,31 @@
+// +build linux,!ppc64,!ppc64le
+// 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 a -B option is passed through when using both internal
+// and external linking mode.
+
+package main
+
+import (
+	"fmt"
+	"os"
+	"os/exec"
+	"path/filepath"
+)
+
+func main() {
+	test("internal")
+	test("external")
+}
+
+func test(linkmode string) {
+	out, err := exec.Command("go", "run", "-ldflags", "-B=0x12345678 -linkmode="+linkmode, filepath.Join("fixedbugs", "issue10607a.go")).CombinedOutput()
+	if err != nil {
+		fmt.Printf("BUG: linkmode=%s %v\n%s\n", linkmode, err, out)
+		os.Exit(1)
+	}
+}
diff --git a/test/fixedbugs/issue10607a.go b/test/fixedbugs/issue10607a.go
new file mode 100644
index 0000000..18bf1a2
--- /dev/null
+++ b/test/fixedbugs/issue10607a.go
@@ -0,0 +1,81 @@
+// skip
+
+// 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 is built by issue10607.go with a -B option.
+// Verify that we have one build-id note with the expected value.
+
+package main
+
+import (
+	"bytes"
+	"debug/elf"
+	"fmt"
+	"os"
+)
+
+func main() {
+	f, err := elf.Open("/proc/self/exe")
+	if err != nil {
+		if os.IsNotExist(err) {
+			return
+		}
+		fmt.Fprintln(os.Stderr, "opening /proc/self/exe:", err)
+		os.Exit(1)
+	}
+
+	c := 0
+	fail := false
+	for i, s := range f.Sections {
+		if s.Type != elf.SHT_NOTE {
+			continue
+		}
+
+		d, err := s.Data()
+		if err != nil {
+			fmt.Fprintln(os.Stderr, "reading data of note section %d: %v", i, err)
+			continue
+		}
+
+		for len(d) > 0 {
+			namesz := f.ByteOrder.Uint32(d)
+			descsz := f.ByteOrder.Uint32(d[4:])
+			typ := f.ByteOrder.Uint32(d[8:])
+
+			an := (namesz + 3) &^ 3
+			ad := (descsz + 3) &^ 3
+
+			if int(12+an+ad) > len(d) {
+				fmt.Fprintf(os.Stderr, "note section %d too short for header (%d < 12 + align(%d,4) + align(%d,4))\n", i, len(d), namesz, descsz)
+				break
+			}
+
+			// 3 == NT_GNU_BUILD_ID
+			if typ == 3 && namesz == 4 && bytes.Equal(d[12:16], []byte("GNU\000")) {
+				id := string(d[12+an:12+an+descsz])
+				if id == "\x12\x34\x56\x78" {
+					c++
+				} else {
+					fmt.Fprintf(os.Stderr, "wrong build ID data: %q\n", id)
+					fail = true
+				}
+			}
+
+			d = d[12+an+ad:]
+		}
+	}
+
+	if c == 0 {
+		fmt.Fprintln(os.Stderr, "no build-id note")
+		fail = true
+	} else if c > 1 {
+		fmt.Fprintln(os.Stderr, c, "build-id notes")
+		fail = true
+	}
+
+	if fail {
+		os.Exit(1)
+	}
+}
diff --git a/test/fixedbugs/issue10654.go b/test/fixedbugs/issue10654.go
new file mode 100644
index 0000000..0600a80
--- /dev/null
+++ b/test/fixedbugs/issue10654.go
@@ -0,0 +1,17 @@
+// 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 10654: Failure to use generated temps
+// for function calls etc. in boolean codegen.
+
+package main
+
+var s string
+
+func main() {
+	if (s == "this") != (s == "that") {
+	}
+}
diff --git a/test/fixedbugs/issue10700.dir/other.go b/test/fixedbugs/issue10700.dir/other.go
new file mode 100644
index 0000000..12908b9
--- /dev/null
+++ b/test/fixedbugs/issue10700.dir/other.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.
+
+package other
+
+type Exported interface {
+	Do()
+	secret()
+}
diff --git a/test/fixedbugs/issue10700.dir/test.go b/test/fixedbugs/issue10700.dir/test.go
new file mode 100644
index 0000000..2033efc
--- /dev/null
+++ b/test/fixedbugs/issue10700.dir/test.go
@@ -0,0 +1,49 @@
+// 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.
+
+package main
+
+import "./other"
+
+type Imported interface {
+	Do()
+}
+
+type HasAMethod struct {
+	x int
+}
+
+func (me *HasAMethod) Do() {
+	println(me.x)
+}
+
+func InMyCode(x *Imported, y *HasAMethod, z *other.Exported) {
+	x.Do() // ERROR "x\.Do undefined \(type \*Imported is pointer to interface, not interface\)"
+	x.do() // ERROR "x\.do undefined \(type \*Imported is pointer to interface, not interface\)"
+	(*x).Do()
+	x.Dont()    // ERROR "x\.Dont undefined \(type \*Imported is pointer to interface, not interface\)"
+	(*x).Dont() // ERROR "\(\*x\)\.Dont undefined \(type Imported has no field or method Dont\)"
+
+	y.Do()
+	y.do() // ERROR "y\.do undefined \(type \*HasAMethod has no field or method do, but does have Do\)"
+	(*y).Do()
+	(*y).do()   // ERROR "\(\*y\)\.do undefined \(type HasAMethod has no field or method do, but does have Do\)"
+	y.Dont()    // ERROR "y\.Dont undefined \(type \*HasAMethod has no field or method Dont\)"
+	(*y).Dont() // ERROR "\(\*y\)\.Dont undefined \(type HasAMethod has no field or method Dont\)"
+
+	z.Do() // ERROR "z\.Do undefined \(type \*other\.Exported is pointer to interface, not interface\)"
+	z.do() // ERROR "z\.do undefined \(type \*other\.Exported is pointer to interface, not interface\)"
+	(*z).Do()
+	(*z).do()     // ERROR "\(\*z\)\.do undefined \(type other.Exported has no field or method do, but does have Do\)"
+	z.Dont()      // ERROR "z\.Dont undefined \(type \*other\.Exported is pointer to interface, not interface\)"
+	(*z).Dont()   // ERROR "\(\*z\)\.Dont undefined \(type other\.Exported has no field or method Dont\)"
+	z.secret()    // ERROR "z\.secret undefined \(type \*other\.Exported is pointer to interface, not interface\)"
+	(*z).secret() // ERROR "\(\*z\)\.secret undefined \(cannot refer to unexported field or method secret\)"
+
+}
+
+func main() {
+}
diff --git a/test/fixedbugs/issue10700.go b/test/fixedbugs/issue10700.go
new file mode 100644
index 0000000..25544ef
--- /dev/null
+++ b/test/fixedbugs/issue10700.go
@@ -0,0 +1,7 @@
+// errorcheckdir
+
+// 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 ignored
diff --git a/test/fixedbugs/issue10925.go b/test/fixedbugs/issue10925.go
new file mode 100644
index 0000000..30add82
--- /dev/null
+++ b/test/fixedbugs/issue10925.go
@@ -0,0 +1,23 @@
+// 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.
+
+package main
+
+import "fmt"
+
+func prototype(xyz []string) {}
+func main() {
+	var got [][]string
+	f := prototype
+	f = func(ss []string) { got = append(got, ss) }
+	for _, s := range []string{"one", "two", "three"} {
+		f([]string{s})
+	}
+	if got[0][0] != "one" || got[1][0] != "two" || got[2][0] != "three" {
+		// Bug's wrong output was [[three] [three] [three]]
+		fmt.Println("Expected [[one] [two] [three]], got", got)
+	}
+}
diff --git a/test/fixedbugs/issue10977.go b/test/fixedbugs/issue10977.go
new file mode 100644
index 0000000..0b18c70
--- /dev/null
+++ b/test/fixedbugs/issue10977.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.
+
+package p
+
+type T struct{}
+
+var (
+	t = T{}
+	u = t.New()
+)
+
+func x(T) (int, int) { return 0, 0 }
+
+var _, _ = x(u)
+
+func (T) New() T { return T{} }
diff --git a/test/fixedbugs/issue11053.dir/p.go b/test/fixedbugs/issue11053.dir/p.go
new file mode 100644
index 0000000..e431cb4
--- /dev/null
+++ b/test/fixedbugs/issue11053.dir/p.go
@@ -0,0 +1,9 @@
+// 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 Int32(i int32) *int32 {
+	return &i
+}
diff --git a/test/fixedbugs/issue11053.dir/p_test.go b/test/fixedbugs/issue11053.dir/p_test.go
new file mode 100644
index 0000000..e0a9555
--- /dev/null
+++ b/test/fixedbugs/issue11053.dir/p_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 main
+
+import (
+	"fmt"
+	"p"
+)
+
+type I interface {
+	Add(out *P)
+}
+
+type P struct {
+	V *int32
+}
+
+type T struct{}
+
+var x int32 = 42
+
+func Int32x(i int32) *int32 {
+	return &i
+}
+
+func (T) Add(out *P) {
+	out.V = p.Int32(x) // inlined, p.i.2 moved to heap
+}
+
+var PP P
+var out *P = &PP
+
+func F(s I) interface{} {
+	s.Add(out) // not inlined.
+	return out
+}
+
+var s T
+
+func main() {
+	println("Starting")
+	fmt.Sprint(new(int32))
+	resp := F(s).(*P)
+	println("Before, *resp.V=", *resp.V) // Trashes *resp.V in process of printing.
+	println("After,  *resp.V=", *resp.V)
+	if got, want := *resp.V, int32(42); got != want {
+		fmt.Printf("FAIL, got %v, want %v", got, want)
+	}
+}
diff --git a/test/fixedbugs/issue11053.go b/test/fixedbugs/issue11053.go
new file mode 100644
index 0000000..06005d3
--- /dev/null
+++ b/test/fixedbugs/issue11053.go
@@ -0,0 +1,10 @@
+// rundir
+
+// 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 11053: Compiler does not run escape analysis on an inlined
+// generated method wrapper.
+
+package ignored
diff --git a/test/fixedbugs/issue11053.out b/test/fixedbugs/issue11053.out
new file mode 100644
index 0000000..a75f73c
--- /dev/null
+++ b/test/fixedbugs/issue11053.out
@@ -0,0 +1,3 @@
+Starting
+Before, *resp.V= 42
+After,  *resp.V= 42
diff --git a/test/fixedbugs/issue11256.go b/test/fixedbugs/issue11256.go
new file mode 100644
index 0000000..69fc3e8
--- /dev/null
+++ b/test/fixedbugs/issue11256.go
@@ -0,0 +1,53 @@
+// 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 stack barriers are reset when a goroutine exits without
+// returning.
+
+package main
+
+import (
+	"runtime"
+	"sync/atomic"
+	"time"
+)
+
+func main() {
+	// Let the garbage collector run concurrently.
+	runtime.GOMAXPROCS(2)
+
+	var x [100][]byte
+
+	for i := range x {
+		var done int32
+
+		go func() {
+			// Use enough stack to get stack barriers, but
+			// not so much that we go over _FixedStack.
+			// There's a very narrow window here on most
+			// OSs, so we basically can't do anything (not
+			// even a time.Sleep or a channel).
+			var buf [1024]byte
+			buf[0]++
+			for atomic.LoadInt32(&done) == 0 {
+				runtime.Gosched()
+			}
+			atomic.StoreInt32(&done, 0)
+			// Exit without unwinding stack barriers.
+			runtime.Goexit()
+		}()
+
+		// Generate some garbage.
+		x[i] = make([]byte, 1024*1024)
+
+		// Give GC some time to install stack barriers in the G.
+		time.Sleep(50 * time.Microsecond)
+		atomic.StoreInt32(&done, 1)
+		for atomic.LoadInt32(&done) == 1 {
+			runtime.Gosched()
+		}
+	}
+}
diff --git a/test/fixedbugs/issue11286.go b/test/fixedbugs/issue11286.go
new file mode 100644
index 0000000..560b7d4
--- /dev/null
+++ b/test/fixedbugs/issue11286.go
@@ -0,0 +1,34 @@
+// 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 pointer bitmaps of types with large scalar tails are
+// correctly repeated when unrolled into the heap bitmap.
+
+package main
+
+import "runtime"
+
+const D = 57
+
+type T struct {
+	a [D]float64
+	b map[string]int
+	c [D]float64
+}
+
+var ts []T
+
+func main() {
+	ts = make([]T, 4)
+	for i := range ts {
+		ts[i].b = make(map[string]int)
+	}
+	ts[3].b["abc"] = 42
+	runtime.GC()
+	if ts[3].b["abc"] != 42 {
+		panic("bad field value")
+	}
+}
diff --git a/test/fixedbugs/issue11326.go b/test/fixedbugs/issue11326.go
new file mode 100644
index 0000000..fd1fab3
--- /dev/null
+++ b/test/fixedbugs/issue11326.go
@@ -0,0 +1,28 @@
+// errorcheck
+
+// 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 "fmt"
+
+func main() {
+	var g = 1e81391777742999 // ERROR "exponent too large"
+	// The next should only cause a problem when converted to float64
+	// by the assignment, but instead the compiler rejects it outright,
+	// rather than mishandle it. Specifically, when handled, 'var h' prints:
+	//	issue11326.go:N: constant 0.93342e+536870911 overflows float64
+	// The rejection of 'var i' is just insurance. It seems to work correctly.
+	// See golang.org/issue/11326.
+	// var h = 1e2147483647     // should be "1.00000e+2147483647 overflows float64"
+	var h = 1e2147483647 // ERROR "exponent too large"
+	// var i = 1e214748364  // should be "1.00000e\+214748364 overflows float64"
+	var i = 1e214748364 // ERROR "exponent too large"
+	var j = 1e21474836  // ERROR "1.00000e\+21474836 overflows float64"
+	var k = 1e2147483   // ERROR "1.00000e\+2147483 overflows float64"
+	var l = 1e214748    // ERROR "1.00000e\+214748 overflows float64"
+	var m = 1e21474     // ERROR "1.00000e\+21474 overflows float64"
+	fmt.Println(g)
+}
diff --git a/test/fixedbugs/issue11326b.go b/test/fixedbugs/issue11326b.go
new file mode 100644
index 0000000..00effbc
--- /dev/null
+++ b/test/fixedbugs/issue11326b.go
@@ -0,0 +1,44 @@
+// 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.
+
+package main
+
+func main() {
+	/* TODO(rsc): Should work but does not. See golang.org/issue/11326.
+	{
+		const n = 1e2147483647
+		const d = 1e2147483646
+		x := n / d
+		if x != 10.0 {
+			println("incorrect value:", x)
+		}
+	}
+	{
+		const n = 1e214748364
+		const d = 1e214748363
+		x := n / d
+		if x != 10.0 {
+			println("incorrect value:", x)
+		}
+	}
+	*/
+	{
+		const n = 1e21474836
+		const d = 1e21474835
+		x := n / d
+		if x != 10.0 {
+			println("incorrect value:", x)
+		}
+	}
+	{
+		const n = 1e2147483
+		const d = 1e2147482
+		x := n / d
+		if x != 10.0 {
+			println("incorrect value:", x)
+		}
+	}
+}
diff --git a/test/fixedbugs/issue11369.go b/test/fixedbugs/issue11369.go
new file mode 100644
index 0000000..9df37c3
--- /dev/null
+++ b/test/fixedbugs/issue11369.go
@@ -0,0 +1,27 @@
+// 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 the half multiply resulting from a division
+// by a constant generates correct code.
+
+package main
+
+func main() {
+	var _ = 7 / "0"[0] // test case from #11369
+	var _ = 1 / "."[0] // test case from #11358
+	var x = 0 / "0"[0]
+	var y = 48 / "0"[0]
+	var z = 5 * 48 / "0"[0]
+	if x != 0 {
+		panic("expected 0")
+	}
+	if y != 1 {
+		panic("expected 1")
+	}
+	if z != 5 {
+		panic("expected 5")
+	}
+}
diff --git a/test/fixedbugs/issue11656.go b/test/fixedbugs/issue11656.go
new file mode 100644
index 0000000..90385bb
--- /dev/null
+++ b/test/fixedbugs/issue11656.go
@@ -0,0 +1,62 @@
+// 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.
+
+// darwin/386 seems to mangle the PC and SP before
+// it manages to invoke the signal handler, so this test fails there.
+// +build !darwin !386
+//
+// openbsd/386 and netbsd/386 don't work, not sure why.
+// +build !openbsd !386
+// +build !netbsd !386
+//
+// windows doesn't work, because Windows exception handling
+// delivers signals based on the current PC, and that current PC
+// doesn't go into the Go runtime.
+// +build !windows
+//
+// arm64 gets "illegal instruction" (why is the data executable?)
+// and is unable to do the traceback correctly (why?).
+// +build !arm64
+
+package main
+
+import (
+	"runtime"
+	"runtime/debug"
+	"unsafe"
+)
+
+func main() {
+	debug.SetPanicOnFault(true)
+	defer func() {
+		if err := recover(); err == nil {
+			panic("not panicking")
+		}
+		pc, _, _, _ := runtime.Caller(10)
+		f := runtime.FuncForPC(pc)
+		if f == nil || f.Name() != "main.f" {
+			if f == nil {
+				println("no func for ", unsafe.Pointer(pc))
+			} else {
+				println("found func:", f.Name())
+			}
+			panic("cannot find main.f on stack")
+		}
+	}()
+	f(20)
+}
+
+func f(n int) {
+	if n > 0 {
+		f(n - 1)
+	}
+	var f struct {
+		x uintptr
+	}
+	f.x = uintptr(unsafe.Pointer(&f))
+	fn := *(*func())(unsafe.Pointer(&f))
+	fn()
+}
diff --git a/test/fixedbugs/issue11750.go b/test/fixedbugs/issue11750.go
new file mode 100644
index 0000000..5e6fe60
--- /dev/null
+++ b/test/fixedbugs/issue11750.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.
+
+// Issue 11750: mkdotargslice: typecheck failed
+
+package main
+
+func main() {
+	fn := func(names string) {
+
+	}
+	func(names ...string) {
+		for _, name := range names {
+			fn(name)
+		}
+	}("one", "two")
+}
diff --git a/test/fixedbugs/issue11771.go b/test/fixedbugs/issue11771.go
new file mode 100644
index 0000000..7691ca6
--- /dev/null
+++ b/test/fixedbugs/issue11771.go
@@ -0,0 +1,64 @@
+// +build !nacl
+// 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 11771: Magic comments should ignore carriage returns.
+
+package main
+
+import (
+	"bytes"
+	"fmt"
+	"io/ioutil"
+	"log"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"runtime"
+)
+
+func main() {
+	if runtime.Compiler != "gc" {
+		return
+	}
+
+	dir, err := ioutil.TempDir("", "go-issue11771")
+	if err != nil {
+		log.Fatalf("creating temp dir: %v\n", err)
+	}
+	defer os.RemoveAll(dir)
+
+	// The go:nowritebarrier magic comment is only permitted in
+	// the runtime package.  So we confirm that the compilation
+	// fails.
+
+	var buf bytes.Buffer
+	fmt.Fprintln(&buf, `
+package main
+
+func main() {
+}
+`)
+	fmt.Fprintln(&buf, "//go:nowritebarrier\r")
+	fmt.Fprintln(&buf, `
+func x() {
+}
+`)
+
+	if err := ioutil.WriteFile(filepath.Join(dir, "x.go"), buf.Bytes(), 0666); err != nil {
+		log.Fatal(err)
+	}
+
+	cmd := exec.Command("go", "tool", "compile", "x.go")
+	cmd.Dir = dir
+	output, err := cmd.CombinedOutput()
+	if err == nil {
+		log.Fatal("compile succeeded unexpectedly")
+	}
+	if !bytes.Contains(output, []byte("only allowed in runtime")) {
+		log.Fatalf("wrong error message from compiler; got:\n%s\n", output)
+	}
+}
diff --git a/test/fixedbugs/issue11790.go b/test/fixedbugs/issue11790.go
new file mode 100644
index 0000000..d7669f8
--- /dev/null
+++ b/test/fixedbugs/issue11790.go
@@ -0,0 +1,36 @@
+// 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 11790: Incorrect error following named pointer dereference on field
+
+package main
+
+import "fmt"
+
+type T0 struct {
+	x int
+}
+
+func (*T0) M0() {
+	fmt.Println("M0")
+}
+
+type T2 struct {
+	*T0
+}
+
+type Q *T2
+
+func main() {
+	// If run, expected output is
+	// 42
+	// M0
+	t0 := T0{42}
+	t2 := T2{&t0}
+	var q Q = &t2
+	fmt.Println(q.x) // Comment out either this line or the next line and the program works
+	(*q).T0.M0()
+}
diff --git a/test/fixedbugs/issue12133.go b/test/fixedbugs/issue12133.go
new file mode 100644
index 0000000..0b66c56
--- /dev/null
+++ b/test/fixedbugs/issue12133.go
@@ -0,0 +1,26 @@
+// 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 12133.  The CX register was getting clobbered
+// because we did not keep track of its allocation correctly.
+
+package main
+
+import "fmt"
+
+func main() {
+	want := uint(48)
+	got := f1(48)
+	if got != want {
+		fmt.Println("got", got, ", wanted", want)
+		panic("bad")
+	}
+}
+func f1(v1 uint) uint {
+	switch {
+	} // prevent inlining
+	return v1 >> ((1 >> v1) + (1 >> v1))
+}
diff --git a/test/fixedbugs/issue12226.go b/test/fixedbugs/issue12226.go
new file mode 100644
index 0000000..2246711
--- /dev/null
+++ b/test/fixedbugs/issue12226.go
@@ -0,0 +1,15 @@
+// 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.
+
+package main
+
+import "fmt"
+
+func main() {
+	if []byte("foo")[0] == []byte("b")[0] {
+		fmt.Println("BUG: \"foo\" and \"b\" appear to have the same first byte")
+	}
+}
diff --git a/test/fixedbugs/issue3924.go b/test/fixedbugs/issue3924.go
deleted file mode 100644
index d4739b2..0000000
--- a/test/fixedbugs/issue3924.go
+++ /dev/null
@@ -1,13 +0,0 @@
-// errorcheck
-
-// 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.
-
-package foo
-
-type mybool bool
-
-var x, y = 1, 2
-var _ mybool = x < y && x < y // ERROR "cannot use"
-var _ mybool = x < y || x < y // ERROR "cannot use"
diff --git a/test/fixedbugs/issue4365.go b/test/fixedbugs/issue4365.go
new file mode 100644
index 0000000..04d31f7
--- /dev/null
+++ b/test/fixedbugs/issue4365.go
@@ -0,0 +1,27 @@
+// errorcheck
+
+// 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 fields hide promoted methods.
+// https://golang.org/issue/4365
+
+package main
+
+type T interface {
+        M()
+}
+
+type M struct{}
+
+func (M) M() {}
+
+type Foo struct {
+        M
+}
+
+func main() {
+        var v T = Foo{} // ERROR "has no methods|not a method|cannot use"
+        _ = v
+}
diff --git a/test/fixedbugs/issue5373.go b/test/fixedbugs/issue5373.go
new file mode 100644
index 0000000..17ce189
--- /dev/null
+++ b/test/fixedbugs/issue5373.go
@@ -0,0 +1,71 @@
+// 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.
+
+// Ensure that zeroing range loops have the requisite side-effects.
+
+package main
+
+import (
+	"fmt"
+	"os"
+)
+
+func check(n int) {
+	// When n == 0, i is untouched by the range loop.
+	// Picking an initial value of -1 for i makes the
+	// "want" calculation below correct in all cases.
+	i := -1
+	s := make([]byte, n)
+	for i = range s {
+		s[i] = 0
+	}
+	if want := n - 1; i != want {
+		fmt.Printf("index after range with side-effect = %d want %d\n", i, want)
+		os.Exit(1)
+	}
+
+	i = n + 1
+	// i is shadowed here, so its value should be unchanged.
+	for i := range s {
+		s[i] = 0
+	}
+	if want := n + 1; i != want {
+		fmt.Printf("index after range without side-effect = %d want %d\n", i, want)
+		os.Exit(1)
+	}
+
+	// Index variable whose evaluation has side-effects
+	var x int
+	f := func() int {
+		x++
+		return 0
+	}
+	var a [1]int
+	for a[f()] = range s {
+		s[a[f()]] = 0
+	}
+	if want := n * 2; x != want {
+		fmt.Printf("index function calls = %d want %d\n", x, want)
+		os.Exit(1)
+	}
+
+	// Range expression whose evaluation has side-effects
+	x = 0
+	b := [1][]byte{s}
+	for i := range b[f()] {
+		b[f()][i] = 0
+	}
+	if want := n + 1; x != n+1 {
+		fmt.Printf("range expr function calls = %d want %d\n", x, want)
+		os.Exit(1)
+	}
+}
+
+func main() {
+	check(0)
+	check(1)
+	check(15)
+}
diff --git a/test/fixedbugs/issue6671.go b/test/fixedbugs/issue6671.go
new file mode 100644
index 0000000..b88faa4
--- /dev/null
+++ b/test/fixedbugs/issue6671.go
@@ -0,0 +1,28 @@
+// errorcheck
+
+// 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.
+
+// Issue 6671: Logical operators should produce untyped bool for untyped operands.
+
+package p
+
+type mybool bool
+
+func _(x, y int) {
+	type mybool bool
+	var b mybool
+	_ = b
+	b = bool(true)             // ERROR "cannot use"
+	b = true                   // permitted as expected
+	b = bool(true) && true     // ERROR "cannot use"
+	b = true && true           // permitted => && returns an untyped bool
+	b = x < y                  // permitted => x < y returns an untyped bool
+	b = true && x < y          // permitted => result of && returns untyped bool
+	b = x < y && x < y         // permitted => result of && returns untyped bool
+	b = x < y || x < y         // permitted => result of || returns untyped bool
+	var c bool = true && x < y // permitted => result of && is bool
+	c = false || x < y         // permitted => result of || returns untyped bool
+	_ = c
+}
diff --git a/test/fixedbugs/issue6866.go b/test/fixedbugs/issue6866.go
new file mode 100644
index 0000000..1080b27
--- /dev/null
+++ b/test/fixedbugs/issue6866.go
@@ -0,0 +1,80 @@
+// 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.
+
+// WARNING: GENERATED FILE - DO NOT MODIFY MANUALLY!
+// (To generate, in go/types directory: go test -run=Hilbert -H=2 -out="h2.src")
+
+// This program tests arbitrary precision constant arithmetic
+// by generating the constant elements of a Hilbert matrix H,
+// its inverse I, and the product P = H*I. The product should
+// be the identity matrix.
+package main
+
+func main() {
+	if !ok {
+		print()
+		return
+	}
+}
+
+// Hilbert matrix, n = 2
+const (
+	h0_0, h0_1 = 1.0 / (iota + 1), 1.0 / (iota + 2)
+	h1_0, h1_1
+)
+
+// Inverse Hilbert matrix
+const (
+	i0_0 = +1 * b2_1 * b2_1 * b0_0 * b0_0
+	i0_1 = -2 * b2_0 * b3_1 * b1_0 * b1_0
+
+	i1_0 = -2 * b3_1 * b2_0 * b1_1 * b1_1
+	i1_1 = +3 * b3_0 * b3_0 * b2_1 * b2_1
+)
+
+// Product matrix
+const (
+	p0_0 = h0_0*i0_0 + h0_1*i1_0
+	p0_1 = h0_0*i0_1 + h0_1*i1_1
+
+	p1_0 = h1_0*i0_0 + h1_1*i1_0
+	p1_1 = h1_0*i0_1 + h1_1*i1_1
+)
+
+// Verify that product is identity matrix
+const ok = p0_0 == 1 && p0_1 == 0 &&
+	p1_0 == 0 && p1_1 == 1 &&
+	true
+
+func print() {
+	println(p0_0, p0_1)
+	println(p1_0, p1_1)
+}
+
+// Binomials
+const (
+	b0_0 = f0 / (f0 * f0)
+
+	b1_0 = f1 / (f0 * f1)
+	b1_1 = f1 / (f1 * f0)
+
+	b2_0 = f2 / (f0 * f2)
+	b2_1 = f2 / (f1 * f1)
+	b2_2 = f2 / (f2 * f0)
+
+	b3_0 = f3 / (f0 * f3)
+	b3_1 = f3 / (f1 * f2)
+	b3_2 = f3 / (f2 * f1)
+	b3_3 = f3 / (f3 * f0)
+)
+
+// Factorials
+const (
+	f0 = 1
+	f1 = 1
+	f2 = f1 * 2
+	f3 = f2 * 3
+)
diff --git a/test/fixedbugs/issue6889.go b/test/fixedbugs/issue6889.go
index 46bb5da..805a877 100644
--- a/test/fixedbugs/issue6889.go
+++ b/test/fixedbugs/issue6889.go
@@ -99,5 +99,13 @@ const (
 	f88 = f87 * 88
 	f89 = f88 * 89
 	f90 = f89 * 90
-	f91 = f90 * 91 // ERROR "overflow"
+	f91 = f90 * 91
+	f92 = f91 * 92
+	f93 = f92 * 93
+	f94 = f93 * 94
+	f95 = f94 * 95
+	f96 = f95 * 96
+	f97 = f96 * 97
+	f98 = f97 * 98
+	f99 = f98 * 99 // ERROR "overflow"
 )
diff --git a/test/fixedbugs/issue6964.go b/test/fixedbugs/issue6964.go
index 821735c..8f4b60d 100644
--- a/test/fixedbugs/issue6964.go
+++ b/test/fixedbugs/issue6964.go
@@ -7,5 +7,5 @@
 package main
 
 func main() {
-	_ = string(-4 + 2i + 2) // ERROR "-4\+2i"
+	_ = string(-4 + 2i + 2) // ERROR "-4 \+ 2i"
 }
diff --git a/test/fixedbugs/issue7740.go b/test/fixedbugs/issue7740.go
new file mode 100644
index 0000000..8f1afe8
--- /dev/null
+++ b/test/fixedbugs/issue7740.go
@@ -0,0 +1,35 @@
+// 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.
+
+// This test computes the precision of the compiler's internal multiprecision floats.
+
+package main
+
+import (
+	"fmt"
+	"math"
+	"runtime"
+)
+
+const ulp = (1.0 + (2.0 / 3.0)) - (5.0 / 3.0)
+
+func main() {
+	// adjust precision depending on compiler
+	var prec float64
+	switch runtime.Compiler {
+	case "gc":
+		prec = 512
+	case "gccgo":
+		prec = 256
+	default:
+		// unknown compiler
+		return
+	}
+	p := 1 - math.Log(math.Abs(ulp))/math.Log(2)
+	if math.Abs(p-prec) > 1e-10 {
+		fmt.Printf("BUG: got %g; want %g\n", p, prec)
+	}
+}
diff --git a/test/fixedbugs/issue7746.go b/test/fixedbugs/issue7746.go
new file mode 100644
index 0000000..0dc119d
--- /dev/null
+++ b/test/fixedbugs/issue7746.go
@@ -0,0 +1,133 @@
+// errorcheck
+
+// 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
+
+const (
+	c0   = 1 << 100
+	c1   = c0 * c0
+	c2   = c1 * c1
+	c3   = c2 * c2 // ERROR "overflow"
+	c4   = c3 * c3
+	c5   = c4 * c4
+	c6   = c5 * c5
+	c7   = c6 * c6
+	c8   = c7 * c7
+	c9   = c8 * c8
+	c10  = c9 * c9
+	c11  = c10 * c10
+	c12  = c11 * c11
+	c13  = c12 * c12
+	c14  = c13 * c13
+	c15  = c14 * c14
+	c16  = c15 * c15
+	c17  = c16 * c16
+	c18  = c17 * c17
+	c19  = c18 * c18
+	c20  = c19 * c19
+	c21  = c20 * c20
+	c22  = c21 * c21
+	c23  = c22 * c22
+	c24  = c23 * c23
+	c25  = c24 * c24
+	c26  = c25 * c25
+	c27  = c26 * c26
+	c28  = c27 * c27
+	c29  = c28 * c28
+	c30  = c29 * c29
+	c31  = c30 * c30
+	c32  = c31 * c31
+	c33  = c32 * c32
+	c34  = c33 * c33
+	c35  = c34 * c34
+	c36  = c35 * c35
+	c37  = c36 * c36
+	c38  = c37 * c37
+	c39  = c38 * c38
+	c40  = c39 * c39
+	c41  = c40 * c40
+	c42  = c41 * c41
+	c43  = c42 * c42
+	c44  = c43 * c43
+	c45  = c44 * c44
+	c46  = c45 * c45
+	c47  = c46 * c46
+	c48  = c47 * c47
+	c49  = c48 * c48
+	c50  = c49 * c49
+	c51  = c50 * c50
+	c52  = c51 * c51
+	c53  = c52 * c52
+	c54  = c53 * c53
+	c55  = c54 * c54
+	c56  = c55 * c55
+	c57  = c56 * c56
+	c58  = c57 * c57
+	c59  = c58 * c58
+	c60  = c59 * c59
+	c61  = c60 * c60
+	c62  = c61 * c61
+	c63  = c62 * c62
+	c64  = c63 * c63
+	c65  = c64 * c64
+	c66  = c65 * c65
+	c67  = c66 * c66
+	c68  = c67 * c67
+	c69  = c68 * c68
+	c70  = c69 * c69
+	c71  = c70 * c70
+	c72  = c71 * c71
+	c73  = c72 * c72
+	c74  = c73 * c73
+	c75  = c74 * c74
+	c76  = c75 * c75
+	c77  = c76 * c76
+	c78  = c77 * c77
+	c79  = c78 * c78
+	c80  = c79 * c79
+	c81  = c80 * c80
+	c82  = c81 * c81
+	c83  = c82 * c82
+	c84  = c83 * c83
+	c85  = c84 * c84
+	c86  = c85 * c85
+	c87  = c86 * c86
+	c88  = c87 * c87
+	c89  = c88 * c88
+	c90  = c89 * c89
+	c91  = c90 * c90
+	c92  = c91 * c91
+	c93  = c92 * c92
+	c94  = c93 * c93
+	c95  = c94 * c94
+	c96  = c95 * c95
+	c97  = c96 * c96
+	c98  = c97 * c97
+	c99  = c98 * c98
+	c100 = c99 * c99
+)
+
+func main() {
+	println(c1 / c1)
+	println(c2 / c2)
+	println(c3 / c3)
+	println(c4 / c4)
+	println(c5 / c5)
+	println(c6 / c6)
+	println(c7 / c7)
+	println(c8 / c8)
+	println(c9 / c9)
+	println(c10 / c10)
+	println(c20 / c20)
+	println(c30 / c30)
+	println(c40 / c40)
+	println(c50 / c50)
+	println(c60 / c60)
+	println(c70 / c70)
+	println(c80 / c80)
+	println(c90 / c90)
+	println(c100 / c100)
+}
diff --git a/test/fixedbugs/issue8154.go b/test/fixedbugs/issue8154.go
new file mode 100644
index 0000000..92c3cac
--- /dev/null
+++ b/test/fixedbugs/issue8154.go
@@ -0,0 +1,14 @@
+// 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 8154: cmd/5g: ICE in walkexpr walk.c
+
+package main
+
+func main() {
+	c := make(chan int)
+	_ = [1][]func(){[]func(){func() { <-c }}}
+}
diff --git a/test/fixedbugs/issue8183.go b/test/fixedbugs/issue8183.go
new file mode 100644
index 0000000..7104f1e
--- /dev/null
+++ b/test/fixedbugs/issue8183.go
@@ -0,0 +1,23 @@
+// errorcheck
+
+// 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.
+
+// Tests correct reporting of line numbers for errors involving iota,
+// Issue #8183.
+package foo
+
+const (
+	ok = byte(iota + 253)
+	bad
+	barn
+	bard // ERROR "constant 256 overflows byte"
+)
+
+const (
+	c = len([1 - iota]int{})
+	d
+	e // ERROR "array bound must be non-negative" "const initializer len\(composite literal\) is not a constant"
+	f // ERROR "array bound must be non-negative" "const initializer len\(composite literal\) is not a constant"
+)
diff --git a/test/fixedbugs/issue8385.go b/test/fixedbugs/issue8385.go
new file mode 100644
index 0000000..6447e9f
--- /dev/null
+++ b/test/fixedbugs/issue8385.go
@@ -0,0 +1,42 @@
+// errorcheck
+
+// 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.
+
+// Issue 8385: provide a more descriptive error when a method expression
+// is called without a receiver.
+
+package main
+
+type Fooer interface {
+	Foo(i, j int)
+}
+
+func f(x int) {
+}
+
+type I interface {
+	M(int)
+}
+type T struct{}
+
+func (t T) M(x int) {
+}
+
+func g() func(int)
+
+func main() {
+	Fooer.Foo(5, 6) // ERROR "not enough arguments in call to method expression Fooer.Foo"
+
+	var i I
+	var t *T
+
+	g()()    // ERROR "not enough arguments in call to g\(\)"
+	f()      // ERROR "not enough arguments in call to f"
+	i.M()    // ERROR "not enough arguments in call to i\.M"
+	I.M()    // ERROR "not enough arguments in call to method expression I\.M"
+	t.M()    // ERROR "not enough arguments in call to t\.M"
+	T.M()    // ERROR "not enough arguments in call to method expression T\.M"
+	(*T).M() // ERROR "not enough arguments in call to method expression \(\*T\)\.M"
+}
diff --git a/test/fixedbugs/issue8501.go b/test/fixedbugs/issue8501.go
new file mode 100644
index 0000000..90ba096
--- /dev/null
+++ b/test/fixedbugs/issue8501.go
@@ -0,0 +1,18 @@
+// errorcheck
+
+// 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 p
+
+type T struct {
+	f float64
+}
+
+var t T
+
+func F() {
+	_ = complex(1.0) // ERROR "invalid operation|not enough arguments"
+	_ = complex(t.f) // ERROR "invalid operation|not enough arguments"
+}
diff --git a/test/fixedbugs/issue8620.go b/test/fixedbugs/issue8620.go
new file mode 100644
index 0000000..30d7a82
--- /dev/null
+++ b/test/fixedbugs/issue8620.go
@@ -0,0 +1,30 @@
+// run
+
+// 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.
+
+// Issue 8620. Used to fail with -race.
+
+package main
+
+func min(a, b int) int {
+	if a < b {
+		return a
+	}
+	return b
+}
+
+func test(s1, s2 []struct{}) {
+	n := min(len(s1), len(s2))
+	if copy(s1, s2) != n {
+		panic("bad copy result")
+	}
+}
+
+func main() {
+	var b [100]struct{}
+	test(b[:], b[:])
+	test(b[1:], b[:])
+	test(b[:], b[2:])
+}
diff --git a/test/fixedbugs/issue8745.go b/test/fixedbugs/issue8745.go
new file mode 100644
index 0000000..f3a70af
--- /dev/null
+++ b/test/fixedbugs/issue8745.go
@@ -0,0 +1,13 @@
+// errorcheck
+
+// 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.
+
+// Check that the error says s[2] is a byte, not a uint8.
+
+package p
+
+func f(s string) {
+	var _ float64 = s[2] // ERROR "cannot use.*type byte.*as type float64"
+}
diff --git a/test/fixedbugs/issue8836.go b/test/fixedbugs/issue8836.go
new file mode 100644
index 0000000..92c18f6
--- /dev/null
+++ b/test/fixedbugs/issue8836.go
@@ -0,0 +1,24 @@
+// errorcheck
+
+// 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.
+
+// Checking that line number is correct in error message.
+
+package main
+
+type Cint int
+
+func foobar(*Cint, Cint, Cint, *Cint)
+
+func main() {
+	a := Cint(1)
+
+	foobar(
+		&a,
+		0,
+		0,
+		42, // ERROR ".*"
+	)
+}
diff --git a/test/fixedbugs/issue9017.go b/test/fixedbugs/issue9017.go
new file mode 100644
index 0000000..e19bac2
--- /dev/null
+++ b/test/fixedbugs/issue9017.go
@@ -0,0 +1,57 @@
+// errorcheck
+
+// 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.
+
+// Issue 9017: Method selector shouldn't automatically dereference a named pointer type.
+
+package main
+
+type T struct{ x int }
+
+func (T) mT() {}
+
+type S struct {
+	T
+}
+
+func (S) mS() {}
+
+type P *S
+
+type I interface {
+	mT()
+}
+
+func main() {
+	var s S
+	s.T.mT()
+	s.mT() // == s.T.mT()
+
+	var i I
+	_ = i
+	i = s.T
+	i = s
+
+	var ps = &s
+	ps.mS()
+	ps.T.mT()
+	ps.mT() // == ps.T.mT()
+
+	i = ps.T
+	i = ps
+
+	var p P = ps
+	(*p).mS()
+	p.mS() // ERROR "undefined"
+
+	i = *p
+	i = p // ERROR "cannot use|incompatible types"
+
+	p.T.mT()
+	p.mT() // ERROR "undefined"
+
+	i = p.T
+	i = p // ERROR "cannot use|incompatible types"
+}
diff --git a/test/fixedbugs/issue9036.go b/test/fixedbugs/issue9036.go
new file mode 100644
index 0000000..283159e
--- /dev/null
+++ b/test/fixedbugs/issue9036.go
@@ -0,0 +1,29 @@
+// errorcheck
+
+// 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.
+
+// Expects to see error messages on "p" exponents.
+
+package main
+
+import "fmt"
+
+const (
+	x1 = 1.1    // float
+	x2 = 1e10   // float
+	x3 = 0x1e10 // integer (e is a hex digit)
+	x4 = 0x1p10 // ERROR "malformed floating point constant"
+	x5 = 1p10   // ERROR "malformed floating point constant"
+	x6 = 0p0    // ERROR "malformed floating point constant"
+)
+
+func main() {
+	fmt.Printf("%g %T\n", x1, x1)
+	fmt.Printf("%g %T\n", x2, x2)
+	fmt.Printf("%g %T\n", x3, x3)
+	fmt.Printf("%g %T\n", x4, x4)
+	fmt.Printf("%g %T\n", x5, x5)
+	fmt.Printf("%g %T\n", x6, x6)
+}
diff --git a/test/fixedbugs/issue9076.go b/test/fixedbugs/issue9076.go
new file mode 100644
index 0000000..ad1cd5d
--- /dev/null
+++ b/test/fixedbugs/issue9076.go
@@ -0,0 +1,15 @@
+// errorcheck
+
+// 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.
+
+// Issue 9076: cmd/gc shows computed values in error messages instead of original expression.
+
+package main
+
+import "unsafe"
+
+const Hundred = 100
+var _ int32 = 100/unsafe.Sizeof(int(0)) + 1 // GC_ERROR "100 \/ unsafe.Sizeof\(int\(0\)\) \+ 1"
+var _ int32 = Hundred/unsafe.Sizeof(int(0)) + 1 // GC_ERROR "Hundred \/ unsafe.Sizeof\(int\(0\)\) \+ 1"
diff --git a/test/fixedbugs/issue9083.go b/test/fixedbugs/issue9083.go
new file mode 100644
index 0000000..c92c0a6
--- /dev/null
+++ b/test/fixedbugs/issue9083.go
@@ -0,0 +1,22 @@
+// errorcheck
+
+// 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.
+
+// Issue 9083: map/chan error messages show non-explicit capacity.
+
+package main
+
+// untyped constant
+const zero = 0
+
+func main() {
+	var x int
+	x = make(map[int]int) // ERROR "cannot use make\(map\[int\]int\)|incompatible"
+	x = make(map[int]int, 0) // ERROR "cannot use make\(map\[int\]int, 0\)|incompatible"
+	x = make(map[int]int, zero) // ERROR "cannot use make\(map\[int\]int, zero\)|incompatible"
+	x = make(chan int) // ERROR "cannot use make\(chan int\)|incompatible"
+	x = make(chan int, 0) // ERROR "cannot use make\(chan int, 0\)|incompatible"
+	x = make(chan int, zero) // ERROR "cannot use make\(chan int, zero\)|incompatible"
+}
diff --git a/test/fixedbugs/issue9110.go b/test/fixedbugs/issue9110.go
index 7294633..b9e861f 100644
--- a/test/fixedbugs/issue9110.go
+++ b/test/fixedbugs/issue9110.go
@@ -17,6 +17,7 @@ import (
 )
 
 func main() {
+	runtime.GOMAXPROCS(1)
 	debug.SetGCPercent(1000000) // only GC when we ask for GC
 
 	var stats, stats1, stats2 runtime.MemStats
diff --git a/test/fixedbugs/issue9321.go b/test/fixedbugs/issue9321.go
index 06cb5a6..e850d8f 100644
--- a/test/fixedbugs/issue9321.go
+++ b/test/fixedbugs/issue9321.go
@@ -17,7 +17,7 @@ func test() {
 	var wg sync.WaitGroup
 	wg.Add(2)
 	test := func() {
-		for i := 0; i < 100; i++ {
+		for i := 0; i < 10; i++ {
 			buf := &bytes.Buffer{}
 			pprof.Lookup("goroutine").WriteTo(buf, 2)
 		}
@@ -30,8 +30,8 @@ func test() {
 }
 
 func main() {
-	runtime.GOMAXPROCS(2)
-	for i := 0; i < 100; i++ {
+	runtime.GOMAXPROCS(4)
+	for i := 0; i < 10; i++ {
 		test()
 	}
 }
diff --git a/test/fixedbugs/issue9355.dir/a.go b/test/fixedbugs/issue9355.dir/a.go
new file mode 100644
index 0000000..84500c8
--- /dev/null
+++ b/test/fixedbugs/issue9355.dir/a.go
@@ -0,0 +1,16 @@
+package main
+
+var x struct {
+	a, b, c int64
+	d       struct{ p, q, r int32 }
+	e       [8]byte
+	f       [4]struct{ p, q, r int32 }
+}
+
+var y = &x.b
+var z = &x.d.q
+
+var b [10]byte
+var c = &b[5]
+
+var w = &x.f[3].r
diff --git a/test/fixedbugs/issue9355.go b/test/fixedbugs/issue9355.go
new file mode 100644
index 0000000..40c9ba9
--- /dev/null
+++ b/test/fixedbugs/issue9355.go
@@ -0,0 +1,59 @@
+// run
+
+// 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 (
+	"fmt"
+	"os"
+	"os/exec"
+	"path/filepath"
+	"regexp"
+	"runtime"
+)
+
+func main() {
+	if runtime.Compiler != "gc" || runtime.GOOS == "nacl" {
+		return
+	}
+
+	err := os.Chdir(filepath.Join("fixedbugs", "issue9355.dir"))
+	check(err)
+
+	out := run("go", "tool", "compile", "-S", "a.go")
+	os.Remove("a.o")
+
+	// 6g/8g print the offset as dec, but 5g/9g print the offset as hex.
+	patterns := []string{
+		`rel 0\+\d t=1 \"\"\.x\+8\r?\n`,       // y = &x.b
+		`rel 0\+\d t=1 \"\"\.x\+(28|1c)\r?\n`, // z = &x.d.q
+		`rel 0\+\d t=1 \"\"\.b\+5\r?\n`,       // c = &b[5]
+		`rel 0\+\d t=1 \"\"\.x\+(88|58)\r?\n`, // w = &x.f[3].r
+	}
+	for _, p := range patterns {
+		if ok, err := regexp.Match(p, out); !ok || err != nil {
+			println(string(out))
+			panic("can't find pattern " + p)
+		}
+	}
+}
+
+func run(cmd string, args ...string) []byte {
+	out, err := exec.Command(cmd, args...).CombinedOutput()
+	if err != nil {
+		fmt.Println(string(out))
+		fmt.Println(err)
+		os.Exit(1)
+	}
+	return out
+}
+
+func check(err error) {
+	if err != nil {
+		fmt.Println("BUG:", err)
+		os.Exit(1)
+	}
+}
diff --git a/test/fixedbugs/issue9370.go b/test/fixedbugs/issue9370.go
new file mode 100644
index 0000000..120af35
--- /dev/null
+++ b/test/fixedbugs/issue9370.go
@@ -0,0 +1,127 @@
+// errorcheck
+
+// 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.
+
+// Verify that concrete/interface comparisons are
+// typechecked correctly by the compiler.
+
+package main
+
+type I interface {
+	Method()
+}
+
+type C int
+
+func (C) Method() {}
+
+type G func()
+
+func (G) Method() {}
+
+var (
+	e interface{}
+	i I
+	c C
+	n int
+	f func()
+	g G
+)
+
+var (
+	_ = e == c
+	_ = e != c
+	_ = e >= c // ERROR "invalid operation.*not defined"
+	_ = c == e
+	_ = c != e
+	_ = c >= e // ERROR "invalid operation.*not defined"
+
+	_ = i == c
+	_ = i != c
+	_ = i >= c // ERROR "invalid operation.*not defined"
+	_ = c == i
+	_ = c != i
+	_ = c >= i // ERROR "invalid operation.*not defined"
+
+	_ = e == n
+	_ = e != n
+	_ = e >= n // ERROR "invalid operation.*not defined"
+	_ = n == e
+	_ = n != e
+	_ = n >= e // ERROR "invalid operation.*not defined"
+
+	// i and n are not assignable to each other
+	_ = i == n // ERROR "invalid operation.*mismatched types"
+	_ = i != n // ERROR "invalid operation.*mismatched types"
+	_ = i >= n // ERROR "invalid operation.*mismatched types"
+	_ = n == i // ERROR "invalid operation.*mismatched types"
+	_ = n != i // ERROR "invalid operation.*mismatched types"
+	_ = n >= i // ERROR "invalid operation.*mismatched types"
+
+	_ = e == 1
+	_ = e != 1
+	_ = e >= 1 // ERROR "invalid operation.*not defined"
+	_ = 1 == e
+	_ = 1 != e
+	_ = 1 >= e // ERROR "invalid operation.*not defined"
+
+	_ = i == 1 // ERROR "invalid operation.*mismatched types"
+	_ = i != 1 // ERROR "invalid operation.*mismatched types"
+	_ = i >= 1 // ERROR "invalid operation.*mismatched types"
+	_ = 1 == i // ERROR "invalid operation.*mismatched types"
+	_ = 1 != i // ERROR "invalid operation.*mismatched types"
+	_ = 1 >= i // ERROR "invalid operation.*mismatched types"
+
+	_ = e == f // ERROR "invalid operation.*not defined"
+	_ = e != f // ERROR "invalid operation.*not defined"
+	_ = e >= f // ERROR "invalid operation.*not defined"
+	_ = f == e // ERROR "invalid operation.*not defined"
+	_ = f != e // ERROR "invalid operation.*not defined"
+	_ = f >= e // ERROR "invalid operation.*not defined"
+
+	_ = i == f // ERROR "invalid operation.*mismatched types"
+	_ = i != f // ERROR "invalid operation.*mismatched types"
+	_ = i >= f // ERROR "invalid operation.*mismatched types"
+	_ = f == i // ERROR "invalid operation.*mismatched types"
+	_ = f != i // ERROR "invalid operation.*mismatched types"
+	_ = f >= i // ERROR "invalid operation.*mismatched types"
+
+	_ = e == g // ERROR "invalid operation.*not defined"
+	_ = e != g // ERROR "invalid operation.*not defined"
+	_ = e >= g // ERROR "invalid operation.*not defined"
+	_ = g == e // ERROR "invalid operation.*not defined"
+	_ = g != e // ERROR "invalid operation.*not defined"
+	_ = g >= e // ERROR "invalid operation.*not defined"
+
+	_ = i == g // ERROR "invalid operation.*not defined"
+	_ = i != g // ERROR "invalid operation.*not defined"
+	_ = i >= g // ERROR "invalid operation.*not defined"
+	_ = g == i // ERROR "invalid operation.*not defined"
+	_ = g != i // ERROR "invalid operation.*not defined"
+	_ = g >= i // ERROR "invalid operation.*not defined"
+
+	_ = _ == e // ERROR "cannot use _ as value"
+	_ = _ == i // ERROR "cannot use _ as value"
+	_ = _ == c // ERROR "cannot use _ as value"
+	_ = _ == n // ERROR "cannot use _ as value"
+	_ = _ == f // ERROR "cannot use _ as value"
+	_ = _ == g // ERROR "cannot use _ as value"
+
+	_ = e == _ // ERROR "cannot use _ as value"
+	_ = i == _ // ERROR "cannot use _ as value"
+	_ = c == _ // ERROR "cannot use _ as value"
+	_ = n == _ // ERROR "cannot use _ as value"
+	_ = f == _ // ERROR "cannot use _ as value"
+	_ = g == _ // ERROR "cannot use _ as value"
+
+	_ = _ == _ // ERROR "cannot use _ as value"
+
+	_ = e ^ c // ERROR "invalid operation.*mismatched types"
+	_ = c ^ e // ERROR "invalid operation.*mismatched types"
+	_ = 1 ^ e // ERROR "invalid operation.*mismatched types"
+	_ = e ^ 1 // ERROR "invalid operation.*mismatched types"
+	_ = 1 ^ c
+	_ = c ^ 1
+)
diff --git a/test/fixedbugs/issue9521.go b/test/fixedbugs/issue9521.go
new file mode 100644
index 0000000..ef0a5a6
--- /dev/null
+++ b/test/fixedbugs/issue9521.go
@@ -0,0 +1,18 @@
+// errorcheck
+
+// 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 an incorrect use of the blank identifer is caught.
+// Does not compile.
+
+package main
+
+func f() (_, _ []int)         { return }
+func g() (x []int, y float64) { return }
+
+func main() {
+	_ = append(f()) // ERROR "cannot append \[\]int value to \[\]int"
+	_ = append(g()) // ERROR "cannot append float64 value to \[\]int"
+}
diff --git a/test/fixedbugs/issue9604b.go b/test/fixedbugs/issue9604b.go
new file mode 100644
index 0000000..ebbd205
--- /dev/null
+++ b/test/fixedbugs/issue9604b.go
@@ -0,0 +1,177 @@
+// runoutput
+
+// 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 (
+	"fmt"
+	"math/big"
+	"unsafe"
+)
+
+var one = big.NewInt(1)
+
+type _type struct {
+	name   string
+	bits   uint
+	signed bool
+}
+
+// testvalues returns a list of all test values for this type.
+func (t *_type) testvalues() []*big.Int {
+	var a []*big.Int
+
+	a = append(a, big.NewInt(0))
+	a = append(a, big.NewInt(1))
+	a = append(a, big.NewInt(2))
+	if t.signed {
+		a = append(a, big.NewInt(-1))
+		a = append(a, big.NewInt(-2))
+		r := big.NewInt(1)
+		a = append(a, r.Lsh(r, t.bits-1).Sub(r, big.NewInt(1)))
+		r = big.NewInt(1)
+		a = append(a, r.Lsh(r, t.bits-1).Sub(r, big.NewInt(2)))
+		r = big.NewInt(1)
+		a = append(a, r.Lsh(r, t.bits-1).Neg(r))
+		r = big.NewInt(1)
+		a = append(a, r.Lsh(r, t.bits-1).Neg(r).Add(r, big.NewInt(1)))
+	} else {
+		r := big.NewInt(1)
+		a = append(a, r.Lsh(r, t.bits).Sub(r, big.NewInt(1)))
+		r = big.NewInt(1)
+		a = append(a, r.Lsh(r, t.bits).Sub(r, big.NewInt(2)))
+	}
+	return a
+}
+
+// trunc truncates a value to the range of the given type.
+func (t *_type) trunc(x *big.Int) *big.Int {
+	r := new(big.Int)
+	m := new(big.Int)
+	m.Lsh(one, t.bits)
+	m.Sub(m, one)
+	r.And(x, m)
+	if t.signed && r.Bit(int(t.bits)-1) == 1 {
+		m.Neg(one)
+		m.Lsh(m, t.bits)
+		r.Or(r, m)
+	}
+	return r
+}
+
+var types = []_type{
+	_type{"byte", 8, false},
+	_type{"int8", 8, true},
+	_type{"uint8", 8, false},
+	_type{"rune", 32, true},
+	_type{"int16", 16, true},
+	_type{"uint16", 16, false},
+	_type{"int32", 32, true},
+	_type{"uint32", 32, false},
+	_type{"int64", 64, true},
+	_type{"uint64", 64, false},
+	_type{"int", 8 * uint(unsafe.Sizeof(int(0))), true},
+	_type{"uint", 8 * uint(unsafe.Sizeof(uint(0))), false},
+	_type{"uintptr", 8 * uint(unsafe.Sizeof((*byte)(nil))), false},
+}
+
+type binop struct {
+	name string
+	eval func(x, y *big.Int) *big.Int
+}
+
+var binops = []binop{
+	binop{"+", func(x, y *big.Int) *big.Int { return new(big.Int).Add(x, y) }},
+	binop{"-", func(x, y *big.Int) *big.Int { return new(big.Int).Sub(x, y) }},
+	binop{"*", func(x, y *big.Int) *big.Int { return new(big.Int).Mul(x, y) }},
+	binop{"/", func(x, y *big.Int) *big.Int { return new(big.Int).Quo(x, y) }},
+	binop{"%", func(x, y *big.Int) *big.Int { return new(big.Int).Rem(x, y) }},
+	binop{"&", func(x, y *big.Int) *big.Int { return new(big.Int).And(x, y) }},
+	binop{"|", func(x, y *big.Int) *big.Int { return new(big.Int).Or(x, y) }},
+	binop{"^", func(x, y *big.Int) *big.Int { return new(big.Int).Xor(x, y) }},
+	binop{"&^", func(x, y *big.Int) *big.Int { return new(big.Int).AndNot(x, y) }},
+}
+
+type unop struct {
+	name string
+	eval func(x *big.Int) *big.Int
+}
+
+var unops = []unop{
+	unop{"+", func(x *big.Int) *big.Int { return new(big.Int).Set(x) }},
+	unop{"-", func(x *big.Int) *big.Int { return new(big.Int).Neg(x) }},
+	unop{"^", func(x *big.Int) *big.Int { return new(big.Int).Not(x) }},
+}
+
+type shiftop struct {
+	name string
+	eval func(x *big.Int, i uint) *big.Int
+}
+
+var shiftops = []shiftop{
+	shiftop{"<<", func(x *big.Int, i uint) *big.Int { return new(big.Int).Lsh(x, i) }},
+	shiftop{">>", func(x *big.Int, i uint) *big.Int { return new(big.Int).Rsh(x, i) }},
+}
+
+// valname returns the name of n as can be used as part of a variable name.
+func valname(n *big.Int) string {
+	s := fmt.Sprintf("%d", n)
+	if s[0] == '-' {
+		s = "neg" + s[1:]
+	}
+	return s
+}
+
+func main() {
+	fmt.Println("package main")
+
+	// We make variables to hold all the different values we'd like to use.
+	// We use global variables to prevent any constant folding.
+	for _, t := range types {
+		for _, n := range t.testvalues() {
+			fmt.Printf("var %s_%s %s = %d\n", t.name, valname(n), t.name, n)
+		}
+	}
+
+	fmt.Println("func main() {")
+
+	for _, t := range types {
+		// test binary ops
+		for _, op := range binops {
+			for _, x := range t.testvalues() {
+				for _, y := range t.testvalues() {
+					if (op.name == "/" || op.name == "%") && y.Sign() == 0 {
+						continue
+					}
+					r := t.trunc(op.eval(x, y))
+					eqn := fmt.Sprintf("%s_%s %s %s_%s != %d", t.name, valname(x), op.name, t.name, valname(y), r)
+					fmt.Printf("\tif %s { println(\"bad: %s\") }\n", eqn, eqn)
+				}
+			}
+		}
+		// test unary ops
+		for _, op := range unops {
+			for _, x := range t.testvalues() {
+				r := t.trunc(op.eval(x))
+				eqn := fmt.Sprintf("%s %s_%s != %d", op.name, t.name, valname(x), r)
+				fmt.Printf("\tif %s { println(\"bad: %s\") }\n", eqn, eqn)
+			}
+		}
+		// test shifts
+		for _, op := range shiftops {
+			for _, x := range t.testvalues() {
+
+				for _, i := range []uint{0, 1, t.bits - 2, t.bits - 1, t.bits, t.bits + 1} {
+					r := t.trunc(op.eval(x, i))
+					eqn := fmt.Sprintf("%s_%s %s %d != %d", t.name, valname(x), op.name, i, r)
+					fmt.Printf("\tif %s { println(\"bad: %s\") }\n", eqn, eqn)
+				}
+			}
+		}
+	}
+
+	fmt.Println("}")
+}
diff --git a/test/fixedbugs/issue9608.dir/issue9608.go b/test/fixedbugs/issue9608.dir/issue9608.go
new file mode 100644
index 0000000..56b52cc
--- /dev/null
+++ b/test/fixedbugs/issue9608.dir/issue9608.go
@@ -0,0 +1,73 @@
+// 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
+
+func fail() // unimplemented, to test dead code elimination
+
+// Test dead code elimination in if statements
+func init() {
+	if false {
+		fail()
+	}
+	if 0 == 1 {
+		fail()
+	}
+}
+
+// Test dead code elimination in ordinary switch statements
+func init() {
+	const x = 0
+	switch x {
+	case 1:
+		fail()
+	}
+
+	switch 1 {
+	case x:
+		fail()
+	}
+
+	switch {
+	case false:
+		fail()
+	}
+
+	const a = "a"
+	switch a {
+	case "b":
+		fail()
+	}
+
+	const snowman = '☃'
+	switch snowman {
+	case '☀':
+		fail()
+	}
+
+	const zero = float64(0.0)
+	const one = float64(1.0)
+	switch one {
+	case -1.0:
+		fail()
+	case zero:
+		fail()
+	}
+
+	switch 1.0i {
+	case 1:
+		fail()
+	case -1i:
+		fail()
+	}
+
+	const no = false
+	switch no {
+	case true:
+		fail()
+	}
+}
+
+func main() {
+}
diff --git a/test/fixedbugs/issue9608.go b/test/fixedbugs/issue9608.go
new file mode 100644
index 0000000..92592d7
--- /dev/null
+++ b/test/fixedbugs/issue9608.go
@@ -0,0 +1,14 @@
+// rundir
+
+// 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 9608: dead code elimination in switch statements.
+
+// This has to be done as a package rather than as a file,
+// because run.go runs files with 'go run', which passes the
+// -complete flag to compiler, causing it to complain about
+// the intentionally unimplemented function fail.
+
+package ignored
diff --git a/test/fixedbugs/issue9691.go b/test/fixedbugs/issue9691.go
new file mode 100644
index 0000000..39c3dfa
--- /dev/null
+++ b/test/fixedbugs/issue9691.go
@@ -0,0 +1,21 @@
+// 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.
+
+package main
+
+func main() {
+	s := "foo"
+	b := []byte(s)
+	m := make(map[string]int)
+	// Test that map index can be used in range
+	// and that slicebytetostringtmp is not used in this context.
+	for m[string(b)] = range s {
+	}
+	b[0] = 'b'
+	if m["foo"] != 2 {
+		panic("bad")
+	}
+}
diff --git a/test/fixedbugs/issue9731.go b/test/fixedbugs/issue9731.go
new file mode 100644
index 0000000..286cebd
--- /dev/null
+++ b/test/fixedbugs/issue9731.go
@@ -0,0 +1,21 @@
+// compile
+
+// 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 p
+
+func f(x interface{}) {
+	switch x := x.(type) {
+	case int:
+		func() {
+			_ = x
+		}()
+	case map[int]int:
+		func() {
+			for range x {
+			}
+		}()
+	}
+}
diff --git a/test/fixedbugs/issue9738.go b/test/fixedbugs/issue9738.go
new file mode 100644
index 0000000..85319d7
--- /dev/null
+++ b/test/fixedbugs/issue9738.go
@@ -0,0 +1,20 @@
+// 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.
+
+package main
+
+func F() (x int) {
+	defer func() {
+		if x != 42 {
+			println("BUG: x =", x)
+		}
+	}()
+	return 42
+}
+
+func main() {
+	F()
+}
diff --git a/test/fixedbugs/issue9862.go b/test/fixedbugs/issue9862.go
new file mode 100644
index 0000000..692a60d
--- /dev/null
+++ b/test/fixedbugs/issue9862.go
@@ -0,0 +1,15 @@
+// skip
+
+// 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
+
+var a [1<<31 - 1024]byte
+
+func main() {
+	if a[0] != 0 {
+		panic("bad array")
+	}
+}
diff --git a/test/fixedbugs/issue9862_run.go b/test/fixedbugs/issue9862_run.go
new file mode 100644
index 0000000..be22f40
--- /dev/null
+++ b/test/fixedbugs/issue9862_run.go
@@ -0,0 +1,27 @@
+// +build !nacl
+// 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.
+
+// Check for compile or link error.
+
+package main
+
+import (
+	"os/exec"
+	"strings"
+)
+
+func main() {
+	out, err := exec.Command("go", "run", "fixedbugs/issue9862.go").CombinedOutput()
+	outstr := string(out)
+	if err == nil {
+		println("go run issue9862.go succeeded, should have failed\n", outstr)
+		return
+	}
+	if !strings.Contains(outstr, "symbol too large") {
+		println("go run issue9862.go gave unexpected error; want symbol too large:\n", outstr)
+	}
+}
diff --git a/test/func6.go b/test/func6.go
index 456cb49..d1b7f46 100644
--- a/test/func6.go
+++ b/test/func6.go
@@ -9,7 +9,7 @@
 package main
 
 func main() {
-	if func() bool { return true }() {}  // 6g used to say this was a syntax error
+	if func() bool { return true }() {}  // gc used to say this was a syntax error
 	if (func() bool { return true })() {}
 	if (func() bool { return true }()) {}
 }
diff --git a/test/func7.go b/test/func7.go
index 2d646b6..feb7c20 100644
--- a/test/func7.go
+++ b/test/func7.go
@@ -23,7 +23,7 @@ func g() int {
 }
 
 func main() {
-	// 6g, 8g, 5g all used to evaluate g() before f().
+	// gc used to evaluate g() before f().
 	if f() < g() {
 		panic("wrong answer")
 	}
diff --git a/test/gc2.go b/test/gc2.go
index 561516b..b33a027 100644
--- a/test/gc2.go
+++ b/test/gc2.go
@@ -1,6 +1,5 @@
-// run
-
 // +build !nacl
+// run
 
 // Copyright 2011 The Go Authors.  All rights reserved.
 // Use of this source code is governed by a BSD-style
diff --git a/test/golden.out b/test/golden.out
deleted file mode 100644
index 742a5d3..0000000
--- a/test/golden.out
+++ /dev/null
@@ -1,24 +0,0 @@
-
-== ./
-
-== ken/
-
-== chan/
-
-== interface/
-
-== syntax/
-
-== dwarf/
-
-== safe/
-
-== fixedbugs/
-
-=========== fixedbugs/bug429.go
-fatal error: all goroutines are asleep - deadlock!
-
-== bugs/
-
-=========== bugs/bug395.go
-bug395 is broken
diff --git a/test/index.go b/test/index.go
index a8c471b..9ff9e9f 100644
--- a/test/index.go
+++ b/test/index.go
@@ -216,7 +216,7 @@ func main() {
 		thisPass := 0
 		if c == "c" && (a == "a" || a == "pa" || n == "n" || i == "i64big" || i == "i64bigger" || i == "huge" || i == "fbad") {
 			if i == "huge" {
-				// Due to a detail of 6g's internals,
+				// Due to a detail of gc's internals,
 				// the huge constant errors happen in an
 				// earlier pass than the others and inhibits
 				// the next pass from running.
diff --git a/test/init1.go b/test/init1.go
index f6eda6e..62dfb72 100644
--- a/test/init1.go
+++ b/test/init1.go
@@ -17,22 +17,30 @@ func init() {
 	go send(c)
 	<-c
 
-	const chunk = 1 << 20
-	memstats := new(runtime.MemStats)
-	runtime.ReadMemStats(memstats)
-	sys := memstats.Sys
-	b := make([]byte, chunk)
+	const N = 1000
+	const MB = 1 << 20
+	b := make([]byte, MB)
 	for i := range b {
 		b[i] = byte(i%10 + '0')
 	}
 	s := string(b)
-	for i := 0; i < 1000; i++ {
+
+	memstats := new(runtime.MemStats)
+	runtime.ReadMemStats(memstats)
+	sys, numGC := memstats.Sys, memstats.NumGC
+
+	// Generate 1,000 MB of garbage, only retaining 1 MB total.
+	for i := 0; i < N; i++ {
 		x = []byte(s)
 	}
+
+	// Verify that the garbage collector ran by seeing if we
+	// allocated fewer than N*MB bytes from the system.
 	runtime.ReadMemStats(memstats)
-	sys1 := memstats.Sys
-	if sys1-sys > chunk*50 {
-		println("allocated 1000 chunks of", chunk, "and used ", sys1-sys, "memory")
+	sys1, numGC1 := memstats.Sys, memstats.NumGC
+	if sys1-sys >= N*MB || numGC1 == numGC {
+		println("allocated 1000 chunks of", MB, "and used ", sys1-sys, "memory")
+		println("numGC went", numGC, "to", numGC)
 		panic("init1")
 	}
 }
diff --git a/test/inline.go b/test/inline.go
new file mode 100644
index 0000000..54f7b3e
--- /dev/null
+++ b/test/inline.go
@@ -0,0 +1,24 @@
+// errorcheck -0 -m
+
+// 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, using compiler diagnostic flags, that inlining is working.
+// Compiles but does not run.
+
+package foo
+
+import "unsafe"
+
+func add2(p *byte, n uintptr) *byte { // ERROR "can inline add2" "leaking param: p to result"
+	return (*byte)(add1(unsafe.Pointer(p), n)) // ERROR "inlining call to add1"
+}
+
+func add1(p unsafe.Pointer, x uintptr) unsafe.Pointer { // ERROR "can inline add1" "leaking param: p to result"
+	return unsafe.Pointer(uintptr(p) + x)
+}
+
+func f(x *byte) *byte { // ERROR "can inline f" "leaking param: x to result"
+	return add2(x, 1) // ERROR "inlining call to add2" "inlining call to add1"
+}
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/interface/embed2.go b/test/interface/embed2.go
index 1636db7..df3e2e4 100644
--- a/test/interface/embed2.go
+++ b/test/interface/embed2.go
@@ -12,20 +12,25 @@ import "os"
 
 const Value = 1e12
 
-type Inter interface { M() int64 }
+type Inter interface {
+	M() int64
+}
 
 type T int64
+
 func (t T) M() int64 { return int64(t) }
+
 var t = T(Value)
 var pt = &t
 var ti Inter = t
 var pti = &ti
 
-type S struct { Inter }
-var s = S{ ti }
+type S struct{ Inter }
+
+var s = S{ti}
 var ps = &s
 
-type SP struct { *Inter }	// ERROR "interface"
+type SP struct{ *Inter } // ERROR "interface"
 
 var i Inter
 var pi = &i
@@ -43,25 +48,25 @@ func main() {
 	check("t.M()", t.M())
 	check("pt.M()", pt.M())
 	check("ti.M()", ti.M())
-	check("pti.M()", pti.M())	// ERROR "method"
+	check("pti.M()", pti.M()) // ERROR "pointer to interface, not interface"
 	check("s.M()", s.M())
 	check("ps.M()", ps.M())
 
 	i = t
 	check("i = t; i.M()", i.M())
-	check("i = t; pi.M()", pi.M())	// ERROR "method"
+	check("i = t; pi.M()", pi.M()) // ERROR "pointer to interface, not interface"
 
 	i = pt
 	check("i = pt; i.M()", i.M())
-	check("i = pt; pi.M()", pi.M())	// ERROR "method"
+	check("i = pt; pi.M()", pi.M()) // ERROR "pointer to interface, not interface"
 
 	i = s
 	check("i = s; i.M()", i.M())
-	check("i = s; pi.M()", pi.M())	// ERROR "method"
+	check("i = s; pi.M()", pi.M()) // ERROR "pointer to interface, not interface"
 
 	i = ps
 	check("i = ps; i.M()", i.M())
-	check("i = ps; pi.M()", pi.M())	// ERROR "method"
+	check("i = ps; pi.M()", pi.M()) // ERROR "pointer to interface, not interface"
 
 	if !ok {
 		println("BUG: interface10")
diff --git a/test/linkx.go b/test/linkx.go
index 151b6db..ac20334 100644
--- a/test/linkx.go
+++ b/test/linkx.go
@@ -9,10 +9,15 @@
 
 package main
 
+import "fmt"
+
 var tbd string
 var overwrite string = "dibs"
 
+var b bool
+var x int
+
 func main() {
-	println(tbd)
-	println(overwrite)
+	fmt.Println(tbd)
+	fmt.Println(overwrite)
 }
diff --git a/test/linkx_run.go b/test/linkx_run.go
index 5b67ce7..a6c7c67 100644
--- a/test/linkx_run.go
+++ b/test/linkx_run.go
@@ -10,24 +10,61 @@
 package main
 
 import (
+	"bytes"
 	"fmt"
 	"os"
 	"os/exec"
+	"strings"
 )
 
 func main() {
-	cmd := exec.Command("go", "run", "-ldflags=-X main.tbd hello -X main.overwrite trumped", "linkx.go")
-	out, err := cmd.CombinedOutput()
+	test(" ") // old deprecated syntax
+	test("=") // new syntax
+}
+
+func test(sep string) {
+	// Successful run
+	cmd := exec.Command("go", "run", "-ldflags=-X main.tbd"+sep+"hello -X main.overwrite"+sep+"trumped -X main.nosuchsymbol"+sep+"neverseen", "linkx.go")
+	var out, errbuf bytes.Buffer
+	cmd.Stdout = &out
+	cmd.Stderr = &errbuf
+	err := cmd.Run()
 	if err != nil {
-		fmt.Println(string(out))
+		fmt.Println(errbuf.String())
+		fmt.Println(out.String())
 		fmt.Println(err)
 		os.Exit(1)
 	}
 
 	want := "hello\ntrumped\n"
-	got := string(out)
+	got := out.String()
 	if got != want {
 		fmt.Printf("got %q want %q\n", got, want)
 		os.Exit(1)
 	}
+
+	// Issue 8810
+	cmd = exec.Command("go", "run", "-ldflags=-X main.tbd", "linkx.go")
+	_, err = cmd.CombinedOutput()
+	if err == nil {
+		fmt.Println("-X linker flag should not accept keys without values")
+		os.Exit(1)
+	}
+
+	// Issue 9621
+	cmd = exec.Command("go", "run", "-ldflags=-X main.b=false -X main.x=42", "linkx.go")
+	outx, err := cmd.CombinedOutput()
+	if err == nil {
+		fmt.Println("-X linker flag should not overwrite non-strings")
+		os.Exit(1)
+	}
+	outstr := string(outx)
+	if !strings.Contains(outstr, "main.b") {
+		fmt.Printf("-X linker flag did not diagnose overwrite of main.b\n")
+		os.Exit(1)
+	}
+	if !strings.Contains(outstr, "main.x") {
+		fmt.Printf("-X linker flag did not diagnose overwrite of main.x\n")
+		os.Exit(1)
+	}
 }
diff --git a/test/live.go b/test/live.go
index f15bb74..ae982f4 100644
--- a/test/live.go
+++ b/test/live.go
@@ -9,20 +9,39 @@
 
 package main
 
+func printnl()
+
+//go:noescape
+func printpointer(**int)
+
+//go:noescape
+func printintpointer(*int)
+
+//go:noescape
+func printstringpointer(*string)
+
+//go:noescape
+func printstring(string)
+
+//go:noescape
+func printbytepointer(*byte)
+
+func printint(int)
+
 func f1() {
 	var x *int
-	print(&x) // ERROR "live at call to printpointer: x$"
-	print(&x) // ERROR "live at call to printpointer: x$"
+	printpointer(&x) // ERROR "live at call to printpointer: x$"
+	printpointer(&x) // ERROR "live at call to printpointer: x$"
 }
 
 func f2(b bool) {
 	if b {
-		print(0) // nothing live here
+		printint(0) // nothing live here
 		return
 	}
 	var x *int
-	print(&x) // ERROR "live at call to printpointer: x$"
-	print(&x) // ERROR "live at call to printpointer: x$"
+	printpointer(&x) // ERROR "live at call to printpointer: x$"
+	printpointer(&x) // ERROR "live at call to printpointer: x$"
 }
 
 func f3(b bool) {
@@ -30,22 +49,22 @@ func f3(b bool) {
 	// live throughout the function, to avoid being poisoned
 	// in GODEBUG=gcdead=1 mode.
 
-	print(0) // ERROR "live at call to printint: x y$"
+	printint(0) // ERROR "live at call to printint: x y$"
 	if b == false {
-		print(0) // ERROR "live at call to printint: x y$"
+		printint(0) // ERROR "live at call to printint: x y$"
 		return
 	}
 
 	if b {
 		var x *int
-		print(&x) // ERROR "live at call to printpointer: x y$"
-		print(&x) // ERROR "live at call to printpointer: x y$"
+		printpointer(&x) // ERROR "live at call to printpointer: x y$"
+		printpointer(&x) // ERROR "live at call to printpointer: x y$"
 	} else {
 		var y *int
-		print(&y) // ERROR "live at call to printpointer: x y$"
-		print(&y) // ERROR "live at call to printpointer: x y$"
+		printpointer(&y) // ERROR "live at call to printpointer: x y$"
+		printpointer(&y) // ERROR "live at call to printpointer: x y$"
 	}
-	print(0) // ERROR "live at call to printint: x y$" "x \(type \*int\) is ambiguously live" "y \(type \*int\) is ambiguously live"
+	printint(0) // ERROR "f3: x \(type \*int\) is ambiguously live$" "f3: y \(type \*int\) is ambiguously live$" "live at call to printint: x y$"
 }
 
 // The old algorithm treated x as live on all code that
@@ -56,20 +75,20 @@ func f3(b bool) {
 
 func f4(b1, b2 bool) { // x not live here
 	if b2 {
-		print(0) // x not live here
+		printint(0) // x not live here
 		return
 	}
 	var z **int
 	x := new(int)
 	*x = 42
 	z = &x
-	print(**z) // ERROR "live at call to printint: x z$"
+	printint(**z) // ERROR "live at call to printint: x z$"
 	if b2 {
-		print(1) // ERROR "live at call to printint: x$"
+		printint(1) // ERROR "live at call to printint: x$"
 		return
 	}
 	for {
-		print(**z) // ERROR "live at call to printint: x z$"
+		printint(**z) // ERROR "live at call to printint: x z$"
 	}
 }
 
@@ -84,7 +103,7 @@ func f5(b1 bool) {
 		*y = 54
 		z = &y
 	}
-	print(**z) // ERROR "live at call to printint: x y$" "x \(type \*int\) is ambiguously live" "y \(type \*int\) is ambiguously live"
+	printint(**z) // ERROR "f5: x \(type \*int\) is ambiguously live$" "f5: y \(type \*int\) is ambiguously live$" "live at call to printint: x y$"
 }
 
 // confusion about the _ result used to cause spurious "live at entry to f6: _".
@@ -118,10 +137,7 @@ var i9 interface{}
 func f9() bool {
 	g8()
 	x := i9
-	// using complex number in comparison so that
-	// there is always a convT2E, no matter what the
-	// interface rules are.
-	return x != 99.0i // ERROR "live at call to convT2E: x"
+	return x != interface{}(99.0i) // ERROR "live at call to convT2E: x$"
 }
 
 // liveness formerly confused by UNDEF followed by RET,
@@ -141,10 +157,10 @@ var b bool
 
 // this used to have a spurious "live at entry to f11a: ~r0"
 func f11a() *int {
-	select { // ERROR "live at call to newselect: autotmp" "live at call to selectgo: autotmp"
-	case <-c: // ERROR "live at call to selectrecv: autotmp"
+	select { // ERROR "live at call to newselect: autotmp_[0-9]+$" "live at call to selectgo: autotmp_[0-9]+$"
+	case <-c: // ERROR "live at call to selectrecv: autotmp_[0-9]+$"
 		return nil
-	case <-c: // ERROR "live at call to selectrecv: autotmp"
+	case <-c: // ERROR "live at call to selectrecv: autotmp_[0-9]+$"
 		return nil
 	}
 }
@@ -155,11 +171,11 @@ func f11b() *int {
 		// At this point p is dead: the code here cannot
 		// get to the bottom of the function.
 		// This used to have a spurious "live at call to printint: p".
-		print(1) // nothing live here!
-		select { // ERROR "live at call to newselect: autotmp" "live at call to selectgo: autotmp"
-		case <-c: // ERROR "live at call to selectrecv: autotmp"
+		printint(1) // nothing live here!
+		select {    // ERROR "live at call to newselect: autotmp_[0-9]+$" "live at call to selectgo: autotmp_[0-9]+$"
+		case <-c: // ERROR "live at call to selectrecv: autotmp_[0-9]+$"
 			return nil
-		case <-c: // ERROR "live at call to selectrecv: autotmp"
+		case <-c: // ERROR "live at call to selectrecv: autotmp_[0-9]+$"
 			return nil
 		}
 	}
@@ -172,10 +188,10 @@ func f11c() *int {
 	if b {
 		// Unlike previous, the cases in this select fall through,
 		// so we can get to the println, so p is not dead.
-		print(1) // ERROR "live at call to printint: p"
-		select { // ERROR "live at call to newselect: autotmp.* p" "live at call to selectgo: autotmp.* p"
-		case <-c: // ERROR "live at call to selectrecv: autotmp.* p"
-		case <-c: // ERROR "live at call to selectrecv: autotmp.* p"
+		printint(1) // ERROR "live at call to printint: p$"
+		select {    // ERROR "live at call to newselect: autotmp_[0-9]+ p$" "live at call to selectgo: autotmp_[0-9]+ p$"
+		case <-c: // ERROR "live at call to selectrecv: autotmp_[0-9]+ p$"
+		case <-c: // ERROR "live at call to selectrecv: autotmp_[0-9]+ p$"
 		}
 	}
 	println(*p)
@@ -199,7 +215,7 @@ func f12() *int {
 
 func f13() {
 	s := "hello"
-	s = h13(s, g13(s)) // ERROR "live at call to g13: s"
+	s = h13(s, g13(s)) // ERROR "live at call to g13: s$"
 }
 
 func g13(string) string
@@ -209,7 +225,7 @@ func h13(string, string) string
 
 func f14() {
 	x := g14()
-	print(&x) // ERROR "live at call to printpointer: x"
+	printstringpointer(&x) // ERROR "live at call to printstringpointer: x$"
 }
 
 func g14() string
@@ -217,8 +233,8 @@ func g14() string
 func f15() {
 	var x string
 	_ = &x
-	x = g15() // ERROR "live at call to g15: x"
-	print(x)  // ERROR "live at call to printstring: x"
+	x = g15()      // ERROR "live at call to g15: x$"
+	printstring(x) // ERROR "live at call to printstring: x$"
 }
 
 func g15() string
@@ -282,7 +298,7 @@ func f18() {
 	}
 	z = m2[g18()] // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
 	z = m2[g18()] // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
-	print(z)
+	printbytepointer(z)
 }
 
 var ch chan *byte
@@ -296,7 +312,7 @@ func f19() {
 	}
 	z = <-ch // ERROR "live at call to chanrecv1: autotmp_[0-9]+$"
 	z = <-ch // ERROR "live at call to chanrecv1: autotmp_[0-9]+$"
-	print(z)
+	printbytepointer(z)
 }
 
 func f20() {
@@ -316,7 +332,7 @@ func f21() {
 	}
 	z = m2[[2]string{"x", "y"}] // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
 	z = m2[[2]string{"x", "y"}] // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
-	print(z)
+	printbytepointer(z)
 }
 
 func f23() {
@@ -328,7 +344,8 @@ func f23() {
 	}
 	z, ok = m2[[2]string{"x", "y"}] // ERROR "live at call to mapaccess2: autotmp_[0-9]+$"
 	z, ok = m2[[2]string{"x", "y"}] // ERROR "live at call to mapaccess2: autotmp_[0-9]+$"
-	print(z, ok)
+	printbytepointer(z)
+	print(ok)
 }
 
 func f24() {
@@ -350,9 +367,9 @@ func f25(b bool) {
 	}
 	var x string
 	_ = &x
-	x = g15() // ERROR "live at call to g15: x"
-	print(x)  // ERROR "live at call to printstring: x"
-} // ERROR "live at call to deferreturn: x"
+	x = g15()      // ERROR "live at call to g15: x$"
+	printstring(x) // ERROR "live at call to printstring: x$"
+} // ERROR "live at call to deferreturn: x$"
 
 func g25()
 
@@ -366,7 +383,7 @@ func f26(b bool) {
 	}
 	print26((*int)(nil), (*int)(nil), (*int)(nil)) // ERROR "live at call to print26: autotmp_[0-9]+$"
 	print26((*int)(nil), (*int)(nil), (*int)(nil)) // ERROR "live at call to print26: autotmp_[0-9]+$"
-	println()
+	printnl()
 }
 
 //go:noescape
@@ -381,7 +398,7 @@ func f27(b bool) {
 	}
 	call27(func() { x++ }) // ERROR "live at call to call27: autotmp_[0-9]+$"
 	call27(func() { x++ }) // ERROR "live at call to call27: autotmp_[0-9]+$"
-	println()
+	printnl()
 }
 
 // but defer does escape to later execution in the function
@@ -391,8 +408,8 @@ func f27defer(b bool) {
 	if b {
 		defer call27(func() { x++ }) // ERROR "live at call to deferproc: autotmp_[0-9]+$" "live at call to deferreturn: autotmp_[0-9]+$"
 	}
-	defer call27(func() { x++ }) // ERROR "live at call to deferproc: autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to deferreturn: autotmp_[0-9]+ autotmp_[0-9]+$" "ambiguously live"
-	println()                    // ERROR "live at call to printnl: autotmp_[0-9]+ autotmp_[0-9]+$"
+	defer call27(func() { x++ }) // ERROR "f27defer: autotmp_[0-9]+ \(type struct { F uintptr; x \*int }\) is ambiguously live$" "live at call to deferproc: autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to deferreturn: autotmp_[0-9]+ autotmp_[0-9]+$"
+	printnl()                    // ERROR "live at call to printnl: autotmp_[0-9]+ autotmp_[0-9]+$"
 } // ERROR "live at call to deferreturn: autotmp_[0-9]+ autotmp_[0-9]+$"
 
 // and newproc (go) escapes to the heap
@@ -400,10 +417,10 @@ func f27defer(b bool) {
 func f27go(b bool) {
 	x := 0
 	if b {
-		go call27(func() { x++ }) // ERROR "live at call to newobject: &x" "live at call to newproc: &x$"
+		go call27(func() { x++ }) // ERROR "live at call to newobject: &x$" "live at call to newproc: &x$"
 	}
-	go call27(func() { x++ }) // ERROR "live at call to newobject: &x"
-	println()
+	go call27(func() { x++ }) // ERROR "live at call to newobject: &x$"
+	printnl()
 }
 
 //go:noescape
@@ -415,10 +432,10 @@ var s1, s2, s3, s4, s5, s6, s7, s8, s9, s10 string
 
 func f28(b bool) {
 	if b {
-		print(s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10) // ERROR "live at call to concatstrings: autotmp_[0-9]+$" "live at call to printstring: autotmp_[0-9]+$"
+		printstring(s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10) // ERROR "live at call to concatstrings: autotmp_[0-9]+$" "live at call to printstring: autotmp_[0-9]+$"
 	}
-	print(s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10) // ERROR "live at call to concatstrings: autotmp_[0-9]+$" "live at call to printstring: autotmp_[0-9]+$"
-	print(s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10) // ERROR "live at call to concatstrings: autotmp_[0-9]+$" "live at call to printstring: autotmp_[0-9]+$"
+	printstring(s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10) // ERROR "live at call to concatstrings: autotmp_[0-9]+$" "live at call to printstring: autotmp_[0-9]+$"
+	printstring(s1 + s2 + s3 + s4 + s5 + s6 + s7 + s8 + s9 + s10) // ERROR "live at call to concatstrings: autotmp_[0-9]+$" "live at call to printstring: autotmp_[0-9]+$"
 }
 
 // map iterator should die on end of range loop
@@ -426,14 +443,14 @@ func f28(b bool) {
 func f29(b bool) {
 	if b {
 		for k := range m { // ERROR "live at call to mapiterinit: autotmp_[0-9]+$" "live at call to mapiternext: autotmp_[0-9]+$"
-			print(k) // ERROR "live at call to printstring: autotmp_[0-9]+$"
+			printstring(k) // ERROR "live at call to printstring: autotmp_[0-9]+$"
 		}
 	}
 	for k := range m { // ERROR "live at call to mapiterinit: autotmp_[0-9]+$" "live at call to mapiternext: autotmp_[0-9]+$"
-		print(k) // ERROR "live at call to printstring: autotmp_[0-9]+$"
+		printstring(k) // ERROR "live at call to printstring: autotmp_[0-9]+$"
 	}
 	for k := range m { // ERROR "live at call to mapiterinit: autotmp_[0-9]+$" "live at call to mapiternext: autotmp_[0-9]+$"
-		print(k) // ERROR "live at call to printstring: autotmp_[0-9]+$"
+		printstring(k) // ERROR "live at call to printstring: autotmp_[0-9]+$"
 	}
 }
 
@@ -446,14 +463,14 @@ func f30(b bool) {
 	// the copy of ptrarr and the internal iterator pointer.
 	if b {
 		for _, p := range ptrarr {
-			print(p) // ERROR "live at call to printpointer: autotmp_[0-9]+ autotmp_[0-9]+$"
+			printintpointer(p) // ERROR "live at call to printintpointer: autotmp_[0-9]+ autotmp_[0-9]+$"
 		}
 	}
 	for _, p := range ptrarr {
-		print(p) // ERROR "live at call to printpointer: autotmp_[0-9]+ autotmp_[0-9]+$"
+		printintpointer(p) // ERROR "live at call to printintpointer: autotmp_[0-9]+ autotmp_[0-9]+$"
 	}
 	for _, p := range ptrarr {
-		print(p) // ERROR "live at call to printpointer: autotmp_[0-9]+ autotmp_[0-9]+$"
+		printintpointer(p) // ERROR "live at call to printintpointer: autotmp_[0-9]+ autotmp_[0-9]+$"
 	}
 }
 
@@ -464,7 +481,7 @@ func f31(b1, b2, b3 bool) {
 		g31("a") // ERROR "live at call to convT2E: autotmp_[0-9]+$" "live at call to g31: autotmp_[0-9]+$"
 	}
 	if b2 {
-		h31("b") // ERROR "live at call to newobject: autotmp_[0-9]+$" "live at call to convT2E: autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to h31: autotmp_[0-9]+$"
+		h31("b") // ERROR "live at call to convT2E: autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to h31: autotmp_[0-9]+$" "live at call to newobject: autotmp_[0-9]+$"
 	}
 	if b3 {
 		panic("asdf") // ERROR "live at call to convT2E: autotmp_[0-9]+$" "live at call to gopanic: autotmp_[0-9]+$"
@@ -479,7 +496,7 @@ func h31(...interface{})
 
 type T32 int
 
-func (t *T32) Inc() { // ERROR "live at entry"
+func (t *T32) Inc() { // ERROR "live at entry to \(\*T32\).Inc: t$"
 	*t++
 }
 
@@ -503,44 +520,44 @@ var m33 map[interface{}]int
 
 func f33() {
 	if m33[nil] == 0 { // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
-		println()
+		printnl()
 		return
 	} else {
-		println()
+		printnl()
 	}
-	println()
+	printnl()
 }
 
 func f34() {
 	if m33[nil] == 0 { // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
-		println()
+		printnl()
 		return
 	}
-	println()
+	printnl()
 }
 
 func f35() {
 	if m33[nil] == 0 && m33[nil] == 0 { // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
-		println()
+		printnl()
 		return
 	}
-	println()
+	printnl()
 }
 
 func f36() {
 	if m33[nil] == 0 || m33[nil] == 0 { // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
-		println()
+		printnl()
 		return
 	}
-	println()
+	printnl()
 }
 
 func f37() {
 	if (m33[nil] == 0 || m33[nil] == 0) && m33[nil] == 0 { // ERROR "live at call to mapaccess1: autotmp_[0-9]+$"
-		println()
+		printnl()
 		return
 	}
-	println()
+	printnl()
 }
 
 // select temps should disappear in the case bodies
@@ -556,46 +573,46 @@ func f38(b bool) {
 	// we care that the println lines have no live variables
 	// and therefore no output.
 	if b {
-		select { // ERROR "live at call"
-		case <-fc38(): // ERROR "live at call"
-			println()
-		case fc38() <- *fi38(1): // ERROR "live at call"
-			println()
-		case *fi38(2) = <-fc38(): // ERROR "live at call"
-			println()
-		case *fi38(3), *fb38() = <-fc38(): // ERROR "live at call"
-			println()
+		select { // ERROR "live at call to newselect: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to selectgo: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$"
+		case <-fc38(): // ERROR "live at call to selectrecv: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$"
+			printnl()
+		case fc38() <- *fi38(1): // ERROR "live at call to fc38: autotmp_[0-9]+$" "live at call to fi38: autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to selectsend: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$"
+			printnl()
+		case *fi38(2) = <-fc38(): // ERROR "live at call to fc38: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to fi38: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to selectrecv: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$"
+			printnl()
+		case *fi38(3), *fb38() = <-fc38(): // ERROR "live at call to fb38: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to fc38: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to fi38: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$" "live at call to selectrecv2: autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+ autotmp_[0-9]+$"
+			printnl()
 		}
-		println()
+		printnl()
 	}
-	println()
+	printnl()
 }
 
 // issue 8097: mishandling of x = x during return.
 
 func f39() (x []int) {
 	x = []int{1}
-	println() // ERROR "live at call to printnl: x"
+	printnl() // ERROR "live at call to printnl: x$"
 	return x
 }
 
 func f39a() (x []int) {
 	x = []int{1}
-	println() // ERROR "live at call to printnl: x"
+	printnl() // ERROR "live at call to printnl: x$"
 	return
 }
 
 func f39b() (x [10]*int) {
 	x = [10]*int{}
-	x[0] = new(int) // ERROR "live at call to newobject: x"
-	println()       // ERROR "live at call to printnl: x"
+	x[0] = new(int) // ERROR "live at call to newobject: x$"
+	printnl()       // ERROR "live at call to printnl: x$"
 	return x
 }
 
 func f39c() (x [10]*int) {
 	x = [10]*int{}
-	x[0] = new(int) // ERROR "live at call to newobject: x"
-	println()       // ERROR "live at call to printnl: x"
+	x[0] = new(int) // ERROR "live at call to newobject: x$"
+	printnl()       // ERROR "live at call to printnl: x$"
 	return
 }
 
@@ -608,20 +625,20 @@ type T40 struct {
 
 func newT40() *T40 {
 	ret := T40{}
-	ret.m = make(map[int]int) // ERROR "live at call to makemap: &ret"
+	ret.m = make(map[int]int) // ERROR "live at call to makemap: &ret$"
 	return &ret
 }
 
 func bad40() {
 	t := newT40()
-	println()
 	_ = t
+	printnl()
 }
 
 func good40() {
 	ret := T40{}
-	ret.m = make(map[int]int) // ERROR "live at call to makemap: ret"
+	ret.m = make(map[int]int) // ERROR "live at call to makemap: autotmp_[0-9]+ ret$"
 	t := &ret
-	println() // ERROR "live at call to printnl: ret"
+	printnl() // ERROR "live at call to printnl: autotmp_[0-9]+ ret$"
 	_ = t
 }
diff --git a/test/live2.go b/test/live2.go
index ef6ad99..7474756 100644
--- a/test/live2.go
+++ b/test/live2.go
@@ -12,6 +12,8 @@ package main
 // issue 8142: lost 'addrtaken' bit on inlined variables.
 // no inlining in this test, so just checking that non-inlined works.
 
+func printnl()
+
 type T40 struct {
 	m map[int]int
 }
@@ -23,15 +25,15 @@ func newT40() *T40 {
 }
 
 func bad40() {
-	t := newT40() // ERROR "live at call to makemap: ret"
-	println()     // ERROR "live at call to printnl: ret"
+	t := newT40() // ERROR "live at call to makemap: autotmp_.* ret"
+	printnl()     // ERROR "live at call to printnl: autotmp_.* ret"
 	_ = t
 }
 
 func good40() {
 	ret := T40{}
-	ret.m = make(map[int]int) // ERROR "live at call to makemap: ret"
+	ret.m = make(map[int]int) // ERROR "live at call to makemap: autotmp_.* ret"
 	t := &ret
-	println() // ERROR "live at call to printnl: ret"
+	printnl() // ERROR "live at call to printnl: autotmp_.* ret"
 	_ = t
 }
diff --git a/test/nilcheck.go b/test/nilcheck.go
index fe05d05..99c3c5f 100644
--- a/test/nilcheck.go
+++ b/test/nilcheck.go
@@ -182,3 +182,8 @@ func f4(x *[10]int) {
 	_ = &x[9] // ERROR "nil check"
 }
 
+func f5(m map[string]struct{}) bool {
+	// Existence-only map lookups should not generate a nil check
+	_, ok := m[""]
+	return ok
+}
diff --git a/test/nilptr3.go b/test/nilptr3.go
index 2757dae..607c6fb 100644
--- a/test/nilptr3.go
+++ b/test/nilptr3.go
@@ -1,4 +1,7 @@
 // errorcheck -0 -d=nil
+// Fails on ppc64x because of incomplete optimization.
+// See issues 9058.
+// +build !ppc64,!ppc64le
 
 // 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 953a5bf..e5c2a9f 100644
--- a/test/nosplit.go
+++ b/test/nosplit.go
@@ -1,6 +1,5 @@
-// run
-
 // +build !nacl
+// run
 
 // Copyright 2014 The Go Authors.  All rights reserved.
 // Use of this source code is governed by a BSD-style
@@ -127,8 +126,9 @@ main 136 nosplit; REJECT
 # Calling a nosplit function from a nosplit function requires
 # having room for the saved caller PC and the called frame.
 # Because ARM doesn't save LR in the leaf, it gets an extra 4 bytes.
+# Because ppc64 doesn't save LR in the leaf, it gets an extra 8 bytes.
 main 112 nosplit call f; f 0 nosplit
-main 116 nosplit call f; f 0 nosplit; REJECT amd64
+main 116 nosplit call f; f 0 nosplit
 main 120 nosplit call f; f 0 nosplit; REJECT amd64
 main 124 nosplit call f; f 0 nosplit; REJECT amd64 386
 main 128 nosplit call f; f 0 nosplit; REJECT
@@ -137,8 +137,8 @@ main 136 nosplit call f; f 0 nosplit; REJECT
 
 # Calling a splitting function from a nosplit function requires
 # having room for the saved caller PC of the call but also the
-# saved caller PC for the call to morestack. Again the ARM works
-# in less space.
+# saved caller PC for the call to morestack.
+# Again the ARM and ppc64 work in less space.
 main 104 nosplit call f; f 0 call f
 main 108 nosplit call f; f 0 call f
 main 112 nosplit call f; f 0 call f; REJECT amd64
@@ -184,6 +184,17 @@ func main() {
 		goarch = runtime.GOARCH
 	}
 
+	version, err := exec.Command("go", "tool", "compile", "-V").Output()
+	if err != nil {
+		bug()
+		fmt.Printf("running go tool compile -V: %v\n", err)
+		return
+	}
+	if strings.Contains(string(version), "framepointer") {
+		// Skip this test if GOEXPERIMENT=framepointer
+		return
+	}
+
 	dir, err := ioutil.TempDir("", "go-test-nosplit")
 	if err != nil {
 		bug()
@@ -234,9 +245,20 @@ TestCases:
 		fmt.Fprintf(&gobuf, "package main\n")
 
 		var buf bytes.Buffer
-		if goarch == "arm" {
+		ptrSize := 4
+		switch goarch {
+		case "ppc64", "ppc64le":
+			ptrSize = 8
+			fmt.Fprintf(&buf, "#define CALL BL\n#define REGISTER (CTR)\n")
+		case "arm":
 			fmt.Fprintf(&buf, "#define CALL BL\n#define REGISTER (R0)\n")
-		} else {
+		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")
+		default:
 			fmt.Fprintf(&buf, "#define REGISTER AX\n")
 		}
 
@@ -259,14 +281,21 @@ TestCases:
 				name := m[1]
 				size, _ := strconv.Atoi(m[2])
 
-				// The limit was originally 128 but is now 384.
+				// The limit was originally 128 but is now 512.
 				// Instead of rewriting the test cases above, adjust
-				// the first stack frame to use up the extra 32 bytes.
+				// the first stack frame to use up the extra bytes.
 				if i == 0 {
-					size += 384 - 128
+					size += 512 - 128
+					// Noopt builds have a larger stackguard.
+					// See ../cmd/dist/buildruntime.go:stackGuardMultiplier
+					for _, s := range strings.Split(os.Getenv("GO_GCFLAGS"), " ") {
+						if s == "-N" {
+							size += 640
+						}
+					}
 				}
 
-				if goarch == "amd64" && size%8 == 4 {
+				if size%ptrSize == 4 || goarch == "arm64" && size != 0 && (size+8)%16 != 0 {
 					continue TestCases
 				}
 				nosplit := m[3]
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)
+	}
+}
diff --git a/test/run b/test/run
deleted file mode 100755
index 729fc1e..0000000
--- a/test/run
+++ /dev/null
@@ -1,138 +0,0 @@
-#!/usr/bin/env bash
-# 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.
-
-eval $(go tool dist env)
-export GOARCH GOOS GOROOT
-export E=
-
-case X"$GOARCH" in
-Xamd64)
-	export A=6
-	;;
-X386)
-	export A=8
-	;;
-Xarm)
-	export A=5
-	export E="$GORUN"
-	;;
-*)
-	echo 1>&2 run: unsupported '$GOARCH'
-	exit 1
-esac
-
-export G="${A}g ${GCFLAGS}"
-export L=${A}l
-export GOTRACEBACK=0
-export LANG=C
-unset GREP_OPTIONS	# in case user has a non-standard set
-
-unset GOROOT_FINAL  # breaks ./ imports
-
-failed=0
-
-PATH=${GOBIN:-$GOROOT/bin}:`pwd`:/bin:/usr/bin:/usr/local/bin:/usr/pkg/bin
-
-# TODO: We add the tool directory to the PATH to avoid thinking about a better way.
-PATH="$GOTOOLDIR:$PATH"
-
-RUNFILE="${TMPDIR:-/tmp}/gorun-$$-$USER"
-TMP1FILE="${TMPDIR:-/tmp}/gotest1-$$-$USER"
-TMP2FILE="${TMPDIR:-/tmp}/gotest2-$$-$USER"
-
-# don't run the machine out of memory: limit individual processes to 4GB.
-# on thresher, 3GB suffices to run the tests; with 2GB, peano fails.
-ulimit -v 4000000
-
-# no core files please
-ulimit -c 0
-
-true >pass.out >times.out
-
-exclude=false	# exclude nothing
-golden=golden.out
-
-rm -f tmp.go  # generated by some tests, left behind if interrupted
-
-filterout() {
-	grep '^'"$2"'$' $1 >/dev/null
-}
-
-for dir in . ken chan interface syntax dwarf safe fixedbugs bugs
-do
-	echo
-	echo '==' $dir'/'
-	for i in $(ls $dir/*.go 2>/dev/null)
-	do (
-		if $exclude $i; then
-			exit 0  # continues for loop
-		fi
-		export F=$(basename $i .go)
-		export D=$dir
-		echo '. ./testlib' >"$RUNFILE"
-		sed '/^\/\//!q' $i | sed 's@//@@; $d' |sed 's|./\$A.out|$E &|g' >>"$RUNFILE"
-		if ! { time -p bash -c "bash '$RUNFILE' >'$TMP1FILE' 2>&1" ; } 2>"$TMP2FILE"
-		then
-			echo
-			echo "===========" $i
-			cat "$TMP1FILE"
-			echo >&2 fail: $i
-			echo "# $i	# fail" >>pass.out
-		elif test -s "$TMP1FILE"
-		then
-			echo
-			echo "===========" $i
-			cat "$TMP1FILE"
-			if grep -q '^BUG' "$TMP1FILE"
-			then
-				if [ $dir != bugs ]
-				then
-					echo >&2 bug: $i
-				fi
-				echo "# $i	# fail, BUG" >>pass.out
-			else
-				echo $i >>pass.out
-			fi
-		elif [ $dir = "bugs" ]
-		then
-			echo $i succeeded with no output.
-		else
-			echo $i >>pass.out
-		fi
-		echo $(awk 'NR==1{print $2}' "$TMP2FILE") $D/$F >>times.out
-		rm -f $F.$A $A.out tmp.go
-	) done
-done | # clean up some stack noise
-	egrep -v '^(r[0-9a-z]+|[cfg]s)  +0x'  |
-	sed '/tmp.*Bus error/s/.*Bus/Bus/; /tmp.*Trace.BPT/s/.*Trace/Trace/
-		s!'"$RUNFILE"'!$RUNFILE!g
-		s/^PC=0x[0-9a-f]*/pc: xxx/
-		s/^pc: 0x[0-9a-f]*/pc: xxx/
-		s/PC=0x[0-9a-f]*/PC=xxx/
-		/^Trace\/breakpoint trap/d
-		/^Trace\/BPT trap/d
-		/RUNFILE/ s/line 1: *[0-9]*/line 1: PID/
-		/^\$RUNFILE: line 1: PID Trace\/breakpoint trap/d
-		/Segmentation fault/d
-		/^qemu: uncaught target signal 11 (Segmentation fault) - exiting/d' > run.out
-
-rm -f "$RUNFILE" "$TMP1FILE" "$TMP2FILE" *.$A *.a $A.out
-diffmsg=""
-if ! diff $golden run.out
-then
-	diffmsg="; test output differs"
-	failed=1
-fi
-
-notinbugs=$(sed '/^== bugs/q' run.out | grep -c '^BUG')
-inbugs=$(sed '1,/^== bugs/d' run.out | grep -c '^BUG')
-
-echo 2>&1 $inbugs known bugs';' $notinbugs unexpected bugs$diffmsg
-
-if [ "$failed" != "0" ]; then
-	echo FAILED
-fi
-
-exit $failed
diff --git a/test/run.go b/test/run.go
index e8ec2df..6e1cde9 100644
--- a/test/run.go
+++ b/test/run.go
@@ -15,7 +15,8 @@ import (
 	"errors"
 	"flag"
 	"fmt"
-	"go/build"
+	"hash/fnv"
+	"io"
 	"io/ioutil"
 	"log"
 	"os"
@@ -36,16 +37,14 @@ var (
 	numParallel    = flag.Int("n", runtime.NumCPU(), "number of parallel tests to run")
 	summary        = flag.Bool("summary", false, "show summary of results")
 	showSkips      = flag.Bool("show_skips", false, "show skipped tests")
+	updateErrors   = flag.Bool("update_errors", false, "update error messages in test file based on compiler output")
 	runoutputLimit = flag.Int("l", defaultRunOutputLimit(), "number of parallel runoutput tests to run")
+
+	shard  = flag.Int("shard", 0, "shard index to run. Only applicable if -shards is non-zero.")
+	shards = flag.Int("shards", 0, "number of shards. If 0, all tests are run. This is used by the continuous build.")
 )
 
 var (
-	// gc and ld are [568][gl].
-	gc, ld string
-
-	// letter is the build.ArchChar
-	letter string
-
 	goos, goarch string
 
 	// dirs are the directories to look for *.go files in.
@@ -83,11 +82,6 @@ func main() {
 
 	ratec = make(chan bool, *numParallel)
 	rungatec = make(chan bool, *runoutputLimit)
-	var err error
-	letter, err = build.ArchChar(build.Default.GOARCH)
-	check(err)
-	gc = letter + "g"
-	ld = letter + "l"
 
 	var tests []*test
 	if flag.NArg() > 0 {
@@ -126,12 +120,9 @@ func main() {
 		status := "ok  "
 		errStr := ""
 		if _, isSkip := test.err.(skipError); isSkip {
-			status = "skip"
 			test.err = nil
-			if !skipOkay[path.Join(test.dir, test.gofile)] {
-				errStr = "unexpected skip for " + path.Join(test.dir, test.gofile) + ": " + errStr
-				status = "FAIL"
-			}
+			errStr = "unexpected skip for " + path.Join(test.dir, test.gofile) + ": " + errStr
+			status = "FAIL"
 		}
 		if test.err != nil {
 			status = "FAIL"
@@ -176,6 +167,15 @@ func toolPath(name string) string {
 	return p
 }
 
+func shardMatch(name string) bool {
+	if *shards == 0 {
+		return true
+	}
+	h := fnv.New32()
+	io.WriteString(h, name)
+	return int(h.Sum32()%uint32(*shards)) == *shard
+}
+
 func goFiles(dir string) []string {
 	f, err := os.Open(dir)
 	check(err)
@@ -183,7 +183,7 @@ func goFiles(dir string) []string {
 	check(err)
 	names := []string{}
 	for _, name := range dirnames {
-		if !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go") {
+		if !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go") && shardMatch(name) {
 			names = append(names, name)
 		}
 	}
@@ -194,11 +194,11 @@ func goFiles(dir string) []string {
 type runCmd func(...string) ([]byte, error)
 
 func compileFile(runcmd runCmd, longname string) (out []byte, err error) {
-	return runcmd("go", "tool", gc, "-e", longname)
+	return runcmd("go", "tool", "compile", "-e", longname)
 }
 
 func compileInDir(runcmd runCmd, dir string, names ...string) (out []byte, err error) {
-	cmd := []string{"go", "tool", gc, "-e", "-D", ".", "-I", "."}
+	cmd := []string{"go", "tool", "compile", "-e", "-D", ".", "-I", "."}
 	for _, name := range names {
 		cmd = append(cmd, filepath.Join(dir, name))
 	}
@@ -206,8 +206,8 @@ func compileInDir(runcmd runCmd, dir string, names ...string) (out []byte, err e
 }
 
 func linkFile(runcmd runCmd, goname string) (err error) {
-	pfile := strings.Replace(goname, ".go", "."+letter, -1)
-	_, err = runcmd("go", "tool", ld, "-w", "-o", "a.exe", "-L", ".", pfile)
+	pfile := strings.Replace(goname, ".go", ".o", -1)
+	_, err = runcmd("go", "tool", "link", "-w", "-o", "a.exe", "-L", ".", pfile)
 	return
 }
 
@@ -328,9 +328,6 @@ type context struct {
 // shouldTest looks for build tags in a source file and returns
 // whether the file should be used according to the tags.
 func shouldTest(src string, goos, goarch string) (ok bool, whyNot string) {
-	if idx := strings.Index(src, "\npackage"); idx >= 0 {
-		src = src[:idx]
-	}
 	for _, line := range strings.Split(src, "\n") {
 		line = strings.TrimSpace(line)
 		if strings.HasPrefix(line, "//") {
@@ -415,18 +412,13 @@ func (t *test) run() {
 		t.err = skipError("starts with newline")
 		return
 	}
+
+	// Execution recipe stops at first blank line.
 	pos := strings.Index(t.src, "\n\n")
 	if pos == -1 {
 		t.err = errors.New("double newline not found")
 		return
 	}
-	if ok, why := shouldTest(t.src, goos, goarch); !ok {
-		t.action = "skip"
-		if *showSkips {
-			fmt.Printf("%-20s %-20s: %s\n", t.action, t.goFileName(), why)
-		}
-		return
-	}
 	action := t.src[:pos]
 	if nl := strings.Index(action, "\n"); nl >= 0 && strings.Contains(action[:nl], "+build") {
 		// skip first line
@@ -436,6 +428,19 @@ func (t *test) run() {
 		action = action[2:]
 	}
 
+	// Check for build constraints only up to the actual code.
+	pkgPos := strings.Index(t.src, "\npackage")
+	if pkgPos == -1 {
+		pkgPos = pos // some files are intentionally malformed
+	}
+	if ok, why := shouldTest(t.src[:pkgPos], goos, goarch); !ok {
+		t.action = "skip"
+		if *showSkips {
+			fmt.Printf("%-20s %-20s: %s\n", t.action, t.goFileName(), why)
+		}
+		return
+	}
+
 	var args, flags []string
 	wantError := false
 	f := strings.Fields(action)
@@ -510,7 +515,7 @@ func (t *test) run() {
 		t.err = fmt.Errorf("unimplemented action %q", action)
 
 	case "errorcheck":
-		cmdline := []string{"go", "tool", gc, "-e", "-o", "a." + letter}
+		cmdline := []string{"go", "tool", "compile", "-e", "-o", "a.o"}
 		cmdline = append(cmdline, flags...)
 		cmdline = append(cmdline, long)
 		out, err := runcmd(cmdline...)
@@ -525,6 +530,9 @@ func (t *test) run() {
 				return
 			}
 		}
+		if *updateErrors {
+			t.updateErrors(string(out), long)
+		}
 		t.err = t.errorCheck(string(out), long, t.gofile)
 		return
 
@@ -670,7 +678,7 @@ func (t *test) run() {
 			t.err = fmt.Errorf("write tempfile:%s", err)
 			return
 		}
-		cmdline := []string{"go", "tool", gc, "-e", "-o", "a." + letter}
+		cmdline := []string{"go", "tool", "compile", "-e", "-o", "a.o"}
 		cmdline = append(cmdline, flags...)
 		cmdline = append(cmdline, tfile)
 		out, err = runcmd(cmdline...)
@@ -725,29 +733,34 @@ func (t *test) expectedOutput() string {
 	return string(b)
 }
 
-func (t *test) errorCheck(outStr string, fullshort ...string) (err error) {
-	defer func() {
-		if *verbose && err != nil {
-			log.Printf("%s gc output:\n%s", t, outStr)
-		}
-	}()
-	var errs []error
-
-	var out []string
-	// 6g error messages continue onto additional lines with leading tabs.
+func splitOutput(out string) []string {
+	// gc error messages continue onto additional lines with leading tabs.
 	// Split the output at the beginning of each line that doesn't begin with a tab.
-	for _, line := range strings.Split(outStr, "\n") {
+	// <autogenerated> lines are impossible to match so those are filtered out.
+	var res []string
+	for _, line := range strings.Split(out, "\n") {
 		if strings.HasSuffix(line, "\r") { // remove '\r', output by compiler on windows
 			line = line[:len(line)-1]
 		}
 		if strings.HasPrefix(line, "\t") {
-			out[len(out)-1] += "\n" + line
-		} else if strings.HasPrefix(line, "go tool") {
+			res[len(res)-1] += "\n" + line
+		} else if strings.HasPrefix(line, "go tool") || strings.HasPrefix(line, "<autogenerated>") {
 			continue
 		} else if strings.TrimSpace(line) != "" {
-			out = append(out, line)
+			res = append(res, line)
 		}
 	}
+	return res
+}
+
+func (t *test) errorCheck(outStr string, fullshort ...string) (err error) {
+	defer func() {
+		if *verbose && err != nil {
+			log.Printf("%s gc output:\n%s", t, outStr)
+		}
+	}()
+	var errs []error
+	out := splitOutput(outStr)
 
 	// Cut directory name.
 	for i := range out {
@@ -804,7 +817,72 @@ func (t *test) errorCheck(outStr string, fullshort ...string) (err error) {
 		fmt.Fprintf(&buf, "%s\n", err.Error())
 	}
 	return errors.New(buf.String())
+}
 
+func (t *test) updateErrors(out string, file string) {
+	// Read in source file.
+	src, err := ioutil.ReadFile(file)
+	if err != nil {
+		fmt.Fprintln(os.Stderr, err)
+		return
+	}
+	lines := strings.Split(string(src), "\n")
+	// Remove old errors.
+	for i, ln := range lines {
+		pos := strings.Index(ln, " // ERROR ")
+		if pos >= 0 {
+			lines[i] = ln[:pos]
+		}
+	}
+	// Parse new errors.
+	errors := make(map[int]map[string]bool)
+	tmpRe := regexp.MustCompile(`autotmp_[0-9]+`)
+	for _, errStr := range splitOutput(out) {
+		colon1 := strings.Index(errStr, ":")
+		if colon1 < 0 || errStr[:colon1] != file {
+			continue
+		}
+		colon2 := strings.Index(errStr[colon1+1:], ":")
+		if colon2 < 0 {
+			continue
+		}
+		colon2 += colon1 + 1
+		line, err := strconv.Atoi(errStr[colon1+1 : colon2])
+		line--
+		if err != nil || line < 0 || line >= len(lines) {
+			continue
+		}
+		msg := errStr[colon2+2:]
+		for _, r := range []string{`\`, `*`, `+`, `[`, `]`, `(`, `)`} {
+			msg = strings.Replace(msg, r, `\`+r, -1)
+		}
+		msg = strings.Replace(msg, `"`, `.`, -1)
+		msg = tmpRe.ReplaceAllLiteralString(msg, `autotmp_[0-9]+`)
+		if errors[line] == nil {
+			errors[line] = make(map[string]bool)
+		}
+		errors[line][msg] = true
+	}
+	// Add new errors.
+	for line, errs := range errors {
+		var sorted []string
+		for e := range errs {
+			sorted = append(sorted, e)
+		}
+		sort.Strings(sorted)
+		lines[line] += " // ERROR"
+		for _, e := range sorted {
+			lines[line] += fmt.Sprintf(` "%s$"`, e)
+		}
+	}
+	// Write new file.
+	err = ioutil.WriteFile(file, []byte(strings.Join(lines, "\n")), 0640)
+	if err != nil {
+		fmt.Fprintln(os.Stderr, err)
+		return
+	}
+	// Polish.
+	exec.Command("go", "fmt", file).CombinedOutput()
 }
 
 // matchPrefix reports whether s is of the form ^(.*/)?prefix(:|[),
@@ -888,7 +966,7 @@ func (t *test) wantedErrors(file, short string) (errs []wantedError) {
 				var err error
 				re, err = regexp.Compile(rx)
 				if err != nil {
-					log.Fatalf("%s:%d: invalid regexp in ERROR line: %v", t.goFileName(), lineNum, err)
+					log.Fatalf("%s:%d: invalid regexp \"%s\" in ERROR line: %v", t.goFileName(), lineNum, rx, err)
 				}
 				cache[rx] = re
 			}
@@ -906,15 +984,6 @@ func (t *test) wantedErrors(file, short string) (errs []wantedError) {
 	return
 }
 
-var skipOkay = map[string]bool{
-	"fixedbugs/bug248.go": true, // combines errorcheckdir and rundir in the same dir.
-	"fixedbugs/bug302.go": true, // tests both .$O and .a imports.
-	"fixedbugs/bug345.go": true, // needs the appropriate flags in gc invocation.
-	"fixedbugs/bug369.go": true, // needs compiler flags.
-	"fixedbugs/bug429.go": true, // like "run" but program should fail
-	"bugs/bug395.go":      true,
-}
-
 // defaultRunOutputLimit returns the number of runoutput tests that
 // can be executed in parallel.
 func defaultRunOutputLimit() int {
diff --git a/test/sinit.go b/test/sinit.go
index df1a4cc..188a530 100644
--- a/test/sinit.go
+++ b/test/sinit.go
@@ -10,6 +10,8 @@
 
 package p
 
+import "unsafe"
+
 // Should be no init func in the assembly.
 // All these initializations should be done at link time.
 
@@ -284,3 +286,6 @@ type Mer interface {
 }
 
 var _ Mer = (*T1)(nil)
+
+var Byte byte
+var PtrByte unsafe.Pointer = unsafe.Pointer(&Byte)
diff --git a/test/sinit_run.go b/test/sinit_run.go
index b0a91ce..c9afd3b 100644
--- a/test/sinit_run.go
+++ b/test/sinit_run.go
@@ -12,26 +12,19 @@ package main
 import (
 	"bytes"
 	"fmt"
-	"go/build"
 	"os"
 	"os/exec"
 )
 
 func main() {
-	letter, err := build.ArchChar(build.Default.GOARCH)
-	if err != nil {
-		fmt.Println(err)
-		os.Exit(1)
-	}
-
-	cmd := exec.Command("go", "tool", letter+"g", "-S", "sinit.go")
+	cmd := exec.Command("go", "tool", "compile", "-S", "sinit.go")
 	out, err := cmd.CombinedOutput()
 	if err != nil {
 		fmt.Println(string(out))
 		fmt.Println(err)
 		os.Exit(1)
 	}
-	os.Remove("sinit." + letter)
+	os.Remove("sinit.o")
 
 	if bytes.Contains(out, []byte("initdone")) {
 		fmt.Println("sinit generated an init function")
diff --git a/test/sliceopt.go b/test/sliceopt.go
new file mode 100644
index 0000000..c9d089f
--- /dev/null
+++ b/test/sliceopt.go
@@ -0,0 +1,59 @@
+// errorcheck -0 -d=append,slice
+
+// 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.
+
+// Check optimization results for append and slicing.
+
+package main
+
+func a1(x []int, y int) []int {
+	x = append(x, y) // ERROR "append: len-only update"
+	return x
+}
+
+func a2(x []int, y int) []int {
+	return append(x, y) // ERROR "append: full update"
+}
+
+func a3(x *[]int, y int) {
+	*x = append(*x, y) // ERROR "append: len-only update"
+}
+
+func s1(x **[]int, xs **string, i, j int) {
+	var z []int
+	z = (**x)[2:]         // ERROR "slice: omit check for 2nd index"
+	z = (**x)[2:len(**x)] // not yet: "slice: reuse len" "slice: omit check for 2nd index"
+	z = (**x)[2:cap(**x)] // not yet: "slice: reuse cap" "slice: omit check for 2nd index"
+	z = (**x)[i:i]        // ERROR "slice: reuse 1st index" "slice: omit check for 1st index" "slice: result len == 0"
+	z = (**x)[1:i:i]      // ERROR "slice: reuse 2nd index" "slice: omit check for 2nd index" "slice: result cap == result len"
+	z = (**x)[i:j:0]      // ERROR "slice: omit check for 3rd index"
+	z = (**x)[i:0:j]      // ERROR "slice: omit check for 2nd index"
+	z = (**x)[0:i:j]      // ERROR "slice: omit check for 1st index" "slice: skip base adjustment for 1st index 0"
+	z = (**x)[0:]         // ERROR "slice: omit slice operation"
+	z = (**x)[2:8]        // ERROR "slice: omit check for 1st index" "slice: result len == 6"
+	z = (**x)[2:2]        // ERROR "slice: omit check for 1st index" "slice: result len == 0"
+	z = (**x)[0:i]        // ERROR "slice: omit check for 1st index" "slice: skip base adjustment for 1st index 0"
+	z = (**x)[2:i:8]      // ERROR "slice: result cap == 6"
+	z = (**x)[i:2:i]      // ERROR "slice: reuse 1st index" "slice: result cap == 0" "slice: skip base adjustment for cap == 0"
+
+	z = z[0:i]       // ERROR "slice: omit check for 1st index" "slice: result cap not computed" "slice: skip base adjustment for 1st index 0" "slice: len-only update"
+	z = z[0:i : i+1] // ERROR "slice: omit check for 1st index" "slice: skip base adjustment for 1st index 0" "slice: len/cap-only update"
+	z = z[i : i+1]
+
+	println(z)
+
+	var zs string
+	zs = (**xs)[2:]          // ERROR "slice: omit check for 2nd index"
+	zs = (**xs)[2:len(**xs)] // not yet: "slice: reuse len" "slice: omit check for 2nd index"
+	zs = (**xs)[i:i]         // ERROR "slice: reuse 1st index" "slice: omit check for 1st index" "slice: result len == 0" "slice: skip base adjustment for string len == 0"
+	zs = (**xs)[0:]          // ERROR "slice: omit slice operation"
+	zs = (**xs)[2:8]         // ERROR "slice: omit check for 1st index" "slice: result len == 6"
+	zs = (**xs)[2:2]         // ERROR "slice: omit check for 1st index" "slice: result len == 0" "slice: skip base adjustment for string len == 0"
+	zs = (**xs)[0:i]         // ERROR "slice: omit check for 1st index" "slice: skip base adjustment for 1st index 0"
+
+	zs = zs[0:i] // ERROR "slice: omit check for 1st index" "slice: skip base adjustment for 1st index 0" "slice: len-only update"
+	zs = zs[i : i+1]
+	println(zs)
+}
diff --git a/test/testlib b/test/testlib
deleted file mode 100644
index 4a17f4f..0000000
--- a/test/testlib
+++ /dev/null
@@ -1,170 +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.
-
-# These function names are also known to
-# (and are the plan for transitioning to) run.go.
-
-# helper (not known to run.go)
-# group file list by packages and return list of packages
-# each package is a comma-separated list of go files.
-pkgs() {
-	pkglist=$(grep -h '^package ' $* | awk '{print $2}' | sort -u)
-	for p in $pkglist
-	do
-		echo $(grep -l "^package $p\$" $*) | tr ' ' ,
-	done | sort
-}
-
-_match() {
-	case $1 in
-	*,*)
-		#echo >&2 "match comma separated $1"
-		first=$(echo $1 | sed 's/,.*//')
-		rest=$(echo $1 | sed 's/[^,]*,//')
-		if _match $first && _match $rest; then
-			return 0
-		fi
-		return 1
-		;;
-	'!'*)
-		#echo >&2 "match negation $1"
-		neg=$(echo $1 | sed 's/^!//')
-		if _match $neg; then
-			return 1
-		fi
-		return 0
-		;;
-	$GOARCH|$GOOS)
-		#echo >&2 "match GOARCH or GOOS $1"
-		return 0
-		;;
-	esac
-	return 1
-}
-
-# +build aborts execution if the supplied tags don't match,
-# i.e. none of the tags (x or !x) matches GOARCH or GOOS.
-+build() {
-	if (( $# == 0 )); then
-		return
-	fi
-	m=0
-	for tag; do
-		if _match $tag; then
-			m=1
-		fi
-	done
-	if [ $m = 0 ]; then
-		#echo >&2 no match
-		exit 0
-	fi
-	unset m
-}
-
-compile() {
-	$G $D/$F.go
-}
-
-compiledir() {
-	for pkg in $(pkgs $D/$F.dir/*.go)
-	do
-		$G -I . $(echo $pkg | tr , ' ') || return 1
-	done
-}
-
-errorcheckdir() {
-	lastzero=""
-	if [ "$1" = "-0" ]; then
-		lastzero="-0"
-	fi
-	pkgs=$(pkgs $D/$F.dir/*.go)
-	for pkg in $pkgs.last
-	do
-		zero="-0"
-		case $pkg in
-		*.last)
-			pkg=$(echo $pkg |sed 's/\.last$//')
-			zero=$lastzero
-		esac
-		errchk $zero $G -D . -I . -e $(echo $pkg | tr , ' ')
-	done
-}
-
-rundir() {
-	lastfile=""
-	for pkg in $(pkgs $D/$F.dir/*.go)
-	do
-		name=$(echo $pkg | sed 's/\.go.*//; s/.*\///')
-		$G -D . -I . -e $(echo $pkg | tr , ' ') || return 1
-		lastfile=$name
-	done
-	$L -o $A.out -L . $lastfile.$A
-	./$A.out
-}
-
-rundircmpout() {
-	lastfile=""
-	for pkg in $(pkgs $D/$F.dir/*.go)
-	do
-		name=$(echo $pkg | sed 's/\.go.*//; s/.*\///')
-		$G -D . -I . -e $(echo $pkg | tr , ' ') || return 1
-		lastfile=$name
-	done
-	$L -o $A.out -L . $lastfile.$A
-	./$A.out 2>&1 | cmp - $D/$F.out
-}
-
-build() {
-	$G $D/$F.go && $L $F.$A
-}
-
-runoutput() {
-	go run "$D/$F.go" "$@" > tmp.go
-	go run tmp.go
-}
-
-run() {
-	gofiles=""
-	ingo=true
-	while $ingo; do
-		case "$1" in
-		*.go)
-			gofiles="$gofiles $1"
-			shift
-			;;
-		*)
-			ingo=false
-			;;
-		esac
-	done
-
-	$G $D/$F.go $gofiles && $L $F.$A && ./$A.out "$@"
-}
-
-cmpout() {
-	$G $D/$F.go && $L $F.$A && ./$A.out 2>&1 | cmp - $D/$F.out
-}
-
-errorcheck() {
-	zero=""
-	if [ "$1" = "-0" ]; then
-		zero="-0"
-		shift
-	fi
-	errchk $zero $G -e $* $D/$F.go
-}
-
-errorcheckoutput() {
-	zero=""
-	if [ "$1" = "-0" ]; then
-		zero="-0"
-		shift
-	fi
-	go run "$D/$F.go" "$@" > tmp.go
-	errchk $zero $G -e tmp.go
-}
-
-skip() {
-	true
-}
diff --git a/test/writebarrier.go b/test/writebarrier.go
new file mode 100644
index 0000000..9b741a6
--- /dev/null
+++ b/test/writebarrier.go
@@ -0,0 +1,146 @@
+// errorcheck -0 -l -d=wb
+
+// 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 where write barriers are and are not emitted.
+
+package p
+
+import "unsafe"
+
+func f(x **byte, y *byte) {
+	*x = y // ERROR "write barrier"
+
+	z := y // no barrier
+	*x = z // ERROR "write barrier"
+}
+
+func f1(x *[]byte, y []byte) {
+	*x = y // ERROR "write barrier"
+
+	z := y // no barrier
+	*x = z // ERROR "write barrier"
+}
+
+func f1a(x *[]byte, y *[]byte) {
+	*x = *y // ERROR "write barrier"
+
+	z := *y // no barrier
+	*x = z  // ERROR "write barrier"
+}
+
+func f2(x *interface{}, y interface{}) {
+	*x = y // ERROR "write barrier"
+
+	z := y // no barrier
+	*x = z // ERROR "write barrier"
+}
+
+func f2a(x *interface{}, y *interface{}) {
+	*x = *y // ERROR "write barrier"
+
+	z := y // no barrier
+	*x = z // ERROR "write barrier"
+}
+
+func f3(x *string, y string) {
+	*x = y // ERROR "write barrier"
+
+	z := y // no barrier
+	*x = z // ERROR "write barrier"
+}
+
+func f3a(x *string, y *string) {
+	*x = *y // ERROR "write barrier"
+
+	z := *y // no barrier
+	*x = z  // ERROR "write barrier"
+}
+
+func f4(x *[2]string, y [2]string) {
+	*x = y // ERROR "write barrier"
+
+	z := y // no barrier
+	*x = z // ERROR "write barrier"
+}
+
+func f4a(x *[2]string, y *[2]string) {
+	*x = *y // ERROR "write barrier"
+
+	z := *y // no barrier
+	*x = z  // ERROR "write barrier"
+}
+
+type T struct {
+	X *int
+	Y int
+	M map[int]int
+}
+
+func f5(t, u *T) {
+	t.X = &u.Y // ERROR "write barrier"
+}
+
+func f6(t *T) {
+	t.M = map[int]int{1: 2} // ERROR "write barrier"
+}
+
+func f7(x, y *int) []*int {
+	var z [3]*int
+	i := 0
+	z[i] = x // ERROR "write barrier"
+	i++
+	z[i] = y // ERROR "write barrier"
+	i++
+	return z[:i]
+}
+
+func f9(x *interface{}, v *byte) {
+	*x = v // ERROR "write barrier"
+}
+
+func f10(x *byte, f func(interface{})) {
+	f(x)
+}
+
+func f11(x *unsafe.Pointer, y unsafe.Pointer) {
+	*x = unsafe.Pointer(uintptr(y) + 1) // ERROR "write barrier"
+}
+
+func f12(x []*int, y *int) []*int {
+	// write barrier for storing y in x's underlying array
+	x = append(x, y) // ERROR "write barrier"
+	return x
+}
+
+func f12a(x []int, y int) []int {
+	// y not a pointer, so no write barriers in this function
+	x = append(x, y)
+	return x
+}
+
+func f13(x []int, y *[]int) {
+	*y = append(x, 1) // ERROR "write barrier"
+}
+
+func f14(y *[]int) {
+	*y = append(*y, 1) // ERROR "write barrier"
+}
+
+type T1 struct {
+	X *int
+}
+
+func f15(x []T1, y T1) []T1 {
+	return append(x, y) // ERROR "write barrier"
+}
+
+type T8 struct {
+	X [8]*int
+}
+
+func f16(x []T8, y T8) []T8 {
+	return append(x, y) // ERROR "write barrier"
+}

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-golang/golang.git



More information about the pkg-golang-commits mailing list